什么是SVE

NEON指令集是ARM64架构的单指令多数据流(SIMD)的规范实现。SVE(可扩大矢量指令Scalable Vector Extension)是针对高性能计算(HPC)和机器学习等畛域开发的一套全新的矢量指令集,它是下一代SIMD指令集实现,而不是NEON指令集的简略扩大。SVE指令集中有很多概念与NEON指令集相似,例如矢量、通道、数据元素等。SVE指令集也提出了一个全新的概念:可变矢量长度编程模型(VectorLength Agnostic,VLA)。

传统的SIMD指令集采纳固定大小的向量寄存器,例如NEON指令集采纳固定的128位长度的矢量寄存器。而反对VLA编程模型的SVE指令集则反对可变长度的矢量寄存器。这样容许芯片设计者依据负载和老本来抉择一个适合的矢量长度。SVE指令集的矢量寄存器的长度最小反对128位,最大能够反对2048位,以128位为增量。SVE设计确保同一个应用程序能够在反对不同矢量长度的SVE指令机器上运行,而不须要从新编译代码,这是VLA编程模型的精华。

SVE指令集是在A64指令集的根底上新增的一组指令集,而SVE2是在ARMv9架构上公布的,它是SVE指令集的一个超集和裁减。

SVE指令集蕴含了几百条指令,它们能够分成如下几大类。

Ø 加载存储指令以及预取指令

Ø 向量挪动指令

Ø 整数运算指令

Ø 位操作指令

Ø 浮点数运算指令

Ø 预测操作指令

Ø 数据元素操作指令

SVE2指令集在SVE指令集的根底进一步裁减和欠缺,新增了局部指令和扩大。本节不对每条指令做具体的介绍,有趣味的读者能够浏览ARMv9指令集文档:《Arm A64 Instruction SetArchitecture,Armv9, for Armv9-A architectureprofile》。

什么是矢量计算?

SIMD,全称Single Instruction Multiple Data,一条指令操作多个数据,提供小数据并行处理能力。ARM从ARMv7架构开始退出NEON指令集扩大,矢量化并行计算,用于图像处理、音视频解决、视频编解码等场景。

SISD(Single Instruction Single Data)指的是单指令单数据。大多数ARM64指令是单指令单数据(SISD)。每条指令在单个数据源上执行其指定的操作,所以,解决多个数据项须要多个指令。例如,要执行4个加法操作,须要4条指令从4对寄存器进行加法运算。

ADD w0, w0, w5

ADD w1, w1, w6

ADD w2, w2, w7

ADD w3, w3, w8

如果数据元素比拟小,例如当将8位值相加时,须要将每个8位值加载到一个独自的64位寄存器中。因为处理器、寄存器和数据门路都是为64位计算而设计的,所以在小数据大小上执行大量独自的操作不能无效地应用机器资源。

SIMD指的是单指令多数据流,它对多个数据元素同时执行雷同的操作。这些数据元素被打包成一个更大的寄存器中的独立通道(Lanes)。例如,ADD指令将32位数据元素加在一起。这些值被打包到两对128位寄存器(别离是V8和V9)中的独自通道中。而后将第一源寄存器中的每个通道增加到第二源寄存器中的相应通道,而后将其存储在指标寄存器(V10)中的同一通道中。

ADD V0.4S, V1.4S, V2.4S

如图1所示,ADD指令会并行做4个加法运算,它们别离位于处理器外部的4个计算通道并且是互相独立的,任何一个通道产生了溢出或者进位都不会影响其余通道。

V0.4S[0] = V1.4S[0]+ V2.4S[0]
V0.4S[1] = V1.4S[1]+ V2.4S[1]
V0.4S[2] = V1.4S[2]+ V2.4S[2]
V0.4S[3]= V1.4S[3] + V2.4S[3]

在图1中,一个128位的矢量寄存器Vn能够同时存储4个32位的数据Sn,另外它还能够存储2个64位数据Dn、8个16位数据Hn或者16个8位数据Bn。

SIMD非常适合图像处理场景。图像的数据罕用的数据类型是RGB565, RGBA8888,YUV422等格局,这些格局的数据特点是一个像素点的一个重量(A、R、G以及B重量)应用8位数据表示。如果应用传统的处理器做计算,尽管处理器的寄存器是32位或是64位的,解决这些数据确只能应用寄存器的低8位,有点节约。如果把64位寄存器拆成8个8位数据通道就能同时实现8个操作,计算效率晋升了8倍。

总之,SISD和SIMD的区别如图2所示。

矢量与通道

