为什么在将 C 语言从 unsigned int 向下转换为 unsigned char 时,movl 优于 movb?

Why is movl preferred to movb when translating a C downcast from unsigned int to unsigned char?

考虑将 unsigned 向下转换为 unsigned char

的精简示例
void unsigned_to_unsigned_char(unsigned *sp, unsigned char *dp)
{
  *dp = (unsigned char)*sp;
}

上面的C代码用gcc -Og -S翻译成汇编代码为

movl    (%rdi), %eax
movb    %al, (%rsi)

为什么 C 语言到汇编的翻译不是如下所示?

movb    (%rdi), %al
movb    %al, (%rsi)

是因为这是不正确的,还是因为 movlmovb 更传统,或者编码更短?

当新低字节与相应 32/64 位寄存器的旧高字节合并时,写入 8 位 x86 寄存器可能会产生额外的合并微操作。这也可能导致对寄存器先前值的意外数据依赖。

出于这个原因,在 x86 上只写入通用寄存器的 32/64 位变体通常是个好主意。

你问题中的强制转换是完全不必要的,因为语言无论如何都会在赋值之前有效地执行强制转换,因此它对生成的代码没有任何贡献(删除它并且看不到任何更改,没有错误或警告)。

右边的引用是 unsigned int 类型的,所以,这就是它所做的。给定 32 位总线,执行字解引用(模对齐问题)不会影响性能。

如果你想要其他的,你可以在解引用之前强制转换,如下:

void unsigned_to_unsigned_char(unsigned *sp, unsigned char *dp)
{
  *dp = *(unsigned char *)sp;
}

这将生成您期望的字节移动指令。

https://godbolt.org/z/57nzrsrMe