From e038b70b6e50b0a5bad001e6609377e766ea0fca Mon Sep 17 00:00:00 2001 From: Matt Arsenault Date: Mon, 25 Aug 2025 07:29:46 +0900 Subject: [PATCH 01/28] CodeGen: Add RegisterClass by HwMode This is a generalization of the LookupPtrRegClass mechanism. AMDGPU has several use cases for swapping the register class of instruction operands based on the subtarget, but none of them really fit into the box of being pointer-like. The current system requires manual management of an arbitrary integer ID. For the AMDGPU use case, this would end up being around 40 new entries to manage. This just introduces the base infrastructure. I have ports of all the target specific usage of PointerLikeRegClass ready. --- llvm/include/llvm/CodeGen/TargetInstrInfo.h | 24 +- llvm/include/llvm/MC/MCInstrDesc.h | 20 +- llvm/include/llvm/MC/MCInstrInfo.h | 28 +- llvm/include/llvm/MC/MCSubtargetInfo.h | 1 + llvm/include/llvm/Target/Target.td | 27 +- llvm/lib/CodeGen/TargetInstrInfo.cpp | 7 +- llvm/lib/Target/AMDGPU/BUFInstructions.td | 7 +- llvm/lib/Target/AMDGPU/SIInstrFormats.td | 2 +- llvm/lib/Target/AMDGPU/SIInstrInfo.td | 4 +- .../lib/Target/AVR/AsmParser/AVRAsmParser.cpp | 4 +- .../SystemZ/AsmParser/SystemZAsmParser.cpp | 2 +- llvm/test/TableGen/RegClassByHwMode.td | 429 ++++++++++++++++++ llvm/utils/TableGen/AsmMatcherEmitter.cpp | 156 ++++++- llvm/utils/TableGen/AsmWriterEmitter.cpp | 2 +- .../TableGen/Common/CodeGenDAGPatterns.cpp | 33 +- .../TableGen/Common/CodeGenInstAlias.cpp | 14 +- .../TableGen/Common/CodeGenInstruction.cpp | 2 +- llvm/utils/TableGen/Common/CodeGenTarget.h | 8 + llvm/utils/TableGen/Common/InfoByHwMode.cpp | 14 + llvm/utils/TableGen/Common/InfoByHwMode.h | 12 + .../TableGen/Common/InstructionEncoding.cpp | 40 +- .../TableGen/Common/InstructionEncoding.h | 13 +- llvm/utils/TableGen/DAGISelMatcherGen.cpp | 2 +- llvm/utils/TableGen/DecoderEmitter.cpp | 67 ++- llvm/utils/TableGen/GlobalISelEmitter.cpp | 79 +++- llvm/utils/TableGen/InstrInfoEmitter.cpp | 102 ++++- llvm/utils/TableGen/SubtargetEmitter.cpp | 4 +- 27 files changed, 1014 insertions(+), 89 deletions(-) create mode 100644 llvm/test/TableGen/RegClassByHwMode.td diff --git a/llvm/include/llvm/CodeGen/TargetInstrInfo.h b/llvm/include/llvm/CodeGen/TargetInstrInfo.h index 6a624a7052cdd..0212c8bde7d55 100644 --- a/llvm/include/llvm/CodeGen/TargetInstrInfo.h +++ b/llvm/include/llvm/CodeGen/TargetInstrInfo.h @@ -113,9 +113,17 @@ struct ExtAddrMode { /// class LLVM_ABI TargetInstrInfo : public MCInstrInfo { protected: + /// Subtarget specific sub-array of MCInstrInfo's RegClassByHwModeTables. + /// This should be indexed by MCOperandInfo's RegClass field for + /// LookupRegClassByHwMode operands. + const int16_t *const RegClassByHwMode; + +public: TargetInstrInfo(unsigned CFSetupOpcode = ~0u, unsigned CFDestroyOpcode = ~0u, - unsigned CatchRetOpcode = ~0u, unsigned ReturnOpcode = ~0u) - : CallFrameSetupOpcode(CFSetupOpcode), + unsigned CatchRetOpcode = ~0u, unsigned ReturnOpcode = ~0u, + const int16_t *const RegClassByHwModeTable = nullptr) + : RegClassByHwMode(RegClassByHwModeTable), + CallFrameSetupOpcode(CFSetupOpcode), CallFrameDestroyOpcode(CFDestroyOpcode), CatchRetOpcode(CatchRetOpcode), ReturnOpcode(ReturnOpcode) {} @@ -133,6 +141,18 @@ class LLVM_ABI TargetInstrInfo : public MCInstrInfo { Opc <= TargetOpcode::GENERIC_ATOMICRMW_OP_END; } + /// Return the subtarget appropripate RegClassID for \p OpInfo + /// + /// Note this shadows a version of getOpRegClassID in MCInstrInfo which takes + /// an additional argument for the subtarget's HwMode, since TargetInstrInfo + /// is owned by a subtarget in CodeGen but MCInstrInfo is a TargetMachine + /// constant. + int16_t getOpRegClassID(const MCOperandInfo &OpInfo) const { + if (OpInfo.isLookupRegClassByHwMode()) + return RegClassByHwMode[OpInfo.RegClass]; + return OpInfo.RegClass; + } + /// Given a machine instruction descriptor, returns the register /// class constraint for OpNum, or NULL. virtual const TargetRegisterClass * diff --git a/llvm/include/llvm/MC/MCInstrDesc.h b/llvm/include/llvm/MC/MCInstrDesc.h index 8c70925d4780e..292c40a8cb128 100644 --- a/llvm/include/llvm/MC/MCInstrDesc.h +++ b/llvm/include/llvm/MC/MCInstrDesc.h @@ -50,6 +50,7 @@ enum OperandConstraint { /// See the accessors for a description of what these are. enum OperandFlags { LookupPtrRegClass = 0, + LookupRegClassByHwMode, Predicate, OptionalDef, BranchTarget @@ -85,10 +86,14 @@ enum OperandType { /// indicating the register class for register operands, etc. class MCOperandInfo { public: - /// This specifies the register class enumeration of the operand - /// if the operand is a register. If isLookupPtrRegClass is set, then this is - /// an index that is passed to TargetRegisterInfo::getPointerRegClass(x) to - /// get a dynamic register class. + /// This specifies the register class enumeration of the operand if the + /// operand is a register. If LookupRegClassByHwMode is set, then this is an + /// index into a table in TargetInstrInfo or MCInstrInfo which contains the + /// real register class ID. + /// + /// If isLookupPtrRegClass is set, then this is / an index that is passed to + /// TargetRegisterInfo::getPointerRegClass(x) to / get a dynamic register + /// class. int16_t RegClass; /// These are flags from the MCOI::OperandFlags enum. @@ -102,10 +107,17 @@ class MCOperandInfo { /// Set if this operand is a pointer value and it requires a callback /// to look up its register class. + // TODO: Deprecated in favor of isLookupRegClassByHwMode bool isLookupPtrRegClass() const { return Flags & (1 << MCOI::LookupPtrRegClass); } + /// Set if this operand is a value that requires the current hwmode to look up + /// its register class. + bool isLookupRegClassByHwMode() const { + return Flags & (1 << MCOI::LookupRegClassByHwMode); + } + /// Set if this is one of the operands that made up of the predicate /// operand that controls an isPredicable() instruction. bool isPredicate() const { return Flags & (1 << MCOI::Predicate); } diff --git a/llvm/include/llvm/MC/MCInstrInfo.h b/llvm/include/llvm/MC/MCInstrInfo.h index 77ead222b9549..aaad450ef99c3 100644 --- a/llvm/include/llvm/MC/MCInstrInfo.h +++ b/llvm/include/llvm/MC/MCInstrInfo.h @@ -43,22 +43,48 @@ class MCInstrInfo { const ComplexDeprecationPredicate *ComplexDeprecationInfos; unsigned NumOpcodes; // Number of entries in the desc array +protected: + // Pointer to 2d array [NumHwModess][NumRegClassByHwModes] + const int16_t *RegClassByHwModeTables; + int16_t NumRegClassByHwModes; + public: /// Initialize MCInstrInfo, called by TableGen auto-generated routines. /// *DO NOT USE*. void InitMCInstrInfo(const MCInstrDesc *D, const unsigned *NI, const char *ND, const uint8_t *DF, - const ComplexDeprecationPredicate *CDI, unsigned NO) { + const ComplexDeprecationPredicate *CDI, unsigned NO, + const int16_t *RCHWTables = nullptr, + int16_t NumRegClassByHwMode = 0) { LastDesc = D + NO - 1; InstrNameIndices = NI; InstrNameData = ND; DeprecatedFeatures = DF; ComplexDeprecationInfos = CDI; NumOpcodes = NO; + RegClassByHwModeTables = RCHWTables; + NumRegClassByHwModes = NumRegClassByHwMode; } unsigned getNumOpcodes() const { return NumOpcodes; } + const int16_t *getRegClassByHwModeTable(unsigned ModeId) const { + assert(RegClassByHwModeTables); + assert(NumRegClassByHwModes != 0); + return &RegClassByHwModeTables[ModeId * NumRegClassByHwModes]; + } + + /// Return the ID of the register class to use for \p OpInfo, for the active + /// HwMode \p HwModeId. In general TargetInstrInfo's version which is already + /// specialized to the subtarget should be used. + int16_t getOpRegClassID(const MCOperandInfo &OpInfo, + unsigned HwModeId) const { + int16_t RegClass = OpInfo.RegClass; + if (OpInfo.isLookupRegClassByHwMode()) + RegClass = getRegClassByHwModeTable(HwModeId)[RegClass]; + return RegClass; + } + /// Return the machine instruction descriptor that corresponds to the /// specified instruction opcode. const MCInstrDesc &get(unsigned Opcode) const { diff --git a/llvm/include/llvm/MC/MCSubtargetInfo.h b/llvm/include/llvm/MC/MCSubtargetInfo.h index 44b4cb8fa17bd..5204c23897d67 100644 --- a/llvm/include/llvm/MC/MCSubtargetInfo.h +++ b/llvm/include/llvm/MC/MCSubtargetInfo.h @@ -259,6 +259,7 @@ class LLVM_ABI MCSubtargetInfo { HwMode_ValueType, // Return the HwMode ID that controls the ValueType. HwMode_RegInfo, // Return the HwMode ID that controls the RegSizeInfo and // SubRegRange. + HwMode_RegClass, // Return the HwMode ID that controls the RegisterClass. HwMode_EncodingInfo // Return the HwMode ID that controls the EncodingInfo. }; diff --git a/llvm/include/llvm/Target/Target.td b/llvm/include/llvm/Target/Target.td index e664e20896db4..af4f70f51e0ee 100644 --- a/llvm/include/llvm/Target/Target.td +++ b/llvm/include/llvm/Target/Target.td @@ -258,6 +258,12 @@ class DAGOperand { bit hasCompleteDecoder = true; } +/// Abstract base class common to RegisterClass and +/// RegClassByHwMode. This permits using RegClassByHwMode in +/// RegisterOperand contexts without creating an artificial +/// RegisterClass. +class RegisterClassLike : DAGOperand; + // RegisterClass - Now that all of the registers are defined, and aliases // between registers are defined, specify which registers belong to which // register classes. This also defines the default allocation order of @@ -265,7 +271,7 @@ class DAGOperand { // class RegisterClass regTypes, int alignment, dag regList, RegAltNameIndex idx = NoRegAltName> - : DAGOperand { + : DAGOperand, RegisterClassLike { string Namespace = namespace; // The register size/alignment information, parameterized by a HW mode. @@ -916,15 +922,30 @@ def decoder; /// derived from this. TableGen treats the register class as having a symbolic /// type that it doesn't know, and resolves the actual regclass to use by using /// the TargetRegisterInfo::getPointerRegClass() hook at codegen time. +/// +/// This is deprecated in favor of RegClassByHwMode class PointerLikeRegClass { int RegClassKind = Kind; } +/// RegClassByHwMode - Operands that change the register class based +/// on the subtarget are derived from this derived from this. TableGen +/// treats the register class as having a symbolic kind that it +/// doesn't know, and resolves the actual regclass to use by using the +/// a mapping in TargetInstrInfo at codegen time. This can be used to +/// define operands which swap the register class with the pointer +/// type. +class RegClassByHwMode Modes, + list RegClasses> : + HwModeSelect, RegisterClassLike { + list Objects = RegClasses; +} /// ptr_rc definition - Mark this operand as being a pointer value whose /// register class is resolved dynamically via a callback to TargetInstrInfo. /// FIXME: We should probably change this to a class which contain a list of /// flags. But currently we have but one flag. +// Deprecated, use RegClassByHwMode instead. def ptr_rc : PointerLikeRegClass<0>; /// unknown definition - Mark this operand as being of unknown type, causing @@ -1024,10 +1045,10 @@ class Operand : DAGOperand { AsmOperandClass ParserMatchClass = ImmAsmOperand; } -class RegisterOperand +class RegisterOperand : DAGOperand { // RegClass - The register class of the operand. - RegisterClass RegClass = regclass; + RegisterClassLike RegClass = regclass; // PrintMethod - The target method to call to print register operands of // this type. The method normally will just use an alt-name index to look // up the name to print. Default to the generic printOperand(). diff --git a/llvm/lib/CodeGen/TargetInstrInfo.cpp b/llvm/lib/CodeGen/TargetInstrInfo.cpp index b0009560d3fcb..5be89b49fb6ba 100644 --- a/llvm/lib/CodeGen/TargetInstrInfo.cpp +++ b/llvm/lib/CodeGen/TargetInstrInfo.cpp @@ -64,8 +64,11 @@ TargetInstrInfo::getRegClass(const MCInstrDesc &MCID, unsigned OpNum, if (OpNum >= MCID.getNumOperands()) return nullptr; - short RegClass = MCID.operands()[OpNum].RegClass; - if (MCID.operands()[OpNum].isLookupPtrRegClass()) + const MCOperandInfo &OpInfo = MCID.operands()[OpNum]; + int16_t RegClass = getOpRegClassID(OpInfo); + + // TODO: Remove isLookupPtrRegClass in favor of isLookupRegClassByHwMode + if (OpInfo.isLookupPtrRegClass()) return TRI->getPointerRegClass(RegClass); // Instructions like INSERT_SUBREG do not have fixed register classes. diff --git a/llvm/lib/Target/AMDGPU/BUFInstructions.td b/llvm/lib/Target/AMDGPU/BUFInstructions.td index f229298ba516b..09a66d785d5cf 100644 --- a/llvm/lib/Target/AMDGPU/BUFInstructions.td +++ b/llvm/lib/Target/AMDGPU/BUFInstructions.td @@ -411,11 +411,16 @@ class getBUFVDataRegisterOperand { RegisterOperand ret = !if(isTFE, tfeVDataOp, VDataOp); } +class getBUFVDataRegisterOperandForOp { + defvar Size = !cast(Op.RegClass).Size; + RegisterOperand ret = getBUFVDataRegisterOperand.ret; +} + class getMUBUFInsDA vdataList, list vaddrList, bit isTFE, bit hasRestrictedSOffset> { RegisterOperand vdataClass = !if(!empty(vdataList), ?, !head(vdataList)); RegisterClass vaddrClass = !if(!empty(vaddrList), ?, !head(vaddrList)); - RegisterOperand vdata_op = getBUFVDataRegisterOperand.ret; + RegisterOperand vdata_op = getBUFVDataRegisterOperandForOp.ret; dag SOffset = !if(hasRestrictedSOffset, (ins SReg_32:$soffset), (ins SCSrc_b32:$soffset)); dag NonVaddrInputs = !con((ins SReg_128_XNULL:$srsrc), SOffset, (ins Offset:$offset, CPol_0:$cpol, i1imm_0:$swz)); diff --git a/llvm/lib/Target/AMDGPU/SIInstrFormats.td b/llvm/lib/Target/AMDGPU/SIInstrFormats.td index 50964a94d6e58..de66c472be0ca 100644 --- a/llvm/lib/Target/AMDGPU/SIInstrFormats.td +++ b/llvm/lib/Target/AMDGPU/SIInstrFormats.td @@ -321,7 +321,7 @@ def CPolBit { int SCAL = 11; } -class VOPDstOperand : RegisterOperand ; +class VOPDstOperand : RegisterOperand; def VOPDstOperand_t16 : VOPDstOperand { let EncoderMethod = "getMachineOpValueT16"; diff --git a/llvm/lib/Target/AMDGPU/SIInstrInfo.td b/llvm/lib/Target/AMDGPU/SIInstrInfo.td index 18fae6cfc7ed9..fb2cd04b364d7 100644 --- a/llvm/lib/Target/AMDGPU/SIInstrInfo.td +++ b/llvm/lib/Target/AMDGPU/SIInstrInfo.td @@ -2636,7 +2636,7 @@ class getAlign2RegOp { } class getEquivalentAGPROperand { - defvar Size = RC.RegClass.Size; + defvar Size = !cast(RC.RegClass).Size; RegisterOperand ret = !cond(!eq(Size, 32) : RegisterOperand, !eq(Size, 64) : RegisterOperand, @@ -2647,7 +2647,7 @@ class getEquivalentAGPROperand { } class getEquivalentVGPROperand { - defvar Size = RC.RegClass.Size; + defvar Size = !cast(RC.RegClass).Size; RegisterOperand ret = !cond(!eq(Size, 32) : RegisterOperand, !eq(Size, 64) : RegisterOperand, diff --git a/llvm/lib/Target/AVR/AsmParser/AVRAsmParser.cpp b/llvm/lib/Target/AVR/AsmParser/AVRAsmParser.cpp index a8650146e988a..fc794c4968b8c 100644 --- a/llvm/lib/Target/AVR/AsmParser/AVRAsmParser.cpp +++ b/llvm/lib/Target/AVR/AsmParser/AVRAsmParser.cpp @@ -764,7 +764,7 @@ unsigned AVRAsmParser::validateTargetOperandClass(MCParsedAsmOperand &AsmOp, RegName << "r" << RegNum; if (MCRegister Reg = MatchRegisterName(RegName.str())) { Op.makeReg(Reg); - if (validateOperandClass(Op, Expected) == Match_Success) { + if (validateOperandClass(Op, Expected, *STI) == Match_Success) { return Match_Success; } } @@ -780,7 +780,7 @@ unsigned AVRAsmParser::validateTargetOperandClass(MCParsedAsmOperand &AsmOp, if (correspondingDREG) { Op.makeReg(correspondingDREG); - return validateOperandClass(Op, Expected); + return validateOperandClass(Op, Expected, *STI); } } } diff --git a/llvm/lib/Target/SystemZ/AsmParser/SystemZAsmParser.cpp b/llvm/lib/Target/SystemZ/AsmParser/SystemZAsmParser.cpp index 597ce8eabfeb2..4efb305b2d55a 100644 --- a/llvm/lib/Target/SystemZ/AsmParser/SystemZAsmParser.cpp +++ b/llvm/lib/Target/SystemZ/AsmParser/SystemZAsmParser.cpp @@ -1339,7 +1339,7 @@ bool SystemZAsmParser::parseDirectiveInsn(SMLoc L) { MatchClassKind Kind = Entry->OperandKinds[I]; // Verify operand. - unsigned Res = validateOperandClass(Operand, Kind); + unsigned Res = validateOperandClass(Operand, Kind, *STI); if (Res != Match_Success) return Error(Operand.getStartLoc(), "unexpected operand type"); diff --git a/llvm/test/TableGen/RegClassByHwMode.td b/llvm/test/TableGen/RegClassByHwMode.td new file mode 100644 index 0000000000000..3944c7eb79a7a --- /dev/null +++ b/llvm/test/TableGen/RegClassByHwMode.td @@ -0,0 +1,429 @@ +// RUN: llvm-tblgen -gen-instr-info -I %p/../../include %s -o - | FileCheck -check-prefix=INSTRINFO %s +// RUN: llvm-tblgen -gen-asm-matcher -I %p/../../include %s -o - | FileCheck -check-prefix=ASMMATCHER %s +// RUN: llvm-tblgen -gen-disassembler -I %p/../../include %s -o - | FileCheck -check-prefix=DISASM %s +// RUN: llvm-tblgen -gen-dag-isel -I %p/../../include %s -o - | FileCheck -check-prefix=ISEL-SDAG %s +// RUN: llvm-tblgen -gen-global-isel -I %p/../../include %s -o - | FileCheck -check-prefix=ISEL-GISEL %s + +include "llvm/Target/Target.td" + + +// INSTRINFO: #if defined(GET_INSTRINFO_MC_DESC) || defined(GET_INSTRINFO_CTOR_DTOR) +// INSTRINFO-NEXT: namespace { +// INSTRINFO-NEXT: enum RegClassByHwModeUses : uint16_t { +// INSTRINFO-NEXT: MyPtrRC, +// INSTRINFO-NEXT: XRegs_EvenIfRequired, +// INSTRINFO-NEXT: YRegs_EvenIfRequired, +// INSTRINFO-NEXT: }; +// INSTRINFO-NEXT: } + +// INSTRINFO: { MyTarget::XRegsRegClassID, 0, MCOI::OPERAND_REGISTER, 0 }, +// INSTRINFO: { MyTarget::XRegs_EvenRegClassID, 0, MCOI::OPERAND_REGISTER, 0 }, +// INSTRINFO: { YRegs_EvenIfRequired, 0|(1< MCK_LAST_REGISTER && Kind <= MCK_LAST_REGCLASS_BY_HWMODE) { +// ASMMATCHER-NEXT: static constexpr MatchClassKind RegClassByHwModeMatchTable[4][3] = { +// ASMMATCHER-NEXT: { // DefaultMode +// ASMMATCHER-NEXT: MCK_PtrRegs32, +// ASMMATCHER-NEXT: MCK_XRegs, +// ASMMATCHER-NEXT: MCK_YRegs, +// ASMMATCHER-NEXT: }, +// ASMMATCHER-NEXT: { // EvenMode +// ASMMATCHER-NEXT: InvalidMatchClass, // Missing mode +// ASMMATCHER-NEXT: MCK_XRegs_Even, +// ASMMATCHER-NEXT: MCK_YRegs_Even, +// ASMMATCHER-NEXT: }, +// ASMMATCHER-NEXT: { // OddMode +// ASMMATCHER-NEXT: InvalidMatchClass, // Missing mode +// ASMMATCHER-NEXT: MCK_XRegs_Odd, +// ASMMATCHER-NEXT: InvalidMatchClass, // Missing mode +// ASMMATCHER-NEXT: }, +// ASMMATCHER-NEXT: { // Ptr64 +// ASMMATCHER-NEXT: MCK_PtrRegs64, +// ASMMATCHER-NEXT: InvalidMatchClass, // Missing mode +// ASMMATCHER-NEXT: InvalidMatchClass, // Missing mode +// ASMMATCHER-NEXT: }, +// ASMMATCHER-NEXT: }; +// ASMMATCHER-EMPTY: +// ASMMATCHER-NEXT: static_assert(MCK_LAST_REGCLASS_BY_HWMODE - MCK_LAST_REGISTER == 3); +// ASMMATCHER-NEXT: const unsigned HwMode = STI.getHwMode(MCSubtargetInfo::HwMode_RegClass); +// ASMMATCHER-NEXT: Kind = RegClassByHwModeMatchTable[HwMode][Kind - (MCK_LAST_REGISTER + 1)]; +// ASMMATCHER-NEXT: } + +// ASMMATCHER: if (Operand.isReg()) { + +// ASMMATCHER: static const MatchEntry MatchTable0[] = { +// ASMMATCHER: /* always_all */, MyTarget::ALWAYS_ALL, Convert__Reg1_0, AMFBS_None, { MCK_XRegs }, }, +// ASMMATCHER: /* always_even */, MyTarget::ALWAYS_EVEN, Convert__Reg1_0, AMFBS_None, { MCK_XRegs_Even }, }, +// ASMMATCHER: /* custom_decode */, MyTarget::CUSTOM_DECODE, Convert__RegByHwMode_YRegs_EvenIfRequired1_0, AMFBS_None, { MCK_RegByHwMode_YRegs_EvenIfRequired }, }, +// ASMMATCHER: /* even_if_mode */, MyTarget::EVEN_IF_MODE, Convert__RegByHwMode_XRegs_EvenIfRequired1_0, AMFBS_None, { MCK_RegByHwMode_XRegs_EvenIfRequired }, }, +// ASMMATCHER: /* my_mov */, MyTarget::MY_MOV, Convert__RegByHwMode_YRegs_EvenIfRequired1_0__RegByHwMode_XRegs_EvenIfRequired1_1, AMFBS_None, { MCK_RegByHwMode_YRegs_EvenIfRequired, MCK_RegByHwMode_XRegs_EvenIfRequired }, }, + + + +// DISASM: {{\[\[}}maybe_unused{{\]\]}} +// DISASM-NEXT: static DecodeStatus DecodeMyPtrRCRegClassByHwMode(MCInst &Inst, unsigned Imm, uint64_t Addr, const MCDisassembler *Decoder) { +// DISASM-NEXT: switch (Decoder->getSubtargetInfo().getHwMode(MCSubtargetInfo::HwMode_RegClass)) { +// DISASM-NEXT: case 0: // DefaultMode +// DISASM-NEXT: return DecodePtrRegs32RegisterClass(Inst, Imm, Addr, Decoder); +// DISASM-NEXT: case 3: // Ptr64 +// DISASM-NEXT: return DecodePtrRegs64RegisterClass(Inst, Imm, Addr, Decoder); +// DISASM-NEXT: default: +// DISASM-NEXT: llvm_unreachable("no decoder for hwmode"); +// DISASM-NEXT: } +// DISASM-NEXT: } + +// DISASM: {{\[\[}}maybe_unused{{\]\]}} +// DISASM-NEXT: static DecodeStatus DecodeXRegs_EvenIfRequiredRegClassByHwMode(MCInst &Inst, unsigned Imm, uint64_t Addr, const MCDisassembler *Decoder) { +// DISASM-NEXT: switch (Decoder->getSubtargetInfo().getHwMode(MCSubtargetInfo::HwMode_RegClass)) { +// DISASM-NEXT: case 0: // DefaultMode +// DISASM-NEXT: return DecodeXRegsRegisterClass(Inst, Imm, Addr, Decoder); +// DISASM-NEXT: case 1: // EvenMode +// DISASM-NEXT: return DecodeXRegs_EvenRegisterClass(Inst, Imm, Addr, Decoder); +// DISASM-NEXT: case 2: // OddMode +// DISASM-NEXT: return DecodeXRegs_OddRegisterClass(Inst, Imm, Addr, Decoder); +// DISASM-NEXT: default: +// DISASM-NEXT: llvm_unreachable("no decoder for hwmode"); +// DISASM-NEXT: } +// DISASM-NEXT:} +// DISASM-EMPTY: +// DISASM: {{\[\[}}maybe_unused{{\]\]}} +// DISASM-NEXT: static DecodeStatus DecodeYRegs_EvenIfRequiredRegClassByHwMode(MCInst &Inst, unsigned Imm, uint64_t Addr, const MCDisassembler *Decoder) { +// DISASM-NEXT: switch (Decoder->getSubtargetInfo().getHwMode(MCSubtargetInfo::HwMode_RegClass)) { +// DISASM-NEXT: case 0: // DefaultMode +// DISASM-NEXT: return DecodeYRegsRegisterClass(Inst, Imm, Addr, Decoder); +// DISASM-NEXT: case 1: // EvenMode +// DISASM-NEXT: return DecodeYRegs_EvenRegisterClass(Inst, Imm, Addr, Decoder); +// DISASM-NEXT: default: +// DISASM-NEXT: llvm_unreachable("no decoder for hwmode"); +// DISASM-NEXT: } +// DISASM-NEXT:} + +// DISASM: static DecodeStatus decodeToMCInst( +// DISASM: switch (Idx) { +// DISASM: case 0: +// DISASM: if (!Check(S, DecodeYRegs_EvenIfRequiredRegClassByHwMode(MI, tmp, Address, Decoder))) { return MCDisassembler::Fail; } +// DISASM: if (!Check(S, DecodeXRegs_EvenIfRequiredRegClassByHwMode(MI, tmp, Address, Decoder))) { return MCDisassembler::Fail; } + +// DISASM: case 1: +// DISASM: if (!Check(S, DecodeXRegs_EvenIfRequiredRegClassByHwMode(MI, tmp, Address, Decoder))) { return MCDisassembler::Fail; } + +// DISASM: case 2: +// DISASM: if (!Check(S, DecodeXRegs_EvenRegisterClass(MI, tmp, Address, Decoder))) { return MCDisassembler::Fail; } +// DISASM: case 3: +// DISASM: if (!Check(S, DecodeXRegsRegisterClass(MI, tmp, Address, Decoder))) { return MCDisassembler::Fail; } + +// DISASM: case 4: +// DISASM: if (!Check(S, YEvenIfRequiredCustomDecoder(MI, tmp, Address, Decoder))) { return MCDisassembler::Fail; } + + +// ISEL-SDAG: MatcherTable +// ISEL-SDAG: OPC_SwitchOpcode /*2 cases */, {{[0-9]+}}, TARGET_VAL(ISD::STORE), +// ISEL-SDAG: OPC_RecordMemRef, +// ISEL-SDAG: OPC_RecordNode, // #0 = 'st' chained node +// ISEL-SDAG: OPC_RecordChild1, // #1 = $val +// ISEL-SDAG-NEXT: OPC_RecordChild2, // #2 = $src +// ISEL-SDAG-NEXT: OPC_CheckChild2TypeI64, +// ISEL-SDAG-NEXT: OPC_CheckPredicate2, // Predicate_unindexedstore +// ISEL-SDAG-NEXT: OPC_CheckPredicate3, // Predicate_store +// ISEL-SDAG: OPC_MorphNodeTo0, TARGET_VAL(MyTarget::MY_STORE), 0|OPFL_Chain|OPFL_MemRefs, + +// ISEL-SDAG: /*SwitchOpcode*/ {{[0-9]+}}, TARGET_VAL(ISD::LOAD), +// ISEL-SDAG-NEXT: OPC_RecordMemRef, +// ISEL-SDAG-NEXT: OPC_RecordNode, // #0 = 'ld' chained node +// ISEL-SDAG-NEXT: OPC_RecordChild1, // #1 = $src +// ISEL-SDAG-NEXT: OPC_CheckTypeI64, +// ISEL-SDAG-NEXT: OPC_Scope, {{[0-9]+}}, /*->{{[0-9]+}}*/ // 2 children in Scope +// ISEL-SDAG-NEXT: OPC_CheckChild1TypeI32, +// ISEL-SDAG-NEXT: OPC_CheckPredicate0, // Predicate_unindexedload +// ISEL-SDAG-NEXT: OPC_CheckPredicate1, // Predicate_load +// ISEL-SDAG-NEXT: OPC_Scope, {{[0-9]+}}, /*->{{[0-9]+}}*/ // 3 children in Scope +// ISEL-SDAG-NEXT: OPC_CheckPatternPredicate1, // (Subtarget->hasAlignedRegisters()) +// ISEL-SDAG-NEXT: OPC_EmitMergeInputChains1_0, +// ISEL-SDAG-NEXT: OPC_MorphNodeTo1, TARGET_VAL(MyTarget::MY_LOAD), 0|OPFL_Chain|OPFL_MemRefs, + +// ISEL-SDAG: /*Scope*/ +// ISEL-SDAG: OPC_CheckPatternPredicate2, // (Subtarget->hasUnalignedRegisters()) +// ISEL-SDAG-NEXT: OPC_EmitMergeInputChains1_0, +// ISEL-SDAG-NEXT: OPC_MorphNodeTo1, TARGET_VAL(MyTarget::MY_LOAD), 0|OPFL_Chain|OPFL_MemRefs, + +// ISEL-SDAG: /*Scope*/ +// ISEL-SDAG: OPC_CheckPatternPredicate3, // !((Subtarget->hasAlignedRegisters())) && !((Subtarget->hasUnalignedRegisters())) && !((Subtarget->isPtr64())) +// ISEL-SDAG-NEXT: OPC_EmitMergeInputChains1_0, +// ISEL-SDAG-NEXT: OPC_MorphNodeTo1, TARGET_VAL(MyTarget::MY_LOAD), 0|OPFL_Chain|OPFL_MemRefs, + +// ISEL-SDAG: /*Scope*/ +// ISEL-SDAG-NEXT: OPC_CheckChild1TypeI64, +// ISEL-SDAG-NEXT: OPC_CheckPredicate0, // Predicate_unindexedload +// ISEL-SDAG-NEXT: OPC_CheckPredicate1, // Predicate_load +// ISEL-SDAG-NEXT: OPC_CheckPatternPredicate0, // (Subtarget->isPtr64()) +// ISEL-SDAG-NEXT: OPC_EmitMergeInputChains1_0, +// ISEL-SDAG-NEXT: OPC_MorphNodeTo1, TARGET_VAL(MyTarget::MY_LOAD), 0|OPFL_Chain|OPFL_MemRefs, + + + + + +// ISEL-GISEL: GIM_Try, /*On fail goto*//*Label 3*/ GIMT_Encode4(148), +// ISEL-GISEL-NEXT: GIM_RootCheckType, /*Op*/0, /*Type*/GILLT_s64, +// ISEL-GISEL-NEXT: GIM_CheckAtomicOrdering, /*MI*/0, /*Order*/(uint8_t)AtomicOrdering::NotAtomic, +// ISEL-GISEL-NEXT: GIM_CheckMemorySizeEqualToLLT, /*MI*/0, /*MMO*/0, /*OpIdx*/0, +// ISEL-GISEL-NEXT: GIM_RootCheckRegBankForClass, /*Op*/0, /*RC*/GIMT_Encode2(MyTarget::XRegsRegClassID), +// ISEL-GISEL-NEXT: GIM_Try, /*On fail goto*//*Label 4*/ GIMT_Encode4(101), +// ISEL-GISEL-NEXT: GIM_CheckPointerToAny, /*MI*/0, /*Op*/1, /*SizeInBits*/32, + +// FIXME: This should be a direct check for regbank, not have an incorrect class + +// ISEL-GISEL-NEXT: GIM_RootCheckRegBankForClass, /*Op*/1, /*RC*/GIMT_Encode2(MyTarget::PtrRegs32RegClassID), +// ISEL-GISEL-NEXT: GIM_Try, /*On fail goto*//*Label 5*/ GIMT_Encode4(85), // Rule ID 1 // +// ISEL-GISEL-NEXT: GIM_CheckFeatures, GIMT_Encode2(GIFBS_HwMode1), +// ISEL-GISEL-NEXT: // (ld:{ *:[i64] } PtrRegOperand:{ *:[i32] }:$src)<><> => (MY_LOAD:{ *:[i64] } ?:{ *:[i32] }:$src) +// ISEL-GISEL-NEXT: GIR_MutateOpcode, /*InsnID*/0, /*RecycleInsnID*/0, /*Opcode*/GIMT_Encode2(MyTarget::MY_LOAD), +// ISEL-GISEL-NEXT: GIR_RootConstrainSelectedInstOperands, +// ISEL-GISEL-NEXT: // GIR_Coverage, 1, +// ISEL-GISEL-NEXT: GIR_Done, +// ISEL-GISEL-NEXT: // Label 5: @85 +// ISEL-GISEL-NEXT: GIM_Try, /*On fail goto*//*Label 6*/ GIMT_Encode4(100), // Rule ID 2 // +// ISEL-GISEL-NEXT: GIM_CheckFeatures, GIMT_Encode2(GIFBS_HwMode2), +// ISEL-GISEL-NEXT: // (ld:{ *:[i64] } PtrRegOperand:{ *:[i32] }:$src)<><> => (MY_LOAD:{ *:[i64] } ?:{ *:[i32] }:$src) +// ISEL-GISEL-NEXT: GIR_MutateOpcode, /*InsnID*/0, /*RecycleInsnID*/0, /*Opcode*/GIMT_Encode2(MyTarget::MY_LOAD), +// ISEL-GISEL-NEXT: GIR_RootConstrainSelectedInstOperands, +// ISEL-GISEL-NEXT: // GIR_Coverage, 2, +// ISEL-GISEL-NEXT: GIR_Done, +// ISEL-GISEL-NEXT: // Label 6: @100 +// ISEL-GISEL-NEXT: GIM_Reject, +// ISEL-GISEL-NEXT: // Label 4: @101 +// ISEL-GISEL-NEXT: GIM_Try, /*On fail goto*//*Label 7*/ GIMT_Encode4(124), // Rule ID 3 // +// ISEL-GISEL-NEXT: GIM_CheckFeatures, GIMT_Encode2(GIFBS_HwMode0), +// ISEL-GISEL-NEXT: // MIs[0] src +// ISEL-GISEL-NEXT: GIM_CheckPointerToAny, /*MI*/0, /*Op*/1, /*SizeInBits*/64, +// ISEL-GISEL-NEXT: GIM_RootCheckRegBankForClass, /*Op*/1, /*RC*/GIMT_Encode2(MyTarget::PtrRegs32RegClassID), +// ISEL-GISEL-NEXT: // (ld:{ *:[i64] } PtrRegOperand:{ *:[i64] }:$src)<><> => (MY_LOAD:{ *:[i64] } ?:{ *:[i64] }:$src) +// ISEL-GISEL-NEXT: GIR_MutateOpcode, /*InsnID*/0, /*RecycleInsnID*/0, /*Opcode*/GIMT_Encode2(MyTarget::MY_LOAD), +// ISEL-GISEL-NEXT: GIR_RootConstrainSelectedInstOperands, +// ISEL-GISEL-NEXT: // GIR_Coverage, 3, +// ISEL-GISEL-NEXT: GIR_Done, +// ISEL-GISEL-NEXT: // Label 7: @124 +// ISEL-GISEL-NEXT: GIM_Try, /*On fail goto*//*Label 8*/ GIMT_Encode4(147), // Rule ID 4 // +// ISEL-GISEL-NEXT: GIM_CheckFeatures, GIMT_Encode2(GIFBS_HwMode3), +// ISEL-GISEL-NEXT: // MIs[0] src +// ISEL-GISEL-NEXT: GIM_CheckPointerToAny, /*MI*/0, /*Op*/1, /*SizeInBits*/32, +// ISEL-GISEL-NEXT: GIM_RootCheckRegBankForClass, /*Op*/1, /*RC*/GIMT_Encode2(MyTarget::PtrRegs32RegClassID), +// ISEL-GISEL-NEXT: // (ld:{ *:[i64] } PtrRegOperand:{ *:[i32] }:$src)<><> => (MY_LOAD:{ *:[i64] } ?:{ *:[i32] }:$src) +// ISEL-GISEL-NEXT: GIR_MutateOpcode, /*InsnID*/0, /*RecycleInsnID*/0, /*Opcode*/GIMT_Encode2(MyTarget::MY_LOAD), +// ISEL-GISEL-NEXT: GIR_RootConstrainSelectedInstOperands, +// ISEL-GISEL-NEXT: // GIR_Coverage, 4, +// ISEL-GISEL-NEXT: GIR_Done, +// ISEL-GISEL-NEXT: // Label 8: @147 +// ISEL-GISEL-NEXT: GIM_Reject, +// ISEL-GISEL-NEXT: // Label 3: @148 +// ISEL-GISEL-NEXT: GIM_Reject, +// ISEL-GISEL-NEXT: // Label 1: @149 +// ISEL-GISEL-NEXT: GIM_Try, /*On fail goto*//*Label 9*/ GIMT_Encode4(186), // Rule ID 0 // +// ISEL-GISEL-NEXT: GIM_CheckFeatures, GIMT_Encode2(GIFBS_HwMode0), +// ISEL-GISEL-NEXT: GIM_RootCheckType, /*Op*/0, /*Type*/GILLT_s64, +// ISEL-GISEL-NEXT: GIM_CheckAtomicOrdering, /*MI*/0, /*Order*/(uint8_t)AtomicOrdering::NotAtomic, +// ISEL-GISEL-NEXT: GIM_CheckMemorySizeEqualToLLT, /*MI*/0, /*MMO*/0, /*OpIdx*/0, +// ISEL-GISEL-NEXT: GIM_RootCheckRegBankForClass, /*Op*/0, /*RC*/GIMT_Encode2(MyTarget::XRegsRegClassID), +// ISEL-GISEL-NEXT: // MIs[0] src +// ISEL-GISEL-NEXT: GIM_CheckPointerToAny, /*MI*/0, /*Op*/1, /*SizeInBits*/64, +// ISEL-GISEL-NEXT: GIM_RootCheckRegBankForClass, /*Op*/1, /*RC*/GIMT_Encode2(MyTarget::PtrRegs32RegClassID), +// ISEL-GISEL-NEXT: // (st XRegs_EvenIfRequired:{ *:[i64] }:$val, MyPtrRC:{ *:[i64] }:$src)<><> => (MY_STORE ?:{ *:[i64] }:$val, XRegs_EvenIfRequired:{ *:[i64] }:$src) +// ISEL-GISEL-NEXT: GIR_MutateOpcode, /*InsnID*/0, /*RecycleInsnID*/0, /*Opcode*/GIMT_Encode2(MyTarget::MY_STORE), +// ISEL-GISEL-NEXT: GIR_RootConstrainSelectedInstOperands, + + + +def HasAlignedRegisters : Predicate<"Subtarget->hasAlignedRegisters()">; +def HasUnalignedRegisters : Predicate<"Subtarget->hasUnalignedRegisters()">; +def IsPtr64 : Predicate<"Subtarget->isPtr64()">; + +// FIXME: In reality these should be mutually exclusive and we need +// the cross product of even mode / ptr size. i.e. EvenModePtr64, +// OddMode32 etc. For the purposes of this test where we won't be +// executing the code to compute a mode ID, it's simpler to pretend +// these are orthogonal. +def EvenMode : HwMode<[HasAlignedRegisters]>; +def OddMode : HwMode<[HasUnalignedRegisters]>; +def Ptr64 : HwMode<[IsPtr64]>; + +class MyReg + : Register { + let Namespace = "MyTarget"; +} + +class MyClass types, dag registers> + : RegisterClass<"MyTarget", types, size, registers> { + let Size = size; +} + +def X0 : MyReg<"x0">; +def X1 : MyReg<"x1">; +def X2 : MyReg<"x2">; +def X3 : MyReg<"x3">; +def X4 : MyReg<"x4">; +def X5 : MyReg<"x5">; +def X6 : MyReg<"x6">; + +def Y0 : MyReg<"y0">; +def Y1 : MyReg<"y1">; +def Y2 : MyReg<"y2">; +def Y3 : MyReg<"y3">; +def Y4 : MyReg<"y4">; +def Y5 : MyReg<"y5">; +def Y6 : MyReg<"y6">; + + + +def P0_32 : MyReg<"p0">; +def P1_32 : MyReg<"p1">; +def P2_32 : MyReg<"p2">; +def P3_32 : MyReg<"p3">; + +def P0_64 : MyReg<"p0_64">; +def P1_64 : MyReg<"p1_64">; +def P2_64 : MyReg<"p2_64">; +def P3_64 : MyReg<"p3_64">; + + + +def XRegs : RegisterClass<"MyTarget", [i64], 64, (add X0, X1, X2, X3, X4, X5, X6)>; +def XRegs_Odd : RegisterClass<"MyTarget", [i64], 64, (add X1, X3, X5)>; +def XRegs_Even : RegisterClass<"MyTarget", [i64], 64, (add X0, X2, X4, X6)>; + +def XRegs_EvenIfRequired : RegClassByHwMode<[DefaultMode, EvenMode, OddMode], + [XRegs, XRegs_Even, XRegs_Odd]>; + +def YRegs : RegisterClass<"MyTarget", [i64], 64, (add Y0, Y1, Y2, Y3, Y4, Y5, Y6)>; +def YRegs_Even : RegisterClass<"MyTarget", [i64], 64, (add Y0, Y2, Y4, Y6)>; + +def YRegs_EvenIfRequired : RegClassByHwMode<[DefaultMode, EvenMode], + [YRegs, YRegs_Even]>; + + +def PtrRegs32 : RegisterClass<"MyTarget", [i32], 32, (add P0_32, P1_32, P2_32, P3_32)>; +def PtrRegs64 : RegisterClass<"MyTarget", [i64], 64, (add P0_64, P1_64, P2_64, P3_64)>; + +def MyPtrRC : RegClassByHwMode<[DefaultMode, Ptr64], + [PtrRegs32, PtrRegs64]>, Operand; + + +def PtrRegOperand : RegisterOperand, Operand; + + +def CustomDecodeYEvenIfRequired : RegisterOperand { + let DecoderMethod = "YEvenIfRequiredCustomDecoder"; +} + +class TestInstruction : Instruction { + let Size = 2; + let Namespace = "MyTarget"; + let hasSideEffects = false; + let hasExtraSrcRegAllocReq = false; + let hasExtraDefRegAllocReq = false; + + field bits<16> Inst; + bits<3> dst; + bits<3> src; + bits<3> opcode; + + let Inst{2-0} = dst; + let Inst{5-3} = src; + let Inst{7-5} = opcode; +} + +def SpecialOperand : RegisterOperand; + +def MY_MOV : TestInstruction { + let OutOperandList = (outs YRegs_EvenIfRequired:$dst); + let InOperandList = (ins XRegs_EvenIfRequired:$src); + let AsmString = "my_mov $dst, $src"; + let opcode = 0; +} + +def EVEN_IF_MODE : TestInstruction { + let OutOperandList = (outs); + let InOperandList = (ins XRegs_EvenIfRequired:$src); + let AsmString = "even_if_mode $src"; + let opcode = 1; +} + +def ALWAYS_EVEN : TestInstruction { + let OutOperandList = (outs); + let InOperandList = (ins XRegs_Even:$src); + let AsmString = "always_even $src"; + let opcode = 2; +} + +def ALWAYS_ALL : TestInstruction { + let OutOperandList = (outs); + let InOperandList = (ins XRegs:$src); + let AsmString = "always_all $src"; + let opcode = 3; +} + +def CUSTOM_DECODE : TestInstruction { + let OutOperandList = (outs); + let InOperandList = (ins CustomDecodeYEvenIfRequired:$src); + let AsmString = "custom_decode $src"; + let opcode = 4; +} + +def MyTargetMov : SDNode<"MyTarget::MY_MOV", SDTUnaryOp, []>; + +// Test 2 different cases directly in the instruction +def MY_STORE : TestInstruction { + let OutOperandList = (outs); + let InOperandList = (ins XRegs_EvenIfRequired:$src, MyPtrRC:$dst); + let AsmString = "my_store $src, $dst"; + let opcode = 5; +} + +// Test 2 different cases wrapped by RegisterOperand +def MY_LOAD : TestInstruction { + let OutOperandList = (outs RegisterOperand:$dst); + let InOperandList = (ins PtrRegOperand:$src); + let AsmString = "my_load $dst, $src"; + let opcode = 6; +} + + +// Direct RegClassByHwMode usage +def : Pat< + (store XRegs_EvenIfRequired:$val, MyPtrRC:$src), + (MY_STORE $val, XRegs_EvenIfRequired:$src) +>; + +// Wrapped in RegisterOperand +def : Pat< + (i64 (load PtrRegOperand:$src)), + (MY_LOAD $src) +>; + +def MyTargetISA : InstrInfo; +def MyTarget : Target { let InstructionSet = MyTargetISA; } diff --git a/llvm/utils/TableGen/AsmMatcherEmitter.cpp b/llvm/utils/TableGen/AsmMatcherEmitter.cpp index 29d26d5237695..ef41d93a09bc8 100644 --- a/llvm/utils/TableGen/AsmMatcherEmitter.cpp +++ b/llvm/utils/TableGen/AsmMatcherEmitter.cpp @@ -166,9 +166,14 @@ struct ClassInfo { /// RegisterClass0+1, and so on. RegisterClass0, + /// The (first) register class by hwmode, subsequent register classes by + /// hwmode are + /// RegisterClassByHwMode0+1, and so on. + RegisterClassByHwMode0 = 1 << 12, + /// The (first) user defined class, subsequent user defined classes are /// UserClass0+1, and so on. - UserClass0 = 1 << 16 + UserClass0 = 1 << 24 }; /// Kind - The class kind, which is either a predefined kind, or (UserClass0 + @@ -224,7 +229,11 @@ struct ClassInfo { public: /// isRegisterClass() - Check if this is a register class. bool isRegisterClass() const { - return Kind >= RegisterClass0 && Kind < UserClass0; + return Kind >= RegisterClass0 && Kind < RegisterClassByHwMode0; + } + + bool isRegisterClassByHwMode() const { + return Kind >= RegisterClassByHwMode0 && Kind < UserClass0; } /// isUserClass() - Check if this is a user defined class. @@ -251,6 +260,9 @@ struct ClassInfo { return !Tmp.empty(); } + if (isRegisterClassByHwMode() || RHS.isRegisterClassByHwMode()) + return isRegisterClassByHwMode() == RHS.isRegisterClassByHwMode(); + // Otherwise we have two users operands; they are related if they are in the // same class hierarchy. // @@ -315,7 +327,8 @@ struct ClassInfo { return false; // First, enforce the ordering between the three different types of class. - // Tokens sort before registers, which sort before user classes. + // Tokens sort before registers, which sort before regclass by hwmode, which + // sort before user classes. if (Kind == Token) { if (RHS.Kind != Token) return true; @@ -323,9 +336,15 @@ struct ClassInfo { } else if (isRegisterClass()) { if (RHS.Kind == Token) return false; - else if (RHS.isUserClass()) + else if (RHS.isUserClass() || RHS.isRegisterClassByHwMode()) return true; assert(RHS.isRegisterClass()); + } else if (isRegisterClassByHwMode()) { + if (RHS.Kind == Token || RHS.isRegisterClass()) + return false; + else if (RHS.isUserClass()) + return true; + assert(RHS.isRegisterClassByHwMode()); } else if (isUserClass()) { if (!RHS.isUserClass()) return false; @@ -353,6 +372,10 @@ struct ClassInfo { // a set will always sort before all of it's strict supersets. if (Registers.size() != RHS.Registers.size()) return Registers.size() < RHS.Registers.size(); + } else if (isRegisterClassByHwMode()) { + // Ensure the MCK enum entries are in the same order as RegClassIDs. The + // lookup table to from RegByHwMode to concrete class relies on it. + return Kind < RHS.Kind; } else { llvm_unreachable("Unknown ClassInfoKind"); } @@ -1205,9 +1228,13 @@ ClassInfo *AsmMatcherInfo::getOperandClass(const Record *Rec, int SubOpIdx) { PrintFatalError(Rec->getLoc(), "RegisterOperand `" + Rec->getName() + "' has no associated register class!\n"); - if (ClassInfo *CI = RegisterClassClasses[ClassRec]) - return CI; - PrintFatalError(Rec->getLoc(), "register class has no class info!"); + + if (ClassRec->isSubClassOf("RegisterClassLike")) { + if (ClassInfo *CI = RegisterClassClasses[ClassRec]) + return CI; + + PrintFatalError(Rec->getLoc(), "register class has no class info!"); + } } if (Rec->isSubClassOf("RegisterClass")) { @@ -1216,13 +1243,19 @@ ClassInfo *AsmMatcherInfo::getOperandClass(const Record *Rec, int SubOpIdx) { PrintFatalError(Rec->getLoc(), "register class has no class info!"); } - if (!Rec->isSubClassOf("Operand")) + if (Rec->isSubClassOf("Operand")) { + const Record *MatchClass = Rec->getValueAsDef("ParserMatchClass"); + if (ClassInfo *CI = AsmOperandClasses[MatchClass]) + return CI; + } else if (Rec->isSubClassOf("RegisterClassLike")) { + if (ClassInfo *CI = RegisterClassClasses[Rec]) + return CI; + PrintFatalError(Rec->getLoc(), "register class has no class info!"); + } else { PrintFatalError(Rec->getLoc(), "Operand `" + Rec->getName() + "' does not derive from class Operand!\n"); - const Record *MatchClass = Rec->getValueAsDef("ParserMatchClass"); - if (ClassInfo *CI = AsmOperandClasses[MatchClass]) - return CI; + } PrintFatalError(Rec->getLoc(), "operand has no match class!"); } @@ -1307,6 +1340,7 @@ void AsmMatcherInfo::buildRegisterClasses( CI->DefaultMethod = ""; // unused RegisterSetClasses.try_emplace(RS, CI); ++Index; + assert(CI->isRegisterClass()); } // Find the superclasses; we could compute only the subgroup lattice edges, @@ -1348,6 +1382,32 @@ void AsmMatcherInfo::buildRegisterClasses( CI->DiagnosticType = RC.getName(); RegisterClassClasses.try_emplace(Def, CI); + assert(CI->isRegisterClass()); + } + + unsigned RegClassByHwModeIndex = 0; + for (const Record *ClassByHwMode : Target.getAllRegClassByHwMode()) { + Classes.emplace_front(); + ClassInfo *CI = &Classes.front(); + CI->Kind = ClassInfo::RegisterClassByHwMode0 + RegClassByHwModeIndex; + + CI->ClassName = "RegByHwMode_" + ClassByHwMode->getName().str(); + CI->Name = "MCK_" + CI->ClassName; + CI->ValueName = ClassByHwMode->getName(); + CI->PredicateMethod = ""; // unused + CI->RenderMethod = "addRegOperands"; + // CI->Registers = RS; + // FIXME: diagnostic type. + CI->DiagnosticType = ""; + CI->IsOptional = false; + CI->DefaultMethod = ""; // unused + // RegisterSetClasses.try_emplace(RS, CI); + + ++RegClassByHwModeIndex; + + assert(CI->isRegisterClassByHwMode()); + + RegisterClassClasses.try_emplace(ClassByHwMode, CI); } // Populate the map for individual registers. @@ -2367,10 +2427,14 @@ static void emitMatchClassEnumeration(CodeGenTarget &Target, for (const auto &CI : Infos) { if (LastKind == ClassInfo::Token && CI.Kind != ClassInfo::Token) { OS << " MCK_LAST_TOKEN = " << LastName << ",\n"; + } else if (LastKind < ClassInfo::RegisterClassByHwMode0 && + CI.Kind >= ClassInfo::RegisterClassByHwMode0) { + OS << " MCK_LAST_REGISTER = " << LastName << ",\n"; } else if (LastKind < ClassInfo::UserClass0 && CI.Kind >= ClassInfo::UserClass0) { - OS << " MCK_LAST_REGISTER = " << LastName << ",\n"; + OS << " MCK_LAST_REGCLASS_BY_HWMODE = " << LastName << ",\n"; } + LastKind = (ClassInfo::ClassInfoKind)CI.Kind; LastName = CI.Name; @@ -2382,6 +2446,8 @@ static void emitMatchClassEnumeration(CodeGenTarget &Target, OS << "register class '" << CI.ValueName << "'\n"; else OS << "derived register class\n"; + } else if (CI.isRegisterClassByHwMode()) { + OS << "register class by hwmode\n"; } else { OS << "user defined class '" << CI.ValueName << "'\n"; } @@ -2454,7 +2520,7 @@ static void emitRegisterMatchErrorFunc(AsmMatcherInfo &Info, raw_ostream &OS) { static void emitValidateOperandClass(const CodeGenTarget &Target, AsmMatcherInfo &Info, raw_ostream &OS) { OS << "static unsigned validateOperandClass(MCParsedAsmOperand &GOp, " - << "MatchClassKind Kind) {\n"; + << "MatchClassKind Kind, const MCSubtargetInfo &STI) {\n"; OS << " " << Info.Target.getName() << "Operand &Operand = (" << Info.Target.getName() << "Operand &)GOp;\n"; @@ -2494,8 +2560,68 @@ static void emitValidateOperandClass(const CodeGenTarget &Target, } OS << " } // end switch (Kind)\n\n"; + const CodeGenRegBank &RegBank = Target.getRegBank(); + ArrayRef RegClassesByHwMode = Target.getAllRegClassByHwMode(); + unsigned NumClassesByHwMode = RegClassesByHwMode.size(); + + if (!RegClassesByHwMode.empty()) { + OS << " if (Operand.isReg() && Kind > MCK_LAST_REGISTER &&" + " Kind <= MCK_LAST_REGCLASS_BY_HWMODE) {\n"; + + const CodeGenHwModes &CGH = Target.getHwModes(); + unsigned NumModes = CGH.getNumModeIds(); + + OS << indent(4) + << "static constexpr MatchClassKind RegClassByHwModeMatchTable[" + << NumModes << "][" << RegClassesByHwMode.size() << "] = {\n"; + + // TODO: If the instruction predicates can statically resolve which hwmode, + // directly match the register class + for (unsigned M = 0; M < NumModes; ++M) { + OS << indent(6) << "{ // " << CGH.getModeName(M, /*IncludeDefault=*/true) + << '\n'; + for (unsigned I = 0; I != NumClassesByHwMode; ++I) { + const Record *Class = RegClassesByHwMode[I]; + const HwModeSelect &ModeSelect = CGH.getHwModeSelect(Class); + + bool Seen = false; + for (const HwModeSelect::PairType &P : ModeSelect.Items) { + if (P.first == M) { + const CodeGenRegisterClass *RegClass = + RegBank.getRegClass(P.second); + + const ClassInfo *CI = + Info.RegisterClassClasses.at(RegClass->getDef()); + + OS << indent(8) << CI->Name << ",\n"; + Seen = true; + break; + } + } + + if (!Seen) + OS << indent(8) << "InvalidMatchClass, // Missing mode\n"; + } + + OS << indent(6) << "},\n"; + } + + OS << indent(4) << "};\n\n"; + + OS << indent(4) + << "static_assert(MCK_LAST_REGCLASS_BY_HWMODE - MCK_LAST_REGISTER == " + << NumClassesByHwMode << ");\n"; + + OS << indent(4) + << "const unsigned HwMode = " + "STI.getHwMode(MCSubtargetInfo::HwMode_RegClass);\n" + "Kind = RegClassByHwModeMatchTable[HwMode][Kind - (MCK_LAST_REGISTER " + "+ 1)];\n" + " }\n\n"; + } + // Check for register operands, including sub-classes. - const auto &Regs = Target.getRegBank().getRegisters(); + const auto &Regs = RegBank.getRegisters(); StringRef Namespace = Regs.front().TheDef->getValueAsString("Namespace"); SmallVector Table(1 + Regs.size(), "InvalidMatchClass"); for (const auto &RC : Info.RegisterClasses) { @@ -3758,7 +3884,7 @@ void AsmMatcherEmitter::run(raw_ostream &OS) { } OS << " }\n"; OS << " MCParsedAsmOperand &Actual = *Operands[ActualIdx];\n"; - OS << " unsigned Diag = validateOperandClass(Actual, Formal);\n"; + OS << " unsigned Diag = validateOperandClass(Actual, Formal, *STI);\n"; OS << " if (Diag == Match_Success) {\n"; OS << " DEBUG_WITH_TYPE(\"asm-matcher\",\n"; OS << " dbgs() << \"match success using generic " diff --git a/llvm/utils/TableGen/AsmWriterEmitter.cpp b/llvm/utils/TableGen/AsmWriterEmitter.cpp index 9f32333f82100..c8c6c23bea014 100644 --- a/llvm/utils/TableGen/AsmWriterEmitter.cpp +++ b/llvm/utils/TableGen/AsmWriterEmitter.cpp @@ -945,7 +945,7 @@ void AsmWriterEmitter::EmitPrintAliasInstruction(raw_ostream &O) { if (Rec->isSubClassOf("RegisterOperand")) Rec = Rec->getValueAsDef("RegClass"); - if (Rec->isSubClassOf("RegisterClass")) { + if (Rec->isSubClassOf("RegisterClassLike")) { if (!IAP.isOpMapped(ROName)) { IAP.addOperand(ROName, MIOpNum, PrintMethodIdx); const Record *R = CGA.ResultOperands[i].getRecord(); diff --git a/llvm/utils/TableGen/Common/CodeGenDAGPatterns.cpp b/llvm/utils/TableGen/Common/CodeGenDAGPatterns.cpp index 37844663dfc33..7fdb6b97e435c 100644 --- a/llvm/utils/TableGen/Common/CodeGenDAGPatterns.cpp +++ b/llvm/utils/TableGen/Common/CodeGenDAGPatterns.cpp @@ -1789,6 +1789,23 @@ bool llvm::operator<(const SDTypeConstraint &LHS, const SDTypeConstraint &RHS) { return false; } +/// RegClassByHwMode acts like ValueTypeByHwMode, taking the type of the +/// register class from the active mode. +static TypeSetByHwMode getTypeForRegClassByHwMode(const CodeGenTarget &T, + const Record *R) { + TypeSetByHwMode TypeSet; + RegClassByHwMode Helper(R, T.getHwModes(), T); + + for (auto [ModeID, RegClass] : Helper) { + ArrayRef RegClassVTs = RegClass->getValueTypes(); + MachineValueTypeSet &ModeTypeSet = TypeSet.getOrCreate(ModeID); + for (const ValueTypeByHwMode &VT : RegClassVTs) + ModeTypeSet.insert(VT.getType(ModeID)); + } + + return TypeSet; +} + // Update the node type to match an instruction operand or result as specified // in the ins or outs lists on the instruction definition. Return true if the // type was actually changed. @@ -1814,13 +1831,16 @@ bool TreePatternNode::UpdateNodeTypeFromInst(unsigned ResNo, // Both RegisterClass and RegisterOperand operands derive their types from a // register class def. const Record *RC = nullptr; - if (Operand->isSubClassOf("RegisterClass")) + if (Operand->isSubClassOf("RegisterClassLike")) RC = Operand; else if (Operand->isSubClassOf("RegisterOperand")) RC = Operand->getValueAsDef("RegClass"); assert(RC && "Unknown operand type"); CodeGenTarget &Tgt = TP.getDAGPatterns().getTargetInfo(); + if (RC->isSubClassOf("RegClassByHwMode")) + return UpdateNodeType(ResNo, getTypeForRegClassByHwMode(Tgt, RC), TP); + return UpdateNodeType(ResNo, Tgt.getRegisterClass(RC).getValueTypes(), TP); } @@ -2306,6 +2326,10 @@ static TypeSetByHwMode getImplicitType(const Record *R, unsigned ResNo, return TypeSetByHwMode(); // Unknown. const Record *RegClass = R->getValueAsDef("RegClass"); const CodeGenTarget &T = TP.getDAGPatterns().getTargetInfo(); + + if (RegClass->isSubClassOf("RegClassByHwMode")) + return getTypeForRegClassByHwMode(T, RegClass); + return TypeSetByHwMode(T.getRegisterClass(RegClass).getValueTypes()); } @@ -2325,6 +2349,11 @@ static TypeSetByHwMode getImplicitType(const Record *R, unsigned ResNo, return TypeSetByHwMode(T.getRegisterClass(R).getValueTypes()); } + if (R->isSubClassOf("RegClassByHwMode")) { + const CodeGenTarget &T = CDP.getTargetInfo(); + return getTypeForRegClassByHwMode(T, R); + } + if (R->isSubClassOf("PatFrags")) { assert(ResNo == 0 && "FIXME: PatFrag with multiple results?"); // Pattern fragment types will be resolved when they are inlined. @@ -3581,7 +3610,7 @@ void CodeGenDAGPatterns::FindPatternInputsAndOutputs( continue; } - if (Val->getDef()->isSubClassOf("RegisterClass") || + if (Val->getDef()->isSubClassOf("RegisterClassLike") || Val->getDef()->isSubClassOf("ValueType") || Val->getDef()->isSubClassOf("RegisterOperand") || Val->getDef()->isSubClassOf("PointerLikeRegClass")) { diff --git a/llvm/utils/TableGen/Common/CodeGenInstAlias.cpp b/llvm/utils/TableGen/Common/CodeGenInstAlias.cpp index 54ea0f1bfad5a..fb1091015a78d 100644 --- a/llvm/utils/TableGen/Common/CodeGenInstAlias.cpp +++ b/llvm/utils/TableGen/Common/CodeGenInstAlias.cpp @@ -65,11 +65,15 @@ static Expected matchSimpleOperand(const Init *Arg, // Match 'RegClass:$name' or 'RegOp:$name'. if (const Record *ArgRC = getInitValueAsRegClass(Arg)) { - if (!T.getRegisterClass(OpRC).hasSubClass(&T.getRegisterClass(ArgRC))) - return createStringError( - "argument register class" + ArgRC->getName() + - " is not a subclass of operand register class " + - OpRC->getName()); + if (OpRC->isSubClassOf("RegisterClass")) { + if (!T.getRegisterClass(OpRC).hasSubClass(&T.getRegisterClass(ArgRC))) + return createStringError( + "argument register class" + ArgRC->getName() + + " is not a subclass of operand register class " + + OpRC->getName()); + } + // FIXME: Do some validation on RegClassByHwMode + if (!ArgName) return createStringError("register class argument must have a name"); return ResultOperand::createRecord(ArgName->getAsUnquotedString(), diff --git a/llvm/utils/TableGen/Common/CodeGenInstruction.cpp b/llvm/utils/TableGen/Common/CodeGenInstruction.cpp index ff70d50971b89..93d4f4bfe5d27 100644 --- a/llvm/utils/TableGen/Common/CodeGenInstruction.cpp +++ b/llvm/utils/TableGen/Common/CodeGenInstruction.cpp @@ -118,7 +118,7 @@ CGIOperandList::CGIOperandList(const Record *R) : TheDef(R) { VariadicOuts = true; isVariadic = true; continue; - } else if (Rec->isSubClassOf("RegisterClass")) { + } else if (Rec->isSubClassOf("RegisterClassLike")) { OperandType = "OPERAND_REGISTER"; } else if (!Rec->isSubClassOf("PointerLikeRegClass") && !Rec->isSubClassOf("unknown_class")) { diff --git a/llvm/utils/TableGen/Common/CodeGenTarget.h b/llvm/utils/TableGen/Common/CodeGenTarget.h index ac138344c83c6..59a04e182c0cc 100644 --- a/llvm/utils/TableGen/Common/CodeGenTarget.h +++ b/llvm/utils/TableGen/Common/CodeGenTarget.h @@ -134,6 +134,14 @@ class CodeGenTarget { const CodeGenRegisterClass &getRegisterClass(const Record *R) const; + /// Convenience wrapper to avoid hardcoding the name of RegClassByHwMode + /// everywhere. This is here instead of CodeGenRegBank to avoid the fatal + /// error that occurs when no RegisterClasses are defined when constructing + /// the bank. + ArrayRef getAllRegClassByHwMode() const { + return Records.getAllDerivedDefinitions("RegClassByHwMode"); + } + /// getRegisterVTs - Find the union of all possible SimpleValueTypes for the /// specified physical register. std::vector getRegisterVTs(const Record *R) const; diff --git a/llvm/utils/TableGen/Common/InfoByHwMode.cpp b/llvm/utils/TableGen/Common/InfoByHwMode.cpp index cb4f8876c648a..fd6494bc8cad1 100644 --- a/llvm/utils/TableGen/Common/InfoByHwMode.cpp +++ b/llvm/utils/TableGen/Common/InfoByHwMode.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "InfoByHwMode.h" +#include "CodeGenRegisters.h" #include "CodeGenTarget.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/Twine.h" @@ -186,6 +187,19 @@ void RegSizeInfoByHwMode::writeToStream(raw_ostream &OS) const { OS << '}'; } +RegClassByHwMode::RegClassByHwMode(const Record *R, const CodeGenHwModes &CGH, + const CodeGenTarget &Target) { + const HwModeSelect &MS = CGH.getHwModeSelect(R); + + for (const HwModeSelect::PairType &P : MS.Items) { + assert(P.second && P.second->isSubClassOf("RegisterClass") && + "Register class must subclass RegisterClass"); + const CodeGenRegisterClass &RegClass = Target.getRegisterClass(P.second); + if (!Map.try_emplace(P.first, &RegClass).second) + llvm_unreachable("duplicate entry"); + } +} + SubRegRange::SubRegRange(const Record *R) { Size = R->getValueAsInt("Size"); Offset = R->getValueAsInt("Offset"); diff --git a/llvm/utils/TableGen/Common/InfoByHwMode.h b/llvm/utils/TableGen/Common/InfoByHwMode.h index 7925599a98a0c..1d3bc434ced4f 100644 --- a/llvm/utils/TableGen/Common/InfoByHwMode.h +++ b/llvm/utils/TableGen/Common/InfoByHwMode.h @@ -28,6 +28,8 @@ namespace llvm { +class CodeGenRegisterClass; +class CodeGenTarget; class Record; class raw_ostream; @@ -244,6 +246,16 @@ struct EncodingInfoByHwMode : public InfoByHwMode { EncodingInfoByHwMode() = default; }; +struct RegClassByHwMode : public InfoByHwMode { +public: + RegClassByHwMode(const Record *R, const CodeGenHwModes &CGH, + const CodeGenTarget &Target); + RegClassByHwMode() = default; +}; + +raw_ostream &operator<<(raw_ostream &OS, const RegSizeInfo &T); +raw_ostream &operator<<(raw_ostream &OS, const RegClassByHwMode &T); + } // namespace llvm #endif // LLVM_UTILS_TABLEGEN_COMMON_INFOBYHWMODE_H diff --git a/llvm/utils/TableGen/Common/InstructionEncoding.cpp b/llvm/utils/TableGen/Common/InstructionEncoding.cpp index 22163e1898333..5917f2ace94eb 100644 --- a/llvm/utils/TableGen/Common/InstructionEncoding.cpp +++ b/llvm/utils/TableGen/Common/InstructionEncoding.cpp @@ -14,7 +14,10 @@ using namespace llvm; -static std::string findOperandDecoderMethod(const Record *Record) { +/// If this is explictly set value, return true for second. +std::pair +InstructionEncoding::findOperandDecoderMethod(const CodeGenTarget &Target, + const Record *Record) { std::string Decoder; const RecordVal *DecoderString = Record->getValue("DecoderMethod"); @@ -23,24 +26,27 @@ static std::string findOperandDecoderMethod(const Record *Record) { if (String) { Decoder = String->getValue().str(); if (!Decoder.empty()) - return Decoder; + return {Decoder, false}; } if (Record->isSubClassOf("RegisterOperand")) // Allows use of a DecoderMethod in referenced RegisterClass if set. - return findOperandDecoderMethod(Record->getValueAsDef("RegClass")); + return findOperandDecoderMethod(Target, Record->getValueAsDef("RegClass")); if (Record->isSubClassOf("RegisterClass")) { Decoder = "Decode" + Record->getName().str() + "RegisterClass"; + } else if (Record->isSubClassOf("RegClassByHwMode")) { + Decoder = "Decode" + Record->getName().str() + "RegClassByHwMode"; } else if (Record->isSubClassOf("PointerLikeRegClass")) { Decoder = "DecodePointerLikeRegClass" + utostr(Record->getValueAsInt("RegClassKind")); } - return Decoder; + return {Decoder, true}; } -static OperandInfo getOpInfo(const Record *TypeRecord) { +OperandInfo InstructionEncoding::getOpInfo(const CodeGenTarget &Target, + const Record *TypeRecord) { const RecordVal *HasCompleteDecoderVal = TypeRecord->getValue("hasCompleteDecoder"); const BitInit *HasCompleteDecoderBit = @@ -50,7 +56,8 @@ static OperandInfo getOpInfo(const Record *TypeRecord) { bool HasCompleteDecoder = HasCompleteDecoderBit ? HasCompleteDecoderBit->getValue() : true; - return OperandInfo(findOperandDecoderMethod(TypeRecord), HasCompleteDecoder); + return OperandInfo(findOperandDecoderMethod(Target, TypeRecord).first, + HasCompleteDecoder); } void InstructionEncoding::parseVarLenEncoding(const VarLenInst &VLI) { @@ -171,15 +178,16 @@ void InstructionEncoding::parseFixedLenEncoding( } } -void InstructionEncoding::parseVarLenOperands(const VarLenInst &VLI) { +void InstructionEncoding::parseVarLenOperands(const CodeGenTarget &Target, + const VarLenInst &VLI) { SmallVector TiedTo; for (const auto &[Idx, Op] : enumerate(Inst->Operands)) { if (Op.MIOperandInfo && Op.MIOperandInfo->getNumArgs() > 0) for (auto *Arg : Op.MIOperandInfo->getArgs()) - Operands.push_back(getOpInfo(cast(Arg)->getDef())); + Operands.push_back(getOpInfo(Target, cast(Arg)->getDef())); else - Operands.push_back(getOpInfo(Op.Rec)); + Operands.push_back(getOpInfo(Target, Op.Rec)); int TiedReg = Op.getTiedRegister(); TiedTo.push_back(-1); @@ -314,7 +322,8 @@ static void addOneOperandFields(const Record *EncodingDef, } } -void InstructionEncoding::parseFixedLenOperands(const BitsInit &Bits) { +void InstructionEncoding::parseFixedLenOperands(const CodeGenTarget &Target, + const BitsInit &Bits) { // Search for tied operands, so that we can correctly instantiate // operands that are not explicitly represented in the encoding. std::map TiedNames; @@ -340,7 +349,7 @@ void InstructionEncoding::parseFixedLenOperands(const BitsInit &Bits) { for (const CGIOperandList::OperandInfo &Op : Inst->Operands) { // Lookup the decoder method and construct a new OperandInfo to hold our // result. - OperandInfo OpInfo = getOpInfo(Op.Rec); + OperandInfo OpInfo = getOpInfo(Target, Op.Rec); // If we have named sub-operands... if (Op.MIOperandInfo && !Op.SubOpNames[0].empty()) { @@ -359,7 +368,7 @@ void InstructionEncoding::parseFixedLenOperands(const BitsInit &Bits) { for (auto [SubOpName, SubOp] : zip_equal(Op.SubOpNames, Op.MIOperandInfo->getArgs())) { const Record *SubOpRec = cast(SubOp)->getDef(); - OperandInfo SubOpInfo = getOpInfo(SubOpRec); + OperandInfo SubOpInfo = getOpInfo(Target, SubOpRec); addOneOperandFields(EncodingDef, Bits, TiedNames, SubOpRec, SubOpName, SubOpInfo); Operands.push_back(std::move(SubOpInfo)); @@ -387,7 +396,8 @@ void InstructionEncoding::parseFixedLenOperands(const BitsInit &Bits) { } } -InstructionEncoding::InstructionEncoding(const Record *EncodingDef, +InstructionEncoding::InstructionEncoding(const CodeGenTarget &Target, + const Record *EncodingDef, const CodeGenInstruction *Inst) : EncodingDef(EncodingDef), Inst(Inst) { const Record *InstDef = Inst->TheDef; @@ -408,13 +418,13 @@ InstructionEncoding::InstructionEncoding(const Record *EncodingDef, parseVarLenEncoding(VLI); // If the encoding has a custom decoder, don't bother parsing the operands. if (DecoderMethod.empty()) - parseVarLenOperands(VLI); + parseVarLenOperands(Target, VLI); } else { const auto *BI = cast(InstField->getValue()); parseFixedLenEncoding(*BI); // If the encoding has a custom decoder, don't bother parsing the operands. if (DecoderMethod.empty()) - parseFixedLenOperands(*BI); + parseFixedLenOperands(Target, *BI); } if (DecoderMethod.empty()) { diff --git a/llvm/utils/TableGen/Common/InstructionEncoding.h b/llvm/utils/TableGen/Common/InstructionEncoding.h index 40c89dd4c6f2d..ec416f5b34d2b 100644 --- a/llvm/utils/TableGen/Common/InstructionEncoding.h +++ b/llvm/utils/TableGen/Common/InstructionEncoding.h @@ -21,6 +21,7 @@ namespace llvm { class BitsInit; class CodeGenInstruction; +class CodeGenTarget; class Record; class RecordVal; class VarLenInst; @@ -91,7 +92,7 @@ class InstructionEncoding { SmallVector Operands; public: - InstructionEncoding(const Record *EncodingDef, + InstructionEncoding(const CodeGenTarget &Target, const Record *EncodingDef, const CodeGenInstruction *Inst); /// Returns the Record this encoding originates from. @@ -137,12 +138,18 @@ class InstructionEncoding { /// Returns information about the operands' contribution to this encoding. ArrayRef getOperands() const { return Operands; } + static std::pair + findOperandDecoderMethod(const CodeGenTarget &Target, const Record *Record); + + static OperandInfo getOpInfo(const CodeGenTarget &Target, + const Record *TypeRecord); + private: void parseVarLenEncoding(const VarLenInst &VLI); void parseFixedLenEncoding(const BitsInit &RecordInstBits); - void parseVarLenOperands(const VarLenInst &VLI); - void parseFixedLenOperands(const BitsInit &Bits); + void parseVarLenOperands(const CodeGenTarget &Target, const VarLenInst &VLI); + void parseFixedLenOperands(const CodeGenTarget &Target, const BitsInit &Bits); }; } // namespace llvm diff --git a/llvm/utils/TableGen/DAGISelMatcherGen.cpp b/llvm/utils/TableGen/DAGISelMatcherGen.cpp index 227311b0a3bc8..d84bfa8d0c92e 100644 --- a/llvm/utils/TableGen/DAGISelMatcherGen.cpp +++ b/llvm/utils/TableGen/DAGISelMatcherGen.cpp @@ -238,7 +238,7 @@ void MatcherGen::EmitLeafMatchCode(const TreePatternNode &N) { } if ( // Handle register references. Nothing to do here, they always match. - LeafRec->isSubClassOf("RegisterClass") || + LeafRec->isSubClassOf("RegisterClassLike") || LeafRec->isSubClassOf("RegisterOperand") || LeafRec->isSubClassOf("PointerLikeRegClass") || LeafRec->isSubClassOf("SubRegIndex") || diff --git a/llvm/utils/TableGen/DecoderEmitter.cpp b/llvm/utils/TableGen/DecoderEmitter.cpp index 083d78c4986f0..5c8b5fd2096c7 100644 --- a/llvm/utils/TableGen/DecoderEmitter.cpp +++ b/llvm/utils/TableGen/DecoderEmitter.cpp @@ -13,6 +13,7 @@ #include "Common/CodeGenHwModes.h" #include "Common/CodeGenInstruction.h" +#include "Common/CodeGenRegisters.h" #include "Common/CodeGenTarget.h" #include "Common/InfoByHwMode.h" #include "Common/InstructionEncoding.h" @@ -276,6 +277,8 @@ class DecoderEmitter { ArrayRef InstrLen) const; void emitPredicateFunction(formatted_raw_ostream &OS, const PredicateSet &Predicates) const; + + void emitRegClassByHwModeDecoders(formatted_raw_ostream &OS) const; void emitDecoderFunction(formatted_raw_ostream &OS, const DecoderSet &Decoders, unsigned BucketBitWidth) const; @@ -842,9 +845,66 @@ void DecoderEmitter::emitPredicateFunction( OS << "}\n\n"; } +/// Emit a default implementation of a decoder for all RegClassByHwModes which +/// do not have an explicit DecoderMethodSet, which dispatches over the decoder +/// methods for the member classes. +void DecoderEmitter::emitRegClassByHwModeDecoders( + formatted_raw_ostream &OS) const { + const CodeGenHwModes &CGH = Target.getHwModes(); + if (CGH.getNumModeIds() == 1) + return; + + ArrayRef RegClassByHwMode = Target.getAllRegClassByHwMode(); + if (RegClassByHwMode.empty()) + return; + + const CodeGenRegBank &RegBank = Target.getRegBank(); + + for (const Record *ClassByHwMode : RegClassByHwMode) { + // Ignore cases that had an explicit DecoderMethod set. + if (!InstructionEncoding::findOperandDecoderMethod(Target, ClassByHwMode) + .second) + continue; + + const HwModeSelect &ModeSelect = CGH.getHwModeSelect(ClassByHwMode); + + // Mips has a system where this is only used by compound operands with + // custom decoders, and we don't try to detect if this decoder is really + // needed. + OS << "[[maybe_unused]]\n"; + + OS << "static DecodeStatus Decode" << ClassByHwMode->getName() + << "RegClassByHwMode"; + OS << R"((MCInst &Inst, unsigned Imm, uint64_t Addr, const MCDisassembler *Decoder) { + switch (Decoder->getSubtargetInfo().getHwMode(MCSubtargetInfo::HwMode_RegClass)) { +)"; + for (const HwModeSelect::PairType &P : ModeSelect.Items) { + const CodeGenRegisterClass *RegClass = RegBank.getRegClass(P.second); + + OS << indent(2) << "case " << P.first << ": // " + << CGH.getModeName(P.first, /*IncludeDefault=*/true) << '\n' + << indent(4) << "return " + << InstructionEncoding::findOperandDecoderMethod(Target, + RegClass->getDef()) + .first + << "(Inst, Imm, Addr, Decoder);\n"; + } + OS << indent(2) << R"(default: + llvm_unreachable("no decoder for hwmode"); + } +} + +)"; + } + + OS << '\n'; +} + void DecoderEmitter::emitDecoderFunction(formatted_raw_ostream &OS, const DecoderSet &Decoders, unsigned BucketBitWidth) const { + emitRegClassByHwModeDecoders(OS); + // The decoder function is just a big switch statement or a table of function // pointers based on the input decoder index. @@ -1800,7 +1860,7 @@ void DecoderEmitter::parseInstructionEncodings() { continue; } unsigned EncodingID = Encodings.size(); - Encodings.emplace_back(EncodingDef, Inst); + Encodings.emplace_back(Target, EncodingDef, Inst); EncodingIDsByHwMode[HwModeID].push_back(EncodingID); } continue; // Ignore encoding specified by Instruction itself. @@ -1812,7 +1872,7 @@ void DecoderEmitter::parseInstructionEncodings() { } unsigned EncodingID = Encodings.size(); - Encodings.emplace_back(InstDef, Inst); + Encodings.emplace_back(Target, InstDef, Inst); // This instruction is encoded the same on all HwModes. // According to user needs, add it to all, some, or only the default HwMode. @@ -1835,7 +1895,8 @@ void DecoderEmitter::parseInstructionEncodings() { continue; } unsigned EncodingID = Encodings.size(); - Encodings.emplace_back(EncodingDef, &Target.getInstruction(InstDef)); + Encodings.emplace_back(Target, EncodingDef, + &Target.getInstruction(InstDef)); EncodingIDsByHwMode[DefaultMode].push_back(EncodingID); } diff --git a/llvm/utils/TableGen/GlobalISelEmitter.cpp b/llvm/utils/TableGen/GlobalISelEmitter.cpp index 7ae6107b98554..359383f79b9bb 100644 --- a/llvm/utils/TableGen/GlobalISelEmitter.cpp +++ b/llvm/utils/TableGen/GlobalISelEmitter.cpp @@ -267,13 +267,28 @@ static Error isTrivialOperatorNode(const TreePatternNode &N) { return failedImport(Explanation); } -static const Record *getInitValueAsRegClass(const Init *V) { +static const Record *getInitValueAsRegClass(const CodeGenTarget &Target, + const Init *V) { if (const DefInit *VDefInit = dyn_cast(V)) { - if (VDefInit->getDef()->isSubClassOf("RegisterOperand")) - return VDefInit->getDef()->getValueAsDef("RegClass"); - if (VDefInit->getDef()->isSubClassOf("RegisterClass")) - return VDefInit->getDef(); + const Record *RegClass = VDefInit->getDef(); + if (RegClass->isSubClassOf("RegisterOperand")) + RegClass = RegClass->getValueAsDef("RegClass"); + + if (RegClass->isSubClassOf("RegisterClass")) + return RegClass; + + // FIXME: We should figure out the hwmode and dispatch. But this interface + // is broken, we should be returning a register class. The expected uses + // will use the same RegBanks in all modes. + if (RegClass->isSubClassOf("RegClassByHwMode")) { + const HwModeSelect &ModeSelect = + Target.getHwModes().getHwModeSelect(RegClass); + if (ModeSelect.Items.empty()) + return nullptr; + return ModeSelect.Items.front().second; + } } + return nullptr; } @@ -475,6 +490,9 @@ class GlobalISelEmitter final : public GlobalISelMatchTableExecutorEmitter { const CodeGenRegisterClass * inferRegClassFromPattern(const TreePatternNode &N) const; + const CodeGenRegisterClass * + inferRegClassFromRegisterClassLike(const Record *RecClassLike) const; + const CodeGenRegisterClass * inferRegClassFromInstructionPattern(const TreePatternNode &N, unsigned ResIdx) const; @@ -1141,9 +1159,10 @@ Error GlobalISelEmitter::importChildMatcher( // Check for register classes. if (ChildRec->isSubClassOf("RegisterClass") || - ChildRec->isSubClassOf("RegisterOperand")) { - OM.addPredicate( - Target.getRegisterClass(getInitValueAsRegClass(ChildDefInit))); + ChildRec->isSubClassOf("RegisterOperand") || + ChildRec->isSubClassOf("RegClassByHwMode")) { + OM.addPredicate(Target.getRegisterClass( + getInitValueAsRegClass(Target, ChildDefInit))); return Error::success(); } @@ -1285,7 +1304,7 @@ Error GlobalISelEmitter::importNamedNodeRenderer( // TODO: All special cases are handled above. Remove this check and add // CopyRenderer unconditionally. - if (R->isSubClassOf("RegisterClass") || + if (R->isSubClassOf("RegisterClassLike") || R->isSubClassOf("RegisterOperand") || R->isSubClassOf("ValueType")) { MIBuilder.addRenderer(NodeName); return Error::success(); @@ -1640,7 +1659,8 @@ Expected GlobalISelEmitter::importExplicitUseRenderers( } // If this is a source operand, this is just a subregister copy. - const Record *RCDef = getInitValueAsRegClass(ValChild.getLeafValue()); + const Record *RCDef = + getInitValueAsRegClass(Target, ValChild.getLeafValue()); if (!RCDef) return failedImport("EXTRACT_SUBREG child #0 could not " "be coerced to a register class"); @@ -1672,7 +1692,7 @@ Expected GlobalISelEmitter::importExplicitUseRenderers( return failedImport("REG_SEQUENCE child #0 is not a leaf"); const Record *RCDef = - getInitValueAsRegClass(Dst.getChild(0).getLeafValue()); + getInitValueAsRegClass(Target, Dst.getChild(0).getLeafValue()); if (!RCDef) return failedImport("REG_SEQUENCE child #0 could not " "be coerced to a register class"); @@ -1791,7 +1811,7 @@ Error GlobalISelEmitter::constrainOperands(action_iterator InsertPt, // COPY_TO_REGCLASS does not provide operand constraints itself but the // result is constrained to the class given by the second child. const Record *DstIOpRec = - getInitValueAsRegClass(Dst.getChild(1).getLeafValue()); + getInitValueAsRegClass(Target, Dst.getChild(1).getLeafValue()); if (DstIOpRec == nullptr) return failedImport("COPY_TO_REGCLASS operand #1 isn't a register class"); @@ -1897,7 +1917,7 @@ Error GlobalISelEmitter::constrainOperands(action_iterator InsertPt, const CodeGenRegisterClass * GlobalISelEmitter::getRegClassFromLeaf(const TreePatternNode &Leaf) const { assert(Leaf.isLeaf() && "Expected leaf?"); - const Record *RCRec = getInitValueAsRegClass(Leaf.getLeafValue()); + const Record *RCRec = getInitValueAsRegClass(Target, Leaf.getLeafValue()); if (!RCRec) return nullptr; return CGRegs.getRegClass(RCRec); @@ -1926,6 +1946,26 @@ GlobalISelEmitter::inferRegClassFromPattern(const TreePatternNode &N) const { return inferRegClassFromInstructionPattern(N, /*ResIdx=*/0); } +const CodeGenRegisterClass * +GlobalISelEmitter::inferRegClassFromRegisterClassLike( + const Record *RegClassDef) const { + if (RegClassDef->isSubClassOf("RegClassByHwMode")) { + // TODO: We only are trying to match the regbank, which we assume is the + // same across modes, but we are just picking one class and assuming they + // all have the same bank. + // + // We should verify there is a common regbank among the possible classes, + // and return that instead of a concrete class. + const HwModeSelect &ModeSelect = + Target.getHwModes().getHwModeSelect(RegClassDef); + if (ModeSelect.Items.empty()) + return nullptr; + return Target.getRegBank().getRegClass(ModeSelect.Items.front().second); + } + + return &Target.getRegisterClass(RegClassDef); +} + const CodeGenRegisterClass * GlobalISelEmitter::inferRegClassFromInstructionPattern(const TreePatternNode &N, unsigned ResIdx) const { @@ -1997,8 +2037,14 @@ GlobalISelEmitter::inferRegClassFromInstructionPattern(const TreePatternNode &N, // from. const auto &DstIOperand = Inst.Operands[ResIdx]; const Record *DstIOpRec = DstIOperand.Rec; - if (DstIOpRec->isSubClassOf("RegisterOperand")) - return &Target.getRegisterClass(DstIOpRec->getValueAsDef("RegClass")); + + if (DstIOpRec->isSubClassOf("RegisterOperand")) { + const Record *RegClassDef = DstIOpRec->getValueAsDef("RegClass"); + return inferRegClassFromRegisterClassLike(RegClassDef); + } + + if (DstIOpRec->isSubClassOf("RegClassByHwMode")) + return inferRegClassFromRegisterClassLike(DstIOpRec); if (DstIOpRec->isSubClassOf("RegisterClass")) return &Target.getRegisterClass(DstIOpRec); @@ -2111,7 +2157,8 @@ Expected GlobalISelEmitter::runOnPattern(const PatternToMatch &P) { InstructionMatcher &InsnMatcher = InsnMatcherOrError.get(); if (Dst.isLeaf()) { - if (const Record *RCDef = getInitValueAsRegClass(Dst.getLeafValue())) { + if (const Record *RCDef = + getInitValueAsRegClass(Target, Dst.getLeafValue())) { const CodeGenRegisterClass &RC = Target.getRegisterClass(RCDef); // We need to replace the def and all its uses with the specified diff --git a/llvm/utils/TableGen/InstrInfoEmitter.cpp b/llvm/utils/TableGen/InstrInfoEmitter.cpp index 0174475e70602..9ed81c6f6c9e6 100644 --- a/llvm/utils/TableGen/InstrInfoEmitter.cpp +++ b/llvm/utils/TableGen/InstrInfoEmitter.cpp @@ -14,6 +14,7 @@ #include "Basic/SequenceToOffsetTable.h" #include "Common/CodeGenDAGPatterns.h" #include "Common/CodeGenInstruction.h" +#include "Common/CodeGenRegisters.h" #include "Common/CodeGenSchedule.h" #include "Common/CodeGenTarget.h" #include "Common/PredicateExpander.h" @@ -144,7 +145,11 @@ InstrInfoEmitter::GetOperandInfo(const CodeGenInstruction &Inst) { if (OpR->isSubClassOf("RegisterOperand")) OpR = OpR->getValueAsDef("RegClass"); - if (OpR->isSubClassOf("RegisterClass")) + + if (OpR->isSubClassOf("RegClassByHwMode")) { + Res += OpR->getName(); + Res += ", "; + } else if (OpR->isSubClassOf("RegisterClass")) Res += getQualifiedName(OpR) + "RegClassID, "; else if (OpR->isSubClassOf("PointerLikeRegClass")) Res += utostr(OpR->getValueAsInt("RegClassKind")) + ", "; @@ -155,9 +160,12 @@ InstrInfoEmitter::GetOperandInfo(const CodeGenInstruction &Inst) { // Fill in applicable flags. Res += "0"; - // Ptr value whose register class is resolved via callback. - if (OpR->isSubClassOf("PointerLikeRegClass")) + if (OpR->isSubClassOf("RegClassByHwMode")) { + Res += "|(1<isSubClassOf("PointerLikeRegClass")) { + // Ptr value whose register class is resolved via callback. Res += "|(1<getName() << ",\n"; + OS << "};\n"; + OS << "}\n"; + OS << "namespace llvm {\n\n"; OS << "struct " << TargetName << "InstrTable {\n"; @@ -986,6 +1002,16 @@ void InstrInfoEmitter::run(raw_ostream &OS) { InstrNames.layout(); InstrNames.emitStringLiteralDef(OS, Twine("extern const char ") + TargetName + "InstrNameData[]"); + const CodeGenRegBank &RegBank = Target.getRegBank(); + const CodeGenHwModes &CGH = Target.getHwModes(); + unsigned NumModes = CGH.getNumModeIds(); + ArrayRef RegClassByHwMode = Target.getAllRegClassByHwMode(); + unsigned NumClassesByHwMode = RegClassByHwMode.size(); + + if (NumClassesByHwMode != 0) { + OS << "extern const int16_t " << TargetName << "RegClassByHwModeTables[" + << NumModes << "][" << NumClassesByHwMode << "];\n"; + } OS << "extern const unsigned " << TargetName << "InstrNameIndices[] = {"; Num = 0; @@ -1044,6 +1070,40 @@ void InstrInfoEmitter::run(raw_ostream &OS) { // MCInstrInfo initialization routine. Timer.startTimer("Emit initialization routine"); + + if (NumClassesByHwMode != 0) { + OS << "const int16_t " << TargetName << "RegClassByHwModeTables[" + << NumModes << "][" << NumClassesByHwMode << "] = {\n"; + + for (unsigned M = 0; M < NumModes; ++M) { + OS << " { // " << CGH.getModeName(M, /*IncludeDefault=*/true) << '\n'; + for (unsigned I = 0; I != NumClassesByHwMode; ++I) { + const Record *Class = RegClassByHwMode[I]; + const HwModeSelect &ModeSelect = CGH.getHwModeSelect(Class); + + bool Seen = false; + for (const HwModeSelect::PairType &P : ModeSelect.Items) { + if (P.first == M) { + const CodeGenRegisterClass *RegClass = + RegBank.getRegClass(P.second); + OS << indent(4) << RegClass->getQualifiedIdName() << ",\n"; + Seen = true; + break; + } + } + + // If a RegClassByHwMode doesn't have an entry corresponding to a mode, + // pad with default register class. + if (!Seen) + OS << indent(4) << "-1, // Missing mode entry\n"; + } + + OS << " },\n"; + } + + OS << "};\n\n"; + } + OS << "static inline void Init" << TargetName << "MCInstrInfo(MCInstrInfo *II) {\n"; OS << " II->InitMCInstrInfo(" << TargetName << "Descs.Insts, " << TargetName @@ -1056,7 +1116,15 @@ void InstrInfoEmitter::run(raw_ostream &OS) { OS << TargetName << "InstrComplexDeprecationInfos, "; else OS << "nullptr, "; - OS << NumberedInstructions.size() << ");\n}\n\n"; + OS << NumberedInstructions.size() << ", "; + + if (NumClassesByHwMode != 0) { + OS << '&' << TargetName << "RegClassByHwModeTables[0][0], " + << NumClassesByHwMode; + } else + OS << "nullptr, 0"; + + OS << ");\n}\n\n"; OS << "} // end namespace llvm\n"; @@ -1098,6 +1166,12 @@ void InstrInfoEmitter::run(raw_ostream &OS) { << "Descs;\n"; OS << "extern const unsigned " << TargetName << "InstrNameIndices[];\n"; OS << "extern const char " << TargetName << "InstrNameData[];\n"; + + if (NumClassesByHwMode != 0) { + OS << "extern const int16_t " << TargetName << "RegClassByHwModeTables[" + << NumModes << "][" << NumClassesByHwMode << "];\n"; + } + if (HasDeprecationFeatures) OS << "extern const uint8_t " << TargetName << "InstrDeprecationFeatures[];\n"; @@ -1108,7 +1182,13 @@ void InstrInfoEmitter::run(raw_ostream &OS) { << "(const TargetSubtargetInfo &STI, unsigned CFSetupOpcode, unsigned " "CFDestroyOpcode, unsigned CatchRetOpcode, unsigned ReturnOpcode)\n" << " : TargetInstrInfo(CFSetupOpcode, CFDestroyOpcode, CatchRetOpcode, " - "ReturnOpcode) {\n" + "ReturnOpcode"; + if (NumClassesByHwMode != 0) + OS << ", " << TargetName + << "RegClassByHwModeTables[STI.getHwMode(MCSubtargetInfo::HwMode_" + "RegClass)]"; + + OS << ") {\n" << " InitMCInstrInfo(" << TargetName << "Descs.Insts, " << TargetName << "InstrNameIndices, " << TargetName << "InstrNameData, "; if (HasDeprecationFeatures) @@ -1119,8 +1199,16 @@ void InstrInfoEmitter::run(raw_ostream &OS) { OS << TargetName << "InstrComplexDeprecationInfos, "; else OS << "nullptr, "; - OS << NumberedInstructions.size() << ");\n}\n"; - OS << "} // end namespace llvm\n"; + OS << NumberedInstructions.size(); + + if (NumClassesByHwMode != 0) { + OS << ", &" << TargetName << "RegClassByHwModeTables[0][0], " + << NumClassesByHwMode; + } + + OS << ");\n" + "}\n" + "} // end namespace llvm\n"; OS << "#endif // GET_INSTRINFO_CTOR_DTOR\n\n"; diff --git a/llvm/utils/TableGen/SubtargetEmitter.cpp b/llvm/utils/TableGen/SubtargetEmitter.cpp index e218927621dd3..b5ffbedc41b24 100644 --- a/llvm/utils/TableGen/SubtargetEmitter.cpp +++ b/llvm/utils/TableGen/SubtargetEmitter.cpp @@ -1792,7 +1792,8 @@ void SubtargetEmitter::emitHwModeCheck(const std::string &ClassName, if (P.second->isSubClassOf("ValueType")) { ValueTypeModes |= (1 << (P.first - 1)); } else if (P.second->isSubClassOf("RegInfo") || - P.second->isSubClassOf("SubRegRange")) { + P.second->isSubClassOf("SubRegRange") || + P.second->isSubClassOf("RegisterClassLike")) { RegInfoModes |= (1 << (P.first - 1)); } else if (P.second->isSubClassOf("InstructionEncoding")) { EncodingInfoModes |= (1 << (P.first - 1)); @@ -1849,6 +1850,7 @@ void SubtargetEmitter::emitHwModeCheck(const std::string &ClassName, OS << " case HwMode_Default:\n return llvm::countr_zero(Modes) + 1;\n"; HandlePerMode("ValueType", ValueTypeModes); HandlePerMode("RegInfo", RegInfoModes); + HandlePerMode("RegClass", RegInfoModes); HandlePerMode("EncodingInfo", EncodingInfoModes); OS << " }\n"; OS << " llvm_unreachable(\"unexpected HwModeType\");\n" From b4275a6fa9aeddc4c7d0453eae080d433afa4125 Mon Sep 17 00:00:00 2001 From: Matt Arsenault Date: Mon, 15 Sep 2025 11:57:24 +0900 Subject: [PATCH 02/28] Review comments --- llvm/include/llvm/CodeGen/TargetInstrInfo.h | 8 ++++---- llvm/include/llvm/MC/MCInstrDesc.h | 5 ++--- llvm/include/llvm/MC/MCInstrInfo.h | 2 +- llvm/include/llvm/Target/Target.td | 8 ++++---- llvm/utils/TableGen/AsmMatcherEmitter.cpp | 16 ++++------------ 5 files changed, 15 insertions(+), 24 deletions(-) diff --git a/llvm/include/llvm/CodeGen/TargetInstrInfo.h b/llvm/include/llvm/CodeGen/TargetInstrInfo.h index 0212c8bde7d55..e8ffbe31118ee 100644 --- a/llvm/include/llvm/CodeGen/TargetInstrInfo.h +++ b/llvm/include/llvm/CodeGen/TargetInstrInfo.h @@ -113,9 +113,9 @@ struct ExtAddrMode { /// class LLVM_ABI TargetInstrInfo : public MCInstrInfo { protected: - /// Subtarget specific sub-array of MCInstrInfo's RegClassByHwModeTables. - /// This should be indexed by MCOperandInfo's RegClass field for - /// LookupRegClassByHwMode operands. + /// Subtarget specific sub-array of MCInstrInfo's RegClassByHwModeTables + /// (i.e. the table for the active HwMode). This should be indexed by + /// MCOperandInfo's RegClass field for LookupRegClassByHwMode operands. const int16_t *const RegClassByHwMode; public: @@ -141,7 +141,7 @@ class LLVM_ABI TargetInstrInfo : public MCInstrInfo { Opc <= TargetOpcode::GENERIC_ATOMICRMW_OP_END; } - /// Return the subtarget appropripate RegClassID for \p OpInfo + /// \returns the subtarget appropriate RegClassID for \p OpInfo /// /// Note this shadows a version of getOpRegClassID in MCInstrInfo which takes /// an additional argument for the subtarget's HwMode, since TargetInstrInfo diff --git a/llvm/include/llvm/MC/MCInstrDesc.h b/llvm/include/llvm/MC/MCInstrDesc.h index 292c40a8cb128..0a4bd17e20738 100644 --- a/llvm/include/llvm/MC/MCInstrDesc.h +++ b/llvm/include/llvm/MC/MCInstrDesc.h @@ -91,9 +91,8 @@ class MCOperandInfo { /// index into a table in TargetInstrInfo or MCInstrInfo which contains the /// real register class ID. /// - /// If isLookupPtrRegClass is set, then this is / an index that is passed to - /// TargetRegisterInfo::getPointerRegClass(x) to / get a dynamic register - /// class. + /// If isLookupPtrRegClass is set, then this is an index that is passed to + /// TargetRegisterInfo::getPointerRegClass(x) to get a dynamic register class. int16_t RegClass; /// These are flags from the MCOI::OperandFlags enum. diff --git a/llvm/include/llvm/MC/MCInstrInfo.h b/llvm/include/llvm/MC/MCInstrInfo.h index aaad450ef99c3..0ceb2d1717510 100644 --- a/llvm/include/llvm/MC/MCInstrInfo.h +++ b/llvm/include/llvm/MC/MCInstrInfo.h @@ -44,7 +44,7 @@ class MCInstrInfo { unsigned NumOpcodes; // Number of entries in the desc array protected: - // Pointer to 2d array [NumHwModess][NumRegClassByHwModes] + // Pointer to 2d array [NumHwModes][NumRegClassByHwModes] const int16_t *RegClassByHwModeTables; int16_t NumRegClassByHwModes; diff --git a/llvm/include/llvm/Target/Target.td b/llvm/include/llvm/Target/Target.td index af4f70f51e0ee..82c44d4817322 100644 --- a/llvm/include/llvm/Target/Target.td +++ b/llvm/include/llvm/Target/Target.td @@ -271,7 +271,7 @@ class RegisterClassLike : DAGOperand; // class RegisterClass regTypes, int alignment, dag regList, RegAltNameIndex idx = NoRegAltName> - : DAGOperand, RegisterClassLike { + : RegisterClassLike { string Namespace = namespace; // The register size/alignment information, parameterized by a HW mode. @@ -923,7 +923,7 @@ def decoder; /// type that it doesn't know, and resolves the actual regclass to use by using /// the TargetRegisterInfo::getPointerRegClass() hook at codegen time. /// -/// This is deprecated in favor of RegClassByHwMode +/// This is deprecated in favor of RegClassByHwMode. class PointerLikeRegClass { int RegClassKind = Kind; } @@ -936,8 +936,8 @@ class PointerLikeRegClass { /// define operands which swap the register class with the pointer /// type. class RegClassByHwMode Modes, - list RegClasses> : - HwModeSelect, RegisterClassLike { + list RegClasses> + : HwModeSelect, RegisterClassLike { list Objects = RegClasses; } diff --git a/llvm/utils/TableGen/AsmMatcherEmitter.cpp b/llvm/utils/TableGen/AsmMatcherEmitter.cpp index ef41d93a09bc8..db3154b70c1f3 100644 --- a/llvm/utils/TableGen/AsmMatcherEmitter.cpp +++ b/llvm/utils/TableGen/AsmMatcherEmitter.cpp @@ -167,8 +167,7 @@ struct ClassInfo { RegisterClass0, /// The (first) register class by hwmode, subsequent register classes by - /// hwmode are - /// RegisterClassByHwMode0+1, and so on. + /// hwmode are RegisterClassByHwMode0+1, and so on. RegisterClassByHwMode0 = 1 << 12, /// The (first) user defined class, subsequent user defined classes are @@ -178,7 +177,7 @@ struct ClassInfo { /// Kind - The class kind, which is either a predefined kind, or (UserClass0 + /// N) for the Nth user defined class. - unsigned Kind; + unsigned Kind = 0; /// SuperClasses - The super classes of this class. Note that for simplicities /// sake user operands only record their immediate super class, while register @@ -220,7 +219,7 @@ struct ClassInfo { std::string DiagnosticString; /// Is this operand optional and not always required. - bool IsOptional; + bool IsOptional = false; /// DefaultMethod - The name of the method that returns the default operand /// for optional operand @@ -1394,15 +1393,8 @@ void AsmMatcherInfo::buildRegisterClasses( CI->ClassName = "RegByHwMode_" + ClassByHwMode->getName().str(); CI->Name = "MCK_" + CI->ClassName; CI->ValueName = ClassByHwMode->getName(); - CI->PredicateMethod = ""; // unused CI->RenderMethod = "addRegOperands"; - // CI->Registers = RS; - // FIXME: diagnostic type. - CI->DiagnosticType = ""; - CI->IsOptional = false; - CI->DefaultMethod = ""; // unused - // RegisterSetClasses.try_emplace(RS, CI); - + // FIXME: Set diagnostic type. ++RegClassByHwModeIndex; assert(CI->isRegisterClassByHwMode()); From 77f9e0ad996dd746779e5411bad30f73c46d9143 Mon Sep 17 00:00:00 2001 From: Matt Arsenault Date: Mon, 15 Sep 2025 12:03:42 +0900 Subject: [PATCH 03/28] Move getInitValueAsRegClass into CodeGenTarget --- llvm/utils/TableGen/Common/CodeGenTarget.cpp | 23 ++++++++++++ llvm/utils/TableGen/Common/CodeGenTarget.h | 2 + llvm/utils/TableGen/GlobalISelEmitter.cpp | 39 ++++---------------- 3 files changed, 32 insertions(+), 32 deletions(-) diff --git a/llvm/utils/TableGen/Common/CodeGenTarget.cpp b/llvm/utils/TableGen/Common/CodeGenTarget.cpp index 8982927eeefcf..a1bf683dbcd34 100644 --- a/llvm/utils/TableGen/Common/CodeGenTarget.cpp +++ b/llvm/utils/TableGen/Common/CodeGenTarget.cpp @@ -197,6 +197,29 @@ void CodeGenTarget::ReadLegalValueTypes() const { LegalValueTypes.erase(llvm::unique(LegalValueTypes), LegalValueTypes.end()); } +const Record *CodeGenTarget::getInitValueAsRegClass(const Init *V) const { + if (const DefInit *VDefInit = dyn_cast(V)) { + const Record *RegClass = VDefInit->getDef(); + if (RegClass->isSubClassOf("RegisterOperand")) + RegClass = RegClass->getValueAsDef("RegClass"); + + if (RegClass->isSubClassOf("RegisterClass")) + return RegClass; + + // FIXME: We should figure out the hwmode and dispatch. But this interface + // is broken, we should be returning a register class. The expected uses + // will use the same RegBanks in all modes. + if (RegClass->isSubClassOf("RegClassByHwMode")) { + const HwModeSelect &ModeSelect = getHwModes().getHwModeSelect(RegClass); + if (ModeSelect.Items.empty()) + return nullptr; + return ModeSelect.Items.front().second; + } + } + + return nullptr; +} + CodeGenSchedModels &CodeGenTarget::getSchedModels() const { if (!SchedModels) SchedModels = std::make_unique(Records, *this); diff --git a/llvm/utils/TableGen/Common/CodeGenTarget.h b/llvm/utils/TableGen/Common/CodeGenTarget.h index 59a04e182c0cc..88dfef0df3e02 100644 --- a/llvm/utils/TableGen/Common/CodeGenTarget.h +++ b/llvm/utils/TableGen/Common/CodeGenTarget.h @@ -152,6 +152,8 @@ class CodeGenTarget { return LegalValueTypes; } + const Record *getInitValueAsRegClass(const Init *V) const; + CodeGenSchedModels &getSchedModels() const; const CodeGenHwModes &getHwModes() const { return CGH; } diff --git a/llvm/utils/TableGen/GlobalISelEmitter.cpp b/llvm/utils/TableGen/GlobalISelEmitter.cpp index 359383f79b9bb..23775a80c6144 100644 --- a/llvm/utils/TableGen/GlobalISelEmitter.cpp +++ b/llvm/utils/TableGen/GlobalISelEmitter.cpp @@ -267,31 +267,6 @@ static Error isTrivialOperatorNode(const TreePatternNode &N) { return failedImport(Explanation); } -static const Record *getInitValueAsRegClass(const CodeGenTarget &Target, - const Init *V) { - if (const DefInit *VDefInit = dyn_cast(V)) { - const Record *RegClass = VDefInit->getDef(); - if (RegClass->isSubClassOf("RegisterOperand")) - RegClass = RegClass->getValueAsDef("RegClass"); - - if (RegClass->isSubClassOf("RegisterClass")) - return RegClass; - - // FIXME: We should figure out the hwmode and dispatch. But this interface - // is broken, we should be returning a register class. The expected uses - // will use the same RegBanks in all modes. - if (RegClass->isSubClassOf("RegClassByHwMode")) { - const HwModeSelect &ModeSelect = - Target.getHwModes().getHwModeSelect(RegClass); - if (ModeSelect.Items.empty()) - return nullptr; - return ModeSelect.Items.front().second; - } - } - - return nullptr; -} - static std::string getScopedName(unsigned Scope, const std::string &Name) { return ("pred:" + Twine(Scope) + ":" + Name).str(); } @@ -1161,8 +1136,8 @@ Error GlobalISelEmitter::importChildMatcher( if (ChildRec->isSubClassOf("RegisterClass") || ChildRec->isSubClassOf("RegisterOperand") || ChildRec->isSubClassOf("RegClassByHwMode")) { - OM.addPredicate(Target.getRegisterClass( - getInitValueAsRegClass(Target, ChildDefInit))); + OM.addPredicate( + Target.getRegisterClass(Target.getInitValueAsRegClass(ChildDefInit))); return Error::success(); } @@ -1660,7 +1635,7 @@ Expected GlobalISelEmitter::importExplicitUseRenderers( // If this is a source operand, this is just a subregister copy. const Record *RCDef = - getInitValueAsRegClass(Target, ValChild.getLeafValue()); + Target.getInitValueAsRegClass(ValChild.getLeafValue()); if (!RCDef) return failedImport("EXTRACT_SUBREG child #0 could not " "be coerced to a register class"); @@ -1692,7 +1667,7 @@ Expected GlobalISelEmitter::importExplicitUseRenderers( return failedImport("REG_SEQUENCE child #0 is not a leaf"); const Record *RCDef = - getInitValueAsRegClass(Target, Dst.getChild(0).getLeafValue()); + Target.getInitValueAsRegClass(Dst.getChild(0).getLeafValue()); if (!RCDef) return failedImport("REG_SEQUENCE child #0 could not " "be coerced to a register class"); @@ -1811,7 +1786,7 @@ Error GlobalISelEmitter::constrainOperands(action_iterator InsertPt, // COPY_TO_REGCLASS does not provide operand constraints itself but the // result is constrained to the class given by the second child. const Record *DstIOpRec = - getInitValueAsRegClass(Target, Dst.getChild(1).getLeafValue()); + Target.getInitValueAsRegClass(Dst.getChild(1).getLeafValue()); if (DstIOpRec == nullptr) return failedImport("COPY_TO_REGCLASS operand #1 isn't a register class"); @@ -1917,7 +1892,7 @@ Error GlobalISelEmitter::constrainOperands(action_iterator InsertPt, const CodeGenRegisterClass * GlobalISelEmitter::getRegClassFromLeaf(const TreePatternNode &Leaf) const { assert(Leaf.isLeaf() && "Expected leaf?"); - const Record *RCRec = getInitValueAsRegClass(Target, Leaf.getLeafValue()); + const Record *RCRec = Target.getInitValueAsRegClass(Leaf.getLeafValue()); if (!RCRec) return nullptr; return CGRegs.getRegClass(RCRec); @@ -2158,7 +2133,7 @@ Expected GlobalISelEmitter::runOnPattern(const PatternToMatch &P) { if (Dst.isLeaf()) { if (const Record *RCDef = - getInitValueAsRegClass(Target, Dst.getLeafValue())) { + Target.getInitValueAsRegClass(Dst.getLeafValue())) { const CodeGenRegisterClass &RC = Target.getRegisterClass(RCDef); // We need to replace the def and all its uses with the specified From dcb4387a3e1401557b2aaa0810c9485fa9f300bc Mon Sep 17 00:00:00 2001 From: Matt Arsenault Date: Mon, 15 Sep 2025 12:08:54 +0900 Subject: [PATCH 04/28] Use CodeGenTarget::getInitValueAsRegClass in CodeGenInstAlias --- .../TableGen/Common/CodeGenInstAlias.cpp | 27 +++++-------------- 1 file changed, 6 insertions(+), 21 deletions(-) diff --git a/llvm/utils/TableGen/Common/CodeGenInstAlias.cpp b/llvm/utils/TableGen/Common/CodeGenInstAlias.cpp index fb1091015a78d..eaeb28f5e5b42 100644 --- a/llvm/utils/TableGen/Common/CodeGenInstAlias.cpp +++ b/llvm/utils/TableGen/Common/CodeGenInstAlias.cpp @@ -38,17 +38,6 @@ unsigned CodeGenInstAlias::ResultOperand::getMINumOperands() const { return MIOpInfo->getNumArgs(); } -static const Record *getInitValueAsRegClass(const Init *V) { - if (const auto *VDefInit = dyn_cast(V)) { - const Record *R = VDefInit->getDef(); - if (R->isSubClassOf("RegisterClass")) - return R; - if (R->isSubClassOf("RegisterOperand")) - return R->getValueAsDef("RegClass"); - } - return nullptr; -} - using ResultOperand = CodeGenInstAlias::ResultOperand; static Expected matchSimpleOperand(const Init *Arg, @@ -64,16 +53,12 @@ static Expected matchSimpleOperand(const Init *Arg, const Record *ArgRec = ArgDef->getDef(); // Match 'RegClass:$name' or 'RegOp:$name'. - if (const Record *ArgRC = getInitValueAsRegClass(Arg)) { - if (OpRC->isSubClassOf("RegisterClass")) { - if (!T.getRegisterClass(OpRC).hasSubClass(&T.getRegisterClass(ArgRC))) - return createStringError( - "argument register class" + ArgRC->getName() + - " is not a subclass of operand register class " + - OpRC->getName()); - } - // FIXME: Do some validation on RegClassByHwMode - + if (const Record *ArgRC = T.getInitValueAsRegClass(Arg)) { + if (!T.getRegisterClass(OpRC).hasSubClass(&T.getRegisterClass(ArgRC))) + return createStringError( + "argument register class" + ArgRC->getName() + + " is not a subclass of operand register class " + + OpRC->getName()); if (!ArgName) return createStringError("register class argument must have a name"); return ResultOperand::createRecord(ArgName->getAsUnquotedString(), From 149b9fd0a8b3e7e1a1871f3be2d5bb180b6e8ae9 Mon Sep 17 00:00:00 2001 From: Matt Arsenault Date: Mon, 15 Sep 2025 14:15:10 +0900 Subject: [PATCH 05/28] getInitValueAsRegClass(Like) --- .../TableGen/Common/CodeGenInstAlias.cpp | 22 +++++---- llvm/utils/TableGen/Common/CodeGenTarget.cpp | 45 +++++++++++-------- llvm/utils/TableGen/Common/CodeGenTarget.h | 15 ++++++- llvm/utils/TableGen/Common/InfoByHwMode.h | 3 -- llvm/utils/TableGen/GlobalISelEmitter.cpp | 4 +- 5 files changed, 58 insertions(+), 31 deletions(-) diff --git a/llvm/utils/TableGen/Common/CodeGenInstAlias.cpp b/llvm/utils/TableGen/Common/CodeGenInstAlias.cpp index eaeb28f5e5b42..6c1a3e9977c28 100644 --- a/llvm/utils/TableGen/Common/CodeGenInstAlias.cpp +++ b/llvm/utils/TableGen/Common/CodeGenInstAlias.cpp @@ -53,14 +53,20 @@ static Expected matchSimpleOperand(const Init *Arg, const Record *ArgRec = ArgDef->getDef(); // Match 'RegClass:$name' or 'RegOp:$name'. - if (const Record *ArgRC = T.getInitValueAsRegClass(Arg)) { - if (!T.getRegisterClass(OpRC).hasSubClass(&T.getRegisterClass(ArgRC))) - return createStringError( - "argument register class" + ArgRC->getName() + - " is not a subclass of operand register class " + - OpRC->getName()); - if (!ArgName) - return createStringError("register class argument must have a name"); + if (const Record *ArgRC = T.getInitValueAsRegClassLike(Arg)) { + if (ArgRC->isSubClassOf("RegisterClass")) { + if (!T.getRegisterClass(OpRC).hasSubClass(&T.getRegisterClass(ArgRC))) + return createStringError( + "argument register class" + ArgRC->getName() + + " is not a subclass of operand register class " + + OpRC->getName()); + if (!ArgName) + return createStringError( + "register class argument must have a name"); + } + + // TODO: Verify RegClassByHwMode usage + return ResultOperand::createRecord(ArgName->getAsUnquotedString(), ArgRec); } diff --git a/llvm/utils/TableGen/Common/CodeGenTarget.cpp b/llvm/utils/TableGen/Common/CodeGenTarget.cpp index a1bf683dbcd34..a8d9572321a89 100644 --- a/llvm/utils/TableGen/Common/CodeGenTarget.cpp +++ b/llvm/utils/TableGen/Common/CodeGenTarget.cpp @@ -197,29 +197,38 @@ void CodeGenTarget::ReadLegalValueTypes() const { LegalValueTypes.erase(llvm::unique(LegalValueTypes), LegalValueTypes.end()); } -const Record *CodeGenTarget::getInitValueAsRegClass(const Init *V) const { - if (const DefInit *VDefInit = dyn_cast(V)) { - const Record *RegClass = VDefInit->getDef(); - if (RegClass->isSubClassOf("RegisterOperand")) - RegClass = RegClass->getValueAsDef("RegClass"); - - if (RegClass->isSubClassOf("RegisterClass")) - return RegClass; - - // FIXME: We should figure out the hwmode and dispatch. But this interface - // is broken, we should be returning a register class. The expected uses - // will use the same RegBanks in all modes. - if (RegClass->isSubClassOf("RegClassByHwMode")) { - const HwModeSelect &ModeSelect = getHwModes().getHwModeSelect(RegClass); - if (ModeSelect.Items.empty()) - return nullptr; - return ModeSelect.Items.front().second; - } +const Record *CodeGenTarget::getInitValueAsRegClass( + const Init *V, bool AssumeRegClassByHwModeIsDefault) const { + const Record *RegClassLike = getInitValueAsRegClassLike(V); + if (!RegClassLike || RegClassLike->isSubClassOf("RegisterClass")) + return RegClassLike; + + // FIXME: We should figure out the hwmode and dispatch. But this interface + // is broken, we should be returning a register class. The expected uses + // will use the same RegBanks in all modes. + if (AssumeRegClassByHwModeIsDefault && + RegClassLike->isSubClassOf("RegClassByHwMode")) { + const HwModeSelect &ModeSelect = getHwModes().getHwModeSelect(RegClassLike); + if (ModeSelect.Items.empty()) + return nullptr; + return ModeSelect.Items.front().second; } return nullptr; } +const Record *CodeGenTarget::getInitValueAsRegClassLike(const Init *V) const { + const DefInit *VDefInit = dyn_cast(V); + if (!VDefInit) + return nullptr; + + const Record *RegClass = VDefInit->getDef(); + if (RegClass->isSubClassOf("RegisterOperand")) + RegClass = RegClass->getValueAsDef("RegClass"); + + return RegClass->isSubClassOf("RegisterClassLike") ? RegClass : nullptr; +} + CodeGenSchedModels &CodeGenTarget::getSchedModels() const { if (!SchedModels) SchedModels = std::make_unique(Records, *this); diff --git a/llvm/utils/TableGen/Common/CodeGenTarget.h b/llvm/utils/TableGen/Common/CodeGenTarget.h index 88dfef0df3e02..770d0cef96c34 100644 --- a/llvm/utils/TableGen/Common/CodeGenTarget.h +++ b/llvm/utils/TableGen/Common/CodeGenTarget.h @@ -152,7 +152,20 @@ class CodeGenTarget { return LegalValueTypes; } - const Record *getInitValueAsRegClass(const Init *V) const; + /// If \p V is a DefInit that can be interpreted as a RegisterClass (e.g., + /// it's a RegisterOperand, or a direct RegisterClass reference), return the + /// Record for that RegisterClass. + /// + /// AssumeRegClassByHwModeIsDefault is a hack which should be removed. It's + /// only happens to be adequate for the current GlobalISel usage. + const Record * + getInitValueAsRegClass(const Init *V, + bool AssumeRegClassByHwModeIsDefault = false) const; + + /// If \p V is a DefInit that can be interpreted as a RegisterClassLike, + /// return the Record. This is used as a convenience function to handle direct + /// RegisterClass references, or those wrapped in a RegisterOperand. + const Record *getInitValueAsRegClassLike(const Init *V) const; CodeGenSchedModels &getSchedModels() const; diff --git a/llvm/utils/TableGen/Common/InfoByHwMode.h b/llvm/utils/TableGen/Common/InfoByHwMode.h index 1d3bc434ced4f..6f55fc794cf26 100644 --- a/llvm/utils/TableGen/Common/InfoByHwMode.h +++ b/llvm/utils/TableGen/Common/InfoByHwMode.h @@ -253,9 +253,6 @@ struct RegClassByHwMode : public InfoByHwMode { RegClassByHwMode() = default; }; -raw_ostream &operator<<(raw_ostream &OS, const RegSizeInfo &T); -raw_ostream &operator<<(raw_ostream &OS, const RegClassByHwMode &T); - } // namespace llvm #endif // LLVM_UTILS_TABLEGEN_COMMON_INFOBYHWMODE_H diff --git a/llvm/utils/TableGen/GlobalISelEmitter.cpp b/llvm/utils/TableGen/GlobalISelEmitter.cpp index 23775a80c6144..0dbfe96039103 100644 --- a/llvm/utils/TableGen/GlobalISelEmitter.cpp +++ b/llvm/utils/TableGen/GlobalISelEmitter.cpp @@ -1137,7 +1137,9 @@ Error GlobalISelEmitter::importChildMatcher( ChildRec->isSubClassOf("RegisterOperand") || ChildRec->isSubClassOf("RegClassByHwMode")) { OM.addPredicate( - Target.getRegisterClass(Target.getInitValueAsRegClass(ChildDefInit))); + Target.getRegisterClass(Target.getInitValueAsRegClass( + ChildDefInit, + /*AssumeRegClassByHwModeIsDefault=*/true))); return Error::success(); } From 0987bce09111e05996e74d9680fa39a07298e93b Mon Sep 17 00:00:00 2001 From: Matt Arsenault Date: Mon, 15 Sep 2025 15:27:51 +0900 Subject: [PATCH 06/28] Fix crash in CodeGenInstAlias --- llvm/test/TableGen/RegClassByHwMode.td | 9 +++++++++ llvm/utils/TableGen/Common/CodeGenInstAlias.cpp | 3 ++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/llvm/test/TableGen/RegClassByHwMode.td b/llvm/test/TableGen/RegClassByHwMode.td index 3944c7eb79a7a..c487e28d0f33c 100644 --- a/llvm/test/TableGen/RegClassByHwMode.td +++ b/llvm/test/TableGen/RegClassByHwMode.td @@ -78,6 +78,8 @@ include "llvm/Target/Target.td" // ASMMATCHER: if (Operand.isReg()) { // ASMMATCHER: static const MatchEntry MatchTable0[] = { +// ASMMATCHER: /* also_my_load_1 */, MyTarget::MY_LOAD, Convert__RegByHwMode_XRegs_EvenIfRequired1_0__Imm1_1, AMFBS_None, { MCK_RegByHwMode_XRegs_EvenIfRequired, MCK_Imm }, }, +// ASMMATCHER: /* also_my_load_2 */, MyTarget::MY_LOAD, Convert__RegByHwMode_XRegs_EvenIfRequired1_0__Imm1_1, AMFBS_None, { MCK_RegByHwMode_XRegs_EvenIfRequired, MCK_Imm }, }, // ASMMATCHER: /* always_all */, MyTarget::ALWAYS_ALL, Convert__Reg1_0, AMFBS_None, { MCK_XRegs }, }, // ASMMATCHER: /* always_even */, MyTarget::ALWAYS_EVEN, Convert__Reg1_0, AMFBS_None, { MCK_XRegs_Even }, }, // ASMMATCHER: /* custom_decode */, MyTarget::CUSTOM_DECODE, Convert__RegByHwMode_YRegs_EvenIfRequired1_0, AMFBS_None, { MCK_RegByHwMode_YRegs_EvenIfRequired }, }, @@ -412,6 +414,13 @@ def MY_LOAD : TestInstruction { let opcode = 6; } +// Direct RegClassByHwMode reference +def MY_LOAD_ALIAS1 : InstAlias<"also_my_load_1 $dst, $src", + (MY_LOAD XRegs_EvenIfRequired:$dst, MyPtrRC:$src)>; + +// RegClassByHwMode wrapped in RegisterOperand +def MY_LOAD_ALIAS2 : InstAlias<"also_my_load_2 $dst, $src", + (MY_LOAD RegisterOperand:$dst, PtrRegOperand:$src)>; // Direct RegClassByHwMode usage def : Pat< diff --git a/llvm/utils/TableGen/Common/CodeGenInstAlias.cpp b/llvm/utils/TableGen/Common/CodeGenInstAlias.cpp index 6c1a3e9977c28..980471261301a 100644 --- a/llvm/utils/TableGen/Common/CodeGenInstAlias.cpp +++ b/llvm/utils/TableGen/Common/CodeGenInstAlias.cpp @@ -182,7 +182,8 @@ CodeGenInstAlias::CodeGenInstAlias(const Record *R, const CodeGenTarget &T) PrintFatalError(R->getLoc(), "not enough arguments for instruction!"); const Record *Op = OpInfo.Rec; - if (Op->isSubClassOf("Operand") && !OpInfo.MIOperandInfo->arg_empty()) { + if (Op->isSubClassOf("Operand") && OpInfo.MIOperandInfo && + !OpInfo.MIOperandInfo->arg_empty()) { // Complex operand (a subclass of Operand with non-empty MIOperandInfo). // The argument can be a DAG or a subclass of Operand. if (auto *ArgDag = dyn_cast(Result->getArg(ArgIdx))) { From 44b63fe252b0c3bb001ed8795d788be8958dd11c Mon Sep 17 00:00:00 2001 From: Matt Arsenault Date: Mon, 15 Sep 2025 16:08:31 +0900 Subject: [PATCH 07/28] Avoid unnecessary declaration --- llvm/test/TableGen/RegClassByHwMode.td | 28 +++++++++++++++++++++++- llvm/utils/TableGen/InstrInfoEmitter.cpp | 7 +----- 2 files changed, 28 insertions(+), 7 deletions(-) diff --git a/llvm/test/TableGen/RegClassByHwMode.td b/llvm/test/TableGen/RegClassByHwMode.td index c487e28d0f33c..b579b01a61526 100644 --- a/llvm/test/TableGen/RegClassByHwMode.td +++ b/llvm/test/TableGen/RegClassByHwMode.td @@ -6,7 +6,6 @@ include "llvm/Target/Target.td" - // INSTRINFO: #if defined(GET_INSTRINFO_MC_DESC) || defined(GET_INSTRINFO_CTOR_DTOR) // INSTRINFO-NEXT: namespace { // INSTRINFO-NEXT: enum RegClassByHwModeUses : uint16_t { @@ -24,6 +23,33 @@ include "llvm/Target/Target.td" // INSTRINFO: { YRegs_EvenIfRequired, 0|(1<InitMCInstrInfo(MyTargetDescs.Insts, MyTargetInstrNameIndices, MyTargetInstrNameData, nullptr, nullptr, 321, &MyTargetRegClassByHwModeTables[0][0], 3); + + // ASMMATCHER: enum MatchClassKind { // ASMMATCHER: MCK_LAST_TOKEN = OptionalMatchClass, diff --git a/llvm/utils/TableGen/InstrInfoEmitter.cpp b/llvm/utils/TableGen/InstrInfoEmitter.cpp index 9ed81c6f6c9e6..29ccc74b99266 100644 --- a/llvm/utils/TableGen/InstrInfoEmitter.cpp +++ b/llvm/utils/TableGen/InstrInfoEmitter.cpp @@ -1008,11 +1008,6 @@ void InstrInfoEmitter::run(raw_ostream &OS) { ArrayRef RegClassByHwMode = Target.getAllRegClassByHwMode(); unsigned NumClassesByHwMode = RegClassByHwMode.size(); - if (NumClassesByHwMode != 0) { - OS << "extern const int16_t " << TargetName << "RegClassByHwModeTables[" - << NumModes << "][" << NumClassesByHwMode << "];\n"; - } - OS << "extern const unsigned " << TargetName << "InstrNameIndices[] = {"; Num = 0; for (const CodeGenInstruction *Inst : NumberedInstructions) { @@ -1072,7 +1067,7 @@ void InstrInfoEmitter::run(raw_ostream &OS) { Timer.startTimer("Emit initialization routine"); if (NumClassesByHwMode != 0) { - OS << "const int16_t " << TargetName << "RegClassByHwModeTables[" + OS << "extern const int16_t " << TargetName << "RegClassByHwModeTables[" << NumModes << "][" << NumClassesByHwMode << "] = {\n"; for (unsigned M = 0; M < NumModes; ++M) { From 943b1f2e3f6d2796d76aad986b8bf5f343ab0f60 Mon Sep 17 00:00:00 2001 From: Matt Arsenault Date: Mon, 15 Sep 2025 16:15:04 +0900 Subject: [PATCH 08/28] Move where emitRegClassByHwModeDecoders is called --- llvm/utils/TableGen/DecoderEmitter.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/llvm/utils/TableGen/DecoderEmitter.cpp b/llvm/utils/TableGen/DecoderEmitter.cpp index 5c8b5fd2096c7..c203c33538530 100644 --- a/llvm/utils/TableGen/DecoderEmitter.cpp +++ b/llvm/utils/TableGen/DecoderEmitter.cpp @@ -903,8 +903,6 @@ void DecoderEmitter::emitRegClassByHwModeDecoders( void DecoderEmitter::emitDecoderFunction(formatted_raw_ostream &OS, const DecoderSet &Decoders, unsigned BucketBitWidth) const { - emitRegClassByHwModeDecoders(OS); - // The decoder function is just a big switch statement or a table of function // pointers based on the input decoder index. @@ -1953,6 +1951,8 @@ template constexpr uint32_t InsnBitWidth = 0; emitInstrLenTable(OS, InstrLen); } + emitRegClassByHwModeDecoders(OS); + // Map of (bitwidth, namespace, hwmode) tuple to encoding IDs. // Its organized as a nested map, with the (namespace, hwmode) as the key for // the inner map and bitwidth as the key for the outer map. We use std::map From 7c391b6461d46c4b40b40028066a5b2aeba58cc5 Mon Sep 17 00:00:00 2001 From: Matt Arsenault Date: Mon, 15 Sep 2025 16:17:03 +0900 Subject: [PATCH 09/28] Fix comment --- llvm/utils/TableGen/Common/InstructionEncoding.cpp | 1 - llvm/utils/TableGen/Common/InstructionEncoding.h | 2 ++ 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/llvm/utils/TableGen/Common/InstructionEncoding.cpp b/llvm/utils/TableGen/Common/InstructionEncoding.cpp index 5917f2ace94eb..c6c006b527b05 100644 --- a/llvm/utils/TableGen/Common/InstructionEncoding.cpp +++ b/llvm/utils/TableGen/Common/InstructionEncoding.cpp @@ -14,7 +14,6 @@ using namespace llvm; -/// If this is explictly set value, return true for second. std::pair InstructionEncoding::findOperandDecoderMethod(const CodeGenTarget &Target, const Record *Record) { diff --git a/llvm/utils/TableGen/Common/InstructionEncoding.h b/llvm/utils/TableGen/Common/InstructionEncoding.h index ec416f5b34d2b..421fc9c7e47b8 100644 --- a/llvm/utils/TableGen/Common/InstructionEncoding.h +++ b/llvm/utils/TableGen/Common/InstructionEncoding.h @@ -138,6 +138,8 @@ class InstructionEncoding { /// Returns information about the operands' contribution to this encoding. ArrayRef getOperands() const { return Operands; } + /// \returns the effective value of the DecoderMethod field.t If DecoderMethod + /// is an explictly set value, return false for second. static std::pair findOperandDecoderMethod(const CodeGenTarget &Target, const Record *Record); From b9bd6292145850bd141295d0f25127003e5a2be5 Mon Sep 17 00:00:00 2001 From: Matt Arsenault Date: Mon, 15 Sep 2025 19:52:05 +0900 Subject: [PATCH 10/28] Check RegisterClassLike --- llvm/utils/TableGen/GlobalISelEmitter.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/llvm/utils/TableGen/GlobalISelEmitter.cpp b/llvm/utils/TableGen/GlobalISelEmitter.cpp index 0dbfe96039103..f7993ce0b845d 100644 --- a/llvm/utils/TableGen/GlobalISelEmitter.cpp +++ b/llvm/utils/TableGen/GlobalISelEmitter.cpp @@ -1133,9 +1133,8 @@ Error GlobalISelEmitter::importChildMatcher( auto *ChildRec = ChildDefInit->getDef(); // Check for register classes. - if (ChildRec->isSubClassOf("RegisterClass") || - ChildRec->isSubClassOf("RegisterOperand") || - ChildRec->isSubClassOf("RegClassByHwMode")) { + if (ChildRec->isSubClassOf("RegisterClassLike") || + ChildRec->isSubClassOf("RegisterOperand")) { OM.addPredicate( Target.getRegisterClass(Target.getInitValueAsRegClass( ChildDefInit, From 768d11474637ae919f1ac2416edbb3a0dbb551e9 Mon Sep 17 00:00:00 2001 From: Matt Arsenault Date: Mon, 15 Sep 2025 20:00:29 +0900 Subject: [PATCH 11/28] Use check literal --- llvm/test/TableGen/RegClassByHwMode.td | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/llvm/test/TableGen/RegClassByHwMode.td b/llvm/test/TableGen/RegClassByHwMode.td index b579b01a61526..b8d37c9da4c44 100644 --- a/llvm/test/TableGen/RegClassByHwMode.td +++ b/llvm/test/TableGen/RegClassByHwMode.td @@ -114,7 +114,7 @@ include "llvm/Target/Target.td" -// DISASM: {{\[\[}}maybe_unused{{\]\]}} +// DISASM{LITERAL}: [[maybe_unused]] // DISASM-NEXT: static DecodeStatus DecodeMyPtrRCRegClassByHwMode(MCInst &Inst, unsigned Imm, uint64_t Addr, const MCDisassembler *Decoder) { // DISASM-NEXT: switch (Decoder->getSubtargetInfo().getHwMode(MCSubtargetInfo::HwMode_RegClass)) { // DISASM-NEXT: case 0: // DefaultMode @@ -126,7 +126,7 @@ include "llvm/Target/Target.td" // DISASM-NEXT: } // DISASM-NEXT: } -// DISASM: {{\[\[}}maybe_unused{{\]\]}} +// DISASM{LITERAL}: [[maybe_unused]] // DISASM-NEXT: static DecodeStatus DecodeXRegs_EvenIfRequiredRegClassByHwMode(MCInst &Inst, unsigned Imm, uint64_t Addr, const MCDisassembler *Decoder) { // DISASM-NEXT: switch (Decoder->getSubtargetInfo().getHwMode(MCSubtargetInfo::HwMode_RegClass)) { // DISASM-NEXT: case 0: // DefaultMode @@ -140,7 +140,7 @@ include "llvm/Target/Target.td" // DISASM-NEXT: } // DISASM-NEXT:} // DISASM-EMPTY: -// DISASM: {{\[\[}}maybe_unused{{\]\]}} +// DISASM{LITERAL}: [[maybe_unused]] // DISASM-NEXT: static DecodeStatus DecodeYRegs_EvenIfRequiredRegClassByHwMode(MCInst &Inst, unsigned Imm, uint64_t Addr, const MCDisassembler *Decoder) { // DISASM-NEXT: switch (Decoder->getSubtargetInfo().getHwMode(MCSubtargetInfo::HwMode_RegClass)) { // DISASM-NEXT: case 0: // DefaultMode From 4e0978fb21a090f2f9b44269e8205b1ff1b6bc12 Mon Sep 17 00:00:00 2001 From: Matt Arsenault Date: Mon, 15 Sep 2025 20:04:36 +0900 Subject: [PATCH 12/28] Structured binding --- llvm/utils/TableGen/DecoderEmitter.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/llvm/utils/TableGen/DecoderEmitter.cpp b/llvm/utils/TableGen/DecoderEmitter.cpp index c203c33538530..35f0a6de89790 100644 --- a/llvm/utils/TableGen/DecoderEmitter.cpp +++ b/llvm/utils/TableGen/DecoderEmitter.cpp @@ -878,14 +878,13 @@ void DecoderEmitter::emitRegClassByHwModeDecoders( OS << R"((MCInst &Inst, unsigned Imm, uint64_t Addr, const MCDisassembler *Decoder) { switch (Decoder->getSubtargetInfo().getHwMode(MCSubtargetInfo::HwMode_RegClass)) { )"; - for (const HwModeSelect::PairType &P : ModeSelect.Items) { - const CodeGenRegisterClass *RegClass = RegBank.getRegClass(P.second); + for (auto [ModeID, RegClassRec] : ModeSelect.Items) { + const CodeGenRegisterClass *RegClass = RegBank.getRegClass(RegClassRec); - OS << indent(2) << "case " << P.first << ": // " - << CGH.getModeName(P.first, /*IncludeDefault=*/true) << '\n' + OS << indent(2) << "case " << ModeID << ": // " + << CGH.getModeName(ModeID, /*IncludeDefault=*/true) << '\n' << indent(4) << "return " - << InstructionEncoding::findOperandDecoderMethod(Target, - RegClass->getDef()) + << InstructionEncoding::findOperandDecoderMethod(Target, RegClassRec) .first << "(Inst, Imm, Addr, Decoder);\n"; } From 586c48f8bf5ec3d06bfb9c3269154a571909119f Mon Sep 17 00:00:00 2001 From: Matt Arsenault Date: Mon, 15 Sep 2025 20:15:51 +0900 Subject: [PATCH 13/28] Re-use RegInfo HwMode kind --- llvm/include/llvm/MC/MCSubtargetInfo.h | 9 ++++----- llvm/test/TableGen/RegClassByHwMode.td | 8 ++++---- llvm/utils/TableGen/AsmMatcherEmitter.cpp | 2 +- llvm/utils/TableGen/DecoderEmitter.cpp | 6 +----- llvm/utils/TableGen/InstrInfoEmitter.cpp | 2 +- llvm/utils/TableGen/SubtargetEmitter.cpp | 1 - 6 files changed, 11 insertions(+), 17 deletions(-) diff --git a/llvm/include/llvm/MC/MCSubtargetInfo.h b/llvm/include/llvm/MC/MCSubtargetInfo.h index 5204c23897d67..03ff85f6a8f47 100644 --- a/llvm/include/llvm/MC/MCSubtargetInfo.h +++ b/llvm/include/llvm/MC/MCSubtargetInfo.h @@ -255,11 +255,10 @@ class LLVM_ABI MCSubtargetInfo { /// this method also supports controlling multiple attributes with a single /// HwMode ID, just as was done previously. enum HwModeType { - HwMode_Default, // Return the smallest HwMode ID of current subtarget. - HwMode_ValueType, // Return the HwMode ID that controls the ValueType. - HwMode_RegInfo, // Return the HwMode ID that controls the RegSizeInfo and - // SubRegRange. - HwMode_RegClass, // Return the HwMode ID that controls the RegisterClass. + HwMode_Default, // Return the smallest HwMode ID of current subtarget. + HwMode_ValueType, // Return the HwMode ID that controls the ValueType. + HwMode_RegInfo, // Return the HwMode ID that controls the RegSizeInfo, + // SubRegRange, and RegisterClass. HwMode_EncodingInfo // Return the HwMode ID that controls the EncodingInfo. }; diff --git a/llvm/test/TableGen/RegClassByHwMode.td b/llvm/test/TableGen/RegClassByHwMode.td index b8d37c9da4c44..bafff14e0eb74 100644 --- a/llvm/test/TableGen/RegClassByHwMode.td +++ b/llvm/test/TableGen/RegClassByHwMode.td @@ -97,7 +97,7 @@ include "llvm/Target/Target.td" // ASMMATCHER-NEXT: }; // ASMMATCHER-EMPTY: // ASMMATCHER-NEXT: static_assert(MCK_LAST_REGCLASS_BY_HWMODE - MCK_LAST_REGISTER == 3); -// ASMMATCHER-NEXT: const unsigned HwMode = STI.getHwMode(MCSubtargetInfo::HwMode_RegClass); +// ASMMATCHER-NEXT: const unsigned HwMode = STI.getHwMode(MCSubtargetInfo::HwMode_RegInfo); // ASMMATCHER-NEXT: Kind = RegClassByHwModeMatchTable[HwMode][Kind - (MCK_LAST_REGISTER + 1)]; // ASMMATCHER-NEXT: } @@ -116,7 +116,7 @@ include "llvm/Target/Target.td" // DISASM{LITERAL}: [[maybe_unused]] // DISASM-NEXT: static DecodeStatus DecodeMyPtrRCRegClassByHwMode(MCInst &Inst, unsigned Imm, uint64_t Addr, const MCDisassembler *Decoder) { -// DISASM-NEXT: switch (Decoder->getSubtargetInfo().getHwMode(MCSubtargetInfo::HwMode_RegClass)) { +// DISASM-NEXT: switch (Decoder->getSubtargetInfo().getHwMode(MCSubtargetInfo::HwMode_RegInfo)) { // DISASM-NEXT: case 0: // DefaultMode // DISASM-NEXT: return DecodePtrRegs32RegisterClass(Inst, Imm, Addr, Decoder); // DISASM-NEXT: case 3: // Ptr64 @@ -128,7 +128,7 @@ include "llvm/Target/Target.td" // DISASM{LITERAL}: [[maybe_unused]] // DISASM-NEXT: static DecodeStatus DecodeXRegs_EvenIfRequiredRegClassByHwMode(MCInst &Inst, unsigned Imm, uint64_t Addr, const MCDisassembler *Decoder) { -// DISASM-NEXT: switch (Decoder->getSubtargetInfo().getHwMode(MCSubtargetInfo::HwMode_RegClass)) { +// DISASM-NEXT: switch (Decoder->getSubtargetInfo().getHwMode(MCSubtargetInfo::HwMode_RegInfo)) { // DISASM-NEXT: case 0: // DefaultMode // DISASM-NEXT: return DecodeXRegsRegisterClass(Inst, Imm, Addr, Decoder); // DISASM-NEXT: case 1: // EvenMode @@ -142,7 +142,7 @@ include "llvm/Target/Target.td" // DISASM-EMPTY: // DISASM{LITERAL}: [[maybe_unused]] // DISASM-NEXT: static DecodeStatus DecodeYRegs_EvenIfRequiredRegClassByHwMode(MCInst &Inst, unsigned Imm, uint64_t Addr, const MCDisassembler *Decoder) { -// DISASM-NEXT: switch (Decoder->getSubtargetInfo().getHwMode(MCSubtargetInfo::HwMode_RegClass)) { +// DISASM-NEXT: switch (Decoder->getSubtargetInfo().getHwMode(MCSubtargetInfo::HwMode_RegInfo)) { // DISASM-NEXT: case 0: // DefaultMode // DISASM-NEXT: return DecodeYRegsRegisterClass(Inst, Imm, Addr, Decoder); // DISASM-NEXT: case 1: // EvenMode diff --git a/llvm/utils/TableGen/AsmMatcherEmitter.cpp b/llvm/utils/TableGen/AsmMatcherEmitter.cpp index db3154b70c1f3..c32c2a3d5753b 100644 --- a/llvm/utils/TableGen/AsmMatcherEmitter.cpp +++ b/llvm/utils/TableGen/AsmMatcherEmitter.cpp @@ -2606,7 +2606,7 @@ static void emitValidateOperandClass(const CodeGenTarget &Target, OS << indent(4) << "const unsigned HwMode = " - "STI.getHwMode(MCSubtargetInfo::HwMode_RegClass);\n" + "STI.getHwMode(MCSubtargetInfo::HwMode_RegInfo);\n" "Kind = RegClassByHwModeMatchTable[HwMode][Kind - (MCK_LAST_REGISTER " "+ 1)];\n" " }\n\n"; diff --git a/llvm/utils/TableGen/DecoderEmitter.cpp b/llvm/utils/TableGen/DecoderEmitter.cpp index 35f0a6de89790..10863343d4625 100644 --- a/llvm/utils/TableGen/DecoderEmitter.cpp +++ b/llvm/utils/TableGen/DecoderEmitter.cpp @@ -858,8 +858,6 @@ void DecoderEmitter::emitRegClassByHwModeDecoders( if (RegClassByHwMode.empty()) return; - const CodeGenRegBank &RegBank = Target.getRegBank(); - for (const Record *ClassByHwMode : RegClassByHwMode) { // Ignore cases that had an explicit DecoderMethod set. if (!InstructionEncoding::findOperandDecoderMethod(Target, ClassByHwMode) @@ -876,11 +874,9 @@ void DecoderEmitter::emitRegClassByHwModeDecoders( OS << "static DecodeStatus Decode" << ClassByHwMode->getName() << "RegClassByHwMode"; OS << R"((MCInst &Inst, unsigned Imm, uint64_t Addr, const MCDisassembler *Decoder) { - switch (Decoder->getSubtargetInfo().getHwMode(MCSubtargetInfo::HwMode_RegClass)) { + switch (Decoder->getSubtargetInfo().getHwMode(MCSubtargetInfo::HwMode_RegInfo)) { )"; for (auto [ModeID, RegClassRec] : ModeSelect.Items) { - const CodeGenRegisterClass *RegClass = RegBank.getRegClass(RegClassRec); - OS << indent(2) << "case " << ModeID << ": // " << CGH.getModeName(ModeID, /*IncludeDefault=*/true) << '\n' << indent(4) << "return " diff --git a/llvm/utils/TableGen/InstrInfoEmitter.cpp b/llvm/utils/TableGen/InstrInfoEmitter.cpp index 29ccc74b99266..7e485356fe14e 100644 --- a/llvm/utils/TableGen/InstrInfoEmitter.cpp +++ b/llvm/utils/TableGen/InstrInfoEmitter.cpp @@ -1181,7 +1181,7 @@ void InstrInfoEmitter::run(raw_ostream &OS) { if (NumClassesByHwMode != 0) OS << ", " << TargetName << "RegClassByHwModeTables[STI.getHwMode(MCSubtargetInfo::HwMode_" - "RegClass)]"; + "RegInfo)]"; OS << ") {\n" << " InitMCInstrInfo(" << TargetName << "Descs.Insts, " << TargetName diff --git a/llvm/utils/TableGen/SubtargetEmitter.cpp b/llvm/utils/TableGen/SubtargetEmitter.cpp index b5ffbedc41b24..0f42d49a6bea1 100644 --- a/llvm/utils/TableGen/SubtargetEmitter.cpp +++ b/llvm/utils/TableGen/SubtargetEmitter.cpp @@ -1850,7 +1850,6 @@ void SubtargetEmitter::emitHwModeCheck(const std::string &ClassName, OS << " case HwMode_Default:\n return llvm::countr_zero(Modes) + 1;\n"; HandlePerMode("ValueType", ValueTypeModes); HandlePerMode("RegInfo", RegInfoModes); - HandlePerMode("RegClass", RegInfoModes); HandlePerMode("EncodingInfo", EncodingInfoModes); OS << " }\n"; OS << " llvm_unreachable(\"unexpected HwModeType\");\n" From f780b469500142deb37938ce10bc90e50eb25312 Mon Sep 17 00:00:00 2001 From: Matt Arsenault Date: Mon, 15 Sep 2025 20:38:55 +0900 Subject: [PATCH 14/28] CodeGenRegBank to RegClassByHwMode --- llvm/utils/TableGen/Common/CodeGenDAGPatterns.cpp | 2 +- llvm/utils/TableGen/Common/InfoByHwMode.cpp | 6 +++--- llvm/utils/TableGen/Common/InfoByHwMode.h | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/llvm/utils/TableGen/Common/CodeGenDAGPatterns.cpp b/llvm/utils/TableGen/Common/CodeGenDAGPatterns.cpp index 7fdb6b97e435c..af75e44f63e48 100644 --- a/llvm/utils/TableGen/Common/CodeGenDAGPatterns.cpp +++ b/llvm/utils/TableGen/Common/CodeGenDAGPatterns.cpp @@ -1794,7 +1794,7 @@ bool llvm::operator<(const SDTypeConstraint &LHS, const SDTypeConstraint &RHS) { static TypeSetByHwMode getTypeForRegClassByHwMode(const CodeGenTarget &T, const Record *R) { TypeSetByHwMode TypeSet; - RegClassByHwMode Helper(R, T.getHwModes(), T); + RegClassByHwMode Helper(R, T.getHwModes(), T.getRegBank()); for (auto [ModeID, RegClass] : Helper) { ArrayRef RegClassVTs = RegClass->getValueTypes(); diff --git a/llvm/utils/TableGen/Common/InfoByHwMode.cpp b/llvm/utils/TableGen/Common/InfoByHwMode.cpp index fd6494bc8cad1..6bc5e0e8eae58 100644 --- a/llvm/utils/TableGen/Common/InfoByHwMode.cpp +++ b/llvm/utils/TableGen/Common/InfoByHwMode.cpp @@ -188,14 +188,14 @@ void RegSizeInfoByHwMode::writeToStream(raw_ostream &OS) const { } RegClassByHwMode::RegClassByHwMode(const Record *R, const CodeGenHwModes &CGH, - const CodeGenTarget &Target) { + const CodeGenRegBank &RegBank) { const HwModeSelect &MS = CGH.getHwModeSelect(R); for (const HwModeSelect::PairType &P : MS.Items) { assert(P.second && P.second->isSubClassOf("RegisterClass") && "Register class must subclass RegisterClass"); - const CodeGenRegisterClass &RegClass = Target.getRegisterClass(P.second); - if (!Map.try_emplace(P.first, &RegClass).second) + const CodeGenRegisterClass *RegClass = RegBank.getRegClass(P.second); + if (!Map.try_emplace(P.first, RegClass).second) llvm_unreachable("duplicate entry"); } } diff --git a/llvm/utils/TableGen/Common/InfoByHwMode.h b/llvm/utils/TableGen/Common/InfoByHwMode.h index 6f55fc794cf26..c730b7397c173 100644 --- a/llvm/utils/TableGen/Common/InfoByHwMode.h +++ b/llvm/utils/TableGen/Common/InfoByHwMode.h @@ -28,8 +28,8 @@ namespace llvm { +class CodeGenRegBank; class CodeGenRegisterClass; -class CodeGenTarget; class Record; class raw_ostream; @@ -249,7 +249,7 @@ struct EncodingInfoByHwMode : public InfoByHwMode { struct RegClassByHwMode : public InfoByHwMode { public: RegClassByHwMode(const Record *R, const CodeGenHwModes &CGH, - const CodeGenTarget &Target); + const CodeGenRegBank &RegBank); RegClassByHwMode() = default; }; From e862ef380d7b013b8b58c53b23668f406feb162d Mon Sep 17 00:00:00 2001 From: Matt Arsenault Date: Tue, 16 Sep 2025 12:49:17 +0900 Subject: [PATCH 15/28] comment typos --- llvm/utils/TableGen/Common/CodeGenTarget.h | 4 ++-- llvm/utils/TableGen/Common/InstructionEncoding.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/llvm/utils/TableGen/Common/CodeGenTarget.h b/llvm/utils/TableGen/Common/CodeGenTarget.h index 770d0cef96c34..b6f9d4209a13e 100644 --- a/llvm/utils/TableGen/Common/CodeGenTarget.h +++ b/llvm/utils/TableGen/Common/CodeGenTarget.h @@ -156,8 +156,8 @@ class CodeGenTarget { /// it's a RegisterOperand, or a direct RegisterClass reference), return the /// Record for that RegisterClass. /// - /// AssumeRegClassByHwModeIsDefault is a hack which should be removed. It's - /// only happens to be adequate for the current GlobalISel usage. + /// AssumeRegClassByHwModeIsDefault is a hack which should be removed. It only + /// happens to be adequate for the current GlobalISel usage. const Record * getInitValueAsRegClass(const Init *V, bool AssumeRegClassByHwModeIsDefault = false) const; diff --git a/llvm/utils/TableGen/Common/InstructionEncoding.h b/llvm/utils/TableGen/Common/InstructionEncoding.h index 421fc9c7e47b8..412f93402170c 100644 --- a/llvm/utils/TableGen/Common/InstructionEncoding.h +++ b/llvm/utils/TableGen/Common/InstructionEncoding.h @@ -138,7 +138,7 @@ class InstructionEncoding { /// Returns information about the operands' contribution to this encoding. ArrayRef getOperands() const { return Operands; } - /// \returns the effective value of the DecoderMethod field.t If DecoderMethod + /// \returns the effective value of the DecoderMethod field. If DecoderMethod /// is an explictly set value, return false for second. static std::pair findOperandDecoderMethod(const CodeGenTarget &Target, const Record *Record); From 2fee8f89668d8c0b457eab9c2dda3b2c4c6be176 Mon Sep 17 00:00:00 2001 From: Matt Arsenault Date: Tue, 16 Sep 2025 12:50:06 +0900 Subject: [PATCH 16/28] Address comment --- llvm/utils/TableGen/Common/CodeGenTarget.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/llvm/utils/TableGen/Common/CodeGenTarget.cpp b/llvm/utils/TableGen/Common/CodeGenTarget.cpp index a8d9572321a89..3db0d07eec88f 100644 --- a/llvm/utils/TableGen/Common/CodeGenTarget.cpp +++ b/llvm/utils/TableGen/Common/CodeGenTarget.cpp @@ -224,7 +224,7 @@ const Record *CodeGenTarget::getInitValueAsRegClassLike(const Init *V) const { const Record *RegClass = VDefInit->getDef(); if (RegClass->isSubClassOf("RegisterOperand")) - RegClass = RegClass->getValueAsDef("RegClass"); + return RegClass->getValueAsDef("RegClass"); return RegClass->isSubClassOf("RegisterClassLike") ? RegClass : nullptr; } From 706d391347d89031d52736e9b3a18de3ae9d1667 Mon Sep 17 00:00:00 2001 From: Matt Arsenault Date: Tue, 16 Sep 2025 13:06:40 +0900 Subject: [PATCH 17/28] Stop multiple inheritance from Operand in test --- llvm/test/TableGen/RegClassByHwMode.td | 11 +++++------ llvm/utils/TableGen/Common/CodeGenInstAlias.cpp | 3 +-- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/llvm/test/TableGen/RegClassByHwMode.td b/llvm/test/TableGen/RegClassByHwMode.td index bafff14e0eb74..299fe7850e313 100644 --- a/llvm/test/TableGen/RegClassByHwMode.td +++ b/llvm/test/TableGen/RegClassByHwMode.td @@ -19,10 +19,9 @@ include "llvm/Target/Target.td" // INSTRINFO: { MyTarget::XRegs_EvenRegClassID, 0, MCOI::OPERAND_REGISTER, 0 }, // INSTRINFO: { YRegs_EvenIfRequired, 0|(1<; def MyPtrRC : RegClassByHwMode<[DefaultMode, Ptr64], - [PtrRegs32, PtrRegs64]>, Operand; + [PtrRegs32, PtrRegs64]>; -def PtrRegOperand : RegisterOperand, Operand; +def PtrRegOperand : RegisterOperand; def CustomDecodeYEvenIfRequired : RegisterOperand { diff --git a/llvm/utils/TableGen/Common/CodeGenInstAlias.cpp b/llvm/utils/TableGen/Common/CodeGenInstAlias.cpp index 980471261301a..6c1a3e9977c28 100644 --- a/llvm/utils/TableGen/Common/CodeGenInstAlias.cpp +++ b/llvm/utils/TableGen/Common/CodeGenInstAlias.cpp @@ -182,8 +182,7 @@ CodeGenInstAlias::CodeGenInstAlias(const Record *R, const CodeGenTarget &T) PrintFatalError(R->getLoc(), "not enough arguments for instruction!"); const Record *Op = OpInfo.Rec; - if (Op->isSubClassOf("Operand") && OpInfo.MIOperandInfo && - !OpInfo.MIOperandInfo->arg_empty()) { + if (Op->isSubClassOf("Operand") && !OpInfo.MIOperandInfo->arg_empty()) { // Complex operand (a subclass of Operand with non-empty MIOperandInfo). // The argument can be a DAG or a subclass of Operand. if (auto *ArgDag = dyn_cast(Result->getArg(ArgIdx))) { From efbcd71246783a3588e2eb7ab1d62c0f55bb7b40 Mon Sep 17 00:00:00 2001 From: Matt Arsenault Date: Tue, 16 Sep 2025 13:17:50 +0900 Subject: [PATCH 18/28] Use find_if --- llvm/utils/TableGen/AsmMatcherEmitter.cpp | 27 ++++++++++------------- llvm/utils/TableGen/InstrInfoEmitter.cpp | 27 +++++++++++------------ 2 files changed, 25 insertions(+), 29 deletions(-) diff --git a/llvm/utils/TableGen/AsmMatcherEmitter.cpp b/llvm/utils/TableGen/AsmMatcherEmitter.cpp index c32c2a3d5753b..2379d5568224e 100644 --- a/llvm/utils/TableGen/AsmMatcherEmitter.cpp +++ b/llvm/utils/TableGen/AsmMatcherEmitter.cpp @@ -2576,23 +2576,20 @@ static void emitValidateOperandClass(const CodeGenTarget &Target, const Record *Class = RegClassesByHwMode[I]; const HwModeSelect &ModeSelect = CGH.getHwModeSelect(Class); - bool Seen = false; - for (const HwModeSelect::PairType &P : ModeSelect.Items) { - if (P.first == M) { - const CodeGenRegisterClass *RegClass = - RegBank.getRegClass(P.second); - - const ClassInfo *CI = - Info.RegisterClassClasses.at(RegClass->getDef()); - - OS << indent(8) << CI->Name << ",\n"; - Seen = true; - break; - } - } + auto FoundMode = + find_if(ModeSelect.Items, [=](const HwModeSelect::PairType P) { + return P.first == M; + }); - if (!Seen) + if (FoundMode == ModeSelect.Items.end()) { OS << indent(8) << "InvalidMatchClass, // Missing mode\n"; + } else { + const CodeGenRegisterClass *RegClass = + RegBank.getRegClass(FoundMode->second); + const ClassInfo *CI = + Info.RegisterClassClasses.at(RegClass->getDef()); + OS << indent(8) << CI->Name << ",\n"; + } } OS << indent(6) << "},\n"; diff --git a/llvm/utils/TableGen/InstrInfoEmitter.cpp b/llvm/utils/TableGen/InstrInfoEmitter.cpp index 7e485356fe14e..2066994ca3387 100644 --- a/llvm/utils/TableGen/InstrInfoEmitter.cpp +++ b/llvm/utils/TableGen/InstrInfoEmitter.cpp @@ -1076,21 +1076,20 @@ void InstrInfoEmitter::run(raw_ostream &OS) { const Record *Class = RegClassByHwMode[I]; const HwModeSelect &ModeSelect = CGH.getHwModeSelect(Class); - bool Seen = false; - for (const HwModeSelect::PairType &P : ModeSelect.Items) { - if (P.first == M) { - const CodeGenRegisterClass *RegClass = - RegBank.getRegClass(P.second); - OS << indent(4) << RegClass->getQualifiedIdName() << ",\n"; - Seen = true; - break; - } - } - - // If a RegClassByHwMode doesn't have an entry corresponding to a mode, - // pad with default register class. - if (!Seen) + auto FoundMode = + find_if(ModeSelect.Items, [=](const HwModeSelect::PairType P) { + return P.first == M; + }); + + if (FoundMode == ModeSelect.Items.end()) { + // If a RegClassByHwMode doesn't have an entry corresponding to a + // mode, pad with default register class. OS << indent(4) << "-1, // Missing mode entry\n"; + } else { + const CodeGenRegisterClass *RegClass = + RegBank.getRegClass(FoundMode->second); + OS << indent(4) << RegClass->getQualifiedIdName() << ",\n"; + } } OS << " },\n"; From 9bbaca38bf97cedd1d87eeb502548e797a756781 Mon Sep 17 00:00:00 2001 From: Matt Arsenault Date: Wed, 17 Sep 2025 21:32:40 +0900 Subject: [PATCH 19/28] Move RegClassByHwModeUses definition to header --- llvm/test/TableGen/RegClassByHwMode.td | 18 +++++++++++------- llvm/utils/TableGen/InstrInfoEmitter.cpp | 18 +++++++++++------- 2 files changed, 22 insertions(+), 14 deletions(-) diff --git a/llvm/test/TableGen/RegClassByHwMode.td b/llvm/test/TableGen/RegClassByHwMode.td index 299fe7850e313..5d813d2bfc83a 100644 --- a/llvm/test/TableGen/RegClassByHwMode.td +++ b/llvm/test/TableGen/RegClassByHwMode.td @@ -6,9 +6,13 @@ include "llvm/Target/Target.td" -// INSTRINFO: #if defined(GET_INSTRINFO_MC_DESC) || defined(GET_INSTRINFO_CTOR_DTOR) -// INSTRINFO-NEXT: namespace { -// INSTRINFO-NEXT: enum RegClassByHwModeUses : uint16_t { +// INSTRINFO: #ifdef GET_INSTRINFO_ENUM +// INSTRINFO-NEXT: #undef GET_INSTRINFO_ENUM +// INSTRINFO-NEXT: namespace llvm::MyTarget { +// INSTRINFO-NEXT: enum { +// INSTRINFO-NEXT: PHI +// INSTRINFO: }; +// INSTRINFO: enum RegClassByHwModeUses : uint16_t { // INSTRINFO-NEXT: MyPtrRC, // INSTRINFO-NEXT: XRegs_EvenIfRequired, // INSTRINFO-NEXT: YRegs_EvenIfRequired, @@ -17,10 +21,10 @@ include "llvm/Target/Target.td" // INSTRINFO: { MyTarget::XRegsRegClassID, 0, MCOI::OPERAND_REGISTER, 0 }, // INSTRINFO: { MyTarget::XRegs_EvenRegClassID, 0, MCOI::OPERAND_REGISTER, 0 }, -// INSTRINFO: { YRegs_EvenIfRequired, 0|(1<getValueAsDef("RegClass"); if (OpR->isSubClassOf("RegClassByHwMode")) { + Res += Namespace; + Res += "::"; Res += OpR->getName(); Res += ", "; } else if (OpR->isSubClassOf("RegisterClass")) @@ -934,13 +937,6 @@ void InstrInfoEmitter::run(raw_ostream &OS) { OS << "#if defined(GET_INSTRINFO_MC_DESC) || " "defined(GET_INSTRINFO_CTOR_DTOR)\n"; - OS << "namespace {\n"; - OS << "enum RegClassByHwModeUses : uint16_t {\n"; - for (const Record *ClassByHwMode : Target.getAllRegClassByHwMode()) - OS << " " << ClassByHwMode->getName() << ",\n"; - OS << "};\n"; - OS << "}\n"; - OS << "namespace llvm {\n\n"; OS << "struct " << TargetName << "InstrTable {\n"; @@ -1398,6 +1394,14 @@ void InstrInfoEmitter::emitEnums( } OS << " INSTRUCTION_LIST_END = " << NumberedInstructions.size() << '\n'; OS << " };\n"; + + if (!Target.getAllRegClassByHwMode().empty()) { + OS << " enum RegClassByHwModeUses : uint16_t {\n"; + for (const Record *ClassByHwMode : Target.getAllRegClassByHwMode()) + OS << indent(4) << ClassByHwMode->getName() << ",\n"; + OS << " };\n"; + } + OS << "} // end namespace llvm::" << Namespace << '\n'; OS << "#endif // GET_INSTRINFO_ENUM\n\n"; From 4edfaaa238cd2f1b86bd9de48068181be11d9be9 Mon Sep 17 00:00:00 2001 From: Matt Arsenault Date: Thu, 18 Sep 2025 09:02:39 +0900 Subject: [PATCH 20/28] Another InfoByHwMode structure binding --- llvm/utils/TableGen/Common/InfoByHwMode.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/llvm/utils/TableGen/Common/InfoByHwMode.cpp b/llvm/utils/TableGen/Common/InfoByHwMode.cpp index 6bc5e0e8eae58..a6e2fc415f350 100644 --- a/llvm/utils/TableGen/Common/InfoByHwMode.cpp +++ b/llvm/utils/TableGen/Common/InfoByHwMode.cpp @@ -191,11 +191,11 @@ RegClassByHwMode::RegClassByHwMode(const Record *R, const CodeGenHwModes &CGH, const CodeGenRegBank &RegBank) { const HwModeSelect &MS = CGH.getHwModeSelect(R); - for (const HwModeSelect::PairType &P : MS.Items) { - assert(P.second && P.second->isSubClassOf("RegisterClass") && + for (auto [ModeID, RegClassRec] : MS.Items) { + assert(RegClassRec && RegClassRec->isSubClassOf("RegisterClass") && "Register class must subclass RegisterClass"); - const CodeGenRegisterClass *RegClass = RegBank.getRegClass(P.second); - if (!Map.try_emplace(P.first, RegClass).second) + const CodeGenRegisterClass *RegClass = RegBank.getRegClass(RegClassRec); + if (!Map.try_emplace(ModeID, RegClass).second) llvm_unreachable("duplicate entry"); } } From abff318b79a492fe339ce201208afeaeb179f1a1 Mon Sep 17 00:00:00 2001 From: Matt Arsenault Date: Fri, 19 Sep 2025 14:36:28 +0900 Subject: [PATCH 21/28] Apply suggestions from code review Co-authored-by: Craig Topper --- llvm/include/llvm/Target/Target.td | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/llvm/include/llvm/Target/Target.td b/llvm/include/llvm/Target/Target.td index 82c44d4817322..13175177edd3e 100644 --- a/llvm/include/llvm/Target/Target.td +++ b/llvm/include/llvm/Target/Target.td @@ -929,7 +929,7 @@ class PointerLikeRegClass { } /// RegClassByHwMode - Operands that change the register class based -/// on the subtarget are derived from this derived from this. TableGen +/// on the subtarget are derived from this. TableGen /// treats the register class as having a symbolic kind that it /// doesn't know, and resolves the actual regclass to use by using the /// a mapping in TargetInstrInfo at codegen time. This can be used to From 4722d066879e2aadf24a788d0fdd6cef26c9e383 Mon Sep 17 00:00:00 2001 From: Matt Arsenault Date: Fri, 19 Sep 2025 14:36:46 +0900 Subject: [PATCH 22/28] Update llvm/include/llvm/CodeGen/TargetInstrInfo.h --- llvm/include/llvm/CodeGen/TargetInstrInfo.h | 1 - 1 file changed, 1 deletion(-) diff --git a/llvm/include/llvm/CodeGen/TargetInstrInfo.h b/llvm/include/llvm/CodeGen/TargetInstrInfo.h index e8ffbe31118ee..f2ad5ee249b46 100644 --- a/llvm/include/llvm/CodeGen/TargetInstrInfo.h +++ b/llvm/include/llvm/CodeGen/TargetInstrInfo.h @@ -118,7 +118,6 @@ class LLVM_ABI TargetInstrInfo : public MCInstrInfo { /// MCOperandInfo's RegClass field for LookupRegClassByHwMode operands. const int16_t *const RegClassByHwMode; -public: TargetInstrInfo(unsigned CFSetupOpcode = ~0u, unsigned CFDestroyOpcode = ~0u, unsigned CatchRetOpcode = ~0u, unsigned ReturnOpcode = ~0u, const int16_t *const RegClassByHwModeTable = nullptr) From 8c4a25bb83a91a830df08c497ccf34da53156862 Mon Sep 17 00:00:00 2001 From: Matt Arsenault Date: Fri, 19 Sep 2025 14:51:31 +0900 Subject: [PATCH 23/28] emplace_front returns reference --- llvm/utils/TableGen/AsmMatcherEmitter.cpp | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/llvm/utils/TableGen/AsmMatcherEmitter.cpp b/llvm/utils/TableGen/AsmMatcherEmitter.cpp index 2379d5568224e..e1f2f06d755f1 100644 --- a/llvm/utils/TableGen/AsmMatcherEmitter.cpp +++ b/llvm/utils/TableGen/AsmMatcherEmitter.cpp @@ -1386,20 +1386,19 @@ void AsmMatcherInfo::buildRegisterClasses( unsigned RegClassByHwModeIndex = 0; for (const Record *ClassByHwMode : Target.getAllRegClassByHwMode()) { - Classes.emplace_front(); - ClassInfo *CI = &Classes.front(); - CI->Kind = ClassInfo::RegisterClassByHwMode0 + RegClassByHwModeIndex; + ClassInfo &CI = Classes.emplace_front(); + CI.Kind = ClassInfo::RegisterClassByHwMode0 + RegClassByHwModeIndex; - CI->ClassName = "RegByHwMode_" + ClassByHwMode->getName().str(); - CI->Name = "MCK_" + CI->ClassName; - CI->ValueName = ClassByHwMode->getName(); - CI->RenderMethod = "addRegOperands"; + CI.ClassName = "RegByHwMode_" + ClassByHwMode->getName().str(); + CI.Name = "MCK_" + CI.ClassName; + CI.ValueName = ClassByHwMode->getName(); + CI.RenderMethod = "addRegOperands"; // FIXME: Set diagnostic type. ++RegClassByHwModeIndex; - assert(CI->isRegisterClassByHwMode()); + assert(CI.isRegisterClassByHwMode()); - RegisterClassClasses.try_emplace(ClassByHwMode, CI); + RegisterClassClasses.try_emplace(ClassByHwMode, &CI); } // Populate the map for individual registers. From 8bfcdcc57c39cdb6d65eb079258e68dd99d81321 Mon Sep 17 00:00:00 2001 From: Matt Arsenault Date: Fri, 19 Sep 2025 14:51:42 +0900 Subject: [PATCH 24/28] variable for Target.getAllRegClassByHwMode --- llvm/utils/TableGen/InstrInfoEmitter.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/llvm/utils/TableGen/InstrInfoEmitter.cpp b/llvm/utils/TableGen/InstrInfoEmitter.cpp index a732a75d8183f..176e4b250b82a 100644 --- a/llvm/utils/TableGen/InstrInfoEmitter.cpp +++ b/llvm/utils/TableGen/InstrInfoEmitter.cpp @@ -1395,9 +1395,10 @@ void InstrInfoEmitter::emitEnums( OS << " INSTRUCTION_LIST_END = " << NumberedInstructions.size() << '\n'; OS << " };\n"; - if (!Target.getAllRegClassByHwMode().empty()) { + ArrayRef RegClassesByHwMode = Target.getAllRegClassByHwMode(); + if (!RegClassesByHwMode.empty()) { OS << " enum RegClassByHwModeUses : uint16_t {\n"; - for (const Record *ClassByHwMode : Target.getAllRegClassByHwMode()) + for (const Record *ClassByHwMode : RegClassesByHwMode) OS << indent(4) << ClassByHwMode->getName() << ",\n"; OS << " };\n"; } From 53a024c55b39e827b5a2707c1153305be0445cea Mon Sep 17 00:00:00 2001 From: Matt Arsenault Date: Fri, 19 Sep 2025 18:40:09 +0900 Subject: [PATCH 25/28] assert message --- llvm/include/llvm/MC/MCInstrInfo.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/llvm/include/llvm/MC/MCInstrInfo.h b/llvm/include/llvm/MC/MCInstrInfo.h index 0ceb2d1717510..a0eb27ab700a9 100644 --- a/llvm/include/llvm/MC/MCInstrInfo.h +++ b/llvm/include/llvm/MC/MCInstrInfo.h @@ -69,8 +69,8 @@ class MCInstrInfo { unsigned getNumOpcodes() const { return NumOpcodes; } const int16_t *getRegClassByHwModeTable(unsigned ModeId) const { - assert(RegClassByHwModeTables); - assert(NumRegClassByHwModes != 0); + assert(RegClassByHwModeTables && NumRegClassByHwModes != 0 && + "MCInstrInfo not properly initialized"); return &RegClassByHwModeTables[ModeId * NumRegClassByHwModes]; } From 080dcc65835ef174742d1c554a38f4dfc3512366 Mon Sep 17 00:00:00 2001 From: Matt Arsenault Date: Fri, 19 Sep 2025 18:41:01 +0900 Subject: [PATCH 26/28] whitespace is hard on GitHub --- llvm/include/llvm/MC/MCInstrInfo.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/llvm/include/llvm/MC/MCInstrInfo.h b/llvm/include/llvm/MC/MCInstrInfo.h index a0eb27ab700a9..d5abea6f60ebc 100644 --- a/llvm/include/llvm/MC/MCInstrInfo.h +++ b/llvm/include/llvm/MC/MCInstrInfo.h @@ -70,7 +70,7 @@ class MCInstrInfo { const int16_t *getRegClassByHwModeTable(unsigned ModeId) const { assert(RegClassByHwModeTables && NumRegClassByHwModes != 0 && - "MCInstrInfo not properly initialized"); + "MCInstrInfo not properly initialized"); return &RegClassByHwModeTables[ModeId * NumRegClassByHwModes]; } From d4790716b0f0d3e23f65e16710af774cc87d3519 Mon Sep 17 00:00:00 2001 From: Matt Arsenault Date: Fri, 19 Sep 2025 18:41:27 +0900 Subject: [PATCH 27/28] whitespace --- llvm/include/llvm/MC/MCInstrInfo.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/llvm/include/llvm/MC/MCInstrInfo.h b/llvm/include/llvm/MC/MCInstrInfo.h index d5abea6f60ebc..8e569538bca1e 100644 --- a/llvm/include/llvm/MC/MCInstrInfo.h +++ b/llvm/include/llvm/MC/MCInstrInfo.h @@ -70,7 +70,7 @@ class MCInstrInfo { const int16_t *getRegClassByHwModeTable(unsigned ModeId) const { assert(RegClassByHwModeTables && NumRegClassByHwModes != 0 && - "MCInstrInfo not properly initialized"); + "MCInstrInfo not properly initialized"); return &RegClassByHwModeTables[ModeId * NumRegClassByHwModes]; } From a9006f3c2e8d6e98f7e5780b0bc5eeb327b2468d Mon Sep 17 00:00:00 2001 From: Matt Arsenault Date: Fri, 19 Sep 2025 19:09:55 +0900 Subject: [PATCH 28/28] GitHub whitespace is impossible --- llvm/include/llvm/MC/MCInstrInfo.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/llvm/include/llvm/MC/MCInstrInfo.h b/llvm/include/llvm/MC/MCInstrInfo.h index 8e569538bca1e..97d5e7a52d1a8 100644 --- a/llvm/include/llvm/MC/MCInstrInfo.h +++ b/llvm/include/llvm/MC/MCInstrInfo.h @@ -70,7 +70,7 @@ class MCInstrInfo { const int16_t *getRegClassByHwModeTable(unsigned ModeId) const { assert(RegClassByHwModeTables && NumRegClassByHwModes != 0 && - "MCInstrInfo not properly initialized"); + "MCInstrInfo not properly initialized"); return &RegClassByHwModeTables[ModeId * NumRegClassByHwModes]; }