gcc内联asm没有编译

时间:2017-01-15 23:52:15

标签: c gcc inline-assembly

我目前正在尝试使用内置popcnt来计算unsigned char数组中1的数量。

我让这个函数与常规__builtin_popcount一起工作但是有一些更激进的速度要求,我决定采用内联asm方法。

size_t popcnt_manual( unsigned char *bytes, size_t len ) {
    size_t i, cnt = 0;
    for( i = 0; i < len; i++ ) {
        __asm__(
                 "popcnt %0, %0    \n\t"
                 "add    %0, %1    \n\t"
                 : "+r" (cnt)
                 : "r"  (bytes[i]));
    }

    return cnt;
}

编译器一直在说

  

后缀或操作数无法添加

1 个答案:

答案 0 :(得分:2)

除了代码中的语法错误(" "r" - &gt; : "r")之外,您的问题是参数不匹配。

查看-S:

的输出
 add    rax, r8b

由于cnt是size_t且bytes[i]是一个字节,因此这是您所期望的。添加要求它们具有相同的大小。

我还可以建议使用内置而不是内联asm吗?它避免了这样的问题(以及许多其他问题)。

  

有没有办法将popcnt的结果加起来而不先将它存储在寄存器中?

嗯。这实际上是一个完全不同的问题。您询问的错误是由于在单个add指令中混合了一个字节和一个size_t。可以通过以下方式解决:

    __asm__(
             "popcnt %0, %0    \n\t"
             "add    %0, %1    \n\t"
             : "+r" (cnt)
             : "r"  ((size_t)bytes[i]));

我不应该鼓励你继续添加新的问题(我如何获得我的业力点数?),但是看看那个网站,他似乎在弄乱的代码就是:

uint32_t builtin_popcnt_unrolled_errata(const uint64_t* buf, int len) {
  assert(len % 4 == 0);
  int cnt[4];
  for (int i = 0; i < 4; ++i) {
    cnt[i] = 0;
  }

  for (int i = 0; i < len; i+=4) {
    cnt[0] += __builtin_popcountll(buf[i]);
    cnt[1] += __builtin_popcountll(buf[i+1]);
    cnt[2] += __builtin_popcountll(buf[i+2]);
    cnt[3] += __builtin_popcountll(buf[i+3]);
  }
  return cnt[0] + cnt[1] + cnt[2] + cnt[3];
}

他明确地使用cnt [x]来试图避免错误依赖&#39; popcnt的问题。

使用gcc 6.1并使用-m64 -O3 -march=native -mtune=native进行编译,我将此视为输出:

.L14:
        popcnt  r11, QWORD PTR [rcx]
        add     rcx, 32
        add     edx, r11d
        popcnt  r11, QWORD PTR -24[rcx]
        add     eax, r11d
        popcnt  r11, QWORD PTR -16[rcx]
        add     r10d, r11d
        popcnt  r11, QWORD PTR -8[rcx]
        add     r9d, r11d
        cmp     rcx, r8
        jne     .L14

将其存储在寄存器中&#34;你是指?