diff --git a/llvm/include/llvm/CodeGen/MachineFunction.h b/llvm/include/llvm/CodeGen/MachineFunction.h index 09f9ff60f955037..f802fe5779900d2 100644 --- a/llvm/include/llvm/CodeGen/MachineFunction.h +++ b/llvm/include/llvm/CodeGen/MachineFunction.h @@ -1158,6 +1158,10 @@ class LLVM_EXTERNAL_VISIBILITY MachineFunction { /// Find or create an LandingPadInfo for the specified MachineBasicBlock. LandingPadInfo &getOrCreateLandingPadInfo(MachineBasicBlock *LandingPad); + /// Remap landing pad labels and remove any deleted landing pads. + void tidyLandingPads(DenseMap *LPMap = nullptr, + bool TidyIfNoBeginLabels = true); + /// Return a reference to the landing pad info for the current function. const std::vector &getLandingPads() const { return LandingPads; @@ -1173,11 +1177,22 @@ class LLVM_EXTERNAL_VISIBILITY MachineFunction { /// entry. MCSymbol *addLandingPad(MachineBasicBlock *LandingPad); + /// Provide the catch typeinfo for a landing pad. + void addCatchTypeInfo(MachineBasicBlock *LandingPad, + ArrayRef TyInfo); + + /// Provide the filter typeinfo for a landing pad. + void addFilterTypeInfo(MachineBasicBlock *LandingPad, + ArrayRef TyInfo); + + /// Add a cleanup action for a landing pad. + void addCleanup(MachineBasicBlock *LandingPad); + /// Return the type id for the specified typeinfo. This is function wide. unsigned getTypeIDFor(const GlobalValue *TI); /// Return the id of the filter encoded by TyIds. This is function wide. - int getFilterIDFor(ArrayRef TyIds); + int getFilterIDFor(std::vector &TyIds); /// Map the landing pad's EH symbol to the call site indexes. void setCallSiteLandingPad(MCSymbol *Sym, ArrayRef Sites); diff --git a/llvm/lib/CodeGen/AsmPrinter/AIXException.cpp b/llvm/lib/CodeGen/AsmPrinter/AIXException.cpp index 82b5ccdc70ea1d1..6943c9584594581 100644 --- a/llvm/lib/CodeGen/AsmPrinter/AIXException.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/AIXException.cpp @@ -21,7 +21,16 @@ namespace llvm { -AIXException::AIXException(AsmPrinter *A) : EHStreamer(A) {} +AIXException::AIXException(AsmPrinter *A) : DwarfCFIExceptionBase(A) {} + +// This overrides 'DwarfCFIExceptionBase::markFunctionEnd', to avoid the call to +// tidyLandingPads. This is necessary, because the +// 'PPCAIXAsmPrinter::emitFunctionBodyEnd' function already checked whether we +// need ehinfo, and emitted a traceback table with the bits set to indicate that +// we will be emitting it, if so. Thus, if we remove it now -- so late in the +// process -- we'll end up having emitted a reference to __ehinfo.N symbol, but +// not emitting a definition for said symbol. +void AIXException::markFunctionEnd() {} void AIXException::emitExceptionInfoTable(const MCSymbol *LSDA, const MCSymbol *PerSym) { diff --git a/llvm/lib/CodeGen/AsmPrinter/ARMException.cpp b/llvm/lib/CodeGen/AsmPrinter/ARMException.cpp index de6ebcf0c3419f7..aa56442881d46b7 100644 --- a/llvm/lib/CodeGen/AsmPrinter/ARMException.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/ARMException.cpp @@ -19,7 +19,7 @@ #include "llvm/MC/MCStreamer.h" using namespace llvm; -ARMException::ARMException(AsmPrinter *A) : EHStreamer(A) {} +ARMException::ARMException(AsmPrinter *A) : DwarfCFIExceptionBase(A) {} ARMException::~ARMException() = default; @@ -51,6 +51,7 @@ void ARMException::beginFunction(const MachineFunction *MF) { void ARMException::markFunctionEnd() { if (shouldEmitCFI) Asm->OutStreamer->emitCFIEndProc(); + DwarfCFIExceptionBase::markFunctionEnd(); } /// endFunction - Gather and emit post-function exception information. diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfCFIException.cpp b/llvm/lib/CodeGen/AsmPrinter/DwarfCFIException.cpp index 10c844ddb14a146..81ed6798b8adef3 100644 --- a/llvm/lib/CodeGen/AsmPrinter/DwarfCFIException.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfCFIException.cpp @@ -23,7 +23,18 @@ #include "llvm/Target/TargetOptions.h" using namespace llvm; -DwarfCFIException::DwarfCFIException(AsmPrinter *A) : EHStreamer(A) {} +DwarfCFIExceptionBase::DwarfCFIExceptionBase(AsmPrinter *A) : EHStreamer(A) {} + +void DwarfCFIExceptionBase::markFunctionEnd() { + // Map all labels and get rid of any dead landing pads. + if (!Asm->MF->getLandingPads().empty()) { + MachineFunction *NonConstMF = const_cast(Asm->MF); + NonConstMF->tidyLandingPads(); + } +} + +DwarfCFIException::DwarfCFIException(AsmPrinter *A) + : DwarfCFIExceptionBase(A) {} DwarfCFIException::~DwarfCFIException() = default; diff --git a/llvm/lib/CodeGen/AsmPrinter/DwarfException.h b/llvm/lib/CodeGen/AsmPrinter/DwarfException.h index c2c11c7bc14d1c5..9b09edc5e75f6b2 100644 --- a/llvm/lib/CodeGen/AsmPrinter/DwarfException.h +++ b/llvm/lib/CodeGen/AsmPrinter/DwarfException.h @@ -21,7 +21,19 @@ namespace llvm { class MachineFunction; class ARMTargetStreamer; -class LLVM_LIBRARY_VISIBILITY DwarfCFIException : public EHStreamer { +class LLVM_LIBRARY_VISIBILITY DwarfCFIExceptionBase : public EHStreamer { +protected: + DwarfCFIExceptionBase(AsmPrinter *A); + + /// Per-function flag to indicate if frame CFI info should be emitted. + bool shouldEmitCFI = false; + /// Per-module flag to indicate if .cfi_section has beeen emitted. + bool hasEmittedCFISections = false; + + void markFunctionEnd() override; +}; + +class LLVM_LIBRARY_VISIBILITY DwarfCFIException : public DwarfCFIExceptionBase { /// Per-function flag to indicate if .cfi_personality should be emitted. bool shouldEmitPersonality = false; @@ -63,13 +75,7 @@ class LLVM_LIBRARY_VISIBILITY DwarfCFIException : public EHStreamer { void endBasicBlockSection(const MachineBasicBlock &MBB) override; }; -class LLVM_LIBRARY_VISIBILITY ARMException : public EHStreamer { - /// Per-function flag to indicate if frame CFI info should be emitted. - bool shouldEmitCFI = false; - - /// Per-module flag to indicate if .cfi_section has beeen emitted. - bool hasEmittedCFISections = false; - +class LLVM_LIBRARY_VISIBILITY ARMException : public DwarfCFIExceptionBase { void emitTypeInfos(unsigned TTypeEncoding, MCSymbol *TTBaseLabel) override; ARMTargetStreamer &getTargetStreamer(); @@ -93,7 +99,7 @@ class LLVM_LIBRARY_VISIBILITY ARMException : public EHStreamer { void markFunctionEnd() override; }; -class LLVM_LIBRARY_VISIBILITY AIXException : public EHStreamer { +class LLVM_LIBRARY_VISIBILITY AIXException : public DwarfCFIExceptionBase { /// This is AIX's compat unwind section, which unwinder would use /// to find the location of LSDA area and personality rountine. void emitExceptionInfoTable(const MCSymbol *LSDA, const MCSymbol *PerSym); @@ -101,6 +107,8 @@ class LLVM_LIBRARY_VISIBILITY AIXException : public EHStreamer { public: AIXException(AsmPrinter *A); + void markFunctionEnd() override; + void endModule() override {} void beginFunction(const MachineFunction *MF) override {} void endFunction(const MachineFunction *MF) override; diff --git a/llvm/lib/CodeGen/AsmPrinter/EHStreamer.cpp b/llvm/lib/CodeGen/AsmPrinter/EHStreamer.cpp index eef6b1d93f36e89..6f85fb1b07ff992 100644 --- a/llvm/lib/CodeGen/AsmPrinter/EHStreamer.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/EHStreamer.cpp @@ -195,12 +195,6 @@ void EHStreamer::computePadMap( const LandingPadInfo *LandingPad = LandingPads[i]; for (unsigned j = 0, E = LandingPad->BeginLabels.size(); j != E; ++j) { MCSymbol *BeginLabel = LandingPad->BeginLabels[j]; - MCSymbol *EndLabel = LandingPad->BeginLabels[j]; - // If we have deleted the code for a given invoke after registering it in - // the LandingPad label list, the associated symbols will not have been - // emitted. In that case, ignore this callsite entry. - if (!BeginLabel->isDefined() || !EndLabel->isDefined()) - continue; assert(!PadMap.count(BeginLabel) && "Duplicate landing pad labels!"); PadRange P = { i, j }; PadMap[BeginLabel] = P; @@ -389,14 +383,8 @@ MCSymbol *EHStreamer::emitExceptionTable() { SmallVector LandingPads; LandingPads.reserve(PadInfos.size()); - for (const LandingPadInfo &LPI : PadInfos) { - // If a landing-pad has an associated label, but the label wasn't ever - // emitted, then skip it. (This can occur if the landingpad's MBB was - // deleted). - if (LPI.LandingPadLabel && !LPI.LandingPadLabel->isDefined()) - continue; + for (const LandingPadInfo &LPI : PadInfos) LandingPads.push_back(&LPI); - } // Order landing pads lexicographically by type id. llvm::sort(LandingPads, [](const LandingPadInfo *L, const LandingPadInfo *R) { diff --git a/llvm/lib/CodeGen/AsmPrinter/WasmException.cpp b/llvm/lib/CodeGen/AsmPrinter/WasmException.cpp index bf65e525dde1456..a514ff161ceea37 100644 --- a/llvm/lib/CodeGen/AsmPrinter/WasmException.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/WasmException.cpp @@ -42,6 +42,16 @@ void WasmException::endModule() { } } +void WasmException::markFunctionEnd() { + // Get rid of any dead landing pads. + if (!Asm->MF->getLandingPads().empty()) { + auto *NonConstMF = const_cast(Asm->MF); + // Wasm does not set BeginLabel and EndLabel information for landing pads, + // so we should set the second argument false. + NonConstMF->tidyLandingPads(nullptr, /* TidyIfNoBeginLabels */ false); + } +} + void WasmException::endFunction(const MachineFunction *MF) { bool ShouldEmitExceptionTable = false; for (const LandingPadInfo &Info : MF->getLandingPads()) { diff --git a/llvm/lib/CodeGen/AsmPrinter/WasmException.h b/llvm/lib/CodeGen/AsmPrinter/WasmException.h index 86cc37dfde079ec..419b569d123ca0e 100644 --- a/llvm/lib/CodeGen/AsmPrinter/WasmException.h +++ b/llvm/lib/CodeGen/AsmPrinter/WasmException.h @@ -28,6 +28,7 @@ class LLVM_LIBRARY_VISIBILITY WasmException : public EHStreamer { void endModule() override; void beginFunction(const MachineFunction *MF) override {} + void markFunctionEnd() override; void endFunction(const MachineFunction *MF) override; protected: diff --git a/llvm/lib/CodeGen/AsmPrinter/WinException.cpp b/llvm/lib/CodeGen/AsmPrinter/WinException.cpp index 6d6432b61f2d7dd..97e51949808aafd 100644 --- a/llvm/lib/CodeGen/AsmPrinter/WinException.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/WinException.cpp @@ -130,6 +130,14 @@ void WinException::endFunction(const MachineFunction *MF) { if (F.hasPersonalityFn()) Per = classifyEHPersonality(F.getPersonalityFn()->stripPointerCasts()); + // Get rid of any dead landing pads if we're not using funclets. In funclet + // schemes, the landing pad is not actually reachable. It only exists so + // that we can emit the right table data. + if (!isFuncletEHPersonality(Per)) { + MachineFunction *NonConstMF = const_cast(MF); + NonConstMF->tidyLandingPads(); + } + endFuncletImpl(); // endFunclet will emit the necessary .xdata tables for table-based SEH. diff --git a/llvm/lib/CodeGen/MachineFunction.cpp b/llvm/lib/CodeGen/MachineFunction.cpp index 88939e96e07f558..e872df9d4d57886 100644 --- a/llvm/lib/CodeGen/MachineFunction.cpp +++ b/llvm/lib/CodeGen/MachineFunction.cpp @@ -780,31 +780,32 @@ MCSymbol *MachineFunction::addLandingPad(MachineBasicBlock *LandingPad) { if (LPI->isCleanup() && LPI->getNumClauses() != 0) LP.TypeIds.push_back(0); + if (LPI->isCleanup()) + addCleanup(LandingPad); + // FIXME: New EH - Add the clauses in reverse order. This isn't 100% // correct, but we need to do it this way because of how the DWARF EH // emitter processes the clauses. for (unsigned I = LPI->getNumClauses(); I != 0; --I) { Value *Val = LPI->getClause(I - 1); if (LPI->isCatch(I - 1)) { - LP.TypeIds.push_back( - getTypeIDFor(dyn_cast(Val->stripPointerCasts()))); + addCatchTypeInfo(LandingPad, + dyn_cast(Val->stripPointerCasts())); } else { // Add filters in a list. auto *CVal = cast(Val); - SmallVector FilterList; + SmallVector FilterList; for (const Use &U : CVal->operands()) - FilterList.push_back( - getTypeIDFor(cast(U->stripPointerCasts()))); + FilterList.push_back(cast(U->stripPointerCasts())); - LP.TypeIds.push_back(getFilterIDFor(FilterList)); + addFilterTypeInfo(LandingPad, FilterList); } } } else if (const auto *CPI = dyn_cast(FirstI)) { for (unsigned I = CPI->arg_size(); I != 0; --I) { - auto *TypeInfo = - dyn_cast(CPI->getArgOperand(I - 1)->stripPointerCasts()); - LP.TypeIds.push_back(getTypeIDFor(TypeInfo)); + Value *TypeInfo = CPI->getArgOperand(I - 1)->stripPointerCasts(); + addCatchTypeInfo(LandingPad, dyn_cast(TypeInfo)); } } else { @@ -814,6 +815,73 @@ MCSymbol *MachineFunction::addLandingPad(MachineBasicBlock *LandingPad) { return LandingPadLabel; } +void MachineFunction::addCatchTypeInfo(MachineBasicBlock *LandingPad, + ArrayRef TyInfo) { + LandingPadInfo &LP = getOrCreateLandingPadInfo(LandingPad); + for (const GlobalValue *GV : llvm::reverse(TyInfo)) + LP.TypeIds.push_back(getTypeIDFor(GV)); +} + +void MachineFunction::addFilterTypeInfo(MachineBasicBlock *LandingPad, + ArrayRef TyInfo) { + LandingPadInfo &LP = getOrCreateLandingPadInfo(LandingPad); + std::vector IdsInFilter(TyInfo.size()); + for (unsigned I = 0, E = TyInfo.size(); I != E; ++I) + IdsInFilter[I] = getTypeIDFor(TyInfo[I]); + LP.TypeIds.push_back(getFilterIDFor(IdsInFilter)); +} + +void MachineFunction::tidyLandingPads(DenseMap *LPMap, + bool TidyIfNoBeginLabels) { + for (unsigned i = 0; i != LandingPads.size(); ) { + LandingPadInfo &LandingPad = LandingPads[i]; + if (LandingPad.LandingPadLabel && + !LandingPad.LandingPadLabel->isDefined() && + (!LPMap || (*LPMap)[LandingPad.LandingPadLabel] == 0)) + LandingPad.LandingPadLabel = nullptr; + + // Special case: we *should* emit LPs with null LP MBB. This indicates + // "nounwind" case. + if (!LandingPad.LandingPadLabel && LandingPad.LandingPadBlock) { + LandingPads.erase(LandingPads.begin() + i); + continue; + } + + if (TidyIfNoBeginLabels) { + for (unsigned j = 0, e = LandingPads[i].BeginLabels.size(); j != e; ++j) { + MCSymbol *BeginLabel = LandingPad.BeginLabels[j]; + MCSymbol *EndLabel = LandingPad.EndLabels[j]; + if ((BeginLabel->isDefined() || (LPMap && (*LPMap)[BeginLabel] != 0)) && + (EndLabel->isDefined() || (LPMap && (*LPMap)[EndLabel] != 0))) + continue; + + LandingPad.BeginLabels.erase(LandingPad.BeginLabels.begin() + j); + LandingPad.EndLabels.erase(LandingPad.EndLabels.begin() + j); + --j; + --e; + } + + // Remove landing pads with no try-ranges. + if (LandingPads[i].BeginLabels.empty()) { + 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; + } +} + +void MachineFunction::addCleanup(MachineBasicBlock *LandingPad) { + LandingPadInfo &LP = getOrCreateLandingPadInfo(LandingPad); + LP.TypeIds.push_back(0); +} + void MachineFunction::setCallSiteLandingPad(MCSymbol *Sym, ArrayRef Sites) { LPadToCallSiteMap[Sym].append(Sites.begin(), Sites.end()); @@ -827,7 +895,7 @@ unsigned MachineFunction::getTypeIDFor(const GlobalValue *TI) { return TypeInfos.size(); } -int MachineFunction::getFilterIDFor(ArrayRef TyIds) { +int MachineFunction::getFilterIDFor(std::vector &TyIds) { // If the new filter coincides with the tail of an existing filter, then // re-use the existing filter. Folding filters more than this requires // re-ordering filters and/or their elements - probably not worth it. diff --git a/llvm/test/CodeGen/X86/gcc_except_table_bb_sections.ll b/llvm/test/CodeGen/X86/gcc_except_table_bb_sections.ll index d14bb8e03443d6d..accef082fdadc98 100644 --- a/llvm/test/CodeGen/X86/gcc_except_table_bb_sections.ll +++ b/llvm/test/CodeGen/X86/gcc_except_table_bb_sections.ll @@ -148,7 +148,7 @@ declare i32 @__gxx_personality_v0(...) ; CHECK-NEXT: .uleb128 .Ltmp0-.Lfunc_begin0 # >> Call Site 1 << ; CHECK-NEXT: .uleb128 .Ltmp1-.Ltmp0 # Call between .Ltmp0 and .Ltmp1 ; CHECK-NEXT: .uleb128 .Ltmp2-main.__part.2 # jumps to .Ltmp2 -; CHECK-NEXT: .byte 3 # On action: 2 +; CHECK-NEXT: .byte 5 # On action: 3 ; CHECK-NEXT: .p2align 2 ; CHECK-NEXT: .Lexception1: @@ -207,9 +207,12 @@ declare i32 @__gxx_personality_v0(...) ; 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: .byte 0 # >> Action Record 2 << +; CHECK-NEXT: # Cleanup +; CHECK-NEXT: .byte 125 # Continue to action 1 +; CHECK-NEXT: .byte 1 # >> Action Record 3 << +; CHECK-NEXT: # Catch TypeInfo 1 +; CHECK-NEXT: .byte 125 # Continue to action 2 ; CHECK-NEXT: .p2align 2 ; CHECK-NEXT: # >> Catch TypeInfos << 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 index 82dafecbf3c290c..065acc536afa7d0 100644 --- 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 @@ -66,7 +66,7 @@ declare i32 @__gxx_personality_v0(...) ; 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: .byte 5 # On action: 3 ; CHECK-NEXT: .p2align 2 ; CHECK-NEXT: .Lexception1: ; CHECK-NEXT: .byte 0 # @LPStart Encoding = absptr @@ -85,9 +85,12 @@ declare i32 @__gxx_personality_v0(...) ; 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 0 # >> Action Record 2 << +; CHECK-NEXT: # Cleanup ; CHECK-NEXT: .byte 125 # Continue to action 1 +; CHECK-NEXT: .byte 1 # >> Action Record 3 << +; CHECK-NEXT: # Catch TypeInfo 1 +; CHECK-NEXT: .byte 125 # Continue to action 2 ; CHECK-NEXT: .p2align 2 ; CHECK-NEXT: # >> Catch TypeInfos << ; CHECK-NEXT: .long _ZTIi # TypeInfo 1 diff --git a/llvm/test/CodeGen/XCore/exception.ll b/llvm/test/CodeGen/XCore/exception.ll index 725c17eca6a9dad..2869f594ff26239 100644 --- a/llvm/test/CodeGen/XCore/exception.ll +++ b/llvm/test/CodeGen/XCore/exception.ll @@ -112,7 +112,7 @@ Exit: ; CHECK: .uleb128 [[PRE_G]]-[[START]] ; CHECK: .uleb128 [[POST_G]]-[[PRE_G]] ; CHECK: .uleb128 [[LANDING]]-[[START]] -; CHECK: .byte 5 +; CHECK: .byte 7 ; CHECK: .uleb128 [[POST_G]]-[[START]] ; CHECK: .uleb128 [[END]]-[[POST_G]] ; CHECK: .byte 0 @@ -120,10 +120,11 @@ Exit: ; CHECK: [[CST_END]]: ; CHECK: .byte 0 ; CHECK: .byte 0 +; CHECK: .byte 0 +; CHECK: .byte 125 ; CHECK: .byte 1 ; CHECK: .byte 125 ; CHECK: .byte 2 -; CHECK: .byte 125 ; CHECK: .p2align 2 ; CHECK: .long _ZTIi ; CHECK: .long _ZTId