llvm / llvm-project

The LLVM Project is a collection of modular and reusable compiler and toolchain technologies.
http://llvm.org
Other
28.22k stars 11.64k forks source link

[x86] The x86 backend seems to break the cse optimizations #69001

Open ZY546 opened 11 months ago

ZY546 commented 11 months ago

For the following test cases, cse has been done in llvm ir, but on x86, the final assembler code seems to break this optimization: https://godbolt.org/z/EYc9c66jK

extern int x, y;
void test(int a, int b) {

    x = a + b + 1;
    y = a + b + 2;
}
define dso_local void @test(int, int)(i32 noundef %a, i32 noundef %b) local_unnamed_addr {
entry:
  %add = add nsw i32 %b, %a
  %add1 = add nsw i32 %add, 1
  store i32 %add1, ptr @x, align 4
  %add3 = add nsw i32 %add, 2
  store i32 %add3, ptr @y, align 4
  ret void
}
test(int, int):                              # @test(int, int)
        lea     eax, [rsi + rdi]
        inc     eax
        mov     rcx, qword ptr [rip + x@GOTPCREL]
        mov     dword ptr [rcx], eax
        lea     eax, [rsi + rdi]
        add     eax, 2
        mov     rcx, qword ptr [rip + y@GOTPCREL]
        mov     dword ptr [rcx], eax
        ret

Maybe lea eax, [rsi + rdi] should not be repeated twice.

llvmbot commented 11 months ago

@llvm/issue-subscribers-backend-x86

Author: None (ZY546)

For the following test cases, `cse` has been done in llvm ir, but on x86, the final assembler code seems to break this optimization: https://godbolt.org/z/EYc9c66jK ```cpp extern int x, y; void test(int a, int b) { x = a + b + 1; y = a + b + 2; } ``` ```llvm define dso_local void @test(int, int)(i32 noundef %a, i32 noundef %b) local_unnamed_addr { entry: %add = add nsw i32 %b, %a %add1 = add nsw i32 %add, 1 store i32 %add1, ptr @x, align 4 %add3 = add nsw i32 %add, 2 store i32 %add3, ptr @y, align 4 ret void } ``` ```asm test(int, int): # @test(int, int) lea eax, [rsi + rdi] inc eax mov rcx, qword ptr [rip + x@GOTPCREL] mov dword ptr [rcx], eax lea eax, [rsi + rdi] add eax, 2 mov rcx, qword ptr [rip + y@GOTPCREL] mov dword ptr [rcx], eax ret ``` Maybe `lea eax, [rsi + rdi]` should not be repeated twice.
RKSimon commented 1 month ago

The x86-fixup-LEAs pass is splitting the 3-op LEAs but we don't merge the now matching 2-op LEAs:

# Machine code for function test(int, int): NoPHIs, TracksLiveness, NoVRegs, TiedOpsRewritten, TracksDebugUserValues
Function Live Ins: $edi, $esi

bb.0.entry:
  liveins: $edi, $esi
  renamable $esi = KILL $esi, implicit-def $rsi
  renamable $edi = KILL $edi, implicit-def $rdi
  renamable $eax = nsw LEA64_32r renamable $rsi, 1, renamable $rdi, 1, $noreg
  renamable $rcx = MOV64rm $rip, 1, $noreg, target-flags(x86-gotpcrel) @x, $noreg :: (load (s64) from got)
  MOV32mr killed renamable $rcx, 1, $noreg, 0, $noreg, killed renamable $eax :: (store (s32) into @x)
  renamable $eax = nsw LEA64_32r killed renamable $rsi, 1, killed renamable $rdi, 2, $noreg
  renamable $rcx = MOV64rm $rip, 1, $noreg, target-flags(x86-gotpcrel) @y, $noreg :: (load (s64) from got)
  MOV32mr killed renamable $rcx, 1, $noreg, 0, $noreg, killed renamable $eax :: (store (s32) into @y)
  RET64

# End machine code for function test(int, int).

-->

# Machine code for function test(int, int): NoPHIs, TracksLiveness, NoVRegs, TiedOpsRewritten, TracksDebugUserValues
Function Live Ins: $edi, $esi

bb.0.entry:
  liveins: $edi, $esi
  renamable $esi = KILL $esi, implicit-def $rsi
  renamable $edi = KILL $edi, implicit-def $rdi
  renamable $eax = LEA64_32r renamable $rsi, 1, renamable $rdi, 0, $noreg
  $eax = INC32r $eax(tied-def 0), implicit-def $eflags
  renamable $rcx = MOV64rm $rip, 1, $noreg, target-flags(x86-gotpcrel) @x, $noreg :: (load (s64) from got)
  MOV32mr killed renamable $rcx, 1, $noreg, 0, $noreg, killed renamable $eax :: (store (s32) into @x)
  renamable $eax = LEA64_32r killed renamable $rsi, 1, killed renamable $rdi, 0, $noreg
  $eax = ADD32ri $eax(tied-def 0), 2, implicit-def $eflags
  renamable $rcx = MOV64rm $rip, 1, $noreg, target-flags(x86-gotpcrel) @y, $noreg :: (load (s64) from got)
  MOV32mr killed renamable $rcx, 1, $noreg, 0, $noreg, killed renamable $eax :: (store (s32) into @y)
  RET64

# End machine code for function test(int, int).