1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-11-24 11:42:57 +01:00

Fix PR1628. When exception handling is turned on,

labels are generated bracketing each call (not just
invokes).  This is used to generate entries in
the exception table required by the C++ personality.
However it gets in the way of tail-merging.  This
patch solves the problem by no longer placing labels
around ordinary calls.  Instead we generate entries
in the exception table that cover every instruction
in the function that wasn't covered by an invoke
range (the range given by the labels around the invoke).
As an optimization, such entries are only generated for
parts of the function that contain a call, since for
the moment those are the only instructions that can
throw an exception [1].  As a happy consequence, we
now get a smaller exception table, since the same
region can cover many calls.  While there, I also
implemented folding of invoke ranges - successive
ranges are merged when safe to do so.  Finally, if
a selector contains only a cleanup, there's a special
shorthand for it - place a 0 in the call-site entry.
I implemented this while there.  As a result, the
exception table output (excluding filters) is now
optimal - it cannot be made smaller [2].  The
problem with throw filters is that folding them
optimally is hard, and the benefit of folding them is
minimal.

[1] I tested that having trapping instructions (eg
divide by zero) in such a region doesn't cause trouble.
[2] It could be made smaller with the help of higher
layers, eg by having branch folding reorder basic blocks
ending in invokes with the same landing pad so they
follow each other.  I don't know if this is worth doing.

llvm-svn: 41718
This commit is contained in:
Duncan Sands 2007-09-05 11:27:52 +00:00
parent 13549db795
commit ab8eb598be
3 changed files with 165 additions and 87 deletions

View File

