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