[GlobalISel] Add combine action for C++ combine rules (#135941)
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
This commit is contained in:
committed by
GitHub
parent
6738cfe0a4
commit
c792b25e47
@@ -74,7 +74,7 @@ Operands are ordered just like they would be in a MachineInstr: the defs (outs)
|
||||
come first, then the uses (ins).
|
||||
|
||||
Patterns are generally grouped into another DAG datatype with a dummy operator
|
||||
such as ``match``, ``apply`` or ``pattern``.
|
||||
such as ``match``, ``apply``, ``combine`` or ``pattern``.
|
||||
|
||||
Finally, any DAG datatype in TableGen can be named. This also holds for
|
||||
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:
|
||||
(match (G_ZEXT $root, $src):$mi),
|
||||
(apply "foobar(${root}.getReg(), ${src}.getReg(), ${mi}->hasImplicitDef())")>;
|
||||
|
||||
``combine`` Operator
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
``GICombineRule`` also supports a single ``combine`` pattern, which is a shorter way to
|
||||
declare patterns that just match one or more instructions, then defer all remaining matching
|
||||
and rewriting logic to C++ code.
|
||||
|
||||
.. code-block:: text
|
||||
:caption: Example usage of the combine operator.
|
||||
|
||||
// match + apply
|
||||
def FooLong : GICombineRule<
|
||||
(defs root:$root),
|
||||
(match (G_ZEXT $root, $src):$mi, "return matchFoo(${mi});"),
|
||||
(apply "applyFoo(${mi});")>;
|
||||
|
||||
// combine
|
||||
def FooShort : GICombineRule<
|
||||
(defs root:$root),
|
||||
(combine (G_ZEXT $root, $src):$mi, "return combineFoo(${mi});")>;
|
||||
|
||||
This has a couple of advantages:
|
||||
|
||||
* We only need one C++ function, not two.
|
||||
* We no longer need to use ``GIDefMatchData`` to pass information between the match/apply functions.
|
||||
|
||||
As described above, this is syntactic sugar for the match+apply form. In a ``combine`` pattern:
|
||||
|
||||
* Everything except C++ code is considered the ``match`` part.
|
||||
* The C++ code is the ``apply`` part. C++ code is emitted in order of appearance.
|
||||
|
||||
.. note::
|
||||
|
||||
The C++ code **must** return true if it changed any instruction. Returning false when changing
|
||||
instructions is undefined behavior.
|
||||
|
||||
Common Pattern #1: Replace a Register with Another
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
||||
@@ -31,6 +31,8 @@ def defs;
|
||||
def pattern;
|
||||
def match;
|
||||
def apply;
|
||||
def combine;
|
||||
def empty_action;
|
||||
|
||||
def wip_match_opcode;
|
||||
|
||||
@@ -67,18 +69,17 @@ class GIDefMatchData<string type> {
|
||||
string Type = type;
|
||||
}
|
||||
|
||||
class GICombineRule<dag defs, dag match, dag apply> : GICombine {
|
||||
class GICombineRule<dag defs, dag a0, dag a1 = (empty_action)> : GICombine {
|
||||
/// Defines the external interface of the match rule. This includes:
|
||||
/// * The names of the root nodes (requires at least one)
|
||||
/// See GIDefKind for details.
|
||||
dag Defs = defs;
|
||||
|
||||
/// Defines the things which must be true for the pattern to match
|
||||
dag Match = match;
|
||||
|
||||
/// Defines the things which happen after the decision is made to apply a
|
||||
/// combine rule.
|
||||
dag Apply = apply;
|
||||
// The patterns that will be used. Two types of list can exist:
|
||||
// match (Action0) + apply (Action1).
|
||||
// combine (Action0) + empty_action (Action1).
|
||||
dag Action0 = a0;
|
||||
dag Action1 = a1;
|
||||
|
||||
/// Defines the predicates that are checked before the match function
|
||||
/// is called. Targets can use this to, for instance, check Subtarget
|
||||
|
||||
@@ -28,11 +28,16 @@ def NoMatchTwoApply : GICombineRule<
|
||||
(match (G_SEXT $a, $y)),
|
||||
(apply "APPLY0", "APPLY1")>;
|
||||
|
||||
def CombineCXXOrder : GICombineRule<
|
||||
(defs root:$a),
|
||||
(combine (G_ZEXT $a, $y), "A0", "return A1")>;
|
||||
|
||||
def MyCombiner: GICombiner<"GenMyCombiner", [
|
||||
OneMatchOneApply,
|
||||
TwoMatchTwoApply,
|
||||
TwoMatchNoApply,
|
||||
NoMatchTwoApply
|
||||
NoMatchTwoApply,
|
||||
CombineCXXOrder
|
||||
]>;
|
||||
|
||||
// CHECK: bool GenMyCombiner::testMIPredicate_MI(unsigned PredicateID, const MachineInstr & MI, const MatcherState &State) const {
|
||||
@@ -79,65 +84,83 @@ def MyCombiner: GICombiner<"GenMyCombiner", [
|
||||
// CHECK-NEXT: APPLY1
|
||||
// CHECK-NEXT: return true;
|
||||
// CHECK-NEXT: }
|
||||
// CHECK-NEXT: case GICXXCustomAction_GICombiner3:{
|
||||
// CHECK-NEXT: // Apply Patterns
|
||||
// CHECK-NEXT: A0
|
||||
// CHECK-NEXT: return A1
|
||||
// CHECK-NEXT: return true;
|
||||
// CHECK-NEXT: }
|
||||
// CHECK-NEXT: }
|
||||
// CHECK-NEXT: llvm_unreachable("Unknown Apply Action");
|
||||
// CHECK-NEXT: }
|
||||
|
||||
// CHECK: const uint8_t *GenMyCombiner::getMatchTable() const {
|
||||
// CHECK-NEXT: constexpr static uint8_t MatchTable0[] = {
|
||||
// CHECK-NEXT: GIM_SwitchOpcode, /*MI*/0, /*[*/GIMT_Encode2([[#LOWER:]]), GIMT_Encode2([[#UPPER:]]), /*)*//*default:*//*Label 4*/ GIMT_Encode4([[#DEFAULT:]]),
|
||||
// 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),
|
||||
// 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),
|
||||
// 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),
|
||||
// CHECK-NEXT: /*TargetOpcode::G_FABS*//*Label 3*/ GIMT_Encode4([[L460:[0-9]+]]),
|
||||
// CHECK-NEXT: // Label 0: @[[#%u, mul(UPPER-LOWER, 4) + 10]]
|
||||
// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label 5*/ GIMT_Encode4([[L435:[0-9]+]]), // Rule ID 2 //
|
||||
// CHECK-NEXT: GIM_CheckSimplePredicate, GIMT_Encode2(GICXXPred_Simple_IsRule2Enabled),
|
||||
// CHECK-NEXT: // MIs[0] x
|
||||
// CHECK-NEXT: // No operand predicates
|
||||
// CHECK-NEXT: // MIs[0] y
|
||||
// CHECK-NEXT: // No operand predicates
|
||||
// CHECK-NEXT: GIM_CheckCxxInsnPredicate, /*MI*/0, /*FnId*/GIMT_Encode2(GICXXPred_MI_Predicate_GICombiner0),
|
||||
// CHECK-NEXT: GIM_CheckCxxInsnPredicate, /*MI*/0, /*FnId*/GIMT_Encode2(GICXXPred_MI_Predicate_GICombiner1),
|
||||
// CHECK-NEXT: // Combiner Rule #2: TwoMatchNoApply
|
||||
// CHECK-NEXT: GIR_EraseRootFromParent_Done,
|
||||
// CHECK-NEXT: // Label 5: @[[L435]]
|
||||
// CHECK-NEXT: GIM_Reject,
|
||||
// CHECK-NEXT: // Label 1: @[[L436]]
|
||||
// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label 6*/ GIMT_Encode4([[L447:[0-9]+]]), // Rule ID 3 //
|
||||
// CHECK-NEXT: GIM_CheckSimplePredicate, GIMT_Encode2(GICXXPred_Simple_IsRule3Enabled),
|
||||
// CHECK-NEXT: // MIs[0] a
|
||||
// CHECK-NEXT: // No operand predicates
|
||||
// CHECK-NEXT: // MIs[0] y
|
||||
// CHECK-NEXT: // No operand predicates
|
||||
// CHECK-NEXT: // Combiner Rule #3: NoMatchTwoApply
|
||||
// CHECK-NEXT: GIR_DoneWithCustomAction, /*Fn*/GIMT_Encode2(GICXXCustomAction_GICombiner2),
|
||||
// CHECK-NEXT: // Label 6: @[[L447]]
|
||||
// CHECK-NEXT: GIM_Reject,
|
||||
// CHECK-NEXT: // Label 2: @[[L448]]
|
||||
// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label 7*/ GIMT_Encode4([[L459:[0-9]+]]), // Rule ID 1 //
|
||||
// CHECK-NEXT: GIM_CheckSimplePredicate, GIMT_Encode2(GICXXPred_Simple_IsRule1Enabled),
|
||||
// CHECK-NEXT: // MIs[0] a
|
||||
// CHECK-NEXT: // No operand predicates
|
||||
// CHECK-NEXT: // MIs[0] b
|
||||
// CHECK-NEXT: // No operand predicates
|
||||
// CHECK-NEXT: // Combiner Rule #1: TwoMatchTwoApply
|
||||
// CHECK-NEXT: GIR_DoneWithCustomAction, /*Fn*/GIMT_Encode2(GICXXCustomAction_GICombiner1),
|
||||
// CHECK-NEXT: // Label 7: @[[L459]]
|
||||
// CHECK-NEXT: GIM_Reject,
|
||||
// CHECK-NEXT: // Label 3: @[[L460]]
|
||||
// CHECK-NEXT: GIM_Try, /*On fail goto*//*Label 8*/ GIMT_Encode4([[L471:[0-9]+]]), // Rule ID 0 //
|
||||
// CHECK-NEXT: GIM_CheckSimplePredicate, GIMT_Encode2(GICXXPred_Simple_IsRule0Enabled),
|
||||
// CHECK-NEXT: // MIs[0] a
|
||||
// CHECK-NEXT: // No operand predicates
|
||||
// CHECK-NEXT: // MIs[0] b
|
||||
// CHECK-NEXT: // No operand predicates
|
||||
// CHECK-NEXT: // Combiner Rule #0: OneMatchOneApply
|
||||
// CHECK-NEXT: GIR_DoneWithCustomAction, /*Fn*/GIMT_Encode2(GICXXCustomAction_GICombiner0),
|
||||
// CHECK-NEXT: // Label 8: @[[L471]]
|
||||
// CHECK-NEXT: GIM_Reject,
|
||||
// CHECK-NEXT: // Label 4: @[[#%u, DEFAULT]]
|
||||
// CHECK-NEXT: GIM_Reject,
|
||||
// CHECK-NEXT: }; // Size: [[#%u, DEFAULT + 1]] bytes
|
||||
// CHECK-NEXT: /* 0 */ GIM_SwitchOpcode, /*MI*/0, /*[*/GIMT_Encode2(99), GIMT_Encode2(205), /*)*//*default:*//*Label 5*/ GIMT_Encode4(500),
|
||||
// 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),
|
||||
// CHECK-NEXT: /* 162 */ /*TargetOpcode::G_SEXT*//*Label 1*/ GIMT_Encode4(452), GIMT_Encode4(0),
|
||||
// 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),
|
||||
// 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),
|
||||
// CHECK-NEXT: /* 430 */ /*TargetOpcode::G_FABS*//*Label 4*/ GIMT_Encode4(488),
|
||||
// CHECK-NEXT: /* 434 */ // Label 0: @434
|
||||
// CHECK-NEXT: /* 434 */ GIM_Try, /*On fail goto*//*Label 6*/ GIMT_Encode4(451), // Rule ID 2 //
|
||||
// CHECK-NEXT: /* 439 */ GIM_CheckSimplePredicate, GIMT_Encode2(GICXXPred_Simple_IsRule2Enabled),
|
||||
// CHECK-NEXT: /* 442 */ // MIs[0] x
|
||||
// CHECK-NEXT: /* 442 */ // No operand predicates
|
||||
// CHECK-NEXT: /* 442 */ // MIs[0] y
|
||||
// CHECK-NEXT: /* 442 */ // No operand predicates
|
||||
// CHECK-NEXT: /* 442 */ GIM_CheckCxxInsnPredicate, /*MI*/0, /*FnId*/GIMT_Encode2(GICXXPred_MI_Predicate_GICombiner0),
|
||||
// CHECK-NEXT: /* 446 */ GIM_CheckCxxInsnPredicate, /*MI*/0, /*FnId*/GIMT_Encode2(GICXXPred_MI_Predicate_GICombiner1),
|
||||
// CHECK-NEXT: /* 450 */ // Combiner Rule #2: TwoMatchNoApply
|
||||
// CHECK-NEXT: /* 450 */ GIR_EraseRootFromParent_Done,
|
||||
// CHECK-NEXT: /* 451 */ // Label 6: @451
|
||||
// CHECK-NEXT: /* 451 */ GIM_Reject,
|
||||
// CHECK-NEXT: /* 452 */ // Label 1: @452
|
||||
// CHECK-NEXT: /* 452 */ GIM_Try, /*On fail goto*//*Label 7*/ GIMT_Encode4(463), // Rule ID 3 //
|
||||
// CHECK-NEXT: /* 457 */ GIM_CheckSimplePredicate, GIMT_Encode2(GICXXPred_Simple_IsRule3Enabled),
|
||||
// CHECK-NEXT: /* 460 */ // MIs[0] a
|
||||
// CHECK-NEXT: /* 460 */ // No operand predicates
|
||||
// CHECK-NEXT: /* 460 */ // MIs[0] y
|
||||
// CHECK-NEXT: /* 460 */ // No operand predicates
|
||||
// CHECK-NEXT: /* 460 */ // Combiner Rule #3: NoMatchTwoApply
|
||||
// CHECK-NEXT: /* 460 */ GIR_DoneWithCustomAction, /*Fn*/GIMT_Encode2(GICXXCustomAction_GICombiner2),
|
||||
// CHECK-NEXT: /* 463 */ // Label 7: @463
|
||||
// CHECK-NEXT: /* 463 */ GIM_Reject,
|
||||
// CHECK-NEXT: /* 464 */ // Label 2: @464
|
||||
// CHECK-NEXT: /* 464 */ GIM_Try, /*On fail goto*//*Label 8*/ GIMT_Encode4(475), // Rule ID 4 //
|
||||
// CHECK-NEXT: /* 469 */ GIM_CheckSimplePredicate, GIMT_Encode2(GICXXPred_Simple_IsRule4Enabled),
|
||||
// CHECK-NEXT: /* 472 */ // MIs[0] a
|
||||
// CHECK-NEXT: /* 472 */ // No operand predicates
|
||||
// CHECK-NEXT: /* 472 */ // MIs[0] y
|
||||
// CHECK-NEXT: /* 472 */ // No operand predicates
|
||||
// CHECK-NEXT: /* 472 */ // Combiner Rule #4: CombineCXXOrder
|
||||
// CHECK-NEXT: /* 472 */ GIR_DoneWithCustomAction, /*Fn*/GIMT_Encode2(GICXXCustomAction_GICombiner3),
|
||||
// CHECK-NEXT: /* 475 */ // Label 8: @475
|
||||
// CHECK-NEXT: /* 475 */ GIM_Reject,
|
||||
// CHECK-NEXT: /* 476 */ // Label 3: @476
|
||||
// CHECK-NEXT: /* 476 */ GIM_Try, /*On fail goto*//*Label 9*/ GIMT_Encode4(487), // Rule ID 1 //
|
||||
// CHECK-NEXT: /* 481 */ GIM_CheckSimplePredicate, GIMT_Encode2(GICXXPred_Simple_IsRule1Enabled),
|
||||
// CHECK-NEXT: /* 484 */ // MIs[0] a
|
||||
// CHECK-NEXT: /* 484 */ // No operand predicates
|
||||
// CHECK-NEXT: /* 484 */ // MIs[0] b
|
||||
// CHECK-NEXT: /* 484 */ // No operand predicates
|
||||
// CHECK-NEXT: /* 484 */ // Combiner Rule #1: TwoMatchTwoApply
|
||||
// CHECK-NEXT: /* 484 */ GIR_DoneWithCustomAction, /*Fn*/GIMT_Encode2(GICXXCustomAction_GICombiner1),
|
||||
// CHECK-NEXT: /* 487 */ // Label 9: @487
|
||||
// CHECK-NEXT: /* 487 */ GIM_Reject,
|
||||
// CHECK-NEXT: /* 488 */ // Label 4: @488
|
||||
// CHECK-NEXT: /* 488 */ GIM_Try, /*On fail goto*//*Label 10*/ GIMT_Encode4(499), // Rule ID 0 //
|
||||
// CHECK-NEXT: /* 493 */ GIM_CheckSimplePredicate, GIMT_Encode2(GICXXPred_Simple_IsRule0Enabled),
|
||||
// CHECK-NEXT: /* 496 */ // MIs[0] a
|
||||
// CHECK-NEXT: /* 496 */ // No operand predicates
|
||||
// CHECK-NEXT: /* 496 */ // MIs[0] b
|
||||
// CHECK-NEXT: /* 496 */ // No operand predicates
|
||||
// CHECK-NEXT: /* 496 */ // Combiner Rule #0: OneMatchOneApply
|
||||
// CHECK-NEXT: /* 496 */ GIR_DoneWithCustomAction, /*Fn*/GIMT_Encode2(GICXXCustomAction_GICombiner0),
|
||||
// CHECK-NEXT: /* 499 */ // Label 10: @499
|
||||
// CHECK-NEXT: /* 499 */ GIM_Reject,
|
||||
// CHECK-NEXT: /* 500 */ // Label 5: @500
|
||||
// CHECK-NEXT: /* 500 */ GIM_Reject,
|
||||
// CHECK-NEXT: /* 501 */ }; // Size: 501 bytes
|
||||
// CHECK-NEXT: return MatchTable0;
|
||||
// CHECK-NEXT: }
|
||||
|
||||
@@ -283,6 +283,33 @@ def matchdata_without_cxx_apply : GICombineRule<
|
||||
(match (G_ZEXT $dst, $src):$mi),
|
||||
(apply (G_MUL $dst, $src, $src))>;
|
||||
|
||||
// CHECK: :[[@LINE+1]]:{{[0-9]+}}: error: expected both a 'match' and 'apply' action in combine rule, or a single 'combine' action
|
||||
def missing_apply : GICombineRule<
|
||||
(defs root:$dst),
|
||||
(match (G_ZEXT $dst, $src))>;
|
||||
|
||||
// CHECK: :[[@LINE+1]]:{{[0-9]+}}: error: 'combine' action needs at least one pattern to match, and C++ code to apply
|
||||
def combineop_missing_cxx : GICombineRule<
|
||||
(defs root:$d),
|
||||
(combine (wip_match_opcode G_TRUNC):$d)>;
|
||||
|
||||
// CHECK: :[[@LINE+1]]:{{[0-9]+}}: error: 'combine' action needs at least one pattern to match, and C++ code to apply
|
||||
def combineop_missing_mir : GICombineRule<
|
||||
(defs root:$d),
|
||||
(combine "return APPLY;")>;
|
||||
|
||||
// CHECK: :[[@LINE+1]]:{{[0-9]+}}: error: expected both a 'match' and 'apply' action in combine rule, or a single 'combine' action
|
||||
def mixed_combine_match : GICombineRule<
|
||||
(defs root:$d),
|
||||
(combine (G_ZEXT $d, $y), "return APPLY;"),
|
||||
(match (G_ZEXT $d, $y))>;
|
||||
|
||||
// CHECK: :[[@LINE+1]]:{{[0-9]+}}: error: expected both a 'match' and 'apply' action in combine rule, or a single 'combine' action
|
||||
def mixed_combine_apply : GICombineRule<
|
||||
(defs root:$d),
|
||||
(combine "return APPLY;"),
|
||||
(apply (G_ZEXT $d, $y))>;
|
||||
|
||||
// CHECK: error: Failed to parse one or more rules
|
||||
|
||||
def MyCombiner: GICombiner<"GenMyCombiner", [
|
||||
@@ -326,5 +353,10 @@ def MyCombiner: GICombiner<"GenMyCombiner", [
|
||||
using_flagref_in_match,
|
||||
badflagref_in_apply,
|
||||
mixed_cxx_apply,
|
||||
matchdata_without_cxx_apply
|
||||
matchdata_without_cxx_apply,
|
||||
missing_apply,
|
||||
combineop_missing_cxx,
|
||||
combineop_missing_mir,
|
||||
mixed_combine_match,
|
||||
mixed_combine_apply
|
||||
]>;
|
||||
|
||||
@@ -383,6 +383,37 @@ def IntrinTest1 : GICombineRule<
|
||||
(match (int_convergent_1in_1out $a, $b)),
|
||||
(apply (int_convergent_sideeffects_1in_1out $a, $b))>;
|
||||
|
||||
// CHECK: (CombineRule name:CombineOperator0 id:14 root:d
|
||||
// CHECK-NEXT: (MatchPats
|
||||
// CHECK-NEXT: <match_root>d:(AnyOpcodePattern [G_TRUNC])
|
||||
// CHECK-NEXT: )
|
||||
// CHECK-NEXT: (ApplyPats
|
||||
// CHECK-NEXT: __CombineOperator0_combine_1:(CXXPattern apply code:"return APPLY;")
|
||||
// CHECK-NEXT: )
|
||||
// CHECK-NEXT: (OperandTable MatchPats <empty>)
|
||||
// CHECK-NEXT: (OperandTable ApplyPats <empty>)
|
||||
// CHECK-NEXT: )
|
||||
def CombineOperator0 : GICombineRule<
|
||||
(defs root:$d),
|
||||
(combine (wip_match_opcode G_TRUNC):$d, "return APPLY;")>;
|
||||
|
||||
// CHECK: (CombineRule name:CombineOperator1 id:15 root:a
|
||||
// CHECK-NEXT: (MatchPats
|
||||
// CHECK-NEXT: <match_root>__CombineOperator1_combine_0:(CodeGenInstructionPattern G_TRUNC operands:[<def>$a, $b])
|
||||
// CHECK-NEXT: )
|
||||
// CHECK-NEXT: (ApplyPats
|
||||
// CHECK-NEXT: __CombineOperator1_combine_1:(CXXPattern apply code:"return APPLY ${a} ${b};")
|
||||
// CHECK-NEXT: )
|
||||
// CHECK-NEXT: (OperandTable MatchPats
|
||||
// CHECK-NEXT: a -> __CombineOperator1_combine_0
|
||||
// CHECK-NEXT: b -> <live-in>
|
||||
// CHECK-NEXT: )
|
||||
// CHECK-NEXT: (OperandTable ApplyPats <empty>)
|
||||
// CHECK-NEXT: )
|
||||
def CombineOperator1 : GICombineRule<
|
||||
(defs root:$a),
|
||||
(combine (G_TRUNC $a, $b), "return APPLY ${a} ${b};")>;
|
||||
|
||||
def MyCombiner: GICombiner<"GenMyCombiner", [
|
||||
WipOpcodeTest0,
|
||||
WipOpcodeTest1,
|
||||
@@ -397,5 +428,7 @@ def MyCombiner: GICombiner<"GenMyCombiner", [
|
||||
TypeOfTest,
|
||||
MIFlagsTest,
|
||||
IntrinTest0,
|
||||
IntrinTest1
|
||||
IntrinTest1,
|
||||
CombineOperator0,
|
||||
CombineOperator1
|
||||
]>;
|
||||
|
||||
@@ -798,17 +798,45 @@ bool CombineRuleBuilder::parseAll() {
|
||||
if (!parseDefs(*RuleDef.getValueAsDag("Defs")))
|
||||
return false;
|
||||
|
||||
if (!Parser.parsePatternList(
|
||||
*RuleDef.getValueAsDag("Match"),
|
||||
[this](auto Pat) { return addMatchPattern(std::move(Pat)); }, "match",
|
||||
(RuleDef.getName() + "_match").str()))
|
||||
return false;
|
||||
const DagInit &Act0 = *RuleDef.getValueAsDag("Action0");
|
||||
const DagInit &Act1 = *RuleDef.getValueAsDag("Action1");
|
||||
|
||||
if (!Parser.parsePatternList(
|
||||
*RuleDef.getValueAsDag("Apply"),
|
||||
[this](auto Pat) { return addApplyPattern(std::move(Pat)); }, "apply",
|
||||
(RuleDef.getName() + "_apply").str()))
|
||||
StringRef Act0Op = Act0.getOperatorAsDef(RuleDef.getLoc())->getName();
|
||||
StringRef Act1Op = Act1.getOperatorAsDef(RuleDef.getLoc())->getName();
|
||||
|
||||
if (Act0Op == "match" && Act1Op == "apply") {
|
||||
if (!Parser.parsePatternList(
|
||||
Act0, [this](auto Pat) { return addMatchPattern(std::move(Pat)); },
|
||||
"match", (RuleDef.getName() + "_match").str()))
|
||||
return false;
|
||||
|
||||
if (!Parser.parsePatternList(
|
||||
Act1, [this](auto Pat) { return addApplyPattern(std::move(Pat)); },
|
||||
"apply", (RuleDef.getName() + "_apply").str()))
|
||||
return false;
|
||||
|
||||
} else if (Act0Op == "combine" && Act1Op == "empty_action") {
|
||||
// combine: everything is a "match" except C++ code which is an apply.
|
||||
const auto AddCombinePat = [this](std::unique_ptr<Pattern> Pat) {
|
||||
if (isa<CXXPattern>(Pat.get()))
|
||||
return addApplyPattern(std::move(Pat));
|
||||
return addMatchPattern(std::move(Pat));
|
||||
};
|
||||
|
||||
if (!Parser.parsePatternList(Act0, AddCombinePat, "combine",
|
||||
(RuleDef.getName() + "_combine").str()))
|
||||
return false;
|
||||
|
||||
if (MatchPats.empty() || ApplyPats.empty()) {
|
||||
PrintError("'combine' action needs at least one pattern to match, and "
|
||||
"C++ code to apply");
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
PrintError("expected both a 'match' and 'apply' action in combine rule, "
|
||||
"or a single 'combine' action");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!buildRuleOperandsTable() || !typecheckPatterns() || !findRoots() ||
|
||||
!checkSemantics() || !buildPermutationsToEmit())
|
||||
@@ -1340,6 +1368,8 @@ bool CombineRuleBuilder::checkSemantics() {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Diagnose uses of MatchDatas if the Rule doesn't have C++ on both the
|
||||
// match and apply. It's useless in such cases.
|
||||
if (!hasOnlyCXXApplyPatterns() && !MatchDatas.empty()) {
|
||||
PrintError(MatchDataClassName +
|
||||
" can only be used if 'apply' in entirely written in C++");
|
||||
|
||||
Reference in New Issue
Block a user