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 @@ -441,6 +441,14 @@ /// `MCAsmInfo::ExceptionsType == ExceptionHandling::None`. bool needsCFIForDebug() const; + /// Emitting CFI unwind information is also entangled with supporting + /// unwinding used by sanitizers. This returns true for platforms which use + /// CFI for the unwind tables or exception handling. + bool needsCFIForUnwindTables(const Function &F) const; + + /// MachineFunction version of @ref needsCFIForUnwindTables(const Function &F) + bool needsCFIForUnwindTables(const MachineFunction &F) const; + /// Print to the current output stream assembly representations of the /// constants in the constant pool MCP. This is used to print out constants /// which have been "spilled to memory" by the code generator. 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 @@ -172,6 +172,13 @@ void deleted() override; void allUsesReplacedWith(Value *V2) override; }; + +static bool anyFunctionNeedsCFIForUnwindTables(const AsmPrinter &Printer, + const Module &M) { + return any_of(M, [&Printer](const Function &F) { + return Printer.needsCFIForUnwindTables(F); + }); +} } // namespace class llvm::AddrLabelMap { @@ -528,7 +535,8 @@ PPTimerDescription, PPGroupName, PPGroupDescription); } - switch (MAI->getExceptionHandlingType()) { + auto const ExceptionHandlingType = MAI->getExceptionHandlingType(); + switch (ExceptionHandlingType) { case ExceptionHandling::None: // We may want to emit CFI for debug. [[fallthrough]]; @@ -536,24 +544,23 @@ case ExceptionHandling::DwarfCFI: case ExceptionHandling::ARM: for (auto &F : M.getFunctionList()) { - if (getFunctionCFISectionType(F) != CFISection::None) - ModuleCFISection = getFunctionCFISectionType(F); + auto FunctionCFISection = getFunctionCFISectionType(F); + if (FunctionCFISection != CFISection::None) + ModuleCFISection = FunctionCFISection; // If any function needsUnwindTableEntry(), it needs .eh_frame and hence // the module needs .eh_frame. If we have found that case, we are done. if (ModuleCFISection == CFISection::EH) break; } - assert(MAI->getExceptionHandlingType() == ExceptionHandling::DwarfCFI || - ModuleCFISection != CFISection::EH); break; default: break; } EHStreamer *ES = nullptr; - switch (MAI->getExceptionHandlingType()) { + switch (ExceptionHandlingType) { case ExceptionHandling::None: - if (!needsCFIForDebug()) + if (!needsCFIForDebug() && !anyFunctionNeedsCFIForUnwindTables(*this, M)) break; [[fallthrough]]; case ExceptionHandling::SjLj: @@ -1250,8 +1257,7 @@ if (F.isDeclarationForLinker()) return CFISection::None; - if (MAI->getExceptionHandlingType() == ExceptionHandling::DwarfCFI && - F.needsUnwindTableEntry()) + if (needsCFIForUnwindTables(F)) return CFISection::EH; if (MMI->hasDebugInfo() || TM.Options.ForceDwarfFrameSection) @@ -1269,6 +1275,30 @@ return MAI->usesWindowsCFI() && MF->getFunction().needsUnwindTableEntry(); } +bool AsmPrinter::needsCFIForUnwindTables(const MachineFunction &F) const { + return needsCFIForUnwindTables(F.getFunction()); +} + +bool AsmPrinter::needsCFIForUnwindTables(const Function &F) const { + // If the unwind table entries are used for eh, emit them. + // If the unwind table entires are explicitely needed via the corresponding + // attribute, and cfi is supported by the target, emit unwind table entries + // This last case is used by sanitizers (e.g. asan) that force the use of + // unwind tables + if (F.isDeclarationForLinker()) + return false; + + const auto EHType = MAI->getExceptionHandlingType(); + if (EHType == ExceptionHandling::DwarfCFI && F.needsUnwindTableEntry()) + return true; + + if (EHType == ExceptionHandling::None && MAI->doesUseCFIForDebug() && + F.hasUWTable()) + return true; + + return false; +} + bool AsmPrinter::needsCFIForDebug() const { return MAI->getExceptionHandlingType() == ExceptionHandling::None && MAI->doesUseCFIForDebug() && ModuleCFISection == CFISection::Debug; @@ -1276,8 +1306,8 @@ void AsmPrinter::emitCFIInstruction(const MachineInstr &MI) { ExceptionHandling ExceptionHandlingType = MAI->getExceptionHandlingType(); - if (!needsCFIForDebug() && - ExceptionHandlingType != ExceptionHandling::DwarfCFI && + bool NeedsCFI = needsCFIForDebug() || needsCFIForUnwindTables(*MI.getMF()); + if (!NeedsCFI && ExceptionHandlingType != ExceptionHandling::DwarfCFI && ExceptionHandlingType != ExceptionHandling::ARM) return; 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 @@ -101,7 +101,9 @@ shouldEmitCFI = MAI.usesCFIForEH() && (shouldEmitPersonality || shouldEmitMoves); else - shouldEmitCFI = Asm->needsCFIForDebug() && shouldEmitMoves; + shouldEmitCFI = + (Asm->needsCFIForDebug() || Asm->needsCFIForUnwindTables(*MF)) && + shouldEmitMoves; } void DwarfCFIException::beginBasicBlockSection(const MachineBasicBlock &MBB) { diff --git a/llvm/test/CodeGen/AMDGPU/eh_frame.ll b/llvm/test/CodeGen/AMDGPU/eh_frame.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/AMDGPU/eh_frame.ll @@ -0,0 +1,29 @@ +; RUN: llc -mtriple=amdgcn-amd-amdhsa -mcpu=gfx908 -o - < %s | FileCheck %s --check-prefix=EH +; RUN: llc -mtriple=amdgcn-amd-amdhsa --force-dwarf-frame-section -o - < %s | FileCheck %s --check-prefix=BOTH +; RUN: llc -mtriple=amdgcn-amd-amdhsa --exception-model=dwarf -o - < %s | FileCheck %s --check-prefix=EH +; RUN: llc -mtriple=amdgcn-amd-amdhsa --force-dwarf-frame-section --exception-model=dwarf -o - < %s | FileCheck %s --check-prefix=BOTH + +; EH: f: +; EH-NOT: .cfi_sections +; EH: .cfi_startproc + +; BOTH: f: +; BOTH: .cfi_sections .eh_frame, .debug_frame +; BOTH: .cfi_startproc + +define void @f() nounwind uwtable !dbg !0 { +entry: + ret void +} + +!llvm.dbg.cu = !{!2} +!llvm.module.flags = !{!7} +!5 = !{!0} + +!0 = distinct !DISubprogram(name: "f", line: 1, isLocal: false, isDefinition: true, virtualIndex: 6, flags: DIFlagPrototyped, isOptimized: true, unit: !2, scopeLine: 1, file: !6, scope: !1, type: !3) +!1 = !DIFile(filename: "/home/llvm/test.c", directory: "/home/llvm/build") +!2 = distinct !DICompileUnit(language: DW_LANG_C99, producer: "clang", isOptimized: true, emissionKind: FullDebug, file: !6, enums: !{}, retainedTypes: !{}) +!3 = !DISubroutineType(types: !4) +!4 = !{null} +!6 = !DIFile(filename: "/home/llvm/test.c", directory: "/home/llvm/build") +!7 = !{i32 1, !"Debug Info Version", i32 3} diff --git a/llvm/test/tools/UpdateTestChecks/update_llc_test_checks/Inputs/amdgpu_generated_funcs.ll.generated.expected b/llvm/test/tools/UpdateTestChecks/update_llc_test_checks/Inputs/amdgpu_generated_funcs.ll.generated.expected --- a/llvm/test/tools/UpdateTestChecks/update_llc_test_checks/Inputs/amdgpu_generated_funcs.ll.generated.expected +++ b/llvm/test/tools/UpdateTestChecks/update_llc_test_checks/Inputs/amdgpu_generated_funcs.ll.generated.expected @@ -67,6 +67,7 @@ ; CHECK-LABEL: check_boundaries: ; CHECK: check_boundaries$local: ; CHECK-NEXT: .type check_boundaries$local,@function +; CHECK-NEXT: .cfi_startproc ; CHECK-NEXT: ; %bb.0: ; CHECK-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0) ; CHECK-NEXT: s_mov_b32 s4, s33 @@ -78,6 +79,7 @@ ; CHECK-LABEL: main: ; CHECK: main$local: ; CHECK-NEXT: .type main$local,@function +; CHECK-NEXT: .cfi_startproc ; CHECK-NEXT: ; %bb.0: ; CHECK-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0) ; CHECK-NEXT: s_mov_b32 s6, s33 diff --git a/llvm/test/tools/UpdateTestChecks/update_llc_test_checks/Inputs/amdgpu_generated_funcs.ll.nogenerated.expected b/llvm/test/tools/UpdateTestChecks/update_llc_test_checks/Inputs/amdgpu_generated_funcs.ll.nogenerated.expected --- a/llvm/test/tools/UpdateTestChecks/update_llc_test_checks/Inputs/amdgpu_generated_funcs.ll.nogenerated.expected +++ b/llvm/test/tools/UpdateTestChecks/update_llc_test_checks/Inputs/amdgpu_generated_funcs.ll.nogenerated.expected @@ -8,6 +8,7 @@ ; CHECK-LABEL: check_boundaries: ; CHECK: check_boundaries$local: ; CHECK-NEXT: .type check_boundaries$local,@function +; CHECK-NEXT: .cfi_startproc ; CHECK-NEXT: ; %bb.0: ; CHECK-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0) ; CHECK-NEXT: s_mov_b32 s4, s33 @@ -55,6 +56,7 @@ ; CHECK-LABEL: main: ; CHECK: main$local: ; CHECK-NEXT: .type main$local,@function +; CHECK-NEXT: .cfi_startproc ; CHECK-NEXT: ; %bb.0: ; CHECK-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0) ; CHECK-NEXT: s_mov_b32 s6, s33