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 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 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"; 36 FileLineColLocTestingAction(ArrayRef<IRUnit> irUnits) 37 : ActionImpl<FileLineColLocTestingAction>(irUnits) {} 38 }; 39 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 = [&](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 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 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 ®ion = containerOp->getRegion(0); 215 216 FileLineColLocBreakpointManager breakpointManager; 217 executionCtx.addBreakpointManager(&breakpointManager); 218 219 // Test 220 counter = 0; 221 executionCtx(counterInc, FileLineColLocTestingAction({®ion})); 222 EXPECT_EQ(counter, 1); 223 auto *breakpoint = breakpointManager.addBreakpoint(fileName, line, col); 224 executionCtx(counterInc, FileLineColLocTestingAction({®ion})); 225 EXPECT_EQ(counter, 1); 226 breakpoint->disable(); 227 executionCtx(counterInc, FileLineColLocTestingAction({®ion})); 228 EXPECT_EQ(counter, 2); 229 230 containerOp->destroy(); 231 } 232 } // namespace 233