Skip to content

[mc] Add CFI directive to emit val_offset() rules #113971

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Nov 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions bolt/lib/Core/BinaryFunction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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:
Expand Down
13 changes: 11 additions & 2 deletions llvm/include/llvm/MC/MCDwarf.h
Original file line number Diff line number Diff line change
Expand Up @@ -518,6 +518,7 @@ class MCCFIInstruction {
OpNegateRAStateWithPC,
OpGnuArgsSize,
OpLabel,
OpValOffset,
};

private:
Expand Down Expand Up @@ -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; }

Expand All @@ -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;
}

Expand All @@ -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;
}

Expand Down
2 changes: 2 additions & 0 deletions llvm/include/llvm/MC/MCStreamer.h
Original file line number Diff line number Diff line change
Expand Up @@ -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());
Expand Down
3 changes: 3 additions & 0 deletions llvm/lib/CodeGen/AsmPrinter/AsmPrinterDwarf.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
}

Expand Down
1 change: 1 addition & 0 deletions llvm/lib/CodeGen/CFIInstrInserter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
10 changes: 10 additions & 0 deletions llvm/lib/MC/MCAsmStreamer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);

Expand Down
19 changes: 19 additions & 0 deletions llvm/lib/MC/MCDwarf.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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");
}
Expand Down
19 changes: 19 additions & 0 deletions llvm/lib/MC/MCParser/AsmParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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;
Expand Down
1 change: 1 addition & 0 deletions llvm/lib/MC/MCParser/MasmParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
10 changes: 10 additions & 0 deletions llvm/lib/MC/MCStreamer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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()) {
Expand Down
34 changes: 34 additions & 0 deletions llvm/test/MC/AArch64/cfi_val_offset.s
Original file line number Diff line number Diff line change
@@ -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
Loading