| //===- ExecutionContext.cpp - Debug Execution Context Support -------------===// | |
| // | |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| // See https://llvm.org/LICENSE.txt for license information. | |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| // | |
| //===----------------------------------------------------------------------===// | |
| #include "mlir/Debug/ExecutionContext.h" | |
| #include "llvm/ADT/ScopeExit.h" | |
| #include "llvm/Support/FormatVariadic.h" | |
| using namespace mlir; | |
| using namespace mlir::tracing; | |
| //===----------------------------------------------------------------------===// | |
| // ActionActiveStack | |
| //===----------------------------------------------------------------------===// | |
| void ActionActiveStack::print(raw_ostream &os, bool withContext) const { | |
| os << "ActionActiveStack depth " << getDepth() << "\n"; | |
| const ActionActiveStack *current = this; | |
| int count = 0; | |
| while (current) { | |
| llvm::errs() << llvm::formatv("#{0,3}: ", count++); | |
| current->action.print(llvm::errs()); | |
| llvm::errs() << "\n"; | |
| ArrayRef<IRUnit> context = current->action.getContextIRUnits(); | |
| if (withContext && !context.empty()) { | |
| llvm::errs() << "Context:\n"; | |
| llvm::interleave( | |
| current->action.getContextIRUnits(), | |
| [&](const IRUnit &unit) { | |
| llvm::errs() << " - "; | |
| unit.print(llvm::errs()); | |
| }, | |
| [&]() { llvm::errs() << "\n"; }); | |
| llvm::errs() << "\n"; | |
| } | |
| current = current->parent; | |
| } | |
| } | |
| //===----------------------------------------------------------------------===// | |
| // ExecutionContext | |
| //===----------------------------------------------------------------------===// | |
| static const LLVM_THREAD_LOCAL ActionActiveStack *actionStack = nullptr; | |
| void ExecutionContext::registerObserver(Observer *observer) { | |
| observers.push_back(observer); | |
| } | |
| void ExecutionContext::operator()(llvm::function_ref<void()> transform, | |
| const Action &action) { | |
| // Update the top of the stack with the current action. | |
| int depth = 0; | |
| if (actionStack) | |
| depth = actionStack->getDepth() + 1; | |
| ActionActiveStack info{actionStack, action, depth}; | |
| actionStack = &info; | |
| llvm::scope_exit raii([&]() { actionStack = info.getParent(); }); | |
| Breakpoint *breakpoint = nullptr; | |
| // Invoke the callback here and handles control requests here. | |
| auto handleUserInput = [&]() -> bool { | |
| if (!onBreakpointControlExecutionCallback) | |
| return true; | |
| auto todoNext = onBreakpointControlExecutionCallback(actionStack); | |
| switch (todoNext) { | |
| case ExecutionContext::Apply: | |
| depthToBreak = std::nullopt; | |
| return true; | |
| case ExecutionContext::Skip: | |
| depthToBreak = std::nullopt; | |
| return false; | |
| case ExecutionContext::Step: | |
| depthToBreak = depth + 1; | |
| return true; | |
| case ExecutionContext::Next: | |
| depthToBreak = depth; | |
| return true; | |
| case ExecutionContext::Finish: | |
| depthToBreak = depth - 1; | |
| return true; | |
| } | |
| llvm::report_fatal_error("Unknown control request"); | |
| }; | |
| // 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) { | |
| breakpoint = breakpointManager->match(action); | |
| if (breakpoint) | |
| break; | |
| } | |
| info.setBreakpoint(breakpoint); | |
| bool shouldExecuteAction = true; | |
| // If we have a breakpoint, or if `depthToBreak` was previously set and the | |
| // current depth matches, we invoke the user-provided callback. | |
| if (breakpoint || (depthToBreak && depth <= depthToBreak)) | |
| shouldExecuteAction = handleUserInput(); | |
| // Notify the observers about the current action. | |
| for (auto *observer : observers) | |
| observer->beforeExecute(actionStack, breakpoint, shouldExecuteAction); | |
| if (shouldExecuteAction) { | |
| // Execute the action here. | |
| transform(); | |
| // Notify the observers about completion of the action. | |
| for (auto *observer : observers) | |
| observer->afterExecute(actionStack); | |
| } | |
| if (depthToBreak && depth <= depthToBreak) | |
| handleUserInput(); | |
| } |