llvm / llvm/llvm-project

Avoid materialising `-k` by rewriting `use(a + k, b + (-k))` to `use(a + k, b - k)`

Open
#222,095 3 comments 0 reactions 1 assignee Claimed by @prajapati-git View on GitHub
backend:AArch64 backend:X86 missed-optimization
Dominant language
LLVM
Stars
40.5k
Forks
18.7k
PR merge metrics
PR metrics pending

Description

LLVM rewrites expressions of the form `a - k` to `a + (-k)` when `k` is a constant. This is usually beneficial because it may expose more associativity/commutativity. But, if `k` is a constant that has to be materialized by the target because it doesn't fit in an immediate, the rewrite should be undone, so that only `k` has to be materialised:

# C++ examples
https://godbolt.org/z/G4P76sfPT

```c++
using u32 = unsigned int;
using f32 = float;
using f64 = double;

u32 use(u32 a, u32 b);
f32 use(f32 a, f32 b);
f64 use(f64 a, f64 b);

auto src(u32 a, u32 b) {
u32 k = (1 << 12) + 1;
return use(a + k, b - k);
}

auto src(f32 a, f32 b) {
f32 k = 1.0;
return use(a + k, b - k);
}

auto src(f64 a, f64 b) {
f64 k = 1.0;
return use(a + k, b - k);
}
```

# Current AArch64 assembly
```asm
src(unsigned int, unsigned int):
mov w8, #4097
mov w9, #-4097
add w0, w0, w8
add w1, w1, w9
b use(unsigned int, unsigned int)

src(float, float):
fmov s2, #1.00000000
fmov s3, #-1.00000000
fadd s0, s0, s2
fadd s1, s1, s3
b use(float, float)

src(double, double):
fmov d2, #1.00000000
fmov d3, #-1.00000000
fadd d0, d0, d2
fadd d1, d1, d3
b use(double, double)
```

# Expected AArch64 assembly
```asm
src(unsigned int, unsigned int):
mov w8, #4097
add w0, w0, w8
sub w1, w1, w9
b use(unsigned int, unsigned int)

src(float, float):
fmov s2, #1.00000000
fadd s0, s0, s2
fsub s1, s1, s2
b use(float, float)

src(double, double):
fmov d2, #1.00000000
fadd d0, d0, d2
fsub d1, d1, d2
b use(double, double)
```

# Current x86_64 assembly
```asm
src(unsigned int, unsigned int):
add edi, 4097
add esi, -4097
jmp use(unsigned int, unsigned int)@PLT

.LCPI1_0:
.long 0x3f800000
.LCPI1_1:
.long 0xbf800000
src(float, float):
addss xmm0, dword ptr [rip + .LCPI1_0]
addss xmm1, dword ptr [rip + .LCPI1_1]
jmp use(float, float)@PLT

.LCPI2_0:
.quad 0x3ff0000000000000
.LCPI2_1:
.quad 0xbff0000000000000
src(double, double):
addsd xmm0, qword ptr [rip + .LCPI2_0]
addsd xmm1, qword ptr [rip + .LCPI2_1]
jmp use(double, double)@PLT
```

# Expected x86_64 assembly
```asm
src(unsigned int, unsigned int):
add edi, 4097
add esi, -4097
jmp use(unsigned int, unsigned int)@PLT

.LCPI1_0:
.long 0x3f800000
src(float, float):
addss xmm0, dword ptr [rip + .LCPI1_0]
subss xmm1, dword ptr [rip + .LCPI1_0]
jmp use(float, float)@PLT

.LCPI2_0:
.quad 0x3ff0000000000000
src(double, double):
addsd xmm0, qword ptr [rip + .LCPI2_0]
subsd xmm1, qword ptr [rip + .LCPI2_0]
jmp use(double, double)@PLT
```

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.