1// RUN: mlir-opt \ 2// RUN: -test-strict-pattern-driver="strictness=AnyOp" \ 3// RUN: --split-input-file %s | FileCheck %s --check-prefix=CHECK-AN 4 5// RUN: mlir-opt \ 6// RUN: -test-strict-pattern-driver="strictness=ExistingAndNewOps" \ 7// RUN: --split-input-file %s | FileCheck %s --check-prefix=CHECK-EN 8 9// RUN: mlir-opt \ 10// RUN: -test-strict-pattern-driver="strictness=ExistingOps" \ 11// RUN: --split-input-file %s | FileCheck %s --check-prefix=CHECK-EX 12 13// CHECK-EN-LABEL: func @test_erase 14// CHECK-EN-SAME: pattern_driver_all_erased = true, pattern_driver_changed = true} 15// CHECK-EN: "test.arg0" 16// CHECK-EN: "test.arg1" 17// CHECK-EN-NOT: "test.erase_op" 18func.func @test_erase() { 19 %0 = "test.arg0"() : () -> (i32) 20 %1 = "test.arg1"() : () -> (i32) 21 %erase = "test.erase_op"(%0, %1) : (i32, i32) -> (i32) 22 return 23} 24 25// ----- 26 27// CHECK-EN: notifyOperationInserted: test.insert_same_op, was unlinked 28// CHECK-EN-LABEL: func @test_insert_same_op 29// CHECK-EN-SAME: {pattern_driver_all_erased = false, pattern_driver_changed = true} 30// CHECK-EN: "test.insert_same_op"() {skip = true} 31// CHECK-EN: "test.insert_same_op"() {skip = true} 32func.func @test_insert_same_op() { 33 %0 = "test.insert_same_op"() : () -> (i32) 34 return 35} 36 37// ----- 38 39// CHECK-EN: notifyOperationInserted: test.new_op, was unlinked 40// CHECK-EN-LABEL: func @test_replace_with_new_op 41// CHECK-EN-SAME: {pattern_driver_all_erased = true, pattern_driver_changed = true} 42// CHECK-EN: %[[n:.*]] = "test.new_op" 43// CHECK-EN: "test.dummy_user"(%[[n]]) 44// CHECK-EN: "test.dummy_user"(%[[n]]) 45func.func @test_replace_with_new_op() { 46 %0 = "test.replace_with_new_op"() : () -> (i32) 47 %1 = "test.dummy_user"(%0) : (i32) -> (i32) 48 %2 = "test.dummy_user"(%0) : (i32) -> (i32) 49 return 50} 51 52// ----- 53 54// CHECK-EN: notifyOperationInserted: test.erase_op, was unlinked 55// CHECK-EN: notifyOperationErased: test.replace_with_new_op 56// CHECK-EN: notifyOperationErased: test.erase_op 57// CHECK-EN-LABEL: func @test_replace_with_erase_op 58// CHECK-EN-SAME: {pattern_driver_all_erased = true, pattern_driver_changed = true} 59// CHECK-EN-NOT: "test.replace_with_new_op" 60// CHECK-EN-NOT: "test.erase_op" 61 62// CHECK-EX-LABEL: func @test_replace_with_erase_op 63// CHECK-EX-SAME: {pattern_driver_all_erased = true, pattern_driver_changed = true} 64// CHECK-EX-NOT: "test.replace_with_new_op" 65// CHECK-EX: "test.erase_op" 66func.func @test_replace_with_erase_op() { 67 "test.replace_with_new_op"() {create_erase_op} : () -> () 68 return 69} 70 71// ----- 72 73// CHECK-AN-LABEL: func @test_trigger_rewrite_through_block 74// CHECK-AN: "test.change_block_op"()[^[[BB0:.*]], ^[[BB0]]] 75// CHECK-AN: return 76// CHECK-AN: ^[[BB1:[^:]*]]: 77// CHECK-AN: "test.implicit_change_op"()[^[[BB1]]] 78func.func @test_trigger_rewrite_through_block() { 79 return 80^bb1: 81 // Uses bb1. ChangeBlockOp replaces that and all other usages of bb1 with bb2. 82 "test.change_block_op"() [^bb1, ^bb2] : () -> () 83^bb2: 84 return 85^bb3: 86 // Also uses bb1. ChangeBlockOp replaces that usage with bb2. This triggers 87 // this op being put on the worklist, which triggers ImplicitChangeOp, which, 88 // in turn, replaces the successor with bb3. 89 "test.implicit_change_op"() [^bb1] : () -> () 90} 91 92// ----- 93 94// CHECK-AN: notifyOperationErased: test.foo_b 95// CHECK-AN: notifyOperationErased: test.foo_a 96// CHECK-AN: notifyOperationErased: test.graph_region 97// CHECK-AN: notifyOperationErased: test.erase_op 98// CHECK-AN-LABEL: func @test_remove_graph_region() 99// CHECK-AN-NEXT: return 100func.func @test_remove_graph_region() { 101 "test.erase_op"() ({ 102 test.graph_region { 103 %0 = "test.foo_a"(%1) : (i1) -> (i1) 104 %1 = "test.foo_b"(%0) : (i1) -> (i1) 105 } 106 }) : () -> () 107 return 108} 109 110// ----- 111 112// CHECK-AN: notifyOperationErased: cf.br 113// CHECK-AN: notifyOperationErased: test.bar 114// CHECK-AN: notifyOperationErased: cf.br 115// CHECK-AN: notifyOperationErased: test.foo 116// CHECK-AN: notifyOperationErased: cf.br 117// CHECK-AN: notifyOperationErased: test.dummy_op 118// CHECK-AN: notifyOperationErased: test.erase_op 119// CHECK-AN-LABEL: func @test_remove_cyclic_blocks() 120// CHECK-AN-NEXT: return 121func.func @test_remove_cyclic_blocks() { 122 "test.erase_op"() ({ 123 %x = "test.dummy_op"() : () -> (i1) 124 cf.br ^bb1(%x: i1) 125 ^bb1(%arg0: i1): 126 "test.foo"(%x) : (i1) -> () 127 cf.br ^bb2(%arg0: i1) 128 ^bb2(%arg1: i1): 129 "test.bar"(%x) : (i1) -> () 130 cf.br ^bb1(%arg1: i1) 131 }) : () -> () 132 return 133} 134 135// ----- 136 137// CHECK-AN: notifyOperationErased: test.dummy_op 138// CHECK-AN: notifyOperationErased: test.bar 139// CHECK-AN: notifyOperationErased: test.qux 140// CHECK-AN: notifyOperationErased: test.qux_unreachable 141// CHECK-AN: notifyOperationErased: test.nested_dummy 142// CHECK-AN: notifyOperationErased: cf.br 143// CHECK-AN: notifyOperationErased: test.foo 144// CHECK-AN: notifyOperationErased: test.erase_op 145// CHECK-AN-LABEL: func @test_remove_dead_blocks() 146// CHECK-AN-NEXT: return 147func.func @test_remove_dead_blocks() { 148 "test.erase_op"() ({ 149 "test.dummy_op"() : () -> (i1) 150 // The following blocks are not reachable. Still, ^bb2 should be deleted 151 // befire ^bb1. 152 ^bb1(%arg0: i1): 153 "test.foo"() : () -> () 154 cf.br ^bb2(%arg0: i1) 155 ^bb2(%arg1: i1): 156 "test.nested_dummy"() ({ 157 "test.qux"() : () -> () 158 // The following block is unreachable. 159 ^bb3: 160 "test.qux_unreachable"() : () -> () 161 }) : () -> () 162 "test.bar"() : () -> () 163 }) : () -> () 164 return 165} 166 167// ----- 168 169// test.nested_* must be deleted before test.foo. 170// test.bar must be deleted before test.foo. 171 172// CHECK-AN: notifyOperationErased: cf.br 173// CHECK-AN: notifyOperationErased: test.bar 174// CHECK-AN: notifyOperationErased: cf.br 175// CHECK-AN: notifyOperationErased: test.nested_b 176// CHECK-AN: notifyOperationErased: test.nested_a 177// CHECK-AN: notifyOperationErased: test.nested_d 178// CHECK-AN: notifyOperationErased: cf.br 179// CHECK-AN: notifyOperationErased: test.nested_e 180// CHECK-AN: notifyOperationErased: cf.br 181// CHECK-AN: notifyOperationErased: test.nested_c 182// CHECK-AN: notifyOperationErased: test.foo 183// CHECK-AN: notifyOperationErased: cf.br 184// CHECK-AN: notifyOperationErased: test.dummy_op 185// CHECK-AN: notifyOperationErased: test.erase_op 186// CHECK-AN-LABEL: func @test_remove_nested_ops() 187// CHECK-AN-NEXT: return 188func.func @test_remove_nested_ops() { 189 "test.erase_op"() ({ 190 %x = "test.dummy_op"() : () -> (i1) 191 cf.br ^bb1(%x: i1) 192 ^bb1(%arg0: i1): 193 "test.foo"() ({ 194 "test.nested_a"() : () -> () 195 "test.nested_b"() : () -> () 196 ^dead1: 197 "test.nested_c"() : () -> () 198 cf.br ^dead3 199 ^dead2: 200 "test.nested_d"() : () -> () 201 ^dead3: 202 "test.nested_e"() : () -> () 203 cf.br ^dead2 204 }) : () -> () 205 cf.br ^bb2(%arg0: i1) 206 ^bb2(%arg1: i1): 207 "test.bar"(%x) : (i1) -> () 208 cf.br ^bb1(%arg1: i1) 209 }) : () -> () 210 return 211} 212 213// ----- 214 215// CHECK-AN: notifyOperationErased: test.qux 216// CHECK-AN: notifyOperationErased: cf.br 217// CHECK-AN: notifyOperationErased: test.foo 218// CHECK-AN: notifyOperationErased: cf.br 219// CHECK-AN: notifyOperationErased: test.bar 220// CHECK-AN: notifyOperationErased: cf.cond_br 221// CHECK-AN-LABEL: func @test_remove_diamond( 222// CHECK-AN-NEXT: return 223func.func @test_remove_diamond(%c: i1) { 224 "test.erase_op"() ({ 225 cf.cond_br %c, ^bb1, ^bb2 226 ^bb1: 227 "test.foo"() : () -> () 228 cf.br ^bb3 229 ^bb2: 230 "test.bar"() : () -> () 231 cf.br ^bb3 232 ^bb3: 233 "test.qux"() : () -> () 234 }) : () -> () 235 return 236} 237 238// ----- 239 240// CHECK-AN: notifyOperationInserted: test.move_before_parent_op, previous = test.dummy_terminator 241// CHECK-AN-LABEL: func @test_move_op_before( 242// CHECK-AN: test.move_before_parent_op 243// CHECK-AN: test.op_with_region 244// CHECK-AN: test.dummy_terminator 245func.func @test_move_op_before() { 246 "test.op_with_region"() ({ 247 "test.move_before_parent_op"() : () -> () 248 "test.dummy_terminator"() : () ->() 249 }) : () -> () 250 return 251} 252 253// ----- 254 255// CHECK-AN: notifyOperationInserted: test.op_1, previous = test.op_2 256// CHECK-AN: notifyOperationInserted: test.op_2, previous = test.op_3 257// CHECK-AN: notifyOperationInserted: test.op_3, was last in block 258// CHECK-AN-LABEL: func @test_inline_block_before( 259// CHECK-AN: test.op_1 260// CHECK-AN: test.op_2 261// CHECK-AN: test.op_3 262// CHECK-AN: test.inline_blocks_into_parent 263// CHECK-AN: return 264func.func @test_inline_block_before() { 265 "test.inline_blocks_into_parent"() ({ 266 "test.op_1"() : () -> () 267 "test.op_2"() : () -> () 268 "test.op_3"() : () -> () 269 }) : () -> () 270 return 271} 272 273// ----- 274 275// CHECK-AN: notifyBlockInserted into test.op_with_region: was unlinked 276// CHECK-AN: notifyOperationInserted: test.op_3, was last in block 277// CHECK-AN: notifyOperationInserted: test.op_2, was last in block 278// CHECK-AN: notifyOperationInserted: test.split_block_here, was last in block 279// CHECK-AN: notifyOperationInserted: test.new_op, was unlinked 280// CHECK-AN: notifyOperationErased: test.split_block_here 281// CHECK-AN-LABEL: func @test_split_block( 282// CHECK-AN: "test.op_with_region"() ({ 283// CHECK-AN: test.op_1 284// CHECK-AN: ^{{.*}}: 285// CHECK-AN: test.new_op 286// CHECK-AN: test.op_2 287// CHECK-AN: test.op_3 288// CHECK-AN: }) : () -> () 289func.func @test_split_block() { 290 "test.op_with_region"() ({ 291 "test.op_1"() : () -> () 292 "test.split_block_here"() : () -> () 293 "test.op_2"() : () -> () 294 "test.op_3"() : () -> () 295 }) : () -> () 296 return 297} 298 299// ----- 300 301// CHECK-AN: notifyOperationInserted: test.clone_me, was unlinked 302// CHECK-AN: notifyBlockInserted into test.clone_me: was unlinked 303// CHECK-AN: notifyBlockInserted into test.clone_me: was unlinked 304// CHECK-AN: notifyOperationInserted: test.foo, was unlinked 305// CHECK-AN: notifyOperationInserted: test.bar, was unlinked 306// CHECK-AN-LABEL: func @clone_op( 307// CHECK-AN: "test.clone_me"() ({ 308// CHECK-AN: "test.foo"() : () -> () 309// CHECK-AN: ^bb1: // no predecessors 310// CHECK-AN: "test.bar"() : () -> () 311// CHECK-AN: }) {was_cloned} : () -> () 312// CHECK-AN: "test.clone_me"() ({ 313// CHECK-AN: "test.foo"() : () -> () 314// CHECK-AN: ^bb1: // no predecessors 315// CHECK-AN: "test.bar"() : () -> () 316// CHECK-AN: }) : () -> () 317func.func @clone_op() { 318 "test.clone_me"() ({ 319 ^bb0: 320 "test.foo"() : () -> () 321 ^bb1: 322 "test.bar"() : () -> () 323 }) : () -> () 324 return 325} 326 327 328// ----- 329 330// CHECK-AN: notifyBlockInserted into func.func: was unlinked 331// CHECK-AN: notifyOperationInserted: test.op_1, was unlinked 332// CHECK-AN: notifyBlockInserted into func.func: was unlinked 333// CHECK-AN: notifyOperationInserted: test.op_2, was unlinked 334// CHECK-AN: notifyBlockInserted into test.op_2: was unlinked 335// CHECK-AN: notifyOperationInserted: test.op_3, was unlinked 336// CHECK-AN: notifyOperationInserted: test.op_4, was unlinked 337// CHECK-AN-LABEL: func @test_clone_region_before( 338// CHECK-AN: "test.op_1"() : () -> () 339// CHECK-AN: ^{{.*}}: 340// CHECK-AN: "test.op_2"() ({ 341// CHECK-AN: "test.op_3"() : () -> () 342// CHECK-AN: }) : () -> () 343// CHECK-AN: "test.op_4"() : () -> () 344// CHECK-AN: ^{{.*}}: 345// CHECK-AN: "test.clone_region_before"() ({ 346func.func @test_clone_region_before() { 347 "test.clone_region_before"() ({ 348 "test.op_1"() : () -> () 349 ^bb0: 350 "test.op_2"() ({ 351 "test.op_3"() : () -> () 352 }) : () -> () 353 "test.op_4"() : () -> () 354 }) : () -> () 355 return 356} 357