diff options
author | Reid Kleckner <rnk@google.com> | 2015-09-10 00:25:23 +0000 |
---|---|---|
committer | Reid Kleckner <rnk@google.com> | 2015-09-10 00:25:23 +0000 |
commit | 787839120885519d4cbff64ad59e179bdf3744fa (patch) | |
tree | dd894b990329961d9452bd1f672fe38c263c7100 /llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp | |
parent | 60f3e1f466c9dfa834ab9e71ae4fe0589a42774f (diff) | |
download | bcm5719-llvm-787839120885519d4cbff64ad59e179bdf3744fa.tar.gz bcm5719-llvm-787839120885519d4cbff64ad59e179bdf3744fa.zip |
[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
Diffstat (limited to 'llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp')
-rw-r--r-- | llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp | 91 |
1 files changed, 57 insertions, 34 deletions
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp index 6fba18d60b2..2885776a306 100644 --- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp @@ -1165,9 +1165,8 @@ void SelectionDAGBuilder::visitCatchPad(const CatchPadInst &I) { void SelectionDAGBuilder::visitCatchRet(const CatchReturnInst &I) { // Update machine-CFG edge. - MachineBasicBlock *PadMBB = FuncInfo.MBB; MachineBasicBlock *TargetMBB = FuncInfo.MBBMap[I.getSuccessor()]; - PadMBB->addSuccessor(TargetMBB); + FuncInfo.MBB->addSuccessor(TargetMBB); // Create the terminator node. 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) { - 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) { - 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) { @@ -2020,37 +2072,8 @@ void SelectionDAGBuilder::visitInvoke(const InvokeInst &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; - 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(); - } - } + findUnwindDestinations(FuncInfo, EHPadBB, UnwindDests); // Update successor info. // FIXME: The weights for catchpads will be wrong. |