灵魂深处 AMD新一代SIMD指令集剖析.docx
《灵魂深处 AMD新一代SIMD指令集剖析.docx》由会员分享,可在线阅读,更多相关《灵魂深处 AMD新一代SIMD指令集剖析.docx(10页珍藏版)》请在冰豆网上搜索。
灵魂深处AMD新一代SIMD指令集剖析
魂深处AMD新一代SIMD指令集剖析
窥视灵对处理器来说指令集是赋予硬件活力的催化剂,就像灵魂之于肉体。
因此,AMD与Intel在指令集研发的斗争上从来没有停息过,只是随着AMD的推土机微架构逐渐浮出水面,x86领域的SIMD(SingleInstructionMultipleData单指令多数据流)指令之争将暂时告一段落。
据现有消息来看推土机架构的指令集规格比SandyBridge乃至后续的IvyBridge都要完整。
这不禁让人好奇,以XOP、FMA4等为代表的AMD新一代指令集到底有何特点和优势,能有如此的前瞻性。
Bulldozer(推土机)是AMD继使用了多年的K10microarchitecture(微架构)后全新一代的微架构。
从AMD给出的官方资料来看AMD除了在Bulldozer上实现自家的XOP、FMA4以及CVT16指令外,还将完整地支持IntelSandyBridge上的所有指令集。
除了以前的MMX和SSE系列指令,还将包括新的SSE4.1、SSE4.2、AVX、AES和CLMUL指令集。
Bulldozer和SandyBridge架构的指令集对比介绍
1.SandyBridge支持的指令集
SandyBridge微架构的处理器已经在2011年1月发布了,在SIMD指令方面SandyBridge微架构的处理器支持新一代的AVX(AdvancedVectorExtensions高级适量扩展)、AES或者说AES-NI(AdvancedEncryptionStandardNewInstructions高级加密标准指令)以及CLMUL指令,但并不提供对FMA指令的支持。
从Intel给出的资料显示,在下一代微架构IvyBridge上FMA指令也不会得到支持,要到Haswell微架构才会将FMA指令集加入到支持列表中。
2.Bulldozer支持的指令集
AMD即将登场的推土机架构处理器,桌面产品代号为Zambezi,在SIMD指令方面推土机微架构将完整地支持Intel新一代的AVX、AES以及CLMUL指令,并对SSE系列的扩展指令进行了补充支持,包括SSSE3、SSE4.1和SSE4.2指令集。
此外,除了继承自己的老指令集,还会提供包括XOP、FMA4以及CVT16指令集在内的新指令集。
实际上XOP、FMA4和CVT16指令集是从SSE5发展改良而来的,使用了AVX指令的设计方案,可以理解为是对AVX指令集的补充。
值得注意的是,对于CVT16指令集AMD官方没有文档化,还不能肯定推土机架构处理器是否能支持。
从SSE5和AVX开始的新一代指令集之争
在对x86指令集背景知识有所了解后,我们进入本文所要讲的主角——XOP系列指令集。
由于XOP系列指令集算是AVX的扩充版,所以笔者将尝试带领读者深入探索,对比AVX与XOP系列指令的底层知识。
XOP、FMA4以及CVT16指令是由SSE5演变发展而来,可是SSE5指令集已经不存在了,AMD改变了SSE5指令集的设计方案,它的指令编码方式使用了AVX的编码规则,以达到兼容AVX指令的方案。
也因此,XOP指令与AVX指令不存在冲突,你甚至可以将XOP、FMA和CVT16指令集可以看作是对AVX指令集的补充。
实际上XOP、FMA4、CVT16以及FMA、AES(AES-NI)、CLMUL指令都使用了AVX的指令编码设计方式。
从这方面来看AVX统一了新一代SIMD指令的编码设计方案,这完全有别于早前的SSE系列仅以指令来区别的指令集形式。
从这个趋势看AVX的指令集编码设计方案将在x86处理器平台上统冶相当长的时间,换句话说Intel又掌握了未来相当长时间内x86架构指令集设计的主动权。
AMD新指令集得从AVX系指令集说起
Intel的AVX系指令集包括下面4个子集:
(1)AVX指令集:
新一代的SIMD指令
(2)FMA指令集:
新一代的fused-multiply-addSIMD指令
(3)AES-NI指令集:
新的指令由原SSE指令演变而来
(4)CLMUL指令集:
新的指令由原SSE指令演变而来
这些指令集都统一使用了AVX指令的编码设计规则,FMA是全新的子集,而AES-NI与CLMUL指令由原有的SSE系列指令演变而来,因此它们既有SSE版本,也有全新的AVX版本。
推土机完整地支持AVX,实现的指令与Intel的AVX完全兼容。
因此这里描述的AVX指令内容既适合Intel也同样适合AMD。
AVX在规格方面,提供了共365条指令,其中包括:
提供了35条256位的double-precision(双精度)和single-precision(单精度)浮点vector运算。
覆盖了9类运算:
add(加):
例如vaddps指令
subtract(减):
例如vsubps指令
multiply(乘):
例如vmulps指令
divide(除):
例如vdivps指令
square-root(平方根):
vsqrtps指令
compare(比较):
例如vcmpps指令
max(求最大值):
例如vmaxps指令
min(求最小值):
例如vminps指令
round(舍入):
例如vroundps指令
提供了57条256位非运算类的数据处理指令,其中包括了39条256位数据处理指令和18条新提供的256位vector数据处理指令。
FMA指令
FMA指令是AVX指令集的一个分支,因此FMA指令使用的是与AVX指令同样的编码设计规则。
事实上,Intel的FMA指令集也吸取了AMD提出的SSE5指令集的精髓,FMA指令的fused-multiply-add(融合乘加)与SSE5中的multiply-add/subtract运算如出一辙。
当前FMA指令已分为2个版本:
FMA3版本:
这是Intel实现的,提供了3个操作数。
FMA4版本:
这是AMD实现的,提供了4个操作数。
FMA指令实现了多样的融合乘加/减操作,包括:
fused-multiply-add(融合乘加)操作,例如:
VFMADDPS指令等。
它做的操作表示为:
d=(a*b)+c
fused-multiply-subtract(融合乘减)操作,例如:
VFMASUBPS指令等。
它做的操作表示为:
d=(a*b)-c
fused-multiply-add/subtractinterleave(融合乘与交互加减)操作,例如:
FMADDSUBPS指令,FMASUBADDPS指令等,操作数必须为vector数据,因此:
可以一串式子表示为:
d[1]=(a[1]*b[1])+c[1],d[0]=(a[0]*b[0])-c[0] 这意味着vector中的数据交互进行融合乘加/减。
signed-reversedmultiplyonfusedmultiply-add(负融合乘加)操作,例如:
VFNMADDPS指令,这表示:
相乘后取负然后相加,即:
d=-(a*b)+c
signed-reversedmultiplyonfusedmultiply-subtract(负融合乘减)操作,例如:
VFNMSUBPS指令,这表示:
相乘后取负然后相减,即:
d=-(a*b)-c
这些FMA指令集包括256位的浮点vector运算,还提供了128位的浮点vector数据与scalar数据运算。
对浮点运算来说,FMA指令可谓提供了质的效能飞越。
AMD的FMA4版本
AMD在FMA指令上实现了4个operands(操作数),被称为FMA4版本。
对于上面第一个例子,我们用FMA4指令可以描述为:
//FMA4指令
vfmaddsdxmm0,xmm1,xmm2,xmm3(表示xmm0=xmm1*xmm2+xmm3)
vmovsdmmwordptr[d],xmm0(表示d=xmm0)
可以看到AMD的FMA4指令支持4-operand(4个操作数),这样可以无损地使用目标操作数,图1直观地表达了vfmaddsd指令的操作:
图1
Intel的FMA3版本
在FMA3版本中,其中一个操作数既是源操作数又是目标操作数,上面的示例使用FMA3指令描述如下:
//FMA3指令
vfmadd213sdxmm1,xmm2,xmm3(表示xmm1=xmm1*xmm2+xmm3)
vmovsdmmwordptr[d],xmm1(表示d=xmm1)
在FMA3版本中第1个源操作数也是目标操作数,vfmadd213sd指令的操作过程如图2所示:
图2我们看到这个图上表示了src1和dest操作数都是xmm1寄存器。
FMA3与FMA4指令设计的差异
AMD的FMA4指令大部分是从SSE5分离出来,并增加了少量的新指令。
FMA3指令与FMA4指令在规格上是一致的,它们相同之处都是进行相同的运算,但是实现方式有些区别。
两者除了在操作数上有别外,最大的差异在指令的Mnemonic(助记符),由于Intel的FMA3指令是3个操作数,因此额外增加了123的mnemonic方法来表达指令操作数的顺序,数字的意义如下:
1表示:
第1个源操作数(也是目标操作数),它由ModRM.reg寻址
2表示:
第2个源操作数,它由VEX.vvvv寻址
3表示:
第3个源操作数,它由ModRM.r/m寻址
这些数字的排列顺序有着特殊的意义:
排在第1位表示:
被乘数
排在第2位表示:
乘数
排在第3位表示:
加数或者减数
举个例子:
231的mnemonic的排列表示:
第2个源操作数是被乘数
第3个源操作数是乘数
第1个源操作数是加数或减数,目标操作数原来存放的就是加数或减数。
vfmadd231psymm0,ymm1,ymmwordptr[mem]
----- ---- -----------------
加数 被乘数 乘数
这是一条典型的FMA3指令,它的运算方式是:
ymm0=(ymm1*[mem])+ymm0。
然而,同样的运算对应的FMA4指令的语法则是:
vfmaddpsymm0,ymm1,ymmwordptr[mem],ymm0
从上例执行fused-multiply-add操作中我们已经可以隐约看出Intel和AMD在指令设计中的差异。
再以上面的VFMADDSD指令为例:
在AMD的FMA4设计中,只存在这种模式:
VFMADDSDdest,src1,src2,src3→dest=src1*src2+src3
无论指令操作数如何变化都是按照这个种模式进行运算。
这种4个操作数的设计模式提供了更大的灵活性。
需要使用特定的操作数运算,只需改变操作数的位置便可实现了。
在Intel的FMA3设计中,存在3种运算模式:
VFMADD132SDdest,src1,src2→dest=dest*src2+src1
VFMADD213SDdest,src1,src2→dest=dest*src1+src2
VFMADD231SDdest,src1,src2→dest=src1*src2+dest
FMA3指令通过对指令mnemonic(助记符)的修饰达到实现多种运算模式的目的,在这种情况下产生了3条opcode码,这是3条不同的指令opcode,可是实际上只进行了一种运算,就是fused-multiply-add(融合乘加运算)。
它的好处是:
灵活多样,在某些指令中已经赋值给某个寄存器的情况下,可以从中选择一种合适的指令来执行fused-multiply-add运算,来保证某一个操作数不被改变。
弊端是:
多增加了opcode码,可能会让人感觉有些混乱。
并且更重要的是会改变dest操作数原有的值。
不过,总体来说FMA3和FMA4的设计是殊途同归,目的和意图是一样的。
Intel提供了96条FMA3指令,其中36条256位浮点vector运算,60条128位的浮点运算,包括:
vector数据与scalar数据。
AMD提供了64条FMA4指令,其中24条256位浮点vector运算,40条128位的浮点运算,包括:
vector数据与scalar数据。
实际上FMA4与FMA3指令在规格上是一一对应的。
表面上看FMA4比FMA3少了32条指令,其实这是因为FMA3指令采用了多个opcode的设计方案,这才导至了FMA3指令比FMA4指令多出了32条,但这完全不影响FMA3与FMA4指令是一一对应的事实。
可是这样又重新步入了指令斗争的漩涡。
理论上说支持4个操作数的FMA4设计更为优越,灵活性更大,并且重要的是FMA4并不改变dest操作数原有的值。
但实际情况中FMA3与FMA4谁胜谁负只有等待2013年Haswell微架构推出之后以见分晓。
AES与CLMUL指令简介
Intel从Westmere微架构处理器开始就加入了对AES(AES-NI)指令和CLMUL指令的支持,而AMD也将在推土机微架构处理器中提供对AES和CLMUL指令的支持。
AES指令
在2010年5月,Intel更新了官方术语,将AES称为AES-NI(AESNewInstructions),在发布的AESNI指令集中分两个版本各6条指令:
AES版本,也就是SSE版本,它使用了原来的SSE指令的编码规则,仅支持2个操作数,在处理器的CPUID标志中只需要为支持AES即可。
AES版本有6条指令,分别为:
AESENC,AESENCLAST,AESDEC,AESDECLAST,AESKEYGENASSIST以及AESIMC。
AVX版本,使用了AVX指令的编码规则,支持3个操作数,在处理器CPUID标志中需要同时支持AES与AVX标志。
对应的AVX版本也有6条指令,分别为:
VAESENC,VAESENCLAST,VAESDEC,VAESDECLAST,VAESKEYGENASSIST以及VAESIMC。
AES-NI指令从硬件层上支持加密、解密运算,这有软件层上运算无法比拟的效能优势,其中4条AES-NI指令是对round进行加密、解密,2条AES-NI指令用来产生roundkey。
CLMUL指令
CLMUL指令执行的是Carry-lessmultiplication(无进位乘)操作,实际上做的是复杂的二进制多项式乘法。
CLMUL也分为SSE版本和AVX版本各1条,分为:
PCLMULQDQ(SSE版本)以及VPCLMULQDQ(AVX版本)。
CLMUL类似于AES-NI指令在加密、解密方面得到广泛的应用。
XOP指令的特色
AMD在2007年公布SSE5指令集规范,SSE5指令是原生的128位设计,提供了几大特色:
浮点multiply-add/subtract运算;整数multiply-add/subtract运算;整数horizontal-add/subtract运算;矢量条件move操作;整数rotate和shift操作;浮点和整数comparison操作;test操作;round操作;convert操作
事实上XOP指令集和FMA指令集都脱胎于SSE5指令集,它们是在SSE5指令集的基础上,使用了与AVX指令同样的编码设计规则重新设计的指令集。
而原来定义的SSE5指令集已经宣告废止。
现在的XOP指令与SSE5定义的指令格式已经大相庭径。
也就是说同FAM一样,XOP指令集中大量的指令都是从SSE5分离出来的整数运算指令,它的特色包括:
1.XOP指令集原生是128位的设计:
在256位执行环境中,指令使用128位的xmm寄存器,结果会使相应的ymm寄存器高128位清0。
只有少数指令会使用256位的ymm寄存器
2.提供强大的integer(整数)运算:
将SSE5指令中的integer运算分离形成XOP指令,主要体现在多样的整数multiply-add/subtract运算;整数rotate与shift运算;以及多样的comparison与test运算。
3.引进3个byes的XOPprefix编码设计方案:
这个设计方案来源于AVX指令集,舍弃了原来SSE5指令集中的SIMDprefix与escapeopcode,XOPprefix使用了8F这个opcode。
XOP指令的integer运算
与AVX指令强大的float(浮点)运算形成鲜明的对比,XOP指令着重于integer(整数)运算,包括:
multiply-add/subtract运算,它执行的是:
整数的(a*b)+c
multiply-add-accumulate运算,这是一个相乘后相加再累加的运算。
Horizontaladd/subtract运算:
这类指令只有两个操作数,在源操作数内进行加/减运算。
Vectorconditionalmove操作:
实现了在bit级别的条件选择赋值操作vpcmov指令。
packedintegerrotate/shift操作:
这类指令分为shift(位移)和rotate(循环)两类操作,每类操作可以实现多种元素单位,包括:
byte,word,doubleword以及quadword这4种元素。
shift操作实现了logic(逻辑)位移以及arithmetic(算术)位数,其意义与通用指令中的logic/arithmetic位移是一致的。
packedintegercomparison操作:
这类比较指令分为unsigned(无符号数)比较和singed(符号数)比较,同样操作在byte,word,doubleword以及quadword元素大小。
fractionextract指令:
最后一部分是提取浮点数中的小数(或者分数)部分,这是XOP指令中少量的浮点数处理指令。
这些指令将提供单精度或双精度浮点数的分数部分,结果放入目标寄存器相应的元素大小部分。
AVX与XOP指令编码设计方案对比
XOP指令与AVX指令采取了相同的编码设计规则,在XOP指令中使用了3bytes的XOPprefix来定义XOP指令集,这个XOPprefix是8F字节,AVXprefix采用了C4/C5作为AVXprefix,在AVX指令的定义中区分了AVX128和AVX256指令,分别处理128位和256位数据,这是通过VEX.L来实现,XOP指令中同样使用XOP.L来确定128位和256位数据的处理。
接下来,由于篇幅有限笔者只简要介绍一下它们的编码设计方案,AVX与XOP指令编码与通用指令结构上是一致的,如下图3所示:
这个ExtendedPrefix是AVXprefix或者XOPprefix,在AVXprefix中分为2bytes与3bytes,XOPprefix仅使用3bytes,AVX/XOPprefix,opcode以及ModRM是必须提供,其它部分是可选的。
Extendedprefix部分是确定AVX指令还是XOP指令的关键。
图3
SSE指令的特殊prefix
SSE系列指令将x86指令系统推上复杂化,它们常使用两个特殊的prefix作为opcode的一部分:
escapeopcode(或称escapeprefix),包括:
0F,0F38以及0F3A
SIMDprefix,包括:
66,F2以及F3
它们事实上会作为指令的opcode组成部分一起被提供在指令参考手册上,已经脱离了原本作为prefix的意义。
AVXprefix与XOPprefix结构
从图4中我们可以了解到AVX与XOP的组成部分:
第1个字节是C4/8F(3bytes),C5(2bytes)接下来的2个字节或1个字节,组成部分为:
图4
VEX.R,VEX.X,VEX.B;VEX.mmmmm;VEX.W;VEX.vvvvv;VEX.L;VEX.pp
大部分情况下,同一条AVX指令可以选择实现2bytes的版本或者3bytes的版本,满足指令中的escapeopcode为0F或无需扩展ModRM.r/m域,SIB.base以及SIB.base这两种情况时3bytes版本可以转为2bytes版本。
主流的编译器会优先选择生成2bytesVEXprefix的AVX指令encode,以产生更短的指令序列。
AVXprefix与XOPprefix的集成功能
1、集成了REXprefix
VEX.RXB以及VEX.W是对通用指令中的REXprefix提供了对扩展registers的访问功能,与REXprefix一样,我们能够对扩展的新寄存器进行访问。
2、集成了escapeopcode
VEX.mmmmm域中集成了escapeopcode,VEX.mmmmm使用5bits来表达,这样使得它可以在未来的指令集中可以扩展更多的escapeopcode。
3、集成了SIMDprefix
VEX.pp集成了原有的SIMDprefix。
由于VEXprefix对原SSE指令opcode部分的集成,使得AVX指令轻易地从SSE指令转为AVX指令,除了新提供的AVX指令外,大部分AVX指令都有对应的SSE版本。
XOP.mmmmm与VEX.mmmmm存在区别,XOP.mmmmm不集成escapeopcode,它有两个选项值,意
义是:
XOP.mmmmm=8时,表示指令需要immediate操作数
XOP.mmmmm=9时,表示指令不需要immediate操作数
与此同时,VEX.vvvv(XOP.vvvv)是提供源或目标操作数的寄存器寻址,这个寄存器编码与原有的寄存器编码是相反的。
操作数的寻址
AVX指令和XOP指令都可以提供4个操作数的寻址,这4个操作数是:
ModRM.regVEX.vvvv(或XOP.vvvv)ModRM.r/mimm8[7:
4]
对于只有两个操作数的指令来说,VEX.vvvv将不需要提供寻址,VEX.vvvv必须置为1111值,额外的第4个操作数(第3个源操作数)有两个情境:
寄存器操作数:
由8位immediate操作数的高4位提供;立即数操作数:
这种情况下它提供的是immediate值,大多数表现为一些mask值。
展望
从编码设计方式来看,Intel无疑再次获得了行业的话语权,统一了未来一段时间的指令设计方式。
但从实际指令集来看,AMD重新定义了SSE5指令,根据AVX编码方式扩展出了XOP、FMA4等一系列更完善的指令集。
在保证了兼容性的基础上,强化了整数运算效能。
这也从侧面印证了AMD要将异构运算进行到底的未来规划。
毕竟Radeon系列GPU的浮点运算能力十分出众,对于未来的APU来说,x86核心更多的是负责整数运算,加强指令集整数运算的效能显然符合AMD的预期。
至于新一代处理器指令集的效能究竟几何,还跟实际处理器的架构和运行程序的优化程度有关,究竟鹿死谁手还让我们拭目以待。