From 57810cdac4c842b4b395d2a0b2fae406aacb3ee4 Mon Sep 17 00:00:00 2001 From: Duncan Sands Date: Wed, 5 Sep 2007 11:27:52 +0000 Subject: [PATCH] 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. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@41718 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/CodeGen/DwarfWriter.cpp | 224 ++++++++++++------ lib/CodeGen/MachineModuleInfo.cpp | 24 +- lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp | 4 +- 3 files changed, 165 insertions(+), 87 deletions(-) diff --git a/lib/CodeGen/DwarfWriter.cpp b/lib/CodeGen/DwarfWriter.cpp index 232c5c4ba2e..e9988743a50 100644 --- a/lib/CodeGen/DwarfWriter.cpp +++ b/lib/CodeGen/DwarfWriter.cpp @@ -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 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 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 FirstActions; - FirstActions.reserve(PadInfos.size()); - - // The actions table. - SmallVector 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 Actions; + SmallVector 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 &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 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); } diff --git a/lib/CodeGen/MachineModuleInfo.cpp b/lib/CodeGen/MachineModuleInfo.cpp index 62224fdca84..8360745ff16 100644 --- a/lib/CodeGen/MachineModuleInfo.cpp +++ b/lib/CodeGen/MachineModuleInfo.cpp @@ -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; } } diff --git a/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp b/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp index 62bcc32bb4e..a695048a5ad 100644 --- a/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp +++ b/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp @@ -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();