[llvm] [AVR] Support return address intrinsics (PR #67266)

Emil J via llvm-commits llvm-commits at lists.llvm.org
Thu Oct 12 12:55:54 PDT 2023


https://github.com/ekliptik updated https://github.com/llvm/llvm-project/pull/67266

>From 24f98d3c29c41ce16e12262cd414efd7e8b37a29 Mon Sep 17 00:00:00 2001
From: "Emil J. Tywoniak" <emil at tywoniak.eu>
Date: Thu, 12 Oct 2023 21:55:41 +0200
Subject: [PATCH] [AVR] Support return address intrinsics

---
 llvm/lib/Target/AVR/AVRExpandPseudoInsts.cpp | 31 ++++++++------
 llvm/lib/Target/AVR/AVRISelLowering.cpp      | 43 ++++++++++++++++++++
 llvm/lib/Target/AVR/AVRISelLowering.h        |  3 ++
 llvm/lib/Target/AVR/AVRMachineFunctionInfo.h |  8 +++-
 llvm/test/CodeGen/AVR/addr-of-ret-addr.ll    | 32 +++++++++++++++
 llvm/test/CodeGen/AVR/returnaddr.ll          | 20 +++++++++
 6 files changed, 123 insertions(+), 14 deletions(-)
 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/AVRExpandPseudoInsts.cpp b/llvm/lib/Target/AVR/AVRExpandPseudoInsts.cpp
index f257ccea6c50a91..a5c3090a0495b02 100644
--- a/llvm/lib/Target/AVR/AVRExpandPseudoInsts.cpp
+++ b/llvm/lib/Target/AVR/AVRExpandPseudoInsts.cpp
@@ -2498,6 +2498,7 @@ template <> bool AVRExpandPseudo::expand<AVR::ZEXT>(Block &MBB, BlockIt MBBI) {
 
 template <>
 bool AVRExpandPseudo::expand<AVR::SPREAD>(Block &MBB, BlockIt MBBI) {
+  const AVRSubtarget &STI = MBB.getParent()->getSubtarget<AVRSubtarget>();
   MachineInstr &MI = *MBBI;
   Register DstLoReg, DstHiReg;
   Register DstReg = MI.getOperand(0).getReg();
@@ -2514,10 +2515,12 @@ bool AVRExpandPseudo::expand<AVR::SPREAD>(Block &MBB, BlockIt MBBI) {
       .setMIFlags(Flags);
 
   // High part
-  buildMI(MBB, MBBI, OpHi)
-      .addReg(DstHiReg, RegState::Define | getDeadRegState(DstIsDead))
-      .addImm(0x3e)
-      .setMIFlags(Flags);
+  if (!STI.hasSmallStack()) {
+    buildMI(MBB, MBBI, OpHi)
+        .addReg(DstHiReg, RegState::Define | getDeadRegState(DstIsDead))
+        .addImm(0x3e)
+        .setMIFlags(Flags);
+  }
 
   MI.eraseFromParent();
   return true;
@@ -2533,17 +2536,19 @@ bool AVRExpandPseudo::expand<AVR::SPWRITE>(Block &MBB, BlockIt MBBI) {
   unsigned Flags = MI.getFlags();
   TRI->splitReg(SrcReg, SrcLoReg, SrcHiReg);
 
-  buildMI(MBB, MBBI, AVR::INRdA)
-      .addReg(STI.getTmpRegister(), RegState::Define)
-      .addImm(STI.getIORegSREG())
-      .setMIFlags(Flags);
+  if (!STI.hasSmallStack()) {
+    buildMI(MBB, MBBI, AVR::INRdA)
+        .addReg(STI.getTmpRegister(), RegState::Define)
+        .addImm(STI.getIORegSREG())
+        .setMIFlags(Flags);
 
-  buildMI(MBB, MBBI, AVR::BCLRs).addImm(0x07).setMIFlags(Flags);
+    buildMI(MBB, MBBI, AVR::BCLRs).addImm(0x07).setMIFlags(Flags);
 
-  buildMI(MBB, MBBI, AVR::OUTARr)
-      .addImm(0x3e)
-      .addReg(SrcHiReg, getKillRegState(SrcIsKill))
-      .setMIFlags(Flags);
+    buildMI(MBB, MBBI, AVR::OUTARr)
+        .addImm(0x3e)
+        .addReg(SrcHiReg, getKillRegState(SrcIsKill))
+        .setMIFlags(Flags);
+  }
 
   buildMI(MBB, MBBI, AVR::OUTARr)
       .addImm(STI.getIORegSREG())
diff --git a/llvm/lib/Target/AVR/AVRISelLowering.cpp b/llvm/lib/Target/AVR/AVRISelLowering.cpp
index 4f5a48bd05a4e86..e253fa0cdd545cd 100644
--- a/llvm/lib/Target/AVR/AVRISelLowering.cpp
+++ b/llvm/lib/Target/AVR/AVRISelLowering.cpp
@@ -992,6 +992,45 @@ 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 +1058,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..0b70aee28b1f4f2
--- /dev/null
+++ b/llvm/test/CodeGen/AVR/addr-of-ret-addr.ll
@@ -0,0 +1,32 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 2
+; RUN: llc < %s -mtriple=avr -mcpu=attiny25 | FileCheck %s --check-prefix=SMALL-SP
+; RUN: llc < %s -mtriple=avr -mcpu=attiny45 | FileCheck %s --check-prefix=BIG-SP
+
+declare ptr @llvm.addressofreturnaddress()
+
+define ptr @a() {
+; SMALL-SP-LABEL: a:
+; SMALL-SP:       ; %bb.0:
+; SMALL-SP-NEXT:    push r28
+; SMALL-SP-NEXT:    push r29
+; SMALL-SP-NEXT:    in r28, 61
+; SMALL-SP-NEXT:    movw r24, r28
+; SMALL-SP-NEXT:    adiw r24, 3
+; SMALL-SP-NEXT:    pop r29
+; SMALL-SP-NEXT:    pop r28
+; SMALL-SP-NEXT:    ret
+;
+; BIG-SP-LABEL: a:
+; BIG-SP:       ; %bb.0:
+; BIG-SP-NEXT:    push r28
+; BIG-SP-NEXT:    push r29
+; BIG-SP-NEXT:    in r28, 61
+; BIG-SP-NEXT:    in r29, 62
+; BIG-SP-NEXT:    movw r24, r28
+; BIG-SP-NEXT:    adiw r24, 3
+; BIG-SP-NEXT:    pop r29
+; BIG-SP-NEXT:    pop r28
+; BIG-SP-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