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 <[email protected]>

>From f621b6515740a279d51fc4ced44967b103987d13 Mon Sep 17 00:00:00 2001
From: Mikhail Gudim <[email protected]>
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 <[email protected]>
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 <[email protected]>
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

_______________________________________________
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits

Reply via email to