mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-10-19 11:02:59 +02:00
[WinEH] Add codegen support for cleanuppad and cleanupret
All of the complexity is in cleanupret, and it mostly follows the same codepaths as catchret, except it doesn't take a return value in RAX. This small example now compiles and executes successfully on win32: extern "C" int printf(const char *, ...) noexcept; struct Dtor { ~Dtor() { printf("~Dtor\n"); } }; void has_cleanup() { Dtor o; throw 42; } int main() { try { has_cleanup(); } catch (int) { printf("caught it\n"); } } Don't try to put the cleanup in the same function as the catch, or Bad Things will happen. llvm-svn: 247219
This commit is contained in:
parent
ad09731a88
commit
b5753fd45f
@ -591,8 +591,13 @@ namespace ISD {
|
|||||||
/// take a chain as input and return a chain.
|
/// take a chain as input and return a chain.
|
||||||
EH_LABEL,
|
EH_LABEL,
|
||||||
|
|
||||||
|
/// CATCHRET - Represents a return from a catch block funclet. Used for
|
||||||
|
/// MSVC compatible exception handling. Takes a chain operand and a
|
||||||
|
/// destination basic block operand.
|
||||||
CATCHRET,
|
CATCHRET,
|
||||||
|
|
||||||
|
/// CLEANUPRET - Represents a return from a cleanup block funclet. Used for
|
||||||
|
/// MSVC compatible exception handling. Takes only a chain operand.
|
||||||
CLEANUPRET,
|
CLEANUPRET,
|
||||||
|
|
||||||
/// STACKSAVE - STACKSAVE has one operand, an input chain. It produces a
|
/// STACKSAVE - STACKSAVE has one operand, an input chain. It produces a
|
||||||
|
@ -116,14 +116,14 @@ void parseEHActions(const IntrinsicInst *II,
|
|||||||
// The following structs respresent the .xdata for functions using C++
|
// The following structs respresent the .xdata for functions using C++
|
||||||
// exceptions on Windows.
|
// exceptions on Windows.
|
||||||
|
|
||||||
struct WinEHUnwindMapEntry {
|
|
||||||
int ToState;
|
|
||||||
const Value *Cleanup;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef PointerUnion<const BasicBlock *, MachineBasicBlock *> MBBOrBasicBlock;
|
typedef PointerUnion<const BasicBlock *, MachineBasicBlock *> MBBOrBasicBlock;
|
||||||
typedef PointerUnion<const Value *, MachineBasicBlock *> ValueOrMBB;
|
typedef PointerUnion<const Value *, MachineBasicBlock *> ValueOrMBB;
|
||||||
|
|
||||||
|
struct WinEHUnwindMapEntry {
|
||||||
|
int ToState;
|
||||||
|
ValueOrMBB Cleanup;
|
||||||
|
};
|
||||||
|
|
||||||
/// Similar to WinEHUnwindMapEntry, but supports SEH filters.
|
/// Similar to WinEHUnwindMapEntry, but supports SEH filters.
|
||||||
struct SEHUnwindMapEntry {
|
struct SEHUnwindMapEntry {
|
||||||
/// If unwinding continues through this handler, transition to the handler at
|
/// If unwinding continues through this handler, transition to the handler at
|
||||||
|
@ -316,10 +316,11 @@ void WinException::emitCSpecificHandlerTable(const MachineFunction *MF) {
|
|||||||
/// Retreive the MCSymbol for a GlobalValue or MachineBasicBlock. GlobalValues
|
/// Retreive the MCSymbol for a GlobalValue or MachineBasicBlock. GlobalValues
|
||||||
/// are used in the old WinEH scheme, and they will be removed eventually.
|
/// are used in the old WinEH scheme, and they will be removed eventually.
|
||||||
static MCSymbol *getMCSymbolForMBBOrGV(AsmPrinter *Asm, ValueOrMBB Handler) {
|
static MCSymbol *getMCSymbolForMBBOrGV(AsmPrinter *Asm, ValueOrMBB Handler) {
|
||||||
|
if (!Handler)
|
||||||
|
return nullptr;
|
||||||
if (Handler.is<MachineBasicBlock *>())
|
if (Handler.is<MachineBasicBlock *>())
|
||||||
return Handler.get<MachineBasicBlock *>()->getSymbol();
|
return Handler.get<MachineBasicBlock *>()->getSymbol();
|
||||||
else
|
return Asm->getSymbol(cast<GlobalValue>(Handler.get<const Value *>()));
|
||||||
return Asm->getSymbol(cast<GlobalValue>(Handler.get<const Value *>()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void WinException::emitCXXFrameHandler3Table(const MachineFunction *MF) {
|
void WinException::emitCXXFrameHandler3Table(const MachineFunction *MF) {
|
||||||
@ -404,8 +405,9 @@ void WinException::emitCXXFrameHandler3Table(const MachineFunction *MF) {
|
|||||||
if (UnwindMapXData) {
|
if (UnwindMapXData) {
|
||||||
OS.EmitLabel(UnwindMapXData);
|
OS.EmitLabel(UnwindMapXData);
|
||||||
for (const WinEHUnwindMapEntry &UME : FuncInfo.UnwindMap) {
|
for (const WinEHUnwindMapEntry &UME : FuncInfo.UnwindMap) {
|
||||||
OS.EmitIntValue(UME.ToState, 4); // ToState
|
MCSymbol *CleanupSym = getMCSymbolForMBBOrGV(Asm, UME.Cleanup);
|
||||||
OS.EmitValue(create32bitRef(UME.Cleanup), 4); // Action
|
OS.EmitIntValue(UME.ToState, 4); // ToState
|
||||||
|
OS.EmitValue(create32bitRef(CleanupSym), 4); // Action
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -223,8 +223,6 @@ void FunctionLoweringInfo::set(const Function &fn, MachineFunction &mf,
|
|||||||
assert(&*BB->begin() == I &&
|
assert(&*BB->begin() == I &&
|
||||||
"WinEHPrepare failed to remove PHIs from imaginary BBs");
|
"WinEHPrepare failed to remove PHIs from imaginary BBs");
|
||||||
continue;
|
continue;
|
||||||
} else if (!isa<LandingPadInst>(I)) {
|
|
||||||
llvm_unreachable("unhandled EH pad in MBB graph");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -269,7 +267,7 @@ void FunctionLoweringInfo::set(const Function &fn, MachineFunction &mf,
|
|||||||
SmallVector<const LandingPadInst *, 4> LPads;
|
SmallVector<const LandingPadInst *, 4> LPads;
|
||||||
for (BB = Fn->begin(); BB != EB; ++BB) {
|
for (BB = Fn->begin(); BB != EB; ++BB) {
|
||||||
const Instruction *FNP = BB->getFirstNonPHI();
|
const Instruction *FNP = BB->getFirstNonPHI();
|
||||||
if (BB->isEHPad() && !isa<CatchPadInst>(FNP) && !isa<CatchEndPadInst>(FNP))
|
if (BB->isEHPad() && MBBMap.count(BB))
|
||||||
MBBMap[BB]->setIsEHPad();
|
MBBMap[BB]->setIsEHPad();
|
||||||
if (const auto *LPI = dyn_cast<LandingPadInst>(FNP))
|
if (const auto *LPI = dyn_cast<LandingPadInst>(FNP))
|
||||||
LPads.push_back(LPI);
|
LPads.push_back(LPI);
|
||||||
@ -289,24 +287,27 @@ void FunctionLoweringInfo::set(const Function &fn, MachineFunction &mf,
|
|||||||
|
|
||||||
// Calculate state numbers if we haven't already.
|
// Calculate state numbers if we haven't already.
|
||||||
WinEHFuncInfo &EHInfo = MMI.getWinEHFuncInfo(&fn);
|
WinEHFuncInfo &EHInfo = MMI.getWinEHFuncInfo(&fn);
|
||||||
if (Personality == EHPersonality::MSVC_CXX) {
|
const Function *WinEHParentFn = MMI.getWinEHParent(&fn);
|
||||||
const Function *WinEHParentFn = MMI.getWinEHParent(&fn);
|
if (Personality == EHPersonality::MSVC_CXX)
|
||||||
calculateWinCXXEHStateNumbers(WinEHParentFn, EHInfo);
|
calculateWinCXXEHStateNumbers(WinEHParentFn, EHInfo);
|
||||||
} else {
|
else
|
||||||
const Function *WinEHParentFn = MMI.getWinEHParent(&fn);
|
|
||||||
calculateSEHStateNumbers(WinEHParentFn, EHInfo);
|
calculateSEHStateNumbers(WinEHParentFn, EHInfo);
|
||||||
|
|
||||||
|
// Map all BB references in the WinEH data to MBBs.
|
||||||
|
for (WinEHTryBlockMapEntry &TBME : EHInfo.TryBlockMap)
|
||||||
|
for (WinEHHandlerType &H : TBME.HandlerArray)
|
||||||
|
if (const auto *BB =
|
||||||
|
dyn_cast<BasicBlock>(H.Handler.get<const Value *>()))
|
||||||
|
H.Handler = MBBMap[BB];
|
||||||
|
for (WinEHUnwindMapEntry &UME : EHInfo.UnwindMap)
|
||||||
|
if (UME.Cleanup)
|
||||||
|
if (const auto *BB = dyn_cast<BasicBlock>(UME.Cleanup.get<const Value *>()))
|
||||||
|
UME.Cleanup = MBBMap[BB];
|
||||||
|
for (SEHUnwindMapEntry &UME : EHInfo.SEHUnwindMap) {
|
||||||
|
const BasicBlock *BB = UME.Handler.get<const BasicBlock *>();
|
||||||
|
UME.Handler = MBBMap[BB];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Map all BB references in the EH data to MBBs.
|
|
||||||
for (WinEHTryBlockMapEntry &TBME : EHInfo.TryBlockMap)
|
|
||||||
for (WinEHHandlerType &H : TBME.HandlerArray)
|
|
||||||
if (const auto *BB =
|
|
||||||
dyn_cast<BasicBlock>(H.Handler.get<const Value *>()))
|
|
||||||
H.Handler = MBBMap[BB];
|
|
||||||
for (SEHUnwindMapEntry &UME : EHInfo.SEHUnwindMap) {
|
|
||||||
const BasicBlock *BB = UME.Handler.get<const BasicBlock *>();
|
|
||||||
UME.Handler = MBBMap[BB];
|
|
||||||
}
|
|
||||||
// If there's an explicit EH registration node on the stack, record its
|
// If there's an explicit EH registration node on the stack, record its
|
||||||
// frame index.
|
// frame index.
|
||||||
if (EHInfo.EHRegNode && EHInfo.EHRegNode->getParent()->getParent() == Fn) {
|
if (EHInfo.EHRegNode && EHInfo.EHRegNode->getParent()->getParent() == Fn) {
|
||||||
|
@ -1165,9 +1165,8 @@ void SelectionDAGBuilder::visitCatchPad(const CatchPadInst &I) {
|
|||||||
|
|
||||||
void SelectionDAGBuilder::visitCatchRet(const CatchReturnInst &I) {
|
void SelectionDAGBuilder::visitCatchRet(const CatchReturnInst &I) {
|
||||||
// Update machine-CFG edge.
|
// Update machine-CFG edge.
|
||||||
MachineBasicBlock *PadMBB = FuncInfo.MBB;
|
|
||||||
MachineBasicBlock *TargetMBB = FuncInfo.MBBMap[I.getSuccessor()];
|
MachineBasicBlock *TargetMBB = FuncInfo.MBBMap[I.getSuccessor()];
|
||||||
PadMBB->addSuccessor(TargetMBB);
|
FuncInfo.MBB->addSuccessor(TargetMBB);
|
||||||
|
|
||||||
// Create the terminator node.
|
// Create the terminator node.
|
||||||
SDValue Ret = DAG.getNode(ISD::CATCHRET, getCurSDLoc(), MVT::Other,
|
SDValue Ret = DAG.getNode(ISD::CATCHRET, getCurSDLoc(), MVT::Other,
|
||||||
@ -1180,11 +1179,64 @@ void SelectionDAGBuilder::visitCatchEndPad(const CatchEndPadInst &I) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void SelectionDAGBuilder::visitCleanupPad(const CleanupPadInst &CPI) {
|
void SelectionDAGBuilder::visitCleanupPad(const CleanupPadInst &CPI) {
|
||||||
report_fatal_error("visitCleanupPad not yet implemented!");
|
// Don't emit any special code for the cleanuppad instruction. It just marks
|
||||||
|
// the start of a funclet.
|
||||||
|
FuncInfo.MBB->setIsEHFuncletEntry();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// When an invoke or a cleanupret unwinds to the next EH pad, there are
|
||||||
|
/// many places it could ultimately go. In the IR, we have a single unwind
|
||||||
|
/// destination, but in the machine CFG, we enumerate all the possible blocks.
|
||||||
|
/// This function skips over imaginary basic blocks that hold catchpad,
|
||||||
|
/// terminatepad, or catchendpad instructions, and finds all the "real" machine
|
||||||
|
/// basic block destinations.
|
||||||
|
static void
|
||||||
|
findUnwindDestinations(FunctionLoweringInfo &FuncInfo,
|
||||||
|
const BasicBlock *EHPadBB,
|
||||||
|
SmallVectorImpl<MachineBasicBlock *> &UnwindDests) {
|
||||||
|
bool IsMSVCCXX = classifyEHPersonality(FuncInfo.Fn->getPersonalityFn()) ==
|
||||||
|
EHPersonality::MSVC_CXX;
|
||||||
|
while (EHPadBB) {
|
||||||
|
const Instruction *Pad = EHPadBB->getFirstNonPHI();
|
||||||
|
if (isa<LandingPadInst>(Pad)) {
|
||||||
|
// Stop on landingpads. They are not funclets.
|
||||||
|
UnwindDests.push_back(FuncInfo.MBBMap[EHPadBB]);
|
||||||
|
break;
|
||||||
|
} else if (isa<CleanupPadInst>(Pad) || isa<LandingPadInst>(Pad)) {
|
||||||
|
// Stop on cleanup pads. Cleanups are always funclet entries for all known
|
||||||
|
// personalities.
|
||||||
|
UnwindDests.push_back(FuncInfo.MBBMap[EHPadBB]);
|
||||||
|
UnwindDests.back()->setIsEHFuncletEntry();
|
||||||
|
break;
|
||||||
|
} else if (const auto *CPI = dyn_cast<CatchPadInst>(Pad)) {
|
||||||
|
// Add the catchpad handler to the possible destinations.
|
||||||
|
UnwindDests.push_back(FuncInfo.MBBMap[CPI->getNormalDest()]);
|
||||||
|
// In MSVC C++, catchblocks are funclets and need prologues.
|
||||||
|
if (IsMSVCCXX)
|
||||||
|
UnwindDests.back()->setIsEHFuncletEntry();
|
||||||
|
EHPadBB = CPI->getUnwindDest();
|
||||||
|
} else if (const auto *CEPI = dyn_cast<CatchEndPadInst>(Pad)) {
|
||||||
|
EHPadBB = CEPI->getUnwindDest();
|
||||||
|
} else if (const auto *CEPI = dyn_cast<CleanupEndPadInst>(Pad)) {
|
||||||
|
EHPadBB = CEPI->getUnwindDest();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SelectionDAGBuilder::visitCleanupRet(const CleanupReturnInst &I) {
|
void SelectionDAGBuilder::visitCleanupRet(const CleanupReturnInst &I) {
|
||||||
report_fatal_error("visitCleanupRet not yet implemented!");
|
// Update successor info.
|
||||||
|
// FIXME: The weights for catchpads will be wrong.
|
||||||
|
SmallVector<MachineBasicBlock *, 1> UnwindDests;
|
||||||
|
findUnwindDestinations(FuncInfo, I.getUnwindDest(), UnwindDests);
|
||||||
|
for (MachineBasicBlock *UnwindDest : UnwindDests) {
|
||||||
|
UnwindDest->setIsEHPad();
|
||||||
|
addSuccessorWithWeight(FuncInfo.MBB, UnwindDest);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the terminator node.
|
||||||
|
SDValue Ret =
|
||||||
|
DAG.getNode(ISD::CLEANUPRET, getCurSDLoc(), MVT::Other, getControlRoot());
|
||||||
|
DAG.setRoot(Ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SelectionDAGBuilder::visitCleanupEndPad(const CleanupEndPadInst &I) {
|
void SelectionDAGBuilder::visitCleanupEndPad(const CleanupEndPadInst &I) {
|
||||||
@ -2020,37 +2072,8 @@ void SelectionDAGBuilder::visitInvoke(const InvokeInst &I) {
|
|||||||
CopyToExportRegsIfNeeded(&I);
|
CopyToExportRegsIfNeeded(&I);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stop when we hit a pad that generates real code or we unwind to caller.
|
|
||||||
// Catchpads are conditional branches that add real MBB destinations and
|
|
||||||
// continue the loop. EH "end" pads are not real BBs and simply continue.
|
|
||||||
SmallVector<MachineBasicBlock *, 1> UnwindDests;
|
SmallVector<MachineBasicBlock *, 1> UnwindDests;
|
||||||
bool IsMSVCCXX = classifyEHPersonality(FuncInfo.Fn->getPersonalityFn()) ==
|
findUnwindDestinations(FuncInfo, EHPadBB, UnwindDests);
|
||||||
EHPersonality::MSVC_CXX;
|
|
||||||
while (EHPadBB) {
|
|
||||||
const Instruction *Pad = EHPadBB->getFirstNonPHI();
|
|
||||||
if (isa<LandingPadInst>(Pad)) {
|
|
||||||
// Stop on landingpads. They are not funclets.
|
|
||||||
UnwindDests.push_back(FuncInfo.MBBMap[EHPadBB]);
|
|
||||||
break;
|
|
||||||
} else if (isa<CleanupPadInst>(Pad) || isa<LandingPadInst>(Pad)) {
|
|
||||||
// Stop on cleanup pads. Cleanups are always funclet entries for all known
|
|
||||||
// personalities.
|
|
||||||
UnwindDests.push_back(FuncInfo.MBBMap[EHPadBB]);
|
|
||||||
UnwindDests.back()->setIsEHFuncletEntry();
|
|
||||||
break;
|
|
||||||
} else if (const auto *CPI = dyn_cast<CatchPadInst>(Pad)) {
|
|
||||||
// Add the catchpad handler to the possible destinations.
|
|
||||||
UnwindDests.push_back(FuncInfo.MBBMap[CPI->getNormalDest()]);
|
|
||||||
// In MSVC C++, catchblocks are funclets and need prologues.
|
|
||||||
if (IsMSVCCXX)
|
|
||||||
UnwindDests.back()->setIsEHFuncletEntry();
|
|
||||||
EHPadBB = CPI->getUnwindDest();
|
|
||||||
} else if (const auto *CEPI = dyn_cast<CatchEndPadInst>(Pad)) {
|
|
||||||
EHPadBB = CEPI->getUnwindDest();
|
|
||||||
} else if (const auto *CEPI = dyn_cast<CleanupEndPadInst>(Pad)) {
|
|
||||||
EHPadBB = CEPI->getUnwindDest();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update successor info.
|
// Update successor info.
|
||||||
// FIXME: The weights for catchpads will be wrong.
|
// FIXME: The weights for catchpads will be wrong.
|
||||||
|
@ -3053,7 +3053,7 @@ static void calculateExplicitCXXStateNumbers(WinEHFuncInfo &FuncInfo,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int addSEHHandler(WinEHFuncInfo &FuncInfo, int ParentState,
|
static int addSEHHandler(WinEHFuncInfo &FuncInfo, int ParentState,
|
||||||
const Function *Filter, const BasicBlock *Handler) {
|
const Function *Filter, const BasicBlock *Handler) {
|
||||||
SEHUnwindMapEntry Entry;
|
SEHUnwindMapEntry Entry;
|
||||||
Entry.ToState = ParentState;
|
Entry.ToState = ParentState;
|
||||||
Entry.Filter = Filter;
|
Entry.Filter = Filter;
|
||||||
|
@ -1030,6 +1030,8 @@ static bool isFuncletReturnInstr(MachineInstr *MI) {
|
|||||||
switch (MI->getOpcode()) {
|
switch (MI->getOpcode()) {
|
||||||
case X86::CATCHRET:
|
case X86::CATCHRET:
|
||||||
case X86::CATCHRET64:
|
case X86::CATCHRET64:
|
||||||
|
case X86::CLEANUPRET:
|
||||||
|
case X86::CLEANUPRET64:
|
||||||
return true;
|
return true;
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
|
@ -418,6 +418,7 @@ X86TargetLowering::X86TargetLowering(const X86TargetMachine &TM,
|
|||||||
}
|
}
|
||||||
setOperationAction(ISD::EH_RETURN , MVT::Other, Custom);
|
setOperationAction(ISD::EH_RETURN , MVT::Other, Custom);
|
||||||
setOperationAction(ISD::CATCHRET , MVT::Other, Custom);
|
setOperationAction(ISD::CATCHRET , MVT::Other, Custom);
|
||||||
|
setOperationAction(ISD::CLEANUPRET , MVT::Other, Custom);
|
||||||
// NOTE: EH_SJLJ_SETJMP/_LONGJMP supported here is NOT intended to support
|
// NOTE: EH_SJLJ_SETJMP/_LONGJMP supported here is NOT intended to support
|
||||||
// SjLj exception handling but a light-weight setjmp/longjmp replacement to
|
// SjLj exception handling but a light-weight setjmp/longjmp replacement to
|
||||||
// support continuation, user-level threading, and etc.. As a result, no
|
// support continuation, user-level threading, and etc.. As a result, no
|
||||||
@ -16889,20 +16890,26 @@ SDValue X86TargetLowering::LowerCATCHRET(SDValue Op, SelectionDAG &DAG) const {
|
|||||||
return DAG.getNode(ISD::BR, DL, MVT::Other, Chain, Dest);
|
return DAG.getNode(ISD::BR, DL, MVT::Other, Chain, Dest);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
unsigned ReturnReg = (PtrVT == MVT::i64 ? X86::RAX : X86::EAX);
|
unsigned ReturnReg = (PtrVT == MVT::i64 ? X86::RAX : X86::EAX);
|
||||||
|
|
||||||
// Load the address of the destination block.
|
// Load the address of the destination block.
|
||||||
|
// FIXME: Do this without creating a BlockAddress.
|
||||||
MachineBasicBlock *DestMBB = cast<BasicBlockSDNode>(Dest)->getBasicBlock();
|
MachineBasicBlock *DestMBB = cast<BasicBlockSDNode>(Dest)->getBasicBlock();
|
||||||
SDValue BlockPtr = DAG.getMCSymbol(DestMBB->getSymbol(), PtrVT);
|
BlockAddress *BA =
|
||||||
unsigned WrapperKind =
|
BlockAddress::get(const_cast<Function *>(MF.getFunction()),
|
||||||
Subtarget->isPICStyleRIPRel() ? X86ISD::WrapperRIP : X86ISD::Wrapper;
|
const_cast<BasicBlock *>(DestMBB->getBasicBlock()));
|
||||||
SDValue WrappedPtr = DAG.getNode(WrapperKind, DL, PtrVT, BlockPtr);
|
DestMBB->setHasAddressTaken();
|
||||||
Chain = DAG.getCopyToReg(Chain, DL, ReturnReg, WrappedPtr);
|
SDValue BlockPtr = DAG.getBlockAddress(BA, PtrVT);
|
||||||
|
Chain = DAG.getCopyToReg(Chain, DL, ReturnReg, BlockPtr);
|
||||||
return DAG.getNode(X86ISD::CATCHRET, DL, MVT::Other, Chain,
|
return DAG.getNode(X86ISD::CATCHRET, DL, MVT::Other, Chain,
|
||||||
DAG.getRegister(ReturnReg, PtrVT));
|
DAG.getRegister(ReturnReg, PtrVT));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SDValue X86TargetLowering::LowerCLEANUPRET(SDValue Op, SelectionDAG &DAG) const {
|
||||||
|
return DAG.getNode(X86ISD::CLEANUPRET, SDLoc(Op), MVT::Other,
|
||||||
|
Op.getOperand(0));
|
||||||
|
}
|
||||||
|
|
||||||
SDValue X86TargetLowering::lowerEH_SJLJ_SETJMP(SDValue Op,
|
SDValue X86TargetLowering::lowerEH_SJLJ_SETJMP(SDValue Op,
|
||||||
SelectionDAG &DAG) const {
|
SelectionDAG &DAG) const {
|
||||||
SDLoc DL(Op);
|
SDLoc DL(Op);
|
||||||
@ -19142,6 +19149,7 @@ SDValue X86TargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) const {
|
|||||||
return LowerFRAME_TO_ARGS_OFFSET(Op, DAG);
|
return LowerFRAME_TO_ARGS_OFFSET(Op, DAG);
|
||||||
case ISD::DYNAMIC_STACKALLOC: return LowerDYNAMIC_STACKALLOC(Op, DAG);
|
case ISD::DYNAMIC_STACKALLOC: return LowerDYNAMIC_STACKALLOC(Op, DAG);
|
||||||
case ISD::EH_RETURN: return LowerEH_RETURN(Op, DAG);
|
case ISD::EH_RETURN: return LowerEH_RETURN(Op, DAG);
|
||||||
|
case ISD::CLEANUPRET: return LowerCLEANUPRET(Op, DAG);
|
||||||
case ISD::CATCHRET: return LowerCATCHRET(Op, DAG);
|
case ISD::CATCHRET: return LowerCATCHRET(Op, DAG);
|
||||||
case ISD::EH_SJLJ_SETJMP: return lowerEH_SJLJ_SETJMP(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_LONGJMP: return lowerEH_SJLJ_LONGJMP(Op, DAG);
|
||||||
@ -19480,6 +19488,7 @@ const char *X86TargetLowering::getTargetNodeName(unsigned Opcode) const {
|
|||||||
case X86ISD::EH_SJLJ_LONGJMP: return "X86ISD::EH_SJLJ_LONGJMP";
|
case X86ISD::EH_SJLJ_LONGJMP: return "X86ISD::EH_SJLJ_LONGJMP";
|
||||||
case X86ISD::EH_RETURN: return "X86ISD::EH_RETURN";
|
case X86ISD::EH_RETURN: return "X86ISD::EH_RETURN";
|
||||||
case X86ISD::CATCHRET: return "X86ISD::CATCHRET";
|
case X86ISD::CATCHRET: return "X86ISD::CATCHRET";
|
||||||
|
case X86ISD::CLEANUPRET: return "X86ISD::CLEANUPRET";
|
||||||
case X86ISD::TC_RETURN: return "X86ISD::TC_RETURN";
|
case X86ISD::TC_RETURN: return "X86ISD::TC_RETURN";
|
||||||
case X86ISD::FNSTCW16m: return "X86ISD::FNSTCW16m";
|
case X86ISD::FNSTCW16m: return "X86ISD::FNSTCW16m";
|
||||||
case X86ISD::FNSTSW16r: return "X86ISD::FNSTSW16r";
|
case X86ISD::FNSTSW16r: return "X86ISD::FNSTSW16r";
|
||||||
|
@ -268,8 +268,14 @@ namespace llvm {
|
|||||||
// Exception Handling helpers.
|
// Exception Handling helpers.
|
||||||
EH_RETURN,
|
EH_RETURN,
|
||||||
|
|
||||||
|
// CATCHRET - Represents a return from a catch block funclet. Used for
|
||||||
|
// MSVC compatible exception handling. Takes a chain operand and RAX.
|
||||||
CATCHRET,
|
CATCHRET,
|
||||||
|
|
||||||
|
// CLEANUPRET - Represents a return from a cleanup block funclet. Used
|
||||||
|
// for MSVC compatible exception handling. Takes only a chain operand.
|
||||||
|
CLEANUPRET,
|
||||||
|
|
||||||
// SjLj exception handling setjmp.
|
// SjLj exception handling setjmp.
|
||||||
EH_SJLJ_SETJMP,
|
EH_SJLJ_SETJMP,
|
||||||
|
|
||||||
@ -1009,6 +1015,7 @@ namespace llvm {
|
|||||||
SDValue LowerFRAME_TO_ARGS_OFFSET(SDValue Op, SelectionDAG &DAG) const;
|
SDValue LowerFRAME_TO_ARGS_OFFSET(SDValue Op, SelectionDAG &DAG) const;
|
||||||
SDValue LowerEH_RETURN(SDValue Op, SelectionDAG &DAG) const;
|
SDValue LowerEH_RETURN(SDValue Op, SelectionDAG &DAG) const;
|
||||||
SDValue LowerCATCHRET(SDValue Op, SelectionDAG &DAG) const;
|
SDValue LowerCATCHRET(SDValue Op, SelectionDAG &DAG) const;
|
||||||
|
SDValue LowerCLEANUPRET(SDValue Op, SelectionDAG &DAG) const;
|
||||||
SDValue lowerEH_SJLJ_SETJMP(SDValue Op, SelectionDAG &DAG) const;
|
SDValue lowerEH_SJLJ_SETJMP(SDValue Op, SelectionDAG &DAG) const;
|
||||||
SDValue lowerEH_SJLJ_LONGJMP(SDValue Op, SelectionDAG &DAG) const;
|
SDValue lowerEH_SJLJ_LONGJMP(SDValue Op, SelectionDAG &DAG) const;
|
||||||
SDValue LowerINIT_TRAMPOLINE(SDValue Op, SelectionDAG &DAG) const;
|
SDValue LowerINIT_TRAMPOLINE(SDValue Op, SelectionDAG &DAG) const;
|
||||||
|
@ -159,6 +159,14 @@ def CATCHRET : I<0xC3, RawFrm, (outs), (ins GR32:$addr),
|
|||||||
def CATCHRET64 : I<0xC3, RawFrm, (outs), (ins GR64:$addr),
|
def CATCHRET64 : I<0xC3, RawFrm, (outs), (ins GR64:$addr),
|
||||||
"ret{q}\t# CATCHRET",
|
"ret{q}\t# CATCHRET",
|
||||||
[(X86catchret GR64:$addr)], IIC_RET>, Sched<[WriteJumpLd]>;
|
[(X86catchret GR64:$addr)], IIC_RET>, Sched<[WriteJumpLd]>;
|
||||||
|
def CLEANUPRET : I<0xC3, RawFrm, (outs), (ins),
|
||||||
|
"ret{l}\t# CLEANUPRET",
|
||||||
|
[(X86cleanupret)], IIC_RET>, Sched<[WriteJumpLd]>,
|
||||||
|
Requires<[Not64BitMode]>;
|
||||||
|
def CLEANUPRET64 : I<0xC3, RawFrm, (outs), (ins),
|
||||||
|
"ret{q}\t# CLEANUPRET",
|
||||||
|
[(X86cleanupret)], IIC_RET>, Sched<[WriteJumpLd]>,
|
||||||
|
Requires<[In64BitMode]>;
|
||||||
}
|
}
|
||||||
|
|
||||||
let hasSideEffects = 1, isBarrier = 1, isCodeGenOnly = 1,
|
let hasSideEffects = 1, isBarrier = 1, isCodeGenOnly = 1,
|
||||||
|
@ -207,6 +207,8 @@ def X86ehret : SDNode<"X86ISD::EH_RETURN", SDT_X86EHRET,
|
|||||||
|
|
||||||
def X86catchret : SDNode<"X86ISD::CATCHRET", SDT_X86EHRET, [SDNPHasChain]>;
|
def X86catchret : SDNode<"X86ISD::CATCHRET", SDT_X86EHRET, [SDNPHasChain]>;
|
||||||
|
|
||||||
|
def X86cleanupret : SDNode<"X86ISD::CLEANUPRET", SDTX86Void, [SDNPHasChain]>;
|
||||||
|
|
||||||
def X86eh_sjlj_setjmp : SDNode<"X86ISD::EH_SJLJ_SETJMP",
|
def X86eh_sjlj_setjmp : SDNode<"X86ISD::EH_SJLJ_SETJMP",
|
||||||
SDTypeProfile<1, 1, [SDTCisInt<0>,
|
SDTypeProfile<1, 1, [SDTCisInt<0>,
|
||||||
SDTCisPtrTy<1>]>,
|
SDTCisPtrTy<1>]>,
|
||||||
|
@ -63,7 +63,7 @@ catchendblock: ; preds = %catch,
|
|||||||
; X86: movl $0, -{{[0-9]+}}(%ebp)
|
; X86: movl $0, -{{[0-9]+}}(%ebp)
|
||||||
; X86: movl $1, (%esp)
|
; X86: movl $1, (%esp)
|
||||||
; X86: calll _f
|
; X86: calll _f
|
||||||
; X86: [[contbb:LBB0_[0-9]+]]:
|
; X86: [[contbb:Ltmp[0-9]+]]: # Block address taken
|
||||||
; X86: movl -{{[0-9]+}}(%ebp), %esp
|
; X86: movl -{{[0-9]+}}(%ebp), %esp
|
||||||
; X86: addl ${{[0-9]+}}, %esp
|
; X86: addl ${{[0-9]+}}, %esp
|
||||||
; X86: popl %esi
|
; X86: popl %esi
|
||||||
@ -111,7 +111,7 @@ catchendblock: ; preds = %catch,
|
|||||||
; X64: callq useints
|
; X64: callq useints
|
||||||
; X64: movl $1, %ecx
|
; X64: movl $1, %ecx
|
||||||
; X64: callq f
|
; X64: callq f
|
||||||
; X64: [[contbb:\.LBB0_[0-9]+]]:
|
; X64: [[contbb:.Ltmp[0-9]+]]: # Block address taken
|
||||||
; X64: addq $40, %rsp
|
; X64: addq $40, %rsp
|
||||||
; X64: popq %rbp
|
; X64: popq %rbp
|
||||||
; X64: retq
|
; X64: retq
|
||||||
|
@ -71,7 +71,7 @@ catchendblock: ; preds = %catch, %catch.2, %c
|
|||||||
; X86-DAG: movl %[[addr_reg]], 4(%esp)
|
; X86-DAG: movl %[[addr_reg]], 4(%esp)
|
||||||
; X86-DAG: movl $1, (%esp)
|
; X86-DAG: movl $1, (%esp)
|
||||||
; X86: calll _f
|
; X86: calll _f
|
||||||
; X86: [[contbb:LBB0_[0-9]+]]:
|
; X86: [[contbb:Ltmp[0-9]+]]: # Block address taken
|
||||||
; X86: movl -{{[0-9]+}}(%ebp), %esp
|
; X86: movl -{{[0-9]+}}(%ebp), %esp
|
||||||
; X86: retl
|
; X86: retl
|
||||||
|
|
||||||
@ -120,7 +120,7 @@ catchendblock: ; preds = %catch, %catch.2, %c
|
|||||||
; X64-DAG: leaq -[[local_offs:[0-9]+]](%rbp), %rdx
|
; X64-DAG: leaq -[[local_offs:[0-9]+]](%rbp), %rdx
|
||||||
; X64-DAG: movl $1, %ecx
|
; X64-DAG: movl $1, %ecx
|
||||||
; X64: callq f
|
; X64: callq f
|
||||||
; X64: [[contbb:\.LBB0_[0-9]+]]:
|
; X64: [[contbb:.Ltmp[0-9]+]]: # Block address taken
|
||||||
; X64: addq $48, %rsp
|
; X64: addq $48, %rsp
|
||||||
; X64: popq %rbp
|
; X64: popq %rbp
|
||||||
; X64: retq
|
; X64: retq
|
||||||
|
Loading…
Reference in New Issue
Block a user