Skip to content

Commit 844c0da

Browse files
committed
[TableGen][GlobalISel] Add MIR Pattern Builtins
Adds a new feature to MIR patterns: builtin instructions. They offer some additional capabilities that currently cannot be expressed without falling back to C++ code. There are two builtins added with this patch, but more can be added later as new needs arise: - GIReplaceReg - GIEraseRoot Depends on D158714, D158713 Reviewed By: arsenm, aemerson Differential Revision: https://reviews.llvm.org/D158975
1 parent 4e513f6 commit 844c0da

14 files changed

+857
-94
lines changed

llvm/docs/GlobalISel/MIRPatterns.rst

Lines changed: 63 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,46 @@ 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+
Builtin Operations
105+
------------------
106+
107+
MIR Patterns also offer builtin operations, also called "builtin instructions".
108+
They offer some powerful features that would otherwise require use of C++ code.
109+
110+
GIReplaceReg
111+
~~~~~~~~~~~~
112+
113+
.. code-block:: text
114+
:caption: Usage
115+
116+
(apply (GIReplaceReg $old, $new))
117+
118+
Operands:
119+
120+
* ``$old`` (out) register defined by a matched instruction
121+
* ``$new`` (in) register
122+
123+
Semantics:
124+
125+
* Can only appear in an 'apply' pattern.
126+
* If both old/new are operands of matched instructions,
127+
``canReplaceReg`` is checked before applying the rule.
128+
129+
130+
GIEraseRoot
131+
~~~~~~~~~~~
132+
133+
.. code-block:: text
134+
:caption: Usage
135+
136+
(apply (GIEraseRoot))
137+
138+
Semantics:
139+
140+
* Can only appear as the only pattern of an 'apply' pattern list.
141+
* The root cannot have any output operands.
142+
* The root must be a CodeGenInstruction
143+
104144

105145
Limitations
106146
-----------
@@ -114,10 +154,6 @@ This a non-exhaustive list of known issues with MIR patterns at this time.
114154
* Instructions with multiple defs cannot be the root of a ``GICombinePatFrag``.
115155
* Using ``GICombinePatFrag`` in the ``apply`` pattern of a ``GICombineRule``
116156
is not supported.
117-
* Deleting the matched pattern in a ``GICombineRule`` needs to be done using
118-
``G_IMPLICIT_DEF`` or C++.
119-
* Replacing the root of a pattern with another instruction needs to be done
120-
using COPY.
121157
* We cannot rewrite a matched instruction other than the root.
122158
* Matching/creating a (CImm) immediate >64 bits is not supported
123159
(see comment in ``GIM_CheckConstantInt``)
@@ -179,33 +215,41 @@ The following expansions are available for MIR patterns:
179215
Common Pattern #1: Replace a Register with Another
180216
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
181217

182-
The 'apply' pattern must always redefine its root.
183-
It cannot just replace it with something else directly.
184-
A simple workaround is to just use a COPY that'll be eliminated later.
218+
The 'apply' pattern must always redefine all operands defined by the match root.
219+
Sometimes, we do not need to create instructions, simply replace a def with
220+
another matched register. The ``GIReplaceReg`` builtin can do just that.
185221

186222
.. code-block:: text
187223
188224
def Foo : GICombineRule<
189225
(defs root:$dst),
190226
(match (G_FNEG $tmp, $src), (G_FNEG $dst, $tmp)),
191-
(apply (COPY $dst, $src))>;
227+
(apply (GIReplaceReg $dst, $src))>;
192228
193-
Common Pattern #2: Erasing a Pattern
194-
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
229+
This also works if the replacement register is a temporary register from the
230+
``apply`` pattern.
195231

