-
Notifications
You must be signed in to change notification settings - Fork 13.5k
[MLIR][Python] Add optional arguments to PassManager IR printing #89301
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
base: main
Are you sure you want to change the base?
Conversation
Thank you for submitting a Pull Request (PR) to the LLVM Project! This PR will be automatically labeled and the relevant teams will be If you wish to, you can add reviewers by using the "Reviewers" section on this page. If this is not working for you, it is probably because you do not have write If you have received no comments on your PR for a week, you can request a review If you have further questions, they may be answered by the LLVM GitHub User Guide. You can also ask questions in a comment on this PR, on the LLVM Discord or on the forums. |
@llvm/pr-subscribers-mlir Author: None (vraspar) ChangesThis MR adds support for more granular ir printing for python pass manager by exposing existing parameters Pass Manager CPP API. Specifically, it adds followng arguments:
Full diff: https://github.com/llvm/llvm-project/pull/89301.diff 4 Files Affected:
diff --git a/mlir/include/mlir-c/Pass.h b/mlir/include/mlir-c/Pass.h
index 35db138305d1e2..47edaecd5ed8d8 100644
--- a/mlir/include/mlir-c/Pass.h
+++ b/mlir/include/mlir-c/Pass.h
@@ -76,7 +76,15 @@ mlirPassManagerRunOnOp(MlirPassManager passManager, MlirOperation op);
/// Enable mlir-print-ir-after-all.
MLIR_CAPI_EXPORTED void
-mlirPassManagerEnableIRPrinting(MlirPassManager passManager);
+mlirPassManagerEnableIRPrinting(MlirPassManager passManager,
+ bool shouldPrintBeforePass,
+ bool shouldPrintAfterPass,
+ bool printAfterOnlyOnChange,
+ bool printAfterOnlyOnFailure);
+
+// Enable timing of passes
+MLIR_CAPI_EXPORTED void
+mlirPassManagerEnableTiming(MlirPassManager passManager);
/// Enable / disable verify-each.
MLIR_CAPI_EXPORTED void
diff --git a/mlir/lib/Bindings/Python/Pass.cpp b/mlir/lib/Bindings/Python/Pass.cpp
index a68421b61641f6..60694fa00782a3 100644
--- a/mlir/lib/Bindings/Python/Pass.cpp
+++ b/mlir/lib/Bindings/Python/Pass.cpp
@@ -74,10 +74,27 @@ void mlir::python::populatePassManagerSubmodule(py::module &m) {
"Releases (leaks) the backing pass manager (testing)")
.def(
"enable_ir_printing",
- [](PyPassManager &passManager) {
- mlirPassManagerEnableIRPrinting(passManager.get());
+ [](PyPassManager &passManager,
+ bool print_before_pass,
+ bool print_after_pass,
+ bool print_after_only_on_change,
+ bool print_after_only_on_failure) {
+ mlirPassManagerEnableIRPrinting(passManager.get(),
+ print_before_pass,
+ print_after_pass,
+ print_after_only_on_change,
+ print_after_only_on_failure);
},
+ "print_before_pass"_a = true, "print_after_pass"_a = true,
+ "print_after_only_on_change"_a = true, "print_after_only_on_failure"_a = false,
"Enable mlir-print-ir-after-all.")
+ .def(
+ "enable_timing",
+ [](PyPassManager &PyPassManager) {
+ mlirPassManagerEnableTiming(PyPassManager.get());
+ },
+ "Enable timing of passes"
+ )
.def(
"enable_verifier",
[](PyPassManager &passManager, bool enable) {
diff --git a/mlir/lib/CAPI/IR/Pass.cpp b/mlir/lib/CAPI/IR/Pass.cpp
index d242baae99c086..a499b1cdbf501f 100644
--- a/mlir/lib/CAPI/IR/Pass.cpp
+++ b/mlir/lib/CAPI/IR/Pass.cpp
@@ -44,8 +44,23 @@ MlirLogicalResult mlirPassManagerRunOnOp(MlirPassManager passManager,
return wrap(unwrap(passManager)->run(unwrap(op)));
}
-void mlirPassManagerEnableIRPrinting(MlirPassManager passManager) {
- return unwrap(passManager)->enableIRPrinting();
+void mlirPassManagerEnableIRPrinting(MlirPassManager passManager,
+ bool shouldPrintBeforePass,
+ bool shouldPrintAfterPass,
+ bool printAfterOnlyOnChange,
+ bool printAfterOnlyOnFailure) {
+ auto shouldPrintBeforeFn = [shouldPrintBeforePass](Pass *, Operation *) {return shouldPrintBeforePass;};
+ auto shouldPrintAfterFn = [shouldPrintAfterPass](Pass *, Operation *) {return shouldPrintAfterPass;};
+
+ return unwrap(passManager)->enableIRPrinting(shouldPrintBeforeFn,
+ shouldPrintAfterFn,
+ true,
+ printAfterOnlyOnChange,
+ printAfterOnlyOnFailure);
+}
+
+void mlirPassManagerEnableTiming(MlirPassManager passManager) {
+ return unwrap(passManager)->enableTiming();
}
void mlirPassManagerEnableVerifier(MlirPassManager passManager, bool enable) {
diff --git a/mlir/python/mlir/_mlir_libs/_mlir/passmanager.pyi b/mlir/python/mlir/_mlir_libs/_mlir/passmanager.pyi
index c072d5e0fb86f3..1c0e7d4d0f6151 100644
--- a/mlir/python/mlir/_mlir_libs/_mlir/passmanager.pyi
+++ b/mlir/python/mlir/_mlir_libs/_mlir/passmanager.pyi
@@ -4,6 +4,7 @@
# * Relative imports for cross-module references.
# * Add __all__
+from pickle import TRUE
from typing import Any, Optional
from . import ir as _ir
@@ -16,7 +17,14 @@ class PassManager:
def __init__(self, context: Optional[_ir.Context] = None) -> None: ...
def _CAPICreate(self) -> object: ...
def _testing_release(self) -> None: ...
- def enable_ir_printing(self) -> None: ...
+ def enable_ir_printing(
+ self,
+ print_before_pass=True,
+ print_after_pass=True,
+ print_after_only_on_change=True,
+ print_after_only_on_failure=False,
+ ) -> None: ...
+ def enable_timing(self) -> None: ...
def enable_verifier(self, enable: bool) -> None: ...
@staticmethod
def parse(pipeline: str, context: Optional[_ir.Context] = None) -> PassManager: ...
|
caff7d4
to
43a4862
Compare
You can test this locally with the following command:git-clang-format --diff 4759890f859277cd798648a9a333573cd088d98a dd062a077de06018cd765526696f6e7200b66c10 -- mlir/include/mlir-c/Pass.h mlir/lib/Bindings/Python/Pass.cpp mlir/lib/CAPI/IR/Pass.cpp View the diff from clang-format here.diff --git a/mlir/lib/CAPI/IR/Pass.cpp b/mlir/lib/CAPI/IR/Pass.cpp
index 6d63b6519bd..fdee1077526 100644
--- a/mlir/lib/CAPI/IR/Pass.cpp
+++ b/mlir/lib/CAPI/IR/Pass.cpp
@@ -50,8 +50,12 @@ void mlirPassManagerEnableIRPrinting(MlirPassManager passManager,
bool printModuleScope,
bool printAfterOnlyOnChange,
bool printAfterOnlyOnFailure) {
- auto shouldPrintBeforeFn = [shouldPrintBeforePass](Pass *, Operation *) {return shouldPrintBeforePass;};
- auto shouldPrintAfterFn = [shouldPrintAfterPass](Pass *, Operation *) {return shouldPrintAfterPass;};
+ auto shouldPrintBeforeFn = [shouldPrintBeforePass](Pass *, Operation *) {
+ return shouldPrintBeforePass;
+ };
+ auto shouldPrintAfterFn = [shouldPrintAfterPass](Pass *, Operation *) {
+ return shouldPrintAfterPass;
+ };
return unwrap(passManager)
->enableIRPrinting(shouldPrintBeforeFn, shouldPrintAfterFn,
|
Overall this is cool - just those small things and I'll approve (and then we wait for 2 days for Windows pre-commit CI workers lol). But I'll keep hitting "approve and run" for you. |
43a4862
to
dd062a0
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder if this would be the right time to introduce a PassManager::PrintConfig
struct, or even a more general PassManagerConfig
, that would take care of all these API flags. This way, we won't break C API unnecessarily and sparse C and C++ clients the pain on passing a list of mostly useless options.
auto shouldPrintBeforeFn = [shouldPrintBeforePass](Pass *, Operation *) {return shouldPrintBeforePass;}; | ||
auto shouldPrintAfterFn = [shouldPrintAfterPass](Pass *, Operation *) {return shouldPrintAfterPass;}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can't we actually take a C function pointer instead? On the Python side, we can then do a dispatch based on the actual type and accept bool as well as a py::function
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi! I am so sorry for the delay.
I am new to the MLIR world, so my understanding might be incorrect. But, I believe useful implementation from py::function
to std::function<bool(Pass *, Operation *)>
will need additional wrappers around the Pass and Operation class. Should we add these changes to this pull request?
Thank you so much!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wrappers are already available. This can take a bool (*shouldPrintAfterPass)(MlirPass, MlirOperation, void *userData)
. Python binding side can define two overloads: one that takes a bool and another that takes a std::function<bool (MlirPass, MlirOperation)>
, both using lambdas to delegate further. I believe we have type casters in place for this to work pretty much out of the box.
The implementation of |
Hi @vraspar, just checking in to see if you're still working on this PR. It's been a month since the last update. Enabling the additional IR printing functionality through the Python extension is something we care about. Let me know if you need any help. |
Hi @Andrew-Cain. I am so sorry, I just saw this message. I was on vacation since beginnning of May and did not bring my laptop. I will implement suggested changes and update the PR. Thank you! |
man what a great vacation! |
This MR adds support for more granular IR printing for python pass manager by exposing existing parameters Pass Manager available through the C++ API.
Specifically, it adds following arguments: