diff --git a/.github/workflows/ci-test-mac.yml b/.github/workflows/ci-test-mac.yml index d3d9f74c19..4c8845dbe0 100644 --- a/.github/workflows/ci-test-mac.yml +++ b/.github/workflows/ci-test-mac.yml @@ -93,12 +93,6 @@ jobs: - name: Install dependencies (MacOS) run: | - # FIXME: We should not need to do this, but there are currently some complications with Github CI. - # See https://github.com/actions/runner-images/issues/4020. - # See https://github.com/actions/runner-images/issues/8838. - brew install python@3.12 || true - brew link --overwrite python@3.12 - brew pin python@3.12 tools/install_mac_deps.sh - name: Build (MacOS) diff --git a/backends/bmv2/common/controlFlowGraph.cpp b/backends/bmv2/common/controlFlowGraph.cpp index 3c56b0eee8..ffbdbb9562 100644 --- a/backends/bmv2/common/controlFlowGraph.cpp +++ b/backends/bmv2/common/controlFlowGraph.cpp @@ -17,7 +17,7 @@ limitations under the License. #include "controlFlowGraph.h" #include "frontends/common/resolveReferences/referenceMap.h" -#include "frontends/p4/fromv1.0/v1model.h" +#include "frontends/p4-14/fromv1.0/v1model.h" #include "frontends/p4/methodInstance.h" #include "frontends/p4/tableApply.h" #include "frontends/p4/typeMap.h" diff --git a/backends/bmv2/common/extern.cpp b/backends/bmv2/common/extern.cpp index 0d4f9cdeb0..03e3666d8a 100644 --- a/backends/bmv2/common/extern.cpp +++ b/backends/bmv2/common/extern.cpp @@ -16,7 +16,7 @@ limitations under the License. #include "extern.h" -#include "frontends/p4/fromv1.0/v1model.h" +#include "frontends/p4-14/fromv1.0/v1model.h" #include "lib/json.h" namespace P4::BMV2 { diff --git a/backends/bmv2/common/helpers.h b/backends/bmv2/common/helpers.h index d158c0718d..98c81f8a45 100644 --- a/backends/bmv2/common/helpers.h +++ b/backends/bmv2/common/helpers.h @@ -22,7 +22,7 @@ limitations under the License. #include "controlFlowGraph.h" #include "expression.h" #include "frontends/common/model.h" -#include "frontends/p4/fromv1.0/v1model.h" +#include "frontends/p4-14/fromv1.0/v1model.h" #include "ir/ir.h" #include "lib/cstring.h" #include "lib/json.h" diff --git a/backends/bmv2/common/lower.cpp b/backends/bmv2/common/lower.cpp index 962f4813c2..bb3dfb6f12 100644 --- a/backends/bmv2/common/lower.cpp +++ b/backends/bmv2/common/lower.cpp @@ -16,8 +16,8 @@ limitations under the License. #include "lower.h" +#include "frontends/p4-14/fromv1.0/v1model.h" #include "frontends/p4/coreLibrary.h" -#include "frontends/p4/fromv1.0/v1model.h" #include "frontends/p4/methodInstance.h" #include "lib/big_int_util.h" diff --git a/backends/bmv2/common/parser.cpp b/backends/bmv2/common/parser.cpp index 9dfa150cb0..815eeda484 100644 --- a/backends/bmv2/common/parser.cpp +++ b/backends/bmv2/common/parser.cpp @@ -19,8 +19,8 @@ limitations under the License. #include "JsonObjects.h" #include "backend.h" #include "extern.h" +#include "frontends/p4-14/fromv1.0/v1model.h" #include "frontends/p4/coreLibrary.h" -#include "frontends/p4/fromv1.0/v1model.h" #include "lib/algorithm.h" namespace P4::BMV2 { diff --git a/backends/bmv2/pna_nic/midend.cpp b/backends/bmv2/pna_nic/midend.cpp index ac096f0984..8e36e7bc0a 100644 --- a/backends/bmv2/pna_nic/midend.cpp +++ b/backends/bmv2/pna_nic/midend.cpp @@ -20,8 +20,8 @@ limitations under the License. #include "backends/bmv2/pna_nic/options.h" #include "frontends/common/constantFolding.h" #include "frontends/common/resolveReferences/resolveReferences.h" +#include "frontends/p4-14/fromv1.0/v1model.h" #include "frontends/p4/evaluator/evaluator.h" -#include "frontends/p4/fromv1.0/v1model.h" #include "frontends/p4/moveDeclarations.h" #include "frontends/p4/simplify.h" #include "frontends/p4/simplifyParsers.h" diff --git a/backends/bmv2/portable_common/midend.cpp b/backends/bmv2/portable_common/midend.cpp index 7878a1a16e..fdb06feac0 100644 --- a/backends/bmv2/portable_common/midend.cpp +++ b/backends/bmv2/portable_common/midend.cpp @@ -20,8 +20,8 @@ limitations under the License. #include "backends/bmv2/portable_common/options.h" #include "frontends/common/constantFolding.h" #include "frontends/common/resolveReferences/resolveReferences.h" +#include "frontends/p4-14/fromv1.0/v1model.h" #include "frontends/p4/evaluator/evaluator.h" -#include "frontends/p4/fromv1.0/v1model.h" #include "frontends/p4/moveDeclarations.h" #include "frontends/p4/simplify.h" #include "frontends/p4/simplifyParsers.h" diff --git a/backends/bmv2/psa_switch/midend.cpp b/backends/bmv2/psa_switch/midend.cpp index 6a3a14bfb9..f9e9ab9e24 100644 --- a/backends/bmv2/psa_switch/midend.cpp +++ b/backends/bmv2/psa_switch/midend.cpp @@ -20,8 +20,8 @@ limitations under the License. #include "backends/bmv2/psa_switch/options.h" #include "frontends/common/constantFolding.h" #include "frontends/common/resolveReferences/resolveReferences.h" +#include "frontends/p4-14/fromv1.0/v1model.h" #include "frontends/p4/evaluator/evaluator.h" -#include "frontends/p4/fromv1.0/v1model.h" #include "frontends/p4/moveDeclarations.h" #include "frontends/p4/simplify.h" #include "frontends/p4/simplifyParsers.h" diff --git a/backends/bmv2/simple_switch/midend.cpp b/backends/bmv2/simple_switch/midend.cpp index ba04ca2779..654fab90e6 100644 --- a/backends/bmv2/simple_switch/midend.cpp +++ b/backends/bmv2/simple_switch/midend.cpp @@ -20,8 +20,8 @@ limitations under the License. #include "backends/bmv2/simple_switch/options.h" #include "frontends/common/constantFolding.h" #include "frontends/common/resolveReferences/resolveReferences.h" +#include "frontends/p4-14/fromv1.0/v1model.h" #include "frontends/p4/evaluator/evaluator.h" -#include "frontends/p4/fromv1.0/v1model.h" #include "frontends/p4/moveDeclarations.h" #include "frontends/p4/simplify.h" #include "frontends/p4/simplifyParsers.h" diff --git a/backends/bmv2/simple_switch/simpleSwitch.cpp b/backends/bmv2/simple_switch/simpleSwitch.cpp index 5634bee00e..7795348511 100644 --- a/backends/bmv2/simple_switch/simpleSwitch.cpp +++ b/backends/bmv2/simple_switch/simpleSwitch.cpp @@ -23,8 +23,8 @@ limitations under the License. #include "backends/bmv2/common/annotations.h" #include "backends/bmv2/simple_switch/options.h" +#include "frontends/p4-14/fromv1.0/v1model.h" #include "frontends/p4/cloner.h" -#include "frontends/p4/fromv1.0/v1model.h" #include "lib/json.h" #include "midend/flattenLogMsg.h" diff --git a/backends/bmv2/simple_switch/simpleSwitch.h b/backends/bmv2/simple_switch/simpleSwitch.h index 681276a388..30725e7f0c 100644 --- a/backends/bmv2/simple_switch/simpleSwitch.h +++ b/backends/bmv2/simple_switch/simpleSwitch.h @@ -32,8 +32,8 @@ limitations under the License. #include "backends/bmv2/common/sharedActionSelectorCheck.h" #include "backends/common/programStructure.h" #include "frontends/common/constantFolding.h" +#include "frontends/p4-14/fromv1.0/v1model.h" #include "frontends/p4/evaluator/evaluator.h" -#include "frontends/p4/fromv1.0/v1model.h" #include "frontends/p4/simplify.h" #include "frontends/p4/unusedDeclarations.h" #include "midend/convertEnums.h" diff --git a/backends/dpdk/midend.cpp b/backends/dpdk/midend.cpp index 87d1f3d319..52d5393346 100644 --- a/backends/dpdk/midend.cpp +++ b/backends/dpdk/midend.cpp @@ -19,8 +19,8 @@ limitations under the License. #include "dpdkArch.h" #include "frontends/common/constantFolding.h" #include "frontends/common/resolveReferences/resolveReferences.h" +#include "frontends/p4-14/fromv1.0/v1model.h" #include "frontends/p4/evaluator/evaluator.h" -#include "frontends/p4/fromv1.0/v1model.h" #include "frontends/p4/moveDeclarations.h" #include "frontends/p4/simplify.h" #include "frontends/p4/simplifyParsers.h" diff --git a/backends/p4fmt/p4formatter.cpp b/backends/p4fmt/p4formatter.cpp index 73d8f4ee41..4cdaeaac6f 100644 --- a/backends/p4fmt/p4formatter.cpp +++ b/backends/p4fmt/p4formatter.cpp @@ -1,11 +1,10 @@ #include "p4formatter.h" -#include #include #include -#include "frontends/common/options.h" -#include "frontends/p4/fromv1.0/v1model.h" +#include "frontends/p4-14/fromv1.0/v1model.h" +#include "frontends/p4/getV1ModelVersion.h" #include "frontends/parsers/p4/p4parser.hpp" #include "ir/dump.h" @@ -69,7 +68,7 @@ bool P4Formatter::preorder(const IR::P4Program *program) { if (sourceFile.parent_path() == p4includePath) { std::filesystem::path p = sourceFile.filename(); if (P4V1::V1Model::instance.file.name == p) { - P4V1::getV1ModelVersion g; + P4V1::GetV1ModelVersion g; program->apply(g); builder.append("#define V1MODEL_VERSION "); builder.append(g.version); diff --git a/backends/p4test/midend.cpp b/backends/p4test/midend.cpp index 3cd139a1b1..2637557daa 100644 --- a/backends/p4test/midend.cpp +++ b/backends/p4test/midend.cpp @@ -18,8 +18,8 @@ limitations under the License. #include "frontends/common/constantFolding.h" #include "frontends/common/resolveReferences/resolveReferences.h" +#include "frontends/p4-14/fromv1.0/v1model.h" #include "frontends/p4/evaluator/evaluator.h" -#include "frontends/p4/fromv1.0/v1model.h" #include "frontends/p4/moveDeclarations.h" #include "frontends/p4/simplify.h" #include "frontends/p4/simplifyParsers.h" diff --git a/control-plane/p4RuntimeArchHandler.cpp b/control-plane/p4RuntimeArchHandler.cpp index ea1703da13..bf2bc5a7fa 100644 --- a/control-plane/p4RuntimeArchHandler.cpp +++ b/control-plane/p4RuntimeArchHandler.cpp @@ -20,8 +20,8 @@ limitations under the License. #include "frontends/common/resolveReferences/referenceMap.h" // TODO(antonin): this include should go away when we cleanup getTableSize // implementation. +#include "frontends/p4-14/fromv1.0/v1model.h" #include "frontends/p4/externInstance.h" -#include "frontends/p4/fromv1.0/v1model.h" #include "frontends/p4/toP4/toP4.h" #include "frontends/p4/typeMap.h" #include "ir/ir.h" diff --git a/control-plane/p4RuntimeArchStandard.cpp b/control-plane/p4RuntimeArchStandard.cpp index 9bab516124..dcc7591acd 100644 --- a/control-plane/p4RuntimeArchStandard.cpp +++ b/control-plane/p4RuntimeArchStandard.cpp @@ -21,7 +21,6 @@ limitations under the License. #include #include "frontends/common/resolveReferences/referenceMap.h" -#include "frontends/p4/fromv1.0/v1model.h" #include "frontends/p4/typeMap.h" #include "ir/ir.h" #include "lib/log.h" diff --git a/control-plane/p4RuntimeArchStandard.h b/control-plane/p4RuntimeArchStandard.h index ed57dbdfec..4678af8e8e 100644 --- a/control-plane/p4RuntimeArchStandard.h +++ b/control-plane/p4RuntimeArchStandard.h @@ -18,7 +18,7 @@ limitations under the License. #define CONTROL_PLANE_P4RUNTIMEARCHSTANDARD_H_ #include "frontends/common/resolveReferences/referenceMap.h" -#include "frontends/p4/fromv1.0/v1model.h" +#include "frontends/p4-14/fromv1.0/v1model.h" #include "frontends/p4/typeMap.h" #include "ir/ir.h" #include "p4RuntimeArchHandler.h" diff --git a/control-plane/p4RuntimeSerializer.cpp b/control-plane/p4RuntimeSerializer.cpp index 743adf3585..e6120d824c 100644 --- a/control-plane/p4RuntimeSerializer.cpp +++ b/control-plane/p4RuntimeSerializer.cpp @@ -52,7 +52,7 @@ limitations under the License. #include "frontends/p4/externInstance.h" // TODO(antonin): this include should go away when we cleanup getMatchFields // and tableNeedsPriority implementations. -#include "frontends/p4/fromv1.0/v1model.h" +#include "frontends/p4-14/fromv1.0/v1model.h" #include "frontends/p4/methodInstance.h" #include "frontends/p4/typeChecking/typeChecker.h" #include "frontends/p4/typeMap.h" diff --git a/frontends/CMakeLists.txt b/frontends/CMakeLists.txt index dc0647b236..9a2acc3eed 100644 --- a/frontends/CMakeLists.txt +++ b/frontends/CMakeLists.txt @@ -30,15 +30,12 @@ set (P4_FRONTEND_SRCS p4/evaluator/evaluator.cpp p4/evaluator/substituteParameters.cpp p4/externInstance.cpp - p4/fromv1.0/converters.cpp - p4/fromv1.0/programStructure.cpp p4/frontend.cpp p4/functionsInlining.cpp p4/hierarchicalNames.cpp p4/inlining.cpp p4/localizeActions.cpp p4/methodInstance.cpp - p4/modelInstances.cpp p4/moveConstructors.cpp p4/moveDeclarations.cpp p4/parameterSubstitution.cpp @@ -110,9 +107,6 @@ set (P4_FRONTEND_HDRS p4/evaluator/evaluator.h p4/evaluator/substituteParameters.h p4/externInstance.h - p4/fromv1.0/converters.h - p4/fromv1.0/programStructure.h - p4/fromv1.0/v1model.h p4/frontend.h p4/functionsInlining.h p4/hierarchicalNames.h @@ -196,6 +190,11 @@ set (COMMON_FRONTEND_HDRS set (V1_FRONTEND_SRCS p4-14/typecheck.cpp p4-14/header_type.cpp + p4-14/v1.cpp + + p4-14/fromv1.0/converters.cpp + p4-14/fromv1.0/programStructure.cpp + p4-14/fromv1.0/v1model.cpp ) set (IR_DEF_FILES ${IR_DEF_FILES} ${CMAKE_CURRENT_SOURCE_DIR}/p4-14/ir-v1.def PARENT_SCOPE) @@ -204,6 +203,10 @@ set (V1_FRONTEND_HDRS p4-14/header_type.h p4-14/inline_control_flow.h p4-14/typecheck.h + + p4-14/fromv1.0/converters.h + p4-14/fromv1.0/programStructure.h + p4-14/fromv1.0/v1model.h ) set (PARSERS_SRCS diff --git a/frontends/common/parseInput.cpp b/frontends/common/parseInput.cpp index c12e0b8abd..15799b8d1c 100644 --- a/frontends/common/parseInput.cpp +++ b/frontends/common/parseInput.cpp @@ -19,7 +19,7 @@ limitations under the License. #include #include -#include "frontends/p4/fromv1.0/converters.h" +#include "frontends/p4-14/fromv1.0/converters.h" #include "frontends/parsers/parserDriver.h" #include "lib/error.h" diff --git a/frontends/common/parseInput.h b/frontends/common/parseInput.h index 84e44918d8..afe05064e9 100644 --- a/frontends/common/parseInput.h +++ b/frontends/common/parseInput.h @@ -19,7 +19,7 @@ limitations under the License. #include "frontends/common/options.h" #include "frontends/common/parser_options.h" -#include "frontends/p4/fromv1.0/converters.h" +#include "frontends/p4-14/fromv1.0/converters.h" #include "frontends/parsers/parserDriver.h" #include "lib/error.h" diff --git a/frontends/common/parser_options.cpp b/frontends/common/parser_options.cpp index d598987f0d..4f6da2845d 100644 --- a/frontends/common/parser_options.cpp +++ b/frontends/common/parser_options.cpp @@ -487,10 +487,10 @@ void ParserOptions::dumpPass(const char *manager, unsigned seq, const char *pass // regex_search checks if the regex is contained as substring match = std::regex_search(name.begin(), name.end(), s_regex); } catch (const std::regex_error &e) { - ::P4::error(ErrorType::ERR_INVALID, - "Malformed toP4 regex string \"%s\".\n" - "The regex matcher follows ECMAScript syntax.", - s); + error(ErrorType::ERR_INVALID, + "Malformed toP4 regex string \"%s\".\n" + "The regex matcher follows ECMAScript syntax.", + s); exit(1); } if (match) { @@ -501,13 +501,12 @@ void ParserOptions::dumpPass(const char *manager, unsigned seq, const char *pass std::unique_ptr stream{openFile(fileName, true)}; if (stream != nullptr) { if (Log::verbose()) std::cerr << "Writing program to " << fileName << std::endl; - // FIXME: Accept path here - P4::ToP4 toP4(stream.get(), Log::verbose(), cstring(file)); + std::unique_ptr toP4 = getToP4(stream.get(), Log::verbose(), file); if (noIncludes) { - toP4.setnoIncludesArg(true); + toP4->setnoIncludesArg(true); } if (node) { - node->apply(toP4); + node->apply(*toP4); } else { *stream << "No P4 program returned by the pass" << std::endl; } @@ -517,6 +516,11 @@ void ParserOptions::dumpPass(const char *manager, unsigned seq, const char *pass } } +std::unique_ptr ParserOptions::getToP4(std::ostream *outStream, bool showIR, + std::filesystem::path mainFile) const { + return std::make_unique(outStream, showIR, mainFile); +} + bool ParserOptions::isAnnotationDisabled(const IR::Annotation *a) const { if (disabledAnnotations.count(a->name.name) > 0) { ::P4::warning(ErrorType::WARN_IGNORE, "%1% is ignored because it was explicitly disabled", diff --git a/frontends/common/parser_options.h b/frontends/common/parser_options.h index 88a6d916b4..e41abdb30e 100644 --- a/frontends/common/parser_options.h +++ b/frontends/common/parser_options.h @@ -31,6 +31,8 @@ limitations under the License. namespace P4 { +class ToP4; + /// Standard include paths for .p4 header files. The values are determined by /// `configure`. extern const char *p4includePath; @@ -50,9 +52,14 @@ class ParserOptions : public Util::Options { mutable size_t dump_uid = 0; protected: - /// Function that is returned by getDebugHook. + /// Implements function that is returned by getDebugHook. The hook will take the same arguments. + /// The hook uses \ref getToP4 to obtain the P4 printer. void dumpPass(const char *manager, unsigned seq, const char *pass, const IR::Node *node) const; + /// Obtain an instance of ToP4 or its descendant. The arguments correspond to constructor + /// arguments of ToP4. + virtual std::unique_ptr getToP4(std::ostream *, bool, std::filesystem::path) const; + public: explicit ParserOptions(std::string_view defaultMessage = "Parse a P4 program"); @@ -92,8 +99,8 @@ class ParserOptions : public Util::Options { std::optional preprocess() const; /// True if we are compiling a P4 v1.0 or v1.1 program bool isv1() const; - /// Get a debug hook function suitable for insertion - /// in the pass managers that are executed. + /// Get a debug hook function suitable for insertion in the pass managers. The hook is + /// responsible for dumping P4 according to th --top4 and related options. DebugHook getDebugHook() const; /// Check whether this particular annotation was disabled bool isAnnotationDisabled(const IR::Annotation *a) const; diff --git a/frontends/p4/fromv1.0/converters.cpp b/frontends/p4-14/fromv1.0/converters.cpp similarity index 100% rename from frontends/p4/fromv1.0/converters.cpp rename to frontends/p4-14/fromv1.0/converters.cpp diff --git a/frontends/p4/fromv1.0/converters.h b/frontends/p4-14/fromv1.0/converters.h similarity index 99% rename from frontends/p4/fromv1.0/converters.h rename to frontends/p4-14/fromv1.0/converters.h index 4295531e9f..58290452fa 100644 --- a/frontends/p4/fromv1.0/converters.h +++ b/frontends/p4-14/fromv1.0/converters.h @@ -14,8 +14,8 @@ See the License for the specific language governing permissions and limitations under the License. */ -#ifndef FRONTENDS_P4_FROMV1_0_CONVERTERS_H_ -#define FRONTENDS_P4_FROMV1_0_CONVERTERS_H_ +#ifndef FRONTENDS_P4_14_FROMV1_0_CONVERTERS_H_ +#define FRONTENDS_P4_14_FROMV1_0_CONVERTERS_H_ #include #include @@ -1059,4 +1059,4 @@ class Converter : public PassManager { } // namespace P4::P4V1 -#endif /* FRONTENDS_P4_FROMV1_0_CONVERTERS_H_ */ +#endif /* FRONTENDS_P4_14_FROMV1_0_CONVERTERS_H_ */ diff --git a/frontends/p4/fromv1.0/programStructure.cpp b/frontends/p4-14/fromv1.0/programStructure.cpp similarity index 100% rename from frontends/p4/fromv1.0/programStructure.cpp rename to frontends/p4-14/fromv1.0/programStructure.cpp diff --git a/frontends/p4/fromv1.0/programStructure.h b/frontends/p4-14/fromv1.0/programStructure.h similarity index 98% rename from frontends/p4/fromv1.0/programStructure.h rename to frontends/p4-14/fromv1.0/programStructure.h index cdd3512bb3..14bb14ce19 100644 --- a/frontends/p4/fromv1.0/programStructure.h +++ b/frontends/p4-14/fromv1.0/programStructure.h @@ -14,8 +14,8 @@ See the License for the specific language governing permissions and limitations under the License. */ -#ifndef FRONTENDS_P4_FROMV1_0_PROGRAMSTRUCTURE_H_ -#define FRONTENDS_P4_FROMV1_0_PROGRAMSTRUCTURE_H_ +#ifndef FRONTENDS_P4_14_FROMV1_0_PROGRAMSTRUCTURE_H_ +#define FRONTENDS_P4_14_FROMV1_0_PROGRAMSTRUCTURE_H_ #include #include @@ -330,4 +330,4 @@ class ProgramStructure { } // namespace P4::P4V1 -#endif /* FRONTENDS_P4_FROMV1_0_PROGRAMSTRUCTURE_H_ */ +#endif /* FRONTENDS_P4_14_FROMV1_0_PROGRAMSTRUCTURE_H_ */ diff --git a/frontends/p4-14/fromv1.0/v1model.cpp b/frontends/p4-14/fromv1.0/v1model.cpp new file mode 100644 index 0000000000..d42259063e --- /dev/null +++ b/frontends/p4-14/fromv1.0/v1model.cpp @@ -0,0 +1,11 @@ +#include "frontends/p4-14/fromv1.0/v1model.h" + +/* These must be in the same compilation unit to ensure that P4CoreLibrary::instance + * is initialized before V1Model::instance */ +namespace P4::P4V1 { + +V1Model V1Model::instance; +const char *V1Model::versionInitial = "20180101"; +const char *V1Model::versionCurrent = "20200408"; + +} // namespace P4::P4V1 diff --git a/frontends/p4/fromv1.0/v1model.h b/frontends/p4-14/fromv1.0/v1model.h similarity index 94% rename from frontends/p4/fromv1.0/v1model.h rename to frontends/p4-14/fromv1.0/v1model.h index 4fb8f0eff4..faf3bd1353 100644 --- a/frontends/p4/fromv1.0/v1model.h +++ b/frontends/p4-14/fromv1.0/v1model.h @@ -14,15 +14,13 @@ See the License for the specific language governing permissions and limitations under the License. */ -#ifndef FRONTENDS_P4_FROMV1_0_V1MODEL_H_ -#define FRONTENDS_P4_FROMV1_0_V1MODEL_H_ +#ifndef FRONTENDS_P4_14_FROMV1_0_V1MODEL_H_ +#define FRONTENDS_P4_14_FROMV1_0_V1MODEL_H_ #include "frontends/common/model.h" #include "frontends/p4/coreLibrary.h" -#include "frontends/p4/methodInstance.h" #include "ir/ir.h" #include "lib/cstring.h" -#include "lib/json.h" namespace P4::P4V1 { @@ -353,22 +351,6 @@ class V1Model : public Model::Model { static const char *versionCurrent; // 20200408 }; -/// Stores the version of the global constant __v1model_version used -/// in the 'version' public instance variable. -class getV1ModelVersion : public Inspector { - bool preorder(const IR::Declaration_Constant *dc) override { - if (dc->name == "__v1model_version") { - auto val = dc->initializer->to(); - version = static_cast(val->value); - } - return false; - } - bool preorder(const IR::Declaration *) override { return false; } - - public: - unsigned version = 0; -}; - } // namespace P4::P4V1 -#endif /* FRONTENDS_P4_FROMV1_0_V1MODEL_H_ */ +#endif /* FRONTENDS_P4_14_FROMV1_0_V1MODEL_H_ */ diff --git a/frontends/p4-14/ir-v1.def b/frontends/p4-14/ir-v1.def index 2be392e8e6..0ea4d1179a 100644 --- a/frontends/p4-14/ir-v1.def +++ b/frontends/p4-14/ir-v1.def @@ -1,3 +1,110 @@ +/* -*-C++-*- */ + +/* + This file contains IR classes needed just for the P4 v1.0/v1.1 front-end. +*/ + +/** \addtogroup irdefs + * @{ + */ +#emit +namespace P4 { + +namespace IR { +enum class CounterType { NONE, PACKETS, BYTES, BOTH }; +} + +inline std::ostream& operator<<(std::ostream &out, IR::CounterType d) { + switch (d) { + case IR::CounterType::NONE: + out << "NONE"; + break; + case IR::CounterType::PACKETS: + out << "PACKETS"; + break; + case IR::CounterType::BYTES: + out << "BYTES"; + break; + case IR::CounterType::BOTH: + out << "BOTH"; + break; + default: + BUG("Unhandled case"); + } + return out; +} + +inline bool operator>>(cstring s, IR::CounterType &ctr) { + if (!s || s == "" || s == "NONE") ctr = IR::CounterType::NONE; + else if (s == "PACKETS") ctr = IR::CounterType::PACKETS; + else if (s == "BYTES") ctr = IR::CounterType::BYTES; + else if (s == "BOTH") ctr = IR::CounterType::BOTH; + else return false; + return true; +} + +} // namespace P4 + +#end + +class Type_Block : Type_Base { + toString { return "block"_cs; } + static Type_Block get(); + dbprint { out << "block"; } +} +class Type_Counter : Type_Base { + toString { return "counter"_cs; } + static Type_Counter get(); + dbprint { out << "counter"; } +} +class Type_Expression : Type_Base { + toString { return "expression"_cs; } + static Type_Expression get(); + dbprint { out << "expression"; } +} +class Type_FieldListCalculation : Type_Base { + toString { return "field_list_calculation"_cs; } + static Type_FieldListCalculation get(); + dbprint { out << "field_list_calculation"; } +} +class Type_Meter : Type_Base { + toString { return "meter"_cs; } + static Type_Meter get(); + dbprint { out << "meter"; } +} +class Type_Register : Type_Base { + toString { return "register"_cs; } + static Type_Register get(); + dbprint { out << "register"; } +} +class Type_AnyTable : Type_Base { + toString { return "table"_cs; } + static Type_AnyTable get(); + dbprint { out << "table"; } +} + +abstract HeaderOrMetadata : IAnnotated { + ID type_name; + ID name; + Annotations annotations; + NullOK Type_StructLike type = nullptr; + + Annotations getAnnotations() const override { return annotations; } + HeaderOrMetadata(ID n, Type_StructLike t) + : type_name(t->name), name(n), annotations(Annotations::empty), type(t) {} + dbprint { out << type_name << ' ' << name; } +} + +class Header : HeaderOrMetadata { + Header(ID n, Type_Header t) : HeaderOrMetadata(n, t) {} +#nodbprint +} + +class HeaderStack : HeaderOrMetadata { + int size; + HeaderStack(ID n, Type_Header t, int sz) : HeaderOrMetadata(n, t), size(sz) {} +#nodbprint +} class v1HeaderType { ID name; @@ -8,3 +115,379 @@ class v1HeaderType { : v1HeaderType(Util::SourceInfo(), m->name, m, h) {} dbprint { out << "header " << name; } } + +class Metadata : HeaderOrMetadata { + Metadata(ID n, Type_StructLike t) : HeaderOrMetadata(n, t) {} +#nodbprint +} + +abstract HeaderRef : Expression { + virtual HeaderOrMetadata baseRef() const = 0; +} + +class ConcreteHeaderRef : HeaderRef { + HeaderOrMetadata ref; + ConcreteHeaderRef { if (type->is() && ref) type = ref->type; } + HeaderOrMetadata baseRef() const override { return ref; } + toString{ return ref->name; } + dbprint{ out << ref->name; } +} + +class HeaderStackItemRef : HeaderRef { + Expression base_; + Expression index_; + HeaderStackItemRef { + if (type->is() && base_) + if (auto *hr = base_->to()) + type = hr->baseRef()->type; } + Expression base() const { return base_; } + /// Returns `nullptr` if the base is not `HeaderOrMetadata` (e.g. when this + /// is stack ref of an expression such as `lookahead`). + HeaderOrMetadata baseRef() const override { + auto hdrRef = base_->to(); + return hdrRef ? hdrRef->baseRef() : nullptr; + } + Expression index() const { return index_; } + void set_base(Expression b) { base_ = b; } + toString{ return base_->toString() + "[" + index_->toString() + "]"; } +} + +class If : Expression { + Expression pred; + NullOK Vector ifTrue; + NullOK Vector ifFalse; + visit_children { + v.visit(pred, "pred"); + SplitFlowVisit>(v, ifTrue, ifFalse).run_visit(); + Expression::visit_children(v); + } +} + +// an if condition tagged with a name so we can refer to it +class NamedCond : If { + cstring name = unique_name(); + + static cstring unique_name(); + NamedCond(const If &i) : If(i), name(unique_name()) {} + operator== { return If::operator==(static_cast(a)); } +#noconstructor +#nodbprint +} + +class Apply : Expression { + optional ID name; + // We should not use a NameMap, since it does not have source position information... + inline NameMap, ordered_map> actions = {}; + // ... we make up for it by storing the position of each label here. + inline NameMap position = {}; +} + +class Primitive : Operation { + cstring name; + inline Vector operands = {}; + + Primitive(cstring n, Vector l) : name(n) { + if (l) for (auto e : *l) operands.push_back(e); } + Primitive(Util::SourceInfo si, cstring n, Vector l) : Operation(si), name(n) { + if (l) for (auto e : *l) operands.push_back(e); } + Primitive(cstring n, Expression a1) : name(n) { + operands.push_back(a1); } + Primitive(Util::SourceInfo si, cstring n, Expression a1) : Operation(si), name(n) { + operands.push_back(a1); } + Primitive(cstring n, Expression a1, Expression a2) : name(n) { + operands.push_back(a1); operands.push_back(a2); } + Primitive(Util::SourceInfo si, cstring n, Expression a1, Expression a2) + : Operation(si), name(n) { + operands.push_back(a1); operands.push_back(a2); } + Primitive(cstring n, Expression a1, Vector a2) : name(n) { + operands.push_back(a1); + if (a2) for (auto e : *a2) operands.push_back(e); } + Primitive(Util::SourceInfo si, cstring n, Expression a1, Vector a2) + : Operation(si), name(n) { + operands.push_back(a1); + if (a2) for (auto e : *a2) operands.push_back(e); } + Primitive(cstring n, Expression a1, Expression a2, Expression a3) : name(n) { + operands.push_back(a1); operands.push_back(a2); operands.push_back(a3); } + Primitive(Util::SourceInfo si, cstring n, Expression a1, Expression a2, Expression a3) + : Operation(si), name(n) { + operands.push_back(a1); operands.push_back(a2); operands.push_back(a3); } + virtual bool isOutput(int operand_index) const; + virtual unsigned inferOperandTypes() const; + virtual Type inferOperandType(int operand) const; + virtual void typecheck() const; +#apply + stringOp = name; + precedence = DBPrint::Prec_Postfix; +} + +class FieldList : IAnnotated { + optional ID name; + bool payload = false; + optional Annotations annotations = Annotations::empty; + inline Vector fields = {}; + Annotations getAnnotations() const override { return annotations; } +} + +class FieldListCalculation : IAnnotated { + optional ID name; + NullOK NameList input = nullptr; + NullOK FieldList input_fields = nullptr; + NullOK NameList algorithm = nullptr; + int output_width = 0; + optional Annotations annotations = Annotations::empty; + Annotations getAnnotations() const override { return annotations; } +} + +class CalculatedField : IAnnotated { + optional NullOK Expression field; + class update_or_verify { + Util::SourceInfo srcInfo; + optional bool update = false; + ID name; + Expression cond; + update_or_verify() { } // FIXME -- needed by umpack_json(safe_vector) -- should not be + } + safe_vector specs = {}; + Annotations annotations; + Annotations getAnnotations() const override { return annotations; } + visit_children { + v.visit(field, "field"); + for (auto &s : specs) v.visit(s.cond, s.name.name); + v.visit(annotations, "annotations"); } +} + +class ParserValueSet : IAnnotated { + ID name; + optional Annotations annotations = Annotations::empty; + Annotations getAnnotations() const override { return annotations; } + dbprint { out << node_type_name() << " " << name; } + toString { return node_type_name() + " " + name; } +} + +class CaseEntry { + safe_vector> values = {}; + optional ID action; +} + +class V1Parser :IAnnotated { + optional ID name; + inline Vector stmts = {}; + NullOK Vector select = nullptr; + NullOK Vector cases = nullptr; + ID default_return = {}; + ID parse_error = {}; + bool drop = false; + Annotations annotations; + Annotations getAnnotations() const override { return annotations; } + toString { return node_type_name() + " " + name; } +} + +class ParserException {} + +abstract Attached : IInstance, IAnnotated { + optional ID name; + optional Annotations annotations = Annotations::empty; + ID Name() const override { return name; } + virtual const char *kind() const = 0; + Type getType() const override { return Type_Unknown::get(); } + Annotations getAnnotations() const override { return annotations; } + virtual bool indexed() const { return false; } + Attached *clone_rename(const char *ext) const { + Attached *rv = clone(); + rv->name = ID(Util::SourceInfo(), rv->name.name + ext); + return rv; } + dbprint { out << node_type_name() << " " << name; } + toString { return node_type_name() + " " + name; } +} + +abstract Stateful : Attached { + ID table = {}; + bool direct = false; + bool saturating = false; + int instance_count = -1; + virtual bool indexed() const override { return !direct; } + int index_width() const; // width of index in bits +} + +abstract CounterOrMeter : Stateful { + CounterType type = CounterType::NONE; + void settype(cstring t) { + if (strcasecmp(t.c_str(), "packets") == 0) type = CounterType::PACKETS; + else if (strcasecmp(t.c_str(), "bytes") == 0) type = CounterType::BYTES; + else if (strcasecmp(t.c_str(), "packets_and_bytes") == 0 || + strcasecmp(t.c_str(), "PacketAndBytes") == 0) type = CounterType::BOTH; + else error(ErrorType::ERR_UNKNOWN, "%s: Unknown type %s", srcInfo, t); } // NOLINT +} + +class Counter : CounterOrMeter { + int max_width = -1; + int min_width = -1; + const char *kind() const override { return "stats"; } + const Type *getType() const override { return Type_Counter::get(); } +} + +class Meter : CounterOrMeter { + NullOK Expression result = nullptr; + NullOK Expression pre_color = nullptr; + ID implementation = {}; + const char *kind() const override { return "meter"; } + Type getType() const override { return Type_Meter::get(); } +} + +class Register : Stateful { + ID layout = {}; + int width = -1; + bool signed_ = false; + /* bool saturating = false; */ + const char *kind() const override { return "register"; } + Type getType() const override { return Type_Register::get(); } +} + +class PrimitiveAction {} + +class NameList { + safe_vector names = {}; + NameList(Util::SourceInfo si, cstring n) { names.emplace_back(si, n); } + NameList(Util::SourceInfo si, ID n) { names.emplace_back(si, n); } + dump_fields { out << "names=" << names; } +} + +class ActionArg : Expression { + cstring action_name; + ID name; + bool read = false; + bool write = false; + ActionArg { if (!srcInfo) srcInfo = name.srcInfo; } + dbprint{ out << action_name << ':' << name; } + toString{ return name.name; } +} + +// Represents a P4 v1.0 action +class ActionFunction : IAnnotated { + optional ID name; + inline Vector action = {}; + safe_vector args = {}; + optional Annotations annotations = Annotations::empty; + + Annotations getAnnotations() const override { return annotations; } + ActionArg arg(cstring n) const { + for (auto a : args) + if (a->name == n) + return a; + return nullptr; } + visit_children { + v.visit(action, "action"); + // DANGER -- visiting action first so type inferencing will push types to + // DANGER -- action args based on use. This is immoral. + for (auto &a : args) v.visit(a, "arg"); + v.visit(annotations, "annotations"); + } + toString { + return "action "_cs + name + " {\n"_cs + + cstring::join(action.begin(), action.end(), ";\n") + + " }"_cs; } +} + +class ActionProfile : Attached { + ID selector = {}; + safe_vector actions = {}; + int size = 0; + const char *kind() const override { return "action_profile"; } + bool indexed() const override { return true; } +} + +class ActionSelector : Attached { + ID key = {}; + NullOK FieldListCalculation key_fields = nullptr; + ID mode = {}; + ID type = {}; + const char *kind() const override { return "action_selector"; } +} + +class V1Table : IInstance, IAnnotated { + optional ID name; + NullOK Vector reads = 0; + safe_vector reads_types = {}; + int min_size = 0; + int max_size = 0; + int size = 0; + ID action_profile = {}; + safe_vector actions = {}; + ID default_action = {}; + bool default_action_is_const = false; + NullOK Vector default_action_args = 0; + inline TableProperties properties = {}; // non-standard properties + optional Annotations annotations = Annotations::empty; + + void addProperty(Property prop) { properties.push_back(prop); } + Annotations getAnnotations() const override { return annotations; } + toString { return node_type_name() + " " + name; } + ID Name() const override { return name; } + Type getType() const override { return Type_AnyTable::get(); } +} + +class V1Control : IAnnotated { + ID name; + Vector code; + Annotations annotations; + + V1Control(ID n) : name(n), code(new Vector()) {} + V1Control(Util::SourceInfo si, ID n) : Node(si), name(n), code(new Vector()) {} +#apply + Annotations getAnnotations() const override { return annotations; } + toString { return node_type_name() + " " + name; } +} + +class AttribLocal : Expression, IDeclaration { + ID name; + ID getName() const override { return name; } + dbprint { out << name; } +} + +class AttribLocals : ISimpleNamespace { + inline NameMap locals = {}; +#nodbprint + Util::Enumerator *getDeclarations() const override { + return locals.valueEnumerator()->as(); } + IDeclaration getDeclByName(cstring name) const override { return locals[name]; } + IDeclaration getDeclByName(std::string_view name) const override { return locals[cstring(name)]; } +} + +class Attribute : Declaration { + NullOK Type type = nullptr; + NullOK AttribLocals locals = nullptr; + bool optional = false; + dbprint { if (type) out << type << ' '; out << name; } +} + +class GlobalRef : Expression { + Node obj; // FIXME -- should be IInstance, but IRgen doesn't allow + // FIXME -- interface references directly in the IR + GlobalRef { type = obj->to()->getType(); } + validate { BUG_CHECK(obj->is(), "Invalid object %1%", obj); } + toString { return obj->to()->toString(); } + ID Name() const { return obj->to()->Name(); } + dbprint { out << obj->to()->Name(); } +} + +class AttributeRef : Expression { + cstring extern_name; + Type_Extern extern_type; + Attribute attrib; + AttributeRef { type = attrib->type; } + toString { return attrib->name; } + dbprint { out << attrib->name; } +} + +class V1Program { + inline NameMap scope; + +#noconstructor + explicit V1Program(); +#emit + template const T *get(cstring name) const { return scope.get(name); } +#end + void add(cstring name, const Node *n) { scope.add(name, n); } +#apply +} +/** @} *//* end group irdefs */ diff --git a/ir/v1.cpp b/frontends/p4-14/v1.cpp similarity index 100% rename from ir/v1.cpp rename to frontends/p4-14/v1.cpp diff --git a/frontends/p4/frontend.cpp b/frontends/p4/frontend.cpp index 35872e1ad7..f22a6fd2b2 100644 --- a/frontends/p4/frontend.cpp +++ b/frontends/p4/frontend.cpp @@ -16,12 +16,10 @@ limitations under the License. #include "frontend.h" -#include #include #include "../common/options.h" #include "frontends/common/resolveReferences/resolveReferences.h" -#include "frontends/p4/fromv1.0/v1model.h" #include "frontends/p4/typeChecking/bindVariables.h" #include "frontends/p4/typeMap.h" #include "ir/ir.h" @@ -41,6 +39,7 @@ limitations under the License. #include "evaluator/evaluator.h" #include "frontends/common/constantFolding.h" #include "functionsInlining.h" +#include "getV1ModelVersion.h" #include "hierarchicalNames.h" #include "inlining.h" #include "localizeActions.h" @@ -105,8 +104,7 @@ class PrettyPrint : public Inspector { bool preorder(const IR::P4Program *program) override { if (!ppfile.empty()) { std::ostream *ppStream = openFile(ppfile, true); - // FIXME: ToP4 should accept PathName - P4::ToP4 top4(ppStream, false, cstring(inputfile)); + P4::ToP4 top4(ppStream, false, inputfile); (void)program->apply(top4); } return false; // prune @@ -163,7 +161,7 @@ const IR::P4Program *FrontEnd::run(const CompilerOptions &options, const IR::P4P auto evaluator = new P4::EvaluatorPass(&refMap, &typeMap); PassManager passes({ - new P4V1::getV1ModelVersion, + new P4V1::GetV1ModelVersion, // Parse annotations new ParseAnnotationBodies(parseAnnotations, &typeMap), new PrettyPrint(options), @@ -237,7 +235,7 @@ const IR::P4Program *FrontEnd::run(const CompilerOptions &options, const IR::P4P new ClearTypeMap(&typeMap), evaluator, }); - if (policy->optimize(options)) + if (policy->optimize(options)) { passes.addPasses({ new Inline(&refMap, &typeMap, evaluator, *policy, options.optimizeParserInlining), new InlineActions(&refMap, &typeMap, *policy), @@ -262,6 +260,7 @@ const IR::P4Program *FrontEnd::run(const CompilerOptions &options, const IR::P4P new RemoveAllUnusedDeclarations(&refMap, *policy), new SimplifyControlFlow(&typeMap), }); + } passes.addPasses({ // Check for shadowing after all inlining passes. We disable this // check during inlining since it significantly slows compilation. diff --git a/frontends/p4/functionsInlining.cpp b/frontends/p4/functionsInlining.cpp index 78ce544150..147c6a4d2e 100644 --- a/frontends/p4/functionsInlining.cpp +++ b/frontends/p4/functionsInlining.cpp @@ -69,6 +69,48 @@ Visitor::profile_t FunctionsInliner::init_apply(const IR::Node *node) { return rv; } +class FunctionsInliner::isLocalExpression : public Inspector, ResolutionContext { + bool done = false; + bool result = true; + + profile_t init_apply(const IR::Node *node) override { + BUG_CHECK(!done, "isLocalExpression can only be applied once"); + return Inspector::init_apply(node); + } + void end_apply() override { done = true; } + bool preorder(const IR::Node *) override { return result; } + bool preorder(const IR::Path *p) override { + if (p->absolute) return result = false; + // cribbed from ResolutionContext::resolve -- we want to resolve the name, + // except we want to know what scope it is found in, not what it resolves to + const Context *ctxt = nullptr; + while (auto scope = findOrigCtxt(ctxt)) { + if (scope->is() || scope->is() || + scope->is() || scope->is() || + scope->is() || scope->is()) { + // these are "global" things that may contain functions + return result = false; + } + if (!lookup(scope, p->name, P4::ResolutionType::Any).empty()) return result; + if (scope->is() || scope->is()) { + // no need to look further as can't have nested functions + return result = false; + } + } + BUG("failed to reach global scope"); + return result; + } + + public: + isLocalExpression(const IR::Expression *expr, const Visitor_Context *ctxt) { + expr->apply(*this, ctxt); + } + explicit operator bool() { + BUG_CHECK(done, "isLocalExpression not computed"); + return result; + } +}; + bool FunctionsInliner::preCaller() { LOG2("Visiting: " << dbp(getOriginal())); if (toInline->sites.count(getOriginal()) == 0) { @@ -195,19 +237,26 @@ const IR::Statement *FunctionsInliner::inlineBefore(const IR::Node *calleeNode, BUG_CHECK(callee, "%1%: expected a function", calleeNode); IR::IndexedVector body; - ParameterSubstitution subst; + ParameterSubstitution subst; // rewrites for params TypeVariableSubstitution tvs; // empty - std::map paramRename; - ParameterSubstitution substitution; + ParameterSubstitution substitution; // map params to actual arguments substitution.populate(callee->type->parameters, mce->arguments); + // parameters that need copyout + std::vector> needCopyout; + // evaluate in and inout parameters in order for (auto param : callee->type->parameters->parameters) { auto argument = substitution.lookup(param); cstring newName = nameGen->newName(param->name.name.string_view()); - paramRename.emplace(param, newName); - if (param->direction == IR::Direction::In || param->direction == IR::Direction::InOut) { + if ((param->direction == IR::Direction::Out || param->direction == IR::Direction::InOut) && + isLocalExpression(argument->expression, getChildContext())) { + // If the actual parameter is local to the caller, we can just rewrite the callee + // to access it directly, without the overhead of copying it in or out + subst.add(param, argument); + } else if (param->direction == IR::Direction::In || + param->direction == IR::Direction::InOut) { auto vardecl = new IR::Declaration_Variable(newName, param->annotations, param->type); body.push_back(vardecl); auto copyin = @@ -215,6 +264,8 @@ const IR::Statement *FunctionsInliner::inlineBefore(const IR::Node *calleeNode, body.push_back(copyin); subst.add(param, new IR::Argument(argument->srcInfo, argument->name, new IR::PathExpression(newName))); + if (param->direction == IR::Direction::InOut) + needCopyout.emplace_back(newName, argument); } else if (param->direction == IR::Direction::None) { // This works because there can be no side-effects in the evaluation of this // argument. @@ -225,6 +276,7 @@ const IR::Statement *FunctionsInliner::inlineBefore(const IR::Node *calleeNode, subst.add(param, new IR::Argument(argument->srcInfo, argument->name, new IR::PathExpression(newName))); body.push_back(vardecl); + needCopyout.emplace_back(newName, argument); } } @@ -242,14 +294,10 @@ const IR::Statement *FunctionsInliner::inlineBefore(const IR::Node *calleeNode, auto retExpr = cloneBody(funclone->body->components, body); // copy out and inout parameters - for (auto param : callee->type->parameters->parameters) { - auto left = substitution.lookup(param); - if (param->direction == IR::Direction::InOut || param->direction == IR::Direction::Out) { - cstring newName = ::P4::get(paramRename, param); - auto right = new IR::PathExpression(newName); - auto copyout = new IR::AssignmentStatement(left->expression, right); - body.push_back(copyout); - } + for (auto [newName, argument] : needCopyout) { + auto right = new IR::PathExpression(newName); + auto copyout = new IR::AssignmentStatement(argument->expression, right); + body.push_back(copyout); } if (auto assign = statement->to()) { diff --git a/frontends/p4/functionsInlining.h b/frontends/p4/functionsInlining.h index 48215e7c9c..269cf6b90d 100644 --- a/frontends/p4/functionsInlining.h +++ b/frontends/p4/functionsInlining.h @@ -73,6 +73,7 @@ class FunctionsInliner : public AbstractInlinername == "__v1model_version") { + const auto *val = dc->initializer->to(); + version = static_cast(val->value); + } + return false; + } + bool preorder(const IR::Declaration *) override { return false; } + + public: + unsigned version = 0; +}; + +} // namespace P4::P4V1 + +#endif /* _FRONTENDS_P4_GETV1MODELVERSION_H_ */ diff --git a/frontends/p4/modelInstances.cpp b/frontends/p4/modelInstances.cpp deleted file mode 100644 index fd1633a2eb..0000000000 --- a/frontends/p4/modelInstances.cpp +++ /dev/null @@ -1,28 +0,0 @@ -/* -Copyright 2013-present Barefoot Networks, Inc. - -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 "coreLibrary.h" -#include "fromv1.0/v1model.h" - -/* These must be in the same compiliation unit to ensure that P4CoreLibrary::instance - * is initialized before V1Model::instance */ -namespace P4::P4V1 { - -V1Model V1Model::instance; -const char *V1Model::versionInitial = "20180101"; -const char *V1Model::versionCurrent = "20200408"; - -} // namespace P4::P4V1 diff --git a/frontends/p4/parameterSubstitution.h b/frontends/p4/parameterSubstitution.h index 15fcc0c4f0..eb3462e925 100644 --- a/frontends/p4/parameterSubstitution.h +++ b/frontends/p4/parameterSubstitution.h @@ -75,12 +75,21 @@ class ParameterSubstitution : public IHasDbPrint { } void dbprint(std::ostream &out) const { + bool brief = (DBPrint::dbgetflags(out) & DBPrint::Brief); if (paramList != nullptr) { - for (auto s : *paramList->getEnumerator()) - out << dbp(s) << "=>" << dbp(lookup(s)) << std::endl; + if (!brief) out << "paramList:" << Log::endl; + for (auto s : *paramList->getEnumerator()) { + out << dbp(s) << "=>" << dbp(lookup(s)); + if (!brief) out << " " << lookup(s); + out << Log::endl; + } } else { - for (auto s : parametersByName) - out << dbp(s.second) << "=>" << dbp(lookupByName(s.first)) << std::endl; + if (!brief) out << "parametersByName:" << Log::endl; + for (auto s : parametersByName) { + out << dbp(s.second) << "=>" << dbp(lookupByName(s.first)); + if (!brief) out << " " << lookupByName(s.first); + out << Log::endl; + } } } diff --git a/frontends/p4/toP4/toP4.cpp b/frontends/p4/toP4/toP4.cpp index cad9e003b5..270c6bc8da 100644 --- a/frontends/p4/toP4/toP4.cpp +++ b/frontends/p4/toP4/toP4.cpp @@ -16,12 +16,12 @@ limitations under the License. #include "toP4.h" -#include #include #include -#include "frontends/common/options.h" -#include "frontends/p4/fromv1.0/v1model.h" +#include "frontends/common/parser_options.h" +#include "frontends/p4-14/fromv1.0/v1model.h" +#include "frontends/p4/getV1ModelVersion.h" #include "frontends/parsers/p4/p4parser.hpp" #include "ir/dump.h" @@ -165,8 +165,10 @@ bool ToP4::preorder(const IR::P4Program *program) { if (sourceFile.startsWith(p4includePath)) { const char *p = sourceFile.c_str() + strlen(p4includePath); if (*p == '/') p++; + // TODO: This is v1model-specific code. This should be not part of the core + // pass. if (P4V1::V1Model::instance.file.name == p) { - P4V1::getV1ModelVersion g; + P4V1::GetV1ModelVersion g; program->apply(g); builder.append("#define V1MODEL_VERSION "); builder.append(g.version); diff --git a/frontends/p4/toP4/toP4.h b/frontends/p4/toP4/toP4.h index 87e78e7771..52ee1cf78b 100644 --- a/frontends/p4/toP4/toP4.h +++ b/frontends/p4/toP4/toP4.h @@ -17,7 +17,10 @@ limitations under the License. #ifndef P4_TOP4_TOP4_H_ #define P4_TOP4_TOP4_H_ +#include +#include #include +#include #include "frontends/common/resolveReferences/resolveReferences.h" #include "ir/ir.h" @@ -31,12 +34,14 @@ This pass converts a P4-16 IR into a P4 source (text) program. It can optionally emit as comments a representation of the program IR. */ class ToP4 : public Inspector, ResolutionContext { - int expressionPrecedence; /// precedence of current IR::Operation - bool isDeclaration; /// current type is a declaration - bool showIR; /// if true dump IR as comments - bool withinArgument; /// if true we are within a method call argument - bool noIncludes = false; /// If true do not generate #include statements. - /// Used for debugging. + protected: + /// precedence of current IR::Operation + int expressionPrecedence = DBPrint::Prec_Low; + bool isDeclaration = true; /// current type is a declaration + bool showIR; /// if true dump IR as comments + bool withinArgument = false; /// if true we are within a method call argument + bool noIncludes = false; /// If true do not generate #include statements. + /// Used for debugging. struct VecPrint { cstring separator; @@ -87,46 +92,31 @@ class ToP4 : public Inspector, ResolutionContext { * directly to the ostream. The SourceCodeBuilder object does not appear to add any * useful functionality the ostream does not already provide; it just serves to * obfuscate the code */ - std::ostream *outStream; - /** If this is set to non-nullptr, some declarations + std::ostream *outStream = nullptr; + /** If this is set to non-empty, some declarations that come from libraries and models are not emitted. */ - cstring mainFile; - - ToP4(Util::SourceCodeBuilder &builder, bool showIR, cstring mainFile = nullptr) - : expressionPrecedence(DBPrint::Prec_Low), - isDeclaration(true), - showIR(showIR), - withinArgument(false), - builder(builder), - outStream(nullptr), - mainFile(mainFile) { + std::optional mainFile; + + ToP4(Util::SourceCodeBuilder &builder, bool showIR) : showIR(showIR), builder(builder) { visitDagOnce = false; setName("ToP4"); } - ToP4(std::ostream *outStream, bool showIR, cstring mainFile = nullptr) - : expressionPrecedence(DBPrint::Prec_Low), - isDeclaration(true), - showIR(showIR), - withinArgument(false), - builder(*new Util::SourceCodeBuilder()), - outStream(outStream), - mainFile(mainFile) { - visitDagOnce = false; - setName("ToP4"); + + ToP4(std::ostream *outStream, bool showIR) : ToP4(*new Util::SourceCodeBuilder(), showIR) { + this->outStream = outStream; } - ToP4() - : // this is useful for debugging - expressionPrecedence(DBPrint::Prec_Low), - isDeclaration(true), - showIR(false), - withinArgument(false), - builder(*new Util::SourceCodeBuilder()), - outStream(&std::cout), - mainFile(nullptr) { - visitDagOnce = false; - setName("ToP4"); + + ToP4(Util::SourceCodeBuilder &builder, bool showIR, std::filesystem::path mainFile) + : ToP4(builder, showIR) { + this->mainFile = mainFile; } + ToP4(std::ostream *outStream, bool showIR, std::filesystem::path mainFile) + : ToP4(outStream, showIR) { + this->mainFile = mainFile; + } + + ToP4() : ToP4(*new Util::SourceCodeBuilder(), false) {} using Inspector::preorder; diff --git a/frontends/parsers/p4/p4parser.ypp b/frontends/parsers/p4/p4parser.ypp index 22ba7c5e7c..01efb79d36 100644 --- a/frontends/parsers/p4/p4parser.ypp +++ b/frontends/parsers/p4/p4parser.ypp @@ -250,7 +250,7 @@ using namespace P4; // End of token definitions /////////////////////////////////////////////////// -%type name dot_name nonTypeName nonTableKwName +%type name dot_name nonTypeName nonTableKwName annotationName %type direction %type prefixedNonTypeName prefixedType %type*> typeParameterList @@ -533,20 +533,20 @@ annotations ; annotation - : "@" name + : "@" annotationName { // Initialize with an empty sequence of annotation tokens so that the // annotation node is marked as unparsed. IR::Vector body; $$ = new IR::Annotation(@1, *$2, body); } - | "@" name "(" annotationBody ")" + | "@" annotationName "(" annotationBody ")" { $$ = new IR::Annotation(@1, *$2, *$4); } - | "@" name "[" expressionList optTrailingComma "]" + | "@" annotationName "[" expressionList optTrailingComma "]" { $$ = new IR::Annotation(@1, *$2, *$4, true); } - | "@" name "[" kvList optTrailingComma "]" + | "@" annotationName "[" kvList optTrailingComma "]" { $$ = new IR::Annotation(@1, *$2, *$4, true); } // Experimental: backwards compatibility with P4-14 pragmas (which // themselves are experimental!) - | PRAGMA name annotationBody END_PRAGMA + | PRAGMA annotationName annotationBody END_PRAGMA { $$ = new IR::Annotation(@1, *$2, *$3, false); } ; @@ -566,6 +566,60 @@ annotationBody } ; +annotationName + : ABSTRACT { $$ = new IR::ID(@1, "abstract"_cs); } + | ACTION { $$ = new IR::ID(@1, "action"_cs); } + | ACTIONS { $$ = new IR::ID(@1, "actions"_cs); } + | APPLY { $$ = new IR::ID(@1, "apply"_cs); } + | BOOL { $$ = new IR::ID(@1, "bool"_cs); } + | BIT { $$ = new IR::ID(@1, "bit"_cs); } + | BREAK { $$ = new IR::ID(@1, "break"_cs); } + | CONST { $$ = new IR::ID(@1, "const"_cs); } + | CONTINUE { $$ = new IR::ID(@1, "continue"_cs); } + | CONTROL { $$ = new IR::ID(@1, "control"_cs); } + | DEFAULT { $$ = new IR::ID(@1, "default"_cs); } + | ELSE { $$ = new IR::ID(@1, "else"_cs); } + | ENTRIES { $$ = new IR::ID(@1, "entries"_cs); } + | ENUM { $$ = new IR::ID(@1, "enum"_cs); } + | ERROR { $$ = new IR::ID(@1, "error"_cs); } + | EXIT { $$ = new IR::ID(@1, "exit"_cs); } + | EXTERN { $$ = new IR::ID(@1, "extern"_cs); } + | FALSE { $$ = new IR::ID(@1, "false"_cs); } + | FOR { $$ = new IR::ID(@1, "for"_cs); } + | HEADER { $$ = new IR::ID(@1, "header"_cs); } + | HEADER_UNION { $$ = new IR::ID(@1, "header_union"_cs); } + | IF { $$ = new IR::ID(@1, "if"_cs); } + | IN { $$ = new IR::ID(@1, "in"_cs); } + | INOUT { $$ = new IR::ID(@1, "inout"_cs); } + | INT { $$ = new IR::ID(@1, "int"_cs); } + | KEY { $$ = new IR::ID(@1, "key"_cs); } + | MATCH_KIND { $$ = new IR::ID(@1, "match_kind"_cs); } + | TYPE { $$ = new IR::ID(@1, "type"_cs); } + | OUT { $$ = new IR::ID(@1, "out"_cs); } + | PARSER { $$ = new IR::ID(@1, "parser"_cs); } + | PACKAGE { $$ = new IR::ID(@1, "package"_cs); } + | PRIORITY { $$ = new IR::ID(@1, "priority"_cs); } + | RETURN { $$ = new IR::ID(@1, "return"_cs); } + | SELECT { $$ = new IR::ID(@1, "select"_cs); } + | STATE { $$ = new IR::ID(@1, "state"_cs); } + | STRING { $$ = new IR::ID(@1, "string"_cs); } + | STRUCT { $$ = new IR::ID(@1, "struct"_cs); } + | SWITCH { $$ = new IR::ID(@1, "switch"_cs); } + | TABLE { $$ = new IR::ID(@1, "table"_cs); } + | THIS { $$ = new IR::ID(@1, "this"_cs); } + | TRANSITION { $$ = new IR::ID(@1, "transition"_cs); } + | TRUE { $$ = new IR::ID(@1, "true"_cs); } + | TUPLE { $$ = new IR::ID(@1, "tuple"_cs); } + | TYPEDEF { $$ = new IR::ID(@1, "typedef"_cs); } + | VARBIT { $$ = new IR::ID(@1, "varbit"_cs); } + | VALUESET { $$ = new IR::ID(@1, "valueset"_cs); } + | LIST { $$ = new IR::ID(@1, "list"_cs); } + | VOID { $$ = new IR::ID(@1, "void"_cs); } + | "_" { $$ = new IR::ID(@1, "_"_cs); } + | IDENTIFIER { $$ = new IR::ID(@1, $1); } + | TYPE_IDENTIFIER { $$ = new IR::ID(@1, $1); } + ; + annotationToken : UNEXPECTED_TOKEN { $$ = $1; } | ABSTRACT { $$ = $1; } diff --git a/ir/CMakeLists.txt b/ir/CMakeLists.txt index bdce1d6aac..9ae8a25324 100644 --- a/ir/CMakeLists.txt +++ b/ir/CMakeLists.txt @@ -30,7 +30,6 @@ set (IR_SRCS pass_manager.cpp pass_utils.cpp type.cpp - v1.cpp visitor.cpp write_context.cpp ) @@ -62,7 +61,6 @@ set (BASE_IR_DEF_FILES ${CMAKE_CURRENT_SOURCE_DIR}/type.def ${CMAKE_CURRENT_SOURCE_DIR}/expression.def ${CMAKE_CURRENT_SOURCE_DIR}/ir.def - ${CMAKE_CURRENT_SOURCE_DIR}/v1.def ) set (IR_DEF_FILES ${IR_DEF_FILES} ${BASE_IR_DEF_FILES} PARENT_SCOPE) diff --git a/ir/type.def b/ir/type.def index 6e753d0e98..2a05cedf51 100644 --- a/ir/type.def +++ b/ir/type.def @@ -442,7 +442,7 @@ interface Type_Indexed { // Probably this sohuld be called 'size()', but some subclasses already // have a 'size' field. virtual size_t getSize() const = 0; - Type at(size_t index) const; + virtual Type at(size_t index) const = 0; } /// Base class for Type_List, and Type_Tuple @@ -450,7 +450,7 @@ abstract Type_BaseList : Type, Type_Indexed { optional inline Vector components; validate{ components.check_null(); } size_t getSize() const override { return components.size(); } - Type at(size_t index) const { return components.at(index); } + Type at(size_t index) const override { return components.at(index); } int width_bits() const override { /// returning sum of the width of the elements int rv = 0; @@ -571,7 +571,7 @@ class Type_Stack : Type_Indexed, Type { dbprint{ out << elementType << "[" << size << "]"; } bool sizeKnown() const; size_t getSize() const override; - Type at(size_t index) const; + Type at(size_t index) const override; static const cstring next; static const cstring last; static const cstring arraySize; diff --git a/ir/v1.def b/ir/v1.def index c7a09a2e78..e69de29bb2 100644 --- a/ir/v1.def +++ b/ir/v1.def @@ -1,482 +0,0 @@ -/* -*-C++-*- */ - -/* - This file contains IR classes needed just for the P4 v1.0/v1.1 front-end. -*/ - -/** \addtogroup irdefs - * @{ - */ -#emit -namespace P4 { -namespace IR { -enum class CounterType { NONE, PACKETS, BYTES, BOTH }; -} // namespace IR - -inline std::ostream& operator<<(std::ostream &out, IR::CounterType d) { - switch (d) { - case IR::CounterType::NONE: - out << "NONE"; - break; - case IR::CounterType::PACKETS: - out << "PACKETS"; - break; - case IR::CounterType::BYTES: - out << "BYTES"; - break; - case IR::CounterType::BOTH: - out << "BOTH"; - break; - default: - BUG("Unhandled case"); - } - return out; -} - -inline bool operator>>(cstring s, IR::CounterType &ctr) { - if (!s || s == "" || s == "NONE") ctr = IR::CounterType::NONE; - else if (s == "PACKETS") ctr = IR::CounterType::PACKETS; - else if (s == "BYTES") ctr = IR::CounterType::BYTES; - else if (s == "BOTH") ctr = IR::CounterType::BOTH; - else return false; - return true; -} - -} // namespace P4 - -#end - -class Type_Block : Type_Base { - toString { return "block"_cs; } - static Type_Block get(); - dbprint { out << "block"; } -} -class Type_Counter : Type_Base { - toString { return "counter"_cs; } - static Type_Counter get(); - dbprint { out << "counter"; } -} -class Type_Expression : Type_Base { - toString { return "expression"_cs; } - static Type_Expression get(); - dbprint { out << "expression"; } -} -class Type_FieldListCalculation : Type_Base { - toString { return "field_list_calculation"_cs; } - static Type_FieldListCalculation get(); - dbprint { out << "field_list_calculation"; } -} -class Type_Meter : Type_Base { - toString { return "meter"_cs; } - static Type_Meter get(); - dbprint { out << "meter"; } -} -class Type_Register : Type_Base { - toString { return "register"_cs; } - static Type_Register get(); - dbprint { out << "register"; } -} -class Type_AnyTable : Type_Base { - toString { return "table"_cs; } - static Type_AnyTable get(); - dbprint { out << "table"; } -} - -abstract HeaderOrMetadata : IAnnotated { - ID type_name; - ID name; - Annotations annotations; - NullOK Type_StructLike type = nullptr; - - Annotations getAnnotations() const override { return annotations; } - HeaderOrMetadata(ID n, Type_StructLike t) - : type_name(t->name), name(n), annotations(Annotations::empty), type(t) {} - dbprint { out << type_name << ' ' << name; } -} - -class Header : HeaderOrMetadata { - Header(ID n, Type_Header t) : HeaderOrMetadata(n, t) {} -#nodbprint -} - -class HeaderStack : HeaderOrMetadata { - int size; - HeaderStack(ID n, Type_Header t, int sz) : HeaderOrMetadata(n, t), size(sz) {} -#nodbprint -} - -class Metadata : HeaderOrMetadata { - Metadata(ID n, Type_StructLike t) : HeaderOrMetadata(n, t) {} -#nodbprint -} - -abstract HeaderRef : Expression { - virtual HeaderOrMetadata baseRef() const = 0; -} - -class ConcreteHeaderRef : HeaderRef { - HeaderOrMetadata ref; - ConcreteHeaderRef { if (type->is() && ref) type = ref->type; } - HeaderOrMetadata baseRef() const override { return ref; } - toString{ return ref->name; } - dbprint{ out << ref->name; } -} - -class HeaderStackItemRef : HeaderRef { - Expression base_; - Expression index_; - HeaderStackItemRef { - if (type->is() && base_) - if (auto *hr = base_->to()) - type = hr->baseRef()->type; } - Expression base() const { return base_; } - /// Returns `nullptr` if the base is not `HeaderOrMetadata` (e.g. when this - /// is stack ref of an expression such as `lookahead`). - HeaderOrMetadata baseRef() const override { - auto hdrRef = base_->to(); - return hdrRef ? hdrRef->baseRef() : nullptr; - } - Expression index() const { return index_; } - void set_base(Expression b) { base_ = b; } - toString{ return base_->toString() + "[" + index_->toString() + "]"; } -} - -class If : Expression { - Expression pred; - NullOK Vector ifTrue; - NullOK Vector ifFalse; - visit_children { - v.visit(pred, "pred"); - SplitFlowVisit>(v, ifTrue, ifFalse).run_visit(); - Expression::visit_children(v); - } -} - -// an if condition tagged with a name so we can refer to it -class NamedCond : If { - cstring name = unique_name(); - - static cstring unique_name(); - NamedCond(const If &i) : If(i), name(unique_name()) {} - operator== { return If::operator==(static_cast(a)); } -#noconstructor -#nodbprint -} - -class Apply : Expression { - optional ID name; - // We should not use a NameMap, since it does not have source position information... - inline NameMap, ordered_map> actions = {}; - // ... we make up for it by storing the position of each label here. - inline NameMap position = {}; -} - -class Primitive : Operation { - cstring name; - inline Vector operands = {}; - - Primitive(cstring n, Vector l) : name(n) { - if (l) for (auto e : *l) operands.push_back(e); } - Primitive(Util::SourceInfo si, cstring n, Vector l) : Operation(si), name(n) { - if (l) for (auto e : *l) operands.push_back(e); } - Primitive(cstring n, Expression a1) : name(n) { - operands.push_back(a1); } - Primitive(Util::SourceInfo si, cstring n, Expression a1) : Operation(si), name(n) { - operands.push_back(a1); } - Primitive(cstring n, Expression a1, Expression a2) : name(n) { - operands.push_back(a1); operands.push_back(a2); } - Primitive(Util::SourceInfo si, cstring n, Expression a1, Expression a2) - : Operation(si), name(n) { - operands.push_back(a1); operands.push_back(a2); } - Primitive(cstring n, Expression a1, Vector a2) : name(n) { - operands.push_back(a1); - if (a2) for (auto e : *a2) operands.push_back(e); } - Primitive(Util::SourceInfo si, cstring n, Expression a1, Vector a2) - : Operation(si), name(n) { - operands.push_back(a1); - if (a2) for (auto e : *a2) operands.push_back(e); } - Primitive(cstring n, Expression a1, Expression a2, Expression a3) : name(n) { - operands.push_back(a1); operands.push_back(a2); operands.push_back(a3); } - Primitive(Util::SourceInfo si, cstring n, Expression a1, Expression a2, Expression a3) - : Operation(si), name(n) { - operands.push_back(a1); operands.push_back(a2); operands.push_back(a3); } - virtual bool isOutput(int operand_index) const; - virtual unsigned inferOperandTypes() const; - virtual Type inferOperandType(int operand) const; - virtual void typecheck() const; -#apply - stringOp = name; - precedence = DBPrint::Prec_Postfix; -} - -class FieldList : IAnnotated { - optional ID name; - bool payload = false; - optional Annotations annotations = Annotations::empty; - inline Vector fields = {}; - Annotations getAnnotations() const override { return annotations; } -} - -class FieldListCalculation : IAnnotated { - optional ID name; - NullOK NameList input = nullptr; - NullOK FieldList input_fields = nullptr; - NullOK NameList algorithm = nullptr; - int output_width = 0; - optional Annotations annotations = Annotations::empty; - Annotations getAnnotations() const override { return annotations; } -} - -class CalculatedField : IAnnotated { - optional NullOK Expression field; - class update_or_verify { - Util::SourceInfo srcInfo; - optional bool update = false; - ID name; - Expression cond; - update_or_verify() { } // FIXME -- needed by umpack_json(safe_vector) -- should not be - } - safe_vector specs = {}; - Annotations annotations; - Annotations getAnnotations() const override { return annotations; } - visit_children { - v.visit(field, "field"); - for (auto &s : specs) v.visit(s.cond, s.name.name); - v.visit(annotations, "annotations"); } -} - -class ParserValueSet : IAnnotated { - ID name; - optional Annotations annotations = Annotations::empty; - Annotations getAnnotations() const override { return annotations; } - dbprint { out << node_type_name() << " " << name; } - toString { return node_type_name() + " " + name; } -} - -class CaseEntry { - safe_vector> values = {}; - optional ID action; -} - -class V1Parser :IAnnotated { - optional ID name; - inline Vector stmts = {}; - NullOK Vector select = nullptr; - NullOK Vector cases = nullptr; - ID default_return = {}; - ID parse_error = {}; - bool drop = false; - Annotations annotations; - Annotations getAnnotations() const override { return annotations; } - toString { return node_type_name() + " " + name; } -} - -class ParserException {} - -abstract Attached : IInstance, IAnnotated { - optional ID name; - optional Annotations annotations = Annotations::empty; - ID Name() const override { return name; } - virtual const char *kind() const = 0; - Type getType() const override { return Type_Unknown::get(); } - Annotations getAnnotations() const override { return annotations; } - virtual bool indexed() const { return false; } - Attached *clone_rename(const char *ext) const { - Attached *rv = clone(); - rv->name = ID(Util::SourceInfo(), rv->name.name + ext); - return rv; } - dbprint { out << node_type_name() << " " << name; } - toString { return node_type_name() + " " + name; } -} - -abstract Stateful : Attached { - ID table = {}; - bool direct = false; - bool saturating = false; - int instance_count = -1; - virtual bool indexed() const override { return !direct; } - int index_width() const; // width of index in bits -} - -abstract CounterOrMeter : Stateful { - CounterType type = CounterType::NONE; - void settype(cstring t) { - if (strcasecmp(t.c_str(), "packets") == 0) type = CounterType::PACKETS; - else if (strcasecmp(t.c_str(), "bytes") == 0) type = CounterType::BYTES; - else if (strcasecmp(t.c_str(), "packets_and_bytes") == 0 || - strcasecmp(t.c_str(), "PacketAndBytes") == 0) type = CounterType::BOTH; - else error(ErrorType::ERR_UNKNOWN, "%s: Unknown type %s", srcInfo, t); } // NOLINT -} - -class Counter : CounterOrMeter { - int max_width = -1; - int min_width = -1; - const char *kind() const override { return "stats"; } - const Type *getType() const override { return Type_Counter::get(); } -} - -class Meter : CounterOrMeter { - NullOK Expression result = nullptr; - NullOK Expression pre_color = nullptr; - ID implementation = {}; - const char *kind() const override { return "meter"; } - Type getType() const override { return Type_Meter::get(); } -} - -class Register : Stateful { - ID layout = {}; - int width = -1; - bool signed_ = false; - /* bool saturating = false; */ - const char *kind() const override { return "register"; } - Type getType() const override { return Type_Register::get(); } -} - -class PrimitiveAction {} - -class NameList { - safe_vector names = {}; - NameList(Util::SourceInfo si, cstring n) { names.emplace_back(si, n); } - NameList(Util::SourceInfo si, ID n) { names.emplace_back(si, n); } - dump_fields { out << "names=" << names; } -} - -class ActionArg : Expression { - cstring action_name; - ID name; - bool read = false; - bool write = false; - ActionArg { if (!srcInfo) srcInfo = name.srcInfo; } - dbprint{ out << action_name << ':' << name; } - toString{ return name.name; } -} - -// Represents a P4 v1.0 action -class ActionFunction : IAnnotated { - optional ID name; - inline Vector action = {}; - safe_vector args = {}; - optional Annotations annotations = Annotations::empty; - - Annotations getAnnotations() const override { return annotations; } - ActionArg arg(cstring n) const { - for (auto a : args) - if (a->name == n) - return a; - return nullptr; } - visit_children { - v.visit(action, "action"); - // DANGER -- visiting action first so type inferencing will push types to - // DANGER -- action args based on use. This is immoral. - for (auto &a : args) v.visit(a, "arg"); - v.visit(annotations, "annotations"); - } - toString { - return "action "_cs + name + " {\n"_cs + - cstring::join(action.begin(), action.end(), ";\n") + - " }"_cs; } -} - -class ActionProfile : Attached { - ID selector = {}; - safe_vector actions = {}; - int size = 0; - const char *kind() const override { return "action_profile"; } - bool indexed() const override { return true; } -} - -class ActionSelector : Attached { - ID key = {}; - NullOK FieldListCalculation key_fields = nullptr; - ID mode = {}; - ID type = {}; - const char *kind() const override { return "action_selector"; } -} - -class V1Table : IInstance, IAnnotated { - optional ID name; - NullOK Vector reads = 0; - safe_vector reads_types = {}; - int min_size = 0; - int max_size = 0; - int size = 0; - ID action_profile = {}; - safe_vector actions = {}; - ID default_action = {}; - bool default_action_is_const = false; - NullOK Vector default_action_args = 0; - inline TableProperties properties = {}; // non-standard properties - optional Annotations annotations = Annotations::empty; - - void addProperty(Property prop) { properties.push_back(prop); } - Annotations getAnnotations() const override { return annotations; } - toString { return node_type_name() + " " + name; } - ID Name() const override { return name; } - Type getType() const override { return Type_AnyTable::get(); } -} - -class V1Control : IAnnotated { - ID name; - Vector code; - Annotations annotations; - - V1Control(ID n) : name(n), code(new Vector()) {} - V1Control(Util::SourceInfo si, ID n) : Node(si), name(n), code(new Vector()) {} -#apply - Annotations getAnnotations() const override { return annotations; } - toString { return node_type_name() + " " + name; } -} - -class AttribLocal : Expression, IDeclaration { - ID name; - ID getName() const override { return name; } - dbprint { out << name; } -} - -class AttribLocals : ISimpleNamespace { - inline NameMap locals = {}; -#nodbprint - Util::Enumerator *getDeclarations() const override { - return locals.valueEnumerator()->as(); } - IDeclaration getDeclByName(cstring name) const override { return locals[name]; } - IDeclaration getDeclByName(std::string_view name) const override { return locals[cstring(name)]; } -} - -class Attribute : Declaration { - NullOK Type type = nullptr; - NullOK AttribLocals locals = nullptr; - bool optional = false; - dbprint { if (type) out << type << ' '; out << name; } -} - -class GlobalRef : Expression { - Node obj; // FIXME -- should be IInstance, but IRgen doesn't allow - // FIXME -- interface references directly in the IR - GlobalRef { type = obj->to()->getType(); } - validate { BUG_CHECK(obj->is(), "Invalid object %1%", obj); } - toString { return obj->to()->toString(); } - ID Name() const { return obj->to()->Name(); } - dbprint { out << obj->to()->Name(); } -} - -class AttributeRef : Expression { - cstring extern_name; - Type_Extern extern_type; - Attribute attrib; - AttributeRef { type = attrib->type; } - toString { return attrib->name; } - dbprint { out << attrib->name; } -} - -class V1Program { - inline NameMap scope; - -#noconstructor - explicit V1Program(); -#emit - template const T *get(cstring name) const { return scope.get(name); } -#end - void add(cstring name, const Node *n) { scope.add(name, n); } -#apply -} -/** @} *//* end group irdefs */ diff --git a/midend/removeComplexExpressions.cpp b/midend/removeComplexExpressions.cpp index dc23be3ff0..25bd9390dc 100644 --- a/midend/removeComplexExpressions.cpp +++ b/midend/removeComplexExpressions.cpp @@ -17,7 +17,6 @@ limitations under the License. #include "removeComplexExpressions.h" #include "frontends/p4/coreLibrary.h" -#include "frontends/p4/fromv1.0/v1model.h" #include "frontends/p4/methodInstance.h" namespace P4 { diff --git a/test/gtest/midend_pass.cpp b/test/gtest/midend_pass.cpp index 667727b01b..c5e44cd531 100644 --- a/test/gtest/midend_pass.cpp +++ b/test/gtest/midend_pass.cpp @@ -18,8 +18,8 @@ limitations under the License. #include "frontends/common/constantFolding.h" #include "frontends/common/options.h" +#include "frontends/p4-14/fromv1.0/v1model.h" #include "frontends/p4/evaluator/evaluator.h" -#include "frontends/p4/fromv1.0/v1model.h" #include "frontends/p4/moveDeclarations.h" #include "frontends/p4/simplify.h" #include "frontends/p4/simplifyParsers.h" diff --git a/testdata/p4_16_samples_outputs/issue2345-2-frontend.p4 b/testdata/p4_16_samples_outputs/issue2345-2-frontend.p4 index 5c2ca5181c..ea9dab48b7 100644 --- a/testdata/p4_16_samples_outputs/issue2345-2-frontend.p4 +++ b/testdata/p4_16_samples_outputs/issue2345-2-frontend.p4 @@ -24,21 +24,15 @@ parser p(packet_in pkt, out Headers hdr, inout Meta m, inout standard_metadata_t control ingress(inout Headers h, inout Meta m, inout standard_metadata_t sm) { @name("ingress.val_0") Headers val; - @name("ingress.val1_0") Headers val1; - @name("ingress.val1_1") Headers val1_2; @name("ingress.simple_action") action simple_action() { if (h.eth_hdr.eth_type == 16w1) { ; } else { h.eth_hdr.src_addr = 48w1; val = h; - val1 = val; - val1.eth_hdr.dst_addr = val1.eth_hdr.dst_addr + 48w3; - val = val1; + val.eth_hdr.dst_addr = val.eth_hdr.dst_addr + 48w3; val.eth_hdr.eth_type = 16w2; - val1_2 = val; - val1_2.eth_hdr.dst_addr = val1_2.eth_hdr.dst_addr + 48w3; - val = val1_2; + val.eth_hdr.dst_addr = val.eth_hdr.dst_addr + 48w3; h = val; h.eth_hdr.dst_addr = h.eth_hdr.dst_addr + 48w4; } diff --git a/testdata/p4_16_samples_outputs/issue2345-2-midend.p4 b/testdata/p4_16_samples_outputs/issue2345-2-midend.p4 index 03af45d38b..63afc28ce5 100644 --- a/testdata/p4_16_samples_outputs/issue2345-2-midend.p4 +++ b/testdata/p4_16_samples_outputs/issue2345-2-midend.p4 @@ -24,22 +24,16 @@ parser p(packet_in pkt, out Headers hdr, inout Meta m, inout standard_metadata_t control ingress(inout Headers h, inout Meta m, inout standard_metadata_t sm) { ethernet_t val_eth_hdr; - ethernet_t val1_eth_hdr; - ethernet_t val1_2_eth_hdr; @name("ingress.simple_action") action simple_action() { if (h.eth_hdr.eth_type == 16w1) { ; } else { h.eth_hdr.src_addr = 48w1; val_eth_hdr = h.eth_hdr; - val1_eth_hdr = h.eth_hdr; - val1_eth_hdr.dst_addr = val1_eth_hdr.dst_addr + 48w3; - val_eth_hdr = val1_eth_hdr; + val_eth_hdr.dst_addr = val_eth_hdr.dst_addr + 48w3; val_eth_hdr.eth_type = 16w2; - val1_2_eth_hdr = val_eth_hdr; - val1_2_eth_hdr.dst_addr = val1_2_eth_hdr.dst_addr + 48w3; - val_eth_hdr = val1_2_eth_hdr; - h.eth_hdr = val1_2_eth_hdr; + val_eth_hdr.dst_addr = val_eth_hdr.dst_addr + 48w3; + h.eth_hdr = val_eth_hdr; h.eth_hdr.dst_addr = h.eth_hdr.dst_addr + 48w4; } }