https://github.com/slinder1 updated 
https://github.com/llvm/llvm-project/pull/164721

>From 04d8928355220a82c00d9ad9e251e4838bac5d08 Mon Sep 17 00:00:00 2001
From: Emma Pilkington <[email protected]>
Date: Thu, 19 Jun 2025 10:59:31 -0400
Subject: [PATCH 1/2] [MC][Dwarf] Add custom CFI pseudo-ops for use in AMDGPU

While these can be represented with .cfi_escape, using these pseudo-cfi
instructions makes .s/.mir files more readable, and it is necessary to
support updating registers in CFI instructions (something that the
AMDGPU backend requires).
---
 llvm/include/llvm/MC/MCDwarf.h                |  92 ++++++++-
 llvm/include/llvm/MC/MCStreamer.h             |  18 ++
 .../CodeGen/AsmPrinter/AsmPrinterDwarf.cpp    |  33 ++++
 llvm/lib/CodeGen/CFIInstrInserter.cpp         |   4 +
 llvm/lib/CodeGen/MIRParser/MILexer.cpp        |   5 +
 llvm/lib/CodeGen/MIRParser/MILexer.h          |   4 +
 llvm/lib/CodeGen/MIRParser/MIParser.cpp       |  75 +++++++
 llvm/lib/CodeGen/MachineOperand.cpp           |  58 ++++++
 llvm/lib/DWARFCFIChecker/DWARFCFIState.cpp    |  10 +
 llvm/lib/MC/MCAsmStreamer.cpp                 |  76 +++++++
 llvm/lib/MC/MCDwarf.cpp                       | 186 ++++++++++++++++++
 llvm/lib/MC/MCParser/AsmParser.cpp            | 106 ++++++++++
 llvm/lib/MC/MCParser/MasmParser.cpp           |   4 +
 llvm/lib/MC/MCStreamer.cpp                    |  54 +++++
 .../heterogeneous-dwarf-cfi-directives.s      |  57 ++++++
 llvm/test/MC/ELF/cfi-register-pair.s          |  56 ++++++
 llvm/test/MC/ELF/cfi-vector-offset.s          |  56 ++++++
 llvm/test/MC/ELF/cfi-vector-registers.s       |  56 ++++++
 18 files changed, 949 insertions(+), 1 deletion(-)
 create mode 100644 
llvm/test/DebugInfo/AMDGPU/heterogeneous-dwarf-cfi-directives.s
 create mode 100644 llvm/test/MC/ELF/cfi-register-pair.s
 create mode 100644 llvm/test/MC/ELF/cfi-vector-offset.s
 create mode 100644 llvm/test/MC/ELF/cfi-vector-registers.s

diff --git a/llvm/include/llvm/MC/MCDwarf.h b/llvm/include/llvm/MC/MCDwarf.h
index 640d2eeb68d61..e602f03de5ebf 100644
--- a/llvm/include/llvm/MC/MCDwarf.h
+++ b/llvm/include/llvm/MC/MCDwarf.h
@@ -530,6 +530,10 @@ class MCCFIInstruction {
     OpGnuArgsSize,
     OpLabel,
     OpValOffset,
+    OpLLVMRegisterPair,
+    OpLLVMVectorRegisters,
+    OpLLVMVectorOffset,
+    OpLLVMVectorRegisterMask,
   };
 
   // Held in ExtraFields for most common OpTypes, exceptions follow.
