xref: /llvm-project/mlir/test/mlir-tblgen/pattern.mlir (revision 0f8a6b7d03550cb58cf49535af2de2230abfe997)
1// RUN: mlir-opt -test-greedy-patterns -mlir-print-debuginfo -mlir-print-local-scope %s | FileCheck %s
2
3// CHECK-LABEL: verifyFusedLocs
4func.func @verifyFusedLocs(%arg0 : i32) -> i32 {
5  %0 = "test.op_a"(%arg0) {attr = 10 : i32} : (i32) -> i32 loc("a")
6  %result = "test.op_a"(%0) {attr = 20 : i32} : (i32) -> i32 loc("b")
7
8  // CHECK: "test.op_b"(%arg0) <{attr = 10 : i32}> : (i32) -> i32 loc("a")
9  // CHECK: "test.op_b"(%arg0) <{attr = 20 : i32}> : (i32) -> i32 loc(fused["b", "a"])
10  return %result : i32
11}
12
13// CHECK-LABEL: verifyDesignatedLoc
14func.func @verifyDesignatedLoc(%arg0 : i32) -> i32 {
15  %0 = "test.loc_src"(%arg0) : (i32) -> i32 loc("loc3")
16  %1 = "test.loc_src"(%0) : (i32) -> i32 loc("loc2")
17  %2 = "test.loc_src"(%1) : (i32) -> i32 loc("loc1")
18  "test.loc_src_no_res"(%2) : (i32) -> () loc("loc4")
19
20  // CHECK: "test.loc_dst"({{.*}}) : (i32) -> i32 loc("loc1")
21  // CHECK: "test.loc_dst"({{.*}}) : (i32) -> i32 loc("named")
22  // CHECK: "test.loc_dst"({{.*}}) : (i32) -> i32 loc(fused<"fused">["loc2", "loc3"])
23  // CHECK: "test.loc_dst_no_res"({{.*}}) : (i32) -> () loc("loc4")
24  return %1 : i32
25}
26
27// CHECK-LABEL: verifyZeroResult
28func.func @verifyZeroResult(%arg0 : i32) {
29  // CHECK: "test.op_i"(%arg0) : (i32) -> ()
30  "test.op_h"(%arg0) : (i32) -> ()
31  return
32}
33
34// CHECK-LABEL: verifyZeroArg
35func.func @verifyZeroArg() -> i32 {
36  // CHECK: "test.op_k"() : () -> i32
37  %0 = "test.op_j"() : () -> i32
38  return %0 : i32
39}
40
41// CHECK-LABEL: testIgnoreArgMatch
42// CHECK-SAME: (%{{[a-z0-9]*}}: i32 loc({{[^)]*}}), %[[ARG1:[a-z0-9]*]]: i32 loc({{[^)]*}}),
43func.func @testIgnoreArgMatch(%arg0: i32, %arg1: i32, %arg2: i32, %arg3: f32) {
44  // CHECK: "test.ignore_arg_match_dst"(%[[ARG1]]) <{f = 15 : i64}>
45  "test.ignore_arg_match_src"(%arg0, %arg1, %arg2) {d = 42, e = 24, f = 15} : (i32, i32, i32) -> ()
46
47  // CHECK: test.ignore_arg_match_src
48  // Not match because wrong type for $c.
49  "test.ignore_arg_match_src"(%arg0, %arg1, %arg3) {d = 42, e = 24, f = 15} : (i32, i32, f32) -> ()
50
51  // CHECK: test.ignore_arg_match_src
52  // Not match because wrong type for $f.
53  "test.ignore_arg_match_src"(%arg0, %arg1, %arg2) {d = 42 : i32, e = 24, f = 15} : (i32, i32, i32) -> ()
54  return
55}
56
57// CHECK-LABEL: verifyInterleavedOperandAttribute
58// CHECK-SAME:    %[[ARG0:.*]]: i32 loc({{[^)]*}}), %[[ARG1:.*]]: i32 loc({{[^)]*}})
59func.func @verifyInterleavedOperandAttribute(%arg0: i32, %arg1: i32) {
60  // CHECK: "test.interleaved_operand_attr2"(%[[ARG0]], %[[ARG1]]) <{attr1 = 15 : i64, attr2 = 42 : i64}>
61  "test.interleaved_operand_attr1"(%arg0, %arg1) {attr1 = 15, attr2 = 42} : (i32, i32) -> ()
62  return
63}
64
65// CHECK-LABEL: verifyBenefit
66func.func @verifyBenefit(%arg0 : i32) -> i32 {
67  %0 = "test.op_d"(%arg0) : (i32) -> i32
68  %1 = "test.op_g"(%arg0) : (i32) -> i32
69  %2 = "test.op_g"(%1) : (i32) -> i32
70
71  // CHECK: "test.op_f"(%arg0)
72  // CHECK: "test.op_b"(%arg0) <{attr = 34 : i32}>
73  return %0 : i32
74}
75
76// CHECK-LABEL: verifyNativeCodeCall
77func.func @verifyNativeCodeCall(%arg0: i32, %arg1: i32) -> (i32, i32) {
78  // CHECK: %0 = "test.native_code_call2"(%arg0) <{attr = [42, 24]}> : (i32) -> i32
79  // CHECK:  return %0, %arg1
80  %0 = "test.native_code_call1"(%arg0, %arg1) {choice = true, attr1 = 42, attr2 = 24} : (i32, i32) -> (i32)
81  %1 = "test.native_code_call1"(%arg0, %arg1) {choice = false, attr1 = 42, attr2 = 24} : (i32, i32) -> (i32)
82  return %0, %1: i32, i32
83}
84
85// CHECK-LABEL: verifyAuxiliaryNativeCodeCall
86func.func @verifyAuxiliaryNativeCodeCall(%arg0: i32) -> (i32) {
87  // CHECK: test.op_i
88  // CHECK: test.op_k
89  %0 = "test.native_code_call3"(%arg0) : (i32) -> (i32)
90  return %0 : i32
91}
92
93// CHECK-LABEL: verifyNativeCodeCallBinding
94func.func @verifyNativeCodeCallBinding(%arg0 : i32) -> (i32) {
95  %0 = "test.op_k"() : () -> (i32)
96  // CHECK: %[[A:.*]], %[[B:.*]] = "test.native_code_call5"(%1, %1) : (i32, i32) -> (i32, i32)
97  %1, %2 = "test.native_code_call4"(%0) : (i32) -> (i32, i32)
98  %3 = "test.constant"() {value = 1 : i8} : () -> i8
99  // %3 is i8 so it'll fail at GetFirstI32Result match. The operation should
100  // keep the same form.
101  // CHECK: %{{.*}}, %{{.*}} = "test.native_code_call4"({{%.*}}) : (i8) -> (i32, i32)
102  %4, %5 = "test.native_code_call4"(%3) : (i8) -> (i32, i32)
103  // CHECK: return %[[A]]
104  return %1 : i32
105}
106
107// CHECK-LABEL: verifyMultipleNativeCodeCallBinding
108func.func @verifyMultipleNativeCodeCallBinding(%arg0 : i32) -> (i32) {
109  %0 = "test.op_k"() : () -> (i32)
110  %1 = "test.op_k"() : () -> (i32)
111  // CHECK: %[[A:.*]] = "test.native_code_call7"(%1) : (i32) -> i32
112  // CHECK: %[[A:.*]] = "test.native_code_call7"(%0) : (i32) -> i32
113  %2, %3 = "test.native_code_call6"(%0, %1) : (i32, i32) -> (i32, i32)
114  return %2 : i32
115}
116
117// CHECK-LABEL: verifyAllAttrConstraintOf
118func.func @verifyAllAttrConstraintOf() -> (i32, i32, i32) {
119  // CHECK: "test.all_attr_constraint_of2"
120  %0 = "test.all_attr_constraint_of1"() {attr = [0, 1]} : () -> (i32)
121  // CHECK: "test.all_attr_constraint_of1"
122  %1 = "test.all_attr_constraint_of1"() {attr = [0, 2]} : () -> (i32)
123  // CHECK: "test.all_attr_constraint_of1"
124  %2 = "test.all_attr_constraint_of1"() {attr = [-1, 1]} : () -> (i32)
125  return %0, %1, %2: i32, i32, i32
126}
127
128// CHECK-LABEL: verifyManyArgs
129// CHECK-SAME: (%[[ARG:.*]]: i32 loc({{[^)]*}}))
130func.func @verifyManyArgs(%arg: i32) {
131  // CHECK: "test.many_arguments"(%[[ARG]], %[[ARG]], %[[ARG]], %[[ARG]], %[[ARG]], %[[ARG]], %[[ARG]], %[[ARG]], %[[ARG]])
132  // CHECK-SAME: {attr1 = 24 : i64, attr2 = 42 : i64, attr3 = 42 : i64, attr4 = 42 : i64, attr5 = 42 : i64, attr6 = 42 : i64, attr7 = 42 : i64, attr8 = 42 : i64, attr9 = 42 : i64}
133  "test.many_arguments"(%arg, %arg, %arg, %arg, %arg, %arg, %arg, %arg, %arg) {
134    attr1 = 42, attr2 = 42, attr3 = 42, attr4 = 42, attr5 = 42,
135    attr6 = 42, attr7 = 42, attr8 = 42, attr9 = 42
136  } : (i32, i32, i32, i32, i32, i32, i32, i32, i32) -> ()
137  return
138}
139
140// CHECK-LABEL: verifyEqualArgs
141func.func @verifyEqualArgs(%arg0: i32, %arg1: i32) {
142  // def TestEqualArgsPattern : Pat<(OpN $a, $a), (OpO $a)>;
143
144  // CHECK: "test.op_o"(%arg0) : (i32) -> i32
145  "test.op_n"(%arg0, %arg0) : (i32, i32) -> (i32)
146
147  // CHECK: "test.op_n"(%arg0, %arg1) : (i32, i32) -> i32
148  "test.op_n"(%arg0, %arg1) : (i32, i32) -> (i32)
149
150  return
151}
152
153// CHECK-LABEL: verifyNestedOpEqualArgs
154func.func @verifyNestedOpEqualArgs(
155  %arg0: i32, %arg1: i32, %arg2 : i32, %arg3 : i32, %arg4 : i32, %arg5 : i32) {
156  // def TestNestedOpEqualArgsPattern :
157  //   Pat<(OpN $b, (OpP $a, $b, $c, $d, $e, $f)), (replaceWithValue $b)>;
158
159  // CHECK: %arg1
160  %0 = "test.op_p"(%arg0, %arg1, %arg2, %arg3, %arg4, %arg5)
161    : (i32, i32, i32, i32, i32, i32) -> (i32)
162  %1 = "test.op_n"(%arg1, %0) : (i32, i32) -> (i32)
163
164  // CHECK: test.op_p
165  // CHECK: test.op_n
166  %2 = "test.op_p"(%arg0, %arg1, %arg2, %arg3, %arg4, %arg5)
167    : (i32, i32, i32, i32, i32, i32) -> (i32)
168  %3 = "test.op_n"(%arg0, %2) : (i32, i32) -> (i32)
169
170  return
171}
172
173// CHECK-LABEL: verifyNestedSameOpAndSameArgEquality
174func.func @verifyNestedSameOpAndSameArgEquality(%arg0: i32, %arg1: i32) -> i32 {
175  // def TestNestedSameOpAndSameArgEqualityPattern:
176  //   Pat<(OpN (OpN $_, $x), $x), (replaceWithValue $x)>;
177
178  %0 = "test.op_n"(%arg1, %arg0) : (i32, i32) -> (i32)
179  %1 = "test.op_n"(%0, %arg0) : (i32, i32) -> (i32)
180  // CHECK: return %arg0 : i32
181  return %1 : i32
182}
183
184// CHECK-LABEL: verifyMultipleEqualArgs
185func.func @verifyMultipleEqualArgs(
186  %arg0: i32, %arg1 : i32, %arg2 : i32, %arg3 : i32, %arg4 : i32) {
187  // def TestMultipleEqualArgsPattern :
188  //   Pat<(OpP $a, $b, $a, $a, $b, $c), (OpN $c, $b)>;
189
190  // CHECK: "test.op_n"(%arg2, %arg1) : (i32, i32) -> i32
191  "test.op_p"(%arg0, %arg1, %arg0, %arg0, %arg1, %arg2) :
192    (i32, i32, i32, i32 , i32, i32) -> i32
193
194  // CHECK: test.op_p
195  "test.op_p"(%arg0, %arg1, %arg0, %arg0, %arg0, %arg2) :
196    (i32, i32, i32, i32 , i32, i32) -> i32
197
198  // CHECK: test.op_p
199  "test.op_p"(%arg0, %arg1, %arg1, %arg0, %arg1, %arg2) :
200    (i32, i32, i32, i32 , i32, i32) -> i32
201
202   // CHECK: test.op_p
203  "test.op_p"(%arg0, %arg1, %arg2, %arg2, %arg3, %arg4) :
204    (i32, i32, i32, i32 , i32, i32) -> i32
205
206  return
207}
208
209//===----------------------------------------------------------------------===//
210// Test Symbol Binding
211//===----------------------------------------------------------------------===//
212
213// CHECK-LABEL: symbolBinding
214func.func @symbolBinding(%arg0: i32) -> i32 {
215  // An op with one use is matched.
216  // CHECK: %0 = "test.symbol_binding_b"(%arg0)
217  // CHECK: %1 = "test.symbol_binding_c"(%0)
218  // CHECK: %2 = "test.symbol_binding_d"(%0, %1) <{attr = 42 : i64}>
219  %0 = "test.symbol_binding_a"(%arg0) {attr = 42} : (i32) -> (i32)
220
221  // An op without any use is not matched.
222  // CHECK: "test.symbol_binding_a"(%arg0)
223  %1 = "test.symbol_binding_a"(%arg0) {attr = 42} : (i32) -> (i32)
224
225  // CHECK: return %2
226  return %0: i32
227}
228
229// CHECK-LABEL: symbolBindingNoResult
230func.func @symbolBindingNoResult(%arg0: i32) {
231  // CHECK: test.symbol_binding_b
232  "test.symbol_binding_no_result"(%arg0) : (i32) -> ()
233  return
234}
235
236//===----------------------------------------------------------------------===//
237// Test Attributes
238//===----------------------------------------------------------------------===//
239
240// CHECK-LABEL: succeedMatchOpAttr
241func.func @succeedMatchOpAttr() -> i32 {
242  // CHECK: "test.match_op_attribute2"() <{default_valued_attr = 3 : i32, more_attr = 4 : i32, optional_attr = 2 : i32, required_attr = 1 : i32}>
243  %0 = "test.match_op_attribute1"() {required_attr = 1: i32, optional_attr = 2: i32, default_valued_attr = 3: i32, more_attr = 4: i32} : () -> (i32)
244  return %0: i32
245}
246
247// CHECK-LABEL: succeedMatchMissingOptionalAttr
248func.func @succeedMatchMissingOptionalAttr() -> i32 {
249  // CHECK: "test.match_op_attribute2"() <{default_valued_attr = 3 : i32, more_attr = 4 : i32, required_attr = 1 : i32}>
250  %0 = "test.match_op_attribute1"() {required_attr = 1: i32, default_valued_attr = 3: i32, more_attr = 4: i32} : () -> (i32)
251  return %0: i32
252}
253
254// CHECK-LABEL: succeedMatchMissingDefaultValuedAttr
255func.func @succeedMatchMissingDefaultValuedAttr() -> i32 {
256  // CHECK: "test.match_op_attribute2"() <{default_valued_attr = 42 : i32, more_attr = 4 : i32, optional_attr = 2 : i32, required_attr = 1 : i32}>
257  %0 = "test.match_op_attribute1"() {required_attr = 1: i32, optional_attr = 2: i32, more_attr = 4: i32} : () -> (i32)
258  return %0: i32
259}
260
261// CHECK-LABEL: failedMatchAdditionalConstraintNotSatisfied
262func.func @failedMatchAdditionalConstraintNotSatisfied() -> i32 {
263  // CHECK: "test.match_op_attribute1"()
264  %0 = "test.match_op_attribute1"() {required_attr = 1: i32, optional_attr = 2: i32, more_attr = 5: i32} : () -> (i32)
265  return %0: i32
266}
267
268// CHECK-LABEL: verifyConstantAttr
269func.func @verifyConstantAttr(%arg0 : i32) -> i32 {
270  // CHECK: "test.op_b"(%arg0) <{attr = 17 : i32}> : (i32) -> i32 loc("a")
271  %0 = "test.op_c"(%arg0) : (i32) -> i32 loc("a")
272  return %0 : i32
273}
274
275// CHECK-LABEL: verifyUnitAttr
276func.func @verifyUnitAttr() -> (i32, i32) {
277  // Unit attribute present in the matched op is propagated as attr2.
278  // CHECK: "test.match_op_attribute4"() <{attr1, attr2}> : () -> i32
279  %0 = "test.match_op_attribute3"() {attr} : () -> i32
280
281  // Since the original op doesn't have the unit attribute, the new op
282  // only has the constant-constructed unit attribute attr1.
283  // CHECK: "test.match_op_attribute4"() <{attr1}> : () -> i32
284  %1 = "test.match_op_attribute3"() : () -> i32
285  return %0, %1 : i32, i32
286}
287
288//===----------------------------------------------------------------------===//
289// Test Constant Matching
290//===----------------------------------------------------------------------===//
291
292// CHECK-LABEL: testConstOp
293func.func @testConstOp() -> (i32) {
294  // CHECK-NEXT: [[C0:%.+]] = "test.constant"() <{value = 1
295  %0 = "test.constant"() {value = 1 : i32} : () -> i32
296
297  // CHECK-NEXT: return [[C0]]
298  return %0 : i32
299}
300
301// CHECK-LABEL: testConstOpUsed
302func.func @testConstOpUsed() -> (i32) {
303  // CHECK-NEXT: [[C0:%.+]] = "test.constant"() <{value = 1
304  %0 = "test.constant"() {value = 1 : i32} : () -> i32
305
306  // CHECK-NEXT: [[V0:%.+]] = "test.op_s"([[C0]])
307  %1 = "test.op_s"(%0) {value = 1 : i32} : (i32) -> i32
308
309  // CHECK-NEXT: return [[V0]]
310  return %1 : i32
311}
312
313// CHECK-LABEL: testConstOpReplaced
314func.func @testConstOpReplaced() -> (i32) {
315  // CHECK-NEXT: [[C0:%.+]] = "test.constant"() <{value = 1
316  %0 = "test.constant"() {value = 1 : i32} : () -> i32
317  %1 = "test.constant"() {value = 2 : i32} : () -> i32
318
319  // CHECK: [[V0:%.+]] = "test.op_s"([[C0]]) <{value = 2 : i32}
320  %2 = "test.op_r"(%0, %1) : (i32, i32) -> i32
321
322  // CHECK: [[V0]]
323  return %2 : i32
324}
325
326// CHECK-LABEL: testConstOpMatchFailure
327func.func @testConstOpMatchFailure() -> (i64) {
328  // CHECK-DAG: [[C0:%.+]] = "test.constant"() <{value = 1
329  %0 = "test.constant"() {value = 1 : i64} : () -> i64
330
331  // CHECK-DAG: [[C1:%.+]] = "test.constant"() <{value = 2
332  %1 = "test.constant"() {value = 2 : i64} : () -> i64
333
334  // CHECK: [[V0:%.+]] = "test.op_r"([[C0]], [[C1]])
335  %2 = "test.op_r"(%0, %1) : (i64, i64) -> i64
336
337  // CHECK: [[V0]]
338  return %2 : i64
339}
340
341// CHECK-LABEL: testConstOpMatchNonConst
342func.func @testConstOpMatchNonConst(%arg0 : i32) -> (i32) {
343  // CHECK-DAG: [[C0:%.+]] = "test.constant"() <{value = 1
344  %0 = "test.constant"() {value = 1 : i32} : () -> i32
345
346  // CHECK: [[V0:%.+]] = "test.op_r"([[C0]], %arg0)
347  %1 = "test.op_r"(%0, %arg0) : (i32, i32) -> i32
348
349  // CHECK: [[V0]]
350  return %1 : i32
351}
352
353
354
355//===----------------------------------------------------------------------===//
356// Test Enum Attributes
357//===----------------------------------------------------------------------===//
358
359// CHECK-LABEL: verifyI32EnumAttr
360func.func @verifyI32EnumAttr() -> i32 {
361  // CHECK: "test.i32_enum_attr"() <{attr = 10 : i32}
362  %0 = "test.i32_enum_attr"() {attr = 5: i32} : () -> i32
363  return %0 : i32
364}
365
366// CHECK-LABEL: verifyI64EnumAttr
367func.func @verifyI64EnumAttr() -> i32 {
368  // CHECK: "test.i64_enum_attr"() <{attr = 10 : i64}
369  %0 = "test.i64_enum_attr"() {attr = 5: i64} : () -> i32
370  return %0 : i32
371}
372
373//===----------------------------------------------------------------------===//
374// Test ElementsAttr
375//===----------------------------------------------------------------------===//
376
377// CHECK-LABEL: rewrite_i32elementsattr
378func.func @rewrite_i32elementsattr() -> () {
379  // CHECK: attr = dense<0> : tensor<i32>
380  "test.i32ElementsAttr"() {attr = dense<[3, 5]>:tensor<2xi32>} : () -> ()
381  return
382}
383
384// CHECK-LABEL: rewrite_f64elementsattr
385func.func @rewrite_f64elementsattr() -> () {
386  "test.float_elements_attr"() {
387    // Should match
388    // CHECK: scalar_f32_attr = dense<[5.000000e+00, 6.000000e+00]> : tensor<2xf32>
389    scalar_f32_attr = dense<[3.0, 4.0]> : tensor<2xf32>,
390    tensor_f64_attr = dense<6.0> : tensor<4x8xf64>
391  } : () -> ()
392
393  "test.float_elements_attr"() {
394    // Should not match
395    // CHECK: scalar_f32_attr = dense<7.000000e+00> : tensor<2xf32>
396    scalar_f32_attr = dense<7.0> : tensor<2xf32>,
397    tensor_f64_attr = dense<3.0> : tensor<4x8xf64>
398  } : () -> ()
399  return
400}
401
402//===----------------------------------------------------------------------===//
403// Test Multi-result Ops
404//===----------------------------------------------------------------------===//
405
406// CHECK-LABEL: @useMultiResultOpToReplaceWhole
407func.func @useMultiResultOpToReplaceWhole() -> (i32, f32, f32) {
408  // CHECK: %[[A:.*]], %[[B:.*]], %[[C:.*]] = "test.another_three_result"()
409  // CHECK: return %[[A]], %[[B]], %[[C]]
410  %0:3 = "test.three_result"() {kind = 1} : () -> (i32, f32, f32)
411  return %0#0, %0#1, %0#2 : i32, f32, f32
412}
413
414// CHECK-LABEL: @useMultiResultOpToReplacePartial1
415func.func @useMultiResultOpToReplacePartial1() -> (i32, f32, f32) {
416  // CHECK: %[[A:.*]], %[[B:.*]] = "test.two_result"()
417  // CHECK: %[[C:.*]] = "test.one_result1"()
418  // CHECK: return %[[A]], %[[B]], %[[C]]
419  %0:3 = "test.three_result"() {kind = 2} : () -> (i32, f32, f32)
420  return %0#0, %0#1, %0#2 : i32, f32, f32
421}
422
423// CHECK-LABEL: @useMultiResultOpToReplacePartial2
424func.func @useMultiResultOpToReplacePartial2() -> (i32, f32, f32) {
425  // CHECK: %[[A:.*]] = "test.one_result2"()
426  // CHECK: %[[B:.*]], %[[C:.*]] = "test.another_two_result"()
427  // CHECK: return %[[A]], %[[B]], %[[C]]
428  %0:3 = "test.three_result"() {kind = 3} : () -> (i32, f32, f32)
429  return %0#0, %0#1, %0#2 : i32, f32, f32
430}
431
432// CHECK-LABEL: @useMultiResultOpResultsSeparately
433func.func @useMultiResultOpResultsSeparately() -> (i32, f32, f32) {
434  // CHECK: %[[A:.*]], %[[B:.*]] = "test.two_result"()
435  // CHECK: %[[C:.*]] = "test.one_result1"()
436  // CHECK: %[[D:.*]], %[[E:.*]] = "test.two_result"()
437  // CHECK: return %[[A]], %[[C]], %[[E]]
438  %0:3 = "test.three_result"() {kind = 4} : () -> (i32, f32, f32)
439  return %0#0, %0#1, %0#2 : i32, f32, f32
440}
441
442// CHECK-LABEL: @constraintOnSourceOpResult
443func.func @constraintOnSourceOpResult() -> (i32, f32, i32) {
444  // CHECK: %[[A:.*]], %[[B:.*]] = "test.two_result"()
445  // CHECK: %[[C:.*]] = "test.one_result2"()
446  // CHECK: %[[D:.*]] = "test.one_result1"()
447  // CHECK: return %[[A]], %[[B]], %[[C]]
448  %0:2 = "test.two_result"() {kind = 5} : () -> (i32, f32)
449  %1:2 = "test.two_result"() {kind = 5} : () -> (i32, f32)
450  return %0#0, %0#1, %1#0 : i32, f32, i32
451}
452
453// CHECK-LABEL: @useAuxiliaryOpToReplaceMultiResultOp
454func.func @useAuxiliaryOpToReplaceMultiResultOp() -> (i32, f32, f32) {
455  // An auxiliary op is generated to help building the op for replacing the
456  // matched op.
457  // CHECK: %[[A:.*]], %[[B:.*]] = "test.two_result"()
458
459  // CHECK: %[[C:.*]] = "test.one_result3"(%[[B]])
460  // CHECK: %[[D:.*]], %[[E:.*]] = "test.another_two_result"()
461  // CHECK: return %[[C]], %[[D]], %[[E]]
462  %0:3 = "test.three_result"() {kind = 6} : () -> (i32, f32, f32)
463  return %0#0, %0#1, %0#2 : i32, f32, f32
464}
465
466//===----------------------------------------------------------------------===//
467// Test Multi-result Ops
468//===----------------------------------------------------------------------===//
469
470// CHECK-LABEL: @replaceOneVariadicOutOneVariadicInOp
471func.func @replaceOneVariadicOutOneVariadicInOp(%arg0: i32, %arg1: i32, %arg2: i32) -> (i32, i32, i32, i32, i32, i32) {
472  // CHECK: %[[cnt1:.*]] = "test.one_variadic_out_one_variadic_in2"(%arg0)
473  // CHECK: %[[cnt2:.*]]:2 = "test.one_variadic_out_one_variadic_in2"(%arg0, %arg1)
474  // CHECK: %[[cnt3:.*]]:3 = "test.one_variadic_out_one_variadic_in2"(%arg0, %arg1, %arg2)
475  // CHECK: return %[[cnt1]], %[[cnt2]]#0, %[[cnt2]]#1, %[[cnt3]]#0, %[[cnt3]]#1, %[[cnt3]]#2
476
477  %0   = "test.one_variadic_out_one_variadic_in1"(%arg0) : (i32) -> (i32)
478  %1:2 = "test.one_variadic_out_one_variadic_in1"(%arg0, %arg1) : (i32, i32) -> (i32, i32)
479  %2:3 = "test.one_variadic_out_one_variadic_in1"(%arg0, %arg1, %arg2) : (i32, i32, i32) -> (i32, i32, i32)
480  return %0, %1#0, %1#1, %2#0, %2#1, %2#2 : i32, i32, i32, i32, i32, i32
481}
482
483// CHECK-LABEL: @replaceMixedVariadicInputOp
484func.func @replaceMixedVariadicInputOp(%arg0: i32, %arg1: f32, %arg2: i32) -> () {
485  // CHECK: "test.mixed_variadic_in2"(%arg1)
486  // CHECK: "test.mixed_variadic_in2"(%arg0, %arg1, %arg2)
487  // CHECK: "test.mixed_variadic_in2"(%arg0, %arg0, %arg1, %arg2, %arg2)
488
489  "test.mixed_variadic_in1"(%arg1) : (f32) -> ()
490  "test.mixed_variadic_in1"(%arg0, %arg1, %arg2) : (i32, f32, i32) -> ()
491  "test.mixed_variadic_in1"(%arg0, %arg0, %arg1, %arg2, %arg2) : (i32, i32, f32, i32, i32) -> ()
492  return
493}
494
495// CHECK-LABEL: @replaceMixedVariadicOutputOp
496func.func @replaceMixedVariadicOutputOp() -> (f32, i32, f32, i32, i32, i32, f32, i32, i32) {
497  // CHECK: %[[cnt1:.*]] = "test.mixed_variadic_out2"()
498  // CHECK: %[[cnt3_a:.*]], %[[cnt3_b:.*]], %[[cnt3_c:.*]] = "test.mixed_variadic_out2"()
499  // CHECK: %[[cnt5_a:.*]]:2, %[[cnt5_b:.*]], %[[cnt5_c:.*]]:2 = "test.mixed_variadic_out2"()
500  // CHECK: return %[[cnt1]], %[[cnt3_a]], %[[cnt3_b]], %[[cnt3_c]], %[[cnt5_a]]#0, %[[cnt5_a]]#1, %[[cnt5_b]], %[[cnt5_c]]#0, %[[cnt5_c]]#1
501
502  %0   = "test.mixed_variadic_out1"() : () -> (f32)
503  %1:3 = "test.mixed_variadic_out1"() : () -> (i32, f32, i32)
504  %2:5 = "test.mixed_variadic_out1"() : () -> (i32, i32, f32, i32, i32)
505  return %0, %1#0, %1#1, %1#2, %2#0, %2#1, %2#2, %2#3, %2#4 : f32, i32, f32, i32, i32, i32, f32, i32, i32
506}
507
508// CHECK-LABEL: @generateVariadicOutputOpInNestedPattern
509func.func @generateVariadicOutputOpInNestedPattern() -> (i32) {
510  // CHECK: %[[cnt5_a:.*]], %[[cnt5_b:.*]]:2, %[[cnt5_c:.*]]:2 = "test.mixed_variadic_out3"()
511  // CHECK: %[[res:.*]] = "test.mixed_variadic_in3"(%[[cnt5_a]], %[[cnt5_b]]#0, %[[cnt5_b]]#1, %[[cnt5_c]]#0, %[[cnt5_c]]#1)
512  // CHECK: return %[[res]]
513
514  %0 = "test.one_i32_out"() : () -> (i32)
515  return %0 : i32
516}
517
518// CHECK-LABEL: @testMatchVariadic
519func.func @testMatchVariadic(%arg0: i32, %arg1: i32, %arg2: i32, %arg3: i32) -> () {
520  // CHECK: "test.mixed_variadic_in5"(%arg0, %arg1, %arg2) <{attr1 = 0 : i32, pattern_name = "MatchVariadic"}> : (i32, i32, i32) -> ()
521  "test.mixed_variadic_in4"(%arg0, %arg1, %arg2) {attr1 = 0 : i32} : (i32, i32, i32) -> ()
522
523  // Note: Not rewritten because variadic operand size mismatches.
524  // CHECK: "test.mixed_variadic_in4"(%arg0, %arg1, %arg2, %arg3) <{attr1 = 0 : i32}> : (i32, i32, i32, i32) -> ()
525  "test.mixed_variadic_in4"(%arg0, %arg1, %arg2, %arg3) {attr1 = 0 : i32} : (i32, i32, i32, i32) -> ()
526
527  return
528}
529
530// CHECK-LABEL: @testReplaceVariadic
531func.func @testReplaceVariadic(%arg0: i32, %arg1: i32, %arg2: i32, %arg3: i32) -> () {
532  // CHECK: "test.mixed_variadic_in3"(%arg2, %arg1, %arg0) <{count = 1 : i32}>
533  "test.mixed_variadic_in5"(%arg0, %arg1, %arg2) <{attr1 = 0 : i32, pattern_name = "MatchInverseVariadic"}> : (i32, i32, i32) -> ()
534
535  return
536}
537
538// CHECK-LABEL: @testMatchVariadicSubDag
539func.func @testMatchVariadicSubDag(%arg0: i32, %arg1: i32, %arg2: i32) -> () {
540  // CHECK: %[[IN0:.*]] = "test.mixed_variadic_in_out_i32"(%arg0) : (i32) -> i32
541  %0 = "test.mixed_variadic_in_out_i32"(%arg0) : (i32) -> i32
542  // CHECK: %[[IN1:.*]] = "test.mixed_variadic_in_out_i32"(%arg1) : (i32) -> i32
543  %1 = "test.mixed_variadic_in_out_i32"(%arg1) : (i32) -> i32
544
545  // CHECK: "test.mixed_variadic_in5"(%arg0, %arg1, %arg2) <{attr1 = 1 : i32, pattern_name = "MatchVariadicSubDag"}> : (i32, i32, i32) -> ()
546  "test.mixed_variadic_in4"(%0, %1, %arg2) {attr1 = 1 : i32} : (i32, i32, i32) -> ()
547
548  // Note: MatchVariadicSubDag doesn't apply
549  // CHECK: "test.mixed_variadic_in4"(%arg0, %arg1, %arg2) <{attr1 = 1 : i32}> : (i32, i32, i32) -> ()
550  "test.mixed_variadic_in4"(%arg0, %arg1, %arg2) {attr1 = 1 : i32} : (i32, i32, i32) -> ()
551
552  return
553}
554
555// CHECK-LABEL: @testMatchVariadicSameSymbol
556func.func @testMatchVariadicSameSymbol(%arg0: i32, %arg1: i32, %arg2: i32) -> () {
557  // CHECK: "test.mixed_variadic_in5"(%arg0, %arg0, %arg2) <{attr1 = 2 : i32, pattern_name = "MatchVariadicSameSymbol"}> : (i32, i32, i32) -> ()
558  "test.mixed_variadic_in4"(%arg0, %arg0, %arg2) {attr1 = 2 : i32} : (i32, i32, i32) -> ()
559
560  // Note: MatchVariadicSameSymbol doesn't apply.
561  // CHECK: "test.mixed_variadic_in4"(%arg0, %arg1, %arg2) <{attr1 = 2 : i32}> : (i32, i32, i32) -> ()
562  "test.mixed_variadic_in4"(%arg0, %arg1, %arg2) {attr1 = 2 : i32} : (i32, i32, i32) -> ()
563
564  return
565}
566
567// CHECK-LABEL: @testMatchAndRewriteVariadicFullRange
568func.func @testMatchAndRewriteVariadicFullRange(%arg0: i32, %arg1: i32, %arg2: i32, %arg3: i32) -> () {
569  // CHECK: "test.mixed_variadic_in6"(%arg2, %arg3, %arg0, %arg1) <{attr1 = -1 : i32}> : (i32, i32, i32, i32) -> ()
570  "test.mixed_variadic_in6"(%arg0, %arg1, %arg2, %arg3) {attr1 = 1 : i32} : (i32, i32, i32, i32) -> ()
571
572  // Note: MatchAndRewriteVariadicFullRange doesn't apply because the length of each variadic operand is not equal to 2.
573  // CHECK: "test.mixed_variadic_in6"(%arg0, %arg1) <{attr1 = 1 : i32}> : (i32, i32) -> ()
574  "test.mixed_variadic_in6"(%arg0, %arg1) {attr1 = 1 : i32} : (i32, i32) -> ()
575
576  return
577}
578
579// CHECK-LABEL: @testMatchMultiVariadicSubSymbol
580func.func @testMatchMultiVariadicSubSymbol(%arg0: i32, %arg1: i32, %arg2: i32, %arg3: i32) -> () {
581  // CHECK: "test.mixed_variadic_in5"(%arg2, %arg3, %arg1) <{attr1 = 2 : i32, pattern_name = "MatchMultiVariadicSubSymbol"}> : (i32, i32, i32) -> ()
582  "test.mixed_variadic_in6"(%arg0, %arg1, %arg2, %arg3) {attr1 = 2 : i32} : (i32, i32, i32, i32) -> ()
583
584  return
585}
586
587//===----------------------------------------------------------------------===//
588// Test that natives calls are only called once during rewrites.
589//===----------------------------------------------------------------------===//
590
591// CHECK-LABEL: redundantTest
592func.func @redundantTest(%arg0: i32) -> i32 {
593  %0 = "test.op_m"(%arg0) : (i32) -> i32
594  // CHECK: "test.op_m"(%arg0) <{optional_attr = 314159265 : i32}> : (i32) -> i32
595  return %0 : i32
596}
597
598//===----------------------------------------------------------------------===//
599// Test either directive
600//===----------------------------------------------------------------------===//
601
602// CHECK: @either_dag_leaf_only
603func.func @either_dag_leaf_only_1(%arg0 : i32, %arg1 : i16, %arg2 : i8) -> () {
604  // CHECK: "test.either_op_b"(%arg1, %arg2) : (i16, i8) -> i32
605  %0 = "test.either_op_a"(%arg0, %arg1, %arg2) : (i32, i16, i8) -> i32
606  // CHECK: "test.either_op_b"(%arg1, %arg2) : (i16, i8) -> i32
607  %1 = "test.either_op_a"(%arg1, %arg0, %arg2) : (i16, i32, i8) -> i32
608  return
609}
610
611// CHECK: @either_dag_leaf_dag_node
612func.func @either_dag_leaf_dag_node(%arg0 : i32, %arg1 : i16, %arg2 : i8) -> () {
613  %0 = "test.either_op_b"(%arg0, %arg0) : (i32, i32) -> i32
614  // CHECK: "test.either_op_b"(%arg1, %arg2) : (i16, i8) -> i32
615  %1 = "test.either_op_a"(%0, %arg1, %arg2) : (i32, i16, i8) -> i32
616  // CHECK: "test.either_op_b"(%arg1, %arg2) : (i16, i8) -> i32
617  %2 = "test.either_op_a"(%arg1, %0, %arg2) : (i16, i32, i8) -> i32
618  return
619}
620
621// CHECK: @either_dag_node_dag_node
622func.func @either_dag_node_dag_node(%arg0 : i32, %arg1 : i16, %arg2 : i8) -> () {
623  %0 = "test.either_op_b"(%arg0, %arg0) : (i32, i32) -> i32
624  %1 = "test.either_op_b"(%arg1, %arg1) : (i16, i16) -> i32
625  // CHECK: "test.either_op_b"(%arg1, %arg2) : (i16, i8) -> i32
626  %2 = "test.either_op_a"(%0, %1, %arg2) : (i32, i32, i8) -> i32
627  // CHECK: "test.either_op_b"(%arg1, %arg2) : (i16, i8) -> i32
628  %3 = "test.either_op_a"(%1, %0, %arg2) : (i32, i32, i8) -> i32
629  return
630}
631
632//===----------------------------------------------------------------------===//
633// Test that ops without type deduction can be created with type builders.
634//===----------------------------------------------------------------------===//
635
636func.func @explicitReturnTypeTest(%arg0 : i64) -> i8 {
637  %0 = "test.source_op"(%arg0) {tag = 11 : i32} : (i64) -> i8
638  // CHECK: "test.op_x"(%arg0) : (i64) -> i32
639  // CHECK: "test.op_x"(%0) : (i32) -> i8
640  return %0 : i8
641}
642
643func.func @returnTypeBuilderTest(%arg0 : i1) -> i8 {
644  %0 = "test.source_op"(%arg0) {tag = 22 : i32} : (i1) -> i8
645  // CHECK: "test.op_x"(%arg0) : (i1) -> i1
646  // CHECK: "test.op_x"(%0) : (i1) -> i8
647  return %0 : i8
648}
649
650func.func @multipleReturnTypeBuildTest(%arg0 : i1) -> i1 {
651  %0 = "test.source_op"(%arg0) {tag = 33 : i32} : (i1) -> i1
652  // CHECK: "test.one_to_two"(%arg0) : (i1) -> (i64, i32)
653  // CHECK: "test.op_x"(%0#0) : (i64) -> i32
654  // CHECK: "test.op_x"(%0#1) : (i32) -> i64
655  // CHECK: "test.two_to_one"(%1, %2) : (i32, i64) -> i1
656  return %0 : i1
657}
658
659func.func @copyValueType(%arg0 : i8) -> i32 {
660  %0 = "test.source_op"(%arg0) {tag = 44 : i32} : (i8) -> i32
661  // CHECK: "test.op_x"(%arg0) : (i8) -> i8
662  // CHECK: "test.op_x"(%0) : (i8) -> i32
663  return %0 : i32
664}
665
666func.func @multipleReturnTypeDifferent(%arg0 : i1) -> i64 {
667  %0 = "test.source_op"(%arg0) {tag = 55 : i32} : (i1) -> i64
668  // CHECK: "test.one_to_two"(%arg0) : (i1) -> (i1, i64)
669  // CHECK: "test.two_to_one"(%0#0, %0#1) : (i1, i64) -> i64
670  return %0 : i64
671}
672
673//===----------------------------------------------------------------------===//
674// Test that multiple trailing directives can be mixed in patterns.
675//===----------------------------------------------------------------------===//
676
677func.func @returnTypeAndLocation(%arg0 : i32) -> i1 {
678  %0 = "test.source_op"(%arg0) {tag = 66 : i32} : (i32) -> i1
679  // CHECK: "test.op_x"(%arg0) : (i32) -> i32 loc("loc1")
680  // CHECK: "test.op_x"(%arg0) : (i32) -> i32 loc("loc2")
681  // CHECK: "test.two_to_one"(%0, %1) : (i32, i32) -> i1
682  return %0 : i1
683}
684
685//===----------------------------------------------------------------------===//
686// Test that patterns can create ConstantStrAttr
687//===----------------------------------------------------------------------===//
688
689func.func @testConstantStrAttr() -> () {
690  // CHECK: test.has_str_value {value = "foo"}
691  test.no_str_value {value = "bar"}
692  return
693}
694
695//===----------------------------------------------------------------------===//
696// Test that patterns with variadics propagate sizes
697//===----------------------------------------------------------------------===//
698
699func.func @testVariadic(%arg_0: i32, %arg_1: i32, %brg: i64,
700    %crg_0: f32, %crg_1: f32, %crg_2: f32, %crg_3: f32) -> () {
701  // CHECK: "test.variadic_rewrite_dst_op"(%arg2, %arg3, %arg4, %arg5, %arg6, %arg0, %arg1) <{operandSegmentSizes = array<i32: 1, 4, 2>}> : (i64, f32, f32, f32, f32, i32, i32) -> ()
702  "test.variadic_rewrite_src_op"(%arg_0, %arg_1, %brg,
703    %crg_0, %crg_1, %crg_2, %crg_3) {operandSegmentSizes = array<i32: 2, 1, 4>} :
704    (i32, i32, i64, f32, f32, f32, f32) -> ()
705  return
706}
707