C 8位旋转的内联程序集大小不匹配

C 8位旋转的内联程序集大小不匹配,c,x86,inline-assembly,att,C,X86,Inline Assembly,Att,我正在尝试使用内联汇编在C中编写向左旋转操作,如下所示: byte rotate_left(byte a) { __asm__("rol %0, $1": "=a" (a) : "a" (a)); return a; } (其中字节类型定义为无符号字符) 这就产生了错误 /tmp/ccKYcEHR.s:363:错误:“rol”的操作数大小不匹配 这里有什么问题?AT&T语法使用与Intel语法相反的顺序。旋转计数必须是第一个,而不是最后一个:rol$1,%0 此外,您不需要也

我正在尝试使用内联汇编在C中编写向左旋转操作,如下所示:

byte rotate_left(byte a) {
    __asm__("rol %0, $1": "=a" (a) : "a" (a));
    return a;
}
(其中字节类型定义为无符号字符)

这就产生了错误

/tmp/ccKYcEHR.s:363:错误:“rol”的操作数大小不匹配


这里有什么问题?

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


此外,您不需要也不应该为此使用内联asm:

如中所述,GNU C具有用于窄旋转的内部函数,因为旋转惯用法识别代码无法优化旋转计数的
。x86移位/旋转使用
count&31
屏蔽计数,即使是8位和16位,但仍会旋转环绕。不过,这对轮班确实很重要

无论如何,gcc有一个内置函数用于窄旋转,以避免任何开销。在
x86intrin.h
中有一个
\uuuu rolb
包装器,但是MSVC使用自己的
\uuuu rotr8
等等。无论如何,clang既不支持
\uu内置的
也不支持
x86intrin.h
包装器,但gcc和ICC支持

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

这为您提供了一个函数,它可以像内联asm一样高效地编译,但可以完全优化编译时常量,编译器知道它是如何工作的/它做什么,并且可以相应地进行优化。

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


此外,您不需要也不应该为此使用内联asm:

如中所述,GNU C具有用于窄旋转的内部函数,因为旋转惯用法识别代码无法优化旋转计数的
。x86移位/旋转使用
count&31
屏蔽计数,即使是8位和16位,但仍会旋转环绕。不过,这对轮班确实很重要

无论如何,gcc有一个内置函数用于窄旋转,以避免任何开销。在
x86intrin.h
中有一个
\uuuu rolb
包装器,但是MSVC使用自己的
\uuuu rotr8
等等。无论如何,clang既不支持
\uu内置的
也不支持
x86intrin.h
包装器,但gcc和ICC支持

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

这为您提供了一个函数,它可以像内联asm一样高效地编译,但可以完全优化编译时常量,并且编译器知道它是如何工作的/它做了什么,并且可以相应地进行优化。

在哪里定义
byte
?使用AT&T语法,src和destination是相反的。也许你的意思是
“rol$1,%0”
这不需要内联汇编(至少对于gcc和clang来说),你在哪里定义
字节
?使用at&T语法,src和destination是相反的。也许你的意思是,
“rol$1,%0”
正如上面所说,这不需要内联汇编(至少对于gcc和clang),gcc,所以它甚至似乎不需要使用任何内在的;然而,令人好奇的是,VC++和icc都无法识别它。@MatteoItalia:它可以识别,但如果没有
来屏蔽运行时变量计数,很难让它发出
rolb
。也许是在习语识别器能够处理字节和16位旋转之前添加了内置代码;我没有检查旧的gcc版本。更新:VC++如果我在
uint8\u t
中随意添加一些强制类型转换(即使只有一个在左班次上似乎也能正常工作)。嗯,是的,运行时已知的班次更为棘手;我只是在测试“按固定值旋转”,因为OP在他的问题中就是这么写的。尽管如此,7.2处理得很好-看不到
。通过快速的二进制搜索,它似乎从4.9.0开始巧妙地处理它;4.8.5仍然为此生成了可怕的代码;然而,令人好奇的是,VC++和icc都无法识别它。@MatteoItalia:它可以识别,但如果没有
来屏蔽运行时变量计数,很难让它发出
rolb
。也许是在习语识别器能够处理字节和16位旋转之前添加了内置代码;我没有检查旧的gcc版本。更新:VC++如果我在
uint8\u t
中随意添加一些强制类型转换(即使只有一个在左班次上似乎也能正常工作)。嗯,是的,运行时已知的班次更为棘手;我只是在测试“按固定值旋转”,因为OP在他的问题中就是这么写的。尽管如此,7.2处理得很好-看不到
。通过快速的二进制搜索,它似乎从4.9.0开始巧妙地处理它;4.8.5仍然为此生成了可怕的代码。