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 将使用其集成汇编器。在这两种情况下,您都应该使用 AT&T 内联汇编,因为 Clang 对 Intel 汇编的支持参差不齐。例如,目前是Clang can't generate a negate instructions(又名LLVM Bug 24232)。
使用 Clang 时,需要指定操作数大小。因此,您将使用rolb、rolw、roll 和rolq 和朋友。这记录在 Clang 的 Language Compatibility | Inline Assembly 页面中。
这是 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 或__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 版本的旋转时遇到问题。另请参阅 Stack Overflow 上的 Force Clang to “perform math early” on constant values 和 LLVM Bug 24226。
您应该花时间访问 John Regehr 的Safe, Efficient, and Portable Rotate in C/C++。它是一种反高潮。它说一旦您在 C/C++ 中正确编写了旋转(即没有未定义的行为),它将不再被识别为旋转,并且不会生成旋转指令。
最后,请参阅 Stack Overflow 上的 Near constant time rotate that does not violate the standards。