P4C
The P4 Compiler
Loading...
Searching...
No Matches
execution_state.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_LIB_EXECUTION_STATE_H_
8#define BACKENDS_P4TOOLS_MODULES_TESTGEN_LIB_EXECUTION_STATE_H_
9
10#include <cstdint>
11#include <functional>
12#include <initializer_list>
13#include <iostream>
14#include <map>
15#include <optional>
16#include <stack>
17#include <utility>
18#include <variant>
19#include <vector>
20
21#include "backends/p4tools/common/compiler/reachability.h"
22#include "backends/p4tools/common/core/abstract_execution_state.h"
23#include "backends/p4tools/common/lib/namespace_context.h"
24#include "backends/p4tools/common/lib/symbolic_env.h"
25#include "backends/p4tools/common/lib/trace_event.h"
26#include "ir/declaration.h"
27#include "ir/ir.h"
28#include "ir/node.h"
29#include "ir/solver.h"
30#include "lib/cstring.h"
31#include "lib/exceptions.h"
32#include "midend/coverage.h"
33
34#include "backends/p4tools/modules/testgen/lib/continuation.h"
35#include "backends/p4tools/modules/testgen/lib/test_object.h"
36
37namespace P4::P4Tools::P4Testgen {
38
41 friend class Test::SmallStepTest;
42
43 public:
44 class StackFrame {
45 public:
46 using ExceptionHandlers = std::map<Continuation::Exception, Continuation>;
47
48 private:
49 Continuation normalContinuation;
50 ExceptionHandlers exceptionHandlers;
51 const NamespaceContext *namespaces = nullptr;
52
53 public:
54 StackFrame(Continuation normalContinuation, const NamespaceContext *namespaces);
55
56 StackFrame(Continuation normalContinuation, ExceptionHandlers exceptionHandlers,
57 const NamespaceContext *namespaces);
58
59 StackFrame(const StackFrame &) = default;
60 StackFrame(StackFrame &&) noexcept = default;
61 StackFrame &operator=(const StackFrame &) = default;
62 StackFrame &operator=(StackFrame &&) = default;
63 ~StackFrame() = default;
64
66 [[nodiscard]] const Continuation &getContinuation() const;
67
69 [[nodiscard]] const ExceptionHandlers &getExceptionHandlers() const;
70
72 [[nodiscard]] const NamespaceContext *getNameSpaces() const;
73 };
74
77 ExecutionState &operator=(ExecutionState &&) = delete;
78 ~ExecutionState() override = default;
79
80 private:
82 std::vector<std::reference_wrapper<const TraceEvent>> trace;
83
85 P4::Coverage::CoverageSet visitedNodes;
86
91
98 // Invariant: if the @body is empty, then so is this, and this state is terminal.
99 std::stack<std::reference_wrapper<const StackFrame>> stack;
100
107 std::map<cstring, Continuation::PropertyValue> stateProperties;
108
109 // Test objects are classes of variables that influence the execution of test frameworks. They
110 // are collected during interpreter execution and consumed by the respective test framework. For
111 // example, when visiting a table, the interpreter will generate a table test object per table,
112 // which defines control plane match action entries. Once the interpreter has solved for the
113 // variables used by these test objects and concretized the values, they can be used to generate
114 // a test. Test objects are not constant because they may be manipulated by a target back end.
115 std::map<cstring, TestObjectMap> testObjects;
116
119 std::optional<IR::StateVariable> parserErrorLabel = std::nullopt;
120
125 int inputPacketCursor = 0;
126
129 std::vector<const IR::Expression *> pathConstraint;
130
132 std::vector<uint64_t> selectedBranches;
133
135 ReachabilityEngineState *reachabilityEngineState = nullptr;
136
139 uint16_t numAllocatedPacketVariables = 0;
140
145 [[nodiscard]] const IR::SymbolicVariable *createPacketVariable(const IR::Type *type);
146
147 /* =========================================================================================
148 * Accessors
149 * ========================================================================================= */
150 public:
152 [[nodiscard]] bool isTerminal() const;
153
155 [[nodiscard]] const std::vector<const IR::Expression *> &getPathConstraint() const;
156
158 [[nodiscard]] const std::vector<uint64_t> &getSelectedBranches() const;
159
161 void pushPathConstraint(const IR::Expression *e);
162
166 void pushBranchDecision(uint64_t);
167
170 [[nodiscard]] std::optional<const Continuation::Command> getNextCmd() const;
171
173 [[nodiscard]] const IR::Expression *get(const IR::StateVariable &var) const override;
174
176 void markVisited(const IR::Node *node);
177
179 [[nodiscard]] const P4::Coverage::CoverageSet &getVisited() const;
180
183 void set(const IR::StateVariable &var, const IR::Expression *value) override;
184
186 [[nodiscard]] const std::vector<std::reference_wrapper<const TraceEvent>> &getTrace() const;
187
189 [[nodiscard]] const Continuation::Body &getBody() const;
190
192 [[nodiscard]] const std::stack<std::reference_wrapper<const StackFrame>> &getStack() const;
193
195 void setProperty(cstring propertyName, Continuation::PropertyValue property);
196
198 [[nodiscard]] bool hasProperty(cstring propertyName) const;
199
202 template <class T>
203 [[nodiscard]] T getProperty(cstring propertyName) const {
204 auto iterator = stateProperties.find(propertyName);
205 if (iterator != stateProperties.end()) {
206 auto val = iterator->second;
207 try {
208 T resolvedVal = std::get<T>(val);
209 return resolvedVal;
210 } catch (std::bad_variant_access const &ex) {
211 BUG("Expected property value type does not correspond to value type stored in the "
212 "property map.");
213 }
214 }
215 BUG("Property %s not found in configuration map.", propertyName);
216 }
217
220 void addTestObject(cstring category, cstring objectLabel, const TestObject *object);
221
224 [[nodiscard]] const TestObject *getTestObject(cstring category, cstring objectLabel,
225 bool checked) const;
226
228 void deleteTestObject(cstring category, cstring objectLabel);
229
231 void deleteTestObjectCategory(cstring category);
232
237 template <class T>
238 [[nodiscard]] const T *getTestObject(cstring category, cstring objectLabel) const {
239 const auto *testObject = getTestObject(category, objectLabel, true);
240 return testObject->checkedTo<T>();
241 }
242
245 [[nodiscard]] TestObjectMap getTestObjectCategory(cstring category) const;
246
249
252
253 /* =========================================================================================
254 * Trace events.
255 * ========================================================================================= */
257 void add(const TraceEvent &event);
258
259 /* =========================================================================================
260 * Body operations
261 * ========================================================================================= */
263 void replaceTopBody(const Continuation::Command &cmd);
264
267 void replaceTopBody(const std::vector<Continuation::Command> *cmds);
268
271 void replaceTopBody(std::initializer_list<Continuation::Command> cmds);
272
276 //
277 // Needs to be implemented here because of limitations with templates.
278 template <class N>
279 void replaceTopBody(const std::vector<const N *> *nodes) {
280 BUG_CHECK(!nodes->empty(), "Replaced top of execution stack with empty list");
281 body.pop();
282 for (auto it = nodes->rbegin(); it != nodes->rend(); ++it) {
283 BUG_CHECK(*it, "Evaluation produced a null node.");
284 body.push(*it);
285 }
286 }
287
289 void popBody();
290
292 void replaceBody(const Continuation::Body &body);
293
294 /* =========================================================================================
295 * Continuation-stack operations
296 * ========================================================================================= */
298 void pushContinuation(const StackFrame &frame);
299
303 void pushCurrentContinuation(StackFrame::ExceptionHandlers handlers);
304
309 void pushCurrentContinuation(std::optional<const IR::Type *> parameterType_opt = std::nullopt,
310 StackFrame::ExceptionHandlers = {});
311
318 void popContinuation(std::optional<const IR::Node *> argument_opt = std::nullopt);
319
322
323 /* =========================================================================================
324 * Packet manipulation
325 * ========================================================================================= */
328 static const IR::SymbolicVariable *getInputPacketSizeVar();
329
332 [[nodiscard]] static int getMaxPacketLength();
333
335 [[nodiscard]] const IR::Expression *getInputPacket() const;
336
338 [[nodiscard]] int getInputPacketSize() const;
339
341 void appendToInputPacket(const IR::Expression *expr);
342
344 void prependToInputPacket(const IR::Expression *expr);
345
347 [[nodiscard]] int getInputPacketCursor() const;
348
350 [[nodiscard]] const IR::Expression *getPacketBuffer() const;
351
353 [[nodiscard]] int getPacketBufferSize() const;
354
359 const IR::Expression *slicePacketBuffer(int amount);
360
365 [[nodiscard]] const IR::Expression *peekPacketBuffer(int amount);
366
368 void appendToPacketBuffer(const IR::Expression *expr);
369
371 void prependToPacketBuffer(const IR::Expression *expr);
372
374 void resetPacketBuffer();
375
377 [[nodiscard]] const IR::Expression *getEmitBuffer() const;
378
380 void resetEmitBuffer();
381
383 void appendToEmitBuffer(const IR::Expression *expr);
384
386 void setParserErrorLabel(const IR::StateVariable &parserError);
387
389 [[nodiscard]] const IR::StateVariable &getCurrentParserErrorLabel() const;
390
391 /* =========================================================================================
392 * Constructors
393 * ========================================================================================= */
396 [[nodiscard]] ExecutionState &clone() const override;
397
400 [[nodiscard]] static ExecutionState &create(const IR::P4Program *program);
401
402 private:
404 explicit ExecutionState(Continuation::Body body);
405
406 // Execution state should always be allocated through explicit operators.
408 explicit ExecutionState(const IR::P4Program *program);
409 ExecutionState(const ExecutionState &) = default;
410
412 ExecutionState &operator=(const ExecutionState &) = default;
413};
414
415using ExecutionStateReference = std::reference_wrapper<ExecutionState>;
416
417} // namespace P4::P4Tools::P4Testgen
418
419#endif /* BACKENDS_P4TOOLS_MODULES_TESTGEN_LIB_EXECUTION_STATE_H_ */
Definition node.h:53
AbstractExecutionState(const AbstractExecutionState &)=default
Execution state needs to be explicitly copied using the clone call..
Represents a stack of namespaces.
Definition namespace_context.h:20
A continuation body is a list of commands.
Definition continuation.h:135
Definition continuation.h:35
Exception
Enumerates the exceptions that can be thrown during symbolic execution.
Definition continuation.h:41
std::variant< cstring, uint64_t, int64_t, bool, const IR::Expression * > PropertyValue
Definition continuation.h:91
const NamespaceContext * getNameSpaces() const
Definition execution_state.cpp:67
const ExceptionHandlers & getExceptionHandlers() const
Definition execution_state.cpp:63
const Continuation & getContinuation() const
Definition execution_state.cpp:58
const IR::Expression * getInputPacket() const
Definition execution_state.cpp:380
static const IR::SymbolicVariable * getInputPacketSizeVar()
Definition execution_state.cpp:373
const std::vector< const IR::Expression * > & getPathConstraint() const
Definition execution_state.cpp:117
void replaceTopBody(const Continuation::Command &cmd)
Replaces the top element of @body with @cmd.
Definition execution_state.cpp:350
int getInputPacketSize() const
Definition execution_state.cpp:384
void pushContinuation(const StackFrame &frame)
Pushes a new frame onto the continuation stack.
Definition execution_state.cpp:293
const IR::Expression * getPacketBuffer() const
Definition execution_state.cpp:405
void setReachabilityEngineState(ReachabilityEngineState *newEngineState)
Update the reachability engine state.
Definition execution_state.cpp:275
void pushCurrentContinuation(StackFrame::ExceptionHandlers handlers)
Definition execution_state.cpp:295
void deleteTestObject(cstring category, cstring objectLabel)
Remove a test object from a category.
Definition execution_state.cpp:266
const IR::StateVariable & getCurrentParserErrorLabel() const
Definition execution_state.cpp:535
const IR::Expression * getEmitBuffer() const
Definition execution_state.cpp:516
void set(const IR::StateVariable &var, const IR::Expression *value) override
Definition execution_state.cpp:202
void replaceBody(const Continuation::Body &body)
Replaces @body with the given argument.
Definition execution_state.cpp:291
void popBody()
Pops the top element of @body.
Definition execution_state.cpp:289
const P4::Coverage::CoverageSet & getVisited() const
Definition execution_state.cpp:183
const IR::Expression * get(const IR::StateVariable &var) const override
Definition execution_state.cpp:128
bool hasProperty(cstring propertyName) const
Definition execution_state.cpp:235
ExecutionState(ExecutionState &&)=delete
No move semantics because of constant members. We always need to clone a state.
void markVisited(const IR::Node *node)
Checks whether the node has been visited in this state.
Definition execution_state.cpp:162
void appendToPacketBuffer(const IR::Expression *expr)
Append data to the packet buffer.
Definition execution_state.cpp:498
const TestObject * getTestObject(cstring category, cstring objectLabel, bool checked) const
Definition execution_state.cpp:244
void deleteTestObjectCategory(cstring category)
Remove a test category entirely.
Definition execution_state.cpp:273
T getProperty(cstring propertyName) const
Definition execution_state.h:203
const std::vector< std::reference_wrapper< const TraceEvent > > & getTrace() const
Definition execution_state.cpp:220
void prependToInputPacket(const IR::Expression *expr)
Prepend data to the input packet.
Definition execution_state.cpp:396
void pushPathConstraint(const IR::Expression *e)
Adds path constraint.
Definition execution_state.cpp:369
const IR::Expression * slicePacketBuffer(int amount)
Definition execution_state.cpp:447
std::optional< const Continuation::Command > getNextCmd() const
Definition execution_state.cpp:121
void handleException(Continuation::Exception e)
Invokes first handler for e found on the stack.
Definition execution_state.cpp:331
ExecutionState & clone() const override
Definition execution_state.cpp:105
void appendToEmitBuffer(const IR::Expression *expr)
Append data to the emit buffer.
Definition execution_state.cpp:524
TestObjectMap getTestObjectCategory(cstring category) const
Definition execution_state.cpp:258
void setProperty(cstring propertyName, Continuation::PropertyValue property)
Set the property with.
Definition execution_state.cpp:231
bool isTerminal() const
Determines whether this state represents the end of an execution.
Definition execution_state.cpp:111
void resetEmitBuffer()
Reset the emit buffer to zero.
Definition execution_state.cpp:520
const T * getTestObject(cstring category, cstring objectLabel) const
Definition execution_state.h:238
void popContinuation(std::optional< const IR::Node * > argument_opt=std::nullopt)
Definition execution_state.cpp:321
void addTestObject(cstring category, cstring objectLabel, const TestObject *object)
Definition execution_state.cpp:239
void setParserErrorLabel(const IR::StateVariable &parserError)
Set the parser error label to the.
Definition execution_state.cpp:531
void pushBranchDecision(uint64_t)
Definition execution_state.cpp:371
int getPacketBufferSize() const
Definition execution_state.cpp:409
const IR::Expression * peekPacketBuffer(int amount)
Definition execution_state.cpp:414
ReachabilityEngineState * getReachabilityEngineState() const
Get the current state of the reachability engine.
Definition execution_state.cpp:279
int getInputPacketCursor() const
Definition execution_state.cpp:403
const std::stack< std::reference_wrapper< const StackFrame > > & getStack() const
Definition execution_state.cpp:227
void replaceTopBody(const std::vector< const N * > *nodes)
Definition execution_state.h:279
void add(const TraceEvent &event)
Add a new trace event to the state.
Definition execution_state.cpp:287
const Continuation::Body & getBody() const
Definition execution_state.cpp:224
void resetPacketBuffer()
Reset the packet buffer to zero.
Definition execution_state.cpp:512
void prependToPacketBuffer(const IR::Expression *expr)
Prepend data to the packet buffer.
Definition execution_state.cpp:505
static int getMaxPacketLength()
Definition execution_state.cpp:378
const std::vector< uint64_t > & getSelectedBranches() const
Definition execution_state.cpp:113
void appendToInputPacket(const IR::Expression *expr)
Append data to the input packet.
Definition execution_state.cpp:389
static ExecutionState & create(const IR::P4Program *program)
Definition execution_state.cpp:101
Definition test_object.h:21
The main data for reachability engine.
Definition reachability.h:122
Definition modules/testgen/test/small-step/util.h:46
An event in a trace of the execution of a P4 program.
Definition trace_event.h:20
Definition cstring.h:85
std::set< const IR::Node *, SourceIdCmp > CoverageSet
Definition coverage.h:47