gcc内联asm未编译
我目前正试图使用内置的gcc内联asm未编译,c,gcc,inline-assembly,C,Gcc,Inline Assembly,我目前正试图使用内置的popcnt来计算无符号字符数组中的1数 我的函数与常规的\uuu内置的\uu 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
popcnt
来计算无符号字符数组中的1数
我的函数与常规的\uuu内置的\uu 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;
}
size\u t popcnt\u手册(无符号字符*字节,size\t len){
尺寸i,cnt=0;
对于(i=0;i
编译器一直在说
后缀或操作数对于add无效
除了代码中的语法错误(“r”
->:“r”
)之外,您的问题是参数不匹配
查看-S的输出:
add rax, r8b
由于cnt
是大小\u t,bytes[i]
是一个字节,这是您所期望的。Add要求它们的大小相同
我还可以建议使用内置而不是内联asm吗?它可以避免类似这样的问题(以及许多其他问题)
有没有办法在不先将popcnt的结果存储在寄存器中的情况下将其相加
嗯。这实际上是一个完全不同的问题。您所问的错误是由于在单个add
指令中混合了一个字节和一个大小。可以通过执行以下操作来解决:
__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];
}
它“将其存储在寄存器中”“你指的是什么?忘了提我一开始是用内置的,但我想要更快的。有没有办法在不先将popcnt的结果存储在寄存器中的情况下将其相加?你是从“谢谢你的回答”那里得到这个主意的吗?我一定是被这篇博文想说的话弄糊涂了。以下是你的因果报应:)博客上没有日期,但它是用4.8.2写的。那是很久以前的事了,所以事情可能已经改变了。这是我建议使用内置而不是内联的另一个原因。内置可以随着时间的推移而改进,但如果您内联编写,您只能得到您所编写的内容。顺便说一句,如果性能至关重要,那么使用64位popcnt(可能)比重复使用8位快。您需要检查透镜和处理奇数尺寸,但我会尝试并计时。明白。谢谢你的意见
.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