@ -2896,7 +2896,7 @@ private:
O << UsedDirective << EHFrameInfo.FnName << ".eh\n\n";
}
/// EmitExceptionTable - Emit landpads and actions.
/// EmitExceptionTable - Emit landing pads and actions.
///
/// The general organization of the table is complex, but the basic concepts
/// are easy. First there is a header which describes the location and
@ -2951,19 +2951,31 @@ private:
static bool isPod() { return true; }
};
struct PadSite {
unsigned PadIndex;
unsigned SiteIndex;
};
typedef DenseMap<unsigned, PadSite, KeyInfo> PadMapType;
/// ActionEntry - Structure describing an entry in the actions table.
struct ActionEntry {
int ValueForTypeID; // The value to write - may not be equal to the type id.
int NextAction;
struct ActionEntry *Previous;
};
/// PadRange - Structure holding a try-range and the associated landing pad.
struct PadRange {
// The index of the landing pad.
unsigned PadIndex;
// The index of the begin and end labels in the landing pad's label lists.
unsigned RangeIndex;
};
typedef DenseMap<unsigned, PadRange, KeyInfo> RangeMapType;
/// CallSiteEntry - Structure describing an entry in the call-site table.
struct CallSiteEntry {
unsigned BeginLabel; // zero indicates the start of the function.
unsigned EndLabel; // zero indicates the end of the function.
unsigned PadLabel; // zero indicates that there is no landing pad.
unsigned Action;
};
void EmitExceptionTable() {
// Map all labels and get rid of any dead landing pads.
MMI->TidyLandingPads();
@ -2981,13 +2993,6 @@ private:
LandingPads.push_back(&PadInfos[i]);
std::sort(LandingPads.begin(), LandingPads.end(), PadLT);
// Gather first action index for each landing pad site.
SmallVector<unsigned, 64> FirstActions;
FirstActions.reserve(PadInfos.size());
// The actions table.
SmallVector<ActionEntry, 32> Actions;
// Negative type ids index into FilterIds, positive type ids index into
// TypeInfos. The value written for a positive type id is just the type
// id itself. For a negative type id, however, the value written is the
@ -3007,14 +3012,14 @@ private:
Offset -= Asm->SizeULEB128(*I);
}
// Compute sizes for exception table.
unsigned SizeSites = 0;
unsigned SizeActions = 0;
// Compute the actions table and gather the first action index for each
// landing pad site.
SmallVector<ActionEntry, 32> Actions;
SmallVector<unsigned, 64> FirstActions;
FirstActions.reserve(LandingPads.size());
// Look at each landing pad site to compute size. We need the size of each
// landing pad site info and the size of the landing pad's actions.
int FirstAction = 0;
unsigned SizeActions = 0;
for (unsigned i = 0, N = LandingPads.size(); i != N; ++i) {
const LandingPadInfo *LP = LandingPads[i];
const std::vector<int> &TypeIds = LP->TypeIds;
@ -3063,14 +3068,96 @@ private:
// Compute this sites contribution to size.
SizeActions += SizeSiteActions;
unsigned M = LP->BeginLabels.size();
SizeSites += M*(sizeof(int32_t) + // Site start.
sizeof(int32_t) + // Site length.
sizeof(int32_t) + // Landing pad.
Asm->SizeULEB128(FirstAction)); // Action.
}
// Compute the call-site table. Entries must be ordered by address.
SmallVector<CallSiteEntry, 64> CallSites;
RangeMapType PadMap;
for (unsigned i = 0, N = LandingPads.size(); i != N; ++i) {
const LandingPadInfo *LandingPad = LandingPads[i];
for (unsigned j=0, E = LandingPad->BeginLabels.size(); j != E; ++j) {
unsigned BeginLabel = LandingPad->BeginLabels[j];
assert(!PadMap.count(BeginLabel) && "Duplicate landing pad labels!");
PadRange P = { i, j };
PadMap[BeginLabel] = P;
}
}
bool MayThrow = false;
unsigned LastLabel = 0;
const TargetInstrInfo *TII = MF->getTarget().getInstrInfo();
for (MachineFunction::const_iterator I = MF->begin(), E = MF->end();
I != E; ++I) {
for (MachineBasicBlock::const_iterator MI = I->begin(), E = I->end();
MI != E; ++MI) {
if (MI->getOpcode() != TargetInstrInfo::LABEL) {
MayThrow |= TII->isCall(MI->getOpcode());
continue;
}
unsigned BeginLabel = MI->getOperand(0).getImmedValue();
assert(BeginLabel && "Invalid label!");
if (BeginLabel == LastLabel) {
MayThrow = false;
continue;
}
RangeMapType::iterator L = PadMap.find(BeginLabel);
if (L == PadMap.end())
continue;
PadRange P = L->second;
const LandingPadInfo *LandingPad = LandingPads[P.PadIndex];
assert(BeginLabel == LandingPad->BeginLabels[P.RangeIndex] &&
"Inconsistent landing pad map!");
// 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
// between the try-ranges.
if (MayThrow) {
CallSiteEntry Site = {LastLabel, BeginLabel, 0, 0};
CallSites.push_back(Site);
}
LastLabel = LandingPad->EndLabels[P.RangeIndex];
CallSiteEntry Site = {BeginLabel, LastLabel,
LandingPad->LandingPadLabel, FirstActions[P.PadIndex]};
assert(Site.BeginLabel && Site.EndLabel && Site.PadLabel &&
"Invalid landing pad!");
// Try to merge with the previous call-site.
if (CallSites.size()) {
CallSiteEntry &Prev = CallSites[CallSites.size()-1];
if (Site.PadLabel == Prev.PadLabel && Site.Action == Prev.Action) {
// Extend the range of the previous entry.
Prev.EndLabel = Site.EndLabel;
continue;
}
}
// Otherwise, create a new call-site.
CallSites.push_back(Site);
}
}
// 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
// region following the try-range.
if (MayThrow) {
CallSiteEntry Site = {LastLabel, 0, 0, 0};
CallSites.push_back(Site);
}
// Final tallies.
unsigned SizeSites = CallSites.size() * (sizeof(int32_t) + // Site start.
sizeof(int32_t) + // Site length.
sizeof(int32_t)); // Landing pad.
for (unsigned i = 0, e = CallSites.size(); i < e; ++i)
SizeSites += Asm->SizeULEB128(CallSites[i].Action);
unsigned SizeTypes = TypeInfos.size() * TAI->getAddressSize();
unsigned TypeOffset = sizeof(int8_t) + // Call site format
@ -3106,61 +3193,44 @@ private:
Asm->EmitULEB128Bytes(SizeSites);
Asm->EOL("Call-site table length");
// Emit the landing pad site information in order of address.
PadMapType PadMap;
// Emit the landing pad site information.
for (unsigned i = 0; i < CallSites.size(); ++i) {
CallSiteEntry &S = CallSites[i];
const char *BeginTag;
unsigned BeginNumber;
for (unsigned i = 0, N = LandingPads.size(); i != N; ++i) {
const LandingPadInfo *LandingPad = LandingPads[i];
for (unsigned j=0, E = LandingPad->BeginLabels.size(); j != E; ++j) {
unsigned BeginLabel = LandingPad->BeginLabels[j];
assert(!PadMap.count(BeginLabel) && "duplicate landing pad labels!");
PadSite P = { i, j };
PadMap[BeginLabel] = P;
if (!S.BeginLabel) {
BeginTag = "eh_func_begin";
BeginNumber = SubprogramCount;
} else {
BeginTag = "label";
BeginNumber = S.BeginLabel;
}
}
for (MachineFunction::const_iterator I = MF->begin(), E = MF->end();
I != E; ++I) {
for (MachineBasicBlock::const_iterator MI = I->begin(), E = I->end();
MI != E; ++MI) {
if (MI->getOpcode() != TargetInstrInfo::LABEL)
continue;
EmitSectionOffset(BeginTag, "eh_func_begin", BeginNumber, SubprogramCount,
false, true);
Asm->EOL("Region start");
unsigned BeginLabel = MI->getOperand(0).getImmedValue();
PadMapType::iterator L = PadMap.find(BeginLabel);
if (!S.EndLabel) {
EmitDifference("eh_func_end", SubprogramCount, BeginTag, BeginNumber);
} else {
EmitDifference("label", S.EndLabel, BeginTag, BeginNumber);
}
Asm->EOL("Region length");
if (L == PadMap.end())
continue;
PadSite P = L->second;
const LandingPadInfo *LandingPad = LandingPads[P.PadIndex];
assert(BeginLabel == LandingPad->BeginLabels[P.SiteIndex] &&
"Inconsistent landing pad map!");
EmitSectionOffset("label", "eh_func_begin", BeginLabel, SubprogramCount,
if (!S.PadLabel) {
if (TAI->getAddressSize() == sizeof(int32_t))
Asm->EmitInt32(0);
else
Asm->EmitInt64(0);
} else {
EmitSectionOffset("label", "eh_func_begin", S.PadLabel, SubprogramCount,
false, true);
Asm->EOL("Region start");
EmitDifference("label", LandingPad->EndLabels[P.SiteIndex],
"label", BeginLabel);
Asm->EOL("Region length");
if (LandingPad->TypeIds.empty()) {
if (TAI->getAddressSize() == sizeof(int32_t))
Asm->EmitInt32(0);
else
Asm->EmitInt64(0);
} else {
EmitSectionOffset("label", "eh_func_begin",
LandingPad->LandingPadLabel, SubprogramCount,
false, true);
}
Asm->EOL("Landing pad");
Asm->EmitULEB128Bytes(FirstActions[P.PadIndex]);
Asm->EOL("Action");
}
Asm->EOL("Landing pad");
Asm->EmitULEB128Bytes(S.Action);
Asm->EOL("Action");
}
// Emit the actions.
@ -3183,7 +3253,7 @@ private:
O << Asm->getGlobalLinkName(GV);
else
O << "0";
Asm->EOL("TypeInfo");
}
@ -3193,7 +3263,7 @@ private:
Asm->EmitULEB128Bytes(TypeID);
Asm->EOL("Filter TypeInfo index");
}
Asm->EmitAlignment(2);
}

View File

@ -1740,22 +1740,18 @@ void MachineModuleInfo::TidyLandingPads() {
LandingPadInfo &LandingPad = LandingPads[i];
LandingPad.LandingPadLabel = MappedLabel(LandingPad.LandingPadLabel);
if (!LandingPad.LandingPadBlock)
// Must not have cleanups if no landing pad.
LandingPad.TypeIds.clear();
// Special case: we *should* emit LPs with null LP MBB. This indicates
// "rethrow" case.
if (!LandingPad.LandingPadLabel && LandingPad.LandingPadBlock) {
LandingPads.erase(LandingPads.begin() + i);
continue;
}
for (unsigned j=0; j != LandingPads[i].BeginLabels.size(); ) {
unsigned BeginLabel = MappedLabel(LandingPad.BeginLabels[j]);
unsigned EndLabel = MappedLabel(LandingPad.EndLabels[j]);
if (!BeginLabel || !EndLabel) {
LandingPad.BeginLabels.erase(LandingPad.BeginLabels.begin() + j);
LandingPad.EndLabels.erase(LandingPad.EndLabels.begin() + j);
@ -1766,7 +1762,19 @@ void MachineModuleInfo::TidyLandingPads() {
LandingPad.EndLabels[j] = EndLabel;
++j;
}
// Remove landing pads with no try-ranges.
if (!LandingPads[i].BeginLabels.size()) {
LandingPads.erase(LandingPads.begin() + i);
continue;
}
// If there is no landing pad, ensure that the list of typeids is empty.
// If the only typeid is a cleanup, this is the same as having no typeids.
if (!LandingPad.LandingPadBlock ||
(LandingPad.TypeIds.size() == 1 && !LandingPad.TypeIds[0]))
LandingPad.TypeIds.clear();
++i;
}
}

View File

@ -2928,7 +2928,7 @@ void SelectionDAGLowering::LowerCallTo(Instruction &I,
Args.push_back(Entry);
}
if (ExceptionHandling && MMI) {
if (ExceptionHandling && MMI && LandingPad) {
// 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.
BeginLabel = MMI->NextLabelID();
@ -2945,7 +2945,7 @@ void SelectionDAGLowering::LowerCallTo(Instruction &I,
setValue(&I, Result.first);
DAG.setRoot(Result.second);
if (ExceptionHandling && MMI) {
if (ExceptionHandling && MMI && LandingPad) {
// 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.
EndLabel = MMI->NextLabelID();