1

我正在尝试组装以使用我以前从未真正使用过的向量操作,并且我承认在掌握一些语法时遇到了一些麻烦。

相关代码如下。

unit16_t asdf[4];
asdf[0] = 1;
asdf[1] = 2;
asdf[2] = 3;
asdf[3] = 4;
uint16_t other = 3;

__asm__("movq %0, %%mm0"
        :
        : "m" (asdf));
__asm__("pcmpeqw %0, %%mm0"
        :
        : "r" (other));
__asm__("movq %%mm0, %0" : "=m" (asdf));

printf("%u %u %u %u\n", asdf[0], asdf[1], asdf[2], asdf[3]);

在这个简单的示例中,我尝试对数组中的每个元素进行 16 位“3”比较。我希望输出是“0 0 65535 0”。但它甚至不会组装。

第一条汇编指令给了我以下错误:

错误:内存输入 0 不可直接寻址

第二条指令给了我一个不同的错误:

错误:“pcmpeqw”的后缀或操作数无效

任何帮助,将不胜感激。

4

4 回答 4

4

您不能直接在 gcc asm 语句中使用寄存器并期望它们与其他 asm 语句中的任何内容相匹配——优化器会四处移动。相反,您需要声明适当类型的变量并使用约束将这些变量强制放入您正在使用的指令的正确类型的寄存器中。

MMX/SSE 的相关约束适用x于 xmm 寄存器和ymmx 寄存器。对于您的示例,您可以执行以下操作:

#include <stdint.h>
#include <stdio.h>

typedef union xmmreg {
    uint8_t   b[16];
    uint16_t  w[8];
    uint32_t  d[4];
    uint64_t  q[2];
} xmmreg;

int main() {
    xmmreg v1, v2;
    v1.w[0] = 1;
    v1.w[1] = 2;
    v1.w[2] = 3;
    v1.w[3] = 4;
    v2.w[0] = v2.w[1] = v2.w[2] = v2.w[3] = 3;
    asm("pcmpeqw %1,%0" : "+x"(v1) : "x"(v2));
    printf("%u %u %u %u\n", v1.w[0], v1.w[1], v1.w[2], v1.w[3]);
}

请注意,您需要显式复制3第二个向量的所有相关元素。

于 2014-02-24T21:41:26.473 回答
3

来自英特尔参考手册:

PCMPEQW mm, mm/m64        Compare packed words in mm/m64 and mm for equality.
PCMPEQW xmm1, xmm2/m128   Compare packed words in xmm2/m128 and xmm1 for equality.

pcmpeqw使用了错误的“r”寄存器。只有“mm”和“m64”寄存器

瓦尔特

于 2014-02-24T19:03:40.073 回答
0

他是对的,优化器正在更改寄存器内容。切换到内在函数并使用 volatile 使事情保持原状可能会有所帮助。

于 2014-04-24T08:54:54.607 回答
0

上面的代码在扩展时失败了asm(),它甚至没有尝试组装任何东西。在这种情况下,您尝试使用第零个参数 ( %0),但您没有提供任何参数。

查看GCC Inline assembler HOWTO,或阅读当地 GCC 文档的相关章节。

于 2014-02-24T20:00:58.140 回答