Skip to content

Commit 74003f1

Browse files
authored
[mc] Add CFI directive to emit val_offset() rules (#113971)
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.
1 parent b242ae3 commit 74003f1

File tree

11 files changed

+113
-2
lines changed

11 files changed

+113
-2
lines changed

bolt/lib/Core/BinaryFunction.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2580,6 +2580,7 @@ struct CFISnapshot {
25802580
case MCCFIInstruction::OpNegateRAStateWithPC:
25812581
case MCCFIInstruction::OpLLVMDefAspaceCfa:
25822582
case MCCFIInstruction::OpLabel:
2583+
case MCCFIInstruction::OpValOffset:
25832584
llvm_unreachable("unsupported CFI opcode");
25842585
break;
25852586
case MCCFIInstruction::OpRememberState:
@@ -2719,6 +2720,7 @@ struct CFISnapshotDiff : public CFISnapshot {
27192720
case MCCFIInstruction::OpNegateRAStateWithPC:
27202721
case MCCFIInstruction::OpLLVMDefAspaceCfa:
27212722
case MCCFIInstruction::OpLabel:
2723+
case MCCFIInstruction::OpValOffset:
27222724
llvm_unreachable("unsupported CFI opcode");
27232725
return false;
27242726
case MCCFIInstruction::OpRememberState:
@@ -2869,6 +2871,7 @@ BinaryFunction::unwindCFIState(int32_t FromState, int32_t ToState,
28692871
case MCCFIInstruction::OpNegateRAStateWithPC:
28702872
case MCCFIInstruction::OpLLVMDefAspaceCfa:
28712873
case MCCFIInstruction::OpLabel:
2874+
case MCCFIInstruction::OpValOffset:
28722875
llvm_unreachable("unsupported CFI opcode");
28732876
break;
28742877
case MCCFIInstruction::OpGnuArgsSize:

llvm/include/llvm/MC/MCDwarf.h

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -518,6 +518,7 @@ class MCCFIInstruction {
518518
OpNegateRAStateWithPC,
519519
OpGnuArgsSize,
520520
OpLabel,
521+
OpValOffset,
521522
};
522523

523524
private:
@@ -699,6 +700,13 @@ class MCCFIInstruction {
699700
return MCCFIInstruction(OpLabel, L, CfiLabel, Loc);
700701
}
701702

703+
/// .cfi_val_offset Previous value of Register is offset Offset from the
704+
/// current CFA register.
705+
static MCCFIInstruction createValOffset(MCSymbol *L, unsigned Register,
706+
int64_t Offset, SMLoc Loc = {}) {
707+
return MCCFIInstruction(OpValOffset, L, Register, Offset, Loc);
708+
}
709+
702710
OpType getOperation() const { return Operation; }
703711
MCSymbol *getLabel() const { return Label; }
704712

@@ -710,7 +718,7 @@ class MCCFIInstruction {
710718
assert(Operation == OpDefCfa || Operation == OpOffset ||
711719
Operation == OpRestore || Operation == OpUndefined ||
712720
Operation == OpSameValue || Operation == OpDefCfaRegister ||
713-
Operation == OpRelOffset);
721+
Operation == OpRelOffset || Operation == OpValOffset);
714722
return U.RI.Register;
715723
}
716724

@@ -729,7 +737,8 @@ class MCCFIInstruction {
729737
return U.RIA.Offset;
730738
assert(Operation == OpDefCfa || Operation == OpOffset ||
731739
Operation == OpRelOffset || Operation == OpDefCfaOffset ||
732-
Operation == OpAdjustCfaOffset || Operation == OpGnuArgsSize);
740+
Operation == OpAdjustCfaOffset || Operation == OpGnuArgsSize ||
741+
Operation == OpValOffset);
733742
return U.RI.Offset;
734743
}
735744

llvm/include/llvm/MC/MCStreamer.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1024,6 +1024,8 @@ class MCStreamer {
10241024
virtual void emitCFINegateRAState(SMLoc Loc = {});
10251025
virtual void emitCFINegateRAStateWithPC(SMLoc Loc = {});
10261026
virtual void emitCFILabelDirective(SMLoc Loc, StringRef Name);
1027+
virtual void emitCFIValOffset(int64_t Register, int64_t Offset,
1028+
SMLoc Loc = {});
10271029

10281030
virtual void emitWinCFIStartProc(const MCSymbol *Symbol, SMLoc Loc = SMLoc());
10291031
virtual void emitWinCFIEndProc(SMLoc Loc = SMLoc());

llvm/lib/CodeGen/AsmPrinter/AsmPrinterDwarf.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,9 @@ void AsmPrinter::emitCFIInstruction(const MCCFIInstruction &Inst) const {
260260
case MCCFIInstruction::OpRestoreState:
261261
OutStreamer->emitCFIRestoreState(Loc);
262262
break;
263+
case MCCFIInstruction::OpValOffset:
264+
OutStreamer->emitCFIValOffset(Inst.getRegister(), Inst.getOffset(), Loc);
265+
break;
263266
}
264267
}
265268

llvm/lib/CodeGen/CFIInstrInserter.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -263,6 +263,7 @@ void CFIInstrInserter::calculateOutgoingCFAInfo(MBBCFAInfo &MBBInfo) {
263263
case MCCFIInstruction::OpNegateRAStateWithPC:
264264
case MCCFIInstruction::OpGnuArgsSize:
265265
case MCCFIInstruction::OpLabel:
266+
case MCCFIInstruction::OpValOffset:
266267
break;
267268
}
268269
if (CSRReg || CSROffset) {

llvm/lib/MC/MCAsmStreamer.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -376,6 +376,7 @@ class MCAsmStreamer final : public MCStreamer {
376376
void emitCFINegateRAStateWithPC(SMLoc Loc) override;
377377
void emitCFIReturnColumn(int64_t Register) override;
378378
void emitCFILabelDirective(SMLoc Loc, StringRef Name) override;
379+
void emitCFIValOffset(int64_t Register, int64_t Offset, SMLoc Loc) override;
379380

380381
void emitWinCFIStartProc(const MCSymbol *Symbol, SMLoc Loc) override;
381382
void emitWinCFIEndProc(SMLoc Loc) override;
@@ -2177,6 +2178,15 @@ void MCAsmStreamer::emitCFIMTETaggedFrame() {
21772178
EmitEOL();
21782179
}
21792180

2181+
void MCAsmStreamer::emitCFIValOffset(int64_t Register, int64_t Offset,
2182+
SMLoc Loc) {
2183+
MCStreamer::emitCFIValOffset(Register, Offset, Loc);
2184+
OS << "\t.cfi_val_offset ";
2185+
EmitRegisterName(Register);
2186+
OS << ", " << Offset;
2187+
EmitEOL();
2188+
}
2189+
21802190
void MCAsmStreamer::emitWinCFIStartProc(const MCSymbol *Symbol, SMLoc Loc) {
21812191
MCStreamer::emitWinCFIStartProc(Symbol, Loc);
21822192

llvm/lib/MC/MCDwarf.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1503,6 +1503,25 @@ void FrameEmitterImpl::emitCFIInstruction(const MCCFIInstruction &Instr) {
15031503
case MCCFIInstruction::OpLabel:
15041504
Streamer.emitLabel(Instr.getCfiLabel(), Instr.getLoc());
15051505
return;
1506+
case MCCFIInstruction::OpValOffset: {
1507+
unsigned Reg = Instr.getRegister();
1508+
if (!IsEH)
1509+
Reg = MRI->getDwarfRegNumFromDwarfEHRegNum(Reg);
1510+
1511+
int Offset = Instr.getOffset();
1512+
Offset = Offset / dataAlignmentFactor;
1513+
1514+
if (Offset < 0) {
1515+
Streamer.emitInt8(dwarf::DW_CFA_val_offset_sf);
1516+
Streamer.emitULEB128IntValue(Reg);
1517+
Streamer.emitSLEB128IntValue(Offset);
1518+
} else {
1519+
Streamer.emitInt8(dwarf::DW_CFA_val_offset);
1520+
Streamer.emitULEB128IntValue(Reg);
1521+
Streamer.emitULEB128IntValue(Offset);
1522+
}
1523+
return;
1524+
}
15061525
}
15071526
llvm_unreachable("Unhandled case in switch");
15081527
}

llvm/lib/MC/MCParser/AsmParser.cpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -523,6 +523,7 @@ class AsmParser : public MCAsmParser {
523523
DK_CFI_WINDOW_SAVE,
524524
DK_CFI_LABEL,
525525
DK_CFI_B_KEY_FRAME,
526+
DK_CFI_VAL_OFFSET,
526527
DK_MACROS_ON,
527528
DK_MACROS_OFF,
528529
DK_ALTMACRO,
@@ -626,6 +627,7 @@ class AsmParser : public MCAsmParser {
626627
bool parseDirectiveCFISignalFrame(SMLoc DirectiveLoc);
627628
bool parseDirectiveCFIUndefined(SMLoc DirectiveLoc);
628629
bool parseDirectiveCFILabel(SMLoc DirectiveLoc);
630+
bool parseDirectiveCFIValOffset(SMLoc DirectiveLoc);
629631

630632
// macro directives
631633
bool parseDirectivePurgeMacro(SMLoc DirectiveLoc);
@@ -2232,6 +2234,8 @@ bool AsmParser::parseStatement(ParseStatementInfo &Info,
22322234
return parseDirectiveCFIWindowSave(IDLoc);
22332235
case DK_CFI_LABEL:
22342236
return parseDirectiveCFILabel(IDLoc);
2237+
case DK_CFI_VAL_OFFSET:
2238+
return parseDirectiveCFIValOffset(IDLoc);
22352239
case DK_MACROS_ON:
22362240
case DK_MACROS_OFF:
22372241
return parseDirectiveMacrosOnOff(IDVal);
@@ -4531,6 +4535,20 @@ bool AsmParser::parseDirectiveCFILabel(SMLoc Loc) {
45314535
return false;
45324536
}
45334537

4538+
/// parseDirectiveCFIValOffset
4539+
/// ::= .cfi_val_offset register, offset
4540+
bool AsmParser::parseDirectiveCFIValOffset(SMLoc DirectiveLoc) {
4541+
int64_t Register = 0;
4542+
int64_t Offset = 0;
4543+
4544+
if (parseRegisterOrRegisterNumber(Register, DirectiveLoc) || parseComma() ||
4545+
parseAbsoluteExpression(Offset) || parseEOL())
4546+
return true;
4547+
4548+
getStreamer().emitCFIValOffset(Register, Offset, DirectiveLoc);
4549+
return false;
4550+
}
4551+
45344552
/// parseDirectiveAltmacro
45354553
/// ::= .altmacro
45364554
/// ::= .noaltmacro
@@ -5603,6 +5621,7 @@ void AsmParser::initializeDirectiveKindMap() {
56035621
DirectiveKindMap[".cfi_label"] = DK_CFI_LABEL;
56045622
DirectiveKindMap[".cfi_b_key_frame"] = DK_CFI_B_KEY_FRAME;
56055623
DirectiveKindMap[".cfi_mte_tagged_frame"] = DK_CFI_MTE_TAGGED_FRAME;
5624+
DirectiveKindMap[".cfi_val_offset"] = DK_CFI_VAL_OFFSET;
56065625
DirectiveKindMap[".macros_on"] = DK_MACROS_ON;
56075626
DirectiveKindMap[".macros_off"] = DK_MACROS_OFF;
56085627
DirectiveKindMap[".macro"] = DK_MACRO;

llvm/lib/MC/MCParser/MasmParser.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6750,6 +6750,7 @@ void MasmParser::initializeDirectiveKindMap() {
67506750
// DirectiveKindMap[".cfi_register"] = DK_CFI_REGISTER;
67516751
// DirectiveKindMap[".cfi_window_save"] = DK_CFI_WINDOW_SAVE;
67526752
// DirectiveKindMap[".cfi_b_key_frame"] = DK_CFI_B_KEY_FRAME;
6753+
// DirectiveKindMap[".cfi_val_offset"] = DK_CFI_VAL_OFFSET;
67536754
DirectiveKindMap["macro"] = DK_MACRO;
67546755
DirectiveKindMap["exitm"] = DK_EXITM;
67556756
DirectiveKindMap["endm"] = DK_ENDM;

llvm/lib/MC/MCStreamer.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -712,6 +712,16 @@ void MCStreamer::emitCFILabelDirective(SMLoc Loc, StringRef Name) {
712712
F->Instructions.push_back(MCCFIInstruction::createLabel(Label, Sym, Loc));
713713
}
714714

715+
void MCStreamer::emitCFIValOffset(int64_t Register, int64_t Offset, SMLoc Loc) {
716+
MCSymbol *Label = emitCFILabel();
717+
MCCFIInstruction Instruction =
718+
MCCFIInstruction::createValOffset(Label, Register, Offset, Loc);
719+
MCDwarfFrameInfo *CurFrame = getCurrentDwarfFrameInfo();
720+
if (!CurFrame)
721+
return;
722+
CurFrame->Instructions.push_back(Instruction);
723+
}
724+
715725
WinEH::FrameInfo *MCStreamer::EnsureValidWinFrameInfo(SMLoc Loc) {
716726
const MCAsmInfo *MAI = Context.getAsmInfo();
717727
if (!MAI->usesWindowsCFI()) {

llvm/test/MC/AArch64/cfi_val_offset.s

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
// RUN: llvm-mc -triple aarch64-- -o - %s | FileCheck %s
2+
// RUN: llvm-mc -triple aarch64-- -filetype=obj -o - %s | llvm-dwarfdump --debug-frame - | FileCheck --check-prefix=DWARF %s
3+
4+
// This test just confirms the .cfi_val_offset directive emits a val_offset()
5+
// rule. It's not testing anything AArch64 specific, it just needs a targets
6+
// registers to be able to use the directive.
7+
example:
8+
// CHECK: .cfi_startproc
9+
.cfi_startproc
10+
add wsp, wsp, 16
11+
.cfi_def_cfa wsp, -16
12+
// CHECK: .cfi_def_cfa wsp, -16
13+
// DWARF: DW_CFA_advance_loc: 4 to 0x4
14+
// DWARF: DW_CFA_def_cfa: WSP -16
15+
.cfi_val_offset wsp, 0
16+
// CHECK: .cfi_val_offset wsp, 0
17+
// DWARF: DW_CFA_val_offset: WSP 0
18+
nop
19+
sub wsp, wsp, 16
20+
.cfi_def_cfa wsp, 0
21+
// CHECK: .cfi_def_cfa wsp, 0
22+
// DWARF: DW_CFA_advance_loc: 8 to 0xc
23+
// DWARF: DW_CFA_def_cfa: WSP +0
24+
.cfi_register wsp, wsp
25+
// CHECK: .cfi_register wsp, wsp
26+
// DWARF: DW_CFA_register: WSP WSP
27+
ret
28+
.cfi_endproc
29+
// CHECK: .cfi_endproc
30+
31+
32+
// DWARF: 0x0: CFA=WSP
33+
// DWARF: 0x4: CFA=WSP-16: WSP=CFA
34+
// DWARF: 0xc: CFA=WSP: WSP=WSP

0 commit comments

Comments
 (0)