[Mlir-commits] [mlir] [MLIR] Rerun control for actions in execution context (PR #209197)
llvmlistbot at llvm.org
llvmlistbot at llvm.org
Mon Jul 13 07:46:19 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-mlir-core
Author: Kigyosi Alexandru (akigyosi)
<details>
<summary>Changes</summary>
Adds a Rerun control value to ExecutionContext::Control that allows the re-execution of the current action immediately after it completes, without restarting the full compilation pipeline. This is analogous to GDB's ability to restart execution from a breakpoint. When the callback returns Rerun, the action is executed normally, then re-dispatched through the full ExecutionContext::operator() pipeline, including breakpoint matching, so the user gets a fresh opportunity to inspect or control the re-execution. As a practical usage example, a breakpoint + an observer can be added, to save and restore IR between runs to check if each run produces the same IR or something different each time. A depth-keyed structure is used, so rerun requests survive nested action dispatch and are consumed by the correct stack frame.
---
Full diff: https://github.com/llvm/llvm-project/pull/209197.diff
3 Files Affected:
- (modified) mlir/include/mlir/Debug/ExecutionContext.h (+5-1)
- (modified) mlir/lib/Debug/ExecutionContext.cpp (+21-1)
- (modified) mlir/unittests/Debug/ExecutionContextTest.cpp (+27)
``````````diff
diff --git a/mlir/include/mlir/Debug/ExecutionContext.h b/mlir/include/mlir/Debug/ExecutionContext.h
index fbad04b9a2f1d..e42d61087f22d 100644
--- a/mlir/include/mlir/Debug/ExecutionContext.h
+++ b/mlir/include/mlir/Debug/ExecutionContext.h
@@ -65,7 +65,8 @@ class ExecutionContext {
/// - Finish: The action is executed and the execution is paused only when we
/// reach the parent/enclosing operation. If there are no enclosing
/// operation, the execution continues without stopping.
- enum Control { Apply = 1, Skip = 2, Step = 3, Next = 4, Finish = 5 };
+ /// - Rerun: The action gets executed again immediately after it finishes.
+ enum Control { Apply = 1, Skip = 2, Step = 3, Next = 4, Finish = 5, Rerun = 6 };
/// The type of the callback that is used to control the execution.
/// The callback is passed the current action.
@@ -134,6 +135,9 @@ class ExecutionContext {
/// The list of managers that are queried for breakpoints.
SmallVector<BreakpointManager *> breakpoints;
+
+ /// Stack of depths of actions that should be rerun.
+ SmallVector<int> rerunControlStack;
};
} // namespace tracing
diff --git a/mlir/lib/Debug/ExecutionContext.cpp b/mlir/lib/Debug/ExecutionContext.cpp
index 7fc5c165d391e..cc72bac549ab0 100644
--- a/mlir/lib/Debug/ExecutionContext.cpp
+++ b/mlir/lib/Debug/ExecutionContext.cpp
@@ -84,10 +84,25 @@ void ExecutionContext::operator()(llvm::function_ref<void()> transform,
case ExecutionContext::Finish:
depthToBreak = depth - 1;
return true;
+ case ExecutionContext::Rerun:
+ depthToBreak = std::nullopt;
+ rerunControlStack.push_back(depth);
+ return true;
}
llvm::report_fatal_error("Unknown control request");
};
+ auto rerunCurrentActionIfRequested = [&]() -> bool {
+ if (!rerunControlStack.empty() && rerunControlStack.back() == depth) {
+ // If the user requested to rerun this action, we do it here.
+ rerunControlStack.pop_back();
+ actionStack = info.getParent();
+ (*this)(transform, action);
+ return true;
+ }
+ return false;
+ };
+
// Try to find a breakpoint that would hit on this action.
// Right now there is no way to collect them all, we stop at the first one.
for (auto *breakpointManager : breakpoints) {
@@ -116,6 +131,11 @@ void ExecutionContext::operator()(llvm::function_ref<void()> transform,
observer->afterExecute(actionStack);
}
- if (depthToBreak && depth <= depthToBreak)
+ if (rerunCurrentActionIfRequested())
+ return;
+
+ if (depthToBreak && depth <= depthToBreak) {
handleUserInput();
+ rerunCurrentActionIfRequested();
+ }
}
diff --git a/mlir/unittests/Debug/ExecutionContextTest.cpp b/mlir/unittests/Debug/ExecutionContextTest.cpp
index 642adff51002a..16c785b6f826e 100644
--- a/mlir/unittests/Debug/ExecutionContextTest.cpp
+++ b/mlir/unittests/Debug/ExecutionContextTest.cpp
@@ -349,4 +349,31 @@ TEST(ExecutionContext, EnableDisableBreakpointOnCallback) {
executionCtx(original, DebuggerAction{});
EXPECT_EQ(counter, 4);
}
+
+TEST(ExecutionContext, RerunRequestedFromPostActionCallback) {
+ // If rerun is requested from the post-action callback path,
+ // the same action must be rerun immediately.
+ std::vector<ExecutionContext::Control> controlSequence = {
+ ExecutionContext::Next, ExecutionContext::Rerun, ExecutionContext::Apply};
+ int idx = 0;
+ int callbackCounter = 0;
+ int executionCounter = 0;
+
+ auto onBreakpoint = [&](const ActionActiveStack *backtrace) {
+ ++callbackCounter;
+ EXPECT_EQ(backtrace->getAction().getTag(), DebuggerAction::tag);
+ return controlSequence[idx++];
+ };
+
+ TagBreakpointManager simpleManager;
+ ExecutionContext executionCtx(onBreakpoint);
+ executionCtx.addBreakpointManager(&simpleManager);
+ simpleManager.addBreakpoint(DebuggerAction::tag);
+
+ auto callback = [&]() { ++executionCounter; };
+
+ executionCtx(callback, DebuggerAction{});
+ EXPECT_EQ(callbackCounter, 3);
+ EXPECT_EQ(executionCounter, 2);
+}
} // namespace
``````````
</details>
https://github.com/llvm/llvm-project/pull/209197
More information about the Mlir-commits
mailing list