diff --git a/llvm/include/llvm/BinaryFormat/Dwarf.def b/llvm/include/llvm/BinaryFormat/Dwarf.def --- a/llvm/include/llvm/BinaryFormat/Dwarf.def +++ b/llvm/include/llvm/BinaryFormat/Dwarf.def @@ -611,6 +611,13 @@ HANDLE_DW_AT(0x3e07, LLVM_apinotes, 0, APPLE) HANDLE_DW_AT(0x3e08, LLVM_ptrauth_isa_pointer, 0, LLVM) HANDLE_DW_AT(0x3e09, LLVM_ptrauth_authenticates_null_values, 0, LLVM) +// Heterogeneous Debugging Extension defined at +// https://llvm.org/docs/AMDGPUDwarfProposalForHeterogeneousDebugging.html. +HANDLE_DW_AT(0x3f08, LLVM_active_lane, 0, LLVM) +HANDLE_DW_AT(0x3f09, LLVM_augmentation, 0, LLVM) +HANDLE_DW_AT(0x3f0a, LLVM_lanes, 0, LLVM) +HANDLE_DW_AT(0x3f0b, LLVM_lane_pc, 0, LLVM) +HANDLE_DW_AT(0x3f0c, LLVM_vector_size, 0, LLVM) // Apple extensions. @@ -896,6 +903,20 @@ // location stack or any of its values. It is defined as a placeholder for // testing purposes. HANDLE_DW_OP_LLVM_USEROP(0x0001, nop) +// Heterogeneous Debugging Extension defined at +// https://llvm.org/docs/AMDGPUDwarfProposalForHeterogeneousDebugging.html. +HANDLE_DW_OP_LLVM_USEROP(0x0002, form_aspace_address) +HANDLE_DW_OP_LLVM_USEROP(0x0003, push_lane) +HANDLE_DW_OP_LLVM_USEROP(0x0004, offset) +HANDLE_DW_OP_LLVM_USEROP(0x0005, offset_uconst) +HANDLE_DW_OP_LLVM_USEROP(0x0006, bit_offset) +HANDLE_DW_OP_LLVM_USEROP(0x0007, call_frame_entry_reg) +HANDLE_DW_OP_LLVM_USEROP(0x0008, undefined) +HANDLE_DW_OP_LLVM_USEROP(0x0009, aspace_bregx) +HANDLE_DW_OP_LLVM_USEROP(0x000a, aspace_implicit_pointer) +HANDLE_DW_OP_LLVM_USEROP(0x000b, piece_end) +HANDLE_DW_OP_LLVM_USEROP(0x000c, extend) +HANDLE_DW_OP_LLVM_USEROP(0x000d, select_bit_piece) // DWARF languages. HANDLE_DW_LANG(0x0001, C89, 0, 2, DWARF) diff --git a/llvm/lib/DebugInfo/DWARF/DWARFExpression.cpp b/llvm/lib/DebugInfo/DWARF/DWARFExpression.cpp --- a/llvm/lib/DebugInfo/DWARF/DWARFExpression.cpp +++ b/llvm/lib/DebugInfo/DWARF/DWARFExpression.cpp @@ -125,6 +125,26 @@ static constexpr auto LlvmUserDescriptions = []() { std::array Descriptions; Descriptions[DW_OP_LLVM_nop] = Desc(Op::Dwarf5, Op::SizeSubOpLEB); + Descriptions[DW_OP_LLVM_nop] = Desc(Op::Dwarf5, Op::SizeSubOpLEB); + Descriptions[DW_OP_LLVM_form_aspace_address] = + Desc(Op::Dwarf5, Op::SizeSubOpLEB); + Descriptions[DW_OP_LLVM_push_lane] = Desc(Op::Dwarf5, Op::SizeSubOpLEB); + Descriptions[DW_OP_LLVM_offset] = Desc(Op::Dwarf5, Op::SizeSubOpLEB); + Descriptions[DW_OP_LLVM_offset_uconst] = + Desc(Op::Dwarf5, Op::SizeSubOpLEB, Op::SizeLEB); + Descriptions[DW_OP_LLVM_bit_offset] = Desc(Op::Dwarf5, Op::SizeSubOpLEB); + Descriptions[DW_OP_LLVM_call_frame_entry_reg] = + Desc(Op::Dwarf5, Op::SizeSubOpLEB, Op::SizeLEB); + Descriptions[DW_OP_LLVM_undefined] = Desc(Op::Dwarf5, Op::SizeSubOpLEB); + Descriptions[DW_OP_LLVM_aspace_bregx] = + Desc(Op::Dwarf5, Op::SizeSubOpLEB, Op::SizeLEB, Op::SignedSizeLEB); + Descriptions[DW_OP_LLVM_aspace_implicit_pointer] = + Desc(Op::Dwarf5, Op::SizeSubOpLEB, Op::SizeRefAddr, Op::SignedSizeLEB); + Descriptions[DW_OP_LLVM_piece_end] = Desc(Op::Dwarf5, Op::SizeSubOpLEB); + Descriptions[DW_OP_LLVM_extend] = + Desc(Op::Dwarf5, Op::SizeSubOpLEB, Op::SizeLEB, Op::SizeLEB); + Descriptions[DW_OP_LLVM_select_bit_piece] = + Desc(Op::Dwarf5, Op::SizeSubOpLEB, Op::SizeLEB, Op::SizeLEB); return Descriptions; }(); assert(Opcode == DW_OP_LLVM_user); @@ -257,10 +277,23 @@ uint64_t DwarfRegNum; unsigned OpNum = 0; + unsigned SubOpcode = 0; + + if (Opcode == DW_OP_LLVM_user) { + SubOpcode = Operands[OpNum++]; + // FIXME: This shouldn't be here, but with the current structure it is + // cleanest to have this routine handle it. It seems like this + // entire routine should just be "inlined" into the caller. + StringRef SubName = SubOperationEncodingString(Opcode, SubOpcode); + assert(!SubName.empty() && "DW_OP SubOp has no name!"); + OS << ' ' << SubName; + } if (Opcode == DW_OP_bregx || Opcode == DW_OP_regx || - Opcode == DW_OP_regval_type) + Opcode == DW_OP_regval_type || SubOpcode == DW_OP_LLVM_aspace_bregx) DwarfRegNum = Operands[OpNum++]; + else if (SubOpcode == DW_OP_LLVM_call_frame_entry_reg) + DwarfRegNum = Operands[OpNum]; else if (Opcode >= DW_OP_breg0 && Opcode < DW_OP_bregx) DwarfRegNum = Opcode - DW_OP_breg0; else @@ -269,7 +302,7 @@ auto RegName = DumpOpts.GetNameForDWARFReg(DwarfRegNum, DumpOpts.IsEH); if (!RegName.empty()) { if ((Opcode >= DW_OP_breg0 && Opcode <= DW_OP_breg31) || - Opcode == DW_OP_bregx) + Opcode == DW_OP_bregx || SubOpcode == DW_OP_LLVM_aspace_bregx) OS << ' ' << RegName << format("%+" PRId64, Operands[OpNum]); else OS << ' ' << RegName.data(); @@ -300,10 +333,14 @@ assert(!Name.empty() && "DW_OP has no name!"); OS << Name; + std::optional SubOpcode = getSubCode(); + if ((Opcode >= DW_OP_breg0 && Opcode <= DW_OP_breg31) || (Opcode >= DW_OP_reg0 && Opcode <= DW_OP_reg31) || Opcode == DW_OP_bregx || Opcode == DW_OP_regx || - Opcode == DW_OP_regval_type) + Opcode == DW_OP_regval_type || + (SubOpcode && (SubOpcode == DW_OP_LLVM_call_frame_entry_reg || + SubOpcode == DW_OP_LLVM_aspace_bregx))) if (prettyPrintRegisterOp(U, OS, DumpOpts, Opcode, Operands)) return true; diff --git a/llvm/test/tools/llvm-dwarfdump/X86/heterogeneous_proposal.s b/llvm/test/tools/llvm-dwarfdump/X86/heterogeneous_proposal.s new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-dwarfdump/X86/heterogeneous_proposal.s @@ -0,0 +1,37 @@ +# RUN: llvm-mc %s -filetype=obj -triple=i686-pc-linux -o %t +# RUN: llvm-dwarfdump -v %t | FileCheck %s + +# Check that we can decode new ops described at +# llvm/docs/AMDGPUUsage.rst#expression-operation-encodings + +# FIXME: Is there a better approach than using `DW_CFA_expression EAX `? + +# CHECK: .eh_frame contents: +# CHECK: FDE +# CHECK: Format: DWARF32 + +foo: + .cfi_startproc + # CHECK-NEXT: DW_CFA_expression: EAX DW_OP_LLVM_user DW_OP_LLVM_form_aspace_address + .cfi_escape 0x10, 0x00, 0x02, 0xe9, 0x02 + # CHECK-NEXT: DW_CFA_expression: EAX DW_OP_LLVM_user DW_OP_LLVM_push_lane + .cfi_escape 0x10, 0x00, 0x02, 0xe9, 0x03 + # CHECK-NEXT: DW_CFA_expression: EAX DW_OP_LLVM_user DW_OP_LLVM_offset + .cfi_escape 0x10, 0x00, 0x02, 0xe9, 0x04 + # CHECK-NEXT: DW_CFA_expression: EAX DW_OP_LLVM_user DW_OP_LLVM_offset_uconst 0x0 + .cfi_escape 0x10, 0x00, 0x03, 0xe9, 0x05, 0x00 + # CHECK-NEXT: DW_CFA_expression: EAX DW_OP_LLVM_user DW_OP_LLVM_bit_offset + .cfi_escape 0x10, 0x00, 0x02, 0xe9, 0x06 + # CHECK-NEXT: DW_CFA_expression: EAX DW_OP_LLVM_user DW_OP_LLVM_call_frame_entry_reg EAX + .cfi_escape 0x10, 0x00, 0x03, 0xe9, 0x07, 0x00 + # CHECK-NEXT: DW_CFA_expression: EAX DW_OP_LLVM_user DW_OP_LLVM_undefined + .cfi_escape 0x10, 0x00, 0x02, 0xe9, 0x08 + # CHECK-NEXT: DW_CFA_expression: EAX DW_OP_LLVM_user DW_OP_LLVM_aspace_bregx EAX+2 + .cfi_escape 0x10, 0x00, 0x04, 0xe9, 0x09, 0x0, 0x2 + # CHECK-NEXT: DW_CFA_expression: EAX DW_OP_LLVM_user DW_OP_LLVM_piece_end + .cfi_escape 0x10, 0x00, 0x02, 0xe9, 0x0b + # CHECK-NEXT: DW_CFA_expression: EAX DW_OP_LLVM_user DW_OP_LLVM_extend 0x0 0x0 + .cfi_escape 0x10, 0x00, 0x04, 0xe9, 0x0c, 0x0, 0x0 + # CHECK-NEXT: DW_CFA_expression: EAX DW_OP_LLVM_user DW_OP_LLVM_select_bit_piece 0x0 0x0 + .cfi_escape 0x10, 0x00, 0x04, 0xe9, 0x0d, 0x0, 0x0 + .cfi_endproc