Skip to content

Commit 7afc442

Browse files
authored
[TableGen][GISel] Add PtrValueTypeByHwMode to be able to vary … (llvm#67501)
…the size of a pointer by HwMode. This adds an equivalent of PtrValueType that can use a ValueTypeByHwMode. This allows the size of a pointer to vary based on HwMode. This is needed for RISC-V to support XLen sized pointers.
1 parent 31e01e9 commit 7afc442

File tree

3 files changed

+222
-0
lines changed

3 files changed

+222
-0
lines changed

llvm/include/llvm/Target/Target.td

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,16 @@ class ValueTypeByHwMode<list<HwMode> Ms, list<ValueType> Ts>
5858
list<ValueType> Objects = Ts;
5959
}
6060

61+
// A class that implements a counterpart of PtrValueType, which is
62+
// dependent on a HW mode. This class inherits from PtrValueType itself,
63+
// which makes it possible to use objects of this class where PtrValueType
64+
// or ValueType could be used. This is specifically applicable to selection
65+
// patterns.
66+
class PtrValueTypeByHwMode<ValueTypeByHwMode scalar, int addrspace>
67+
: HwModeSelect<scalar.Modes>, PtrValueType<ValueType<0, 0>, addrspace> {
68+
list<ValueType> Objects = scalar.Objects;
69+
}
70+
6171
// A class representing the register size, spill size and spill alignment
6272
// in bits of a register.
6373
class RegInfo<int RS, int SS, int SA> {
Lines changed: 210 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,210 @@
1+
// RUN: llvm-tblgen -gen-global-isel -I %p/../../include -I %p/Common -optimize-match-table=false %s -o %T/hwmode-non-optimized.cpp
2+
// RUN: FileCheck %s --check-prefixes=CHECK -input-file=%T/hwmode-non-optimized.cpp
3+
4+
include "llvm/Target/Target.td"
5+
6+
def MyTargetISA : InstrInfo;
7+
def MyTarget : Target { let InstructionSet = MyTargetISA; }
8+
9+
class MyTargetGenericInstruction : GenericInstruction {
10+
let Namespace = "MyTarget";
11+
}
12+
13+
//def Has32 : Predicate<"Subtarget->has32()">;
14+
def Has64 : Predicate<"Subtarget->has64()">;
15+
16+
//def Mode32 : HwMode<"+a", [Has32]>;
17+
def Mode64 : HwMode<"+b", [Has64]>;
18+
19+
def ModeVT : ValueTypeByHwMode<[DefaultMode, Mode64],
20+
[i32, i64]>;
21+
def ModeRI : RegInfoByHwMode<
22+
[DefaultMode, Mode64],
23+
[RegInfo<32,32,32>, RegInfo<64,64,64>]>;
24+
25+
def R0 : Register<"r0"> { let Namespace = "MyTarget"; }
26+
def GPR : RegisterClass<"MyTarget", [ModeVT], 32, (add R0)> {
27+
let RegInfos = ModeRI;
28+
}
29+
30+
def p0 : PtrValueTypeByHwMode<ModeVT, 0>;
31+
32+
class I<dag OOps, dag IOps, list<dag> Pat>
33+
: Instruction {
34+
let Namespace = "MyTarget";
35+
let OutOperandList = OOps;
36+
let InOperandList = IOps;
37+
let Pattern = Pat;
38+
}
39+
40+
//===- Test the function boilerplate. -------------------------------------===//
41+
42+
// CHECK: const unsigned MAX_SUBTARGET_PREDICATES = 2;
43+
// CHECK: using PredicateBitset = llvm::Bitset<MAX_SUBTARGET_PREDICATES>;
44+
45+
// CHECK-LABEL: #ifdef GET_GLOBALISEL_TEMPORARIES_DECL
46+
// CHECK-NEXT: mutable MatcherState State;
47+
// CHECK-NEXT: typedef ComplexRendererFns(MyTargetInstructionSelector::*ComplexMatcherMemFn)(MachineOperand &) const;
48+
// CHECK-NEXT: typedef void(MyTargetInstructionSelector::*CustomRendererFn)(MachineInstrBuilder &, const MachineInstr &, int) const;
49+
// CHECK-NEXT: const ExecInfoTy<PredicateBitset, ComplexMatcherMemFn, CustomRendererFn> ExecInfo;
50+
// CHECK-NEXT: static MyTargetInstructionSelector::ComplexMatcherMemFn ComplexPredicateFns[];
51+
// CHECK-NEXT: static MyTargetInstructionSelector::CustomRendererFn CustomRenderers[];
52+
// CHECK-NEXT: bool testImmPredicate_I64(unsigned PredicateID, int64_t Imm) const override;
53+
// CHECK-NEXT: bool testImmPredicate_APInt(unsigned PredicateID, const APInt &Imm) const override;
54+
// CHECK-NEXT: bool testImmPredicate_APFloat(unsigned PredicateID, const APFloat &Imm) const override;
55+
// CHECK-NEXT: const int64_t *getMatchTable() const override;
56+
// CHECK-NEXT: bool testMIPredicate_MI(unsigned PredicateID, const MachineInstr &MI, const MatcherState &State) const override;
57+
// CHECK-NEXT: bool testSimplePredicate(unsigned PredicateID) const override;
58+
// CHECK-NEXT: void runCustomAction(unsigned FnID, const MatcherState &State, NewMIVector &OutMIs) const override;
59+
// CHECK-NEXT: #endif // ifdef GET_GLOBALISEL_TEMPORARIES_DECL
60+
61+
// CHECK-LABEL: #ifdef GET_GLOBALISEL_TEMPORARIES_INIT
62+
// CHECK-NEXT: , State(0),
63+
// CHECK-NEXT: ExecInfo(TypeObjects, NumTypeObjects, FeatureBitsets, ComplexPredicateFns, CustomRenderers)
64+
// CHECK-NEXT: #endif // ifdef GET_GLOBALISEL_TEMPORARIES_INIT
65+
66+
// CHECK-LABEL: // LLT Objects.
67+
// CHECK-NEXT: enum {
68+
// CHECK-NEXT: GILLT_p0s32,
69+
// CHECK-NEXT: GILLT_p0s64,
70+
// CHECK-NEXT: GILLT_s32,
71+
// CHECK-NEXT: GILLT_s64,
72+
// CHECK-NEXT: }
73+
// CHECK-NEXT: const static size_t NumTypeObjects = 4;
74+
// CHECK-NEXT: const static LLT TypeObjects[] = {
75+
// CHECK-NEXT: LLT::pointer(0, 32),
76+
// CHECK-NEXT: LLT::pointer(0, 64),
77+
// CHECK-NEXT: LLT::scalar(32),
78+
// CHECK-NEXT: LLT::scalar(64),
79+
// CHECK-NEXT: };
80+
81+
// CHECK-LABEL: enum SubtargetFeatureBits : uint8_t {
82+
// CHECK-NEXT: Feature_HwMode1Bit = 1,
83+
// CHECK-NEXT: Feature_HwMode0Bit = 0,
84+
// CHECK-NEXT: };
85+
86+
// CHECK-LABEL: PredicateBitset MyTargetInstructionSelector::
87+
// CHECK-NEXT: computeAvailableModuleFeatures(const MyTargetSubtarget *Subtarget) const {
88+
// CHECK-NEXT: PredicateBitset Features;
89+
// CHECK-NEXT: if (!((Subtarget->has64())))
90+
// CHECK-NEXT: Features.set(Feature_HwMode1Bit);
91+
// CHECK-NEXT: if ((Subtarget->has64()))
92+
// CHECK-NEXT: Features.set(Feature_HwMode0Bit);
93+
// CHECK-NEXT: return Features;
94+
// CHECK-NEXT: }
95+
96+
// CHECK-LABEL: PredicateBitset MyTargetInstructionSelector::
97+
// CHECK-NEXT: computeAvailableFunctionFeatures(const MyTargetSubtarget *Subtarget, const MachineFunction *MF) const {
98+
// CHECK-NEXT: PredicateBitset Features;
99+
// CHECK-NEXT: return Features;
100+
// CHECK-NEXT: }
101+
102+
// CHECK-LABEL: // Feature bitsets.
103+
// CHECK-NEXT: enum {
104+
// CHECK-NEXT: GIFBS_Invalid,
105+
// CHECK-NEXT: GIFBS_HwMode0,
106+
// CHECK-NEXT: GIFBS_HwMode1,
107+
// CHECK-NEXT: }
108+
// CHECK-NEXT: constexpr static PredicateBitset FeatureBitsets[] {
109+
// CHECK-NEXT: {}, // GIFBS_Invalid
110+
// CHECK-NEXT: {Feature_HwMode0Bit, },
111+
// CHECK-NEXT: {Feature_HwMode1Bit, },
112+
// CHECK-NEXT: };
113+
114+
// CHECK: bool MyTargetInstructionSelector::selectImpl(MachineInstr &I, CodeGenCoverage &CoverageInfo) const {
115+
// CHECK-NEXT: const PredicateBitset AvailableFeatures = getAvailableFeatures();
116+
// CHECK-NEXT: NewMIVector OutMIs;
117+
// CHECK-NEXT: State.MIs.clear();
118+
// CHECK-NEXT: State.MIs.push_back(&I);
119+
120+
// CHECK: if (executeMatchTable(*this, OutMIs, State, ExecInfo, getMatchTable(), TII, MF->getRegInfo(), TRI, RBI, AvailableFeatures, &CoverageInfo)) {
121+
// CHECK-NEXT: return true;
122+
// CHECK-NEXT: }
123+
124+
// CHECK: const int64_t *
125+
// CHECK-LABEL: MyTargetInstructionSelector::getMatchTable() const {
126+
// CHECK-NEXT: MatchTable0[] = {
127+
128+
//===- Test a simple pattern with inferred pointer operands. ---------------===//
129+
130+
// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label [[LABEL_NUM:[0-9]+]]*/ [[LABEL:[0-9]+]],
131+
// CHECK-NEXT: GIM_CheckFeatures, GIFBS_HwMode0,
132+
// CHECK-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/2,
133+
// CHECK-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_LOAD,
134+
// CHECK-NEXT: GIM_CheckMemorySizeEqualToLLT, /*MI*/0, /*MMO*/0, /*OpIdx*/0,
135+
// CHECK-NEXT: GIM_CheckAtomicOrdering, /*MI*/0, /*Order*/(int64_t)AtomicOrdering::NotAtomic,
136+
// CHECK-NEXT: // MIs[0] dst
137+
// CHECK-NEXT: GIM_CheckType, /*MI*/0, /*Op*/0, /*Type*/GILLT_s64,
138+
// CHECK-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/0, /*RC*/MyTarget::GPRRegClassID,
139+
// CHECK-NEXT: // MIs[0] src1
140+
// CHECK-NEXT: GIM_CheckPointerToAny, /*MI*/0, /*Op*/1, /*SizeInBits*/64,
141+
// CHECK-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/1, /*RC*/MyTarget::GPRRegClassID,
142+
// CHECK-NEXT: // (ld:{ *:[i64] } GPR:{ *:[i64] }:$src1)<<P:Predicate_unindexedload>><<P:Predicate_load>> => (LOAD:{ *:[i64] } GPR:{ *:[i64] }:$src1)
143+
// CHECK-NEXT: GIR_MutateOpcode, /*InsnID*/0, /*RecycleInsnID*/0, /*Opcode*/MyTarget::LOAD,
144+
// CHECK-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0,
145+
// CHECK-NEXT: // GIR_Coverage, 0,
146+
// CHECK-NEXT: GIR_Done,
147+
// CHECK-NEXT: // Label [[LABEL_NUM]]: @[[LABEL]]
148+
// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label [[LABEL_NUM:[0-9]+]]*/ [[LABEL:[0-9]+]],
149+
// CHECK-NEXT: GIM_CheckFeatures, GIFBS_HwMode1,
150+
// CHECK-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/2,
151+
// CHECK-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_LOAD,
152+
// CHECK-NEXT: GIM_CheckMemorySizeEqualToLLT, /*MI*/0, /*MMO*/0, /*OpIdx*/0,
153+
// CHECK-NEXT: GIM_CheckAtomicOrdering, /*MI*/0, /*Order*/(int64_t)AtomicOrdering::NotAtomic,
154+
// CHECK-NEXT: // MIs[0] dst
155+
// CHECK-NEXT: GIM_CheckType, /*MI*/0, /*Op*/0, /*Type*/GILLT_s32,
156+
// CHECK-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/0, /*RC*/MyTarget::GPRRegClassID,
157+
// CHECK-NEXT: // MIs[0] src1
158+
// CHECK-NEXT: GIM_CheckPointerToAny, /*MI*/0, /*Op*/1, /*SizeInBits*/32,
159+
// CHECK-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/1, /*RC*/MyTarget::GPRRegClassID,
160+
// CHECK-NEXT: // (ld:{ *:[i32] } GPR:{ *:[i32] }:$src1)<<P:Predicate_unindexedload>><<P:Predicate_load>> => (LOAD:{ *:[i32] } GPR:{ *:[i32] }:$src1)
161+
// CHECK-NEXT: GIR_MutateOpcode, /*InsnID*/0, /*RecycleInsnID*/0, /*Opcode*/MyTarget::LOAD,
162+
// CHECK-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0,
163+
// CHECK-NEXT: // GIR_Coverage, 1,
164+
// CHECK-NEXT: GIR_Done,
165+
// CHECK-NEXT: // Label [[LABEL_NUM]]: @[[LABEL]]
166+
167+
def LOAD : I<(outs GPR:$dst), (ins GPR:$src1),
168+
[(set GPR:$dst, (load GPR:$src1))]>;
169+
170+
//===- Test a simple pattern with explicit pointer operands. ---------------===//
171+
172+
// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label [[LABEL_NUM:[0-9]+]]*/ [[LABEL:[0-9]+]],
173+
// CHECK-NEXT: GIM_CheckFeatures, GIFBS_HwMode0,
174+
// CHECK-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/2,
175+
// CHECK-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_LOAD,
176+
// CHECK-NEXT: GIM_CheckMemorySizeEqualToLLT, /*MI*/0, /*MMO*/0, /*OpIdx*/0,
177+
// CHECK-NEXT: GIM_CheckAtomicOrdering, /*MI*/0, /*Order*/(int64_t)AtomicOrdering::NotAtomic,
178+
// CHECK-NEXT: // MIs[0] dst
179+
// CHECK-NEXT: GIM_CheckType, /*MI*/0, /*Op*/0, /*Type*/GILLT_p0s64,
180+
// CHECK-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/0, /*RC*/MyTarget::GPRRegClassID,
181+
// CHECK-NEXT: // MIs[0] src
182+
// CHECK-NEXT: GIM_CheckPointerToAny, /*MI*/0, /*Op*/1, /*SizeInBits*/64,
183+
// CHECK-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/1, /*RC*/MyTarget::GPRRegClassID,
184+
// CHECK-NEXT: // (ld:{ *:[i64] } GPR:{ *:[i64] }:$src)<<P:Predicate_unindexedload>><<P:Predicate_load>> => (LOAD:{ *:[i64] } GPR:{ *:[i64] }:$src)
185+
// CHECK-NEXT: GIR_MutateOpcode, /*InsnID*/0, /*RecycleInsnID*/0, /*Opcode*/MyTarget::LOAD,
186+
// CHECK-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0,
187+
// CHECK-NEXT: // GIR_Coverage, 2,
188+
// CHECK-NEXT: GIR_Done,
189+
// CHECK-NEXT: // Label [[LABEL_NUM]]: @[[LABEL]]
190+
// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label [[LABEL_NUM:[0-9]+]]*/ [[LABEL:[0-9]+]],
191+
// CHECK-NEXT: GIM_CheckFeatures, GIFBS_HwMode1,
192+
// CHECK-NEXT: GIM_CheckNumOperands, /*MI*/0, /*Expected*/2,
193+
// CHECK-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_LOAD,
194+
// CHECK-NEXT: GIM_CheckMemorySizeEqualToLLT, /*MI*/0, /*MMO*/0, /*OpIdx*/0,
195+
// CHECK-NEXT: GIM_CheckAtomicOrdering, /*MI*/0, /*Order*/(int64_t)AtomicOrdering::NotAtomic,
196+
// CHECK-NEXT: // MIs[0] dst
197+
// CHECK-NEXT: GIM_CheckType, /*MI*/0, /*Op*/0, /*Type*/GILLT_p0s32,
198+
// CHECK-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/0, /*RC*/MyTarget::GPRRegClassID,
199+
// CHECK-NEXT: // MIs[0] src
200+
// CHECK-NEXT: GIM_CheckPointerToAny, /*MI*/0, /*Op*/1, /*SizeInBits*/32,
201+
// CHECK-NEXT: GIM_CheckRegBankForClass, /*MI*/0, /*Op*/1, /*RC*/MyTarget::GPRRegClassID,
202+
// CHECK-NEXT: // (ld:{ *:[i32] } GPR:{ *:[i32] }:$src)<<P:Predicate_unindexedload>><<P:Predicate_load>> => (LOAD:{ *:[i32] } GPR:{ *:[i32] }:$src)
203+
// CHECK-NEXT: GIR_MutateOpcode, /*InsnID*/0, /*RecycleInsnID*/0, /*Opcode*/MyTarget::LOAD,
204+
// CHECK-NEXT: GIR_ConstrainSelectedInstOperands, /*InsnID*/0,
205+
// CHECK-NEXT: // GIR_Coverage, 3,
206+
// CHECK-NEXT: GIR_Done,
207+
// CHECK-NEXT: // Label [[LABEL_NUM]]: @[[LABEL]]
208+
209+
def : Pat<(load GPR:$src),
210+
(p0 (LOAD GPR:$src))>;

llvm/utils/TableGen/InfoByHwMode.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ ValueTypeByHwMode::ValueTypeByHwMode(Record *R, const CodeGenHwModes &CGH) {
3535
assert(I.second && "Duplicate entry?");
3636
(void)I;
3737
}
38+
if (R->isSubClassOf("PtrValueType"))
39+
PtrAddrSpace = R->getValueAsInt("AddrSpace");
3840
}
3941

4042
ValueTypeByHwMode::ValueTypeByHwMode(Record *R, MVT T) : ValueTypeByHwMode(T) {

0 commit comments

Comments
 (0)