当 x 是 uint8 时 x |= 128 的好奇 gcc 编译器代码

curious gcc compiler code for x |= 128 when x is uint8

我最近偶然发现了一个我不理解的有趣的编译器代码。 取以下代码:

unsigned char x;
...
x |= 127;
x |= 128;

对于第一条语句,编译器生成:

or eax, 0x7f.

然而,对于第二个语句,它变成:

or eax, 0xffffff80

似乎对于小于 127 的值,使用一个字节值,而在 128 个双字之后是首选。

有人知道为什么会这样吗? 我转载了这个 gcc 6.2(我认为是最新的)。

我试图 post 在 gcc 邮件列表(gcc-bugs@gcc.gnu.org 或 gcc-help@gcc.gnu.org )上,但我只收到了发送失败。

两条指令都是 3 字节宽,从反汇编输出中可以看出:

 83 c8 7f                or     [=10=]x7f,%eax
 83 c8 80                or     [=10=]xffffff80,%eax

83 / 1 是 32-bit register / memory with 8-bit sign-extended immediate value:

83 /1 ib    OR r/m32,imm8   r/m32 OR imm8 (sign-extended).

因此实际上它确实改变了 32 位寄存器的不可见部分,但这并不重要。它的效率不低于任何其他方法。除了那些使用 8 位寄存器 halves/quarters 操作的指令外,也没有指令 不会 对 8 位立即值进行符号扩展。但是使用这条指令使得它与其他寄存器的工作方式相同,这些寄存器可以用 r/m32 寻址但不能作为单个字节访问(例如 edi、esi)。