Issue 171671
Summary Multiplication by zero generated for widening multiplication in loops
Labels new issue
Assignees
Reporter purplesyringa
    [Godbolt](https://godbolt.org/z/445r7c4KW)

```cpp
#include <stdint.h>

static uint64_t mul(uint64_t a, uint64_t b) {
    __uint128_t product = (__uint128_t)a * b;
    uint64_t result;
    result += __builtin_add_overflow((uint64_t)product, (uint64_t)(product >> 64), &result);
    return result;
}

uint64_t pow(uint64_t x, uint64_t n) {
 uint64_t res = 1;
    uint64_t tmp = x;
    while (n > 0) {
        if (n % 2 == 1) {
            res = mul(res, tmp);
        }
        tmp = mul(tmp, tmp);
        n /= 2;
    }
    return res;
}
```

```asm
pow(unsigned long, unsigned long):
        mov ecx, 1
        test    rsi, rsi
        jne     .LBB0_1
.LBB0_4:
 mov     rax, rcx
        ret
.LBB0_3:
        xor     r8d, r8d       ; r8 is cleared
        imul    r8, rdi        ; ...and then multiplied by rdi
 mov     rax, rdi
        mul     rdi
        mov     rdi, rdx
 add     rdi, r8        ; adding 0 to rdi for no reason
        add     rdi, r8        ; ...and again
        add     rdi, rax
        adc     rdi, 0
 shr     rsi
        je      .LBB0_4
.LBB0_1:
        test    sil, 1
        je      .LBB0_3
        mov     rax, rdi
        mul     rcx
 mov     rcx, rdx
        add     rcx, rax
        adc     rcx, 0
 jmp     .LBB0_3
```

>From a quick check, it seems like GVN hoists `zext` from `i64` to `i128` out of the BB that performs the squaring, which prevents isel from realizing this is not a full 128x128 -> 128 multiplication, but only 64x64 -> 128.
_______________________________________________
llvm-bugs mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-bugs

Reply via email to