Assembly 为什么vhaddps指令以如此复杂的方式添加?

Assembly 为什么vhaddps指令以如此复杂的方式添加?,assembly,x86,avx,Assembly,X86,Avx,vhaddps指令以一种非常独特的方式添加: 资料来源: 这是什么原因?本说明适用于哪些用例?看起来设计中有一些特定的想法。它是低128位和高128位通道中的2个通道内haddps指令。大多数AVX指令并没有真正将操作扩展到256位,它们执行两个独立的车道内操作。这使得AVX很难使用,尤其是没有AVX2用于小于128位粒度的车道交叉洗牌 但它节省了晶体管,例如,使vpshufb成为单个32字节的洗牌,而不是2x 16字节的洗牌。AVX2甚至没有提供:必须等待AVX512VBMI 相关:另外,AV

vhaddps指令以一种非常独特的方式添加:

资料来源:

这是什么原因?本说明适用于哪些用例?看起来设计中有一些特定的想法。

它是低128位和高128位通道中的2个通道内haddps指令。大多数AVX指令并没有真正将操作扩展到256位,它们执行两个独立的车道内操作。这使得AVX很难使用,尤其是没有AVX2用于小于128位粒度的车道交叉洗牌

但它节省了晶体管,例如,使vpshufb成为单个32字节的洗牌,而不是2x 16字节的洗牌。AVX2甚至没有提供:必须等待AVX512VBMI

相关:另外,AVX512增加了许多灵活的车道交叉混洗,但AXV512版本的SSE/AVX指令(如vhaddps zmm)仍在车道上。另见

AVX2 vpack*链通常需要vpermq在末端进行车道交叉修正,除非您打算再次在车道中解包。所以在大多数情况下,2x通道内混洗比完整的256位宽操作更糟糕,但这不是我们从AVX得到的。从128位矢量到256位矢量,即使需要额外的洗牌来纠正车道内的行为,通常仍然需要加速,但这通常意味着即使没有内存瓶颈,也不是2倍的加速

VPAligner可能是同一个洗牌的2x 128位版本本身不是一个有用的构建块的最令人震惊的例子;我不记得我是否见过使用两个单独的车道内字节数据窗口的用例。哦,事实上是的,如果您使用vperm2i128为其提供数据,但通常未对齐的负载在支持AVX2的CPU上会更好

VHADDP的用例非常有限 在SSE3中引入HADDP后,英特尔可能计划在某个时候将其制作成一条uop指令,但这从未发生过

用例包括转置和添加类型,在这些情况下,无论如何都需要为垂直添加洗牌两个输入。e、 g.包括VHADDP。加上AVX1 vperm2f128以纠正车道内行为

许多人错误地认为它适用于单个向量的水平求和,但128位和256位VHADDP都会解码为2x洗牌uop,为垂直vaddps uop准备输入向量。对于水平总和,每次添加只需要1个随机uop

使用vextractf128/vaddps将范围缩小到128位优先通常是更好的第一步,除非您希望结果广播到每个元素,并且您不是在AMD CPU上,其中256位矢量运算解码到至少2 UOP,或更多用于车道交叉洗牌。如果您正在优化代码大小而不是速度,则vhaddps xmm或整数vphaddd对于水平和非常有用,例如,在代码高尔夫问题上,计算两个数字的平均值


AVX非破坏性目标操作数还消除了使用多uop指令的一些吸引力。如果没有AVX,有时您无法避免movaps在销毁寄存器之前复制寄存器,因此烘焙2x shuffle+add-into-1指令确实节省了UOP,而不必使用movaps+shufps手动执行此操作。

与许多256位宽的指令一样,上面的128位 vhaddps-ymm-ymm-ymm只是128位宽vhaddps-xmm-xmm的复制粘贴 指示下面的示例表明 以这样一种复杂的方式定义vhaddps xmm xmm:使用此指令两次 提供4个xmm寄存器的水平和

/*gcc-m64-O3 hadd_ex.c-march=sandybridge*/ 包括 包括 int main{ 浮动tmp[4]; __m128 a=_mm_set_ps1.0,2.0,3.0,4.0; __m128 b=_mm_set_ps10.0、20.0、30.0、40.0; __m128 c=_mm_set_ps100.0、200.0、300.0、400.0; __m128 d=_mm_套装_ps1000.0、2000.0、3000.0、4000.0; __m128 sum1=_mm_hadd_psa,b; __m128 sum2=_mm_hadd_psc,d; __m128总和=_mm_hadd_pssum1,sum2; _mm_storeupstmp,总和; printfsum=%f%f%f%f\n,tmp[0],tmp[1],tmp[2],tmp[3]; 返回0; } 输出:

sum = 10.000000  100.000000  1000.000000  10000.000000

我猜你打字的速度比我快多了。@wim:我打字很快,是的:我从一开始就养成了好习惯;我父亲在Atari ST上有一个打字指导游戏,叫做单词入侵者,我在90年代十几岁的时候玩过这个游戏,所以我总是触摸打字,知道你应该如何高效地打字,这是我最喜欢的。到现在为止,我已经练了好几年了PI开始在ZX频谱上打字,这解释了很多。