我目前正在尝试使用内置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;
}
编译器一直在说
后缀或操作数无法添加
答案 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;你是指?