From 50366806de8c745af42b6c0300407ae50fd069ec Mon Sep 17 00:00:00 2001 From: Damian Rovara <93778306+DRovara@users.noreply.github.com> Date: Fri, 9 Aug 2024 15:25:18 +0200 Subject: [PATCH] fix: :bug: Fix bug that prevents breakpoints to be hit inside function definitions (#7) Custom gate definitions are defined with start position at `gate...` and end position at their closing `}`. Therefore, when putting a breakpoint at any location within those bounds, it was always attached to the function. Now, if a breakpoint would be attached to a function, we first check if it would fit better to one of the gates inside it. --- src/backend/dd/DDSimDebug.cpp | 22 +++++++++++++++ test/test_simulation.cpp | 50 +++++++++++++++++++++++++++++++++++ 2 files changed, 72 insertions(+) diff --git a/src/backend/dd/DDSimDebug.cpp b/src/backend/dd/DDSimDebug.cpp index 10a9918..f8c6d86 100644 --- a/src/backend/dd/DDSimDebug.cpp +++ b/src/backend/dd/DDSimDebug.cpp @@ -725,6 +725,28 @@ Result ddsimSetBreakpoint(SimulationState* self, size_t desiredPosition, const size_t start = ddsim->instructionStarts[i]; const size_t end = ddsim->instructionEnds[i]; if (desiredPosition >= start && desiredPosition <= end) { + if (ddsim->processedCode.substr(start, end - start).find("gate ") != + std::string::npos) { + // Breakpoint may be located in a sub-gate of the gate definition. + for (auto j = i + 1; j < ddsim->instructionTypes.size(); j++) { + const size_t startSub = ddsim->instructionStarts[j]; + const size_t endSub = ddsim->instructionEnds[j]; + if (startSub > desiredPosition) { + break; + } + if (endSub >= desiredPosition) { + *targetInstruction = j; + ddsim->breakpoints.insert(j); + return OK; + } + if (ddsim->instructionTypes[j] == RETURN) { + break; + } + } + *targetInstruction = i; + ddsim->breakpoints.insert(i); + return OK; + } *targetInstruction = i; ddsim->breakpoints.insert(i); return OK; diff --git a/test/test_simulation.cpp b/test/test_simulation.cpp index 573039d..34bf0f3 100644 --- a/test/test_simulation.cpp +++ b/test/test_simulation.cpp @@ -326,6 +326,56 @@ TEST_P(SimulationTest, RunSimulation) { ASSERT_TRUE(state->isFinished(state)); } +TEST_P(SimulationTest, InGateDefinitionBreakpoints) { + const std::map> breakpointPositions = { + {"complex-jumps", {86, 280, 411}}, {"failing-assertions", {}}}; + const std::map> + expectedBreakpointPositions = {{"complex-jumps", {2, 7, 11}}, + {"failing-assertions", {}}}; + const std::map> + expectedBreakpointHits = { + {"complex-jumps", {2, 11, 7, 2, 11, 2, 11, 2, 11}}, + {"failing-assertions", {}}}; + + for (size_t index = 0; index < breakpointPositions.at(GetParam()).size(); + index++) { + const auto breakpoint = breakpointPositions.at(GetParam())[index]; + size_t targetInstruction = 0; + ASSERT_EQ(state->setBreakpoint(state, breakpoint, &targetInstruction), + Result::OK) + << "Failed to set breakpoint at instruction " << breakpoint << " in " + << GetParam() << "\n"; + ASSERT_EQ(targetInstruction, + expectedBreakpointPositions.at(GetParam())[index]) + << "Breakpoint set at wrong instruction for breakpoint " << breakpoint + << " in " << GetParam() << "\n"; + } + + for (const auto instruction : expectedBreakpointHits.at(GetParam())) { + ASSERT_EQ(state->runSimulation(state), Result::OK) + << "Failed to run simulation in " << GetParam() << "\n"; + while (state->didAssertionFail(state)) { + ASSERT_EQ(state->runSimulation(state), Result::OK) + << "Failed to run simulation in " << GetParam() << "\n"; + } + ASSERT_EQ(state->getCurrentInstruction(state), instruction) + << "Breakpoint not hit at expected instruction " << instruction + << " in " << GetParam() << "\n"; + ASSERT_TRUE(state->wasBreakpointHit(state)); + } + + ASSERT_EQ(state->clearBreakpoints(state), Result::OK) + << "Failed to clear breakpoints in " << GetParam() << "\n"; + ASSERT_EQ(state->runSimulationBackward(state), Result::OK); + ASSERT_FALSE(state->wasBreakpointHit(state)) + << "Breakpoint hit after clearing in " << GetParam() << "\n"; + while (!state->isFinished(state)) { + ASSERT_EQ(state->runSimulation(state), Result::OK); + ASSERT_FALSE(state->wasBreakpointHit(state)) + << "Breakpoint hit after clearing in " << GetParam() << "\n"; + } +} + INSTANTIATE_TEST_SUITE_P(StringParams, SimulationTest, ::testing::Values("complex-jumps", "failing-assertions"));