From 99e00663d4cd13b0c296380147ef3f53a2172fbf Mon Sep 17 00:00:00 2001 From: Victor Huang Date: Thu, 12 Aug 2021 08:03:21 -0500 Subject: [PATCH] [PowerPC] Fix return address computation for "__builtin_return_address" 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 | 7 +- llvm/test/CodeGen/PowerPC/2010-05-03-retaddr1.ll | 1 + llvm/test/CodeGen/PowerPC/retaddr_multi_levels.ll | 140 ++++++++++++++++++++++ 3 files changed, 147 insertions(+), 1 deletion(-) create mode 100644 llvm/test/CodeGen/PowerPC/retaddr_multi_levels.ll diff --git a/llvm/lib/Target/PowerPC/PPCISelLowering.cpp b/llvm/lib/Target/PowerPC/PPCISelLowering.cpp index 3735817..6d38b39f 100644 --- a/llvm/lib/Target/PowerPC/PPCISelLowering.cpp +++ b/llvm/lib/Target/PowerPC/PPCISelLowering.cpp @@ -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); diff --git a/llvm/test/CodeGen/PowerPC/2010-05-03-retaddr1.ll b/llvm/test/CodeGen/PowerPC/2010-05-03-retaddr1.ll index 170a82a..055cd44 100644 --- a/llvm/test/CodeGen/PowerPC/2010-05-03-retaddr1.ll +++ b/llvm/test/CodeGen/PowerPC/2010-05-03-retaddr1.ll @@ -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 index 0000000..7e55f05 --- /dev/null +++ b/llvm/test/CodeGen/PowerPC/retaddr_multi_levels.ll @@ -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 +} -- 2.7.4