P4C
The P4 Compiler
Loading...
Searching...
No Matches
modules/testgen/test/small-step/util.h
1/*
2 * SPDX-FileCopyrightText: 2022 The P4 Language Consortium
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7#ifndef BACKENDS_P4TOOLS_MODULES_TESTGEN_TEST_SMALL_STEP_UTIL_H_
8#define BACKENDS_P4TOOLS_MODULES_TESTGEN_TEST_SMALL_STEP_UTIL_H_
9
10#include <gtest/gtest.h>
11
12#include <functional>
13#include <optional>
14#include <stack>
15#include <string>
16#include <utility>
17#include <vector>
18
19#include "backends/p4tools/common/compiler/compiler_target.h"
20#include "backends/p4tools/common/core/z3_solver.h"
21#include "backends/p4tools/common/lib/namespace_context.h"
22#include "backends/p4tools/common/lib/symbolic_env.h"
23#include "ir/declaration.h"
24#include "ir/indexed_vector.h"
25#include "ir/ir.h"
26#include "lib/cstring.h"
27#include "lib/enumerator.h"
28
29#include "backends/p4tools/modules/testgen/core/small_step/small_step.h"
30#include "backends/p4tools/modules/testgen/core/target.h"
31#include "backends/p4tools/modules/testgen/lib/continuation.h"
32#include "backends/p4tools/modules/testgen/lib/execution_state.h"
33#include "backends/p4tools/modules/testgen/test/gtest_utils.h"
34
35namespace P4::P4Tools::Test {
36
37using Body = P4Testgen::Continuation::Body;
38using Continuation = P4Testgen::Continuation;
39using ExecutionState = P4Testgen::ExecutionState;
40using NamespaceContext = NamespaceContext;
41using Return = P4Testgen::Continuation::Return;
42using SmallStepEvaluator = P4Testgen::SmallStepEvaluator;
43using TestgenTarget = P4Testgen::TestgenTarget;
44using Z3Solver = Z3Solver;
45
47 public:
49 static ExecutionState mkState(Body body) { return ExecutionState(std::move(body)); }
50};
51
52namespace SmallStepUtil {
53
54using namespace P4::literals;
55
57template <class T>
58const T *extractExpr(const IR::P4Program &program) {
59 // Get the mau declarations in the P4Program.
60 auto *decl = program.getDeclsByName("mau"_cs)->single();
61
62 // Convert the mau declaration to a control and ensure that
63 // there is a single statement in the body.
64 const auto *control = decl->checkedTo<IR::P4Control>();
65 if (control->body->components.size() != 1) {
66 return nullptr;
67 }
68
69 // Ensure that the control body statement is a method call statement.
70 const auto *mcStmt = control->body->components[0]->to<IR::MethodCallStatement>();
71 if (!mcStmt) {
72 return nullptr;
73 }
74
75 // Ensure that there is only one argument to the method call and return it.
76 const auto *mcArgs = mcStmt->methodCall->arguments;
77 if (mcArgs->size() != 1) {
78 return nullptr;
79 }
80 return (*mcArgs)[0]->expression->to<T>();
81}
82
84template <class T>
85void stepAndExamineValue(const T *value, const CompilerResult &compilerResult) {
86 // Produce a ProgramInfo, which is needed to create a SmallStepEvaluator.
87 const auto *progInfo = TestgenTarget::produceProgramInfo(compilerResult);
88 ASSERT_TRUE(progInfo);
89
90 // Create a base state with a parameter continuation to apply the value on.
91 const auto *v = Continuation::genParameter(value->type, "v"_cs, NamespaceContext::Empty);
92 Body bodyBase({Return(v->param)});
93 Continuation continuationBase(v, bodyBase);
94 ExecutionState esBase = SmallStepTest::mkState(bodyBase);
95
96 // Step on the value.
97 Z3Solver solver;
98 auto &testState = esBase.clone();
99 Body body({Return(value)});
100 testState.replaceBody(body);
101 testState.pushContinuation(
102 *new ExecutionState::StackFrame(continuationBase, esBase.getNamespaceContext()));
103 SmallStepEvaluator eval(solver, *progInfo);
104 auto *successors = eval.step(testState);
105 ASSERT_EQ(successors->size(), 1u);
106
107 // Examine the resulting execution state.
108 const auto branch = (*successors)[0];
109 const auto *constraint = branch.constraint;
110 auto executionState = branch.nextState;
111 ASSERT_TRUE(constraint->checkedTo<IR::BoolLiteral>()->value);
112 ASSERT_EQ(executionState.get().getNamespaceContext(), NamespaceContext::Empty);
113 ASSERT_TRUE(executionState.get().getSymbolicEnv().getInternalMap().empty());
114
115 // Examine the resulting body.
116 Body finalBody = executionState.get().getBody();
117 ASSERT_EQ(finalBody, Body({Return(value)}));
118
119 // Examine the resulting stack.
120 ASSERT_EQ(executionState.get().getStack().empty(), true);
121}
122
127template <class T>
128void stepAndExamineOp(
129 const T *op, const IR::Expression *subexpr, const CompilerResult &compilerResult,
130 std::function<const IR::Expression *(const IR::PathExpression *)> rebuildNode) {
131 // Produce a ProgramInfo, which is needed to create a SmallStepEvaluator.
132 const auto *progInfo = TestgenTarget::produceProgramInfo(compilerResult);
133 ASSERT_TRUE(progInfo);
134
135 // Step on the operation.
136 Z3Solver solver;
137 Body body({Return(op)});
138 ExecutionState es = SmallStepTest::mkState(body);
139 SmallStepEvaluator eval(solver, *progInfo);
140 auto *successors = eval.step(es);
141 ASSERT_EQ(successors->size(), 1U);
142
143 // Examine the resulting execution state.
144 const auto branch = (*successors)[0];
145 const auto *constraint = branch.constraint;
146 auto executionState = branch.nextState;
147 ASSERT_TRUE(constraint->checkedTo<IR::BoolLiteral>()->value);
148 ASSERT_EQ(executionState.get().getNamespaceContext(), NamespaceContext::Empty);
149 ASSERT_TRUE(executionState.get().getSymbolicEnv().getInternalMap().empty());
150
151 // Examine the resulting body.
152 Body finalBody = executionState.get().getBody();
153 ASSERT_EQ(finalBody, Body({Return(subexpr)}));
154
155 // Examine the resulting stack.
156 ASSERT_EQ(executionState.get().getStack().size(), 1u);
157 const auto stackFrame = executionState.get().getStack().top();
158 ASSERT_TRUE(stackFrame.get().getExceptionHandlers().empty());
159 ASSERT_EQ(stackFrame.get().getNameSpaces(), NamespaceContext::Empty);
160
161 // Examine the pushed continuation.
162 Continuation pushedContinuation = stackFrame.get().getContinuation();
163 ASSERT_TRUE(pushedContinuation.parameterOpt);
164 Body pushedBody = pushedContinuation.body;
165 ASSERT_EQ(pushedBody, Body({Return(rebuildNode(*pushedContinuation.parameterOpt))}));
166}
167
168} // namespace SmallStepUtil
169
170} // namespace P4::P4Tools::Test
171
172#endif /* BACKENDS_P4TOOLS_MODULES_TESTGEN_TEST_SMALL_STEP_UTIL_H_ */
static const NamespaceContext * Empty
Represents the empty namespace context.
Definition namespace_context.h:39
static const Parameter * genParameter(const IR::Type *type, cstring name, const NamespaceContext *ctx)
Definition continuation.cpp:171
static const ProgramInfo * produceProgramInfo(const CompilerResult &compilerResult)
Definition p4tools/modules/testgen/core/target.cpp:54
Definition test/gtest_utils.h:61
Definition modules/testgen/test/small-step/util.h:46
static ExecutionState mkState(Body body)
Creates an execution state out of a continuation body.
Definition modules/testgen/test/small-step/util.h:49
Definition cstring.h:80