缺少优化: mov al, [mem] 位域将新的低字节插入整数

Hom*_*512 8 c assembly x86-64 micro-optimization

我想替换整数中的最低字节。在 x86 上这确实是这样mov al, [mem],但我似乎无法让编译器输出它。我是否遗漏了一个明显的可识别代码模式,我是否误解了某些内容,或者这只是一个错过的优化?

unsigned insert_1(const unsigned* a, const unsigned char* b)
{
    return (*a & ~255) | *b;
}
unsigned insert_2(const unsigned* a, const unsigned char* b)
{
    return *a >> 8 << 8 | *b;
}
Run Code Online (Sandbox Code Playgroud)

GCC 实际上使用al但只是为了归零。

        mov     eax, DWORD PTR [rdi]
        movzx   edx, BYTE PTR [rsi]
        xor     al, al
        or      eax, edx
        ret
Run Code Online (Sandbox Code Playgroud)

Clang 几乎逐字编译两者

        mov     ecx, -256
        and     ecx, dword ptr [rdi]
        movzx   eax, byte ptr [rsi]
        or      eax, ecx
        ret
Run Code Online (Sandbox Code Playgroud)

Eri*_*idt 7

在 x86 上这确实是这样mov al, [mem],但我似乎无法让编译器输出它。

试试这个,无需算术:

unsigned insert_4(const unsigned* a, const unsigned char* b)
{
    unsigned int t = *a;
    unsigned char *tcp = (unsigned char *) & t;
    tcp[0] = *b;
    return t;
}

Run Code Online (Sandbox Code Playgroud)
insert_4(unsigned int const*, unsigned char const*):
        mov     eax, DWORD PTR [rdi]
        mov     al, BYTE PTR [rsi]
        ret
Run Code Online (Sandbox Code Playgroud)

我知道有点奇怪,但编译器擅长删除局部变量的间接寻址和地址(尽管尝试了几次......)。

godbolt x86-64 gcc 13.1 -O3


使用 union 的替代方案:

unsigned insert_5(const unsigned* a, const unsigned char* b)
{
    union {
        unsigned int ui;
        unsigned char uc;
    } u;
    u.ui = *a;
    u.uc = *b;
    return u.ui;
}
Run Code Online (Sandbox Code Playgroud)

godbolt x86-64 gcc 13.1 -O3


请注意,这些解决方案是特定于字节序的,尽管它看起来像您正在寻找的,并且可以根据需要针对其他字节序进行调整。

  • 呵呵,这甚至可以在 ARM 上编译为“BFI”。这确实很奇怪,但我无法否认结果。 (4认同)