Skip to content

[MLIR][Transform] apply_registered_pass: support ListOptions #144026

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Jun 16, 2025

Conversation

rolfmorel
Copy link
Contributor

@rolfmorel rolfmorel commented Jun 13, 2025

Interpret an option value with multiple values, either in the form of an ArrayAttr (either static or passed through a param) or as the multiple attrs associated to a param, as a comma-separated list, i.e. as a ListOption on a pass.

@llvmbot
Copy link
Member

llvmbot commented Jun 13, 2025

@llvm/pr-subscribers-mlir

Author: Rolf Morel (rolfmorel)

Changes

Interpret the multiple values associated to a param as a comma-separated list, i.e. as the analog of a ListOption on a pass.


Full diff: https://github.com/llvm/llvm-project/pull/144026.diff

2 Files Affected:

  • (modified) mlir/lib/Dialect/Transform/IR/TransformOps.cpp (+13-15)
  • (modified) mlir/test/Dialect/Transform/test-pass-application.mlir (+32-20)
diff --git a/mlir/lib/Dialect/Transform/IR/TransformOps.cpp b/mlir/lib/Dialect/Transform/IR/TransformOps.cpp
index 582d082153bef..bfe6416987629 100644
--- a/mlir/lib/Dialect/Transform/IR/TransformOps.cpp
+++ b/mlir/lib/Dialect/Transform/IR/TransformOps.cpp
@@ -791,6 +791,12 @@ transform::ApplyRegisteredPassOp::apply(transform::TransformRewriter &rewriter,
 
   std::string options;
   llvm::raw_string_ostream optionsStream(options); // For "printing" attrs.
+  auto appendValueAttr = [&](Attribute valueAttr) {
+    if (auto strAttr = dyn_cast<StringAttr>(valueAttr))
+      optionsStream << strAttr.getValue().str();
+    else
+      valueAttr.print(optionsStream, /*elideType=*/true);
+  };
 
   OperandRange dynamicOptions = getDynamicOptions();
   for (auto [idx, namedAttribute] : llvm::enumerate(getOptions())) {
@@ -799,7 +805,6 @@ transform::ApplyRegisteredPassOp::apply(transform::TransformRewriter &rewriter,
     optionsStream << namedAttribute.getName().str(); // Append the key.
     optionsStream << "="; // And the key-value separator.
 
-    Attribute valueAttrToAppend;
     if (auto paramOperandIndex =
             dyn_cast<transform::ParamOperandAttr>(namedAttribute.getValue())) {
       // The corresponding value attribute is passed in via a param.
@@ -810,22 +815,15 @@ transform::ApplyRegisteredPassOp::apply(transform::TransformRewriter &rewriter,
              "should be the same as the number of options passed as params");
       ArrayRef<Attribute> dynamicOption =
           state.getParams(dynamicOptions[dynamicOptionIdx]);
-      if (dynamicOption.size() != 1)
-        return emitSilenceableError()
-               << "options passed as a param must have "
-                  "a single value associated, param "
-               << dynamicOptionIdx << " associates " << dynamicOption.size();
-      valueAttrToAppend = dynamicOption[0];
+      // Append all attributes associated to the param, separated by commas.
+      for (auto [idx, associatedAttr] : llvm::enumerate(dynamicOption)) {
+        if (idx > 0)
+          optionsStream << ",";
+        appendValueAttr(associatedAttr);
+      }
     } else {
       // Value is a static attribute.
-      valueAttrToAppend = namedAttribute.getValue();
-    }
-
-    // Append string representation of value attribute.
-    if (auto strAttr = dyn_cast<StringAttr>(valueAttrToAppend)) {
-      optionsStream << strAttr.getValue().str();
-    } else {
-      valueAttrToAppend.print(optionsStream, /*elideType=*/true);
+      appendValueAttr(namedAttribute.getValue());
     }
   }
   optionsStream.flush();
diff --git a/mlir/test/Dialect/Transform/test-pass-application.mlir b/mlir/test/Dialect/Transform/test-pass-application.mlir
index 1d1be9eda3496..407dfa3823436 100644
--- a/mlir/test/Dialect/Transform/test-pass-application.mlir
+++ b/mlir/test/Dialect/Transform/test-pass-application.mlir
@@ -164,6 +164,38 @@ module attributes {transform.with_named_sequence} {
 
 // -----
 
+// CHECK-LABEL: func private @valid_dynamic_pass_list_option()
+module {
+  func.func @valid_dynamic_pass_list_option() {
+    return
+  }
+
+  // CHECK: func @a()
+  func.func @a() {
+    return
+  }
+  // CHECK: func @b()
+  func.func @b() {
+    return
+  }
+}
+
+module attributes {transform.with_named_sequence} {
+  transform.named_sequence @__transform_main(%arg1: !transform.any_op) {
+    %1 = transform.structured.match ops{["func.func"]} in %arg1 : (!transform.any_op) -> !transform.any_op
+    %2 = transform.get_parent_op %1 { deduplicate } : (!transform.any_op) -> !transform.any_op
+    %symbol_a = transform.param.constant "a" -> !transform.any_param
+    %symbol_b = transform.param.constant "b" -> !transform.any_param
+    %multiple_symbol_names = transform.merge_handles %symbol_a, %symbol_b : !transform.any_param
+    transform.apply_registered_pass "symbol-privatize"
+        with options = { exclude = %multiple_symbol_names } to %2
+        : (!transform.any_op, !transform.any_param) -> !transform.any_op
+    transform.yield
+  }
+}
+
+// -----
+
 func.func @invalid_options_as_str() {
   return
 }
@@ -262,26 +294,6 @@ module attributes {transform.with_named_sequence} {
 
 // -----
 
-func.func @too_many_pass_option_params() {
-  return
-}
-
-module attributes {transform.with_named_sequence} {
-  transform.named_sequence @__transform_main(%arg1: !transform.any_op) {
-    %1 = transform.structured.match ops{["func.func"]} in %arg1 : (!transform.any_op) -> !transform.any_op
-    %x = transform.param.constant true -> !transform.any_param
-    %y = transform.param.constant false -> !transform.any_param
-    %topdown_options = transform.merge_handles %x, %y : !transform.any_param
-    // expected-error @below {{options passed as a param must have a single value associated, param 0 associates 2}}
-    transform.apply_registered_pass "canonicalize"
-        with options = { "top-down" = %topdown_options } to %1
-        : (!transform.any_op, !transform.any_param) -> !transform.any_op
-    transform.yield
-  }
-}
-
-// -----
-
 module attributes {transform.with_named_sequence} {
   // expected-error @below {{trying to schedule a pass on an unsupported operation}}
   // expected-note @below {{target op}}

@rolfmorel rolfmorel changed the title [MLIR][Transform] apply_registered_pass: support ListOptions as params [MLIR][Transform] apply_registered_pass: support ListOptions Jun 13, 2025
@rolfmorel rolfmorel force-pushed the transform-reg-pass-list-options branch from a54688e to 7767260 Compare June 13, 2025 08:03
@rolfmorel
Copy link
Contributor Author

rolfmorel commented Jun 13, 2025

Based on offline discussion with @fschlimb, am now working on support for ... with options = { "option-name" = [%param1, %param2] }. Will update the PR in a couple hours.

@llvmbot llvmbot added the mlir:python MLIR Python bindings label Jun 13, 2025
@rolfmorel
Copy link
Contributor Author

Based on offline discussion with @fschlimb, am now working on support for ... with options = { "option-name" = [%param1, %param2] }. Will update the PR in a couple hours.

This is now implemented. Also on the Python side.

Copy link

github-actions bot commented Jun 13, 2025

✅ With the latest revision this PR passed the Python code formatter.

@rolfmorel rolfmorel force-pushed the transform-reg-pass-list-options branch from bcc104a to 83553bc Compare June 16, 2025 10:51
@rolfmorel rolfmorel merged commit e008538 into llvm:main Jun 16, 2025
6 of 7 checks passed
rolfmorel added a commit to libxsmm/tpp-mlir that referenced this pull request Jun 16, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
mlir:python MLIR Python bindings mlir
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants