【问题标题】:Why is the AVX-256 VMOVAPS Instruction only copying four single precision floats instead of 8?为什么 AVX-256 VMOVAPS 指令只复制四个单精度浮点数而不是 8 个?
【发布时间】:2016-08-16 08:46:26
【问题描述】:

我正在尝试熟悉一些较新的英特尔处理器上可用的 256 位 AVX 指令。我已经验证我的 i7-4720HQ 支持 256 位 AVX 指令。我遇到的问题是,应该复制 8 个单精度浮点值的 VMOVAPS 指令只复制了 4 个。

dot PROC
    VMOVAPS YMM1, ymmword ptr [RCX]                
    VDPPS   YMM2, YMM1, ymmword ptr [RDX], 255      
    VMOVAPS ymmword ptr [RCX], YMM2                 
    MOVSS   XMM0, DWORD PTR [RCX]                  
    RET
dot ENDP

如果您不熟悉调用约定,Visual C++ 2015 预计此函数的返回值(因为它是一个浮点数)在返回时为 XMM0。

除此之外,标准是第一个参数在 RCX 中传递,第二个参数在 RDX 中传递。

这里是调用这个函数的 C 代码。

_declspec(align(32)) float d1[] = { 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f };
_declspec(align(32)) float d2[] = { 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f, 2.0f };
printf("Dot Product Test: %f\n", dot(d1, d2));

点函数的返回值总是8.0。除此之外,我调试了函数,发现在第一条汇编指令之后,只有四个值被复制到 YMM1 中。 YMM1 的其余部分保持为零。

我在这里做错了吗?我查看了英特尔文档和一些第三方文档。据我所知,我做的一切都是正确的。我是否使用了错误的指令?顺便说一句,如果您是来告诉我使用 Intel 编译器内部函数的,请不要打扰。

【问题讨论】:

  • 通过使用ymm0 作为vdpps 的目标,您可以在更少的指令中获得相同的(非工作)行为。然后你不需要存储或重新加载,只需返回。如果__vectorcall ABI 与 SysV ABI 类似,则您可以将非零垃圾留在保持返回值的位之外的部分寄存器中。 (例如,向量 reg 的高元素)。对于这么小的函数,用 asm 手工编写而不是可以内联的东西意味着函数调用开销可能很大。特别是。因为你通过 ref 传递 args,而不是向量 regs。
  • 我刚刚用两分钟写了这段代码来测试汇编指令。我很清楚它可以被优化。

标签: c assembly intel avx avx2


【解决方案1】:

您忘记阅读VDPPS 的指令集参考页。它提到结果分为两半:

VDPPS (VEX.256 encoded version)
DEST[127:0] ← DP_Primitive(SRC1[127:0], SRC2[127:0]);
DEST[255:128] ← DP_Primitive(SRC1[255:128], SRC2[255:128]);

不是VMOVAPS 错了。

【讨论】:

  • 我在调试时读取了寄存器。 VMOVAPS 仅将一半的值复制到 YMM1 中。那是我的问题。
  • 没错。 IIRC 当 Intel 迁移到 256 位宽的寄存器时,他们在旧的寄存器上复制了 128 位单元,并且您实际上为导致数据移动的指令(如洗牌)支付了 车道交叉惩罚从上半部分到下半部分,反之亦然。
  • @A.Robinson 您想要的上半部分点积在 YMM 寄存器的位 [159:128] 中,因此您需要将其洗牌或向下移动,将其相加到下-half dot-product,并将 that 放入 XMM0.
  • 你只返回最低的浮点数,所以你得到8.0,因为VDPPS在那里只产生一半的结果。至于您在调试器中看到的内容,您没有提供任何详细的证明。
  • 那么你的调试器坏了。我无法检查 Visual Studio,但请放心 vmovaps 可以正常工作并加载所有 8 个:(gdb) p $ymm1.v8_float $1 = {1, 1, 1, 1, 1, 1, 1, 1}
【解决方案2】:

我刚刚更新到 Visual Studio 2015 更新二,现在它可以正常工作了。我不知道为什么。我最好的猜测是 MASM 无缘无故地将我的 AVX256 代码转换为 AVX128 代码。不管怎样,问题都解决了。

【讨论】:

  • 如果你有旧的 asm 代码,你可以用反汇编程序检查。
猜你喜欢
  • 2018-12-18
  • 2020-09-26
  • 1970-01-01
  • 1970-01-01
  • 2013-04-08
  • 2010-09-07
  • 1970-01-01
  • 2020-05-28
  • 1970-01-01
相关资源
最近更新 更多