【问题标题】:Errors using inline assembly in C在 C 中使用内联汇编时出错
【发布时间】:2014-03-26 14:18:38
【问题描述】:

我正在尝试汇编,以便使用我以前从未真正使用过的向量运算,而且我承认在掌握一些语法方面有些困难。

相关代码如下。

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' 的后缀或操作数无效

任何帮助将不胜感激。

【问题讨论】:

  • 你在标题中说C,但标记C++
  • 已修复,尽管我认为此示例中的区别并不重要。
  • 为什么不直接使用内在函数?
  • 哪个内在函数可以做到这一点?
  • 它有很多名称,例如_m_pcmpeqw_mm_cmpeq_pi16__builtin_ia32_pcmpeqw。此外,在使用矢量扩展时,您可以简单地使用 == 运算符。请参阅 gcc 文档。

标签: c assembly gcc inline-assembly mmx


【解决方案1】:

来自英特尔参考手册:

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”寄存器

变态

【讨论】:

    【解决方案2】:

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

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

    【讨论】:

    • 问题中错误代码中的所有 asm 语句都包含一个操作数,输入或输出。这不是它有什么问题,而是约束是错误的,所以它扩展到像pcmpeqw %eax, %mm0 这样的东西。 (以及其他错误,例如假设 asm 语句之间的 mm0 连续性。)
    【解决方案3】:

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

    MMX/SSE 的相关约束是 x 用于 xmm 寄存器,y 用于 mmx 寄存器。对于您的示例,您可以这样做:

    #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

    【讨论】:

    • 另外值得一提的是,使用 __m128i pattern = _mm_set_epi16(3);_mm_loadu_si128( (const __m128i*)asdf ); 这样的内部函数会更好。但是,是的,这解决了使用内联汇编的致命缺陷。 stackoverflow.com/tags/inline-assembly/info
    【解决方案4】:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多