From 90a9a016bd635958e57043eeebbd46a86e773363 Mon Sep 17 00:00:00 2001 From: Fabian Ruffy <5960321+fruffy@users.noreply.github.com> Date: Thu, 19 Sep 2024 16:45:02 +0200 Subject: [PATCH 1/6] Remove the workaround that was required for MacOS CI installation. (#4921) Signed-off-by: fruffy --- .github/workflows/ci-test-mac.yml | 6 ------ 1 file changed, 6 deletions(-) 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) From d63f2e888f4c96c9f35fb8a73dd7d23906cf7337 Mon Sep 17 00:00:00 2001 From: Chris Dodd Date: Fri, 20 Sep 2024 16:56:58 +1200 Subject: [PATCH 2/6] Allow keywords to be used as annotation names. (#4897) Signed-off-by: Chris Dodd --- frontends/parsers/p4/p4parser.ypp | 66 ++++++++++++++++++++++++++++--- 1 file changed, 60 insertions(+), 6 deletions(-) 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; } From 6497f399a8fe559a69fd2702a3abb20c82e69016 Mon Sep 17 00:00:00 2001 From: Chris Dodd Date: Fri, 20 Sep 2024 16:57:46 +1200 Subject: [PATCH 3/6] Avoid copying out/inout args when inlining (#4877) - If the actual argument for an out or inout argument is local to the calling functions, we can use it directly in the inlined function instead of introducing extra copies in and out. Signed-off-by: Chris Dodd --- frontends/p4/functionsInlining.cpp | 74 +++++++++++++++---- frontends/p4/functionsInlining.h | 1 + frontends/p4/parameterSubstitution.h | 17 ++++- .../issue2345-2-frontend.p4 | 10 +-- .../issue2345-2-midend.p4 | 12 +-- 5 files changed, 80 insertions(+), 34 deletions(-) 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 AbstractInlinergetEnumerator()) - 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/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; } } From a9f0e67b5c7bf24ea441aa772fc0d7e19f3a45a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20=C5=A0till?= Date: Mon, 23 Sep 2024 21:26:23 +0200 Subject: [PATCH 4/6] Allow extending ToP4, clean its constructors (#4899) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Refactor ToP4 constructors Signed-off-by: Vladimir Still * Allow overriding ToP4 with its descendant in options Signed-off-by: Vladimir Still * Make ToP4's internals protected instead of private Signed-off-by: Vladimir Still * Fix format Signed-off-by: Vladimir Still * Use virtual function instead of factory Signed-off-by: Vladimir Still * Update frontends/common/parser_options.cpp Signed-off-by: Vladimír Štill --------- Signed-off-by: Vladimir Still Signed-off-by: Vladimír Štill --- frontends/common/parser_options.cpp | 20 +++++---- frontends/common/parser_options.h | 13 ++++-- frontends/p4/frontend.cpp | 3 +- frontends/p4/toP4/toP4.h | 68 ++++++++++++----------------- 4 files changed, 52 insertions(+), 52 deletions(-) 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/frontend.cpp b/frontends/p4/frontend.cpp index 35872e1ad7..fda3105eee 100644 --- a/frontends/p4/frontend.cpp +++ b/frontends/p4/frontend.cpp @@ -105,8 +105,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 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; From abf696e2b82278c20da9e6160c93a58f72cd7a6d Mon Sep 17 00:00:00 2001 From: Fabian Ruffy <5960321+fruffy@users.noreply.github.com> Date: Sat, 28 Sep 2024 01:12:01 +0200 Subject: [PATCH 5/6] Clean up the P4-14 dependent code. (#4925) Signed-off-by: fruffy --- backends/bmv2/common/controlFlowGraph.cpp | 2 +- backends/bmv2/common/extern.cpp | 2 +- backends/bmv2/common/helpers.h | 2 +- backends/bmv2/common/lower.cpp | 2 +- backends/bmv2/common/parser.cpp | 2 +- backends/bmv2/pna_nic/midend.cpp | 2 +- backends/bmv2/portable_common/midend.cpp | 2 +- backends/bmv2/psa_switch/midend.cpp | 2 +- backends/bmv2/simple_switch/midend.cpp | 2 +- backends/bmv2/simple_switch/simpleSwitch.cpp | 2 +- backends/bmv2/simple_switch/simpleSwitch.h | 2 +- backends/dpdk/midend.cpp | 2 +- backends/p4fmt/p4formatter.cpp | 7 +- backends/p4test/midend.cpp | 2 +- control-plane/p4RuntimeArchHandler.cpp | 2 +- control-plane/p4RuntimeArchStandard.cpp | 1 - control-plane/p4RuntimeArchStandard.h | 2 +- control-plane/p4RuntimeSerializer.cpp | 2 +- frontends/CMakeLists.txt | 15 +- frontends/common/parseInput.cpp | 2 +- frontends/common/parseInput.h | 2 +- .../{p4 => p4-14}/fromv1.0/converters.cpp | 0 frontends/{p4 => p4-14}/fromv1.0/converters.h | 6 +- .../fromv1.0/programStructure.cpp | 0 .../{p4 => p4-14}/fromv1.0/programStructure.h | 6 +- frontends/p4-14/fromv1.0/v1model.cpp | 11 + frontends/{p4 => p4-14}/fromv1.0/v1model.h | 24 +- frontends/p4-14/ir-v1.def | 483 ++++++++++++++++++ {ir => frontends/p4-14}/v1.cpp | 0 frontends/p4/frontend.cpp | 8 +- frontends/p4/getV1ModelVersion.h | 27 + frontends/p4/modelInstances.cpp | 28 - frontends/p4/toP4/toP4.cpp | 10 +- ir/CMakeLists.txt | 2 - ir/v1.def | 482 ----------------- midend/removeComplexExpressions.cpp | 1 - test/gtest/midend_pass.cpp | 2 +- 37 files changed, 571 insertions(+), 578 deletions(-) rename frontends/{p4 => p4-14}/fromv1.0/converters.cpp (100%) rename frontends/{p4 => p4-14}/fromv1.0/converters.h (99%) rename frontends/{p4 => p4-14}/fromv1.0/programStructure.cpp (100%) rename frontends/{p4 => p4-14}/fromv1.0/programStructure.h (98%) create mode 100644 frontends/p4-14/fromv1.0/v1model.cpp rename frontends/{p4 => p4-14}/fromv1.0/v1model.h (94%) rename {ir => frontends/p4-14}/v1.cpp (100%) create mode 100644 frontends/p4/getV1ModelVersion.h delete mode 100644 frontends/p4/modelInstances.cpp 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/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 fda3105eee..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" @@ -162,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), @@ -236,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), @@ -261,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/getV1ModelVersion.h b/frontends/p4/getV1ModelVersion.h new file mode 100644 index 0000000000..a1378f030d --- /dev/null +++ b/frontends/p4/getV1ModelVersion.h @@ -0,0 +1,27 @@ +#ifndef _FRONTENDS_P4_GETV1MODELVERSION_H_ +#define _FRONTENDS_P4_GETV1MODELVERSION_H_ + +#include "ir/ir.h" +#include "ir/visitor.h" + +namespace P4::P4V1 { + +/// 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") { + 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/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/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/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" From 7dec522a6b3233529b17aaba53a0a8511a9ea7db Mon Sep 17 00:00:00 2001 From: Chris Dodd Date: Sat, 28 Sep 2024 11:30:06 +1200 Subject: [PATCH 6/6] Fix Type_Indexed::at (#4927) Signed-off-by: Chris Dodd --- ir/type.def | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) 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;