diff --git a/llvm/include/llvm/CodeGen/AsmPrinter.h b/llvm/include/llvm/CodeGen/AsmPrinter.h --- a/llvm/include/llvm/CodeGen/AsmPrinter.h +++ b/llvm/include/llvm/CodeGen/AsmPrinter.h @@ -141,7 +141,11 @@ private: MCSymbol *CurrentFnEnd = nullptr; - MCSymbol *CurExceptionSym = nullptr; + + /// Map a basic block section ID to the exception symbol associated with that + /// section. Map entries are assigned and looked up via + /// AsmPrinter::getMBBExceptionSym. + DenseMap MBBSectionExceptionSyms; // The symbol used to represent the start of the current BB section of the // function. This is used to calculate the size of the BB section. @@ -238,7 +242,10 @@ MCSymbol *getFunctionBegin() const { return CurrentFnBegin; } MCSymbol *getFunctionEnd() const { return CurrentFnEnd; } - MCSymbol *getCurExceptionSym(); + + // Return the exception symbol associated with the MBB section containing a + // given basic block. + MCSymbol *getMBBExceptionSym(const MachineBasicBlock &MBB); /// Return information about object file lowering. const TargetLoweringObjectFile &getObjFileLowering() const; diff --git a/llvm/include/llvm/CodeGen/AsmPrinterHandler.h b/llvm/include/llvm/CodeGen/AsmPrinterHandler.h --- a/llvm/include/llvm/CodeGen/AsmPrinterHandler.h +++ b/llvm/include/llvm/CodeGen/AsmPrinterHandler.h @@ -24,7 +24,8 @@ class MachineInstr; class MCSymbol; -typedef MCSymbol *ExceptionSymbolProvider(AsmPrinter *Asm); +typedef MCSymbol *ExceptionSymbolProvider(AsmPrinter *Asm, + const MachineBasicBlock *MBB); /// Collects and handles AsmPrinter objects required to build debug /// or EH information. diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp --- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp @@ -1763,10 +1763,11 @@ return false; } -MCSymbol *AsmPrinter::getCurExceptionSym() { - if (!CurExceptionSym) - CurExceptionSym = createTempSymbol("exception"); - return CurExceptionSym; +MCSymbol *AsmPrinter::getMBBExceptionSym(const MachineBasicBlock &MBB) { + auto Res = MBBSectionExceptionSyms.try_emplace(MBB.getSectionIDNum()); + if (Res.second) + Res.first->second = createTempSymbol("exception"); + return Res.first->second; } void AsmPrinter::SetupMachineFunction(MachineFunction &MF) { @@ -1793,7 +1794,7 @@ CurrentFnBegin = nullptr; CurrentSectionBeginSym = nullptr; MBBSectionRanges.clear(); - CurExceptionSym = nullptr; + MBBSectionExceptionSyms.clear(); bool NeedsLocalForSize = MAI->needsLocalForSize(); if (F.hasFnAttribute("patchable-function-entry") || F.hasFnAttribute("function-instrument") || diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfCFIException.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfCFIException.cpp --- a/llvm/lib/CodeGen/AsmPrinter/DwarfCFIException.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfCFIException.cpp @@ -81,8 +81,9 @@ } } -static MCSymbol *getExceptionSym(AsmPrinter *Asm) { - return Asm->getCurExceptionSym(); +static MCSymbol *getExceptionSym(AsmPrinter *Asm, + const MachineBasicBlock *MBB) { + return Asm->getMBBExceptionSym(*MBB); } void DwarfCFIException::beginFunction(const MachineFunction *MF) { @@ -161,7 +162,7 @@ // Provide LSDA information. if (shouldEmitLSDA) - Asm->OutStreamer->emitCFILsda(ESP(Asm), TLOF.getLSDAEncoding()); + Asm->OutStreamer->emitCFILsda(ESP(Asm, MBB), TLOF.getLSDAEncoding()); } /// endFunction - Gather and emit post-function exception information. diff --git a/llvm/lib/CodeGen/AsmPrinter/EHStreamer.h b/llvm/lib/CodeGen/AsmPrinter/EHStreamer.h --- a/llvm/lib/CodeGen/AsmPrinter/EHStreamer.h +++ b/llvm/lib/CodeGen/AsmPrinter/EHStreamer.h @@ -69,23 +69,48 @@ unsigned Action; }; + /// Structure describing a contiguous range of call-sites which reside + /// in the same procedure fragment. With -fbasic-block-sections, there will + /// be one call site range per basic block section. Otherwise, we will have + /// one call site range containing all the call sites in the function. + struct CallSiteRange { + // Symbol marking the beginning of the precedure fragment. + MCSymbol *FragmentBeginLabel = nullptr; + // Symbol marking the end of the procedure fragment. + MCSymbol *FragmentEndLabel = nullptr; + // LSDA symbol for this call-site range. + MCSymbol *ExceptionLabel = nullptr; + // Index of the first call-site entry in the call-site table which + // belongs to this range. + size_t CallSiteBeginIdx = 0; + // Index just after the last call-site entry in the call-site table which + // belongs to this range. + size_t CallSiteEndIdx = 0; + // Whether this is the call-site range containing all the landing pads. + bool IsLPRange = false; + }; + /// Compute the actions table and gather the first action index for each /// landing pad site. - void computeActionsTable(const SmallVectorImpl &LandingPads, - SmallVectorImpl &Actions, - SmallVectorImpl &FirstActions); + void computeActionsTable( + const SmallVectorImpl &LandingPads, + SmallVectorImpl &Actions, + SmallVectorImpl &FirstActions); void computePadMap(const SmallVectorImpl &LandingPads, RangeMapType &PadMap); - /// 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. + /// Compute the call-site table and the call-site ranges. 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. CallSiteRanges vector is only populated for Itanium + /// exception handling. virtual void computeCallSiteTable( SmallVectorImpl &CallSites, + SmallVectorImpl &CallSiteRanges, const SmallVectorImpl &LandingPads, const SmallVectorImpl &FirstActions); diff --git a/llvm/lib/CodeGen/AsmPrinter/EHStreamer.cpp b/llvm/lib/CodeGen/AsmPrinter/EHStreamer.cpp --- a/llvm/lib/CodeGen/AsmPrinter/EHStreamer.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/EHStreamer.cpp @@ -214,10 +214,25 @@ /// 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. -void EHStreamer:: -computeCallSiteTable(SmallVectorImpl &CallSites, - const SmallVectorImpl &LandingPads, - const SmallVectorImpl &FirstActions) { +/// +/// Call-sites are split into one or more call-site ranges associated with +/// different sections of the function. +/// +/// - Without -basic-block-sections, all call-sites are grouped into one +/// call-site-range corresponding to the function section. +/// +/// - With -basic-block-sections, one call-site range is created for each +/// section, with its FragmentBeginLabel and FragmentEndLabel respectively +// set to the beginning and ending of the corresponding section and its +// ExceptionLabel set to the exception symbol dedicated for this section. +// Later, one LSDA header will be emitted for each call-site range with its +// call-sites following. The action table and type info table will be +// shared across all ranges. +void EHStreamer::computeCallSiteTable( + SmallVectorImpl &CallSites, + SmallVectorImpl &CallSiteRanges, + const SmallVectorImpl &LandingPads, + const SmallVectorImpl &FirstActions) { RangeMapType PadMap; computePadMap(LandingPads, PadMap); @@ -235,6 +250,21 @@ // Visit all instructions in order of address. for (const auto &MBB : *Asm->MF) { + if (&MBB == &Asm->MF->front() || MBB.isBeginSection()) { + // We start a call-site range upon function entry and at the beginning of + // every basic block section. + CallSiteRanges.push_back( + {Asm->MBBSectionRanges[MBB.getSectionIDNum()].BeginLabel, + Asm->MBBSectionRanges[MBB.getSectionIDNum()].EndLabel, + Asm->getMBBExceptionSym(MBB), CallSites.size()}); + PreviousIsInvoke = false; + SawPotentiallyThrowing = false; + LastLabel = nullptr; + } + + if (MBB.isEHPad()) + CallSiteRanges.back().IsLPRange = true; + for (const auto &MI : MBB) { if (!MI.isEHLabel()) { if (MI.isCall()) @@ -306,13 +336,22 @@ PreviousIsInvoke = true; } } - } - // 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 (SawPotentiallyThrowing && !IsSJLJ) - CallSites.push_back({LastLabel, Asm->getFunctionEnd(), nullptr, 0}); + // We end the call-site range upon function exit and at the end of every + // basic block section. + if (&MBB == &Asm->MF->back() || MBB.isEndSection()) { + // 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 (SawPotentiallyThrowing && !IsSJLJ) { + CallSiteEntry Site = {LastLabel, CallSiteRanges.back().FragmentEndLabel, + nullptr, 0}; + CallSites.push_back(Site); + SawPotentiallyThrowing = false; + } + CallSiteRanges.back().CallSiteEndIdx = CallSites.size(); + } + } } /// Emit landing pads and actions. @@ -362,9 +401,13 @@ SmallVector FirstActions; computeActionsTable(LandingPads, Actions, FirstActions); - // Compute the call-site table. + // Compute the call-site table and call-site ranges. Normally, there is only + // one call-site-range which covers the whole funciton. With + // -basic-block-sections, there is one call-site-range per basic block + // section. SmallVector CallSites; - computeCallSiteTable(CallSites, LandingPads, FirstActions); + SmallVector CallSiteRanges; + computeCallSiteTable(CallSites, CallSiteRanges, LandingPads, FirstActions); bool IsSJLJ = Asm->MAI->getExceptionHandlingType() == ExceptionHandling::SjLj; bool IsWasm = Asm->MAI->getExceptionHandlingType() == ExceptionHandling::Wasm; @@ -424,35 +467,49 @@ Asm->OutContext.getOrCreateSymbol(Twine("GCC_except_table")+ Twine(Asm->getFunctionNumber())); Asm->OutStreamer->emitLabel(GCCETSym); - Asm->OutStreamer->emitLabel(Asm->getCurExceptionSym()); - - // Emit the LSDA header. - Asm->emitEncodingByte(dwarf::DW_EH_PE_omit, "@LPStart"); - Asm->emitEncodingByte(TTypeEncoding, "@TType"); + MCSymbol *CstEndLabel = Asm->createTempSymbol( + CallSiteRanges.size() > 1 ? "action_table_base" : "cst_end"); MCSymbol *TTBaseLabel = nullptr; - if (HaveTTData) { - // N.B.: There is a dependency loop between the size of the TTBase uleb128 - // here and the amount of padding before the aligned type table. The - // assembler must sometimes pad this uleb128 or insert extra padding before - // the type table. See PR35809 or GNU as bug 4029. - MCSymbol *TTBaseRefLabel = Asm->createTempSymbol("ttbaseref"); + if (HaveTTData) TTBaseLabel = Asm->createTempSymbol("ttbase"); - Asm->emitLabelDifferenceAsULEB128(TTBaseLabel, TTBaseRefLabel); - Asm->OutStreamer->emitLabel(TTBaseRefLabel); - } - bool VerboseAsm = Asm->OutStreamer->isVerboseAsm(); + const bool VerboseAsm = Asm->OutStreamer->isVerboseAsm(); + + // Helper for emitting references (offsets) for type table and the end of the + // call-site table (which marks the beginning of the action table). + // * For Itanium, these references will be emitted for every callsite range. + // * For SJLJ and Wasm, they will be emitted only once in the LSDA header. + auto EmitTypeTableRefAndCallSiteTableEndRef = [&]() { + Asm->emitEncodingByte(TTypeEncoding, "@TType"); + if (HaveTTData) { + // N.B.: There is a dependency loop between the size of the TTBase uleb128 + // here and the amount of padding before the aligned type table. The + // assembler must sometimes pad this uleb128 or insert extra padding + // before the type table. See PR35809 or GNU as bug 4029. + MCSymbol *TTBaseRefLabel = Asm->createTempSymbol("ttbaseref"); + Asm->emitLabelDifferenceAsULEB128(TTBaseLabel, TTBaseRefLabel); + Asm->OutStreamer->emitLabel(TTBaseRefLabel); + } - // Emit the landing pad call site table. - MCSymbol *CstBeginLabel = Asm->createTempSymbol("cst_begin"); - MCSymbol *CstEndLabel = Asm->createTempSymbol("cst_end"); - Asm->emitEncodingByte(CallSiteEncoding, "Call site"); - Asm->emitLabelDifferenceAsULEB128(CstEndLabel, CstBeginLabel); - Asm->OutStreamer->emitLabel(CstBeginLabel); + // The Action table follows the call-site table. So we emit the + // label difference from here (start of the call-site table for SJLJ and + // Wasm, and start of a call-site range for Itanium) to the end of the + // whole call-site table (end of the last call-site range for Itanium). + MCSymbol *CstBeginLabel = Asm->createTempSymbol("cst_begin"); + Asm->emitEncodingByte(CallSiteEncoding, "Call site"); + Asm->emitLabelDifferenceAsULEB128(CstEndLabel, CstBeginLabel); + Asm->OutStreamer->emitLabel(CstBeginLabel); + }; // SjLj / Wasm Exception handling if (IsSJLJ || IsWasm) { + Asm->OutStreamer->emitLabel(Asm->getMBBExceptionSym(Asm->MF->front())); + + // emit the LSDA header. + Asm->emitEncodingByte(dwarf::DW_EH_PE_omit, "@LPStart"); + EmitTypeTableRefAndCallSiteTableEndRef(); + unsigned idx = 0; for (SmallVectorImpl::const_iterator I = CallSites.begin(), E = CallSites.end(); I != E; ++I, ++idx) { @@ -477,6 +534,7 @@ } Asm->emitULEB128(S.Action); } + Asm->OutStreamer->emitLabel(CstEndLabel); } else { // Itanium LSDA exception handling @@ -498,50 +556,124 @@ // A missing entry in the call-site table indicates that a call is not // supposed to throw. + assert(CallSiteRanges.size() != 0 && "No call-site ranges!"); + + // There should be only one call-site range which includes all the landing + // pads. Find that call-site range here. + const CallSiteRange *LandingPadRange = nullptr; + for (const CallSiteRange &CSRange : CallSiteRanges) { + if (CSRange.IsLPRange) { + assert(LandingPadRange == nullptr && + "All landing pads must be in a single callsite range."); + LandingPadRange = &CSRange; + } + } + + // The call-site table is split into its call-site ranges, each being + // emitted as: + // [ LPStartEncoding | LPStart ] + // [ TypeTableEncoding | TypeTableOffset ] + // [ CallSiteEncoding | CallSiteTableEndOffset ] + // cst_begin -> { call-site entries contained in this range } + // + // and is followed by the next call-site range. + // + // For each call-site range, CallSiteTableEndOffset is computed as the + // difference between cst_begin of that range and the last call-site-table's + // end label. This offset is used to find the action table. + unsigned Entry = 0; - for (SmallVectorImpl::const_iterator - I = CallSites.begin(), E = CallSites.end(); I != E; ++I) { - const CallSiteEntry &S = *I; + for (const CallSiteRange &CSRange : CallSiteRanges) { + if (CSRange.CallSiteBeginIdx != 0) { + // Align the call-site range for all ranges except the first. The + // first range is already aligned due to the exception table alignment. + Asm->emitAlignment(Align(4)); + } + Asm->OutStreamer->emitLabel(CSRange.ExceptionLabel); + + // Emit the LSDA header. + // If only one call-site range exists, LPStart is omitted as it is the + // same as the function entry. + if (CallSiteRanges.size() == 1) { + Asm->emitEncodingByte(dwarf::DW_EH_PE_omit, "@LPStart"); + } else if (!Asm->isPositionIndependent()) { + // For more than one call-site ranges, LPStart must be explicitly + // specified. + // For non-PIC we can simply use the absolute value. + Asm->emitEncodingByte(dwarf::DW_EH_PE_absptr, "@LPStart"); + Asm->OutStreamer->emitSymbolValue(LandingPadRange->FragmentBeginLabel, + Asm->MAI->getCodePointerSize()); + } else { + // For PIC mode, we Emit a PC-relative address for LPStart. + Asm->emitEncodingByte(dwarf::DW_EH_PE_pcrel, "@LPStart"); + MCContext &Context = Asm->OutStreamer->getContext(); + MCSymbol *Dot = Context.createTempSymbol(); + Asm->OutStreamer->emitLabel(Dot); + Asm->OutStreamer->emitValue( + MCBinaryExpr::createSub( + MCSymbolRefExpr::create(LandingPadRange->FragmentBeginLabel, + Context), + MCSymbolRefExpr::create(Dot, Context), Context), + Asm->MAI->getCodePointerSize()); + } + + EmitTypeTableRefAndCallSiteTableEndRef(); - MCSymbol *EHFuncBeginSym = Asm->getFunctionBegin(); + for (size_t CallSiteIdx = CSRange.CallSiteBeginIdx; + CallSiteIdx != CSRange.CallSiteEndIdx; ++CallSiteIdx) { + const CallSiteEntry &S = CallSites[CallSiteIdx]; - // Offset of the call site relative to the start of the procedure. - if (VerboseAsm) - Asm->OutStreamer->AddComment(">> Call Site " + Twine(++Entry) + " <<"); - Asm->emitCallSiteOffset(S.BeginLabel, EHFuncBeginSym, CallSiteEncoding); - if (VerboseAsm) - Asm->OutStreamer->AddComment(Twine(" Call between ") + - S.BeginLabel->getName() + " and " + - S.EndLabel->getName()); - Asm->emitCallSiteOffset(S.EndLabel, S.BeginLabel, CallSiteEncoding); + MCSymbol *EHFuncBeginSym = CSRange.FragmentBeginLabel; + MCSymbol *EHFuncEndSym = CSRange.FragmentEndLabel; - // Offset of the landing pad relative to the start of the procedure. - if (!S.LPad) { + MCSymbol *BeginLabel = S.BeginLabel; + if (!BeginLabel) + BeginLabel = EHFuncBeginSym; + MCSymbol *EndLabel = S.EndLabel; + if (!EndLabel) + EndLabel = EHFuncEndSym; + + // Offset of the call site relative to the start of the procedure. if (VerboseAsm) - Asm->OutStreamer->AddComment(" has no landing pad"); - Asm->emitCallSiteValue(0, CallSiteEncoding); - } else { + Asm->OutStreamer->AddComment(">> Call Site " + Twine(++Entry) + + " <<"); + Asm->emitCallSiteOffset(BeginLabel, EHFuncBeginSym, CallSiteEncoding); if (VerboseAsm) - Asm->OutStreamer->AddComment(Twine(" jumps to ") + - S.LPad->LandingPadLabel->getName()); - Asm->emitCallSiteOffset(S.LPad->LandingPadLabel, EHFuncBeginSym, - CallSiteEncoding); - } + Asm->OutStreamer->AddComment(Twine(" Call between ") + + BeginLabel->getName() + " and " + + EndLabel->getName()); + Asm->emitCallSiteOffset(EndLabel, BeginLabel, CallSiteEncoding); + + // Offset of the landing pad relative to the start of the landing pad + // fragment. + if (!S.LPad) { + if (VerboseAsm) + Asm->OutStreamer->AddComment(" has no landing pad"); + Asm->emitCallSiteValue(0, CallSiteEncoding); + } else { + if (VerboseAsm) + Asm->OutStreamer->AddComment(Twine(" jumps to ") + + S.LPad->LandingPadLabel->getName()); + Asm->emitCallSiteOffset(S.LPad->LandingPadLabel, + LandingPadRange->FragmentBeginLabel, + CallSiteEncoding); + } - // Offset of the first associated action record, relative to the start of - // the action table. This value is biased by 1 (1 indicates the start of - // the action table), and 0 indicates that there are no actions. - if (VerboseAsm) { - if (S.Action == 0) - Asm->OutStreamer->AddComment(" On action: cleanup"); - else - Asm->OutStreamer->AddComment(" On action: " + - Twine((S.Action - 1) / 2 + 1)); + // Offset of the first associated action record, relative to the start + // of the action table. This value is biased by 1 (1 indicates the start + // of the action table), and 0 indicates that there are no actions. + if (VerboseAsm) { + if (S.Action == 0) + Asm->OutStreamer->AddComment(" On action: cleanup"); + else + Asm->OutStreamer->AddComment(" On action: " + + Twine((S.Action - 1) / 2 + 1)); + } + Asm->emitULEB128(S.Action); } - Asm->emitULEB128(S.Action); } + Asm->OutStreamer->emitLabel(CstEndLabel); } - Asm->OutStreamer->emitLabel(CstEndLabel); // Emit the Action Table. int Entry = 0; @@ -596,7 +728,7 @@ const std::vector &TypeInfos = MF->getTypeInfos(); const std::vector &FilterIds = MF->getFilterIds(); - bool VerboseAsm = Asm->OutStreamer->isVerboseAsm(); + const bool VerboseAsm = Asm->OutStreamer->isVerboseAsm(); int Entry = 0; // Emit the Catch TypeInfos. diff --git a/llvm/lib/CodeGen/AsmPrinter/WasmException.h b/llvm/lib/CodeGen/AsmPrinter/WasmException.h --- a/llvm/lib/CodeGen/AsmPrinter/WasmException.h +++ b/llvm/lib/CodeGen/AsmPrinter/WasmException.h @@ -32,6 +32,7 @@ // Compute the call site table for wasm EH. void computeCallSiteTable( SmallVectorImpl &CallSites, + SmallVectorImpl &CallSiteRanges, const SmallVectorImpl &LandingPads, const SmallVectorImpl &FirstActions) override; }; diff --git a/llvm/lib/CodeGen/AsmPrinter/WasmException.cpp b/llvm/lib/CodeGen/AsmPrinter/WasmException.cpp --- a/llvm/lib/CodeGen/AsmPrinter/WasmException.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/WasmException.cpp @@ -76,6 +76,7 @@ // information. void WasmException::computeCallSiteTable( SmallVectorImpl &CallSites, + SmallVectorImpl &CallSiteRanges, const SmallVectorImpl &LandingPads, const SmallVectorImpl &FirstActions) { MachineFunction &MF = *Asm->MF; diff --git a/llvm/lib/CodeGen/BasicBlockSections.cpp b/llvm/lib/CodeGen/BasicBlockSections.cpp --- a/llvm/lib/CodeGen/BasicBlockSections.cpp +++ b/llvm/lib/CodeGen/BasicBlockSections.cpp @@ -293,6 +293,26 @@ updateBranches(MF, PreLayoutFallThroughs); } +// If the exception section begins with a landing pad, that landing pad will +// assume a zero offset (relative to @LPStart) in the LSDA. However, a value of +// zero implies "no landing pad." This function inserts a NOP just before the EH +// pad label to ensure a nonzero offset. Returns true if padding is not needed. +static bool avoidZeroOffsetLandingPad(MachineFunction &MF) { + for (auto &MBB : MF) { + if (MBB.isBeginSection() && MBB.isEHPad()) { + MachineBasicBlock::iterator MI = MBB.begin(); + while (!MI->isEHLabel()) + ++MI; + MCInst Noop; + MF.getSubtarget().getInstrInfo()->getNoop(Noop); + BuildMI(MBB, MI, DebugLoc(), + MF.getSubtarget().getInstrInfo()->get(Noop.getOpcode())); + return false; + } + } + return true; +} + bool BasicBlockSections::runOnMachineFunction(MachineFunction &MF) { auto BBSectionsType = MF.getTarget().getBBSectionsType(); assert(BBSectionsType != BasicBlockSection::None && @@ -354,6 +374,7 @@ }; sortBasicBlocksAndUpdateBranches(MF, Comparator); + avoidZeroOffsetLandingPad(MF); return true; } diff --git a/llvm/lib/Target/ARM/ARMAsmPrinter.cpp b/llvm/lib/Target/ARM/ARMAsmPrinter.cpp --- a/llvm/lib/Target/ARM/ARMAsmPrinter.cpp +++ b/llvm/lib/Target/ARM/ARMAsmPrinter.cpp @@ -903,7 +903,7 @@ MCSymbol *MCSym; if (ACPV->isLSDA()) { - MCSym = getCurExceptionSym(); + MCSym = getMBBExceptionSym(MF->front()); } else if (ACPV->isBlockAddress()) { const BlockAddress *BA = cast(ACPV)->getBlockAddress(); diff --git a/llvm/test/CodeGen/X86/gcc_except_table_bb_sections.ll b/llvm/test/CodeGen/X86/gcc_except_table_bb_sections.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/X86/gcc_except_table_bb_sections.ll @@ -0,0 +1,166 @@ +; RUN: llc -basic-block-sections=all -mtriple x86_64-pc-linux-gnu < %s | FileCheck %s --check-prefixes=CHECK,CHECK-NON-PIC +; RUN: llc -basic-block-sections=all -mtriple x86_64-pc-linux-gnu -relocation-model=pic < %s | FileCheck %s --check-prefixes=CHECK,CHECK-PIC +@_ZTIi = external constant i8* + +define i32 @main() uwtable optsize ssp personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) { +; Verify that each basic block section gets its own LSDA exception symbol. +; +; CHECK-LABEL: main: +; CHECK-NEXT: .Lfunc_begin0: +; CHECK-NEXT: .cfi_startproc + +;; Verify personality function and LSDA encoding for NON-PIC mode. +; PersonalityEncoding = dwarf::DW_EH_PE_udata4 +; CHECK-NON-PIC-NEXT: .cfi_personality 3, __gxx_personality_v0 +; LSDAEncoding = dwarf::DW_EH_PE_udata4 +; CHECK-NON-PIC-NEXT: .cfi_lsda 3, .Lexception0 + +;; Verify personality function and LSDA encoding for PIC mode. +; PersonalityEncoding = DW_EH_PE_indirect | DW_EH_PE_pcrel | DW_EH_PE_sdata4 +; CHECK-PIC-NEXT: .cfi_personality 155, DW.ref.__gxx_personality_v0 +; LSDAEncoding = DW_EH_PE_pcrel | DW_EH_PE_sdata4 +; CHECK-PIC-NEXT: .cfi_lsda 27, .Lexception0 + +; CHECK-LABEL: .Ltmp0: +; CHECK-NEXT: callq _Z1fv +; CHECK-LABEL: .Ltmp1: + +; CHECK-NOT: .cfi_lsda + +; CHECK-LABEL: main.1: +; CHECK-NEXT: .cfi_startproc + +; CHECK-NON-PIC-NEXT: .cfi_personality 3, __gxx_personality_v0 +; CHECK-NON-PIC-NEXT: .cfi_lsda 3, .Lexception1 + +; CHECK-PIC-NEXT: .cfi_personality 155, DW.ref.__gxx_personality_v0 +; CHECK-PIC-NEXT: .cfi_lsda 27, .Lexception1 + +; CHECK-NOT: .cfi_lsda + +; CHECK-LABEL: main.2: +; CHECK-NEXT: .cfi_startproc + +; CHECK-NON-PIC-NEXT: .cfi_personality 3, __gxx_personality_v0 +; CHECK-NON-PIC-NEXT: .cfi_lsda 3, .Lexception2 + +; CHECK-PIC-NEXT: .cfi_personality 155, DW.ref.__gxx_personality_v0 +; CHECK-PIC-NEXT: .cfi_lsda 27, .Lexception2 + +; CHECK: nop +; CHECK-LABEL: .Ltmp2: +; CHECK-LABEL: .LBB_END0_2: + +; CHECK-NOT: .cfi_lsda + +entry: + invoke void @_Z1fv() optsize + to label %try.cont unwind label %lpad + +lpad: + %0 = landingpad { i8*, i32 } + cleanup + catch i8* bitcast (i8** @_ZTIi to i8*) + br label %eh.resume + +try.cont: + ret i32 0 + +eh.resume: + resume { i8*, i32 } %0 +} + +declare void @_Z1fv() optsize + +declare i32 @__gxx_personality_v0(...) +;; Verify that the exception table gets split across the three basic block sections. +; +; CHECK: .section .gcc_except_table +; CHECK-NEXT: .p2align 2 +; CHECK-NEXT: GCC_except_table0: +; CHECK-NEXT: .Lexception0: + +;; Verify @LPStart encoding for NON-PIC mode. +; CHECK-NON-PIC-NEXT: .byte 0 # @LPStart Encoding = absptr +; CHECK-NON-PIC-NEXT: .quad main.2 + +;; Verify @LPStart encoding for PIC mode. +; CHECK-PIC-NEXT: .byte 16 # @LPStart Encoding = pcrel +; CHECK-PIC-NEXT: [[DOT:\.Ltmp[0-9]+]]: +; CHECK-PIC-NEXT: .quad main.2-[[DOT]] + +;; Verify @TType encoding for NON-PIC mode. +; CHECK-NON-PIC-NEXT: .byte 3 # @TType Encoding = udata4 + +;; Verify @TType encoding for PIC mode. +; CHECK-PIC-NEXT: .byte 156 # @TType Encoding = indirect pcrel sdata8 + +; CHECK-NEXT: .uleb128 .Lttbase0-.Lttbaseref0 +; CHECK-NEXT: .Lttbaseref0: +; CHECK-NEXT: .byte 1 # Call site Encoding = uleb128 +; CHECK-NEXT: .uleb128 .Laction_table_base0-.Lcst_begin0 +; CHECK-NEXT: .Lcst_begin0: +; CHECK-NEXT: .uleb128 .Ltmp0-.Lfunc_begin0 # >> Call Site 1 << +; CHECK-NEXT: .uleb128 .Ltmp1-.Ltmp0 # Call between .Ltmp0 and .Ltmp1 +; CHECK-NEXT: .uleb128 .Ltmp2-main.2 # jumps to .Ltmp2 +; CHECK-NEXT: .byte 3 # On action: 2 +; CHECK-NEXT: .p2align 2 +; CHECK-NEXT: .Lexception1: + +; CHECK-NON-PIC-NEXT: .byte 0 # @LPStart Encoding = absptr +; CHECK-NON-PIC-NEXT: .quad main.2 + +; CHECK-PIC-NEXT: .byte 16 # @LPStart Encoding = pcrel +; CHECK-PIC-NEXT: [[DOT:\.Ltmp[0-9]+]]: +; CHECK-PIC-NEXT: .quad main.2-[[DOT]] + +; CHECK-NON-PIC-NEXT: .byte 3 # @TType Encoding = udata4 + +; CHECK-PIC-NEXT: .byte 156 # @TType Encoding = indirect pcrel sdata8 + +; CHECK-NEXT: .uleb128 .Lttbase0-.Lttbaseref1 +; CHECK-NEXT: .Lttbaseref1: +; CHECK-NEXT: .byte 1 # Call site Encoding = uleb128 +; CHECK-NEXT: .uleb128 .Laction_table_base0-.Lcst_begin1 +; CHECK-NEXT: .Lcst_begin1: +; CHECK-NEXT: .p2align 2 +; CHECK-NEXT: .Lexception2: + +; CHECK-NON-PIC-NEXT: .byte 0 # @LPStart Encoding = absptr +; CHECK-NON-PIC-NEXT: .quad main.2 + +; CHECK-PIC-NEXT: .byte 16 # @LPStart Encoding = pcrel +; CHECK-PIC-NEXT: [[DOT:\.Ltmp[0-9]+]]: +; CHECK-PIC-NEXT: .quad main.2-[[DOT]] + +; CHECK-NON-PIC-NEXT: .byte 3 # @TType Encoding = udata4 + +; CHECK-PIC-NEXT: .byte 156 # @TType Encoding = indirect pcrel sdata8 + +; CHECK-NEXT: .uleb128 .Lttbase0-.Lttbaseref2 +; CHECK-NEXT: .Lttbaseref2: +; CHECK-NEXT: .byte 1 # Call site Encoding = uleb128 +; CHECK-NEXT: .uleb128 .Laction_table_base0-.Lcst_begin2 +; CHECK-NEXT: .Lcst_begin2: +; CHECK-NEXT: .uleb128 main.2-main.2 # >> Call Site 2 << +; CHECK-NEXT: .uleb128 .LBB_END0_2-main.2 # Call between main.2 and .LBB_END0_2 +; CHECK-NEXT: .byte 0 # has no landing pad +; CHECK-NEXT: .byte 0 # On action: cleanup +; CHECK-NEXT: .Laction_table_base0: +; CHECK-NEXT: .byte 0 # >> Action Record 1 << +; CHECK-NEXT: # Cleanup +; CHECK-NEXT: .byte 0 # No further actions +; CHECK-NEXT: .byte 1 # >> Action Record 2 << +; CHECK-NEXT: # Catch TypeInfo 1 +; CHECK-NEXT: .byte 125 # Continue to action 1 +; CHECK-NEXT: .p2align 2 +; CHECK-NEXT: # >> Catch TypeInfos << + +; CHECK-NON-PIC-NEXT: .long _ZTIi # TypeInfo 1 + +; CHECK-PIC-NEXT: [[DOT:\.Ltmp[0-9]+]]: +; CHECK-PIC-NEXT: .quad .L_ZTIi.DW.stub-[[DOT]] + +; CHECK-NEXT: .Lttbase0: +; CHECK-NEXT: .p2align 2 +; CHECK-NEXT: # -- End function diff --git a/llvm/test/CodeGen/X86/gcc_except_table_bb_sections_ehpad_groups_with_cold.ll b/llvm/test/CodeGen/X86/gcc_except_table_bb_sections_ehpad_groups_with_cold.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/X86/gcc_except_table_bb_sections_ehpad_groups_with_cold.ll @@ -0,0 +1,96 @@ +; Check that when all exception handling blocks are cold, they get grouped with the cold bbs. +; RUN: echo '!main' > %t +; RUN: echo '!!0' >> %t +; RUN: llc -function-sections -basic-block-sections=%t -mtriple x86_64-pc-linux-gnu < %s | FileCheck %s +@_ZTIi = external constant i8* + +define i32 @main() uwtable optsize ssp personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) { +; Verify that each basic block section gets its own LSDA exception symbol. +; +; CHECK-LABEL: main: +; CHECK-NEXT: .Lfunc_begin0: +; CHECK-NEXT: .cfi_startproc +; PersonalityEncoding = dwarf::DW_EH_PE_udata4 +; CHECK-NEXT: .cfi_personality 3, __gxx_personality_v0 +; LSDAEncoding = dwarf::DW_EH_PE_udata4 +; CHECK-NEXT: .cfi_lsda 3, .Lexception0 +; CHECK-LABEL: .Ltmp0: +; CHECK-LABEL: .Ltmp1: + +; CHECK-NOT: .cfi_lsda + +; CHECK-LABEL: main.cold: +; CHECK-NEXT: .cfi_startproc +; CHECK-NEXT: .cfi_personality 3, __gxx_personality_v0 +; CHECK-NEXT: .cfi_lsda 3, .Lexception1 +; CHECK-LABEL: .Ltmp2: +; CHECK-LABEL: .LBB_END0_2: + +; CHECK-NOT: .cfi_lsda + +entry: + invoke void @_Z1fv() optsize + to label %try.cont unwind label %lpad + +lpad: + %0 = landingpad { i8*, i32 } + cleanup + catch i8* bitcast (i8** @_ZTIi to i8*) + br label %eh.resume + +try.cont: + ret i32 0 + +eh.resume: + resume { i8*, i32 } %0 +} + +declare void @_Z1fv() optsize + +declare i32 @__gxx_personality_v0(...) + +; Verify that the exception table gets split across the two basic block sections. +; +; CHECK: .section .gcc_except_table +; CHECK-NEXT: .p2align 2 +; CHECK-NEXT: GCC_except_table0: +; CHECK-NEXT: .Lexception0: +; CHECK-NEXT: .byte 0 # @LPStart Encoding = absptr +; CHECK-NEXT: .quad main.cold +; CHECK-NEXT: .byte 3 # @TType Encoding = udata4 +; CHECK-NEXT: .uleb128 .Lttbase0-.Lttbaseref0 +; CHECK-NEXT: .Lttbaseref0: +; CHECK-NEXT: .byte 1 # Call site Encoding = uleb128 +; CHECK-NEXT: .uleb128 .Laction_table_base0-.Lcst_begin0 +; CHECK-NEXT: .Lcst_begin0: +; CHECK-NEXT: .uleb128 .Ltmp0-.Lfunc_begin0 # >> Call Site 1 << +; CHECK-NEXT: .uleb128 .Ltmp1-.Ltmp0 # Call between .Ltmp0 and .Ltmp1 +; CHECK-NEXT: .uleb128 .Ltmp2-main.cold # jumps to .Ltmp2 +; CHECK-NEXT: .byte 3 # On action: 2 +; CHECK-NEXT: .p2align 2 +; CHECK-NEXT: .Lexception1: +; CHECK-NEXT: .byte 0 # @LPStart Encoding = absptr +; CHECK-NEXT: .quad main.cold +; CHECK-NEXT: .byte 3 # @TType Encoding = udata4 +; CHECK-NEXT: .uleb128 .Lttbase0-.Lttbaseref1 +; CHECK-NEXT: .Lttbaseref1: +; CHECK-NEXT: .byte 1 # Call site Encoding = uleb128 +; CHECK-NEXT: .uleb128 .Laction_table_base0-.Lcst_begin1 +; CHECK-NEXT: .Lcst_begin1: +; CHECK-NEXT: .uleb128 main.cold-main.cold # >> Call Site 2 << +; CHECK-NEXT: .uleb128 .LBB_END0_2-main.cold # Call between main.cold and .LBB_END0_2 +; CHECK-NEXT: .byte 0 # has no landing pad +; CHECK-NEXT: .byte 0 # On action: cleanup +; CHECK-NEXT: .Laction_table_base0: +; CHECK-NEXT: .byte 0 # >> Action Record 1 << +; CHECK-NEXT: # Cleanup +; CHECK-NEXT: .byte 0 # No further actions +; CHECK-NEXT: .byte 1 # >> Action Record 2 << +; CHECK-NEXT: # Catch TypeInfo 1 +; CHECK-NEXT: .byte 125 # Continue to action 1 +; CHECK-NEXT: .p2align 2 +; CHECK-NEXT: # >> Catch TypeInfos << +; CHECK-NEXT: .long _ZTIi # TypeInfo 1 +; CHECK-NEXT: .Lttbase0: +; CHECK-NEXT: .p2align 2 +; CHECK-NEXT: # -- End function