• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1// RUN: mlir-opt -allow-unregistered-dialect -split-input-file -test-legalize-patterns -verify-diagnostics %s | FileCheck %s
2
3// CHECK-LABEL: verifyDirectPattern
4func @verifyDirectPattern() -> i32 {
5  // CHECK-NEXT:  "test.legal_op_a"() {status = "Success"}
6  %result = "test.illegal_op_a"() : () -> (i32)
7  // expected-remark@+1 {{op 'std.return' is not legalizable}}
8  return %result : i32
9}
10
11// CHECK-LABEL: verifyLargerBenefit
12func @verifyLargerBenefit() -> i32 {
13  // CHECK-NEXT:  "test.legal_op_a"() {status = "Success"}
14  %result = "test.illegal_op_c"() : () -> (i32)
15  // expected-remark@+1 {{op 'std.return' is not legalizable}}
16  return %result : i32
17}
18
19// CHECK-LABEL: func private @remap_input_1_to_0()
20func private @remap_input_1_to_0(i16)
21
22// CHECK-LABEL: func @remap_input_1_to_1(%arg0: f64)
23func @remap_input_1_to_1(%arg0: i64) {
24  // CHECK-NEXT: "test.valid"{{.*}} : (f64)
25  "test.invalid"(%arg0) : (i64) -> ()
26}
27
28// CHECK-LABEL: func @remap_call_1_to_1(%arg0: f64)
29func @remap_call_1_to_1(%arg0: i64) {
30  // CHECK-NEXT: call @remap_input_1_to_1(%arg0) : (f64) -> ()
31  // expected-remark@+1 {{op 'std.call' is not legalizable}}
32  call @remap_input_1_to_1(%arg0) : (i64) -> ()
33  // expected-remark@+1 {{op 'std.return' is not legalizable}}
34  return
35}
36
37// CHECK-LABEL: func @remap_input_1_to_N({{.*}}f16, {{.*}}f16)
38func @remap_input_1_to_N(%arg0: f32) -> f32 {
39  // CHECK-NEXT: [[CAST:%.*]] = "test.cast"(%arg0, %arg1) : (f16, f16) -> f32
40  // CHECK-NEXT: "test.return"{{.*}} : (f16, f16) -> ()
41  "test.return"(%arg0) : (f32) -> ()
42}
43
44// CHECK-LABEL: func @remap_input_1_to_N_remaining_use(%arg0: f16, %arg1: f16)
45func @remap_input_1_to_N_remaining_use(%arg0: f32) {
46  // CHECK-NEXT: [[CAST:%.*]] = "test.cast"(%arg0, %arg1) : (f16, f16) -> f32
47  // CHECK-NEXT: "work"([[CAST]]) : (f32) -> ()
48  // expected-remark@+1 {{op 'work' is not legalizable}}
49  "work"(%arg0) : (f32) -> ()
50}
51
52// CHECK-LABEL: func @remap_materialize_1_to_1(%{{.*}}: i43)
53func @remap_materialize_1_to_1(%arg0: i42) {
54  // CHECK: %[[V:.*]] = "test.cast"(%arg0) : (i43) -> i42
55  // CHECK: "test.return"(%[[V]])
56  "test.return"(%arg0) : (i42) -> ()
57}
58
59// CHECK-LABEL: func @remap_input_to_self
60func @remap_input_to_self(%arg0: index) {
61  // CHECK-NOT: test.cast
62  // CHECK: "work"
63  // expected-remark@+1 {{op 'work' is not legalizable}}
64  "work"(%arg0) : (index) -> ()
65}
66
67// CHECK-LABEL: func @remap_multi(%arg0: f64, %arg1: f64) -> (f64, f64)
68func @remap_multi(%arg0: i64, %unused: i16, %arg1: i64) -> (i64, i64) {
69 // CHECK-NEXT: "test.valid"{{.*}} : (f64, f64)
70 "test.invalid"(%arg0, %arg1) : (i64, i64) -> ()
71}
72
73// CHECK-LABEL: func @no_remap_nested
74func @no_remap_nested() {
75  // CHECK-NEXT: "foo.region"
76  // expected-remark@+1 {{op 'foo.region' is not legalizable}}
77  "foo.region"() ({
78    // CHECK-NEXT: ^bb0(%{{.*}}: i64, %{{.*}}: i16, %{{.*}}: i64):
79    ^bb0(%i0: i64, %unused: i16, %i1: i64):
80      // CHECK-NEXT: "test.valid"{{.*}} : (i64, i64)
81      "test.invalid"(%i0, %i1) : (i64, i64) -> ()
82  }) : () -> ()
83  // expected-remark@+1 {{op 'std.return' is not legalizable}}
84  return
85}
86
87// CHECK-LABEL: func @remap_moved_region_args
88func @remap_moved_region_args() {
89  // CHECK-NEXT: return
90  // CHECK-NEXT: ^bb1(%{{.*}}: f64, %{{.*}}: f64, %{{.*}}: f16, %{{.*}}: f16):
91  // CHECK-NEXT: "test.cast"{{.*}} : (f16, f16) -> f32
92  // CHECK-NEXT: "test.valid"{{.*}} : (f64, f64, f32)
93  "test.region"() ({
94    ^bb1(%i0: i64, %unused: i16, %i1: i64, %2: f32):
95      "test.invalid"(%i0, %i1, %2) : (i64, i64, f32) -> ()
96  }) : () -> ()
97  // expected-remark@+1 {{op 'std.return' is not legalizable}}
98  return
99}
100
101// CHECK-LABEL: func @remap_cloned_region_args
102func @remap_cloned_region_args() {
103  // CHECK-NEXT: return
104  // CHECK-NEXT: ^bb1(%{{.*}}: f64, %{{.*}}: f64, %{{.*}}: f16, %{{.*}}: f16):
105  // CHECK-NEXT: "test.cast"{{.*}} : (f16, f16) -> f32
106  // CHECK-NEXT: "test.valid"{{.*}} : (f64, f64, f32)
107  "test.region"() ({
108    ^bb1(%i0: i64, %unused: i16, %i1: i64, %2: f32):
109      "test.invalid"(%i0, %i1, %2) : (i64, i64, f32) -> ()
110  }) {legalizer.should_clone} : () -> ()
111  // expected-remark@+1 {{op 'std.return' is not legalizable}}
112  return
113}
114
115// CHECK-LABEL: func @remap_drop_region
116func @remap_drop_region() {
117  // CHECK-NEXT: return
118  // CHECK-NEXT: }
119  "test.drop_region_op"() ({
120    ^bb1(%i0: i64, %unused: i16, %i1: i64, %2: f32):
121      "test.invalid"(%i0, %i1, %2) : (i64, i64, f32) -> ()
122  }) : () -> ()
123  // expected-remark@+1 {{op 'std.return' is not legalizable}}
124  return
125}
126
127// CHECK-LABEL: func @dropped_input_in_use
128func @dropped_input_in_use(%arg: i16, %arg2: i64) {
129  // CHECK-NEXT: "test.cast"{{.*}} : () -> i16
130  // CHECK-NEXT: "work"{{.*}} : (i16)
131  // expected-remark@+1 {{op 'work' is not legalizable}}
132  "work"(%arg) : (i16) -> ()
133}
134
135// CHECK-LABEL: func @up_to_date_replacement
136func @up_to_date_replacement(%arg: i8) -> i8 {
137  // CHECK-NEXT: return
138  %repl_1 = "test.rewrite"(%arg) : (i8) -> i8
139  %repl_2 = "test.rewrite"(%repl_1) : (i8) -> i8
140  // expected-remark@+1 {{op 'std.return' is not legalizable}}
141  return %repl_2 : i8
142}
143
144// CHECK-LABEL: func @remove_foldable_op
145// CHECK-SAME:                          (%[[ARG_0:[a-z0-9]*]]: i32)
146func @remove_foldable_op(%arg0 : i32) -> (i32) {
147  // CHECK-NEXT: return %[[ARG_0]]
148  %0 = "test.op_with_region_fold"(%arg0) ({
149    "foo.op_with_region_terminator"() : () -> ()
150  }) : (i32) -> (i32)
151  // expected-remark@+1 {{op 'std.return' is not legalizable}}
152  return %0 : i32
153}
154
155// CHECK-LABEL: @create_block
156func @create_block() {
157  // Check that we created a block with arguments.
158  // CHECK-NOT: test.create_block
159  // CHECK: ^{{.*}}(%{{.*}}: i32, %{{.*}}: i32):
160  "test.create_block"() : () -> ()
161
162  // expected-remark@+1 {{op 'std.return' is not legalizable}}
163  return
164}
165
166// CHECK-LABEL: @bounded_recursion
167func @bounded_recursion() {
168  // CHECK: test.recursive_rewrite 0
169  test.recursive_rewrite 3
170  // expected-remark@+1 {{op 'std.return' is not legalizable}}
171  return
172}
173
174// -----
175
176func @fail_to_convert_illegal_op() -> i32 {
177  // expected-error@+1 {{failed to legalize operation 'test.illegal_op_f'}}
178  %result = "test.illegal_op_f"() : () -> (i32)
179  return %result : i32
180}
181
182// -----
183
184func @fail_to_convert_illegal_op_in_region() {
185  // expected-error@+1 {{failed to legalize operation 'test.region_builder'}}
186  "test.region_builder"() : () -> ()
187  return
188}
189
190// -----
191
192// Check that the entry block arguments of a region are untouched in the case
193// of failure.
194
195// CHECK-LABEL: func @fail_to_convert_region
196func @fail_to_convert_region() {
197  // CHECK-NEXT: "test.region"
198  // CHECK-NEXT: ^bb{{.*}}(%{{.*}}: i64):
199  "test.region"() ({
200    ^bb1(%i0: i64):
201      // expected-error@+1 {{failed to legalize operation 'test.region_builder'}}
202      "test.region_builder"() : () -> ()
203      "test.valid"() : () -> ()
204  }) : () -> ()
205  return
206}
207
208// -----
209
210// CHECK-LABEL: @create_illegal_block
211func @create_illegal_block() {
212  // Check that we can undo block creation, i.e. that the block was removed.
213  // CHECK: test.create_illegal_block
214  // CHECK-NOT: ^{{.*}}(%{{.*}}: i32, %{{.*}}: i32):
215  // expected-remark@+1 {{op 'test.create_illegal_block' is not legalizable}}
216  "test.create_illegal_block"() : () -> ()
217
218  // expected-remark@+1 {{op 'std.return' is not legalizable}}
219  return
220}
221
222// -----
223
224// CHECK-LABEL: @undo_block_arg_replace
225func @undo_block_arg_replace() {
226  // expected-remark@+1 {{op 'test.undo_block_arg_replace' is not legalizable}}
227  "test.undo_block_arg_replace"() ({
228  ^bb0(%arg0: i32):
229    // CHECK: ^bb0(%[[ARG:.*]]: i32):
230    // CHECK-NEXT: "test.return"(%[[ARG]]) : (i32)
231
232    "test.return"(%arg0) : (i32) -> ()
233  }) : () -> ()
234  // expected-remark@+1 {{op 'std.return' is not legalizable}}
235  return
236}
237
238// -----
239
240// The op in this function is rewritten to itself (and thus remains illegal) by
241// a pattern that removes its second block after adding an operation into it.
242// Check that we can undo block removal successfully.
243// CHECK-LABEL: @undo_block_erase
244func @undo_block_erase() {
245  // CHECK: test.undo_block_erase
246  "test.undo_block_erase"() ({
247    // expected-remark@-1 {{not legalizable}}
248    // CHECK: "unregistered.return"()[^[[BB:.*]]]
249    "unregistered.return"()[^bb1] : () -> ()
250    // expected-remark@-1 {{not legalizable}}
251  // CHECK: ^[[BB]]
252  ^bb1:
253    // CHECK: unregistered.return
254    "unregistered.return"() : () -> ()
255    // expected-remark@-1 {{not legalizable}}
256  }) : () -> ()
257}
258
259// -----
260
261// The op in this function is attempted to be rewritten to another illegal op
262// with an attached region containing an invalid terminator. The terminator is
263// created before the parent op. The deletion should not crash when deleting
264// created ops in the inverse order, i.e. deleting the parent op and then the
265// child op.
266// CHECK-LABEL: @undo_child_created_before_parent
267func @undo_child_created_before_parent() {
268  // expected-remark@+1 {{is not legalizable}}
269  "test.illegal_op_with_region_anchor"() : () -> ()
270  // expected-remark@+1 {{op 'std.return' is not legalizable}}
271  return
272}
273