-bool WinEHPrepare::prepareExceptionHandlers(
- Function &F, SmallVectorImpl<LandingPadInst *> &LPads) {
- // Don't run on functions that are already prepared.
- for (LandingPadInst *LPad : LPads) {
- BasicBlock *LPadBB = LPad->getParent();
- for (Instruction &Inst : *LPadBB)
- if (match(&Inst, m_Intrinsic<Intrinsic::eh_actions>()))
- return false;
- }
-
- identifyEHBlocks(F, LPads);
- demoteValuesLiveAcrossHandlers(F, LPads);
-
- // These containers are used to re-map frame variables that are used in
- // outlined catch and cleanup handlers. They will be populated as the
- // handlers are outlined.
- FrameVarInfoMap FrameVarInfo;
-
- bool HandlersOutlined = false;
-
- Module *M = F.getParent();
- LLVMContext &Context = M->getContext();
-
- // Create a new function to receive the handler contents.
- PointerType *Int8PtrType = Type::getInt8PtrTy(Context);
- Type *Int32Type = Type::getInt32Ty(Context);
- Function *ActionIntrin = Intrinsic::getDeclaration(M, Intrinsic::eh_actions);
-
- if (isAsynchronousEHPersonality(Personality)) {
- // FIXME: Switch the ehptr type to i32 and then switch this.
- SEHExceptionCodeSlot =
- new AllocaInst(Int8PtrType, nullptr, "seh_exception_code",
- F.getEntryBlock().getFirstInsertionPt());
- }
-
- // In order to handle the case where one outlined catch handler returns
- // to a block within another outlined catch handler that would otherwise
- // be unreachable, we need to outline the nested landing pad before we
- // outline the landing pad which encloses it.
- if (!isAsynchronousEHPersonality(Personality))
- std::sort(LPads.begin(), LPads.end(),
- [this](LandingPadInst *const &L, LandingPadInst *const &R) {
- return DT->properlyDominates(R->getParent(), L->getParent());
- });
-
- // This container stores the llvm.eh.recover and IndirectBr instructions
- // that make up the body of each landing pad after it has been outlined.
- // We need to defer the population of the target list for the indirectbr
- // until all landing pads have been outlined so that we can handle the
- // case of blocks in the target that are reached only from nested
- // landing pads.
- SmallVector<std::pair<CallInst*, IndirectBrInst *>, 4> LPadImpls;
-
- for (LandingPadInst *LPad : LPads) {
- // Look for evidence that this landingpad has already been processed.
- bool LPadHasActionList = false;
- BasicBlock *LPadBB = LPad->getParent();
- for (Instruction &Inst : *LPadBB) {
- if (match(&Inst, m_Intrinsic<Intrinsic::eh_actions>())) {
- LPadHasActionList = true;
- break;
- }
- }
-
- // If we've already outlined the handlers for this landingpad,
- // there's nothing more to do here.
- if (LPadHasActionList)
- continue;
-
- // If either of the values in the aggregate returned by the landing pad is
- // extracted and stored to memory, promote the stored value to a register.
- promoteLandingPadValues(LPad);
-
- LandingPadActions Actions;
- mapLandingPadBlocks(LPad, Actions);
-
- HandlersOutlined |= !Actions.actions().empty();
- for (ActionHandler *Action : Actions) {
- if (Action->hasBeenProcessed())
- continue;
- BasicBlock *StartBB = Action->getStartBlock();
-
- // SEH doesn't do any outlining for catches. Instead, pass the handler
- // basic block addr to llvm.eh.actions and list the block as a return
- // target.
- if (isAsynchronousEHPersonality(Personality)) {
- if (auto *CatchAction = dyn_cast<CatchHandler>(Action)) {
- processSEHCatchHandler(CatchAction, StartBB);
- continue;
- }
- }
-
- outlineHandler(Action, &F, LPad, StartBB, FrameVarInfo);
- }
-
- // Split the block after the landingpad instruction so that it is just a
- // call to llvm.eh.actions followed by indirectbr.
- assert(!isa<PHINode>(LPadBB->begin()) && "lpad phi not removed");
- SplitBlock(LPadBB, LPad->getNextNode(), DT);
- // Erase the branch inserted by the split so we can insert indirectbr.
- LPadBB->getTerminator()->eraseFromParent();
-
- // Replace all extracted values with undef and ultimately replace the
- // landingpad with undef.
- SmallVector<Instruction *, 4> SEHCodeUses;
- SmallVector<Instruction *, 4> EHUndefs;
- for (User *U : LPad->users()) {
- auto *E = dyn_cast<ExtractValueInst>(U);
- if (!E)
- continue;
- assert(E->getNumIndices() == 1 &&
- "Unexpected operation: extracting both landing pad values");
- unsigned Idx = *E->idx_begin();
- assert((Idx == 0 || Idx == 1) && "unexpected index");
- if (Idx == 0 && isAsynchronousEHPersonality(Personality))
- SEHCodeUses.push_back(E);
- else
- EHUndefs.push_back(E);
- }
- for (Instruction *E : EHUndefs) {
- E->replaceAllUsesWith(UndefValue::get(E->getType()));
- E->eraseFromParent();
- }
- LPad->replaceAllUsesWith(UndefValue::get(LPad->getType()));
-
- // Rewrite uses of the exception pointer to loads of an alloca.
- for (Instruction *E : SEHCodeUses) {
- SmallVector<Use *, 4> Uses;
- for (Use &U : E->uses())
- Uses.push_back(&U);
- for (Use *U : Uses) {
- auto *I = cast<Instruction>(U->getUser());
- if (isa<ResumeInst>(I))
- continue;
- LoadInst *LI;
- if (auto *Phi = dyn_cast<PHINode>(I))
- LI = new LoadInst(SEHExceptionCodeSlot, "sehcode", false,
- Phi->getIncomingBlock(*U)->getTerminator());
- else
- LI = new LoadInst(SEHExceptionCodeSlot, "sehcode", false, I);
- U->set(LI);
- }
- E->replaceAllUsesWith(UndefValue::get(E->getType()));
- E->eraseFromParent();
- }
-
- // Add a call to describe the actions for this landing pad.
- std::vector<Value *> ActionArgs;
- for (ActionHandler *Action : Actions) {
- // Action codes from docs are: 0 cleanup, 1 catch.
- if (auto *CatchAction = dyn_cast<CatchHandler>(Action)) {
- ActionArgs.push_back(ConstantInt::get(Int32Type, 1));
- ActionArgs.push_back(CatchAction->getSelector());
- // Find the frame escape index of the exception object alloca in the
- // parent.
- int FrameEscapeIdx = -1;
- Value *EHObj = const_cast<Value *>(CatchAction->getExceptionVar());
- if (EHObj && !isa<ConstantPointerNull>(EHObj)) {
- auto I = FrameVarInfo.find(EHObj);
- assert(I != FrameVarInfo.end() &&
- "failed to map llvm.eh.begincatch var");
- FrameEscapeIdx = std::distance(FrameVarInfo.begin(), I);
- }
- ActionArgs.push_back(ConstantInt::get(Int32Type, FrameEscapeIdx));
- } else {
- ActionArgs.push_back(ConstantInt::get(Int32Type, 0));
- }
- ActionArgs.push_back(Action->getHandlerBlockOrFunc());
- }
- CallInst *Recover =
- CallInst::Create(ActionIntrin, ActionArgs, "recover", LPadBB);
-
- SetVector<BasicBlock *> ReturnTargets;
- for (ActionHandler *Action : Actions) {
- if (auto *CatchAction = dyn_cast<CatchHandler>(Action)) {
- const auto &CatchTargets = CatchAction->getReturnTargets();
- ReturnTargets.insert(CatchTargets.begin(), CatchTargets.end());
- }
- }
- IndirectBrInst *Branch =
- IndirectBrInst::Create(Recover, ReturnTargets.size(), LPadBB);
- for (BasicBlock *Target : ReturnTargets)
- Branch->addDestination(Target);
-
- if (!isAsynchronousEHPersonality(Personality)) {
- // C++ EH must repopulate the targets later to handle the case of
- // targets that are reached indirectly through nested landing pads.
- LPadImpls.push_back(std::make_pair(Recover, Branch));
- }
-
- } // End for each landingpad
-
- // If nothing got outlined, there is no more processing to be done.
- if (!HandlersOutlined)
- return false;