[SystemZ] Support llvm.frameaddress/llvm.returnaddress intrinsics
authorUlrich Weigand <ulrich.weigand@de.ibm.com>
Mon, 4 Apr 2016 12:44:55 +0000 (12:44 +0000)
committerUlrich Weigand <ulrich.weigand@de.ibm.com>
Mon, 4 Apr 2016 12:44:55 +0000 (12:44 +0000)
Enable the SystemZ back-end to lower FRAMEADDR and RETURNADDR, which
previously would cause the back-end to crash.  Currently, only a
frame count of zero is supported.

Author: bryanpkc
Differential Revision: http://reviews.llvm.org/D18514

llvm-svn: 265291

llvm/lib/Target/SystemZ/SystemZISelLowering.cpp
llvm/lib/Target/SystemZ/SystemZISelLowering.h
llvm/lib/Target/SystemZ/SystemZMachineFunctionInfo.h
llvm/test/CodeGen/SystemZ/frameaddr-01.ll [new file with mode: 0644]
llvm/test/CodeGen/SystemZ/ret-addr-01.ll [new file with mode: 0644]

index a670185..654f66a 100644 (file)
@@ -2676,6 +2676,57 @@ SDValue SystemZTargetLowering::lowerConstantPool(ConstantPoolSDNode *CP,
   return DAG.getNode(SystemZISD::PCREL_WRAPPER, DL, PtrVT, Result);
 }
 
