The C++ exception handling personality function wants

to know about calls that cannot throw ('nounwind'):
if such a call does throw for some reason then the
personality will terminate the program.  The distinction
between an ordinary call and a nounwind call is that
an ordinary call gets an entry in the exception table
but a nounwind call does not.  This patch sets up the
exception table appropriately.  One oddity is that
I've chosen to bracket nounwind calls with labels (like
invokes) - the other choice would have been to bracket
ordinary calls with labels.  While bracketing
ordinary calls is more natural (because bracketing
by labels would then correspond exactly to getting an
entry in the exception table), I didn't do it because
introducing labels impedes some optimizations and I'm
guessing that ordinary calls occur more often than
nounwind calls.  This fixes the gcc filter2 eh test,
at least at -O0 (the inliner needs some tweaking at
higher optimization levels).


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@45197 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Duncan Sands 2007-12-19 07:36:31 +00:00
parent 9999e685ea
commit 481dc721c3
3 changed files with 58 additions and 26 deletions

View File

@ -3013,8 +3013,10 @@ private:
/// CallSiteEntry - Structure describing an entry in the call-site table. /// CallSiteEntry - Structure describing an entry in the call-site table.
struct CallSiteEntry { struct CallSiteEntry {
// The 'try-range' is BeginLabel .. EndLabel.
unsigned BeginLabel; // zero indicates the start of the function. unsigned BeginLabel; // zero indicates the start of the function.
unsigned EndLabel; // zero indicates the end of the function. unsigned EndLabel; // zero indicates the end of the function.
// The landing pad starts at PadLabel.
unsigned PadLabel; // zero indicates that there is no landing pad. unsigned PadLabel; // zero indicates that there is no landing pad.
unsigned Action; unsigned Action;
}; };
@ -3113,13 +3115,21 @@ private:
SizeActions += SizeSiteActions; SizeActions += SizeSiteActions;
} }
// Compute the call-site table. Entries must be ordered by address. // Compute the call-site table. The entry for an invoke has a try-range
// containing the call, a non-zero landing pad and an appropriate action.
// The entry for an ordinary call has a try-range containing the call and
// zero for the landing pad and the action. Calls marked 'nounwind' have
// no entry and must not be contained in the try-range of any entry - they
// form gaps in the table. Entries must be ordered by try-range address.
SmallVector<CallSiteEntry, 64> CallSites; SmallVector<CallSiteEntry, 64> CallSites;
RangeMapType PadMap; RangeMapType PadMap;
// Invokes and nounwind calls have entries in PadMap (due to being bracketed
// by try-range labels when lowered). Ordinary calls do not, so appropriate
// try-ranges for them need be deduced.
for (unsigned i = 0, N = LandingPads.size(); i != N; ++i) { for (unsigned i = 0, N = LandingPads.size(); i != N; ++i) {
const LandingPadInfo *LandingPad = LandingPads[i]; const LandingPadInfo *LandingPad = LandingPads[i];
for (unsigned j=0, E = LandingPad->BeginLabels.size(); j != E; ++j) { for (unsigned j = 0, E = LandingPad->BeginLabels.size(); j != E; ++j) {
unsigned BeginLabel = LandingPad->BeginLabels[j]; unsigned BeginLabel = LandingPad->BeginLabels[j];
assert(!PadMap.count(BeginLabel) && "Duplicate landing pad labels!"); assert(!PadMap.count(BeginLabel) && "Duplicate landing pad labels!");
PadRange P = { i, j }; PadRange P = { i, j };
@ -3127,27 +3137,39 @@ private:
} }
} }
bool MayThrow = false; // The end label of the previous invoke or nounwind try-range.
unsigned LastLabel = 0; unsigned LastLabel = 0;
// Whether there is a potentially throwing instruction (currently this means
// an ordinary call) between the end of the previous try-range and now.
bool SawPotentiallyThrowing = false;
// Whether the last callsite entry was for an invoke.
bool PreviousIsInvoke = false;
const TargetInstrInfo *TII = MF->getTarget().getInstrInfo(); const TargetInstrInfo *TII = MF->getTarget().getInstrInfo();
// Visit all instructions in order of address.
for (MachineFunction::const_iterator I = MF->begin(), E = MF->end(); for (MachineFunction::const_iterator I = MF->begin(), E = MF->end();
I != E; ++I) { I != E; ++I) {
for (MachineBasicBlock::const_iterator MI = I->begin(), E = I->end(); for (MachineBasicBlock::const_iterator MI = I->begin(), E = I->end();
MI != E; ++MI) { MI != E; ++MI) {
if (MI->getOpcode() != TargetInstrInfo::LABEL) { if (MI->getOpcode() != TargetInstrInfo::LABEL) {
MayThrow |= TII->isCall(MI->getOpcode()); SawPotentiallyThrowing |= TII->isCall(MI->getOpcode());
continue; continue;
} }
unsigned BeginLabel = MI->getOperand(0).getImmedValue(); unsigned BeginLabel = MI->getOperand(0).getImmedValue();
assert(BeginLabel && "Invalid label!"); assert(BeginLabel && "Invalid label!");
// End of the previous try-range?
if (BeginLabel == LastLabel) if (BeginLabel == LastLabel)
MayThrow = false; SawPotentiallyThrowing = false;
// Beginning of a new try-range?
RangeMapType::iterator L = PadMap.find(BeginLabel); RangeMapType::iterator L = PadMap.find(BeginLabel);
if (L == PadMap.end()) if (L == PadMap.end())
// Nope, it was just some random label.
continue; continue;
PadRange P = L->second; PadRange P = L->second;
@ -3159,36 +3181,43 @@ private:
// If some instruction between the previous try-range and this one may // If some instruction between the previous try-range and this one may
// throw, create a call-site entry with no landing pad for the region // throw, create a call-site entry with no landing pad for the region
// between the try-ranges. // between the try-ranges.
if (MayThrow) { if (SawPotentiallyThrowing) {
CallSiteEntry Site = {LastLabel, BeginLabel, 0, 0}; CallSiteEntry Site = {LastLabel, BeginLabel, 0, 0};
CallSites.push_back(Site); CallSites.push_back(Site);
PreviousIsInvoke = false;
} }
LastLabel = LandingPad->EndLabels[P.RangeIndex]; LastLabel = LandingPad->EndLabels[P.RangeIndex];
CallSiteEntry Site = {BeginLabel, LastLabel, assert(BeginLabel && LastLabel && "Invalid landing pad!");
LandingPad->LandingPadLabel, FirstActions[P.PadIndex]};
assert(Site.BeginLabel && Site.EndLabel && Site.PadLabel && if (LandingPad->LandingPadLabel) {
"Invalid landing pad!"); // This try-range is for an invoke.
CallSiteEntry Site = {BeginLabel, LastLabel,
LandingPad->LandingPadLabel, FirstActions[P.PadIndex]};
// Try to merge with the previous call-site. // Try to merge with the previous call-site.
if (CallSites.size()) { if (PreviousIsInvoke) {
CallSiteEntry &Prev = CallSites[CallSites.size()-1]; CallSiteEntry &Prev = CallSites[CallSites.size()-1];
if (Site.PadLabel == Prev.PadLabel && Site.Action == Prev.Action) { if (Site.PadLabel == Prev.PadLabel && Site.Action == Prev.Action) {
// Extend the range of the previous entry. // Extend the range of the previous entry.
Prev.EndLabel = Site.EndLabel; Prev.EndLabel = Site.EndLabel;
continue; continue;
}
} }
}
// Otherwise, create a new call-site. // Otherwise, create a new call-site.
CallSites.push_back(Site); CallSites.push_back(Site);
PreviousIsInvoke = true;
} else {
// Create a gap.
PreviousIsInvoke = false;
}
} }
} }
// If some instruction between the previous try-range and the end of the // If some instruction between the previous try-range and the end of the
// function may throw, create a call-site entry with no landing pad for the // function may throw, create a call-site entry with no landing pad for the
// region following the try-range. // region following the try-range.
if (MayThrow) { if (SawPotentiallyThrowing) {
CallSiteEntry Site = {LastLabel, 0, 0, 0}; CallSiteEntry Site = {LastLabel, 0, 0, 0};
CallSites.push_back(Site); CallSites.push_back(Site);
} }

