122 lines · cpp
1//===- ExecutionContext.cpp - Debug Execution Context Support -------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "mlir/Debug/ExecutionContext.h"10 11#include "llvm/ADT/ScopeExit.h"12#include "llvm/Support/FormatVariadic.h"13 14using namespace mlir;15using namespace mlir::tracing;16 17//===----------------------------------------------------------------------===//18// ActionActiveStack19//===----------------------------------------------------------------------===//20 21void ActionActiveStack::print(raw_ostream &os, bool withContext) const {22 os << "ActionActiveStack depth " << getDepth() << "\n";23 const ActionActiveStack *current = this;24 int count = 0;25 while (current) {26 llvm::errs() << llvm::formatv("#{0,3}: ", count++);27 current->action.print(llvm::errs());28 llvm::errs() << "\n";29 ArrayRef<IRUnit> context = current->action.getContextIRUnits();30 if (withContext && !context.empty()) {31 llvm::errs() << "Context:\n";32 llvm::interleave(33 current->action.getContextIRUnits(),34 [&](const IRUnit &unit) {35 llvm::errs() << " - ";36 unit.print(llvm::errs());37 },38 [&]() { llvm::errs() << "\n"; });39 llvm::errs() << "\n";40 }41 current = current->parent;42 }43}44 45//===----------------------------------------------------------------------===//46// ExecutionContext47//===----------------------------------------------------------------------===//48 49static const LLVM_THREAD_LOCAL ActionActiveStack *actionStack = nullptr;50 51void ExecutionContext::registerObserver(Observer *observer) {52 observers.push_back(observer);53}54 55void ExecutionContext::operator()(llvm::function_ref<void()> transform,56 const Action &action) {57 // Update the top of the stack with the current action.58 int depth = 0;59 if (actionStack)60 depth = actionStack->getDepth() + 1;61 ActionActiveStack info{actionStack, action, depth};62 actionStack = &info;63 auto raii = llvm::make_scope_exit([&]() { actionStack = info.getParent(); });64 Breakpoint *breakpoint = nullptr;65 66 // Invoke the callback here and handles control requests here.67 auto handleUserInput = [&]() -> bool {68 if (!onBreakpointControlExecutionCallback)69 return true;70 auto todoNext = onBreakpointControlExecutionCallback(actionStack);71 switch (todoNext) {72 case ExecutionContext::Apply:73 depthToBreak = std::nullopt;74 return true;75 case ExecutionContext::Skip:76 depthToBreak = std::nullopt;77 return false;78 case ExecutionContext::Step:79 depthToBreak = depth + 1;80 return true;81 case ExecutionContext::Next:82 depthToBreak = depth;83 return true;84 case ExecutionContext::Finish:85 depthToBreak = depth - 1;86 return true;87 }88 llvm::report_fatal_error("Unknown control request");89 };90 91 // Try to find a breakpoint that would hit on this action.92 // Right now there is no way to collect them all, we stop at the first one.93 for (auto *breakpointManager : breakpoints) {94 breakpoint = breakpointManager->match(action);95 if (breakpoint)96 break;97 }98 info.setBreakpoint(breakpoint);99 100 bool shouldExecuteAction = true;101 // If we have a breakpoint, or if `depthToBreak` was previously set and the102 // current depth matches, we invoke the user-provided callback.103 if (breakpoint || (depthToBreak && depth <= depthToBreak))104 shouldExecuteAction = handleUserInput();105 106 // Notify the observers about the current action.107 for (auto *observer : observers)108 observer->beforeExecute(actionStack, breakpoint, shouldExecuteAction);109 110 if (shouldExecuteAction) {111 // Execute the action here.112 transform();113 114 // Notify the observers about completion of the action.115 for (auto *observer : observers)116 observer->afterExecute(actionStack);117 }118 119 if (depthToBreak && depth <= depthToBreak)120 handleUserInput();121}122