Skip to content

Commit 5ee539b

Browse files
committed
[GlobalISel] Add combine action for C++ combine rules
Adds a `combine` action (DAG operator) which allows for easy definition of combine rule that only match one or more instructions, and defer all remaining match/apply logic to C++ code. This avoids the need for split match/apply function in such cases. One function can do the trick as long as it returns `true` if it changed any code. This is implemented as syntactic sugar over match/apply. The combine rule is just a match pattern BUT every C++ pattern inside is treated as an "apply" function. This makes it fit seamlessly with the current backend. Fixes #92410
1 parent 0f52649 commit 5ee539b

File tree

6 files changed

+230
-74
lines changed

6 files changed

+230
-74
lines changed

llvm/docs/GlobalISel/MIRPatterns.rst

+37-1
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ Operands are ordered just like they would be in a MachineInstr: the defs (outs)
7474
come first, then the uses (ins).
7575

7676
Patterns are generally grouped into another DAG datatype with a dummy operator
77-
such as ``match``, ``apply`` or ``pattern``.
77+
such as ``match``, ``apply``, ``combine`` or ``pattern``.
7878

7979
Finally, any DAG datatype in TableGen can be named. This also holds for
8080
patterns. e.g. the following is valid: ``(G_FOO $root, (i32 0):$cst):$mypat``.
@@ -370,6 +370,42 @@ The following expansions are available for MIR patterns:
370370
(match (G_ZEXT $root, $src):$mi),
371371
(apply "foobar(${root}.getReg(), ${src}.getReg(), ${mi}->hasImplicitDef())")>;
372372
373+
``combine`` Operator
374+
~~~~~~~~~~~~~~~~~~~~
375+
376+
``GICombineRule`` also supports a single ``combine`` pattern, which is a shorter way to
377+
declare patterns that just match one or more instruction, then defer all remaining matching
378+
and rewriting logic to C++ code.
379+
380+
.. code-block:: text
381+
:caption: Example usage of the combine operator.
382+
383+
// match + apply
384+
def FooLong : GICombineRule<
385+
(defs root:$root),
386+
(match (G_ZEXT $root, $src):$mi, "return matchFoo(${mi});"),
387+
(apply "applyFoo(${mi});")>;
388+
389+
// combine
390+
def FooShort : GICombineRule<
391+
(defs root:$root),
392+
(combine (G_ZEXT $root, $src):$mi, "return combineFoo(${mi});")>;
393+
394+
This has a couple of advantages:
395+
396+
* We only need one C++ function, not two.
397+
* We no longer need to use ``GIDefMatchData`` to pass information between the match/apply functions.
398+
399+
As described above, this is syntactic sugar for the match+apply form. In a ``combine`` pattern:
400+
401+
* Everything except C++ code is considered the ``match`` part.
402+
* The C++ code is the ``apply`` part. C++ code is emitted in order of appearance.
403+
404+
.. note::
405+
406+
The C++ code **must** return true if it changed any instruction. Returning false when changing
407+
instructions is undefined behavior.
408+
373409
Common Pattern #1: Replace a Register with Another
374410
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
375411

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

+8-7
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ def defs;
3131
def pattern;
3232
def match;
3333
def apply;
34+
def combine;
35+
def empty_action;
3436

3537
def wip_match_opcode;
3638

@@ -67,18 +69,17 @@ class GIDefMatchData<string type> {
6769
string Type = type;
6870
}
6971

