[llvm] [AVR] Support return address intrinsics (PR #67266)
Emil J via llvm-commits
llvm-commits at lists.llvm.org
Sun Sep 24 06:53:24 PDT 2023
https://github.com/ekliptik created https://github.com/llvm/llvm-project/pull/67266
This PR allows the use of @llvm.returnaddress and @llvm.addressofreturnaddress. Zig's runtime checks currently use these for some sort of unwinding mechanism. All code used in this implementation has been copied from PPC/MSP430/M68k/X86 and relies on functions exposed by generic LLVM code. I am unable to verify the correctness of the generated assembly because I don't know anything about AVR
>From 710fcf356ad494c88610919d8e6236c3aa001d14 Mon Sep 17 00:00:00 2001
From: "Emil J. Tywoniak" <emil at tywoniak.eu>
Date: Sun, 24 Sep 2023 15:41:02 +0200
Subject: [PATCH] [AVR] Support return address intrinsics
---
llvm/lib/Target/AVR/AVRISelLowering.cpp | 42 ++++++++++++++++++++
llvm/lib/Target/AVR/AVRISelLowering.h | 3 ++
llvm/lib/Target/AVR/AVRMachineFunctionInfo.h | 8 +++-
llvm/test/CodeGen/AVR/addr-of-ret-addr.ll | 21 ++++++++++
llvm/test/CodeGen/AVR/returnaddr.ll | 20 ++++++++++
5 files changed, 93 insertions(+), 1 deletion(-)
create mode 100644 llvm/test/CodeGen/AVR/addr-of-ret-addr.ll
create mode 100644 llvm/test/CodeGen/AVR/returnaddr.ll
diff --git a/llvm/lib/Target/AVR/AVRISelLowering.cpp b/llvm/lib/Target/AVR/AVRISelLowering.cpp
index 4f5a48bd05a4e86..8b558f32f14c8d6 100644
--- a/llvm/lib/Target/AVR/AVRISelLowering.cpp
+++ b/llvm/lib/Target/AVR/AVRISelLowering.cpp
@@ -992,6 +992,44 @@ SDValue AVRTargetLowering::LowerINLINEASM(SDValue Op, SelectionDAG &DAG) const {
return New;
}
+SDValue
+AVRTargetLowering::getReturnAddressFrameIndex(SelectionDAG &DAG) const {
+ MachineFunction &MF = DAG.getMachineFunction();
+ AVRMachineFunctionInfo *FuncInfo = MF.getInfo<AVRMachineFunctionInfo>();
+ int ReturnAddrIndex = FuncInfo->getRAIndex();
+ MVT PtrVT = getFrameIndexTy(MF.getDataLayout());
+
+ if (ReturnAddrIndex == 0) {
+ // Set up a frame object for the return address.
+ unsigned SlotSize = PtrVT.getStoreSize();
+ ReturnAddrIndex = MF.getFrameInfo().CreateFixedObject(
+ SlotSize, -(int64_t)SlotSize, false);
+ FuncInfo->setRAIndex(ReturnAddrIndex);
+ }
+
+ return DAG.getFrameIndex(ReturnAddrIndex, getPointerTy(DAG.getDataLayout()));
+}
+
+SDValue AVRTargetLowering::LowerRETURNADDR(SDValue Op, SelectionDAG &DAG) const {
+ MachineFunction &MF = DAG.getMachineFunction();
+ MachineFrameInfo &MFI = MF.getFrameInfo();
+ const AVRMachineFunctionInfo *AFI = MF.getInfo<AVRMachineFunctionInfo>();
+ MFI.setReturnAddressIsTaken(true);
+
+ EVT VT = Op.getValueType();
+ SDLoc DL(Op);
+ unsigned Depth = cast<ConstantSDNode>(Op.getOperand(0))->getZExtValue();
+ assert(Depth == 0 && "AVR RETURNADDR depth must be 0!");
+ // Just load the return address off the stack.
+ SDValue RetAddrFI = getReturnAddressFrameIndex(DAG);
+ return DAG.getLoad(VT, DL, DAG.getEntryNode(), RetAddrFI,
+ MachinePointerInfo());
+}
+SDValue AVRTargetLowering::LowerADDROFRETURNADDR(SDValue Op, SelectionDAG &DAG) const {
+ DAG.getMachineFunction().getFrameInfo().setReturnAddressIsTaken(true);
+ return getReturnAddressFrameIndex(DAG);
+}
+
SDValue AVRTargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) const {
switch (Op.getOpcode()) {
default:
@@ -1019,6 +1057,10 @@ SDValue AVRTargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) const {
return LowerDivRem(Op, DAG);
case ISD::INLINEASM:
return LowerINLINEASM(Op, DAG);
+ case ISD::RETURNADDR:
+ return LowerRETURNADDR(Op, DAG);
+ case ISD::ADDROFRETURNADDR:
+ return LowerADDROFRETURNADDR(Op, DAG);
}
return SDValue();
diff --git a/llvm/lib/Target/AVR/AVRISelLowering.h b/llvm/lib/Target/AVR/AVRISelLowering.h
index 6815b519bebf74d..443913541b340c2 100644
--- a/llvm/lib/Target/AVR/AVRISelLowering.h
+++ b/llvm/lib/Target/AVR/AVRISelLowering.h
@@ -155,6 +155,7 @@ class AVRTargetLowering : public TargetLowering {
}
private:
+ SDValue getReturnAddressFrameIndex(SelectionDAG &DAG) const;
SDValue getAVRCmp(SDValue LHS, SDValue RHS, ISD::CondCode CC, SDValue &AVRcc,
SelectionDAG &DAG, SDLoc dl) const;
SDValue getAVRCmp(SDValue LHS, SDValue RHS, SelectionDAG &DAG,
@@ -190,6 +191,8 @@ class AVRTargetLowering : public TargetLowering {
const SmallVectorImpl<ISD::InputArg> &Ins,
const SDLoc &dl, SelectionDAG &DAG,
SmallVectorImpl<SDValue> &InVals) const;
+ SDValue LowerRETURNADDR(SDValue Op, SelectionDAG &DAG) const;
+ SDValue LowerADDROFRETURNADDR(SDValue Op, SelectionDAG &DAG) const;
protected:
const AVRSubtarget &Subtarget;
diff --git a/llvm/lib/Target/AVR/AVRMachineFunctionInfo.h b/llvm/lib/Target/AVR/AVRMachineFunctionInfo.h
index 45c367a4dcd493f..dad0b1ca62ca19a 100644
--- a/llvm/lib/Target/AVR/AVRMachineFunctionInfo.h
+++ b/llvm/lib/Target/AVR/AVRMachineFunctionInfo.h
@@ -44,10 +44,13 @@ class AVRMachineFunctionInfo : public MachineFunctionInfo {
/// FrameIndex for start of varargs area.
int VarArgsFrameIndex;
+ /// FrameIndex for return slot.
+ int ReturnAddrIndex;
+
public:
AVRMachineFunctionInfo(const Function &F, const TargetSubtargetInfo *STI)
: HasSpills(false), HasAllocas(false), HasStackArgs(false),
- CalleeSavedFrameSize(0), VarArgsFrameIndex(0) {
+ CalleeSavedFrameSize(0), VarArgsFrameIndex(0), ReturnAddrIndex(0) {
CallingConv::ID CallConv = F.getCallingConv();
this->IsInterruptHandler =
@@ -85,6 +88,9 @@ class AVRMachineFunctionInfo : public MachineFunctionInfo {
int getVarArgsFrameIndex() const { return VarArgsFrameIndex; }
void setVarArgsFrameIndex(int Idx) { VarArgsFrameIndex = Idx; }
+
+ int getRAIndex() const { return ReturnAddrIndex; }
+ void setRAIndex(int Index) { ReturnAddrIndex = Index; }
};
} // namespace llvm
diff --git a/llvm/test/CodeGen/AVR/addr-of-ret-addr.ll b/llvm/test/CodeGen/AVR/addr-of-ret-addr.ll
new file mode 100644
index 000000000000000..118a0b459140e3e
--- /dev/null
+++ b/llvm/test/CodeGen/AVR/addr-of-ret-addr.ll
@@ -0,0 +1,21 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 2
+; RUN: llc < %s -mtriple=avr | FileCheck %s
+
+declare ptr @llvm.addressofreturnaddress()
+
+define ptr @a() {
+; CHECK-LABEL: a:
+; CHECK: ; %bb.0:
+; CHECK-NEXT: push r28
+; CHECK-NEXT: push r29
+; CHECK-NEXT: in r28, 61
+; CHECK-NEXT: in r29, 62
+; CHECK-NEXT: mov r24, r28
+; CHECK-NEXT: mov r25, r29
+; CHECK-NEXT: adiw r24, 3
+; CHECK-NEXT: pop r29
+; CHECK-NEXT: pop r28
+; CHECK-NEXT: ret
+ %1 = call ptr @llvm.addressofreturnaddress()
+ ret ptr %1
+}
diff --git a/llvm/test/CodeGen/AVR/returnaddr.ll b/llvm/test/CodeGen/AVR/returnaddr.ll
new file mode 100644
index 000000000000000..5e7b3a22a4bc2b8
--- /dev/null
+++ b/llvm/test/CodeGen/AVR/returnaddr.ll
@@ -0,0 +1,20 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 2
+; RUN: llc < %s -mtriple=avr | FileCheck %s
+
+declare ptr @llvm.returnaddress(i32) nounwind readnone
+
+define ptr @a() {
+; CHECK-LABEL: a:
+; CHECK: ; %bb.0:
+; CHECK-NEXT: push r28
+; CHECK-NEXT: push r29
+; CHECK-NEXT: in r28, 61
+; CHECK-NEXT: in r29, 62
+; CHECK-NEXT: ldd r24, Y+3
+; CHECK-NEXT: ldd r25, Y+4
+; CHECK-NEXT: pop r29
+; CHECK-NEXT: pop r28
+; CHECK-NEXT: ret
+ %1 = call ptr @llvm.returnaddress(i32 0)
+ ret ptr %1
+}
More information about the llvm-commits
mailing list