Skip to content

Commit

Permalink
[WinEH] Implement state numbering for CoreCLR
Browse files Browse the repository at this point in the history
Summary:
Assign one state number per handler/funclet, tracking parent state,
handler type, and catch type token.
State numbers are arranged such that ancestors have lower state numbers
than their descendants.

Reviewers: majnemer, andrew.w.kaylor, rnk

Subscribers: pgavlin, AndyAyers, llvm-commits

Differential Revision: http://reviews.llvm.org/D13450

llvm-svn: 249457
  • Loading branch information
JosephTremoulet committed Oct 6, 2015
1 parent 07a1c45 commit 7f8c116
Show file tree
Hide file tree
Showing 3 changed files with 103 additions and 0 deletions.
12 changes: 12 additions & 0 deletions llvm/include/llvm/CodeGen/WinEHFuncInfo.h
Expand Up @@ -161,6 +161,15 @@ struct WinEHTryBlockMapEntry {
SmallVector<WinEHHandlerType, 1> HandlerArray;
};

enum class ClrHandlerType { Catch, Finally, Fault, Filter };

struct ClrEHUnwindMapEntry {
MBBOrBasicBlock Handler;
uint32_t TypeToken;
int Parent;
ClrHandlerType HandlerType;
};

struct WinEHFuncInfo {
DenseMap<const Instruction *, int> EHPadStateMap;
DenseMap<const CatchReturnInst *, const BasicBlock *>
Expand All @@ -169,6 +178,7 @@ struct WinEHFuncInfo {
SmallVector<WinEHUnwindMapEntry, 4> UnwindMap;
SmallVector<WinEHTryBlockMapEntry, 4> TryBlockMap;
SmallVector<SEHUnwindMapEntry, 4> SEHUnwindMap;
SmallVector<ClrEHUnwindMapEntry, 4> ClrEHUnwindMap;
int UnwindHelpFrameIdx = INT_MAX;
int UnwindHelpFrameOffset = -1;

Expand Down Expand Up @@ -196,6 +206,8 @@ void calculateWinCXXEHStateNumbers(const Function *ParentFn,
void calculateSEHStateNumbers(const Function *ParentFn,
WinEHFuncInfo &FuncInfo);

void calculateClrEHStateNumbers(const Function *Fn, WinEHFuncInfo &FuncInfo);

void calculateCatchReturnSuccessorColors(const Function *Fn,
WinEHFuncInfo &FuncInfo);
}
Expand Down
6 changes: 6 additions & 0 deletions llvm/lib/CodeGen/SelectionDAG/FunctionLoweringInfo.cpp
Expand Up @@ -292,6 +292,8 @@ void FunctionLoweringInfo::set(const Function &fn, MachineFunction &mf,
calculateWinCXXEHStateNumbers(WinEHParentFn, EHInfo);
else if (isAsynchronousEHPersonality(Personality))
calculateSEHStateNumbers(WinEHParentFn, EHInfo);
else if (Personality == EHPersonality::CoreCLR)
calculateClrEHStateNumbers(WinEHParentFn, EHInfo);

calculateCatchReturnSuccessorColors(WinEHParentFn, EHInfo);

Expand All @@ -316,6 +318,10 @@ void FunctionLoweringInfo::set(const Function &fn, MachineFunction &mf,
const BasicBlock *BB = UME.Handler.get<const BasicBlock *>();
UME.Handler = MBBMap[BB];
}
for (ClrEHUnwindMapEntry &CME : EHInfo.ClrEHUnwindMap) {
const BasicBlock *BB = CME.Handler.get<const BasicBlock *>();
CME.Handler = MBBMap[BB];
}

// If there's an explicit EH registration node on the stack, record its
// frame index.
Expand Down
85 changes: 85 additions & 0 deletions llvm/lib/CodeGen/WinEHPrepare.cpp
Expand Up @@ -2864,6 +2864,91 @@ void llvm::calculateWinCXXEHStateNumbers(const Function *Fn,
}
}

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;
Expand Down

0 comments on commit 7f8c116

Please sign in to comment.