@@ -548,10 +552,45 @@ class MCCFIInstruction {
   struct LabelFields {
     MCSymbol *CfiLabel = nullptr;
   };
+  /// Held in ExtraFields when OpLLVMRegisterPair.
+  struct RegisterPairFields {
+    unsigned Register;
+    unsigned Reg1, Reg2;
+    unsigned Reg1SizeInBits, Reg2SizeInBits;
+  };
+  struct VectorRegisterWithLane {
+    unsigned Register;
+    unsigned Lane;
+    unsigned SizeInBits;
+  };
+  /// Held in ExtraFields when OpLLVMVectorRegisters.
+  struct VectorRegistersFields {
+    unsigned Register;
+    std::vector<VectorRegisterWithLane> VectorRegisters;
+  };
+  /// Held in ExtraFields when OpLLVMVectorOffset.
+  struct VectorOffsetFields {
+    unsigned Register;
+    unsigned RegisterSizeInBits;
+    int64_t Offset;
+    unsigned MaskRegister;
+    unsigned MaskRegisterSizeInBits;
+  };
+  /// Held in ExtraFields when OpLLVMVectorRegisterMask.
+  struct VectorRegisterMaskFields {
+    unsigned Register;
+    unsigned SpillRegister;
+    unsigned SpillRegisterLaneSizeInBits;
+    unsigned MaskRegister;
+    unsigned MaskRegisterSizeInBits;
+  };
 
 private:
   MCSymbol *Label;
-  std::variant<CommonFields, EscapeFields, LabelFields> ExtraFields;
+  std::variant<CommonFields, EscapeFields, LabelFields, RegisterPairFields,
+               VectorRegistersFields, VectorOffsetFields,
+               VectorRegisterMaskFields>
+      ExtraFields;
   OpType Operation;
   SMLoc Loc;
 
@@ -694,6 +733,57 @@ class MCCFIInstruction {
     return {OpLabel, L, LabelFields{CfiLabel}, Loc};
   }
 
+  /// .cfi_llvm_register_pair Previous value of Register is saved in R1:R2.
+  static MCCFIInstruction
+  createLLVMRegisterPair(MCSymbol *L, unsigned Register, unsigned R1,
+                         unsigned R1SizeInBits, unsigned R2,
+                         unsigned R2SizeInBits, SMLoc Loc = {}) {
+    RegisterPairFields Extra{Register, R1, R2, R1SizeInBits, R2SizeInBits};
+    return {OpLLVMRegisterPair, L, Extra, Loc};
+  }
+
+  /// .cfi_llvm_vector_registers Previous value of Register is saved in lanes 
of
+  /// vector registers.
+  static MCCFIInstruction
+  createLLVMVectorRegisters(MCSymbol *L, unsigned Register,
+                            std::vector<VectorRegisterWithLane> 
VectorRegisters,
+                            SMLoc Loc = {}) {
+    VectorRegistersFields Extra{Register, std::move(VectorRegisters)};
+    return {OpLLVMVectorRegisters, L, std::move(Extra), Loc};
+  }
+
+  /// .cfi_llvm_vector_offset Previous value of Register is saved at Offset 
from
+  /// CFA. MaskRegister specifies the active lanes of register.
+  static MCCFIInstruction
+  createLLVMVectorOffset(MCSymbol *L, unsigned Register,
+                         unsigned RegisterSizeInBits, unsigned MaskRegister,
+                         unsigned MaskRegisterSizeInBits, int64_t Offset,
+                         SMLoc Loc = {}) {
+    VectorOffsetFields Extra{Register, RegisterSizeInBits, Offset, 
MaskRegister,
+                             MaskRegisterSizeInBits};
+    return MCCFIInstruction(OpLLVMVectorOffset, L, Extra, Loc);
+  }
+
+  /// .cfi_llvm_vector_register_mask Previous value of Register is saved in
+  /// SpillRegister, predicated on the value of MaskRegister.
+  static MCCFIInstruction createLLVMVectorRegisterMask(
+      MCSymbol *L, unsigned Register, unsigned SpillRegister,
+      unsigned SpillRegisterLaneSizeInBits, unsigned MaskRegister,
+      unsigned MaskRegisterSizeInBits, SMLoc Loc = {}) {
+    VectorRegisterMaskFields Extra{
+        Register,     SpillRegister,          SpillRegisterLaneSizeInBits,
+        MaskRegister, MaskRegisterSizeInBits,
+    };
+    return MCCFIInstruction(OpLLVMVectorRegisterMask, L, Extra, Loc);
+  }
+
+  template <class ExtraFieldsTy> ExtraFieldsTy &getExtraFields() {
+    return std::get<ExtraFieldsTy>(ExtraFields);
+  }
+
+  template <class ExtraFieldsTy> const ExtraFieldsTy &getExtraFields() const {
+    return std::get<ExtraFieldsTy>(ExtraFields);
+  }
   /// .cfi_val_offset Previous value of Register is offset Offset from the
   /// current CFA register.
   static MCCFIInstruction createValOffset(MCSymbol *L, unsigned Register,
diff --git a/llvm/include/llvm/MC/MCStreamer.h 
b/llvm/include/llvm/MC/MCStreamer.h
index 79c715e3820a6..4e76aa323eb30 100644
--- a/llvm/include/llvm/MC/MCStreamer.h
+++ b/llvm/include/llvm/MC/MCStreamer.h
@@ -1012,6 +1012,24 @@ class LLVM_ABI MCStreamer {
                                SMLoc Loc = {});
   virtual void emitCFIWindowSave(SMLoc Loc = {});
   virtual void emitCFINegateRAState(SMLoc Loc = {});
+  virtual void emitCFILLVMRegisterPair(int64_t Register, int64_t R1,
+                                       int64_t R1SizeInBits, int64_t R2,
+                                       int64_t R2SizeInBits, SMLoc Loc = {});
+  virtual void emitCFILLVMVectorRegisters(
+      int64_t Register,
+      std::vector<MCCFIInstruction::VectorRegisterWithLane> VRs,
+      SMLoc Loc = {});
+  virtual void emitCFILLVMVectorOffset(int64_t Register,
+                                       int64_t RegisterSizeInBits,
+                                       int64_t MaskRegister,
+                                       int64_t MaskRegisterSizeInBits,
+                                       int64_t Offset, SMLoc Loc = {});
+  virtual void
+  emitCFILLVMVectorRegisterMask(int64_t Register, int64_t SpillRegister,
+                                int64_t SpillRegisterLaneSizeInBits,
+                                int64_t MaskRegister,
+                                int64_t MaskRegisterSizeInBits, SMLoc Loc = 
{});
+
   virtual void emitCFINegateRAStateWithPC(SMLoc Loc = {});
   virtual void emitCFILabelDirective(SMLoc Loc, StringRef Name);
   virtual void emitCFIValOffset(int64_t Register, int64_t Offset,
diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinterDwarf.cpp 
b/llvm/lib/CodeGen/AsmPrinter/AsmPrinterDwarf.cpp
index 2a146eb15f709..895c18abc56f9 100644
--- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinterDwarf.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinterDwarf.cpp
@@ -260,6 +260,39 @@ void AsmPrinter::emitCFIInstruction(const MCCFIInstruction 
&Inst) const {
   case MCCFIInstruction::OpRestoreState:
     OutStreamer->emitCFIRestoreState(Loc);
     break;
+  case MCCFIInstruction::OpLLVMRegisterPair: {
+    const auto &Fields =
+        Inst.getExtraFields<MCCFIInstruction::RegisterPairFields>();
+    OutStreamer->emitCFILLVMRegisterPair(Fields.Register, Fields.Reg1,
+                                         Fields.Reg1SizeInBits, Fields.Reg2,
+                                         Fields.Reg2SizeInBits, Loc);
+    break;
+  }
+  case MCCFIInstruction::OpLLVMVectorRegisters: {
+    const auto &Fields =
+        Inst.getExtraFields<MCCFIInstruction::VectorRegistersFields>();
+    OutStreamer->emitCFILLVMVectorRegisters(Fields.Register,
+                                            Fields.VectorRegisters, Loc);
+    break;
+  }
+  case MCCFIInstruction::OpLLVMVectorOffset: {
+    const auto &Fields =
+        Inst.getExtraFields<MCCFIInstruction::VectorOffsetFields>();
+    OutStreamer->emitCFILLVMVectorOffset(
+        Fields.Register, Fields.RegisterSizeInBits, Fields.MaskRegister,
+        Fields.MaskRegisterSizeInBits, Fields.Offset, Loc);
+    break;
+  }
+  case MCCFIInstruction::OpLLVMVectorRegisterMask: {
+    const auto &Fields =
+        Inst.getExtraFields<MCCFIInstruction::VectorRegisterMaskFields>();
+    OutStreamer->emitCFILLVMVectorRegisterMask(
+        Fields.Register, Fields.SpillRegister,
+        Fields.SpillRegisterLaneSizeInBits, Fields.MaskRegister,
+        Fields.MaskRegisterSizeInBits);
+    break;
+  }
+
   case MCCFIInstruction::OpValOffset:
     OutStreamer->emitCFIValOffset(Inst.getRegister(), Inst.getOffset(), Loc);
     break;
diff --git a/llvm/lib/CodeGen/CFIInstrInserter.cpp 
b/llvm/lib/CodeGen/CFIInstrInserter.cpp
index 1a0e222da98cd..73458fbf57286 100644
--- a/llvm/lib/CodeGen/CFIInstrInserter.cpp
+++ b/llvm/lib/CodeGen/CFIInstrInserter.cpp
@@ -262,6 +262,10 @@ void CFIInstrInserter::calculateOutgoingCFAInfo(MBBCFAInfo 
&MBBInfo) {
       case MCCFIInstruction::OpNegateRAState:
       case MCCFIInstruction::OpNegateRAStateWithPC:
       case MCCFIInstruction::OpGnuArgsSize:
+      case MCCFIInstruction::OpLLVMRegisterPair:
+      case MCCFIInstruction::OpLLVMVectorRegisters:
+      case MCCFIInstruction::OpLLVMVectorOffset:
+      case MCCFIInstruction::OpLLVMVectorRegisterMask:
       case MCCFIInstruction::OpLabel:
       case MCCFIInstruction::OpValOffset:
         break;
diff --git a/llvm/lib/CodeGen/MIRParser/MILexer.cpp 
b/llvm/lib/CodeGen/MIRParser/MILexer.cpp
index 8b72c295416a2..8ed590669a3b0 100644
--- a/llvm/lib/CodeGen/MIRParser/MILexer.cpp
+++ b/llvm/lib/CodeGen/MIRParser/MILexer.cpp
@@ -240,6 +240,11 @@ static MIToken::TokenKind getIdentifierKind(StringRef 
Identifier) {
       .Case("window_save", MIToken::kw_cfi_window_save)
       .Case("negate_ra_sign_state",
             MIToken::kw_cfi_aarch64_negate_ra_sign_state)
+      .Case("llvm_register_pair", MIToken::kw_cfi_llvm_register_pair)
+      .Case("llvm_vector_registers", MIToken::kw_cfi_llvm_vector_registers)
+      .Case("llvm_vector_offset", MIToken::kw_cfi_llvm_vector_offset)
+      .Case("llvm_vector_register_mask",
+            MIToken::kw_cfi_llvm_vector_register_mask)
       .Case("negate_ra_sign_state_with_pc",
             MIToken::kw_cfi_aarch64_negate_ra_sign_state_with_pc)
       .Case("blockaddress", MIToken::kw_blockaddress)
diff --git a/llvm/lib/CodeGen/MIRParser/MILexer.h 
b/llvm/lib/CodeGen/MIRParser/MILexer.h
index 0627f176b9e00..abac1880f94e0 100644
--- a/llvm/lib/CodeGen/MIRParser/MILexer.h
+++ b/llvm/lib/CodeGen/MIRParser/MILexer.h
@@ -98,6 +98,10 @@ struct MIToken {
     kw_cfi_undefined,
     kw_cfi_window_save,
     kw_cfi_aarch64_negate_ra_sign_state,
+    kw_cfi_llvm_register_pair,
+    kw_cfi_llvm_vector_registers,
+    kw_cfi_llvm_vector_offset,
+    kw_cfi_llvm_vector_register_mask,
     kw_cfi_aarch64_negate_ra_sign_state_with_pc,
     kw_blockaddress,
     kw_intrinsic,
diff --git a/llvm/lib/CodeGen/MIRParser/MIParser.cpp 
b/llvm/lib/CodeGen/MIRParser/MIParser.cpp
index 434a579c3be3f..7ff504c5122da 100644
--- a/llvm/lib/CodeGen/MIRParser/MIParser.cpp
+++ b/llvm/lib/CodeGen/MIRParser/MIParser.cpp
@@ -484,6 +484,7 @@ class MIParser {
   bool parseDILocation(MDNode *&Expr);
   bool parseMetadataOperand(MachineOperand &Dest);
   bool parseCFIOffset(int &Offset);
+  bool parseCFIUnsigned(unsigned &Value);
   bool parseCFIRegister(unsigned &Reg);
   bool parseCFIAddressSpace(unsigned &AddressSpace);
   bool parseCFIEscapeValues(std::string& Values);
@@ -2477,6 +2478,13 @@ bool MIParser::parseCFIOffset(int &Offset) {
   return false;
 }
 
+bool MIParser::parseCFIUnsigned(unsigned &Value) {
+  if (getUnsigned(Value))
+    return true;
+  lex();
+  return false;
+}
+
 bool MIParser::parseCFIRegister(unsigned &Reg) {
   if (Token.isNot(MIToken::NamedRegister))
     return error("expected a cfi register");
@@ -2610,6 +2618,69 @@ bool MIParser::parseCFIOperand(MachineOperand &Dest) {
   case MIToken::kw_cfi_aarch64_negate_ra_sign_state:
     CFIIndex = MF.addFrameInst(MCCFIInstruction::createNegateRAState(nullptr));
     break;
+  case MIToken::kw_cfi_llvm_register_pair: {
+    unsigned Reg, R1, R2;
+    unsigned R1Size, R2Size;
+    if (parseCFIRegister(Reg) || expectAndConsume(MIToken::comma) ||
+        parseCFIRegister(R1) || expectAndConsume(MIToken::comma) ||
+        parseCFIUnsigned(R1Size) || expectAndConsume(MIToken::comma) ||
+        parseCFIRegister(R2) || expectAndConsume(MIToken::comma) ||
+        parseCFIUnsigned(R2Size))
+      return true;
+
+    CFIIndex = MF.addFrameInst(MCCFIInstruction::createLLVMRegisterPair(
+        nullptr, Reg, R1, R1Size, R2, R2Size));
+    break;
+  }
+  case MIToken::kw_cfi_llvm_vector_registers: {
+    std::vector<MCCFIInstruction::VectorRegisterWithLane> VectorRegisters;
+    if (parseCFIRegister(Reg) || expectAndConsume(MIToken::comma))
+      return true;
+    do {
+      unsigned VR;
+      unsigned Lane, Size;
+      if (parseCFIRegister(VR) || expectAndConsume(MIToken::comma) ||
+          parseCFIUnsigned(Lane) || expectAndConsume(MIToken::comma) ||
+          parseCFIUnsigned(Size))
+        return true;
+      VectorRegisters.push_back({VR, Lane, Size});
+    } while (consumeIfPresent(MIToken::comma));
+
+    CFIIndex = MF.addFrameInst(MCCFIInstruction::createLLVMVectorRegisters(
+        nullptr, Reg, std::move(VectorRegisters)));
+    break;
+  }
+  case MIToken::kw_cfi_llvm_vector_offset: {
+    unsigned Reg, MaskReg;
+    unsigned RegSize, MaskRegSize;
+    int Offset = 0;
+
+    if (parseCFIRegister(Reg) || expectAndConsume(MIToken::comma) ||
+        parseCFIUnsigned(RegSize) || expectAndConsume(MIToken::comma) ||
+        parseCFIRegister(MaskReg) || expectAndConsume(MIToken::comma) ||
+        parseCFIUnsigned(MaskRegSize) || expectAndConsume(MIToken::comma) ||
+        parseCFIOffset(Offset))
+      return true;
+
+    CFIIndex = MF.addFrameInst(MCCFIInstruction::createLLVMVectorOffset(
+        nullptr, Reg, RegSize, MaskReg, MaskRegSize, Offset));
+    break;
+  }
+  case MIToken::kw_cfi_llvm_vector_register_mask: {
+    unsigned Reg, SpillReg, MaskReg;
+    unsigned SpillRegLaneSize, MaskRegSize;
+
+    if (parseCFIRegister(Reg) || expectAndConsume(MIToken::comma) ||
+        parseCFIRegister(SpillReg) || expectAndConsume(MIToken::comma) ||
+        parseCFIUnsigned(SpillRegLaneSize) ||
+        expectAndConsume(MIToken::comma) || parseCFIRegister(MaskReg) ||
+        expectAndConsume(MIToken::comma) || parseCFIUnsigned(MaskRegSize))
+      return true;
+
+    CFIIndex = MF.addFrameInst(MCCFIInstruction::createLLVMVectorRegisterMask(
+        nullptr, Reg, SpillReg, SpillRegLaneSize, MaskReg, MaskRegSize));
+    break;
+  }
   case MIToken::kw_cfi_aarch64_negate_ra_sign_state_with_pc:
     CFIIndex =
         MF.addFrameInst(MCCFIInstruction::createNegateRAStateWithPC(nullptr));
@@ -2967,6 +3038,10 @@ bool MIParser::parseMachineOperand(const unsigned 
OpCode, const unsigned OpIdx,
   case MIToken::kw_cfi_undefined:
   case MIToken::kw_cfi_window_save:
   case MIToken::kw_cfi_aarch64_negate_ra_sign_state:
+  case MIToken::kw_cfi_llvm_register_pair:
+  case MIToken::kw_cfi_llvm_vector_registers:
+  case MIToken::kw_cfi_llvm_vector_offset:
+  case MIToken::kw_cfi_llvm_vector_register_mask:
   case MIToken::kw_cfi_aarch64_negate_ra_sign_state_with_pc:
     return parseCFIOperand(Dest);
   case MIToken::kw_blockaddress:
diff --git a/llvm/lib/CodeGen/MachineOperand.cpp 
b/llvm/lib/CodeGen/MachineOperand.cpp
index 8c6d2194433d0..7dfed81690d29 100644
--- a/llvm/lib/CodeGen/MachineOperand.cpp
+++ b/llvm/lib/CodeGen/MachineOperand.cpp
@@ -780,6 +780,64 @@ static void printCFI(raw_ostream &OS, const 
MCCFIInstruction &CFI,
     if (MCSymbol *Label = CFI.getLabel())
       MachineOperand::printSymbol(OS, *Label);
     break;
+  case MCCFIInstruction::OpLLVMRegisterPair: {
+    const auto &Fields =
+        CFI.getExtraFields<MCCFIInstruction::RegisterPairFields>();
+
+    OS << "llvm_register_pair ";
+    if (MCSymbol *Label = CFI.getLabel())
+      MachineOperand::printSymbol(OS, *Label);
+    printCFIRegister(Fields.Register, OS, TRI);
+    OS << ", ";
+    printCFIRegister(Fields.Reg1, OS, TRI);
+    OS << ", " << Fields.Reg1SizeInBits << ", ";
+    printCFIRegister(Fields.Reg2, OS, TRI);
+    OS << ", " << Fields.Reg2SizeInBits;
+    break;
+  }
+  case MCCFIInstruction::OpLLVMVectorRegisters: {
+    const auto &Fields =
+        CFI.getExtraFields<MCCFIInstruction::VectorRegistersFields>();
+
+    OS << "llvm_vector_registers ";
+    if (MCSymbol *Label = CFI.getLabel())
+      MachineOperand::printSymbol(OS, *Label);
+    printCFIRegister(Fields.Register, OS, TRI);
+    for (auto [Reg, Lane, Size] : Fields.VectorRegisters) {
+      OS << ", ";
+      printCFIRegister(Reg, OS, TRI);
+      OS << ", " << Lane << ", " << Size;
+    }
+    break;
+  }
+  case MCCFIInstruction::OpLLVMVectorOffset: {
+    const auto &Fields =
+        CFI.getExtraFields<MCCFIInstruction::VectorOffsetFields>();
+
+    OS << "llvm_vector_offset ";
+    if (MCSymbol *Label = CFI.getLabel())
+      MachineOperand::printSymbol(OS, *Label);
+    printCFIRegister(Fields.Register, OS, TRI);
+    OS << ", " << Fields.RegisterSizeInBits << ", ";
+    printCFIRegister(Fields.MaskRegister, OS, TRI);
+    OS << ", " << Fields.MaskRegisterSizeInBits << ", " << Fields.Offset;
+    break;
+  }
+  case MCCFIInstruction::OpLLVMVectorRegisterMask: {
+    const auto &Fields =
+        CFI.getExtraFields<MCCFIInstruction::VectorRegisterMaskFields>();
+
+    OS << "llvm_vector_register_mask ";
+    if (MCSymbol *Label = CFI.getLabel())
+      MachineOperand::printSymbol(OS, *Label);
+    printCFIRegister(Fields.Register, OS, TRI);
+    OS << ", ";
+    printCFIRegister(Fields.SpillRegister, OS, TRI);
+    OS << ", " << Fields.SpillRegisterLaneSizeInBits << ", ";
+    printCFIRegister(Fields.MaskRegister, OS, TRI);
+    OS << ", " << Fields.MaskRegisterSizeInBits;
+    break;
+  }
   case MCCFIInstruction::OpNegateRAStateWithPC:
     OS << "negate_ra_sign_state_with_pc ";
     if (MCSymbol *Label = CFI.getLabel())
diff --git a/llvm/lib/DWARFCFIChecker/DWARFCFIState.cpp 
b/llvm/lib/DWARFCFIChecker/DWARFCFIState.cpp
index 4acc064dbc212..2918ba1de652f 100644
--- a/llvm/lib/DWARFCFIChecker/DWARFCFIState.cpp
+++ b/llvm/lib/DWARFCFIChecker/DWARFCFIState.cpp
@@ -160,6 +160,16 @@ dwarf::CFIProgram DWARFCFIState::convert(MCCFIInstruction 
Directive) {
     CFIP.addInstruction(dwarf::DW_CFA_val_offset, Directive.getRegister(),
                         Directive.getOffset());
     break;
+  case MCCFIInstruction::OpLLVMRegisterPair:
+  case MCCFIInstruction::OpLLVMVectorRegisters:
+  case MCCFIInstruction::OpLLVMVectorOffset:
+  case MCCFIInstruction::OpLLVMVectorRegisterMask:
+    // TODO: These should be pretty straightforward to support, but is low
+    // priority. Similarly the implementation of OpLLVMDefAspaceCfa above
+    // seem incomplete and should be fixed.
+    Context->reportWarning(Directive.getLoc(),
+                           "this directive is not supported, ignoring it");
+    break;
   }
 
   return CFIP;
diff --git a/llvm/lib/MC/MCAsmStreamer.cpp b/llvm/lib/MC/MCAsmStreamer.cpp
index 885fa55b65d50..930683c447931 100644
--- a/llvm/lib/MC/MCAsmStreamer.cpp
+++ b/llvm/lib/MC/MCAsmStreamer.cpp
@@ -369,6 +369,21 @@ class MCAsmStreamer final : public MCStreamer {
   void emitCFINegateRAState(SMLoc Loc) override;
   void emitCFINegateRAStateWithPC(SMLoc Loc) override;
   void emitCFIReturnColumn(int64_t Register) override;
+  void emitCFILLVMRegisterPair(int64_t Register, int64_t R1, int64_t R1Size,
+                               int64_t R2, int64_t R2Size, SMLoc Loc) override;
+  void emitCFILLVMVectorRegisters(
+      int64_t Register,
+      std::vector<MCCFIInstruction::VectorRegisterWithLane> VRs,
+      SMLoc Loc) override;
+  void emitCFILLVMVectorOffset(int64_t Register, int64_t RegisterSize,
+                               int64_t MaskRegister, int64_t MaskRegisterSize,
+                               int64_t Offset, SMLoc Loc) override;
+  void emitCFILLVMVectorRegisterMask(int64_t Register, int64_t SpillRegister,
+                                     int64_t SpillRegisterLaneSizeInBits,
+                                     int64_t MaskRegister,
+                                     int64_t MaskRegisterSizeInBits,
+                                     SMLoc Loc) override;
+
   void emitCFILabelDirective(SMLoc Loc, StringRef Name) override;
   void emitCFIValOffset(int64_t Register, int64_t Offset, SMLoc Loc) override;
 
@@ -2101,6 +2116,67 @@ void MCAsmStreamer::emitCFIRegister(int64_t Register1, 
int64_t Register2,
   EmitEOL();
 }
 
+void MCAsmStreamer::emitCFILLVMRegisterPair(int64_t Register, int64_t R1,
+                                            int64_t R1Size, int64_t R2,
+                                            int64_t R2Size, SMLoc Loc) {
+  MCStreamer::emitCFILLVMRegisterPair(Register, R1, R1Size, R2, R2Size, Loc);
+
+  OS << "\t.cfi_llvm_register_pair ";
+  EmitRegisterName(Register);
+  OS << ", ";
+  EmitRegisterName(R1);
+  OS << ", " << R1Size << ", ";
+  EmitRegisterName(R2);
+  OS << ", " << R2Size;
+  EmitEOL();
+}
+
+void MCAsmStreamer::emitCFILLVMVectorRegisters(
+    int64_t Register, std::vector<MCCFIInstruction::VectorRegisterWithLane> 
VRs,
+    SMLoc Loc) {
+  MCStreamer::emitCFILLVMVectorRegisters(Register, VRs, Loc);
+
+  OS << "\t.cfi_llvm_vector_registers ";
+  EmitRegisterName(Register);
+  for (auto [Reg, Lane, Size] : VRs)
+    OS << ", " << Reg << ", " << Lane << ", " << Size;
+  EmitEOL();
+}
+
+void MCAsmStreamer::emitCFILLVMVectorOffset(int64_t Register,
+                                            int64_t RegisterSize,
+                                            int64_t MaskRegister,
+                                            int64_t MaskRegisterSize,
+                                            int64_t Offset, SMLoc Loc) {
+  MCStreamer::emitCFILLVMVectorOffset(Register, RegisterSize, MaskRegister,
+                                      MaskRegisterSize, Offset, Loc);
+
+  OS << "\t.cfi_llvm_vector_offset ";
+  EmitRegisterName(Register);
+  OS << ", " << RegisterSize << ", ";
+  EmitRegisterName(MaskRegister);
+  OS << ", " << MaskRegisterSize << ", " << Offset;
+  EmitEOL();
+}
+
+void MCAsmStreamer::emitCFILLVMVectorRegisterMask(
+    int64_t Register, int64_t SpillRegister,
+    int64_t SpillRegisterLaneSizeInBits, int64_t MaskRegister,
+    int64_t MaskRegisterSizeInBits, SMLoc Loc) {
+  MCStreamer::emitCFILLVMVectorRegisterMask(
+      Register, SpillRegister, SpillRegisterLaneSizeInBits, MaskRegister,
+      MaskRegisterSizeInBits, Loc);
+
+  OS << "\t.cfi_llvm_vector_register_mask ";
+  EmitRegisterName(Register);
+  OS << ", ";
+  EmitRegisterName(SpillRegister);
+  OS << ", " << SpillRegisterLaneSizeInBits << ", ";
+  EmitRegisterName(MaskRegister);
+  OS << ", " << MaskRegisterSizeInBits;
+  EmitEOL();
+}
+
 void MCAsmStreamer::emitCFIWindowSave(SMLoc Loc) {
   MCStreamer::emitCFIWindowSave(Loc);
   OS << "\t.cfi_window_save";
diff --git a/llvm/lib/MC/MCDwarf.cpp b/llvm/lib/MC/MCDwarf.cpp
index e8f000a584839..09a93dd34ece3 100644
--- a/llvm/lib/MC/MCDwarf.cpp
+++ b/llvm/lib/MC/MCDwarf.cpp
@@ -1377,6 +1377,16 @@ static void emitEncodingByte(MCObjectStreamer &Streamer, 
unsigned Encoding) {
   Streamer.emitInt8(Encoding);
 }
 
+static void encodeDwarfRegisterLocation(int DwarfReg, raw_ostream &OS) {
+  assert(DwarfReg >= 0);
+  if (DwarfReg < 32) {
+    OS << uint8_t(dwarf::DW_OP_reg0 + DwarfReg);
+  } else {
+    OS << uint8_t(dwarf::DW_OP_regx);
+    encodeULEB128(DwarfReg, OS);
+  }
+}
+
 void FrameEmitterImpl::emitCFIInstruction(const MCCFIInstruction &Instr) {
   int dataAlignmentFactor = getDataAlignmentFactor(Streamer);
   auto *MRI = Streamer.getContext().getRegisterInfo();
@@ -1521,6 +1531,7 @@ void FrameEmitterImpl::emitCFIInstruction(const 
MCCFIInstruction &Instr) {
   case MCCFIInstruction::OpEscape:
     Streamer.emitBytes(Instr.getValues());
     return;
+
   case MCCFIInstruction::OpLabel:
     Streamer.emitLabel(Instr.getCfiLabel(), Instr.getLoc());
     return;
@@ -1543,7 +1554,182 @@ void FrameEmitterImpl::emitCFIInstruction(const 
MCCFIInstruction &Instr) {
     }
     return;
   }
+  case MCCFIInstruction::OpLLVMRegisterPair: {
+    // CFI for a register spilled to a pair of SGPRs is implemented as an
+    // expression(E) rule where E is a composite location description with
+    // multiple parts each referencing SGPR register location storage with a 
bit
+    // offset of 0. In other words we generate the following DWARF:
+    //
+    // DW_CFA_expression: <Reg>,
+    //    (DW_OP_regx <SGPRPair[0]>) (DW_OP_piece <Size>)
+    //    (DW_OP_regx <SGPRPair[1]>) (DW_OP_piece <Size>)
+    //
+    // The memory location description for the current CFA is pushed on the
+    // stack before E is evaluated, but we choose not to drop it as it would
+    // require a longer expression E and DWARF defines the result of the
+    // evaulation to be the location description on the top of the stack (i.e.
+    // the implictly pushed one is just ignored.)
+
+    const auto &Fields =
+        Instr.getExtraFields<MCCFIInstruction::RegisterPairFields>();
+
+    SmallString<10> Block;
+    raw_svector_ostream OSBlock(Block);
+    encodeDwarfRegisterLocation(Fields.Reg1, OSBlock);
+    if (Fields.Reg1SizeInBits % 8 == 0) {
+      OSBlock << uint8_t(dwarf::DW_OP_piece);
+      encodeULEB128(Fields.Reg1SizeInBits / 8, OSBlock);
+    } else {
+      OSBlock << uint8_t(dwarf::DW_OP_bit_piece);
+      encodeULEB128(Fields.Reg1SizeInBits, OSBlock);
+      encodeULEB128(0, OSBlock);
+    }
+    encodeDwarfRegisterLocation(Fields.Reg2, OSBlock);
+    if (Fields.Reg2SizeInBits % 8 == 0) {
+      OSBlock << uint8_t(dwarf::DW_OP_piece);
+      encodeULEB128(Fields.Reg2SizeInBits / 8, OSBlock);
+    } else {
+      OSBlock << uint8_t(dwarf::DW_OP_bit_piece);
+      encodeULEB128(Fields.Reg2SizeInBits, OSBlock);
+      encodeULEB128(0, OSBlock);
+    }
+
+    Streamer.emitInt8(dwarf::DW_CFA_expression);
+    Streamer.emitULEB128IntValue(Fields.Register);
+    Streamer.emitULEB128IntValue(Block.size());
+    Streamer.emitBinaryData(StringRef(&Block[0], Block.size()));
+    return;
   }
+  case MCCFIInstruction::OpLLVMVectorRegisters: {
+    // CFI for an SGPR spilled to a multiple lanes of VGPRs is implemented as 
an
+    // expression(E) rule where E is a composite location description with
+    // multiple parts each referencing VGPR register location storage with a 
bit
+    // offset of the lane index multiplied by the size of a lane. In other 
words
+    // we generate the following DWARF:
+    //
+    // DW_CFA_expression: <SGPR>,
+    //    (DW_OP_regx <VGPR[0]>) (DW_OP_bit_piece <Size>, <Lane[0]>*<Size>)
+    //    (DW_OP_regx <VGPR[1]>) (DW_OP_bit_piece <Size>, <Lane[1]>*<Size>)
+    //    ...
+    //    (DW_OP_regx <VGPR[N]>) (DW_OP_bit_piece <Size>, <Lane[N]>*<Size>)
+    //
+    // However if we're only using a single lane then we can emit a slightly
+    // more optimal form:
+    //
+    // DW_CFA_expression: <SGPR>,
+    //    (DW_OP_regx <VGPR[0]>) (DW_OP_LLVM_offset_uconst <Lane[0]>*<Size>)
+    //
+    // The memory location description for the current CFA is pushed on the
+    // stack before E is evaluated, but we choose not to drop it as it would
+    // require a longer expression E and DWARF defines the result of the
+    // evaulation to be the location description on the top of the stack (i.e.
+    // the implictly pushed one is just ignored.)
+
+    const auto &Fields =
+        Instr.getExtraFields<MCCFIInstruction::VectorRegistersFields>();
+    auto &VRs = Fields.VectorRegisters;
+
+    SmallString<20> Block;
+    raw_svector_ostream OSBlock(Block);
+
+    if (VRs.size() == 1 && VRs[0].SizeInBits % 8 == 0) {
+      encodeDwarfRegisterLocation(VRs[0].Register, OSBlock);
+      OSBlock << uint8_t(dwarf::DW_OP_LLVM_user)
+              << uint8_t(dwarf::DW_OP_LLVM_offset_uconst);
+      encodeULEB128((VRs[0].SizeInBits / 8) * VRs[0].Lane, OSBlock);
+    } else {
+      for (const auto &VR : VRs) {
+        // TODO: Detect when we can merge multiple adjacent pieces, or even
+        // reduce this to a register location description (when all pieces are
+        // adjacent).
+        encodeDwarfRegisterLocation(VR.Register, OSBlock);
+        OSBlock << uint8_t(dwarf::DW_OP_bit_piece);
+        encodeULEB128(VR.SizeInBits, OSBlock);
+        encodeULEB128(VR.SizeInBits * VR.Lane, OSBlock);
+      }
+    }
+
+    Streamer.emitInt8(dwarf::DW_CFA_expression);
+    Streamer.emitULEB128IntValue(Fields.Register);
+    Streamer.emitULEB128IntValue(Block.size());
+    Streamer.emitBinaryData(StringRef(&Block[0], Block.size()));
+    return;
+  }
+  case MCCFIInstruction::OpLLVMVectorOffset: {
+    // CFI for a vector register spilled to memory is implemented as an
+    // expression(E) rule where E is a location description.
+    //
+    // DW_CFA_expression: <VGPR>,
+    //    (DW_OP_regx <VGPR>)
+    //    (DW_OP_swap)
+    //    (DW_OP_LLVM_offset_uconst <Offset>)
+    //    (DW_OP_LLVM_call_frame_entry_reg <Mask>)
+    //    (DW_OP_deref_size <MaskSize>)
+    //    (DW_OP_LLVM_select_bit_piece <VGPRSize> <MaskSize>)
+
+    const auto &Fields =
+        Instr.getExtraFields<MCCFIInstruction::VectorOffsetFields>();
+
+    SmallString<20> Block;
+    raw_svector_ostream OSBlock(Block);
+    encodeDwarfRegisterLocation(Fields.Register, OSBlock);
+    OSBlock << uint8_t(dwarf::DW_OP_swap);
+    OSBlock << uint8_t(dwarf::DW_OP_LLVM_user)
+            << uint8_t(dwarf::DW_OP_LLVM_offset_uconst);
+    encodeULEB128(Fields.Offset, OSBlock);
+    OSBlock << uint8_t(dwarf::DW_OP_LLVM_user)
+            << uint8_t(dwarf::DW_OP_LLVM_call_frame_entry_reg);
+    encodeULEB128(Fields.MaskRegister, OSBlock);
+    OSBlock << uint8_t(dwarf::DW_OP_deref_size);
+    OSBlock << uint8_t(Fields.MaskRegisterSizeInBits / 8);
+    OSBlock << uint8_t(dwarf::DW_OP_LLVM_user)
+            << uint8_t(dwarf::DW_OP_LLVM_select_bit_piece);
+    encodeULEB128(Fields.RegisterSizeInBits, OSBlock);
+    encodeULEB128(Fields.MaskRegisterSizeInBits, OSBlock);
+
+    Streamer.emitInt8(dwarf::DW_CFA_expression);
+    Streamer.emitULEB128IntValue(Fields.Register);
+    Streamer.emitULEB128IntValue(Block.size());
+    Streamer.emitBinaryData(StringRef(&Block[0], Block.size()));
+    return;
+  }
+  case MCCFIInstruction::OpLLVMVectorRegisterMask: {
+    // CFI for a VGPR/AGPR partially spilled to another VGPR/AGPR dependent on
+    // an EXEC mask is implemented as an expression(E) rule where E is a
+    // location description.
+    //
+    // DW_CFA_expression: <GPR>,
+    //   (DW_OP_regx <GPR>)
+    //   (DW_OP_regx <Spill GPR>)
+    //   (DW_OP_LLVM_call_frame_entry_reg <Mask>)
+    //   (DW_OP_deref_size <MaskSize>)
+    //   (DW_OP_LLVM_select_bit_piece <GPR lane size> <MaskSize>)
+
+    const auto Fields =
+        Instr.getExtraFields<MCCFIInstruction::VectorRegisterMaskFields>();
+
+    SmallString<20> Block;
+    raw_svector_ostream OSBlock(Block);
+    encodeDwarfRegisterLocation(Fields.Register, OSBlock);
+    encodeDwarfRegisterLocation(Fields.SpillRegister, OSBlock);
+    OSBlock << uint8_t(dwarf::DW_OP_LLVM_user)
+            << uint8_t(dwarf::DW_OP_LLVM_call_frame_entry_reg);
+    encodeULEB128(Fields.MaskRegister, OSBlock);
+    OSBlock << uint8_t(dwarf::DW_OP_deref_size)
+            << uint8_t(Fields.MaskRegisterSizeInBits / 8);
+    OSBlock << uint8_t(dwarf::DW_OP_LLVM_user)
+            << uint8_t(dwarf::DW_OP_LLVM_select_bit_piece);
+    encodeULEB128(Fields.SpillRegisterLaneSizeInBits, OSBlock);
+    encodeULEB128(Fields.MaskRegisterSizeInBits, OSBlock);
+
+    Streamer.emitInt8(dwarf::DW_CFA_expression);
+    Streamer.emitULEB128IntValue(Fields.Register);
+    Streamer.emitULEB128IntValue(Block.size());
+    Streamer.emitBinaryData(StringRef(&Block[0], Block.size()));
+    return;
+  }
+  }
+
   llvm_unreachable("Unhandled case in switch");
 }
 
diff --git a/llvm/lib/MC/MCParser/AsmParser.cpp 
b/llvm/lib/MC/MCParser/AsmParser.cpp
index 429cdae1fa1b6..9dd30c0c29ca7 100644
--- a/llvm/lib/MC/MCParser/AsmParser.cpp
+++ b/llvm/lib/MC/MCParser/AsmParser.cpp
@@ -492,6 +492,10 @@ class AsmParser : public MCAsmParser {
     DK_CFI_LLVM_DEF_ASPACE_CFA,
     DK_CFI_OFFSET,
     DK_CFI_REL_OFFSET,
+    DK_CFI_LLVM_REGISTER_PAIR,
+    DK_CFI_LLVM_VECTOR_REGISTERS,
+    DK_CFI_LLVM_VECTOR_OFFSET,
+    DK_CFI_LLVM_VECTOR_REGISTER_MASK,
     DK_CFI_PERSONALITY,
     DK_CFI_LSDA,
     DK_CFI_REMEMBER_STATE,
@@ -611,6 +615,10 @@ class AsmParser : public MCAsmParser {
   bool parseDirectiveCFIReturnColumn(SMLoc DirectiveLoc);
   bool parseDirectiveCFISignalFrame(SMLoc DirectiveLoc);
   bool parseDirectiveCFIUndefined(SMLoc DirectiveLoc);
+  bool parseDirectiveCFILLVMRegisterPair(SMLoc DirectiveLoc);
+  bool parseDirectiveCFILLVMVectorRegisters(SMLoc DirectiveLoc);
+  bool parseDirectiveCFILLVMVectorOffset(SMLoc DirectiveLoc);
+  bool parseDirectiveCFILLVMVectorRegisterMask(SMLoc DirectiveLoc);
   bool parseDirectiveCFILabel(SMLoc DirectiveLoc);
   bool parseDirectiveCFIValOffset(SMLoc DirectiveLoc);
 
@@ -2112,6 +2120,14 @@ bool AsmParser::parseStatement(ParseStatementInfo &Info,
       return parseDirectiveCFIOffset(IDLoc);
     case DK_CFI_REL_OFFSET:
       return parseDirectiveCFIRelOffset(IDLoc);
+    case DK_CFI_LLVM_REGISTER_PAIR:
+      return parseDirectiveCFILLVMRegisterPair(IDLoc);
+    case DK_CFI_LLVM_VECTOR_REGISTERS:
+      return parseDirectiveCFILLVMVectorRegisters(IDLoc);
+    case DK_CFI_LLVM_VECTOR_OFFSET:
+      return parseDirectiveCFILLVMVectorOffset(IDLoc);
+    case DK_CFI_LLVM_VECTOR_REGISTER_MASK:
+      return parseDirectiveCFILLVMVectorRegisterMask(IDLoc);
     case DK_CFI_PERSONALITY:
       return parseDirectiveCFIPersonalityOrLsda(true);
     case DK_CFI_LSDA:
@@ -4437,6 +4453,91 @@ bool AsmParser::parseDirectiveCFIUndefined(SMLoc 
DirectiveLoc) {
   return false;
 }
 
+/// parseDirectiveCFILLVMRegisterPair
+/// ::= .cfi_llvm_register_pair reg, r1, r1size, r2, r2size
+bool AsmParser::parseDirectiveCFILLVMRegisterPair(SMLoc DirectiveLoc) {
+  int64_t Register = 0;
+  int64_t R1 = 0, R2 = 0;
+  int64_t R1Size = 0, R2Size = 0;
+
+  if (parseRegisterOrRegisterNumber(Register, DirectiveLoc) || parseComma() ||
+      parseRegisterOrRegisterNumber(R1, DirectiveLoc) || parseComma() ||
+      parseAbsoluteExpression(R1Size) || parseComma() ||
+      parseRegisterOrRegisterNumber(R2, DirectiveLoc) || parseComma() ||
+      parseAbsoluteExpression(R2Size) || parseEOL())
+    return true;
+
+  getStreamer().emitCFILLVMRegisterPair(Register, R1, R1Size, R2, R2Size,
+                                        DirectiveLoc);
+  return false;
+}
+
+/// parseDirectiveCFILLVMVectorRegisters
+/// ::= .cfi_llvm_vector_registers reg, vreg0, vlane0, vreg0size,
+bool AsmParser::parseDirectiveCFILLVMVectorRegisters(SMLoc DirectiveLoc) {
+  int64_t Register = 0;
+  std::vector<MCCFIInstruction::VectorRegisterWithLane> VRs;
+
+  if (parseRegisterOrRegisterNumber(Register, DirectiveLoc) || parseComma())
+    return true;
+
+  do {
+    int64_t VectorRegister = 0;
+    int64_t Lane = 0;
+    int64_t Size = 0;
+    if (parseRegisterOrRegisterNumber(VectorRegister, DirectiveLoc) ||
+        parseComma() || parseIntToken(Lane, "expected a lane number") ||
+        parseComma() || parseAbsoluteExpression(Size))
+      return true;
+    VRs.push_back({unsigned(VectorRegister), unsigned(Lane), unsigned(Size)});
+  } while (parseOptionalToken(AsmToken::Comma));
+
+  if (parseEOL())
+    return true;
+
+  getStreamer().emitCFILLVMVectorRegisters(Register, std::move(VRs),
+                                           DirectiveLoc);
+  return false;
+}
+
+/// parseDirectiveCFILLVMVectorOffset
+/// ::= .cfi_llvm_vector_offset register, register-size, mask, mask-size, 
offset
+bool AsmParser::parseDirectiveCFILLVMVectorOffset(SMLoc DirectiveLoc) {
+  int64_t Register = 0, MaskRegister = 0;
+  int64_t RegisterSize = 0, MaskRegisterSize = 0;
+  int64_t Offset = 0;
+
+  if (parseRegisterOrRegisterNumber(Register, DirectiveLoc) || parseComma() ||
+      parseAbsoluteExpression(RegisterSize) || parseComma() ||
+      parseRegisterOrRegisterNumber(MaskRegister, DirectiveLoc) ||
+      parseComma() || parseAbsoluteExpression(MaskRegisterSize) ||
+      parseComma() || parseAbsoluteExpression(Offset) || parseEOL())
+    return true;
+
+  getStreamer().emitCFILLVMVectorOffset(Register, RegisterSize, MaskRegister,
+                                        MaskRegisterSize, Offset, 
DirectiveLoc);
+  return false;
+}
+
+/// parseDirectiveCFILLVMVectorOffset
+/// ::= .cfi_llvm_vector_register_mask register, spill-reg, 
spill-reg-lane-size,
+///                                              mask-reg, mask-reg-size
+bool AsmParser::parseDirectiveCFILLVMVectorRegisterMask(SMLoc DirectiveLoc) {
+  int64_t Register = 0, SpillReg = 0, MaskReg = 0;
+  int64_t SpillRegLaneSize = 0, MaskRegSize = 0;
+
+  if (parseRegisterOrRegisterNumber(Register, DirectiveLoc) || parseComma() ||
+      parseRegisterOrRegisterNumber(SpillReg, DirectiveLoc) || parseComma() ||
+      parseAbsoluteExpression(SpillRegLaneSize) || parseComma() ||
+      parseRegisterOrRegisterNumber(MaskReg, DirectiveLoc) || parseComma() ||
+      parseAbsoluteExpression(MaskRegSize) || parseEOL())
+    return true;
+
+  getStreamer().emitCFILLVMVectorRegisterMask(
+      Register, SpillReg, SpillRegLaneSize, MaskReg, MaskRegSize, 
DirectiveLoc);
+  return false;
+}
+
 /// parseDirectiveCFILabel
 /// ::= .cfi_label label
 bool AsmParser::parseDirectiveCFILabel(SMLoc Loc) {
@@ -5472,6 +5573,11 @@ void AsmParser::initializeDirectiveKindMap() {
   DirectiveKindMap[".cfi_llvm_def_aspace_cfa"] = DK_CFI_LLVM_DEF_ASPACE_CFA;
   DirectiveKindMap[".cfi_offset"] = DK_CFI_OFFSET;
   DirectiveKindMap[".cfi_rel_offset"] = DK_CFI_REL_OFFSET;
+  DirectiveKindMap[".cfi_llvm_register_pair"] = DK_CFI_LLVM_REGISTER_PAIR;
+  DirectiveKindMap[".cfi_llvm_vector_registers"] = 
DK_CFI_LLVM_VECTOR_REGISTERS;
+  DirectiveKindMap[".cfi_llvm_vector_offset"] = DK_CFI_LLVM_VECTOR_OFFSET;
+  DirectiveKindMap[".cfi_llvm_vector_register_mask"] =
+      DK_CFI_LLVM_VECTOR_REGISTER_MASK;
   DirectiveKindMap[".cfi_personality"] = DK_CFI_PERSONALITY;
   DirectiveKindMap[".cfi_lsda"] = DK_CFI_LSDA;
   DirectiveKindMap[".cfi_remember_state"] = DK_CFI_REMEMBER_STATE;
diff --git a/llvm/lib/MC/MCParser/MasmParser.cpp 
b/llvm/lib/MC/MCParser/MasmParser.cpp
index 7b6ec4d6950e6..b3301b7cdd723 100644
--- a/llvm/lib/MC/MCParser/MasmParser.cpp
+++ b/llvm/lib/MC/MCParser/MasmParser.cpp
@@ -5271,6 +5271,10 @@ void MasmParser::initializeDirectiveKindMap() {
   // DirectiveKindMap[".cfi_def_cfa_register"] = DK_CFI_DEF_CFA_REGISTER;
   // DirectiveKindMap[".cfi_offset"] = DK_CFI_OFFSET;
   // DirectiveKindMap[".cfi_rel_offset"] = DK_CFI_REL_OFFSET;
+  // DirectiveKindMap[".cfi_llvm_register_pair"] = DK_CFI_LLVM_REGISTER_PAIR;
+  // DirectiveKindMap[".cfi_llvm_vector_registers"] =
+  //   DK_CFI_LLVM_VECTOR_REGISTERS;
+  // DirectiveKindMap[".cfi_llvm_vector_offset"] = DK_CFI_LLVM_VECTOR_OFFSET;
   // DirectiveKindMap[".cfi_personality"] = DK_CFI_PERSONALITY;
   // DirectiveKindMap[".cfi_lsda"] = DK_CFI_LSDA;
   // DirectiveKindMap[".cfi_remember_state"] = DK_CFI_REMEMBER_STATE;
diff --git a/llvm/lib/MC/MCStreamer.cpp b/llvm/lib/MC/MCStreamer.cpp
index bc7398120096e..27a87a6281340 100644
--- a/llvm/lib/MC/MCStreamer.cpp
+++ b/llvm/lib/MC/MCStreamer.cpp
@@ -630,6 +630,60 @@ void MCStreamer::emitCFIGnuArgsSize(int64_t Size, SMLoc 
Loc) {
   CurFrame->Instructions.push_back(std::move(Instruction));
 }
 
+void MCStreamer::emitCFILLVMRegisterPair(int64_t Register, int64_t R1,
+                                         int64_t R1Size, int64_t R2,
+                                         int64_t R2Size, SMLoc Loc) {
+  MCSymbol *Label = emitCFILabel();
+  MCCFIInstruction Instruction = MCCFIInstruction::createLLVMRegisterPair(
+      Label, Register, R1, R1Size, R2, R2Size, Loc);
+  MCDwarfFrameInfo *CurFrame = getCurrentDwarfFrameInfo();
+  if (!CurFrame)
+    return;
+  CurFrame->Instructions.push_back(std::move(Instruction));
+}
+
+void MCStreamer::emitCFILLVMVectorRegisters(
+    int64_t Register, std::vector<MCCFIInstruction::VectorRegisterWithLane> 
VRs,
+    SMLoc Loc) {
+  MCSymbol *Label = emitCFILabel();
+  MCCFIInstruction Instruction = MCCFIInstruction::createLLVMVectorRegisters(
+      Label, Register, std::move(VRs), Loc);
+  MCDwarfFrameInfo *CurFrame = getCurrentDwarfFrameInfo();
+  if (!CurFrame)
+    return;
+  CurFrame->Instructions.push_back(std::move(Instruction));
+}
+
+void MCStreamer::emitCFILLVMVectorOffset(int64_t Register,
+                                         int64_t RegisterSizeInBits,
+                                         int64_t MaskRegister,
+                                         int64_t MaskRegisterSizeInBits,
+                                         int64_t Offset, SMLoc Loc) {
+  MCSymbol *Label = emitCFILabel();
+  MCCFIInstruction Instruction = MCCFIInstruction::createLLVMVectorOffset(
+      Label, Register, RegisterSizeInBits, MaskRegister, 
MaskRegisterSizeInBits,
+      Offset, Loc);
+  MCDwarfFrameInfo *CurFrame = getCurrentDwarfFrameInfo();
+  if (!CurFrame)
+    return;
+  CurFrame->Instructions.push_back(std::move(Instruction));
+}
+
+void MCStreamer::emitCFILLVMVectorRegisterMask(
+    int64_t Register, int64_t SpillRegister,
+    int64_t SpillRegisterLaneSizeInBits, int64_t MaskRegister,
+    int64_t MaskRegisterSizeInBits, SMLoc Loc) {
+
+  MCSymbol *Label = emitCFILabel();
+  MCCFIInstruction Instruction = 
MCCFIInstruction::createLLVMVectorRegisterMask(
+      Label, Register, SpillRegister, SpillRegisterLaneSizeInBits, 
MaskRegister,
+      MaskRegisterSizeInBits, Loc);
+  MCDwarfFrameInfo *CurFrame = getCurrentDwarfFrameInfo();
+  if (!CurFrame)
+    return;
+  CurFrame->Instructions.push_back(std::move(Instruction));
+}
+
 void MCStreamer::emitCFISignalFrame() {
   MCDwarfFrameInfo *CurFrame = getCurrentDwarfFrameInfo();
   if (!CurFrame)
diff --git a/llvm/test/DebugInfo/AMDGPU/heterogeneous-dwarf-cfi-directives.s 
b/llvm/test/DebugInfo/AMDGPU/heterogeneous-dwarf-cfi-directives.s
new file mode 100644
index 0000000000000..d742cfc49689c
--- /dev/null
+++ b/llvm/test/DebugInfo/AMDGPU/heterogeneous-dwarf-cfi-directives.s
@@ -0,0 +1,57 @@
+; RUN: llvm-mc -triple=amdgcn-amd-amdhsa -mcpu=gfx1100 -filetype=obj %s | 
llvm-dwarfdump -debug-frame - | FileCheck %s
+
+.text
+.cfi_sections .debug_frame
+
+; CHECK-NOT: DW_CFA_expression
+
+register_pair:
+  .cfi_startproc
+  s_nop 2
+  ; CHECK: DW_CFA_expression: PC_REG DW_OP_regx SGPR30, DW_OP_piece 0x4, 
DW_OP_regx SGPR31, DW_OP_piece 0x4
+  .cfi_llvm_register_pair 16, 62, 32, 63, 32
+  s_nop 2
+  .cfi_endproc
+
+; CHECK-NOT: DW_CFA_expression
+
+vector_registers:
+  .cfi_startproc
+  s_nop 2
+  ; CHECK: DW_CFA_expression: PC_REG DW_OP_regx 0x67f, DW_OP_bit_piece 0x20 
0x0, DW_OP_regx 0x67f, DW_OP_bit_piece 0x20 0x20
+  .cfi_llvm_vector_registers 16, 1663, 0, 32, 1663, 1, 32
+  s_nop 2
+  .cfi_endproc
+
+; CHECK-NOT: DW_CFA_expression
+
+vector_registers_single:
+  .cfi_startproc
+  s_nop 2
+  ;; Note that 0x2c below is the offset in the VGPR, so 4 (bytes, vgpr lane 
size) * 11 (the lane).
+  ; CHECK: DW_CFA_expression: SGPR45 DW_OP_regx VGPR41, DW_OP_LLVM_user 
DW_OP_LLVM_offset_uconst 0x2c
+  .cfi_llvm_vector_registers 77, 2601, 11, 32
+  s_nop 2
+  .cfi_endproc
+
+; CHECK-NOT: DW_CFA_expression
+
+vector_offsets:
+  .cfi_startproc
+  s_nop 2
+  ; CHECK: DW_CFA_expression: VGPR40 DW_OP_regx VGPR40, DW_OP_swap, 
DW_OP_LLVM_user DW_OP_LLVM_offset_uconst 0x100, DW_OP_LLVM_user 
DW_OP_LLVM_call_frame_entry_reg EXEC, DW_OP_deref_size 0x8, DW_OP_LLVM_user 
DW_OP_LLVM_select_bit_piece 0x20 0x40
+  .cfi_llvm_vector_offset 2600, 32, 17, 64, 256
+  s_nop 2
+  .cfi_endproc
+
+; CHECK-NOT: DW_CFA_expression
+
+vector_register_mask:
+  .cfi_startproc
+  s_nop 0
+  ; CHECK: DW_CFA_expression: VGPR40 DW_OP_regx VGPR40, DW_OP_regx AGPR0, 
DW_OP_LLVM_user DW_OP_LLVM_call_frame_entry_reg EXEC, DW_OP_deref_size 0x8, 
DW_OP_LLVM_user DW_OP_LLVM_select_bit_piece 0x20 0x40
+  .cfi_llvm_vector_register_mask 2600, 3072, 32, 17, 64
+  s_nop 0
+  .cfi_endproc
+
+; CHECK-NOT: DW_CFA_expression
diff --git a/llvm/test/MC/ELF/cfi-register-pair.s 
b/llvm/test/MC/ELF/cfi-register-pair.s
new file mode 100644
index 0000000000000..05ef8e9ae2a4d
--- /dev/null
+++ b/llvm/test/MC/ELF/cfi-register-pair.s
@@ -0,0 +1,56 @@
+# RUN: llvm-mc -triple amdgcn-amd-amdhsa %s | FileCheck %s --check-prefix=ASM
+# RUN: llvm-mc -filetype=obj -triple amdgcn-amd-amdhsa %s | llvm-readobj -S 
--sr --sd - | FileCheck %s
+
+# REQUIRES: amdgpu-registered-target
+
+# ASM: .cfi_llvm_register_pair 16, 62, 32, 63, 32
+# ASM-NEXT: s_nop 0
+
+f:
+  .cfi_startproc
+  s_nop 0
+  .cfi_llvm_register_pair 16, 62, 32, 63, 32
+  s_nop 0
+  .cfi_endproc
+
+// CHECK:        Section {
+// CHECK:          Index:
+// CHECK:          Name: .eh_frame
+// CHECK-NEXT:     Type: SHT_PROGBITS
+// CHECK-NEXT:     Flags [
+// CHECK-NEXT:       SHF_ALLOC
+// CHECK-NEXT:     ]
+// CHECK-NEXT:     Address: 0x0
+// CHECK-NEXT:     Offset: 0x48
+// CHECK-NEXT:     Size: 56
+// CHECK-NEXT:     Link: 0
+// CHECK-NEXT:     Info: 0
+// CHECK-NEXT:     AddressAlignment: 8
+// CHECK-NEXT:     EntrySize: 0
+// CHECK-NEXT:     Relocations [
+// CHECK-NEXT:     ]
+// CHECK-NEXT:     SectionData (
+// CHECK-NEXT:       0000: 10000000 00000000 017A5200 04041001  
|.........zR.....|
+// CHECK-NEXT:       0010: 1B000000 20000000 18000000 00000000  |.... 
...........|
+// CHECK-NEXT:       0020: 08000000 00411010 08903E93 04903F93  
|.....A....>...?.|
+// CHECK-NEXT:       0030: 04000000 00000000                    |........|
+// CHECK-NEXT:     )
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Section {
+// CHECK-NEXT:     Index:
+// CHECK-NEXT:     Name: .rela.eh_frame
+// CHECK-NEXT:     Type: SHT_RELA
+// CHECK-NEXT:     Flags [
+// CHECK-NEXT:       SHF_INFO_LINK
+// CHECK-NEXT:     ]
+// CHECK-NEXT:     Address: 0x0
+// CHECK-NEXT:     Offset:
+// CHECK-NEXT:     Size: 24
+// CHECK-NEXT:     Link:
+// CHECK-NEXT:     Info:
+// CHECK-NEXT:     AddressAlignment: 8
+// CHECK-NEXT:     EntrySize: 24
+// CHECK-NEXT:     Relocations [
+// CHECK-NEXT:       0x1C R_AMDGPU_REL32 .text
+// CHECK-NEXT:     ]
+// CHECK:        }
diff --git a/llvm/test/MC/ELF/cfi-vector-offset.s 
b/llvm/test/MC/ELF/cfi-vector-offset.s
new file mode 100644
index 0000000000000..7817396b8f316
--- /dev/null
+++ b/llvm/test/MC/ELF/cfi-vector-offset.s
@@ -0,0 +1,56 @@
+# RUN: llvm-mc -triple amdgcn-amd-amdhsa %s | FileCheck %s --check-prefix=ASM
+# RUN: llvm-mc -filetype=obj -triple amdgcn-amd-amdhsa %s | llvm-readobj -S 
--sr --sd - | FileCheck %s
+
+# REQUIRES: amdgpu-registered-target
+
+# ASM: .cfi_llvm_vector_offset 2600, 32, 17, 64, 256
+# ASM-NEXT: s_nop 0
+
+f:
+  .cfi_startproc
+  s_nop 0
+  .cfi_llvm_vector_offset 2600, 32, 17, 64, 256
+  s_nop 0
+  .cfi_endproc
+
+// CHECK:        Section {
+// CHECK:          Index:
+// CHECK:          Name: .eh_frame
+// CHECK-NEXT:     Type: SHT_PROGBITS
+// CHECK-NEXT:     Flags [
+// CHECK-NEXT:       SHF_ALLOC
+// CHECK-NEXT:     ]
+// CHECK-NEXT:     Address: 0x0
+// CHECK-NEXT:     Offset: 0x48
+// CHECK-NEXT:     Size: 64
+// CHECK-NEXT:     Link: 0
+// CHECK-NEXT:     Info: 0
+// CHECK-NEXT:     AddressAlignment: 8
+// CHECK-NEXT:     EntrySize: 0
+// CHECK-NEXT:     Relocations [
+// CHECK-NEXT:     ]
+// CHECK-NEXT:     SectionData (
+// CHECK-NEXT:       0000: 10000000 00000000 017A5200 04041001  
|.........zR.....|
+// CHECK-NEXT:       0010: 1B000000 28000000 18000000 00000000  
|....(...........|
+// CHECK-NEXT:       0020: 08000000 004110A8 141190A8 1416E905  
|.....A..........|
+// CHECK-NEXT:       0030: 8002E907 119408E9 0C204000 00000000  |......... 
@.....|
+// CHECK-NEXT:     )
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Section {
+// CHECK-NEXT:     Index:
+// CHECK-NEXT:     Name: .rela.eh_frame
+// CHECK-NEXT:     Type: SHT_RELA
+// CHECK-NEXT:     Flags [
+// CHECK-NEXT:       SHF_INFO_LINK
+// CHECK-NEXT:     ]
+// CHECK-NEXT:     Address: 0x0
+// CHECK-NEXT:     Offset:
+// CHECK-NEXT:     Size: 24
+// CHECK-NEXT:     Link:
+// CHECK-NEXT:     Info:
+// CHECK-NEXT:     AddressAlignment: 8
+// CHECK-NEXT:     EntrySize: 24
+// CHECK-NEXT:     Relocations [
+// CHECK-NEXT:       0x1C R_AMDGPU_REL32 .text
+// CHECK-NEXT:     ]
+// CHECK:        }
diff --git a/llvm/test/MC/ELF/cfi-vector-registers.s 
b/llvm/test/MC/ELF/cfi-vector-registers.s
new file mode 100644
index 0000000000000..76f001007a272
--- /dev/null
+++ b/llvm/test/MC/ELF/cfi-vector-registers.s
@@ -0,0 +1,56 @@
+# RUN: llvm-mc -triple amdgcn-amd-amdhsa %s | FileCheck %s --check-prefix=ASM
+# RUN: llvm-mc -filetype=obj -triple amdgcn-amd-amdhsa -mcpu=gfx908 %s | 
llvm-readobj -S --sr --sd - | FileCheck %s
+
+# REQUIRES: amdgpu-registered-target
+
+# ASM: .cfi_llvm_vector_registers 16, 1663, 0, 32, 1663, 1, 32
+# ASM-NEXT: s_nop 0
+
+f:
+  .cfi_startproc
+  s_nop 0
+  .cfi_llvm_vector_registers 16, 1663, 0, 32, 1663, 1, 32
+  s_nop 0
+  .cfi_endproc
+
+// CHECK:        Section {
+// CHECK:          Index:
+// CHECK:          Name: .eh_frame
+// CHECK-NEXT:     Type: SHT_PROGBITS
+// CHECK-NEXT:     Flags [
+// CHECK-NEXT:       SHF_ALLOC
+// CHECK-NEXT:     ]
+// CHECK-NEXT:     Address: 0x0
+// CHECK-NEXT:     Offset: 0x48
+// CHECK-NEXT:     Size: 56
+// CHECK-NEXT:     Link: 0
+// CHECK-NEXT:     Info: 0
+// CHECK-NEXT:     AddressAlignment: 8
+// CHECK-NEXT:     EntrySize: 0
+// CHECK-NEXT:     Relocations [
+// CHECK-NEXT:     ]
+// CHECK-NEXT:     SectionData (
+// CHECK-NEXT:        0000: 10000000 00000000 017A5200 04041001  
|.........zR.....|
+// CHECK-NEXT:        0010: 1B000000 20000000 18000000 00000000  |.... 
...........|
+// CHECK-NEXT:        0020: 08000000 00411010 0C90FF0C 9D200090  
|.....A....... ..|
+// CHECK-NEXT:        0030: FF0C9D20 20000000                    |...  ...|
+// CHECK-NEXT:     )
+// CHECK-NEXT:   }
+// CHECK-NEXT:   Section {
+// CHECK-NEXT:     Index:
+// CHECK-NEXT:     Name: .rela.eh_frame
+// CHECK-NEXT:     Type: SHT_RELA
+// CHECK-NEXT:     Flags [
+// CHECK-NEXT:       SHF_INFO_LINK
+// CHECK-NEXT:     ]
+// CHECK-NEXT:     Address: 0x0
+// CHECK-NEXT:     Offset:
+// CHECK-NEXT:     Size: 24
+// CHECK-NEXT:     Link:
+// CHECK-NEXT:     Info:
+// CHECK-NEXT:     AddressAlignment: 8
+// CHECK-NEXT:     EntrySize: 24
+// CHECK-NEXT:     Relocations [
+// CHECK-NEXT:       0x1C R_AMDGPU_REL32 .text
+// CHECK-NEXT:     ]
+// CHECK:        }

>From 879504bf8387323d726eecd010d9a2776c67a627 Mon Sep 17 00:00:00 2001
From: Scott Linder <[email protected]>
Date: Fri, 24 Oct 2025 20:14:48 +0000
Subject: [PATCH 2/2] Add MIR test

---
 llvm/test/CodeGen/AMDGPU/cfi-pseudos.mir | 21 +++++++++++++++++++++
 1 file changed, 21 insertions(+)
 create mode 100644 llvm/test/CodeGen/AMDGPU/cfi-pseudos.mir

diff --git a/llvm/test/CodeGen/AMDGPU/cfi-pseudos.mir 
b/llvm/test/CodeGen/AMDGPU/cfi-pseudos.mir
new file mode 100644
index 0000000000000..313daf5911d57
--- /dev/null
+++ b/llvm/test/CodeGen/AMDGPU/cfi-pseudos.mir
@@ -0,0 +1,21 @@
+# RUN: llc -mtriple=amdgcn -mcpu=gfx908 -run-pass none -o - %s | \
+# RUN: llc -mtriple=amdgcn -mcpu=gfx908 -x=mir -run-pass none -o - | \
+# RUN: FileCheck %s
+
+# Verify we can parse and emit these CFI pseudos.
+
+# CHECK-LABEL: name: test
+# CHECK: CFI_INSTRUCTION llvm_register_pair $pc_reg, $sgpr30, 32, $sgpr31, 32
+# CHECK-NEXT: CFI_INSTRUCTION llvm_vector_registers $sgpr4, $vgpr3, 0, 32
+# CHECK-NEXT: CFI_INSTRUCTION llvm_vector_registers $pc_reg, $vgpr62, 0, 32, 
$vgpr62, 1, 32
+# CHECK-NEXT: CFI_INSTRUCTION llvm_vector_offset $vgpr41, 32, $exec, 64, 100
+# CHECK-NEXT: CFI_INSTRUCTION llvm_vector_register_mask $agpr1, $vgpr1, 32, 
$exec, 64
+
+name: test
+body: |
+  bb.0:
+    CFI_INSTRUCTION llvm_register_pair $pc_reg, $sgpr30, 32, $sgpr31, 32
+    CFI_INSTRUCTION llvm_vector_registers $sgpr4, $vgpr3, 0, 32
+    CFI_INSTRUCTION llvm_vector_registers $pc_reg, $vgpr62, 0, 32, $vgpr62, 1, 
32
+    CFI_INSTRUCTION llvm_vector_offset $vgpr41, 32, $exec, 64, 100
+    CFI_INSTRUCTION llvm_vector_register_mask $agpr1, $vgpr1, 32, $exec, 64

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

Reply via email to