diff --git a/llvm/docs/AMDGPUUsage.rst b/llvm/docs/AMDGPUUsage.rst --- a/llvm/docs/AMDGPUUsage.rst +++ b/llvm/docs/AMDGPUUsage.rst @@ -3650,7 +3650,7 @@ 2 6 Bits Bits =================================== ==== ==== ============== ================ - DW_CFA_LLVM_def_cfa_aspace 0 0Xxx ULEB128 + DW_CFA_LLVM_def_cfa_aspace 0 0x2f ULEB128 =================================== ==== ==== ============== ================ Line Table 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 @@ -891,6 +891,8 @@ HANDLE_DW_CFA_PRED(0x2d, GNU_window_save, SELECT_SPARC) HANDLE_DW_CFA_PRED(0x2d, AARCH64_negate_ra_state, SELECT_AARCH64) HANDLE_DW_CFA_PRED(0x2e, GNU_args_size, SELECT_X86) +// FIXME: decide on encoding, and decide if this should be AMDGPU-specific +HANDLE_DW_CFA(0x2f, LLVM_def_cfa_aspace) // Apple Objective-C Property Attributes. // Keep this list in sync with clang's DeclSpec.h ObjCPropertyAttributeKind! diff --git a/llvm/include/llvm/DebugInfo/DWARF/DWARFDebugFrame.h b/llvm/include/llvm/DebugInfo/DWARF/DWARFDebugFrame.h --- a/llvm/include/llvm/DebugInfo/DWARF/DWARFDebugFrame.h +++ b/llvm/include/llvm/DebugInfo/DWARF/DWARFDebugFrame.h @@ -113,6 +113,7 @@ OT_SignedFactDataOffset, OT_UnsignedFactDataOffset, OT_Register, + OT_AddressSpace, OT_Expression }; diff --git a/llvm/include/llvm/MC/MCDwarf.h b/llvm/include/llvm/MC/MCDwarf.h --- a/llvm/include/llvm/MC/MCDwarf.h +++ b/llvm/include/llvm/MC/MCDwarf.h @@ -444,6 +444,7 @@ OpRememberState, OpRestoreState, OpOffset, + OpLLVMDefCfaAspace, OpDefCfaRegister, OpDefCfaOffset, OpDefCfa, @@ -465,6 +466,7 @@ union { int Offset; unsigned Register2; + unsigned AddressSpace; }; std::vector Values; @@ -479,6 +481,11 @@ assert(Op == OpRegister); } + MCCFIInstruction(OpType Op, MCSymbol *L, unsigned AS) + : Operation(Op), Label(L), AddressSpace(AS) { + assert(Op == OpLLVMDefCfaAspace); + } + public: /// .cfi_def_cfa defines a rule for computing CFA as: take address from /// Register and add Offset to it. @@ -507,6 +514,14 @@ return MCCFIInstruction(OpAdjustCfaOffset, L, 0, Adjustment, ""); } + // FIXME: This wording and the rest of the docs here should be updated to + // better match the proposal. + /// .cfi_llvm_def_cfa_aspace modifies the rule for computing the CFA to + /// result in a memory location description in the given address space. + static MCCFIInstruction createLLVMDefCfaAspace(MCSymbol *L, unsigned AS) { + return MCCFIInstruction(OpLLVMDefCfaAspace, L, AS); + } + /// .cfi_offset Previous value of Register is saved at offset Offset /// from CFA. static MCCFIInstruction createOffset(MCSymbol *L, unsigned Register, @@ -595,6 +610,11 @@ return Register2; } + unsigned getAddressSpace() const { + assert(Operation == OpLLVMDefCfaAspace); + return AddressSpace; + } + int getOffset() const { assert(Operation == OpDefCfa || Operation == OpOffset || Operation == OpRelOffset || Operation == OpDefCfaOffset || diff --git a/llvm/include/llvm/MC/MCStreamer.h b/llvm/include/llvm/MC/MCStreamer.h --- a/llvm/include/llvm/MC/MCStreamer.h +++ b/llvm/include/llvm/MC/MCStreamer.h @@ -942,6 +942,7 @@ virtual void emitCFIDefCfa(int64_t Register, int64_t Offset); virtual void emitCFIDefCfaOffset(int64_t Offset); virtual void emitCFIDefCfaRegister(int64_t Register); + virtual void emitCFILLVMDefCfaAspace(int64_t AddressSpace); virtual void emitCFIOffset(int64_t Register, int64_t Offset); virtual void emitCFIPersonality(const MCSymbol *Sym, unsigned Encoding); virtual void emitCFILsda(const MCSymbol *Sym, unsigned Encoding); diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinterDwarf.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinterDwarf.cpp --- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinterDwarf.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinterDwarf.cpp @@ -221,6 +221,9 @@ case MCCFIInstruction::OpDefCfaRegister: OutStreamer->emitCFIDefCfaRegister(Inst.getRegister()); break; + case MCCFIInstruction::OpLLVMDefCfaAspace: + OutStreamer->emitCFILLVMDefCfaAspace(Inst.getAddressSpace()); + break; case MCCFIInstruction::OpOffset: OutStreamer->emitCFIOffset(Inst.getRegister(), Inst.getOffset()); break; diff --git a/llvm/lib/CodeGen/CFIInstrInserter.cpp b/llvm/lib/CodeGen/CFIInstrInserter.cpp --- a/llvm/lib/CodeGen/CFIInstrInserter.cpp +++ b/llvm/lib/CodeGen/CFIInstrInserter.cpp @@ -181,6 +181,14 @@ SetRegister = CFI.getRegister(); SetOffset = CFI.getOffset(); break; + case MCCFIInstruction::OpLLVMDefCfaAspace: + // TODO: Add support for handling cfi_def_cfa_aspace. +#ifndef NDEBUG + report_fatal_error( + "Support for cfi_llvm_def_cfa_aspace not implemented! Value of CFA " + "may be incorrect!\n"); +#endif + break; case MCCFIInstruction::OpRememberState: // TODO: Add support for handling cfi_remember_state. #ifndef NDEBUG diff --git a/llvm/lib/CodeGen/MIRParser/MILexer.h b/llvm/lib/CodeGen/MIRParser/MILexer.h --- a/llvm/lib/CodeGen/MIRParser/MILexer.h +++ b/llvm/lib/CodeGen/MIRParser/MILexer.h @@ -83,6 +83,7 @@ kw_cfi_adjust_cfa_offset, kw_cfi_escape, kw_cfi_def_cfa, + kw_cfi_llvm_def_cfa_aspace, kw_cfi_register, kw_cfi_remember_state, kw_cfi_restore, diff --git a/llvm/lib/CodeGen/MIRParser/MILexer.cpp b/llvm/lib/CodeGen/MIRParser/MILexer.cpp --- a/llvm/lib/CodeGen/MIRParser/MILexer.cpp +++ b/llvm/lib/CodeGen/MIRParser/MILexer.cpp @@ -228,6 +228,7 @@ .Case("adjust_cfa_offset", MIToken::kw_cfi_adjust_cfa_offset) .Case("escape", MIToken::kw_cfi_escape) .Case("def_cfa", MIToken::kw_cfi_def_cfa) + .Case("llvm_def_cfa_aspace", MIToken::kw_cfi_llvm_def_cfa_aspace) .Case("remember_state", MIToken::kw_cfi_remember_state) .Case("restore", MIToken::kw_cfi_restore) .Case("restore_state", MIToken::kw_cfi_restore_state) diff --git a/llvm/lib/CodeGen/MIRParser/MIParser.cpp b/llvm/lib/CodeGen/MIRParser/MIParser.cpp --- a/llvm/lib/CodeGen/MIRParser/MIParser.cpp +++ b/llvm/lib/CodeGen/MIRParser/MIParser.cpp @@ -475,6 +475,7 @@ bool parseMetadataOperand(MachineOperand &Dest); bool parseCFIOffset(int &Offset); bool parseCFIRegister(unsigned &Reg); + bool parseCFIAddressSpace(unsigned &AddressSpace); bool parseCFIEscapeValues(std::string& Values); bool parseCFIOperand(MachineOperand &Dest); bool parseIRBlock(BasicBlock *&BB, const Function &F); @@ -2189,6 +2190,16 @@ return false; } +bool MIParser::parseCFIAddressSpace(unsigned &AddressSpace) { + if (Token.isNot(MIToken::IntegerLiteral)) + return error("expected a cfi address space"); + if (Token.integerValue().isSigned()) + return error("expected an unsigned integer (cfi address space)"); + AddressSpace = Token.integerValue().getZExtValue(); + lex(); + return false; +} + bool MIParser::parseCFIEscapeValues(std::string &Values) { do { if (Token.isNot(MIToken::HexLiteral)) @@ -2209,6 +2220,7 @@ lex(); int Offset; unsigned Reg; + unsigned AddressSpace; unsigned CFIIndex; switch (Kind) { case MIToken::kw_cfi_same_value: @@ -2257,6 +2269,12 @@ CFIIndex = MF.addFrameInst(MCCFIInstruction::createDefCfa(nullptr, Reg, -Offset)); break; + case MIToken::kw_cfi_llvm_def_cfa_aspace: + if (parseCFIAddressSpace(AddressSpace)) + return true; + CFIIndex = MF.addFrameInst( + MCCFIInstruction::createLLVMDefCfaAspace(nullptr, AddressSpace)); + break; case MIToken::kw_cfi_remember_state: CFIIndex = MF.addFrameInst(MCCFIInstruction::createRememberState(nullptr)); break; @@ -2604,6 +2622,7 @@ case MIToken::kw_cfi_adjust_cfa_offset: case MIToken::kw_cfi_escape: case MIToken::kw_cfi_def_cfa: + case MIToken::kw_cfi_llvm_def_cfa_aspace: case MIToken::kw_cfi_register: case MIToken::kw_cfi_remember_state: case MIToken::kw_cfi_restore: diff --git a/llvm/lib/CodeGen/MachineOperand.cpp b/llvm/lib/CodeGen/MachineOperand.cpp --- a/llvm/lib/CodeGen/MachineOperand.cpp +++ b/llvm/lib/CodeGen/MachineOperand.cpp @@ -642,6 +642,12 @@ printCFIRegister(CFI.getRegister(), OS, TRI); OS << ", " << CFI.getOffset(); break; + case MCCFIInstruction::OpLLVMDefCfaAspace: + OS << "llvm_def_cfa_aspace "; + if (MCSymbol *Label = CFI.getLabel()) + MachineOperand::printSymbol(OS, *Label); + OS << CFI.getAddressSpace(); + break; case MCCFIInstruction::OpRelOffset: OS << "rel_offset "; if (MCSymbol *Label = CFI.getLabel()) diff --git a/llvm/lib/DebugInfo/DWARF/DWARFDebugFrame.cpp b/llvm/lib/DebugInfo/DWARF/DWARFDebugFrame.cpp --- a/llvm/lib/DebugInfo/DWARF/DWARFDebugFrame.cpp +++ b/llvm/lib/DebugInfo/DWARF/DWARFDebugFrame.cpp @@ -93,6 +93,7 @@ case DW_CFA_same_value: case DW_CFA_def_cfa_register: case DW_CFA_def_cfa_offset: + case DW_CFA_LLVM_def_cfa_aspace: case DW_CFA_GNU_args_size: // Operands: ULEB128 addInstruction(Opcode, Data.getULEB128(Offset)); @@ -185,6 +186,7 @@ DECLARE_OP2(DW_CFA_def_cfa, OT_Register, OT_Offset); DECLARE_OP2(DW_CFA_def_cfa_sf, OT_Register, OT_SignedFactDataOffset); DECLARE_OP1(DW_CFA_def_cfa_register, OT_Register); + DECLARE_OP1(DW_CFA_LLVM_def_cfa_aspace, OT_AddressSpace); DECLARE_OP1(DW_CFA_def_cfa_offset, OT_Offset); DECLARE_OP1(DW_CFA_def_cfa_offset_sf, OT_SignedFactDataOffset); DECLARE_OP1(DW_CFA_def_cfa_expression, OT_Expression); @@ -263,6 +265,9 @@ case OT_Register: OS << format(" reg%" PRId64, Operand); break; + case OT_AddressSpace: + OS << format(" as%" PRId64, Operand); + break; case OT_Expression: assert(Instr.Expression && "missing DWARFExpression object"); OS << " "; diff --git a/llvm/lib/MC/MCAsmStreamer.cpp b/llvm/lib/MC/MCAsmStreamer.cpp --- a/llvm/lib/MC/MCAsmStreamer.cpp +++ b/llvm/lib/MC/MCAsmStreamer.cpp @@ -295,6 +295,7 @@ void emitCFIDefCfa(int64_t Register, int64_t Offset) override; void emitCFIDefCfaOffset(int64_t Offset) override; void emitCFIDefCfaRegister(int64_t Register) override; + void emitCFILLVMDefCfaAspace(int64_t Register) override; void emitCFIOffset(int64_t Register, int64_t Offset) override; void emitCFIPersonality(const MCSymbol *Sym, unsigned Encoding) override; void emitCFILsda(const MCSymbol *Sym, unsigned Encoding) override; @@ -1580,6 +1581,15 @@ EmitEOL(); } +void MCAsmStreamer::emitCFILLVMDefCfaAspace(int64_t AddressSpace) { + MCStreamer::emitCFILLVMDefCfaAspace(AddressSpace); + OS << "\t.cfi_llvm_def_cfa_aspace " << AddressSpace; + // FIXME: When going from ASM->ASM a lot of these directives seem to add too + // much whitespace; maybe something isn't consuming whitespace eagerly enough + // while parsing? + EmitEOL(); +} + static void PrintCFIEscape(llvm::formatted_raw_ostream &OS, StringRef Values) { OS << "\t.cfi_escape "; if (!Values.empty()) { diff --git a/llvm/lib/MC/MCDwarf.cpp b/llvm/lib/MC/MCDwarf.cpp --- a/llvm/lib/MC/MCDwarf.cpp +++ b/llvm/lib/MC/MCDwarf.cpp @@ -1424,6 +1424,13 @@ return; } + case MCCFIInstruction::OpLLVMDefCfaAspace: { + unsigned AddressSpace = Instr.getAddressSpace(); + Streamer.emitIntValue(dwarf::DW_CFA_LLVM_def_cfa_aspace, 1); + Streamer.emitULEB128IntValue(AddressSpace); + + return; + } case MCCFIInstruction::OpOffset: case MCCFIInstruction::OpRelOffset: { const bool IsRelative = diff --git a/llvm/lib/MC/MCParser/AsmParser.cpp b/llvm/lib/MC/MCParser/AsmParser.cpp --- a/llvm/lib/MC/MCParser/AsmParser.cpp +++ b/llvm/lib/MC/MCParser/AsmParser.cpp @@ -481,6 +481,7 @@ DK_CFI_DEF_CFA_OFFSET, DK_CFI_ADJUST_CFA_OFFSET, DK_CFI_DEF_CFA_REGISTER, + DK_CFI_LLVM_DEF_CFA_ASPACE, DK_CFI_OFFSET, DK_CFI_REL_OFFSET, DK_CFI_PERSONALITY, @@ -580,6 +581,7 @@ bool parseDirectiveCFIDefCfa(SMLoc DirectiveLoc); bool parseDirectiveCFIAdjustCfaOffset(); bool parseDirectiveCFIDefCfaRegister(SMLoc DirectiveLoc); + bool parseDirectiveCFILLVMDefCfaAspace(SMLoc DirectiveLoc); bool parseDirectiveCFIOffset(SMLoc DirectiveLoc); bool parseDirectiveCFIRelOffset(SMLoc DirectiveLoc); bool parseDirectiveCFIPersonalityOrLsda(bool IsPersonality); @@ -2100,6 +2102,8 @@ return parseDirectiveCFIAdjustCfaOffset(); case DK_CFI_DEF_CFA_REGISTER: return parseDirectiveCFIDefCfaRegister(IDLoc); + case DK_CFI_LLVM_DEF_CFA_ASPACE: + return parseDirectiveCFILLVMDefCfaAspace(IDLoc); case DK_CFI_OFFSET: return parseDirectiveCFIOffset(IDLoc); case DK_CFI_REL_OFFSET: @@ -4176,6 +4180,17 @@ return false; } +/// parseDirectiveCFILLVMDefCfaAspace +/// ::= .cfi_llvm_def_cfa_aspace address_space +bool AsmParser::parseDirectiveCFILLVMDefCfaAspace(SMLoc DirectiveLoc) { + int64_t AddressSpace = 0; + if (parseAbsoluteExpression(AddressSpace)) + return true; + + getStreamer().emitCFILLVMDefCfaAspace(AddressSpace); + return false; +} + /// parseDirectiveCFIOffset /// ::= .cfi_offset register, offset bool AsmParser::parseDirectiveCFIOffset(SMLoc DirectiveLoc) { @@ -5445,6 +5460,7 @@ DirectiveKindMap[".cfi_def_cfa_offset"] = DK_CFI_DEF_CFA_OFFSET; DirectiveKindMap[".cfi_adjust_cfa_offset"] = DK_CFI_ADJUST_CFA_OFFSET; DirectiveKindMap[".cfi_def_cfa_register"] = DK_CFI_DEF_CFA_REGISTER; + DirectiveKindMap[".cfi_llvm_def_cfa_aspace"] = DK_CFI_LLVM_DEF_CFA_ASPACE; DirectiveKindMap[".cfi_offset"] = DK_CFI_OFFSET; DirectiveKindMap[".cfi_rel_offset"] = DK_CFI_REL_OFFSET; DirectiveKindMap[".cfi_personality"] = DK_CFI_PERSONALITY; diff --git a/llvm/lib/MC/MCStreamer.cpp b/llvm/lib/MC/MCStreamer.cpp --- a/llvm/lib/MC/MCStreamer.cpp +++ b/llvm/lib/MC/MCStreamer.cpp @@ -502,6 +502,16 @@ CurFrame->CurrentCfaRegister = static_cast(Register); } +void MCStreamer::emitCFILLVMDefCfaAspace(int64_t AddressSpace) { + MCSymbol *Label = emitCFILabel(); + MCCFIInstruction Instruction = + MCCFIInstruction::createLLVMDefCfaAspace(Label, AddressSpace); + MCDwarfFrameInfo *CurFrame = getCurrentDwarfFrameInfo(); + if (!CurFrame) + return; + CurFrame->Instructions.push_back(Instruction); +} + void MCStreamer::emitCFIOffset(int64_t Register, int64_t Offset) { MCSymbol *Label = emitCFILabel(); MCCFIInstruction Instruction = diff --git a/llvm/test/CodeGen/MIR/AArch64/cfi.mir b/llvm/test/CodeGen/MIR/AArch64/cfi.mir --- a/llvm/test/CodeGen/MIR/AArch64/cfi.mir +++ b/llvm/test/CodeGen/MIR/AArch64/cfi.mir @@ -23,6 +23,8 @@ frame-setup CFI_INSTRUCTION def_cfa_register $w29 ; CHECK: CFI_INSTRUCTION def_cfa_offset -8 frame-setup CFI_INSTRUCTION def_cfa_offset -8 + ; CHECK: CFI_INSTRUCTION llvm_def_cfa_aspace 6 + frame-setup CFI_INSTRUCTION llvm_def_cfa_aspace 6 ; CHECK: CFI_INSTRUCTION offset $w30, -8 frame-setup CFI_INSTRUCTION offset $w30, -8 ; CHECK: CFI_INSTRUCTION rel_offset $w30, -8 diff --git a/llvm/test/MC/ELF/cfi-llvm-def-cfa-aspace.s b/llvm/test/MC/ELF/cfi-llvm-def-cfa-aspace.s new file mode 100644 --- /dev/null +++ b/llvm/test/MC/ELF/cfi-llvm-def-cfa-aspace.s @@ -0,0 +1,57 @@ +// RUN: llvm-mc -filetype=asm -triple x86_64-pc-linux-gnu %s -o - | FileCheck --check-prefix=ASM %s +// RUN: llvm-mc -filetype=obj -triple x86_64-pc-linux-gnu %s -o - | llvm-readobj -S --sr --sd | FileCheck --check-prefix=READOBJ %s + +f: + .cfi_startproc + nop + .cfi_llvm_def_cfa_aspace 6 + nop + .cfi_endproc + +// ASM: f: +// ASM-NEXT: .cfi_startproc +// ASM-NEXT: nop +// ASM-NEXT: .cfi_llvm_def_cfa_aspace 6 +// FIXME Why emit an extra empty line? +// ASM-EMPTY: +// ASM-NEXT: nop +// ASM-NEXT: .cfi_endproc + +// READOBJ: Section { +// READOBJ: Name: .eh_frame +// READOBJ-NEXT: Type: SHT_X86_64_UNWIND +// READOBJ-NEXT: Flags [ +// READOBJ-NEXT: SHF_ALLOC +// READOBJ-NEXT: ] +// READOBJ-NEXT: Address: 0x0 +// READOBJ-NEXT: Offset: 0x48 +// READOBJ-NEXT: Size: 48 +// READOBJ-NEXT: Link: 0 +// READOBJ-NEXT: Info: 0 +// READOBJ-NEXT: AddressAlignment: 8 +// READOBJ-NEXT: EntrySize: 0 +// READOBJ-NEXT: Relocations [ +// READOBJ-NEXT: ] +// READOBJ-NEXT: SectionData ( +// READOBJ-NEXT: 0000: 14000000 00000000 017A5200 01781001 +// READOBJ-NEXT: 0010: 1B0C0708 90010000 14000000 1C000000 +// READOBJ-NEXT: 0020: 00000000 02000000 00412F06 00000000 +// READOBJ-NEXT: ) +// READOBJ-NEXT: } + +// READOBJ: Section { +// READOBJ: Name: .rela.eh_frame +// READOBJ-NEXT: Type: SHT_RELA +// READOBJ-NEXT: Flags [ +// READOBJ-NEXT: ] +// READOBJ-NEXT: Address: 0x0 +// READOBJ-NEXT: Offset: +// READOBJ-NEXT: Size: 24 +// READOBJ-NEXT: Link: +// READOBJ-NEXT: Info: +// READOBJ-NEXT: AddressAlignment: 8 +// READOBJ-NEXT: EntrySize: 24 +// READOBJ-NEXT: Relocations [ +// READOBJ-NEXT: 0x20 R_X86_64_PC32 .text 0x0 +// READOBJ-NEXT: ] +// READOBJ: } diff --git a/llvm/test/tools/llvm-dwarfdump/X86/debug_frame_LLVM_def_cfa_aspace.s b/llvm/test/tools/llvm-dwarfdump/X86/debug_frame_LLVM_def_cfa_aspace.s new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-dwarfdump/X86/debug_frame_LLVM_def_cfa_aspace.s @@ -0,0 +1,15 @@ +# RUN: llvm-mc %s -filetype=obj -triple=i686-pc-linux -o %t +# RUN: llvm-dwarfdump -v %t | FileCheck %s + +# CHECK: .eh_frame contents: +# CHECK: FDE +# CHECK-NEXT: DW_CFA_LLVM_def_cfa_aspace: as6 +# CHECK-NEXT: DW_CFA_nop: + +.text +.globl foo +.type foo,@function +foo: + .cfi_startproc + .cfi_llvm_def_cfa_aspace 6 + .cfi_endproc