xref: /llvm-project/mlir/include/mlir/Debug/BreakpointManagers/FileLineColLocBreakpointManager.h (revision 68f58812e3e99e31d77c0c23b6298489444dc0be)
1 //===- FileLineColLocBreakpointManager.h - TODO: add message ----*- C++ -*-===//
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 //===----------------------------------------------------------------------===//
8 
9 #ifndef MLIR_TRACING_BREAKPOINTMANAGERS_FILELINECOLLOCBREAKPOINTMANAGER_H
10 #define MLIR_TRACING_BREAKPOINTMANAGERS_FILELINECOLLOCBREAKPOINTMANAGER_H
11 
12 #include "mlir/Debug/BreakpointManager.h"
13 #include "mlir/Debug/ExecutionContext.h"
14 #include "mlir/IR/Action.h"
15 #include "mlir/IR/Location.h"
16 #include "mlir/IR/Operation.h"
17 #include "llvm/ADT/DenseMap.h"
18 #include <memory>
19 #include <optional>
20 
21 namespace mlir {
22 namespace tracing {
23 
24 /// This breakpoing intends to match a FileLineColLocation, that is a tuple of
25 /// file name, line number, and column number. Using -1 for  the column and the
26 /// line number will match any column and line number respectively.
27 class FileLineColLocBreakpoint
28     : public BreakpointBase<FileLineColLocBreakpoint> {
29 public:
FileLineColLocBreakpoint(StringRef file,int64_t line,int64_t col)30   FileLineColLocBreakpoint(StringRef file, int64_t line, int64_t col)
31       : line(line), col(col) {}
32 
print(raw_ostream & os)33   void print(raw_ostream &os) const override {
34     os << "Location: " << file << ':' << line << ':' << col;
35   }
36 
37   /// Parse a string representation in the form of "<file>:<line>:<col>". Return
38   /// a tuple with these three elements, the first one is a StringRef pointing
39   /// into the original string.
40   static FailureOr<std::tuple<StringRef, int64_t, int64_t>> parseFromString(
41       StringRef str, llvm::function_ref<void(Twine)> diag = [](Twine) {});
42 
43 private:
44   /// A filename on which to break.
45   StringRef file;
46 
47   /// A particular line on which to break, or -1 to break on any line.
48   int64_t line;
49 
50   /// A particular column on which to break, or -1 to break on any column
51   int64_t col;
52 
53   friend class FileLineColLocBreakpointManager;
54 };
55 
56 /// This breakpoint manager is responsible for matching
57 /// FileLineColLocBreakpoint. It'll extract the location from the action context
58 /// looking for a FileLineColLocation, and match it against the registered
59 /// breakpoints.
60 class FileLineColLocBreakpointManager
61     : public BreakpointManagerBase<FileLineColLocBreakpointManager> {
62 public:
match(const Action & action)63   Breakpoint *match(const Action &action) const override {
64     for (const IRUnit &unit : action.getContextIRUnits()) {
65       if (auto *op = llvm::dyn_cast_if_present<Operation *>(unit)) {
66         if (auto match = matchFromLocation(op->getLoc()))
67           return *match;
68         continue;
69       }
70       if (auto *block = llvm::dyn_cast_if_present<Block *>(unit)) {
71         for (auto &op : block->getOperations()) {
72           if (auto match = matchFromLocation(op.getLoc()))
73             return *match;
74         }
75         continue;
76       }
77       if (Region *region = llvm::dyn_cast_if_present<Region *>(unit)) {
78         if (auto match = matchFromLocation(region->getLoc()))
79           return *match;
80         continue;
81       }
82     }
83     return {};
84   }
85 
86   FileLineColLocBreakpoint *addBreakpoint(StringRef file, int64_t line,
87                                           int64_t col = -1) {
88     auto &breakpoint = breakpoints[std::make_tuple(file, line, col)];
89     if (!breakpoint)
90       breakpoint = std::make_unique<FileLineColLocBreakpoint>(file, line, col);
91     return breakpoint.get();
92   }
93 
94 private:
matchFromLocation(Location initialLoc)95   std::optional<Breakpoint *> matchFromLocation(Location initialLoc) const {
96     std::optional<Breakpoint *> match = std::nullopt;
97     initialLoc->walk([&](Location loc) {
98       auto fileLoc = dyn_cast<FileLineColLoc>(loc);
99       if (!fileLoc)
100         return WalkResult::advance();
101       StringRef file = fileLoc.getFilename();
102       int64_t line = fileLoc.getLine();
103       int64_t col = fileLoc.getColumn();
104       auto lookup = breakpoints.find(std::make_tuple(file, line, col));
105       if (lookup != breakpoints.end() && lookup->second->isEnabled()) {
106         match = lookup->second.get();
107         return WalkResult::interrupt();
108       }
109       // If not found, check with the -1 key if we have a breakpoint for any
110       // col.
111       lookup = breakpoints.find(std::make_tuple(file, line, -1));
112       if (lookup != breakpoints.end() && lookup->second->isEnabled()) {
113         match = lookup->second.get();
114         return WalkResult::interrupt();
115       }
116       // If not found, check with the -1 key if we have a breakpoint for any
117       // line.
118       lookup = breakpoints.find(std::make_tuple(file, -1, -1));
119       if (lookup != breakpoints.end() && lookup->second->isEnabled()) {
120         match = lookup->second.get();
121         return WalkResult::interrupt();
122       }
123       return WalkResult::advance();
124     });
125     return match;
126   }
127 
128   /// A map from a (filename, line, column) -> breakpoint.
129   DenseMap<std::tuple<StringRef, int64_t, int64_t>,
130            std::unique_ptr<FileLineColLocBreakpoint>>
131       breakpoints;
132 };
133 
134 } // namespace tracing
135 } // namespace mlir
136 
137 #endif // MLIR_TRACING_BREAKPOINTMANAGERS_FILELINECOLLOCBREAKPOINTMANAGER_H
138