summaryrefslogtreecommitdiffstats
path: root/llvm/lib
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib')
-rw-r--r--llvm/lib/Analysis/CaptureTracking.cpp5
-rw-r--r--llvm/lib/Analysis/EHPersonalities.cpp65
-rw-r--r--llvm/lib/Analysis/InstructionSimplify.cpp6
-rw-r--r--llvm/lib/Analysis/LoopInfo.cpp8
-rw-r--r--llvm/lib/Analysis/ScalarEvolutionExpander.cpp10
-rw-r--r--llvm/lib/Analysis/ValueTracking.cpp3
-rw-r--r--llvm/lib/AsmParser/LLLexer.cpp5
-rw-r--r--llvm/lib/AsmParser/LLParser.cpp284
-rw-r--r--llvm/lib/AsmParser/LLParser.h29
-rw-r--r--llvm/lib/AsmParser/LLToken.h6
-rw-r--r--llvm/lib/Bitcode/Reader/BitcodeReader.cpp234
-rw-r--r--llvm/lib/Bitcode/Writer/BitcodeWriter.cpp62
-rw-r--r--llvm/lib/CodeGen/AsmPrinter/WinException.cpp113
-rw-r--r--llvm/lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp4
-rw-r--r--llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp63
-rw-r--r--llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.h3
-rw-r--r--llvm/lib/CodeGen/TargetLoweringBase.cpp9
-rw-r--r--llvm/lib/CodeGen/WinEHPrepare.cpp1685
-rw-r--r--llvm/lib/IR/AsmWriter.cpp66
-rw-r--r--llvm/lib/IR/Dominators.cpp28
-rw-r--r--llvm/lib/IR/Instruction.cpp9
-rw-r--r--llvm/lib/IR/Instructions.cpp347
-rw-r--r--llvm/lib/IR/Verifier.cpp155
-rw-r--r--llvm/lib/Target/X86/X86WinEHState.cpp24
-rw-r--r--llvm/lib/Transforms/Instrumentation/MemorySanitizer.cpp14
-rw-r--r--llvm/lib/Transforms/Scalar/Reassociate.cpp2
-rw-r--r--llvm/lib/Transforms/Scalar/SCCP.cpp6
-rw-r--r--llvm/lib/Transforms/Scalar/Sink.cpp8
-rw-r--r--llvm/lib/Transforms/Utils/CodeExtractor.cpp6
-rw-r--r--llvm/lib/Transforms/Utils/InlineFunction.cpp142
-rw-r--r--llvm/lib/Transforms/Utils/LCSSA.cpp8
-rw-r--r--llvm/lib/Transforms/Utils/Local.cpp18
-rw-r--r--llvm/lib/Transforms/Utils/SimplifyCFG.cpp23
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.
OpenPOWER on IntegriCloud