- if (Pred == CmpInst::ICMP_EQ) {
- CatchHandler = TBB;
- NextBB = FBB;
- return true;
- }
-
- if (Pred == CmpInst::ICMP_NE) {
- CatchHandler = FBB;
- NextBB = TBB;
- return true;
- }
-
- return false;
-}
-
-static bool isCatchBlock(BasicBlock *BB) {
- for (BasicBlock::iterator II = BB->getFirstNonPHIOrDbg(), IE = BB->end();
- II != IE; ++II) {
- if (match(cast<Value>(II), m_Intrinsic<Intrinsic::eh_begincatch>()))
- return true;
- }
- return false;
-}
-
-static BasicBlock *createStubLandingPad(Function *Handler) {
- // FIXME: Finish this!
- LLVMContext &Context = Handler->getContext();
- BasicBlock *StubBB = BasicBlock::Create(Context, "stub");
- Handler->getBasicBlockList().push_back(StubBB);
- IRBuilder<> Builder(StubBB);
- LandingPadInst *LPad = Builder.CreateLandingPad(
- llvm::StructType::get(Type::getInt8PtrTy(Context),
- Type::getInt32Ty(Context), nullptr),
- 0);
- // Insert a call to llvm.eh.actions so that we don't try to outline this lpad.
- Function *ActionIntrin =
- Intrinsic::getDeclaration(Handler->getParent(), Intrinsic::eh_actions);
- Builder.CreateCall(ActionIntrin, {}, "recover");
- LPad->setCleanup(true);
- Builder.CreateUnreachable();
- return StubBB;
-}
-
-// Cycles through the blocks in an outlined handler function looking for an
-// invoke instruction and inserts an invoke of llvm.donothing with an empty
-// landing pad if none is found. The code that generates the .xdata tables for
-// the handler needs at least one landing pad to identify the parent function's
-// personality.
-void WinEHPrepare::addStubInvokeToHandlerIfNeeded(Function *Handler) {
- ReturnInst *Ret = nullptr;
- UnreachableInst *Unreached = nullptr;
- for (BasicBlock &BB : *Handler) {
- TerminatorInst *Terminator = BB.getTerminator();
- // If we find an invoke, there is nothing to be done.
- auto *II = dyn_cast<InvokeInst>(Terminator);
- if (II)
- return;
- // If we've already recorded a return instruction, keep looking for invokes.
- if (!Ret)
- Ret = dyn_cast<ReturnInst>(Terminator);
- // If we haven't recorded an unreachable instruction, try this terminator.
- if (!Unreached)
- Unreached = dyn_cast<UnreachableInst>(Terminator);
- }
-
- // If we got this far, the handler contains no invokes. We should have seen
- // at least one return or unreachable instruction. We'll insert an invoke of
- // llvm.donothing ahead of that instruction.
- assert(Ret || Unreached);
- TerminatorInst *Term;
- if (Ret)
- Term = Ret;
- else
- Term = Unreached;
- BasicBlock *OldRetBB = Term->getParent();
- BasicBlock *NewRetBB = SplitBlock(OldRetBB, Term, DT);
- // SplitBlock adds an unconditional branch instruction at the end of the
- // parent block. We want to replace that with an invoke call, so we can
- // erase it now.
- OldRetBB->getTerminator()->eraseFromParent();
- BasicBlock *StubLandingPad = createStubLandingPad(Handler);
- Function *F =
- Intrinsic::getDeclaration(Handler->getParent(), Intrinsic::donothing);
- InvokeInst::Create(F, NewRetBB, StubLandingPad, None, "", OldRetBB);
-}
-
-// FIXME: Consider sinking this into lib/Target/X86 somehow. TargetLowering
-// usually doesn't build LLVM IR, so that's probably the wrong place.
-Function *WinEHPrepare::createHandlerFunc(Function *ParentFn, Type *RetTy,
- const Twine &Name, Module *M,
- Value *&ParentFP) {
- // x64 uses a two-argument prototype where the parent FP is the second
- // argument. x86 uses no arguments, just the incoming EBP value.
- LLVMContext &Context = M->getContext();
- Type *Int8PtrType = Type::getInt8PtrTy(Context);
- FunctionType *FnType;
- if (TheTriple.getArch() == Triple::x86_64) {
- Type *ArgTys[2] = {Int8PtrType, Int8PtrType};
- FnType = FunctionType::get(RetTy, ArgTys, false);
- } else {
- FnType = FunctionType::get(RetTy, None, false);
- }
-
- Function *Handler =
- Function::Create(FnType, GlobalVariable::InternalLinkage, Name, M);
- BasicBlock *Entry = BasicBlock::Create(Context, "entry");
- Handler->getBasicBlockList().push_front(Entry);
- if (TheTriple.getArch() == Triple::x86_64) {
- ParentFP = &(Handler->getArgumentList().back());
- } else {
- assert(M);
- Function *FrameAddressFn =
- Intrinsic::getDeclaration(M, Intrinsic::frameaddress);
- Function *RecoverFPFn =
- Intrinsic::getDeclaration(M, Intrinsic::x86_seh_recoverfp);
- IRBuilder<> Builder(&Handler->getEntryBlock());
- Value *EBP =
- Builder.CreateCall(FrameAddressFn, {Builder.getInt32(1)}, "ebp");
- Value *ParentI8Fn = Builder.CreateBitCast(ParentFn, Int8PtrType);
- ParentFP = Builder.CreateCall(RecoverFPFn, {ParentI8Fn, EBP});
- }
- return Handler;
-}
-
-bool WinEHPrepare::outlineHandler(ActionHandler *Action, Function *SrcFn,
- LandingPadInst *LPad, BasicBlock *StartBB,
- FrameVarInfoMap &VarInfo) {
- Module *M = SrcFn->getParent();
- LLVMContext &Context = M->getContext();
- Type *Int8PtrType = Type::getInt8PtrTy(Context);
-
- // Create a new function to receive the handler contents.
- Value *ParentFP;
- Function *Handler;
- if (Action->getType() == Catch) {
- Handler = createHandlerFunc(SrcFn, Int8PtrType, SrcFn->getName() + ".catch", M,
- ParentFP);
- } else {
- Handler = createHandlerFunc(SrcFn, Type::getVoidTy(Context),
- SrcFn->getName() + ".cleanup", M, ParentFP);
- }
- Handler->setPersonalityFn(SrcFn->getPersonalityFn());
- HandlerToParentFP[Handler] = ParentFP;
- Handler->addFnAttr("wineh-parent", SrcFn->getName());
- BasicBlock *Entry = &Handler->getEntryBlock();
-
- // Generate a standard prolog to setup the frame recovery structure.
- IRBuilder<> Builder(Context);
- Builder.SetInsertPoint(Entry);
- Builder.SetCurrentDebugLocation(LPad->getDebugLoc());
-
- std::unique_ptr<WinEHCloningDirectorBase> Director;
-
- ValueToValueMapTy VMap;
-
- LandingPadMap &LPadMap = LPadMaps[LPad];
- if (!LPadMap.isInitialized())
- LPadMap.mapLandingPad(LPad);
- if (auto *CatchAction = dyn_cast<CatchHandler>(Action)) {
- Constant *Sel = CatchAction->getSelector();
- Director.reset(new WinEHCatchDirector(Handler, ParentFP, Sel, VarInfo,
- LPadMap, NestedLPtoOriginalLP, DT,
- EHBlocks));
- LPadMap.remapEHValues(VMap, UndefValue::get(Int8PtrType),
- ConstantInt::get(Type::getInt32Ty(Context), 1));
- } else {
- Director.reset(
- new WinEHCleanupDirector(Handler, ParentFP, VarInfo, LPadMap));
- LPadMap.remapEHValues(VMap, UndefValue::get(Int8PtrType),
- UndefValue::get(Type::getInt32Ty(Context)));
- }
-
- SmallVector<ReturnInst *, 8> Returns;
- ClonedCodeInfo OutlinedFunctionInfo;
-
- // If the start block contains PHI nodes, we need to map them.
- BasicBlock::iterator II = StartBB->begin();
- while (auto *PN = dyn_cast<PHINode>(II)) {
- bool Mapped = false;
- // Look for PHI values that we have already mapped (such as the selector).
- for (Value *Val : PN->incoming_values()) {
- if (VMap.count(Val)) {
- VMap[PN] = VMap[Val];
- Mapped = true;
- }
- }
- // If we didn't find a match for this value, map it as an undef.
- if (!Mapped) {
- VMap[PN] = UndefValue::get(PN->getType());
- }
- ++II;
- }
-
- // The landing pad value may be used by PHI nodes. It will ultimately be
- // eliminated, but we need it in the map for intermediate handling.
- VMap[LPad] = UndefValue::get(LPad->getType());
-
- // Skip over PHIs and, if applicable, landingpad instructions.
- II = StartBB->getFirstInsertionPt();
-
- CloneAndPruneIntoFromInst(Handler, SrcFn, II, VMap,
- /*ModuleLevelChanges=*/false, Returns, "",
- &OutlinedFunctionInfo, Director.get());
-
- // Move all the instructions in the cloned "entry" block into our entry block.
- // Depending on how the parent function was laid out, the block that will
- // correspond to the outlined entry block may not be the first block in the
- // list. We can recognize it, however, as the cloned block which has no
- // predecessors. Any other block wouldn't have been cloned if it didn't
- // have a predecessor which was also cloned.
- Function::iterator ClonedIt = std::next(Function::iterator(Entry));
- while (!pred_empty(ClonedIt))
- ++ClonedIt;
- BasicBlock *ClonedEntryBB = ClonedIt;
- assert(ClonedEntryBB);
- Entry->getInstList().splice(Entry->end(), ClonedEntryBB->getInstList());
- ClonedEntryBB->eraseFromParent();
-
- // Make sure we can identify the handler's personality later.
- addStubInvokeToHandlerIfNeeded(Handler);
-
- if (auto *CatchAction = dyn_cast<CatchHandler>(Action)) {
- WinEHCatchDirector *CatchDirector =
- reinterpret_cast<WinEHCatchDirector *>(Director.get());
- CatchAction->setExceptionVar(CatchDirector->getExceptionVar());
- CatchAction->setReturnTargets(CatchDirector->getReturnTargets());
-
- // Look for blocks that are not part of the landing pad that we just
- // outlined but terminate with a call to llvm.eh.endcatch and a
- // branch to a block that is in the handler we just outlined.
- // These blocks will be part of a nested landing pad that intends to
- // return to an address in this handler. This case is best handled
- // after both landing pads have been outlined, so for now we'll just
- // save the association of the blocks in LPadTargetBlocks. The
- // return instructions which are created from these branches will be
- // replaced after all landing pads have been outlined.
- for (const auto MapEntry : VMap) {
- // VMap maps all values and blocks that were just cloned, but dead
- // blocks which were pruned will map to nullptr.
- if (!isa<BasicBlock>(MapEntry.first) || MapEntry.second == nullptr)
- continue;
- const BasicBlock *MappedBB = cast<BasicBlock>(MapEntry.first);
- for (auto *Pred : predecessors(const_cast<BasicBlock *>(MappedBB))) {
- auto *Branch = dyn_cast<BranchInst>(Pred->getTerminator());
- if (!Branch || !Branch->isUnconditional() || Pred->size() <= 1)
- continue;
- BasicBlock::iterator II = const_cast<BranchInst *>(Branch);
- --II;
- if (match(cast<Value>(II), m_Intrinsic<Intrinsic::eh_endcatch>())) {
- // This would indicate that a nested landing pad wants to return
- // to a block that is outlined into two different handlers.
- assert(!LPadTargetBlocks.count(MappedBB));
- LPadTargetBlocks[MappedBB] = cast<BasicBlock>(MapEntry.second);
- }
- }
- }
- } // End if (CatchAction)
-
- Action->setHandlerBlockOrFunc(Handler);
-
- return true;
-}
-
-/// This BB must end in a selector dispatch. All we need to do is pass the
-/// handler block to llvm.eh.actions and list it as a possible indirectbr
-/// target.
-void WinEHPrepare::processSEHCatchHandler(CatchHandler *CatchAction,
- BasicBlock *StartBB) {
- BasicBlock *HandlerBB;
- BasicBlock *NextBB;
- Constant *Selector;
- bool Res = isSelectorDispatch(StartBB, HandlerBB, Selector, NextBB);
- if (Res) {
- // If this was EH dispatch, this must be a conditional branch to the handler
- // block.
- // FIXME: Handle instructions in the dispatch block. Currently we drop them,
- // leading to crashes if some optimization hoists stuff here.
- assert(CatchAction->getSelector() && HandlerBB &&
- "expected catch EH dispatch");
- } else {
- // This must be a catch-all. Split the block after the landingpad.
- assert(CatchAction->getSelector()->isNullValue() && "expected catch-all");
- HandlerBB = SplitBlock(StartBB, StartBB->getFirstInsertionPt(), DT);
- }
- IRBuilder<> Builder(HandlerBB->getFirstInsertionPt());
- Function *EHCodeFn = Intrinsic::getDeclaration(
- StartBB->getParent()->getParent(), Intrinsic::eh_exceptioncode);
- Value *Code = Builder.CreateCall(EHCodeFn, {}, "sehcode");
- Code = Builder.CreateIntToPtr(Code, SEHExceptionCodeSlot->getAllocatedType());
- Builder.CreateStore(Code, SEHExceptionCodeSlot);
- CatchAction->setHandlerBlockOrFunc(BlockAddress::get(HandlerBB));
- TinyPtrVector<BasicBlock *> Targets(HandlerBB);
- CatchAction->setReturnTargets(Targets);
-}
-
-void LandingPadMap::mapLandingPad(const LandingPadInst *LPad) {
- // Each instance of this class should only ever be used to map a single
- // landing pad.
- assert(OriginLPad == nullptr || OriginLPad == LPad);
-
- // If the landing pad has already been mapped, there's nothing more to do.
- if (OriginLPad == LPad)
- return;
-
- OriginLPad = LPad;
-
- // The landingpad instruction returns an aggregate value. Typically, its
- // value will be passed to a pair of extract value instructions and the
- // results of those extracts will have been promoted to reg values before
- // this routine is called.
- for (auto *U : LPad->users()) {
- const ExtractValueInst *Extract = dyn_cast<ExtractValueInst>(U);
- if (!Extract)
- continue;
- assert(Extract->getNumIndices() == 1 &&
- "Unexpected operation: extracting both landing pad values");
- unsigned int Idx = *(Extract->idx_begin());
- assert((Idx == 0 || Idx == 1) &&
- "Unexpected operation: extracting an unknown landing pad element");
- if (Idx == 0) {
- ExtractedEHPtrs.push_back(Extract);
- } else if (Idx == 1) {
- ExtractedSelectors.push_back(Extract);
- }
- }
-}
-
-bool LandingPadMap::isOriginLandingPadBlock(const BasicBlock *BB) const {
- return BB->getLandingPadInst() == OriginLPad;
-}
-
-bool LandingPadMap::isLandingPadSpecificInst(const Instruction *Inst) const {
- if (Inst == OriginLPad)
- return true;
- for (auto *Extract : ExtractedEHPtrs) {
- if (Inst == Extract)
- return true;
- }
- for (auto *Extract : ExtractedSelectors) {
- if (Inst == Extract)
- return true;
- }
- return false;
-}
-
-void LandingPadMap::remapEHValues(ValueToValueMapTy &VMap, Value *EHPtrValue,
- Value *SelectorValue) const {
- // Remap all landing pad extract instructions to the specified values.
- for (auto *Extract : ExtractedEHPtrs)
- VMap[Extract] = EHPtrValue;
- for (auto *Extract : ExtractedSelectors)
- VMap[Extract] = SelectorValue;
-}
-
-static bool isLocalAddressCall(const Value *V) {
- return match(const_cast<Value *>(V), m_Intrinsic<Intrinsic::localaddress>());
-}
-
-CloningDirector::CloningAction WinEHCloningDirectorBase::handleInstruction(
- ValueToValueMapTy &VMap, const Instruction *Inst, BasicBlock *NewBB) {
- // If this is one of the boilerplate landing pad instructions, skip it.
- // The instruction will have already been remapped in VMap.
- if (LPadMap.isLandingPadSpecificInst(Inst))
- return CloningDirector::SkipInstruction;
-
- // Nested landing pads that have not already been outlined will be cloned as
- // stubs, with just the landingpad instruction and an unreachable instruction.
- // When all landingpads have been outlined, we'll replace this with the
- // llvm.eh.actions call and indirect branch created when the landing pad was
- // outlined.
- if (auto *LPad = dyn_cast<LandingPadInst>(Inst)) {
- return handleLandingPad(VMap, LPad, NewBB);
- }
-
- // Nested landing pads that have already been outlined will be cloned in their
- // outlined form, but we need to intercept the ibr instruction to filter out
- // targets that do not return to the handler we are outlining.
- if (auto *IBr = dyn_cast<IndirectBrInst>(Inst)) {
- return handleIndirectBr(VMap, IBr, NewBB);
- }
-
- if (auto *Invoke = dyn_cast<InvokeInst>(Inst))
- return handleInvoke(VMap, Invoke, NewBB);
-
- if (auto *Resume = dyn_cast<ResumeInst>(Inst))
- return handleResume(VMap, Resume, NewBB);
-
- if (auto *Cmp = dyn_cast<CmpInst>(Inst))
- return handleCompare(VMap, Cmp, NewBB);
-
- if (match(Inst, m_Intrinsic<Intrinsic::eh_begincatch>()))
- return handleBeginCatch(VMap, Inst, NewBB);
- if (match(Inst, m_Intrinsic<Intrinsic::eh_endcatch>()))
- return handleEndCatch(VMap, Inst, NewBB);
- if (match(Inst, m_Intrinsic<Intrinsic::eh_typeid_for>()))
- return handleTypeIdFor(VMap, Inst, NewBB);
-
- // When outlining llvm.localaddress(), remap that to the second argument,
- // which is the FP of the parent.
- if (isLocalAddressCall(Inst)) {
- VMap[Inst] = ParentFP;
- return CloningDirector::SkipInstruction;
- }
-
- // Continue with the default cloning behavior.
- return CloningDirector::CloneInstruction;
-}
-
-CloningDirector::CloningAction WinEHCatchDirector::handleLandingPad(
- ValueToValueMapTy &VMap, const LandingPadInst *LPad, BasicBlock *NewBB) {
- // If the instruction after the landing pad is a call to llvm.eh.actions
- // the landing pad has already been outlined. In this case, we should
- // clone it because it may return to a block in the handler we are
- // outlining now that would otherwise be unreachable. The landing pads
- // are sorted before outlining begins to enable this case to work
- // properly.
- const Instruction *NextI = LPad->getNextNode();
- if (match(NextI, m_Intrinsic<Intrinsic::eh_actions>()))
- return CloningDirector::CloneInstruction;
-
- // If the landing pad hasn't been outlined yet, the landing pad we are
- // outlining now does not dominate it and so it cannot return to a block
- // in this handler. In that case, we can just insert a stub landing
- // pad now and patch it up later.
- Instruction *NewInst = LPad->clone();
- if (LPad->hasName())
- NewInst->setName(LPad->getName());
- // Save this correlation for later processing.
- NestedLPtoOriginalLP[cast<LandingPadInst>(NewInst)] = LPad;
- VMap[LPad] = NewInst;
- BasicBlock::InstListType &InstList = NewBB->getInstList();
- InstList.push_back(NewInst);
- InstList.push_back(new UnreachableInst(NewBB->getContext()));
- return CloningDirector::StopCloningBB;
-}
-
-CloningDirector::CloningAction WinEHCatchDirector::handleBeginCatch(
- ValueToValueMapTy &VMap, const Instruction *Inst, BasicBlock *NewBB) {
- // The argument to the call is some form of the first element of the
- // landingpad aggregate value, but that doesn't matter. It isn't used
- // here.
- // The second argument is an outparameter where the exception object will be
- // stored. Typically the exception object is a scalar, but it can be an
- // aggregate when catching by value.
- // FIXME: Leave something behind to indicate where the exception object lives
- // for this handler. Should it be part of llvm.eh.actions?
- assert(ExceptionObjectVar == nullptr && "Multiple calls to "
- "llvm.eh.begincatch found while "
- "outlining catch handler.");
- ExceptionObjectVar = Inst->getOperand(1)->stripPointerCasts();
- if (isa<ConstantPointerNull>(ExceptionObjectVar))
- return CloningDirector::SkipInstruction;
- assert(cast<AllocaInst>(ExceptionObjectVar)->isStaticAlloca() &&
- "catch parameter is not static alloca");
- Materializer.escapeCatchObject(ExceptionObjectVar);
- return CloningDirector::SkipInstruction;
-}
-
-CloningDirector::CloningAction
-WinEHCatchDirector::handleEndCatch(ValueToValueMapTy &VMap,
- const Instruction *Inst, BasicBlock *NewBB) {
- auto *IntrinCall = dyn_cast<IntrinsicInst>(Inst);
- // It might be interesting to track whether or not we are inside a catch
- // function, but that might make the algorithm more brittle than it needs
- // to be.
-
- // The end catch call can occur in one of two places: either in a
- // landingpad block that is part of the catch handlers exception mechanism,
- // or at the end of the catch block. However, a catch-all handler may call
- // end catch from the original landing pad. If the call occurs in a nested
- // landing pad block, we must skip it and continue so that the landing pad
- // gets cloned.
- auto *ParentBB = IntrinCall->getParent();
- if (ParentBB->isLandingPad() && !LPadMap.isOriginLandingPadBlock(ParentBB))
- return CloningDirector::SkipInstruction;
-
- // If an end catch occurs anywhere else we want to terminate the handler
- // with a return to the code that follows the endcatch call. If the
- // next instruction is not an unconditional branch, we need to split the
- // block to provide a clear target for the return instruction.
- BasicBlock *ContinueBB;
- auto Next = std::next(BasicBlock::const_iterator(IntrinCall));
- const BranchInst *Branch = dyn_cast<BranchInst>(Next);
- if (!Branch || !Branch->isUnconditional()) {
- // We're interrupting the cloning process at this location, so the
- // const_cast we're doing here will not cause a problem.
- ContinueBB = SplitBlock(const_cast<BasicBlock *>(ParentBB),
- const_cast<Instruction *>(cast<Instruction>(Next)));
- } else {
- ContinueBB = Branch->getSuccessor(0);
- }
-
- ReturnInst::Create(NewBB->getContext(), BlockAddress::get(ContinueBB), NewBB);
- ReturnTargets.push_back(ContinueBB);
-
- // We just added a terminator to the cloned block.
- // Tell the caller to stop processing the current basic block so that
- // the branch instruction will be skipped.
- return CloningDirector::StopCloningBB;
-}
-
-CloningDirector::CloningAction WinEHCatchDirector::handleTypeIdFor(
- ValueToValueMapTy &VMap, const Instruction *Inst, BasicBlock *NewBB) {
- auto *IntrinCall = dyn_cast<IntrinsicInst>(Inst);
- Value *Selector = IntrinCall->getArgOperand(0)->stripPointerCasts();
- // This causes a replacement that will collapse the landing pad CFG based
- // on the filter function we intend to match.
- if (Selector == CurrentSelector)
- VMap[Inst] = ConstantInt::get(SelectorIDType, 1);
- else
- VMap[Inst] = ConstantInt::get(SelectorIDType, 0);
- // Tell the caller not to clone this instruction.
- return CloningDirector::SkipInstruction;
-}
-
-CloningDirector::CloningAction WinEHCatchDirector::handleIndirectBr(
- ValueToValueMapTy &VMap,
- const IndirectBrInst *IBr,
- BasicBlock *NewBB) {
- // If this indirect branch is not part of a landing pad block, just clone it.
- const BasicBlock *ParentBB = IBr->getParent();
- if (!ParentBB->isLandingPad())
- return CloningDirector::CloneInstruction;
-
- // If it is part of a landing pad, we want to filter out target blocks
- // that are not part of the handler we are outlining.
- const LandingPadInst *LPad = ParentBB->getLandingPadInst();
-
- // Save this correlation for later processing.
- NestedLPtoOriginalLP[cast<LandingPadInst>(VMap[LPad])] = LPad;
-
- // We should only get here for landing pads that have already been outlined.
- assert(match(LPad->getNextNode(), m_Intrinsic<Intrinsic::eh_actions>()));
-
- // Copy the indirectbr, but only include targets that were previously
- // identified as EH blocks and are dominated by the nested landing pad.
- SetVector<const BasicBlock *> ReturnTargets;
- for (int I = 0, E = IBr->getNumDestinations(); I < E; ++I) {
- auto *TargetBB = IBr->getDestination(I);
- if (EHBlocks.count(const_cast<BasicBlock*>(TargetBB)) &&
- DT->dominates(ParentBB, TargetBB)) {
- DEBUG(dbgs() << " Adding destination " << TargetBB->getName() << "\n");
- ReturnTargets.insert(TargetBB);
- }
- }
- IndirectBrInst *NewBranch =
- IndirectBrInst::Create(const_cast<Value *>(IBr->getAddress()),
- ReturnTargets.size(), NewBB);
- for (auto *Target : ReturnTargets)
- NewBranch->addDestination(const_cast<BasicBlock*>(Target));
-
- // The operands and targets of the branch instruction are remapped later
- // because it is a terminator. Tell the cloning code to clone the
- // blocks we just added to the target list.
- return CloningDirector::CloneSuccessors;
-}
-
-CloningDirector::CloningAction
-WinEHCatchDirector::handleInvoke(ValueToValueMapTy &VMap,
- const InvokeInst *Invoke, BasicBlock *NewBB) {
- return CloningDirector::CloneInstruction;
-}
-
-CloningDirector::CloningAction
-WinEHCatchDirector::handleResume(ValueToValueMapTy &VMap,
- const ResumeInst *Resume, BasicBlock *NewBB) {
- // Resume instructions shouldn't be reachable from catch handlers.
- // We still need to handle it, but it will be pruned.
- BasicBlock::InstListType &InstList = NewBB->getInstList();
- InstList.push_back(new UnreachableInst(NewBB->getContext()));
- return CloningDirector::StopCloningBB;
-}
-
-CloningDirector::CloningAction
-WinEHCatchDirector::handleCompare(ValueToValueMapTy &VMap,
- const CmpInst *Compare, BasicBlock *NewBB) {
- const IntrinsicInst *IntrinCall = nullptr;
- if (match(Compare->getOperand(0), m_Intrinsic<Intrinsic::eh_typeid_for>())) {
- IntrinCall = dyn_cast<IntrinsicInst>(Compare->getOperand(0));
- } else if (match(Compare->getOperand(1),
- m_Intrinsic<Intrinsic::eh_typeid_for>())) {
- IntrinCall = dyn_cast<IntrinsicInst>(Compare->getOperand(1));
- }
- if (IntrinCall) {
- Value *Selector = IntrinCall->getArgOperand(0)->stripPointerCasts();
- // This causes a replacement that will collapse the landing pad CFG based
- // on the filter function we intend to match.
- if (Selector == CurrentSelector->stripPointerCasts()) {
- VMap[Compare] = ConstantInt::get(SelectorIDType, 1);
- } else {
- VMap[Compare] = ConstantInt::get(SelectorIDType, 0);
- }
- return CloningDirector::SkipInstruction;
- }
- return CloningDirector::CloneInstruction;
-}
-
-CloningDirector::CloningAction WinEHCleanupDirector::handleLandingPad(
- ValueToValueMapTy &VMap, const LandingPadInst *LPad, BasicBlock *NewBB) {
- // The MS runtime will terminate the process if an exception occurs in a
- // cleanup handler, so we shouldn't encounter landing pads in the actual
- // cleanup code, but they may appear in catch blocks. Depending on where
- // we started cloning we may see one, but it will get dropped during dead
- // block pruning.
- Instruction *NewInst = new UnreachableInst(NewBB->getContext());
- VMap[LPad] = NewInst;
- BasicBlock::InstListType &InstList = NewBB->getInstList();
- InstList.push_back(NewInst);
- return CloningDirector::StopCloningBB;
-}
-
-CloningDirector::CloningAction WinEHCleanupDirector::handleBeginCatch(
- ValueToValueMapTy &VMap, const Instruction *Inst, BasicBlock *NewBB) {
- // Cleanup code may flow into catch blocks or the catch block may be part
- // of a branch that will be optimized away. We'll insert a return
- // instruction now, but it may be pruned before the cloning process is
- // complete.
- ReturnInst::Create(NewBB->getContext(), nullptr, NewBB);
- return CloningDirector::StopCloningBB;
-}
-
-CloningDirector::CloningAction WinEHCleanupDirector::handleEndCatch(
- ValueToValueMapTy &VMap, const Instruction *Inst, BasicBlock *NewBB) {
- // Cleanup handlers nested within catch handlers may begin with a call to
- // eh.endcatch. We can just ignore that instruction.
- return CloningDirector::SkipInstruction;
-}
-
-CloningDirector::CloningAction WinEHCleanupDirector::handleTypeIdFor(
- ValueToValueMapTy &VMap, const Instruction *Inst, BasicBlock *NewBB) {
- // If we encounter a selector comparison while cloning a cleanup handler,
- // we want to stop cloning immediately. Anything after the dispatch
- // will be outlined into a different handler.
- BasicBlock *CatchHandler;
- Constant *Selector;
- BasicBlock *NextBB;
- if (isSelectorDispatch(const_cast<BasicBlock *>(Inst->getParent()),
- CatchHandler, Selector, NextBB)) {
- ReturnInst::Create(NewBB->getContext(), nullptr, NewBB);
- return CloningDirector::StopCloningBB;
- }
- // If eg.typeid.for is called for any other reason, it can be ignored.
- VMap[Inst] = ConstantInt::get(SelectorIDType, 0);
- return CloningDirector::SkipInstruction;
-}
-
-CloningDirector::CloningAction WinEHCleanupDirector::handleIndirectBr(
- ValueToValueMapTy &VMap,
- const IndirectBrInst *IBr,
- BasicBlock *NewBB) {
- // No special handling is required for cleanup cloning.
- return CloningDirector::CloneInstruction;
-}
-
-CloningDirector::CloningAction WinEHCleanupDirector::handleInvoke(
- ValueToValueMapTy &VMap, const InvokeInst *Invoke, BasicBlock *NewBB) {
- // All invokes in cleanup handlers can be replaced with calls.
- SmallVector<Value *, 16> CallArgs(Invoke->op_begin(), Invoke->op_end() - 3);
- // Insert a normal call instruction...
- CallInst *NewCall =
- CallInst::Create(const_cast<Value *>(Invoke->getCalledValue()), CallArgs,
- Invoke->getName(), NewBB);
- NewCall->setCallingConv(Invoke->getCallingConv());
- NewCall->setAttributes(Invoke->getAttributes());
- NewCall->setDebugLoc(Invoke->getDebugLoc());
- VMap[Invoke] = NewCall;
-
- // Remap the operands.
- llvm::RemapInstruction(NewCall, VMap, RF_None, nullptr, &Materializer);
-
- // Insert an unconditional branch to the normal destination.
- BranchInst::Create(Invoke->getNormalDest(), NewBB);
-
- // The unwind destination won't be cloned into the new function, so
- // we don't need to clean up its phi nodes.
-
- // We just added a terminator to the cloned block.
- // Tell the caller to stop processing the current basic block.
- return CloningDirector::CloneSuccessors;
-}
-
-CloningDirector::CloningAction WinEHCleanupDirector::handleResume(
- ValueToValueMapTy &VMap, const ResumeInst *Resume, BasicBlock *NewBB) {
- ReturnInst::Create(NewBB->getContext(), nullptr, NewBB);
-
- // We just added a terminator to the cloned block.
- // Tell the caller to stop processing the current basic block so that
- // the branch instruction will be skipped.
- return CloningDirector::StopCloningBB;
-}
-
-CloningDirector::CloningAction
-WinEHCleanupDirector::handleCompare(ValueToValueMapTy &VMap,
- const CmpInst *Compare, BasicBlock *NewBB) {
- if (match(Compare->getOperand(0), m_Intrinsic<Intrinsic::eh_typeid_for>()) ||
- match(Compare->getOperand(1), m_Intrinsic<Intrinsic::eh_typeid_for>())) {
- VMap[Compare] = ConstantInt::get(SelectorIDType, 1);
- return CloningDirector::SkipInstruction;
- }
- return CloningDirector::CloneInstruction;
-}
-
-WinEHFrameVariableMaterializer::WinEHFrameVariableMaterializer(
- Function *OutlinedFn, Value *ParentFP, FrameVarInfoMap &FrameVarInfo)
- : FrameVarInfo(FrameVarInfo), Builder(OutlinedFn->getContext()) {
- BasicBlock *EntryBB = &OutlinedFn->getEntryBlock();
-
- // New allocas should be inserted in the entry block, but after the parent FP
- // is established if it is an instruction.
- Instruction *InsertPoint = EntryBB->getFirstInsertionPt();
- if (auto *FPInst = dyn_cast<Instruction>(ParentFP))
- InsertPoint = FPInst->getNextNode();
- Builder.SetInsertPoint(EntryBB, InsertPoint);
-}
-
-Value *WinEHFrameVariableMaterializer::materializeValueFor(Value *V) {
- // If we're asked to materialize a static alloca, we temporarily create an
- // alloca in the outlined function and add this to the FrameVarInfo map. When
- // all the outlining is complete, we'll replace these temporary allocas with
- // calls to llvm.localrecover.
- if (auto *AV = dyn_cast<AllocaInst>(V)) {
- assert(AV->isStaticAlloca() &&
- "cannot materialize un-demoted dynamic alloca");
- AllocaInst *NewAlloca = dyn_cast<AllocaInst>(AV->clone());
- Builder.Insert(NewAlloca, AV->getName());
- FrameVarInfo[AV].push_back(NewAlloca);
- return NewAlloca;
- }
-
- if (isa<Instruction>(V) || isa<Argument>(V)) {
- Function *Parent = isa<Instruction>(V)
- ? cast<Instruction>(V)->getParent()->getParent()
- : cast<Argument>(V)->getParent();
- errs()
- << "Failed to demote instruction used in exception handler of function "
- << GlobalValue::getRealLinkageName(Parent->getName()) << ":\n";
- errs() << " " << *V << '\n';
- report_fatal_error("WinEHPrepare failed to demote instruction");
- }
-
- // Don't materialize other values.
- return nullptr;
-}
-
-void WinEHFrameVariableMaterializer::escapeCatchObject(Value *V) {
- // Catch parameter objects have to live in the parent frame. When we see a use
- // of a catch parameter, add a sentinel to the multimap to indicate that it's
- // used from another handler. This will prevent us from trying to sink the
- // alloca into the handler and ensure that the catch parameter is present in
- // the call to llvm.localescape.
- FrameVarInfo[V].push_back(getCatchObjectSentinel());
-}
-
-// This function maps the catch and cleanup handlers that are reachable from the
-// specified landing pad. The landing pad sequence will have this basic shape:
-//
-// <cleanup handler>
-// <selector comparison>
-// <catch handler>
-// <cleanup handler>
-// <selector comparison>
-// <catch handler>
-// <cleanup handler>
-// ...
-//
-// Any of the cleanup slots may be absent. The cleanup slots may be occupied by
-// any arbitrary control flow, but all paths through the cleanup code must
-// eventually reach the next selector comparison and no path can skip to a
-// different selector comparisons, though some paths may terminate abnormally.
-// Therefore, we will use a depth first search from the start of any given
-// cleanup block and stop searching when we find the next selector comparison.
-//
-// If the landingpad instruction does not have a catch clause, we will assume
-// that any instructions other than selector comparisons and catch handlers can
-// be ignored. In practice, these will only be the boilerplate instructions.
-//
-// The catch handlers may also have any control structure, but we are only
-// interested in the start of the catch handlers, so we don't need to actually
-// follow the flow of the catch handlers. The start of the catch handlers can
-// be located from the compare instructions, but they can be skipped in the
-// flow by following the contrary branch.
-void WinEHPrepare::mapLandingPadBlocks(LandingPadInst *LPad,
- LandingPadActions &Actions) {
- unsigned int NumClauses = LPad->getNumClauses();
- unsigned int HandlersFound = 0;
- BasicBlock *BB = LPad->getParent();
-
- DEBUG(dbgs() << "Mapping landing pad: " << BB->getName() << "\n");
-
- if (NumClauses == 0) {
- findCleanupHandlers(Actions, BB, nullptr);
- return;
- }
-
- VisitedBlockSet VisitedBlocks;
-
- while (HandlersFound != NumClauses) {
- BasicBlock *NextBB = nullptr;
-
- // Skip over filter clauses.
- if (LPad->isFilter(HandlersFound)) {
- ++HandlersFound;
- continue;
- }
-
- // See if the clause we're looking for is a catch-all.
- // If so, the catch begins immediately.
- Constant *ExpectedSelector =
- LPad->getClause(HandlersFound)->stripPointerCasts();
- if (isa<ConstantPointerNull>(ExpectedSelector)) {
- // The catch all must occur last.
- assert(HandlersFound == NumClauses - 1);
-
- // There can be additional selector dispatches in the call chain that we
- // need to ignore.
- BasicBlock *CatchBlock = nullptr;
- Constant *Selector;
- while (BB && isSelectorDispatch(BB, CatchBlock, Selector, NextBB)) {
- DEBUG(dbgs() << " Found extra catch dispatch in block "
- << CatchBlock->getName() << "\n");
- BB = NextBB;
- }
-
- // Add the catch handler to the action list.
- CatchHandler *Action = nullptr;
- if (CatchHandlerMap.count(BB) && CatchHandlerMap[BB] != nullptr) {
- // If the CatchHandlerMap already has an entry for this BB, re-use it.
- Action = CatchHandlerMap[BB];
- assert(Action->getSelector() == ExpectedSelector);
- } else {
- // We don't expect a selector dispatch, but there may be a call to
- // llvm.eh.begincatch, which separates catch handling code from
- // cleanup code in the same control flow. This call looks for the
- // begincatch intrinsic.
- Action = findCatchHandler(BB, NextBB, VisitedBlocks);
- if (Action) {
- // For C++ EH, check if there is any interesting cleanup code before
- // we begin the catch. This is important because cleanups cannot
- // rethrow exceptions but code called from catches can. For SEH, it
- // isn't important if some finally code before a catch-all is executed
- // out of line or after recovering from the exception.
- if (Personality == EHPersonality::MSVC_CXX)
- findCleanupHandlers(Actions, BB, BB);
- } else {
- // If an action was not found, it means that the control flows
- // directly into the catch-all handler and there is no cleanup code.
- // That's an expected situation and we must create a catch action.
- // Since this is a catch-all handler, the selector won't actually
- // appear in the code anywhere. ExpectedSelector here is the constant
- // null ptr that we got from the landing pad instruction.
- Action = new CatchHandler(BB, ExpectedSelector, nullptr);
- CatchHandlerMap[BB] = Action;
- }
- }
- Actions.insertCatchHandler(Action);
- DEBUG(dbgs() << " Catch all handler at block " << BB->getName() << "\n");
- ++HandlersFound;
-
- // Once we reach a catch-all, don't expect to hit a resume instruction.
- BB = nullptr;
- break;
- }
-
- CatchHandler *CatchAction = findCatchHandler(BB, NextBB, VisitedBlocks);
- assert(CatchAction);
-
- // See if there is any interesting code executed before the dispatch.
- findCleanupHandlers(Actions, BB, CatchAction->getStartBlock());
-
- // When the source program contains multiple nested try blocks the catch
- // handlers can get strung together in such a way that we can encounter
- // a dispatch for a selector that we've already had a handler for.
- if (CatchAction->getSelector()->stripPointerCasts() == ExpectedSelector) {
- ++HandlersFound;
-
- // Add the catch handler to the action list.
- DEBUG(dbgs() << " Found catch dispatch in block "
- << CatchAction->getStartBlock()->getName() << "\n");
- Actions.insertCatchHandler(CatchAction);
- } else {
- // Under some circumstances optimized IR will flow unconditionally into a
- // handler block without checking the selector. This can only happen if
- // the landing pad has a catch-all handler and the handler for the
- // preceding catch clause is identical to the catch-call handler
- // (typically an empty catch). In this case, the handler must be shared
- // by all remaining clauses.
- if (isa<ConstantPointerNull>(
- CatchAction->getSelector()->stripPointerCasts())) {
- DEBUG(dbgs() << " Applying early catch-all handler in block "
- << CatchAction->getStartBlock()->getName()
- << " to all remaining clauses.\n");
- Actions.insertCatchHandler(CatchAction);
- return;
- }
-
- DEBUG(dbgs() << " Found extra catch dispatch in block "
- << CatchAction->getStartBlock()->getName() << "\n");
- }
-
- // Move on to the block after the catch handler.
- BB = NextBB;
- }
-
- // If we didn't wind up in a catch-all, see if there is any interesting code
- // executed before the resume.
- findCleanupHandlers(Actions, BB, BB);
-
- // It's possible that some optimization moved code into a landingpad that
- // wasn't
- // previously being used for cleanup. If that happens, we need to execute
- // that
- // extra code from a cleanup handler.
- if (Actions.includesCleanup() && !LPad->isCleanup())
- LPad->setCleanup(true);
-}
-
-// This function searches starting with the input block for the next
-// block that terminates with a branch whose condition is based on a selector
-// comparison. This may be the input block. See the mapLandingPadBlocks
-// comments for a discussion of control flow assumptions.
-//
-CatchHandler *WinEHPrepare::findCatchHandler(BasicBlock *BB,
- BasicBlock *&NextBB,
- VisitedBlockSet &VisitedBlocks) {
- // See if we've already found a catch handler use it.
- // Call count() first to avoid creating a null entry for blocks
- // we haven't seen before.
- if (CatchHandlerMap.count(BB) && CatchHandlerMap[BB] != nullptr) {
- CatchHandler *Action = cast<CatchHandler>(CatchHandlerMap[BB]);
- NextBB = Action->getNextBB();
- return Action;
- }
-
- // VisitedBlocks applies only to the current search. We still
- // need to consider blocks that we've visited while mapping other
- // landing pads.
- VisitedBlocks.insert(BB);
-
- BasicBlock *CatchBlock = nullptr;
- Constant *Selector = nullptr;
-
- // If this is the first time we've visited this block from any landing pad
- // look to see if it is a selector dispatch block.
- if (!CatchHandlerMap.count(BB)) {
- if (isSelectorDispatch(BB, CatchBlock, Selector, NextBB)) {
- CatchHandler *Action = new CatchHandler(BB, Selector, NextBB);
- CatchHandlerMap[BB] = Action;
- return Action;
- }
- // If we encounter a block containing an llvm.eh.begincatch before we
- // find a selector dispatch block, the handler is assumed to be
- // reached unconditionally. This happens for catch-all blocks, but
- // it can also happen for other catch handlers that have been combined
- // with the catch-all handler during optimization.
- if (isCatchBlock(BB)) {
- PointerType *Int8PtrTy = Type::getInt8PtrTy(BB->getContext());
- Constant *NullSelector = ConstantPointerNull::get(Int8PtrTy);
- CatchHandler *Action = new CatchHandler(BB, NullSelector, nullptr);
- CatchHandlerMap[BB] = Action;
- return Action;
- }
- }
-
- // Visit each successor, looking for the dispatch.
- // FIXME: We expect to find the dispatch quickly, so this will probably
- // work better as a breadth first search.
- for (BasicBlock *Succ : successors(BB)) {
- if (VisitedBlocks.count(Succ))
- continue;
-
- CatchHandler *Action = findCatchHandler(Succ, NextBB, VisitedBlocks);
- if (Action)
- return Action;
- }
- return nullptr;
-}
-
-// These are helper functions to combine repeated code from findCleanupHandlers.
-static void createCleanupHandler(LandingPadActions &Actions,
- CleanupHandlerMapTy &CleanupHandlerMap,
- BasicBlock *BB) {
- CleanupHandler *Action = new CleanupHandler(BB);
- CleanupHandlerMap[BB] = Action;
- Actions.insertCleanupHandler(Action);
- DEBUG(dbgs() << " Found cleanup code in block "
- << Action->getStartBlock()->getName() << "\n");
-}
-
-static CallSite matchOutlinedFinallyCall(BasicBlock *BB,
- Instruction *MaybeCall) {
- // Look for finally blocks that Clang has already outlined for us.
- // %fp = call i8* @llvm.localaddress()
- // call void @"fin$parent"(iN 1, i8* %fp)
- if (isLocalAddressCall(MaybeCall) && MaybeCall != BB->getTerminator())
- MaybeCall = MaybeCall->getNextNode();
- CallSite FinallyCall(MaybeCall);
- if (!FinallyCall || FinallyCall.arg_size() != 2)
- return CallSite();
- if (!match(FinallyCall.getArgument(0), m_SpecificInt(1)))
- return CallSite();
- if (!isLocalAddressCall(FinallyCall.getArgument(1)))
- return CallSite();
- return FinallyCall;
-}
-
-static BasicBlock *followSingleUnconditionalBranches(BasicBlock *BB) {
- // Skip single ubr blocks.
- while (BB->getFirstNonPHIOrDbg() == BB->getTerminator()) {
- auto *Br = dyn_cast<BranchInst>(BB->getTerminator());
- if (Br && Br->isUnconditional())
- BB = Br->getSuccessor(0);
- else
- return BB;
- }
- return BB;
-}
-
-// This function searches starting with the input block for the next block that
-// contains code that is not part of a catch handler and would not be eliminated
-// during handler outlining.
-//
-void WinEHPrepare::findCleanupHandlers(LandingPadActions &Actions,
- BasicBlock *StartBB, BasicBlock *EndBB) {
- // Here we will skip over the following:
- //
- // landing pad prolog:
- //
- // Unconditional branches
- //
- // Selector dispatch
- //
- // Resume pattern
- //
- // Anything else marks the start of an interesting block
-
- BasicBlock *BB = StartBB;
- // Anything other than an unconditional branch will kick us out of this loop
- // one way or another.
- while (BB) {
- BB = followSingleUnconditionalBranches(BB);
- // If we've already scanned this block, don't scan it again. If it is
- // a cleanup block, there will be an action in the CleanupHandlerMap.
- // If we've scanned it and it is not a cleanup block, there will be a
- // nullptr in the CleanupHandlerMap. If we have not scanned it, there will
- // be no entry in the CleanupHandlerMap. We must call count() first to
- // avoid creating a null entry for blocks we haven't scanned.
- if (CleanupHandlerMap.count(BB)) {
- if (auto *Action = CleanupHandlerMap[BB]) {
- Actions.insertCleanupHandler(Action);
- DEBUG(dbgs() << " Found cleanup code in block "
- << Action->getStartBlock()->getName() << "\n");
- // FIXME: This cleanup might chain into another, and we need to discover
- // that.
- return;
- } else {
- // Here we handle the case where the cleanup handler map contains a
- // value for this block but the value is a nullptr. This means that
- // we have previously analyzed the block and determined that it did
- // not contain any cleanup code. Based on the earlier analysis, we
- // know the block must end in either an unconditional branch, a
- // resume or a conditional branch that is predicated on a comparison
- // with a selector. Either the resume or the selector dispatch
- // would terminate the search for cleanup code, so the unconditional
- // branch is the only case for which we might need to continue
- // searching.
- BasicBlock *SuccBB = followSingleUnconditionalBranches(BB);
- if (SuccBB == BB || SuccBB == EndBB)
- return;
- BB = SuccBB;
- continue;
- }
- }
-
- // Create an entry in the cleanup handler map for this block. Initially
- // we create an entry that says this isn't a cleanup block. If we find
- // cleanup code, the caller will replace this entry.
- CleanupHandlerMap[BB] = nullptr;
-
- TerminatorInst *Terminator = BB->getTerminator();
-
- // Landing pad blocks have extra instructions we need to accept.
- LandingPadMap *LPadMap = nullptr;
- if (BB->isLandingPad()) {
- LandingPadInst *LPad = BB->getLandingPadInst();
- LPadMap = &LPadMaps[LPad];
- if (!LPadMap->isInitialized())
- LPadMap->mapLandingPad(LPad);
- }
-
- // Look for the bare resume pattern:
- // %lpad.val1 = insertvalue { i8*, i32 } undef, i8* %exn, 0
- // %lpad.val2 = insertvalue { i8*, i32 } %lpad.val1, i32 %sel, 1
- // resume { i8*, i32 } %lpad.val2
- if (auto *Resume = dyn_cast<ResumeInst>(Terminator)) {
- InsertValueInst *Insert1 = nullptr;
- InsertValueInst *Insert2 = nullptr;
- Value *ResumeVal = Resume->getOperand(0);
- // If the resume value isn't a phi or landingpad value, it should be a
- // series of insertions. Identify them so we can avoid them when scanning
- // for cleanups.
- if (!isa<PHINode>(ResumeVal) && !isa<LandingPadInst>(ResumeVal)) {
- Insert2 = dyn_cast<InsertValueInst>(ResumeVal);
- if (!Insert2)
- return createCleanupHandler(Actions, CleanupHandlerMap, BB);
- Insert1 = dyn_cast<InsertValueInst>(Insert2->getAggregateOperand());
- if (!Insert1)
- return createCleanupHandler(Actions, CleanupHandlerMap, BB);
- }
- for (BasicBlock::iterator II = BB->getFirstNonPHIOrDbg(), IE = BB->end();
- II != IE; ++II) {
- Instruction *Inst = II;
- if (LPadMap && LPadMap->isLandingPadSpecificInst(Inst))
- continue;
- if (Inst == Insert1 || Inst == Insert2 || Inst == Resume)
- continue;
- if (!Inst->hasOneUse() ||
- (Inst->user_back() != Insert1 && Inst->user_back() != Insert2)) {
- return createCleanupHandler(Actions, CleanupHandlerMap, BB);
- }
- }
- return;
- }
-
- BranchInst *Branch = dyn_cast<BranchInst>(Terminator);
- if (Branch && Branch->isConditional()) {
- // Look for the selector dispatch.
- // %2 = call i32 @llvm.eh.typeid.for(i8* bitcast (i8** @_ZTIf to i8*))
- // %matches = icmp eq i32 %sel, %2
- // br i1 %matches, label %catch14, label %eh.resume
- CmpInst *Compare = dyn_cast<CmpInst>(Branch->getCondition());
- if (!Compare || !Compare->isEquality())
- return createCleanupHandler(Actions, CleanupHandlerMap, BB);
- for (BasicBlock::iterator II = BB->getFirstNonPHIOrDbg(), IE = BB->end();
- II != IE; ++II) {
- Instruction *Inst = II;
- if (LPadMap && LPadMap->isLandingPadSpecificInst(Inst))
- continue;
- if (Inst == Compare || Inst == Branch)
- continue;
- if (match(Inst, m_Intrinsic<Intrinsic::eh_typeid_for>()))
- continue;
- return createCleanupHandler(Actions, CleanupHandlerMap, BB);
- }
- // The selector dispatch block should always terminate our search.
- assert(BB == EndBB);
- return;
- }
-
- if (isAsynchronousEHPersonality(Personality)) {
- // If this is a landingpad block, split the block at the first non-landing
- // pad instruction.
- Instruction *MaybeCall = BB->getFirstNonPHIOrDbg();
- if (LPadMap) {
- while (MaybeCall != BB->getTerminator() &&
- LPadMap->isLandingPadSpecificInst(MaybeCall))
- MaybeCall = MaybeCall->getNextNode();
- }
-
- // Look for outlined finally calls on x64, since those happen to match the
- // prototype provided by the runtime.
- if (TheTriple.getArch() == Triple::x86_64) {
- if (CallSite FinallyCall = matchOutlinedFinallyCall(BB, MaybeCall)) {
- Function *Fin = FinallyCall.getCalledFunction();
- assert(Fin && "outlined finally call should be direct");
- auto *Action = new CleanupHandler(BB);
- Action->setHandlerBlockOrFunc(Fin);
- Actions.insertCleanupHandler(Action);
- CleanupHandlerMap[BB] = Action;
- DEBUG(dbgs() << " Found frontend-outlined finally call to "
- << Fin->getName() << " in block "
- << Action->getStartBlock()->getName() << "\n");
-
- // Split the block if there were more interesting instructions and
- // look for finally calls in the normal successor block.
- BasicBlock *SuccBB = BB;
- if (FinallyCall.getInstruction() != BB->getTerminator() &&
- FinallyCall.getInstruction()->getNextNode() !=
- BB->getTerminator()) {
- SuccBB =
- SplitBlock(BB, FinallyCall.getInstruction()->getNextNode(), DT);
- } else {
- if (FinallyCall.isInvoke()) {
- SuccBB = cast<InvokeInst>(FinallyCall.getInstruction())
- ->getNormalDest();
- } else {
- SuccBB = BB->getUniqueSuccessor();
- assert(SuccBB &&
- "splitOutlinedFinallyCalls didn't insert a branch");
- }
- }
- BB = SuccBB;
- if (BB == EndBB)
- return;
- continue;
- }
- }
- }
-
- // Anything else is either a catch block or interesting cleanup code.
- for (BasicBlock::iterator II = BB->getFirstNonPHIOrDbg(), IE = BB->end();
- II != IE; ++II) {
- Instruction *Inst = II;
- if (LPadMap && LPadMap->isLandingPadSpecificInst(Inst))
- continue;
- // Unconditional branches fall through to this loop.
- if (Inst == Branch)
- continue;
- // If this is a catch block, there is no cleanup code to be found.
- if (match(Inst, m_Intrinsic<Intrinsic::eh_begincatch>()))
- return;
- // If this a nested landing pad, it may contain an endcatch call.
- if (match(Inst, m_Intrinsic<Intrinsic::eh_endcatch>()))
- return;
- // Anything else makes this interesting cleanup code.
- return createCleanupHandler(Actions, CleanupHandlerMap, BB);
- }
-
- // Only unconditional branches in empty blocks should get this far.
- assert(Branch && Branch->isUnconditional());
- if (BB == EndBB)
- return;
- BB = Branch->getSuccessor(0);
- }
-}
-
-// This is a public function, declared in WinEHFuncInfo.h and is also
-// referenced by WinEHNumbering in FunctionLoweringInfo.cpp.
-void llvm::parseEHActions(
- const IntrinsicInst *II,
- SmallVectorImpl<std::unique_ptr<ActionHandler>> &Actions) {
- assert(II->getIntrinsicID() == Intrinsic::eh_actions &&
- "attempted to parse non eh.actions intrinsic");
- 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));
- ConstantInt *EHObjIndex = cast<ConstantInt>(II->getArgOperand(I + 2));
- int64_t EHObjIndexVal = EHObjIndex->getSExtValue();
- Constant *Handler = cast<Constant>(II->getArgOperand(I + 3));
- I += 4;
- auto CH = make_unique<CatchHandler>(/*BB=*/nullptr, Selector,
- /*NextBB=*/nullptr);
- CH->setHandlerBlockOrFunc(Handler);
- CH->setExceptionVarIndex(EHObjIndexVal);
- Actions.push_back(std::move(CH));
- } else if (ActionKind == 0) {
- Constant *Handler = cast<Constant>(II->getArgOperand(I + 1));
- I += 2;
- auto CH = make_unique<CleanupHandler>(/*BB=*/nullptr);
- CH->setHandlerBlockOrFunc(Handler);
- Actions.push_back(std::move(CH));
- } else {
- llvm_unreachable("Expected either a catch or cleanup handler!");
- }
- }
- std::reverse(Actions.begin(), Actions.end());
-}
-
-namespace {
-struct WinEHNumbering {
- WinEHNumbering(WinEHFuncInfo &FuncInfo) : FuncInfo(FuncInfo),
- CurrentBaseState(-1), NextState(0) {}
-
- WinEHFuncInfo &FuncInfo;
- int CurrentBaseState;
- int NextState;
-
- SmallVector<std::unique_ptr<ActionHandler>, 4> HandlerStack;
- SmallPtrSet<const Function *, 4> VisitedHandlers;
-
- int currentEHNumber() const {
- return HandlerStack.empty() ? CurrentBaseState : HandlerStack.back()->getEHState();
- }