Skip to content

Commit 27f5e90

Browse files
committed
[GlobalISel] Add GITypeOf special type
Allows creating a register/immediate that uses the same type as a matched operand.
1 parent 1be3b1e commit 27f5e90

File tree

13 files changed

+622
-103
lines changed

13 files changed

+622
-103
lines changed

llvm/docs/GlobalISel/MIRPatterns.rst

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,48 @@ pattern, you can try naming your patterns to see exactly where the issue is.
101101
// using $x again here copies operand 1 from G_AND into the new inst.
102102
(apply (COPY $root, $x))
103103
104+
Types
105+
-----
106+
107+
ValueType
108+
~~~~~~~~~
109+
110+
Subclasses of ``ValueType`` are valid types, e.g. ``i32``.
111+
112+
GITypeOf
113+
~~~~~~~~
114+
115+
``GITypeOf<"$x">`` is a ``GISpecialType`` that allows for the creation of a
116+
register or immediate with the same type as another (register) operand.
117+
118+
Operand:
119+
120+
* An operand name as a string, prefixed by ``$``.
121+
122+
Semantics:
123+
124+
* Can only appear in an 'apply' pattern.
125+
* The operand name used must appear in the 'match' pattern of the
126+
same ``GICombineRule``.
127+
128+
.. code-block:: text
129+
:caption: Example: Immediate
130+
131+
def mul_by_neg_one: GICombineRule <
132+
(defs root:$root),
133+
(match (G_MUL $dst, $x, -1)),
134+
(apply (G_SUB $dst, (GITypeOf<"$x"> 0), $x))
135+
>;
136+
137+
.. code-block:: text
138+
:caption: Example: Temp Reg
139+
140+
def Test0 : GICombineRule<
141+
(defs root:$dst),
142+
(match (G_FMUL $dst, $src, -1)),
143+
(apply (G_FSUB $dst, $src, $tmp),
144+
(G_FNEG GITypeOf<"$dst">:$tmp, $src))>;
145+
104146
Builtin Operations
105147
------------------
106148

