llvm / llvm-project

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

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

Open ZY546 opened 1 year ago

ZY546 commented 1 year 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 1 year 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 3 months 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).