1//===- Combine.td - Combine rule definitions ---------------*- tablegen -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// Declare GlobalISel combine rules and provide mechanisms to opt-out.
10//
11//===----------------------------------------------------------------------===//
12
13// Common base class for GICombineRule and GICombineGroup.
14class GICombine {
15  // See GICombineGroup. We only declare it here to make the tablegen pass
16  // simpler.
17  list<GICombine> Rules = ?;
18}
19
20// A group of combine rules that can be added to a GICombiner or another group.
21class GICombineGroup<list<GICombine> rules> : GICombine {
22  // The rules contained in this group. The rules in a group are flattened into
23  // a single list and sorted into whatever order is most efficient. However,
24  // they will never be re-ordered such that behaviour differs from the
25  // specified order. It is therefore possible to use the order of rules in this
26  // list to describe priorities.
27  let Rules = rules;
28}
29
30class GICombinerHelperArg<string type, string name> {
31  string Type = type;
32  string Name = name;
33}
34
35// Declares a combiner helper class
36class GICombinerHelper<string classname, list<GICombine> rules>
37    : GICombineGroup<rules> {
38  // The class name to use in the generated output.
39  string Classname = classname;
40  // The name of a run-time compiler option that will be generated to disable
41  // specific rules within this combiner.
42  string DisableRuleOption = ?;
43  // The state class to inherit from (if any). The generated helper will inherit
44  // from this class and will forward arguments to its constructors.
45  string StateClass = "";
46  // Any additional arguments that should be appended to the tryCombine*().
47  list<GICombinerHelperArg> AdditionalArguments =
48      [GICombinerHelperArg<"CombinerHelper &", "Helper">];
49}
50class GICombineRule<dag defs, dag match, dag apply> : GICombine {
51  /// Defines the external interface of the match rule. This includes:
52  /// * The names of the root nodes (requires at least one)
53  /// See GIDefKind for details.
54  dag Defs = defs;
55
56  /// Defines the things which must be true for the pattern to match
57  /// See GIMatchKind for details.
58  dag Match = match;
59
60  /// Defines the things which happen after the decision is made to apply a
61  /// combine rule.
62  /// See GIApplyKind for details.
63  dag Apply = apply;
64}
65
66/// The operator at the root of a GICombineRule.Defs dag.
67def defs;
68
69/// All arguments of the defs operator must be subclasses of GIDefKind or
70/// sub-dags whose operator is GIDefKindWithArgs.
71class GIDefKind;
72class GIDefKindWithArgs;
73/// Declare a root node. There must be at least one of these in every combine
74/// rule.
75/// TODO: The plan is to elide `root` definitions and determine it from the DAG
76///       itself with an overide for situations where the usual determination
77///       is incorrect.
78def root : GIDefKind;
79
80/// Declares data that is passed from the match stage to the apply stage.
81class GIDefMatchData<string type> : GIDefKind {
82  /// A C++ type name indicating the storage type.
83  string Type = type;
84}
85
86def extending_load_matchdata : GIDefMatchData<"PreferredTuple">;
87def indexed_load_store_matchdata : GIDefMatchData<"IndexedLoadStoreMatchInfo">;
88
89/// The operator at the root of a GICombineRule.Match dag.
90def match;
91/// All arguments of the match operator must be either:
92/// * A subclass of GIMatchKind
93/// * A subclass of GIMatchKindWithArgs
94/// * A subclass of Instruction
95/// * A MIR code block (deprecated)
96/// The GIMatchKind and GIMatchKindWithArgs cases are described in more detail
97/// in their definitions below.
98/// For the Instruction case, these are collected into a DAG where operand names
99/// that occur multiple times introduce edges.
100class GIMatchKind;
101class GIMatchKindWithArgs;
102
103/// In lieu of having proper macro support. Trivial one-off opcode checks can be
104/// performed with this.
105def wip_match_opcode : GIMatchKindWithArgs;
106
107/// The operator at the root of a GICombineRule.Apply dag.
108def apply;
109/// All arguments of the apply operator must be subclasses of GIApplyKind, or
110/// sub-dags whose operator is GIApplyKindWithArgs, or an MIR block
111/// (deprecated).
112class GIApplyKind;
113class GIApplyKindWithArgs;
114
115def copy_prop : GICombineRule<
116  (defs root:$d),
117  (match (COPY $d, $s):$mi,
118         [{ return Helper.matchCombineCopy(*${mi}); }]),
119  (apply [{ Helper.applyCombineCopy(*${mi}); }])>;
120
121def extending_loads : GICombineRule<
122  (defs root:$root, extending_load_matchdata:$matchinfo),
123  (match (wip_match_opcode G_LOAD, G_SEXTLOAD, G_ZEXTLOAD):$root,
124         [{ return Helper.matchCombineExtendingLoads(*${root}, ${matchinfo}); }]),
125  (apply [{ Helper.applyCombineExtendingLoads(*${root}, ${matchinfo}); }])>;
126def combines_for_extload: GICombineGroup<[extending_loads]>;
127
128def sext_already_extended : GICombineRule<
129  (defs root:$d),
130  (match (wip_match_opcode G_SEXT_INREG):$d,
131         [{ return Helper.matchSextAlreadyExtended(*${d}); }]),
132  (apply [{ Helper.applySextAlreadyExtended(*${d}); }])>;
133
134def combine_indexed_load_store : GICombineRule<
135  (defs root:$root, indexed_load_store_matchdata:$matchinfo),
136  (match (wip_match_opcode G_LOAD, G_SEXTLOAD, G_ZEXTLOAD, G_STORE):$root,
137         [{ return Helper.matchCombineIndexedLoadStore(*${root}, ${matchinfo}); }]),
138  (apply [{ Helper.applyCombineIndexedLoadStore(*${root}, ${matchinfo}); }])>;
139
140// FIXME: Is there a reason this wasn't in tryCombine? I've left it out of
141//        all_combines because it wasn't there.
142def elide_br_by_inverting_cond : GICombineRule<
143  (defs root:$root),
144  (match (wip_match_opcode G_BR):$root,
145         [{ return Helper.matchElideBrByInvertingCond(*${root}); }]),
146  (apply [{ Helper.applyElideBrByInvertingCond(*${root}); }])>;
147
148def ptr_add_immed_matchdata : GIDefMatchData<"PtrAddChain">;
149def ptr_add_immed_chain : GICombineRule<
150  (defs root:$d, ptr_add_immed_matchdata:$matchinfo),
151  (match (wip_match_opcode G_PTR_ADD):$d,
152         [{ return Helper.matchPtrAddImmedChain(*${d}, ${matchinfo}); }]),
153  (apply [{ Helper.applyPtrAddImmedChain(*${d}, ${matchinfo}); }])>;
154
155def mul_to_shl_matchdata : GIDefMatchData<"unsigned">;
156def mul_to_shl : GICombineRule<
157  (defs root:$d, mul_to_shl_matchdata:$matchinfo),
158  (match (G_MUL $d, $op1, $op2):$mi,
159         [{ return Helper.matchCombineMulToShl(*${mi}, ${matchinfo}); }]),
160  (apply [{ Helper.applyCombineMulToShl(*${mi}, ${matchinfo}); }])>;
161
162// [us]itofp(undef) = 0, because the result value is bounded.
163def undef_to_fp_zero : GICombineRule<
164  (defs root:$root),
165  (match (wip_match_opcode G_UITOFP, G_SITOFP):$root,
166         [{ return Helper.matchAnyExplicitUseIsUndef(*${root}); }]),
167  (apply [{ Helper.replaceInstWithFConstant(*${root}, 0.0); }])>;
168
169def undef_to_int_zero: GICombineRule<
170  (defs root:$root),
171  (match (wip_match_opcode G_AND, G_MUL):$root,
172         [{ return Helper.matchAnyExplicitUseIsUndef(*${root}); }]),
173  (apply [{ Helper.replaceInstWithConstant(*${root}, 0); }])>;
174
175def undef_to_negative_one: GICombineRule<
176  (defs root:$root),
177  (match (wip_match_opcode G_OR):$root,
178         [{ return Helper.matchAnyExplicitUseIsUndef(*${root}); }]),
179  (apply [{ Helper.replaceInstWithConstant(*${root}, -1); }])>;
180
181// Instructions where if any source operand is undef, the instruction can be
182// replaced with undef.
183def propagate_undef_any_op: GICombineRule<
184  (defs root:$root),
185  (match (wip_match_opcode G_ADD, G_FPTOSI, G_FPTOUI, G_SUB, G_XOR):$root,
186         [{ return Helper.matchAnyExplicitUseIsUndef(*${root}); }]),
187  (apply [{ Helper.replaceInstWithUndef(*${root}); }])>;
188
189// Instructions where if all source operands are undef, the instruction can be
190// replaced with undef.
191def propagate_undef_all_ops: GICombineRule<
192  (defs root:$root),
193  (match (wip_match_opcode G_SHUFFLE_VECTOR):$root,
194          [{ return Helper.matchAllExplicitUsesAreUndef(*${root}); }]),
195  (apply [{ Helper.replaceInstWithUndef(*${root}); }])>;
196
197// Replace a G_SHUFFLE_VECTOR with an undef mask with a G_IMPLICIT_DEF.
198def propagate_undef_shuffle_mask: GICombineRule<
199  (defs root:$root),
200  (match (wip_match_opcode G_SHUFFLE_VECTOR):$root,
201         [{ return Helper.matchUndefShuffleVectorMask(*${root}); }]),
202  (apply [{ Helper.replaceInstWithUndef(*${root}); }])>;
203
204// Fold (cond ? x : x) -> x
205def select_same_val: GICombineRule<
206  (defs root:$root),
207  (match (wip_match_opcode G_SELECT):$root,
208    [{ return Helper.matchSelectSameVal(*${root}); }]),
209  (apply [{ return Helper.replaceSingleDefInstWithOperand(*${root}, 2); }])
210>;
211
212// Fold x op 0 -> x
213def right_identity_zero: GICombineRule<
214  (defs root:$root),
215  (match (wip_match_opcode G_SUB, G_ADD, G_OR, G_XOR, G_SHL, G_ASHR, G_LSHR):$root,
216    [{ return Helper.matchConstantOp(${root}->getOperand(2), 0); }]),
217  (apply [{ return Helper.replaceSingleDefInstWithOperand(*${root}, 1); }])
218>;
219
220// Fold (x op x) - > x
221def binop_same_val: GICombineRule<
222  (defs root:$root),
223  (match (wip_match_opcode G_AND, G_OR):$root,
224    [{ return Helper.matchBinOpSameVal(*${root}); }]),
225  (apply [{ return Helper.replaceSingleDefInstWithOperand(*${root}, 1); }])
226>;
227
228// Fold (0 op x) - > 0
229def binop_left_to_zero: GICombineRule<
230  (defs root:$root),
231  (match (wip_match_opcode G_SDIV, G_UDIV, G_SREM, G_UREM):$root,
232    [{ return Helper.matchOperandIsZero(*${root}, 1); }]),
233  (apply [{ return Helper.replaceSingleDefInstWithOperand(*${root}, 1); }])
234>;
235
236// Fold (x op 0) - > 0
237def binop_right_to_zero: GICombineRule<
238  (defs root:$root),
239  (match (wip_match_opcode G_MUL):$root,
240    [{ return Helper.matchOperandIsZero(*${root}, 2); }]),
241  (apply [{ return Helper.replaceSingleDefInstWithOperand(*${root}, 2); }])
242>;
243
244// Erase stores of undef values.
245def erase_undef_store : GICombineRule<
246  (defs root:$root),
247  (match (wip_match_opcode G_STORE):$root,
248    [{ return Helper.matchUndefStore(*${root}); }]),
249  (apply [{ return Helper.eraseInst(*${root}); }])
250>;
251
252def simplify_add_to_sub_matchinfo: GIDefMatchData<"std::tuple<Register, Register>">;
253def simplify_add_to_sub: GICombineRule <
254  (defs root:$root, simplify_add_to_sub_matchinfo:$info),
255  (match (wip_match_opcode G_ADD):$root,
256    [{ return Helper.matchSimplifyAddToSub(*${root}, ${info}); }]),
257  (apply [{ return Helper.applySimplifyAddToSub(*${root}, ${info});}])
258>;
259
260// FIXME: These should use the custom predicate feature once it lands.
261def undef_combines : GICombineGroup<[undef_to_fp_zero, undef_to_int_zero,
262                                     undef_to_negative_one,
263                                     propagate_undef_any_op,
264                                     propagate_undef_all_ops,
265                                     propagate_undef_shuffle_mask,
266                                     erase_undef_store]>;
267
268def identity_combines : GICombineGroup<[select_same_val, right_identity_zero,
269                                        binop_same_val, binop_left_to_zero,
270                                        binop_right_to_zero]>;
271
272def trivial_combines : GICombineGroup<[copy_prop, mul_to_shl]>;
273def all_combines : GICombineGroup<[trivial_combines, ptr_add_immed_chain,
274    combines_for_extload, combine_indexed_load_store, undef_combines,
275    identity_combines, simplify_add_to_sub]>;
276