+SDValue SystemZTargetLowering::lowerFRAMEADDR(SDValue Op,
+                                              SelectionDAG &DAG) const {
+  MachineFunction &MF = DAG.getMachineFunction();
+  MachineFrameInfo *MFI = MF.getFrameInfo();
+  MFI->setFrameAddressIsTaken(true);
+
+  SDLoc DL(Op);
+  unsigned Depth = cast<ConstantSDNode>(Op.getOperand(0))->getZExtValue();
+  EVT PtrVT = getPointerTy(DAG.getDataLayout());
+
+  // If the back chain frame index has not been allocated yet, do so.
+  SystemZMachineFunctionInfo *FI = MF.getInfo<SystemZMachineFunctionInfo>();
+  int BackChainIdx = FI->getFramePointerSaveIndex();
+  if (!BackChainIdx) {
+    // By definition, the frame address is the address of the back chain.
+    BackChainIdx = MFI->CreateFixedObject(8, -SystemZMC::CallFrameSize, false);
+    FI->setFramePointerSaveIndex(BackChainIdx);
+  }
+  SDValue BackChain = DAG.getFrameIndex(BackChainIdx, PtrVT);
+
+  // FIXME The frontend should detect this case.
+  if (Depth > 0) {
+    report_fatal_error("Unsupported stack frame traversal count");
+  }
+
+  return BackChain;
+}
+
+SDValue SystemZTargetLowering::lowerRETURNADDR(SDValue Op,
+                                               SelectionDAG &DAG) const {
+  MachineFunction &MF = DAG.getMachineFunction();
+  MachineFrameInfo *MFI = MF.getFrameInfo();
+  MFI->setReturnAddressIsTaken(true);
+
+  if (verifyReturnAddressArgumentIsConstant(Op, DAG))
+    return SDValue();
+
+  SDLoc DL(Op);
+  unsigned Depth = cast<ConstantSDNode>(Op.getOperand(0))->getZExtValue();
+  EVT PtrVT = getPointerTy(DAG.getDataLayout());
+
+  // FIXME The frontend should detect this case.
+  if (Depth > 0) {
+    report_fatal_error("Unsupported stack frame traversal count");
+  }
+
+  // Return R14D, which has the return address. Mark it an implicit live-in.
+  unsigned LinkReg = MF.addLiveIn(SystemZ::R14D, &SystemZ::GR64BitRegClass);
+  return DAG.getCopyFromReg(DAG.getEntryNode(), DL, LinkReg, PtrVT);
+}
+
 SDValue SystemZTargetLowering::lowerBITCAST(SDValue Op,
                                             SelectionDAG &DAG) const {
   SDLoc DL(Op);
@@ -4347,6 +4398,10 @@ SDValue SystemZTargetLowering::lowerShift(SDValue Op, SelectionDAG &DAG,
 SDValue SystemZTargetLowering::LowerOperation(SDValue Op,
                                               SelectionDAG &DAG) const {
   switch (Op.getOpcode()) {
+  case ISD::FRAMEADDR:
+    return lowerFRAMEADDR(Op, DAG);
+  case ISD::RETURNADDR:
+    return lowerRETURNADDR(Op, DAG);
   case ISD::BR_CC:
     return lowerBR_CC(Op, DAG);
   case ISD::SELECT_CC:
index 391636e..af8c67d 100644 (file)
@@ -467,6 +467,8 @@ private:
                             SelectionDAG &DAG) const;
   SDValue lowerJumpTable(JumpTableSDNode *JT, SelectionDAG &DAG) const;
   SDValue lowerConstantPool(ConstantPoolSDNode *CP, SelectionDAG &DAG) const;
+  SDValue lowerFRAMEADDR(SDValue Op, SelectionDAG &DAG) const;
+  SDValue lowerRETURNADDR(SDValue Op, SelectionDAG &DAG) const;
   SDValue lowerVASTART(SDValue Op, SelectionDAG &DAG) const;
   SDValue lowerVACOPY(SDValue Op, SelectionDAG &DAG) const;
   SDValue lowerDYNAMIC_STACKALLOC(SDValue Op, SelectionDAG &DAG) const;
index f4a517b..4f64f4c 100644 (file)
@@ -22,14 +22,15 @@ class SystemZMachineFunctionInfo : public MachineFunctionInfo {
   unsigned VarArgsFirstFPR;
   unsigned VarArgsFrameIndex;
   unsigned RegSaveFrameIndex;
+  int FramePointerSaveIndex;
   bool ManipulatesSP;
   unsigned NumLocalDynamics;
 
 public:
   explicit SystemZMachineFunctionInfo(MachineFunction &MF)
     : LowSavedGPR(0), HighSavedGPR(0), VarArgsFirstGPR(0), VarArgsFirstFPR(0),
-      VarArgsFrameIndex(0), RegSaveFrameIndex(0), ManipulatesSP(false),
-      NumLocalDynamics(0) {}
+      VarArgsFrameIndex(0), RegSaveFrameIndex(0), FramePointerSaveIndex(0),
+      ManipulatesSP(false), NumLocalDynamics(0) {}
 
   // Get and set the first call-saved GPR that should be saved and restored
   // by this function.  This is 0 if no GPRs need to be saved or restored.
@@ -59,6 +60,10 @@ public:
   unsigned getRegSaveFrameIndex() const { return RegSaveFrameIndex; }
   void setRegSaveFrameIndex(unsigned FI) { RegSaveFrameIndex = FI; }
 
+  // Get and set the frame index of where the old frame pointer is stored.
+  int getFramePointerSaveIndex() const { return FramePointerSaveIndex; }
+  void setFramePointerSaveIndex(int Idx) { FramePointerSaveIndex = Idx; }
+
   // Get and set whether the function directly manipulates the stack pointer,
   // e.g. through STACKSAVE or STACKRESTORE.
   bool getManipulatesSP() const { return ManipulatesSP; }
diff --git a/llvm/test/CodeGen/SystemZ/frameaddr-01.ll b/llvm/test/CodeGen/SystemZ/frameaddr-01.ll
new file mode 100644 (file)
index 0000000..4dfdf30
--- /dev/null
@@ -0,0 +1,28 @@
+; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s
+
+; The current function's frame address is the address of
+; the optional back chain slot.
+define i8* @fp0() nounwind {
+entry:
+; CHECK-LABEL: fp0:
+; CHECK: la   %r2, 0(%r15)
+; CHECK: br   %r14
+  %0 = tail call i8* @llvm.frameaddress(i32 0)
+  ret i8* %0
+}
+
+; Check that the frame address is correct in a presence
+; of a stack frame.
+define i8* @fp0f() nounwind {
+entry:
+; CHECK-LABEL: fp0f:
+; CHECK: aghi %r15, -168
+; CHECK: la   %r2, 168(%r15)
+; CHECK: aghi %r15, 168
+; CHECK: br   %r14
+  %0 = alloca i64, align 8
+  %1 = tail call i8* @llvm.frameaddress(i32 0)
+  ret i8* %1
+}
+
+declare i8* @llvm.frameaddress(i32) nounwind readnone
diff --git a/llvm/test/CodeGen/SystemZ/ret-addr-01.ll b/llvm/test/CodeGen/SystemZ/ret-addr-01.ll
new file mode 100644 (file)
index 0000000..9c3b246
--- /dev/null
@@ -0,0 +1,15 @@
+; Test support for the llvm.returnaddress intrinsic.
+; 
+; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s
+
+; The current function's return address is in the link register.
+define i8* @rt0() norecurse nounwind readnone {
+entry:
+; CHECK-LABEL: rt0:
+; CHECK: lgr  %r2, %r14
+; CHECK: br   %r14
+  %0 = tail call i8* @llvm.returnaddress(i32 0)
+  ret i8* %0
+}
+
+declare i8* @llvm.returnaddress(i32) nounwind readnone