diff --git a/bolt/lib/Core/BinaryFunction.cpp b/bolt/lib/Core/BinaryFunction.cpp index c12217d549479..5da777411ba7a 100644 --- a/bolt/lib/Core/BinaryFunction.cpp +++ b/bolt/lib/Core/BinaryFunction.cpp @@ -2580,6 +2580,7 @@ struct CFISnapshot { case MCCFIInstruction::OpNegateRAStateWithPC: case MCCFIInstruction::OpLLVMDefAspaceCfa: case MCCFIInstruction::OpLabel: + case MCCFIInstruction::OpValOffset: llvm_unreachable("unsupported CFI opcode"); break; case MCCFIInstruction::OpRememberState: @@ -2719,6 +2720,7 @@ struct CFISnapshotDiff : public CFISnapshot { case MCCFIInstruction::OpNegateRAStateWithPC: case MCCFIInstruction::OpLLVMDefAspaceCfa: case MCCFIInstruction::OpLabel: + case MCCFIInstruction::OpValOffset: llvm_unreachable("unsupported CFI opcode"); return false; case MCCFIInstruction::OpRememberState: @@ -2869,6 +2871,7 @@ BinaryFunction::unwindCFIState(int32_t FromState, int32_t ToState, case MCCFIInstruction::OpNegateRAStateWithPC: case MCCFIInstruction::OpLLVMDefAspaceCfa: case MCCFIInstruction::OpLabel: + case MCCFIInstruction::OpValOffset: llvm_unreachable("unsupported CFI opcode"); break; case MCCFIInstruction::OpGnuArgsSize: diff --git a/llvm/include/llvm/MC/MCDwarf.h b/llvm/include/llvm/MC/MCDwarf.h index 1392336968e74..2fa7d73e1fa25 100644 --- a/llvm/include/llvm/MC/MCDwarf.h +++ b/llvm/include/llvm/MC/MCDwarf.h @@ -518,6 +518,7 @@ class MCCFIInstruction { OpNegateRAStateWithPC, OpGnuArgsSize, OpLabel, + OpValOffset, }; private: @@ -699,6 +700,13 @@ class MCCFIInstruction { return MCCFIInstruction(OpLabel, L, CfiLabel, Loc); } + /// .cfi_val_offset Previous value of Register is offset Offset from the + /// current CFA register. + static MCCFIInstruction createValOffset(MCSymbol *L, unsigned Register, + int64_t Offset, SMLoc Loc = {}) { + return MCCFIInstruction(OpValOffset, L, Register, Offset, Loc); + } + OpType getOperation() const { return Operation; } MCSymbol *getLabel() const { return Label; } @@ -710,7 +718,7 @@ class MCCFIInstruction { assert(Operation == OpDefCfa || Operation == OpOffset || Operation == OpRestore || Operation == OpUndefined || Operation == OpSameValue || Operation == OpDefCfaRegister || - Operation == OpRelOffset); + Operation == OpRelOffset || Operation == OpValOffset); return U.RI.Register; } @@ -729,7 +737,8 @@ class MCCFIInstruction { return U.RIA.Offset; assert(Operation == OpDefCfa || Operation == OpOffset || Operation == OpRelOffset || Operation == OpDefCfaOffset || - Operation == OpAdjustCfaOffset || Operation == OpGnuArgsSize); + Operation == OpAdjustCfaOffset || Operation == OpGnuArgsSize || + Operation == OpValOffset); return U.RI.Offset; } diff --git a/llvm/include/llvm/MC/MCStreamer.h b/llvm/include/llvm/MC/MCStreamer.h index df2eb9cf136bc..d12ab4257613a 100644 --- a/llvm/include/llvm/MC/MCStreamer.h +++ b/llvm/include/llvm/MC/MCStreamer.h @@ -1024,6 +1024,8 @@ class MCStreamer { virtual void emitCFINegateRAState(SMLoc Loc = {}); virtual void emitCFINegateRAStateWithPC(SMLoc Loc = {}); virtual void emitCFILabelDirective(SMLoc Loc, StringRef Name); + virtual void emitCFIValOffset(int64_t Register, int64_t Offset, + SMLoc Loc = {}); virtual void emitWinCFIStartProc(const MCSymbol *Symbol, SMLoc Loc = SMLoc()); virtual void emitWinCFIEndProc(SMLoc Loc = SMLoc()); diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinterDwarf.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinterDwarf.cpp index 4ca2cf02a2601..2a146eb15f709 100644 --- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinterDwarf.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinterDwarf.cpp @@ -260,6 +260,9 @@ void AsmPrinter::emitCFIInstruction(const MCCFIInstruction &Inst) const { case MCCFIInstruction::OpRestoreState: OutStreamer->emitCFIRestoreState(Loc); break; + case MCCFIInstruction::OpValOffset: + OutStreamer->emitCFIValOffset(Inst.getRegister(), Inst.getOffset(), Loc); + break; } } diff --git a/llvm/lib/CodeGen/CFIInstrInserter.cpp b/llvm/lib/CodeGen/CFIInstrInserter.cpp index 4217ec6a1cca8..be8393cd38674 100644 --- a/llvm/lib/CodeGen/CFIInstrInserter.cpp +++ b/llvm/lib/CodeGen/CFIInstrInserter.cpp @@ -263,6 +263,7 @@ void CFIInstrInserter::calculateOutgoingCFAInfo(MBBCFAInfo &MBBInfo) { case MCCFIInstruction::OpNegateRAStateWithPC: case MCCFIInstruction::OpGnuArgsSize: case MCCFIInstruction::OpLabel: + case MCCFIInstruction::OpValOffset: break; } if (CSRReg || CSROffset) { diff --git a/llvm/lib/MC/MCAsmStreamer.cpp b/llvm/lib/MC/MCAsmStreamer.cpp index 112a4b3f1e9cd..d48b384f21cbc 100644 --- a/llvm/lib/MC/MCAsmStreamer.cpp +++ b/llvm/lib/MC/MCAsmStreamer.cpp @@ -376,6 +376,7 @@ class MCAsmStreamer final : public MCStreamer { void emitCFINegateRAStateWithPC(SMLoc Loc) override; void emitCFIReturnColumn(int64_t Register) override; void emitCFILabelDirective(SMLoc Loc, StringRef Name) override; + void emitCFIValOffset(int64_t Register, int64_t Offset, SMLoc Loc) override; void emitWinCFIStartProc(const MCSymbol *Symbol, SMLoc Loc) override; void emitWinCFIEndProc(SMLoc Loc) override; @@ -2177,6 +2178,15 @@ void MCAsmStreamer::emitCFIMTETaggedFrame() { EmitEOL(); } +void MCAsmStreamer::emitCFIValOffset(int64_t Register, int64_t Offset, + SMLoc Loc) { + MCStreamer::emitCFIValOffset(Register, Offset, Loc); + OS << "\t.cfi_val_offset "; + EmitRegisterName(Register); + OS << ", " << Offset; + EmitEOL(); +} + void MCAsmStreamer::emitWinCFIStartProc(const MCSymbol *Symbol, SMLoc Loc) { MCStreamer::emitWinCFIStartProc(Symbol, Loc); diff --git a/llvm/lib/MC/MCDwarf.cpp b/llvm/lib/MC/MCDwarf.cpp index e058358fb8ad4..552822e1b1838 100644 --- a/llvm/lib/MC/MCDwarf.cpp +++ b/llvm/lib/MC/MCDwarf.cpp @@ -1503,6 +1503,25 @@ void FrameEmitterImpl::emitCFIInstruction(const MCCFIInstruction &Instr) { case MCCFIInstruction::OpLabel: Streamer.emitLabel(Instr.getCfiLabel(), Instr.getLoc()); return; + case MCCFIInstruction::OpValOffset: { + unsigned Reg = Instr.getRegister(); + if (!IsEH) + Reg = MRI->getDwarfRegNumFromDwarfEHRegNum(Reg); + + int Offset = Instr.getOffset(); + Offset = Offset / dataAlignmentFactor; + + if (Offset < 0) { + Streamer.emitInt8(dwarf::DW_CFA_val_offset_sf); + Streamer.emitULEB128IntValue(Reg); + Streamer.emitSLEB128IntValue(Offset); + } else { + Streamer.emitInt8(dwarf::DW_CFA_val_offset); + Streamer.emitULEB128IntValue(Reg); + Streamer.emitULEB128IntValue(Offset); + } + return; + } } llvm_unreachable("Unhandled case in switch"); } diff --git a/llvm/lib/MC/MCParser/AsmParser.cpp b/llvm/lib/MC/MCParser/AsmParser.cpp index ecccb228c8c38..505b905617837 100644 --- a/llvm/lib/MC/MCParser/AsmParser.cpp +++ b/llvm/lib/MC/MCParser/AsmParser.cpp @@ -523,6 +523,7 @@ class AsmParser : public MCAsmParser { DK_CFI_WINDOW_SAVE, DK_CFI_LABEL, DK_CFI_B_KEY_FRAME, + DK_CFI_VAL_OFFSET, DK_MACROS_ON, DK_MACROS_OFF, DK_ALTMACRO, @@ -626,6 +627,7 @@ class AsmParser : public MCAsmParser { bool parseDirectiveCFISignalFrame(SMLoc DirectiveLoc); bool parseDirectiveCFIUndefined(SMLoc DirectiveLoc); bool parseDirectiveCFILabel(SMLoc DirectiveLoc); + bool parseDirectiveCFIValOffset(SMLoc DirectiveLoc); // macro directives bool parseDirectivePurgeMacro(SMLoc DirectiveLoc); @@ -2232,6 +2234,8 @@ bool AsmParser::parseStatement(ParseStatementInfo &Info, return parseDirectiveCFIWindowSave(IDLoc); case DK_CFI_LABEL: return parseDirectiveCFILabel(IDLoc); + case DK_CFI_VAL_OFFSET: + return parseDirectiveCFIValOffset(IDLoc); case DK_MACROS_ON: case DK_MACROS_OFF: return parseDirectiveMacrosOnOff(IDVal); @@ -4531,6 +4535,20 @@ bool AsmParser::parseDirectiveCFILabel(SMLoc Loc) { return false; } +/// parseDirectiveCFIValOffset +/// ::= .cfi_val_offset register, offset +bool AsmParser::parseDirectiveCFIValOffset(SMLoc DirectiveLoc) { + int64_t Register = 0; + int64_t Offset = 0; + + if (parseRegisterOrRegisterNumber(Register, DirectiveLoc) || parseComma() || + parseAbsoluteExpression(Offset) || parseEOL()) + return true; + + getStreamer().emitCFIValOffset(Register, Offset, DirectiveLoc); + return false; +} + /// parseDirectiveAltmacro /// ::= .altmacro /// ::= .noaltmacro @@ -5603,6 +5621,7 @@ void AsmParser::initializeDirectiveKindMap() { DirectiveKindMap[".cfi_label"] = DK_CFI_LABEL; DirectiveKindMap[".cfi_b_key_frame"] = DK_CFI_B_KEY_FRAME; DirectiveKindMap[".cfi_mte_tagged_frame"] = DK_CFI_MTE_TAGGED_FRAME; + DirectiveKindMap[".cfi_val_offset"] = DK_CFI_VAL_OFFSET; DirectiveKindMap[".macros_on"] = DK_MACROS_ON; DirectiveKindMap[".macros_off"] = DK_MACROS_OFF; DirectiveKindMap[".macro"] = DK_MACRO; diff --git a/llvm/lib/MC/MCParser/MasmParser.cpp b/llvm/lib/MC/MCParser/MasmParser.cpp index a7f37d81f6409..9e947bab2a015 100644 --- a/llvm/lib/MC/MCParser/MasmParser.cpp +++ b/llvm/lib/MC/MCParser/MasmParser.cpp @@ -6750,6 +6750,7 @@ void MasmParser::initializeDirectiveKindMap() { // DirectiveKindMap[".cfi_register"] = DK_CFI_REGISTER; // DirectiveKindMap[".cfi_window_save"] = DK_CFI_WINDOW_SAVE; // DirectiveKindMap[".cfi_b_key_frame"] = DK_CFI_B_KEY_FRAME; + // DirectiveKindMap[".cfi_val_offset"] = DK_CFI_VAL_OFFSET; DirectiveKindMap["macro"] = DK_MACRO; DirectiveKindMap["exitm"] = DK_EXITM; DirectiveKindMap["endm"] = DK_ENDM; diff --git a/llvm/lib/MC/MCStreamer.cpp b/llvm/lib/MC/MCStreamer.cpp index 5474db1315f14..cfef318f502ab 100644 --- a/llvm/lib/MC/MCStreamer.cpp +++ b/llvm/lib/MC/MCStreamer.cpp @@ -712,6 +712,16 @@ void MCStreamer::emitCFILabelDirective(SMLoc Loc, StringRef Name) { F->Instructions.push_back(MCCFIInstruction::createLabel(Label, Sym, Loc)); } +void MCStreamer::emitCFIValOffset(int64_t Register, int64_t Offset, SMLoc Loc) { + MCSymbol *Label = emitCFILabel(); + MCCFIInstruction Instruction = + MCCFIInstruction::createValOffset(Label, Register, Offset, Loc); + MCDwarfFrameInfo *CurFrame = getCurrentDwarfFrameInfo(); + if (!CurFrame) + return; + CurFrame->Instructions.push_back(Instruction); +} + WinEH::FrameInfo *MCStreamer::EnsureValidWinFrameInfo(SMLoc Loc) { const MCAsmInfo *MAI = Context.getAsmInfo(); if (!MAI->usesWindowsCFI()) { diff --git a/llvm/test/MC/AArch64/cfi_val_offset.s b/llvm/test/MC/AArch64/cfi_val_offset.s new file mode 100644 index 0000000000000..e345030c661d6 --- /dev/null +++ b/llvm/test/MC/AArch64/cfi_val_offset.s @@ -0,0 +1,34 @@ +// RUN: llvm-mc -triple aarch64-- -o - %s | FileCheck %s +// RUN: llvm-mc -triple aarch64-- -filetype=obj -o - %s | llvm-dwarfdump --debug-frame - | FileCheck --check-prefix=DWARF %s + +// This test just confirms the .cfi_val_offset directive emits a val_offset() +// rule. It's not testing anything AArch64 specific, it just needs a targets +// registers to be able to use the directive. +example: +// CHECK: .cfi_startproc + .cfi_startproc + add wsp, wsp, 16 + .cfi_def_cfa wsp, -16 +// CHECK: .cfi_def_cfa wsp, -16 +// DWARF: DW_CFA_advance_loc: 4 to 0x4 +// DWARF: DW_CFA_def_cfa: WSP -16 + .cfi_val_offset wsp, 0 +// CHECK: .cfi_val_offset wsp, 0 +// DWARF: DW_CFA_val_offset: WSP 0 + nop + sub wsp, wsp, 16 + .cfi_def_cfa wsp, 0 +// CHECK: .cfi_def_cfa wsp, 0 +// DWARF: DW_CFA_advance_loc: 8 to 0xc +// DWARF: DW_CFA_def_cfa: WSP +0 + .cfi_register wsp, wsp +// CHECK: .cfi_register wsp, wsp +// DWARF: DW_CFA_register: WSP WSP + ret + .cfi_endproc +// CHECK: .cfi_endproc + + +// DWARF: 0x0: CFA=WSP +// DWARF: 0x4: CFA=WSP-16: WSP=CFA +// DWARF: 0xc: CFA=WSP: WSP=WSP