1 // RUN: mlir-opt -allow-unregistered-dialect -split-input-file -test-legalize-patterns -verify-diagnostics %s | FileCheck %s
3 // CHECK: notifyOperationInserted: test.legal_op_a, was unlinked
4 // CHECK-NEXT: notifyOperationReplaced: test.illegal_op_a
5 // CHECK-NEXT: notifyOperationModified: func.return
6 // CHECK-NEXT: notifyOperationErased: test.illegal_op_a
8 // CHECK-LABEL: verifyDirectPattern
9 func.func @verifyDirectPattern() -> i32 {
10 // CHECK-NEXT: "test.legal_op_a"() <{status = "Success"}
11 %result = "test.illegal_op_a"() : () -> (i32)
12 // expected-remark@+1 {{op 'func.return' is not legalizable}}
18 // CHECK: notifyOperationInserted: test.illegal_op_e, was unlinked
19 // CHECK-NEXT: notifyOperationReplaced: test.illegal_op_c
20 // CHECK-NEXT: notifyOperationModified: func.return
21 // CHECK-NEXT: notifyOperationErased: test.illegal_op_c
22 // CHECK-NEXT: notifyOperationInserted: test.legal_op_a, was unlinked
23 // CHECK-NEXT: notifyOperationReplaced: test.illegal_op_e
24 // CHECK-NEXT: notifyOperationErased: test.illegal_op_e
26 // CHECK-LABEL: verifyLargerBenefit
27 func.func @verifyLargerBenefit() -> i32 {
28 // CHECK-NEXT: "test.legal_op_a"() <{status = "Success"}
29 %result = "test.illegal_op_c"() : () -> (i32)
30 // expected-remark@+1 {{op 'func.return' is not legalizable}}
36 // CHECK: notifyOperationModified: func.func
37 // Note: No block insertion because this function is external and no block
38 // signature conversion is performed.
40 // CHECK-LABEL: func private @remap_input_1_to_0()
41 func.func private @remap_input_1_to_0(i16)
45 // CHECK-LABEL: func @remap_input_1_to_1(%arg0: f64)
46 func.func @remap_input_1_to_1(%arg0: i64) {
47 // CHECK-NEXT: "test.valid"{{.*}} : (f64)
48 "test.invalid"(%arg0) : (i64) -> ()
51 // CHECK: func @remap_call_1_to_1(%arg0: f64)
52 func.func @remap_call_1_to_1(%arg0: i64) {
53 // CHECK-NEXT: call @remap_input_1_to_1(%arg0) : (f64) -> ()
54 call @remap_input_1_to_1(%arg0) : (i64) -> ()
55 // expected-remark@+1 {{op 'func.return' is not legalizable}}
61 // Block signature conversion: new block is inserted.
62 // CHECK: notifyBlockInserted into func.func: was unlinked
64 // Contents of the old block are moved to the new block.
65 // CHECK-NEXT: notifyOperationInserted: test.return, was linked, exact position unknown
67 // The new block arguments are used in "test.return".
68 // CHECK-NEXT: notifyOperationModified: test.return
70 // The old block is erased.
71 // CHECK-NEXT: notifyBlockErased
73 // The function op gets a new type attribute.
74 // CHECK-NEXT: notifyOperationModified: func.func
76 // "test.return" is replaced.
77 // CHECK-NEXT: notifyOperationInserted: test.return, was unlinked
78 // CHECK-NEXT: notifyOperationReplaced: test.return
79 // CHECK-NEXT: notifyOperationErased: test.return
81 // CHECK-LABEL: func @remap_input_1_to_N({{.*}}f16, {{.*}}f16)
82 func.func @remap_input_1_to_N(%arg0: f32) -> f32 {
83 // CHECK-NEXT: "test.return"{{.*}} : (f16, f16) -> ()
84 "test.return"(%arg0) : (f32) -> ()
89 // CHECK-LABEL: func @remap_input_1_to_N_remaining_use(%arg0: f16, %arg1: f16)
90 func.func @remap_input_1_to_N_remaining_use(%arg0: f32) {
91 // CHECK-NEXT: [[CAST:%.*]] = "test.cast"(%arg0, %arg1) : (f16, f16) -> f32
92 // CHECK-NEXT: "work"([[CAST]]) : (f32) -> ()
93 // expected-remark@+1 {{op 'work' is not legalizable}}
94 "work"(%arg0) : (f32) -> ()
97 // CHECK-LABEL: func @remap_materialize_1_to_1(%{{.*}}: i43)
98 func.func @remap_materialize_1_to_1(%arg0: i42) {
99 // CHECK: %[[V:.*]] = "test.cast"(%arg0) : (i43) -> i42
100 // CHECK: "test.return"(%[[V]])
101 "test.return"(%arg0) : (i42) -> ()
106 // CHECK-LABEL: func @remap_input_to_self
107 func.func @remap_input_to_self(%arg0: index) {
108 // CHECK-NOT: test.cast
110 // expected-remark@+1 {{op 'work' is not legalizable}}
111 "work"(%arg0) : (index) -> ()
114 // CHECK-LABEL: func @remap_multi(%arg0: f64, %arg1: f64) -> (f64, f64)
115 func.func @remap_multi(%arg0: i64, %unused: i16, %arg1: i64) -> (i64, i64) {
116 // CHECK-NEXT: "test.valid"{{.*}} : (f64, f64)
117 "test.invalid"(%arg0, %arg1) : (i64, i64) -> ()
122 // CHECK-LABEL: func @no_remap_nested
123 func.func @no_remap_nested() {
124 // CHECK-NEXT: "foo.region"
125 // expected-remark@+1 {{op 'foo.region' is not legalizable}}
127 // CHECK-NEXT: ^bb0(%{{.*}}: i64, %{{.*}}: i16, %{{.*}}: i64):
128 ^bb0(%i0: i64, %unused: i16, %i1: i64):
129 // CHECK-NEXT: "test.valid"{{.*}} : (i64, i64)
130 "test.invalid"(%i0, %i1) : (i64, i64) -> ()
132 // expected-remark@+1 {{op 'func.return' is not legalizable}}
138 // CHECK-LABEL: func @remap_moved_region_args
139 func.func @remap_moved_region_args() {
140 // CHECK-NEXT: return
141 // CHECK-NEXT: ^bb1(%{{.*}}: f64, %{{.*}}: f64, %{{.*}}: f16, %{{.*}}: f16):
142 // CHECK-NEXT: "test.cast"{{.*}} : (f16, f16) -> f32
143 // CHECK-NEXT: "test.valid"{{.*}} : (f64, f64, f32)
145 ^bb1(%i0: i64, %unused: i16, %i1: i64, %2: f32):
146 "test.invalid"(%i0, %i1, %2) : (i64, i64, f32) -> ()
148 // expected-remark@+1 {{op 'func.return' is not legalizable}}
154 // CHECK-LABEL: func @remap_cloned_region_args
155 func.func @remap_cloned_region_args() {
156 // CHECK-NEXT: return
157 // CHECK-NEXT: ^bb1(%{{.*}}: f64, %{{.*}}: f64, %{{.*}}: f16, %{{.*}}: f16):
158 // CHECK-NEXT: "test.cast"{{.*}} : (f16, f16) -> f32
159 // CHECK-NEXT: "test.valid"{{.*}} : (f64, f64, f32)
161 ^bb1(%i0: i64, %unused: i16, %i1: i64, %2: f32):
162 "test.invalid"(%i0, %i1, %2) : (i64, i64, f32) -> ()
163 }) {legalizer.should_clone} : () -> ()
164 // expected-remark@+1 {{op 'func.return' is not legalizable}}
168 // CHECK-LABEL: func @remap_drop_region
169 func.func @remap_drop_region() {
170 // CHECK-NEXT: return
172 "test.drop_region_op"() ({
173 ^bb1(%i0: i64, %unused: i16, %i1: i64, %2: f32):
174 "test.invalid"(%i0, %i1, %2) : (i64, i64, f32) -> ()
176 // expected-remark@+1 {{op 'func.return' is not legalizable}}
182 // CHECK-LABEL: func @dropped_input_in_use
183 func.func @dropped_input_in_use(%arg: i16, %arg2: i64) {
184 // CHECK-NEXT: "test.cast"{{.*}} : () -> i16
185 // CHECK-NEXT: "work"{{.*}} : (i16)
186 // expected-remark@+1 {{op 'work' is not legalizable}}
187 "work"(%arg) : (i16) -> ()
192 // CHECK-LABEL: func @up_to_date_replacement
193 func.func @up_to_date_replacement(%arg: i8) -> i8 {
194 // CHECK-NEXT: return
195 %repl_1 = "test.rewrite"(%arg) : (i8) -> i8
196 %repl_2 = "test.rewrite"(%repl_1) : (i8) -> i8
197 // expected-remark@+1 {{op 'func.return' is not legalizable}}
203 // CHECK-LABEL: func @remove_foldable_op
204 // CHECK-SAME: (%[[ARG_0:[a-z0-9]*]]: i32)
205 func.func @remove_foldable_op(%arg0 : i32) -> (i32) {
206 // CHECK-NEXT: return %[[ARG_0]]
207 %0 = "test.op_with_region_fold"(%arg0) ({
208 "foo.op_with_region_terminator"() : () -> ()
210 // expected-remark@+1 {{op 'func.return' is not legalizable}}
216 // CHECK-LABEL: @create_block
217 func.func @create_block() {
218 // Check that we created a block with arguments.
219 // CHECK-NOT: test.create_block
220 // CHECK: ^{{.*}}(%{{.*}}: i32, %{{.*}}: i32):
221 "test.create_block"() : () -> ()
223 // expected-remark@+1 {{op 'func.return' is not legalizable}}
229 // CHECK: notifyOperationModified: test.recursive_rewrite
230 // CHECK-NEXT: notifyOperationModified: test.recursive_rewrite
231 // CHECK-NEXT: notifyOperationModified: test.recursive_rewrite
233 // CHECK-LABEL: @bounded_recursion
234 func.func @bounded_recursion() {
235 // CHECK: test.recursive_rewrite 0
236 test.recursive_rewrite 3
237 // expected-remark@+1 {{op 'func.return' is not legalizable}}
243 // expected-remark@+1 {{applyPartialConversion failed}}
246 func.func @fail_to_convert_illegal_op() -> i32 {
247 // expected-error@+1 {{failed to legalize operation 'test.illegal_op_f'}}
248 %result = "test.illegal_op_f"() : () -> (i32)
256 // expected-remark@+1 {{applyPartialConversion failed}}
259 func.func @fail_to_convert_illegal_op_in_region() {
260 // expected-error@+1 {{failed to legalize operation 'test.region_builder'}}
261 "test.region_builder"() : () -> ()
269 // Check that the entry block arguments of a region are untouched in the case
272 // expected-remark@+1 {{applyPartialConversion failed}}
275 func.func @fail_to_convert_region() {
276 // CHECK: "test.region"
277 // CHECK-NEXT: ^bb{{.*}}(%{{.*}}: i64):
280 // expected-error@+1 {{failed to legalize operation 'test.region_builder'}}
281 "test.region_builder"() : () -> ()
282 "test.valid"() : () -> ()
291 // CHECK-LABEL: @create_illegal_block
292 func.func @create_illegal_block() {
293 // Check that we can undo block creation, i.e. that the block was removed.
294 // CHECK: test.create_illegal_block
295 // CHECK-NOT: ^{{.*}}(%{{.*}}: i32, %{{.*}}: i32):
296 // expected-remark@+1 {{op 'test.create_illegal_block' is not legalizable}}
297 "test.create_illegal_block"() : () -> ()
299 // expected-remark@+1 {{op 'func.return' is not legalizable}}
305 // CHECK-LABEL: @undo_block_arg_replace
306 func.func @undo_block_arg_replace() {
307 // expected-remark@+1 {{op 'test.undo_block_arg_replace' is not legalizable}}
308 "test.undo_block_arg_replace"() ({
310 // CHECK: ^bb0(%[[ARG:.*]]: i32):
311 // CHECK-NEXT: "test.return"(%[[ARG]]) : (i32)
313 "test.return"(%arg0) : (i32) -> ()
315 // expected-remark@+1 {{op 'func.return' is not legalizable}}
321 // The op in this function is rewritten to itself (and thus remains illegal) by
322 // a pattern that removes its second block after adding an operation into it.
323 // Check that we can undo block removal successfully.
324 // CHECK-LABEL: @undo_block_erase
325 func.func @undo_block_erase() {
326 // CHECK: test.undo_block_erase
327 "test.undo_block_erase"() ({
328 // expected-remark@-1 {{not legalizable}}
329 // CHECK: "unregistered.return"()[^[[BB:.*]]]
330 "unregistered.return"()[^bb1] : () -> ()
331 // expected-remark@-1 {{not legalizable}}
334 // CHECK: unregistered.return
335 "unregistered.return"() : () -> ()
336 // expected-remark@-1 {{not legalizable}}
342 // The op in this function is attempted to be rewritten to another illegal op
343 // with an attached region containing an invalid terminator. The terminator is
344 // created before the parent op. The deletion should not crash when deleting
345 // created ops in the inverse order, i.e. deleting the parent op and then the
347 // CHECK-LABEL: @undo_child_created_before_parent
348 func.func @undo_child_created_before_parent() {
349 // expected-remark@+1 {{is not legalizable}}
350 "test.illegal_op_with_region_anchor"() : () -> ()
351 // expected-remark@+1 {{op 'func.return' is not legalizable}}
357 // Check that a conversion pattern on `test.blackhole` can mark the producer
359 // CHECK-LABEL: @blackhole
360 func.func @blackhole() {
361 %input = "test.blackhole_producer"() : () -> (i32)
362 "test.blackhole"(%input) : (i32) -> ()
363 // expected-remark@+1 {{op 'func.return' is not legalizable}}
369 // expected-remark@+1 {{applyPartialConversion failed}}
372 func.func @create_unregistered_op_in_pattern() -> i32 {
373 // expected-error@+1 {{failed to legalize operation 'test.illegal_op_g'}}
374 %0 = "test.illegal_op_g"() : () -> (i32)
375 "test.return"(%0) : (i32) -> ()
382 // expected-remark @below {{applyPartialConversion failed}}
384 func.func private @callee(%0 : f32) -> f32
386 func.func @caller( %arg: f32) {
387 // expected-error @below {{failed to legalize}}
388 %1 = func.call @callee(%arg) : (f32) -> f32
395 // CHECK-LABEL: func @test_move_op_before_rollback()
396 func.func @test_move_op_before_rollback() {
397 // CHECK: "test.one_region_op"()
398 // CHECK: "test.hoist_me"()
399 "test.one_region_op"() ({
400 // expected-remark @below{{'test.hoist_me' is not legalizable}}
401 %0 = "test.hoist_me"() : () -> (i32)
402 "test.valid"(%0) : (i32) -> ()
404 "test.return"() : () -> ()
409 // CHECK-LABEL: func @test_properties_rollback()
410 func.func @test_properties_rollback() {
411 // CHECK: test.with_properties a = 32,
412 // expected-remark @below{{op 'test.with_properties' is not legalizable}}
414 a = 32, b = "foo", c = "bar", flag = true, array = [1, 2, 3, 4]
416 "test.return"() : () -> ()
421 // CHECK: func.func @use_of_replaced_bbarg(
422 // CHECK-SAME: %[[arg0:.*]]: f64)
423 // CHECK: "test.valid"(%[[arg0]])
424 func.func @use_of_replaced_bbarg(%arg0: i64) {
425 %0 = "test.op_with_region_fold"(%arg0) ({
426 "foo.op_with_region_terminator"() : () -> ()
428 "test.invalid"(%0) : (i64) -> ()
433 // CHECK-LABEL: @fold_legalization
434 func.func @fold_legalization() -> i32 {
435 // CHECK: op_in_place_self_fold
436 // CHECK-SAME: folded
437 %1 = "test.op_in_place_self_fold"() : () -> (i32)
438 "test.return"(%1) : (i32) -> ()
443 // CHECK-LABEL: func @convert_detached_signature()
444 // CHECK: "test.legal_op_with_region"() ({
445 // CHECK: ^bb0(%arg0: f64):
446 // CHECK: "test.return"() : () -> ()
447 // CHECK: }) : () -> ()
448 func.func @convert_detached_signature() {
449 "test.detached_signature_conversion"() ({
451 "test.return"() : () -> ()
453 "test.return"() : () -> ()
458 // CHECK-LABEL: func @circular_mapping()
459 // CHECK-NEXT: "test.valid"() : () -> ()
460 func.func @circular_mapping() {
461 // Regression test that used to crash due to circular
462 // unrealized_conversion_cast ops.
463 %0 = "test.erase_op"() : () -> (i64)
464 "test.drop_operands_and_replace_with_valid"(%0) : (i64) -> ()