From ca2e3832105b464dbcd4cce53fa49e2418e4fec7 Mon Sep 17 00:00:00 2001 From: fruffy-bfn Date: Fri, 9 Jun 2023 22:33:25 +0200 Subject: [PATCH] [P4Testgen] Remove complete from the model, make it part of the evaluation step instead. (#4015) * Remove complete from the model. * Execution state refactoring. * Remove createSymbolicVariable entirely and replace it with the static getSymbolicVariable. --------- Co-authored-by: fruffy --- backends/p4tools/common/lib/model.cpp | 65 ++++++----------- backends/p4tools/common/lib/model.h | 45 ++++-------- backends/p4tools/common/lib/symbolic_env.cpp | 10 +-- backends/p4tools/common/lib/symbolic_env.h | 3 - backends/p4tools/common/lib/taint.cpp | 4 +- backends/p4tools/common/lib/taint.h | 2 +- backends/p4tools/common/lib/trace_event.cpp | 6 +- backends/p4tools/common/lib/trace_event.h | 5 +- .../p4tools/common/lib/trace_event_types.cpp | 39 +++------- .../p4tools/common/lib/trace_event_types.h | 18 ++--- backends/p4tools/common/lib/variables.cpp | 6 +- backends/p4tools/common/lib/variables.h | 3 +- .../core/small_step/abstract_stepper.cpp | 3 +- .../testgen/core/small_step/table_stepper.cpp | 32 +++++---- .../testgen/core/small_step/table_stepper.h | 6 +- .../p4tools/modules/testgen/lib/concolic.cpp | 14 ++-- .../p4tools/modules/testgen/lib/concolic.h | 12 ++-- .../modules/testgen/lib/execution_state.cpp | 71 ++++++++++--------- .../modules/testgen/lib/execution_state.h | 55 +++++++------- .../modules/testgen/lib/final_state.cpp | 18 ++--- .../modules/testgen/lib/test_backend.cpp | 12 ++-- .../p4tools/modules/testgen/lib/test_object.h | 2 +- .../p4tools/modules/testgen/lib/test_spec.cpp | 42 +++++------ .../p4tools/modules/testgen/lib/test_spec.h | 16 ++--- .../testgen/targets/bmv2/cmd_stepper.cpp | 3 +- .../modules/testgen/targets/bmv2/concolic.cpp | 9 +-- .../testgen/targets/bmv2/expr_stepper.cpp | 6 +- .../targets/bmv2/p4_asserts_parser.cpp | 5 +- .../targets/bmv2/p4_refers_to_parser.cpp | 4 +- .../testgen/targets/bmv2/table_stepper.cpp | 35 ++++----- .../testgen/targets/bmv2/table_stepper.h | 3 +- .../testgen/targets/bmv2/test_backend.cpp | 19 +++-- .../testgen/targets/bmv2/test_spec.cpp | 52 ++++++++------ .../modules/testgen/targets/bmv2/test_spec.h | 28 +++++--- .../testgen/targets/ebpf/table_stepper.cpp | 7 -- .../testgen/targets/ebpf/table_stepper.h | 5 -- .../testgen/targets/ebpf/test/P4Tests.cmake | 1 - .../testgen/targets/ebpf/test_backend.cpp | 9 ++- .../targets/pna/dpdk/table_stepper.cpp | 8 --- .../testgen/targets/pna/dpdk/table_stepper.h | 6 -- .../targets/pna/shared_table_stepper.cpp | 35 ++++----- .../targets/pna/shared_table_stepper.h | 3 +- .../testgen/targets/pna/test_backend.cpp | 15 ++-- .../modules/testgen/targets/pna/test_spec.cpp | 43 ++++++----- .../modules/testgen/targets/pna/test_spec.h | 19 +++-- .../modules/testgen/test/gtest_utils.cpp | 2 +- .../small-step/p4_asserts_parser_test.cpp | 22 +++--- .../modules/testgen/test/small-step/util.h | 6 +- 48 files changed, 377 insertions(+), 457 deletions(-) diff --git a/backends/p4tools/common/lib/model.cpp b/backends/p4tools/common/lib/model.cpp index 18de05ff1a..01ba8d17f6 100644 --- a/backends/p4tools/common/lib/model.cpp +++ b/backends/p4tools/common/lib/model.cpp @@ -16,65 +16,40 @@ namespace P4Tools { -Model::SubstVisitor::SubstVisitor(const Model &model) : self(model) {} +Model::SubstVisitor::SubstVisitor(const Model &model, bool doComplete) + : self(model), doComplete(doComplete) {} const IR::Literal *Model::SubstVisitor::preorder(IR::StateVariable *var) { BUG("At this point all state variables should have been resolved. Encountered %1%.", var); } const IR::Literal *Model::SubstVisitor::preorder(IR::SymbolicVariable *var) { - BUG_CHECK(self.symbolicMap.find(var) != self.symbolicMap.end(), - "Variable not bound in model: %1%", var); + auto varIt = self.symbolicMap.find(var); + if (varIt == self.symbolicMap.end()) { + if (doComplete) { + return IR::getDefaultValue(var->type, var->srcInfo, true)->checkedTo(); + } + BUG("Variable not bound in model: %1%", var); + } prune(); - return self.symbolicMap.at(var)->checkedTo(); + return varIt->second->checkedTo(); } const IR::Literal *Model::SubstVisitor::preorder(IR::TaintExpression *var) { return IR::getDefaultValue(var->type, var->getSourceInfo())->checkedTo(); } -Model::CompleteVisitor::CompleteVisitor(Model &model) : self(model) {} - -bool Model::CompleteVisitor::preorder(const IR::SymbolicVariable *var) { - if (self.symbolicMap.find(var) == self.symbolicMap.end()) { - LOG_FEATURE("common", 5, - "***** Did not find a binding for " << var << ". Autocompleting." << std::endl); - const auto *type = var->type; - self.symbolicMap.emplace(var, IR::getDefaultValue(type, var->getSourceInfo())); - } - return false; -} - -bool Model::CompleteVisitor::preorder(const IR::StateVariable *var) { - BUG("At this point all state variables should have been resolved. Encountered %1%.", var); -} - -void Model::complete(const IR::Expression *expr) { expr->apply(CompleteVisitor(*this)); } - -void Model::complete(const SymbolicSet &inputSet) { - auto completionVisitor = CompleteVisitor(*this); - for (const auto &var : inputSet) { - var->apply(completionVisitor); - } -} - -void Model::complete(const SymbolicMapType &inputMap) { - for (const auto &inputTuple : inputMap) { - const auto *expr = inputTuple.second; - expr->apply(CompleteVisitor(*this)); - } -} - const IR::StructExpression *Model::evaluateStructExpr(const IR::StructExpression *structExpr, + bool doComplete, ExpressionMap *resolvedExpressions) const { auto *resolvedStructExpr = new IR::StructExpression(structExpr->srcInfo, structExpr->type, structExpr->structType, {}); for (const auto *namedExpr : structExpr->components) { const IR::Expression *resolvedExpr = nullptr; if (const auto *subStructExpr = namedExpr->expression->to()) { - resolvedExpr = evaluateStructExpr(subStructExpr, resolvedExpressions); + resolvedExpr = evaluateStructExpr(subStructExpr, doComplete, resolvedExpressions); } else { - resolvedExpr = evaluate(namedExpr->expression, resolvedExpressions); + resolvedExpr = evaluate(namedExpr->expression, doComplete, resolvedExpressions); } resolvedStructExpr->components.push_back( new IR::NamedExpression(namedExpr->srcInfo, namedExpr->name, resolvedExpr)); @@ -83,23 +58,24 @@ const IR::StructExpression *Model::evaluateStructExpr(const IR::StructExpression } const IR::ListExpression *Model::evaluateListExpr(const IR::ListExpression *listExpr, + bool doComplete, ExpressionMap *resolvedExpressions) const { auto *resolvedListExpr = new IR::ListExpression(listExpr->srcInfo, listExpr->type, {}); for (const auto *expr : listExpr->components) { const IR::Expression *resolvedExpr = nullptr; if (const auto *subStructExpr = expr->to()) { - resolvedExpr = evaluateListExpr(subStructExpr, resolvedExpressions); + resolvedExpr = evaluateListExpr(subStructExpr, doComplete, resolvedExpressions); } else { - resolvedExpr = evaluate(expr, resolvedExpressions); + resolvedExpr = evaluate(expr, doComplete, resolvedExpressions); } resolvedListExpr->components.push_back(resolvedExpr); } return resolvedListExpr; } -const IR::Literal *Model::evaluate(const IR::Expression *expr, +const IR::Literal *Model::evaluate(const IR::Expression *expr, bool doComplete, ExpressionMap *resolvedExpressions) const { - const auto *substituted = expr->apply(SubstVisitor(*this)); + const auto *substituted = expr->apply(SubstVisitor(*this, doComplete)); const auto *evaluated = P4::optimizeExpression(substituted); const auto *literal = evaluated->checkedTo(); // Add the variable to the resolvedExpressions list, if the list is not null. @@ -109,12 +85,13 @@ const IR::Literal *Model::evaluate(const IR::Expression *expr, return literal; } -Model *Model::evaluate(const SymbolicMapType &inputMap, ExpressionMap *resolvedExpressions) const { +Model *Model::evaluate(const SymbolicMapType &inputMap, bool doComplete, + ExpressionMap *resolvedExpressions) const { auto *result = new Model(*this); for (const auto &inputTuple : inputMap) { const auto &name = inputTuple.first; const auto *expr = inputTuple.second; - (*result)[name] = evaluate(expr, resolvedExpressions); + (*result)[name] = evaluate(expr, doComplete, resolvedExpressions); } return result; } diff --git a/backends/p4tools/common/lib/model.h b/backends/p4tools/common/lib/model.h index 79eadf03ee..de75585b4e 100644 --- a/backends/p4tools/common/lib/model.h +++ b/backends/p4tools/common/lib/model.h @@ -31,24 +31,17 @@ class Model : public SymbolicMapType { class SubstVisitor : public Transform { const Model &self; + /// If doComplete is true, the visitor will not throw an error if a variable does not have a + /// substitution and instead assign a random or zero value (depending on whether there is a + /// seed) to the variable.. + bool doComplete; + public: const IR::Literal *preorder(IR::StateVariable *var) override; const IR::Literal *preorder(IR::SymbolicVariable *var) override; const IR::Literal *preorder(IR::TaintExpression *var) override; - explicit SubstVisitor(const Model &model); - }; - - // @see SubstVisitor. Does not fail if a variable is not part of the model. - /// Instead, it completes the variable and adds it to the symbolic map. - class CompleteVisitor : public Inspector { - Model &self; - - public: - bool preorder(const IR::SymbolicVariable *var) override; - bool preorder(const IR::StateVariable *var) override; - - explicit CompleteVisitor(Model &model); + explicit SubstVisitor(const Model &model, bool doComplete); }; public: @@ -64,37 +57,23 @@ class Model : public SymbolicMapType { Model &operator=(Model &&) = default; ~Model() = default; - /// Completes the model with the variables in the given expression. A variable needs to be - /// completed if it is not present in the model computed by the solver that produced the - /// model. This typically happens when a variable is not needed to solve a set of - /// constraints. - void complete(const IR::Expression *expr); - - /// Completes the model with the variables in the given list of expressions. A variable needs to - /// be completed if it is not present in the model computed by the solver that produced the - /// model. This typically happens when a variable is not needed to solve a set of constraints. - void complete(const SymbolicMapType &inputMap); - - /// Adds the given set of variables to the model (if they do not exist already). - /// If the variable does not exist, it is initialized to a default value. - void complete(const SymbolicSet &inputSet); - /// Evaluates a P4 expression in the context of this model. /// /// A BUG occurs if the given expression refers to a variable that is not bound by this model. /// If the input list @param resolvedExpressions is not null, we also collect the resolved value /// of this expression. - const IR::Literal *evaluate(const IR::Expression *expr, + const IR::Literal *evaluate(const IR::Expression *expr, bool doComplete, ExpressionMap *resolvedExpressions = nullptr) const; // Evaluates a P4 StructExpression in the context of this model. Recursively calls into // @evaluate and substitutes all members of this list with a Value type. const IR::StructExpression *evaluateStructExpr(const IR::StructExpression *structExpr, + bool doComplete, ExpressionMap *resolvedExpressions) const; // Evaluates a P4 ListExpression in the context of this model. Recursively calls into @evaluate // and substitutes all members of this list with a Value type. - const IR::ListExpression *evaluateListExpr(const IR::ListExpression *listExpr, + const IR::ListExpression *evaluateListExpr(const IR::ListExpression *listExpr, bool doComplete, ExpressionMap *resolvedExpressions) const; /// Evaluates a collection of P4 expressions in the context of this model by calling @evaluate @@ -106,11 +85,11 @@ class Model : public SymbolicMapType { /// of all the variables we have resolved within this expression. template