diff options
author | David Majnemer <david.majnemer@gmail.com> | 2015-03-31 22:35:44 +0000 |
---|---|---|
committer | David Majnemer <david.majnemer@gmail.com> | 2015-03-31 22:35:44 +0000 |
commit | a225a19dd0739024f6a232d601c381d217483ca8 (patch) | |
tree | e6a8e66c4c9342738f47595835c157a9101bcce5 /llvm/lib/CodeGen | |
parent | 6a9c46bc3f02573c51eb7eaf48872423f18f4745 (diff) | |
download | bcm5719-llvm-a225a19dd0739024f6a232d601c381d217483ca8.tar.gz bcm5719-llvm-a225a19dd0739024f6a232d601c381d217483ca8.zip |
[WinEH] Generate .xdata for catch handlers
This lets us catch exceptions in simple cases.
N.B. Things that do not work include (but are not limited to):
- Throwing from within a catch handler.
- Catching an object with a named catch parameter.
- 'CatchHigh' is fictitious, we aren't sure of its purpose.
- We aren't entirely efficient with regards to the number of EH states
that we generate.
- IP-to-State tables are sensitive to the order of emission.
llvm-svn: 233767
Diffstat (limited to 'llvm/lib/CodeGen')
-rw-r--r-- | llvm/lib/CodeGen/AsmPrinter/Win64Exception.cpp | 34 | ||||
-rw-r--r-- | llvm/lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp | 135 | ||||
-rw-r--r-- | llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp | 12 | ||||
-rw-r--r-- | llvm/lib/CodeGen/WinEHPrepare.cpp | 10 |
4 files changed, 135 insertions, 56 deletions
diff --git a/llvm/lib/CodeGen/AsmPrinter/Win64Exception.cpp b/llvm/lib/CodeGen/AsmPrinter/Win64Exception.cpp index 974e94dcb6a..7a82daa3337 100644 --- a/llvm/lib/CodeGen/AsmPrinter/Win64Exception.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/Win64Exception.cpp @@ -68,6 +68,27 @@ void Win64Exception::beginFunction(const MachineFunction *MF) { shouldEmitLSDA = shouldEmitPersonality && LSDAEncoding != dwarf::DW_EH_PE_omit; + + // If this was an outlined handler, we need to define the label corresponding + // to the offset of the parent frame relative to the stack pointer after the + // prologue. + const Function *F = MF->getFunction(); + const Function *ParentF = MMI->getWinEHParent(F); + if (F != ParentF) { + WinEHFuncInfo &FuncInfo = MMI->getWinEHFuncInfo(ParentF); + auto I = FuncInfo.CatchHandlerParentFrameObjOffset.find(F); + if (I != FuncInfo.CatchHandlerParentFrameObjOffset.end()) { + MCSymbol *HandlerTypeParentFrameOffset = + Asm->OutContext.getOrCreateParentFrameOffsetSymbol( + GlobalValue::getRealLinkageName(F->getName())); + + // Emit a symbol assignment. + Asm->OutStreamer.EmitAssignment( + HandlerTypeParentFrameOffset, + MCConstantExpr::Create(I->second, Asm->OutContext)); + } + } + if (!shouldEmitPersonality && !shouldEmitMoves) return; @@ -253,6 +274,7 @@ void Win64Exception::emitCXXFrameHandler3Table(const MachineFunction *MF) { const Function *F = MF->getFunction(); const Function *ParentF = MMI->getWinEHParent(F); auto &OS = Asm->OutStreamer; + WinEHFuncInfo &FuncInfo = MMI->getWinEHFuncInfo(ParentF); StringRef ParentLinkageName = GlobalValue::getRealLinkageName(ParentF->getName()); @@ -279,8 +301,6 @@ void Win64Exception::emitCXXFrameHandler3Table(const MachineFunction *MF) { // an ordinary call) between the end of the previous try-range and now. bool SawPotentiallyThrowing = false; - WinEHFuncInfo &FuncInfo = MMI->getWinEHFuncInfo(ParentF); - int LastEHState = -2; // The parent function and the catch handlers contribute to the 'ip2state' @@ -424,11 +444,17 @@ void Win64Exception::emitCXXFrameHandler3Table(const MachineFunction *MF) { // }; OS.EmitLabel(HandlerMapXData); for (const WinEHHandlerType &HT : TBME.HandlerArray) { + MCSymbol *ParentFrameOffset = + Asm->OutContext.getOrCreateParentFrameOffsetSymbol( + GlobalValue::getRealLinkageName(HT.Handler->getName())); + const MCSymbolRefExpr *ParentFrameOffsetRef = MCSymbolRefExpr::Create( + ParentFrameOffset, MCSymbolRefExpr::VK_None, Asm->OutContext); + OS.EmitIntValue(HT.Adjectives, 4); // Adjectives OS.EmitValue(createImageRel32(HT.TypeDescriptor), 4); // Type - OS.EmitIntValue(0, 4); // CatchObjOffset + OS.EmitIntValue(HT.CatchObjOffset, 4); // CatchObjOffset OS.EmitValue(createImageRel32(HT.Handler), 4); // Handler - OS.EmitIntValue(0, 4); // ParentFrameOffset + OS.EmitValue(ParentFrameOffsetRef, 4); // ParentFrameOffset } } } diff --git a/llvm/lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp b/llvm/lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp index c00b11893bf..e2235fbc044 100644 --- a/llvm/lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp @@ -88,6 +88,7 @@ struct WinEHNumbering { int NextState; SmallVector<ActionHandler *, 4> HandlerStack; + SmallPtrSet<const Function *, 4> VisitedHandlers; int currentEHNumber() const { return HandlerStack.empty() ? -1 : HandlerStack.back()->getEHState(); @@ -96,7 +97,9 @@ struct WinEHNumbering { void parseEHActions(const IntrinsicInst *II, SmallVectorImpl<ActionHandler *> &Actions); void createUnwindMapEntry(int ToState, ActionHandler *AH); - void proccessCallSite(ArrayRef<ActionHandler *> Actions, ImmutableCallSite CS); + void createTryBlockMapEntry(int TryLow, int TryHigh, + ArrayRef<CatchHandler *> Handlers); + void processCallSite(ArrayRef<ActionHandler *> Actions, ImmutableCallSite CS); void calculateStateNumbers(const Function &F); }; } @@ -276,8 +279,12 @@ void FunctionLoweringInfo::set(const Function &fn, MachineFunction &mf, MBBMap[Invoke->getSuccessor(1)]->setIsLandingPad(); // Calculate EH numbers for WinEH. - if (fn.getFnAttribute("wineh-parent").getValueAsString() == fn.getName()) - WinEHNumbering(MMI.getWinEHFuncInfo(&fn)).calculateStateNumbers(fn); + if (fn.getFnAttribute("wineh-parent").getValueAsString() == fn.getName()) { + WinEHNumbering Num(MMI.getWinEHFuncInfo(&fn)); + Num.calculateStateNumbers(fn); + // Pop everything on the handler stack. + Num.processCallSite(None, ImmutableCallSite()); + } } void WinEHNumbering::parseEHActions(const IntrinsicInst *II, @@ -309,13 +316,42 @@ void WinEHNumbering::parseEHActions(const IntrinsicInst *II, void WinEHNumbering::createUnwindMapEntry(int ToState, ActionHandler *AH) { WinEHUnwindMapEntry UME; UME.ToState = ToState; - if (auto *CH = dyn_cast<CleanupHandler>(AH)) + if (auto *CH = dyn_cast_or_null<CleanupHandler>(AH)) UME.Cleanup = cast<Function>(CH->getHandlerBlockOrFunc()); else UME.Cleanup = nullptr; FuncInfo.UnwindMap.push_back(UME); } +void WinEHNumbering::createTryBlockMapEntry(int TryLow, int TryHigh, + ArrayRef<CatchHandler *> Handlers) { + WinEHTryBlockMapEntry TBME; + TBME.TryLow = TryLow; + TBME.TryHigh = TryHigh; + // FIXME: This should be revisited when we want to throw inside a catch + // handler. + TBME.CatchHigh = INT_MAX; + assert(TBME.TryLow <= TBME.TryHigh); + assert(TBME.CatchHigh > TBME.TryHigh); + for (CatchHandler *CH : Handlers) { + WinEHHandlerType HT; + auto *GV = cast<GlobalVariable>(CH->getSelector()->stripPointerCasts()); + // Selectors are always pointers to GlobalVariables with 'struct' type. + // The struct has two fields, adjectives and a type descriptor. + auto *CS = cast<ConstantStruct>(GV->getInitializer()); + HT.Adjectives = + cast<ConstantInt>(CS->getAggregateElement(0U))->getZExtValue(); + HT.TypeDescriptor = cast<GlobalVariable>( + CS->getAggregateElement(1)->stripPointerCasts()); + HT.Handler = cast<Function>(CH->getHandlerBlockOrFunc()); + // FIXME: We don't support catching objects yet! + HT.CatchObjIdx = INT_MAX; + HT.CatchObjOffset = 0; + TBME.HandlerArray.push_back(HT); + } + FuncInfo.TryBlockMap.push_back(TBME); +} + static void print_name(const Value *V) { #ifndef NDEBUG if (!V) { @@ -330,10 +366,8 @@ static void print_name(const Value *V) { #endif } -void WinEHNumbering::proccessCallSite(ArrayRef<ActionHandler *> Actions, - ImmutableCallSite CS) { - // float, int - // float, double, int +void WinEHNumbering::processCallSite(ArrayRef<ActionHandler *> Actions, + ImmutableCallSite CS) { int FirstMismatch = 0; for (int E = std::min(HandlerStack.size(), Actions.size()); FirstMismatch < E; ++FirstMismatch) { @@ -343,28 +377,65 @@ void WinEHNumbering::proccessCallSite(ArrayRef<ActionHandler *> Actions, delete Actions[FirstMismatch]; } + bool EnteringScope = (int)Actions.size() > FirstMismatch; + bool ExitingScope = (int)HandlerStack.size() > FirstMismatch; + // Don't recurse while we are looping over the handler stack. Instead, defer // the numbering of the catch handlers until we are done popping. - SmallVector<const Function *, 4> UnnumberedHandlers; + SmallVector<CatchHandler *, 4> PoppedCatches; for (int I = HandlerStack.size() - 1; I >= FirstMismatch; --I) { - if (auto *CH = dyn_cast<CatchHandler>(HandlerStack.back())) - if (const auto *F = dyn_cast<Function>(CH->getHandlerBlockOrFunc())) - UnnumberedHandlers.push_back(F); - // Pop the handlers off of the stack. - delete HandlerStack.back(); + if (auto *CH = dyn_cast<CatchHandler>(HandlerStack.back())) { + PoppedCatches.push_back(CH); + } else { + // Delete cleanup handlers + delete HandlerStack.back(); + } HandlerStack.pop_back(); } - for (const Function *F : UnnumberedHandlers) - calculateStateNumbers(*F); + // We need to create a new state number if we are exiting a try scope and we + // will not push any more actions. + int TryHigh = NextState - 1; + if (ExitingScope && !EnteringScope && !PoppedCatches.empty()) { + createUnwindMapEntry(currentEHNumber(), nullptr); + ++NextState; + } + + int LastTryLowIdx = 0; + for (int I = 0, E = PoppedCatches.size(); I != E; ++I) { + CatchHandler *CH = PoppedCatches[I]; + if (I + 1 == E || CH->getEHState() != PoppedCatches[I + 1]->getEHState()) { + int TryLow = CH->getEHState(); + auto Handlers = + makeArrayRef(&PoppedCatches[LastTryLowIdx], I - LastTryLowIdx + 1); + createTryBlockMapEntry(TryLow, TryHigh, Handlers); + LastTryLowIdx = I + 1; + } + } + for (CatchHandler *CH : PoppedCatches) { + if (auto *F = dyn_cast<Function>(CH->getHandlerBlockOrFunc())) + calculateStateNumbers(*F); + delete CH; + } + + bool LastActionWasCatch = false; for (size_t I = FirstMismatch; I != Actions.size(); ++I) { - createUnwindMapEntry(currentEHNumber(), Actions[I]); - Actions[I]->setEHState(NextState++); - DEBUG(dbgs() << "Creating unwind map entry for: ("); - print_name(Actions[I]->getHandlerBlockOrFunc()); - DEBUG(dbgs() << ", " << currentEHNumber() << ")\n"); + // We can reuse eh states when pushing two catches for the same invoke. + bool CurrActionIsCatch = isa<CatchHandler>(Actions[I]); + // FIXME: Reenable this optimization! + if (CurrActionIsCatch && LastActionWasCatch && false) { + Actions[I]->setEHState(currentEHNumber()); + } else { + createUnwindMapEntry(currentEHNumber(), Actions[I]); + Actions[I]->setEHState(NextState); + NextState++; + DEBUG(dbgs() << "Creating unwind map entry for: ("); + print_name(Actions[I]->getHandlerBlockOrFunc()); + DEBUG(dbgs() << ", " << currentEHNumber() << ")\n"); + } HandlerStack.push_back(Actions[I]); + LastActionWasCatch = CurrActionIsCatch; } DEBUG(dbgs() << "In EHState " << currentEHNumber() << " for CallSite: "); @@ -373,6 +444,10 @@ void WinEHNumbering::proccessCallSite(ArrayRef<ActionHandler *> Actions, } void WinEHNumbering::calculateStateNumbers(const Function &F) { + auto I = VisitedHandlers.insert(&F); + if (!I.second) + return; // We've already visited this handler, don't renumber it. + DEBUG(dbgs() << "Calculating state numbers for: " << F.getName() << '\n'); SmallVector<ActionHandler *, 4> ActionList; for (const BasicBlock &BB : F) { @@ -380,21 +455,21 @@ void WinEHNumbering::calculateStateNumbers(const Function &F) { const auto *CI = dyn_cast<CallInst>(&I); if (!CI || CI->doesNotThrow()) continue; - proccessCallSite(None, CI); + processCallSite(None, CI); } const auto *II = dyn_cast<InvokeInst>(BB.getTerminator()); if (!II) continue; const LandingPadInst *LPI = II->getLandingPadInst(); - if (auto *ActionsCall = dyn_cast<IntrinsicInst>(LPI->getNextNode())) { - assert(ActionsCall->getIntrinsicID() == Intrinsic::eh_actions); - parseEHActions(ActionsCall, ActionList); - proccessCallSite(ActionList, II); - ActionList.clear(); - FuncInfo.LandingPadStateMap[LPI] = currentEHNumber(); - } + auto *ActionsCall = dyn_cast<IntrinsicInst>(LPI->getNextNode()); + if (!ActionsCall) + continue; + assert(ActionsCall->getIntrinsicID() == Intrinsic::eh_actions); + parseEHActions(ActionsCall, ActionList); + processCallSite(ActionList, II); + ActionList.clear(); + FuncInfo.LandingPadStateMap[LPI] = currentEHNumber(); } - proccessCallSite(None, ImmutableCallSite()); } /// clear - Clear out all the function-specific state. This returns this diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp index fd9d7e6b69a..fa58614a4b3 100644 --- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp @@ -5450,18 +5450,6 @@ SelectionDAGBuilder::visitIntrinsicCall(const CallInst &I, unsigned Intrinsic) { case Intrinsic::eh_begincatch: case Intrinsic::eh_endcatch: llvm_unreachable("begin/end catch intrinsics not lowered in codegen"); - case Intrinsic::eh_parentframe: { - AllocaInst *Slot = - cast<AllocaInst>(I.getArgOperand(0)->stripPointerCasts()); - assert(FuncInfo.StaticAllocaMap.count(Slot) && - "can only use static allocas with llvm.eh.parentframe"); - int FI = FuncInfo.StaticAllocaMap[Slot]; - MachineFunction &MF = DAG.getMachineFunction(); - const Function *F = MF.getFunction(); - MachineModuleInfo &MMI = MF.getMMI(); - MMI.getWinEHFuncInfo(F).CatchHandlerParentFrameObjIdx[F] = FI; - return nullptr; - } case Intrinsic::eh_unwindhelp: { AllocaInst *Slot = cast<AllocaInst>(I.getArgOperand(0)->stripPointerCasts()); diff --git a/llvm/lib/CodeGen/WinEHPrepare.cpp b/llvm/lib/CodeGen/WinEHPrepare.cpp index 94e046c424d..5b4ee17d949 100644 --- a/llvm/lib/CodeGen/WinEHPrepare.cpp +++ b/llvm/lib/CodeGen/WinEHPrepare.cpp @@ -638,16 +638,6 @@ bool WinEHPrepare::outlineHandler(ActionHandler *Action, Function *SrcFn, if (!LPadMap.isInitialized()) LPadMap.mapLandingPad(LPad); if (auto *CatchAction = dyn_cast<CatchHandler>(Action)) { - // Insert an alloca for the object which holds the address of the parent's - // frame pointer. The stack offset of this object needs to be encoded in - // xdata. - AllocaInst *ParentFrame = new AllocaInst(Int8PtrType, "parentframe", Entry); - Builder.CreateStore(&Handler->getArgumentList().back(), ParentFrame, - /*isStore=*/true); - Function *ParentFrameFn = - Intrinsic::getDeclaration(M, Intrinsic::eh_parentframe); - Builder.CreateCall(ParentFrameFn, ParentFrame); - Constant *Sel = CatchAction->getSelector(); Director.reset(new WinEHCatchDirector(Handler, Sel, VarInfo, LPadMap)); LPadMap.remapSelector(VMap, ConstantInt::get(Type::getInt32Ty(Context), 1)); |