mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-07-25 13:24:46 +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:
@@ -80,33 +80,6 @@ static ISD::NodeType getPreferredExtendForValue(const Value *V) {
|
||||
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,
|
||||
SelectionDAG *DAG) {
|
||||
Fn = &fn;
|
||||
@@ -291,31 +264,18 @@ void FunctionLoweringInfo::set(const Function &fn, MachineFunction &mf,
|
||||
if (!isMSVCEHPersonality(Personality))
|
||||
return;
|
||||
|
||||
WinEHFuncInfo *EHInfo = nullptr;
|
||||
if (Personality == EHPersonality::MSVC_Win64SEH) {
|
||||
addSEHHandlersForLPads(LPads);
|
||||
} else if (Personality == EHPersonality::MSVC_CXX) {
|
||||
const Function *WinEHParentFn = MMI.getWinEHParent(&fn);
|
||||
EHInfo = &MMI.getWinEHFuncInfo(WinEHParentFn);
|
||||
if (EHInfo->LandingPadStateMap.empty()) {
|
||||
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());
|
||||
}
|
||||
WinEHFuncInfo &EHInfo = MMI.getWinEHFuncInfo(WinEHParentFn);
|
||||
calculateWinCXXEHStateNumbers(WinEHParentFn, EHInfo);
|
||||
|
||||
// Copy the state numbers to LandingPadInfo for the current function, which
|
||||
// could be a handler or the parent.
|
||||
for (const LandingPadInst *LP : LPads) {
|
||||
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
|
||||
/// FunctionLoweringInfo to an empty state, ready to be used for a
|
||||
/// different function.
|
||||
|
@@ -2480,3 +2480,377 @@ void llvm::parseEHActions(
|
||||
}
|
||||
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());
|
||||
}
|
||||
|
Reference in New Issue
Block a user