diff options
Diffstat (limited to 'llvm/lib')
33 files changed, 1165 insertions, 2285 deletions
diff --git a/llvm/lib/Analysis/CaptureTracking.cpp b/llvm/lib/Analysis/CaptureTracking.cpp index c717a8ee2e6..1add2fa7756 100644 --- a/llvm/lib/Analysis/CaptureTracking.cpp +++ b/llvm/lib/Analysis/CaptureTracking.cpp @@ -80,12 +80,11 @@ namespace { if (BB == BeforeHere->getParent()) { // 'I' dominates 'BeforeHere' => not safe to prune. // - // The value defined by an invoke/catchpad dominates an instruction only + // The value defined by an invoke dominates an instruction only // if it dominates every instruction in UseBB. A PHI is dominated only // if the instruction dominates every possible use in the UseBB. Since // UseBB == BB, avoid pruning. - if (isa<InvokeInst>(BeforeHere) || isa<CatchPadInst>(BeforeHere) || - isa<PHINode>(I) || I == BeforeHere) + if (isa<InvokeInst>(BeforeHere) || isa<PHINode>(I) || I == BeforeHere) return false; if (!OrderedBB->dominates(BeforeHere, I)) return false; diff --git a/llvm/lib/Analysis/EHPersonalities.cpp b/llvm/lib/Analysis/EHPersonalities.cpp index 1d1b5fe11f6..c95fcee13b8 100644 --- a/llvm/lib/Analysis/EHPersonalities.cpp +++ b/llvm/lib/Analysis/EHPersonalities.cpp @@ -9,7 +9,11 @@ #include "llvm/Analysis/EHPersonalities.h" #include "llvm/ADT/StringSwitch.h" +#include "llvm/IR/CFG.h" +#include "llvm/IR/Constants.h" #include "llvm/IR/Function.h" +#include "llvm/IR/Instructions.h" +#include "llvm/Support/Debug.h" using namespace llvm; /// See if the given exception handling personality function is one that we @@ -39,3 +43,64 @@ bool llvm::canSimplifyInvokeNoUnwind(const Function *F) { // implies that the function does not throw synchronous exceptions. return !isAsynchronousEHPersonality(Personality); } + +DenseMap<BasicBlock *, ColorVector> llvm::colorEHFunclets(Function &F) { + SmallVector<std::pair<BasicBlock *, BasicBlock *>, 16> Worklist; + BasicBlock *EntryBlock = &F.getEntryBlock(); + DenseMap<BasicBlock *, ColorVector> BlockColors; + + // Build up the color map, which maps each block to its set of 'colors'. + // For any block B the "colors" of B are the set of funclets F (possibly + // including a root "funclet" representing the main function) such that + // F will need to directly contain B or a copy of B (where the term "directly + // contain" is used to distinguish from being "transitively contained" in + // a nested funclet). + // + // Note: Despite not being funclets in the truest sense, terminatepad and + // catchswitch are considered to belong to their own funclet for the purposes + // of coloring. + + DEBUG_WITH_TYPE("winehprepare-coloring", dbgs() << "\nColoring funclets for " + << F.getName() << "\n"); + + Worklist.push_back({EntryBlock, EntryBlock}); + + while (!Worklist.empty()) { + BasicBlock *Visiting; + BasicBlock *Color; + std::tie(Visiting, Color) = Worklist.pop_back_val(); + DEBUG_WITH_TYPE("winehprepare-coloring", + dbgs() << "Visiting " << Visiting->getName() << ", " + << Color->getName() << "\n"); + Instruction *VisitingHead = Visiting->getFirstNonPHI(); + if (VisitingHead->isEHPad()) { + // Mark this funclet head as a member of itself. + Color = Visiting; + } + // Note that this is a member of the given color. + ColorVector &Colors = BlockColors[Visiting]; + if (std::find(Colors.begin(), Colors.end(), Color) == Colors.end()) + Colors.push_back(Color); + else + continue; + + DEBUG_WITH_TYPE("winehprepare-coloring", + dbgs() << " Assigned color \'" << Color->getName() + << "\' to block \'" << Visiting->getName() + << "\'.\n"); + + BasicBlock *SuccColor = Color; + TerminatorInst *Terminator = Visiting->getTerminator(); + if (auto *CatchRet = dyn_cast<CatchReturnInst>(Terminator)) { + Value *ParentPad = CatchRet->getParentPad(); + if (isa<ConstantTokenNone>(ParentPad)) + SuccColor = EntryBlock; + else + SuccColor = cast<Instruction>(ParentPad)->getParent(); + } + + for (BasicBlock *Succ : successors(Visiting)) + Worklist.push_back({Succ, SuccColor}); + } + return BlockColors; +} diff --git a/llvm/lib/Analysis/InstructionSimplify.cpp b/llvm/lib/Analysis/InstructionSimplify.cpp index 0bd18c1a35c..db17d886e4b 100644 --- a/llvm/lib/Analysis/InstructionSimplify.cpp +++ b/llvm/lib/Analysis/InstructionSimplify.cpp @@ -122,10 +122,10 @@ static bool ValueDominatesPHI(Value *V, PHINode *P, const DominatorTree *DT) { return DT->dominates(I, P); } - // Otherwise, if the instruction is in the entry block, and is not an invoke, - // and is not a catchpad, then it obviously dominates all phi nodes. + // Otherwise, if the instruction is in the entry block and is not an invoke, + // then it obviously dominates all phi nodes. if (I->getParent() == &I->getParent()->getParent()->getEntryBlock() && - !isa<InvokeInst>(I) && !isa<CatchPadInst>(I)) + !isa<InvokeInst>(I)) return true; return false; diff --git a/llvm/lib/Analysis/LoopInfo.cpp b/llvm/lib/Analysis/LoopInfo.cpp index 67a82b192e5..07fd6a2ae70 100644 --- a/llvm/lib/Analysis/LoopInfo.cpp +++ b/llvm/lib/Analysis/LoopInfo.cpp @@ -227,9 +227,15 @@ bool Loop::isSafeToClone() const { if (isa<IndirectBrInst>((*I)->getTerminator())) return false; - if (const InvokeInst *II = dyn_cast<InvokeInst>((*I)->getTerminator())) + if (const InvokeInst *II = dyn_cast<InvokeInst>((*I)->getTerminator())) { if (II->cannotDuplicate()) return false; + // Return false if any loop blocks contain invokes to EH-pads other than + // landingpads; we don't know how to split those edges yet. + auto *FirstNonPHI = II->getUnwindDest()->getFirstNonPHI(); + if (FirstNonPHI->isEHPad() && !isa<LandingPadInst>(FirstNonPHI)) + return false; + } for (BasicBlock::iterator BI = (*I)->begin(), BE = (*I)->end(); BI != BE; ++BI) { if (const CallInst *CI = dyn_cast<CallInst>(BI)) { diff --git a/llvm/lib/Analysis/ScalarEvolutionExpander.cpp b/llvm/lib/Analysis/ScalarEvolutionExpander.cpp index abfcfbafb32..bcbf35b046b 100644 --- a/llvm/lib/Analysis/ScalarEvolutionExpander.cpp +++ b/llvm/lib/Analysis/ScalarEvolutionExpander.cpp @@ -91,22 +91,16 @@ static BasicBlock::iterator findInsertPointAfter(Instruction *I, BasicBlock::iterator IP = ++I->getIterator(); if (auto *II = dyn_cast<InvokeInst>(I)) IP = II->getNormalDest()->begin(); - if (auto *CPI = dyn_cast<CatchPadInst>(I)) - IP = CPI->getNormalDest()->begin(); while (isa<PHINode>(IP)) ++IP; while (IP->isEHPad()) { - if (isa<LandingPadInst>(IP) || isa<CleanupPadInst>(IP)) { + if (isa<FuncletPadInst>(IP) || isa<LandingPadInst>(IP)) { ++IP; } else if (auto *TPI = dyn_cast<TerminatePadInst>(IP)) { IP = TPI->getUnwindDest()->getFirstNonPHI()->getIterator(); - } else if (auto *CEPI = dyn_cast<CatchEndPadInst>(IP)) { - IP = CEPI->getUnwindDest()->getFirstNonPHI()->getIterator(); - } else if (auto *CEPI = dyn_cast<CleanupEndPadInst>(IP)) { - IP = CEPI->getUnwindDest()->getFirstNonPHI()->getIterator(); - } else if (isa<CatchPadInst>(IP)) { + } else if (isa<CatchSwitchInst>(IP)) { IP = MustDominate->getFirstInsertionPt(); } else { llvm_unreachable("unexpected eh pad!"); diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp index b2a1034eeaa..4a228c30a93 100644 --- a/llvm/lib/Analysis/ValueTracking.cpp +++ b/llvm/lib/Analysis/ValueTracking.cpp @@ -3431,11 +3431,10 @@ bool llvm::isSafeToSpeculativelyExecute(const Value *V, case Instruction::AtomicCmpXchg: case Instruction::LandingPad: case Instruction::Resume: + case Instruction::CatchSwitch: case Instruction::CatchPad: - case Instruction::CatchEndPad: case Instruction::CatchRet: case Instruction::CleanupPad: - case Instruction::CleanupEndPad: case Instruction::CleanupRet: case Instruction::TerminatePad: return false; // Misc instructions which have effects diff --git a/llvm/lib/AsmParser/LLLexer.cpp b/llvm/lib/AsmParser/LLLexer.cpp index db90f78b318..59b7db0ea4c 100644 --- a/llvm/lib/AsmParser/LLLexer.cpp +++ b/llvm/lib/AsmParser/LLLexer.cpp @@ -526,6 +526,8 @@ lltok::Kind LLLexer::LexIdentifier() { KEYWORD(none); KEYWORD(to); KEYWORD(caller); + KEYWORD(within); + KEYWORD(from); KEYWORD(tail); KEYWORD(musttail); KEYWORD(notail); @@ -759,11 +761,10 @@ lltok::Kind LLLexer::LexIdentifier() { INSTKEYWORD(landingpad, LandingPad); INSTKEYWORD(cleanupret, CleanupRet); INSTKEYWORD(catchret, CatchRet); + INSTKEYWORD(catchswitch, CatchSwitch); INSTKEYWORD(catchpad, CatchPad); INSTKEYWORD(terminatepad, TerminatePad); INSTKEYWORD(cleanuppad, CleanupPad); - INSTKEYWORD(catchendpad, CatchEndPad); - INSTKEYWORD(cleanupendpad, CleanupEndPad); #undef INSTKEYWORD #define DWKEYWORD(TYPE, TOKEN) \ diff --git a/llvm/lib/AsmParser/LLParser.cpp b/llvm/lib/AsmParser/LLParser.cpp index b5cbee5085b..2e411733e27 100644 --- a/llvm/lib/AsmParser/LLParser.cpp +++ b/llvm/lib/AsmParser/LLParser.cpp @@ -2315,7 +2315,7 @@ bool LLParser::PerFunctionState::FinishFunction() { /// forward reference record if needed. This can return null if the value /// exists but does not have the right type. Value *LLParser::PerFunctionState::GetVal(const std::string &Name, Type *Ty, - LocTy Loc, OperatorConstraint OC) { + LocTy Loc) { // Look this name up in the normal function symbol table. Value *Val = F.getValueSymbolTable().lookup(Name); @@ -2329,24 +2329,6 @@ Value *LLParser::PerFunctionState::GetVal(const std::string &Name, Type *Ty, // If we have the value in the symbol table or fwd-ref table, return it. if (Val) { - // Check operator constraints. - switch (OC) { - case OC_None: - // no constraint - break; - case OC_CatchPad: - if (!isa<CatchPadInst>(Val)) { - P.Error(Loc, "'%" + Name + "' is not a catchpad"); - return nullptr; - } - break; - case OC_CleanupPad: - if (!isa<CleanupPadInst>(Val)) { - P.Error(Loc, "'%" + Name + "' is not a cleanuppad"); - return nullptr; - } - break; - } if (Val->getType() == Ty) return Val; if (Ty->isLabelTy()) P.Error(Loc, "'%" + Name + "' is not a basic block"); @@ -2365,30 +2347,16 @@ Value *LLParser::PerFunctionState::GetVal(const std::string &Name, Type *Ty, // Otherwise, create a new forward reference for this value and remember it. Value *FwdVal; if (Ty->isLabelTy()) { - assert(!OC); FwdVal = BasicBlock::Create(F.getContext(), Name, &F); - } else if (!OC) { - FwdVal = new Argument(Ty, Name); } else { - switch (OC) { - case OC_CatchPad: - FwdVal = CatchPadInst::Create(&F.getEntryBlock(), &F.getEntryBlock(), {}, - Name); - break; - case OC_CleanupPad: - FwdVal = CleanupPadInst::Create(F.getContext(), {}, Name); - break; - default: - llvm_unreachable("unexpected constraint"); - } + FwdVal = new Argument(Ty, Name); } ForwardRefVals[Name] = std::make_pair(FwdVal, Loc); return FwdVal; } -Value *LLParser::PerFunctionState::GetVal(unsigned ID, Type *Ty, LocTy Loc, - OperatorConstraint OC) { +Value *LLParser::PerFunctionState::GetVal(unsigned ID, Type *Ty, LocTy Loc) { // Look this name up in the normal function symbol table. Value *Val = ID < NumberedVals.size() ? NumberedVals[ID] : nullptr; @@ -2402,24 +2370,6 @@ Value *LLParser::PerFunctionState::GetVal(unsigned ID, Type *Ty, LocTy Loc, // If we have the value in the symbol table or fwd-ref table, return it. if (Val) { - // Check operator constraint. - switch (OC) { - case OC_None: - // no constraint - break; - case OC_CatchPad: - if (!isa<CatchPadInst>(Val)) { - P.Error(Loc, "'%" + Twine(ID) + "' is not a catchpad"); - return nullptr; - } - break; - case OC_CleanupPad: - if (!isa<CleanupPadInst>(Val)) { - P.Error(Loc, "'%" + Twine(ID) + "' is not a cleanuppad"); - return nullptr; - } - break; - } if (Val->getType() == Ty) return Val; if (Ty->isLabelTy()) P.Error(Loc, "'%" + Twine(ID) + "' is not a basic block"); @@ -2437,21 +2387,9 @@ Value *LLParser::PerFunctionState::GetVal(unsigned ID, Type *Ty, LocTy Loc, // Otherwise, create a new forward reference for this value and remember it. Value *FwdVal; if (Ty->isLabelTy()) { - assert(!OC); FwdVal = BasicBlock::Create(F.getContext(), "", &F); - } else if (!OC) { - FwdVal = new Argument(Ty); } else { - switch (OC) { - case OC_CatchPad: - FwdVal = CatchPadInst::Create(&F.getEntryBlock(), &F.getEntryBlock(), {}); - break; - case OC_CleanupPad: - FwdVal = CleanupPadInst::Create(F.getContext(), {}); - break; - default: - llvm_unreachable("unexpected constraint"); - } + FwdVal = new Argument(Ty); } ForwardRefValIDs[ID] = std::make_pair(FwdVal, Loc); @@ -2487,17 +2425,6 @@ bool LLParser::PerFunctionState::SetInstName(int NameID, if (Sentinel->getType() != Inst->getType()) return P.Error(NameLoc, "instruction forward referenced with type '" + getTypeString(FI->second.first->getType()) + "'"); - // Check operator constraints. We only put cleanuppads or catchpads in - // the forward value map if the value is constrained to match. - if (isa<CatchPadInst>(Sentinel)) { - if (!isa<CatchPadInst>(Inst)) - return P.Error(FI->second.second, - "'%" + Twine(NameID) + "' is not a catchpad"); - } else if (isa<CleanupPadInst>(Sentinel)) { - if (!isa<CleanupPadInst>(Inst)) - return P.Error(FI->second.second, - "'%" + Twine(NameID) + "' is not a cleanuppad"); - } Sentinel->replaceAllUsesWith(Inst); delete Sentinel; @@ -2515,17 +2442,6 @@ bool LLParser::PerFunctionState::SetInstName(int NameID, if (Sentinel->getType() != Inst->getType()) return P.Error(NameLoc, "instruction forward referenced with type '" + getTypeString(FI->second.first->getType()) + "'"); - // Check operator constraints. We only put cleanuppads or catchpads in - // the forward value map if the value is constrained to match. - if (isa<CatchPadInst>(Sentinel)) { - if (!isa<CatchPadInst>(Inst)) - return P.Error(FI->second.second, - "'%" + NameStr + "' is not a catchpad"); - } else if (isa<CleanupPadInst>(Sentinel)) { - if (!isa<CleanupPadInst>(Inst)) - return P.Error(FI->second.second, - "'%" + NameStr + "' is not a cleanuppad"); - } Sentinel->replaceAllUsesWith(Inst); delete Sentinel; @@ -4235,30 +4151,18 @@ bool LLParser::ParseMetadata(Metadata *&MD, PerFunctionState *PFS) { //===----------------------------------------------------------------------===// bool LLParser::ConvertValIDToValue(Type *Ty, ValID &ID, Value *&V, - PerFunctionState *PFS, - OperatorConstraint OC) { + PerFunctionState *PFS) { if (Ty->isFunctionTy()) return Error(ID.Loc, "functions are not values, refer to them as pointers"); - if (OC && ID.Kind != ValID::t_LocalID && ID.Kind != ValID::t_LocalName) { - switch (OC) { - case OC_CatchPad: - return Error(ID.Loc, "Catchpad value required in this position"); - case OC_CleanupPad: - return Error(ID.Loc, "Cleanuppad value required in this position"); - default: - llvm_unreachable("Unexpected constraint kind"); - } - } - switch (ID.Kind) { case ValID::t_LocalID: if (!PFS) return Error(ID.Loc, "invalid use of function-local name"); - V = PFS->GetVal(ID.UIntVal, Ty, ID.Loc, OC); + V = PFS->GetVal(ID.UIntVal, Ty, ID.Loc); return V == nullptr; case ValID::t_LocalName: if (!PFS) return Error(ID.Loc, "invalid use of function-local name"); - V = PFS->GetVal(ID.StrVal, Ty, ID.Loc, OC); + V = PFS->GetVal(ID.StrVal, Ty, ID.Loc); return V == nullptr; case ValID::t_InlineAsm: { if (!ID.FTy || !InlineAsm::Verify(ID.FTy, ID.StrVal2)) @@ -4385,11 +4289,10 @@ bool LLParser::parseConstantValue(Type *Ty, Constant *&C) { } } -bool LLParser::ParseValue(Type *Ty, Value *&V, PerFunctionState *PFS, - OperatorConstraint OC) { +bool LLParser::ParseValue(Type *Ty, Value *&V, PerFunctionState *PFS) { V = nullptr; ValID ID; - return ParseValID(ID, PFS) || ConvertValIDToValue(Ty, ID, V, PFS, OC); + return ParseValID(ID, PFS) || ConvertValIDToValue(Ty, ID, V, PFS); } bool LLParser::ParseTypeAndValue(Value *&V, PerFunctionState *PFS) { @@ -4818,11 +4721,10 @@ int LLParser::ParseInstruction(Instruction *&Inst, BasicBlock *BB, case lltok::kw_resume: return ParseResume(Inst, PFS); case lltok::kw_cleanupret: return ParseCleanupRet(Inst, PFS); case lltok::kw_catchret: return ParseCatchRet(Inst, PFS); - case lltok::kw_catchpad: return ParseCatchPad(Inst, PFS); - case lltok::kw_terminatepad: return ParseTerminatePad(Inst, PFS); - case lltok::kw_cleanuppad: return ParseCleanupPad(Inst, PFS); - case lltok::kw_catchendpad: return ParseCatchEndPad(Inst, PFS); - case lltok::kw_cleanupendpad: return ParseCleanupEndPad(Inst, PFS); + case lltok::kw_catchswitch: return ParseCatchSwitch(Inst, PFS); + case lltok::kw_catchpad: return ParseCatchPad(Inst, PFS); + case lltok::kw_terminatepad:return ParseTerminatePad(Inst, PFS); + case lltok::kw_cleanuppad: return ParseCleanupPad(Inst, PFS); // Binary Operators. case lltok::kw_add: case lltok::kw_sub: @@ -5262,11 +5164,14 @@ bool LLParser::ParseExceptionArgs(SmallVectorImpl<Value *> &Args, } /// ParseCleanupRet -/// ::= 'cleanupret' Value unwind ('to' 'caller' | TypeAndValue) +/// ::= 'cleanupret' from Value unwind ('to' 'caller' | TypeAndValue) bool LLParser::ParseCleanupRet(Instruction *&Inst, PerFunctionState &PFS) { Value *CleanupPad = nullptr; - if (ParseValue(Type::getTokenTy(Context), CleanupPad, PFS, OC_CleanupPad)) + if (ParseToken(lltok::kw_from, "expected 'from' after cleanupret")) + return true; + + if (ParseValue(Type::getTokenTy(Context), CleanupPad, PFS)) return true; if (ParseToken(lltok::kw_unwind, "expected 'unwind' in cleanupret")) @@ -5283,16 +5188,19 @@ bool LLParser::ParseCleanupRet(Instruction *&Inst, PerFunctionState &PFS) { } } - Inst = CleanupReturnInst::Create(cast<CleanupPadInst>(CleanupPad), UnwindBB); + Inst = CleanupReturnInst::Create(CleanupPad, UnwindBB); return false; } /// ParseCatchRet -/// ::= 'catchret' Value 'to' TypeAndValue +/// ::= 'catchret' from Parent Value 'to' TypeAndValue bool LLParser::ParseCatchRet(Instruction *&Inst, PerFunctionState &PFS) { Value *CatchPad = nullptr; - if (ParseValue(Type::getTokenTy(Context), CatchPad, PFS, OC_CatchPad)) + if (ParseToken(lltok::kw_from, "expected 'from' after catchret")) + return true; + + if (ParseValue(Type::getTokenTy(Context), CatchPad, PFS)) return true; BasicBlock *BB; @@ -5300,114 +5208,140 @@ bool LLParser::ParseCatchRet(Instruction *&Inst, PerFunctionState &PFS) { ParseTypeAndBasicBlock(BB, PFS)) return true; - Inst = CatchReturnInst::Create(cast<CatchPadInst>(CatchPad), BB); + Inst = CatchReturnInst::Create(CatchPad, BB); return false; } -/// ParseCatchPad -/// ::= 'catchpad' ParamList 'to' TypeAndValue 'unwind' TypeAndValue -bool LLParser::ParseCatchPad(Instruction *&Inst, PerFunctionState &PFS) { - SmallVector<Value *, 8> Args; - if (ParseExceptionArgs(Args, PFS)) +/// ParseCatchSwitch +/// ::= 'catchswitch' within Parent +bool LLParser::ParseCatchSwitch(Instruction *&Inst, PerFunctionState &PFS) { + Value *ParentPad; + LocTy BBLoc; + + if (ParseToken(lltok::kw_within, "expected 'within' after catchswitch")) return true; - BasicBlock *NormalBB, *UnwindBB; - if (ParseToken(lltok::kw_to, "expected 'to' in catchpad") || - ParseTypeAndBasicBlock(NormalBB, PFS) || - ParseToken(lltok::kw_unwind, "expected 'unwind' in catchpad") || - ParseTypeAndBasicBlock(UnwindBB, PFS)) + if (Lex.getKind() != lltok::kw_none && Lex.getKind() != lltok::LocalVar && + Lex.getKind() != lltok::LocalVarID) + return TokError("expected scope value for catchswitch"); + + if (ParseValue(Type::getTokenTy(Context), ParentPad, PFS)) return true; - Inst = CatchPadInst::Create(NormalBB, UnwindBB, Args); - return false; -} + if (ParseToken(lltok::lsquare, "expected '[' with catchswitch labels")) + return true; -/// ParseTerminatePad -/// ::= 'terminatepad' ParamList 'to' TypeAndValue -bool LLParser::ParseTerminatePad(Instruction *&Inst, PerFunctionState &PFS) { - SmallVector<Value *, 8> Args; - if (ParseExceptionArgs(Args, PFS)) + SmallVector<BasicBlock *, 32> Table; + do { + BasicBlock *DestBB; + if (ParseTypeAndBasicBlock(DestBB, PFS)) + return true; + Table.push_back(DestBB); + } while (EatIfPresent(lltok::comma)); + + if (ParseToken(lltok::rsquare, "expected ']' after catchswitch labels")) return true; - if (ParseToken(lltok::kw_unwind, "expected 'unwind' in terminatepad")) + if (ParseToken(lltok::kw_unwind, + "expected 'unwind' after catchswitch scope")) return true; BasicBlock *UnwindBB = nullptr; - if (Lex.getKind() == lltok::kw_to) { - Lex.Lex(); - if (ParseToken(lltok::kw_caller, "expected 'caller' in terminatepad")) + if (EatIfPresent(lltok::kw_to)) { + if (ParseToken(lltok::kw_caller, "expected 'caller' in catchswitch")) return true; } else { - if (ParseTypeAndBasicBlock(UnwindBB, PFS)) { + if (ParseTypeAndBasicBlock(UnwindBB, PFS)) return true; - } } - Inst = TerminatePadInst::Create(Context, UnwindBB, Args); + auto *CatchSwitch = + CatchSwitchInst::Create(ParentPad, UnwindBB, Table.size()); + for (BasicBlock *DestBB : Table) + CatchSwitch->addHandler(DestBB); + Inst = CatchSwitch; return false; } -/// ParseCleanupPad -/// ::= 'cleanuppad' ParamList -bool LLParser::ParseCleanupPad(Instruction *&Inst, PerFunctionState &PFS) { +/// ParseCatchPad +/// ::= 'catchpad' ParamList 'to' TypeAndValue 'unwind' TypeAndValue +bool LLParser::ParseCatchPad(Instruction *&Inst, PerFunctionState &PFS) { + Value *CatchSwitch = nullptr; + + if (ParseToken(lltok::kw_within, "expected 'within' after catchpad")) + return true; + + if (Lex.getKind() != lltok::LocalVar && Lex.getKind() != lltok::LocalVarID) + return TokError("expected scope value for catchpad"); + + if (ParseValue(Type::getTokenTy(Context), CatchSwitch, PFS)) + return true; + SmallVector<Value *, 8> Args; if (ParseExceptionArgs(Args, PFS)) return true; - Inst = CleanupPadInst::Create(Context, Args); + Inst = CatchPadInst::Create(CatchSwitch, Args); return false; } -/// ParseCatchEndPad -/// ::= 'catchendpad' unwind ('to' 'caller' | TypeAndValue) -bool LLParser::ParseCatchEndPad(Instruction *&Inst, PerFunctionState &PFS) { - if (ParseToken(lltok::kw_unwind, "expected 'unwind' in catchendpad")) +/// ParseTerminatePad +/// ::= 'terminatepad' within Parent ParamList 'to' TypeAndValue +bool LLParser::ParseTerminatePad(Instruction *&Inst, PerFunctionState &PFS) { + Value *ParentPad = nullptr; + + if (ParseToken(lltok::kw_within, "expected 'within' after terminatepad")) + return true; + + if (Lex.getKind() != lltok::kw_none && Lex.getKind() != lltok::LocalVar && + Lex.getKind() != lltok::LocalVarID) + return TokError("expected scope value for terminatepad"); + + if (ParseValue(Type::getTokenTy(Context), ParentPad, PFS)) + return true; + + SmallVector<Value *, 8> Args; + if (ParseExceptionArgs(Args, PFS)) + return true; + + if (ParseToken(lltok::kw_unwind, "expected 'unwind' in terminatepad")) return true; BasicBlock *UnwindBB = nullptr; if (Lex.getKind() == lltok::kw_to) { Lex.Lex(); - if (Lex.getKind() == lltok::kw_caller) { - Lex.Lex(); - } else { + if (ParseToken(lltok::kw_caller, "expected 'caller' in terminatepad")) return true; - } } else { if (ParseTypeAndBasicBlock(UnwindBB, PFS)) { return true; } } - Inst = CatchEndPadInst::Create(Context, UnwindBB); + Inst = TerminatePadInst::Create(ParentPad, UnwindBB, Args); return false; } -/// ParseCatchEndPad -/// ::= 'cleanupendpad' Value unwind ('to' 'caller' | TypeAndValue) -bool LLParser::ParseCleanupEndPad(Instruction *&Inst, PerFunctionState &PFS) { - Value *CleanupPad = nullptr; +/// ParseCleanupPad +/// ::= 'cleanuppad' within Parent ParamList +bool LLParser::ParseCleanupPad(Instruction *&Inst, PerFunctionState &PFS) { + Value *ParentPad = nullptr; - if (ParseValue(Type::getTokenTy(Context), CleanupPad, PFS, OC_CleanupPad)) + if (ParseToken(lltok::kw_within, "expected 'within' after cleanuppad")) return true; - if (ParseToken(lltok::kw_unwind, "expected 'unwind' in catchendpad")) + if (Lex.getKind() != lltok::kw_none && Lex.getKind() != lltok::LocalVar && + Lex.getKind() != lltok::LocalVarID) + return TokError("expected scope value for cleanuppad"); + + if (ParseValue(Type::getTokenTy(Context), ParentPad, PFS)) return true; - BasicBlock *UnwindBB = nullptr; - if (Lex.getKind() == lltok::kw_to) { - Lex.Lex(); - if (Lex.getKind() == lltok::kw_caller) { - Lex.Lex(); - } else { - return true; - } - } else { - if (ParseTypeAndBasicBlock(UnwindBB, PFS)) { - return true; - } - } + SmallVector<Value *, 8> Args; + if (ParseExceptionArgs(Args, PFS)) + return true; - Inst = CleanupEndPadInst::Create(cast<CleanupPadInst>(CleanupPad), UnwindBB); + Inst = CleanupPadInst::Create(ParentPad, Args); return false; } diff --git a/llvm/lib/AsmParser/LLParser.h b/llvm/lib/AsmParser/LLParser.h index d4384db9bf0..97a13f1a057 100644 --- a/llvm/lib/AsmParser/LLParser.h +++ b/llvm/lib/AsmParser/LLParser.h @@ -108,14 +108,6 @@ namespace llvm { unsigned MDKind, MDSlot; }; - /// Indicates which operator an operand allows (for the few operands that - /// may only reference a certain operator). - enum OperatorConstraint { - OC_None = 0, // No constraint - OC_CatchPad, // Must be CatchPadInst - OC_CleanupPad // Must be CleanupPadInst - }; - SmallVector<Instruction*, 64> InstsWithTBAATag; // Type resolution handling data structures. The location is set when we @@ -337,10 +329,8 @@ namespace llvm { /// GetVal - Get a value with the specified name or ID, creating a /// forward reference record if needed. This can return null if the value /// exists but does not have the right type. - Value *GetVal(const std::string &Name, Type *Ty, LocTy Loc, - OperatorConstraint OC = OC_None); - Value *GetVal(unsigned ID, Type *Ty, LocTy Loc, - OperatorConstraint OC = OC_None); + Value *GetVal(const std::string &Name, Type *Ty, LocTy Loc); + Value *GetVal(unsigned ID, Type *Ty, LocTy Loc); /// SetInstName - After an instruction is parsed and inserted into its /// basic block, this installs its name. @@ -362,16 +352,14 @@ namespace llvm { }; bool ConvertValIDToValue(Type *Ty, ValID &ID, Value *&V, - PerFunctionState *PFS, - OperatorConstraint OC = OC_None); + PerFunctionState *PFS); bool parseConstantValue(Type *Ty, Constant *&C); - bool ParseValue(Type *Ty, Value *&V, PerFunctionState *PFS, - OperatorConstraint OC = OC_None); - bool ParseValue(Type *Ty, Value *&V, PerFunctionState &PFS, - OperatorConstraint OC = OC_None) { - return ParseValue(Ty, V, &PFS, OC); + bool ParseValue(Type *Ty, Value *&V, PerFunctionState *PFS); + bool ParseValue(Type *Ty, Value *&V, PerFunctionState &PFS) { + return ParseValue(Ty, V, &PFS); } + bool ParseValue(Type *Ty, Value *&V, LocTy &Loc, PerFunctionState &PFS) { Loc = Lex.getLoc(); @@ -475,11 +463,10 @@ namespace llvm { bool ParseResume(Instruction *&Inst, PerFunctionState &PFS); bool ParseCleanupRet(Instruction *&Inst, PerFunctionState &PFS); bool ParseCatchRet(Instruction *&Inst, PerFunctionState &PFS); + bool ParseCatchSwitch(Instruction *&Inst, PerFunctionState &PFS); bool ParseCatchPad(Instruction *&Inst, PerFunctionState &PFS); bool ParseTerminatePad(Instruction *&Inst, PerFunctionState &PFS); bool ParseCleanupPad(Instruction *&Inst, PerFunctionState &PFS); - bool ParseCatchEndPad(Instruction *&Inst, PerFunctionState &PFS); - bool ParseCleanupEndPad(Instruction *&Inst, PerFunctionState &PFS); bool ParseArithmetic(Instruction *&I, PerFunctionState &PFS, unsigned Opc, unsigned OperandType); diff --git a/llvm/lib/AsmParser/LLToken.h b/llvm/lib/AsmParser/LLToken.h index 10c840d257f..b35aae5f570 100644 --- a/llvm/lib/AsmParser/LLToken.h +++ b/llvm/lib/AsmParser/LLToken.h @@ -52,6 +52,8 @@ namespace lltok { kw_undef, kw_null, kw_none, kw_to, kw_caller, + kw_within, + kw_from, kw_tail, kw_musttail, kw_notail, @@ -182,8 +184,8 @@ namespace lltok { kw_landingpad, kw_personality, kw_cleanup, kw_catch, kw_filter, kw_ret, kw_br, kw_switch, kw_indirectbr, kw_invoke, kw_resume, - kw_unreachable, kw_cleanupret, kw_catchret, kw_catchpad, - kw_terminatepad, kw_cleanuppad, kw_catchendpad, kw_cleanupendpad, + kw_unreachable, kw_cleanupret, kw_catchswitch, kw_catchret, kw_catchpad, + kw_terminatepad, kw_cleanuppad, kw_alloca, kw_load, kw_store, kw_fence, kw_cmpxchg, kw_atomicrmw, kw_getelementptr, diff --git a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp index 4b5af3dd80f..e85cf4d8ebd 100644 --- a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp +++ b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp @@ -42,14 +42,6 @@ enum { SWITCH_INST_MAGIC = 0x4B5 // May 2012 => 1205 => Hex }; -/// Indicates which operator an operand allows (for the few operands that may -/// only reference a certain operator). -enum OperatorConstraint { - OC_None = 0, // No constraint - OC_CatchPad, // Must be CatchPadInst - OC_CleanupPad // Must be CleanupPadInst -}; - class BitcodeReaderValueList { std::vector<WeakVH> ValuePtrs; @@ -93,10 +85,9 @@ public: } Constant *getConstantFwdRef(unsigned Idx, Type *Ty); - Value *getValueFwdRef(unsigned Idx, Type *Ty, - OperatorConstraint OC = OC_None); + Value *getValueFwdRef(unsigned Idx, Type *Ty); - bool assignValue(Value *V, unsigned Idx); + void assignValue(Value *V, unsigned Idx); /// Once all constants are read, this method bulk resolves any forward /// references. @@ -297,11 +288,10 @@ private: StructType *createIdentifiedStructType(LLVMContext &Context); Type *getTypeByID(unsigned ID); - Value *getFnValueByID(unsigned ID, Type *Ty, - OperatorConstraint OC = OC_None) { + Value *getFnValueByID(unsigned ID, Type *Ty) { if (Ty && Ty->isMetadataTy()) return MetadataAsValue::get(Ty->getContext(), getFnMetadataByID(ID)); - return ValueList.getValueFwdRef(ID, Ty, OC); + return ValueList.getValueFwdRef(ID, Ty); } Metadata *getFnMetadataByID(unsigned ID) { return MDValueList.getValueFwdRef(ID); @@ -344,9 +334,8 @@ private: /// past the number of slots used by the value in the record. Return true if /// there is an error. bool popValue(SmallVectorImpl<uint64_t> &Record, unsigned &Slot, - unsigned InstNum, Type *Ty, Value *&ResVal, - OperatorConstraint OC = OC_None) { - if (getValue(Record, Slot, InstNum, Ty, ResVal, OC)) + unsigned InstNum, Type *Ty, Value *&ResVal) { + if (getValue(Record, Slot, InstNum, Ty, ResVal)) return true; // All values currently take a single record slot. ++Slot; @@ -355,34 +344,32 @@ private: /// Like popValue, but does not increment the Slot number. bool getValue(SmallVectorImpl<uint64_t> &Record, unsigned Slot, - unsigned InstNum, Type *Ty, Value *&ResVal, - OperatorConstraint OC = OC_None) { - ResVal = getValue(Record, Slot, InstNum, Ty, OC); + unsigned InstNum, Type *Ty, Value *&ResVal) { + ResVal = getValue(Record, Slot, InstNum, Ty); return ResVal == nullptr; } /// Version of getValue that returns ResVal directly, or 0 if there is an /// error. Value *getValue(SmallVectorImpl<uint64_t> &Record, unsigned Slot, - unsigned InstNum, Type *Ty, OperatorConstraint OC = OC_None) { + unsigned InstNum, Type *Ty) { if (Slot == Record.size()) return nullptr; unsigned ValNo = (unsigned)Record[Slot]; // Adjust the ValNo, if it was encoded relative to the InstNum. if (UseRelativeIDs) ValNo = InstNum - ValNo; - return getFnValueByID(ValNo, Ty, OC); + return getFnValueByID(ValNo, Ty); } /// Like getValue, but decodes signed VBRs. Value *getValueSigned(SmallVectorImpl<uint64_t> &Record, unsigned Slot, - unsigned InstNum, Type *Ty, - OperatorConstraint OC = OC_None) { + unsigned InstNum, Type *Ty) { if (Slot == Record.size()) return nullptr; unsigned ValNo = (unsigned)decodeSignRotatedValue(Record[Slot]); // Adjust the ValNo, if it was encoded relative to the InstNum. if (UseRelativeIDs) ValNo = InstNum - ValNo; - return getFnValueByID(ValNo, Ty, OC); + return getFnValueByID(ValNo, Ty); } /// Converts alignment exponent (i.e. power of two (or zero)) to the @@ -898,10 +885,10 @@ struct OperandTraits<ConstantPlaceHolder> : DEFINE_TRANSPARENT_OPERAND_ACCESSORS(ConstantPlaceHolder, Value) } -bool BitcodeReaderValueList::assignValue(Value *V, unsigned Idx) { +void BitcodeReaderValueList::assignValue(Value *V, unsigned Idx) { if (Idx == size()) { push_back(V); - return false; + return; } if (Idx >= size()) @@ -910,7 +897,7 @@ bool BitcodeReaderValueList::assignValue(Value *V, unsigned Idx) { WeakVH &OldV = ValuePtrs[Idx]; if (!OldV) { OldV = V; - return false; + return; } // Handle constants and non-constants (e.g. instrs) differently for @@ -921,26 +908,11 @@ bool BitcodeReaderValueList::assignValue(Value *V, unsigned Idx) { } else { // If there was a forward reference to this value, replace it. Value *PrevVal = OldV; - // Check operator constraints. We only put cleanuppads or catchpads in - // the forward value map if the value is constrained to match. - if (CatchPadInst *CatchPad = dyn_cast<CatchPadInst>(PrevVal)) { - if (!isa<CatchPadInst>(V)) - return true; - // Delete the dummy basic block that was created with the sentinel - // catchpad. - BasicBlock *DummyBlock = CatchPad->getUnwindDest(); - assert(DummyBlock == CatchPad->getNormalDest()); - CatchPad->dropAllReferences(); - delete DummyBlock; - } else if (isa<CleanupPadInst>(PrevVal)) { - if (!isa<CleanupPadInst>(V)) - return true; - } OldV->replaceAllUsesWith(V); delete PrevVal; } - return false; + return; } @@ -961,8 +933,7 @@ Constant *BitcodeReaderValueList::getConstantFwdRef(unsigned Idx, return C; } -Value *BitcodeReaderValueList::getValueFwdRef(unsigned Idx, Type *Ty, - OperatorConstraint OC) { +Value *BitcodeReaderValueList::getValueFwdRef(unsigned Idx, Type *Ty) { // Bail out for a clearly invalid value. This would make us call resize(0) if (Idx == UINT_MAX) return nullptr; @@ -974,39 +945,14 @@ Value *BitcodeReaderValueList::getValueFwdRef(unsigned Idx, Type *Ty, // If the types don't match, it's invalid. if (Ty && Ty != V->getType()) return nullptr; - if (!OC) - return V; - // Use dyn_cast to enforce operator constraints - switch (OC) { - case OC_CatchPad: - return dyn_cast<CatchPadInst>(V); - case OC_CleanupPad: - return dyn_cast<CleanupPadInst>(V); - default: - llvm_unreachable("Unexpected operator constraint"); - } + return V; } // No type specified, must be invalid reference. if (!Ty) return nullptr; // Create and return a placeholder, which will later be RAUW'd. - Value *V; - switch (OC) { - case OC_None: - V = new Argument(Ty); - break; - case OC_CatchPad: { - BasicBlock *BB = BasicBlock::Create(Context); - V = CatchPadInst::Create(BB, BB, {}); - break; - } - default: - assert(OC == OC_CleanupPad && "unexpected operator constraint"); - V = CleanupPadInst::Create(Context, {}); - break; - } - + Value *V = new Argument(Ty); ValuePtrs[Idx] = V; return V; } @@ -3023,8 +2969,7 @@ std::error_code BitcodeReader::parseConstants() { } } - if (ValueList.assignValue(V, NextCstNo)) - return error("Invalid forward reference"); + ValueList.assignValue(V, NextCstNo); ++NextCstNo; } } @@ -4470,8 +4415,8 @@ std::error_code BitcodeReader::parseFunctionBody(Function *F) { if (Record.size() != 1 && Record.size() != 2) return error("Invalid record"); unsigned Idx = 0; - Value *CleanupPad = getValue(Record, Idx++, NextValueNo, - Type::getTokenTy(Context), OC_CleanupPad); + Value *CleanupPad = + getValue(Record, Idx++, NextValueNo, Type::getTokenTy(Context)); if (!CleanupPad) return error("Invalid record"); BasicBlock *UnwindDest = nullptr; @@ -4481,8 +4426,7 @@ std::error_code BitcodeReader::parseFunctionBody(Function *F) { return error("Invalid record"); } - I = CleanupReturnInst::Create(cast<CleanupPadInst>(CleanupPad), - UnwindDest); + I = CleanupReturnInst::Create(CleanupPad, UnwindDest); InstructionList.push_back(I); break; } @@ -4490,57 +4434,68 @@ std::error_code BitcodeReader::parseFunctionBody(Function *F) { if (Record.size() != 2) return error("Invalid record"); unsigned Idx = 0; - Value *CatchPad = getValue(Record, Idx++, NextValueNo, - Type::getTokenTy(Context), OC_CatchPad); + Value *CatchPad = + getValue(Record, Idx++, NextValueNo, Type::getTokenTy(Context)); if (!CatchPad) return error("Invalid record"); BasicBlock *BB = getBasicBlock(Record[Idx++]); if (!BB) return error("Invalid record"); - I = CatchReturnInst::Create(cast<CatchPadInst>(CatchPad), BB); + I = CatchReturnInst::Create(CatchPad, BB); InstructionList.push_back(I); break; } - case bitc::FUNC_CODE_INST_CATCHPAD: { // CATCHPAD: [bb#,bb#,num,(ty,val)*] - if (Record.size() < 3) + case bitc::FUNC_CODE_INST_CATCHSWITCH: { // CATCHSWITCH: [tok,num,(bb)*,bb?] + // We must have, at minimum, the outer scope and the number of arguments. + if (Record.size() < 2) return error("Invalid record"); + unsigned Idx = 0; - BasicBlock *NormalBB = getBasicBlock(Record[Idx++]); - if (!NormalBB) - return error("Invalid record"); - BasicBlock *UnwindBB = getBasicBlock(Record[Idx++]); - if (!UnwindBB) - return error("Invalid record"); - unsigned NumArgOperands = Record[Idx++]; - SmallVector<Value *, 2> Args; - for (unsigned Op = 0; Op != NumArgOperands; ++Op) { - Value *Val; - if (getValueTypePair(Record, Idx, NextValueNo, Val)) + + Value *ParentPad = + getValue(Record, Idx++, NextValueNo, Type::getTokenTy(Context)); + + unsigned NumHandlers = Record[Idx++]; + + SmallVector<BasicBlock *, 2> Handlers; + for (unsigned Op = 0; Op != NumHandlers; ++Op) { + BasicBlock *BB = getBasicBlock(Record[Idx++]); + if (!BB) + return error("Invalid record"); + Handlers.push_back(BB); + } + + BasicBlock *UnwindDest = nullptr; + if (Idx + 1 == Record.size()) { + UnwindDest = getBasicBlock(Record[Idx++]); + if (!UnwindDest) return error("Invalid record"); - Args.push_back(Val); } + if (Record.size() != Idx) return error("Invalid record"); - I = CatchPadInst::Create(NormalBB, UnwindBB, Args); + auto *CatchSwitch = + CatchSwitchInst::Create(ParentPad, UnwindDest, NumHandlers); + for (BasicBlock *Handler : Handlers) + CatchSwitch->addHandler(Handler); + I = CatchSwitch; InstructionList.push_back(I); break; } - case bitc::FUNC_CODE_INST_TERMINATEPAD: { // TERMINATEPAD: [bb#,num,(ty,val)*] - if (Record.size() < 1) + case bitc::FUNC_CODE_INST_TERMINATEPAD: { // TERMINATEPAD: [tok,bb#,num,(ty,val)*] + // We must have, at minimum, the outer scope and the number of arguments. + if (Record.size() < 2) return error("Invalid record"); + unsigned Idx = 0; - bool HasUnwindDest = !!Record[Idx++]; - BasicBlock *UnwindDest = nullptr; - if (HasUnwindDest) { - if (Idx == Record.size()) - return error("Invalid record"); - UnwindDest = getBasicBlock(Record[Idx++]); - if (!UnwindDest) - return error("Invalid record"); - } + + Value *ParentPad = + getValue(Record, Idx++, NextValueNo, Type::getTokenTy(Context)); + unsigned NumArgOperands = Record[Idx++]; + SmallVector<Value *, 2> Args; for (unsigned Op = 0; Op != NumArgOperands; ++Op) { Value *Val; @@ -4548,18 +4503,34 @@ std::error_code BitcodeReader::parseFunctionBody(Function *F) { return error("Invalid record"); Args.push_back(Val); } + + BasicBlock *UnwindDest = nullptr; + if (Idx + 1 == Record.size()) { + UnwindDest = getBasicBlock(Record[Idx++]); + if (!UnwindDest) + return error("Invalid record"); + } + if (Record.size() != Idx) return error("Invalid record"); - I = TerminatePadInst::Create(Context, UnwindDest, Args); + I = TerminatePadInst::Create(ParentPad, UnwindDest, Args); InstructionList.push_back(I); break; } - case bitc::FUNC_CODE_INST_CLEANUPPAD: { // CLEANUPPAD: [num,(ty,val)*] - if (Record.size() < 1) + case bitc::FUNC_CODE_INST_CATCHPAD: + case bitc::FUNC_CODE_INST_CLEANUPPAD: { // [tok,num,(ty,val)*] + // We must have, at minimum, the outer scope and the number of arguments. + if (Record.size() < 2) return error("Invalid record"); + unsigned Idx = 0; + + Value *ParentPad = + getValue(Record, Idx++, NextValueNo, Type::getTokenTy(Context)); + unsigned NumArgOperands = Record[Idx++]; + SmallVector<Value *, 2> Args; for (unsigned Op = 0; Op != NumArgOperands; ++Op) { Value *Val; @@ -4567,42 +4538,14 @@ std::error_code BitcodeReader::parseFunctionBody(Function *F) { return error("Invalid record"); Args.push_back(Val); } - if (Record.size() != Idx) - return error("Invalid record"); - I = CleanupPadInst::Create(Context, Args); - InstructionList.push_back(I); - break; - } - case bitc::FUNC_CODE_INST_CATCHENDPAD: { // CATCHENDPADINST: [bb#] or [] - if (Record.size() > 1) - return error("Invalid record"); - BasicBlock *BB = nullptr; - if (Record.size() == 1) { - BB = getBasicBlock(Record[0]); - if (!BB) - return error("Invalid record"); - } - I = CatchEndPadInst::Create(Context, BB); - InstructionList.push_back(I); - break; - } - case bitc::FUNC_CODE_INST_CLEANUPENDPAD: { // CLEANUPENDPADINST: [val] or [val,bb#] - if (Record.size() != 1 && Record.size() != 2) - return error("Invalid record"); - unsigned Idx = 0; - Value *CleanupPad = getValue(Record, Idx++, NextValueNo, - Type::getTokenTy(Context), OC_CleanupPad); - if (!CleanupPad) + if (Record.size() != Idx) return error("Invalid record"); - BasicBlock *BB = nullptr; - if (Record.size() == 2) { - BB = getBasicBlock(Record[Idx++]); - if (!BB) - return error("Invalid record"); - } - I = CleanupEndPadInst::Create(cast<CleanupPadInst>(CleanupPad), BB); + if (BitCode == bitc::FUNC_CODE_INST_CLEANUPPAD) + I = CleanupPadInst::Create(ParentPad, Args); + else + I = CatchPadInst::Create(ParentPad, Args); InstructionList.push_back(I); break; } @@ -5224,8 +5167,7 @@ std::error_code BitcodeReader::parseFunctionBody(Function *F) { // Non-void values get registered in the value table for future use. if (I && !I->getType()->isVoidTy()) - if (ValueList.assignValue(I, NextValueNo++)) - return error("Invalid forward reference"); + ValueList.assignValue(I, NextValueNo++); } OutOfRecordLoop: diff --git a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp index 201b4bc34c2..bc6f0edafac 100644 --- a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp +++ b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp @@ -1997,51 +1997,47 @@ static void WriteInstruction(const Instruction &I, unsigned InstID, Vals.push_back(VE.getValueID(CRI.getSuccessor())); break; } + case Instruction::CleanupPad: case Instruction::CatchPad: { - Code = bitc::FUNC_CODE_INST_CATCHPAD; - const auto &CPI = cast<CatchPadInst>(I); - Vals.push_back(VE.getValueID(CPI.getNormalDest())); - Vals.push_back(VE.getValueID(CPI.getUnwindDest())); - unsigned NumArgOperands = CPI.getNumArgOperands(); + const auto &FuncletPad = cast<FuncletPadInst>(I); + Code = isa<CatchPadInst>(FuncletPad) ? bitc::FUNC_CODE_INST_CATCHPAD + : bitc::FUNC_CODE_INST_CLEANUPPAD; + pushValue(FuncletPad.getParentPad(), InstID, Vals, VE); + + unsigned NumArgOperands = FuncletPad.getNumArgOperands(); Vals.push_back(NumArgOperands); for (unsigned Op = 0; Op != NumArgOperands; ++Op) - PushValueAndType(CPI.getArgOperand(Op), InstID, Vals, VE); + PushValueAndType(FuncletPad.getArgOperand(Op), InstID, Vals, VE); + break; + } + case Instruction::CatchSwitch: { + Code = bitc::FUNC_CODE_INST_CATCHSWITCH; + const auto &CatchSwitch = cast<CatchSwitchInst>(I); + + pushValue(CatchSwitch.getParentPad(), InstID, Vals, VE); + + unsigned NumHandlers = CatchSwitch.getNumHandlers(); + Vals.push_back(NumHandlers); + for (const BasicBlock *CatchPadBB : CatchSwitch.handlers()) + Vals.push_back(VE.getValueID(CatchPadBB)); + + if (CatchSwitch.hasUnwindDest()) + Vals.push_back(VE.getValueID(CatchSwitch.getUnwindDest())); break; } case Instruction::TerminatePad: { Code = bitc::FUNC_CODE_INST_TERMINATEPAD; const auto &TPI = cast<TerminatePadInst>(I); - Vals.push_back(TPI.hasUnwindDest()); - if (TPI.hasUnwindDest()) - Vals.push_back(VE.getValueID(TPI.getUnwindDest())); + + pushValue(TPI.getParentPad(), InstID, Vals, VE); + unsigned NumArgOperands = TPI.getNumArgOperands(); Vals.push_back(NumArgOperands); for (unsigned Op = 0; Op != NumArgOperands; ++Op) PushValueAndType(TPI.getArgOperand(Op), InstID, Vals, VE); - break; - } - case Instruction::CleanupPad: { - Code = bitc::FUNC_CODE_INST_CLEANUPPAD; - const auto &CPI = cast<CleanupPadInst>(I); - unsigned NumOperands = CPI.getNumOperands(); - Vals.push_back(NumOperands); - for (unsigned Op = 0; Op != NumOperands; ++Op) - PushValueAndType(CPI.getOperand(Op), InstID, Vals, VE); - break; - } - case Instruction::CatchEndPad: { - Code = bitc::FUNC_CODE_INST_CATCHENDPAD; - const auto &CEPI = cast<CatchEndPadInst>(I); - if (CEPI.hasUnwindDest()) - Vals.push_back(VE.getValueID(CEPI.getUnwindDest())); - break; - } - case Instruction::CleanupEndPad: { - Code = bitc::FUNC_CODE_INST_CLEANUPENDPAD; - const auto &CEPI = cast<CleanupEndPadInst>(I); - pushValue(CEPI.getCleanupPad(), InstID, Vals, VE); - if (CEPI.hasUnwindDest()) - Vals.push_back(VE.getValueID(CEPI.getUnwindDest())); + + if (TPI.hasUnwindDest()) + Vals.push_back(VE.getValueID(TPI.getUnwindDest())); break; } case Instruction::Unreachable: diff --git a/llvm/lib/CodeGen/AsmPrinter/WinException.cpp b/llvm/lib/CodeGen/AsmPrinter/WinException.cpp index cd1f3f51bc4..e2994172415 100644 --- a/llvm/lib/CodeGen/AsmPrinter/WinException.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/WinException.cpp @@ -344,42 +344,32 @@ class InvokeStateChangeIterator { InvokeStateChangeIterator(const WinEHFuncInfo &EHInfo, MachineFunction::const_iterator MFI, MachineFunction::const_iterator MFE, - MachineBasicBlock::const_iterator MBBI) - : EHInfo(EHInfo), MFI(MFI), MFE(MFE), MBBI(MBBI) { + MachineBasicBlock::const_iterator MBBI, + int BaseState) + : EHInfo(EHInfo), MFI(MFI), MFE(MFE), MBBI(MBBI), BaseState(BaseState) { LastStateChange.PreviousEndLabel = nullptr; LastStateChange.NewStartLabel = nullptr; - LastStateChange.NewState = NullState; + LastStateChange.NewState = BaseState; scan(); } public: static iterator_range<InvokeStateChangeIterator> - range(const WinEHFuncInfo &EHInfo, const MachineFunction &MF) { - // Reject empty MFs to simplify bookkeeping by ensuring that we can get the - // end of the last block. - assert(!MF.empty()); - auto FuncBegin = MF.begin(); - auto FuncEnd = MF.end(); - auto BlockBegin = FuncBegin->begin(); - auto BlockEnd = MF.back().end(); - return make_range( - InvokeStateChangeIterator(EHInfo, FuncBegin, FuncEnd, BlockBegin), - InvokeStateChangeIterator(EHInfo, FuncEnd, FuncEnd, BlockEnd)); - } - static iterator_range<InvokeStateChangeIterator> range(const WinEHFuncInfo &EHInfo, MachineFunction::const_iterator Begin, - MachineFunction::const_iterator End) { + MachineFunction::const_iterator End, int BaseState = NullState) { // Reject empty ranges to simplify bookkeeping by ensuring that we can get // the end of the last block. assert(Begin != End); auto BlockBegin = Begin->begin(); auto BlockEnd = std::prev(End)->end(); - return make_range(InvokeStateChangeIterator(EHInfo, Begin, End, BlockBegin), - InvokeStateChangeIterator(EHInfo, End, End, BlockEnd)); + return make_range( + InvokeStateChangeIterator(EHInfo, Begin, End, BlockBegin, BaseState), + InvokeStateChangeIterator(EHInfo, End, End, BlockEnd, BaseState)); } // Iterator methods. bool operator==(const InvokeStateChangeIterator &O) const { + assert(BaseState == O.BaseState); // Must be visiting same block. if (MFI != O.MFI) return false; @@ -410,6 +400,7 @@ private: MachineBasicBlock::const_iterator MBBI; InvokeStateChange LastStateChange; bool VisitingInvoke = false; + int BaseState; }; } // end anonymous namespace @@ -421,14 +412,14 @@ InvokeStateChangeIterator &InvokeStateChangeIterator::scan() { MBBI = MFI->begin(); for (auto MBBE = MFI->end(); MBBI != MBBE; ++MBBI) { const MachineInstr &MI = *MBBI; - if (!VisitingInvoke && LastStateChange.NewState != NullState && + if (!VisitingInvoke && LastStateChange.NewState != BaseState && MI.isCall() && !EHStreamer::callToNoUnwindFunction(&MI)) { // Indicate a change of state to the null state. We don't have // start/end EH labels handy but the caller won't expect them for // null state regions. LastStateChange.PreviousEndLabel = CurrentEndLabel; LastStateChange.NewStartLabel = nullptr; - LastStateChange.NewState = NullState; + LastStateChange.NewState = BaseState; CurrentEndLabel = nullptr; // Don't re-visit this instr on the next scan ++MBBI; @@ -443,18 +434,12 @@ InvokeStateChangeIterator &InvokeStateChangeIterator::scan() { VisitingInvoke = false; continue; } - auto InvokeMapIter = EHInfo.InvokeToStateMap.find(Label); + auto InvokeMapIter = EHInfo.LabelToStateMap.find(Label); // Ignore EH labels that aren't the ones inserted before an invoke - if (InvokeMapIter == EHInfo.InvokeToStateMap.end()) + if (InvokeMapIter == EHInfo.LabelToStateMap.end()) continue; auto &StateAndEnd = InvokeMapIter->second; int NewState = StateAndEnd.first; - // Ignore EH labels explicitly annotated with the null state (which - // can happen for invokes that unwind to a chain of endpads the last - // of which unwinds to caller). We'll see the subsequent invoke and - // report a transition to the null state same as we do for calls. - if (NewState == NullState) - continue; // Keep track of the fact that we're between EH start/end labels so // we know not to treat the inoke we'll see as unwinding to caller. VisitingInvoke = true; @@ -476,11 +461,11 @@ InvokeStateChangeIterator &InvokeStateChangeIterator::scan() { } } // Iteration hit the end of the block range. - if (LastStateChange.NewState != NullState) { + if (LastStateChange.NewState != BaseState) { // Report the end of the last new state LastStateChange.PreviousEndLabel = CurrentEndLabel; LastStateChange.NewStartLabel = nullptr; - LastStateChange.NewState = NullState; + LastStateChange.NewState = BaseState; // Leave CurrentEndLabel non-null to distinguish this state from end. assert(CurrentEndLabel != nullptr); return *this; @@ -775,26 +760,54 @@ void WinException::emitCXXFrameHandler3Table(const MachineFunction *MF) { void WinException::computeIP2StateTable( const MachineFunction *MF, const WinEHFuncInfo &FuncInfo, SmallVectorImpl<std::pair<const MCExpr *, int>> &IPToStateTable) { - // Indicate that all calls from the prologue to the first invoke unwind to - // caller. We handle this as a special case since other ranges starting at end - // labels need to use LtmpN+1. - MCSymbol *StartLabel = Asm->getFunctionBegin(); - assert(StartLabel && "need local function start label"); - IPToStateTable.push_back(std::make_pair(create32bitRef(StartLabel), -1)); - - // FIXME: Do we need to emit entries for funclet base states? - for (const auto &StateChange : - InvokeStateChangeIterator::range(FuncInfo, *MF)) { - // Compute the label to report as the start of this entry; use the EH start - // label for the invoke if we have one, otherwise (this is a call which may - // unwind to our caller and does not have an EH start label, so) use the - // previous end label. - const MCSymbol *ChangeLabel = StateChange.NewStartLabel; - if (!ChangeLabel) - ChangeLabel = StateChange.PreviousEndLabel; - // Emit an entry indicating that PCs after 'Label' have this EH state. + + for (MachineFunction::const_iterator FuncletStart = MF->begin(), + FuncletEnd = MF->begin(), + End = MF->end(); + FuncletStart != End; FuncletStart = FuncletEnd) { + // Find the end of the funclet + while (++FuncletEnd != End) { + if (FuncletEnd->isEHFuncletEntry()) { + break; + } + } + + // Don't emit ip2state entries for cleanup funclets. Any interesting + // exceptional actions in cleanups must be handled in a separate IR + // function. + if (FuncletStart->isCleanupFuncletEntry()) + continue; + + MCSymbol *StartLabel; + int BaseState; + if (FuncletStart == MF->begin()) { + BaseState = NullState; + StartLabel = Asm->getFunctionBegin(); + } else { + auto *FuncletPad = + cast<FuncletPadInst>(FuncletStart->getBasicBlock()->getFirstNonPHI()); + assert(FuncInfo.FuncletBaseStateMap.count(FuncletPad) != 0); + BaseState = FuncInfo.FuncletBaseStateMap.find(FuncletPad)->second; + StartLabel = getMCSymbolForMBB(Asm, &*FuncletStart); + } + assert(StartLabel && "need local function start label"); IPToStateTable.push_back( - std::make_pair(getLabelPlusOne(ChangeLabel), StateChange.NewState)); + std::make_pair(create32bitRef(StartLabel), BaseState)); + + for (const auto &StateChange : InvokeStateChangeIterator::range( + FuncInfo, FuncletStart, FuncletEnd, BaseState)) { + // Compute the label to report as the start of this entry; use the EH + // start label for the invoke if we have one, otherwise (this is a call + // which may unwind to our caller and does not have an EH start label, so) + // use the previous end label. + const MCSymbol *ChangeLabel = StateChange.NewStartLabel; + if (!ChangeLabel) + ChangeLabel = StateChange.PreviousEndLabel; + // Emit an entry indicating that PCs after 'Label' have this EH state. + IPToStateTable.push_back( + std::make_pair(getLabelPlusOne(ChangeLabel), StateChange.NewState)); + // FIXME: assert that NewState is between CatchLow and CatchHigh. + } } } diff --git a/llvm/lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp b/llvm/lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp index ff0ccd415db..6ae38d3258d 100644 --- a/llvm/lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp @@ -225,12 +225,12 @@ void FunctionLoweringInfo::set(const Function &fn, MachineFunction &mf, MMI.setHasEHFunclets(true); MF->getFrameInfo()->setHasOpaqueSPAdjustment(true); } - if (isa<CatchEndPadInst>(I) || isa<CleanupEndPadInst>(I)) { + if (isa<CatchSwitchInst>(I)) { assert(&*BB->begin() == I && "WinEHPrepare failed to remove PHIs from imaginary BBs"); continue; } - if (isa<CatchPadInst>(I) || isa<CleanupPadInst>(I)) + if (isa<FuncletPadInst>(I)) assert(&*BB->begin() == I && "WinEHPrepare failed to demote PHIs"); } diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp index dc2a57a860f..506115c7856 100644 --- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp @@ -1184,21 +1184,7 @@ void SelectionDAGBuilder::visitCatchPad(const CatchPadInst &I) { if (IsMSVCCXX || IsCoreCLR) CatchPadMBB->setIsEHFuncletEntry(); - MachineBasicBlock *NormalDestMBB = FuncInfo.MBBMap[I.getNormalDest()]; - - // Update machine-CFG edge. - FuncInfo.MBB->addSuccessor(NormalDestMBB); - - SDValue Chain = - DAG.getNode(ISD::CATCHPAD, getCurSDLoc(), MVT::Other, getControlRoot()); - - // If this is not a fall-through branch or optimizations are switched off, - // emit the branch. - if (NormalDestMBB != NextBlock(CatchPadMBB) || - TM.getOptLevel() == CodeGenOpt::None) - Chain = DAG.getNode(ISD::BR, getCurSDLoc(), MVT::Other, Chain, - DAG.getBasicBlock(NormalDestMBB)); - DAG.setRoot(Chain); + DAG.setRoot(DAG.getNode(ISD::CATCHPAD, getCurSDLoc(), MVT::Other, getControlRoot())); } void SelectionDAGBuilder::visitCatchRet(const CatchReturnInst &I) { @@ -1234,10 +1220,6 @@ void SelectionDAGBuilder::visitCatchRet(const CatchReturnInst &I) { DAG.setRoot(Ret); } -void SelectionDAGBuilder::visitCatchEndPad(const CatchEndPadInst &I) { - llvm_unreachable("should never codegen catchendpads"); -} - void SelectionDAGBuilder::visitCleanupPad(const CleanupPadInst &CPI) { // Don't emit any special code for the cleanuppad instruction. It just marks // the start of a funclet. @@ -1248,8 +1230,8 @@ void SelectionDAGBuilder::visitCleanupPad(const CleanupPadInst &CPI) { /// 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 +/// This function skips over imaginary basic blocks that hold catchswitch or +/// terminatepad instructions, and finds all the "real" machine /// basic block destinations. As those destinations may not be successors of /// EHPadBB, here we also calculate the edge probability to those destinations. /// The passed-in Prob is the edge probability to EHPadBB. @@ -1276,19 +1258,18 @@ static void findUnwindDestinations( UnwindDests.emplace_back(FuncInfo.MBBMap[EHPadBB], Prob); UnwindDests.back().first->setIsEHFuncletEntry(); break; - } else if (const auto *CPI = dyn_cast<CatchPadInst>(Pad)) { - // Add the catchpad handler to the possible destinations. - UnwindDests.emplace_back(FuncInfo.MBBMap[EHPadBB], Prob); - // In MSVC C++, catchblocks are funclets and need prologues. - if (IsMSVCCXX || IsCoreCLR) - UnwindDests.back().first->setIsEHFuncletEntry(); - NewEHPadBB = CPI->getUnwindDest(); - } else if (const auto *CEPI = dyn_cast<CatchEndPadInst>(Pad)) - NewEHPadBB = CEPI->getUnwindDest(); - else if (const auto *CEPI = dyn_cast<CleanupEndPadInst>(Pad)) - NewEHPadBB = CEPI->getUnwindDest(); - else + } else if (auto *CatchSwitch = dyn_cast<CatchSwitchInst>(Pad)) { + // Add the catchpad handlers to the possible destinations. + for (const BasicBlock *CatchPadBB : CatchSwitch->handlers()) { + UnwindDests.emplace_back(FuncInfo.MBBMap[CatchPadBB], Prob); + // For MSVC++ and the CLR, catchblocks are funclets and need prologues. + if (IsMSVCCXX || IsCoreCLR) + UnwindDests.back().first->setIsEHFuncletEntry(); + } + NewEHPadBB = CatchSwitch->getUnwindDest(); + } else { continue; + } BranchProbabilityInfo *BPI = FuncInfo.BPI; if (BPI && NewEHPadBB) @@ -1319,14 +1300,14 @@ void SelectionDAGBuilder::visitCleanupRet(const CleanupReturnInst &I) { DAG.setRoot(Ret); } -void SelectionDAGBuilder::visitCleanupEndPad(const CleanupEndPadInst &I) { - report_fatal_error("visitCleanupEndPad not yet implemented!"); -} - void SelectionDAGBuilder::visitTerminatePad(const TerminatePadInst &TPI) { report_fatal_error("visitTerminatePad not yet implemented!"); } +void SelectionDAGBuilder::visitCatchSwitch(const CatchSwitchInst &CSI) { + report_fatal_error("visitCatchSwitch not yet implemented!"); +} + void SelectionDAGBuilder::visitRet(const ReturnInst &I) { const TargetLowering &TLI = DAG.getTargetLoweringInfo(); auto &DL = DAG.getDataLayout(); @@ -2124,8 +2105,8 @@ void SelectionDAGBuilder::visitBitTestCase(BitTestBlock &BB, void SelectionDAGBuilder::visitInvoke(const InvokeInst &I) { MachineBasicBlock *InvokeMBB = FuncInfo.MBB; - // Retrieve successors. Look through artificial IR level blocks like catchpads - // and catchendpads for successors. + // Retrieve successors. Look through artificial IR level blocks like + // catchswitch for successors. MachineBasicBlock *Return = FuncInfo.MBBMap[I.getSuccessor(0)]; const BasicBlock *EHPadBB = I.getSuccessor(1); @@ -5367,8 +5348,10 @@ SelectionDAGBuilder::lowerInvokable(TargetLowering::CallLoweringInfo &CLI, // Inform MachineModuleInfo of range. if (MMI.hasEHFunclets()) { + assert(CLI.CS); WinEHFuncInfo *EHInfo = DAG.getMachineFunction().getWinEHFuncInfo(); - EHInfo->addIPToStateRange(EHPadBB, BeginLabel, EndLabel); + EHInfo->addIPToStateRange(cast<InvokeInst>(CLI.CS->getInstruction()), + BeginLabel, EndLabel); } else { MMI.addInvoke(FuncInfo.MBBMap[EHPadBB], BeginLabel, EndLabel); } diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.h b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.h index 1171f0aad00..4f8e8132c4a 100644 --- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.h +++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.h @@ -736,9 +736,8 @@ private: void visitSwitch(const SwitchInst &I); void visitIndirectBr(const IndirectBrInst &I); void visitUnreachable(const UnreachableInst &I); - void visitCleanupEndPad(const CleanupEndPadInst &I); void visitCleanupRet(const CleanupReturnInst &I); - void visitCatchEndPad(const CatchEndPadInst &I); + void visitCatchSwitch(const CatchSwitchInst &I); void visitCatchRet(const CatchReturnInst &I); void visitCatchPad(const CatchPadInst &I); void visitTerminatePad(const TerminatePadInst &TPI); diff --git a/llvm/lib/CodeGen/TargetLoweringBase.cpp b/llvm/lib/CodeGen/TargetLoweringBase.cpp index c5972263046..74a42f8ee34 100644 --- a/llvm/lib/CodeGen/TargetLoweringBase.cpp +++ b/llvm/lib/CodeGen/TargetLoweringBase.cpp @@ -1570,13 +1570,12 @@ int TargetLoweringBase::InstructionOpcodeToISD(unsigned Opcode) const { case Invoke: return 0; case Resume: return 0; case Unreachable: return 0; - case CleanupEndPad: return 0; case CleanupRet: return 0; - case CatchEndPad: return 0; case CatchRet: return 0; - case CatchPad: return 0; - case TerminatePad: return 0; - case CleanupPad: return 0; + case CatchPad: return 0; + case CatchSwitch: return 0; + case TerminatePad: return 0; + case CleanupPad: return 0; case Add: return ISD::ADD; case FAdd: return ISD::FADD; case Sub: return ISD::SUB; diff --git a/llvm/lib/CodeGen/WinEHPrepare.cpp b/llvm/lib/CodeGen/WinEHPrepare.cpp index dee4b870434..9f199a15718 100644 --- a/llvm/lib/CodeGen/WinEHPrepare.cpp +++ b/llvm/lib/CodeGen/WinEHPrepare.cpp @@ -17,7 +17,7 @@ //===----------------------------------------------------------------------===// #include "llvm/CodeGen/Passes.h" -#include "llvm/ADT/SetVector.h" +#include "llvm/ADT/MapVector.h" #include "llvm/Analysis/CFG.h" #include "llvm/Analysis/EHPersonalities.h" #include "llvm/CodeGen/WinEHFuncInfo.h" @@ -69,27 +69,12 @@ private: AllocaInst *insertPHILoads(PHINode *PN, Function &F); void replaceUseWithLoad(Value *V, Use &U, AllocaInst *&SpillSlot, DenseMap<BasicBlock *, Value *> &Loads, Function &F); - bool prepareExplicitEH(Function &F, - SmallVectorImpl<BasicBlock *> &EntryBlocks); + bool prepareExplicitEH(Function &F); void replaceTerminatePadWithCleanup(Function &F); - void colorFunclets(Function &F, SmallVectorImpl<BasicBlock *> &EntryBlocks); - void resolveFuncletAncestry(Function &F, - SmallVectorImpl<BasicBlock *> &EntryBlocks); - void resolveFuncletAncestryForPath( - Function &F, SmallVectorImpl<BasicBlock *> &FuncletPath, - std::map<BasicBlock *, BasicBlock *> &IdentityMap); - void makeFuncletEdgeUnreachable(BasicBlock *Parent, BasicBlock *Child); - BasicBlock *cloneFuncletForParent(Function &F, BasicBlock *FuncletEntry, - BasicBlock *Parent); - void updateTerminatorsAfterFuncletClone( - Function &F, BasicBlock *OrigFunclet, BasicBlock *CloneFunclet, - BasicBlock *OrigBlock, BasicBlock *CloneBlock, BasicBlock *CloneParent, - ValueToValueMapTy &VMap, - std::map<BasicBlock *, BasicBlock *> &Orig2Clone); + void colorFunclets(Function &F); void demotePHIsOnFunclets(Function &F); - void cloneCommonBlocks(Function &F, - SmallVectorImpl<BasicBlock *> &EntryBlocks); + void cloneCommonBlocks(Function &F); void removeImplausibleTerminators(Function &F); void cleanupPreparedFunclets(Function &F); void verifyPreparedFunclets(Function &F); @@ -97,20 +82,8 @@ private: // All fields are reset by runOnFunction. EHPersonality Personality = EHPersonality::Unknown; - std::map<BasicBlock *, SetVector<BasicBlock *>> BlockColors; - std::map<BasicBlock *, std::set<BasicBlock *>> FuncletBlocks; - std::map<BasicBlock *, std::vector<BasicBlock *>> FuncletChildren; - std::map<BasicBlock *, std::vector<BasicBlock *>> FuncletParents; - - // This is a flag that indicates an uncommon situation where we need to - // clone funclets has been detected. - bool FuncletCloningRequired = false; - // When a funclet with multiple parents contains a catchret, the block to - // which it returns will be cloned so that there is a copy in each parent - // but one of the copies will not be properly linked to the catchret and - // in most cases will have no predecessors. This double map allows us - // to find these cloned blocks when we clone the child funclet. - std::map<BasicBlock *, std::map<BasicBlock *, BasicBlock*>> EstrangedBlocks; + DenseMap<BasicBlock *, ColorVector> BlockColors; + MapVector<BasicBlock *, std::vector<BasicBlock *>> FuncletBlocks; }; } // end anonymous namespace @@ -123,21 +96,6 @@ FunctionPass *llvm::createWinEHPass(const TargetMachine *TM) { return new WinEHPrepare(TM); } -static void findFuncletEntryPoints(Function &Fn, - SmallVectorImpl<BasicBlock *> &EntryBlocks) { - EntryBlocks.push_back(&Fn.getEntryBlock()); - for (BasicBlock &BB : Fn) { - Instruction *First = BB.getFirstNonPHI(); - if (!First->isEHPad()) - continue; - assert(!isa<LandingPadInst>(First) && - "landingpad cannot be used with funclet EH personality"); - // Find EH pad blocks that represent funclet start points. - if (!isa<CatchEndPadInst>(First) && !isa<CleanupEndPadInst>(First)) - EntryBlocks.push_back(&BB); - } -} - bool WinEHPrepare::runOnFunction(Function &Fn) { if (!Fn.hasPersonalityFn()) return false; @@ -149,14 +107,7 @@ bool WinEHPrepare::runOnFunction(Function &Fn) { if (!isFuncletEHPersonality(Personality)) return false; - // Remove unreachable blocks. It is not valuable to assign them a color and - // their existence can trick us into thinking values are alive when they are - // not. - removeUnreachableBlocks(Fn); - - SmallVector<BasicBlock *, 4> EntryBlocks; - findFuncletEntryPoints(Fn, EntryBlocks); - return prepareExplicitEH(Fn, EntryBlocks); + return prepareExplicitEH(Fn); } bool WinEHPrepare::doFinalization(Module &M) { return false; } @@ -198,117 +149,142 @@ static void addTryBlockMapEntry(WinEHFuncInfo &FuncInfo, int TryLow, FuncInfo.TryBlockMap.push_back(TBME); } -static const CatchPadInst *getSingleCatchPadPredecessor(const BasicBlock *BB) { - for (const BasicBlock *PredBlock : predecessors(BB)) - if (auto *CPI = dyn_cast<CatchPadInst>(PredBlock->getFirstNonPHI())) - return CPI; +static BasicBlock *getCleanupRetUnwindDest(const CleanupPadInst *CleanupPad) { + for (const User *U : CleanupPad->users()) + if (const auto *CRI = dyn_cast<CleanupReturnInst>(U)) + return CRI->getUnwindDest(); return nullptr; } -/// Find all the catchpads that feed directly into the catchendpad. Frontends -/// using this personality should ensure that each catchendpad and catchpad has -/// one or zero catchpad predecessors. -/// -/// The following C++ generates the IR after it: -/// try { -/// } catch (A) { -/// } catch (B) { -/// } -/// -/// IR: -/// %catchpad.A -/// catchpad [i8* A typeinfo] -/// to label %catch.A unwind label %catchpad.B -/// %catchpad.B -/// catchpad [i8* B typeinfo] -/// to label %catch.B unwind label %endcatches -/// %endcatches -/// catchendblock unwind to caller -static void -findCatchPadsForCatchEndPad(const BasicBlock *CatchEndBB, - SmallVectorImpl<const CatchPadInst *> &Handlers) { - const CatchPadInst *CPI = getSingleCatchPadPredecessor(CatchEndBB); - while (CPI) { - Handlers.push_back(CPI); - CPI = getSingleCatchPadPredecessor(CPI->getParent()); +static void calculateStateNumbersForInvokes(const Function *Fn, + WinEHFuncInfo &FuncInfo) { + auto *F = const_cast<Function *>(Fn); + DenseMap<BasicBlock *, ColorVector> BlockColors = colorEHFunclets(*F); + for (BasicBlock &BB : *F) { + auto *II = dyn_cast<InvokeInst>(BB.getTerminator()); + if (!II) + continue; + + auto &BBColors = BlockColors[&BB]; + assert(BBColors.size() == 1 && + "multi-color BB not removed by preparation"); + BasicBlock *FuncletEntryBB = BBColors.front(); + + BasicBlock *FuncletUnwindDest; + auto *FuncletPad = + dyn_cast<FuncletPadInst>(FuncletEntryBB->getFirstNonPHI()); + assert(FuncletPad || FuncletEntryBB == &Fn->getEntryBlock()); + if (!FuncletPad) + FuncletUnwindDest = nullptr; + else if (auto *CatchPad = dyn_cast<CatchPadInst>(FuncletPad)) + FuncletUnwindDest = CatchPad->getCatchSwitch()->getUnwindDest(); + else if (auto *CleanupPad = dyn_cast<CleanupPadInst>(FuncletPad)) + FuncletUnwindDest = getCleanupRetUnwindDest(CleanupPad); + else + llvm_unreachable("unexpected funclet pad!"); + + BasicBlock *InvokeUnwindDest = II->getUnwindDest(); + int BaseState = -1; + if (FuncletUnwindDest == InvokeUnwindDest) { + auto BaseStateI = FuncInfo.FuncletBaseStateMap.find(FuncletPad); + if (BaseStateI != FuncInfo.FuncletBaseStateMap.end()) + BaseState = BaseStateI->second; + } + + if (BaseState != -1) { + FuncInfo.InvokeStateMap[II] = BaseState; + } else { + Instruction *PadInst = InvokeUnwindDest->getFirstNonPHI(); + assert(FuncInfo.EHPadStateMap.count(PadInst) && "EH Pad has no state!"); + FuncInfo.InvokeStateMap[II] = FuncInfo.EHPadStateMap[PadInst]; + } } - // We've pushed these back into reverse source order. Reverse them to get - // the list back into source order. - std::reverse(Handlers.begin(), Handlers.end()); } // Given BB which ends in an unwind edge, return the EHPad that this BB belongs // to. If the unwind edge came from an invoke, return null. -static const BasicBlock *getEHPadFromPredecessor(const BasicBlock *BB) { +static const BasicBlock *getEHPadFromPredecessor(const BasicBlock *BB, + Value *ParentPad) { const TerminatorInst *TI = BB->getTerminator(); if (isa<InvokeInst>(TI)) return nullptr; - if (TI->isEHPad()) + if (auto *CatchSwitch = dyn_cast<CatchSwitchInst>(TI)) { + if (CatchSwitch->getParentPad() != ParentPad) + return nullptr; return BB; - return cast<CleanupReturnInst>(TI)->getCleanupPad()->getParent(); + } + assert(!TI->isEHPad() && "unexpected EHPad!"); + auto *CleanupPad = cast<CleanupReturnInst>(TI)->getCleanupPad(); + if (CleanupPad->getParentPad() != ParentPad) + return nullptr; + return CleanupPad->getParent(); } -static void calculateExplicitCXXStateNumbers(WinEHFuncInfo &FuncInfo, - const BasicBlock &BB, - int ParentState) { - assert(BB.isEHPad()); - const Instruction *FirstNonPHI = BB.getFirstNonPHI(); - // All catchpad instructions will be handled when we process their - // respective catchendpad instruction. - if (isa<CatchPadInst>(FirstNonPHI)) - return; +static void calculateCXXStateNumbers(WinEHFuncInfo &FuncInfo, + const Instruction *FirstNonPHI, + int ParentState) { + const BasicBlock *BB = FirstNonPHI->getParent(); + assert(BB->isEHPad() && "not a funclet!"); + + if (auto *CatchSwitch = dyn_cast<CatchSwitchInst>(FirstNonPHI)) { + assert(FuncInfo.EHPadStateMap.count(CatchSwitch) == 0 && + "shouldn't revist catch funclets!"); - if (isa<CatchEndPadInst>(FirstNonPHI)) { SmallVector<const CatchPadInst *, 2> Handlers; - findCatchPadsForCatchEndPad(&BB, Handlers); - const BasicBlock *FirstTryPad = Handlers.front()->getParent(); + for (const BasicBlock *CatchPadBB : CatchSwitch->handlers()) { + auto *CatchPad = cast<CatchPadInst>(CatchPadBB->getFirstNonPHI()); + Handlers.push_back(CatchPad); + } int TryLow = addUnwindMapEntry(FuncInfo, ParentState, nullptr); - FuncInfo.EHPadStateMap[Handlers.front()] = TryLow; - for (const BasicBlock *PredBlock : predecessors(FirstTryPad)) - if ((PredBlock = getEHPadFromPredecessor(PredBlock))) - calculateExplicitCXXStateNumbers(FuncInfo, *PredBlock, TryLow); + FuncInfo.EHPadStateMap[CatchSwitch] = TryLow; + for (const BasicBlock *PredBlock : predecessors(BB)) + if ((PredBlock = getEHPadFromPredecessor(PredBlock, + CatchSwitch->getParentPad()))) + calculateCXXStateNumbers(FuncInfo, PredBlock->getFirstNonPHI(), + TryLow); int CatchLow = addUnwindMapEntry(FuncInfo, ParentState, nullptr); // catchpads are separate funclets in C++ EH due to the way rethrow works. - // In SEH, they aren't, so no invokes will unwind to the catchendpad. - FuncInfo.EHPadStateMap[FirstNonPHI] = CatchLow; int TryHigh = CatchLow - 1; - for (const BasicBlock *PredBlock : predecessors(&BB)) - if ((PredBlock = getEHPadFromPredecessor(PredBlock))) - calculateExplicitCXXStateNumbers(FuncInfo, *PredBlock, CatchLow); + for (const auto *CatchPad : Handlers) { + FuncInfo.FuncletBaseStateMap[CatchPad] = CatchLow; + for (const User *U : CatchPad->users()) { + const auto *UserI = cast<Instruction>(U); + if (UserI->isEHPad()) + calculateCXXStateNumbers(FuncInfo, UserI, CatchLow); + } + } int CatchHigh = FuncInfo.getLastStateNumber(); addTryBlockMapEntry(FuncInfo, TryLow, TryHigh, CatchHigh, Handlers); - DEBUG(dbgs() << "TryLow[" << FirstTryPad->getName() << "]: " << TryLow + DEBUG(dbgs() << "TryLow[" << BB->getName() << "]: " << TryLow << '\n'); + DEBUG(dbgs() << "TryHigh[" << BB->getName() << "]: " << TryHigh << '\n'); + DEBUG(dbgs() << "CatchHigh[" << BB->getName() << "]: " << CatchHigh << '\n'); - DEBUG(dbgs() << "TryHigh[" << FirstTryPad->getName() << "]: " << TryHigh - << '\n'); - DEBUG(dbgs() << "CatchHigh[" << FirstTryPad->getName() << "]: " << CatchHigh - << '\n'); - } else if (isa<CleanupPadInst>(FirstNonPHI)) { - // A cleanup can have multiple exits; don't re-process after the first. - if (FuncInfo.EHPadStateMap.count(FirstNonPHI)) + } else { + auto *CleanupPad = cast<CleanupPadInst>(FirstNonPHI); + + // It's possible for a cleanup to be visited twice: it might have multiple + // cleanupret instructions. + if (FuncInfo.EHPadStateMap.count(CleanupPad)) return; - int CleanupState = addUnwindMapEntry(FuncInfo, ParentState, &BB); - FuncInfo.EHPadStateMap[FirstNonPHI] = CleanupState; + + int CleanupState = addUnwindMapEntry(FuncInfo, ParentState, BB); + FuncInfo.EHPadStateMap[CleanupPad] = CleanupState; DEBUG(dbgs() << "Assigning state #" << CleanupState << " to BB " - << BB.getName() << '\n'); - for (const BasicBlock *PredBlock : predecessors(&BB)) - if ((PredBlock = getEHPadFromPredecessor(PredBlock))) - calculateExplicitCXXStateNumbers(FuncInfo, *PredBlock, CleanupState); - } else if (auto *CEPI = dyn_cast<CleanupEndPadInst>(FirstNonPHI)) { - // Propagate ParentState to the cleanuppad in case it doesn't have - // any cleanuprets. - BasicBlock *CleanupBlock = CEPI->getCleanupPad()->getParent(); - calculateExplicitCXXStateNumbers(FuncInfo, *CleanupBlock, ParentState); - // Anything unwinding through CleanupEndPadInst is in ParentState. - FuncInfo.EHPadStateMap[FirstNonPHI] = ParentState; - for (const BasicBlock *PredBlock : predecessors(&BB)) - if ((PredBlock = getEHPadFromPredecessor(PredBlock))) - calculateExplicitCXXStateNumbers(FuncInfo, *PredBlock, ParentState); - } else if (isa<TerminatePadInst>(FirstNonPHI)) { - report_fatal_error("Not yet implemented!"); - } else { - llvm_unreachable("unexpected EH Pad!"); + << BB->getName() << '\n'); + for (const BasicBlock *PredBlock : predecessors(BB)) { + if ((PredBlock = getEHPadFromPredecessor(PredBlock, + CleanupPad->getParentPad()))) { + calculateCXXStateNumbers(FuncInfo, PredBlock->getFirstNonPHI(), + CleanupState); + } + } + for (const User *U : CleanupPad->users()) { + const auto *UserI = cast<Instruction>(U); + if (UserI->isEHPad()) + report_fatal_error("Cleanup funclets for the MSVC++ personality cannot " + "contain exceptional actions"); + } } } @@ -334,94 +310,84 @@ static int addSEHFinally(WinEHFuncInfo &FuncInfo, int ParentState, return FuncInfo.SEHUnwindMap.size() - 1; } -static void calculateExplicitSEHStateNumbers(WinEHFuncInfo &FuncInfo, - const BasicBlock &BB, - int ParentState) { - assert(BB.isEHPad()); - const Instruction *FirstNonPHI = BB.getFirstNonPHI(); - // All catchpad instructions will be handled when we process their - // respective catchendpad instruction. - if (isa<CatchPadInst>(FirstNonPHI)) - return; +static void calculateSEHStateNumbers(WinEHFuncInfo &FuncInfo, + const Instruction *FirstNonPHI, + int ParentState) { + const BasicBlock *BB = FirstNonPHI->getParent(); + assert(BB->isEHPad() && "no a funclet!"); + + if (auto *CatchSwitch = dyn_cast<CatchSwitchInst>(FirstNonPHI)) { + assert(FuncInfo.EHPadStateMap.count(CatchSwitch) == 0 && + "shouldn't revist catch funclets!"); - if (isa<CatchEndPadInst>(FirstNonPHI)) { // Extract the filter function and the __except basic block and create a // state for them. - SmallVector<const CatchPadInst *, 1> Handlers; - findCatchPadsForCatchEndPad(&BB, Handlers); - assert(Handlers.size() == 1 && + assert(CatchSwitch->getNumHandlers() == 1 && "SEH doesn't have multiple handlers per __try"); - const CatchPadInst *CPI = Handlers.front(); - const BasicBlock *CatchPadBB = CPI->getParent(); + const auto *CatchPad = + cast<CatchPadInst>((*CatchSwitch->handler_begin())->getFirstNonPHI()); + const BasicBlock *CatchPadBB = CatchPad->getParent(); const Constant *FilterOrNull = - cast<Constant>(CPI->getArgOperand(0)->stripPointerCasts()); + cast<Constant>(CatchPad->getArgOperand(0)->stripPointerCasts()); const Function *Filter = dyn_cast<Function>(FilterOrNull); assert((Filter || FilterOrNull->isNullValue()) && "unexpected filter value"); int TryState = addSEHExcept(FuncInfo, ParentState, Filter, CatchPadBB); // Everything in the __try block uses TryState as its parent state. - FuncInfo.EHPadStateMap[CPI] = TryState; + FuncInfo.EHPadStateMap[CatchSwitch] = TryState; DEBUG(dbgs() << "Assigning state #" << TryState << " to BB " << CatchPadBB->getName() << '\n'); - for (const BasicBlock *PredBlock : predecessors(CatchPadBB)) - if ((PredBlock = getEHPadFromPredecessor(PredBlock))) - calculateExplicitSEHStateNumbers(FuncInfo, *PredBlock, TryState); + for (const BasicBlock *PredBlock : predecessors(BB)) + if ((PredBlock = getEHPadFromPredecessor(PredBlock, + CatchSwitch->getParentPad()))) + calculateSEHStateNumbers(FuncInfo, PredBlock->getFirstNonPHI(), + TryState); // Everything in the __except block unwinds to ParentState, just like code // outside the __try. - FuncInfo.EHPadStateMap[FirstNonPHI] = ParentState; - DEBUG(dbgs() << "Assigning state #" << ParentState << " to BB " - << BB.getName() << '\n'); - for (const BasicBlock *PredBlock : predecessors(&BB)) - if ((PredBlock = getEHPadFromPredecessor(PredBlock))) - calculateExplicitSEHStateNumbers(FuncInfo, *PredBlock, ParentState); - } else if (isa<CleanupPadInst>(FirstNonPHI)) { - // A cleanup can have multiple exits; don't re-process after the first. - if (FuncInfo.EHPadStateMap.count(FirstNonPHI)) + for (const User *U : CatchPad->users()) { + const auto *UserI = cast<Instruction>(U); + if (UserI->isEHPad()) { + calculateSEHStateNumbers(FuncInfo, UserI, ParentState); + } + } + } else { + auto *CleanupPad = cast<CleanupPadInst>(FirstNonPHI); + + // It's possible for a cleanup to be visited twice: it might have multiple + // cleanupret instructions. + if (FuncInfo.EHPadStateMap.count(CleanupPad)) return; - int CleanupState = addSEHFinally(FuncInfo, ParentState, &BB); - FuncInfo.EHPadStateMap[FirstNonPHI] = CleanupState; + + int CleanupState = addSEHFinally(FuncInfo, ParentState, BB); + FuncInfo.EHPadStateMap[CleanupPad] = CleanupState; DEBUG(dbgs() << "Assigning state #" << CleanupState << " to BB " - << BB.getName() << '\n'); - for (const BasicBlock *PredBlock : predecessors(&BB)) - if ((PredBlock = getEHPadFromPredecessor(PredBlock))) - calculateExplicitSEHStateNumbers(FuncInfo, *PredBlock, CleanupState); - } else if (auto *CEPI = dyn_cast<CleanupEndPadInst>(FirstNonPHI)) { - // Propagate ParentState to the cleanuppad in case it doesn't have - // any cleanuprets. - BasicBlock *CleanupBlock = CEPI->getCleanupPad()->getParent(); - calculateExplicitSEHStateNumbers(FuncInfo, *CleanupBlock, ParentState); - // Anything unwinding through CleanupEndPadInst is in ParentState. - FuncInfo.EHPadStateMap[FirstNonPHI] = ParentState; - DEBUG(dbgs() << "Assigning state #" << ParentState << " to BB " - << BB.getName() << '\n'); - for (const BasicBlock *PredBlock : predecessors(&BB)) - if ((PredBlock = getEHPadFromPredecessor(PredBlock))) - calculateExplicitSEHStateNumbers(FuncInfo, *PredBlock, ParentState); - } else if (isa<TerminatePadInst>(FirstNonPHI)) { - report_fatal_error("Not yet implemented!"); - } else { - llvm_unreachable("unexpected EH Pad!"); + << BB->getName() << '\n'); + for (const BasicBlock *PredBlock : predecessors(BB)) + if ((PredBlock = + getEHPadFromPredecessor(PredBlock, CleanupPad->getParentPad()))) + calculateSEHStateNumbers(FuncInfo, PredBlock->getFirstNonPHI(), + CleanupState); + for (const User *U : CleanupPad->users()) { + const auto *UserI = cast<Instruction>(U); + if (UserI->isEHPad()) + report_fatal_error("Cleanup funclets for the SEH personality cannot " + "contain exceptional actions"); + } } } -/// Check if the EH Pad unwinds to caller. Cleanups are a little bit of a -/// special case because we have to look at the cleanupret instruction that uses -/// the cleanuppad. -static bool doesEHPadUnwindToCaller(const Instruction *EHPad) { - auto *CPI = dyn_cast<CleanupPadInst>(EHPad); - if (!CPI) - return EHPad->mayThrow(); - - // This cleanup does not return or unwind, so we say it unwinds to caller. - if (CPI->use_empty()) - return true; - - const Instruction *User = CPI->user_back(); - if (auto *CRI = dyn_cast<CleanupReturnInst>(User)) - return CRI->unwindsToCaller(); - return cast<CleanupEndPadInst>(User)->unwindsToCaller(); +static bool isTopLevelPadForMSVC(const Instruction *EHPad) { + if (auto *CatchSwitch = dyn_cast<CatchSwitchInst>(EHPad)) + return isa<ConstantTokenNone>(CatchSwitch->getParentPad()) && + CatchSwitch->unwindsToCaller(); + if (auto *CleanupPad = dyn_cast<CleanupPadInst>(EHPad)) + return isa<ConstantTokenNone>(CleanupPad->getParentPad()) && + getCleanupRetUnwindDest(CleanupPad) == nullptr; + if (isa<CatchPadInst>(EHPad)) + return false; + llvm_unreachable("unexpected EHPad!"); } void llvm::calculateSEHStateNumbers(const Function *Fn, @@ -431,10 +397,15 @@ void llvm::calculateSEHStateNumbers(const Function *Fn, return; for (const BasicBlock &BB : *Fn) { - if (!BB.isEHPad() || !doesEHPadUnwindToCaller(BB.getFirstNonPHI())) + if (!BB.isEHPad()) + continue; + const Instruction *FirstNonPHI = BB.getFirstNonPHI(); + if (!isTopLevelPadForMSVC(FirstNonPHI)) continue; - calculateExplicitSEHStateNumbers(FuncInfo, BB, -1); + ::calculateSEHStateNumbers(FuncInfo, FirstNonPHI, -1); } + + calculateStateNumbersForInvokes(Fn, FuncInfo); } void llvm::calculateWinCXXEHStateNumbers(const Function *Fn, @@ -446,13 +417,13 @@ void llvm::calculateWinCXXEHStateNumbers(const Function *Fn, for (const BasicBlock &BB : *Fn) { if (!BB.isEHPad()) continue; - if (BB.isLandingPad()) - report_fatal_error("MSVC C++ EH cannot use landingpads"); const Instruction *FirstNonPHI = BB.getFirstNonPHI(); - if (!doesEHPadUnwindToCaller(FirstNonPHI)) + if (!isTopLevelPadForMSVC(FirstNonPHI)) continue; - calculateExplicitCXXStateNumbers(FuncInfo, BB, -1); + calculateCXXStateNumbers(FuncInfo, FirstNonPHI, -1); } + + calculateStateNumbersForInvokes(Fn, FuncInfo); } static int addClrEHHandler(WinEHFuncInfo &FuncInfo, int ParentState, @@ -483,7 +454,7 @@ void llvm::calculateClrEHStateNumbers(const Function *Fn, if (BB.isLandingPad()) report_fatal_error("CoreCLR EH cannot use landingpads"); const Instruction *FirstNonPHI = BB.getFirstNonPHI(); - if (!doesEHPadUnwindToCaller(FirstNonPHI)) + if (!isTopLevelPadForMSVC(FirstNonPHI)) continue; // queue this with sentinel parent state -1 to mean unwind to caller. Worklist.emplace_back(FirstNonPHI, -1); @@ -494,16 +465,11 @@ void llvm::calculateClrEHStateNumbers(const Function *Fn, int ParentState; std::tie(Pad, ParentState) = Worklist.pop_back_val(); + Value *ParentPad; int PredState; - if (const CleanupEndPadInst *EndPad = dyn_cast<CleanupEndPadInst>(Pad)) { - FuncInfo.EHPadStateMap[EndPad] = ParentState; - // Queue the cleanuppad, in case it doesn't have a cleanupret. - Worklist.emplace_back(EndPad->getCleanupPad(), ParentState); - // Preds of the endpad should get the parent state. - PredState = ParentState; - } else if (const CleanupPadInst *Cleanup = dyn_cast<CleanupPadInst>(Pad)) { + if (const CleanupPadInst *Cleanup = dyn_cast<CleanupPadInst>(Pad)) { // A cleanup can have multiple exits; don't re-process after the first. - if (FuncInfo.EHPadStateMap.count(Pad)) + if (FuncInfo.EHPadStateMap.count(Cleanup)) continue; // CoreCLR personality uses arity to distinguish faults from finallies. const BasicBlock *PadBlock = Cleanup->getParent(); @@ -514,30 +480,47 @@ void llvm::calculateClrEHStateNumbers(const Function *Fn, addClrEHHandler(FuncInfo, ParentState, HandlerType, 0, PadBlock); FuncInfo.EHPadStateMap[Cleanup] = NewState; // Propagate the new state to all preds of the cleanup + ParentPad = Cleanup->getParentPad(); PredState = NewState; - } else if (const CatchEndPadInst *EndPad = dyn_cast<CatchEndPadInst>(Pad)) { - FuncInfo.EHPadStateMap[EndPad] = ParentState; - // Preds of the endpad should get the parent state. - PredState = ParentState; - } else if (const CatchPadInst *Catch = dyn_cast<CatchPadInst>(Pad)) { - const BasicBlock *PadBlock = Catch->getParent(); - uint32_t TypeToken = static_cast<uint32_t>( - cast<ConstantInt>(Catch->getArgOperand(0))->getZExtValue()); - int NewState = addClrEHHandler(FuncInfo, ParentState, - ClrHandlerType::Catch, TypeToken, PadBlock); - FuncInfo.EHPadStateMap[Catch] = NewState; - // Preds of the catch get its state + } else if (const auto *CatchSwitch = dyn_cast<CatchSwitchInst>(Pad)) { + SmallVector<const CatchPadInst *, 1> Handlers; + for (const BasicBlock *CatchPadBB : CatchSwitch->handlers()) { + const auto *Catch = cast<CatchPadInst>(CatchPadBB->getFirstNonPHI()); + Handlers.push_back(Catch); + } + FuncInfo.EHPadStateMap[CatchSwitch] = ParentState; + int NewState = ParentState; + for (auto HandlerI = Handlers.rbegin(), HandlerE = Handlers.rend(); + HandlerI != HandlerE; ++HandlerI) { + const CatchPadInst *Catch = *HandlerI; + const BasicBlock *PadBlock = Catch->getParent(); + uint32_t TypeToken = static_cast<uint32_t>( + cast<ConstantInt>(Catch->getArgOperand(0))->getZExtValue()); + NewState = addClrEHHandler(FuncInfo, NewState, ClrHandlerType::Catch, + TypeToken, PadBlock); + FuncInfo.EHPadStateMap[Catch] = NewState; + } + for (const auto *CatchPad : Handlers) { + for (const User *U : CatchPad->users()) { + const auto *UserI = cast<Instruction>(U); + if (UserI->isEHPad()) + Worklist.emplace_back(UserI, ParentState); + } + } PredState = NewState; + ParentPad = CatchSwitch->getParentPad(); } else { llvm_unreachable("Unexpected EH pad"); } // Queue all predecessors with the given state for (const BasicBlock *Pred : predecessors(Pad->getParent())) { - if ((Pred = getEHPadFromPredecessor(Pred))) + if ((Pred = getEHPadFromPredecessor(Pred, ParentPad))) Worklist.emplace_back(Pred->getFirstNonPHI(), PredState); } } + + calculateStateNumbersForInvokes(Fn, FuncInfo); } void WinEHPrepare::replaceTerminatePadWithCleanup(Function &F) { @@ -559,8 +542,9 @@ void WinEHPrepare::replaceTerminatePadWithCleanup(Function &F) { "C++ personalities!"); // Insert the cleanuppad instruction. - auto *CPI = CleanupPadInst::Create( - BB.getContext(), {}, Twine("terminatepad.for.", BB.getName()), &BB); + auto *CPI = + CleanupPadInst::Create(TPI->getParentPad(), {}, + Twine("terminatepad.for.", BB.getName()), &BB); // Insert the call to the terminate instruction. auto *CallTerminate = CallInst::Create(TerminateFn, {}, &BB); @@ -578,980 +562,32 @@ void WinEHPrepare::replaceTerminatePadWithCleanup(Function &F) { } } -static void -colorFunclets(Function &F, SmallVectorImpl<BasicBlock *> &EntryBlocks, - std::map<BasicBlock *, SetVector<BasicBlock *>> &BlockColors, - std::map<BasicBlock *, std::set<BasicBlock *>> &FuncletBlocks) { - SmallVector<std::pair<BasicBlock *, BasicBlock *>, 16> Worklist; - BasicBlock *EntryBlock = &F.getEntryBlock(); - - // Build up the color map, which maps each block to its set of 'colors'. - // For any block B, the "colors" of B are the set of funclets F (possibly - // including a root "funclet" representing the main function), such that - // F will need to directly contain B or a copy of B (where the term "directly - // contain" is used to distinguish from being "transitively contained" in - // a nested funclet). - // Use a CFG walk driven by a worklist of (block, color) pairs. The "color" - // sets attached during this processing to a block which is the entry of some - // funclet F is actually the set of F's parents -- i.e. the union of colors - // of all predecessors of F's entry. For all other blocks, the color sets - // are as defined above. A post-pass fixes up the block color map to reflect - // the same sense of "color" for funclet entries as for other blocks. - - DEBUG_WITH_TYPE("winehprepare-coloring", dbgs() << "\nColoring funclets for " - << F.getName() << "\n"); - - Worklist.push_back({EntryBlock, EntryBlock}); - - while (!Worklist.empty()) { - BasicBlock *Visiting; - BasicBlock *Color; - std::tie(Visiting, Color) = Worklist.pop_back_val(); - DEBUG_WITH_TYPE("winehprepare-coloring", - dbgs() << "Visiting " << Visiting->getName() << ", " - << Color->getName() << "\n"); - Instruction *VisitingHead = Visiting->getFirstNonPHI(); - if (VisitingHead->isEHPad() && !isa<CatchEndPadInst>(VisitingHead) && - !isa<CleanupEndPadInst>(VisitingHead)) { - // Mark this as a funclet head as a member of itself. - FuncletBlocks[Visiting].insert(Visiting); - // Queue exits (i.e. successors of rets/endpads) with the parent color. - // Skip any exits that are catchendpads, since the parent color must then - // represent one of the catches chained to that catchendpad, but the - // catchendpad should get the color of the common parent of all its - // chained catches (i.e. the grandparent color of the current pad). - // We don't need to worry abou catchendpads going unvisited, since the - // catches chained to them must have unwind edges to them by which we will - // visit them. - for (User *U : VisitingHead->users()) { - if (auto *Exit = dyn_cast<TerminatorInst>(U)) { - for (BasicBlock *Succ : successors(Exit->getParent())) - if (!isa<CatchEndPadInst>(*Succ->getFirstNonPHI())) - if (BlockColors[Succ].insert(Color)) { - DEBUG_WITH_TYPE("winehprepare-coloring", - dbgs() << " Assigned color \'" - << Color->getName() << "\' to block \'" - << Succ->getName() << "\'.\n"); - Worklist.push_back({Succ, Color}); - } - } - } - // Handle CatchPad specially since its successors need different colors. - if (CatchPadInst *CatchPad = dyn_cast<CatchPadInst>(VisitingHead)) { - // Visit the normal successor with the color of the new EH pad, and - // visit the unwind successor with the color of the parent. - BasicBlock *NormalSucc = CatchPad->getNormalDest(); - if (BlockColors[NormalSucc].insert(Visiting)) { - DEBUG_WITH_TYPE("winehprepare-coloring", - dbgs() << " Assigned color \'" << Visiting->getName() - << "\' to block \'" << NormalSucc->getName() - << "\'.\n"); - Worklist.push_back({NormalSucc, Visiting}); - } - BasicBlock *UnwindSucc = CatchPad->getUnwindDest(); - if (BlockColors[UnwindSucc].insert(Color)) { - DEBUG_WITH_TYPE("winehprepare-coloring", - dbgs() << " Assigned color \'" << Color->getName() - << "\' to block \'" << UnwindSucc->getName() - << "\'.\n"); - Worklist.push_back({UnwindSucc, Color}); - } - continue; - } - // Switch color to the current node, except for terminate pads which - // have no bodies and only unwind successors and so need their successors - // visited with the color of the parent. - if (!isa<TerminatePadInst>(VisitingHead)) - Color = Visiting; - } else { - // Note that this is a member of the given color. - FuncletBlocks[Color].insert(Visiting); - } - - TerminatorInst *Terminator = Visiting->getTerminator(); - if (isa<CleanupReturnInst>(Terminator) || - isa<CatchReturnInst>(Terminator) || - isa<CleanupEndPadInst>(Terminator)) { - // These blocks' successors have already been queued with the parent - // color. - continue; - } - for (BasicBlock *Succ : successors(Visiting)) { - if (isa<CatchEndPadInst>(Succ->getFirstNonPHI())) { - // The catchendpad needs to be visited with the parent's color, not - // the current color. This will happen in the code above that visits - // any catchpad unwind successor with the parent color, so we can - // safely skip this successor here. - continue; - } - if (BlockColors[Succ].insert(Color)) { - DEBUG_WITH_TYPE("winehprepare-coloring", - dbgs() << " Assigned color \'" << Color->getName() - << "\' to block \'" << Succ->getName() - << "\'.\n"); - Worklist.push_back({Succ, Color}); - } - } - } -} - -static BasicBlock *getEndPadForCatch(CatchPadInst *Catch) { - // The catch may have sibling catches. Follow the unwind chain until we get - // to the catchendpad. - BasicBlock *NextUnwindDest = Catch->getUnwindDest(); - auto *UnwindTerminator = NextUnwindDest->getTerminator(); - while (auto *NextCatch = dyn_cast<CatchPadInst>(UnwindTerminator)) { - NextUnwindDest = NextCatch->getUnwindDest(); - UnwindTerminator = NextUnwindDest->getTerminator(); - } - // The last catch in the chain must unwind to a catchendpad. - assert(isa<CatchEndPadInst>(UnwindTerminator)); - return NextUnwindDest; -} - -static void updateClonedEHPadUnwindToParent( - BasicBlock *UnwindDest, BasicBlock *OrigBlock, BasicBlock *CloneBlock, - std::vector<BasicBlock *> &OrigParents, BasicBlock *CloneParent) { - auto updateUnwindTerminator = [](BasicBlock *BB) { - auto *Terminator = BB->getTerminator(); - if (isa<CatchEndPadInst>(Terminator) || - isa<CleanupEndPadInst>(Terminator)) { - removeUnwindEdge(BB); - } else { - // If the block we're updating has a cleanupendpad or cleanupret - // terminator, we just want to replace that terminator with an - // unreachable instruction. - assert(isa<CleanupEndPadInst>(Terminator) || - isa<CleanupReturnInst>(Terminator)); - // Loop over all of the successors, removing the block's entry from any - // PHI nodes. - for (succ_iterator SI = succ_begin(BB), SE = succ_end(BB); SI != SE; ++SI) - (*SI)->removePredecessor(BB); - // Remove the terminator and replace it with an unreachable instruction. - BB->getTerminator()->eraseFromParent(); - new UnreachableInst(BB->getContext(), BB); - } - }; - - assert(UnwindDest->isEHPad()); - // There are many places to which this EH terminator can unwind and each has - // slightly different rules for whether or not it fits with the given - // location. - auto *EHPadInst = UnwindDest->getFirstNonPHI(); - if (isa<CatchEndPadInst>(EHPadInst)) { - auto *CloneParentCatch = - dyn_cast<CatchPadInst>(CloneParent->getFirstNonPHI()); - if (!CloneParentCatch || - getEndPadForCatch(CloneParentCatch) != UnwindDest) { - DEBUG_WITH_TYPE( - "winehprepare-coloring", - dbgs() << " removing unwind destination of clone block \'" - << CloneBlock->getName() << "\'.\n"); - updateUnwindTerminator(CloneBlock); - } - // It's possible that the catch end pad is a legal match for both the clone - // and the original, so they must be checked separately. If the original - // funclet will still have multiple parents after the current clone parent - // is removed, we'll leave its unwind terminator until later. - assert(OrigParents.size() >= 2); - if (OrigParents.size() != 2) - return; - - // If the original funclet will have a single parent after the clone parent - // is removed, check that parent's unwind destination. - assert(OrigParents.front() == CloneParent || - OrigParents.back() == CloneParent); - BasicBlock *OrigParent; - if (OrigParents.front() == CloneParent) - OrigParent = OrigParents.back(); - else - OrigParent = OrigParents.front(); - - auto *OrigParentCatch = - dyn_cast<CatchPadInst>(OrigParent->getFirstNonPHI()); - if (!OrigParentCatch || getEndPadForCatch(OrigParentCatch) != UnwindDest) { - DEBUG_WITH_TYPE( - "winehprepare-coloring", - dbgs() << " removing unwind destination of original block \'" - << OrigBlock << "\'.\n"); - updateUnwindTerminator(OrigBlock); - } - } else if (auto *CleanupEnd = dyn_cast<CleanupEndPadInst>(EHPadInst)) { - // If the EH terminator unwinds to a cleanupendpad, that cleanupendpad - // must be ending a cleanuppad of either our clone parent or one - // one of the parents of the original funclet. - auto *CloneParentCP = - dyn_cast<CleanupPadInst>(CloneParent->getFirstNonPHI()); - auto *EndedCP = CleanupEnd->getCleanupPad(); - if (EndedCP == CloneParentCP) { - // If it is ending the cleanuppad of our cloned parent, then we - // want to remove the unwind destination of the EH terminator that - // we associated with the original funclet. - assert(isa<CatchEndPadInst>(OrigBlock->getFirstNonPHI())); - DEBUG_WITH_TYPE( - "winehprepare-coloring", - dbgs() << " removing unwind destination of original block \'" - << OrigBlock->getName() << "\'.\n"); - updateUnwindTerminator(OrigBlock); - } else { - // If it isn't ending the cleanuppad of our clone parent, then we - // want to remove the unwind destination of the EH terminator that - // associated with our cloned funclet. - assert(isa<CatchEndPadInst>(CloneBlock->getFirstNonPHI())); - DEBUG_WITH_TYPE( - "winehprepare-coloring", - dbgs() << " removing unwind destination of clone block \'" - << CloneBlock->getName() << "\'.\n"); - updateUnwindTerminator(CloneBlock); - } - } else { - // If the EH terminator unwinds to a catchpad, cleanuppad or - // terminatepad that EH pad must be a sibling of the funclet we're - // cloning. We'll clone it later and update one of the catchendpad - // instrunctions that unwinds to it at that time. - assert(isa<CatchPadInst>(EHPadInst) || isa<CleanupPadInst>(EHPadInst) || - isa<TerminatePadInst>(EHPadInst)); - } -} - -// If the terminator is a catchpad, we must also clone the catchendpad to which -// it unwinds and add this to the clone parent's block list. The catchendpad -// unwinds to either its caller, a sibling EH pad, a cleanup end pad in its -// parent funclet or a catch end pad in its grandparent funclet (which must be -// coupled with the parent funclet). If it has no unwind destination -// (i.e. unwind to caller), there is nothing to be done. If the unwind -// destination is a sibling EH pad, we will update the terminators later (in -// resolveFuncletAncestryForPath). If it unwinds to a cleanup end pad or a -// catch end pad and this end pad corresponds to the clone parent, we will -// remove the unwind destination in the original catchendpad. If it unwinds to -// a cleanup end pad or a catch end pad that does not correspond to the clone -// parent, we will remove the unwind destination in the cloned catchendpad. -static void updateCatchTerminators( - Function &F, CatchPadInst *OrigCatch, CatchPadInst *CloneCatch, - std::vector<BasicBlock *> &OrigParents, BasicBlock *CloneParent, - ValueToValueMapTy &VMap, - std::map<BasicBlock *, SetVector<BasicBlock *>> &BlockColors, - std::map<BasicBlock *, std::set<BasicBlock *>> &FuncletBlocks) { - // If we're cloning a catch pad that unwinds to a catchendpad, we also - // need to clone the catchendpad. The coloring algorithm associates - // the catchendpad block with the funclet's parent, so we have some work - // to do here to figure out whether the original belongs to the clone - // parent or one of the original funclets other parents (it might have - // more than one at this point). In either case, we might also need to - // remove the unwind edge if the catchendpad doesn't unwind to a block - // in the right grandparent funclet. - Instruction *I = CloneCatch->getUnwindDest()->getFirstNonPHI(); - if (auto *CEP = dyn_cast<CatchEndPadInst>(I)) { - assert(BlockColors[CEP->getParent()].size() == 1); - BasicBlock *CEPFunclet = *(BlockColors[CEP->getParent()].begin()); - BasicBlock *CEPCloneParent = nullptr; - CatchPadInst *PredCatch = nullptr; - if (CEPFunclet == CloneParent) { - // The catchendpad is in the clone parent, so we need to clone it - // and associate the clone with the original funclet's parent. If - // the original funclet had multiple parents, we'll add it to the - // first parent that isn't the clone parent. The logic in - // updateClonedEHPadUnwindToParent() will only remove the unwind edge - // if there is only one parent other than the clone parent, so we don't - // need to verify the ancestry. The catchendpad will eventually be - // cloned into the correct parent and all invalid unwind edges will be - // removed. - for (auto *Parent : OrigParents) { - if (Parent != CloneParent) { - CEPCloneParent = Parent; - break; - } - } - PredCatch = OrigCatch; - } else { - CEPCloneParent = CloneParent; - PredCatch = CloneCatch; - } - assert(CEPCloneParent && PredCatch); - DEBUG_WITH_TYPE("winehprepare-coloring", - dbgs() << " Cloning catchendpad \'" - << CEP->getParent()->getName() << "\' for funclet \'" - << CEPCloneParent->getName() << "\'.\n"); - BasicBlock *ClonedCEP = CloneBasicBlock( - CEP->getParent(), VMap, Twine(".from.", CEPCloneParent->getName())); - // Insert the clone immediately after the original to ensure determinism - // and to keep the same relative ordering of any funclet's blocks. - ClonedCEP->insertInto(&F, CEP->getParent()->getNextNode()); - PredCatch->setUnwindDest(ClonedCEP); - FuncletBlocks[CEPCloneParent].insert(ClonedCEP); - BlockColors[ClonedCEP].insert(CEPCloneParent); - DEBUG_WITH_TYPE("winehprepare-coloring", - dbgs() << " Assigning color \'" - << CEPCloneParent->getName() << "\' to block \'" - << ClonedCEP->getName() << "\'.\n"); - auto *ClonedCEPInst = cast<CatchEndPadInst>(ClonedCEP->getTerminator()); - if (auto *Dest = ClonedCEPInst->getUnwindDest()) - updateClonedEHPadUnwindToParent(Dest, OrigCatch->getUnwindDest(), - CloneCatch->getUnwindDest(), OrigParents, - CloneParent); - } -} - -// While we are cloning a funclet because it has multiple parents, we will call -// this routine to update the terminators for the original and cloned copies -// of each basic block. All blocks in the funclet have been clone by this time. -// OrigBlock and CloneBlock will be identical except for their block label. -// -// If the terminator is a catchpad, we must also clone the catchendpad to which -// it unwinds and in most cases update either the original catchendpad or the -// clone. See the updateCatchTerminators() helper routine for details. -// -// If the terminator is a catchret its successor is a block in its parent -// funclet. If the instruction returns to a block in the parent for which the -// cloned funclet was created, the terminator in the original block must be -// replaced by an unreachable instruction. Otherwise the terminator in the -// clone block must be replaced by an unreachable instruction. -// -// If the terminator is a cleanupret or cleanupendpad it either unwinds to -// caller or unwinds to a sibling EH pad, a cleanup end pad in its parent -// funclet or a catch end pad in its grandparent funclet (which must be -// coupled with the parent funclet). If it unwinds to caller there is -// nothing to be done. If the unwind destination is a sibling EH pad, we will -// update the terminators later (in resolveFuncletAncestryForPath). If it -// unwinds to a cleanup end pad or a catch end pad and this end pad corresponds -// to the clone parent, we will replace the terminator in the original block -// with an unreachable instruction. If it unwinds to a cleanup end pad or a -// catch end pad that does not correspond to the clone parent, we will replace -// the terminator in the clone block with an unreachable instruction. -// -// If the terminator is an invoke instruction, we will handle it after all -// siblings of the current funclet have been cloned. -void WinEHPrepare::updateTerminatorsAfterFuncletClone( - Function &F, BasicBlock *OrigFunclet, BasicBlock *CloneFunclet, - BasicBlock *OrigBlock, BasicBlock *CloneBlock, BasicBlock *CloneParent, - ValueToValueMapTy &VMap, std::map<BasicBlock *, BasicBlock *> &Orig2Clone) { - // If the cloned block doesn't have an exceptional terminator, there is - // nothing to be done here. - TerminatorInst *CloneTerminator = CloneBlock->getTerminator(); - if (!CloneTerminator->isExceptional()) - return; - - if (auto *CloneCatch = dyn_cast<CatchPadInst>(CloneTerminator)) { - // A cloned catch pad has a lot of wrinkles, so we'll call a helper function - // to update this case. - auto *OrigCatch = cast<CatchPadInst>(OrigBlock->getTerminator()); - updateCatchTerminators(F, OrigCatch, CloneCatch, - FuncletParents[OrigFunclet], CloneParent, VMap, - BlockColors, FuncletBlocks); - } else if (auto *CRI = dyn_cast<CatchReturnInst>(CloneTerminator)) { - if (FuncletBlocks[CloneParent].count(CRI->getSuccessor())) { - BasicBlock *OrigParent; - // The original funclet may have more than two parents, but that's OK. - // We just need to remap the original catchret to any of the parents. - // All of the parents should have an entry in the EstrangedBlocks map - // if any of them do. - if (FuncletParents[OrigFunclet].front() == CloneParent) - OrigParent = FuncletParents[OrigFunclet].back(); - else - OrigParent = FuncletParents[OrigFunclet].front(); - for (succ_iterator SI = succ_begin(OrigBlock), SE = succ_end(OrigBlock); - SI != SE; ++SI) - (*SI)->removePredecessor(OrigBlock); - BasicBlock *LostBlock = EstrangedBlocks[OrigParent][CRI->getSuccessor()]; - auto *OrigCatchRet = cast<CatchReturnInst>(OrigBlock->getTerminator()); - if (LostBlock) { - OrigCatchRet->setSuccessor(LostBlock); - } else { - OrigCatchRet->eraseFromParent(); - new UnreachableInst(OrigBlock->getContext(), OrigBlock); - } - } else { - for (succ_iterator SI = succ_begin(CloneBlock), SE = succ_end(CloneBlock); - SI != SE; ++SI) - (*SI)->removePredecessor(CloneBlock); - BasicBlock *LostBlock = EstrangedBlocks[CloneParent][CRI->getSuccessor()]; - if (LostBlock) { - CRI->setSuccessor(LostBlock); - } else { - CRI->eraseFromParent(); - new UnreachableInst(CloneBlock->getContext(), CloneBlock); - } - } - } else if (isa<CleanupReturnInst>(CloneTerminator) || - isa<CleanupEndPadInst>(CloneTerminator)) { - BasicBlock *UnwindDest = nullptr; - - // A cleanup pad can unwind through either a cleanupret or a cleanupendpad - // but both are handled the same way. - if (auto *CRI = dyn_cast<CleanupReturnInst>(CloneTerminator)) - UnwindDest = CRI->getUnwindDest(); - else if (auto *CEI = dyn_cast<CleanupEndPadInst>(CloneTerminator)) - UnwindDest = CEI->getUnwindDest(); - - // If the instruction has no local unwind destination, there is nothing - // to be done. - if (!UnwindDest) - return; - - // The unwind destination may be a sibling EH pad, a catchendpad in - // a grandparent funclet (ending a catchpad in the parent) or a cleanup - // cleanupendpad in the parent. Call a helper routine to diagnose this - // and remove either the clone or original terminator as needed. - updateClonedEHPadUnwindToParent(UnwindDest, OrigBlock, CloneBlock, - FuncletParents[OrigFunclet], CloneParent); - } -} - -// Clones all blocks used by the specified funclet to avoid the funclet having -// multiple parent funclets. All terminators in the parent that unwind to the -// original funclet are remapped to unwind to the clone. Any terminator in the -// original funclet which returned to this parent is converted to an unreachable -// instruction. Likewise, any terminator in the cloned funclet which returns to -// a parent funclet other than the specified parent is converted to an -// unreachable instruction. -BasicBlock *WinEHPrepare::cloneFuncletForParent(Function &F, - BasicBlock *FuncletEntry, - BasicBlock *Parent) { - std::set<BasicBlock *> &BlocksInFunclet = FuncletBlocks[FuncletEntry]; - - DEBUG_WITH_TYPE("winehprepare-coloring", - dbgs() << "Cloning funclet \'" << FuncletEntry->getName() - << "\' for parent \'" << Parent->getName() << "\'.\n"); - - std::map<BasicBlock *, BasicBlock *> Orig2Clone; - ValueToValueMapTy VMap; - for (BasicBlock *BB : BlocksInFunclet) { - // Create a new basic block and copy instructions into it. - BasicBlock *CBB = - CloneBasicBlock(BB, VMap, Twine(".from.", Parent->getName())); - - // Insert the clone immediately after the original to ensure determinism - // and to keep the same relative ordering of any funclet's blocks. - CBB->insertInto(&F, BB->getNextNode()); - - // Add basic block mapping. - VMap[BB] = CBB; - - // Record delta operations that we need to perform to our color mappings. - Orig2Clone[BB] = CBB; - } // end for (BasicBlock *BB : BlocksInFunclet) - - BasicBlock *ClonedFunclet = Orig2Clone[FuncletEntry]; - assert(ClonedFunclet); - - // Set the coloring for the blocks we just cloned. - std::set<BasicBlock *> &ClonedBlocks = FuncletBlocks[ClonedFunclet]; - for (auto &BBMapping : Orig2Clone) { - BasicBlock *NewBlock = BBMapping.second; - ClonedBlocks.insert(NewBlock); - BlockColors[NewBlock].insert(ClonedFunclet); - - DEBUG_WITH_TYPE("winehprepare-coloring", - dbgs() << " Assigning color \'" << ClonedFunclet->getName() - << "\' to block \'" << NewBlock->getName() - << "\'.\n"); - - // Use the VMap to remap the instructions in this cloned block. - for (Instruction &I : *NewBlock) - RemapInstruction(&I, VMap, RF_IgnoreMissingEntries); - } - - // All the cloned blocks have to be colored in the loop above before we can - // update the terminators because doing so can require checking the color of - // other blocks in the cloned funclet. - for (auto &BBMapping : Orig2Clone) { - BasicBlock *OldBlock = BBMapping.first; - BasicBlock *NewBlock = BBMapping.second; - - // Update the terminator, if necessary, in both the original block and the - // cloned so that the original funclet never returns to a block in the - // clone parent and the clone funclet never returns to a block in any other - // of the original funclet's parents. - updateTerminatorsAfterFuncletClone(F, FuncletEntry, ClonedFunclet, OldBlock, - NewBlock, Parent, VMap, Orig2Clone); - - // Check to see if the cloned block successor has PHI nodes. If so, we need - // to add entries to the PHI nodes for the cloned block now. - for (BasicBlock *SuccBB : successors(NewBlock)) { - for (Instruction &SuccI : *SuccBB) { - auto *SuccPN = dyn_cast<PHINode>(&SuccI); - if (!SuccPN) - break; - - // Ok, we have a PHI node. Figure out what the incoming value was for - // the OldBlock. - int OldBlockIdx = SuccPN->getBasicBlockIndex(OldBlock); - if (OldBlockIdx == -1) - break; - Value *IV = SuccPN->getIncomingValue(OldBlockIdx); - - // Remap the value if necessary. - if (auto *Inst = dyn_cast<Instruction>(IV)) { - ValueToValueMapTy::iterator I = VMap.find(Inst); - if (I != VMap.end()) - IV = I->second; - } +void WinEHPrepare::colorFunclets(Function &F) { + BlockColors = colorEHFunclets(F); - SuccPN->addIncoming(IV, NewBlock); - } - } - } - - // Erase the clone's parent from the original funclet's parent list. - std::vector<BasicBlock *> &Parents = FuncletParents[FuncletEntry]; - Parents.erase(std::remove(Parents.begin(), Parents.end(), Parent), - Parents.end()); - - // Store the cloned funclet's parent. - assert(std::find(FuncletParents[ClonedFunclet].begin(), - FuncletParents[ClonedFunclet].end(), - Parent) == std::end(FuncletParents[ClonedFunclet])); - FuncletParents[ClonedFunclet].push_back(Parent); - - // Copy any children of the original funclet to the clone. We'll either - // clone them too or make that path unreachable when we take the next step - // in resolveFuncletAncestryForPath(). - for (auto *Child : FuncletChildren[FuncletEntry]) { - assert(std::find(FuncletChildren[ClonedFunclet].begin(), - FuncletChildren[ClonedFunclet].end(), - Child) == std::end(FuncletChildren[ClonedFunclet])); - FuncletChildren[ClonedFunclet].push_back(Child); - assert(std::find(FuncletParents[Child].begin(), FuncletParents[Child].end(), - ClonedFunclet) == std::end(FuncletParents[Child])); - FuncletParents[Child].push_back(ClonedFunclet); - } - - // Find any blocks that unwound to the original funclet entry from the - // clone parent block and remap them to the clone. - for (auto *U : FuncletEntry->users()) { - auto *UT = dyn_cast<TerminatorInst>(U); - if (!UT) - continue; - BasicBlock *UBB = UT->getParent(); - assert(BlockColors[UBB].size() == 1); - BasicBlock *UFunclet = *(BlockColors[UBB].begin()); - // Funclets shouldn't be able to loop back on themselves. - assert(UFunclet != FuncletEntry); - // If this instruction unwinds to the original funclet from the clone - // parent, remap the terminator so that it unwinds to the clone instead. - // We will perform a similar transformation for siblings after all - // the siblings have been cloned. - if (UFunclet == Parent) { - // We're about to break the path from this block to the uncloned funclet - // entry, so remove it as a predeccessor to clean up the PHIs. - FuncletEntry->removePredecessor(UBB); - TerminatorInst *Terminator = UBB->getTerminator(); - RemapInstruction(Terminator, VMap, RF_IgnoreMissingEntries); - } - } - - // This asserts a condition that is relied upon inside the loop below, - // namely that no predecessors of the original funclet entry block - // are also predecessors of the cloned funclet entry block. - assert(std::all_of(pred_begin(FuncletEntry), pred_end(FuncletEntry), - [&ClonedFunclet](BasicBlock *Pred) { - return std::find(pred_begin(ClonedFunclet), - pred_end(ClonedFunclet), - Pred) == pred_end(ClonedFunclet); - })); - - // Remove any invalid PHI node entries in the cloned funclet.cl - std::vector<PHINode *> PHIsToErase; - for (Instruction &I : *ClonedFunclet) { - auto *PN = dyn_cast<PHINode>(&I); - if (!PN) - break; - - // Predecessors of the original funclet do not reach the cloned funclet, - // but the cloning process assumes they will. Remove them now. - for (auto *Pred : predecessors(FuncletEntry)) - PN->removeIncomingValue(Pred, false); - } - for (auto *PN : PHIsToErase) - PN->eraseFromParent(); - - // Replace the original funclet in the parent's children vector with the - // cloned funclet. - for (auto &It : FuncletChildren[Parent]) { - if (It == FuncletEntry) { - It = ClonedFunclet; - break; - } - } - - return ClonedFunclet; -} - -// Removes the unwind edge for any exceptional terminators within the specified -// parent funclet that previously unwound to the specified child funclet. -void WinEHPrepare::makeFuncletEdgeUnreachable(BasicBlock *Parent, - BasicBlock *Child) { - for (BasicBlock *BB : FuncletBlocks[Parent]) { - TerminatorInst *Terminator = BB->getTerminator(); - if (!Terminator->isExceptional()) - continue; - - // Look for terninators that unwind to the child funclet. - BasicBlock *UnwindDest = nullptr; - if (auto *I = dyn_cast<InvokeInst>(Terminator)) - UnwindDest = I->getUnwindDest(); - else if (auto *I = dyn_cast<CatchEndPadInst>(Terminator)) - UnwindDest = I->getUnwindDest(); - else if (auto *I = dyn_cast<TerminatePadInst>(Terminator)) - UnwindDest = I->getUnwindDest(); - // cleanupendpad, catchret and cleanupret don't represent a parent-to-child - // funclet transition, so we don't need to consider them here. - - // If the child funclet is the unwind destination, replace the terminator - // with an unreachable instruction. - if (UnwindDest == Child) - removeUnwindEdge(BB); - } - // The specified parent is no longer a parent of the specified child. - std::vector<BasicBlock *> &Children = FuncletChildren[Parent]; - Children.erase(std::remove(Children.begin(), Children.end(), Child), - Children.end()); -} - -// This routine is called after funclets with multiple parents are cloned for -// a specific parent. Here we look for children of the specified funclet that -// unwind to other children of that funclet and update the unwind destinations -// to ensure that each sibling is connected to the correct clone of the sibling -// to which it unwinds. -// -// If the terminator is an invoke instruction, it unwinds either to a child -// EH pad, a cleanup end pad in the current funclet, or a catch end pad in a -// parent funclet (which ends either the current catch pad or a sibling -// catch pad). If it unwinds to a child EH pad, the child will have multiple -// parents after this funclet is cloned and this case will be handled later in -// the resolveFuncletAncestryForPath processing. If it unwinds to a -// cleanup end pad in the current funclet, the instruction remapping during -// the cloning process should have already mapped the unwind destination to -// the cloned copy of the cleanup end pad. If it unwinds to a catch end pad -// there are two possibilities: either the catch end pad is the unwind -// destination for the catch pad we are currently cloning or it is the unwind -// destination for a sibling catch pad. If it it the unwind destination of the -// catch pad we are cloning, we need to update the cloned invoke instruction -// to unwind to the cloned catch end pad. Otherwise, we will handle this -// later (in resolveFuncletAncestryForPath). -static void updateSiblingToSiblingUnwind( - BasicBlock *CurFunclet, - std::map<BasicBlock *, SetVector<BasicBlock *>> &BlockColors, - std::map<BasicBlock *, std::set<BasicBlock *>> &FuncletBlocks, - std::map<BasicBlock *, std::vector<BasicBlock *>> &FuncletParents, - std::map<BasicBlock *, std::vector<BasicBlock *>> &FuncletChildren, - std::map<BasicBlock *, BasicBlock *> &Funclet2Orig) { - // Remap any bad sibling-to-sibling transitions for funclets that - // we just cloned. - for (BasicBlock *ChildFunclet : FuncletChildren[CurFunclet]) { - for (auto *BB : FuncletBlocks[ChildFunclet]) { - TerminatorInst *Terminator = BB->getTerminator(); - if (!Terminator->isExceptional()) - continue; - - // See if this terminator has an unwind destination. - // Note that catchendpads are handled when the associated catchpad - // is cloned. They don't fit the pattern we're looking for here. - BasicBlock *UnwindDest = nullptr; - if (auto *I = dyn_cast<CatchPadInst>(Terminator)) { - UnwindDest = I->getUnwindDest(); - // The catchendpad is not a sibling destination. This case should - // have been handled in cloneFuncletForParent(). - if (isa<CatchEndPadInst>(Terminator)) { - assert(BlockColors[UnwindDest].size() == 1 && - "Cloned catchpad unwinds to an pad with multiple parents."); - assert(FuncletParents[UnwindDest].front() == CurFunclet && - "Cloned catchpad unwinds to the wrong parent."); - continue; - } - } else { - if (auto *I = dyn_cast<CleanupReturnInst>(Terminator)) - UnwindDest = I->getUnwindDest(); - else if (auto *I = dyn_cast<CleanupEndPadInst>(Terminator)) - UnwindDest = I->getUnwindDest(); - - // If the cleanup unwinds to caller, there is nothing to be done. - if (!UnwindDest) - continue; - } - - // If the destination is not a cleanup pad, catch pad or terminate pad - // we don't need to handle it here. - Instruction *EHPad = UnwindDest->getFirstNonPHI(); - if (!isa<CleanupPadInst>(EHPad) && !isa<CatchPadInst>(EHPad) && - !isa<TerminatePadInst>(EHPad)) - continue; - - // If it is one of these, then it is either a sibling of the current - // child funclet or a clone of one of those siblings. - // If it is a sibling, no action is needed. - if (FuncletParents[UnwindDest].size() == 1 && - FuncletParents[UnwindDest].front() == CurFunclet) - continue; - - // If the unwind destination is a clone of a sibling, we need to figure - // out which sibling it is a clone of and use that sibling as the - // unwind destination. - BasicBlock *DestOrig = Funclet2Orig[UnwindDest]; - BasicBlock *TargetSibling = nullptr; - for (auto &Mapping : Funclet2Orig) { - if (Mapping.second != DestOrig) - continue; - BasicBlock *MappedFunclet = Mapping.first; - if (FuncletParents[MappedFunclet].size() == 1 && - FuncletParents[MappedFunclet].front() == CurFunclet) { - TargetSibling = MappedFunclet; - } - } - // If we didn't find the sibling we were looking for then the - // unwind destination is not a clone of one of child's siblings. - // That's unexpected. - assert(TargetSibling && "Funclet unwinds to unexpected destination."); - - // Update the terminator instruction to unwind to the correct sibling. - if (auto *I = dyn_cast<CatchPadInst>(Terminator)) - I->setUnwindDest(TargetSibling); - else if (auto *I = dyn_cast<CleanupReturnInst>(Terminator)) - I->setUnwindDest(TargetSibling); - else if (auto *I = dyn_cast<CleanupEndPadInst>(Terminator)) - I->setUnwindDest(TargetSibling); - } - } - - // Invoke remapping can't be done correctly until after all of their - // other sibling-to-sibling unwinds have been remapped. - for (BasicBlock *ChildFunclet : FuncletChildren[CurFunclet]) { - bool NeedOrigInvokeRemapping = false; - for (auto *BB : FuncletBlocks[ChildFunclet]) { - TerminatorInst *Terminator = BB->getTerminator(); - auto *II = dyn_cast<InvokeInst>(Terminator); - if (!II) - continue; - - BasicBlock *UnwindDest = II->getUnwindDest(); - assert(UnwindDest && "Invoke unwinds to a null destination."); - assert(UnwindDest->isEHPad() && "Invoke does not unwind to an EH pad."); - auto *EHPadInst = UnwindDest->getFirstNonPHI(); - if (isa<CleanupEndPadInst>(EHPadInst)) { - // An invoke that unwinds to a cleanup end pad must be in a cleanup pad. - assert(isa<CleanupPadInst>(ChildFunclet->getFirstNonPHI()) && - "Unwinding to cleanup end pad from a non cleanup pad funclet."); - // The funclet cloning should have remapped the destination to the cloned - // cleanup end pad. - assert(FuncletBlocks[ChildFunclet].count(UnwindDest) && - "Unwind destination for invoke was not updated during cloning."); - } else if (isa<CatchEndPadInst>(EHPadInst)) { - // If the invoke unwind destination is the unwind destination for - // the current child catch pad funclet, there is nothing to be done. - BasicBlock *OrigFunclet = Funclet2Orig[ChildFunclet]; - auto *CurCatch = cast<CatchPadInst>(ChildFunclet->getFirstNonPHI()); - auto *OrigCatch = cast<CatchPadInst>(OrigFunclet->getFirstNonPHI()); - if (OrigCatch->getUnwindDest() == UnwindDest) { - // If the invoke unwinds to a catch end pad that is the unwind - // destination for the original catch pad, the cloned invoke should - // unwind to the cloned catch end pad. - II->setUnwindDest(CurCatch->getUnwindDest()); - } else if (CurCatch->getUnwindDest() == UnwindDest) { - // If the invoke unwinds to a catch end pad that is the unwind - // destination for the clone catch pad, the original invoke should - // unwind to the unwind destination of the original catch pad. - // This happens when the catch end pad is matched to the clone - // parent when the catchpad instruction is cloned and the original - // invoke instruction unwinds to the original catch end pad (which - // is now the unwind destination of the cloned catch pad). - NeedOrigInvokeRemapping = true; - } else { - // Otherwise, the invoke unwinds to a catch end pad that is the unwind - // destination another catch pad in the unwind chain from either the - // current catch pad or one of its clones. If it is already the - // catch end pad at the end unwind chain from the current catch pad, - // we'll need to check the invoke instructions in the original funclet - // later. Otherwise, we need to remap this invoke now. - assert((getEndPadForCatch(OrigCatch) == UnwindDest || - getEndPadForCatch(CurCatch) == UnwindDest) && - "Invoke within catch pad unwinds to an invalid catch end pad."); - BasicBlock *CurCatchEnd = getEndPadForCatch(CurCatch); - if (CurCatchEnd == UnwindDest) - NeedOrigInvokeRemapping = true; - else - II->setUnwindDest(CurCatchEnd); - } - } - } - if (NeedOrigInvokeRemapping) { - // To properly remap invoke instructions that unwind to catch end pads - // that are not the unwind destination of the catch pad funclet in which - // the invoke appears, we must also look at the uncloned invoke in the - // original funclet. If we saw an invoke that was already properly - // unwinding to a sibling's catch end pad, we need to check the invokes - // in the original funclet. - BasicBlock *OrigFunclet = Funclet2Orig[ChildFunclet]; - for (auto *BB : FuncletBlocks[OrigFunclet]) { - auto *II = dyn_cast<InvokeInst>(BB->getTerminator()); - if (!II) - continue; - - BasicBlock *UnwindDest = II->getUnwindDest(); - assert(UnwindDest && "Invoke unwinds to a null destination."); - assert(UnwindDest->isEHPad() && "Invoke does not unwind to an EH pad."); - auto *CEP = dyn_cast<CatchEndPadInst>(UnwindDest->getFirstNonPHI()); - if (!CEP) - continue; - - // If the invoke unwind destination is the unwind destination for - // the original catch pad funclet, there is nothing to be done. - auto *OrigCatch = cast<CatchPadInst>(OrigFunclet->getFirstNonPHI()); - - // If the invoke unwinds to a catch end pad that is neither the unwind - // destination of OrigCatch or the destination another catch pad in the - // unwind chain from current catch pad, we need to remap the invoke. - BasicBlock *OrigCatchEnd = getEndPadForCatch(OrigCatch); - if (OrigCatchEnd != UnwindDest) - II->setUnwindDest(OrigCatchEnd); - } - } - } -} - -void WinEHPrepare::resolveFuncletAncestry( - Function &F, SmallVectorImpl<BasicBlock *> &EntryBlocks) { - // Most of the time this will be unnecessary. If the conditions arise that - // require this work, this flag will be set. - if (!FuncletCloningRequired) - return; - - // Funclet2Orig is used to map any cloned funclets back to the original - // funclet from which they were cloned. The map is seeded with the - // original funclets mapping to themselves. - std::map<BasicBlock *, BasicBlock *> Funclet2Orig; - for (auto *Funclet : EntryBlocks) - Funclet2Orig[Funclet] = Funclet; - - // Start with the entry funclet and walk the funclet parent-child tree. - SmallVector<BasicBlock *, 4> FuncletPath; - FuncletPath.push_back(&(F.getEntryBlock())); - resolveFuncletAncestryForPath(F, FuncletPath, Funclet2Orig); -} - -// Walks the funclet control flow, cloning any funclets that have more than one -// parent funclet and breaking any cyclic unwind chains so that the path becomes -// unreachable at the point where a funclet would have unwound to a funclet that -// was already in the chain. -void WinEHPrepare::resolveFuncletAncestryForPath( - Function &F, SmallVectorImpl<BasicBlock *> &FuncletPath, - std::map<BasicBlock *, BasicBlock *> &Funclet2Orig) { - bool ClonedAnyChildren = false; - BasicBlock *CurFunclet = FuncletPath.back(); - // Copy the children vector because we might changing it. - std::vector<BasicBlock *> Children(FuncletChildren[CurFunclet]); - for (BasicBlock *ChildFunclet : Children) { - // Don't allow the funclet chain to unwind back on itself. - // If this funclet is already in the current funclet chain, make the - // path to it through the current funclet unreachable. - bool IsCyclic = false; - BasicBlock *ChildIdentity = Funclet2Orig[ChildFunclet]; - for (BasicBlock *Ancestor : FuncletPath) { - BasicBlock *AncestorIdentity = Funclet2Orig[Ancestor]; - if (AncestorIdentity == ChildIdentity) { - IsCyclic = true; - break; - } - } - // If the unwind chain wraps back on itself, break the chain. - if (IsCyclic) { - makeFuncletEdgeUnreachable(CurFunclet, ChildFunclet); - continue; - } - // If this child funclet has other parents, clone the entire funclet. - if (FuncletParents[ChildFunclet].size() > 1) { - ChildFunclet = cloneFuncletForParent(F, ChildFunclet, CurFunclet); - Funclet2Orig[ChildFunclet] = ChildIdentity; - ClonedAnyChildren = true; - } - FuncletPath.push_back(ChildFunclet); - resolveFuncletAncestryForPath(F, FuncletPath, Funclet2Orig); - FuncletPath.pop_back(); - } - // If we didn't clone any children, we can return now. - if (!ClonedAnyChildren) - return; - - updateSiblingToSiblingUnwind(CurFunclet, BlockColors, FuncletBlocks, - FuncletParents, FuncletChildren, Funclet2Orig); -} - -void WinEHPrepare::colorFunclets(Function &F, - SmallVectorImpl<BasicBlock *> &EntryBlocks) { - ::colorFunclets(F, EntryBlocks, BlockColors, FuncletBlocks); - - // The processing above actually accumulated the parent set for this - // funclet into the color set for its entry; use the parent set to - // populate the children map, and reset the color set to include just - // the funclet itself (no instruction can target a funclet entry except on - // that transitions to the child funclet). - for (BasicBlock *FuncletEntry : EntryBlocks) { - SetVector<BasicBlock *> &ColorMapItem = BlockColors[FuncletEntry]; - // It will be rare for funclets to have multiple parents, but if any - // do we need to clone the funclet later to address that. Here we - // set a flag indicating that this case has arisen so that we don't - // have to do a lot of checking later to handle the more common case. - if (ColorMapItem.size() > 1) - FuncletCloningRequired = true; - for (BasicBlock *Parent : ColorMapItem) { - assert(std::find(FuncletChildren[Parent].begin(), - FuncletChildren[Parent].end(), - FuncletEntry) == std::end(FuncletChildren[Parent])); - FuncletChildren[Parent].push_back(FuncletEntry); - assert(std::find(FuncletParents[FuncletEntry].begin(), - FuncletParents[FuncletEntry].end(), - Parent) == std::end(FuncletParents[FuncletEntry])); - FuncletParents[FuncletEntry].push_back(Parent); - } - ColorMapItem.clear(); - ColorMapItem.insert(FuncletEntry); + // Invert the map from BB to colors to color to BBs. + for (BasicBlock &BB : F) { + ColorVector &Colors = BlockColors[&BB]; + for (BasicBlock *Color : Colors) + FuncletBlocks[Color].push_back(&BB); } } void llvm::calculateCatchReturnSuccessorColors(const Function *Fn, WinEHFuncInfo &FuncInfo) { - SmallVector<BasicBlock *, 4> EntryBlocks; - // colorFunclets needs the set of EntryBlocks, get them using - // findFuncletEntryPoints. - findFuncletEntryPoints(const_cast<Function &>(*Fn), EntryBlocks); - - std::map<BasicBlock *, SetVector<BasicBlock *>> BlockColors; - std::map<BasicBlock *, std::set<BasicBlock *>> FuncletBlocks; - // Figure out which basic blocks belong to which funclets. - colorFunclets(const_cast<Function &>(*Fn), EntryBlocks, BlockColors, - FuncletBlocks); - - // The static colorFunclets routine assigns multiple colors to funclet entries - // because that information is needed to calculate funclets' parent-child - // relationship, but we don't need those relationship here and ultimately the - // entry blocks should have the color of the funclet they begin. - for (BasicBlock *FuncletEntry : EntryBlocks) { - BlockColors[FuncletEntry].clear(); - BlockColors[FuncletEntry].insert(FuncletEntry); - } - - // We need to find the catchret successors. To do this, we must first find - // all the catchpad funclets. - for (auto &Funclet : FuncletBlocks) { - // Figure out what kind of funclet we are looking at; We only care about - // catchpads. - BasicBlock *FuncletPadBB = Funclet.first; - Instruction *FirstNonPHI = FuncletPadBB->getFirstNonPHI(); - auto *CatchPad = dyn_cast<CatchPadInst>(FirstNonPHI); - if (!CatchPad) + for (const BasicBlock &BB : *Fn) { + const auto *CatchRet = dyn_cast<CatchReturnInst>(BB.getTerminator()); + if (!CatchRet) continue; - - // The users of a catchpad are always catchrets. - for (User *Exit : CatchPad->users()) { - auto *CatchReturn = dyn_cast<CatchReturnInst>(Exit); - if (!CatchReturn) - continue; - BasicBlock *CatchRetSuccessor = CatchReturn->getSuccessor(); - SetVector<BasicBlock *> &SuccessorColors = BlockColors[CatchRetSuccessor]; - assert(SuccessorColors.size() == 1 && "Expected BB to be monochrome!"); - BasicBlock *Color = *SuccessorColors.begin(); - // Record the catchret successor's funclet membership. - FuncInfo.CatchRetSuccessorColorMap[CatchReturn] = Color; - } + // A 'catchret' returns to the outer scope's color. + Value *ParentPad = CatchRet->getParentPad(); + const BasicBlock *Color; + if (isa<ConstantTokenNone>(ParentPad)) + Color = &Fn->getEntryBlock(); + else + Color = cast<Instruction>(ParentPad)->getParent(); + // Record the catchret successor's funclet membership. + FuncInfo.CatchRetSuccessorColorMap[CatchRet] = Color; } } @@ -1584,70 +620,23 @@ void WinEHPrepare::demotePHIsOnFunclets(Function &F) { } } -void WinEHPrepare::cloneCommonBlocks( - Function &F, SmallVectorImpl<BasicBlock *> &EntryBlocks) { +void WinEHPrepare::cloneCommonBlocks(Function &F) { // We need to clone all blocks which belong to multiple funclets. Values are // remapped throughout the funclet to propogate both the new instructions // *and* the new basic blocks themselves. - for (BasicBlock *FuncletPadBB : EntryBlocks) { - std::set<BasicBlock *> &BlocksInFunclet = FuncletBlocks[FuncletPadBB]; + for (auto &Funclets : FuncletBlocks) { + BasicBlock *FuncletPadBB = Funclets.first; + std::vector<BasicBlock *> &BlocksInFunclet = Funclets.second; - std::map<BasicBlock *, BasicBlock *> Orig2Clone; + std::vector<std::pair<BasicBlock *, BasicBlock *>> Orig2Clone; ValueToValueMapTy VMap; - for (auto BlockIt = BlocksInFunclet.begin(), - BlockEnd = BlocksInFunclet.end(); - BlockIt != BlockEnd;) { - // Increment the iterator inside the loop because we might be removing - // blocks from the set. - BasicBlock *BB = *BlockIt++; - SetVector<BasicBlock *> &ColorsForBB = BlockColors[BB]; + for (BasicBlock *BB : BlocksInFunclet) { + ColorVector &ColorsForBB = BlockColors[BB]; // We don't need to do anything if the block is monochromatic. size_t NumColorsForBB = ColorsForBB.size(); if (NumColorsForBB == 1) continue; - // If this block is a catchendpad, it shouldn't be cloned. - // We will only see a catchendpad with multiple colors in the case where - // some funclet has multiple parents. In that case, the color will be - // resolved during the resolveFuncletAncestry processing. - // For now, find the catchpad that unwinds to this block and assign - // that catchpad's first parent to be the color for this block. - if (isa<CatchEndPadInst>(BB->getFirstNonPHI())) { - assert( - FuncletCloningRequired && - "Found multi-colored catchendpad with no multi-parent funclets."); - BasicBlock *CatchParent = nullptr; - // There can only be one catchpad predecessor for a catchendpad. - for (BasicBlock *PredBB : predecessors(BB)) { - if (isa<CatchPadInst>(PredBB->getTerminator())) { - CatchParent = PredBB; - break; - } - } - // There must be one catchpad predecessor for a catchendpad. - assert(CatchParent && "No catchpad found for catchendpad."); - - // If the catchpad has multiple parents, we'll clone the catchendpad - // when we clone the catchpad funclet and insert it into the correct - // funclet. For now, we just select the first parent of the catchpad - // and give the catchendpad that color. - BasicBlock *CorrectColor = FuncletParents[CatchParent].front(); - assert(FuncletBlocks[CorrectColor].count(BB)); - assert(BlockColors[BB].count(CorrectColor)); - - // Remove this block from the FuncletBlocks set of any funclet that - // isn't the funclet whose color we just selected. - for (BasicBlock *ContainingFunclet : BlockColors[BB]) - if (ContainingFunclet != CorrectColor) - FuncletBlocks[ContainingFunclet].erase(BB); - BlockColors[BB].remove_if([&](BasicBlock *ContainingFunclet) { - return ContainingFunclet != CorrectColor; - }); - // This should leave just one color for BB. - assert(BlockColors[BB].size() == 1); - continue; - } - DEBUG_WITH_TYPE("winehprepare-coloring", dbgs() << " Cloning block \'" << BB->getName() << "\' for funclet \'" << FuncletPadBB->getName() @@ -1664,7 +653,7 @@ void WinEHPrepare::cloneCommonBlocks( VMap[BB] = CBB; // Record delta operations that we need to perform to our color mappings. - Orig2Clone[BB] = CBB; + Orig2Clone.emplace_back(BB, CBB); } // If nothing was cloned, we're done cloning in this funclet. @@ -1677,55 +666,28 @@ void WinEHPrepare::cloneCommonBlocks( BasicBlock *OldBlock = BBMapping.first; BasicBlock *NewBlock = BBMapping.second; - BlocksInFunclet.insert(NewBlock); - BlockColors[NewBlock].insert(FuncletPadBB); + BlocksInFunclet.push_back(NewBlock); + ColorVector &NewColors = BlockColors[NewBlock]; + assert(NewColors.empty() && "A new block should only have one color!"); + NewColors.push_back(FuncletPadBB); DEBUG_WITH_TYPE("winehprepare-coloring", dbgs() << " Assigned color \'" << FuncletPadBB->getName() << "\' to block \'" << NewBlock->getName() << "\'.\n"); - BlocksInFunclet.erase(OldBlock); - BlockColors[OldBlock].remove(FuncletPadBB); + BlocksInFunclet.erase( + std::remove(BlocksInFunclet.begin(), BlocksInFunclet.end(), OldBlock), + BlocksInFunclet.end()); + ColorVector &OldColors = BlockColors[OldBlock]; + OldColors.erase( + std::remove(OldColors.begin(), OldColors.end(), FuncletPadBB), + OldColors.end()); DEBUG_WITH_TYPE("winehprepare-coloring", dbgs() << " Removed color \'" << FuncletPadBB->getName() << "\' from block \'" << OldBlock->getName() << "\'.\n"); - - // If we are cloning a funclet that might share a child funclet with - // another funclet, look to see if the cloned block is reached from a - // catchret instruction. If so, save this association so we can retrieve - // the possibly orphaned clone when we clone the child funclet. - if (FuncletCloningRequired) { - for (auto *Pred : predecessors(OldBlock)) { - auto *Terminator = Pred->getTerminator(); - if (!isa<CatchReturnInst>(Terminator)) - continue; - // If this block is reached from a catchret instruction in a funclet - // that has multiple parents, it will have a color for each of those - // parents. We just removed the color of one of the parents, but - // the cloned block will be unreachable until we clone the child - // funclet that contains the catchret instruction. In that case we - // need to create a mapping that will let us find the cloned block - // later and associate it with the cloned child funclet. - bool BlockWillBeEstranged = false; - for (auto *Color : BlockColors[Pred]) { - if (FuncletParents[Color].size() > 1) { - BlockWillBeEstranged = true; - break; // Breaks out of the color loop - } - } - if (BlockWillBeEstranged) { - EstrangedBlocks[FuncletPadBB][OldBlock] = NewBlock; - DEBUG_WITH_TYPE("winehprepare-coloring", - dbgs() << " Saved mapping of estranged block \'" - << NewBlock->getName() << "\' for \'" - << FuncletPadBB->getName() << "\'.\n"); - break; // Breaks out of the predecessor loop - } - } - } } // Loop over all of the instructions in this funclet, fixing up operand @@ -1736,6 +698,40 @@ void WinEHPrepare::cloneCommonBlocks( RemapInstruction(&I, VMap, RF_IgnoreMissingEntries | RF_NoModuleLevelChanges); + auto UpdatePHIOnClonedBlock = [&](PHINode *PN, bool IsForOldBlock) { + unsigned NumPreds = PN->getNumIncomingValues(); + for (unsigned PredIdx = 0, PredEnd = NumPreds; PredIdx != PredEnd; + ++PredIdx) { + BasicBlock *IncomingBlock = PN->getIncomingBlock(PredIdx); + ColorVector &IncomingColors = BlockColors[IncomingBlock]; + bool BlockInFunclet = IncomingColors.size() == 1 && + IncomingColors.front() == FuncletPadBB; + if (IsForOldBlock != BlockInFunclet) + continue; + PN->removeIncomingValue(IncomingBlock, /*DeletePHIIfEmpty=*/false); + // Revisit the next entry. + --PredIdx; + --PredEnd; + } + }; + + for (auto &BBMapping : Orig2Clone) { + BasicBlock *OldBlock = BBMapping.first; + BasicBlock *NewBlock = BBMapping.second; + for (Instruction &OldI : *OldBlock) { + auto *OldPN = dyn_cast<PHINode>(&OldI); + if (!OldPN) + break; + UpdatePHIOnClonedBlock(OldPN, /*IsForOldBlock=*/true); + } + for (Instruction &NewI : *NewBlock) { + auto *NewPN = dyn_cast<PHINode>(&NewI); + if (!NewPN) + break; + UpdatePHIOnClonedBlock(NewPN, /*IsForOldBlock=*/false); + } + } + // Check to see if SuccBB has PHI nodes. If so, we need to add entries to // the PHI nodes for NewBB now. for (auto &BBMapping : Orig2Clone) { @@ -1783,7 +779,7 @@ void WinEHPrepare::cloneCommonBlocks( for (Use &U : OldI->uses()) { Instruction *UserI = cast<Instruction>(U.getUser()); BasicBlock *UserBB = UserI->getParent(); - SetVector<BasicBlock *> &ColorsForUserBB = BlockColors[UserBB]; + ColorVector &ColorsForUserBB = BlockColors[UserBB]; assert(!ColorsForUserBB.empty()); if (ColorsForUserBB.size() > 1 || *ColorsForUserBB.begin() != FuncletPadBB) @@ -1813,10 +809,10 @@ void WinEHPrepare::removeImplausibleTerminators(Function &F) { // Remove implausible terminators and replace them with UnreachableInst. for (auto &Funclet : FuncletBlocks) { BasicBlock *FuncletPadBB = Funclet.first; - std::set<BasicBlock *> &BlocksInFunclet = Funclet.second; - Instruction *FirstNonPHI = FuncletPadBB->getFirstNonPHI(); - auto *CatchPad = dyn_cast<CatchPadInst>(FirstNonPHI); - auto *CleanupPad = dyn_cast<CleanupPadInst>(FirstNonPHI); + std::vector<BasicBlock *> &BlocksInFunclet = Funclet.second; + Instruction *FuncletPadInst = FuncletPadBB->getFirstNonPHI(); + auto *CatchPad = dyn_cast<CatchPadInst>(FuncletPadInst); + auto *CleanupPad = dyn_cast<CleanupPadInst>(FuncletPadInst); for (BasicBlock *BB : BlocksInFunclet) { TerminatorInst *TI = BB->getTerminator(); @@ -1830,34 +826,22 @@ void WinEHPrepare::removeImplausibleTerminators(Function &F) { bool IsUnreachableCleanupret = false; if (auto *CRI = dyn_cast<CleanupReturnInst>(TI)) IsUnreachableCleanupret = CRI->getCleanupPad() != CleanupPad; - // The token consumed by a CleanupEndPadInst must match the funclet token. - bool IsUnreachableCleanupendpad = false; - if (auto *CEPI = dyn_cast<CleanupEndPadInst>(TI)) - IsUnreachableCleanupendpad = CEPI->getCleanupPad() != CleanupPad; if (IsUnreachableRet || IsUnreachableCatchret || - IsUnreachableCleanupret || IsUnreachableCleanupendpad) { + IsUnreachableCleanupret) { // Loop through all of our successors and make sure they know that one // of their predecessors is going away. for (BasicBlock *SuccBB : TI->successors()) SuccBB->removePredecessor(BB); - if (IsUnreachableCleanupendpad) { - // We can't simply replace a cleanupendpad with unreachable, because - // its predecessor edges are EH edges and unreachable is not an EH - // pad. Change all predecessors to the "unwind to caller" form. - for (pred_iterator PI = pred_begin(BB), PE = pred_end(BB); - PI != PE;) { - BasicBlock *Pred = *PI++; - removeUnwindEdge(Pred); - } - } - new UnreachableInst(BB->getContext(), TI); TI->eraseFromParent(); + } else if (isa<InvokeInst>(TI)) { + // Invokes within a cleanuppad for the MSVC++ personality never + // transfer control to their unwind edge: the personality will + // terminate the program. + if (Personality == EHPersonality::MSVC_CXX && CleanupPad) + removeUnwindEdge(BB); } - // FIXME: Check for invokes/cleanuprets/cleanupendpads which unwind to - // implausible catchendpads (i.e. catchendpad not in immediate parent - // funclet). } } } @@ -1886,27 +870,31 @@ void WinEHPrepare::verifyPreparedFunclets(Function &F) { report_fatal_error("Uncolored BB!"); if (NumColors > 1) report_fatal_error("Multicolor BB!"); - bool EHPadHasPHI = BB.isEHPad() && isa<PHINode>(BB.begin()); - assert(!EHPadHasPHI && "EH Pad still has a PHI!"); - if (EHPadHasPHI) - report_fatal_error("EH Pad still has a PHI!"); + if (!DisableDemotion) { + bool EHPadHasPHI = BB.isEHPad() && isa<PHINode>(BB.begin()); + assert(!EHPadHasPHI && "EH Pad still has a PHI!"); + if (EHPadHasPHI) + report_fatal_error("EH Pad still has a PHI!"); + } } } -bool WinEHPrepare::prepareExplicitEH( - Function &F, SmallVectorImpl<BasicBlock *> &EntryBlocks) { +bool WinEHPrepare::prepareExplicitEH(Function &F) { + // Remove unreachable blocks. It is not valuable to assign them a color and + // their existence can trick us into thinking values are alive when they are + // not. + removeUnreachableBlocks(F); + replaceTerminatePadWithCleanup(F); // Determine which blocks are reachable from which funclet entries. - colorFunclets(F, EntryBlocks); + colorFunclets(F); + + cloneCommonBlocks(F); if (!DisableDemotion) demotePHIsOnFunclets(F); - cloneCommonBlocks(F, EntryBlocks); - - resolveFuncletAncestry(F, EntryBlocks); - if (!DisableCleanups) { removeImplausibleTerminators(F); @@ -1917,10 +905,6 @@ bool WinEHPrepare::prepareExplicitEH( BlockColors.clear(); FuncletBlocks.clear(); - FuncletChildren.clear(); - FuncletParents.clear(); - EstrangedBlocks.clear(); - FuncletCloningRequired = false; return true; } @@ -1930,9 +914,11 @@ bool WinEHPrepare::prepareExplicitEH( AllocaInst *WinEHPrepare::insertPHILoads(PHINode *PN, Function &F) { BasicBlock *PHIBlock = PN->getParent(); AllocaInst *SpillSlot = nullptr; + Instruction *EHPad = PHIBlock->getFirstNonPHI(); - if (isa<CleanupPadInst>(PHIBlock->getFirstNonPHI())) { - // Insert a load in place of the PHI and replace all uses. + if (!isa<TerminatorInst>(EHPad)) { + // If the EHPad isn't a terminator, then we can insert a load in this block + // that will dominate all uses. SpillSlot = new AllocaInst(PN->getType(), nullptr, Twine(PN->getName(), ".wineh.spillslot"), &F.getEntryBlock().front()); @@ -1942,16 +928,16 @@ AllocaInst *WinEHPrepare::insertPHILoads(PHINode *PN, Function &F) { return SpillSlot; } + // Otherwise, we have a PHI on a terminator EHPad, and we give up and insert + // loads of the slot before every use. DenseMap<BasicBlock *, Value *> Loads; for (Value::use_iterator UI = PN->use_begin(), UE = PN->use_end(); UI != UE;) { Use &U = *UI++; auto *UsingInst = cast<Instruction>(U.getUser()); - BasicBlock *UsingBB = UsingInst->getParent(); - if (UsingBB->isEHPad()) { + if (isa<PHINode>(UsingInst) && UsingInst->getParent()->isEHPad()) { // Use is on an EH pad phi. Leave it alone; we'll insert loads and // stores for it separately. - assert(isa<PHINode>(UsingInst)); continue; } replaceUseWithLoad(PN, U, SpillSlot, Loads, F); @@ -2005,7 +991,7 @@ void WinEHPrepare::insertPHIStore( SmallVectorImpl<std::pair<BasicBlock *, Value *>> &Worklist) { if (PredBlock->isEHPad() && - !isa<CleanupPadInst>(PredBlock->getFirstNonPHI())) { + isa<TerminatorInst>(PredBlock->getFirstNonPHI())) { // Pred is unsplittable, so we need to queue it on the worklist. Worklist.push_back({PredBlock, PredVal}); return; @@ -2065,10 +1051,10 @@ void WinEHPrepare::replaceUseWithLoad(Value *V, Use &U, AllocaInst *&SpillSlot, Goto->setSuccessor(0, PHIBlock); CatchRet->setSuccessor(NewBlock); // Update the color mapping for the newly split edge. - SetVector<BasicBlock *> &ColorsForPHIBlock = BlockColors[PHIBlock]; + ColorVector &ColorsForPHIBlock = BlockColors[PHIBlock]; BlockColors[NewBlock] = ColorsForPHIBlock; for (BasicBlock *FuncletPad : ColorsForPHIBlock) - FuncletBlocks[FuncletPad].insert(NewBlock); + FuncletBlocks[FuncletPad].push_back(NewBlock); // Treat the new block as incoming for load insertion. IncomingBlock = NewBlock; } @@ -2087,11 +1073,10 @@ void WinEHPrepare::replaceUseWithLoad(Value *V, Use &U, AllocaInst *&SpillSlot, } } -void WinEHFuncInfo::addIPToStateRange(const BasicBlock *PadBB, +void WinEHFuncInfo::addIPToStateRange(const InvokeInst *II, MCSymbol *InvokeBegin, MCSymbol *InvokeEnd) { - assert(PadBB->isEHPad() && EHPadStateMap.count(PadBB->getFirstNonPHI()) && - "should get EH pad BB with precomputed state"); - InvokeToStateMap[InvokeBegin] = - std::make_pair(EHPadStateMap[PadBB->getFirstNonPHI()], InvokeEnd); + assert(InvokeStateMap.count(II) && + "should get invoke with precomputed state"); + LabelToStateMap[InvokeBegin] = std::make_pair(InvokeStateMap[II], InvokeEnd); } diff --git a/llvm/lib/IR/AsmWriter.cpp b/llvm/lib/IR/AsmWriter.cpp index e41815aafa8..fbb27773c11 100644 --- a/llvm/lib/IR/AsmWriter.cpp +++ b/llvm/lib/IR/AsmWriter.cpp @@ -2890,19 +2890,36 @@ void AssemblyWriter::printInstruction(const Instruction &I) { writeOperand(LPI->getClause(i), true); } - } else if (const auto *CPI = dyn_cast<CatchPadInst>(&I)) { + } else if (const auto *CatchSwitch = dyn_cast<CatchSwitchInst>(&I)) { + Out << " within "; + writeOperand(CatchSwitch->getParentPad(), /*PrintType=*/false); Out << " ["; - for (unsigned Op = 0, NumOps = CPI->getNumArgOperands(); Op < NumOps; + unsigned Op = 0; + for (const BasicBlock *PadBB : CatchSwitch->handlers()) { + if (Op > 0) + Out << ", "; + writeOperand(PadBB, /*PrintType=*/true); + ++Op; + } + Out << "] unwind "; + if (const BasicBlock *UnwindDest = CatchSwitch->getUnwindDest()) + writeOperand(UnwindDest, /*PrintType=*/true); + else + Out << "to caller"; + } else if (const auto *FPI = dyn_cast<FuncletPadInst>(&I)) { + Out << " within "; + writeOperand(FPI->getParentPad(), /*PrintType=*/false); + Out << " ["; + for (unsigned Op = 0, NumOps = FPI->getNumArgOperands(); Op < NumOps; ++Op) { if (Op > 0) Out << ", "; - writeOperand(CPI->getArgOperand(Op), /*PrintType=*/true); + writeOperand(FPI->getArgOperand(Op), /*PrintType=*/true); } - Out << "]\n to "; - writeOperand(CPI->getNormalDest(), /*PrintType=*/true); - Out << " unwind "; - writeOperand(CPI->getUnwindDest(), /*PrintType=*/true); + Out << ']'; } else if (const auto *TPI = dyn_cast<TerminatePadInst>(&I)) { + Out << " within "; + writeOperand(TPI->getParentPad(), /*PrintType=*/false); Out << " ["; for (unsigned Op = 0, NumOps = TPI->getNumArgOperands(); Op < NumOps; ++Op) { @@ -2915,44 +2932,21 @@ void AssemblyWriter::printInstruction(const Instruction &I) { writeOperand(TPI->getUnwindDest(), /*PrintType=*/true); else Out << "to caller"; - } else if (const auto *CPI = dyn_cast<CleanupPadInst>(&I)) { - Out << " ["; - for (unsigned Op = 0, NumOps = CPI->getNumOperands(); Op < NumOps; ++Op) { - if (Op > 0) - Out << ", "; - writeOperand(CPI->getOperand(Op), /*PrintType=*/true); - } - Out << "]"; } else if (isa<ReturnInst>(I) && !Operand) { Out << " void"; } else if (const auto *CRI = dyn_cast<CatchReturnInst>(&I)) { - Out << ' '; - writeOperand(CRI->getCatchPad(), /*PrintType=*/false); + Out << " from "; + writeOperand(CRI->getOperand(0), /*PrintType=*/false); Out << " to "; - writeOperand(CRI->getSuccessor(), /*PrintType=*/true); + writeOperand(CRI->getOperand(1), /*PrintType=*/true); } else if (const auto *CRI = dyn_cast<CleanupReturnInst>(&I)) { - Out << ' '; - writeOperand(CRI->getCleanupPad(), /*PrintType=*/false); + Out << " from "; + writeOperand(CRI->getOperand(0), /*PrintType=*/false); Out << " unwind "; if (CRI->hasUnwindDest()) - writeOperand(CRI->getUnwindDest(), /*PrintType=*/true); - else - Out << "to caller"; - } else if (const auto *CEPI = dyn_cast<CatchEndPadInst>(&I)) { - Out << " unwind "; - if (CEPI->hasUnwindDest()) - writeOperand(CEPI->getUnwindDest(), /*PrintType=*/true); - else - Out << "to caller"; - } else if (const auto *CEPI = dyn_cast<CleanupEndPadInst>(&I)) { - Out << ' '; - writeOperand(CEPI->getCleanupPad(), /*PrintType=*/false); - - Out << " unwind "; - if (CEPI->hasUnwindDest()) - writeOperand(CEPI->getUnwindDest(), /*PrintType=*/true); + writeOperand(CRI->getOperand(1), /*PrintType=*/true); else Out << "to caller"; } else if (const CallInst *CI = dyn_cast<CallInst>(&I)) { diff --git a/llvm/lib/IR/Dominators.cpp b/llvm/lib/IR/Dominators.cpp index d94e31d4875..b9d4fb7de88 100644 --- a/llvm/lib/IR/Dominators.cpp +++ b/llvm/lib/IR/Dominators.cpp @@ -91,11 +91,11 @@ bool DominatorTree::dominates(const Instruction *Def, if (Def == User) return false; - // The value defined by an invoke/catchpad dominates an instruction only if - // it dominates every instruction in UseBB. - // A PHI is dominated only if the instruction dominates every possible use - // in the UseBB. - if (isa<InvokeInst>(Def) || isa<CatchPadInst>(Def) || isa<PHINode>(User)) + // The value defined by an invoke dominates an instruction only if it + // dominates every instruction in UseBB. + // A PHI is dominated only if the instruction dominates every possible use in + // the UseBB. + if (isa<InvokeInst>(Def) || isa<PHINode>(User)) return dominates(Def, UseBB); if (DefBB != UseBB) @@ -126,18 +126,13 @@ bool DominatorTree::dominates(const Instruction *Def, if (DefBB == UseBB) return false; - // Invoke/CatchPad results are only usable in the normal destination, not in - // the exceptional destination. + // Invoke results are only usable in the normal destination, not in the + // exceptional destination. if (const auto *II = dyn_cast<InvokeInst>(Def)) { BasicBlock *NormalDest = II->getNormalDest(); BasicBlockEdge E(DefBB, NormalDest); return dominates(E, UseBB); } - if (const auto *CPI = dyn_cast<CatchPadInst>(Def)) { - BasicBlock *NormalDest = CPI->getNormalDest(); - BasicBlockEdge E(DefBB, NormalDest); - return dominates(E, UseBB); - } return dominates(DefBB, UseBB); } @@ -239,8 +234,8 @@ bool DominatorTree::dominates(const Instruction *Def, const Use &U) const { if (!isReachableFromEntry(DefBB)) return false; - // Invoke/CatchPad instructions define their return values on the edges - // to their normal successors, so we have to handle them specially. + // Invoke instructions define their return values on the edges to their normal + // successors, so we have to handle them specially. // Among other things, this means they don't dominate anything in // their own block, except possibly a phi, so we don't need to // walk the block in any case. @@ -249,11 +244,6 @@ bool DominatorTree::dominates(const Instruction *Def, const Use &U) const { BasicBlockEdge E(DefBB, NormalDest); return dominates(E, U); } - if (const auto *CPI = dyn_cast<CatchPadInst>(Def)) { - BasicBlock *NormalDest = CPI->getNormalDest(); - BasicBlockEdge E(DefBB, NormalDest); - return dominates(E, U); - } // If the def and use are in different blocks, do a simple CFG dominator // tree query. diff --git a/llvm/lib/IR/Instruction.cpp b/llvm/lib/IR/Instruction.cpp index 7bd50328b12..ce2e1d8c02b 100644 --- a/llvm/lib/IR/Instruction.cpp +++ b/llvm/lib/IR/Instruction.cpp @@ -202,11 +202,10 @@ const char *Instruction::getOpcodeName(unsigned OpCode) { case Invoke: return "invoke"; case Resume: return "resume"; case Unreachable: return "unreachable"; - case CleanupEndPad: return "cleanupendpad"; case CleanupRet: return "cleanupret"; - case CatchEndPad: return "catchendpad"; case CatchRet: return "catchret"; case CatchPad: return "catchpad"; + case CatchSwitch: return "catchswitch"; case TerminatePad: return "terminatepad"; // Standard binary operators... @@ -476,10 +475,8 @@ bool Instruction::mayThrow() const { return !CI->doesNotThrow(); if (const auto *CRI = dyn_cast<CleanupReturnInst>(this)) return CRI->unwindsToCaller(); - if (const auto *CEPI = dyn_cast<CleanupEndPadInst>(this)) - return CEPI->unwindsToCaller(); - if (const auto *CEPI = dyn_cast<CatchEndPadInst>(this)) - return CEPI->unwindsToCaller(); + if (const auto *CatchSwitch = dyn_cast<CatchSwitchInst>(this)) + return CatchSwitch->unwindsToCaller(); if (const auto *TPI = dyn_cast<TerminatePadInst>(this)) return TPI->unwindsToCaller(); return isa<ResumeInst>(this); diff --git a/llvm/lib/IR/Instructions.cpp b/llvm/lib/IR/Instructions.cpp index 11c55865135..82eb1e0f2f7 100644 --- a/llvm/lib/IR/Instructions.cpp +++ b/llvm/lib/IR/Instructions.cpp @@ -764,61 +764,6 @@ BasicBlock *ResumeInst::getSuccessorV(unsigned idx) const { } //===----------------------------------------------------------------------===// -// CleanupEndPadInst Implementation -//===----------------------------------------------------------------------===// - -CleanupEndPadInst::CleanupEndPadInst(const CleanupEndPadInst &CEPI) - : TerminatorInst(CEPI.getType(), Instruction::CleanupEndPad, - OperandTraits<CleanupEndPadInst>::op_end(this) - - CEPI.getNumOperands(), - CEPI.getNumOperands()) { - setInstructionSubclassData(CEPI.getSubclassDataFromInstruction()); - setCleanupPad(CEPI.getCleanupPad()); - if (BasicBlock *UnwindDest = CEPI.getUnwindDest()) - setUnwindDest(UnwindDest); -} - -void CleanupEndPadInst::init(CleanupPadInst *CleanupPad, BasicBlock *UnwindBB) { - setCleanupPad(CleanupPad); - if (UnwindBB) { - setInstructionSubclassData(getSubclassDataFromInstruction() | 1); - setUnwindDest(UnwindBB); - } -} - -CleanupEndPadInst::CleanupEndPadInst(CleanupPadInst *CleanupPad, - BasicBlock *UnwindBB, unsigned Values, - Instruction *InsertBefore) - : TerminatorInst(Type::getVoidTy(CleanupPad->getContext()), - Instruction::CleanupEndPad, - OperandTraits<CleanupEndPadInst>::op_end(this) - Values, - Values, InsertBefore) { - init(CleanupPad, UnwindBB); -} - -CleanupEndPadInst::CleanupEndPadInst(CleanupPadInst *CleanupPad, - BasicBlock *UnwindBB, unsigned Values, - BasicBlock *InsertAtEnd) - : TerminatorInst(Type::getVoidTy(CleanupPad->getContext()), - Instruction::CleanupEndPad, - OperandTraits<CleanupEndPadInst>::op_end(this) - Values, - Values, InsertAtEnd) { - init(CleanupPad, UnwindBB); -} - -BasicBlock *CleanupEndPadInst::getSuccessorV(unsigned Idx) const { - assert(Idx == 0); - return getUnwindDest(); -} -unsigned CleanupEndPadInst::getNumSuccessorsV() const { - return getNumSuccessors(); -} -void CleanupEndPadInst::setSuccessorV(unsigned Idx, BasicBlock *B) { - assert(Idx == 0); - setUnwindDest(B); -} - -//===----------------------------------------------------------------------===// // CleanupReturnInst Implementation //===----------------------------------------------------------------------===// @@ -828,23 +773,22 @@ CleanupReturnInst::CleanupReturnInst(const CleanupReturnInst &CRI) CRI.getNumOperands(), CRI.getNumOperands()) { setInstructionSubclassData(CRI.getSubclassDataFromInstruction()); - Op<-1>() = CRI.Op<-1>(); + Op<0>() = CRI.Op<0>(); if (CRI.hasUnwindDest()) - Op<-2>() = CRI.Op<-2>(); + Op<1>() = CRI.Op<1>(); } -void CleanupReturnInst::init(CleanupPadInst *CleanupPad, BasicBlock *UnwindBB) { +void CleanupReturnInst::init(Value *CleanupPad, BasicBlock *UnwindBB) { if (UnwindBB) setInstructionSubclassData(getSubclassDataFromInstruction() | 1); - Op<-1>() = CleanupPad; + Op<0>() = CleanupPad; if (UnwindBB) - Op<-2>() = UnwindBB; + Op<1>() = UnwindBB; } -CleanupReturnInst::CleanupReturnInst(CleanupPadInst *CleanupPad, - BasicBlock *UnwindBB, unsigned Values, - Instruction *InsertBefore) +CleanupReturnInst::CleanupReturnInst(Value *CleanupPad, BasicBlock *UnwindBB, + unsigned Values, Instruction *InsertBefore) : TerminatorInst(Type::getVoidTy(CleanupPad->getContext()), Instruction::CleanupRet, OperandTraits<CleanupReturnInst>::op_end(this) - Values, @@ -852,9 +796,8 @@ CleanupReturnInst::CleanupReturnInst(CleanupPadInst *CleanupPad, init(CleanupPad, UnwindBB); } -CleanupReturnInst::CleanupReturnInst(CleanupPadInst *CleanupPad, - BasicBlock *UnwindBB, unsigned Values, - BasicBlock *InsertAtEnd) +CleanupReturnInst::CleanupReturnInst(Value *CleanupPad, BasicBlock *UnwindBB, + unsigned Values, BasicBlock *InsertAtEnd) : TerminatorInst(Type::getVoidTy(CleanupPad->getContext()), Instruction::CleanupRet, OperandTraits<CleanupReturnInst>::op_end(this) - Values, @@ -875,58 +818,9 @@ void CleanupReturnInst::setSuccessorV(unsigned Idx, BasicBlock *B) { } //===----------------------------------------------------------------------===// -// CatchEndPadInst Implementation -//===----------------------------------------------------------------------===// - -CatchEndPadInst::CatchEndPadInst(const CatchEndPadInst &CRI) - : TerminatorInst(CRI.getType(), Instruction::CatchEndPad, - OperandTraits<CatchEndPadInst>::op_end(this) - - CRI.getNumOperands(), - CRI.getNumOperands()) { - setInstructionSubclassData(CRI.getSubclassDataFromInstruction()); - if (BasicBlock *UnwindDest = CRI.getUnwindDest()) - setUnwindDest(UnwindDest); -} - -void CatchEndPadInst::init(BasicBlock *UnwindBB) { - if (UnwindBB) { - setInstructionSubclassData(getSubclassDataFromInstruction() | 1); - setUnwindDest(UnwindBB); - } -} - -CatchEndPadInst::CatchEndPadInst(LLVMContext &C, BasicBlock *UnwindBB, - unsigned Values, Instruction *InsertBefore) - : TerminatorInst(Type::getVoidTy(C), Instruction::CatchEndPad, - OperandTraits<CatchEndPadInst>::op_end(this) - Values, - Values, InsertBefore) { - init(UnwindBB); -} - -CatchEndPadInst::CatchEndPadInst(LLVMContext &C, BasicBlock *UnwindBB, - unsigned Values, BasicBlock *InsertAtEnd) - : TerminatorInst(Type::getVoidTy(C), Instruction::CatchEndPad, - OperandTraits<CatchEndPadInst>::op_end(this) - Values, - Values, InsertAtEnd) { - init(UnwindBB); -} - -BasicBlock *CatchEndPadInst::getSuccessorV(unsigned Idx) const { - assert(Idx == 0); - return getUnwindDest(); -} -unsigned CatchEndPadInst::getNumSuccessorsV() const { - return getNumSuccessors(); -} -void CatchEndPadInst::setSuccessorV(unsigned Idx, BasicBlock *B) { - assert(Idx == 0); - setUnwindDest(B); -} - -//===----------------------------------------------------------------------===// // CatchReturnInst Implementation //===----------------------------------------------------------------------===// -void CatchReturnInst::init(CatchPadInst *CatchPad, BasicBlock *BB) { +void CatchReturnInst::init(Value *CatchPad, BasicBlock *BB) { Op<0>() = CatchPad; Op<1>() = BB; } @@ -938,7 +832,7 @@ CatchReturnInst::CatchReturnInst(const CatchReturnInst &CRI) Op<1>() = CRI.Op<1>(); } -CatchReturnInst::CatchReturnInst(CatchPadInst *CatchPad, BasicBlock *BB, +CatchReturnInst::CatchReturnInst(Value *CatchPad, BasicBlock *BB, Instruction *InsertBefore) : TerminatorInst(Type::getVoidTy(BB->getContext()), Instruction::CatchRet, OperandTraits<CatchReturnInst>::op_begin(this), 2, @@ -946,7 +840,7 @@ CatchReturnInst::CatchReturnInst(CatchPadInst *CatchPad, BasicBlock *BB, init(CatchPad, BB); } -CatchReturnInst::CatchReturnInst(CatchPadInst *CatchPad, BasicBlock *BB, +CatchReturnInst::CatchReturnInst(Value *CatchPad, BasicBlock *BB, BasicBlock *InsertAtEnd) : TerminatorInst(Type::getVoidTy(BB->getContext()), Instruction::CatchRet, OperandTraits<CatchReturnInst>::op_begin(this), 2, @@ -967,64 +861,136 @@ void CatchReturnInst::setSuccessorV(unsigned Idx, BasicBlock *B) { } //===----------------------------------------------------------------------===// -// CatchPadInst Implementation +// CatchSwitchInst Implementation //===----------------------------------------------------------------------===// -void CatchPadInst::init(BasicBlock *IfNormal, BasicBlock *IfException, - ArrayRef<Value *> Args, const Twine &NameStr) { - assert(getNumOperands() == 2 + Args.size() && "NumOperands not set up?"); - Op<-2>() = IfNormal; - Op<-1>() = IfException; - std::copy(Args.begin(), Args.end(), op_begin()); + +CatchSwitchInst::CatchSwitchInst(Value *ParentPad, BasicBlock *UnwindDest, + unsigned NumReservedValues, + const Twine &NameStr, + Instruction *InsertBefore) + : TerminatorInst(ParentPad->getType(), Instruction::CatchSwitch, nullptr, 0, + InsertBefore) { + if (UnwindDest) + ++NumReservedValues; + init(ParentPad, UnwindDest, NumReservedValues + 1); setName(NameStr); } -CatchPadInst::CatchPadInst(const CatchPadInst &CPI) - : TerminatorInst(CPI.getType(), Instruction::CatchPad, - OperandTraits<CatchPadInst>::op_end(this) - - CPI.getNumOperands(), - CPI.getNumOperands()) { - std::copy(CPI.op_begin(), CPI.op_end(), op_begin()); +CatchSwitchInst::CatchSwitchInst(Value *ParentPad, BasicBlock *UnwindDest, + unsigned NumReservedValues, + const Twine &NameStr, BasicBlock *InsertAtEnd) + : TerminatorInst(ParentPad->getType(), Instruction::CatchSwitch, nullptr, 0, + InsertAtEnd) { + if (UnwindDest) + ++NumReservedValues; + init(ParentPad, UnwindDest, NumReservedValues + 1); + setName(NameStr); } -CatchPadInst::CatchPadInst(BasicBlock *IfNormal, BasicBlock *IfException, - ArrayRef<Value *> Args, unsigned Values, - const Twine &NameStr, Instruction *InsertBefore) - : TerminatorInst(Type::getTokenTy(IfNormal->getContext()), - Instruction::CatchPad, - OperandTraits<CatchPadInst>::op_end(this) - Values, Values, - InsertBefore) { - init(IfNormal, IfException, Args, NameStr); +CatchSwitchInst::CatchSwitchInst(const CatchSwitchInst &CSI) + : TerminatorInst(CSI.getType(), Instruction::CatchSwitch, nullptr, + CSI.getNumOperands()) { + init(CSI.getParentPad(), CSI.getUnwindDest(), CSI.getNumOperands()); + setNumHungOffUseOperands(ReservedSpace); + Use *OL = getOperandList(); + const Use *InOL = CSI.getOperandList(); + for (unsigned I = 1, E = ReservedSpace; I != E; ++I) + OL[I] = InOL[I]; } -CatchPadInst::CatchPadInst(BasicBlock *IfNormal, BasicBlock *IfException, - ArrayRef<Value *> Args, unsigned Values, - const Twine &NameStr, BasicBlock *InsertAtEnd) - : TerminatorInst(Type::getTokenTy(IfNormal->getContext()), - Instruction::CatchPad, - OperandTraits<CatchPadInst>::op_end(this) - Values, Values, - InsertAtEnd) { - init(IfNormal, IfException, Args, NameStr); +void CatchSwitchInst::init(Value *ParentPad, BasicBlock *UnwindDest, + unsigned NumReservedValues) { + assert(ParentPad && NumReservedValues); + + ReservedSpace = NumReservedValues; + setNumHungOffUseOperands(UnwindDest ? 2 : 1); + allocHungoffUses(ReservedSpace); + + Op<0>() = ParentPad; + if (UnwindDest) { + setInstructionSubclassData(getSubclassDataFromInstruction() | 1); + setUnwindDest(UnwindDest); + } } -BasicBlock *CatchPadInst::getSuccessorV(unsigned Idx) const { - return getSuccessor(Idx); +/// growOperands - grow operands - This grows the operand list in response to a +/// push_back style of operation. This grows the number of ops by 2 times. +void CatchSwitchInst::growOperands(unsigned Size) { + unsigned NumOperands = getNumOperands(); + assert(NumOperands >= 1); + if (ReservedSpace >= NumOperands + Size) + return; + ReservedSpace = (NumOperands + Size / 2) * 2; + growHungoffUses(ReservedSpace); +} + +void CatchSwitchInst::addHandler(BasicBlock *Handler) { + unsigned OpNo = getNumOperands(); + growOperands(1); + assert(OpNo < ReservedSpace && "Growing didn't work!"); + setNumHungOffUseOperands(getNumOperands() + 1); + getOperandList()[OpNo] = Handler; +} + +BasicBlock *CatchSwitchInst::getSuccessorV(unsigned idx) const { + return getSuccessor(idx); } -unsigned CatchPadInst::getNumSuccessorsV() const { +unsigned CatchSwitchInst::getNumSuccessorsV() const { return getNumSuccessors(); } -void CatchPadInst::setSuccessorV(unsigned Idx, BasicBlock *B) { - return setSuccessor(Idx, B); +void CatchSwitchInst::setSuccessorV(unsigned idx, BasicBlock *B) { + setSuccessor(idx, B); +} + +//===----------------------------------------------------------------------===// +// FuncletPadInst Implementation +//===----------------------------------------------------------------------===// +void FuncletPadInst::init(Value *ParentPad, ArrayRef<Value *> Args, + const Twine &NameStr) { + assert(getNumOperands() == 1 + Args.size() && "NumOperands not set up?"); + std::copy(Args.begin(), Args.end(), op_begin()); + setParentPad(ParentPad); + setName(NameStr); +} + +FuncletPadInst::FuncletPadInst(const FuncletPadInst &FPI) + : Instruction(FPI.getType(), FPI.getOpcode(), + OperandTraits<FuncletPadInst>::op_end(this) - + FPI.getNumOperands(), + FPI.getNumOperands()) { + std::copy(FPI.op_begin(), FPI.op_end(), op_begin()); + setParentPad(FPI.getParentPad()); +} + +FuncletPadInst::FuncletPadInst(Instruction::FuncletPadOps Op, Value *ParentPad, + ArrayRef<Value *> Args, unsigned Values, + const Twine &NameStr, Instruction *InsertBefore) + : Instruction(ParentPad->getType(), Op, + OperandTraits<FuncletPadInst>::op_end(this) - Values, Values, + InsertBefore) { + init(ParentPad, Args, NameStr); +} + +FuncletPadInst::FuncletPadInst(Instruction::FuncletPadOps Op, Value *ParentPad, + ArrayRef<Value *> Args, unsigned Values, + const Twine &NameStr, BasicBlock *InsertAtEnd) + : Instruction(ParentPad->getType(), Op, + OperandTraits<FuncletPadInst>::op_end(this) - Values, Values, + InsertAtEnd) { + init(ParentPad, Args, NameStr); } //===----------------------------------------------------------------------===// // TerminatePadInst Implementation //===----------------------------------------------------------------------===// -void TerminatePadInst::init(BasicBlock *BB, ArrayRef<Value *> Args) { - if (BB) +void TerminatePadInst::init(Value *ParentPad, BasicBlock *BB, + ArrayRef<Value *> Args) { + if (BB) { setInstructionSubclassData(getSubclassDataFromInstruction() | 1); - if (BB) - Op<-1>() = BB; - std::copy(Args.begin(), Args.end(), op_begin()); + setUnwindDest(BB); + } + std::copy(Args.begin(), Args.end(), arg_begin()); + setParentPad(ParentPad); } TerminatePadInst::TerminatePadInst(const TerminatePadInst &TPI) @@ -1036,22 +1002,24 @@ TerminatePadInst::TerminatePadInst(const TerminatePadInst &TPI) std::copy(TPI.op_begin(), TPI.op_end(), op_begin()); } -TerminatePadInst::TerminatePadInst(LLVMContext &C, BasicBlock *BB, +TerminatePadInst::TerminatePadInst(Value *ParentPad, BasicBlock *BB, ArrayRef<Value *> Args, unsigned Values, Instruction *InsertBefore) - : TerminatorInst(Type::getVoidTy(C), Instruction::TerminatePad, + : TerminatorInst(Type::getVoidTy(ParentPad->getContext()), + Instruction::TerminatePad, OperandTraits<TerminatePadInst>::op_end(this) - Values, Values, InsertBefore) { - init(BB, Args); + init(ParentPad, BB, Args); } -TerminatePadInst::TerminatePadInst(LLVMContext &C, BasicBlock *BB, +TerminatePadInst::TerminatePadInst(Value *ParentPad, BasicBlock *BB, ArrayRef<Value *> Args, unsigned Values, BasicBlock *InsertAtEnd) - : TerminatorInst(Type::getVoidTy(C), Instruction::TerminatePad, + : TerminatorInst(Type::getVoidTy(ParentPad->getContext()), + Instruction::TerminatePad, OperandTraits<TerminatePadInst>::op_end(this) - Values, Values, InsertAtEnd) { - init(BB, Args); + init(ParentPad, BB, Args); } BasicBlock *TerminatePadInst::getSuccessorV(unsigned Idx) const { @@ -1067,39 +1035,6 @@ void TerminatePadInst::setSuccessorV(unsigned Idx, BasicBlock *B) { } //===----------------------------------------------------------------------===// -// CleanupPadInst Implementation -//===----------------------------------------------------------------------===// -void CleanupPadInst::init(ArrayRef<Value *> Args, const Twine &NameStr) { - assert(getNumOperands() == Args.size() && "NumOperands not set up?"); - std::copy(Args.begin(), Args.end(), op_begin()); - setName(NameStr); -} - -CleanupPadInst::CleanupPadInst(const CleanupPadInst &CPI) - : Instruction(CPI.getType(), Instruction::CleanupPad, - OperandTraits<CleanupPadInst>::op_end(this) - - CPI.getNumOperands(), - CPI.getNumOperands()) { - std::copy(CPI.op_begin(), CPI.op_end(), op_begin()); -} - -CleanupPadInst::CleanupPadInst(LLVMContext &C, ArrayRef<Value *> Args, - const Twine &NameStr, Instruction *InsertBefore) - : Instruction(Type::getTokenTy(C), Instruction::CleanupPad, - OperandTraits<CleanupPadInst>::op_end(this) - Args.size(), - Args.size(), InsertBefore) { - init(Args, NameStr); -} - -CleanupPadInst::CleanupPadInst(LLVMContext &C, ArrayRef<Value *> Args, - const Twine &NameStr, BasicBlock *InsertAtEnd) - : Instruction(Type::getTokenTy(C), Instruction::CleanupPad, - OperandTraits<CleanupPadInst>::op_end(this) - Args.size(), - Args.size(), InsertAtEnd) { - init(Args, NameStr); -} - -//===----------------------------------------------------------------------===// // UnreachableInst Implementation //===----------------------------------------------------------------------===// @@ -4074,32 +4009,24 @@ InvokeInst *InvokeInst::cloneImpl() const { ResumeInst *ResumeInst::cloneImpl() const { return new (1) ResumeInst(*this); } -CleanupEndPadInst *CleanupEndPadInst::cloneImpl() const { - return new (getNumOperands()) CleanupEndPadInst(*this); -} - CleanupReturnInst *CleanupReturnInst::cloneImpl() const { return new (getNumOperands()) CleanupReturnInst(*this); } -CatchEndPadInst *CatchEndPadInst::cloneImpl() const { - return new (getNumOperands()) CatchEndPadInst(*this); -} - CatchReturnInst *CatchReturnInst::cloneImpl() const { return new (getNumOperands()) CatchReturnInst(*this); } -CatchPadInst *CatchPadInst::cloneImpl() const { - return new (getNumOperands()) CatchPadInst(*this); +CatchSwitchInst *CatchSwitchInst::cloneImpl() const { + return new CatchSwitchInst(*this); } -TerminatePadInst *TerminatePadInst::cloneImpl() const { - return new (getNumOperands()) TerminatePadInst(*this); +FuncletPadInst *FuncletPadInst::cloneImpl() const { + return new (getNumOperands()) FuncletPadInst(*this); } -CleanupPadInst *CleanupPadInst::cloneImpl() const { - return new (getNumOperands()) CleanupPadInst(*this); +TerminatePadInst *TerminatePadInst::cloneImpl() const { + return new (getNumOperands()) TerminatePadInst(*this); } UnreachableInst *UnreachableInst::cloneImpl() const { diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp index 58f9c5388bf..9862bfcc4fa 100644 --- a/llvm/lib/IR/Verifier.cpp +++ b/llvm/lib/IR/Verifier.cpp @@ -399,9 +399,9 @@ private: void visitEHPadPredecessors(Instruction &I); void visitLandingPadInst(LandingPadInst &LPI); void visitCatchPadInst(CatchPadInst &CPI); - void visitCatchEndPadInst(CatchEndPadInst &CEPI); + void visitCatchReturnInst(CatchReturnInst &CatchReturn); void visitCleanupPadInst(CleanupPadInst &CPI); - void visitCleanupEndPadInst(CleanupEndPadInst &CEPI); + void visitCatchSwitchInst(CatchSwitchInst &CatchSwitch); void visitCleanupReturnInst(CleanupReturnInst &CRI); void visitTerminatePadInst(TerminatePadInst &TPI); @@ -2885,25 +2885,24 @@ void Verifier::visitEHPadPredecessors(Instruction &I) { } return; } + if (auto *CPI = dyn_cast<CatchPadInst>(&I)) { + if (!pred_empty(BB)) + Assert(BB->getUniquePredecessor() == CPI->getCatchSwitch()->getParent(), + "Block containg CatchPadInst must be jumped to " + "only by its catchswitch.", + CPI); + return; + } for (BasicBlock *PredBB : predecessors(BB)) { TerminatorInst *TI = PredBB->getTerminator(); - if (auto *II = dyn_cast<InvokeInst>(TI)) + if (auto *II = dyn_cast<InvokeInst>(TI)) { Assert(II->getUnwindDest() == BB && II->getNormalDest() != BB, "EH pad must be jumped to via an unwind edge", &I, II); - else if (auto *CPI = dyn_cast<CatchPadInst>(TI)) - Assert(CPI->getUnwindDest() == BB && CPI->getNormalDest() != BB, - "EH pad must be jumped to via an unwind edge", &I, CPI); - else if (isa<CatchEndPadInst>(TI)) - ; - else if (isa<CleanupReturnInst>(TI)) - ; - else if (isa<CleanupEndPadInst>(TI)) - ; - else if (isa<TerminatePadInst>(TI)) - ; - else + } else if (!isa<CleanupReturnInst>(TI) && !isa<TerminatePadInst>(TI) && + !isa<CatchSwitchInst>(TI)) { Assert(false, "EH pad must be jumped to via an unwind edge", &I, TI); + } } } @@ -2952,67 +2951,29 @@ void Verifier::visitCatchPadInst(CatchPadInst &CPI) { visitEHPadPredecessors(CPI); BasicBlock *BB = CPI.getParent(); + Function *F = BB->getParent(); Assert(F->hasPersonalityFn(), "CatchPadInst needs to be in a function with a personality.", &CPI); + Assert(isa<CatchSwitchInst>(CPI.getParentPad()), + "CatchPadInst needs to be directly nested in a CatchSwitchInst.", + CPI.getParentPad()); + // The catchpad instruction must be the first non-PHI instruction in the // block. Assert(BB->getFirstNonPHI() == &CPI, - "CatchPadInst not the first non-PHI instruction in the block.", - &CPI); + "CatchPadInst not the first non-PHI instruction in the block.", &CPI); - if (!BB->getSinglePredecessor()) - for (BasicBlock *PredBB : predecessors(BB)) { - Assert(!isa<CatchPadInst>(PredBB->getTerminator()), - "CatchPadInst with CatchPadInst predecessor cannot have any other " - "predecessors.", - &CPI); - } - - BasicBlock *UnwindDest = CPI.getUnwindDest(); - Instruction *I = UnwindDest->getFirstNonPHI(); - Assert( - isa<CatchPadInst>(I) || isa<CatchEndPadInst>(I), - "CatchPadInst must unwind to a CatchPadInst or a CatchEndPadInst.", - &CPI); - - visitTerminatorInst(CPI); + visitInstruction(CPI); } -void Verifier::visitCatchEndPadInst(CatchEndPadInst &CEPI) { - visitEHPadPredecessors(CEPI); - - BasicBlock *BB = CEPI.getParent(); - Function *F = BB->getParent(); - Assert(F->hasPersonalityFn(), - "CatchEndPadInst needs to be in a function with a personality.", - &CEPI); - - // The catchendpad instruction must be the first non-PHI instruction in the - // block. - Assert(BB->getFirstNonPHI() == &CEPI, - "CatchEndPadInst not the first non-PHI instruction in the block.", - &CEPI); - - unsigned CatchPadsSeen = 0; - for (BasicBlock *PredBB : predecessors(BB)) - if (isa<CatchPadInst>(PredBB->getTerminator())) - ++CatchPadsSeen; - - Assert(CatchPadsSeen <= 1, "CatchEndPadInst must have no more than one " - "CatchPadInst predecessor.", - &CEPI); +void Verifier::visitCatchReturnInst(CatchReturnInst &CatchReturn) { + Assert(isa<CatchPadInst>(CatchReturn.getOperand(0)), + "CatchReturnInst needs to be provided a CatchPad", &CatchReturn, + CatchReturn.getOperand(0)); - if (BasicBlock *UnwindDest = CEPI.getUnwindDest()) { - Instruction *I = UnwindDest->getFirstNonPHI(); - Assert( - I->isEHPad() && !isa<LandingPadInst>(I), - "CatchEndPad must unwind to an EH block which is not a landingpad.", - &CEPI); - } - - visitTerminatorInst(CEPI); + visitTerminatorInst(CatchReturn); } void Verifier::visitCleanupPadInst(CleanupPadInst &CPI) { @@ -3030,57 +2991,76 @@ void Verifier::visitCleanupPadInst(CleanupPadInst &CPI) { "CleanupPadInst not the first non-PHI instruction in the block.", &CPI); + auto *ParentPad = CPI.getParentPad(); + Assert(isa<CatchSwitchInst>(ParentPad) || isa<ConstantTokenNone>(ParentPad) || + isa<CleanupPadInst>(ParentPad) || isa<CatchPadInst>(ParentPad), + "CleanupPadInst has an invalid parent.", &CPI); + User *FirstUser = nullptr; BasicBlock *FirstUnwindDest = nullptr; for (User *U : CPI.users()) { BasicBlock *UnwindDest; if (CleanupReturnInst *CRI = dyn_cast<CleanupReturnInst>(U)) { UnwindDest = CRI->getUnwindDest(); + } else if (isa<CleanupPadInst>(U) || isa<CatchSwitchInst>(U) || + isa<TerminatePadInst>(U)) { + continue; } else { - UnwindDest = cast<CleanupEndPadInst>(U)->getUnwindDest(); + Assert(false, "bogus cleanuppad use", &CPI); } if (!FirstUser) { FirstUser = U; FirstUnwindDest = UnwindDest; } else { - Assert(UnwindDest == FirstUnwindDest, - "Cleanuprets/cleanupendpads from the same cleanuppad must " - "have the same unwind destination", - FirstUser, U); + Assert( + UnwindDest == FirstUnwindDest, + "cleanupret instructions from the same cleanuppad must have the same " + "unwind destination", + FirstUser, U); } } visitInstruction(CPI); } -void Verifier::visitCleanupEndPadInst(CleanupEndPadInst &CEPI) { - visitEHPadPredecessors(CEPI); +void Verifier::visitCatchSwitchInst(CatchSwitchInst &CatchSwitch) { + visitEHPadPredecessors(CatchSwitch); + + BasicBlock *BB = CatchSwitch.getParent(); - BasicBlock *BB = CEPI.getParent(); Function *F = BB->getParent(); Assert(F->hasPersonalityFn(), - "CleanupEndPadInst needs to be in a function with a personality.", - &CEPI); + "CatchSwitchInst needs to be in a function with a personality.", + &CatchSwitch); - // The cleanupendpad instruction must be the first non-PHI instruction in the + // The catchswitch instruction must be the first non-PHI instruction in the // block. - Assert(BB->getFirstNonPHI() == &CEPI, - "CleanupEndPadInst not the first non-PHI instruction in the block.", - &CEPI); + Assert(BB->getFirstNonPHI() == &CatchSwitch, + "CatchSwitchInst not the first non-PHI instruction in the block.", + &CatchSwitch); - if (BasicBlock *UnwindDest = CEPI.getUnwindDest()) { + if (BasicBlock *UnwindDest = CatchSwitch.getUnwindDest()) { Instruction *I = UnwindDest->getFirstNonPHI(); - Assert( - I->isEHPad() && !isa<LandingPadInst>(I), - "CleanupEndPad must unwind to an EH block which is not a landingpad.", - &CEPI); + Assert(I->isEHPad() && !isa<LandingPadInst>(I), + "CatchSwitchInst must unwind to an EH block which is not a " + "landingpad.", + &CatchSwitch); } - visitTerminatorInst(CEPI); + auto *ParentPad = CatchSwitch.getParentPad(); + Assert(isa<CatchSwitchInst>(ParentPad) || isa<ConstantTokenNone>(ParentPad) || + isa<CleanupPadInst>(ParentPad) || isa<CatchPadInst>(ParentPad), + "CatchSwitchInst has an invalid parent.", ParentPad); + + visitTerminatorInst(CatchSwitch); } void Verifier::visitCleanupReturnInst(CleanupReturnInst &CRI) { + Assert(isa<CleanupPadInst>(CRI.getOperand(0)), + "CleanupReturnInst needs to be provided a CleanupPad", &CRI, + CRI.getOperand(0)); + if (BasicBlock *UnwindDest = CRI.getUnwindDest()) { Instruction *I = UnwindDest->getFirstNonPHI(); Assert(I->isEHPad() && !isa<LandingPadInst>(I), @@ -3115,6 +3095,11 @@ void Verifier::visitTerminatePadInst(TerminatePadInst &TPI) { &TPI); } + auto *ParentPad = TPI.getParentPad(); + Assert(isa<CatchSwitchInst>(ParentPad) || isa<ConstantTokenNone>(ParentPad) || + isa<CleanupPadInst>(ParentPad) || isa<CatchPadInst>(ParentPad), + "TerminatePadInst has an invalid parent.", ParentPad); + visitTerminatorInst(TPI); } diff --git a/llvm/lib/Target/X86/X86WinEHState.cpp b/llvm/lib/Target/X86/X86WinEHState.cpp index 0276f3969b4..7ceb41662ad 100644 --- a/llvm/lib/Target/X86/X86WinEHState.cpp +++ b/llvm/lib/Target/X86/X86WinEHState.cpp @@ -15,6 +15,7 @@ //===----------------------------------------------------------------------===// #include "X86.h" +#include "llvm/Analysis/CFG.h" #include "llvm/Analysis/EHPersonalities.h" #include "llvm/CodeGen/MachineModuleInfo.h" #include "llvm/CodeGen/Passes.h" @@ -416,20 +417,33 @@ void WinEHStatePass::addStateStores(Function &F, WinEHFuncInfo &FuncInfo) { calculateWinCXXEHStateNumbers(&F, FuncInfo); // Iterate all the instructions and emit state number stores. + DenseMap<BasicBlock *, ColorVector> BlockColors = colorEHFunclets(F); for (BasicBlock &BB : F) { + // Figure out what state we should assign calls in this block. + int BaseState = -1; + auto &BBColors = BlockColors[&BB]; + + assert(BBColors.size() == 1 && + "multi-color BB not removed by preparation"); + BasicBlock *FuncletEntryBB = BBColors.front(); + if (auto *FuncletPad = + dyn_cast<FuncletPadInst>(FuncletEntryBB->getFirstNonPHI())) { + auto BaseStateI = FuncInfo.FuncletBaseStateMap.find(FuncletPad); + if (BaseStateI != FuncInfo.FuncletBaseStateMap.end()) + BaseState = BaseStateI->second; + } + for (Instruction &I : BB) { if (auto *CI = dyn_cast<CallInst>(&I)) { // Possibly throwing call instructions have no actions to take after // an unwind. Ensure they are in the -1 state. if (CI->doesNotThrow()) continue; - insertStateNumberStore(RegNode, CI, -1); + insertStateNumberStore(RegNode, CI, BaseState); } else if (auto *II = dyn_cast<InvokeInst>(&I)) { // Look up the state number of the landingpad this unwinds to. - Instruction *PadInst = II->getUnwindDest()->getFirstNonPHI(); - // FIXME: Why does this assertion fail? - //assert(FuncInfo.EHPadStateMap.count(PadInst) && "EH Pad has no state!"); - int State = FuncInfo.EHPadStateMap[PadInst]; + assert(FuncInfo.InvokeStateMap.count(II) && "invoke has no state!"); + int State = FuncInfo.InvokeStateMap[II]; insertStateNumberStore(RegNode, II, State); } } diff --git a/llvm/lib/Transforms/Instrumentation/MemorySanitizer.cpp b/llvm/lib/Transforms/Instrumentation/MemorySanitizer.cpp index 218e3e96c23..91bb3337509 100644 --- a/llvm/lib/Transforms/Instrumentation/MemorySanitizer.cpp +++ b/llvm/lib/Transforms/Instrumentation/MemorySanitizer.cpp @@ -2684,12 +2684,12 @@ struct MemorySanitizerVisitor : public InstVisitor<MemorySanitizerVisitor> { setOrigin(&I, getCleanOrigin()); } - void visitCleanupPadInst(CleanupPadInst &I) { + void visitCatchSwitchInst(CatchSwitchInst &I) { setShadow(&I, getCleanShadow(&I)); setOrigin(&I, getCleanOrigin()); } - void visitCatchPad(CatchPadInst &I) { + void visitFuncletPadInst(FuncletPadInst &I) { setShadow(&I, getCleanShadow(&I)); setOrigin(&I, getCleanOrigin()); } @@ -2699,16 +2699,6 @@ struct MemorySanitizerVisitor : public InstVisitor<MemorySanitizerVisitor> { // Nothing to do here. } - void visitCatchEndPadInst(CatchEndPadInst &I) { - DEBUG(dbgs() << "CatchEndPad: " << I << "\n"); - // Nothing to do here. - } - - void visitCleanupEndPadInst(CleanupEndPadInst &I) { - DEBUG(dbgs() << "CleanupEndPad: " << I << "\n"); - // Nothing to do here. - } - void visitGetElementPtrInst(GetElementPtrInst &I) { handleShadowOr(I); } diff --git a/llvm/lib/Transforms/Scalar/Reassociate.cpp b/llvm/lib/Transforms/Scalar/Reassociate.cpp index fa2f7d995c6..13d9b6d4fee 100644 --- a/llvm/lib/Transforms/Scalar/Reassociate.cpp +++ b/llvm/lib/Transforms/Scalar/Reassociate.cpp @@ -947,8 +947,6 @@ static Value *NegateValue(Value *V, Instruction *BI, if (Instruction *InstInput = dyn_cast<Instruction>(V)) { if (InvokeInst *II = dyn_cast<InvokeInst>(InstInput)) { InsertPt = II->getNormalDest()->begin(); - } else if (auto *CPI = dyn_cast<CatchPadInst>(InstInput)) { - InsertPt = CPI->getNormalDest()->begin(); } else { InsertPt = ++InstInput->getIterator(); } diff --git a/llvm/lib/Transforms/Scalar/SCCP.cpp b/llvm/lib/Transforms/Scalar/SCCP.cpp index 52281d4e044..2fca803adde 100644 --- a/llvm/lib/Transforms/Scalar/SCCP.cpp +++ b/llvm/lib/Transforms/Scalar/SCCP.cpp @@ -480,8 +480,10 @@ private: void visitExtractValueInst(ExtractValueInst &EVI); void visitInsertValueInst(InsertValueInst &IVI); void visitLandingPadInst(LandingPadInst &I) { markAnythingOverdefined(&I); } - void visitCleanupPadInst(CleanupPadInst &CPI) { markAnythingOverdefined(&CPI); } - void visitCatchPadInst(CatchPadInst &CPI) { + void visitFuncletPadInst(FuncletPadInst &FPI) { + markAnythingOverdefined(&FPI); + } + void visitCatchSwitchInst(CatchSwitchInst &CPI) { markAnythingOverdefined(&CPI); visitTerminatorInst(CPI); } diff --git a/llvm/lib/Transforms/Scalar/Sink.cpp b/llvm/lib/Transforms/Scalar/Sink.cpp index 7c0ac7aa6fa..64109b2df11 100644 --- a/llvm/lib/Transforms/Scalar/Sink.cpp +++ b/llvm/lib/Transforms/Scalar/Sink.cpp @@ -169,7 +169,8 @@ static bool isSafeToMove(Instruction *Inst, AliasAnalysis *AA, return false; } - if (isa<TerminatorInst>(Inst) || isa<PHINode>(Inst) || Inst->isEHPad()) + if (isa<TerminatorInst>(Inst) || isa<PHINode>(Inst) || Inst->isEHPad() || + Inst->mayThrow()) return false; // Convergent operations cannot be made control-dependent on additional @@ -194,6 +195,11 @@ bool Sinking::IsAcceptableTarget(Instruction *Inst, if (Inst->getParent() == SuccToSinkTo) return false; + // It's never legal to sink an instruction into a block which terminates in an + // EH-pad. + if (SuccToSinkTo->getTerminator()->isExceptional()) + return false; + // If the block has multiple predecessors, this would introduce computation // on different code paths. We could split the critical edge, but for now we // just punt. diff --git a/llvm/lib/Transforms/Utils/CodeExtractor.cpp b/llvm/lib/Transforms/Utils/CodeExtractor.cpp index 8ee596e5323..823696d88e6 100644 --- a/llvm/lib/Transforms/Utils/CodeExtractor.cpp +++ b/llvm/lib/Transforms/Utils/CodeExtractor.cpp @@ -560,8 +560,8 @@ emitCallAndSwitchStatement(Function *newFunction, BasicBlock *codeReplacer, // Restore values just before we exit Function::arg_iterator OAI = OutputArgBegin; for (unsigned out = 0, e = outputs.size(); out != e; ++out) { - // For an invoke/catchpad, the normal destination is the only one - // that is dominated by the result of the invocation + // For an invoke, the normal destination is the only one that is + // dominated by the result of the invocation BasicBlock *DefBlock = cast<Instruction>(outputs[out])->getParent(); bool DominatesDef = true; @@ -569,8 +569,6 @@ emitCallAndSwitchStatement(Function *newFunction, BasicBlock *codeReplacer, BasicBlock *NormalDest = nullptr; if (auto *Invoke = dyn_cast<InvokeInst>(outputs[out])) NormalDest = Invoke->getNormalDest(); - if (auto *CatchPad = dyn_cast<CatchPadInst>(outputs[out])) - NormalDest = CatchPad->getNormalDest(); if (NormalDest) { DefBlock = NormalDest; diff --git a/llvm/lib/Transforms/Utils/InlineFunction.cpp b/llvm/lib/Transforms/Utils/InlineFunction.cpp index cafd1818fed..74ece385581 100644 --- a/llvm/lib/Transforms/Utils/InlineFunction.cpp +++ b/llvm/lib/Transforms/Utils/InlineFunction.cpp @@ -21,6 +21,7 @@ #include "llvm/Analysis/AssumptionCache.h" #include "llvm/Analysis/CallGraph.h" #include "llvm/Analysis/CaptureTracking.h" +#include "llvm/Analysis/EHPersonalities.h" #include "llvm/Analysis/InstructionSimplify.h" #include "llvm/Analysis/ValueTracking.h" #include "llvm/IR/Attributes.h" @@ -192,8 +193,6 @@ HandleCallsInBlockInlinedThroughInvoke(BasicBlock *BB, BasicBlock *UnwindEdge) { // instructions require no special handling. CallInst *CI = dyn_cast<CallInst>(I); - // If this call cannot unwind, don't convert it to an invoke. - // Inline asm calls cannot throw. if (!CI || CI->doesNotThrow() || isa<InlineAsm>(CI->getCalledValue())) continue; @@ -327,40 +326,10 @@ static void HandleInlinedEHPad(InvokeInst *II, BasicBlock *FirstNewBlock, } }; - // Forward EH terminator instructions to the caller's invoke destination. - // This is as simple as connect all the instructions which 'unwind to caller' - // to the invoke destination. + // This connects all the instructions which 'unwind to caller' to the invoke + // destination. for (Function::iterator BB = FirstNewBlock->getIterator(), E = Caller->end(); BB != E; ++BB) { - Instruction *I = BB->getFirstNonPHI(); - if (I->isEHPad()) { - if (auto *CEPI = dyn_cast<CatchEndPadInst>(I)) { - if (CEPI->unwindsToCaller()) { - CatchEndPadInst::Create(CEPI->getContext(), UnwindDest, CEPI); - CEPI->eraseFromParent(); - UpdatePHINodes(&*BB); - } - } else if (auto *CEPI = dyn_cast<CleanupEndPadInst>(I)) { - if (CEPI->unwindsToCaller()) { - CleanupEndPadInst::Create(CEPI->getCleanupPad(), UnwindDest, CEPI); - CEPI->eraseFromParent(); - UpdatePHINodes(&*BB); - } - } else if (auto *TPI = dyn_cast<TerminatePadInst>(I)) { - if (TPI->unwindsToCaller()) { - SmallVector<Value *, 3> TerminatePadArgs; - for (Value *ArgOperand : TPI->arg_operands()) - TerminatePadArgs.push_back(ArgOperand); - TerminatePadInst::Create(TPI->getContext(), UnwindDest, - TerminatePadArgs, TPI); - TPI->eraseFromParent(); - UpdatePHINodes(&*BB); - } - } else { - assert(isa<CatchPadInst>(I) || isa<CleanupPadInst>(I)); - } - } - if (auto *CRI = dyn_cast<CleanupReturnInst>(BB->getTerminator())) { if (CRI->unwindsToCaller()) { CleanupReturnInst::Create(CRI->getCleanupPad(), UnwindDest, CRI); @@ -368,6 +337,40 @@ static void HandleInlinedEHPad(InvokeInst *II, BasicBlock *FirstNewBlock, UpdatePHINodes(&*BB); } } + + Instruction *I = BB->getFirstNonPHI(); + if (!I->isEHPad()) + continue; + + Instruction *Replacement = nullptr; + if (auto *TPI = dyn_cast<TerminatePadInst>(I)) { + if (TPI->unwindsToCaller()) { + SmallVector<Value *, 3> TerminatePadArgs; + for (Value *ArgOperand : TPI->arg_operands()) + TerminatePadArgs.push_back(ArgOperand); + Replacement = TerminatePadInst::Create(TPI->getParentPad(), UnwindDest, + TerminatePadArgs, TPI); + } + } else if (auto *CatchSwitch = dyn_cast<CatchSwitchInst>(I)) { + if (CatchSwitch->unwindsToCaller()) { + auto *NewCatchSwitch = CatchSwitchInst::Create( + CatchSwitch->getParentPad(), UnwindDest, + CatchSwitch->getNumHandlers(), CatchSwitch->getName(), + CatchSwitch); + for (BasicBlock *PadBB : CatchSwitch->handlers()) + NewCatchSwitch->addHandler(PadBB); + Replacement = NewCatchSwitch; + } + } else if (!isa<FuncletPadInst>(I)) { + llvm_unreachable("unexpected EHPad!"); + } + + if (Replacement) { + Replacement->takeName(I); + I->replaceAllUsesWith(Replacement); + I->eraseFromParent(); + UpdatePHINodes(&*BB); + } } if (InlinedCodeInfo.ContainsCalls) @@ -1090,6 +1093,53 @@ bool llvm::InlineFunction(CallSite CS, InlineFunctionInfo &IFI, return false; } + // We need to figure out which funclet the callsite was in so that we may + // properly nest the callee. + Instruction *CallSiteEHPad = nullptr; + if (CalledPersonality && CallerPersonality) { + EHPersonality Personality = classifyEHPersonality(CalledPersonality); + if (isFuncletEHPersonality(Personality)) { + DenseMap<BasicBlock *, ColorVector> CallerBlockColors = + colorEHFunclets(*Caller); + ColorVector &CallSiteColors = CallerBlockColors[OrigBB]; + size_t NumColors = CallSiteColors.size(); + // There is no single parent, inlining will not succeed. + if (NumColors > 1) + return false; + if (NumColors == 1) { + BasicBlock *CallSiteFuncletBB = CallSiteColors.front(); + if (CallSiteFuncletBB != Caller->begin()) { + CallSiteEHPad = CallSiteFuncletBB->getFirstNonPHI(); + assert(CallSiteEHPad->isEHPad() && "Expected an EHPad!"); + } + } + + // OK, the inlining site is legal. What about the target function? + + if (CallSiteEHPad) { + if (Personality == EHPersonality::MSVC_CXX) { + // The MSVC personality cannot tolerate catches getting inlined into + // cleanup funclets. + if (isa<CleanupPadInst>(CallSiteEHPad)) { + // Ok, the call site is within a cleanuppad. Let's check the callee + // for catchpads. + for (const BasicBlock &CalledBB : *CalledFunc) { + if (isa<CatchPadInst>(CalledBB.getFirstNonPHI())) + return false; + } + } + } else if (isAsynchronousEHPersonality(Personality)) { + // SEH is even less tolerant, there may not be any sort of exceptional + // funclet in the callee. + for (const BasicBlock &CalledBB : *CalledFunc) { + if (CalledBB.isEHPad()) + return false; + } + } + } + } + } + // Get an iterator to the last basic block in the function, which will have // the new function inlined after it. Function::iterator LastBlock = --Caller->end(); @@ -1381,6 +1431,30 @@ bool llvm::InlineFunction(CallSite CS, InlineFunctionInfo &IFI, } } + // Update the lexical scopes of the new funclets. Anything that had 'none' as + // its parent is now nested inside the callsite's EHPad. + if (CallSiteEHPad) { + for (Function::iterator BB = FirstNewBlock->getIterator(), + E = Caller->end(); + BB != E; ++BB) { + Instruction *I = BB->getFirstNonPHI(); + if (!I->isEHPad()) + continue; + + if (auto *TPI = dyn_cast<TerminatePadInst>(I)) { + if (isa<ConstantTokenNone>(TPI->getParentPad())) + TPI->setParentPad(CallSiteEHPad); + } else if (auto *CatchSwitch = dyn_cast<CatchSwitchInst>(I)) { + if (isa<ConstantTokenNone>(CatchSwitch->getParentPad())) + CatchSwitch->setParentPad(CallSiteEHPad); + } else { + auto *FPI = cast<FuncletPadInst>(I); + if (isa<ConstantTokenNone>(FPI->getParentPad())) + FPI->setParentPad(CallSiteEHPad); + } + } + } + // If we are inlining for an invoke instruction, we must make sure to rewrite // any call instructions into invoke instructions. if (auto *II = dyn_cast<InvokeInst>(TheCall)) { diff --git a/llvm/lib/Transforms/Utils/LCSSA.cpp b/llvm/lib/Transforms/Utils/LCSSA.cpp index 12a8c71d829..ef2f5042169 100644 --- a/llvm/lib/Transforms/Utils/LCSSA.cpp +++ b/llvm/lib/Transforms/Utils/LCSSA.cpp @@ -84,15 +84,13 @@ static bool processInstruction(Loop &L, Instruction &Inst, DominatorTree &DT, ++NumLCSSA; // We are applying the transformation - // Invoke/CatchPad instructions are special in that their result value is not - // available along their unwind edge. The code below tests to see whether - // DomBB dominates the value, so adjust DomBB to the normal destination block, + // Invoke instructions are special in that their result value is not available + // along their unwind edge. The code below tests to see whether DomBB + // dominates the value, so adjust DomBB to the normal destination block, // which is effectively where the value is first usable. BasicBlock *DomBB = Inst.getParent(); if (InvokeInst *Inv = dyn_cast<InvokeInst>(&Inst)) DomBB = Inv->getNormalDest(); - if (auto *CPI = dyn_cast<CatchPadInst>(&Inst)) - DomBB = CPI->getNormalDest(); DomTreeNode *DomNode = DT.getNode(DomBB); diff --git a/llvm/lib/Transforms/Utils/Local.cpp b/llvm/lib/Transforms/Utils/Local.cpp index 391ed685766..cb17b603ae5 100644 --- a/llvm/lib/Transforms/Utils/Local.cpp +++ b/llvm/lib/Transforms/Utils/Local.cpp @@ -1338,19 +1338,22 @@ void llvm::removeUnwindEdge(BasicBlock *BB) { if (auto *CRI = dyn_cast<CleanupReturnInst>(TI)) { NewTI = CleanupReturnInst::Create(CRI->getCleanupPad(), nullptr, CRI); UnwindDest = CRI->getUnwindDest(); - } else if (auto *CEP = dyn_cast<CleanupEndPadInst>(TI)) { - NewTI = CleanupEndPadInst::Create(CEP->getCleanupPad(), nullptr, CEP); - UnwindDest = CEP->getUnwindDest(); - } else if (auto *CEP = dyn_cast<CatchEndPadInst>(TI)) { - NewTI = CatchEndPadInst::Create(CEP->getContext(), nullptr, CEP); - UnwindDest = CEP->getUnwindDest(); } else if (auto *TPI = dyn_cast<TerminatePadInst>(TI)) { SmallVector<Value *, 3> TerminatePadArgs; for (Value *Operand : TPI->arg_operands()) TerminatePadArgs.push_back(Operand); - NewTI = TerminatePadInst::Create(TPI->getContext(), nullptr, + NewTI = TerminatePadInst::Create(TPI->getParentPad(), nullptr, TerminatePadArgs, TPI); UnwindDest = TPI->getUnwindDest(); + } else if (auto *CatchSwitch = dyn_cast<CatchSwitchInst>(TI)) { + auto *NewCatchSwitch = CatchSwitchInst::Create( + CatchSwitch->getParentPad(), nullptr, CatchSwitch->getNumHandlers(), + CatchSwitch->getName(), CatchSwitch); + for (BasicBlock *PadBB : CatchSwitch->handlers()) + NewCatchSwitch->addHandler(PadBB); + + NewTI = NewCatchSwitch; + UnwindDest = CatchSwitch->getUnwindDest(); } else { llvm_unreachable("Could not find unwind successor"); } @@ -1358,6 +1361,7 @@ void llvm::removeUnwindEdge(BasicBlock *BB) { NewTI->takeName(TI); NewTI->setDebugLoc(TI->getDebugLoc()); UnwindDest->removePredecessor(BB); + TI->replaceAllUsesWith(NewTI); TI->eraseFromParent(); } diff --git a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp index fe9fd18292c..cbb8cf234aa 100644 --- a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp +++ b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp @@ -3254,8 +3254,8 @@ bool SimplifyCFGOpt::SimplifyCleanupReturn(CleanupReturnInst *RI) { // updated to continue to the unwind destination of the cleanup pad being // simplified. BasicBlock *BB = RI->getParent(); - Instruction *CPInst = dyn_cast<CleanupPadInst>(BB->getFirstNonPHI()); - if (!CPInst) + CleanupPadInst *CPInst = RI->getCleanupPad(); + if (CPInst->getParent() != BB) // This isn't an empty cleanup. return false; @@ -3265,9 +3265,10 @@ bool SimplifyCFGOpt::SimplifyCleanupReturn(CleanupReturnInst *RI) { if (!isa<DbgInfoIntrinsic>(I)) return false; - // If the cleanup return we are simplifying unwinds to the caller, this - // will set UnwindDest to nullptr. + // If the cleanup return we are simplifying unwinds to the caller, this will + // set UnwindDest to nullptr. BasicBlock *UnwindDest = RI->getUnwindDest(); + Instruction *DestEHPad = UnwindDest ? UnwindDest->getFirstNonPHI() : nullptr; // We're about to remove BB from the control flow. Before we do, sink any // PHINodes into the unwind destination. Doing this before changing the @@ -3278,7 +3279,7 @@ bool SimplifyCFGOpt::SimplifyCleanupReturn(CleanupReturnInst *RI) { // First, go through the PHI nodes in UnwindDest and update any nodes that // reference the block we are removing for (BasicBlock::iterator I = UnwindDest->begin(), - IE = UnwindDest->getFirstNonPHI()->getIterator(); + IE = DestEHPad->getIterator(); I != IE; ++I) { PHINode *DestPN = cast<PHINode>(I); @@ -3322,7 +3323,7 @@ bool SimplifyCFGOpt::SimplifyCleanupReturn(CleanupReturnInst *RI) { } // Sink any remaining PHI nodes directly into UnwindDest. - Instruction *InsertPt = UnwindDest->getFirstNonPHI(); + Instruction *InsertPt = DestEHPad; for (BasicBlock::iterator I = BB->begin(), IE = BB->getFirstNonPHI()->getIterator(); I != IE;) { @@ -3492,18 +3493,16 @@ bool SimplifyCFGOpt::SimplifyUnreachable(UnreachableInst *UI) { } } else if ((isa<InvokeInst>(TI) && cast<InvokeInst>(TI)->getUnwindDest() == BB) || - isa<CatchEndPadInst>(TI) || isa<TerminatePadInst>(TI)) { + isa<TerminatePadInst>(TI) || isa<CatchSwitchInst>(TI)) { removeUnwindEdge(TI->getParent()); Changed = true; - } else if (isa<CleanupReturnInst>(TI) || isa<CleanupEndPadInst>(TI)) { + } else if (isa<CleanupReturnInst>(TI)) { new UnreachableInst(TI->getContext(), TI); TI->eraseFromParent(); Changed = true; } - // TODO: If TI is a CatchPadInst, then (BB must be its normal dest and) - // we can eliminate it, redirecting its preds to its unwind successor, - // or to the next outer handler if the removed catch is the last for its - // catchendpad. + // TODO: We can remove a catchswitch if all it's catchpads end in + // unreachable. } // If this block is now dead, remove it. |