diff --git a/llvm/include/llvm/MC/MCAsmInfo.h b/llvm/include/llvm/MC/MCAsmInfo.h --- a/llvm/include/llvm/MC/MCAsmInfo.h +++ b/llvm/include/llvm/MC/MCAsmInfo.h @@ -371,6 +371,11 @@ /// false. bool SupportsDebugInformation = false; + /// True if target supports emitting .debug_frame unwind information when + /// ExceptionsType = ExceptionHandling::None and debug info is requested. + /// Defaults to false. + bool SupportsDebugUnwindInformation = false; + /// Exception handling format for the target. Defaults to None. ExceptionHandling ExceptionsType = ExceptionHandling::None; @@ -631,6 +636,10 @@ bool doesSupportDebugInformation() const { return SupportsDebugInformation; } + bool doesSupportDebugUnwindInformation() const { + return SupportsDebugUnwindInformation; + } + bool doesSupportExceptionHandling() const { return ExceptionsType != ExceptionHandling::None; } 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 @@ -14,6 +14,7 @@ #include "CodeViewDebug.h" #include "DwarfDebug.h" #include "DwarfException.h" +#include "UnwindStreamer.h" #include "WasmException.h" #include "WinCFGuard.h" #include "WinException.h" @@ -135,6 +136,8 @@ static const char *const DWARFGroupDescription = "DWARF Emission"; static const char *const DbgTimerName = "emit"; static const char *const DbgTimerDescription = "Debug Info Emission"; +static const char *const UnwindTimerName = "write_unwind"; +static const char *const UnwindTimerDescription = "DWARF Unwind Writer"; static const char *const EHTimerName = "write_exception"; static const char *const EHTimerDescription = "DWARF Exception Writer"; static const char *const CFGuardName = "Control Flow Guard"; @@ -321,58 +324,68 @@ } } - switch (MAI->getExceptionHandlingType()) { - case ExceptionHandling::SjLj: - case ExceptionHandling::DwarfCFI: - case ExceptionHandling::ARM: + if (MAI->getExceptionHandlingType() == ExceptionHandling::None && + (TM.Options.ForceDwarfFrameSection || + (MMI->hasDebugInfo() && MAI->doesSupportDebugUnwindInformation()))) { isCFIMoveForDebugging = true; - if (MAI->getExceptionHandlingType() != ExceptionHandling::DwarfCFI) - break; - for (auto &F: M.getFunctionList()) { - // If the module contains any function with unwind data, - // .eh_frame has to be emitted. - // Ignore functions that won't get emitted. - if (!F.isDeclarationForLinker() && F.needsUnwindTableEntry()) { - isCFIMoveForDebugging = false; + Handlers.emplace_back(std::make_unique(this), + UnwindTimerName, UnwindTimerDescription, + DWARFGroupName, DWARFGroupDescription); + } else { + switch (MAI->getExceptionHandlingType()) { + case ExceptionHandling::SjLj: + case ExceptionHandling::DwarfCFI: + case ExceptionHandling::ARM: + isCFIMoveForDebugging = true; + if (MAI->getExceptionHandlingType() != ExceptionHandling::DwarfCFI) break; + for (auto &F : M.getFunctionList()) { + // If the module contains any function with unwind data, + // .eh_frame has to be emitted. + // Ignore functions that won't get emitted. + if (!F.isDeclarationForLinker() && F.needsUnwindTableEntry()) { + isCFIMoveForDebugging = false; + break; + } } + break; + default: + isCFIMoveForDebugging = false; + break; } - break; - default: - isCFIMoveForDebugging = false; - break; - } - EHStreamer *ES = nullptr; - switch (MAI->getExceptionHandlingType()) { - case ExceptionHandling::None: - break; - case ExceptionHandling::SjLj: - case ExceptionHandling::DwarfCFI: - ES = new DwarfCFIException(this); - break; - case ExceptionHandling::ARM: - ES = new ARMException(this); - break; - case ExceptionHandling::WinEH: - switch (MAI->getWinEHEncodingType()) { - default: llvm_unreachable("unsupported unwinding information encoding"); - case WinEH::EncodingType::Invalid: + EHStreamer *ES = nullptr; + switch (MAI->getExceptionHandlingType()) { + case ExceptionHandling::None: break; - case WinEH::EncodingType::X86: - case WinEH::EncodingType::Itanium: - ES = new WinException(this); + case ExceptionHandling::SjLj: + case ExceptionHandling::DwarfCFI: + ES = new DwarfCFIException(this); + break; + case ExceptionHandling::ARM: + ES = new ARMException(this); + break; + case ExceptionHandling::WinEH: + switch (MAI->getWinEHEncodingType()) { + default: + llvm_unreachable("unsupported unwinding information encoding"); + case WinEH::EncodingType::Invalid: + break; + case WinEH::EncodingType::X86: + case WinEH::EncodingType::Itanium: + ES = new WinException(this); + break; + } + break; + case ExceptionHandling::Wasm: + ES = new WasmException(this); break; } - break; - case ExceptionHandling::Wasm: - ES = new WasmException(this); - break; + if (ES) + Handlers.emplace_back(std::unique_ptr(ES), EHTimerName, + EHTimerDescription, DWARFGroupName, + DWARFGroupDescription); } - if (ES) - Handlers.emplace_back(std::unique_ptr(ES), EHTimerName, - EHTimerDescription, DWARFGroupName, - DWARFGroupDescription); // Emit tables for any value of cfguard flag (i.e. cfguard=1 or cfguard=2). if (mdconst::extract_or_null(M.getModuleFlag("cfguard"))) @@ -997,7 +1010,8 @@ void AsmPrinter::emitCFIInstruction(const MachineInstr &MI) { ExceptionHandling ExceptionHandlingType = MAI->getExceptionHandlingType(); - if (ExceptionHandlingType != ExceptionHandling::DwarfCFI && + if (!MAI->doesSupportDebugUnwindInformation() && + ExceptionHandlingType != ExceptionHandling::DwarfCFI && ExceptionHandlingType != ExceptionHandling::ARM) return; diff --git a/llvm/lib/CodeGen/AsmPrinter/CMakeLists.txt b/llvm/lib/CodeGen/AsmPrinter/CMakeLists.txt --- a/llvm/lib/CodeGen/AsmPrinter/CMakeLists.txt +++ b/llvm/lib/CodeGen/AsmPrinter/CMakeLists.txt @@ -24,6 +24,7 @@ WinException.cpp CodeViewDebug.cpp WasmException.cpp + UnwindStreamer.cpp DEPENDS intrinsics_gen diff --git a/llvm/lib/CodeGen/AsmPrinter/UnwindStreamer.h b/llvm/lib/CodeGen/AsmPrinter/UnwindStreamer.h new file mode 100644 --- /dev/null +++ b/llvm/lib/CodeGen/AsmPrinter/UnwindStreamer.h @@ -0,0 +1,50 @@ +//===- UnwindStreamer.h - Unwind Directive Streamer -------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file contains support for writing unwind info into assembly files. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_CODEGEN_ASMPRINTER_UNWINDSTREAMER_H +#define LLVM_LIB_CODEGEN_ASMPRINTER_UNWINDSTREAMER_H + +#include "llvm/CodeGen/AsmPrinterHandler.h" +#include "llvm/Support/Compiler.h" + +namespace llvm { + +class AsmPrinter; +class MachineInstr; +class MCSymbol; + +/// Emits unwind info directives. +class LLVM_LIBRARY_VISIBILITY UnwindStreamer : public AsmPrinterHandler { +protected: + /// Target of directive emission. + AsmPrinter *Asm; + + /// Per-module flag to indicate if .debug_frame has been emitted yet. + bool HasEmittedDebugFrame = false; + +public: + UnwindStreamer(AsmPrinter *A); + ~UnwindStreamer() override; + + // Unused. + void setSymbolSize(const MCSymbol *Sym, uint64_t Size) override {} + void endModule() override {} + void beginInstruction(const MachineInstr *MI) override {} + void endInstruction() override {} + + void beginFunction(const MachineFunction *MF) override; + void endFunction(const MachineFunction *MF) override; +}; + +} // end namespace llvm + +#endif // LLVM_LIB_CODEGEN_ASMPRINTER_UNWINDSTREAMER_H diff --git a/llvm/lib/CodeGen/AsmPrinter/UnwindStreamer.cpp b/llvm/lib/CodeGen/AsmPrinter/UnwindStreamer.cpp new file mode 100644 --- /dev/null +++ b/llvm/lib/CodeGen/AsmPrinter/UnwindStreamer.cpp @@ -0,0 +1,38 @@ +//===- CodeGen/AsmPrinter/UnwindStreamer.cpp - Unwind Directive Streamer --===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file contains support for writing unwind info into assembly files. +// +//===----------------------------------------------------------------------===// + +#include "UnwindStreamer.h" +#include "llvm/CodeGen/AsmPrinter.h" +#include "llvm/MC/MCStreamer.h" + +using namespace llvm; + +namespace llvm { +class MachineFunction; +} // end namespace llvm + +UnwindStreamer::UnwindStreamer(AsmPrinter *A) : Asm(A) {} + +UnwindStreamer::~UnwindStreamer() = default; + +void UnwindStreamer::beginFunction(const MachineFunction *MF) { + assert(Asm->needsCFIMoves() == AsmPrinter::CFI_M_Debug); + if (!HasEmittedDebugFrame) { + Asm->OutStreamer->emitCFISections(false, true); + HasEmittedDebugFrame = true; + } + Asm->OutStreamer->emitCFIStartProc(/*IsSimple=*/false); +} + +void UnwindStreamer::endFunction(const MachineFunction *MF) { + Asm->OutStreamer->emitCFIEndProc(); +} diff --git a/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUMCAsmInfo.cpp b/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUMCAsmInfo.cpp --- a/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUMCAsmInfo.cpp +++ b/llvm/lib/Target/AMDGPU/MCTargetDesc/AMDGPUMCAsmInfo.cpp @@ -43,6 +43,7 @@ //===--- Dwarf Emission Directives -----------------------------------===// SupportsDebugInformation = true; DwarfRegNumForCFI = true; + SupportsDebugUnwindInformation = true; UseIntegratedAssembler = false; } diff --git a/llvm/test/CodeGen/AMDGPU/split-arg-dbg-value.ll b/llvm/test/CodeGen/AMDGPU/split-arg-dbg-value.ll --- a/llvm/test/CodeGen/AMDGPU/split-arg-dbg-value.ll +++ b/llvm/test/CodeGen/AMDGPU/split-arg-dbg-value.ll @@ -6,6 +6,8 @@ ; GCN: .Lfunc_begin0: ; GCN-NEXT: .file 0 ; GCN-NEXT: .loc 0 3 0 ; /tmp/dbg.cl:3:0 +; GCN-NEXT: .cfi_sections .debug_frame +; GCN-NEXT: .cfi_startproc ; GCN-NEXT: ; %bb.0: ; GCN-NEXT: ;DEBUG_VALUE: split_v4f32_arg:arg <- [DW_OP_constu 1, DW_OP_swap, DW_OP_xderef, DW_OP_LLVM_fragment 96 32] $vgpr3 ; GCN-NEXT: ;DEBUG_VALUE: split_v4f32_arg:arg <- [DW_OP_constu 1, DW_OP_swap, DW_OP_xderef, DW_OP_LLVM_fragment 64 32] $vgpr2 @@ -16,6 +18,7 @@ ; GCN-NEXT: .loc 0 4 5 prologue_end ; /tmp/dbg.cl:4:5 ; GCN-NEXT: s_setpc_b64 s[30:31] ; GCN-NEXT: .Ltmp1: +; GCN: .cfi_endproc call void @llvm.dbg.value(metadata <4 x float> %arg, metadata !18, metadata !DIExpression(DW_OP_constu, 1, DW_OP_swap, DW_OP_xderef)), !dbg !19 ret <4 x float> %arg, !dbg !20 } @@ -24,6 +27,7 @@ ; GCN-LABEL: split_v4f32_multi_arg: ; GCN: .Lfunc_begin1: ; GCN-NEXT: .loc 0 7 0 ; /tmp/dbg.cl:7:0 +; GCN-NEXT: .cfi_startproc ; GCN-NEXT: ; %bb.0: ; GCN-NEXT: ;DEBUG_VALUE: split_v4f32_multi_arg:arg1 <- [DW_OP_constu 1, DW_OP_swap, DW_OP_xderef, DW_OP_LLVM_fragment 32 32] $vgpr5 ; GCN-NEXT: ;DEBUG_VALUE: split_v4f32_multi_arg:arg1 <- [DW_OP_constu 1, DW_OP_swap, DW_OP_xderef, DW_OP_LLVM_fragment 0 32] $vgpr4 @@ -45,6 +49,7 @@ ; GCN-NEXT: .loc 0 8 5 is_stmt 0 ; /tmp/dbg.cl:8:5 ; GCN-NEXT: s_setpc_b64 s[30:31] ; GCN-NEXT: .Ltmp7: +; GCN: .cfi_endproc call void @llvm.dbg.value(metadata <4 x float> %arg0, metadata !29, metadata !DIExpression(DW_OP_constu, 1, DW_OP_swap, DW_OP_xderef)), !dbg !31 call void @llvm.dbg.value(metadata <2 x float> %arg1, metadata !30, metadata !DIExpression(DW_OP_constu, 1, DW_OP_swap, DW_OP_xderef)), !dbg !31 %tmp = shufflevector <2 x float> %arg1, <2 x float> undef, <4 x i32> , !dbg !32 @@ -56,6 +61,7 @@ ; GCN-LABEL: split_v4f16_arg: ; GCN: .Lfunc_begin2: ; GCN-NEXT: .loc 0 11 0 is_stmt 1 ; /tmp/dbg.cl:11:0 +; GCN-NEXT: .cfi_startproc ; GCN-NEXT: ; %bb.0: ; GCN-NEXT: ;DEBUG_VALUE: split_v4f16_arg:arg <- [DW_OP_constu 1, DW_OP_swap, DW_OP_xderef, DW_OP_LLVM_fragment 32 32] $vgpr1 ; GCN-NEXT: ;DEBUG_VALUE: split_v4f16_arg:arg <- [DW_OP_constu 1, DW_OP_swap, DW_OP_xderef, DW_OP_LLVM_fragment 0 32] $vgpr0 @@ -64,6 +70,7 @@ ; GCN-NEXT: .loc 0 12 5 prologue_end ; /tmp/dbg.cl:12:5 ; GCN-NEXT: s_setpc_b64 s[30:31] ; GCN-NEXT: .Ltmp9: +; GCN: .cfi_endproc call void @llvm.dbg.value(metadata <4 x half> %arg, metadata !42, metadata !DIExpression(DW_OP_constu, 1, DW_OP_swap, DW_OP_xderef)), !dbg !43 ret <4 x half> %arg, !dbg !44 } @@ -72,6 +79,7 @@ ; GCN-LABEL: split_f64_arg: ; GCN: .Lfunc_begin3: ; GCN-NEXT: .loc 0 15 0 ; /tmp/dbg.cl:15:0 +; GCN-NEXT: .cfi_startproc ; GCN-NEXT: ; %bb.0: ; GCN-NEXT: ;DEBUG_VALUE: split_f64_arg:arg <- [DW_OP_constu 1, DW_OP_swap, DW_OP_xderef, DW_OP_LLVM_fragment 32 32] $vgpr1 ; GCN-NEXT: ;DEBUG_VALUE: split_f64_arg:arg <- [DW_OP_constu 1, DW_OP_swap, DW_OP_xderef, DW_OP_LLVM_fragment 0 32] $vgpr0 @@ -80,6 +88,7 @@ ; GCN-NEXT: .loc 0 16 5 prologue_end ; /tmp/dbg.cl:16:5 ; GCN-NEXT: s_setpc_b64 s[30:31] ; GCN-NEXT: .Ltmp11: +; GCN: .cfi_endproc call void @llvm.dbg.value(metadata double %arg, metadata !50, metadata !DIExpression(DW_OP_constu, 1, DW_OP_swap, DW_OP_xderef)), !dbg !51 ret double %arg, !dbg !52 } @@ -88,6 +97,7 @@ ; GCN-LABEL: split_v2f64_arg: ; GCN: .Lfunc_begin4: ; GCN-NEXT: .loc 0 19 0 ; /tmp/dbg.cl:19:0 +; GCN-NEXT: .cfi_startproc ; GCN-NEXT: ; %bb.0: ; GCN-NEXT: ;DEBUG_VALUE: split_v2f64_arg:arg <- [DW_OP_constu 1, DW_OP_swap, DW_OP_xderef, DW_OP_LLVM_fragment 96 32] $vgpr3 ; GCN-NEXT: ;DEBUG_VALUE: split_v2f64_arg:arg <- [DW_OP_constu 1, DW_OP_swap, DW_OP_xderef, DW_OP_LLVM_fragment 64 32] $vgpr2 @@ -98,6 +108,7 @@ ; GCN-NEXT: .loc 0 20 5 prologue_end ; /tmp/dbg.cl:20:5 ; GCN-NEXT: s_setpc_b64 s[30:31] ; GCN-NEXT: .Ltmp13: +; GCN: .cfi_endproc call void @llvm.dbg.value(metadata <2 x double> %arg, metadata !59, metadata !DIExpression(DW_OP_constu, 1, DW_OP_swap, DW_OP_xderef)), !dbg !60 ret <2 x double> %arg, !dbg !61 } @@ -106,6 +117,7 @@ ; GCN-LABEL: split_i64_arg: ; GCN: .Lfunc_begin5: ; GCN-NEXT: .loc 0 23 0 ; /tmp/dbg.cl:23:0 +; GCN-NEXT: .cfi_startproc ; GCN-NEXT: ; %bb.0: ; GCN-NEXT: ;DEBUG_VALUE: split_i64_arg:arg <- [DW_OP_constu 1, DW_OP_swap, DW_OP_xderef, DW_OP_LLVM_fragment 32 32] $vgpr1 ; GCN-NEXT: ;DEBUG_VALUE: split_i64_arg:arg <- [DW_OP_constu 1, DW_OP_swap, DW_OP_xderef, DW_OP_LLVM_fragment 0 32] $vgpr0 @@ -114,6 +126,7 @@ ; GCN-NEXT: .loc 0 24 5 prologue_end ; /tmp/dbg.cl:24:5 ; GCN-NEXT: s_setpc_b64 s[30:31] ; GCN-NEXT: .Ltmp15: +; GCN: .cfi_endproc call void @llvm.dbg.value(metadata i64 %arg, metadata !67, metadata !DIExpression(DW_OP_constu, 1, DW_OP_swap, DW_OP_xderef)), !dbg !68 ret i64 %arg, !dbg !69 } @@ -122,6 +135,7 @@ ; GCN-LABEL: split_ptr_arg: ; GCN: .Lfunc_begin6: ; GCN-NEXT: .loc 0 27 0 ; /tmp/dbg.cl:27:0 +; GCN-NEXT: .cfi_startproc ; GCN-NEXT: ; %bb.0: ; GCN-NEXT: ;DEBUG_VALUE: split_ptr_arg:arg <- [DW_OP_constu 1, DW_OP_swap, DW_OP_xderef, DW_OP_LLVM_fragment 32 32] $vgpr1 ; GCN-NEXT: ;DEBUG_VALUE: split_ptr_arg:arg <- [DW_OP_constu 1, DW_OP_swap, DW_OP_xderef, DW_OP_LLVM_fragment 0 32] $vgpr0 @@ -130,6 +144,7 @@ ; GCN-NEXT: .loc 0 28 5 prologue_end ; /tmp/dbg.cl:28:5 ; GCN-NEXT: s_setpc_b64 s[30:31] ; GCN-NEXT: .Ltmp17: +; GCN: .cfi_endproc call void @llvm.dbg.value(metadata i8 addrspace(1)* %arg, metadata !76, metadata !DIExpression(DW_OP_constu, 1, DW_OP_swap, DW_OP_xderef)), !dbg !77 ret i8 addrspace(1)* %arg, !dbg !78 } diff --git a/llvm/test/DebugInfo/AMDGPU/cfi.ll b/llvm/test/DebugInfo/AMDGPU/cfi.ll new file mode 100644 --- /dev/null +++ b/llvm/test/DebugInfo/AMDGPU/cfi.ll @@ -0,0 +1,35 @@ +; RUN: llc -mcpu=gfx900 -mtriple=amdgcn-amd-amdhsa -filetype=obj -o - %s | llvm-dwarfdump -debug-frame - | FileCheck %s + +; CHECK: .debug_frame contents: +; CHECK: 00000000 0000000c ffffffff CIE +; CHECK-NEXT: Format: DWARF32 +; CHECK-NEXT: Version: 4 +; CHECK-NEXT: Augmentation: "" +; CHECK-NEXT: Address size: 8 +; CHECK-NEXT: Segment desc size: 0 +; CHECK-NEXT: Code alignment factor: 4 +; CHECK-NEXT: Data alignment factor: 4 +; CHECK-NEXT: Return address column: 16 +; CHECK-EMPTY: +; CHECK: DW_CFA_nop: +; CHECK-EMPTY: +; CHECK-NEXT: 00000010 {{[0-9]+}} 00000000 FDE cie=00000000 pc=00000000...{{[0-9]+}} +; CHECK-NEXT: Format: DWARF32 +; CHECK-EMPTY: +; CHECK-EMPTY: +; CHECK: .eh_frame contents: +; CHECK-NOT: CIE + +define void @func() #0 { + ret void +} + +attributes #0 = { nounwind } + +!llvm.module.flags = !{!0, !1} +!llvm.dbg.cu = !{!2} + +!0 = !{i32 2, !"Dwarf Version", i32 4} +!1 = !{i32 2, !"Debug Info Version", i32 3} +!2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, emissionKind: FullDebug) +!3 = !DIFile(filename: "file", directory: "dir") diff --git a/llvm/test/MC/ELF/AMDGPU/cfi.s b/llvm/test/MC/ELF/AMDGPU/cfi.s new file mode 100644 --- /dev/null +++ b/llvm/test/MC/ELF/AMDGPU/cfi.s @@ -0,0 +1,33 @@ +# RUN: llvm-mc -filetype=asm -mcpu=gfx900 -triple amdgcn-amd-amdhsa %s -o - | FileCheck --check-prefix=ASM %s +# RUN: llvm-mc -filetype=obj -mcpu=gfx900 -triple amdgcn-amd-amdhsa %s -o %t +# RUN: llvm-readelf -S -r -x .debug_frame %t | FileCheck --check-prefix=READELF %s + +f: + .cfi_sections .debug_frame + .cfi_startproc + s_nop 0 + .cfi_endproc + +# ASM: f: +# ASM-NEXT: .cfi_sections .debug_frame +# NOTE: an extra empty line is an outcome of how AsmParser works today +# ASM-EMPTY: +# ASM-NEXT: .cfi_startproc +# ASM-NEXT: s_nop 0 +# NOTE: an extra empty line is an outcome of how AsmParser works today +# ASM-EMPTY: +# ASM-NEXT: .cfi_endproc + +# READELF: Section Headers: +# READELF: Name Type Address Off Size ES Flg Lk Inf Al +# READELF: .debug_frame PROGBITS 0000000000000000 000048 000028 00 0 0 8 + +# READELF: Relocation section '.rela.debug_frame' at offset 0xd0 contains 2 entries: +# READELF-NEXT: Offset Info Type Symbol's Value Symbol's Name + Addend +# READELF-NEXT: 0000000000000014 0000000300000006 R_AMDGPU_ABS32 0000000000000000 .debug_frame + 0 +# READELF-NEXT: 0000000000000018 0000000200000003 R_AMDGPU_ABS64 0000000000000000 .text + 0 + +# READELF: Hex dump of section '.debug_frame': +# READELF-NEXT: 0x00000000 0c000000 ffffffff 04000800 04041000 ................ +# READELF-NEXT: 0x00000010 14000000 00000000 00000000 00000000 ................ +# READELF-NEXT: 0x00000020 04000000 00000000 ........ diff --git a/llvm/test/MC/ELF/AMDGPU/lit.local.cfg b/llvm/test/MC/ELF/AMDGPU/lit.local.cfg new file mode 100644 --- /dev/null +++ b/llvm/test/MC/ELF/AMDGPU/lit.local.cfg @@ -0,0 +1,3 @@ +# We have to reset config.unsupported here because the parent directory is +# predicated on 'X86'. +config.unsupported = 'AMDGPU' not in config.root.targets