[PowerPC] Fix return address computation for "__builtin_return_address"
authorVictor Huang <wei.huang@ibm.com>
Thu, 12 Aug 2021 13:03:21 +0000 (08:03 -0500)
committerVictor Huang <wei.huang@ibm.com>
Thu, 12 Aug 2021 14:44:49 +0000 (09:44 -0500)
When depth > 0, callee frame address is used to compute the return address of
callee producing improper return address. This patch adds the fix to use caller
frame address to compute the return address of callee.

Reviewed By: nemanjai, #powerpc

Differential revision: https://reviews.llvm.org/D107646

llvm/lib/Target/PowerPC/PPCISelLowering.cpp
llvm/test/CodeGen/PowerPC/2010-05-03-retaddr1.ll
llvm/test/CodeGen/PowerPC/retaddr_multi_levels.ll [new file with mode: 0644]

index 3735817..6d38b39 100644 (file)
@@ -15960,7 +15960,12 @@ SDValue PPCTargetLowering::LowerRETURNADDR(SDValue Op,
   auto PtrVT = getPointerTy(MF.getDataLayout());
 
   if (Depth > 0) {
-    SDValue FrameAddr = LowerFRAMEADDR(Op, DAG);
+    // The link register (return address) is saved in the caller's frame
+    // not the callee's stack frame. So we must get the caller's frame
+    // address and load the return address at the LR offset from there.
+    SDValue FrameAddr =
+        DAG.getLoad(Op.getValueType(), dl, DAG.getEntryNode(),
+                    LowerFRAMEADDR(Op, DAG), MachinePointerInfo());
     SDValue Offset =
         DAG.getConstant(Subtarget.getFrameLowering()->getReturnSaveOffset(), dl,
                         isPPC64 ? MVT::i64 : MVT::i32);
index 170a82a..055cd44 100644 (file)
@@ -23,6 +23,7 @@ define i8* @g() nounwind readnone {
 ; CHECK-NEXT:    stw 0, 4(1)
 ; CHECK-NEXT:    stwu 1, -16(1)
 ; CHECK-NEXT:    lwz 3, 0(1)
+; CHECK-NEXT:    lwz 3, 0(3)
 ; CHECK-NEXT:    lwz 3, 4(3)
 ; CHECK-NEXT:    lwz 0, 20(1)
 ; CHECK-NEXT:    addi 1, 1, 16
diff --git a/llvm/test/CodeGen/PowerPC/retaddr_multi_levels.ll b/llvm/test/CodeGen/PowerPC/retaddr_multi_levels.ll
new file mode 100644 (file)
index 0000000..7e55f05
--- /dev/null
@@ -0,0 +1,140 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc -verify-machineinstrs < %s -mtriple=powerpc64le-unknown-linux \
+; RUN:   -mcpu=pwr8 | FileCheck %s -check-prefix=CHECK-64B-LE
+; RUN: llc -verify-machineinstrs < %s -mtriple=powerpc64-unknown-linux \
+; RUN:   -mcpu=pwr7 | FileCheck %s -check-prefix=CHECK-64B-BE
+; RUN: llc -verify-machineinstrs < %s -mtriple=powerpc64-unknown-aix \
+; RUN:   -mcpu=pwr7 | FileCheck %s -check-prefix=CHECK-64B-BE
+; RUN: llc -verify-machineinstrs < %s -mtriple=powerpc-unknown-aix \
+; RUN:   -mcpu=pwr7 | FileCheck %s -check-prefix=CHECK-32B-BE
+
+declare i8* @llvm.returnaddress(i32) nounwind readnone
+
+define i8* @test0() nounwind readnone {
+; CHECK-64B-LE-LABEL: test0:
+; CHECK-64B-LE:       # %bb.0: # %entry
+; CHECK-64B-LE-NEXT:    mflr 0
+; CHECK-64B-LE-NEXT:    std 0, 16(1)
+; CHECK-64B-LE-NEXT:    stdu 1, -32(1)
+; CHECK-64B-LE-NEXT:    ld 3, 48(1)
+; CHECK-64B-LE-NEXT:    addi 1, 1, 32
+; CHECK-64B-LE-NEXT:    ld 0, 16(1)
+; CHECK-64B-LE-NEXT:    mtlr 0
+; CHECK-64B-LE-NEXT:    blr
+;
+; CHECK-64B-BE-LABEL: test0:
+; CHECK-64B-BE:       # %bb.0: # %entry
+; CHECK-64B-BE-NEXT:    mflr 0
+; CHECK-64B-BE-NEXT:    std 0, 16(1)
+; CHECK-64B-BE-NEXT:    stdu 1, -48(1)
+; CHECK-64B-BE-NEXT:    ld 3, 64(1)
+; CHECK-64B-BE-NEXT:    addi 1, 1, 48
+; CHECK-64B-BE-NEXT:    ld 0, 16(1)
+; CHECK-64B-BE-NEXT:    mtlr 0
+; CHECK-64B-BE-NEXT:    blr
+;
+; CHECK-32B-BE-LABEL: test0:
+; CHECK-32B-BE:       # %bb.0: # %entry
+; CHECK-32B-BE-NEXT:    mflr 0
+; CHECK-32B-BE-NEXT:    stw 0, 8(1)
+; CHECK-32B-BE-NEXT:    stwu 1, -32(1)
+; CHECK-32B-BE-NEXT:    lwz 3, 40(1)
+; CHECK-32B-BE-NEXT:    addi 1, 1, 32
+; CHECK-32B-BE-NEXT:    lwz 0, 8(1)
+; CHECK-32B-BE-NEXT:    mtlr 0
+; CHECK-32B-BE-NEXT:    blr
+entry:
+  %0 = tail call i8* @llvm.returnaddress(i32 0);
+  ret i8* %0
+}
+
+define i8* @test1() nounwind readnone {
+; CHECK-64B-LE-LABEL: test1:
+; CHECK-64B-LE:       # %bb.0: # %entry
+; CHECK-64B-LE-NEXT:    mflr 0
+; CHECK-64B-LE-NEXT:    std 0, 16(1)
+; CHECK-64B-LE-NEXT:    stdu 1, -32(1)
+; CHECK-64B-LE-NEXT:    ld 3, 0(1)
+; CHECK-64B-LE-NEXT:    ld 3, 0(3)
+; CHECK-64B-LE-NEXT:    ld 3, 16(3)
+; CHECK-64B-LE-NEXT:    addi 1, 1, 32
+; CHECK-64B-LE-NEXT:    ld 0, 16(1)
+; CHECK-64B-LE-NEXT:    mtlr 0
+; CHECK-64B-LE-NEXT:    blr
+;
+; CHECK-64B-BE-LABEL: test1:
+; CHECK-64B-BE:       # %bb.0: # %entry
+; CHECK-64B-BE-NEXT:    mflr 0
+; CHECK-64B-BE-NEXT:    std 0, 16(1)
+; CHECK-64B-BE-NEXT:    stdu 1, -48(1)
+; CHECK-64B-BE-NEXT:    ld 3, 0(1)
+; CHECK-64B-BE-NEXT:    ld 3, 0(3)
+; CHECK-64B-BE-NEXT:    ld 3, 16(3)
+; CHECK-64B-BE-NEXT:    addi 1, 1, 48
+; CHECK-64B-BE-NEXT:    ld 0, 16(1)
+; CHECK-64B-BE-NEXT:    mtlr 0
+; CHECK-64B-BE-NEXT:    blr
+;
+; CHECK-32B-BE-LABEL: test1:
+; CHECK-32B-BE:       # %bb.0: # %entry
+; CHECK-32B-BE-NEXT:    mflr 0
+; CHECK-32B-BE-NEXT:    stw 0, 8(1)
+; CHECK-32B-BE-NEXT:    stwu 1, -32(1)
+; CHECK-32B-BE-NEXT:    lwz 3, 0(1)
+; CHECK-32B-BE-NEXT:    lwz 3, 0(3)
+; CHECK-32B-BE-NEXT:    lwz 3, 8(3)
+; CHECK-32B-BE-NEXT:    addi 1, 1, 32
+; CHECK-32B-BE-NEXT:    lwz 0, 8(1)
+; CHECK-32B-BE-NEXT:    mtlr 0
+; CHECK-32B-BE-NEXT:    blr
+entry:
+  %0 = tail call i8* @llvm.returnaddress(i32 1);
+  ret i8* %0
+}
+
+define i8* @test2() nounwind readnone {
+; CHECK-64B-LE-LABEL: test2:
+; CHECK-64B-LE:       # %bb.0: # %entry
+; CHECK-64B-LE-NEXT:    mflr 0
+; CHECK-64B-LE-NEXT:    std 0, 16(1)
+; CHECK-64B-LE-NEXT:    stdu 1, -32(1)
+; CHECK-64B-LE-NEXT:    ld 3, 0(1)
+; CHECK-64B-LE-NEXT:    ld 3, 0(3)
+; CHECK-64B-LE-NEXT:    ld 3, 0(3)
+; CHECK-64B-LE-NEXT:    ld 3, 16(3)
+; CHECK-64B-LE-NEXT:    addi 1, 1, 32
+; CHECK-64B-LE-NEXT:    ld 0, 16(1)
+; CHECK-64B-LE-NEXT:    mtlr 0
+; CHECK-64B-LE-NEXT:    blr
+;
+; CHECK-64B-BE-LABEL: test2:
+; CHECK-64B-BE:       # %bb.0: # %entry
+; CHECK-64B-BE-NEXT:    mflr 0
+; CHECK-64B-BE-NEXT:    std 0, 16(1)
+; CHECK-64B-BE-NEXT:    stdu 1, -48(1)
+; CHECK-64B-BE-NEXT:    ld 3, 0(1)
+; CHECK-64B-BE-NEXT:    ld 3, 0(3)
+; CHECK-64B-BE-NEXT:    ld 3, 0(3)
+; CHECK-64B-BE-NEXT:    ld 3, 16(3)
+; CHECK-64B-BE-NEXT:    addi 1, 1, 48
+; CHECK-64B-BE-NEXT:    ld 0, 16(1)
+; CHECK-64B-BE-NEXT:    mtlr 0
+; CHECK-64B-BE-NEXT:    blr
+;
+; CHECK-32B-BE-LABEL: test2:
+; CHECK-32B-BE:       # %bb.0: # %entry
+; CHECK-32B-BE-NEXT:    mflr 0
+; CHECK-32B-BE-NEXT:    stw 0, 8(1)
+; CHECK-32B-BE-NEXT:    stwu 1, -32(1)
+; CHECK-32B-BE-NEXT:    lwz 3, 0(1)
+; CHECK-32B-BE-NEXT:    lwz 3, 0(3)
+; CHECK-32B-BE-NEXT:    lwz 3, 0(3)
+; CHECK-32B-BE-NEXT:    lwz 3, 8(3)
+; CHECK-32B-BE-NEXT:    addi 1, 1, 32
+; CHECK-32B-BE-NEXT:    lwz 0, 8(1)
+; CHECK-32B-BE-NEXT:    mtlr 0
+; CHECK-32B-BE-NEXT:    blr
+entry:
+  %0 = tail call i8* @llvm.returnaddress(i32 2);
+  ret i8* %0
+}