[rtsan] Remove mkfifoat interceptor (#116997)
[llvm-project.git] / mlir / lib / Debug / DebuggerExecutionContextHook.cpp
blob863113928d5b4f776202f20a109797e132495d99
1 //===- DebuggerExecutionContextHook.cpp - Debugger 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-exception
6 //
7 //===----------------------------------------------------------------------===//
9 #include "mlir/Debug/DebuggerExecutionContextHook.h"
11 #include "mlir/Debug/BreakpointManagers/FileLineColLocBreakpointManager.h"
12 #include "mlir/Debug/BreakpointManagers/TagBreakpointManager.h"
14 using namespace mlir;
15 using namespace mlir::tracing;
17 namespace {
18 /// This structure tracks the state of the interactive debugger.
19 struct DebuggerState {
20 /// This variable keeps track of the current control option. This is set by
21 /// the debugger when control is handed over to it.
22 ExecutionContext::Control debuggerControl = ExecutionContext::Apply;
24 /// The breakpoint manager that allows the debugger to set breakpoints on
25 /// action tags.
26 TagBreakpointManager tagBreakpointManager;
28 /// The breakpoint manager that allows the debugger to set breakpoints on
29 /// FileLineColLoc locations.
30 FileLineColLocBreakpointManager fileLineColLocBreakpointManager;
32 /// Map of breakpoint IDs to breakpoint objects.
33 DenseMap<unsigned, Breakpoint *> breakpointIdsMap;
35 /// The current stack of actiive actions.
36 const tracing::ActionActiveStack *actionActiveStack;
38 /// This is a "cursor" in the IR, it is used for the debugger to navigate the
39 /// IR associated to the actions.
40 IRUnit cursor;
42 } // namespace
44 static DebuggerState &getGlobalDebuggerState() {
45 static LLVM_THREAD_LOCAL DebuggerState debuggerState;
46 return debuggerState;
49 extern "C" {
50 void mlirDebuggerSetControl(int controlOption) {
51 getGlobalDebuggerState().debuggerControl =
52 static_cast<ExecutionContext::Control>(controlOption);
55 void mlirDebuggerPrintContext() {
56 DebuggerState &state = getGlobalDebuggerState();
57 if (!state.actionActiveStack) {
58 llvm::outs() << "No active action.\n";
59 return;
61 const ArrayRef<IRUnit> &units =
62 state.actionActiveStack->getAction().getContextIRUnits();
63 llvm::outs() << units.size() << " available IRUnits:\n";
64 for (const IRUnit &unit : units) {
65 llvm::outs() << " - ";
66 unit.print(
67 llvm::outs(),
68 OpPrintingFlags().useLocalScope().skipRegions().enableDebugInfo());
69 llvm::outs() << "\n";
73 void mlirDebuggerPrintActionBacktrace(bool withContext) {
74 DebuggerState &state = getGlobalDebuggerState();
75 if (!state.actionActiveStack) {
76 llvm::outs() << "No active action.\n";
77 return;
79 state.actionActiveStack->print(llvm::outs(), withContext);
82 //===----------------------------------------------------------------------===//
83 // Cursor Management
84 //===----------------------------------------------------------------------===//
86 void mlirDebuggerCursorPrint(bool withRegion) {
87 auto &state = getGlobalDebuggerState();
88 if (!state.cursor) {
89 llvm::outs() << "No active MLIR cursor, select from the context first\n";
90 return;
92 state.cursor.print(llvm::outs(), OpPrintingFlags()
93 .skipRegions(!withRegion)
94 .useLocalScope()
95 .enableDebugInfo());
96 llvm::outs() << "\n";
99 void mlirDebuggerCursorSelectIRUnitFromContext(int index) {
100 auto &state = getGlobalDebuggerState();
101 if (!state.actionActiveStack) {
102 llvm::outs() << "No active MLIR Action stack\n";
103 return;
105 ArrayRef<IRUnit> units =
106 state.actionActiveStack->getAction().getContextIRUnits();
107 if (index < 0 || index >= static_cast<int>(units.size())) {
108 llvm::outs() << "Index invalid, bounds: [0, " << units.size()
109 << "] but got " << index << "\n";
110 return;
112 state.cursor = units[index];
113 state.cursor.print(llvm::outs());
114 llvm::outs() << "\n";
117 void mlirDebuggerCursorSelectParentIRUnit() {
118 auto &state = getGlobalDebuggerState();
119 if (!state.cursor) {
120 llvm::outs() << "No active MLIR cursor, select from the context first\n";
121 return;
123 IRUnit *unit = &state.cursor;
124 if (auto *op = llvm::dyn_cast_if_present<Operation *>(*unit)) {
125 state.cursor = op->getBlock();
126 } else if (auto *region = llvm::dyn_cast_if_present<Region *>(*unit)) {
127 state.cursor = region->getParentOp();
128 } else if (auto *block = llvm::dyn_cast_if_present<Block *>(*unit)) {
129 state.cursor = block->getParent();
130 } else {
131 llvm::outs() << "Current cursor is not a valid IRUnit";
132 return;
134 state.cursor.print(llvm::outs());
135 llvm::outs() << "\n";
138 void mlirDebuggerCursorSelectChildIRUnit(int index) {
139 auto &state = getGlobalDebuggerState();
140 if (!state.cursor) {
141 llvm::outs() << "No active MLIR cursor, select from the context first\n";
142 return;
144 IRUnit *unit = &state.cursor;
145 if (auto *op = llvm::dyn_cast_if_present<Operation *>(*unit)) {
146 if (index < 0 || index >= static_cast<int>(op->getNumRegions())) {
147 llvm::outs() << "Index invalid, op has " << op->getNumRegions()
148 << " but got " << index << "\n";
149 return;
151 state.cursor = &op->getRegion(index);
152 } else if (auto *region = llvm::dyn_cast_if_present<Region *>(*unit)) {
153 auto block = region->begin();
154 int count = 0;
155 while (block != region->end() && count != index) {
156 ++block;
157 ++count;
160 if (block == region->end()) {
161 llvm::outs() << "Index invalid, region has " << count << " block but got "
162 << index << "\n";
163 return;
165 state.cursor = &*block;
166 } else if (auto *block = llvm::dyn_cast_if_present<Block *>(*unit)) {
167 auto op = block->begin();
168 int count = 0;
169 while (op != block->end() && count != index) {
170 ++op;
171 ++count;
174 if (op == block->end()) {
175 llvm::outs() << "Index invalid, block has " << count
176 << "operations but got " << index << "\n";
177 return;
179 state.cursor = &*op;
180 } else {
181 llvm::outs() << "Current cursor is not a valid IRUnit";
182 return;
184 state.cursor.print(llvm::outs());
185 llvm::outs() << "\n";
188 void mlirDebuggerCursorSelectPreviousIRUnit() {
189 auto &state = getGlobalDebuggerState();
190 if (!state.cursor) {
191 llvm::outs() << "No active MLIR cursor, select from the context first\n";
192 return;
194 IRUnit *unit = &state.cursor;
195 if (auto *op = llvm::dyn_cast_if_present<Operation *>(*unit)) {
196 Operation *previous = op->getPrevNode();
197 if (!previous) {
198 llvm::outs() << "No previous operation in the current block\n";
199 return;
201 state.cursor = previous;
202 } else if (auto *region = llvm::dyn_cast_if_present<Region *>(*unit)) {
203 llvm::outs() << "Has region\n";
204 Operation *parent = region->getParentOp();
205 if (!parent) {
206 llvm::outs() << "No parent operation for the current region\n";
207 return;
209 if (region->getRegionNumber() == 0) {
210 llvm::outs() << "No previous region in the current operation\n";
211 return;
213 state.cursor =
214 &region->getParentOp()->getRegion(region->getRegionNumber() - 1);
215 } else if (auto *block = llvm::dyn_cast_if_present<Block *>(*unit)) {
216 Block *previous = block->getPrevNode();
217 if (!previous) {
218 llvm::outs() << "No previous block in the current region\n";
219 return;
221 state.cursor = previous;
222 } else {
223 llvm::outs() << "Current cursor is not a valid IRUnit";
224 return;
226 state.cursor.print(llvm::outs());
227 llvm::outs() << "\n";
230 void mlirDebuggerCursorSelectNextIRUnit() {
231 auto &state = getGlobalDebuggerState();
232 if (!state.cursor) {
233 llvm::outs() << "No active MLIR cursor, select from the context first\n";
234 return;
236 IRUnit *unit = &state.cursor;
237 if (auto *op = llvm::dyn_cast_if_present<Operation *>(*unit)) {
238 Operation *next = op->getNextNode();
239 if (!next) {
240 llvm::outs() << "No next operation in the current block\n";
241 return;
243 state.cursor = next;
244 } else if (auto *region = llvm::dyn_cast_if_present<Region *>(*unit)) {
245 Operation *parent = region->getParentOp();
246 if (!parent) {
247 llvm::outs() << "No parent operation for the current region\n";
248 return;
250 if (region->getRegionNumber() == parent->getNumRegions() - 1) {
251 llvm::outs() << "No next region in the current operation\n";
252 return;
254 state.cursor =
255 &region->getParentOp()->getRegion(region->getRegionNumber() + 1);
256 } else if (auto *block = llvm::dyn_cast_if_present<Block *>(*unit)) {
257 Block *next = block->getNextNode();
258 if (!next) {
259 llvm::outs() << "No next block in the current region\n";
260 return;
262 state.cursor = next;
263 } else {
264 llvm::outs() << "Current cursor is not a valid IRUnit";
265 return;
267 state.cursor.print(llvm::outs());
268 llvm::outs() << "\n";
271 //===----------------------------------------------------------------------===//
272 // Breakpoint Management
273 //===----------------------------------------------------------------------===//
275 void mlirDebuggerEnableBreakpoint(BreakpointHandle breakpoint) {
276 reinterpret_cast<Breakpoint *>(breakpoint)->enable();
279 void mlirDebuggerDisableBreakpoint(BreakpointHandle breakpoint) {
280 reinterpret_cast<Breakpoint *>(breakpoint)->disable();
283 BreakpointHandle mlirDebuggerAddTagBreakpoint(const char *tag) {
284 DebuggerState &state = getGlobalDebuggerState();
285 Breakpoint *breakpoint =
286 state.tagBreakpointManager.addBreakpoint(StringRef(tag, strlen(tag)));
287 int breakpointId = state.breakpointIdsMap.size() + 1;
288 state.breakpointIdsMap[breakpointId] = breakpoint;
289 return reinterpret_cast<BreakpointHandle>(breakpoint);
292 void mlirDebuggerAddRewritePatternBreakpoint(const char *patternNameInfo) {}
294 void mlirDebuggerAddFileLineColLocBreakpoint(const char *file, int line,
295 int col) {
296 getGlobalDebuggerState().fileLineColLocBreakpointManager.addBreakpoint(
297 StringRef(file, strlen(file)), line, col);
300 } // extern "C"
302 LLVM_ATTRIBUTE_NOINLINE void mlirDebuggerBreakpointHook() {
303 static LLVM_THREAD_LOCAL void *volatile sink;
304 sink = static_cast<void *>(const_cast<void **>(&sink));
307 static void preventLinkerDeadCodeElim() {
308 static void *volatile sink;
309 static bool initialized = [&]() {
310 sink = (void *)mlirDebuggerSetControl;
311 sink = (void *)mlirDebuggerEnableBreakpoint;
312 sink = (void *)mlirDebuggerDisableBreakpoint;
313 sink = (void *)mlirDebuggerPrintContext;
314 sink = (void *)mlirDebuggerPrintActionBacktrace;
315 sink = (void *)mlirDebuggerCursorPrint;
316 sink = (void *)mlirDebuggerCursorSelectIRUnitFromContext;
317 sink = (void *)mlirDebuggerCursorSelectParentIRUnit;
318 sink = (void *)mlirDebuggerCursorSelectChildIRUnit;
319 sink = (void *)mlirDebuggerCursorSelectPreviousIRUnit;
320 sink = (void *)mlirDebuggerCursorSelectNextIRUnit;
321 sink = (void *)mlirDebuggerAddTagBreakpoint;
322 sink = (void *)mlirDebuggerAddRewritePatternBreakpoint;
323 sink = (void *)mlirDebuggerAddFileLineColLocBreakpoint;
324 sink = static_cast<void *>(const_cast<void **>(&sink));
325 return true;
326 }();
327 (void)initialized;
330 static tracing::ExecutionContext::Control
331 debuggerCallBackFunction(const tracing::ActionActiveStack *actionStack) {
332 preventLinkerDeadCodeElim();
333 // Invoke the breakpoint hook, the debugger is supposed to trap this.
334 // The debugger controls the execution from there by invoking
335 // `mlirDebuggerSetControl()`.
336 auto &state = getGlobalDebuggerState();
337 state.actionActiveStack = actionStack;
338 getGlobalDebuggerState().debuggerControl = ExecutionContext::Apply;
339 actionStack->getAction().print(llvm::outs());
340 llvm::outs() << "\n";
341 mlirDebuggerBreakpointHook();
342 return getGlobalDebuggerState().debuggerControl;
345 namespace {
346 /// Manage the stack of actions that are currently active.
347 class DebuggerObserver : public ExecutionContext::Observer {
348 void beforeExecute(const ActionActiveStack *action, Breakpoint *breakpoint,
349 bool willExecute) override {
350 auto &state = getGlobalDebuggerState();
351 state.actionActiveStack = action;
353 void afterExecute(const ActionActiveStack *action) override {
354 auto &state = getGlobalDebuggerState();
355 state.actionActiveStack = action->getParent();
356 state.cursor = nullptr;
359 } // namespace
361 void mlir::setupDebuggerExecutionContextHook(
362 tracing::ExecutionContext &executionContext) {
363 executionContext.setCallback(debuggerCallBackFunction);
364 DebuggerState &state = getGlobalDebuggerState();
365 static DebuggerObserver observer;
366 executionContext.registerObserver(&observer);
367 executionContext.addBreakpointManager(&state.fileLineColLocBreakpointManager);
368 executionContext.addBreakpointManager(&state.tagBreakpointManager);