mirror of
https://github.com/RPCS3/llvm.git
synced 2024-11-27 21:50:29 +00:00
Add a pre-dispatch SjLj EH hook on the unwind edge for targets to do any
setup they require. Use this for ARM/Darwin to rematerialize the base pointer from the frame pointer when required. rdar://8564268 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@116879 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
db4708cf86
commit
e4ad387a5a
@ -40,6 +40,7 @@
|
||||
<li><a href="#llvm_eh_sjlj_longjmp"><tt>llvm.eh.sjlj.longjmp</tt></a></li>
|
||||
<li><a href="#llvm_eh_sjlj_lsda"><tt>llvm.eh.sjlj.lsda</tt></a></li>
|
||||
<li><a href="#llvm_eh_sjlj_callsite"><tt>llvm.eh.sjlj.callsite</tt></a></li>
|
||||
<li><a href="#llvm_eh_sjlj_dispatchsetup"><tt>llvm.eh.sjlj.dispatchsetup</tt></a></li>
|
||||
</ol></li>
|
||||
<li><a href="#asm">Asm Table Formats</a>
|
||||
<ol>
|
||||
@ -547,6 +548,23 @@
|
||||
|
||||
</div>
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<div class="doc_subsubsection">
|
||||
<a name="llvm_eh_sjlj_dispatchsetup">llvm.eh.sjlj.dispatchsetup</a>
|
||||
</div>
|
||||
|
||||
<div class="doc_text">
|
||||
|
||||
<pre>
|
||||
void %<a href="#llvm_eh_sjlj_dispatchsetup">llvm.eh.sjlj.dispatchsetup</a>(i32)
|
||||
</pre>
|
||||
|
||||
<p>For SJLJ based exception handling, the <a href="#llvm_eh_sjlj_dispatchsetup">
|
||||
<tt>llvm.eh.sjlj.dispatchsetup</tt></a> intrinsic is used by targets to do
|
||||
any unwind-edge setup they need. By default, no action is taken. </p>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- ======================================================================= -->
|
||||
<div class="doc_section">
|
||||
<a name="asm">Asm Table Formats</a>
|
||||
|
@ -107,6 +107,13 @@ namespace ISD {
|
||||
// and returns an outchain.
|
||||
EH_SJLJ_LONGJMP,
|
||||
|
||||
// OUTCHAIN = EH_SJLJ_DISPATCHSETUP(INCHAIN, context)
|
||||
// This corresponds to the eh.sjlj.dispatchsetup intrinsic. It takes an
|
||||
// incput chain and a pointer to the sjlj function context as inputs and
|
||||
// returns an outchain. By default, this does nothing. Targets can lower
|
||||
// this to unwind setup code if needed.
|
||||
EH_SJLJ_DISPATCHSETUP,
|
||||
|
||||
// TargetConstant* - Like Constant*, but the DAG does not do any folding,
|
||||
// simplification, or lowering of the constant. They are used for constants
|
||||
// which are known to fit in the immediate fields of their users, or for
|
||||
|
@ -307,6 +307,7 @@ let Properties = [IntrNoMem] in {
|
||||
def int_eh_sjlj_lsda : Intrinsic<[llvm_ptr_ty]>;
|
||||
def int_eh_sjlj_callsite: Intrinsic<[], [llvm_i32_ty]>;
|
||||
}
|
||||
def int_eh_sjlj_dispatch_setup : Intrinsic<[], [llvm_ptr_ty]>;
|
||||
def int_eh_sjlj_setjmp : Intrinsic<[llvm_i32_ty], [llvm_ptr_ty]>;
|
||||
def int_eh_sjlj_longjmp : Intrinsic<[], [llvm_ptr_ty]>;
|
||||
|
||||
|
@ -865,6 +865,7 @@ SDValue SelectionDAGLegalize::LegalizeOp(SDValue Op) {
|
||||
case ISD::FRAME_TO_ARGS_OFFSET:
|
||||
case ISD::EH_SJLJ_SETJMP:
|
||||
case ISD::EH_SJLJ_LONGJMP:
|
||||
case ISD::EH_SJLJ_DISPATCHSETUP:
|
||||
// These operations lie about being legal: when they claim to be legal,
|
||||
// they should actually be expanded.
|
||||
Action = TLI.getOperationAction(Node->getOpcode(), Node->getValueType(0));
|
||||
@ -2541,9 +2542,14 @@ void SelectionDAGLegalize::ExpandNode(SDNode *Node,
|
||||
case ISD::PREFETCH:
|
||||
case ISD::VAEND:
|
||||
case ISD::EH_SJLJ_LONGJMP:
|
||||
case ISD::EH_SJLJ_DISPATCHSETUP:
|
||||
// If the target didn't expand these, there's nothing to do, so just
|
||||
// preserve the chain and be done.
|
||||
Results.push_back(Node->getOperand(0));
|
||||
break;
|
||||
case ISD::EH_SJLJ_SETJMP:
|
||||
// If the target didn't expand this, just return 'zero' and preserve the
|
||||
// chain.
|
||||
Results.push_back(DAG.getConstant(0, MVT::i32));
|
||||
Results.push_back(Node->getOperand(0));
|
||||
break;
|
||||
|
@ -5616,6 +5616,7 @@ std::string SDNode::getOperationName(const SelectionDAG *G) const {
|
||||
case ISD::EH_RETURN: return "EH_RETURN";
|
||||
case ISD::EH_SJLJ_SETJMP: return "EH_SJLJ_SETJMP";
|
||||
case ISD::EH_SJLJ_LONGJMP: return "EH_SJLJ_LONGJMP";
|
||||
case ISD::EH_SJLJ_DISPATCHSETUP: return "EH_SJLJ_DISPATCHSETUP";
|
||||
case ISD::ConstantPool: return "ConstantPool";
|
||||
case ISD::ExternalSymbol: return "ExternalSymbol";
|
||||
case ISD::BlockAddress: return "BlockAddress";
|
||||
|
@ -4319,8 +4319,12 @@ SelectionDAGBuilder::visitIntrinsicCall(const CallInst &I, unsigned Intrinsic) {
|
||||
}
|
||||
case Intrinsic::eh_sjlj_longjmp: {
|
||||
DAG.setRoot(DAG.getNode(ISD::EH_SJLJ_LONGJMP, dl, MVT::Other,
|
||||
getRoot(),
|
||||
getValue(I.getArgOperand(0))));
|
||||
getRoot(), getValue(I.getArgOperand(0))));
|
||||
return 0;
|
||||
}
|
||||
case Intrinsic::eh_sjlj_dispatch_setup: {
|
||||
DAG.setRoot(DAG.getNode(ISD::EH_SJLJ_DISPATCHSETUP, dl, MVT::Other,
|
||||
getRoot(), getValue(I.getArgOperand(0))));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -53,6 +53,7 @@ namespace {
|
||||
Constant *SelectorFn;
|
||||
Constant *ExceptionFn;
|
||||
Constant *CallSiteFn;
|
||||
Constant *DispatchSetupFn;
|
||||
|
||||
Value *CallSite;
|
||||
public:
|
||||
@ -116,6 +117,8 @@ bool SjLjEHPass::doInitialization(Module &M) {
|
||||
SelectorFn = Intrinsic::getDeclaration(&M, Intrinsic::eh_selector);
|
||||
ExceptionFn = Intrinsic::getDeclaration(&M, Intrinsic::eh_exception);
|
||||
CallSiteFn = Intrinsic::getDeclaration(&M, Intrinsic::eh_sjlj_callsite);
|
||||
DispatchSetupFn
|
||||
= Intrinsic::getDeclaration(&M, Intrinsic::eh_sjlj_dispatch_setup);
|
||||
PersonalityFn = 0;
|
||||
|
||||
return true;
|
||||
@ -438,9 +441,17 @@ bool SjLjEHPass::insertSjLjEHSupport(Function &F) {
|
||||
BasicBlock *DispatchBlock =
|
||||
BasicBlock::Create(F.getContext(), "eh.sjlj.setjmp.catch", &F);
|
||||
|
||||
// Insert a load in the Catch block, and a switch on its value. By default,
|
||||
// we go to a block that just does an unwind (which is the correct action
|
||||
// for a standard call).
|
||||
// Add a call to dispatch_setup at the start of the dispatch block. This
|
||||
// is expanded to any target-specific setup that needs to be done.
|
||||
Value *SetupArg =
|
||||
CastInst::Create(Instruction::BitCast, FunctionContext,
|
||||
Type::getInt8PtrTy(F.getContext()), "",
|
||||
DispatchBlock);
|
||||
CallInst::Create(DispatchSetupFn, SetupArg, "", DispatchBlock);
|
||||
|
||||
// Insert a load of the callsite in the dispatch block, and a switch on
|
||||
// its value. By default, we go to a block that just does an unwind
|
||||
// (which is the correct action for a standard call).
|
||||
BasicBlock *UnwindBlock =
|
||||
BasicBlock::Create(F.getContext(), "unwindbb", &F);
|
||||
Unwinds.push_back(new UnwindInst(F.getContext(), UnwindBlock));
|
||||
|
@ -447,6 +447,12 @@ void emitT2RegPlusImmediate(MachineBasicBlock &MBB,
|
||||
unsigned DestReg, unsigned BaseReg, int NumBytes,
|
||||
ARMCC::CondCodes Pred, unsigned PredReg,
|
||||
const ARMBaseInstrInfo &TII);
|
||||
void emitThumbRegPlusImmediate(MachineBasicBlock &MBB,
|
||||
MachineBasicBlock::iterator &MBBI,
|
||||
unsigned DestReg, unsigned BaseReg,
|
||||
int NumBytes, const TargetInstrInfo &TII,
|
||||
const ARMBaseRegisterInfo& MRI,
|
||||
DebugLoc dl);
|
||||
|
||||
|
||||
/// rewriteARMFrameIndex / rewriteT2FrameIndex -
|
||||
|
@ -18,10 +18,14 @@
|
||||
#include "ARM.h"
|
||||
#include "ARMAddressingModes.h"
|
||||
#include "ARMBaseInstrInfo.h"
|
||||
#include "ARMBaseRegisterInfo.h"
|
||||
#include "ARMMachineFunctionInfo.h"
|
||||
#include "ARMRegisterInfo.h"
|
||||
#include "llvm/CodeGen/MachineFrameInfo.h"
|
||||
#include "llvm/CodeGen/MachineFunctionPass.h"
|
||||
#include "llvm/CodeGen/MachineInstrBuilder.h"
|
||||
#include "llvm/Target/TargetRegisterInfo.h"
|
||||
#include "llvm/Support/raw_ostream.h" // FIXME: for debug only. remove!
|
||||
using namespace llvm;
|
||||
|
||||
namespace {
|
||||
@ -30,7 +34,7 @@ namespace {
|
||||
static char ID;
|
||||
ARMExpandPseudo() : MachineFunctionPass(ID) {}
|
||||
|
||||
const TargetInstrInfo *TII;
|
||||
const ARMBaseInstrInfo *TII;
|
||||
const TargetRegisterInfo *TRI;
|
||||
|
||||
virtual bool runOnMachineFunction(MachineFunction &Fn);
|
||||
@ -576,6 +580,38 @@ bool ARMExpandPseudo::ExpandMBB(MachineBasicBlock &MBB) {
|
||||
ModifiedOp = false;
|
||||
break;
|
||||
|
||||
case ARM::Int_eh_sjlj_dispatchsetup: {
|
||||
MachineFunction &MF = *MI.getParent()->getParent();
|
||||
const ARMBaseInstrInfo *AII =
|
||||
static_cast<const ARMBaseInstrInfo*>(TII);
|
||||
const ARMBaseRegisterInfo &RI = AII->getRegisterInfo();
|
||||
// For functions using a base pointer, we rematerialize it (via the frame
|
||||
// pointer) here since eh.sjlj.setjmp and eh.sjlj.longjmp don't do it
|
||||
// for us. Otherwise, expand to nothing.
|
||||
if (RI.hasBasePointer(MF)) {
|
||||
ARMFunctionInfo *AFI = MF.getInfo<ARMFunctionInfo>();
|
||||
int32_t NumBytes = AFI->getFramePtrSpillOffset();
|
||||
unsigned FramePtr = RI.getFrameRegister(MF);
|
||||
assert (RI.hasFP(MF) && "base pointer without frame pointer?");
|
||||
|
||||
if (AFI->isThumb2Function()) {
|
||||
llvm::emitT2RegPlusImmediate(MBB, MBBI, MI.getDebugLoc(), ARM::R6,
|
||||
FramePtr, -NumBytes, ARMCC::AL, 0, *TII);
|
||||
} else if (AFI->isThumbFunction()) {
|
||||
llvm::emitThumbRegPlusImmediate(MBB, MBBI, ARM::R6,
|
||||
FramePtr, -NumBytes,
|
||||
*TII, RI, MI.getDebugLoc());
|
||||
} else {
|
||||
llvm::emitARMRegPlusImmediate(MBB, MBBI, MI.getDebugLoc(), ARM::R6,
|
||||
FramePtr, -NumBytes, ARMCC::AL, 0,
|
||||
*TII);
|
||||
}
|
||||
|
||||
}
|
||||
MI.eraseFromParent();
|
||||
break;
|
||||
}
|
||||
|
||||
case ARM::MOVsrl_flag:
|
||||
case ARM::MOVsra_flag: {
|
||||
// These are just fancy MOVs insructions.
|
||||
@ -953,7 +989,7 @@ bool ARMExpandPseudo::ExpandMBB(MachineBasicBlock &MBB) {
|
||||
}
|
||||
|
||||
bool ARMExpandPseudo::runOnMachineFunction(MachineFunction &MF) {
|
||||
TII = MF.getTarget().getInstrInfo();
|
||||
TII = static_cast<const ARMBaseInstrInfo*>(MF.getTarget().getInstrInfo());
|
||||
TRI = MF.getTarget().getRegisterInfo();
|
||||
|
||||
bool Modified = false;
|
||||
|
@ -612,6 +612,7 @@ ARMTargetLowering::ARMTargetLowering(TargetMachine &TM)
|
||||
if (Subtarget->isTargetDarwin()) {
|
||||
setOperationAction(ISD::EH_SJLJ_SETJMP, MVT::i32, Custom);
|
||||
setOperationAction(ISD::EH_SJLJ_LONGJMP, MVT::Other, Custom);
|
||||
setOperationAction(ISD::EH_SJLJ_DISPATCHSETUP, MVT::Other, Custom);
|
||||
}
|
||||
|
||||
setOperationAction(ISD::SETCC, MVT::i32, Expand);
|
||||
@ -755,6 +756,7 @@ const char *ARMTargetLowering::getTargetNodeName(unsigned Opcode) const {
|
||||
|
||||
case ARMISD::EH_SJLJ_SETJMP: return "ARMISD::EH_SJLJ_SETJMP";
|
||||
case ARMISD::EH_SJLJ_LONGJMP:return "ARMISD::EH_SJLJ_LONGJMP";
|
||||
case ARMISD::EH_SJLJ_DISPATCHSETUP:return "ARMISD::EH_SJLJ_DISPATCHSETUP";
|
||||
|
||||
case ARMISD::TC_RETURN: return "ARMISD::TC_RETURN";
|
||||
|
||||
@ -1947,6 +1949,14 @@ SDValue ARMTargetLowering::LowerGLOBAL_OFFSET_TABLE(SDValue Op,
|
||||
return DAG.getNode(ARMISD::PIC_ADD, dl, PtrVT, Result, PICLabel);
|
||||
}
|
||||
|
||||
SDValue
|
||||
ARMTargetLowering::LowerEH_SJLJ_DISPATCHSETUP(SDValue Op, SelectionDAG &DAG)
|
||||
const {
|
||||
DebugLoc dl = Op.getDebugLoc();
|
||||
return DAG.getNode(ARMISD::EH_SJLJ_DISPATCHSETUP, dl, MVT::Other,
|
||||
Op.getOperand(0), Op.getOperand(1));
|
||||
}
|
||||
|
||||
SDValue
|
||||
ARMTargetLowering::LowerEH_SJLJ_SETJMP(SDValue Op, SelectionDAG &DAG) const {
|
||||
DebugLoc dl = Op.getDebugLoc();
|
||||
@ -3813,6 +3823,7 @@ SDValue ARMTargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) const {
|
||||
case ISD::GLOBAL_OFFSET_TABLE: return LowerGLOBAL_OFFSET_TABLE(Op, DAG);
|
||||
case ISD::EH_SJLJ_SETJMP: return LowerEH_SJLJ_SETJMP(Op, DAG);
|
||||
case ISD::EH_SJLJ_LONGJMP: return LowerEH_SJLJ_LONGJMP(Op, DAG);
|
||||
case ISD::EH_SJLJ_DISPATCHSETUP: return LowerEH_SJLJ_DISPATCHSETUP(Op, DAG);
|
||||
case ISD::INTRINSIC_WO_CHAIN: return LowerINTRINSIC_WO_CHAIN(Op, DAG,
|
||||
Subtarget);
|
||||
case ISD::BIT_CONVERT: return ExpandBIT_CONVERT(Op.getNode(), DAG);
|
||||
|
@ -71,8 +71,9 @@ namespace llvm {
|
||||
VMOVRRD, // double to two gprs.
|
||||
VMOVDRR, // Two gprs to double.
|
||||
|
||||
EH_SJLJ_SETJMP, // SjLj exception handling setjmp.
|
||||
EH_SJLJ_LONGJMP, // SjLj exception handling longjmp.
|
||||
EH_SJLJ_SETJMP, // SjLj exception handling setjmp.
|
||||
EH_SJLJ_LONGJMP, // SjLj exception handling longjmp.
|
||||
EH_SJLJ_DISPATCHSETUP, // SjLj exception handling dispatch setup.
|
||||
|
||||
TC_RETURN, // Tail call return pseudo.
|
||||
|
||||
@ -332,6 +333,7 @@ namespace llvm {
|
||||
ISD::ArgFlagsTy Flags) const;
|
||||
SDValue LowerEH_SJLJ_SETJMP(SDValue Op, SelectionDAG &DAG) const;
|
||||
SDValue LowerEH_SJLJ_LONGJMP(SDValue Op, SelectionDAG &DAG) const;
|
||||
SDValue LowerEH_SJLJ_DISPATCHSETUP(SDValue Op, SelectionDAG &DAG) const;
|
||||
SDValue LowerINTRINSIC_WO_CHAIN(SDValue Op, SelectionDAG &DAG,
|
||||
const ARMSubtarget *Subtarget) const;
|
||||
SDValue LowerBlockAddress(SDValue Op, SelectionDAG &DAG) const;
|
||||
|
@ -58,6 +58,8 @@ def SDT_ARMEH_SJLJ_Setjmp : SDTypeProfile<1, 2, [SDTCisInt<0>, SDTCisPtrTy<1>,
|
||||
SDTCisInt<2>]>;
|
||||
def SDT_ARMEH_SJLJ_Longjmp: SDTypeProfile<0, 2, [SDTCisPtrTy<0>, SDTCisInt<1>]>;
|
||||
|
||||
def SDT_ARMEH_SJLJ_DispatchSetup: SDTypeProfile<0, 1, [SDTCisPtrTy<0>]>;
|
||||
|
||||
def SDT_ARMMEMBARRIER : SDTypeProfile<0, 0, []>;
|
||||
def SDT_ARMSYNCBARRIER : SDTypeProfile<0, 0, []>;
|
||||
def SDT_ARMMEMBARRIERMCR : SDTypeProfile<0, 1, [SDTCisInt<0>]>;
|
||||
@ -122,7 +124,10 @@ def ARMthread_pointer: SDNode<"ARMISD::THREAD_POINTER", SDT_ARMThreadPointer>;
|
||||
def ARMeh_sjlj_setjmp: SDNode<"ARMISD::EH_SJLJ_SETJMP",
|
||||
SDT_ARMEH_SJLJ_Setjmp, [SDNPHasChain]>;
|
||||
def ARMeh_sjlj_longjmp: SDNode<"ARMISD::EH_SJLJ_LONGJMP",
|
||||
SDT_ARMEH_SJLJ_Longjmp, [SDNPHasChain]>;
|
||||
SDT_ARMEH_SJLJ_Longjmp, [SDNPHasChain]>;
|
||||
def ARMeh_sjlj_dispatchsetup: SDNode<"ARMISD::EH_SJLJ_DISPATCHSETUP",
|
||||
SDT_ARMEH_SJLJ_DispatchSetup, [SDNPHasChain]>;
|
||||
|
||||
|
||||
def ARMMemBarrier : SDNode<"ARMISD::MEMBARRIER", SDT_ARMMEMBARRIER,
|
||||
[SDNPHasChain]>;
|
||||
@ -3010,6 +3015,16 @@ def Int_eh_sjlj_longjmp : XI<(outs), (ins GPR:$src, GPR:$scratch),
|
||||
Requires<[IsARM, IsDarwin]>;
|
||||
}
|
||||
|
||||
// eh.sjlj.dispatchsetup pseudo-instruction.
|
||||
// This pseudo is usef for ARM, Thumb1 and Thumb2. Any differences are
|
||||
// handled when the pseudo is expanded (which happens before any passes
|
||||
// that need the instruction size).
|
||||
let isBarrier = 1, hasSideEffects = 1 in
|
||||
def Int_eh_sjlj_dispatchsetup :
|
||||
PseudoInst<(outs), (ins GPR:$src), NoItinerary, "",
|
||||
[(ARMeh_sjlj_dispatchsetup GPR:$src)]>,
|
||||
Requires<[IsDarwin]>;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Non-Instruction Patterns
|
||||
//
|
||||
|
@ -92,7 +92,7 @@ void emitThumbRegPlusImmInReg(MachineBasicBlock &MBB,
|
||||
unsigned DestReg, unsigned BaseReg,
|
||||
int NumBytes, bool CanChangeCC,
|
||||
const TargetInstrInfo &TII,
|
||||
const Thumb1RegisterInfo& MRI,
|
||||
const ARMBaseRegisterInfo& MRI,
|
||||
DebugLoc dl) {
|
||||
MachineFunction &MF = *MBB.getParent();
|
||||
bool isHigh = !isARMLowRegister(DestReg) ||
|
||||
@ -162,13 +162,12 @@ static unsigned calcNumMI(int Opc, int ExtraOpc, unsigned Bytes,
|
||||
|
||||
/// emitThumbRegPlusImmediate - Emits a series of instructions to materialize
|
||||
/// a destreg = basereg + immediate in Thumb code.
|
||||
static
|
||||
void emitThumbRegPlusImmediate(MachineBasicBlock &MBB,
|
||||
MachineBasicBlock::iterator &MBBI,
|
||||
unsigned DestReg, unsigned BaseReg,
|
||||
int NumBytes, const TargetInstrInfo &TII,
|
||||
const Thumb1RegisterInfo& MRI,
|
||||
DebugLoc dl) {
|
||||
void llvm::emitThumbRegPlusImmediate(MachineBasicBlock &MBB,
|
||||
MachineBasicBlock::iterator &MBBI,
|
||||
unsigned DestReg, unsigned BaseReg,
|
||||
int NumBytes, const TargetInstrInfo &TII,
|
||||
const ARMBaseRegisterInfo& MRI,
|
||||
DebugLoc dl) {
|
||||
bool isSub = NumBytes < 0;
|
||||
unsigned Bytes = (unsigned)NumBytes;
|
||||
if (isSub) Bytes = -NumBytes;
|
||||
|
Loading…
Reference in New Issue
Block a user