Skip to content

Commit 0a59e1a

Browse files
committed
[GlobalIsSel] Allow using PatFrags with multiple defs as the root of a combine rule
I had to tighten the restrictions on PatFrags a bit to make it consistent: instructions that define the root of a PF can only have one def. Reviewed By: arsenm Differential Revision: https://reviews.llvm.org/D157700
1 parent 3515409 commit 0a59e1a

File tree

5 files changed

+75
-17
lines changed

5 files changed

+75
-17
lines changed

llvm/docs/GlobalISel/MIRPatterns.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,8 @@ This a non-exhaustive list of known issues with MIR patterns at this time.
110110
* Matching intrinsics is not yet possible.
111111
* Using ``GICombinePatFrag`` within another ``GICombinePatFrag`` is not
112112
supported.
113+
* ``GICombinePatFrag`` can only have a single root.
114+
* Instructions with multiple defs cannot be the root of a ``GICombinePatFrag``.
113115
* Using ``GICombinePatFrag`` in the ``apply`` pattern of a ``GICombineRule``
114116
is not supported.
115117
* Deleting the matched pattern in a ``GICombineRule`` needs to be done using

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

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -160,12 +160,15 @@ def copy_prop : GICombineRule<
160160
// Fold (freeze (freeze x)) -> (freeze x).
161161
// Fold (fabs (fabs x)) -> (fabs x).
162162
// Fold (fcanonicalize (fcanonicalize x)) -> (fcanonicalize x).
163+
def idempotent_prop_frags : GICombinePatFrag<
164+
(outs root:$dst, $src), (ins),
165+
!foreach(op, [G_FREEZE, G_FABS, G_FCANONICALIZE],
166+
(pattern (op $dst, $src), (op $src, $x)))>;
167+
163168
def idempotent_prop : GICombineRule<
164-
(defs root:$mi),
165-
(match (wip_match_opcode G_FREEZE, G_FABS, G_FCANONICALIZE):$mi,
166-
[{ return MRI.getVRegDef(${mi}->getOperand(1).getReg())->getOpcode() ==
167-
${mi}->getOpcode(); }]),
168-
(apply [{ Helper.replaceSingleDefInstWithOperand(*${mi}, 1); }])>;
169+
(defs root:$dst),
170+
(match (idempotent_prop_frags $dst, $src)),
171+
(apply (COPY $dst, $src))>;
169172

170173

171174
def extending_loads : GICombineRule<

llvm/test/TableGen/GlobalISelCombinerMatchTableEmitter/patfrag-errors.td

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -257,6 +257,20 @@ def inconsistent_arg_type : GICombineRule<
257257
(match (TypedParams $dst, i64:$k):$broken),
258258
(apply (COPY $dst, (i32 0)))>;
259259

260+
// CHECK: :[[@LINE+2]]:{{[0-9]+}}: error: all instructions that define root 'foo' in 'RootDefHasMultiDefs' can only have a single output operand
261+
// CHECK: :[[@LINE+1]]:{{[0-9]+}}: error: Could not parse GICombinePatFrag 'RootDefHasMultiDefs'
262+
def RootDefHasMultiDefs: GICombinePatFrag<
263+
(outs root:$foo),
264+
(ins gi_imm:$cst),
265+
[
266+
(pattern (G_UNMERGE_VALUES $foo, $z, $y))
267+
]>;
268+
// CHECK: :[[@LINE+1]]:{{[0-9]+}}: error: Failed to parse pattern: '(RootDefHasMultiDefs ?:$root, (i32 10))'
269+
def root_def_has_multi_defs : GICombineRule<
270+
(defs root:$root),
271+
(match (RootDefHasMultiDefs $root, (i32 10))),
272+
(apply (COPY $root, (i32 0)))>;
273+
260274
// CHECK: error: Failed to parse one or more rules
261275

