forked from OSchip/llvm-project
[SystemZ] Support llvm.frameaddress/llvm.returnaddress intrinsics
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
This commit is contained in:
parent
e4a77057a3
commit
f557d08325
|
@ -2676,6 +2676,57 @@ SDValue SystemZTargetLowering::lowerConstantPool(ConstantPoolSDNode *CP,
|
||||||
return DAG.getNode(SystemZISD::PCREL_WRAPPER, DL, PtrVT, Result);
|
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,
|
SDValue SystemZTargetLowering::lowerBITCAST(SDValue Op,
|
||||||
SelectionDAG &DAG) const {
|
SelectionDAG &DAG) const {
|
||||||
SDLoc DL(Op);
|
SDLoc DL(Op);
|
||||||
|
@ -4347,6 +4398,10 @@ SDValue SystemZTargetLowering::lowerShift(SDValue Op, SelectionDAG &DAG,
|
||||||
SDValue SystemZTargetLowering::LowerOperation(SDValue Op,
|
SDValue SystemZTargetLowering::LowerOperation(SDValue Op,
|
||||||
SelectionDAG &DAG) const {
|
SelectionDAG &DAG) const {
|
||||||
switch (Op.getOpcode()) {
|
switch (Op.getOpcode()) {
|
||||||
|
case ISD::FRAMEADDR:
|
||||||
|
return lowerFRAMEADDR(Op, DAG);
|
||||||
|
case ISD::RETURNADDR:
|
||||||
|
return lowerRETURNADDR(Op, DAG);
|
||||||
case ISD::BR_CC:
|
case ISD::BR_CC:
|
||||||
return lowerBR_CC(Op, DAG);
|
return lowerBR_CC(Op, DAG);
|
||||||
case ISD::SELECT_CC:
|
case ISD::SELECT_CC:
|
||||||
|
|
|
@ -467,6 +467,8 @@ private:
|
||||||
SelectionDAG &DAG) const;
|
SelectionDAG &DAG) const;
|
||||||
SDValue lowerJumpTable(JumpTableSDNode *JT, SelectionDAG &DAG) const;
|
SDValue lowerJumpTable(JumpTableSDNode *JT, SelectionDAG &DAG) const;
|
||||||
SDValue lowerConstantPool(ConstantPoolSDNode *CP, 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 lowerVASTART(SDValue Op, SelectionDAG &DAG) const;
|
||||||
SDValue lowerVACOPY(SDValue Op, SelectionDAG &DAG) const;
|
SDValue lowerVACOPY(SDValue Op, SelectionDAG &DAG) const;
|
||||||
SDValue lowerDYNAMIC_STACKALLOC(SDValue Op, SelectionDAG &DAG) const;
|
SDValue lowerDYNAMIC_STACKALLOC(SDValue Op, SelectionDAG &DAG) const;
|
||||||
|
|
|
@ -22,14 +22,15 @@ class SystemZMachineFunctionInfo : public MachineFunctionInfo {
|
||||||
unsigned VarArgsFirstFPR;
|
unsigned VarArgsFirstFPR;
|
||||||
unsigned VarArgsFrameIndex;
|
unsigned VarArgsFrameIndex;
|
||||||
unsigned RegSaveFrameIndex;
|
unsigned RegSaveFrameIndex;
|
||||||
|
int FramePointerSaveIndex;
|
||||||
bool ManipulatesSP;
|
bool ManipulatesSP;
|
||||||
unsigned NumLocalDynamics;
|
unsigned NumLocalDynamics;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit SystemZMachineFunctionInfo(MachineFunction &MF)
|
explicit SystemZMachineFunctionInfo(MachineFunction &MF)
|
||||||
: LowSavedGPR(0), HighSavedGPR(0), VarArgsFirstGPR(0), VarArgsFirstFPR(0),
|
: LowSavedGPR(0), HighSavedGPR(0), VarArgsFirstGPR(0), VarArgsFirstFPR(0),
|
||||||
VarArgsFrameIndex(0), RegSaveFrameIndex(0), ManipulatesSP(false),
|
VarArgsFrameIndex(0), RegSaveFrameIndex(0), FramePointerSaveIndex(0),
|
||||||
NumLocalDynamics(0) {}
|
ManipulatesSP(false), NumLocalDynamics(0) {}
|
||||||
|
|
||||||
// Get and set the first call-saved GPR that should be saved and restored
|
// 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.
|
// 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; }
|
unsigned getRegSaveFrameIndex() const { return RegSaveFrameIndex; }
|
||||||
void setRegSaveFrameIndex(unsigned FI) { RegSaveFrameIndex = FI; }
|
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,
|
// Get and set whether the function directly manipulates the stack pointer,
|
||||||
// e.g. through STACKSAVE or STACKRESTORE.
|
// e.g. through STACKSAVE or STACKRESTORE.
|
||||||
bool getManipulatesSP() const { return ManipulatesSP; }
|
bool getManipulatesSP() const { return ManipulatesSP; }
|
||||||
|
|
|
@ -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
|
|
@ -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
|
Loading…
Reference in New Issue