196-
As said before, we must always emit something in the 'apply' pattern.
197-
If we wish to delete the matched instruction, we can simply replace its
198-
definition with a ``G_IMPLICIT_DEF``.
232+
.. code-block:: text
233+
234+
def ReplaceTemp : GICombineRule<
235+
(defs root:$a),
236+
(match (G_BUILD_VECTOR $tmp, $x, $y),
237+
(G_UNMERGE_VALUES $a, $b, $tmp)),
238+
(apply (G_UNMERGE_VALUES $a, i32:$new, $y),
239+
(GIReplaceReg $b, $new))>
240+
241+
Common Pattern #2: Erasing a Def-less Root
242+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
243+
244+
If we simply want to erase a def-less match root, we can use the
245+
``GIEraseRoot`` builtin.
199246

200247
.. code-block:: text
201248
202249
def Foo : GICombineRule<
203-
(defs root:$dst),
204-
(match (G_FOO $tmp, $src), (G_BAR $dst, $tmp)),
205-
(apply (G_IMPLICIT_DEF $dst))>;
206-
207-
If the instruction has no definition, like ``G_STORE``, we cannot use
208-
an instruction pattern in 'apply' - C++ has to be used.
250+
(defs root:$mi),
251+
(match (G_STORE $a, $b):$mi),
252+
(apply (GIEraseRoot))>;
209253
210254
Common Pattern #3: Emitting a Constant Value
211255
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

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

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,13 @@ enum {
258258
GIM_CheckIsSameOperand,
259259
GIM_CheckIsSameOperandIgnoreCopies,
260260

261+
/// Check we can replace all uses of a register with another.
262+
/// - OldInsnID
263+
/// - OldOpIdx
264+
/// - NewInsnID
265+
/// - NewOpIdx
266+
GIM_CheckCanReplaceReg,
267+
261268
/// Predicates with 'let PredicateCodeUsesOperands = 1' need to examine some
262269
/// named operands that will be recorded in RecordedOperands. Names of these
263270
/// operands are referenced in predicate argument list. Emitter determines
@@ -431,6 +438,20 @@ enum {
431438
/// - Expected type
432439
GIR_MakeTempReg,
433440

441+
/// Replaces all references to a register from an instruction
442+
/// with another register from another instruction.
443+
/// - OldInsnID
444+
/// - OldOpIdx
445+
/// - NewInsnID
446+
/// - NewOpIdx
447+
GIR_ReplaceReg,
448+
449+
/// Replaces all references to a register with a temporary register.
450+
/// - OldInsnID
451+
/// - OldOpIdx
452+
/// - TempRegIdx
453+
GIR_ReplaceRegWithTempReg,
454+
434455
/// A successful emission
435456
GIR_Done,
436457

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

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -866,6 +866,25 @@ bool GIMatchTableExecutor::executeMatchTable(
866866
}
867867
break;
868868
}
869+
case GIM_CheckCanReplaceReg: {
870+
int64_t OldInsnID = MatchTable[CurrentIdx++];
871+
int64_t OldOpIdx = MatchTable[CurrentIdx++];
872+
int64_t NewInsnID = MatchTable[CurrentIdx++];
873+
int64_t NewOpIdx = MatchTable[CurrentIdx++];
874+
875+
DEBUG_WITH_TYPE(TgtExecutor::getName(),
876+
dbgs() << CurrentIdx << ": GIM_CheckCanReplaceReg(MIs["
877+
<< OldInsnID << "][" << OldOpIdx << "] = MIs["
878+
<< NewInsnID << "][" << NewOpIdx << "])\n");
879+
880+
Register Old = State.MIs[OldInsnID]->getOperand(OldOpIdx).getReg();
881+
Register New = State.MIs[NewInsnID]->getOperand(NewOpIdx).getReg();
882+
if (!canReplaceReg(Old, New, MRI)) {
883+
if (handleReject() == RejectAndGiveUp)
884+
return false;
885+
}
886+
break;
887+
}
869888
case GIM_Reject:
870889
DEBUG_WITH_TYPE(TgtExecutor::getName(),
871890
dbgs() << CurrentIdx << ": GIM_Reject\n");
@@ -1237,7 +1256,45 @@ bool GIMatchTableExecutor::executeMatchTable(
12371256
<< "] = GIR_MakeTempReg(" << TypeID << ")\n");
12381257
break;
12391258
}
1259+
case GIR_ReplaceReg: {
1260+
int64_t OldInsnID = MatchTable[CurrentIdx++];
1261+
int64_t OldOpIdx = MatchTable[CurrentIdx++];
1262+
int64_t NewInsnID = MatchTable[CurrentIdx++];
1263+
int64_t NewOpIdx = MatchTable[CurrentIdx++];
1264+
1265+
DEBUG_WITH_TYPE(TgtExecutor::getName(),
1266+
dbgs() << CurrentIdx << ": GIR_ReplaceReg(MIs["
1267+
<< OldInsnID << "][" << OldOpIdx << "] = MIs["
1268+
<< NewInsnID << "][" << NewOpIdx << "])\n");
12401269

1270+
Register Old = State.MIs[OldInsnID]->getOperand(OldOpIdx).getReg();
1271+
Register New = State.MIs[NewInsnID]->getOperand(NewOpIdx).getReg();
1272+
if (Observer)
1273+
Observer->changingAllUsesOfReg(MRI, Old);
1274+
MRI.replaceRegWith(Old, New);
1275+
if (Observer)
1276+
Observer->finishedChangingAllUsesOfReg();
1277+
break;
1278+
}
1279+
case GIR_ReplaceRegWithTempReg: {
1280+
int64_t OldInsnID = MatchTable[CurrentIdx++];
1281+
int64_t OldOpIdx = MatchTable[CurrentIdx++];
1282+
int64_t TempRegID = MatchTable[CurrentIdx++];
1283+
1284+
DEBUG_WITH_TYPE(TgtExecutor::getName(),
1285+
dbgs() << CurrentIdx << ": GIR_ReplaceRegWithTempReg(MIs["
1286+
<< OldInsnID << "][" << OldOpIdx << "] = TempRegs["
1287+
<< TempRegID << "])\n");
1288+
1289+
Register Old = State.MIs[OldInsnID]->getOperand(OldOpIdx).getReg();
1290+
Register New = State.TempRegisters[TempRegID];
1291+
if (Observer)
1292+
Observer->changingAllUsesOfReg(MRI, Old);
1293+
MRI.replaceRegWith(Old, New);
1294+
if (Observer)
1295+
Observer->finishedChangingAllUsesOfReg();
1296+
break;
1297+
}
12411298
case GIR_Coverage: {
12421299
int64_t RuleID = MatchTable[CurrentIdx++];
12431300
assert(CoverageInfo);

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

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

113+
//===----------------------------------------------------------------------===//
114+
// Pattern Builtins
115+
//===----------------------------------------------------------------------===//
116+
117+
// "Magic" Builtin instructions for MIR patterns.
118+
// The definitions that implement
119+
class GIBuiltinInst;
120+
121+
// Replace all references to a register with another one.
122+
//
123+
// Usage:
124+
// (apply (GIReplaceReg $old, $new))
125+
//
126+
// Operands:
127+
// - $old (out) register defined by a matched instruction
128+
// - $new (in) register
129+
//
130+
// Semantics:
131+
// - Can only appear in an 'apply' pattern.
132+
// - If both old/new are operands of matched instructions,
133+
// "canReplaceReg" is checked before applying the rule.
134+
def GIReplaceReg : GIBuiltinInst;
135+
136+
// Apply action that erases the match root.
137+
//
138+
// Usage:
139+
// (apply (GIEraseRoot))
140+
//
141+
// Semantics:
142+
// - Can only appear as the only pattern of an 'apply' pattern list.
143+
// - The root cannot have any output operands.
144+
// - The root must be a CodeGenInstruction
145+
//
146+
// TODO: Allow using this directly, like (apply GIEraseRoot)
147+
def GIEraseRoot : GIBuiltinInst;
148+
113149
//===----------------------------------------------------------------------===//
114150

115151
def extending_load_matchdata : GIDefMatchData<"PreferredTuple">;
@@ -141,7 +177,7 @@ def idempotent_prop_frags : GICombinePatFrag<
141177
def idempotent_prop : GICombineRule<
142178
(defs root:$dst),
143179
(match (idempotent_prop_frags $dst, $src)),
144-
(apply (COPY $dst, $src))>;
180+
(apply (GIReplaceReg $dst, $src))>;
145181

146182

147183
def extending_loads : GICombineRule<
@@ -337,7 +373,7 @@ def select_undef_cmp: GICombineRule<
337373
(defs root:$dst),
338374
(match (G_IMPLICIT_DEF $undef),
339375
(G_SELECT $dst, $undef, $x, $y)),
340-
(apply (COPY $dst, $y))
376+
(apply (GIReplaceReg $dst, $y))
341377
>;
342378

343379
// Fold (true ? x : y) -> x
@@ -384,14 +420,14 @@ def right_identity_zero_frags : GICombinePatFrag<
384420
def right_identity_zero: GICombineRule<
385421
(defs root:$dst),
386422
(match (right_identity_zero_frags $dst, $lhs)),
387-
(apply (COPY $dst, $lhs))
423+
(apply (GIReplaceReg $dst, $lhs))
388424
>;
389425

390426
// Fold x op 1 -> x
391427
def right_identity_one: GICombineRule<
392428
(defs root:$dst),
393429
(match (G_MUL $dst, $x, 1)),
394-
(apply (COPY $dst, $x))
430+
(apply (GIReplaceReg $dst, $x))
395431
>;
396432

397433
// Fold (x op x) - > x
@@ -405,7 +441,7 @@ def binop_same_val_frags : GICombinePatFrag<
405441
def binop_same_val: GICombineRule<
406442
(defs root:$dst),
407443
(match (binop_same_val_frags $dst, $src)),
408-
(apply (COPY $dst, $src))
444+
(apply (GIReplaceReg $dst, $src))
409445
>;
410446

411447
// Fold (0 op x) - > 0
@@ -456,7 +492,7 @@ def div_rem_to_divrem : GICombineRule<
456492
def binop_right_to_zero: GICombineRule<
457493
(defs root:$dst),
458494
(match (G_MUL $dst, $lhs, 0:$zero)),
459-
(apply (COPY $dst, $zero))
495+
(apply (GIReplaceReg $dst, $zero))
460496
>;
461497

462498
// Erase stores of undef values.
@@ -623,7 +659,7 @@ def fneg_fneg_fold: GICombineRule <
623659
(defs root:$dst),
624660
(match (G_FNEG $t, $src),
625661
(G_FNEG $dst, $t)),
626-
(apply (COPY $dst, $src))
662+
(apply (GIReplaceReg $dst, $src))
627663
>;
628664

629665
// Fold (unmerge(merge x, y, z)) -> z, y, z.
@@ -1033,7 +1069,7 @@ def add_sub_reg_frags : GICombinePatFrag<
10331069
def add_sub_reg: GICombineRule <
10341070
(defs root:$dst),
10351071
(match (add_sub_reg_frags $dst, $src)),
1036-
(apply (COPY $dst, $src))>;
1072+
(apply (GIReplaceReg $dst, $src))>;
10371073

10381074
def buildvector_identity_fold : GICombineRule<
10391075
(defs root:$build_vector, register_matchinfo:$matchinfo),

llvm/test/CodeGen/AArch64/GlobalISel/prelegalizercombiner-trivial-arith.mir

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,8 +74,9 @@ body: |
7474
; CHECK-LABEL: name: mul_0_cant_replace
7575
; CHECK: liveins: $w0
7676
; CHECK-NEXT: {{ $}}
77+
; CHECK-NEXT: %x:_(s32) = COPY $w0
7778
; CHECK-NEXT: %cst:_(s32) = G_CONSTANT i32 0
78-
; CHECK-NEXT: %op:gpr(s32) = COPY %cst(s32)
79+
; CHECK-NEXT: %op:gpr(s32) = G_MUL %x, %cst
7980
; CHECK-NEXT: $w0 = COPY %op(s32)
8081
; CHECK-NEXT: RET_ReallyLR implicit $w0
8182
%x:_(s32) = COPY $w0

0 commit comments

Comments
 (0)