在SIMD指令中经常应用矢量数据格式(Vectorformats)。矢量被划分为多个通道(lanes),每个通道蕴含一个矢量元素(vector elements)。如图3所示,一个Vn矢量寄存器能够分成8个16位数据,如通道0、通道1等。

通道能够由多种不同的数据类型组成,比方128位的数据类型用Vn来示意,64位的数据类型用Dn来示意,32位的数据类型用Sn来示意,16位的数据类型用Hn来示意,8位的数据类型用Bn来示意,如图4所示。

在矢量指令集(NEON/SVE)中,指令通常能够分成两大类,一类是矢量(vector)运算指令,另一类是标量(scalar)运算指令。矢量运算指的是对矢量寄存器中所有通道的数据都同时进行运算,而标量运算指的是只对矢量寄存器中某个通道的数据进行运算。

SVE寄存器组

SVE指令集提供了一组全新的寄存器。

Ø 32个全新的可变长矢量寄存器Z0~ Z31。

Ø 16个预测寄存器(predicateregister)P0 ~ P15。

Ø 首次谬误预测寄存器(First Fault predicateRegister,FFR)

Ø SVE管制寄存器ZCR_Elx

(1)可变长矢量寄存器Z

Z寄存器是数据寄存器,长度是可变长的。它的长度是128的倍数,最高可达2048位。Z寄存器中的数据能够用来存储为8位、16位、32位、64位或128位数据元素,如图5所示。每个Z寄存器的低128位与对应的NEON寄存器复用。

(2) 预测寄存器P

P寄存器为Z寄存器中的每个字节保留一个位,也就是说,P寄存器总是Z寄存器的1/8大小。预测指令(Predicatedinstruction)应用P寄存器来确定要解决哪些向量元素(通道数据)。P寄存器中的每个比特位指定Z寄存器中相应的字节是处于沉闷状态还是非沉闷状态。

当数据元素为8位宽(Bn)时,P寄存器能够应用1个比特位来示意其沉闷状态,这个比特位为1示意沉闷,为0示意不沉闷。顺次类推,当数据元素为128位宽(Vn)时,P寄存器预留了8个比特位来示意Z寄存器中对应的数据元素的沉闷状态,不过只应用了最低1位即可示意其沉闷状态,其余比特位保留。

假如矢量寄存器的长度为256位,矢量寄存器分成了8个通道,每个通道存储32位宽的数据。如果在SVE指令中想同时操作这8个通道的数据,那么须要应用一个P寄存器来示意这8个数据通道的状态。如图6所示,Pn寄存器也分成8个组,每个组由4个比特位组成,每个组只应用最低的比特位来示意Zn寄存器中对应的数据通道(32位宽)的沉闷状态。例如,Pn寄存器的Bit[3:0]示意Zn寄存器的通道0,Pn寄存器的Bit[7:4]示意Zn寄存器的通道1,顺次类推。

3) FFR寄存器

FFR寄存器的大小与格局和预测寄存器P雷同。FFR寄存器用于第一异样预测加载指令(First Fault PredicteLoad Instruction),例如LDRFF指令。在应用第一异样预测加载指来加载矢量元素时,FFR寄存器会及时更新每个数据元素的加载状态,是胜利还是失败

(4) ECR_ELx寄存器

系统软件能够通过ECR_ELx寄存器中的LEN字段来设置矢量寄存器的长度。不过,设置的长度不能超过硬件实现的长度。

SVE指令语法

SVE指令的语法与NEON指令有很大不同。SVE指令格局由操作代码、指标寄存器、P寄存器和输出操作符等组成。上面举几个例子来介绍。

【例】

上面是一条LD1D指令的格局。

LD1D { <Zt>.D },<Pg>/Z, [<Xn|SP>, <Xm>, LSL #3]

其中:

Ø Zt示意矢量寄存器,能够应用Z0~Z31。

Ø D示意矢量寄存器中通道的数据类型。

Ø Pg示意预测操作数(predicateoperand),能够应用P0~P15。

Ø <Pg>/Z中的Z示意零预测(zeroingpredication)。

Ø Xn/SP:示意源操作数的基地址,Xn为通用寄存器,SP为栈指针寄存器。

Ø Xm:示意第二个源操作数寄存器。

【例2】

上面是一条ADD指令的格局。

ADD <Zdn>.<T>,<Pg>/M, <Zdn>.<T>, <Zm>.<T>

其中:

Ø Zdn示意第一个源矢量寄存器或者指标矢量寄存器。

Ø Pg示意预测寄存器,能够应用P0~P15。

Ø <Pg>/M中的M示意合并预测(mergingpredication)。

Ø Zm示意第二个源矢量寄存器。

Ø T示意矢量寄存器中通道的数据类型。