当 x 的范围有限时,为什么 x/10 会通过不必要的偏移进行优化?

Sle*_*lei 9 c++ compiler-construction assembly compiler-optimization

我有这个功能

long long int divideBy10(long long int a){
    return a / 10;
}
Run Code Online (Sandbox Code Playgroud)

它被编译为:

        mov     rax, rdi
        movabs  rcx, 7378697629483820647
        imul    rcx
        mov     rax, rdx
        shr     rax, 63
        sar     rdx, 2
        add     rax, rdx
        ret
Run Code Online (Sandbox Code Playgroud)

如果我添加 __builtin_assume(a > 0);

它被编译为

        mov     rax, rdi
        movabs  rcx, -3689348814741910323
        mul     rcx
        mov     rax, rdx
        shr     rax, 3
        ret
Run Code Online (Sandbox Code Playgroud)

代码效率更高,因为它不必担心负号。现在,如果我添加 __builtin_assume(a < 10000); 我原以为它会被编译成一个乘法而没有移位。但事实并非如此。

我想也许编译器只跟踪数字是正数还是负数,但是

long long int noBranch(long long int a){
    __builtin_assume(a < 400);
    if( a < 500){
        return a;
    }
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

编译为一条移动指令,以便编译器能够跟踪这些边界。

为什么编译器不能优化转移?(这发生在 GCC 和 Clang 中)。

这是我希望生成的代码:

long long int d10(long long int a){
    __builtin_assume(a > 0);
    __builtin_assume(a < 10'000);
    __uint128_t e = a;
    e *= 0x199999999999999A;
    return e >> 64;

}
Run Code Online (Sandbox Code Playgroud)
d10(long long):                                # @d10(long long)
        mov     rax, rdi
        movabs  rcx, 1844674407370955162
        mul     rcx
        mov     rax, rdx
        ret
Run Code Online (Sandbox Code Playgroud)

编辑:我知道你需要一个班次才能涵盖 long long int 的整个范围。我在问如果范围受到限制,为什么编译器不能优化转移。