[llvm-branch-commits] [llvm] Users/ppenzin/ra saverestore offsets (PR #170607)
Petr Penzin via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Wed Dec 3 22:14:58 PST 2025
https://github.com/ppenzin created https://github.com/llvm/llvm-project/pull/170607
Support scalable offsets in CFI.
This has been split out from https://github.com/mgudim/llvm-project/tree/save_csr_in_ra3, and is PR 2 out of 5.
Co-authored-by: Mikhail Gudim <mgudim at ventanamicro.com>
>From f621b6515740a279d51fc4ced44967b103987d13 Mon Sep 17 00:00:00 2001
From: Mikhail Gudim <mgudim at ventanamicro.com>
Date: Mon, 25 Aug 2025 12:50:34 -0700
Subject: [PATCH 1/3] Support scalable offset in CFI.
Currently, targets with scalable vectors (AArch64, RISCV) handle
scalable offsets in cfi using cfi_escape expression. The problem is that
CFIInstrInserter doesn't understand these expressions.
We define new "pseudo" cfi instructions to support scalable offsets in
CFI:
(1) llvm_def_cfa_reg_scalable_offset - creates the new rule for calculating
cfa: `deref(Reg + ScalableOffset * x + FixedOffset)` where `x` is the
"scale" runtime constant.
(2) llvm_reg_at_scalable_offset_from_cfa - creates the new rule to calculate
previoius value of register `deref(cfa + ScalableOffset * x +
FixedOffset)` where `x` is the "scale" runtime constant.
(3) llvm_reg_at_scalable_offset_from_reg - creates the new rule to calculate previous value
of register `deref(Reg2 + ScalableOffset * x +
FixedOffset)`. This rule is to be used when
offset from cfa is not known, but intead fixed offset from `Reg2` is
known.
All of these cfi_instructions will be "lowered" to escape expressions
during final assembly emission. But during `CFIInstrInserter` these are
not lowered yet, so their semantics can be understood without decoding
cfi expressions. Since (1) and (2) depend on how target calculates
scalable offsets, their lowering is target-dependent.
---
llvm/include/llvm/MC/MCDwarf.h | 94 +++++++++++++++-
llvm/include/llvm/MC/MCStreamer.h | 19 ++++
.../CodeGen/AsmPrinter/AsmPrinterDwarf.cpp | 18 +++
llvm/lib/CodeGen/CFIInstrInserter.cpp | 8 +-
llvm/lib/CodeGen/MIRParser/MILexer.cpp | 6 +
llvm/lib/CodeGen/MIRParser/MILexer.h | 3 +
llvm/lib/CodeGen/MIRParser/MIParser.cpp | 41 +++++++
llvm/lib/CodeGen/MachineOperand.cpp | 26 +++++
llvm/lib/MC/MCDwarf.cpp | 4 +
.../MCTargetDesc/RISCVTargetStreamer.cpp | 103 +++++++++++++++++-
.../RISCV/MCTargetDesc/RISCVTargetStreamer.h | 17 +++
llvm/lib/Target/RISCV/RISCVFrameLowering.cpp | 80 ++++----------
.../cfi-llvm-def-cfa-reg-scalable-offset.mir | 11 ++
...i-llvm-reg-at-scalable-offset-from-cfa.mir | 11 ++
...i-llvm-reg-at-scalable-offset-from-reg.mir | 11 ++
.../cfi-llvm-def-cfa-reg-scalable-offset.mir | 33 ++++++
...i-llvm-reg-at-scalable-offset-from-cfa.mir | 34 ++++++
...i-llvm-reg-at-scalable-offset-from-reg.mir | 36 ++++++
.../CodeGen/RISCV/rvv/get-vlen-debugloc.mir | 2 +-
.../rvv/wrong-stack-offset-for-rvv-object.mir | 8 +-
llvm/test/CodeGen/RISCV/rvv/zvlsseg-spill.mir | 2 +-
21 files changed, 498 insertions(+), 69 deletions(-)
create mode 100644 llvm/test/CodeGen/MIR/RISCV/cfi-llvm-def-cfa-reg-scalable-offset.mir
create mode 100644 llvm/test/CodeGen/MIR/RISCV/cfi-llvm-reg-at-scalable-offset-from-cfa.mir
create mode 100644 llvm/test/CodeGen/MIR/RISCV/cfi-llvm-reg-at-scalable-offset-from-reg.mir
create mode 100644 llvm/test/CodeGen/RISCV/cfi-llvm-def-cfa-reg-scalable-offset.mir
create mode 100644 llvm/test/CodeGen/RISCV/cfi-llvm-reg-at-scalable-offset-from-cfa.mir
create mode 100644 llvm/test/CodeGen/RISCV/cfi-llvm-reg-at-scalable-offset-from-reg.mir
diff --git a/llvm/include/llvm/MC/MCDwarf.h b/llvm/include/llvm/MC/MCDwarf.h
index 9944a9a92ab1f..8a46ac64cdc87 100644
--- a/llvm/include/llvm/MC/MCDwarf.h
+++ b/llvm/include/llvm/MC/MCDwarf.h
@@ -15,6 +15,7 @@
#define LLVM_MC_MCDWARF_H
#include "llvm/ADT/MapVector.h"
+#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringRef.h"
@@ -514,6 +515,9 @@ class MCCFIInstruction {
OpRestoreState,
OpOffset,
OpLLVMDefAspaceCfa,
+ OpLLVMDefCfaRegScalableOffset,
+ OpLLVMRegAtScalableOffsetFromCfa,
+ OpLLVMRegAtScalableOffsetFromReg,
OpDefCfaRegister,
OpDefCfaOffset,
OpDefCfa,
@@ -547,6 +551,17 @@ class MCCFIInstruction {
unsigned Register;
unsigned Register2;
} RR;
+ struct {
+ unsigned Register;
+ int64_t ScalableOffset;
+ int64_t FixedOffset;
+ } ROO;
+ struct {
+ unsigned Register;
+ unsigned Register2;
+ int64_t ScalableOffset;
+ int64_t FixedOffset;
+ } RROO;
MCSymbol *CfiLabel;
} U;
OpType Operation;
@@ -579,6 +594,22 @@ class MCCFIInstruction {
U.CfiLabel = CfiLabel;
}
+ MCCFIInstruction(OpType Op, MCSymbol *L, unsigned R, int64_t ScalableOffset,
+ int64_t FixedOffset, SMLoc Loc, StringRef Comment = "")
+ : Label(L), Operation(Op), Loc(Loc), Comment(Comment) {
+ assert(Operation == OpLLVMDefCfaRegScalableOffset ||
+ Operation == OpLLVMRegAtScalableOffsetFromCfa);
+ U.ROO = {R, ScalableOffset, FixedOffset};
+ }
+
+ MCCFIInstruction(OpType Op, MCSymbol *L, unsigned R, unsigned R2,
+ int64_t ScalableOffset, int64_t FixedOffset, SMLoc Loc,
+ StringRef Comment = "")
+ : Label(L), Operation(Op), Loc(Loc), Comment(Comment) {
+ assert(Op == OpLLVMRegAtScalableOffsetFromReg);
+ U.RROO = {R, R2, ScalableOffset, FixedOffset};
+ }
+
public:
/// .cfi_def_cfa defines a rule for computing CFA as: take address from
/// Register and add Offset to it.
@@ -644,6 +675,41 @@ class MCCFIInstruction {
return MCCFIInstruction(OpRegister, L, Register1, Register2, Loc);
}
+ /// Create the new rule for calculating cfa: deref(Reg + ScalableOffset * x +
+ /// FixedOffset) where x is the runtime constant. This is a "pseudo" CFI
+ /// instruction - each target has to lower it into standard cfi directives.
+ static MCCFIInstruction
+ createLLVMDefCfaRegScalableOffset(MCSymbol *L, unsigned Reg,
+ int64_t ScalableOffset, int64_t FixedOffset,
+ SMLoc Loc = {}, StringRef Comment = "") {
+ return MCCFIInstruction(OpLLVMDefCfaRegScalableOffset, L, Reg,
+ ScalableOffset, FixedOffset, Loc, Comment);
+ }
+
+ /// Create the new rule for calculating the previous value (before the call)
+ /// of callee-saved register Reg: deref(cfa + ScalableOffset * x +
+ /// FixedOffset) where x is the runtime constant. This is a "pseudo" CFI
+ /// instruction - each target has to lower it into standard cfi directives.
+ static MCCFIInstruction createLLVMRegAtScalableOffsetFromCfa(
+ MCSymbol *L, unsigned Reg, int64_t ScalableOffset, int64_t FixedOffset,
+ SMLoc Loc = {}, StringRef Comment = "") {
+ return MCCFIInstruction(OpLLVMRegAtScalableOffsetFromCfa, L, Reg,
+ ScalableOffset, FixedOffset, Loc, Comment);
+ }
+
+ static MCCFIInstruction createLLVMRegAtScalableOffsetFromReg(
+ MCSymbol *L, unsigned Reg, unsigned Reg2, int64_t ScalableOffset,
+ int64_t FixedOffset, SMLoc Loc = {}, StringRef Comment = "") {
+ return MCCFIInstruction(OpLLVMRegAtScalableOffsetFromReg, L, Reg, Reg2,
+ ScalableOffset, FixedOffset, Loc, Comment);
+ }
+
+ /// Create the expression (FrameRegister + Offset) and write it to CFAExpr
+ static void createRegOffsetExpression(unsigned Reg, unsigned FrameReg,
+ int64_t ScalableOffset,
+ int64_t FixedOffset,
+ SmallString<64> &CFAExpr);
+
/// .cfi_window_save SPARC register window is saved.
static MCCFIInstruction createWindowSave(MCSymbol *L, SMLoc Loc = {}) {
return MCCFIInstruction(OpWindowSave, L, 0, INT64_C(0), Loc);
@@ -725,6 +791,10 @@ class MCCFIInstruction {
return U.RR.Register;
if (Operation == OpLLVMDefAspaceCfa)
return U.RIA.Register;
+ if (Operation == OpLLVMRegAtScalableOffsetFromCfa)
+ return U.ROO.Register;
+ if (Operation == OpLLVMRegAtScalableOffsetFromReg)
+ return U.RROO.Register;
assert(Operation == OpDefCfa || Operation == OpOffset ||
Operation == OpRestore || Operation == OpUndefined ||
Operation == OpSameValue || Operation == OpDefCfaRegister ||
@@ -733,8 +803,12 @@ class MCCFIInstruction {
}
unsigned getRegister2() const {
- assert(Operation == OpRegister);
- return U.RR.Register2;
+ if (Operation == OpRegister)
+ return U.RR.Register2;
+ if (Operation == OpLLVMDefCfaRegScalableOffset)
+ return U.ROO.Register;
+ assert(Operation == OpLLVMRegAtScalableOffsetFromReg);
+ return U.RROO.Register2;
}
unsigned getAddressSpace() const {
@@ -752,6 +826,22 @@ class MCCFIInstruction {
return U.RI.Offset;
}
+ int64_t getScalableOffset() const {
+ if (Operation == OpLLVMRegAtScalableOffsetFromReg)
+ return U.RROO.ScalableOffset;
+ assert(Operation == OpLLVMDefCfaRegScalableOffset ||
+ Operation == OpLLVMRegAtScalableOffsetFromCfa);
+ return U.ROO.ScalableOffset;
+ }
+
+ int64_t getFixedOffset() const {
+ if (Operation == OpLLVMRegAtScalableOffsetFromReg)
+ return U.RROO.FixedOffset;
+ assert(Operation == OpLLVMDefCfaRegScalableOffset ||
+ Operation == OpLLVMRegAtScalableOffsetFromCfa);
+ return U.ROO.FixedOffset;
+ }
+
MCSymbol *getCfiLabel() const {
assert(Operation == OpLabel);
return U.CfiLabel;
diff --git a/llvm/include/llvm/MC/MCStreamer.h b/llvm/include/llvm/MC/MCStreamer.h
index 79c715e3820a6..3429c2988423c 100644
--- a/llvm/include/llvm/MC/MCStreamer.h
+++ b/llvm/include/llvm/MC/MCStreamer.h
@@ -101,6 +101,25 @@ class LLVM_ABI MCTargetStreamer {
MCStreamer &getStreamer() { return Streamer; }
MCContext &getContext();
+ virtual void emitCFILLVMDefCfaRegScalableOffset(unsigned Register,
+ int64_t ScalableOffset,
+ int64_t FixedOffset,
+ SMLoc Loc = {}) {
+ llvm_unreachable("Not implemented!");
+ }
+ virtual void emitCFILLVMRegAtScalableOffsetFromCfa(unsigned Register,
+ int64_t ScalableOffset,
+ int64_t FixedOffset,
+ SMLoc Loc = {}) {
+ llvm_unreachable("Not implemented!");
+ }
+ virtual void emitCFILLVMRegAtScalableOffsetFromReg(unsigned Register,
+ unsigned Register2,
+ int64_t ScalableOffset,
+ int64_t FixedOffset,
+ SMLoc Loc = {}) {
+ llvm_unreachable("Not implemented!");
+ }
// Allow a target to add behavior to the EmitLabel of MCStreamer.
virtual void emitLabel(MCSymbol *Symbol);
// Allow a target to add behavior to the emitAssignment of MCStreamer.
diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinterDwarf.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinterDwarf.cpp
index 2a146eb15f709..55cd47daffd84 100644
--- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinterDwarf.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinterDwarf.cpp
@@ -223,6 +223,24 @@ void AsmPrinter::emitCFIInstruction(const MCCFIInstruction &Inst) const {
OutStreamer->emitCFILLVMDefAspaceCfa(Inst.getRegister(), Inst.getOffset(),
Inst.getAddressSpace(), Loc);
break;
+ case MCCFIInstruction::OpLLVMDefCfaRegScalableOffset:
+ OutStreamer->AddComment(Inst.getComment());
+ OutStreamer->getTargetStreamer()->emitCFILLVMDefCfaRegScalableOffset(
+ Inst.getRegister2(), Inst.getScalableOffset(), Inst.getFixedOffset(),
+ Loc);
+ break;
+ case MCCFIInstruction::OpLLVMRegAtScalableOffsetFromCfa:
+ OutStreamer->AddComment(Inst.getComment());
+ OutStreamer->getTargetStreamer()->emitCFILLVMRegAtScalableOffsetFromCfa(
+ Inst.getRegister(), Inst.getScalableOffset(), Inst.getFixedOffset(),
+ Loc);
+ break;
+ case MCCFIInstruction::OpLLVMRegAtScalableOffsetFromReg:
+ OutStreamer->AddComment(Inst.getComment());
+ OutStreamer->getTargetStreamer()->emitCFILLVMRegAtScalableOffsetFromReg(
+ Inst.getRegister(), Inst.getRegister2(), Inst.getScalableOffset(),
+ Inst.getFixedOffset(), Loc);
+ break;
case MCCFIInstruction::OpOffset:
OutStreamer->emitCFIOffset(Inst.getRegister(), Inst.getOffset(), Loc);
break;
diff --git a/llvm/lib/CodeGen/CFIInstrInserter.cpp b/llvm/lib/CodeGen/CFIInstrInserter.cpp
index 667928304df50..5d2ca15c2e12e 100644
--- a/llvm/lib/CodeGen/CFIInstrInserter.cpp
+++ b/llvm/lib/CodeGen/CFIInstrInserter.cpp
@@ -83,9 +83,11 @@ class CFIInstrInserter : public MachineFunctionPass {
int64_t Offset;
bool isValid() const { return K != Kind::INVALID; }
bool operator==(const CSRSavedLocation &RHS) const {
+ if (K != RHS.K)
+ return false;
switch (K) {
case Kind::INVALID:
- return !RHS.isValid();
+ return true;
case Kind::REGISTER:
return Reg == RHS.Reg;
case Kind::CFA_OFFSET:
@@ -323,6 +325,10 @@ void CFIInstrInserter::calculateOutgoingCFAInfo(MBBCFAInfo &MBBInfo) {
case MCCFIInstruction::OpLabel:
case MCCFIInstruction::OpValOffset:
break;
+ case MCCFIInstruction::OpLLVMDefCfaRegScalableOffset:
+ case MCCFIInstruction::OpLLVMRegAtScalableOffsetFromCfa:
+ case MCCFIInstruction::OpLLVMRegAtScalableOffsetFromReg:
+ llvm_unreachable("not implemented");
}
}
}
diff --git a/llvm/lib/CodeGen/MIRParser/MILexer.cpp b/llvm/lib/CodeGen/MIRParser/MILexer.cpp
index dbd56c7414f38..1f4c39bcc8e00 100644
--- a/llvm/lib/CodeGen/MIRParser/MILexer.cpp
+++ b/llvm/lib/CodeGen/MIRParser/MILexer.cpp
@@ -232,6 +232,12 @@ static MIToken::TokenKind getIdentifierKind(StringRef Identifier) {
.Case("escape", MIToken::kw_cfi_escape)
.Case("def_cfa", MIToken::kw_cfi_def_cfa)
.Case("llvm_def_aspace_cfa", MIToken::kw_cfi_llvm_def_aspace_cfa)
+ .Case("llvm_def_cfa_reg_scalable_offset",
+ MIToken::kw_cfi_llvm_def_cfa_reg_scalable_offset)
+ .Case("llvm_reg_at_scalable_offset_from_cfa",
+ MIToken::kw_cfi_llvm_reg_at_scalable_offset_from_cfa)
+ .Case("llvm_reg_at_scalable_offset_from_reg",
+ MIToken::kw_cfi_llvm_reg_at_scalable_offset_from_reg)
.Case("remember_state", MIToken::kw_cfi_remember_state)
.Case("restore", MIToken::kw_cfi_restore)
.Case("restore_state", MIToken::kw_cfi_restore_state)
diff --git a/llvm/lib/CodeGen/MIRParser/MILexer.h b/llvm/lib/CodeGen/MIRParser/MILexer.h
index 0407a0e7540d7..9b74bbe9012fd 100644
--- a/llvm/lib/CodeGen/MIRParser/MILexer.h
+++ b/llvm/lib/CodeGen/MIRParser/MILexer.h
@@ -91,6 +91,9 @@ struct MIToken {
kw_cfi_escape,
kw_cfi_def_cfa,
kw_cfi_llvm_def_aspace_cfa,
+ kw_cfi_llvm_def_cfa_reg_scalable_offset,
+ kw_cfi_llvm_reg_at_scalable_offset_from_cfa,
+ kw_cfi_llvm_reg_at_scalable_offset_from_reg,
kw_cfi_register,
kw_cfi_remember_state,
kw_cfi_restore,
diff --git a/llvm/lib/CodeGen/MIRParser/MIParser.cpp b/llvm/lib/CodeGen/MIRParser/MIParser.cpp
index f35274d4e2edf..da79f6b328f6e 100644
--- a/llvm/lib/CodeGen/MIRParser/MIParser.cpp
+++ b/llvm/lib/CodeGen/MIRParser/MIParser.cpp
@@ -2589,6 +2589,44 @@ bool MIParser::parseCFIOperand(MachineOperand &Dest) {
CFIIndex = MF.addFrameInst(MCCFIInstruction::createLLVMDefAspaceCfa(
nullptr, Reg, Offset, AddressSpace, SMLoc()));
break;
+ case MIToken::kw_cfi_llvm_def_cfa_reg_scalable_offset: {
+ int ScalableOffset;
+ int FixedOffset;
+ if (parseCFIRegister(Reg) || expectAndConsume(MIToken::comma) ||
+ parseCFIOffset(ScalableOffset) || expectAndConsume(MIToken::comma) ||
+ parseCFIOffset(FixedOffset))
+ return true;
+ CFIIndex =
+ MF.addFrameInst(MCCFIInstruction::createLLVMDefCfaRegScalableOffset(
+ nullptr, Reg, ScalableOffset, FixedOffset));
+ break;
+ }
+ case MIToken::kw_cfi_llvm_reg_at_scalable_offset_from_cfa: {
+ int ScalableOffset;
+ int FixedOffset;
+ if (parseCFIRegister(Reg) || expectAndConsume(MIToken::comma) ||
+ parseCFIOffset(ScalableOffset) || expectAndConsume(MIToken::comma) ||
+ parseCFIOffset(FixedOffset))
+ return true;
+ CFIIndex =
+ MF.addFrameInst(MCCFIInstruction::createLLVMRegAtScalableOffsetFromCfa(
+ nullptr, Reg, ScalableOffset, FixedOffset));
+ break;
+ }
+ case MIToken::kw_cfi_llvm_reg_at_scalable_offset_from_reg: {
+ unsigned FrameReg;
+ int ScalableOffset;
+ int FixedOffset;
+ if (parseCFIRegister(Reg) || expectAndConsume(MIToken::comma) ||
+ parseCFIRegister(FrameReg) || expectAndConsume(MIToken::comma) ||
+ parseCFIOffset(ScalableOffset) || expectAndConsume(MIToken::comma) ||
+ parseCFIOffset(FixedOffset))
+ return true;
+ CFIIndex =
+ MF.addFrameInst(MCCFIInstruction::createLLVMRegAtScalableOffsetFromReg(
+ nullptr, Reg, FrameReg, ScalableOffset, FixedOffset));
+ break;
+ }
case MIToken::kw_cfi_remember_state:
CFIIndex = MF.addFrameInst(MCCFIInstruction::createRememberState(nullptr));
break;
@@ -2971,6 +3009,9 @@ bool MIParser::parseMachineOperand(const unsigned OpCode, const unsigned OpIdx,
case MIToken::kw_cfi_escape:
case MIToken::kw_cfi_def_cfa:
case MIToken::kw_cfi_llvm_def_aspace_cfa:
+ case MIToken::kw_cfi_llvm_def_cfa_reg_scalable_offset:
+ case MIToken::kw_cfi_llvm_reg_at_scalable_offset_from_cfa:
+ case MIToken::kw_cfi_llvm_reg_at_scalable_offset_from_reg:
case MIToken::kw_cfi_register:
case MIToken::kw_cfi_remember_state:
case MIToken::kw_cfi_restore:
diff --git a/llvm/lib/CodeGen/MachineOperand.cpp b/llvm/lib/CodeGen/MachineOperand.cpp
index 8c6d2194433d0..b777a3ea63df2 100644
--- a/llvm/lib/CodeGen/MachineOperand.cpp
+++ b/llvm/lib/CodeGen/MachineOperand.cpp
@@ -725,6 +725,32 @@ static void printCFI(raw_ostream &OS, const MCCFIInstruction &CFI,
OS << ", " << CFI.getOffset();
OS << ", " << CFI.getAddressSpace();
break;
+ case MCCFIInstruction::OpLLVMDefCfaRegScalableOffset:
+ OS << "llvm_def_cfa_reg_scalable_offset ";
+ if (MCSymbol *Label = CFI.getLabel())
+ MachineOperand::printSymbol(OS, *Label);
+ printCFIRegister(CFI.getRegister2(), OS, TRI);
+ OS << ", " << CFI.getScalableOffset();
+ OS << ", " << CFI.getFixedOffset();
+ break;
+ case MCCFIInstruction::OpLLVMRegAtScalableOffsetFromCfa:
+ OS << "llvm_reg_at_scalable_offset_from_cfa ";
+ if (MCSymbol *Label = CFI.getLabel())
+ MachineOperand::printSymbol(OS, *Label);
+ printCFIRegister(CFI.getRegister(), OS, TRI);
+ OS << ", " << CFI.getScalableOffset();
+ OS << ", " << CFI.getFixedOffset();
+ break;
+ case MCCFIInstruction::OpLLVMRegAtScalableOffsetFromReg:
+ OS << "llvm_reg_at_scalable_offset_from_reg ";
+ if (MCSymbol *Label = CFI.getLabel())
+ MachineOperand::printSymbol(OS, *Label);
+ printCFIRegister(CFI.getRegister(), OS, TRI);
+ OS << ", ";
+ printCFIRegister(CFI.getRegister2(), OS, TRI);
+ OS << ", " << CFI.getScalableOffset();
+ OS << ", " << CFI.getFixedOffset();
+ break;
case MCCFIInstruction::OpRelOffset:
OS << "rel_offset ";
if (MCSymbol *Label = CFI.getLabel())
diff --git a/llvm/lib/MC/MCDwarf.cpp b/llvm/lib/MC/MCDwarf.cpp
index e8f000a584839..05e975458fe0f 100644
--- a/llvm/lib/MC/MCDwarf.cpp
+++ b/llvm/lib/MC/MCDwarf.cpp
@@ -1543,6 +1543,10 @@ void FrameEmitterImpl::emitCFIInstruction(const MCCFIInstruction &Instr) {
}
return;
}
+ case MCCFIInstruction::OpLLVMDefCfaRegScalableOffset:
+ case MCCFIInstruction::OpLLVMRegAtScalableOffsetFromCfa:
+ case MCCFIInstruction::OpLLVMRegAtScalableOffsetFromReg:
+ llvm_unreachable("Can't emit target-dependent cfi instruction here");
}
llvm_unreachable("Unhandled case in switch");
}
diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVTargetStreamer.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVTargetStreamer.cpp
index f70837ea3433b..d8eafe681311f 100644
--- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVTargetStreamer.cpp
+++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVTargetStreamer.cpp
@@ -16,6 +16,7 @@
#include "llvm/BinaryFormat/ELF.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCExpr.h"
+#include "llvm/MC/MCRegisterInfo.h"
#include "llvm/MC/MCSectionELF.h"
#include "llvm/MC/MCStreamer.h"
#include "llvm/MC/MCSymbol.h"
@@ -23,6 +24,7 @@
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/FormattedStream.h"
+#include "llvm/Support/LEB128.h"
#include "llvm/Support/RISCVAttributes.h"
#include "llvm/TargetParser/RISCVISAInfo.h"
@@ -35,11 +37,110 @@ static cl::opt<bool> RiscvAbiAttr(
cl::desc("Enable emitting RISC-V ELF attributes for ABI features"),
cl::Hidden);
-RISCVTargetStreamer::RISCVTargetStreamer(MCStreamer &S) : MCTargetStreamer(S) {}
+static void appendRegister(unsigned DwarfRegNum, SmallVectorImpl<char> &Expr) {
+ uint8_t Buffer[16];
+ if (DwarfRegNum < 32) {
+ Expr.push_back((uint8_t)(dwarf::DW_OP_breg0 + DwarfRegNum));
+ } else {
+ Expr.push_back((uint8_t)dwarf::DW_OP_bregx);
+ Expr.append(Buffer, Buffer + encodeULEB128(DwarfRegNum, Buffer));
+ }
+ Expr.push_back(0);
+}
+
+static void appendScalableVectorExpression(const MCRegisterInfo &MRI,
+ SmallVectorImpl<char> &Expr,
+ int FixedOffset,
+ int ScalableOffset) {
+ unsigned DwarfVLenB = MRI.getDwarfRegNum(RISCV::VLENB, true);
+ uint8_t Buffer[16];
+ if (FixedOffset) {
+ Expr.push_back(dwarf::DW_OP_consts);
+ Expr.append(Buffer, Buffer + encodeSLEB128(FixedOffset, Buffer));
+ Expr.push_back((uint8_t)dwarf::DW_OP_plus);
+ }
+
+ // TODO: case when ScalableOffset == 0
+ // TODO: case when ScalableOffset == 1
+ Expr.push_back((uint8_t)dwarf::DW_OP_consts);
+ Expr.append(Buffer, Buffer + encodeSLEB128(ScalableOffset, Buffer));
+
+ Expr.push_back((uint8_t)dwarf::DW_OP_bregx);
+ Expr.append(Buffer, Buffer + encodeULEB128(DwarfVLenB, Buffer));
+ Expr.push_back(0);
+
+ Expr.push_back((uint8_t)dwarf::DW_OP_mul);
+ Expr.push_back((uint8_t)dwarf::DW_OP_plus);
+}
+
+RISCVTargetStreamer::RISCVTargetStreamer(MCStreamer &S) : MCTargetStreamer(S) {
+ MRI = getContext().getRegisterInfo();
+}
void RISCVTargetStreamer::finish() { finishAttributeSection(); }
void RISCVTargetStreamer::reset() {}
+void RISCVTargetStreamer::emitCFILLVMDefCfaRegScalableOffset(
+ unsigned Register, int64_t ScalableOffset, int64_t FixedOffset, SMLoc Loc) {
+ SmallString<64> RegPlusScalableOffsetExpr;
+ uint8_t Buffer[16];
+ // Encode Register
+ appendRegister(Register, RegPlusScalableOffsetExpr);
+ // Encode scalable offset
+ appendScalableVectorExpression(*MRI, RegPlusScalableOffsetExpr, FixedOffset,
+ ScalableOffset);
+
+ // Wrap this into DW_CFA_def_cfa_expression.
+ SmallString<64> Expr;
+ Expr.push_back(dwarf::DW_CFA_def_cfa_expression);
+ Expr.append(Buffer,
+ Buffer + encodeULEB128(RegPlusScalableOffsetExpr.size(), Buffer));
+ Expr.append(RegPlusScalableOffsetExpr.str());
+
+ Streamer.emitCFIEscape(Expr.str(), Loc);
+}
+
+void RISCVTargetStreamer::emitCFILLVMRegAtScalableOffsetFromCfa(
+ unsigned Register, int64_t ScalableOffset, int64_t FixedOffset, SMLoc Loc) {
+ SmallString<64> RegPlusScalableOffsetExpr;
+ uint8_t Buffer[16];
+ // Value of CFA will be pushed onto the expression stack by the
+ // DW_CFA_expression. Encode scalable offset
+ appendScalableVectorExpression(*MRI, RegPlusScalableOffsetExpr, FixedOffset,
+ ScalableOffset);
+ // Wrap this into DW_CFA_expression.
+ SmallString<64> Expr;
+ Expr.push_back(dwarf::DW_CFA_expression);
+ Expr.append(Buffer, Buffer + encodeULEB128(Register, Buffer));
+ Expr.append(Buffer,
+ Buffer + encodeULEB128(RegPlusScalableOffsetExpr.size(), Buffer));
+ Expr.append(RegPlusScalableOffsetExpr.str());
+
+ Streamer.emitCFIEscape(Expr.str(), Loc);
+}
+
+void RISCVTargetStreamer::emitCFILLVMRegAtScalableOffsetFromReg(
+ unsigned Register, unsigned Register2, int64_t ScalableOffset,
+ int64_t FixedOffset, SMLoc Loc) {
+ SmallString<64> RegPlusScalableOffsetExpr;
+ uint8_t Buffer[16];
+ // Encode Register2
+ appendRegister(Register2, RegPlusScalableOffsetExpr);
+ // Encode (Register2 + FixedOffset + ScalableOffset * VLENB)
+ appendScalableVectorExpression(*MRI, RegPlusScalableOffsetExpr, FixedOffset,
+ ScalableOffset);
+
+ // Wrap this into DW_CFA_expression.
+ SmallString<64> Expr;
+ Expr.push_back(dwarf::DW_CFA_expression);
+ Expr.append(Buffer, Buffer + encodeULEB128(Register, Buffer));
+ Expr.append(Buffer,
+ Buffer + encodeULEB128(RegPlusScalableOffsetExpr.size(), Buffer));
+ Expr.append(RegPlusScalableOffsetExpr.str());
+
+ Streamer.emitCFIEscape(Expr.str(), Loc);
+}
+
void RISCVTargetStreamer::emitDirectiveOptionArch(
ArrayRef<RISCVOptionArchArg> Args) {}
void RISCVTargetStreamer::emitDirectiveOptionExact() {}
diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVTargetStreamer.h b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVTargetStreamer.h
index d7b3b1ed92068..b0807de9c6993 100644
--- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVTargetStreamer.h
+++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVTargetStreamer.h
@@ -16,6 +16,7 @@
namespace llvm {
class formatted_raw_ostream;
+class MCRegisterInfo;
enum class RISCVOptionArchArgType {
Full,
@@ -35,12 +36,28 @@ class RISCVTargetStreamer : public MCTargetStreamer {
RISCVABI::ABI TargetABI = RISCVABI::ABI_Unknown;
bool HasRVC = false;
bool HasTSO = false;
+ const MCRegisterInfo *MRI = nullptr;
public:
RISCVTargetStreamer(MCStreamer &S);
void finish() override;
virtual void reset();
+ void emitCFILLVMDefCfaRegScalableOffset(unsigned Register,
+ int64_t ScalableOffset,
+ int64_t FixedOffset,
+ SMLoc Loc) override;
+ void emitCFILLVMRegAtScalableOffsetFromCfa(unsigned Register,
+ int64_t ScalableOffset,
+ int64_t FixedOffset,
+ SMLoc Loc) override;
+
+ void emitCFILLVMRegAtScalableOffsetFromReg(unsigned Register,
+ unsigned Register2,
+ int64_t ScalableOffset,
+ int64_t FixedOffset,
+ SMLoc Loc) override;
+
virtual void emitDirectiveOptionArch(ArrayRef<RISCVOptionArchArg> Args);
virtual void emitDirectiveOptionExact();
virtual void emitDirectiveOptionNoExact();
diff --git a/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp b/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp
index 75e7cf347e461..6d91790c59a84 100644
--- a/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp
@@ -669,86 +669,48 @@ void RISCVFrameLowering::allocateAndProbeStackForRVV(
}
}
-static void appendScalableVectorExpression(const TargetRegisterInfo &TRI,
- SmallVectorImpl<char> &Expr,
- int FixedOffset, int ScalableOffset,
- llvm::raw_string_ostream &Comment) {
- unsigned DwarfVLenB = TRI.getDwarfRegNum(RISCV::VLENB, true);
- uint8_t Buffer[16];
- if (FixedOffset) {
- Expr.push_back(dwarf::DW_OP_consts);
- Expr.append(Buffer, Buffer + encodeSLEB128(FixedOffset, Buffer));
- Expr.push_back((uint8_t)dwarf::DW_OP_plus);
- Comment << (FixedOffset < 0 ? " - " : " + ") << std::abs(FixedOffset);
- }
-
- Expr.push_back((uint8_t)dwarf::DW_OP_consts);
- Expr.append(Buffer, Buffer + encodeSLEB128(ScalableOffset, Buffer));
-
- Expr.push_back((uint8_t)dwarf::DW_OP_bregx);
- Expr.append(Buffer, Buffer + encodeULEB128(DwarfVLenB, Buffer));
- Expr.push_back(0);
-
- Expr.push_back((uint8_t)dwarf::DW_OP_mul);
- Expr.push_back((uint8_t)dwarf::DW_OP_plus);
-
- Comment << (ScalableOffset < 0 ? " - " : " + ") << std::abs(ScalableOffset)
- << " * vlenb";
-}
-
static MCCFIInstruction createDefCFAExpression(const TargetRegisterInfo &TRI,
Register Reg,
- uint64_t FixedOffset,
- uint64_t ScalableOffset) {
+ int64_t FixedOffset,
+ int64_t ScalableOffset) {
+ // TODO: here we pass FixedOffset as uint64_t but we use it as int64_t. Is
+ // this correct?
assert(ScalableOffset != 0 && "Did not need to adjust CFA for RVV");
- SmallString<64> Expr;
std::string CommentBuffer;
llvm::raw_string_ostream Comment(CommentBuffer);
// Build up the expression (Reg + FixedOffset + ScalableOffset * VLENB).
- unsigned DwarfReg = TRI.getDwarfRegNum(Reg, true);
- Expr.push_back((uint8_t)(dwarf::DW_OP_breg0 + DwarfReg));
- Expr.push_back(0);
if (Reg == SPReg)
Comment << "sp";
else
Comment << printReg(Reg, &TRI);
+ if (FixedOffset)
+ Comment << (FixedOffset < 0 ? " - " : " + ") << std::abs(FixedOffset);
+ if (ScalableOffset)
+ Comment << (ScalableOffset < 0 ? " - " : " + ") << std::abs(ScalableOffset)
+ << " * vlenb";
- appendScalableVectorExpression(TRI, Expr, FixedOffset, ScalableOffset,
- Comment);
-
- SmallString<64> DefCfaExpr;
- uint8_t Buffer[16];
- DefCfaExpr.push_back(dwarf::DW_CFA_def_cfa_expression);
- DefCfaExpr.append(Buffer, Buffer + encodeULEB128(Expr.size(), Buffer));
- DefCfaExpr.append(Expr.str());
-
- return MCCFIInstruction::createEscape(nullptr, DefCfaExpr.str(), SMLoc(),
- Comment.str());
+ unsigned DwarfReg = TRI.getDwarfRegNum(Reg, true);
+ return MCCFIInstruction::createLLVMDefCfaRegScalableOffset(
+ nullptr, DwarfReg, ScalableOffset, FixedOffset, SMLoc(), Comment.str());
}
static MCCFIInstruction createDefCFAOffset(const TargetRegisterInfo &TRI,
- Register Reg, uint64_t FixedOffset,
- uint64_t ScalableOffset) {
+ Register Reg, int64_t FixedOffset,
+ int64_t ScalableOffset) {
assert(ScalableOffset != 0 && "Did not need to adjust CFA for RVV");
- SmallString<64> Expr;
std::string CommentBuffer;
llvm::raw_string_ostream Comment(CommentBuffer);
Comment << printReg(Reg, &TRI) << " @ cfa";
+ if (FixedOffset)
+ Comment << (FixedOffset < 0 ? " - " : " + ") << std::abs(FixedOffset);
- // Build up the expression (FixedOffset + ScalableOffset * VLENB).
- appendScalableVectorExpression(TRI, Expr, FixedOffset, ScalableOffset,
- Comment);
+ if (ScalableOffset)
+ Comment << (ScalableOffset < 0 ? " - " : " + ") << std::abs(ScalableOffset)
+ << " * vlenb";
- SmallString<64> DefCfaExpr;
- uint8_t Buffer[16];
unsigned DwarfReg = TRI.getDwarfRegNum(Reg, true);
- DefCfaExpr.push_back(dwarf::DW_CFA_expression);
- DefCfaExpr.append(Buffer, Buffer + encodeULEB128(DwarfReg, Buffer));
- DefCfaExpr.append(Buffer, Buffer + encodeULEB128(Expr.size(), Buffer));
- DefCfaExpr.append(Expr.str());
-
- return MCCFIInstruction::createEscape(nullptr, DefCfaExpr.str(), SMLoc(),
- Comment.str());
+ return MCCFIInstruction::createLLVMRegAtScalableOffsetFromCfa(
+ nullptr, DwarfReg, ScalableOffset, FixedOffset, SMLoc(), Comment.str());
}
// Allocate stack space and probe it if necessary.
diff --git a/llvm/test/CodeGen/MIR/RISCV/cfi-llvm-def-cfa-reg-scalable-offset.mir b/llvm/test/CodeGen/MIR/RISCV/cfi-llvm-def-cfa-reg-scalable-offset.mir
new file mode 100644
index 0000000000000..bd311173695b0
--- /dev/null
+++ b/llvm/test/CodeGen/MIR/RISCV/cfi-llvm-def-cfa-reg-scalable-offset.mir
@@ -0,0 +1,11 @@
+# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py UTC_ARGS: --version 5
+# RUN: llc -mtriple=riscv64 -run-pass none -o - %s \
+# RUN: | FileCheck %s
+
+# This test ensures that the MIR parser parses the llvm_def_cfa_reg_scalable_offset cfi instruction correctly.
+
+name: func
+body: |
+ bb.0:
+ ; CHECK: CFI_INSTRUCTION llvm_def_cfa_reg_scalable_offset $x2, 5, -42
+ CFI_INSTRUCTION llvm_def_cfa_reg_scalable_offset $x2, 5, -42
diff --git a/llvm/test/CodeGen/MIR/RISCV/cfi-llvm-reg-at-scalable-offset-from-cfa.mir b/llvm/test/CodeGen/MIR/RISCV/cfi-llvm-reg-at-scalable-offset-from-cfa.mir
new file mode 100644
index 0000000000000..c1af1e295b399
--- /dev/null
+++ b/llvm/test/CodeGen/MIR/RISCV/cfi-llvm-reg-at-scalable-offset-from-cfa.mir
@@ -0,0 +1,11 @@
+# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py UTC_ARGS: --version 5
+# RUN: llc -mtriple=riscv64 -run-pass none -o - %s \
+# RUN: | FileCheck %s
+
+# This test ensures that the MIR parser parses the llvm_reg_at_scalable_offset_from_cfa cfi instruction correctly.
+
+name: func
+body: |
+ bb.0:
+ ; CHECK: CFI_INSTRUCTION llvm_reg_at_scalable_offset_from_cfa $x2, 5, -42
+ CFI_INSTRUCTION llvm_reg_at_scalable_offset_from_cfa $x2, 5, -42
diff --git a/llvm/test/CodeGen/MIR/RISCV/cfi-llvm-reg-at-scalable-offset-from-reg.mir b/llvm/test/CodeGen/MIR/RISCV/cfi-llvm-reg-at-scalable-offset-from-reg.mir
new file mode 100644
index 0000000000000..604082fbc7d92
--- /dev/null
+++ b/llvm/test/CodeGen/MIR/RISCV/cfi-llvm-reg-at-scalable-offset-from-reg.mir
@@ -0,0 +1,11 @@
+# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py UTC_ARGS: --version 5
+# RUN: llc -mtriple=riscv64 -run-pass none -o - %s \
+# RUN: | FileCheck %s
+
+# This test ensures that the MIR parser parses the llvm_reg_offset cfi instruction correctly.
+
+name: func
+body: |
+ bb.0:
+ ; CHECK: CFI_INSTRUCTION llvm_reg_at_scalable_offset_from_reg $x1, $x2, 5, -42
+ CFI_INSTRUCTION llvm_reg_at_scalable_offset_from_reg $x1, $x2, 5, -42
diff --git a/llvm/test/CodeGen/RISCV/cfi-llvm-def-cfa-reg-scalable-offset.mir b/llvm/test/CodeGen/RISCV/cfi-llvm-def-cfa-reg-scalable-offset.mir
new file mode 100644
index 0000000000000..9bd901c43c480
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/cfi-llvm-def-cfa-reg-scalable-offset.mir
@@ -0,0 +1,33 @@
+# RUN: llc -mtriple=riscv64 -start-after=unpack-mi-bundles -o - %s \
+# RUN: | FileCheck %s
+
+# Check that `llvm_def_cfa_reg_scalable_offset` generates an escape expression corresponding to `deref(Reg) + FixedOffset + ScalableOffset * deref(vlenb)`
+
+# | 0x0f | def_cfa_expression |
+# | 0x0d | length of expression
+# | 0x72 | dw_op_breg2
+# | 0x00 | | deref($x2)
+# | 0x11 | consts
+# | 0x2a | leb8(42) = 0x2a | deref($x2), 42
+# | 0x22 | dw_op_plus | (42 + deref($x2))
+# | 0x11 | consts
+# | 0x05 | leb8(5) = 0x05 | (42 + deref($x2)), 5
+# | 0x92 | dw_op_bregx |
+# | 0xa2 | vlenb reg number is 7202 |
+# | 0x38 | leb128(7202) = 0xa238 |
+# | 0x00 | | (deref($x1) + 42), 5, deref($vlenb)
+# | 0x1e | dw_op_mul | (deref($x1) + 42), (5 * deref($vleb))
+# | 0x22 | dw_op_plus | (deref($x1) + 42 + 5 * deref(vlenb)
+
+name: func
+body: |
+ bb.0:
+ CFI_INSTRUCTION llvm_def_cfa_reg_scalable_offset $x2, 5, 42
+ PseudoRET
+# CHECK-LABEL: func:
+# CHECK: .cfi_startproc
+# CHECK: .cfi_escape 0x0f, 0x0d, 0x72, 0x00, 0x11, 0x2a, 0x22, 0x11, 0x05, 0x92, 0xa2, 0x38, 0x00, 0x1e, 0x22
+# CHECK: ret
+# CHECK: .Lfunc_end0:
+# CHECK: .size func, .Lfunc_end0-func
+# CHECK: .cfi_endproc
diff --git a/llvm/test/CodeGen/RISCV/cfi-llvm-reg-at-scalable-offset-from-cfa.mir b/llvm/test/CodeGen/RISCV/cfi-llvm-reg-at-scalable-offset-from-cfa.mir
new file mode 100644
index 0000000000000..cf6d4c49dde55
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/cfi-llvm-reg-at-scalable-offset-from-cfa.mir
@@ -0,0 +1,34 @@
+# RUN: llc -mtriple=riscv64 -start-after=unpack-mi-bundles -o - %s \
+# RUN: | FileCheck %s
+
+# Check that `llvm_reg_at_scalable_offset_from_cfa` generates an escape expression corresponding to `cfa + FixedOffset + ScalableOffset * deref(vlenb)`
+
+# | Opcode | Meaning | Stack (bottom to top)
+# ---------------------------------------------------------------------------
+# | 0x10 | dw_cfa_expression cfa
+# | 0x01 | register number
+# | 0x0b | length of expression
+# | 0x11 | dw_op_consts
+# | 0x2a | leb8(42) = 0x2a cfa, 42
+# | 0x22 | dw_op_plus (cfa + 42)
+# | 0x11 | dw_op_consts
+# | 0x05 | leb8(5) = 0x05 (cfa + 42), 5
+# | 0x92 | dw_op_bregx
+# | 0xa2 | vlenb reg number is 7202
+# | 0x38 | leb128(7202) = 0xa238
+# | 0x00 | (cfa + 42), 5, deref($vlenb)
+# | 0x1e | dw_op_mul (cfa + 42), 5 * deref($vlenb)
+# | 0x22 | dw_op_plus (cfa + 42 + 5 * deref($vlenb)
+
+name: func
+body: |
+ bb.0:
+ CFI_INSTRUCTION llvm_reg_at_scalable_offset_from_cfa $x1, 5, 42
+ PseudoRET
+# CHECK-LABEL: func:
+# CHECK: .cfi_startproc
+# CHECK: .cfi_escape 0x10, 0x01, 0x0b, 0x11, 0x2a, 0x22, 0x11, 0x05, 0x92, 0xa2, 0x38, 0x00, 0x1e, 0x22
+# CHECK: ret
+# CHECK: .Lfunc_end0:
+# CHECK: .size func, .Lfunc_end0-func
+# CHECK: .cfi_endproc
diff --git a/llvm/test/CodeGen/RISCV/cfi-llvm-reg-at-scalable-offset-from-reg.mir b/llvm/test/CodeGen/RISCV/cfi-llvm-reg-at-scalable-offset-from-reg.mir
new file mode 100644
index 0000000000000..b68949844e1f9
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/cfi-llvm-reg-at-scalable-offset-from-reg.mir
@@ -0,0 +1,36 @@
+# RUN: llc -mtriple=riscv64 -start-after=unpack-mi-bundles -o - %s \
+# RUN: | FileCheck %s
+
+# Check that `llvm_reg_at_scalable_offset_from_reg` generates an escape expression corresponding to `deref(Reg) + FixedOffset + ScalableOffset * deref(vlenb)`
+
+# | Opcode | Meaning | Stack (bottom to top)
+# ---------------------------------------------------------------------------
+# | 0x10 | dw_cfa_expression | cfa (pushed before expression is evaluated)
+# | 0x01 | register number |
+# | 0x0d | length of the expression |
+# | 0x72 | dw_op_breg2 |
+# | 0x00 | offset | cfa, deref($x1)
+# | 0x11 | consts |
+# | 0x2a | 42 | cfa, deref($x1), 42
+# | 0x22 | plus | cfa, (deref($x1) + 42)
+# | 0x11 | consts |
+# | 0x05 | 5 | cfa, (deref($x1) + 42), 5
+# | 0x92 | dw_op_bregx |
+# | 0xa2 | vlenb reg number is 7202 |
+# | 0x38 | leb128(7202) = 0xa238 |
+# | 0x00 | | cfa, (deref($x1) + 42), 5, deref($vlenb)
+# | 0x1e | dw_op_mul | cfa, (deref($x1) + 42), (5 * deref($vleb))
+# | 0x22 | dw_op_plus | cfa, (deref($x1) + 42 + 5 * deref(vlenb)
+
+name: func
+body: |
+ bb.0:
+ CFI_INSTRUCTION llvm_reg_at_scalable_offset_from_reg $x1, $x2, 5, 42
+ PseudoRET
+# CHECK-LABEL: func:
+# CHECK: .cfi_startproc
+# CHECK: .cfi_escape 0x10, 0x01, 0x0d, 0x72, 0x00, 0x11, 0x2a, 0x22, 0x11, 0x05, 0x92, 0xa2, 0x38, 0x00, 0x1e, 0x22
+# CHECK: ret
+# CHECK: .Lfunc_end0:
+# CHECK: .size func, .Lfunc_end0-func
+# CHECK: .cfi_endproc
diff --git a/llvm/test/CodeGen/RISCV/rvv/get-vlen-debugloc.mir b/llvm/test/CodeGen/RISCV/rvv/get-vlen-debugloc.mir
index c493a6ca180aa..998c28d422b76 100644
--- a/llvm/test/CodeGen/RISCV/rvv/get-vlen-debugloc.mir
+++ b/llvm/test/CodeGen/RISCV/rvv/get-vlen-debugloc.mir
@@ -29,7 +29,7 @@ body: |
; CHECK-NEXT: $x10 = frame-setup PseudoReadVLENB
; CHECK-NEXT: $x10 = frame-setup SLLI killed $x10, 1
; CHECK-NEXT: $x2 = frame-setup SUB $x2, killed $x10
- ; CHECK-NEXT: frame-setup CFI_INSTRUCTION escape 0x0f, 0x0a, 0x72, 0x00, 0x11, 0x02, 0x92, 0xa2, 0x38, 0x00, 0x1e, 0x22
+ ; CHECK-NEXT: frame-setup CFI_INSTRUCTION llvm_def_cfa_reg_scalable_offset $x2, 2, 0
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: bb.1:
; CHECK-NEXT: $x10 = frame-destroy PseudoReadVLENB
diff --git a/llvm/test/CodeGen/RISCV/rvv/wrong-stack-offset-for-rvv-object.mir b/llvm/test/CodeGen/RISCV/rvv/wrong-stack-offset-for-rvv-object.mir
index 6e5b49d543216..0c55da0c73c92 100644
--- a/llvm/test/CodeGen/RISCV/rvv/wrong-stack-offset-for-rvv-object.mir
+++ b/llvm/test/CodeGen/RISCV/rvv/wrong-stack-offset-for-rvv-object.mir
@@ -126,15 +126,15 @@ body: |
; CHECK-NEXT: {{ $}}
; CHECK-NEXT: $x2 = frame-setup ADDI $x2, -80
; CHECK-NEXT: frame-setup CFI_INSTRUCTION def_cfa_offset 80
- ; CHECK-NEXT: SD killed $x1, $x2, 56 :: (store (s64) into %stack.2)
- ; CHECK-NEXT: SD killed $x8, $x2, 48 :: (store (s64) into %stack.3)
- ; CHECK-NEXT: SD killed $x9, $x2, 40 :: (store (s64) into %stack.4)
+ ; CHECK-NEXT: frame-setup SD killed $x1, $x2, 56 :: (store (s64) into %stack.2)
+ ; CHECK-NEXT: frame-setup SD killed $x8, $x2, 48 :: (store (s64) into %stack.3)
+ ; CHECK-NEXT: frame-setup SD killed $x9, $x2, 40 :: (store (s64) into %stack.4)
; CHECK-NEXT: frame-setup CFI_INSTRUCTION offset $x1, -24
; CHECK-NEXT: frame-setup CFI_INSTRUCTION offset $x8, -32
; CHECK-NEXT: frame-setup CFI_INSTRUCTION offset $x9, -40
; CHECK-NEXT: $x10 = frame-setup PseudoReadVLENB
; CHECK-NEXT: $x2 = frame-setup SUB $x2, killed $x10
- ; CHECK-NEXT: frame-setup CFI_INSTRUCTION escape 0x0f, 0x0e, 0x72, 0x00, 0x11, 0xd0, 0x00, 0x22, 0x11, 0x01, 0x92, 0xa2, 0x38, 0x00, 0x1e, 0x22
+ ; CHECK-NEXT: frame-setup CFI_INSTRUCTION llvm_def_cfa_reg_scalable_offset $x2, 1, 80
; CHECK-NEXT: renamable $x8 = COPY $x14
; CHECK-NEXT: renamable $x9 = COPY $x11
; CHECK-NEXT: $x10 = PseudoReadVLENB
diff --git a/llvm/test/CodeGen/RISCV/rvv/zvlsseg-spill.mir b/llvm/test/CodeGen/RISCV/rvv/zvlsseg-spill.mir
index 9c2fa9d0009a7..fd1a40f553425 100644
--- a/llvm/test/CodeGen/RISCV/rvv/zvlsseg-spill.mir
+++ b/llvm/test/CodeGen/RISCV/rvv/zvlsseg-spill.mir
@@ -26,7 +26,7 @@ body: |
; CHECK-NEXT: $x12 = frame-setup PseudoReadVLENB
; CHECK-NEXT: $x12 = frame-setup SLLI killed $x12, 3
; CHECK-NEXT: $x2 = frame-setup SUB $x2, killed $x12
- ; CHECK-NEXT: frame-setup CFI_INSTRUCTION escape 0x0f, 0x0d, 0x72, 0x00, 0x11, 0x10, 0x22, 0x11, 0x08, 0x92, 0xa2, 0x38, 0x00, 0x1e, 0x22
+ ; CHECK-NEXT: frame-setup CFI_INSTRUCTION llvm_def_cfa_reg_scalable_offset $x2, 8, 16
; CHECK-NEXT: dead $x0 = PseudoVSETVLI killed renamable $x11, 216 /* e64, m1, ta, ma */, implicit-def $vl, implicit-def $vtype
; CHECK-NEXT: $v0_v1_v2_v3_v4_v5_v6 = PseudoVLSEG7E64_V_M1 undef $v0_v1_v2_v3_v4_v5_v6, renamable $x10, $noreg, 6 /* e64 */, 0 /* tu, mu */, implicit $vl, implicit $vtype
; CHECK-NEXT: $x11 = ADDI $x2, 16
>From f8b004910c604138bba0724176980727953208dd Mon Sep 17 00:00:00 2001
From: Mikhail Gudim <mgudim at ventanamicro.com>
Date: Tue, 15 Apr 2025 23:47:17 -0700
Subject: [PATCH 2/3] Add a test showing that scalable offsets are not handled.
Currently we encode scalable offsets in CFIs using cfi_escape. But
CFIInstrInserter can't handle cfi_escape.
---
.../RISCV/cfi-inserter-scalable-offset.mir | 94 +++++++++++++++++++
1 file changed, 94 insertions(+)
create mode 100644 llvm/test/CodeGen/RISCV/cfi-inserter-scalable-offset.mir
diff --git a/llvm/test/CodeGen/RISCV/cfi-inserter-scalable-offset.mir b/llvm/test/CodeGen/RISCV/cfi-inserter-scalable-offset.mir
new file mode 100644
index 0000000000000..17fde2dcc86dc
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/cfi-inserter-scalable-offset.mir
@@ -0,0 +1,94 @@
+# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py UTC_ARGS: --version 5
+# RUN: llc %s -mtriple=riscv64 -mattr=+v \
+# RUN: -run-pass=prologepilog,cfi-instr-inserter \
+# RUN: -riscv-enable-cfi-instr-inserter=true \
+# RUN: -o - | FileCheck %s
+# XFAIL: *
+#
+# In this test prolog will be inserted in bb.3. We need to save the scalable vector register v1.
+# In bb.3 the new rule for computing CFA will be (sp + 16 + 1 * vlenb) which we encode using cfi_escape. Also, $v1 will be saved at (cfa - 1 * vlenb), which we also encode using cfi_escape.
+# Since the only way to get to bb.2 is from bb.3, the same cfi's should be emitted at beginning of bb.2
+#
+# Currently CFIInstrInserter can't handle escape, so we end up with wrong CFI.
+# NOTE: if llc was compiled with NDEBUG, this will just crash. Otherwise, the output will be as in CHECK lines.
+
+--- |
+
+ define riscv_vector_cc void @test0(ptr %p0, ptr %p1) #0 {
+ entry:
+ %v = load <4 x i32>, ptr %p0, align 16
+ store <4 x i32> %v, ptr %p1, align 16
+ ret void
+ }
+
+ attributes #0 = { "target-features"="+v" }
+
+...
+---
+name: test0
+tracksRegLiveness: true
+frameInfo:
+ savePoint:
+ - point: '%bb.3'
+ restorePoint:
+ - point: '%bb.2'
+body: |
+ ; CHECK-LABEL: name: test0
+ ; CHECK: bb.0.entry:
+ ; CHECK-NEXT: successors: %bb.3(0x40000000), %bb.1(0x40000000)
+ ; CHECK-NEXT: liveins: $x10, $x11, $v1
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: BEQ $x10, $x0, %bb.3
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: bb.1:
+ ; CHECK-NEXT: liveins: $v1
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: PseudoRET
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: bb.2:
+ ; CHECK-NEXT: successors: %bb.1(0x80000000)
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: CFI_INSTRUCTION def_cfa_offset 16
+ ; CHECK-NEXT: $x10 = ADDI $x2, 16
+ ; CHECK-NEXT: $v1 = frame-destroy VL1RE8_V killed $x10 :: (load (<vscale x 1 x s64>) from %stack.0)
+ ; CHECK-NEXT: $x10 = frame-destroy PseudoReadVLENB
+ ; CHECK-NEXT: $x2 = frame-destroy ADD $x2, killed $x10
+ ; CHECK-NEXT: frame-destroy CFI_INSTRUCTION def_cfa $x2, 16
+ ; CHECK-NEXT: frame-destroy CFI_INSTRUCTION restore $v1
+ ; CHECK-NEXT: $x2 = frame-destroy ADDI $x2, 16
+ ; CHECK-NEXT: frame-destroy CFI_INSTRUCTION def_cfa_offset 0
+ ; CHECK-NEXT: PseudoBR %bb.1
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: bb.3:
+ ; CHECK-NEXT: successors: %bb.2(0x80000000)
+ ; CHECK-NEXT: liveins: $x10, $x11, $v1
+ ; CHECK-NEXT: {{ $}}
+ ; CHECK-NEXT: $x2 = frame-setup ADDI $x2, -16
+ ; CHECK-NEXT: frame-setup CFI_INSTRUCTION def_cfa_offset 16
+ ; CHECK-NEXT: $x12 = frame-setup PseudoReadVLENB
+ ; CHECK-NEXT: $x2 = frame-setup SUB $x2, killed $x12
+ ; CHECK-NEXT: frame-setup CFI_INSTRUCTION escape 0x0f, 0x0d, 0x72, 0x00, 0x11, 0x10, 0x22, 0x11, 0x01, 0x92, 0xa2, 0x38, 0x00, 0x1e, 0x22
+ ; CHECK-NEXT: $x12 = ADDI $x2, 16
+ ; CHECK-NEXT: frame-setup VS1R_V killed $v1, killed $x12 :: (store (<vscale x 1 x s64>) into %stack.0)
+ ; CHECK-NEXT: frame-setup CFI_INSTRUCTION escape 0x10, 0x61, 0x08, 0x11, 0x7f, 0x92, 0xa2, 0x38, 0x00, 0x1e, 0x22
+ ; CHECK-NEXT: dead $x0 = PseudoVSETIVLI 4, 208 /* e32, m1, ta, ma */, implicit-def $vl, implicit-def $vtype
+ ; CHECK-NEXT: renamable $v1 = PseudoVLE32_V_M1 undef renamable $v1, killed renamable $x10, 4, 5 /* e32 */, 2 /* tu, ma */, implicit $vl, implicit $vtype
+ ; CHECK-NEXT: PseudoVSE32_V_M1 killed renamable $v1, killed renamable $x11, 4, 5 /* e32 */, implicit $vl, implicit $vtype
+ ; CHECK-NEXT: PseudoBR %bb.2
+ bb.0.entry:
+ liveins: $x10, $x11
+ BEQ $x10, $x0, %bb.3
+
+ bb.1:
+ PseudoRET
+
+ bb.2:
+ PseudoBR %bb.1
+
+ bb.3:
+ liveins: $x10, $x11
+ dead $x0 = PseudoVSETIVLI 4, 208, implicit-def $vl, implicit-def $vtype
+ renamable $v1 = PseudoVLE32_V_M1 undef renamable $v1, killed renamable $x10, 4, 5, 2, implicit $vl, implicit $vtype
+ PseudoVSE32_V_M1 killed renamable $v1, killed renamable $x11, 4, 5, implicit $vl, implicit $vtype
+ PseudoBR %bb.2
+...
>From 12dfd4994538e87537dfe392a89445a3f90f4b22 Mon Sep 17 00:00:00 2001
From: Mikhail Gudim <mgudim at ventanamicro.com>
Date: Thu, 1 May 2025 00:51:43 -0700
Subject: [PATCH 3/3] [CFIInstrInserter] Support scalable offsets.
Add support for scalable offsets.
---
llvm/lib/CodeGen/CFIInstrInserter.cpp | 139 +++++++++++++-----
.../RISCV/cfi-inserter-scalable-offset.mir | 11 +-
2 files changed, 108 insertions(+), 42 deletions(-)
diff --git a/llvm/lib/CodeGen/CFIInstrInserter.cpp b/llvm/lib/CodeGen/CFIInstrInserter.cpp
index 5d2ca15c2e12e..1caa9f040e092 100644
--- a/llvm/lib/CodeGen/CFIInstrInserter.cpp
+++ b/llvm/lib/CodeGen/CFIInstrInserter.cpp
@@ -70,17 +70,17 @@ class CFIInstrInserter : public MachineFunctionPass {
#define INVALID_OFFSET INT_MAX
/// contains the location where CSR register is saved.
struct CSRSavedLocation {
- enum Kind { INVALID, REGISTER, CFA_OFFSET };
+ enum Kind { INVALID, REGISTER, CFA_OFFSET, REG_OFFSET };
CSRSavedLocation() {
K = Kind::INVALID;
Reg = 0;
- Offset = 0;
+ Offset = StackOffset::get(0, 0);
}
Kind K;
// Dwarf register number
unsigned Reg;
- // CFA offset
- int64_t Offset;
+ // Offset from CFA or Reg
+ StackOffset Offset;
bool isValid() const { return K != Kind::INVALID; }
bool operator==(const CSRSavedLocation &RHS) const {
if (K != RHS.K)
@@ -92,6 +92,8 @@ class CFIInstrInserter : public MachineFunctionPass {
return Reg == RHS.Reg;
case Kind::CFA_OFFSET:
return Offset == RHS.Offset;
+ case Kind::REG_OFFSET:
+ return (Reg == RHS.Reg) && (Offset == RHS.Offset);
}
llvm_unreachable("Unknown CSRSavedLocation Kind!");
}
@@ -104,7 +106,12 @@ class CFIInstrInserter : public MachineFunctionPass {
OS << "In Dwarf register: " << Reg;
break;
case Kind::CFA_OFFSET:
- OS << "At CFA offset: " << Offset;
+ OS << "At CFA offset: (fixed: " << Offset.getFixed()
+ << ", scalable: " << Offset.getScalable() << ")";
+ break;
+ case Kind::REG_OFFSET:
+ OS << "At offset " << Offset.getFixed() << " from Dwarf register "
+ << Reg;
break;
}
}
@@ -113,9 +120,9 @@ class CFIInstrInserter : public MachineFunctionPass {
struct MBBCFAInfo {
MachineBasicBlock *MBB;
/// Value of cfa offset valid at basic block entry.
- int64_t IncomingCFAOffset = -1;
+ StackOffset IncomingCFAOffset = StackOffset::getFixed(-1);
/// Value of cfa offset valid at basic block exit.
- int64_t OutgoingCFAOffset = -1;
+ StackOffset OutgoingCFAOffset = StackOffset::getFixed(-1);
/// Value of cfa register valid at basic block entry.
unsigned IncomingCFARegister = 0;
/// Value of cfa register valid at basic block exit.
@@ -154,7 +161,7 @@ class CFIInstrInserter : public MachineFunctionPass {
/// Return the cfa offset value that should be set at the beginning of a MBB
/// if needed. The negated value is needed when creating CFI instructions
/// that set absolute offset.
- int64_t getCorrectCFAOffset(MachineBasicBlock *MBB) {
+ StackOffset getCorrectCFAOffset(MachineBasicBlock *MBB) {
return MBBVector[MBB->getNumber()].IncomingCFAOffset;
}
@@ -191,8 +198,8 @@ void CFIInstrInserter::calculateCFAInfo(MachineFunction &MF) {
for (MachineBasicBlock &MBB : MF) {
MBBCFAInfo &MBBInfo = MBBVector[MBB.getNumber()];
MBBInfo.MBB = &MBB;
- MBBInfo.IncomingCFAOffset = InitialOffset;
- MBBInfo.OutgoingCFAOffset = InitialOffset;
+ MBBInfo.IncomingCFAOffset = StackOffset::getFixed(InitialOffset);
+ MBBInfo.OutgoingCFAOffset = StackOffset::getFixed(InitialOffset);
MBBInfo.IncomingCFARegister = DwarfInitialRegister;
MBBInfo.OutgoingCFARegister = DwarfInitialRegister;
MBBInfo.IncomingCSRLocations.resize(NumRegs);
@@ -217,7 +224,7 @@ void CFIInstrInserter::calculateCFAInfo(MachineFunction &MF) {
void CFIInstrInserter::calculateOutgoingCFAInfo(MBBCFAInfo &MBBInfo) {
// Outgoing cfa offset set by the block.
- int64_t &OutgoingCFAOffset = MBBInfo.OutgoingCFAOffset;
+ StackOffset &OutgoingCFAOffset = MBBInfo.OutgoingCFAOffset;
OutgoingCFAOffset = MBBInfo.IncomingCFAOffset;
// Outgoing cfa register set by the block.
unsigned &OutgoingCFARegister = MBBInfo.OutgoingCFARegister;
@@ -245,22 +252,28 @@ void CFIInstrInserter::calculateOutgoingCFAInfo(MBBCFAInfo &MBBInfo) {
break;
}
case MCCFIInstruction::OpDefCfaOffset: {
- OutgoingCFAOffset = CFI.getOffset();
+ OutgoingCFAOffset = StackOffset::getFixed(CFI.getOffset());
break;
}
case MCCFIInstruction::OpAdjustCfaOffset: {
- OutgoingCFAOffset += CFI.getOffset();
+ OutgoingCFAOffset += StackOffset::getFixed(CFI.getOffset());
break;
}
case MCCFIInstruction::OpDefCfa: {
OutgoingCFARegister = CFI.getRegister();
- OutgoingCFAOffset = CFI.getOffset();
+ OutgoingCFAOffset = StackOffset::getFixed(CFI.getOffset());
+ break;
+ }
+ case MCCFIInstruction::OpLLVMDefCfaRegScalableOffset: {
+ OutgoingCFARegister = CFI.getRegister2();
+ OutgoingCFAOffset =
+ StackOffset::get(CFI.getFixedOffset(), CFI.getScalableOffset());
break;
}
case MCCFIInstruction::OpOffset: {
CSRSavedLocation &CSRLocation = OutgoingCSRLocations[CFI.getRegister()];
CSRLocation.K = CSRSavedLocation::Kind::CFA_OFFSET;
- CSRLocation.Offset = CFI.getOffset();
+ CSRLocation.Offset = StackOffset::getFixed(CFI.getOffset());
break;
}
case MCCFIInstruction::OpRegister: {
@@ -272,7 +285,23 @@ void CFIInstrInserter::calculateOutgoingCFAInfo(MBBCFAInfo &MBBInfo) {
case MCCFIInstruction::OpRelOffset: {
CSRSavedLocation &CSRLocation = OutgoingCSRLocations[CFI.getRegister()];
CSRLocation.K = CSRSavedLocation::Kind::CFA_OFFSET;
- CSRLocation.Offset = CFI.getOffset() - OutgoingCFAOffset;
+ CSRLocation.Offset =
+ StackOffset::getFixed(CFI.getOffset()) - OutgoingCFAOffset;
+ break;
+ }
+ case MCCFIInstruction::OpLLVMRegAtScalableOffsetFromCfa: {
+ CSRSavedLocation &CSRLocation = OutgoingCSRLocations[CFI.getRegister()];
+ CSRLocation.K = CSRSavedLocation::Kind::CFA_OFFSET;
+ CSRLocation.Offset =
+ StackOffset::get(CFI.getFixedOffset(), CFI.getScalableOffset());
+ break;
+ }
+ case MCCFIInstruction::OpLLVMRegAtScalableOffsetFromReg: {
+ CSRSavedLocation &CSRLocation = OutgoingCSRLocations[CFI.getRegister()];
+ CSRLocation.K = CSRSavedLocation::Kind::REG_OFFSET;
+ CSRLocation.Reg = CFI.getRegister2();
+ CSRLocation.Offset =
+ StackOffset::get(CFI.getFixedOffset(), CFI.getScalableOffset());
break;
}
case MCCFIInstruction::OpRestore: {
@@ -325,10 +354,6 @@ void CFIInstrInserter::calculateOutgoingCFAInfo(MBBCFAInfo &MBBInfo) {
case MCCFIInstruction::OpLabel:
case MCCFIInstruction::OpValOffset:
break;
- case MCCFIInstruction::OpLLVMDefCfaRegScalableOffset:
- case MCCFIInstruction::OpLLVMRegAtScalableOffsetFromCfa:
- case MCCFIInstruction::OpLLVMRegAtScalableOffsetFromReg:
- llvm_unreachable("not implemented");
}
}
}
@@ -386,10 +411,19 @@ bool CFIInstrInserter::insertCFIInstrs(MachineFunction &MF) {
ForceFullCFA) {
// If both outgoing offset and register of a previous block don't match
// incoming offset and register of this block, or if this block begins a
- // section, add a def_cfa instruction with the correct offset and
- // register for this block.
- unsigned CFIIndex = MF.addFrameInst(MCCFIInstruction::cfiDefCfa(
- nullptr, MBBInfo.IncomingCFARegister, getCorrectCFAOffset(&MBB)));
+ // section, add a def_cfa (or llvm_def_cfa_reg_scalable_offset)
+ // instruction with the correct offset and register for this block.
+ StackOffset CorrectOffset = getCorrectCFAOffset(&MBB);
+ unsigned CFIIndex = (unsigned)(-1);
+ if (CorrectOffset.getScalable() == 0) {
+ CFIIndex = MF.addFrameInst(MCCFIInstruction::cfiDefCfa(
+ nullptr, MBBInfo.IncomingCFARegister, CorrectOffset.getFixed()));
+ } else {
+ CFIIndex =
+ MF.addFrameInst(MCCFIInstruction::createLLVMDefCfaRegScalableOffset(
+ nullptr, MBBInfo.IncomingCFARegister,
+ CorrectOffset.getScalable(), CorrectOffset.getFixed()));
+ }
BuildMI(*MBBInfo.MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION))
.addCFIIndex(CFIIndex);
InsertedCFIInstr = true;
@@ -397,8 +431,18 @@ bool CFIInstrInserter::insertCFIInstrs(MachineFunction &MF) {
// If outgoing offset of a previous block doesn't match incoming offset
// of this block, add a def_cfa_offset instruction with the correct
// offset for this block.
- unsigned CFIIndex = MF.addFrameInst(MCCFIInstruction::cfiDefCfaOffset(
- nullptr, getCorrectCFAOffset(&MBB)));
+ // If offset is scalable, add cfi_llvm_def_cfa_reg_scalable_offset
+ StackOffset CorrectOffset = getCorrectCFAOffset(&MBB);
+ unsigned CFIIndex = (unsigned)(-1);
+ if (CorrectOffset.getScalable() == 0) {
+ CFIIndex = MF.addFrameInst(MCCFIInstruction::cfiDefCfaOffset(
+ nullptr, CorrectOffset.getFixed()));
+ } else {
+ CFIIndex =
+ MF.addFrameInst(MCCFIInstruction::createLLVMDefCfaRegScalableOffset(
+ nullptr, MBBInfo.IncomingCFARegister,
+ CorrectOffset.getScalable(), CorrectOffset.getFixed()));
+ }
BuildMI(*MBBInfo.MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION))
.addCFIIndex(CFIIndex);
InsertedCFIInstr = true;
@@ -431,12 +475,21 @@ bool CFIInstrInserter::insertCFIInstrs(MachineFunction &MF) {
continue;
unsigned CFIIndex = (unsigned)(-1);
- if (HasToBeCSRLoc.K == CSRSavedLocation::Kind::CFA_OFFSET &&
- HasToBeCSRLoc.Offset != PrevOutgoingCSRLoc.Offset) {
- CFIIndex = MF.addFrameInst(
- MCCFIInstruction::createOffset(nullptr, i, HasToBeCSRLoc.Offset));
- } else if (HasToBeCSRLoc.K == CSRSavedLocation::Kind::REGISTER &&
- (HasToBeCSRLoc.Reg != PrevOutgoingCSRLoc.Reg)) {
+ switch (HasToBeCSRLoc.K) {
+ case CSRSavedLocation::Kind::CFA_OFFSET: {
+ StackOffset CorrectOffset = HasToBeCSRLoc.Offset;
+ if (CorrectOffset.getScalable() == 0) {
+ CFIIndex = MF.addFrameInst(MCCFIInstruction::createOffset(
+ nullptr, i, CorrectOffset.getFixed()));
+ } else {
+ CFIIndex = MF.addFrameInst(
+ MCCFIInstruction::createLLVMRegAtScalableOffsetFromCfa(
+ nullptr, i, CorrectOffset.getScalable(),
+ CorrectOffset.getFixed()));
+ }
+ break;
+ }
+ case CSRSavedLocation::Kind::REGISTER: {
unsigned NewReg = HasToBeCSRLoc.Reg;
unsigned DwarfEHReg = i;
if (NewReg == DwarfEHReg) {
@@ -446,8 +499,20 @@ bool CFIInstrInserter::insertCFIInstrs(MachineFunction &MF) {
CFIIndex = MF.addFrameInst(
MCCFIInstruction::createRegister(nullptr, i, HasToBeCSRLoc.Reg));
}
- } else
+ break;
+ }
+ case CSRSavedLocation::Kind::REG_OFFSET: {
+ StackOffset CorrectOffset = HasToBeCSRLoc.Offset;
+ unsigned CorrectReg = HasToBeCSRLoc.Reg;
+ CFIIndex = MF.addFrameInst(
+ MCCFIInstruction::createLLVMRegAtScalableOffsetFromReg(
+ nullptr, i, CorrectReg, CorrectOffset.getScalable(),
+ CorrectOffset.getFixed()));
+ break;
+ }
+ default:
llvm_unreachable("Unexpected CSR location.");
+ }
BuildMI(*MBBInfo.MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION))
.addCFIIndex(CFIIndex);
InsertedCFIInstr = true;
@@ -467,11 +532,15 @@ void CFIInstrInserter::reportCFAError(const MBBCFAInfo &Pred,
<< " outgoing CFA Reg:" << Pred.OutgoingCFARegister << "\n";
errs() << "Pred: " << Pred.MBB->getName() << " #" << Pred.MBB->getNumber()
<< " in " << Pred.MBB->getParent()->getName()
- << " outgoing CFA Offset:" << Pred.OutgoingCFAOffset << "\n";
+ << " outgoing CFA Offset: (fixed: "
+ << Pred.OutgoingCFAOffset.getFixed()
+ << ", scalable: " << Pred.OutgoingCFAOffset.getScalable() << ")\n";
errs() << "Succ: " << Succ.MBB->getName() << " #" << Succ.MBB->getNumber()
<< " incoming CFA Reg:" << Succ.IncomingCFARegister << "\n";
errs() << "Succ: " << Succ.MBB->getName() << " #" << Succ.MBB->getNumber()
- << " incoming CFA Offset:" << Succ.IncomingCFAOffset << "\n";
+ << " incoming CFA Offset: (fixed: "
+ << Succ.IncomingCFAOffset.getFixed()
+ << ", scalable: " << Succ.IncomingCFAOffset.getFixed() << ")\n";
}
void CFIInstrInserter::reportCSRError(const MBBCFAInfo &Pred,
diff --git a/llvm/test/CodeGen/RISCV/cfi-inserter-scalable-offset.mir b/llvm/test/CodeGen/RISCV/cfi-inserter-scalable-offset.mir
index 17fde2dcc86dc..7ae74ebf8ca95 100644
--- a/llvm/test/CodeGen/RISCV/cfi-inserter-scalable-offset.mir
+++ b/llvm/test/CodeGen/RISCV/cfi-inserter-scalable-offset.mir
@@ -3,14 +3,10 @@
# RUN: -run-pass=prologepilog,cfi-instr-inserter \
# RUN: -riscv-enable-cfi-instr-inserter=true \
# RUN: -o - | FileCheck %s
-# XFAIL: *
#
# In this test prolog will be inserted in bb.3. We need to save the scalable vector register v1.
# In bb.3 the new rule for computing CFA will be (sp + 16 + 1 * vlenb) which we encode using cfi_escape. Also, $v1 will be saved at (cfa - 1 * vlenb), which we also encode using cfi_escape.
# Since the only way to get to bb.2 is from bb.3, the same cfi's should be emitted at beginning of bb.2
-#
-# Currently CFIInstrInserter can't handle escape, so we end up with wrong CFI.
-# NOTE: if llc was compiled with NDEBUG, this will just crash. Otherwise, the output will be as in CHECK lines.
--- |
@@ -48,7 +44,8 @@ body: |
; CHECK-NEXT: bb.2:
; CHECK-NEXT: successors: %bb.1(0x80000000)
; CHECK-NEXT: {{ $}}
- ; CHECK-NEXT: CFI_INSTRUCTION def_cfa_offset 16
+ ; CHECK-NEXT: CFI_INSTRUCTION llvm_def_cfa_reg_scalable_offset $x2, 1, 16
+ ; CHECK-NEXT: CFI_INSTRUCTION llvm_reg_at_scalable_offset_from_cfa $v1, -1, 0
; CHECK-NEXT: $x10 = ADDI $x2, 16
; CHECK-NEXT: $v1 = frame-destroy VL1RE8_V killed $x10 :: (load (<vscale x 1 x s64>) from %stack.0)
; CHECK-NEXT: $x10 = frame-destroy PseudoReadVLENB
@@ -67,10 +64,10 @@ body: |
; CHECK-NEXT: frame-setup CFI_INSTRUCTION def_cfa_offset 16
; CHECK-NEXT: $x12 = frame-setup PseudoReadVLENB
; CHECK-NEXT: $x2 = frame-setup SUB $x2, killed $x12
- ; CHECK-NEXT: frame-setup CFI_INSTRUCTION escape 0x0f, 0x0d, 0x72, 0x00, 0x11, 0x10, 0x22, 0x11, 0x01, 0x92, 0xa2, 0x38, 0x00, 0x1e, 0x22
+ ; CHECK-NEXT: frame-setup CFI_INSTRUCTION llvm_def_cfa_reg_scalable_offset $x2, 1, 16
; CHECK-NEXT: $x12 = ADDI $x2, 16
; CHECK-NEXT: frame-setup VS1R_V killed $v1, killed $x12 :: (store (<vscale x 1 x s64>) into %stack.0)
- ; CHECK-NEXT: frame-setup CFI_INSTRUCTION escape 0x10, 0x61, 0x08, 0x11, 0x7f, 0x92, 0xa2, 0x38, 0x00, 0x1e, 0x22
+ ; CHECK-NEXT: frame-setup CFI_INSTRUCTION llvm_reg_at_scalable_offset_from_cfa $v1, -1, 0
; CHECK-NEXT: dead $x0 = PseudoVSETIVLI 4, 208 /* e32, m1, ta, ma */, implicit-def $vl, implicit-def $vtype
; CHECK-NEXT: renamable $v1 = PseudoVLE32_V_M1 undef renamable $v1, killed renamable $x10, 4, 5 /* e32 */, 2 /* tu, ma */, implicit $vl, implicit $vtype
; CHECK-NEXT: PseudoVSE32_V_M1 killed renamable $v1, killed renamable $x11, 4, 5 /* e32 */, implicit $vl, implicit $vtype
More information about the llvm-branch-commits
mailing list