Skip to content

x86-64 optimization: (x <= 0xFFFFF) in '-Os' mode can convert to ((x >> 20) == 0) #149073

@Explorer09

Description

@Explorer09

Test code

#include <stdbool.h>
#include <stdint.h>

bool func1(uint32_t x) {
    return x < 0x100000U;
}

bool func2(uint32_t x) {
    return ((x >> 20) == 0);
}

bool func3(uint32_t x) {
    return ((x / 0x100000U) == 0);
}

The three functions are equivalent. Specifically the threshold constant to be compared with is a power-of-two. If there is no shortage of temporary registers, then the right shift version (that is, func2) will likely make the smallest code.

My expected result is like this (assuming -Os optimization, not -O2)

        shrl    $20, %edi
        sete    %al
        retq

Instead I got this (x86-64 clang 20.1.0 with -Os option, tested in Compiler Explorer):

        cmpl    $1048576, %edi
        setb    %al
        retq

(Clang can recognize the three functions are equivalent. It just made suboptimal code among the possible choices.)

Note that in RISC-V targets of Clang, it does use the right shift to reduce code size

        srliw   a0, a0, 20
        seqz    a0, a0
        ret

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions