Skip to content

shl nuw + zext adds unnecessary masking #171750

@purplesyringa

Description

@purplesyringa

Godbolt

#include <stdint.h>

uint32_t f(uint16_t x) {
    if (x >= 8192) {
        __builtin_unreachable();
    }
    return (uint16_t)(x << 3);
}

uint32_t g(uint16_t x) {
    if (x >= 8192) {
        __builtin_unreachable();
    }
    return (uint16_t)(x << 3) | ((uint32_t)x << 16);
}

Expected behavior: x fits in 13 bits, so x << 3 fits in 16 bits and the cast can be optimized out. Current lowering:

f(unsigned short):
        shl     edi, 3
        movzx   eax, di ; unnecessary
        ret

g(unsigned short):
        mov     eax, edi
        and     eax, 8191 ; unnecessary
        shl     edi, 16
        lea     eax, [rdi + 8*rax]
        ret

IR recognizes shift as non-wrapping with shl nuw, so this is just a missed opt in isel.

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions