[NFC] Add libcxx python reformat SHA to .git-blame-ignore-revs
[llvm-project.git] / mlir / unittests / Debug / ExecutionContextTest.cpp
blob642adff51002a3cd0cafd1872a4c94c4cae7049b
1 //===- ExecutionContextTest.cpp - Debug Execution Context first impl ------===//
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/ExecutionContext.h"
10 #include "mlir/Debug/BreakpointManagers/TagBreakpointManager.h"
11 #include "llvm/ADT/MapVector.h"
12 #include "gmock/gmock.h"
14 using namespace mlir;
15 using namespace mlir::tracing;
17 namespace {
18 struct DebuggerAction : public ActionImpl<DebuggerAction> {
19 MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(DebuggerAction)
20 static constexpr StringLiteral tag = "debugger-action";
22 struct OtherAction : public ActionImpl<OtherAction> {
23 MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(OtherAction)
24 static constexpr StringLiteral tag = "other-action";
26 struct ThirdAction : public ActionImpl<ThirdAction> {
27 MLIR_DEFINE_EXPLICIT_INTERNAL_INLINE_TYPE_ID(ThirdAction)
28 static constexpr StringLiteral tag = "third-action";
31 // Simple action that does nothing.
32 void noOp() {}
34 /// This test executes a stack of nested action and check that the backtrace is
35 /// as expect.
36 TEST(ExecutionContext, ActionActiveStackTest) {
38 // We'll break three time, once on each action, the backtraces should match
39 // each of the entries here.
40 std::vector<std::vector<StringRef>> expectedStacks = {
41 {DebuggerAction::tag},
42 {OtherAction::tag, DebuggerAction::tag},
43 {ThirdAction::tag, OtherAction::tag, DebuggerAction::tag}};
45 auto checkStacks = [&](const ActionActiveStack *backtrace,
46 const std::vector<StringRef> &currentStack) {
47 ASSERT_EQ((int)currentStack.size(), backtrace->getDepth() + 1);
48 for (StringRef stackEntry : currentStack) {
49 ASSERT_NE(backtrace, nullptr);
50 ASSERT_EQ(stackEntry, backtrace->getAction().getTag());
51 backtrace = backtrace->getParent();
55 std::vector<ExecutionContext::Control> controlSequence = {
56 ExecutionContext::Step, ExecutionContext::Step, ExecutionContext::Apply};
57 int idx = 0;
58 StringRef current;
59 int currentDepth = -1;
60 auto onBreakpoint = [&](const ActionActiveStack *backtrace) {
61 current = backtrace->getAction().getTag();
62 currentDepth = backtrace->getDepth();
63 checkStacks(backtrace, expectedStacks[idx]);
64 return controlSequence[idx++];
67 TagBreakpointManager simpleManager;
68 ExecutionContext executionCtx(onBreakpoint);
69 executionCtx.addBreakpointManager(&simpleManager);
70 std::vector<TagBreakpoint *> breakpoints;
71 breakpoints.push_back(simpleManager.addBreakpoint(DebuggerAction::tag));
72 breakpoints.push_back(simpleManager.addBreakpoint(OtherAction::tag));
73 breakpoints.push_back(simpleManager.addBreakpoint(ThirdAction::tag));
75 auto third = [&]() {
76 EXPECT_EQ(current, ThirdAction::tag);
77 EXPECT_EQ(currentDepth, 2);
79 auto nested = [&]() {
80 EXPECT_EQ(current, OtherAction::tag);
81 EXPECT_EQ(currentDepth, 1);
82 executionCtx(third, ThirdAction{});
84 auto original = [&]() {
85 EXPECT_EQ(current, DebuggerAction::tag);
86 EXPECT_EQ(currentDepth, 0);
87 executionCtx(nested, OtherAction{});
88 return;
91 executionCtx(original, DebuggerAction{});
94 TEST(ExecutionContext, DebuggerTest) {
95 // Check matching and non matching breakpoints, with various enable/disable
96 // schemes.
97 int match = 0;
98 auto onBreakpoint = [&match](const ActionActiveStack *backtrace) {
99 match++;
100 return ExecutionContext::Skip;
102 TagBreakpointManager simpleManager;
103 ExecutionContext executionCtx(onBreakpoint);
104 executionCtx.addBreakpointManager(&simpleManager);
106 executionCtx(noOp, DebuggerAction{});
107 EXPECT_EQ(match, 0);
109 Breakpoint *dbgBreakpoint = simpleManager.addBreakpoint(DebuggerAction::tag);
110 executionCtx(noOp, DebuggerAction{});
111 EXPECT_EQ(match, 1);
113 dbgBreakpoint->disable();
114 executionCtx(noOp, DebuggerAction{});
115 EXPECT_EQ(match, 1);
117 dbgBreakpoint->enable();
118 executionCtx(noOp, DebuggerAction{});
119 EXPECT_EQ(match, 2);
121 executionCtx(noOp, OtherAction{});
122 EXPECT_EQ(match, 2);
125 TEST(ExecutionContext, ApplyTest) {
126 // Test the "apply" control.
127 std::vector<StringRef> tagSequence = {DebuggerAction::tag};
128 std::vector<ExecutionContext::Control> controlSequence = {
129 ExecutionContext::Apply};
130 int idx = 0, counter = 0;
131 auto onBreakpoint = [&](const ActionActiveStack *backtrace) {
132 ++counter;
133 EXPECT_EQ(tagSequence[idx], backtrace->getAction().getTag());
134 return controlSequence[idx++];
136 auto callback = [&]() { EXPECT_EQ(counter, 1); };
137 TagBreakpointManager simpleManager;
138 ExecutionContext executionCtx(onBreakpoint);
139 executionCtx.addBreakpointManager(&simpleManager);
140 simpleManager.addBreakpoint(DebuggerAction::tag);
142 executionCtx(callback, DebuggerAction{});
143 EXPECT_EQ(counter, 1);
146 TEST(ExecutionContext, SkipTest) {
147 // Test the "skip" control.
148 std::vector<StringRef> tagSequence = {DebuggerAction::tag,
149 DebuggerAction::tag};
150 std::vector<ExecutionContext::Control> controlSequence = {
151 ExecutionContext::Apply, ExecutionContext::Skip};
152 int idx = 0, counter = 0, executionCounter = 0;
153 auto onBreakpoint = [&](const ActionActiveStack *backtrace) {
154 ++counter;
155 EXPECT_EQ(tagSequence[idx], backtrace->getAction().getTag());
156 return controlSequence[idx++];
158 auto callback = [&]() { ++executionCounter; };
159 TagBreakpointManager simpleManager;
160 ExecutionContext executionCtx(onBreakpoint);
161 executionCtx.addBreakpointManager(&simpleManager);
162 simpleManager.addBreakpoint(DebuggerAction::tag);
164 executionCtx(callback, DebuggerAction{});
165 executionCtx(callback, DebuggerAction{});
166 EXPECT_EQ(counter, 2);
167 EXPECT_EQ(executionCounter, 1);
170 TEST(ExecutionContext, StepApplyTest) {
171 // Test the "step" control with a nested action.
172 std::vector<StringRef> tagSequence = {DebuggerAction::tag, OtherAction::tag};
173 std::vector<ExecutionContext::Control> controlSequence = {
174 ExecutionContext::Step, ExecutionContext::Apply};
175 int idx = 0, counter = 0;
176 auto onBreakpoint = [&](const ActionActiveStack *backtrace) {
177 ++counter;
178 EXPECT_EQ(tagSequence[idx], backtrace->getAction().getTag());
179 return controlSequence[idx++];
181 TagBreakpointManager simpleManager;
182 ExecutionContext executionCtx(onBreakpoint);
183 executionCtx.addBreakpointManager(&simpleManager);
184 simpleManager.addBreakpoint(DebuggerAction::tag);
185 auto nested = [&]() { EXPECT_EQ(counter, 2); };
186 auto original = [&]() {
187 EXPECT_EQ(counter, 1);
188 executionCtx(nested, OtherAction{});
191 executionCtx(original, DebuggerAction{});
192 EXPECT_EQ(counter, 2);
195 TEST(ExecutionContext, StepNothingInsideTest) {
196 // Test the "step" control without a nested action.
197 std::vector<StringRef> tagSequence = {DebuggerAction::tag,
198 DebuggerAction::tag};
199 std::vector<ExecutionContext::Control> controlSequence = {
200 ExecutionContext::Step, ExecutionContext::Step};
201 int idx = 0, counter = 0;
202 auto onBreakpoint = [&](const ActionActiveStack *backtrace) {
203 ++counter;
204 EXPECT_EQ(tagSequence[idx], backtrace->getAction().getTag());
205 return controlSequence[idx++];
207 auto callback = [&]() { EXPECT_EQ(counter, 1); };
208 TagBreakpointManager simpleManager;
209 ExecutionContext executionCtx(onBreakpoint);
210 executionCtx.addBreakpointManager(&simpleManager);
211 simpleManager.addBreakpoint(DebuggerAction::tag);
213 executionCtx(callback, DebuggerAction{});
214 EXPECT_EQ(counter, 2);
217 TEST(ExecutionContext, NextTest) {
218 // Test the "next" control.
219 std::vector<StringRef> tagSequence = {DebuggerAction::tag,
220 DebuggerAction::tag};
221 std::vector<ExecutionContext::Control> controlSequence = {
222 ExecutionContext::Next, ExecutionContext::Next};
223 int idx = 0, counter = 0;
224 auto onBreakpoint = [&](const ActionActiveStack *backtrace) {
225 ++counter;
226 EXPECT_EQ(tagSequence[idx], backtrace->getAction().getTag());
227 return controlSequence[idx++];
229 auto callback = [&]() { EXPECT_EQ(counter, 1); };
230 TagBreakpointManager simpleManager;
231 ExecutionContext executionCtx(onBreakpoint);
232 executionCtx.addBreakpointManager(&simpleManager);
233 simpleManager.addBreakpoint(DebuggerAction::tag);
235 executionCtx(callback, DebuggerAction{});
236 EXPECT_EQ(counter, 2);
239 TEST(ExecutionContext, FinishTest) {
240 // Test the "finish" control.
241 std::vector<StringRef> tagSequence = {DebuggerAction::tag, OtherAction::tag,
242 DebuggerAction::tag};
243 std::vector<ExecutionContext::Control> controlSequence = {
244 ExecutionContext::Step, ExecutionContext::Finish,
245 ExecutionContext::Apply};
246 int idx = 0, counter = 0;
247 auto onBreakpoint = [&](const ActionActiveStack *backtrace) {
248 ++counter;
249 EXPECT_EQ(tagSequence[idx], backtrace->getAction().getTag());
250 return controlSequence[idx++];
252 TagBreakpointManager simpleManager;
253 ExecutionContext executionCtx(onBreakpoint);
254 executionCtx.addBreakpointManager(&simpleManager);
255 simpleManager.addBreakpoint(DebuggerAction::tag);
256 auto nested = [&]() { EXPECT_EQ(counter, 2); };
257 auto original = [&]() {
258 EXPECT_EQ(counter, 1);
259 executionCtx(nested, OtherAction{});
260 EXPECT_EQ(counter, 2);
263 executionCtx(original, DebuggerAction{});
264 EXPECT_EQ(counter, 3);
267 TEST(ExecutionContext, FinishBreakpointInNestedTest) {
268 // Test the "finish" control with a breakpoint in the nested action.
269 std::vector<StringRef> tagSequence = {OtherAction::tag, DebuggerAction::tag};
270 std::vector<ExecutionContext::Control> controlSequence = {
271 ExecutionContext::Finish, ExecutionContext::Apply};
272 int idx = 0, counter = 0;
273 auto onBreakpoint = [&](const ActionActiveStack *backtrace) {
274 ++counter;
275 EXPECT_EQ(tagSequence[idx], backtrace->getAction().getTag());
276 return controlSequence[idx++];
278 TagBreakpointManager simpleManager;
279 ExecutionContext executionCtx(onBreakpoint);
280 executionCtx.addBreakpointManager(&simpleManager);
281 simpleManager.addBreakpoint(OtherAction::tag);
283 auto nested = [&]() { EXPECT_EQ(counter, 1); };
284 auto original = [&]() {
285 EXPECT_EQ(counter, 0);
286 executionCtx(nested, OtherAction{});
287 EXPECT_EQ(counter, 1);
290 executionCtx(original, DebuggerAction{});
291 EXPECT_EQ(counter, 2);
294 TEST(ExecutionContext, FinishNothingBackTest) {
295 // Test the "finish" control without a nested action.
296 std::vector<StringRef> tagSequence = {DebuggerAction::tag};
297 std::vector<ExecutionContext::Control> controlSequence = {
298 ExecutionContext::Finish};
299 int idx = 0, counter = 0;
300 auto onBreakpoint = [&](const ActionActiveStack *backtrace) {
301 ++counter;
302 EXPECT_EQ(tagSequence[idx], backtrace->getAction().getTag());
303 return controlSequence[idx++];
305 auto callback = [&]() { EXPECT_EQ(counter, 1); };
306 TagBreakpointManager simpleManager;
307 ExecutionContext executionCtx(onBreakpoint);
308 executionCtx.addBreakpointManager(&simpleManager);
309 simpleManager.addBreakpoint(DebuggerAction::tag);
311 executionCtx(callback, DebuggerAction{});
312 EXPECT_EQ(counter, 1);
315 TEST(ExecutionContext, EnableDisableBreakpointOnCallback) {
316 // Test enabling and disabling breakpoints while executing the action.
317 std::vector<StringRef> tagSequence = {DebuggerAction::tag, ThirdAction::tag,
318 OtherAction::tag, DebuggerAction::tag};
319 std::vector<ExecutionContext::Control> controlSequence = {
320 ExecutionContext::Apply, ExecutionContext::Finish,
321 ExecutionContext::Finish, ExecutionContext::Apply};
322 int idx = 0, counter = 0;
323 auto onBreakpoint = [&](const ActionActiveStack *backtrace) {
324 ++counter;
325 EXPECT_EQ(tagSequence[idx], backtrace->getAction().getTag());
326 return controlSequence[idx++];
329 TagBreakpointManager simpleManager;
330 ExecutionContext executionCtx(onBreakpoint);
331 executionCtx.addBreakpointManager(&simpleManager);
332 simpleManager.addBreakpoint(DebuggerAction::tag);
333 Breakpoint *toBeDisabled = simpleManager.addBreakpoint(OtherAction::tag);
335 auto third = [&]() { EXPECT_EQ(counter, 2); };
336 auto nested = [&]() {
337 EXPECT_EQ(counter, 1);
338 executionCtx(third, ThirdAction{});
339 EXPECT_EQ(counter, 2);
341 auto original = [&]() {
342 EXPECT_EQ(counter, 1);
343 toBeDisabled->disable();
344 simpleManager.addBreakpoint(ThirdAction::tag);
345 executionCtx(nested, OtherAction{});
346 EXPECT_EQ(counter, 3);
349 executionCtx(original, DebuggerAction{});
350 EXPECT_EQ(counter, 4);
352 } // namespace