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 @@ -142,6 +142,7 @@ private: MCSymbol *CurrentFnEnd = nullptr; MCSymbol *CurExceptionSym = nullptr; + DenseMap ExceptionSymbols; // 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. @@ -232,6 +233,22 @@ MCSymbol *getFunctionEnd() const { return CurrentFnEnd; } MCSymbol *getCurExceptionSym(); + // Set the exception symbol associated with the function fragment which begins + // with a given basic block. + void setExceptionSym(const MachineBasicBlock *MBB, MCSymbol *Sym) { + ExceptionSymbols.try_emplace(MBB, Sym); + } + + // Get the exception symbol associated with the function fragment which begins + // with a given basic block. Falls back to getCurExceptionSym() if no + // association is found. + MCSymbol *getExceptionSym(const MachineBasicBlock *MBB) { + auto R = ExceptionSymbols.find(MBB); + if (R == ExceptionSymbols.end()) + return getCurExceptionSym(); + return R->second; + } + /// Return information about object file lowering. const TargetLoweringObjectFile &getObjFileLowering() const; diff --git a/llvm/include/llvm/CodeGen/BasicBlockSectionUtils.h b/llvm/include/llvm/CodeGen/BasicBlockSectionUtils.h --- a/llvm/include/llvm/CodeGen/BasicBlockSectionUtils.h +++ b/llvm/include/llvm/CodeGen/BasicBlockSectionUtils.h @@ -22,6 +22,8 @@ void sortBasicBlocksAndUpdateBranches(MachineFunction &MF, MachineBasicBlockComparator MBBCmp); +bool avoidZeroOffsetLandingPad(MachineFunction &MF); + } // end namespace llvm #endif // LLVM_CODEGEN_BASICBLOCKSECTIONUTILS_H 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 @@ -1205,6 +1205,9 @@ MBBSectionRanges[MBB.getSectionIDNum()] = MBBSectionRange{CurrentSectionBeginSym, MBB.getEndSymbol()}; } + // If this is the end of the section, nullify the exception symbol to + // ensure a new symbol is created for the next basicblock section. + CurExceptionSym = nullptr; } emitBasicBlockEnd(MBB); } @@ -1797,6 +1800,7 @@ CurrentSectionBeginSym = nullptr; MBBSectionRanges.clear(); CurExceptionSym = nullptr; + ExceptionSymbols.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 @@ -162,6 +162,9 @@ // Provide LSDA information. if (shouldEmitLSDA) Asm->OutStreamer->emitCFILsda(ESP(Asm), TLOF.getLSDAEncoding()); + + // Set the exception symbol associated with this basic block. + Asm->setExceptionSym(MBB, ESP(Asm)); } /// 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 fragmnt. + 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 @@ -220,10 +220,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. +/// +/// - With -function-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); @@ -239,8 +254,25 @@ bool IsSJLJ = Asm->MAI->getExceptionHandlingType() == ExceptionHandling::SjLj; + // All landing pads should reside in one section, and hence in one call-site + // range. // 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->getExceptionSym(&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()) @@ -313,14 +345,24 @@ 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) { - CallSiteEntry Site = { LastLabel, nullptr, nullptr, 0 }; - CallSites.push_back(Site); + // 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, + MBB.isEndSection() + ? CallSiteRanges.back().FragmentEndLabel + : nullptr, + nullptr, 0}; + CallSites.push_back(Site); + SawPotentiallyThrowing = false; + } + CallSiteRanges.back().CallSiteEndIdx = CallSites.size(); + } } } @@ -371,9 +413,10 @@ SmallVector FirstActions; computeActionsTable(LandingPads, Actions, FirstActions); - // Compute the call-site table. + // Compute the call-site table and call-site ranges. 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; @@ -433,35 +476,47 @@ 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("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(); - // 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); + // 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) { + // 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); + } + + // The Action table preciesly 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->getCurExceptionSym()); + + // 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) { @@ -486,6 +541,7 @@ } Asm->emitULEB128(S.Action); } + Asm->OutStreamer->emitLabel(CstEndLabel); } else { // Itanium LSDA exception handling @@ -507,57 +563,123 @@ // 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!"); + + // Find the call-site range which includes the landing pads. + 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(); + + for (size_t CallSiteIdx = CSRange.CallSiteBeginIdx; + CallSiteIdx != CSRange.CallSiteEndIdx; ++CallSiteIdx) { + const CallSiteEntry &S = CallSites[CallSiteIdx]; + + MCSymbol *EHFuncBeginSym = CSRange.FragmentBeginLabel; + MCSymbol *EHFuncEndSym = CSRange.FragmentEndLabel; + + MCSymbol *BeginLabel = S.BeginLabel; + if (!BeginLabel) + BeginLabel = EHFuncBeginSym; + MCSymbol *EndLabel = S.EndLabel; + if (!EndLabel) + EndLabel = EHFuncEndSym; - MCSymbol *EHFuncBeginSym = Asm->getFunctionBegin(); - - MCSymbol *BeginLabel = S.BeginLabel; - if (!BeginLabel) - BeginLabel = EHFuncBeginSym; - MCSymbol *EndLabel = S.EndLabel; - if (!EndLabel) - EndLabel = Asm->getFunctionEnd(); - - // Offset of the call site relative to the start of the procedure. - if (VerboseAsm) - Asm->OutStreamer->AddComment(">> Call Site " + Twine(++Entry) + " <<"); - Asm->emitCallSiteOffset(BeginLabel, EHFuncBeginSym, CallSiteEncoding); - if (VerboseAsm) - 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 procedure. - if (!S.LPad) { + // 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; 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 @@ -292,6 +292,25 @@ 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. +bool llvm::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 && @@ -355,6 +374,7 @@ }; sortBasicBlocksAndUpdateBranches(MF, Comparator); + avoidZeroOffsetLandingPad(MF); return true; } 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,129 @@ +; 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-LABEL: .Lfunc_begin0: +; CHECK-NON-PIC: .cfi_personality 3, __gxx_personality_v0 +; CHECK-PIC: .cfi_personality 155, DW.ref.__gxx_personality_v0 +; CHECK-NON-PIC: .cfi_lsda 3, .Lexception0 +; CHECK-PIC: .cfi_lsda 27, .Lexception0 +; CHECK-LABEL: .Ltmp0: +; CHECK-NEXT: callq _Z1fv +; CHECK-LABEL: .Ltmp1: + +; CHECK-NOT: .cfi_lsda + +; CHECK-LABEL: main.1: +; CHECK: .cfi_startproc +; CHECK-NON-PIC: .cfi_personality 3, __gxx_personality_v0 +; CHECK-PIC: .cfi_personality 155, DW.ref.__gxx_personality_v0 +; CHECK-NON-PIC: .cfi_lsda 3, .Lexception1 +; CHECK-PIC: .cfi_lsda 27, .Lexception1 + + +; CHECK-NOT: .cfi_lsda + +; CHECK-LABEL: main.2: +; CHECK-NON-PIC: .cfi_personality 3, __gxx_personality_v0 +; CHECK-PIC: .cfi_personality 155, DW.ref.__gxx_personality_v0 +; CHECK-NON-PIC: .cfi_lsda 3, .Lexception2 +; CHECK-PIC: .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: +; 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-.Lttbaseref0 +; CHECK-NEXT: .Lttbaseref0: +; CHECK-NEXT: .byte 1 # Call site Encoding = uleb128 +; CHECK-NEXT: .uleb128 .Lcst_end0-.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 .Lcst_end0-.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 .Lcst_end0-.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: .Lcst_end0: +; 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,92 @@ +; 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-LABEL: .Lfunc_begin0: +; CHECK: .cfi_personality 3, __gxx_personality_v0 +; CHECK: .cfi_lsda 3, .Lexception0 +; CHECK-LABEL: .Ltmp0: +; CHECK-LABEL: .Ltmp1: + +; CHECK-NOT: .cfi_lsda + +; CHECK-LABEL: main.cold: +; CHECK: .cfi_personality 3, __gxx_personality_v0 +; CHECK: .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 .Lcst_end0-.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 .Lcst_end0-.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: .Lcst_end0: +; 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