2017-12-27 1258 views
0

我想写使用内联汇编用C离开操作的旋转,像这样:8位内联汇编大小不匹配旋转

byte rotate_left(byte a) { 
    __asm__("rol %0, $1": "=a" (a) : "a" (a)); 
    return a; 
} 

(凡字节通过typedef unsigned char型)。

这就提出了一个错误

/tmp/ccKYcEHR.s:363: Error: operand size mismatch for `rol'.

有什么问题吗?

+1

你在哪里定义'byte'? – klutt

+0

使用AT&T语法,src和destination是相反的。也许你的意思是'“rol $ 1,%0”' –

+1

https://godbolt.org/g/z6Qof7这里没有必要内联汇编(至少对于gcc和clang) –

回答

3

AT & T语法使用与Intel语法相反的顺序。旋转次数必须是第一次,而不是最后一次:rol $1, %0


而且,你不需要和不应该使用内联汇编本:https://gcc.gnu.org/wiki/DontUseInlineAsm

Best practices for circular shift (rotate) operations in C++描述,GNU C有狭窄的旋转内部函数,因为旋转,惯用语法识别代码失败优化掉旋转计数的and。即使对于8位和16位,x86移位/旋转掩码的计数也为count & 31,但旋转仍然环绕。尽管如此,换班确实很重要。

无论如何,gcc有一个内置函数用于缩小旋转以避免任何开销。在x86intrin.h中有一个__rolb包装,但MSVC使用其自己的__rotr8等等intrin.h。无论如何,clang不支持__builtinx86intrin.h旋转包装,但gcc和ICC都支持。

#include <stdint.h> 
uint8_t rotate_left_byte_by1(uint8_t a) { 
    return __builtin_ia32_rolqi(a, 1); // qi = quarter-integer 
} 

我用uint8_tstdint.h像正常人代替限定byte类型。

这并不能编译铿锵,但it compiles as you'd hope with gcc7.2

rotate_left_byte_by1: 
    movl %edi, %eax 
    rolb %al 
    ret 

这使您尽可能高效编译为您的内联汇编都做不到的功能,但它可以完全优化掉了编译时常量,并且编译器知道它是如何工作的以及它做了什么并且可以相应地进行优化。

+0

如上所述,gcc [确实似乎认识到一个天真的旋转](https://godbolt.org/g/z6Qof7),所以它甚至不需要使用任何内在的;但很奇怪,VC++和icc都无法识别它。 –

+0

@MatteoItalia:它可以识别它,但很难让它在没有'和'的情况下只发布'rolb'来屏蔽运行时变量计数。在成语识别器可以处理字节和16位旋转之前,可能已经添加了内建函数;我没有检查旧的gcc版本。 –

+0

更新:VC++ [确认它](https://godbolt.org/g/fSn6YK)如果我添加一些强制转换为'uint8_t'(即使只是左边的一个似乎工作正常)。 –