我想加载一个带有32位非连续浮点数的128位寄存器。实际上,那些浮点数在内存中间隔128位。
所以如果内存看起来像那样:
| Float 0 | Float X | Float X | Float X |
| Float 4 | Float X | Float X | Float X |
| Float 8 | Float X | Float X | Float X |
| Float 12 | Float X | Float X | Float X |
我想加载这样的矢量:
| Float 0 | Float 4 | Float 8 | Float 12 |
答案 0 :(得分:5)
希望您将其他数据用于某些事情,在这种情况下,加载所有内容并进行转置更有可能是有用的。
如果没有,那么只要数据在向量中有很多工作要做,那么SIMD根本就是可行的,因为将它打包到向量中是很昂贵的。
movss
/ insertps
如@ zx485所示,答案是“正常”的方式,就像您使用_mm_set_ps(f[12], f[8], f[4], f[0]);
时可能从编译器中得到的那样
当你的步幅正好是4时,使用AVX你可以用两个负载跨越所有四个浮点数并混合。
(相关:What's the fastest stride-3 gather instruction sequence?或者对于步幅2,更值得做矢量加载和改组。)
vmovups ymm1, [float0] ; float0 and float4 in the low element of low/high lanes
vblendps ymm1, [float8 - 4], 0b00100010 ; { x x f12 f4 | x x f8 f0 }
这不是很好,因为您可能会与其中一个加载跨越缓存行边界。对于第二次加载,您可以使用vshufps ymm0, ymm1, [float8], 0b???????
获得类似的东西。
这可能会很好,具体取决于周围的代码,特别是如果您有vpermps
的AVX2(具有随机控制向量常量)或vpermpd
(带有立即数)用于交叉路由的随机播放将你想要的元素放入低128b的通道。
如果没有AVX2进行跨车道随机播放,您需要vextractf128
然后shufps
。这可能需要提前做一些计划,以便在shufps
可以将它们放在正确位置的位置放置元素。
当然,这一切都与内在函数一起使用,但它们需要更多的输入。
答案 1 :(得分:2)
如果你有AVX2可用,你可以使用VGATHERDPS指令来实现你的目标,解释here in this SO answer。在你的情况下,你只需要将index-vector初始化为0,1,2,3,...(并使用聚集寻址模式将其扩展到0,4,8,12)。
.data
.align 16
ddIndices dd 0,1,2,3
dpValues REAL4 ... ; replace 'dpValues' with your value array
.code
lea rsi, dpValues
vmovdqa xmm7, ddIndices
.loop:
vpcmpeqw xmm1, xmm1 ; set to all ones
vpxor xmm0, xmm0 ; break dependency on previous gather
vgatherdps xmm0, [rsi+xmm7*4], xmm1
; do something with gather result in xmm0
add rsi, 16
cmp rsi, end_pointer
jb .loop ; do another gather with same indices, base+=16
XMM1是condition mask
,用于选择加载的元素。
请注意,这个指令在Haswell上并不是那么快,但是在Broadwell上实现速度更快,而在Skylake上实现速度更快。
即便如此,对于小步幅负载使用收集指令可能只是Skylake上8元素ymm向量的胜利。根据{{3}}( 11.16.4聚集指令的注意事项),当数据热时,具有4元素向量的Broadwell硬件采集具有每个元素1.56个周期的最佳情况吞吐量L1D缓存。
在AVX2之前的架构上,我没有办法(我知道)这样做而不会像这样单独加载所有值(使用SSE4.1 Intel's optimization manual或pinsrd
)。
lea esi, dpValues
movss xmm0, [esi] ; breaks dependency on old value of xmm0
insertps xmm0, [esi+4], 1<<4 ; dst element index in bits 5:4 of the imm8
insertps xmm0, [esi+8], 2<<4
insertps xmm0, [esi+12], 3<<4
对于整数数据,最后一条指令为pinsrd xmm0, [esi+12], 3
。
如果没有SSE4.1,则将movss
/ unpcklps
和/ {p>一起随机播放unpcklpd