[llvm] Spill/restore FP/BP around instructions in which they are clobbered (PR #81048)

via llvm-commits llvm-commits at lists.llvm.org
Fri Aug 2 14:49:14 PDT 2024


================
@@ -0,0 +1,52 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 4
+; RUN: llc -mtriple=x86_64-pc-linux -stackrealign -verify-machineinstrs < %s | FileCheck %s
+
+; Calling convention ghccc uses ebp to pass parameter, so calling a function
+; using ghccc clobbers ebp. We should save and restore ebp around such a call
+; if ebp is used as frame pointer.
+
+declare ghccc i32 @external(i32)
+
+define i32 @foo(i32 %0, i32 %1) {
+; CHECK-LABEL: foo:
+; CHECK:       # %bb.0:
+; CHECK-NEXT:    pushq %rbp
+; CHECK-NEXT:    .cfi_def_cfa_offset 16
+; CHECK-NEXT:    .cfi_offset %rbp, -16
+; CHECK-NEXT:    movq %rsp, %rbp
+; CHECK-NEXT:    .cfi_def_cfa_register %rbp
+; CHECK-NEXT:    pushq %r15
+; CHECK-NEXT:    pushq %r14
+; CHECK-NEXT:    pushq %r13
+; CHECK-NEXT:    pushq %r12
+; CHECK-NEXT:    pushq %rbx
+; CHECK-NEXT:    andq $-16, %rsp
+; CHECK-NEXT:    subq $16, %rsp
+; CHECK-NEXT:    .cfi_offset %rbx, -56
+; CHECK-NEXT:    .cfi_offset %r12, -48
+; CHECK-NEXT:    .cfi_offset %r13, -40
+; CHECK-NEXT:    .cfi_offset %r14, -32
+; CHECK-NEXT:    .cfi_offset %r15, -24
+; CHECK-NEXT:    # kill: def $edi killed $edi def $rdi
+; CHECK-NEXT:    pushq %rbp
+; CHECK-NEXT:    pushq %rax
+; CHECK-NEXT:    .cfi_remember_state
+; CHECK-NEXT:    .cfi_escape 0x0f, 0x06, 0x77, 0x08, 0x06, 0x11, 0x10, 0x22 #
+; CHECK-NEXT:    movl %esi, %ebp
+; CHECK-NEXT:    movq %rdi, %r13
+; CHECK-NEXT:    callq external at PLT
+; CHECK-NEXT:    addq $8, %rsp
+; CHECK-NEXT:    popq %rbp
+; CHECK-NEXT:    .cfi_restore_state
+; CHECK-NEXT:    leaq -40(%rbp), %rsp
+; CHECK-NEXT:    popq %rbx
+; CHECK-NEXT:    popq %r12
+; CHECK-NEXT:    popq %r13
+; CHECK-NEXT:    popq %r14
+; CHECK-NEXT:    popq %r15
+; CHECK-NEXT:    popq %rbp
+; CHECK-NEXT:    .cfi_def_cfa %rsp, 8
+; CHECK-NEXT:    retq
+    %x = call ghccc i32 @external(i32 %0, i32 %1)
----------------
weiguozhi wrote:

The only calling convention that clobbers RBP but no RBX is HiPE. I added a new test case for it. And this patch does correct work.

But the generated code is still wrong because of a different bug.
```
  %6:gr64 = MOV64rm %fixed-stack.1, 1, $noreg, 0, $noreg :: (load (s64) from %fixed-stack.1)
  %7:gr64 = MOV64rm %fixed-stack.0, 1, $noreg, 0, $noreg :: (load (s64) from %fixed-stack.0)
  ADJCALLSTACKDOWN64 16, 0, 0, implicit-def dead $rsp, implicit-def dead $eflags, implicit-def dead $ssp, implicit $rsp, implicit $ssp
  %8:gr64 = COPY $rsp 
  MOV64mr %8:gr64, 1, $noreg, 8, $noreg, killed %7:gr64 :: (store (s64) into stack + 8) 
  MOV64mr %8:gr64, 1, $noreg, 0, $noreg, killed %6:gr64 :: (store (s64) into stack)
  $r15 = COPY %0:gr64
  $rbp = COPY %1:gr64
  $rsi = COPY %2:gr64
  $rdx = COPY %3:gr64
  $rcx = COPY %4:gr64
  $r8 = COPY %5:gr64
  CALL64pcrel32 target-flags(x86-plt) @external2, <regmask>, ...
```
x86-cf-opt transforms it to
```
  ADJCALLSTACKDOWN64 16, 0, 16, implicit-def dead $rsp, implicit-def dead $eflags, implicit-def dead $ssp, implicit $rsp, implicit $ssp 
  $r15 = COPY %0:gr64
  $rbp = COPY %1:gr64
  $rsi = COPY %2:gr64
  $rdx = COPY %3:gr64
  $rcx = COPY %4:gr64
  $r8 = COPY %5:gr64
  PUSH64rmm %fixed-stack.0, 1, $noreg, 0, $noreg, implicit-def $rsp, implicit $rsp :: (load (s64) from %fixed-stack.0), (store (s64) into stack + 8)
  PUSH64rmm %fixed-stack.1, 1, $noreg, 0, $noreg, implicit-def $rsp, implicit $rsp :: (load (s64) from %fixed-stack.1), (store (s64) into stack)
  CALL64pcrel32 target-flags(x86-plt) @external2, <regmask>, ...
```
The access to %fixed-stack.0 needs rbp, but it is already assigned function argument.


https://github.com/llvm/llvm-project/pull/81048


More information about the llvm-commits mailing list