#include "llvm/IR/IntrinsicInst.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/PatternMatch.h"
+#include "llvm/MC/MCSymbol.h"
#include "llvm/Pass.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
return new WinEHPrepare(TM);
}
+static bool
+findExceptionalConstructs(Function &Fn,
+ SmallVectorImpl<LandingPadInst *> &LPads,
+ SmallVectorImpl<ResumeInst *> &Resumes,
+ SmallVectorImpl<BasicBlock *> &EntryBlocks) {
+ bool ForExplicitEH = false;
+ for (BasicBlock &BB : Fn) {
+ Instruction *First = BB.getFirstNonPHI();
+ if (auto *LP = dyn_cast<LandingPadInst>(First)) {
+ LPads.push_back(LP);
+ } else if (First->isEHPad()) {
+ if (!ForExplicitEH)
+ EntryBlocks.push_back(&Fn.getEntryBlock());
+ if (!isa<CatchEndPadInst>(First) && !isa<CleanupEndPadInst>(First))
+ EntryBlocks.push_back(&BB);
+ ForExplicitEH = true;
+ }
+ if (auto *Resume = dyn_cast<ResumeInst>(BB.getTerminator()))
+ Resumes.push_back(Resume);
+ }
+ return ForExplicitEH;
+}
+
bool WinEHPrepare::runOnFunction(Function &Fn) {
if (!Fn.hasPersonalityFn())
return false;
// Classify the personality to see what kind of preparation we need.
Personality = classifyEHPersonality(Fn.getPersonalityFn());
- // Do nothing if this is not an MSVC personality.
- if (!isMSVCEHPersonality(Personality))
+ // Do nothing if this is not a funclet-based personality.
+ if (!isFuncletEHPersonality(Personality))
return false;
SmallVector<LandingPadInst *, 4> LPads;
SmallVector<ResumeInst *, 4> Resumes;
SmallVector<BasicBlock *, 4> EntryBlocks;
- bool ForExplicitEH = false;
- for (BasicBlock &BB : Fn) {
- Instruction *First = BB.getFirstNonPHI();
- if (auto *LP = dyn_cast<LandingPadInst>(First)) {
- LPads.push_back(LP);
- } else if (First->isEHPad()) {
- if (!ForExplicitEH)
- EntryBlocks.push_back(&Fn.getEntryBlock());
- if (!isa<CatchEndPadInst>(First) && !isa<CleanupEndPadInst>(First))
- EntryBlocks.push_back(&BB);
- ForExplicitEH = true;
- }
- if (auto *Resume = dyn_cast<ResumeInst>(BB.getTerminator()))
- Resumes.push_back(Resume);
- }
+ bool ForExplicitEH =
+ findExceptionalConstructs(Fn, LPads, Resumes, EntryBlocks);
if (ForExplicitEH)
return prepareExplicitEH(Fn, EntryBlocks);
}
}
-static int addSEHHandler(WinEHFuncInfo &FuncInfo, int ParentState,
- const Function *Filter, const BasicBlock *Handler) {
+static int addSEHExcept(WinEHFuncInfo &FuncInfo, int ParentState,
+ const Function *Filter, const BasicBlock *Handler) {
SEHUnwindMapEntry Entry;
Entry.ToState = ParentState;
+ Entry.IsFinally = false;
Entry.Filter = Filter;
Entry.Handler = Handler;
FuncInfo.SEHUnwindMap.push_back(Entry);
return FuncInfo.SEHUnwindMap.size() - 1;
}
+static int addSEHFinally(WinEHFuncInfo &FuncInfo, int ParentState,
+ const BasicBlock *Handler) {
+ SEHUnwindMapEntry Entry;
+ Entry.ToState = ParentState;
+ Entry.IsFinally = true;
+ Entry.Filter = nullptr;
+ Entry.Handler = Handler;
+ FuncInfo.SEHUnwindMap.push_back(Entry);
+ return FuncInfo.SEHUnwindMap.size() - 1;
+}
+
static void calculateExplicitSEHStateNumbers(WinEHFuncInfo &FuncInfo,
const BasicBlock &BB,
int ParentState) {
"SEH doesn't have multiple handlers per __try");
const CatchPadInst *CPI = Handlers.front();
const BasicBlock *CatchPadBB = CPI->getParent();
- const Function *Filter =
- cast<Function>(CPI->getArgOperand(0)->stripPointerCasts());
+ const Constant *FilterOrNull =
+ cast<Constant>(CPI->getArgOperand(0)->stripPointerCasts());
+ const Function *Filter = dyn_cast<Function>(FilterOrNull);
+ assert((Filter || FilterOrNull->isNullValue()) &&
+ "unexpected filter value");
int TryState =
- addSEHHandler(FuncInfo, ParentState, Filter, CPI->getNormalDest());
+ addSEHExcept(FuncInfo, ParentState, Filter, CPI->getNormalDest());
// Everything in the __try block uses TryState as its parent state.
FuncInfo.EHPadStateMap[CPI] = TryState;
if ((PredBlock = getEHPadFromPredecessor(PredBlock)))
calculateExplicitSEHStateNumbers(FuncInfo, *PredBlock, ParentState);
} else if (isa<CleanupPadInst>(FirstNonPHI)) {
- int CleanupState =
- addSEHHandler(FuncInfo, ParentState, /*Filter=*/nullptr, &BB);
+ int CleanupState = addSEHFinally(FuncInfo, ParentState, &BB);
FuncInfo.EHPadStateMap[FirstNonPHI] = CleanupState;
DEBUG(dbgs() << "Assigning state #" << CleanupState << " to BB "
<< BB.getName() << '\n');
}
}
+static int addClrEHHandler(WinEHFuncInfo &FuncInfo, int ParentState,
+ ClrHandlerType HandlerType, uint32_t TypeToken,
+ const BasicBlock *Handler) {
+ ClrEHUnwindMapEntry Entry;
+ Entry.Parent = ParentState;
+ Entry.Handler = Handler;
+ Entry.HandlerType = HandlerType;
+ Entry.TypeToken = TypeToken;
+ FuncInfo.ClrEHUnwindMap.push_back(Entry);
+ return FuncInfo.ClrEHUnwindMap.size() - 1;
+}
+
+void llvm::calculateClrEHStateNumbers(const Function *Fn,
+ WinEHFuncInfo &FuncInfo) {
+ // Return if it's already been done.
+ if (!FuncInfo.EHPadStateMap.empty())
+ return;
+
+ SmallVector<std::pair<const Instruction *, int>, 8> Worklist;
+
+ // Each pad needs to be able to refer to its parent, so scan the function
+ // looking for top-level handlers and seed the worklist with them.
+ for (const BasicBlock &BB : *Fn) {
+ if (!BB.isEHPad())
+ continue;
+ if (BB.isLandingPad())
+ report_fatal_error("CoreCLR EH cannot use landingpads");
+ const Instruction *FirstNonPHI = BB.getFirstNonPHI();
+ if (!doesEHPadUnwindToCaller(FirstNonPHI))
+ continue;
+ // queue this with sentinel parent state -1 to mean unwind to caller.
+ Worklist.emplace_back(FirstNonPHI, -1);
+ }
+
+ while (!Worklist.empty()) {
+ const Instruction *Pad;
+ int ParentState;
+ std::tie(Pad, ParentState) = Worklist.pop_back_val();
+
+ 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)) {
+ // A cleanup can have multiple exits; don't re-process after the first.
+ if (FuncInfo.EHPadStateMap.count(Pad))
+ continue;
+ // CoreCLR personality uses arity to distinguish faults from finallies.
+ const BasicBlock *PadBlock = Cleanup->getParent();
+ ClrHandlerType HandlerType =
+ (Cleanup->getNumOperands() ? ClrHandlerType::Fault
+ : ClrHandlerType::Finally);
+ int NewState =
+ addClrEHHandler(FuncInfo, ParentState, HandlerType, 0, PadBlock);
+ FuncInfo.EHPadStateMap[Cleanup] = NewState;
+ // Propagate the new state to all preds of the cleanup
+ 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 *Handler = Catch->getNormalDest();
+ uint32_t TypeToken = static_cast<uint32_t>(
+ cast<ConstantInt>(Catch->getArgOperand(0))->getZExtValue());
+ int NewState = addClrEHHandler(FuncInfo, ParentState,
+ ClrHandlerType::Catch, TypeToken, Handler);
+ FuncInfo.EHPadStateMap[Catch] = NewState;
+ // Preds of the catch get its state
+ PredState = NewState;
+ } else {
+ llvm_unreachable("Unexpected EH pad");
+ }
+
+ // Queue all predecessors with the given state
+ for (const BasicBlock *Pred : predecessors(Pad->getParent())) {
+ if ((Pred = getEHPadFromPredecessor(Pred)))
+ Worklist.emplace_back(Pred->getFirstNonPHI(), PredState);
+ }
+ }
+}
+
void WinEHPrepare::replaceTerminatePadWithCleanup(Function &F) {
if (Personality != EHPersonality::MSVC_CXX)
return;
}
}
-void WinEHPrepare::colorFunclets(Function &F,
- SmallVectorImpl<BasicBlock *> &EntryBlocks) {
+static void
+colorFunclets(Function &F, SmallVectorImpl<BasicBlock *> &EntryBlocks,
+ std::map<BasicBlock *, std::set<BasicBlock *>> &BlockColors,
+ std::map<BasicBlock *, std::set<BasicBlock *>> &FuncletBlocks,
+ std::map<BasicBlock *, std::set<BasicBlock *>> &FuncletChildren) {
SmallVector<std::pair<BasicBlock *, BasicBlock *>, 16> Worklist;
BasicBlock *EntryBlock = &F.getEntryBlock();
}
}
+void WinEHPrepare::colorFunclets(Function &F,
+ SmallVectorImpl<BasicBlock *> &EntryBlocks) {
+ ::colorFunclets(F, EntryBlocks, BlockColors, FuncletBlocks, FuncletChildren);
+}
+
+void llvm::calculateCatchReturnSuccessorColors(const Function *Fn,
+ WinEHFuncInfo &FuncInfo) {
+ SmallVector<LandingPadInst *, 4> LPads;
+ SmallVector<ResumeInst *, 4> Resumes;
+ SmallVector<BasicBlock *, 4> EntryBlocks;
+ // colorFunclets needs the set of EntryBlocks, get them using
+ // findExceptionalConstructs.
+ bool ForExplicitEH = findExceptionalConstructs(const_cast<Function &>(*Fn),
+ LPads, Resumes, EntryBlocks);
+ if (!ForExplicitEH)
+ return;
+
+ std::map<BasicBlock *, std::set<BasicBlock *>> BlockColors;
+ std::map<BasicBlock *, std::set<BasicBlock *>> FuncletBlocks;
+ std::map<BasicBlock *, std::set<BasicBlock *>> FuncletChildren;
+ // Figure out which basic blocks belong to which funclets.
+ colorFunclets(const_cast<Function &>(*Fn), EntryBlocks, BlockColors,
+ FuncletBlocks, FuncletChildren);
+
+ // 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)
+ continue;
+
+ // The users of a catchpad are always catchrets.
+ for (User *Exit : CatchPad->users()) {
+ auto *CatchReturn = cast<CatchReturnInst>(Exit);
+ BasicBlock *CatchRetSuccessor = CatchReturn->getSuccessor();
+ std::set<BasicBlock *> &SuccessorColors = BlockColors[CatchRetSuccessor];
+ assert(SuccessorColors.size() == 1 && "Expected BB to be monochrome!");
+ BasicBlock *Color = *SuccessorColors.begin();
+ if (auto *CPI = dyn_cast<CatchPadInst>(Color->getFirstNonPHI()))
+ Color = CPI->getNormalDest();
+ // Record the catchret successor's funclet membership.
+ FuncInfo.CatchRetSuccessorColorMap[CatchReturn] = Color;
+ }
+ }
+}
+
void WinEHPrepare::demotePHIsOnFunclets(Function &F) {
// Strip PHI nodes off of EH pads.
SmallVector<PHINode *, 16> PHINodes;
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();
}
+ // FIXME: Check for invokes/cleanuprets/cleanupendpads which unwind to
+ // implausible catchendpads (i.e. catchendpad not in immediate parent
+ // funclet).
}
}
}
U.set(Load);
}
}
+
+void WinEHFuncInfo::addIPToStateRange(const BasicBlock *PadBB,
+ 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);
+}