1//===- FileLineColLocBreakpointManagerTest.cpp - --------------------------===//
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#include "mlir/Debug/BreakpointManagers/FileLineColLocBreakpointManager.h"
10#include "mlir/Debug/ExecutionContext.h"
11#include "mlir/IR/Builders.h"
12#include "mlir/IR/BuiltinAttributes.h"
13#include "mlir/IR/BuiltinTypes.h"
14#include "mlir/IR/Location.h"
15#include "mlir/IR/OperationSupport.h"
16#include "llvm/ADT/STLExtras.h"
17#include "gtest/gtest.h"
18
19using namespace mlir;
20using namespace mlir::tracing;
21
22static Operation *createOp(MLIRContext *context, Location loc,
23 StringRef operationName,
24 unsigned int numRegions = 0) {
25 context->allowUnregisteredDialects();
26 return Operation::create(location: loc, name: OperationName(operationName, context),
27 resultTypes: std::nullopt, operands: std::nullopt, attributes: std::nullopt,
28 properties: OpaqueProperties(nullptr), successors: std::nullopt, numRegions);
29}
30
31namespace {
32struct FileLineColLocTestingAction
33 : public ActionImpl<FileLineColLocTestingAction> {
34 MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(FileLineColLocTestingAction)
35 static constexpr StringLiteral tag = "file-line-col-loc-testing-action";
36 FileLineColLocTestingAction(ArrayRef<IRUnit> irUnits)
37 : ActionImpl<FileLineColLocTestingAction>(irUnits) {}
38};
39
40TEST(FileLineColLocBreakpointManager, OperationMatch) {
41 // This test will process a sequence of operation and check various situation
42 // with a breakpoint hitting or not based on the location attached to the
43 // operation. When a breakpoint hits, the action is skipped and the counter is
44 // not incremented.
45 ExecutionContext executionCtx(
46 [](const ActionActiveStack *) { return ExecutionContext::Skip; });
47 int counter = 0;
48 auto counterInc = [&]() { counter++; };
49
50 // Setup
51
52 MLIRContext context;
53 // Miscellaneous information to define operations
54 std::vector<StringRef> fileNames = {
55 StringRef("foo.bar"), StringRef("baz.qux"), StringRef("quux.corge")};
56 std::vector<std::pair<unsigned, unsigned>> lineColLoc = {{42, 7}, {24, 3}};
57 Location callee = UnknownLoc::get(&context),
58 caller = UnknownLoc::get(&context), loc = UnknownLoc::get(&context);
59
60 // Set of operations over where we are going to be testing the functionality
61 std::vector<Operation *> operations = {
62 createOp(&context, CallSiteLoc::get(callee, caller),
63 "callSiteLocOperation"),
64 createOp(&context,
65 FileLineColLoc::get(&context, fileNames[0], lineColLoc[0].first,
66 lineColLoc[0].second),
67 "fileLineColLocOperation"),
68 createOp(&context, FusedLoc::get(&context, {}, Attribute()),
69 "fusedLocOperation"),
70 createOp(&context, NameLoc::get(StringAttr::get(&context, fileNames[2])),
71 "nameLocOperation"),
72 createOp(&context, OpaqueLoc::get<void *>(nullptr, loc),
73 "opaqueLocOperation"),
74 createOp(&context,
75 FileLineColLoc::get(&context, fileNames[1], lineColLoc[1].first,
76 lineColLoc[1].second),
77 "anotherFileLineColLocOperation"),
78 createOp(&context, UnknownLoc::get(&context), "unknownLocOperation"),
79 };
80
81 FileLineColLocBreakpointManager breakpointManager;
82 executionCtx.addBreakpointManager(manager: &breakpointManager);
83
84 // Test
85
86 // Basic case is that no breakpoint is set and the counter is incremented for
87 // every op.
88 auto checkNoMatch = [&]() {
89 counter = 0;
90 for (auto enumeratedOp : llvm::enumerate(First&: operations)) {
91 executionCtx(counterInc,
92 FileLineColLocTestingAction({enumeratedOp.value()}));
93 EXPECT_EQ(counter, static_cast<int>(enumeratedOp.index() + 1));
94 }
95 };
96 checkNoMatch();
97
98 // Set a breakpoint matching only the second operation in the list.
99 auto *breakpoint = breakpointManager.addBreakpoint(
100 file: fileNames[0], line: lineColLoc[0].first, col: lineColLoc[0].second);
101 auto checkMatchIdxs = [&](const DenseSet<int> &idxs) {
102 counter = 0;
103 int reference = 0;
104 for (int i = 0; i < (int)operations.size(); ++i) {
105 executionCtx(counterInc, FileLineColLocTestingAction({operations[i]}));
106 if (!idxs.contains(V: i))
107 reference++;
108 EXPECT_EQ(counter, reference);
109 }
110 };
111 checkMatchIdxs({1});
112
113 // Check that disabling the breakpoing brings us back to the original
114 // behavior.
115 breakpoint->disable();
116 checkNoMatch();
117
118 // Adding a breakpoint that won't match any location shouldn't affect the
119 // behavior.
120 breakpointManager.addBreakpoint(file: StringRef("random.file"), line: 3, col: 14);
121 checkNoMatch();
122
123 // Set a breakpoint matching only the fifth operation in the list.
124 breakpointManager.addBreakpoint(file: fileNames[1], line: lineColLoc[1].first,
125 col: lineColLoc[1].second);
126 counter = 0;
127 checkMatchIdxs({5});
128
129 // Re-enable the breakpoint matching only the second operation in the list.
130 // We now expect matching of operations 1 and 5.
131 breakpoint->enable();
132 checkMatchIdxs({1, 5});
133
134 for (auto *op : operations) {
135 op->destroy();
136 }
137}
138
139TEST(FileLineColLocBreakpointManager, BlockMatch) {
140 // This test will process a block and check various situation with
141 // a breakpoint hitting or not based on the location attached.
142 // When a breakpoint hits, the action is skipped and the counter is not
143 // incremented.
144 ExecutionContext executionCtx(
145 [](const ActionActiveStack *) { return ExecutionContext::Skip; });
146 int counter = 0;
147 auto counterInc = [&]() { counter++; };
148
149 // Setup
150
151 MLIRContext context;
152 std::vector<StringRef> fileNames = {StringRef("grault.garply"),
153 StringRef("waldo.fred")};
154 std::vector<std::pair<unsigned, unsigned>> lineColLoc = {{42, 7}, {24, 3}};
155 Operation *frontOp = createOp(&context,
156 FileLineColLoc::get(&context, fileNames.front(),
157 lineColLoc.front().first,
158 lineColLoc.front().second),
159 "firstOperation");
160 Operation *backOp = createOp(&context,
161 FileLineColLoc::get(&context, fileNames.back(),
162 lineColLoc.back().first,
163 lineColLoc.back().second),
164 "secondOperation");
165 Block block;
166 block.push_back(op: frontOp);
167 block.push_back(op: backOp);
168
169 FileLineColLocBreakpointManager breakpointManager;
170 executionCtx.addBreakpointManager(manager: &breakpointManager);
171
172 // Test
173
174 executionCtx(counterInc, FileLineColLocTestingAction({&block}));
175 EXPECT_EQ(counter, 1);
176
177 auto *breakpoint = breakpointManager.addBreakpoint(
178 file: fileNames.front(), line: lineColLoc.front().first, col: lineColLoc.front().second);
179 counter = 0;
180 executionCtx(counterInc, FileLineColLocTestingAction({&block}));
181 EXPECT_EQ(counter, 0);
182 breakpoint->disable();
183 executionCtx(counterInc, FileLineColLocTestingAction({&block}));
184 EXPECT_EQ(counter, 1);
185
186 breakpoint = breakpointManager.addBreakpoint(
187 file: fileNames.back(), line: lineColLoc.back().first, col: lineColLoc.back().second);
188 counter = 0;
189 executionCtx(counterInc, FileLineColLocTestingAction({&block}));
190 EXPECT_EQ(counter, 0);
191 breakpoint->disable();
192 executionCtx(counterInc, FileLineColLocTestingAction({&block}));
193 EXPECT_EQ(counter, 1);
194}
195
196TEST(FileLineColLocBreakpointManager, RegionMatch) {
197 // This test will process a region and check various situation with
198 // a breakpoint hitting or not based on the location attached.
199 // When a breakpoint hits, the action is skipped and the counter is not
200 // incremented.
201 ExecutionContext executionCtx(
202 [](const ActionActiveStack *) { return ExecutionContext::Skip; });
203 int counter = 0;
204 auto counterInc = [&]() { counter++; };
205
206 // Setup
207
208 MLIRContext context;
209 StringRef fileName("plugh.xyzzy");
210 unsigned line = 42, col = 7;
211 Operation *containerOp =
212 createOp(&context, FileLineColLoc::get(&context, fileName, line, col),
213 "containerOperation", 1);
214 Region &region = containerOp->getRegion(index: 0);
215
216 FileLineColLocBreakpointManager breakpointManager;
217 executionCtx.addBreakpointManager(manager: &breakpointManager);
218
219 // Test
220 counter = 0;
221 executionCtx(counterInc, FileLineColLocTestingAction({&region}));
222 EXPECT_EQ(counter, 1);
223 auto *breakpoint = breakpointManager.addBreakpoint(file: fileName, line, col);
224 executionCtx(counterInc, FileLineColLocTestingAction({&region}));
225 EXPECT_EQ(counter, 1);
226 breakpoint->disable();
227 executionCtx(counterInc, FileLineColLocTestingAction({&region}));
228 EXPECT_EQ(counter, 2);
229
230 containerOp->destroy();
231}
232} // namespace
233

source code of mlir/unittests/Debug/FileLineColLocBreakpointManagerTest.cpp