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