diff options
author | David Majnemer <david.majnemer@gmail.com> | 2015-12-12 05:38:55 +0000 |
---|---|---|
committer | David Majnemer <david.majnemer@gmail.com> | 2015-12-12 05:38:55 +0000 |
commit | 8a1c45d6e86d54c40835fa8638d1fd900071783c (patch) | |
tree | e485010342db16bc7c4de112e89d5b5e23b29bba /llvm/lib/CodeGen/AsmPrinter/WinException.cpp | |
parent | a38312a9a4eeb8ab8976adf5712fadd68dd763cf (diff) | |
download | bcm5719-llvm-8a1c45d6e86d54c40835fa8638d1fd900071783c.tar.gz bcm5719-llvm-8a1c45d6e86d54c40835fa8638d1fd900071783c.zip |
[IR] Reformulate LLVM's EH funclet IR
While we have successfully implemented a funclet-oriented EH scheme on
top of LLVM IR, our scheme has some notable deficiencies:
- catchendpad and cleanupendpad are necessary in the current design
but they are difficult to explain to others, even to seasoned LLVM
experts.
- catchendpad and cleanupendpad are optimization barriers. They cannot
be split and force all potentially throwing call-sites to be invokes.
This has a noticable effect on the quality of our code generation.
- catchpad, while similar in some aspects to invoke, is fairly awkward.
It is unsplittable, starts a funclet, and has control flow to other
funclets.
- The nesting relationship between funclets is currently a property of
control flow edges. Because of this, we are forced to carefully
analyze the flow graph to see if there might potentially exist illegal
nesting among funclets. While we have logic to clone funclets when
they are illegally nested, it would be nicer if we had a
representation which forbade them upfront.
Let's clean this up a bit by doing the following:
- Instead, make catchpad more like cleanuppad and landingpad: no control
flow, just a bunch of simple operands; catchpad would be splittable.
- Introduce catchswitch, a control flow instruction designed to model
the constraints of funclet oriented EH.
- Make funclet scoping explicit by having funclet instructions consume
the token produced by the funclet which contains them.
- Remove catchendpad and cleanupendpad. Their presence can be inferred
implicitly using coloring information.
N.B. The state numbering code for the CLR has been updated but the
veracity of it's output cannot be spoken for. An expert should take a
look to make sure the results are reasonable.
Reviewers: rnk, JosephTremoulet, andrew.w.kaylor
Differential Revision: http://reviews.llvm.org/D15139
llvm-svn: 255422
Diffstat (limited to 'llvm/lib/CodeGen/AsmPrinter/WinException.cpp')
-rw-r--r-- | llvm/lib/CodeGen/AsmPrinter/WinException.cpp | 113 |
1 files changed, 63 insertions, 50 deletions
diff --git a/llvm/lib/CodeGen/AsmPrinter/WinException.cpp b/llvm/lib/CodeGen/AsmPrinter/WinException.cpp index cd1f3f51bc4..e2994172415 100644 --- a/llvm/lib/CodeGen/AsmPrinter/WinException.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/WinException.cpp @@ -344,42 +344,32 @@ class InvokeStateChangeIterator { InvokeStateChangeIterator(const WinEHFuncInfo &EHInfo, MachineFunction::const_iterator MFI, MachineFunction::const_iterator MFE, - MachineBasicBlock::const_iterator MBBI) - : EHInfo(EHInfo), MFI(MFI), MFE(MFE), MBBI(MBBI) { + MachineBasicBlock::const_iterator MBBI, + int BaseState) + : EHInfo(EHInfo), MFI(MFI), MFE(MFE), MBBI(MBBI), BaseState(BaseState) { LastStateChange.PreviousEndLabel = nullptr; LastStateChange.NewStartLabel = nullptr; - LastStateChange.NewState = NullState; + LastStateChange.NewState = BaseState; scan(); } public: static iterator_range<InvokeStateChangeIterator> - range(const WinEHFuncInfo &EHInfo, const MachineFunction &MF) { - // Reject empty MFs to simplify bookkeeping by ensuring that we can get the - // end of the last block. - assert(!MF.empty()); - auto FuncBegin = MF.begin(); - auto FuncEnd = MF.end(); - auto BlockBegin = FuncBegin->begin(); - auto BlockEnd = MF.back().end(); - return make_range( - InvokeStateChangeIterator(EHInfo, FuncBegin, FuncEnd, BlockBegin), - InvokeStateChangeIterator(EHInfo, FuncEnd, FuncEnd, BlockEnd)); - } - static iterator_range<InvokeStateChangeIterator> range(const WinEHFuncInfo &EHInfo, MachineFunction::const_iterator Begin, - MachineFunction::const_iterator End) { + MachineFunction::const_iterator End, int BaseState = NullState) { // Reject empty ranges to simplify bookkeeping by ensuring that we can get // the end of the last block. assert(Begin != End); auto BlockBegin = Begin->begin(); auto BlockEnd = std::prev(End)->end(); - return make_range(InvokeStateChangeIterator(EHInfo, Begin, End, BlockBegin), - InvokeStateChangeIterator(EHInfo, End, End, BlockEnd)); + return make_range( + InvokeStateChangeIterator(EHInfo, Begin, End, BlockBegin, BaseState), + InvokeStateChangeIterator(EHInfo, End, End, BlockEnd, BaseState)); } // Iterator methods. bool operator==(const InvokeStateChangeIterator &O) const { + assert(BaseState == O.BaseState); // Must be visiting same block. if (MFI != O.MFI) return false; @@ -410,6 +400,7 @@ private: MachineBasicBlock::const_iterator MBBI; InvokeStateChange LastStateChange; bool VisitingInvoke = false; + int BaseState; }; } // end anonymous namespace @@ -421,14 +412,14 @@ InvokeStateChangeIterator &InvokeStateChangeIterator::scan() { MBBI = MFI->begin(); for (auto MBBE = MFI->end(); MBBI != MBBE; ++MBBI) { const MachineInstr &MI = *MBBI; - if (!VisitingInvoke && LastStateChange.NewState != NullState && + if (!VisitingInvoke && LastStateChange.NewState != BaseState && MI.isCall() && !EHStreamer::callToNoUnwindFunction(&MI)) { // Indicate a change of state to the null state. We don't have // start/end EH labels handy but the caller won't expect them for // null state regions. LastStateChange.PreviousEndLabel = CurrentEndLabel; LastStateChange.NewStartLabel = nullptr; - LastStateChange.NewState = NullState; + LastStateChange.NewState = BaseState; CurrentEndLabel = nullptr; // Don't re-visit this instr on the next scan ++MBBI; @@ -443,18 +434,12 @@ InvokeStateChangeIterator &InvokeStateChangeIterator::scan() { VisitingInvoke = false; continue; } - auto InvokeMapIter = EHInfo.InvokeToStateMap.find(Label); + auto InvokeMapIter = EHInfo.LabelToStateMap.find(Label); // Ignore EH labels that aren't the ones inserted before an invoke - if (InvokeMapIter == EHInfo.InvokeToStateMap.end()) + if (InvokeMapIter == EHInfo.LabelToStateMap.end()) continue; auto &StateAndEnd = InvokeMapIter->second; int NewState = StateAndEnd.first; - // Ignore EH labels explicitly annotated with the null state (which - // can happen for invokes that unwind to a chain of endpads the last - // of which unwinds to caller). We'll see the subsequent invoke and - // report a transition to the null state same as we do for calls. - if (NewState == NullState) - continue; // Keep track of the fact that we're between EH start/end labels so // we know not to treat the inoke we'll see as unwinding to caller. VisitingInvoke = true; @@ -476,11 +461,11 @@ InvokeStateChangeIterator &InvokeStateChangeIterator::scan() { } } // Iteration hit the end of the block range. - if (LastStateChange.NewState != NullState) { + if (LastStateChange.NewState != BaseState) { // Report the end of the last new state LastStateChange.PreviousEndLabel = CurrentEndLabel; LastStateChange.NewStartLabel = nullptr; - LastStateChange.NewState = NullState; + LastStateChange.NewState = BaseState; // Leave CurrentEndLabel non-null to distinguish this state from end. assert(CurrentEndLabel != nullptr); return *this; @@ -775,26 +760,54 @@ void WinException::emitCXXFrameHandler3Table(const MachineFunction *MF) { void WinException::computeIP2StateTable( const MachineFunction *MF, const WinEHFuncInfo &FuncInfo, SmallVectorImpl<std::pair<const MCExpr *, int>> &IPToStateTable) { - // Indicate that all calls from the prologue to the first invoke unwind to - // caller. We handle this as a special case since other ranges starting at end - // labels need to use LtmpN+1. - MCSymbol *StartLabel = Asm->getFunctionBegin(); - assert(StartLabel && "need local function start label"); - IPToStateTable.push_back(std::make_pair(create32bitRef(StartLabel), -1)); - - // FIXME: Do we need to emit entries for funclet base states? - for (const auto &StateChange : - InvokeStateChangeIterator::range(FuncInfo, *MF)) { - // Compute the label to report as the start of this entry; use the EH start - // label for the invoke if we have one, otherwise (this is a call which may - // unwind to our caller and does not have an EH start label, so) use the - // previous end label. - const MCSymbol *ChangeLabel = StateChange.NewStartLabel; - if (!ChangeLabel) - ChangeLabel = StateChange.PreviousEndLabel; - // Emit an entry indicating that PCs after 'Label' have this EH state. + + for (MachineFunction::const_iterator FuncletStart = MF->begin(), + FuncletEnd = MF->begin(), + End = MF->end(); + FuncletStart != End; FuncletStart = FuncletEnd) { + // Find the end of the funclet + while (++FuncletEnd != End) { + if (FuncletEnd->isEHFuncletEntry()) { + break; + } + } + + // Don't emit ip2state entries for cleanup funclets. Any interesting + // exceptional actions in cleanups must be handled in a separate IR + // function. + if (FuncletStart->isCleanupFuncletEntry()) + continue; + + MCSymbol *StartLabel; + int BaseState; + if (FuncletStart == MF->begin()) { + BaseState = NullState; + StartLabel = Asm->getFunctionBegin(); + } else { + auto *FuncletPad = + cast<FuncletPadInst>(FuncletStart->getBasicBlock()->getFirstNonPHI()); + assert(FuncInfo.FuncletBaseStateMap.count(FuncletPad) != 0); + BaseState = FuncInfo.FuncletBaseStateMap.find(FuncletPad)->second; + StartLabel = getMCSymbolForMBB(Asm, &*FuncletStart); + } + assert(StartLabel && "need local function start label"); IPToStateTable.push_back( - std::make_pair(getLabelPlusOne(ChangeLabel), StateChange.NewState)); + std::make_pair(create32bitRef(StartLabel), BaseState)); + + for (const auto &StateChange : InvokeStateChangeIterator::range( + FuncInfo, FuncletStart, FuncletEnd, BaseState)) { + // Compute the label to report as the start of this entry; use the EH + // start label for the invoke if we have one, otherwise (this is a call + // which may unwind to our caller and does not have an EH start label, so) + // use the previous end label. + const MCSymbol *ChangeLabel = StateChange.NewStartLabel; + if (!ChangeLabel) + ChangeLabel = StateChange.PreviousEndLabel; + // Emit an entry indicating that PCs after 'Label' have this EH state. + IPToStateTable.push_back( + std::make_pair(getLabelPlusOne(ChangeLabel), StateChange.NewState)); + // FIXME: assert that NewState is between CatchLow and CatchHigh. + } } } |