70-
class GICombineRule<dag defs, dag match, dag apply> : GICombine {
72+
class GICombineRule<dag defs, dag a0, dag a1 = (empty_action)> : GICombine {
7173
/// Defines the external interface of the match rule. This includes:
7274
/// * The names of the root nodes (requires at least one)
7375
/// See GIDefKind for details.
7476
dag Defs = defs;
7577

76-
/// Defines the things which must be true for the pattern to match
77-
dag Match = match;
78-
79-
/// Defines the things which happen after the decision is made to apply a
80-
/// combine rule.
81-
dag Apply = apply;
78+
// The patterns that will be used. Two types of list can exist:
79+
// match (Action0) + apply (Action1).
80+
// combine (Action0) + empty_action (Action1).
81+
dag Action0 = a0;
82+
dag Action1 = a1;
8283

8384
/// Defines the predicates that are checked before the match function
8485
/// is called. Targets can use this to, for instance, check Subtarget

llvm/test/TableGen/GlobalISelCombinerEmitter/match-table-cxx.td

+78-55
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,16 @@ def NoMatchTwoApply : GICombineRule<
2828
(match (G_SEXT $a, $y)),
2929
(apply "APPLY0", "APPLY1")>;
3030

31+
def CopmbineCXXOrder : GICombineRule<
32+
(defs root:$a),
33+
(combine (G_ZEXT $a, $y), "A0", "return A1")>;
34+
3135
def MyCombiner: GICombiner<"GenMyCombiner", [
3236
OneMatchOneApply,
3337
TwoMatchTwoApply,
3438
TwoMatchNoApply,
35-
NoMatchTwoApply
39+
NoMatchTwoApply,
40+
CopmbineCXXOrder
3641
]>;
3742

3843
// CHECK: bool GenMyCombiner::testMIPredicate_MI(unsigned PredicateID, const MachineInstr & MI, const MatcherState &State) const {
@@ -79,65 +84,83 @@ def MyCombiner: GICombiner<"GenMyCombiner", [
7984
// CHECK-NEXT: APPLY1
8085
// CHECK-NEXT: return true;
8186
// CHECK-NEXT: }
87+
// CHECK-NEXT: case GICXXCustomAction_GICombiner3:{
88+
// CHECK-NEXT: // Apply Patterns
89+
// CHECK-NEXT: A0
90+
// CHECK-NEXT: return A1
91+
// CHECK-NEXT: return true;
92+
// CHECK-NEXT: }
8293
// CHECK-NEXT: }
8394
// CHECK-NEXT: llvm_unreachable("Unknown Apply Action");
8495
// CHECK-NEXT: }
8596

8697
// CHECK: const uint8_t *GenMyCombiner::getMatchTable() const {
8798
// CHECK-NEXT: constexpr static uint8_t MatchTable0[] = {
88-
// CHECK-NEXT: GIM_SwitchOpcode, /*MI*/0, /*[*/GIMT_Encode2([[#LOWER:]]), GIMT_Encode2([[#UPPER:]]), /*)*//*default:*//*Label 4*/ GIMT_Encode4([[#DEFAULT:]]),
89-
// CHECK-NEXT: /*TargetOpcode::G_STORE*//*Label 0*/ GIMT_Encode4([[L418:[0-9]+]]), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0),
90-
// CHECK-NEXT: /*TargetOpcode::G_SEXT*//*Label 1*/ GIMT_Encode4([[L436:[0-9]+]]), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0),
91-
// CHECK-NEXT: /*TargetOpcode::G_FNEG*//*Label 2*/ GIMT_Encode4([[L448:[0-9]+]]), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0),
92-
// CHECK-NEXT: /*TargetOpcode::G_FABS*//*Label 3*/ GIMT_Encode4([[L460:[0-9]+]]),
93-
// CHECK-NEXT: // Label 0: @[[#%u, mul(UPPER-LOWER, 4) + 10]]
94-
// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label 5*/ GIMT_Encode4([[L435:[0-9]+]]), // Rule ID 2 //
95-
// CHECK-NEXT: GIM_CheckSimplePredicate, GIMT_Encode2(GICXXPred_Simple_IsRule2Enabled),
96-
// CHECK-NEXT: // MIs[0] x
97-
// CHECK-NEXT: // No operand predicates
98-
// CHECK-NEXT: // MIs[0] y
99-
// CHECK-NEXT: // No operand predicates
100-
// CHECK-NEXT: GIM_CheckCxxInsnPredicate, /*MI*/0, /*FnId*/GIMT_Encode2(GICXXPred_MI_Predicate_GICombiner0),
101-
// CHECK-NEXT: GIM_CheckCxxInsnPredicate, /*MI*/0, /*FnId*/GIMT_Encode2(GICXXPred_MI_Predicate_GICombiner1),
102-
// CHECK-NEXT: // Combiner Rule #2: TwoMatchNoApply
103-
// CHECK-NEXT: GIR_EraseRootFromParent_Done,
104-
// CHECK-NEXT: // Label 5: @[[L435]]
105-
// CHECK-NEXT: GIM_Reject,
106-
// CHECK-NEXT: // Label 1: @[[L436]]
107-
// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label 6*/ GIMT_Encode4([[L447:[0-9]+]]), // Rule ID 3 //
108-
// CHECK-NEXT: GIM_CheckSimplePredicate, GIMT_Encode2(GICXXPred_Simple_IsRule3Enabled),
109-
// CHECK-NEXT: // MIs[0] a
110-
// CHECK-NEXT: // No operand predicates
111-
// CHECK-NEXT: // MIs[0] y
112-
// CHECK-NEXT: // No operand predicates
113-
// CHECK-NEXT: // Combiner Rule #3: NoMatchTwoApply
114-
// CHECK-NEXT: GIR_DoneWithCustomAction, /*Fn*/GIMT_Encode2(GICXXCustomAction_GICombiner2),
115-
// CHECK-NEXT: // Label 6: @[[L447]]
116-
// CHECK-NEXT: GIM_Reject,
117-
// CHECK-NEXT: // Label 2: @[[L448]]
118-
// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label 7*/ GIMT_Encode4([[L459:[0-9]+]]), // Rule ID 1 //
119-
// CHECK-NEXT: GIM_CheckSimplePredicate, GIMT_Encode2(GICXXPred_Simple_IsRule1Enabled),
120-
// CHECK-NEXT: // MIs[0] a
121-
// CHECK-NEXT: // No operand predicates
122-
// CHECK-NEXT: // MIs[0] b
123-
// CHECK-NEXT: // No operand predicates
124-
// CHECK-NEXT: // Combiner Rule #1: TwoMatchTwoApply
125-
// CHECK-NEXT: GIR_DoneWithCustomAction, /*Fn*/GIMT_Encode2(GICXXCustomAction_GICombiner1),
126-
// CHECK-NEXT: // Label 7: @[[L459]]
127-
// CHECK-NEXT: GIM_Reject,
128-
// CHECK-NEXT: // Label 3: @[[L460]]
129-
// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label 8*/ GIMT_Encode4([[L471:[0-9]+]]), // Rule ID 0 //
130-
// CHECK-NEXT: GIM_CheckSimplePredicate, GIMT_Encode2(GICXXPred_Simple_IsRule0Enabled),
131-
// CHECK-NEXT: // MIs[0] a
132-
// CHECK-NEXT: // No operand predicates
133-
// CHECK-NEXT: // MIs[0] b
134-
// CHECK-NEXT: // No operand predicates
135-
// CHECK-NEXT: // Combiner Rule #0: OneMatchOneApply
136-
// CHECK-NEXT: GIR_DoneWithCustomAction, /*Fn*/GIMT_Encode2(GICXXCustomAction_GICombiner0),
137-
// CHECK-NEXT: // Label 8: @[[L471]]
138-
// CHECK-NEXT: GIM_Reject,
139-
// CHECK-NEXT: // Label 4: @[[#%u, DEFAULT]]
140-
// CHECK-NEXT: GIM_Reject,
141-
// CHECK-NEXT: }; // Size: [[#%u, DEFAULT + 1]] bytes
99+
// CHECK-NEXT: /* 0 */ GIM_SwitchOpcode, /*MI*/0, /*[*/GIMT_Encode2(99), GIMT_Encode2(205), /*)*//*default:*//*Label 5*/ GIMT_Encode4(500),
100+
// CHECK-NEXT: /* 10 */ /*TargetOpcode::G_STORE*//*Label 0*/ GIMT_Encode4(434), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0),
101+
// CHECK-NEXT: /* 162 */ /*TargetOpcode::G_SEXT*//*Label 1*/ GIMT_Encode4(452), GIMT_Encode4(0),
102+
// CHECK-NEXT: /* 170 */ /*TargetOpcode::G_ZEXT*//*Label 2*/ GIMT_Encode4(464), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0),
103+
// CHECK-NEXT: /* 394 */ /*TargetOpcode::G_FNEG*//*Label 3*/ GIMT_Encode4(476), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0),
104+
// CHECK-NEXT: /* 430 */ /*TargetOpcode::G_FABS*//*Label 4*/ GIMT_Encode4(488),
105+
// CHECK-NEXT: /* 434 */ // Label 0: @434
106+
// CHECK-NEXT: /* 434 */ GIM_Try, /*On fail goto*//*Label 6*/ GIMT_Encode4(451), // Rule ID 2 //
107+
// CHECK-NEXT: /* 439 */ GIM_CheckSimplePredicate, GIMT_Encode2(GICXXPred_Simple_IsRule2Enabled),
108+
// CHECK-NEXT: /* 442 */ // MIs[0] x
109+
// CHECK-NEXT: /* 442 */ // No operand predicates
110+
// CHECK-NEXT: /* 442 */ // MIs[0] y
111+
// CHECK-NEXT: /* 442 */ // No operand predicates
112+
// CHECK-NEXT: /* 442 */ GIM_CheckCxxInsnPredicate, /*MI*/0, /*FnId*/GIMT_Encode2(GICXXPred_MI_Predicate_GICombiner0),
113+
// CHECK-NEXT: /* 446 */ GIM_CheckCxxInsnPredicate, /*MI*/0, /*FnId*/GIMT_Encode2(GICXXPred_MI_Predicate_GICombiner1),
114+
// CHECK-NEXT: /* 450 */ // Combiner Rule #2: TwoMatchNoApply
115+
// CHECK-NEXT: /* 450 */ GIR_EraseRootFromParent_Done,
116+
// CHECK-NEXT: /* 451 */ // Label 6: @451
117+
// CHECK-NEXT: /* 451 */ GIM_Reject,
118+
// CHECK-NEXT: /* 452 */ // Label 1: @452
119+
// CHECK-NEXT: /* 452 */ GIM_Try, /*On fail goto*//*Label 7*/ GIMT_Encode4(463), // Rule ID 3 //
120+
// CHECK-NEXT: /* 457 */ GIM_CheckSimplePredicate, GIMT_Encode2(GICXXPred_Simple_IsRule3Enabled),
121+
// CHECK-NEXT: /* 460 */ // MIs[0] a
122+
// CHECK-NEXT: /* 460 */ // No operand predicates
123+
// CHECK-NEXT: /* 460 */ // MIs[0] y
124+
// CHECK-NEXT: /* 460 */ // No operand predicates
125+
// CHECK-NEXT: /* 460 */ // Combiner Rule #3: NoMatchTwoApply
126+
// CHECK-NEXT: /* 460 */ GIR_DoneWithCustomAction, /*Fn*/GIMT_Encode2(GICXXCustomAction_GICombiner2),
127+
// CHECK-NEXT: /* 463 */ // Label 7: @463
128+
// CHECK-NEXT: /* 463 */ GIM_Reject,
129+
// CHECK-NEXT: /* 464 */ // Label 2: @464
130+
// CHECK-NEXT: /* 464 */ GIM_Try, /*On fail goto*//*Label 8*/ GIMT_Encode4(475), // Rule ID 4 //
131+
// CHECK-NEXT: /* 469 */ GIM_CheckSimplePredicate, GIMT_Encode2(GICXXPred_Simple_IsRule4Enabled),
132+
// CHECK-NEXT: /* 472 */ // MIs[0] a
133+
// CHECK-NEXT: /* 472 */ // No operand predicates
134+
// CHECK-NEXT: /* 472 */ // MIs[0] y
135+
// CHECK-NEXT: /* 472 */ // No operand predicates
136+
// CHECK-NEXT: /* 472 */ // Combiner Rule #4: CopmbineCXXOrder
137+
// CHECK-NEXT: /* 472 */ GIR_DoneWithCustomAction, /*Fn*/GIMT_Encode2(GICXXCustomAction_GICombiner3),
138+
// CHECK-NEXT: /* 475 */ // Label 8: @475
139+
// CHECK-NEXT: /* 475 */ GIM_Reject,
140+
// CHECK-NEXT: /* 476 */ // Label 3: @476
141+
// CHECK-NEXT: /* 476 */ GIM_Try, /*On fail goto*//*Label 9*/ GIMT_Encode4(487), // Rule ID 1 //
142+
// CHECK-NEXT: /* 481 */ GIM_CheckSimplePredicate, GIMT_Encode2(GICXXPred_Simple_IsRule1Enabled),
143+
// CHECK-NEXT: /* 484 */ // MIs[0] a
144+
// CHECK-NEXT: /* 484 */ // No operand predicates
145+
// CHECK-NEXT: /* 484 */ // MIs[0] b
146+
// CHECK-NEXT: /* 484 */ // No operand predicates
147+
// CHECK-NEXT: /* 484 */ // Combiner Rule #1: TwoMatchTwoApply
148+
// CHECK-NEXT: /* 484 */ GIR_DoneWithCustomAction, /*Fn*/GIMT_Encode2(GICXXCustomAction_GICombiner1),
149+
// CHECK-NEXT: /* 487 */ // Label 9: @487
150+
// CHECK-NEXT: /* 487 */ GIM_Reject,
151+
// CHECK-NEXT: /* 488 */ // Label 4: @488
152+
// CHECK-NEXT: /* 488 */ GIM_Try, /*On fail goto*//*Label 10*/ GIMT_Encode4(499), // Rule ID 0 //
153+
// CHECK-NEXT: /* 493 */ GIM_CheckSimplePredicate, GIMT_Encode2(GICXXPred_Simple_IsRule0Enabled),
154+
// CHECK-NEXT: /* 496 */ // MIs[0] a
155+
// CHECK-NEXT: /* 496 */ // No operand predicates
156+
// CHECK-NEXT: /* 496 */ // MIs[0] b
157+
// CHECK-NEXT: /* 496 */ // No operand predicates
158+
// CHECK-NEXT: /* 496 */ // Combiner Rule #0: OneMatchOneApply
159+
// CHECK-NEXT: /* 496 */ GIR_DoneWithCustomAction, /*Fn*/GIMT_Encode2(GICXXCustomAction_GICombiner0),
160+
// CHECK-NEXT: /* 499 */ // Label 10: @499
161+
// CHECK-NEXT: /* 499 */ GIM_Reject,
162+
// CHECK-NEXT: /* 500 */ // Label 5: @500
163+
// CHECK-NEXT: /* 500 */ GIM_Reject,
164+
// CHECK-NEXT: /* 501 */ }; // Size: 501 bytes
142165
// CHECK-NEXT: return MatchTable0;
143166
// CHECK-NEXT: }

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

+33-1
Original file line numberDiff line numberDiff line change
@@ -283,6 +283,33 @@ def matchdata_without_cxx_apply : GICombineRule<
283283
(match (G_ZEXT $dst, $src):$mi),
284284
(apply (G_MUL $dst, $src, $src))>;
285285

286+
// CHECK: :[[@LINE+1]]:{{[0-9]+}}: error: Expected both a 'match' and 'apply' action in combine rule, or a single 'combine' action
287+
def missing_apply : GICombineRule<
288+
(defs root:$dst),
289+
(match (G_ZEXT $dst, $src))>;
290+
291+
// CHECK: :[[@LINE+1]]:{{[0-9]+}}: error: 'combine' action needs at least one pattern to match, and C++ code to apply
292+
def combineop_missing_cxx : GICombineRule<
293+
(defs root:$d),
294+
(combine (wip_match_opcode G_TRUNC):$d)>;
295+
296+
// CHECK: :[[@LINE+1]]:{{[0-9]+}}: error: 'combine' action needs at least one pattern to match, and C++ code to apply
297+
def combineop_missing_mir : GICombineRule<
298+
(defs root:$d),
299+
(combine "return APPLY;")>;
300+
301+
// CHECK: :[[@LINE+1]]:{{[0-9]+}}: error: Expected both a 'match' and 'apply' action in combine rule, or a single 'combine' action
302+
def mixed_combine_match : GICombineRule<
303+
(defs root:$d),
304+
(combine (G_ZEXT $d, $y), "return APPLY;"),
305+
(match (G_ZEXT $d, $y))>;
306+
307+
// CHECK: :[[@LINE+1]]:{{[0-9]+}}: error: Expected both a 'match' and 'apply' action in combine rule, or a single 'combine' action
308+
def mixed_combine_apply : GICombineRule<
309+
(defs root:$d),
310+
(combine "return APPLY;"),
311+
(apply (G_ZEXT $d, $y))>;
312+
286313
// CHECK: error: Failed to parse one or more rules
287314

288315
def MyCombiner: GICombiner<"GenMyCombiner", [
@@ -326,5 +353,10 @@ def MyCombiner: GICombiner<"GenMyCombiner", [
326353
using_flagref_in_match,
327354
badflagref_in_apply,
328355
mixed_cxx_apply,
329-
matchdata_without_cxx_apply
356+
matchdata_without_cxx_apply,
357+
missing_apply,
358+
combineop_missing_cxx,
359+
combineop_missing_mir,
360+
mixed_combine_match,
361+
mixed_combine_apply
330362
]>;

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

+34-1
Original file line numberDiff line numberDiff line change
@@ -383,6 +383,37 @@ def IntrinTest1 : GICombineRule<
383383
(match (int_convergent_1in_1out $a, $b)),
384384
(apply (int_convergent_sideeffects_1in_1out $a, $b))>;
385385

386+
// CHECK: (CombineRule name:CombineOperator0 id:14 root:d
387+
// CHECK-NEXT: (MatchPats
388+
// CHECK-NEXT: <match_root>d:(AnyOpcodePattern [G_TRUNC])
389+
// CHECK-NEXT: )
390+
// CHECK-NEXT: (ApplyPats
391+
// CHECK-NEXT: __CombineOperator0_combine_1:(CXXPattern apply code:"return APPLY;")
392+
// CHECK-NEXT: )
393+
// CHECK-NEXT: (OperandTable MatchPats <empty>)
394+
// CHECK-NEXT: (OperandTable ApplyPats <empty>)
395+
// CHECK-NEXT: )
396+
def CombineOperator0 : GICombineRule<
397+
(defs root:$d),
398+
(combine (wip_match_opcode G_TRUNC):$d, "return APPLY;")>;
399+
400+
// CHECK: (CombineRule name:CombineOperator1 id:15 root:a
401+
// CHECK-NEXT: (MatchPats
402+
// CHECK-NEXT: <match_root>__CombineOperator1_combine_0:(CodeGenInstructionPattern G_TRUNC operands:[<def>$a, $b])
403+
// CHECK-NEXT: )
404+
// CHECK-NEXT: (ApplyPats
405+
// CHECK-NEXT: __CombineOperator1_combine_1:(CXXPattern apply code:"return APPLY ${a} ${b};")
406+
// CHECK-NEXT: )
407+
// CHECK-NEXT: (OperandTable MatchPats
408+
// CHECK-NEXT: a -> __CombineOperator1_combine_0
409+
// CHECK-NEXT: b -> <live-in>
410+
// CHECK-NEXT: )
411+
// CHECK-NEXT: (OperandTable ApplyPats <empty>)
412+
// CHECK-NEXT: )
413+
def CombineOperator1 : GICombineRule<
414+
(defs root:$a),
415+
(combine (G_TRUNC $a, $b), "return APPLY ${a} ${b};")>;
416+
386417
def MyCombiner: GICombiner<"GenMyCombiner", [
387418
WipOpcodeTest0,
388419
WipOpcodeTest1,
@@ -397,5 +428,7 @@ def MyCombiner: GICombiner<"GenMyCombiner", [
397428
TypeOfTest,
398429
MIFlagsTest,
399430
IntrinTest0,
400-
IntrinTest1
431+
IntrinTest1,
432+
CombineOperator0,
433+
CombineOperator1
401434
]>;

0 commit comments

Comments
 (0)