478 lines · plain
1// RUN: mlir-opt %s --transform-interpreter -allow-unregistered-dialect --split-input-file --verify-diagnostics | FileCheck %s2 3// CHECK-LABEL: func @successful_pass_application(4// CHECK: %[[c5:.*]] = arith.constant 5 : index5// CHECK: return %[[c5]]6func.func @successful_pass_application(%t: tensor<5xf32>) -> index {7 %c0 = arith.constant 0 : index8 %dim = tensor.dim %t, %c0 : tensor<5xf32>9 return %dim : index10}11 12module attributes {transform.with_named_sequence} {13 transform.named_sequence @__transform_main(%arg1: !transform.any_op) {14 %1 = transform.structured.match ops{["func.func"]} in %arg1 : (!transform.any_op) -> !transform.any_op15 transform.apply_registered_pass "canonicalize" to %1 : (!transform.any_op) -> !transform.any_op16 transform.yield17 }18}19 20// -----21 22// CHECK-LABEL: func @pass_pipeline(23func.func @pass_pipeline() {24 return25}26 27module attributes {transform.with_named_sequence} {28 transform.named_sequence @__transform_main(%arg1: !transform.any_op) {29 %1 = transform.structured.match ops{["func.func"]} in %arg1 : (!transform.any_op) -> !transform.any_op30 // This pipeline does not do anything. Just make sure that the pipeline is31 // found and no error is produced.32 transform.apply_registered_pass "test-options-pass-pipeline" to %1 : (!transform.any_op) -> !transform.any_op33 transform.yield34 }35}36 37// -----38 39func.func @invalid_pass_name() {40 return41}42 43module attributes {transform.with_named_sequence} {44 transform.named_sequence @__transform_main(%arg1: !transform.any_op) {45 %1 = transform.structured.match ops{["func.func"]} in %arg1 : (!transform.any_op) -> !transform.any_op46 // expected-error @below {{unknown pass or pass pipeline: non-existing-pass}}47 transform.apply_registered_pass "non-existing-pass" to %1 : (!transform.any_op) -> !transform.any_op48 transform.yield49 }50}51 52// -----53 54func.func @not_isolated_from_above(%t: tensor<5xf32>) -> index {55 %c0 = arith.constant 0 : index56 // expected-note @below {{target op}}57 // expected-error @below {{trying to schedule a pass on an operation not marked as 'IsolatedFromAbove'}}58 %dim = tensor.dim %t, %c0 : tensor<5xf32>59 return %dim : index60}61 62module attributes {transform.with_named_sequence} {63 transform.named_sequence @__transform_main(%arg1: !transform.any_op) {64 %1 = transform.structured.match ops{["tensor.dim"]} in %arg1 : (!transform.any_op) -> !transform.any_op65 // expected-error @below {{pass pipeline failed}}66 transform.apply_registered_pass "canonicalize" to %1 : (!transform.any_op) -> !transform.any_op67 transform.yield68 }69}70 71// -----72 73func.func @invalid_pass_option() {74 return75}76 77module attributes {transform.with_named_sequence} {78 transform.named_sequence @__transform_main(%arg1: !transform.any_op) {79 %1 = transform.structured.match ops{["func.func"]} in %arg1 : (!transform.any_op) -> !transform.any_op80 // expected-error @below {{failed to add pass or pass pipeline to pipeline: canonicalize}}81 // expected-error @below {{<Pass-Options-Parser>: no such option invalid-option}}82 transform.apply_registered_pass "canonicalize"83 with options = { "invalid-option" = 1 } to %184 : (!transform.any_op) -> !transform.any_op85 transform.yield86 }87}88 89// -----90 91// CHECK-LABEL: func @valid_pass_option()92func.func @valid_pass_option() {93 return94}95 96module attributes {transform.with_named_sequence} {97 transform.named_sequence @__transform_main(%arg1: !transform.any_op) {98 %1 = transform.structured.match ops{["func.func"]} in %arg1 : (!transform.any_op) -> !transform.any_op99 transform.apply_registered_pass "canonicalize"100 with options = { "top-down" = false } to %1101 : (!transform.any_op) -> !transform.any_op102 transform.yield103 }104}105 106// -----107 108// CHECK-LABEL: func @valid_pass_options()109func.func @valid_pass_options() {110 return111}112 113module attributes {transform.with_named_sequence} {114 transform.named_sequence @__transform_main(%arg1: !transform.any_op) {115 %1 = transform.structured.match ops{["func.func"]} in %arg1 : (!transform.any_op) -> !transform.any_op116 //transform.apply_registered_pass "canonicalize" with options = "top-down=false,max-iterations=10" to %1 : (!transform.any_op) -> !transform.any_op117 transform.apply_registered_pass "canonicalize"118 with options = { "top-down" = false, "test-convergence" =true } to %1119 : (!transform.any_op) -> !transform.any_op120 transform.yield121 }122}123 124// -----125 126// CHECK-LABEL: func @valid_pass_options_as_list()127func.func @valid_pass_options_as_list() {128 return129}130 131module attributes {transform.with_named_sequence} {132 transform.named_sequence @__transform_main(%arg1: !transform.any_op) {133 %1 = transform.structured.match ops{["func.func"]} in %arg1 : (!transform.any_op) -> !transform.any_op134 transform.apply_registered_pass "canonicalize"135 with options = { "top-down" = false, "max-iterations" = 0 } to %1136 : (!transform.any_op) -> !transform.any_op137 transform.yield138 }139}140 141// -----142 143// CHECK-LABEL: func @valid_dynamic_pass_options()144func.func @valid_dynamic_pass_options() {145 return146}147 148module attributes {transform.with_named_sequence} {149 transform.named_sequence @__transform_main(%arg1: !transform.any_op) {150 %1 = transform.structured.match ops{["func.func"]} in %arg1 : (!transform.any_op) -> !transform.any_op151 %max_iter = transform.param.constant 10 -> !transform.any_param152 %max_rewrites = transform.param.constant 1 -> !transform.any_param153 %2 = transform.apply_registered_pass154 "canonicalize"155 with options = { "top-down" = false,156 "max-iterations" = %max_iter,157 "test-convergence" = true,158 "max-num-rewrites" = %max_rewrites }159 to %1160 : (!transform.any_op, !transform.any_param, !transform.any_param) -> !transform.any_op161 transform.yield162 }163}164 165// -----166 167// CHECK-LABEL: func private @valid_multiple_values_as_list_option_single_param()168module {169 func.func @valid_multiple_values_as_list_option_single_param() {170 return171 }172 173 // CHECK: func @a()174 func.func @a() {175 return176 }177 // CHECK: func @b()178 func.func @b() {179 return180 }181}182 183module attributes {transform.with_named_sequence} {184 transform.named_sequence @__transform_main(%arg1: !transform.any_op) {185 %1 = transform.structured.match ops{["func.func"]} in %arg1 : (!transform.any_op) -> !transform.any_op186 %2 = transform.get_parent_op %1 { deduplicate } : (!transform.any_op) -> !transform.any_op187 %symbol_a = transform.param.constant "a" -> !transform.any_param188 %symbol_b = transform.param.constant "b" -> !transform.any_param189 %multiple_symbol_names = transform.merge_handles %symbol_a, %symbol_b : !transform.any_param190 transform.apply_registered_pass "symbol-privatize"191 with options = { exclude = %multiple_symbol_names } to %2192 : (!transform.any_op, !transform.any_param) -> !transform.any_op193 transform.yield194 }195}196 197// -----198 199// CHECK-LABEL: func private @valid_array_attr_as_list_option()200module {201 func.func @valid_array_attr_as_list_option() {202 return203 }204 205 // CHECK: func @a()206 func.func @a() {207 return208 }209 // CHECK: func @b()210 func.func @b() {211 return212 }213}214 215module attributes {transform.with_named_sequence} {216 transform.named_sequence @__transform_main(%arg1: !transform.any_op) {217 %1 = transform.structured.match ops{["func.func"]} in %arg1 : (!transform.any_op) -> !transform.any_op218 %2 = transform.get_parent_op %1 { deduplicate } : (!transform.any_op) -> !transform.any_op219 transform.apply_registered_pass "symbol-privatize"220 with options = { exclude = ["a", "b"] } to %2221 : (!transform.any_op) -> !transform.any_op222 transform.yield223 }224}225 226// -----227 228// CHECK-LABEL: func private @valid_array_attr_param_as_list_option()229module {230 func.func @valid_array_attr_param_as_list_option() {231 return232 }233 234 // CHECK: func @a()235 func.func @a() {236 return237 }238 // CHECK: func @b()239 func.func @b() {240 return241 }242}243 244module attributes {transform.with_named_sequence} {245 transform.named_sequence @__transform_main(%arg1: !transform.any_op) {246 %1 = transform.structured.match ops{["func.func"]} in %arg1 : (!transform.any_op) -> !transform.any_op247 %2 = transform.get_parent_op %1 { deduplicate } : (!transform.any_op) -> !transform.any_op248 %multiple_symbol_names = transform.param.constant ["a","b"] -> !transform.any_param249 transform.apply_registered_pass "symbol-privatize"250 with options = { exclude = %multiple_symbol_names } to %2251 : (!transform.any_op, !transform.any_param) -> !transform.any_op252 transform.yield253 }254}255 256// -----257 258// CHECK-LABEL: func private @valid_multiple_params_as_single_list_option()259module {260 func.func @valid_multiple_params_as_single_list_option() {261 return262 }263 264 // CHECK: func @a()265 func.func @a() {266 return267 }268 // CHECK: func @b()269 func.func @b() {270 return271 }272}273 274module attributes {transform.with_named_sequence} {275 transform.named_sequence @__transform_main(%arg1: !transform.any_op) {276 %1 = transform.structured.match ops{["func.func"]} in %arg1 : (!transform.any_op) -> !transform.any_op277 %2 = transform.get_parent_op %1 { deduplicate } : (!transform.any_op) -> !transform.any_op278 %symbol_a = transform.param.constant "a" -> !transform.any_param279 %symbol_b = transform.param.constant "b" -> !transform.any_param280 transform.apply_registered_pass "symbol-privatize"281 with options = { exclude = [%symbol_a, %symbol_b] } to %2282 : (!transform.any_op, !transform.any_param, !transform.any_param) -> !transform.any_op283 transform.yield284 }285}286 287// -----288 289func.func @invalid_options_as_str() {290 return291}292 293module attributes {transform.with_named_sequence} {294 transform.named_sequence @__transform_main(%arg1: !transform.any_op) {295 %1 = transform.structured.match ops{["func.func"]} in %arg1 : (!transform.any_op) -> !transform.any_op296 // expected-error @+2 {{expected '{' in options dictionary}}297 %2 = transform.apply_registered_pass "canonicalize"298 with options = "top-down=false" to %1 : (!transform.any_op) -> !transform.any_op299 transform.yield300 }301}302 303// -----304 305func.func @invalid_options_as_pairs_without_braces() {306 return307}308 309module attributes {transform.with_named_sequence} {310 transform.named_sequence @__transform_main(%arg1: !transform.any_op) {311 %1 = transform.structured.match ops{["func.func"]} in %arg1 : (!transform.any_op) -> !transform.any_op312 // expected-error @+2 {{expected '{' in options dictionary}}313 %2 = transform.apply_registered_pass "canonicalize"314 with options = "top-down"=false to %1 : (!transform.any_op) -> !transform.any_op315 transform.yield316 }317}318 319// -----320 321func.func @invalid_options_due_to_reserved_attr() {322 return323}324 325module attributes {transform.with_named_sequence} {326 transform.named_sequence @__transform_main(%arg1: !transform.any_op) {327 %1 = transform.structured.match ops{["func.func"]} in %arg1 : (!transform.any_op) -> !transform.any_op328 // expected-error @+3 {{the param_operand attribute is a marker reserved for indicating a value will be passed via params and is only used in the generic print format}}329 // expected-error @+2 {{expected a valid attribute or operand as value associated to key 'top-down'}}330 %2 = transform.apply_registered_pass "canonicalize"331 with options = { "top-down" = #transform.param_operand<index=0> } to %1 : (!transform.any_op) -> !transform.any_op332 transform.yield333 }334}335 336// -----337 338func.func @invalid_options_due_duplicated_key() {339 return340}341 342module attributes {transform.with_named_sequence} {343 transform.named_sequence @__transform_main(%arg1: !transform.any_op) {344 %1 = transform.structured.match ops{["func.func"]} in %arg1 : (!transform.any_op) -> !transform.any_op345 // expected-error @+2 {{duplicate keys found in options dictionary}}346 %2 = transform.apply_registered_pass "canonicalize"347 with options = {"top-down"=false,"top-down"=true} to %1 : (!transform.any_op) -> !transform.any_op348 transform.yield349 }350}351 352// -----353 354func.func @invalid_options_due_invalid_key() {355 return356}357 358module attributes {transform.with_named_sequence} {359 transform.named_sequence @__transform_main(%arg1: !transform.any_op) {360 %1 = transform.structured.match ops{["func.func"]} in %arg1 : (!transform.any_op) -> !transform.any_op361 // expected-error @+2 {{expected key to either be an identifier or a string}}362 %2 = transform.apply_registered_pass "canonicalize"363 with options = { @label = 0 } to %1 : (!transform.any_op) -> !transform.any_op364 transform.yield365 }366}367 368// -----369 370func.func @invalid_pass_option_bare_param() {371 return372}373 374module attributes {transform.with_named_sequence} {375 transform.named_sequence @__transform_main(%arg1: !transform.any_op) {376 %1 = transform.structured.match ops{["func.func"]} in %arg1 : (!transform.any_op) -> !transform.any_op377 %pass_options = transform.param.constant 42 -> !transform.any_param378 // expected-error @+2 {{expected '{' in options dictionary}}379 transform.apply_registered_pass "canonicalize"380 with options = %pass_options to %1381 : (!transform.any_op, !transform.any_param) -> !transform.any_op382 transform.yield383 }384}385 386// -----387 388module attributes {transform.with_named_sequence} {389 // expected-error @below {{trying to schedule pass 'DuplicateFunctionEliminationPass' on an unsupported operation}}390 // expected-note @below {{target op}}391 func.func @invalid_target_op_type() {392 return393 }394 395 transform.named_sequence @__transform_main(%arg1: !transform.any_op) {396 %1 = transform.structured.match ops{["func.func"]} in %arg1 : (!transform.any_op) -> !transform.any_op397 398 // duplicate-function-elimination can be applied only to ModuleOps.399 // expected-error @below {{pass pipeline failed}}400 transform.apply_registered_pass "duplicate-function-elimination" to %1 : (!transform.any_op) -> !transform.any_op401 transform.yield402 }403}404 405// -----406 407/////////////////////////////////////////////////////////////////////408// Check that the following cases are caugh in the generic format. //409/////////////////////////////////////////////////////////////////////410 411// Invalid due to param_operand occurences in options dict not being412// one-to-one with the dynamic options provided as params:413// param_operand_index out of bounds w.r.t. the number of options provided via params.414 415"builtin.module"() ({416 "transform.named_sequence"() <{function_type = (!transform.any_op) -> (), sym_name = "__transform_main"}> ({417 ^bb0(%arg0: !transform.any_op):418 %0 = "transform.structured.match"(%arg0) <{ops = ["func.func"]}> : (!transform.any_op) -> !transform.any_op419 %1 = "transform.param.constant"() <{value = 10 : i64}> : () -> !transform.any_param420 // expected-error @below {{dynamic option index 1 is out of bounds for the number of dynamic options: 1}}421 %2 = "transform.apply_registered_pass"(%0, %1) <{422 options = {"max-iterations" = #transform.param_operand<index=1 : i64>,423 "test-convergence" = true,424 "top-down" = false},425 pass_name = "canonicalize"}>426 : (!transform.any_op, !transform.any_param) -> !transform.any_op427 "transform.yield"() : () -> ()428 }) : () -> ()429}) {transform.with_named_sequence} : () -> ()430 431// -----432 433// Invalid due to param_operand occurences in options dict not being434// one-to-one with the dynamic options provided as params:435// the first option-param is referred to twice and the second one not at all.436// (In the pretty-printed format, if you want to refer to a param SSA-value twice, it counts as two param arguments.)437 438"builtin.module"() ({439 "transform.named_sequence"() <{function_type = (!transform.any_op) -> (), sym_name = "__transform_main"}> ({440 ^bb0(%arg0: !transform.any_op):441 %0 = "transform.structured.match"(%arg0) <{ops = ["func.func"]}> : (!transform.any_op) -> !transform.any_op442 %1 = "transform.param.constant"() <{value = 10 : i64}> : () -> !transform.any_param443 %2 = "transform.param.constant"() <{value = 1 : i64}> : () -> !transform.any_param444 // expected-error @below {{dynamic option index 0 is already used in options}}445 %3 = "transform.apply_registered_pass"(%0, %1, %2) <{446 options = {"max-iterations" = #transform.param_operand<index=0 : i64>,447 "max-num-rewrites" = #transform.param_operand<index=0 : i64>,448 "test-convergence" = true,449 "top-down" = false},450 pass_name = "canonicalize"}>451 : (!transform.any_op, !transform.any_param, !transform.any_param) -> !transform.any_op452 "transform.yield"() : () -> ()453 }) : () -> ()454}) {transform.with_named_sequence} : () -> ()455 456// -----457 458// Invalid due to param_operand occurences in options dict not being459// one-to-one with the dynamic options provided as params:460// two option-params are provide though only the first one is referred to from the options-dict.461 462"builtin.module"() ({463 "transform.named_sequence"() <{function_type = (!transform.any_op) -> (), sym_name = "__transform_main"}> ({464 ^bb0(%arg0: !transform.any_op):465 %0 = "transform.structured.match"(%arg0) <{ops = ["func.func"]}> : (!transform.any_op) -> !transform.any_op466 %1 = "transform.param.constant"() <{value = 10 : i64}> : () -> !transform.any_param467 %2 = "transform.param.constant"() <{value = 1 : i64}> : () -> !transform.any_param468 // expected-error @below {{a param operand does not have a corresponding param_operand attr in the options dict}}469 %3 = "transform.apply_registered_pass"(%0, %1, %2) <{470 options = {"max-iterations" = #transform.param_operand<index=0 : i64>,471 "test-convergence" = true,472 "top-down" = false},473 pass_name = "canonicalize"}>474 : (!transform.any_op, !transform.any_param, !transform.any_param) -> !transform.any_op475 "transform.yield"() : () -> ()476 }) : () -> ()477}) {transform.with_named_sequence} : () -> ()478