Skip to content

Commit 6b54c92

Browse files
authored
CodeGen: Add RegisterClass by HwMode (#158269)
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.
1 parent b6231f5 commit 6b54c92

28 files changed

+1066
-113
lines changed

llvm/include/llvm/CodeGen/TargetInstrInfo.h

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -113,9 +113,16 @@ struct ExtAddrMode {
113113
///
114114
class LLVM_ABI TargetInstrInfo : public MCInstrInfo {
115115
protected:
116+
/// Subtarget specific sub-array of MCInstrInfo's RegClassByHwModeTables
117+
/// (i.e. the table for the active HwMode). This should be indexed by
118+
/// MCOperandInfo's RegClass field for LookupRegClassByHwMode operands.
119+
const int16_t *const RegClassByHwMode;
120+
116121
TargetInstrInfo(unsigned CFSetupOpcode = ~0u, unsigned CFDestroyOpcode = ~0u,
117-
unsigned CatchRetOpcode = ~0u, unsigned ReturnOpcode = ~0u)
118-
: CallFrameSetupOpcode(CFSetupOpcode),
122+
unsigned CatchRetOpcode = ~0u, unsigned ReturnOpcode = ~0u,
123+
const int16_t *const RegClassByHwModeTable = nullptr)
124+
: RegClassByHwMode(RegClassByHwModeTable),
125+
CallFrameSetupOpcode(CFSetupOpcode),
119126
CallFrameDestroyOpcode(CFDestroyOpcode), CatchRetOpcode(CatchRetOpcode),
120127
ReturnOpcode(ReturnOpcode) {}
121128

@@ -133,6 +140,18 @@ class LLVM_ABI TargetInstrInfo : public MCInstrInfo {
133140
Opc <= TargetOpcode::GENERIC_ATOMICRMW_OP_END;
134141
}
135142

143+
/// \returns the subtarget appropriate RegClassID for \p OpInfo
144+
///
145+
/// Note this shadows a version of getOpRegClassID in MCInstrInfo which takes
146+
/// an additional argument for the subtarget's HwMode, since TargetInstrInfo
147+
/// is owned by a subtarget in CodeGen but MCInstrInfo is a TargetMachine
148+
/// constant.
149+
int16_t getOpRegClassID(const MCOperandInfo &OpInfo) const {
150+
if (OpInfo.isLookupRegClassByHwMode())
151+
return RegClassByHwMode[OpInfo.RegClass];
152+
return OpInfo.RegClass;
153+
}
154+
136155
/// Given a machine instruction descriptor, returns the register
137156
/// class constraint for OpNum, or NULL.
138157
virtual const TargetRegisterClass *

llvm/include/llvm/MC/MCInstrDesc.h

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ enum OperandConstraint {
5050
/// See the accessors for a description of what these are.
5151
enum OperandFlags {
5252
LookupPtrRegClass = 0,
53+
LookupRegClassByHwMode,
5354
Predicate,
5455
OptionalDef,
5556
BranchTarget
@@ -85,10 +86,13 @@ enum OperandType {
8586
/// indicating the register class for register operands, etc.
8687
class MCOperandInfo {
8788
public:
88-
/// This specifies the register class enumeration of the operand
89-
/// if the operand is a register. If isLookupPtrRegClass is set, then this is
90-
/// an index that is passed to TargetRegisterInfo::getPointerRegClass(x) to
91-
/// get a dynamic register class.
89+
/// This specifies the register class enumeration of the operand if the
90+
/// operand is a register. If LookupRegClassByHwMode is set, then this is an
91+
/// index into a table in TargetInstrInfo or MCInstrInfo which contains the
92+
/// real register class ID.
93+
///
94+
/// If isLookupPtrRegClass is set, then this is an index that is passed to
95+
/// TargetRegisterInfo::getPointerRegClass(x) to get a dynamic register class.
9296
int16_t RegClass;
9397

9498
/// These are flags from the MCOI::OperandFlags enum.
@@ -102,10 +106,17 @@ class MCOperandInfo {
102106

103107
/// Set if this operand is a pointer value and it requires a callback
104108
/// to look up its register class.
109+
// TODO: Deprecated in favor of isLookupRegClassByHwMode
105110
bool isLookupPtrRegClass() const {
106111
return Flags & (1 << MCOI::LookupPtrRegClass);
107112
}
108113

114+
/// Set if this operand is a value that requires the current hwmode to look up
115+
/// its register class.
116+
bool isLookupRegClassByHwMode() const {
117+
return Flags & (1 << MCOI::LookupRegClassByHwMode);
118+
}
119+
109120
/// Set if this is one of the operands that made up of the predicate
110121
/// operand that controls an isPredicable() instruction.
111122
bool isPredicate() const { return Flags & (1 << MCOI::Predicate); }

llvm/include/llvm/MC/MCInstrInfo.h

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,22 +43,48 @@ class MCInstrInfo {
4343
const ComplexDeprecationPredicate *ComplexDeprecationInfos;
4444
unsigned NumOpcodes; // Number of entries in the desc array
4545

46+
protected:
47+
// Pointer to 2d array [NumHwModes][NumRegClassByHwModes]
48+
const int16_t *RegClassByHwModeTables;
49+
int16_t NumRegClassByHwModes;
50+
4651
public:
4752
/// Initialize MCInstrInfo, called by TableGen auto-generated routines.
4853
/// *DO NOT USE*.
4954
void InitMCInstrInfo(const MCInstrDesc *D, const unsigned *NI, const char *ND,
5055
const uint8_t *DF,
51-
const ComplexDeprecationPredicate *CDI, unsigned NO) {
56+
const ComplexDeprecationPredicate *CDI, unsigned NO,
57+
const int16_t *RCHWTables = nullptr,
58+
int16_t NumRegClassByHwMode = 0) {
5259
LastDesc = D + NO - 1;
5360
InstrNameIndices = NI;
5461
InstrNameData = ND;
5562
DeprecatedFeatures = DF;
5663
ComplexDeprecationInfos = CDI;
5764
NumOpcodes = NO;
65+
RegClassByHwModeTables = RCHWTables;
66+
NumRegClassByHwModes = NumRegClassByHwMode;
5867
}
5968

6069
unsigned getNumOpcodes() const { return NumOpcodes; }
6170

71+
const int16_t *getRegClassByHwModeTable(unsigned ModeId) const {
72+
assert(RegClassByHwModeTables && NumRegClassByHwModes != 0 &&
73+
"MCInstrInfo not properly initialized");
74+
return &RegClassByHwModeTables[ModeId * NumRegClassByHwModes];
75+
}
76+
77+
/// Return the ID of the register class to use for \p OpInfo, for the active
78+
/// HwMode \p HwModeId. In general TargetInstrInfo's version which is already
79+
/// specialized to the subtarget should be used.
80+
int16_t getOpRegClassID(const MCOperandInfo &OpInfo,
81+
unsigned HwModeId) const {
82+
int16_t RegClass = OpInfo.RegClass;
83+
if (OpInfo.isLookupRegClassByHwMode())
84+
RegClass = getRegClassByHwModeTable(HwModeId)[RegClass];
85+
return RegClass;
86+
}
87+
6288
/// Return the machine instruction descriptor that corresponds to the
6389
/// specified instruction opcode.
6490
const MCInstrDesc &get(unsigned Opcode) const {

llvm/include/llvm/MC/MCSubtargetInfo.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -255,10 +255,10 @@ class LLVM_ABI MCSubtargetInfo {
255255
/// this method also supports controlling multiple attributes with a single
256256
/// HwMode ID, just as was done previously.
257257
enum HwModeType {
258-
HwMode_Default, // Return the smallest HwMode ID of current subtarget.
259-
HwMode_ValueType, // Return the HwMode ID that controls the ValueType.
260-
HwMode_RegInfo, // Return the HwMode ID that controls the RegSizeInfo and
261-
// SubRegRange.
258+
HwMode_Default, // Return the smallest HwMode ID of current subtarget.
259+
HwMode_ValueType, // Return the HwMode ID that controls the ValueType.
260+
HwMode_RegInfo, // Return the HwMode ID that controls the RegSizeInfo,
261+
// SubRegRange, and RegisterClass.
262262
HwMode_EncodingInfo // Return the HwMode ID that controls the EncodingInfo.
263263
};
264264

llvm/include/llvm/Target/Target.td

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -258,14 +258,20 @@ class DAGOperand {
258258
bit hasCompleteDecoder = true;
259259
}
260260

261+
/// Abstract base class common to RegisterClass and
262+
/// RegClassByHwMode. This permits using RegClassByHwMode in
263+
/// RegisterOperand contexts without creating an artificial
264+
/// RegisterClass.
265+
class RegisterClassLike : DAGOperand;
266+
261267
// RegisterClass - Now that all of the registers are defined, and aliases
262268
// between registers are defined, specify which registers belong to which
263269
// register classes. This also defines the default allocation order of
264270
// registers by register allocators.
265271
//
266272
class RegisterClass<string namespace, list<ValueType> regTypes, int alignment,
267273
dag regList, RegAltNameIndex idx = NoRegAltName>
268-
: DAGOperand {
274+
: RegisterClassLike {
269275
string Namespace = namespace;
270276

271277
// The register size/alignment information, parameterized by a HW mode.
@@ -916,15 +922,30 @@ def decoder;
916922
/// derived from this. TableGen treats the register class as having a symbolic
917923
/// type that it doesn't know, and resolves the actual regclass to use by using
918924
/// the TargetRegisterInfo::getPointerRegClass() hook at codegen time.
925+
///
926+
/// This is deprecated in favor of RegClassByHwMode.
919927
class PointerLikeRegClass<int Kind> {
920928
int RegClassKind = Kind;
921929
}
922930

931+
/// RegClassByHwMode - Operands that change the register class based
932+
/// on the subtarget are derived from this. TableGen
933+
/// treats the register class as having a symbolic kind that it
934+
/// doesn't know, and resolves the actual regclass to use by using the
935+
/// a mapping in TargetInstrInfo at codegen time. This can be used to
936+
/// define operands which swap the register class with the pointer
937+
/// type.
938+
class RegClassByHwMode<list<HwMode> Modes,
939+
list<RegisterClass> RegClasses>
940+
: HwModeSelect<Modes, !size(RegClasses)>, RegisterClassLike {
941+
list<RegisterClass> Objects = RegClasses;
942+
}
923943

924944
/// ptr_rc definition - Mark this operand as being a pointer value whose
925945
/// register class is resolved dynamically via a callback to TargetInstrInfo.
926946
/// FIXME: We should probably change this to a class which contain a list of
927947
/// flags. But currently we have but one flag.
948+
// Deprecated, use RegClassByHwMode instead.
928949
def ptr_rc : PointerLikeRegClass<0>;
929950

930951
/// unknown definition - Mark this operand as being of unknown type, causing
@@ -1024,10 +1045,10 @@ class Operand<ValueType ty> : DAGOperand {
10241045
AsmOperandClass ParserMatchClass = ImmAsmOperand;
10251046
}
10261047

1027-
class RegisterOperand<RegisterClass regclass, string pm = "printOperand">
1048+
class RegisterOperand<RegisterClassLike regclass, string pm = "printOperand">
10281049
: DAGOperand {
10291050
// RegClass - The register class of the operand.
1030-
RegisterClass RegClass = regclass;
1051+
RegisterClassLike RegClass = regclass;
10311052
// PrintMethod - The target method to call to print register operands of
10321053
// this type. The method normally will just use an alt-name index to look
10331054
// up the name to print. Default to the generic printOperand().

llvm/lib/CodeGen/TargetInstrInfo.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,8 +64,11 @@ TargetInstrInfo::getRegClass(const MCInstrDesc &MCID, unsigned OpNum,
6464
if (OpNum >= MCID.getNumOperands())
6565
return nullptr;
6666

67-
short RegClass = MCID.operands()[OpNum].RegClass;
68-
if (MCID.operands()[OpNum].isLookupPtrRegClass())
67+
const MCOperandInfo &OpInfo = MCID.operands()[OpNum];
68+
int16_t RegClass = getOpRegClassID(OpInfo);
69+
70+
// TODO: Remove isLookupPtrRegClass in favor of isLookupRegClassByHwMode
71+
if (OpInfo.isLookupPtrRegClass())
6972
return TRI->getPointerRegClass(RegClass);
7073

7174
// Instructions like INSERT_SUBREG do not have fixed register classes.

llvm/lib/Target/AMDGPU/BUFInstructions.td

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -411,11 +411,16 @@ class getBUFVDataRegisterOperand<int Size, bit isTFE> {
411411
RegisterOperand ret = !if(isTFE, tfeVDataOp, VDataOp);
412412
}
413413

414+
class getBUFVDataRegisterOperandForOp<RegisterOperand Op, bit isTFE> {
415+
defvar Size = !cast<RegisterClass>(Op.RegClass).Size;
416+
RegisterOperand ret = getBUFVDataRegisterOperand<Size, isTFE>.ret;
417+
}
418+
414419
class getMUBUFInsDA<list<RegisterOperand> vdataList,
415420
list<RegisterClass> vaddrList, bit isTFE, bit hasRestrictedSOffset> {
416421
RegisterOperand vdataClass = !if(!empty(vdataList), ?, !head(vdataList));
417422
RegisterClass vaddrClass = !if(!empty(vaddrList), ?, !head(vaddrList));
418-
RegisterOperand vdata_op = getBUFVDataRegisterOperand<vdataClass.RegClass.Size, isTFE>.ret;
423+
RegisterOperand vdata_op = getBUFVDataRegisterOperandForOp<vdataClass, isTFE>.ret;
419424

420425
dag SOffset = !if(hasRestrictedSOffset, (ins SReg_32:$soffset), (ins SCSrc_b32:$soffset));
421426
dag NonVaddrInputs = !con((ins SReg_128_XNULL:$srsrc), SOffset, (ins Offset:$offset, CPol_0:$cpol, i1imm_0:$swz));

llvm/lib/Target/AMDGPU/SIInstrFormats.td

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -321,7 +321,7 @@ def CPolBit {
321321
int SCAL = 11;
322322
}
323323

324-
class VOPDstOperand <RegisterClass rc> : RegisterOperand <rc, "printVOPDst">;
324+
class VOPDstOperand<RegisterClassLike rc> : RegisterOperand<rc, "printVOPDst">;
325325

326326
def VOPDstOperand_t16 : VOPDstOperand <VGPR_16> {
327327
let EncoderMethod = "getMachineOpValueT16";

llvm/lib/Target/AMDGPU/SIInstrInfo.td

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2636,7 +2636,7 @@ class getAlign2RegOp<RegisterOperand RC> {
26362636
}
26372637

26382638
class getEquivalentAGPROperand<RegisterOperand RC> {
2639-
defvar Size = RC.RegClass.Size;
2639+
defvar Size = !cast<RegisterClass>(RC.RegClass).Size;
26402640
RegisterOperand ret =
26412641
!cond(!eq(Size, 32) : RegisterOperand<AGPR_32>,
26422642
!eq(Size, 64) : RegisterOperand<AReg_64>,
@@ -2647,7 +2647,7 @@ class getEquivalentAGPROperand<RegisterOperand RC> {
26472647
}
26482648

26492649
class getEquivalentVGPROperand<RegisterOperand RC> {
2650-
defvar Size = RC.RegClass.Size;
2650+
defvar Size = !cast<RegisterClass>(RC.RegClass).Size;
26512651
RegisterOperand ret =
26522652
!cond(!eq(Size, 32) : RegisterOperand<VGPR_32>,
26532653
!eq(Size, 64) : RegisterOperand<VReg_64>,

llvm/lib/Target/AVR/AsmParser/AVRAsmParser.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -764,7 +764,7 @@ unsigned AVRAsmParser::validateTargetOperandClass(MCParsedAsmOperand &AsmOp,
764764
RegName << "r" << RegNum;
765765
if (MCRegister Reg = MatchRegisterName(RegName.str())) {
766766
Op.makeReg(Reg);
767-
if (validateOperandClass(Op, Expected) == Match_Success) {
767+
if (validateOperandClass(Op, Expected, *STI) == Match_Success) {
768768
return Match_Success;
769769
}
770770
}
@@ -780,7 +780,7 @@ unsigned AVRAsmParser::validateTargetOperandClass(MCParsedAsmOperand &AsmOp,
780780

781781
if (correspondingDREG) {
782782
Op.makeReg(correspondingDREG);
783-
return validateOperandClass(Op, Expected);
783+
return validateOperandClass(Op, Expected, *STI);
784784
}
785785
}
786786
}

0 commit comments

Comments
 (0)