262276
def MyCombiner: GICombinerHelper<"GenMyCombiner", [
@@ -278,5 +292,6 @@ def MyCombiner: GICombinerHelper<"GenMyCombiner", [
278292
expected_mo_namedimm,
279293
patfrag_in_apply,
280294
patfrag_cannot_be_root,
281-
inconsistent_arg_type
295+
inconsistent_arg_type,
296+
root_def_has_multi_defs
282297
]>;

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

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -119,14 +119,13 @@ def undef_in_apply : GICombineRule<
119119
(match (COPY $a, $b):$d),
120120
(apply (COPY $a, $x))>;
121121

122-
// CHECK: :[[@LINE+2]]:{{[0-9]+}}: error: def of pattern root 'a' is not redefined in the apply pattern!
123-
// CHECK: :[[@LINE+1]]:{{[0-9]+}}: note: match pattern root is 'foo'
122+
// CHECK: :[[@LINE+1]]:{{[0-9]+}}: error: 'a' must be redefined in the 'apply' pattern
124123
def no_redef_in_apply : GICombineRule<
125124
(defs root:$a),
126125
(match (COPY $a, $b):$foo),
127126
(apply (COPY $x, $b))>;
128127

129-
// CHECK: :[[@LINE+1]]:{{[0-9]+}}: error: def of pattern root 'b' is not redefined in the apply pattern!
128+
// CHECK: :[[@LINE+1]]:{{[0-9]+}}: error: 'b' must be redefined in the 'apply' pattern
130129
def no_redef_in_apply_multidefroot : GICombineRule<
131130
(defs root:$a),
132131
(match (G_UNMERGE_VALUES $a, $b, $c)),

llvm/utils/TableGen/GlobalISelCombinerMatchTableEmitter.cpp

Lines changed: 47 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -581,6 +581,16 @@ class InstructionPattern : public Pattern {
581581
InstructionOperand &getOperand(unsigned K) { return Operands[K]; }
582582
const InstructionOperand &getOperand(unsigned K) const { return Operands[K]; }
583583

584+
/// When this InstructionPattern is used as the match root, returns the
585+
/// operands that must be redefined in the 'apply' pattern for the rule to be
586+
/// valid.
587+
///
588+
/// For CodeGenInstructionPatterns, this just returns the defs of the CGI.
589+
/// For PatFrag this only returns the root of the PF.
590+
///
591+
/// Returns an empty array on error.
592+
virtual ArrayRef<InstructionOperand> getApplyDefsNeeded() const = 0;
593+
584594
auto named_operands() {
585595
return make_filter_range(Operands,
586596
[&](auto &O) { return O.isNamedOperand(); });
@@ -760,6 +770,8 @@ class CodeGenInstructionPattern : public InstructionPattern {
760770
unsigned getNumInstDefs() const override;
761771
unsigned getNumInstOperands() const override;
762772

773+
ArrayRef<InstructionOperand> getApplyDefsNeeded() const override;
774+
763775
const CodeGenInstruction &getInst() const { return I; }
764776
StringRef getInstName() const override { return I.TheDef->getName(); }
765777

@@ -798,6 +810,11 @@ unsigned CodeGenInstructionPattern::getNumInstOperands() const {
798810
: NumCGIOps;
799811
}
800812

813+
ArrayRef<InstructionOperand>
814+
CodeGenInstructionPattern::getApplyDefsNeeded() const {
815+
return {operands().begin(), getNumInstDefs()};
816+
}
817+
801818
//===- OperandTypeChecker -------------------------------------------------===//
802819

803820
/// This is a trivial type checker for all operands in a set of
@@ -1078,12 +1095,24 @@ bool PatFrag::checkSemantics() {
10781095

10791096
// Check this operand is defined in all alternative's patterns.
10801097
for (const auto &Alt : Alts) {
1081-
if (!Alt.OpTable.getDef(Op.Name)) {
1098+
const auto *OpDef = Alt.OpTable.getDef(Op.Name);
1099+
if (!OpDef) {
10821100
PrintError("output parameter '" + Op.Name +
10831101
"' must be defined by all alternative patterns in '" +
10841102
Def.getName() + "'");
10851103
return false;
10861104
}
1105+
1106+
if (Op.Kind == PK_Root && OpDef->getNumInstDefs() != 1) {
1107+
// The instruction that defines the root must have a single def.
1108+
// Otherwise we'd need to support multiple roots and it gets messy.
1109+
//
1110+
// e.g. this is not supported:
1111+
// (pattern (G_UNMERGE_VALUES $x, $root, $vec))
1112+
PrintError("all instructions that define root '" + Op.Name + "' in '" +
1113+
Def.getName() + "' can only have a single output operand");
1114+
return false;
1115+
}
10871116
}
10881117

10891118
SeenOps.insert(Op.Name);
@@ -1232,6 +1261,8 @@ class PatFragPattern : public InstructionPattern {
12321261
unsigned getNumInstDefs() const override { return PF.num_out_params(); }
12331262
unsigned getNumInstOperands() const override { return PF.num_params(); }
12341263

1264+
ArrayRef<InstructionOperand> getApplyDefsNeeded() const override;
1265+
12351266
bool checkSemantics(ArrayRef<SMLoc> DiagLoc) override;
12361267

12371268
/// Before emitting the patterns inside the PatFrag, add all necessary code
@@ -1258,6 +1289,16 @@ class PatFragPattern : public InstructionPattern {
12581289
const PatFrag &PF;
12591290
};
12601291

1292+
ArrayRef<InstructionOperand> PatFragPattern::getApplyDefsNeeded() const {
1293+
assert(PF.num_roots() == 1);
1294+
// Only roots need to be redef.
1295+
for (auto [Idx, Param] : enumerate(PF.out_params())) {
1296+
if (Param.Kind == PatFrag::PK_Root)
1297+
return getOperand(Idx);
1298+
}
1299+
llvm_unreachable("root not found!");
1300+
}
1301+
12611302
bool PatFragPattern::checkSemantics(ArrayRef<SMLoc> DiagLoc) {
12621303
if (!InstructionPattern::checkSemantics(DiagLoc))
12631304
return false;
@@ -1990,16 +2031,14 @@ bool CombineRuleBuilder::findRoots() {
19902031

19912032
// Collect all redefinitions of the MatchRoot's defs and put them in
19922033
// ApplyRoots.
1993-
for (unsigned K = 0; K < IPRoot->getNumInstDefs(); ++K) {
1994-
auto &O = IPRoot->getOperand(K);
1995-
assert(O.isDef() && O.isNamedOperand());
1996-
StringRef Name = O.getOperandName();
2034+
const auto DefsNeeded = IPRoot->getApplyDefsNeeded();
2035+
for (auto &Op : DefsNeeded) {
2036+
assert(Op.isDef() && Op.isNamedOperand());
2037+
StringRef Name = Op.getOperandName();
19972038

19982039
auto *ApplyRedef = ApplyOpTable.getDef(Name);
19992040
if (!ApplyRedef) {
2000-
PrintError("def of pattern root '" + Name +
2001-
"' is not redefined in the apply pattern!");
2002-
PrintNote("match pattern root is '" + MatchRoot->getName() + "'");
2041+
PrintError("'" + Name + "' must be redefined in the 'apply' pattern");
20032042
return false;
20042043
}
20052044

0 commit comments

Comments
 (0)