我试图在不使用内联程序集的情况下有效地实现SHLD
和SHRD
的x86
指令。
uint32_t shld_UB_on_0(uint32_t a, uint32_t b, uint32_t c) {
return a << c | b >> 32 - c;
}
似乎工作,但调用未定义的行为时,c == 0
,因为第二班的操作数变成32
。第三个操作数为0
的实际0
指令被很好地定义为什么也不做。(https://www.felixcloutier.com/x86/shld)
uint32_t shld_broken_on_0(uint32_t a, uint32_t b, uint32_t c) {
return a << c | b >> (-c & 31);
}
不会调用未定义的行为,但是当c == 0
时,结果是a | b
而不是a
。
uint32_t shld_safe(uint32_t a, uint32_t b, uint32_t c) {
if (c == 0) return a;
return a << c | b >> 32 - c;
}
实现了预期的目标,但是gcc
现在提供了一个je
。另一方面,clang
足够聪明地将其转换为单个shld
指令。
是否有任何方法可以在不进行内联装配的情况下正确有效地实现它?
为什么gcc
这么不想把shld
放进去?shld_safe
尝试由gcc
11.2 -O3 as (哥德波特)翻译:
shld_safe:
mov eax, edi
test edx, edx
je .L1
mov ecx, 32
sub ecx, edx
shr esi, cl
mov ecx, edx
sal eax, cl
or eax, esi
.L1:
ret
当嘎嘎作响的时候,
shld_safe:
mov ecx, edx
mov eax, edi
shld eax, esi, cl
ret
发布于 2022-04-09 03:33:10
就我使用gcc 9.3 (x86-64)进行的测试而言,它将下面的代码转换为shldq
和shrdq
。
uint64_t shldq_x64(uint64_t low, uint64_t high, uint64_t count) {
return (uint64_t)(((((unsigned __int128)high << 64) | (unsigned __int128)low) << (count & 63)) >> 64);
}
uint64_t shrdq_x64(uint64_t low, uint64_t high, uint64_t count) {
return (uint64_t)((((unsigned __int128)high << 64) | (unsigned __int128)low) >> (count & 63));
}
另外,gcc -m32 -O3
将以下代码转换为shld
和shrd
。(不过,我还没有和gcc (i386)做过测试。)
uint32_t shld_x86(uint32_t low, uint32_t high, uint32_t count) {
return (uint32_t)(((((uint64_t)high << 32) | (uint64_t)low) << (count & 31)) >> 32);
}
uint32_t shrd_x86(uint32_t low, uint32_t high, uint32_t count) {
return (uint32_t)((((uint64_t)high << 32) | (uint64_t)low) >> (count & 31));
}
(我刚读过gcc的代码,写了上面的函数,即我不确定它们是否是你所期望的。)
https://stackoverflow.com/questions/70657806
复制相似问题