View File

@ -1747,7 +1747,7 @@ void MachineModuleInfo::TidyLandingPads() {
LandingPad.LandingPadLabel = MappedLabel(LandingPad.LandingPadLabel); LandingPad.LandingPadLabel = MappedLabel(LandingPad.LandingPadLabel);
// Special case: we *should* emit LPs with null LP MBB. This indicates // Special case: we *should* emit LPs with null LP MBB. This indicates
// "rethrow" case. // "nounwind" case.
if (!LandingPad.LandingPadLabel && LandingPad.LandingPadBlock) { if (!LandingPad.LandingPadLabel && LandingPad.LandingPadBlock) {
LandingPads.erase(LandingPads.begin() + i); LandingPads.erase(LandingPads.begin() + i);
continue; continue;
@ -1757,7 +1757,6 @@ void MachineModuleInfo::TidyLandingPads() {
unsigned BeginLabel = MappedLabel(LandingPad.BeginLabels[j]); unsigned BeginLabel = MappedLabel(LandingPad.BeginLabels[j]);
unsigned EndLabel = MappedLabel(LandingPad.EndLabels[j]); unsigned EndLabel = MappedLabel(LandingPad.EndLabels[j]);
if (!BeginLabel || !EndLabel) { if (!BeginLabel || !EndLabel) {
LandingPad.BeginLabels.erase(LandingPad.BeginLabels.begin() + j); LandingPad.BeginLabels.erase(LandingPad.BeginLabels.begin() + j);
LandingPad.EndLabels.erase(LandingPad.EndLabels.begin() + j); LandingPad.EndLabels.erase(LandingPad.EndLabels.begin() + j);

View File

@ -2952,7 +2952,11 @@ void SelectionDAGLowering::LowerCallTo(Instruction &I,
Args.push_back(Entry); Args.push_back(Entry);
} }
if (ExceptionHandling && MMI && LandingPad) { bool MarkTryRange = LandingPad ||
// C++ requires special handling of 'nounwind' calls.
(Attrs && Attrs->paramHasAttr(0, ParamAttr::NoUnwind));
if (MarkTryRange && ExceptionHandling && MMI) {
// Insert a label before the invoke call to mark the try range. This can be // Insert a label before the invoke call to mark the try range. This can be
// used to detect deletion of the invoke via the MachineModuleInfo. // used to detect deletion of the invoke via the MachineModuleInfo.
BeginLabel = MMI->NextLabelID(); BeginLabel = MMI->NextLabelID();
@ -2969,7 +2973,7 @@ void SelectionDAGLowering::LowerCallTo(Instruction &I,
setValue(&I, Result.first); setValue(&I, Result.first);
DAG.setRoot(Result.second); DAG.setRoot(Result.second);
if (ExceptionHandling && MMI && LandingPad) { if (MarkTryRange && ExceptionHandling && MMI) {
// Insert a label at the end of the invoke call to mark the try range. This // Insert a label at the end of the invoke call to mark the try range. This
// can be used to detect deletion of the invoke via the MachineModuleInfo. // can be used to detect deletion of the invoke via the MachineModuleInfo.
EndLabel = MMI->NextLabelID(); EndLabel = MMI->NextLabelID();