491 lines · plain
1// RUN: mlir-opt --allow-unregistered-dialect --transform-interpreter --split-input-file --verify-diagnostics %s | FileCheck %s2 3// Check simple move of dependent operation before insertion.4func.func @simple_move() -> f32 {5 %0 = "before"() : () -> (f32)6 %1 = "moved_op"() : () -> (f32)7 %2 = "foo"(%1) : (f32) -> (f32)8 return %2 : f329}10// CHECK-LABEL: func @simple_move()11// CHECK: %[[MOVED:.+]] = "moved_op"12// CHECK: %[[BEFORE:.+]] = "before"13// CHECK: %[[FOO:.+]] = "foo"(%[[MOVED]])14// CHECK: return %[[FOO]]15 16module attributes {transform.with_named_sequence} {17 transform.named_sequence @__transform_main(%arg0 : !transform.any_op {transform.readonly}) {18 %op1 = transform.structured.match ops{["foo"]} in %arg019 : (!transform.any_op) -> !transform.any_op20 %op2 = transform.structured.match ops{["before"]} in %arg021 : (!transform.any_op) -> !transform.any_op22 transform.test.move_operand_deps %op1 before %op223 : !transform.any_op, !transform.any_op24 transform.yield25 }26}27 28// -----29 30// Move operands that are implicitly captured by the op31func.func @move_region_dependencies() -> f32 {32 %0 = "before"() : () -> (f32)33 %1 = "moved_op"() : () -> (f32)34 %2 = "foo"() ({35 %3 = "inner_op"(%1) : (f32) -> (f32)36 "yield"(%3) : (f32) -> ()37 }) : () -> (f32)38 return %2 : f3239}40// CHECK-LABEL: func @move_region_dependencies()41// CHECK: %[[MOVED:.+]] = "moved_op"42// CHECK: %[[BEFORE:.+]] = "before"43// CHECK: %[[FOO:.+]] = "foo"44// CHECK: return %[[FOO]]45 46module attributes {transform.with_named_sequence} {47 transform.named_sequence @__transform_main(%arg0 : !transform.any_op {transform.readonly}) {48 %op1 = transform.structured.match ops{["foo"]} in %arg049 : (!transform.any_op) -> !transform.any_op50 %op2 = transform.structured.match ops{["before"]} in %arg051 : (!transform.any_op) -> !transform.any_op52 transform.test.move_operand_deps %op1 before %op253 : !transform.any_op, !transform.any_op54 transform.yield55 }56}57 58// -----59 60// Move operations in toplogical sort order61func.func @move_in_topological_sort_order() -> f32 {62 %0 = "before"() : () -> (f32)63 %1 = "moved_op_1"() : () -> (f32)64 %2 = "moved_op_2"() : () -> (f32)65 %3 = "moved_op_3"(%1) : (f32) -> (f32)66 %4 = "moved_op_4"(%1, %3) : (f32, f32) -> (f32)67 %5 = "moved_op_5"(%2) : (f32) -> (f32)68 %6 = "foo"(%4, %5) : (f32, f32) -> (f32)69 return %6 : f3270}71// CHECK-LABEL: func @move_in_topological_sort_order()72// CHECK: %[[MOVED_1:.+]] = "moved_op_1"73// CHECK-DAG: %[[MOVED_2:.+]] = "moved_op_3"(%[[MOVED_1]])74// CHECK-DAG: %[[MOVED_3:.+]] = "moved_op_4"(%[[MOVED_1]], %[[MOVED_2]])75// CHECK-DAG: %[[MOVED_4:.+]] = "moved_op_2"76// CHECK-DAG: %[[MOVED_5:.+]] = "moved_op_5"(%[[MOVED_4]])77// CHECK: %[[BEFORE:.+]] = "before"78// CHECK: %[[FOO:.+]] = "foo"(%[[MOVED_3]], %[[MOVED_5]])79// CHECK: return %[[FOO]]80 81module attributes {transform.with_named_sequence} {82 transform.named_sequence @__transform_main(%arg0 : !transform.any_op {transform.readonly}) {83 %op1 = transform.structured.match ops{["foo"]} in %arg084 : (!transform.any_op) -> !transform.any_op85 %op2 = transform.structured.match ops{["before"]} in %arg086 : (!transform.any_op) -> !transform.any_op87 transform.test.move_operand_deps %op1 before %op288 : !transform.any_op, !transform.any_op89 transform.yield90 }91}92 93// -----94 95func.func @move_region_dependencies() -> f32 {96 %0 = "before"() : () -> (f32)97 %1 = "moved_op_1"() : () -> (f32)98 %2 = "moved_op_2"() ({99 "yield"(%1) : (f32) -> ()100 }) : () -> (f32)101 %3 = "foo"() ({102 "yield"(%2) : (f32) -> ()103 }) : () -> (f32)104 return %3 : f32105}106 107module attributes {transform.with_named_sequence} {108 transform.named_sequence @__transform_main(%arg0 : !transform.any_op {transform.readonly}) {109 %op1 = transform.structured.match ops{["foo"]} in %arg0110 : (!transform.any_op) -> !transform.any_op111 %op2 = transform.structured.match ops{["before"]} in %arg0112 : (!transform.any_op) -> !transform.any_op113 transform.test.move_operand_deps %op1 before %op2114 : !transform.any_op, !transform.any_op115 transform.yield116 }117}118// CHECK-LABEL: func @move_region_dependencies()119// CHECK: %[[MOVED_1:.+]] = "moved_op_1"120// CHECK: %[[MOVED_2:.+]] = "moved_op_2"121// CHECK: "yield"(%[[MOVED_1]])122// CHECK: "before"123// CHECK: %[[FOO:.+]] = "foo"124// CHECK: return %[[FOO]]125 126// -----127 128// Current implementation omits following basic block argument when129// computing slices. Verify that this gives expected result.130func.func @ignore_basic_block_arguments() -> f32 {131^bb0():132 %8 = "test"() : () -> (f32)133 return %8: f32134^bb1(%bbArg : f32):135 %0 = "before"() : () -> (f32)136 %1 = "moved_op"() ({137 "yield"(%bbArg) : (f32) -> ()138 }) : () -> (f32)139 %2 = "foo"() ({140 "yield"(%1) : (f32) -> ()141 }) : () -> (f32)142 return %2 : f32143}144 145module attributes {transform.with_named_sequence} {146 transform.named_sequence @__transform_main(%arg0 : !transform.any_op {transform.readonly}) {147 %op1 = transform.structured.match ops{["foo"]} in %arg0148 : (!transform.any_op) -> !transform.any_op149 %op2 = transform.structured.match ops{["before"]} in %arg0150 : (!transform.any_op) -> !transform.any_op151 transform.test.move_operand_deps %op1 before %op2152 : !transform.any_op, !transform.any_op153 transform.yield154 }155}156// CHECK-LABEL: func @ignore_basic_block_arguments()157// CHECK: %[[MOVED_1:.+]] = "moved_op"158// CHECK: "before"159// CHECK: %[[FOO:.+]] = "foo"160// CHECK: return %[[FOO]]161 162// -----163 164// Fail when the "before" operation is part of the operation slice.165func.func @do_not_move_slice() -> f32 {166 %0 = "before"() : () -> (f32)167 %1 = "moved_op"(%0) : (f32) -> (f32)168 %2 = "foo"(%1) : (f32) -> (f32)169 return %2 : f32170}171 172module attributes {transform.with_named_sequence} {173 transform.named_sequence @__transform_main(%arg0 : !transform.any_op {transform.readonly}) {174 %op1 = transform.structured.match ops{["foo"]} in %arg0175 : (!transform.any_op) -> !transform.any_op176 %op2 = transform.structured.match ops{["before"]} in %arg0177 : (!transform.any_op) -> !transform.any_op178 // expected-remark@+1{{cannot move dependencies before operation in backward slice of op}}179 transform.test.move_operand_deps %op1 before %op2180 : !transform.any_op, !transform.any_op181 transform.yield182 }183}184 185// -----186 187// Fail when the "before" operation is part of the operation slice (computed188// when looking through implicitly captured values).189func.func @do_not_move_slice() -> f32 {190 %0 = "before"() : () -> (f32)191 %1 = "moved_op"() ({192 "yield"(%0) : (f32) -> ()193 }) : () -> (f32)194 %2 = "foo"() ({195 "yield"(%1) : (f32) -> ()196 }) : () -> (f32)197 return %2 : f32198}199 200module attributes {transform.with_named_sequence} {201 transform.named_sequence @__transform_main(%arg0 : !transform.any_op {transform.readonly}) {202 %op1 = transform.structured.match ops{["foo"]} in %arg0203 : (!transform.any_op) -> !transform.any_op204 %op2 = transform.structured.match ops{["before"]} in %arg0205 : (!transform.any_op) -> !transform.any_op206 // expected-remark@+1{{cannot move dependencies before operation in backward slice of op}}207 transform.test.move_operand_deps %op1 before %op2208 : !transform.any_op, !transform.any_op209 transform.yield210 }211}212 213// -----214 215// Dont move ops when insertion point does not dominate the op216func.func @do_not_move() -> f32 {217 %1 = "moved_op"() : () -> (f32)218 %2 = "foo"() ({219 "yield"(%1) : (f32) -> ()220 }) : () -> (f32)221 %3 = "before"() : () -> f32222 return %2 : f32223}224 225module attributes {transform.with_named_sequence} {226 transform.named_sequence @__transform_main(%arg0 : !transform.any_op {transform.readonly}) {227 %op1 = transform.structured.match ops{["foo"]} in %arg0228 : (!transform.any_op) -> !transform.any_op229 %op2 = transform.structured.match ops{["before"]} in %arg0230 : (!transform.any_op) -> !transform.any_op231 // expected-remark@+1{{insertion point does not dominate op}}232 transform.test.move_operand_deps %op1 before %op2233 : !transform.any_op, !transform.any_op234 transform.yield235 }236}237 238// -----239 240// Check simple move value definitions before insertion operation.241func.func @simple_move_values() -> f32 {242 %0 = "before"() : () -> (f32)243 %1 = "moved_op_1"() : () -> (f32)244 %2 = "moved_op_2"() : () -> (f32)245 %3 = "foo"(%1, %2) : (f32, f32) -> (f32)246 return %3 : f32247}248// CHECK-LABEL: func @simple_move_values()249// CHECK: %[[MOVED1:.+]] = "moved_op_1"250// CHECK: %[[MOVED2:.+]] = "moved_op_2"251// CHECK: %[[BEFORE:.+]] = "before"252// CHECK: %[[FOO:.+]] = "foo"(%[[MOVED1]], %[[MOVED2]])253// CHECK: return %[[FOO]]254 255module attributes {transform.with_named_sequence} {256 transform.named_sequence @__transform_main(%arg0 : !transform.any_op {transform.readonly}) {257 %op1 = transform.structured.match ops{["moved_op_1"]} in %arg0258 : (!transform.any_op) -> !transform.any_op259 %op2 = transform.structured.match ops{["moved_op_2"]} in %arg0260 : (!transform.any_op) -> !transform.any_op261 %op3 = transform.structured.match ops{["before"]} in %arg0262 : (!transform.any_op) -> !transform.any_op263 %v1 = transform.get_result %op1[0] : (!transform.any_op) -> !transform.any_value264 %v2 = transform.get_result %op2[0] : (!transform.any_op) -> !transform.any_value265 transform.test.move_value_defns %v1, %v2 before %op3266 : (!transform.any_value, !transform.any_value), !transform.any_op267 transform.yield268 }269}270 271// -----272 273// Compute slice including the implicitly captured values.274func.func @move_region_dependencies_values() -> f32 {275 %0 = "before"() : () -> (f32)276 %1 = "moved_op_1"() : () -> (f32)277 %2 = "moved_op_2"() ({278 %3 = "inner_op"(%1) : (f32) -> (f32)279 "yield"(%3) : (f32) -> ()280 }) : () -> (f32)281 return %2 : f32282}283// CHECK-LABEL: func @move_region_dependencies_values()284// CHECK: %[[MOVED1:.+]] = "moved_op_1"285// CHECK: %[[MOVED2:.+]] = "moved_op_2"286// CHECK: %[[BEFORE:.+]] = "before"287 288module attributes {transform.with_named_sequence} {289 transform.named_sequence @__transform_main(%arg0 : !transform.any_op {transform.readonly}) {290 %op1 = transform.structured.match ops{["moved_op_2"]} in %arg0291 : (!transform.any_op) -> !transform.any_op292 %op2 = transform.structured.match ops{["before"]} in %arg0293 : (!transform.any_op) -> !transform.any_op294 %v1 = transform.get_result %op1[0] : (!transform.any_op) -> !transform.any_value295 transform.test.move_value_defns %v1 before %op2296 : (!transform.any_value), !transform.any_op297 transform.yield298 }299}300 301// -----302 303// Move operations in toplogical sort order304func.func @move_values_in_topological_sort_order() -> f32 {305 %0 = "before"() : () -> (f32)306 %1 = "moved_op_1"() : () -> (f32)307 %2 = "moved_op_2"() : () -> (f32)308 %3 = "moved_op_3"(%1) : (f32) -> (f32)309 %4 = "moved_op_4"(%1, %3) : (f32, f32) -> (f32)310 %5 = "moved_op_5"(%2) : (f32) -> (f32)311 %6 = "foo"(%4, %5) : (f32, f32) -> (f32)312 return %6 : f32313}314// CHECK-LABEL: func @move_values_in_topological_sort_order()315// CHECK: %[[MOVED_1:.+]] = "moved_op_1"316// CHECK-DAG: %[[MOVED_2:.+]] = "moved_op_3"(%[[MOVED_1]])317// CHECK-DAG: %[[MOVED_3:.+]] = "moved_op_4"(%[[MOVED_1]], %[[MOVED_2]])318// CHECK-DAG: %[[MOVED_4:.+]] = "moved_op_2"319// CHECK-DAG: %[[MOVED_5:.+]] = "moved_op_5"(%[[MOVED_4]])320// CHECK: %[[BEFORE:.+]] = "before"321// CHECK: %[[FOO:.+]] = "foo"(%[[MOVED_3]], %[[MOVED_5]])322// CHECK: return %[[FOO]]323 324module attributes {transform.with_named_sequence} {325 transform.named_sequence @__transform_main(%arg0 : !transform.any_op {transform.readonly}) {326 %op1 = transform.structured.match ops{["moved_op_4"]} in %arg0327 : (!transform.any_op) -> !transform.any_op328 %op2 = transform.structured.match ops{["moved_op_5"]} in %arg0329 : (!transform.any_op) -> !transform.any_op330 %op3 = transform.structured.match ops{["before"]} in %arg0331 : (!transform.any_op) -> !transform.any_op332 %v1 = transform.get_result %op1[0] : (!transform.any_op) -> !transform.any_value333 %v2 = transform.get_result %op2[0] : (!transform.any_op) -> !transform.any_value334 transform.test.move_value_defns %v1, %v2 before %op3335 : (!transform.any_value, !transform.any_value), !transform.any_op336 transform.yield337 }338}339 340// -----341 342// Move only those value definitions that are not dominated by insertion point343 344func.func @move_only_required_defns() -> (f32, f32, f32, f32) {345 %0 = "unmoved_op"() : () -> (f32)346 %1 = "dummy_op"() : () -> (f32)347 %2 = "before"() : () -> (f32)348 %3 = "moved_op"() : () -> (f32)349 return %0, %1, %2, %3 : f32, f32, f32, f32350}351// CHECK-LABEL: func @move_only_required_defns()352// CHECK: %[[UNMOVED:.+]] = "unmoved_op"353// CHECK: %[[DUMMY:.+]] = "dummy_op"354// CHECK: %[[MOVED:.+]] = "moved_op"355// CHECK: %[[BEFORE:.+]] = "before"356 357module attributes {transform.with_named_sequence} {358 transform.named_sequence @__transform_main(%arg0 : !transform.any_op {transform.readonly}) {359 %op1 = transform.structured.match ops{["unmoved_op"]} in %arg0360 : (!transform.any_op) -> !transform.any_op361 %op2 = transform.structured.match ops{["dummy_op"]} in %arg0362 : (!transform.any_op) -> !transform.any_op363 %op3 = transform.structured.match ops{["before"]} in %arg0364 : (!transform.any_op) -> !transform.any_op365 %op4 = transform.structured.match ops{["moved_op"]} in %arg0366 : (!transform.any_op) -> !transform.any_op367 %v1 = transform.get_result %op1[0] : (!transform.any_op) -> !transform.any_value368 %v2 = transform.get_result %op4[0] : (!transform.any_op) -> !transform.any_value369 transform.test.move_value_defns %v1, %v2 before %op3370 : (!transform.any_value, !transform.any_value), !transform.any_op371 transform.yield372 }373}374 375// -----376 377// Move only those value definitions that are not dominated by insertion point378 379func.func @move_only_required_defns() -> (f32, f32, f32, f32) {380 %0 = "unmoved_op"() : () -> (f32)381 %1 = "dummy_op"() : () -> (f32)382 %2 = "before"() : () -> (f32)383 %3 = "moved_op"() : () -> (f32)384 return %0, %1, %2, %3 : f32, f32, f32, f32385}386// CHECK-LABEL: func @move_only_required_defns()387// CHECK: %[[UNMOVED:.+]] = "unmoved_op"388// CHECK: %[[DUMMY:.+]] = "dummy_op"389// CHECK: %[[MOVED:.+]] = "moved_op"390// CHECK: %[[BEFORE:.+]] = "before"391 392module attributes {transform.with_named_sequence} {393 transform.named_sequence @__transform_main(%arg0 : !transform.any_op {transform.readonly}) {394 %op1 = transform.structured.match ops{["unmoved_op"]} in %arg0395 : (!transform.any_op) -> !transform.any_op396 %op2 = transform.structured.match ops{["dummy_op"]} in %arg0397 : (!transform.any_op) -> !transform.any_op398 %op3 = transform.structured.match ops{["before"]} in %arg0399 : (!transform.any_op) -> !transform.any_op400 %op4 = transform.structured.match ops{["moved_op"]} in %arg0401 : (!transform.any_op) -> !transform.any_op402 %v1 = transform.get_result %op1[0] : (!transform.any_op) -> !transform.any_value403 %v2 = transform.get_result %op4[0] : (!transform.any_op) -> !transform.any_value404 transform.test.move_value_defns %v1, %v2 before %op3405 : (!transform.any_value, !transform.any_value), !transform.any_op406 transform.yield407 }408}409 410// -----411 412// Check handling of block arguments413func.func @move_only_required_defns() -> (f32, f32) {414 %0 = "unmoved_op"() : () -> (f32)415 cf.br ^bb0(%0 : f32) 416 ^bb0(%arg0 : f32) :417 %1 = "before"() : () -> (f32)418 %2 = "moved_op"(%arg0) : (f32) -> (f32)419 return %1, %2 : f32, f32420}421// CHECK-LABEL: func @move_only_required_defns()422// CHECK: %[[MOVED:.+]] = "moved_op"423// CHECK: %[[BEFORE:.+]] = "before"424 425module attributes {transform.with_named_sequence} {426 transform.named_sequence @__transform_main(%arg0 : !transform.any_op {transform.readonly}) {427 %op1 = transform.structured.match ops{["before"]} in %arg0428 : (!transform.any_op) -> !transform.any_op429 %op2 = transform.structured.match ops{["moved_op"]} in %arg0430 : (!transform.any_op) -> !transform.any_op431 %v1 = transform.get_result %op2[0] : (!transform.any_op) -> !transform.any_value432 transform.test.move_value_defns %v1 before %op1433 : (!transform.any_value), !transform.any_op434 transform.yield435 }436}437 438// -----439 440// Do not move across basic blocks441func.func @no_move_across_basic_blocks() -> (f32, f32) {442 %0 = "unmoved_op"() : () -> (f32)443 %1 = "before"() : () -> (f32)444 cf.br ^bb0(%0 : f32) 445 ^bb0(%arg0 : f32) :446 %2 = "moved_op"(%arg0) : (f32) -> (f32)447 return %1, %2 : f32, f32448}449 450module attributes {transform.with_named_sequence} {451 transform.named_sequence @__transform_main(%arg0 : !transform.any_op {transform.readonly}) {452 %op1 = transform.structured.match ops{["before"]} in %arg0453 : (!transform.any_op) -> !transform.any_op454 %op2 = transform.structured.match ops{["moved_op"]} in %arg0455 : (!transform.any_op) -> !transform.any_op456 %v1 = transform.get_result %op2[0] : (!transform.any_op) -> !transform.any_value457 // expected-remark@+1{{unsupported case of moving definition of value before an insertion point in a different basic block}}458 transform.test.move_value_defns %v1 before %op1459 : (!transform.any_value), !transform.any_op460 transform.yield461 }462}463 464// -----465 466func.func @move_isolated_from_above() -> () {467 %1 = "before"() : () -> (f32)468 %2 = "moved0"() : () -> (f32)469 %3 = test.isolated_one_region_op %2 {} : f32 -> f32470 %4 = "moved1"(%3) : (f32) -> (f32)471 return472}473// CHECK-LABEL: func @move_isolated_from_above()474// CHECK: %[[MOVED0:.+]] = "moved0"475// CHECK: %[[ISOLATED:.+]] = test.isolated_one_region_op %[[MOVED0]]476// CHECK: %[[MOVED1:.+]] = "moved1"(%[[ISOLATED]])477// CHECK: %[[BEFORE:.+]] = "before"478 479module attributes {transform.with_named_sequence} {480 transform.named_sequence @__transform_main(%arg0 : !transform.any_op {transform.readonly}) {481 %op1 = transform.structured.match ops{["before"]} in %arg0482 : (!transform.any_op) -> !transform.any_op483 %op2 = transform.structured.match ops{["moved1"]} in %arg0484 : (!transform.any_op) -> !transform.any_op485 %v1 = transform.get_result %op2[0] : (!transform.any_op) -> !transform.any_value486 transform.test.move_value_defns %v1 before %op1487 : (!transform.any_value), !transform.any_op488 transform.yield489 }490}491