Skip to content

Commit bb72c5f

Browse files
author
Mikhail Gudim
committed
[MC][AsmPrinter] Introduce llvm_reg_offset pseudo cfi instruction.
Some targets which have scalable vectors (AArch64, RISCV) emit cfi escape expression of the form "deref(FrameReg + Offset)". Now instead of explicitly building up the expression, we can just emit the llvm_reg_offset. Also, we will need to handle such escape expressions in CFIInstrInserter. Without this pseudo, we would have to try to decode the escape expression inside the CFIInstrInserter. Now, when we have this pseudo, we can understand such escape expressions without decoding.
1 parent 67f59a6 commit bb72c5f

File tree

10 files changed

+145
-3
lines changed

10 files changed

+145
-3
lines changed

llvm/include/llvm/MC/MCDwarf.h

Lines changed: 40 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#define LLVM_MC_MCDWARF_H
1616

1717
#include "llvm/ADT/MapVector.h"
18+
#include "llvm/ADT/SmallString.h"
1819
#include "llvm/ADT/SmallVector.h"
1920
#include "llvm/ADT/StringMap.h"
2021
#include "llvm/ADT/StringRef.h"
@@ -504,6 +505,7 @@ class MCCFIInstruction {
504505
OpRestoreState,
505506
OpOffset,
506507
OpLLVMDefAspaceCfa,
508+
OpLLVMRegOffset,
507509
OpDefCfaRegister,
508510
OpDefCfaOffset,
509511
OpDefCfa,
@@ -537,6 +539,11 @@ class MCCFIInstruction {
537539
unsigned Register;
538540
unsigned Register2;
539541
} RR;
542+
struct {
543+
unsigned Register;
544+
unsigned Register2;
545+
int64_t Offset;
546+
} RRO;
540547
MCSymbol *CfiLabel;
541548
} U;
542549
OpType Operation;
@@ -569,6 +576,14 @@ class MCCFIInstruction {
569576
U.CfiLabel = CfiLabel;
570577
}
571578

579+
MCCFIInstruction(OpType Op, MCSymbol *L, unsigned R, unsigned R2, int64_t O,
580+
SMLoc Loc, StringRef V, StringRef Comment = "")
581+
: Label(L), Operation(Op), Loc(Loc), Values(V.begin(), V.end()),
582+
Comment(Comment) {
583+
assert(Op == OpLLVMRegOffset);
584+
U.RRO = {R, R2, O};
585+
}
586+
572587
public:
573588
/// .cfi_def_cfa defines a rule for computing CFA as: take address from
574589
/// Register and add Offset to it.
@@ -634,6 +649,22 @@ class MCCFIInstruction {
634649
return MCCFIInstruction(OpRegister, L, Register1, Register2, Loc);
635650
}
636651

