summaryrefslogtreecommitdiffstats
path: root/llvm/lib/CodeGen/AsmPrinter/WinException.cpp
diff options
context:
space:
mode:
authorDavid Majnemer <david.majnemer@gmail.com>2015-12-12 05:38:55 +0000
committerDavid Majnemer <david.majnemer@gmail.com>2015-12-12 05:38:55 +0000
commit8a1c45d6e86d54c40835fa8638d1fd900071783c (patch)
treee485010342db16bc7c4de112e89d5b5e23b29bba /llvm/lib/CodeGen/AsmPrinter/WinException.cpp
parenta38312a9a4eeb8ab8976adf5712fadd68dd763cf (diff)
downloadbcm5719-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.cpp113
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.
+ }
}
}
OpenPOWER on IntegriCloud