-
Notifications
You must be signed in to change notification settings - Fork 15.2k
CodeGen: Add RegisterClass by HwMode #158269
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
CodeGen: Add RegisterClass by HwMode #158269
Conversation
This stack of pull requests is managed by Graphite. Learn more about stacking. |
@llvm/pr-subscribers-llvm-mc @llvm/pr-subscribers-backend-systemz Author: Matt Arsenault (arsenm) ChangesThis is a generalization of the LookupPtrRegClass mechanism. The current system requires manual management of an arbitrary integer This just introduces the base infrastructure. I have ports of all Patch is 82.14 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/158269.diff 25 Files Affected:
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 6a7ecf78b2131..13d715582be0d 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<string namespace, list<ValueType> 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 Kind> {
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<list<HwMode> Modes,
+ list<RegisterClass> RegClasses> :
+ HwModeSelect<Modes, !size(RegClasses)>, RegisterClassLike {
+ list<RegisterClass> 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<ValueType ty> : DAGOperand {
AsmOperandClass ParserMatchClass = ImmAsmOperand;
}
-class RegisterOperand<RegisterClass regclass, string pm = "printOperand">
+class RegisterOperand<RegisterClassLike regclass, string pm = "printOperand">
: 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<int Size, bit isTFE> {
RegisterOperand ret = !if(isTFE, tfeVDataOp, VDataOp);
}
+class getBUFVDataRegisterOperandForOp<RegisterOperand Op, bit isTFE> {
+ defvar Size = !cast<RegisterClass>(Op.RegClass).Size;
+ RegisterOperand ret = getBUFVDataRegisterOperand<Size, isTFE>.ret;
+}
+
class getMUBUFInsDA<list<RegisterOperand> vdataList,
list<RegisterClass> vaddrList, bit isTFE, bit hasRestrictedSOffset> {
RegisterOperand vdataClass = !if(!empty(vdataList), ?, !head(vdataList));
RegisterClass vaddrClass = !if(!empty(vaddrList), ?, !head(vaddrList));
- RegisterOperand vdata_op = getBUFVDataRegisterOperand<vdataClass.RegClass.Size, isTFE>.ret;
+ RegisterOperand vdata_op = getBUFVDataRegisterOperandForOp<vdataClass, isTFE>.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 <RegisterClass rc> : RegisterOperand <rc, "printVOPDst">;
+class VOPDstOperand<RegisterClassLike rc> : RegisterOperand<rc, "printVOPDst">;
def VOPDstOperand_t16 : VOPDstOperand <VGPR_16> {
let EncoderMethod = "getMachineOpValueT16";
diff --git a/llvm/lib/Target/AMDGPU/SIInstrInfo.td b/llvm/lib/Target/AMDGPU/SIInstrInfo.td
index c8231b470abae..e3c71d211faa0 100644
--- a/llvm/lib/Target/AMDGPU/SIInstrInfo.td
+++ b/llvm/lib/Target/AMDGPU/SIInstrInfo.td
@@ -2635,7 +2635,7 @@ class getAlign2RegOp<RegisterOperand RC> {
}
class getEquivalentAGPROperand<RegisterOperand RC> {
- defvar Size = RC.RegClass.Size;
+ defvar Size = !cast<RegisterClass>(RC.RegClass).Size;
RegisterOperand ret =
!cond(!eq(Size, 32) : RegisterOperand<AGPR_32>,
!eq(Size, 64) : RegisterOperand<AReg_64>,
@@ -2646,7 +2646,7 @@ class getEquivalentAGPROperand<RegisterOperand RC> {
}
class getEquivalentVGPROperand<RegisterOperand RC> {
- defvar Size = RC.RegClass.Size;
+ defvar Size = !cast<RegisterClass>(RC.RegClass).Size;
RegisterOperand ret =
!cond(!eq(Size, 32) : RegisterOperand<VGPR_32>,
!eq(Size, 64) : RegisterOperand<VReg_64>,
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<<MCOI::LookupRegClassByHwMode), MCOI::OPERAND_REGISTER, 0 },
+// INSTRINFO: { XRegs_EvenIfRequired, 0|(1<<MCOI::LookupRegClassByHwMode), MCOI::OPERAND_REGISTER, 0 },
+// INSTRINFO: { XRegs_EvenIfRequired, 0|(1<<MCOI::LookupRegClassByHwMode), MCOI::OPERAND_REGISTER, 0 }, { MyPtrRC, 0|(1<<MCOI::LookupRegClassByHwMode), MCOI::OPERAND_UNKNOWN, 0 },
+// INSTRINFO: { YRegs_EvenIfRequired, 0|(1<<MCOI::LookupRegClassByHwMode), MCOI::OPERAND_REGISTER, 0 }, { XRegs_EvenIfRequired, 0|(1<<MCOI::LookupRegClassByHwMode), MCOI::OPERAND_REGISTER, 0 },
+
+
+
+// ASMMATCHER: enum MatchClassKind {
+// ASMMATCHER: MCK_LAST_TOKEN = OptionalMatchClass,
+// ASMMATCHER-NEXT: MCK_XRegs_Odd, // register class 'XRegs_Odd'
+// ASMMATCHER-NEXT: MCK_PtrRegs32, // register class 'PtrRegs32'
+// ASMMATCHER-NEXT: MCK_PtrRegs64, // register class 'PtrRegs64'
+// ASMMATCHER-NEXT: MCK_XRegs_Even, // register class 'XRegs_Even'
+// ASMMATCHER-NEXT: MCK_YRegs_Even, // register class 'YRegs_Even'
+// ASMMATCHER-NEXT: MCK_XRegs, // register class 'XRegs'
+// ASMMATCHER-NEXT: MCK_YRegs, // register class 'YRegs'
+// ASMMATCHER-NEXT: MCK_LAST_REGISTER = MCK_YRegs,
+// ASMMATCHER-NEXT: MCK_RegByHwMode_MyPtrRC, // register class by hwmode
+// ASMMATCHER-NEXT: MCK_RegByHwMode_XRegs_EvenIfRequired, // register class by hwmode
+// ASMMATCHER-NEXT: MCK_RegByHwMode_YRegs_EvenIfRequired, // register class by hwmode
+// ASMMATCHER-NEXT: MCK_LAST_REGCLASS_BY_HWMODE = MCK_RegByHwMode_YRegs_EvenIfRequired,
+// ASMMATCHER-NEXT: MCK_Imm, // user defined class 'ImmAsmOperand'
+
+// ASMMATCHER: static unsigned validateOperandClass(MCParsedAsmOperand &GOp, MatchClassKind Kind, const MCSubtargetInfo &STI) {
+// ASMMATCHER: if (Operand.isToken() && Kind <= MCK_LAST_TOKEN)
+
+// ASMMATCHER: switch (Kind) {
+
+// ASMMATCHER: if (Operand.isReg() && Kind > 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 }...
[truncated]
|
@llvm/pr-subscribers-backend-amdgpu Author: Matt Arsenault (arsenm) ChangesThis is a generalization of the LookupPtrRegClass mechanism. The current system requires manual management of an arbitrary integer This just introduces the base infrastructure. I have ports of all Patch is 82.14 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/158269.diff 25 Files Affected:
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 6a7ecf78b2131..13d715582be0d 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<string namespace, list<ValueType> 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 Kind> {
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<list<HwMode> Modes,
+ list<RegisterClass> RegClasses> :
+ HwModeSelect<Modes, !size(RegClasses)>, RegisterClassLike {
+ list<RegisterClass> 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<ValueType ty> : DAGOperand {
AsmOperandClass ParserMatchClass = ImmAsmOperand;
}
-class RegisterOperand<RegisterClass regclass, string pm = "printOperand">
+class RegisterOperand<RegisterClassLike regclass, string pm = "printOperand">
: 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<int Size, bit isTFE> {
RegisterOperand ret = !if(isTFE, tfeVDataOp, VDataOp);
}
+class getBUFVDataRegisterOperandForOp<RegisterOperand Op, bit isTFE> {
+ defvar Size = !cast<RegisterClass>(Op.RegClass).Size;
+ RegisterOperand ret = getBUFVDataRegisterOperand<Size, isTFE>.ret;
+}
+
class getMUBUFInsDA<list<RegisterOperand> vdataList,
list<RegisterClass> vaddrList, bit isTFE, bit hasRestrictedSOffset> {
RegisterOperand vdataClass = !if(!empty(vdataList), ?, !head(vdataList));
RegisterClass vaddrClass = !if(!empty(vaddrList), ?, !head(vaddrList));
- RegisterOperand vdata_op = getBUFVDataRegisterOperand<vdataClass.RegClass.Size, isTFE>.ret;
+ RegisterOperand vdata_op = getBUFVDataRegisterOperandForOp<vdataClass, isTFE>.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 <RegisterClass rc> : RegisterOperand <rc, "printVOPDst">;
+class VOPDstOperand<RegisterClassLike rc> : RegisterOperand<rc, "printVOPDst">;
def VOPDstOperand_t16 : VOPDstOperand <VGPR_16> {
let EncoderMethod = "getMachineOpValueT16";
diff --git a/llvm/lib/Target/AMDGPU/SIInstrInfo.td b/llvm/lib/Target/AMDGPU/SIInstrInfo.td
index c8231b470abae..e3c71d211faa0 100644
--- a/llvm/lib/Target/AMDGPU/SIInstrInfo.td
+++ b/llvm/lib/Target/AMDGPU/SIInstrInfo.td
@@ -2635,7 +2635,7 @@ class getAlign2RegOp<RegisterOperand RC> {
}
class getEquivalentAGPROperand<RegisterOperand RC> {
- defvar Size = RC.RegClass.Size;
+ defvar Size = !cast<RegisterClass>(RC.RegClass).Size;
RegisterOperand ret =
!cond(!eq(Size, 32) : RegisterOperand<AGPR_32>,
!eq(Size, 64) : RegisterOperand<AReg_64>,
@@ -2646,7 +2646,7 @@ class getEquivalentAGPROperand<RegisterOperand RC> {
}
class getEquivalentVGPROperand<RegisterOperand RC> {
- defvar Size = RC.RegClass.Size;
+ defvar Size = !cast<RegisterClass>(RC.RegClass).Size;
RegisterOperand ret =
!cond(!eq(Size, 32) : RegisterOperand<VGPR_32>,
!eq(Size, 64) : RegisterOperand<VReg_64>,
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<<MCOI::LookupRegClassByHwMode), MCOI::OPERAND_REGISTER, 0 },
+// INSTRINFO: { XRegs_EvenIfRequired, 0|(1<<MCOI::LookupRegClassByHwMode), MCOI::OPERAND_REGISTER, 0 },
+// INSTRINFO: { XRegs_EvenIfRequired, 0|(1<<MCOI::LookupRegClassByHwMode), MCOI::OPERAND_REGISTER, 0 }, { MyPtrRC, 0|(1<<MCOI::LookupRegClassByHwMode), MCOI::OPERAND_UNKNOWN, 0 },
+// INSTRINFO: { YRegs_EvenIfRequired, 0|(1<<MCOI::LookupRegClassByHwMode), MCOI::OPERAND_REGISTER, 0 }, { XRegs_EvenIfRequired, 0|(1<<MCOI::LookupRegClassByHwMode), MCOI::OPERAND_REGISTER, 0 },
+
+
+
+// ASMMATCHER: enum MatchClassKind {
+// ASMMATCHER: MCK_LAST_TOKEN = OptionalMatchClass,
+// ASMMATCHER-NEXT: MCK_XRegs_Odd, // register class 'XRegs_Odd'
+// ASMMATCHER-NEXT: MCK_PtrRegs32, // register class 'PtrRegs32'
+// ASMMATCHER-NEXT: MCK_PtrRegs64, // register class 'PtrRegs64'
+// ASMMATCHER-NEXT: MCK_XRegs_Even, // register class 'XRegs_Even'
+// ASMMATCHER-NEXT: MCK_YRegs_Even, // register class 'YRegs_Even'
+// ASMMATCHER-NEXT: MCK_XRegs, // register class 'XRegs'
+// ASMMATCHER-NEXT: MCK_YRegs, // register class 'YRegs'
+// ASMMATCHER-NEXT: MCK_LAST_REGISTER = MCK_YRegs,
+// ASMMATCHER-NEXT: MCK_RegByHwMode_MyPtrRC, // register class by hwmode
+// ASMMATCHER-NEXT: MCK_RegByHwMode_XRegs_EvenIfRequired, // register class by hwmode
+// ASMMATCHER-NEXT: MCK_RegByHwMode_YRegs_EvenIfRequired, // register class by hwmode
+// ASMMATCHER-NEXT: MCK_LAST_REGCLASS_BY_HWMODE = MCK_RegByHwMode_YRegs_EvenIfRequired,
+// ASMMATCHER-NEXT: MCK_Imm, // user defined class 'ImmAsmOperand'
+
+// ASMMATCHER: static unsigned validateOperandClass(MCParsedAsmOperand &GOp, MatchClassKind Kind, const MCSubtargetInfo &STI) {
+// ASMMATCHER: if (Operand.isToken() && Kind <= MCK_LAST_TOKEN)
+
+// ASMMATCHER: switch (Kind) {
+
+// ASMMATCHER: if (Operand.isReg() && Kind > 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 }...
[truncated]
|
Co-authored-by: Craig Topper <craig.topper@sifive.com>
da6fc27
to
8bfcdcc
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
a couple of trivial minors
✅ With the latest revision this PR passed the C/C++ code formatter. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
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.