652+
/// Create the expression (FrameRegister + Offset) and write it to CFAExpr
653+
static void createRegOffsetExpression(unsigned Reg, unsigned FrameReg,
654+
int64_t Offset,
655+
SmallString<64> &CFAExpr);
656+
/// This is a "pseudo CFI" instruction which generates the escape expression
657+
/// deref(FrameReg + Offset) for the register Reg.
658+
static MCCFIInstruction createLLVMRegOffset(MCSymbol *L, unsigned Reg,
659+
unsigned FrameReg, int64_t Offset,
660+
SMLoc Loc = {},
661+
StringRef Comment = "") {
662+
SmallString<64> CFAExpr;
663+
createRegOffsetExpression(Reg, FrameReg, Offset, CFAExpr);
664+
return MCCFIInstruction(OpLLVMRegOffset, L, Reg, FrameReg, Offset, Loc,
665+
CFAExpr, Comment);
666+
}
667+
637668
/// .cfi_window_save SPARC register window is saved.
638669
static MCCFIInstruction createWindowSave(MCSymbol *L, SMLoc Loc = {}) {
639670
return MCCFIInstruction(OpWindowSave, L, 0, INT64_C(0), Loc);
@@ -715,6 +746,8 @@ class MCCFIInstruction {
715746
return U.RR.Register;
716747
if (Operation == OpLLVMDefAspaceCfa)
717748
return U.RIA.Register;
749+
if (Operation == OpLLVMRegOffset)
750+
return U.RRO.Register;
718751
assert(Operation == OpDefCfa || Operation == OpOffset ||
719752
Operation == OpRestore || Operation == OpUndefined ||
720753
Operation == OpSameValue || Operation == OpDefCfaRegister ||
@@ -723,8 +756,10 @@ class MCCFIInstruction {
723756
}
724757

725758
unsigned getRegister2() const {
726-
assert(Operation == OpRegister);
727-
return U.RR.Register2;
759+
if (Operation == OpRegister)
760+
return U.RR.Register2;
761+
assert(Operation == OpLLVMRegOffset);
762+
return U.RRO.Register2;
728763
}
729764

730765
unsigned getAddressSpace() const {
@@ -735,6 +770,8 @@ class MCCFIInstruction {
735770
int64_t getOffset() const {
736771
if (Operation == OpLLVMDefAspaceCfa)
737772
return U.RIA.Offset;
773+
if (Operation == OpLLVMRegOffset)
774+
return U.RRO.Offset;
738775
assert(Operation == OpDefCfa || Operation == OpOffset ||
739776
Operation == OpRelOffset || Operation == OpDefCfaOffset ||
740777
Operation == OpAdjustCfaOffset || Operation == OpGnuArgsSize ||
@@ -748,7 +785,7 @@ class MCCFIInstruction {
748785
}
749786

750787
StringRef getValues() const {
751-
assert(Operation == OpEscape);
788+
assert(Operation == OpEscape || Operation == OpLLVMRegOffset);
752789
return StringRef(&Values[0], Values.size());
753790
}
754791

llvm/lib/CodeGen/AsmPrinter/AsmPrinterDwarf.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,10 @@ void AsmPrinter::emitCFIInstruction(const MCCFIInstruction &Inst) const {
223223
OutStreamer->emitCFILLVMDefAspaceCfa(Inst.getRegister(), Inst.getOffset(),
224224
Inst.getAddressSpace(), Loc);
225225
break;
226+
case MCCFIInstruction::OpLLVMRegOffset:
227+
OutStreamer->AddComment(Inst.getComment());
228+
OutStreamer->emitCFIEscape(Inst.getValues(), Loc);
229+
break;
226230
case MCCFIInstruction::OpOffset:
227231
OutStreamer->emitCFIOffset(Inst.getRegister(), Inst.getOffset(), Loc);
228232
break;

llvm/lib/CodeGen/CFIInstrInserter.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -265,6 +265,8 @@ void CFIInstrInserter::calculateOutgoingCFAInfo(MBBCFAInfo &MBBInfo) {
265265
case MCCFIInstruction::OpLabel:
266266
case MCCFIInstruction::OpValOffset:
267267
break;
268+
case MCCFIInstruction::OpLLVMRegOffset:
269+
llvm_unreachable("Can't handle llvm_reg_offset yet!");
268270
}
269271
if (CSRReg || CSROffset) {
270272
auto It = CSRLocMap.find(CFI.getRegister());

llvm/lib/CodeGen/MIRParser/MILexer.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,7 @@ static MIToken::TokenKind getIdentifierKind(StringRef Identifier) {
231231
.Case("escape", MIToken::kw_cfi_escape)
232232
.Case("def_cfa", MIToken::kw_cfi_def_cfa)
233233
.Case("llvm_def_aspace_cfa", MIToken::kw_cfi_llvm_def_aspace_cfa)
234+
.Case("llvm_reg_offset", MIToken::kw_cfi_llvm_reg_offset)
234235
.Case("remember_state", MIToken::kw_cfi_remember_state)
235236
.Case("restore", MIToken::kw_cfi_restore)
236237
.Case("restore_state", MIToken::kw_cfi_restore_state)

llvm/lib/CodeGen/MIRParser/MILexer.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ struct MIToken {
9090
kw_cfi_escape,
9191
kw_cfi_def_cfa,
9292
kw_cfi_llvm_def_aspace_cfa,
93+
kw_cfi_llvm_reg_offset,
9394
kw_cfi_register,
9495
kw_cfi_remember_state,
9596
kw_cfi_restore,

llvm/lib/CodeGen/MIRParser/MIParser.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2546,6 +2546,16 @@ bool MIParser::parseCFIOperand(MachineOperand &Dest) {
25462546
CFIIndex = MF.addFrameInst(MCCFIInstruction::createLLVMDefAspaceCfa(
25472547
nullptr, Reg, Offset, AddressSpace, SMLoc()));
25482548
break;
2549+
case MIToken::kw_cfi_llvm_reg_offset: {
2550+
Register FrameReg;
2551+
if (parseCFIRegister(Reg) || expectAndConsume(MIToken::comma) ||
2552+
parseCFIRegister(FrameReg) || expectAndConsume(MIToken::comma) ||
2553+
parseCFIOffset(Offset))
2554+
return true;
2555+
CFIIndex = MF.addFrameInst(
2556+
MCCFIInstruction::createLLVMRegOffset(nullptr, Reg, FrameReg, Offset));
2557+
break;
2558+
}
25492559
case MIToken::kw_cfi_remember_state:
25502560
CFIIndex = MF.addFrameInst(MCCFIInstruction::createRememberState(nullptr));
25512561
break;
@@ -2925,6 +2935,7 @@ bool MIParser::parseMachineOperand(const unsigned OpCode, const unsigned OpIdx,
29252935
case MIToken::kw_cfi_escape:
29262936
case MIToken::kw_cfi_def_cfa:
29272937
case MIToken::kw_cfi_llvm_def_aspace_cfa:
2938+
case MIToken::kw_cfi_llvm_reg_offset:
29282939
case MIToken::kw_cfi_register:
29292940
case MIToken::kw_cfi_remember_state:
29302941
case MIToken::kw_cfi_restore:

llvm/lib/CodeGen/MachineOperand.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -710,6 +710,15 @@ static void printCFI(raw_ostream &OS, const MCCFIInstruction &CFI,
710710
OS << ", " << CFI.getOffset();
711711
OS << ", " << CFI.getAddressSpace();
712712
break;
713+
case MCCFIInstruction::OpLLVMRegOffset:
714+
OS << "llvm_reg_offset ";
715+
if (MCSymbol *Label = CFI.getLabel())
716+
MachineOperand::printSymbol(OS, *Label);
717+
printCFIRegister(CFI.getRegister(), OS, TRI);
718+
OS << ", ";
719+
printCFIRegister(CFI.getRegister2(), OS, TRI);
720+
OS << ", " << CFI.getOffset();
721+
break;
713722
case MCCFIInstruction::OpRelOffset:
714723
OS << "rel_offset ";
715724
if (MCSymbol *Label = CFI.getLabel())

llvm/lib/MC/MCDwarf.cpp

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,45 @@
4141

4242
using namespace llvm;
4343

44+
void MCCFIInstruction::createRegOffsetExpression(unsigned Reg,
45+
unsigned FrameReg,
46+
int64_t Offset,
47+
SmallString<64> &CFAExpr) {
48+
// Below all the comments about specific CFI instructions and opcodes are
49+
// taken directly from DWARF Standard version 5.
50+
//
51+
// Encode the expression: (Offset + FrameReg) into Expr:
52+
SmallString<64> Expr;
53+
uint8_t Buffer[16];
54+
// Encode offset:
55+
Expr.push_back(dwarf::DW_OP_consts);
56+
// The single operand of the DW_OP_consts operation provides a signed
57+
// LEB128 integer constant
58+
Expr.append(Buffer, Buffer + encodeSLEB128(Offset, Buffer));
59+
// Encode FrameReg:
60+
Expr.push_back((uint8_t)dwarf::DW_OP_bregx);
61+
// The DW_OP_bregx operation provides the sum of two values specified by its
62+
// two operands. The first operand is a register number which is specified by
63+
// an unsigned LEB128 number. The second operand is a signed LEB128 offset.
64+
Expr.append(Buffer, Buffer + encodeULEB128(FrameReg, Buffer));
65+
Expr.push_back(0);
66+
// The DW_OP_plus operation pops the top two stack entries, adds them
67+
// together, and pushes the result.
68+
Expr.push_back((uint8_t)dwarf::DW_OP_plus);
69+
// Now pass the encoded Expr to DW_CFA_expression:
70+
//
71+
// The DW_CFA_expression instruction takes two operands: an unsigned
72+
// LEB128 value representing a register number, and a DW_FORM_block value
73+
// representing a DWARF expression
74+
CFAExpr.push_back(dwarf::DW_CFA_expression);
75+
CFAExpr.append(Buffer, Buffer + encodeULEB128(Reg, Buffer));
76+
// DW_FORM_block value is unsigned LEB128 length followed by the number of
77+
// bytes specified by the length
78+
CFAExpr.append(Buffer, Buffer + encodeULEB128(Expr.size(), Buffer));
79+
CFAExpr.append(Expr.str());
80+
return;
81+
}
82+
4483
MCSymbol *mcdwarf::emitListsTableHeaderStart(MCStreamer &S) {
4584
MCSymbol *Start = S.getContext().createTempSymbol("debug_list_header_start");
4685
MCSymbol *End = S.getContext().createTempSymbol("debug_list_header_end");
@@ -1518,6 +1557,8 @@ void FrameEmitterImpl::emitCFIInstruction(const MCCFIInstruction &Instr) {
15181557
}
15191558
return;
15201559
}
1560+
case MCCFIInstruction::OpLLVMRegOffset:
1561+
llvm_unreachable("Should emit llvm_reg_offset as escape");
15211562
}
15221563
llvm_unreachable("Unhandled case in switch");
15231564
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py UTC_ARGS: --version 5
2+
# RUN: llc -mtriple=riscv64 -run-pass none -o - %s \
3+
# RUN: | FileCheck %s
4+
5+
# This test ensures that the MIR parser parses the llvm_reg_offset cfi instruction correctly.
6+
7+
name: func
8+
body: |
9+
bb.0:
10+
; CHECK: CFI_INSTRUCTION llvm_reg_offset $x1, $x2, -42
11+
CFI_INSTRUCTION llvm_reg_offset $x1, $x2, -42
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# RUN: llc -mtriple=riscv64 -start-after=unpack-mi-bundles -o - %s \
2+
# RUN: | FileCheck %s
3+
4+
# Check that `llvm_reg_offset` generates an escape expression corresponding to `deref(FrameReg + Offset)`. See comments in `MCCFIInstruction::createRegOffsetExpression`.
5+
# DW_CFA_expression = 0x10
6+
# $x1 = 0x01 - the register to be defined
7+
# 0x06 - length of expression encoding the (FrameReg + Offset)
8+
# DW_OP_consts = 0x11
9+
# le128 signed encoding of -42 = 0x56
10+
# DW_OP_bregx = 0x92
11+
# $x2 = 0x02
12+
# the second argument of DW_OP_bregx = 0x0
13+
# DW_OP_plus = 0x92
14+
name: func
15+
body: |
16+
bb.0:
17+
CFI_INSTRUCTION llvm_reg_offset $x1, $x2, -42
18+
PseudoRET
19+
#CHECK-LABEL: func:
20+
#CHECK: .cfi_startproc
21+
#CHECK: .cfi_escape 0x10, 0x01, 0x06, 0x11, 0x56, 0x92, 0x02, 0x00, 0x22
22+
#CHECK: ret
23+
#CHECK: .Lfunc_end0:
24+
#CHECK: .size func, .Lfunc_end0-func
25+
#CHECK: .cfi_endproc

0 commit comments

Comments
 (0)