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 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 ExtraFields; + std::variant + 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 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 ExtraFieldsTy &getExtraFields() { + return std::get(ExtraFields); + } + + template const ExtraFieldsTy &getExtraFields() const { + return std::get(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 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(); + OutStreamer->emitCFILLVMRegisterPair(Fields.Register, Fields.Reg1, + Fields.Reg1SizeInBits, Fields.Reg2, + Fields.Reg2SizeInBits, Loc); + break; + } + case MCCFIInstruction::OpLLVMVectorRegisters: { + const auto &Fields = + Inst.getExtraFields(); + OutStreamer->emitCFILLVMVectorRegisters(Fields.Register, + Fields.VectorRegisters, Loc); + break; + } + case MCCFIInstruction::OpLLVMVectorOffset: { + const auto &Fields = + Inst.getExtraFields(); + OutStreamer->emitCFILLVMVectorOffset( + Fields.Register, Fields.RegisterSizeInBits, Fields.MaskRegister, + Fields.MaskRegisterSizeInBits, Fields.Offset, Loc); + break; + } + case MCCFIInstruction::OpLLVMVectorRegisterMask: { + const auto &Fields = + Inst.getExtraFields(); + 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 14098bc821617..0d60d17da0cf7 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 6a464d9dd6886..27cc7d9104837 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); @@ -2475,6 +2476,14 @@ bool MIParser::parseCFIOffset(int &Offset) { return false; } +bool MIParser::parseCFIUnsigned(unsigned &Value) { + // test + if (getUnsigned(Value)) + return true; + lex(); + return false; +} + bool MIParser::parseCFIRegister(unsigned &Reg) { if (Token.isNot(MIToken::NamedRegister)) return error("expected a cfi register"); @@ -2608,6 +2617,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 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)); @@ -2962,6 +3034,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 bb9c76ff0c729..db802cc6e9024 100644 --- a/llvm/lib/CodeGen/MachineOperand.cpp +++ b/llvm/lib/CodeGen/MachineOperand.cpp @@ -778,6 +778,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(); + + 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(); + + 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(); + + 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(); + + 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 bca820fa807c8..4d2d2da8a4445 100644 --- a/llvm/lib/DWARFCFIChecker/DWARFCFIState.cpp +++ b/llvm/lib/DWARFCFIChecker/DWARFCFIState.cpp @@ -161,6 +161,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 be8c022f39ad1..6c54a9efbf2c6 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 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 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: , + // (DW_OP_regx ) (DW_OP_piece ) + // (DW_OP_regx ) (DW_OP_piece ) + // + // 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(); + + 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: , + // (DW_OP_regx ) (DW_OP_bit_piece , *) + // (DW_OP_regx ) (DW_OP_bit_piece , *) + // ... + // (DW_OP_regx ) (DW_OP_bit_piece , *) + // + // However if we're only using a single lane then we can emit a slightly + // more optimal form: + // + // DW_CFA_expression: , + // (DW_OP_regx ) (DW_OP_LLVM_offset_uconst *) + // + // 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(); + 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: , + // (DW_OP_regx ) + // (DW_OP_swap) + // (DW_OP_LLVM_offset_uconst ) + // (DW_OP_LLVM_call_frame_entry_reg ) + // (DW_OP_deref_size ) + // (DW_OP_LLVM_select_bit_piece ) + + const auto &Fields = + Instr.getExtraFields(); + + 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: , + // (DW_OP_regx ) + // (DW_OP_regx ) + // (DW_OP_LLVM_call_frame_entry_reg ) + // (DW_OP_deref_size ) + // (DW_OP_LLVM_select_bit_piece ) + + const auto Fields = + Instr.getExtraFields(); + + 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 acea3ab23680a..0a3f22083a51d 100644 --- a/llvm/lib/MC/MCParser/AsmParser.cpp +++ b/llvm/lib/MC/MCParser/AsmParser.cpp @@ -493,6 +493,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, @@ -610,6 +614,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); @@ -2116,6 +2124,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: @@ -4410,6 +4426,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 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) { @@ -5444,6 +5545,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 7f0ea7830b495..19bc0b494c55b 100644 --- a/llvm/lib/MC/MCParser/MasmParser.cpp +++ b/llvm/lib/MC/MCParser/MasmParser.cpp @@ -5275,6 +5275,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 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: }