diff --git a/README.md b/README.md index e8ea66f3655..aab770d0a8e 100644 --- a/README.md +++ b/README.md @@ -297,7 +297,9 @@ pip3 install --user -r requirements.txt ``` For documentation building: -`sudo apt-get install -y doxygen graphviz texlive-full` +```bash +sudo apt-get install -y doxygen graphviz texlive-full +``` `p4c` also depends on Google Protocol Buffers (Protobuf). `p4c` requires version 3.0 or higher, so the packaged version provided in Ubuntu 20.04 **should** diff --git a/backends/p4tools/common/core/z3_solver.cpp b/backends/p4tools/common/core/z3_solver.cpp index 773977e8899..13f0638cf84 100644 --- a/backends/p4tools/common/core/z3_solver.cpp +++ b/backends/p4tools/common/core/z3_solver.cpp @@ -290,7 +290,7 @@ const IR::Literal *Z3Solver::toLiteral(const z3::expr &e, const IR::Type *type) // Handle booleans. if (type->is()) { BUG_CHECK(e.is_bool(), "Expected a boolean value: %1%", e); - return new IR::BoolLiteral(type, e.is_true()); + return IR::getBoolLiteral(e.is_true()); } // Handle bit vectors. diff --git a/backends/p4tools/common/lib/gen_eq.cpp b/backends/p4tools/common/lib/gen_eq.cpp index 4ce9112f7b6..7615c3078cd 100644 --- a/backends/p4tools/common/lib/gen_eq.cpp +++ b/backends/p4tools/common/lib/gen_eq.cpp @@ -36,13 +36,11 @@ const IR::Expression *equateListTypes(const IR::Expression *left, const IR::Expr "different.", leftElemsSize, rightElemsSize); - const IR::Expression *result = new IR::BoolLiteral(IR::Type::Boolean::get(), true); - bool firstLoop = true; + const IR::Expression *result = nullptr; for (size_t i = 0; i < leftElems.size(); i++) { const auto *conjunct = equate(leftElems.at(i), rightElems.at(i)); - if (firstLoop) { + if (result == nullptr) { result = conjunct; - firstLoop = false; } else { result = new IR::LAnd(IR::Type::Boolean::get(), result, conjunct); } @@ -62,7 +60,7 @@ const IR::Expression *equate(const IR::Expression *left, const IR::Expression *r // A single default expression can be matched with a list expression. if (left->is() || right->is()) { - return new IR::BoolLiteral(IR::Type::Boolean::get(), true); + return IR::getBoolLiteral(true); } // If we still have lists after unrolling, compare them. @@ -82,9 +80,9 @@ const IR::Expression *equate(const IR::Expression *left, const IR::Expression *r } if (const auto *rangeKey = right->to()) { - const auto *boolType = IR::Type::Boolean::get(); - return new IR::LAnd(boolType, new IR::Leq(boolType, rangeKey->left, left), - new IR::Leq(boolType, left, rangeKey->right)); + return new IR::LAnd(IR::Type::Boolean::get(), + new IR::Leq(IR::Type::Boolean::get(), rangeKey->left, left), + new IR::Leq(IR::Type::Boolean::get(), left, rangeKey->right)); } return mkEq(left, right); diff --git a/backends/p4tools/modules/testgen/core/program_info.cpp b/backends/p4tools/modules/testgen/core/program_info.cpp index 2dab8bedbe8..3175193dd2c 100644 --- a/backends/p4tools/modules/testgen/core/program_info.cpp +++ b/backends/p4tools/modules/testgen/core/program_info.cpp @@ -83,11 +83,12 @@ void ProgramInfo::produceCopyInOutCall(const IR::Parameter *param, size_t paramI } const auto *archPath = new IR::PathExpression(paramType, new IR::Path(archRef)); const auto *paramRef = new IR::PathExpression(paramType, new IR::Path(param->name)); - const auto *paramDir = new IR::StringLiteral(directionToString(param->direction)); + const auto *paramDir = + new IR::StringLiteral(IR::Type_String::get(), directionToString(param->direction)); if (copyIns != nullptr) { // This mimicks the copy-in from the architecture environment. const auto *copyInCall = new IR::MethodCallStatement(Utils::generateInternalMethodCall( - "copy_in", {archPath, paramRef, paramDir, new IR::BoolLiteral(false)})); + "copy_in", {archPath, paramRef, paramDir, IR::getBoolLiteral(false)})); copyIns->emplace_back(copyInCall); } if (copyOuts != nullptr) { diff --git a/backends/p4tools/modules/testgen/core/small_step/abstract_stepper.cpp b/backends/p4tools/modules/testgen/core/small_step/abstract_stepper.cpp index a38ba4cb4f6..84250a3232d 100644 --- a/backends/p4tools/modules/testgen/core/small_step/abstract_stepper.cpp +++ b/backends/p4tools/modules/testgen/core/small_step/abstract_stepper.cpp @@ -192,14 +192,12 @@ bool AbstractStepper::stepGetHeaderValidity(const IR::StateVariable &headerRef) const auto *res = value->to(); BUG_CHECK(res, "%1%: expected a boolean", value); if (res->value) { - state.replaceTopBody( - Continuation::Return(new IR::BoolLiteral(IR::Type::Boolean::get(), true))); + state.replaceTopBody(Continuation::Return(IR::getBoolLiteral(true))); result->emplace_back(state); return false; } } - state.replaceTopBody( - Continuation::Return(new IR::BoolLiteral(IR::Type::Boolean::get(), false))); + state.replaceTopBody(Continuation::Return(IR::getBoolLiteral(false))); result->emplace_back(state); return false; } diff --git a/backends/p4tools/modules/testgen/targets/bmv2/expr_stepper.cpp b/backends/p4tools/modules/testgen/targets/bmv2/expr_stepper.cpp index bd309e0c69c..684b86b0228 100644 --- a/backends/p4tools/modules/testgen/targets/bmv2/expr_stepper.cpp +++ b/backends/p4tools/modules/testgen/targets/bmv2/expr_stepper.cpp @@ -18,7 +18,6 @@ #include "backends/p4tools/common/lib/variables.h" #include "ir/declaration.h" #include "ir/indexed_vector.h" -#include "ir/ir-generated.h" #include "ir/irutils.h" #include "ir/node.h" #include "ir/solver.h" diff --git a/backends/p4tools/modules/testgen/targets/ebpf/constants.cpp b/backends/p4tools/modules/testgen/targets/ebpf/constants.cpp index db16bfa1279..3a8fbb342fd 100644 --- a/backends/p4tools/modules/testgen/targets/ebpf/constants.cpp +++ b/backends/p4tools/modules/testgen/targets/ebpf/constants.cpp @@ -3,6 +3,6 @@ namespace P4Tools::P4Testgen::EBPF { const IR::PathExpression EBPFConstants::ACCEPT_VAR = - IR::PathExpression(new IR::Type_Boolean(), new IR::Path("*accept")); + IR::PathExpression(IR::Type_Boolean::get(), new IR::Path("*accept")); } // namespace P4Tools::P4Testgen::EBPF diff --git a/backends/p4tools/modules/testgen/targets/pna/constants.cpp b/backends/p4tools/modules/testgen/targets/pna/constants.cpp index e545b70e9f1..21c54c9af5e 100644 --- a/backends/p4tools/modules/testgen/targets/pna/constants.cpp +++ b/backends/p4tools/modules/testgen/targets/pna/constants.cpp @@ -6,7 +6,7 @@ namespace P4Tools::P4Testgen::Pna { const IR::Member PnaConstants::DROP_VAR = - IR::Member(new IR::Type_Boolean(), new IR::PathExpression("*pna_internal"), "drop_var"); + IR::Member(IR::Type_Boolean::get(), new IR::PathExpression("*pna_internal"), "drop_var"); const IR::Member PnaConstants::OUTPUT_PORT_VAR = IR::Member( new IR::Type_Bits(32, false), new IR::PathExpression("*pna_internal"), "output_port"); const IR::Member PnaConstants::PARSER_ERROR = IR::Member( diff --git a/backends/p4tools/modules/testgen/test/z3-solver/constraints.cpp b/backends/p4tools/modules/testgen/test/z3-solver/constraints.cpp index b9c638ee306..d3aa65a47b3 100644 --- a/backends/p4tools/modules/testgen/test/z3-solver/constraints.cpp +++ b/backends/p4tools/modules/testgen/test/z3-solver/constraints.cpp @@ -5,7 +5,6 @@ #include "backends/p4tools/common/core/z3_solver.h" #include "backends/p4tools/common/lib/variables.h" -#include "ir/ir-generated.h" #include "ir/ir.h" #include "ir/irutils.h" #include "lib/cstring.h" diff --git a/ir/visitor.cpp b/ir/visitor.cpp index be1b116e691..0f5c6bb68b8 100644 --- a/ir/visitor.cpp +++ b/ir/visitor.cpp @@ -78,6 +78,7 @@ class Visitor::ChangeTracker { if (!inserted) { // We already seen this node, determine its status if (it->second.visit_in_progress) return VisitStatus::Busy; if (it->second.visitOnce) return VisitStatus::Done; + it->second.visit_in_progress = true; return VisitStatus::Revisit; } @@ -250,6 +251,7 @@ class Visitor::Tracker { if (!inserted) { // We already seen this node, determine its status if (!it->second.done) return VisitStatus::Busy; if (it->second.visitOnce) return VisitStatus::Done; + it->second.done = false; return VisitStatus::Revisit; } diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index f8619d68bf6..9f149e0908f 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -53,6 +53,7 @@ set (GTEST_UNITTEST_SOURCES gtest/stringify.cpp gtest/rtti_test.cpp gtest/nethash.cpp + gtest/visitor.cpp ) # Combine the executable and the non-backend-specific unit tests into a single diff --git a/test/gtest/visitor.cpp b/test/gtest/visitor.cpp new file mode 100644 index 00000000000..4921ed9c49c --- /dev/null +++ b/test/gtest/visitor.cpp @@ -0,0 +1,163 @@ +/* +Copyright 2024 Intel Corp. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +#include "frontends/common/parseInput.h" +#include "frontends/common/resolveReferences/resolveReferences.h" +#include "gtest/gtest.h" +#include "helpers.h" +#include "ir/ir.h" +#include "midend_pass.h" + +namespace Test { + +using P4TestContext = P4CContextWithOptions; + +class P4CVisitor : public P4CTest {}; + +struct MultiVisitInspector : public Inspector, virtual public P4::ResolutionContext { + MultiVisitInspector() { visitDagOnce = false; } + + private: + // ignore parser and declaration loops for now + void loop_revisit(const IR::ParserState *) override {} + + void visit_def(const IR::PathExpression *pe) { + auto *d = resolveUnique(pe->path->name, P4::ResolutionType::Any); + BUG_CHECK(d, "failed to resolve %s", pe); + if (auto *ps = d->to()) { + visit(ps, "transition"); + } else if (auto *act = d->to()) { + visit(act, "actions"); + } else { + auto *obj = d->getNode(); // FIXME -- should be able to visit an INode + visit(obj); + } + } + + bool preorder(const IR::PathExpression *path) override { + visit_def(path); + return true; + } + + MultiVisitInspector(const MultiVisitInspector &) = default; +}; + +struct MultiVisitModifier : public Modifier, + // protected ControlFlowVisitor, + virtual public P4::ResolutionContext { + MultiVisitModifier() { visitDagOnce = false; } + + private: + // ignore parser and declaration loops for now + void loop_revisit(const IR::ParserState *) override {} + + void visit_def(const IR::PathExpression *pe) { + auto *d = resolveUnique(pe->path->name, P4::ResolutionType::Any); + BUG_CHECK(d, "failed to resolve %s", pe); + if (auto *ps = d->to()) { + visit(ps, "transition"); + } else if (auto *act = d->to()) { + visit(act, "actions"); + } else { + auto *obj = d->getNode(); // FIXME -- should be able to visit an INode + visit(obj); + } + } + + bool preorder(IR::PathExpression *path) override { + visit_def(path); + return true; + } + + MultiVisitModifier(const MultiVisitModifier &) = default; +}; + +std::string getMultiVisitLoopSource() { + // Non-sensical parser with loops + return R"( + extern packet_in { + void extract (out T hdr); + } + + header Header { + bit<32> data; + } + + struct H { + Header h1; + Header h2; + } + + struct M { } + + parser MyParser(packet_in pkt, out H hdr, out M meta) { + state start { + transition next; + } + + state next { + transition select (hdr.h1.data) { + 0: state0; + 1: state1; + default: accept; + } + } + + state state0 { + hdr.h1.setInvalid(); + transition select (hdr.h2.data) { + 2: state1; + default: next; + } + } + + state state1 { + hdr.h2.setValid(); + transition select (hdr.h2.data) { + 1: state1; + 2: state0; + default: accept; + } + } + + state accept { } + } + )"; +} + +// This test fails when Visitor::Tracker::try_start does _not_ reset done on a previously-visited +// node +TEST_F(P4CVisitor, MultiVisitInspectorLoop) { + auto *program = + P4::parseP4String(getMultiVisitLoopSource(), CompilerOptions::FrontendVersion::P4_16); + ASSERT_TRUE(program != nullptr); + + program = program->apply(MultiVisitInspector()); + ASSERT_TRUE(program != nullptr); +} + +// This test fails when Visitor::ChangeTracker::try_start does _not_ reset visit_in_progress on a +// previously-visited node +TEST_F(P4CVisitor, MultiVisitModifierLoop) { + auto *program = + P4::parseP4String(getMultiVisitLoopSource(), CompilerOptions::FrontendVersion::P4_16); + ASSERT_TRUE(program != nullptr); + + program = program->apply(MultiVisitModifier()); + ASSERT_TRUE(program != nullptr); +} + +} // namespace Test