[llvm] [mc] Add CFI directive to emit val_offset() rules (PR #113971)
via llvm-commits
llvm-commits at lists.llvm.org
Mon Oct 28 15:18:36 PDT 2024
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-backend-aarch64
Author: Daniel Sanders (dsandersllvm)
<details>
<summary>Changes</summary>
These specify that the value of the given register in the previous frame is the CFA plus some offset. This isn't very common but can be necessary if the original value is normally reconstructed from the stack/frame pointer instead of being saved on the stack and reloaded from there.
---
Full diff: https://github.com/llvm/llvm-project/pull/113971.diff
11 Files Affected:
- (modified) bolt/lib/Core/BinaryFunction.cpp (+3)
- (modified) llvm/include/llvm/MC/MCDwarf.h (+11-2)
- (modified) llvm/include/llvm/MC/MCStreamer.h (+2)
- (modified) llvm/lib/CodeGen/AsmPrinter/AsmPrinterDwarf.cpp (+3)
- (modified) llvm/lib/CodeGen/CFIInstrInserter.cpp (+1)
- (modified) llvm/lib/MC/MCAsmStreamer.cpp (+10)
- (modified) llvm/lib/MC/MCDwarf.cpp (+19)
- (modified) llvm/lib/MC/MCParser/AsmParser.cpp (+19)
- (modified) llvm/lib/MC/MCParser/MasmParser.cpp (+1)
- (modified) llvm/lib/MC/MCStreamer.cpp (+10)
- (added) llvm/test/MC/AArch64/cfi_val_offset.s (+34)
``````````diff
diff --git a/bolt/lib/Core/BinaryFunction.cpp b/bolt/lib/Core/BinaryFunction.cpp
index ef3fba37817daa..4a35e6cc755487 100644
--- a/bolt/lib/Core/BinaryFunction.cpp
+++ b/bolt/lib/Core/BinaryFunction.cpp
@@ -2579,6 +2579,7 @@ struct CFISnapshot {
case MCCFIInstruction::OpNegateRAState:
case MCCFIInstruction::OpLLVMDefAspaceCfa:
case MCCFIInstruction::OpLabel:
+ case MCCFIInstruction::OpValOffset:
llvm_unreachable("unsupported CFI opcode");
break;
case MCCFIInstruction::OpRememberState:
@@ -2717,6 +2718,7 @@ struct CFISnapshotDiff : public CFISnapshot {
case MCCFIInstruction::OpNegateRAState:
case MCCFIInstruction::OpLLVMDefAspaceCfa:
case MCCFIInstruction::OpLabel:
+ case MCCFIInstruction::OpValOffset:
llvm_unreachable("unsupported CFI opcode");
return false;
case MCCFIInstruction::OpRememberState:
@@ -2866,6 +2868,7 @@ BinaryFunction::unwindCFIState(int32_t FromState, int32_t ToState,
case MCCFIInstruction::OpNegateRAState:
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 1392336968e74a..2fa7d73e1fa25a 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 a376ba810ba515..3fc1e92083d31e 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 daad82d26da652..c9e67caac8710e 100644
--- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinterDwarf.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinterDwarf.cpp
@@ -261,6 +261,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 4217ec6a1cca8a..be8393cd386746 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 b9ad0b4eac9c7b..ce9a5ff3ca39fb 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 e058358fb8ad4b..552822e1b1838b 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 4774e5112af535..b9ccc4e238469e 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 d88fd09a1aa07c..46fb5e1e457f8c 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 5474db1315f141..cfef318f502abc 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 00000000000000..e345030c661d6f
--- /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
``````````
</details>
https://github.com/llvm/llvm-project/pull/113971
More information about the llvm-commits
mailing list