mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-12-20 03:17:48 +00:00
[WinEH] Start inserting state number stores for C++ EH
This moves all the state numbering code for C++ EH to WinEHPrepare so that we can call it from the X86 state numbering IR pass that runs before isel. Now we just call the same state numbering machinery and insert a bunch of stores. It also populates MachineModuleInfo with information about the current function. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@238514 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
@@ -23,6 +23,7 @@ class BasicBlock;
|
|||||||
class Constant;
|
class Constant;
|
||||||
class Function;
|
class Function;
|
||||||
class GlobalVariable;
|
class GlobalVariable;
|
||||||
|
class InvokeInst;
|
||||||
class IntrinsicInst;
|
class IntrinsicInst;
|
||||||
class LandingPadInst;
|
class LandingPadInst;
|
||||||
class MCSymbol;
|
class MCSymbol;
|
||||||
@@ -153,5 +154,11 @@ struct WinEHFuncInfo {
|
|||||||
NumIPToStateFuncsVisited(0) {}
|
NumIPToStateFuncsVisited(0) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Analyze the IR in ParentFn and it's handlers to build WinEHFuncInfo, which
|
||||||
|
/// describes the state numbers and tables used by __CxxFrameHandler3. This
|
||||||
|
/// analysis assumes that WinEHPrepare has already been run.
|
||||||
|
void calculateWinCXXEHStateNumbers(const Function *ParentFn,
|
||||||
|
WinEHFuncInfo &FuncInfo);
|
||||||
|
|
||||||
}
|
}
|
||||||
#endif // LLVM_CODEGEN_WINEHFUNCINFO_H
|
#endif // LLVM_CODEGEN_WINEHFUNCINFO_H
|
||||||
|
|||||||
@@ -80,33 +80,6 @@ static ISD::NodeType getPreferredExtendForValue(const Value *V) {
|
|||||||
return ExtendKind;
|
return ExtendKind;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace {
|
|
||||||
struct WinEHNumbering {
|
|
||||||
WinEHNumbering(WinEHFuncInfo &FuncInfo) : FuncInfo(FuncInfo),
|
|
||||||
CurrentBaseState(-1), NextState(0) {}
|
|
||||||
|
|
||||||
WinEHFuncInfo &FuncInfo;
|
|
||||||
int CurrentBaseState;
|
|
||||||
int NextState;
|
|
||||||
|
|
||||||
SmallVector<std::unique_ptr<ActionHandler>, 4> HandlerStack;
|
|
||||||
SmallPtrSet<const Function *, 4> VisitedHandlers;
|
|
||||||
|
|
||||||
int currentEHNumber() const {
|
|
||||||
return HandlerStack.empty() ? CurrentBaseState : HandlerStack.back()->getEHState();
|
|
||||||
}
|
|
||||||
|
|
||||||
void createUnwindMapEntry(int ToState, ActionHandler *AH);
|
|
||||||
void createTryBlockMapEntry(int TryLow, int TryHigh,
|
|
||||||
ArrayRef<CatchHandler *> Handlers);
|
|
||||||
void processCallSite(MutableArrayRef<std::unique_ptr<ActionHandler>> Actions,
|
|
||||||
ImmutableCallSite CS);
|
|
||||||
void popUnmatchedActions(int FirstMismatch);
|
|
||||||
void calculateStateNumbers(const Function &F);
|
|
||||||
void findActionRootLPads(const Function &F);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
void FunctionLoweringInfo::set(const Function &fn, MachineFunction &mf,
|
void FunctionLoweringInfo::set(const Function &fn, MachineFunction &mf,
|
||||||
SelectionDAG *DAG) {
|
SelectionDAG *DAG) {
|
||||||
Fn = &fn;
|
Fn = &fn;
|
||||||
@@ -291,31 +264,18 @@ void FunctionLoweringInfo::set(const Function &fn, MachineFunction &mf,
|
|||||||
if (!isMSVCEHPersonality(Personality))
|
if (!isMSVCEHPersonality(Personality))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
WinEHFuncInfo *EHInfo = nullptr;
|
|
||||||
if (Personality == EHPersonality::MSVC_Win64SEH) {
|
if (Personality == EHPersonality::MSVC_Win64SEH) {
|
||||||
addSEHHandlersForLPads(LPads);
|
addSEHHandlersForLPads(LPads);
|
||||||
} else if (Personality == EHPersonality::MSVC_CXX) {
|
} else if (Personality == EHPersonality::MSVC_CXX) {
|
||||||
const Function *WinEHParentFn = MMI.getWinEHParent(&fn);
|
const Function *WinEHParentFn = MMI.getWinEHParent(&fn);
|
||||||
EHInfo = &MMI.getWinEHFuncInfo(WinEHParentFn);
|
WinEHFuncInfo &EHInfo = MMI.getWinEHFuncInfo(WinEHParentFn);
|
||||||
if (EHInfo->LandingPadStateMap.empty()) {
|
calculateWinCXXEHStateNumbers(WinEHParentFn, EHInfo);
|
||||||
WinEHNumbering Num(*EHInfo);
|
|
||||||
Num.findActionRootLPads(*WinEHParentFn);
|
|
||||||
// The VisitedHandlers list is used by both findActionRootLPads and
|
|
||||||
// calculateStateNumbers, but both functions need to visit all handlers.
|
|
||||||
Num.VisitedHandlers.clear();
|
|
||||||
Num.calculateStateNumbers(*WinEHParentFn);
|
|
||||||
// Pop everything on the handler stack.
|
|
||||||
// It may be necessary to call this more than once because a handler can
|
|
||||||
// be pushed on the stack as a result of clearing the stack.
|
|
||||||
while (!Num.HandlerStack.empty())
|
|
||||||
Num.processCallSite(None, ImmutableCallSite());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Copy the state numbers to LandingPadInfo for the current function, which
|
// Copy the state numbers to LandingPadInfo for the current function, which
|
||||||
// could be a handler or the parent.
|
// could be a handler or the parent.
|
||||||
for (const LandingPadInst *LP : LPads) {
|
for (const LandingPadInst *LP : LPads) {
|
||||||
MachineBasicBlock *LPadMBB = MBBMap[LP->getParent()];
|
MachineBasicBlock *LPadMBB = MBBMap[LP->getParent()];
|
||||||
MMI.addWinEHState(LPadMBB, EHInfo->LandingPadStateMap[LP]);
|
MMI.addWinEHState(LPadMBB, EHInfo.LandingPadStateMap[LP]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -358,334 +318,6 @@ void FunctionLoweringInfo::addSEHHandlersForLPads(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void WinEHNumbering::createUnwindMapEntry(int ToState, ActionHandler *AH) {
|
|
||||||
WinEHUnwindMapEntry UME;
|
|
||||||
UME.ToState = ToState;
|
|
||||||
if (auto *CH = dyn_cast_or_null<CleanupHandler>(AH))
|
|
||||||
UME.Cleanup = cast<Function>(CH->getHandlerBlockOrFunc());
|
|
||||||
else
|
|
||||||
UME.Cleanup = nullptr;
|
|
||||||
FuncInfo.UnwindMap.push_back(UME);
|
|
||||||
}
|
|
||||||
|
|
||||||
void WinEHNumbering::createTryBlockMapEntry(int TryLow, int TryHigh,
|
|
||||||
ArrayRef<CatchHandler *> Handlers) {
|
|
||||||
// See if we already have an entry for this set of handlers.
|
|
||||||
// This is using iterators rather than a range-based for loop because
|
|
||||||
// if we find the entry we're looking for we'll need the iterator to erase it.
|
|
||||||
int NumHandlers = Handlers.size();
|
|
||||||
auto I = FuncInfo.TryBlockMap.begin();
|
|
||||||
auto E = FuncInfo.TryBlockMap.end();
|
|
||||||
for ( ; I != E; ++I) {
|
|
||||||
auto &Entry = *I;
|
|
||||||
if (Entry.HandlerArray.size() != (size_t)NumHandlers)
|
|
||||||
continue;
|
|
||||||
int N;
|
|
||||||
for (N = 0; N < NumHandlers; ++N) {
|
|
||||||
if (Entry.HandlerArray[N].Handler != Handlers[N]->getHandlerBlockOrFunc())
|
|
||||||
break; // breaks out of inner loop
|
|
||||||
}
|
|
||||||
// If all the handlers match, this is what we were looking for.
|
|
||||||
if (N == NumHandlers) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we found an existing entry for this set of handlers, extend the range
|
|
||||||
// but move the entry to the end of the map vector. The order of entries
|
|
||||||
// in the map is critical to the way that the runtime finds handlers.
|
|
||||||
// FIXME: Depending on what has happened with block ordering, this may
|
|
||||||
// incorrectly combine entries that should remain separate.
|
|
||||||
if (I != E) {
|
|
||||||
// Copy the existing entry.
|
|
||||||
WinEHTryBlockMapEntry Entry = *I;
|
|
||||||
Entry.TryLow = std::min(TryLow, Entry.TryLow);
|
|
||||||
Entry.TryHigh = std::max(TryHigh, Entry.TryHigh);
|
|
||||||
assert(Entry.TryLow <= Entry.TryHigh);
|
|
||||||
// Erase the old entry and add this one to the back.
|
|
||||||
FuncInfo.TryBlockMap.erase(I);
|
|
||||||
FuncInfo.TryBlockMap.push_back(Entry);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we didn't find an entry, create a new one.
|
|
||||||
WinEHTryBlockMapEntry TBME;
|
|
||||||
TBME.TryLow = TryLow;
|
|
||||||
TBME.TryHigh = TryHigh;
|
|
||||||
assert(TBME.TryLow <= TBME.TryHigh);
|
|
||||||
for (CatchHandler *CH : Handlers) {
|
|
||||||
WinEHHandlerType HT;
|
|
||||||
if (CH->getSelector()->isNullValue()) {
|
|
||||||
HT.Adjectives = 0x40;
|
|
||||||
HT.TypeDescriptor = nullptr;
|
|
||||||
} else {
|
|
||||||
auto *GV = cast<GlobalVariable>(CH->getSelector()->stripPointerCasts());
|
|
||||||
// Selectors are always pointers to GlobalVariables with 'struct' type.
|
|
||||||
// The struct has two fields, adjectives and a type descriptor.
|
|
||||||
auto *CS = cast<ConstantStruct>(GV->getInitializer());
|
|
||||||
HT.Adjectives =
|
|
||||||
cast<ConstantInt>(CS->getAggregateElement(0U))->getZExtValue();
|
|
||||||
HT.TypeDescriptor =
|
|
||||||
cast<GlobalVariable>(CS->getAggregateElement(1)->stripPointerCasts());
|
|
||||||
}
|
|
||||||
HT.Handler = cast<Function>(CH->getHandlerBlockOrFunc());
|
|
||||||
HT.CatchObjRecoverIdx = CH->getExceptionVarIndex();
|
|
||||||
TBME.HandlerArray.push_back(HT);
|
|
||||||
}
|
|
||||||
FuncInfo.TryBlockMap.push_back(TBME);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void print_name(const Value *V) {
|
|
||||||
#ifndef NDEBUG
|
|
||||||
if (!V) {
|
|
||||||
DEBUG(dbgs() << "null");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (const auto *F = dyn_cast<Function>(V))
|
|
||||||
DEBUG(dbgs() << F->getName());
|
|
||||||
else
|
|
||||||
DEBUG(V->dump());
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
void WinEHNumbering::processCallSite(
|
|
||||||
MutableArrayRef<std::unique_ptr<ActionHandler>> Actions,
|
|
||||||
ImmutableCallSite CS) {
|
|
||||||
DEBUG(dbgs() << "processCallSite (EH state = " << currentEHNumber()
|
|
||||||
<< ") for: ");
|
|
||||||
print_name(CS ? CS.getCalledValue() : nullptr);
|
|
||||||
DEBUG(dbgs() << '\n');
|
|
||||||
|
|
||||||
DEBUG(dbgs() << "HandlerStack: \n");
|
|
||||||
for (int I = 0, E = HandlerStack.size(); I < E; ++I) {
|
|
||||||
DEBUG(dbgs() << " ");
|
|
||||||
print_name(HandlerStack[I]->getHandlerBlockOrFunc());
|
|
||||||
DEBUG(dbgs() << '\n');
|
|
||||||
}
|
|
||||||
DEBUG(dbgs() << "Actions: \n");
|
|
||||||
for (int I = 0, E = Actions.size(); I < E; ++I) {
|
|
||||||
DEBUG(dbgs() << " ");
|
|
||||||
print_name(Actions[I]->getHandlerBlockOrFunc());
|
|
||||||
DEBUG(dbgs() << '\n');
|
|
||||||
}
|
|
||||||
int FirstMismatch = 0;
|
|
||||||
for (int E = std::min(HandlerStack.size(), Actions.size()); FirstMismatch < E;
|
|
||||||
++FirstMismatch) {
|
|
||||||
if (HandlerStack[FirstMismatch]->getHandlerBlockOrFunc() !=
|
|
||||||
Actions[FirstMismatch]->getHandlerBlockOrFunc())
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove unmatched actions from the stack and process their EH states.
|
|
||||||
popUnmatchedActions(FirstMismatch);
|
|
||||||
|
|
||||||
DEBUG(dbgs() << "Pushing actions for CallSite: ");
|
|
||||||
print_name(CS ? CS.getCalledValue() : nullptr);
|
|
||||||
DEBUG(dbgs() << '\n');
|
|
||||||
|
|
||||||
bool LastActionWasCatch = false;
|
|
||||||
const LandingPadInst *LastRootLPad = nullptr;
|
|
||||||
for (size_t I = FirstMismatch; I != Actions.size(); ++I) {
|
|
||||||
// We can reuse eh states when pushing two catches for the same invoke.
|
|
||||||
bool CurrActionIsCatch = isa<CatchHandler>(Actions[I].get());
|
|
||||||
auto *Handler = cast<Function>(Actions[I]->getHandlerBlockOrFunc());
|
|
||||||
// Various conditions can lead to a handler being popped from the
|
|
||||||
// stack and re-pushed later. That shouldn't create a new state.
|
|
||||||
// FIXME: Can code optimization lead to re-used handlers?
|
|
||||||
if (FuncInfo.HandlerEnclosedState.count(Handler)) {
|
|
||||||
// If we already assigned the state enclosed by this handler re-use it.
|
|
||||||
Actions[I]->setEHState(FuncInfo.HandlerEnclosedState[Handler]);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
const LandingPadInst* RootLPad = FuncInfo.RootLPad[Handler];
|
|
||||||
if (CurrActionIsCatch && LastActionWasCatch && RootLPad == LastRootLPad) {
|
|
||||||
DEBUG(dbgs() << "setEHState for handler to " << currentEHNumber() << "\n");
|
|
||||||
Actions[I]->setEHState(currentEHNumber());
|
|
||||||
} else {
|
|
||||||
DEBUG(dbgs() << "createUnwindMapEntry(" << currentEHNumber() << ", ");
|
|
||||||
print_name(Actions[I]->getHandlerBlockOrFunc());
|
|
||||||
DEBUG(dbgs() << ") with EH state " << NextState << "\n");
|
|
||||||
createUnwindMapEntry(currentEHNumber(), Actions[I].get());
|
|
||||||
DEBUG(dbgs() << "setEHState for handler to " << NextState << "\n");
|
|
||||||
Actions[I]->setEHState(NextState);
|
|
||||||
NextState++;
|
|
||||||
}
|
|
||||||
HandlerStack.push_back(std::move(Actions[I]));
|
|
||||||
LastActionWasCatch = CurrActionIsCatch;
|
|
||||||
LastRootLPad = RootLPad;
|
|
||||||
}
|
|
||||||
|
|
||||||
// This is used to defer numbering states for a handler until after the
|
|
||||||
// last time it appears in an invoke action list.
|
|
||||||
if (CS.isInvoke()) {
|
|
||||||
for (int I = 0, E = HandlerStack.size(); I < E; ++I) {
|
|
||||||
auto *Handler = cast<Function>(HandlerStack[I]->getHandlerBlockOrFunc());
|
|
||||||
if (FuncInfo.LastInvoke[Handler] != cast<InvokeInst>(CS.getInstruction()))
|
|
||||||
continue;
|
|
||||||
FuncInfo.LastInvokeVisited[Handler] = true;
|
|
||||||
DEBUG(dbgs() << "Last invoke of ");
|
|
||||||
print_name(Handler);
|
|
||||||
DEBUG(dbgs() << " has been visited.\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
DEBUG(dbgs() << "In EHState " << currentEHNumber() << " for CallSite: ");
|
|
||||||
print_name(CS ? CS.getCalledValue() : nullptr);
|
|
||||||
DEBUG(dbgs() << '\n');
|
|
||||||
}
|
|
||||||
|
|
||||||
void WinEHNumbering::popUnmatchedActions(int FirstMismatch) {
|
|
||||||
// Don't recurse while we are looping over the handler stack. Instead, defer
|
|
||||||
// the numbering of the catch handlers until we are done popping.
|
|
||||||
SmallVector<CatchHandler *, 4> PoppedCatches;
|
|
||||||
for (int I = HandlerStack.size() - 1; I >= FirstMismatch; --I) {
|
|
||||||
std::unique_ptr<ActionHandler> Handler = HandlerStack.pop_back_val();
|
|
||||||
if (isa<CatchHandler>(Handler.get()))
|
|
||||||
PoppedCatches.push_back(cast<CatchHandler>(Handler.release()));
|
|
||||||
}
|
|
||||||
|
|
||||||
int TryHigh = NextState - 1;
|
|
||||||
int LastTryLowIdx = 0;
|
|
||||||
for (int I = 0, E = PoppedCatches.size(); I != E; ++I) {
|
|
||||||
CatchHandler *CH = PoppedCatches[I];
|
|
||||||
DEBUG(dbgs() << "Popped handler with state " << CH->getEHState() << "\n");
|
|
||||||
if (I + 1 == E || CH->getEHState() != PoppedCatches[I + 1]->getEHState()) {
|
|
||||||
int TryLow = CH->getEHState();
|
|
||||||
auto Handlers =
|
|
||||||
makeArrayRef(&PoppedCatches[LastTryLowIdx], I - LastTryLowIdx + 1);
|
|
||||||
DEBUG(dbgs() << "createTryBlockMapEntry(" << TryLow << ", " << TryHigh);
|
|
||||||
for (size_t J = 0; J < Handlers.size(); ++J) {
|
|
||||||
DEBUG(dbgs() << ", ");
|
|
||||||
print_name(Handlers[J]->getHandlerBlockOrFunc());
|
|
||||||
}
|
|
||||||
DEBUG(dbgs() << ")\n");
|
|
||||||
createTryBlockMapEntry(TryLow, TryHigh, Handlers);
|
|
||||||
LastTryLowIdx = I + 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (CatchHandler *CH : PoppedCatches) {
|
|
||||||
if (auto *F = dyn_cast<Function>(CH->getHandlerBlockOrFunc())) {
|
|
||||||
if (FuncInfo.LastInvokeVisited[F]) {
|
|
||||||
DEBUG(dbgs() << "Assigning base state " << NextState << " to ");
|
|
||||||
print_name(F);
|
|
||||||
DEBUG(dbgs() << '\n');
|
|
||||||
FuncInfo.HandlerBaseState[F] = NextState;
|
|
||||||
DEBUG(dbgs() << "createUnwindMapEntry(" << currentEHNumber()
|
|
||||||
<< ", null)\n");
|
|
||||||
createUnwindMapEntry(currentEHNumber(), nullptr);
|
|
||||||
++NextState;
|
|
||||||
calculateStateNumbers(*F);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
DEBUG(dbgs() << "Deferring handling of ");
|
|
||||||
print_name(F);
|
|
||||||
DEBUG(dbgs() << " until last invoke visited.\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
delete CH;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void WinEHNumbering::calculateStateNumbers(const Function &F) {
|
|
||||||
auto I = VisitedHandlers.insert(&F);
|
|
||||||
if (!I.second)
|
|
||||||
return; // We've already visited this handler, don't renumber it.
|
|
||||||
|
|
||||||
int OldBaseState = CurrentBaseState;
|
|
||||||
if (FuncInfo.HandlerBaseState.count(&F)) {
|
|
||||||
CurrentBaseState = FuncInfo.HandlerBaseState[&F];
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t SavedHandlerStackSize = HandlerStack.size();
|
|
||||||
|
|
||||||
DEBUG(dbgs() << "Calculating state numbers for: " << F.getName() << '\n');
|
|
||||||
SmallVector<std::unique_ptr<ActionHandler>, 4> ActionList;
|
|
||||||
for (const BasicBlock &BB : F) {
|
|
||||||
for (const Instruction &I : BB) {
|
|
||||||
const auto *CI = dyn_cast<CallInst>(&I);
|
|
||||||
if (!CI || CI->doesNotThrow())
|
|
||||||
continue;
|
|
||||||
processCallSite(None, CI);
|
|
||||||
}
|
|
||||||
const auto *II = dyn_cast<InvokeInst>(BB.getTerminator());
|
|
||||||
if (!II)
|
|
||||||
continue;
|
|
||||||
const LandingPadInst *LPI = II->getLandingPadInst();
|
|
||||||
auto *ActionsCall = dyn_cast<IntrinsicInst>(LPI->getNextNode());
|
|
||||||
if (!ActionsCall)
|
|
||||||
continue;
|
|
||||||
assert(ActionsCall->getIntrinsicID() == Intrinsic::eh_actions);
|
|
||||||
parseEHActions(ActionsCall, ActionList);
|
|
||||||
if (ActionList.empty())
|
|
||||||
continue;
|
|
||||||
processCallSite(ActionList, II);
|
|
||||||
ActionList.clear();
|
|
||||||
FuncInfo.LandingPadStateMap[LPI] = currentEHNumber();
|
|
||||||
DEBUG(dbgs() << "Assigning state " << currentEHNumber()
|
|
||||||
<< " to landing pad at " << LPI->getParent()->getName()
|
|
||||||
<< '\n');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Pop any actions that were pushed on the stack for this function.
|
|
||||||
popUnmatchedActions(SavedHandlerStackSize);
|
|
||||||
|
|
||||||
DEBUG(dbgs() << "Assigning max state " << NextState - 1
|
|
||||||
<< " to " << F.getName() << '\n');
|
|
||||||
FuncInfo.CatchHandlerMaxState[&F] = NextState - 1;
|
|
||||||
|
|
||||||
CurrentBaseState = OldBaseState;
|
|
||||||
}
|
|
||||||
|
|
||||||
// This function follows the same basic traversal as calculateStateNumbers
|
|
||||||
// but it is necessary to identify the root landing pad associated
|
|
||||||
// with each action before we start assigning state numbers.
|
|
||||||
void WinEHNumbering::findActionRootLPads(const Function &F) {
|
|
||||||
auto I = VisitedHandlers.insert(&F);
|
|
||||||
if (!I.second)
|
|
||||||
return; // We've already visited this handler, don't revisit it.
|
|
||||||
|
|
||||||
SmallVector<std::unique_ptr<ActionHandler>, 4> ActionList;
|
|
||||||
for (const BasicBlock &BB : F) {
|
|
||||||
const auto *II = dyn_cast<InvokeInst>(BB.getTerminator());
|
|
||||||
if (!II)
|
|
||||||
continue;
|
|
||||||
const LandingPadInst *LPI = II->getLandingPadInst();
|
|
||||||
auto *ActionsCall = dyn_cast<IntrinsicInst>(LPI->getNextNode());
|
|
||||||
if (!ActionsCall)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
assert(ActionsCall->getIntrinsicID() == Intrinsic::eh_actions);
|
|
||||||
parseEHActions(ActionsCall, ActionList);
|
|
||||||
if (ActionList.empty())
|
|
||||||
continue;
|
|
||||||
for (int I = 0, E = ActionList.size(); I < E; ++I) {
|
|
||||||
if (auto *Handler
|
|
||||||
= dyn_cast<Function>(ActionList[I]->getHandlerBlockOrFunc())) {
|
|
||||||
FuncInfo.LastInvoke[Handler] = II;
|
|
||||||
// Don't replace the root landing pad if we previously saw this
|
|
||||||
// handler in a different function.
|
|
||||||
if (FuncInfo.RootLPad.count(Handler) &&
|
|
||||||
FuncInfo.RootLPad[Handler]->getParent()->getParent() != &F)
|
|
||||||
continue;
|
|
||||||
DEBUG(dbgs() << "Setting root lpad for ");
|
|
||||||
print_name(Handler);
|
|
||||||
DEBUG(dbgs() << " to " << LPI->getParent()->getName() << '\n');
|
|
||||||
FuncInfo.RootLPad[Handler] = LPI;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Walk the actions again and look for nested handlers. This has to
|
|
||||||
// happen after all of the actions have been processed in the current
|
|
||||||
// function.
|
|
||||||
for (int I = 0, E = ActionList.size(); I < E; ++I)
|
|
||||||
if (auto *Handler
|
|
||||||
= dyn_cast<Function>(ActionList[I]->getHandlerBlockOrFunc()))
|
|
||||||
findActionRootLPads(*Handler);
|
|
||||||
ActionList.clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// clear - Clear out all the function-specific state. This returns this
|
/// clear - Clear out all the function-specific state. This returns this
|
||||||
/// FunctionLoweringInfo to an empty state, ready to be used for a
|
/// FunctionLoweringInfo to an empty state, ready to be used for a
|
||||||
/// different function.
|
/// different function.
|
||||||
|
|||||||
@@ -2480,3 +2480,377 @@ void llvm::parseEHActions(
|
|||||||
}
|
}
|
||||||
std::reverse(Actions.begin(), Actions.end());
|
std::reverse(Actions.begin(), Actions.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
struct WinEHNumbering {
|
||||||
|
WinEHNumbering(WinEHFuncInfo &FuncInfo) : FuncInfo(FuncInfo),
|
||||||
|
CurrentBaseState(-1), NextState(0) {}
|
||||||
|
|
||||||
|
WinEHFuncInfo &FuncInfo;
|
||||||
|
int CurrentBaseState;
|
||||||
|
int NextState;
|
||||||
|
|
||||||
|
SmallVector<std::unique_ptr<ActionHandler>, 4> HandlerStack;
|
||||||
|
SmallPtrSet<const Function *, 4> VisitedHandlers;
|
||||||
|
|
||||||
|
int currentEHNumber() const {
|
||||||
|
return HandlerStack.empty() ? CurrentBaseState : HandlerStack.back()->getEHState();
|
||||||
|
}
|
||||||
|
|
||||||
|
void createUnwindMapEntry(int ToState, ActionHandler *AH);
|
||||||
|
void createTryBlockMapEntry(int TryLow, int TryHigh,
|
||||||
|
ArrayRef<CatchHandler *> Handlers);
|
||||||
|
void processCallSite(MutableArrayRef<std::unique_ptr<ActionHandler>> Actions,
|
||||||
|
ImmutableCallSite CS);
|
||||||
|
void popUnmatchedActions(int FirstMismatch);
|
||||||
|
void calculateStateNumbers(const Function &F);
|
||||||
|
void findActionRootLPads(const Function &F);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
void WinEHNumbering::createUnwindMapEntry(int ToState, ActionHandler *AH) {
|
||||||
|
WinEHUnwindMapEntry UME;
|
||||||
|
UME.ToState = ToState;
|
||||||
|
if (auto *CH = dyn_cast_or_null<CleanupHandler>(AH))
|
||||||
|
UME.Cleanup = cast<Function>(CH->getHandlerBlockOrFunc());
|
||||||
|
else
|
||||||
|
UME.Cleanup = nullptr;
|
||||||
|
FuncInfo.UnwindMap.push_back(UME);
|
||||||
|
}
|
||||||
|
|
||||||
|
void WinEHNumbering::createTryBlockMapEntry(int TryLow, int TryHigh,
|
||||||
|
ArrayRef<CatchHandler *> Handlers) {
|
||||||
|
// See if we already have an entry for this set of handlers.
|
||||||
|
// This is using iterators rather than a range-based for loop because
|
||||||
|
// if we find the entry we're looking for we'll need the iterator to erase it.
|
||||||
|
int NumHandlers = Handlers.size();
|
||||||
|
auto I = FuncInfo.TryBlockMap.begin();
|
||||||
|
auto E = FuncInfo.TryBlockMap.end();
|
||||||
|
for ( ; I != E; ++I) {
|
||||||
|
auto &Entry = *I;
|
||||||
|
if (Entry.HandlerArray.size() != (size_t)NumHandlers)
|
||||||
|
continue;
|
||||||
|
int N;
|
||||||
|
for (N = 0; N < NumHandlers; ++N) {
|
||||||
|
if (Entry.HandlerArray[N].Handler != Handlers[N]->getHandlerBlockOrFunc())
|
||||||
|
break; // breaks out of inner loop
|
||||||
|
}
|
||||||
|
// If all the handlers match, this is what we were looking for.
|
||||||
|
if (N == NumHandlers) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we found an existing entry for this set of handlers, extend the range
|
||||||
|
// but move the entry to the end of the map vector. The order of entries
|
||||||
|
// in the map is critical to the way that the runtime finds handlers.
|
||||||
|
// FIXME: Depending on what has happened with block ordering, this may
|
||||||
|
// incorrectly combine entries that should remain separate.
|
||||||
|
if (I != E) {
|
||||||
|
// Copy the existing entry.
|
||||||
|
WinEHTryBlockMapEntry Entry = *I;
|
||||||
|
Entry.TryLow = std::min(TryLow, Entry.TryLow);
|
||||||
|
Entry.TryHigh = std::max(TryHigh, Entry.TryHigh);
|
||||||
|
assert(Entry.TryLow <= Entry.TryHigh);
|
||||||
|
// Erase the old entry and add this one to the back.
|
||||||
|
FuncInfo.TryBlockMap.erase(I);
|
||||||
|
FuncInfo.TryBlockMap.push_back(Entry);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we didn't find an entry, create a new one.
|
||||||
|
WinEHTryBlockMapEntry TBME;
|
||||||
|
TBME.TryLow = TryLow;
|
||||||
|
TBME.TryHigh = TryHigh;
|
||||||
|
assert(TBME.TryLow <= TBME.TryHigh);
|
||||||
|
for (CatchHandler *CH : Handlers) {
|
||||||
|
WinEHHandlerType HT;
|
||||||
|
if (CH->getSelector()->isNullValue()) {
|
||||||
|
HT.Adjectives = 0x40;
|
||||||
|
HT.TypeDescriptor = nullptr;
|
||||||
|
} else {
|
||||||
|
auto *GV = cast<GlobalVariable>(CH->getSelector()->stripPointerCasts());
|
||||||
|
// Selectors are always pointers to GlobalVariables with 'struct' type.
|
||||||
|
// The struct has two fields, adjectives and a type descriptor.
|
||||||
|
auto *CS = cast<ConstantStruct>(GV->getInitializer());
|
||||||
|
HT.Adjectives =
|
||||||
|
cast<ConstantInt>(CS->getAggregateElement(0U))->getZExtValue();
|
||||||
|
HT.TypeDescriptor =
|
||||||
|
cast<GlobalVariable>(CS->getAggregateElement(1)->stripPointerCasts());
|
||||||
|
}
|
||||||
|
HT.Handler = cast<Function>(CH->getHandlerBlockOrFunc());
|
||||||
|
HT.CatchObjRecoverIdx = CH->getExceptionVarIndex();
|
||||||
|
TBME.HandlerArray.push_back(HT);
|
||||||
|
}
|
||||||
|
FuncInfo.TryBlockMap.push_back(TBME);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void print_name(const Value *V) {
|
||||||
|
#ifndef NDEBUG
|
||||||
|
if (!V) {
|
||||||
|
DEBUG(dbgs() << "null");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (const auto *F = dyn_cast<Function>(V))
|
||||||
|
DEBUG(dbgs() << F->getName());
|
||||||
|
else
|
||||||
|
DEBUG(V->dump());
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void WinEHNumbering::processCallSite(
|
||||||
|
MutableArrayRef<std::unique_ptr<ActionHandler>> Actions,
|
||||||
|
ImmutableCallSite CS) {
|
||||||
|
DEBUG(dbgs() << "processCallSite (EH state = " << currentEHNumber()
|
||||||
|
<< ") for: ");
|
||||||
|
print_name(CS ? CS.getCalledValue() : nullptr);
|
||||||
|
DEBUG(dbgs() << '\n');
|
||||||
|
|
||||||
|
DEBUG(dbgs() << "HandlerStack: \n");
|
||||||
|
for (int I = 0, E = HandlerStack.size(); I < E; ++I) {
|
||||||
|
DEBUG(dbgs() << " ");
|
||||||
|
print_name(HandlerStack[I]->getHandlerBlockOrFunc());
|
||||||
|
DEBUG(dbgs() << '\n');
|
||||||
|
}
|
||||||
|
DEBUG(dbgs() << "Actions: \n");
|
||||||
|
for (int I = 0, E = Actions.size(); I < E; ++I) {
|
||||||
|
DEBUG(dbgs() << " ");
|
||||||
|
print_name(Actions[I]->getHandlerBlockOrFunc());
|
||||||
|
DEBUG(dbgs() << '\n');
|
||||||
|
}
|
||||||
|
int FirstMismatch = 0;
|
||||||
|
for (int E = std::min(HandlerStack.size(), Actions.size()); FirstMismatch < E;
|
||||||
|
++FirstMismatch) {
|
||||||
|
if (HandlerStack[FirstMismatch]->getHandlerBlockOrFunc() !=
|
||||||
|
Actions[FirstMismatch]->getHandlerBlockOrFunc())
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove unmatched actions from the stack and process their EH states.
|
||||||
|
popUnmatchedActions(FirstMismatch);
|
||||||
|
|
||||||
|
DEBUG(dbgs() << "Pushing actions for CallSite: ");
|
||||||
|
print_name(CS ? CS.getCalledValue() : nullptr);
|
||||||
|
DEBUG(dbgs() << '\n');
|
||||||
|
|
||||||
|
bool LastActionWasCatch = false;
|
||||||
|
const LandingPadInst *LastRootLPad = nullptr;
|
||||||
|
for (size_t I = FirstMismatch; I != Actions.size(); ++I) {
|
||||||
|
// We can reuse eh states when pushing two catches for the same invoke.
|
||||||
|
bool CurrActionIsCatch = isa<CatchHandler>(Actions[I].get());
|
||||||
|
auto *Handler = cast<Function>(Actions[I]->getHandlerBlockOrFunc());
|
||||||
|
// Various conditions can lead to a handler being popped from the
|
||||||
|
// stack and re-pushed later. That shouldn't create a new state.
|
||||||
|
// FIXME: Can code optimization lead to re-used handlers?
|
||||||
|
if (FuncInfo.HandlerEnclosedState.count(Handler)) {
|
||||||
|
// If we already assigned the state enclosed by this handler re-use it.
|
||||||
|
Actions[I]->setEHState(FuncInfo.HandlerEnclosedState[Handler]);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const LandingPadInst* RootLPad = FuncInfo.RootLPad[Handler];
|
||||||
|
if (CurrActionIsCatch && LastActionWasCatch && RootLPad == LastRootLPad) {
|
||||||
|
DEBUG(dbgs() << "setEHState for handler to " << currentEHNumber() << "\n");
|
||||||
|
Actions[I]->setEHState(currentEHNumber());
|
||||||
|
} else {
|
||||||
|
DEBUG(dbgs() << "createUnwindMapEntry(" << currentEHNumber() << ", ");
|
||||||
|
print_name(Actions[I]->getHandlerBlockOrFunc());
|
||||||
|
DEBUG(dbgs() << ") with EH state " << NextState << "\n");
|
||||||
|
createUnwindMapEntry(currentEHNumber(), Actions[I].get());
|
||||||
|
DEBUG(dbgs() << "setEHState for handler to " << NextState << "\n");
|
||||||
|
Actions[I]->setEHState(NextState);
|
||||||
|
NextState++;
|
||||||
|
}
|
||||||
|
HandlerStack.push_back(std::move(Actions[I]));
|
||||||
|
LastActionWasCatch = CurrActionIsCatch;
|
||||||
|
LastRootLPad = RootLPad;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is used to defer numbering states for a handler until after the
|
||||||
|
// last time it appears in an invoke action list.
|
||||||
|
if (CS.isInvoke()) {
|
||||||
|
for (int I = 0, E = HandlerStack.size(); I < E; ++I) {
|
||||||
|
auto *Handler = cast<Function>(HandlerStack[I]->getHandlerBlockOrFunc());
|
||||||
|
if (FuncInfo.LastInvoke[Handler] != cast<InvokeInst>(CS.getInstruction()))
|
||||||
|
continue;
|
||||||
|
FuncInfo.LastInvokeVisited[Handler] = true;
|
||||||
|
DEBUG(dbgs() << "Last invoke of ");
|
||||||
|
print_name(Handler);
|
||||||
|
DEBUG(dbgs() << " has been visited.\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DEBUG(dbgs() << "In EHState " << currentEHNumber() << " for CallSite: ");
|
||||||
|
print_name(CS ? CS.getCalledValue() : nullptr);
|
||||||
|
DEBUG(dbgs() << '\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
void WinEHNumbering::popUnmatchedActions(int FirstMismatch) {
|
||||||
|
// Don't recurse while we are looping over the handler stack. Instead, defer
|
||||||
|
// the numbering of the catch handlers until we are done popping.
|
||||||
|
SmallVector<CatchHandler *, 4> PoppedCatches;
|
||||||
|
for (int I = HandlerStack.size() - 1; I >= FirstMismatch; --I) {
|
||||||
|
std::unique_ptr<ActionHandler> Handler = HandlerStack.pop_back_val();
|
||||||
|
if (isa<CatchHandler>(Handler.get()))
|
||||||
|
PoppedCatches.push_back(cast<CatchHandler>(Handler.release()));
|
||||||
|
}
|
||||||
|
|
||||||
|
int TryHigh = NextState - 1;
|
||||||
|
int LastTryLowIdx = 0;
|
||||||
|
for (int I = 0, E = PoppedCatches.size(); I != E; ++I) {
|
||||||
|
CatchHandler *CH = PoppedCatches[I];
|
||||||
|
DEBUG(dbgs() << "Popped handler with state " << CH->getEHState() << "\n");
|
||||||
|
if (I + 1 == E || CH->getEHState() != PoppedCatches[I + 1]->getEHState()) {
|
||||||
|
int TryLow = CH->getEHState();
|
||||||
|
auto Handlers =
|
||||||
|
makeArrayRef(&PoppedCatches[LastTryLowIdx], I - LastTryLowIdx + 1);
|
||||||
|
DEBUG(dbgs() << "createTryBlockMapEntry(" << TryLow << ", " << TryHigh);
|
||||||
|
for (size_t J = 0; J < Handlers.size(); ++J) {
|
||||||
|
DEBUG(dbgs() << ", ");
|
||||||
|
print_name(Handlers[J]->getHandlerBlockOrFunc());
|
||||||
|
}
|
||||||
|
DEBUG(dbgs() << ")\n");
|
||||||
|
createTryBlockMapEntry(TryLow, TryHigh, Handlers);
|
||||||
|
LastTryLowIdx = I + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (CatchHandler *CH : PoppedCatches) {
|
||||||
|
if (auto *F = dyn_cast<Function>(CH->getHandlerBlockOrFunc())) {
|
||||||
|
if (FuncInfo.LastInvokeVisited[F]) {
|
||||||
|
DEBUG(dbgs() << "Assigning base state " << NextState << " to ");
|
||||||
|
print_name(F);
|
||||||
|
DEBUG(dbgs() << '\n');
|
||||||
|
FuncInfo.HandlerBaseState[F] = NextState;
|
||||||
|
DEBUG(dbgs() << "createUnwindMapEntry(" << currentEHNumber()
|
||||||
|
<< ", null)\n");
|
||||||
|
createUnwindMapEntry(currentEHNumber(), nullptr);
|
||||||
|
++NextState;
|
||||||
|
calculateStateNumbers(*F);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
DEBUG(dbgs() << "Deferring handling of ");
|
||||||
|
print_name(F);
|
||||||
|
DEBUG(dbgs() << " until last invoke visited.\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
delete CH;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void WinEHNumbering::calculateStateNumbers(const Function &F) {
|
||||||
|
auto I = VisitedHandlers.insert(&F);
|
||||||
|
if (!I.second)
|
||||||
|
return; // We've already visited this handler, don't renumber it.
|
||||||
|
|
||||||
|
int OldBaseState = CurrentBaseState;
|
||||||
|
if (FuncInfo.HandlerBaseState.count(&F)) {
|
||||||
|
CurrentBaseState = FuncInfo.HandlerBaseState[&F];
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t SavedHandlerStackSize = HandlerStack.size();
|
||||||
|
|
||||||
|
DEBUG(dbgs() << "Calculating state numbers for: " << F.getName() << '\n');
|
||||||
|
SmallVector<std::unique_ptr<ActionHandler>, 4> ActionList;
|
||||||
|
for (const BasicBlock &BB : F) {
|
||||||
|
for (const Instruction &I : BB) {
|
||||||
|
const auto *CI = dyn_cast<CallInst>(&I);
|
||||||
|
if (!CI || CI->doesNotThrow())
|
||||||
|
continue;
|
||||||
|
processCallSite(None, CI);
|
||||||
|
}
|
||||||
|
const auto *II = dyn_cast<InvokeInst>(BB.getTerminator());
|
||||||
|
if (!II)
|
||||||
|
continue;
|
||||||
|
const LandingPadInst *LPI = II->getLandingPadInst();
|
||||||
|
auto *ActionsCall = dyn_cast<IntrinsicInst>(LPI->getNextNode());
|
||||||
|
if (!ActionsCall)
|
||||||
|
continue;
|
||||||
|
assert(ActionsCall->getIntrinsicID() == Intrinsic::eh_actions);
|
||||||
|
parseEHActions(ActionsCall, ActionList);
|
||||||
|
if (ActionList.empty())
|
||||||
|
continue;
|
||||||
|
processCallSite(ActionList, II);
|
||||||
|
ActionList.clear();
|
||||||
|
FuncInfo.LandingPadStateMap[LPI] = currentEHNumber();
|
||||||
|
DEBUG(dbgs() << "Assigning state " << currentEHNumber()
|
||||||
|
<< " to landing pad at " << LPI->getParent()->getName()
|
||||||
|
<< '\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pop any actions that were pushed on the stack for this function.
|
||||||
|
popUnmatchedActions(SavedHandlerStackSize);
|
||||||
|
|
||||||
|
DEBUG(dbgs() << "Assigning max state " << NextState - 1
|
||||||
|
<< " to " << F.getName() << '\n');
|
||||||
|
FuncInfo.CatchHandlerMaxState[&F] = NextState - 1;
|
||||||
|
|
||||||
|
CurrentBaseState = OldBaseState;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This function follows the same basic traversal as calculateStateNumbers
|
||||||
|
// but it is necessary to identify the root landing pad associated
|
||||||
|
// with each action before we start assigning state numbers.
|
||||||
|
void WinEHNumbering::findActionRootLPads(const Function &F) {
|
||||||
|
auto I = VisitedHandlers.insert(&F);
|
||||||
|
if (!I.second)
|
||||||
|
return; // We've already visited this handler, don't revisit it.
|
||||||
|
|
||||||
|
SmallVector<std::unique_ptr<ActionHandler>, 4> ActionList;
|
||||||
|
for (const BasicBlock &BB : F) {
|
||||||
|
const auto *II = dyn_cast<InvokeInst>(BB.getTerminator());
|
||||||
|
if (!II)
|
||||||
|
continue;
|
||||||
|
const LandingPadInst *LPI = II->getLandingPadInst();
|
||||||
|
auto *ActionsCall = dyn_cast<IntrinsicInst>(LPI->getNextNode());
|
||||||
|
if (!ActionsCall)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
assert(ActionsCall->getIntrinsicID() == Intrinsic::eh_actions);
|
||||||
|
parseEHActions(ActionsCall, ActionList);
|
||||||
|
if (ActionList.empty())
|
||||||
|
continue;
|
||||||
|
for (int I = 0, E = ActionList.size(); I < E; ++I) {
|
||||||
|
if (auto *Handler
|
||||||
|
= dyn_cast<Function>(ActionList[I]->getHandlerBlockOrFunc())) {
|
||||||
|
FuncInfo.LastInvoke[Handler] = II;
|
||||||
|
// Don't replace the root landing pad if we previously saw this
|
||||||
|
// handler in a different function.
|
||||||
|
if (FuncInfo.RootLPad.count(Handler) &&
|
||||||
|
FuncInfo.RootLPad[Handler]->getParent()->getParent() != &F)
|
||||||
|
continue;
|
||||||
|
DEBUG(dbgs() << "Setting root lpad for ");
|
||||||
|
print_name(Handler);
|
||||||
|
DEBUG(dbgs() << " to " << LPI->getParent()->getName() << '\n');
|
||||||
|
FuncInfo.RootLPad[Handler] = LPI;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Walk the actions again and look for nested handlers. This has to
|
||||||
|
// happen after all of the actions have been processed in the current
|
||||||
|
// function.
|
||||||
|
for (int I = 0, E = ActionList.size(); I < E; ++I)
|
||||||
|
if (auto *Handler
|
||||||
|
= dyn_cast<Function>(ActionList[I]->getHandlerBlockOrFunc()))
|
||||||
|
findActionRootLPads(*Handler);
|
||||||
|
ActionList.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void llvm::calculateWinCXXEHStateNumbers(const Function *ParentFn,
|
||||||
|
WinEHFuncInfo &FuncInfo) {
|
||||||
|
// Return if it's already been done.
|
||||||
|
if (!FuncInfo.LandingPadStateMap.empty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
WinEHNumbering Num(FuncInfo);
|
||||||
|
Num.findActionRootLPads(*ParentFn);
|
||||||
|
// The VisitedHandlers list is used by both findActionRootLPads and
|
||||||
|
// calculateStateNumbers, but both functions need to visit all handlers.
|
||||||
|
Num.VisitedHandlers.clear();
|
||||||
|
Num.calculateStateNumbers(*ParentFn);
|
||||||
|
// Pop everything on the handler stack.
|
||||||
|
// It may be necessary to call this more than once because a handler can
|
||||||
|
// be pushed on the stack as a result of clearing the stack.
|
||||||
|
while (!Num.HandlerStack.empty())
|
||||||
|
Num.processCallSite(None, ImmutableCallSite());
|
||||||
|
}
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
#include "X86.h"
|
#include "X86.h"
|
||||||
#include "llvm/Analysis/LibCallSemantics.h"
|
#include "llvm/Analysis/LibCallSemantics.h"
|
||||||
|
#include "llvm/CodeGen/MachineModuleInfo.h"
|
||||||
#include "llvm/CodeGen/Passes.h"
|
#include "llvm/CodeGen/Passes.h"
|
||||||
#include "llvm/CodeGen/WinEHFuncInfo.h"
|
#include "llvm/CodeGen/WinEHFuncInfo.h"
|
||||||
#include "llvm/IR/Dominators.h"
|
#include "llvm/IR/Dominators.h"
|
||||||
@@ -59,14 +60,19 @@ public:
|
|||||||
private:
|
private:
|
||||||
void emitExceptionRegistrationRecord(Function *F);
|
void emitExceptionRegistrationRecord(Function *F);
|
||||||
|
|
||||||
void linkExceptionRegistration(IRBuilder<> &Builder, Value *RegNode,
|
void linkExceptionRegistration(IRBuilder<> &Builder, Value *Handler);
|
||||||
Value *Handler);
|
void unlinkExceptionRegistration(IRBuilder<> &Builder);
|
||||||
void unlinkExceptionRegistration(IRBuilder<> &Builder, Value *RegNode);
|
void addCXXStateStores(Function &F, MachineModuleInfo &MMI);
|
||||||
|
void addCXXStateStoresToFunclet(Value *ParentRegNode, WinEHFuncInfo &FuncInfo,
|
||||||
|
Function &F, int BaseState);
|
||||||
|
void insertStateNumberStore(Value *ParentRegNode, Instruction *IP, int State);
|
||||||
|
|
||||||
Value *emitEHLSDA(IRBuilder<> &Builder, Function *F);
|
Value *emitEHLSDA(IRBuilder<> &Builder, Function *F);
|
||||||
|
|
||||||
Function *generateLSDAInEAXThunk(Function *ParentFunc);
|
Function *generateLSDAInEAXThunk(Function *ParentFunc);
|
||||||
|
|
||||||
|
int escapeRegNode(Function &F);
|
||||||
|
|
||||||
// Module-level type getters.
|
// Module-level type getters.
|
||||||
Type *getEHRegistrationType();
|
Type *getEHRegistrationType();
|
||||||
Type *getSEH3RegistrationType();
|
Type *getSEH3RegistrationType();
|
||||||
@@ -83,6 +89,19 @@ private:
|
|||||||
// Per-function state
|
// Per-function state
|
||||||
EHPersonality Personality = EHPersonality::Unknown;
|
EHPersonality Personality = EHPersonality::Unknown;
|
||||||
Function *PersonalityFn = nullptr;
|
Function *PersonalityFn = nullptr;
|
||||||
|
|
||||||
|
/// The stack allocation containing all EH data, including the link in the
|
||||||
|
/// fs:00 chain and the current state.
|
||||||
|
AllocaInst *RegNode = nullptr;
|
||||||
|
|
||||||
|
/// Struct type of RegNode. Used for GEPing.
|
||||||
|
Type *RegNodeTy = nullptr;
|
||||||
|
|
||||||
|
/// The index of the state field of RegNode.
|
||||||
|
int StateFieldIndex = ~0U;
|
||||||
|
|
||||||
|
/// The linked list node subobject inside of RegNode.
|
||||||
|
Value *Link = nullptr;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -137,7 +156,13 @@ bool WinEHStatePass::runOnFunction(Function &F) {
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
emitExceptionRegistrationRecord(&F);
|
emitExceptionRegistrationRecord(&F);
|
||||||
// FIXME: State insertion.
|
|
||||||
|
auto *MMIPtr = getAnalysisIfAvailable<MachineModuleInfo>();
|
||||||
|
assert(MMIPtr && "MachineModuleInfo should always be available");
|
||||||
|
MachineModuleInfo &MMI = *MMIPtr;
|
||||||
|
if (Personality == EHPersonality::MSVC_CXX) {
|
||||||
|
addCXXStateStores(F, MMI);
|
||||||
|
}
|
||||||
|
|
||||||
// Reset per-function state.
|
// Reset per-function state.
|
||||||
PersonalityFn = nullptr;
|
PersonalityFn = nullptr;
|
||||||
@@ -238,62 +263,61 @@ void WinEHStatePass::emitExceptionRegistrationRecord(Function *F) {
|
|||||||
StringRef PersonalityName = PersonalityFn->getName();
|
StringRef PersonalityName = PersonalityFn->getName();
|
||||||
IRBuilder<> Builder(&F->getEntryBlock(), F->getEntryBlock().begin());
|
IRBuilder<> Builder(&F->getEntryBlock(), F->getEntryBlock().begin());
|
||||||
Type *Int8PtrType = Builder.getInt8PtrTy();
|
Type *Int8PtrType = Builder.getInt8PtrTy();
|
||||||
Value *SubRecord = nullptr;
|
|
||||||
if (PersonalityName == "__CxxFrameHandler3") {
|
if (PersonalityName == "__CxxFrameHandler3") {
|
||||||
Type *RegNodeTy = getCXXEH3RegistrationType();
|
RegNodeTy = getCXXEH3RegistrationType();
|
||||||
Value *RegNode = Builder.CreateAlloca(RegNodeTy);
|
RegNode = Builder.CreateAlloca(RegNodeTy);
|
||||||
// FIXME: We can skip this in -GS- mode, when we figure that out.
|
// FIXME: We can skip this in -GS- mode, when we figure that out.
|
||||||
// SavedESP = llvm.stacksave()
|
// SavedESP = llvm.stacksave()
|
||||||
Value *SP = Builder.CreateCall(
|
Value *SP = Builder.CreateCall(
|
||||||
Intrinsic::getDeclaration(TheModule, Intrinsic::stacksave), {});
|
Intrinsic::getDeclaration(TheModule, Intrinsic::stacksave), {});
|
||||||
Builder.CreateStore(SP, Builder.CreateStructGEP(RegNodeTy, RegNode, 0));
|
Builder.CreateStore(SP, Builder.CreateStructGEP(RegNodeTy, RegNode, 0));
|
||||||
// TryLevel = -1
|
// TryLevel = -1
|
||||||
Builder.CreateStore(Builder.getInt32(-1),
|
StateFieldIndex = 2;
|
||||||
Builder.CreateStructGEP(RegNodeTy, RegNode, 2));
|
insertStateNumberStore(RegNode, Builder.GetInsertPoint(), -1);
|
||||||
// Handler = __ehhandler$F
|
// Handler = __ehhandler$F
|
||||||
Function *Trampoline = generateLSDAInEAXThunk(F);
|
Function *Trampoline = generateLSDAInEAXThunk(F);
|
||||||
SubRecord = Builder.CreateStructGEP(RegNodeTy, RegNode, 1);
|
Link = Builder.CreateStructGEP(RegNodeTy, RegNode, 1);
|
||||||
linkExceptionRegistration(Builder, SubRecord, Trampoline);
|
linkExceptionRegistration(Builder, Trampoline);
|
||||||
} else if (PersonalityName == "_except_handler3") {
|
} else if (PersonalityName == "_except_handler3") {
|
||||||
Type *RegNodeTy = getSEH3RegistrationType();
|
RegNodeTy = getSEH3RegistrationType();
|
||||||
Value *RegNode = Builder.CreateAlloca(RegNodeTy);
|
RegNode = Builder.CreateAlloca(RegNodeTy);
|
||||||
// TryLevel = -1
|
// TryLevel = -1
|
||||||
Builder.CreateStore(Builder.getInt32(-1),
|
StateFieldIndex = 2;
|
||||||
Builder.CreateStructGEP(RegNodeTy, RegNode, 2));
|
insertStateNumberStore(RegNode, Builder.GetInsertPoint(), -1);
|
||||||
// ScopeTable = llvm.x86.seh.lsda(F)
|
// ScopeTable = llvm.x86.seh.lsda(F)
|
||||||
Value *LSDA = emitEHLSDA(Builder, F);
|
Value *LSDA = emitEHLSDA(Builder, F);
|
||||||
Builder.CreateStore(LSDA, Builder.CreateStructGEP(RegNodeTy, RegNode, 1));
|
Builder.CreateStore(LSDA, Builder.CreateStructGEP(RegNodeTy, RegNode, 1));
|
||||||
SubRecord = Builder.CreateStructGEP(RegNodeTy, RegNode, 0);
|
Link = Builder.CreateStructGEP(RegNodeTy, RegNode, 0);
|
||||||
linkExceptionRegistration(Builder, SubRecord, PersonalityFn);
|
linkExceptionRegistration(Builder, PersonalityFn);
|
||||||
} else if (PersonalityName == "_except_handler4") {
|
} else if (PersonalityName == "_except_handler4") {
|
||||||
Type *RegNodeTy = getSEH4RegistrationType();
|
RegNodeTy = getSEH4RegistrationType();
|
||||||
Value *RegNode = Builder.CreateAlloca(RegNodeTy);
|
RegNode = Builder.CreateAlloca(RegNodeTy);
|
||||||
// SavedESP = llvm.stacksave()
|
// SavedESP = llvm.stacksave()
|
||||||
Value *SP = Builder.CreateCall(
|
Value *SP = Builder.CreateCall(
|
||||||
Intrinsic::getDeclaration(TheModule, Intrinsic::stacksave), {});
|
Intrinsic::getDeclaration(TheModule, Intrinsic::stacksave), {});
|
||||||
Builder.CreateStore(SP, Builder.CreateStructGEP(RegNodeTy, RegNode, 0));
|
Builder.CreateStore(SP, Builder.CreateStructGEP(RegNodeTy, RegNode, 0));
|
||||||
// TryLevel = -2
|
// TryLevel = -1
|
||||||
Builder.CreateStore(Builder.getInt32(-2),
|
StateFieldIndex = 4;
|
||||||
Builder.CreateStructGEP(RegNodeTy, RegNode, 4));
|
insertStateNumberStore(RegNode, Builder.GetInsertPoint(), -1);
|
||||||
// FIXME: XOR the LSDA with __security_cookie.
|
// FIXME: XOR the LSDA with __security_cookie.
|
||||||
// ScopeTable = llvm.x86.seh.lsda(F)
|
// ScopeTable = llvm.x86.seh.lsda(F)
|
||||||
Value *FI8 = Builder.CreateBitCast(F, Int8PtrType);
|
Value *FI8 = Builder.CreateBitCast(F, Int8PtrType);
|
||||||
Value *LSDA = Builder.CreateCall(
|
Value *LSDA = Builder.CreateCall(
|
||||||
Intrinsic::getDeclaration(TheModule, Intrinsic::x86_seh_lsda), FI8);
|
Intrinsic::getDeclaration(TheModule, Intrinsic::x86_seh_lsda), FI8);
|
||||||
Builder.CreateStore(LSDA, Builder.CreateStructGEP(RegNodeTy, RegNode, 1));
|
Builder.CreateStore(LSDA, Builder.CreateStructGEP(RegNodeTy, RegNode, 1));
|
||||||
SubRecord = Builder.CreateStructGEP(RegNodeTy, RegNode, 2);
|
Link = Builder.CreateStructGEP(RegNodeTy, RegNode, 2);
|
||||||
linkExceptionRegistration(Builder, SubRecord, PersonalityFn);
|
linkExceptionRegistration(Builder, PersonalityFn);
|
||||||
} else {
|
} else {
|
||||||
llvm_unreachable("unexpected personality function");
|
llvm_unreachable("unexpected personality function");
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: Insert an unlink before all returns.
|
// Insert an unlink before all returns.
|
||||||
for (BasicBlock &BB : *F) {
|
for (BasicBlock &BB : *F) {
|
||||||
TerminatorInst *T = BB.getTerminator();
|
TerminatorInst *T = BB.getTerminator();
|
||||||
if (!isa<ReturnInst>(T))
|
if (!isa<ReturnInst>(T))
|
||||||
continue;
|
continue;
|
||||||
Builder.SetInsertPoint(T);
|
Builder.SetInsertPoint(T);
|
||||||
unlinkExceptionRegistration(Builder, SubRecord);
|
unlinkExceptionRegistration(Builder);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -342,33 +366,127 @@ Function *WinEHStatePass::generateLSDAInEAXThunk(Function *ParentFunc) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void WinEHStatePass::linkExceptionRegistration(IRBuilder<> &Builder,
|
void WinEHStatePass::linkExceptionRegistration(IRBuilder<> &Builder,
|
||||||
Value *RegNode, Value *Handler) {
|
Value *Handler) {
|
||||||
Type *RegNodeTy = getEHRegistrationType();
|
Type *LinkTy = getEHRegistrationType();
|
||||||
// Handler = Handler
|
// Handler = Handler
|
||||||
Handler = Builder.CreateBitCast(Handler, Builder.getInt8PtrTy());
|
Handler = Builder.CreateBitCast(Handler, Builder.getInt8PtrTy());
|
||||||
Builder.CreateStore(Handler, Builder.CreateStructGEP(RegNodeTy, RegNode, 1));
|
Builder.CreateStore(Handler, Builder.CreateStructGEP(LinkTy, Link, 1));
|
||||||
// Next = [fs:00]
|
// Next = [fs:00]
|
||||||
Constant *FSZero =
|
Constant *FSZero =
|
||||||
Constant::getNullValue(RegNodeTy->getPointerTo()->getPointerTo(257));
|
Constant::getNullValue(LinkTy->getPointerTo()->getPointerTo(257));
|
||||||
Value *Next = Builder.CreateLoad(FSZero);
|
Value *Next = Builder.CreateLoad(FSZero);
|
||||||
Builder.CreateStore(Next, Builder.CreateStructGEP(RegNodeTy, RegNode, 0));
|
Builder.CreateStore(Next, Builder.CreateStructGEP(LinkTy, Link, 0));
|
||||||
// [fs:00] = RegNode
|
// [fs:00] = Link
|
||||||
Builder.CreateStore(RegNode, FSZero);
|
Builder.CreateStore(Link, FSZero);
|
||||||
}
|
}
|
||||||
|
|
||||||
void WinEHStatePass::unlinkExceptionRegistration(IRBuilder<> &Builder,
|
void WinEHStatePass::unlinkExceptionRegistration(IRBuilder<> &Builder) {
|
||||||
Value *RegNode) {
|
// Clone Link into the current BB for better address mode folding.
|
||||||
// Clone RegNode into the current BB for better address mode folding.
|
if (auto *GEP = dyn_cast<GetElementPtrInst>(Link)) {
|
||||||
if (auto *GEP = dyn_cast<GetElementPtrInst>(RegNode)) {
|
|
||||||
GEP = cast<GetElementPtrInst>(GEP->clone());
|
GEP = cast<GetElementPtrInst>(GEP->clone());
|
||||||
Builder.Insert(GEP);
|
Builder.Insert(GEP);
|
||||||
RegNode = GEP;
|
Link = GEP;
|
||||||
}
|
}
|
||||||
Type *RegNodeTy = getEHRegistrationType();
|
Type *LinkTy = getEHRegistrationType();
|
||||||
// [fs:00] = RegNode->Next
|
// [fs:00] = Link->Next
|
||||||
Value *Next =
|
Value *Next =
|
||||||
Builder.CreateLoad(Builder.CreateStructGEP(RegNodeTy, RegNode, 0));
|
Builder.CreateLoad(Builder.CreateStructGEP(LinkTy, Link, 0));
|
||||||
Constant *FSZero =
|
Constant *FSZero =
|
||||||
Constant::getNullValue(RegNodeTy->getPointerTo()->getPointerTo(257));
|
Constant::getNullValue(LinkTy->getPointerTo()->getPointerTo(257));
|
||||||
Builder.CreateStore(Next, FSZero);
|
Builder.CreateStore(Next, FSZero);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void WinEHStatePass::addCXXStateStores(Function &F, MachineModuleInfo &MMI) {
|
||||||
|
WinEHFuncInfo &FuncInfo = MMI.getWinEHFuncInfo(&F);
|
||||||
|
calculateWinCXXEHStateNumbers(&F, FuncInfo);
|
||||||
|
|
||||||
|
// The base state for the parent is -1.
|
||||||
|
addCXXStateStoresToFunclet(RegNode, FuncInfo, F, -1);
|
||||||
|
|
||||||
|
// Set up RegNodeEscapeIndex
|
||||||
|
int RegNodeEscapeIndex = escapeRegNode(F);
|
||||||
|
|
||||||
|
// Only insert stores in catch handlers.
|
||||||
|
Function *FrameRecover =
|
||||||
|
Intrinsic::getDeclaration(TheModule, Intrinsic::framerecover);
|
||||||
|
Function *FrameAddress =
|
||||||
|
Intrinsic::getDeclaration(TheModule, Intrinsic::frameaddress);
|
||||||
|
Constant *FI8 =
|
||||||
|
ConstantExpr::getBitCast(&F, Type::getInt8PtrTy(TheModule->getContext()));
|
||||||
|
for (auto P : FuncInfo.HandlerBaseState) {
|
||||||
|
Function *Handler = const_cast<Function *>(P.first);
|
||||||
|
int BaseState = P.second;
|
||||||
|
IRBuilder<> Builder(&Handler->getEntryBlock(),
|
||||||
|
Handler->getEntryBlock().begin());
|
||||||
|
// FIXME: Find and reuse such a call if present.
|
||||||
|
Value *ParentFP = Builder.CreateCall(FrameAddress, {Builder.getInt32(1)});
|
||||||
|
Value *RecoveredRegNode = Builder.CreateCall(
|
||||||
|
FrameRecover, {FI8, ParentFP, Builder.getInt32(RegNodeEscapeIndex)});
|
||||||
|
RecoveredRegNode =
|
||||||
|
Builder.CreateBitCast(RecoveredRegNode, RegNodeTy->getPointerTo(0));
|
||||||
|
addCXXStateStoresToFunclet(RecoveredRegNode, FuncInfo, *Handler, BaseState);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Escape RegNode so that we can access it from child handlers. Find the call
|
||||||
|
/// to frameescape, if any, in the entry block and append RegNode to the list
|
||||||
|
/// of arguments.
|
||||||
|
int WinEHStatePass::escapeRegNode(Function &F) {
|
||||||
|
// Find the call to frameescape and extract its arguments.
|
||||||
|
IntrinsicInst *EscapeCall = nullptr;
|
||||||
|
for (Instruction &I : F.getEntryBlock()) {
|
||||||
|
IntrinsicInst *II = dyn_cast<IntrinsicInst>(&I);
|
||||||
|
if (II && II->getIntrinsicID() == Intrinsic::frameescape) {
|
||||||
|
EscapeCall = II;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SmallVector<Value *, 8> Args;
|
||||||
|
if (EscapeCall) {
|
||||||
|
auto Ops = EscapeCall->arg_operands();
|
||||||
|
Args.append(Ops.begin(), Ops.end());
|
||||||
|
}
|
||||||
|
Args.push_back(RegNode);
|
||||||
|
|
||||||
|
// Replace the call (if it exists) with new one. Otherwise, insert at the end
|
||||||
|
// of the entry block.
|
||||||
|
IRBuilder<> Builder(&F.getEntryBlock(),
|
||||||
|
EscapeCall ? EscapeCall : F.getEntryBlock().end());
|
||||||
|
Builder.CreateCall(
|
||||||
|
Intrinsic::getDeclaration(TheModule, Intrinsic::frameescape), Args);
|
||||||
|
if (EscapeCall)
|
||||||
|
EscapeCall->eraseFromParent();
|
||||||
|
return Args.size() - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void WinEHStatePass::addCXXStateStoresToFunclet(Value *ParentRegNode,
|
||||||
|
WinEHFuncInfo &FuncInfo,
|
||||||
|
Function &F, int BaseState) {
|
||||||
|
// Iterate all the instructions and emit state number stores.
|
||||||
|
for (BasicBlock &BB : F) {
|
||||||
|
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(ParentRegNode, CI, BaseState);
|
||||||
|
} else if (auto *II = dyn_cast<InvokeInst>(&I)) {
|
||||||
|
// Look up the state number of the landingpad this unwinds to.
|
||||||
|
LandingPadInst *LPI = II->getUnwindDest()->getLandingPadInst();
|
||||||
|
// FIXME: Why does this assertion fail?
|
||||||
|
//assert(FuncInfo.LandingPadStateMap.count(LPI) && "LP has no state!");
|
||||||
|
int State = FuncInfo.LandingPadStateMap[LPI];
|
||||||
|
insertStateNumberStore(ParentRegNode, II, State);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void WinEHStatePass::insertStateNumberStore(Value *ParentRegNode,
|
||||||
|
Instruction *IP, int State) {
|
||||||
|
IRBuilder<> Builder(IP);
|
||||||
|
Value *StateField =
|
||||||
|
Builder.CreateStructGEP(RegNodeTy, ParentRegNode, StateFieldIndex);
|
||||||
|
Builder.CreateStore(Builder.getInt32(State), StateField);
|
||||||
|
}
|
||||||
|
|||||||
112
test/CodeGen/X86/win32-eh-states.ll
Normal file
112
test/CodeGen/X86/win32-eh-states.ll
Normal file
@@ -0,0 +1,112 @@
|
|||||||
|
; RUN: llc -mtriple=i686-pc-windows-msvc < %s | FileCheck %s
|
||||||
|
|
||||||
|
; Based on this source:
|
||||||
|
; extern "C" void may_throw(int);
|
||||||
|
; void f() {
|
||||||
|
; try {
|
||||||
|
; may_throw(1);
|
||||||
|
; try {
|
||||||
|
; may_throw(2);
|
||||||
|
; } catch (int) {
|
||||||
|
; may_throw(3);
|
||||||
|
; }
|
||||||
|
; } catch (int) {
|
||||||
|
; may_throw(4);
|
||||||
|
; }
|
||||||
|
; }
|
||||||
|
|
||||||
|
%rtti.TypeDescriptor2 = type { i8**, i8*, [3 x i8] }
|
||||||
|
%eh.CatchHandlerType = type { i32, i8* }
|
||||||
|
|
||||||
|
declare void @may_throw(i32)
|
||||||
|
declare i32 @__CxxFrameHandler3(...)
|
||||||
|
declare void @llvm.eh.begincatch(i8*, i8*)
|
||||||
|
declare void @llvm.eh.endcatch()
|
||||||
|
declare i32 @llvm.eh.typeid.for(i8*)
|
||||||
|
|
||||||
|
$"\01??_R0H@8" = comdat any
|
||||||
|
|
||||||
|
@"\01??_7type_info@@6B@" = external constant i8*
|
||||||
|
@"\01??_R0H@8" = linkonce_odr global %rtti.TypeDescriptor2 { i8** @"\01??_7type_info@@6B@", i8* null, [3 x i8] c".H\00" }, comdat
|
||||||
|
@llvm.eh.handlertype.H.0 = private unnamed_addr constant %eh.CatchHandlerType { i32 0, i8* bitcast (%rtti.TypeDescriptor2* @"\01??_R0H@8" to i8*) }, section "llvm.metadata"
|
||||||
|
|
||||||
|
define void @f() #0 {
|
||||||
|
entry:
|
||||||
|
invoke void @may_throw(i32 1)
|
||||||
|
to label %invoke.cont unwind label %lpad
|
||||||
|
|
||||||
|
invoke.cont: ; preds = %entry
|
||||||
|
invoke void @may_throw(i32 2)
|
||||||
|
to label %try.cont.9 unwind label %lpad.1
|
||||||
|
|
||||||
|
try.cont.9: ; preds = %invoke.cont.3, %invoke.cont, %catch.7
|
||||||
|
; FIXME: Something about our CFG breaks TailDuplication. This empy asm blocks
|
||||||
|
; it so we can focus on testing the state numbering.
|
||||||
|
call void asm sideeffect "", "~{dirflag},~{fpsr},~{flags}"()
|
||||||
|
ret void
|
||||||
|
|
||||||
|
lpad: ; preds = %catch, %entry
|
||||||
|
%0 = landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*)
|
||||||
|
catch %eh.CatchHandlerType* @llvm.eh.handlertype.H.0
|
||||||
|
%1 = extractvalue { i8*, i32 } %0, 0
|
||||||
|
%2 = extractvalue { i8*, i32 } %0, 1
|
||||||
|
br label %catch.dispatch.4
|
||||||
|
|
||||||
|
lpad.1: ; preds = %invoke.cont
|
||||||
|
%3 = landingpad { i8*, i32 } personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*)
|
||||||
|
catch i8* bitcast (%eh.CatchHandlerType* @llvm.eh.handlertype.H.0 to i8*)
|
||||||
|
%4 = extractvalue { i8*, i32 } %3, 0
|
||||||
|
%5 = extractvalue { i8*, i32 } %3, 1
|
||||||
|
%6 = tail call i32 @llvm.eh.typeid.for(i8* bitcast (%eh.CatchHandlerType* @llvm.eh.handlertype.H.0 to i8*)) #3
|
||||||
|
%matches = icmp eq i32 %5, %6
|
||||||
|
br i1 %matches, label %catch, label %catch.dispatch.4
|
||||||
|
|
||||||
|
catch.dispatch.4: ; preds = %lpad.1, %lpad
|
||||||
|
%exn.slot.0 = phi i8* [ %4, %lpad.1 ], [ %1, %lpad ]
|
||||||
|
%ehselector.slot.0 = phi i32 [ %5, %lpad.1 ], [ %2, %lpad ]
|
||||||
|
%.pre = tail call i32 @llvm.eh.typeid.for(i8* bitcast (%eh.CatchHandlerType* @llvm.eh.handlertype.H.0 to i8*)) #3
|
||||||
|
%matches6 = icmp eq i32 %ehselector.slot.0, %.pre
|
||||||
|
br i1 %matches6, label %catch.7, label %eh.resume
|
||||||
|
|
||||||
|
catch.7: ; preds = %catch.dispatch.4
|
||||||
|
tail call void @llvm.eh.begincatch(i8* %exn.slot.0, i8* null) #3
|
||||||
|
tail call void @may_throw(i32 4)
|
||||||
|
tail call void @llvm.eh.endcatch() #3
|
||||||
|
br label %try.cont.9
|
||||||
|
|
||||||
|
catch: ; preds = %lpad.1
|
||||||
|
tail call void @llvm.eh.begincatch(i8* %4, i8* null) #3
|
||||||
|
invoke void @may_throw(i32 3)
|
||||||
|
to label %invoke.cont.3 unwind label %lpad
|
||||||
|
|
||||||
|
invoke.cont.3: ; preds = %catch
|
||||||
|
tail call void @llvm.eh.endcatch() #3
|
||||||
|
br label %try.cont.9
|
||||||
|
|
||||||
|
eh.resume: ; preds = %catch.dispatch.4
|
||||||
|
%lpad.val = insertvalue { i8*, i32 } undef, i8* %exn.slot.0, 0
|
||||||
|
%lpad.val.12 = insertvalue { i8*, i32 } %lpad.val, i32 %ehselector.slot.0, 1
|
||||||
|
resume { i8*, i32 } %lpad.val.12
|
||||||
|
}
|
||||||
|
|
||||||
|
; CHECK-LABEL: _f:
|
||||||
|
; CHECK: movl $-1, [[state:[0-9]+]](%esp)
|
||||||
|
; CHECK: movl $___ehhandler$f, {{.*}}
|
||||||
|
;
|
||||||
|
; CHECK: movl $0, [[state]](%esp)
|
||||||
|
; CHECK: movl $1, (%esp)
|
||||||
|
; CHECK: calll _may_throw
|
||||||
|
;
|
||||||
|
; CHECK: movl $1, [[state]](%esp)
|
||||||
|
; CHECK: movl $2, (%esp)
|
||||||
|
; CHECK: calll _may_throw
|
||||||
|
|
||||||
|
; CHECK-LABEL: _f.catch:
|
||||||
|
; CHECK: movl $4, Lf$frame_escape_{{[0-9]+.*}}
|
||||||
|
; CHECK: movl $4, (%esp)
|
||||||
|
; CHECK: calll _may_throw
|
||||||
|
|
||||||
|
; CHECK-LABEL: _f.catch.1:
|
||||||
|
; CHECK: movl $3, Lf$frame_escape_{{[0-9]+.*}}
|
||||||
|
; CHECK: movl $3, (%esp)
|
||||||
|
; CHECK: calll _may_throw
|
||||||
@@ -46,7 +46,7 @@ catchall:
|
|||||||
; CHECK-LABEL: _use_except_handler4:
|
; CHECK-LABEL: _use_except_handler4:
|
||||||
; CHECK: subl ${{[0-9]+}}, %esp
|
; CHECK: subl ${{[0-9]+}}, %esp
|
||||||
; CHECK: movl %esp, (%esp)
|
; CHECK: movl %esp, (%esp)
|
||||||
; CHECK: movl $-2, 20(%esp)
|
; CHECK: movl $-1, 20(%esp)
|
||||||
; CHECK: movl $L__ehtable$use_except_handler4, 4(%esp)
|
; CHECK: movl $L__ehtable$use_except_handler4, 4(%esp)
|
||||||
; CHECK: leal 8(%esp), %[[node:[^ ,]*]]
|
; CHECK: leal 8(%esp), %[[node:[^ ,]*]]
|
||||||
; CHECK: movl $__except_handler4, 12(%esp)
|
; CHECK: movl $__except_handler4, 12(%esp)
|
||||||
@@ -81,6 +81,7 @@ catchall:
|
|||||||
; CHECK: movl %fs:0, %[[next:[^ ,]*]]
|
; CHECK: movl %fs:0, %[[next:[^ ,]*]]
|
||||||
; CHECK: movl %[[next]], 4(%esp)
|
; CHECK: movl %[[next]], 4(%esp)
|
||||||
; CHECK: movl %[[node]], %fs:0
|
; CHECK: movl %[[node]], %fs:0
|
||||||
|
; CHECK: movl $0, 12(%esp)
|
||||||
; CHECK: calll _may_throw_or_crash
|
; CHECK: calll _may_throw_or_crash
|
||||||
; CHECK: movl 4(%esp), %[[next:[^ ,]*]]
|
; CHECK: movl 4(%esp), %[[next:[^ ,]*]]
|
||||||
; CHECK: movl %[[next]], %fs:0
|
; CHECK: movl %[[next]], %fs:0
|
||||||
|
|||||||
Reference in New Issue
Block a user