var = (var << shift) | (var >> (sizeof(var)*CHAR_BIT-shift))
不要使用此代码。它在shift
为 0 时具有未定义的行为。英特尔的 ICC 删除具有未定义行为的语句。我知道第一手资料。
另外,代码不会通过 Clang 或 GCC 的未定义行为清理程序。如需阅读,请参阅 Clang 的Controlling Code Generation或 GCC 的Undefined Behavior Sanitizer – ubsan。
我得到的错误是:
未知大小后缀的指令助记符的未知使用
您正在使用两种工具之一 - GCC 或 Clang。我认为 Apple 在 Xcode 4 前后默认切换到 Clang,因此您可能正在使用 Clang。
GCC 将委托给 GNU AS (GAS),而 Clang 将使用它的 Integrated Assembler。在这两种情况下,您都应该使用 AT&T 内联汇编,因为 Clang 对 Intel 汇编的支持参差不齐。例如,Clang 目前无法生成否定指令(又名LLVM 错误 24232)。
使用 Clang 时,需要指定操作数大小。因此,您将使用rolb
, rolw
, roll
, and rolq
and 朋友。这记录在 Clang 的语言兼容性 | 内联汇编页面。
这是 8 位旋转的样子:
// Immediate
inline word8 rotlImmediate8 (word8 x /*value*/, unsigned int y /*rotate*/)
{
__asm__ ("rolb %1, %0" : "+mq" (x) : "I" ((unsigned char)y));
return x;
}
// Immediate or register
inline word8 rotl8 (word8 x /*value*/, unsigned int y /*rotate*/)
{
__asm__ ("rolb %1, %0" : "+mq" (x) : "cI" ((unsigned char)y));
return x;
}
// Immediate
inline word8 rotrImmediate8 (word8 x /*value*/, unsigned int y /*rotate*/)
{
__asm__ ("rorb %1, %0" : "+mq" (x) : "I" ((unsigned char)y));
return x;
}
// Immediate or register
inline word8 rotr8 (word8 x /*value*/, unsigned int y /*rotate*/)
{
__asm__ ("rorb %1, %0" : "+mq" (x) : "cI" ((unsigned char)y));
return x;
}
8 位字需要对约束进行特殊处理。你不能使用+g
; 而是你需要+mq
。
这是 16 位字版本:
// Immediate
inline word16 rotlImmediate16 (word16 x /*value*/, unsigned int y /*rotate*/)
{
__asm__ ("rolw %1, %0" : "+g" (x) : "I" ((unsigned char)y));
return x;
}
// Immediate or register
inline word16 rotl16 (word16 x /*value*/, unsigned int y /*rotate*/)
{
__asm__ ("rolw %1, %0" : "+g" (x) : "cI" ((unsigned char)y));
return x;
}
// Immediate
inline word16 rotrImmediate16 (word16 x /*value*/, unsigned int y /*rotate*/)
{
__asm__ ("rorw %1, %0" : "+g" (x) : "I" ((unsigned char)y));
return x;
}
// Immediate or register
inline word16 rotr16 (word16 x /*value*/, unsigned int y /*rotate*/)
{
__asm__ ("rorw %1, %0" : "+g" (x) : "cI" ((unsigned char)y));
return x;
}
这是 32 位版本:
// Immediate
inline word32 rotlImmediate32 (word32 x /*value*/, unsigned int y /*rotate*/)
{
__asm__ ("roll %1, %0" : "+g" (x) : "I" ((unsigned char)y));
return x;
}
// Immediate or register
inline word32 rotl32 (word32 x /*value*/, unsigned int y /*rotate*/)
{
__asm__ ("roll %1, %0" : "+g" (x) : "cI" ((unsigned char)y));
return x;
}
// Immediate
inline word32 rotrImmediate32 (word32 x /*value*/, unsigned int y /*rotate*/)
{
__asm__ ("rorl %1, %0" : "+g" (x) : "I" ((unsigned char)y));
return x;
}
// Immediate or register
inline word32 rotr32 (word32 x /*value*/, unsigned int y /*rotate*/)
{
__asm__ ("rorl %1, %0" : "+g" (x) : "cI" ((unsigned char)y));
return x;
}
最后,这是 64 位版本。你应该用类似的东西来保护它__amd64
or __x86_64__
。因为旋转量可以是[0,63]
,所以您使用J
约束。
// Immediate
inline word64 rotlImmediate64 (word64 x /*value*/, unsigned int y /*rotate*/)
{
__asm__ ("rolq %1, %0" : "+g" (x) : "J" ((unsigned char)y));
return x;
}
// Immediate or register
inline word64 rotl64 (word64 x /*value*/, unsigned int y /*rotate*/)
{
__asm__ ("rolq %1, %0" : "+g" (x) : "cJ" ((unsigned char)y));
return x;
}
// Immediate
inline word64 rotrImmediate64 (word64 x /*value*/, unsigned int y /*rotate*/)
{
__asm__ ("rorq %1, %0" : "+g" (x) : "J" ((unsigned char)y));
return x;
}
// Immediate or register
inline word64 rotr64 (word64 x /*value*/, unsigned int y /*rotate*/)
{
__asm__ ("rorq %1, %0" : "+g" (x) : "cJ" ((unsigned char)y));
return x;
}
Clang 不会像 GCC 那样传播常量,因此您可能在使用 Immediate-8 版本的旋转时遇到问题。另请参阅Force Clang 以对 Stack Overflow上的常量值“提前执行数学运算”和LLVM 错误 24226。
您应该花时间访问 John Regehr 的Safe, Efficient, and Portable Rotate in C/C++。它是一种反高潮。它说一旦您在 C/C++ 中正确编写了旋转(即没有未定义的行为),它将不再被识别为旋转,并且不会生成旋转指令。
最后,另请参阅不违反Stack Overflow 标准的近乎恒定时间旋转。