【发布时间】:2019-06-25 04:50:39
【问题描述】:
我正在寻找一种更紧凑的方法来从<8 x float>(例如ymm0)寄存器中提取连续的<4 x float>(例如xmm0),最终将使用SIMD 向量宽度命名。
这是按预期工作的,但相当复杂:
%out.1 = extractelement <8 x float> %out.0, i32 0
%out.2 = extractelement <8 x float> %out.0, i32 1
%out.3 = extractelement <8 x float> %out.0, i32 2
%out.4 = extractelement <8 x float> %out.0, i32 3
%out.5 = insertelement <4 x float> undef, float %out.1, i32 0
%out.6 = insertelement <4 x float> %out.5, float %out.2, i32 1
%out.7 = insertelement <4 x float> %out.6, float %out.3, i32 2
%out.8 = insertelement <4 x float> %out.7, float %out.4, i32 3
有没有更精简的方法来完成同样的任务?
【问题讨论】:
-
总是高 4 (
vextractf128) 还是低 4(只是重新解释)?或者您有时是否需要元素 2..5 或其他内容,并希望 LLVM 优化为vpermpd ymm, ymm, imm以在 xmm 中创建您想要的结果? (或带有元素 1..4 或 3..6 的矢量控制的vpermps。)我实际上不太了解 LLVM-IR,但如果它可以在一个 LLVM-IR 中表达任何 x86 shuffle 指令指令,使用它。 -
它将始终是高位或低位部分,无需洗牌,只需一个不同的寄存器名称。但是,如果 LLVM 用寄存器名称更改替换它,则在 IR 中使用 shuffle 可能是一种选择。我会尝试并报告。
-
@PeterCordes 这就是诀窍。谢谢!
-
提取高 128 确实需要 x86 asm 中的洗牌,例如
vextractf128。它不像 ARM32 那样,q10的高半部分和低半部分别名为d21和d20,可以直接访问。只有 YMM 的低半部分被 XMM reg 别名。但无论如何,肯定就像在你的答案中一样,你可以将它写成一个随机播放,每个元素都有一个单独的索引,如果你使用不同的索引,LLVM 会将它编译为一个提取物,或者什么都没有,或者编译为vpermps。