xref: /llvm-project/mlir/unittests/Debug/FileLineColLocBreakpointManagerTest.cpp (revision 1893a3743eb971f0ea7657dc119b642a12870a1e)
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 
19 using namespace mlir;
20 using namespace mlir::tracing;
21 
createOp(MLIRContext * context,Location loc,StringRef operationName,unsigned int numRegions=0)22 static Operation *createOp(MLIRContext *context, Location loc,
23                            StringRef operationName,
24                            unsigned int numRegions = 0) {
25   context->allowUnregisteredDialects();
26   return Operation::create(loc, OperationName(operationName, context),
27                            std::nullopt, std::nullopt, std::nullopt,
28                            OpaqueProperties(nullptr), std::nullopt, numRegions);
29 }
30 
31 namespace {
32 struct 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";
FileLineColLocTestingAction__anon99b9193c0111::FileLineColLocTestingAction36   FileLineColLocTestingAction(ArrayRef<IRUnit> irUnits)
37       : ActionImpl<FileLineColLocTestingAction>(irUnits) {}
38 };
39 
TEST(FileLineColLocBreakpointManager,OperationMatch)40 TEST(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(&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(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       fileNames[0], lineColLoc[0].first, 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(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(StringRef("random.file"), 3, 14);
121   checkNoMatch();
122 
123   // Set a breakpoint matching only the fifth operation in the list.
124   breakpointManager.addBreakpoint(fileNames[1], lineColLoc[1].first,
125                                   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 
TEST(FileLineColLocBreakpointManager,BlockMatch)139 TEST(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(frontOp);
167   block.push_back(backOp);
168 
169   FileLineColLocBreakpointManager breakpointManager;
170   executionCtx.addBreakpointManager(&breakpointManager);
171 
172   // Test
173 
174   executionCtx(counterInc, FileLineColLocTestingAction({&block}));
175   EXPECT_EQ(counter, 1);
176 
177   auto *breakpoint = breakpointManager.addBreakpoint(
178       fileNames.front(), lineColLoc.front().first, 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       fileNames.back(), lineColLoc.back().first, 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 
TEST(FileLineColLocBreakpointManager,RegionMatch)196 TEST(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(0);
215 
216   FileLineColLocBreakpointManager breakpointManager;
217   executionCtx.addBreakpointManager(&breakpointManager);
218 
219   // Test
220   counter = 0;
221   executionCtx(counterInc, FileLineColLocTestingAction({&region}));
222   EXPECT_EQ(counter, 1);
223   auto *breakpoint = breakpointManager.addBreakpoint(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