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