[llvm-branch-commits] [llvm] [MC][Dwarf] Add custom CFI pseudo-ops for use in AMDGPU (PR #164721)
Scott Linder via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Mon Nov 24 10:18:28 PST 2025
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 <Emma.Pilkington at amd.com>
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 <Scott.Linder at amd.com>
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
More information about the llvm-branch-commits
mailing list