namespace {
struct WinEHNumbering {
- WinEHNumbering(WinEHFuncInfo &FuncInfo) : FuncInfo(FuncInfo), NextState(0) {}
+ WinEHNumbering(WinEHFuncInfo &FuncInfo) : FuncInfo(FuncInfo),
+ CurrentBaseState(-1), NextState(0) {}
WinEHFuncInfo &FuncInfo;
+ int CurrentBaseState;
int NextState;
- SmallVector<ActionHandler *, 4> HandlerStack;
+ SmallVector<std::unique_ptr<ActionHandler>, 4> HandlerStack;
+ SmallPtrSet<const Function *, 4> VisitedHandlers;
int currentEHNumber() const {
- return HandlerStack.empty() ? -1 : HandlerStack.back()->getEHState();
+ return HandlerStack.empty() ? CurrentBaseState : HandlerStack.back()->getEHState();
}
- 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(MutableArrayRef<std::unique_ptr<ActionHandler>> Actions,
+ ImmutableCallSite CS);
void calculateStateNumbers(const Function &F);
};
}
// during the initial isel pass through the IR so that it is done
// in a predictable order.
if (const DbgDeclareInst *DI = dyn_cast<DbgDeclareInst>(I)) {
- DIVariable DIVar(DI->getVariable());
- assert((!DIVar || DIVar.isVariable()) &&
- "Variable in DbgDeclareInst should be either null or a DIVariable.");
- if (MMI.hasDebugInfo() && DIVar && DI->getDebugLoc()) {
+ assert(DI->getVariable() && "Missing variable");
+ assert(DI->getDebugLoc() && "Missing location");
+ if (MMI.hasDebugInfo()) {
// Don't handle byval struct arguments or VLAs, for example.
// Non-byval arguments are handled here (they refer to the stack
// temporary alloca at this point).
}
// Mark landing pad blocks.
- for (BB = Fn->begin(); BB != EB; ++BB)
+ SmallVector<const LandingPadInst *, 4> LPads;
+ for (BB = Fn->begin(); BB != EB; ++BB) {
if (const auto *Invoke = dyn_cast<InvokeInst>(BB->getTerminator()))
MBBMap[Invoke->getSuccessor(1)]->setIsLandingPad();
+ if (BB->isLandingPad())
+ LPads.push_back(BB->getLandingPadInst());
+ }
+
+ // If this is an MSVC EH personality, we need to do a bit more work.
+ EHPersonality Personality = EHPersonality::Unknown;
+ if (!LPads.empty())
+ Personality = classifyEHPersonality(LPads.back()->getPersonalityFn());
+ if (!isMSVCEHPersonality(Personality))
+ return;
- // Calculate EH numbers for WinEH.
- if (fn.getFnAttribute("wineh-parent").getValueAsString() == fn.getName())
- WinEHNumbering(MMI.getWinEHFuncInfo(&fn)).calculateStateNumbers(fn);
+ WinEHFuncInfo *EHInfo = nullptr;
+ if (Personality == EHPersonality::MSVC_Win64SEH) {
+ addSEHHandlersForLPads(LPads);
+ } else if (Personality == EHPersonality::MSVC_CXX) {
+ const Function *WinEHParentFn = MMI.getWinEHParent(&fn);
+ EHInfo = &MMI.getWinEHFuncInfo(WinEHParentFn);
+ if (EHInfo->LandingPadStateMap.empty()) {
+ WinEHNumbering Num(*EHInfo);
+ Num.calculateStateNumbers(*WinEHParentFn);
+ // Pop everything on the handler stack.
+ Num.processCallSite(None, ImmutableCallSite());
+ }
+
+ // Copy the state numbers to LandingPadInfo for the current function, which
+ // could be a handler or the parent.
+ for (const LandingPadInst *LP : LPads) {
+ MachineBasicBlock *LPadMBB = MBBMap[LP->getParent()];
+ MMI.addWinEHState(LPadMBB, EHInfo->LandingPadStateMap[LP]);
+ }
+ }
}
-void WinEHNumbering::parseEHActions(const IntrinsicInst *II,
- SmallVectorImpl<ActionHandler *> &Actions) {
- for (unsigned I = 0, E = II->getNumArgOperands(); I != E;) {
- uint64_t ActionKind =
- cast<ConstantInt>(II->getArgOperand(I))->getZExtValue();
- if (ActionKind == /*catch=*/1) {
- auto *Selector = cast<Constant>(II->getArgOperand(I + 1));
- Value *CatchObject = II->getArgOperand(I + 2);
- Constant *Handler = cast<Constant>(II->getArgOperand(I + 3));
- I += 4;
- auto *CH = new CatchHandler(/*BB=*/nullptr, Selector, /*NextBB=*/nullptr);
- CH->setExceptionVar(CatchObject);
- CH->setHandlerBlockOrFunc(Handler);
- Actions.push_back(CH);
- } else {
- assert(ActionKind == 0 && "expected a cleanup or a catch action!");
- Constant *Handler = cast<Constant>(II->getArgOperand(I + 1));
- I += 2;
- auto *CH = new CleanupHandler(/*BB=*/nullptr);
- CH->setHandlerBlockOrFunc(Handler);
- Actions.push_back(CH);
+void FunctionLoweringInfo::addSEHHandlersForLPads(
+ ArrayRef<const LandingPadInst *> LPads) {
+ MachineModuleInfo &MMI = MF->getMMI();
+
+ // Iterate over all landing pads with llvm.eh.actions calls.
+ for (const LandingPadInst *LP : LPads) {
+ const IntrinsicInst *ActionsCall =
+ dyn_cast<IntrinsicInst>(LP->getNextNode());
+ if (!ActionsCall ||
+ ActionsCall->getIntrinsicID() != Intrinsic::eh_actions)
+ continue;
+
+ // Parse the llvm.eh.actions call we found.
+ MachineBasicBlock *LPadMBB = MBBMap[LP->getParent()];
+ SmallVector<std::unique_ptr<ActionHandler>, 4> Actions;
+ parseEHActions(ActionsCall, Actions);
+
+ // Iterate EH actions from most to least precedence, which means
+ // iterating in reverse.
+ for (auto I = Actions.rbegin(), E = Actions.rend(); I != E; ++I) {
+ ActionHandler *Action = I->get();
+ if (auto *CH = dyn_cast<CatchHandler>(Action)) {
+ const auto *Filter =
+ dyn_cast<Function>(CH->getSelector()->stripPointerCasts());
+ assert((Filter || CH->getSelector()->isNullValue()) &&
+ "expected function or catch-all");
+ const auto *RecoverBA =
+ cast<BlockAddress>(CH->getHandlerBlockOrFunc());
+ MMI.addSEHCatchHandler(LPadMBB, Filter, RecoverBA);
+ } else {
+ assert(isa<CleanupHandler>(Action));
+ const auto *Fini = cast<Function>(Action->getHandlerBlockOrFunc());
+ MMI.addSEHCleanupHandler(LPadMBB, Fini);
+ }
}
}
- std::reverse(Actions.begin(), Actions.end());
}
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;
+ assert(TBME.TryLow <= TBME.TryHigh);
+ for (CatchHandler *CH : Handlers) {
+ WinEHHandlerType HT;
+ if (CH->getSelector()->isNullValue()) {
+ HT.Adjectives = 0x40;
+ HT.TypeDescriptor = nullptr;
+ } else {
+ 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());
+ HT.CatchObjRecoverIdx = CH->getExceptionVarIndex();
+ TBME.HandlerArray.push_back(HT);
+ }
+ FuncInfo.TryBlockMap.push_back(TBME);
+}
+
static void print_name(const Value *V) {
+#ifndef NDEBUG
if (!V) {
DEBUG(dbgs() << "null");
return;
DEBUG(dbgs() << F->getName());
else
DEBUG(V->dump());
+#endif
}
-void WinEHNumbering::proccessCallSite(ArrayRef<ActionHandler *> Actions,
- ImmutableCallSite CS) {
- // float, int
- // float, double, int
+void WinEHNumbering::processCallSite(
+ MutableArrayRef<std::unique_ptr<ActionHandler>> Actions,
+ ImmutableCallSite CS) {
+ DEBUG(dbgs() << "processCallSite (EH state = " << currentEHNumber()
+ << ") for: ");
+ print_name(CS ? CS.getCalledValue() : nullptr);
+ DEBUG(dbgs() << '\n');
+
+ DEBUG(dbgs() << "HandlerStack: \n");
+ for (int I = 0, E = HandlerStack.size(); I < E; ++I) {
+ DEBUG(dbgs() << " ");
+ print_name(HandlerStack[I]->getHandlerBlockOrFunc());
+ DEBUG(dbgs() << '\n');
+ }
+ DEBUG(dbgs() << "Actions: \n");
+ for (int I = 0, E = Actions.size(); I < E; ++I) {
+ DEBUG(dbgs() << " ");
+ print_name(Actions[I]->getHandlerBlockOrFunc());
+ DEBUG(dbgs() << '\n');
+ }
int FirstMismatch = 0;
for (int E = std::min(HandlerStack.size(), Actions.size()); FirstMismatch < E;
++FirstMismatch) {
if (HandlerStack[FirstMismatch]->getHandlerBlockOrFunc() !=
Actions[FirstMismatch]->getHandlerBlockOrFunc())
break;
- delete Actions[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();
- HandlerStack.pop_back();
+ std::unique_ptr<ActionHandler> Handler = HandlerStack.pop_back_val();
+ if (isa<CatchHandler>(Handler.get()))
+ PoppedCatches.push_back(cast<CatchHandler>(Handler.release()));
}
- for (const Function *F : UnnumberedHandlers)
- calculateStateNumbers(*F);
+ int TryHigh = NextState - 1;
+ int LastTryLowIdx = 0;
+ for (int I = 0, E = PoppedCatches.size(); I != E; ++I) {
+ CatchHandler *CH = PoppedCatches[I];
+ DEBUG(dbgs() << "Popped handler with state " << CH->getEHState() << "\n");
+ if (I + 1 == E || CH->getEHState() != PoppedCatches[I + 1]->getEHState()) {
+ int TryLow = CH->getEHState();
+ auto Handlers =
+ makeArrayRef(&PoppedCatches[LastTryLowIdx], I - LastTryLowIdx + 1);
+ DEBUG(dbgs() << "createTryBlockMapEntry(" << TryLow << ", " << TryHigh);
+ for (size_t J = 0; J < Handlers.size(); ++J) {
+ DEBUG(dbgs() << ", ");
+ print_name(Handlers[J]->getHandlerBlockOrFunc());
+ }
+ DEBUG(dbgs() << ")\n");
+ createTryBlockMapEntry(TryLow, TryHigh, Handlers);
+ LastTryLowIdx = I + 1;
+ }
+ }
+ for (CatchHandler *CH : PoppedCatches) {
+ if (auto *F = dyn_cast<Function>(CH->getHandlerBlockOrFunc())) {
+ DEBUG(dbgs() << "Assigning base state " << NextState << " to ");
+ print_name(F);
+ DEBUG(dbgs() << '\n');
+ FuncInfo.HandlerBaseState[F] = NextState;
+ DEBUG(dbgs() << "createUnwindMapEntry(" << currentEHNumber()
+ << ", null)\n");
+ createUnwindMapEntry(currentEHNumber(), nullptr);
+ ++NextState;
+ calculateStateNumbers(*F);
+ }
+ delete CH;
+ }
+
+ // The handler functions may have pushed actions onto the handler stack
+ // that we expected to push here. Compare the handler stack to our
+ // actions again to check for that possibility.
+ if (HandlerStack.size() > (size_t)FirstMismatch) {
+ for (int E = std::min(HandlerStack.size(), Actions.size());
+ FirstMismatch < E; ++FirstMismatch) {
+ if (HandlerStack[FirstMismatch]->getHandlerBlockOrFunc() !=
+ Actions[FirstMismatch]->getHandlerBlockOrFunc())
+ break;
+ }
+ }
+
+ DEBUG(dbgs() << "Pushing actions for CallSite: ");
+ print_name(CS ? CS.getCalledValue() : nullptr);
+ DEBUG(dbgs() << '\n');
+
+ 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");
- HandlerStack.push_back(Actions[I]);
+ // We can reuse eh states when pushing two catches for the same invoke.
+ bool CurrActionIsCatch = isa<CatchHandler>(Actions[I].get());
+ // FIXME: Reenable this optimization!
+ if (CurrActionIsCatch && LastActionWasCatch && false) {
+ DEBUG(dbgs() << "setEHState for handler to " << currentEHNumber()
+ << "\n");
+ Actions[I]->setEHState(currentEHNumber());
+ } else {
+ DEBUG(dbgs() << "createUnwindMapEntry(" << currentEHNumber() << ", ");
+ print_name(Actions[I]->getHandlerBlockOrFunc());
+ DEBUG(dbgs() << ")\n");
+ createUnwindMapEntry(currentEHNumber(), Actions[I].get());
+ DEBUG(dbgs() << "setEHState for handler to " << NextState << "\n");
+ Actions[I]->setEHState(NextState);
+ NextState++;
+ }
+ HandlerStack.push_back(std::move(Actions[I]));
+ LastActionWasCatch = CurrActionIsCatch;
}
DEBUG(dbgs() << "In EHState " << currentEHNumber() << " for CallSite: ");
}
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.
+
+ int OldBaseState = CurrentBaseState;
+ if (FuncInfo.HandlerBaseState.count(&F)) {
+ CurrentBaseState = FuncInfo.HandlerBaseState[&F];
+ }
+
DEBUG(dbgs() << "Calculating state numbers for: " << F.getName() << '\n');
- SmallVector<ActionHandler *, 4> ActionList;
+ SmallVector<std::unique_ptr<ActionHandler>, 4> ActionList;
for (const BasicBlock &BB : F) {
for (const Instruction &I : BB) {
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);
+ if (ActionList.empty())
+ continue;
+ processCallSite(ActionList, II);
+ ActionList.clear();
+ FuncInfo.LandingPadStateMap[LPI] = currentEHNumber();
+ DEBUG(dbgs() << "Assigning state " << currentEHNumber()
+ << " to landing pad at " << LPI->getParent()->getName()
+ << '\n');
}
- proccessCallSite(None, ImmutableCallSite());
+
+ FuncInfo.CatchHandlerMaxState[&F] = NextState - 1;
+
+ CurrentBaseState = OldBaseState;
}
/// clear - Clear out all the function-specific state. This returns this
ByValArgFrameIndexMap.clear();
RegFixups.clear();
StatepointStackSlots.clear();
+ StatepointRelocatedValues.clear();
PreferredExtendType.clear();
}
if (FT->isVarArg() && !MMI->usesVAFloatArgument()) {
for (unsigned i = 0, e = I.getNumArgOperands(); i != e; ++i) {
Type* T = I.getArgOperand(i)->getType();
- for (po_iterator<Type*> i = po_begin(T), e = po_end(T);
- i != e; ++i) {
+ for (auto i : post_order(T)) {
if (i->isFloatingPointTy()) {
MMI->setUsesVAFloatArgument(true);
return;