llvm/include/llvm/CodeGen/GlobalISel/CombinerHelper.h

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -403,9 +403,6 @@ class CombinerHelper {
403403
void applyCombineTruncOfShift(MachineInstr &MI,
404404
std::pair<MachineInstr *, LLT> &MatchInfo);
405405

406-
/// Transform G_MUL(x, -1) to G_SUB(0, x)
407-
void applyCombineMulByNegativeOne(MachineInstr &MI);
408-
409406
/// Return true if any explicit use operand on \p MI is defined by a
410407
/// G_IMPLICIT_DEF.
411408
bool matchAnyExplicitUseIsUndef(MachineInstr &MI);

llvm/include/llvm/CodeGen/GlobalISel/GIMatchTableExecutor.h

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,12 @@ enum {
275275
/// - StoreIdx - Store location in RecordedOperands.
276276
GIM_RecordNamedOperand,
277277

278+
/// Records an operand's register type into the set of temporary types.
279+
/// - InsnID - Instruction ID
280+
/// - OpIdx - Operand index
281+
/// - TempTypeIdx - Temp Type Index, always negative.
282+
GIM_RecordRegType,
283+
278284
/// Fail the current try-block, or completely fail to match if there is no
279285
/// current try-block.
280286
GIM_Reject,
@@ -356,12 +362,6 @@ enum {
356362
/// - Imm - The immediate to add
357363
GIR_AddImm,
358364

359-
/// Add an CImm to the specified instruction
360-
/// - InsnID - Instruction ID to modify
361-
/// - Ty - Type of the constant immediate.
362-
/// - Imm - The immediate to add
363-
GIR_AddCImm,
364-
365365
/// Render complex operands to the specified instruction
366366
/// - InsnID - Instruction ID to modify
367367
/// - RendererID - The renderer to call
@@ -522,6 +522,10 @@ class GIMatchTableExecutor {
522522
/// list. Currently such predicates don't have more then 3 arguments.
523523
std::array<const MachineOperand *, 3> RecordedOperands;
524524

525+
/// Types extracted from an instruction's operand.
526+
/// Whenever a type index is negative, we look here instead.
527+
SmallVector<LLT, 4> RecordedTypes;
528+
525529
MatcherState(unsigned MaxRenderers);
526530
};
527531

llvm/include/llvm/CodeGen/GlobalISel/GIMatchTableExecutorImpl.h

Lines changed: 29 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,14 @@ bool GIMatchTableExecutor::executeMatchTable(
9292
return true;
9393
};
9494

95+
// If the index is >= 0, it's an index in the type objects generated by
96+
// TableGen. If the index is <0, it's an index in the recorded types object.
97+
auto getTypeFromIdx = [&](int64_t Idx) -> const LLT & {
98+
if (Idx >= 0)
99+
return ExecInfo.TypeObjects[Idx];
100+
return State.RecordedTypes[1 - Idx];
101+
};
102+
95103
while (true) {
96104
assert(CurrentIdx != ~0u && "Invalid MatchTable index");
97105
int64_t MatcherOpcode = MatchTable[CurrentIdx++];
@@ -627,8 +635,7 @@ bool GIMatchTableExecutor::executeMatchTable(
627635
<< "), TypeID=" << TypeID << ")\n");
628636
assert(State.MIs[InsnID] != nullptr && "Used insn before defined");
629637
MachineOperand &MO = State.MIs[InsnID]->getOperand(OpIdx);
630-
if (!MO.isReg() ||
631-
MRI.getType(MO.getReg()) != ExecInfo.TypeObjects[TypeID]) {
638+
if (!MO.isReg() || MRI.getType(MO.getReg()) != getTypeFromIdx(TypeID)) {
632639
if (handleReject() == RejectAndGiveUp)
633640
return false;
634641
}
@@ -679,6 +686,25 @@ bool GIMatchTableExecutor::executeMatchTable(
679686
State.RecordedOperands[StoreIdx] = &State.MIs[InsnID]->getOperand(OpIdx);
680687
break;
681688
}
689+
case GIM_RecordRegType: {
690+
int64_t InsnID = MatchTable[CurrentIdx++];
691+
int64_t OpIdx = MatchTable[CurrentIdx++];
692+
int64_t TypeIdx = MatchTable[CurrentIdx++];
693+
694+
DEBUG_WITH_TYPE(TgtExecutor::getName(),
695+
dbgs() << CurrentIdx << ": GIM_RecordRegType(MIs["
696+
<< InsnID << "]->getOperand(" << OpIdx
697+
<< "), TypeIdx=" << TypeIdx << ")\n");
698+
assert(State.MIs[InsnID] != nullptr && "Used insn before defined");
699+
assert(TypeIdx <= 0 && "Temp types always have negative indexes!");
700+
// Indexes start at -1.
701+
TypeIdx = 1 - TypeIdx;
702+
const auto &Op = State.MIs[InsnID]->getOperand(OpIdx);
703+
if (State.RecordedTypes.size() <= (uint64_t)TypeIdx)
704+
State.RecordedTypes.resize(TypeIdx + 1, LLT());
705+
State.RecordedTypes[TypeIdx] = MRI.getType(Op.getReg());
706+
break;
707+
}
682708
case GIM_CheckRegBankForClass: {
683709
int64_t InsnID = MatchTable[CurrentIdx++];
684710
int64_t OpIdx = MatchTable[CurrentIdx++];
@@ -1068,24 +1094,6 @@ bool GIMatchTableExecutor::executeMatchTable(
10681094
<< "], " << Imm << ")\n");
10691095
break;
10701096
}
1071-
1072-
case GIR_AddCImm: {
1073-
int64_t InsnID = MatchTable[CurrentIdx++];
1074-
int64_t TypeID = MatchTable[CurrentIdx++];
1075-
int64_t Imm = MatchTable[CurrentIdx++];
1076-
assert(OutMIs[InsnID] && "Attempted to add to undefined instruction");
1077-
1078-
unsigned Width = ExecInfo.TypeObjects[TypeID].getScalarSizeInBits();
1079-
LLVMContext &Ctx = MF->getFunction().getContext();
1080-
OutMIs[InsnID].addCImm(
1081-
ConstantInt::get(IntegerType::get(Ctx, Width), Imm, /*signed*/ true));
1082-
DEBUG_WITH_TYPE(TgtExecutor::getName(),
1083-
dbgs() << CurrentIdx << ": GIR_AddCImm(OutMIs[" << InsnID
1084-
<< "], TypeID=" << TypeID << ", Imm=" << Imm
1085-
<< ")\n");
1086-
break;
1087-
}
1088-
10891097
case GIR_ComplexRenderer: {
10901098
int64_t InsnID = MatchTable[CurrentIdx++];
10911099
int64_t RendererID = MatchTable[CurrentIdx++];
@@ -1275,7 +1283,7 @@ bool GIMatchTableExecutor::executeMatchTable(
12751283
int64_t TypeID = MatchTable[CurrentIdx++];
12761284

12771285
State.TempRegisters[TempRegID] =
1278-
MRI.createGenericVirtualRegister(ExecInfo.TypeObjects[TypeID]);
1286+
MRI.createGenericVirtualRegister(getTypeFromIdx(TypeID));
12791287
DEBUG_WITH_TYPE(TgtExecutor::getName(),
12801288
dbgs() << CurrentIdx << ": TempRegs[" << TempRegID
12811289
<< "] = GIR_MakeTempReg(" << TypeID << ")\n");

llvm/include/llvm/Target/GlobalISel/Combine.td

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,24 @@ class GICombinePatFrag<dag outs, dag ins, list<dag> alts> {
110110
list<dag> Alternatives = alts;
111111
}
112112

113+
//===----------------------------------------------------------------------===//
114+
// Pattern Special Types
115+
//===----------------------------------------------------------------------===//
116+
117+
class GISpecialType;
118+
119+
// In an apply pattern, GITypeOf can be used to set the type of a new temporary
120+
// register to match the type of a matched register.
121+
//
122+
// This can only be used on temporary registers defined by the apply pattern.
123+
//
124+
// TODO: Make this work in matchers as well?
125+
//
126+
// FIXME: Syntax is very ugly.
127+
class GITypeOf<string opName> : GISpecialType {
128+
string OpName = opName;
129+
}
130+
113131
//===----------------------------------------------------------------------===//
114132
// Pattern Builtins
115133
//===----------------------------------------------------------------------===//
@@ -776,10 +794,9 @@ def trunc_shift: GICombineRule <
776794

777795
// Transform (mul x, -1) -> (sub 0, x)
778796
def mul_by_neg_one: GICombineRule <
779-
(defs root:$root),
780-
(match (wip_match_opcode G_MUL):$root,
781-
[{ return Helper.matchConstantOp(${root}->getOperand(2), -1); }]),
782-
(apply [{ Helper.applyCombineMulByNegativeOne(*${root}); }])
797+
(defs root:$dst),
798+
(match (G_MUL $dst, $x, -1)),
799+
(apply (G_SUB $dst, (GITypeOf<"$x"> 0), $x))
783800
>;
784801

785802
// Fold (xor (and x, y), y) -> (and (not x), y)

llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2224,18 +2224,6 @@ void CombinerHelper::applyCombineExtOfExt(
22242224
}
22252225
}
22262226

2227-
void CombinerHelper::applyCombineMulByNegativeOne(MachineInstr &MI) {
2228-
assert(MI.getOpcode() == TargetOpcode::G_MUL && "Expected a G_MUL");
2229-
Register DstReg = MI.getOperand(0).getReg();
2230-
Register SrcReg = MI.getOperand(1).getReg();
2231-
LLT DstTy = MRI.getType(DstReg);
2232-
2233-
Builder.setInstrAndDebugLoc(MI);
2234-
Builder.buildSub(DstReg, Builder.buildConstant(DstTy, 0), SrcReg,
2235-
MI.getFlags());
2236-
MI.eraseFromParent();
2237-
}
2238-
22392227
bool CombinerHelper::matchCombineTruncOfExt(
22402228
MachineInstr &MI, std::pair<Register, unsigned> &MatchInfo) {
22412229
assert(MI.getOpcode() == TargetOpcode::G_TRUNC && "Expected a G_TRUNC");
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
// RUN: llvm-tblgen -I %p/../../../include -gen-global-isel-combiner \
2+
// RUN: -combiners=MyCombiner %s | \
3+
// RUN: FileCheck %s
4+
5+
include "llvm/Target/Target.td"
6+
include "llvm/Target/GlobalISel/Combine.td"
7+
8+
def MyTargetISA : InstrInfo;
9+
def MyTarget : Target { let InstructionSet = MyTargetISA; }
10+
11+
def Test0 : GICombineRule<
12+
(defs root:$dst),
13+
(match (G_MUL $dst, $src, -1)),
14+
(apply (G_SUB $dst, (GITypeOf<"$src"> 0), $tmp),
15+
(G_CONSTANT GITypeOf<"$dst">:$tmp, (GITypeOf<"$src"> 42)))>;
16+
17+
// CHECK: const int64_t *GenMyCombiner::getMatchTable() const {
18+
// CHECK-NEXT: constexpr static int64_t MatchTable0[] = {
19+
// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label 0*/ 57, // Rule ID 0 //
20+
// CHECK-NEXT: GIM_CheckSimplePredicate, GICXXPred_Simple_IsRule0Enabled,
21+
// CHECK-NEXT: GIM_CheckOpcode, /*MI*/0, TargetOpcode::G_MUL,
22+
// CHECK-NEXT: // MIs[0] dst
23+
// CHECK-NEXT: GIM_RecordRegType, /*MI*/0, /*Op*/0, /*TempTypeIdx*/-1,
24+
// CHECK-NEXT: // MIs[0] src
25+
// CHECK-NEXT: GIM_RecordRegType, /*MI*/0, /*Op*/1, /*TempTypeIdx*/-2,
26+
// CHECK-NEXT: // MIs[0] Operand 2
27+
// CHECK-NEXT: GIM_CheckConstantInt, /*MI*/0, /*Op*/2, -1,
28+
// CHECK-NEXT: GIR_MakeTempReg, /*TempRegID*/1, /*TypeID*/-2,
29+
// CHECK-NEXT: GIR_BuildConstant, /*TempRegID*/1, /*Val*/0,
30+
// CHECK-NEXT: GIR_MakeTempReg, /*TempRegID*/0, /*TypeID*/-1,
31+
// CHECK-NEXT: // Combiner Rule #0: Test0
32+
// CHECK-NEXT: GIR_BuildMI, /*InsnID*/0, /*Opcode*/TargetOpcode::G_CONSTANT,
33+
// CHECK-NEXT: GIR_AddTempRegister, /*InsnID*/0, /*TempRegID*/0, /*TempRegFlags*/0,
34+
// CHECK-NEXT: GIR_AddCImm, /*InsnID*/0, /*Type*/-2, /*Imm*/42,
35+
// CHECK-NEXT: GIR_EraseFromParent, /*InsnID*/0,
36+
// CHECK-NEXT: GIR_BuildMI, /*InsnID*/1, /*Opcode*/TargetOpcode::G_SUB,
37+
// CHECK-NEXT: GIR_Copy, /*NewInsnID*/1, /*OldInsnID*/0, /*OpIdx*/0, // dst
38+
// CHECK-NEXT: GIR_AddTempRegister, /*InsnID*/1, /*TempRegID*/1, /*TempRegFlags*/0,
39+
// CHECK-NEXT: GIR_AddTempRegister, /*InsnID*/1, /*TempRegID*/0, /*TempRegFlags*/0,
40+
// CHECK-NEXT: GIR_Done,
41+
// CHECK-NEXT: // Label 0: @57
42+
// CHECK-NEXT: GIM_Reject,
43+
// CHECK-NEXT: };
44+
// CHECK-NEXT: return MatchTable0;
45+
// CHECK-NEXT: }
46+
47+
def MyCombiner: GICombiner<"GenMyCombiner", [
48+
Test0
49+
]>;

llvm/test/TableGen/GlobalISelCombinerEmitter/operand-types.td

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,33 @@ def PatFragTest0 : GICombineRule<
7979
(match (FooPF $dst)),
8080
(apply (COPY $dst, (i32 0)))>;
8181

82+
83+
// CHECK: (CombineRule name:TypeOfProp id:2 root:x
84+
// CHECK-NEXT: (MatchPats
85+
// CHECK-NEXT: <match_root>__TypeOfProp_match_0:(CodeGenInstructionPattern G_ZEXT operands:[<def>$x, $y])
86+
// CHECK-NEXT: )
87+
// CHECK-NEXT: (ApplyPats
88+
// CHECK-NEXT: <apply_root>__TypeOfProp_apply_0:(CodeGenInstructionPattern G_ANYEXT operands:[<def>$x, GITypeOf<$y>:$tmp])
89+
// CHECK-NEXT: __TypeOfProp_apply_1:(CodeGenInstructionPattern G_ANYEXT operands:[<def>GITypeOf<$y>:$tmp, $y])
90+
// CHECK-NEXT: )
91+
// CHECK-NEXT: (OperandTable MatchPats
92+
// CHECK-NEXT: x -> __TypeOfProp_match_0
93+
// CHECK-NEXT: y -> <live-in>
94+
// CHECK-NEXT: )
95+
// CHECK-NEXT: (OperandTable ApplyPats
96+
// CHECK-NEXT: tmp -> __TypeOfProp_apply_1
97+
// CHECK-NEXT: x -> __TypeOfProp_apply_0
98+
// CHECK-NEXT: y -> <live-in>
99+
// CHECK-NEXT: )
100+
// CHECK-NEXT: )
101+
def TypeOfProp : GICombineRule<
102+
(defs root:$x),
103+
(match (G_ZEXT $x, $y)),
104+
(apply (G_ANYEXT $x, GITypeOf<"$y">:$tmp),
105+
(G_ANYEXT $tmp, $y))>;
106+
82107
def MyCombiner: GICombiner<"GenMyCombiner", [
83108
InstTest0,
84-
PatFragTest0
109+
PatFragTest0,
110+
TypeOfProp
85111
]>;

llvm/test/TableGen/GlobalISelCombinerEmitter/pattern-parsing.td

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -297,6 +297,28 @@ def VariadicsOutTest : GICombineRule<
297297
(apply (COPY $a, (i32 0)),
298298
(COPY $b, (i32 0)))>;
299299

300+
// CHECK: (CombineRule name:TypeOfTest id:10 root:dst
301+
// CHECK-NEXT: (MatchPats
302+
// CHECK-NEXT: <match_root>__TypeOfTest_match_0:(CodeGenInstructionPattern COPY operands:[<def>$dst, $tmp])
303+
// CHECK-NEXT: __TypeOfTest_match_1:(CodeGenInstructionPattern G_ZEXT operands:[<def>$tmp, $src])
304+
// CHECK-NEXT: )
305+
// CHECK-NEXT: (ApplyPats
306+
// CHECK-NEXT: <apply_root>__TypeOfTest_apply_0:(CodeGenInstructionPattern G_MUL operands:[<def>$dst, (GITypeOf<$src> 0), (GITypeOf<$dst> -1)])
307+
// CHECK-NEXT: )
308+
// CHECK-NEXT: (OperandTable MatchPats
309+
// CHECK-NEXT: dst -> __TypeOfTest_match_0
310+
// CHECK-NEXT: src -> <live-in>
311+
// CHECK-NEXT: tmp -> __TypeOfTest_match_1
312+
// CHECK-NEXT: )
313+
// CHECK-NEXT: (OperandTable ApplyPats
314+
// CHECK-NEXT: dst -> __TypeOfTest_apply_0
315+
// CHECK-NEXT: )
316+
// CHECK-NEXT: )
317+
def TypeOfTest : GICombineRule<
318+
(defs root:$dst),
319+
(match (COPY $dst, $tmp),
320+
(G_ZEXT $tmp, $src)),
321+
(apply (G_MUL $dst, (GITypeOf<"$src"> 0), (GITypeOf<"$dst"> -1)))>;
300322

301323
def MyCombiner: GICombiner<"GenMyCombiner", [
302324
WipOpcodeTest0,
@@ -308,5 +330,6 @@ def MyCombiner: GICombiner<"GenMyCombiner", [
308330
PatFragTest0,
309331
PatFragTest1,
310332
VariadicsInTest,
311-
VariadicsOutTest
333+
VariadicsOutTest,
334+
TypeOfTest
312335
]>;

0 commit comments

Comments
 (0)