From a87d0b8085a8bd9dadc37046e38297feb8960e0a Mon Sep 17 00:00:00 2001 From: Jed Liu Date: Wed, 18 Sep 2019 17:25:34 -0700 Subject: [PATCH 001/106] Implement IAnnotated where possible (#2035) * Add missing #include. * Implement IAnnotated where appropriate. --- backends/graphs/parsers.h | 1 + ir/v1.def | 30 ++++++++++++++++++++---------- 2 files changed, 21 insertions(+), 10 deletions(-) diff --git a/backends/graphs/parsers.h b/backends/graphs/parsers.h index 0e075571fe9..14fec822c8d 100644 --- a/backends/graphs/parsers.h +++ b/backends/graphs/parsers.h @@ -18,6 +18,7 @@ #ifndef _BACKENDS_GRAPHS_PARSERS_H_ #define _BACKENDS_GRAPHS_PARSERS_H_ +#include "frontends/common/resolveReferences/referenceMap.h" #include "ir/ir.h" #include "lib/cstring.h" #include "lib/nullstream.h" diff --git a/ir/v1.def b/ir/v1.def index 154aae01bb4..d5b1a2bbb80 100644 --- a/ir/v1.def +++ b/ir/v1.def @@ -78,12 +78,13 @@ class Type_AnyTable : Type_Base { dbprint { out << "table"; } } -abstract HeaderOrMetadata { +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; } @@ -215,23 +216,25 @@ class Primitive : Operation { precedence = DBPrint::Prec_Postfix; } -class FieldList { +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 { +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 { +class CalculatedField : IAnnotated { optional NullOK Expression field; class update_or_verify { Util::SourceInfo srcInfo; @@ -246,15 +249,17 @@ class CalculatedField { } 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 { +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; } } @@ -264,7 +269,7 @@ class CaseEntry { optional ID action; } -class V1Parser { +class V1Parser :IAnnotated { optional ID name; inline Vector stmts = {}; NullOK Vector select = nullptr; @@ -273,17 +278,19 @@ class V1Parser { 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 { +abstract Attached : IInstance, IAnnotated { optional ID name; optional Annotations annotations = Annotations::empty; cstring 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(); @@ -355,12 +362,13 @@ class ActionArg : Expression { } // Represents a P4 v1.0 action -class ActionFunction { +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) @@ -395,7 +403,7 @@ class ActionSelector : Attached { const char *kind() const override { return "action_selector"; } } -class V1Table : IInstance { +class V1Table : IInstance, IAnnotated { optional ID name; NullOK Vector reads = 0; safe_vector reads_types = {}; @@ -411,12 +419,13 @@ class V1Table : IInstance { 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; } cstring Name() const override { return name; } Type getType() const override { return Type_AnyTable::get(); } } -class V1Control { +class V1Control : IAnnotated { ID name; Vector code; Annotations annotations; @@ -424,6 +433,7 @@ class V1Control { 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; } } From 7b1733b7ffb09fb616e1d32de4020bb026a39d23 Mon Sep 17 00:00:00 2001 From: Mihai Budiu Date: Thu, 19 Sep 2019 09:47:48 -0700 Subject: [PATCH 002/106] Require list to come first; fix unified build (#2034) --- backends/bmv2/CMakeLists.txt | 4 ++-- backends/ebpf/CMakeLists.txt | 2 +- frontends/p4/typeChecking/typeChecker.cpp | 5 ++++ testdata/p4_16_errors/issue2033.p4 | 20 ++++++++++++++++ testdata/p4_16_errors_outputs/issue2033.p4 | 24 +++++++++++++++++++ .../p4_16_errors_outputs/issue2033.p4-stderr | 3 +++ 6 files changed, 55 insertions(+), 3 deletions(-) create mode 100644 testdata/p4_16_errors/issue2033.p4 create mode 100644 testdata/p4_16_errors_outputs/issue2033.p4 create mode 100644 testdata/p4_16_errors_outputs/issue2033.p4-stderr diff --git a/backends/bmv2/CMakeLists.txt b/backends/bmv2/CMakeLists.txt index 1d7b0fbea34..0b92e83b1d1 100644 --- a/backends/bmv2/CMakeLists.txt +++ b/backends/bmv2/CMakeLists.txt @@ -88,13 +88,13 @@ build_unified(BMV2_BACKEND_COMMON_SRCS) add_library(bmv2backend ${BMV2_BACKEND_COMMON_SRCS}) add_dependencies(bmv2backend genIR frontend) -build_unified(BMV2_SIMPLE_SWiTCH_SRCS) +build_unified(BMV2_SIMPLE_SWITCH_SRCS) add_executable(p4c-bm2-ss ${BMV2_SIMPLE_SWITCH_SRCS}) target_link_libraries (p4c-bm2-ss bmv2backend ${P4C_LIBRARIES} ${P4C_LIB_DEPS}) install(TARGETS p4c-bm2-ss RUNTIME DESTINATION ${P4C_RUNTIME_OUTPUT_DIRECTORY}) -build_unified(BMV2_PSA_SWiTCH_SRCS) +build_unified(BMV2_PSA_SWITCH_SRCS) add_executable(p4c-bm2-psa ${BMV2_PSA_SWITCH_SRCS}) target_link_libraries (p4c-bm2-psa bmv2backend ${P4C_LIBRARIES} ${P4C_LIB_DEPS}) install(TARGETS p4c-bm2-psa RUNTIME DESTINATION ${P4C_RUNTIME_OUTPUT_DIRECTORY}) diff --git a/backends/ebpf/CMakeLists.txt b/backends/ebpf/CMakeLists.txt index cbd86b88b1f..523f269efff 100644 --- a/backends/ebpf/CMakeLists.txt +++ b/backends/ebpf/CMakeLists.txt @@ -54,7 +54,7 @@ add_cpplint_files(${CMAKE_CURRENT_SOURCE_DIR} "${P4C_EBPF_SRCS};${P4C_EBPF_HDRS} set (P4C_EBPF_DIST_HEADERS p4include/ebpf_model.p4) -build_unified(P4C_EBPF_SRCS ALL) +build_unified(P4C_EBPF_SRCS) add_executable(p4c-ebpf ${P4C_EBPF_SRCS}) target_link_libraries (p4c-ebpf ${P4C_LIBRARIES} ${P4C_LIB_DEPS}) add_dependencies(p4c-ebpf genIR frontend) diff --git a/frontends/p4/typeChecking/typeChecker.cpp b/frontends/p4/typeChecking/typeChecker.cpp index 840295ce85d..d2429b89e56 100644 --- a/frontends/p4/typeChecking/typeChecker.cpp +++ b/frontends/p4/typeChecking/typeChecker.cpp @@ -3451,6 +3451,11 @@ const IR::ActionListElement* TypeInference::validateActionInitializer( // the actions list. auto actionListCall = elem->expression->to(); CHECK_NULL(actionListCall); + auto type = typeMap->getType(actionListCall->method); + if (type == nullptr) { + typeError("%1%: action invocation should be after the `actions` list", actionCall); + return nullptr; + } if (actionListCall->arguments->size() > call->arguments->size()) { typeError("%1%: not enough arguments", call); diff --git a/testdata/p4_16_errors/issue2033.p4 b/testdata/p4_16_errors/issue2033.p4 new file mode 100644 index 00000000000..5714af42862 --- /dev/null +++ b/testdata/p4_16_errors/issue2033.p4 @@ -0,0 +1,20 @@ +match_kind { exact, ternary, lpm } +struct Header_t { + bit<8> fieldname; +} + +control ingress(Header_t h) { + action nop() { } + + table badtable { + default_action = nop; + + actions = { + nop; + } + } + + apply { + badtable.apply(); + } +} \ No newline at end of file diff --git a/testdata/p4_16_errors_outputs/issue2033.p4 b/testdata/p4_16_errors_outputs/issue2033.p4 new file mode 100644 index 00000000000..e64c4e6e355 --- /dev/null +++ b/testdata/p4_16_errors_outputs/issue2033.p4 @@ -0,0 +1,24 @@ +match_kind { + exact, + ternary, + lpm +} + +struct Header_t { + bit<8> fieldname; +} + +control ingress(Header_t h) { + action nop() { + } + table badtable { + default_action = nop; + actions = { + nop; + } + } + apply { + badtable.apply(); + } +} + diff --git a/testdata/p4_16_errors_outputs/issue2033.p4-stderr b/testdata/p4_16_errors_outputs/issue2033.p4-stderr new file mode 100644 index 00000000000..7eeb6c775a5 --- /dev/null +++ b/testdata/p4_16_errors_outputs/issue2033.p4-stderr @@ -0,0 +1,3 @@ +issue2033.p4(10): [--Werror=type-error] error: nop: action invocation should be after the `actions` list + default_action = nop; + ^^^ From de77fd172d33c07af57f2b633532b5d37ff05c3d Mon Sep 17 00:00:00 2001 From: Sylvain Afchain Date: Mon, 30 Sep 2019 17:25:12 +0200 Subject: [PATCH 003/106] Add a add function to eBPF CounterArray (#2011) This aims to be able to increment counters based on packet information. --- backends/ebpf/ebpfModel.h | 3 +- backends/ebpf/ebpfTable.cpp | 67 ++++++++++++++++ backends/ebpf/ebpfTable.h | 1 + backends/ebpf/p4include/ebpf_model.p4 | 2 + backends/ebpf/runtime/ebpf_common.h | 2 +- testdata/p4_16_samples/count_add_ebpf.p4 | 62 +++++++++++++++ .../count_add_ebpf-first.p4 | 59 ++++++++++++++ .../count_add_ebpf-frontend.p4 | 59 ++++++++++++++ .../count_add_ebpf-midend.p4 | 77 +++++++++++++++++++ .../p4_16_samples_outputs/count_add_ebpf.p4 | 59 ++++++++++++++ .../count_add_ebpf.p4-stderr | 0 11 files changed, 389 insertions(+), 2 deletions(-) create mode 100644 testdata/p4_16_samples/count_add_ebpf.p4 create mode 100644 testdata/p4_16_samples_outputs/count_add_ebpf-first.p4 create mode 100644 testdata/p4_16_samples_outputs/count_add_ebpf-frontend.p4 create mode 100644 testdata/p4_16_samples_outputs/count_add_ebpf-midend.p4 create mode 100644 testdata/p4_16_samples_outputs/count_add_ebpf.p4 create mode 100644 testdata/p4_16_samples_outputs/count_add_ebpf.p4-stderr diff --git a/backends/ebpf/ebpfModel.h b/backends/ebpf/ebpfModel.h index ddb98fdf891..2b9868fe62e 100644 --- a/backends/ebpf/ebpfModel.h +++ b/backends/ebpf/ebpfModel.h @@ -33,9 +33,10 @@ struct TableImpl_Model : public ::Model::Extern_Model { struct CounterArray_Model : public ::Model::Extern_Model { CounterArray_Model() : Extern_Model("CounterArray"), - increment("increment"), + increment("increment"), add("add"), max_index("max_index"), sparse("sparse") {} ::Model::Elem increment; + ::Model::Elem add; ::Model::Elem max_index; ::Model::Elem sparse; }; diff --git a/backends/ebpf/ebpfTable.cpp b/backends/ebpf/ebpfTable.cpp index ace72aacaa6..8c93751941c 100644 --- a/backends/ebpf/ebpfTable.cpp +++ b/backends/ebpf/ebpfTable.cpp @@ -571,12 +571,79 @@ void EBPFCounterTable::emitCounterIncrement(CodeBuilder* builder, builder->decreaseIndent(); } +void EBPFCounterTable::emitCounterAdd(CodeBuilder* builder, + const IR::MethodCallExpression *expression) { + cstring keyName = program->refMap->newName("key"); + cstring valueName = program->refMap->newName("value"); + cstring incName = program->refMap->newName("inc"); + + builder->emitIndent(); + builder->append(valueTypeName); + builder->spc(); + builder->append("*"); + builder->append(valueName); + builder->endOfStatement(true); + + builder->emitIndent(); + builder->append(valueTypeName); + builder->spc(); + builder->appendLine("init_val = 1;"); + + builder->emitIndent(); + builder->append(keyTypeName); + builder->spc(); + builder->append(keyName); + builder->append(" = "); + + BUG_CHECK(expression->arguments->size() == 2, "Expected just 2 arguments for %1%", expression); + auto index = expression->arguments->at(0); + + codeGen->visit(index); + builder->endOfStatement(true); + + builder->emitIndent(); + builder->append(valueTypeName); + builder->spc(); + builder->append(incName); + builder->append(" = "); + + auto inc = expression->arguments->at(1); + + codeGen->visit(inc); + builder->endOfStatement(true); + + builder->emitIndent(); + builder->target->emitTableLookup(builder, dataMapName, keyName, valueName); + builder->endOfStatement(true); + + builder->emitIndent(); + builder->appendFormat("if (%s != NULL)", valueName.c_str()); + builder->newline(); + builder->increaseIndent(); + builder->emitIndent(); + builder->appendFormat("__sync_fetch_and_add(%s, %s);", valueName.c_str(), incName.c_str()); + builder->newline(); + builder->decreaseIndent(); + + builder->emitIndent(); + builder->appendLine("else"); + builder->increaseIndent(); + builder->emitIndent(); + builder->target->emitTableUpdate(builder, dataMapName, keyName, "init_val"); + builder->newline(); + builder->decreaseIndent(); +} + void EBPFCounterTable::emitMethodInvocation(CodeBuilder* builder, const P4::ExternMethod* method) { if (method->method->name.name == program->model.counterArray.increment.name) { emitCounterIncrement(builder, method->expr); return; } + if (method->method->name.name == program->model.counterArray.add.name) { + emitCounterAdd(builder, method->expr); + return; + } ::error(ErrorType::ERR_UNSUPPORTED, "Unexpected method for %2%", method->expr, program->model.counterArray.name); } diff --git a/backends/ebpf/ebpfTable.h b/backends/ebpf/ebpfTable.h index ea1f3114ada..3185b109001 100644 --- a/backends/ebpf/ebpfTable.h +++ b/backends/ebpf/ebpfTable.h @@ -74,6 +74,7 @@ class EBPFCounterTable final : public EBPFTableBase { void emitTypes(CodeBuilder*); void emitInstance(CodeBuilder* builder); void emitCounterIncrement(CodeBuilder* builder, const IR::MethodCallExpression* expression); + void emitCounterAdd(CodeBuilder* builder, const IR::MethodCallExpression* expression); void emitMethodInvocation(CodeBuilder* builder, const P4::ExternMethod* method); }; diff --git a/backends/ebpf/p4include/ebpf_model.p4 b/backends/ebpf/p4include/ebpf_model.p4 index f0d9d4f1656..f9b4e1ef737 100644 --- a/backends/ebpf/p4include/ebpf_model.p4 +++ b/backends/ebpf/p4include/ebpf_model.p4 @@ -33,6 +33,8 @@ extern CounterArray { CounterArray(bit<32> max_index, bool sparse); /** Increment counter with specified index. */ void increment(in bit<32> index); + /** Add value to counter with specified index. */ + void add(in bit<32> index, in bit<32> value); } /* diff --git a/backends/ebpf/runtime/ebpf_common.h b/backends/ebpf/runtime/ebpf_common.h index fb912e1bbcd..850ef95e49f 100644 --- a/backends/ebpf/runtime/ebpf_common.h +++ b/backends/ebpf/runtime/ebpf_common.h @@ -92,4 +92,4 @@ typedef unsigned long long u64; #define load_byte(data, b) (*(((u8*)(data)) + (b))) #define load_half(data, b) __constant_ntohs(*(u16 *)((u8*)(data) + (b))) #define load_word(data, b) __constant_ntohl(*(u32 *)((u8*)(data) + (b))) -#define load_dword(data, b) __constant_ntohll(*(u64 *)((u8*)(data) + (b))) \ No newline at end of file +#define load_dword(data, b) __constant_ntohll(*(u64 *)((u8*)(data) + (b))) diff --git a/testdata/p4_16_samples/count_add_ebpf.p4 b/testdata/p4_16_samples/count_add_ebpf.p4 new file mode 100644 index 00000000000..3a884336692 --- /dev/null +++ b/testdata/p4_16_samples/count_add_ebpf.p4 @@ -0,0 +1,62 @@ +/* +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 +#include + +#include "ebpf_headers.p4" + +struct Headers_t +{ + Ethernet_h ethernet; + IPv4_h ipv4; +} + +parser prs(packet_in p, out Headers_t headers) +{ + state start + { + p.extract(headers.ethernet); + transition select(headers.ethernet.etherType) + { + 16w0x800 : ip; + default : reject; + } + } + + state ip + { + p.extract(headers.ipv4); + transition accept; + } +} + +control pipe(inout Headers_t headers, out bool pass) +{ + CounterArray(32w10, true) counters; + + apply { + if (headers.ipv4.isValid()) + { + counters.add((bit<32>)headers.ipv4.dstAddr, (bit<32>)headers.ipv4.totalLen); + pass = true; + } + else + pass = false; + } +} + +ebpfFilter(prs(), pipe()) main; diff --git a/testdata/p4_16_samples_outputs/count_add_ebpf-first.p4 b/testdata/p4_16_samples_outputs/count_add_ebpf-first.p4 new file mode 100644 index 00000000000..a38f33e939f --- /dev/null +++ b/testdata/p4_16_samples_outputs/count_add_ebpf-first.p4 @@ -0,0 +1,59 @@ +#include +#include + +@ethernetaddress typedef bit<48> EthernetAddress; +@ipv4address typedef bit<32> IPv4Address; +header Ethernet_h { + EthernetAddress dstAddr; + EthernetAddress srcAddr; + bit<16> etherType; +} + +header IPv4_h { + bit<4> version; + bit<4> ihl; + bit<8> diffserv; + bit<16> totalLen; + bit<16> identification; + bit<3> flags; + bit<13> fragOffset; + bit<8> ttl; + bit<8> protocol; + bit<16> hdrChecksum; + IPv4Address srcAddr; + IPv4Address dstAddr; +} + +struct Headers_t { + Ethernet_h ethernet; + IPv4_h ipv4; +} + +parser prs(packet_in p, out Headers_t headers) { + state start { + p.extract(headers.ethernet); + transition select(headers.ethernet.etherType) { + 16w0x800: ip; + default: reject; + } + } + state ip { + p.extract(headers.ipv4); + transition accept; + } +} + +control pipe(inout Headers_t headers, out bool pass) { + CounterArray(32w10, true) counters; + apply { + if (headers.ipv4.isValid()) { + counters.add(headers.ipv4.dstAddr, (bit<32>)headers.ipv4.totalLen); + pass = true; + } else { + pass = false; + } + } +} + +ebpfFilter(prs(), pipe()) main; + diff --git a/testdata/p4_16_samples_outputs/count_add_ebpf-frontend.p4 b/testdata/p4_16_samples_outputs/count_add_ebpf-frontend.p4 new file mode 100644 index 00000000000..af78842a7cc --- /dev/null +++ b/testdata/p4_16_samples_outputs/count_add_ebpf-frontend.p4 @@ -0,0 +1,59 @@ +#include +#include + +@ethernetaddress typedef bit<48> EthernetAddress; +@ipv4address typedef bit<32> IPv4Address; +header Ethernet_h { + EthernetAddress dstAddr; + EthernetAddress srcAddr; + bit<16> etherType; +} + +header IPv4_h { + bit<4> version; + bit<4> ihl; + bit<8> diffserv; + bit<16> totalLen; + bit<16> identification; + bit<3> flags; + bit<13> fragOffset; + bit<8> ttl; + bit<8> protocol; + bit<16> hdrChecksum; + IPv4Address srcAddr; + IPv4Address dstAddr; +} + +struct Headers_t { + Ethernet_h ethernet; + IPv4_h ipv4; +} + +parser prs(packet_in p, out Headers_t headers) { + state start { + p.extract(headers.ethernet); + transition select(headers.ethernet.etherType) { + 16w0x800: ip; + default: reject; + } + } + state ip { + p.extract(headers.ipv4); + transition accept; + } +} + +control pipe(inout Headers_t headers, out bool pass) { + @name("pipe.counters") CounterArray(32w10, true) counters_0; + apply { + if (headers.ipv4.isValid()) { + counters_0.add(headers.ipv4.dstAddr, (bit<32>)headers.ipv4.totalLen); + pass = true; + } else { + pass = false; + } + } +} + +ebpfFilter(prs(), pipe()) main; + diff --git a/testdata/p4_16_samples_outputs/count_add_ebpf-midend.p4 b/testdata/p4_16_samples_outputs/count_add_ebpf-midend.p4 new file mode 100644 index 00000000000..efd70c62246 --- /dev/null +++ b/testdata/p4_16_samples_outputs/count_add_ebpf-midend.p4 @@ -0,0 +1,77 @@ +#include +#include + +@ethernetaddress typedef bit<48> EthernetAddress; +@ipv4address typedef bit<32> IPv4Address; +header Ethernet_h { + EthernetAddress dstAddr; + EthernetAddress srcAddr; + bit<16> etherType; +} + +header IPv4_h { + bit<4> version; + bit<4> ihl; + bit<8> diffserv; + bit<16> totalLen; + bit<16> identification; + bit<3> flags; + bit<13> fragOffset; + bit<8> ttl; + bit<8> protocol; + bit<16> hdrChecksum; + IPv4Address srcAddr; + IPv4Address dstAddr; +} + +struct Headers_t { + Ethernet_h ethernet; + IPv4_h ipv4; +} + +parser prs(packet_in p, out Headers_t headers) { + state start { + p.extract(headers.ethernet); + transition select(headers.ethernet.etherType) { + 16w0x800: ip; + default: reject; + } + } + state ip { + p.extract(headers.ipv4); + transition accept; + } +} + +control pipe(inout Headers_t headers, out bool pass) { + @name("pipe.counters") CounterArray(32w10, true) counters_0; + @hidden action count_add_ebpf54() { + counters_0.add(headers.ipv4.dstAddr, (bit<32>)headers.ipv4.totalLen); + pass = true; + } + @hidden action count_add_ebpf58() { + pass = false; + } + @hidden table tbl_count_add_ebpf54 { + actions = { + count_add_ebpf54(); + } + const default_action = count_add_ebpf54(); + } + @hidden table tbl_count_add_ebpf58 { + actions = { + count_add_ebpf58(); + } + const default_action = count_add_ebpf58(); + } + apply { + if (headers.ipv4.isValid()) { + tbl_count_add_ebpf54.apply(); + } else { + tbl_count_add_ebpf58.apply(); + } + } +} + +ebpfFilter(prs(), pipe()) main; + diff --git a/testdata/p4_16_samples_outputs/count_add_ebpf.p4 b/testdata/p4_16_samples_outputs/count_add_ebpf.p4 new file mode 100644 index 00000000000..1bffbf2224d --- /dev/null +++ b/testdata/p4_16_samples_outputs/count_add_ebpf.p4 @@ -0,0 +1,59 @@ +#include +#include + +@ethernetaddress typedef bit<48> EthernetAddress; +@ipv4address typedef bit<32> IPv4Address; +header Ethernet_h { + EthernetAddress dstAddr; + EthernetAddress srcAddr; + bit<16> etherType; +} + +header IPv4_h { + bit<4> version; + bit<4> ihl; + bit<8> diffserv; + bit<16> totalLen; + bit<16> identification; + bit<3> flags; + bit<13> fragOffset; + bit<8> ttl; + bit<8> protocol; + bit<16> hdrChecksum; + IPv4Address srcAddr; + IPv4Address dstAddr; +} + +struct Headers_t { + Ethernet_h ethernet; + IPv4_h ipv4; +} + +parser prs(packet_in p, out Headers_t headers) { + state start { + p.extract(headers.ethernet); + transition select(headers.ethernet.etherType) { + 16w0x800: ip; + default: reject; + } + } + state ip { + p.extract(headers.ipv4); + transition accept; + } +} + +control pipe(inout Headers_t headers, out bool pass) { + CounterArray(32w10, true) counters; + apply { + if (headers.ipv4.isValid()) { + counters.add((bit<32>)headers.ipv4.dstAddr, (bit<32>)headers.ipv4.totalLen); + pass = true; + } else { + pass = false; + } + } +} + +ebpfFilter(prs(), pipe()) main; + diff --git a/testdata/p4_16_samples_outputs/count_add_ebpf.p4-stderr b/testdata/p4_16_samples_outputs/count_add_ebpf.p4-stderr new file mode 100644 index 00000000000..e69de29bb2d From 9ba477d12c5c6c72b9508b19ab0b11dbf8d5d690 Mon Sep 17 00:00:00 2001 From: Han Wang Date: Mon, 30 Sep 2019 13:48:04 -0700 Subject: [PATCH 004/106] fix type inference for modify_conditionally primitive (#2039) --- ir/v1.cpp | 2 +- .../p4_14_samples/modify_conditionally.p4 | 50 +++++++++++ .../modify_conditionally-first.p4 | 77 +++++++++++++++++ .../modify_conditionally-frontend.p4 | 84 +++++++++++++++++++ .../modify_conditionally-midend.p4 | 81 ++++++++++++++++++ .../modify_conditionally.p4 | 75 +++++++++++++++++ .../modify_conditionally.p4-stderr | 0 7 files changed, 368 insertions(+), 1 deletion(-) create mode 100644 testdata/p4_14_samples/modify_conditionally.p4 create mode 100644 testdata/p4_14_samples_outputs/modify_conditionally-first.p4 create mode 100644 testdata/p4_14_samples_outputs/modify_conditionally-frontend.p4 create mode 100644 testdata/p4_14_samples_outputs/modify_conditionally-midend.p4 create mode 100644 testdata/p4_14_samples_outputs/modify_conditionally.p4 create mode 100644 testdata/p4_14_samples_outputs/modify_conditionally.p4-stderr diff --git a/ir/v1.cpp b/ir/v1.cpp index a6526109648..adaa4e63506 100644 --- a/ir/v1.cpp +++ b/ir/v1.cpp @@ -157,7 +157,7 @@ const IR::Type *IR::Primitive::inferOperandType(int operand) const { if ((name == "execute") && operand == 2) return IR::Type::Bits::get(32); if (name == "modify_field_conditionally" && operand == 1) - return IR::Type::Boolean::get(); + return IR::Type::Bits::get(1); if (name == "shift_left" && operand == 1) { if (operands.at(0)->type->width_bits() > operands.at(1)->type->width_bits()) return operands.at(0)->type; diff --git a/testdata/p4_14_samples/modify_conditionally.p4 b/testdata/p4_14_samples/modify_conditionally.p4 new file mode 100644 index 00000000000..62fb5ea2987 --- /dev/null +++ b/testdata/p4_14_samples/modify_conditionally.p4 @@ -0,0 +1,50 @@ +header_type ethernet_t { + fields { + dstAddr : 48; + srcAddr : 48; + etherType : 16; + } +} + +header ethernet_t ethernet; + +parser start { + extract(ethernet); + return ingress; +} + +header_type metadata_global_t{ + fields{ + do_goto_table: 1; + goto_table_id: 8; + } +} + +metadata metadata_global_t metadata_global; + +action table0_actionlist( + do_goto_table, goto_table_id +) +{ + modify_field( metadata_global.do_goto_table, do_goto_table ); + modify_field_conditionally( metadata_global.goto_table_id, do_goto_table, goto_table_id ); +} + +table table0 { + reads { + ethernet.etherType:ternary; + } + actions { + table0_actionlist; + } + size: 2000; +} + +control ingress{ + if(metadata_global.goto_table_id == 0) { + apply( table0 ); + } +} + +control egress{ +} diff --git a/testdata/p4_14_samples_outputs/modify_conditionally-first.p4 b/testdata/p4_14_samples_outputs/modify_conditionally-first.p4 new file mode 100644 index 00000000000..ac9de9c63a5 --- /dev/null +++ b/testdata/p4_14_samples_outputs/modify_conditionally-first.p4 @@ -0,0 +1,77 @@ +#include +#include + +struct metadata_global_t { + bit<1> do_goto_table; + bit<8> goto_table_id; +} + +header ethernet_t { + bit<48> dstAddr; + bit<48> srcAddr; + bit<16> etherType; +} + +struct metadata { + @name(".metadata_global") + metadata_global_t metadata_global; +} + +struct headers { + @name(".ethernet") + ethernet_t ethernet; +} + +parser ParserImpl(packet_in packet, out headers hdr, inout metadata meta, inout standard_metadata_t standard_metadata) { + @name(".start") state start { + packet.extract(hdr.ethernet); + transition accept; + } +} + +control egress(inout headers hdr, inout metadata meta, inout standard_metadata_t standard_metadata) { + apply { + } +} + +control ingress(inout headers hdr, inout metadata meta, inout standard_metadata_t standard_metadata) { + @name(".table0_actionlist") action table0_actionlist(bit<1> do_goto_table, bit<8> goto_table_id) { + meta.metadata_global.do_goto_table = do_goto_table; + meta.metadata_global.goto_table_id = (do_goto_table != 1w0 ? goto_table_id : meta.metadata_global.goto_table_id); + } + @name(".table0") table table0 { + actions = { + table0_actionlist(); + @defaultonly NoAction(); + } + key = { + hdr.ethernet.etherType: ternary @name("ethernet.etherType") ; + } + size = 2000; + default_action = NoAction(); + } + apply { + if (meta.metadata_global.goto_table_id == 8w0) { + table0.apply(); + } + } +} + +control DeparserImpl(packet_out packet, in headers hdr) { + apply { + packet.emit(hdr.ethernet); + } +} + +control verifyChecksum(inout headers hdr, inout metadata meta) { + apply { + } +} + +control computeChecksum(inout headers hdr, inout metadata meta) { + apply { + } +} + +V1Switch(ParserImpl(), verifyChecksum(), ingress(), egress(), computeChecksum(), DeparserImpl()) main; + diff --git a/testdata/p4_14_samples_outputs/modify_conditionally-frontend.p4 b/testdata/p4_14_samples_outputs/modify_conditionally-frontend.p4 new file mode 100644 index 00000000000..a595eee4843 --- /dev/null +++ b/testdata/p4_14_samples_outputs/modify_conditionally-frontend.p4 @@ -0,0 +1,84 @@ +#include +#include + +struct metadata_global_t { + bit<1> do_goto_table; + bit<8> goto_table_id; +} + +header ethernet_t { + bit<48> dstAddr; + bit<48> srcAddr; + bit<16> etherType; +} + +struct metadata { + @name(".metadata_global") + metadata_global_t metadata_global; +} + +struct headers { + @name(".ethernet") + ethernet_t ethernet; +} + +parser ParserImpl(packet_in packet, out headers hdr, inout metadata meta, inout standard_metadata_t standard_metadata) { + @name(".start") state start { + packet.extract(hdr.ethernet); + transition accept; + } +} + +control egress(inout headers hdr, inout metadata meta, inout standard_metadata_t standard_metadata) { + apply { + } +} + +control ingress(inout headers hdr, inout metadata meta, inout standard_metadata_t standard_metadata) { + @name(".NoAction") action NoAction_0() { + } + bit<8> tmp; + @name(".table0_actionlist") action table0_actionlist(bit<1> do_goto_table, bit<8> goto_table_id) { + meta.metadata_global.do_goto_table = do_goto_table; + if (do_goto_table != 1w0) { + tmp = goto_table_id; + } else { + tmp = meta.metadata_global.goto_table_id; + } + } + @name(".table0") table table0_0 { + actions = { + table0_actionlist(); + @defaultonly NoAction_0(); + } + key = { + hdr.ethernet.etherType: ternary @name("ethernet.etherType") ; + } + size = 2000; + default_action = NoAction_0(); + } + apply { + if (meta.metadata_global.goto_table_id == 8w0) { + table0_0.apply(); + } + } +} + +control DeparserImpl(packet_out packet, in headers hdr) { + apply { + packet.emit(hdr.ethernet); + } +} + +control verifyChecksum(inout headers hdr, inout metadata meta) { + apply { + } +} + +control computeChecksum(inout headers hdr, inout metadata meta) { + apply { + } +} + +V1Switch(ParserImpl(), verifyChecksum(), ingress(), egress(), computeChecksum(), DeparserImpl()) main; + diff --git a/testdata/p4_14_samples_outputs/modify_conditionally-midend.p4 b/testdata/p4_14_samples_outputs/modify_conditionally-midend.p4 new file mode 100644 index 00000000000..47ae69c7531 --- /dev/null +++ b/testdata/p4_14_samples_outputs/modify_conditionally-midend.p4 @@ -0,0 +1,81 @@ +#include +#include + +struct metadata_global_t { + bit<1> do_goto_table; + bit<8> goto_table_id; +} + +header ethernet_t { + bit<48> dstAddr; + bit<48> srcAddr; + bit<16> etherType; +} + +struct metadata { + bit<1> _metadata_global_do_goto_table0; + bit<8> _metadata_global_goto_table_id1; +} + +struct headers { + @name(".ethernet") + ethernet_t ethernet; +} + +parser ParserImpl(packet_in packet, out headers hdr, inout metadata meta, inout standard_metadata_t standard_metadata) { + @name(".start") state start { + packet.extract(hdr.ethernet); + transition accept; + } +} + +control egress(inout headers hdr, inout metadata meta, inout standard_metadata_t standard_metadata) { + apply { + } +} + +control ingress(inout headers hdr, inout metadata meta, inout standard_metadata_t standard_metadata) { + bit<8> tmp; + @name(".NoAction") action NoAction_0() { + } + @name(".table0_actionlist") action table0_actionlist(bit<1> do_goto_table, bit<8> goto_table_id) { + meta._metadata_global_do_goto_table0 = do_goto_table; + tmp = (do_goto_table != 1w0 ? goto_table_id : tmp); + tmp = (!(do_goto_table != 1w0) ? meta._metadata_global_goto_table_id1 : tmp); + } + @name(".table0") table table0_0 { + actions = { + table0_actionlist(); + @defaultonly NoAction_0(); + } + key = { + hdr.ethernet.etherType: ternary @name("ethernet.etherType") ; + } + size = 2000; + default_action = NoAction_0(); + } + apply { + if (meta._metadata_global_goto_table_id1 == 8w0) { + table0_0.apply(); + } + } +} + +control DeparserImpl(packet_out packet, in headers hdr) { + apply { + packet.emit(hdr.ethernet); + } +} + +control verifyChecksum(inout headers hdr, inout metadata meta) { + apply { + } +} + +control computeChecksum(inout headers hdr, inout metadata meta) { + apply { + } +} + +V1Switch(ParserImpl(), verifyChecksum(), ingress(), egress(), computeChecksum(), DeparserImpl()) main; + diff --git a/testdata/p4_14_samples_outputs/modify_conditionally.p4 b/testdata/p4_14_samples_outputs/modify_conditionally.p4 new file mode 100644 index 00000000000..1a08305715b --- /dev/null +++ b/testdata/p4_14_samples_outputs/modify_conditionally.p4 @@ -0,0 +1,75 @@ +#include +#include + +struct metadata_global_t { + bit<1> do_goto_table; + bit<8> goto_table_id; +} + +header ethernet_t { + bit<48> dstAddr; + bit<48> srcAddr; + bit<16> etherType; +} + +struct metadata { + @name(".metadata_global") + metadata_global_t metadata_global; +} + +struct headers { + @name(".ethernet") + ethernet_t ethernet; +} + +parser ParserImpl(packet_in packet, out headers hdr, inout metadata meta, inout standard_metadata_t standard_metadata) { + @name(".start") state start { + packet.extract(hdr.ethernet); + transition accept; + } +} + +control egress(inout headers hdr, inout metadata meta, inout standard_metadata_t standard_metadata) { + apply { + } +} + +control ingress(inout headers hdr, inout metadata meta, inout standard_metadata_t standard_metadata) { + @name(".table0_actionlist") action table0_actionlist(bit<1> do_goto_table, bit<8> goto_table_id) { + meta.metadata_global.do_goto_table = do_goto_table; + meta.metadata_global.goto_table_id = (do_goto_table != 0 ? goto_table_id : meta.metadata_global.goto_table_id); + } + @name(".table0") table table0 { + actions = { + table0_actionlist; + } + key = { + hdr.ethernet.etherType: ternary; + } + size = 2000; + } + apply { + if (meta.metadata_global.goto_table_id == 8w0) { + table0.apply(); + } + } +} + +control DeparserImpl(packet_out packet, in headers hdr) { + apply { + packet.emit(hdr.ethernet); + } +} + +control verifyChecksum(inout headers hdr, inout metadata meta) { + apply { + } +} + +control computeChecksum(inout headers hdr, inout metadata meta) { + apply { + } +} + +V1Switch(ParserImpl(), verifyChecksum(), ingress(), egress(), computeChecksum(), DeparserImpl()) main; + diff --git a/testdata/p4_14_samples_outputs/modify_conditionally.p4-stderr b/testdata/p4_14_samples_outputs/modify_conditionally.p4-stderr new file mode 100644 index 00000000000..e69de29bb2d From f7589a8eb200f9d8f7f9c4235f267e0e16560e24 Mon Sep 17 00:00:00 2001 From: Chris Dodd Date: Tue, 1 Oct 2019 08:55:48 -0700 Subject: [PATCH 005/106] Avoid ambiguous overload when doing operations on a Match (#2040) - because of the operator T * converter operations between a Match and an int that could be pointer arithmetic or comparisons generate an ambiguous overload message. Avoid that by explicitly supplying these operator overloads that avoid user-defined conversions. --- ir/pattern.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/ir/pattern.h b/ir/pattern.h index 01ad100d38c..a142f23ee66 100644 --- a/ir/pattern.h +++ b/ir/pattern.h @@ -99,6 +99,11 @@ class Pattern { Pattern operator^(const Pattern &a) { return Pattern(*this) ^ a; } Pattern operator&&(const Pattern &a) { return Pattern(*this) && a; } Pattern operator||(const Pattern &a) { return Pattern(*this) || a; } + // avoid ambiguous overloads with operator const T * above + Pattern operator+(int a) { return Pattern(*this) + Pattern(a); } + Pattern operator-(int a) { return Pattern(*this) - Pattern(a); } + Pattern operator==(int a) { return Pattern(*this) == Pattern(a); } + Pattern operator!=(int a) { return Pattern(*this) != Pattern(a); } }; template Pattern(const T*&m) : pattern(new MatchExt(m)) {} From d6e143a6dbc5cf55d08cb5cc22edf68319d44fd3 Mon Sep 17 00:00:00 2001 From: Luka <53172552+lbanduka@users.noreply.github.com> Date: Tue, 1 Oct 2019 23:29:08 +0200 Subject: [PATCH 006/106] Support for logging user defined messages (#2010) * Support for logging user defined messages * Added test logging.p4 for testing function log_msg. --- backends/bmv2/common/deparser.cpp | 18 ++++++++--- backends/bmv2/common/deparser.h | 3 +- backends/bmv2/common/expression.cpp | 7 +++++ backends/bmv2/common/expression.h | 1 + backends/bmv2/common/parser.cpp | 9 ++++++ backends/bmv2/simple_switch/simpleSwitch.cpp | 27 ++++++++++++++++ backends/bmv2/simple_switch/simpleSwitch.h | 1 + frontends/p4/fromv1.0/v1model.h | 2 ++ frontends/parsers/p4/p4parser.ypp | 1 + lib/source_file.cpp | 8 +++++ p4include/v1model.p4 | 8 +++++ testdata/p4_16_samples/logging.p4 | 19 ++++++++++++ .../p4_16_samples_outputs/logging-first.p4 | 24 ++++++++++++++ .../p4_16_samples_outputs/logging-frontend.p4 | 26 ++++++++++++++++ .../p4_16_samples_outputs/logging-midend.p4 | 31 +++++++++++++++++++ testdata/p4_16_samples_outputs/logging.p4 | 22 +++++++++++++ .../p4_16_samples_outputs/logging.p4-stderr | 0 17 files changed, 202 insertions(+), 5 deletions(-) create mode 100644 testdata/p4_16_samples/logging.p4 create mode 100644 testdata/p4_16_samples_outputs/logging-first.p4 create mode 100644 testdata/p4_16_samples_outputs/logging-frontend.p4 create mode 100644 testdata/p4_16_samples_outputs/logging-midend.p4 create mode 100644 testdata/p4_16_samples_outputs/logging.p4 create mode 100644 testdata/p4_16_samples_outputs/logging.p4-stderr diff --git a/backends/bmv2/common/deparser.cpp b/backends/bmv2/common/deparser.cpp index a34e316c48a..652da0d3d9e 100644 --- a/backends/bmv2/common/deparser.cpp +++ b/backends/bmv2/common/deparser.cpp @@ -20,11 +20,11 @@ limitations under the License. namespace BMV2 { void DeparserConverter::convertDeparserBody(const IR::Vector* body, - Util::JsonArray* result) { + Util::JsonArray* order, Util::JsonArray* primitives) { ctxt->conv->simpleExpressionsOnly = true; for (auto s : *body) { if (auto block = s->to()) { - convertDeparserBody(&block->components, result); + convertDeparserBody(&block->components, order, primitives); continue; } else if (s->is() || s->is()) { break; @@ -44,7 +44,7 @@ void DeparserConverter::convertDeparserBody(const IR::Vector* bo if (type->is()) { auto j = ctxt->conv->convert(arg->expression); auto val = j->to()->get("value"); - result->append(val); + order->append(val); } else { // We don't need to handle other types, // like header unions or stacks; they were @@ -56,6 +56,15 @@ void DeparserConverter::convertDeparserBody(const IR::Vector* bo } continue; } + } else if (mi->is()) { + auto ef = mi->to(); + ctxt->conv->simpleExpressionsOnly = false; + auto json = ExternConverter::cvtExternFunction(ctxt, ef, mc, + s, /* emitExterns */ true); + ctxt->conv->simpleExpressionsOnly = true; + if (json) + primitives->append(json); + continue; } } ::error(ErrorType::ERR_UNSUPPORTED, "within a deparser on this target", s); @@ -69,7 +78,8 @@ Util::IJson* DeparserConverter::convertDeparser(const IR::P4Control* ctrl) { result->emplace("id", nextId("deparser")); result->emplace_non_null("source_info", ctrl->sourceInfoJsonObj()); auto order = mkArrayField(result, "order"); - convertDeparserBody(&ctrl->body->components, order); + auto primitives = mkArrayField(result, "primitives"); + convertDeparserBody(&ctrl->body->components, order, primitives); return result; } diff --git a/backends/bmv2/common/deparser.h b/backends/bmv2/common/deparser.h index b103e41381b..b08d1126602 100644 --- a/backends/bmv2/common/deparser.h +++ b/backends/bmv2/common/deparser.h @@ -33,7 +33,8 @@ class DeparserConverter : public Inspector { protected: Util::IJson* convertDeparser(const IR::P4Control* ctrl); - void convertDeparserBody(const IR::Vector* body, Util::JsonArray* result); + void convertDeparserBody(const IR::Vector* body, + Util::JsonArray* order, Util::JsonArray* primitives); public: bool preorder(const IR::P4Control* ctrl); diff --git a/backends/bmv2/common/expression.cpp b/backends/bmv2/common/expression.cpp index 9e0c684f10e..5246aeef6a0 100644 --- a/backends/bmv2/common/expression.cpp +++ b/backends/bmv2/common/expression.cpp @@ -665,6 +665,13 @@ void ExpressionConverter::postorder(const IR::PathExpression* expression) { } } +void ExpressionConverter::postorder(const IR::StringLiteral* expression) { + auto result = new Util::JsonObject(); + result->emplace("type", "string"); + result->emplace("value", expression->value); + mapExpression(expression, result); +} + void ExpressionConverter::postorder(const IR::TypeNameExpression* expression) { (void)expression; } diff --git a/backends/bmv2/common/expression.h b/backends/bmv2/common/expression.h index 95ed19c63b0..77e03334cca 100644 --- a/backends/bmv2/common/expression.h +++ b/backends/bmv2/common/expression.h @@ -119,6 +119,7 @@ class ExpressionConverter : public Inspector { void postorder(const IR::StructInitializerExpression* expression) override; void postorder(const IR::Operation_Unary* expression) override; void postorder(const IR::PathExpression* expression) override; + void postorder(const IR::StringLiteral* expression) override; void postorder(const IR::TypeNameExpression* expression) override; void postorder(const IR::Expression* expression) override; void mapExpression(const IR::Expression* expression, Util::IJson* json); diff --git a/backends/bmv2/common/parser.cpp b/backends/bmv2/common/parser.cpp index 96ecc220a0d..245cc251fa0 100644 --- a/backends/bmv2/common/parser.cpp +++ b/backends/bmv2/common/parser.cpp @@ -17,6 +17,8 @@ limitations under the License. #include "parser.h" #include "JsonObjects.h" #include "backend.h" +#include "extern.h" +#include "frontends/p4/fromv1.0/v1model.h" namespace BMV2 { @@ -200,6 +202,13 @@ Util::IJson* ParserConverter::convertParserStatement(const IR::StatOrDecl* stat) paramsArray->append(expr); paramValue->emplace("op", extFuncName); paramValue->emplace_non_null("source_info", mce->sourceInfoJsonObj()); + } else if (extFuncName == P4V1::V1Model::instance.log_msg.name) { + BUG_CHECK(mce->arguments->size() == 2 || mce->arguments->size() == 1, + "%1%: Expected 1 or 2 arguments", mce); + result->emplace("op", "primitive"); + auto ef = minst->to(); + auto ijson = ExternConverter::cvtExternFunction(ctxt, ef, mce, stat, false); + params->append(ijson); return result; } } else if (minst->is()) { diff --git a/backends/bmv2/simple_switch/simpleSwitch.cpp b/backends/bmv2/simple_switch/simpleSwitch.cpp index 0c808df0ed3..2ec39e39e23 100644 --- a/backends/bmv2/simple_switch/simpleSwitch.cpp +++ b/backends/bmv2/simple_switch/simpleSwitch.cpp @@ -108,6 +108,7 @@ ExternConverter_direct_counter ExternConverter_direct_counter::singleton; ExternConverter_direct_meter ExternConverter_direct_meter::singleton; ExternConverter_action_profile ExternConverter_action_profile::singleton; ExternConverter_action_selector ExternConverter_action_selector::singleton; +ExternConverter_log_msg ExternConverter_log_msg::singleton; Util::IJson* ExternConverter_clone::convertExternFunction( UNUSED ConversionContext* ctxt, UNUSED const P4::ExternFunction* ef, @@ -791,6 +792,32 @@ void ExternConverter_action_selector::convertExternInstance( ctxt->action_profiles->append(action_profile); } +Util::IJson* ExternConverter_log_msg::convertExternFunction( + ConversionContext* ctxt, UNUSED const P4::ExternFunction* ef, + const IR::MethodCallExpression* mc, const IR::StatOrDecl* s, + UNUSED const bool emitExterns) { + if (mc->arguments->size() != 2 && mc->arguments->size() != 1) { + modelError("Expected 1 or 2 arguments for %1%", mc); + return nullptr; + } + auto primitive = mkPrimitive("log_msg"); + auto params = mkParameters(primitive); + primitive->emplace_non_null("source_info", s->sourceInfoJsonObj()); + auto paramsValue = new Util::JsonObject(); + paramsValue->emplace("type", "parameters_vector"); + auto str = ctxt->conv->convert(mc->arguments->at(0)->expression); + params->append(str); + if (mc->arguments->size() == 2) { + auto val = ctxt->conv->convert(mc->arguments->at(1)->expression); + paramsValue->emplace("value", val); + } else { + auto tmp = new Util::JsonObject(); + paramsValue->emplace("value", tmp); + } + params->append(paramsValue); + return primitive; +} + void SimpleSwitchBackend::modelError(const char* format, const IR::Node* node) const { ::error(format, node); diff --git a/backends/bmv2/simple_switch/simpleSwitch.h b/backends/bmv2/simple_switch/simpleSwitch.h index 47591f48eb5..54f65320871 100644 --- a/backends/bmv2/simple_switch/simpleSwitch.h +++ b/backends/bmv2/simple_switch/simpleSwitch.h @@ -154,6 +154,7 @@ EXTERN_CONVERTER_W_FUNCTION(digest) EXTERN_CONVERTER_W_FUNCTION(resubmit) EXTERN_CONVERTER_W_FUNCTION(recirculate) EXTERN_CONVERTER_W_FUNCTION(mark_to_drop) +EXTERN_CONVERTER_W_FUNCTION(log_msg) EXTERN_CONVERTER_W_FUNCTION_AND_MODEL(random, P4V1::V1Model, v1model) EXTERN_CONVERTER_W_FUNCTION_AND_MODEL(truncate, P4V1::V1Model, v1model) EXTERN_CONVERTER_W_OBJECT_AND_INSTANCE_AND_MODEL(register, P4V1::V1Model, v1model) diff --git a/frontends/p4/fromv1.0/v1model.h b/frontends/p4/fromv1.0/v1model.h index 5adb26c8e70..8745dda44e3 100644 --- a/frontends/p4/fromv1.0/v1model.h +++ b/frontends/p4/fromv1.0/v1model.h @@ -263,6 +263,7 @@ class V1Model : public ::Model::Model { update_checksum("update_checksum"), verify_checksum_with_payload("verify_checksum_with_payload"), update_checksum_with_payload("update_checksum_with_payload"), + log_msg("log_msg"), directMeter(), directCounter() {} @@ -303,6 +304,7 @@ class V1Model : public ::Model::Model { ::Model::Elem update_checksum; ::Model::Elem verify_checksum_with_payload; ::Model::Elem update_checksum_with_payload; + ::Model::Elem log_msg; DirectMeter_Model directMeter; DirectCounter_Model directCounter; diff --git a/frontends/parsers/p4/p4parser.ypp b/frontends/parsers/p4/p4parser.ypp index a3aad6a04fd..ff5c82f64c4 100644 --- a/frontends/parsers/p4/p4parser.ypp +++ b/frontends/parsers/p4/p4parser.ypp @@ -505,6 +505,7 @@ annotationToken | RETURN { $$ = $1; } | SELECT { $$ = $1; } | STATE { $$ = $1; } + | STRING { $$ = $1; } | STRUCT { $$ = $1; } | SWITCH { $$ = $1; } | TABLE { $$ = $1; } diff --git a/lib/source_file.cpp b/lib/source_file.cpp index 880322faa9a..327b63b6891 100644 --- a/lib/source_file.cpp +++ b/lib/source_file.cpp @@ -254,6 +254,14 @@ cstring InputSources::getBriefSourceFragment(const SourceInfo &position) const { } else { end = position.getEnd().getColumnNumber(); } + + // Adding escape character in front of '"' character to properly store + // quote marks as part of JSON properties, they must be escaped. + if (result.find('"') != nullptr) { + cstring out = result.replace("\"", "\\\""); + return out.substr(0, out.size()-1); + } + return result.substr(start, end - start) + toadd; } diff --git a/p4include/v1model.p4 b/p4include/v1model.p4 index c019beeceed..dd005ce6ba2 100644 --- a/p4include/v1model.p4 +++ b/p4include/v1model.p4 @@ -619,6 +619,14 @@ extern void assert(in bool check); */ extern void assume(in bool check); +/* + * Log user defined messages + * Example: log_msg("User defined message"); + * or log_msg("Value1 = {}, Value2 = {}",{value1, value2}); + */ +extern void log_msg(string msg); +extern void log_msg(string msg, in T data); + // The name 'standard_metadata' is reserved /* diff --git a/testdata/p4_16_samples/logging.p4 b/testdata/p4_16_samples/logging.p4 new file mode 100644 index 00000000000..e6e82d204d3 --- /dev/null +++ b/testdata/p4_16_samples/logging.p4 @@ -0,0 +1,19 @@ +#include + +control c(inout bit<32> x, inout bit<32> y) { + action a(inout bit<32> b, inout bit<32> d) { + log_msg("Logging message."); + log_msg("Logging values {} and {}", {b, d}); + } + table t { + actions = { a(x,y); } + } + apply { + t.apply(); + } +} + +control e(inout bit<32> x, inout bit<32> y); +package top(e _e); + +top(c()) main; diff --git a/testdata/p4_16_samples_outputs/logging-first.p4 b/testdata/p4_16_samples_outputs/logging-first.p4 new file mode 100644 index 00000000000..330fec49051 --- /dev/null +++ b/testdata/p4_16_samples_outputs/logging-first.p4 @@ -0,0 +1,24 @@ +#include +#include + +control c(inout bit<32> x, inout bit<32> y) { + action a(inout bit<32> b, inout bit<32> d) { + log_msg("Logging message."); + log_msg, bit<32>>>("Logging values {} and {}", { b, d }); + } + table t { + actions = { + a(x, y); + @defaultonly NoAction(); + } + default_action = NoAction(); + } + apply { + t.apply(); + } +} + +control e(inout bit<32> x, inout bit<32> y); +package top(e _e); +top(c()) main; + diff --git a/testdata/p4_16_samples_outputs/logging-frontend.p4 b/testdata/p4_16_samples_outputs/logging-frontend.p4 new file mode 100644 index 00000000000..9436e684cc1 --- /dev/null +++ b/testdata/p4_16_samples_outputs/logging-frontend.p4 @@ -0,0 +1,26 @@ +#include +#include + +control c(inout bit<32> x, inout bit<32> y) { + @name(".NoAction") action NoAction_0() { + } + @name("c.a") action a(inout bit<32> b, inout bit<32> d) { + log_msg("Logging message."); + log_msg, bit<32>>>("Logging values {} and {}", { b, d }); + } + @name("c.t") table t_0 { + actions = { + a(x, y); + @defaultonly NoAction_0(); + } + default_action = NoAction_0(); + } + apply { + t_0.apply(); + } +} + +control e(inout bit<32> x, inout bit<32> y); +package top(e _e); +top(c()) main; + diff --git a/testdata/p4_16_samples_outputs/logging-midend.p4 b/testdata/p4_16_samples_outputs/logging-midend.p4 new file mode 100644 index 00000000000..9a0a1990bc3 --- /dev/null +++ b/testdata/p4_16_samples_outputs/logging-midend.p4 @@ -0,0 +1,31 @@ +#include +#include + +struct tuple_0 { + bit<32> field; + bit<32> field_0; +} + +control c(inout bit<32> x, inout bit<32> y) { + @name(".NoAction") action NoAction_0() { + } + @name("c.a") action a() { + log_msg("Logging message."); + log_msg("Logging values {} and {}", { x, y }); + } + @name("c.t") table t_0 { + actions = { + a(); + @defaultonly NoAction_0(); + } + default_action = NoAction_0(); + } + apply { + t_0.apply(); + } +} + +control e(inout bit<32> x, inout bit<32> y); +package top(e _e); +top(c()) main; + diff --git a/testdata/p4_16_samples_outputs/logging.p4 b/testdata/p4_16_samples_outputs/logging.p4 new file mode 100644 index 00000000000..209623d0670 --- /dev/null +++ b/testdata/p4_16_samples_outputs/logging.p4 @@ -0,0 +1,22 @@ +#include +#include + +control c(inout bit<32> x, inout bit<32> y) { + action a(inout bit<32> b, inout bit<32> d) { + log_msg("Logging message."); + log_msg("Logging values {} and {}", { b, d }); + } + table t { + actions = { + a(x, y); + } + } + apply { + t.apply(); + } +} + +control e(inout bit<32> x, inout bit<32> y); +package top(e _e); +top(c()) main; + diff --git a/testdata/p4_16_samples_outputs/logging.p4-stderr b/testdata/p4_16_samples_outputs/logging.p4-stderr new file mode 100644 index 00000000000..e69de29bb2d From b120be6dbf36dfa1d97701b11a93790920f85b78 Mon Sep 17 00:00:00 2001 From: Mihai Budiu Date: Tue, 1 Oct 2019 14:33:11 -0700 Subject: [PATCH 007/106] Do not constant fold on the lhs of = (#2022) * Do not constant fold on the lhs of = --- frontends/common/constantFolding.cpp | 21 ++++++++++++++++++- frontends/common/constantFolding.h | 6 ++++++ testdata/p4_16_errors/issue2021.p4 | 12 +++++++++++ testdata/p4_16_errors_outputs/issue2021.p4 | 13 ++++++++++++ .../p4_16_errors_outputs/issue2021.p4-stderr | 9 ++++++++ 5 files changed, 60 insertions(+), 1 deletion(-) create mode 100644 testdata/p4_16_errors/issue2021.p4 create mode 100644 testdata/p4_16_errors_outputs/issue2021.p4 create mode 100644 testdata/p4_16_errors_outputs/issue2021.p4-stderr diff --git a/frontends/common/constantFolding.cpp b/frontends/common/constantFolding.cpp index de50e0794f6..16be69fad22 100644 --- a/frontends/common/constantFolding.cpp +++ b/frontends/common/constantFolding.cpp @@ -78,7 +78,7 @@ const IR::Expression* DoConstantFolding::getConstant(const IR::Expression* expr) } const IR::Node* DoConstantFolding::postorder(IR::PathExpression* e) { - if (refMap == nullptr) + if (refMap == nullptr || assignmentTarget) return e; auto decl = refMap->getDeclaration(e->path); if (decl == nullptr) @@ -164,6 +164,25 @@ const IR::Node* DoConstantFolding::postorder(IR::Declaration_Constant* d) { return d; } +const IR::Node* DoConstantFolding::preorder(IR::AssignmentStatement* statement) { + assignmentTarget = true; + visit(statement->left); + assignmentTarget = false; + visit(statement->right); + prune(); + return statement; +} + +const IR::Node* DoConstantFolding::preorder(IR::ArrayIndex* e) { + visit(e->left); + bool save = assignmentTarget; + assignmentTarget = false; + visit(e->right); + assignmentTarget = save; + prune(); + return e; +} + const IR::Node* DoConstantFolding::postorder(IR::Cmpl* e) { auto op = getConstant(e->expr); if (op == nullptr) diff --git a/frontends/common/constantFolding.h b/frontends/common/constantFolding.h index 1c04e226745..bcfe2f604c2 100644 --- a/frontends/common/constantFolding.h +++ b/frontends/common/constantFolding.h @@ -62,6 +62,9 @@ class DoConstantFolding : public Transform { /// Maps declaration constants to constant expressions std::map constants; + // True if we are processing a left side of an assignment; we should not + // we substituting constants there. + bool assignmentTarget; protected: /// @returns a constant equivalent to @p expr or `nullptr` @@ -104,6 +107,7 @@ class DoConstantFolding : public Transform { DoConstantFolding(const ReferenceMap* refMap, TypeMap* typeMap, bool warnings = true) : refMap(refMap), typeMap(typeMap), typesKnown(typeMap != nullptr), warnings(warnings) { visitDagOnce = true; setName("DoConstantFolding"); + assignmentTarget = false; } const IR::Node* postorder(IR::Declaration_Constant* d) override; @@ -140,6 +144,8 @@ class DoConstantFolding : public Transform { const IR::Node* postorder(IR::Type_Varbits* type) override; const IR::Node* postorder(IR::SelectExpression* e) override; const IR::Node* postorder(IR::IfStatement* statement) override; + const IR::Node* preorder(IR::AssignmentStatement* statement) override; + const IR::Node* preorder(IR::ArrayIndex* e) override; }; /** Optionally runs @ref TypeChecking if @p typeMap is not diff --git a/testdata/p4_16_errors/issue2021.p4 b/testdata/p4_16_errors/issue2021.p4 new file mode 100644 index 00000000000..3f09ae120fa --- /dev/null +++ b/testdata/p4_16_errors/issue2021.p4 @@ -0,0 +1,12 @@ +control C(); +package S(C c); +const bit<8> x = 8w1; +extern void f(out bit<8> a); + +control MyC() { + apply { + .x = 8w3; + f(.x); + } +} +S(MyC()) main; diff --git a/testdata/p4_16_errors_outputs/issue2021.p4 b/testdata/p4_16_errors_outputs/issue2021.p4 new file mode 100644 index 00000000000..91b13a2a7d6 --- /dev/null +++ b/testdata/p4_16_errors_outputs/issue2021.p4 @@ -0,0 +1,13 @@ +control C(); +package S(C c); +const bit<8> x = 8w1; +extern void f(out bit<8> a); +control MyC() { + apply { + .x = 8w3; + f(.x); + } +} + +S(MyC()) main; + diff --git a/testdata/p4_16_errors_outputs/issue2021.p4-stderr b/testdata/p4_16_errors_outputs/issue2021.p4-stderr new file mode 100644 index 00000000000..51ac780878a --- /dev/null +++ b/testdata/p4_16_errors_outputs/issue2021.p4-stderr @@ -0,0 +1,9 @@ +issue2021.p4(8): [--Werror=type-error] error: Expression .x cannot be the target of an assignment + .x = 8w3; + ^ +issue2021.p4(3): [--Werror=type-error] error: : Read-only value used for out/inout parameter a +const bit<8> x = 8w1; + ^^^ +issue2021.p4(4) +extern void f(out bit<8> a); + ^ From 0199ea5569de31f53085b6f0c138f1bf08fe83fa Mon Sep 17 00:00:00 2001 From: Han Wang Date: Wed, 2 Oct 2019 09:04:26 -0700 Subject: [PATCH 008/106] refactoring to allow overriding the default p4-14 converter (#2015) --- backends/graphs/parsers.h | 1 + frontends/common/parseInput.cpp | 60 +- frontends/common/parseInput.h | 64 +- frontends/p4/fromv1.0/converters.cpp | 807 +-------------------- frontends/p4/fromv1.0/converters.h | 764 ++++++++++++++++++- frontends/p4/fromv1.0/programStructure.cpp | 64 +- frontends/p4/fromv1.0/programStructure.h | 27 +- frontends/p4/frontend.cpp | 3 +- test/gtest/diagnostics.cpp | 6 +- test/gtest/p4runtime.cpp | 2 +- 10 files changed, 920 insertions(+), 878 deletions(-) diff --git a/backends/graphs/parsers.h b/backends/graphs/parsers.h index 14fec822c8d..a38174efc04 100644 --- a/backends/graphs/parsers.h +++ b/backends/graphs/parsers.h @@ -28,6 +28,7 @@ namespace P4 { // Forward declaration to avoid includes class TypeMap; +class ReferenceMap; } // end namespace P4 namespace graphs { diff --git a/frontends/common/parseInput.cpp b/frontends/common/parseInput.cpp index df03502cafd..d1837967a70 100644 --- a/frontends/common/parseInput.cpp +++ b/frontends/common/parseInput.cpp @@ -29,69 +29,13 @@ limitations under the License. namespace P4 { -template -static const IR::P4Program* -parseV1Program(Input& stream, const char* sourceFile, unsigned sourceLine, - boost::optional debugHook = boost::none) { - // We load the model before parsing the input file, so that the SourceInfo - // in the model comes first. - P4V1::Converter converter; - if (debugHook) converter.addDebugHook(*debugHook); - converter.loadModel(); - - // Parse. - const IR::Node* v1 = V1::V1ParserDriver::parse(stream, sourceFile, - sourceLine); - if (::errorCount() > 0 || v1 == nullptr) - return nullptr; - - // Convert to P4-16. - if (Log::verbose()) - std::cerr << "Converting to P4-16" << std::endl; - v1 = v1->apply(converter); - if (::errorCount() > 0 || v1 == nullptr) - return nullptr; - BUG_CHECK(v1->is(), "Conversion returned %1%", v1); - return v1->to(); -} - -const IR::P4Program* parseP4File(CompilerOptions& options) { - BUG_CHECK(&options == &P4CContext::get().options(), - "Parsing using options that don't match the current " - "compiler context"); - FILE* in = nullptr; - if (options.doNotPreprocess) { - in = fopen(options.file, "r"); - if (in == nullptr) { - ::error("%s: No such file or directory.", options.file); - return nullptr; - } - } else { - in = options.preprocess(); - if (::errorCount() > 0 || in == nullptr) - return nullptr; - } - - auto result = options.isv1() - ? parseV1Program(in, options.file, 1, options.getDebugHook()) - : P4ParserDriver::parse(in, options.file); - options.closeInput(in); - - if (::errorCount() > 0) { - ::error("%1% errors encountered, aborting compilation", ::errorCount()); - return nullptr; - } - BUG_CHECK(result != nullptr, "Parsing failed, but we didn't report an error"); - return result; -} - const IR::P4Program* parseP4String(const char* sourceFile, unsigned sourceLine, const std::string& input, CompilerOptions::FrontendVersion version) { std::istringstream stream(input); auto result = version == CompilerOptions::FrontendVersion::P4_14 - ? parseV1Program(stream, sourceFile, sourceLine) - : P4ParserDriver::parse(stream, sourceFile, sourceLine); + ? parseV1Program(stream, sourceFile, sourceLine) + : P4ParserDriver::parse(stream, sourceFile, sourceLine); if (::errorCount() > 0) { ::error("%1% errors encountered, aborting compilation", ::errorCount()); diff --git a/frontends/common/parseInput.h b/frontends/common/parseInput.h index a825a42200f..33116d79dfc 100644 --- a/frontends/common/parseInput.h +++ b/frontends/common/parseInput.h @@ -1,5 +1,5 @@ /* -Copyright 2013-present Barefoot Networks, Inc. +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. @@ -18,6 +18,11 @@ limitations under the License. #define _FRONTENDS_COMMON_PARSEINPUT_H_ #include "frontends/common/options.h" +#include "frontends/parsers/parserDriver.h" +#include "frontends/p4/fromv1.0/converters.h" +#include "frontends/p4/frontend.h" +#include "lib/error.h" +#include "lib/source_file.h" namespace IR { class P4Program; @@ -25,6 +30,32 @@ class P4Program; namespace P4 { +template +static const IR::P4Program* +parseV1Program(Input& stream, const char* sourceFile, unsigned sourceLine, + boost::optional debugHook = boost::none) { + // We load the model before parsing the input file, so that the SourceInfo + // in the model comes first. + C converter; + if (debugHook) converter.addDebugHook(*debugHook, true); + converter.loadModel(); + + // Parse. + const IR::Node* v1 = V1::V1ParserDriver::parse(stream, sourceFile, + sourceLine); + if (::errorCount() > 0 || v1 == nullptr) + return nullptr; + + // Convert to P4-16. + if (Log::verbose()) + std::cerr << "Converting to P4-16" << std::endl; + v1 = v1->apply(converter); + if (::errorCount() > 0 || v1 == nullptr) + return nullptr; + BUG_CHECK(v1->is(), "Conversion returned %1%", v1); + return v1->to(); +} + /** * Parse P4 source from a file. The filename and language version are specified * by @options. If the language version is not P4-16, then the program is @@ -33,7 +64,36 @@ namespace P4 { * @return a P4-16 IR tree representing the contents of the given file, or null * on failure. If failure occurs, an error will also be reported. */ -const IR::P4Program* parseP4File(CompilerOptions& options); +template +const IR::P4Program* parseP4File(CompilerOptions& options) { + BUG_CHECK(&options == &P4CContext::get().options(), + "Parsing using options that don't match the current " + "compiler context"); + FILE* in = nullptr; + if (options.doNotPreprocess) { + in = fopen(options.file, "r"); + if (in == nullptr) { + ::error("%s: No such file or directory.", options.file); + return nullptr; + } + } else { + in = options.preprocess(); + if (::errorCount() > 0 || in == nullptr) + return nullptr; + } + + auto result = options.isv1() + ? parseV1Program(in, options.file, 1, options.getDebugHook()) + : P4ParserDriver::parse(in, options.file); + options.closeInput(in); + + if (::errorCount() > 0) { + ::error("%1% errors encountered, aborting compilation", ::errorCount()); + return nullptr; + } + BUG_CHECK(result != nullptr, "Parsing failed, but we didn't report an error"); + return result; +} /** * Parse P4 source from the string @input, interpreting it as having language diff --git a/frontends/p4/fromv1.0/converters.cpp b/frontends/p4/fromv1.0/converters.cpp index 52f10e8e80f..4cb4d6837d6 100644 --- a/frontends/p4/fromv1.0/converters.cpp +++ b/frontends/p4/fromv1.0/converters.cpp @@ -150,15 +150,36 @@ const IR::Node* ExpressionConverter::postorder(IR::PathExpression *ref) { const IR::Node* ExpressionConverter::postorder(IR::ConcreteHeaderRef* nhr) { const IR::Expression* ref; - if (structure->isHeader(nhr)) { - if (nhr->type->is()) { - auto type = nhr->type->to(); - if (structure->systemHeaderTypes.count(type->name)) { - auto path = new IR::Path(nhr->ref->name); - auto result = new IR::PathExpression(nhr->srcInfo, nhr->type, path); - return result; - } + + // convert types defined by the target system + if (nhr->type->is()) { + auto type = nhr->type->to(); + if (structure->parameterTypes.count(type->name)) { + auto path = new IR::Path(nhr->ref->name); + auto result = new IR::PathExpression(nhr->srcInfo, nhr->type, path); + result->type = nhr->type; + return result; + } else if (structure->headerTypes.count(type->name)) { + ref = structure->conversionContext->header->clone(); + auto result = new IR::Member(nhr->srcInfo, ref, nhr->ref->name); + result->type = nhr->type; + return result; } + } else if (nhr->type->is()) { + auto type = nhr->type->to(); + if (structure->parameterTypes.count(type->name)) { + auto path = new IR::Path(nhr->ref->name); + auto result = new IR::PathExpression(nhr->srcInfo, nhr->type, path); + return result; + } else if (structure->metadataTypes.count(type->name)) { + ref = structure->conversionContext->header->clone(); + auto result = new IR::Member(nhr->srcInfo, ref, nhr->ref->name); + return result; + } + } + + // convert types defined by user program + if (structure->isHeader(nhr)) { ref = structure->conversionContext->header->clone(); } else { if (nhr->ref->name == P4V1::V1Model::instance.standardMetadata.name) @@ -585,770 +606,6 @@ PrimitiveConverter::convertArgs(ProgramStructure *structure, const IR::Primitive return rv; } -/////////////////////////////////////////////////////////////// - -namespace { -class DiscoverStructure : public Inspector { - ProgramStructure* structure; - - // These names can only be used for very specific purposes - std::map reserved_names = { - { "standard_metadata_t", "type" }, - { "standard_metadata", "metadata" }, - { "egress", "control" } - }; - - void checkReserved(const IR::Node* node, cstring nodeName, cstring kind) const { - auto it = reserved_names.find(nodeName); - if (it == reserved_names.end()) - return; - if (it->second != kind) - ::error("%1% cannot have this name; it can only be used for %2%", node, it->second); - } - void checkReserved(const IR::Node* node, cstring nodeName) const { - checkReserved(node, nodeName, nullptr); - } - - public: - explicit DiscoverStructure(ProgramStructure* structure) : structure(structure) - { CHECK_NULL(structure); setName("DiscoverStructure"); } - - void postorder(const IR::ParserException* ex) override { - ::warning(ErrorType::WARN_UNSUPPORTED, "%1%: parser exception is not translated to P4-16", - ex); } - void postorder(const IR::Metadata* md) override - { structure->metadata.emplace(md); checkReserved(md, md->name, "metadata"); } - void postorder(const IR::Header* hd) override - { structure->headers.emplace(hd); checkReserved(hd, hd->name); } - void postorder(const IR::Type_StructLike *t) override - { structure->types.emplace(t); checkReserved(t, t->name, "type"); } - void postorder(const IR::V1Control* control) override - { structure->controls.emplace(control); checkReserved(control, control->name, "control"); } - void postorder(const IR::V1Parser* parser) override - { structure->parserStates.emplace(parser); checkReserved(parser, parser->name); } - void postorder(const IR::V1Table* table) override - { structure->tables.emplace(table); checkReserved(table, table->name); } - void postorder(const IR::ActionFunction* action) override - { structure->actions.emplace(action); checkReserved(action, action->name); } - void postorder(const IR::HeaderStack* stack) override - { structure->stacks.emplace(stack); checkReserved(stack, stack->name); } - void postorder(const IR::Counter* count) override - { structure->counters.emplace(count); checkReserved(count, count->name); } - void postorder(const IR::Register* reg) override - { structure->registers.emplace(reg); checkReserved(reg, reg->name); } - void postorder(const IR::ActionProfile* ap) override - { structure->action_profiles.emplace(ap); checkReserved(ap, ap->name); } - void postorder(const IR::FieldList* fl) override - { structure->field_lists.emplace(fl); checkReserved(fl, fl->name); } - void postorder(const IR::FieldListCalculation* flc) override - { structure->field_list_calculations.emplace(flc); checkReserved(flc, flc->name); } - void postorder(const IR::CalculatedField* cf) override - { structure->calculated_fields.push_back(cf); } - void postorder(const IR::Meter* m) override - { structure->meters.emplace(m); checkReserved(m, m->name); } - void postorder(const IR::ActionSelector* as) override - { structure->action_selectors.emplace(as); checkReserved(as, as->name); } - void postorder(const IR::Type_Extern *ext) override - { structure->extern_types.emplace(ext); checkReserved(ext, ext->name); } - void postorder(const IR::Declaration_Instance *ext) override - { structure->externs.emplace(ext); checkReserved(ext, ext->name); } - void postorder(const IR::ParserValueSet* pvs) override - { structure->value_sets.emplace(pvs); checkReserved(pvs, pvs->name); } -}; - -class ComputeCallGraph : public Inspector { - ProgramStructure* structure; - - public: - explicit ComputeCallGraph(ProgramStructure* structure) : structure(structure) - { CHECK_NULL(structure); setName("ComputeCallGraph"); } - - void postorder(const IR::V1Parser* parser) override { - LOG3("Scanning parser " << parser->name); - structure->parsers.add(parser->name); - if (!parser->default_return.name.isNullOrEmpty()) - structure->parsers.calls(parser->name, parser->default_return); - if (parser->cases != nullptr) - for (auto ce : *parser->cases) - structure->parsers.calls(parser->name, ce->action.name); - for (auto expr : parser->stmts) { - if (expr->is()) { - auto primitive = expr->to(); - if (primitive->name == "extract") { - BUG_CHECK(primitive->operands.size() == 1, - "Expected 1 operand for %1%", primitive); - auto dest = primitive->operands.at(0); - LOG3("Parser " << parser->name << " extracts into " << dest); - structure->extracts[parser->name].push_back(dest); - } - } - } - } - void postorder(const IR::Primitive* primitive) override { - auto name = primitive->name; - const IR::GlobalRef *glob = nullptr; - const IR::Declaration_Instance *extrn = nullptr; - if (primitive->operands.size() >= 1) - glob = primitive->operands[0]->to(); - if (glob) extrn = glob->obj->to(); - - if (extrn) { - auto parent = findContext(); - BUG_CHECK(parent != nullptr, "%1%: Extern call not within action", primitive); - structure->calledExterns.calls(parent->name, extrn->name.name); - return; - } else if (primitive->name == "count") { - // counter invocation - auto ctrref = primitive->operands.at(0); - const IR::Counter *ctr = nullptr; - if (auto gr = ctrref->to()) - ctr = gr->obj->to(); - else if (auto nr = ctrref->to()) - ctr = structure->counters.get(nr->path->name); - if (ctr == nullptr) - ::error("Cannot find counter %1%", ctrref); - auto parent = findContext(); - BUG_CHECK(parent != nullptr, "%1%: Counter call not within action", primitive); - structure->calledCounters.calls(parent->name, ctr->name.name); - return; - } else if (primitive->name == "execute_meter") { - auto mtrref = primitive->operands.at(0); - const IR::Meter *mtr = nullptr; - if (auto gr = mtrref->to()) - mtr = gr->obj->to(); - else if (auto nr = mtrref->to()) - mtr = structure->meters.get(nr->path->name); - if (mtr == nullptr) - ::error("Cannot find meter %1%", mtrref); - auto parent = findContext(); - BUG_CHECK(parent != nullptr, - "%1%: not within action", primitive); - structure->calledMeters.calls(parent->name, mtr->name.name); - return; - } else if (primitive->name == "register_read" || primitive->name == "register_write") { - const IR::Expression* regref; - if (primitive->name == "register_read") - regref = primitive->operands.at(1); - else - regref = primitive->operands.at(0); - const IR::Register *reg = nullptr; - if (auto gr = regref->to()) - reg = gr->obj->to(); - else if (auto nr = regref->to()) - reg = structure->registers.get(nr->path->name); - if (reg == nullptr) - ::error("Cannot find register %1%", regref); - auto parent = findContext(); - BUG_CHECK(parent != nullptr, - "%1%: not within action", primitive); - structure->calledRegisters.calls(parent->name, reg->name.name); - return; - } else if (structure->actions.contains(name)) { - auto parent = findContext(); - BUG_CHECK(parent != nullptr, "%1%: Action call not within action", primitive); - structure->calledActions.calls(parent->name, name); - } else if (structure->controls.contains(name)) { - auto parent = findContext(); - BUG_CHECK(parent != nullptr, "%1%: Control call not within control", primitive); - structure->calledControls.calls(parent->name, name); - } - } - void postorder(const IR::GlobalRef *gref) override { - cstring caller; - if (auto af = findContext()) { - caller = af->name; - } else if (auto di = findContext()) { - caller = di->name; - } else { - BUG("%1%: GlobalRef not within action or extern", gref); } - if (auto ctr = gref->obj->to()) - structure->calledCounters.calls(caller, ctr->name.name); - else if (auto mtr = gref->obj->to()) - structure->calledMeters.calls(caller, mtr->name.name); - else if (auto reg = gref->obj->to()) - structure->calledRegisters.calls(caller, reg->name.name); - else if (auto ext = gref->obj->to()) - structure->calledExterns.calls(caller, ext->name.name); - } -}; - -/// Table call graph should be built after the control call graph is built. -/// In the case that the program contains an unused control block, the -/// table invocation in the unused control block should not be considered. -class ComputeTableCallGraph : public Inspector { - ProgramStructure *structure; - - public: - explicit ComputeTableCallGraph(ProgramStructure *structure) : structure(structure) { - CHECK_NULL(structure); - setName("ComputeTableCallGraph"); - } - - void postorder(const IR::Apply *apply) override { - LOG3("Scanning " << apply->name); - auto tbl = structure->tables.get(apply->name.name); - if (tbl == nullptr) - ::error("Could not find table %1%", apply->name); - auto parent = findContext(); - ERROR_CHECK(parent != nullptr, "%1%: Apply not within a control block?", apply); - - auto ctrl = get(structure->tableMapping, tbl); - - // skip control block that is unused. - if (!structure->calledControls.isCallee(parent->name) && - parent->name != P4V1::V1Model::instance.ingress.name && - parent->name != P4V1::V1Model::instance.egress.name ) - return; - - if (ctrl != nullptr && ctrl != parent) { - auto previous = get(structure->tableInvocation, tbl); - ::error("Table %1% invoked from two different controls: %2% and %3%", - tbl, apply, previous); - } - LOG3("Invoking " << tbl << " in " << parent->name); - structure->tableMapping.emplace(tbl, parent); - structure->tableInvocation.emplace(tbl, apply); - } -}; - -class Rewriter : public Transform { - ProgramStructure* structure; - public: - explicit Rewriter(ProgramStructure* structure) : structure(structure) - { CHECK_NULL(structure); setName("Rewriter"); } - - const IR::Node* preorder(IR::V1Program* global) override { - if (LOGGING(4)) { - LOG4("#### Initial P4_14 program"); - dump(global); } - prune(); - auto *rv = structure->create(global->srcInfo); - if (LOGGING(4)) { - LOG4("#### Generated P4_16 program"); - dump(rv); } - return rv; - } -}; - -/** -This pass uses the @length annotation set by the v1 front-end on -varbit fields and converts extracts for headers with varbit fields. -This only supports headers with a single varbit field. -(The @length annotation is inserted as a conversion from the length -header property.) For example: - -header H { - bit<8> len; - @length(len) - varbit<64> data; -} -... -H h; -pkt.extract(h); - -is converted to: - -header H { - bit<8> len; - varbit<64> data; // annotation removed -} -... -H h; - -// Fixed-length size of H -header H_0 { - bit<8> len; -} - -H_0 h_0; -h_0 = pkt.lookahead(); -pkt.extract(h, h_0.len); - -*/ -class FixExtracts final : public Transform { - ProgramStructure* structure; - - struct HeaderSplit { - /// Fixed-size part of a header type (computed for each extract). - const IR::Type_Header* fixedHeaderType; - /// Expression computing the length of the variable-size header. - const IR::Expression* headerLength; - }; - - /// All newly-introduced types. - // The following vector contains only IR::Type_Header, but it is easier - // to append if the elements are Node. - IR::Vector allTypeDecls; - /// All newly-introduced variables, for each parser. - IR::IndexedVector varDecls; - /// Maps each original header type name to the fixed part of it. - std::map fixedPart; - - /// If a header type contains a varbit field then create a new - /// header type containing only the fields prior to the varbit. - /// Returns nullptr otherwise. - HeaderSplit* splitHeaderType(const IR::Type_Header* type) { - // Maybe we have seen this type already - auto fixed = ::get(fixedPart, type->name.name); - if (fixed != nullptr) - return fixed; - - const IR::Expression* headerLength = nullptr; - // We allocate the following when we find the first varbit field. - const IR::Type_Header* fixedHeaderType = nullptr; - IR::IndexedVector fields; - - for (auto f : type->fields) { - if (f->type->is()) { - cstring hname = structure->makeUniqueName(type->name); - if (fixedHeaderType != nullptr) { - ::error("%1%: header types with multiple varbit fields are not supported", - type); - return nullptr; - } - fixedHeaderType = new IR::Type_Header(IR::ID(hname), fields); - // extract length from annotation - auto anno = f->getAnnotation(IR::Annotation::lengthAnnotation); - BUG_CHECK(anno != nullptr, "No length annotation on varbit field", f); - BUG_CHECK(anno->expr.size() == 1, "Expected exactly 1 argument", anno->expr); - headerLength = anno->expr.at(0); - // We keep going through the loop just to check whether there is another - // varbit field in the header. - } else if (fixedHeaderType == nullptr) { - // We only keep the fields prior to the varbit field - fields.push_back(f); - } - } - if (fixedHeaderType != nullptr) { - LOG3("Extracted fixed-size header type from " << type << " into " << fixedHeaderType); - fixed = new HeaderSplit; - fixed->fixedHeaderType = fixedHeaderType; - fixed->headerLength = headerLength; - fixedPart.emplace(type->name.name, fixed); - allTypeDecls.push_back(fixedHeaderType); - return fixed; - } - return nullptr; - } - - /** - This pass rewrites expressions that appear in a @length - annotation: PathExpressions that refer to enclosing struct - fields are rewritten to refer to the proper fields of a - variable `var`. In the example above, the variable is `h_0` - and `len` is translated to `h_0.len`. - */ - class RewriteLength final : public Transform { - const IR::Type_Header* header; - const IR::Declaration* var; - public: - explicit RewriteLength(const IR::Type_Header* header, - const IR::Declaration* var) : - header(header), var(var) { setName("RewriteLength"); } - - const IR::Node* postorder(IR::PathExpression* expression) override { - if (expression->path->absolute) - return expression; - for (auto f : header->fields) { - if (f->name == expression->path->name) - return new IR::Member( - expression->srcInfo, - new IR::PathExpression(var->name), f->name); - } - return expression; - } - }; - - public: - explicit FixExtracts(ProgramStructure* structure) : structure(structure) - { CHECK_NULL(structure); setName("FixExtracts"); } - - const IR::Node* postorder(IR::P4Program* program) override { - // P4-14 headers cannot refer to other types, so it is safe - // to prepend them to the list of declarations. - allTypeDecls.append(program->objects); - program->objects = allTypeDecls; - return program; - } - - const IR::Node* postorder(IR::P4Parser* parser) override { - if (!varDecls.empty()) { - parser->parserLocals.append(varDecls); - varDecls.clear(); - } - return parser; - } - - const IR::Node* postorder(IR::MethodCallStatement* statement) override { - auto mce = getOriginal()->methodCall; - LOG3("Looking up in extracts " << dbp(mce)); - auto ht = ::get(structure->extractsSynthesized, mce); - if (ht == nullptr) - // not an extract - return statement; - - // This is an extract method invocation - BUG_CHECK(mce->arguments->size() == 1, "%1%: expected 1 argument", mce); - auto arg = mce->arguments->at(0); - - auto fixed = splitHeaderType(ht); - if (fixed == nullptr) - return statement; - CHECK_NULL(fixed->headerLength); - CHECK_NULL(fixed->fixedHeaderType); - - auto result = new IR::IndexedVector(); - cstring varName = structure->makeUniqueName("tmp_hdr"); - auto var = new IR::Declaration_Variable( - IR::ID(varName), fixed->fixedHeaderType->to()); - varDecls.push_back(var); - - // Create lookahead - auto member = mce->method->to(); // should be packet_in.extract - CHECK_NULL(member); - auto typeArgs = new IR::Vector(); - typeArgs->push_back(fixed->fixedHeaderType->getP4Type()); - auto lookaheadMethod = new IR::Member(member->expr, - P4::P4CoreLibrary::instance.packetIn.lookahead.name); - auto lookahead = new IR::MethodCallExpression( - mce->srcInfo, lookaheadMethod, typeArgs, new IR::Vector()); - auto assign = new IR::AssignmentStatement( - mce->srcInfo, new IR::PathExpression(varName), lookahead); - result->push_back(assign); - LOG3("Created lookahead " << assign); - - // Create actual extract - RewriteLength rewrite(fixed->fixedHeaderType, var); - auto length = fixed->headerLength->apply(rewrite); - auto args = new IR::Vector(); - args->push_back(arg->clone()); - auto type = IR::Type_Bits::get( - P4::P4CoreLibrary::instance.packetIn.extractSecondArgSize); - auto cast = new IR::Cast(Util::SourceInfo(), type, length); - args->push_back(new IR::Argument(cast)); - auto expression = new IR::MethodCallExpression( - mce->srcInfo, mce->method->clone(), args); - result->push_back(new IR::MethodCallStatement(expression)); - return result; - } -}; - -/* - This class is used to adjust the expressions in a @length - annotation on a varbit field. The P4-14 to P4-16 converter inserts - these annotations on the unique varbit field in a header; the - annotations are created from the header max_length and length - fields. The length annotation contains an expression which is used - to compute the length of the varbit field. The problem that we are - solving here is that expression semantics is different in P4-14 and - P4-16. Consider the canonical case of an IPv4 header: - - header_type ipv4_t { - fields { - version : 4; - ihl : 4; - // lots of other fields... - options: *; - } - length : ihl*4; - max_length : 64; - } - - This generates the following P4-16 structure: - struct ipv4_t { - bit<4> version; - bit<4> ihl; - @length((ihl*4) * 8 - 20) // 20 is the size of the fixed part of the header - varbit<(64 - 20) * 8> options; - } - - When such a header is used in an extract statement, the @length - annotation is used to compute the second argument of the extract - method. The problem we are solving here is the fact that ihl is - only represented on 4 bits, so the evaluation ihl*4 will actually - overflow. This is not a problem in P4-14, but it is a problem in - P4-16. Unfortunately there is no easy way to guess how many bits - are required to evaluate this computation. So what we do is to cast - all PathExpressions to 32-bits. This is really just a heuristic, - but since the semantics of P4-14 expressions is unclear, we cannot - do much better than this. -*/ -class AdjustLengths : public Transform { - public: - AdjustLengths() { setName("AdjustLengths"); } - const IR::Node* postorder(IR::PathExpression* expression) override { - auto anno = findContext(); - if (anno == nullptr) - return expression; - if (anno->name != "length") - return expression; - - LOG3("Inserting cast in length annotation"); - auto type = IR::Type_Bits::get(32); - auto cast = new IR::Cast(expression->srcInfo, type, expression); - return cast; - } -}; - -/// Detects whether there are two declarations in the P4-14 program -/// with the same name and for the same kind of object. -class DetectDuplicates: public Inspector { - public: - DetectDuplicates() { setName("DetectDuplicates"); } - - bool preorder(const IR::V1Program* program) override { - auto &map = program->scope; - auto firstWithKey = map.begin(); - while (firstWithKey != map.end()) { - auto key = firstWithKey->first; - auto range = map.equal_range(key); - for (auto s = range.first; s != range.second; s++) { - auto n = s; - for (n++; n != range.second; n++) { - auto e1 = s->second; - auto e2 = n->second; - if (e1->node_type_name() == e2->node_type_name()) { - if (e1->srcInfo.getStart().isValid()) - ::error("%1%: same name as %2%", e1, e2); - else - // This name is probably standard_metadata_t, a built-in declaration - ::error("%1%: name %2% is reserved", e2, key); - } - } - } - firstWithKey = range.second; - } - // prune; we're done; everything is top-level - return false; - } -}; - -// If a parser state has a pragma @packet_entry, it is treated as a new entry -// point to the parser. -class CheckIfMultiEntryPoint: public Inspector { - ProgramStructure* structure; - - public: - explicit CheckIfMultiEntryPoint(ProgramStructure* structure) : structure(structure) { - setName("CheckIfMultiEntryPoint"); - } - bool preorder(const IR::ParserState* state) { - for (const auto* anno : state->getAnnotations()->annotations) { - if (anno->name.name == "packet_entry") { - structure->parserEntryPoints.emplace(state->name, state); - } - } - return false; - } -}; - -// Generate a new start state that selects on the meta variable, -// standard_metadata.instance_type and branches into one of the entry points. -// The backend is responsible for removing the use of the meta variable and -// eliminate the new start state. The new start state is not added if the user -// does not use the @packet_entry pragma. -class InsertCompilerGeneratedStartState: public Transform { - ProgramStructure* structure; - IR::Vector allTypeDecls; - IR::IndexedVector varDecls; - IR::Vector selCases; - cstring newStartState; - cstring newInstanceType; - - public: - explicit InsertCompilerGeneratedStartState(ProgramStructure* structure) : structure(structure) { - setName("InsertCompilerGeneratedStartState"); - structure->allNames.emplace("start"); - structure->allNames.emplace("InstanceType"); - newStartState = structure->makeUniqueName("start"); - newInstanceType = structure->makeUniqueName("InstanceType"); - } - - const IR::Node* postorder(IR::P4Program* program) override { - allTypeDecls.append(program->objects); - program->objects = allTypeDecls; - return program; - } - - // rename original start state - const IR::Node* postorder(IR::ParserState* state) override { - if (!structure->parserEntryPoints.size()) - return state; - if (state->name == IR::ParserState::start) { - state->name = newStartState; - } - return state; - } - - const IR::Node* postorder(IR::P4Parser* parser) override { - if (!structure->parserEntryPoints.size()) - return parser; - IR::IndexedVector members; - // transition to original start state - members.push_back(new IR::SerEnumMember("START", new IR::Constant(0))); - selCases.push_back(new IR::SelectCase( - new IR::Member(new IR::TypeNameExpression(new IR::Type_Name(newInstanceType)), "START"), - new IR::PathExpression(new IR::Path(newStartState)))); - - // transition to addtional entry points - unsigned idx = 1; - for (auto p : structure->parserEntryPoints) { - members.push_back(new IR::SerEnumMember(p.first, new IR::Constant(idx++))); - selCases.push_back(new IR::SelectCase( - new IR::Member(new IR::TypeNameExpression(new IR::Type_Name(newInstanceType)), - p.first), - new IR::PathExpression(new IR::Path(p.second->name)))); - } - auto instAnnos = new IR::Annotations(); - instAnnos->add(new IR::Annotation(IR::Annotation::nameAnnotation, - {new IR::StringLiteral(IR::ID(".$InstanceType"))})); - auto instEnum = - new IR::Type_SerEnum(newInstanceType, instAnnos, IR::Type_Bits::get(32), members); - allTypeDecls.push_back(instEnum); - - IR::Vector selExpr; - selExpr.push_back( - new IR::Cast(new IR::Type_Name(newInstanceType), - new IR::Member(new IR::PathExpression(new IR::Path("standard_metadata")), - "instance_type"))); - auto selects = new IR::SelectExpression(new IR::ListExpression(selExpr), selCases); - auto annos = new IR::Annotations(); - annos->add(new IR::Annotation(IR::Annotation::nameAnnotation, - {new IR::StringLiteral(IR::ID(".$start"))})); - auto startState = new IR::ParserState(IR::ParserState::start, annos, selects); - varDecls.push_back(startState); - - if (!varDecls.empty()) { - parser->parserLocals.append(varDecls); - varDecls.clear(); - } - return parser; - } -}; - -/// Handle @packet_entry pragma in P4-14. A P4-14 program may be extended to -/// support multiple entry points to the parser. This feature does not comply -/// with P4-14 specification, but it is useful in certain use cases. -class FixMultiEntryPoint : public PassManager { - public: - explicit FixMultiEntryPoint(ProgramStructure* structure) { - setName("FixMultiEntryPoint"); - passes.emplace_back(new CheckIfMultiEntryPoint(structure)); - passes.emplace_back(new InsertCompilerGeneratedStartState(structure)); - } -}; - -/** - If the user metadata structure has a fields called - "intrinsic_metadata" or "queueing_metadata" move all their fields - to the standard_metadata Change all references appropriately. We - do this because the intrinsic_metadata and queueing_metadata are - handled specially in P4-14 programs - much more like - standard_metadata. -*/ -class MoveIntrinsicMetadata : public Transform { - ProgramStructure* structure; - const IR::Type_Struct* stdType = nullptr; - const IR::Type_Struct* userType = nullptr; - const IR::Type_Struct* intrType = nullptr; - const IR::Type_Struct* queueType = nullptr; - const IR::StructField* intrField = nullptr; - const IR::StructField* queueField = nullptr; - - public: - explicit MoveIntrinsicMetadata(ProgramStructure* structure): structure(structure) - { CHECK_NULL(structure); setName("MoveIntrinsicMetadata"); } - const IR::Node* preorder(IR::P4Program* program) override { - stdType = program->getDeclsByName( - structure->v1model.standardMetadataType.name)->single()->to(); - userType = program->getDeclsByName( - structure->v1model.metadataType.name)->single()->to(); - CHECK_NULL(stdType); - CHECK_NULL(userType); - intrField = userType->getField(structure->v1model.intrinsicMetadata.name); - if (intrField != nullptr) { - auto intrTypeName = intrField->type; - auto tn = intrTypeName->to(); - BUG_CHECK(tn, "%1%: expected a Type_Name", intrTypeName); - auto nt = program->getDeclsByName(tn->path->name)->nextOrDefault(); - if (nt == nullptr || !nt->is()) { - ::error("%1%: expected a structure", tn); - return program; - } - intrType = nt->to(); - LOG2("Intrinsic metadata type " << intrType); - } - - queueField = userType->getField(structure->v1model.queueingMetadata.name); - if (queueField != nullptr) { - auto queueTypeName = queueField->type; - auto tn = queueTypeName->to(); - BUG_CHECK(tn, "%1%: expected a Type_Name", queueTypeName); - auto nt = program->getDeclsByName(tn->path->name)->nextOrDefault(); - if (nt == nullptr || !nt->is()) { - ::error("%1%: expected a structure", tn); - return program; - } - queueType = nt->to(); - LOG2("Queueing metadata type " << queueType); - } - return program; - } - - const IR::Node* postorder(IR::Type_Struct* type) override { - if (getOriginal() == stdType) { - if (intrType != nullptr) { - for (auto f : intrType->fields) { - if (type->fields.getDeclaration(f->name) == nullptr) { - ::error("%1%: no such field in standard_metadata", f->name); - LOG2("standard_metadata: " << type); - } - } - } - if (queueType != nullptr) { - for (auto f : queueType->fields) { - if (type->fields.getDeclaration(f->name) == nullptr) { - ::error("%1%: no such field in standard_metadata", f->name); - LOG2("standard_metadata: " << type); - } - } - } - } - return type; - } - - const IR::Node* postorder(IR::StructField* field) override { - if (getOriginal() == intrField || getOriginal() == queueField) - // delete it from its parent - return nullptr; - return field; - } - - const IR::Node* postorder(IR::Member* member) override { - // We rewrite expressions like meta.intrinsic_metadata.x as - // standard_metadata.x. We know that these parameter names - // are always the same. - if (member->member != structure->v1model.intrinsicMetadata.name && - member->member != structure->v1model.queueingMetadata.name) - return member; - auto pe = member->expr->to(); - if (pe == nullptr || pe->path->absolute) - return member; - if (pe->path->name == structure->v1model.parser.metadataParam.name) { - LOG2("Renaming reference " << member); - return new IR::PathExpression( - new IR::Path(member->expr->srcInfo, - IR::ID(pe->path->name.srcInfo, - structure->v1model.standardMetadata.name))); - } - return member; - } -}; - -} // namespace - -/////////////////////////////////////////////////////////////// - static ProgramStructure *defaultCreateProgramStructure() { return new ProgramStructure(); } @@ -1380,10 +637,8 @@ Converter::Converter() { passes.emplace_back(new ComputeTableCallGraph(structure)); passes.emplace_back(new Rewriter(structure)); passes.emplace_back(new FixExtracts(structure)); - if (P4CContext::get().options().enable_intrinsic_metadata_fix()) { - passes.emplace_back(new FixMultiEntryPoint(structure)); - passes.emplace_back(new MoveIntrinsicMetadata(structure)); - } + passes.emplace_back(new FixMultiEntryPoint(structure)); + passes.emplace_back(new MoveIntrinsicMetadata(structure)); } Visitor::profile_t Converter::init_apply(const IR::Node* node) { diff --git a/frontends/p4/fromv1.0/converters.h b/frontends/p4/fromv1.0/converters.h index c4ce291eb13..4eb10ab7e78 100644 --- a/frontends/p4/fromv1.0/converters.h +++ b/frontends/p4/fromv1.0/converters.h @@ -158,11 +158,771 @@ class PrimitiveConverter { const IR::Statement *PrimitiveConverter_##NAME##_##__VA_ARGS__::convert( \ ProgramStructure *structure, const IR::Primitive *primitive) -// Is fed a P4-14 program and outputs an equivalent P4-16 program -class Converter : public PassManager { +/////////////////////////////////////////////////////////////// + +class DiscoverStructure : public Inspector { + ProgramStructure* structure; + + // These names can only be used for very specific purposes + std::map reserved_names = { + { "standard_metadata_t", "type" }, + { "standard_metadata", "metadata" }, + { "egress", "control" } + }; + + void checkReserved(const IR::Node* node, cstring nodeName, cstring kind) const { + auto it = reserved_names.find(nodeName); + if (it == reserved_names.end()) + return; + if (it->second != kind) + ::error("%1% cannot have this name; it can only be used for %2%", node, it->second); + } + void checkReserved(const IR::Node* node, cstring nodeName) const { + checkReserved(node, nodeName, nullptr); + } + + public: + explicit DiscoverStructure(ProgramStructure* structure) : structure(structure) + { CHECK_NULL(structure); setName("DiscoverStructure"); } + + void postorder(const IR::ParserException* ex) override { + ::warning(ErrorType::WARN_UNSUPPORTED, "%1%: parser exception is not translated to P4-16", + ex); } + void postorder(const IR::Metadata* md) override + { structure->metadata.emplace(md); checkReserved(md, md->name, "metadata"); } + void postorder(const IR::Header* hd) override + { structure->headers.emplace(hd); checkReserved(hd, hd->name); } + void postorder(const IR::Type_StructLike *t) override + { structure->types.emplace(t); checkReserved(t, t->name, "type"); } + void postorder(const IR::V1Control* control) override + { structure->controls.emplace(control); checkReserved(control, control->name, "control"); } + void postorder(const IR::V1Parser* parser) override + { structure->parserStates.emplace(parser); checkReserved(parser, parser->name); } + void postorder(const IR::V1Table* table) override + { structure->tables.emplace(table); checkReserved(table, table->name); } + void postorder(const IR::ActionFunction* action) override + { structure->actions.emplace(action); checkReserved(action, action->name); } + void postorder(const IR::HeaderStack* stack) override + { structure->stacks.emplace(stack); checkReserved(stack, stack->name); } + void postorder(const IR::Counter* count) override + { structure->counters.emplace(count); checkReserved(count, count->name); } + void postorder(const IR::Register* reg) override + { structure->registers.emplace(reg); checkReserved(reg, reg->name); } + void postorder(const IR::ActionProfile* ap) override + { structure->action_profiles.emplace(ap); checkReserved(ap, ap->name); } + void postorder(const IR::FieldList* fl) override + { structure->field_lists.emplace(fl); checkReserved(fl, fl->name); } + void postorder(const IR::FieldListCalculation* flc) override + { structure->field_list_calculations.emplace(flc); checkReserved(flc, flc->name); } + void postorder(const IR::CalculatedField* cf) override + { structure->calculated_fields.push_back(cf); } + void postorder(const IR::Meter* m) override + { structure->meters.emplace(m); checkReserved(m, m->name); } + void postorder(const IR::ActionSelector* as) override + { structure->action_selectors.emplace(as); checkReserved(as, as->name); } + void postorder(const IR::Type_Extern *ext) override + { structure->extern_types.emplace(ext); checkReserved(ext, ext->name); } + void postorder(const IR::Declaration_Instance *ext) override + { structure->externs.emplace(ext); checkReserved(ext, ext->name); } + void postorder(const IR::ParserValueSet* pvs) override + { structure->value_sets.emplace(pvs); checkReserved(pvs, pvs->name); } +}; + +class ComputeCallGraph : public Inspector { + ProgramStructure* structure; + + public: + explicit ComputeCallGraph(ProgramStructure* structure) : structure(structure) + { CHECK_NULL(structure); setName("ComputeCallGraph"); } + + void postorder(const IR::V1Parser* parser) override { + LOG3("Scanning parser " << parser->name); + structure->parsers.add(parser->name); + if (!parser->default_return.name.isNullOrEmpty()) + structure->parsers.calls(parser->name, parser->default_return); + if (parser->cases != nullptr) + for (auto ce : *parser->cases) + structure->parsers.calls(parser->name, ce->action.name); + for (auto expr : parser->stmts) { + if (expr->is()) { + auto primitive = expr->to(); + if (primitive->name == "extract") { + BUG_CHECK(primitive->operands.size() == 1, + "Expected 1 operand for %1%", primitive); + auto dest = primitive->operands.at(0); + LOG3("Parser " << parser->name << " extracts into " << dest); + structure->extracts[parser->name].push_back(dest); + } + } + } + } + void postorder(const IR::Primitive* primitive) override { + auto name = primitive->name; + const IR::GlobalRef *glob = nullptr; + const IR::Declaration_Instance *extrn = nullptr; + if (primitive->operands.size() >= 1) + glob = primitive->operands[0]->to(); + if (glob) extrn = glob->obj->to(); + + if (extrn) { + auto parent = findContext(); + BUG_CHECK(parent != nullptr, "%1%: Extern call not within action", primitive); + structure->calledExterns.calls(parent->name, extrn->name.name); + return; + } else if (primitive->name == "count") { + // counter invocation + auto ctrref = primitive->operands.at(0); + const IR::Counter *ctr = nullptr; + if (auto gr = ctrref->to()) + ctr = gr->obj->to(); + else if (auto nr = ctrref->to()) + ctr = structure->counters.get(nr->path->name); + if (ctr == nullptr) + ::error("Cannot find counter %1%", ctrref); + auto parent = findContext(); + BUG_CHECK(parent != nullptr, "%1%: Counter call not within action", primitive); + structure->calledCounters.calls(parent->name, ctr->name.name); + return; + } else if (primitive->name == "execute_meter") { + auto mtrref = primitive->operands.at(0); + const IR::Meter *mtr = nullptr; + if (auto gr = mtrref->to()) + mtr = gr->obj->to(); + else if (auto nr = mtrref->to()) + mtr = structure->meters.get(nr->path->name); + if (mtr == nullptr) + ::error("Cannot find meter %1%", mtrref); + auto parent = findContext(); + BUG_CHECK(parent != nullptr, + "%1%: not within action", primitive); + structure->calledMeters.calls(parent->name, mtr->name.name); + return; + } else if (primitive->name == "register_read" || primitive->name == "register_write") { + const IR::Expression* regref; + if (primitive->name == "register_read") + regref = primitive->operands.at(1); + else + regref = primitive->operands.at(0); + const IR::Register *reg = nullptr; + if (auto gr = regref->to()) + reg = gr->obj->to(); + else if (auto nr = regref->to()) + reg = structure->registers.get(nr->path->name); + if (reg == nullptr) + ::error("Cannot find register %1%", regref); + auto parent = findContext(); + BUG_CHECK(parent != nullptr, + "%1%: not within action", primitive); + structure->calledRegisters.calls(parent->name, reg->name.name); + return; + } else if (structure->actions.contains(name)) { + auto parent = findContext(); + BUG_CHECK(parent != nullptr, "%1%: Action call not within action", primitive); + structure->calledActions.calls(parent->name, name); + } else if (structure->controls.contains(name)) { + auto parent = findContext(); + BUG_CHECK(parent != nullptr, "%1%: Control call not within control", primitive); + structure->calledControls.calls(parent->name, name); + } + } + void postorder(const IR::GlobalRef *gref) override { + cstring caller; + if (auto af = findContext()) { + caller = af->name; + } else if (auto di = findContext()) { + caller = di->name; + } else { + BUG("%1%: GlobalRef not within action or extern", gref); } + if (auto ctr = gref->obj->to()) + structure->calledCounters.calls(caller, ctr->name.name); + else if (auto mtr = gref->obj->to()) + structure->calledMeters.calls(caller, mtr->name.name); + else if (auto reg = gref->obj->to()) + structure->calledRegisters.calls(caller, reg->name.name); + else if (auto ext = gref->obj->to()) + structure->calledExterns.calls(caller, ext->name.name); + } +}; + +/// Table call graph should be built after the control call graph is built. +/// In the case that the program contains an unused control block, the +/// table invocation in the unused control block should not be considered. +class ComputeTableCallGraph : public Inspector { ProgramStructure *structure; public: + explicit ComputeTableCallGraph(ProgramStructure *structure) : structure(structure) { + CHECK_NULL(structure); + setName("ComputeTableCallGraph"); + } + + void postorder(const IR::Apply *apply) override { + LOG3("Scanning " << apply->name); + auto tbl = structure->tables.get(apply->name.name); + if (tbl == nullptr) + ::error("Could not find table %1%", apply->name); + auto parent = findContext(); + ERROR_CHECK(parent != nullptr, "%1%: Apply not within a control block?", apply); + + auto ctrl = get(structure->tableMapping, tbl); + + // skip control block that is unused. + if (!structure->calledControls.isCallee(parent->name) && + parent->name != P4V1::V1Model::instance.ingress.name && + parent->name != P4V1::V1Model::instance.egress.name ) + return; + + if (ctrl != nullptr && ctrl != parent) { + auto previous = get(structure->tableInvocation, tbl); + ::error("Table %1% invoked from two different controls: %2% and %3%", + tbl, apply, previous); + } + LOG3("Invoking " << tbl << " in " << parent->name); + structure->tableMapping.emplace(tbl, parent); + structure->tableInvocation.emplace(tbl, apply); + } +}; + +class Rewriter : public Transform { + ProgramStructure* structure; + public: + explicit Rewriter(ProgramStructure* structure) : structure(structure) + { CHECK_NULL(structure); setName("Rewriter"); } + + const IR::Node* preorder(IR::V1Program* global) override { + if (LOGGING(4)) { + LOG4("#### Initial P4_14 program"); + dump(global); } + prune(); + auto *rv = structure->create(global->srcInfo); + if (LOGGING(4)) { + LOG4("#### Generated P4_16 program"); + dump(rv); } + return rv; + } +}; + +/** +This pass uses the @length annotation set by the v1 front-end on +varbit fields and converts extracts for headers with varbit fields. +This only supports headers with a single varbit field. +(The @length annotation is inserted as a conversion from the length +header property.) For example: + +header H { + bit<8> len; + @length(len) + varbit<64> data; +} +... +H h; +pkt.extract(h); + +is converted to: + +header H { + bit<8> len; + varbit<64> data; // annotation removed +} +... +H h; + +// Fixed-length size of H +header H_0 { + bit<8> len; +} + +H_0 h_0; +h_0 = pkt.lookahead(); +pkt.extract(h, h_0.len); + +*/ +class FixExtracts final : public Transform { + ProgramStructure* structure; + + struct HeaderSplit { + /// Fixed-size part of a header type (computed for each extract). + const IR::Type_Header* fixedHeaderType; + /// Expression computing the length of the variable-size header. + const IR::Expression* headerLength; + }; + + /// All newly-introduced types. + // The following vector contains only IR::Type_Header, but it is easier + // to append if the elements are Node. + IR::Vector allTypeDecls; + /// All newly-introduced variables, for each parser. + IR::IndexedVector varDecls; + /// Maps each original header type name to the fixed part of it. + std::map fixedPart; + + /// If a header type contains a varbit field then create a new + /// header type containing only the fields prior to the varbit. + /// Returns nullptr otherwise. + HeaderSplit* splitHeaderType(const IR::Type_Header* type) { + // Maybe we have seen this type already + auto fixed = ::get(fixedPart, type->name.name); + if (fixed != nullptr) + return fixed; + + const IR::Expression* headerLength = nullptr; + // We allocate the following when we find the first varbit field. + const IR::Type_Header* fixedHeaderType = nullptr; + IR::IndexedVector fields; + + for (auto f : type->fields) { + if (f->type->is()) { + cstring hname = structure->makeUniqueName(type->name); + if (fixedHeaderType != nullptr) { + ::error("%1%: header types with multiple varbit fields are not supported", + type); + return nullptr; + } + fixedHeaderType = new IR::Type_Header(IR::ID(hname), fields); + // extract length from annotation + auto anno = f->getAnnotation(IR::Annotation::lengthAnnotation); + BUG_CHECK(anno != nullptr, "No length annotation on varbit field", f); + BUG_CHECK(anno->expr.size() == 1, "Expected exactly 1 argument", anno->expr); + headerLength = anno->expr.at(0); + // We keep going through the loop just to check whether there is another + // varbit field in the header. + } else if (fixedHeaderType == nullptr) { + // We only keep the fields prior to the varbit field + fields.push_back(f); + } + } + if (fixedHeaderType != nullptr) { + LOG3("Extracted fixed-size header type from " << type << " into " << fixedHeaderType); + fixed = new HeaderSplit; + fixed->fixedHeaderType = fixedHeaderType; + fixed->headerLength = headerLength; + fixedPart.emplace(type->name.name, fixed); + allTypeDecls.push_back(fixedHeaderType); + return fixed; + } + return nullptr; + } + + /** + This pass rewrites expressions that appear in a @length + annotation: PathExpressions that refer to enclosing struct + fields are rewritten to refer to the proper fields of a + variable `var`. In the example above, the variable is `h_0` + and `len` is translated to `h_0.len`. + */ + class RewriteLength final : public Transform { + const IR::Type_Header* header; + const IR::Declaration* var; + public: + explicit RewriteLength(const IR::Type_Header* header, + const IR::Declaration* var) : + header(header), var(var) { setName("RewriteLength"); } + + const IR::Node* postorder(IR::PathExpression* expression) override { + if (expression->path->absolute) + return expression; + for (auto f : header->fields) { + if (f->name == expression->path->name) + return new IR::Member( + expression->srcInfo, + new IR::PathExpression(var->name), f->name); + } + return expression; + } + }; + + public: + explicit FixExtracts(ProgramStructure* structure) : structure(structure) + { CHECK_NULL(structure); setName("FixExtracts"); } + + const IR::Node* postorder(IR::P4Program* program) override { + // P4-14 headers cannot refer to other types, so it is safe + // to prepend them to the list of declarations. + allTypeDecls.append(program->objects); + program->objects = allTypeDecls; + return program; + } + + const IR::Node* postorder(IR::P4Parser* parser) override { + if (!varDecls.empty()) { + parser->parserLocals.append(varDecls); + varDecls.clear(); + } + return parser; + } + + const IR::Node* postorder(IR::MethodCallStatement* statement) override { + auto mce = getOriginal()->methodCall; + LOG3("Looking up in extracts " << dbp(mce)); + auto ht = ::get(structure->extractsSynthesized, mce); + if (ht == nullptr) + // not an extract + return statement; + + // This is an extract method invocation + BUG_CHECK(mce->arguments->size() == 1, "%1%: expected 1 argument", mce); + auto arg = mce->arguments->at(0); + + auto fixed = splitHeaderType(ht); + if (fixed == nullptr) + return statement; + CHECK_NULL(fixed->headerLength); + CHECK_NULL(fixed->fixedHeaderType); + + auto result = new IR::IndexedVector(); + cstring varName = structure->makeUniqueName("tmp_hdr"); + auto var = new IR::Declaration_Variable( + IR::ID(varName), fixed->fixedHeaderType->to()); + varDecls.push_back(var); + + // Create lookahead + auto member = mce->method->to(); // should be packet_in.extract + CHECK_NULL(member); + auto typeArgs = new IR::Vector(); + typeArgs->push_back(fixed->fixedHeaderType->getP4Type()); + auto lookaheadMethod = new IR::Member(member->expr, + P4::P4CoreLibrary::instance.packetIn.lookahead.name); + auto lookahead = new IR::MethodCallExpression( + mce->srcInfo, lookaheadMethod, typeArgs, new IR::Vector()); + auto assign = new IR::AssignmentStatement( + mce->srcInfo, new IR::PathExpression(varName), lookahead); + result->push_back(assign); + LOG3("Created lookahead " << assign); + + // Create actual extract + RewriteLength rewrite(fixed->fixedHeaderType, var); + auto length = fixed->headerLength->apply(rewrite); + auto args = new IR::Vector(); + args->push_back(arg->clone()); + auto type = IR::Type_Bits::get( + P4::P4CoreLibrary::instance.packetIn.extractSecondArgSize); + auto cast = new IR::Cast(Util::SourceInfo(), type, length); + args->push_back(new IR::Argument(cast)); + auto expression = new IR::MethodCallExpression( + mce->srcInfo, mce->method->clone(), args); + result->push_back(new IR::MethodCallStatement(expression)); + return result; + } +}; + +/* + This class is used to adjust the expressions in a @length + annotation on a varbit field. The P4-14 to P4-16 converter inserts + these annotations on the unique varbit field in a header; the + annotations are created from the header max_length and length + fields. The length annotation contains an expression which is used + to compute the length of the varbit field. The problem that we are + solving here is that expression semantics is different in P4-14 and + P4-16. Consider the canonical case of an IPv4 header: + + header_type ipv4_t { + fields { + version : 4; + ihl : 4; + // lots of other fields... + options: *; + } + length : ihl*4; + max_length : 64; + } + + This generates the following P4-16 structure: + struct ipv4_t { + bit<4> version; + bit<4> ihl; + @length((ihl*4) * 8 - 20) // 20 is the size of the fixed part of the header + varbit<(64 - 20) * 8> options; + } + + When such a header is used in an extract statement, the @length + annotation is used to compute the second argument of the extract + method. The problem we are solving here is the fact that ihl is + only represented on 4 bits, so the evaluation ihl*4 will actually + overflow. This is not a problem in P4-14, but it is a problem in + P4-16. Unfortunately there is no easy way to guess how many bits + are required to evaluate this computation. So what we do is to cast + all PathExpressions to 32-bits. This is really just a heuristic, + but since the semantics of P4-14 expressions is unclear, we cannot + do much better than this. +*/ +class AdjustLengths : public Transform { + public: + AdjustLengths() { setName("AdjustLengths"); } + const IR::Node* postorder(IR::PathExpression* expression) override { + auto anno = findContext(); + if (anno == nullptr) + return expression; + if (anno->name != "length") + return expression; + + LOG3("Inserting cast in length annotation"); + auto type = IR::Type_Bits::get(32); + auto cast = new IR::Cast(expression->srcInfo, type, expression); + return cast; + } +}; + +/// Detects whether there are two declarations in the P4-14 program +/// with the same name and for the same kind of object. +class DetectDuplicates: public Inspector { + public: + DetectDuplicates() { setName("DetectDuplicates"); } + + bool preorder(const IR::V1Program* program) override { + auto &map = program->scope; + auto firstWithKey = map.begin(); + while (firstWithKey != map.end()) { + auto key = firstWithKey->first; + auto range = map.equal_range(key); + for (auto s = range.first; s != range.second; s++) { + auto n = s; + for (n++; n != range.second; n++) { + auto e1 = s->second; + auto e2 = n->second; + if (e1->node_type_name() == e2->node_type_name()) { + if (e1->srcInfo.getStart().isValid()) + ::error("%1%: same name as %2%", e1, e2); + else + // This name is probably standard_metadata_t, a built-in declaration + ::error("%1%: name %2% is reserved", e2, key); + } + } + } + firstWithKey = range.second; + } + // prune; we're done; everything is top-level + return false; + } +}; + +// If a parser state has a pragma @packet_entry, it is treated as a new entry +// point to the parser. +class CheckIfMultiEntryPoint: public Inspector { + ProgramStructure* structure; + + public: + explicit CheckIfMultiEntryPoint(ProgramStructure* structure) : structure(structure) { + setName("CheckIfMultiEntryPoint"); + } + bool preorder(const IR::ParserState* state) { + for (const auto* anno : state->getAnnotations()->annotations) { + if (anno->name.name == "packet_entry") { + structure->parserEntryPoints.emplace(state->name, state); + } + } + return false; + } +}; + +// Generate a new start state that selects on the meta variable, +// standard_metadata.instance_type and branches into one of the entry points. +// The backend is responsible for removing the use of the meta variable and +// eliminate the new start state. The new start state is not added if the user +// does not use the @packet_entry pragma. +class InsertCompilerGeneratedStartState: public Transform { + ProgramStructure* structure; + IR::Vector allTypeDecls; + IR::IndexedVector varDecls; + IR::Vector selCases; + cstring newStartState; + cstring newInstanceType; + + public: + explicit InsertCompilerGeneratedStartState(ProgramStructure* structure) : structure(structure) { + setName("InsertCompilerGeneratedStartState"); + structure->allNames.emplace("start"); + structure->allNames.emplace("InstanceType"); + newStartState = structure->makeUniqueName("start"); + newInstanceType = structure->makeUniqueName("InstanceType"); + } + + const IR::Node* postorder(IR::P4Program* program) override { + allTypeDecls.append(program->objects); + program->objects = allTypeDecls; + return program; + } + + // rename original start state + const IR::Node* postorder(IR::ParserState* state) override { + if (!structure->parserEntryPoints.size()) + return state; + if (state->name == IR::ParserState::start) { + state->name = newStartState; + } + return state; + } + + const IR::Node* postorder(IR::P4Parser* parser) override { + if (!structure->parserEntryPoints.size()) + return parser; + IR::IndexedVector members; + // transition to original start state + members.push_back(new IR::SerEnumMember("START", new IR::Constant(0))); + selCases.push_back(new IR::SelectCase( + new IR::Member(new IR::TypeNameExpression(new IR::Type_Name(newInstanceType)), "START"), + new IR::PathExpression(new IR::Path(newStartState)))); + + // transition to addtional entry points + unsigned idx = 1; + for (auto p : structure->parserEntryPoints) { + members.push_back(new IR::SerEnumMember(p.first, new IR::Constant(idx++))); + selCases.push_back(new IR::SelectCase( + new IR::Member(new IR::TypeNameExpression(new IR::Type_Name(newInstanceType)), + p.first), + new IR::PathExpression(new IR::Path(p.second->name)))); + } + auto instAnnos = new IR::Annotations(); + instAnnos->add(new IR::Annotation(IR::Annotation::nameAnnotation, + {new IR::StringLiteral(IR::ID(".$InstanceType"))})); + auto instEnum = + new IR::Type_SerEnum(newInstanceType, instAnnos, IR::Type_Bits::get(32), members); + allTypeDecls.push_back(instEnum); + + IR::Vector selExpr; + selExpr.push_back( + new IR::Cast(new IR::Type_Name(newInstanceType), + new IR::Member(new IR::PathExpression(new IR::Path("standard_metadata")), + "instance_type"))); + auto selects = new IR::SelectExpression(new IR::ListExpression(selExpr), selCases); + auto annos = new IR::Annotations(); + annos->add(new IR::Annotation(IR::Annotation::nameAnnotation, + {new IR::StringLiteral(IR::ID(".$start"))})); + auto startState = new IR::ParserState(IR::ParserState::start, annos, selects); + varDecls.push_back(startState); + + if (!varDecls.empty()) { + parser->parserLocals.append(varDecls); + varDecls.clear(); + } + return parser; + } +}; + +/// Handle @packet_entry pragma in P4-14. A P4-14 program may be extended to +/// support multiple entry points to the parser. This feature does not comply +/// with P4-14 specification, but it is useful in certain use cases. +class FixMultiEntryPoint : public PassManager { + public: + explicit FixMultiEntryPoint(ProgramStructure* structure) { + setName("FixMultiEntryPoint"); + passes.emplace_back(new CheckIfMultiEntryPoint(structure)); + passes.emplace_back(new InsertCompilerGeneratedStartState(structure)); + } +}; + +/** + If the user metadata structure has a fields called + "intrinsic_metadata" or "queueing_metadata" move all their fields + to the standard_metadata Change all references appropriately. We + do this because the intrinsic_metadata and queueing_metadata are + handled specially in P4-14 programs - much more like + standard_metadata. +*/ +class MoveIntrinsicMetadata : public Transform { + ProgramStructure* structure; + const IR::Type_Struct* stdType = nullptr; + const IR::Type_Struct* userType = nullptr; + const IR::Type_Struct* intrType = nullptr; + const IR::Type_Struct* queueType = nullptr; + const IR::StructField* intrField = nullptr; + const IR::StructField* queueField = nullptr; + + public: + explicit MoveIntrinsicMetadata(ProgramStructure* structure): structure(structure) + { CHECK_NULL(structure); setName("MoveIntrinsicMetadata"); } + const IR::Node* preorder(IR::P4Program* program) override { + stdType = program->getDeclsByName( + structure->v1model.standardMetadataType.name)->single()->to(); + userType = program->getDeclsByName( + structure->v1model.metadataType.name)->single()->to(); + CHECK_NULL(stdType); + CHECK_NULL(userType); + intrField = userType->getField(structure->v1model.intrinsicMetadata.name); + if (intrField != nullptr) { + auto intrTypeName = intrField->type; + auto tn = intrTypeName->to(); + BUG_CHECK(tn, "%1%: expected a Type_Name", intrTypeName); + auto nt = program->getDeclsByName(tn->path->name)->nextOrDefault(); + if (nt == nullptr || !nt->is()) { + ::error("%1%: expected a structure", tn); + return program; + } + intrType = nt->to(); + LOG2("Intrinsic metadata type " << intrType); + } + + queueField = userType->getField(structure->v1model.queueingMetadata.name); + if (queueField != nullptr) { + auto queueTypeName = queueField->type; + auto tn = queueTypeName->to(); + BUG_CHECK(tn, "%1%: expected a Type_Name", queueTypeName); + auto nt = program->getDeclsByName(tn->path->name)->nextOrDefault(); + if (nt == nullptr || !nt->is()) { + ::error("%1%: expected a structure", tn); + return program; + } + queueType = nt->to(); + LOG2("Queueing metadata type " << queueType); + } + return program; + } + + const IR::Node* postorder(IR::Type_Struct* type) override { + if (getOriginal() == stdType) { + if (intrType != nullptr) { + for (auto f : intrType->fields) { + if (type->fields.getDeclaration(f->name) == nullptr) { + ::error("%1%: no such field in standard_metadata", f->name); + LOG2("standard_metadata: " << type); + } + } + } + if (queueType != nullptr) { + for (auto f : queueType->fields) { + if (type->fields.getDeclaration(f->name) == nullptr) { + ::error("%1%: no such field in standard_metadata", f->name); + LOG2("standard_metadata: " << type); + } + } + } + } + return type; + } + + const IR::Node* postorder(IR::StructField* field) override { + if (getOriginal() == intrField || getOriginal() == queueField) + // delete it from its parent + return nullptr; + return field; + } + + const IR::Node* postorder(IR::Member* member) override { + // We rewrite expressions like meta.intrinsic_metadata.x as + // standard_metadata.x. We know that these parameter names + // are always the same. + if (member->member != structure->v1model.intrinsicMetadata.name && + member->member != structure->v1model.queueingMetadata.name) + return member; + auto pe = member->expr->to(); + if (pe == nullptr || pe->path->absolute) + return member; + if (pe->path->name == structure->v1model.parser.metadataParam.name) { + LOG2("Renaming reference " << member); + return new IR::PathExpression( + new IR::Path(member->expr->srcInfo, + IR::ID(pe->path->name.srcInfo, + structure->v1model.standardMetadata.name))); + } + return member; + } +}; + +/////////////////////////////////////////////////////////////// + +// Is fed a P4-14 program and outputs an equivalent P4-16 program in v1model +class Converter : public PassManager { + public: + ProgramStructure *structure; static ProgramStructure *(*createProgramStructure)(); static ConversionContext *(*createConversionContext)(); Converter(); diff --git a/frontends/p4/fromv1.0/programStructure.cpp b/frontends/p4/fromv1.0/programStructure.cpp index 21d620e37f2..4bbaeb2a208 100644 --- a/frontends/p4/fromv1.0/programStructure.cpp +++ b/frontends/p4/fromv1.0/programStructure.cpp @@ -130,7 +130,8 @@ void ProgramStructure::createTypes() { // Metadata first for (auto it : metadata) { auto type = it.first->type; - if (systemHeaderTypes.count(type->name.name) != 0) + if (metadataTypes.count(type->externalName()) || + parameterTypes.count(type->externalName())) continue; createType(type, false, &converted); } @@ -166,7 +167,8 @@ void ProgramStructure::createTypes() { for (auto it : headers) { auto type = it.first->type; CHECK_NULL(type); - if (systemHeaderTypes.count(type->externalName()) != 0) + if (headerTypes.count(type->externalName()) || + parameterTypes.count(type->externalName())) continue; createType(type, true, &converted); } @@ -218,17 +220,17 @@ const IR::Type_Struct* ProgramStructure::createFieldListType(const IR::Expressio void ProgramStructure::createStructures() { auto metadata = new IR::Type_Struct(v1model.metadataType.Id()); for (auto it : this->metadata) { - if (systemHeaderTypes.count(it.first->type->name)) - continue; IR::ID id = it.first->name; auto type = it.first->type; + auto type_name = types.get(type); + if (metadataInstances.count(type_name)) + continue; auto h = headers.get(it.first->name); if (h != nullptr) ::warning(ErrorType::ERR_DUPLICATE, "header and metadata instances %2% with the same name", it.first, h); - auto type_name = types.get(type); - auto ht = type->to(); + auto ht = type->to(); auto path = new IR::Path(type_name); auto tn = new IR::Type_Name(ht->name.srcInfo, path); auto annos = addGlobalNameAnnotation(id, it.first->annotations); @@ -242,10 +244,9 @@ void ProgramStructure::createStructures() { IR::ID id = it.first->name; auto type = it.first->type; auto type_name = types.get(type); - // filter out headers defined in architecture - if (systemHeaderTypes.count(type_name)) + if (headerInstances.count(type_name)) continue; - auto ht = type->to(); + auto ht = type->to(); auto path = new IR::Path(type_name); auto tn = new IR::Type_Name(ht->name.srcInfo, path); auto annos = addGlobalNameAnnotation(id, it.first->annotations); @@ -373,8 +374,8 @@ const IR::PathExpression* ProgramStructure::getState(IR::ID dest) { } } -static const IR::Expression* -explodeLabel(const IR::Constant* value, const IR::Constant* mask, +const IR::Expression* +ProgramStructure::explodeLabel(const IR::Constant* value, const IR::Constant* mask, const std::vector &fieldTypes) { if (mask->value == 0) return new IR::DefaultExpression(value->srcInfo); @@ -400,8 +401,8 @@ explodeLabel(const IR::Constant* value, const IR::Constant* mask, return rv; } -static const IR::Type* -explodeType(const std::vector &fieldTypes) { +const IR::Type* +ProgramStructure::explodeType(const std::vector &fieldTypes) { auto rv = new IR::Vector(); for (auto it = fieldTypes.begin(); it != fieldTypes.end(); ++it) { rv->push_back(*it); @@ -483,7 +484,6 @@ const IR::ParserState* ProgramStructure::convertParser(const IR::V1Parser* parse } auto annos = addGlobalNameAnnotation(value_set->name, value_set->annotations); auto decl = new IR::P4ValueSet(value_set->name, annos, type, sizeConstant); - LOG1(decl); stateful->push_back(decl); } for (auto v : c->values) { @@ -592,7 +592,11 @@ void ProgramStructure::loadModel() { // This includes in turn core.p4 include("v1model.p4"); - systemHeaderTypes.insert(v1model.standardMetadataType.name); + metadataInstances.insert(v1model.standardMetadataType.name); + metadataTypes.insert(v1model.standardMetadataType.name); + headerInstances.insert(v1model.standardMetadataType.name); + headerTypes.insert(v1model.standardMetadataType.name); + parameterTypes.insert(v1model.standardMetadataType.name); } namespace { @@ -654,16 +658,14 @@ class HeaderRepresentation { }; } // namespace -void ProgramStructure::createDeparserInternal(IR::ID hdrType, - IR::ID hdrParam, IR::ID pktParam, IR::ID deparserId, +void ProgramStructure::createDeparserInternal( + IR::ID deparserId, + IR::Parameter* packetOut, + IR::Parameter* headers, std::vector extraParams = {}, - IR::Direction hdrDirection = IR::Direction::In, IR::IndexedVector controlLocals = {}, std::function fn = [](IR::BlockStatement* b){ return b; }) { - auto headpath = new IR::Path(hdrType); - auto headtype = new IR::Type_Name(headpath); - auto headers = new IR::Parameter(hdrParam, hdrDirection, headtype); auto hdrsParam = paramReference(headers); HeaderRepresentation hr(hdrsParam); @@ -721,12 +723,8 @@ void ProgramStructure::createDeparserInternal(IR::ID hdrType, startHeader); auto params = new IR::ParameterList; - auto poutpath = new IR::Path(p4lib.packetOut.Id()); - auto pouttype = new IR::Type_Name(poutpath); - auto packetOut = new IR::Parameter(pktParam, IR::Direction::None, pouttype); params->push_back(packetOut); params->push_back(headers); - conversionContext->header = paramReference(headers); for (auto p : extraParams) params->push_back(p); @@ -764,10 +762,18 @@ void ProgramStructure::createDeparserInternal(IR::ID hdrType, } void ProgramStructure::createDeparser() { - createDeparserInternal(v1model.headersType.Id(), - v1model.deparser.headersParam.Id(), - v1model.deparser.packetParam.Id(), - v1model.deparser.Id()); + auto poutpath = new IR::Path(p4lib.packetOut.Id()); + auto pouttype = new IR::Type_Name(poutpath); + auto packetOut = new IR::Parameter( + v1model.deparser.packetParam.Id(), IR::Direction::None, pouttype); + + auto headpath = new IR::Path(v1model.headersType.Id()); + auto headtype = new IR::Type_Name(headpath); + auto headers = new IR::Parameter( + v1model.deparser.headersParam.Id(), IR::Direction::In, headtype); + conversionContext->header = paramReference(headers); + + createDeparserInternal(v1model.deparser.Id(), packetOut, headers); } const IR::Declaration_Instance* diff --git a/frontends/p4/fromv1.0/programStructure.h b/frontends/p4/fromv1.0/programStructure.h index 0474177bc15..edbac987b40 100644 --- a/frontends/p4/fromv1.0/programStructure.h +++ b/frontends/p4/fromv1.0/programStructure.h @@ -121,7 +121,7 @@ class ProgramStructure { std::unordered_set allNames; NamedObjectInfo types; - NamedObjectInfo metadata; + NamedObjectInfo metadata; NamedObjectInfo headers; NamedObjectInfo stacks; NamedObjectInfo controls; @@ -173,8 +173,19 @@ class ProgramStructure { std::map parserEntryPoints; - /// system header type - std::set systemHeaderTypes; + // P4-14 struct/header type can be converted to three types + // of struct/header in P4-16. + // 1) as part of the 'hdr' struct + // 2) as part of the 'meta' struct + // 3) as the parameters of a parser/control block + // In case 1 and 2, the converter needs to fix the path + // by prepending 'hdr.' or 'meta.' to the ConcreteHeaderRef. + // In case 3. the converter only needs to convert headerRef to PathExpression + std::set headerTypes; + std::set metadataTypes; + std::set parameterTypes; + std::set metadataInstances; + std::set headerInstances; /// extra local instances to control created by primitive translation std::vector localInstances; @@ -251,8 +262,10 @@ class ProgramStructure { std::unordered_set *converted); virtual void createParser(); virtual void createControls(); - void createDeparserInternal(IR::ID hdrType, IR::ID hdrParam, IR::ID pktParam, IR::ID deparserId, - std::vector, IR::Direction, + void createDeparserInternal(IR::ID deparserId, + IR::Parameter* packetOut, + IR::Parameter* headers, + std::vector, IR::IndexedVector controlLocals, std::function); virtual void createDeparser(); @@ -280,6 +293,10 @@ class ProgramStructure { bool isHeader(const IR::ConcreteHeaderRef* nhr) const; cstring makeUniqueName(cstring base); + const IR::Type* explodeType(const std::vector &fieldTypes); + const IR::Expression* explodeLabel(const IR::Constant* value, const IR::Constant* mask, + const std::vector &fieldTypes); + virtual IR::Vector* createApplyArguments(cstring n); const IR::V1Control* ingress; diff --git a/frontends/p4/frontend.cpp b/frontends/p4/frontend.cpp index 9c5cb2c19dc..82dc170319b 100644 --- a/frontends/p4/frontend.cpp +++ b/frontends/p4/frontend.cpp @@ -209,8 +209,7 @@ const IR::P4Program *FrontEnd::run(const CompilerOptions &options, const IR::P4P passes.setName("FrontEnd"); passes.setStopOnError(true); - passes.addDebugHooks(hooks); - + passes.addDebugHooks(hooks, true); const IR::P4Program* result = program->apply(passes); return result; } diff --git a/test/gtest/diagnostics.cpp b/test/gtest/diagnostics.cpp index d32aa4c842b..d88491ccdc1 100644 --- a/test/gtest/diagnostics.cpp +++ b/test/gtest/diagnostics.cpp @@ -97,7 +97,7 @@ TEST_F(Diagnostics, P4_16_Error) { EXPECT_EQ(1u, ::errorCount()); } -TEST_F(Diagnostics, P4_14_Disable) { +TEST_F(Diagnostics, DISABLED_P4_14_Disable) { auto test = createP4_14DiagnosticsTestCase(P4_SOURCE(R"( @pragma diagnostic uninitialized_use disable )")); @@ -105,7 +105,7 @@ TEST_F(Diagnostics, P4_14_Disable) { EXPECT_EQ(0u, ::diagnosticCount()); } -TEST_F(Diagnostics, P4_14_Warn) { +TEST_F(Diagnostics, DISABLED_P4_14_Warn) { auto test = createP4_14DiagnosticsTestCase(P4_SOURCE(R"( @pragma diagnostic uninitialized_use warn )")); @@ -114,7 +114,7 @@ TEST_F(Diagnostics, P4_14_Warn) { EXPECT_EQ(0u, ::errorCount()); } -TEST_F(Diagnostics, P4_14_Error) { +TEST_F(Diagnostics, DISABLED_P4_14_Error) { auto test = createP4_14DiagnosticsTestCase(P4_SOURCE(R"( @pragma diagnostic uninitialized_use error )")); diff --git a/test/gtest/p4runtime.cpp b/test/gtest/p4runtime.cpp index 29371688aee..2556202725d 100644 --- a/test/gtest/p4runtime.cpp +++ b/test/gtest/p4runtime.cpp @@ -543,7 +543,7 @@ TEST_F(P4Runtime, P4_16_MatchFields) { } } -TEST_F(P4Runtime, P4_14_MatchFields) { +TEST_F(P4Runtime, DISABLED_P4_14_MatchFields) { using MatchField = p4configv1::MatchField; auto test = createP4RuntimeTestCase(P4_SOURCE(P4Headers::NONE, R"( From f4867ffa515455340211fc0f7a4caa3c6afa4073 Mon Sep 17 00:00:00 2001 From: Calin Cascaval Date: Fri, 4 Oct 2019 21:00:09 -0700 Subject: [PATCH 009/106] add a compiler option to disable specific annotations/pragmas Add the --disable-annotations option to disable annotations by name. It accepts a comma separated list of annotations that will not be added in the IR tree. A warning will be printed that the annotation was explicitly disabled. We do print the warning for every instance of the annotation, which may be an overkill, however, it is intentional, so that users can make sure that a particular annotation was not taken into account. The option only disable annotations present in the source file. Compiler passes may continue to add annotations and process them as before. Note that users may be able to disable annotations that may cripple the code generation -- backend or control-plane. That's another reason why it is important to print those warnings! --- frontends/common/options.cpp | 19 +++++++++++++++++++ frontends/common/options.h | 6 ++++++ frontends/parsers/p4/p4parser.ypp | 11 +++++++++-- frontends/parsers/parserDriver.cpp | 4 +++- tools/driver/p4c_src/driver.py | 4 ++++ tools/driver/p4c_src/main.py | 5 ++++- 6 files changed, 45 insertions(+), 4 deletions(-) diff --git a/frontends/common/options.cpp b/frontends/common/options.cpp index a4a88e55666..72fd21f4522 100644 --- a/frontends/common/options.cpp +++ b/frontends/common/options.cpp @@ -132,6 +132,16 @@ CompilerOptions::CompilerOptions() : Util::Options(defaultMessage) { return true; }, "Choose output format for the P4Runtime API description (default is binary).\n" "[Deprecated; use '--p4runtime-files' instead]."); + registerOption("--disable-annotations", "annotations", + [this](const char *arg) { + auto copy = strdup(arg); + while (auto name = strsep(©, ",")) + disabledAnnotations.insert(name); + return true; + }, + "Specify a (comma separated) list of annotations that should be ignored by\n" + "the compiler. A warning will be printed that the annotation is ignored", + OptionFlags::OptionalArgument); registerOption("--Wdisable", "diagnostic", [](const char *diagnostic) { if (diagnostic) { @@ -438,6 +448,15 @@ void CompilerOptions::dumpPass(const char* manager, unsigned seq, const char* pa } } +bool CompilerOptions::isAnnotationDisabled(const IR::Annotation *a) const { + if (disabledAnnotations.count(a->name.name) > 0) { + ::warning(ErrorType::WARN_IGNORE, + "%1% is ignored because it was explicitly disabled", a); + return true; + } + return false; +} + DebugHook CompilerOptions::getDebugHook() const { using namespace std::placeholders; auto dp = std::bind(&CompilerOptions::dumpPass, this, _1, _2, _3, _4); diff --git a/frontends/common/options.h b/frontends/common/options.h index 592ecaf0a13..0362a3686b2 100644 --- a/frontends/common/options.h +++ b/frontends/common/options.h @@ -19,6 +19,7 @@ limitations under the License. #ifndef FRONTENDS_COMMON_OPTIONS_H_ #define FRONTENDS_COMMON_OPTIONS_H_ +#include #include #include "lib/compile_context.h" #include "lib/cstring.h" @@ -39,6 +40,9 @@ class CompilerOptions : public Util::Options { bool close_input = false; static const char* defaultMessage; + // annotation names that are to be ignored by the compiler + std::set disabledAnnotations; + // Checks if parsed options make sense with respect to each-other. void validateOptions() const; @@ -139,6 +143,8 @@ class CompilerOptions : public Util::Options { // in the pass managers that are executed. DebugHook getDebugHook() const; + bool isAnnotationDisabled(const IR::Annotation *) const; + virtual bool enable_intrinsic_metadata_fix(); }; diff --git a/frontends/parsers/p4/p4parser.ypp b/frontends/parsers/p4/p4parser.ypp index ff5c82f64c4..7dd0dcc4494 100644 --- a/frontends/parsers/p4/p4parser.ypp +++ b/frontends/parsers/p4/p4parser.ypp @@ -39,6 +39,7 @@ limitations under the License. #include // NOLINT(build/include_order) #include "frontends/common/constantParsing.h" +#include "frontends/common/options.h" #include "ir/ir.h" #include "lib/cstring.h" #include "lib/source_file.h" @@ -440,8 +441,14 @@ optAnnotations ; annotations - : annotation { $$ = new IR::Vector(); $$->push_back($1); } - | annotations annotation { $$ = $1; $$->push_back($2); } + : annotation { + $$ = new IR::Vector(); + if (! P4CContext::get().options().isAnnotationDisabled($1)) + $$->push_back($1); } + | annotations annotation { + $$ = $1; + if (! P4CContext::get().options().isAnnotationDisabled($2)) + $$->push_back($2); } ; annotation diff --git a/frontends/parsers/parserDriver.cpp b/frontends/parsers/parserDriver.cpp index 7a97190ceaf..29390034a96 100644 --- a/frontends/parsers/parserDriver.cpp +++ b/frontends/parsers/parserDriver.cpp @@ -8,6 +8,7 @@ #include #include +#include "frontends/common/options.h" #include "frontends/common/constantFolding.h" #include "frontends/parsers/p4/p4lexer.hpp" #include "frontends/parsers/p4/p4AnnotationLexer.hpp" @@ -374,7 +375,8 @@ void V1ParserDriver::clearPragmas() { } void V1ParserDriver::addPragma(IR::Annotation* pragma) { - currentPragmas.push_back(pragma); + if (!P4CContext::get().options().isAnnotationDisabled(pragma)) + currentPragmas.push_back(pragma); } IR::Vector V1ParserDriver::takePragmasAsVector() { diff --git a/tools/driver/p4c_src/driver.py b/tools/driver/p4c_src/driver.py index ccef276bd68..375d6732af5 100644 --- a/tools/driver/p4c_src/driver.py +++ b/tools/driver/p4c_src/driver.py @@ -158,6 +158,10 @@ def process_command_line_options(self, opts): self.add_command_option('compiler', "--p4runtime-files {}".format(opts.p4runtime_files)) + # disable annotations + if opts.disabled_annos is not None: + self.add_command_option('compiler', + '--disable-annotations={}'.format(opts.disabled_annos)) # set developer options if (os.environ['P4C_BUILD_TYPE'] == "DEVELOPER"): for option in opts.log_levels: diff --git a/tools/driver/p4c_src/main.py b/tools/driver/p4c_src/main.py index 775b6f1e283..516675cb0f1 100644 --- a/tools/driver/p4c_src/main.py +++ b/tools/driver/p4c_src/main.py @@ -98,7 +98,7 @@ def main(): parser.add_argument("-a", "--arch", dest="arch", help="specify target architecture", action="store", default="v1model") - parser.add_argument("-c", dest="run_all", + parser.add_argument("-c", "--compile", dest="run_all", help="Only run preprocess, compile, and assemble steps", action="store_true", default=True) parser.add_argument("-D", dest="preprocessor_defines", @@ -144,6 +144,9 @@ def main(): dest="show_target_help", help="Display target specific command line options.", action="store_true", default=False) + parser.add_argument("--disable-annotations", "--disable-pragmas", + dest="disabled_annos", action="store", + help="List of annotations (comma separated) that should be ignored by the compiler.") parser.add_argument("-S", dest="run_till_assembler", help="Only run the preprocess and compilation steps", action="store_true", default=False) From 807c6feb06446e596f39e4042860c713b2174872 Mon Sep 17 00:00:00 2001 From: Calin Cascaval Date: Tue, 8 Oct 2019 11:24:13 -0700 Subject: [PATCH 010/106] dyslexic help For people like me who forget whether the option is singular or plural. --- tools/driver/p4c_src/main.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/driver/p4c_src/main.py b/tools/driver/p4c_src/main.py index 516675cb0f1..38d38796783 100644 --- a/tools/driver/p4c_src/main.py +++ b/tools/driver/p4c_src/main.py @@ -144,7 +144,8 @@ def main(): dest="show_target_help", help="Display target specific command line options.", action="store_true", default=False) - parser.add_argument("--disable-annotations", "--disable-pragmas", + parser.add_argument("--disable-annotations", "--disable-annotation", + "--disable-pragmas", "--disable-pragma", dest="disabled_annos", action="store", help="List of annotations (comma separated) that should be ignored by the compiler.") parser.add_argument("-S", dest="run_till_assembler", From 896b342da929ba70087ca86139c8fccaea028838 Mon Sep 17 00:00:00 2001 From: Calin Cascaval Date: Tue, 8 Oct 2019 12:10:17 -0700 Subject: [PATCH 011/106] detect whether the kernel header files are available and disable EBPF tests if not --- backends/ebpf/CMakeLists.txt | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/backends/ebpf/CMakeLists.txt b/backends/ebpf/CMakeLists.txt index 523f269efff..fd7a41a2871 100644 --- a/backends/ebpf/CMakeLists.txt +++ b/backends/ebpf/CMakeLists.txt @@ -50,6 +50,19 @@ set (P4C_EBPF_HDRS lower.h ) +# determine the kernel version +execute_process(COMMAND uname -r + OUTPUT_VARIABLE P4C_EBPF_KERNEL_VER + OUTPUT_STRIP_TRAILING_WHITESPACE + RESULT_VARIABLE rc) +message(STATUS "Detected kernel version: ${P4C_EBPF_KERNEL_VER}") +if (EXISTS /usr/src/linux-headers-${P4C_EBPF_KERNEL_VER}/include/uapi/linux) + include_directories(/usr/src/linux-headers-${P4C_EBPF_KERNEL_VER}/include/uapi/linux) + set (SUPPORTS_KERNEL True) +else() + set (SUPPORTS_KERNEL False) +endif() + add_cpplint_files(${CMAKE_CURRENT_SOURCE_DIR} "${P4C_EBPF_SRCS};${P4C_EBPF_HDRS}") set (P4C_EBPF_DIST_HEADERS p4include/ebpf_model.p4) @@ -94,8 +107,6 @@ set (EBPF_TEST_SUITES "${P4C_SOURCE_DIR}/testdata/p4_16_samples/*_ebpf.p4" ) -set (SUPPORTS_KERNEL True) - # Check if the kernel version is new enough to support ebpf features set (MIN_KERNEL 4.15.0) string (REGEX MATCH "[0-9]+[^-]*" KERNEL_VER ${CMAKE_SYSTEM}) From 70d393e6ee89f4fd29ab0ec192e6b975420dd398 Mon Sep 17 00:00:00 2001 From: Prathima Kotikalapudi <36422468+pkotikal@users.noreply.github.com> Date: Tue, 8 Oct 2019 23:07:21 -0700 Subject: [PATCH 012/106] Add pthreads to move to protobuf v3.6.1 (#2047) --- control-plane/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/control-plane/CMakeLists.txt b/control-plane/CMakeLists.txt index 8bd79741a74..259bbb01d11 100644 --- a/control-plane/CMakeLists.txt +++ b/control-plane/CMakeLists.txt @@ -100,5 +100,5 @@ set_source_files_properties (${CONTROLPLANE_SOURCES} PROPERTIES COMPILE_FLAGS "- set_source_files_properties (${P4RUNTIME_GEN_SRCS} PROPERTIES GENERATED TRUE) build_unified(CONTROLPLANE_SOURCES) add_library (controlplane STATIC ${CONTROLPLANE_SOURCES} ) -target_link_libraries (controlplane ${PROTOBUF_LIBRARY}) +target_link_libraries (controlplane ${PROTOBUF_LIBRARY} ${CMAKE_THREAD_LIBS_INIT}) add_dependencies (controlplane mkP4configdir genIR frontend) From 1eb850ff9ff19c2b4fda56e1dec6822e76405d56 Mon Sep 17 00:00:00 2001 From: Andy Fingerhut Date: Wed, 9 Oct 2019 13:32:48 -0700 Subject: [PATCH 013/106] Change that seems to enable EBPF back end to build on Ubuntu 16.04 (#2049) * Change that seems to enable EBPF back end to build on Ubuntu 16.04 --- backends/ebpf/CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/backends/ebpf/CMakeLists.txt b/backends/ebpf/CMakeLists.txt index fd7a41a2871..cfc7854885c 100644 --- a/backends/ebpf/CMakeLists.txt +++ b/backends/ebpf/CMakeLists.txt @@ -57,7 +57,6 @@ execute_process(COMMAND uname -r RESULT_VARIABLE rc) message(STATUS "Detected kernel version: ${P4C_EBPF_KERNEL_VER}") if (EXISTS /usr/src/linux-headers-${P4C_EBPF_KERNEL_VER}/include/uapi/linux) - include_directories(/usr/src/linux-headers-${P4C_EBPF_KERNEL_VER}/include/uapi/linux) set (SUPPORTS_KERNEL True) else() set (SUPPORTS_KERNEL False) From 474ea783d2adf41c1b424e04cb0dc1981ce4b124 Mon Sep 17 00:00:00 2001 From: Mihai Budiu Date: Wed, 9 Oct 2019 17:59:46 -0700 Subject: [PATCH 014/106] Disable kernel ebpf tests (#2050) --- backends/ebpf/CMakeLists.txt | 25 ++++++++++++++----------- backends/ebpf/targets/kernel_target.py | 4 ++-- 2 files changed, 16 insertions(+), 13 deletions(-) diff --git a/backends/ebpf/CMakeLists.txt b/backends/ebpf/CMakeLists.txt index cfc7854885c..728a85bb23c 100644 --- a/backends/ebpf/CMakeLists.txt +++ b/backends/ebpf/CMakeLists.txt @@ -50,17 +50,20 @@ set (P4C_EBPF_HDRS lower.h ) -# determine the kernel version -execute_process(COMMAND uname -r - OUTPUT_VARIABLE P4C_EBPF_KERNEL_VER - OUTPUT_STRIP_TRAILING_WHITESPACE - RESULT_VARIABLE rc) -message(STATUS "Detected kernel version: ${P4C_EBPF_KERNEL_VER}") -if (EXISTS /usr/src/linux-headers-${P4C_EBPF_KERNEL_VER}/include/uapi/linux) - set (SUPPORTS_KERNEL True) -else() - set (SUPPORTS_KERNEL False) -endif() +# # determine the kernel version +# execute_process(COMMAND uname -r +# OUTPUT_VARIABLE P4C_EBPF_KERNEL_VER +# OUTPUT_STRIP_TRAILING_WHITESPACE +# RESULT_VARIABLE rc) +# message(STATUS "Detected kernel version: ${P4C_EBPF_KERNEL_VER}") +# if (EXISTS /usr/src/linux-headers-${P4C_EBPF_KERNEL_VER}/include/uapi/linux) +# set (SUPPORTS_KERNEL True) +# else() +# set (SUPPORTS_KERNEL False) +# endif() +# The kernel-based ebpf tests seem to be broken, so we disable them +# The dependences on the kernel APIs are too brittle +set (SUPPORTS_KERNEL False) add_cpplint_files(${CMAKE_CURRENT_SOURCE_DIR} "${P4C_EBPF_SRCS};${P4C_EBPF_HDRS}") diff --git a/backends/ebpf/targets/kernel_target.py b/backends/ebpf/targets/kernel_target.py index a9cb8ab7e6c..8fbfed2abd1 100644 --- a/backends/ebpf/targets/kernel_target.py +++ b/backends/ebpf/targets/kernel_target.py @@ -42,9 +42,9 @@ def compile_dataplane(self): # Input eBPF byte code args += self.template + ".o " # The bpf program to attach to the interface - args += "BPFOBJ=" + self.template + ".o " + args += "BPFOBJ=" + self.template + ".o" # add the folder local to the P4 file to the list of includes - args += "INCLUDES+=-I" + os.path.dirname(self.options.p4filename) + args += " INCLUDES+=-I" + os.path.dirname(self.options.p4filename) errmsg = "Failed to compile the eBPF byte code:" return run_timeout(self.options.verbose, args, TIMEOUT, self.outputs, errmsg) From 3240e3e23d2a24c07c2f327ffd9b4b03a5705fae Mon Sep 17 00:00:00 2001 From: Andy Fingerhut Date: Sat, 19 Oct 2019 14:56:50 -0700 Subject: [PATCH 015/106] Correct import statement in ebpf target.py test running file (#2063) Change python import statement --- backends/ebpf/targets/target.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/backends/ebpf/targets/target.py b/backends/ebpf/targets/target.py index b2ce4e5768c..db118889225 100644 --- a/backends/ebpf/targets/target.py +++ b/backends/ebpf/targets/target.py @@ -26,8 +26,8 @@ import os import sys from glob import glob -from scapy.utils import rdpcap -from scapy.layers.all import RawPcapWriter +from scapy.utils import rdpcap, RawPcapWriter +from scapy.layers.all import * from ebpfstf import create_table_file, parse_stf_file # path to the tools folder of the compiler sys.path.insert(0, os.path.dirname( From 9d8907a479b1cc55cfd627be28cd371ca21df8fb Mon Sep 17 00:00:00 2001 From: Mihai Budiu Date: Tue, 22 Oct 2019 09:55:43 -0700 Subject: [PATCH 016/106] Make argument in only; fixes #2057 (#2061) * Make argument in only; fixes #2057 --- p4include/v1model.p4 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/p4include/v1model.p4 b/p4include/v1model.p4 index dd005ce6ba2..95cbf6b720c 100644 --- a/p4include/v1model.p4 +++ b/p4include/v1model.p4 @@ -415,7 +415,7 @@ extern Checksum16 { * may be supported). Must be a compile-time * constant. */ -extern void verify_checksum(in bool condition, in T data, inout O checksum, HashAlgorithm algo); +extern void verify_checksum(in bool condition, in T data, in O checksum, HashAlgorithm algo); /*** * Computes the checksum of the supplied data and writes it to the @@ -447,7 +447,7 @@ extern void update_checksum(in bool condition, in T data, inout O checksum * Calling verify_checksum_with_payload is only supported in the * VerifyChecksum control. */ -extern void verify_checksum_with_payload(in bool condition, in T data, inout O checksum, HashAlgorithm algo); +extern void verify_checksum_with_payload(in bool condition, in T data, in O checksum, HashAlgorithm algo); /** * update_checksum_with_payload is identical in all ways to From 53fd23c7251f64fef51ada7076bc81d0a139c9a2 Mon Sep 17 00:00:00 2001 From: Han Wang Date: Sun, 27 Oct 2019 13:31:52 +0800 Subject: [PATCH 017/106] =?UTF-8?q?remove=20test=5Fargs=20from=20p4c=5Fadd?= =?UTF-8?q?=5Ftest=5Fwith=5Fargs,=20always=20pass=20args=20throug=E2=80=A6?= =?UTF-8?q?=20(#2068)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backends/bmv2/CMakeLists.txt | 4 +++- cmake/P4CUtils.cmake | 8 ++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/backends/bmv2/CMakeLists.txt b/backends/bmv2/CMakeLists.txt index 0b92e83b1d1..83a70afc8b3 100644 --- a/backends/bmv2/CMakeLists.txt +++ b/backends/bmv2/CMakeLists.txt @@ -186,12 +186,14 @@ set (XFAIL_TESTS testdata/p4_16_samples/issue1882-1-bmv2.p4 # Uses non-constant array index testdata/p4_16_samples/issue1989-bmv2.p4 + # Use unknown extern, test should be added with args + testdata/p4_16_samples/extern-funcs-bmv2.p4 ) if (HAVE_SIMPLE_SWITCH) p4c_add_tests("bmv2" ${BMV2_DRIVER} "${BMV2_V1MODEL_TEST_SUITES}" "${XFAIL_TESTS}") add_library(extern_func_module MODULE EXCLUDE_FROM_ALL "${P4C_SOURCE_DIR}/testdata/extern_modules/extern-funcs-bmv2.cpp" ) - p4c_add_test_with_args("bmv2" ${BMV2_DRIVER} FALSE "bmv2_emit_externs" "testdata/p4_16_samples/extern-funcs-bmv2.p4" "-a --emit-externs --target-specific-switch-arg \"--load-modules ${CMAKE_CURRENT_BINARY_DIR}/libextern_func_module.so\" --init \"make extern_func_module\"" "") + p4c_add_test_with_args("bmv2" ${BMV2_DRIVER} FALSE "bmv2_emit_externs" "testdata/p4_16_samples/extern-funcs-bmv2.p4" "-a --emit-externs --target-specific-switch-arg \"--load-modules ${CMAKE_CURRENT_BINARY_DIR}/libextern_func_module.so\" --init \"make extern_func_module\"") else() MESSAGE(WARNING "BMv2 simple switch is not available, not adding v1model BMv2 tests") endif() diff --git a/cmake/P4CUtils.cmake b/cmake/P4CUtils.cmake index e525086cec9..6ffe9cb4edf 100644 --- a/cmake/P4CUtils.cmake +++ b/cmake/P4CUtils.cmake @@ -81,12 +81,12 @@ endmacro(p4c_test_set_name) # program with command line arguments ${args} # Sets the timeout on tests at 300s (for the slow Travis machines) # -macro(p4c_add_test_with_args tag driver isXfail alias p4test test_args cmake_args) +macro(p4c_add_test_with_args tag driver isXfail alias p4test cmake_args) set(__testfile "${P4C_BINARY_DIR}/${tag}/${p4test}.test") file (WRITE ${__testfile} "#! /bin/bash\n") file (APPEND ${__testfile} "# Generated file, modify with care\n\n") file (APPEND ${__testfile} "cd ${P4C_BINARY_DIR}\n") - file (APPEND ${__testfile} "${driver} ${P4C_SOURCE_DIR} ${test_args} \"$@\" ${P4C_SOURCE_DIR}/${p4test}") + file (APPEND ${__testfile} "${driver} ${P4C_SOURCE_DIR} \"$@\" ${P4C_SOURCE_DIR}/${p4test}") execute_process(COMMAND chmod +x ${__testfile}) p4c_test_set_name(__testname ${tag} ${alias}) separate_arguments(__args UNIX_COMMAND ${cmake_args}) @@ -127,10 +127,10 @@ macro(p4c_add_test_list tag driver tests xfail) foreach(t ${__test_list}) list (FIND __xfail_list ${t} __xfail_test) if(__xfail_test GREATER -1) - p4c_add_test_with_args (${tag} ${driver} TRUE ${t} ${t} "${ARGN}" "") + p4c_add_test_with_args (${tag} ${driver} TRUE ${t} ${t} "${ARGN}") math (EXPR __xfailCounter "${__xfailCounter} + 1") else() - p4c_add_test_with_args (${tag} ${driver} FALSE ${t} ${t} "${ARGN}" "") + p4c_add_test_with_args (${tag} ${driver} FALSE ${t} ${t} "${ARGN}") endif() # __xfail_test endforeach() # tests math (EXPR __testCounter "${__testCounter} + ${__nTests}") From 92d6e69d760eb86f0131a5f1a18808835ce2a763 Mon Sep 17 00:00:00 2001 From: Jed Liu Date: Mon, 28 Oct 2019 15:55:32 -0700 Subject: [PATCH 018/106] WIP: Add non-unified builds to Travis (#2031) * Add non-unified builds to Travis This should catch any compilation issues when unified compilation is disabled. * Add missing include. * Needs git * fix --- .travis.yml | 7 ++- Dockerfile | 57 ++------------------- backends/bmv2/common/deparser.cpp | 1 + tools/travis-build | 83 +++++++++++++++++++++++++++++++ 4 files changed, 94 insertions(+), 54 deletions(-) create mode 100644 tools/travis-build diff --git a/.travis.yml b/.travis.yml index c142d35c118..161c3183a16 100644 --- a/.travis.yml +++ b/.travis.yml @@ -25,7 +25,12 @@ before_install: install: - if [[ $TRAVIS_OS_NAME == 'linux' ]] ; then tools/start_ccache; fi - - if [[ $TRAVIS_OS_NAME == 'linux' ]] ; then docker build --network ccache_network -t p4c --build-arg IMAGE_TYPE=test . ; fi + # To flush out issues with unified vs. non-unified builds, do a non-unified + # build before continuing with the rest, which produces a unified build. + # This is done here on MacOS; for Linux, this is done in Dockerfile. + - if [[ $TRAVIS_OS_NAME == 'linux' ]] ; then docker build --network ccache_network -t p4c --build-arg IMAGE_TYPE=test --build-arg ENABLE_UNIFIED_COMPILATION=OFF . ; fi + - if [[ $TRAVIS_OS_NAME == 'linux' ]] ; then docker build --network ccache_network -t p4c --build-arg IMAGE_TYPE=test --build-arg ENABLE_UNIFIED_COMPILATION=ON . ; fi + - if [[ $TRAVIS_OS_NAME == 'osx' ]] ; then ./bootstrap.sh -DCMAKE_BUILD_TYPE=RELEASE -DENABLE_UNIFIED_COMPILATION=OFF && cd build && make -j2 && cd .. && git clean -xfd ; fi - if [[ $TRAVIS_OS_NAME == 'osx' ]] ; then ./bootstrap.sh -DCMAKE_BUILD_TYPE=RELEASE && cd build && make -j 2 ; fi script: diff --git a/Dockerfile b/Dockerfile index 62c4e2a39d8..cf93f6d99ac 100644 --- a/Dockerfile +++ b/Dockerfile @@ -11,59 +11,10 @@ ARG MAKEFLAGS=-j2 # removed from the image. ARG IMAGE_TYPE=build -ENV P4C_DEPS bison \ - build-essential \ - cmake \ - curl \ - flex \ - g++ \ - libboost-dev \ - libboost-graph-dev \ - libboost-iostreams1.58-dev \ - libfl-dev \ - libgc-dev \ - libgmp-dev \ - pkg-config \ - tcpdump -ENV P4C_EBPF_DEPS libpcap-dev \ - libelf-dev \ - llvm \ - clang \ - iproute2 \ - net-tools -ENV P4C_RUNTIME_DEPS cpp \ - libboost-graph1.58.0 \ - libboost-iostreams1.58.0 \ - libgc1c2 \ - libgmp10 \ - libgmpxx4ldbl \ - python -ENV P4C_PIP_PACKAGES ipaddr \ - pyroute2 \ - ply==3.8 \ - scapy==2.4.0 +# Whether to do a unified build. +ARG ENABLE_UNIFIED_COMPILATION=ON -# We install pip with get-pip.py (https://pip.pypa.io/en/stable/installing/) -# since the Ubuntu package manager's version of pip seems to be broken on Ubuntu -# 16.04. +# Delegate the build to tools/travis-build. COPY . /p4c/ WORKDIR /p4c/ -RUN apt-get update && \ - apt-get install -y --no-install-recommends $P4C_DEPS $P4C_EBPF_DEPS $P4C_RUNTIME_DEPS && \ - mkdir /tmp/pip && cd /tmp/pip && curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py && python get-pip.py && cd - && rm -rf /tmp/pip && \ - pip install $P4C_PIP_PACKAGES && \ - mkdir build && \ - cd build && \ - cmake .. '-DCMAKE_CXX_FLAGS:STRING=-O3' && \ - make && \ - make install && \ - /usr/local/bin/ccache -p -s && \ - ( \ - (test "$IMAGE_TYPE" = "build" && \ - apt-get purge -y $P4C_DEPS && \ - apt-get autoremove --purge -y && \ - rm -rf /p4c /var/cache/apt/* /var/lib/apt/lists/* && \ - echo 'Build image ready') || \ - (test "$IMAGE_TYPE" = "test" && \ - echo 'Test image ready') \ - ) +RUN chmod u+x tools/travis-build && tools/travis-build diff --git a/backends/bmv2/common/deparser.cpp b/backends/bmv2/common/deparser.cpp index 652da0d3d9e..3d60e6a6bb8 100644 --- a/backends/bmv2/common/deparser.cpp +++ b/backends/bmv2/common/deparser.cpp @@ -16,6 +16,7 @@ limitations under the License. #include "backend.h" #include "deparser.h" +#include "extern.h" namespace BMV2 { diff --git a/tools/travis-build b/tools/travis-build new file mode 100644 index 00000000000..8a32354cf64 --- /dev/null +++ b/tools/travis-build @@ -0,0 +1,83 @@ +#!/bin/bash + +# Script for building in a Docker container on Travis. + +set -e # Exit on error. + +export P4C_DEPS="bison \ + build-essential \ + cmake \ + curl \ + flex \ + g++ \ + libboost-dev \ + libboost-graph-dev \ + libboost-iostreams1.58-dev \ + libfl-dev \ + libgc-dev \ + libgmp-dev \ + pkg-config \ + tcpdump" + +export P4C_EBPF_DEPS="libpcap-dev \ + libelf-dev \ + llvm \ + clang \ + iproute2 \ + net-tools" + +export P4C_RUNTIME_DEPS="cpp \ + libboost-graph1.58.0 \ + libboost-iostreams1.58.0 \ + libgc1c2 \ + libgmp10 \ + libgmpxx4ldbl \ + python" + +export P4C_PIP_PACKAGES="ipaddr \ + pyroute2 \ + ply==3.8 \ + scapy==2.4.0" + +apt-get update +apt-get install -y --no-install-recommends \ + ${P4C_DEPS} \ + ${P4C_EBPF_DEPS} \ + ${P4C_RUNTIME_DEPS} \ + git + +# We install pip with get-pip.py (https://pip.pypa.io/en/stable/installing/) +# since the Ubuntu package manager's version of pip seems to be broken on +# Ubuntu 16.04. +mkdir /tmp/pip +cd /tmp/pip +curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py +python get-pip.py +cd - +rm -rf /tmp/pip + +pip install $P4C_PIP_PACKAGES + +function build() { + mkdir build + cd build + + cmake .. '-DCMAKE_CXX_FLAGS:STRING=-O3' "$@" + make +} + +build "-DENABLE_UNIFIED_COMPILATION=${ENABLE_UNIFIED_COMPILATION}" + +make install +/usr/local/bin/ccache -p -s + +if [[ "${IMAGE_TYPE}" == "build" ]] ; then + apt-get purge -y ${P4C_DEPS} git + apt-get autoremove --purge -y + rm -rf /p4c /var/cache/apt/* /var/lib/apt/lists/* + echo 'Build image ready' + +elif [[ "${IMAGE_TYPE}" == "test" ]] ; then + echo 'Test image ready' + +fi From 0bbcc6b7f0140d94c66381debd369b7e4152229c Mon Sep 17 00:00:00 2001 From: Chris Dodd Date: Wed, 30 Oct 2019 09:30:02 -0700 Subject: [PATCH 019/106] Logging prettification (#2072) --- ir/dbprint-expression.cpp | 8 +++---- ir/dbprint-p4.cpp | 48 +++++++++++++++++++-------------------- ir/dbprint-stmt.cpp | 8 +++---- ir/dbprint-type.cpp | 4 ++-- ir/dbprint.cpp | 10 ++++---- lib/log.h | 5 ++-- 6 files changed, 42 insertions(+), 41 deletions(-) diff --git a/ir/dbprint-expression.cpp b/ir/dbprint-expression.cpp index 07d81f1a95d..180f25d3b17 100644 --- a/ir/dbprint-expression.cpp +++ b/ir/dbprint-expression.cpp @@ -89,7 +89,7 @@ void IR::NamedExpression::dbprint(std::ostream &out) const { void IR::StructInitializerExpression::dbprint(std::ostream& out) const { out << "{" << indent; for (auto &field : components) - out << endl << field << ';'; + out << Log::endl << field << ';'; out << " }" << unindent; } @@ -110,7 +110,7 @@ void IR::If::dbprint(std::ostream &out) const { out << "if (" << setprec(Prec_Low) << pred << ") {" << indent << setprec(0) << ifTrue; if (ifFalse) { if (!ifFalse->empty()) - out << unindent << endl << "} else {" << indent; + out << unindent << Log::endl << "} else {" << indent; out << ifFalse; } out << " }" << unindent; } @@ -122,7 +122,7 @@ void IR::Apply::dbprint(std::ostream &out) const { if (!actions.empty()) { out << " {" << indent << setprec(0); for (auto act : actions) - out << endl << act.first << " {" << indent << act.second << unindent << " }"; + out << Log::endl << act.first << " {" << indent << act.second << unindent << " }"; out << setprec(prec) << " }" << unindent; } else if (prec == 0) { out << ';'; } @@ -251,6 +251,6 @@ void IR::SelectExpression::dbprint(std::ostream &out) const { int prec = getprec(out); out << "select" << setprec(Prec_Low) << select << " {" << indent; for (auto c : selectCases) - out << endl << c; + out << Log::endl << c; out << " }" << unindent << setprec(prec); } diff --git a/ir/dbprint-p4.cpp b/ir/dbprint-p4.cpp index da4a4b6de7d..fb867c9e016 100644 --- a/ir/dbprint-p4.cpp +++ b/ir/dbprint-p4.cpp @@ -32,9 +32,9 @@ void IR::HeaderStackItemRef::dbprint(std::ostream &out) const { void IR::FieldList::dbprint(std::ostream &out) const { out << "field_list " << name << " {" << indent; for (auto f : fields) - out << endl << f; + out << Log::endl << f; if (payload) - out << endl << "payload;"; + out << Log::endl << "payload;"; out << unindent << " }"; } void IR::FieldListCalculation::dbprint(std::ostream &out) const { @@ -49,7 +49,7 @@ void IR::CalculatedField::dbprint(std::ostream &out) const { } out << indent; for (auto &spec : specs) { - out << endl << (spec.update ? "update " : "verify ") << spec.name; + out << Log::endl << (spec.update ? "update " : "verify ") << spec.name; if (spec.cond) out << " if " << spec.cond; } out << unindent; } @@ -74,35 +74,35 @@ void IR::CaseEntry::dbprint(std::ostream &out) const { void IR::V1Parser::dbprint(std::ostream &out) const { out << "parser " << name << " {" << indent; for (auto &stmt : stmts) - out << endl << *stmt; + out << Log::endl << *stmt; if (select) { int prec = getprec(out); const char *sep = ""; - out << endl << "select (" << setprec(Prec_Low); + out << Log::endl << "select (" << setprec(Prec_Low); for (auto e : *select) { out << sep << *e; sep = ", "; } out << ") {" << indent << setprec(prec); } if (cases) for (auto c : *cases) - out << endl << *c; + out << Log::endl << *c; if (select) out << " }" << unindent; if (default_return) - out << endl << "return " << default_return << ";"; + out << Log::endl << "return " << default_return << ";"; if (parse_error) - out << endl << "error " << parse_error << ";"; + out << Log::endl << "error " << parse_error << ";"; if (drop) - out << endl << "drop;"; + out << Log::endl << "drop;"; out << " }" << unindent; } void IR::ParserException::dbprint(std::ostream &out) const { out << "IR::ParserException"; } void IR::ParserState::dbprint(std::ostream &out) const { out << "state " << name << " " << annotations << "{" << indent; for (auto s : components) - out << endl << s; + out << Log::endl << s; if (selectExpression) - out << endl << selectExpression; + out << Log::endl << selectExpression; out << " }" << unindent; } void IR::P4Parser::dbprint(std::ostream &out) const { @@ -114,9 +114,9 @@ void IR::P4Parser::dbprint(std::ostream &out) const { out << '(' << constructorParams << ')'; out << " " << type->annotations << "{" << indent; for (auto d : parserLocals) - out << endl << d; + out << Log::endl << d; for (auto s : states) - out << endl << s; + out << Log::endl << s; out << " }" << unindent; } @@ -134,7 +134,7 @@ void IR::ActionFunction::dbprint(std::ostream &out) const { sep = ", "; } out << ") {" << indent; for (auto &p : action) - out << endl << p; + out << Log::endl << p; out << unindent << " }"; } @@ -147,7 +147,7 @@ void IR::P4Action::dbprint(std::ostream &out) const { out << ") {" << indent; if (body) for (auto p : body->components) - out << endl << p; + out << Log::endl << p; out << unindent << " }"; } @@ -159,7 +159,7 @@ void IR::BlockStatement::dbprint(std::ostream &out) const { out << ' ' << p; first = false; } else { - out << endl << p; } } + out << Log::endl << p; } } out << unindent << " }"; } @@ -174,7 +174,7 @@ void IR::ActionList::dbprint(std::ostream &out) const { if (first) out << ' ' << el; else - out << endl << el; + out << Log::endl << el; first = false; } out << unindent << " }"; } @@ -190,7 +190,7 @@ void IR::Key::dbprint(std::ostream &out) const { if (first) out << ' ' << el; else - out << endl << el; + out << Log::endl << el; first = false; } out << unindent << " }"; } @@ -198,7 +198,7 @@ void IR::P4Table::dbprint(std::ostream &out) const { out << "table " << name; out << " " << annotations << "{" << indent; for (auto p : properties->properties) - out << endl << p; + out << Log::endl << p; out << " }" << unindent; } @@ -220,20 +220,20 @@ void IR::P4Control::dbprint(std::ostream &out) const { out << '(' << constructorParams << ')'; out << " " << type->annotations << "{" << indent; for (auto d : controlLocals) - out << endl << d; + out << Log::endl << d; for (auto s : body->components) - out << endl << s; + out << Log::endl << s; out << " }" << unindent; } void IR::V1Program::dbprint(std::ostream &out) const { for (auto &obj : Values(scope)) - out << obj << endl; + out << obj << Log::endl; } void IR::P4Program::dbprint(std::ostream &out) const { for (auto obj : objects) - out << obj << endl; + out << obj << Log::endl; } void IR::Type_Error::dbprint(std::ostream &out) const { @@ -267,6 +267,6 @@ void IR::Declaration_Instance::dbprint(std::ostream &out) const { if (!properties.empty()) { out << " {" << indent; for (auto &obj : properties) - out << endl << obj.second; + out << Log::endl << obj.second; out << " }" << unindent; } } diff --git a/ir/dbprint-stmt.cpp b/ir/dbprint-stmt.cpp index 5df48403402..345b8fbc857 100644 --- a/ir/dbprint-stmt.cpp +++ b/ir/dbprint-stmt.cpp @@ -37,9 +37,9 @@ void IR::AssignmentStatement::dbprint(std::ostream &out) const { void IR::IfStatement::dbprint(std::ostream &out) const { int prec = getprec(out); - out << Prec_Low << "if (" << condition << ") {" << indent << setprec(0) << endl << ifTrue; + out << Prec_Low << "if (" << condition << ") {" << indent << setprec(0) << Log::endl << ifTrue; if (ifFalse) - out << unindent << endl << "} else {" << indent << endl << ifFalse; + out << unindent << Log::endl << "} else {" << indent << Log::endl << ifFalse; out << " }" << unindent << setprec(prec); } @@ -56,7 +56,7 @@ void IR::Function::dbprint(std::ostream &out) const { out << type->typeParameters; out << "(" << type->parameters << ") {" << indent; for (auto s : body->components) - out << endl << s; + out << Log::endl << s; out << unindent << " }"; } @@ -65,7 +65,7 @@ void IR::SwitchStatement::dbprint(std::ostream &out) const { out << Prec_Low << "switch (" << expression << ") {" << indent; bool fallthrough = false; for (auto c : cases) { - if (!fallthrough) out << endl; + if (!fallthrough) out << Log::endl; out << Prec_Low << c->label << ": " << setprec(0); if (c->statement) { out << c->statement; diff --git a/ir/dbprint-type.cpp b/ir/dbprint-type.cpp index 366cb3950e9..e7b7a87d72a 100644 --- a/ir/dbprint-type.cpp +++ b/ir/dbprint-type.cpp @@ -115,7 +115,7 @@ void IR::Type_Extern::dbprint(std::ostream& out) const { out << typeParameters; out << " {" << indent << clrflag(Brief); for (auto &method : methods) - out << endl << method << ';'; + out << Log::endl << method << ';'; out << " }" << unindent; } @@ -142,7 +142,7 @@ void IR::Type_StructLike::dbprint(std::ostream &out) const { return; } out << toString() << " " << annotations << "{" << indent; for (auto &field : fields) - out << endl << field << ';'; + out << Log::endl << field << ';'; out << " }" << unindent; } diff --git a/ir/dbprint.cpp b/ir/dbprint.cpp index 27940821941..2e2a205c7b8 100644 --- a/ir/dbprint.cpp +++ b/ir/dbprint.cpp @@ -64,12 +64,12 @@ void IR::Block::dbprint_recursive(std::ostream& out) const { out << indent; for (auto it : constantValue) { if (it.second == nullptr) { - out << endl << dbp(it.first) << " => null"; + out << Log::endl << dbp(it.first) << " => null"; continue; } if (it.second->is() && it.first->is()) { auto block = it.second->to(); - out << endl << dbp(it.first) << " => "; + out << Log::endl << dbp(it.first) << " => "; block->dbprint_recursive(out); } } @@ -84,7 +84,7 @@ std::ostream &operator<<(std::ostream &out, const IR::Vector &v) return out; } out << "{"; } for (auto e : v) - out << endl << setprec(0) << e << setprec(prec); + out << Log::endl << setprec(0) << e << setprec(prec); if (prec) out << " }"; return out; @@ -99,6 +99,6 @@ void dbprint(const IR::Node &n) { void dbprint(const std::set s) { std::cout << indent << " {"; int i = 0; - for (auto el : s) std::cout << endl << '[' << i++ << "] " << el; - std::cout << " }" << unindent << std::endl; + for (auto el : s) std::cout << Log::endl << '[' << i++ << "] " << el; + std::cout << " }" << unindent << Log::endl; } diff --git a/lib/log.h b/lib/log.h index 087e54cd0f6..973677ae67b 100644 --- a/lib/log.h +++ b/lib/log.h @@ -115,8 +115,9 @@ void increaseVerbosity(); #define LOG9_UNINDENT LOGN_UNINDENT(9) #define LOG_FEATURE(TAG, N, X) (::Log::fileLogLevelIsAtLeast(TAG, N) \ - ? std::clog << ::Log::Detail::OutputLogPrefix(TAG, N) \ - << X << std::endl \ + ? ::Log::Detail::fileLogOutput(TAG) \ + << ::Log::Detail::OutputLogPrefix(TAG, N) \ + << X << std::endl \ : std::clog) #define ERROR(X) (std::clog << "ERROR: " << X << std::endl) From 9da3711fd25bf5a5fc00962ebeca4a315ee68f99 Mon Sep 17 00:00:00 2001 From: Chris Dodd Date: Wed, 30 Oct 2019 10:50:14 -0700 Subject: [PATCH 020/106] clean up remove_if/erase_if a bit (#2058) --- ir/base.def | 6 ++---- lib/algorithm.h | 15 +++++++-------- 2 files changed, 9 insertions(+), 12 deletions(-) diff --git a/ir/base.def b/ir/base.def index ef5af68847d..2b1b358e9b9 100644 --- a/ir/base.def +++ b/ir/base.def @@ -295,10 +295,8 @@ class Annotations { // Add this annotation. Annotations addOrReplace(cstring name, Expression expr) const { auto rv = clone(); - auto &vec = rv->annotations; - vec.resize(std::remove_if(vec.begin(), vec.end(), - [name](const Annotation *a)->bool { return a->name == name; }) - vec.begin()); - vec.push_back(new Annotation(name, Vector(expr))); + remove_if(rv->annotations, [name](const Annotation *a)->bool { return a->name == name; }); + rv->annotations.push_back(new Annotation(name, Vector(expr))); return rv; } #emit typedef std::function Filter; diff --git a/lib/algorithm.h b/lib/algorithm.h index 709ff4f1477..ccfcd851b6b 100644 --- a/lib/algorithm.h +++ b/lib/algorithm.h @@ -35,19 +35,18 @@ template inline bool contains_if(C &c, Pred pred) { return std::find_if(c.begin(), c.end(), pred) != c.end(); } -template, class Alloc = std::allocator> -inline void remove_if(std::set &set, Pred pred) { - auto it = set.begin(); - while (it != set.end()) +template +inline void erase_if(C &c, Pred pred) { + for (auto it = c.begin(); it != c.end();) { if (pred(*it)) - it = set.erase(it); + it = c.erase(it); else - ++it; + ++it; } } template -inline typename C::iterator remove_if(C &c, Pred pred) { - return std::remove_if(c.begin(), c.end(), pred); } +inline void remove_if(C &c, Pred pred) { + c.erase(std::remove_if(c.begin(), c.end(), pred), c.end()); } template inline typename C::iterator find(C &c, const T &val) { From 550708f9b1cbf0ea1fc4550bb11454842ad6984a Mon Sep 17 00:00:00 2001 From: Chris Dodd Date: Wed, 30 Oct 2019 18:56:35 -0700 Subject: [PATCH 021/106] Do unified and non-unified builds in separate Travis instances (#2076) - avoid Travis 50 minute timeout --- .travis.yml | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/.travis.yml b/.travis.yml index 161c3183a16..ca94520a162 100644 --- a/.travis.yml +++ b/.travis.yml @@ -18,6 +18,9 @@ cache: env: - CTEST_PARALLEL_LEVEL=4 + UNIFIED=ON + - CTEST_PARALLEL_LEVEL=4 + UNIFIED=OFF before_install: - tools/install_os_deps.sh @@ -28,11 +31,9 @@ install: # To flush out issues with unified vs. non-unified builds, do a non-unified # build before continuing with the rest, which produces a unified build. # This is done here on MacOS; for Linux, this is done in Dockerfile. - - if [[ $TRAVIS_OS_NAME == 'linux' ]] ; then docker build --network ccache_network -t p4c --build-arg IMAGE_TYPE=test --build-arg ENABLE_UNIFIED_COMPILATION=OFF . ; fi - - if [[ $TRAVIS_OS_NAME == 'linux' ]] ; then docker build --network ccache_network -t p4c --build-arg IMAGE_TYPE=test --build-arg ENABLE_UNIFIED_COMPILATION=ON . ; fi - - if [[ $TRAVIS_OS_NAME == 'osx' ]] ; then ./bootstrap.sh -DCMAKE_BUILD_TYPE=RELEASE -DENABLE_UNIFIED_COMPILATION=OFF && cd build && make -j2 && cd .. && git clean -xfd ; fi - - if [[ $TRAVIS_OS_NAME == 'osx' ]] ; then ./bootstrap.sh -DCMAKE_BUILD_TYPE=RELEASE && cd build && make -j 2 ; fi + - if [[ $TRAVIS_OS_NAME == 'linux' ]] ; then docker build --network ccache_network -t p4c --build-arg IMAGE_TYPE=test --build-arg ENABLE_UNIFIED_COMPILATION=$UNIFIED . ; fi + - if [[ $TRAVIS_OS_NAME == 'osx' ]] ; then ./bootstrap.sh -DCMAKE_BUILD_TYPE=RELEASE -DENABLE_UNIFIED_COMPILATION=$UNIFIED && cd build && make -j2; fi script: - - if [[ $TRAVIS_OS_NAME == 'linux' ]] ; then docker run -w /p4c/build -e CTEST_PARALLEL_LEVEL p4c ctest --output-on-failure --schedule-random ; fi - - if [[ $TRAVIS_OS_NAME == 'osx' ]] ; then ctest --output-on-failure -j 2 --schedule-random -LE "ebpf$" ; fi + - if [[ $TRAVIS_OS_NAME == 'linux' && $UNIFIED == ON ]] ; then docker run -w /p4c/build -e CTEST_PARALLEL_LEVEL p4c ctest --output-on-failure --schedule-random ; fi + - if [[ $TRAVIS_OS_NAME == 'osx' && $UNIFIED == ON ]] ; then ctest --output-on-failure -j 2 --schedule-random -LE "ebpf$" ; fi From ebde76c05d14edbea62add9675b973eb0e6fc56c Mon Sep 17 00:00:00 2001 From: Chris Dodd Date: Thu, 31 Oct 2019 09:42:35 -0700 Subject: [PATCH 022/106] Compile-time MAX_LOGGING_LEVEL (#2074) --- CMakeLists.txt | 4 ++++ lib/log.h | 9 +++++++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 6b1123ce7ea..86cf04e4346 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -38,6 +38,10 @@ OPTION (ENABLE_PROTOBUF_STATIC "Link against Protobuf statically" ON) OPTION (ENABLE_GC "Use libgc" ON) OPTION (ENABLE_MULTITHREAD "Use multithreading" OFF) +set(MAX_LOGGING_LEVEL 10 CACHE STRING "Control the maximum logging level for -T logs") +set_property(CACHE MAX_LOGGING_LEVEL PROPERTY STRINGS 0 1 2 3 4 5 6 7 8 9 10) +add_definitions(-DMAX_LOGGING_LEVEL=${MAX_LOGGING_LEVEL}) + if (NOT CMAKE_BUILD_TYPE) set (CMAKE_BUILD_TYPE "RELEASE") endif() diff --git a/lib/log.h b/lib/log.h index 973677ae67b..b93b5575cba 100644 --- a/lib/log.h +++ b/lib/log.h @@ -86,7 +86,12 @@ void increaseVerbosity(); } // namespace Log -#define LOGGING(N) (::Log::fileLogLevelIsAtLeast(__FILE__, N)) +#ifndef MAX_LOGGING_LEVEL +// can be set on build command line and disables higher logging levels at compile time +#define MAX_LOGGING_LEVEL 10 +#endif + +#define LOGGING(N) ((N) <= MAX_LOGGING_LEVEL && ::Log::fileLogLevelIsAtLeast(__FILE__, N)) #define LOGN(N, X) (LOGGING(N) \ ? ::Log::Detail::fileLogOutput(__FILE__) \ << ::Log::Detail::OutputLogPrefix(__FILE__, N) \ @@ -114,7 +119,7 @@ void increaseVerbosity(); #define LOG8_UNINDENT LOGN_UNINDENT(8) #define LOG9_UNINDENT LOGN_UNINDENT(9) -#define LOG_FEATURE(TAG, N, X) (::Log::fileLogLevelIsAtLeast(TAG, N) \ +#define LOG_FEATURE(TAG, N, X) ((N) <= MAX_LOGGING_LEVEL && ::Log::fileLogLevelIsAtLeast(TAG, N) \ ? ::Log::Detail::fileLogOutput(TAG) \ << ::Log::Detail::OutputLogPrefix(TAG, N) \ << X << std::endl \ From ad2d2586d8ed1a182f4a8dc68341ef97b1ede72a Mon Sep 17 00:00:00 2001 From: Han Wang Date: Sat, 2 Nov 2019 02:42:37 +0800 Subject: [PATCH 023/106] =?UTF-8?q?Revert=20"remove=20test=5Fargs=20from?= =?UTF-8?q?=20p4c=5Fadd=5Ftest=5Fwith=5Fargs,=20always=20pass=20args=20thr?= =?UTF-8?q?oug=E2=80=A6=20(#2068)"=20(#2077)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 53fd23c7251f64fef51ada7076bc81d0a139c9a2. --- backends/bmv2/CMakeLists.txt | 4 +--- cmake/P4CUtils.cmake | 8 ++++---- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/backends/bmv2/CMakeLists.txt b/backends/bmv2/CMakeLists.txt index 83a70afc8b3..0b92e83b1d1 100644 --- a/backends/bmv2/CMakeLists.txt +++ b/backends/bmv2/CMakeLists.txt @@ -186,14 +186,12 @@ set (XFAIL_TESTS testdata/p4_16_samples/issue1882-1-bmv2.p4 # Uses non-constant array index testdata/p4_16_samples/issue1989-bmv2.p4 - # Use unknown extern, test should be added with args - testdata/p4_16_samples/extern-funcs-bmv2.p4 ) if (HAVE_SIMPLE_SWITCH) p4c_add_tests("bmv2" ${BMV2_DRIVER} "${BMV2_V1MODEL_TEST_SUITES}" "${XFAIL_TESTS}") add_library(extern_func_module MODULE EXCLUDE_FROM_ALL "${P4C_SOURCE_DIR}/testdata/extern_modules/extern-funcs-bmv2.cpp" ) - p4c_add_test_with_args("bmv2" ${BMV2_DRIVER} FALSE "bmv2_emit_externs" "testdata/p4_16_samples/extern-funcs-bmv2.p4" "-a --emit-externs --target-specific-switch-arg \"--load-modules ${CMAKE_CURRENT_BINARY_DIR}/libextern_func_module.so\" --init \"make extern_func_module\"") + p4c_add_test_with_args("bmv2" ${BMV2_DRIVER} FALSE "bmv2_emit_externs" "testdata/p4_16_samples/extern-funcs-bmv2.p4" "-a --emit-externs --target-specific-switch-arg \"--load-modules ${CMAKE_CURRENT_BINARY_DIR}/libextern_func_module.so\" --init \"make extern_func_module\"" "") else() MESSAGE(WARNING "BMv2 simple switch is not available, not adding v1model BMv2 tests") endif() diff --git a/cmake/P4CUtils.cmake b/cmake/P4CUtils.cmake index 6ffe9cb4edf..e525086cec9 100644 --- a/cmake/P4CUtils.cmake +++ b/cmake/P4CUtils.cmake @@ -81,12 +81,12 @@ endmacro(p4c_test_set_name) # program with command line arguments ${args} # Sets the timeout on tests at 300s (for the slow Travis machines) # -macro(p4c_add_test_with_args tag driver isXfail alias p4test cmake_args) +macro(p4c_add_test_with_args tag driver isXfail alias p4test test_args cmake_args) set(__testfile "${P4C_BINARY_DIR}/${tag}/${p4test}.test") file (WRITE ${__testfile} "#! /bin/bash\n") file (APPEND ${__testfile} "# Generated file, modify with care\n\n") file (APPEND ${__testfile} "cd ${P4C_BINARY_DIR}\n") - file (APPEND ${__testfile} "${driver} ${P4C_SOURCE_DIR} \"$@\" ${P4C_SOURCE_DIR}/${p4test}") + file (APPEND ${__testfile} "${driver} ${P4C_SOURCE_DIR} ${test_args} \"$@\" ${P4C_SOURCE_DIR}/${p4test}") execute_process(COMMAND chmod +x ${__testfile}) p4c_test_set_name(__testname ${tag} ${alias}) separate_arguments(__args UNIX_COMMAND ${cmake_args}) @@ -127,10 +127,10 @@ macro(p4c_add_test_list tag driver tests xfail) foreach(t ${__test_list}) list (FIND __xfail_list ${t} __xfail_test) if(__xfail_test GREATER -1) - p4c_add_test_with_args (${tag} ${driver} TRUE ${t} ${t} "${ARGN}") + p4c_add_test_with_args (${tag} ${driver} TRUE ${t} ${t} "${ARGN}" "") math (EXPR __xfailCounter "${__xfailCounter} + 1") else() - p4c_add_test_with_args (${tag} ${driver} FALSE ${t} ${t} "${ARGN}") + p4c_add_test_with_args (${tag} ${driver} FALSE ${t} ${t} "${ARGN}" "") endif() # __xfail_test endforeach() # tests math (EXPR __testCounter "${__testCounter} + ${__nTests}") From df500eefbb34e397c3e9ec25b6ac7fbfdcb1d078 Mon Sep 17 00:00:00 2001 From: Mihai Budiu Date: Wed, 6 Nov 2019 10:52:08 -0800 Subject: [PATCH 024/106] Allow actions with absolute paths; fixes #2037 (#2042) --- frontends/parsers/p4/p4parser.ypp | 10 ++++------ testdata/p4_16_samples/issue2037.p4 | 8 ++++++++ testdata/p4_16_samples_outputs/issue2037-first.p4 | 13 +++++++++++++ .../p4_16_samples_outputs/issue2037-frontend.p4 | 0 testdata/p4_16_samples_outputs/issue2037.p4 | 13 +++++++++++++ testdata/p4_16_samples_outputs/issue2037.p4-stderr | 1 + 6 files changed, 39 insertions(+), 6 deletions(-) create mode 100644 testdata/p4_16_samples/issue2037.p4 create mode 100644 testdata/p4_16_samples_outputs/issue2037-first.p4 create mode 100644 testdata/p4_16_samples_outputs/issue2037-frontend.p4 create mode 100644 testdata/p4_16_samples_outputs/issue2037.p4 create mode 100644 testdata/p4_16_samples_outputs/issue2037.p4-stderr diff --git a/frontends/parsers/p4/p4parser.ypp b/frontends/parsers/p4/p4parser.ypp index 7dd0dcc4494..856654cac95 100644 --- a/frontends/parsers/p4/p4parser.ypp +++ b/frontends/parsers/p4/p4parser.ypp @@ -1200,12 +1200,10 @@ actionList ; actionRef - : optAnnotations name { auto expr = new IR::PathExpression(*$2); - $$ = new IR::ActionListElement(@2, $1, expr);} - | optAnnotations name "(" argumentList ")" - { auto method = new IR::PathExpression(*$2); - auto mce = new IR::MethodCallExpression( - @2+@4, method, $4); + : optAnnotations prefixedNonTypeName { $$ = new IR::ActionListElement(@2, $1, new IR::PathExpression($2));} + | optAnnotations prefixedNonTypeName "(" argumentList ")" + { auto mce = new IR::MethodCallExpression( + @2+@4, new IR::PathExpression($2), $4); $$ = new IR::ActionListElement(@2, $1, mce); } ; diff --git a/testdata/p4_16_samples/issue2037.p4 b/testdata/p4_16_samples/issue2037.p4 new file mode 100644 index 00000000000..4404c4b295d --- /dev/null +++ b/testdata/p4_16_samples/issue2037.p4 @@ -0,0 +1,8 @@ +action a() {} +control c() { + table t { + actions = { .a; } + default_action = a; + } + apply {} +} diff --git a/testdata/p4_16_samples_outputs/issue2037-first.p4 b/testdata/p4_16_samples_outputs/issue2037-first.p4 new file mode 100644 index 00000000000..9708d212a13 --- /dev/null +++ b/testdata/p4_16_samples_outputs/issue2037-first.p4 @@ -0,0 +1,13 @@ +action a() { +} +control c() { + table t { + actions = { + .a(); + } + default_action = a(); + } + apply { + } +} + diff --git a/testdata/p4_16_samples_outputs/issue2037-frontend.p4 b/testdata/p4_16_samples_outputs/issue2037-frontend.p4 new file mode 100644 index 00000000000..e69de29bb2d diff --git a/testdata/p4_16_samples_outputs/issue2037.p4 b/testdata/p4_16_samples_outputs/issue2037.p4 new file mode 100644 index 00000000000..3283c356a53 --- /dev/null +++ b/testdata/p4_16_samples_outputs/issue2037.p4 @@ -0,0 +1,13 @@ +action a() { +} +control c() { + table t { + actions = { + .a; + } + default_action = a; + } + apply { + } +} + diff --git a/testdata/p4_16_samples_outputs/issue2037.p4-stderr b/testdata/p4_16_samples_outputs/issue2037.p4-stderr new file mode 100644 index 00000000000..7f94c95a8ff --- /dev/null +++ b/testdata/p4_16_samples_outputs/issue2037.p4-stderr @@ -0,0 +1 @@ +warning: Program does not contain a `main' module From bd0308a87a491e966b5202aa5e2d139a58dffb84 Mon Sep 17 00:00:00 2001 From: Mihai Budiu Date: Wed, 6 Nov 2019 15:32:06 -0800 Subject: [PATCH 025/106] Support table.apply().miss (#2051) * Support table.apply().miss * Convert table.apply().miss to not table.apply.hit() --- backends/bmv2/psa_switch/midend.cpp | 2 + backends/bmv2/simple_switch/midend.cpp | 2 + backends/ebpf/midend.cpp | 2 + backends/p4test/midend.cpp | 2 + frontends/p4/def_use.cpp | 1 + frontends/p4/sideEffects.cpp | 8 +- frontends/p4/tableApply.cpp | 22 +++++ frontends/p4/tableApply.h | 5 +- ir/ir.cpp | 3 +- ir/type.cpp | 1 + ir/type.def | 1 + midend/CMakeLists.txt | 16 ++-- midend/removeMiss.cpp | 29 ++++++ midend/removeMiss.h | 54 +++++++++++ midend/tableHit.cpp | 17 +++- .../{hit-expr.p4 => hit-expr-bmv2.p4} | 0 testdata/p4_16_samples/issue2044-bmv2.p4 | 42 ++++++++ ...t-expr-first.p4 => hit-expr-bmv2-first.p4} | 0 ...-frontend.p4 => hit-expr-bmv2-frontend.p4} | 0 ...expr-midend.p4 => hit-expr-bmv2-midend.p4} | 0 .../{hit-expr.p4 => hit-expr-bmv2.p4} | 0 ...expr.p4-stderr => hit-expr-bmv2.p4-stderr} | 0 ...tries.txt => hit-expr-bmv2.p4.entries.txt} | 0 ...p4info.txt => hit-expr-bmv2.p4.p4info.txt} | 0 .../issue2044-bmv2-first.p4 | 60 ++++++++++++ .../issue2044-bmv2-frontend.p4 | 64 +++++++++++++ .../issue2044-bmv2-midend.p4 | 95 +++++++++++++++++++ .../p4_16_samples_outputs/issue2044-bmv2.p4 | 60 ++++++++++++ .../issue2044-bmv2.p4-stderr | 0 .../issue2044-bmv2.p4.entries.txt | 0 .../issue2044-bmv2.p4.p4info.txt | 27 ++++++ 31 files changed, 497 insertions(+), 16 deletions(-) create mode 100644 midend/removeMiss.cpp create mode 100644 midend/removeMiss.h rename testdata/p4_16_samples/{hit-expr.p4 => hit-expr-bmv2.p4} (100%) create mode 100644 testdata/p4_16_samples/issue2044-bmv2.p4 rename testdata/p4_16_samples_outputs/{hit-expr-first.p4 => hit-expr-bmv2-first.p4} (100%) rename testdata/p4_16_samples_outputs/{hit-expr-frontend.p4 => hit-expr-bmv2-frontend.p4} (100%) rename testdata/p4_16_samples_outputs/{hit-expr-midend.p4 => hit-expr-bmv2-midend.p4} (100%) rename testdata/p4_16_samples_outputs/{hit-expr.p4 => hit-expr-bmv2.p4} (100%) rename testdata/p4_16_samples_outputs/{hit-expr.p4-stderr => hit-expr-bmv2.p4-stderr} (100%) rename testdata/p4_16_samples_outputs/{hit-expr.p4.entries.txt => hit-expr-bmv2.p4.entries.txt} (100%) rename testdata/p4_16_samples_outputs/{hit-expr.p4.p4info.txt => hit-expr-bmv2.p4.p4info.txt} (100%) create mode 100644 testdata/p4_16_samples_outputs/issue2044-bmv2-first.p4 create mode 100644 testdata/p4_16_samples_outputs/issue2044-bmv2-frontend.p4 create mode 100644 testdata/p4_16_samples_outputs/issue2044-bmv2-midend.p4 create mode 100644 testdata/p4_16_samples_outputs/issue2044-bmv2.p4 create mode 100644 testdata/p4_16_samples_outputs/issue2044-bmv2.p4-stderr create mode 100644 testdata/p4_16_samples_outputs/issue2044-bmv2.p4.entries.txt create mode 100644 testdata/p4_16_samples_outputs/issue2044-bmv2.p4.p4info.txt diff --git a/backends/bmv2/psa_switch/midend.cpp b/backends/bmv2/psa_switch/midend.cpp index bbfe5c6965d..7afeddd7b70 100644 --- a/backends/bmv2/psa_switch/midend.cpp +++ b/backends/bmv2/psa_switch/midend.cpp @@ -39,6 +39,7 @@ limitations under the License. #include "midend/local_copyprop.h" #include "midend/nestedStructs.h" #include "midend/removeLeftSlices.h" +#include "midend/removeMiss.h" #include "midend/removeParameters.h" #include "midend/removeUnusedParameters.h" #include "midend/simplifyKey.h" @@ -93,6 +94,7 @@ PsaSwitchMidEnd::PsaSwitchMidEnd(CompilerOptions& options, std::ostream* outStre if (BMV2::PsaSwitchContext::get().options().loadIRFromJson == false) { std::initializer_list midendPasses = { options.ndebug ? new P4::RemoveAssertAssume(&refMap, &typeMap) : nullptr, + new P4::RemoveMiss(&refMap, &typeMap), new P4::EliminateNewtype(&refMap, &typeMap), new P4::EliminateSerEnums(&refMap, &typeMap), new P4::RemoveActionParameters(&refMap, &typeMap), diff --git a/backends/bmv2/simple_switch/midend.cpp b/backends/bmv2/simple_switch/midend.cpp index 1968bd2acd6..82f88711788 100644 --- a/backends/bmv2/simple_switch/midend.cpp +++ b/backends/bmv2/simple_switch/midend.cpp @@ -40,6 +40,7 @@ limitations under the License. #include "midend/local_copyprop.h" #include "midend/nestedStructs.h" #include "midend/removeLeftSlices.h" +#include "midend/removeMiss.h" #include "midend/removeParameters.h" #include "midend/removeUnusedParameters.h" #include "midend/simplifyKey.h" @@ -69,6 +70,7 @@ SimpleSwitchMidEnd::SimpleSwitchMidEnd(CompilerOptions& options, std::ostream* o std::initializer_list midendPasses = { options.ndebug ? new P4::RemoveAssertAssume(&refMap, &typeMap) : nullptr, new P4::CheckTableSize(), + new P4::RemoveMiss(&refMap, &typeMap), new P4::EliminateNewtype(&refMap, &typeMap), new P4::EliminateSerEnums(&refMap, &typeMap), new P4::RemoveActionParameters(&refMap, &typeMap), diff --git a/backends/ebpf/midend.cpp b/backends/ebpf/midend.cpp index cde665aca39..acfecd9ff36 100644 --- a/backends/ebpf/midend.cpp +++ b/backends/ebpf/midend.cpp @@ -37,6 +37,7 @@ limitations under the License. #include "midend/noMatch.h" #include "midend/removeExits.h" #include "midend/removeLeftSlices.h" +#include "midend/removeMiss.h" #include "midend/removeParameters.h" #include "midend/removeSelectBooleans.h" #include "midend/simplifyKey.h" @@ -76,6 +77,7 @@ const IR::ToplevelBlock* MidEnd::run(EbpfOptions& options, if (options.loadIRFromJson == false) { std::initializer_list midendPasses = { new P4::ConvertEnums(&refMap, &typeMap, new EnumOn32Bits()), + new P4::RemoveMiss(&refMap, &typeMap), new P4::ClearTypeMap(&typeMap), new P4::EliminateNewtype(&refMap, &typeMap), new P4::SimplifyControlFlow(&refMap, &typeMap), diff --git a/backends/p4test/midend.cpp b/backends/p4test/midend.cpp index c9d73308d8d..6bbfbf75820 100644 --- a/backends/p4test/midend.cpp +++ b/backends/p4test/midend.cpp @@ -45,6 +45,7 @@ limitations under the License. #include "midend/parserUnroll.h" #include "midend/predication.h" #include "midend/removeExits.h" +#include "midend/removeMiss.h" #include "midend/removeParameters.h" #include "midend/removeSelectBooleans.h" #include "midend/simplifyKey.h" @@ -80,6 +81,7 @@ MidEnd::MidEnd(CompilerOptions& options) { // TODO: handle bit-slices as out arguments addPasses({ options.ndebug ? new P4::RemoveAssertAssume(&refMap, &typeMap) : nullptr, + new P4::RemoveMiss(&refMap, &typeMap), new P4::EliminateNewtype(&refMap, &typeMap), new P4::EliminateSerEnums(&refMap, &typeMap), new P4::RemoveActionParameters(&refMap, &typeMap), diff --git a/frontends/p4/def_use.cpp b/frontends/p4/def_use.cpp index a81fd5e6be3..69ec0d50bdf 100644 --- a/frontends/p4/def_use.cpp +++ b/frontends/p4/def_use.cpp @@ -527,6 +527,7 @@ bool ComputeWriteSet::preorder(const IR::Member* expression) { if (type->is()) return false; if (TableApplySolver::isHit(expression, storageMap->refMap, storageMap->typeMap) || + TableApplySolver::isMiss(expression, storageMap->refMap, storageMap->typeMap) || TableApplySolver::isActionRun(expression, storageMap->refMap, storageMap->typeMap)) return false; auto storage = getWrites(expression->expr); diff --git a/frontends/p4/sideEffects.cpp b/frontends/p4/sideEffects.cpp index 51a34113f8f..4e17874a6f4 100644 --- a/frontends/p4/sideEffects.cpp +++ b/frontends/p4/sideEffects.cpp @@ -168,9 +168,10 @@ class DismantleExpression : public Transform { if (leftValue) typeMap->setLeftValue(result->final); - // Special case for table.apply().hit, which is not dismantled by + // Special case for table.apply().hit/miss, which is not dismantled by // the MethodCallExpression. - if (TableApplySolver::isHit(expression, refMap, typeMap)) { + if (TableApplySolver::isHit(expression, refMap, typeMap) || + TableApplySolver::isMiss(expression, refMap, typeMap)) { BUG_CHECK(type->is(), "%1%: not boolean", type); auto tmp = result->createTemporary(type); auto path = new IR::PathExpression(IR::ID(tmp, nullptr)); @@ -479,7 +480,8 @@ class DismantleExpression : public Transform { if (auto mmbr = getParent()) { auto tbl = TableApplySolver::isActionRun(mmbr, refMap, typeMap); auto tbl1 = TableApplySolver::isHit(mmbr, refMap, typeMap); - tbl_apply = tbl != nullptr || tbl1 != nullptr; + auto tbl2 = TableApplySolver::isMiss(mmbr, refMap, typeMap); + tbl_apply = tbl != nullptr || tbl1 != nullptr || tbl2 != nullptr; } // Simplified method call, with arguments substituted auto simplified = new IR::MethodCallExpression( diff --git a/frontends/p4/tableApply.cpp b/frontends/p4/tableApply.cpp index 57ebba77f3e..dd17077f584 100644 --- a/frontends/p4/tableApply.cpp +++ b/frontends/p4/tableApply.cpp @@ -41,6 +41,28 @@ TableApplySolver::isHit(const IR::Expression* expression, return am->object->to(); } +const IR::P4Table* +TableApplySolver::isMiss(const IR::Expression* expression, + ReferenceMap* refMap, + TypeMap* typeMap) { + if (!expression->is()) + return nullptr; + auto mem = expression->to(); + if (!mem->expr->is()) + return nullptr; + if (mem->member != IR::Type_Table::miss) + return nullptr; + auto mce = mem->expr->to(); + auto mi = P4::MethodInstance::resolve(mce, refMap, typeMap); + if (!mi->isApply()) + return nullptr; + + auto am = mi->to(); + if (!am->object->is()) + return nullptr; + return am->object->to(); +} + const IR::P4Table* TableApplySolver::isActionRun(const IR::Expression* expression, ReferenceMap* refMap, diff --git a/frontends/p4/tableApply.h b/frontends/p4/tableApply.h index 8855268dbdf..d33d67dfce5 100644 --- a/frontends/p4/tableApply.h +++ b/frontends/p4/tableApply.h @@ -28,13 +28,16 @@ limitations under the License. namespace P4 { // These are used to figure out whether an expression has the form: -// table.apply().hit +// table.apply().hit, +// table.apply().miss, // or // table.apply().action_run class TableApplySolver { public: static const IR::P4Table* isHit(const IR::Expression* expression, ReferenceMap* refMap, TypeMap* typeMap); + static const IR::P4Table* isMiss(const IR::Expression* expression, + ReferenceMap* refMap, TypeMap* typeMap); static const IR::P4Table* isActionRun(const IR::Expression* expression, ReferenceMap* refMap, TypeMap* typeMap); }; diff --git a/ir/ir.cpp b/ir/ir.cpp index 810f95eb79d..949cad17a67 100644 --- a/ir/ir.cpp +++ b/ir/ir.cpp @@ -180,8 +180,9 @@ P4Table::getApplyMethodType() const { actions); auto alv = actions->value->to(); auto hit = new IR::StructField(IR::Type_Table::hit, IR::Type_Boolean::get()); + auto miss = new IR::StructField(IR::Type_Table::miss, IR::Type_Boolean::get()); auto label = new IR::StructField(IR::Type_Table::action_run, new IR::Type_ActionEnum(alv)); - auto rettype = new IR::Type_Struct(ID(name), { hit, label }); + auto rettype = new IR::Type_Struct(ID(name), { hit, miss, label }); auto applyMethod = new IR::Type_Method(rettype, new IR::ParameterList()); return applyMethod; } diff --git a/ir/type.cpp b/ir/type.cpp index 44bd2c5ecce..709c6d2cd9c 100644 --- a/ir/type.cpp +++ b/ir/type.cpp @@ -32,6 +32,7 @@ const cstring IR::Type_StructLike::minSizeInBits = "minSizeInBits"; const cstring IR::Type_StructLike::minSizeInBytes = "minSizeInBytes"; const IR::ID IR::Type_Table::hit = ID("hit"); +const IR::ID IR::Type_Table::miss = ID("miss"); const IR::ID IR::Type_Table::action_run = ID("action_run"); const cstring IR::Annotation::nameAnnotation = "name"; diff --git a/ir/type.def b/ir/type.def index be1918cf811..1f9b0f7e58d 100644 --- a/ir/type.def +++ b/ir/type.def @@ -446,6 +446,7 @@ class Type_Table : Type, IApply { /// names for the fields of the struct returned /// by applying a table static const ID hit; + static const ID miss; static const ID action_run; const IR::Type* getP4Type() const override { return nullptr; } dbprint { out << table->name; } diff --git a/midend/CMakeLists.txt b/midend/CMakeLists.txt index 116464460c2..e3b0d4c40a6 100644 --- a/midend/CMakeLists.txt +++ b/midend/CMakeLists.txt @@ -17,11 +17,12 @@ set (MIDEND_SRCS complexComparison.cpp convertEnums.cpp copyStructures.cpp - eliminateTuples.cpp eliminateNewtype.cpp eliminateSerEnums.cpp + eliminateTuples.cpp expandEmit.cpp expandLookahead.cpp + fillEnumMap.cpp flattenHeaders.cpp flattenInterfaceStructs.cpp interpreter.cpp @@ -31,8 +32,10 @@ set (MIDEND_SRCS orderArguments.cpp parserUnroll.cpp predication.cpp + removeAssertAssume.cpp removeExits.cpp removeLeftSlices.cpp + removeMiss.cpp removeParameters.cpp removeSelectBooleans.cpp removeUnusedParameters.cpp @@ -43,8 +46,6 @@ set (MIDEND_SRCS singleArgumentSelect.cpp tableHit.cpp validateProperties.cpp - fillEnumMap.cpp - removeAssertAssume.cpp ) set (MIDEND_HDRS @@ -54,14 +55,15 @@ set (MIDEND_HDRS complexComparison.h convertEnums.h copyStructures.h - eliminateTuples.h eliminateNewtype.h eliminateSerEnums.h + eliminateTuples.h expandEmit.h expandLookahead.h expr_uses.h - flattenInterfaceStructs.h + fillEnumMap.h flattenHeaders.h + flattenInterfaceStructs.h has_side_effects.h interpreter.h local_copyprop.h @@ -71,8 +73,10 @@ set (MIDEND_HDRS orderArguments.h parserUnroll.h predication.h + removeAssertAssume.h removeExits.h removeLeftSlices.h + removeMiss.h removeParameters.h removeSelectBooleans.h removeUnusedParameters.h @@ -83,8 +87,6 @@ set (MIDEND_HDRS singleArgumentSelect.h tableHit.h validateProperties.h - fillEnumMap.h - removeAssertAssume.h ) add_cpplint_files (${CMAKE_CURRENT_SOURCE_DIR} "${MIDEND_SRCS};${MIDEND_HDRS}") diff --git a/midend/removeMiss.cpp b/midend/removeMiss.cpp new file mode 100644 index 00000000000..d9588ee9b9e --- /dev/null +++ b/midend/removeMiss.cpp @@ -0,0 +1,29 @@ +/* +Copyright 2019 VMware, 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 "removeMiss.h" +#include "frontends/p4/tableApply.h" + +namespace P4 { + +const IR::Node* DoRemoveMiss::preorder(IR::Member* expression) { + if (!TableApplySolver::isMiss(expression, refMap, typeMap)) + return expression; + auto hit = new IR::Member(expression->expr, IR::Type_Table::hit); + return new IR::LNot(hit); +} + +} // namespace P4 diff --git a/midend/removeMiss.h b/midend/removeMiss.h new file mode 100644 index 00000000000..bd9c731fc92 --- /dev/null +++ b/midend/removeMiss.h @@ -0,0 +1,54 @@ +/* +Copyright 2019 VMware, 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. +*/ + +#ifndef _MIDEND_REMOVEMISS_H_ +#define _MIDEND_REMOVEMISS_H_ + +#include "ir/ir.h" +#include "frontends/p4/typeChecking/typeChecker.h" +#include "frontends/common/resolveReferences/referenceMap.h" +#include "frontends/p4/typeMap.h" + +namespace P4 { + +/** + * This visitor converts table.apply().miss into !table.apply().hit. + */ +class DoRemoveMiss : public Transform { + ReferenceMap* refMap; + TypeMap* typeMap; + public: + DoRemoveMiss(ReferenceMap* refMap, TypeMap* typeMap) : + refMap(refMap), typeMap(typeMap) + { visitDagOnce = false; CHECK_NULL(typeMap); setName("DoRemoveMiss"); } + const IR::Node* preorder(IR::Member* expression) override; +}; + +class RemoveMiss : public PassManager { + public: + RemoveMiss(ReferenceMap* refMap, TypeMap* typeMap, + TypeChecking* typeChecking = nullptr) { + if (!typeChecking) + typeChecking = new TypeChecking(refMap, typeMap); + passes.push_back(typeChecking); + passes.push_back(new DoRemoveMiss(refMap, typeMap)); + setName("RemoveMiss"); + } +}; + +} // namespace P4 + +#endif /* _MIDEND_REMOVEMISS_H_ */ diff --git a/midend/tableHit.cpp b/midend/tableHit.cpp index 560ec044207..18580af3619 100644 --- a/midend/tableHit.cpp +++ b/midend/tableHit.cpp @@ -21,16 +21,25 @@ namespace P4 { const IR::Node* DoTableHit::postorder(IR::AssignmentStatement* statement) { LOG3("Visiting " << getOriginal()); - if (!TableApplySolver::isHit(statement->right, refMap, typeMap)) + auto right = statement->right; + bool negated = false; + if (auto neg = right->to()) { + // We handle !hit, which may have been created by the removal of miss + negated = true; + right = neg->expr; + } + + if (!TableApplySolver::isHit(right, refMap, typeMap)) return statement; auto tstat = new IR::AssignmentStatement( statement->left->clone(), new IR::BoolLiteral(true)); auto fstat = new IR::AssignmentStatement( statement->left->clone(), new IR::BoolLiteral(false)); - auto ifStatement = new IR::IfStatement( - statement->right, tstat, fstat); - return ifStatement; + if (negated) + return new IR::IfStatement(right, fstat, tstat); + else + return new IR::IfStatement(right, tstat, fstat); } } // namespace P4 diff --git a/testdata/p4_16_samples/hit-expr.p4 b/testdata/p4_16_samples/hit-expr-bmv2.p4 similarity index 100% rename from testdata/p4_16_samples/hit-expr.p4 rename to testdata/p4_16_samples/hit-expr-bmv2.p4 diff --git a/testdata/p4_16_samples/issue2044-bmv2.p4 b/testdata/p4_16_samples/issue2044-bmv2.p4 new file mode 100644 index 00000000000..6b1cdabc701 --- /dev/null +++ b/testdata/p4_16_samples/issue2044-bmv2.p4 @@ -0,0 +1,42 @@ +#include +#include + +header hdr { + bit<32> b; +} + +struct Headers { + hdr h; +} + +struct Meta {} + +parser p(packet_in b, out Headers h, inout Meta m, inout standard_metadata_t sm) { + state start { + transition accept; + } +} + +control vrfy(inout Headers h, inout Meta m) { apply {} } +control update(inout Headers h, inout Meta m) { apply {} } + +control egress(inout Headers h, inout Meta m, inout standard_metadata_t sm) { apply {} } + +control deparser(packet_out b, in Headers h) { + apply { b.emit(h); } +} + +control ingress(inout Headers h, inout Meta m, inout standard_metadata_t sm) { + table t { + key = { h.h.b : exact; } + actions = { NoAction; } + default_action = NoAction; + } + apply { + if (t.apply().miss) { + h.h.setInvalid(); + } + } +} + +V1Switch(p(), vrfy(), ingress(), egress(), update(), deparser()) main; diff --git a/testdata/p4_16_samples_outputs/hit-expr-first.p4 b/testdata/p4_16_samples_outputs/hit-expr-bmv2-first.p4 similarity index 100% rename from testdata/p4_16_samples_outputs/hit-expr-first.p4 rename to testdata/p4_16_samples_outputs/hit-expr-bmv2-first.p4 diff --git a/testdata/p4_16_samples_outputs/hit-expr-frontend.p4 b/testdata/p4_16_samples_outputs/hit-expr-bmv2-frontend.p4 similarity index 100% rename from testdata/p4_16_samples_outputs/hit-expr-frontend.p4 rename to testdata/p4_16_samples_outputs/hit-expr-bmv2-frontend.p4 diff --git a/testdata/p4_16_samples_outputs/hit-expr-midend.p4 b/testdata/p4_16_samples_outputs/hit-expr-bmv2-midend.p4 similarity index 100% rename from testdata/p4_16_samples_outputs/hit-expr-midend.p4 rename to testdata/p4_16_samples_outputs/hit-expr-bmv2-midend.p4 diff --git a/testdata/p4_16_samples_outputs/hit-expr.p4 b/testdata/p4_16_samples_outputs/hit-expr-bmv2.p4 similarity index 100% rename from testdata/p4_16_samples_outputs/hit-expr.p4 rename to testdata/p4_16_samples_outputs/hit-expr-bmv2.p4 diff --git a/testdata/p4_16_samples_outputs/hit-expr.p4-stderr b/testdata/p4_16_samples_outputs/hit-expr-bmv2.p4-stderr similarity index 100% rename from testdata/p4_16_samples_outputs/hit-expr.p4-stderr rename to testdata/p4_16_samples_outputs/hit-expr-bmv2.p4-stderr diff --git a/testdata/p4_16_samples_outputs/hit-expr.p4.entries.txt b/testdata/p4_16_samples_outputs/hit-expr-bmv2.p4.entries.txt similarity index 100% rename from testdata/p4_16_samples_outputs/hit-expr.p4.entries.txt rename to testdata/p4_16_samples_outputs/hit-expr-bmv2.p4.entries.txt diff --git a/testdata/p4_16_samples_outputs/hit-expr.p4.p4info.txt b/testdata/p4_16_samples_outputs/hit-expr-bmv2.p4.p4info.txt similarity index 100% rename from testdata/p4_16_samples_outputs/hit-expr.p4.p4info.txt rename to testdata/p4_16_samples_outputs/hit-expr-bmv2.p4.p4info.txt diff --git a/testdata/p4_16_samples_outputs/issue2044-bmv2-first.p4 b/testdata/p4_16_samples_outputs/issue2044-bmv2-first.p4 new file mode 100644 index 00000000000..b907ee734e0 --- /dev/null +++ b/testdata/p4_16_samples_outputs/issue2044-bmv2-first.p4 @@ -0,0 +1,60 @@ +#include +#include + +header hdr { + bit<32> b; +} + +struct Headers { + hdr h; +} + +struct Meta { +} + +parser p(packet_in b, out Headers h, inout Meta m, inout standard_metadata_t sm) { + state start { + transition accept; + } +} + +control vrfy(inout Headers h, inout Meta m) { + apply { + } +} + +control update(inout Headers h, inout Meta m) { + apply { + } +} + +control egress(inout Headers h, inout Meta m, inout standard_metadata_t sm) { + apply { + } +} + +control deparser(packet_out b, in Headers h) { + apply { + b.emit(h); + } +} + +control ingress(inout Headers h, inout Meta m, inout standard_metadata_t sm) { + table t { + key = { + h.h.b: exact @name("h.h.b") ; + } + actions = { + NoAction(); + } + default_action = NoAction(); + } + apply { + if (t.apply().miss) { + h.h.setInvalid(); + } + } +} + +V1Switch(p(), vrfy(), ingress(), egress(), update(), deparser()) main; + diff --git a/testdata/p4_16_samples_outputs/issue2044-bmv2-frontend.p4 b/testdata/p4_16_samples_outputs/issue2044-bmv2-frontend.p4 new file mode 100644 index 00000000000..4bb65421c99 --- /dev/null +++ b/testdata/p4_16_samples_outputs/issue2044-bmv2-frontend.p4 @@ -0,0 +1,64 @@ +#include +#include + +header hdr { + bit<32> b; +} + +struct Headers { + hdr h; +} + +struct Meta { +} + +parser p(packet_in b, out Headers h, inout Meta m, inout standard_metadata_t sm) { + state start { + transition accept; + } +} + +control vrfy(inout Headers h, inout Meta m) { + apply { + } +} + +control update(inout Headers h, inout Meta m) { + apply { + } +} + +control egress(inout Headers h, inout Meta m, inout standard_metadata_t sm) { + apply { + } +} + +control deparser(packet_out b, in Headers h) { + apply { + b.emit(h); + } +} + +control ingress(inout Headers h, inout Meta m, inout standard_metadata_t sm) { + @name(".NoAction") action NoAction_0() { + } + bool tmp; + @name("ingress.t") table t_0 { + key = { + h.h.b: exact @name("h.h.b") ; + } + actions = { + NoAction_0(); + } + default_action = NoAction_0(); + } + apply { + tmp = t_0.apply().miss; + if (tmp) { + h.h.setInvalid(); + } + } +} + +V1Switch(p(), vrfy(), ingress(), egress(), update(), deparser()) main; + diff --git a/testdata/p4_16_samples_outputs/issue2044-bmv2-midend.p4 b/testdata/p4_16_samples_outputs/issue2044-bmv2-midend.p4 new file mode 100644 index 00000000000..289f0fe1664 --- /dev/null +++ b/testdata/p4_16_samples_outputs/issue2044-bmv2-midend.p4 @@ -0,0 +1,95 @@ +#include +#include + +header hdr { + bit<32> b; +} + +struct Headers { + hdr h; +} + +struct Meta { +} + +parser p(packet_in b, out Headers h, inout Meta m, inout standard_metadata_t sm) { + state start { + transition accept; + } +} + +control vrfy(inout Headers h, inout Meta m) { + apply { + } +} + +control update(inout Headers h, inout Meta m) { + apply { + } +} + +control egress(inout Headers h, inout Meta m, inout standard_metadata_t sm) { + apply { + } +} + +control deparser(packet_out b, in Headers h) { + apply { + b.emit(h.h); + } +} + +control ingress(inout Headers h, inout Meta m, inout standard_metadata_t sm) { + bool tmp; + @name(".NoAction") action NoAction_0() { + } + @name("ingress.t") table t_0 { + key = { + h.h.b: exact @name("h.h.b") ; + } + actions = { + NoAction_0(); + } + default_action = NoAction_0(); + } + @hidden action act() { + tmp = false; + } + @hidden action act_0() { + tmp = true; + } + @hidden action issue2044bmv2l37() { + h.h.setInvalid(); + } + @hidden table tbl_act { + actions = { + act(); + } + const default_action = act(); + } + @hidden table tbl_act_0 { + actions = { + act_0(); + } + const default_action = act_0(); + } + @hidden table tbl_issue2044bmv2l37 { + actions = { + issue2044bmv2l37(); + } + const default_action = issue2044bmv2l37(); + } + apply { + if (t_0.apply().hit) { + tbl_act.apply(); + } else { + tbl_act_0.apply(); + } + if (tmp) { + tbl_issue2044bmv2l37.apply(); + } + } +} + +V1Switch(p(), vrfy(), ingress(), egress(), update(), deparser()) main; + diff --git a/testdata/p4_16_samples_outputs/issue2044-bmv2.p4 b/testdata/p4_16_samples_outputs/issue2044-bmv2.p4 new file mode 100644 index 00000000000..3ac6ac39f33 --- /dev/null +++ b/testdata/p4_16_samples_outputs/issue2044-bmv2.p4 @@ -0,0 +1,60 @@ +#include +#include + +header hdr { + bit<32> b; +} + +struct Headers { + hdr h; +} + +struct Meta { +} + +parser p(packet_in b, out Headers h, inout Meta m, inout standard_metadata_t sm) { + state start { + transition accept; + } +} + +control vrfy(inout Headers h, inout Meta m) { + apply { + } +} + +control update(inout Headers h, inout Meta m) { + apply { + } +} + +control egress(inout Headers h, inout Meta m, inout standard_metadata_t sm) { + apply { + } +} + +control deparser(packet_out b, in Headers h) { + apply { + b.emit(h); + } +} + +control ingress(inout Headers h, inout Meta m, inout standard_metadata_t sm) { + table t { + key = { + h.h.b: exact; + } + actions = { + NoAction; + } + default_action = NoAction; + } + apply { + if (t.apply().miss) { + h.h.setInvalid(); + } + } +} + +V1Switch(p(), vrfy(), ingress(), egress(), update(), deparser()) main; + diff --git a/testdata/p4_16_samples_outputs/issue2044-bmv2.p4-stderr b/testdata/p4_16_samples_outputs/issue2044-bmv2.p4-stderr new file mode 100644 index 00000000000..e69de29bb2d diff --git a/testdata/p4_16_samples_outputs/issue2044-bmv2.p4.entries.txt b/testdata/p4_16_samples_outputs/issue2044-bmv2.p4.entries.txt new file mode 100644 index 00000000000..e69de29bb2d diff --git a/testdata/p4_16_samples_outputs/issue2044-bmv2.p4.p4info.txt b/testdata/p4_16_samples_outputs/issue2044-bmv2.p4.p4info.txt new file mode 100644 index 00000000000..599ec43e5e2 --- /dev/null +++ b/testdata/p4_16_samples_outputs/issue2044-bmv2.p4.p4info.txt @@ -0,0 +1,27 @@ +pkg_info { + arch: "v1model" +} +tables { + preamble { + id: 33614349 + name: "ingress.t" + alias: "t" + } + match_fields { + id: 1 + name: "h.h.b" + bitwidth: 32 + match_type: EXACT + } + action_refs { + id: 16800567 + } + size: 1024 +} +actions { + preamble { + id: 16800567 + name: "NoAction" + alias: "NoAction" + } +} From b3798b95f3e407ef269ed4d5eb02843e78b35754 Mon Sep 17 00:00:00 2001 From: Chris Dodd Date: Wed, 6 Nov 2019 18:15:47 -0800 Subject: [PATCH 026/106] IR/json support for bitvec fields (#2078) --- ir/json_generator.h | 5 +++++ ir/json_loader.h | 4 ++++ lib/bitvec.cpp | 33 +++++++++++++++++++++++++++++++++ lib/bitvec.h | 2 ++ test/gtest/bitvec_test.cpp | 11 +++++++++++ 5 files changed, 55 insertions(+) diff --git a/ir/json_generator.h b/ir/json_generator.h index 012931a6330..8a728d35ca2 100644 --- a/ir/json_generator.h +++ b/ir/json_generator.h @@ -22,6 +22,7 @@ limitations under the License. #include #include #include +#include "lib/bitvec.h" #include "lib/cstring.h" #include "lib/indent.h" #include "lib/match.h" @@ -188,6 +189,10 @@ class JSONGenerator { out << "\"" << v << "\""; } + void generate(const bitvec &v) { + out << "\"" << v << "\""; + } + void generate(const match_t &v) { out << "{" << std::endl << (indent + 1) << "\"word0\" : " << v.word0 << "," << std::endl diff --git a/ir/json_loader.h b/ir/json_loader.h index 90f8d5c9978..68e1f387f4b 100644 --- a/ir/json_loader.h +++ b/ir/json_loader.h @@ -205,6 +205,10 @@ class JSONLoader { if (auto *s = json->to()) s->c_str() >> m; } + void unpack_json(bitvec &v) { + if (auto *s = json->to()) + s->c_str() >> v; } + template typename std::enable_if::value>::type unpack_json(T &v) { if (auto *s = json->to()) diff --git a/lib/bitvec.cpp b/lib/bitvec.cpp index 07995157ab7..0802a3791ed 100644 --- a/lib/bitvec.cpp +++ b/lib/bitvec.cpp @@ -14,6 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ +#include #include "bitvec.h" #include "hex.h" @@ -35,6 +36,38 @@ std::ostream &operator<<(std::ostream &os, const bitvec &bv) { return os; } +std::istream &operator>>(std::istream &is, bitvec &bv) { + char ch; + while (is && isspace((ch = is.get()))) {} + if (!is) return is; + if (!isxdigit(ch)) { + is.unget(); + is.setstate(std::ios_base::failbit); + } else { + bv.clear(); + do { + bv <<= 4; + if (isdigit(ch)) bv |= ch - '0'; + if (islower(ch)) bv |= ch - 'a' + 10; + if (isupper(ch)) bv |= ch - 'A' + 10; + ch = is.get(); + } while (is && isxdigit(ch)); + if (is) is.unget(); } + return is; +} + +bool operator>>(const char *s, bitvec &bv) { + bv.clear(); + while (*s) { + if (!isxdigit(*s)) return false; + bv <<= 4; + if (isdigit(*s)) bv |= *s - '0'; + if (islower(*s)) bv |= *s - 'a' + 10; + if (isupper(*s)) bv |= *s - 'A' + 10; + s++; } + return true; +} + bitvec &bitvec::operator>>=(size_t count) { if (size == 1) { if (count >= bits_per_unit) diff --git a/lib/bitvec.h b/lib/bitvec.h index d830eadd767..c7d354dabef 100644 --- a/lib/bitvec.h +++ b/lib/bitvec.h @@ -489,6 +489,8 @@ class bitvec { public: friend std::ostream &operator<<(std::ostream &, const bitvec &); + friend std::istream &operator>>(std::istream &, bitvec &); + friend bool operator>>(const char *, bitvec &); }; class bitvec::copy_bitref : public bitvec::bitref { diff --git a/test/gtest/bitvec_test.cpp b/test/gtest/bitvec_test.cpp index bceffadce39..25b2cc3ad3f 100644 --- a/test/gtest/bitvec_test.cpp +++ b/test/gtest/bitvec_test.cpp @@ -130,4 +130,15 @@ TEST(Bitvec, rvalue) { } } +TEST(Bitvec, io) { + bitvec a(0xde10fe1f); + bitvec b; + "DE10fe1f" >> b; + EXPECT_EQ(a, b); + std::stringstream tmp; + tmp << a; + tmp >> b; + EXPECT_EQ(a, b); +} + } // namespace Test From 06021c2335dc51c9fbf4839bd27fd862a03dc408 Mon Sep 17 00:00:00 2001 From: Nate Foster Date: Thu, 7 Nov 2019 00:08:09 -0500 Subject: [PATCH 027/106] Update version to match language specification (#2059) * Update version to match language specification * Update version number to v1.2.0 for release --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 86cf04e4346..4b68e2412dd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -52,7 +52,7 @@ if (NOT $ENV{P4C_VERSION} STREQUAL "") else() # Semantic version numbering: ..[-rcX] # Examples: 0.5.1, 1.0.0-rc1, 1.0.1-alpha - set (P4C_SEM_VERSION_STRING "1.1.0-rc1") + set (P4C_SEM_VERSION_STRING "1.2.0") string (REGEX MATCH "([0-9]+)\\.([0-9]+)\\.([0-9]+)([-0-9a-z\\.]*).*" __p4c_version ${P4C_SEM_VERSION_STRING}) set (P4C_VERSION_MAJOR ${CMAKE_MATCH_1}) From 1cbcd6a9d4159afe1f685f1ad54ca203d6f31d3c Mon Sep 17 00:00:00 2001 From: Andy Fingerhut Date: Mon, 11 Nov 2019 13:49:51 -0800 Subject: [PATCH 028/106] Update first paragraph of README to no longer say alpha-quality (#2081) --- README.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 5a5c1abd275..46ae49a692b 100644 --- a/README.md +++ b/README.md @@ -2,10 +2,14 @@ # p4c -p4c is a new, alpha-quality reference compiler for the P4 programming language. +p4c is a reference compiler for the P4 programming language. It supports both P4-14 and P4-16; you can find more information about P4 [here](http://p4.org) and the specifications for both versions of the language [here](https://p4.org/specs). +One fact attesting to the level of quality and completeness of p4c's +code is that its front-end code, mid-end code, and p4c-graphs back end +are used as the basis for at least one commercially supported P4 +compiler. p4c is modular; it provides a standard frontend and midend which can be combined with a target-specific backend to create a complete P4 compiler. The goal is to From 2fca832c860c673141c3b67d791623162819c8de Mon Sep 17 00:00:00 2001 From: Calin Cascaval <3770874+cc10512@users.noreply.github.com> Date: Mon, 18 Nov 2019 19:40:05 -0800 Subject: [PATCH 029/106] Move to Python3 (#2087) Converts scripts to Python3 Moves all python scripts in the p4c repository to Python3, except for cpplint. We should consider moving to https://github.com/cpplint/cpplint to avoid maintaining cpplint. However, this requires adapting all the linting rules to the new version of cpplint, which is orthogonal to this PR. We still install Python2 dependencies so that we don't break downstream projects. While I do not have a crystal ball to know when they are transitioned, we should put a deadline for these projects to transition and remove the Python2 dependencies. --- CMakeLists.txt | 2 +- backends/bmv2/bmv2stf.py | 28 +++++++++----------------- backends/bmv2/run-bmv2-test.py | 4 +--- backends/ebpf/run-ebpf-test.py | 3 +-- backends/ebpf/targets/bcc_target.py | 4 ++-- backends/ebpf/targets/ebpfenv.py | 2 +- backends/ebpf/targets/ebpfstf.py | 5 ++--- backends/ebpf/targets/kernel_target.py | 6 +++--- backends/ebpf/targets/target.py | 14 ++++++++++--- backends/ebpf/targets/test_target.py | 4 ++-- backends/p4test/run-p4-sample.py | 8 ++++---- testdata/p4_16_samples/gen-large.py | 19 +++++++++-------- tools/driver/p4c.in | 2 +- tools/driver/p4c_src/config.py | 6 +++--- tools/driver/p4c_src/driver.py | 20 +++++++++--------- tools/driver/p4c_src/main.py | 14 +++++++------ tools/driver/p4c_src/util.py | 8 ++++---- tools/install_os_deps.sh | 9 +++++---- tools/stf/stf_lexer.py | 2 +- tools/stf/stf_parser.py | 10 ++++----- tools/stf/stf_runner.py | 3 +-- tools/stf/stf_test.py | 6 +++--- tools/testutils.py | 11 +++------- tools/travis-build | 23 ++++++++++++++++++--- 24 files changed, 111 insertions(+), 102 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4b68e2412dd..45e8093fe3a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -75,7 +75,7 @@ set (P4C_CXX_FLAGS "") set (P4C_LIB_DEPS) # required tools and libraries -find_package (PythonInterp REQUIRED) +find_package (PythonInterp 3 REQUIRED) find_package (FLEX REQUIRED) find_package (BISON 3.0.2 REQUIRED) if (ENABLE_PROTOBUF_STATIC) diff --git a/backends/bmv2/bmv2stf.py b/backends/bmv2/bmv2stf.py index 95f861860ea..e6ac0737094 100755 --- a/backends/bmv2/bmv2stf.py +++ b/backends/bmv2/bmv2stf.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python3 # Copyright 2013-present Barefoot Networks, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -15,7 +15,6 @@ # Runs the BMv2 behavioral model simulator with input from an stf file -from __future__ import print_function from subprocess import Popen from threading import Thread from glob import glob @@ -33,7 +32,6 @@ import random import errno import socket -from string import maketrans from collections import OrderedDict try: from scapy.layers.all import * @@ -46,7 +44,7 @@ class TimeoutException(Exception): pass def signal_handler(signum, frame): - raise TimeoutException, "Timed out!" + raise TimeoutException("Timed out!") signal.signal(signal.SIGALRM, signal_handler) class Options(object): @@ -72,15 +70,8 @@ def nextWord(text, sep = None): def ByteToHex(byteStr): return ''.join( [ "%02X " % ord( x ) for x in byteStr ] ).strip() -def HexToByte(hexStr): - bytes = [] - hexStr = ''.join( hexStr.split(" ") ) - for i in range(0, len(hexStr), 2): - bytes.append( chr( int (hexStr[i:i+2], 16 ) ) ) - return ''.join( bytes ) - def convert_packet_bin2hexstr(pkt_bin): - return ''.join(ByteToHex(str(pkt_bin)).split()).upper() + return pkt_bin.convert_to(Raw).load.hex().upper() def convert_packet_stf2hexstr(pkt_stf_text): return ''.join(pkt_stf_text.split()).upper() @@ -191,7 +182,7 @@ def __init__(self, tableKey): assert isinstance(tableKey, TableKey) self.values = {} self.key = tableKey - for f,t in tableKey.fields.iteritems(): + for f,t in tableKey.fields.items(): if t == "ternary": self.values[f] = "0&&&0" elif t == "lpm": @@ -262,7 +253,7 @@ def makeMask(self, value): return value values = "0123456789abcdefABCDEF*" replacements = (mask * 22) + "0" - trans = maketrans(values, replacements) + trans = str.maketrans(values, replacements) m = value.translate(trans) return prefix + value.replace("*", "0") + "&&&" + prefix + m def makeLpm(self, value): @@ -390,7 +381,7 @@ def interface_of_filename(self, f): def do_cli_command(self, cmd): if self.options.verbose: print(cmd) - self.cli_stdin.write(cmd + "\n") + self.cli_stdin.write(bytes(cmd + "\n", encoding='utf8')) self.cli_stdin.flush() self.packetDelay = 1 def do_command(self, cmd): @@ -417,7 +408,7 @@ def do_command(self, cmd): data = ''.join(data.split()) time.sleep(self.packetDelay) try: - self.interfaces[interface]._write_packet(HexToByte(data)) + self.interfaces[interface]._write_packet(bytes.fromhex(data)) except ValueError: reportError("Invalid packet data", data) return FAILURE @@ -649,7 +640,7 @@ def openInterface(ifname): line, comment = nextWord(line, "#") self.do_command(line) cli.stdin.close() - for interface, fp in self.interfaces.iteritems(): + for interface, fp in self.interfaces.items(): fp.close() # Give time to the model to execute time.sleep(2) @@ -776,7 +767,8 @@ def checkOutputs(self): del self.expected[interface] if len(self.expected) != 0: # didn't find all the expects we were expecting - reportError("Expected packects on ports", self.expected.keys(), "not received") + reportError("Expected packets on ports", + list(self.expected.keys()), "not received") return FAILURE else: return SUCCESS diff --git a/backends/bmv2/run-bmv2-test.py b/backends/bmv2/run-bmv2-test.py index bfda4f7df09..866a7a2b6a3 100755 --- a/backends/bmv2/run-bmv2-test.py +++ b/backends/bmv2/run-bmv2-test.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python3 # Copyright 2013-present Barefoot Networks, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -16,7 +16,6 @@ # Runs the compiler on a sample P4 program generating code for the BMv2 # behavioral model simulator -from __future__ import print_function from subprocess import Popen from threading import Thread import json @@ -31,7 +30,6 @@ import time import random import errno -from string import maketrans try: from scapy.layers.all import * from scapy.utils import * diff --git a/backends/ebpf/run-ebpf-test.py b/backends/ebpf/run-ebpf-test.py index c902d4970dd..5940685a639 100755 --- a/backends/ebpf/run-ebpf-test.py +++ b/backends/ebpf/run-ebpf-test.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python3 # Copyright 2013-present Barefoot Networks, Inc. # Copyright 2018 VMware, Inc. # @@ -23,7 +23,6 @@ 5. Evaluates the output with the expected result from the .stf file """ -from __future__ import print_function import sys import os import tempfile diff --git a/backends/ebpf/targets/bcc_target.py b/backends/ebpf/targets/bcc_target.py index 3e755174251..4ea1e1e6986 100644 --- a/backends/ebpf/targets/bcc_target.py +++ b/backends/ebpf/targets/bcc_target.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python3 # Copyright 2013-present Barefoot Networks, Inc. # Copyright 2018 VMware, Inc. # @@ -16,7 +16,7 @@ import os import sys -from target import EBPFTarget +from .target import EBPFTarget sys.path.insert(0, os.path.dirname( os.path.realpath(__file__)) + '/../../../tools') from testutils import * diff --git a/backends/ebpf/targets/ebpfenv.py b/backends/ebpf/targets/ebpfenv.py index 37292a30c8a..bb75cb55344 100644 --- a/backends/ebpf/targets/ebpfenv.py +++ b/backends/ebpf/targets/ebpfenv.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python3 # Copyright 2018 VMware, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/backends/ebpf/targets/ebpfstf.py b/backends/ebpf/targets/ebpfstf.py index c3f02965a93..92a43a0ac19 100644 --- a/backends/ebpf/targets/ebpfstf.py +++ b/backends/ebpf/targets/ebpfstf.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python3 # Copyright 2018 VMware, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -109,8 +109,7 @@ def parse_stf_file(raw_stf): expected = {} for stf_entry in stf_map: if stf_entry[0] == "packet": - input_pkts.setdefault(stf_entry[1], []).append( - hex_to_byte(stf_entry[2])) + input_pkts.setdefault(stf_entry[1], []).append(bytes.fromhex(stf_entry[2])) elif stf_entry[0] == "expect": interface = int(stf_entry[1]) pkt_data = stf_entry[2] diff --git a/backends/ebpf/targets/kernel_target.py b/backends/ebpf/targets/kernel_target.py index 8fbfed2abd1..010eca0d768 100644 --- a/backends/ebpf/targets/kernel_target.py +++ b/backends/ebpf/targets/kernel_target.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python3 # Copyright 2013-present Barefoot Networks, Inc. # Copyright 2018 VMware, Inc. # @@ -18,8 +18,8 @@ import sys import time from glob import glob -from ebpfenv import Bridge -from target import EBPFTarget +from .ebpfenv import Bridge +from .target import EBPFTarget # path to the tools folder of the compiler sys.path.insert(0, os.path.dirname( os.path.realpath(__file__)) + '/../../../tools') diff --git a/backends/ebpf/targets/target.py b/backends/ebpf/targets/target.py index db118889225..957852f182c 100644 --- a/backends/ebpf/targets/target.py +++ b/backends/ebpf/targets/target.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python3 # Copyright 2013-present Barefoot Networks, Inc. # Copyright 2018 VMware, Inc. # @@ -28,7 +28,7 @@ from glob import glob from scapy.utils import rdpcap, RawPcapWriter from scapy.layers.all import * -from ebpfstf import create_table_file, parse_stf_file +from .ebpfstf import create_table_file, parse_stf_file # path to the tools folder of the compiler sys.path.insert(0, os.path.dirname( os.path.realpath(__file__)) + '/../../../tools') @@ -129,6 +129,14 @@ def _write_pcap_files(self, iface_pkts_map): report_err(self.outputs["stderr"], "Invalid packet data", pkt_data) return FAILURE + fp.flush() + fp.close() + # debug -- the bytes in the pcap file should be identical to the + # hex strings in the STF file + # packets = rdpcap(infile) + # for p in packets: + # print(p.convert_to(Raw).show()) + return SUCCESS def generate_model_inputs(self, stffile): @@ -210,7 +218,7 @@ def check_outputs(self): if len(self.expected) != 0: # Didn't find all the expects we were expecting report_err(self.outputs["stderr"], "Expected packets on port(s)", - self.expected.keys(), "not received") + list(self.expected.keys()), "not received") return FAILURE report_output(self.outputs["stdout"], self.options.verbose, "All went well.") diff --git a/backends/ebpf/targets/test_target.py b/backends/ebpf/targets/test_target.py index f440f49de27..905a65ffb99 100644 --- a/backends/ebpf/targets/test_target.py +++ b/backends/ebpf/targets/test_target.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python3 # Copyright 2013-present Barefoot Networks, Inc. # Copyright 2018 VMware, Inc. # @@ -17,7 +17,7 @@ import os import sys from glob import glob -from target import EBPFTarget +from .target import EBPFTarget # path to the tools folder of the compiler sys.path.insert(0, os.path.dirname( os.path.realpath(__file__)) + '/../../../tools') diff --git a/backends/p4test/run-p4-sample.py b/backends/p4test/run-p4-sample.py index c970e6ca641..c42d17de4ff 100755 --- a/backends/p4test/run-p4-sample.py +++ b/backends/p4test/run-p4-sample.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python3 # Copyright 2013-present Barefoot Networks, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -15,7 +15,7 @@ # Runs the compiler on a sample P4 V1.2 program -from __future__ import print_function + from subprocess import Popen,PIPE from threading import Thread import errno @@ -196,7 +196,7 @@ def process_file(options, argv): if options.verbose: print("Writing temporary files into ", tmpdir) ppfile = tmpdir + "/" + basename # after parsing - referenceOutputs = ",".join(rename.keys()) + referenceOutputs = ",".join(list(rename.keys())) stderr = tmpdir + "/" + basename + "-stderr" p4runtimeFile = tmpdir + "/" + basename + ".p4info.txt" p4runtimeEntriesFile = tmpdir + "/" + basename + ".entries.txt" @@ -219,7 +219,7 @@ def process_file(options, argv): def getArch(path): v1Pattern = re.compile('include.*v1model\.p4') psaPattern = re.compile('include.*psa\.p4') - with open(path, 'r') as f: + with open(path, 'r', encoding='utf-8') as f: for line in f: if v1Pattern.search(line): return "v1model" diff --git a/testdata/p4_16_samples/gen-large.py b/testdata/p4_16_samples/gen-large.py index a135e49220e..6757aaf3ee4 100644 --- a/testdata/p4_16_samples/gen-large.py +++ b/testdata/p4_16_samples/gen-large.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python3 # Copyright 2013-present Barefoot Networks, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); @@ -18,15 +18,14 @@ size = 10000; -print "// Generated by a program"; -print "struct large {" +print("// Generated by a program"); +print("struct large {") for i in range(0, size): - print "\tbit<8> field" + str(i) + ";" -print "}" + print("\tbit<8> field" + str(i) + ";") +print("}") -print "action a() {" -print "\tlarge h;"; +print("action a() {") +print("\tlarge h;"); for i in range(0, size): - print "\th.field" + str(i) + " = 0;" -print "}" - + print("\th.field" + str(i) + " = 0;") +print("}") diff --git a/tools/driver/p4c.in b/tools/driver/p4c.in index bcf6fe6d93a..973cb33dbf2 100644 --- a/tools/driver/p4c.in +++ b/tools/driver/p4c.in @@ -1,4 +1,4 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python3 # # Copyright 2013-present Barefoot Networks, Inc. # diff --git a/tools/driver/p4c_src/config.py b/tools/driver/p4c_src/config.py index 8ec68c6478c..06bbf83b179 100644 --- a/tools/driver/p4c_src/config.py +++ b/tools/driver/p4c_src/config.py @@ -12,7 +12,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -from __future__ import absolute_import + import sys import os @@ -40,7 +40,7 @@ def load_from_config(self, path, argParser): try: data = f.read() except: - print "error", path + print("error", path) f.close() try: @@ -51,4 +51,4 @@ def load_from_config(self, path, argParser): raise except: import traceback - print traceback.format_exc() + print(traceback.format_exc()) diff --git a/tools/driver/p4c_src/driver.py b/tools/driver/p4c_src/driver.py index 375d6732af5..353d0c084bb 100644 --- a/tools/driver/p4c_src/driver.py +++ b/tools/driver/p4c_src/driver.py @@ -56,7 +56,7 @@ def add_command(self, cmd_name, cmd): If the command was previously set, it is overwritten """ if cmd_name in self._commands: - print >> sys.stderr, "Warning: overwriting command", cmd_name + print("Warning: overwriting command", cmd_name, file=sys.stderr) self._commands[cmd_name] = [] self._commands[cmd_name].append(cmd) @@ -65,8 +65,8 @@ def add_command_option(self, cmd_name, option): """ if cmd_name not in self._commands: if self._verbose: - print >> sys.stderr, "Command", "'" + cmd_name + "'", \ - "was not set for target", self._backend + print("Command", "'" + cmd_name + "'", \ + "was not set for target", self._backend, file=sys.stderr) return self._commands[cmd_name].append(option) @@ -147,8 +147,8 @@ def process_command_line_options(self, opts): # P4Runtime options if opts.p4runtime_file: - print >> sys.stderr, "'--p4runtime-file' and '--p4runtime-format'", \ - "are deprecated, consider using '--p4runtime-files'" + print("'--p4runtime-file' and '--p4runtime-format'", \ + "are deprecated, consider using '--p4runtime-files'", file=sys.stderr) self.add_command_option('compiler', "--p4runtime-file {}".format(opts.p4runtime_file)) self.add_command_option('compiler', @@ -220,7 +220,7 @@ def runCmd(self, step, cmd): Also exit with the command error code if failed """ if self._dry_run: - print '{}:\n{}'.format(step, ' '.join(cmd)) + print('{}:\n{}'.format(step, ' '.join(cmd))) return 0 args = shlex.split(" ".join(cmd)) @@ -228,11 +228,11 @@ def runCmd(self, step, cmd): p = subprocess.Popen(args) except: import traceback - print >> sys.stderr, "error invoking {}".format(" ".join(cmd)) - print >> sys.stderr, traceback.format_exc() + print("error invoking {}".format(" ".join(cmd)), file=sys.stderr) + print(traceback.format_exc(), file=sys.stderr) return 1 - if self._verbose: print 'running {}'.format(' '.join(cmd)) + if self._verbose: print('running {}'.format(' '.join(cmd))) p.communicate() # now wait return p.returncode @@ -282,7 +282,7 @@ def run(self): # run the command cmd = self._commands[c] if cmd[0].find('/') != 0 and (util.find_bin(cmd[0]) == None): - print >> sys.stderr, "{}: command not found".format(cmd[0]) + print("{}: command not found".format(cmd[0]), file=sys.stderr) sys.exit(1) rc = self.runCmd(c, cmd) diff --git a/tools/driver/p4c_src/main.py b/tools/driver/p4c_src/main.py index 38d38796783..88208843896 100644 --- a/tools/driver/p4c_src/main.py +++ b/tools/driver/p4c_src/main.py @@ -12,14 +12,14 @@ # See the License for the specific language governing permissions and # limitations under the License. -#!/usr/bin/env python2 +#!/usr/bin/env python3 """ p4c - P4 Compiler Driver """ -from __future__ import absolute_import + import argparse import glob import os @@ -193,11 +193,11 @@ def main(): # deal with early exits if opts.show_version: - print "p4c", get_version() + print("p4c", get_version()) sys.exit(0) if opts.show_target_help: - print display_supported_targets(cfg) + print(display_supported_targets(cfg)) sys.exit(0) # When using --help-* options, we don't necessarily need to pass an input file @@ -224,7 +224,8 @@ def main(): opts.source_file = opts.json_source if checkInput and not os.path.isfile(opts.source_file): - print >> sys.stderr, 'Input file ' + opts.source_file + ' does not exist' + print('Input file {} does not exist'.format(opts.source_file), + file = sys.stderr) sys.exit(1) # check that the tuple value is correct @@ -242,7 +243,8 @@ def main(): backend = target break if backend == None: - parser.error("Unknown backend: {}-{}".format(str(opts.target), str(opts.arch))) + parser.error("Unknown backend: {}-{}".format(str(opts.target), + str(opts.arch))) # set all configuration and command line options for backend backend.process_command_line_options(opts) diff --git a/tools/driver/p4c_src/util.py b/tools/driver/p4c_src/util.py index 3773347286c..5a93a043ad3 100644 --- a/tools/driver/p4c_src/util.py +++ b/tools/driver/p4c_src/util.py @@ -79,18 +79,18 @@ def check_file(f): if check_file(executable): return executable # find the file up the hierarchy - dir = os.path.abspath(get_script_dir()) + dir = os.path.abspath(get_script_dir()) if os.path.basename(filename) != filename: directory = os.path.join(directory, os.path.dirname(filename)) filename = os.path.basename(filename) while dir != "/": path_to_file = os.path.join(dir, directory) if os.path.isdir(path_to_file): - files = os.listdir(path_to_file) + files = os.listdir(path_to_file) if filename in files: executable = os.path.join(path_to_file, filename) if check_file(executable): return executable - dir = os.path.dirname(dir) - print 'File', filename, 'Not found' + dir = os.path.dirname(dir) + print('File {} not found'.format(filename)) sys.exit(1) diff --git a/tools/install_os_deps.sh b/tools/install_os_deps.sh index 9e4bf070dde..070d4a9cb87 100755 --- a/tools/install_os_deps.sh +++ b/tools/install_os_deps.sh @@ -8,7 +8,8 @@ if [[ $TRAVIS_OS_NAME == 'osx' ]]; then fi $BREW update - $BREW install autoconf automake bdw-gc bison boost ccache cmake git libtool openssl pkg-config protobuf + $BREW install autoconf automake bdw-gc bison boost ccache cmake git \ + libtool openssl pkg-config protobuf python $BREW install gmp --c++11 # Prefer Homebrew's bison over the macOS-provided version @@ -17,7 +18,7 @@ if [[ $TRAVIS_OS_NAME == 'osx' ]]; then export PATH="/usr/local/opt/bison/bin:$PATH" # install pip and required pip packages - curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py - python get-pip.py --user - pip install --user scapy==2.4.0 ply + # curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py + # python get-pip.py --user + pip3 install --user scapy==2.4.0 ply==3.8 fi diff --git a/tools/stf/stf_lexer.py b/tools/stf/stf_lexer.py index 3d756b199f9..762b474a274 100644 --- a/tools/stf/stf_lexer.py +++ b/tools/stf/stf_lexer.py @@ -64,7 +64,7 @@ def build(self,**kwargs): self.lexer.begin('keyword') def _error(self, s, token): - print s, "in file", self.filename, "at line", self.get_lineno() + print(s, "in file", self.filename, "at line", self.get_lineno()) self.errors_cnt += 1 states = ( diff --git a/tools/stf/stf_parser.py b/tools/stf/stf_parser.py index 9a0adf2aa82..fdb472584f8 100644 --- a/tools/stf/stf_parser.py +++ b/tools/stf/stf_parser.py @@ -19,7 +19,7 @@ # ----------------------------------------------------------------------------- import ply.yacc as yacc -from stf_lexer import STFLexer +from .stf_lexer import STFLexer # PARSER GRAMMAR -------------------------------------------------------------- @@ -90,7 +90,7 @@ def __init__(self): def parse(self, data = None, filename=''): if data is None and filename == '': - raise "Please specify either a filename or data" + raise ValueError("Please specify either a filename or data") # if we specified only the filename, initialize the data if data is None: @@ -105,11 +105,11 @@ def parse(self, data = None, filename=''): def print_error(self, lineno, lexpos, msg): self.errors_cnt += 1 - print "parse error (%s%s:%s): %s" % ( + print("parse error (%s%s:%s): %s" % ( '%s:' % self.lexer.filename if self.lexer.filename else '', lineno, lexpos, - msg) + msg)) def get_filename(self): return self.lexer.filename @@ -342,4 +342,4 @@ def p_expect_dataum(self, p): parser = STFParser() stf, errs = parser.parse(data) if errs == 0: - print '\n'.join(map(str, stf)) + print('\n'.join(map(str, stf))) diff --git a/tools/stf/stf_runner.py b/tools/stf/stf_runner.py index e7cbb0853d1..050beb96622 100644 --- a/tools/stf/stf_runner.py +++ b/tools/stf/stf_runner.py @@ -18,7 +18,6 @@ # the STF statements. import logging -from string import maketrans class STFNamedEntry: """ @@ -40,7 +39,7 @@ class STFRunner(object): def __init__(self, ast, testname): testNameEscapeChars = "-" testNameEscapes = "_"*len(testNameEscapeChars) - self._transTable = maketrans(testNameEscapeChars,testNameEscapes) + self._transTable = str.maketrans(testNameEscapeChars,testNameEscapes) self._testname = testname.translate(self._transTable) logging.basicConfig(level=logging.INFO) self._logger = logging.getLogger(self._testname) diff --git a/tools/stf/stf_test.py b/tools/stf/stf_test.py index 7f82d1df8d3..8be0ab04c5c 100755 --- a/tools/stf/stf_test.py +++ b/tools/stf/stf_test.py @@ -1,4 +1,4 @@ -#! /usr/bin/env python2 +#! /usr/bin/env python3 # # Copyright 2013-present Barefoot Networks, Inc. # @@ -25,8 +25,8 @@ import time import traceback import unittest -from stf_parser import STFParser -from stf_runner import STFRunner +from .stf_parser import STFParser +from .stf_runner import STFRunner class STFTest (STFRunner): def __init__(self, ast, testname): diff --git a/tools/testutils.py b/tools/testutils.py index 54ff797afc7..b567e690e3b 100644 --- a/tools/testutils.py +++ b/tools/testutils.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python2 +#!/usr/bin/env python3 # Copyright 2013-present Barefoot Networks, Inc. # Copyright 2018 VMware, Inc. # @@ -17,12 +17,12 @@ """ Defines helper functions for a general testing framework. Used by multiple Python testing scripts in the backends folder.""" -from __future__ import print_function import subprocess from subprocess import Popen from threading import Timer import sys import os +from scapy.packet import Raw TIMEOUT = 10 * 60 SUCCESS = 0 @@ -56,11 +56,6 @@ def report_output(file, verbose, *message): out_file.close() -def byte_to_hex(byteStr): - """ Convert byte sequences to a hex string. """ - return ''.join(["%02X " % ord(x) for x in byteStr]).strip() - - def hex_to_byte(hexStr): """ Convert hex strings to bytes. """ bytes = [] @@ -73,7 +68,7 @@ def hex_to_byte(hexStr): def compare_pkt(outputs, expected, received): """ Compare two given byte sequences and check if they are the same. Report errors if this is not the case. """ - received = ''.join(byte_to_hex(str(received)).split()).upper() + received = received.convert_to(Raw).load.hex().upper() expected = ''.join(expected.split()).upper() if len(received) < len(expected): report_err(outputs["stderr"], "Received packet too short", diff --git a/tools/travis-build b/tools/travis-build index 8a32354cf64..36d1e468e85 100644 --- a/tools/travis-build +++ b/tools/travis-build @@ -17,6 +17,10 @@ export P4C_DEPS="bison \ libgc-dev \ libgmp-dev \ pkg-config \ + python \ + python3 \ + python3-pip \ + python3-setuptools \ tcpdump" export P4C_EBPF_DEPS="libpcap-dev \ @@ -32,13 +36,18 @@ export P4C_RUNTIME_DEPS="cpp \ libgc1c2 \ libgmp10 \ libgmpxx4ldbl \ - python" + python3" export P4C_PIP_PACKAGES="ipaddr \ pyroute2 \ ply==3.8 \ scapy==2.4.0" +export P4C_PIP3_PACKAGES="ipaddr \ + pyroute2 \ + ply==3.8 \ + scapy" + apt-get update apt-get install -y --no-install-recommends \ ${P4C_DEPS} \ @@ -46,20 +55,28 @@ apt-get install -y --no-install-recommends \ ${P4C_RUNTIME_DEPS} \ git +pip3 install $P4C_PIP3_PACKAGES + +# ! ------- BEGIN Python2 ------------------------------------------------- +# ! ------- Should be deleted when conversion to Python3 is finalized ----- # We install pip with get-pip.py (https://pip.pypa.io/en/stable/installing/) # since the Ubuntu package manager's version of pip seems to be broken on # Ubuntu 16.04. mkdir /tmp/pip cd /tmp/pip curl https://bootstrap.pypa.io/get-pip.py -o get-pip.py -python get-pip.py +python2 get-pip.py cd - rm -rf /tmp/pip +# just to make sure we don't break other downstream projects that have +# not yet converted, we still install python2 and the modules pip install $P4C_PIP_PACKAGES +# ! ------ END Python2 ---------------------------------------------------- function build() { - mkdir build + if [ -e build ]; then /bin/rm -rf build; fi + mkdir -p build cd build cmake .. '-DCMAKE_CXX_FLAGS:STRING=-O3' "$@" From a9b95be307ebe8a0e6d3dd284342e5add69b23a3 Mon Sep 17 00:00:00 2001 From: Mihai Budiu Date: Wed, 20 Nov 2019 15:40:10 -0800 Subject: [PATCH 030/106] Insert cast for signed slices; fixes #2090 (#2091) * Insert cast for signed slices; fixes #2090 --- midend/expandLookahead.cpp | 6 +- testdata/p4_16_samples/issue2090.p4 | 67 +++++++++++++ testdata/p4_16_samples/spec-ex19.p4 | 5 + .../p4_16_samples_outputs/issue2090-first.p4 | 91 ++++++++++++++++++ .../issue2090-frontend.p4 | 95 +++++++++++++++++++ .../p4_16_samples_outputs/issue2090-midend.p4 | 94 ++++++++++++++++++ testdata/p4_16_samples_outputs/issue2090.p4 | 91 ++++++++++++++++++ .../p4_16_samples_outputs/issue2090.p4-stderr | 0 .../p4_16_samples_outputs/spec-ex19-first.p4 | 4 + .../spec-ex19-frontend.p4 | 47 +++++++++ .../p4_16_samples_outputs/spec-ex19-midend.p4 | 92 ++++++++++++++++++ testdata/p4_16_samples_outputs/spec-ex19.p4 | 4 + .../p4_16_samples_outputs/spec-ex19.p4-stderr | 1 - 13 files changed, 595 insertions(+), 2 deletions(-) create mode 100644 testdata/p4_16_samples/issue2090.p4 create mode 100644 testdata/p4_16_samples_outputs/issue2090-first.p4 create mode 100644 testdata/p4_16_samples_outputs/issue2090-frontend.p4 create mode 100644 testdata/p4_16_samples_outputs/issue2090-midend.p4 create mode 100644 testdata/p4_16_samples_outputs/issue2090.p4 create mode 100644 testdata/p4_16_samples_outputs/issue2090.p4-stderr create mode 100644 testdata/p4_16_samples_outputs/spec-ex19-midend.p4 diff --git a/midend/expandLookahead.cpp b/midend/expandLookahead.cpp index 390d411a778..707a92978a3 100644 --- a/midend/expandLookahead.cpp +++ b/midend/expandLookahead.cpp @@ -56,7 +56,11 @@ const IR::Expression* DoExpandLookahead::expand( } else if (type->is() || type->is()) { unsigned size = type->width_bits(); BUG_CHECK(size > 0, "%1%: unexpected size %2%", type, size); - auto expression = new IR::Slice(base->clone(), *offset - 1, *offset - size); + const IR::Expression* expression = + new IR::Slice(base->clone(), *offset - 1, *offset - size); + auto tb = type->to(); + if (!tb || tb->isSigned) + expression = new IR::Cast(type, expression); *offset -= size; return expression; } else { diff --git a/testdata/p4_16_samples/issue2090.p4 b/testdata/p4_16_samples/issue2090.p4 new file mode 100644 index 00000000000..c813771a5e5 --- /dev/null +++ b/testdata/p4_16_samples/issue2090.p4 @@ -0,0 +1,67 @@ +/* +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 + +#include "spec-ex09.p4" + +struct Tcp_option_sack_top +{ + int<8> kind; + bit<8> length; + bool f; + bit<7> padding; +} +parser Tcp_option_parser(packet_in b, + out Tcp_option_stack vec) +{ + state start { + transition select(b.lookahead>()) { + 8w0x0 : parse_tcp_option_end; + 8w0x1 : parse_tcp_option_nop; + 8w0x2 : parse_tcp_option_ss; + 8w0x3 : parse_tcp_option_s; + 8w0x5 : parse_tcp_option_sack; + } + } + state parse_tcp_option_end { + b.extract(vec.next.end); + transition accept; + } + state parse_tcp_option_nop { + b.extract(vec.next.nop); + transition start; + } + state parse_tcp_option_ss { + b.extract(vec.next.ss); + transition start; + } + state parse_tcp_option_s { + b.extract(vec.next.s); + transition start; + } + state parse_tcp_option_sack { + b.extract(vec.next.sack, + (bit<32>)(8 * (b.lookahead().length) - + 16)); + transition start; + } +} + +parser pr(packet_in b, out H h); +package top(pr p); + +top(Tcp_option_parser()) main; diff --git a/testdata/p4_16_samples/spec-ex19.p4 b/testdata/p4_16_samples/spec-ex19.p4 index 2c71a2659db..57d84503b99 100644 --- a/testdata/p4_16_samples/spec-ex19.p4 +++ b/testdata/p4_16_samples/spec-ex19.p4 @@ -58,3 +58,8 @@ parser Tcp_option_parser(packet_in b, transition start; } } + +parser pr(packet_in b, out H h); +package top(pr p); + +top(Tcp_option_parser()) main; diff --git a/testdata/p4_16_samples_outputs/issue2090-first.p4 b/testdata/p4_16_samples_outputs/issue2090-first.p4 new file mode 100644 index 00000000000..d4e83ee5312 --- /dev/null +++ b/testdata/p4_16_samples_outputs/issue2090-first.p4 @@ -0,0 +1,91 @@ +#include + +header Mpls_h { + bit<20> label; + bit<3> tc; + bit<1> bos; + bit<8> ttl; +} + +control p() { + apply { + Mpls_h[10] mpls_vec; + } +} + +header Tcp_option_end_h { + bit<8> kind; +} + +header Tcp_option_nop_h { + bit<8> kind; +} + +header Tcp_option_ss_h { + bit<8> kind; + bit<32> maxSegmentSize; +} + +header Tcp_option_s_h { + bit<8> kind; + bit<24> scale; +} + +header Tcp_option_sack_h { + bit<8> kind; + bit<8> length; + varbit<256> sack; +} + +header_union Tcp_option_h { + Tcp_option_end_h end; + Tcp_option_nop_h nop; + Tcp_option_ss_h ss; + Tcp_option_s_h s; + Tcp_option_sack_h sack; +} + +typedef Tcp_option_h[10] Tcp_option_stack; +struct Tcp_option_sack_top { + int<8> kind; + bit<8> length; + bool f; + bit<7> padding; +} + +parser Tcp_option_parser(packet_in b, out Tcp_option_stack vec) { + state start { + transition select(b.lookahead>()) { + 8w0x0: parse_tcp_option_end; + 8w0x1: parse_tcp_option_nop; + 8w0x2: parse_tcp_option_ss; + 8w0x3: parse_tcp_option_s; + 8w0x5: parse_tcp_option_sack; + } + } + state parse_tcp_option_end { + b.extract(vec.next.end); + transition accept; + } + state parse_tcp_option_nop { + b.extract(vec.next.nop); + transition start; + } + state parse_tcp_option_ss { + b.extract(vec.next.ss); + transition start; + } + state parse_tcp_option_s { + b.extract(vec.next.s); + transition start; + } + state parse_tcp_option_sack { + b.extract(vec.next.sack, (bit<32>)(((b.lookahead()).length << 3) + 8w240)); + transition start; + } +} + +parser pr(packet_in b, out H h); +package top(pr p); +top(Tcp_option_parser()) main; + diff --git a/testdata/p4_16_samples_outputs/issue2090-frontend.p4 b/testdata/p4_16_samples_outputs/issue2090-frontend.p4 new file mode 100644 index 00000000000..fc190a8122a --- /dev/null +++ b/testdata/p4_16_samples_outputs/issue2090-frontend.p4 @@ -0,0 +1,95 @@ +#include + +header Mpls_h { + bit<20> label; + bit<3> tc; + bit<1> bos; + bit<8> ttl; +} + +header Tcp_option_end_h { + bit<8> kind; +} + +header Tcp_option_nop_h { + bit<8> kind; +} + +header Tcp_option_ss_h { + bit<8> kind; + bit<32> maxSegmentSize; +} + +header Tcp_option_s_h { + bit<8> kind; + bit<24> scale; +} + +header Tcp_option_sack_h { + bit<8> kind; + bit<8> length; + varbit<256> sack; +} + +header_union Tcp_option_h { + Tcp_option_end_h end; + Tcp_option_nop_h nop; + Tcp_option_ss_h ss; + Tcp_option_s_h s; + Tcp_option_sack_h sack; +} + +typedef Tcp_option_h[10] Tcp_option_stack; +struct Tcp_option_sack_top { + int<8> kind; + bit<8> length; + bool f; + bit<7> padding; +} + +parser Tcp_option_parser(packet_in b, out Tcp_option_stack vec) { + bit<8> tmp; + Tcp_option_sack_top tmp_0; + bit<8> tmp_1; + bit<8> tmp_2; + bit<32> tmp_3; + state start { + tmp = b.lookahead>(); + transition select(tmp) { + 8w0x0: parse_tcp_option_end; + 8w0x1: parse_tcp_option_nop; + 8w0x2: parse_tcp_option_ss; + 8w0x3: parse_tcp_option_s; + 8w0x5: parse_tcp_option_sack; + } + } + state parse_tcp_option_end { + b.extract(vec.next.end); + transition accept; + } + state parse_tcp_option_nop { + b.extract(vec.next.nop); + transition start; + } + state parse_tcp_option_ss { + b.extract(vec.next.ss); + transition start; + } + state parse_tcp_option_s { + b.extract(vec.next.s); + transition start; + } + state parse_tcp_option_sack { + tmp_0 = b.lookahead(); + tmp_1 = tmp_0.length << 3; + tmp_2 = tmp_1 + 8w240; + tmp_3 = (bit<32>)tmp_2; + b.extract(vec.next.sack, tmp_3); + transition start; + } +} + +parser pr(packet_in b, out H h); +package top(pr p); +top(Tcp_option_parser()) main; + diff --git a/testdata/p4_16_samples_outputs/issue2090-midend.p4 b/testdata/p4_16_samples_outputs/issue2090-midend.p4 new file mode 100644 index 00000000000..38e04afa9e5 --- /dev/null +++ b/testdata/p4_16_samples_outputs/issue2090-midend.p4 @@ -0,0 +1,94 @@ +#include + +header Mpls_h { + bit<20> label; + bit<3> tc; + bit<1> bos; + bit<8> ttl; +} + +header Tcp_option_end_h { + bit<8> kind; +} + +header Tcp_option_nop_h { + bit<8> kind; +} + +header Tcp_option_ss_h { + bit<8> kind; + bit<32> maxSegmentSize; +} + +header Tcp_option_s_h { + bit<8> kind; + bit<24> scale; +} + +header Tcp_option_sack_h { + bit<8> kind; + bit<8> length; + varbit<256> sack; +} + +header_union Tcp_option_h { + Tcp_option_end_h end; + Tcp_option_nop_h nop; + Tcp_option_ss_h ss; + Tcp_option_s_h s; + Tcp_option_sack_h sack; +} + +typedef Tcp_option_h[10] Tcp_option_stack; +struct Tcp_option_sack_top { + int<8> kind; + bit<8> length; + bool f; + bit<7> padding; +} + +parser Tcp_option_parser(packet_in b, out Tcp_option_stack vec) { + bit<8> tmp; + bit<24> tmp_4; + state start { + tmp = b.lookahead>(); + transition select(tmp) { + 8w0x0: parse_tcp_option_end; + 8w0x1: parse_tcp_option_nop; + 8w0x2: parse_tcp_option_ss; + 8w0x3: parse_tcp_option_s; + 8w0x5: parse_tcp_option_sack; + default: noMatch; + } + } + state parse_tcp_option_end { + b.extract(vec.next.end); + transition accept; + } + state parse_tcp_option_nop { + b.extract(vec.next.nop); + transition start; + } + state parse_tcp_option_ss { + b.extract(vec.next.ss); + transition start; + } + state parse_tcp_option_s { + b.extract(vec.next.s); + transition start; + } + state parse_tcp_option_sack { + tmp_4 = b.lookahead>(); + b.extract(vec.next.sack, (bit<32>)((tmp_4[15:8] << 3) + 8w240)); + transition start; + } + state noMatch { + verify(false, error.NoMatch); + transition reject; + } +} + +parser pr(packet_in b, out H h); +package top(pr p); +top(Tcp_option_parser()) main; + diff --git a/testdata/p4_16_samples_outputs/issue2090.p4 b/testdata/p4_16_samples_outputs/issue2090.p4 new file mode 100644 index 00000000000..75a5ce919bf --- /dev/null +++ b/testdata/p4_16_samples_outputs/issue2090.p4 @@ -0,0 +1,91 @@ +#include + +header Mpls_h { + bit<20> label; + bit<3> tc; + bit<1> bos; + bit<8> ttl; +} + +control p() { + apply { + Mpls_h[10] mpls_vec; + } +} + +header Tcp_option_end_h { + bit<8> kind; +} + +header Tcp_option_nop_h { + bit<8> kind; +} + +header Tcp_option_ss_h { + bit<8> kind; + bit<32> maxSegmentSize; +} + +header Tcp_option_s_h { + bit<8> kind; + bit<24> scale; +} + +header Tcp_option_sack_h { + bit<8> kind; + bit<8> length; + varbit<256> sack; +} + +header_union Tcp_option_h { + Tcp_option_end_h end; + Tcp_option_nop_h nop; + Tcp_option_ss_h ss; + Tcp_option_s_h s; + Tcp_option_sack_h sack; +} + +typedef Tcp_option_h[10] Tcp_option_stack; +struct Tcp_option_sack_top { + int<8> kind; + bit<8> length; + bool f; + bit<7> padding; +} + +parser Tcp_option_parser(packet_in b, out Tcp_option_stack vec) { + state start { + transition select(b.lookahead>()) { + 8w0x0: parse_tcp_option_end; + 8w0x1: parse_tcp_option_nop; + 8w0x2: parse_tcp_option_ss; + 8w0x3: parse_tcp_option_s; + 8w0x5: parse_tcp_option_sack; + } + } + state parse_tcp_option_end { + b.extract(vec.next.end); + transition accept; + } + state parse_tcp_option_nop { + b.extract(vec.next.nop); + transition start; + } + state parse_tcp_option_ss { + b.extract(vec.next.ss); + transition start; + } + state parse_tcp_option_s { + b.extract(vec.next.s); + transition start; + } + state parse_tcp_option_sack { + b.extract(vec.next.sack, (bit<32>)(8 * (b.lookahead()).length - 16)); + transition start; + } +} + +parser pr(packet_in b, out H h); +package top(pr p); +top(Tcp_option_parser()) main; + diff --git a/testdata/p4_16_samples_outputs/issue2090.p4-stderr b/testdata/p4_16_samples_outputs/issue2090.p4-stderr new file mode 100644 index 00000000000..e69de29bb2d diff --git a/testdata/p4_16_samples_outputs/spec-ex19-first.p4 b/testdata/p4_16_samples_outputs/spec-ex19-first.p4 index c8cf179ecdd..6b7bf584b4a 100644 --- a/testdata/p4_16_samples_outputs/spec-ex19-first.p4 +++ b/testdata/p4_16_samples_outputs/spec-ex19-first.p4 @@ -83,3 +83,7 @@ parser Tcp_option_parser(packet_in b, out Tcp_option_stack vec) { } } +parser pr(packet_in b, out H h); +package top(pr p); +top(Tcp_option_parser()) main; + diff --git a/testdata/p4_16_samples_outputs/spec-ex19-frontend.p4 b/testdata/p4_16_samples_outputs/spec-ex19-frontend.p4 index 657c0ad3531..33dea379a77 100644 --- a/testdata/p4_16_samples_outputs/spec-ex19-frontend.p4 +++ b/testdata/p4_16_samples_outputs/spec-ex19-frontend.p4 @@ -39,8 +39,55 @@ header_union Tcp_option_h { Tcp_option_sack_h sack; } +typedef Tcp_option_h[10] Tcp_option_stack; struct Tcp_option_sack_top { bit<8> kind; bit<8> length; } +parser Tcp_option_parser(packet_in b, out Tcp_option_stack vec) { + bit<8> tmp; + Tcp_option_sack_top tmp_0; + bit<8> tmp_1; + bit<8> tmp_2; + bit<32> tmp_3; + state start { + tmp = b.lookahead>(); + transition select(tmp) { + 8w0x0: parse_tcp_option_end; + 8w0x1: parse_tcp_option_nop; + 8w0x2: parse_tcp_option_ss; + 8w0x3: parse_tcp_option_s; + 8w0x5: parse_tcp_option_sack; + } + } + state parse_tcp_option_end { + b.extract(vec.next.end); + transition accept; + } + state parse_tcp_option_nop { + b.extract(vec.next.nop); + transition start; + } + state parse_tcp_option_ss { + b.extract(vec.next.ss); + transition start; + } + state parse_tcp_option_s { + b.extract(vec.next.s); + transition start; + } + state parse_tcp_option_sack { + tmp_0 = b.lookahead(); + tmp_1 = tmp_0.length << 3; + tmp_2 = tmp_1 + 8w240; + tmp_3 = (bit<32>)tmp_2; + b.extract(vec.next.sack, tmp_3); + transition start; + } +} + +parser pr(packet_in b, out H h); +package top(pr p); +top(Tcp_option_parser()) main; + diff --git a/testdata/p4_16_samples_outputs/spec-ex19-midend.p4 b/testdata/p4_16_samples_outputs/spec-ex19-midend.p4 new file mode 100644 index 00000000000..850ec2d1743 --- /dev/null +++ b/testdata/p4_16_samples_outputs/spec-ex19-midend.p4 @@ -0,0 +1,92 @@ +#include + +header Mpls_h { + bit<20> label; + bit<3> tc; + bit<1> bos; + bit<8> ttl; +} + +header Tcp_option_end_h { + bit<8> kind; +} + +header Tcp_option_nop_h { + bit<8> kind; +} + +header Tcp_option_ss_h { + bit<8> kind; + bit<32> maxSegmentSize; +} + +header Tcp_option_s_h { + bit<8> kind; + bit<24> scale; +} + +header Tcp_option_sack_h { + bit<8> kind; + bit<8> length; + varbit<256> sack; +} + +header_union Tcp_option_h { + Tcp_option_end_h end; + Tcp_option_nop_h nop; + Tcp_option_ss_h ss; + Tcp_option_s_h s; + Tcp_option_sack_h sack; +} + +typedef Tcp_option_h[10] Tcp_option_stack; +struct Tcp_option_sack_top { + bit<8> kind; + bit<8> length; +} + +parser Tcp_option_parser(packet_in b, out Tcp_option_stack vec) { + bit<8> tmp; + bit<16> tmp_4; + state start { + tmp = b.lookahead>(); + transition select(tmp) { + 8w0x0: parse_tcp_option_end; + 8w0x1: parse_tcp_option_nop; + 8w0x2: parse_tcp_option_ss; + 8w0x3: parse_tcp_option_s; + 8w0x5: parse_tcp_option_sack; + default: noMatch; + } + } + state parse_tcp_option_end { + b.extract(vec.next.end); + transition accept; + } + state parse_tcp_option_nop { + b.extract(vec.next.nop); + transition start; + } + state parse_tcp_option_ss { + b.extract(vec.next.ss); + transition start; + } + state parse_tcp_option_s { + b.extract(vec.next.s); + transition start; + } + state parse_tcp_option_sack { + tmp_4 = b.lookahead>(); + b.extract(vec.next.sack, (bit<32>)((tmp_4[7:0] << 3) + 8w240)); + transition start; + } + state noMatch { + verify(false, error.NoMatch); + transition reject; + } +} + +parser pr(packet_in b, out H h); +package top(pr p); +top(Tcp_option_parser()) main; + diff --git a/testdata/p4_16_samples_outputs/spec-ex19.p4 b/testdata/p4_16_samples_outputs/spec-ex19.p4 index c1578fda96b..60bd2c2402d 100644 --- a/testdata/p4_16_samples_outputs/spec-ex19.p4 +++ b/testdata/p4_16_samples_outputs/spec-ex19.p4 @@ -83,3 +83,7 @@ parser Tcp_option_parser(packet_in b, out Tcp_option_stack vec) { } } +parser pr(packet_in b, out H h); +package top(pr p); +top(Tcp_option_parser()) main; + diff --git a/testdata/p4_16_samples_outputs/spec-ex19.p4-stderr b/testdata/p4_16_samples_outputs/spec-ex19.p4-stderr index 7f94c95a8ff..e69de29bb2d 100644 --- a/testdata/p4_16_samples_outputs/spec-ex19.p4-stderr +++ b/testdata/p4_16_samples_outputs/spec-ex19.p4-stderr @@ -1 +0,0 @@ -warning: Program does not contain a `main' module From 9648d1104d38df2726c74d305efb88cda36444bf Mon Sep 17 00:00:00 2001 From: Antonin Bas Date: Sun, 17 Nov 2019 19:47:21 -0800 Subject: [PATCH 031/106] Fix SerEnum member values in generated P4Info The value should be a P4Runtime "bytestring" and not a human-readable hexadecimal string. Thanks to @mbudiu-vmw for his help making the SerEnum Google Test work. --- control-plane/CMakeLists.txt | 2 + control-plane/bytestrings.cpp | 68 +++++++++++++++++++ control-plane/bytestrings.h | 47 +++++++++++++ control-plane/p4RuntimeSerializer.cpp | 35 +--------- control-plane/typeSpecConverter.cpp | 12 +++- test/gtest/p4runtime.cpp | 29 +++++++- testdata/p4_16_samples/register-serenum.p4 | 49 +++++++++++++ .../logging.p4.entries.txt | 0 .../logging.p4.p4info.txt | 35 ++++++++++ .../register-serenum-first.p4 | 47 +++++++++++++ .../register-serenum-frontend.p4 | 47 +++++++++++++ .../register-serenum-midend.p4 | 46 +++++++++++++ .../p4_16_samples_outputs/register-serenum.p4 | 47 +++++++++++++ .../register-serenum.p4-stderr | 0 .../register-serenum.p4.entries.txt | 0 .../register-serenum.p4.p4info.txt | 54 +++++++++++++++ ...l-digest-containing-ser-enum.p4.p4info.txt | 6 +- 17 files changed, 484 insertions(+), 40 deletions(-) create mode 100644 control-plane/bytestrings.cpp create mode 100644 control-plane/bytestrings.h create mode 100644 testdata/p4_16_samples/register-serenum.p4 create mode 100644 testdata/p4_16_samples_outputs/logging.p4.entries.txt create mode 100644 testdata/p4_16_samples_outputs/logging.p4.p4info.txt create mode 100644 testdata/p4_16_samples_outputs/register-serenum-first.p4 create mode 100644 testdata/p4_16_samples_outputs/register-serenum-frontend.p4 create mode 100644 testdata/p4_16_samples_outputs/register-serenum-midend.p4 create mode 100644 testdata/p4_16_samples_outputs/register-serenum.p4 create mode 100644 testdata/p4_16_samples_outputs/register-serenum.p4-stderr create mode 100644 testdata/p4_16_samples_outputs/register-serenum.p4.entries.txt create mode 100644 testdata/p4_16_samples_outputs/register-serenum.p4.p4info.txt diff --git a/control-plane/CMakeLists.txt b/control-plane/CMakeLists.txt index 259bbb01d11..16f1e467b79 100644 --- a/control-plane/CMakeLists.txt +++ b/control-plane/CMakeLists.txt @@ -71,6 +71,7 @@ add_custom_command(OUTPUT ${P4RUNTIME_GEN_SRCS} ${P4RUNTIME_GEN_HDRS} #PROTOBUF_GENERATE_PYTHON (P4RUNTIME_GEN_PYTHON P4RUNTIME_INFO_GEN_HDRS ${P4RUNTIME_INFO_PROTO}) set (CONTROLPLANE_SRCS + bytestrings.cpp flattenHeader.cpp p4RuntimeArchHandler.cpp p4RuntimeArchStandard.cpp @@ -83,6 +84,7 @@ set (CONTROLPLANE_SOURCES ) set (CONTROLPLANE_HDRS + bytestrings.h flattenHeader.h p4RuntimeArchHandler.h p4RuntimeArchStandard.h diff --git a/control-plane/bytestrings.cpp b/control-plane/bytestrings.cpp new file mode 100644 index 00000000000..4bc19102c1b --- /dev/null +++ b/control-plane/bytestrings.cpp @@ -0,0 +1,68 @@ +/* +Copyright 2019 VMware, 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 "bytestrings.h" + +#include "ir/ir.h" + +namespace P4 { + +namespace ControlPlaneAPI { + +/// Convert a bignum to the P4Runtime bytes representation. The value must fit +/// within the provided @width expressed in bits. Padding will be added as +/// necessary (as the most significant bits). +boost::optional stringReprConstant(mpz_class value, int width) { + // TODO(antonin): support negative values + if (value < 0) { + ::error("%1%: Negative values not supported yet", value); + return boost::none; + } + BUG_CHECK(width > 0, "Unexpected width 0"); + auto bitsRequired = static_cast(mpz_sizeinbase(value.get_mpz_t(), 2)); + BUG_CHECK(static_cast(width) >= bitsRequired, + "Cannot represent %1% on %2% bits", value, width); + // TODO(antonin): P4Runtime defines the canonical representation for bit + // value as the smallest binary string required to represent the value (no 0 + // padding). Unfortunately the reference P4Runtime implementation + // (https://github.com/p4lang/PI) does not currently support the canonical + // representation, so instead we use a padded binary string, which according + // to the P4Runtime specification is also valid (but not the canonical + // representation, which means no RW symmetry). + // auto bytes = ROUNDUP(mpz_sizeinbase(value.get_mpz_t(), 2), 8); + auto bytes = ROUNDUP(width, 8); + std::vector data(bytes); + mpz_export(data.data(), NULL, 1 /* big endian word */, bytes, + 1 /* big endian bytes */, 0 /* full words */, value.get_mpz_t()); + return std::string(data.begin(), data.end()); +} + +/// Convert a Constant to the P4Runtime bytes representation by calling +/// stringReprConstant. +boost::optional stringRepr(const IR::Constant* constant, int width) { + return stringReprConstant(constant->value, width); +} + +/// Convert a BoolLiteral to the P4Runtime bytes representation by calling +/// stringReprConstant. +boost::optional stringRepr(const IR::BoolLiteral* constant, int width) { + auto v = static_cast(constant->value ? 1 : 0); + return stringReprConstant(v, width); +} + +} // namespace ControlPlaneAPI + +} // namespace P4 diff --git a/control-plane/bytestrings.h b/control-plane/bytestrings.h new file mode 100644 index 00000000000..0242138a627 --- /dev/null +++ b/control-plane/bytestrings.h @@ -0,0 +1,47 @@ +/* +Copyright 2019 VMware, 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. +*/ + +#ifndef CONTROL_PLANE_BYTESTRINGS_H_ +#define CONTROL_PLANE_BYTESTRINGS_H_ + +#include + +#include + +#include "lib/gmputil.h" + +namespace IR { + +class Constant; +class BoolLiteral; + +} // namespace IR + +namespace P4 { + +namespace ControlPlaneAPI { + +boost::optional stringRepr(const IR::Constant* constant, int width); + +boost::optional stringRepr(const IR::BoolLiteral* constant, int width); + +boost::optional stringReprConstant(mpz_class value, int width); + +} // namespace ControlPlaneAPI + +} // namespace P4 + +#endif // CONTROL_PLANE_BYTESTRINGS_H_ diff --git a/control-plane/p4RuntimeSerializer.cpp b/control-plane/p4RuntimeSerializer.cpp index 43223eb4e1f..aca87c1bf25 100644 --- a/control-plane/p4RuntimeSerializer.cpp +++ b/control-plane/p4RuntimeSerializer.cpp @@ -58,6 +58,7 @@ limitations under the License. #include "p4RuntimeArchHandler.h" #include "p4RuntimeArchStandard.h" #include "flattenHeader.h" +#include "bytestrings.h" namespace p4v1 = ::p4::v1; namespace p4configv1 = ::p4::config::v1; @@ -1642,40 +1643,6 @@ class P4RuntimeEntriesConverter { return mt->name.name; } - boost::optional stringReprConstant(mpz_class value, int width) const { - if (value < 0) { - ::error("%1%: P4Runtime does not support negative values in match key", value); - return boost::none; - } - BUG_CHECK(width > 0, "Cannot have match fields with width 0"); - auto bitsRequired = static_cast(mpz_sizeinbase(value.get_mpz_t(), 2)); - BUG_CHECK(static_cast(width) >= bitsRequired, - "Cannot represent %1% on %2% bits", value, width); - // TODO(antonin): P4Runtime defines the canonical representation for - // bit value as the smallest binary string required to represent the - // value (no 0 padding). Unfortunately the reference P4Runtime - // implementation (https://github.com/p4lang/PI) does not currently - // support the canonical representation, so instead we use a padded - // binary string, which according to the P4Runtime specification is also - // valid (but not the canonical representation, which means no RW - // symmetry). - // auto bytes = ROUNDUP(mpz_sizeinbase(value.get_mpz_t(), 2), 8); - auto bytes = ROUNDUP(width, 8); - std::vector data(bytes); - mpz_export(data.data(), NULL, 1 /* big endian word */, bytes, - 1 /* big endian bytes */, 0 /* full words */, value.get_mpz_t()); - return std::string(data.begin(), data.end()); - } - - boost::optional stringRepr(const IR::Constant* constant, int width) const { - return stringReprConstant(constant->value, width); - } - - boost::optional stringRepr(const IR::BoolLiteral* constant, int width) const { - auto v = static_cast(constant->value ? 1 : 0); - return stringReprConstant(v, width); - } - /// We represent all static table entries as one P4Runtime WriteRequest object p4v1::WriteRequest *entries; /// The symbols used in the API and their ids. diff --git a/control-plane/typeSpecConverter.cpp b/control-plane/typeSpecConverter.cpp index 046bff6fd11..fff9cb5ee34 100644 --- a/control-plane/typeSpecConverter.cpp +++ b/control-plane/typeSpecConverter.cpp @@ -19,6 +19,7 @@ limitations under the License. #include "p4/config/v1/p4types.pb.h" +#include "bytestrings.h" #include "flattenHeader.h" #include "frontends/common/resolveReferences/referenceMap.h" #include "frontends/p4/typeMap.h" @@ -308,11 +309,18 @@ bool TypeSpecConverter::preorder(const IR::Type_SerEnum* type) { if (enums->find(name) == enums->end()) { auto enumTypeSpec = new p4configv1::P4SerializableEnumTypeSpec(); auto bitTypeSpec = enumTypeSpec->mutable_underlying_type(); - bitTypeSpec->set_bitwidth(type->type->width_bits()); + auto width = type->type->width_bits(); + bitTypeSpec->set_bitwidth(width); for (auto m : type->members) { auto member = enumTypeSpec->add_members(); member->set_name(m->controlPlaneName()); - member->set_value(std::string(m->value->toString())); + if (!m->value->is()) { + ::error("%1% unsupported SerEnum member value", m->value); + continue; + } + auto value = stringRepr(m->value->to(), width); + if (!value) continue; // error already logged by stringRepr + member->set_value(*value); } (*enums)[name] = *enumTypeSpec; } diff --git a/test/gtest/p4runtime.cpp b/test/gtest/p4runtime.cpp index 2556202725d..caa314cfc23 100644 --- a/test/gtest/p4runtime.cpp +++ b/test/gtest/p4runtime.cpp @@ -34,6 +34,7 @@ limitations under the License. #include "control-plane/typeSpecConverter.h" #include "frontends/common/parseInput.h" #include "frontends/common/resolveReferences/referenceMap.h" +#include "frontends/common/resolveReferences/resolveReferences.h" #include "frontends/p4/parseAnnotations.h" #include "frontends/p4/typeChecking/typeChecker.h" #include "frontends/p4/typeMap.h" @@ -1406,7 +1407,8 @@ class P4RuntimeDataTypeSpec : public P4Runtime { auto pgm = P4::parseP4String(programStr, CompilerOptions::FrontendVersion::P4_16); if (pgm == nullptr) return nullptr; PassManager passes({ - new P4::TypeChecking(&refMap, &typeMap) + new P4::ResolveReferences(&refMap), + new P4::TypeInference(&refMap, &typeMap, false) }); pgm = pgm->apply(passes); return pgm; @@ -1660,6 +1662,31 @@ TEST_F(P4RuntimeDataTypeSpec, Enum) { EXPECT_EQ("MBR_2", it->second.members(1).name()); } +TEST_F(P4RuntimeDataTypeSpec, SerEnum) { + std::string program = P4_SOURCE(R"( + enum bit<8> my_enum { MBR_1 = 1, MBR_2 = 2} + extern my_extern_t { my_extern_t(bit<32> v); } + my_extern_t(32w1024) my_extern; + )"); + auto pgm = getProgram(program); + ASSERT_TRUE(pgm != nullptr && ::errorCount() == 0); + + auto type = findExternTypeParameterName(pgm, "my_extern_t"); + ASSERT_TRUE(type != nullptr); + auto typeSpec = P4::ControlPlaneAPI::TypeSpecConverter::convert( + &refMap, &typeMap, type, &typeInfo); + ASSERT_TRUE(typeSpec->has_serializable_enum()); + EXPECT_EQ("my_enum", typeSpec->serializable_enum().name()); + + auto it = typeInfo.serializable_enums().find("my_enum"); + ASSERT_TRUE(it != typeInfo.serializable_enums().end()); + ASSERT_EQ(2, it->second.members_size()); + EXPECT_EQ("MBR_1", it->second.members(0).name()); + EXPECT_EQ("\x01", it->second.members(0).value()); + EXPECT_EQ("MBR_2", it->second.members(1).name()); + EXPECT_EQ("\x02", it->second.members(1).value()); +} + TEST_F(P4RuntimeDataTypeSpec, Error) { std::string program = P4_SOURCE(R"( error { MBR_1, MBR_2 } diff --git a/testdata/p4_16_samples/register-serenum.p4 b/testdata/p4_16_samples/register-serenum.p4 new file mode 100644 index 00000000000..5e8e42869ef --- /dev/null +++ b/testdata/p4_16_samples/register-serenum.p4 @@ -0,0 +1,49 @@ +#include + +enum bit<16> EthTypes { + IPv4 = 0x0800, + ARP = 0x0806, + RARP = 0x8035, + EtherTalk = 0x809B, + VLAN = 0x8100, + IPX = 0x8137, + IPv6 = 0x86DD +} + +header Ethernet { + bit<48> src; + bit<48> dest; + EthTypes type; +} + +struct Headers { + Ethernet eth; +} + +parser prs(packet_in p, out Headers h) { + Ethernet e; + + state start { + p.extract(e); + transition select(e.type) { + EthTypes.IPv4: accept; + EthTypes.ARP: accept; + default: reject; + } + } +} + +control c(inout Headers h, inout standard_metadata_t sm) { + register(1) reg; + + apply { + reg.write(0, h.eth.type); + } + +} + +parser p(packet_in _p, out H h); +control ctr(inout H h, inout SM sm); +package top(p _p, ctr _c); + +top(prs(), c()) main; diff --git a/testdata/p4_16_samples_outputs/logging.p4.entries.txt b/testdata/p4_16_samples_outputs/logging.p4.entries.txt new file mode 100644 index 00000000000..e69de29bb2d diff --git a/testdata/p4_16_samples_outputs/logging.p4.p4info.txt b/testdata/p4_16_samples_outputs/logging.p4.p4info.txt new file mode 100644 index 00000000000..870b03b8f90 --- /dev/null +++ b/testdata/p4_16_samples_outputs/logging.p4.p4info.txt @@ -0,0 +1,35 @@ +pkg_info { + arch: "v1model" +} +tables { + preamble { + id: 33595561 + name: "c.t" + alias: "t" + } + action_refs { + id: 16782098 + } + action_refs { + id: 16800567 + annotations: "@defaultonly" + scope: DEFAULT_ONLY + } + size: 1024 +} +actions { + preamble { + id: 16800567 + name: "NoAction" + alias: "NoAction" + } +} +actions { + preamble { + id: 16782098 + name: "c.a" + alias: "a" + } +} +type_info { +} diff --git a/testdata/p4_16_samples_outputs/register-serenum-first.p4 b/testdata/p4_16_samples_outputs/register-serenum-first.p4 new file mode 100644 index 00000000000..04f9733e4a5 --- /dev/null +++ b/testdata/p4_16_samples_outputs/register-serenum-first.p4 @@ -0,0 +1,47 @@ +#include +#include + +enum bit<16> EthTypes { + IPv4 = 16w0x800, + ARP = 16w0x806, + RARP = 16w0x8035, + EtherTalk = 16w0x809b, + VLAN = 16w0x8100, + IPX = 16w0x8137, + IPv6 = 16w0x86dd +} + +header Ethernet { + bit<48> src; + bit<48> dest; + EthTypes type; +} + +struct Headers { + Ethernet eth; +} + +parser prs(packet_in p, out Headers h) { + Ethernet e; + state start { + p.extract(e); + transition select(e.type) { + EthTypes.IPv4: accept; + EthTypes.ARP: accept; + default: reject; + } + } +} + +control c(inout Headers h, inout standard_metadata_t sm) { + register(32w1) reg; + apply { + reg.write(32w0, h.eth.type); + } +} + +parser p(packet_in _p, out H h); +control ctr(inout H h, inout SM sm); +package top(p _p, ctr _c); +top(prs(), c()) main; + diff --git a/testdata/p4_16_samples_outputs/register-serenum-frontend.p4 b/testdata/p4_16_samples_outputs/register-serenum-frontend.p4 new file mode 100644 index 00000000000..06af19fd525 --- /dev/null +++ b/testdata/p4_16_samples_outputs/register-serenum-frontend.p4 @@ -0,0 +1,47 @@ +#include +#include + +enum bit<16> EthTypes { + IPv4 = 16w0x800, + ARP = 16w0x806, + RARP = 16w0x8035, + EtherTalk = 16w0x809b, + VLAN = 16w0x8100, + IPX = 16w0x8137, + IPv6 = 16w0x86dd +} + +header Ethernet { + bit<48> src; + bit<48> dest; + EthTypes type; +} + +struct Headers { + Ethernet eth; +} + +parser prs(packet_in p, out Headers h) { + Ethernet e_0; + state start { + p.extract(e_0); + transition select(e_0.type) { + EthTypes.IPv4: accept; + EthTypes.ARP: accept; + default: reject; + } + } +} + +control c(inout Headers h, inout standard_metadata_t sm) { + @name("c.reg") register(32w1) reg_0; + apply { + reg_0.write(32w0, h.eth.type); + } +} + +parser p(packet_in _p, out H h); +control ctr(inout H h, inout SM sm); +package top(p _p, ctr _c); +top(prs(), c()) main; + diff --git a/testdata/p4_16_samples_outputs/register-serenum-midend.p4 b/testdata/p4_16_samples_outputs/register-serenum-midend.p4 new file mode 100644 index 00000000000..0a8ad2c6da3 --- /dev/null +++ b/testdata/p4_16_samples_outputs/register-serenum-midend.p4 @@ -0,0 +1,46 @@ +#include +#include + +header Ethernet { + bit<48> src; + bit<48> dest; + bit<16> type; +} + +struct Headers { + Ethernet eth; +} + +parser prs(packet_in p, out Headers h) { + Ethernet e_0; + state start { + p.extract(e_0); + transition select(e_0.type) { + 16w0x800: accept; + 16w0x806: accept; + default: reject; + } + } +} + +control c(inout Headers h, inout standard_metadata_t sm) { + @name("c.reg") register>(32w1) reg_0; + @hidden action registerserenum40() { + reg_0.write(32w0, h.eth.type); + } + @hidden table tbl_registerserenum40 { + actions = { + registerserenum40(); + } + const default_action = registerserenum40(); + } + apply { + tbl_registerserenum40.apply(); + } +} + +parser p(packet_in _p, out H h); +control ctr(inout H h, inout SM sm); +package top(p _p, ctr _c); +top(prs(), c()) main; + diff --git a/testdata/p4_16_samples_outputs/register-serenum.p4 b/testdata/p4_16_samples_outputs/register-serenum.p4 new file mode 100644 index 00000000000..318c0b439f0 --- /dev/null +++ b/testdata/p4_16_samples_outputs/register-serenum.p4 @@ -0,0 +1,47 @@ +#include +#include + +enum bit<16> EthTypes { + IPv4 = 0x800, + ARP = 0x806, + RARP = 0x8035, + EtherTalk = 0x809b, + VLAN = 0x8100, + IPX = 0x8137, + IPv6 = 0x86dd +} + +header Ethernet { + bit<48> src; + bit<48> dest; + EthTypes type; +} + +struct Headers { + Ethernet eth; +} + +parser prs(packet_in p, out Headers h) { + Ethernet e; + state start { + p.extract(e); + transition select(e.type) { + EthTypes.IPv4: accept; + EthTypes.ARP: accept; + default: reject; + } + } +} + +control c(inout Headers h, inout standard_metadata_t sm) { + register(1) reg; + apply { + reg.write(0, h.eth.type); + } +} + +parser p(packet_in _p, out H h); +control ctr(inout H h, inout SM sm); +package top(p _p, ctr _c); +top(prs(), c()) main; + diff --git a/testdata/p4_16_samples_outputs/register-serenum.p4-stderr b/testdata/p4_16_samples_outputs/register-serenum.p4-stderr new file mode 100644 index 00000000000..e69de29bb2d diff --git a/testdata/p4_16_samples_outputs/register-serenum.p4.entries.txt b/testdata/p4_16_samples_outputs/register-serenum.p4.entries.txt new file mode 100644 index 00000000000..e69de29bb2d diff --git a/testdata/p4_16_samples_outputs/register-serenum.p4.p4info.txt b/testdata/p4_16_samples_outputs/register-serenum.p4.p4info.txt new file mode 100644 index 00000000000..995173441cd --- /dev/null +++ b/testdata/p4_16_samples_outputs/register-serenum.p4.p4info.txt @@ -0,0 +1,54 @@ +pkg_info { + arch: "v1model" +} +registers { + preamble { + id: 369133130 + name: "c.reg" + alias: "reg" + } + type_spec { + serializable_enum { + name: "EthTypes" + } + } + size: 1 +} +type_info { + serializable_enums { + key: "EthTypes" + value { + underlying_type { + bitwidth: 16 + } + members { + name: "IPv4" + value: "\010\000" + } + members { + name: "ARP" + value: "\010\006" + } + members { + name: "RARP" + value: "\2005" + } + members { + name: "EtherTalk" + value: "\200\233" + } + members { + name: "VLAN" + value: "\201\000" + } + members { + name: "IPX" + value: "\2017" + } + members { + name: "IPv6" + value: "\206\335" + } + } + } +} diff --git a/testdata/p4_16_samples_outputs/v1model-digest-containing-ser-enum.p4.p4info.txt b/testdata/p4_16_samples_outputs/v1model-digest-containing-ser-enum.p4.p4info.txt index 9abac3709e5..5135f3e8f3d 100644 --- a/testdata/p4_16_samples_outputs/v1model-digest-containing-ser-enum.p4.p4info.txt +++ b/testdata/p4_16_samples_outputs/v1model-digest-containing-ser-enum.p4.p4info.txt @@ -263,15 +263,15 @@ type_info { } members { name: "foo" - value: "28" + value: "\034" } members { name: "bar" - value: "17" + value: "\021" } members { name: "gah" - value: "42" + value: "*" } } } From f238d25467a2a884d87fcf2991744ae9685ff639 Mon Sep 17 00:00:00 2001 From: Mihai Budiu Date: Wed, 20 Nov 2019 17:12:36 -0800 Subject: [PATCH 032/106] Fix for python3 (#2092) --- backends/ebpf/targets/ebpfstf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backends/ebpf/targets/ebpfstf.py b/backends/ebpf/targets/ebpfstf.py index 92a43a0ac19..7946dc89cbc 100644 --- a/backends/ebpf/targets/ebpfstf.py +++ b/backends/ebpf/targets/ebpfstf.py @@ -109,7 +109,7 @@ def parse_stf_file(raw_stf): expected = {} for stf_entry in stf_map: if stf_entry[0] == "packet": - input_pkts.setdefault(stf_entry[1], []).append(bytes.fromhex(stf_entry[2])) + input_pkts.setdefault(stf_entry[1], []).append(bytes.fromhex(''.join(stf_entry[2].split()))) elif stf_entry[0] == "expect": interface = int(stf_entry[1]) pkt_data = stf_entry[2] From fbe395bbf1eed9653323ac73b20cf6c06af2121e Mon Sep 17 00:00:00 2001 From: Han Wang Date: Thu, 21 Nov 2019 14:09:41 +0800 Subject: [PATCH 033/106] fix type inference for IR::Neg and IR::Cmpl (#2093) --- frontends/p4-14/typecheck.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/frontends/p4-14/typecheck.cpp b/frontends/p4-14/typecheck.cpp index 48422af3c83..d5e73bd2d1e 100644 --- a/frontends/p4-14/typecheck.cpp +++ b/frontends/p4-14/typecheck.cpp @@ -315,6 +315,10 @@ class TypeCheck::InferExpressionsBottomUp : public Modifier { void postorder(IR::LNot *op) override { logic_operand(op->expr); setType(op, IR::Type::Boolean::get()); } + void postorder(IR::Neg *op) override { + setType(op, op->expr->type); } + void postorder(IR::Cmpl *op) override { + setType(op, op->expr->type); } void postorder(IR::Operation_Relation *op) override { setType(op, IR::Type::Boolean::get()); } }; From 7029f1d61d413b9b5036f50d3add0ced13498ec2 Mon Sep 17 00:00:00 2001 From: Antonin Bas Date: Thu, 21 Nov 2019 01:14:39 -0800 Subject: [PATCH 034/106] Fix FindPythonModule to avoid warnings Not sure what the purpose of all the find_python_module directives is, since we only check for presence of standard library stuff. We also use find_python_module to "find" the "re" module, and the find_python_module implementation itself imports "re" :) Fixes #2095 --- cmake/FindPythonModule.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/FindPythonModule.cmake b/cmake/FindPythonModule.cmake index e3c04318d93..6b8a6e7c179 100644 --- a/cmake/FindPythonModule.cmake +++ b/cmake/FindPythonModule.cmake @@ -7,7 +7,7 @@ function(find_python_module module) # A module's location is usually a directory, but for binary modules # it's a .so file. execute_process(COMMAND "${PYTHON_EXECUTABLE}" "-c" - "import re, ${module}; print re.compile('/__init__.py.*').sub('',${module}.__file__)" + "import re, ${module}; print(re.compile('/__init__.py.*').sub('',${module}.__file__))" RESULT_VARIABLE _${module}_status OUTPUT_VARIABLE _${module}_location ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE) From 75df2526b6d9fa1146dfe41c73fc24224baf4502 Mon Sep 17 00:00:00 2001 From: Chris Dodd Date: Sun, 1 Dec 2019 09:13:08 -0800 Subject: [PATCH 035/106] Stack backtrace in exceptions (#2100) - print the backtrace when unexpected exceptions are caught at the top level --- backends/bmv2/psa_switch/main.cpp | 6 +- backends/bmv2/simple_switch/main.cpp | 6 +- backends/ebpf/p4c-ebpf.cpp | 2 +- backends/graphs/p4c-graphs.cpp | 4 +- backends/p4test/p4test.cpp | 4 +- lib/CMakeLists.txt | 1 + lib/backtrace.cpp | 88 ++++++++++++++++++++++++++++ lib/backtrace.h | 55 +++++++++++++++++ lib/crash.h | 1 + lib/ordered_map.h | 10 +--- 10 files changed, 158 insertions(+), 19 deletions(-) create mode 100644 lib/backtrace.cpp create mode 100644 lib/backtrace.h diff --git a/backends/bmv2/psa_switch/main.cpp b/backends/bmv2/psa_switch/main.cpp index c42e9c3d9a3..57cc16d500d 100644 --- a/backends/bmv2/psa_switch/main.cpp +++ b/backends/bmv2/psa_switch/main.cpp @@ -72,7 +72,7 @@ int main(int argc, char *const argv[]) { P4::FrontEnd frontend; frontend.addDebugHook(hook); program = frontend.run(options, program); - } catch (const Util::P4CExceptionBase &bug) { + } catch (const std::exception &bug) { std::cerr << bug.what() << std::endl; return 1; } @@ -107,7 +107,7 @@ int main(int argc, char *const argv[]) { return 1; if (options.dumpJsonFile) JSONGenerator(*openFile(options.dumpJsonFile, true), true) << program << std::endl; - } catch (const Util::P4CExceptionBase &bug) { + } catch (const std::exception &bug) { std::cerr << bug.what() << std::endl; return 1; } @@ -121,7 +121,7 @@ int main(int argc, char *const argv[]) { AutoCompileContext autoContext(new BMV2::BMV2Context(BMV2::PsaSwitchContext::get())); try { backend->convert(toplevel); - } catch (const Util::P4CExceptionBase &bug) { + } catch (const std::exception &bug) { std::cerr << bug.what() << std::endl; return 1; } diff --git a/backends/bmv2/simple_switch/main.cpp b/backends/bmv2/simple_switch/main.cpp index f308e52a39c..76abec29e80 100644 --- a/backends/bmv2/simple_switch/main.cpp +++ b/backends/bmv2/simple_switch/main.cpp @@ -72,7 +72,7 @@ int main(int argc, char *const argv[]) { P4::FrontEnd frontend; frontend.addDebugHook(hook); program = frontend.run(options, program); - } catch (const Util::P4CExceptionBase &bug) { + } catch (const std::exception &bug) { std::cerr << bug.what() << std::endl; return 1; } @@ -107,7 +107,7 @@ int main(int argc, char *const argv[]) { return 1; if (options.dumpJsonFile && !options.loadIRFromJson) JSONGenerator(*openFile(options.dumpJsonFile, true), true) << program << std::endl; - } catch (const Util::P4CExceptionBase &bug) { + } catch (const std::exception &bug) { std::cerr << bug.what() << std::endl; return 1; } @@ -121,7 +121,7 @@ int main(int argc, char *const argv[]) { AutoCompileContext autoContext(new BMV2::BMV2Context(BMV2::SimpleSwitchContext::get())); try { backend->convert(toplevel); - } catch (const Util::P4CExceptionBase &bug) { + } catch (const std::exception &bug) { std::cerr << bug.what() << std::endl; return 1; } diff --git a/backends/ebpf/p4c-ebpf.cpp b/backends/ebpf/p4c-ebpf.cpp index db78c57e6e0..ed0db20cdab 100644 --- a/backends/ebpf/p4c-ebpf.cpp +++ b/backends/ebpf/p4c-ebpf.cpp @@ -101,7 +101,7 @@ int main(int argc, char *const argv[]) { try { compile(options); - } catch (const Util::P4CExceptionBase &bug) { + } catch (const std::exception &bug) { std::cerr << bug.what() << std::endl; return 1; } diff --git a/backends/graphs/p4c-graphs.cpp b/backends/graphs/p4c-graphs.cpp index 928c2eab5b2..e2e26996010 100644 --- a/backends/graphs/p4c-graphs.cpp +++ b/backends/graphs/p4c-graphs.cpp @@ -128,7 +128,7 @@ int main(int argc, char *const argv[]) { P4::FrontEnd fe; fe.addDebugHook(hook); program = fe.run(options, program); - } catch (const Util::P4CExceptionBase &bug) { + } catch (const std::exception &bug) { std::cerr << bug.what() << std::endl; return 1; } @@ -143,7 +143,7 @@ int main(int argc, char *const argv[]) { top = midEnd.process(program); if (options.dumpJsonFile) JSONGenerator(*openFile(options.dumpJsonFile, true)) << program << std::endl; - } catch (const Util::P4CExceptionBase &bug) { + } catch (const std::exception &bug) { std::cerr << bug.what() << std::endl; return 1; } diff --git a/backends/p4test/p4test.cpp b/backends/p4test/p4test.cpp index 0813e658fc1..63842c90686 100644 --- a/backends/p4test/p4test.cpp +++ b/backends/p4test/p4test.cpp @@ -114,7 +114,7 @@ int main(int argc, char *const argv[]) { P4::FrontEnd fe; fe.addDebugHook(hook); program = fe.run(options, program); - } catch (const Util::P4CExceptionBase &bug) { + } catch (const std::exception &bug) { std::cerr << bug.what() << std::endl; return 1; } @@ -142,7 +142,7 @@ int main(int argc, char *const argv[]) { const IR::ToplevelBlock *top = nullptr; try { top = midEnd.process(program); - } catch (const Util::P4CExceptionBase &bug) { + } catch (const std::exception &bug) { std::cerr << bug.what() << std::endl; return 1; } diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index 4cfdf677449..f7bd0d76212 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -13,6 +13,7 @@ # limitations under the License. set (LIBP4CTOOLKIT_SRCS + backtrace.cpp bitvec.cpp compile_context.cpp crash.cpp diff --git a/lib/backtrace.cpp b/lib/backtrace.cpp new file mode 100644 index 00000000000..a4746d94a92 --- /dev/null +++ b/lib/backtrace.cpp @@ -0,0 +1,88 @@ +/* +Copyright 2019-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 "backtrace.h" +#include +#include +#include +#include +#include +#include "crash.h" + +void backtrace_fill_stacktrace(std::string &msg, void *const*backtrace, int size) { + char **strings = backtrace_symbols(backtrace, size); + for (int i = 0; i < size; i++) { + if (strings) { + msg += "\n "; + msg += strings[i]; } + if (const char *line = addr2line(backtrace[i], strings ? strings[i] : 0)) { + msg += "\n "; + msg += line; } } + free(strings); +} + +#ifdef __GLIBC__ +/* DANGER -- overrides for glibc++ exception throwers to include a stack trace. + * correct functions depends on library internals, so may not work on some versions + * and will fail with non-GNU libc++ */ + +void std::__throw_bad_alloc() { + throw backtrace_exception(); +} + +void std::__throw_bad_cast() { + throw backtrace_exception(); +} + +void std::__throw_bad_function_call() { + throw backtrace_exception(); +} + +void std::__throw_invalid_argument(char const *m) { + throw backtrace_exception(m); +} + +void std::__throw_length_error(char const *m) { + throw backtrace_exception(m); +} + +void std::__throw_logic_error(char const *m) { + throw backtrace_exception(m); +} + +void std::__throw_out_of_range(char const *m) { + throw backtrace_exception(m); +} + +void std::__throw_out_of_range_fmt(char const *fmt, ...) { + char buffer[1024]; // should be large enough for all cases? + va_list args; + va_start(args, fmt); + vsnprintf(buffer, sizeof(buffer), fmt, args); + va_end(args); + throw backtrace_exception(buffer); +} + +void std::__throw_regex_error(std::regex_constants::error_type err) { + throw backtrace_exception(err); +} + +void std::__throw_system_error(int err) { + throw backtrace_exception(error_code(err, generic_category())); +} + + +#endif /* __GLIBC__ */ diff --git a/lib/backtrace.h b/lib/backtrace.h new file mode 100644 index 00000000000..824a102caf1 --- /dev/null +++ b/lib/backtrace.h @@ -0,0 +1,55 @@ +/* +Copyright 2019-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. +*/ + +#ifndef _LIB_BACKTRACE_H_ +#define _LIB_BACKTRACE_H_ + +#include +#include +#include "config.h" + +#if HAVE_EXECINFO_H +#include +#endif + +void backtrace_fill_stacktrace(std::string &msg, void *const*backtrace, int size); + +template class backtrace_exception : public E { + static constexpr int buffer_size = 64; + void *backtrace_buffer[buffer_size]; + int backtrace_size; + mutable std::string message; + public: + template backtrace_exception(Args... args) : E(std::forward(args)...) { +#if HAVE_EXECINFO_H + backtrace_size = backtrace(backtrace_buffer, buffer_size); +#else + backtrace_size = 0; +#endif + } + + const char *what() const noexcept { + try { + message = E::what(); + if (backtrace_size > 0) + backtrace_fill_stacktrace(message, backtrace_buffer, backtrace_size); + return message.c_str(); + } catch(...) {} + return E::what(); + } +}; + +#endif /* _LIB_CRASH_H_ */ diff --git a/lib/crash.h b/lib/crash.h index 3b1f3b41a89..4ddacbf6a1f 100644 --- a/lib/crash.h +++ b/lib/crash.h @@ -18,5 +18,6 @@ limitations under the License. #define _LIB_CRASH_H_ void setup_signals(); +const char *addr2line(void *addr, const char *text); #endif /* _LIB_CRASH_H_ */ diff --git a/lib/ordered_map.h b/lib/ordered_map.h index 7dc8dda37f9..5f221629fee 100644 --- a/lib/ordered_map.h +++ b/lib/ordered_map.h @@ -144,14 +144,8 @@ class ordered_map { it = data.emplace(data.end(), std::move(x), V()); data_map.emplace(&it->first, it); } return it->second; } - V& at(const K &x) { - auto it = find(x); - if (it == data.end()) throw std::out_of_range("ordered_map"); - return it->second; } - const V& at(const K &x) const { - auto it = find(x); - if (it == data.end()) throw std::out_of_range("ordered_map"); - return it->second; } + V& at(const K &x) { return data_map.at(&x)->second; } + const V& at(const K &x) const { return data_map.at(&x)->second; } template std::pair emplace(KK &&k, VV &&... v) { From de8a5076cc4903ea83aa2d7acd89b3edeb640fb5 Mon Sep 17 00:00:00 2001 From: Chris Dodd Date: Mon, 2 Dec 2019 17:43:01 -0800 Subject: [PATCH 036/106] Remove GMP, using boost::multiprecision instead (#1418) -- ENABLE_GMP option to use GMP as the backend for boost::mulitprecision - case insensitive compare of stderr in p4test as hex constants may be either upper or lower case, depending on GMP setting :-( --- .travis.yml | 9 ++- CMakeLists.txt | 28 +++++--- backends/bmv2/common/control.cpp | 4 +- backends/bmv2/common/helpers.cpp | 15 ++--- backends/bmv2/common/helpers.h | 2 +- backends/bmv2/common/lower.cpp | 4 +- backends/bmv2/common/parser.cpp | 8 +-- backends/bmv2/common/parser.h | 4 +- backends/ebpf/lower.cpp | 4 +- backends/p4test/run-p4-sample.py | 11 ++-- cmake/config.h.cmake | 3 + control-plane/bytestrings.cpp | 11 ++-- control-plane/bytestrings.h | 2 +- control-plane/p4RuntimeArchHandler.h | 2 +- control-plane/p4RuntimeArchStandard.cpp | 2 +- control-plane/p4RuntimeSerializer.cpp | 26 ++++---- control-plane/typeSpecConverter.cpp | 7 +- frontends/common/constantFolding.cpp | 62 ++++++++--------- frontends/common/constantFolding.h | 5 +- frontends/common/constantParsing.cpp | 2 +- frontends/p4/fromv1.0/converters.cpp | 2 +- frontends/p4/fromv1.0/programStructure.cpp | 4 +- frontends/p4/strengthReduction.cpp | 16 ++--- frontends/p4/toP4/toP4.cpp | 14 ++-- frontends/p4/typeChecking/typeChecker.cpp | 4 +- ir/expression.cpp | 40 ++++------- ir/expression.def | 47 ++++++------- ir/json_generator.h | 5 +- ir/json_loader.h | 3 +- ir/json_parser.cpp | 12 +++- ir/json_parser.h | 6 +- ir/pattern.h | 6 +- ir/visitor.cpp | 1 + lib/bitops.h | 6 +- lib/error_helper.h | 24 +++---- lib/gmputil.cpp | 50 +++++++------- lib/gmputil.h | 66 +++++++++++++------ lib/json.cpp | 21 +++--- lib/json.h | 16 ++--- lib/stringify.cpp | 12 ++-- lib/stringify.h | 4 +- midend/removeLeftSlices.cpp | 2 +- midend/simplifyBitwise.cpp | 10 +-- midend/simplifyBitwise.h | 2 +- .../p4_16_samples_outputs/spec-ex04.p4-stderr | 2 +- 45 files changed, 306 insertions(+), 280 deletions(-) diff --git a/.travis.yml b/.travis.yml index ca94520a162..99970272c55 100644 --- a/.travis.yml +++ b/.travis.yml @@ -19,8 +19,13 @@ cache: env: - CTEST_PARALLEL_LEVEL=4 UNIFIED=ON + ENABLE_GMP=ON - CTEST_PARALLEL_LEVEL=4 UNIFIED=OFF + ENABLE_GMP=ON + - CTEST_PARALLEL_LEVEL=4 + UNIFIED=ON + ENABLE_GMP=OFF before_install: - tools/install_os_deps.sh @@ -31,8 +36,8 @@ install: # To flush out issues with unified vs. non-unified builds, do a non-unified # build before continuing with the rest, which produces a unified build. # This is done here on MacOS; for Linux, this is done in Dockerfile. - - if [[ $TRAVIS_OS_NAME == 'linux' ]] ; then docker build --network ccache_network -t p4c --build-arg IMAGE_TYPE=test --build-arg ENABLE_UNIFIED_COMPILATION=$UNIFIED . ; fi - - if [[ $TRAVIS_OS_NAME == 'osx' ]] ; then ./bootstrap.sh -DCMAKE_BUILD_TYPE=RELEASE -DENABLE_UNIFIED_COMPILATION=$UNIFIED && cd build && make -j2; fi + - if [[ $TRAVIS_OS_NAME == 'linux' ]] ; then docker build --network ccache_network -t p4c --build-arg IMAGE_TYPE=test --build-arg ENABLE_UNIFIED_COMPILATION=$UNIFIED --build-arg ENABLE_GMP=$ENABLE_GMP . ; fi + - if [[ $TRAVIS_OS_NAME == 'osx' ]] ; then ./bootstrap.sh -DCMAKE_BUILD_TYPE=RELEASE -DENABLE_UNIFIED_COMPILATION=$UNIFIED -DENABLE_GMP=$ENABLE_GMP && cd build && make -j2; fi script: - if [[ $TRAVIS_OS_NAME == 'linux' && $UNIFIED == ON ]] ; then docker run -w /p4c/build -e CTEST_PARALLEL_LEVEL p4c ctest --output-on-failure --schedule-random ; fi diff --git a/CMakeLists.txt b/CMakeLists.txt index 45e8093fe3a..0dd8101ee80 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -37,6 +37,7 @@ OPTION (ENABLE_P4C_GRAPHS "Build the p4c-graphs backend" ON) OPTION (ENABLE_PROTOBUF_STATIC "Link against Protobuf statically" ON) OPTION (ENABLE_GC "Use libgc" ON) OPTION (ENABLE_MULTITHREAD "Use multithreading" OFF) +OPTION (ENABLE_GMP "Use GMP library" ON) set(MAX_LOGGING_LEVEL 10 CACHE STRING "Control the maximum logging level for -T logs") set_property(CACHE MAX_LOGGING_LEVEL PROPERTY STRINGS 0 1 2 3 4 5 6 7 8 9 10) @@ -102,19 +103,26 @@ if (ENABLE_GC) endif () if (ENABLE_MULTITHREAD) add_definitions(-DMULTITHREAD) - set(THREADS_PREFER_PTHREAD_FLAG ON) - find_package(Threads REQUIRED) - set (P4C_LIB_DEPS "${P4C_LIB_DEPS};${CMAKE_THREAD_LIBS_INIT}") endif() -find_package (LibGmp REQUIRED) +# we require -pthread to make std::call_once work, even if we're not using threads... +set(THREADS_PREFER_PTHREAD_FLAG ON) +find_package(Threads REQUIRED) +set (P4C_LIB_DEPS "${P4C_LIB_DEPS};${CMAKE_THREAD_LIBS_INIT}") include_directories(${Boost_INCLUDE_DIRS}) include_directories(${PROTOBUF_INCLUDE_DIRS}) -include_directories(${LIBGMP_INCLUDE_DIR}) include_directories(${LIBGC_INCLUDE_DIR}) set (HAVE_LIBBOOST_IOSTREAMS 1) -set (HAVE_LIBGMP 1) -set (HAVE_LIBGMPXX 1) -set (P4C_LIB_DEPS "${P4C_LIB_DEPS};${Boost_LIBRARIES};${LIBGMP_LIBRARIES};${LIBGC_LIBRARIES}") +set (P4C_LIB_DEPS "${P4C_LIB_DEPS};${Boost_LIBRARIES}") +if (ENABLE_GMP) + find_package (LibGmp REQUIRED) + include_directories(${LIBGMP_INCLUDE_DIR}) + set (HAVE_LIBGMP 1) + set (HAVE_LIBGMPXX 1) + set (P4C_LIB_DEPS "${P4C_LIB_DEPS};${LIBGMP_LIBRARIES}") +endif () +if (ENABLE_GC) + set (P4C_LIB_DEPS "${P4C_LIB_DEPS};${LIBGC_LIBRARIES}") +endif () # other required libraries p4c_add_library (rt clock_gettime HAVE_CLOCK_GETTIME) @@ -130,7 +138,9 @@ check_include_file_cxx (cxxabi.h HAVE_CXXABI_H) # set libraries to be used with check_function_exists set (CMAKE_REQUIRED_LIBRARIES_PRECHECK ${CMAKE_REQUIRED_LIBRARIES}) -set (CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} ${LIBGC_LIBRARIES}) +if (ENABLE_GC) + set (CMAKE_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES} ${LIBGC_LIBRARIES}) +endif () include (CheckFunctionExists) check_function_exists (memchr HAVE_MEMCHR) diff --git a/backends/bmv2/common/control.cpp b/backends/bmv2/common/control.cpp index c31f0b71605..a46117fcf21 100644 --- a/backends/bmv2/common/control.cpp +++ b/backends/bmv2/common/control.cpp @@ -71,7 +71,7 @@ void ControlConverter::convertTableEntries(const IR::P4Table *table, key->emplace("key", stringRepr(km->left->to()->value, k8)); auto trailing_zeros = [](unsigned long n) { return n ? __builtin_ctzl(n) : 0; }; auto count_ones = [](unsigned long n) { return n ? __builtin_popcountl(n) : 0;}; - unsigned long mask = km->right->to()->value.get_ui(); + auto mask = static_cast(km->right->to()->value); auto len = trailing_zeros(mask); if (len + count_ones(mask) != keyWidth) // any remaining 0s in the prefix? ::error(ErrorType::ERR_INVALID, "mask for LPM key", k); @@ -336,7 +336,7 @@ ControlConverter::convertTable(const CFG::TableNode* node, ::error(ErrorType::ERR_UNSUPPORTED, "multiple LPM keys in table %1%", table); } - mpz_class mask; + big_int mask; if (auto mexp = expr->to()) { if (mexp->right->is()) { mask = mexp->right->to()->value; diff --git a/backends/bmv2/common/helpers.cpp b/backends/bmv2/common/helpers.cpp index 46b911cf83d..88352dc90ff 100644 --- a/backends/bmv2/common/helpers.cpp +++ b/backends/bmv2/common/helpers.cpp @@ -57,24 +57,21 @@ Util::JsonObject* mkPrimitive(cstring name) { return result; } -cstring stringRepr(mpz_class value, unsigned bytes) { +cstring stringRepr(big_int value, unsigned bytes) { cstring sign = ""; - const char* r; + std::stringstream r; cstring filler = ""; if (value < 0) { value =- value; - r = mpz_get_str(nullptr, 16, value.get_mpz_t()); - sign = "-"; - } else { - r = mpz_get_str(nullptr, 16, value.get_mpz_t()); - } + sign = "-"; } + r << std::hex << value; if (bytes > 0) { - int digits = bytes * 2 - strlen(r); + int digits = bytes * 2 - r.str().size(); BUG_CHECK(digits >= 0, "Cannot represent %1% on %2% bytes", value, bytes); filler = std::string(digits, '0'); } - return sign + "0x" + filler + r; + return sign + "0x" + filler + r.str(); } unsigned nextId(cstring group) { diff --git a/backends/bmv2/common/helpers.h b/backends/bmv2/common/helpers.h index 3ea609914c6..49f9e44cbe4 100644 --- a/backends/bmv2/common/helpers.h +++ b/backends/bmv2/common/helpers.h @@ -100,7 +100,7 @@ Util::JsonArray* mkArrayField(Util::JsonObject* parent, cstring name); Util::JsonArray* mkParameters(Util::JsonObject* object); Util::JsonObject* mkPrimitive(cstring name, Util::JsonArray* appendTo); Util::JsonObject* mkPrimitive(cstring name); -cstring stringRepr(mpz_class value, unsigned bytes = 0); +cstring stringRepr(big_int value, unsigned bytes = 0); unsigned nextId(cstring group); } // namespace BMV2 diff --git a/backends/bmv2/common/lower.cpp b/backends/bmv2/common/lower.cpp index cd528335dda..14779f5935a 100644 --- a/backends/bmv2/common/lower.cpp +++ b/backends/bmv2/common/lower.cpp @@ -31,7 +31,7 @@ const IR::Expression* LowerExpressions::shift(const IR::Operation_Binary* expres auto rhstype = typeMap->getType(rhs, true); if (rhstype->is()) { auto cst = rhs->to(); - mpz_class maxShift = Util::shift_left(1, LowerExpressions::maxShiftWidth); + big_int maxShift = Util::shift_left(1, LowerExpressions::maxShiftWidth); if (cst->value > maxShift) ::error(ErrorType::ERR_OVERLIMIT, "%1%: shift amount limited to %2% on this target", expression, maxShift); @@ -130,7 +130,7 @@ const IR::Node* LowerExpressions::postorder(IR::Concat* expression) { auto cast1 = new IR::Cast(expression->right->srcInfo, resulttype, expression->right); auto sh = new IR::Shl(cast0->srcInfo, cast0, new IR::Constant(sizeofb)); - mpz_class m = Util::maskFromSlice(sizeofb, 0); + big_int m = Util::maskFromSlice(sizeofb, 0); auto mask = new IR::Constant(expression->right->srcInfo, IR::Type_Bits::get(sizeofresult), m, 16); auto and0 = new IR::BAnd(expression->right->srcInfo, cast1, mask); diff --git a/backends/bmv2/common/parser.cpp b/backends/bmv2/common/parser.cpp index 245cc251fa0..4536ac4304a 100644 --- a/backends/bmv2/common/parser.cpp +++ b/backends/bmv2/common/parser.cpp @@ -261,7 +261,7 @@ Util::IJson* ParserConverter::convertParserStatement(const IR::StatOrDecl* stat) // Operates on a select keyset void ParserConverter::convertSimpleKey(const IR::Expression* keySet, - mpz_class& value, mpz_class& mask) const { + big_int& value, big_int& mask) const { if (keySet->is()) { auto mk = keySet->to(); if (!mk->left->is()) { @@ -292,7 +292,7 @@ void ParserConverter::convertSimpleKey(const IR::Expression* keySet, unsigned ParserConverter::combine(const IR::Expression* keySet, const IR::ListExpression* select, - mpz_class& value, mpz_class& mask, + big_int& value, big_int& mask, bool& is_vset, cstring& vset_name) const { // From the BMv2 spec: For values and masks, make sure that you // use the correct format. They need to be the concatenation (in @@ -325,7 +325,7 @@ unsigned ParserConverter::combine(const IR::Expression* keySet, int width = type->width_bits(); BUG_CHECK(width > 0, "%1%: unknown width", e); - mpz_class key_value, mask_value; + big_int key_value, mask_value; convertSimpleKey(keyElement, key_value, mask_value); unsigned w = 8 * ROUNDUP(width, 8); totalWidth += ROUNDUP(width, 8); @@ -383,7 +383,7 @@ ParserConverter::convertSelectExpression(const IR::SelectExpression* expr) { auto se = expr->to(); for (auto sc : se->selectCases) { auto trans = new Util::JsonObject(); - mpz_class value, mask; + big_int value, mask; bool is_vset; cstring vset_name; unsigned bytes = combine(sc->keyset, se->select, value, mask, is_vset, vset_name); diff --git a/backends/bmv2/common/parser.h b/backends/bmv2/common/parser.h index fe90adc7ae1..52dd7a33171 100644 --- a/backends/bmv2/common/parser.h +++ b/backends/bmv2/common/parser.h @@ -34,9 +34,9 @@ class ParserConverter : public Inspector { P4::P4CoreLibrary& corelib; protected: - void convertSimpleKey(const IR::Expression* keySet, mpz_class& value, mpz_class& mask) const; + void convertSimpleKey(const IR::Expression* keySet, big_int& value, big_int& mask) const; unsigned combine(const IR::Expression* keySet, const IR::ListExpression* select, - mpz_class& value, mpz_class& mask, bool& is_vset, cstring& vset_name) const; + big_int& value, big_int& mask, bool& is_vset, cstring& vset_name) const; Util::IJson* stateName(IR::ID state); Util::IJson* convertParserStatement(const IR::StatOrDecl* stat); Util::IJson* convertSelectKey(const IR::SelectExpression* expr); diff --git a/backends/ebpf/lower.cpp b/backends/ebpf/lower.cpp index 2d1627c7364..0bb3756f9f6 100644 --- a/backends/ebpf/lower.cpp +++ b/backends/ebpf/lower.cpp @@ -23,7 +23,7 @@ const IR::Expression* LowerExpressions::shift(const IR::Operation_Binary* expres auto rhstype = typeMap->getType(rhs, true); if (rhstype->is()) { auto cst = rhs->to(); - mpz_class maxShift = Util::shift_left(1, LowerExpressions::maxShiftWidth); + big_int maxShift = Util::shift_left(1, LowerExpressions::maxShiftWidth); if (cst->value > maxShift) ::error("%1%: shift amount limited to %2% on this target", expression, maxShift); } else { @@ -78,7 +78,7 @@ const IR::Node* LowerExpressions::postorder(IR::Concat* expression) { auto cast1 = new IR::Cast(expression->right->srcInfo, resulttype, expression->right); auto sh = new IR::Shl(cast0->srcInfo, cast0, new IR::Constant(sizeofb)); - mpz_class m = Util::maskFromSlice(sizeofb, 0); + big_int m = Util::maskFromSlice(sizeofb, 0); auto mask = new IR::Constant(expression->right->srcInfo, IR::Type_Bits::get(sizeofresult), m, 16); auto and0 = new IR::BAnd(expression->right->srcInfo, cast1, mask); diff --git a/backends/p4test/run-p4-sample.py b/backends/p4test/run-p4-sample.py index c42d17de4ff..c806a7238c8 100755 --- a/backends/p4test/run-p4-sample.py +++ b/backends/p4test/run-p4-sample.py @@ -117,7 +117,7 @@ def target(): timeout = 10 * 60 -def compare_files(options, produced, expected): +def compare_files(options, produced, expected, ignore_case): if options.replace: if options.verbose: print("Saving new version of ", expected) @@ -127,7 +127,10 @@ def compare_files(options, produced, expected): if options.verbose: print("Comparing", expected, "and", produced) - cmd = ("diff -B -u -w " + expected + " " + produced + " >&2") + args = "-B -u -w"; + if ignore_case: + args = args + " -i"; + cmd = ("diff " + args + " " + expected + " " + produced + " >&2") if options.verbose: print(cmd) exitcode = subprocess.call(cmd, shell=True); @@ -145,7 +148,7 @@ def recompile_file(options, produced, mustBeIdentical): if result != SUCCESS: return result if mustBeIdentical: - result = compare_files(options, produced, secondFile) + result = compare_files(options, produced, secondFile, false) return result def check_generated_files(options, tmpdir, expecteddir): @@ -160,7 +163,7 @@ def check_generated_files(options, tmpdir, expecteddir): print("Expected file does not exist; creating", expected) shutil.copy2(produced, expected) else: - result = compare_files(options, produced, expected) + result = compare_files(options, produced, expected, file[-7:] == "-stderr") if result != SUCCESS and (file[-7:] != "-stderr" or not ignoreStderr(options)): return result return SUCCESS diff --git a/cmake/config.h.cmake b/cmake/config.h.cmake index 2be59aeaadd..0bf684fde32 100644 --- a/cmake/config.h.cmake +++ b/cmake/config.h.cmake @@ -10,6 +10,9 @@ /* Define to 1 if you have the LIBGC library. */ #cmakedefine HAVE_LIBGC 1 +/* Define to 1 if you have the GMP library. */ +#cmakedefine HAVE_LIBGMP 1 + /* Define to 1 if you have the memchr function. */ #cmakedefine HAVE_MEMCHR 1 diff --git a/control-plane/bytestrings.cpp b/control-plane/bytestrings.cpp index 4bc19102c1b..e1b6987bec8 100644 --- a/control-plane/bytestrings.cpp +++ b/control-plane/bytestrings.cpp @@ -25,14 +25,14 @@ namespace ControlPlaneAPI { /// Convert a bignum to the P4Runtime bytes representation. The value must fit /// within the provided @width expressed in bits. Padding will be added as /// necessary (as the most significant bits). -boost::optional stringReprConstant(mpz_class value, int width) { +boost::optional stringReprConstant(big_int value, int width) { // TODO(antonin): support negative values if (value < 0) { ::error("%1%: Negative values not supported yet", value); return boost::none; } BUG_CHECK(width > 0, "Unexpected width 0"); - auto bitsRequired = static_cast(mpz_sizeinbase(value.get_mpz_t(), 2)); + size_t bitsRequired = floor_log2(value) + 1; BUG_CHECK(static_cast(width) >= bitsRequired, "Cannot represent %1% on %2% bits", value, width); // TODO(antonin): P4Runtime defines the canonical representation for bit @@ -45,8 +45,9 @@ boost::optional stringReprConstant(mpz_class value, int width) { // auto bytes = ROUNDUP(mpz_sizeinbase(value.get_mpz_t(), 2), 8); auto bytes = ROUNDUP(width, 8); std::vector data(bytes); - mpz_export(data.data(), NULL, 1 /* big endian word */, bytes, - 1 /* big endian bytes */, 0 /* full words */, value.get_mpz_t()); + for (auto &d : data) { + big_int v = (value >> (--bytes * 8)) & 0xff; + d = static_cast(v); } return std::string(data.begin(), data.end()); } @@ -59,7 +60,7 @@ boost::optional stringRepr(const IR::Constant* constant, int width) /// Convert a BoolLiteral to the P4Runtime bytes representation by calling /// stringReprConstant. boost::optional stringRepr(const IR::BoolLiteral* constant, int width) { - auto v = static_cast(constant->value ? 1 : 0); + auto v = static_cast(constant->value ? 1 : 0); return stringReprConstant(v, width); } diff --git a/control-plane/bytestrings.h b/control-plane/bytestrings.h index 0242138a627..c2c8b488c4a 100644 --- a/control-plane/bytestrings.h +++ b/control-plane/bytestrings.h @@ -38,7 +38,7 @@ boost::optional stringRepr(const IR::Constant* constant, int width) boost::optional stringRepr(const IR::BoolLiteral* constant, int width); -boost::optional stringReprConstant(mpz_class value, int width); +boost::optional stringReprConstant(big_int value, int width); } // namespace ControlPlaneAPI diff --git a/control-plane/p4RuntimeArchHandler.h b/control-plane/p4RuntimeArchHandler.h index 6e0fef0f85a..9044a1b1e9c 100644 --- a/control-plane/p4RuntimeArchHandler.h +++ b/control-plane/p4RuntimeArchHandler.h @@ -385,7 +385,7 @@ struct Counterlike { return Counterlike{declaration->controlPlaneName(), declaration->to(), unit->to()->name, - size->template to()->value.get_si(), + int(size->template to()->value), boost::none}; } diff --git a/control-plane/p4RuntimeArchStandard.cpp b/control-plane/p4RuntimeArchStandard.cpp index e48a88bad68..145d2194292 100644 --- a/control-plane/p4RuntimeArchStandard.cpp +++ b/control-plane/p4RuntimeArchStandard.cpp @@ -318,7 +318,7 @@ struct Register { return Register{declaration->controlPlaneName(), declaration->to(), - size->value.get_si(), + int(size->value), typeSpec}; } }; diff --git a/control-plane/p4RuntimeSerializer.cpp b/control-plane/p4RuntimeSerializer.cpp index aca87c1bf25..3c370a945dd 100644 --- a/control-plane/p4RuntimeSerializer.cpp +++ b/control-plane/p4RuntimeSerializer.cpp @@ -217,7 +217,7 @@ externalId(const IR::IDeclaration* declaration) { return boost::none; } - const uint32_t id = idConstant->value.get_si(); + const uint32_t id = static_cast(idConstant->value); return id; } @@ -647,13 +647,13 @@ getTypeWidth(const IR::Type* type, TypeMap* typeMap) { return -1; } auto value = sdnB->value; - auto bitsRequired = static_cast(mpz_sizeinbase(value.get_mpz_t(), 2)); + auto bitsRequired = floor_log2(value) + 1; if (bitsRequired > 31) { - ::error("Cannot represent %1% on 31 bits, require %2%", value.get_ui(), + ::error("Cannot represent %1% on 31 bits, require %2%", value, bitsRequired); return -2; } - return static_cast(value.get_ui()); + return static_cast(value); } return typeMap->minWidthBits(type, type->getNode()); } @@ -1084,7 +1084,7 @@ class P4RuntimeAnalyzer { ::error("@size should be a positive integer for declaration %1%", inst); return; } - size = sizeConstant->value.get_ui(); + size = static_cast(sizeConstant->value); auto id = symbols.getId(P4RuntimeSymbolType::VALUE_SET(), name); setPreamble(vs->mutable_preamble(), id, name, symbols.getAlias(name), @@ -1491,15 +1491,15 @@ class P4RuntimeEntriesConverter { } } - /// Convert a key expression to the mpz_class integer value if the + /// Convert a key expression to the big_int integer value if the /// expression is simple (integer literal or boolean literal) or returns /// boost::none otherwise. - boost::optional simpleKeyExpressionValue( + boost::optional simpleKeyExpressionValue( const IR::Expression* k, TypeMap* typeMap) const { if (k->is()) { return k->to()->value; } else if (k->is()) { - return static_cast(k->to()->value ? 1 : 0); + return static_cast(k->to()->value ? 1 : 0); } else if (k->is()) { // handle SerEnum members auto mem = k->to(); auto ei = EnumInstance::resolve(mem, typeMap); @@ -1539,10 +1539,10 @@ class P4RuntimeEntriesConverter { auto km = k->to(); auto value = simpleKeyExpressionValue(km->left, typeMap); if (value == boost::none) return; - auto trailing_zeros = [keyWidth](const mpz_class& n) -> int { - return (n == 0) ? keyWidth : mpz_scan1(n.get_mpz_t(), 0); }; - auto count_ones = [](const mpz_class& n) -> int { - return mpz_popcount(n.get_mpz_t()); }; + auto trailing_zeros = [keyWidth](const big_int& n) -> int { + return (n == 0) ? keyWidth : boost::multiprecision::lsb(n); }; + auto count_ones = [](const big_int& n) -> int { + return bitcount(n); }; auto mask = km->right->to()->value; auto len = trailing_zeros(mask); if (len + count_ones(mask) != keyWidth) { // any remaining 0s in the prefix? @@ -1616,7 +1616,7 @@ class P4RuntimeEntriesConverter { auto start = simpleKeyExpressionValue(kr->left, typeMap); auto end = simpleKeyExpressionValue(kr->right, typeMap); if (start == boost::none || end == boost::none) return; - mpz_class maxValue = (mpz_class(1) << keyWidth) - 1; + big_int maxValue = (big_int(1) << keyWidth) - 1; // These should be guaranteed by the frontend BUG_CHECK(*start <= *end, "Invalid range with start greater than end"); BUG_CHECK(*end <= maxValue, "End of range is too large"); diff --git a/control-plane/typeSpecConverter.cpp b/control-plane/typeSpecConverter.cpp index fff9cb5ee34..a4653f24fc4 100644 --- a/control-plane/typeSpecConverter.cpp +++ b/control-plane/typeSpecConverter.cpp @@ -140,8 +140,7 @@ bool TypeSpecConverter::preorder(const IR::Type_Newtype* type) { return false; } auto value = sdnB->value; - auto bitsRequired = static_cast( - mpz_sizeinbase(value.get_mpz_t(), 2)); + auto bitsRequired = floor_log2(value) + 1; BUG_CHECK(bitsRequired <= 31, "Cannot represent %1% on 31 bits, require %2%", value, bitsRequired); @@ -162,7 +161,7 @@ bool TypeSpecConverter::preorder(const IR::Type_Newtype* type) { } else { auto dataType = newTypeSpec->mutable_translated_type(); dataType->set_uri(std::string(uri->value)); - dataType->set_sdn_bitwidth((uint32_t) sdnB->value.get_ui()); + dataType->set_sdn_bitwidth((uint32_t) sdnB->value); } (*types)[name] = *newTypeSpec; } @@ -195,7 +194,7 @@ bool TypeSpecConverter::preorder(const IR::Type_Stack* type) { auto name = decl->controlPlaneName(); auto sizeConstant = type->size->to(); - auto size = sizeConstant->value.get_ui(); + unsigned size = static_cast(sizeConstant->value); if (decl->is()) { auto headerStackTypeSpec = typeSpec->mutable_header_stack(); diff --git a/frontends/common/constantFolding.cpp b/frontends/common/constantFolding.cpp index 16be69fad22..0dfb3e07f46 100644 --- a/frontends/common/constantFolding.cpp +++ b/frontends/common/constantFolding.cpp @@ -206,7 +206,7 @@ const IR::Node* DoConstantFolding::postorder(IR::Cmpl* e) { return e; } - mpz_class value = ~cst->value; + big_int value = ~cst->value; return new IR::Constant(cst->srcInfo, t, value, cst->base, true); } @@ -231,7 +231,7 @@ const IR::Node* DoConstantFolding::postorder(IR::Neg* e) { return e; } - mpz_class value = -cst->value; + big_int value = -cst->value; return new IR::Constant(cst->srcInfo, t, value, cst->base, true); } @@ -241,35 +241,35 @@ DoConstantFolding::cast(const IR::Constant* node, unsigned base, const IR::Type_ } const IR::Node* DoConstantFolding::postorder(IR::Add* e) { - return binary(e, [](mpz_class a, mpz_class b) -> mpz_class { return a + b; }); + return binary(e, [](big_int a, big_int b) -> big_int { return a + b; }); } const IR::Node* DoConstantFolding::postorder(IR::AddSat* e) { - return binary(e, [](mpz_class a, mpz_class b) -> mpz_class { return a + b; }, true); + return binary(e, [](big_int a, big_int b) -> big_int { return a + b; }, true); } const IR::Node* DoConstantFolding::postorder(IR::Sub* e) { - return binary(e, [](mpz_class a, mpz_class b) -> mpz_class { return a - b; }); + return binary(e, [](big_int a, big_int b) -> big_int { return a - b; }); } const IR::Node* DoConstantFolding::postorder(IR::SubSat* e) { - return binary(e, [](mpz_class a, mpz_class b) -> mpz_class { return a - b; }, true); + return binary(e, [](big_int a, big_int b) -> big_int { return a - b; }, true); } const IR::Node* DoConstantFolding::postorder(IR::Mul* e) { - return binary(e, [](mpz_class a, mpz_class b) -> mpz_class { return a * b; }); + return binary(e, [](big_int a, big_int b) -> big_int { return a * b; }); } const IR::Node* DoConstantFolding::postorder(IR::BXor* e) { - return binary(e, [](mpz_class a, mpz_class b) -> mpz_class { return a ^ b; }); + return binary(e, [](big_int a, big_int b) -> big_int { return a ^ b; }); } const IR::Node* DoConstantFolding::postorder(IR::BAnd* e) { - return binary(e, [](mpz_class a, mpz_class b) -> mpz_class { return a & b; }); + return binary(e, [](big_int a, big_int b) -> big_int { return a & b; }); } const IR::Node* DoConstantFolding::postorder(IR::BOr* e) { - return binary(e, [](mpz_class a, mpz_class b) -> mpz_class { return a | b; }); + return binary(e, [](big_int a, big_int b) -> big_int { return a | b; }); } const IR::Node* DoConstantFolding::postorder(IR::Equ* e) { @@ -281,28 +281,28 @@ const IR::Node* DoConstantFolding::postorder(IR::Neq* e) { } const IR::Node* DoConstantFolding::postorder(IR::Lss* e) { - return binary(e, [](mpz_class a, mpz_class b) -> mpz_class { return a < b; }); + return binary(e, [](big_int a, big_int b) -> big_int { return a < b; }); } const IR::Node* DoConstantFolding::postorder(IR::Grt* e) { - return binary(e, [](mpz_class a, mpz_class b) -> mpz_class { return a > b; }); + return binary(e, [](big_int a, big_int b) -> big_int { return a > b; }); } const IR::Node* DoConstantFolding::postorder(IR::Leq* e) { - return binary(e, [](mpz_class a, mpz_class b) -> mpz_class { return a <= b; }); + return binary(e, [](big_int a, big_int b) -> big_int { return a <= b; }); } const IR::Node* DoConstantFolding::postorder(IR::Geq* e) { - return binary(e, [](mpz_class a, mpz_class b) -> mpz_class { return a >= b; }); + return binary(e, [](big_int a, big_int b) -> big_int { return a >= b; }); } const IR::Node* DoConstantFolding::postorder(IR::Div* e) { - return binary(e, [e](mpz_class a, mpz_class b) -> mpz_class { - if (sgn(a) < 0 || sgn(b) < 0) { + return binary(e, [e](big_int a, big_int b) -> big_int { + if (a < 0 || b < 0) { ::error("%1%: Division is not defined for negative numbers", e); return 0; } - if (sgn(b) == 0) { + if (b == 0) { ::error("%1%: Division by zero", e); return 0; } @@ -311,12 +311,12 @@ const IR::Node* DoConstantFolding::postorder(IR::Div* e) { } const IR::Node* DoConstantFolding::postorder(IR::Mod* e) { - return binary(e, [e](mpz_class a, mpz_class b) -> mpz_class { - if (sgn(a) < 0 || sgn(b) < 0) { + return binary(e, [e](big_int a, big_int b) -> big_int { + if (a < 0 || b < 0) { ::error("%1%: Modulo is not defined for negative numbers", e); return 0; } - if (sgn(b) == 0) { + if (b == 0) { ::error("%1%: Modulo by zero", e); return 0; } @@ -386,14 +386,14 @@ DoConstantFolding::compare(const IR::Operation_Binary* e) { } if (eqTest) - return binary(e, [](mpz_class a, mpz_class b) -> mpz_class { return a == b; }); + return binary(e, [](big_int a, big_int b) -> big_int { return a == b; }); else - return binary(e, [](mpz_class a, mpz_class b) -> mpz_class { return a != b; }); + return binary(e, [](big_int a, big_int b) -> big_int { return a != b; }); } const IR::Node* DoConstantFolding::binary(const IR::Operation_Binary* e, - std::function func, + std::function func, bool saturating) { auto eleft = getConstant(e->left); auto eright = getConstant(e->right); @@ -417,7 +417,7 @@ DoConstantFolding::binary(const IR::Operation_Binary* e, bool runk = rt->is(); const IR::Type* resultType; - mpz_class value = func(left->value, right->value); + big_int value = func(left->value, right->value); const IR::Type_Bits* ltb = nullptr; const IR::Type_Bits* rtb = nullptr; @@ -460,7 +460,7 @@ DoConstantFolding::binary(const IR::Operation_Binary* e, } if (saturating) { if ((rtb = resultType->to())) { - mpz_class limit = 1; + big_int limit = 1; if (rtb->isSigned) { limit <<= rtb->size-1; if (value < -limit) @@ -556,8 +556,8 @@ const IR::Node* DoConstantFolding::postorder(IR::Slice* e) { e, P4CConfiguration::MaximumWidthSupported); return e; } - mpz_class value = cbase->value >> l; - mpz_class mask = 1; + big_int value = cbase->value >> l; + big_int mask = 1; mask = (mask << (m - l + 1)) - 1; value = value & mask; auto resultType = typeMap->getType(getOriginal(), true); @@ -637,7 +637,7 @@ const IR::Node* DoConstantFolding::postorder(IR::Concat* e) { } auto resultType = IR::Type_Bits::get(lt->size + rt->size, lt->isSigned); - mpz_class value = Util::shift_left(left->value, static_cast(rt->size)) + right->value; + big_int value = Util::shift_left(left->value, static_cast(rt->size)) + right->value; return new IR::Constant(e->srcInfo, resultType, value, left->base); } @@ -677,12 +677,12 @@ const IR::Node* DoConstantFolding::shift(const IR::Operation_Binary* e) { ::error(ErrorType::ERR_EXPECTED, "an integer value", right); return e; } - if (sgn(cr->value) < 0) { + if (cr->value < 0) { ::error("%1%: Shifts with negative amounts are not permitted", e); return e; } - if (sgn(cr->value) == 0) { + if (cr->value == 0) { // ::warning("%1% with zero", e); return e->left; } @@ -697,7 +697,7 @@ const IR::Node* DoConstantFolding::shift(const IR::Operation_Binary* e) { return e; } - mpz_class value = cl->value; + big_int value = cl->value; unsigned shift = static_cast(cr->asInt()); auto tb = left->type->to(); diff --git a/frontends/common/constantFolding.h b/frontends/common/constantFolding.h index bcfe2f604c2..b6ee7ef26cb 100644 --- a/frontends/common/constantFolding.h +++ b/frontends/common/constantFolding.h @@ -17,8 +17,7 @@ limitations under the License. #ifndef _COMMON_CONSTANTFOLDING_H_ #define _COMMON_CONSTANTFOLDING_H_ -#include - +#include "lib/gmputil.h" #include "ir/ir.h" #include "frontends/p4/typeChecking/typeChecker.h" @@ -76,7 +75,7 @@ class DoConstantFolding : public Transform { /// Statically evaluate binary operation @p e implemented by @p func. const IR::Node* binary(const IR::Operation_Binary* op, - std::function func, + std::function func, bool saturating = false); /// Statically evaluate comparison operation @p e. /// Note that this only handles the case where @p e represents `==` or `!=`. diff --git a/frontends/common/constantParsing.cpp b/frontends/common/constantParsing.cpp index c9aa1e9a077..0abbccc5315 100644 --- a/frontends/common/constantParsing.cpp +++ b/frontends/common/constantParsing.cpp @@ -48,7 +48,7 @@ parseConstantWithWidth(Util::SourceInfo srcInfo, const char* text, bool isSigned = *sep++ == 's'; sep += strspn(sep, " \t\r\n"); - mpz_class value = Util::cvtInt(sep+skip, base); + big_int value = Util::cvtInt(sep+skip, base); const IR::Type* type = IR::Type_Bits::get(srcInfo, size, isSigned); IR::Constant* result = new IR::Constant(srcInfo, type, value, base); return result; diff --git a/frontends/p4/fromv1.0/converters.cpp b/frontends/p4/fromv1.0/converters.cpp index 4cb4d6837d6..a829978e83d 100644 --- a/frontends/p4/fromv1.0/converters.cpp +++ b/frontends/p4/fromv1.0/converters.cpp @@ -43,7 +43,7 @@ const IR::Node* ExpressionConverter::postorder(IR::Mask* expression) { auto exp = expression->left; auto cst = expression->right->to(); - mpz_class value = cst->value; + big_int value = cst->value; if (value == 0) { ::warning(ErrorType::WARN_INVALID, "%1%: zero mask", expression->right); return cst; diff --git a/frontends/p4/fromv1.0/programStructure.cpp b/frontends/p4/fromv1.0/programStructure.cpp index 4bbaeb2a208..52d9a824f06 100644 --- a/frontends/p4/fromv1.0/programStructure.cpp +++ b/frontends/p4/fromv1.0/programStructure.cpp @@ -381,8 +381,8 @@ ProgramStructure::explodeLabel(const IR::Constant* value, const IR::Constant* ma return new IR::DefaultExpression(value->srcInfo); bool useMask = mask->value != -1; - mpz_class v = value->value; - mpz_class m = mask->value; + big_int v = value->value; + big_int m = mask->value; auto rv = new IR::ListExpression(value->srcInfo, {}); for (auto it = fieldTypes.rbegin(); it != fieldTypes.rend(); ++it) { diff --git a/frontends/p4/strengthReduction.cpp b/frontends/p4/strengthReduction.cpp index 0c3277f05c8..ae0097e2c74 100644 --- a/frontends/p4/strengthReduction.cpp +++ b/frontends/p4/strengthReduction.cpp @@ -51,13 +51,11 @@ int DoStrengthReduction::isPowerOf2(const IR::Expression* expr) const { auto cst = expr->to(); if (cst == nullptr) return -1; - mpz_class value = cst->value; - if (sgn(value) <= 0) + if (cst->value <= 0) return -1; - auto bitcnt = mpz_popcount(value.get_mpz_t()); - if (bitcnt != 1) + auto log = boost::multiprecision::msb(cst->value); + if (log != boost::multiprecision::lsb(cst->value)) return -1; - auto log = mpz_scan1(value.get_mpz_t(), 0); // Assumes value does not have more than 2 billion bits return log; } @@ -66,10 +64,10 @@ bool DoStrengthReduction::isAllOnes(const IR::Expression* expr) const { auto cst = expr->to(); if (cst == nullptr) return false; - mpz_class value = cst->value; - if (sgn(value) <= 0) + big_int value = cst->value; + if (value <= 0) return false; - auto bitcnt = mpz_popcount(value.get_mpz_t()); + auto bitcnt = bitcount(value); return bitcnt == (unsigned long)(expr->type->width_bits()); } @@ -250,7 +248,7 @@ const IR::Node* DoStrengthReduction::postorder(IR::Mod* expr) { return expr->left; auto exp = isPowerOf2(expr->right); if (exp >= 0) { - mpz_class mask = 1; + big_int mask = 1; mask = (mask << exp) - 1; auto amt = new IR::Constant(expr->right->to()->type, mask); auto sh = new IR::BAnd(expr->srcInfo, expr->left, amt); diff --git a/frontends/p4/toP4/toP4.cpp b/frontends/p4/toP4/toP4.cpp index 4a3024e2df8..af19ad27e3b 100644 --- a/frontends/p4/toP4/toP4.cpp +++ b/frontends/p4/toP4/toP4.cpp @@ -16,6 +16,7 @@ limitations under the License. #include #include +#include #include "toP4.h" #include "frontends/common/options.h" #include "frontends/parsers/p4/p4parser.hpp" @@ -553,10 +554,10 @@ bool ToP4::preorder(const IR::Type_Control* t) { /////////////////////// bool ToP4::preorder(const IR::Constant* c) { - mpz_class value = c->value; + big_int value = c->value; const IR::Type_Bits* tb = dynamic_cast(c->type); if (tb != nullptr) { - mpz_class zero = 0; + big_int zero = 0; if (value < zero) { builder.append("-"); value = -value; @@ -564,7 +565,6 @@ bool ToP4::preorder(const IR::Constant* c) { builder.appendFormat("%d", tb->size); builder.append(tb->isSigned ? "s" : "w"); } - const char* repr = mpz_get_str(nullptr, c->base, value.get_mpz_t()); switch (c->base) { case 2: builder.append("0b"); @@ -580,7 +580,13 @@ bool ToP4::preorder(const IR::Constant* c) { default: BUG("%1%: Unexpected base %2%", c, c->base); } - builder.append(repr); + std::deque buf; + do { + buf.push_front("0123456789abcdef"[static_cast(static_cast(value % c->base))]); + value = value / c->base; + } while (value > 0); + for (auto ch : buf) + builder.appendFormat("%c", ch); return false; } diff --git a/frontends/p4/typeChecking/typeChecker.cpp b/frontends/p4/typeChecking/typeChecker.cpp index d2429b89e56..c61e25925aa 100644 --- a/frontends/p4/typeChecking/typeChecker.cpp +++ b/frontends/p4/typeChecking/typeChecker.cpp @@ -2010,14 +2010,14 @@ const IR::Node* TypeInference::unsBinaryArith(const IR::Operation_Binary* expres auto cleft = expression->left->to(); if (cleft != nullptr) { - if (sgn(cleft->value) < 0) { + if (cleft->value < 0) { typeError("%1%: not defined on negative numbers", expression); return expression; } } auto cright = expression->right->to(); if (cright != nullptr) { - if (sgn(cright->value) < 0) { + if (cright->value < 0) { typeError("%1%: not defined on negative numbers", expression); return expression; } diff --git a/ir/expression.cpp b/ir/expression.cpp index 32838820bc3..bcb37e3b1ce 100644 --- a/ir/expression.cpp +++ b/ir/expression.cpp @@ -73,12 +73,12 @@ IR::Constant::handleOverflow(bool noWarning) { } int width = tb->size; - mpz_class one = 1; - mpz_class mask = Util::mask(width); + big_int one = 1; + big_int mask = Util::mask(width); if (tb->isSigned) { - mpz_class max = (one << (width - 1)) - 1; - mpz_class min = -(one << (width - 1)); + big_int max = (one << (width - 1)) - 1; + big_int min = -(one << (width - 1)); if (value < min || value > max) { if (!noWarning) ::warning(ErrorType::WARN_OVERFLOW, @@ -91,7 +91,7 @@ IR::Constant::handleOverflow(bool noWarning) { value -= (one << width); } } else { - if (sgn(value) < 0) { + if (value < 0) { if (!noWarning) ::warning(ErrorType::WARN_MISMATCH, "%1%: negative value with unsigned type", this); @@ -102,58 +102,44 @@ IR::Constant::handleOverflow(bool noWarning) { } value = value & mask; - if (sgn(value) < 0) + if (value < 0) BUG("Negative value after masking %1%", value); } } IR::Constant IR::Constant::operator<<(const unsigned &shift) const { - mpz_class v; - mpz_mul_2exp(v.get_mpz_t(), value.get_mpz_t(), shift); - return IR::Constant(v); + return IR::Constant(value << shift); } IR::Constant IR::Constant::operator>>(const unsigned &shift) const { - mpz_class v; - mpz_div_2exp(v.get_mpz_t(), value.get_mpz_t(), shift); - return IR::Constant(v); + return IR::Constant(value >> shift); } IR::Constant IR::Constant::operator&(const IR::Constant &c) const { - mpz_class v; - mpz_and(v.get_mpz_t(), value.get_mpz_t(), c.value.get_mpz_t()); - return IR::Constant(v); + return IR::Constant(value & c.value); } IR::Constant IR::Constant::operator|(const IR::Constant &c) const { - mpz_class v; - mpz_ior(v.get_mpz_t(), value.get_mpz_t(), c.value.get_mpz_t()); - return IR::Constant(v); + return IR::Constant(value | c.value); } IR::Constant IR::Constant::operator^(const IR::Constant &c) const { - mpz_class v; - mpz_xor(v.get_mpz_t(), value.get_mpz_t(), c.value.get_mpz_t()); - return IR::Constant(v); + return IR::Constant(value ^ c.value); } IR::Constant IR::Constant::operator-(const IR::Constant &c) const { - mpz_class v; - mpz_sub(v.get_mpz_t(), value.get_mpz_t(), c.value.get_mpz_t()); - return IR::Constant(v); + return IR::Constant(value - c.value); } IR::Constant IR::Constant::operator-() const { - mpz_class v; - mpz_neg(v.get_mpz_t(), value.get_mpz_t()); - return IR::Constant(v); + return IR::Constant(-value); } IR::Constant diff --git a/ir/expression.def b/ir/expression.def index 40e8976993c..81ab381b1db 100644 --- a/ir/expression.def +++ b/ir/expression.def @@ -136,7 +136,7 @@ abstract Literal : Expression, CompileTimeValue { /// This is an integer literal on arbitrary-precision. class Constant : Literal { - mpz_class value; + big_int value; optional unsigned base; /// base used when reading/writing #noconstructor /// if noWarning is true, no warning is emitted @@ -158,53 +158,44 @@ class Constant : Literal { Constant(unsigned long v, unsigned base = 10) : Literal(new Type_InfInt()), value(v), base(base) {} Constant(intmax_t v, unsigned base = 10) : - Literal(new Type_InfInt()), base(base) { - mpz_import(value.get_mpz_t(), /* word count */1, /* msb first */0, - /* word size */sizeof(v), /* native endian */0, /* nails */0, &v); } + Literal(new Type_InfInt()), value(v), base(base) {} #endif #end Constant(uint64_t v, unsigned base = 10) : - Literal(new Type_InfInt()), base(base) { - mpz_import(value.get_mpz_t(), /* word count */1, /* msb first */0, - /* word size */sizeof(v), /* native endian */0, /* nails */0, &v); } - Constant(mpz_class v, unsigned base = 10) : - Literal(new Type_InfInt()), value(v), base(base) {} - Constant(Util::SourceInfo si, mpz_class v, unsigned base = 10) : - Literal(si, new Type_InfInt()), value(v), base(base) {} - Constant(const Type *t, mpz_class v, unsigned base = 10, bool noWarning = false) : - Literal(t), value(v), base(base) { CHECK_NULL(t); handleOverflow(noWarning); } - Constant(Util::SourceInfo si, const Type *t, mpz_class v, + Literal(new Type_InfInt()), value(v), base(base) {} + Constant(big_int v, unsigned base = 10) : + Literal(new Type_InfInt()), value(v), base(base) {} + Constant(Util::SourceInfo si, big_int v, unsigned base = 10) : + Literal(si, new Type_InfInt()), value(v), base(base) {} + Constant(const Type *t, big_int v, unsigned base = 10, bool noWarning = false) : + Literal(t), value(v), base(base) { CHECK_NULL(t); handleOverflow(noWarning); } + Constant(Util::SourceInfo si, const Type *t, big_int v, unsigned base = 10, bool noWarning = false) : - Literal(si, t), value(v), base(base) { CHECK_NULL(t); handleOverflow(noWarning); } + Literal(si, t), value(v), base(base) { CHECK_NULL(t); handleOverflow(noWarning); } #emit static Constant GetMask(unsigned width); #end - bool fitsInt() const { return value.fits_sint_p(); } - bool fitsLong() const { return value.fits_slong_p(); } - bool fitsUint() const { return value.fits_uint_p(); } - bool fitsUint64() const { return mpz_sizeinbase(value.get_mpz_t(), 2) < 65; } + bool fitsInt() const { return value >= INT_MIN && value <= INT_MAX; } + bool fitsLong() const { return value >= LONG_MIN && value <= LONG_MAX; } + bool fitsUint() const { return value >= 0 && value <= UINT_MAX; } + bool fitsUint64() const { return value >= 0 && value <= UINT64_MAX; } long asLong() const { if (!fitsLong()) ::error(ErrorType::ERR_OVERLIMIT, "%1$x: Value too large for long", this); - return value.get_si(); } + return static_cast(value); } int asInt() const { if (!fitsInt()) ::error(ErrorType::ERR_OVERLIMIT, "%1$x: Value too large for int", this); - return value.get_si(); } + return static_cast(value); } unsigned asUnsigned() const { if (!fitsUint()) ::error(ErrorType::ERR_OVERLIMIT, "%1$x: Value too large for unsigned int", this); - return value.get_ui(); + return static_cast(value); } uint64_t asUint64() const { if (!fitsUint64()) ::error(ErrorType::ERR_OVERLIMIT, "%1$x: Value too large for uint64", this); - uint64_t res = UINT64_C(0); - size_t nWords = 0; - mpz_export(&res, &nWords, /* msb first */0, /* word size */8, - /* native endian */0, /* nails */0, - value.get_mpz_t()); - return res; + return static_cast(value); } // The following operators are only used in special circumstances. // They do not look at the type when operating. There are separate diff --git a/ir/json_generator.h b/ir/json_generator.h index 8a728d35ca2..e126531eec7 100644 --- a/ir/json_generator.h +++ b/ir/json_generator.h @@ -19,7 +19,6 @@ limitations under the License. #include #include -#include #include #include #include "lib/bitvec.h" @@ -173,7 +172,9 @@ class JSONGenerator { typename std::enable_if::value>::type generate(T v) { out << std::to_string(v); } void generate(double v) { out << std::to_string(v); } - void generate(const mpz_class &v) { out << v; } + template + typename std::enable_if::value>::type + generate(const T &v) { out << v; } void generate(cstring v) { if (v) diff --git a/ir/json_loader.h b/ir/json_loader.h index 68e1f387f4b..af10bc0794b 100644 --- a/ir/json_loader.h +++ b/ir/json_loader.h @@ -19,7 +19,6 @@ limitations under the License. #include #include -#include #include #include #include @@ -197,7 +196,7 @@ class JSONLoader { template typename std::enable_if::value>::type unpack_json(T &v) { v = *json->to(); } - void unpack_json(mpz_class &v) { v = json->to()->val; } + void unpack_json(big_int &v) { v = json->to()->val; } void unpack_json(cstring &v) { if (!json->is()) v = *json->to(); } void unpack_json(IR::ID &v) { if (!json->is()) v.name = *json->to(); } diff --git a/ir/json_parser.cpp b/ir/json_parser.cpp index 5ef3b1561c1..9bd137e41a5 100644 --- a/ir/json_parser.cpp +++ b/ir/json_parser.cpp @@ -178,10 +178,16 @@ std::istream& operator>>(std::istream &in, JsonData*& json) { } case '-': case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': { - mpz_class num; + // operator>>(istream, big_int) is broken and throws exceptions if the + // number is not followed by whitespace, so we need to manually extract all + // the digits into a buffer and convert that to big_int + std::string num; + do { + num += ch; + in >> ch; + } while (isdigit(ch)); in.unget(); - in >> num; - json = new JsonNumber(num); + json = new JsonNumber(big_int(num)); return in; } case 't': case 'T': diff --git a/ir/json_parser.h b/ir/json_parser.h index d1884510acb..75d5f178e75 100644 --- a/ir/json_parser.h +++ b/ir/json_parser.h @@ -23,9 +23,9 @@ class JsonData { class JsonNumber : public JsonData { public: - JsonNumber(mpz_class v) : val(v) {} // NOLINT(runtime/explicit) - operator int() const { return val.get_si(); } // Does not handle overflow - mpz_class val; + JsonNumber(big_int v) : val(v) {} // NOLINT(runtime/explicit) + operator int() const { return int(val); } // Does not handle overflow + big_int val; }; class JsonBoolean : public JsonData { diff --git a/ir/pattern.h b/ir/pattern.h index a142f23ee66..936e9d27444 100644 --- a/ir/pattern.h +++ b/ir/pattern.h @@ -40,13 +40,13 @@ class Pattern { }; class Const : public Base { - mpz_class value; + big_int value; public: bool match(const IR::Node *n) override { if (auto k = n->to()) return k->value == value; return false; } - Const(mpz_class v) : value(v) {} + Const(big_int v) : value(v) {} Const(int v) : value(v) {} }; template class Unary : public Base { @@ -108,7 +108,7 @@ class Pattern { template Pattern(const T*&m) : pattern(new MatchExt(m)) {} template Pattern(Match &m) : pattern(&m) {} - Pattern(mpz_class v) : pattern(new Const(v)) {} // NOLINT(runtime/explicit) + Pattern(big_int v) : pattern(new Const(v)) {} // NOLINT(runtime/explicit) Pattern(int v) : pattern(new Const(v)) {} // NOLINT(runtime/explicit) Pattern operator-() const { return Pattern(new Unary(pattern)); } Pattern operator~() const { return Pattern(new Unary(pattern)); } diff --git a/ir/visitor.cpp b/ir/visitor.cpp index 955ddaafe82..6223dee82cb 100644 --- a/ir/visitor.cpp +++ b/ir/visitor.cpp @@ -474,6 +474,7 @@ IRNODE_ALL_NON_TEMPLATE_CLASSES(DEFINE_APPLY_FUNCTIONS, , , ) std::ostream &operator<<(std::ostream &out, const IR::Vector *v) { return v ? out << *v : out << ""; } +#include #if HAVE_CXXABI_H #include diff --git a/lib/bitops.h b/lib/bitops.h index 06de93c4762..72f37a2559d 100644 --- a/lib/bitops.h +++ b/lib/bitops.h @@ -27,8 +27,7 @@ static inline unsigned bitcount(unsigned v) { unsigned rv = 0; while (v) { v &= v-1; ++rv; } #endif - return rv; -} + return rv; } static inline int floor_log2(unsigned v) { int rv = -1; @@ -37,8 +36,7 @@ static inline int floor_log2(unsigned v) { #else while (v) { rv++; v >>= 1; } #endif - return rv; -} + return rv; } static inline int ceil_log2(unsigned v) { return v ? floor_log2(v-1) + 1 : -1; diff --git a/lib/error_helper.h b/lib/error_helper.h index ae8515e84e5..63a8ecfa653 100644 --- a/lib/error_helper.h +++ b/lib/error_helper.h @@ -77,11 +77,11 @@ auto error_helper(boost::format& f, std::string message, std::string position, template std::string error_helper(boost::format& f, std::string message, std::string position, - std::string tail, const mpz_class *t, Args... args); + std::string tail, const big_int *t, Args... args); template std::string error_helper(boost::format& f, std::string message, std::string position, - std::string tail, const mpz_class &t, Args... args); + std::string tail, const big_int &t, Args... args); template auto @@ -122,14 +122,14 @@ auto error_helper(boost::format& f, std::string message, std::string position, template std::string error_helper(boost::format& f, std::string message, std::string position, - std::string tail, const mpz_class *t, Args... args) { - return error_helper(f % t->get_str(), message, position, tail, std::forward(args)...); + std::string tail, const big_int *t, Args... args) { + return error_helper(f % t, message, position, tail, std::forward(args)...); } template std::string error_helper(boost::format& f, std::string message, std::string position, - std::string tail, const mpz_class &t, Args... args) { - return error_helper(f % t.get_str(), message, position, tail, std::forward(args)...); + std::string tail, const big_int &t, Args... args) { + return error_helper(f % t, message, position, tail, std::forward(args)...); } template @@ -231,11 +231,11 @@ auto bug_helper(boost::format& f, std::string message, std::string position, template std::string bug_helper(boost::format& f, std::string message, std::string position, - std::string tail, const mpz_class *t, Args... args); + std::string tail, const big_int *t, Args... args); template std::string bug_helper(boost::format& f, std::string message, std::string position, - std::string tail, const mpz_class &t, Args... args); + std::string tail, const big_int &t, Args... args); template auto @@ -270,14 +270,14 @@ auto bug_helper(boost::format& f, std::string message, std::string position, template std::string bug_helper(boost::format& f, std::string message, std::string position, - std::string tail, const mpz_class *t, Args... args) { - return bug_helper(f % t->get_str(), message, position, tail, std::forward(args)...); + std::string tail, const big_int *t, Args... args) { + return bug_helper(f % t, message, position, tail, std::forward(args)...); } template std::string bug_helper(boost::format& f, std::string message, std::string position, - std::string tail, const mpz_class &t, Args... args) { - return bug_helper(f % t.get_str(), message, position, tail, std::forward(args)...); + std::string tail, const big_int &t, Args... args) { + return bug_helper(f % t, message, position, tail, std::forward(args)...); } template diff --git a/lib/gmputil.cpp b/lib/gmputil.cpp index c1e08f0ffdf..f17e2ac4812 100644 --- a/lib/gmputil.cpp +++ b/lib/gmputil.cpp @@ -19,49 +19,45 @@ limitations under the License. namespace Util { -mpz_class shift_left(const mpz_class &v, unsigned bits) { - mpz_class exp; - mpz_class two(2); - mpz_pow_ui(exp.get_mpz_t(), two.get_mpz_t(), bits); - return v * exp; +using namespace boost::multiprecision; + +big_int shift_left(const big_int &v, unsigned bits) { + return v << bits; } -mpz_class shift_right(const mpz_class &v, unsigned bits) { - mpz_class result; - mpz_fdiv_q_2exp(result.get_mpz_t(), v.get_mpz_t(), bits); - return result; +big_int shift_right(const big_int &v, unsigned bits) { + return v >> bits; } // Returns last 'bits' of value // value is shifted right by this many bits -mpz_class ripBits(mpz_class &value, int bits) { - mpz_class last; - mpz_class rest; - - mpz_fdiv_r_2exp(last.get_mpz_t(), value.get_mpz_t(), bits); - mpz_fdiv_q_2exp(rest.get_mpz_t(), value.get_mpz_t(), bits); - value = rest; - return last; +big_int ripBits(big_int &value, int bits) { + big_int rv = 1; + rv <<= bits; + rv -= 1; + rv &= value; + value >>= bits; + return rv; } -mpz_class mask(unsigned bits) { - mpz_class one = 1; - mpz_class result = shift_left(one, bits); +big_int mask(unsigned bits) { + big_int one = 1; + big_int result = shift_left(one, bits); return result - 1; } -mpz_class maskFromSlice(unsigned m, unsigned l) { +big_int maskFromSlice(unsigned m, unsigned l) { if (m < l) throw std::logic_error("wrong argument order in maskFromSlice"); - mpz_class result = mask(m+1) - mask(l); + big_int result = mask(m+1) - mask(l); return result; } /// Find a consecutive scan of 1 bits -BitRange findOnes(const mpz_class &value) { +BitRange findOnes(const big_int &value) { BitRange result; if (value != 0) { - result.lowIndex = mpz_scan1(value.get_mpz_t(), 0); - result.highIndex = mpz_scan0(value.get_mpz_t(), result.lowIndex) - 1; + result.lowIndex = scan1(value, 0); + result.highIndex = scan0(value, result.lowIndex) - 1; result.value = maskFromSlice(result.highIndex, result.lowIndex); } else { result.lowIndex = -1; @@ -71,8 +67,8 @@ BitRange findOnes(const mpz_class &value) { return result; } -mpz_class cvtInt(const char *s, unsigned base) { - mpz_class rv; +big_int cvtInt(const char *s, unsigned base) { + big_int rv; while (*s) { switch (*s) { diff --git a/lib/gmputil.h b/lib/gmputil.h index 83279f383da..8701083a0d2 100644 --- a/lib/gmputil.h +++ b/lib/gmputil.h @@ -17,50 +17,78 @@ limitations under the License. #ifndef _LIB_GMPUTIL_H_ #define _LIB_GMPUTIL_H_ -#include // needed because of a bug in gcc-4.9/libgmp -#include // NOLINT: cstddef HAS to come first +#include "config.h" + +#if HAVE_LIBGMP +#include +typedef boost::multiprecision::mpz_int big_int; +#else +#include +typedef boost::multiprecision::cpp_int big_int; +#endif namespace Util { // Useful functions for manipulating GMP values // (arbitrary-precision values) -mpz_class ripBits(mpz_class &value, int bits); +big_int ripBits(big_int &value, int bits); struct BitRange { unsigned lowIndex; unsigned highIndex; - mpz_class value; + big_int value; }; // Find a consecutive scan of 1 bits at the "bottom" -BitRange findOnes(const mpz_class &value); +BitRange findOnes(const big_int &value); -mpz_class cvtInt(const char *s, unsigned base); -mpz_class shift_left(const mpz_class &v, unsigned bits); -mpz_class shift_right(const mpz_class &v, unsigned bits); +big_int cvtInt(const char *s, unsigned base); +big_int shift_left(const big_int &v, unsigned bits); +big_int shift_right(const big_int &v, unsigned bits); // Convert a slice [m:l] into a mask -mpz_class maskFromSlice(unsigned m, unsigned l); -mpz_class mask(unsigned bits); -} // namespace Util +big_int maskFromSlice(unsigned m, unsigned l); +big_int mask(unsigned bits); + +#if HAVE_LIBGMP +inline unsigned scan0(const boost::multiprecision::mpz_int &val, unsigned pos) { + return mpz_scan0(val.backend().data(), pos); } +inline unsigned scan1(const boost::multiprecision::mpz_int &val, unsigned pos) { + return mpz_scan1(val.backend().data(), pos); } +#else +inline unsigned scan0_positive(const boost::multiprecision::cpp_int &val, unsigned pos) { + while (boost::multiprecision::bit_test(val, pos)) ++pos; + return pos; } +inline unsigned scan1_positive(const boost::multiprecision::cpp_int &val, unsigned pos) { + if (val == 0 || pos > boost::multiprecision::msb(val)) return ~0U; + unsigned lsb = boost::multiprecision::lsb(val); + if (lsb >= pos) return lsb; + while (!boost::multiprecision::bit_test(val, pos)) ++pos; + return pos; } +inline unsigned scan0(const boost::multiprecision::cpp_int &val, unsigned pos) { + if (val < 0) return scan1_positive(-val - 1, pos); + return scan0_positive(val, pos); } +inline unsigned scan1(const boost::multiprecision::cpp_int &val, unsigned pos) { + if (val < 0) return scan0_positive(-val - 1, pos); + return scan1_positive(val, pos); } +#endif -#include "exceptions.h" -static inline unsigned bitcount(mpz_class value) { - mpz_class v = value; - if (sgn(v) < 0) - BUG("bitcount of negative number %1%", value); +} // namespace Util + +static inline unsigned bitcount(big_int v) { + if (v < 0) return ~0U; unsigned rv = 0; while (v != 0) { v &= v-1; ++rv; } return rv; } -static inline int ffs(mpz_class v) { +static inline int ffs(big_int v) { if (v == 0) return -1; - return mpz_scan1(v.get_mpz_t(), 0); + return boost::multiprecision::lsb(v); } -static inline int floor_log2(mpz_class v) { +static inline int floor_log2(big_int v) { int rv = -1; while (v > 0) { rv++; v /= 2; } return rv; diff --git a/lib/json.cpp b/lib/json.cpp index 0df8751c01a..7fa15907167 100644 --- a/lib/json.cpp +++ b/lib/json.cpp @@ -34,7 +34,7 @@ void IJson::dump() const { JsonValue* JsonValue::null = new JsonValue(); -mpz_class JsonValue::makeValue(long long v) { +big_int JsonValue::makeValue(long long v) { if (v >= 0) { return makeValue(static_cast(v)); } else { @@ -45,9 +45,8 @@ mpz_class JsonValue::makeValue(long long v) { } } -mpz_class JsonValue::makeValue(unsigned long long v) { - mpz_class tmp; - mpz_import(tmp.get_mpz_t(), 1, 1, sizeof(v), 0, 0, &v); +big_int JsonValue::makeValue(unsigned long long v) { + big_int tmp = v; return tmp; } @@ -85,12 +84,12 @@ void JsonValue::serialize(std::ostream& out) const { } } -bool JsonValue::operator==(const mpz_class& v) const +bool JsonValue::operator==(const big_int& v) const { return tag == Kind::Number ? v == value : false; } bool JsonValue::operator==(const double& v) const -{ return tag == Kind::Number ? v == value : false; } +{ return tag == Kind::Number ? big_int(v) == value : false; } bool JsonValue::operator==(const float& v) const -{ return tag == Kind::Number ? v == value : false; } +{ return tag == Kind::Number ? big_int(v) == value : false; } bool JsonValue::operator==(const cstring& s) const { return tag == Kind::String ? s == str : false; } bool JsonValue::operator==(const std::string& s) const @@ -154,17 +153,17 @@ cstring JsonValue::getString() const { return str; } -mpz_class JsonValue::getValue() const { +big_int JsonValue::getValue() const { if (!isNumber()) throw std::logic_error("Incorrect json value kind"); return value; } int JsonValue::getInt() const { - auto val = getValue(); - if (!value.fits_sint_p()) + big_int val = getValue(); + if (val < INT_MIN || val > INT_MAX) throw std::logic_error("Value too large for an int"); - return val.get_si(); + return int(val); } JsonArray* JsonArray::append(IJson* value) { diff --git a/lib/json.h b/lib/json.h index 2251549e41a..5a50f4ad7d4 100644 --- a/lib/json.h +++ b/lib/json.h @@ -55,7 +55,7 @@ class JsonValue final : public IJson { }; JsonValue() : tag(Kind::Null) {} JsonValue(bool b) : tag(b ? Kind::True : Kind::False) {} // NOLINT - JsonValue(mpz_class v) : tag(Kind::Number), value(v) {} // NOLINT + JsonValue(big_int v) : tag(Kind::Number), value(v) {} // NOLINT JsonValue(int v) : tag(Kind::Number), value(v) {} // NOLINT JsonValue(long v) : tag(Kind::Number), value(v) {} // NOLINT JsonValue(long long v); // NOLINT @@ -69,7 +69,7 @@ class JsonValue final : public IJson { JsonValue(const char* s) : tag(Kind::String), str(s) {} // NOLINT void serialize(std::ostream& out) const; - bool operator==(const mpz_class& v) const; + bool operator==(const big_int& v) const; // is_integral is true for bool template::value, int>::type = 0> bool operator==(const T& v) const @@ -88,7 +88,7 @@ class JsonValue final : public IJson { bool getBool() const; cstring getString() const; - mpz_class getValue() const; + big_int getValue() const; int getInt() const; static JsonValue* null; @@ -99,11 +99,11 @@ class JsonValue final : public IJson { throw std::logic_error("Incorrect constructor called"); } - static mpz_class makeValue(long long v); - static mpz_class makeValue(unsigned long long v); + static big_int makeValue(long long v); + static big_int makeValue(unsigned long long v); const Kind tag; - const mpz_class value = 0; + const big_int value = 0; const cstring str = nullptr; }; @@ -113,7 +113,7 @@ class JsonArray final : public IJson, public std::vector { void serialize(std::ostream& out) const; JsonArray* clone() const { return new JsonArray(*this); } JsonArray* append(IJson* value); - JsonArray* append(mpz_class v) { append(new JsonValue(v)); return this; } + JsonArray* append(big_int v) { append(new JsonValue(v)); return this; } template::value, int>::type = 0> JsonArray* append(T v) { append(new JsonValue(v)); return this; } JsonArray* append(double v) { append(new JsonValue(v)); return this; } @@ -138,7 +138,7 @@ class JsonObject final : public IJson, public ordered_map { void serialize(std::ostream& out) const; JsonObject* emplace(cstring label, IJson* value); JsonObject* emplace_non_null(cstring label, IJson* value); - JsonObject* emplace(cstring label, mpz_class v) + JsonObject* emplace(cstring label, big_int v) { emplace(label, new JsonValue(v)); return this; } template::value, int>::type = 0> JsonObject* emplace(cstring label, T v) diff --git a/lib/stringify.cpp b/lib/stringify.cpp index 50c0b9d9e98..9a2b638a666 100644 --- a/lib/stringify.cpp +++ b/lib/stringify.cpp @@ -41,10 +41,10 @@ cstring toString(const void* value) { return result.str(); } -cstring toString(const mpz_class* value, unsigned int base) { +cstring toString(const big_int* value, unsigned int base) { if (value == nullptr) return cstring::literal(""); - mpz_class v = *value; + big_int v = *value; std::ostringstream oss; if (v < 0) { oss << "-"; @@ -52,20 +52,20 @@ cstring toString(const mpz_class* value, unsigned int base) { } switch (base) { case 2: - oss << "0b"; + oss << "0x" << std::hex; break; case 8: - oss << "0o"; + oss << "0o" << std::oct; break; case 16: - oss << "0x"; + oss << "0x" << std::hex; break; case 10: break; default: throw std::runtime_error("Unexpected base"); } - oss << v.get_str(static_cast(base)); + oss << v; return oss.str(); } diff --git a/lib/stringify.h b/lib/stringify.h index a96c336fe1e..f07dd9292cc 100644 --- a/lib/stringify.h +++ b/lib/stringify.h @@ -20,7 +20,7 @@ limitations under the License. #define P4C_LIB_STRINGIFY_H_ #include -#include // for mpz_class +#include "gmputil.h" #include "cstring.h" #include "stringref.h" @@ -63,7 +63,7 @@ cstring toString(std::string value); cstring toString(const char* value); cstring toString(cstring value); cstring toString(StringRef value); -cstring toString(const mpz_class* value, unsigned int base = 10); +cstring toString(const big_int* value, unsigned int base = 10); cstring toString(const void* value); // printf into a string diff --git a/midend/removeLeftSlices.cpp b/midend/removeLeftSlices.cpp index 160f7ca369b..b2483795010 100644 --- a/midend/removeLeftSlices.cpp +++ b/midend/removeLeftSlices.cpp @@ -24,7 +24,7 @@ const IR::Node* DoRemoveLeftSlices::postorder(IR::AssignmentStatement* stat) { auto ls = stat->left->to(); int h = ls->getH(); int l = ls->getL(); - mpz_class m = Util::maskFromSlice(h, l); + big_int m = Util::maskFromSlice(h, l); auto type = typeMap->getType(ls->e0, true); auto mask = new IR::Constant(ls->srcInfo, type, m, 16); diff --git a/midend/simplifyBitwise.cpp b/midend/simplifyBitwise.cpp index 4ebffaf76bf..f735551ccf4 100644 --- a/midend/simplifyBitwise.cpp +++ b/midend/simplifyBitwise.cpp @@ -3,17 +3,17 @@ namespace P4 { -void SimplifyBitwise::assignSlices(const IR::Expression *expr, mpz_class mask) { - int one_pos = mpz_scan1(mask.get_mpz_t(), 0); +void SimplifyBitwise::assignSlices(const IR::Expression *expr, big_int mask) { + int one_pos = Util::scan1(mask, 0); // Calculate the slices for this particular mask while (one_pos >= 0) { - int zero_pos = mpz_scan0(mask.get_mpz_t(), one_pos); + int zero_pos = Util::scan0(mask, one_pos); auto left_slice = IR::Slice::make(changing_as->left, one_pos, zero_pos - 1); auto right_slice = IR::Slice::make(expr, one_pos, zero_pos - 1); auto new_as = new IR::AssignmentStatement(changing_as->srcInfo, left_slice, right_slice); slice_statements->push_back(new_as); - one_pos = mpz_scan1(mask.get_mpz_t(), zero_pos); + one_pos = Util::scan1(mask, zero_pos); } } @@ -30,7 +30,7 @@ const IR::Node *SimplifyBitwise::preorder(IR::AssignmentStatement *as) { slice_statements = new IR::Vector(); assignSlices(a, maskA->value); assignSlices(b, maskB->value); - mpz_class parameter_mask = (mpz_class(1) << (as->left->type->width_bits())) - 1; + big_int parameter_mask = (big_int(1) << (as->left->type->width_bits())) - 1; parameter_mask &= ~maskA->value; parameter_mask &= ~maskB->value; if (parameter_mask != 0) diff --git a/midend/simplifyBitwise.h b/midend/simplifyBitwise.h index 61b4b2bf6ff..98fe78ecf68 100644 --- a/midend/simplifyBitwise.h +++ b/midend/simplifyBitwise.h @@ -26,7 +26,7 @@ class SimplifyBitwise : public Transform { IR::Vector *slice_statements; const IR::AssignmentStatement *changing_as; - void assignSlices(const IR::Expression *expr, mpz_class mask); + void assignSlices(const IR::Expression *expr, big_int mask); public: const IR::Node *preorder(IR::AssignmentStatement *as) override; diff --git a/testdata/p4_16_samples_outputs/spec-ex04.p4-stderr b/testdata/p4_16_samples_outputs/spec-ex04.p4-stderr index 07bfe4f8aa0..a4ccec3ed90 100644 --- a/testdata/p4_16_samples_outputs/spec-ex04.p4-stderr +++ b/testdata/p4_16_samples_outputs/spec-ex04.p4-stderr @@ -1,4 +1,4 @@ -spec-ex04.p4(24): [--Wwarn=overflow] warning: 0b10101010: signed value does not fit in 8 bits +spec-ex04.p4(24): [--Wwarn=overflow] warning: 0xaa: signed value does not fit in 8 bits const int<8> b8 = 8s0b1010_1010 ^^^^^^^^^^^^^ warning: Program does not contain a `main' module From 69b9607a914b814268e02f7c77bea99474bbfdf5 Mon Sep 17 00:00:00 2001 From: Mihai Budiu Date: Tue, 3 Dec 2019 10:10:40 -0800 Subject: [PATCH 037/106] Update installation instructions for python3 (#2101) --- README.md | 3 ++- backends/bmv2/README.md | 4 +--- backends/ebpf/README.md | 6 +++++- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 46ae49a692b..a7b0c503200 100644 --- a/README.md +++ b/README.md @@ -108,7 +108,8 @@ dot -Tpdf ParserImpl.dot > ParserImpl.pdf 2. Install [dependencies](#dependencies). You can find specific instructions for Ubuntu 16.04 [here](#ubuntu-dependencies) and for macOS 10.12 - [here](#macos-dependencies). + [here](#macos-dependencies). You can also look at the + [travis installation script](tools/travis-build). 3. Build. Building should also take place in a subdirectory named `build`. ``` diff --git a/backends/bmv2/README.md b/backends/bmv2/README.md index 9931a14f30d..9b6ea5de8c3 100644 --- a/backends/bmv2/README.md +++ b/backends/bmv2/README.md @@ -14,9 +14,7 @@ To run and test this back-end you need some additional tools: https://github.com/p4lang/behavioral-model.git. You may need to update your dynamic libraries after installing bmv2: `sudo ldconfig` -- the Python scapy library for manipulating network packets `sudo pip install scapy` - -- the Python ipaddr library `sudo pip install ipaddr` +- the Python scapy and ipaddr libraries `sudo pip3 install scapy ipaddr` # Unsupported P4_16 language features diff --git a/backends/ebpf/README.md b/backends/ebpf/README.md index a005d7819c6..1696949167f 100644 --- a/backends/ebpf/README.md +++ b/backends/ebpf/README.md @@ -207,7 +207,7 @@ Additionally, the eBPF compiler test suite has the following python dependencies You can install these using: ``` $ sudo apt-get install clang llvm libpcap-dev libelf-dev iproute2 net-tools -$ sudo pip install pyroute2 ply scapy==2.4.0 +$ sudo pip3 install pyroute2 ply==3.8 scapy==2.4.0 ``` ### Supported capabilities @@ -332,3 +332,7 @@ The following tests run ebpf programs: - `make check-ebpf-bcc`: runs the user-space tests using bcc to compile ebpf - `sudo make check-ebpf-kernel`: runs the kernel-level tests. Requires root privileges to install the ebpf program in the Linux kernel. + Note: by default the kernel ebpf tests are disabled; if you want to enable them + you can modify the file `backends/ebpf/CMakeLists.txt` by setting this variable to `True`: + `set (SUPPORTS_KERNEL True)` + \ No newline at end of file From 152d5a67275ab4ab2cb3361ac4219c1b3fa2573b Mon Sep 17 00:00:00 2001 From: fruffy <5960321+fruffy@users.noreply.github.com> Date: Wed, 4 Dec 2019 12:35:23 -0500 Subject: [PATCH 038/106] Quick scapy fix. (#2099) --- backends/ebpf/targets/target.py | 7 +++---- tools/testutils.py | 2 +- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/backends/ebpf/targets/target.py b/backends/ebpf/targets/target.py index 957852f182c..c7a6ec470e8 100644 --- a/backends/ebpf/targets/target.py +++ b/backends/ebpf/targets/target.py @@ -26,8 +26,7 @@ import os import sys from glob import glob -from scapy.utils import rdpcap, RawPcapWriter -from scapy.layers.all import * +import scapy.utils as scapy_util from .ebpfstf import create_table_file, parse_stf_file # path to the tools folder of the compiler sys.path.insert(0, os.path.dirname( @@ -120,7 +119,7 @@ def _write_pcap_files(self, iface_pkts_map): direction = "in" infile = self.filename(iface, direction) # Linktype 1 the Ethernet Link Type, see also 'man pcap-linktype' - fp = RawPcapWriter(infile, linktype=1) + fp = scapy_util.RawPcapWriter(infile, linktype=1) fp._write_header(None) for pkt_data in pkts: try: @@ -181,7 +180,7 @@ def check_outputs(self): packets = [] else: try: - packets = rdpcap(file) + packets = scapy_util.rdpcap(file) except Exception as e: report_err(self.outputs["stderr"], "Corrupt pcap file", file, e) diff --git a/tools/testutils.py b/tools/testutils.py index b567e690e3b..3b9f02a8ea7 100644 --- a/tools/testutils.py +++ b/tools/testutils.py @@ -68,7 +68,7 @@ def hex_to_byte(hexStr): def compare_pkt(outputs, expected, received): """ Compare two given byte sequences and check if they are the same. Report errors if this is not the case. """ - received = received.convert_to(Raw).load.hex().upper() + received = bytes(received).hex().upper() expected = ''.join(expected.split()).upper() if len(received) < len(expected): report_err(outputs["stderr"], "Received packet too short", From d7647a430e0ab1c38f81adf10f259808a3491e96 Mon Sep 17 00:00:00 2001 From: Andy Fingerhut Date: Wed, 4 Dec 2019 09:35:58 -0800 Subject: [PATCH 039/106] Add instructions to install Python 3 version of Scapy as dependency (#2097) Without something like this, `cd p4c/build ; make check` fails on a freshly installed Ubuntu Linux machine. --- README.md | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index a7b0c503200..b653f5b82dd 100644 --- a/README.md +++ b/README.md @@ -198,10 +198,14 @@ included with `p4c` are documented here: Most dependencies can be installed using `apt-get install`: -`sudo apt-get install cmake g++ git automake libtool libgc-dev bison flex +```bash +$ sudo apt-get install cmake g++ git automake libtool libgc-dev bison flex libfl-dev libgmp-dev libboost-dev libboost-iostreams-dev -libboost-graph-dev llvm pkg-config python python-scapy python-ipaddr python-ply -tcpdump` +libboost-graph-dev llvm pkg-config python python-scapy python-ipaddr python-ply python3-pip +tcpdump + +$ pip3 install scapy +``` For documentation building: `sudo apt-get install -y doxygen graphviz texlive-full` From 8a292b491647c33ca10c0eb8331244371d037a80 Mon Sep 17 00:00:00 2001 From: Mihai Budiu Date: Thu, 5 Dec 2019 08:18:59 -0800 Subject: [PATCH 040/106] Add a Type_List for list expressions; fixes #2036 (#2085) --- control-plane/p4RuntimeSerializer.cpp | 2 +- control-plane/typeSpecConverter.cpp | 4 +- control-plane/typeSpecConverter.h | 2 +- frontends/p4/setHeaders.cpp | 2 +- frontends/p4/structInitializers.cpp | 6 +- frontends/p4/toP4/toP4.cpp | 2 +- frontends/p4/toP4/toP4.h | 2 +- frontends/p4/typeChecking/typeChecker.cpp | 98 ++++++++++--------- frontends/p4/typeChecking/typeChecker.h | 3 +- frontends/p4/typeChecking/typeUnification.cpp | 13 ++- frontends/p4/typeMap.cpp | 70 +++++++------ frontends/p4/typeMap.h | 3 +- ir/dbprint-type.cpp | 11 +++ ir/expression.def | 2 +- ir/type.cpp | 10 ++ ir/type.def | 21 +++- midend/complexComparison.cpp | 8 +- midend/eliminateTuples.cpp | 12 +-- midend/eliminateTuples.h | 6 +- testdata/p4_16_errors/issue2036-1.p4 | 12 +++ testdata/p4_16_errors/issue2036-2.p4 | 12 +++ testdata/p4_16_errors/issue2036.p4 | 29 ++++++ testdata/p4_16_errors_outputs/issue2036-1.p4 | 12 +++ .../issue2036-1.p4-stderr | 3 + testdata/p4_16_errors_outputs/issue2036-2.p4 | 12 +++ .../issue2036-2.p4-stderr | 3 + testdata/p4_16_errors_outputs/issue2036.p4 | 27 +++++ .../p4_16_errors_outputs/issue2036.p4-stderr | 3 + .../table-entries-exact.p4-stderr | 2 +- .../table-entries-lpm.p4-stderr | 2 +- .../table-entries-range.p4-stderr | 2 +- .../tuple-newtype.p4-stderr | 3 + .../tuple-to-header.p4-stderr | 8 +- testdata/p4_16_samples/issue2036-3.p4 | 11 +++ .../issue2036-3-first.p4 | 11 +++ .../issue2036-3-frontend.p4 | 4 + testdata/p4_16_samples_outputs/issue2036-3.p4 | 11 +++ .../issue2036-3.p4-stderr | 1 + 38 files changed, 321 insertions(+), 124 deletions(-) create mode 100644 testdata/p4_16_errors/issue2036-1.p4 create mode 100644 testdata/p4_16_errors/issue2036-2.p4 create mode 100644 testdata/p4_16_errors/issue2036.p4 create mode 100644 testdata/p4_16_errors_outputs/issue2036-1.p4 create mode 100644 testdata/p4_16_errors_outputs/issue2036-1.p4-stderr create mode 100644 testdata/p4_16_errors_outputs/issue2036-2.p4 create mode 100644 testdata/p4_16_errors_outputs/issue2036-2.p4-stderr create mode 100644 testdata/p4_16_errors_outputs/issue2036.p4 create mode 100644 testdata/p4_16_errors_outputs/issue2036.p4-stderr create mode 100644 testdata/p4_16_samples/issue2036-3.p4 create mode 100644 testdata/p4_16_samples_outputs/issue2036-3-first.p4 create mode 100644 testdata/p4_16_samples_outputs/issue2036-3-frontend.p4 create mode 100644 testdata/p4_16_samples_outputs/issue2036-3.p4 create mode 100644 testdata/p4_16_samples_outputs/issue2036-3.p4-stderr diff --git a/control-plane/p4RuntimeSerializer.cpp b/control-plane/p4RuntimeSerializer.cpp index 3c370a945dd..ad4def51c2b 100644 --- a/control-plane/p4RuntimeSerializer.cpp +++ b/control-plane/p4RuntimeSerializer.cpp @@ -1148,7 +1148,7 @@ class P4RuntimeAnalyzer { [](cstring name) { return name == IR::Annotation::matchAnnotation; }); addDocumentation(match, f); } - } else if (et->is()) { + } else if (et->is()) { ::error(ErrorType::ERR_UNSUPPORTED, "type parameter for Value Set; " "this version of P4Runtime requires the type parameter of a Value Set " diff --git a/control-plane/typeSpecConverter.cpp b/control-plane/typeSpecConverter.cpp index a4653f24fc4..e482bcfdd33 100644 --- a/control-plane/typeSpecConverter.cpp +++ b/control-plane/typeSpecConverter.cpp @@ -122,7 +122,7 @@ bool TypeSpecConverter::preorder(const IR::Type_Name* type) { bool TypeSpecConverter::preorder(const IR::Type_Newtype* type) { if (p4RtTypeInfo) { bool orig_type = true; - const IR::StringLiteral* uri; + const IR::StringLiteral* uri = nullptr; const IR::Constant* sdnB; auto ann = type->getAnnotation("p4runtime_translation"); if (ann != nullptr) { @@ -170,7 +170,7 @@ bool TypeSpecConverter::preorder(const IR::Type_Newtype* type) { return false; } -bool TypeSpecConverter::preorder(const IR::Type_Tuple* type) { +bool TypeSpecConverter::preorder(const IR::Type_BaseList* type) { auto typeSpec = new P4DataTypeSpec(); auto tupleTypeSpec = typeSpec->mutable_tuple(); for (auto cType : type->components) { diff --git a/control-plane/typeSpecConverter.h b/control-plane/typeSpecConverter.h index ce6b75b8c5f..95e9502d319 100644 --- a/control-plane/typeSpecConverter.h +++ b/control-plane/typeSpecConverter.h @@ -61,7 +61,7 @@ class TypeSpecConverter : public Inspector { bool preorder(const IR::Type_Bits* type) override; bool preorder(const IR::Type_Varbits* type) override; bool preorder(const IR::Type_Boolean* type) override; - bool preorder(const IR::Type_Tuple* type) override; + bool preorder(const IR::Type_BaseList* type) override; bool preorder(const IR::Type_Stack* type) override; bool preorder(const IR::Type_Name* type) override; diff --git a/frontends/p4/setHeaders.cpp b/frontends/p4/setHeaders.cpp index bd3c8275b2b..f2823696fd5 100644 --- a/frontends/p4/setHeaders.cpp +++ b/frontends/p4/setHeaders.cpp @@ -45,7 +45,7 @@ void DoSetHeaders::generateSetValid( // Recurse on fields of structType if (list != nullptr) { - auto tt = srcType->to(); + auto tt = srcType->to(); CHECK_NULL(tt); auto it = list->components.begin(); for (auto f : structType->fields) { diff --git a/frontends/p4/structInitializers.cpp b/frontends/p4/structInitializers.cpp index 9ad655333a9..52668f1c635 100644 --- a/frontends/p4/structInitializers.cpp +++ b/frontends/p4/structInitializers.cpp @@ -56,7 +56,7 @@ convert(const IR::Expression* expression, const IR::Type* type) { return result; } } - } else if (auto tup = type->to()) { + } else if (auto tup = type->to()) { auto le = expression->to(); if (le == nullptr) return expression; @@ -117,9 +117,9 @@ const IR::Node* CreateStructInitializers::postorder(IR::MethodCallExpression* ex const IR::Node* CreateStructInitializers::postorder(IR::Operation_Relation* expression) { auto ltype = typeMap->getType(expression->left); auto rtype = typeMap->getType(expression->right); - if (ltype->is() && rtype->is()) + if (ltype->is() && rtype->is()) expression->right = convert(expression->right, ltype); - if (rtype->is() && ltype->is()) + if (rtype->is() && ltype->is()) expression->left = convert(expression->left, rtype); return expression; } diff --git a/frontends/p4/toP4/toP4.cpp b/frontends/p4/toP4/toP4.cpp index af19ad27e3b..6d8f76220a1 100644 --- a/frontends/p4/toP4/toP4.cpp +++ b/frontends/p4/toP4/toP4.cpp @@ -289,7 +289,7 @@ bool ToP4::preorder(const IR::Type_Newtype* t) { return false; } -bool ToP4::preorder(const IR::Type_Tuple* t) { +bool ToP4::preorder(const IR::Type_BaseList* t) { dump(3); builder.append("tuple<"); bool first = true; diff --git a/frontends/p4/toP4/toP4.h b/frontends/p4/toP4/toP4.h index c86fd07520b..0e33949f21a 100644 --- a/frontends/p4/toP4/toP4.h +++ b/frontends/p4/toP4/toP4.h @@ -148,7 +148,7 @@ class ToP4 : public Inspector { bool preorder(const IR::Type_Newtype* t) override; bool preorder(const IR::Type_Extern* t) override; bool preorder(const IR::Type_Unknown* t) override; - bool preorder(const IR::Type_Tuple* t) override; + bool preorder(const IR::Type_BaseList* t) override; // declarations bool preorder(const IR::Declaration_Constant* cst) override; diff --git a/frontends/p4/typeChecking/typeChecker.cpp b/frontends/p4/typeChecking/typeChecker.cpp index c61e25925aa..284d339ceab 100644 --- a/frontends/p4/typeChecking/typeChecker.cpp +++ b/frontends/p4/typeChecking/typeChecker.cpp @@ -341,8 +341,7 @@ const IR::Type* TypeInference::canonicalize(const IR::Type* type) { type->is() || type->is()) { return type; - } else if (type->is()) { - auto set = type->to(); + } else if (auto set = type->to()) { auto et = canonicalize(set->elementType); if (et == nullptr) return nullptr; @@ -353,8 +352,7 @@ const IR::Type* TypeInference::canonicalize(const IR::Type* type) { return type; const IR::Type *canon = new IR::Type_Set(type->srcInfo, et); return canon; - } else if (type->is()) { - auto stack = type->to(); + } else if (auto stack = type->to()) { auto et = canonicalize(stack->elementType); if (et == nullptr) return nullptr; @@ -365,14 +363,13 @@ const IR::Type* TypeInference::canonicalize(const IR::Type* type) { canon = new IR::Type_Stack(stack->srcInfo, et, stack->size); canon = typeMap->getCanonical(canon); return canon; - } else if (type->is()) { - auto tuple = type->to(); + } else if (auto list = type->to()) { auto fields = new IR::Vector(); - // tuple, b> = set> + // list, b> = set> // TODO: this should not be done here. bool anySet = false; bool anyChange = false; - for (auto t : tuple->components) { + for (auto t : list->components) { if (t->is()) { anySet = true; t = t->to()->elementType; @@ -384,16 +381,34 @@ const IR::Type* TypeInference::canonicalize(const IR::Type* type) { fields->push_back(t1); } const IR::Type *canon; - if (anyChange || anySet) + if (anySet) canon = new IR::Type_Tuple(type->srcInfo, *fields); + else if (anyChange) + canon = new IR::Type_List(type->srcInfo, *fields); else canon = type; canon = typeMap->getCanonical(canon); if (anySet) canon = new IR::Type_Set(type->srcInfo, canon); return canon; - } else if (type->is()) { - auto tp = type->to(); + } else if (auto tuple = type->to()) { + auto fields = new IR::Vector(); + bool anyChange = false; + for (auto t : tuple->components) { + auto t1 = canonicalize(t); + anyChange = anyChange || t != t1; + if (t1 == nullptr) + return nullptr; + fields->push_back(t1); + } + const IR::Type *canon; + if (anyChange) + canon = new IR::Type_Tuple(type->srcInfo, *fields); + else + canon = type; + canon = typeMap->getCanonical(canon); + return canon; + } else if (auto tp = type->to()) { auto pl = canonicalizeParameters(tp->applyParams); auto tps = tp->typeParameters; if (pl == nullptr || tps == nullptr) @@ -403,8 +418,7 @@ const IR::Type* TypeInference::canonicalize(const IR::Type* type) { if (pl != tp->applyParams || tps != tp->typeParameters) return new IR::Type_Parser(tp->srcInfo, tp->name, tp->annotations, tps, pl); return type; - } else if (type->is()) { - auto tp = type->to(); + } else if (auto tp = type->to()) { auto pl = canonicalizeParameters(tp->applyParams); auto tps = tp->typeParameters; if (pl == nullptr || tps == nullptr) @@ -414,8 +428,7 @@ const IR::Type* TypeInference::canonicalize(const IR::Type* type) { if (pl != tp->applyParams || tps != tp->typeParameters) return new IR::Type_Control(tp->srcInfo, tp->name, tp->annotations, tps, pl); return type; - } else if (type->is()) { - auto tp = type->to(); + } else if (auto tp = type->to()) { auto pl = canonicalizeParameters(tp->constructorParams); auto tps = tp->typeParameters; if (pl == nullptr || tps == nullptr) @@ -423,8 +436,7 @@ const IR::Type* TypeInference::canonicalize(const IR::Type* type) { if (pl != tp->constructorParams || tps != tp->typeParameters) return new IR::Type_Package(tp->srcInfo, tp->name, tp->annotations, tps, pl); return type; - } else if (type->is()) { - auto cont = type->to(); + } else if (auto cont = type->to()) { auto ctype0 = getTypeType(cont->type); if (ctype0 == nullptr) return nullptr; @@ -436,8 +448,7 @@ const IR::Type* TypeInference::canonicalize(const IR::Type* type) { return new IR::P4Control(cont->srcInfo, cont->name, ctype, pl, cont->controlLocals, cont->body); return type; - } else if (type->is()) { - auto p = type->to(); + } else if (auto p = type->to()) { auto ctype0 = getTypeType(p->type); if (ctype0 == nullptr) return nullptr; @@ -449,8 +460,7 @@ const IR::Type* TypeInference::canonicalize(const IR::Type* type) { return new IR::P4Parser(p->srcInfo, p->name, ctype, pl, p->parserLocals, p->states); return type; - } else if (type->is()) { - auto te = type->to(); + } else if (auto te = type->to()) { bool changes = false; auto methods = new IR::Vector(); for (auto method : te->methods) { @@ -475,8 +485,7 @@ const IR::Type* TypeInference::canonicalize(const IR::Type* type) { if (changes || tps != te->typeParameters) resultType = new IR::Type_Extern(te->srcInfo, te->name, tps, *methods); return resultType; - } else if (type->is()) { - auto mt = type->to(); + } else if (auto mt = type->to()) { const IR::Type* res = nullptr; if (mt->returnType != nullptr) { res = canonicalize(mt->returnType); @@ -511,8 +520,7 @@ const IR::Type* TypeInference::canonicalize(const IR::Type* type) { return canonicalizeFields(su, [su](const IR::IndexedVector* fields) { return new IR::Type_UnknownStruct(su->srcInfo, su->name, su->annotations, *fields); }); - } else if (type->is()) { - auto st = type->to(); + } else if (auto st = type->to()) { auto baseCanon = canonicalize(st->baseType); if (baseCanon == nullptr) return nullptr; @@ -722,14 +730,6 @@ TypeInference::assignment(const IR::Node* errorPosition, const IR::Type* destTyp if (initType == destType) return sourceExpression; - // Unification allows tuples to be assigned to headers and structs. - // We should only allow this if the source expression is a ListExpression. - if (destType->is() && initType->is() && - !sourceExpression->is()) { - typeError("%1%: Cannot assign a %2% to a %3%", errorPosition, initType, destType); - return sourceExpression; - } - auto tvs = unify(errorPosition, destType, initType); if (tvs == nullptr) // error already signalled @@ -1215,6 +1215,11 @@ const IR::Node* TypeInference::postorder(IR::Type_Var* typeVar) { return typeVar; } +const IR::Node* TypeInference::postorder(IR::Type_List* type) { + (void)setTypeType(type); + return type; +} + const IR::Node* TypeInference::postorder(IR::Type_Tuple* type) { (void)setTypeType(type); return type; @@ -1517,7 +1522,7 @@ const IR::Node* TypeInference::postorder(IR::Operation_Relation* expression) { } else if (ltype->is() && rtype->is() && TypeMap::equivalent(ltype, rtype)) { defined = true; - } else if (ltype->is() && rtype->is()) { + } else if (ltype->is() && rtype->is()) { auto tvs = unify(expression, ltype, rtype); if (tvs == nullptr) // error already signalled @@ -1576,12 +1581,9 @@ const IR::Node* TypeInference::postorder(IR::Operation_Relation* expression) { defined = true; } - // comparison between structs and list expressions is allowed only - // if the expression with tuple type is a list expression - if ((ltype->is() && - rtype->is() && expression->right->is()) || - (ltype->is() && expression->left->is() - && rtype->is())) { + // comparison between structs and list expressions is allowed + if ((ltype->is() && rtype->is()) || + (ltype->is() && rtype->is())) { if (!ltype->is()) { // swap auto type = ltype; @@ -1742,7 +1744,7 @@ const IR::Node* TypeInference::postorder(IR::Entry* entry) { entryKeyType = entryKeyType->to()->elementType; auto keyset = entry->getKeys(); - if (keyset == nullptr || !keyset->is()) { + if (keyset == nullptr || !(keyset->is())) { typeError("%1%: key expression must be tuple", keyset); return entry; } else if (keyset->components.size() < key->keyElements.size()) { @@ -1797,7 +1799,7 @@ const IR::Node* TypeInference::postorder(IR::ListExpression* expression) { components->push_back(type); } - auto tupleType = new IR::Type_Tuple(expression->srcInfo, *components); + auto tupleType = new IR::Type_List(expression->srcInfo, *components); auto type = canonicalize(tupleType); if (type == nullptr) return expression; @@ -2873,8 +2875,8 @@ void TypeInference::checkEmitType(const IR::Expression* emit, const IR::Type* ty return; } - if (type->is()) { - for (auto f : type->to()->components) { + if (auto list = type->to()) { + for (auto f : list->components) { auto ftype = typeMap->getType(f); if (ftype == nullptr) continue; @@ -3163,7 +3165,7 @@ static void convertStructToTuple(const IR::Type_StructLike* structType, IR::Type } const IR::SelectCase* -TypeInference::matchCase(const IR::SelectExpression* select, const IR::Type_Tuple* selectType, +TypeInference::matchCase(const IR::SelectExpression* select, const IR::Type_BaseList* selectType, const IR::SelectCase* selectCase, const IR::Type* caseType) { // The selectType is always a tuple // If the caseType is a set type, we unify the type of the set elements @@ -3179,7 +3181,7 @@ TypeInference::matchCase(const IR::SelectExpression* select, const IR::Type_Tupl caseType = tupleType; } const IR::Type* useSelType = selectType; - if (!caseType->is()) { + if (!caseType->is()) { if (selectType->components.size() != 1) { typeError("Type mismatch %1% (%2%) vs %3% (%4%)", select->select, selectType->toString(), selectCase, caseType->toString()); @@ -3241,10 +3243,10 @@ const IR::Node* TypeInference::postorder(IR::SelectExpression* expression) { return expression; // Check that the selectType is determined - if (!selectType->is()) + if (!selectType->is()) BUG("%1%: Expected a tuple type for the select expression, got %2%", expression, selectType); - auto tuple = selectType->to(); + auto tuple = selectType->to(); for (auto ct : tuple->components) { if (ct->is()) { typeError("Cannot infer type for %1%", ct); diff --git a/frontends/p4/typeChecking/typeChecker.h b/frontends/p4/typeChecking/typeChecker.h index bb5d0e91178..5a42c4962f0 100644 --- a/frontends/p4/typeChecking/typeChecker.h +++ b/frontends/p4/typeChecking/typeChecker.h @@ -106,7 +106,7 @@ class TypeInference : public Transform { const IR::Expression* assignment(const IR::Node* errorPosition, const IR::Type* destType, const IR::Expression* sourceExpression); const IR::SelectCase* matchCase(const IR::SelectExpression* select, - const IR::Type_Tuple* selectType, + const IR::Type_BaseList* selectType, const IR::SelectCase* selectCase, const IR::Type* caseType); bool canCastBetween(const IR::Type* dest, const IR::Type* src) const; @@ -217,6 +217,7 @@ class TypeInference : public Transform { const IR::Node* postorder(IR::Type_Specialized* type) override; const IR::Node* postorder(IR::Type_SpecializedCanonical* type) override; const IR::Node* postorder(IR::Type_Tuple* type) override; + const IR::Node* postorder(IR::Type_List* type) override; const IR::Node* postorder(IR::Type_Set* type) override; const IR::Node* postorder(IR::Type_ArchBlock* type) override; const IR::Node* postorder(IR::Type_Newtype* type) override; diff --git a/frontends/p4/typeChecking/typeUnification.cpp b/frontends/p4/typeChecking/typeUnification.cpp index 50f325eb5e4..28bcfa9b7d1 100644 --- a/frontends/p4/typeChecking/typeUnification.cpp +++ b/frontends/p4/typeChecking/typeUnification.cpp @@ -292,21 +292,20 @@ bool TypeUnification::unify(const IR::Node* errorPosition, TypeInference::typeError("%1%: Cannot unify non-function type %2% to function type %3%", errorPosition, src->toString(), dest->toString()); return false; - } else if (dest->is()) { + } else if (auto td = dest->to()) { if (src->is() || src->is()) { // swap and try again: handled below return unify(errorPosition, src, dest, reportErrors); } - if (!src->is()) { + if (!src->is()) { if (reportErrors) - TypeInference::typeError("%1%: Cannot unify tuple type %2% with non tuple-type %3%", + TypeInference::typeError("%1%: Cannot unify type %2% with %3%", errorPosition, dest->toString(), src->toString()); return false; } - auto td = dest->to(); - auto ts = src->to(); + auto ts = src->to(); if (td->components.size() != ts->components.size()) { - TypeInference::typeError("%1%: Cannot match tuples with different sizes %2% vs %3%", + TypeInference::typeError("%1%: tuples with different sizes %2% vs %3%", errorPosition, td->components.size(), ts->components.size()); return false; } @@ -321,7 +320,7 @@ bool TypeUnification::unify(const IR::Node* errorPosition, return true; } else if (dest->is() || dest->is()) { auto strct = dest->to(); - if (auto tpl = src->to()) { + if (auto tpl = src->to()) { if (strct->fields.size() != tpl->components.size()) { if (reportErrors) TypeInference::typeError("%1%: Number of fields %2% in initializer different " diff --git a/frontends/p4/typeMap.cpp b/frontends/p4/typeMap.cpp index e55136aecbb..4d1ec2096e0 100644 --- a/frontends/p4/typeMap.cpp +++ b/frontends/p4/typeMap.cpp @@ -116,17 +116,15 @@ bool TypeMap::equivalent(const IR::Type* left, const IR::Type* right) { // Below we are sure that it's the same Node class if (left->is() || left->is()) return *left == *right; - if (left->is()) - return equivalent(left->to()->type, right->to()->type); + if (auto tt = left->to()) + return equivalent(tt->type, right->to()->type); if (left->is()) return true; - if (left->is()) { - auto lv = left->to(); + if (auto lv = left->to()) { auto rv = right->to(); return lv->getVarName() == rv->getVarName() && lv->getDeclId() == rv->getDeclId(); } - if (left->is()) { - auto ls = left->to(); + if (auto ls = left->to()) { auto rs = right->to(); if (!ls->sizeKnown()) { ::error(ErrorType::ERR_TYPE_ERROR, @@ -149,8 +147,7 @@ bool TypeMap::equivalent(const IR::Type* left, const IR::Type* right) { auto re = right->to(); return le->name == re->name; } - if (left->is()) { - auto sl = left->to(); + if (auto sl = left->to()) { auto sr = right->to(); if (sl->fields.size() != sr->fields.size()) return false; @@ -164,8 +161,7 @@ bool TypeMap::equivalent(const IR::Type* left, const IR::Type* right) { } return true; } - if (left->is()) { - auto lt = left->to(); + if (auto lt = left->to()) { auto rt = right->to(); if (lt->components.size() != rt->components.size()) return false; @@ -177,13 +173,23 @@ bool TypeMap::equivalent(const IR::Type* left, const IR::Type* right) { } return true; } - if (left->is()) { - auto lt = left->to(); + if (auto lt = left->to()) { + auto rt = right->to(); + if (lt->components.size() != rt->components.size()) + return false; + for (size_t i = 0; i < lt->components.size(); i++) { + auto l = lt->components.at(i); + auto r = rt->components.at(i); + if (!equivalent(l, r)) + return false; + } + return true; + } + if (auto lt = left->to()) { auto rt = right->to(); return equivalent(lt->elementType, rt->elementType); } - if (left->is()) { - auto lp = left->to(); + if (auto lp = left->to()) { auto rp = right->to(); // The following gets into an infinite loop, since the return type of the // constructor is the Type_Package itself. @@ -212,17 +218,15 @@ bool TypeMap::equivalent(const IR::Type* left, const IR::Type* right) { } return true; } - if (left->is()) { - return equivalent(left->to()->getApplyMethodType(), + if (auto a = left->to()) { + return equivalent(a->getApplyMethodType(), right->to()->getApplyMethodType()); } - if (left->is()) { - auto ls = left->to(); + if (auto ls = left->to()) { auto rs = right->to(); return equivalent(ls->substituted, rs->substituted); } - if (left->is()) { - auto la = left->to(); + if (auto la = left->to()) { auto ra = right->to(); return la->actionList == ra->actionList; // pointer comparison } @@ -251,8 +255,7 @@ bool TypeMap::equivalent(const IR::Type* left, const IR::Type* right) { } return true; } - if (left->is()) { - auto le = left->to(); + if (auto le = left->to()) { auto re = right->to(); return le->name == re->name; } @@ -268,11 +271,9 @@ bool TypeMap::implicitlyConvertibleTo(const IR::Type* from, const IR::Type* to) if (from->is() && to->is()) // this case is not caught by the equivalence check return true; - // We allow implicit casts from tuples to structs - if (from->is()) { - if (to->is()) { - auto sl = from->to(); - auto rt = to->to(); + if (auto rt = to->to()) { + if (auto sl = from->to()) { + // We allow implicit casts from list types to structs if (sl->fields.size() != rt->components.size()) return false; for (size_t i = 0; i < rt->components.size(); i++) { @@ -282,12 +283,23 @@ bool TypeMap::implicitlyConvertibleTo(const IR::Type* from, const IR::Type* to) return false; } return true; + } else if (auto sl = from->to()) { + // We allow implicit casts from list types to tuples + if (sl->components.size() != rt->components.size()) + return false; + for (size_t i = 0; i < rt->components.size(); i++) { + auto f = sl->components.at(i); + auto r = rt->components.at(i); + if (!TypeMap::implicitlyConvertibleTo(f, r)) + return false; + } + return true; } } return false; } -// Used for tuples and stacks only +// Used for tuples, stacks and lists only const IR::Type* TypeMap::getCanonical(const IR::Type* type) { // Currently a linear search; hopefully this won't be too expensive in practice std::vector* searchIn; @@ -295,6 +307,8 @@ const IR::Type* TypeMap::getCanonical(const IR::Type* type) { searchIn = &canonicalStacks; else if (type->is()) searchIn = &canonicalTuples; + else if (type->is()) + searchIn = &canonicalLists; else BUG("%1%: unexpected type", type); diff --git a/frontends/p4/typeMap.h b/frontends/p4/typeMap.h index e901efecda9..39df46c7e2e 100644 --- a/frontends/p4/typeMap.h +++ b/frontends/p4/typeMap.h @@ -40,9 +40,10 @@ Objects that have a type in the map: class TypeMap final : public ProgramMap { protected: // We want to have the same canonical type for two - // different tuples or stacks with the same signature. + // different tuples, lists, or stacks with the same signature. std::vector canonicalTuples; std::vector canonicalStacks; + std::vector canonicalLists; // Map each node to its canonical type std::map typeMap; diff --git a/ir/dbprint-type.cpp b/ir/dbprint-type.cpp index e7b7a87d72a..3d3f1e1d704 100644 --- a/ir/dbprint-type.cpp +++ b/ir/dbprint-type.cpp @@ -106,6 +106,17 @@ void IR::Type_Tuple::dbprint(std::ostream& out) const { dbsetflags(out, flags); } +void IR::Type_List::dbprint(std::ostream& out) const { + int flags = dbgetflags(out); + out << Brief << "list<"; + const char *sep = ""; + for (auto t : components) { + out << sep << t; + sep = ", "; } + out << ">"; + dbsetflags(out, flags); +} + void IR::Type_Extern::dbprint(std::ostream& out) const { if (dbgetflags(out) & Brief) { out << name; diff --git a/ir/expression.def b/ir/expression.def index 81ab381b1db..b8be0a400df 100644 --- a/ir/expression.def +++ b/ir/expression.def @@ -391,7 +391,7 @@ class ListExpression : Expression { Vector tuple; for (auto e : components) tuple.push_back(e->type); - type = new Type_Tuple(tuple); } } + type = new Type_List(tuple); } } validate { components.check_null(); } size_t size() const { return components.size(); } void push_back(Expression e) { components.push_back(e); } diff --git a/ir/type.cpp b/ir/type.cpp index 709c6d2cd9c..41c63b87a55 100644 --- a/ir/type.cpp +++ b/ir/type.cpp @@ -145,6 +145,16 @@ size_t Type_MethodBase::minParameterCount() const { return rv; } +const Type* Type_List::getP4Type() const { + auto args = new IR::Vector(); + for (auto a : components) { + auto at = a->getP4Type(); + if (!at) return nullptr; + args->push_back(at); + } + return new IR::Type_List(srcInfo, *args); +} + const Type* Type_Tuple::getP4Type() const { auto args = new IR::Vector(); for (auto a : components) { diff --git a/ir/type.def b/ir/type.def index 1f9b0f7e58d..3a7c2171ab3 100644 --- a/ir/type.def +++ b/ir/type.def @@ -288,15 +288,13 @@ class Type_Set : Type { return elementType->width_bits(); } } -/// The type of an expressionList -class Type_Tuple : Type { +/// Base class for Type_List and Type_Tuple +abstract Type_BaseList : Type { optional inline Vector components; - toString{ return "Tuple(" + Util::toString(components.size()) + ")"; } validate{ components.check_null(); } - const Type* getP4Type() const override; size_t size() const { return components.size(); } int width_bits() const override { - /// returning sum of the width of the tuple elements + /// returning sum of the width of the elements int rv = 0; for (auto f : components) { rv += f->width_bits(); @@ -304,6 +302,19 @@ class Type_Tuple : Type { return rv; } } +/// The type of an expressionList; can be unified with both Type_Tuple and Type_Struct +class Type_List : Type_BaseList { + // In error messages this is shown as if it is a Tuple + toString{ return "Tuple(" + Util::toString(components.size()) + ")"; } + const Type* getP4Type() const override; +} + +/// The type of a tuple. +class Type_Tuple : Type_BaseList { + toString{ return "Tuple(" + Util::toString(components.size()) + ")"; } + const Type* getP4Type() const override; +} + /// The type of an architectural block. /// Abstract base for Type_Control, Type_Parser and Type_Package abstract Type_ArchBlock : Type_Declaration, IMayBeGenericType, IAnnotated { diff --git a/midend/complexComparison.cpp b/midend/complexComparison.cpp index fcf5651ed75..d48e55021a6 100644 --- a/midend/complexComparison.cpp +++ b/midend/complexComparison.cpp @@ -25,7 +25,7 @@ const IR::Expression* RemoveComplexComparisons::explode( // we allow several cases // header == header - // header == list (tuple) + // header == list // list == header // list == list // struct == struct @@ -33,8 +33,8 @@ const IR::Expression* RemoveComplexComparisons::explode( // struct == list // list == struct - auto rightTuple = rightType->to(); - auto leftTuple = leftType->to(); + auto rightTuple = rightType->to(); + auto leftTuple = leftType->to(); if (leftTuple && !rightTuple) // put the tuple on the right if it is the only one, // so we handle fewer cases @@ -155,7 +155,7 @@ const IR::Node* RemoveComplexComparisons::postorder(IR::Operation_Binary* expres auto ltype = typeMap->getType(expression->left, true); auto rtype = typeMap->getType(expression->right, true); if (!ltype->is() && !ltype->is() && - !ltype->is()) + !ltype->is()) return expression; auto result = explode(expression->srcInfo, ltype, expression->left, rtype, expression->right); if (expression->is()) diff --git a/midend/eliminateTuples.cpp b/midend/eliminateTuples.cpp index dff9d1ad648..c7889ceff66 100644 --- a/midend/eliminateTuples.cpp +++ b/midend/eliminateTuples.cpp @@ -26,10 +26,10 @@ const IR::Type* ReplacementMap::convertType(const IR::Type* type) { } else { return type; } - } else if (type->is()) { + } else if (type->is()) { cstring name = ng->newName("tuple"); IR::IndexedVector fields; - for (auto t : type->to()->components) { + for (auto t : type->to()->components) { auto ftype = convertType(t); auto fname = ng->newName("field"); auto field = new IR::StructField(IR::ID(fname), ftype->getP4Type()); @@ -43,7 +43,7 @@ const IR::Type* ReplacementMap::convertType(const IR::Type* type) { return type; } -const IR::Type_Struct* ReplacementMap::getReplacement(const IR::Type_Tuple* tt) { +const IR::Type_Struct* ReplacementMap::getReplacement(const IR::Type_BaseList* tt) { auto st = convertType(tt)->to(); CHECK_NULL(st); replacement.emplace(tt, st); @@ -63,9 +63,9 @@ IR::IndexedVector* ReplacementMap::getNewReplacements() { return retval; } -const IR::Node* DoReplaceTuples::postorder(IR::Type_Tuple*) { - auto type = getOriginal(); - auto canon = repl->typeMap->getTypeType(type, true)->to(); +const IR::Node* DoReplaceTuples::postorder(IR::Type_BaseList*) { + auto type = getOriginal(); + auto canon = repl->typeMap->getTypeType(type, true)->to(); auto st = repl->getReplacement(canon)->getP4Type(); return st; } diff --git a/midend/eliminateTuples.h b/midend/eliminateTuples.h index c0bc9c4f019..f8b36917ef5 100644 --- a/midend/eliminateTuples.h +++ b/midend/eliminateTuples.h @@ -24,7 +24,7 @@ limitations under the License. namespace P4 { /** - * Maintains for each type that may contain a tuple (or be a tuple) the + * Maintains for each type that may contain a tuple (or is a tuple) the * corresponding struct replacement. */ class ReplacementMap { @@ -37,7 +37,7 @@ class ReplacementMap { ReplacementMap(NameGenerator* ng, TypeMap* typeMap) : ng(ng), typeMap(typeMap) { CHECK_NULL(ng); CHECK_NULL(typeMap); } - const IR::Type_Struct* getReplacement(const IR::Type_Tuple* tt); + const IR::Type_Struct* getReplacement(const IR::Type_BaseList* tt); IR::IndexedVector* getNewReplacements(); }; @@ -69,7 +69,7 @@ class DoReplaceTuples final : public Transform { public: explicit DoReplaceTuples(ReplacementMap* replMap) : repl(replMap) { CHECK_NULL(repl); setName("DoReplaceTuples"); } - const IR::Node* postorder(IR::Type_Tuple* type) override; + const IR::Node* postorder(IR::Type_BaseList* type) override; const IR::Node* insertReplacements(const IR::Node* before); const IR::Node* postorder(IR::Type_Struct* type) override { return insertReplacements(type); } diff --git a/testdata/p4_16_errors/issue2036-1.p4 b/testdata/p4_16_errors/issue2036-1.p4 new file mode 100644 index 00000000000..ac566bc13a7 --- /dev/null +++ b/testdata/p4_16_errors/issue2036-1.p4 @@ -0,0 +1,12 @@ +struct s { + bit<8> x; +} + +extern void f(in s sarg); + +control c() { + apply { + tuple> b = { 0 }; + f(b); + } +} diff --git a/testdata/p4_16_errors/issue2036-2.p4 b/testdata/p4_16_errors/issue2036-2.p4 new file mode 100644 index 00000000000..98a1d9fb7c9 --- /dev/null +++ b/testdata/p4_16_errors/issue2036-2.p4 @@ -0,0 +1,12 @@ +struct s { + bit<8> x; +} + +extern void f(out s sarg); + +control c() { + apply { + tuple> b = { 0 }; + f(b); + } +} diff --git a/testdata/p4_16_errors/issue2036.p4 b/testdata/p4_16_errors/issue2036.p4 new file mode 100644 index 00000000000..6e7f573c9aa --- /dev/null +++ b/testdata/p4_16_errors/issue2036.p4 @@ -0,0 +1,29 @@ +#include + +//Architecture +parser C(); +package S(C p); + +//User Program +struct s { + bit<8> x; +} + +parser D(in s z) { + state start { + transition accept; + } +} + +parser E() { + tuple> a = { 0 }; + s b = { 1 }; + D() d; + state start { + d.apply(a); + d.apply(b); + transition accept; + } +} + +S(E()) main; diff --git a/testdata/p4_16_errors_outputs/issue2036-1.p4 b/testdata/p4_16_errors_outputs/issue2036-1.p4 new file mode 100644 index 00000000000..84c3a726177 --- /dev/null +++ b/testdata/p4_16_errors_outputs/issue2036-1.p4 @@ -0,0 +1,12 @@ +struct s { + bit<8> x; +} + +extern void f(in s sarg); +control c() { + apply { + tuple> b = { 0 }; + f(b); + } +} + diff --git a/testdata/p4_16_errors_outputs/issue2036-1.p4-stderr b/testdata/p4_16_errors_outputs/issue2036-1.p4-stderr new file mode 100644 index 00000000000..dfae200d2ba --- /dev/null +++ b/testdata/p4_16_errors_outputs/issue2036-1.p4-stderr @@ -0,0 +1,3 @@ +issue2036-1.p4(10): [--Werror=type-error] error: f: Cannot unify Tuple(1) to struct s + f(b); + ^^^^ diff --git a/testdata/p4_16_errors_outputs/issue2036-2.p4 b/testdata/p4_16_errors_outputs/issue2036-2.p4 new file mode 100644 index 00000000000..8242bf121ae --- /dev/null +++ b/testdata/p4_16_errors_outputs/issue2036-2.p4 @@ -0,0 +1,12 @@ +struct s { + bit<8> x; +} + +extern void f(out s sarg); +control c() { + apply { + tuple> b = { 0 }; + f(b); + } +} + diff --git a/testdata/p4_16_errors_outputs/issue2036-2.p4-stderr b/testdata/p4_16_errors_outputs/issue2036-2.p4-stderr new file mode 100644 index 00000000000..4a482be77d2 --- /dev/null +++ b/testdata/p4_16_errors_outputs/issue2036-2.p4-stderr @@ -0,0 +1,3 @@ +issue2036-2.p4(10): [--Werror=type-error] error: f: Cannot unify Tuple(1) to struct s + f(b); + ^^^^ diff --git a/testdata/p4_16_errors_outputs/issue2036.p4 b/testdata/p4_16_errors_outputs/issue2036.p4 new file mode 100644 index 00000000000..ff9586a71f1 --- /dev/null +++ b/testdata/p4_16_errors_outputs/issue2036.p4 @@ -0,0 +1,27 @@ +#include + +parser C(); +package S(C p); +struct s { + bit<8> x; +} + +parser D(in s z) { + state start { + transition accept; + } +} + +parser E() { + tuple> a = { 0 }; + s b = { 1 }; + D() d; + state start { + d.apply(a); + d.apply(b); + transition accept; + } +} + +S(E()) main; + diff --git a/testdata/p4_16_errors_outputs/issue2036.p4-stderr b/testdata/p4_16_errors_outputs/issue2036.p4-stderr new file mode 100644 index 00000000000..3de43782c75 --- /dev/null +++ b/testdata/p4_16_errors_outputs/issue2036.p4-stderr @@ -0,0 +1,3 @@ +issue2036.p4(23): [--Werror=type-error] error: d.apply: Cannot unify Tuple(1) to struct s + d.apply(a); + ^^^^^^^^^^ diff --git a/testdata/p4_16_errors_outputs/table-entries-exact.p4-stderr b/testdata/p4_16_errors_outputs/table-entries-exact.p4-stderr index ab1298327c5..a0bf081e432 100644 --- a/testdata/p4_16_errors_outputs/table-entries-exact.p4-stderr +++ b/testdata/p4_16_errors_outputs/table-entries-exact.p4-stderr @@ -1,3 +1,3 @@ -table-entries-exact.p4(72): [--Werror=type-error] error: Entry: Cannot match tuples with different sizes 1 vs 2 +table-entries-exact.p4(72): [--Werror=type-error] error: Entry: tuples with different sizes 1 vs 2 (0x1111 &&& 0xF, 0x1 ) : a(); // invalid exact key ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/testdata/p4_16_errors_outputs/table-entries-lpm.p4-stderr b/testdata/p4_16_errors_outputs/table-entries-lpm.p4-stderr index 003c7a54a30..3506e07678f 100644 --- a/testdata/p4_16_errors_outputs/table-entries-lpm.p4-stderr +++ b/testdata/p4_16_errors_outputs/table-entries-lpm.p4-stderr @@ -1,3 +1,3 @@ -table-entries-lpm.p4(72): [--Werror=type-error] error: Entry: Cannot match tuples with different sizes 1 vs 2 +table-entries-lpm.p4(72): [--Werror=type-error] error: Entry: tuples with different sizes 1 vs 2 (0x1, 0x11 &&& 0xF0): a(); // invalid keyset ^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/testdata/p4_16_errors_outputs/table-entries-range.p4-stderr b/testdata/p4_16_errors_outputs/table-entries-range.p4-stderr index b1ec080fa60..0eea88a518f 100644 --- a/testdata/p4_16_errors_outputs/table-entries-range.p4-stderr +++ b/testdata/p4_16_errors_outputs/table-entries-range.p4-stderr @@ -1,3 +1,3 @@ -table-entries-range.p4(71): [--Werror=type-error] error: Entry: Cannot match tuples with different sizes 1 vs 2 +table-entries-range.p4(71): [--Werror=type-error] error: Entry: tuples with different sizes 1 vs 2 (0x18, 0xF) : a_with_control_params(24); // not a range ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/testdata/p4_16_errors_outputs/tuple-newtype.p4-stderr b/testdata/p4_16_errors_outputs/tuple-newtype.p4-stderr index 31f20609626..9e2a79c296f 100644 --- a/testdata/p4_16_errors_outputs/tuple-newtype.p4-stderr +++ b/testdata/p4_16_errors_outputs/tuple-newtype.p4-stderr @@ -1,3 +1,6 @@ tuple-newtype.p4(5): error: T: `type' can only be applied to base types type tuple T; ^ +tuple-newtype.p4(12): [--Werror=type-error] error: cast: Illegal cast from Tuple(1) to T + T tt2 = (T){1w0}; + ^^^^^^^^ diff --git a/testdata/p4_16_errors_outputs/tuple-to-header.p4-stderr b/testdata/p4_16_errors_outputs/tuple-to-header.p4-stderr index 514006007e2..268c9cdd1eb 100644 --- a/testdata/p4_16_errors_outputs/tuple-to-header.p4-stderr +++ b/testdata/p4_16_errors_outputs/tuple-to-header.p4-stderr @@ -1,9 +1,3 @@ -tuple-to-header.p4(23): [--Werror=type-error] error: AssignmentStatement: Cannot assign a Tuple(1) to a header H +tuple-to-header.p4(23): [--Werror=type-error] error: AssignmentStatement: Cannot unify Tuple(1) to header H h = t; // illegal assignment between tuple and header ^ -tuple-to-header.p4(20) - tuple> t = { 0 }; - ^^^^^^^^^^^^^^ -tuple-to-header.p4(17) -header H { bit<32> x; } - ^ diff --git a/testdata/p4_16_samples/issue2036-3.p4 b/testdata/p4_16_samples/issue2036-3.p4 new file mode 100644 index 00000000000..eb19557268c --- /dev/null +++ b/testdata/p4_16_samples/issue2036-3.p4 @@ -0,0 +1,11 @@ +struct s { + bit<8> x; +} + +extern void f(in tuple> a, in s sarg); + +control c() { + apply { + f({0}, {0}); + } +} diff --git a/testdata/p4_16_samples_outputs/issue2036-3-first.p4 b/testdata/p4_16_samples_outputs/issue2036-3-first.p4 new file mode 100644 index 00000000000..bdba1466608 --- /dev/null +++ b/testdata/p4_16_samples_outputs/issue2036-3-first.p4 @@ -0,0 +1,11 @@ +struct s { + bit<8> x; +} + +extern void f(in tuple> a, in s sarg); +control c() { + apply { + f({ 8w0 }, s {x = 8w0}); + } +} + diff --git a/testdata/p4_16_samples_outputs/issue2036-3-frontend.p4 b/testdata/p4_16_samples_outputs/issue2036-3-frontend.p4 new file mode 100644 index 00000000000..474762c01be --- /dev/null +++ b/testdata/p4_16_samples_outputs/issue2036-3-frontend.p4 @@ -0,0 +1,4 @@ +struct s { + bit<8> x; +} + diff --git a/testdata/p4_16_samples_outputs/issue2036-3.p4 b/testdata/p4_16_samples_outputs/issue2036-3.p4 new file mode 100644 index 00000000000..e1acd1d3161 --- /dev/null +++ b/testdata/p4_16_samples_outputs/issue2036-3.p4 @@ -0,0 +1,11 @@ +struct s { + bit<8> x; +} + +extern void f(in tuple> a, in s sarg); +control c() { + apply { + f({ 0 }, { 0 }); + } +} + diff --git a/testdata/p4_16_samples_outputs/issue2036-3.p4-stderr b/testdata/p4_16_samples_outputs/issue2036-3.p4-stderr new file mode 100644 index 00000000000..7f94c95a8ff --- /dev/null +++ b/testdata/p4_16_samples_outputs/issue2036-3.p4-stderr @@ -0,0 +1 @@ +warning: Program does not contain a `main' module From 81802beec79f946f5a08bf340d0d7a2473d83aa8 Mon Sep 17 00:00:00 2001 From: marko-stanoj Date: Fri, 6 Dec 2019 18:20:57 +0100 Subject: [PATCH 041/106] Order of src and dst template function arguments fix (#2106) Fixing order of arguments allows removing of unnecessary destination and source argument swapping if dst is base list type and src is struct like type. Select-struct.p4 test is changed to be in conformance with specification. --- frontends/p4/typeChecking/typeUnification.cpp | 10 +++++----- testdata/p4_16_samples/select-struct.p4 | 4 +--- testdata/p4_16_samples_outputs/select-struct-first.p4 | 4 +--- .../p4_16_samples_outputs/select-struct-frontend.p4 | 6 +----- testdata/p4_16_samples_outputs/select-struct-midend.p4 | 6 ------ testdata/p4_16_samples_outputs/select-struct.p4 | 4 +--- 6 files changed, 9 insertions(+), 25 deletions(-) diff --git a/frontends/p4/typeChecking/typeUnification.cpp b/frontends/p4/typeChecking/typeUnification.cpp index 28bcfa9b7d1..2bc3fe20d41 100644 --- a/frontends/p4/typeChecking/typeUnification.cpp +++ b/frontends/p4/typeChecking/typeUnification.cpp @@ -21,6 +21,7 @@ limitations under the License. namespace P4 { + /// Unifies a call with a prototype. bool TypeUnification::unifyCall(const IR::Node* errorPosition, const IR::Type_MethodBase* dest, @@ -53,7 +54,10 @@ bool TypeUnification::unifyCall(const IR::Node* errorPosition, size_t i = 0; for (auto tv : dest->typeParameters->parameters) { auto type = src->typeArguments->at(i++); - constraints->addEqualityConstraint(tv, type); + // variable type represents type of formal method argument + // written beetween angle brackets, and tv should be replaced + // with type of an actual argument + constraints->addEqualityConstraint(type /*dst */, tv /* src */); } } @@ -293,10 +297,6 @@ bool TypeUnification::unify(const IR::Node* errorPosition, errorPosition, src->toString(), dest->toString()); return false; } else if (auto td = dest->to()) { - if (src->is() || src->is()) { - // swap and try again: handled below - return unify(errorPosition, src, dest, reportErrors); - } if (!src->is()) { if (reportErrors) TypeInference::typeError("%1%: Cannot unify type %2% with %3%", diff --git a/testdata/p4_16_samples/select-struct.p4 b/testdata/p4_16_samples/select-struct.p4 index e9713328fbd..ca56bb746e6 100644 --- a/testdata/p4_16_samples/select-struct.p4 +++ b/testdata/p4_16_samples/select-struct.p4 @@ -25,13 +25,11 @@ parser p() { state start { bit<8> x = 5; S s = { 0, 0 }; - tuple, bit<8>> t = { 0, 0 }; transition select(x, x, {x, x}, x) { (0, 0, {0, 0}, 0): accept; (1, 1, default, 1): accept; - (1, 1, s, 2): accept; - (1, 1, t, 2): accept; + (1, 1, {s.f0, s.f1}, 2): accept; default: reject; } } diff --git a/testdata/p4_16_samples_outputs/select-struct-first.p4 b/testdata/p4_16_samples_outputs/select-struct-first.p4 index d0e5752b31c..7ea082eae42 100644 --- a/testdata/p4_16_samples_outputs/select-struct-first.p4 +++ b/testdata/p4_16_samples_outputs/select-struct-first.p4 @@ -9,12 +9,10 @@ parser p() { state start { bit<8> x = 8w5; S s = { 8w0, 8w0 }; - tuple, bit<8>> t = { 8w0, 8w0 }; transition select(x, x, { x, x }, x) { (8w0, 8w0, { 8w0, 8w0 }, 8w0): accept; (8w1, 8w1, default, 8w1): accept; - (8w1, 8w1, s, 8w2): accept; - (8w1, 8w1, t, 8w2): accept; + (8w1, 8w1, { s.f0, s.f1 }, 8w2): accept; default: reject; } } diff --git a/testdata/p4_16_samples_outputs/select-struct-frontend.p4 b/testdata/p4_16_samples_outputs/select-struct-frontend.p4 index 42531ed8d81..46cad875b36 100644 --- a/testdata/p4_16_samples_outputs/select-struct-frontend.p4 +++ b/testdata/p4_16_samples_outputs/select-struct-frontend.p4 @@ -8,16 +8,13 @@ struct S { parser p() { bit<8> x_0; S s_0; - tuple, bit<8>> t_0; state start { x_0 = 8w5; s_0 = { 8w0, 8w0 }; - t_0 = { 8w0, 8w0 }; transition select(x_0, x_0, { x_0, x_0 }, x_0) { (8w0, 8w0, { 8w0, 8w0 }, 8w0): accept; (8w1, 8w1, default, 8w1): accept; - (8w1, 8w1, s_0, 8w2): accept; - (8w1, 8w1, t_0, 8w2): accept; + (8w1, 8w1, { s_0.f0, s_0.f1 }, 8w2): accept; default: reject; } } @@ -26,4 +23,3 @@ parser p() { parser s(); package top(s _s); top(p()) main; - diff --git a/testdata/p4_16_samples_outputs/select-struct-midend.p4 b/testdata/p4_16_samples_outputs/select-struct-midend.p4 index 533b79c52f2..5b7174a5c53 100644 --- a/testdata/p4_16_samples_outputs/select-struct-midend.p4 +++ b/testdata/p4_16_samples_outputs/select-struct-midend.p4 @@ -5,11 +5,6 @@ struct S { bit<8> f1; } -struct tuple_0 { - bit<8> field; - bit<8> field_0; -} - parser p() { state start { transition reject; @@ -19,4 +14,3 @@ parser p() { parser s(); package top(s _s); top(p()) main; - diff --git a/testdata/p4_16_samples_outputs/select-struct.p4 b/testdata/p4_16_samples_outputs/select-struct.p4 index 5c07b1af832..44eb5c4978b 100644 --- a/testdata/p4_16_samples_outputs/select-struct.p4 +++ b/testdata/p4_16_samples_outputs/select-struct.p4 @@ -9,12 +9,10 @@ parser p() { state start { bit<8> x = 5; S s = { 0, 0 }; - tuple, bit<8>> t = { 0, 0 }; transition select(x, x, { x, x }, x) { (0, 0, { 0, 0 }, 0): accept; (1, 1, default, 1): accept; - (1, 1, s, 2): accept; - (1, 1, t, 2): accept; + (1, 1, { s.f0, s.f1 }, 2): accept; default: reject; } } From 84907cfc795b36d4a9e8615f4bf22899fe0017ad Mon Sep 17 00:00:00 2001 From: Chris Dodd Date: Fri, 6 Dec 2019 15:14:46 -0800 Subject: [PATCH 042/106] Treat P4_14 default_action with () args as const (#2084) - match obscure behavior of old p4-hlir code --- frontends/parsers/v1/v1parser.ypp | 1 + testdata/p4_14_samples_outputs/name_collision-first.p4 | 2 +- testdata/p4_14_samples_outputs/name_collision-frontend.p4 | 2 +- testdata/p4_14_samples_outputs/name_collision-midend.p4 | 2 +- testdata/p4_14_samples_outputs/name_collision.p4 | 2 +- testdata/p4_14_samples_outputs/simple_router-first.p4 | 4 ++-- testdata/p4_14_samples_outputs/simple_router-frontend.p4 | 4 ++-- testdata/p4_14_samples_outputs/simple_router-midend.p4 | 4 ++-- testdata/p4_14_samples_outputs/simple_router.p4 | 4 ++-- 9 files changed, 13 insertions(+), 12 deletions(-) diff --git a/frontends/parsers/v1/v1parser.ypp b/frontends/parsers/v1/v1parser.ypp index 57cad69395a..2c6010ce075 100644 --- a/frontends/parsers/v1/v1parser.ypp +++ b/frontends/parsers/v1/v1parser.ypp @@ -760,6 +760,7 @@ table_body: /* epsilon */ { ($$=$1)->default_action = IR::ID(@4, $4); } | table_body DEFAULT_ACTION ":" name "(" opt_expression_list ")" ";" { ($$=$1)->default_action = IR::ID(@4, $4); + if ($6 == nullptr) $$->default_action_is_const = true; $$->default_action_args = $6; } | table_body CONST DEFAULT_ACTION ":" name ";" { ($$=$1)->default_action = IR::ID(@5, $5); diff --git a/testdata/p4_14_samples_outputs/name_collision-first.p4 b/testdata/p4_14_samples_outputs/name_collision-first.p4 index ce630de77fd..bc0fd143dc9 100644 --- a/testdata/p4_14_samples_outputs/name_collision-first.p4 +++ b/testdata/p4_14_samples_outputs/name_collision-first.p4 @@ -62,7 +62,7 @@ control ingress(inout headers hdr, inout metadata meta, inout standard_metadata_ actions = { B_2(); } - default_action = B_2(); + const default_action = B_2(); } apply { A_4.apply(); diff --git a/testdata/p4_14_samples_outputs/name_collision-frontend.p4 b/testdata/p4_14_samples_outputs/name_collision-frontend.p4 index 2af6fa25fa5..842838aa825 100644 --- a/testdata/p4_14_samples_outputs/name_collision-frontend.p4 +++ b/testdata/p4_14_samples_outputs/name_collision-frontend.p4 @@ -64,7 +64,7 @@ control ingress(inout headers hdr, inout metadata meta, inout standard_metadata_ actions = { B_2(); } - default_action = B_2(); + const default_action = B_2(); } apply { A_3.apply(); diff --git a/testdata/p4_14_samples_outputs/name_collision-midend.p4 b/testdata/p4_14_samples_outputs/name_collision-midend.p4 index 18185400f89..e5d9a1c84ce 100644 --- a/testdata/p4_14_samples_outputs/name_collision-midend.p4 +++ b/testdata/p4_14_samples_outputs/name_collision-midend.p4 @@ -64,7 +64,7 @@ control ingress(inout headers hdr, inout metadata meta, inout standard_metadata_ actions = { B_2(); } - default_action = B_2(); + const default_action = B_2(); } apply { A_3.apply(); diff --git a/testdata/p4_14_samples_outputs/name_collision.p4 b/testdata/p4_14_samples_outputs/name_collision.p4 index 588e969ed64..81e3f8e4c55 100644 --- a/testdata/p4_14_samples_outputs/name_collision.p4 +++ b/testdata/p4_14_samples_outputs/name_collision.p4 @@ -60,7 +60,7 @@ control ingress(inout headers hdr, inout metadata meta, inout standard_metadata_ actions = { B_2; } - default_action = B_2(); + const default_action = B_2(); } apply { A_4.apply(); diff --git a/testdata/p4_14_samples_outputs/simple_router-first.p4 b/testdata/p4_14_samples_outputs/simple_router-first.p4 index e2ae9f316ef..a4f0206e730 100644 --- a/testdata/p4_14_samples_outputs/simple_router-first.p4 +++ b/testdata/p4_14_samples_outputs/simple_router-first.p4 @@ -98,7 +98,7 @@ control ingress(inout headers hdr, inout metadata meta, inout standard_metadata_ key = { } size = 1; - default_action = _drop(); + const default_action = _drop(); } @name(".forward") table forward { actions = { @@ -121,7 +121,7 @@ control ingress(inout headers hdr, inout metadata meta, inout standard_metadata_ hdr.ipv4.dstAddr: lpm @name("ipv4.dstAddr") ; } size = 1024; - default_action = _drop(); + const default_action = _drop(); } apply { if (hdr.ipv4.isValid() && hdr.ipv4.ttl > 8w0) { diff --git a/testdata/p4_14_samples_outputs/simple_router-frontend.p4 b/testdata/p4_14_samples_outputs/simple_router-frontend.p4 index dd7fc346626..39fb10fe182 100644 --- a/testdata/p4_14_samples_outputs/simple_router-frontend.p4 +++ b/testdata/p4_14_samples_outputs/simple_router-frontend.p4 @@ -108,7 +108,7 @@ control ingress(inout headers hdr, inout metadata meta, inout standard_metadata_ key = { } size = 1; - default_action = _drop_2(); + const default_action = _drop_2(); } @name(".forward") table forward_0 { actions = { @@ -131,7 +131,7 @@ control ingress(inout headers hdr, inout metadata meta, inout standard_metadata_ hdr.ipv4.dstAddr: lpm @name("ipv4.dstAddr") ; } size = 1024; - default_action = _drop_6(); + const default_action = _drop_6(); } apply { if (hdr.ipv4.isValid() && hdr.ipv4.ttl > 8w0) { diff --git a/testdata/p4_14_samples_outputs/simple_router-midend.p4 b/testdata/p4_14_samples_outputs/simple_router-midend.p4 index 6331495e48a..062c6ccaac2 100644 --- a/testdata/p4_14_samples_outputs/simple_router-midend.p4 +++ b/testdata/p4_14_samples_outputs/simple_router-midend.p4 @@ -107,7 +107,7 @@ control ingress(inout headers hdr, inout metadata meta, inout standard_metadata_ key = { } size = 1; - default_action = _drop_2(); + const default_action = _drop_2(); } @name(".forward") table forward_0 { actions = { @@ -130,7 +130,7 @@ control ingress(inout headers hdr, inout metadata meta, inout standard_metadata_ hdr.ipv4.dstAddr: lpm @name("ipv4.dstAddr") ; } size = 1024; - default_action = _drop_6(); + const default_action = _drop_6(); } apply { if (hdr.ipv4.isValid() && hdr.ipv4.ttl > 8w0) { diff --git a/testdata/p4_14_samples_outputs/simple_router.p4 b/testdata/p4_14_samples_outputs/simple_router.p4 index 4b18d439fad..b2ba34a8aa7 100644 --- a/testdata/p4_14_samples_outputs/simple_router.p4 +++ b/testdata/p4_14_samples_outputs/simple_router.p4 @@ -96,7 +96,7 @@ control ingress(inout headers hdr, inout metadata meta, inout standard_metadata_ key = { } size = 1; - default_action = _drop(); + const default_action = _drop(); } @name(".forward") table forward { actions = { @@ -117,7 +117,7 @@ control ingress(inout headers hdr, inout metadata meta, inout standard_metadata_ hdr.ipv4.dstAddr: lpm; } size = 1024; - default_action = _drop(); + const default_action = _drop(); } apply { if (hdr.ipv4.isValid() && hdr.ipv4.ttl > 8w0) { From 53c347ddd43e0b37989e04235e18f1755f7535a4 Mon Sep 17 00:00:00 2001 From: Mihai Budiu Date: Sun, 8 Dec 2019 14:34:08 -0800 Subject: [PATCH 043/106] Track unreachable statements; fixes #2104 (#2107) * Track unreachable statements; fixes #2104 --- frontends/p4/def_use.cpp | 23 ++++- frontends/p4/def_use.h | 14 ++- frontends/p4/simplifyDefUse.cpp | 98 +++++++++++++------ frontends/p4/simplifyDefUse.h | 2 +- testdata/p4_16_samples/issue2104-1.p4 | 18 ++++ testdata/p4_16_samples/issue2104.p4 | 23 +++++ .../issue2104-1-first.p4 | 16 +++ .../issue2104-1-frontend.p4 | 20 ++++ .../issue2104-1-midend.p4 | 12 +++ testdata/p4_16_samples_outputs/issue2104-1.p4 | 16 +++ .../issue2104-1.p4-stderr | 0 .../issue2104-1.p4.entries.txt | 0 .../issue2104-1.p4.p4info.txt | 3 + .../p4_16_samples_outputs/issue2104-first.p4 | 23 +++++ .../issue2104-frontend.p4 | 17 ++++ .../p4_16_samples_outputs/issue2104-midend.p4 | 21 ++++ testdata/p4_16_samples_outputs/issue2104.p4 | 23 +++++ .../p4_16_samples_outputs/issue2104.p4-stderr | 0 .../issue2104.p4.entries.txt | 0 .../issue2104.p4.p4info.txt | 10 ++ 20 files changed, 304 insertions(+), 35 deletions(-) create mode 100644 testdata/p4_16_samples/issue2104-1.p4 create mode 100644 testdata/p4_16_samples/issue2104.p4 create mode 100644 testdata/p4_16_samples_outputs/issue2104-1-first.p4 create mode 100644 testdata/p4_16_samples_outputs/issue2104-1-frontend.p4 create mode 100644 testdata/p4_16_samples_outputs/issue2104-1-midend.p4 create mode 100644 testdata/p4_16_samples_outputs/issue2104-1.p4 create mode 100644 testdata/p4_16_samples_outputs/issue2104-1.p4-stderr create mode 100644 testdata/p4_16_samples_outputs/issue2104-1.p4.entries.txt create mode 100644 testdata/p4_16_samples_outputs/issue2104-1.p4.p4info.txt create mode 100644 testdata/p4_16_samples_outputs/issue2104-first.p4 create mode 100644 testdata/p4_16_samples_outputs/issue2104-frontend.p4 create mode 100644 testdata/p4_16_samples_outputs/issue2104-midend.p4 create mode 100644 testdata/p4_16_samples_outputs/issue2104.p4 create mode 100644 testdata/p4_16_samples_outputs/issue2104.p4-stderr create mode 100644 testdata/p4_16_samples_outputs/issue2104.p4.entries.txt create mode 100644 testdata/p4_16_samples_outputs/issue2104.p4.p4info.txt diff --git a/frontends/p4/def_use.cpp b/frontends/p4/def_use.cpp index 69ec0d50bdf..0c7bbc18b7e 100644 --- a/frontends/p4/def_use.cpp +++ b/frontends/p4/def_use.cpp @@ -304,6 +304,8 @@ Definitions* Definitions::joinDefinitions(const Definitions* other) const { result->definitions.emplace(loc, defs); // otherwise have have already done it in the loop above } + if (unreachable && other->unreachable) + result->setUnreachable(); return result; } @@ -767,6 +769,9 @@ bool ComputeWriteSet::preorder(const IR::P4Control* control) { } bool ComputeWriteSet::preorder(const IR::IfStatement* statement) { + LOG3("CWS Visiting " << dbp(statement)); + if (currentDefinitions->isUnreachable()) + return setDefinitions(currentDefinitions); visit(statement->condition); auto cond = getWrites(statement->condition); // defs are the definitions after evaluating the condition @@ -782,6 +787,8 @@ bool ComputeWriteSet::preorder(const IR::IfStatement* statement) { } bool ComputeWriteSet::preorder(const IR::BlockStatement* statement) { + if (currentDefinitions->isUnreachable()) + return setDefinitions(currentDefinitions); visit(statement->components, "components"); return setDefinitions(currentDefinitions); } @@ -791,13 +798,19 @@ bool ComputeWriteSet::preorder(const IR::ReturnStatement* statement) { visit(statement->expression); returnedDefinitions = returnedDefinitions->joinDefinitions(currentDefinitions); LOG3("Return definitions " << returnedDefinitions); - return setDefinitions(new Definitions()); + auto defs = currentDefinitions->cloneDefinitions(); + defs->setUnreachable(); + return setDefinitions(defs); } bool ComputeWriteSet::preorder(const IR::ExitStatement*) { + if (currentDefinitions->isUnreachable()) + return setDefinitions(currentDefinitions); exitDefinitions = exitDefinitions->joinDefinitions(currentDefinitions); LOG3("Exit definitions " << exitDefinitions); - return setDefinitions(new Definitions()); + auto defs = currentDefinitions->cloneDefinitions(); + defs->setUnreachable(); + return setDefinitions(defs); } bool ComputeWriteSet::preorder(const IR::EmptyStatement*) { @@ -806,6 +819,8 @@ bool ComputeWriteSet::preorder(const IR::EmptyStatement*) { bool ComputeWriteSet::preorder(const IR::AssignmentStatement* statement) { LOG3("CWS Visiting " << dbp(statement) << " " << statement); + if (currentDefinitions->isUnreachable()) + return setDefinitions(currentDefinitions); lhs = true; visit(statement->left); lhs = false; @@ -820,6 +835,8 @@ bool ComputeWriteSet::preorder(const IR::AssignmentStatement* statement) { bool ComputeWriteSet::preorder(const IR::SwitchStatement* statement) { LOG3("CWS Visiting " << dbp(statement)); + if (currentDefinitions->isUnreachable()) + return setDefinitions(currentDefinitions); visit(statement->expression); auto locs = getWrites(statement->expression); auto defs = currentDefinitions->writes(getProgramPoint(statement->expression), locs); @@ -928,6 +945,8 @@ bool ComputeWriteSet::preorder(const IR::P4Table* table) { } bool ComputeWriteSet::preorder(const IR::MethodCallStatement* statement) { + if (currentDefinitions->isUnreachable()) + return setDefinitions(currentDefinitions); lhs = false; visit(statement->methodCall); auto locs = getWrites(statement->methodCall); diff --git a/frontends/p4/def_use.h b/frontends/p4/def_use.h index 0325e620c50..d5bf2142bec 100644 --- a/frontends/p4/def_use.h +++ b/frontends/p4/def_use.h @@ -212,7 +212,7 @@ class StorageMap { StorageLocation* add(const IR::IDeclaration* decl) { CHECK_NULL(decl); auto type = typeMap->getType(decl->getNode(), true); - auto loc = factory.create(type, decl->getName()); + auto loc = factory.create(type, decl->externalName()); if (loc != nullptr) storage.emplace(decl, loc); return loc; @@ -329,10 +329,14 @@ class Definitions : public IHasDbPrint { /// Set of program points that have written last to each location /// (conservative approximation). std::map definitions; + /// If true the current program point is actually unreachable and + /// it's definitions should not matter. + bool unreachable; public: Definitions() = default; - Definitions(const Definitions& other) : definitions(other.definitions) {} + Definitions(const Definitions& other) : + definitions(other.definitions), unreachable(other.unreachable) {} Definitions* joinDefinitions(const Definitions* other) const; /// Point writes the specified LocationSet. Definitions* writes(ProgramPoint point, const LocationSet* locations) const; @@ -340,6 +344,8 @@ class Definitions : public IHasDbPrint { { CHECK_NULL(loc); CHECK_NULL(point); definitions[loc] = point; } void setDefinition(const StorageLocation* loc, const ProgramPoints* point); void setDefinition(const LocationSet* loc, const ProgramPoints* point); + Definitions* setUnreachable() { unreachable = true; return this; } + bool isUnreachable() const { return unreachable; } bool hasLocation(const BaseLocation* location) const { return definitions.find(location) != definitions.end(); } const ProgramPoints* getPoints(const BaseLocation* location) const { @@ -349,6 +355,10 @@ class Definitions : public IHasDbPrint { const ProgramPoints* getPoints(const LocationSet* locations) const; bool operator==(const Definitions& other) const; void dbprint(std::ostream& out) const { + if (unreachable) { + out << " Unreachable"; + return; + } if (definitions.empty()) out << " Empty definitions"; bool first = true; diff --git a/frontends/p4/simplifyDefUse.cpp b/frontends/p4/simplifyDefUse.cpp index b6863f38462..eb01e192a6c 100644 --- a/frontends/p4/simplifyDefUse.cpp +++ b/frontends/p4/simplifyDefUse.cpp @@ -69,10 +69,12 @@ class FindUninitialized : public Inspector { AllDefinitions* definitions; bool lhs; // checking the lhs of an assignment ProgramPoint currentPoint; // context of the current expression/statement - // For some simple expresssions keep here the read location sets. - // This does not include location sets read by subexpressions. + /// For some simple expresssions keep here the read location sets. + /// This does not include location sets read by subexpressions. std::map readLocations; HasUses* hasUses; // output + /// If true the current statement is unreachable + bool unreachable; const LocationSet* getReads(const IR::Expression* expression, bool nonNull = false) const { auto result = ::get(readLocations, expression); @@ -152,11 +154,9 @@ class FindUninitialized : public Inspector { } if (checkReturn) { - // check returned value - auto storage = definitions->storageMap->getRetVal(); - if (storage != nullptr && defs->hasLocation(storage)) - // If this definition is "live" it means that we have - // not returned on all paths; returns kill this definition. + // The final definitions should be unreachable, otherwise + // we have not returned on all paths. + if (!defs->isUnreachable()) ::error("Function %1% does not return a value on all paths", block); } } @@ -165,6 +165,7 @@ class FindUninitialized : public Inspector { LOG3("FU Visiting control " << control->name << "[" << control->id << "]"); BUG_CHECK(context.isBeforeStart(), "non-empty context in FindUnitialized::P4Control"); currentPoint = ProgramPoint(control); + unreachable = false; for (auto d : control->controlLocals) if (d->is()) // visit virtual Function implementation if any @@ -180,16 +181,19 @@ class FindUninitialized : public Inspector { LOG5(func); // FIXME -- this throws away the context of the current point, which seems wrong, // FIXME -- but otherwise analysis fails + unreachable = false; currentPoint = ProgramPoint(func); visit(func->body); bool checkReturn = !func->type->returnType->is(); checkOutParameters(func, func->type->parameters, getCurrentDefinitions(), checkReturn); + unreachable = false; // not inherited across function calls return false; } bool preorder(const IR::P4Parser* parser) override { LOG3("FU Visiting parser " << parser->name << "[" << parser->id << "]"); visit(parser->states, "states"); + unreachable = false; auto accept = ProgramPoint(parser->getDeclByName(IR::ParserState::accept)->getNode()); auto acceptdefs = definitions->getDefinitions(accept, true); if (!acceptdefs->empty()) @@ -200,56 +204,87 @@ class FindUninitialized : public Inspector { bool preorder(const IR::AssignmentStatement* statement) override { LOG3("FU Visiting " << dbp(statement) << " " << statement); - auto assign = statement->to(); - lhs = true; - visit(assign->left); - lhs = false; - visit(assign->right); + if (!unreachable) { + lhs = true; + visit(statement->left); + lhs = false; + visit(statement->right); + } else { + LOG3("Unreachable"); + } return setCurrent(statement); } bool preorder(const IR::ReturnStatement* statement) override { LOG3("FU Visiting " << statement); - if (statement->expression != nullptr) + if (!unreachable && statement->expression != nullptr) visit(statement->expression); + else + LOG3("Unreachable"); + unreachable = true; return setCurrent(statement); } bool preorder(const IR::MethodCallStatement* statement) override { LOG3("FU Visiting " << statement); - visit(statement->methodCall); + if (!unreachable) + visit(statement->methodCall); + else + LOG3("Unreachable"); + return setCurrent(statement); } bool preorder(const IR::BlockStatement* statement) override { LOG3("FU Visiting " << statement); - visit(statement->components, "components"); + if (!unreachable) { + visit(statement->components, "components"); + } else { + LOG3("Unreachable"); + } return setCurrent(statement); } bool preorder(const IR::IfStatement* statement) override { LOG3("FU Visiting " << statement); - visit(statement->condition); - auto saveCurrent = currentPoint; - visit(statement->ifTrue); - if (statement->ifFalse != nullptr) { - currentPoint = saveCurrent; - visit(statement->ifFalse); + if (!unreachable) { + visit(statement->condition); + auto saveCurrent = currentPoint; + auto saveUnreachable = unreachable; + visit(statement->ifTrue); + auto unreachableAfterThen = unreachable; + unreachable = saveUnreachable; + if (statement->ifFalse != nullptr) { + currentPoint = saveCurrent; + visit(statement->ifFalse); + } + unreachable = unreachableAfterThen && unreachable; + } else { + LOG3("Unreachable"); } return setCurrent(statement); } bool preorder(const IR::SwitchStatement* statement) override { LOG3("FU Visiting " << statement); - visit(statement->expression); - currentPoint = ProgramPoint(context, statement->expression); // CTD -- added context - auto saveCurrent = currentPoint; - for (auto c : statement->cases) { - if (c->statement != nullptr) { - LOG3("Visiting " << c); - currentPoint = saveCurrent; - visit(c); + if (!unreachable) { + bool finalUnreachable = true; + visit(statement->expression); + currentPoint = ProgramPoint(context, statement->expression); + auto saveCurrent = currentPoint; + auto saveUnreachable = unreachable; + for (auto c : statement->cases) { + if (c->statement != nullptr) { + LOG3("Visiting " << c); + currentPoint = saveCurrent; + unreachable = saveUnreachable; + visit(c); + finalUnreachable = finalUnreachable && unreachable; + } } + unreachable = finalUnreachable; + } else { + LOG3("Unreachable"); } return setCurrent(statement); } @@ -297,12 +332,14 @@ class FindUninitialized : public Inspector { // Keeps track of which expression producers have uses in the given expression void registerUses(const IR::Expression* expression, bool reportUninitialized = true) { + auto currentDefinitions = getCurrentDefinitions(); + if (currentDefinitions->isUnreachable()) + return; if (!isFinalRead(getContext(), expression)) return; const LocationSet* read = getReads(expression); if (read == nullptr || read->isEmpty()) return; - auto currentDefinitions = getCurrentDefinitions(); auto points = currentDefinitions->getPoints(read); if (reportUninitialized && !lhs && points->containsBeforeStart()) { // Do not report uninitialized values on the LHS. @@ -341,6 +378,7 @@ class FindUninitialized : public Inspector { bool preorder(const IR::P4Action* action) override { LOG3("FU Visiting " << action); + unreachable = false; currentPoint = ProgramPoint(context, action); visit(action->body); checkOutParameters(action, action->parameters, getCurrentDefinitions()); diff --git a/frontends/p4/simplifyDefUse.h b/frontends/p4/simplifyDefUse.h index 19ee186b5c3..86b862cb0e6 100644 --- a/frontends/p4/simplifyDefUse.h +++ b/frontends/p4/simplifyDefUse.h @@ -37,7 +37,7 @@ class DoSimplifyDefUse : public Transform { const IR::Node* postorder(IR::Function* function) override { if (findContext() == nullptr) // not an abstract function implementation: these - // are processed as parat of the control body + // are processed as part of the control body return process(function); return function; } diff --git a/testdata/p4_16_samples/issue2104-1.p4 b/testdata/p4_16_samples/issue2104-1.p4 new file mode 100644 index 00000000000..678fb9705a8 --- /dev/null +++ b/testdata/p4_16_samples/issue2104-1.p4 @@ -0,0 +1,18 @@ +#include +#include + +// adding the inout qualifier leads to a compiler crash +bit<8> test(inout bit<8> x) { + return x; +} + +control c(inout bit<8> a) { + apply { + test(a); + } +} + +control E(inout bit<8> t); +package top(E e); + +top(c()) main; diff --git a/testdata/p4_16_samples/issue2104.p4 b/testdata/p4_16_samples/issue2104.p4 new file mode 100644 index 00000000000..d1386cabb85 --- /dev/null +++ b/testdata/p4_16_samples/issue2104.p4 @@ -0,0 +1,23 @@ +#include +#include + +control c() { + bit<16> F = 0; + bit<128> Y = 0; + action r() { + Y = (bit<128>) F; + } + action v() { + return; // the return comes before the action call + r(); + F = (bit<16>)Y; + } + apply { + v(); + } +} + +control e(); +package top(e e); + +top(c()) main; diff --git a/testdata/p4_16_samples_outputs/issue2104-1-first.p4 b/testdata/p4_16_samples_outputs/issue2104-1-first.p4 new file mode 100644 index 00000000000..fb83f561525 --- /dev/null +++ b/testdata/p4_16_samples_outputs/issue2104-1-first.p4 @@ -0,0 +1,16 @@ +#include +#include + +bit<8> test(inout bit<8> x) { + return x; +} +control c(inout bit<8> a) { + apply { + test(a); + } +} + +control E(inout bit<8> t); +package top(E e); +top(c()) main; + diff --git a/testdata/p4_16_samples_outputs/issue2104-1-frontend.p4 b/testdata/p4_16_samples_outputs/issue2104-1-frontend.p4 new file mode 100644 index 00000000000..fee90e234f0 --- /dev/null +++ b/testdata/p4_16_samples_outputs/issue2104-1-frontend.p4 @@ -0,0 +1,20 @@ +#include +#include + +control c(inout bit<8> a) { + apply { + { + bit<8> x_0 = a; + bool hasReturned = false; + bit<8> retval; + hasReturned = true; + retval = x_0; + a = x_0; + } + } +} + +control E(inout bit<8> t); +package top(E e); +top(c()) main; + diff --git a/testdata/p4_16_samples_outputs/issue2104-1-midend.p4 b/testdata/p4_16_samples_outputs/issue2104-1-midend.p4 new file mode 100644 index 00000000000..8cd128ee4b0 --- /dev/null +++ b/testdata/p4_16_samples_outputs/issue2104-1-midend.p4 @@ -0,0 +1,12 @@ +#include +#include + +control c(inout bit<8> a) { + apply { + } +} + +control E(inout bit<8> t); +package top(E e); +top(c()) main; + diff --git a/testdata/p4_16_samples_outputs/issue2104-1.p4 b/testdata/p4_16_samples_outputs/issue2104-1.p4 new file mode 100644 index 00000000000..fb83f561525 --- /dev/null +++ b/testdata/p4_16_samples_outputs/issue2104-1.p4 @@ -0,0 +1,16 @@ +#include +#include + +bit<8> test(inout bit<8> x) { + return x; +} +control c(inout bit<8> a) { + apply { + test(a); + } +} + +control E(inout bit<8> t); +package top(E e); +top(c()) main; + diff --git a/testdata/p4_16_samples_outputs/issue2104-1.p4-stderr b/testdata/p4_16_samples_outputs/issue2104-1.p4-stderr new file mode 100644 index 00000000000..e69de29bb2d diff --git a/testdata/p4_16_samples_outputs/issue2104-1.p4.entries.txt b/testdata/p4_16_samples_outputs/issue2104-1.p4.entries.txt new file mode 100644 index 00000000000..e69de29bb2d diff --git a/testdata/p4_16_samples_outputs/issue2104-1.p4.p4info.txt b/testdata/p4_16_samples_outputs/issue2104-1.p4.p4info.txt new file mode 100644 index 00000000000..9ec92493e4c --- /dev/null +++ b/testdata/p4_16_samples_outputs/issue2104-1.p4.p4info.txt @@ -0,0 +1,3 @@ +pkg_info { + arch: "v1model" +} diff --git a/testdata/p4_16_samples_outputs/issue2104-first.p4 b/testdata/p4_16_samples_outputs/issue2104-first.p4 new file mode 100644 index 00000000000..d93f7eba60c --- /dev/null +++ b/testdata/p4_16_samples_outputs/issue2104-first.p4 @@ -0,0 +1,23 @@ +#include +#include + +control c() { + bit<16> F = 16w0; + bit<128> Y = 128w0; + action r() { + Y = (bit<128>)F; + } + action v() { + return; + r(); + F = (bit<16>)Y; + } + apply { + v(); + } +} + +control e(); +package top(e e); +top(c()) main; + diff --git a/testdata/p4_16_samples_outputs/issue2104-frontend.p4 b/testdata/p4_16_samples_outputs/issue2104-frontend.p4 new file mode 100644 index 00000000000..07749761f0b --- /dev/null +++ b/testdata/p4_16_samples_outputs/issue2104-frontend.p4 @@ -0,0 +1,17 @@ +#include +#include + +control c() { + @name("c.v") action v() { + bool hasReturned = false; + hasReturned = true; + } + apply { + v(); + } +} + +control e(); +package top(e e); +top(c()) main; + diff --git a/testdata/p4_16_samples_outputs/issue2104-midend.p4 b/testdata/p4_16_samples_outputs/issue2104-midend.p4 new file mode 100644 index 00000000000..1ec0969e72d --- /dev/null +++ b/testdata/p4_16_samples_outputs/issue2104-midend.p4 @@ -0,0 +1,21 @@ +#include +#include + +control c() { + @name("c.v") action v() { + } + @hidden table tbl_v { + actions = { + v(); + } + const default_action = v(); + } + apply { + tbl_v.apply(); + } +} + +control e(); +package top(e e); +top(c()) main; + diff --git a/testdata/p4_16_samples_outputs/issue2104.p4 b/testdata/p4_16_samples_outputs/issue2104.p4 new file mode 100644 index 00000000000..d5f1ccdd789 --- /dev/null +++ b/testdata/p4_16_samples_outputs/issue2104.p4 @@ -0,0 +1,23 @@ +#include +#include + +control c() { + bit<16> F = 0; + bit<128> Y = 0; + action r() { + Y = (bit<128>)F; + } + action v() { + return; + r(); + F = (bit<16>)Y; + } + apply { + v(); + } +} + +control e(); +package top(e e); +top(c()) main; + diff --git a/testdata/p4_16_samples_outputs/issue2104.p4-stderr b/testdata/p4_16_samples_outputs/issue2104.p4-stderr new file mode 100644 index 00000000000..e69de29bb2d diff --git a/testdata/p4_16_samples_outputs/issue2104.p4.entries.txt b/testdata/p4_16_samples_outputs/issue2104.p4.entries.txt new file mode 100644 index 00000000000..e69de29bb2d diff --git a/testdata/p4_16_samples_outputs/issue2104.p4.p4info.txt b/testdata/p4_16_samples_outputs/issue2104.p4.p4info.txt new file mode 100644 index 00000000000..204be956739 --- /dev/null +++ b/testdata/p4_16_samples_outputs/issue2104.p4.p4info.txt @@ -0,0 +1,10 @@ +pkg_info { + arch: "v1model" +} +actions { + preamble { + id: 16819975 + name: "c.v" + alias: "v" + } +} From 9a47d2a2d51b2e59678f52458cca4f9eb206e67c Mon Sep 17 00:00:00 2001 From: Mihai Budiu Date: Tue, 10 Dec 2019 09:43:04 -0800 Subject: [PATCH 044/106] Handle MUX in FindUses; fixes #2105 (#2109) * Handle MUX in FindUses; fixes #2105 --- frontends/p4/simplifyDefUse.cpp | 37 +++++++++---------- testdata/p4_16_samples/issue2105.p4 | 25 +++++++++++++ .../p4_16_samples_outputs/issue2105-first.p4 | 23 ++++++++++++ .../issue2105-frontend.p4 | 22 +++++++++++ .../p4_16_samples_outputs/issue2105-midend.p4 | 20 ++++++++++ testdata/p4_16_samples_outputs/issue2105.p4 | 23 ++++++++++++ .../p4_16_samples_outputs/issue2105.p4-stderr | 0 .../issue2105.p4.entries.txt | 0 .../issue2105.p4.p4info.txt | 3 ++ 9 files changed, 134 insertions(+), 19 deletions(-) create mode 100644 testdata/p4_16_samples/issue2105.p4 create mode 100644 testdata/p4_16_samples_outputs/issue2105-first.p4 create mode 100644 testdata/p4_16_samples_outputs/issue2105-frontend.p4 create mode 100644 testdata/p4_16_samples_outputs/issue2105-midend.p4 create mode 100644 testdata/p4_16_samples_outputs/issue2105.p4 create mode 100644 testdata/p4_16_samples_outputs/issue2105.p4-stderr create mode 100644 testdata/p4_16_samples_outputs/issue2105.p4.entries.txt create mode 100644 testdata/p4_16_samples_outputs/issue2105.p4.p4info.txt diff --git a/frontends/p4/simplifyDefUse.cpp b/frontends/p4/simplifyDefUse.cpp index eb01e192a6c..4b08e1f50f9 100644 --- a/frontends/p4/simplifyDefUse.cpp +++ b/frontends/p4/simplifyDefUse.cpp @@ -515,6 +515,20 @@ class FindUninitialized : public Inspector { return false; } + void otherExpression(const IR::Expression* expression) { + BUG_CHECK(!lhs, "%1%: unexpected operation on LHS", expression); + LOG3("FU Visiting [" << expression->id << "]: " << expression); + // This expression in fact reads the result of the operation, + // which is a temporary storage location, which we do not model + // in the def-use analysis. + reads(expression, LocationSet::empty); + registerUses(expression); + } + + void postorder(const IR::Mux* expression) override { + otherExpression(expression); + } + bool preorder(const IR::ArrayIndex* expression) override { LOG3("FU Visiting [" << expression->id << "]: " << expression); if (expression->right->is()) { @@ -543,27 +557,12 @@ class FindUninitialized : public Inspector { return false; } - bool preorder(const IR::Operation_Unary* expression) override { - BUG_CHECK(!lhs, "%1%: Unary operation on LHS?", expression); - visit(expression->expr); - // This expression in fact reads the result of the operation, - // which is a temporary storage location, which we do not model - // in the def-use analysis. - reads(expression, LocationSet::empty); - registerUses(expression); - return false; + void postorder(const IR::Operation_Unary* expression) override { + otherExpression(expression); } - bool preorder(const IR::Operation_Binary* expression) override { - BUG_CHECK(!lhs, "%1%: Binary operation on LHS?", expression); - visit(expression->left); - visit(expression->right); - // This expression in fact reads the result of the operation, - // which is a temporary storage location, which we do not model - // in the def-use analysis. - reads(expression, LocationSet::empty); - registerUses(expression); - return false; + void postorder(const IR::Operation_Binary* expression) override { + otherExpression(expression); } }; diff --git a/testdata/p4_16_samples/issue2105.p4 b/testdata/p4_16_samples/issue2105.p4 new file mode 100644 index 00000000000..ea1b096c3fd --- /dev/null +++ b/testdata/p4_16_samples/issue2105.p4 @@ -0,0 +1,25 @@ +#include +#include + +header H { + bit<8> a; +} + +struct Headers { + H h; +} + +control c() { + apply { + bit<8> x = 0; + bit<8> y = 0; + // the crash happens when reassigning c while referencing b + // removing either the slice or the bor operation will fix the crash + y = (x < 4 ? 8w2 : 8w1)[7:0] | 8w8; + } +} + +control e(); +package top(e e); + +top(c()) main; diff --git a/testdata/p4_16_samples_outputs/issue2105-first.p4 b/testdata/p4_16_samples_outputs/issue2105-first.p4 new file mode 100644 index 00000000000..e35cd13aa1a --- /dev/null +++ b/testdata/p4_16_samples_outputs/issue2105-first.p4 @@ -0,0 +1,23 @@ +#include +#include + +header H { + bit<8> a; +} + +struct Headers { + H h; +} + +control c() { + apply { + bit<8> x = 8w0; + bit<8> y = 8w0; + y = (x < 8w4 ? 8w2 : 8w1)[7:0] | 8w8; + } +} + +control e(); +package top(e e); +top<_>(c()) main; + diff --git a/testdata/p4_16_samples_outputs/issue2105-frontend.p4 b/testdata/p4_16_samples_outputs/issue2105-frontend.p4 new file mode 100644 index 00000000000..0f0c131de23 --- /dev/null +++ b/testdata/p4_16_samples_outputs/issue2105-frontend.p4 @@ -0,0 +1,22 @@ +#include +#include + +header H { + bit<8> a; +} + +struct Headers { + H h; +} + +control c() { + bit<8> x_0; + apply { + x_0 = 8w0; + } +} + +control e(); +package top(e e); +top<_>(c()) main; + diff --git a/testdata/p4_16_samples_outputs/issue2105-midend.p4 b/testdata/p4_16_samples_outputs/issue2105-midend.p4 new file mode 100644 index 00000000000..6f7ab670ec2 --- /dev/null +++ b/testdata/p4_16_samples_outputs/issue2105-midend.p4 @@ -0,0 +1,20 @@ +#include +#include + +header H { + bit<8> a; +} + +struct Headers { + H h; +} + +control c() { + apply { + } +} + +control e(); +package top(e e); +top<_>(c()) main; + diff --git a/testdata/p4_16_samples_outputs/issue2105.p4 b/testdata/p4_16_samples_outputs/issue2105.p4 new file mode 100644 index 00000000000..50cb0f5cee6 --- /dev/null +++ b/testdata/p4_16_samples_outputs/issue2105.p4 @@ -0,0 +1,23 @@ +#include +#include + +header H { + bit<8> a; +} + +struct Headers { + H h; +} + +control c() { + apply { + bit<8> x = 0; + bit<8> y = 0; + y = (x < 4 ? 8w2 : 8w1)[7:0] | 8w8; + } +} + +control e(); +package top(e e); +top(c()) main; + diff --git a/testdata/p4_16_samples_outputs/issue2105.p4-stderr b/testdata/p4_16_samples_outputs/issue2105.p4-stderr new file mode 100644 index 00000000000..e69de29bb2d diff --git a/testdata/p4_16_samples_outputs/issue2105.p4.entries.txt b/testdata/p4_16_samples_outputs/issue2105.p4.entries.txt new file mode 100644 index 00000000000..e69de29bb2d diff --git a/testdata/p4_16_samples_outputs/issue2105.p4.p4info.txt b/testdata/p4_16_samples_outputs/issue2105.p4.p4info.txt new file mode 100644 index 00000000000..9ec92493e4c --- /dev/null +++ b/testdata/p4_16_samples_outputs/issue2105.p4.p4info.txt @@ -0,0 +1,3 @@ +pkg_info { + arch: "v1model" +} From c50a6bec93d6ffbb249dd0a0d67a3ddf64ef0b8d Mon Sep 17 00:00:00 2001 From: Mihai Budiu Date: Tue, 10 Dec 2019 10:02:52 -0800 Subject: [PATCH 045/106] Return a BlockStatement instead of a Vector; fixes #2102 (#2103) --- midend/copyStructures.cpp | 4 ++-- testdata/p4_16_samples/issue2102.p4 | 22 +++++++++++++++++++ .../p4_16_samples_outputs/issue2102-first.p4 | 22 +++++++++++++++++++ .../issue2102-frontend.p4 | 22 +++++++++++++++++++ .../p4_16_samples_outputs/issue2102-midend.p4 | 19 ++++++++++++++++ testdata/p4_16_samples_outputs/issue2102.p4 | 22 +++++++++++++++++++ .../p4_16_samples_outputs/issue2102.p4-stderr | 0 7 files changed, 109 insertions(+), 2 deletions(-) create mode 100644 testdata/p4_16_samples/issue2102.p4 create mode 100644 testdata/p4_16_samples_outputs/issue2102-first.p4 create mode 100644 testdata/p4_16_samples_outputs/issue2102-frontend.p4 create mode 100644 testdata/p4_16_samples_outputs/issue2102-midend.p4 create mode 100644 testdata/p4_16_samples_outputs/issue2102.p4 create mode 100644 testdata/p4_16_samples_outputs/issue2102.p4-stderr diff --git a/midend/copyStructures.cpp b/midend/copyStructures.cpp index 409e991924c..5683a167482 100644 --- a/midend/copyStructures.cpp +++ b/midend/copyStructures.cpp @@ -30,13 +30,13 @@ const IR::Node* RemoveAliases::postorder(IR::AssignmentStatement* statement) { auto tmp = refMap->newName("tmp"); auto decl = new IR::Declaration_Variable(IR::ID(tmp), type->getP4Type(), nullptr); declarations.push_back(decl); - auto result = new IR::Vector(); + auto result = new IR::IndexedVector(); result->push_back(new IR::AssignmentStatement( statement->srcInfo, new IR::PathExpression(tmp), statement->right)); result->push_back(new IR::AssignmentStatement( statement->srcInfo, statement->left, new IR::PathExpression(tmp))); LOG3("Inserted temporary " << decl << " for " << statement); - return result; + return new IR::BlockStatement(statement->srcInfo, *result); } const IR::Node* RemoveAliases::postorder(IR::P4Parser* parser) { diff --git a/testdata/p4_16_samples/issue2102.p4 b/testdata/p4_16_samples/issue2102.p4 new file mode 100644 index 00000000000..b06f34f801d --- /dev/null +++ b/testdata/p4_16_samples/issue2102.p4 @@ -0,0 +1,22 @@ +#include + +header H { + bit<1> a; +} + +struct headers { + H h; +} + +control c(inout headers hdr) { + apply { + if (hdr.h.a < 1) { + hdr = hdr; + } + } +} + +control e(inout T t); +package top(e e); + +top(c()) main; diff --git a/testdata/p4_16_samples_outputs/issue2102-first.p4 b/testdata/p4_16_samples_outputs/issue2102-first.p4 new file mode 100644 index 00000000000..14a0c71cb12 --- /dev/null +++ b/testdata/p4_16_samples_outputs/issue2102-first.p4 @@ -0,0 +1,22 @@ +#include + +header H { + bit<1> a; +} + +struct headers { + H h; +} + +control c(inout headers hdr) { + apply { + if (hdr.h.a < 1w1) { + hdr = hdr; + } + } +} + +control e(inout T t); +package top(e e); +top(c()) main; + diff --git a/testdata/p4_16_samples_outputs/issue2102-frontend.p4 b/testdata/p4_16_samples_outputs/issue2102-frontend.p4 new file mode 100644 index 00000000000..14a0c71cb12 --- /dev/null +++ b/testdata/p4_16_samples_outputs/issue2102-frontend.p4 @@ -0,0 +1,22 @@ +#include + +header H { + bit<1> a; +} + +struct headers { + H h; +} + +control c(inout headers hdr) { + apply { + if (hdr.h.a < 1w1) { + hdr = hdr; + } + } +} + +control e(inout T t); +package top(e e); +top(c()) main; + diff --git a/testdata/p4_16_samples_outputs/issue2102-midend.p4 b/testdata/p4_16_samples_outputs/issue2102-midend.p4 new file mode 100644 index 00000000000..930120c13cd --- /dev/null +++ b/testdata/p4_16_samples_outputs/issue2102-midend.p4 @@ -0,0 +1,19 @@ +#include + +header H { + bit<1> a; +} + +struct headers { + H h; +} + +control c(inout headers hdr) { + apply { + } +} + +control e(inout T t); +package top(e e); +top(c()) main; + diff --git a/testdata/p4_16_samples_outputs/issue2102.p4 b/testdata/p4_16_samples_outputs/issue2102.p4 new file mode 100644 index 00000000000..22f9e57103c --- /dev/null +++ b/testdata/p4_16_samples_outputs/issue2102.p4 @@ -0,0 +1,22 @@ +#include + +header H { + bit<1> a; +} + +struct headers { + H h; +} + +control c(inout headers hdr) { + apply { + if (hdr.h.a < 1) { + hdr = hdr; + } + } +} + +control e(inout T t); +package top(e e); +top(c()) main; + diff --git a/testdata/p4_16_samples_outputs/issue2102.p4-stderr b/testdata/p4_16_samples_outputs/issue2102.p4-stderr new file mode 100644 index 00000000000..e69de29bb2d From d381f26f5ee7a51a69c3efc9a5392941142e30f1 Mon Sep 17 00:00:00 2001 From: Jed Liu Date: Wed, 11 Dec 2019 16:20:44 -0800 Subject: [PATCH 046/106] Ignore warnings if we've already emitted errors (#2111) * Ignore warnings if we've already emitted errors This avoids burying errors in a pile of warnings by ignoring all warnings after the first error. * Update expected output. --- lib/error_reporter.h | 4 ++++ testdata/p4_16_errors_outputs/nostart.p4-stderr | 3 --- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/lib/error_reporter.h b/lib/error_reporter.h index d90788065b2..82d7be3701f 100644 --- a/lib/error_reporter.h +++ b/lib/error_reporter.h @@ -138,6 +138,10 @@ class ErrorReporter final { std::string prefix; if (action == DiagnosticAction::Warn) { + // Avoid burying errors in a pile of warnings: don't emit any more warnings if we've + // emitted errors. + if (errorCount > 0) return; + warningCount++; if (diagnosticName != nullptr) { prefix.append("[--Wwarn="); diff --git a/testdata/p4_16_errors_outputs/nostart.p4-stderr b/testdata/p4_16_errors_outputs/nostart.p4-stderr index de750a3b349..89ff17669c3 100644 --- a/testdata/p4_16_errors_outputs/nostart.p4-stderr +++ b/testdata/p4_16_errors_outputs/nostart.p4-stderr @@ -4,6 +4,3 @@ nostart.p4(18): [--Wwarn=parser-transition] warning: next: implicit transition t nostart.p4(17): error: parser p: parser does not have a `start' state parser p() { ^ -nostart.p4(17): [--Wwarn=parser-transition] warning: accept state in parser p is unreachable -parser p() { - ^ From 7d5e4bed481161a9e3cb6a26512d00dd2ba9e055 Mon Sep 17 00:00:00 2001 From: Chris Dodd Date: Wed, 11 Dec 2019 20:27:33 -0800 Subject: [PATCH 047/106] Allow extern methods to be marked @noSideEffects (#2112) - allows transformations/optimizations to have more knowledge of architecture-specific externs so as to better optimize things. --- frontends/p4/parseAnnotations.cpp | 1 + ir/base.def | 3 ++- ir/type.cpp | 1 + midend/has_side_effects.h | 31 ++++++++++++++++++++++++++----- midend/local_copyprop.cpp | 4 ++-- midend/local_copyprop.h | 3 +++ 6 files changed, 35 insertions(+), 8 deletions(-) diff --git a/frontends/p4/parseAnnotations.cpp b/frontends/p4/parseAnnotations.cpp index 10e182d567c..9a849fefe4f 100644 --- a/frontends/p4/parseAnnotations.cpp +++ b/frontends/p4/parseAnnotations.cpp @@ -27,6 +27,7 @@ ParseAnnotations::HandlerMap ParseAnnotations::standardHandlers() { PARSE_EMPTY(IR::Annotation::hiddenAnnotation), PARSE_EMPTY(IR::Annotation::atomicAnnotation), PARSE_EMPTY(IR::Annotation::optionalAnnotation), + PARSE_EMPTY(IR::Annotation::noSideEffectsAnnotation), // @name and @deprecated have a string literal argument. PARSE(IR::Annotation::nameAnnotation, StringLiteral), diff --git a/ir/base.def b/ir/base.def index 2b1b358e9b9..599f3fd353d 100644 --- a/ir/base.def +++ b/ir/base.def @@ -252,7 +252,8 @@ class Annotation { static const cstring optionalAnnotation; /// Optional parameter annotation static const cstring pkginfoAnnotation; /// Package documentation annotation. static const cstring deprecatedAnnotation; /// Deprecation annotation. - static const cstring synchronousAnnotation; /// Synchronous annotation. + static const cstring synchronousAnnotation; /// noSideEffects annotation. + static const cstring noSideEffectsAnnotation; /// Synchronous annotation. static const cstring matchAnnotation; /// Match annotation (for value sets). toString{ return cstring("@") + name; } validate{ diff --git a/ir/type.cpp b/ir/type.cpp index 41c63b87a55..559584626a1 100644 --- a/ir/type.cpp +++ b/ir/type.cpp @@ -45,6 +45,7 @@ const cstring IR::Annotation::optionalAnnotation = "optional"; const cstring IR::Annotation::pkginfoAnnotation = "pkginfo"; const cstring IR::Annotation::deprecatedAnnotation = "deprecated"; const cstring IR::Annotation::synchronousAnnotation = "synchronous"; +const cstring IR::Annotation::noSideEffectsAnnotation = "noSideEffects"; const cstring IR::Annotation::matchAnnotation = "match"; int Type_Declaration::nextId = 0; diff --git a/midend/has_side_effects.h b/midend/has_side_effects.h index 693f6d15f51..09d14aa5e83 100644 --- a/midend/has_side_effects.h +++ b/midend/has_side_effects.h @@ -18,18 +18,39 @@ limitations under the License. #define MIDEND_HAS_SIDE_EFFECTS_H_ #include "ir/ir.h" +#include "frontends/p4/typeChecking/typeChecker.h" +#include "frontends/common/resolveReferences/referenceMap.h" -/* Should this be a method on IR::Expression? */ +/* Should this be a method on IR::Expression? Maybe after the refMap/typeMap go away */ class hasSideEffects : public Inspector { + P4::ReferenceMap *refMap = nullptr; + P4::TypeMap *typeMap = nullptr; + bool result = false; - bool preorder(const IR::AssignmentStatement *) override { return !(result = true); } - /* FIXME -- currently assuming all calls and primitves have side effects */ - bool preorder(const IR::MethodCallExpression *) override { return !(result = true); } - bool preorder(const IR::Primitive *) override { return !(result = true); } + bool preorder(const IR::AssignmentStatement *) override { result = true; return false; } + bool preorder(const IR::MethodCallExpression *mc) override { + if (result) return false; + /* assume has side effects if we can't look it up */ + if (refMap && typeMap) { + auto *mi = P4::MethodInstance::resolve(mc, refMap, typeMap, true); + if (auto *em = mi->to()) { + if (em->method->getAnnotation(IR::Annotation::noSideEffectsAnnotation)) + return true; } } + result = true; + return false; } + bool preorder(const IR::Primitive *) override { result = true; return false; } bool preorder(const IR::Expression *) override { return !result; } + public: explicit hasSideEffects(const IR::Expression *e) { e->apply(*this); } + hasSideEffects(P4::ReferenceMap *rm, P4::TypeMap *tm) : refMap(rm), typeMap(tm) {} + hasSideEffects(P4::ReferenceMap *rm, P4::TypeMap *tm, const IR::Expression *e) + : refMap(rm), typeMap(tm) { e->apply(*this); } + bool operator()(const IR::Expression *e) { + result = false; + e->apply(*this); + return result; } explicit operator bool () { return result; } }; diff --git a/midend/local_copyprop.cpp b/midend/local_copyprop.cpp index cc6e772cff6..12db5d4629d 100644 --- a/midend/local_copyprop.cpp +++ b/midend/local_copyprop.cpp @@ -80,7 +80,7 @@ class DoLocalCopyPropagation::ElimDead : public Transform { if (auto var = ::getref(self.available, dest->path->name)) { if (var->local && !var->live) { LOG3(" removing dead assignment to " << dest->path->name); - if (hasSideEffects(as->right)) + if (self.hasSideEffects(as->right)) return makeSideEffectStatement(as->right); return nullptr; } else if (var->local) { @@ -93,7 +93,7 @@ class DoLocalCopyPropagation::ElimDead : public Transform { /* can't leave ifTrue == nullptr, as that will fail validation -- fold away * the if statement as needed */ if (s->ifFalse == nullptr) { - if (!hasSideEffects(s->condition)) { + if (!self.hasSideEffects(s->condition)) { return nullptr; } else { s->ifTrue = new IR::EmptyStatement(); diff --git a/midend/local_copyprop.h b/midend/local_copyprop.h index 991022ddfbf..8304f62ebe6 100644 --- a/midend/local_copyprop.h +++ b/midend/local_copyprop.h @@ -19,6 +19,7 @@ limitations under the License. #include "ir/ir.h" #include "frontends/p4/typeChecking/typeChecker.h" #include "frontends/common/resolveReferences/referenceMap.h" +#include "has_side_effects.h" namespace P4 { @@ -80,6 +81,8 @@ class DoLocalCopyPropagation : public ControlFlowVisitor, Transform, P4WriteCont bool name_overlap(cstring, cstring); void forOverlapAvail(cstring, std::function); void dropValuesUsing(cstring); + bool hasSideEffects(const IR::Expression *e) { + return bool(::hasSideEffects(refMap, typeMap, e)); } void visit_local_decl(const IR::Declaration_Variable *); const IR::Node *postorder(IR::Declaration_Variable *) override; From 7cf234df1992c61645f57519260f31a491d425c2 Mon Sep 17 00:00:00 2001 From: Chris Dodd Date: Thu, 12 Dec 2019 16:41:18 -0800 Subject: [PATCH 048/106] Fix simplifyDefUse to deal with side effect in if condition (#2114) - fixes issue seen in #2026 --- frontends/p4/simplifyDefUse.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/frontends/p4/simplifyDefUse.cpp b/frontends/p4/simplifyDefUse.cpp index 4b08e1f50f9..a87b6389039 100644 --- a/frontends/p4/simplifyDefUse.cpp +++ b/frontends/p4/simplifyDefUse.cpp @@ -249,6 +249,7 @@ class FindUninitialized : public Inspector { LOG3("FU Visiting " << statement); if (!unreachable) { visit(statement->condition); + currentPoint = ProgramPoint(context, statement->condition); auto saveCurrent = currentPoint; auto saveUnreachable = unreachable; visit(statement->ifTrue); From afb501c85159bb511650759eaf6aa8e259d37827 Mon Sep 17 00:00:00 2001 From: Andy Fingerhut Date: Sun, 15 Dec 2019 13:34:26 -0800 Subject: [PATCH 049/106] Add Python 3 ply to install steps in README (#2115) Without this, following the existing README instructions leads to an installation that fails all ebpf tests run by 'cd p4c/build ; make check'. With this addition, I believe all tests pass. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b653f5b82dd..8ba594f2e3b 100644 --- a/README.md +++ b/README.md @@ -204,7 +204,7 @@ libfl-dev libgmp-dev libboost-dev libboost-iostreams-dev libboost-graph-dev llvm pkg-config python python-scapy python-ipaddr python-ply python3-pip tcpdump -$ pip3 install scapy +$ pip3 install scapy ply ``` For documentation building: From e41634cd7ae1214fca589eaa92a3f2b37eeea79e Mon Sep 17 00:00:00 2001 From: Chris Dodd Date: Thu, 19 Dec 2019 12:45:52 -0800 Subject: [PATCH 050/106] Use libgc for all malloc calls, so they are scanned properly. (#2116) - glibstdc++ uses malloc to allocate exceptions being thrown, which could result in them not being scanned by the garbage collector, leading to memory corruption. --- lib/gc.cpp | 43 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 42 insertions(+), 1 deletion(-) diff --git a/lib/gc.cpp b/lib/gc.cpp index 6f126b5b4b6..9edb3413faf 100644 --- a/lib/gc.cpp +++ b/lib/gc.cpp @@ -19,6 +19,7 @@ limitations under the License. #include #include #endif /* HAVE_LIBGC */ +#include #include #include "log.h" #include "gc.h" @@ -33,19 +34,21 @@ limitations under the License. // One can disable the GC, e.g., to run under Valgrind, by editing config.h #if HAVE_LIBGC -static bool done_init; +static bool done_init, started_init; void *operator new(std::size_t size) { /* DANGER -- on OSX, can't safely call the garbage collector allocation * routines from a static global constructor without manually initializing * it first. Since we have global constructors that want to allocate * memory, we need to force initialization */ if (!done_init) { + started_init = true; GC_INIT(); done_init = true; } return ::operator new(size, UseGC, 0, 0); } void *operator new[](std::size_t size) { if (!done_init) { + started_init = true; GC_INIT(); done_init = true; } return ::operator new(size, UseGC, 0, 0); @@ -53,6 +56,44 @@ void *operator new[](std::size_t size) { void operator delete(void *p) _GLIBCXX_USE_NOEXCEPT { return gc::operator delete(p); } void operator delete[](void *p) _GLIBCXX_USE_NOEXCEPT { return gc::operator delete(p); } +void *realloc(void *ptr, size_t size) { + if (!done_init) { + if (started_init) { + // called from within GC_INIT, so we can't call it again. Fall back to using + // sbrk and let it leak. + size = (size + 0xf) & ~0xf; + void *rv = sbrk(size); + if (ptr) { + size_t max = reinterpret_cast(rv) - reinterpret_cast(ptr); + memcpy(rv, ptr, max < size ? max : size); } + return rv; + } else { + started_init = true; + GC_INIT(); + done_init = true; } } + if (ptr) { + if (GC_is_heap_ptr(ptr)) + return GC_realloc(ptr, size); + size_t max = reinterpret_cast(sbrk(0)) - reinterpret_cast(ptr); + void *rv = GC_malloc(size); + memcpy(rv, ptr, max < size ? max : size); + return rv; + } else { + return GC_malloc(size); + } +} +void *malloc(size_t size) { return realloc(nullptr, size); } +void free(void *ptr) { + if (done_init && GC_is_heap_ptr(ptr)) + GC_free(ptr); +} +void *calloc(size_t size, size_t elsize) { + size *= elsize; + void *rv = malloc(size); + if (rv) memset(rv, 0, size); + return rv; +} + #if HAVE_GC_PRINT_STATS /* GC_print_stats is not exported as an API symbol and cannot be used on some systems */ extern "C" int GC_print_stats; From 94e55783733be7420b8d8fd7bfc0025a3ad9033a Mon Sep 17 00:00:00 2001 From: Chris Dodd Date: Thu, 19 Dec 2019 17:06:23 -0800 Subject: [PATCH 051/106] refactoring sideEffects.cpp to fix problems (#2108) - Fix sideEffect to not pull table hit/miss out of if -- will just be converted into a (redundant) table and temp by actionSynthesis, so is a complete waste - don't introduce unnecessary block statements. - don't try to create Type_Dontcare temps - changes in expected outputs - bmv2 support "if (!table.apply().hit)" - setHeaders create a BlockStatement when needed - Merge DismantleExpression into DoSimplifyExpressions -- all one Transform pass so we can use the context. - remove unnecessary clones - avoid extra copies for return values that are just copied again. --- backends/bmv2/common/controlFlowGraph.cpp | 10 +- backends/p4test/run-p4-sample.py | 18 +- frontends/p4/setHeaders.cpp | 4 +- frontends/p4/sideEffects.cpp | 934 ++++++++---------- frontends/p4/sideEffects.h | 34 +- ir/node.h | 4 + .../09-IPv4OptionsUnparsed-frontend.p4 | 4 +- .../09-IPv4OptionsUnparsed-midend.p4 | 38 +- .../TLV_parsing-frontend.p4 | 10 +- .../TLV_parsing-midend.p4 | 20 +- .../const_default_action-frontend.p4 | 4 +- .../const_default_action-midend.p4 | 24 - .../p4_14_samples_outputs/hit-frontend.p4 | 4 +- testdata/p4_14_samples_outputs/hit-midend.p4 | 24 - .../p4_14_samples_outputs/hitmiss-frontend.p4 | 4 +- .../p4_14_samples_outputs/hitmiss-midend.p4 | 24 - .../issue576-frontend.p4 | 8 +- .../p4_14_samples_outputs/issue576-midend.p4 | 68 +- .../issue781-frontend.p4 | 4 +- .../p4_14_samples_outputs/issue781-midend.p4 | 34 +- .../p4_14_samples_outputs/miss-frontend.p4 | 4 +- testdata/p4_14_samples_outputs/miss-midend.p4 | 24 - .../p4_16_errors_outputs/issue532-frontend.p4 | 4 +- .../array_field-frontend.p4 | 7 +- .../array_field-midend.p4 | 17 +- .../array_field1-frontend.p4 | 8 +- .../array_field1-midend.p4 | 8 +- .../p4_16_samples_outputs/complex-frontend.p4 | 4 +- .../p4_16_samples_outputs/complex-midend.p4 | 4 +- .../complex1-frontend.p4 | 4 +- .../p4_16_samples_outputs/complex1-midend.p4 | 4 +- .../complex6-frontend.p4 | 12 +- .../p4_16_samples_outputs/complex6-midend.p4 | 8 +- .../p4_16_samples_outputs/exit4-frontend.p4 | 4 +- .../p4_16_samples_outputs/exit4-midend.p4 | 30 +- .../fabric_20190420/fabric-frontend.p4 | 26 +- .../fabric_20190420/fabric-midend.p4 | 102 +- .../function-frontend.p4 | 4 +- .../functors8-frontend.p4 | 4 +- .../p4_16_samples_outputs/functors8-midend.p4 | 4 +- .../functors9-frontend.p4 | 3 +- .../generic1-frontend.p4 | 7 +- .../p4_16_samples_outputs/generic1-midend.p4 | 6 +- .../hit-expr-bmv2-frontend.p4 | 4 +- .../hit-expr-bmv2-midend.p4 | 4 +- .../hit_ebpf-frontend.p4 | 4 +- .../p4_16_samples_outputs/hit_ebpf-midend.p4 | 23 +- .../inline-control-frontend.p4 | 4 +- .../inline-control-midend.p4 | 4 +- .../inline-control1-frontend.p4 | 7 +- .../inline-control1-midend.p4 | 18 +- .../inline-function-frontend.p4 | 20 +- .../inline-function-midend.p4 | 8 +- .../issue1538-frontend.p4 | 30 +- .../issue1544-1-bmv2-frontend.p4 | 4 +- .../issue1544-2-bmv2-frontend.p4 | 4 +- .../issue1544-2-frontend.p4 | 28 +- .../issue1544-2-midend.p4 | 22 +- .../issue1544-bmv2-frontend.p4 | 4 +- .../issue1781-bmv2-frontend.p4 | 6 +- .../issue2044-bmv2-frontend.p4 | 4 +- .../issue2044-bmv2-midend.p4 | 26 +- .../issue841-frontend.p4 | 4 +- .../p4_16_samples_outputs/issue841-midend.p4 | 4 +- .../issue949-frontend.p4 | 3 +- .../key-issue-1020_ebpf-frontend.p4 | 3 +- .../psa-example-parser-checksum-frontend.p4 | 4 +- .../psa-example-parser-checksum-midend.p4 | 4 +- .../psa-example-register2-bmv2-frontend.p4 | 8 +- .../psa-example-register2-bmv2-midend.p4 | 12 +- .../psa-hash-frontend.p4 | 4 +- .../p4_16_samples_outputs/psa-hash-midend.p4 | 4 +- .../psa-random-frontend.p4 | 4 +- .../psa-random-midend.p4 | 4 +- .../psa-register1-frontend.p4 | 3 +- .../side_effects-frontend.p4 | 35 +- .../side_effects-midend.p4 | 32 +- .../p4_16_samples_outputs/unused-frontend.p4 | 4 +- .../p4_16_samples_outputs/unused-midend.p4 | 4 +- .../value-sets-frontend.p4 | 4 +- .../value-sets-midend.p4 | 6 +- .../p4_16_samples_outputs/virtual-frontend.p4 | 4 +- .../p4_16_samples_outputs/virtual-midend.p4 | 4 +- .../virtual3-frontend.p4 | 4 +- .../p4_16_samples_outputs/virtual3-midend.p4 | 4 +- .../vss-example-frontend.p4 | 4 +- .../vss-example-midend.p4 | 4 +- 87 files changed, 753 insertions(+), 1213 deletions(-) diff --git a/backends/bmv2/common/controlFlowGraph.cpp b/backends/bmv2/common/controlFlowGraph.cpp index 22d78756531..9fb3278ba7f 100644 --- a/backends/bmv2/common/controlFlowGraph.cpp +++ b/backends/bmv2/common/controlFlowGraph.cpp @@ -223,6 +223,10 @@ class CFGBuilder : public Inspector { // If the expression is more complex it should have been // simplified by prior passes. auto tc = P4::TableApplySolver::isHit(statement->condition, refMap, typeMap); + bool condition = true; + if (auto *lnot = statement->condition->to()) { + if ((tc = P4::TableApplySolver::isHit(lnot->expr, refMap, typeMap))) { + condition = false; } } CFG::Node* node; if (tc != nullptr) { // hit-miss case. @@ -233,7 +237,7 @@ class CFGBuilder : public Inspector { node->addPredecessors(live); // If branch - live = new CFG::EdgeSet(new CFG::Edge(node, true)); + live = new CFG::EdgeSet(new CFG::Edge(node, condition)); visit(statement->ifTrue); auto afterTrue = live; if (afterTrue == nullptr) @@ -242,12 +246,12 @@ class CFGBuilder : public Inspector { auto result = new CFG::EdgeSet(afterTrue); // Else branch if (statement->ifFalse != nullptr) { - live = new CFG::EdgeSet(new CFG::Edge(node, false)); + live = new CFG::EdgeSet(new CFG::Edge(node, !condition)); visit(statement->ifFalse); result->mergeWith(live); } else { // no else branch - result->mergeWith(new CFG::EdgeSet(new CFG::Edge(node, false))); + result->mergeWith(new CFG::EdgeSet(new CFG::Edge(node, !condition))); } live = result; return false; diff --git a/backends/p4test/run-p4-sample.py b/backends/p4test/run-p4-sample.py index c806a7238c8..7968c3cfb20 100755 --- a/backends/p4test/run-p4-sample.py +++ b/backends/p4test/run-p4-sample.py @@ -43,6 +43,7 @@ def __init__(self): self.dumpToJson = False self.compilerOptions = [] self.runDebugger = False + self.runDebugger_skip = 0 self.generateP4Runtime = False def usage(options): @@ -144,6 +145,12 @@ def recompile_file(options, produced, mustBeIdentical): secondFile = produced + "-x"; args = ["./p4test", "-I.", "--pp", secondFile, "--std", "p4-16", produced] + \ options.compilerOptions + if options.runDebugger: + if options.runDebugger_skip > 0: + options.runDebugger_skip = options.runDebugger_skip - 1 + else: + args[0:0] = options.runDebugger.split() + os.execvp(args[0], args) result = run_timeout(options, args, timeout, None) if result != SUCCESS: return result @@ -245,8 +252,11 @@ def getArch(path): args.extend(["--std", "p4-14"]); args.extend(argv) if options.runDebugger: - args[0:0] = options.runDebugger.split() - os.execvp(args[0], args) + if options.runDebugger_skip > 0: + options.runDebugger_skip = options.runDebugger_skip - 1 + else: + args[0:0] = options.runDebugger.split() + os.execvp(args[0], args) result = run_timeout(options, args, timeout, stderr) if result != SUCCESS: @@ -336,8 +346,10 @@ def main(argv): argv = argv[1:] elif argv[0][1] == 'D' or argv[0][1] == 'I' or argv[0][1] == 'T': options.compilerOptions.append(argv[0]) - elif argv[0] == "-gdb": + elif argv[0][0:4] == "-gdb": options.runDebugger = "gdb --args" + if len(argv[0]) > 4: + options.runDebugger_skip = int(argv[0][4:]) - 1 elif argv[0] == "--p4runtime": options.generateP4Runtime = True else: diff --git a/frontends/p4/setHeaders.cpp b/frontends/p4/setHeaders.cpp index f2823696fd5..93dea61f69c 100644 --- a/frontends/p4/setHeaders.cpp +++ b/frontends/p4/setHeaders.cpp @@ -68,13 +68,13 @@ void DoSetHeaders::generateSetValid( } const IR::Node* DoSetHeaders::postorder(IR::AssignmentStatement* statement) { - auto vec = new IR::Vector(); + auto vec = new IR::IndexedVector(); auto destType = typeMap->getType(statement->left, true); generateSetValid(statement->left, statement->right, destType, vec); if (vec->empty()) return statement; vec->push_back(statement); - return vec; + return new IR::BlockStatement(statement->srcInfo, *vec); } } // namespace P4 diff --git a/frontends/p4/sideEffects.cpp b/frontends/p4/sideEffects.cpp index 4e17874a6f4..08f5a592bc5 100644 --- a/frontends/p4/sideEffects.cpp +++ b/frontends/p4/sideEffects.cpp @@ -21,518 +21,413 @@ limitations under the License. namespace P4 { -namespace { - -/** Data structure used for making the order of evaluation explicit for - * sub-expressions in an expression. An expression ```e``` will be represented - * as a sequence of temporary declarations, followed by a sequence of - * statements (mostly assignments to the temporaries, but which could also - * include conditionals for short-circuit evaluation). - */ -struct EvaluationOrder { - ReferenceMap* refMap; - - /// Output: An expression whose evaluation will produce the same result as - /// the original one, but where side-effects have been factored out such - /// that each statement produces at most one side-effect. - const IR::Expression* final; - - // Declaration instead of Declaration_Variable so it can be more easily inserted - // in the program IR. - IR::IndexedVector *temporaries; - IR::IndexedVector *statements; - - explicit EvaluationOrder(ReferenceMap* refMap) : - refMap(refMap), final(nullptr), - temporaries(new IR::IndexedVector()), - statements(new IR::IndexedVector()) - { CHECK_NULL(refMap); } - - bool simple() const - { return temporaries->empty() && statements->empty(); } - - cstring createTemporary(const IR::Type* type) { - type = type->getP4Type(); - auto tmp = refMap->newName("tmp"); - auto decl = new IR::Declaration_Variable(IR::ID(tmp, nullptr), type); - temporaries->push_back(decl); - return tmp; - } +cstring DoSimplifyExpressions::createTemporary(const IR::Type* type) { + type = type->getP4Type(); + BUG_CHECK(!type->is(), "Can't create don't-care temps"); + auto tmp = refMap->newName("tmp"); + auto decl = new IR::Declaration_Variable(IR::ID(tmp, nullptr), type); + toInsert.push_back(decl); + return tmp; +} - /** Add ```@varName = @expression``` to the vector of statements. - * - * @return A copy of the l-value expression created for varName. - */ - const IR::Expression* addAssignment( - Util::SourceInfo srcInfo, - cstring varName, - const IR::Expression* expression) { - auto left = new IR::PathExpression(IR::ID(varName, nullptr)); - auto stat = new IR::AssignmentStatement(srcInfo, left, expression); - statements->push_back(stat); - auto result = left->clone(); - return result; - } -}; - -/** @brief Replaces expressions containing constructor or method invocations - * with temporaries. Also unrolls short-circuit evaluation. - * - * The EvaluationOrder field accumulates lists of the temporaries introduced in - * this way, as well as assignment statements that assign the original - * expressions to the appropriate temporaries. - * - * The DoSimplifyExpressions pass will later insert the declarations and - * assignments above the expression. - * - * @pre An up-to-date ReferenceMap and TypeMap. - * - * @post The RefenceMap and TypeMap are updated to reflect changes to the IR. - * This includes extra information stored in the TypeMap, specifically - * left-value-ness and compile-time-contant-ness. - */ -class DismantleExpression : public Transform { - ReferenceMap* refMap; - TypeMap* typeMap; - EvaluationOrder *result; - - /// true when we are dismantling a left-value. - bool leftValue; - - /// true when the caller does not want the result (i.e., - /// we are invoked from a MethodCallStatement). - bool resultNotUsed; - - // catch-all case - const IR::Node* postorder(IR::Expression* expression) override { - LOG3("Visiting " << dbp(expression)); - auto orig = getOriginal(); - auto type = typeMap->getType(orig, true); - typeMap->setType(expression, type); - if (typeMap->isLeftValue(orig)) - typeMap->setLeftValue(expression); - if (typeMap->isCompileTimeConstant(orig)) - typeMap->setCompileTimeConstant(expression); - result->final = expression; - return result->final; - } +/** Add ```@varName = @expression``` to the vector of statements. + * + * @return A copy of the l-value expression created for varName. + */ +const IR::Expression* DoSimplifyExpressions::addAssignment( + Util::SourceInfo srcInfo, + cstring varName, + const IR::Expression* expression) { + auto left = new IR::PathExpression(IR::ID(varName, nullptr)); + auto stat = new IR::AssignmentStatement(srcInfo, left, expression); + statements.push_back(stat); + auto result = left->clone(); + return result; +} - const IR::Node* preorder(IR::Literal* expression) override { - result->final = expression; - prune(); - return expression; - } +// catch-all case +const IR::Node* DoSimplifyExpressions::postorder(IR::Expression* expression) { + LOG3("Visiting " << dbp(expression)); + auto orig = getOriginal(); + auto type = typeMap->getType(orig, true); + typeMap->setType(expression, type); + if (typeMap->isLeftValue(orig)) + typeMap->setLeftValue(expression); + if (typeMap->isCompileTimeConstant(orig)) + typeMap->setCompileTimeConstant(expression); + return expression; +} - const IR::Node* preorder(IR::ArrayIndex* expression) override { - LOG3("Visiting " << dbp(expression)); - auto type = typeMap->getType(getOriginal(), true); - if (!SideEffects::check(getOriginal(), refMap, typeMap)) { - result->final = expression; - } else { - visit(expression->left); - auto left = result->final; - CHECK_NULL(left); - bool save = leftValue; - leftValue = false; - visit(expression->right); - auto right = result->final; - CHECK_NULL(right); - leftValue = save; - if (!right->is()) { - auto indexType = typeMap->getType(expression->right, true); - auto tmp = result->createTemporary(indexType); - right = result->addAssignment(expression->srcInfo, tmp, right); - typeMap->setType(right, indexType); - } +const IR::Node* DoSimplifyExpressions::preorder(IR::Literal* expression) { + prune(); + return expression; +} - result->final = new IR::ArrayIndex(expression->srcInfo, left, right); +const IR::Node* DoSimplifyExpressions::preorder(IR::ArrayIndex* expression) { + LOG3("Visiting " << dbp(expression)); + auto type = typeMap->getType(getOriginal(), true); + if (SideEffects::check(getOriginal(), refMap, typeMap)) { + visit(expression->left); + CHECK_NULL(expression->left); + visit(expression->right); + CHECK_NULL(expression->right); + if (!expression->right->is()) { + auto indexType = typeMap->getType(expression->right, true); + auto tmp = createTemporary(indexType); + expression->right = addAssignment(expression->srcInfo, tmp, expression->right); + typeMap->setType(expression->right, indexType); } - typeMap->setType(result->final, type); - if (leftValue) - typeMap->setLeftValue(result->final); - prune(); - return result->final; } + typeMap->setType(expression, type); + if (isWrite()) + typeMap->setLeftValue(expression); + prune(); + return expression; +} - const IR::Node* preorder(IR::Member* expression) override { - LOG3("Visiting " << dbp(expression)); - auto type = typeMap->getType(getOriginal(), true); - if (!SideEffects::check(getOriginal(), refMap, typeMap)) { - result->final = expression; - } else { - visit(expression->expr); - auto left = result->final; - CHECK_NULL(left); - result->final = new IR::Member(expression->srcInfo, left, expression->member); - typeMap->setType(result->final, type); - if (leftValue) - typeMap->setLeftValue(result->final); - - // Special case for table.apply().hit/miss, which is not dismantled by - // the MethodCallExpression. - if (TableApplySolver::isHit(expression, refMap, typeMap) || - TableApplySolver::isMiss(expression, refMap, typeMap)) { +static bool isIfContext(const Visitor::Context *ctxt) { + if (ctxt && ctxt->node->is()) + ctxt = ctxt->parent; + return ctxt && ctxt->node->is(); +} + +const IR::Node* DoSimplifyExpressions::preorder(IR::Member* expression) { + LOG3("Visiting " << dbp(expression)); + auto type = typeMap->getType(getOriginal(), true); + const IR::Expression *rv = expression; + if (SideEffects::check(getOriginal(), refMap, typeMap)) { + visit(expression->expr); + CHECK_NULL(expression->expr); + + // Special case for table.apply().hit/miss, which is not dismantled by + // the MethodCallExpression. + if (TableApplySolver::isHit(expression, refMap, typeMap) || + TableApplySolver::isMiss(expression, refMap, typeMap)) { + if (isIfContext(getContext())) { + /* if the hit/miss test is directly in an "if", don't bother cloning it + * as that will just create a redundant table later */ + } else if (getParent()) { + /* already assigning it somewhere -- no need to add another copy */ + } else { BUG_CHECK(type->is(), "%1%: not boolean", type); - auto tmp = result->createTemporary(type); + auto tmp = createTemporary(type); auto path = new IR::PathExpression(IR::ID(tmp, nullptr)); - auto stat = new IR::AssignmentStatement(path, result->final); - result->statements->push_back(stat); - result->final = path->clone(); - typeMap->setType(result->final, type); + auto stat = new IR::AssignmentStatement(path, expression); + statements.push_back(stat); + typeMap->setType(expression, type); + rv = path->clone();; } - prune(); - return result->final; } - typeMap->setType(result->final, type); - if (leftValue) - typeMap->setLeftValue(result->final); - prune(); - return result->final; } + typeMap->setType(rv, type); + if (isWrite()) + typeMap->setLeftValue(rv); + prune(); + return rv; +} - const IR::Node* preorder(IR::SelectExpression* expression) override { - LOG3("Visiting " << dbp(expression)); - visit(expression->select); - prune(); - result->final = expression; - return expression; - } +const IR::Node* DoSimplifyExpressions::preorder(IR::SelectExpression* expression) { + LOG3("Visiting " << dbp(expression)); + visit(expression->select); + prune(); + return expression; +} - const IR::Node* preorder(IR::Operation_Unary* expression) override { - LOG3("Visiting " << dbp(expression)); - auto type = typeMap->getType(getOriginal(), true); - visit(expression->expr); - auto left = result->final; - CHECK_NULL(left); - auto clone = expression->clone(); - clone->expr = left; - typeMap->setType(clone, type); - result->final = clone; - prune(); - return result->final; - } +const IR::Node* DoSimplifyExpressions::preorder(IR::Operation_Unary* expression) { + LOG3("Visiting " << dbp(expression)); + auto type = typeMap->getType(getOriginal(), true); + visit(expression->expr); + CHECK_NULL(expression->expr); + typeMap->setType(expression, type); + prune(); + return expression; +} - const IR::Node* preorder(IR::Operation_Binary* expression) override { - LOG3("Visiting " << dbp(expression)); - auto type = typeMap->getType(getOriginal(), true); - if (!SideEffects::check(getOriginal(), refMap, typeMap)) { - result->final = expression; - } else { - visit(expression->left); - auto left = result->final; - CHECK_NULL(left); - visit(expression->right); - auto right = result->final; - auto clone = expression->clone(); - clone->left = left; - clone->right = right; - typeMap->setType(clone, type); - auto tmp = result->createTemporary(type); - auto path = result->addAssignment(expression->srcInfo, tmp, clone); - result->final = path; - } - typeMap->setType(result->final, type); +const IR::Node* DoSimplifyExpressions::preorder(IR::Operation_Binary* expression) { + LOG3("Visiting " << dbp(expression)); + auto type = typeMap->getType(getOriginal(), true); + if (SideEffects::check(getOriginal(), refMap, typeMap)) { + visit(expression->left); + CHECK_NULL(expression->left); + visit(expression->right); + typeMap->setType(expression, type); + auto tmp = createTemporary(type); + auto path = addAssignment(expression->srcInfo, tmp, expression); + typeMap->setType(path, type); prune(); - return result->final; + return path; } + typeMap->setType(expression, type); + prune(); + return expression; +} - const IR::Node* shortCircuit(IR::Operation_Binary* expression) { - LOG3("Visiting " << dbp(expression)); - auto type = typeMap->getType(getOriginal(), true); - if (!SideEffects::check(getOriginal(), refMap, typeMap)) { - result->final = expression; - } else { - visit(expression->left); - auto cond = result->final; - CHECK_NULL(cond); - - // e1 && e2 - // becomes roughly: - // if (!simplify(e1)) - // tmp = false; - // else - // tmp = simplify(e2); - - bool land = expression->is(); - auto constant = new IR::BoolLiteral(!land); - auto tmp = result->createTemporary(type); - auto ifTrue = new IR::AssignmentStatement(expression->srcInfo, - new IR::PathExpression(IR::ID(tmp, nullptr)), constant); - auto ifFalse = new IR::IndexedVector(); - - auto save = result->statements; - result->statements = ifFalse; - visit(expression->right); - auto path = result->addAssignment(expression->srcInfo, tmp, result->final); - result->statements = save; - if (land) { - cond = new IR::LNot(cond); - typeMap->setType(cond, type); - } - auto block = new IR::BlockStatement(*ifFalse); - auto ifStatement = new IR::IfStatement(expression->srcInfo, cond, ifTrue, block); - result->statements->push_back(ifStatement); - result->final = path->clone(); +const IR::Node* DoSimplifyExpressions::shortCircuit(IR::Operation_Binary* expression) { + LOG3("Visiting " << dbp(expression)); + auto type = typeMap->getType(getOriginal(), true); + if (SideEffects::check(getOriginal(), refMap, typeMap)) { + visit(expression->left); + CHECK_NULL(expression->left); + + // e1 && e2 + // becomes roughly: + // if (!simplify(e1)) + // tmp = false; + // else + // tmp = simplify(e2); + + bool land = expression->is(); + auto constant = new IR::BoolLiteral(!land); + auto tmp = createTemporary(type); + auto ifTrue = new IR::AssignmentStatement(expression->srcInfo, + new IR::PathExpression(IR::ID(tmp, nullptr)), constant); + + auto save = statements; + statements.clear(); + visit(expression->right); + auto path = addAssignment(expression->srcInfo, tmp, expression->right); + auto ifFalse = statements; + statements = save; + if (land) { + expression->left = new IR::LNot(expression->left); + typeMap->setType(expression->left, type); } - typeMap->setType(result->final, type); + auto block = new IR::BlockStatement(ifFalse); + auto ifStatement = new IR::IfStatement(expression->srcInfo, + expression->left, ifTrue, block); + statements.push_back(ifStatement); + typeMap->setType(path, type); prune(); - return result->final; + return path; } + typeMap->setType(expression, type); + prune(); + return expression; +} - const IR::Node* preorder(IR::Mux* expression) override { - // We always dismantle muxes - some architectures may not support them - LOG3("Visiting " << dbp(expression)); - auto type = typeMap->getType(getOriginal(), true); - visit(expression->e0); - auto e0 = result->final; - CHECK_NULL(e0); - auto tmp = result->createTemporary(type); - - auto save = result->statements; - auto ifTrue = new IR::IndexedVector(); - result->statements = ifTrue; - visit(expression->e1); - (void)result->addAssignment(expression->srcInfo, tmp, result->final); - - auto ifFalse = new IR::IndexedVector(); - result->statements = ifFalse; - visit(expression->e2); - auto path = result->addAssignment(expression->srcInfo, tmp, result->final); - result->statements = save; - - auto ifStatement = new IR::IfStatement( - e0, new IR::BlockStatement(*ifTrue), new IR::BlockStatement(*ifFalse)); - result->statements->push_back(ifStatement); - result->final = path->clone(); - typeMap->setType(result->final, type); - prune(); - return result->final; - } +const IR::Node* DoSimplifyExpressions::preorder(IR::Mux* expression) { + // We always dismantle muxes - some architectures may not support them + LOG3("Visiting " << dbp(expression)); + auto type = typeMap->getType(getOriginal(), true); + visit(expression->e0); + CHECK_NULL(expression->e0); + auto tmp = createTemporary(type); + + auto save = statements; + statements.clear(); + visit(expression->e1); + (void)addAssignment(expression->srcInfo, tmp, expression->e1); + auto ifTrue = statements; + + statements.clear(); + visit(expression->e2); + auto path = addAssignment(expression->srcInfo, tmp, expression->e2); + auto ifFalse = statements; + statements = save; + + auto ifStatement = new IR::IfStatement( + expression->e0, new IR::BlockStatement(ifTrue), new IR::BlockStatement(ifFalse)); + statements.push_back(ifStatement); + typeMap->setType(path, type); + prune(); + return path; +} - const IR::Node* preorder(IR::LAnd* expression) override { return shortCircuit(expression); } - const IR::Node* preorder(IR::LOr* expression) override { return shortCircuit(expression); } +const IR::Node* DoSimplifyExpressions::preorder(IR::LAnd* expression) { + return shortCircuit(expression); } +const IR::Node* DoSimplifyExpressions::preorder(IR::LOr* expression) { + return shortCircuit(expression); } - bool mayAlias(const IR::Expression* left, const IR::Expression* right) const { - ReadsWrites rw(refMap, true); - return rw.mayAlias(left, right); - } +bool DoSimplifyExpressions::mayAlias(const IR::Expression* left, + const IR::Expression* right) const { + ReadsWrites rw(refMap, true); + return rw.mayAlias(left, right); +} - /// Returns true if type is a header or a struct containing a header. - /// (We don't care about stacks or unions.) - bool containsHeaderType(const IR::Type* type) { - if (type->is()) - return true; - auto st = type->to(); - if (st == nullptr) - return false; - for (auto f : st->fields) { - auto ftype = typeMap->getType(f, true); - if (containsHeaderType(ftype)) - return true; - } +/// Returns true if type is a header or a struct containing a header. +/// (We don't care about stacks or unions.) +bool DoSimplifyExpressions::containsHeaderType(const IR::Type* type) { + if (type->is()) + return true; + auto st = type->to(); + if (st == nullptr) return false; + for (auto f : st->fields) { + auto ftype = typeMap->getType(f, true); + if (containsHeaderType(ftype)) + return true; } + return false; +} - const IR::Node* preorder(IR::MethodCallExpression* mce) override { - BUG_CHECK(!leftValue, "%1%: method on left hand side?", mce); - LOG3("Visiting " << dbp(mce)); - auto orig = getOriginal(); - auto type = typeMap->getType(orig, true); - if (!SideEffects::check(orig, refMap, typeMap)) { - result->final = mce; - return mce; - } +const IR::Node* DoSimplifyExpressions::preorder(IR::MethodCallExpression* mce) { + BUG_CHECK(!isWrite(), "%1%: method on left hand side?", mce); + LOG3("Visiting " << dbp(mce)); + auto orig = getOriginal(); + auto type = typeMap->getType(orig, true); + if (!SideEffects::check(orig, refMap, typeMap)) { + return mce; + } - auto copyBack = new IR::IndexedVector(); - auto args = new IR::Vector(); - auto mi = MethodInstance::resolve(orig, refMap, typeMap); - bool savelv = leftValue; - bool savenu = resultNotUsed; - resultNotUsed = false; - - // If a parameter is in this set then we use a temporary to - // copy the corresponding argument. We could always use - // temporaries for arguments - it is always correct - but this - // could entail the creation of "fat" temporaries that contain - // large structs. We want to avoid copying these large - // structs if possible. - std::set useTemporary; - - bool anyOut = false; - for (auto p : *mi->substitution.getParametersInArgumentOrder()) { - if (p->direction == IR::Direction::None) - continue; - if (p->hasOut()) - anyOut = true; - auto arg = mi->substitution.lookup(p); - // If an argument evaluation has side-effects then - // always use a temporary to hold the argument value. - if (SideEffects::check(arg->expression, refMap, typeMap)) { - LOG3("Using temporary for " << dbp(mce) << - " param " << dbp(p) << " arg side effect"); - useTemporary.emplace(p); - continue; - } - // If the parameter contains header values and the - // argument is a list expression or a struct initializer - // then we also use a temporary. This makes the job of - // the SetHeaders pass later simpler (otherwise we have to - // handle this case there). - auto ptype = typeMap->getType(p, true); - if (!containsHeaderType(ptype)) - continue; - - if (arg->expression->is() || - arg->expression->is()) { - LOG3("Using temporary for " << dbp(mce) << - " param " << dbp(p) << " assigning tuple to header"); - useTemporary.emplace(p); - continue; - } + auto copyBack = new IR::IndexedVector(); + auto args = new IR::Vector(); + auto mi = MethodInstance::resolve(orig, refMap, typeMap); + + // If a parameter is in this set then we use a temporary to + // copy the corresponding argument. We could always use + // temporaries for arguments - it is always correct - but this + // could entail the creation of "fat" temporaries that contain + // large structs. We want to avoid copying these large + // structs if possible. + std::set useTemporary; + + bool anyOut = false; + for (auto p : *mi->substitution.getParametersInArgumentOrder()) { + if (p->direction == IR::Direction::None) + continue; + if (p->hasOut()) + anyOut = true; + auto arg = mi->substitution.lookup(p); + // If an argument evaluation has side-effects then + // always use a temporary to hold the argument value. + if (SideEffects::check(arg->expression, refMap, typeMap)) { + LOG3("Using temporary for " << dbp(mce) << + " param " << dbp(p) << " arg side effect"); + useTemporary.emplace(p); + continue; + } + // If the parameter contains header values and the + // argument is a list expression or a struct initializer + // then we also use a temporary. This makes the job of + // the SetHeaders pass later simpler (otherwise we have to + // handle this case there). + auto ptype = typeMap->getType(p, true); + if (!containsHeaderType(ptype)) + continue; + + if (arg->expression->is() || + arg->expression->is()) { + LOG3("Using temporary for " << dbp(mce) << + " param " << dbp(p) << " assigning tuple to header"); + useTemporary.emplace(p); + continue; } + } - if (anyOut) { - // Check aliasing between all pairs of arguments where at - // least one of them is out or inout. - for (auto p1 : *mi->substitution.getParametersInArgumentOrder()) { - auto arg1 = mi->substitution.lookup(p1); - for (auto p2 : *mi->substitution.getParametersInArgumentOrder()) { - if (p2 == p1) - break; - if (!p1->hasOut() && !p2->hasOut()) - continue; - if (useTemporary.find(p1) != useTemporary.end()) - continue; - if (useTemporary.find(p2) != useTemporary.end()) - continue; - auto arg2 = mi->substitution.lookup(p2); - if (mayAlias(arg1->expression, arg2->expression)) { - LOG3("Using temporary for " << dbp(mce) << - " param " << dbp(p1) << " aliasing" << dbp(p2)); - useTemporary.emplace(p1); - useTemporary.emplace(p2); - break; - } + if (anyOut) { + // Check aliasing between all pairs of arguments where at + // least one of them is out or inout. + for (auto p1 : *mi->substitution.getParametersInArgumentOrder()) { + auto arg1 = mi->substitution.lookup(p1); + for (auto p2 : *mi->substitution.getParametersInArgumentOrder()) { + if (p2 == p1) + break; + if (!p1->hasOut() && !p2->hasOut()) + continue; + if (useTemporary.find(p1) != useTemporary.end()) + continue; + if (useTemporary.find(p2) != useTemporary.end()) + continue; + auto arg2 = mi->substitution.lookup(p2); + if (mayAlias(arg1->expression, arg2->expression)) { + LOG3("Using temporary for " << dbp(mce) << + " param " << dbp(p1) << " aliasing" << dbp(p2)); + useTemporary.emplace(p1); + useTemporary.emplace(p2); + break; } } } + } - visit(mce->method); - auto method = result->final; + visit(mce->method); - ClonePathExpressions cloner; // a cheap version of deep copy - for (auto p : *mi->substitution.getParametersInArgumentOrder()) { - auto arg = mi->substitution.lookup(p); - if (p->direction == IR::Direction::None) { - args->push_back(arg); - continue; - } + ClonePathExpressions cloner; // a cheap version of deep copy + for (auto p : *mi->substitution.getParametersInArgumentOrder()) { + auto arg = mi->substitution.lookup(p); + if (p->direction == IR::Direction::None) { + args->push_back(arg); + continue; + } + + bool useTemp = useTemporary.count(p) != 0; + LOG3("Transforming " << dbp(arg) << " for " << dbp(p) << + (useTemp ? " with " : " without ") << "temporary"); - bool useTemp = useTemporary.count(p) != 0; - LOG3("Transforming " << dbp(arg) << " for " << dbp(p) << - (useTemp ? " with " : " without ") << "temporary"); + const IR::Expression* argValue = nullptr; + visit(arg); // May mutate arg! Recursively simplifies arg. + auto newarg = arg->expression; + CHECK_NULL(newarg); - if (p->direction == IR::Direction::In) - leftValue = false; - else - leftValue = true; + if (useTemp) { + // declare temporary variable auto paramtype = typeMap->getType(p, true); - const IR::Expression* argValue; - visit(arg); // May mutate arg! Recursively simplifies arg. - auto newarg = result->final; - CHECK_NULL(newarg); - - if (useTemp) { - // declare temporary variable - auto tmp = refMap->newName("tmp"); - argValue = new IR::PathExpression(IR::ID(tmp, nullptr)); - auto decl = new IR::Declaration_Variable( - IR::ID(tmp, nullptr), paramtype->getP4Type()); - result->temporaries->push_back(decl); - if (p->direction != IR::Direction::Out) { - auto clone = argValue->clone(); - auto stat = new IR::AssignmentStatement(clone, newarg); - LOG3(clone << " = " << newarg); - result->statements->push_back(stat); - typeMap->setType(clone, paramtype); - typeMap->setLeftValue(clone); - } - } else { - argValue = newarg; + if (paramtype->is()) + paramtype = typeMap->getType(arg, true); + auto tmp = createTemporary(paramtype); + argValue = new IR::PathExpression(IR::ID(tmp, nullptr)); + if (p->direction != IR::Direction::Out) { + auto clone = argValue->clone(); + auto stat = new IR::AssignmentStatement(clone, newarg); + LOG3(clone << " = " << newarg); + statements.push_back(stat); + typeMap->setType(clone, paramtype); + typeMap->setLeftValue(clone); } - if (leftValue && useTemp) { - auto assign = new IR::AssignmentStatement( - cloner.clone(newarg), - cloner.clone(argValue)); - copyBack->push_back(assign); - LOG3("Will copy out value " << dbp(assign)); - } - args->push_back(new IR::Argument(arg->name, argValue)); - } - leftValue = savelv; - resultNotUsed = savenu; - - // Special handling for table.apply(...).X; we cannot generate - // a temporary for the method call tmp = table.apply(), since - // we cannot write down the type of tmp. So we don't - // dismantle these expressions. - bool tbl_apply = false; - if (auto mmbr = getParent()) { - auto tbl = TableApplySolver::isActionRun(mmbr, refMap, typeMap); - auto tbl1 = TableApplySolver::isHit(mmbr, refMap, typeMap); - auto tbl2 = TableApplySolver::isMiss(mmbr, refMap, typeMap); - tbl_apply = tbl != nullptr || tbl1 != nullptr || tbl2 != nullptr; - } - // Simplified method call, with arguments substituted - auto simplified = new IR::MethodCallExpression( - mce->srcInfo, method, mce->typeArguments, args); - typeMap->setType(simplified, type); - result->final = simplified; - // See whether we assign the result of the call to a temporary - if (!type->is() && // no return type - !tbl_apply && // not a table.apply call - !resultNotUsed) { // result of call is not used - auto tmp = refMap->newName("tmp"); - auto decl = new IR::Declaration_Variable(IR::ID(tmp, nullptr), type); - result->temporaries->push_back(decl); - auto left = new IR::PathExpression(IR::ID(tmp, nullptr)); - auto stat = new IR::AssignmentStatement(left, simplified); - result->statements->push_back(stat); - result->final = left->clone(); - typeMap->setType(result->final, type); - LOG3(mce << " replaced with " << left << " = " << simplified); } else { - if (tbl_apply) { - result->final = simplified; - } else { - result->statements->push_back( - new IR::MethodCallStatement(mce->srcInfo, simplified)); - result->final = nullptr; - } + argValue = newarg; } - result->statements->append(*copyBack); - prune(); - return result->final; + if (p->direction != IR::Direction::In && useTemp) { + auto assign = new IR::AssignmentStatement( + cloner.clone(newarg), + cloner.clone(argValue)); + copyBack->push_back(assign); + LOG3("Will copy out value " << dbp(assign)); + } + args->push_back(new IR::Argument(arg->name, argValue)); } - public: - DismantleExpression(ReferenceMap* refMap, TypeMap* typeMap) : - refMap(refMap), typeMap(typeMap), leftValue(false) { - CHECK_NULL(refMap); CHECK_NULL(typeMap); - result = new EvaluationOrder(refMap); - setName("DismantleExpressions"); + // Special handling for table.apply(...).X; we cannot generate + // a temporary for the method call tmp = table.apply(), since + // we cannot write down the type of tmp. So we don't + // dismantle these expressions. + bool tbl_apply = false; + if (auto mmbr = getParent()) { + auto tbl = TableApplySolver::isActionRun(mmbr, refMap, typeMap); + auto tbl1 = TableApplySolver::isHit(mmbr, refMap, typeMap); + auto tbl2 = TableApplySolver::isMiss(mmbr, refMap, typeMap); + tbl_apply = tbl != nullptr || tbl1 != nullptr || tbl2 != nullptr; } - EvaluationOrder* dismantle(const IR::Expression* expression, - bool isLeftValue, bool resultNotUsed = false) { - LOG3("Dismantling " << dbp(expression) << (isLeftValue ? " on left" : " on right")); - leftValue = isLeftValue; - this->resultNotUsed = resultNotUsed; - (void)expression->apply(*this); - LOG3("Result is " << result->final); - return result; + // Simplified method call, with arguments substituted + if (!IR::equiv(mce->arguments, args)) + mce->arguments = args; + typeMap->setType(mce, type); + const IR::Expression *rv = mce; + // See whether we assign the result of the call to a temporary + if (type->is() || // no return type + getParent()) { // result of call is not used + statements.push_back(new IR::MethodCallStatement(mce->srcInfo, mce)); + rv = nullptr; + } else if (tbl_apply) { + typeMap->setType(mce, type); + rv = mce; + } else if (getParent() && copyBack->empty()) { + /* no need for an extra copy as there's no out args to copy back afterwards */ + typeMap->setType(mce, type); + rv = mce; + } else { + auto tmp = createTemporary(type); + auto left = new IR::PathExpression(IR::ID(tmp, nullptr)); + auto stat = new IR::AssignmentStatement(left, mce); + statements.push_back(stat); + rv = left->clone(); + typeMap->setType(rv, type); + LOG3(orig << " replaced with " << left << " = " << mce); } -}; -} // namespace + statements.append(*copyBack); + prune(); + return rv; +} const IR::Node* DoSimplifyExpressions::postorder(IR::Function* function) { if (toInsert.empty()) @@ -579,83 +474,72 @@ const IR::Node* DoSimplifyExpressions::postorder(IR::P4Action* action) { const IR::Node* DoSimplifyExpressions::postorder(IR::ParserState* state) { if (state->selectExpression == nullptr) return state; - DismantleExpression dm(refMap, typeMap); - auto parts = dm.dismantle(state->selectExpression, false); - CHECK_NULL(parts); - if (parts->simple()) - return state; - toInsert.append(*parts->temporaries); - state->components.append(*parts->statements); - state->selectExpression = parts->final; + state->components.append(statements); + statements.clear(); return state; } const IR::Node* DoSimplifyExpressions::postorder(IR::AssignmentStatement* statement) { - DismantleExpression dm(refMap, typeMap); - auto left = dm.dismantle(statement->left, true)->final; - CHECK_NULL(left); - auto parts = dm.dismantle(statement->right, false); - CHECK_NULL(parts); - toInsert.append(*parts->temporaries); - auto right = parts->final; - CHECK_NULL(right); - parts->statements->push_back(new IR::AssignmentStatement(statement->srcInfo, left, right)); - auto block = new IR::BlockStatement(*parts->statements); + if (statements.empty()) + return statement; + statements.push_back(statement); + auto block = new IR::BlockStatement(statements); + statements.clear(); return block; } const IR::Node* DoSimplifyExpressions::postorder(IR::MethodCallStatement* statement) { - DismantleExpression dm(refMap, typeMap); - auto parts = dm.dismantle(statement->methodCall, false, true); - CHECK_NULL(parts); - if (parts->simple()) - return statement; - toInsert.append(*parts->temporaries); - auto block = new IR::BlockStatement(*parts->statements); + if (statements.empty()) { + BUG_CHECK(statement->methodCall, "NULL methodCall?"); + return statement; } + if (statement->methodCall) + statements.push_back(statement); + if (statements.size() == 1) { + auto rv = statements.front(); + statements.clear(); + return rv; } + auto block = new IR::BlockStatement(statements); + statements.clear(); return block; } const IR::Node* DoSimplifyExpressions::postorder(IR::ReturnStatement* statement) { - if (statement->expression == nullptr) - return statement; - DismantleExpression dm(refMap, typeMap); - auto parts = dm.dismantle(statement->expression, false); - CHECK_NULL(parts); - if (parts->simple()) + if (statements.empty()) return statement; - toInsert.append(*parts->temporaries); - auto expr = parts->final; - parts->statements->push_back(new IR::ReturnStatement(statement->srcInfo, expr)); - auto block = new IR::BlockStatement(*parts->statements); + statements.push_back(statement); + auto block = new IR::BlockStatement(statements); + statements.clear(); return block; } -const IR::Node* DoSimplifyExpressions::postorder(IR::IfStatement* statement) { - DismantleExpression dm(refMap, typeMap); - auto parts = dm.dismantle(statement->condition, false); - CHECK_NULL(parts); - if (parts->simple()) - return statement; - toInsert.append(*parts->temporaries); - auto expr = parts->final; - parts->statements->push_back(new IR::IfStatement(statement->srcInfo, expr, - statement->ifTrue, statement->ifFalse)); - auto block = new IR::BlockStatement(*parts->statements); - return block; +const IR::Node* DoSimplifyExpressions::preorder(IR::IfStatement* statement) { + IR::Statement *rv = statement; + visit(statement->condition, "condition"); + if (!statements.empty()) { + statements.push_back(statement); + rv = new IR::BlockStatement(statements); + statements.clear(); } + visit(statement->ifTrue, "ifTrue"); + visit(statement->ifFalse, "ifFalse"); + prune(); + return rv; } -const IR::Node* DoSimplifyExpressions::postorder(IR::SwitchStatement* statement) { - DismantleExpression dm(refMap, typeMap); - auto parts = dm.dismantle(statement->expression, false); - CHECK_NULL(parts); - if (parts->simple()) - return statement; - toInsert.append(*parts->temporaries); - auto expr = parts->final; - parts->statements->push_back( - new IR::SwitchStatement(statement->srcInfo, expr, std::move(statement->cases))); - auto block = new IR::BlockStatement(*parts->statements); - return block; +const IR::Node* DoSimplifyExpressions::preorder(IR::SwitchStatement* statement) { + IR::Statement *rv = statement; + visit(statement->expression, "expression"); + if (!statements.empty()) { + statements.push_back(statement); + rv = new IR::BlockStatement(statements); + statements.clear(); } + visit(statement->cases, "cases"); + prune(); + return rv; +} + +void DoSimplifyExpressions::end_apply(const IR::Node *) { + BUG_CHECK(toInsert.empty(), "DoSimplifyExpressions::end_apply orphaned declarations"); + BUG_CHECK(statements.empty(), "DoSimplifyExpressions::end_apply orphaned statements"); } } // namespace P4 diff --git a/frontends/p4/sideEffects.h b/frontends/p4/sideEffects.h index a19b0dea761..8ec646e5df7 100644 --- a/frontends/p4/sideEffects.h +++ b/frontends/p4/sideEffects.h @@ -117,13 +117,20 @@ a[tmp1].x = tmp4; // assign result of call of f to actual left value * For assignment statements ```e = e1;``` the left hand side is evaluated * first. */ -class DoSimplifyExpressions : public Transform { +class DoSimplifyExpressions : public Transform, P4WriteContext { // FIXME: does not handle select labels ReferenceMap* refMap; TypeMap* typeMap; - IR::IndexedVector toInsert; + IR::IndexedVector toInsert; // temporaries + IR::IndexedVector statements; + + cstring createTemporary(const IR::Type* type); + const IR::Expression* addAssignment(Util::SourceInfo srcInfo, cstring varName, + const IR::Expression* expression); + bool mayAlias(const IR::Expression* left, const IR::Expression* right) const; + bool containsHeaderType(const IR::Type* type); public: DoSimplifyExpressions(ReferenceMap* refMap, TypeMap* typeMap) @@ -132,6 +139,23 @@ class DoSimplifyExpressions : public Transform { setName("DoSimplifyExpressions"); } + const IR::Node* postorder(IR::Expression* expression) override; + const IR::Node* preorder(IR::Literal* expression) override; + const IR::Node* preorder(IR::ArrayIndex* expression) override; + const IR::Node* preorder(IR::Member* expression) override; + const IR::Node* preorder(IR::SelectExpression* expression) override; + const IR::Node* preorder(IR::Operation_Unary* expression) override; + const IR::Node* preorder(IR::Operation_Binary* expression) override; + const IR::Node* shortCircuit(IR::Operation_Binary* expression); + const IR::Node* preorder(IR::Mux* expression) override; + const IR::Node* preorder(IR::LAnd* expression) override; + const IR::Node* preorder(IR::LOr* expression) override; + const IR::Node* preorder(IR::MethodCallExpression* mce) override; + + const IR::Node* preorder(IR::ConstructorCallExpression* cce) override { prune(); return cce; } + const IR::Node* preorder(IR::Property* prop) override { prune(); return prop; } + const IR::Node* preorder(IR::Annotation* anno) override { prune(); return anno; } + const IR::Node* postorder(IR::P4Parser* parser) override; const IR::Node* postorder(IR::Function* function) override; const IR::Node* postorder(IR::P4Control* control) override; @@ -140,8 +164,10 @@ class DoSimplifyExpressions : public Transform { const IR::Node* postorder(IR::AssignmentStatement* statement) override; const IR::Node* postorder(IR::MethodCallStatement* statement) override; const IR::Node* postorder(IR::ReturnStatement* statement) override; - const IR::Node* postorder(IR::SwitchStatement* statement) override; - const IR::Node* postorder(IR::IfStatement* statement) override; + const IR::Node* preorder(IR::SwitchStatement* statement) override; + const IR::Node* preorder(IR::IfStatement* statement) override; + + void end_apply(const IR::Node *) override; }; class SideEffectOrdering : public PassManager { diff --git a/ir/node.h b/ir/node.h index 5e500380cd2..2f5d36c8707 100644 --- a/ir/node.h +++ b/ir/node.h @@ -137,6 +137,10 @@ inline bool equal(const Node *a, const Node *b) { return a == b || (a && b && *a == *b); } inline bool equal(const INode *a, const INode *b) { return a == b || (a && b && *a->getNode() == *b->getNode()); } +inline bool equiv(const Node *a, const Node *b) { + return a == b || (a && b && a->equiv(*b)); } +inline bool equiv(const INode *a, const INode *b) { + return a == b || (a && b && a->getNode()->equiv(*b->getNode())); } /* common things that ALL Node subclasses must define */ #define IRNODE_SUBCLASS(T) \ diff --git a/testdata/p4_14_samples_outputs/09-IPv4OptionsUnparsed-frontend.p4 b/testdata/p4_14_samples_outputs/09-IPv4OptionsUnparsed-frontend.p4 index 2fa0f0fa2a0..d2f37fd0b1e 100644 --- a/testdata/p4_14_samples_outputs/09-IPv4OptionsUnparsed-frontend.p4 +++ b/testdata/p4_14_samples_outputs/09-IPv4OptionsUnparsed-frontend.p4 @@ -64,7 +64,6 @@ struct headers { parser ParserImpl(packet_in packet, out headers hdr, inout metadata meta, inout standard_metadata_t standard_metadata) { ipv4_t_1 tmp_hdr_0; - ipv4_t_1 tmp; @name(".parse_ethernet") state parse_ethernet { packet.extract(hdr.ethernet); transition select(hdr.ethernet.ethertype) { @@ -74,8 +73,7 @@ parser ParserImpl(packet_in packet, out headers hdr, inout metadata meta, inout } } @name(".parse_ipv4") state parse_ipv4 { - tmp = packet.lookahead(); - tmp_hdr_0 = tmp; + tmp_hdr_0 = packet.lookahead(); packet.extract(hdr.ipv4, ((bit<32>)tmp_hdr_0.ihl << 2 << 3) + 32w4294967136); transition accept; } diff --git a/testdata/p4_14_samples_outputs/09-IPv4OptionsUnparsed-midend.p4 b/testdata/p4_14_samples_outputs/09-IPv4OptionsUnparsed-midend.p4 index d06f226c8d7..551f7b7e9e2 100644 --- a/testdata/p4_14_samples_outputs/09-IPv4OptionsUnparsed-midend.p4 +++ b/testdata/p4_14_samples_outputs/09-IPv4OptionsUnparsed-midend.p4 @@ -64,8 +64,7 @@ struct headers { parser ParserImpl(packet_in packet, out headers hdr, inout metadata meta, inout standard_metadata_t standard_metadata) { ipv4_t_1 tmp_hdr_0; - ipv4_t_1 tmp; - bit<160> tmp_0; + bit<160> tmp; @name(".parse_ethernet") state parse_ethernet { packet.extract(hdr.ethernet); transition select(hdr.ethernet.ethertype) { @@ -75,24 +74,23 @@ parser ParserImpl(packet_in packet, out headers hdr, inout metadata meta, inout } } @name(".parse_ipv4") state parse_ipv4 { - tmp_0 = packet.lookahead>(); - tmp.setValid(); - tmp.version = tmp_0[159:156]; - tmp.ihl = tmp_0[155:152]; - tmp.diffserv = tmp_0[151:144]; - tmp.totalLen = tmp_0[143:128]; - tmp.identification = tmp_0[127:112]; - tmp.reserved_0 = tmp_0[111:111]; - tmp.df = tmp_0[110:110]; - tmp.mf = tmp_0[109:109]; - tmp.fragOffset = tmp_0[108:96]; - tmp.ttl = tmp_0[95:88]; - tmp.protocol = tmp_0[87:80]; - tmp.hdrChecksum = tmp_0[79:64]; - tmp.srcAddr = tmp_0[63:32]; - tmp.dstAddr = tmp_0[31:0]; - tmp_hdr_0 = tmp; - packet.extract(hdr.ipv4, ((bit<32>)tmp_hdr_0.ihl << 2 << 3) + 32w4294967136); + tmp = packet.lookahead>(); + tmp_hdr_0.setValid(); + tmp_hdr_0.version = tmp[159:156]; + tmp_hdr_0.ihl = tmp[155:152]; + tmp_hdr_0.diffserv = tmp[151:144]; + tmp_hdr_0.totalLen = tmp[143:128]; + tmp_hdr_0.identification = tmp[127:112]; + tmp_hdr_0.reserved_0 = tmp[111:111]; + tmp_hdr_0.df = tmp[110:110]; + tmp_hdr_0.mf = tmp[109:109]; + tmp_hdr_0.fragOffset = tmp[108:96]; + tmp_hdr_0.ttl = tmp[95:88]; + tmp_hdr_0.protocol = tmp[87:80]; + tmp_hdr_0.hdrChecksum = tmp[79:64]; + tmp_hdr_0.srcAddr = tmp[63:32]; + tmp_hdr_0.dstAddr = tmp[31:0]; + packet.extract(hdr.ipv4, ((bit<32>)tmp[155:152] << 2 << 3) + 32w4294967136); transition accept; } @name(".parse_vlan_tag") state parse_vlan_tag { diff --git a/testdata/p4_14_samples_outputs/TLV_parsing-frontend.p4 b/testdata/p4_14_samples_outputs/TLV_parsing-frontend.p4 index 5ce6ce56625..c9399ef4ef2 100644 --- a/testdata/p4_14_samples_outputs/TLV_parsing-frontend.p4 +++ b/testdata/p4_14_samples_outputs/TLV_parsing-frontend.p4 @@ -79,8 +79,7 @@ struct headers { parser ParserImpl(packet_in packet, out headers hdr, inout metadata meta, inout standard_metadata_t standard_metadata) { ipv4_option_timestamp_t_1 tmp_hdr_0; - ipv4_option_timestamp_t_1 tmp; - bit<8> tmp_0; + bit<8> tmp; @name(".parse_ethernet") state parse_ethernet { packet.extract(hdr.ethernet); transition select(hdr.ethernet.etherType) { @@ -112,15 +111,14 @@ parser ParserImpl(packet_in packet, out headers hdr, inout metadata meta, inout transition parse_ipv4_options; } @name(".parse_ipv4_option_timestamp") state parse_ipv4_option_timestamp { - tmp = packet.lookahead(); - tmp_hdr_0 = tmp; + tmp_hdr_0 = packet.lookahead(); packet.extract(hdr.ipv4_option_timestamp, ((bit<32>)tmp_hdr_0.len << 3) + 32w4294967280); meta.my_metadata.parse_ipv4_counter = meta.my_metadata.parse_ipv4_counter - hdr.ipv4_option_timestamp.len; transition parse_ipv4_options; } @name(".parse_ipv4_options") state parse_ipv4_options { - tmp_0 = packet.lookahead>(); - transition select(meta.my_metadata.parse_ipv4_counter, tmp_0[7:0]) { + tmp = packet.lookahead>(); + transition select(meta.my_metadata.parse_ipv4_counter, tmp[7:0]) { (8w0x0 &&& 8w0xff, 8w0x0 &&& 8w0x0): accept; (8w0x0 &&& 8w0x0, 8w0x0 &&& 8w0xff): parse_ipv4_option_EOL; (8w0x0 &&& 8w0x0, 8w0x1 &&& 8w0xff): parse_ipv4_option_NOP; diff --git a/testdata/p4_14_samples_outputs/TLV_parsing-midend.p4 b/testdata/p4_14_samples_outputs/TLV_parsing-midend.p4 index 636dd70b621..ed72e2087fe 100644 --- a/testdata/p4_14_samples_outputs/TLV_parsing-midend.p4 +++ b/testdata/p4_14_samples_outputs/TLV_parsing-midend.p4 @@ -78,9 +78,8 @@ struct headers { parser ParserImpl(packet_in packet, out headers hdr, inout metadata meta, inout standard_metadata_t standard_metadata) { ipv4_option_timestamp_t_1 tmp_hdr_0; - ipv4_option_timestamp_t_1 tmp; - bit<8> tmp_0; - bit<16> tmp_1; + bit<8> tmp; + bit<16> tmp_0; @name(".parse_ethernet") state parse_ethernet { packet.extract(hdr.ethernet); transition select(hdr.ethernet.etherType) { @@ -112,18 +111,17 @@ parser ParserImpl(packet_in packet, out headers hdr, inout metadata meta, inout transition parse_ipv4_options; } @name(".parse_ipv4_option_timestamp") state parse_ipv4_option_timestamp { - tmp_1 = packet.lookahead>(); - tmp.setValid(); - tmp.value = tmp_1[15:8]; - tmp.len = tmp_1[7:0]; - tmp_hdr_0 = tmp; - packet.extract(hdr.ipv4_option_timestamp, ((bit<32>)tmp_hdr_0.len << 3) + 32w4294967280); + tmp_0 = packet.lookahead>(); + tmp_hdr_0.setValid(); + tmp_hdr_0.value = tmp_0[15:8]; + tmp_hdr_0.len = tmp_0[7:0]; + packet.extract(hdr.ipv4_option_timestamp, ((bit<32>)tmp_0[7:0] << 3) + 32w4294967280); meta._my_metadata_parse_ipv4_counter0 = meta._my_metadata_parse_ipv4_counter0 - hdr.ipv4_option_timestamp.len; transition parse_ipv4_options; } @name(".parse_ipv4_options") state parse_ipv4_options { - tmp_0 = packet.lookahead>(); - transition select(meta._my_metadata_parse_ipv4_counter0, tmp_0[7:0]) { + tmp = packet.lookahead>(); + transition select(meta._my_metadata_parse_ipv4_counter0, tmp[7:0]) { (8w0x0 &&& 8w0xff, 8w0x0 &&& 8w0x0): accept; (8w0x0 &&& 8w0x0, 8w0x0 &&& 8w0xff): parse_ipv4_option_EOL; (8w0x0 &&& 8w0x0, 8w0x1 &&& 8w0xff): parse_ipv4_option_NOP; diff --git a/testdata/p4_14_samples_outputs/const_default_action-frontend.p4 b/testdata/p4_14_samples_outputs/const_default_action-frontend.p4 index 59d590609f6..27547b3b82e 100644 --- a/testdata/p4_14_samples_outputs/const_default_action-frontend.p4 +++ b/testdata/p4_14_samples_outputs/const_default_action-frontend.p4 @@ -56,7 +56,6 @@ control egress(inout headers hdr, inout metadata meta, inout standard_metadata_t } control ingress(inout headers hdr, inout metadata meta, inout standard_metadata_t standard_metadata) { - bool _process_port_vlan_mapping_tmp; @name(".no_op") action _no_op_0() { } @name(".no_op") action _no_op_2() { @@ -103,8 +102,7 @@ control ingress(inout headers hdr, inout metadata meta, inout standard_metadata_ implementation = bd_action_profile; } apply { - _process_port_vlan_mapping_tmp = _port_vlan_to_bd_mapping.apply().hit; - if (_process_port_vlan_mapping_tmp) { + if (_port_vlan_to_bd_mapping.apply().hit) { ; } else { _vlan_to_bd_mapping.apply(); diff --git a/testdata/p4_14_samples_outputs/const_default_action-midend.p4 b/testdata/p4_14_samples_outputs/const_default_action-midend.p4 index 5b77ed83752..b583d16eed0 100644 --- a/testdata/p4_14_samples_outputs/const_default_action-midend.p4 +++ b/testdata/p4_14_samples_outputs/const_default_action-midend.p4 @@ -63,7 +63,6 @@ control egress(inout headers hdr, inout metadata meta, inout standard_metadata_t } control ingress(inout headers hdr, inout metadata meta, inout standard_metadata_t standard_metadata) { - bool _process_port_vlan_mapping_tmp; @name(".no_op") action _no_op_0() { } @name(".no_op") action _no_op_2() { @@ -109,31 +108,8 @@ control ingress(inout headers hdr, inout metadata meta, inout standard_metadata_ const default_action = _no_op_2(); implementation = bd_action_profile; } - @hidden action act() { - _process_port_vlan_mapping_tmp = true; - } - @hidden action act_0() { - _process_port_vlan_mapping_tmp = false; - } - @hidden table tbl_act { - actions = { - act(); - } - const default_action = act(); - } - @hidden table tbl_act_0 { - actions = { - act_0(); - } - const default_action = act_0(); - } apply { if (_port_vlan_to_bd_mapping.apply().hit) { - tbl_act.apply(); - } else { - tbl_act_0.apply(); - } - if (_process_port_vlan_mapping_tmp) { ; } else { _vlan_to_bd_mapping.apply(); diff --git a/testdata/p4_14_samples_outputs/hit-frontend.p4 b/testdata/p4_14_samples_outputs/hit-frontend.p4 index 0bef01ffeff..260a78143fa 100644 --- a/testdata/p4_14_samples_outputs/hit-frontend.p4 +++ b/testdata/p4_14_samples_outputs/hit-frontend.p4 @@ -33,7 +33,6 @@ control ingress(inout headers hdr, inout metadata meta, inout standard_metadata_ } @name(".NoAction") action NoAction_5() { } - bool tmp; @name(".setb1") action setb1(bit<8> val, bit<9> port) { hdr.data.b1 = val; standard_metadata.egress_spec = port; @@ -78,8 +77,7 @@ control ingress(inout headers hdr, inout metadata meta, inout standard_metadata_ default_action = NoAction_5(); } apply { - tmp = test1_0.apply().hit; - if (tmp) { + if (test1_0.apply().hit) { test2_0.apply(); } test4_0.apply(); diff --git a/testdata/p4_14_samples_outputs/hit-midend.p4 b/testdata/p4_14_samples_outputs/hit-midend.p4 index 5840af32d77..260a78143fa 100644 --- a/testdata/p4_14_samples_outputs/hit-midend.p4 +++ b/testdata/p4_14_samples_outputs/hit-midend.p4 @@ -27,7 +27,6 @@ parser ParserImpl(packet_in packet, out headers hdr, inout metadata meta, inout } control ingress(inout headers hdr, inout metadata meta, inout standard_metadata_t standard_metadata) { - bool tmp; @name(".NoAction") action NoAction_0() { } @name(".NoAction") action NoAction_4() { @@ -77,31 +76,8 @@ control ingress(inout headers hdr, inout metadata meta, inout standard_metadata_ } default_action = NoAction_5(); } - @hidden action act() { - tmp = true; - } - @hidden action act_0() { - tmp = false; - } - @hidden table tbl_act { - actions = { - act(); - } - const default_action = act(); - } - @hidden table tbl_act_0 { - actions = { - act_0(); - } - const default_action = act_0(); - } apply { if (test1_0.apply().hit) { - tbl_act.apply(); - } else { - tbl_act_0.apply(); - } - if (tmp) { test2_0.apply(); } test4_0.apply(); diff --git a/testdata/p4_14_samples_outputs/hitmiss-frontend.p4 b/testdata/p4_14_samples_outputs/hitmiss-frontend.p4 index 1a68f358ebc..21c3a4234af 100644 --- a/testdata/p4_14_samples_outputs/hitmiss-frontend.p4 +++ b/testdata/p4_14_samples_outputs/hitmiss-frontend.p4 @@ -33,7 +33,6 @@ control ingress(inout headers hdr, inout metadata meta, inout standard_metadata_ } @name(".NoAction") action NoAction_5() { } - bool tmp; @name(".setb1") action setb1(bit<8> val, bit<9> port) { hdr.data.b1 = val; standard_metadata.egress_spec = port; @@ -86,8 +85,7 @@ control ingress(inout headers hdr, inout metadata meta, inout standard_metadata_ default_action = NoAction_5(); } apply { - tmp = test1_0.apply().hit; - if (tmp) { + if (test1_0.apply().hit) { test2_0.apply(); } else { test3_0.apply(); diff --git a/testdata/p4_14_samples_outputs/hitmiss-midend.p4 b/testdata/p4_14_samples_outputs/hitmiss-midend.p4 index 7eea9868274..21c3a4234af 100644 --- a/testdata/p4_14_samples_outputs/hitmiss-midend.p4 +++ b/testdata/p4_14_samples_outputs/hitmiss-midend.p4 @@ -27,7 +27,6 @@ parser ParserImpl(packet_in packet, out headers hdr, inout metadata meta, inout } control ingress(inout headers hdr, inout metadata meta, inout standard_metadata_t standard_metadata) { - bool tmp; @name(".NoAction") action NoAction_0() { } @name(".NoAction") action NoAction_4() { @@ -85,31 +84,8 @@ control ingress(inout headers hdr, inout metadata meta, inout standard_metadata_ } default_action = NoAction_5(); } - @hidden action act() { - tmp = true; - } - @hidden action act_0() { - tmp = false; - } - @hidden table tbl_act { - actions = { - act(); - } - const default_action = act(); - } - @hidden table tbl_act_0 { - actions = { - act_0(); - } - const default_action = act_0(); - } apply { if (test1_0.apply().hit) { - tbl_act.apply(); - } else { - tbl_act_0.apply(); - } - if (tmp) { test2_0.apply(); } else { test3_0.apply(); diff --git a/testdata/p4_14_samples_outputs/issue576-frontend.p4 b/testdata/p4_14_samples_outputs/issue576-frontend.p4 index 93cdd4c002a..1bf109f1a8c 100644 --- a/testdata/p4_14_samples_outputs/issue576-frontend.p4 +++ b/testdata/p4_14_samples_outputs/issue576-frontend.p4 @@ -61,16 +61,12 @@ struct headers { parser ParserImpl(packet_in packet, out headers hdr, inout metadata meta, inout standard_metadata_t standard_metadata) { ipv4_t_1 tmp_hdr_1; ipv4_t_1 tmp_hdr_2; - ipv4_t_1 tmp; - ipv4_t_1 tmp_0; @name(".start") state start { packet.extract(hdr.sh.next); packet.extract(hdr.sh.next); - tmp = packet.lookahead(); - tmp_hdr_1 = tmp; + tmp_hdr_1 = packet.lookahead(); packet.extract(hdr.h.next, ((bit<32>)tmp_hdr_1.ihl << 2 << 3) + 32w4294967136); - tmp_0 = packet.lookahead(); - tmp_hdr_2 = tmp_0; + tmp_hdr_2 = packet.lookahead(); packet.extract(hdr.h.next, ((bit<32>)tmp_hdr_2.ihl << 2 << 3) + 32w4294967136); transition accept; } diff --git a/testdata/p4_14_samples_outputs/issue576-midend.p4 b/testdata/p4_14_samples_outputs/issue576-midend.p4 index 82e21f5eebb..8af8e413cf5 100644 --- a/testdata/p4_14_samples_outputs/issue576-midend.p4 +++ b/testdata/p4_14_samples_outputs/issue576-midend.p4 @@ -61,45 +61,41 @@ struct headers { parser ParserImpl(packet_in packet, out headers hdr, inout metadata meta, inout standard_metadata_t standard_metadata) { ipv4_t_1 tmp_hdr_1; ipv4_t_1 tmp_hdr_2; - ipv4_t_1 tmp; - ipv4_t_1 tmp_0; - bit<160> tmp_1; - bit<160> tmp_2; + bit<160> tmp; + bit<160> tmp_0; @name(".start") state start { packet.extract(hdr.sh.next); packet.extract(hdr.sh.next); - tmp_1 = packet.lookahead>(); - tmp.setValid(); - tmp.version = tmp_1[159:156]; - tmp.ihl = tmp_1[155:152]; - tmp.diffserv = tmp_1[151:144]; - tmp.totalLen = tmp_1[143:128]; - tmp.id = tmp_1[127:112]; - tmp.flags = tmp_1[111:109]; - tmp.fragOffset = tmp_1[108:96]; - tmp.ttl = tmp_1[95:88]; - tmp.protocol = tmp_1[87:80]; - tmp.hdrChecksum = tmp_1[79:64]; - tmp.srcAddr = tmp_1[63:32]; - tmp.dstAddr = tmp_1[31:0]; - tmp_hdr_1 = tmp; - packet.extract(hdr.h.next, ((bit<32>)tmp_hdr_1.ihl << 2 << 3) + 32w4294967136); - tmp_2 = packet.lookahead>(); - tmp_0.setValid(); - tmp_0.version = tmp_2[159:156]; - tmp_0.ihl = tmp_2[155:152]; - tmp_0.diffserv = tmp_2[151:144]; - tmp_0.totalLen = tmp_2[143:128]; - tmp_0.id = tmp_2[127:112]; - tmp_0.flags = tmp_2[111:109]; - tmp_0.fragOffset = tmp_2[108:96]; - tmp_0.ttl = tmp_2[95:88]; - tmp_0.protocol = tmp_2[87:80]; - tmp_0.hdrChecksum = tmp_2[79:64]; - tmp_0.srcAddr = tmp_2[63:32]; - tmp_0.dstAddr = tmp_2[31:0]; - tmp_hdr_2 = tmp_0; - packet.extract(hdr.h.next, ((bit<32>)tmp_hdr_2.ihl << 2 << 3) + 32w4294967136); + tmp = packet.lookahead>(); + tmp_hdr_1.setValid(); + tmp_hdr_1.version = tmp[159:156]; + tmp_hdr_1.ihl = tmp[155:152]; + tmp_hdr_1.diffserv = tmp[151:144]; + tmp_hdr_1.totalLen = tmp[143:128]; + tmp_hdr_1.id = tmp[127:112]; + tmp_hdr_1.flags = tmp[111:109]; + tmp_hdr_1.fragOffset = tmp[108:96]; + tmp_hdr_1.ttl = tmp[95:88]; + tmp_hdr_1.protocol = tmp[87:80]; + tmp_hdr_1.hdrChecksum = tmp[79:64]; + tmp_hdr_1.srcAddr = tmp[63:32]; + tmp_hdr_1.dstAddr = tmp[31:0]; + packet.extract(hdr.h.next, ((bit<32>)tmp[155:152] << 2 << 3) + 32w4294967136); + tmp_0 = packet.lookahead>(); + tmp_hdr_2.setValid(); + tmp_hdr_2.version = tmp_0[159:156]; + tmp_hdr_2.ihl = tmp_0[155:152]; + tmp_hdr_2.diffserv = tmp_0[151:144]; + tmp_hdr_2.totalLen = tmp_0[143:128]; + tmp_hdr_2.id = tmp_0[127:112]; + tmp_hdr_2.flags = tmp_0[111:109]; + tmp_hdr_2.fragOffset = tmp_0[108:96]; + tmp_hdr_2.ttl = tmp_0[95:88]; + tmp_hdr_2.protocol = tmp_0[87:80]; + tmp_hdr_2.hdrChecksum = tmp_0[79:64]; + tmp_hdr_2.srcAddr = tmp_0[63:32]; + tmp_hdr_2.dstAddr = tmp_0[31:0]; + packet.extract(hdr.h.next, ((bit<32>)tmp_0[155:152] << 2 << 3) + 32w4294967136); transition accept; } } diff --git a/testdata/p4_14_samples_outputs/issue781-frontend.p4 b/testdata/p4_14_samples_outputs/issue781-frontend.p4 index 85d29362805..bec95e7d744 100644 --- a/testdata/p4_14_samples_outputs/issue781-frontend.p4 +++ b/testdata/p4_14_samples_outputs/issue781-frontend.p4 @@ -43,10 +43,8 @@ struct headers { parser ParserImpl(packet_in packet, out headers hdr, inout metadata meta, inout standard_metadata_t standard_metadata) { ipv4_t_1 tmp_hdr_0; - ipv4_t_1 tmp; @name(".start") state start { - tmp = packet.lookahead(); - tmp_hdr_0 = tmp; + tmp_hdr_0 = packet.lookahead(); packet.extract(hdr.h, ((bit<32>)tmp_hdr_0.ihl << 2 << 3) + 32w4294967136); transition accept; } diff --git a/testdata/p4_14_samples_outputs/issue781-midend.p4 b/testdata/p4_14_samples_outputs/issue781-midend.p4 index 4799ae6f57a..b1d80716652 100644 --- a/testdata/p4_14_samples_outputs/issue781-midend.p4 +++ b/testdata/p4_14_samples_outputs/issue781-midend.p4 @@ -43,25 +43,23 @@ struct headers { parser ParserImpl(packet_in packet, out headers hdr, inout metadata meta, inout standard_metadata_t standard_metadata) { ipv4_t_1 tmp_hdr_0; - ipv4_t_1 tmp; - bit<160> tmp_0; + bit<160> tmp; @name(".start") state start { - tmp_0 = packet.lookahead>(); - tmp.setValid(); - tmp.version = tmp_0[159:156]; - tmp.ihl = tmp_0[155:152]; - tmp.diffserv = tmp_0[151:144]; - tmp.totalLen = tmp_0[143:128]; - tmp.id = tmp_0[127:112]; - tmp.flags = tmp_0[111:109]; - tmp.fragOffset = tmp_0[108:96]; - tmp.ttl = tmp_0[95:88]; - tmp.protocol = tmp_0[87:80]; - tmp.hdrChecksum = tmp_0[79:64]; - tmp.srcAddr = tmp_0[63:32]; - tmp.dstAddr = tmp_0[31:0]; - tmp_hdr_0 = tmp; - packet.extract(hdr.h, ((bit<32>)tmp_hdr_0.ihl << 2 << 3) + 32w4294967136); + tmp = packet.lookahead>(); + tmp_hdr_0.setValid(); + tmp_hdr_0.version = tmp[159:156]; + tmp_hdr_0.ihl = tmp[155:152]; + tmp_hdr_0.diffserv = tmp[151:144]; + tmp_hdr_0.totalLen = tmp[143:128]; + tmp_hdr_0.id = tmp[127:112]; + tmp_hdr_0.flags = tmp[111:109]; + tmp_hdr_0.fragOffset = tmp[108:96]; + tmp_hdr_0.ttl = tmp[95:88]; + tmp_hdr_0.protocol = tmp[87:80]; + tmp_hdr_0.hdrChecksum = tmp[79:64]; + tmp_hdr_0.srcAddr = tmp[63:32]; + tmp_hdr_0.dstAddr = tmp[31:0]; + packet.extract(hdr.h, ((bit<32>)tmp[155:152] << 2 << 3) + 32w4294967136); transition accept; } } diff --git a/testdata/p4_14_samples_outputs/miss-frontend.p4 b/testdata/p4_14_samples_outputs/miss-frontend.p4 index 822d76d3717..2277f4d3313 100644 --- a/testdata/p4_14_samples_outputs/miss-frontend.p4 +++ b/testdata/p4_14_samples_outputs/miss-frontend.p4 @@ -33,7 +33,6 @@ control ingress(inout headers hdr, inout metadata meta, inout standard_metadata_ } @name(".NoAction") action NoAction_5() { } - bool tmp; @name(".setb1") action setb1(bit<8> val, bit<9> port) { hdr.data.b1 = val; standard_metadata.egress_spec = port; @@ -78,8 +77,7 @@ control ingress(inout headers hdr, inout metadata meta, inout standard_metadata_ default_action = NoAction_5(); } apply { - tmp = test1_0.apply().hit; - if (tmp) { + if (test1_0.apply().hit) { ; } else { test3_0.apply(); diff --git a/testdata/p4_14_samples_outputs/miss-midend.p4 b/testdata/p4_14_samples_outputs/miss-midend.p4 index 9e219f1e954..2277f4d3313 100644 --- a/testdata/p4_14_samples_outputs/miss-midend.p4 +++ b/testdata/p4_14_samples_outputs/miss-midend.p4 @@ -27,7 +27,6 @@ parser ParserImpl(packet_in packet, out headers hdr, inout metadata meta, inout } control ingress(inout headers hdr, inout metadata meta, inout standard_metadata_t standard_metadata) { - bool tmp; @name(".NoAction") action NoAction_0() { } @name(".NoAction") action NoAction_4() { @@ -77,31 +76,8 @@ control ingress(inout headers hdr, inout metadata meta, inout standard_metadata_ } default_action = NoAction_5(); } - @hidden action act() { - tmp = true; - } - @hidden action act_0() { - tmp = false; - } - @hidden table tbl_act { - actions = { - act(); - } - const default_action = act(); - } - @hidden table tbl_act_0 { - actions = { - act_0(); - } - const default_action = act_0(); - } apply { if (test1_0.apply().hit) { - tbl_act.apply(); - } else { - tbl_act_0.apply(); - } - if (tmp) { ; } else { test3_0.apply(); diff --git a/testdata/p4_16_errors_outputs/issue532-frontend.p4 b/testdata/p4_16_errors_outputs/issue532-frontend.p4 index 1d4c84afa52..c199e976723 100644 --- a/testdata/p4_16_errors_outputs/issue532-frontend.p4 +++ b/testdata/p4_16_errors_outputs/issue532-frontend.p4 @@ -29,10 +29,8 @@ extern s1_t choose_entry(in choices_t choices); control ingress(inout parsed_packet_t hdr, inout my_meta_t my_meta, inout standard_metadata_t standard_metadata) { @name(".NoAction") action NoAction_0() { } - s1_t tmp; @name("ingress.select_entry") action select_entry(choices_t choices) { - tmp = choose_entry(choices); - my_meta.entry = tmp; + my_meta.entry = choose_entry(choices); } @name("ingress.t") table t_0 { actions = { diff --git a/testdata/p4_16_samples_outputs/array_field-frontend.p4 b/testdata/p4_16_samples_outputs/array_field-frontend.p4 index bf5d04dd7ab..ef6befe0f21 100644 --- a/testdata/p4_16_samples_outputs/array_field-frontend.p4 +++ b/testdata/p4_16_samples_outputs/array_field-frontend.p4 @@ -7,15 +7,12 @@ control c(out H[2] h); package top(c _c); control my(out H[2] s) { bit<32> a_0; - bit<32> tmp; - bit<32> tmp_0; apply { a_0 = 32w0; s[a_0].z = 1w1; s[a_0 + 32w1].z = 1w0; - tmp = f(s[a_0].z, 1w0); - a_0 = tmp; - tmp_0 = f(s[a_0].z, 1w1); + a_0 = f(s[a_0].z, 1w0); + a_0 = f(s[a_0].z, 1w1); } } diff --git a/testdata/p4_16_samples_outputs/array_field-midend.p4 b/testdata/p4_16_samples_outputs/array_field-midend.p4 index 033f41a3616..2eaf16164be 100644 --- a/testdata/p4_16_samples_outputs/array_field-midend.p4 +++ b/testdata/p4_16_samples_outputs/array_field-midend.p4 @@ -6,21 +6,22 @@ extern bit<32> f(inout bit<1> x, in bit<1> b); control c(out H[2] h); package top(c _c); control my(out H[2] s) { - bit<32> tmp; - @hidden action array_field27() { + bit<32> a_0; + @hidden action array_field26() { + a_0 = 32w0; s[32w0].z = 1w1; s[32w1].z = 1w0; - tmp = f(s[32w0].z, 1w0); - f(s[tmp].z, 1w1); + a_0 = f(s[32w0].z, 1w0); + a_0 = f(s[a_0].z, 1w1); } - @hidden table tbl_array_field27 { + @hidden table tbl_array_field26 { actions = { - array_field27(); + array_field26(); } - const default_action = array_field27(); + const default_action = array_field26(); } apply { - tbl_array_field27.apply(); + tbl_array_field26.apply(); } } diff --git a/testdata/p4_16_samples_outputs/array_field1-frontend.p4 b/testdata/p4_16_samples_outputs/array_field1-frontend.p4 index 85f5a7bf344..342d736849c 100644 --- a/testdata/p4_16_samples_outputs/array_field1-frontend.p4 +++ b/testdata/p4_16_samples_outputs/array_field1-frontend.p4 @@ -15,8 +15,7 @@ control my(out H[2] s) { bit<1> tmp_4; bit<32> tmp_5; bit<1> tmp_6; - bit<1> tmp_8; - bit<1> tmp_9; + bit<1> tmp_7; @name("my.act") action act() { a_0 = 32w0; tmp = a_0; @@ -26,13 +25,12 @@ control my(out H[2] s) { s[tmp_1].z = 1w0; tmp_2 = a_0; tmp_3 = s[tmp_2].z; - tmp_8 = f(tmp_3, 1w0); - tmp_4 = tmp_8; + tmp_4 = f(tmp_3, 1w0); s[tmp_2].z = tmp_3; a_0 = (bit<32>)tmp_4; tmp_5 = a_0; tmp_6 = s[tmp_5].z; - tmp_9 = f(tmp_6, 1w1); + tmp_7 = f(tmp_6, 1w1); s[tmp_5].z = tmp_6; } @name("my.tbl_act") table tbl_act_0 { diff --git a/testdata/p4_16_samples_outputs/array_field1-midend.p4 b/testdata/p4_16_samples_outputs/array_field1-midend.p4 index 35bed969ce1..22f44b383a4 100644 --- a/testdata/p4_16_samples_outputs/array_field1-midend.p4 +++ b/testdata/p4_16_samples_outputs/array_field1-midend.p4 @@ -7,17 +7,17 @@ control c(out H[2] h); package top(c _c); control my(out H[2] s) { bit<1> tmp_3; + bit<1> tmp_4; bit<1> tmp_6; - bit<1> tmp_8; @name("my.act") action act() { s[32w0].z = 1w1; s[32w1].z = 1w0; tmp_3 = s[32w0].z; - tmp_8 = f(tmp_3, 1w0); + tmp_4 = f(tmp_3, 1w0); s[32w0].z = tmp_3; - tmp_6 = s[(bit<32>)tmp_8].z; + tmp_6 = s[(bit<32>)tmp_4].z; f(tmp_6, 1w1); - s[(bit<32>)tmp_8].z = tmp_6; + s[(bit<32>)tmp_4].z = tmp_6; } @name("my.tbl_act") table tbl_act_0 { actions = { diff --git a/testdata/p4_16_samples_outputs/complex-frontend.p4 b/testdata/p4_16_samples_outputs/complex-frontend.p4 index 8457eb92d03..c3c2f638ba7 100644 --- a/testdata/p4_16_samples_outputs/complex-frontend.p4 +++ b/testdata/p4_16_samples_outputs/complex-frontend.p4 @@ -2,12 +2,10 @@ extern bit<32> f(in bit<32> x); control c(inout bit<32> r) { bit<32> tmp; bit<32> tmp_0; - bit<32> tmp_1; apply { tmp = f(32w5); tmp_0 = tmp; - tmp_1 = f(tmp_0); - r = tmp_1; + r = f(tmp_0); } } diff --git a/testdata/p4_16_samples_outputs/complex-midend.p4 b/testdata/p4_16_samples_outputs/complex-midend.p4 index 8b576788523..283bae8fcde 100644 --- a/testdata/p4_16_samples_outputs/complex-midend.p4 +++ b/testdata/p4_16_samples_outputs/complex-midend.p4 @@ -1,11 +1,9 @@ extern bit<32> f(in bit<32> x); control c(inout bit<32> r) { bit<32> tmp; - bit<32> tmp_1; @hidden action complex21() { tmp = f(32w5); - tmp_1 = f(tmp); - r = tmp_1; + r = f(tmp); } @hidden table tbl_complex21 { actions = { diff --git a/testdata/p4_16_samples_outputs/complex1-frontend.p4 b/testdata/p4_16_samples_outputs/complex1-frontend.p4 index ed9d266d014..f4ff9f497ca 100644 --- a/testdata/p4_16_samples_outputs/complex1-frontend.p4 +++ b/testdata/p4_16_samples_outputs/complex1-frontend.p4 @@ -6,7 +6,6 @@ control c(inout bit<32> r) { bit<32> tmp_2; bit<32> tmp_3; bit<32> tmp_4; - bit<32> tmp_5; apply { tmp = f(32w5, 32w2); tmp_0 = tmp; @@ -14,8 +13,7 @@ control c(inout bit<32> r) { tmp_2 = tmp_1; tmp_3 = f(32w6, tmp_2); tmp_4 = tmp_3; - tmp_5 = f(tmp_0, tmp_4); - r = tmp_5; + r = f(tmp_0, tmp_4); } } diff --git a/testdata/p4_16_samples_outputs/complex1-midend.p4 b/testdata/p4_16_samples_outputs/complex1-midend.p4 index 7aca8fa2082..950a9ea2035 100644 --- a/testdata/p4_16_samples_outputs/complex1-midend.p4 +++ b/testdata/p4_16_samples_outputs/complex1-midend.p4 @@ -3,13 +3,11 @@ control c(inout bit<32> r) { bit<32> tmp; bit<32> tmp_1; bit<32> tmp_3; - bit<32> tmp_5; @hidden action complex1l21() { tmp = f(32w5, 32w2); tmp_1 = f(32w2, 32w3); tmp_3 = f(32w6, tmp_1); - tmp_5 = f(tmp, tmp_3); - r = tmp_5; + r = f(tmp, tmp_3); } @hidden table tbl_complex1l21 { actions = { diff --git a/testdata/p4_16_samples_outputs/complex6-frontend.p4 b/testdata/p4_16_samples_outputs/complex6-frontend.p4 index 4b5dc095cf6..4917b014b5c 100644 --- a/testdata/p4_16_samples_outputs/complex6-frontend.p4 +++ b/testdata/p4_16_samples_outputs/complex6-frontend.p4 @@ -5,12 +5,12 @@ control c(inout bit<32> r) { bit<32> tmp_1; bool tmp_2; apply { - tmp_1 = f(32w2); - tmp_2 = tmp_1 > 32w0; - if (tmp_2) { - tmp = f(32w2); - tmp_0 = tmp < 32w2; - if (tmp_0) { + tmp = f(32w2); + tmp_0 = tmp > 32w0; + if (tmp_0) { + tmp_1 = f(32w2); + tmp_2 = tmp_1 < 32w2; + if (tmp_2) { r = 32w1; } else { r = 32w3; diff --git a/testdata/p4_16_samples_outputs/complex6-midend.p4 b/testdata/p4_16_samples_outputs/complex6-midend.p4 index 5d319a5dd77..eaf5e908b9e 100644 --- a/testdata/p4_16_samples_outputs/complex6-midend.p4 +++ b/testdata/p4_16_samples_outputs/complex6-midend.p4 @@ -9,13 +9,13 @@ control c(inout bit<32> r) { r = 32w3; } @hidden action act() { - tmp = f(32w2); + tmp_1 = f(32w2); } @hidden action complex6l27() { r = 32w2; } @hidden action act_0() { - tmp_1 = f(32w2); + tmp = f(32w2); } @hidden table tbl_act { actions = { @@ -49,9 +49,9 @@ control c(inout bit<32> r) { } apply { tbl_act.apply(); - if (tmp_1 > 32w0) { + if (tmp > 32w0) { tbl_act_0.apply(); - if (tmp < 32w2) { + if (tmp_1 < 32w2) { tbl_complex6l23.apply(); } else { tbl_complex6l25.apply(); diff --git a/testdata/p4_16_samples_outputs/exit4-frontend.p4 b/testdata/p4_16_samples_outputs/exit4-frontend.p4 index 429b5be6c8f..e09ef74d954 100644 --- a/testdata/p4_16_samples_outputs/exit4-frontend.p4 +++ b/testdata/p4_16_samples_outputs/exit4-frontend.p4 @@ -1,5 +1,4 @@ control ctrl() { - bool tmp; @name("ctrl.e") action e() { exit; } @@ -10,8 +9,7 @@ control ctrl() { default_action = e(); } apply { - tmp = t_0.apply().hit; - if (tmp) { + if (t_0.apply().hit) { t_0.apply(); } else { t_0.apply(); diff --git a/testdata/p4_16_samples_outputs/exit4-midend.p4 b/testdata/p4_16_samples_outputs/exit4-midend.p4 index b086327ae83..c1c6f38b701 100644 --- a/testdata/p4_16_samples_outputs/exit4-midend.p4 +++ b/testdata/p4_16_samples_outputs/exit4-midend.p4 @@ -1,6 +1,5 @@ control ctrl() { bool hasExited; - bool tmp; @name("ctrl.e") action e() { hasExited = true; } @@ -11,45 +10,22 @@ control ctrl() { default_action = e(); } @hidden action act() { - tmp = true; - } - @hidden action act_0() { - tmp = false; - } - @hidden action act_1() { hasExited = false; } @hidden table tbl_act { - actions = { - act_1(); - } - const default_action = act_1(); - } - @hidden table tbl_act_0 { actions = { act(); } const default_action = act(); } - @hidden table tbl_act_1 { - actions = { - act_0(); - } - const default_action = act_0(); - } apply { tbl_act.apply(); if (t_0.apply().hit) { - tbl_act_0.apply(); - } else { - tbl_act_1.apply(); - } - if (!hasExited) { - if (tmp) { - t_0.apply(); - } else { + if (!hasExited) { t_0.apply(); } + } else if (!hasExited) { + t_0.apply(); } } } diff --git a/testdata/p4_16_samples_outputs/fabric_20190420/fabric-frontend.p4 b/testdata/p4_16_samples_outputs/fabric_20190420/fabric-frontend.p4 index 27729179a8e..2ef83ef6ca3 100644 --- a/testdata/p4_16_samples_outputs/fabric_20190420/fabric-frontend.p4 +++ b/testdata/p4_16_samples_outputs/fabric_20190420/fabric-frontend.p4 @@ -210,7 +210,7 @@ control FabricVerifyChecksum(inout parsed_headers_t hdr, inout fabric_metadata_t } parser FabricParser(packet_in packet, out parsed_headers_t hdr, inout fabric_metadata_t fabric_metadata, inout standard_metadata_t standard_metadata) { - bit<4> tmp_0; + bit<4> tmp; state start { transition select(standard_metadata.ingress_port) { 9w255: parse_packet_out; @@ -253,8 +253,8 @@ parser FabricParser(packet_in packet, out parsed_headers_t hdr, inout fabric_met packet.extract(hdr.mpls); fabric_metadata.mpls_label = hdr.mpls.label; fabric_metadata.mpls_ttl = hdr.mpls.ttl; - tmp_0 = packet.lookahead>(); - transition select(tmp_0) { + tmp = packet.lookahead>(); + transition select(tmp) { 4w4: parse_ipv4; default: parse_ethernet; } @@ -349,8 +349,6 @@ control FabricIngress(inout parsed_headers_t hdr, inout fabric_metadata_t fabric } @name(".nop") action nop_17() { } - bool spgw_ingress_tmp; - bool spgw_ingress_tmp_0; @name("FabricIngress.spgw_ingress.ue_counter") direct_counter(CounterType.packets_and_bytes) spgw_ingress_ue_counter; @hidden @name("FabricIngress.spgw_ingress.gtpu_decap") action spgw_ingress_gtpu_decap_0() { hdr.gtpu_ipv4.setInvalid(); @@ -702,20 +700,16 @@ control FabricIngress(inout parsed_headers_t hdr, inout fabric_metadata_t fabric { bool spgw_ingress_hasReturned = false; if (hdr.gtpu.isValid()) { - spgw_ingress_tmp = spgw_ingress_s1u_filter_table.apply().hit; - if (!spgw_ingress_tmp) { + if (!spgw_ingress_s1u_filter_table.apply().hit) { mark_to_drop(standard_metadata); } fabric_metadata.spgw.direction = 2w1; spgw_ingress_gtpu_decap_0(); + } else if (spgw_ingress_dl_sess_lookup.apply().hit) { + fabric_metadata.spgw.direction = 2w2; } else { - spgw_ingress_tmp_0 = spgw_ingress_dl_sess_lookup.apply().hit; - if (spgw_ingress_tmp_0) { - fabric_metadata.spgw.direction = 2w2; - } else { - fabric_metadata.spgw.direction = 2w0; - spgw_ingress_hasReturned = true; - } + fabric_metadata.spgw.direction = 2w0; + spgw_ingress_hasReturned = true; } if (!spgw_ingress_hasReturned) { fabric_metadata.spgw.ipv4_len = hdr.ipv4.total_len; @@ -780,7 +774,6 @@ control FabricEgress(inout parsed_headers_t hdr, inout fabric_metadata_t fabric_ hdr.gtpu.msglen = fabric_metadata.spgw.ipv4_len; hdr.gtpu.teid = fabric_metadata.spgw.teid; } - bool egress_next_tmp; @hidden @name("FabricEgress.egress_next.pop_mpls_if_present") action egress_next_pop_mpls_if_present_0() { hdr.mpls.setInvalid(); fabric_metadata.eth_type = fabric_metadata.ip_eth_type; @@ -842,8 +835,7 @@ control FabricEgress(inout parsed_headers_t hdr, inout fabric_metadata_t fabric_ } else { egress_next_set_mpls_0(); } - egress_next_tmp = egress_next_egress_vlan.apply().hit; - if (!egress_next_tmp) { + if (!egress_next_egress_vlan.apply().hit) { if (fabric_metadata.vlan_id != 12w4094) { egress_next_push_vlan_0(); } diff --git a/testdata/p4_16_samples_outputs/fabric_20190420/fabric-midend.p4 b/testdata/p4_16_samples_outputs/fabric_20190420/fabric-midend.p4 index 31cdac2298c..3fb337d095b 100644 --- a/testdata/p4_16_samples_outputs/fabric_20190420/fabric-midend.p4 +++ b/testdata/p4_16_samples_outputs/fabric_20190420/fabric-midend.p4 @@ -229,7 +229,7 @@ control FabricVerifyChecksum(inout parsed_headers_t hdr, inout fabric_metadata_t } parser FabricParser(packet_in packet, out parsed_headers_t hdr, inout fabric_metadata_t fabric_metadata, inout standard_metadata_t standard_metadata) { - bit<4> tmp_0; + bit<4> tmp; state start { transition select(standard_metadata.ingress_port) { 9w255: parse_packet_out; @@ -272,8 +272,8 @@ parser FabricParser(packet_in packet, out parsed_headers_t hdr, inout fabric_met packet.extract(hdr.mpls); fabric_metadata._mpls_label5 = hdr.mpls.label; fabric_metadata._mpls_ttl6 = hdr.mpls.ttl; - tmp_0 = packet.lookahead>(); - transition select(tmp_0) { + tmp = packet.lookahead>(); + transition select(tmp) { 4w4: parse_ipv4; default: parse_ethernet; } @@ -351,8 +351,6 @@ control FabricDeparser(packet_out packet, in parsed_headers_t hdr) { control FabricIngress(inout parsed_headers_t hdr, inout fabric_metadata_t fabric_metadata, inout standard_metadata_t standard_metadata) { bool hasExited; - bool spgw_ingress_tmp; - bool spgw_ingress_tmp_0; bool spgw_normalizer_hasReturned; bool spgw_ingress_hasReturned; @name(".nop") action nop() { @@ -690,24 +688,12 @@ control FabricIngress(inout parsed_headers_t hdr, inout fabric_metadata_t fabric @hidden action filtering115() { fabric_metadata._mpls_ttl6 = 8w65; } - @hidden action act() { - spgw_ingress_tmp = true; - } - @hidden action act_0() { - spgw_ingress_tmp = false; - } @hidden action spgw149() { mark_to_drop(standard_metadata); } @hidden action spgw151() { fabric_metadata._spgw_direction17 = 2w1; } - @hidden action act_1() { - spgw_ingress_tmp_0 = true; - } - @hidden action act_2() { - spgw_ingress_tmp_0 = false; - } @hidden action spgw154() { fabric_metadata._spgw_direction17 = 2w2; } @@ -715,7 +701,7 @@ control FabricIngress(inout parsed_headers_t hdr, inout fabric_metadata_t fabric fabric_metadata._spgw_direction17 = 2w0; spgw_ingress_hasReturned = true; } - @hidden action act_3() { + @hidden action act() { spgw_ingress_hasReturned = false; } @hidden action spgw175() { @@ -776,23 +762,11 @@ control FabricIngress(inout parsed_headers_t hdr, inout fabric_metadata_t fabric const default_action = filtering115(); } @hidden table tbl_act { - actions = { - act_3(); - } - const default_action = act_3(); - } - @hidden table tbl_act_0 { actions = { act(); } const default_action = act(); } - @hidden table tbl_act_1 { - actions = { - act_0(); - } - const default_action = act_0(); - } @hidden table tbl_spgw149 { actions = { spgw149(); @@ -811,18 +785,6 @@ control FabricIngress(inout parsed_headers_t hdr, inout fabric_metadata_t fabric } const default_action = spgw_ingress_gtpu_decap_0(); } - @hidden table tbl_act_2 { - actions = { - act_1(); - } - const default_action = act_1(); - } - @hidden table tbl_act_3 { - actions = { - act_2(); - } - const default_action = act_2(); - } @hidden table tbl_spgw154 { actions = { spgw154(); @@ -880,27 +842,15 @@ control FabricIngress(inout parsed_headers_t hdr, inout fabric_metadata_t fabric filtering_fwd_classifier.apply(); tbl_act.apply(); if (hdr.gtpu.isValid()) { - if (spgw_ingress_s1u_filter_table.apply().hit) { - tbl_act_0.apply(); - } else { - tbl_act_1.apply(); - } - if (!spgw_ingress_tmp) { + if (!spgw_ingress_s1u_filter_table.apply().hit) { tbl_spgw149.apply(); } tbl_spgw151.apply(); tbl_spgw_ingress_gtpu_decap.apply(); + } else if (spgw_ingress_dl_sess_lookup.apply().hit) { + tbl_spgw154.apply(); } else { - if (spgw_ingress_dl_sess_lookup.apply().hit) { - tbl_act_2.apply(); - } else { - tbl_act_3.apply(); - } - if (spgw_ingress_tmp_0) { - tbl_spgw154.apply(); - } else { - tbl_spgw156.apply(); - } + tbl_spgw156.apply(); } if (!spgw_ingress_hasReturned) { tbl_spgw175.apply(); @@ -933,7 +883,6 @@ control FabricIngress(inout parsed_headers_t hdr, inout fabric_metadata_t fabric control FabricEgress(inout parsed_headers_t hdr, inout fabric_metadata_t fabric_metadata, inout standard_metadata_t standard_metadata) { bool hasExited_0; - bool egress_next_tmp; @name(".nop") action nop_18() { } @hidden @name("FabricEgress.spgw_egress.gtpu_encap") action spgw_egress_gtpu_encap_0() { @@ -1009,7 +958,7 @@ control FabricEgress(inout parsed_headers_t hdr, inout fabric_metadata_t fabric_ @hidden action packetio41() { hasExited_0 = true; } - @hidden action act_4() { + @hidden action act_0() { hasExited_0 = false; } @hidden action packetio47() { @@ -1023,12 +972,6 @@ control FabricEgress(inout parsed_headers_t hdr, inout fabric_metadata_t fabric_ @hidden action next308() { mark_to_drop(standard_metadata); } - @hidden action act_5() { - egress_next_tmp = true; - } - @hidden action act_6() { - egress_next_tmp = false; - } @hidden action next327() { mark_to_drop(standard_metadata); } @@ -1041,11 +984,11 @@ control FabricEgress(inout parsed_headers_t hdr, inout fabric_metadata_t fabric_ @hidden action next330() { hdr.ipv4.ttl = hdr.ipv4.ttl + 8w255; } - @hidden table tbl_act_4 { + @hidden table tbl_act_0 { actions = { - act_4(); + act_0(); } - const default_action = act_4(); + const default_action = act_0(); } @hidden table tbl_packetio41 { actions = { @@ -1083,18 +1026,6 @@ control FabricEgress(inout parsed_headers_t hdr, inout fabric_metadata_t fabric_ } const default_action = egress_next_set_mpls_0(); } - @hidden table tbl_act_5 { - actions = { - act_5(); - } - const default_action = act_5(); - } - @hidden table tbl_act_6 { - actions = { - act_6(); - } - const default_action = act_6(); - } @hidden table tbl_egress_next_push_vlan { actions = { egress_next_push_vlan_0(); @@ -1132,7 +1063,7 @@ control FabricEgress(inout parsed_headers_t hdr, inout fabric_metadata_t fabric_ const default_action = spgw_egress_gtpu_encap_0(); } apply { - tbl_act_4.apply(); + tbl_act_0.apply(); if (fabric_metadata._is_controller_packet_out12 == true) { tbl_packetio41.apply(); } @@ -1155,12 +1086,7 @@ control FabricEgress(inout parsed_headers_t hdr, inout fabric_metadata_t fabric_ } else { tbl_egress_next_set_mpls.apply(); } - if (egress_next_egress_vlan.apply().hit) { - tbl_act_5.apply(); - } else { - tbl_act_6.apply(); - } - if (!egress_next_tmp) { + if (!egress_next_egress_vlan.apply().hit) { if (fabric_metadata._vlan_id2 != 12w4094) { tbl_egress_next_push_vlan.apply(); } diff --git a/testdata/p4_16_samples_outputs/function-frontend.p4 b/testdata/p4_16_samples_outputs/function-frontend.p4 index 4fd793fadb1..6c0788ff7d2 100644 --- a/testdata/p4_16_samples_outputs/function-frontend.p4 +++ b/testdata/p4_16_samples_outputs/function-frontend.p4 @@ -1,5 +1,4 @@ control c(out bit<16> b) { - bit<16> tmp; apply { { bit<16> left_0 = 16w10; @@ -14,9 +13,8 @@ control c(out bit<16> b) { hasReturned = true; retval = right_0; } - tmp = retval; + b = retval; } - b = tmp; } } diff --git a/testdata/p4_16_samples_outputs/functors8-frontend.p4 b/testdata/p4_16_samples_outputs/functors8-frontend.p4 index 8c2f453c368..9d724b2dc45 100644 --- a/testdata/p4_16_samples_outputs/functors8-frontend.p4 +++ b/testdata/p4_16_samples_outputs/functors8-frontend.p4 @@ -8,11 +8,9 @@ extern e { parser simple(out bit<2> a); package m(simple n); parser p1_0(out bit<2> a) { - bit<2> tmp; @name("p1_0.ei") e>() ei_0; state start { - tmp = ei_0.get(); - a = tmp; + a = ei_0.get(); transition accept; } } diff --git a/testdata/p4_16_samples_outputs/functors8-midend.p4 b/testdata/p4_16_samples_outputs/functors8-midend.p4 index 8c2f453c368..9d724b2dc45 100644 --- a/testdata/p4_16_samples_outputs/functors8-midend.p4 +++ b/testdata/p4_16_samples_outputs/functors8-midend.p4 @@ -8,11 +8,9 @@ extern e { parser simple(out bit<2> a); package m(simple n); parser p1_0(out bit<2> a) { - bit<2> tmp; @name("p1_0.ei") e>() ei_0; state start { - tmp = ei_0.get(); - a = tmp; + a = ei_0.get(); transition accept; } } diff --git a/testdata/p4_16_samples_outputs/functors9-frontend.p4 b/testdata/p4_16_samples_outputs/functors9-frontend.p4 index b7c6de2474f..d5e2e21a3fd 100644 --- a/testdata/p4_16_samples_outputs/functors9-frontend.p4 +++ b/testdata/p4_16_samples_outputs/functors9-frontend.p4 @@ -8,10 +8,9 @@ extern e { parser simple(in bit<2> a); package m(simple n); parser p1_0(in bit<2> a) { - bit<2> tmp; @name("p1_0.ei") e>() ei_0; state start { - tmp = ei_0.get(); + ei_0.get(); transition accept; } } diff --git a/testdata/p4_16_samples_outputs/generic1-frontend.p4 b/testdata/p4_16_samples_outputs/generic1-frontend.p4 index ad76d6f7d94..5687f88b53c 100644 --- a/testdata/p4_16_samples_outputs/generic1-frontend.p4 +++ b/testdata/p4_16_samples_outputs/generic1-frontend.p4 @@ -7,13 +7,10 @@ extern Generic { extern void f(in T arg); control caller() { bit<5> cinst_b; - bit<32> cinst_tmp; - bit<5> cinst_tmp_0; @name("caller.cinst.x") Generic>(8w9) cinst_x; apply { - cinst_tmp = cinst_x.get>(); - cinst_tmp_0 = cinst_x.get1, bit<10>>(10w0, 5w0); - cinst_b = cinst_tmp_0; + cinst_x.get>(); + cinst_b = cinst_x.get1, bit<10>>(10w0, 5w0); f>(cinst_b); } } diff --git a/testdata/p4_16_samples_outputs/generic1-midend.p4 b/testdata/p4_16_samples_outputs/generic1-midend.p4 index a3a5039640e..f11d055ce84 100644 --- a/testdata/p4_16_samples_outputs/generic1-midend.p4 +++ b/testdata/p4_16_samples_outputs/generic1-midend.p4 @@ -6,12 +6,12 @@ extern Generic { extern void f(in T arg); control caller() { - bit<5> cinst_tmp_0; + bit<5> cinst_b; @name("caller.cinst.x") Generic>(8w9) cinst_x; @hidden action generic1l28() { cinst_x.get>(); - cinst_tmp_0 = cinst_x.get1, bit<10>>(10w0, 5w0); - f>(cinst_tmp_0); + cinst_b = cinst_x.get1, bit<10>>(10w0, 5w0); + f>(cinst_b); } @hidden table tbl_generic1l28 { actions = { diff --git a/testdata/p4_16_samples_outputs/hit-expr-bmv2-frontend.p4 b/testdata/p4_16_samples_outputs/hit-expr-bmv2-frontend.p4 index 5369191561a..0498e533bfc 100644 --- a/testdata/p4_16_samples_outputs/hit-expr-bmv2-frontend.p4 +++ b/testdata/p4_16_samples_outputs/hit-expr-bmv2-frontend.p4 @@ -25,7 +25,9 @@ control IngressI(inout H hdr, inout M meta, inout standard_metadata_t smeta) { default_action = NoAction_0(); } apply { - t_0.apply(); + if (!t_0.apply().hit) { + ; + } } } diff --git a/testdata/p4_16_samples_outputs/hit-expr-bmv2-midend.p4 b/testdata/p4_16_samples_outputs/hit-expr-bmv2-midend.p4 index 5369191561a..0498e533bfc 100644 --- a/testdata/p4_16_samples_outputs/hit-expr-bmv2-midend.p4 +++ b/testdata/p4_16_samples_outputs/hit-expr-bmv2-midend.p4 @@ -25,7 +25,9 @@ control IngressI(inout H hdr, inout M meta, inout standard_metadata_t smeta) { default_action = NoAction_0(); } apply { - t_0.apply(); + if (!t_0.apply().hit) { + ; + } } } diff --git a/testdata/p4_16_samples_outputs/hit_ebpf-frontend.p4 b/testdata/p4_16_samples_outputs/hit_ebpf-frontend.p4 index 6686b8e4902..88fb3ac9060 100644 --- a/testdata/p4_16_samples_outputs/hit_ebpf-frontend.p4 +++ b/testdata/p4_16_samples_outputs/hit_ebpf-frontend.p4 @@ -46,7 +46,6 @@ parser prs(packet_in p, out Headers_t headers) { control pipe(inout Headers_t headers, out bool pass) { @name(".NoAction") action NoAction_0() { } - bool tmp; @name("pipe.Reject") action Reject(IPv4Address add) { pass = false; headers.ipv4.srcAddr = add; @@ -70,8 +69,7 @@ control pipe(inout Headers_t headers, out bool pass) { hasReturned = true; } if (!hasReturned) { - tmp = Check_src_ip_0.apply().hit; - if (tmp) { + if (Check_src_ip_0.apply().hit) { pass = pass; } } diff --git a/testdata/p4_16_samples_outputs/hit_ebpf-midend.p4 b/testdata/p4_16_samples_outputs/hit_ebpf-midend.p4 index f525f5f899b..fb1ff3ec36f 100644 --- a/testdata/p4_16_samples_outputs/hit_ebpf-midend.p4 +++ b/testdata/p4_16_samples_outputs/hit_ebpf-midend.p4 @@ -44,7 +44,6 @@ parser prs(packet_in p, out Headers_t headers) { } control pipe(inout Headers_t headers, out bool pass) { - bool tmp; bool hasReturned; @name(".NoAction") action NoAction_0() { } @@ -71,12 +70,6 @@ control pipe(inout Headers_t headers, out bool pass) { hasReturned = false; pass = true; } - @hidden action act() { - tmp = true; - } - @hidden action act_0() { - tmp = false; - } @hidden table tbl_hit_ebpf60 { actions = { hit_ebpf60(); @@ -89,18 +82,6 @@ control pipe(inout Headers_t headers, out bool pass) { } const default_action = hit_ebpf63(); } - @hidden table tbl_act { - actions = { - act(); - } - const default_action = act(); - } - @hidden table tbl_act_0 { - actions = { - act_0(); - } - const default_action = act_0(); - } apply { tbl_hit_ebpf60.apply(); if (!headers.ipv4.isValid()) { @@ -108,9 +89,7 @@ control pipe(inout Headers_t headers, out bool pass) { } if (!hasReturned) { if (Check_src_ip_0.apply().hit) { - tbl_act.apply(); - } else { - tbl_act_0.apply(); + ; } } } diff --git a/testdata/p4_16_samples_outputs/inline-control-frontend.p4 b/testdata/p4_16_samples_outputs/inline-control-frontend.p4 index 4b6f5bbaf74..9602e4b2112 100644 --- a/testdata/p4_16_samples_outputs/inline-control-frontend.p4 +++ b/testdata/p4_16_samples_outputs/inline-control-frontend.p4 @@ -5,10 +5,8 @@ extern Y { control d(out bit<32> x) { @name("d.cinst.y") Y(32w16) cinst_y; - bit<32> cinst_tmp; apply { - cinst_tmp = cinst_y.get(); - x = cinst_tmp; + x = cinst_y.get(); } } diff --git a/testdata/p4_16_samples_outputs/inline-control-midend.p4 b/testdata/p4_16_samples_outputs/inline-control-midend.p4 index 78d83e7a188..f13d4010f47 100644 --- a/testdata/p4_16_samples_outputs/inline-control-midend.p4 +++ b/testdata/p4_16_samples_outputs/inline-control-midend.p4 @@ -4,11 +4,9 @@ extern Y { } control d(out bit<32> x) { - bit<32> cinst_tmp; @name("d.cinst.y") Y(32w16) cinst_y; @hidden action inlinecontrol24() { - cinst_tmp = cinst_y.get(); - x = cinst_tmp; + x = cinst_y.get(); } @hidden table tbl_inlinecontrol24 { actions = { diff --git a/testdata/p4_16_samples_outputs/inline-control1-frontend.p4 b/testdata/p4_16_samples_outputs/inline-control1-frontend.p4 index 4b478700035..0a67e00442b 100644 --- a/testdata/p4_16_samples_outputs/inline-control1-frontend.p4 +++ b/testdata/p4_16_samples_outputs/inline-control1-frontend.p4 @@ -7,13 +7,10 @@ control d(out bit<32> x) { bit<32> y_0; bit<32> x_0; @name("d.cinst.y") Y(32w16) cinst_y; - bit<32> cinst_tmp; apply { - cinst_tmp = cinst_y.get(); - x_0 = cinst_tmp; + x_0 = cinst_y.get(); x = x_0; - cinst_tmp = cinst_y.get(); - x_0 = cinst_tmp; + x_0 = cinst_y.get(); y_0 = x_0; } } diff --git a/testdata/p4_16_samples_outputs/inline-control1-midend.p4 b/testdata/p4_16_samples_outputs/inline-control1-midend.p4 index c32fffc7f29..237aad11f23 100644 --- a/testdata/p4_16_samples_outputs/inline-control1-midend.p4 +++ b/testdata/p4_16_samples_outputs/inline-control1-midend.p4 @@ -4,21 +4,21 @@ extern Y { } control d(out bit<32> x) { - bit<32> cinst_tmp; + bit<32> x_0; @name("d.cinst.y") Y(32w16) cinst_y; - @hidden action act() { - cinst_tmp = cinst_y.get(); - x = cinst_tmp; - cinst_tmp = cinst_y.get(); + @hidden action inlinecontrol1l24() { + x_0 = cinst_y.get(); + x = x_0; + x_0 = cinst_y.get(); } - @hidden table tbl_act { + @hidden table tbl_inlinecontrol1l24 { actions = { - act(); + inlinecontrol1l24(); } - const default_action = act(); + const default_action = inlinecontrol1l24(); } apply { - tbl_act.apply(); + tbl_inlinecontrol1l24.apply(); } } diff --git a/testdata/p4_16_samples_outputs/inline-function-frontend.p4 b/testdata/p4_16_samples_outputs/inline-function-frontend.p4 index aa99afa14da..c34ff396565 100644 --- a/testdata/p4_16_samples_outputs/inline-function-frontend.p4 +++ b/testdata/p4_16_samples_outputs/inline-function-frontend.p4 @@ -1,34 +1,32 @@ control c(inout bit<32> x) { - bit<32> tmp; apply { { bit<32> a_0 = x; bit<32> b_0 = x; bool hasReturned = false; bit<32> retval; + bit<32> tmp; bit<32> tmp_0; - bit<32> tmp_1; { bit<32> a_1 = a_0; bit<32> b_1 = b_0; bool hasReturned_0 = false; bit<32> retval_0; - bit<32> tmp_2; + bit<32> tmp_1; if (a_1 > b_1) { - tmp_2 = b_1; + tmp_1 = b_1; } else { - tmp_2 = a_1; + tmp_1 = a_1; } hasReturned_0 = true; - retval_0 = tmp_2; - tmp_0 = retval_0; + retval_0 = tmp_1; + tmp = retval_0; } - tmp_1 = a_0 + tmp_0; + tmp_0 = a_0 + tmp; hasReturned = true; - retval = tmp_1; - tmp = retval; + retval = tmp_0; + x = retval; } - x = tmp; } } diff --git a/testdata/p4_16_samples_outputs/inline-function-midend.p4 b/testdata/p4_16_samples_outputs/inline-function-midend.p4 index c0403d0af1a..600d686d2f3 100644 --- a/testdata/p4_16_samples_outputs/inline-function-midend.p4 +++ b/testdata/p4_16_samples_outputs/inline-function-midend.p4 @@ -1,13 +1,13 @@ control c(inout bit<32> x) { - bit<32> tmp_2; + bit<32> tmp_1; @hidden action inlinefunction2() { - tmp_2 = x; + tmp_1 = x; } @hidden action inlinefunction2_0() { - tmp_2 = x; + tmp_1 = x; } @hidden action inlinefunction11() { - x = x + tmp_2; + x = x + tmp_1; } @hidden table tbl_inlinefunction2 { actions = { diff --git a/testdata/p4_16_samples_outputs/issue1538-frontend.p4 b/testdata/p4_16_samples_outputs/issue1538-frontend.p4 index 8067821bd01..6a48f1ef82a 100644 --- a/testdata/p4_16_samples_outputs/issue1538-frontend.p4 +++ b/testdata/p4_16_samples_outputs/issue1538-frontend.p4 @@ -17,8 +17,6 @@ struct headers { parser ParserImpl(packet_in packet, out headers hdr, inout metadata meta, inout standard_metadata_t standard_metadata) { bit<16> tmp_port_0; - bit<16> tmp; - bit<16> tmp_0; state start { { bit<16> x_0 = (bit<16>)standard_metadata.ingress_port; @@ -26,9 +24,8 @@ parser ParserImpl(packet_in packet, out headers hdr, inout metadata meta, inout bit<16> retval; hasReturned = true; retval = x_0 + 16w1; - tmp = retval; + tmp_port_0 = retval; } - tmp_port_0 = tmp; packet.extract(hdr.ethernet); { bit<16> x_1 = hdr.ethernet.etherType; @@ -36,9 +33,8 @@ parser ParserImpl(packet_in packet, out headers hdr, inout metadata meta, inout bit<16> retval_0; hasReturned_0 = true; retval_0 = x_1 + 16w1; - tmp_0 = retval_0; + hdr.ethernet.etherType = retval_0; } - hdr.ethernet.etherType = tmp_0; meta.tmp_port = tmp_port_0; transition accept; } @@ -48,9 +44,6 @@ control ingress(inout headers hdr, inout metadata meta, inout standard_metadata_ @name(".my_drop") action my_drop(inout standard_metadata_t smeta) { mark_to_drop(smeta); } - bit<16> tmp_1; - bit<16> tmp_2; - bit<16> tmp_3; @name("ingress.set_port") action set_port(bit<9> output_port) { standard_metadata.egress_spec = output_port; } @@ -70,40 +63,37 @@ control ingress(inout headers hdr, inout metadata meta, inout standard_metadata_ bit<16> x_2 = hdr.ethernet.srcAddr[15:0]; bool hasReturned_3 = false; bit<16> retval_3; - bit<16> tmp_4; - bit<16> tmp_5; + bit<16> tmp; + bit<16> tmp_0; { bit<16> x_3 = x_2; bool hasReturned_4 = false; bit<16> retval_4; hasReturned_4 = true; retval_4 = x_3 + 16w1; - tmp_4 = retval_4; + tmp = retval_4; } - tmp_5 = x_2 + tmp_4; + tmp_0 = x_2 + tmp; hasReturned_3 = true; - retval_3 = tmp_5; - tmp_1 = retval_3; + retval_3 = tmp_0; + hdr.ethernet.srcAddr[15:0] = retval_3; } - hdr.ethernet.srcAddr[15:0] = tmp_1; { bit<16> x_4 = hdr.ethernet.srcAddr[15:0]; bool hasReturned_5 = false; bit<16> retval_5; hasReturned_5 = true; retval_5 = x_4 + 16w1; - tmp_2 = retval_5; + hdr.ethernet.srcAddr[15:0] = retval_5; } - hdr.ethernet.srcAddr[15:0] = tmp_2; { bit<16> x_5 = hdr.ethernet.etherType; bool hasReturned_6 = false; bit<16> retval_6; hasReturned_6 = true; retval_6 = x_5 + 16w1; - tmp_3 = retval_6; + hdr.ethernet.etherType = retval_6; } - hdr.ethernet.etherType = tmp_3; } } diff --git a/testdata/p4_16_samples_outputs/issue1544-1-bmv2-frontend.p4 b/testdata/p4_16_samples_outputs/issue1544-1-bmv2-frontend.p4 index 0a48b5a0429..008e1e71b95 100644 --- a/testdata/p4_16_samples_outputs/issue1544-1-bmv2-frontend.p4 +++ b/testdata/p4_16_samples_outputs/issue1544-1-bmv2-frontend.p4 @@ -25,7 +25,6 @@ control ingress(inout headers hdr, inout metadata meta, inout standard_metadata_ @name(".my_drop") action my_drop(inout standard_metadata_t smeta) { mark_to_drop(smeta); } - bit<16> tmp; @name("ingress.set_port") action set_port(bit<9> output_port) { standard_metadata.egress_spec = output_port; } @@ -53,9 +52,8 @@ control ingress(inout headers hdr, inout metadata meta, inout standard_metadata_ } hasReturned = true; retval = tmp_0; - tmp = retval; + hdr.ethernet.srcAddr[15:0] = retval; } - hdr.ethernet.srcAddr[15:0] = tmp; } } diff --git a/testdata/p4_16_samples_outputs/issue1544-2-bmv2-frontend.p4 b/testdata/p4_16_samples_outputs/issue1544-2-bmv2-frontend.p4 index 40fea2dfa64..f503dd08437 100644 --- a/testdata/p4_16_samples_outputs/issue1544-2-bmv2-frontend.p4 +++ b/testdata/p4_16_samples_outputs/issue1544-2-bmv2-frontend.p4 @@ -25,7 +25,6 @@ control ingress(inout headers hdr, inout metadata meta, inout standard_metadata_ @name(".my_drop") action my_drop(inout standard_metadata_t smeta) { mark_to_drop(smeta); } - bit<16> tmp; @name("ingress.set_port") action set_port(bit<9> output_port) { standard_metadata.egress_spec = output_port; } @@ -52,9 +51,8 @@ control ingress(inout headers hdr, inout metadata meta, inout standard_metadata_ } hasReturned = true; retval = tmp_0; - tmp = retval; + hdr.ethernet.srcAddr[15:0] = retval; } - hdr.ethernet.srcAddr[15:0] = tmp; } } diff --git a/testdata/p4_16_samples_outputs/issue1544-2-frontend.p4 b/testdata/p4_16_samples_outputs/issue1544-2-frontend.p4 index 123f0afa789..e1ca38341bd 100644 --- a/testdata/p4_16_samples_outputs/issue1544-2-frontend.p4 +++ b/testdata/p4_16_samples_outputs/issue1544-2-frontend.p4 @@ -3,21 +3,20 @@ control c(inout bit<32> x) { bit<32> tmp_0; bit<32> tmp_1; bit<32> tmp_2; - bit<32> tmp_3; apply { { bit<32> a_0 = x; bit<32> b_0 = x + 32w1; bool hasReturned = false; bit<32> retval; - bit<32> tmp_4; + bit<32> tmp_3; if (a_0 > b_0) { - tmp_4 = b_0; + tmp_3 = b_0; } else { - tmp_4 = a_0; + tmp_3 = a_0; } hasReturned = true; - retval = tmp_4; + retval = tmp_3; tmp = retval; } tmp_0 = tmp; @@ -26,14 +25,14 @@ control c(inout bit<32> x) { bit<32> b_1 = x + 32w4294967295; bool hasReturned_1 = false; bit<32> retval_1; - bit<32> tmp_11; + bit<32> tmp_9; if (a_1 > b_1) { - tmp_11 = b_1; + tmp_9 = b_1; } else { - tmp_11 = a_1; + tmp_9 = a_1; } hasReturned_1 = true; - retval_1 = tmp_11; + retval_1 = tmp_9; tmp_1 = retval_1; } tmp_2 = tmp_1; @@ -42,17 +41,16 @@ control c(inout bit<32> x) { bit<32> b_2 = tmp_2; bool hasReturned_2 = false; bit<32> retval_2; - bit<32> tmp_12; + bit<32> tmp_10; if (a_2 > b_2) { - tmp_12 = b_2; + tmp_10 = b_2; } else { - tmp_12 = a_2; + tmp_10 = a_2; } hasReturned_2 = true; - retval_2 = tmp_12; - tmp_3 = retval_2; + retval_2 = tmp_10; + x = retval_2; } - x = tmp_3; } } diff --git a/testdata/p4_16_samples_outputs/issue1544-2-midend.p4 b/testdata/p4_16_samples_outputs/issue1544-2-midend.p4 index 3db1e43f59f..17730ad8780 100644 --- a/testdata/p4_16_samples_outputs/issue1544-2-midend.p4 +++ b/testdata/p4_16_samples_outputs/issue1544-2-midend.p4 @@ -1,27 +1,27 @@ control c(inout bit<32> x) { - bit<32> tmp_4; - bit<32> tmp_11; - bit<32> tmp_12; + bit<32> tmp_3; + bit<32> tmp_9; + bit<32> tmp_10; @hidden action issue15442l2() { - tmp_4 = x + 32w1; + tmp_3 = x + 32w1; } @hidden action issue15442l2_0() { - tmp_4 = x; + tmp_3 = x; } @hidden action issue15442l2_1() { - tmp_11 = x + 32w4294967295; + tmp_9 = x + 32w4294967295; } @hidden action issue15442l2_2() { - tmp_11 = x; + tmp_9 = x; } @hidden action issue15442l2_3() { - tmp_12 = tmp_11; + tmp_10 = tmp_9; } @hidden action issue15442l2_4() { - tmp_12 = tmp_4; + tmp_10 = tmp_3; } @hidden action issue15442l7() { - x = tmp_12; + x = tmp_10; } @hidden table tbl_issue15442l2 { actions = { @@ -76,7 +76,7 @@ control c(inout bit<32> x) { } else { tbl_issue15442l2_2.apply(); } - if (tmp_4 > tmp_11) { + if (tmp_3 > tmp_9) { tbl_issue15442l2_3.apply(); } else { tbl_issue15442l2_4.apply(); diff --git a/testdata/p4_16_samples_outputs/issue1544-bmv2-frontend.p4 b/testdata/p4_16_samples_outputs/issue1544-bmv2-frontend.p4 index e206688cc39..20b9cb81042 100644 --- a/testdata/p4_16_samples_outputs/issue1544-bmv2-frontend.p4 +++ b/testdata/p4_16_samples_outputs/issue1544-bmv2-frontend.p4 @@ -25,7 +25,6 @@ control ingress(inout headers hdr, inout metadata meta, inout standard_metadata_ @name(".my_drop") action my_drop(inout standard_metadata_t smeta) { mark_to_drop(smeta); } - bit<16> tmp; @name("ingress.set_port") action set_port(bit<9> output_port) { standard_metadata.egress_spec = output_port; } @@ -52,9 +51,8 @@ control ingress(inout headers hdr, inout metadata meta, inout standard_metadata_ hasReturned = true; retval = x_0; } - tmp = retval; + hdr.ethernet.srcAddr[15:0] = retval; } - hdr.ethernet.srcAddr[15:0] = tmp; } } diff --git a/testdata/p4_16_samples_outputs/issue1781-bmv2-frontend.p4 b/testdata/p4_16_samples_outputs/issue1781-bmv2-frontend.p4 index c8df7dc7c4e..0dd1cfe93c8 100644 --- a/testdata/p4_16_samples_outputs/issue1781-bmv2-frontend.p4 +++ b/testdata/p4_16_samples_outputs/issue1781-bmv2-frontend.p4 @@ -15,17 +15,14 @@ parser ParserImpl(packet_in packet, out headers hdr, inout metadata meta, inout control IngressImpl(inout headers hdr, inout metadata meta, inout standard_metadata_t standard_metadata) { bit<32> value_0; - bit<32> tmp; - bit<32> tmp_0; @name("IngressImpl.update_value") action update_value(out bit<32> value_2) { { bool hasReturned = false; bit<32> retval; hasReturned = true; retval = 32w1; - tmp = retval; + value_2 = retval; } - value_2 = tmp; } apply { { @@ -33,7 +30,6 @@ control IngressImpl(inout headers hdr, inout metadata meta, inout standard_metad bit<32> retval_1; hasReturned_1 = true; retval_1 = 32w1; - tmp_0 = retval_1; } update_value(value_0); } diff --git a/testdata/p4_16_samples_outputs/issue2044-bmv2-frontend.p4 b/testdata/p4_16_samples_outputs/issue2044-bmv2-frontend.p4 index 4bb65421c99..4f1d764507c 100644 --- a/testdata/p4_16_samples_outputs/issue2044-bmv2-frontend.p4 +++ b/testdata/p4_16_samples_outputs/issue2044-bmv2-frontend.p4 @@ -42,7 +42,6 @@ control deparser(packet_out b, in Headers h) { control ingress(inout Headers h, inout Meta m, inout standard_metadata_t sm) { @name(".NoAction") action NoAction_0() { } - bool tmp; @name("ingress.t") table t_0 { key = { h.h.b: exact @name("h.h.b") ; @@ -53,8 +52,7 @@ control ingress(inout Headers h, inout Meta m, inout standard_metadata_t sm) { default_action = NoAction_0(); } apply { - tmp = t_0.apply().miss; - if (tmp) { + if (t_0.apply().miss) { h.h.setInvalid(); } } diff --git a/testdata/p4_16_samples_outputs/issue2044-bmv2-midend.p4 b/testdata/p4_16_samples_outputs/issue2044-bmv2-midend.p4 index 289f0fe1664..cbe1c343bc2 100644 --- a/testdata/p4_16_samples_outputs/issue2044-bmv2-midend.p4 +++ b/testdata/p4_16_samples_outputs/issue2044-bmv2-midend.p4 @@ -40,7 +40,6 @@ control deparser(packet_out b, in Headers h) { } control ingress(inout Headers h, inout Meta m, inout standard_metadata_t sm) { - bool tmp; @name(".NoAction") action NoAction_0() { } @name("ingress.t") table t_0 { @@ -52,27 +51,9 @@ control ingress(inout Headers h, inout Meta m, inout standard_metadata_t sm) { } default_action = NoAction_0(); } - @hidden action act() { - tmp = false; - } - @hidden action act_0() { - tmp = true; - } @hidden action issue2044bmv2l37() { h.h.setInvalid(); } - @hidden table tbl_act { - actions = { - act(); - } - const default_action = act(); - } - @hidden table tbl_act_0 { - actions = { - act_0(); - } - const default_action = act_0(); - } @hidden table tbl_issue2044bmv2l37 { actions = { issue2044bmv2l37(); @@ -80,12 +61,7 @@ control ingress(inout Headers h, inout Meta m, inout standard_metadata_t sm) { const default_action = issue2044bmv2l37(); } apply { - if (t_0.apply().hit) { - tbl_act.apply(); - } else { - tbl_act_0.apply(); - } - if (tmp) { + if (!t_0.apply().hit) { tbl_issue2044bmv2l37.apply(); } } diff --git a/testdata/p4_16_samples_outputs/issue841-frontend.p4 b/testdata/p4_16_samples_outputs/issue841-frontend.p4 index 998508d2691..f3041497fb3 100644 --- a/testdata/p4_16_samples_outputs/issue841-frontend.p4 +++ b/testdata/p4_16_samples_outputs/issue841-frontend.p4 @@ -43,13 +43,11 @@ control MyDeparser(packet_out packet, in headers hdr) { control MyComputeChecksum(inout headers hdr, inout metadata meta) { h_t h_0; - bit<16> tmp; @name("MyComputeChecksum.checksum") Checksum16() checksum_0; apply { h_0.setValid(); h_0 = { hdr.h.src, hdr.h.dst, 16w0 }; - tmp = checksum_0.get(h_0); - hdr.h.csum = tmp; + hdr.h.csum = checksum_0.get(h_0); } } diff --git a/testdata/p4_16_samples_outputs/issue841-midend.p4 b/testdata/p4_16_samples_outputs/issue841-midend.p4 index dfff38d1cd8..5ea4bc996bb 100644 --- a/testdata/p4_16_samples_outputs/issue841-midend.p4 +++ b/testdata/p4_16_samples_outputs/issue841-midend.p4 @@ -43,15 +43,13 @@ control MyDeparser(packet_out packet, in headers hdr) { control MyComputeChecksum(inout headers hdr, inout metadata meta) { h_t h_0; - bit<16> tmp; @name("MyComputeChecksum.checksum") Checksum16() checksum_0; apply { h_0.setValid(); h_0.src = hdr.h.src; h_0.dst = hdr.h.dst; h_0.csum = 16w0; - tmp = checksum_0.get(h_0); - hdr.h.csum = tmp; + hdr.h.csum = checksum_0.get(h_0); } } diff --git a/testdata/p4_16_samples_outputs/issue949-frontend.p4 b/testdata/p4_16_samples_outputs/issue949-frontend.p4 index d0c1da927a9..e78d230c7c8 100644 --- a/testdata/p4_16_samples_outputs/issue949-frontend.p4 +++ b/testdata/p4_16_samples_outputs/issue949-frontend.p4 @@ -48,7 +48,6 @@ control egress(inout headers hdr, inout metadata meta, inout standard_metadata_t control ingress(inout headers hdr, inout metadata meta, inout standard_metadata_t standard_metadata) { @name(".NoAction") action NoAction_0() { } - bool tmp; @name("ingress.setDest") action setDest() { hdr.ethernet.dstAddr = 48w0x6af3400426d3; } @@ -63,7 +62,7 @@ control ingress(inout headers hdr, inout metadata meta, inout standard_metadata_ default_action = NoAction_0(); } apply { - tmp = someTable_0.apply().hit; + someTable_0.apply(); } } diff --git a/testdata/p4_16_samples_outputs/key-issue-1020_ebpf-frontend.p4 b/testdata/p4_16_samples_outputs/key-issue-1020_ebpf-frontend.p4 index e68e44e8d88..6b7c2e76c42 100644 --- a/testdata/p4_16_samples_outputs/key-issue-1020_ebpf-frontend.p4 +++ b/testdata/p4_16_samples_outputs/key-issue-1020_ebpf-frontend.p4 @@ -44,7 +44,6 @@ parser prs(packet_in p, out Headers_t headers) { } control pipe(inout Headers_t headers, out bool pass) { - bool tmp; @name("pipe.invalidate") action invalidate() { headers.ipv4.setInvalid(); headers.ethernet.setInvalid(); @@ -68,7 +67,7 @@ control pipe(inout Headers_t headers, out bool pass) { default_action = drop(); } apply { - tmp = t_0.apply().hit; + t_0.apply(); } } diff --git a/testdata/p4_16_samples_outputs/psa-example-parser-checksum-frontend.p4 b/testdata/p4_16_samples_outputs/psa-example-parser-checksum-frontend.p4 index 65f735c9e13..a01f6362890 100644 --- a/testdata/p4_16_samples_outputs/psa-example-parser-checksum-frontend.p4 +++ b/testdata/p4_16_samples_outputs/psa-example-parser-checksum-frontend.p4 @@ -157,13 +157,11 @@ control IngressDeparserImpl(packet_out packet, out empty_metadata_t clone_i2e_me } control EgressDeparserImpl(packet_out packet, out empty_metadata_t clone_e2e_meta, out empty_metadata_t recirculate_meta, inout headers hdr, in metadata meta, in psa_egress_output_metadata_t istd, in psa_egress_deparser_input_metadata_t edstd) { - bit<16> tmp_2; @name("EgressDeparserImpl.ck") InternetChecksum() ck_1; apply { ck_1.clear(); ck_1.add, bit<4>, bit<8>, bit<16>, bit<16>, bit<3>, bit<13>, bit<8>, bit<8>, bit<32>, bit<32>>>({ hdr.ipv4.version, hdr.ipv4.ihl, hdr.ipv4.diffserv, hdr.ipv4.totalLen, hdr.ipv4.identification, hdr.ipv4.flags, hdr.ipv4.fragOffset, hdr.ipv4.ttl, hdr.ipv4.protocol, hdr.ipv4.srcAddr, hdr.ipv4.dstAddr }); - tmp_2 = ck_1.get(); - hdr.ipv4.hdrChecksum = tmp_2; + hdr.ipv4.hdrChecksum = ck_1.get(); packet.emit(hdr.ethernet); packet.emit(hdr.ipv4); packet.emit(hdr.tcp); diff --git a/testdata/p4_16_samples_outputs/psa-example-parser-checksum-midend.p4 b/testdata/p4_16_samples_outputs/psa-example-parser-checksum-midend.p4 index 035a3cf3179..8aa94f32b65 100644 --- a/testdata/p4_16_samples_outputs/psa-example-parser-checksum-midend.p4 +++ b/testdata/p4_16_samples_outputs/psa-example-parser-checksum-midend.p4 @@ -201,13 +201,11 @@ control IngressDeparserImpl(packet_out packet, out empty_metadata_t clone_i2e_me } control EgressDeparserImpl(packet_out packet, out empty_metadata_t clone_e2e_meta, out empty_metadata_t recirculate_meta, inout headers hdr, in metadata meta, in psa_egress_output_metadata_t istd, in psa_egress_deparser_input_metadata_t edstd) { - bit<16> tmp_2; @name("EgressDeparserImpl.ck") InternetChecksum() ck_1; @hidden action psaexampleparserchecksum238() { ck_1.clear(); ck_1.add({ hdr.ipv4.version, hdr.ipv4.ihl, hdr.ipv4.diffserv, hdr.ipv4.totalLen, hdr.ipv4.identification, hdr.ipv4.flags, hdr.ipv4.fragOffset, hdr.ipv4.ttl, hdr.ipv4.protocol, hdr.ipv4.srcAddr, hdr.ipv4.dstAddr }); - tmp_2 = ck_1.get(); - hdr.ipv4.hdrChecksum = tmp_2; + hdr.ipv4.hdrChecksum = ck_1.get(); packet.emit(hdr.ethernet); packet.emit(hdr.ipv4); packet.emit(hdr.tcp); diff --git a/testdata/p4_16_samples_outputs/psa-example-register2-bmv2-frontend.p4 b/testdata/p4_16_samples_outputs/psa-example-register2-bmv2-frontend.p4 index 52a1939b0df..eaec2b6eb76 100644 --- a/testdata/p4_16_samples_outputs/psa-example-register2-bmv2-frontend.p4 +++ b/testdata/p4_16_samples_outputs/psa-example-register2-bmv2-frontend.p4 @@ -58,16 +58,14 @@ control ingress(inout headers hdr, inout metadata user_meta, in psa_ingress_inpu s[79:48] = s[79:48] + 32w1; s[47:0] = s[47:0] + (bit<48>)ip_length_bytes; } - PacketByteCountState_t tmp; - bit<80> tmp_0; + PacketByteCountState_t tmp_0; @name("ingress.port_pkt_ip_bytes_in") Register(32w512) port_pkt_ip_bytes_in_0; apply { ostd.egress_port = (PortId_t)32w0; if (hdr.ipv4.isValid()) @atomic { tmp_0 = port_pkt_ip_bytes_in_0.read(istd.ingress_port); - tmp = tmp_0; - update_pkt_ip_byte_count(tmp, hdr.ipv4.totalLen); - port_pkt_ip_bytes_in_0.write(istd.ingress_port, tmp); + update_pkt_ip_byte_count(tmp_0, hdr.ipv4.totalLen); + port_pkt_ip_bytes_in_0.write(istd.ingress_port, tmp_0); } } } diff --git a/testdata/p4_16_samples_outputs/psa-example-register2-bmv2-midend.p4 b/testdata/p4_16_samples_outputs/psa-example-register2-bmv2-midend.p4 index c145b747a56..ae98a5ef0bc 100644 --- a/testdata/p4_16_samples_outputs/psa-example-register2-bmv2-midend.p4 +++ b/testdata/p4_16_samples_outputs/psa-example-register2-bmv2-midend.p4 @@ -53,22 +53,20 @@ parser IngressParserImpl(packet_in buffer, out headers parsed_hdr, inout metadat } control ingress(inout headers hdr, inout metadata user_meta, in psa_ingress_input_metadata_t istd, inout psa_ingress_output_metadata_t ostd) { - PacketByteCountState_t tmp; - bit<80> tmp_0; + PacketByteCountState_t tmp_0; PacketByteCountState_t s; @name(".update_pkt_ip_byte_count") action update_pkt_ip_byte_count() { - s = tmp; - s[79:48] = tmp[79:48] + 32w1; + s = tmp_0; + s[79:48] = tmp_0[79:48] + 32w1; s[47:0] = s[47:0] + (bit<48>)hdr.ipv4.totalLen; - tmp = s; + tmp_0 = s; } @name("ingress.port_pkt_ip_bytes_in") Register(32w512) port_pkt_ip_bytes_in_0; @hidden action psaexampleregister2bmv2l127() { tmp_0 = port_pkt_ip_bytes_in_0.read(istd.ingress_port); - tmp = tmp_0; } @hidden action psaexampleregister2bmv2l129() { - port_pkt_ip_bytes_in_0.write(istd.ingress_port, tmp); + port_pkt_ip_bytes_in_0.write(istd.ingress_port, tmp_0); } @hidden action psaexampleregister2bmv2l123() { ostd.egress_port = 32w0; diff --git a/testdata/p4_16_samples_outputs/psa-hash-frontend.p4 b/testdata/p4_16_samples_outputs/psa-hash-frontend.p4 index 6d490b47fc4..9687897e7ce 100644 --- a/testdata/p4_16_samples_outputs/psa-hash-frontend.p4 +++ b/testdata/p4_16_samples_outputs/psa-hash-frontend.p4 @@ -31,11 +31,9 @@ parser MyEP(packet_in buffer, out EMPTY a, inout EMPTY b, in psa_egress_parser_i control MyIC(inout ethernet_t a, inout user_meta_t b, in psa_ingress_input_metadata_t c, inout psa_ingress_output_metadata_t d) { @name(".NoAction") action NoAction_0() { } - bit<16> tmp; @name("MyIC.h") Hash>(PSA_HashAlgorithm_t.CRC16) h_0; @name("MyIC.a1") action a1() { - tmp = h_0.get_hash(a); - b.data = tmp; + b.data = h_0.get_hash(a); } @name("MyIC.tbl") table tbl_0 { key = { diff --git a/testdata/p4_16_samples_outputs/psa-hash-midend.p4 b/testdata/p4_16_samples_outputs/psa-hash-midend.p4 index fff64c74d88..9687897e7ce 100644 --- a/testdata/p4_16_samples_outputs/psa-hash-midend.p4 +++ b/testdata/p4_16_samples_outputs/psa-hash-midend.p4 @@ -29,13 +29,11 @@ parser MyEP(packet_in buffer, out EMPTY a, inout EMPTY b, in psa_egress_parser_i } control MyIC(inout ethernet_t a, inout user_meta_t b, in psa_ingress_input_metadata_t c, inout psa_ingress_output_metadata_t d) { - bit<16> tmp; @name(".NoAction") action NoAction_0() { } @name("MyIC.h") Hash>(PSA_HashAlgorithm_t.CRC16) h_0; @name("MyIC.a1") action a1() { - tmp = h_0.get_hash(a); - b.data = tmp; + b.data = h_0.get_hash(a); } @name("MyIC.tbl") table tbl_0 { key = { diff --git a/testdata/p4_16_samples_outputs/psa-random-frontend.p4 b/testdata/p4_16_samples_outputs/psa-random-frontend.p4 index a63479ba83f..58f9cbcd2d8 100644 --- a/testdata/p4_16_samples_outputs/psa-random-frontend.p4 +++ b/testdata/p4_16_samples_outputs/psa-random-frontend.p4 @@ -31,11 +31,9 @@ parser MyEP(packet_in buffer, out EMPTY a, inout EMPTY b, in psa_egress_parser_i control MyIC(inout ethernet_t a, inout user_meta_t b, in psa_ingress_input_metadata_t c, inout psa_ingress_output_metadata_t d) { @name(".NoAction") action NoAction_0() { } - bit<16> tmp; @name("MyIC.rand") Random>(16w200, 16w400) rand_0; @name("MyIC.execute_random") action execute_random() { - tmp = rand_0.read(); - b.data = tmp; + b.data = rand_0.read(); } @name("MyIC.tbl") table tbl_0 { key = { diff --git a/testdata/p4_16_samples_outputs/psa-random-midend.p4 b/testdata/p4_16_samples_outputs/psa-random-midend.p4 index 4262110ee49..58f9cbcd2d8 100644 --- a/testdata/p4_16_samples_outputs/psa-random-midend.p4 +++ b/testdata/p4_16_samples_outputs/psa-random-midend.p4 @@ -29,13 +29,11 @@ parser MyEP(packet_in buffer, out EMPTY a, inout EMPTY b, in psa_egress_parser_i } control MyIC(inout ethernet_t a, inout user_meta_t b, in psa_ingress_input_metadata_t c, inout psa_ingress_output_metadata_t d) { - bit<16> tmp; @name(".NoAction") action NoAction_0() { } @name("MyIC.rand") Random>(16w200, 16w400) rand_0; @name("MyIC.execute_random") action execute_random() { - tmp = rand_0.read(); - b.data = tmp; + b.data = rand_0.read(); } @name("MyIC.tbl") table tbl_0 { key = { diff --git a/testdata/p4_16_samples_outputs/psa-register1-frontend.p4 b/testdata/p4_16_samples_outputs/psa-register1-frontend.p4 index 9b227876516..cfddd771062 100644 --- a/testdata/p4_16_samples_outputs/psa-register1-frontend.p4 +++ b/testdata/p4_16_samples_outputs/psa-register1-frontend.p4 @@ -27,10 +27,9 @@ parser MyEP(packet_in buffer, out EMPTY a, inout EMPTY b, in psa_egress_parser_i control MyIC(inout ethernet_t a, inout EMPTY b, in psa_ingress_input_metadata_t c, inout psa_ingress_output_metadata_t d) { @name(".NoAction") action NoAction_0() { } - bit<10> tmp; @name("MyIC.reg") Register, bit<10>>(32w1024) reg_0; @name("MyIC.execute_register") action execute_register(bit<10> idx) { - tmp = reg_0.read(idx); + reg_0.read(idx); } @name("MyIC.tbl") table tbl_0 { key = { diff --git a/testdata/p4_16_samples_outputs/side_effects-frontend.p4 b/testdata/p4_16_samples_outputs/side_effects-frontend.p4 index 1ac41409ab1..c32371f21bb 100644 --- a/testdata/p4_16_samples_outputs/side_effects-frontend.p4 +++ b/testdata/p4_16_samples_outputs/side_effects-frontend.p4 @@ -17,32 +17,23 @@ control my() { bit<1> tmp_4; bit<1> tmp_5; bit<1> tmp_6; - bit<1> tmp_7; - bit<1> tmp_8; - bit<1> tmp_9; - bit<1> tmp_10; - bit<1> tmp_11; apply { a_0 = 1w0; tmp = g(a_0); tmp_0 = tmp; - tmp_1 = f(a_0, tmp_0); - a_0 = tmp_1; - tmp_2 = g(a_0); - tmp_3 = tmp_2; - tmp_4 = f(s_0[a_0].z, tmp_3); - a_0 = tmp_4; - tmp_5 = g(a_0); - tmp_6 = tmp_5; - tmp_7 = s_0[tmp_6].z; - tmp_8 = f(tmp_7, a_0); - s_0[tmp_6].z = tmp_7; - a_0 = tmp_8; - tmp_9 = g(a_0); - a_0 = tmp_9; - tmp_10 = g(a_0[0:0]); - a_0[0:0] = tmp_10; - tmp_11 = g(a_0); + a_0 = f(a_0, tmp_0); + tmp_1 = g(a_0); + tmp_2 = tmp_1; + a_0 = f(s_0[a_0].z, tmp_2); + tmp_3 = g(a_0); + tmp_4 = tmp_3; + tmp_5 = s_0[tmp_4].z; + tmp_6 = f(tmp_5, a_0); + s_0[tmp_4].z = tmp_5; + a_0 = tmp_6; + a_0 = g(a_0); + a_0[0:0] = g(a_0[0:0]); + g(a_0); } } diff --git a/testdata/p4_16_samples_outputs/side_effects-midend.p4 b/testdata/p4_16_samples_outputs/side_effects-midend.p4 index 01dd213fd86..50b033a32e2 100644 --- a/testdata/p4_16_samples_outputs/side_effects-midend.p4 +++ b/testdata/p4_16_samples_outputs/side_effects-midend.p4 @@ -11,30 +11,22 @@ control my() { H[2] s_0; bit<1> tmp; bit<1> tmp_1; - bit<1> tmp_2; - bit<1> tmp_4; + bit<1> tmp_3; bit<1> tmp_5; - bit<1> tmp_7; - bit<1> tmp_8; - bit<1> tmp_9; - bit<1> tmp_10; + bit<1> tmp_6; @hidden action side_effects27() { a_0 = 1w0; tmp = g(a_0); - tmp_1 = f(a_0, tmp); - a_0 = tmp_1; - tmp_2 = g(a_0); - tmp_4 = f(s_0[a_0].z, tmp_2); - a_0 = tmp_4; - tmp_5 = g(a_0); - tmp_7 = s_0[tmp_5].z; - tmp_8 = f(tmp_7, a_0); - s_0[tmp_5].z = tmp_7; - a_0 = tmp_8; - tmp_9 = g(a_0); - a_0 = tmp_9; - tmp_10 = g(a_0[0:0]); - a_0[0:0] = tmp_10; + a_0 = f(a_0, tmp); + tmp_1 = g(a_0); + a_0 = f(s_0[a_0].z, tmp_1); + tmp_3 = g(a_0); + tmp_5 = s_0[tmp_3].z; + tmp_6 = f(tmp_5, a_0); + s_0[tmp_3].z = tmp_5; + a_0 = tmp_6; + a_0 = g(a_0); + a_0[0:0] = g(a_0[0:0]); g(a_0); } @hidden table tbl_side_effects27 { diff --git a/testdata/p4_16_samples_outputs/unused-frontend.p4 b/testdata/p4_16_samples_outputs/unused-frontend.p4 index 9e4ae9962a6..e75f1b0e100 100644 --- a/testdata/p4_16_samples_outputs/unused-frontend.p4 +++ b/testdata/p4_16_samples_outputs/unused-frontend.p4 @@ -16,15 +16,13 @@ extern E { } control c(inout S s) { - bit<32> tmp; @name("c.e") E() e_0; apply { if (s.h.isValid()) { s.h.data3 = 32w0; } if (s.h.data2 == 32w0) { - tmp = e_0.get>(s.h.data2); - s.h.data1 = tmp; + s.h.data1 = e_0.get>(s.h.data2); } } } diff --git a/testdata/p4_16_samples_outputs/unused-midend.p4 b/testdata/p4_16_samples_outputs/unused-midend.p4 index b09c27aeb27..95c7aca0c3e 100644 --- a/testdata/p4_16_samples_outputs/unused-midend.p4 +++ b/testdata/p4_16_samples_outputs/unused-midend.p4 @@ -16,14 +16,12 @@ extern E { } control c(inout S s) { - bit<32> tmp; @name("c.e") E() e_0; @hidden action unused38() { s.h.data3 = 32w0; } @hidden action unused40() { - tmp = e_0.get>(s.h.data2); - s.h.data1 = tmp; + s.h.data1 = e_0.get>(s.h.data2); } @hidden table tbl_unused38 { actions = { diff --git a/testdata/p4_16_samples_outputs/value-sets-frontend.p4 b/testdata/p4_16_samples_outputs/value-sets-frontend.p4 index 045a78b3605..ed18546da4a 100644 --- a/testdata/p4_16_samples_outputs/value-sets-frontend.p4 +++ b/testdata/p4_16_samples_outputs/value-sets-frontend.p4 @@ -17,7 +17,6 @@ extern ValueSet { parser TopParser(packet_in b, out Parsed_packet p) { bit<8> setIndex_0; - bit<8> tmp; @name("TopParser.ethtype_kinds") ValueSet(32w5) ethtype_kinds_0; state start { b.extract(p.ethernet); @@ -29,8 +28,7 @@ parser TopParser(packet_in b, out Parsed_packet p) { } } state dispatch_value_sets { - tmp = ethtype_kinds_0.index(p.ethernet.etherType); - setIndex_0 = tmp; + setIndex_0 = ethtype_kinds_0.index(p.ethernet.etherType); transition select(setIndex_0) { 8w1: parse_trill; 8w2: parse_vlan_tag; diff --git a/testdata/p4_16_samples_outputs/value-sets-midend.p4 b/testdata/p4_16_samples_outputs/value-sets-midend.p4 index 7b76965972b..93f49f9fc8d 100644 --- a/testdata/p4_16_samples_outputs/value-sets-midend.p4 +++ b/testdata/p4_16_samples_outputs/value-sets-midend.p4 @@ -16,7 +16,7 @@ extern ValueSet { } parser TopParser(packet_in b, out Parsed_packet p) { - bit<8> tmp; + bit<8> setIndex_0; @name("TopParser.ethtype_kinds") ValueSet(32w5) ethtype_kinds_0; state start { b.extract(p.ethernet); @@ -28,8 +28,8 @@ parser TopParser(packet_in b, out Parsed_packet p) { } } state dispatch_value_sets { - tmp = ethtype_kinds_0.index(p.ethernet.etherType); - transition select(tmp) { + setIndex_0 = ethtype_kinds_0.index(p.ethernet.etherType); + transition select(setIndex_0) { 8w1: parse_trill; 8w2: parse_vlan_tag; default: noMatch; diff --git a/testdata/p4_16_samples_outputs/virtual-frontend.p4 b/testdata/p4_16_samples_outputs/virtual-frontend.p4 index 0f1c0437bd6..76d09c7135c 100644 --- a/testdata/p4_16_samples_outputs/virtual-frontend.p4 +++ b/testdata/p4_16_samples_outputs/virtual-frontend.p4 @@ -10,7 +10,6 @@ extern Virtual { } control c(inout bit<16> p) { - bit<16> tmp; @name("c.cntr") Virtual() cntr_0 = { bit<16> f(in bit<16> ix) { return ix + 16w1; @@ -27,8 +26,7 @@ control c(inout bit<16> p) { } }; apply { - tmp = cntr_0.f(16w6); - p = tmp; + p = cntr_0.f(16w6); } } diff --git a/testdata/p4_16_samples_outputs/virtual-midend.p4 b/testdata/p4_16_samples_outputs/virtual-midend.p4 index 178443ecf1b..b3211eef6ed 100644 --- a/testdata/p4_16_samples_outputs/virtual-midend.p4 +++ b/testdata/p4_16_samples_outputs/virtual-midend.p4 @@ -10,7 +10,6 @@ extern Virtual { } control c(inout bit<16> p) { - bit<16> tmp; @name("c.cntr") Virtual() cntr_0 = { bit<16> f(in bit<16> ix) { return ix + 16w1; @@ -28,8 +27,7 @@ control c(inout bit<16> p) { } }; @hidden action virtual51() { - tmp = cntr_0.f(16w6); - p = tmp; + p = cntr_0.f(16w6); } @hidden table tbl_virtual51 { actions = { diff --git a/testdata/p4_16_samples_outputs/virtual3-frontend.p4 b/testdata/p4_16_samples_outputs/virtual3-frontend.p4 index 405fc3530fe..d8285f4f3f8 100644 --- a/testdata/p4_16_samples_outputs/virtual3-frontend.p4 +++ b/testdata/p4_16_samples_outputs/virtual3-frontend.p4 @@ -11,15 +11,13 @@ control c(inout bit<16> p) { @name(".NoAction") action NoAction_0() { } bit<16> local_0; - bit<16> tmp; @name("c.cntr") Virtual() cntr_0 = { bit<16> f(in bit<16> ix) { return ix + local_0; } }; @name("c.final_ctr") action final_ctr() { - tmp = cntr_0.total(); - p = tmp; + p = cntr_0.total(); } @name("c.add_ctr") action add_ctr() { cntr_0.increment(); diff --git a/testdata/p4_16_samples_outputs/virtual3-midend.p4 b/testdata/p4_16_samples_outputs/virtual3-midend.p4 index 48d6856070e..910e2957e58 100644 --- a/testdata/p4_16_samples_outputs/virtual3-midend.p4 +++ b/testdata/p4_16_samples_outputs/virtual3-midend.p4 @@ -9,7 +9,6 @@ extern Virtual { control c(inout bit<16> p) { bit<16> local_0; - bit<16> tmp; @name(".NoAction") action NoAction_0() { } @name("c.cntr") Virtual() cntr_0 = { @@ -18,8 +17,7 @@ control c(inout bit<16> p) { } }; @name("c.final_ctr") action final_ctr() { - tmp = cntr_0.total(); - p = tmp; + p = cntr_0.total(); } @name("c.add_ctr") action add_ctr() { cntr_0.increment(); diff --git a/testdata/p4_16_samples_outputs/vss-example-frontend.p4 b/testdata/p4_16_samples_outputs/vss-example-frontend.p4 index 01ea1a6e541..24890e02823 100644 --- a/testdata/p4_16_samples_outputs/vss-example-frontend.p4 +++ b/testdata/p4_16_samples_outputs/vss-example-frontend.p4 @@ -182,7 +182,6 @@ control TopPipe(inout Parsed_packet headers, in error parseError, in InControl i } control TopDeparser(inout Parsed_packet p, packet_out b) { - bit<16> tmp_2; @name("TopDeparser.ck") Ck16() ck_1; apply { b.emit(p.ethernet); @@ -190,8 +189,7 @@ control TopDeparser(inout Parsed_packet p, packet_out b) { ck_1.clear(); p.ip.hdrChecksum = 16w0; ck_1.update(p.ip); - tmp_2 = ck_1.get(); - p.ip.hdrChecksum = tmp_2; + p.ip.hdrChecksum = ck_1.get(); } b.emit(p.ip); } diff --git a/testdata/p4_16_samples_outputs/vss-example-midend.p4 b/testdata/p4_16_samples_outputs/vss-example-midend.p4 index 6c9e8a87512..00e0d8b3f70 100644 --- a/testdata/p4_16_samples_outputs/vss-example-midend.p4 +++ b/testdata/p4_16_samples_outputs/vss-example-midend.p4 @@ -235,14 +235,12 @@ control TopPipe(inout Parsed_packet headers, in error parseError, in InControl i } control TopDeparser(inout Parsed_packet p, packet_out b) { - bit<16> tmp_2; @name("TopDeparser.ck") Ck16() ck_1; @hidden action vssexample213() { ck_1.clear(); p.ip.hdrChecksum = 16w0; ck_1.update(p.ip); - tmp_2 = ck_1.get(); - p.ip.hdrChecksum = tmp_2; + p.ip.hdrChecksum = ck_1.get(); } @hidden action vssexample211() { b.emit(p.ethernet); From 90a8f3f7cbd242c8759f66cb7cf8e3966a173e18 Mon Sep 17 00:00:00 2001 From: Chris Dodd Date: Thu, 26 Dec 2019 21:13:39 -0800 Subject: [PATCH 052/106] Allow primitive calls in bbox expressions (#2119) --- frontends/p4/fromv1.0/converters.cpp | 8 +++++++- frontends/p4/typeChecking/bindVariables.cpp | 6 +++++- frontends/parsers/v1/v1parser.ypp | 9 ++++++--- ir/dump.cpp | 2 +- 4 files changed, 19 insertions(+), 6 deletions(-) diff --git a/frontends/p4/fromv1.0/converters.cpp b/frontends/p4/fromv1.0/converters.cpp index a829978e83d..10fdd071a8d 100644 --- a/frontends/p4/fromv1.0/converters.cpp +++ b/frontends/p4/fromv1.0/converters.cpp @@ -123,8 +123,14 @@ const IR::Node* ExpressionConverter::postorder(IR::Primitive* primitive) { auto result = new IR::MethodCallExpression(primitive->srcInfo, IR::Type::Boolean::get(), method); return result; + } else { + auto func = new IR::PathExpression(IR::ID(primitive->srcInfo, primitive->name)); + auto args = new IR::Vector; + for (auto *op : primitive->operands) + args->push_back(new IR::Argument(op)); + auto result = new IR::MethodCallExpression(primitive->srcInfo, func, args); + return result; } - BUG("Unexpected primitive %1%", primitive); } const IR::Node* ExpressionConverter::postorder(IR::PathExpression *ref) { diff --git a/frontends/p4/typeChecking/bindVariables.cpp b/frontends/p4/typeChecking/bindVariables.cpp index 437aa2a3fed..7434d94eba1 100644 --- a/frontends/p4/typeChecking/bindVariables.cpp +++ b/frontends/p4/typeChecking/bindVariables.cpp @@ -93,9 +93,13 @@ const IR::Node* DoBindTypeVariables::postorder(IR::Declaration_Instance* decl) { } const IR::Node* DoBindTypeVariables::postorder(IR::MethodCallExpression* expression) { + auto type = typeMap->getType(getOriginal(), true); + typeMap->setType(expression, type); + if (typeMap->isCompileTimeConstant(getOriginal())) + typeMap->setCompileTimeConstant(expression); if (!expression->typeArguments->empty()) return expression; - auto type = typeMap->getType(expression->method, true); + type = typeMap->getType(expression->method, true); BUG_CHECK(type->is(), "%1%: unexpected type %2% for method", expression->method, type); auto mt = type->to(); diff --git a/frontends/parsers/v1/v1parser.ypp b/frontends/parsers/v1/v1parser.ypp index 2c6010ce075..571dd665987 100644 --- a/frontends/parsers/v1/v1parser.ypp +++ b/frontends/parsers/v1/v1parser.ypp @@ -190,7 +190,8 @@ static const IR::Expression *removeRedundantValid(const IR::Expression *e); %token IDENTIFIER STRING_LITERAL %token INTEGER -%left EXPRLIST +%precedence IDENTIFIER +%left EXPRLIST COMMA R_PAREN %right ASSIGN %left OR %left AND @@ -202,7 +203,7 @@ static const IR::Expression *removeRedundantValid(const IR::Expression *e); %left SHL SHR %left PLUS MINUS %left MUL DIV MOD -%right PREFIX +%right PREFIX L_PAREN %precedence IF %precedence ELSE @@ -947,12 +948,14 @@ blackbox_config: /* epsilon */ { $$ = new IR::NameMap; } ($$=$1)->add($2, new IR::Property(@2+@4, $2, pv, false)); } ; -expressions: /* epsilon */ +expressions: /* epsilon */ %prec EXPRLIST { $$ = new IR::Vector; } | expressions expression %prec EXPRLIST { ($$=$1)->push_back($2); $$->srcInfo += @2; } | expressions "," expression %prec EXPRLIST { ($$=$1)->push_back($3); $$->srcInfo += @3; } + | expressions IDENTIFIER "(" expressions ")" %prec EXPRLIST + { ($$=$1)->push_back(new IR::Primitive(@2, $2, $4)); $$->srcInfo += @5; } ; pragma_operands: /* epsilon */ diff --git a/ir/dump.cpp b/ir/dump.cpp index fb0c908bf84..730a97c32c2 100644 --- a/ir/dump.cpp +++ b/ir/dump.cpp @@ -27,7 +27,7 @@ class IRDumper : public Inspector { if (auto ctxt = getContext()) { if (unsigned(ctxt->depth) > maxdepth) return false; - if (ctxt->child_name && ignore == ctxt->child_name) + if (ctxt->parent && ctxt->parent->child_name && ignore == ctxt->parent->child_name) return false; out << indent_t(ctxt->depth); if (ctxt->child_name) From bbdc2a3ffc300f7b72783bc20d03796c35e53a53 Mon Sep 17 00:00:00 2001 From: Nate Foster Date: Thu, 9 Jan 2020 13:09:34 -0400 Subject: [PATCH 053/106] Correctly parse action references in const table entries (#2129) * Correctly parse action references in const table entries This pull request fixes a discrepancy between the language specification and `p4c` related to the syntax for action references in const table entries. The grammar in the langauge specification allows action references to be given without parentheses: ``` entry : keysetExpression ':' actionRef optAnnotations ';' ; actionRef : optAnnotations prefixedNonTypeName | optAnnotations prefixedNonTypeName '(' argumentList ')' ; ``` However, the grammar in the `p4c` parser required all action references to be given with parentheses: ``` entry : keysetExpression ":" actionBinding optAnnotations ";" { ... } ; actionBinding : lvalue "(" argumentList ")" { ... } | lvalue "<" typeArgumentList ">" "(" argumentList ")" { ... } ; ``` This pull request adds a new clause to the `actionBinding` rule to handle actions without parentheses, as well as a unit test (`table-entries-no-arg-actions.p4`) that checks whether such action references are correctly parsed. * Relocate annotations from `actionRef` to `actionList` * Streamline treatment of action references in compiler frontend This commit eliminates the `actionBinding` rule from the parser and replaces it with `actionRef`. With these changes, the `p4c` implementation becomes consistent with a recent proposed fix to the language specification (see p4lang/p4-spec#803). More specifically, this commit makes several changes: * Remove the `actionBinding` rule in the parser and modify the `entry` rule so it refers to `actionRef` instead. * Modify the `actionRef` rule, eliminating `optAnnotations` and moving them up into `actionList` instead. This allows annotations on action references in the `actions` property of a table but not the `const entries` property. * Extend the `createBuiltins` pass to convert action references represented as `PathExpression` nodes in an `Entry` into `MethodCallExpression` nodes. Hence, in later frontend passes, it is safe to assume that all action references are represented as `MethodCallExpression` nodes. * Update the reference outputs for the `table-entries-no-arg-actions.p4` test * Small fixes for cpplint * Indent table-entries-no-arg-actions.p4 test cleanly --- frontends/p4/createBuiltins.cpp | 8 ++++ frontends/p4/createBuiltins.h | 1 + frontends/parsers/p4/p4parser.ypp | 46 ++++++++----------- .../table-entries-no-arg-actions.p4 | 40 ++++++++++++++++ .../table-entries-no-arg-actions-first.p4 | 38 +++++++++++++++ .../table-entries-no-arg-actions-frontend.p4 | 40 ++++++++++++++++ .../table-entries-no-arg-actions-midend.p4 | 40 ++++++++++++++++ .../table-entries-no-arg-actions.p4 | 36 +++++++++++++++ .../table-entries-no-arg-actions.p4-stderr | 0 9 files changed, 221 insertions(+), 28 deletions(-) create mode 100644 testdata/p4_16_samples/table-entries-no-arg-actions.p4 create mode 100644 testdata/p4_16_samples_outputs/table-entries-no-arg-actions-first.p4 create mode 100644 testdata/p4_16_samples_outputs/table-entries-no-arg-actions-frontend.p4 create mode 100644 testdata/p4_16_samples_outputs/table-entries-no-arg-actions-midend.p4 create mode 100644 testdata/p4_16_samples_outputs/table-entries-no-arg-actions.p4 create mode 100644 testdata/p4_16_samples_outputs/table-entries-no-arg-actions.p4-stderr diff --git a/frontends/p4/createBuiltins.cpp b/frontends/p4/createBuiltins.cpp index 04ef3bcc733..7bd0f7aab36 100644 --- a/frontends/p4/createBuiltins.cpp +++ b/frontends/p4/createBuiltins.cpp @@ -47,6 +47,14 @@ void CreateBuiltins::postorder(IR::ExpressionValue* expression) { new IR::Vector(), new IR::Vector()); } +void CreateBuiltins::postorder(IR::Entry* entry) { + // convert a const table entry with action "a;" into "a();" + if (entry->action->is()) + entry->action = new IR::MethodCallExpression( + entry->action->srcInfo, entry->action, + new IR::Vector(), new IR::Vector()); +} + void CreateBuiltins::postorder(IR::ParserState* state) { if (state->selectExpression == nullptr) { warning(ErrorType::WARN_PARSER_TRANSITION, "%1%: implicit transition to `reject'", state); diff --git a/frontends/p4/createBuiltins.h b/frontends/p4/createBuiltins.h index 631fe0a1887..9da0851925a 100644 --- a/frontends/p4/createBuiltins.h +++ b/frontends/p4/createBuiltins.h @@ -35,6 +35,7 @@ class CreateBuiltins final : public Modifier { void postorder(IR::P4Parser* parser) override; void postorder(IR::ActionListElement* element) override; void postorder(IR::ExpressionValue* property) override; + void postorder(IR::Entry* property) override; bool preorder(IR::P4Table* table) override; void postorder(IR::ActionList* actions) override; void postorder(IR::TableProperties* properties) override; diff --git a/frontends/parsers/p4/p4parser.ypp b/frontends/parsers/p4/p4parser.ypp index 856654cac95..365f2a922bb 100644 --- a/frontends/parsers/p4/p4parser.ypp +++ b/frontends/parsers/p4/p4parser.ypp @@ -284,11 +284,10 @@ inline std::ostream& operator<<(std::ostream& out, const P4::Token& t) { %type*> tablePropertyList %type keyElement %type*> keyElementList -%type actionRef +%type actionRef %type*> actionList %type entry %type*> entriesList -%type actionBinding %type*> kvList %type kvPair %type*> intList @@ -1196,38 +1195,29 @@ keyElement actionList : /* empty */ { $$ = new IR::IndexedVector(); } - | actionList actionRef ";" { $$ = $1; $$->push_back($2); } + | actionList optAnnotations actionRef ";" + { $$ = $1; $$->push_back(new IR::ActionListElement(@3, $2, $3)); } ; actionRef - : optAnnotations prefixedNonTypeName { $$ = new IR::ActionListElement(@2, $1, new IR::PathExpression($2));} - | optAnnotations prefixedNonTypeName "(" argumentList ")" - { auto mce = new IR::MethodCallExpression( - @2+@4, new IR::PathExpression($2), $4); - $$ = new IR::ActionListElement(@2, $1, mce); } + : prefixedNonTypeName + { $$ = new IR::PathExpression($1); } + | prefixedNonTypeName "(" argumentList ")" + { $$ = new IR::MethodCallExpression(@1+@3, new IR::PathExpression($1), $3); } ; entry - : keysetExpression ":" actionBinding optAnnotations ";" - { - assert($3->is()); - if (auto l = $1->to()) - $$ = new IR::Entry(@1+@4, $4, l, $3); - else { // if not a tuple, make it a list of 1 - IR::Vector le($1); - $$ = new IR::Entry(@1+@4, $4, - new IR::ListExpression(@1, le), - $3); - } - } - ; - -actionBinding - : lvalue "(" argumentList ")" - { $$ = new IR::MethodCallExpression(@1 + @4, $1, - new IR::Vector(), $3); } - | lvalue "<" typeArgumentList ">" "(" argumentList ")" - { $$ = new IR::MethodCallExpression(@1 + @7, $1, $3, $6); } + : keysetExpression ":" actionRef optAnnotations ";" + { if (auto l = $1->to()) + $$ = new IR::Entry(@1+@4, $4, l, $3); + else { // if not a tuple, make it a list of 1 + IR::Vector le($1); + $$ = new IR::Entry(@1+@4, $4, + new IR::ListExpression(@1, le), + $3); + } + } + ; entriesList : entry { $$ = new IR::Vector(); $$->push_back($1); } diff --git a/testdata/p4_16_samples/table-entries-no-arg-actions.p4 b/testdata/p4_16_samples/table-entries-no-arg-actions.p4 new file mode 100644 index 00000000000..f0beb37beed --- /dev/null +++ b/testdata/p4_16_samples/table-entries-no-arg-actions.p4 @@ -0,0 +1,40 @@ +/* +* Copyright 2019, Cornell University +* +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 + +control C(inout bit<2> x); +package S(C c); + +control MyC(inout bit<2> x) { + action a() { } + action b() { } + table t { + key = { x : exact; } + actions = {a; b;} + const entries = { + { 0 } : a; + { 1 } : b; + { 2 } : a(); + { 3 } : b(); + } + } + apply { + t.apply(); + } +} + +S(MyC()) main; diff --git a/testdata/p4_16_samples_outputs/table-entries-no-arg-actions-first.p4 b/testdata/p4_16_samples_outputs/table-entries-no-arg-actions-first.p4 new file mode 100644 index 00000000000..75449191614 --- /dev/null +++ b/testdata/p4_16_samples_outputs/table-entries-no-arg-actions-first.p4 @@ -0,0 +1,38 @@ +#include + +control C(inout bit<2> x); +package S(C c); +control MyC(inout bit<2> x) { + action a() { + } + action b() { + } + table t { + key = { + x: exact @name("x") ; + } + actions = { + a(); + b(); + @defaultonly NoAction(); + } + const entries = { + 2w0 : a(); + + 2w1 : b(); + + 2w2 : a(); + + 2w3 : b(); + + } + + default_action = NoAction(); + } + apply { + t.apply(); + } +} + +S(MyC()) main; + diff --git a/testdata/p4_16_samples_outputs/table-entries-no-arg-actions-frontend.p4 b/testdata/p4_16_samples_outputs/table-entries-no-arg-actions-frontend.p4 new file mode 100644 index 00000000000..7b21ce7234c --- /dev/null +++ b/testdata/p4_16_samples_outputs/table-entries-no-arg-actions-frontend.p4 @@ -0,0 +1,40 @@ +#include + +control C(inout bit<2> x); +package S(C c); +control MyC(inout bit<2> x) { + @name(".NoAction") action NoAction_0() { + } + @name("MyC.a") action a() { + } + @name("MyC.b") action b() { + } + @name("MyC.t") table t_0 { + key = { + x: exact @name("x") ; + } + actions = { + a(); + b(); + @defaultonly NoAction_0(); + } + const entries = { + 2w0 : a(); + + 2w1 : b(); + + 2w2 : a(); + + 2w3 : b(); + + } + + default_action = NoAction_0(); + } + apply { + t_0.apply(); + } +} + +S(MyC()) main; + diff --git a/testdata/p4_16_samples_outputs/table-entries-no-arg-actions-midend.p4 b/testdata/p4_16_samples_outputs/table-entries-no-arg-actions-midend.p4 new file mode 100644 index 00000000000..7b21ce7234c --- /dev/null +++ b/testdata/p4_16_samples_outputs/table-entries-no-arg-actions-midend.p4 @@ -0,0 +1,40 @@ +#include + +control C(inout bit<2> x); +package S(C c); +control MyC(inout bit<2> x) { + @name(".NoAction") action NoAction_0() { + } + @name("MyC.a") action a() { + } + @name("MyC.b") action b() { + } + @name("MyC.t") table t_0 { + key = { + x: exact @name("x") ; + } + actions = { + a(); + b(); + @defaultonly NoAction_0(); + } + const entries = { + 2w0 : a(); + + 2w1 : b(); + + 2w2 : a(); + + 2w3 : b(); + + } + + default_action = NoAction_0(); + } + apply { + t_0.apply(); + } +} + +S(MyC()) main; + diff --git a/testdata/p4_16_samples_outputs/table-entries-no-arg-actions.p4 b/testdata/p4_16_samples_outputs/table-entries-no-arg-actions.p4 new file mode 100644 index 00000000000..e383783c8e4 --- /dev/null +++ b/testdata/p4_16_samples_outputs/table-entries-no-arg-actions.p4 @@ -0,0 +1,36 @@ +#include + +control C(inout bit<2> x); +package S(C c); +control MyC(inout bit<2> x) { + action a() { + } + action b() { + } + table t { + key = { + x: exact; + } + actions = { + a; + b; + } + const entries = { + 0 : a; + + 1 : b; + + 2 : a(); + + 3 : b(); + + } + + } + apply { + t.apply(); + } +} + +S(MyC()) main; + diff --git a/testdata/p4_16_samples_outputs/table-entries-no-arg-actions.p4-stderr b/testdata/p4_16_samples_outputs/table-entries-no-arg-actions.p4-stderr new file mode 100644 index 00000000000..e69de29bb2d From c9d763d0188f5c00ad43bf3953fa82b01e0c2376 Mon Sep 17 00:00:00 2001 From: Mihai Budiu Date: Thu, 9 Jan 2020 11:20:21 -0800 Subject: [PATCH 054/106] Allow empty statements in parsers (#2131) --- frontends/parsers/p4/p4parser.ypp | 1 + testdata/p4_16_samples/issue2127.p4 | 17 +++++++++++++++++ .../p4_16_samples_outputs/issue2127-first.p4 | 17 +++++++++++++++++ .../issue2127-frontend.p4 | 17 +++++++++++++++++ .../p4_16_samples_outputs/issue2127-midend.p4 | 17 +++++++++++++++++ testdata/p4_16_samples_outputs/issue2127.p4 | 18 ++++++++++++++++++ .../p4_16_samples_outputs/issue2127.p4-stderr | 0 7 files changed, 87 insertions(+) create mode 100644 testdata/p4_16_samples/issue2127.p4 create mode 100644 testdata/p4_16_samples_outputs/issue2127-first.p4 create mode 100644 testdata/p4_16_samples_outputs/issue2127-frontend.p4 create mode 100644 testdata/p4_16_samples_outputs/issue2127-midend.p4 create mode 100644 testdata/p4_16_samples_outputs/issue2127.p4 create mode 100644 testdata/p4_16_samples_outputs/issue2127.p4-stderr diff --git a/frontends/parsers/p4/p4parser.ypp b/frontends/parsers/p4/p4parser.ypp index 365f2a922bb..bfaaf033364 100644 --- a/frontends/parsers/p4/p4parser.ypp +++ b/frontends/parsers/p4/p4parser.ypp @@ -712,6 +712,7 @@ parserStatements parserStatement : assignmentOrMethodCallStatement { $$ = $1; } | directApplication { $$ = $1; } + | emptyStatement { $$ = $1; } | variableDeclaration { $$ = $1; } | constantDeclaration { $$ = $1; } | parserBlockStatement { $$ = $1; } diff --git a/testdata/p4_16_samples/issue2127.p4 b/testdata/p4_16_samples/issue2127.p4 new file mode 100644 index 00000000000..9bec07e54e7 --- /dev/null +++ b/testdata/p4_16_samples/issue2127.p4 @@ -0,0 +1,17 @@ +#include + +header H { + bit<32> b; +} + +parser p(packet_in packet, out H h) { + state start { + packet.extract(h); + ; + transition accept; + } +} + +parser proto(packet_in p, out T t); +package top(proto p); +top(p()) main; diff --git a/testdata/p4_16_samples_outputs/issue2127-first.p4 b/testdata/p4_16_samples_outputs/issue2127-first.p4 new file mode 100644 index 00000000000..ab075d2b8ef --- /dev/null +++ b/testdata/p4_16_samples_outputs/issue2127-first.p4 @@ -0,0 +1,17 @@ +#include + +header H { + bit<32> b; +} + +parser p(packet_in packet, out H h) { + state start { + packet.extract(h); + transition accept; + } +} + +parser proto(packet_in p, out T t); +package top(proto p); +top(p()) main; + diff --git a/testdata/p4_16_samples_outputs/issue2127-frontend.p4 b/testdata/p4_16_samples_outputs/issue2127-frontend.p4 new file mode 100644 index 00000000000..ab075d2b8ef --- /dev/null +++ b/testdata/p4_16_samples_outputs/issue2127-frontend.p4 @@ -0,0 +1,17 @@ +#include + +header H { + bit<32> b; +} + +parser p(packet_in packet, out H h) { + state start { + packet.extract(h); + transition accept; + } +} + +parser proto(packet_in p, out T t); +package top(proto p); +top(p()) main; + diff --git a/testdata/p4_16_samples_outputs/issue2127-midend.p4 b/testdata/p4_16_samples_outputs/issue2127-midend.p4 new file mode 100644 index 00000000000..ab075d2b8ef --- /dev/null +++ b/testdata/p4_16_samples_outputs/issue2127-midend.p4 @@ -0,0 +1,17 @@ +#include + +header H { + bit<32> b; +} + +parser p(packet_in packet, out H h) { + state start { + packet.extract(h); + transition accept; + } +} + +parser proto(packet_in p, out T t); +package top(proto p); +top(p()) main; + diff --git a/testdata/p4_16_samples_outputs/issue2127.p4 b/testdata/p4_16_samples_outputs/issue2127.p4 new file mode 100644 index 00000000000..e7944aa1959 --- /dev/null +++ b/testdata/p4_16_samples_outputs/issue2127.p4 @@ -0,0 +1,18 @@ +#include + +header H { + bit<32> b; +} + +parser p(packet_in packet, out H h) { + state start { + packet.extract(h); + ; + transition accept; + } +} + +parser proto(packet_in p, out T t); +package top(proto p); +top(p()) main; + diff --git a/testdata/p4_16_samples_outputs/issue2127.p4-stderr b/testdata/p4_16_samples_outputs/issue2127.p4-stderr new file mode 100644 index 00000000000..e69de29bb2d From 7af3cd91020fa6ebe698a006455dbf8fb96c29a2 Mon Sep 17 00:00:00 2001 From: Mihai Budiu Date: Thu, 9 Jan 2020 14:25:52 -0800 Subject: [PATCH 055/106] Block statements in parser create a new scope (#2133) * Block statements in parser create a new scope * More reference outputs --- backends/ebpf/codeGen.h | 3 +- backends/p4test/CMakeLists.txt | 8 ++--- frontends/common/parseInput.h | 6 ++-- frontends/p4/fromv1.0/converters.h | 31 +++++++++++-------- frontends/p4/symbol_table.cpp | 6 ++-- frontends/parsers/p4/p4parser.ypp | 4 +-- ir/indexed_vector.h | 3 +- lib/error_catalog.cpp | 6 ++-- lib/error_catalog.h | 1 + lib/nullstream.cpp | 7 +++-- lib/options.cpp | 4 +-- midend/compileTimeOps.h | 3 +- midend/predication.h | 3 +- .../array_index.p4-stderr | 2 +- .../p4_14_errors_outputs/issue1092.p4-stderr | 2 +- .../p4_14_errors_outputs/issue1093.p4-stderr | 2 +- .../p4_14_errors_outputs/issue1238.p4-stderr | 2 +- .../p4_14_errors_outputs/issue1499.p4-stderr | 2 +- .../p4_14_errors_outputs/issue1745.p4-stderr | 2 +- .../p4_14_errors_outputs/issue187.p4-stderr | 2 +- .../p4_14_errors_outputs/issue747.p4-stderr | 2 +- .../p4_14_errors_outputs/issue763-1.p4-stderr | 4 +-- .../p4_14_errors_outputs/issue763-2.p4-stderr | 4 +-- .../p4_14_errors_outputs/issue763.p4-stderr | 4 +-- .../issue780-10.p4-stderr | 4 +-- .../p4_14_errors_outputs/issue780-4.p4-stderr | 4 +-- .../p4_14_errors_outputs/issue780-6.p4-stderr | 4 +-- .../p4_14_errors_outputs/issue905.p4-stderr | 2 +- .../p4_14_errors_outputs/nasty_meta.p4-stderr | 2 +- .../unknown-state.p4-stderr | 2 +- .../constructor1_e.p4-stderr | 2 +- .../constructor2_e.p4-stderr | 2 +- testdata/p4_16_errors_outputs/div3.p4-stderr | 2 +- .../expression_e.p4-stderr | 2 +- .../globalVar_e.p4-stderr | 2 +- .../p4_16_errors_outputs/header1_e.p4-stderr | 2 +- .../p4_16_errors_outputs/issue1202.p4-stderr | 2 +- .../p4_16_errors_outputs/issue1336.p4-stderr | 2 +- .../issue1932-1.p4-stderr | 4 +-- .../p4_16_errors_outputs/issue1944.p4-stderr | 2 +- .../issue1986-1.p4-stderr | 2 +- .../p4_16_errors_outputs/issue1986.p4-stderr | 2 +- .../p4_16_errors_outputs/issue513.p4-stderr | 2 +- testdata/p4_16_errors_outputs/p_e.p4-stderr | 2 +- .../p4_16_errors_outputs/shift_e.p4-stderr | 2 +- .../table-entries-exact-ternary.p4-stderr | 2 +- .../table-entries-outside-table.p4-stderr | 2 +- .../p4_16_errors_outputs/template_e.p4-stderr | 6 ++-- .../p4_16_errors_outputs/tuple-left.p4-stderr | 2 +- .../underscore1_e.p4-stderr | 2 +- .../underscore2_e.p4-stderr | 2 +- .../underscore3_e.p4-stderr | 2 +- .../underscore_e.p4-stderr | 2 +- .../p4_16_errors_outputs/width_e.p4-stderr | 2 +- testdata/p4_16_samples/issue2126.p4 | 11 +++++++ .../p4_16_samples_outputs/issue2126-first.p4 | 12 +++++++ .../issue2126-frontend.p4 | 0 testdata/p4_16_samples_outputs/issue2126.p4 | 12 +++++++ .../p4_16_samples_outputs/issue2126.p4-stderr | 1 + 59 files changed, 137 insertions(+), 84 deletions(-) create mode 100755 testdata/p4_16_samples/issue2126.p4 create mode 100644 testdata/p4_16_samples_outputs/issue2126-first.p4 create mode 100644 testdata/p4_16_samples_outputs/issue2126-frontend.p4 create mode 100644 testdata/p4_16_samples_outputs/issue2126.p4 create mode 100644 testdata/p4_16_samples_outputs/issue2126.p4-stderr diff --git a/backends/ebpf/codeGen.h b/backends/ebpf/codeGen.h index e30c385b97d..e1cd1b855d8 100644 --- a/backends/ebpf/codeGen.h +++ b/backends/ebpf/codeGen.h @@ -64,7 +64,8 @@ class CodeGenInspector : public Inspector { } bool notSupported(const IR::Expression* expression) - { ::error("%1%: not yet implemented", expression); return false; } + { ::error(ErrorType::ERR_UNSUPPORTED, + "not yet implemented", expression); return false; } bool preorder(const IR::Expression* expression) override { return notSupported(expression); } diff --git a/backends/p4test/CMakeLists.txt b/backends/p4test/CMakeLists.txt index 10b31f7090b..4698f7a87c2 100644 --- a/backends/p4test/CMakeLists.txt +++ b/backends/p4test/CMakeLists.txt @@ -92,12 +92,12 @@ set (P4_XFAIL_TESTS # will be no P4Info file. p4c_add_tests_w_p4runtime("p4" ${P4TEST_DRIVER} "${P4TEST_SUITES}" "${P4_XFAIL_TESTS}" "${P4RUNTIME_EXCLUDE}" "-a '--maxErrorCount 100'") -set (P4TEST_ERRORS "${P4C_SOURCE_DIR}/testdata/p4_16_errors/*.p4") +set (P4TEST_ERRORS + "${P4C_SOURCE_DIR}/testdata/p4_16_errors/*.p4" + "${P4C_SOURCE_DIR}/testdata/p4_14_errors/*.p4") p4c_add_tests_w_p4runtime("err" ${P4TEST_DRIVER} "${P4TEST_ERRORS}" "${P4_XFAIL_TESTS}" "${P4RUNTIME_EXCLUDE}" "-a '--maxErrorCount 100'") set (P4_14_SUITES "${P4C_SOURCE_DIR}/testdata/p4_14_samples/*.p4" - "${P4C_SOURCE_DIR}/testdata/p4_14_samples/switch_*/switch.p4" - "${P4C_SOURCE_DIR}/testdata/p4_14_errors/*.p4" - ) + "${P4C_SOURCE_DIR}/testdata/p4_14_samples/switch_*/switch.p4") p4c_add_tests("p14_to_16" ${P4TEST_DRIVER} "${P4_14_SUITES}" "") diff --git a/frontends/common/parseInput.h b/frontends/common/parseInput.h index 33116d79dfc..0e6d1958c90 100644 --- a/frontends/common/parseInput.h +++ b/frontends/common/parseInput.h @@ -73,7 +73,8 @@ const IR::P4Program* parseP4File(CompilerOptions& options) { if (options.doNotPreprocess) { in = fopen(options.file, "r"); if (in == nullptr) { - ::error("%s: No such file or directory.", options.file); + ::error(ErrorType::ERR_NOT_FOUND, + "No such file or directory.", options.file); return nullptr; } } else { @@ -88,7 +89,8 @@ const IR::P4Program* parseP4File(CompilerOptions& options) { options.closeInput(in); if (::errorCount() > 0) { - ::error("%1% errors encountered, aborting compilation", ::errorCount()); + ::error(ErrorType::ERR_OVERLIMIT, + "%1% errors encountered, aborting compilation", ::errorCount()); return nullptr; } BUG_CHECK(result != nullptr, "Parsing failed, but we didn't report an error"); diff --git a/frontends/p4/fromv1.0/converters.h b/frontends/p4/fromv1.0/converters.h index 4eb10ab7e78..13eda0ca7fd 100644 --- a/frontends/p4/fromv1.0/converters.h +++ b/frontends/p4/fromv1.0/converters.h @@ -175,7 +175,8 @@ class DiscoverStructure : public Inspector { if (it == reserved_names.end()) return; if (it->second != kind) - ::error("%1% cannot have this name; it can only be used for %2%", node, it->second); + ::error(ErrorType::ERR_INVALID, + "name; it can only be used for %2%", node, it->second); } void checkReserved(const IR::Node* node, cstring nodeName) const { checkReserved(node, nodeName, nullptr); @@ -278,7 +279,7 @@ class ComputeCallGraph : public Inspector { else if (auto nr = ctrref->to()) ctr = structure->counters.get(nr->path->name); if (ctr == nullptr) - ::error("Cannot find counter %1%", ctrref); + ::error(ErrorType::ERR_NOT_FOUND, "Cannot find counter", ctrref); auto parent = findContext(); BUG_CHECK(parent != nullptr, "%1%: Counter call not within action", primitive); structure->calledCounters.calls(parent->name, ctr->name.name); @@ -291,7 +292,7 @@ class ComputeCallGraph : public Inspector { else if (auto nr = mtrref->to()) mtr = structure->meters.get(nr->path->name); if (mtr == nullptr) - ::error("Cannot find meter %1%", mtrref); + ::error(ErrorType::ERR_NOT_FOUND, "Cannot find meter", mtrref); auto parent = findContext(); BUG_CHECK(parent != nullptr, "%1%: not within action", primitive); @@ -309,7 +310,7 @@ class ComputeCallGraph : public Inspector { else if (auto nr = regref->to()) reg = structure->registers.get(nr->path->name); if (reg == nullptr) - ::error("Cannot find register %1%", regref); + ::error(ErrorType::ERR_NOT_FOUND, "Cannot find register", regref); auto parent = findContext(); BUG_CHECK(parent != nullptr, "%1%: not within action", primitive); @@ -360,7 +361,7 @@ class ComputeTableCallGraph : public Inspector { LOG3("Scanning " << apply->name); auto tbl = structure->tables.get(apply->name.name); if (tbl == nullptr) - ::error("Could not find table %1%", apply->name); + ::error(ErrorType::ERR_NOT_FOUND, "Could not find table", apply->name); auto parent = findContext(); ERROR_CHECK(parent != nullptr, "%1%: Apply not within a control block?", apply); @@ -374,7 +375,8 @@ class ComputeTableCallGraph : public Inspector { if (ctrl != nullptr && ctrl != parent) { auto previous = get(structure->tableInvocation, tbl); - ::error("Table %1% invoked from two different controls: %2% and %3%", + ::error(ErrorType::ERR_INVALID, + "Table invoked from two different controls: %2% and %3%", tbl, apply, previous); } LOG3("Invoking " << tbl << " in " << parent->name); @@ -474,7 +476,8 @@ class FixExtracts final : public Transform { if (f->type->is()) { cstring hname = structure->makeUniqueName(type->name); if (fixedHeaderType != nullptr) { - ::error("%1%: header types with multiple varbit fields are not supported", + ::error(ErrorType::ERR_INVALID, + "header types with multiple varbit fields are not supported", type); return nullptr; } @@ -681,10 +684,10 @@ class DetectDuplicates: public Inspector { auto e2 = n->second; if (e1->node_type_name() == e2->node_type_name()) { if (e1->srcInfo.getStart().isValid()) - ::error("%1%: same name as %2%", e1, e2); + ::error(ErrorType::ERR_DUPLICATE, "%1%: same name as %2%", e1, e2); else // This name is probably standard_metadata_t, a built-in declaration - ::error("%1%: name %2% is reserved", e2, key); + ::error(ErrorType::ERR_INVALID, "; name %2% is reserved", e2, key); } } } @@ -844,7 +847,7 @@ class MoveIntrinsicMetadata : public Transform { BUG_CHECK(tn, "%1%: expected a Type_Name", intrTypeName); auto nt = program->getDeclsByName(tn->path->name)->nextOrDefault(); if (nt == nullptr || !nt->is()) { - ::error("%1%: expected a structure", tn); + ::error(ErrorType::ERR_INVALID, "expected a structure", tn); return program; } intrType = nt->to(); @@ -858,7 +861,7 @@ class MoveIntrinsicMetadata : public Transform { BUG_CHECK(tn, "%1%: expected a Type_Name", queueTypeName); auto nt = program->getDeclsByName(tn->path->name)->nextOrDefault(); if (nt == nullptr || !nt->is()) { - ::error("%1%: expected a structure", tn); + ::error(ErrorType::ERR_INVALID, "expected a structure", tn); return program; } queueType = nt->to(); @@ -872,7 +875,8 @@ class MoveIntrinsicMetadata : public Transform { if (intrType != nullptr) { for (auto f : intrType->fields) { if (type->fields.getDeclaration(f->name) == nullptr) { - ::error("%1%: no such field in standard_metadata", f->name); + ::error(ErrorType::ERR_NOT_FOUND, + "no such field in standard_metadata", f->name); LOG2("standard_metadata: " << type); } } @@ -880,7 +884,8 @@ class MoveIntrinsicMetadata : public Transform { if (queueType != nullptr) { for (auto f : queueType->fields) { if (type->fields.getDeclaration(f->name) == nullptr) { - ::error("%1%: no such field in standard_metadata", f->name); + ::error(ErrorType::ERR_NOT_FOUND, + "no such field in standard_metadata", f->name); LOG2("standard_metadata: " << type); } } diff --git a/frontends/p4/symbol_table.cpp b/frontends/p4/symbol_table.cpp index b54855a56ba..140546cd895 100644 --- a/frontends/p4/symbol_table.cpp +++ b/frontends/p4/symbol_table.cpp @@ -71,13 +71,15 @@ class Namespace : public NamedSymbol { if (it != contents.end()) { // Check that both declarations have the same type if (!it->second->sameType(symbol)) { - ::error("Re-declaration of %1%%2% with different type: %3%", + ::error(ErrorType::ERR_DUPLICATE, + "Re-declaration of %1%%2% with different type: %3%", symbol->getName(), symbol->getSourceInfo(), it->second->getSourceInfo()); return; } if (!allowDuplicates) { - ::error("Duplicate declaration of %1%%2%; previous at %3%", + ::error(ErrorType::ERR_DUPLICATE, + "Duplicate declaration of %1%%2%; previous at %3%", symbol->getName(), symbol->getSourceInfo(), it->second->getSourceInfo()); return; } diff --git a/frontends/parsers/p4/p4parser.ypp b/frontends/parsers/p4/p4parser.ypp index bfaaf033364..4ed3ae3891c 100644 --- a/frontends/parsers/p4/p4parser.ypp +++ b/frontends/parsers/p4/p4parser.ypp @@ -719,8 +719,8 @@ parserStatement ; parserBlockStatement - : optAnnotations "{" parserStatements "}" - { $$ = new IR::BlockStatement(@1+@4, $1, *$3); } + : optAnnotations "{" { driver.structure->pushNamespace(@2, false); } + parserStatements "}" { driver.structure->pop(); $$ = new IR::BlockStatement(@1+@5, $1, *$4); } ; transitionStatement diff --git a/ir/indexed_vector.h b/ir/indexed_vector.h index 05f3aa189a0..398f6aecc50 100644 --- a/ir/indexed_vector.h +++ b/ir/indexed_vector.h @@ -46,7 +46,8 @@ class IndexedVector : public Vector { auto name = decl->getName().name; auto previous = declarations.find(name); if (previous != declarations.end()) - ::error("%1%: Duplicates declaration %2%", a, previous->second); + ::error(ErrorType::ERR_DUPLICATE, + "%1%: Duplicates declaration %2%", a, previous->second); else declarations[name] = decl; } void removeFromMap(const T* a) { diff --git a/lib/error_catalog.cpp b/lib/error_catalog.cpp index 383162c3c02..86af5241e54 100644 --- a/lib/error_catalog.cpp +++ b/lib/error_catalog.cpp @@ -32,7 +32,8 @@ const int ErrorType::ERR_OVERLIMIT = 9; const int ErrorType::ERR_INSUFFICIENT = 10; const int ErrorType::ERR_TYPE_ERROR = 11; const int ErrorType::ERR_UNSUPPORTED_ON_TARGET = 12; -const int ErrorType::ERR_DUPLICATE = 13; +const int ErrorType::ERR_DUPLICATE = 13; +const int ErrorType::ERR_IO = 14; // If we specialize for 1000 error types we're good! const int ErrorType::ERR_MAX_ERRORS = 999; @@ -63,7 +64,7 @@ using ErrorSig = std::pair; std::map ErrorCatalog::errorCatalog = { // Errors { ErrorType::LEGACY_ERROR, ErrorSig("legacy", "")}, - { ErrorType::ERR_UNKNOWN, ErrorSig("unknown", "%1%: Unknown error")}, + { ErrorType::ERR_UNKNOWN, ErrorSig("unknown", "%1%: Unknown")}, { ErrorType::ERR_UNSUPPORTED, ErrorSig("unsupported", "%1%: Unsupported")}, { ErrorType::ERR_UNEXPECTED, ErrorSig("unexpected", "%1%: Unexpected")}, { ErrorType::ERR_EXPECTED, ErrorSig("expected", "%1%: Expected")}, @@ -77,6 +78,7 @@ std::map ErrorCatalog::errorCatalog = { { ErrorType::ERR_UNSUPPORTED_ON_TARGET, ErrorSig("target-error", "%1%: Unsupported on target")}, { ErrorType::ERR_DUPLICATE, ErrorSig("duplicate", "")}, + { ErrorType::ERR_IO, ErrorSig("I/O error", "")}, // Warnings { ErrorType::LEGACY_WARNING, ErrorSig("legacy", "")}, diff --git a/lib/error_catalog.h b/lib/error_catalog.h index 4190fc78b43..d60de7a4384 100644 --- a/lib/error_catalog.h +++ b/lib/error_catalog.h @@ -42,6 +42,7 @@ class ErrorType { static const int ERR_TYPE_ERROR; // P4 type checking errors static const int ERR_UNSUPPORTED_ON_TARGET; // target can not handle construct static const int ERR_DUPLICATE; // duplicate objects + static const int ERR_IO; // IO error // If we specialize for 1000 error types we're good! static const int ERR_MAX_ERRORS; diff --git a/lib/nullstream.cpp b/lib/nullstream.cpp index 013bec65ee6..8b7e242a2fc 100644 --- a/lib/nullstream.cpp +++ b/lib/nullstream.cpp @@ -1,5 +1,5 @@ /* -Copyright 2013-present Barefoot Networks, Inc. +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. @@ -21,12 +21,13 @@ std::ostream* openFile(cstring name, bool nullOnError) { if (name.isNullOrEmpty()) { if (nullOnError) return new nullstream(); - ::error("Empty name for openFile"); + ::error(ErrorType::ERR_INVALID, "Empty name for openFile", name); return nullptr; } std::ofstream *file = new std::ofstream(name); if (!file->good()) { - ::error("Error writing output to file %1%: %2%", name, strerror(errno)); + ::error(ErrorType::ERR_IO, + "Error writing output to file %1%: %2%", name, strerror(errno)); if (nullOnError) return new nullstream(); return nullptr; diff --git a/lib/options.cpp b/lib/options.cpp index 83bd54c0cd6..73519303edf 100644 --- a/lib/options.cpp +++ b/lib/options.cpp @@ -54,7 +54,7 @@ std::vector* Util::Options::process(int argc, char* const argv[]) { if (!option && (arg = opt.find('='))) option = get(options, opt.before(arg++)); if (option == nullptr) { - ::error("Unknown option %1%", opt); + ::error(ErrorType::ERR_UNKNOWN, "option", opt); usage(); return nullptr; } } else if (opt.startsWith("-")) { @@ -63,7 +63,7 @@ std::vector* Util::Options::process(int argc, char* const argv[]) { opt = opt.substr(0, 2); } option = get(options, opt); if (option == nullptr) { - ::error("Unknown option %1%", opt); + ::error(ErrorType::ERR_UNKNOWN, "option", opt); usage(); return nullptr; } if ((option->flags & OptionFlags::OptionalArgument) && diff --git a/midend/compileTimeOps.h b/midend/compileTimeOps.h index be5f838e203..5c0c656e489 100644 --- a/midend/compileTimeOps.h +++ b/midend/compileTimeOps.h @@ -33,7 +33,8 @@ class CompileTimeOperations : public Inspector { public: CompileTimeOperations() { setName("CompileTimeOperations"); } void err(const IR::Node* expression) - { ::error("%1%: could not evaluate at compilation time", expression); } + { ::error(ErrorType::ERR_INVALID, + "could not evaluate at compilation time", expression); } void postorder(const IR::Mod* expression) override { err(expression); } void postorder(const IR::Div* expression) override diff --git a/midend/predication.h b/midend/predication.h index b71048c1a73..e8fd00f680a 100644 --- a/midend/predication.h +++ b/midend/predication.h @@ -70,7 +70,8 @@ class Predication final : public Transform { return new IR::PathExpression(IR::ID(predicateName.back())); } const IR::Statement* error(const IR::Statement* statement) const { if (inside_action && ifNestingLevel > 0) - ::error("%1%: Conditional execution in actions is not supported on this target", + ::error(ErrorType::ERR_UNSUPPORTED_ON_TARGET, + "Conditional execution in actions", statement); return statement; } diff --git a/testdata/p4_14_errors_outputs/array_index.p4-stderr b/testdata/p4_14_errors_outputs/array_index.p4-stderr index c2fe485caae..d7eb8a84f28 100644 --- a/testdata/p4_14_errors_outputs/array_index.p4-stderr +++ b/testdata/p4_14_errors_outputs/array_index.p4-stderr @@ -5,4 +5,4 @@ array_index.p4(31): error: Illegal array index hdr.data[port]: must be a constan modify_field(data[port].f1, val); ^^^^^^^^^^ error: Cannot locate action noop -error: 2 errors encountered, aborting compilation +[--Werror=overlimit] error: 2 errors encountered, aborting compilation diff --git a/testdata/p4_14_errors_outputs/issue1092.p4-stderr b/testdata/p4_14_errors_outputs/issue1092.p4-stderr index ff51ebbdacd..f7c6be5a147 100644 --- a/testdata/p4_14_errors_outputs/issue1092.p4-stderr +++ b/testdata/p4_14_errors_outputs/issue1092.p4-stderr @@ -1,2 +1,2 @@ error: No transition from a parser to ingress pipeline found -error: 1 errors encountered, aborting compilation +[--Werror=overlimit] error: 1 errors encountered, aborting compilation diff --git a/testdata/p4_14_errors_outputs/issue1093.p4-stderr b/testdata/p4_14_errors_outputs/issue1093.p4-stderr index 945c5174643..f692b64e48b 100644 --- a/testdata/p4_14_errors_outputs/issue1093.p4-stderr +++ b/testdata/p4_14_errors_outputs/issue1093.p4-stderr @@ -1,4 +1,4 @@ issue1093.p4(8):syntax error, unexpected END if(0 == 1) { } ^ -error: 1 errors encountered, aborting compilation +[--Werror=overlimit] error: 1 errors encountered, aborting compilation diff --git a/testdata/p4_14_errors_outputs/issue1238.p4-stderr b/testdata/p4_14_errors_outputs/issue1238.p4-stderr index 399bc07e70c..0be2ff326b0 100644 --- a/testdata/p4_14_errors_outputs/issue1238.p4-stderr +++ b/testdata/p4_14_errors_outputs/issue1238.p4-stderr @@ -1,4 +1,4 @@ issue1238.p4(11): [--Werror=legacy] error: subtract: operation only defined for bit/int types subtract(palatalising, palatalising, 1); ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: 1 errors encountered, aborting compilation +[--Werror=overlimit] error: 1 errors encountered, aborting compilation diff --git a/testdata/p4_14_errors_outputs/issue1499.p4-stderr b/testdata/p4_14_errors_outputs/issue1499.p4-stderr index 4b0b185152f..1a7b08c7b96 100644 --- a/testdata/p4_14_errors_outputs/issue1499.p4-stderr +++ b/testdata/p4_14_errors_outputs/issue1499.p4-stderr @@ -4,4 +4,4 @@ issue1499.p4(18): error: latest: latest not yet defined issue1499.p4(21): [--Werror=legacy] error: ingress: unknown state 1024 : ingress; ^^^^^^^ -error: 2 errors encountered, aborting compilation +[--Werror=overlimit] error: 2 errors encountered, aborting compilation diff --git a/testdata/p4_14_errors_outputs/issue1745.p4-stderr b/testdata/p4_14_errors_outputs/issue1745.p4-stderr index a97deed1c45..2aba2bbffd4 100644 --- a/testdata/p4_14_errors_outputs/issue1745.p4-stderr +++ b/testdata/p4_14_errors_outputs/issue1745.p4-stderr @@ -4,4 +4,4 @@ issue1745.p4(6): [--Werror=legacy] error: length_: header length must depend onl issue1745.p4(3) options : *; ^^^^^^^^^^^ -error: 1 errors encountered, aborting compilation +[--Werror=overlimit] error: 1 errors encountered, aborting compilation diff --git a/testdata/p4_14_errors_outputs/issue187.p4-stderr b/testdata/p4_14_errors_outputs/issue187.p4-stderr index f32895fdb7b..63767382e50 100644 --- a/testdata/p4_14_errors_outputs/issue187.p4-stderr +++ b/testdata/p4_14_errors_outputs/issue187.p4-stderr @@ -1,2 +1,2 @@ error: Program contains recursive control blocks -error: 1 errors encountered, aborting compilation +[--Werror=overlimit] error: 1 errors encountered, aborting compilation diff --git a/testdata/p4_14_errors_outputs/issue747.p4-stderr b/testdata/p4_14_errors_outputs/issue747.p4-stderr index 801853bdd2d..39033715c1e 100644 --- a/testdata/p4_14_errors_outputs/issue747.p4-stderr +++ b/testdata/p4_14_errors_outputs/issue747.p4-stderr @@ -4,4 +4,4 @@ action local_recirc(local_port) { issue747.p4(31): [--Werror=legacy] error: local_port: expected a field list action local_recirc(local_port) { ^^^^^^^^^^ -error: 1 errors encountered, aborting compilation +[--Werror=overlimit] error: 1 errors encountered, aborting compilation diff --git a/testdata/p4_14_errors_outputs/issue763-1.p4-stderr b/testdata/p4_14_errors_outputs/issue763-1.p4-stderr index a48fe611340..f129f594718 100644 --- a/testdata/p4_14_errors_outputs/issue763-1.p4-stderr +++ b/testdata/p4_14_errors_outputs/issue763-1.p4-stderr @@ -1,4 +1,4 @@ -issue763-1.p4(7): [--Werror=legacy] error: Header cannot have this name; it can only be used for metadata +issue763-1.p4(7): [--Werror=invalid] error: Header: Invalid name; it can only be used for metadata header X standard_metadata; ^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: 1 errors encountered, aborting compilation +[--Werror=overlimit] error: 1 errors encountered, aborting compilation diff --git a/testdata/p4_14_errors_outputs/issue763-2.p4-stderr b/testdata/p4_14_errors_outputs/issue763-2.p4-stderr index 61915441f29..b09a84d1435 100644 --- a/testdata/p4_14_errors_outputs/issue763-2.p4-stderr +++ b/testdata/p4_14_errors_outputs/issue763-2.p4-stderr @@ -1,4 +1,4 @@ -issue763-2.p4(1): [--Werror=legacy] error: v1HeaderType: name standard_metadata_t is reserved +issue763-2.p4(1): [--Werror=invalid] error: v1HeaderType: Invalid ; name standard_metadata_t is reserved header_type standard_metadata_t { ^ -error: 1 errors encountered, aborting compilation +[--Werror=overlimit] error: 1 errors encountered, aborting compilation diff --git a/testdata/p4_14_errors_outputs/issue763.p4-stderr b/testdata/p4_14_errors_outputs/issue763.p4-stderr index 216a58d0953..c260b7ccd60 100644 --- a/testdata/p4_14_errors_outputs/issue763.p4-stderr +++ b/testdata/p4_14_errors_outputs/issue763.p4-stderr @@ -1,7 +1,7 @@ -issue763.p4(1): [--Werror=legacy] error: v1HeaderType: same name as v1HeaderType +issue763.p4(1): [--Werror=duplicate] error: v1HeaderType: same name as v1HeaderType header_type X { ^ issue763.p4(7) header_type X { ^ -error: 1 errors encountered, aborting compilation +[--Werror=overlimit] error: 1 errors encountered, aborting compilation diff --git a/testdata/p4_14_errors_outputs/issue780-10.p4-stderr b/testdata/p4_14_errors_outputs/issue780-10.p4-stderr index 9b4a98e2a5e..41a77882ea1 100644 --- a/testdata/p4_14_errors_outputs/issue780-10.p4-stderr +++ b/testdata/p4_14_errors_outputs/issue780-10.p4-stderr @@ -1,4 +1,4 @@ -issue780-10.p4(1): [--Werror=legacy] error: V1Control standard_metadata_t cannot have this name; it can only be used for type +issue780-10.p4(1): [--Werror=invalid] error: V1Control standard_metadata_t: Invalid name; it can only be used for type control standard_metadata_t { } ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: 1 errors encountered, aborting compilation +[--Werror=overlimit] error: 1 errors encountered, aborting compilation diff --git a/testdata/p4_14_errors_outputs/issue780-4.p4-stderr b/testdata/p4_14_errors_outputs/issue780-4.p4-stderr index 5167ae04548..6f55965ee69 100644 --- a/testdata/p4_14_errors_outputs/issue780-4.p4-stderr +++ b/testdata/p4_14_errors_outputs/issue780-4.p4-stderr @@ -1,4 +1,4 @@ -issue780-4.p4(1): [--Werror=legacy] error: header egress cannot have this name; it can only be used for control +issue780-4.p4(1): [--Werror=invalid] error: header egress: Invalid name; it can only be used for control header_type egress { ^ -error: 1 errors encountered, aborting compilation +[--Werror=overlimit] error: 1 errors encountered, aborting compilation diff --git a/testdata/p4_14_errors_outputs/issue780-6.p4-stderr b/testdata/p4_14_errors_outputs/issue780-6.p4-stderr index 0168c15a7a4..7bf5f83d050 100644 --- a/testdata/p4_14_errors_outputs/issue780-6.p4-stderr +++ b/testdata/p4_14_errors_outputs/issue780-6.p4-stderr @@ -1,4 +1,4 @@ -issue780-6.p4(1): [--Werror=legacy] error: header standard_metadata cannot have this name; it can only be used for metadata +issue780-6.p4(1): [--Werror=invalid] error: header standard_metadata: Invalid name; it can only be used for metadata header_type standard_metadata { ^ -error: 1 errors encountered, aborting compilation +[--Werror=overlimit] error: 1 errors encountered, aborting compilation diff --git a/testdata/p4_14_errors_outputs/issue905.p4-stderr b/testdata/p4_14_errors_outputs/issue905.p4-stderr index 042a94422a3..15d2c379959 100644 --- a/testdata/p4_14_errors_outputs/issue905.p4-stderr +++ b/testdata/p4_14_errors_outputs/issue905.p4-stderr @@ -1,4 +1,4 @@ issue905.p4(34): [--Werror=legacy] error: *: not defined on operands of type varbit<0> modify_field(can_data.value, can_data.value * 2); // error ^ -error: 1 errors encountered, aborting compilation +[--Werror=overlimit] error: 1 errors encountered, aborting compilation diff --git a/testdata/p4_14_errors_outputs/nasty_meta.p4-stderr b/testdata/p4_14_errors_outputs/nasty_meta.p4-stderr index d4b6012f187..e0627d472d8 100644 --- a/testdata/p4_14_errors_outputs/nasty_meta.p4-stderr +++ b/testdata/p4_14_errors_outputs/nasty_meta.p4-stderr @@ -1,4 +1,4 @@ nasty_meta.p4(24): [--Werror=invalid] error: extract: Invalid argument. Expected a header not struct ethernet_t extract(ethernet); ^^^^^^^^^^^^^^^^^ -error: 1 errors encountered, aborting compilation +[--Werror=overlimit] error: 1 errors encountered, aborting compilation diff --git a/testdata/p4_14_errors_outputs/unknown-state.p4-stderr b/testdata/p4_14_errors_outputs/unknown-state.p4-stderr index 860d947bbf4..c89607cebe6 100644 --- a/testdata/p4_14_errors_outputs/unknown-state.p4-stderr +++ b/testdata/p4_14_errors_outputs/unknown-state.p4-stderr @@ -1,4 +1,4 @@ unknown-state.p4(2): [--Werror=legacy] error: ingress: unknown state return ingress; ^^^^^^^ -error: 1 errors encountered, aborting compilation +[--Werror=overlimit] error: 1 errors encountered, aborting compilation diff --git a/testdata/p4_16_errors_outputs/constructor1_e.p4-stderr b/testdata/p4_16_errors_outputs/constructor1_e.p4-stderr index 68b700dd9e2..d4550e6552a 100644 --- a/testdata/p4_16_errors_outputs/constructor1_e.p4-stderr +++ b/testdata/p4_16_errors_outputs/constructor1_e.p4-stderr @@ -1,4 +1,4 @@ constructor1_e.p4(18):syntax error, unexpected ( Y( ^ -error: 1 errors encountered, aborting compilation +[--Werror=overlimit] error: 1 errors encountered, aborting compilation diff --git a/testdata/p4_16_errors_outputs/constructor2_e.p4-stderr b/testdata/p4_16_errors_outputs/constructor2_e.p4-stderr index 408a16aabaa..06c4d69fb9a 100644 --- a/testdata/p4_16_errors_outputs/constructor2_e.p4-stderr +++ b/testdata/p4_16_errors_outputs/constructor2_e.p4-stderr @@ -1,4 +1,4 @@ constructor2_e.p4(18):syntax error, unexpected ( m( ^ -error: 1 errors encountered, aborting compilation +[--Werror=overlimit] error: 1 errors encountered, aborting compilation diff --git a/testdata/p4_16_errors_outputs/div3.p4-stderr b/testdata/p4_16_errors_outputs/div3.p4-stderr index 7e93b23b704..b786e569cb7 100644 --- a/testdata/p4_16_errors_outputs/div3.p4-stderr +++ b/testdata/p4_16_errors_outputs/div3.p4-stderr @@ -1,3 +1,3 @@ -div3.p4(19): [--Werror=legacy] error: /: could not evaluate at compilation time +div3.p4(19): [--Werror=invalid] error: /: Invalid could not evaluate at compilation time a = a / b; // not a compile-time constant ^^^^^ diff --git a/testdata/p4_16_errors_outputs/expression_e.p4-stderr b/testdata/p4_16_errors_outputs/expression_e.p4-stderr index 2e013e24e22..11115d1c8c6 100644 --- a/testdata/p4_16_errors_outputs/expression_e.p4-stderr +++ b/testdata/p4_16_errors_outputs/expression_e.p4-stderr @@ -1,4 +1,4 @@ expression_e.p4(21):syntax error, unexpected _ b = 32w0 & _ ^ -error: 1 errors encountered, aborting compilation +[--Werror=overlimit] error: 1 errors encountered, aborting compilation diff --git a/testdata/p4_16_errors_outputs/globalVar_e.p4-stderr b/testdata/p4_16_errors_outputs/globalVar_e.p4-stderr index 1f51a0184d7..d3fae483989 100644 --- a/testdata/p4_16_errors_outputs/globalVar_e.p4-stderr +++ b/testdata/p4_16_errors_outputs/globalVar_e.p4-stderr @@ -1,4 +1,4 @@ globalVar_e.p4(16):syntax error, unexpected ;, expecting ( bit x; ^ -error: 1 errors encountered, aborting compilation +[--Werror=overlimit] error: 1 errors encountered, aborting compilation diff --git a/testdata/p4_16_errors_outputs/header1_e.p4-stderr b/testdata/p4_16_errors_outputs/header1_e.p4-stderr index 64c1667df9b..466518ce36b 100644 --- a/testdata/p4_16_errors_outputs/header1_e.p4-stderr +++ b/testdata/p4_16_errors_outputs/header1_e.p4-stderr @@ -1,4 +1,4 @@ header1_e.p4(18):syntax error, unexpected _ _ ^ -error: 1 errors encountered, aborting compilation +[--Werror=overlimit] error: 1 errors encountered, aborting compilation diff --git a/testdata/p4_16_errors_outputs/issue1202.p4-stderr b/testdata/p4_16_errors_outputs/issue1202.p4-stderr index fee1d2db01c..1e4af4fec5c 100644 --- a/testdata/p4_16_errors_outputs/issue1202.p4-stderr +++ b/testdata/p4_16_errors_outputs/issue1202.p4-stderr @@ -1,4 +1,4 @@ issue1202.p4(1):syntax error, unexpected BIT const bit<32> x = bit ^^^ -error: 1 errors encountered, aborting compilation +[--Werror=overlimit] error: 1 errors encountered, aborting compilation diff --git a/testdata/p4_16_errors_outputs/issue1336.p4-stderr b/testdata/p4_16_errors_outputs/issue1336.p4-stderr index 1df0e1c0da7..77c6a743e1d 100644 --- a/testdata/p4_16_errors_outputs/issue1336.p4-stderr +++ b/testdata/p4_16_errors_outputs/issue1336.p4-stderr @@ -1,4 +1,4 @@ issue1336.p4(3):syntax error, unexpected ( type id ( ^ -error: 1 errors encountered, aborting compilation +[--Werror=overlimit] error: 1 errors encountered, aborting compilation diff --git a/testdata/p4_16_errors_outputs/issue1932-1.p4-stderr b/testdata/p4_16_errors_outputs/issue1932-1.p4-stderr index bc491f5f3c4..0bc4342c78a 100644 --- a/testdata/p4_16_errors_outputs/issue1932-1.p4-stderr +++ b/testdata/p4_16_errors_outputs/issue1932-1.p4-stderr @@ -1,7 +1,7 @@ -issue1932-1.p4(10): [--Werror=legacy] error: foo: Duplicates declaration foo +issue1932-1.p4(10): [--Werror=duplicate] error: foo: Duplicates declaration foo action foo (inout bit<8> x) { x = (x >> 3); } ^^^ issue1932-1.p4(9) action foo (in bit<8> x, out bit<8> y) { y = (x >> 2); } ^^^ -error: 1 errors encountered, aborting compilation +[--Werror=overlimit] error: 1 errors encountered, aborting compilation diff --git a/testdata/p4_16_errors_outputs/issue1944.p4-stderr b/testdata/p4_16_errors_outputs/issue1944.p4-stderr index ea995e60c45..27858efed78 100644 --- a/testdata/p4_16_errors_outputs/issue1944.p4-stderr +++ b/testdata/p4_16_errors_outputs/issue1944.p4-stderr @@ -1,4 +1,4 @@ issue1944.p4(1): [--Werror=overlimit] error: 2147483648: this implementation does not support bitstrings this large const bit<2147483648> ^^^^^^^^^^ -error: 1 errors encountered, aborting compilation +[--Werror=overlimit] error: 1 errors encountered, aborting compilation diff --git a/testdata/p4_16_errors_outputs/issue1986-1.p4-stderr b/testdata/p4_16_errors_outputs/issue1986-1.p4-stderr index c1584106d06..d17ec6527ec 100644 --- a/testdata/p4_16_errors_outputs/issue1986-1.p4-stderr +++ b/testdata/p4_16_errors_outputs/issue1986-1.p4-stderr @@ -1,4 +1,4 @@ issue1986-1.p4(22): [--Werror=invalid] error: : Invalid width; must be positive 0 transition select(2w0) {0w0 ^^^ -error: 1 errors encountered, aborting compilation +[--Werror=overlimit] error: 1 errors encountered, aborting compilation diff --git a/testdata/p4_16_errors_outputs/issue1986.p4-stderr b/testdata/p4_16_errors_outputs/issue1986.p4-stderr index 4196ec76176..e8e8e814632 100644 --- a/testdata/p4_16_errors_outputs/issue1986.p4-stderr +++ b/testdata/p4_16_errors_outputs/issue1986.p4-stderr @@ -1,4 +1,4 @@ issue1986.p4(18): [--Werror=invalid] error: : Invalid width; must be positive 0 {0w0 ^^^ -error: 1 errors encountered, aborting compilation +[--Werror=overlimit] error: 1 errors encountered, aborting compilation diff --git a/testdata/p4_16_errors_outputs/issue513.p4-stderr b/testdata/p4_16_errors_outputs/issue513.p4-stderr index 0eb330383bf..351af5af2ab 100644 --- a/testdata/p4_16_errors_outputs/issue513.p4-stderr +++ b/testdata/p4_16_errors_outputs/issue513.p4-stderr @@ -4,6 +4,6 @@ issue513.p4(60): [--Wwarn=deprecated] warning: mark_to_drop: Using deprecated fe v1model.p4(343) extern void mark_to_drop(); ^^^^^^^^^^^^ -issue513.p4(60): [--Werror=legacy] error: MethodCallStatement: Conditional execution in actions is not supported on this target +issue513.p4(60): [--Werror=target-error] error: MethodCallStatement: Unsupported on target Conditional execution in actions mark_to_drop(); ^^^^^^^^^^^^^^ diff --git a/testdata/p4_16_errors_outputs/p_e.p4-stderr b/testdata/p4_16_errors_outputs/p_e.p4-stderr index 47afa9e227e..f784022d30f 100644 --- a/testdata/p4_16_errors_outputs/p_e.p4-stderr +++ b/testdata/p4_16_errors_outputs/p_e.p4-stderr @@ -1,4 +1,4 @@ p_e.p4(17):syntax error, unexpected END x ^ -error: 1 errors encountered, aborting compilation +[--Werror=overlimit] error: 1 errors encountered, aborting compilation diff --git a/testdata/p4_16_errors_outputs/shift_e.p4-stderr b/testdata/p4_16_errors_outputs/shift_e.p4-stderr index 1e437525c43..fe8341656a0 100644 --- a/testdata/p4_16_errors_outputs/shift_e.p4-stderr +++ b/testdata/p4_16_errors_outputs/shift_e.p4-stderr @@ -1,4 +1,4 @@ shift_e.p4(20): error: Syntax error at shift operator: int<32> b = a > > 1; ^ -error: 1 errors encountered, aborting compilation +[--Werror=overlimit] error: 1 errors encountered, aborting compilation diff --git a/testdata/p4_16_errors_outputs/table-entries-exact-ternary.p4-stderr b/testdata/p4_16_errors_outputs/table-entries-exact-ternary.p4-stderr index f704439b796..6e0b9592474 100644 --- a/testdata/p4_16_errors_outputs/table-entries-exact-ternary.p4-stderr +++ b/testdata/p4_16_errors_outputs/table-entries-exact-ternary.p4-stderr @@ -1,4 +1,4 @@ table-entries-exact-ternary.p4(74):syntax error, unexpected ), expecting "," (0x1111 &&& 0xF ) ^ -error: 1 errors encountered, aborting compilation +[--Werror=overlimit] error: 1 errors encountered, aborting compilation diff --git a/testdata/p4_16_errors_outputs/table-entries-outside-table.p4-stderr b/testdata/p4_16_errors_outputs/table-entries-outside-table.p4-stderr index ebf016f8dea..2427fdf8f37 100644 --- a/testdata/p4_16_errors_outputs/table-entries-outside-table.p4-stderr +++ b/testdata/p4_16_errors_outputs/table-entries-outside-table.p4-stderr @@ -1,4 +1,4 @@ table-entries-outside-table.p4(68):syntax error, unexpected ENTRIES const entries ^^^^^^^ -error: 1 errors encountered, aborting compilation +[--Werror=overlimit] error: 1 errors encountered, aborting compilation diff --git a/testdata/p4_16_errors_outputs/template_e.p4-stderr b/testdata/p4_16_errors_outputs/template_e.p4-stderr index c76dad43d45..a1e5c305b06 100644 --- a/testdata/p4_16_errors_outputs/template_e.p4-stderr +++ b/testdata/p4_16_errors_outputs/template_e.p4-stderr @@ -1,13 +1,13 @@ -template_e.p4(16): [--Werror=legacy] error: T: Duplicates declaration T +template_e.p4(16): [--Werror=duplicate] error: T: Duplicates declaration T package S ^ template_e.p4(16) package S ^ -error: 2 errors encountered, aborting compilation +[--Werror=overlimit] error: 2 errors encountered, aborting compilation diff --git a/testdata/p4_16_errors_outputs/tuple-left.p4-stderr b/testdata/p4_16_errors_outputs/tuple-left.p4-stderr index eac9a3418f4..5c781882785 100644 --- a/testdata/p4_16_errors_outputs/tuple-left.p4-stderr +++ b/testdata/p4_16_errors_outputs/tuple-left.p4-stderr @@ -1,4 +1,4 @@ tuple-left.p4(21):syntax error, unexpected "," { a, ^ -error: 1 errors encountered, aborting compilation +[--Werror=overlimit] error: 1 errors encountered, aborting compilation diff --git a/testdata/p4_16_errors_outputs/underscore1_e.p4-stderr b/testdata/p4_16_errors_outputs/underscore1_e.p4-stderr index 6a7140b38cd..e2887390cdc 100644 --- a/testdata/p4_16_errors_outputs/underscore1_e.p4-stderr +++ b/testdata/p4_16_errors_outputs/underscore1_e.p4-stderr @@ -1,4 +1,4 @@ underscore1_e.p4(17):syntax error, unexpected _ bit _ ^ -error: 1 errors encountered, aborting compilation +[--Werror=overlimit] error: 1 errors encountered, aborting compilation diff --git a/testdata/p4_16_errors_outputs/underscore2_e.p4-stderr b/testdata/p4_16_errors_outputs/underscore2_e.p4-stderr index 44468409282..959c67b3a36 100644 --- a/testdata/p4_16_errors_outputs/underscore2_e.p4-stderr +++ b/testdata/p4_16_errors_outputs/underscore2_e.p4-stderr @@ -1,4 +1,4 @@ underscore2_e.p4(19):syntax error, unexpected _ bit _ ^ -error: 1 errors encountered, aborting compilation +[--Werror=overlimit] error: 1 errors encountered, aborting compilation diff --git a/testdata/p4_16_errors_outputs/underscore3_e.p4-stderr b/testdata/p4_16_errors_outputs/underscore3_e.p4-stderr index f4e54ee33c0..70d29b6d9c8 100644 --- a/testdata/p4_16_errors_outputs/underscore3_e.p4-stderr +++ b/testdata/p4_16_errors_outputs/underscore3_e.p4-stderr @@ -1,4 +1,4 @@ underscore3_e.p4(16):syntax error, unexpected _ const bit _ ^ -error: 1 errors encountered, aborting compilation +[--Werror=overlimit] error: 1 errors encountered, aborting compilation diff --git a/testdata/p4_16_errors_outputs/underscore_e.p4-stderr b/testdata/p4_16_errors_outputs/underscore_e.p4-stderr index 6bba63599a6..447400231dc 100644 --- a/testdata/p4_16_errors_outputs/underscore_e.p4-stderr +++ b/testdata/p4_16_errors_outputs/underscore_e.p4-stderr @@ -1,4 +1,4 @@ underscore_e.p4(16):syntax error, unexpected _ extern void _ ^ -error: 1 errors encountered, aborting compilation +[--Werror=overlimit] error: 1 errors encountered, aborting compilation diff --git a/testdata/p4_16_errors_outputs/width_e.p4-stderr b/testdata/p4_16_errors_outputs/width_e.p4-stderr index 9fa86e26928..5c145288b68 100644 --- a/testdata/p4_16_errors_outputs/width_e.p4-stderr +++ b/testdata/p4_16_errors_outputs/width_e.p4-stderr @@ -1,4 +1,4 @@ width_e.p4(16): [--Werror=overlimit] error: 12301923123132: this implementation does not support bitstrings this large const bit<12301923123132> ^^^^^^^^^^^^^^ -error: 1 errors encountered, aborting compilation +[--Werror=overlimit] error: 1 errors encountered, aborting compilation diff --git a/testdata/p4_16_samples/issue2126.p4 b/testdata/p4_16_samples/issue2126.p4 new file mode 100755 index 00000000000..ce7225e0733 --- /dev/null +++ b/testdata/p4_16_samples/issue2126.p4 @@ -0,0 +1,11 @@ +parser p() { + state start { + { + bit<16> retval = 0; + } + { + bit<16> retval = 1; + } + transition accept; + } +} diff --git a/testdata/p4_16_samples_outputs/issue2126-first.p4 b/testdata/p4_16_samples_outputs/issue2126-first.p4 new file mode 100644 index 00000000000..63bbbbecde5 --- /dev/null +++ b/testdata/p4_16_samples_outputs/issue2126-first.p4 @@ -0,0 +1,12 @@ +parser p() { + state start { + { + bit<16> retval = 16w0; + } + { + bit<16> retval = 16w1; + } + transition accept; + } +} + diff --git a/testdata/p4_16_samples_outputs/issue2126-frontend.p4 b/testdata/p4_16_samples_outputs/issue2126-frontend.p4 new file mode 100644 index 00000000000..e69de29bb2d diff --git a/testdata/p4_16_samples_outputs/issue2126.p4 b/testdata/p4_16_samples_outputs/issue2126.p4 new file mode 100644 index 00000000000..7a1b9d3fd86 --- /dev/null +++ b/testdata/p4_16_samples_outputs/issue2126.p4 @@ -0,0 +1,12 @@ +parser p() { + state start { + { + bit<16> retval = 0; + } + { + bit<16> retval = 1; + } + transition accept; + } +} + diff --git a/testdata/p4_16_samples_outputs/issue2126.p4-stderr b/testdata/p4_16_samples_outputs/issue2126.p4-stderr new file mode 100644 index 00000000000..7f94c95a8ff --- /dev/null +++ b/testdata/p4_16_samples_outputs/issue2126.p4-stderr @@ -0,0 +1 @@ +warning: Program does not contain a `main' module From 28b5258bc8a310af4d7e38c8e6a534c8ed4593f4 Mon Sep 17 00:00:00 2001 From: Hemant Singh <32817427+hesingh@users.noreply.github.com> Date: Tue, 14 Jan 2020 18:55:14 -0500 Subject: [PATCH 056/106] Fix supporting Range operator for bmv2 backend (#2125) * Fix supporting Range operator for bmv2 backend * Add check for range less than check * Fix range check * Add new keyword parse_range to bmv2 backend * Add Range to Mask conversion C code to midend. Another checkin will fold this code into C++ midend pass * Add midend pass to replace Ranges with Masks; backedout bmv2 backend code * Remove old filed not needed any more * Add check Range and new error case * Fix Travis failure due to new error P4 program * Fix positive test Travis error * Address Mihai's comments; added pass to PSA switch * Fix indent and also force another Travis run * Add code change and debug to diagnose Travis failure * Remove debugged code * Add Andy's SFT files * Remove parenthesis from single Range code * Print error in same base as in P4 code * checkin error output missed in prior commit * Change code to add P4 line number to error * Changes from Mihai's review today * Moved checkRange() into rangeToTcam() * Optimize few calls and fixed extra space in range error mesg * Fix more code due to Mihai's comment * Change code after Antonin review * Add check for select Cases exceeding a threshold * Fix Travis cpplint failure * Change threshold to warning * Change warning mesg after Andy's review --- backends/bmv2/psa_switch/midend.cpp | 2 + backends/bmv2/simple_switch/midend.cpp | 2 + backends/p4test/midend.cpp | 2 + midend/CMakeLists.txt | 2 + midend/replaceSelectRange.cpp | 159 +++++++++ midend/replaceSelectRange.h | 65 ++++ testdata/p4_16_errors/issue-2123_e.p4 | 102 ++++++ .../issue-2123_e-first.p4 | 86 +++++ .../issue-2123_e-frontend.p4 | 83 +++++ testdata/p4_16_errors_outputs/issue-2123_e.p4 | 86 +++++ .../issue-2123_e.p4-stderr | 36 ++ .../issue-2123_e.p4.entries.txt | 0 .../issue-2123_e.p4.p4info.txt | 3 + testdata/p4_16_samples/issue-2123-2-bmv2.p4 | 156 +++++++++ testdata/p4_16_samples/issue-2123-2-bmv2.stf | 57 ++++ testdata/p4_16_samples/issue-2123-3-bmv2.p4 | 156 +++++++++ testdata/p4_16_samples/issue-2123-3-bmv2.stf | 83 +++++ testdata/p4_16_samples/issue-2123.p4 | 231 +++++++++++++ .../issue-2123-2-bmv2-first.p4 | 114 +++++++ .../issue-2123-2-bmv2-frontend.p4 | 144 ++++++++ .../issue-2123-2-bmv2-midend.p4 | 287 ++++++++++++++++ .../issue-2123-2-bmv2.p4 | 114 +++++++ .../issue-2123-2-bmv2.p4-stderr | 0 .../issue-2123-2-bmv2.p4.entries.txt | 0 .../issue-2123-2-bmv2.p4.p4info.txt | 3 + .../issue-2123-3-bmv2-first.p4 | 114 +++++++ .../issue-2123-3-bmv2-frontend.p4 | 144 ++++++++ .../issue-2123-3-bmv2-midend.p4 | 312 ++++++++++++++++++ .../issue-2123-3-bmv2.p4 | 114 +++++++ .../issue-2123-3-bmv2.p4-stderr | 0 .../issue-2123-3-bmv2.p4.entries.txt | 0 .../issue-2123-3-bmv2.p4.p4info.txt | 3 + .../p4_16_samples_outputs/issue-2123-first.p4 | 210 ++++++++++++ .../issue-2123-frontend.p4 | 224 +++++++++++++ .../issue-2123-midend.p4 | 257 +++++++++++++++ testdata/p4_16_samples_outputs/issue-2123.p4 | 198 +++++++++++ .../issue-2123.p4-stderr | 0 .../issue-2123.p4.entries.txt | 0 .../issue-2123.p4.p4info.txt | 247 ++++++++++++++ 39 files changed, 3796 insertions(+) create mode 100644 midend/replaceSelectRange.cpp create mode 100644 midend/replaceSelectRange.h create mode 100644 testdata/p4_16_errors/issue-2123_e.p4 create mode 100644 testdata/p4_16_errors_outputs/issue-2123_e-first.p4 create mode 100644 testdata/p4_16_errors_outputs/issue-2123_e-frontend.p4 create mode 100644 testdata/p4_16_errors_outputs/issue-2123_e.p4 create mode 100644 testdata/p4_16_errors_outputs/issue-2123_e.p4-stderr create mode 100644 testdata/p4_16_errors_outputs/issue-2123_e.p4.entries.txt create mode 100644 testdata/p4_16_errors_outputs/issue-2123_e.p4.p4info.txt create mode 100644 testdata/p4_16_samples/issue-2123-2-bmv2.p4 create mode 100644 testdata/p4_16_samples/issue-2123-2-bmv2.stf create mode 100644 testdata/p4_16_samples/issue-2123-3-bmv2.p4 create mode 100644 testdata/p4_16_samples/issue-2123-3-bmv2.stf create mode 100644 testdata/p4_16_samples/issue-2123.p4 create mode 100644 testdata/p4_16_samples_outputs/issue-2123-2-bmv2-first.p4 create mode 100644 testdata/p4_16_samples_outputs/issue-2123-2-bmv2-frontend.p4 create mode 100644 testdata/p4_16_samples_outputs/issue-2123-2-bmv2-midend.p4 create mode 100644 testdata/p4_16_samples_outputs/issue-2123-2-bmv2.p4 create mode 100644 testdata/p4_16_samples_outputs/issue-2123-2-bmv2.p4-stderr create mode 100644 testdata/p4_16_samples_outputs/issue-2123-2-bmv2.p4.entries.txt create mode 100644 testdata/p4_16_samples_outputs/issue-2123-2-bmv2.p4.p4info.txt create mode 100644 testdata/p4_16_samples_outputs/issue-2123-3-bmv2-first.p4 create mode 100644 testdata/p4_16_samples_outputs/issue-2123-3-bmv2-frontend.p4 create mode 100644 testdata/p4_16_samples_outputs/issue-2123-3-bmv2-midend.p4 create mode 100644 testdata/p4_16_samples_outputs/issue-2123-3-bmv2.p4 create mode 100644 testdata/p4_16_samples_outputs/issue-2123-3-bmv2.p4-stderr create mode 100644 testdata/p4_16_samples_outputs/issue-2123-3-bmv2.p4.entries.txt create mode 100644 testdata/p4_16_samples_outputs/issue-2123-3-bmv2.p4.p4info.txt create mode 100644 testdata/p4_16_samples_outputs/issue-2123-first.p4 create mode 100644 testdata/p4_16_samples_outputs/issue-2123-frontend.p4 create mode 100644 testdata/p4_16_samples_outputs/issue-2123-midend.p4 create mode 100644 testdata/p4_16_samples_outputs/issue-2123.p4 create mode 100644 testdata/p4_16_samples_outputs/issue-2123.p4-stderr create mode 100644 testdata/p4_16_samples_outputs/issue-2123.p4.entries.txt create mode 100644 testdata/p4_16_samples_outputs/issue-2123.p4.p4info.txt diff --git a/backends/bmv2/psa_switch/midend.cpp b/backends/bmv2/psa_switch/midend.cpp index 7afeddd7b70..e966fc2a624 100644 --- a/backends/bmv2/psa_switch/midend.cpp +++ b/backends/bmv2/psa_switch/midend.cpp @@ -36,6 +36,7 @@ limitations under the License. #include "midend/eliminateSerEnums.h" #include "midend/flattenHeaders.h" #include "midend/flattenInterfaceStructs.h" +#include "midend/replaceSelectRange.h" #include "midend/local_copyprop.h" #include "midend/nestedStructs.h" #include "midend/removeLeftSlices.h" @@ -121,6 +122,7 @@ PsaSwitchMidEnd::PsaSwitchMidEnd(CompilerOptions& options, std::ostream* outStre new P4::RemoveSelectBooleans(&refMap, &typeMap), new P4::FlattenHeaders(&refMap, &typeMap), new P4::FlattenInterfaceStructs(&refMap, &typeMap), + new P4::ReplaceSelectRange(&refMap, &typeMap), new P4::Predication(&refMap), new P4::MoveDeclarations(), // more may have been introduced new P4::ConstantFolding(&refMap, &typeMap), diff --git a/backends/bmv2/simple_switch/midend.cpp b/backends/bmv2/simple_switch/midend.cpp index 82f88711788..79b29a9d63e 100644 --- a/backends/bmv2/simple_switch/midend.cpp +++ b/backends/bmv2/simple_switch/midend.cpp @@ -37,6 +37,7 @@ limitations under the License. #include "midend/eliminateSerEnums.h" #include "midend/flattenHeaders.h" #include "midend/flattenInterfaceStructs.h" +#include "midend/replaceSelectRange.h" #include "midend/local_copyprop.h" #include "midend/nestedStructs.h" #include "midend/removeLeftSlices.h" @@ -97,6 +98,7 @@ SimpleSwitchMidEnd::SimpleSwitchMidEnd(CompilerOptions& options, std::ostream* o new P4::RemoveSelectBooleans(&refMap, &typeMap), new P4::FlattenHeaders(&refMap, &typeMap), new P4::FlattenInterfaceStructs(&refMap, &typeMap), + new P4::ReplaceSelectRange(&refMap, &typeMap), new P4::Predication(&refMap), new P4::MoveDeclarations(), // more may have been introduced new P4::ConstantFolding(&refMap, &typeMap), diff --git a/backends/p4test/midend.cpp b/backends/p4test/midend.cpp index 6bbfbf75820..da2a7f883b2 100644 --- a/backends/p4test/midend.cpp +++ b/backends/p4test/midend.cpp @@ -36,6 +36,7 @@ limitations under the License. #include "midend/eliminateSerEnums.h" #include "midend/flattenHeaders.h" #include "midend/flattenInterfaceStructs.h" +#include "midend/replaceSelectRange.h" #include "midend/expandEmit.h" #include "midend/expandLookahead.h" #include "midend/local_copyprop.h" @@ -105,6 +106,7 @@ MidEnd::MidEnd(CompilerOptions& options) { new P4::RemoveSelectBooleans(&refMap, &typeMap), new P4::FlattenHeaders(&refMap, &typeMap), new P4::FlattenInterfaceStructs(&refMap, &typeMap), + new P4::ReplaceSelectRange(&refMap, &typeMap), new P4::Predication(&refMap), new P4::MoveDeclarations(), // more may have been introduced new P4::ConstantFolding(&refMap, &typeMap), diff --git a/midend/CMakeLists.txt b/midend/CMakeLists.txt index e3b0d4c40a6..4044827a606 100644 --- a/midend/CMakeLists.txt +++ b/midend/CMakeLists.txt @@ -38,6 +38,7 @@ set (MIDEND_SRCS removeMiss.cpp removeParameters.cpp removeSelectBooleans.cpp + replaceSelectRange.cpp removeUnusedParameters.cpp simplifyBitwise.cpp simplifyKey.cpp @@ -80,6 +81,7 @@ set (MIDEND_HDRS removeParameters.h removeSelectBooleans.h removeUnusedParameters.h + replaceSelectRange.h simplifyBitwise.h simplifyKey.h simplifySelectCases.h diff --git a/midend/replaceSelectRange.cpp b/midend/replaceSelectRange.cpp new file mode 100644 index 00000000000..de89556307c --- /dev/null +++ b/midend/replaceSelectRange.cpp @@ -0,0 +1,159 @@ +/* +* Copyright 2020, MNK Labs & Consulting +* http://mnkcg.com +* +* 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 "replaceSelectRange.h" + +namespace P4 { + +std::vector +DoReplaceSelectRange::rangeToMasks(const IR::Range *r) { + std::vector masks; + + auto l = r->left->to(); + if (!l) { + ::error(ErrorType::ERR_UNSUPPORTED_ON_TARGET, + "%2%: Range min must be a compile-time constant.", + r, r->left); + return masks; + } + auto left = l->value; + + auto ri = r->right->to(); + if (!ri) { + ::error(ErrorType::ERR_UNSUPPORTED_ON_TARGET, + "%2%: Range max must be a compile-time constant.", + r, r->right); + return masks; + } + auto right = ri->value; + if (right < left) { + ::error(ErrorType::ERR_INVALID, "%2%-%3%: Range end is less than start.", + r, r->left, r->right); + return masks; + } + + int width = r->type->width_bits(); + big_int min = left; + big_int max = right; + big_int range_size_remaining = max - min + 1; + + while (range_size_remaining > 0) { + big_int range_size = ((big_int) 1) << ffs(min); + + while (range_size > range_size_remaining) + range_size >>= 1; + + auto constType = r->left->type; + auto base = l->base; + auto valConst = new IR::Constant(constType, min, base, true); + big_int mask = ~(range_size - 1) & ((((big_int) 1) << width) - 1); + auto maskConst = new IR::Constant(constType, mask, base, true); + auto m = new IR::Mask(r->srcInfo, valConst, maskConst); + + masks.push_back(m); + range_size_remaining -= range_size; + min += range_size; + } + + return masks; +} + +std::vector> +DoReplaceSelectRange::cartesianAppend(const std::vector>& vecs, + const std::vector& masks) { + std::vector> newVecs; + + for (auto v : vecs) { + for (auto mask : masks) { + auto copy(v); + + copy.push_back(mask); + newVecs.push_back(copy); + } + } + + return newVecs; +} + +std::vector> +DoReplaceSelectRange::cartesianAppend(const std::vector>& vecs, + const IR::Expression *e) { + std::vector> newVecs; + + for (auto v : vecs) { + auto copy(v); + + copy.push_back(e); + newVecs.push_back(copy); + } + + return newVecs; +} + +const IR::Node* DoReplaceSelectRange::postorder(IR::SelectCase* sc) { + auto newCases = new IR::Vector(); + auto keySet = sc->keyset; + + if (auto r = keySet->to()) { + auto masks = rangeToMasks(r); + if (masks.empty()) + return sc; + + for (auto mask : masks) { + auto c = new IR::SelectCase(sc->srcInfo, mask, sc->state); + newCases->push_back(c); + } + + return newCases; + } else if (auto oldList = keySet->to()) { + std::vector> newVectors; + IR::Vector first; + + newVectors.push_back(first); + + for (auto key : oldList->components) { + if (auto r = key->to()) { + auto masks = rangeToMasks(r); + if (masks.empty()) + return sc; + + newVectors = cartesianAppend(newVectors, masks); + } else { + newVectors = cartesianAppend(newVectors, key); + } + } + + for (auto v : newVectors) { + auto le = new IR::ListExpression(oldList->srcInfo, v); + newCases->push_back(new IR::SelectCase(sc->srcInfo, le, sc->state)); + } + if (newCases->size() > MAX_CASES) { + ::warning(ErrorType::ERR_OVERLIMIT, + "select key set expression with a range expands into %2% " + "ternary key set expressions, which may lead to run-time " + "performance or parser configuration space issues in some" + " targets.", sc, newCases->size()); + } + + return newCases; + } + + return sc; +} + +} // namespace P4 diff --git a/midend/replaceSelectRange.h b/midend/replaceSelectRange.h new file mode 100644 index 00000000000..ec03edcf07e --- /dev/null +++ b/midend/replaceSelectRange.h @@ -0,0 +1,65 @@ +/* +* Copyright 2020, MNK Labs & Consulting +* http://mnkcg.com +* +* 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. +* +*/ +#ifndef _MIDEND_REPLACESELECTRANGE_H_ +#define _MIDEND_REPLACESELECTRANGE_H_ + +#include +#include +#include +#include +#include "../lib/gmputil.h" + +#include "ir/ir.h" +#include "frontends/p4/typeChecking/typeChecker.h" + +namespace P4 { + +/** + Find the types to replace and insert them in the range-mask map. + Call pass after the flattenInterfaceStructs pass. + */ +class DoReplaceSelectRange : public Transform { + public: + // number of new cases generated for ternary operations due to a range + // Each case is a key set expression. + const uint MAX_CASES; + + explicit DoReplaceSelectRange(uint max) : MAX_CASES(max) { + setName("DoReplaceSelectRange"); + } + const IR::Node* postorder(IR::SelectCase* p) override; + std::vector rangeToMasks(const IR::Range *); + std::vector> cartesianAppend( + const std::vector>& vecs, + const std::vector& masks); + std::vector> cartesianAppend( + const std::vector>& vecs, + const IR::Expression *e); +}; + +class ReplaceSelectRange final : public PassManager { + public: + ReplaceSelectRange(ReferenceMap* refMap, TypeMap* typeMap) { + passes.push_back(new TypeChecking(refMap, typeMap)); + passes.push_back(new DoReplaceSelectRange(100)); + setName("ReplaceSelectRange"); + } +}; + +} // namespace P4 +#endif /* _MIDEND_REPLACESELECTRANGE_H_ */ diff --git a/testdata/p4_16_errors/issue-2123_e.p4 b/testdata/p4_16_errors/issue-2123_e.p4 new file mode 100644 index 00000000000..b51cdaf25a0 --- /dev/null +++ b/testdata/p4_16_errors/issue-2123_e.p4 @@ -0,0 +1,102 @@ +/* +* Copyright 2020, MNK Labs & Consulting +* http://mnkcg.com +* +* 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 + +struct ingress_metadata_t { + bit<12> vrf; + bit<16> bd; + bit<16> nexthop_index; +} + +header ethernet_t { + bit<48> dstAddr; + bit<48> srcAddr; + bit<16> etherType; +} + +header ipv4_t { + bit<4> version; + bit<4> ihl; + bit<8> diffserv; + bit<16> totalLen; + bit<16> identification; + bit<3> flags; + bit<13> fragOffset; + bit<8> ttl; + bit<8> protocol; + bit<16> hdrChecksum; + bit<32> srcAddr; + bit<32> dstAddr; +} + +struct metadata { + ingress_metadata_t ingress_metadata; +} + +struct headers { + ethernet_t ethernet; + ipv4_t ipv4; +} + +parser ParserImpl(packet_in packet, out headers hdr, inout metadata meta, inout standard_metadata_t standard_metadata) { + state parse_ethernet { + packet.extract(hdr = hdr.ethernet); + + transition select(hdr.ethernet.etherType) { + 0x0806 .. 0x0800 : parse_ipv4; + 2054 .. 2048 : parse_ipv4; + hdr.ipv4.totalLen .. 0x0800 : parse_ipv4; + 0x0800 .. hdr.ipv4.totalLen : parse_ipv4; + default: accept; + } + } + state parse_ipv4 { + packet.extract(hdr = hdr.ipv4); + transition accept; + } + state start { + transition parse_ethernet; + } +} + +control egress(inout headers hdr, inout metadata meta, inout standard_metadata_t standard_metadata) { + apply {} +} + +control ingress(inout headers hdr, inout metadata meta, inout standard_metadata_t standard_metadata) { + apply {} +} + +control DeparserImpl(packet_out packet, in headers hdr) { + apply {} +} + +control verifyChecksum(inout headers hdr, inout metadata meta) { + apply {} +} + +control computeChecksum(inout headers hdr, inout metadata meta) { + apply {} +} + +V1Switch(p = ParserImpl(), + ig = ingress(), + vr = verifyChecksum(), + eg = egress(), + ck = computeChecksum(), + dep = DeparserImpl()) main; diff --git a/testdata/p4_16_errors_outputs/issue-2123_e-first.p4 b/testdata/p4_16_errors_outputs/issue-2123_e-first.p4 new file mode 100644 index 00000000000..c73fe61aa9e --- /dev/null +++ b/testdata/p4_16_errors_outputs/issue-2123_e-first.p4 @@ -0,0 +1,86 @@ +#include +#include + +struct ingress_metadata_t { + bit<12> vrf; + bit<16> bd; + bit<16> nexthop_index; +} + +header ethernet_t { + bit<48> dstAddr; + bit<48> srcAddr; + bit<16> etherType; +} + +header ipv4_t { + bit<4> version; + bit<4> ihl; + bit<8> diffserv; + bit<16> totalLen; + bit<16> identification; + bit<3> flags; + bit<13> fragOffset; + bit<8> ttl; + bit<8> protocol; + bit<16> hdrChecksum; + bit<32> srcAddr; + bit<32> dstAddr; +} + +struct metadata { + ingress_metadata_t ingress_metadata; +} + +struct headers { + ethernet_t ethernet; + ipv4_t ipv4; +} + +parser ParserImpl(packet_in packet, out headers hdr, inout metadata meta, inout standard_metadata_t standard_metadata) { + state parse_ethernet { + packet.extract(hdr = hdr.ethernet); + transition select(hdr.ethernet.etherType) { + 16w0x806 .. 16w0x800: parse_ipv4; + 16w2054 .. 16w2048: parse_ipv4; + hdr.ipv4.totalLen .. 16w0x800: parse_ipv4; + 16w0x800 .. hdr.ipv4.totalLen: parse_ipv4; + default: accept; + } + } + state parse_ipv4 { + packet.extract(hdr = hdr.ipv4); + transition accept; + } + state start { + transition parse_ethernet; + } +} + +control egress(inout headers hdr, inout metadata meta, inout standard_metadata_t standard_metadata) { + apply { + } +} + +control ingress(inout headers hdr, inout metadata meta, inout standard_metadata_t standard_metadata) { + apply { + } +} + +control DeparserImpl(packet_out packet, in headers hdr) { + apply { + } +} + +control verifyChecksum(inout headers hdr, inout metadata meta) { + apply { + } +} + +control computeChecksum(inout headers hdr, inout metadata meta) { + apply { + } +} + +V1Switch(p = ParserImpl(), ig = ingress(), vr = verifyChecksum(), eg = egress(), ck = computeChecksum(), dep = DeparserImpl()) main; + diff --git a/testdata/p4_16_errors_outputs/issue-2123_e-frontend.p4 b/testdata/p4_16_errors_outputs/issue-2123_e-frontend.p4 new file mode 100644 index 00000000000..764dbcf2918 --- /dev/null +++ b/testdata/p4_16_errors_outputs/issue-2123_e-frontend.p4 @@ -0,0 +1,83 @@ +#include +#include + +struct ingress_metadata_t { + bit<12> vrf; + bit<16> bd; + bit<16> nexthop_index; +} + +header ethernet_t { + bit<48> dstAddr; + bit<48> srcAddr; + bit<16> etherType; +} + +header ipv4_t { + bit<4> version; + bit<4> ihl; + bit<8> diffserv; + bit<16> totalLen; + bit<16> identification; + bit<3> flags; + bit<13> fragOffset; + bit<8> ttl; + bit<8> protocol; + bit<16> hdrChecksum; + bit<32> srcAddr; + bit<32> dstAddr; +} + +struct metadata { + ingress_metadata_t ingress_metadata; +} + +struct headers { + ethernet_t ethernet; + ipv4_t ipv4; +} + +parser ParserImpl(packet_in packet, out headers hdr, inout metadata meta, inout standard_metadata_t standard_metadata) { + state parse_ipv4 { + packet.extract(hdr = hdr.ipv4); + transition accept; + } + state start { + packet.extract(hdr = hdr.ethernet); + transition select(hdr.ethernet.etherType) { + 16w0x806 .. 16w0x800: parse_ipv4; + 16w2054 .. 16w2048: parse_ipv4; + hdr.ipv4.totalLen .. 16w0x800: parse_ipv4; + 16w0x800 .. hdr.ipv4.totalLen: parse_ipv4; + default: accept; + } + } +} + +control egress(inout headers hdr, inout metadata meta, inout standard_metadata_t standard_metadata) { + apply { + } +} + +control ingress(inout headers hdr, inout metadata meta, inout standard_metadata_t standard_metadata) { + apply { + } +} + +control DeparserImpl(packet_out packet, in headers hdr) { + apply { + } +} + +control verifyChecksum(inout headers hdr, inout metadata meta) { + apply { + } +} + +control computeChecksum(inout headers hdr, inout metadata meta) { + apply { + } +} + +V1Switch(p = ParserImpl(), ig = ingress(), vr = verifyChecksum(), eg = egress(), ck = computeChecksum(), dep = DeparserImpl()) main; + diff --git a/testdata/p4_16_errors_outputs/issue-2123_e.p4 b/testdata/p4_16_errors_outputs/issue-2123_e.p4 new file mode 100644 index 00000000000..f7a0086d0c3 --- /dev/null +++ b/testdata/p4_16_errors_outputs/issue-2123_e.p4 @@ -0,0 +1,86 @@ +#include +#include + +struct ingress_metadata_t { + bit<12> vrf; + bit<16> bd; + bit<16> nexthop_index; +} + +header ethernet_t { + bit<48> dstAddr; + bit<48> srcAddr; + bit<16> etherType; +} + +header ipv4_t { + bit<4> version; + bit<4> ihl; + bit<8> diffserv; + bit<16> totalLen; + bit<16> identification; + bit<3> flags; + bit<13> fragOffset; + bit<8> ttl; + bit<8> protocol; + bit<16> hdrChecksum; + bit<32> srcAddr; + bit<32> dstAddr; +} + +struct metadata { + ingress_metadata_t ingress_metadata; +} + +struct headers { + ethernet_t ethernet; + ipv4_t ipv4; +} + +parser ParserImpl(packet_in packet, out headers hdr, inout metadata meta, inout standard_metadata_t standard_metadata) { + state parse_ethernet { + packet.extract(hdr = hdr.ethernet); + transition select(hdr.ethernet.etherType) { + 0x806 .. 0x800: parse_ipv4; + 2054 .. 2048: parse_ipv4; + hdr.ipv4.totalLen .. 0x800: parse_ipv4; + 0x800 .. hdr.ipv4.totalLen: parse_ipv4; + default: accept; + } + } + state parse_ipv4 { + packet.extract(hdr = hdr.ipv4); + transition accept; + } + state start { + transition parse_ethernet; + } +} + +control egress(inout headers hdr, inout metadata meta, inout standard_metadata_t standard_metadata) { + apply { + } +} + +control ingress(inout headers hdr, inout metadata meta, inout standard_metadata_t standard_metadata) { + apply { + } +} + +control DeparserImpl(packet_out packet, in headers hdr) { + apply { + } +} + +control verifyChecksum(inout headers hdr, inout metadata meta) { + apply { + } +} + +control computeChecksum(inout headers hdr, inout metadata meta) { + apply { + } +} + +V1Switch(p = ParserImpl(), ig = ingress(), vr = verifyChecksum(), eg = egress(), ck = computeChecksum(), dep = DeparserImpl()) main; + diff --git a/testdata/p4_16_errors_outputs/issue-2123_e.p4-stderr b/testdata/p4_16_errors_outputs/issue-2123_e.p4-stderr new file mode 100644 index 00000000000..5617e73c181 --- /dev/null +++ b/testdata/p4_16_errors_outputs/issue-2123_e.p4-stderr @@ -0,0 +1,36 @@ +issue-2123_e.p4(63): [--Wwarn=uninitialized_use] warning: hdr.ipv4.totalLen may be uninitialized + hdr.ipv4.totalLen .. 0x0800 : parse_ipv4; + ^^^^^^^^^^^^^^^^^ +issue-2123_e.p4(64): [--Wwarn=uninitialized_use] warning: hdr.ipv4.totalLen may be uninitialized + 0x0800 .. hdr.ipv4.totalLen : parse_ipv4; + ^^^^^^^^^^^^^^^^^ +issue-2123_e.p4(61): [--Werror=invalid] error: ..: Invalid 0x806-0x800: Range end is less than start. + 0x0806 .. 0x0800 : parse_ipv4; + ^^^^^^^^^^^^^^^^ +issue-2123_e.p4(61) + 0x0806 .. 0x0800 : parse_ipv4; + ^^^^^^ +issue-2123_e.p4(61) + 0x0806 .. 0x0800 : parse_ipv4; + ^^^^^^ +issue-2123_e.p4(62): [--Werror=invalid] error: ..: Invalid 2054-2048: Range end is less than start. + 2054 .. 2048 : parse_ipv4; + ^^^^^^^^^^^^ +issue-2123_e.p4(62) + 2054 .. 2048 : parse_ipv4; + ^^^^ +issue-2123_e.p4(62) + 2054 .. 2048 : parse_ipv4; + ^^^^ +issue-2123_e.p4(63): [--Werror=target-error] error: ..: Unsupported on target hdr.ipv4.totalLen: Range min must be a compile-time constant. + hdr.ipv4.totalLen .. 0x0800 : parse_ipv4; + ^^^^^^^^^^^^^^^^^^^^^^^^^^^ +issue-2123_e.p4(63) + hdr.ipv4.totalLen .. 0x0800 : parse_ipv4; + ^^^^^^^^^^^^^^^^^ +issue-2123_e.p4(64): [--Werror=target-error] error: ..: Unsupported on target hdr.ipv4.totalLen: Range max must be a compile-time constant. + 0x0800 .. hdr.ipv4.totalLen : parse_ipv4; + ^^^^^^^^^^^^^^^^^^^^^^^^^^^ +issue-2123_e.p4(64) + 0x0800 .. hdr.ipv4.totalLen : parse_ipv4; + ^^^^^^^^^^^^^^^^^ diff --git a/testdata/p4_16_errors_outputs/issue-2123_e.p4.entries.txt b/testdata/p4_16_errors_outputs/issue-2123_e.p4.entries.txt new file mode 100644 index 00000000000..e69de29bb2d diff --git a/testdata/p4_16_errors_outputs/issue-2123_e.p4.p4info.txt b/testdata/p4_16_errors_outputs/issue-2123_e.p4.p4info.txt new file mode 100644 index 00000000000..9ec92493e4c --- /dev/null +++ b/testdata/p4_16_errors_outputs/issue-2123_e.p4.p4info.txt @@ -0,0 +1,3 @@ +pkg_info { + arch: "v1model" +} diff --git a/testdata/p4_16_samples/issue-2123-2-bmv2.p4 b/testdata/p4_16_samples/issue-2123-2-bmv2.p4 new file mode 100644 index 00000000000..56883f25315 --- /dev/null +++ b/testdata/p4_16_samples/issue-2123-2-bmv2.p4 @@ -0,0 +1,156 @@ +/* + * Copyright 2020, MNK Labs & Consulting + * http://mnkcg.com + * + * 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 + +header ethernet_t { + bit<48> dstAddr; + bit<48> srcAddr; + bit<16> etherType; +} + +header h0_t { + bit<8> f0; +} + +header h1_t { + bit<8> f1; +} + +header h2_t { + bit<8> f2; +} + +header h3_t { + bit<8> f3; +} + +header h4_t { + bit<8> f4; +} + +struct metadata { +} + +struct headers { + ethernet_t ethernet; + h0_t h0; + h1_t h1; + h2_t h2; + h3_t h3; + h4_t h4; +} + +parser ParserImpl( + packet_in packet, + out headers hdr, + inout metadata meta, + inout standard_metadata_t standard_metadata) +{ + state start { + packet.extract(hdr.ethernet); + transition select(hdr.ethernet.etherType) { + 0x0800 .. 0x0806: parse_h0; + 0x0808: parse_h1; + 0xfff1 .. 0xfffe: parse_h2; + 0x0900: parse_h3; + 0x08ff .. 0x0901: parse_h4; + default: accept; + } + } + state parse_h0 { + packet.extract(hdr.h0); + transition accept; + } + state parse_h1 { + packet.extract(hdr.h1); + transition accept; + } + state parse_h2 { + packet.extract(hdr.h2); + transition accept; + } + state parse_h3 { + packet.extract(hdr.h3); + transition accept; + } + state parse_h4 { + packet.extract(hdr.h4); + transition accept; + } +} + +control ingress( + inout headers hdr, + inout metadata meta, + inout standard_metadata_t standard_metadata) +{ + apply { + // Overwrite some bits of one of the header fields so that in + // the STF test we can match on the output packet contents and + // know which case was taken in the select expression in the + // parser. + hdr.ethernet.dstAddr[44:44] = hdr.h4.isValid() ? 1w1 : 0; + hdr.ethernet.dstAddr[43:43] = hdr.h3.isValid() ? 1w1 : 0; + hdr.ethernet.dstAddr[42:42] = hdr.h2.isValid() ? 1w1 : 0; + hdr.ethernet.dstAddr[41:41] = hdr.h1.isValid() ? 1w1 : 0; + hdr.ethernet.dstAddr[40:40] = hdr.h0.isValid() ? 1w1 : 0; + + standard_metadata.egress_spec = 3; + } +} + +control egress( + inout headers hdr, + inout metadata meta, + inout standard_metadata_t standard_metadata) +{ + apply { + } +} + +control DeparserImpl( + packet_out packet, + in headers hdr) +{ + apply { + packet.emit(hdr.ethernet); + packet.emit(hdr.h0); + packet.emit(hdr.h1); + packet.emit(hdr.h2); + packet.emit(hdr.h3); + packet.emit(hdr.h4); + } +} + +control verifyChecksum(inout headers hdr, inout metadata meta) { + apply { } +} + +control computeChecksum(inout headers hdr, inout metadata meta) { + apply { } +} + +V1Switch( + ParserImpl(), + verifyChecksum(), + ingress(), + egress(), + computeChecksum(), + DeparserImpl()) +main; diff --git a/testdata/p4_16_samples/issue-2123-2-bmv2.stf b/testdata/p4_16_samples/issue-2123-2-bmv2.stf new file mode 100644 index 00000000000..1b49548a776 --- /dev/null +++ b/testdata/p4_16_samples/issue-2123-2-bmv2.stf @@ -0,0 +1,57 @@ +# this should match default case of select expression +packet 1 ffffffffffff ffffffffffff 07ff 00 +expect 3 e0ffffffffff ffffffffffff 07ff 00 $ + +# go to parse_h0 +packet 1 ffffffffffff ffffffffffff 0800 00 +expect 3 e1ffffffffff ffffffffffff 0800 00 $ + +packet 1 ffffffffffff ffffffffffff 0806 00 +expect 3 e1ffffffffff ffffffffffff 0806 00 $ + +# default +packet 1 ffffffffffff ffffffffffff 0807 00 +expect 3 e0ffffffffff ffffffffffff 0807 00 $ + +# parse_h1 +packet 1 ffffffffffff ffffffffffff 0808 00 +expect 3 e2ffffffffff ffffffffffff 0808 00 $ + +# default +packet 1 ffffffffffff ffffffffffff 0809 00 +expect 3 e0ffffffffff ffffffffffff 0809 00 $ + +# default +packet 1 ffffffffffff ffffffffffff fff0 00 +expect 3 e0ffffffffff ffffffffffff fff0 00 $ + +# parse_h2 +packet 1 ffffffffffff ffffffffffff fff1 00 +expect 3 e4ffffffffff ffffffffffff fff1 00 $ + +packet 1 ffffffffffff ffffffffffff fffe 00 +expect 3 e4ffffffffff ffffffffffff fffe 00 $ + +# default +packet 1 ffffffffffff ffffffffffff ffff 00 +expect 3 e0ffffffffff ffffffffffff ffff 00 $ + +# default +packet 1 ffffffffffff ffffffffffff 08fe 00 +expect 3 e0ffffffffff ffffffffffff 08fe 00 $ + +# parse_h4 +packet 1 ffffffffffff ffffffffffff 08ff 00 +expect 3 f0ffffffffff ffffffffffff 08ff 00 $ + +# parse_h3 +packet 1 ffffffffffff ffffffffffff 0900 00 +expect 3 e8ffffffffff ffffffffffff 0900 00 $ + +# parse_h4 +packet 1 ffffffffffff ffffffffffff 0901 00 +expect 3 f0ffffffffff ffffffffffff 0901 00 $ + +# default +packet 1 ffffffffffff ffffffffffff 0902 00 +expect 3 e0ffffffffff ffffffffffff 0902 00 $ diff --git a/testdata/p4_16_samples/issue-2123-3-bmv2.p4 b/testdata/p4_16_samples/issue-2123-3-bmv2.p4 new file mode 100644 index 00000000000..348da0a3ed6 --- /dev/null +++ b/testdata/p4_16_samples/issue-2123-3-bmv2.p4 @@ -0,0 +1,156 @@ +/* + * Copyright 2020, MNK Labs & Consulting + * http://mnkcg.com + * + * 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 + +header ethernet_t { + bit<48> dstAddr; + bit<48> srcAddr; + bit<16> etherType; +} + +header h0_t { + bit<8> f0; +} + +header h1_t { + bit<8> f1; +} + +header h2_t { + bit<8> f2; +} + +header h3_t { + bit<8> f3; +} + +header h4_t { + bit<8> f4; +} + +struct metadata { +} + +struct headers { + ethernet_t ethernet; + h0_t h0; + h1_t h1; + h2_t h2; + h3_t h3; + h4_t h4; +} + +parser ParserImpl( + packet_in packet, + out headers hdr, + inout metadata meta, + inout standard_metadata_t standard_metadata) +{ + state start { + packet.extract(hdr.ethernet); + transition select(hdr.ethernet.srcAddr[7:0], hdr.ethernet.etherType) { + (0x61 .. 0x67, 0x0800 .. 0x0806): parse_h0; + (0x61 .. 0x67, 0x0901 .. 0x0902): parse_h1; + (0x77 .. 0x7b, 0x0801 .. 0x0806): parse_h2; + (0x77 .. 0x7b, 0x0a00 .. 0x0aaa): parse_h3; + ( _, 0x0a00 .. 0x0aaa): parse_h4; + default: accept; + } + } + state parse_h0 { + packet.extract(hdr.h0); + transition accept; + } + state parse_h1 { + packet.extract(hdr.h1); + transition accept; + } + state parse_h2 { + packet.extract(hdr.h2); + transition accept; + } + state parse_h3 { + packet.extract(hdr.h3); + transition accept; + } + state parse_h4 { + packet.extract(hdr.h4); + transition accept; + } +} + +control ingress( + inout headers hdr, + inout metadata meta, + inout standard_metadata_t standard_metadata) +{ + apply { + // Overwrite some bits of one of the header fields so that in + // the STF test we can match on the output packet contents and + // know which case was taken in the select expression in the + // parser. + hdr.ethernet.dstAddr[44:44] = hdr.h4.isValid() ? 1w1 : 0; + hdr.ethernet.dstAddr[43:43] = hdr.h3.isValid() ? 1w1 : 0; + hdr.ethernet.dstAddr[42:42] = hdr.h2.isValid() ? 1w1 : 0; + hdr.ethernet.dstAddr[41:41] = hdr.h1.isValid() ? 1w1 : 0; + hdr.ethernet.dstAddr[40:40] = hdr.h0.isValid() ? 1w1 : 0; + + standard_metadata.egress_spec = 3; + } +} + +control egress( + inout headers hdr, + inout metadata meta, + inout standard_metadata_t standard_metadata) +{ + apply { + } +} + +control DeparserImpl( + packet_out packet, + in headers hdr) +{ + apply { + packet.emit(hdr.ethernet); + packet.emit(hdr.h0); + packet.emit(hdr.h1); + packet.emit(hdr.h2); + packet.emit(hdr.h3); + packet.emit(hdr.h4); + } +} + +control verifyChecksum(inout headers hdr, inout metadata meta) { + apply { } +} + +control computeChecksum(inout headers hdr, inout metadata meta) { + apply { } +} + +V1Switch( + ParserImpl(), + verifyChecksum(), + ingress(), + egress(), + computeChecksum(), + DeparserImpl()) +main; diff --git a/testdata/p4_16_samples/issue-2123-3-bmv2.stf b/testdata/p4_16_samples/issue-2123-3-bmv2.stf new file mode 100644 index 00000000000..caeee1c4a67 --- /dev/null +++ b/testdata/p4_16_samples/issue-2123-3-bmv2.stf @@ -0,0 +1,83 @@ +# For pairs of fields, I will only do all four "corners" and 8 "just +# outside the corners" values in the tests for one of the cases of the +# select expression. I lack the patience to do that for all of the +# cases, nor do I care to write a program to do that for me right now. + +# Recall that another good way to verify that the compiler is +# producing the correct code is to examine the P4_16 code output from +# the last mid end pass of the compiler, and check that by hand. + +# go to parse_h0 +packet 1 ffffffffffff ffffffffff61 0800 00 +expect 3 e1ffffffffff ffffffffff61 0800 00 $ + +packet 1 ffffffffffff ffffffffff61 0806 00 +expect 3 e1ffffffffff ffffffffff61 0806 00 $ + +packet 1 ffffffffffff ffffffffff67 0800 00 +expect 3 e1ffffffffff ffffffffff67 0800 00 $ + +packet 1 ffffffffffff ffffffffff67 0806 00 +expect 3 e1ffffffffff ffffffffff67 0806 00 $ + +# Just outside of the four corners of parse_h0, all of which should +# match the default case of the select expression. + +packet 1 ffffffffffff ffffffffff60 0800 00 +expect 3 e0ffffffffff ffffffffff60 0800 00 $ + +packet 1 ffffffffffff ffffffffff60 0806 00 +expect 3 e0ffffffffff ffffffffff60 0806 00 $ + +packet 1 ffffffffffff ffffffffff68 0800 00 +expect 3 e0ffffffffff ffffffffff68 0800 00 $ + +packet 1 ffffffffffff ffffffffff68 0806 00 +expect 3 e0ffffffffff ffffffffff68 0806 00 $ + +packet 1 ffffffffffff ffffffffff61 07ff 00 +expect 3 e0ffffffffff ffffffffff61 07ff 00 $ + +packet 1 ffffffffffff ffffffffff67 07ff 00 +expect 3 e0ffffffffff ffffffffff67 07ff 00 $ + +packet 1 ffffffffffff ffffffffff61 0807 00 +expect 3 e0ffffffffff ffffffffff61 0807 00 $ + +packet 1 ffffffffffff ffffffffff67 0807 00 +expect 3 e0ffffffffff ffffffffff67 0807 00 $ + +# These should match case parse_h1 +packet 1 ffffffffffff ffffffffff61 0901 00 +expect 3 e2ffffffffff ffffffffff61 0901 00 $ + +packet 1 ffffffffffff ffffffffff67 0902 00 +expect 3 e2ffffffffff ffffffffff67 0902 00 $ + +# default +packet 1 ffffffffffff ffffffffff61 0900 00 +expect 3 e0ffffffffff ffffffffff61 0900 00 $ + +packet 1 ffffffffffff ffffffffff67 0903 00 +expect 3 e0ffffffffff ffffffffff67 0903 00 $ + +# parse_h2 +packet 1 ffffffffffff ffffffffff7b 0804 00 +expect 3 e4ffffffffff ffffffffff7b 0804 00 $ + +packet 1 ffffffffffff ffffffffff77 0803 00 +expect 3 e4ffffffffff ffffffffff77 0803 00 $ + +# parse_h3 +packet 1 ffffffffffff ffffffffff79 0a23 00 +expect 3 e8ffffffffff ffffffffff79 0a23 00 $ + +packet 1 ffffffffffff ffffffffff7a 0a99 00 +expect 3 e8ffffffffff ffffffffff7a 0a99 00 $ + +# parse_h4 +packet 1 ffffffffffff ffffffffff00 0a11 00 +expect 3 f0ffffffffff ffffffffff00 0a11 00 $ + +packet 1 ffffffffffff ffffffffffff 0a88 00 +expect 3 f0ffffffffff ffffffffffff 0a88 00 $ diff --git a/testdata/p4_16_samples/issue-2123.p4 b/testdata/p4_16_samples/issue-2123.p4 new file mode 100644 index 00000000000..74f70e39f99 --- /dev/null +++ b/testdata/p4_16_samples/issue-2123.p4 @@ -0,0 +1,231 @@ +/* +* Copyright 2020, MNK Labs & Consulting +* http://mnkcg.com +* +* 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 + +struct ingress_metadata_t { + bit<12> vrf; + bit<16> bd; + bit<16> nexthop_index; +} + +header ethernet_t { + bit<48> dstAddr; + bit<48> srcAddr; + bit<16> etherType; +} + +header ipv4_t { + bit<4> version; + bit<4> ihl; + bit<8> diffserv; + bit<16> totalLen; + bit<16> identification; + bit<3> flags; + bit<13> fragOffset; + bit<8> ttl; + bit<8> protocol; + bit<16> hdrChecksum; + bit<32> srcAddr; + bit<32> dstAddr; +} + +struct metadata { + ingress_metadata_t ingress_metadata; +} + +struct headers { + ethernet_t ethernet; + ipv4_t ipv4; +} + +parser ParserImpl(packet_in packet, out headers hdr, inout metadata meta, inout standard_metadata_t standard_metadata) { + state parse_ethernet { + packet.extract(hdr = hdr.ethernet); + + transition select(hdr.ethernet.etherType, hdr.ethernet.srcAddr[7:0], hdr.ethernet.dstAddr[7:0]) { + // Test three ranges for cartesian product. + (0x0800 .. 0x0806, 0x08 .. 0x11, 0x08 .. 0x10): parse_ipv4; + // Test a constant, range, and ternary op in one keyset. + (0x0800, 0x08 .. 0x10, 0x06 &&& 0x11): parse_ipv4; + default: accept; + } + } + state parse_ipv4 { + packet.extract(hdr = hdr.ipv4); + transition select(hdr.ipv4.ihl, hdr.ipv4.protocol) { + // Cases added to test if new code does not mess up exisitng + // cases for constants keyset. + (4w0x5, 8w0x1): parse_icmp; + (4w0x5, 8w0x6): parse_tcp; + (4w0x5, 8w0x11): parse_udp; + (_, _): accept; } + } + state parse_icmp { + transition accept; + } + state parse_tcp { + transition accept; + } + state parse_udp { + transition accept; + } + + state parse_x { + transition accept; + } + state start { + transition parse_ethernet; + } +} + +control egress(inout headers hdr, inout metadata meta, inout standard_metadata_t standard_metadata) { + action on_miss() { + } + action rewrite_src_dst_mac(bit<48> smac, bit<48> dmac) { + hdr.ethernet.srcAddr = smac; + hdr.ethernet.dstAddr = dmac; + } + table rewrite_mac { + actions = { + on_miss; + rewrite_src_dst_mac; + } + key = { + meta.ingress_metadata.nexthop_index: exact; + } + size = 32768; + } + apply { + rewrite_mac.apply(); + } +} + +control ingress(inout headers hdr, inout metadata meta, inout standard_metadata_t standard_metadata) { + action set_vrf(bit<12> vrf) { + meta.ingress_metadata.vrf = vrf; + } + action on_miss() { + } + action fib_hit_nexthop(bit<16> nexthop_index) { + meta.ingress_metadata.nexthop_index = nexthop_index; + hdr.ipv4.ttl = hdr.ipv4.ttl - 8w1; + } + action set_egress_details(bit<9> egress_spec) { + standard_metadata.egress_spec = egress_spec; + } + action set_bd(bit<16> bd) { + meta.ingress_metadata.bd = bd; + } + table bd { + actions = { + set_vrf; + } + key = { + meta.ingress_metadata.bd: exact; + } + size = 65536; + } + table ipv4_fib { + actions = { + on_miss; + fib_hit_nexthop; + } + key = { + meta.ingress_metadata.vrf: exact; + hdr.ipv4.dstAddr : exact; + } + size = 131072; + } + table ipv4_fib_lpm { + actions = { + on_miss; + fib_hit_nexthop; + } + key = { + meta.ingress_metadata.vrf: exact; + hdr.ipv4.dstAddr : lpm; + } + size = 16384; + } + table nexthop { + actions = { + on_miss; + set_egress_details; + } + key = { + meta.ingress_metadata.nexthop_index: exact; + } + size = 32768; + } + table port_mapping { + actions = { + set_bd; + } + key = { + standard_metadata.ingress_port: exact; + } + size = 32768; + } + apply { + if (hdr.ipv4.isValid()) { + port_mapping.apply(); + bd.apply(); + switch (ipv4_fib.apply().action_run) { + on_miss: { + ipv4_fib_lpm.apply(); + } + } + + nexthop.apply(); + } + } +} + +control DeparserImpl(packet_out packet, in headers hdr) { + apply { + packet.emit(hdr = hdr.ethernet); + packet.emit(hdr = hdr.ipv4); + } +} + +control verifyChecksum(inout headers hdr, inout metadata meta) { + apply { + verify_checksum( + data = { hdr.ipv4.version, hdr.ipv4.ihl, hdr.ipv4.diffserv, hdr.ipv4.totalLen, hdr.ipv4.identification, hdr.ipv4.flags, hdr.ipv4.fragOffset, hdr.ipv4.ttl, hdr.ipv4.protocol, hdr.ipv4.srcAddr, hdr.ipv4.dstAddr }, + checksum = hdr.ipv4.hdrChecksum, + condition = true, + algo = HashAlgorithm.csum16); + } +} + +control computeChecksum(inout headers hdr, inout metadata meta) { + apply { + update_checksum( + condition = true, + data = { hdr.ipv4.version, hdr.ipv4.ihl, hdr.ipv4.diffserv, hdr.ipv4.totalLen, hdr.ipv4.identification, hdr.ipv4.flags, hdr.ipv4.fragOffset, hdr.ipv4.ttl, hdr.ipv4.protocol, hdr.ipv4.srcAddr, hdr.ipv4.dstAddr }, + algo = HashAlgorithm.csum16, + checksum = hdr.ipv4.hdrChecksum); + } +} + +V1Switch(p = ParserImpl(), + ig = ingress(), + vr = verifyChecksum(), + eg = egress(), + ck = computeChecksum(), + dep = DeparserImpl()) main; diff --git a/testdata/p4_16_samples_outputs/issue-2123-2-bmv2-first.p4 b/testdata/p4_16_samples_outputs/issue-2123-2-bmv2-first.p4 new file mode 100644 index 00000000000..6eb804a59e9 --- /dev/null +++ b/testdata/p4_16_samples_outputs/issue-2123-2-bmv2-first.p4 @@ -0,0 +1,114 @@ +#include +#include + +header ethernet_t { + bit<48> dstAddr; + bit<48> srcAddr; + bit<16> etherType; +} + +header h0_t { + bit<8> f0; +} + +header h1_t { + bit<8> f1; +} + +header h2_t { + bit<8> f2; +} + +header h3_t { + bit<8> f3; +} + +header h4_t { + bit<8> f4; +} + +struct metadata { +} + +struct headers { + ethernet_t ethernet; + h0_t h0; + h1_t h1; + h2_t h2; + h3_t h3; + h4_t h4; +} + +parser ParserImpl(packet_in packet, out headers hdr, inout metadata meta, inout standard_metadata_t standard_metadata) { + state start { + packet.extract(hdr.ethernet); + transition select(hdr.ethernet.etherType) { + 16w0x800 .. 16w0x806: parse_h0; + 16w0x808: parse_h1; + 16w0xfff1 .. 16w0xfffe: parse_h2; + 16w0x900: parse_h3; + 16w0x8ff .. 16w0x901: parse_h4; + default: accept; + } + } + state parse_h0 { + packet.extract(hdr.h0); + transition accept; + } + state parse_h1 { + packet.extract(hdr.h1); + transition accept; + } + state parse_h2 { + packet.extract(hdr.h2); + transition accept; + } + state parse_h3 { + packet.extract(hdr.h3); + transition accept; + } + state parse_h4 { + packet.extract(hdr.h4); + transition accept; + } +} + +control ingress(inout headers hdr, inout metadata meta, inout standard_metadata_t standard_metadata) { + apply { + hdr.ethernet.dstAddr[44:44] = (hdr.h4.isValid() ? 1w1 : 1w0); + hdr.ethernet.dstAddr[43:43] = (hdr.h3.isValid() ? 1w1 : 1w0); + hdr.ethernet.dstAddr[42:42] = (hdr.h2.isValid() ? 1w1 : 1w0); + hdr.ethernet.dstAddr[41:41] = (hdr.h1.isValid() ? 1w1 : 1w0); + hdr.ethernet.dstAddr[40:40] = (hdr.h0.isValid() ? 1w1 : 1w0); + standard_metadata.egress_spec = 9w3; + } +} + +control egress(inout headers hdr, inout metadata meta, inout standard_metadata_t standard_metadata) { + apply { + } +} + +control DeparserImpl(packet_out packet, in headers hdr) { + apply { + packet.emit(hdr.ethernet); + packet.emit(hdr.h0); + packet.emit(hdr.h1); + packet.emit(hdr.h2); + packet.emit(hdr.h3); + packet.emit(hdr.h4); + } +} + +control verifyChecksum(inout headers hdr, inout metadata meta) { + apply { + } +} + +control computeChecksum(inout headers hdr, inout metadata meta) { + apply { + } +} + +V1Switch(ParserImpl(), verifyChecksum(), ingress(), egress(), computeChecksum(), DeparserImpl()) main; + diff --git a/testdata/p4_16_samples_outputs/issue-2123-2-bmv2-frontend.p4 b/testdata/p4_16_samples_outputs/issue-2123-2-bmv2-frontend.p4 new file mode 100644 index 00000000000..5cf6ed0bf1b --- /dev/null +++ b/testdata/p4_16_samples_outputs/issue-2123-2-bmv2-frontend.p4 @@ -0,0 +1,144 @@ +#include +#include + +header ethernet_t { + bit<48> dstAddr; + bit<48> srcAddr; + bit<16> etherType; +} + +header h0_t { + bit<8> f0; +} + +header h1_t { + bit<8> f1; +} + +header h2_t { + bit<8> f2; +} + +header h3_t { + bit<8> f3; +} + +header h4_t { + bit<8> f4; +} + +struct metadata { +} + +struct headers { + ethernet_t ethernet; + h0_t h0; + h1_t h1; + h2_t h2; + h3_t h3; + h4_t h4; +} + +parser ParserImpl(packet_in packet, out headers hdr, inout metadata meta, inout standard_metadata_t standard_metadata) { + state start { + packet.extract(hdr.ethernet); + transition select(hdr.ethernet.etherType) { + 16w0x800 .. 16w0x806: parse_h0; + 16w0x808: parse_h1; + 16w0xfff1 .. 16w0xfffe: parse_h2; + 16w0x900: parse_h3; + 16w0x8ff .. 16w0x901: parse_h4; + default: accept; + } + } + state parse_h0 { + packet.extract(hdr.h0); + transition accept; + } + state parse_h1 { + packet.extract(hdr.h1); + transition accept; + } + state parse_h2 { + packet.extract(hdr.h2); + transition accept; + } + state parse_h3 { + packet.extract(hdr.h3); + transition accept; + } + state parse_h4 { + packet.extract(hdr.h4); + transition accept; + } +} + +control ingress(inout headers hdr, inout metadata meta, inout standard_metadata_t standard_metadata) { + bit<1> tmp; + bit<1> tmp_0; + bit<1> tmp_1; + bit<1> tmp_2; + bit<1> tmp_3; + apply { + if (hdr.h4.isValid()) { + tmp = 1w1; + } else { + tmp = 1w0; + } + hdr.ethernet.dstAddr[44:44] = tmp; + if (hdr.h3.isValid()) { + tmp_0 = 1w1; + } else { + tmp_0 = 1w0; + } + hdr.ethernet.dstAddr[43:43] = tmp_0; + if (hdr.h2.isValid()) { + tmp_1 = 1w1; + } else { + tmp_1 = 1w0; + } + hdr.ethernet.dstAddr[42:42] = tmp_1; + if (hdr.h1.isValid()) { + tmp_2 = 1w1; + } else { + tmp_2 = 1w0; + } + hdr.ethernet.dstAddr[41:41] = tmp_2; + if (hdr.h0.isValid()) { + tmp_3 = 1w1; + } else { + tmp_3 = 1w0; + } + hdr.ethernet.dstAddr[40:40] = tmp_3; + standard_metadata.egress_spec = 9w3; + } +} + +control egress(inout headers hdr, inout metadata meta, inout standard_metadata_t standard_metadata) { + apply { + } +} + +control DeparserImpl(packet_out packet, in headers hdr) { + apply { + packet.emit(hdr.ethernet); + packet.emit(hdr.h0); + packet.emit(hdr.h1); + packet.emit(hdr.h2); + packet.emit(hdr.h3); + packet.emit(hdr.h4); + } +} + +control verifyChecksum(inout headers hdr, inout metadata meta) { + apply { + } +} + +control computeChecksum(inout headers hdr, inout metadata meta) { + apply { + } +} + +V1Switch(ParserImpl(), verifyChecksum(), ingress(), egress(), computeChecksum(), DeparserImpl()) main; + diff --git a/testdata/p4_16_samples_outputs/issue-2123-2-bmv2-midend.p4 b/testdata/p4_16_samples_outputs/issue-2123-2-bmv2-midend.p4 new file mode 100644 index 00000000000..146683e88ee --- /dev/null +++ b/testdata/p4_16_samples_outputs/issue-2123-2-bmv2-midend.p4 @@ -0,0 +1,287 @@ +#include +#include + +header ethernet_t { + bit<48> dstAddr; + bit<48> srcAddr; + bit<16> etherType; +} + +header h0_t { + bit<8> f0; +} + +header h1_t { + bit<8> f1; +} + +header h2_t { + bit<8> f2; +} + +header h3_t { + bit<8> f3; +} + +header h4_t { + bit<8> f4; +} + +struct metadata { +} + +struct headers { + ethernet_t ethernet; + h0_t h0; + h1_t h1; + h2_t h2; + h3_t h3; + h4_t h4; +} + +parser ParserImpl(packet_in packet, out headers hdr, inout metadata meta, inout standard_metadata_t standard_metadata) { + state start { + packet.extract(hdr.ethernet); + transition select(hdr.ethernet.etherType) { + 16w0x800 &&& 16w0xfffc: parse_h0; + 16w0x804 &&& 16w0xfffe: parse_h0; + 16w0x806 &&& 16w0xffff: parse_h0; + 16w0x808: parse_h1; + 16w0xfff1 &&& 16w0xffff: parse_h2; + 16w0xfff2 &&& 16w0xfffe: parse_h2; + 16w0xfff4 &&& 16w0xfffc: parse_h2; + 16w0xfff8 &&& 16w0xfffc: parse_h2; + 16w0xfffc &&& 16w0xfffe: parse_h2; + 16w0xfffe &&& 16w0xffff: parse_h2; + 16w0x900: parse_h3; + 16w0x8ff &&& 16w0xffff: parse_h4; + 16w0x900 &&& 16w0xfffe: parse_h4; + default: accept; + } + } + state parse_h0 { + packet.extract(hdr.h0); + transition accept; + } + state parse_h1 { + packet.extract(hdr.h1); + transition accept; + } + state parse_h2 { + packet.extract(hdr.h2); + transition accept; + } + state parse_h3 { + packet.extract(hdr.h3); + transition accept; + } + state parse_h4 { + packet.extract(hdr.h4); + transition accept; + } +} + +control ingress(inout headers hdr, inout metadata meta, inout standard_metadata_t standard_metadata) { + bit<1> tmp; + bit<1> tmp_0; + bit<1> tmp_1; + bit<1> tmp_2; + bit<1> tmp_3; + @hidden action issue21232bmv2l108() { + tmp = 1w1; + } + @hidden action issue21232bmv2l108_0() { + tmp = 1w0; + } + @hidden action issue21232bmv2l109() { + tmp_0 = 1w1; + } + @hidden action issue21232bmv2l109_0() { + tmp_0 = 1w0; + } + @hidden action issue21232bmv2l108_1() { + hdr.ethernet.dstAddr[44:44] = tmp; + } + @hidden action issue21232bmv2l110() { + tmp_1 = 1w1; + } + @hidden action issue21232bmv2l110_0() { + tmp_1 = 1w0; + } + @hidden action issue21232bmv2l109_1() { + hdr.ethernet.dstAddr[43:43] = tmp_0; + } + @hidden action issue21232bmv2l111() { + tmp_2 = 1w1; + } + @hidden action issue21232bmv2l111_0() { + tmp_2 = 1w0; + } + @hidden action issue21232bmv2l110_1() { + hdr.ethernet.dstAddr[42:42] = tmp_1; + } + @hidden action issue21232bmv2l112() { + tmp_3 = 1w1; + } + @hidden action issue21232bmv2l112_0() { + tmp_3 = 1w0; + } + @hidden action issue21232bmv2l111_1() { + hdr.ethernet.dstAddr[41:41] = tmp_2; + } + @hidden action issue21232bmv2l112_1() { + hdr.ethernet.dstAddr[40:40] = tmp_3; + standard_metadata.egress_spec = 9w3; + } + @hidden table tbl_issue21232bmv2l108 { + actions = { + issue21232bmv2l108(); + } + const default_action = issue21232bmv2l108(); + } + @hidden table tbl_issue21232bmv2l108_0 { + actions = { + issue21232bmv2l108_0(); + } + const default_action = issue21232bmv2l108_0(); + } + @hidden table tbl_issue21232bmv2l108_1 { + actions = { + issue21232bmv2l108_1(); + } + const default_action = issue21232bmv2l108_1(); + } + @hidden table tbl_issue21232bmv2l109 { + actions = { + issue21232bmv2l109(); + } + const default_action = issue21232bmv2l109(); + } + @hidden table tbl_issue21232bmv2l109_0 { + actions = { + issue21232bmv2l109_0(); + } + const default_action = issue21232bmv2l109_0(); + } + @hidden table tbl_issue21232bmv2l109_1 { + actions = { + issue21232bmv2l109_1(); + } + const default_action = issue21232bmv2l109_1(); + } + @hidden table tbl_issue21232bmv2l110 { + actions = { + issue21232bmv2l110(); + } + const default_action = issue21232bmv2l110(); + } + @hidden table tbl_issue21232bmv2l110_0 { + actions = { + issue21232bmv2l110_0(); + } + const default_action = issue21232bmv2l110_0(); + } + @hidden table tbl_issue21232bmv2l110_1 { + actions = { + issue21232bmv2l110_1(); + } + const default_action = issue21232bmv2l110_1(); + } + @hidden table tbl_issue21232bmv2l111 { + actions = { + issue21232bmv2l111(); + } + const default_action = issue21232bmv2l111(); + } + @hidden table tbl_issue21232bmv2l111_0 { + actions = { + issue21232bmv2l111_0(); + } + const default_action = issue21232bmv2l111_0(); + } + @hidden table tbl_issue21232bmv2l111_1 { + actions = { + issue21232bmv2l111_1(); + } + const default_action = issue21232bmv2l111_1(); + } + @hidden table tbl_issue21232bmv2l112 { + actions = { + issue21232bmv2l112(); + } + const default_action = issue21232bmv2l112(); + } + @hidden table tbl_issue21232bmv2l112_0 { + actions = { + issue21232bmv2l112_0(); + } + const default_action = issue21232bmv2l112_0(); + } + @hidden table tbl_issue21232bmv2l112_1 { + actions = { + issue21232bmv2l112_1(); + } + const default_action = issue21232bmv2l112_1(); + } + apply { + if (hdr.h4.isValid()) { + tbl_issue21232bmv2l108.apply(); + } else { + tbl_issue21232bmv2l108_0.apply(); + } + tbl_issue21232bmv2l108_1.apply(); + if (hdr.h3.isValid()) { + tbl_issue21232bmv2l109.apply(); + } else { + tbl_issue21232bmv2l109_0.apply(); + } + tbl_issue21232bmv2l109_1.apply(); + if (hdr.h2.isValid()) { + tbl_issue21232bmv2l110.apply(); + } else { + tbl_issue21232bmv2l110_0.apply(); + } + tbl_issue21232bmv2l110_1.apply(); + if (hdr.h1.isValid()) { + tbl_issue21232bmv2l111.apply(); + } else { + tbl_issue21232bmv2l111_0.apply(); + } + tbl_issue21232bmv2l111_1.apply(); + if (hdr.h0.isValid()) { + tbl_issue21232bmv2l112.apply(); + } else { + tbl_issue21232bmv2l112_0.apply(); + } + tbl_issue21232bmv2l112_1.apply(); + } +} + +control egress(inout headers hdr, inout metadata meta, inout standard_metadata_t standard_metadata) { + apply { + } +} + +control DeparserImpl(packet_out packet, in headers hdr) { + apply { + packet.emit(hdr.ethernet); + packet.emit(hdr.h0); + packet.emit(hdr.h1); + packet.emit(hdr.h2); + packet.emit(hdr.h3); + packet.emit(hdr.h4); + } +} + +control verifyChecksum(inout headers hdr, inout metadata meta) { + apply { + } +} + +control computeChecksum(inout headers hdr, inout metadata meta) { + apply { + } +} + +V1Switch(ParserImpl(), verifyChecksum(), ingress(), egress(), computeChecksum(), DeparserImpl()) main; + diff --git a/testdata/p4_16_samples_outputs/issue-2123-2-bmv2.p4 b/testdata/p4_16_samples_outputs/issue-2123-2-bmv2.p4 new file mode 100644 index 00000000000..021fa93e6b8 --- /dev/null +++ b/testdata/p4_16_samples_outputs/issue-2123-2-bmv2.p4 @@ -0,0 +1,114 @@ +#include +#include + +header ethernet_t { + bit<48> dstAddr; + bit<48> srcAddr; + bit<16> etherType; +} + +header h0_t { + bit<8> f0; +} + +header h1_t { + bit<8> f1; +} + +header h2_t { + bit<8> f2; +} + +header h3_t { + bit<8> f3; +} + +header h4_t { + bit<8> f4; +} + +struct metadata { +} + +struct headers { + ethernet_t ethernet; + h0_t h0; + h1_t h1; + h2_t h2; + h3_t h3; + h4_t h4; +} + +parser ParserImpl(packet_in packet, out headers hdr, inout metadata meta, inout standard_metadata_t standard_metadata) { + state start { + packet.extract(hdr.ethernet); + transition select(hdr.ethernet.etherType) { + 0x800 .. 0x806: parse_h0; + 0x808: parse_h1; + 0xfff1 .. 0xfffe: parse_h2; + 0x900: parse_h3; + 0x8ff .. 0x901: parse_h4; + default: accept; + } + } + state parse_h0 { + packet.extract(hdr.h0); + transition accept; + } + state parse_h1 { + packet.extract(hdr.h1); + transition accept; + } + state parse_h2 { + packet.extract(hdr.h2); + transition accept; + } + state parse_h3 { + packet.extract(hdr.h3); + transition accept; + } + state parse_h4 { + packet.extract(hdr.h4); + transition accept; + } +} + +control ingress(inout headers hdr, inout metadata meta, inout standard_metadata_t standard_metadata) { + apply { + hdr.ethernet.dstAddr[44:44] = (hdr.h4.isValid() ? 1w1 : 0); + hdr.ethernet.dstAddr[43:43] = (hdr.h3.isValid() ? 1w1 : 0); + hdr.ethernet.dstAddr[42:42] = (hdr.h2.isValid() ? 1w1 : 0); + hdr.ethernet.dstAddr[41:41] = (hdr.h1.isValid() ? 1w1 : 0); + hdr.ethernet.dstAddr[40:40] = (hdr.h0.isValid() ? 1w1 : 0); + standard_metadata.egress_spec = 3; + } +} + +control egress(inout headers hdr, inout metadata meta, inout standard_metadata_t standard_metadata) { + apply { + } +} + +control DeparserImpl(packet_out packet, in headers hdr) { + apply { + packet.emit(hdr.ethernet); + packet.emit(hdr.h0); + packet.emit(hdr.h1); + packet.emit(hdr.h2); + packet.emit(hdr.h3); + packet.emit(hdr.h4); + } +} + +control verifyChecksum(inout headers hdr, inout metadata meta) { + apply { + } +} + +control computeChecksum(inout headers hdr, inout metadata meta) { + apply { + } +} + +V1Switch(ParserImpl(), verifyChecksum(), ingress(), egress(), computeChecksum(), DeparserImpl()) main; + diff --git a/testdata/p4_16_samples_outputs/issue-2123-2-bmv2.p4-stderr b/testdata/p4_16_samples_outputs/issue-2123-2-bmv2.p4-stderr new file mode 100644 index 00000000000..e69de29bb2d diff --git a/testdata/p4_16_samples_outputs/issue-2123-2-bmv2.p4.entries.txt b/testdata/p4_16_samples_outputs/issue-2123-2-bmv2.p4.entries.txt new file mode 100644 index 00000000000..e69de29bb2d diff --git a/testdata/p4_16_samples_outputs/issue-2123-2-bmv2.p4.p4info.txt b/testdata/p4_16_samples_outputs/issue-2123-2-bmv2.p4.p4info.txt new file mode 100644 index 00000000000..9ec92493e4c --- /dev/null +++ b/testdata/p4_16_samples_outputs/issue-2123-2-bmv2.p4.p4info.txt @@ -0,0 +1,3 @@ +pkg_info { + arch: "v1model" +} diff --git a/testdata/p4_16_samples_outputs/issue-2123-3-bmv2-first.p4 b/testdata/p4_16_samples_outputs/issue-2123-3-bmv2-first.p4 new file mode 100644 index 00000000000..6a62e1bdc84 --- /dev/null +++ b/testdata/p4_16_samples_outputs/issue-2123-3-bmv2-first.p4 @@ -0,0 +1,114 @@ +#include +#include + +header ethernet_t { + bit<48> dstAddr; + bit<48> srcAddr; + bit<16> etherType; +} + +header h0_t { + bit<8> f0; +} + +header h1_t { + bit<8> f1; +} + +header h2_t { + bit<8> f2; +} + +header h3_t { + bit<8> f3; +} + +header h4_t { + bit<8> f4; +} + +struct metadata { +} + +struct headers { + ethernet_t ethernet; + h0_t h0; + h1_t h1; + h2_t h2; + h3_t h3; + h4_t h4; +} + +parser ParserImpl(packet_in packet, out headers hdr, inout metadata meta, inout standard_metadata_t standard_metadata) { + state start { + packet.extract(hdr.ethernet); + transition select(hdr.ethernet.srcAddr[7:0], hdr.ethernet.etherType) { + (8w0x61 .. 8w0x67, 16w0x800 .. 16w0x806): parse_h0; + (8w0x61 .. 8w0x67, 16w0x901 .. 16w0x902): parse_h1; + (8w0x77 .. 8w0x7b, 16w0x801 .. 16w0x806): parse_h2; + (8w0x77 .. 8w0x7b, 16w0xa00 .. 16w0xaaa): parse_h3; + (default, 16w0xa00 .. 16w0xaaa): parse_h4; + default: accept; + } + } + state parse_h0 { + packet.extract(hdr.h0); + transition accept; + } + state parse_h1 { + packet.extract(hdr.h1); + transition accept; + } + state parse_h2 { + packet.extract(hdr.h2); + transition accept; + } + state parse_h3 { + packet.extract(hdr.h3); + transition accept; + } + state parse_h4 { + packet.extract(hdr.h4); + transition accept; + } +} + +control ingress(inout headers hdr, inout metadata meta, inout standard_metadata_t standard_metadata) { + apply { + hdr.ethernet.dstAddr[44:44] = (hdr.h4.isValid() ? 1w1 : 1w0); + hdr.ethernet.dstAddr[43:43] = (hdr.h3.isValid() ? 1w1 : 1w0); + hdr.ethernet.dstAddr[42:42] = (hdr.h2.isValid() ? 1w1 : 1w0); + hdr.ethernet.dstAddr[41:41] = (hdr.h1.isValid() ? 1w1 : 1w0); + hdr.ethernet.dstAddr[40:40] = (hdr.h0.isValid() ? 1w1 : 1w0); + standard_metadata.egress_spec = 9w3; + } +} + +control egress(inout headers hdr, inout metadata meta, inout standard_metadata_t standard_metadata) { + apply { + } +} + +control DeparserImpl(packet_out packet, in headers hdr) { + apply { + packet.emit(hdr.ethernet); + packet.emit(hdr.h0); + packet.emit(hdr.h1); + packet.emit(hdr.h2); + packet.emit(hdr.h3); + packet.emit(hdr.h4); + } +} + +control verifyChecksum(inout headers hdr, inout metadata meta) { + apply { + } +} + +control computeChecksum(inout headers hdr, inout metadata meta) { + apply { + } +} + +V1Switch(ParserImpl(), verifyChecksum(), ingress(), egress(), computeChecksum(), DeparserImpl()) main; + diff --git a/testdata/p4_16_samples_outputs/issue-2123-3-bmv2-frontend.p4 b/testdata/p4_16_samples_outputs/issue-2123-3-bmv2-frontend.p4 new file mode 100644 index 00000000000..592e0c79194 --- /dev/null +++ b/testdata/p4_16_samples_outputs/issue-2123-3-bmv2-frontend.p4 @@ -0,0 +1,144 @@ +#include +#include + +header ethernet_t { + bit<48> dstAddr; + bit<48> srcAddr; + bit<16> etherType; +} + +header h0_t { + bit<8> f0; +} + +header h1_t { + bit<8> f1; +} + +header h2_t { + bit<8> f2; +} + +header h3_t { + bit<8> f3; +} + +header h4_t { + bit<8> f4; +} + +struct metadata { +} + +struct headers { + ethernet_t ethernet; + h0_t h0; + h1_t h1; + h2_t h2; + h3_t h3; + h4_t h4; +} + +parser ParserImpl(packet_in packet, out headers hdr, inout metadata meta, inout standard_metadata_t standard_metadata) { + state start { + packet.extract(hdr.ethernet); + transition select(hdr.ethernet.srcAddr[7:0], hdr.ethernet.etherType) { + (8w0x61 .. 8w0x67, 16w0x800 .. 16w0x806): parse_h0; + (8w0x61 .. 8w0x67, 16w0x901 .. 16w0x902): parse_h1; + (8w0x77 .. 8w0x7b, 16w0x801 .. 16w0x806): parse_h2; + (8w0x77 .. 8w0x7b, 16w0xa00 .. 16w0xaaa): parse_h3; + (default, 16w0xa00 .. 16w0xaaa): parse_h4; + default: accept; + } + } + state parse_h0 { + packet.extract(hdr.h0); + transition accept; + } + state parse_h1 { + packet.extract(hdr.h1); + transition accept; + } + state parse_h2 { + packet.extract(hdr.h2); + transition accept; + } + state parse_h3 { + packet.extract(hdr.h3); + transition accept; + } + state parse_h4 { + packet.extract(hdr.h4); + transition accept; + } +} + +control ingress(inout headers hdr, inout metadata meta, inout standard_metadata_t standard_metadata) { + bit<1> tmp; + bit<1> tmp_0; + bit<1> tmp_1; + bit<1> tmp_2; + bit<1> tmp_3; + apply { + if (hdr.h4.isValid()) { + tmp = 1w1; + } else { + tmp = 1w0; + } + hdr.ethernet.dstAddr[44:44] = tmp; + if (hdr.h3.isValid()) { + tmp_0 = 1w1; + } else { + tmp_0 = 1w0; + } + hdr.ethernet.dstAddr[43:43] = tmp_0; + if (hdr.h2.isValid()) { + tmp_1 = 1w1; + } else { + tmp_1 = 1w0; + } + hdr.ethernet.dstAddr[42:42] = tmp_1; + if (hdr.h1.isValid()) { + tmp_2 = 1w1; + } else { + tmp_2 = 1w0; + } + hdr.ethernet.dstAddr[41:41] = tmp_2; + if (hdr.h0.isValid()) { + tmp_3 = 1w1; + } else { + tmp_3 = 1w0; + } + hdr.ethernet.dstAddr[40:40] = tmp_3; + standard_metadata.egress_spec = 9w3; + } +} + +control egress(inout headers hdr, inout metadata meta, inout standard_metadata_t standard_metadata) { + apply { + } +} + +control DeparserImpl(packet_out packet, in headers hdr) { + apply { + packet.emit(hdr.ethernet); + packet.emit(hdr.h0); + packet.emit(hdr.h1); + packet.emit(hdr.h2); + packet.emit(hdr.h3); + packet.emit(hdr.h4); + } +} + +control verifyChecksum(inout headers hdr, inout metadata meta) { + apply { + } +} + +control computeChecksum(inout headers hdr, inout metadata meta) { + apply { + } +} + +V1Switch(ParserImpl(), verifyChecksum(), ingress(), egress(), computeChecksum(), DeparserImpl()) main; + diff --git a/testdata/p4_16_samples_outputs/issue-2123-3-bmv2-midend.p4 b/testdata/p4_16_samples_outputs/issue-2123-3-bmv2-midend.p4 new file mode 100644 index 00000000000..88c193e882d --- /dev/null +++ b/testdata/p4_16_samples_outputs/issue-2123-3-bmv2-midend.p4 @@ -0,0 +1,312 @@ +#include +#include + +header ethernet_t { + bit<48> dstAddr; + bit<48> srcAddr; + bit<16> etherType; +} + +header h0_t { + bit<8> f0; +} + +header h1_t { + bit<8> f1; +} + +header h2_t { + bit<8> f2; +} + +header h3_t { + bit<8> f3; +} + +header h4_t { + bit<8> f4; +} + +struct metadata { +} + +struct headers { + ethernet_t ethernet; + h0_t h0; + h1_t h1; + h2_t h2; + h3_t h3; + h4_t h4; +} + +parser ParserImpl(packet_in packet, out headers hdr, inout metadata meta, inout standard_metadata_t standard_metadata) { + state start { + packet.extract(hdr.ethernet); + transition select(hdr.ethernet.srcAddr[7:0], hdr.ethernet.etherType) { + (8w0x61 &&& 8w0xff, 16w0x800 &&& 16w0xfffc): parse_h0; + (8w0x61 &&& 8w0xff, 16w0x804 &&& 16w0xfffe): parse_h0; + (8w0x61 &&& 8w0xff, 16w0x806 &&& 16w0xffff): parse_h0; + (8w0x62 &&& 8w0xfe, 16w0x800 &&& 16w0xfffc): parse_h0; + (8w0x62 &&& 8w0xfe, 16w0x804 &&& 16w0xfffe): parse_h0; + (8w0x62 &&& 8w0xfe, 16w0x806 &&& 16w0xffff): parse_h0; + (8w0x64 &&& 8w0xfc, 16w0x800 &&& 16w0xfffc): parse_h0; + (8w0x64 &&& 8w0xfc, 16w0x804 &&& 16w0xfffe): parse_h0; + (8w0x64 &&& 8w0xfc, 16w0x806 &&& 16w0xffff): parse_h0; + (8w0x61 &&& 8w0xff, 16w0x901 &&& 16w0xffff): parse_h1; + (8w0x61 &&& 8w0xff, 16w0x902 &&& 16w0xffff): parse_h1; + (8w0x62 &&& 8w0xfe, 16w0x901 &&& 16w0xffff): parse_h1; + (8w0x62 &&& 8w0xfe, 16w0x902 &&& 16w0xffff): parse_h1; + (8w0x64 &&& 8w0xfc, 16w0x901 &&& 16w0xffff): parse_h1; + (8w0x64 &&& 8w0xfc, 16w0x902 &&& 16w0xffff): parse_h1; + (8w0x77 &&& 8w0xff, 16w0x801 &&& 16w0xffff): parse_h2; + (8w0x77 &&& 8w0xff, 16w0x802 &&& 16w0xfffe): parse_h2; + (8w0x77 &&& 8w0xff, 16w0x804 &&& 16w0xfffe): parse_h2; + (8w0x77 &&& 8w0xff, 16w0x806 &&& 16w0xffff): parse_h2; + (8w0x78 &&& 8w0xfc, 16w0x801 &&& 16w0xffff): parse_h2; + (8w0x78 &&& 8w0xfc, 16w0x802 &&& 16w0xfffe): parse_h2; + (8w0x78 &&& 8w0xfc, 16w0x804 &&& 16w0xfffe): parse_h2; + (8w0x78 &&& 8w0xfc, 16w0x806 &&& 16w0xffff): parse_h2; + (8w0x77 &&& 8w0xff, 16w0xa00 &&& 16w0xff80): parse_h3; + (8w0x77 &&& 8w0xff, 16w0xa80 &&& 16w0xffe0): parse_h3; + (8w0x77 &&& 8w0xff, 16w0xaa0 &&& 16w0xfff8): parse_h3; + (8w0x77 &&& 8w0xff, 16w0xaa8 &&& 16w0xfffe): parse_h3; + (8w0x77 &&& 8w0xff, 16w0xaaa &&& 16w0xffff): parse_h3; + (8w0x78 &&& 8w0xfc, 16w0xa00 &&& 16w0xff80): parse_h3; + (8w0x78 &&& 8w0xfc, 16w0xa80 &&& 16w0xffe0): parse_h3; + (8w0x78 &&& 8w0xfc, 16w0xaa0 &&& 16w0xfff8): parse_h3; + (8w0x78 &&& 8w0xfc, 16w0xaa8 &&& 16w0xfffe): parse_h3; + (8w0x78 &&& 8w0xfc, 16w0xaaa &&& 16w0xffff): parse_h3; + (default, 16w0xa00 &&& 16w0xff80): parse_h4; + (default, 16w0xa80 &&& 16w0xffe0): parse_h4; + (default, 16w0xaa0 &&& 16w0xfff8): parse_h4; + (default, 16w0xaa8 &&& 16w0xfffe): parse_h4; + (default, 16w0xaaa &&& 16w0xffff): parse_h4; + default: accept; + } + } + state parse_h0 { + packet.extract(hdr.h0); + transition accept; + } + state parse_h1 { + packet.extract(hdr.h1); + transition accept; + } + state parse_h2 { + packet.extract(hdr.h2); + transition accept; + } + state parse_h3 { + packet.extract(hdr.h3); + transition accept; + } + state parse_h4 { + packet.extract(hdr.h4); + transition accept; + } +} + +control ingress(inout headers hdr, inout metadata meta, inout standard_metadata_t standard_metadata) { + bit<1> tmp; + bit<1> tmp_0; + bit<1> tmp_1; + bit<1> tmp_2; + bit<1> tmp_3; + @hidden action issue21233bmv2l108() { + tmp = 1w1; + } + @hidden action issue21233bmv2l108_0() { + tmp = 1w0; + } + @hidden action issue21233bmv2l109() { + tmp_0 = 1w1; + } + @hidden action issue21233bmv2l109_0() { + tmp_0 = 1w0; + } + @hidden action issue21233bmv2l108_1() { + hdr.ethernet.dstAddr[44:44] = tmp; + } + @hidden action issue21233bmv2l110() { + tmp_1 = 1w1; + } + @hidden action issue21233bmv2l110_0() { + tmp_1 = 1w0; + } + @hidden action issue21233bmv2l109_1() { + hdr.ethernet.dstAddr[43:43] = tmp_0; + } + @hidden action issue21233bmv2l111() { + tmp_2 = 1w1; + } + @hidden action issue21233bmv2l111_0() { + tmp_2 = 1w0; + } + @hidden action issue21233bmv2l110_1() { + hdr.ethernet.dstAddr[42:42] = tmp_1; + } + @hidden action issue21233bmv2l112() { + tmp_3 = 1w1; + } + @hidden action issue21233bmv2l112_0() { + tmp_3 = 1w0; + } + @hidden action issue21233bmv2l111_1() { + hdr.ethernet.dstAddr[41:41] = tmp_2; + } + @hidden action issue21233bmv2l112_1() { + hdr.ethernet.dstAddr[40:40] = tmp_3; + standard_metadata.egress_spec = 9w3; + } + @hidden table tbl_issue21233bmv2l108 { + actions = { + issue21233bmv2l108(); + } + const default_action = issue21233bmv2l108(); + } + @hidden table tbl_issue21233bmv2l108_0 { + actions = { + issue21233bmv2l108_0(); + } + const default_action = issue21233bmv2l108_0(); + } + @hidden table tbl_issue21233bmv2l108_1 { + actions = { + issue21233bmv2l108_1(); + } + const default_action = issue21233bmv2l108_1(); + } + @hidden table tbl_issue21233bmv2l109 { + actions = { + issue21233bmv2l109(); + } + const default_action = issue21233bmv2l109(); + } + @hidden table tbl_issue21233bmv2l109_0 { + actions = { + issue21233bmv2l109_0(); + } + const default_action = issue21233bmv2l109_0(); + } + @hidden table tbl_issue21233bmv2l109_1 { + actions = { + issue21233bmv2l109_1(); + } + const default_action = issue21233bmv2l109_1(); + } + @hidden table tbl_issue21233bmv2l110 { + actions = { + issue21233bmv2l110(); + } + const default_action = issue21233bmv2l110(); + } + @hidden table tbl_issue21233bmv2l110_0 { + actions = { + issue21233bmv2l110_0(); + } + const default_action = issue21233bmv2l110_0(); + } + @hidden table tbl_issue21233bmv2l110_1 { + actions = { + issue21233bmv2l110_1(); + } + const default_action = issue21233bmv2l110_1(); + } + @hidden table tbl_issue21233bmv2l111 { + actions = { + issue21233bmv2l111(); + } + const default_action = issue21233bmv2l111(); + } + @hidden table tbl_issue21233bmv2l111_0 { + actions = { + issue21233bmv2l111_0(); + } + const default_action = issue21233bmv2l111_0(); + } + @hidden table tbl_issue21233bmv2l111_1 { + actions = { + issue21233bmv2l111_1(); + } + const default_action = issue21233bmv2l111_1(); + } + @hidden table tbl_issue21233bmv2l112 { + actions = { + issue21233bmv2l112(); + } + const default_action = issue21233bmv2l112(); + } + @hidden table tbl_issue21233bmv2l112_0 { + actions = { + issue21233bmv2l112_0(); + } + const default_action = issue21233bmv2l112_0(); + } + @hidden table tbl_issue21233bmv2l112_1 { + actions = { + issue21233bmv2l112_1(); + } + const default_action = issue21233bmv2l112_1(); + } + apply { + if (hdr.h4.isValid()) { + tbl_issue21233bmv2l108.apply(); + } else { + tbl_issue21233bmv2l108_0.apply(); + } + tbl_issue21233bmv2l108_1.apply(); + if (hdr.h3.isValid()) { + tbl_issue21233bmv2l109.apply(); + } else { + tbl_issue21233bmv2l109_0.apply(); + } + tbl_issue21233bmv2l109_1.apply(); + if (hdr.h2.isValid()) { + tbl_issue21233bmv2l110.apply(); + } else { + tbl_issue21233bmv2l110_0.apply(); + } + tbl_issue21233bmv2l110_1.apply(); + if (hdr.h1.isValid()) { + tbl_issue21233bmv2l111.apply(); + } else { + tbl_issue21233bmv2l111_0.apply(); + } + tbl_issue21233bmv2l111_1.apply(); + if (hdr.h0.isValid()) { + tbl_issue21233bmv2l112.apply(); + } else { + tbl_issue21233bmv2l112_0.apply(); + } + tbl_issue21233bmv2l112_1.apply(); + } +} + +control egress(inout headers hdr, inout metadata meta, inout standard_metadata_t standard_metadata) { + apply { + } +} + +control DeparserImpl(packet_out packet, in headers hdr) { + apply { + packet.emit(hdr.ethernet); + packet.emit(hdr.h0); + packet.emit(hdr.h1); + packet.emit(hdr.h2); + packet.emit(hdr.h3); + packet.emit(hdr.h4); + } +} + +control verifyChecksum(inout headers hdr, inout metadata meta) { + apply { + } +} + +control computeChecksum(inout headers hdr, inout metadata meta) { + apply { + } +} + +V1Switch(ParserImpl(), verifyChecksum(), ingress(), egress(), computeChecksum(), DeparserImpl()) main; + diff --git a/testdata/p4_16_samples_outputs/issue-2123-3-bmv2.p4 b/testdata/p4_16_samples_outputs/issue-2123-3-bmv2.p4 new file mode 100644 index 00000000000..dbb4a82ed07 --- /dev/null +++ b/testdata/p4_16_samples_outputs/issue-2123-3-bmv2.p4 @@ -0,0 +1,114 @@ +#include +#include + +header ethernet_t { + bit<48> dstAddr; + bit<48> srcAddr; + bit<16> etherType; +} + +header h0_t { + bit<8> f0; +} + +header h1_t { + bit<8> f1; +} + +header h2_t { + bit<8> f2; +} + +header h3_t { + bit<8> f3; +} + +header h4_t { + bit<8> f4; +} + +struct metadata { +} + +struct headers { + ethernet_t ethernet; + h0_t h0; + h1_t h1; + h2_t h2; + h3_t h3; + h4_t h4; +} + +parser ParserImpl(packet_in packet, out headers hdr, inout metadata meta, inout standard_metadata_t standard_metadata) { + state start { + packet.extract(hdr.ethernet); + transition select(hdr.ethernet.srcAddr[7:0], hdr.ethernet.etherType) { + (0x61 .. 0x67, 0x800 .. 0x806): parse_h0; + (0x61 .. 0x67, 0x901 .. 0x902): parse_h1; + (0x77 .. 0x7b, 0x801 .. 0x806): parse_h2; + (0x77 .. 0x7b, 0xa00 .. 0xaaa): parse_h3; + (default, 0xa00 .. 0xaaa): parse_h4; + default: accept; + } + } + state parse_h0 { + packet.extract(hdr.h0); + transition accept; + } + state parse_h1 { + packet.extract(hdr.h1); + transition accept; + } + state parse_h2 { + packet.extract(hdr.h2); + transition accept; + } + state parse_h3 { + packet.extract(hdr.h3); + transition accept; + } + state parse_h4 { + packet.extract(hdr.h4); + transition accept; + } +} + +control ingress(inout headers hdr, inout metadata meta, inout standard_metadata_t standard_metadata) { + apply { + hdr.ethernet.dstAddr[44:44] = (hdr.h4.isValid() ? 1w1 : 0); + hdr.ethernet.dstAddr[43:43] = (hdr.h3.isValid() ? 1w1 : 0); + hdr.ethernet.dstAddr[42:42] = (hdr.h2.isValid() ? 1w1 : 0); + hdr.ethernet.dstAddr[41:41] = (hdr.h1.isValid() ? 1w1 : 0); + hdr.ethernet.dstAddr[40:40] = (hdr.h0.isValid() ? 1w1 : 0); + standard_metadata.egress_spec = 3; + } +} + +control egress(inout headers hdr, inout metadata meta, inout standard_metadata_t standard_metadata) { + apply { + } +} + +control DeparserImpl(packet_out packet, in headers hdr) { + apply { + packet.emit(hdr.ethernet); + packet.emit(hdr.h0); + packet.emit(hdr.h1); + packet.emit(hdr.h2); + packet.emit(hdr.h3); + packet.emit(hdr.h4); + } +} + +control verifyChecksum(inout headers hdr, inout metadata meta) { + apply { + } +} + +control computeChecksum(inout headers hdr, inout metadata meta) { + apply { + } +} + +V1Switch(ParserImpl(), verifyChecksum(), ingress(), egress(), computeChecksum(), DeparserImpl()) main; + diff --git a/testdata/p4_16_samples_outputs/issue-2123-3-bmv2.p4-stderr b/testdata/p4_16_samples_outputs/issue-2123-3-bmv2.p4-stderr new file mode 100644 index 00000000000..e69de29bb2d diff --git a/testdata/p4_16_samples_outputs/issue-2123-3-bmv2.p4.entries.txt b/testdata/p4_16_samples_outputs/issue-2123-3-bmv2.p4.entries.txt new file mode 100644 index 00000000000..e69de29bb2d diff --git a/testdata/p4_16_samples_outputs/issue-2123-3-bmv2.p4.p4info.txt b/testdata/p4_16_samples_outputs/issue-2123-3-bmv2.p4.p4info.txt new file mode 100644 index 00000000000..9ec92493e4c --- /dev/null +++ b/testdata/p4_16_samples_outputs/issue-2123-3-bmv2.p4.p4info.txt @@ -0,0 +1,3 @@ +pkg_info { + arch: "v1model" +} diff --git a/testdata/p4_16_samples_outputs/issue-2123-first.p4 b/testdata/p4_16_samples_outputs/issue-2123-first.p4 new file mode 100644 index 00000000000..ca305ee5195 --- /dev/null +++ b/testdata/p4_16_samples_outputs/issue-2123-first.p4 @@ -0,0 +1,210 @@ +#include +#include + +struct ingress_metadata_t { + bit<12> vrf; + bit<16> bd; + bit<16> nexthop_index; +} + +header ethernet_t { + bit<48> dstAddr; + bit<48> srcAddr; + bit<16> etherType; +} + +header ipv4_t { + bit<4> version; + bit<4> ihl; + bit<8> diffserv; + bit<16> totalLen; + bit<16> identification; + bit<3> flags; + bit<13> fragOffset; + bit<8> ttl; + bit<8> protocol; + bit<16> hdrChecksum; + bit<32> srcAddr; + bit<32> dstAddr; +} + +struct metadata { + ingress_metadata_t ingress_metadata; +} + +struct headers { + ethernet_t ethernet; + ipv4_t ipv4; +} + +parser ParserImpl(packet_in packet, out headers hdr, inout metadata meta, inout standard_metadata_t standard_metadata) { + state parse_ethernet { + packet.extract(hdr = hdr.ethernet); + transition select(hdr.ethernet.etherType, hdr.ethernet.srcAddr[7:0], hdr.ethernet.dstAddr[7:0]) { + (16w0x800 .. 16w0x806, 8w0x8 .. 8w0x11, 8w0x8 .. 8w0x10): parse_ipv4; + (16w0x800, 8w0x8 .. 8w0x10, 8w0x6 &&& 8w0x11): parse_ipv4; + default: accept; + } + } + state parse_ipv4 { + packet.extract(hdr = hdr.ipv4); + transition select(hdr.ipv4.ihl, hdr.ipv4.protocol) { + (4w0x5, 8w0x1): parse_icmp; + (4w0x5, 8w0x6): parse_tcp; + (4w0x5, 8w0x11): parse_udp; + (default, default): accept; + } + } + state parse_icmp { + transition accept; + } + state parse_tcp { + transition accept; + } + state parse_udp { + transition accept; + } + state parse_x { + transition accept; + } + state start { + transition parse_ethernet; + } +} + +control egress(inout headers hdr, inout metadata meta, inout standard_metadata_t standard_metadata) { + action on_miss() { + } + action rewrite_src_dst_mac(bit<48> smac, bit<48> dmac) { + hdr.ethernet.srcAddr = smac; + hdr.ethernet.dstAddr = dmac; + } + table rewrite_mac { + actions = { + on_miss(); + rewrite_src_dst_mac(); + @defaultonly NoAction(); + } + key = { + meta.ingress_metadata.nexthop_index: exact @name("meta.ingress_metadata.nexthop_index") ; + } + size = 32768; + default_action = NoAction(); + } + apply { + rewrite_mac.apply(); + } +} + +control ingress(inout headers hdr, inout metadata meta, inout standard_metadata_t standard_metadata) { + action set_vrf(bit<12> vrf) { + meta.ingress_metadata.vrf = vrf; + } + action on_miss() { + } + action fib_hit_nexthop(bit<16> nexthop_index) { + meta.ingress_metadata.nexthop_index = nexthop_index; + hdr.ipv4.ttl = hdr.ipv4.ttl + 8w255; + } + action set_egress_details(bit<9> egress_spec) { + standard_metadata.egress_spec = egress_spec; + } + action set_bd(bit<16> bd) { + meta.ingress_metadata.bd = bd; + } + table bd { + actions = { + set_vrf(); + @defaultonly NoAction(); + } + key = { + meta.ingress_metadata.bd: exact @name("meta.ingress_metadata.bd") ; + } + size = 65536; + default_action = NoAction(); + } + table ipv4_fib { + actions = { + on_miss(); + fib_hit_nexthop(); + @defaultonly NoAction(); + } + key = { + meta.ingress_metadata.vrf: exact @name("meta.ingress_metadata.vrf") ; + hdr.ipv4.dstAddr : exact @name("hdr.ipv4.dstAddr") ; + } + size = 131072; + default_action = NoAction(); + } + table ipv4_fib_lpm { + actions = { + on_miss(); + fib_hit_nexthop(); + @defaultonly NoAction(); + } + key = { + meta.ingress_metadata.vrf: exact @name("meta.ingress_metadata.vrf") ; + hdr.ipv4.dstAddr : lpm @name("hdr.ipv4.dstAddr") ; + } + size = 16384; + default_action = NoAction(); + } + table nexthop { + actions = { + on_miss(); + set_egress_details(); + @defaultonly NoAction(); + } + key = { + meta.ingress_metadata.nexthop_index: exact @name("meta.ingress_metadata.nexthop_index") ; + } + size = 32768; + default_action = NoAction(); + } + table port_mapping { + actions = { + set_bd(); + @defaultonly NoAction(); + } + key = { + standard_metadata.ingress_port: exact @name("standard_metadata.ingress_port") ; + } + size = 32768; + default_action = NoAction(); + } + apply { + if (hdr.ipv4.isValid()) { + port_mapping.apply(); + bd.apply(); + switch (ipv4_fib.apply().action_run) { + on_miss: { + ipv4_fib_lpm.apply(); + } + } + + nexthop.apply(); + } + } +} + +control DeparserImpl(packet_out packet, in headers hdr) { + apply { + packet.emit(hdr = hdr.ethernet); + packet.emit(hdr = hdr.ipv4); + } +} + +control verifyChecksum(inout headers hdr, inout metadata meta) { + apply { + verify_checksum, bit<4>, bit<8>, bit<16>, bit<16>, bit<3>, bit<13>, bit<8>, bit<8>, bit<32>, bit<32>>, bit<16>>(data = { hdr.ipv4.version, hdr.ipv4.ihl, hdr.ipv4.diffserv, hdr.ipv4.totalLen, hdr.ipv4.identification, hdr.ipv4.flags, hdr.ipv4.fragOffset, hdr.ipv4.ttl, hdr.ipv4.protocol, hdr.ipv4.srcAddr, hdr.ipv4.dstAddr }, checksum = hdr.ipv4.hdrChecksum, condition = true, algo = HashAlgorithm.csum16); + } +} + +control computeChecksum(inout headers hdr, inout metadata meta) { + apply { + update_checksum, bit<4>, bit<8>, bit<16>, bit<16>, bit<3>, bit<13>, bit<8>, bit<8>, bit<32>, bit<32>>, bit<16>>(condition = true, data = { hdr.ipv4.version, hdr.ipv4.ihl, hdr.ipv4.diffserv, hdr.ipv4.totalLen, hdr.ipv4.identification, hdr.ipv4.flags, hdr.ipv4.fragOffset, hdr.ipv4.ttl, hdr.ipv4.protocol, hdr.ipv4.srcAddr, hdr.ipv4.dstAddr }, algo = HashAlgorithm.csum16, checksum = hdr.ipv4.hdrChecksum); + } +} + +V1Switch(p = ParserImpl(), ig = ingress(), vr = verifyChecksum(), eg = egress(), ck = computeChecksum(), dep = DeparserImpl()) main; + diff --git a/testdata/p4_16_samples_outputs/issue-2123-frontend.p4 b/testdata/p4_16_samples_outputs/issue-2123-frontend.p4 new file mode 100644 index 00000000000..3c4f8d23349 --- /dev/null +++ b/testdata/p4_16_samples_outputs/issue-2123-frontend.p4 @@ -0,0 +1,224 @@ +#include +#include + +struct ingress_metadata_t { + bit<12> vrf; + bit<16> bd; + bit<16> nexthop_index; +} + +header ethernet_t { + bit<48> dstAddr; + bit<48> srcAddr; + bit<16> etherType; +} + +header ipv4_t { + bit<4> version; + bit<4> ihl; + bit<8> diffserv; + bit<16> totalLen; + bit<16> identification; + bit<3> flags; + bit<13> fragOffset; + bit<8> ttl; + bit<8> protocol; + bit<16> hdrChecksum; + bit<32> srcAddr; + bit<32> dstAddr; +} + +struct metadata { + ingress_metadata_t ingress_metadata; +} + +struct headers { + ethernet_t ethernet; + ipv4_t ipv4; +} + +parser ParserImpl(packet_in packet, out headers hdr, inout metadata meta, inout standard_metadata_t standard_metadata) { + state parse_ipv4 { + packet.extract(hdr = hdr.ipv4); + transition select(hdr.ipv4.ihl, hdr.ipv4.protocol) { + (4w0x5, 8w0x1): parse_icmp; + (4w0x5, 8w0x6): parse_tcp; + (4w0x5, 8w0x11): parse_udp; + (default, default): accept; + } + } + state parse_icmp { + transition accept; + } + state parse_tcp { + transition accept; + } + state parse_udp { + transition accept; + } + state start { + packet.extract(hdr = hdr.ethernet); + transition select(hdr.ethernet.etherType, hdr.ethernet.srcAddr[7:0], hdr.ethernet.dstAddr[7:0]) { + (16w0x800 .. 16w0x806, 8w0x8 .. 8w0x11, 8w0x8 .. 8w0x10): parse_ipv4; + (16w0x800, 8w0x8 .. 8w0x10, 8w0x6 &&& 8w0x11): parse_ipv4; + default: accept; + } + } +} + +control egress(inout headers hdr, inout metadata meta, inout standard_metadata_t standard_metadata) { + @name(".NoAction") action NoAction_0() { + } + @name("egress.on_miss") action on_miss() { + } + @name("egress.rewrite_src_dst_mac") action rewrite_src_dst_mac(bit<48> smac, bit<48> dmac) { + hdr.ethernet.srcAddr = smac; + hdr.ethernet.dstAddr = dmac; + } + @name("egress.rewrite_mac") table rewrite_mac_0 { + actions = { + on_miss(); + rewrite_src_dst_mac(); + @defaultonly NoAction_0(); + } + key = { + meta.ingress_metadata.nexthop_index: exact @name("meta.ingress_metadata.nexthop_index") ; + } + size = 32768; + default_action = NoAction_0(); + } + apply { + rewrite_mac_0.apply(); + } +} + +control ingress(inout headers hdr, inout metadata meta, inout standard_metadata_t standard_metadata) { + @name(".NoAction") action NoAction_1() { + } + @name(".NoAction") action NoAction_8() { + } + @name(".NoAction") action NoAction_9() { + } + @name(".NoAction") action NoAction_10() { + } + @name(".NoAction") action NoAction_11() { + } + @name("ingress.set_vrf") action set_vrf(bit<12> vrf) { + meta.ingress_metadata.vrf = vrf; + } + @name("ingress.on_miss") action on_miss_2() { + } + @name("ingress.on_miss") action on_miss_5() { + } + @name("ingress.on_miss") action on_miss_6() { + } + @name("ingress.fib_hit_nexthop") action fib_hit_nexthop(bit<16> nexthop_index) { + meta.ingress_metadata.nexthop_index = nexthop_index; + hdr.ipv4.ttl = hdr.ipv4.ttl + 8w255; + } + @name("ingress.fib_hit_nexthop") action fib_hit_nexthop_2(bit<16> nexthop_index) { + meta.ingress_metadata.nexthop_index = nexthop_index; + hdr.ipv4.ttl = hdr.ipv4.ttl + 8w255; + } + @name("ingress.set_egress_details") action set_egress_details(bit<9> egress_spec) { + standard_metadata.egress_spec = egress_spec; + } + @name("ingress.set_bd") action set_bd(bit<16> bd) { + meta.ingress_metadata.bd = bd; + } + @name("ingress.bd") table bd_0 { + actions = { + set_vrf(); + @defaultonly NoAction_1(); + } + key = { + meta.ingress_metadata.bd: exact @name("meta.ingress_metadata.bd") ; + } + size = 65536; + default_action = NoAction_1(); + } + @name("ingress.ipv4_fib") table ipv4_fib_0 { + actions = { + on_miss_2(); + fib_hit_nexthop(); + @defaultonly NoAction_8(); + } + key = { + meta.ingress_metadata.vrf: exact @name("meta.ingress_metadata.vrf") ; + hdr.ipv4.dstAddr : exact @name("hdr.ipv4.dstAddr") ; + } + size = 131072; + default_action = NoAction_8(); + } + @name("ingress.ipv4_fib_lpm") table ipv4_fib_lpm_0 { + actions = { + on_miss_5(); + fib_hit_nexthop_2(); + @defaultonly NoAction_9(); + } + key = { + meta.ingress_metadata.vrf: exact @name("meta.ingress_metadata.vrf") ; + hdr.ipv4.dstAddr : lpm @name("hdr.ipv4.dstAddr") ; + } + size = 16384; + default_action = NoAction_9(); + } + @name("ingress.nexthop") table nexthop_0 { + actions = { + on_miss_6(); + set_egress_details(); + @defaultonly NoAction_10(); + } + key = { + meta.ingress_metadata.nexthop_index: exact @name("meta.ingress_metadata.nexthop_index") ; + } + size = 32768; + default_action = NoAction_10(); + } + @name("ingress.port_mapping") table port_mapping_0 { + actions = { + set_bd(); + @defaultonly NoAction_11(); + } + key = { + standard_metadata.ingress_port: exact @name("standard_metadata.ingress_port") ; + } + size = 32768; + default_action = NoAction_11(); + } + apply { + if (hdr.ipv4.isValid()) { + port_mapping_0.apply(); + bd_0.apply(); + switch (ipv4_fib_0.apply().action_run) { + on_miss_2: { + ipv4_fib_lpm_0.apply(); + } + } + + nexthop_0.apply(); + } + } +} + +control DeparserImpl(packet_out packet, in headers hdr) { + apply { + packet.emit(hdr = hdr.ethernet); + packet.emit(hdr = hdr.ipv4); + } +} + +control verifyChecksum(inout headers hdr, inout metadata meta) { + apply { + verify_checksum, bit<4>, bit<8>, bit<16>, bit<16>, bit<3>, bit<13>, bit<8>, bit<8>, bit<32>, bit<32>>, bit<16>>(data = { hdr.ipv4.version, hdr.ipv4.ihl, hdr.ipv4.diffserv, hdr.ipv4.totalLen, hdr.ipv4.identification, hdr.ipv4.flags, hdr.ipv4.fragOffset, hdr.ipv4.ttl, hdr.ipv4.protocol, hdr.ipv4.srcAddr, hdr.ipv4.dstAddr }, checksum = hdr.ipv4.hdrChecksum, condition = true, algo = HashAlgorithm.csum16); + } +} + +control computeChecksum(inout headers hdr, inout metadata meta) { + apply { + update_checksum, bit<4>, bit<8>, bit<16>, bit<16>, bit<3>, bit<13>, bit<8>, bit<8>, bit<32>, bit<32>>, bit<16>>(condition = true, data = { hdr.ipv4.version, hdr.ipv4.ihl, hdr.ipv4.diffserv, hdr.ipv4.totalLen, hdr.ipv4.identification, hdr.ipv4.flags, hdr.ipv4.fragOffset, hdr.ipv4.ttl, hdr.ipv4.protocol, hdr.ipv4.srcAddr, hdr.ipv4.dstAddr }, algo = HashAlgorithm.csum16, checksum = hdr.ipv4.hdrChecksum); + } +} + +V1Switch(p = ParserImpl(), ig = ingress(), vr = verifyChecksum(), eg = egress(), ck = computeChecksum(), dep = DeparserImpl()) main; + diff --git a/testdata/p4_16_samples_outputs/issue-2123-midend.p4 b/testdata/p4_16_samples_outputs/issue-2123-midend.p4 new file mode 100644 index 00000000000..48e07f9207c --- /dev/null +++ b/testdata/p4_16_samples_outputs/issue-2123-midend.p4 @@ -0,0 +1,257 @@ +#include +#include + +struct ingress_metadata_t { + bit<12> vrf; + bit<16> bd; + bit<16> nexthop_index; +} + +header ethernet_t { + bit<48> dstAddr; + bit<48> srcAddr; + bit<16> etherType; +} + +header ipv4_t { + bit<4> version; + bit<4> ihl; + bit<8> diffserv; + bit<16> totalLen; + bit<16> identification; + bit<3> flags; + bit<13> fragOffset; + bit<8> ttl; + bit<8> protocol; + bit<16> hdrChecksum; + bit<32> srcAddr; + bit<32> dstAddr; +} + +struct metadata { + bit<12> _ingress_metadata_vrf0; + bit<16> _ingress_metadata_bd1; + bit<16> _ingress_metadata_nexthop_index2; +} + +struct headers { + ethernet_t ethernet; + ipv4_t ipv4; +} + +parser ParserImpl(packet_in packet, out headers hdr, inout metadata meta, inout standard_metadata_t standard_metadata) { + state parse_ipv4 { + packet.extract(hdr = hdr.ipv4); + transition select(hdr.ipv4.ihl, hdr.ipv4.protocol) { + (4w0x5, 8w0x1): parse_icmp; + (4w0x5, 8w0x6): parse_tcp; + (4w0x5, 8w0x11): parse_udp; + (default, default): accept; + default: noMatch; + } + } + state parse_icmp { + transition accept; + } + state parse_tcp { + transition accept; + } + state parse_udp { + transition accept; + } + state start { + packet.extract(hdr = hdr.ethernet); + transition select(hdr.ethernet.etherType, hdr.ethernet.srcAddr[7:0], hdr.ethernet.dstAddr[7:0]) { + (16w0x800 &&& 16w0xfffc, 8w0x8 &&& 8w0xf8, 8w0x8 &&& 8w0xf8): parse_ipv4; + (16w0x800 &&& 16w0xfffc, 8w0x8 &&& 8w0xf8, 8w0x10 &&& 8w0xff): parse_ipv4; + (16w0x800 &&& 16w0xfffc, 8w0x10 &&& 8w0xfe, 8w0x8 &&& 8w0xf8): parse_ipv4; + (16w0x800 &&& 16w0xfffc, 8w0x10 &&& 8w0xfe, 8w0x10 &&& 8w0xff): parse_ipv4; + (16w0x804 &&& 16w0xfffe, 8w0x8 &&& 8w0xf8, 8w0x8 &&& 8w0xf8): parse_ipv4; + (16w0x804 &&& 16w0xfffe, 8w0x8 &&& 8w0xf8, 8w0x10 &&& 8w0xff): parse_ipv4; + (16w0x804 &&& 16w0xfffe, 8w0x10 &&& 8w0xfe, 8w0x8 &&& 8w0xf8): parse_ipv4; + (16w0x804 &&& 16w0xfffe, 8w0x10 &&& 8w0xfe, 8w0x10 &&& 8w0xff): parse_ipv4; + (16w0x806 &&& 16w0xffff, 8w0x8 &&& 8w0xf8, 8w0x8 &&& 8w0xf8): parse_ipv4; + (16w0x806 &&& 16w0xffff, 8w0x8 &&& 8w0xf8, 8w0x10 &&& 8w0xff): parse_ipv4; + (16w0x806 &&& 16w0xffff, 8w0x10 &&& 8w0xfe, 8w0x8 &&& 8w0xf8): parse_ipv4; + (16w0x806 &&& 16w0xffff, 8w0x10 &&& 8w0xfe, 8w0x10 &&& 8w0xff): parse_ipv4; + (16w0x800, 8w0x8 &&& 8w0xf8, 8w0x6 &&& 8w0x11): parse_ipv4; + (16w0x800, 8w0x10 &&& 8w0xff, 8w0x6 &&& 8w0x11): parse_ipv4; + default: accept; + } + } + state noMatch { + verify(false, error.NoMatch); + transition reject; + } +} + +control egress(inout headers hdr, inout metadata meta, inout standard_metadata_t standard_metadata) { + @name(".NoAction") action NoAction_0() { + } + @name("egress.on_miss") action on_miss() { + } + @name("egress.rewrite_src_dst_mac") action rewrite_src_dst_mac(bit<48> smac, bit<48> dmac) { + hdr.ethernet.srcAddr = smac; + hdr.ethernet.dstAddr = dmac; + } + @name("egress.rewrite_mac") table rewrite_mac_0 { + actions = { + on_miss(); + rewrite_src_dst_mac(); + @defaultonly NoAction_0(); + } + key = { + meta._ingress_metadata_nexthop_index2: exact @name("meta.ingress_metadata.nexthop_index") ; + } + size = 32768; + default_action = NoAction_0(); + } + apply { + rewrite_mac_0.apply(); + } +} + +control ingress(inout headers hdr, inout metadata meta, inout standard_metadata_t standard_metadata) { + @name(".NoAction") action NoAction_1() { + } + @name(".NoAction") action NoAction_8() { + } + @name(".NoAction") action NoAction_9() { + } + @name(".NoAction") action NoAction_10() { + } + @name(".NoAction") action NoAction_11() { + } + @name("ingress.set_vrf") action set_vrf(bit<12> vrf) { + meta._ingress_metadata_vrf0 = vrf; + } + @name("ingress.on_miss") action on_miss_2() { + } + @name("ingress.on_miss") action on_miss_5() { + } + @name("ingress.on_miss") action on_miss_6() { + } + @name("ingress.fib_hit_nexthop") action fib_hit_nexthop(bit<16> nexthop_index) { + meta._ingress_metadata_nexthop_index2 = nexthop_index; + hdr.ipv4.ttl = hdr.ipv4.ttl + 8w255; + } + @name("ingress.fib_hit_nexthop") action fib_hit_nexthop_2(bit<16> nexthop_index) { + meta._ingress_metadata_nexthop_index2 = nexthop_index; + hdr.ipv4.ttl = hdr.ipv4.ttl + 8w255; + } + @name("ingress.set_egress_details") action set_egress_details(bit<9> egress_spec) { + standard_metadata.egress_spec = egress_spec; + } + @name("ingress.set_bd") action set_bd(bit<16> bd) { + meta._ingress_metadata_bd1 = bd; + } + @name("ingress.bd") table bd_0 { + actions = { + set_vrf(); + @defaultonly NoAction_1(); + } + key = { + meta._ingress_metadata_bd1: exact @name("meta.ingress_metadata.bd") ; + } + size = 65536; + default_action = NoAction_1(); + } + @name("ingress.ipv4_fib") table ipv4_fib_0 { + actions = { + on_miss_2(); + fib_hit_nexthop(); + @defaultonly NoAction_8(); + } + key = { + meta._ingress_metadata_vrf0: exact @name("meta.ingress_metadata.vrf") ; + hdr.ipv4.dstAddr : exact @name("hdr.ipv4.dstAddr") ; + } + size = 131072; + default_action = NoAction_8(); + } + @name("ingress.ipv4_fib_lpm") table ipv4_fib_lpm_0 { + actions = { + on_miss_5(); + fib_hit_nexthop_2(); + @defaultonly NoAction_9(); + } + key = { + meta._ingress_metadata_vrf0: exact @name("meta.ingress_metadata.vrf") ; + hdr.ipv4.dstAddr : lpm @name("hdr.ipv4.dstAddr") ; + } + size = 16384; + default_action = NoAction_9(); + } + @name("ingress.nexthop") table nexthop_0 { + actions = { + on_miss_6(); + set_egress_details(); + @defaultonly NoAction_10(); + } + key = { + meta._ingress_metadata_nexthop_index2: exact @name("meta.ingress_metadata.nexthop_index") ; + } + size = 32768; + default_action = NoAction_10(); + } + @name("ingress.port_mapping") table port_mapping_0 { + actions = { + set_bd(); + @defaultonly NoAction_11(); + } + key = { + standard_metadata.ingress_port: exact @name("standard_metadata.ingress_port") ; + } + size = 32768; + default_action = NoAction_11(); + } + apply { + if (hdr.ipv4.isValid()) { + port_mapping_0.apply(); + bd_0.apply(); + switch (ipv4_fib_0.apply().action_run) { + on_miss_2: { + ipv4_fib_lpm_0.apply(); + } + } + + nexthop_0.apply(); + } + } +} + +control DeparserImpl(packet_out packet, in headers hdr) { + apply { + packet.emit(hdr = hdr.ethernet); + packet.emit(hdr = hdr.ipv4); + } +} + +struct tuple_0 { + bit<4> field; + bit<4> field_0; + bit<8> field_1; + bit<16> field_2; + bit<16> field_3; + bit<3> field_4; + bit<13> field_5; + bit<8> field_6; + bit<8> field_7; + bit<32> field_8; + bit<32> field_9; +} + +control verifyChecksum(inout headers hdr, inout metadata meta) { + apply { + verify_checksum>(data = { hdr.ipv4.version, hdr.ipv4.ihl, hdr.ipv4.diffserv, hdr.ipv4.totalLen, hdr.ipv4.identification, hdr.ipv4.flags, hdr.ipv4.fragOffset, hdr.ipv4.ttl, hdr.ipv4.protocol, hdr.ipv4.srcAddr, hdr.ipv4.dstAddr }, checksum = hdr.ipv4.hdrChecksum, condition = true, algo = HashAlgorithm.csum16); + } +} + +control computeChecksum(inout headers hdr, inout metadata meta) { + apply { + update_checksum>(condition = true, data = { hdr.ipv4.version, hdr.ipv4.ihl, hdr.ipv4.diffserv, hdr.ipv4.totalLen, hdr.ipv4.identification, hdr.ipv4.flags, hdr.ipv4.fragOffset, hdr.ipv4.ttl, hdr.ipv4.protocol, hdr.ipv4.srcAddr, hdr.ipv4.dstAddr }, algo = HashAlgorithm.csum16, checksum = hdr.ipv4.hdrChecksum); + } +} + +V1Switch(p = ParserImpl(), ig = ingress(), vr = verifyChecksum(), eg = egress(), ck = computeChecksum(), dep = DeparserImpl()) main; + diff --git a/testdata/p4_16_samples_outputs/issue-2123.p4 b/testdata/p4_16_samples_outputs/issue-2123.p4 new file mode 100644 index 00000000000..ee4faa51f35 --- /dev/null +++ b/testdata/p4_16_samples_outputs/issue-2123.p4 @@ -0,0 +1,198 @@ +#include +#include + +struct ingress_metadata_t { + bit<12> vrf; + bit<16> bd; + bit<16> nexthop_index; +} + +header ethernet_t { + bit<48> dstAddr; + bit<48> srcAddr; + bit<16> etherType; +} + +header ipv4_t { + bit<4> version; + bit<4> ihl; + bit<8> diffserv; + bit<16> totalLen; + bit<16> identification; + bit<3> flags; + bit<13> fragOffset; + bit<8> ttl; + bit<8> protocol; + bit<16> hdrChecksum; + bit<32> srcAddr; + bit<32> dstAddr; +} + +struct metadata { + ingress_metadata_t ingress_metadata; +} + +struct headers { + ethernet_t ethernet; + ipv4_t ipv4; +} + +parser ParserImpl(packet_in packet, out headers hdr, inout metadata meta, inout standard_metadata_t standard_metadata) { + state parse_ethernet { + packet.extract(hdr = hdr.ethernet); + transition select(hdr.ethernet.etherType, hdr.ethernet.srcAddr[7:0], hdr.ethernet.dstAddr[7:0]) { + (0x800 .. 0x806, 0x8 .. 0x11, 0x8 .. 0x10): parse_ipv4; + (0x800, 0x8 .. 0x10, 0x6 &&& 0x11): parse_ipv4; + default: accept; + } + } + state parse_ipv4 { + packet.extract(hdr = hdr.ipv4); + transition select(hdr.ipv4.ihl, hdr.ipv4.protocol) { + (4w0x5, 8w0x1): parse_icmp; + (4w0x5, 8w0x6): parse_tcp; + (4w0x5, 8w0x11): parse_udp; + (default, default): accept; + } + } + state parse_icmp { + transition accept; + } + state parse_tcp { + transition accept; + } + state parse_udp { + transition accept; + } + state parse_x { + transition accept; + } + state start { + transition parse_ethernet; + } +} + +control egress(inout headers hdr, inout metadata meta, inout standard_metadata_t standard_metadata) { + action on_miss() { + } + action rewrite_src_dst_mac(bit<48> smac, bit<48> dmac) { + hdr.ethernet.srcAddr = smac; + hdr.ethernet.dstAddr = dmac; + } + table rewrite_mac { + actions = { + on_miss; + rewrite_src_dst_mac; + } + key = { + meta.ingress_metadata.nexthop_index: exact; + } + size = 32768; + } + apply { + rewrite_mac.apply(); + } +} + +control ingress(inout headers hdr, inout metadata meta, inout standard_metadata_t standard_metadata) { + action set_vrf(bit<12> vrf) { + meta.ingress_metadata.vrf = vrf; + } + action on_miss() { + } + action fib_hit_nexthop(bit<16> nexthop_index) { + meta.ingress_metadata.nexthop_index = nexthop_index; + hdr.ipv4.ttl = hdr.ipv4.ttl - 8w1; + } + action set_egress_details(bit<9> egress_spec) { + standard_metadata.egress_spec = egress_spec; + } + action set_bd(bit<16> bd) { + meta.ingress_metadata.bd = bd; + } + table bd { + actions = { + set_vrf; + } + key = { + meta.ingress_metadata.bd: exact; + } + size = 65536; + } + table ipv4_fib { + actions = { + on_miss; + fib_hit_nexthop; + } + key = { + meta.ingress_metadata.vrf: exact; + hdr.ipv4.dstAddr : exact; + } + size = 131072; + } + table ipv4_fib_lpm { + actions = { + on_miss; + fib_hit_nexthop; + } + key = { + meta.ingress_metadata.vrf: exact; + hdr.ipv4.dstAddr : lpm; + } + size = 16384; + } + table nexthop { + actions = { + on_miss; + set_egress_details; + } + key = { + meta.ingress_metadata.nexthop_index: exact; + } + size = 32768; + } + table port_mapping { + actions = { + set_bd; + } + key = { + standard_metadata.ingress_port: exact; + } + size = 32768; + } + apply { + if (hdr.ipv4.isValid()) { + port_mapping.apply(); + bd.apply(); + switch (ipv4_fib.apply().action_run) { + on_miss: { + ipv4_fib_lpm.apply(); + } + } + + nexthop.apply(); + } + } +} + +control DeparserImpl(packet_out packet, in headers hdr) { + apply { + packet.emit(hdr = hdr.ethernet); + packet.emit(hdr = hdr.ipv4); + } +} + +control verifyChecksum(inout headers hdr, inout metadata meta) { + apply { + verify_checksum(data = { hdr.ipv4.version, hdr.ipv4.ihl, hdr.ipv4.diffserv, hdr.ipv4.totalLen, hdr.ipv4.identification, hdr.ipv4.flags, hdr.ipv4.fragOffset, hdr.ipv4.ttl, hdr.ipv4.protocol, hdr.ipv4.srcAddr, hdr.ipv4.dstAddr }, checksum = hdr.ipv4.hdrChecksum, condition = true, algo = HashAlgorithm.csum16); + } +} + +control computeChecksum(inout headers hdr, inout metadata meta) { + apply { + update_checksum(condition = true, data = { hdr.ipv4.version, hdr.ipv4.ihl, hdr.ipv4.diffserv, hdr.ipv4.totalLen, hdr.ipv4.identification, hdr.ipv4.flags, hdr.ipv4.fragOffset, hdr.ipv4.ttl, hdr.ipv4.protocol, hdr.ipv4.srcAddr, hdr.ipv4.dstAddr }, algo = HashAlgorithm.csum16, checksum = hdr.ipv4.hdrChecksum); + } +} + +V1Switch(p = ParserImpl(), ig = ingress(), vr = verifyChecksum(), eg = egress(), ck = computeChecksum(), dep = DeparserImpl()) main; + diff --git a/testdata/p4_16_samples_outputs/issue-2123.p4-stderr b/testdata/p4_16_samples_outputs/issue-2123.p4-stderr new file mode 100644 index 00000000000..e69de29bb2d diff --git a/testdata/p4_16_samples_outputs/issue-2123.p4.entries.txt b/testdata/p4_16_samples_outputs/issue-2123.p4.entries.txt new file mode 100644 index 00000000000..e69de29bb2d diff --git a/testdata/p4_16_samples_outputs/issue-2123.p4.p4info.txt b/testdata/p4_16_samples_outputs/issue-2123.p4.p4info.txt new file mode 100644 index 00000000000..56e67960f18 --- /dev/null +++ b/testdata/p4_16_samples_outputs/issue-2123.p4.p4info.txt @@ -0,0 +1,247 @@ +pkg_info { + arch: "v1model" +} +tables { + preamble { + id: 33581415 + name: "ingress.bd" + alias: "bd" + } + match_fields { + id: 1 + name: "meta.ingress_metadata.bd" + bitwidth: 16 + match_type: EXACT + } + action_refs { + id: 16793910 + } + action_refs { + id: 16800567 + annotations: "@defaultonly" + scope: DEFAULT_ONLY + } + size: 65536 +} +tables { + preamble { + id: 33613387 + name: "ingress.ipv4_fib" + alias: "ipv4_fib" + } + match_fields { + id: 1 + name: "meta.ingress_metadata.vrf" + bitwidth: 12 + match_type: EXACT + } + match_fields { + id: 2 + name: "hdr.ipv4.dstAddr" + bitwidth: 32 + match_type: EXACT + } + action_refs { + id: 16826976 + } + action_refs { + id: 16798108 + } + action_refs { + id: 16800567 + annotations: "@defaultonly" + scope: DEFAULT_ONLY + } + size: 131072 +} +tables { + preamble { + id: 33569838 + name: "ingress.ipv4_fib_lpm" + alias: "ipv4_fib_lpm" + } + match_fields { + id: 1 + name: "meta.ingress_metadata.vrf" + bitwidth: 12 + match_type: EXACT + } + match_fields { + id: 2 + name: "hdr.ipv4.dstAddr" + bitwidth: 32 + match_type: LPM + } + action_refs { + id: 16826976 + } + action_refs { + id: 16798108 + } + action_refs { + id: 16800567 + annotations: "@defaultonly" + scope: DEFAULT_ONLY + } + size: 16384 +} +tables { + preamble { + id: 33619585 + name: "ingress.nexthop" + alias: "nexthop" + } + match_fields { + id: 1 + name: "meta.ingress_metadata.nexthop_index" + bitwidth: 16 + match_type: EXACT + } + action_refs { + id: 16826976 + } + action_refs { + id: 16788993 + } + action_refs { + id: 16800567 + annotations: "@defaultonly" + scope: DEFAULT_ONLY + } + size: 32768 +} +tables { + preamble { + id: 33616322 + name: "ingress.port_mapping" + alias: "port_mapping" + } + match_fields { + id: 1 + name: "standard_metadata.ingress_port" + bitwidth: 9 + match_type: EXACT + } + action_refs { + id: 16817852 + } + action_refs { + id: 16800567 + annotations: "@defaultonly" + scope: DEFAULT_ONLY + } + size: 32768 +} +tables { + preamble { + id: 33558953 + name: "egress.rewrite_mac" + alias: "rewrite_mac" + } + match_fields { + id: 1 + name: "meta.ingress_metadata.nexthop_index" + bitwidth: 16 + match_type: EXACT + } + action_refs { + id: 16805656 + } + action_refs { + id: 16842256 + } + action_refs { + id: 16800567 + annotations: "@defaultonly" + scope: DEFAULT_ONLY + } + size: 32768 +} +actions { + preamble { + id: 16800567 + name: "NoAction" + alias: "NoAction" + } +} +actions { + preamble { + id: 16793910 + name: "ingress.set_vrf" + alias: "set_vrf" + } + params { + id: 1 + name: "vrf" + bitwidth: 12 + } +} +actions { + preamble { + id: 16826976 + name: "ingress.on_miss" + alias: "ingress.on_miss" + } +} +actions { + preamble { + id: 16798108 + name: "ingress.fib_hit_nexthop" + alias: "fib_hit_nexthop" + } + params { + id: 1 + name: "nexthop_index" + bitwidth: 16 + } +} +actions { + preamble { + id: 16788993 + name: "ingress.set_egress_details" + alias: "set_egress_details" + } + params { + id: 1 + name: "egress_spec" + bitwidth: 9 + } +} +actions { + preamble { + id: 16817852 + name: "ingress.set_bd" + alias: "set_bd" + } + params { + id: 1 + name: "bd" + bitwidth: 16 + } +} +actions { + preamble { + id: 16805656 + name: "egress.on_miss" + alias: "egress.on_miss" + } +} +actions { + preamble { + id: 16842256 + name: "egress.rewrite_src_dst_mac" + alias: "rewrite_src_dst_mac" + } + params { + id: 1 + name: "smac" + bitwidth: 48 + } + params { + id: 2 + name: "dmac" + bitwidth: 48 + } +} +type_info { +} From 690833c271fb8edbf74ca418fed19d2b3e878ca2 Mon Sep 17 00:00:00 2001 From: Hemant Singh <32817427+hesingh@users.noreply.github.com> Date: Wed, 15 Jan 2020 12:54:44 -0500 Subject: [PATCH 057/106] Misc minor fixes (#2138) * Misc minor fixes * Changes all instances of protobuf 3.2.0 to 3.6.1 in README.md --- README.md | 10 +++++----- backends/bmv2/common/JsonObjects.cpp | 10 ---------- ir/README.md | 2 +- 3 files changed, 6 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index 8ba594f2e3b..30369b2caf5 100644 --- a/README.md +++ b/README.md @@ -215,17 +215,17 @@ which is not available until Ubuntu 16.10. For earlier releases of Ubuntu, you'll need to install from source. You can find instructions [here](https://github.com/google/protobuf/blob/master/src/README.md). **We recommend that you use version -[3.2.0](https://github.com/google/protobuf/releases/tag/v3.2.0)**. Earlier +[3.6.1](https://github.com/google/protobuf/releases/tag/v3.6.1)**. Earlier versions in the 3 series may not be supported by other p4lang projects, such as [p4lang/PI](https://github.com/p4lang/PI). More recent versions may work as -well, but all our CI testing is done with version 3.2.0. After cloning protobuf -and before you build, check-out version 3.2.0: +well, but all our CI testing is done with version 3.6.1. After cloning protobuf +and before you build, check-out version 3.6.1: -`git checkout v3.2.0` +`git checkout v3.6.1` Please note that while all protobuf versions newer than 3.0 should work for `p4c` itself, you may run into trouble with some extensions and other p4lang -projects unless you install version 3.2.0, so you may want to install from +projects unless you install version 3.6.1, so you may want to install from source even on newer releases of Ubuntu. ## macOS dependencies diff --git a/backends/bmv2/common/JsonObjects.cpp b/backends/bmv2/common/JsonObjects.cpp index 413d50a4477..0942e85459a 100644 --- a/backends/bmv2/common/JsonObjects.cpp +++ b/backends/bmv2/common/JsonObjects.cpp @@ -97,16 +97,6 @@ JsonObjects::create_parameters(Util::JsonObject* object) { return insert_array_field(object, "parameters"); } -/// Append a json object r to a parent json array, -/// insert a field 'op' with 'name' to parent. -Util::JsonObject* -JsonObjects::create_primitive(Util::JsonArray* parent, cstring name) { - auto result = new Util::JsonObject(); - result->emplace("op", name); - parent->append(result); - return result; -} - void JsonObjects::add_program_info(const cstring& name) { toplevel->emplace("program", name); diff --git a/ir/README.md b/ir/README.md index 5e3829d0a42..383f8036927 100644 --- a/ir/README.md +++ b/ir/README.md @@ -44,7 +44,7 @@ boilerplate removed, which the ir-generator generates. | | +-- Operation_Relation | | | \-- Equ, New, Lss, Leq, Grt, Geq | | +-- BAnd, BOr, BXor, LAnd, LOr - | | \-- Concat, ArrayIndex, Rnage, Mask + | | \-- Concat, ArrayIndex, Range, Mask | +-- Operation_Trinary | | \-- Slice, Mux | \-- Primitive From f2b0c79397f187b8e5e2e8fd5bbd3047dc57e0d8 Mon Sep 17 00:00:00 2001 From: Calin Cascaval Date: Thu, 16 Jan 2020 10:11:17 -0800 Subject: [PATCH 058/106] fix missing header when backends are disabled Backends install their own headers, however, when a backend is disabled, we might still want to run p4test to validate the p4. Therefore we copy the headers in the build directory. Fixes #2130 --- CMakeLists.txt | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0dd8101ee80..d1c703a6930 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -323,10 +323,19 @@ add_custom_command (OUTPUT ${IR_GENERATED_SRCS} add_custom_target(genIR DEPENDS ${IR_GENERATED_SRCS}) # Header files +# p4test needs all the backend include files, whether the backend is enabled or not +# Note that we only provide the headers for the build env, they are only installed by the +# backend specific target. +set (OTHER_HEADERS + backends/ebpf/p4include/ebpf_model.p4 + ) add_custom_target(update_includes ALL - #FIXME -- should only run this when headers change -- how to accomplish that? - COMMAND ${CMAKE_COMMAND} -E copy_directory ${P4C_SOURCE_DIR}/p4include ${P4C_BINARY_DIR}/p4include -) + COMMAND ${CMAKE_COMMAND} -E make_directory ${P4C_BINARY_DIR}/p4include + COMMAND ${CMAKE_COMMAND} -E copy_if_different ${P4C_SOURCE_DIR}/p4include/*.p4 ${P4C_BINARY_DIR}/p4include + COMMAND for h in ${OTHER_HEADERS} \; do + ${CMAKE_COMMAND} -E copy_if_different ${CMAKE_CURRENT_SOURCE_DIR}/\$$h ${P4C_BINARY_DIR}/p4include \; + done + ) # Installation # Targets install themselves. Here we install the core headers From 53d0fc68ae02114d42ac03f31a525a6d1e36c8c3 Mon Sep 17 00:00:00 2001 From: Han Wang Date: Sat, 18 Jan 2020 08:55:15 -0800 Subject: [PATCH 059/106] simplify slices (#2142) --- frontends/p4/strengthReduction.cpp | 12 ++ .../TLV_parsing-first.p4 | 2 +- .../TLV_parsing-frontend.p4 | 2 +- .../TLV_parsing-midend.p4 | 2 +- testdata/p4_14_samples_outputs/axon-first.p4 | 2 +- .../p4_14_samples_outputs/axon-frontend.p4 | 2 +- testdata/p4_14_samples_outputs/axon-midend.p4 | 2 +- .../copy_to_cpu-first.p4 | 2 +- .../copy_to_cpu-frontend.p4 | 2 +- .../copy_to_cpu-midend.p4 | 2 +- .../p4_14_samples_outputs/issue583-first.p4 | 2 +- .../issue583-frontend.p4 | 2 +- .../p4_14_samples_outputs/issue583-midend.p4 | 2 +- .../p4_14_samples_outputs/parser1-first.p4 | 2 +- .../p4_14_samples_outputs/parser1-frontend.p4 | 2 +- .../p4_14_samples_outputs/parser1-midend.p4 | 2 +- .../p4_14_samples_outputs/parser2-first.p4 | 2 +- .../p4_14_samples_outputs/parser2-frontend.p4 | 2 +- .../p4_14_samples_outputs/parser2-midend.p4 | 2 +- .../p4_14_samples_outputs/parser4-first.p4 | 2 +- .../p4_14_samples_outputs/parser4-frontend.p4 | 2 +- .../p4_14_samples_outputs/parser4-midend.p4 | 2 +- .../parser_dc_full-first.p4 | 2 +- .../parser_dc_full-frontend.p4 | 2 +- .../parser_dc_full-midend.p4 | 2 +- .../parser_pragma2-first.p4 | 2 +- .../parser_pragma2-frontend.p4 | 2 +- .../port_vlan_mapping-first.p4 | 2 +- .../port_vlan_mapping-frontend.p4 | 2 +- .../port_vlan_mapping-midend.p4 | 2 +- .../p4_14_samples_outputs/simple_nat-first.p4 | 2 +- .../simple_nat-frontend.p4 | 2 +- .../simple_nat-midend.p4 | 2 +- .../source_routing-first.p4 | 2 +- .../source_routing-frontend.p4 | 2 +- .../source_routing-midend.p4 | 2 +- .../switch_20160512/switch-first.p4 | 6 +- .../switch_20160512/switch-frontend.p4 | 6 +- .../switch_20160512/switch-midend.p4 | 6 +- testdata/p4_16_errors/slice_out_of_bound.p4 | 117 +++++++++++++++++ .../slice_out_of_bound.p4 | 74 +++++++++++ .../slice_out_of_bound.p4-stderr | 3 + testdata/p4_16_samples/simplify_slice.p4 | 121 ++++++++++++++++++ .../issue1713-bmv2-first.p4 | 4 +- .../issue1713-bmv2-frontend.p4 | 4 +- .../issue1713-bmv2-midend.p4 | 4 +- .../p4_16_samples_outputs/issue2105-first.p4 | 2 +- .../p4_16_samples_outputs/issue648-first.p4 | 2 +- .../issue648-frontend.p4 | 2 +- .../p4_16_samples_outputs/issue648-midend.p4 | 2 +- .../issue870_ebpf-first.p4 | 2 +- .../issue870_ebpf-frontend.p4 | 2 +- .../issue870_ebpf-midend.p4 | 2 +- .../side_effects-first.p4 | 2 +- .../side_effects-frontend.p4 | 2 +- .../side_effects-midend.p4 | 2 +- .../simplify_slice-first.p4 | 78 +++++++++++ .../simplify_slice-frontend.p4 | 79 ++++++++++++ .../simplify_slice-midend.p4 | 84 ++++++++++++ .../p4_16_samples_outputs/simplify_slice.p4 | 78 +++++++++++ .../simplify_slice.p4-stderr | 0 .../simplify_slice.p4.entries.txt | 0 .../simplify_slice.p4.p4info.txt | 20 +++ .../p4_16_samples_outputs/strength3-first.p4 | 4 +- .../strength3-frontend.p4 | 2 +- .../p4_16_samples_outputs/strength3-midend.p4 | 6 +- 66 files changed, 732 insertions(+), 66 deletions(-) create mode 100644 testdata/p4_16_errors/slice_out_of_bound.p4 create mode 100644 testdata/p4_16_errors_outputs/slice_out_of_bound.p4 create mode 100644 testdata/p4_16_errors_outputs/slice_out_of_bound.p4-stderr create mode 100644 testdata/p4_16_samples/simplify_slice.p4 create mode 100644 testdata/p4_16_samples_outputs/simplify_slice-first.p4 create mode 100644 testdata/p4_16_samples_outputs/simplify_slice-frontend.p4 create mode 100644 testdata/p4_16_samples_outputs/simplify_slice-midend.p4 create mode 100644 testdata/p4_16_samples_outputs/simplify_slice.p4 create mode 100644 testdata/p4_16_samples_outputs/simplify_slice.p4-stderr create mode 100644 testdata/p4_16_samples_outputs/simplify_slice.p4.entries.txt create mode 100644 testdata/p4_16_samples_outputs/simplify_slice.p4.p4info.txt diff --git a/frontends/p4/strengthReduction.cpp b/frontends/p4/strengthReduction.cpp index ae0097e2c74..52eea57938e 100644 --- a/frontends/p4/strengthReduction.cpp +++ b/frontends/p4/strengthReduction.cpp @@ -303,6 +303,18 @@ const IR::Node* DoStrengthReduction::postorder(IR::Slice* expr) { } } + // out-of-bound error has been caught in type checking + if (auto sl = expr->e0->to()) { + auto e = sl->e0; + auto hi = expr->getH() + sl->getL(); + auto lo = expr->getL() + sl->getL(); + return new IR::Slice(e, hi, lo); + } + + auto slice_width = expr->getH() - expr->getL() + 1; + if (slice_width == expr->e0->type->width_bits()) + return expr->e0; + return expr; } diff --git a/testdata/p4_14_samples_outputs/TLV_parsing-first.p4 b/testdata/p4_14_samples_outputs/TLV_parsing-first.p4 index af15ec65473..536bd016395 100644 --- a/testdata/p4_14_samples_outputs/TLV_parsing-first.p4 +++ b/testdata/p4_14_samples_outputs/TLV_parsing-first.p4 @@ -116,7 +116,7 @@ parser ParserImpl(packet_in packet, out headers hdr, inout metadata meta, inout transition parse_ipv4_options; } @name(".parse_ipv4_options") state parse_ipv4_options { - transition select(meta.my_metadata.parse_ipv4_counter, (packet.lookahead>())[7:0]) { + transition select(meta.my_metadata.parse_ipv4_counter, packet.lookahead>()) { (8w0x0 &&& 8w0xff, 8w0x0 &&& 8w0x0): accept; (8w0x0 &&& 8w0x0, 8w0x0 &&& 8w0xff): parse_ipv4_option_EOL; (8w0x0 &&& 8w0x0, 8w0x1 &&& 8w0xff): parse_ipv4_option_NOP; diff --git a/testdata/p4_14_samples_outputs/TLV_parsing-frontend.p4 b/testdata/p4_14_samples_outputs/TLV_parsing-frontend.p4 index c9399ef4ef2..6a40f75fba0 100644 --- a/testdata/p4_14_samples_outputs/TLV_parsing-frontend.p4 +++ b/testdata/p4_14_samples_outputs/TLV_parsing-frontend.p4 @@ -118,7 +118,7 @@ parser ParserImpl(packet_in packet, out headers hdr, inout metadata meta, inout } @name(".parse_ipv4_options") state parse_ipv4_options { tmp = packet.lookahead>(); - transition select(meta.my_metadata.parse_ipv4_counter, tmp[7:0]) { + transition select(meta.my_metadata.parse_ipv4_counter, tmp) { (8w0x0 &&& 8w0xff, 8w0x0 &&& 8w0x0): accept; (8w0x0 &&& 8w0x0, 8w0x0 &&& 8w0xff): parse_ipv4_option_EOL; (8w0x0 &&& 8w0x0, 8w0x1 &&& 8w0xff): parse_ipv4_option_NOP; diff --git a/testdata/p4_14_samples_outputs/TLV_parsing-midend.p4 b/testdata/p4_14_samples_outputs/TLV_parsing-midend.p4 index ed72e2087fe..545a9ecbad2 100644 --- a/testdata/p4_14_samples_outputs/TLV_parsing-midend.p4 +++ b/testdata/p4_14_samples_outputs/TLV_parsing-midend.p4 @@ -121,7 +121,7 @@ parser ParserImpl(packet_in packet, out headers hdr, inout metadata meta, inout } @name(".parse_ipv4_options") state parse_ipv4_options { tmp = packet.lookahead>(); - transition select(meta._my_metadata_parse_ipv4_counter0, tmp[7:0]) { + transition select(meta._my_metadata_parse_ipv4_counter0, tmp) { (8w0x0 &&& 8w0xff, 8w0x0 &&& 8w0x0): accept; (8w0x0 &&& 8w0x0, 8w0x0 &&& 8w0xff): parse_ipv4_option_EOL; (8w0x0 &&& 8w0x0, 8w0x1 &&& 8w0xff): parse_ipv4_option_NOP; diff --git a/testdata/p4_14_samples_outputs/axon-first.p4 b/testdata/p4_14_samples_outputs/axon-first.p4 index 2b7cdd8ff97..42b40f0aa6c 100644 --- a/testdata/p4_14_samples_outputs/axon-first.p4 +++ b/testdata/p4_14_samples_outputs/axon-first.p4 @@ -67,7 +67,7 @@ parser ParserImpl(packet_in packet, out headers hdr, inout metadata meta, inout transition parse_next_revHop; } @name(".start") state start { - transition select((packet.lookahead>())[63:0]) { + transition select(packet.lookahead>()) { 64w0: parse_head; default: accept; } diff --git a/testdata/p4_14_samples_outputs/axon-frontend.p4 b/testdata/p4_14_samples_outputs/axon-frontend.p4 index 2d773c22f6d..64c7c69eb7f 100644 --- a/testdata/p4_14_samples_outputs/axon-frontend.p4 +++ b/testdata/p4_14_samples_outputs/axon-frontend.p4 @@ -69,7 +69,7 @@ parser ParserImpl(packet_in packet, out headers hdr, inout metadata meta, inout } @name(".start") state start { tmp = packet.lookahead>(); - transition select(tmp[63:0]) { + transition select(tmp) { 64w0: parse_head; default: accept; } diff --git a/testdata/p4_14_samples_outputs/axon-midend.p4 b/testdata/p4_14_samples_outputs/axon-midend.p4 index a720fe57fce..006df5254d1 100644 --- a/testdata/p4_14_samples_outputs/axon-midend.p4 +++ b/testdata/p4_14_samples_outputs/axon-midend.p4 @@ -70,7 +70,7 @@ parser ParserImpl(packet_in packet, out headers hdr, inout metadata meta, inout } @name(".start") state start { tmp = packet.lookahead>(); - transition select(tmp[63:0]) { + transition select(tmp) { 64w0: parse_head; default: accept; } diff --git a/testdata/p4_14_samples_outputs/copy_to_cpu-first.p4 b/testdata/p4_14_samples_outputs/copy_to_cpu-first.p4 index 56564a62f9f..385841b7291 100644 --- a/testdata/p4_14_samples_outputs/copy_to_cpu-first.p4 +++ b/testdata/p4_14_samples_outputs/copy_to_cpu-first.p4 @@ -37,7 +37,7 @@ parser ParserImpl(packet_in packet, out headers hdr, inout metadata meta, inout transition accept; } @name(".start") state start { - transition select((packet.lookahead>())[63:0]) { + transition select(packet.lookahead>()) { 64w0: parse_cpu_header; default: parse_ethernet; } diff --git a/testdata/p4_14_samples_outputs/copy_to_cpu-frontend.p4 b/testdata/p4_14_samples_outputs/copy_to_cpu-frontend.p4 index ae162f1313b..0b5132271a5 100644 --- a/testdata/p4_14_samples_outputs/copy_to_cpu-frontend.p4 +++ b/testdata/p4_14_samples_outputs/copy_to_cpu-frontend.p4 @@ -39,7 +39,7 @@ parser ParserImpl(packet_in packet, out headers hdr, inout metadata meta, inout } @name(".start") state start { tmp = packet.lookahead>(); - transition select(tmp[63:0]) { + transition select(tmp) { 64w0: parse_cpu_header; default: parse_ethernet; } diff --git a/testdata/p4_14_samples_outputs/copy_to_cpu-midend.p4 b/testdata/p4_14_samples_outputs/copy_to_cpu-midend.p4 index 109bb8629de..b78cef29481 100644 --- a/testdata/p4_14_samples_outputs/copy_to_cpu-midend.p4 +++ b/testdata/p4_14_samples_outputs/copy_to_cpu-midend.p4 @@ -39,7 +39,7 @@ parser ParserImpl(packet_in packet, out headers hdr, inout metadata meta, inout } @name(".start") state start { tmp = packet.lookahead>(); - transition select(tmp[63:0]) { + transition select(tmp) { 64w0: parse_cpu_header; default: parse_ethernet; } diff --git a/testdata/p4_14_samples_outputs/issue583-first.p4 b/testdata/p4_14_samples_outputs/issue583-first.p4 index f0b5f25faac..2794b9f9d4f 100644 --- a/testdata/p4_14_samples_outputs/issue583-first.p4 +++ b/testdata/p4_14_samples_outputs/issue583-first.p4 @@ -190,7 +190,7 @@ control ingress(inout headers hdr, inout metadata meta, inout standard_metadata_ } @name(".hop") action hop(inout bit<8> ttl, bit<9> egress_spec) { ttl = ttl + 8w255; - standard_metadata.egress_spec[8:0] = egress_spec[8:0]; + standard_metadata.egress_spec = egress_spec; } @name(".hop_ipv4") action hop_ipv4(bit<9> egress_spec) { hop(hdr.ipv4.ttl, egress_spec); diff --git a/testdata/p4_14_samples_outputs/issue583-frontend.p4 b/testdata/p4_14_samples_outputs/issue583-frontend.p4 index 6bea75fea23..1ad264d44e0 100644 --- a/testdata/p4_14_samples_outputs/issue583-frontend.p4 +++ b/testdata/p4_14_samples_outputs/issue583-frontend.p4 @@ -196,7 +196,7 @@ control ingress(inout headers hdr, inout metadata meta, inout standard_metadata_ { bit<8> ttl_1 = hdr.ipv4.ttl; ttl_1 = ttl_1 + 8w255; - standard_metadata.egress_spec[8:0] = egress_spec[8:0]; + standard_metadata.egress_spec = egress_spec; hdr.ipv4.ttl = ttl_1; } } diff --git a/testdata/p4_14_samples_outputs/issue583-midend.p4 b/testdata/p4_14_samples_outputs/issue583-midend.p4 index 9a1a30601e5..adbf4562b7d 100644 --- a/testdata/p4_14_samples_outputs/issue583-midend.p4 +++ b/testdata/p4_14_samples_outputs/issue583-midend.p4 @@ -200,7 +200,7 @@ control ingress(inout headers hdr, inout metadata meta, inout standard_metadata_ mark_to_drop(standard_metadata); } @name(".hop_ipv4") action hop_ipv4(bit<9> egress_spec) { - standard_metadata.egress_spec[8:0] = egress_spec[8:0]; + standard_metadata.egress_spec = egress_spec; hdr.ipv4.ttl = hdr.ipv4.ttl + 8w255; } @name(".act") action act() { diff --git a/testdata/p4_14_samples_outputs/parser1-first.p4 b/testdata/p4_14_samples_outputs/parser1-first.p4 index d92c8f8c8d6..2f57e9078d8 100644 --- a/testdata/p4_14_samples_outputs/parser1-first.p4 +++ b/testdata/p4_14_samples_outputs/parser1-first.p4 @@ -78,7 +78,7 @@ parser ParserImpl(packet_in packet, out headers hdr, inout metadata meta, inout } @name(".parse_mpls_bos") state parse_mpls_bos { packet.extract(hdr.mpls_bos); - transition select((packet.lookahead>())[3:0]) { + transition select(packet.lookahead>()) { 4w0x4: parse_ipv4; default: accept; } diff --git a/testdata/p4_14_samples_outputs/parser1-frontend.p4 b/testdata/p4_14_samples_outputs/parser1-frontend.p4 index eb87518c635..4952381585b 100644 --- a/testdata/p4_14_samples_outputs/parser1-frontend.p4 +++ b/testdata/p4_14_samples_outputs/parser1-frontend.p4 @@ -82,7 +82,7 @@ parser ParserImpl(packet_in packet, out headers hdr, inout metadata meta, inout @name(".parse_mpls_bos") state parse_mpls_bos { packet.extract(hdr.mpls_bos); tmp_0 = packet.lookahead>(); - transition select(tmp_0[3:0]) { + transition select(tmp_0) { 4w0x4: parse_ipv4; default: accept; } diff --git a/testdata/p4_14_samples_outputs/parser1-midend.p4 b/testdata/p4_14_samples_outputs/parser1-midend.p4 index 18c43735976..5b9d1879462 100644 --- a/testdata/p4_14_samples_outputs/parser1-midend.p4 +++ b/testdata/p4_14_samples_outputs/parser1-midend.p4 @@ -82,7 +82,7 @@ parser ParserImpl(packet_in packet, out headers hdr, inout metadata meta, inout @name(".parse_mpls_bos") state parse_mpls_bos { packet.extract(hdr.mpls_bos); tmp_0 = packet.lookahead>(); - transition select(tmp_0[3:0]) { + transition select(tmp_0) { 4w0x4: parse_ipv4; default: accept; } diff --git a/testdata/p4_14_samples_outputs/parser2-first.p4 b/testdata/p4_14_samples_outputs/parser2-first.p4 index e37689b7584..ebc5c123692 100644 --- a/testdata/p4_14_samples_outputs/parser2-first.p4 +++ b/testdata/p4_14_samples_outputs/parser2-first.p4 @@ -154,7 +154,7 @@ parser ParserImpl(packet_in packet, out headers hdr, inout metadata meta, inout } @name(".parse_mpls_bos") state parse_mpls_bos { packet.extract(hdr.mpls_bos); - transition select((packet.lookahead>())[3:0]) { + transition select(packet.lookahead>()) { 4w0x4: parse_ipv4; 4w0x6: parse_ipv6; default: accept; diff --git a/testdata/p4_14_samples_outputs/parser2-frontend.p4 b/testdata/p4_14_samples_outputs/parser2-frontend.p4 index d3cadfcbe3c..982fdf5677a 100644 --- a/testdata/p4_14_samples_outputs/parser2-frontend.p4 +++ b/testdata/p4_14_samples_outputs/parser2-frontend.p4 @@ -158,7 +158,7 @@ parser ParserImpl(packet_in packet, out headers hdr, inout metadata meta, inout @name(".parse_mpls_bos") state parse_mpls_bos { packet.extract(hdr.mpls_bos); tmp_0 = packet.lookahead>(); - transition select(tmp_0[3:0]) { + transition select(tmp_0) { 4w0x4: parse_ipv4; 4w0x6: parse_ipv6; default: accept; diff --git a/testdata/p4_14_samples_outputs/parser2-midend.p4 b/testdata/p4_14_samples_outputs/parser2-midend.p4 index a3401e6415b..ee4931e2c51 100644 --- a/testdata/p4_14_samples_outputs/parser2-midend.p4 +++ b/testdata/p4_14_samples_outputs/parser2-midend.p4 @@ -158,7 +158,7 @@ parser ParserImpl(packet_in packet, out headers hdr, inout metadata meta, inout @name(".parse_mpls_bos") state parse_mpls_bos { packet.extract(hdr.mpls_bos); tmp_0 = packet.lookahead>(); - transition select(tmp_0[3:0]) { + transition select(tmp_0) { 4w0x4: parse_ipv4; 4w0x6: parse_ipv6; default: accept; diff --git a/testdata/p4_14_samples_outputs/parser4-first.p4 b/testdata/p4_14_samples_outputs/parser4-first.p4 index d5e3cafb664..d859fe3ecbd 100644 --- a/testdata/p4_14_samples_outputs/parser4-first.p4 +++ b/testdata/p4_14_samples_outputs/parser4-first.p4 @@ -80,7 +80,7 @@ parser ParserImpl(packet_in packet, out headers hdr, inout metadata meta, inout } @name(".parse_mpls_bos") state parse_mpls_bos { packet.extract(hdr.mpls_bos); - transition select((packet.lookahead>())[3:0]) { + transition select(packet.lookahead>()) { 4w0x4: parse_ipv4; default: accept; } diff --git a/testdata/p4_14_samples_outputs/parser4-frontend.p4 b/testdata/p4_14_samples_outputs/parser4-frontend.p4 index a20b670dfbd..7b9b0b761d8 100644 --- a/testdata/p4_14_samples_outputs/parser4-frontend.p4 +++ b/testdata/p4_14_samples_outputs/parser4-frontend.p4 @@ -84,7 +84,7 @@ parser ParserImpl(packet_in packet, out headers hdr, inout metadata meta, inout @name(".parse_mpls_bos") state parse_mpls_bos { packet.extract(hdr.mpls_bos); tmp_0 = packet.lookahead>(); - transition select(tmp_0[3:0]) { + transition select(tmp_0) { 4w0x4: parse_ipv4; default: accept; } diff --git a/testdata/p4_14_samples_outputs/parser4-midend.p4 b/testdata/p4_14_samples_outputs/parser4-midend.p4 index 641753180a1..2b92d95e2d6 100644 --- a/testdata/p4_14_samples_outputs/parser4-midend.p4 +++ b/testdata/p4_14_samples_outputs/parser4-midend.p4 @@ -84,7 +84,7 @@ parser ParserImpl(packet_in packet, out headers hdr, inout metadata meta, inout @name(".parse_mpls_bos") state parse_mpls_bos { packet.extract(hdr.mpls_bos); tmp_0 = packet.lookahead>(); - transition select(tmp_0[3:0]) { + transition select(tmp_0) { 4w0x4: parse_ipv4; default: accept; } diff --git a/testdata/p4_14_samples_outputs/parser_dc_full-first.p4 b/testdata/p4_14_samples_outputs/parser_dc_full-first.p4 index 62e16b79576..681f84e8eae 100644 --- a/testdata/p4_14_samples_outputs/parser_dc_full-first.p4 +++ b/testdata/p4_14_samples_outputs/parser_dc_full-first.p4 @@ -539,7 +539,7 @@ parser ParserImpl(packet_in packet, out headers hdr, inout metadata meta, inout } @name(".parse_mpls_bos") state parse_mpls_bos { packet.extract(hdr.mpls_bos); - transition select((packet.lookahead>())[3:0]) { + transition select(packet.lookahead>()) { 4w0x4: parse_inner_ipv4; 4w0x6: parse_inner_ipv6; default: parse_eompls; diff --git a/testdata/p4_14_samples_outputs/parser_dc_full-frontend.p4 b/testdata/p4_14_samples_outputs/parser_dc_full-frontend.p4 index 211a9026864..bfa95fe11ed 100644 --- a/testdata/p4_14_samples_outputs/parser_dc_full-frontend.p4 +++ b/testdata/p4_14_samples_outputs/parser_dc_full-frontend.p4 @@ -539,7 +539,7 @@ parser ParserImpl(packet_in packet, out headers hdr, inout metadata meta, inout @name(".parse_mpls_bos") state parse_mpls_bos { packet.extract(hdr.mpls_bos); tmp_0 = packet.lookahead>(); - transition select(tmp_0[3:0]) { + transition select(tmp_0) { 4w0x4: parse_inner_ipv4; 4w0x6: parse_inner_ipv6; default: parse_eompls; diff --git a/testdata/p4_14_samples_outputs/parser_dc_full-midend.p4 b/testdata/p4_14_samples_outputs/parser_dc_full-midend.p4 index af4e336d1c5..f0dba2da2ed 100644 --- a/testdata/p4_14_samples_outputs/parser_dc_full-midend.p4 +++ b/testdata/p4_14_samples_outputs/parser_dc_full-midend.p4 @@ -539,7 +539,7 @@ parser ParserImpl(packet_in packet, out headers hdr, inout metadata meta, inout @name(".parse_mpls_bos") state parse_mpls_bos { packet.extract(hdr.mpls_bos); tmp_0 = packet.lookahead>(); - transition select(tmp_0[3:0]) { + transition select(tmp_0) { 4w0x4: parse_inner_ipv4; 4w0x6: parse_inner_ipv6; default: parse_eompls; diff --git a/testdata/p4_14_samples_outputs/parser_pragma2-first.p4 b/testdata/p4_14_samples_outputs/parser_pragma2-first.p4 index 4231fc97331..5bbf797ed58 100644 --- a/testdata/p4_14_samples_outputs/parser_pragma2-first.p4 +++ b/testdata/p4_14_samples_outputs/parser_pragma2-first.p4 @@ -28,7 +28,7 @@ parser ParserImpl(packet_in packet, out headers hdr, inout metadata meta, inout transition accept; } @packet_entry @name(".start_e2e_mirrored") state start_e2e_mirrored { - transition select((packet.lookahead>())[31:0]) { + transition select(packet.lookahead>()) { default: accept; 32w0xab00: Cowles; } diff --git a/testdata/p4_14_samples_outputs/parser_pragma2-frontend.p4 b/testdata/p4_14_samples_outputs/parser_pragma2-frontend.p4 index 3289caed31a..2de9fae9374 100644 --- a/testdata/p4_14_samples_outputs/parser_pragma2-frontend.p4 +++ b/testdata/p4_14_samples_outputs/parser_pragma2-frontend.p4 @@ -30,7 +30,7 @@ parser ParserImpl(packet_in packet, out headers hdr, inout metadata meta, inout } @packet_entry @name(".start_e2e_mirrored") state start_e2e_mirrored { tmp = packet.lookahead>(); - transition select(tmp[31:0]) { + transition select(tmp) { default: accept; 32w0xab00: Cowles; } diff --git a/testdata/p4_14_samples_outputs/port_vlan_mapping-first.p4 b/testdata/p4_14_samples_outputs/port_vlan_mapping-first.p4 index 3724eef825f..960f37344d1 100644 --- a/testdata/p4_14_samples_outputs/port_vlan_mapping-first.p4 +++ b/testdata/p4_14_samples_outputs/port_vlan_mapping-first.p4 @@ -651,7 +651,7 @@ parser ParserImpl(packet_in packet, out headers hdr, inout metadata meta, inout } @name(".parse_mpls_bos") state parse_mpls_bos { packet.extract(hdr.mpls_bos); - transition select((packet.lookahead>())[3:0]) { + transition select(packet.lookahead>()) { 4w0x4: parse_inner_ipv4; 4w0x6: parse_inner_ipv6; default: parse_eompls; diff --git a/testdata/p4_14_samples_outputs/port_vlan_mapping-frontend.p4 b/testdata/p4_14_samples_outputs/port_vlan_mapping-frontend.p4 index b7098ebf624..df24f6fde5f 100644 --- a/testdata/p4_14_samples_outputs/port_vlan_mapping-frontend.p4 +++ b/testdata/p4_14_samples_outputs/port_vlan_mapping-frontend.p4 @@ -651,7 +651,7 @@ parser ParserImpl(packet_in packet, out headers hdr, inout metadata meta, inout @name(".parse_mpls_bos") state parse_mpls_bos { packet.extract(hdr.mpls_bos); tmp_0 = packet.lookahead>(); - transition select(tmp_0[3:0]) { + transition select(tmp_0) { 4w0x4: parse_inner_ipv4; 4w0x6: parse_inner_ipv6; default: parse_eompls; diff --git a/testdata/p4_14_samples_outputs/port_vlan_mapping-midend.p4 b/testdata/p4_14_samples_outputs/port_vlan_mapping-midend.p4 index cf4e52552fa..b0cf530a89a 100644 --- a/testdata/p4_14_samples_outputs/port_vlan_mapping-midend.p4 +++ b/testdata/p4_14_samples_outputs/port_vlan_mapping-midend.p4 @@ -762,7 +762,7 @@ parser ParserImpl(packet_in packet, out headers hdr, inout metadata meta, inout @name(".parse_mpls_bos") state parse_mpls_bos { packet.extract(hdr.mpls_bos); tmp_0 = packet.lookahead>(); - transition select(tmp_0[3:0]) { + transition select(tmp_0) { 4w0x4: parse_inner_ipv4; 4w0x6: parse_inner_ipv6; default: parse_eompls; diff --git a/testdata/p4_14_samples_outputs/simple_nat-first.p4 b/testdata/p4_14_samples_outputs/simple_nat-first.p4 index e0d84e2d486..94d88415aa8 100644 --- a/testdata/p4_14_samples_outputs/simple_nat-first.p4 +++ b/testdata/p4_14_samples_outputs/simple_nat-first.p4 @@ -108,7 +108,7 @@ parser ParserImpl(packet_in packet, out headers hdr, inout metadata meta, inout } @name(".start") state start { meta.meta.if_index = (bit<8>)standard_metadata.ingress_port; - transition select((packet.lookahead>())[63:0]) { + transition select(packet.lookahead>()) { 64w0: parse_cpu_header; default: parse_ethernet; } diff --git a/testdata/p4_14_samples_outputs/simple_nat-frontend.p4 b/testdata/p4_14_samples_outputs/simple_nat-frontend.p4 index fc5130fd0fc..e20a39601dc 100644 --- a/testdata/p4_14_samples_outputs/simple_nat-frontend.p4 +++ b/testdata/p4_14_samples_outputs/simple_nat-frontend.p4 @@ -110,7 +110,7 @@ parser ParserImpl(packet_in packet, out headers hdr, inout metadata meta, inout @name(".start") state start { meta.meta.if_index = (bit<8>)standard_metadata.ingress_port; tmp = packet.lookahead>(); - transition select(tmp[63:0]) { + transition select(tmp) { 64w0: parse_cpu_header; default: parse_ethernet; } diff --git a/testdata/p4_14_samples_outputs/simple_nat-midend.p4 b/testdata/p4_14_samples_outputs/simple_nat-midend.p4 index 92c8eb459c6..7f14877feb6 100644 --- a/testdata/p4_14_samples_outputs/simple_nat-midend.p4 +++ b/testdata/p4_14_samples_outputs/simple_nat-midend.p4 @@ -119,7 +119,7 @@ parser ParserImpl(packet_in packet, out headers hdr, inout metadata meta, inout @name(".start") state start { meta._meta_if_index10 = (bit<8>)standard_metadata.ingress_port; tmp = packet.lookahead>(); - transition select(tmp[63:0]) { + transition select(tmp) { 64w0: parse_cpu_header; default: parse_ethernet; } diff --git a/testdata/p4_14_samples_outputs/source_routing-first.p4 b/testdata/p4_14_samples_outputs/source_routing-first.p4 index 45b0b9df8ad..718884f870a 100644 --- a/testdata/p4_14_samples_outputs/source_routing-first.p4 +++ b/testdata/p4_14_samples_outputs/source_routing-first.p4 @@ -33,7 +33,7 @@ parser ParserImpl(packet_in packet, out headers hdr, inout metadata meta, inout transition accept; } @name(".start") state start { - transition select((packet.lookahead>())[63:0]) { + transition select(packet.lookahead>()) { 64w0: parse_head; default: accept; } diff --git a/testdata/p4_14_samples_outputs/source_routing-frontend.p4 b/testdata/p4_14_samples_outputs/source_routing-frontend.p4 index 43a9c02a25b..44bc7fc5797 100644 --- a/testdata/p4_14_samples_outputs/source_routing-frontend.p4 +++ b/testdata/p4_14_samples_outputs/source_routing-frontend.p4 @@ -35,7 +35,7 @@ parser ParserImpl(packet_in packet, out headers hdr, inout metadata meta, inout } @name(".start") state start { tmp = packet.lookahead>(); - transition select(tmp[63:0]) { + transition select(tmp) { 64w0: parse_head; default: accept; } diff --git a/testdata/p4_14_samples_outputs/source_routing-midend.p4 b/testdata/p4_14_samples_outputs/source_routing-midend.p4 index 43a9c02a25b..44bc7fc5797 100644 --- a/testdata/p4_14_samples_outputs/source_routing-midend.p4 +++ b/testdata/p4_14_samples_outputs/source_routing-midend.p4 @@ -35,7 +35,7 @@ parser ParserImpl(packet_in packet, out headers hdr, inout metadata meta, inout } @name(".start") state start { tmp = packet.lookahead>(); - transition select(tmp[63:0]) { + transition select(tmp) { 64w0: parse_head; default: accept; } diff --git a/testdata/p4_14_samples_outputs/switch_20160512/switch-first.p4 b/testdata/p4_14_samples_outputs/switch_20160512/switch-first.p4 index 5c3162395ac..f2c9d7b6f9b 100644 --- a/testdata/p4_14_samples_outputs/switch_20160512/switch-first.p4 +++ b/testdata/p4_14_samples_outputs/switch_20160512/switch-first.p4 @@ -1076,7 +1076,7 @@ parser ParserImpl(packet_in packet, out headers hdr, inout metadata meta, inout } @name(".parse_lisp") state parse_lisp { packet.extract(hdr.lisp); - transition select((packet.lookahead>())[3:0]) { + transition select(packet.lookahead>()) { 4w0x4: parse_inner_ipv4; 4w0x6: parse_inner_ipv6; default: accept; @@ -1099,7 +1099,7 @@ parser ParserImpl(packet_in packet, out headers hdr, inout metadata meta, inout } } @name(".parse_mpls_bos") state parse_mpls_bos { - transition select((packet.lookahead>())[3:0]) { + transition select(packet.lookahead>()) { 4w0x4: parse_mpls_inner_ipv4; 4w0x6: parse_mpls_inner_ipv6; default: parse_eompls; @@ -2437,7 +2437,7 @@ control process_tunnel_encap(inout headers hdr, inout metadata meta, inout stand hdr.gre.S = 1w0; hdr.gre.s = 1w0; hdr.nvgre.tni = meta.tunnel_metadata.vnid; - hdr.nvgre.flow_id[7:0] = ((bit<8>)meta.hash_metadata.entropy_hash)[7:0]; + hdr.nvgre.flow_id = (bit<8>)meta.hash_metadata.entropy_hash; } @name(".ipv4_nvgre_rewrite") action ipv4_nvgre_rewrite() { f_insert_nvgre_header(); diff --git a/testdata/p4_14_samples_outputs/switch_20160512/switch-frontend.p4 b/testdata/p4_14_samples_outputs/switch_20160512/switch-frontend.p4 index 4e5157b98c6..db25c309211 100644 --- a/testdata/p4_14_samples_outputs/switch_20160512/switch-frontend.p4 +++ b/testdata/p4_14_samples_outputs/switch_20160512/switch-frontend.p4 @@ -1074,7 +1074,7 @@ parser ParserImpl(packet_in packet, out headers hdr, inout metadata meta, inout } @name(".parse_mpls_bos") state parse_mpls_bos { tmp = packet.lookahead>(); - transition select(tmp[3:0]) { + transition select(tmp) { 4w0x4: parse_mpls_inner_ipv4; 4w0x6: parse_mpls_inner_ipv6; default: parse_eompls; @@ -2461,7 +2461,7 @@ control egress(inout headers hdr, inout metadata meta, inout standard_metadata_t hdr.gre.S = 1w0; hdr.gre.s = 1w0; hdr.nvgre.tni = meta.tunnel_metadata.vnid; - hdr.nvgre.flow_id[7:0] = ((bit<8>)meta.hash_metadata.entropy_hash)[7:0]; + hdr.nvgre.flow_id = (bit<8>)meta.hash_metadata.entropy_hash; hdr.ipv4.setValid(); hdr.ipv4.protocol = 8w47; hdr.ipv4.ttl = 8w64; @@ -2554,7 +2554,7 @@ control egress(inout headers hdr, inout metadata meta, inout standard_metadata_t hdr.gre.S = 1w0; hdr.gre.s = 1w0; hdr.nvgre.tni = meta.tunnel_metadata.vnid; - hdr.nvgre.flow_id[7:0] = ((bit<8>)meta.hash_metadata.entropy_hash)[7:0]; + hdr.nvgre.flow_id = (bit<8>)meta.hash_metadata.entropy_hash; hdr.ipv6.setValid(); hdr.ipv6.version = 4w0x6; hdr.ipv6.nextHdr = 8w47; diff --git a/testdata/p4_14_samples_outputs/switch_20160512/switch-midend.p4 b/testdata/p4_14_samples_outputs/switch_20160512/switch-midend.p4 index 8186186aa48..d725f4f6d64 100644 --- a/testdata/p4_14_samples_outputs/switch_20160512/switch-midend.p4 +++ b/testdata/p4_14_samples_outputs/switch_20160512/switch-midend.p4 @@ -1175,7 +1175,7 @@ parser ParserImpl(packet_in packet, out headers hdr, inout metadata meta, inout } @name(".parse_mpls_bos") state parse_mpls_bos { tmp = packet.lookahead>(); - transition select(tmp[3:0]) { + transition select(tmp) { 4w0x4: parse_mpls_inner_ipv4; 4w0x6: parse_mpls_inner_ipv6; default: parse_eompls; @@ -2578,7 +2578,7 @@ control egress(inout headers hdr, inout metadata meta, inout standard_metadata_t hdr.gre.S = 1w0; hdr.gre.s = 1w0; hdr.nvgre.tni = meta._tunnel_metadata_vnid149; - hdr.nvgre.flow_id[7:0] = ((bit<8>)meta._hash_metadata_entropy_hash34)[7:0]; + hdr.nvgre.flow_id = (bit<8>)meta._hash_metadata_entropy_hash34; hdr.ipv4.setValid(); hdr.ipv4.protocol = 8w47; hdr.ipv4.ttl = 8w64; @@ -2671,7 +2671,7 @@ control egress(inout headers hdr, inout metadata meta, inout standard_metadata_t hdr.gre.S = 1w0; hdr.gre.s = 1w0; hdr.nvgre.tni = meta._tunnel_metadata_vnid149; - hdr.nvgre.flow_id[7:0] = ((bit<8>)meta._hash_metadata_entropy_hash34)[7:0]; + hdr.nvgre.flow_id = (bit<8>)meta._hash_metadata_entropy_hash34; hdr.ipv6.setValid(); hdr.ipv6.version = 4w0x6; hdr.ipv6.nextHdr = 8w47; diff --git a/testdata/p4_16_errors/slice_out_of_bound.p4 b/testdata/p4_16_errors/slice_out_of_bound.p4 new file mode 100644 index 00000000000..9b9f12b75d8 --- /dev/null +++ b/testdata/p4_16_errors/slice_out_of_bound.p4 @@ -0,0 +1,117 @@ +/* +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 +#include + +// This program processes packets composed of an Ethernet and +// an IPv4 header, performing forwarding based on the +// destination IP address + +typedef bit<48> EthernetAddress; +typedef bit<32> IPv4Address; + +// standard Ethernet header +header Ethernet_h { + EthernetAddress dstAddr; + EthernetAddress srcAddr; + bit<16> etherType; +} + +// IPv4 header without options +header Ipv4_h { + bit<4> version; + bit<4> ihl; + bit<8> diffserv; + bit<16> totalLen; + bit<16> identification; + bit<3> flags; + bit<13> fragOffset; + bit<8> ttl; + bit<8> protocol; + bit<16> hdrChecksum; + IPv4Address srcAddr; + IPv4Address dstAddr; +} + +// Parser section + +// List of all recognized headers +struct Headers { + Ethernet_h ethernet; + Ipv4_h ip; +} + +struct Metadata { +} + +parser P(packet_in b, + out Headers p, + inout Metadata meta, + inout standard_metadata_t standard_meta) { + state start { + transition accept; + } +} + +// match-action pipeline section + +control Ing(inout Headers headers, + inout Metadata meta, + inout standard_metadata_t standard_meta) { + + register>(32w2) debug; + + apply { + bit<8> n = 8w0b11111111; + n[7:4][5:2] = 4w0; + debug.write(1, n); + standard_meta.egress_spec = 0; + } +} + +control Eg(inout Headers hdrs, + inout Metadata meta, + inout standard_metadata_t standard_meta) { + + apply { + } +} + +// deparser section +control DP(packet_out b, in Headers p) { + apply { + b.emit(p.ethernet); + b.emit(p.ip); + } +} + +// Fillers +control Verify(inout Headers hdrs, inout Metadata meta) { + apply {} +} + +control Compute(inout Headers hdr, inout Metadata meta) { + apply {} +} + +// Instantiate the top-level V1 Model package. +V1Switch(P(), + Verify(), + Ing(), + Eg(), + Compute(), + DP()) main; diff --git a/testdata/p4_16_errors_outputs/slice_out_of_bound.p4 b/testdata/p4_16_errors_outputs/slice_out_of_bound.p4 new file mode 100644 index 00000000000..10127b1f18c --- /dev/null +++ b/testdata/p4_16_errors_outputs/slice_out_of_bound.p4 @@ -0,0 +1,74 @@ +#include +#include + +typedef bit<48> EthernetAddress; +typedef bit<32> IPv4Address; +header Ethernet_h { + EthernetAddress dstAddr; + EthernetAddress srcAddr; + bit<16> etherType; +} + +header Ipv4_h { + bit<4> version; + bit<4> ihl; + bit<8> diffserv; + bit<16> totalLen; + bit<16> identification; + bit<3> flags; + bit<13> fragOffset; + bit<8> ttl; + bit<8> protocol; + bit<16> hdrChecksum; + IPv4Address srcAddr; + IPv4Address dstAddr; +} + +struct Headers { + Ethernet_h ethernet; + Ipv4_h ip; +} + +struct Metadata { +} + +parser P(packet_in b, out Headers p, inout Metadata meta, inout standard_metadata_t standard_meta) { + state start { + transition accept; + } +} + +control Ing(inout Headers headers, inout Metadata meta, inout standard_metadata_t standard_meta) { + register>(32w2) debug; + apply { + bit<8> n = 8w0b11111111; + n[7:4][5:2] = 4w0; + debug.write(1, n); + standard_meta.egress_spec = 0; + } +} + +control Eg(inout Headers hdrs, inout Metadata meta, inout standard_metadata_t standard_meta) { + apply { + } +} + +control DP(packet_out b, in Headers p) { + apply { + b.emit(p.ethernet); + b.emit(p.ip); + } +} + +control Verify(inout Headers hdrs, inout Metadata meta) { + apply { + } +} + +control Compute(inout Headers hdr, inout Metadata meta) { + apply { + } +} + +V1Switch(P(), Verify(), Ing(), Eg(), Compute(), DP()) main; + diff --git a/testdata/p4_16_errors_outputs/slice_out_of_bound.p4-stderr b/testdata/p4_16_errors_outputs/slice_out_of_bound.p4-stderr new file mode 100644 index 00000000000..b770a5d1cb3 --- /dev/null +++ b/testdata/p4_16_errors_outputs/slice_out_of_bound.p4-stderr @@ -0,0 +1,3 @@ +slice_out_of_bound.p4(80): [--Werror=type-error] error: Bit index 5 greater than width 4 + n[7:4][5:2] = 4w0; + ^ diff --git a/testdata/p4_16_samples/simplify_slice.p4 b/testdata/p4_16_samples/simplify_slice.p4 new file mode 100644 index 00000000000..1bf5e03ea59 --- /dev/null +++ b/testdata/p4_16_samples/simplify_slice.p4 @@ -0,0 +1,121 @@ +/* +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 +#include + +// This program processes packets composed of an Ethernet and +// an IPv4 header, performing forwarding based on the +// destination IP address + +typedef bit<48> EthernetAddress; +typedef bit<32> IPv4Address; + +// standard Ethernet header +header Ethernet_h { + EthernetAddress dstAddr; + EthernetAddress srcAddr; + bit<16> etherType; +} + +// IPv4 header without options +header Ipv4_h { + bit<4> version; + bit<4> ihl; + bit<8> diffserv; + bit<16> totalLen; + bit<16> identification; + bit<3> flags; + bit<13> fragOffset; + bit<8> ttl; + bit<8> protocol; + bit<16> hdrChecksum; + IPv4Address srcAddr; + IPv4Address dstAddr; +} + +// Parser section + +// List of all recognized headers +struct Headers { + Ethernet_h ethernet; + Ipv4_h ip; +} + +struct Metadata { +} + +parser P(packet_in b, + out Headers p, + inout Metadata meta, + inout standard_metadata_t standard_meta) { + state start { + transition accept; + } +} + +// match-action pipeline section + +control Ing(inout Headers headers, + inout Metadata meta, + inout standard_metadata_t standard_meta) { + + register>(32w2) debug; + + apply { + bit<8> n = 8w0b11111111; + bit<8> m = 8w0b11111111; + bit<8> x = 8w0b11111111; + n[7:4][3:0][3:0] = 4w0; + m[7:4][3:1] = 3w0; + x[5:4][1:1] = 1w0; + debug.write(1, n); + standard_meta.egress_spec = 0; + } +} + +control Eg(inout Headers hdrs, + inout Metadata meta, + inout standard_metadata_t standard_meta) { + + apply { + } +} + +// deparser section +control DP(packet_out b, in Headers p) { + apply { + b.emit(p.ethernet); + b.emit(p.ip); + } +} + +// Fillers +control Verify(inout Headers hdrs, inout Metadata meta) { + apply {} +} + +control Compute(inout Headers hdr, inout Metadata meta) { + apply {} +} + +// Instantiate the top-level V1 Model package. +V1Switch(P(), + Verify(), + Ing(), + Eg(), + Compute(), + DP()) main; diff --git a/testdata/p4_16_samples_outputs/issue1713-bmv2-first.p4 b/testdata/p4_16_samples_outputs/issue1713-bmv2-first.p4 index 0c8e6805ebe..135ce391163 100644 --- a/testdata/p4_16_samples_outputs/issue1713-bmv2-first.p4 +++ b/testdata/p4_16_samples_outputs/issue1713-bmv2-first.p4 @@ -21,13 +21,13 @@ control ingress(inout Headers h, inout Meta m, inout standard_metadata_t sm) { h.h.c = ((bit<12>)h.h.a)[11:4]; } action case1() { - h.h.c = (bit<8>)h.h.a[14:3][8:4]; + h.h.c = (bit<8>)h.h.a[11:7]; } action case2() { h.h.c = (bit<8>)(16w0[15:0] ++ h.h.a[15:8]); } action case3() { - h.h.c = ((int<32>)(int<16>)h.h.a)[14:2][10:3]; + h.h.c = ((int<32>)(int<16>)h.h.a)[12:5]; } table t { actions = { diff --git a/testdata/p4_16_samples_outputs/issue1713-bmv2-frontend.p4 b/testdata/p4_16_samples_outputs/issue1713-bmv2-frontend.p4 index 2d14fba9a20..2ec387ceb62 100644 --- a/testdata/p4_16_samples_outputs/issue1713-bmv2-frontend.p4 +++ b/testdata/p4_16_samples_outputs/issue1713-bmv2-frontend.p4 @@ -21,13 +21,13 @@ control ingress(inout Headers h, inout Meta m, inout standard_metadata_t sm) { h.h.c = ((bit<12>)h.h.a)[11:4]; } @name("ingress.case1") action case1() { - h.h.c = (bit<8>)h.h.a[14:3][8:4]; + h.h.c = (bit<8>)h.h.a[11:7]; } @name("ingress.case2") action case2() { h.h.c = (bit<8>)(16w0 ++ h.h.a[15:8]); } @name("ingress.case3") action case3() { - h.h.c = ((int<32>)(int<16>)h.h.a)[14:2][10:3]; + h.h.c = ((int<32>)(int<16>)h.h.a)[12:5]; } @name("ingress.t") table t_0 { actions = { diff --git a/testdata/p4_16_samples_outputs/issue1713-bmv2-midend.p4 b/testdata/p4_16_samples_outputs/issue1713-bmv2-midend.p4 index 2d14fba9a20..2ec387ceb62 100644 --- a/testdata/p4_16_samples_outputs/issue1713-bmv2-midend.p4 +++ b/testdata/p4_16_samples_outputs/issue1713-bmv2-midend.p4 @@ -21,13 +21,13 @@ control ingress(inout Headers h, inout Meta m, inout standard_metadata_t sm) { h.h.c = ((bit<12>)h.h.a)[11:4]; } @name("ingress.case1") action case1() { - h.h.c = (bit<8>)h.h.a[14:3][8:4]; + h.h.c = (bit<8>)h.h.a[11:7]; } @name("ingress.case2") action case2() { h.h.c = (bit<8>)(16w0 ++ h.h.a[15:8]); } @name("ingress.case3") action case3() { - h.h.c = ((int<32>)(int<16>)h.h.a)[14:2][10:3]; + h.h.c = ((int<32>)(int<16>)h.h.a)[12:5]; } @name("ingress.t") table t_0 { actions = { diff --git a/testdata/p4_16_samples_outputs/issue2105-first.p4 b/testdata/p4_16_samples_outputs/issue2105-first.p4 index e35cd13aa1a..c00edbb0a0d 100644 --- a/testdata/p4_16_samples_outputs/issue2105-first.p4 +++ b/testdata/p4_16_samples_outputs/issue2105-first.p4 @@ -13,7 +13,7 @@ control c() { apply { bit<8> x = 8w0; bit<8> y = 8w0; - y = (x < 8w4 ? 8w2 : 8w1)[7:0] | 8w8; + y = (x < 8w4 ? 8w2 : 8w1) | 8w8; } } diff --git a/testdata/p4_16_samples_outputs/issue648-first.p4 b/testdata/p4_16_samples_outputs/issue648-first.p4 index 7aac2e73217..74660000d31 100644 --- a/testdata/p4_16_samples_outputs/issue648-first.p4 +++ b/testdata/p4_16_samples_outputs/issue648-first.p4 @@ -9,7 +9,7 @@ header hdr { control ingress(inout hdr h) { apply { h.a[7:0] = ((bit<32>)h.c)[7:0]; - h.a[15:8] = (h.c + h.c)[7:0]; + h.a[15:8] = h.c + h.c; } } diff --git a/testdata/p4_16_samples_outputs/issue648-frontend.p4 b/testdata/p4_16_samples_outputs/issue648-frontend.p4 index 7aac2e73217..74660000d31 100644 --- a/testdata/p4_16_samples_outputs/issue648-frontend.p4 +++ b/testdata/p4_16_samples_outputs/issue648-frontend.p4 @@ -9,7 +9,7 @@ header hdr { control ingress(inout hdr h) { apply { h.a[7:0] = ((bit<32>)h.c)[7:0]; - h.a[15:8] = (h.c + h.c)[7:0]; + h.a[15:8] = h.c + h.c; } } diff --git a/testdata/p4_16_samples_outputs/issue648-midend.p4 b/testdata/p4_16_samples_outputs/issue648-midend.p4 index 07ad86317ef..5232e8021d5 100644 --- a/testdata/p4_16_samples_outputs/issue648-midend.p4 +++ b/testdata/p4_16_samples_outputs/issue648-midend.p4 @@ -9,7 +9,7 @@ header hdr { control ingress(inout hdr h) { @hidden action issue648l11() { h.a[7:0] = ((bit<32>)h.c)[7:0]; - h.a[15:8] = (h.c + h.c)[7:0]; + h.a[15:8] = h.c + h.c; } @hidden table tbl_issue648l11 { actions = { diff --git a/testdata/p4_16_samples_outputs/issue870_ebpf-first.p4 b/testdata/p4_16_samples_outputs/issue870_ebpf-first.p4 index 5a8ca8c3960..83f08c36595 100644 --- a/testdata/p4_16_samples_outputs/issue870_ebpf-first.p4 +++ b/testdata/p4_16_samples_outputs/issue870_ebpf-first.p4 @@ -46,7 +46,7 @@ parser prs(packet_in p, out Headers_t headers) { control pipe(inout Headers_t headers, out bool pass) { action Reject(IPv4Address add) { pass = false; - headers.ipv4.srcAddr[31:0] = add[31:16] ++ add[15:0]; + headers.ipv4.srcAddr = add[31:16] ++ add[15:0]; } table Check_src_ip { key = { diff --git a/testdata/p4_16_samples_outputs/issue870_ebpf-frontend.p4 b/testdata/p4_16_samples_outputs/issue870_ebpf-frontend.p4 index 8cc332571e7..2cc0f13ae01 100644 --- a/testdata/p4_16_samples_outputs/issue870_ebpf-frontend.p4 +++ b/testdata/p4_16_samples_outputs/issue870_ebpf-frontend.p4 @@ -48,7 +48,7 @@ control pipe(inout Headers_t headers, out bool pass) { } @name("pipe.Reject") action Reject(IPv4Address add) { pass = false; - headers.ipv4.srcAddr[31:0] = add[31:16] ++ add[15:0]; + headers.ipv4.srcAddr = add[31:16] ++ add[15:0]; } @name("pipe.Check_src_ip") table Check_src_ip_0 { key = { diff --git a/testdata/p4_16_samples_outputs/issue870_ebpf-midend.p4 b/testdata/p4_16_samples_outputs/issue870_ebpf-midend.p4 index e92283a2a86..3d9cd146baa 100644 --- a/testdata/p4_16_samples_outputs/issue870_ebpf-midend.p4 +++ b/testdata/p4_16_samples_outputs/issue870_ebpf-midend.p4 @@ -49,7 +49,7 @@ control pipe(inout Headers_t headers, out bool pass) { } @name("pipe.Reject") action Reject(IPv4Address add) { pass = false; - headers.ipv4.srcAddr[31:0] = add[31:16] ++ add[15:0]; + headers.ipv4.srcAddr = add[31:16] ++ add[15:0]; } @name("pipe.Check_src_ip") table Check_src_ip_0 { key = { diff --git a/testdata/p4_16_samples_outputs/side_effects-first.p4 b/testdata/p4_16_samples_outputs/side_effects-first.p4 index e24f378f6e2..d1c36bb7f16 100644 --- a/testdata/p4_16_samples_outputs/side_effects-first.p4 +++ b/testdata/p4_16_samples_outputs/side_effects-first.p4 @@ -14,7 +14,7 @@ control my() { a = f(s[a].z, g(a)); a = f(s[g(a)].z, a); a = g(a); - a[0:0] = g(a[0:0]); + a = g(a); s[a].z = g(a); } } diff --git a/testdata/p4_16_samples_outputs/side_effects-frontend.p4 b/testdata/p4_16_samples_outputs/side_effects-frontend.p4 index c32371f21bb..c9453bf2e1b 100644 --- a/testdata/p4_16_samples_outputs/side_effects-frontend.p4 +++ b/testdata/p4_16_samples_outputs/side_effects-frontend.p4 @@ -32,7 +32,7 @@ control my() { s_0[tmp_4].z = tmp_5; a_0 = tmp_6; a_0 = g(a_0); - a_0[0:0] = g(a_0[0:0]); + a_0 = g(a_0); g(a_0); } } diff --git a/testdata/p4_16_samples_outputs/side_effects-midend.p4 b/testdata/p4_16_samples_outputs/side_effects-midend.p4 index 50b033a32e2..5401361cdc0 100644 --- a/testdata/p4_16_samples_outputs/side_effects-midend.p4 +++ b/testdata/p4_16_samples_outputs/side_effects-midend.p4 @@ -26,7 +26,7 @@ control my() { s_0[tmp_3].z = tmp_5; a_0 = tmp_6; a_0 = g(a_0); - a_0[0:0] = g(a_0[0:0]); + a_0 = g(a_0); g(a_0); } @hidden table tbl_side_effects27 { diff --git a/testdata/p4_16_samples_outputs/simplify_slice-first.p4 b/testdata/p4_16_samples_outputs/simplify_slice-first.p4 new file mode 100644 index 00000000000..ac402a480b9 --- /dev/null +++ b/testdata/p4_16_samples_outputs/simplify_slice-first.p4 @@ -0,0 +1,78 @@ +#include +#include + +typedef bit<48> EthernetAddress; +typedef bit<32> IPv4Address; +header Ethernet_h { + EthernetAddress dstAddr; + EthernetAddress srcAddr; + bit<16> etherType; +} + +header Ipv4_h { + bit<4> version; + bit<4> ihl; + bit<8> diffserv; + bit<16> totalLen; + bit<16> identification; + bit<3> flags; + bit<13> fragOffset; + bit<8> ttl; + bit<8> protocol; + bit<16> hdrChecksum; + IPv4Address srcAddr; + IPv4Address dstAddr; +} + +struct Headers { + Ethernet_h ethernet; + Ipv4_h ip; +} + +struct Metadata { +} + +parser P(packet_in b, out Headers p, inout Metadata meta, inout standard_metadata_t standard_meta) { + state start { + transition accept; + } +} + +control Ing(inout Headers headers, inout Metadata meta, inout standard_metadata_t standard_meta) { + register>(32w2) debug; + apply { + bit<8> n = 8w0b11111111; + bit<8> m = 8w0b11111111; + bit<8> x = 8w0b11111111; + n[7:4] = 4w0; + m[7:5] = 3w0; + x[5:5] = 1w0; + debug.write(32w1, n); + standard_meta.egress_spec = 9w0; + } +} + +control Eg(inout Headers hdrs, inout Metadata meta, inout standard_metadata_t standard_meta) { + apply { + } +} + +control DP(packet_out b, in Headers p) { + apply { + b.emit(p.ethernet); + b.emit(p.ip); + } +} + +control Verify(inout Headers hdrs, inout Metadata meta) { + apply { + } +} + +control Compute(inout Headers hdr, inout Metadata meta) { + apply { + } +} + +V1Switch(P(), Verify(), Ing(), Eg(), Compute(), DP()) main; + diff --git a/testdata/p4_16_samples_outputs/simplify_slice-frontend.p4 b/testdata/p4_16_samples_outputs/simplify_slice-frontend.p4 new file mode 100644 index 00000000000..7813dab578b --- /dev/null +++ b/testdata/p4_16_samples_outputs/simplify_slice-frontend.p4 @@ -0,0 +1,79 @@ +#include +#include + +typedef bit<48> EthernetAddress; +typedef bit<32> IPv4Address; +header Ethernet_h { + EthernetAddress dstAddr; + EthernetAddress srcAddr; + bit<16> etherType; +} + +header Ipv4_h { + bit<4> version; + bit<4> ihl; + bit<8> diffserv; + bit<16> totalLen; + bit<16> identification; + bit<3> flags; + bit<13> fragOffset; + bit<8> ttl; + bit<8> protocol; + bit<16> hdrChecksum; + IPv4Address srcAddr; + IPv4Address dstAddr; +} + +struct Headers { + Ethernet_h ethernet; + Ipv4_h ip; +} + +struct Metadata { +} + +parser P(packet_in b, out Headers p, inout Metadata meta, inout standard_metadata_t standard_meta) { + state start { + transition accept; + } +} + +control Ing(inout Headers headers, inout Metadata meta, inout standard_metadata_t standard_meta) { + bit<8> n_0; + bit<8> m_0; + bit<8> x_0; + @name("Ing.debug") register>(32w2) debug_0; + apply { + n_0 = 8w0b11111111; + m_0 = 8w0b11111111; + x_0 = 8w0b11111111; + n_0[7:4] = 4w0; + debug_0.write(32w1, n_0); + standard_meta.egress_spec = 9w0; + } +} + +control Eg(inout Headers hdrs, inout Metadata meta, inout standard_metadata_t standard_meta) { + apply { + } +} + +control DP(packet_out b, in Headers p) { + apply { + b.emit(p.ethernet); + b.emit(p.ip); + } +} + +control Verify(inout Headers hdrs, inout Metadata meta) { + apply { + } +} + +control Compute(inout Headers hdr, inout Metadata meta) { + apply { + } +} + +V1Switch(P(), Verify(), Ing(), Eg(), Compute(), DP()) main; + diff --git a/testdata/p4_16_samples_outputs/simplify_slice-midend.p4 b/testdata/p4_16_samples_outputs/simplify_slice-midend.p4 new file mode 100644 index 00000000000..abd15e2c386 --- /dev/null +++ b/testdata/p4_16_samples_outputs/simplify_slice-midend.p4 @@ -0,0 +1,84 @@ +#include +#include + +typedef bit<48> EthernetAddress; +typedef bit<32> IPv4Address; +header Ethernet_h { + EthernetAddress dstAddr; + EthernetAddress srcAddr; + bit<16> etherType; +} + +header Ipv4_h { + bit<4> version; + bit<4> ihl; + bit<8> diffserv; + bit<16> totalLen; + bit<16> identification; + bit<3> flags; + bit<13> fragOffset; + bit<8> ttl; + bit<8> protocol; + bit<16> hdrChecksum; + IPv4Address srcAddr; + IPv4Address dstAddr; +} + +struct Headers { + Ethernet_h ethernet; + Ipv4_h ip; +} + +struct Metadata { +} + +parser P(packet_in b, out Headers p, inout Metadata meta, inout standard_metadata_t standard_meta) { + state start { + transition accept; + } +} + +control Ing(inout Headers headers, inout Metadata meta, inout standard_metadata_t standard_meta) { + bit<8> n_0; + @name("Ing.debug") register>(32w2) debug_0; + @hidden action simplify_slice79() { + n_0 = 8w0b11111111; + n_0[7:4] = 4w0; + debug_0.write(32w1, n_0); + standard_meta.egress_spec = 9w0; + } + @hidden table tbl_simplify_slice79 { + actions = { + simplify_slice79(); + } + const default_action = simplify_slice79(); + } + apply { + tbl_simplify_slice79.apply(); + } +} + +control Eg(inout Headers hdrs, inout Metadata meta, inout standard_metadata_t standard_meta) { + apply { + } +} + +control DP(packet_out b, in Headers p) { + apply { + b.emit(p.ethernet); + b.emit(p.ip); + } +} + +control Verify(inout Headers hdrs, inout Metadata meta) { + apply { + } +} + +control Compute(inout Headers hdr, inout Metadata meta) { + apply { + } +} + +V1Switch(P(), Verify(), Ing(), Eg(), Compute(), DP()) main; + diff --git a/testdata/p4_16_samples_outputs/simplify_slice.p4 b/testdata/p4_16_samples_outputs/simplify_slice.p4 new file mode 100644 index 00000000000..7a89a9d528f --- /dev/null +++ b/testdata/p4_16_samples_outputs/simplify_slice.p4 @@ -0,0 +1,78 @@ +#include +#include + +typedef bit<48> EthernetAddress; +typedef bit<32> IPv4Address; +header Ethernet_h { + EthernetAddress dstAddr; + EthernetAddress srcAddr; + bit<16> etherType; +} + +header Ipv4_h { + bit<4> version; + bit<4> ihl; + bit<8> diffserv; + bit<16> totalLen; + bit<16> identification; + bit<3> flags; + bit<13> fragOffset; + bit<8> ttl; + bit<8> protocol; + bit<16> hdrChecksum; + IPv4Address srcAddr; + IPv4Address dstAddr; +} + +struct Headers { + Ethernet_h ethernet; + Ipv4_h ip; +} + +struct Metadata { +} + +parser P(packet_in b, out Headers p, inout Metadata meta, inout standard_metadata_t standard_meta) { + state start { + transition accept; + } +} + +control Ing(inout Headers headers, inout Metadata meta, inout standard_metadata_t standard_meta) { + register>(32w2) debug; + apply { + bit<8> n = 8w0b11111111; + bit<8> m = 8w0b11111111; + bit<8> x = 8w0b11111111; + n[7:4][3:0][3:0] = 4w0; + m[7:4][3:1] = 3w0; + x[5:4][1:1] = 1w0; + debug.write(1, n); + standard_meta.egress_spec = 0; + } +} + +control Eg(inout Headers hdrs, inout Metadata meta, inout standard_metadata_t standard_meta) { + apply { + } +} + +control DP(packet_out b, in Headers p) { + apply { + b.emit(p.ethernet); + b.emit(p.ip); + } +} + +control Verify(inout Headers hdrs, inout Metadata meta) { + apply { + } +} + +control Compute(inout Headers hdr, inout Metadata meta) { + apply { + } +} + +V1Switch(P(), Verify(), Ing(), Eg(), Compute(), DP()) main; + diff --git a/testdata/p4_16_samples_outputs/simplify_slice.p4-stderr b/testdata/p4_16_samples_outputs/simplify_slice.p4-stderr new file mode 100644 index 00000000000..e69de29bb2d diff --git a/testdata/p4_16_samples_outputs/simplify_slice.p4.entries.txt b/testdata/p4_16_samples_outputs/simplify_slice.p4.entries.txt new file mode 100644 index 00000000000..e69de29bb2d diff --git a/testdata/p4_16_samples_outputs/simplify_slice.p4.p4info.txt b/testdata/p4_16_samples_outputs/simplify_slice.p4.p4info.txt new file mode 100644 index 00000000000..3853fcbec7e --- /dev/null +++ b/testdata/p4_16_samples_outputs/simplify_slice.p4.p4info.txt @@ -0,0 +1,20 @@ +pkg_info { + arch: "v1model" +} +registers { + preamble { + id: 369100749 + name: "Ing.debug" + alias: "debug" + } + type_spec { + bitstring { + bit { + bitwidth: 8 + } + } + } + size: 2 +} +type_info { +} diff --git a/testdata/p4_16_samples_outputs/strength3-first.p4 b/testdata/p4_16_samples_outputs/strength3-first.p4 index 5c01d66b711..c0cd5c1f23f 100644 --- a/testdata/p4_16_samples_outputs/strength3-first.p4 +++ b/testdata/p4_16_samples_outputs/strength3-first.p4 @@ -21,10 +21,10 @@ control ingress(inout Headers h, inout Meta m, inout standard_metadata_t sm) { h.h.c = (bit<8>)((16w0 ++ h.h.a)[15:0] ++ 16w0[15:0]); } action case1() { - h.h.c = (bit<8>)h.h.a[15:0]; + h.h.c = (bit<8>)h.h.a; } action case2() { - h.h.c = (bit<8>)16w0[15:0]; + h.h.c = (bit<8>)16w0; } action case3() { h.h.c = h.h.a[7:0]; diff --git a/testdata/p4_16_samples_outputs/strength3-frontend.p4 b/testdata/p4_16_samples_outputs/strength3-frontend.p4 index ba36ffcb03f..c3b8aedad9d 100644 --- a/testdata/p4_16_samples_outputs/strength3-frontend.p4 +++ b/testdata/p4_16_samples_outputs/strength3-frontend.p4 @@ -21,7 +21,7 @@ control ingress(inout Headers h, inout Meta m, inout standard_metadata_t sm) { h.h.c = (bit<8>)((16w0 ++ h.h.a)[15:0] ++ 16w0); } @name("ingress.case1") action case1() { - h.h.c = (bit<8>)h.h.a[15:0]; + h.h.c = (bit<8>)h.h.a; } @name("ingress.case2") action case2() { h.h.c = 8w0; diff --git a/testdata/p4_16_samples_outputs/strength3-midend.p4 b/testdata/p4_16_samples_outputs/strength3-midend.p4 index a25d7f2cfde..6c0380d97d9 100644 --- a/testdata/p4_16_samples_outputs/strength3-midend.p4 +++ b/testdata/p4_16_samples_outputs/strength3-midend.p4 @@ -18,10 +18,10 @@ struct Meta { control ingress(inout Headers h, inout Meta m, inout standard_metadata_t sm) { @name("ingress.case0") action case0() { - h.h.c = (bit<8>)(h.h.a[15:0] ++ 16w0); + h.h.c = (bit<8>)(h.h.a ++ 16w0); } @name("ingress.case1") action case1() { - h.h.c = (bit<8>)h.h.a[15:0]; + h.h.c = (bit<8>)h.h.a; } @name("ingress.case2") action case2() { h.h.c = 8w0; @@ -30,7 +30,7 @@ control ingress(inout Headers h, inout Meta m, inout standard_metadata_t sm) { h.h.c = h.h.a[7:0]; } @name("ingress.case4") action case4() { - h.h.c = (bit<8>)(8w0 ++ h.h.a[15:0]); + h.h.c = (bit<8>)(8w0 ++ h.h.a); } @name("ingress.case5") action case5() { h.h.c = (bit<8>)(8w0 ++ h.h.a[15:8]); From 350ab864ca7ecb23e29049b199e5bdb6509ff73e Mon Sep 17 00:00:00 2001 From: Andy Fingerhut Date: Tue, 21 Jan 2020 13:33:58 -0800 Subject: [PATCH 060/106] Add test program that tests catching of incorrect lpm const entries (#2145) --- testdata/p4_16_errors/table-entries-lpm-2.p4 | 92 +++++++++++++++ .../table-entries-lpm-2-first.p4 | 83 ++++++++++++++ .../table-entries-lpm-2-frontend.p4 | 83 ++++++++++++++ .../table-entries-lpm-2-midend.p4 | 83 ++++++++++++++ .../table-entries-lpm-2.p4 | 83 ++++++++++++++ .../table-entries-lpm-2.p4-stderr | 21 ++++ .../table-entries-lpm-2.p4.entries.txt | 106 ++++++++++++++++++ .../table-entries-lpm-2.p4.p4info.txt | 43 +++++++ 8 files changed, 594 insertions(+) create mode 100644 testdata/p4_16_errors/table-entries-lpm-2.p4 create mode 100644 testdata/p4_16_errors_outputs/table-entries-lpm-2-first.p4 create mode 100644 testdata/p4_16_errors_outputs/table-entries-lpm-2-frontend.p4 create mode 100644 testdata/p4_16_errors_outputs/table-entries-lpm-2-midend.p4 create mode 100644 testdata/p4_16_errors_outputs/table-entries-lpm-2.p4 create mode 100644 testdata/p4_16_errors_outputs/table-entries-lpm-2.p4-stderr create mode 100644 testdata/p4_16_errors_outputs/table-entries-lpm-2.p4.entries.txt create mode 100644 testdata/p4_16_errors_outputs/table-entries-lpm-2.p4.p4info.txt diff --git a/testdata/p4_16_errors/table-entries-lpm-2.p4 b/testdata/p4_16_errors/table-entries-lpm-2.p4 new file mode 100644 index 00000000000..a75002eaf41 --- /dev/null +++ b/testdata/p4_16_errors/table-entries-lpm-2.p4 @@ -0,0 +1,92 @@ +/* +Copyright 2020 Cisco Systems, 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 +#include + +header hdr { + bit<8> e; + bit<16> t; + bit<8> l; + bit<8> r; + bit<8> v; +} + +struct Header_t { + hdr h; +} +struct Meta_t {} + +parser p(packet_in b, out Header_t h, inout Meta_t m, inout standard_metadata_t sm) { + state start { + b.extract(h.h); + transition accept; + } +} + +control vrfy(inout Header_t h, inout Meta_t m) { apply {} } +control update(inout Header_t h, inout Meta_t m) { apply {} } +control egress(inout Header_t h, inout Meta_t m, inout standard_metadata_t sm) { apply {} } +control deparser(packet_out b, in Header_t h) { apply { b.emit(h.h); } } + +control ingress(inout Header_t h, inout Meta_t m, inout standard_metadata_t standard_meta) { + + action a() { standard_meta.egress_spec = 0; } + action a_with_control_params(bit<9> x) { standard_meta.egress_spec = x; } + + table t_lpm { + + key = { + h.h.l : lpm; + } + + actions = { + a; + a_with_control_params; + } + + default_action = a; + + const entries = { + // Test detection of bad values and/or masks for keys with + // match_kind lpm. + + // value has 1s outside of field bit width + 0x100 &&& 0xF0 : a_with_control_params(11); + + // mask has 1s outside of field bit width + 0x11 &&& 0x1F0 : a_with_control_params(12); + + // mask that is not a prefix mask + 0x11 &&& 0xE1 : a_with_control_params(13); + + // another mask that is not a prefix mask, and has 1 bits + // outside of field bit width. + 0x11 &&& 0x181 : a_with_control_params(14); + + // exact match value with value having 1s outside of field + // bit width + 0x100 : a_with_control_params(15); + } + } + + apply { + t_lpm.apply(); + } +} + + +V1Switch(p(), vrfy(), ingress(), egress(), update(), deparser()) main; diff --git a/testdata/p4_16_errors_outputs/table-entries-lpm-2-first.p4 b/testdata/p4_16_errors_outputs/table-entries-lpm-2-first.p4 new file mode 100644 index 00000000000..d1dcdaafc08 --- /dev/null +++ b/testdata/p4_16_errors_outputs/table-entries-lpm-2-first.p4 @@ -0,0 +1,83 @@ +#include +#include + +header hdr { + bit<8> e; + bit<16> t; + bit<8> l; + bit<8> r; + bit<8> v; +} + +struct Header_t { + hdr h; +} + +struct Meta_t { +} + +parser p(packet_in b, out Header_t h, inout Meta_t m, inout standard_metadata_t sm) { + state start { + b.extract(h.h); + transition accept; + } +} + +control vrfy(inout Header_t h, inout Meta_t m) { + apply { + } +} + +control update(inout Header_t h, inout Meta_t m) { + apply { + } +} + +control egress(inout Header_t h, inout Meta_t m, inout standard_metadata_t sm) { + apply { + } +} + +control deparser(packet_out b, in Header_t h) { + apply { + b.emit(h.h); + } +} + +control ingress(inout Header_t h, inout Meta_t m, inout standard_metadata_t standard_meta) { + action a() { + standard_meta.egress_spec = 9w0; + } + action a_with_control_params(bit<9> x) { + standard_meta.egress_spec = x; + } + table t_lpm { + key = { + h.h.l: lpm @name("h.h.l") ; + } + actions = { + a(); + a_with_control_params(); + } + default_action = a(); + const entries = { + 8w0x0 &&& 8w0xf0 : a_with_control_params(9w11); + + 8w0x11 &&& 8w0xf0 : a_with_control_params(9w12); + + 8w0x11 &&& 8w0xe1 : a_with_control_params(9w13); + + 8w0x11 &&& 8w0x81 : a_with_control_params(9w14); + + 8w0x0 : a_with_control_params(9w15); + + } + + } + apply { + t_lpm.apply(); + } +} + +V1Switch(p(), vrfy(), ingress(), egress(), update(), deparser()) main; + diff --git a/testdata/p4_16_errors_outputs/table-entries-lpm-2-frontend.p4 b/testdata/p4_16_errors_outputs/table-entries-lpm-2-frontend.p4 new file mode 100644 index 00000000000..93d47652586 --- /dev/null +++ b/testdata/p4_16_errors_outputs/table-entries-lpm-2-frontend.p4 @@ -0,0 +1,83 @@ +#include +#include + +header hdr { + bit<8> e; + bit<16> t; + bit<8> l; + bit<8> r; + bit<8> v; +} + +struct Header_t { + hdr h; +} + +struct Meta_t { +} + +parser p(packet_in b, out Header_t h, inout Meta_t m, inout standard_metadata_t sm) { + state start { + b.extract(h.h); + transition accept; + } +} + +control vrfy(inout Header_t h, inout Meta_t m) { + apply { + } +} + +control update(inout Header_t h, inout Meta_t m) { + apply { + } +} + +control egress(inout Header_t h, inout Meta_t m, inout standard_metadata_t sm) { + apply { + } +} + +control deparser(packet_out b, in Header_t h) { + apply { + b.emit(h.h); + } +} + +control ingress(inout Header_t h, inout Meta_t m, inout standard_metadata_t standard_meta) { + @name("ingress.a") action a() { + standard_meta.egress_spec = 9w0; + } + @name("ingress.a_with_control_params") action a_with_control_params(bit<9> x) { + standard_meta.egress_spec = x; + } + @name("ingress.t_lpm") table t_lpm_0 { + key = { + h.h.l: lpm @name("h.h.l") ; + } + actions = { + a(); + a_with_control_params(); + } + default_action = a(); + const entries = { + 8w0x0 &&& 8w0xf0 : a_with_control_params(9w11); + + 8w0x11 &&& 8w0xf0 : a_with_control_params(9w12); + + 8w0x11 &&& 8w0xe1 : a_with_control_params(9w13); + + 8w0x11 &&& 8w0x81 : a_with_control_params(9w14); + + 8w0x0 : a_with_control_params(9w15); + + } + + } + apply { + t_lpm_0.apply(); + } +} + +V1Switch(p(), vrfy(), ingress(), egress(), update(), deparser()) main; + diff --git a/testdata/p4_16_errors_outputs/table-entries-lpm-2-midend.p4 b/testdata/p4_16_errors_outputs/table-entries-lpm-2-midend.p4 new file mode 100644 index 00000000000..93d47652586 --- /dev/null +++ b/testdata/p4_16_errors_outputs/table-entries-lpm-2-midend.p4 @@ -0,0 +1,83 @@ +#include +#include + +header hdr { + bit<8> e; + bit<16> t; + bit<8> l; + bit<8> r; + bit<8> v; +} + +struct Header_t { + hdr h; +} + +struct Meta_t { +} + +parser p(packet_in b, out Header_t h, inout Meta_t m, inout standard_metadata_t sm) { + state start { + b.extract(h.h); + transition accept; + } +} + +control vrfy(inout Header_t h, inout Meta_t m) { + apply { + } +} + +control update(inout Header_t h, inout Meta_t m) { + apply { + } +} + +control egress(inout Header_t h, inout Meta_t m, inout standard_metadata_t sm) { + apply { + } +} + +control deparser(packet_out b, in Header_t h) { + apply { + b.emit(h.h); + } +} + +control ingress(inout Header_t h, inout Meta_t m, inout standard_metadata_t standard_meta) { + @name("ingress.a") action a() { + standard_meta.egress_spec = 9w0; + } + @name("ingress.a_with_control_params") action a_with_control_params(bit<9> x) { + standard_meta.egress_spec = x; + } + @name("ingress.t_lpm") table t_lpm_0 { + key = { + h.h.l: lpm @name("h.h.l") ; + } + actions = { + a(); + a_with_control_params(); + } + default_action = a(); + const entries = { + 8w0x0 &&& 8w0xf0 : a_with_control_params(9w11); + + 8w0x11 &&& 8w0xf0 : a_with_control_params(9w12); + + 8w0x11 &&& 8w0xe1 : a_with_control_params(9w13); + + 8w0x11 &&& 8w0x81 : a_with_control_params(9w14); + + 8w0x0 : a_with_control_params(9w15); + + } + + } + apply { + t_lpm_0.apply(); + } +} + +V1Switch(p(), vrfy(), ingress(), egress(), update(), deparser()) main; + diff --git a/testdata/p4_16_errors_outputs/table-entries-lpm-2.p4 b/testdata/p4_16_errors_outputs/table-entries-lpm-2.p4 new file mode 100644 index 00000000000..8d8977ad4a3 --- /dev/null +++ b/testdata/p4_16_errors_outputs/table-entries-lpm-2.p4 @@ -0,0 +1,83 @@ +#include +#include + +header hdr { + bit<8> e; + bit<16> t; + bit<8> l; + bit<8> r; + bit<8> v; +} + +struct Header_t { + hdr h; +} + +struct Meta_t { +} + +parser p(packet_in b, out Header_t h, inout Meta_t m, inout standard_metadata_t sm) { + state start { + b.extract(h.h); + transition accept; + } +} + +control vrfy(inout Header_t h, inout Meta_t m) { + apply { + } +} + +control update(inout Header_t h, inout Meta_t m) { + apply { + } +} + +control egress(inout Header_t h, inout Meta_t m, inout standard_metadata_t sm) { + apply { + } +} + +control deparser(packet_out b, in Header_t h) { + apply { + b.emit(h.h); + } +} + +control ingress(inout Header_t h, inout Meta_t m, inout standard_metadata_t standard_meta) { + action a() { + standard_meta.egress_spec = 0; + } + action a_with_control_params(bit<9> x) { + standard_meta.egress_spec = x; + } + table t_lpm { + key = { + h.h.l: lpm; + } + actions = { + a; + a_with_control_params; + } + default_action = a; + const entries = { + 0x100 &&& 0xf0 : a_with_control_params(11); + + 0x11 &&& 0x1f0 : a_with_control_params(12); + + 0x11 &&& 0xe1 : a_with_control_params(13); + + 0x11 &&& 0x181 : a_with_control_params(14); + + 0x100 : a_with_control_params(15); + + } + + } + apply { + t_lpm.apply(); + } +} + +V1Switch(p(), vrfy(), ingress(), egress(), update(), deparser()) main; + diff --git a/testdata/p4_16_errors_outputs/table-entries-lpm-2.p4-stderr b/testdata/p4_16_errors_outputs/table-entries-lpm-2.p4-stderr new file mode 100644 index 00000000000..97aa349e1f7 --- /dev/null +++ b/testdata/p4_16_errors_outputs/table-entries-lpm-2.p4-stderr @@ -0,0 +1,21 @@ +table-entries-lpm-2.p4(68): [--Wwarn=mismatch] warning: 0x100: value does not fit in 8 bits + 0x100 &&& 0xF0 : a_with_control_params(11); + ^^^^^ +table-entries-lpm-2.p4(71): [--Wwarn=mismatch] warning: 0x1f0: value does not fit in 8 bits + 0x11 &&& 0x1F0 : a_with_control_params(12); + ^^^^^ +table-entries-lpm-2.p4(78): [--Wwarn=mismatch] warning: 0x181: value does not fit in 8 bits + 0x11 &&& 0x181 : a_with_control_params(14); + ^^^^^ +table-entries-lpm-2.p4(82): [--Wwarn=mismatch] warning: 0x100: value does not fit in 8 bits + 0x100 : a_with_control_params(15); + ^^^^^ +table-entries-lpm-2.p4(71): [--Wwarn=mismatch] warning: P4Runtime requires that LPM matches have masked-off bits set to 0, updating value 0x11 to conform to the P4Runtime specification + 0x11 &&& 0x1F0 : a_with_control_params(12); + ^^^^ +table-entries-lpm-2.p4(74): [--Werror=legacy] error: &&& invalid mask for LPM key + 0x11 &&& 0xE1 : a_with_control_params(13); + ^^^^^^^^^^^^^ +table-entries-lpm-2.p4(78): [--Werror=legacy] error: &&& invalid mask for LPM key + 0x11 &&& 0x181 : a_with_control_params(14); + ^^^^^^^^^^^^^^ diff --git a/testdata/p4_16_errors_outputs/table-entries-lpm-2.p4.entries.txt b/testdata/p4_16_errors_outputs/table-entries-lpm-2.p4.entries.txt new file mode 100644 index 00000000000..32ce74abb6f --- /dev/null +++ b/testdata/p4_16_errors_outputs/table-entries-lpm-2.p4.entries.txt @@ -0,0 +1,106 @@ +updates { + type: INSERT + entity { + table_entry { + table_id: 33555353 + match { + field_id: 1 + lpm { + value: "\000" + prefix_len: 4 + } + } + action { + action { + action_id: 16837978 + params { + param_id: 1 + value: "\000\013" + } + } + } + } + } +} +updates { + type: INSERT + entity { + table_entry { + table_id: 33555353 + match { + field_id: 1 + lpm { + value: "\020" + prefix_len: 4 + } + } + action { + action { + action_id: 16837978 + params { + param_id: 1 + value: "\000\014" + } + } + } + } + } +} +updates { + type: INSERT + entity { + table_entry { + table_id: 33555353 + action { + action { + action_id: 16837978 + params { + param_id: 1 + value: "\000\r" + } + } + } + } + } +} +updates { + type: INSERT + entity { + table_entry { + table_id: 33555353 + action { + action { + action_id: 16837978 + params { + param_id: 1 + value: "\000\016" + } + } + } + } + } +} +updates { + type: INSERT + entity { + table_entry { + table_id: 33555353 + match { + field_id: 1 + lpm { + value: "\000" + prefix_len: 8 + } + } + action { + action { + action_id: 16837978 + params { + param_id: 1 + value: "\000\017" + } + } + } + } + } +} diff --git a/testdata/p4_16_errors_outputs/table-entries-lpm-2.p4.p4info.txt b/testdata/p4_16_errors_outputs/table-entries-lpm-2.p4.p4info.txt new file mode 100644 index 00000000000..b3e808f9691 --- /dev/null +++ b/testdata/p4_16_errors_outputs/table-entries-lpm-2.p4.p4info.txt @@ -0,0 +1,43 @@ +pkg_info { + arch: "v1model" +} +tables { + preamble { + id: 33555353 + name: "ingress.t_lpm" + alias: "t_lpm" + } + match_fields { + id: 1 + name: "h.h.l" + bitwidth: 8 + match_type: LPM + } + action_refs { + id: 16795253 + } + action_refs { + id: 16837978 + } + size: 1024 + is_const_table: true +} +actions { + preamble { + id: 16795253 + name: "ingress.a" + alias: "a" + } +} +actions { + preamble { + id: 16837978 + name: "ingress.a_with_control_params" + alias: "a_with_control_params" + } + params { + id: 1 + name: "x" + bitwidth: 9 + } +} From 798f1601d0201dfd1e2d158f85b1f91e9961e042 Mon Sep 17 00:00:00 2001 From: Mihai Budiu Date: Tue, 28 Jan 2020 10:54:05 -0800 Subject: [PATCH 061/106] visitDagOnce = false for control flow simplifications; fixes #2148 (#2149) --- frontends/p4/simplify.cpp | 8 +- frontends/p4/simplify.h | 13 ++- frontends/p4/strengthReduction.cpp | 2 +- ir/ir.def | 1 + testdata/p4_16_samples/issue2148.p4 | 46 +++++++++ .../p4_16_samples_outputs/issue2148-first.p4 | 62 +++++++++++++ .../issue2148-frontend.p4 | 79 ++++++++++++++++ .../p4_16_samples_outputs/issue2148-midend.p4 | 93 +++++++++++++++++++ testdata/p4_16_samples_outputs/issue2148.p4 | 61 ++++++++++++ .../p4_16_samples_outputs/issue2148.p4-stderr | 3 + .../issue2148.p4.entries.txt | 0 .../issue2148.p4.p4info.txt | 10 ++ 12 files changed, 369 insertions(+), 9 deletions(-) create mode 100644 testdata/p4_16_samples/issue2148.p4 create mode 100644 testdata/p4_16_samples_outputs/issue2148-first.p4 create mode 100644 testdata/p4_16_samples_outputs/issue2148-frontend.p4 create mode 100644 testdata/p4_16_samples_outputs/issue2148-midend.p4 create mode 100644 testdata/p4_16_samples_outputs/issue2148.p4 create mode 100644 testdata/p4_16_samples_outputs/issue2148.p4-stderr create mode 100644 testdata/p4_16_samples_outputs/issue2148.p4.entries.txt create mode 100644 testdata/p4_16_samples_outputs/issue2148.p4.p4info.txt diff --git a/frontends/p4/simplify.cpp b/frontends/p4/simplify.cpp index 86b3fecf8f9..e02bdda0e3f 100644 --- a/frontends/p4/simplify.cpp +++ b/frontends/p4/simplify.cpp @@ -20,7 +20,7 @@ limitations under the License. namespace P4 { const IR::Node* DoSimplifyControlFlow::postorder(IR::BlockStatement* statement) { - LOG1("Visiting " << dbp(getOriginal())); + LOG3("Visiting " << dbp(getOriginal())); if (statement->annotations->size() > 0) return statement; auto parent = getContext()->node; @@ -60,7 +60,7 @@ const IR::Node* DoSimplifyControlFlow::postorder(IR::BlockStatement* statement) } const IR::Node* DoSimplifyControlFlow::postorder(IR::IfStatement* statement) { - LOG1("Visiting " << dbp(getOriginal())); + LOG3("Visiting " << dbp(getOriginal())); if (SideEffects::check(statement->condition, refMap, typeMap)) return statement; if (statement->ifTrue->is() && @@ -70,7 +70,7 @@ const IR::Node* DoSimplifyControlFlow::postorder(IR::IfStatement* statement) { } const IR::Node* DoSimplifyControlFlow::postorder(IR::EmptyStatement* statement) { - LOG1("Visiting " << dbp(getOriginal())); + LOG3("Visiting " << dbp(getOriginal())); auto parent = findContext(); if (parent == nullptr || // in a ParserState or P4Action parent->is()) @@ -80,7 +80,7 @@ const IR::Node* DoSimplifyControlFlow::postorder(IR::EmptyStatement* statement) } const IR::Node* DoSimplifyControlFlow::postorder(IR::SwitchStatement* statement) { - LOG1("Visiting " << dbp(getOriginal())); + LOG3("Visiting " << dbp(getOriginal())); if (statement->cases.empty()) { // The P4_16 spec prohibits expressions other than table application as // switch conditions. The parser should have rejected programs for diff --git a/frontends/p4/simplify.h b/frontends/p4/simplify.h index d4088130426..e30cdb7601a 100644 --- a/frontends/p4/simplify.h +++ b/frontends/p4/simplify.h @@ -25,7 +25,7 @@ limitations under the License. namespace P4 { /** @brief Replace complex control flow nodes with simpler ones where possible. - * + * * Simplify the IR in the following ways: * * 1. Remove empty statements from within parser states, actions, and block @@ -42,7 +42,7 @@ namespace P4 { * 5. If a block statement is within another block or a parser state, and (a) * is empty, then replace it with an empty statement, or (b) does not contain * declarations, then move its component statements to the enclosing block. - * + * * 6. If a block statement in an if statement branch only contains a single * statement, replace the block with the statement it contains. * @@ -53,8 +53,13 @@ class DoSimplifyControlFlow : public Transform { TypeMap* typeMap; public: DoSimplifyControlFlow(ReferenceMap* refMap, TypeMap* typeMap) : - refMap(refMap), typeMap(typeMap) - { CHECK_NULL(refMap); CHECK_NULL(typeMap); setName("DoSimplifyControlFlow"); } + refMap(refMap), typeMap(typeMap) { + CHECK_NULL(refMap); CHECK_NULL(typeMap); + setName("DoSimplifyControlFlow"); + // We may want to replace the same statement with different things + // in different places. + visitDagOnce = false; + } const IR::Node* postorder(IR::BlockStatement* statement) override; const IR::Node* postorder(IR::IfStatement* statement) override; const IR::Node* postorder(IR::EmptyStatement* statement) override; diff --git a/frontends/p4/strengthReduction.cpp b/frontends/p4/strengthReduction.cpp index 52eea57938e..701cc3131cc 100644 --- a/frontends/p4/strengthReduction.cpp +++ b/frontends/p4/strengthReduction.cpp @@ -312,7 +312,7 @@ const IR::Node* DoStrengthReduction::postorder(IR::Slice* expr) { } auto slice_width = expr->getH() - expr->getL() + 1; - if (slice_width == expr->e0->type->width_bits()) + if (slice_width == (unsigned)expr->e0->type->width_bits()) return expr->e0; return expr; diff --git a/ir/ir.def b/ir/ir.def index d09759b2db4..4fc3887ab11 100644 --- a/ir/ir.def +++ b/ir/ir.def @@ -439,6 +439,7 @@ class IfStatement : Statement { clone.visit(ifFalse, "ifFalse"); v.flow_merge(clone); } + validate{ CHECK_NULL(ifTrue); } } class BlockStatement : Statement, ISimpleNamespace, IAnnotated { diff --git a/testdata/p4_16_samples/issue2148.p4 b/testdata/p4_16_samples/issue2148.p4 new file mode 100644 index 00000000000..9f2d38db134 --- /dev/null +++ b/testdata/p4_16_samples/issue2148.p4 @@ -0,0 +1,46 @@ +#include +#include + +header H { + bit<16> a; +} + + +struct Headers { + H h; +} + +struct Meta { +} + +bit<16> do_thing_function() { + H not_initialized; + bit<32> new_val = 32w1; + if (not_initialized.a < 6) { + } else { + new_val = 32w232; + } + return (bit<16>)new_val; +} +control ingress(inout Headers h, inout Meta m, inout standard_metadata_t sm) { + action do_thing_action() { + do_thing_function(); + } + apply { + h.h.a = do_thing_function(); + do_thing_action(); + } +} + +parser p(packet_in b, out Headers h, inout Meta m, inout standard_metadata_t sm) { +state start {transition accept;}} + +control vrfy(inout Headers h, inout Meta m) { apply {} } + +control update(inout Headers h, inout Meta m) { apply {} } + +control egress(inout Headers h, inout Meta m, inout standard_metadata_t sm) { apply {} } + +control deparser(packet_out b, in Headers h) { apply {} } + +V1Switch(p(), vrfy(), ingress(), egress(), update(), deparser()) main; diff --git a/testdata/p4_16_samples_outputs/issue2148-first.p4 b/testdata/p4_16_samples_outputs/issue2148-first.p4 new file mode 100644 index 00000000000..86eb8d359f2 --- /dev/null +++ b/testdata/p4_16_samples_outputs/issue2148-first.p4 @@ -0,0 +1,62 @@ +#include +#include + +header H { + bit<16> a; +} + +struct Headers { + H h; +} + +struct Meta { +} + +bit<16> do_thing_function() { + H not_initialized; + bit<32> new_val = 32w1; + if (not_initialized.a < 16w6) { + ; + } else { + new_val = 32w232; + } + return (bit<16>)new_val; +} +control ingress(inout Headers h, inout Meta m, inout standard_metadata_t sm) { + action do_thing_action() { + do_thing_function(); + } + apply { + h.h.a = do_thing_function(); + do_thing_action(); + } +} + +parser p(packet_in b, out Headers h, inout Meta m, inout standard_metadata_t sm) { + state start { + transition accept; + } +} + +control vrfy(inout Headers h, inout Meta m) { + apply { + } +} + +control update(inout Headers h, inout Meta m) { + apply { + } +} + +control egress(inout Headers h, inout Meta m, inout standard_metadata_t sm) { + apply { + } +} + +control deparser(packet_out b, in Headers h) { + apply { + } +} + +V1Switch(p(), vrfy(), ingress(), egress(), update(), deparser()) main; + diff --git a/testdata/p4_16_samples_outputs/issue2148-frontend.p4 b/testdata/p4_16_samples_outputs/issue2148-frontend.p4 new file mode 100644 index 00000000000..37faac095d3 --- /dev/null +++ b/testdata/p4_16_samples_outputs/issue2148-frontend.p4 @@ -0,0 +1,79 @@ +#include +#include + +header H { + bit<16> a; +} + +struct Headers { + H h; +} + +struct Meta { +} + +control ingress(inout Headers h, inout Meta m, inout standard_metadata_t sm) { + @name("ingress.do_thing_action") action do_thing_action() { + { + bool hasReturned = false; + bit<16> retval; + H not_initialized_0; + bit<32> new_val_0; + new_val_0 = 32w1; + if (not_initialized_0.a < 16w6) { + ; + } else { + new_val_0 = 32w232; + } + hasReturned = true; + retval = (bit<16>)new_val_0; + } + } + apply { + { + bool hasReturned_1 = false; + bit<16> retval_1; + H not_initialized_2; + bit<32> new_val_1; + new_val_1 = 32w1; + if (not_initialized_2.a < 16w6) { + ; + } else { + new_val_1 = 32w232; + } + hasReturned_1 = true; + retval_1 = (bit<16>)new_val_1; + h.h.a = retval_1; + } + do_thing_action(); + } +} + +parser p(packet_in b, out Headers h, inout Meta m, inout standard_metadata_t sm) { + state start { + transition accept; + } +} + +control vrfy(inout Headers h, inout Meta m) { + apply { + } +} + +control update(inout Headers h, inout Meta m) { + apply { + } +} + +control egress(inout Headers h, inout Meta m, inout standard_metadata_t sm) { + apply { + } +} + +control deparser(packet_out b, in Headers h) { + apply { + } +} + +V1Switch(p(), vrfy(), ingress(), egress(), update(), deparser()) main; + diff --git a/testdata/p4_16_samples_outputs/issue2148-midend.p4 b/testdata/p4_16_samples_outputs/issue2148-midend.p4 new file mode 100644 index 00000000000..6edbe4f39d5 --- /dev/null +++ b/testdata/p4_16_samples_outputs/issue2148-midend.p4 @@ -0,0 +1,93 @@ +#include +#include + +header H { + bit<16> a; +} + +struct Headers { + H h; +} + +struct Meta { +} + +control ingress(inout Headers h, inout Meta m, inout standard_metadata_t sm) { + H not_initialized_0; + H not_initialized_2; + bit<32> new_val_1; + @name("ingress.do_thing_action") action do_thing_action() { + } + @hidden action issue2148l21() { + new_val_1 = 32w232; + } + @hidden action issue2148l18() { + new_val_1 = 32w1; + } + @hidden action issue2148l30() { + h.h.a = (bit<16>)new_val_1; + } + @hidden table tbl_issue2148l18 { + actions = { + issue2148l18(); + } + const default_action = issue2148l18(); + } + @hidden table tbl_issue2148l21 { + actions = { + issue2148l21(); + } + const default_action = issue2148l21(); + } + @hidden table tbl_issue2148l30 { + actions = { + issue2148l30(); + } + const default_action = issue2148l30(); + } + @hidden table tbl_do_thing_action { + actions = { + do_thing_action(); + } + const default_action = do_thing_action(); + } + apply { + tbl_issue2148l18.apply(); + if (not_initialized_2.a < 16w6) { + ; + } else { + tbl_issue2148l21.apply(); + } + tbl_issue2148l30.apply(); + tbl_do_thing_action.apply(); + } +} + +parser p(packet_in b, out Headers h, inout Meta m, inout standard_metadata_t sm) { + state start { + transition accept; + } +} + +control vrfy(inout Headers h, inout Meta m) { + apply { + } +} + +control update(inout Headers h, inout Meta m) { + apply { + } +} + +control egress(inout Headers h, inout Meta m, inout standard_metadata_t sm) { + apply { + } +} + +control deparser(packet_out b, in Headers h) { + apply { + } +} + +V1Switch(p(), vrfy(), ingress(), egress(), update(), deparser()) main; + diff --git a/testdata/p4_16_samples_outputs/issue2148.p4 b/testdata/p4_16_samples_outputs/issue2148.p4 new file mode 100644 index 00000000000..b152612c08a --- /dev/null +++ b/testdata/p4_16_samples_outputs/issue2148.p4 @@ -0,0 +1,61 @@ +#include +#include + +header H { + bit<16> a; +} + +struct Headers { + H h; +} + +struct Meta { +} + +bit<16> do_thing_function() { + H not_initialized; + bit<32> new_val = 32w1; + if (not_initialized.a < 6) { + } else { + new_val = 32w232; + } + return (bit<16>)new_val; +} +control ingress(inout Headers h, inout Meta m, inout standard_metadata_t sm) { + action do_thing_action() { + do_thing_function(); + } + apply { + h.h.a = do_thing_function(); + do_thing_action(); + } +} + +parser p(packet_in b, out Headers h, inout Meta m, inout standard_metadata_t sm) { + state start { + transition accept; + } +} + +control vrfy(inout Headers h, inout Meta m) { + apply { + } +} + +control update(inout Headers h, inout Meta m) { + apply { + } +} + +control egress(inout Headers h, inout Meta m, inout standard_metadata_t sm) { + apply { + } +} + +control deparser(packet_out b, in Headers h) { + apply { + } +} + +V1Switch(p(), vrfy(), ingress(), egress(), update(), deparser()) main; + diff --git a/testdata/p4_16_samples_outputs/issue2148.p4-stderr b/testdata/p4_16_samples_outputs/issue2148.p4-stderr new file mode 100644 index 00000000000..d3fc09d5551 --- /dev/null +++ b/testdata/p4_16_samples_outputs/issue2148.p4-stderr @@ -0,0 +1,3 @@ +issue2148.p4(19): [--Wwarn=uninitialized_use] warning: not_initialized.a may be uninitialized + if (not_initialized.a < 6) { + ^^^^^^^^^^^^^^^^^ diff --git a/testdata/p4_16_samples_outputs/issue2148.p4.entries.txt b/testdata/p4_16_samples_outputs/issue2148.p4.entries.txt new file mode 100644 index 00000000000..e69de29bb2d diff --git a/testdata/p4_16_samples_outputs/issue2148.p4.p4info.txt b/testdata/p4_16_samples_outputs/issue2148.p4.p4info.txt new file mode 100644 index 00000000000..867b5fb0516 --- /dev/null +++ b/testdata/p4_16_samples_outputs/issue2148.p4.p4info.txt @@ -0,0 +1,10 @@ +pkg_info { + arch: "v1model" +} +actions { + preamble { + id: 16827060 + name: "ingress.do_thing_action" + alias: "do_thing_action" + } +} From 54da5dcf065687c3c1a6c86ec1ab492ec6f68dcb Mon Sep 17 00:00:00 2001 From: Chris Dodd Date: Tue, 28 Jan 2020 11:28:45 -0800 Subject: [PATCH 062/106] Fix right-shift operator precedence (#2158) --- frontends/parsers/p4/p4lexer.ll | 1 + frontends/parsers/p4/p4parser.ypp | 40 ++++++++++--------- frontends/parsers/parserDriver.cpp | 11 ----- frontends/parsers/parserDriver.h | 15 ------- .../p4_16_errors_outputs/shift_e.p4-stderr | 6 +-- testdata/p4_16_samples/shift_precendence.p4 | 12 ++++++ .../shift_precendence-first.p4 | 12 ++++++ .../shift_precendence-frontend.p4 | 12 ++++++ .../shift_precendence-midend.p4 | 19 +++++++++ .../shift_precendence.p4 | 12 ++++++ .../shift_precendence.p4-stderr | 0 11 files changed, 93 insertions(+), 47 deletions(-) create mode 100644 testdata/p4_16_samples/shift_precendence.p4 create mode 100644 testdata/p4_16_samples_outputs/shift_precendence-first.p4 create mode 100644 testdata/p4_16_samples_outputs/shift_precendence-frontend.p4 create mode 100644 testdata/p4_16_samples_outputs/shift_precendence-midend.p4 create mode 100644 testdata/p4_16_samples_outputs/shift_precendence.p4 create mode 100644 testdata/p4_16_samples_outputs/shift_precendence.p4-stderr diff --git a/frontends/parsers/p4/p4lexer.ll b/frontends/parsers/p4/p4lexer.ll index 9338ce9d7ee..13fd2000342 100644 --- a/frontends/parsers/p4/p4lexer.ll +++ b/frontends/parsers/p4/p4lexer.ll @@ -224,6 +224,7 @@ using Parser = P4::P4Parser; "{" { BEGIN(driver.saveState); return makeToken(L_BRACE); } "}" { BEGIN(driver.saveState); return makeToken(R_BRACE); } "<" { BEGIN(driver.saveState); return makeToken(L_ANGLE); } +">"/">" { BEGIN(driver.saveState); return makeToken(R_ANGLE_SHIFT); } ">" { BEGIN(driver.saveState); return makeToken(R_ANGLE); } "!" { BEGIN(driver.saveState); return makeToken(NOT); } diff --git a/frontends/parsers/p4/p4parser.ypp b/frontends/parsers/p4/p4parser.ypp index 4ed3ae3891c..4e63c3bf23e 100644 --- a/frontends/parsers/p4/p4parser.ypp +++ b/frontends/parsers/p4/p4parser.ypp @@ -193,6 +193,7 @@ inline std::ostream& operator<<(std::ostream& out, const P4::Token& t) { %token R_BRACE "}" %token L_ANGLE "<" %token R_ANGLE ">" +%token R_ANGLE_SHIFT // > immediately followed by another > %token L_PAREN "(" %token R_PAREN ")" %token NOT "!" @@ -305,7 +306,7 @@ inline std::ostream& operator<<(std::ostream& out, const P4::Token& t) { %left BIT_OR %left BIT_XOR %left BIT_AND -%left SHL +%left SHL R_ANGLE_SHIFT %left PP PLUS MINUS PLUS_SAT MINUS_SAT %left MUL DIV MOD %right PREFIX @@ -565,6 +566,7 @@ annotationToken | "}" { $$ = $1; } | "<" { $$ = $1; } | ">" { $$ = $1; } + | R_ANGLE_SHIFT { $$ = $1; } | "!" { $$ = $1; } | ":" { $$ = $1; } @@ -776,13 +778,13 @@ simpleKeysetExpression valueSetDeclaration : optAnnotations - VALUESET "<" baseType ">" "(" expression ")" name ";" + VALUESET "<" baseType r_angle "(" expression ")" name ";" { $$ = new IR::P4ValueSet(@9, *$9, $1, $4, $7); } | optAnnotations - VALUESET "<" tupleType ">" "(" expression ")" name ";" + VALUESET "<" tupleType r_angle "(" expression ")" name ";" { $$ = new IR::P4ValueSet(@9, *$9, $1, $4, $7); } | optAnnotations - VALUESET "<" typeName ">" "(" expression ")" name ";" + VALUESET "<" typeName r_angle "(" expression ")" name ";" { $$ = new IR::P4ValueSet(@9, *$9, $1, $4, $7); } ; @@ -888,7 +890,7 @@ typeName ; tupleType - : TUPLE "<" typeArgumentList ">" { $$ = new IR::Type_Tuple(@1+@4, *$3); } + : TUPLE "<" typeArgumentList r_angle { $$ = new IR::Type_Tuple(@1+@4, *$3); } ; headerStackType @@ -896,7 +898,7 @@ headerStackType ; specializedType - : typeName "<" typeArgumentList ">" { $$ = new IR::Type_Specialized(@1 + @4, $1, $3); } + : typeName "<" typeArgumentList r_angle { $$ = new IR::Type_Specialized(@1 + @4, $1, $3); } ; baseType @@ -905,18 +907,18 @@ baseType | BIT { $$ = IR::Type::Bits::get(@1, 1); } | STRING { $$ = IR::Type::String::get(); } | INT { $$ = new IR::Type_InfInt(); } - | BIT "<" INTEGER ">" + | BIT "<" INTEGER r_angle { $$ = IR::Type::Bits::get(@1+@4, parseConstantChecked(@3, $3), false); } - | INT "<" INTEGER ">" + | INT "<" INTEGER r_angle { $$ = IR::Type::Bits::get(@1+@4, parseConstantChecked(@3, $3), true); } - | VARBIT "<" INTEGER ">" + | VARBIT "<" INTEGER r_angle { $$ = IR::Type::Varbits::get(@1+@4, parseConstantChecked(@3, $3)); } - | BIT "<" "(" expression ")" ">" + | BIT "<" "(" expression ")" r_angle { $$ = new IR::Type_Bits(@1+@6, $4, false); } - | INT "<" "(" expression ")" ">" + | INT "<" "(" expression ")" r_angle { $$ = new IR::Type_Bits(@1+@6, $4, true); } - | VARBIT "<" "(" expression ")" ">" + | VARBIT "<" "(" expression ")" r_angle { $$ = new IR::Type_Varbits(@1+@6, $4); } ; @@ -929,7 +931,7 @@ typeOrVoid optTypeParameters : /* empty */ { $$ = new IR::TypeParameters(); } - | "<" typeParameterList ">" { $$ = new IR::TypeParameters(@1+@3, *$2); } + | "<" typeParameterList r_angle { $$ = new IR::TypeParameters(@1+@3, *$2); } ; typeParameterList @@ -1011,7 +1013,7 @@ enumDeclaration : optAnnotations ENUM name { driver.structure->declareType(*$3); } "{" identifierList "}" { $$ = new IR::Type_Enum(@3, *$3, *$6); } - | optAnnotations ENUM BIT "<" INTEGER ">" name { driver.structure->declareType(*$7); } + | optAnnotations ENUM BIT "<" INTEGER r_angle name { driver.structure->declareType(*$7); } "{" specifiedIdentifierList "}" { auto type = IR::Type::Bits::get(@3+@6, parseConstantChecked(@5, $5)); $$ = new IR::Type_SerEnum(@7, *$7, type, *$10); } @@ -1062,7 +1064,7 @@ assignmentOrMethodCallStatement new IR::Vector(), $3); $$ = new IR::MethodCallStatement(@1 + @4, mc); } - | lvalue "<" typeArgumentList ">" "(" argumentList ")" ";" + | lvalue "<" typeArgumentList r_angle "(" argumentList ")" ";" { auto mc = new IR::MethodCallExpression(@1 + @7, $1, $3, $6); $$ = new IR::MethodCallStatement(@1 + @7, mc); } @@ -1337,8 +1339,8 @@ expression | expression "|+|" expression { $$ = new IR::AddSat(@1 + @3, $1, $3); } | expression "|-|" expression { $$ = new IR::SubSat(@1 + @3, $1, $3); } | expression "<<" expression { $$ = new IR::Shl(@1 + @3, $1, $3); } - | expression ">" ">" expression - { driver.checkShift(@2, @3); $$ = new IR::Shr(@1 + @4, $1, $4); } + | expression R_ANGLE_SHIFT ">" expression + { $$ = new IR::Shr(@1 + @4, $1, $4); } | expression "<=" expression { $$ = new IR::Leq(@1 + @3, $1, $3); } | expression ">=" expression { $$ = new IR::Geq(@1 + @3, $1, $3); } | expression "<" expression { $$ = new IR::Lss(@1 + @3, $1, $3); } @@ -1352,7 +1354,7 @@ expression | expression "&&" expression { $$ = new IR::LAnd(@1 + @2 + @3, $1, $3); } | expression "||" expression { $$ = new IR::LOr(@1 + @2 + @3, $1, $3); } | expression "?" expression ":" expression { $$ = new IR::Mux(@1 + @5, $1, $3, $5); } - | expression "<" realTypeArgumentList ">" "(" argumentList ")" + | expression "<" realTypeArgumentList r_angle "(" argumentList ")" { $$ = new IR::MethodCallExpression(@1 + @4, $1, $3, $6); } // FIXME: the previous rule has the wrong precedence, and parses with // precedence weaker than casts. There is no easy way to fix this in bison. @@ -1389,6 +1391,8 @@ strList $$->push_back(new IR::StringLiteral(@3, $3)); } ; +r_angle : ">" | R_ANGLE_SHIFT ; + /*****************************************************************************/ %% diff --git a/frontends/parsers/parserDriver.cpp b/frontends/parsers/parserDriver.cpp index 29390034a96..858d5ce5f52 100644 --- a/frontends/parsers/parserDriver.cpp +++ b/frontends/parsers/parserDriver.cpp @@ -298,17 +298,6 @@ P4ParserDriver::parseStringLiteralTriple(const Util::SourceInfo& srcInfo, P4AnnotationLexer::STRING_LITERAL_TRIPLE, srcInfo, body); } -/* static */ void P4ParserDriver::checkShift(const Util::SourceInfo& l, - const Util::SourceInfo& r) { - if (!l.isValid() || !r.isValid()) - BUG("Source position not available!"); - const Util::SourcePosition& f = l.getStart(); - const Util::SourcePosition& s = r.getStart(); - if (f.getLineNumber() != s.getLineNumber() || - f.getColumnNumber() != s.getColumnNumber() - 1) - ::error("Syntax error at shift operator: %1%", l); -} - void P4ParserDriver::onReadErrorDeclaration(IR::Type_Error* error) { if (allErrors == nullptr) { nodes->push_back(error); diff --git a/frontends/parsers/parserDriver.h b/frontends/parsers/parserDriver.h index 30c9def9877..0fdb1ec2585 100644 --- a/frontends/parsers/parserDriver.h +++ b/frontends/parsers/parserDriver.h @@ -193,21 +193,6 @@ class P4ParserDriver final : public AbstractParserDriver { /// Notify that the parser parsed a P4 `error` declaration. void onReadErrorDeclaration(IR::Type_Error* error); - /** - * There's a lexical ambiguity in P4 between the right shift operator `>>` - * and nested template arguments. (e.g. `A>`) We resolve this at the - * parser level; from the lexer's perspective, both cases are just a - * sequence of R_ANGLE tokens. Whitespace is allowed between the R_ANGLEs of - * nested template arguments, but in the right shift operator case that - * isn't permitted, and the parser calls this function to detect when that - * happens and report and error. - * - * @param l The location of the first R_ANGLE token. - * @param r The location of the second R_ANGLE token. - */ - static void checkShift(const Util::SourceInfo& l, const Util::SourceInfo& r); - - //////////////////////////////////////////////////////////////////////////// // Shared state manipulated directly by the lexer and parser. //////////////////////////////////////////////////////////////////////////// diff --git a/testdata/p4_16_errors_outputs/shift_e.p4-stderr b/testdata/p4_16_errors_outputs/shift_e.p4-stderr index fe8341656a0..f9a2bf94901 100644 --- a/testdata/p4_16_errors_outputs/shift_e.p4-stderr +++ b/testdata/p4_16_errors_outputs/shift_e.p4-stderr @@ -1,4 +1,4 @@ -shift_e.p4(20): error: Syntax error at shift operator: - int<32> b = a > > 1; - ^ +shift_e.p4(20):syntax error, unexpected > + int<32> b = a > > + ^ [--Werror=overlimit] error: 1 errors encountered, aborting compilation diff --git a/testdata/p4_16_samples/shift_precendence.p4 b/testdata/p4_16_samples/shift_precendence.p4 new file mode 100644 index 00000000000..e76c6874145 --- /dev/null +++ b/testdata/p4_16_samples/shift_precendence.p4 @@ -0,0 +1,12 @@ +control i(out bit<4> a) { + bit<4> tmp_0; + apply { + tmp_0 = 4w0; + a = 4w1 & (4w2 + tmp_0) >> 4w2; + } +} + +control c(out bit<4> a); +package top(c _c); +top(i()) main; + diff --git a/testdata/p4_16_samples_outputs/shift_precendence-first.p4 b/testdata/p4_16_samples_outputs/shift_precendence-first.p4 new file mode 100644 index 00000000000..1e9d704c9a2 --- /dev/null +++ b/testdata/p4_16_samples_outputs/shift_precendence-first.p4 @@ -0,0 +1,12 @@ +control i(out bit<4> a) { + bit<4> tmp_0; + apply { + tmp_0 = 4w0; + a = 4w1 & 4w2 + tmp_0 >> 4w2; + } +} + +control c(out bit<4> a); +package top(c _c); +top(i()) main; + diff --git a/testdata/p4_16_samples_outputs/shift_precendence-frontend.p4 b/testdata/p4_16_samples_outputs/shift_precendence-frontend.p4 new file mode 100644 index 00000000000..cd12ef4fb29 --- /dev/null +++ b/testdata/p4_16_samples_outputs/shift_precendence-frontend.p4 @@ -0,0 +1,12 @@ +control i(out bit<4> a) { + bit<4> tmp; + apply { + tmp = 4w0; + a = 4w1 & 4w2 + tmp >> 4w2; + } +} + +control c(out bit<4> a); +package top(c _c); +top(i()) main; + diff --git a/testdata/p4_16_samples_outputs/shift_precendence-midend.p4 b/testdata/p4_16_samples_outputs/shift_precendence-midend.p4 new file mode 100644 index 00000000000..28922d4593f --- /dev/null +++ b/testdata/p4_16_samples_outputs/shift_precendence-midend.p4 @@ -0,0 +1,19 @@ +control i(out bit<4> a) { + @hidden action shift_precendence5() { + a = 4w0; + } + @hidden table tbl_shift_precendence5 { + actions = { + shift_precendence5(); + } + const default_action = shift_precendence5(); + } + apply { + tbl_shift_precendence5.apply(); + } +} + +control c(out bit<4> a); +package top(c _c); +top(i()) main; + diff --git a/testdata/p4_16_samples_outputs/shift_precendence.p4 b/testdata/p4_16_samples_outputs/shift_precendence.p4 new file mode 100644 index 00000000000..1e9d704c9a2 --- /dev/null +++ b/testdata/p4_16_samples_outputs/shift_precendence.p4 @@ -0,0 +1,12 @@ +control i(out bit<4> a) { + bit<4> tmp_0; + apply { + tmp_0 = 4w0; + a = 4w1 & 4w2 + tmp_0 >> 4w2; + } +} + +control c(out bit<4> a); +package top(c _c); +top(i()) main; + diff --git a/testdata/p4_16_samples_outputs/shift_precendence.p4-stderr b/testdata/p4_16_samples_outputs/shift_precendence.p4-stderr new file mode 100644 index 00000000000..e69de29bb2d From be7c7f236875d386121c45551a8c2e997ace38f1 Mon Sep 17 00:00:00 2001 From: Amresh Kulkarni Date: Tue, 28 Jan 2020 13:42:32 -0800 Subject: [PATCH 063/106] Update error message for invalid ranges in const entries (#2160) --- control-plane/p4RuntimeSerializer.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/control-plane/p4RuntimeSerializer.cpp b/control-plane/p4RuntimeSerializer.cpp index ad4def51c2b..e6e14a0476a 100644 --- a/control-plane/p4RuntimeSerializer.cpp +++ b/control-plane/p4RuntimeSerializer.cpp @@ -1616,10 +1616,15 @@ class P4RuntimeEntriesConverter { auto start = simpleKeyExpressionValue(kr->left, typeMap); auto end = simpleKeyExpressionValue(kr->right, typeMap); if (start == boost::none || end == boost::none) return; + // Error on invalid range values big_int maxValue = (big_int(1) << keyWidth) - 1; - // These should be guaranteed by the frontend - BUG_CHECK(*start <= *end, "Invalid range with start greater than end"); - BUG_CHECK(*end <= maxValue, "End of range is too large"); + // NOTE: If end value is > max allowed for keyWidth, value gets + // wrapped around. A warning is issued in this case by the frontend + // earlier. + // For e.g. 16 bit key has a max value of 65535, Range of (1..65536) + // will be converted to (1..0) and will fail below check. + if (*start > *end) + ::error("%s Invalid range for table entry", kr->srcInfo); if (*start == 0 && *end == maxValue) // don't care return; startStr = stringReprConstant(*start, keyWidth); From 19cd6964994671a6da027e07c77d7d30c6ec99ce Mon Sep 17 00:00:00 2001 From: Andy Fingerhut Date: Tue, 28 Jan 2020 14:40:00 -0800 Subject: [PATCH 064/106] Add docs for register constructor, and update metadata preservation notes (#2157) --- p4include/v1model.p4 | 36 ++++++++++++++----- .../p4_16_errors_outputs/issue1541.p4-stderr | 2 +- .../p4_16_errors_outputs/issue513.p4-stderr | 2 +- .../p4_16_samples_outputs/issue841.p4-stderr | 2 +- 4 files changed, 31 insertions(+), 11 deletions(-) diff --git a/p4include/v1model.p4 b/p4include/v1model.p4 index 95cbf6b720c..820178f9c64 100644 --- a/p4include/v1model.p4 +++ b/p4include/v1model.p4 @@ -21,13 +21,14 @@ limitations under the License. * * https://github.com/p4lang/behavioral-model/blob/master/docs/simple_switch.md * - * Note 2: There are ongoing discussions among P4 working group - * members in 2019-Apr regarding exactly how resubmit, recirculate, + * Note 2: There were several discussions among P4 working group + * members in early 2019 regarding exactly how resubmit, recirculate, * and clone3 operations can be called anywhere in their respective * controls, but the values of the fields to be preserved is the value * they have when that control is finished executing. That is how - * these operations behave in P4_14, but this requires some care in - * making this happen in P4_16. + * these operations are defined in P4_14. See + * https://github.com/p4lang/behavioral-model/blob/master/docs/simple_switch.md#restrictions-on-recirculate-resubmit-and-clone-operations + * for more details on the current state of affairs. * * Note 3: There are at least some P4_14 implementations where * invoking a generate_digest operation on a field_list will create a @@ -56,7 +57,6 @@ match_kind { selector } -// Are these correct? @metadata @name("standard_metadata") struct standard_metadata_t { bit<9> ingress_port; @@ -125,6 +125,11 @@ extern counter { * You must provide a choice of whether to maintain only a packet * count (CounterType.packets), only a byte count * (CounterType.bytes), or both (CounterType.packets_and_bytes). + * + * Counters can be updated from your P4 program, but can only be + * read from the control plane. If you need something that can be + * both read and written from the P4 program, consider using a + * register. */ counter(bit<32> size, CounterType type); /*** @@ -153,6 +158,11 @@ extern direct_counter { * definition of that table: * * counters = ; + * + * Counters can be updated from your P4 program, but can only be + * read from the control plane. If you need something that can be + * both read and written from the P4 program, consider using a + * register. */ direct_counter(CounterType type); /*** @@ -248,6 +258,16 @@ extern direct_meter { } extern register { + /*** + * A register object is created by calling its constructor. This + * creates an array of 'size' identical elements, each with type + * T. The array indices are in the range [0, size-1]. For + * example, this constructor call: + * + * register>(512) my_reg; + * + * allocates storage for 512 values, each with type bit<32>. + */ register(bit<32> size); /*** * read() reads the state of the register array stored at the @@ -473,7 +493,7 @@ extern void update_checksum_with_payload(in bool condition, in T data, ino * The value of the user-defined metadata fields that are preserved in * resubmitted packets is the value they have at the end of ingress * processing, not their values at the time the resubmit call is made. - * See Note 2. + * See Note 2 for issues with this. * * Calling resubmit is only supported in the ingress control. There * is no way to undo its effects once it has been called. If resubmit @@ -497,7 +517,7 @@ extern void resubmit(in T data); * The value of the user-defined metadata fields that are preserved in * recirculated packets is the value they have at the end of egress * processing, not their values at the time the recirculate call is - * made. See Note 2. + * made. See Note 2 for issues with this. * * Calling recirculate is only supported in the egress control. There * is no way to undo its effects once it has been called. If @@ -542,7 +562,7 @@ extern void clone(in CloneType type, in bit<32> session); * packet(s). The value of the user-defined metadata fields that are * preserved with cloned packets is the value they have at the end of * ingress or egress processing, not their values at the time the - * clone3 call is made. See Note 2. + * clone3 call is made. See Note 2 for issues with this. * * If clone3 is called during ingress processing, the first parameter * must be CloneType.I2E. If clone3 is called during egress diff --git a/testdata/p4_16_errors_outputs/issue1541.p4-stderr b/testdata/p4_16_errors_outputs/issue1541.p4-stderr index 1a9596ebe72..767ae5f6fb7 100644 --- a/testdata/p4_16_errors_outputs/issue1541.p4-stderr +++ b/testdata/p4_16_errors_outputs/issue1541.p4-stderr @@ -1,7 +1,7 @@ issue1541.p4(25): [--Wwarn=shadow] warning: hash shadows hash action hash() { ^^^^ -v1model.p4(379) +v1model.p4(399) extern void hash(out O result, in HashAlgorithm algo, in T base, in D data, in M max); ^^^^ issue1541.p4(26): [--Werror=type-error] error: hash: Recursive action call diff --git a/testdata/p4_16_errors_outputs/issue513.p4-stderr b/testdata/p4_16_errors_outputs/issue513.p4-stderr index 351af5af2ab..72e3ddb5257 100644 --- a/testdata/p4_16_errors_outputs/issue513.p4-stderr +++ b/testdata/p4_16_errors_outputs/issue513.p4-stderr @@ -1,7 +1,7 @@ issue513.p4(60): [--Wwarn=deprecated] warning: mark_to_drop: Using deprecated feature mark_to_drop. Please use mark_to_drop(standard_metadata) instead. mark_to_drop(); ^^^^^^^^^^^^ -v1model.p4(343) +v1model.p4(363) extern void mark_to_drop(); ^^^^^^^^^^^^ issue513.p4(60): [--Werror=target-error] error: MethodCallStatement: Unsupported on target Conditional execution in actions diff --git a/testdata/p4_16_samples_outputs/issue841.p4-stderr b/testdata/p4_16_samples_outputs/issue841.p4-stderr index a64684395de..05f1774253d 100644 --- a/testdata/p4_16_samples_outputs/issue841.p4-stderr +++ b/testdata/p4_16_samples_outputs/issue841.p4-stderr @@ -1,6 +1,6 @@ issue841.p4(39): [--Wwarn=deprecated] warning: Checksum16: Using deprecated feature Checksum16. Please use verify_checksum/update_checksum instead. Checksum16() checksum; ^^^^^^^^^^ -v1model.p4(391) +v1model.p4(411) extern Checksum16 { ^^^^^^^^^^ From 947499bfef69e5f3cf71a36ba0213d308c53a02a Mon Sep 17 00:00:00 2001 From: Hemant Singh <32817427+hesingh@users.noreply.github.com> Date: Tue, 28 Jan 2020 17:52:50 -0500 Subject: [PATCH 065/106] Complete p4c bmv2 backend header stack runtime index support (#2139) * Complete p4c bmv2 backend header stack runtime index support --- backends/bmv2/CMakeLists.txt | 2 - backends/bmv2/common/action.cpp | 9 +- backends/bmv2/common/expression.cpp | 81 ++++++++++--- backends/bmv2/common/expression.h | 1 + ir/type.def | 9 ++ lib/json.cpp | 8 +- .../p4_16_samples/runtime-index-2-bmv2.p4 | 105 +++++++++++++++++ .../p4_16_samples/runtime-index-2-bmv2.stf | 65 ++++++++++ testdata/p4_16_samples/runtime-index-bmv2.p4 | 111 ++++++++++++++++++ testdata/p4_16_samples/runtime-index-bmv2.stf | 88 ++++++++++++++ .../runtime-index-2-bmv2-first.p4 | 74 ++++++++++++ .../runtime-index-2-bmv2-frontend.p4 | 74 ++++++++++++ .../runtime-index-2-bmv2-midend.p4 | 92 +++++++++++++++ .../runtime-index-2-bmv2.p4 | 74 ++++++++++++ .../runtime-index-2-bmv2.p4-stderr | 0 .../runtime-index-2-bmv2.p4.entries.txt | 0 .../runtime-index-2-bmv2.p4.p4info.txt | 3 + .../runtime-index-bmv2-first.p4 | 87 ++++++++++++++ .../runtime-index-bmv2-frontend.p4 | 87 ++++++++++++++ .../runtime-index-bmv2-midend.p4 | 103 ++++++++++++++++ .../runtime-index-bmv2.p4 | 87 ++++++++++++++ .../runtime-index-bmv2.p4-stderr | 0 .../runtime-index-bmv2.p4.entries.txt | 0 .../runtime-index-bmv2.p4.p4info.txt | 3 + 24 files changed, 1141 insertions(+), 22 deletions(-) create mode 100644 testdata/p4_16_samples/runtime-index-2-bmv2.p4 create mode 100644 testdata/p4_16_samples/runtime-index-2-bmv2.stf create mode 100644 testdata/p4_16_samples/runtime-index-bmv2.p4 create mode 100644 testdata/p4_16_samples/runtime-index-bmv2.stf create mode 100644 testdata/p4_16_samples_outputs/runtime-index-2-bmv2-first.p4 create mode 100644 testdata/p4_16_samples_outputs/runtime-index-2-bmv2-frontend.p4 create mode 100644 testdata/p4_16_samples_outputs/runtime-index-2-bmv2-midend.p4 create mode 100644 testdata/p4_16_samples_outputs/runtime-index-2-bmv2.p4 create mode 100644 testdata/p4_16_samples_outputs/runtime-index-2-bmv2.p4-stderr create mode 100644 testdata/p4_16_samples_outputs/runtime-index-2-bmv2.p4.entries.txt create mode 100644 testdata/p4_16_samples_outputs/runtime-index-2-bmv2.p4.p4info.txt create mode 100644 testdata/p4_16_samples_outputs/runtime-index-bmv2-first.p4 create mode 100644 testdata/p4_16_samples_outputs/runtime-index-bmv2-frontend.p4 create mode 100644 testdata/p4_16_samples_outputs/runtime-index-bmv2-midend.p4 create mode 100644 testdata/p4_16_samples_outputs/runtime-index-bmv2.p4 create mode 100644 testdata/p4_16_samples_outputs/runtime-index-bmv2.p4-stderr create mode 100644 testdata/p4_16_samples_outputs/runtime-index-bmv2.p4.entries.txt create mode 100644 testdata/p4_16_samples_outputs/runtime-index-bmv2.p4.p4info.txt diff --git a/backends/bmv2/CMakeLists.txt b/backends/bmv2/CMakeLists.txt index 0b92e83b1d1..77cfd75fe38 100644 --- a/backends/bmv2/CMakeLists.txt +++ b/backends/bmv2/CMakeLists.txt @@ -184,8 +184,6 @@ set (XFAIL_TESTS # Next two use unknown externs testdata/p4_16_samples/issue1882-bmv2.p4 testdata/p4_16_samples/issue1882-1-bmv2.p4 - # Uses non-constant array index - testdata/p4_16_samples/issue1989-bmv2.p4 ) if (HAVE_SIMPLE_SWITCH) diff --git a/backends/bmv2/common/action.cpp b/backends/bmv2/common/action.cpp index ef262befe34..0caa92fa573 100644 --- a/backends/bmv2/common/action.cpp +++ b/backends/bmv2/common/action.cpp @@ -70,9 +70,14 @@ void ActionConverter::convertActionBody(const IR::Vector* body, auto primitive = mkPrimitive(operation, result); auto parameters = mkParameters(primitive); primitive->emplace_non_null("source_info", assign->sourceInfoJsonObj()); - auto left = ctxt->conv->convertLeftValue(l); - parameters->append(left); bool convertBool = type->is(); + Util::IJson* left; + if (ctxt->conv->isArrayIndexRuntime(l)) { + left = ctxt->conv->convert(l, true, true, convertBool); + } else { + left = ctxt->conv->convertLeftValue(l); + } + parameters->append(left); auto right = ctxt->conv->convert(r, true, true, convertBool); parameters->append(right); continue; diff --git a/backends/bmv2/common/expression.cpp b/backends/bmv2/common/expression.cpp index 5246aeef6a0..181a1484acd 100644 --- a/backends/bmv2/common/expression.cpp +++ b/backends/bmv2/common/expression.cpp @@ -184,32 +184,50 @@ void ExpressionConverter::postorder(const IR::Constant* expression) { void ExpressionConverter::postorder(const IR::ArrayIndex* expression) { auto result = new Util::JsonObject(); - result->emplace("type", "header"); cstring elementAccess; + LOG2("left: " << expression->left << " right: " << expression->right); // This is can be either a header, which is part of the "headers" parameter // or a temporary array. - if (expression->left->is()) { + if (auto mem = expression->left->to()) { // This is a header part of the parameters - auto mem = expression->left->to(); auto parentType = typeMap->getType(mem->expr, true); BUG_CHECK(parentType->is(), "%1%: expected a struct", parentType); auto st = parentType->to(); auto field = st->getField(mem->member); elementAccess = field->controlPlaneName(); - } else if (expression->left->is()) { + } else if (auto path = expression->left->to()) { // This is a temporary variable with type stack. - auto path = expression->left->to(); elementAccess = path->path->name; } if (!expression->right->is()) { - ::error(ErrorType::ERR_INVALID, "all array indexes must be constant", expression->right); + const IR::Expression* ex = expression->right; + auto fresult = ::get(map, ex); + if (fresult == nullptr) { + LOG2("Looking up " << ex); + for (auto it : map) { + LOG3(" " << it.first << " " << it.second); + } + } + BUG_CHECK(fresult, "%1%: Runtime array index json generation failed", ex); + Util::JsonObject* fres = fresult->to(); + result->emplace("type", "expression"); + + auto e = new Util::JsonObject(); + e->emplace("op", "dereference_header_stack"); + auto l = new Util::JsonObject(); + l->emplace("type", "header_stack"); + l->emplace("value", elementAccess); + e->emplace("left", l); + e->emplace("right", fres); + result->emplace("value", e); } else { + result->emplace("type", "header"); int index = expression->right->to()->asInt(); elementAccess += "[" + Util::toString(index) + "]"; + result->emplace("value", elementAccess); } - result->emplace("value", elementAccess); mapExpression(expression, result); } @@ -232,17 +250,19 @@ ExpressionConverter::enclosingParamReference(const IR::Expression* expression) { void ExpressionConverter::postorder(const IR::Member* expression) { auto result = new Util::JsonObject(); + int index_pos = 0; auto parentType = typeMap->getType(expression->expr, true); cstring fieldName = expression->member.name; auto type = typeMap->getType(expression, true); - if (parentType->is()) { - auto st = parentType->to(); + if (auto st = parentType->to()) { auto field = st->getField(expression->member); - if (field != nullptr) + if (field != nullptr) { // field could be a method call, i.e., isValid. fieldName = field->controlPlaneName(); + index_pos = st->getFieldIndex(fieldName); + } } // handle error @@ -279,8 +299,8 @@ void ExpressionConverter::postorder(const IR::Member* expression) { } else if (parentType->is()) { auto l = get(expression->expr); cstring nestedField = fieldName; - if (l->is()) { - auto lv = l->to()->get("value"); + if (auto lv = l->to()) { + lv->get("value"); if (lv->is()) { // header in union reference ["u", "f"] => "u.f" cstring prefix = lv->to()->getString(); @@ -384,8 +404,13 @@ void ExpressionConverter::postorder(const IR::Member* expression) { e->emplace("right", l); } else { const char* fieldRef = parentType->is() ? "stack_field" : "field"; - result->emplace("type", fieldRef); - auto e = mkArrayField(result, "value"); + Util::JsonArray* e; + bool st = isArrayIndexRuntime(expression); + if (!st) { + result->emplace("type", fieldRef); + e = mkArrayField(result, "value"); + } + if (l->is()) { auto lv = l->to()->get("value"); if (lv->is()) { @@ -403,6 +428,19 @@ void ExpressionConverter::postorder(const IR::Member* expression) { } else if (lv->is()) { e->append(lv); e->append(fieldName); + } else if (auto jo = l->to()) { + if (st) { + if (index_pos < 0) { + ::error(ErrorType::ERR_INVALID, "Bmv2: Struct has no field " + "for runtime index computation %1%", st); + } + result->emplace("type", "expression"); + auto e = new Util::JsonObject(); + result->emplace("value", e); + e->emplace("op", "access_field"); + e->emplace("left", jo); + e->emplace("right", index_pos); + } } else { BUG("%1%: Unexpected json", lv); } @@ -426,8 +464,7 @@ void ExpressionConverter::postorder(const IR::Member* expression) { } Util::IJson* ExpressionConverter::fixLocal(Util::IJson* json) { - if (json->is()) { - auto jo = json->to(); + if (auto jo = json->to()) { auto to = jo->get("type"); if (to != nullptr && to->to() != nullptr && (*to->to()) == "runtime_data") { @@ -699,6 +736,18 @@ void ExpressionConverter::postorder(const IR::Expression* expression) { BUG("%1%: Unhandled case", expression); } +bool ExpressionConverter::isArrayIndexRuntime(const IR::Expression* e) { + if (auto mem = e->to()) { + if (auto ai = mem->expr->to()) { + auto right = ai->right; + if (!right->is()) { + return true; + } + } + } + return false; +} + // doFixup = true -> insert masking operations for proper arithmetic implementation // see below for wrap Util::IJson* diff --git a/backends/bmv2/common/expression.h b/backends/bmv2/common/expression.h index 77e03334cca..9ef95eccee5 100644 --- a/backends/bmv2/common/expression.h +++ b/backends/bmv2/common/expression.h @@ -102,6 +102,7 @@ class ExpressionConverter : public Inspector { bool wrap = true, bool convertBool = false); Util::IJson* convertLeftValue(const IR::Expression* e); Util::IJson* convertWithConstantWidths(const IR::Expression* e); + bool isArrayIndexRuntime(const IR::Expression* e); void postorder(const IR::BoolLiteral* expression) override; void postorder(const IR::MethodCallExpression* expression) override; diff --git a/ir/type.def b/ir/type.def index 3a7c2171ab3..22944f3d5c4 100644 --- a/ir/type.def +++ b/ir/type.def @@ -233,6 +233,15 @@ abstract Type_StructLike : Type_Declaration, ISimpleNamespace, IAnnotated { return fields.getDeclarations(); } StructField getField(cstring name) const { return fields.getDeclaration(name); } + int getFieldIndex(cstring name) const { + int index_pos = 0; + for (auto f : fields) { + if (f->name == name) + return index_pos; + index_pos++; + } + return -1; + } int width_bits() const override { int rv = 0; for (auto f : fields) { diff --git a/lib/json.cpp b/lib/json.cpp index 7fa15907167..958d5967ce4 100644 --- a/lib/json.cpp +++ b/lib/json.cpp @@ -192,8 +192,12 @@ JsonObject* JsonObject::emplace(cstring label, IJson* value) { if (label.isNullOrEmpty()) throw std::logic_error("Empty label"); auto j = get(label); - if (j != nullptr) - throw std::logic_error(cstring("Duplicate label in json object ") + label.c_str()); + if (j != nullptr) { + cstring s = value->toString(); + throw std::logic_error(cstring("Attempt to add to json object a value " + "for a label which already exists ") + + label.c_str() + " " + s.c_str()); + } ordered_map::emplace(label, value); return this; } diff --git a/testdata/p4_16_samples/runtime-index-2-bmv2.p4 b/testdata/p4_16_samples/runtime-index-2-bmv2.p4 new file mode 100644 index 00000000000..f55f32f6a41 --- /dev/null +++ b/testdata/p4_16_samples/runtime-index-2-bmv2.p4 @@ -0,0 +1,105 @@ +/* +* Copyright 2020, MNK Labs & Consulting +* http://mnkcg.com +* +* 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 + +typedef bit<48> mac_addr_t; + +header ethernet_t { + mac_addr_t dstAddr; + mac_addr_t srcAddr; + bit<16> etherType; +} + +header ml_hdr_t { + bit<8> idx1; + bit<8> idx2; +} + +header vec_e_t { + bit<8> e; +} + +struct headers { + ethernet_t ethernet; + ml_hdr_t ml; + vec_e_t[8] vector; +} + +struct metadata_t { +} + +parser MyParser(packet_in packet, out headers hdr, inout metadata_t meta, + inout standard_metadata_t standard_metadata) { + state start { + packet.extract(hdr.ethernet); + packet.extract(hdr.ml); + packet.extract(hdr.vector[0]); + packet.extract(hdr.vector[1]); + packet.extract(hdr.vector[2]); + packet.extract(hdr.vector[3]); + packet.extract(hdr.vector[4]); + packet.extract(hdr.vector[5]); + packet.extract(hdr.vector[6]); + packet.extract(hdr.vector[7]); + transition accept; + } +} + +control ingress(inout headers hdr, inout metadata_t meta, + inout standard_metadata_t standard_metadata) { + apply { + // Test runtime index with arithmetic expression as index, as + // L-value. + hdr.vector[hdr.ml.idx1 - (hdr.ml.idx2 >> 8w1)].e = + hdr.ethernet.etherType[15:8] + 7; + // similar, but with runtime index as R-value. + hdr.ethernet.etherType[7:0] = hdr.vector[(hdr.ml.idx2 ^ 8w0x07) & 8w0x7].e; + + // TODO: The line of code below is commented out + // because p4c compilation fails. Another PR will + // fix the failure. + // Test runtime index with arithmetic expression as index, + // where that arithmetic expression includes another header + // stack index with a runtime variable value. + // hdr.vector[hdr.vector[hdr.ethernet.dstAddr[39:32] & 0x7].e & 0x7].e = + // hdr.ethernet.dstAddr[47:40]; + } +} + +control egress(inout headers hdr, inout metadata_t meta, + inout standard_metadata_t standard_metadata) { + apply {} +} + +control MyVerifyChecksum(inout headers hdr, inout metadata_t meta) { + apply {} +} + +control MyComputeChecksum(inout headers hdr, inout metadata_t meta) { + apply {} +} + +control MyDeparser(packet_out packet, in headers hdr) { + apply { + packet.emit(hdr); + } +} + +V1Switch(MyParser(), MyVerifyChecksum(), ingress(), egress(), +MyComputeChecksum(), MyDeparser()) main; diff --git a/testdata/p4_16_samples/runtime-index-2-bmv2.stf b/testdata/p4_16_samples/runtime-index-2-bmv2.stf new file mode 100644 index 00000000000..f1aa457ab85 --- /dev/null +++ b/testdata/p4_16_samples/runtime-index-2-bmv2.stf @@ -0,0 +1,65 @@ +###################################################################### + +packet 0 ca0107fc001c111111111111f00d 0805 01234567 89abcdef +# ^^ ml.idx1 ^^ vector[4] +# ^^ ml.idx2 ^^ vector[7] +# ^^ vector[0] +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ethernet + +# Just before assignment: +# hdr.vector[hdr.ml.idx1 - (hdr.ml.idx2 >> 1)].e = +# hdr.ethernet.etherType[15:8] + 7; +# value of hdr.ml.idx1 - (hdr.ml.idx2 >> 1) = 0x08 - (0x05 >> 1) = 8 - 2 = 6 +# After assignment: +# changed VV +# ca0107fc001c111111111111f00d 0805 01234567 89abf7ef + +# Just before assignment: +# hdr.ethernet.etherType[7:0] = hdr.vector[(hdr.ml.idx2 ^ 0x07) & 0x7].e; +# (hdr.ml.idx2 ^ 0x07) & 0x7 = (0x05 ^ 0x07) & 0x7 = 2 & 7 = 2 +# After assignment: +# changed VV +# ca0107fc001c111111111111f045 0805 01234567 89abf7ef + +# Just before assignment: +# hdr.vector[hdr.vector[hdr.ethernet.dstAddr[39:32] & 0x7].e & 0x7].e = +# hdr.ethernet.dstAddr[47:40]; +# hdr.ethernet.dstAddr[39:32] & 0x7 = 0x01 & 0x7 = 1 +# hdr.vector[1].e & 0x7 = 0x23 & 0x7 = 3 +# changed VV +# ca0107fc001c111111111111f045 0805 012345ca 89abf7ef + +expect 0 ca0107fc001c111111111111f045 0805 01234567 89abf7ef $ + +###################################################################### + +packet 0 cafa07fc001c111111111111cafe 61b8 01234567 89abcdef +# ^^ ml.idx1 ^^ vector[4] +# ^^ ml.idx2 ^^ vector[7] +# ^^ vector[0] +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ethernet + +# Just before assignment: +# hdr.vector[hdr.ml.idx1 - (hdr.ml.idx2 >> 1)].e = +# hdr.ethernet.etherType[15:8] + 7; +# value of hdr.ml.idx1 - (hdr.ml.idx2 >> 1) = 0x61 - (0xb8 >> 1) = 97 - 92 = 5 +# After assignment: +# changed VV +# cafa07fc001c111111111111cafe 61b8 01234567 89d1cdef + +# Just before assignment: +# hdr.ethernet.etherType[7:0] = hdr.vector[(hdr.ml.idx2 ^ 0x07) & 0x7].e; +# (hdr.ml.idx2 ^ 0x07) & 0x7 = (0xb8 ^ 0x07) & 0x7 = 0xbf & 0x7 = 7 +# After assignment: +# changed VV +# cafa07fc001c111111111111caef 61b8 01234567 89cacdef + +# Just before assignment: +# hdr.vector[hdr.vector[hdr.ethernet.dstAddr[39:32] & 0x7].e & 0x7].e = +# hdr.ethernet.dstAddr[47:40]; +# hdr.ethernet.dstAddr[39:32] & 0x7 = 0xfa & 0x7 = 2 +# hdr.vector[2].e & 0x7 = 0x45 & 0x7 = 5 +# changed VV +# cafa07fc001c111111111111caef 61b8 01234567 89cacdef + +expect 0 cafa07fc001c111111111111caef 61b8 01234567 89d1cdef $ \ No newline at end of file diff --git a/testdata/p4_16_samples/runtime-index-bmv2.p4 b/testdata/p4_16_samples/runtime-index-bmv2.p4 new file mode 100644 index 00000000000..0a2198f8095 --- /dev/null +++ b/testdata/p4_16_samples/runtime-index-bmv2.p4 @@ -0,0 +1,111 @@ +/* +* Copyright 2020, MNK Labs & Consulting +* http://mnkcg.com +* +* 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 + +typedef bit<48> mac_addr_t; + +header aggregator_t { + bit<8> base0; + bit<8> base1; + bit<8> base2; + bit<8> base3; + bit<8> val; +} +header vec_e_t { + bit<8> e; +} + +header ml_hdr_t { + int<8> idx; +} + +header ethernet_t { + mac_addr_t dstAddr; + mac_addr_t srcAddr; + bit<16> etherType; +} + +struct headers { + ethernet_t ethernet; + ml_hdr_t ml; + vec_e_t[3] vector; + aggregator_t[3] pool; +} + +struct metadata_t { + int<8> counter; +} + +parser MyParser(packet_in packet, out headers hdr, inout metadata_t meta, + inout standard_metadata_t standard_metadata) { + state start { + packet.extract(hdr.ethernet); + packet.extract(hdr.ml); + packet.extract(hdr.vector[0]); + packet.extract(hdr.vector[1]); + packet.extract(hdr.vector[2]); + packet.extract(hdr.pool[0]); + packet.extract(hdr.pool[1]); + packet.extract(hdr.pool[2]); + meta.counter = 0; + transition accept; + } +} + +control ingress(inout headers hdr, inout metadata_t meta, + inout standard_metadata_t standard_metadata) { + apply { + // Legacy programs should not break + meta.counter = meta.counter + 1; + hdr.vector[0].e = hdr.pool[1].val + 1; + // end legacy test. + + // Test runtime index as l-value. + hdr.pool[hdr.ml.idx].val = hdr.vector[0].e; + hdr.pool[hdr.ml.idx].base2 = hdr.vector[0].e; + // Test runtime index as r-value. + hdr.vector[1].e = hdr.pool[hdr.ml.idx].base0; + // Test runtime index as l- and r-values. + hdr.pool[hdr.ml.idx].base0 = hdr.pool[hdr.ml.idx].base1 + 1; + standard_metadata.egress_spec = standard_metadata.ingress_port; + } +} + +control egress(inout headers hdr, inout metadata_t meta, + inout standard_metadata_t standard_metadata) { + apply {} +} + +control MyVerifyChecksum(inout headers hdr, inout metadata_t meta) { + apply {} +} + +control MyComputeChecksum(inout headers hdr, inout metadata_t meta) { + apply {} +} + +control MyDeparser(packet_out packet, in headers hdr) { + apply { + packet.emit(hdr); + } +} + +V1Switch(MyParser(), MyVerifyChecksum(), ingress(), egress(), +MyComputeChecksum(), MyDeparser()) main; + diff --git a/testdata/p4_16_samples/runtime-index-bmv2.stf b/testdata/p4_16_samples/runtime-index-bmv2.stf new file mode 100644 index 00000000000..ff5cc94f9e8 --- /dev/null +++ b/testdata/p4_16_samples/runtime-index-bmv2.stf @@ -0,0 +1,88 @@ +# +# * Copyright 2020 Cisco Systems, 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. +# * +# + +###################################################################### + +# runtime index is max = 02 and hdr.ml.idx in P4 code. +packet 0 ca0107fc001c1111111111110800 02 010203 0000000001 0123456789 abcdef0123 +# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ethernet ^^^^^^^^^^ pool[0].base0 thru .base4, then .val +# ^^ ml.idx ^^^^^^^^^^ pool[1] +# ^^ vector[0].e ^^^^^^^^^^ pool[2] +# ^^ vector[1].e +# ^^ vector[2].e + +# - denotes unspecified/unknown values + +# After assignment: +# hdr.vector[0].e = hdr.pool[1].val + 1; +# changed VV +# ca0107fc001c1111111111110800 02 8a0203 0000000001 0123456789 abcdef0123 + +# After assignment: +# hdr.pool[hdr.ml.idx].val = hdr.vector[0].e; +# changed VV +# ca0107fc001c1111111111110800 02 8a0203 0000000001 0123456789 abcdef018a + +# After assignment: +# hdr.pool[hdr.ml.idx].base2 = hdr.vector[0].e; +# changed VV +# ca0107fc001c1111111111110800 02 8a0203 0000000001 0123456789 abcd8a018a + +# After assignment: + hdr.vector[1].e = hdr.pool[hdr.ml.idx].base0; +# changed VV +# ca0107fc001c1111111111110800 02 8aab03 0000000001 0123456789 abcd8a018a + +# After assignment: +# hdr.pool[hdr.ml.idx].base0 = hdr.pool[hdr.ml.idx].base1 + 1; +# changed VV +# ca0107fc001c1111111111110800 02 8aab03 0000000001 0123456789 cecd8a018a + +expect 0 ca0107fc001c1111111111110800 02 8aab03 0000000001 0123456789 cecd8a018a + +###################################################################### + +# runtime index is min = 00 +packet 0 ca0107fc001c1111111111110800 00 010203 deadbeeff0 0123456789 abcdef0123 + +# After assignment: +# hdr.vector[0].e = hdr.pool[1].val + 1; +# changed VV +# ca0107fc001c1111111111110800 00 8a0203 deadbeeff0 0123456789 abcdef0123 + +# After assignment: +# hdr.pool[hdr.ml.idx].val = hdr.vector[0].e; +# changed VV +# ca0107fc001c1111111111110800 00 8a0203 deadbeef8a 0123456789 abcdef0123 + +# After assignment: +# hdr.pool[hdr.ml.idx].base2 = hdr.vector[0].e; +# changed VV +# ca0107fc001c1111111111110800 00 8a0203 dead8aef8a 0123456789 abcdef0123 + +# After assignment: + hdr.vector[1].e = hdr.pool[hdr.ml.idx].base0; +# changed VV +# ca0107fc001c1111111111110800 00 8ade03 dead8aef8a 0123456789 abcdef0123 + +# After assignment: +# hdr.pool[hdr.ml.idx].base0 = hdr.pool[hdr.ml.idx].base1 + 1; +# changed VV +# ca0107fc001c1111111111110800 00 8ade03 aead8aef8a 0123456789 abcdef0123 + +expect 0 ca0107fc001c1111111111110800 00 8ade03 aead8aef8a 0123456789 abcdef0123 + diff --git a/testdata/p4_16_samples_outputs/runtime-index-2-bmv2-first.p4 b/testdata/p4_16_samples_outputs/runtime-index-2-bmv2-first.p4 new file mode 100644 index 00000000000..6a45ef4be99 --- /dev/null +++ b/testdata/p4_16_samples_outputs/runtime-index-2-bmv2-first.p4 @@ -0,0 +1,74 @@ +#include +#include + +typedef bit<48> mac_addr_t; +header ethernet_t { + mac_addr_t dstAddr; + mac_addr_t srcAddr; + bit<16> etherType; +} + +header ml_hdr_t { + bit<8> idx1; + bit<8> idx2; +} + +header vec_e_t { + bit<8> e; +} + +struct headers { + ethernet_t ethernet; + ml_hdr_t ml; + vec_e_t[8] vector; +} + +struct metadata_t { +} + +parser MyParser(packet_in packet, out headers hdr, inout metadata_t meta, inout standard_metadata_t standard_metadata) { + state start { + packet.extract(hdr.ethernet); + packet.extract(hdr.ml); + packet.extract(hdr.vector[0]); + packet.extract(hdr.vector[1]); + packet.extract(hdr.vector[2]); + packet.extract(hdr.vector[3]); + packet.extract(hdr.vector[4]); + packet.extract(hdr.vector[5]); + packet.extract(hdr.vector[6]); + packet.extract(hdr.vector[7]); + transition accept; + } +} + +control ingress(inout headers hdr, inout metadata_t meta, inout standard_metadata_t standard_metadata) { + apply { + hdr.vector[hdr.ml.idx1 - (hdr.ml.idx2 >> 8w1)].e = hdr.ethernet.etherType[15:8] + 8w7; + hdr.ethernet.etherType[7:0] = hdr.vector[(hdr.ml.idx2 ^ 8w0x7) & 8w0x7].e; + } +} + +control egress(inout headers hdr, inout metadata_t meta, inout standard_metadata_t standard_metadata) { + apply { + } +} + +control MyVerifyChecksum(inout headers hdr, inout metadata_t meta) { + apply { + } +} + +control MyComputeChecksum(inout headers hdr, inout metadata_t meta) { + apply { + } +} + +control MyDeparser(packet_out packet, in headers hdr) { + apply { + packet.emit(hdr); + } +} + +V1Switch(MyParser(), MyVerifyChecksum(), ingress(), egress(), MyComputeChecksum(), MyDeparser()) main; + diff --git a/testdata/p4_16_samples_outputs/runtime-index-2-bmv2-frontend.p4 b/testdata/p4_16_samples_outputs/runtime-index-2-bmv2-frontend.p4 new file mode 100644 index 00000000000..6a45ef4be99 --- /dev/null +++ b/testdata/p4_16_samples_outputs/runtime-index-2-bmv2-frontend.p4 @@ -0,0 +1,74 @@ +#include +#include + +typedef bit<48> mac_addr_t; +header ethernet_t { + mac_addr_t dstAddr; + mac_addr_t srcAddr; + bit<16> etherType; +} + +header ml_hdr_t { + bit<8> idx1; + bit<8> idx2; +} + +header vec_e_t { + bit<8> e; +} + +struct headers { + ethernet_t ethernet; + ml_hdr_t ml; + vec_e_t[8] vector; +} + +struct metadata_t { +} + +parser MyParser(packet_in packet, out headers hdr, inout metadata_t meta, inout standard_metadata_t standard_metadata) { + state start { + packet.extract(hdr.ethernet); + packet.extract(hdr.ml); + packet.extract(hdr.vector[0]); + packet.extract(hdr.vector[1]); + packet.extract(hdr.vector[2]); + packet.extract(hdr.vector[3]); + packet.extract(hdr.vector[4]); + packet.extract(hdr.vector[5]); + packet.extract(hdr.vector[6]); + packet.extract(hdr.vector[7]); + transition accept; + } +} + +control ingress(inout headers hdr, inout metadata_t meta, inout standard_metadata_t standard_metadata) { + apply { + hdr.vector[hdr.ml.idx1 - (hdr.ml.idx2 >> 8w1)].e = hdr.ethernet.etherType[15:8] + 8w7; + hdr.ethernet.etherType[7:0] = hdr.vector[(hdr.ml.idx2 ^ 8w0x7) & 8w0x7].e; + } +} + +control egress(inout headers hdr, inout metadata_t meta, inout standard_metadata_t standard_metadata) { + apply { + } +} + +control MyVerifyChecksum(inout headers hdr, inout metadata_t meta) { + apply { + } +} + +control MyComputeChecksum(inout headers hdr, inout metadata_t meta) { + apply { + } +} + +control MyDeparser(packet_out packet, in headers hdr) { + apply { + packet.emit(hdr); + } +} + +V1Switch(MyParser(), MyVerifyChecksum(), ingress(), egress(), MyComputeChecksum(), MyDeparser()) main; + diff --git a/testdata/p4_16_samples_outputs/runtime-index-2-bmv2-midend.p4 b/testdata/p4_16_samples_outputs/runtime-index-2-bmv2-midend.p4 new file mode 100644 index 00000000000..5f7852cec05 --- /dev/null +++ b/testdata/p4_16_samples_outputs/runtime-index-2-bmv2-midend.p4 @@ -0,0 +1,92 @@ +#include +#include + +typedef bit<48> mac_addr_t; +header ethernet_t { + mac_addr_t dstAddr; + mac_addr_t srcAddr; + bit<16> etherType; +} + +header ml_hdr_t { + bit<8> idx1; + bit<8> idx2; +} + +header vec_e_t { + bit<8> e; +} + +struct headers { + ethernet_t ethernet; + ml_hdr_t ml; + vec_e_t[8] vector; +} + +struct metadata_t { +} + +parser MyParser(packet_in packet, out headers hdr, inout metadata_t meta, inout standard_metadata_t standard_metadata) { + state start { + packet.extract(hdr.ethernet); + packet.extract(hdr.ml); + packet.extract(hdr.vector[0]); + packet.extract(hdr.vector[1]); + packet.extract(hdr.vector[2]); + packet.extract(hdr.vector[3]); + packet.extract(hdr.vector[4]); + packet.extract(hdr.vector[5]); + packet.extract(hdr.vector[6]); + packet.extract(hdr.vector[7]); + transition accept; + } +} + +control ingress(inout headers hdr, inout metadata_t meta, inout standard_metadata_t standard_metadata) { + @hidden action runtimeindex2bmv2l69() { + hdr.vector[hdr.ml.idx1 - (hdr.ml.idx2 >> 8w1)].e = hdr.ethernet.etherType[15:8] + 8w7; + hdr.ethernet.etherType[7:0] = hdr.vector[(hdr.ml.idx2 ^ 8w0x7) & 8w0x7].e; + } + @hidden table tbl_runtimeindex2bmv2l69 { + actions = { + runtimeindex2bmv2l69(); + } + const default_action = runtimeindex2bmv2l69(); + } + apply { + tbl_runtimeindex2bmv2l69.apply(); + } +} + +control egress(inout headers hdr, inout metadata_t meta, inout standard_metadata_t standard_metadata) { + apply { + } +} + +control MyVerifyChecksum(inout headers hdr, inout metadata_t meta) { + apply { + } +} + +control MyComputeChecksum(inout headers hdr, inout metadata_t meta) { + apply { + } +} + +control MyDeparser(packet_out packet, in headers hdr) { + apply { + packet.emit(hdr.ethernet); + packet.emit(hdr.ml); + packet.emit(hdr.vector[0]); + packet.emit(hdr.vector[1]); + packet.emit(hdr.vector[2]); + packet.emit(hdr.vector[3]); + packet.emit(hdr.vector[4]); + packet.emit(hdr.vector[5]); + packet.emit(hdr.vector[6]); + packet.emit(hdr.vector[7]); + } +} + +V1Switch(MyParser(), MyVerifyChecksum(), ingress(), egress(), MyComputeChecksum(), MyDeparser()) main; + diff --git a/testdata/p4_16_samples_outputs/runtime-index-2-bmv2.p4 b/testdata/p4_16_samples_outputs/runtime-index-2-bmv2.p4 new file mode 100644 index 00000000000..2fd3c863794 --- /dev/null +++ b/testdata/p4_16_samples_outputs/runtime-index-2-bmv2.p4 @@ -0,0 +1,74 @@ +#include +#include + +typedef bit<48> mac_addr_t; +header ethernet_t { + mac_addr_t dstAddr; + mac_addr_t srcAddr; + bit<16> etherType; +} + +header ml_hdr_t { + bit<8> idx1; + bit<8> idx2; +} + +header vec_e_t { + bit<8> e; +} + +struct headers { + ethernet_t ethernet; + ml_hdr_t ml; + vec_e_t[8] vector; +} + +struct metadata_t { +} + +parser MyParser(packet_in packet, out headers hdr, inout metadata_t meta, inout standard_metadata_t standard_metadata) { + state start { + packet.extract(hdr.ethernet); + packet.extract(hdr.ml); + packet.extract(hdr.vector[0]); + packet.extract(hdr.vector[1]); + packet.extract(hdr.vector[2]); + packet.extract(hdr.vector[3]); + packet.extract(hdr.vector[4]); + packet.extract(hdr.vector[5]); + packet.extract(hdr.vector[6]); + packet.extract(hdr.vector[7]); + transition accept; + } +} + +control ingress(inout headers hdr, inout metadata_t meta, inout standard_metadata_t standard_metadata) { + apply { + hdr.vector[hdr.ml.idx1 - (hdr.ml.idx2 >> 8w1)].e = hdr.ethernet.etherType[15:8] + 7; + hdr.ethernet.etherType[7:0] = hdr.vector[(hdr.ml.idx2 ^ 8w0x7) & 8w0x7].e; + } +} + +control egress(inout headers hdr, inout metadata_t meta, inout standard_metadata_t standard_metadata) { + apply { + } +} + +control MyVerifyChecksum(inout headers hdr, inout metadata_t meta) { + apply { + } +} + +control MyComputeChecksum(inout headers hdr, inout metadata_t meta) { + apply { + } +} + +control MyDeparser(packet_out packet, in headers hdr) { + apply { + packet.emit(hdr); + } +} + +V1Switch(MyParser(), MyVerifyChecksum(), ingress(), egress(), MyComputeChecksum(), MyDeparser()) main; + diff --git a/testdata/p4_16_samples_outputs/runtime-index-2-bmv2.p4-stderr b/testdata/p4_16_samples_outputs/runtime-index-2-bmv2.p4-stderr new file mode 100644 index 00000000000..e69de29bb2d diff --git a/testdata/p4_16_samples_outputs/runtime-index-2-bmv2.p4.entries.txt b/testdata/p4_16_samples_outputs/runtime-index-2-bmv2.p4.entries.txt new file mode 100644 index 00000000000..e69de29bb2d diff --git a/testdata/p4_16_samples_outputs/runtime-index-2-bmv2.p4.p4info.txt b/testdata/p4_16_samples_outputs/runtime-index-2-bmv2.p4.p4info.txt new file mode 100644 index 00000000000..9ec92493e4c --- /dev/null +++ b/testdata/p4_16_samples_outputs/runtime-index-2-bmv2.p4.p4info.txt @@ -0,0 +1,3 @@ +pkg_info { + arch: "v1model" +} diff --git a/testdata/p4_16_samples_outputs/runtime-index-bmv2-first.p4 b/testdata/p4_16_samples_outputs/runtime-index-bmv2-first.p4 new file mode 100644 index 00000000000..ef6c1e03421 --- /dev/null +++ b/testdata/p4_16_samples_outputs/runtime-index-bmv2-first.p4 @@ -0,0 +1,87 @@ +#include +#include + +typedef bit<48> mac_addr_t; +header aggregator_t { + bit<8> base0; + bit<8> base1; + bit<8> base2; + bit<8> base3; + bit<8> val; +} + +header vec_e_t { + bit<8> e; +} + +header ml_hdr_t { + int<8> idx; +} + +header ethernet_t { + mac_addr_t dstAddr; + mac_addr_t srcAddr; + bit<16> etherType; +} + +struct headers { + ethernet_t ethernet; + ml_hdr_t ml; + vec_e_t[3] vector; + aggregator_t[3] pool; +} + +struct metadata_t { + int<8> counter; +} + +parser MyParser(packet_in packet, out headers hdr, inout metadata_t meta, inout standard_metadata_t standard_metadata) { + state start { + packet.extract(hdr.ethernet); + packet.extract(hdr.ml); + packet.extract(hdr.vector[0]); + packet.extract(hdr.vector[1]); + packet.extract(hdr.vector[2]); + packet.extract(hdr.pool[0]); + packet.extract(hdr.pool[1]); + packet.extract(hdr.pool[2]); + meta.counter = 8s0; + transition accept; + } +} + +control ingress(inout headers hdr, inout metadata_t meta, inout standard_metadata_t standard_metadata) { + apply { + meta.counter = meta.counter + 8s1; + hdr.vector[0].e = hdr.pool[1].val + 8w1; + hdr.pool[hdr.ml.idx].val = hdr.vector[0].e; + hdr.pool[hdr.ml.idx].base2 = hdr.vector[0].e; + hdr.vector[1].e = hdr.pool[hdr.ml.idx].base0; + hdr.pool[hdr.ml.idx].base0 = hdr.pool[hdr.ml.idx].base1 + 8w1; + standard_metadata.egress_spec = standard_metadata.ingress_port; + } +} + +control egress(inout headers hdr, inout metadata_t meta, inout standard_metadata_t standard_metadata) { + apply { + } +} + +control MyVerifyChecksum(inout headers hdr, inout metadata_t meta) { + apply { + } +} + +control MyComputeChecksum(inout headers hdr, inout metadata_t meta) { + apply { + } +} + +control MyDeparser(packet_out packet, in headers hdr) { + apply { + packet.emit(hdr); + } +} + +V1Switch(MyParser(), MyVerifyChecksum(), ingress(), egress(), MyComputeChecksum(), MyDeparser()) main; + diff --git a/testdata/p4_16_samples_outputs/runtime-index-bmv2-frontend.p4 b/testdata/p4_16_samples_outputs/runtime-index-bmv2-frontend.p4 new file mode 100644 index 00000000000..ef6c1e03421 --- /dev/null +++ b/testdata/p4_16_samples_outputs/runtime-index-bmv2-frontend.p4 @@ -0,0 +1,87 @@ +#include +#include + +typedef bit<48> mac_addr_t; +header aggregator_t { + bit<8> base0; + bit<8> base1; + bit<8> base2; + bit<8> base3; + bit<8> val; +} + +header vec_e_t { + bit<8> e; +} + +header ml_hdr_t { + int<8> idx; +} + +header ethernet_t { + mac_addr_t dstAddr; + mac_addr_t srcAddr; + bit<16> etherType; +} + +struct headers { + ethernet_t ethernet; + ml_hdr_t ml; + vec_e_t[3] vector; + aggregator_t[3] pool; +} + +struct metadata_t { + int<8> counter; +} + +parser MyParser(packet_in packet, out headers hdr, inout metadata_t meta, inout standard_metadata_t standard_metadata) { + state start { + packet.extract(hdr.ethernet); + packet.extract(hdr.ml); + packet.extract(hdr.vector[0]); + packet.extract(hdr.vector[1]); + packet.extract(hdr.vector[2]); + packet.extract(hdr.pool[0]); + packet.extract(hdr.pool[1]); + packet.extract(hdr.pool[2]); + meta.counter = 8s0; + transition accept; + } +} + +control ingress(inout headers hdr, inout metadata_t meta, inout standard_metadata_t standard_metadata) { + apply { + meta.counter = meta.counter + 8s1; + hdr.vector[0].e = hdr.pool[1].val + 8w1; + hdr.pool[hdr.ml.idx].val = hdr.vector[0].e; + hdr.pool[hdr.ml.idx].base2 = hdr.vector[0].e; + hdr.vector[1].e = hdr.pool[hdr.ml.idx].base0; + hdr.pool[hdr.ml.idx].base0 = hdr.pool[hdr.ml.idx].base1 + 8w1; + standard_metadata.egress_spec = standard_metadata.ingress_port; + } +} + +control egress(inout headers hdr, inout metadata_t meta, inout standard_metadata_t standard_metadata) { + apply { + } +} + +control MyVerifyChecksum(inout headers hdr, inout metadata_t meta) { + apply { + } +} + +control MyComputeChecksum(inout headers hdr, inout metadata_t meta) { + apply { + } +} + +control MyDeparser(packet_out packet, in headers hdr) { + apply { + packet.emit(hdr); + } +} + +V1Switch(MyParser(), MyVerifyChecksum(), ingress(), egress(), MyComputeChecksum(), MyDeparser()) main; + diff --git a/testdata/p4_16_samples_outputs/runtime-index-bmv2-midend.p4 b/testdata/p4_16_samples_outputs/runtime-index-bmv2-midend.p4 new file mode 100644 index 00000000000..b7b2f0b9594 --- /dev/null +++ b/testdata/p4_16_samples_outputs/runtime-index-bmv2-midend.p4 @@ -0,0 +1,103 @@ +#include +#include + +typedef bit<48> mac_addr_t; +header aggregator_t { + bit<8> base0; + bit<8> base1; + bit<8> base2; + bit<8> base3; + bit<8> val; +} + +header vec_e_t { + bit<8> e; +} + +header ml_hdr_t { + int<8> idx; +} + +header ethernet_t { + mac_addr_t dstAddr; + mac_addr_t srcAddr; + bit<16> etherType; +} + +struct headers { + ethernet_t ethernet; + ml_hdr_t ml; + vec_e_t[3] vector; + aggregator_t[3] pool; +} + +struct metadata_t { + int<8> counter; +} + +parser MyParser(packet_in packet, out headers hdr, inout metadata_t meta, inout standard_metadata_t standard_metadata) { + state start { + packet.extract(hdr.ethernet); + packet.extract(hdr.ml); + packet.extract(hdr.vector[0]); + packet.extract(hdr.vector[1]); + packet.extract(hdr.vector[2]); + packet.extract(hdr.pool[0]); + packet.extract(hdr.pool[1]); + packet.extract(hdr.pool[2]); + meta.counter = 8s0; + transition accept; + } +} + +control ingress(inout headers hdr, inout metadata_t meta, inout standard_metadata_t standard_metadata) { + @hidden action runtimeindexbmv2l75() { + meta.counter = meta.counter + 8s1; + hdr.vector[0].e = hdr.pool[1].val + 8w1; + hdr.pool[hdr.ml.idx].val = hdr.pool[1].val + 8w1; + hdr.pool[hdr.ml.idx].base2 = hdr.vector[0].e; + hdr.vector[1].e = hdr.pool[hdr.ml.idx].base0; + hdr.pool[hdr.ml.idx].base0 = hdr.pool[hdr.ml.idx].base1 + 8w1; + standard_metadata.egress_spec = standard_metadata.ingress_port; + } + @hidden table tbl_runtimeindexbmv2l75 { + actions = { + runtimeindexbmv2l75(); + } + const default_action = runtimeindexbmv2l75(); + } + apply { + tbl_runtimeindexbmv2l75.apply(); + } +} + +control egress(inout headers hdr, inout metadata_t meta, inout standard_metadata_t standard_metadata) { + apply { + } +} + +control MyVerifyChecksum(inout headers hdr, inout metadata_t meta) { + apply { + } +} + +control MyComputeChecksum(inout headers hdr, inout metadata_t meta) { + apply { + } +} + +control MyDeparser(packet_out packet, in headers hdr) { + apply { + packet.emit(hdr.ethernet); + packet.emit(hdr.ml); + packet.emit(hdr.vector[0]); + packet.emit(hdr.vector[1]); + packet.emit(hdr.vector[2]); + packet.emit(hdr.pool[0]); + packet.emit(hdr.pool[1]); + packet.emit(hdr.pool[2]); + } +} + +V1Switch(MyParser(), MyVerifyChecksum(), ingress(), egress(), MyComputeChecksum(), MyDeparser()) main; + diff --git a/testdata/p4_16_samples_outputs/runtime-index-bmv2.p4 b/testdata/p4_16_samples_outputs/runtime-index-bmv2.p4 new file mode 100644 index 00000000000..8e7e36c70ce --- /dev/null +++ b/testdata/p4_16_samples_outputs/runtime-index-bmv2.p4 @@ -0,0 +1,87 @@ +#include +#include + +typedef bit<48> mac_addr_t; +header aggregator_t { + bit<8> base0; + bit<8> base1; + bit<8> base2; + bit<8> base3; + bit<8> val; +} + +header vec_e_t { + bit<8> e; +} + +header ml_hdr_t { + int<8> idx; +} + +header ethernet_t { + mac_addr_t dstAddr; + mac_addr_t srcAddr; + bit<16> etherType; +} + +struct headers { + ethernet_t ethernet; + ml_hdr_t ml; + vec_e_t[3] vector; + aggregator_t[3] pool; +} + +struct metadata_t { + int<8> counter; +} + +parser MyParser(packet_in packet, out headers hdr, inout metadata_t meta, inout standard_metadata_t standard_metadata) { + state start { + packet.extract(hdr.ethernet); + packet.extract(hdr.ml); + packet.extract(hdr.vector[0]); + packet.extract(hdr.vector[1]); + packet.extract(hdr.vector[2]); + packet.extract(hdr.pool[0]); + packet.extract(hdr.pool[1]); + packet.extract(hdr.pool[2]); + meta.counter = 0; + transition accept; + } +} + +control ingress(inout headers hdr, inout metadata_t meta, inout standard_metadata_t standard_metadata) { + apply { + meta.counter = meta.counter + 1; + hdr.vector[0].e = hdr.pool[1].val + 1; + hdr.pool[hdr.ml.idx].val = hdr.vector[0].e; + hdr.pool[hdr.ml.idx].base2 = hdr.vector[0].e; + hdr.vector[1].e = hdr.pool[hdr.ml.idx].base0; + hdr.pool[hdr.ml.idx].base0 = hdr.pool[hdr.ml.idx].base1 + 1; + standard_metadata.egress_spec = standard_metadata.ingress_port; + } +} + +control egress(inout headers hdr, inout metadata_t meta, inout standard_metadata_t standard_metadata) { + apply { + } +} + +control MyVerifyChecksum(inout headers hdr, inout metadata_t meta) { + apply { + } +} + +control MyComputeChecksum(inout headers hdr, inout metadata_t meta) { + apply { + } +} + +control MyDeparser(packet_out packet, in headers hdr) { + apply { + packet.emit(hdr); + } +} + +V1Switch(MyParser(), MyVerifyChecksum(), ingress(), egress(), MyComputeChecksum(), MyDeparser()) main; + diff --git a/testdata/p4_16_samples_outputs/runtime-index-bmv2.p4-stderr b/testdata/p4_16_samples_outputs/runtime-index-bmv2.p4-stderr new file mode 100644 index 00000000000..e69de29bb2d diff --git a/testdata/p4_16_samples_outputs/runtime-index-bmv2.p4.entries.txt b/testdata/p4_16_samples_outputs/runtime-index-bmv2.p4.entries.txt new file mode 100644 index 00000000000..e69de29bb2d diff --git a/testdata/p4_16_samples_outputs/runtime-index-bmv2.p4.p4info.txt b/testdata/p4_16_samples_outputs/runtime-index-bmv2.p4.p4info.txt new file mode 100644 index 00000000000..9ec92493e4c --- /dev/null +++ b/testdata/p4_16_samples_outputs/runtime-index-bmv2.p4.p4info.txt @@ -0,0 +1,3 @@ +pkg_info { + arch: "v1model" +} From b281cddc79de75f048a2f3c663ebce5b732d2c63 Mon Sep 17 00:00:00 2001 From: Mihai Budiu Date: Tue, 28 Jan 2020 14:53:32 -0800 Subject: [PATCH 066/106] Update leftValues when lowering; fixed #2150 (#2154) --- backends/bmv2/common/lower.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/backends/bmv2/common/lower.cpp b/backends/bmv2/common/lower.cpp index 14779f5935a..c0b9461c9e5 100644 --- a/backends/bmv2/common/lower.cpp +++ b/backends/bmv2/common/lower.cpp @@ -83,8 +83,13 @@ const IR::Node* LowerExpressions::postorder(IR::Cast* expression) { const IR::Node* LowerExpressions::postorder(IR::Expression* expression) { // Just update the typeMap incrementally. - auto type = typeMap->getType(getOriginal(), true); + auto orig = getOriginal(); + auto type = typeMap->getType(orig, true); typeMap->setType(expression, type); + if (typeMap->isCompileTimeConstant(orig)) + typeMap->setCompileTimeConstant(expression); + if (typeMap->isLeftValue(orig)) + typeMap->setLeftValue(expression); return expression; } From d52ef24cb1a4e0bf034ae5d1632153f11b1d388f Mon Sep 17 00:00:00 2001 From: Mihai Budiu Date: Tue, 28 Jan 2020 17:09:06 -0800 Subject: [PATCH 067/106] Exit makes statements unreachable; fixes #2151 (#2159) * Exit makes statements unreachable; fixes #2151 --- frontends/p4/simplifyDefUse.cpp | 25 +++++++++++++------ testdata/p4_16_samples/issue2151.p4 | 17 +++++++++++++ .../p4_16_samples_outputs/issue2151-first.p4 | 16 ++++++++++++ .../issue2151-frontend.p4 | 13 ++++++++++ .../p4_16_samples_outputs/issue2151-midend.p4 | 11 ++++++++ testdata/p4_16_samples_outputs/issue2151.p4 | 16 ++++++++++++ .../p4_16_samples_outputs/issue2151.p4-stderr | 0 7 files changed, 91 insertions(+), 7 deletions(-) create mode 100644 testdata/p4_16_samples/issue2151.p4 create mode 100644 testdata/p4_16_samples_outputs/issue2151-first.p4 create mode 100644 testdata/p4_16_samples_outputs/issue2151-frontend.p4 create mode 100644 testdata/p4_16_samples_outputs/issue2151-midend.p4 create mode 100644 testdata/p4_16_samples_outputs/issue2151.p4 create mode 100644 testdata/p4_16_samples_outputs/issue2151.p4-stderr diff --git a/frontends/p4/simplifyDefUse.cpp b/frontends/p4/simplifyDefUse.cpp index a87b6389039..ddfe2d6efa9 100644 --- a/frontends/p4/simplifyDefUse.cpp +++ b/frontends/p4/simplifyDefUse.cpp @@ -165,11 +165,12 @@ class FindUninitialized : public Inspector { LOG3("FU Visiting control " << control->name << "[" << control->id << "]"); BUG_CHECK(context.isBeforeStart(), "non-empty context in FindUnitialized::P4Control"); currentPoint = ProgramPoint(control); - unreachable = false; for (auto d : control->controlLocals) - if (d->is()) + if (d->is()) { // visit virtual Function implementation if any visit(d); + } + unreachable = false; visit(control->body); checkOutParameters( control, control->getApplyMethodType()->parameters, getCurrentDefinitions()); @@ -177,16 +178,18 @@ class FindUninitialized : public Inspector { } bool preorder(const IR::Function* func) override { + if (findContext() != nullptr) { + // virtual methods. These are traversed individually at the beginning + // before the control body. We mark each as reachable. + unreachable = false; + } + BUG_CHECK(findContext() == nullptr, "Unexpected function"); LOG3("FU Visiting function " << func->name << "[" << func->id << "]"); LOG5(func); - // FIXME -- this throws away the context of the current point, which seems wrong, - // FIXME -- but otherwise analysis fails - unreachable = false; currentPoint = ProgramPoint(func); visit(func->body); bool checkReturn = !func->type->returnType->is(); checkOutParameters(func, func->type->parameters, getCurrentDefinitions(), checkReturn); - unreachable = false; // not inherited across function calls return false; } @@ -225,6 +228,13 @@ class FindUninitialized : public Inspector { return setCurrent(statement); } + bool preorder(const IR::ExitStatement* statement) override { + LOG3("FU Visiting " << statement); + unreachable = true; + LOG3("Unreachable"); + return setCurrent(statement); + } + bool preorder(const IR::MethodCallStatement* statement) override { LOG3("FU Visiting " << statement); if (!unreachable) @@ -378,7 +388,8 @@ class FindUninitialized : public Inspector { } bool preorder(const IR::P4Action* action) override { - LOG3("FU Visiting " << action); + BUG_CHECK(findContext() == nullptr, "Unexpected action"); + LOG3("FU Visiting action " << action); unreachable = false; currentPoint = ProgramPoint(context, action); visit(action->body); diff --git a/testdata/p4_16_samples/issue2151.p4 b/testdata/p4_16_samples/issue2151.p4 new file mode 100644 index 00000000000..3c4acf7f64f --- /dev/null +++ b/testdata/p4_16_samples/issue2151.p4 @@ -0,0 +1,17 @@ +control c() { + bit<16> f = 0; + bit<128> y = 0; + action a() { + y = (bit<128>)f; + } + apply { + exit; // the exit comes before the action call + a(); + } + +} + +control e(); +package top(e e); + +top(c()) main; diff --git a/testdata/p4_16_samples_outputs/issue2151-first.p4 b/testdata/p4_16_samples_outputs/issue2151-first.p4 new file mode 100644 index 00000000000..66ab9dba283 --- /dev/null +++ b/testdata/p4_16_samples_outputs/issue2151-first.p4 @@ -0,0 +1,16 @@ +control c() { + bit<16> f = 16w0; + bit<128> y = 128w0; + action a() { + y = (bit<128>)f; + } + apply { + exit; + a(); + } +} + +control e(); +package top(e e); +top(c()) main; + diff --git a/testdata/p4_16_samples_outputs/issue2151-frontend.p4 b/testdata/p4_16_samples_outputs/issue2151-frontend.p4 new file mode 100644 index 00000000000..2fc84680edc --- /dev/null +++ b/testdata/p4_16_samples_outputs/issue2151-frontend.p4 @@ -0,0 +1,13 @@ +control c() { + @name("c.a") action a() { + } + apply { + exit; + a(); + } +} + +control e(); +package top(e e); +top(c()) main; + diff --git a/testdata/p4_16_samples_outputs/issue2151-midend.p4 b/testdata/p4_16_samples_outputs/issue2151-midend.p4 new file mode 100644 index 00000000000..bc75a30a5bf --- /dev/null +++ b/testdata/p4_16_samples_outputs/issue2151-midend.p4 @@ -0,0 +1,11 @@ +control c() { + @name("c.a") action a() { + } + apply { + } +} + +control e(); +package top(e e); +top(c()) main; + diff --git a/testdata/p4_16_samples_outputs/issue2151.p4 b/testdata/p4_16_samples_outputs/issue2151.p4 new file mode 100644 index 00000000000..14e55bb2319 --- /dev/null +++ b/testdata/p4_16_samples_outputs/issue2151.p4 @@ -0,0 +1,16 @@ +control c() { + bit<16> f = 0; + bit<128> y = 0; + action a() { + y = (bit<128>)f; + } + apply { + exit; + a(); + } +} + +control e(); +package top(e e); +top(c()) main; + diff --git a/testdata/p4_16_samples_outputs/issue2151.p4-stderr b/testdata/p4_16_samples_outputs/issue2151.p4-stderr new file mode 100644 index 00000000000..e69de29bb2d From 2846c66f32124644d088d70d7640f2ad1c8b5483 Mon Sep 17 00:00:00 2001 From: Hemant Singh <32817427+hesingh@users.noreply.github.com> Date: Tue, 28 Jan 2020 20:10:17 -0500 Subject: [PATCH 068/106] Enable Slice test with runtime index (#2162) * Enable Slice test with runtime index --- testdata/p4_16_samples/runtime-index-2-bmv2.p4 | 9 +++------ testdata/p4_16_samples/runtime-index-2-bmv2.stf | 4 ++-- .../p4_16_samples_outputs/runtime-index-2-bmv2-first.p4 | 1 + .../runtime-index-2-bmv2-frontend.p4 | 1 + .../p4_16_samples_outputs/runtime-index-2-bmv2-midend.p4 | 1 + testdata/p4_16_samples_outputs/runtime-index-2-bmv2.p4 | 1 + 6 files changed, 9 insertions(+), 8 deletions(-) diff --git a/testdata/p4_16_samples/runtime-index-2-bmv2.p4 b/testdata/p4_16_samples/runtime-index-2-bmv2.p4 index f55f32f6a41..dde71ff65bc 100644 --- a/testdata/p4_16_samples/runtime-index-2-bmv2.p4 +++ b/testdata/p4_16_samples/runtime-index-2-bmv2.p4 @@ -71,14 +71,11 @@ control ingress(inout headers hdr, inout metadata_t meta, // similar, but with runtime index as R-value. hdr.ethernet.etherType[7:0] = hdr.vector[(hdr.ml.idx2 ^ 8w0x07) & 8w0x7].e; - // TODO: The line of code below is commented out - // because p4c compilation fails. Another PR will - // fix the failure. - // Test runtime index with arithmetic expression as index, + // Test runtime index with arithmetic expression as index, // where that arithmetic expression includes another header // stack index with a runtime variable value. - // hdr.vector[hdr.vector[hdr.ethernet.dstAddr[39:32] & 0x7].e & 0x7].e = - // hdr.ethernet.dstAddr[47:40]; + hdr.vector[hdr.vector[hdr.ethernet.dstAddr[39:32] & 0x7].e & 0x7].e = + hdr.ethernet.dstAddr[47:40]; } } diff --git a/testdata/p4_16_samples/runtime-index-2-bmv2.stf b/testdata/p4_16_samples/runtime-index-2-bmv2.stf index f1aa457ab85..cb56d312f2b 100644 --- a/testdata/p4_16_samples/runtime-index-2-bmv2.stf +++ b/testdata/p4_16_samples/runtime-index-2-bmv2.stf @@ -29,7 +29,7 @@ packet 0 ca0107fc001c111111111111f00d 0805 01234567 89abcdef # changed VV # ca0107fc001c111111111111f045 0805 012345ca 89abf7ef -expect 0 ca0107fc001c111111111111f045 0805 01234567 89abf7ef $ +expect 0 ca0107fc001c111111111111f045 0805 012345ca 89abf7ef $ ###################################################################### @@ -62,4 +62,4 @@ packet 0 cafa07fc001c111111111111cafe 61b8 01234567 89abcdef # changed VV # cafa07fc001c111111111111caef 61b8 01234567 89cacdef -expect 0 cafa07fc001c111111111111caef 61b8 01234567 89d1cdef $ \ No newline at end of file +expect 0 cafA07fc001c111111111111caef 61b8 01234567 89cacdef $ diff --git a/testdata/p4_16_samples_outputs/runtime-index-2-bmv2-first.p4 b/testdata/p4_16_samples_outputs/runtime-index-2-bmv2-first.p4 index 6a45ef4be99..f4dc030ecb9 100644 --- a/testdata/p4_16_samples_outputs/runtime-index-2-bmv2-first.p4 +++ b/testdata/p4_16_samples_outputs/runtime-index-2-bmv2-first.p4 @@ -46,6 +46,7 @@ control ingress(inout headers hdr, inout metadata_t meta, inout standard_metadat apply { hdr.vector[hdr.ml.idx1 - (hdr.ml.idx2 >> 8w1)].e = hdr.ethernet.etherType[15:8] + 8w7; hdr.ethernet.etherType[7:0] = hdr.vector[(hdr.ml.idx2 ^ 8w0x7) & 8w0x7].e; + hdr.vector[hdr.vector[hdr.ethernet.dstAddr[39:32] & 8w0x7].e & 8w0x7].e = hdr.ethernet.dstAddr[47:40]; } } diff --git a/testdata/p4_16_samples_outputs/runtime-index-2-bmv2-frontend.p4 b/testdata/p4_16_samples_outputs/runtime-index-2-bmv2-frontend.p4 index 6a45ef4be99..f4dc030ecb9 100644 --- a/testdata/p4_16_samples_outputs/runtime-index-2-bmv2-frontend.p4 +++ b/testdata/p4_16_samples_outputs/runtime-index-2-bmv2-frontend.p4 @@ -46,6 +46,7 @@ control ingress(inout headers hdr, inout metadata_t meta, inout standard_metadat apply { hdr.vector[hdr.ml.idx1 - (hdr.ml.idx2 >> 8w1)].e = hdr.ethernet.etherType[15:8] + 8w7; hdr.ethernet.etherType[7:0] = hdr.vector[(hdr.ml.idx2 ^ 8w0x7) & 8w0x7].e; + hdr.vector[hdr.vector[hdr.ethernet.dstAddr[39:32] & 8w0x7].e & 8w0x7].e = hdr.ethernet.dstAddr[47:40]; } } diff --git a/testdata/p4_16_samples_outputs/runtime-index-2-bmv2-midend.p4 b/testdata/p4_16_samples_outputs/runtime-index-2-bmv2-midend.p4 index 5f7852cec05..686f27b497e 100644 --- a/testdata/p4_16_samples_outputs/runtime-index-2-bmv2-midend.p4 +++ b/testdata/p4_16_samples_outputs/runtime-index-2-bmv2-midend.p4 @@ -46,6 +46,7 @@ control ingress(inout headers hdr, inout metadata_t meta, inout standard_metadat @hidden action runtimeindex2bmv2l69() { hdr.vector[hdr.ml.idx1 - (hdr.ml.idx2 >> 8w1)].e = hdr.ethernet.etherType[15:8] + 8w7; hdr.ethernet.etherType[7:0] = hdr.vector[(hdr.ml.idx2 ^ 8w0x7) & 8w0x7].e; + hdr.vector[hdr.vector[hdr.ethernet.dstAddr[39:32] & 8w0x7].e & 8w0x7].e = hdr.ethernet.dstAddr[47:40]; } @hidden table tbl_runtimeindex2bmv2l69 { actions = { diff --git a/testdata/p4_16_samples_outputs/runtime-index-2-bmv2.p4 b/testdata/p4_16_samples_outputs/runtime-index-2-bmv2.p4 index 2fd3c863794..9edec92be74 100644 --- a/testdata/p4_16_samples_outputs/runtime-index-2-bmv2.p4 +++ b/testdata/p4_16_samples_outputs/runtime-index-2-bmv2.p4 @@ -46,6 +46,7 @@ control ingress(inout headers hdr, inout metadata_t meta, inout standard_metadat apply { hdr.vector[hdr.ml.idx1 - (hdr.ml.idx2 >> 8w1)].e = hdr.ethernet.etherType[15:8] + 7; hdr.ethernet.etherType[7:0] = hdr.vector[(hdr.ml.idx2 ^ 8w0x7) & 8w0x7].e; + hdr.vector[hdr.vector[hdr.ethernet.dstAddr[39:32] & 0x7].e & 0x7].e = hdr.ethernet.dstAddr[47:40]; } } From d4f5e1f5253177b078c7cb6dc3977d77a908a856 Mon Sep 17 00:00:00 2001 From: Chris Dodd Date: Wed, 29 Jan 2020 15:39:35 -0800 Subject: [PATCH 069/106] Fix precedence of RSH rule (#2166) --- frontends/parsers/p4/p4parser.ypp | 2 +- testdata/p4_16_samples/shift_precendence.p4 | 5 +++-- testdata/p4_16_samples_outputs/shift_precendence-first.p4 | 5 +++-- testdata/p4_16_samples_outputs/shift_precendence-frontend.p4 | 5 +++-- testdata/p4_16_samples_outputs/shift_precendence-midend.p4 | 5 +++-- testdata/p4_16_samples_outputs/shift_precendence.p4 | 5 +++-- 6 files changed, 16 insertions(+), 11 deletions(-) diff --git a/frontends/parsers/p4/p4parser.ypp b/frontends/parsers/p4/p4parser.ypp index 4e63c3bf23e..105e81d9653 100644 --- a/frontends/parsers/p4/p4parser.ypp +++ b/frontends/parsers/p4/p4parser.ypp @@ -1339,7 +1339,7 @@ expression | expression "|+|" expression { $$ = new IR::AddSat(@1 + @3, $1, $3); } | expression "|-|" expression { $$ = new IR::SubSat(@1 + @3, $1, $3); } | expression "<<" expression { $$ = new IR::Shl(@1 + @3, $1, $3); } - | expression R_ANGLE_SHIFT ">" expression + | expression R_ANGLE_SHIFT ">" expression %prec R_ANGLE_SHIFT { $$ = new IR::Shr(@1 + @4, $1, $4); } | expression "<=" expression { $$ = new IR::Leq(@1 + @3, $1, $3); } | expression ">=" expression { $$ = new IR::Geq(@1 + @3, $1, $3); } diff --git a/testdata/p4_16_samples/shift_precendence.p4 b/testdata/p4_16_samples/shift_precendence.p4 index e76c6874145..0181582efc6 100644 --- a/testdata/p4_16_samples/shift_precendence.p4 +++ b/testdata/p4_16_samples/shift_precendence.p4 @@ -1,12 +1,13 @@ -control i(out bit<4> a) { +control i(out bit<4> a, out bit<16> x) { bit<4> tmp_0; apply { tmp_0 = 4w0; a = 4w1 & (4w2 + tmp_0) >> 4w2; + x = 0xffff >> 3 >> 1; } } -control c(out bit<4> a); +control c(out bit<4> a, out bit<16> x); package top(c _c); top(i()) main; diff --git a/testdata/p4_16_samples_outputs/shift_precendence-first.p4 b/testdata/p4_16_samples_outputs/shift_precendence-first.p4 index 1e9d704c9a2..12c71c80ee2 100644 --- a/testdata/p4_16_samples_outputs/shift_precendence-first.p4 +++ b/testdata/p4_16_samples_outputs/shift_precendence-first.p4 @@ -1,12 +1,13 @@ -control i(out bit<4> a) { +control i(out bit<4> a, out bit<16> x) { bit<4> tmp_0; apply { tmp_0 = 4w0; a = 4w1 & 4w2 + tmp_0 >> 4w2; + x = 16w0xfff; } } -control c(out bit<4> a); +control c(out bit<4> a, out bit<16> x); package top(c _c); top(i()) main; diff --git a/testdata/p4_16_samples_outputs/shift_precendence-frontend.p4 b/testdata/p4_16_samples_outputs/shift_precendence-frontend.p4 index cd12ef4fb29..36a43aaa891 100644 --- a/testdata/p4_16_samples_outputs/shift_precendence-frontend.p4 +++ b/testdata/p4_16_samples_outputs/shift_precendence-frontend.p4 @@ -1,12 +1,13 @@ -control i(out bit<4> a) { +control i(out bit<4> a, out bit<16> x) { bit<4> tmp; apply { tmp = 4w0; a = 4w1 & 4w2 + tmp >> 4w2; + x = 16w0xfff; } } -control c(out bit<4> a); +control c(out bit<4> a, out bit<16> x); package top(c _c); top(i()) main; diff --git a/testdata/p4_16_samples_outputs/shift_precendence-midend.p4 b/testdata/p4_16_samples_outputs/shift_precendence-midend.p4 index 28922d4593f..f162d17466e 100644 --- a/testdata/p4_16_samples_outputs/shift_precendence-midend.p4 +++ b/testdata/p4_16_samples_outputs/shift_precendence-midend.p4 @@ -1,6 +1,7 @@ -control i(out bit<4> a) { +control i(out bit<4> a, out bit<16> x) { @hidden action shift_precendence5() { a = 4w0; + x = 16w0xfff; } @hidden table tbl_shift_precendence5 { actions = { @@ -13,7 +14,7 @@ control i(out bit<4> a) { } } -control c(out bit<4> a); +control c(out bit<4> a, out bit<16> x); package top(c _c); top(i()) main; diff --git a/testdata/p4_16_samples_outputs/shift_precendence.p4 b/testdata/p4_16_samples_outputs/shift_precendence.p4 index 1e9d704c9a2..558edfb0ceb 100644 --- a/testdata/p4_16_samples_outputs/shift_precendence.p4 +++ b/testdata/p4_16_samples_outputs/shift_precendence.p4 @@ -1,12 +1,13 @@ -control i(out bit<4> a) { +control i(out bit<4> a, out bit<16> x) { bit<4> tmp_0; apply { tmp_0 = 4w0; a = 4w1 & 4w2 + tmp_0 >> 4w2; + x = 0xffff >> 3 >> 1; } } -control c(out bit<4> a); +control c(out bit<4> a, out bit<16> x); package top(c _c); top(i()) main; From d0a638c63ecf7c18899154d00b8860d278dc874d Mon Sep 17 00:00:00 2001 From: Chris Dodd Date: Wed, 29 Jan 2020 22:39:26 -0800 Subject: [PATCH 070/106] Allow for a Transform that combines identical nodes (#2167) --- ir/visitor.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/ir/visitor.cpp b/ir/visitor.cpp index 6223dee82cb..eef5b38b5c9 100644 --- a/ir/visitor.cpp +++ b/ir/visitor.cpp @@ -62,7 +62,7 @@ class Visitor::ChangeTracker { * If @final is a new node, that node is marked as finished as well, as if * `start(@final); finish(@final);` were invoked. * - * @return true if the node has changed or been removed. + * @return true if the node has changed or been removed or coalesced. * * @exception Util::CompilerBug This method fails if `start(@orig)` has not * previously been invoked. @@ -81,6 +81,11 @@ class Visitor::ChangeTracker { orig_visit_info->result = final; visited.emplace(final, visit_info_t{false, orig_visit_info->visitOnce, final}); return true; + } else if (visited.count(final)) { + // coalescing with some previously visited node, so we don't want to undo + // the coalesce + orig_visit_info->result = final; + return true; } else { // FIXME -- not safe if the visitor resurrects the node (which it shouldn't) // if (final && final->id == IR::Node::currentId - 1) From b0a1168becb02174bdfe1bbb16d8230cb9fe3d8c Mon Sep 17 00:00:00 2001 From: Radostin Stoyanov Date: Wed, 29 Jan 2020 17:43:13 +0000 Subject: [PATCH 071/106] tools-driver: Drop shebang line A script will be executed using the interpreter specified on the first (shebang) line, however, main.py file is not invoked on the command line so we can actually remove that line. Signed-off-by: Radostin Stoyanov --- tools/driver/p4c_src/main.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tools/driver/p4c_src/main.py b/tools/driver/p4c_src/main.py index 88208843896..13ae1bc9c40 100644 --- a/tools/driver/p4c_src/main.py +++ b/tools/driver/p4c_src/main.py @@ -12,7 +12,6 @@ # See the License for the specific language governing permissions and # limitations under the License. -#!/usr/bin/env python3 """ p4c - P4 Compiler Driver From f01184db7bae64c6fa9bb1f8cb5de80b5b9682f7 Mon Sep 17 00:00:00 2001 From: Chris Dodd Date: Thu, 30 Jan 2020 12:42:59 -0800 Subject: [PATCH 072/106] new SwitchAddDefault pass to add default: {} to switch (#2168) - only adds if it does not already have a default and not all cases can be shown to be handled. --- frontends/CMakeLists.txt | 2 + frontends/p4/frontend.cpp | 2 + frontends/p4/switchAddDefault.cpp | 54 ++++++++ frontends/p4/switchAddDefault.h | 36 ++++++ .../16-TwoReferences-first.p4 | 2 + .../16-TwoReferences-frontend.p4 | 2 + .../16-TwoReferences-midend.p4 | 2 + .../action_chain1-first.p4 | 2 + .../action_chain1-frontend.p4 | 2 + .../action_chain1-midend.p4 | 2 + .../basic_routing-first.p4 | 2 + .../basic_routing-frontend.p4 | 2 + .../basic_routing-midend.p4 | 2 + .../switch_20160512/switch-first.p4 | 32 +++++ .../switch_20160512/switch-frontend.p4 | 32 +++++ .../switch_20160512/switch-midend.p4 | 32 +++++ testdata/p4_14_samples_outputs/tp2c-first.p4 | 2 + .../p4_14_samples_outputs/tp2c-frontend.p4 | 2 + testdata/p4_14_samples_outputs/tp2c-midend.p4 | 2 + testdata/p4_16_samples/issue2153-bmv2.p4 | 96 +++++++++++++++ testdata/p4_16_samples/issue2153-bmv2.stf | 6 + .../basic_routing-bmv2-first.p4 | 2 + .../basic_routing-bmv2-frontend.p4 | 2 + .../basic_routing-bmv2-midend.p4 | 2 + testdata/p4_16_samples_outputs/cases-first.p4 | 2 + .../p4_16_samples_outputs/issue-2123-first.p4 | 2 + .../issue-2123-frontend.p4 | 2 + .../issue-2123-midend.p4 | 2 + .../issue2153-bmv2-first.p4 | 87 +++++++++++++ .../issue2153-bmv2-frontend.p4 | 87 +++++++++++++ .../issue2153-bmv2-midend.p4 | 115 ++++++++++++++++++ .../p4_16_samples_outputs/issue2153-bmv2.p4 | 85 +++++++++++++ .../issue2153-bmv2.p4-stderr | 0 .../issue2153-bmv2.p4.entries.txt | 0 .../issue2153-bmv2.p4.p4info.txt | 37 ++++++ .../ternary2-bmv2-first.p4 | 2 + .../ternary2-bmv2-frontend.p4 | 2 + .../ternary2-bmv2-midend.p4 | 2 + .../p4_16_samples_outputs/uninit-first.p4 | 2 + .../p4_16_samples_outputs/uninit-frontend.p4 | 2 + .../p4_16_samples_outputs/uninit-midend.p4 | 2 + 41 files changed, 753 insertions(+) create mode 100644 frontends/p4/switchAddDefault.cpp create mode 100644 frontends/p4/switchAddDefault.h create mode 100644 testdata/p4_16_samples/issue2153-bmv2.p4 create mode 100644 testdata/p4_16_samples/issue2153-bmv2.stf create mode 100644 testdata/p4_16_samples_outputs/issue2153-bmv2-first.p4 create mode 100644 testdata/p4_16_samples_outputs/issue2153-bmv2-frontend.p4 create mode 100644 testdata/p4_16_samples_outputs/issue2153-bmv2-midend.p4 create mode 100644 testdata/p4_16_samples_outputs/issue2153-bmv2.p4 create mode 100644 testdata/p4_16_samples_outputs/issue2153-bmv2.p4-stderr create mode 100644 testdata/p4_16_samples_outputs/issue2153-bmv2.p4.entries.txt create mode 100644 testdata/p4_16_samples_outputs/issue2153-bmv2.p4.p4info.txt diff --git a/frontends/CMakeLists.txt b/frontends/CMakeLists.txt index b0f9e87298e..e28b4a1e0d7 100644 --- a/frontends/CMakeLists.txt +++ b/frontends/CMakeLists.txt @@ -53,6 +53,7 @@ set (P4_FRONTEND_SRCS p4/specialize.cpp p4/strengthReduction.cpp p4/structInitializers.cpp + p4/switchAddDefault.cpp p4/symbol_table.cpp p4/tableApply.cpp p4/tableKeyNames.cpp @@ -116,6 +117,7 @@ set (P4_FRONTEND_HDRS p4/specialize.h p4/strengthReduction.h p4/structInitializers.h + p4/switchAddDefault.h p4/symbol_table.h p4/tableApply.h p4/tableKeyNames.h diff --git a/frontends/p4/frontend.cpp b/frontends/p4/frontend.cpp index 82dc170319b..c38e26a057f 100644 --- a/frontends/p4/frontend.cpp +++ b/frontends/p4/frontend.cpp @@ -55,6 +55,7 @@ limitations under the License. #include "specialize.h" #include "strengthReduction.h" #include "structInitializers.h" +#include "switchAddDefault.h" #include "tableKeyNames.h" #include "toP4/toP4.h" #include "typeChecking/typeChecker.h" @@ -155,6 +156,7 @@ const IR::P4Program *FrontEnd::run(const CompilerOptions &options, const IR::P4P new StrengthReduction(&refMap, &typeMap), new UselessCasts(&refMap, &typeMap), new SimplifyControlFlow(&refMap, &typeMap), + new SwitchAddDefault, new FrontEndDump(), // used for testing the program at this point new RemoveAllUnusedDeclarations(&refMap, true), new SimplifyParsers(&refMap), diff --git a/frontends/p4/switchAddDefault.cpp b/frontends/p4/switchAddDefault.cpp new file mode 100644 index 00000000000..763c59af074 --- /dev/null +++ b/frontends/p4/switchAddDefault.cpp @@ -0,0 +1,54 @@ +/* +Copyright 2020 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 "switchAddDefault.h" + +namespace P4 { + +void SwitchAddDefault::postorder(IR::SwitchStatement *sw) { + ordered_set case_tags; + for (auto sc : sw->cases) { + if (sc->label->is()) { + return; + } else if (auto pe = sc->label->to()) { + case_tags.insert(pe->path->name); + } + } + bool need_default = false; + if (auto actenum = sw->expression->type->to()) { + for (auto act : actenum->actionList->actionList) { + if (auto mce = act->expression->to()) { + if (auto pe = mce->method->to()) { + if (!case_tags.count(pe->path->name)) { + need_default = true; + } + } else { + need_default = true; + } + } else { + need_default = true; + } + if (need_default) break; + } + } + if (need_default) { + sw->cases.push_back( + new IR::SwitchCase(new IR::DefaultExpression(IR::Type_Dontcare::get()), + new IR::BlockStatement)); + } +} + +} // namespace P4 diff --git a/frontends/p4/switchAddDefault.h b/frontends/p4/switchAddDefault.h new file mode 100644 index 00000000000..cafc4e259b3 --- /dev/null +++ b/frontends/p4/switchAddDefault.h @@ -0,0 +1,36 @@ +/* +Copyright 2020 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. +*/ + +#ifndef FRONTENDS_P4_SWITCHADDDEFAULT_H_ +#define FRONTENDS_P4_SWITCHADDDEFAULT_H_ + +#include "ir/ir.h" + +namespace P4 { + +/* + * find switch statements that do not cover all possible cases in their case list (no + * default: case and at least one action tag with no case) and add a default: {} + * case that does nothing. + */ +class SwitchAddDefault : public Modifier { + public: + void postorder(IR::SwitchStatement *) override; +}; + +} // namespace P4 + +#endif /* FRONTENDS_P4_SWITCHADDDEFAULT_H_ */ diff --git a/testdata/p4_14_samples_outputs/16-TwoReferences-first.p4 b/testdata/p4_14_samples_outputs/16-TwoReferences-first.p4 index a2c32c841e9..7e69d5dc093 100644 --- a/testdata/p4_14_samples_outputs/16-TwoReferences-first.p4 +++ b/testdata/p4_14_samples_outputs/16-TwoReferences-first.p4 @@ -96,6 +96,8 @@ control ingress(inout headers hdr, inout metadata meta, inout standard_metadata_ do_e: { E.apply(); } + default: { + } } F.apply(); diff --git a/testdata/p4_14_samples_outputs/16-TwoReferences-frontend.p4 b/testdata/p4_14_samples_outputs/16-TwoReferences-frontend.p4 index fb1721ee839..00e2cfb26eb 100644 --- a/testdata/p4_14_samples_outputs/16-TwoReferences-frontend.p4 +++ b/testdata/p4_14_samples_outputs/16-TwoReferences-frontend.p4 @@ -116,6 +116,8 @@ control ingress(inout headers hdr, inout metadata meta, inout standard_metadata_ do_e: { E_0.apply(); } + default: { + } } F_0.apply(); diff --git a/testdata/p4_14_samples_outputs/16-TwoReferences-midend.p4 b/testdata/p4_14_samples_outputs/16-TwoReferences-midend.p4 index fb1721ee839..00e2cfb26eb 100644 --- a/testdata/p4_14_samples_outputs/16-TwoReferences-midend.p4 +++ b/testdata/p4_14_samples_outputs/16-TwoReferences-midend.p4 @@ -116,6 +116,8 @@ control ingress(inout headers hdr, inout metadata meta, inout standard_metadata_ do_e: { E_0.apply(); } + default: { + } } F_0.apply(); diff --git a/testdata/p4_14_samples_outputs/action_chain1-first.p4 b/testdata/p4_14_samples_outputs/action_chain1-first.p4 index f9b8ac426fb..aec35b1c8db 100644 --- a/testdata/p4_14_samples_outputs/action_chain1-first.p4 +++ b/testdata/p4_14_samples_outputs/action_chain1-first.p4 @@ -137,6 +137,8 @@ control ingress(inout headers hdr, inout metadata meta, inout standard_metadata_ act3: { tbl3.apply(); } + default: { + } } } diff --git a/testdata/p4_14_samples_outputs/action_chain1-frontend.p4 b/testdata/p4_14_samples_outputs/action_chain1-frontend.p4 index c1f4d11b671..5b4d118220b 100644 --- a/testdata/p4_14_samples_outputs/action_chain1-frontend.p4 +++ b/testdata/p4_14_samples_outputs/action_chain1-frontend.p4 @@ -155,6 +155,8 @@ control ingress(inout headers hdr, inout metadata meta, inout standard_metadata_ act3: { tbl3_0.apply(); } + default: { + } } } diff --git a/testdata/p4_14_samples_outputs/action_chain1-midend.p4 b/testdata/p4_14_samples_outputs/action_chain1-midend.p4 index bb57ccca243..1b525e1fbbb 100644 --- a/testdata/p4_14_samples_outputs/action_chain1-midend.p4 +++ b/testdata/p4_14_samples_outputs/action_chain1-midend.p4 @@ -155,6 +155,8 @@ control ingress(inout headers hdr, inout metadata meta, inout standard_metadata_ act3: { tbl3_0.apply(); } + default: { + } } } diff --git a/testdata/p4_14_samples_outputs/basic_routing-first.p4 b/testdata/p4_14_samples_outputs/basic_routing-first.p4 index a2ffa6d4eae..37286500288 100644 --- a/testdata/p4_14_samples_outputs/basic_routing-first.p4 +++ b/testdata/p4_14_samples_outputs/basic_routing-first.p4 @@ -165,6 +165,8 @@ control ingress(inout headers hdr, inout metadata meta, inout standard_metadata_ on_miss: { ipv4_fib_lpm.apply(); } + default: { + } } nexthop.apply(); diff --git a/testdata/p4_14_samples_outputs/basic_routing-frontend.p4 b/testdata/p4_14_samples_outputs/basic_routing-frontend.p4 index 34e38ccd864..f97ac44cc32 100644 --- a/testdata/p4_14_samples_outputs/basic_routing-frontend.p4 +++ b/testdata/p4_14_samples_outputs/basic_routing-frontend.p4 @@ -185,6 +185,8 @@ control ingress(inout headers hdr, inout metadata meta, inout standard_metadata_ on_miss_2: { ipv4_fib_lpm_0.apply(); } + default: { + } } nexthop_0.apply(); diff --git a/testdata/p4_14_samples_outputs/basic_routing-midend.p4 b/testdata/p4_14_samples_outputs/basic_routing-midend.p4 index 739994ac263..76522d62fa1 100644 --- a/testdata/p4_14_samples_outputs/basic_routing-midend.p4 +++ b/testdata/p4_14_samples_outputs/basic_routing-midend.p4 @@ -186,6 +186,8 @@ control ingress(inout headers hdr, inout metadata meta, inout standard_metadata_ on_miss_2: { ipv4_fib_lpm_0.apply(); } + default: { + } } nexthop_0.apply(); diff --git a/testdata/p4_14_samples_outputs/switch_20160512/switch-first.p4 b/testdata/p4_14_samples_outputs/switch_20160512/switch-first.p4 index f2c9d7b6f9b..5bc009452d0 100644 --- a/testdata/p4_14_samples_outputs/switch_20160512/switch-first.p4 +++ b/testdata/p4_14_samples_outputs/switch_20160512/switch-first.p4 @@ -2266,6 +2266,8 @@ control process_int_insertion(inout headers hdr, inout metadata meta, inout stan } int_meta_header_update.apply(); } + default: { + } } } @@ -3085,6 +3087,8 @@ control egress(inout headers hdr, inout metadata meta, inout standard_metadata_t process_int_insertion_0.apply(hdr, meta, standard_metadata); process_egress_bd_stats_0.apply(hdr, meta, standard_metadata); } + default: { + } } process_tunnel_encap_0.apply(hdr, meta, standard_metadata); @@ -3466,6 +3470,8 @@ control process_ip_sourceguard(inout headers hdr, inout metadata meta, inout sta on_miss: { ipsg_permit_special.apply(); } + default: { + } } } @@ -3781,6 +3787,8 @@ control process_outer_ipv4_multicast(inout headers hdr, inout metadata meta, ino on_miss: { outer_ipv4_multicast_star_g.apply(); } + default: { + } } } @@ -3859,6 +3867,8 @@ control process_outer_ipv6_multicast(inout headers hdr, inout metadata meta, ino on_miss: { outer_ipv6_multicast_star_g.apply(); } + default: { + } } } @@ -3932,6 +3942,8 @@ control process_ipv4_vtep(inout headers hdr, inout metadata meta, inout standard src_vtep_hit: { ipv4_dest_vtep.apply(); } + default: { + } } } @@ -3986,6 +3998,8 @@ control process_ipv6_vtep(inout headers hdr, inout metadata meta, inout standard src_vtep_hit: { ipv6_dest_vtep.apply(); } + default: { + } } } @@ -4262,6 +4276,8 @@ control process_tunnel(inout headers hdr, inout metadata meta, inout standard_me tunnel_lookup_miss: { tunnel_lookup_miss_0.apply(); } + default: { + } } } else { @@ -4821,6 +4837,8 @@ control process_ipv4_multicast(inout headers hdr, inout metadata meta, inout sta on_miss: { ipv4_multicast_bridge_star_g.apply(); } + default: { + } } } @@ -4829,6 +4847,8 @@ control process_ipv4_multicast(inout headers hdr, inout metadata meta, inout sta on_miss_0: { ipv4_multicast_route_star_g.apply(); } + default: { + } } } @@ -4962,6 +4982,8 @@ control process_ipv6_multicast(inout headers hdr, inout metadata meta, inout sta on_miss: { ipv6_multicast_bridge_star_g.apply(); } + default: { + } } } @@ -4970,6 +4992,8 @@ control process_ipv6_multicast(inout headers hdr, inout metadata meta, inout sta on_miss_1: { ipv6_multicast_route_star_g.apply(); } + default: { + } } } @@ -5093,6 +5117,8 @@ control process_ipv4_urpf(inout headers hdr, inout metadata meta, inout standard on_miss: { ipv4_urpf_lpm.apply(); } + default: { + } } } @@ -5145,6 +5171,8 @@ control process_ipv4_fib(inout headers hdr, inout metadata meta, inout standard_ on_miss: { ipv4_fib_lpm.apply(); } + default: { + } } } @@ -5248,6 +5276,8 @@ control process_ipv6_urpf(inout headers hdr, inout metadata meta, inout standard on_miss: { ipv6_urpf_lpm.apply(); } + default: { + } } } @@ -5300,6 +5330,8 @@ control process_ipv6_fib(inout headers hdr, inout metadata meta, inout standard_ on_miss: { ipv6_fib_lpm.apply(); } + default: { + } } } diff --git a/testdata/p4_14_samples_outputs/switch_20160512/switch-frontend.p4 b/testdata/p4_14_samples_outputs/switch_20160512/switch-frontend.p4 index db25c309211..1cbe08d3dee 100644 --- a/testdata/p4_14_samples_outputs/switch_20160512/switch-frontend.p4 +++ b/testdata/p4_14_samples_outputs/switch_20160512/switch-frontend.p4 @@ -3093,10 +3093,14 @@ control egress(inout headers hdr, inout metadata meta, inout standard_metadata_t } _int_meta_header_update.apply(); } + default: { + } } _egress_bd_stats_0.apply(); } + default: { + } } if (meta.fabric_metadata.fabric_header_present == 1w0 && meta.tunnel_metadata.egress_tunnel_type != 5w0) { @@ -5682,6 +5686,8 @@ control ingress(inout headers hdr, inout metadata meta, inout standard_metadata_ _on_miss: { _ipsg_permit_special.apply(); } + default: { + } } } @@ -5710,6 +5716,8 @@ control ingress(inout headers hdr, inout metadata meta, inout standard_metadata_ _on_miss_1: { _outer_ipv4_multicast_star_g_0.apply(); } + default: { + } } } else if (hdr.ipv6.isValid()) { @@ -5717,6 +5725,8 @@ control ingress(inout headers hdr, inout metadata meta, inout standard_metadata_ _on_miss_2: { _outer_ipv6_multicast_star_g_0.apply(); } + default: { + } } } @@ -5727,6 +5737,8 @@ control ingress(inout headers hdr, inout metadata meta, inout standard_metadata_ _src_vtep_hit: { _ipv4_dest_vtep_0.apply(); } + default: { + } } } else if (hdr.ipv6.isValid()) { @@ -5734,6 +5746,8 @@ control ingress(inout headers hdr, inout metadata meta, inout standard_metadata_ _src_vtep_hit_0: { _ipv6_dest_vtep_0.apply(); } + default: { + } } } else if (hdr.mpls[0].isValid()) { @@ -5748,6 +5762,8 @@ control ingress(inout headers hdr, inout metadata meta, inout standard_metadata_ _tunnel_lookup_miss_0: { _tunnel_lookup_miss_1.apply(); } + default: { + } } } else { @@ -5789,6 +5805,8 @@ control ingress(inout headers hdr, inout metadata meta, inout standard_metadata_ _on_miss_5: { _ipv4_multicast_bridge_star_g_0.apply(); } + default: { + } } } @@ -5797,6 +5815,8 @@ control ingress(inout headers hdr, inout metadata meta, inout standard_metadata_ _on_miss_6: { _ipv4_multicast_route_star_g_0.apply(); } + default: { + } } } @@ -5806,6 +5826,8 @@ control ingress(inout headers hdr, inout metadata meta, inout standard_metadata_ _on_miss_7: { _ipv6_multicast_bridge_star_g_0.apply(); } + default: { + } } } @@ -5814,6 +5836,8 @@ control ingress(inout headers hdr, inout metadata meta, inout standard_metadata_ _on_miss_8: { _ipv6_multicast_route_star_g_0.apply(); } + default: { + } } } @@ -5828,6 +5852,8 @@ control ingress(inout headers hdr, inout metadata meta, inout standard_metadata_ _on_miss_23: { _ipv4_urpf_lpm.apply(); } + default: { + } } } @@ -5835,6 +5861,8 @@ control ingress(inout headers hdr, inout metadata meta, inout standard_metadata_ _on_miss_24: { _ipv4_fib_lpm.apply(); } + default: { + } } } else if (meta.l3_metadata.lkp_ip_type == 2w2 && meta.ipv6_metadata.ipv6_unicast_enabled == 1w1) { @@ -5844,6 +5872,8 @@ control ingress(inout headers hdr, inout metadata meta, inout standard_metadata_ _on_miss_26: { _ipv6_urpf_lpm.apply(); } + default: { + } } } @@ -5851,6 +5881,8 @@ control ingress(inout headers hdr, inout metadata meta, inout standard_metadata_ _on_miss_29: { _ipv6_fib_lpm.apply(); } + default: { + } } } diff --git a/testdata/p4_14_samples_outputs/switch_20160512/switch-midend.p4 b/testdata/p4_14_samples_outputs/switch_20160512/switch-midend.p4 index d725f4f6d64..95a0af8684c 100644 --- a/testdata/p4_14_samples_outputs/switch_20160512/switch-midend.p4 +++ b/testdata/p4_14_samples_outputs/switch_20160512/switch-midend.p4 @@ -3210,10 +3210,14 @@ control egress(inout headers hdr, inout metadata meta, inout standard_metadata_t } _int_meta_header_update.apply(); } + default: { + } } _egress_bd_stats_0.apply(); } + default: { + } } if (meta._fabric_metadata_fabric_header_present27 == 1w0 && meta._tunnel_metadata_egress_tunnel_type143 != 5w0) { @@ -5858,6 +5862,8 @@ control ingress(inout headers hdr, inout metadata meta, inout standard_metadata_ _on_miss: { _ipsg_permit_special.apply(); } + default: { + } } } @@ -5886,6 +5892,8 @@ control ingress(inout headers hdr, inout metadata meta, inout standard_metadata_ _on_miss_1: { _outer_ipv4_multicast_star_g_0.apply(); } + default: { + } } } else if (hdr.ipv6.isValid()) { @@ -5893,6 +5901,8 @@ control ingress(inout headers hdr, inout metadata meta, inout standard_metadata_ _on_miss_2: { _outer_ipv6_multicast_star_g_0.apply(); } + default: { + } } } @@ -5903,6 +5913,8 @@ control ingress(inout headers hdr, inout metadata meta, inout standard_metadata_ _src_vtep_hit: { _ipv4_dest_vtep_0.apply(); } + default: { + } } } else if (hdr.ipv6.isValid()) { @@ -5910,6 +5922,8 @@ control ingress(inout headers hdr, inout metadata meta, inout standard_metadata_ _src_vtep_hit_0: { _ipv6_dest_vtep_0.apply(); } + default: { + } } } else if (hdr.mpls[0].isValid()) { @@ -5924,6 +5938,8 @@ control ingress(inout headers hdr, inout metadata meta, inout standard_metadata_ _tunnel_lookup_miss_0: { _tunnel_lookup_miss_1.apply(); } + default: { + } } } else { @@ -5965,6 +5981,8 @@ control ingress(inout headers hdr, inout metadata meta, inout standard_metadata_ _on_miss_5: { _ipv4_multicast_bridge_star_g_0.apply(); } + default: { + } } } @@ -5973,6 +5991,8 @@ control ingress(inout headers hdr, inout metadata meta, inout standard_metadata_ _on_miss_6: { _ipv4_multicast_route_star_g_0.apply(); } + default: { + } } } @@ -5982,6 +6002,8 @@ control ingress(inout headers hdr, inout metadata meta, inout standard_metadata_ _on_miss_7: { _ipv6_multicast_bridge_star_g_0.apply(); } + default: { + } } } @@ -5990,6 +6012,8 @@ control ingress(inout headers hdr, inout metadata meta, inout standard_metadata_ _on_miss_8: { _ipv6_multicast_route_star_g_0.apply(); } + default: { + } } } @@ -6004,6 +6028,8 @@ control ingress(inout headers hdr, inout metadata meta, inout standard_metadata_ _on_miss_23: { _ipv4_urpf_lpm.apply(); } + default: { + } } } @@ -6011,6 +6037,8 @@ control ingress(inout headers hdr, inout metadata meta, inout standard_metadata_ _on_miss_24: { _ipv4_fib_lpm.apply(); } + default: { + } } } else if (meta._l3_metadata_lkp_ip_type80 == 2w2 && meta._ipv6_metadata_ipv6_unicast_enabled62 == 1w1) { @@ -6020,6 +6048,8 @@ control ingress(inout headers hdr, inout metadata meta, inout standard_metadata_ _on_miss_26: { _ipv6_urpf_lpm.apply(); } + default: { + } } } @@ -6027,6 +6057,8 @@ control ingress(inout headers hdr, inout metadata meta, inout standard_metadata_ _on_miss_29: { _ipv6_fib_lpm.apply(); } + default: { + } } } diff --git a/testdata/p4_14_samples_outputs/tp2c-first.p4 b/testdata/p4_14_samples_outputs/tp2c-first.p4 index 7b474cd0a6b..d626cc4c7f3 100644 --- a/testdata/p4_14_samples_outputs/tp2c-first.p4 +++ b/testdata/p4_14_samples_outputs/tp2c-first.p4 @@ -121,6 +121,8 @@ control ingress(inout headers hdr, inout metadata meta, inout standard_metadata_ on_hit: { A4.apply(); } + default: { + } } } diff --git a/testdata/p4_14_samples_outputs/tp2c-frontend.p4 b/testdata/p4_14_samples_outputs/tp2c-frontend.p4 index d719300a65e..a6480bc904e 100644 --- a/testdata/p4_14_samples_outputs/tp2c-frontend.p4 +++ b/testdata/p4_14_samples_outputs/tp2c-frontend.p4 @@ -143,6 +143,8 @@ control ingress(inout headers hdr, inout metadata meta, inout standard_metadata_ on_hit: { A4_0.apply(); } + default: { + } } } diff --git a/testdata/p4_14_samples_outputs/tp2c-midend.p4 b/testdata/p4_14_samples_outputs/tp2c-midend.p4 index d719300a65e..a6480bc904e 100644 --- a/testdata/p4_14_samples_outputs/tp2c-midend.p4 +++ b/testdata/p4_14_samples_outputs/tp2c-midend.p4 @@ -143,6 +143,8 @@ control ingress(inout headers hdr, inout metadata meta, inout standard_metadata_ on_hit: { A4_0.apply(); } + default: { + } } } diff --git a/testdata/p4_16_samples/issue2153-bmv2.p4 b/testdata/p4_16_samples/issue2153-bmv2.p4 new file mode 100644 index 00000000000..46e1cf34f07 --- /dev/null +++ b/testdata/p4_16_samples/issue2153-bmv2.p4 @@ -0,0 +1,96 @@ +/* +Copyright 2017 VMware, 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 +#include + +header ethernet_t { + bit<48> dstAddr; + bit<48> srcAddr; + bit<16> etherType; +} + +header H { + bit<8> a; + bit<8> b; +} + +struct Parsed_packet { + ethernet_t eth; + H h; +} + +struct Metadata { +} + +control deparser(packet_out packet, in Parsed_packet hdr) { + apply { + packet.emit(hdr); + } +} + +parser p(packet_in pkt, out Parsed_packet hdr, inout Metadata meta, inout standard_metadata_t stdmeta) { + state start { + pkt.extract(hdr.eth); + transition parse_h; + } + state parse_h { + pkt.extract(hdr.h); + transition accept; + } +} + +control ingress(inout Parsed_packet hdr, inout Metadata meta, inout standard_metadata_t stdmeta) { + action do_something() { + stdmeta.egress_spec = 9w1; + } + table simple_table { + key = { + hdr.h.b: exact; + } + actions = { + NoAction(); + do_something(); + } + default_action = NoAction; + } + apply { + bit<8> tmp_condition = 8w0; + stdmeta.egress_spec = 9w0; + switch (simple_table.apply().action_run) { + do_something: { + tmp_condition = 8w1; + } + } + + if (tmp_condition > 0) { + hdr.h.a = 8w0; + } + } +} + +control egress(inout Parsed_packet hdr, inout Metadata meta, inout standard_metadata_t stdmeta) { + apply {} +} + +control vrfy(inout Parsed_packet hdr, inout Metadata meta) { + apply {} +} + +control update(inout Parsed_packet hdr, inout Metadata meta) { + apply {} +} + +V1Switch(p(), vrfy(), ingress(), egress(), update(), deparser()) main; diff --git a/testdata/p4_16_samples/issue2153-bmv2.stf b/testdata/p4_16_samples/issue2153-bmv2.stf new file mode 100644 index 00000000000..eb9b7cb8bbe --- /dev/null +++ b/testdata/p4_16_samples/issue2153-bmv2.stf @@ -0,0 +1,6 @@ +add simple_table hdr.h.b:0x55 do_something() + +packet 0 11 11 11 11 11 11 22 22 22 22 22 22 33 33 FF EE +expect 0 11 11 11 11 11 11 22 22 22 22 22 22 33 33 FF EE +packet 0 11 11 11 11 11 11 22 22 22 22 22 22 33 33 FF 55 +expect 1 11 11 11 11 11 11 22 22 22 22 22 22 33 33 00 55 diff --git a/testdata/p4_16_samples_outputs/basic_routing-bmv2-first.p4 b/testdata/p4_16_samples_outputs/basic_routing-bmv2-first.p4 index 801fe77ab6f..6d0643d0f8c 100644 --- a/testdata/p4_16_samples_outputs/basic_routing-bmv2-first.p4 +++ b/testdata/p4_16_samples_outputs/basic_routing-bmv2-first.p4 @@ -162,6 +162,8 @@ control ingress(inout headers hdr, inout metadata meta, inout standard_metadata_ on_miss: { ipv4_fib_lpm.apply(); } + default: { + } } nexthop.apply(); diff --git a/testdata/p4_16_samples_outputs/basic_routing-bmv2-frontend.p4 b/testdata/p4_16_samples_outputs/basic_routing-bmv2-frontend.p4 index 688e8aebbe5..dff88779cf5 100644 --- a/testdata/p4_16_samples_outputs/basic_routing-bmv2-frontend.p4 +++ b/testdata/p4_16_samples_outputs/basic_routing-bmv2-frontend.p4 @@ -179,6 +179,8 @@ control ingress(inout headers hdr, inout metadata meta, inout standard_metadata_ on_miss_2: { ipv4_fib_lpm_0.apply(); } + default: { + } } nexthop_0.apply(); diff --git a/testdata/p4_16_samples_outputs/basic_routing-bmv2-midend.p4 b/testdata/p4_16_samples_outputs/basic_routing-bmv2-midend.p4 index 71600f7c23c..8a1177aeb8a 100644 --- a/testdata/p4_16_samples_outputs/basic_routing-bmv2-midend.p4 +++ b/testdata/p4_16_samples_outputs/basic_routing-bmv2-midend.p4 @@ -181,6 +181,8 @@ control ingress(inout headers hdr, inout metadata meta, inout standard_metadata_ on_miss_2: { ipv4_fib_lpm_0.apply(); } + default: { + } } nexthop_0.apply(); diff --git a/testdata/p4_16_samples_outputs/cases-first.p4 b/testdata/p4_16_samples_outputs/cases-first.p4 index 46dc262c4c8..d8eb0dc58dd 100644 --- a/testdata/p4_16_samples_outputs/cases-first.p4 +++ b/testdata/p4_16_samples_outputs/cases-first.p4 @@ -19,6 +19,8 @@ control ctrl() { b: { return; } + default: { + } } } diff --git a/testdata/p4_16_samples_outputs/issue-2123-first.p4 b/testdata/p4_16_samples_outputs/issue-2123-first.p4 index ca305ee5195..323428d2ccd 100644 --- a/testdata/p4_16_samples_outputs/issue-2123-first.p4 +++ b/testdata/p4_16_samples_outputs/issue-2123-first.p4 @@ -180,6 +180,8 @@ control ingress(inout headers hdr, inout metadata meta, inout standard_metadata_ on_miss: { ipv4_fib_lpm.apply(); } + default: { + } } nexthop.apply(); diff --git a/testdata/p4_16_samples_outputs/issue-2123-frontend.p4 b/testdata/p4_16_samples_outputs/issue-2123-frontend.p4 index 3c4f8d23349..6c60969f097 100644 --- a/testdata/p4_16_samples_outputs/issue-2123-frontend.p4 +++ b/testdata/p4_16_samples_outputs/issue-2123-frontend.p4 @@ -194,6 +194,8 @@ control ingress(inout headers hdr, inout metadata meta, inout standard_metadata_ on_miss_2: { ipv4_fib_lpm_0.apply(); } + default: { + } } nexthop_0.apply(); diff --git a/testdata/p4_16_samples_outputs/issue-2123-midend.p4 b/testdata/p4_16_samples_outputs/issue-2123-midend.p4 index 48e07f9207c..cb4833fe8cf 100644 --- a/testdata/p4_16_samples_outputs/issue-2123-midend.p4 +++ b/testdata/p4_16_samples_outputs/issue-2123-midend.p4 @@ -213,6 +213,8 @@ control ingress(inout headers hdr, inout metadata meta, inout standard_metadata_ on_miss_2: { ipv4_fib_lpm_0.apply(); } + default: { + } } nexthop_0.apply(); diff --git a/testdata/p4_16_samples_outputs/issue2153-bmv2-first.p4 b/testdata/p4_16_samples_outputs/issue2153-bmv2-first.p4 new file mode 100644 index 00000000000..c2cb10b96c3 --- /dev/null +++ b/testdata/p4_16_samples_outputs/issue2153-bmv2-first.p4 @@ -0,0 +1,87 @@ +#include +#include + +header ethernet_t { + bit<48> dstAddr; + bit<48> srcAddr; + bit<16> etherType; +} + +header H { + bit<8> a; + bit<8> b; +} + +struct Parsed_packet { + ethernet_t eth; + H h; +} + +struct Metadata { +} + +control deparser(packet_out packet, in Parsed_packet hdr) { + apply { + packet.emit(hdr); + } +} + +parser p(packet_in pkt, out Parsed_packet hdr, inout Metadata meta, inout standard_metadata_t stdmeta) { + state start { + pkt.extract(hdr.eth); + transition parse_h; + } + state parse_h { + pkt.extract(hdr.h); + transition accept; + } +} + +control ingress(inout Parsed_packet hdr, inout Metadata meta, inout standard_metadata_t stdmeta) { + action do_something() { + stdmeta.egress_spec = 9w1; + } + table simple_table { + key = { + hdr.h.b: exact @name("hdr.h.b") ; + } + actions = { + NoAction(); + do_something(); + } + default_action = NoAction(); + } + apply { + bit<8> tmp_condition = 8w0; + stdmeta.egress_spec = 9w0; + switch (simple_table.apply().action_run) { + do_something: { + tmp_condition = 8w1; + } + default: { + } + } + + if (tmp_condition > 8w0) { + hdr.h.a = 8w0; + } + } +} + +control egress(inout Parsed_packet hdr, inout Metadata meta, inout standard_metadata_t stdmeta) { + apply { + } +} + +control vrfy(inout Parsed_packet hdr, inout Metadata meta) { + apply { + } +} + +control update(inout Parsed_packet hdr, inout Metadata meta) { + apply { + } +} + +V1Switch(p(), vrfy(), ingress(), egress(), update(), deparser()) main; + diff --git a/testdata/p4_16_samples_outputs/issue2153-bmv2-frontend.p4 b/testdata/p4_16_samples_outputs/issue2153-bmv2-frontend.p4 new file mode 100644 index 00000000000..372eec1c075 --- /dev/null +++ b/testdata/p4_16_samples_outputs/issue2153-bmv2-frontend.p4 @@ -0,0 +1,87 @@ +#include +#include + +header ethernet_t { + bit<48> dstAddr; + bit<48> srcAddr; + bit<16> etherType; +} + +header H { + bit<8> a; + bit<8> b; +} + +struct Parsed_packet { + ethernet_t eth; + H h; +} + +struct Metadata { +} + +control deparser(packet_out packet, in Parsed_packet hdr) { + apply { + packet.emit(hdr); + } +} + +parser p(packet_in pkt, out Parsed_packet hdr, inout Metadata meta, inout standard_metadata_t stdmeta) { + state start { + pkt.extract(hdr.eth); + pkt.extract(hdr.h); + transition accept; + } +} + +control ingress(inout Parsed_packet hdr, inout Metadata meta, inout standard_metadata_t stdmeta) { + @name(".NoAction") action NoAction_0() { + } + bit<8> tmp_condition_0; + @name("ingress.do_something") action do_something() { + stdmeta.egress_spec = 9w1; + } + @name("ingress.simple_table") table simple_table_0 { + key = { + hdr.h.b: exact @name("hdr.h.b") ; + } + actions = { + NoAction_0(); + do_something(); + } + default_action = NoAction_0(); + } + apply { + tmp_condition_0 = 8w0; + stdmeta.egress_spec = 9w0; + switch (simple_table_0.apply().action_run) { + do_something: { + tmp_condition_0 = 8w1; + } + default: { + } + } + + if (tmp_condition_0 > 8w0) { + hdr.h.a = 8w0; + } + } +} + +control egress(inout Parsed_packet hdr, inout Metadata meta, inout standard_metadata_t stdmeta) { + apply { + } +} + +control vrfy(inout Parsed_packet hdr, inout Metadata meta) { + apply { + } +} + +control update(inout Parsed_packet hdr, inout Metadata meta) { + apply { + } +} + +V1Switch(p(), vrfy(), ingress(), egress(), update(), deparser()) main; + diff --git a/testdata/p4_16_samples_outputs/issue2153-bmv2-midend.p4 b/testdata/p4_16_samples_outputs/issue2153-bmv2-midend.p4 new file mode 100644 index 00000000000..91ed8b2d465 --- /dev/null +++ b/testdata/p4_16_samples_outputs/issue2153-bmv2-midend.p4 @@ -0,0 +1,115 @@ +#include +#include + +header ethernet_t { + bit<48> dstAddr; + bit<48> srcAddr; + bit<16> etherType; +} + +header H { + bit<8> a; + bit<8> b; +} + +struct Parsed_packet { + ethernet_t eth; + H h; +} + +struct Metadata { +} + +control deparser(packet_out packet, in Parsed_packet hdr) { + apply { + packet.emit(hdr.eth); + packet.emit(hdr.h); + } +} + +parser p(packet_in pkt, out Parsed_packet hdr, inout Metadata meta, inout standard_metadata_t stdmeta) { + state start { + pkt.extract(hdr.eth); + pkt.extract(hdr.h); + transition accept; + } +} + +control ingress(inout Parsed_packet hdr, inout Metadata meta, inout standard_metadata_t stdmeta) { + bit<8> tmp_condition_0; + @name(".NoAction") action NoAction_0() { + } + @name("ingress.do_something") action do_something() { + stdmeta.egress_spec = 9w1; + } + @name("ingress.simple_table") table simple_table_0 { + key = { + hdr.h.b: exact @name("hdr.h.b") ; + } + actions = { + NoAction_0(); + do_something(); + } + default_action = NoAction_0(); + } + @hidden action issue2153bmv2l74() { + tmp_condition_0 = 8w1; + } + @hidden action issue2153bmv2l70() { + tmp_condition_0 = 8w0; + stdmeta.egress_spec = 9w0; + } + @hidden action issue2153bmv2l79() { + hdr.h.a = 8w0; + } + @hidden table tbl_issue2153bmv2l70 { + actions = { + issue2153bmv2l70(); + } + const default_action = issue2153bmv2l70(); + } + @hidden table tbl_issue2153bmv2l74 { + actions = { + issue2153bmv2l74(); + } + const default_action = issue2153bmv2l74(); + } + @hidden table tbl_issue2153bmv2l79 { + actions = { + issue2153bmv2l79(); + } + const default_action = issue2153bmv2l79(); + } + apply { + tbl_issue2153bmv2l70.apply(); + switch (simple_table_0.apply().action_run) { + do_something: { + tbl_issue2153bmv2l74.apply(); + } + default: { + } + } + + if (tmp_condition_0 > 8w0) { + tbl_issue2153bmv2l79.apply(); + } + } +} + +control egress(inout Parsed_packet hdr, inout Metadata meta, inout standard_metadata_t stdmeta) { + apply { + } +} + +control vrfy(inout Parsed_packet hdr, inout Metadata meta) { + apply { + } +} + +control update(inout Parsed_packet hdr, inout Metadata meta) { + apply { + } +} + +V1Switch(p(), vrfy(), ingress(), egress(), update(), deparser()) main; + diff --git a/testdata/p4_16_samples_outputs/issue2153-bmv2.p4 b/testdata/p4_16_samples_outputs/issue2153-bmv2.p4 new file mode 100644 index 00000000000..a4f2a3656ad --- /dev/null +++ b/testdata/p4_16_samples_outputs/issue2153-bmv2.p4 @@ -0,0 +1,85 @@ +#include +#include + +header ethernet_t { + bit<48> dstAddr; + bit<48> srcAddr; + bit<16> etherType; +} + +header H { + bit<8> a; + bit<8> b; +} + +struct Parsed_packet { + ethernet_t eth; + H h; +} + +struct Metadata { +} + +control deparser(packet_out packet, in Parsed_packet hdr) { + apply { + packet.emit(hdr); + } +} + +parser p(packet_in pkt, out Parsed_packet hdr, inout Metadata meta, inout standard_metadata_t stdmeta) { + state start { + pkt.extract(hdr.eth); + transition parse_h; + } + state parse_h { + pkt.extract(hdr.h); + transition accept; + } +} + +control ingress(inout Parsed_packet hdr, inout Metadata meta, inout standard_metadata_t stdmeta) { + action do_something() { + stdmeta.egress_spec = 9w1; + } + table simple_table { + key = { + hdr.h.b: exact; + } + actions = { + NoAction(); + do_something(); + } + default_action = NoAction; + } + apply { + bit<8> tmp_condition = 8w0; + stdmeta.egress_spec = 9w0; + switch (simple_table.apply().action_run) { + do_something: { + tmp_condition = 8w1; + } + } + + if (tmp_condition > 0) { + hdr.h.a = 8w0; + } + } +} + +control egress(inout Parsed_packet hdr, inout Metadata meta, inout standard_metadata_t stdmeta) { + apply { + } +} + +control vrfy(inout Parsed_packet hdr, inout Metadata meta) { + apply { + } +} + +control update(inout Parsed_packet hdr, inout Metadata meta) { + apply { + } +} + +V1Switch(p(), vrfy(), ingress(), egress(), update(), deparser()) main; + diff --git a/testdata/p4_16_samples_outputs/issue2153-bmv2.p4-stderr b/testdata/p4_16_samples_outputs/issue2153-bmv2.p4-stderr new file mode 100644 index 00000000000..e69de29bb2d diff --git a/testdata/p4_16_samples_outputs/issue2153-bmv2.p4.entries.txt b/testdata/p4_16_samples_outputs/issue2153-bmv2.p4.entries.txt new file mode 100644 index 00000000000..e69de29bb2d diff --git a/testdata/p4_16_samples_outputs/issue2153-bmv2.p4.p4info.txt b/testdata/p4_16_samples_outputs/issue2153-bmv2.p4.p4info.txt new file mode 100644 index 00000000000..7357a49477b --- /dev/null +++ b/testdata/p4_16_samples_outputs/issue2153-bmv2.p4.p4info.txt @@ -0,0 +1,37 @@ +pkg_info { + arch: "v1model" +} +tables { + preamble { + id: 33563505 + name: "ingress.simple_table" + alias: "simple_table" + } + match_fields { + id: 1 + name: "hdr.h.b" + bitwidth: 8 + match_type: EXACT + } + action_refs { + id: 16800567 + } + action_refs { + id: 16830231 + } + size: 1024 +} +actions { + preamble { + id: 16800567 + name: "NoAction" + alias: "NoAction" + } +} +actions { + preamble { + id: 16830231 + name: "ingress.do_something" + alias: "do_something" + } +} diff --git a/testdata/p4_16_samples_outputs/ternary2-bmv2-first.p4 b/testdata/p4_16_samples_outputs/ternary2-bmv2-first.p4 index aebe8307c13..e24911fcb95 100644 --- a/testdata/p4_16_samples_outputs/ternary2-bmv2-first.p4 +++ b/testdata/p4_16_samples_outputs/ternary2-bmv2-first.p4 @@ -131,6 +131,8 @@ control ingress(inout packet_t hdrs, inout Meta m, inout standard_metadata_t met act3: { tbl3.apply(); } + default: { + } } } diff --git a/testdata/p4_16_samples_outputs/ternary2-bmv2-frontend.p4 b/testdata/p4_16_samples_outputs/ternary2-bmv2-frontend.p4 index 1e3e5a526ee..1747600a73e 100644 --- a/testdata/p4_16_samples_outputs/ternary2-bmv2-frontend.p4 +++ b/testdata/p4_16_samples_outputs/ternary2-bmv2-frontend.p4 @@ -148,6 +148,8 @@ control ingress(inout packet_t hdrs, inout Meta m, inout standard_metadata_t met act3: { tbl3_0.apply(); } + default: { + } } } diff --git a/testdata/p4_16_samples_outputs/ternary2-bmv2-midend.p4 b/testdata/p4_16_samples_outputs/ternary2-bmv2-midend.p4 index c7210714334..4fe7a694a1f 100644 --- a/testdata/p4_16_samples_outputs/ternary2-bmv2-midend.p4 +++ b/testdata/p4_16_samples_outputs/ternary2-bmv2-midend.p4 @@ -148,6 +148,8 @@ control ingress(inout packet_t hdrs, inout Meta m, inout standard_metadata_t met act3: { tbl3_0.apply(); } + default: { + } } } diff --git a/testdata/p4_16_samples_outputs/uninit-first.p4 b/testdata/p4_16_samples_outputs/uninit-first.p4 index b352217504c..65ccea4e9f4 100644 --- a/testdata/p4_16_samples_outputs/uninit-first.p4 +++ b/testdata/p4_16_samples_outputs/uninit-first.p4 @@ -78,6 +78,8 @@ control c(out bit<32> v) { a1: { touched = true; } + default: { + } } touched = !touched; diff --git a/testdata/p4_16_samples_outputs/uninit-frontend.p4 b/testdata/p4_16_samples_outputs/uninit-frontend.p4 index de8e66ddea7..ad410d1eba9 100644 --- a/testdata/p4_16_samples_outputs/uninit-frontend.p4 +++ b/testdata/p4_16_samples_outputs/uninit-frontend.p4 @@ -79,6 +79,8 @@ control c(out bit<32> v) { a1: { touched_0 = true; } + default: { + } } if (e_0 > 32w0) { diff --git a/testdata/p4_16_samples_outputs/uninit-midend.p4 b/testdata/p4_16_samples_outputs/uninit-midend.p4 index d61ac91718c..8a71253a01a 100644 --- a/testdata/p4_16_samples_outputs/uninit-midend.p4 +++ b/testdata/p4_16_samples_outputs/uninit-midend.p4 @@ -91,6 +91,8 @@ control c(out bit<32> v) { switch (t_0.apply().action_run) { a1: { } + default: { + } } if (e_0 > 32w0) { From e5e0c2f1e0f64856c8dd77f1dad1767731d1b5f8 Mon Sep 17 00:00:00 2001 From: Chris Dodd Date: Fri, 31 Jan 2020 12:07:12 -0800 Subject: [PATCH 073/106] Fix uninitialized 'unreachable' field in FindUninitialized (#2171) --- frontends/p4/simplifyDefUse.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/frontends/p4/simplifyDefUse.cpp b/frontends/p4/simplifyDefUse.cpp index ddfe2d6efa9..96b647a15c5 100644 --- a/frontends/p4/simplifyDefUse.cpp +++ b/frontends/p4/simplifyDefUse.cpp @@ -84,6 +84,7 @@ class FindUninitialized : public Inspector { } // 'expression' is reading the 'loc' location set void reads(const IR::Expression* expression, const LocationSet* loc) { + BUG_CHECK(!unreachable, "reached an unreachable expression in FindUninitialized"); LOG3(expression << " reads " << loc); CHECK_NULL(expression); CHECK_NULL(loc); @@ -93,6 +94,10 @@ class FindUninitialized : public Inspector { currentPoint = ProgramPoint(context, statement); return false; } + profile_t init_apply(const IR::Node *root) { + unreachable = false; // assume not unreachable at the start of any apply + return Inspector::init_apply(root); + } FindUninitialized(FindUninitialized* parent, ProgramPoint context) : context(context), refMap(parent->definitions->storageMap->refMap), From a455675c805b16112596bb331ae56c2e7078fd33 Mon Sep 17 00:00:00 2001 From: Hemant Singh <32817427+hesingh@users.noreply.github.com> Date: Tue, 4 Feb 2020 03:24:25 -0500 Subject: [PATCH 074/106] Quarantine four tests broken by behavioral model (#2182) --- backends/bmv2/CMakeLists.txt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/backends/bmv2/CMakeLists.txt b/backends/bmv2/CMakeLists.txt index 77cfd75fe38..e84eeb79e1d 100644 --- a/backends/bmv2/CMakeLists.txt +++ b/backends/bmv2/CMakeLists.txt @@ -184,6 +184,12 @@ set (XFAIL_TESTS # Next two use unknown externs testdata/p4_16_samples/issue1882-bmv2.p4 testdata/p4_16_samples/issue1882-1-bmv2.p4 + # Next four are broken tests due to behavioral model checkin on + # 03/02/2020 via b2b8666. + testdata/p4_14_samples/parser_value_set1.p4 + testdata/p4_14_samples/parser_value_set0.p4 + testdata/p4_14_samples/issue946.p4 + testdata/p4_14_samples/parser_value_set2.p4 ) if (HAVE_SIMPLE_SWITCH) From 53c1b2b42cbd7f80637eb0b711ad050c7407432b Mon Sep 17 00:00:00 2001 From: Mihai Budiu Date: Tue, 4 Feb 2020 13:50:01 -0800 Subject: [PATCH 075/106] Fix mask generation for PVS (#2183) * Fix mask generation for PVS --- backends/bmv2/CMakeLists.txt | 6 ------ backends/bmv2/common/parser.cpp | 13 ++++++++----- 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/backends/bmv2/CMakeLists.txt b/backends/bmv2/CMakeLists.txt index e84eeb79e1d..77cfd75fe38 100644 --- a/backends/bmv2/CMakeLists.txt +++ b/backends/bmv2/CMakeLists.txt @@ -184,12 +184,6 @@ set (XFAIL_TESTS # Next two use unknown externs testdata/p4_16_samples/issue1882-bmv2.p4 testdata/p4_16_samples/issue1882-1-bmv2.p4 - # Next four are broken tests due to behavioral model checkin on - # 03/02/2020 via b2b8666. - testdata/p4_14_samples/parser_value_set1.p4 - testdata/p4_14_samples/parser_value_set0.p4 - testdata/p4_14_samples/issue946.p4 - testdata/p4_14_samples/parser_value_set2.p4 ) if (HAVE_SIMPLE_SWITCH) diff --git a/backends/bmv2/common/parser.cpp b/backends/bmv2/common/parser.cpp index 4536ac4304a..e165b5712b9 100644 --- a/backends/bmv2/common/parser.cpp +++ b/backends/bmv2/common/parser.cpp @@ -291,9 +291,9 @@ void ParserConverter::convertSimpleKey(const IR::Expression* keySet, } unsigned ParserConverter::combine(const IR::Expression* keySet, - const IR::ListExpression* select, - big_int& value, big_int& mask, - bool& is_vset, cstring& vset_name) const { + const IR::ListExpression* select, + big_int& value, big_int& mask, + bool& is_vset, cstring& vset_name) const { // From the BMv2 spec: For values and masks, make sure that you // use the correct format. They need to be the concatenation (in // the right order) of all byte padded fields (padded with 0 @@ -355,7 +355,10 @@ unsigned ParserConverter::combine(const IR::Expression* keySet, auto decl = ctxt->refMap->getDeclaration(pe->path, true); vset_name = decl->controlPlaneName(); is_vset = true; - return totalWidth; + auto vset = decl->to(); + CHECK_NULL(vset); + auto type = ctxt->typeMap->getTypeType(vset->elementType, true); + return ROUNDUP(type->width_bits(), 8); } else { BUG_CHECK(select->components.size() == 1, "%1%: mismatched select/label", select); convertSimpleKey(keySet, value, mask); @@ -390,7 +393,7 @@ ParserConverter::convertSelectExpression(const IR::SelectExpression* expr) { if (is_vset) { trans->emplace("type", "parse_vset"); trans->emplace("value", vset_name); - trans->emplace("mask", mask); + trans->emplace("mask", Util::JsonValue::null); trans->emplace("next_state", stateName(sc->state->path->name)); } else { if (mask == 0) { From 1f6351fa163f8df27d442218397cb2d03f23a7eb Mon Sep 17 00:00:00 2001 From: Chris Dodd Date: Tue, 4 Feb 2020 14:31:27 -0800 Subject: [PATCH 076/106] ordered_set sorted_iterator (#2181) - sorted_begin/end to iterate over elements in sorted order rather than internal order - insert method with position. --- lib/ordered_set.h | 33 +++++++++++++++++++++++++++++++++ test/gtest/ordered_set.cpp | 11 +++++++++++ 2 files changed, 44 insertions(+) diff --git a/lib/ordered_set.h b/lib/ordered_set.h index 3426c19360f..41f856c6579 100644 --- a/lib/ordered_set.h +++ b/lib/ordered_set.h @@ -68,6 +68,21 @@ class ordered_set { public: typedef typename map_type::size_type size_type; + class sorted_iterator : public std::iterator { + friend class ordered_set; + typename map_type::const_iterator iter; + sorted_iterator(typename map_type::const_iterator it) // NOLINT(runtime/explicit) + : iter(it) {} + public: + const T &operator*() const { return *iter->first; } + const T *operator->() const { return iter->first; } + sorted_iterator operator++() { ++iter; return *this; } + sorted_iterator operator--() { --iter; return *this; } + sorted_iterator operator++(int) { auto copy = *this; ++iter; return copy; } + sorted_iterator operator--(int) { auto copy = *this; --iter; return copy; } + bool operator==(const sorted_iterator i) const { return iter == i.iter; } + bool operator!=(const sorted_iterator i) const { return iter != i.iter; } + }; ordered_set() {} ordered_set(const ordered_set &a) : data(a.data) { init_data_map(); } @@ -104,6 +119,8 @@ class ordered_set { const_iterator cend() const noexcept { return data.cend(); } const_reverse_iterator crbegin() const noexcept { return data.crbegin(); } const_reverse_iterator crend() const noexcept { return data.crend(); } + sorted_iterator sorted_begin() const noexcept { return data_map.begin(); } + sorted_iterator sorted_end() const noexcept { return data_map.end(); } reference front() const noexcept { return *data.begin(); } reference back() const noexcept { return *data.rbegin(); } @@ -139,6 +156,22 @@ class ordered_set { for (auto it = begin; it != end; ++it) insert(*it); } + iterator insert(const_iterator pos, const T &v) { + auto it = find(v); + if (it == data.end()) { + it = data.insert(pos, v); + data_map.emplace(&*it, it); + return it; } + return it; + } + iterator insert(const_iterator pos, T &&v) { + auto it = find(v); + if (it == data.end()) { + it = data.insert(pos, std::move(v)); + data_map.emplace(&*it, it); + return it; } + return it; + } void push_back(const T &v) { auto it = find(v); diff --git a/test/gtest/ordered_set.cpp b/test/gtest/ordered_set.cpp index 2b457835628..d844f919028 100644 --- a/test/gtest/ordered_set.cpp +++ b/test/gtest/ordered_set.cpp @@ -14,6 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ +#include #include "gtest/gtest.h" #include "lib/ordered_set.h" @@ -81,5 +82,15 @@ TEST(ordered_set, set_not_equal) { EXPECT_TRUE(a != b); } +TEST(ordered_set, set_intersect) { + ordered_set a = { 5, 8, 1, 10, 4 }; + ordered_set b = { 4, 2, 9, 5, 1 }; + ordered_set expect = { 1, 4, 5 }; + ordered_set res; + std::set_intersection(a.sorted_begin(), a.sorted_end(), b.sorted_begin(), b.sorted_end(), + std::inserter(res, res.end())); + + EXPECT_EQ(res, expect); +} } // namespace Test From 67a899abea0557594d552a149ae2ca1f069b899f Mon Sep 17 00:00:00 2001 From: Hemant Singh <32817427+hesingh@users.noreply.github.com> Date: Tue, 4 Feb 2020 18:28:47 -0500 Subject: [PATCH 077/106] Add function to set left value (#2165) * Add function to copy type properties --- backends/bmv2/common/lower.cpp | 7 +------ frontends/p4/sideEffects.cpp | 7 +------ frontends/p4/typeMap.cpp | 11 +++++++++++ frontends/p4/typeMap.h | 2 ++ 4 files changed, 15 insertions(+), 12 deletions(-) diff --git a/backends/bmv2/common/lower.cpp b/backends/bmv2/common/lower.cpp index c0b9461c9e5..0b4fc1d975c 100644 --- a/backends/bmv2/common/lower.cpp +++ b/backends/bmv2/common/lower.cpp @@ -84,12 +84,7 @@ const IR::Node* LowerExpressions::postorder(IR::Cast* expression) { const IR::Node* LowerExpressions::postorder(IR::Expression* expression) { // Just update the typeMap incrementally. auto orig = getOriginal(); - auto type = typeMap->getType(orig, true); - typeMap->setType(expression, type); - if (typeMap->isCompileTimeConstant(orig)) - typeMap->setCompileTimeConstant(expression); - if (typeMap->isLeftValue(orig)) - typeMap->setLeftValue(expression); + typeMap->cloneExpressionProperties(expression, orig); return expression; } diff --git a/frontends/p4/sideEffects.cpp b/frontends/p4/sideEffects.cpp index 08f5a592bc5..2fc399e813a 100644 --- a/frontends/p4/sideEffects.cpp +++ b/frontends/p4/sideEffects.cpp @@ -49,12 +49,7 @@ const IR::Expression* DoSimplifyExpressions::addAssignment( const IR::Node* DoSimplifyExpressions::postorder(IR::Expression* expression) { LOG3("Visiting " << dbp(expression)); auto orig = getOriginal(); - auto type = typeMap->getType(orig, true); - typeMap->setType(expression, type); - if (typeMap->isLeftValue(orig)) - typeMap->setLeftValue(expression); - if (typeMap->isCompileTimeConstant(orig)) - typeMap->setCompileTimeConstant(expression); + typeMap->cloneExpressionProperties(expression, orig); return expression; } diff --git a/frontends/p4/typeMap.cpp b/frontends/p4/typeMap.cpp index 4d1ec2096e0..11951b749ae 100644 --- a/frontends/p4/typeMap.cpp +++ b/frontends/p4/typeMap.cpp @@ -50,6 +50,17 @@ bool TypeMap::isCompileTimeConstant(const IR::Expression* expression) const { return result; } +// Method copies properties from expression to "to" expression. +void TypeMap::cloneExpressionProperties(const IR::Expression* to, + const IR::Expression* from) { + auto type = getType(from, true); + setType(to, type); + if (isLeftValue(from)) + setLeftValue(to); + if (isCompileTimeConstant(from)) + setCompileTimeConstant(to); +} + void TypeMap::clear() { LOG3("Clearing typeMap"); typeMap.clear(); leftValues.clear(); constants.clear(); allTypeVariables.clear(); diff --git a/frontends/p4/typeMap.h b/frontends/p4/typeMap.h index 39df46c7e2e..e43ff6d24b0 100644 --- a/frontends/p4/typeMap.h +++ b/frontends/p4/typeMap.h @@ -77,6 +77,8 @@ class TypeMap final : public ProgramMap { { return typeMap.size(); } void setLeftValue(const IR::Expression* expression); + void cloneExpressionProperties(const IR::Expression* to, + const IR::Expression* from); void setCompileTimeConstant(const IR::Expression* expression); void addSubstitutions(const TypeVariableSubstitution* tvs); const IR::Type* getSubstitution(const IR::Type_Var* var) From 1159ced13676cba54520474d4e416b314302c1db Mon Sep 17 00:00:00 2001 From: Mihai Budiu Date: Tue, 4 Feb 2020 15:29:18 -0800 Subject: [PATCH 078/106] One more strength reduction (#2178) * One more strength reduction --- frontends/p4/strengthReduction.cpp | 10 ++++++++++ .../09-IPv4OptionsUnparsed-midend.p4 | 4 ++-- testdata/p4_14_samples_outputs/issue576-midend.p4 | 6 +++--- testdata/p4_14_samples_outputs/issue781-midend.p4 | 4 ++-- testdata/p4_16_samples/strength5.p4 | 3 +++ testdata/p4_16_samples_outputs/precedence-first.p4 | 2 +- testdata/p4_16_samples_outputs/strength5-first.p4 | 3 +++ testdata/p4_16_samples_outputs/strength5-frontend.p4 | 0 testdata/p4_16_samples_outputs/strength5.p4 | 3 +++ testdata/p4_16_samples_outputs/strength5.p4-stderr | 1 + 10 files changed, 28 insertions(+), 8 deletions(-) create mode 100644 testdata/p4_16_samples/strength5.p4 create mode 100644 testdata/p4_16_samples_outputs/strength5-first.p4 create mode 100644 testdata/p4_16_samples_outputs/strength5-frontend.p4 create mode 100644 testdata/p4_16_samples_outputs/strength5.p4 create mode 100644 testdata/p4_16_samples_outputs/strength5.p4-stderr diff --git a/frontends/p4/strengthReduction.cpp b/frontends/p4/strengthReduction.cpp index 701cc3131cc..933c84ede77 100644 --- a/frontends/p4/strengthReduction.cpp +++ b/frontends/p4/strengthReduction.cpp @@ -188,12 +188,22 @@ const IR::Node* DoStrengthReduction::postorder(IR::Add* expr) { const IR::Node* DoStrengthReduction::postorder(IR::Shl* expr) { if (isZero(expr->right) || isZero(expr->left)) return expr->left; + if (auto sh2 = expr->left->to()) { + // (a << b) << c is a << (b + c) + return new IR::Shl(expr->srcInfo, sh2->left, + new IR::Add(expr->srcInfo, sh2->right, expr->right)); + } return expr; } const IR::Node* DoStrengthReduction::postorder(IR::Shr* expr) { if (isZero(expr->right) || isZero(expr->left)) return expr->left; + if (auto sh2 = expr->left->to()) { + // (a >> b) >> c is a >> (b + c) + return new IR::Shr(expr->srcInfo, sh2->left, + new IR::Add(expr->srcInfo, sh2->right, expr->right)); + } return expr; } diff --git a/testdata/p4_14_samples_outputs/09-IPv4OptionsUnparsed-midend.p4 b/testdata/p4_14_samples_outputs/09-IPv4OptionsUnparsed-midend.p4 index 551f7b7e9e2..38d4f987bc8 100644 --- a/testdata/p4_14_samples_outputs/09-IPv4OptionsUnparsed-midend.p4 +++ b/testdata/p4_14_samples_outputs/09-IPv4OptionsUnparsed-midend.p4 @@ -39,7 +39,7 @@ header ipv4_t { bit<16> hdrChecksum; bit<32> srcAddr; bit<32> dstAddr; - @length(((bit<32>)ihl << 2 << 3) + 32w4294967136) + @length(((bit<32>)ihl << 5) + 32w4294967136) varbit<352> options; } @@ -90,7 +90,7 @@ parser ParserImpl(packet_in packet, out headers hdr, inout metadata meta, inout tmp_hdr_0.hdrChecksum = tmp[79:64]; tmp_hdr_0.srcAddr = tmp[63:32]; tmp_hdr_0.dstAddr = tmp[31:0]; - packet.extract(hdr.ipv4, ((bit<32>)tmp[155:152] << 2 << 3) + 32w4294967136); + packet.extract(hdr.ipv4, ((bit<32>)tmp[155:152] << 5) + 32w4294967136); transition accept; } @name(".parse_vlan_tag") state parse_vlan_tag { diff --git a/testdata/p4_14_samples_outputs/issue576-midend.p4 b/testdata/p4_14_samples_outputs/issue576-midend.p4 index 8af8e413cf5..776c8e06249 100644 --- a/testdata/p4_14_samples_outputs/issue576-midend.p4 +++ b/testdata/p4_14_samples_outputs/issue576-midend.p4 @@ -29,7 +29,7 @@ header ipv4_t { bit<16> hdrChecksum; bit<32> srcAddr; bit<32> dstAddr; - @length(((bit<32>)ihl << 2 << 3) + 32w4294967136) + @length(((bit<32>)ihl << 5) + 32w4294967136) varbit<320> options_ipv4; } @@ -80,7 +80,7 @@ parser ParserImpl(packet_in packet, out headers hdr, inout metadata meta, inout tmp_hdr_1.hdrChecksum = tmp[79:64]; tmp_hdr_1.srcAddr = tmp[63:32]; tmp_hdr_1.dstAddr = tmp[31:0]; - packet.extract(hdr.h.next, ((bit<32>)tmp[155:152] << 2 << 3) + 32w4294967136); + packet.extract(hdr.h.next, ((bit<32>)tmp[155:152] << 5) + 32w4294967136); tmp_0 = packet.lookahead>(); tmp_hdr_2.setValid(); tmp_hdr_2.version = tmp_0[159:156]; @@ -95,7 +95,7 @@ parser ParserImpl(packet_in packet, out headers hdr, inout metadata meta, inout tmp_hdr_2.hdrChecksum = tmp_0[79:64]; tmp_hdr_2.srcAddr = tmp_0[63:32]; tmp_hdr_2.dstAddr = tmp_0[31:0]; - packet.extract(hdr.h.next, ((bit<32>)tmp_0[155:152] << 2 << 3) + 32w4294967136); + packet.extract(hdr.h.next, ((bit<32>)tmp_0[155:152] << 5) + 32w4294967136); transition accept; } } diff --git a/testdata/p4_14_samples_outputs/issue781-midend.p4 b/testdata/p4_14_samples_outputs/issue781-midend.p4 index b1d80716652..e985863e1aa 100644 --- a/testdata/p4_14_samples_outputs/issue781-midend.p4 +++ b/testdata/p4_14_samples_outputs/issue781-midend.p4 @@ -29,7 +29,7 @@ header ipv4_t { bit<16> hdrChecksum; bit<32> srcAddr; bit<32> dstAddr; - @length(((bit<32>)ihl << 2 << 3) + 32w4294967136) + @length(((bit<32>)ihl << 5) + 32w4294967136) varbit<320> options_ipv4; } @@ -59,7 +59,7 @@ parser ParserImpl(packet_in packet, out headers hdr, inout metadata meta, inout tmp_hdr_0.hdrChecksum = tmp[79:64]; tmp_hdr_0.srcAddr = tmp[63:32]; tmp_hdr_0.dstAddr = tmp[31:0]; - packet.extract(hdr.h, ((bit<32>)tmp[155:152] << 2 << 3) + 32w4294967136); + packet.extract(hdr.h, ((bit<32>)tmp[155:152] << 5) + 32w4294967136); transition accept; } } diff --git a/testdata/p4_16_samples/strength5.p4 b/testdata/p4_16_samples/strength5.p4 new file mode 100644 index 00000000000..b4004ca326f --- /dev/null +++ b/testdata/p4_16_samples/strength5.p4 @@ -0,0 +1,3 @@ +action a(inout bit<32> x) { + x = x >> 3 >> 8; +} diff --git a/testdata/p4_16_samples_outputs/precedence-first.p4 b/testdata/p4_16_samples_outputs/precedence-first.p4 index eeab5a8e6ef..82cba1023b5 100644 --- a/testdata/p4_16_samples_outputs/precedence-first.p4 +++ b/testdata/p4_16_samples_outputs/precedence-first.p4 @@ -69,7 +69,7 @@ action ac() { e = a < b == e; e = e == a < b; e = a < b == e; - a = a << b << c; + a = a << b + c; a = a << (b << c); a = a << b >> c; a = a << (b >> c); diff --git a/testdata/p4_16_samples_outputs/strength5-first.p4 b/testdata/p4_16_samples_outputs/strength5-first.p4 new file mode 100644 index 00000000000..0bf0fa39aed --- /dev/null +++ b/testdata/p4_16_samples_outputs/strength5-first.p4 @@ -0,0 +1,3 @@ +action a(inout bit<32> x) { + x = x >> 3 + 8; +} diff --git a/testdata/p4_16_samples_outputs/strength5-frontend.p4 b/testdata/p4_16_samples_outputs/strength5-frontend.p4 new file mode 100644 index 00000000000..e69de29bb2d diff --git a/testdata/p4_16_samples_outputs/strength5.p4 b/testdata/p4_16_samples_outputs/strength5.p4 new file mode 100644 index 00000000000..b4004ca326f --- /dev/null +++ b/testdata/p4_16_samples_outputs/strength5.p4 @@ -0,0 +1,3 @@ +action a(inout bit<32> x) { + x = x >> 3 >> 8; +} diff --git a/testdata/p4_16_samples_outputs/strength5.p4-stderr b/testdata/p4_16_samples_outputs/strength5.p4-stderr new file mode 100644 index 00000000000..7f94c95a8ff --- /dev/null +++ b/testdata/p4_16_samples_outputs/strength5.p4-stderr @@ -0,0 +1 @@ +warning: Program does not contain a `main' module From 8f3b7474a6dd642a1fe7a128be53b6b63a060db8 Mon Sep 17 00:00:00 2001 From: Andy Fingerhut Date: Tue, 4 Feb 2020 15:31:48 -0800 Subject: [PATCH 079/106] Add match_kind optional to v1model.p4 and bmv2 back end (#2184) --- backends/bmv2/common/control.cpp | 40 +++++++- backends/bmv2/common/helpers.cpp | 1 + backends/bmv2/common/helpers.h | 1 + control-plane/p4RuntimeSerializer.cpp | 22 ++++- control-plane/p4runtime | 2 +- frontends/p4/fromv1.0/v1model.h | 4 +- p4include/v1model.p4 | 2 + .../table-entries-optional-2-bmv2.p4 | 83 ++++++++++++++++ .../p4_16_errors_outputs/issue1541.p4-stderr | 2 +- .../issue1557-bmv2.p4-stderr | 2 +- .../p4_16_errors_outputs/issue513.p4-stderr | 2 +- .../table-entries-optional-2-bmv2-first.p4 | 80 ++++++++++++++++ .../table-entries-optional-2-bmv2-frontend.p4 | 80 ++++++++++++++++ .../table-entries-optional-2-bmv2-midend.p4 | 80 ++++++++++++++++ .../table-entries-optional-2-bmv2.p4 | 80 ++++++++++++++++ .../table-entries-optional-2-bmv2.p4-stderr | 12 +++ ...ble-entries-optional-2-bmv2.p4.entries.txt | 76 +++++++++++++++ ...able-entries-optional-2-bmv2.p4.p4info.txt | 49 ++++++++++ .../table-entries-optional-bmv2.p4 | 80 ++++++++++++++++ .../table-entries-optional-bmv2.stf | 15 +++ .../p4_16_samples_outputs/issue841.p4-stderr | 2 +- .../table-entries-optional-bmv2-first.p4 | 82 ++++++++++++++++ .../table-entries-optional-bmv2-frontend.p4 | 82 ++++++++++++++++ .../table-entries-optional-bmv2-midend.p4 | 82 ++++++++++++++++ .../table-entries-optional-bmv2.p4 | 82 ++++++++++++++++ .../table-entries-optional-bmv2.p4-stderr | 0 ...table-entries-optional-bmv2.p4.entries.txt | 96 +++++++++++++++++++ .../table-entries-optional-bmv2.p4.p4info.txt | 49 ++++++++++ 28 files changed, 1176 insertions(+), 12 deletions(-) create mode 100644 testdata/p4_16_errors/table-entries-optional-2-bmv2.p4 create mode 100644 testdata/p4_16_errors_outputs/table-entries-optional-2-bmv2-first.p4 create mode 100644 testdata/p4_16_errors_outputs/table-entries-optional-2-bmv2-frontend.p4 create mode 100644 testdata/p4_16_errors_outputs/table-entries-optional-2-bmv2-midend.p4 create mode 100644 testdata/p4_16_errors_outputs/table-entries-optional-2-bmv2.p4 create mode 100644 testdata/p4_16_errors_outputs/table-entries-optional-2-bmv2.p4-stderr create mode 100644 testdata/p4_16_errors_outputs/table-entries-optional-2-bmv2.p4.entries.txt create mode 100644 testdata/p4_16_errors_outputs/table-entries-optional-2-bmv2.p4.p4info.txt create mode 100644 testdata/p4_16_samples/table-entries-optional-bmv2.p4 create mode 100644 testdata/p4_16_samples/table-entries-optional-bmv2.stf create mode 100644 testdata/p4_16_samples_outputs/table-entries-optional-bmv2-first.p4 create mode 100644 testdata/p4_16_samples_outputs/table-entries-optional-bmv2-frontend.p4 create mode 100644 testdata/p4_16_samples_outputs/table-entries-optional-bmv2-midend.p4 create mode 100644 testdata/p4_16_samples_outputs/table-entries-optional-bmv2.p4 create mode 100644 testdata/p4_16_samples_outputs/table-entries-optional-bmv2.p4-stderr create mode 100644 testdata/p4_16_samples_outputs/table-entries-optional-bmv2.p4.entries.txt create mode 100644 testdata/p4_16_samples_outputs/table-entries-optional-bmv2.p4.p4info.txt diff --git a/backends/bmv2/common/control.cpp b/backends/bmv2/common/control.cpp index a46117fcf21..af39d96793e 100644 --- a/backends/bmv2/common/control.cpp +++ b/backends/bmv2/common/control.cpp @@ -42,7 +42,14 @@ void ControlConverter::convertTableEntries(const IR::P4Table *table, auto keyWidth = tableKey->expression->type->width_bits(); auto k8 = ROUNDUP(keyWidth, 8); auto matchType = getKeyMatchType(tableKey); - key->emplace("match_type", matchType); + // Table key fields with match_kind optional will be + // represented in the BMv2 JSON file the same as a ternary + // field would be. + if (matchType == "optional") { + key->emplace("match_type", "ternary"); + } else { + key->emplace("match_type", matchType); + } if (matchType == corelib.exactMatch.name) { if (k->is()) key->emplace("key", stringRepr(k->to()->value, k8)); @@ -100,6 +107,23 @@ void ControlConverter::convertTableEntries(const IR::P4Table *table, } else { ::error(ErrorType::ERR_UNSUPPORTED, "range key expression", k); } + } else if (matchType == "optional") { + // Table key fields with match_kind optional with + // "const entries" in the P4 source code will be + // represented using the same "key" and "mask" keys in + // the BMv2 JSON file as table key fields with + // match_kind ternary. In the P4 source code we only + // allow exact values or a DefaultExpression (_ or + // default), no &&& expression. + if (k->is()) { + key->emplace("key", stringRepr(k->to()->value, k8)); + key->emplace("mask", stringRepr(Util::mask(keyWidth), k8)); + } else if (k->is()) { + key->emplace("key", stringRepr(0, k8)); + key->emplace("mask", stringRepr(0, k8)); + } else { + ::error(ErrorType::ERR_UNSUPPORTED, "optional key expression", k); + } } else { ::error(ErrorType::ERR_UNKNOWN, "key match type '%2%' for key %1%", k, matchType); } @@ -320,13 +344,14 @@ ControlConverter::convertTable(const CFG::TableNode* node, // Decreasing order of precedence (bmv2 specification): // 0) more than one LPM field is an error // 1) if there is at least one RANGE field, then the table is RANGE - // 2) if there is at least one TERNARY field, then the table is TERNARY + // 2) if there is at least one TERNARY or OPTIONAL field, then the table is TERNARY // 3) if there is a LPM field, then the table is LPM // 4) otherwise the table is EXACT if (match_type != table_match_type) { if (match_type == BMV2::MatchImplementation::rangeMatchTypeName) table_match_type = BMV2::MatchImplementation::rangeMatchTypeName; - if (match_type == corelib.ternaryMatch.name && + if ((match_type == corelib.ternaryMatch.name || + match_type == BMV2::MatchImplementation::optionalMatchTypeName) && table_match_type != BMV2::MatchImplementation::rangeMatchTypeName) table_match_type = corelib.ternaryMatch.name; if (match_type == corelib.lpmMatch.name && @@ -354,7 +379,14 @@ ControlConverter::convertTable(const CFG::TableNode* node, } auto keyelement = new Util::JsonObject(); - keyelement->emplace("match_type", match_type); + // Table key fields with match_kind optional will be + // represented in the BMv2 JSON file the same as a ternary + // field would be. + if (match_type == BMV2::MatchImplementation::optionalMatchTypeName) { + keyelement->emplace("match_type", corelib.ternaryMatch.name); + } else { + keyelement->emplace("match_type", match_type); + } if (auto na = ke->getAnnotation(IR::Annotation::nameAnnotation)) { BUG_CHECK(na->expr.size() == 1, "%1%: expected 1 name", na); auto name = na->expr[0]->to(); diff --git a/backends/bmv2/common/helpers.cpp b/backends/bmv2/common/helpers.cpp index 88352dc90ff..3593eb1bc32 100644 --- a/backends/bmv2/common/helpers.cpp +++ b/backends/bmv2/common/helpers.cpp @@ -23,6 +23,7 @@ const cstring TableImplementation::actionProfileName = "action_profile"; const cstring TableImplementation::actionSelectorName = "action_selector"; const cstring MatchImplementation::selectorMatchTypeName = "selector"; const cstring MatchImplementation::rangeMatchTypeName = "range"; +const cstring MatchImplementation::optionalMatchTypeName = "optional"; const unsigned TableAttributes::defaultTableSize = 1024; const cstring V1ModelProperties::jsonMetadataParameterName = "standard_metadata"; const cstring V1ModelProperties::validField = "$valid$"; diff --git a/backends/bmv2/common/helpers.h b/backends/bmv2/common/helpers.h index 49f9e44cbe4..275cedb33cd 100644 --- a/backends/bmv2/common/helpers.h +++ b/backends/bmv2/common/helpers.h @@ -48,6 +48,7 @@ class MatchImplementation { public: static const cstring selectorMatchTypeName; static const cstring rangeMatchTypeName; + static const cstring optionalMatchTypeName; }; class TableAttributes { diff --git a/control-plane/p4RuntimeSerializer.cpp b/control-plane/p4RuntimeSerializer.cpp index e6e14a0476a..a040ec8844a 100644 --- a/control-plane/p4RuntimeSerializer.cpp +++ b/control-plane/p4RuntimeSerializer.cpp @@ -625,6 +625,8 @@ getMatchType(cstring matchTypeName) { return MatchField::MatchTypes::TERNARY; } else if (matchTypeName == P4V1::V1Model::instance.rangeMatchType.name) { return MatchField::MatchTypes::RANGE; + } else if (matchTypeName == P4V1::V1Model::instance.optionalMatchType.name) { + return MatchField::MatchTypes::OPTIONAL; } else if (matchTypeName == P4V1::V1Model::instance.selectorMatchType.name) { // Nothing to do here, we cannot even perform some sanity-checking. return boost::none; @@ -1381,13 +1383,14 @@ class P4RuntimeEntriesConverter { } /// Checks if the @table entries need to be assigned a priority, i.e. does - /// the match key for the table includes a ternary or range match? + /// the match key for the table includes a ternary, range, or optional match? bool tableNeedsPriority(const IR::P4Table* table, ReferenceMap* refMap) const { for (auto e : table->getKey()->keyElements) { auto matchType = getKeyMatchType(e, refMap); // TODO(antonin): remove dependency on v1model. if (matchType == P4CoreLibrary::instance.ternaryMatch.name || - matchType == P4V1::V1Model::instance.rangeMatchType.name) { + matchType == P4V1::V1Model::instance.rangeMatchType.name || + matchType == P4V1::V1Model::instance.optionalMatchType.name) { return true; } } @@ -1453,6 +1456,8 @@ class P4RuntimeEntriesConverter { addTernary(protoEntry, fieldId++, k, keyWidth, typeMap); } else if (matchType == P4V1::V1Model::instance.rangeMatchType.name) { addRange(protoEntry, fieldId++, k, keyWidth, typeMap); + } else if (matchType == P4V1::V1Model::instance.optionalMatchType.name) { + addOptional(protoEntry, fieldId++, k, keyWidth, typeMap); } else { if (!k->is()) ::error("%1%: match type not supported by P4Runtime serializer", matchType); @@ -1641,6 +1646,19 @@ class P4RuntimeEntriesConverter { protoRange->set_high(*endStr); } + void addOptional(p4v1::TableEntry* protoEntry, int fieldId, + const IR::Expression* k, int keyWidth, + TypeMap* typeMap) const { + if (k->is()) // don't care, skip in P4Runtime message + return; + auto protoMatch = protoEntry->add_match(); + protoMatch->set_field_id(fieldId); + auto protoOptional = protoMatch->mutable_optional(); + auto value = convertSimpleKeyExpression(k, keyWidth, typeMap); + if (value == boost::none) return; + protoOptional->set_value(*value); + } + cstring getKeyMatchType(const IR::KeyElement* ke, ReferenceMap* refMap) const { auto path = ke->matchType->path; auto mt = refMap->getDeclaration(path, true)->to(); diff --git a/control-plane/p4runtime b/control-plane/p4runtime index e7a10bbc417..a48b45754b3 160000 --- a/control-plane/p4runtime +++ b/control-plane/p4runtime @@ -1 +1 @@ -Subproject commit e7a10bbc4178aad56055ca9384bbdbf18d15341a +Subproject commit a48b45754b39756c226d00380f6e3d00c3087a21 diff --git a/frontends/p4/fromv1.0/v1model.h b/frontends/p4/fromv1.0/v1model.h index 8745dda44e3..7bc5dc36275 100644 --- a/frontends/p4/fromv1.0/v1model.h +++ b/frontends/p4/fromv1.0/v1model.h @@ -255,7 +255,8 @@ class V1Model : public ::Model::Model { ingress("ingress", headersType, metadataType, standardMetadataType), sw(), counterOrMeter("$"), counter(), meter(), random(), action_profile(), action_selector(), clone(), resubmit("resubmit"), - tableAttributes(), rangeMatchType("range"), selectorMatchType("selector"), + tableAttributes(), rangeMatchType("range"), + optionalMatchType("optional"), selectorMatchType("selector"), verify("verifyChecksum", headersType), compute("computeChecksum", headersType), digest_receiver(), hash(), algorithm(), registers(), drop("mark_to_drop"), @@ -291,6 +292,7 @@ class V1Model : public ::Model::Model { ::Model::Elem resubmit; TableAttributes_Model tableAttributes; ::Model::Elem rangeMatchType; + ::Model::Elem optionalMatchType; ::Model::Elem selectorMatchType; VerifyUpdate_Model verify; VerifyUpdate_Model compute; diff --git a/p4include/v1model.p4 b/p4include/v1model.p4 index 820178f9c64..8e841d2ad97 100644 --- a/p4include/v1model.p4 +++ b/p4include/v1model.p4 @@ -53,6 +53,8 @@ limitations under the License. match_kind { range, + // Either an exact match, or a wildcard (matching any value). + optional, // Used for implementing dynamic_action_selection selector } diff --git a/testdata/p4_16_errors/table-entries-optional-2-bmv2.p4 b/testdata/p4_16_errors/table-entries-optional-2-bmv2.p4 new file mode 100644 index 00000000000..6d65bdb78ad --- /dev/null +++ b/testdata/p4_16_errors/table-entries-optional-2-bmv2.p4 @@ -0,0 +1,83 @@ +/* +Copyright 2020 Cisco Systems, 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 +#include + +header hdr { + bit<8> e; + bit<16> t; + bit<8> l; + bit<8> r; + bit<8> v; +} + +struct Header_t { + hdr h; +} +struct Meta_t {} + +parser p(packet_in b, out Header_t h, inout Meta_t m, inout standard_metadata_t sm) { + state start { + b.extract(h.h); + transition accept; + } +} + +control vrfy(inout Header_t h, inout Meta_t m) { apply {} } +control update(inout Header_t h, inout Meta_t m) { apply {} } +control egress(inout Header_t h, inout Meta_t m, inout standard_metadata_t sm) { apply {} } +control deparser(packet_out b, in Header_t h) { apply { b.emit(h.h); } } + +control ingress(inout Header_t h, inout Meta_t m, inout standard_metadata_t standard_meta) { + + action a() { standard_meta.egress_spec = 0; } + action a_with_control_params(bit<9> x) { standard_meta.egress_spec = x; } + + + table t_optional { + + key = { + h.h.e : optional; + h.h.t : optional; + } + + actions = { + a; + a_with_control_params; + } + + default_action = a; + + const entries = { + // Test that p4c gives error if one attempts to use an + // explicit mask for an optional field at all. Only + // support an exact value without a mask, or _ / default. + (0xaa &&& 0xff, 0x1111 &&& 0xffff) : a_with_control_params(1); + // value too large + (0x100, default): a_with_control_params(2); + // other value too large + (default, 0x10000): a_with_control_params(3); + } + } + + apply { + t_optional.apply(); + } +} + + +V1Switch(p(), vrfy(), ingress(), egress(), update(), deparser()) main; diff --git a/testdata/p4_16_errors_outputs/issue1541.p4-stderr b/testdata/p4_16_errors_outputs/issue1541.p4-stderr index 767ae5f6fb7..3af8884bd93 100644 --- a/testdata/p4_16_errors_outputs/issue1541.p4-stderr +++ b/testdata/p4_16_errors_outputs/issue1541.p4-stderr @@ -1,7 +1,7 @@ issue1541.p4(25): [--Wwarn=shadow] warning: hash shadows hash action hash() { ^^^^ -v1model.p4(399) +v1model.p4(401) extern void hash(out O result, in HashAlgorithm algo, in T base, in D data, in M max); ^^^^ issue1541.p4(26): [--Werror=type-error] error: hash: Recursive action call diff --git a/testdata/p4_16_errors_outputs/issue1557-bmv2.p4-stderr b/testdata/p4_16_errors_outputs/issue1557-bmv2.p4-stderr index a364413c554..aae1053d7a5 100644 --- a/testdata/p4_16_errors_outputs/issue1557-bmv2.p4-stderr +++ b/testdata/p4_16_errors_outputs/issue1557-bmv2.p4-stderr @@ -1,7 +1,7 @@ issue1557-bmv2.p4(17): [--Werror=type-error] error: Field drop is not a member of structure struct standard_metadata action drop() { smeta.drop = 1; } ^^^^ -v1model.p4(61) +v1model.p4(63) struct standard_metadata_t { ^^^^^^^^^^^^^^^^^^^ issue1557-bmv2.p4(19): [--Werror=type-error] error: idx: parameter should be assigned in call rewrite diff --git a/testdata/p4_16_errors_outputs/issue513.p4-stderr b/testdata/p4_16_errors_outputs/issue513.p4-stderr index 72e3ddb5257..4e83fafabd4 100644 --- a/testdata/p4_16_errors_outputs/issue513.p4-stderr +++ b/testdata/p4_16_errors_outputs/issue513.p4-stderr @@ -1,7 +1,7 @@ issue513.p4(60): [--Wwarn=deprecated] warning: mark_to_drop: Using deprecated feature mark_to_drop. Please use mark_to_drop(standard_metadata) instead. mark_to_drop(); ^^^^^^^^^^^^ -v1model.p4(363) +v1model.p4(365) extern void mark_to_drop(); ^^^^^^^^^^^^ issue513.p4(60): [--Werror=target-error] error: MethodCallStatement: Unsupported on target Conditional execution in actions diff --git a/testdata/p4_16_errors_outputs/table-entries-optional-2-bmv2-first.p4 b/testdata/p4_16_errors_outputs/table-entries-optional-2-bmv2-first.p4 new file mode 100644 index 00000000000..6a7e14a75c6 --- /dev/null +++ b/testdata/p4_16_errors_outputs/table-entries-optional-2-bmv2-first.p4 @@ -0,0 +1,80 @@ +#include +#include + +header hdr { + bit<8> e; + bit<16> t; + bit<8> l; + bit<8> r; + bit<8> v; +} + +struct Header_t { + hdr h; +} + +struct Meta_t { +} + +parser p(packet_in b, out Header_t h, inout Meta_t m, inout standard_metadata_t sm) { + state start { + b.extract(h.h); + transition accept; + } +} + +control vrfy(inout Header_t h, inout Meta_t m) { + apply { + } +} + +control update(inout Header_t h, inout Meta_t m) { + apply { + } +} + +control egress(inout Header_t h, inout Meta_t m, inout standard_metadata_t sm) { + apply { + } +} + +control deparser(packet_out b, in Header_t h) { + apply { + b.emit(h.h); + } +} + +control ingress(inout Header_t h, inout Meta_t m, inout standard_metadata_t standard_meta) { + action a() { + standard_meta.egress_spec = 9w0; + } + action a_with_control_params(bit<9> x) { + standard_meta.egress_spec = x; + } + table t_optional { + key = { + h.h.e: optional @name("h.h.e") ; + h.h.t: optional @name("h.h.t") ; + } + actions = { + a(); + a_with_control_params(); + } + default_action = a(); + const entries = { + (8w0xaa &&& 8w0xff, 16w0x1111 &&& 16w0xffff) : a_with_control_params(9w1); + + (8w0x0, default) : a_with_control_params(9w2); + + (default, 16w0x0) : a_with_control_params(9w3); + + } + + } + apply { + t_optional.apply(); + } +} + +V1Switch(p(), vrfy(), ingress(), egress(), update(), deparser()) main; + diff --git a/testdata/p4_16_errors_outputs/table-entries-optional-2-bmv2-frontend.p4 b/testdata/p4_16_errors_outputs/table-entries-optional-2-bmv2-frontend.p4 new file mode 100644 index 00000000000..cb8f4b24c0d --- /dev/null +++ b/testdata/p4_16_errors_outputs/table-entries-optional-2-bmv2-frontend.p4 @@ -0,0 +1,80 @@ +#include +#include + +header hdr { + bit<8> e; + bit<16> t; + bit<8> l; + bit<8> r; + bit<8> v; +} + +struct Header_t { + hdr h; +} + +struct Meta_t { +} + +parser p(packet_in b, out Header_t h, inout Meta_t m, inout standard_metadata_t sm) { + state start { + b.extract(h.h); + transition accept; + } +} + +control vrfy(inout Header_t h, inout Meta_t m) { + apply { + } +} + +control update(inout Header_t h, inout Meta_t m) { + apply { + } +} + +control egress(inout Header_t h, inout Meta_t m, inout standard_metadata_t sm) { + apply { + } +} + +control deparser(packet_out b, in Header_t h) { + apply { + b.emit(h.h); + } +} + +control ingress(inout Header_t h, inout Meta_t m, inout standard_metadata_t standard_meta) { + @name("ingress.a") action a() { + standard_meta.egress_spec = 9w0; + } + @name("ingress.a_with_control_params") action a_with_control_params(bit<9> x) { + standard_meta.egress_spec = x; + } + @name("ingress.t_optional") table t_optional_0 { + key = { + h.h.e: optional @name("h.h.e") ; + h.h.t: optional @name("h.h.t") ; + } + actions = { + a(); + a_with_control_params(); + } + default_action = a(); + const entries = { + (8w0xaa &&& 8w0xff, 16w0x1111 &&& 16w0xffff) : a_with_control_params(9w1); + + (8w0x0, default) : a_with_control_params(9w2); + + (default, 16w0x0) : a_with_control_params(9w3); + + } + + } + apply { + t_optional_0.apply(); + } +} + +V1Switch(p(), vrfy(), ingress(), egress(), update(), deparser()) main; + diff --git a/testdata/p4_16_errors_outputs/table-entries-optional-2-bmv2-midend.p4 b/testdata/p4_16_errors_outputs/table-entries-optional-2-bmv2-midend.p4 new file mode 100644 index 00000000000..cb8f4b24c0d --- /dev/null +++ b/testdata/p4_16_errors_outputs/table-entries-optional-2-bmv2-midend.p4 @@ -0,0 +1,80 @@ +#include +#include + +header hdr { + bit<8> e; + bit<16> t; + bit<8> l; + bit<8> r; + bit<8> v; +} + +struct Header_t { + hdr h; +} + +struct Meta_t { +} + +parser p(packet_in b, out Header_t h, inout Meta_t m, inout standard_metadata_t sm) { + state start { + b.extract(h.h); + transition accept; + } +} + +control vrfy(inout Header_t h, inout Meta_t m) { + apply { + } +} + +control update(inout Header_t h, inout Meta_t m) { + apply { + } +} + +control egress(inout Header_t h, inout Meta_t m, inout standard_metadata_t sm) { + apply { + } +} + +control deparser(packet_out b, in Header_t h) { + apply { + b.emit(h.h); + } +} + +control ingress(inout Header_t h, inout Meta_t m, inout standard_metadata_t standard_meta) { + @name("ingress.a") action a() { + standard_meta.egress_spec = 9w0; + } + @name("ingress.a_with_control_params") action a_with_control_params(bit<9> x) { + standard_meta.egress_spec = x; + } + @name("ingress.t_optional") table t_optional_0 { + key = { + h.h.e: optional @name("h.h.e") ; + h.h.t: optional @name("h.h.t") ; + } + actions = { + a(); + a_with_control_params(); + } + default_action = a(); + const entries = { + (8w0xaa &&& 8w0xff, 16w0x1111 &&& 16w0xffff) : a_with_control_params(9w1); + + (8w0x0, default) : a_with_control_params(9w2); + + (default, 16w0x0) : a_with_control_params(9w3); + + } + + } + apply { + t_optional_0.apply(); + } +} + +V1Switch(p(), vrfy(), ingress(), egress(), update(), deparser()) main; + diff --git a/testdata/p4_16_errors_outputs/table-entries-optional-2-bmv2.p4 b/testdata/p4_16_errors_outputs/table-entries-optional-2-bmv2.p4 new file mode 100644 index 00000000000..d6071b49d77 --- /dev/null +++ b/testdata/p4_16_errors_outputs/table-entries-optional-2-bmv2.p4 @@ -0,0 +1,80 @@ +#include +#include + +header hdr { + bit<8> e; + bit<16> t; + bit<8> l; + bit<8> r; + bit<8> v; +} + +struct Header_t { + hdr h; +} + +struct Meta_t { +} + +parser p(packet_in b, out Header_t h, inout Meta_t m, inout standard_metadata_t sm) { + state start { + b.extract(h.h); + transition accept; + } +} + +control vrfy(inout Header_t h, inout Meta_t m) { + apply { + } +} + +control update(inout Header_t h, inout Meta_t m) { + apply { + } +} + +control egress(inout Header_t h, inout Meta_t m, inout standard_metadata_t sm) { + apply { + } +} + +control deparser(packet_out b, in Header_t h) { + apply { + b.emit(h.h); + } +} + +control ingress(inout Header_t h, inout Meta_t m, inout standard_metadata_t standard_meta) { + action a() { + standard_meta.egress_spec = 0; + } + action a_with_control_params(bit<9> x) { + standard_meta.egress_spec = x; + } + table t_optional { + key = { + h.h.e: optional; + h.h.t: optional; + } + actions = { + a; + a_with_control_params; + } + default_action = a; + const entries = { + (0xaa &&& 0xff, 0x1111 &&& 0xffff) : a_with_control_params(1); + + (0x100, default) : a_with_control_params(2); + + (default, 0x10000) : a_with_control_params(3); + + } + + } + apply { + t_optional.apply(); + } +} + +V1Switch(p(), vrfy(), ingress(), egress(), update(), deparser()) main; + diff --git a/testdata/p4_16_errors_outputs/table-entries-optional-2-bmv2.p4-stderr b/testdata/p4_16_errors_outputs/table-entries-optional-2-bmv2.p4-stderr new file mode 100644 index 00000000000..419ff939a83 --- /dev/null +++ b/testdata/p4_16_errors_outputs/table-entries-optional-2-bmv2.p4-stderr @@ -0,0 +1,12 @@ +table-entries-optional-2-bmv2.p4(71): [--Wwarn=mismatch] warning: 0x100: value does not fit in 8 bits + (0x100, default): a_with_control_params(2); + ^^^^^ +table-entries-optional-2-bmv2.p4(73): [--Wwarn=mismatch] warning: 0x10000: value does not fit in 16 bits + (default, 0x10000): a_with_control_params(3); + ^^^^^^^ +table-entries-optional-2-bmv2.p4(69): [--Werror=legacy] error: &&& invalid key expression + (0xaa &&& 0xff, 0x1111 &&& 0xffff) : a_with_control_params(1); + ^^^^^^^^^^^^^ +table-entries-optional-2-bmv2.p4(69): [--Werror=legacy] error: &&& invalid key expression + (0xaa &&& 0xff, 0x1111 &&& 0xffff) : a_with_control_params(1); + ^^^^^^^^^^^^^^^^^ diff --git a/testdata/p4_16_errors_outputs/table-entries-optional-2-bmv2.p4.entries.txt b/testdata/p4_16_errors_outputs/table-entries-optional-2-bmv2.p4.entries.txt new file mode 100644 index 00000000000..0fca100efa9 --- /dev/null +++ b/testdata/p4_16_errors_outputs/table-entries-optional-2-bmv2.p4.entries.txt @@ -0,0 +1,76 @@ +updates { + type: INSERT + entity { + table_entry { + table_id: 33609018 + match { + field_id: 1 + optional { + } + } + match { + field_id: 2 + optional { + } + } + action { + action { + action_id: 16837978 + params { + param_id: 1 + value: "\000\001" + } + } + } + priority: 3 + } + } +} +updates { + type: INSERT + entity { + table_entry { + table_id: 33609018 + match { + field_id: 1 + optional { + value: "\000" + } + } + action { + action { + action_id: 16837978 + params { + param_id: 1 + value: "\000\002" + } + } + } + priority: 2 + } + } +} +updates { + type: INSERT + entity { + table_entry { + table_id: 33609018 + match { + field_id: 2 + optional { + value: "\000\000" + } + } + action { + action { + action_id: 16837978 + params { + param_id: 1 + value: "\000\003" + } + } + } + priority: 1 + } + } +} diff --git a/testdata/p4_16_errors_outputs/table-entries-optional-2-bmv2.p4.p4info.txt b/testdata/p4_16_errors_outputs/table-entries-optional-2-bmv2.p4.p4info.txt new file mode 100644 index 00000000000..a0178dcea7e --- /dev/null +++ b/testdata/p4_16_errors_outputs/table-entries-optional-2-bmv2.p4.p4info.txt @@ -0,0 +1,49 @@ +pkg_info { + arch: "v1model" +} +tables { + preamble { + id: 33609018 + name: "ingress.t_optional" + alias: "t_optional" + } + match_fields { + id: 1 + name: "h.h.e" + bitwidth: 8 + match_type: OPTIONAL + } + match_fields { + id: 2 + name: "h.h.t" + bitwidth: 16 + match_type: OPTIONAL + } + action_refs { + id: 16795253 + } + action_refs { + id: 16837978 + } + size: 1024 + is_const_table: true +} +actions { + preamble { + id: 16795253 + name: "ingress.a" + alias: "a" + } +} +actions { + preamble { + id: 16837978 + name: "ingress.a_with_control_params" + alias: "a_with_control_params" + } + params { + id: 1 + name: "x" + bitwidth: 9 + } +} diff --git a/testdata/p4_16_samples/table-entries-optional-bmv2.p4 b/testdata/p4_16_samples/table-entries-optional-bmv2.p4 new file mode 100644 index 00000000000..6e143f9ea55 --- /dev/null +++ b/testdata/p4_16_samples/table-entries-optional-bmv2.p4 @@ -0,0 +1,80 @@ +/* +Copyright 2020 Cisco Systems, 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 +#include + +header hdr { + bit<8> e; + bit<16> t; + bit<8> l; + bit<8> r; + bit<8> v; +} + +struct Header_t { + hdr h; +} +struct Meta_t {} + +parser p(packet_in b, out Header_t h, inout Meta_t m, inout standard_metadata_t sm) { + state start { + b.extract(h.h); + transition accept; + } +} + +control vrfy(inout Header_t h, inout Meta_t m) { apply {} } +control update(inout Header_t h, inout Meta_t m) { apply {} } +control egress(inout Header_t h, inout Meta_t m, inout standard_metadata_t sm) { apply {} } +control deparser(packet_out b, in Header_t h) { apply { b.emit(h.h); } } + +control ingress(inout Header_t h, inout Meta_t m, inout standard_metadata_t standard_meta) { + + action a() { standard_meta.egress_spec = 0; } + action a_with_control_params(bit<9> x) { standard_meta.egress_spec = x; } + + + table t_optional { + + key = { + h.h.e : optional; + h.h.t : optional; + } + + actions = { + a; + a_with_control_params; + } + + default_action = a; + + const entries = { + (0xaa, 0x1111) : a_with_control_params(1); + ( _, 0x1111) : a_with_control_params(2); + (0xaa, _) : a_with_control_params(3); + // test default entries + ( _, _) : a_with_control_params(4); + } + } + + apply { + t_optional.apply(); + } +} + + +V1Switch(p(), vrfy(), ingress(), egress(), update(), deparser()) main; diff --git a/testdata/p4_16_samples/table-entries-optional-bmv2.stf b/testdata/p4_16_samples/table-entries-optional-bmv2.stf new file mode 100644 index 00000000000..067260d8278 --- /dev/null +++ b/testdata/p4_16_samples/table-entries-optional-bmv2.stf @@ -0,0 +1,15 @@ +# header hdr { bit<8> e; bit<16> t; bit<8> l; bit<8> r; bit<1> v; } + +# t_optional tests: if packets come on port 0, we missed! + +expect 1 aa **** ** ** ** $ +packet 0 aa 1111 00 00 b0 + +expect 2 ab **** ** ** ** $ +packet 0 ab 1111 00 00 b0 + +expect 3 aa **** ** ** ** $ +packet 0 aa 1112 00 00 b0 + +expect 4 a9 **** ** ** ** $ +packet 0 a9 1110 00 00 b0 diff --git a/testdata/p4_16_samples_outputs/issue841.p4-stderr b/testdata/p4_16_samples_outputs/issue841.p4-stderr index 05f1774253d..319997892d3 100644 --- a/testdata/p4_16_samples_outputs/issue841.p4-stderr +++ b/testdata/p4_16_samples_outputs/issue841.p4-stderr @@ -1,6 +1,6 @@ issue841.p4(39): [--Wwarn=deprecated] warning: Checksum16: Using deprecated feature Checksum16. Please use verify_checksum/update_checksum instead. Checksum16() checksum; ^^^^^^^^^^ -v1model.p4(411) +v1model.p4(413) extern Checksum16 { ^^^^^^^^^^ diff --git a/testdata/p4_16_samples_outputs/table-entries-optional-bmv2-first.p4 b/testdata/p4_16_samples_outputs/table-entries-optional-bmv2-first.p4 new file mode 100644 index 00000000000..08c035e3ecd --- /dev/null +++ b/testdata/p4_16_samples_outputs/table-entries-optional-bmv2-first.p4 @@ -0,0 +1,82 @@ +#include +#include + +header hdr { + bit<8> e; + bit<16> t; + bit<8> l; + bit<8> r; + bit<8> v; +} + +struct Header_t { + hdr h; +} + +struct Meta_t { +} + +parser p(packet_in b, out Header_t h, inout Meta_t m, inout standard_metadata_t sm) { + state start { + b.extract(h.h); + transition accept; + } +} + +control vrfy(inout Header_t h, inout Meta_t m) { + apply { + } +} + +control update(inout Header_t h, inout Meta_t m) { + apply { + } +} + +control egress(inout Header_t h, inout Meta_t m, inout standard_metadata_t sm) { + apply { + } +} + +control deparser(packet_out b, in Header_t h) { + apply { + b.emit(h.h); + } +} + +control ingress(inout Header_t h, inout Meta_t m, inout standard_metadata_t standard_meta) { + action a() { + standard_meta.egress_spec = 9w0; + } + action a_with_control_params(bit<9> x) { + standard_meta.egress_spec = x; + } + table t_optional { + key = { + h.h.e: optional @name("h.h.e") ; + h.h.t: optional @name("h.h.t") ; + } + actions = { + a(); + a_with_control_params(); + } + default_action = a(); + const entries = { + (8w0xaa, 16w0x1111) : a_with_control_params(9w1); + + (default, 16w0x1111) : a_with_control_params(9w2); + + (8w0xaa, default) : a_with_control_params(9w3); + + (default, default) : a_with_control_params(9w4); + + } + + } + apply { + t_optional.apply(); + } +} + +V1Switch(p(), vrfy(), ingress(), egress(), update(), deparser()) main; + diff --git a/testdata/p4_16_samples_outputs/table-entries-optional-bmv2-frontend.p4 b/testdata/p4_16_samples_outputs/table-entries-optional-bmv2-frontend.p4 new file mode 100644 index 00000000000..979cdabe565 --- /dev/null +++ b/testdata/p4_16_samples_outputs/table-entries-optional-bmv2-frontend.p4 @@ -0,0 +1,82 @@ +#include +#include + +header hdr { + bit<8> e; + bit<16> t; + bit<8> l; + bit<8> r; + bit<8> v; +} + +struct Header_t { + hdr h; +} + +struct Meta_t { +} + +parser p(packet_in b, out Header_t h, inout Meta_t m, inout standard_metadata_t sm) { + state start { + b.extract(h.h); + transition accept; + } +} + +control vrfy(inout Header_t h, inout Meta_t m) { + apply { + } +} + +control update(inout Header_t h, inout Meta_t m) { + apply { + } +} + +control egress(inout Header_t h, inout Meta_t m, inout standard_metadata_t sm) { + apply { + } +} + +control deparser(packet_out b, in Header_t h) { + apply { + b.emit(h.h); + } +} + +control ingress(inout Header_t h, inout Meta_t m, inout standard_metadata_t standard_meta) { + @name("ingress.a") action a() { + standard_meta.egress_spec = 9w0; + } + @name("ingress.a_with_control_params") action a_with_control_params(bit<9> x) { + standard_meta.egress_spec = x; + } + @name("ingress.t_optional") table t_optional_0 { + key = { + h.h.e: optional @name("h.h.e") ; + h.h.t: optional @name("h.h.t") ; + } + actions = { + a(); + a_with_control_params(); + } + default_action = a(); + const entries = { + (8w0xaa, 16w0x1111) : a_with_control_params(9w1); + + (default, 16w0x1111) : a_with_control_params(9w2); + + (8w0xaa, default) : a_with_control_params(9w3); + + (default, default) : a_with_control_params(9w4); + + } + + } + apply { + t_optional_0.apply(); + } +} + +V1Switch(p(), vrfy(), ingress(), egress(), update(), deparser()) main; + diff --git a/testdata/p4_16_samples_outputs/table-entries-optional-bmv2-midend.p4 b/testdata/p4_16_samples_outputs/table-entries-optional-bmv2-midend.p4 new file mode 100644 index 00000000000..979cdabe565 --- /dev/null +++ b/testdata/p4_16_samples_outputs/table-entries-optional-bmv2-midend.p4 @@ -0,0 +1,82 @@ +#include +#include + +header hdr { + bit<8> e; + bit<16> t; + bit<8> l; + bit<8> r; + bit<8> v; +} + +struct Header_t { + hdr h; +} + +struct Meta_t { +} + +parser p(packet_in b, out Header_t h, inout Meta_t m, inout standard_metadata_t sm) { + state start { + b.extract(h.h); + transition accept; + } +} + +control vrfy(inout Header_t h, inout Meta_t m) { + apply { + } +} + +control update(inout Header_t h, inout Meta_t m) { + apply { + } +} + +control egress(inout Header_t h, inout Meta_t m, inout standard_metadata_t sm) { + apply { + } +} + +control deparser(packet_out b, in Header_t h) { + apply { + b.emit(h.h); + } +} + +control ingress(inout Header_t h, inout Meta_t m, inout standard_metadata_t standard_meta) { + @name("ingress.a") action a() { + standard_meta.egress_spec = 9w0; + } + @name("ingress.a_with_control_params") action a_with_control_params(bit<9> x) { + standard_meta.egress_spec = x; + } + @name("ingress.t_optional") table t_optional_0 { + key = { + h.h.e: optional @name("h.h.e") ; + h.h.t: optional @name("h.h.t") ; + } + actions = { + a(); + a_with_control_params(); + } + default_action = a(); + const entries = { + (8w0xaa, 16w0x1111) : a_with_control_params(9w1); + + (default, 16w0x1111) : a_with_control_params(9w2); + + (8w0xaa, default) : a_with_control_params(9w3); + + (default, default) : a_with_control_params(9w4); + + } + + } + apply { + t_optional_0.apply(); + } +} + +V1Switch(p(), vrfy(), ingress(), egress(), update(), deparser()) main; + diff --git a/testdata/p4_16_samples_outputs/table-entries-optional-bmv2.p4 b/testdata/p4_16_samples_outputs/table-entries-optional-bmv2.p4 new file mode 100644 index 00000000000..db331902cc4 --- /dev/null +++ b/testdata/p4_16_samples_outputs/table-entries-optional-bmv2.p4 @@ -0,0 +1,82 @@ +#include +#include + +header hdr { + bit<8> e; + bit<16> t; + bit<8> l; + bit<8> r; + bit<8> v; +} + +struct Header_t { + hdr h; +} + +struct Meta_t { +} + +parser p(packet_in b, out Header_t h, inout Meta_t m, inout standard_metadata_t sm) { + state start { + b.extract(h.h); + transition accept; + } +} + +control vrfy(inout Header_t h, inout Meta_t m) { + apply { + } +} + +control update(inout Header_t h, inout Meta_t m) { + apply { + } +} + +control egress(inout Header_t h, inout Meta_t m, inout standard_metadata_t sm) { + apply { + } +} + +control deparser(packet_out b, in Header_t h) { + apply { + b.emit(h.h); + } +} + +control ingress(inout Header_t h, inout Meta_t m, inout standard_metadata_t standard_meta) { + action a() { + standard_meta.egress_spec = 0; + } + action a_with_control_params(bit<9> x) { + standard_meta.egress_spec = x; + } + table t_optional { + key = { + h.h.e: optional; + h.h.t: optional; + } + actions = { + a; + a_with_control_params; + } + default_action = a; + const entries = { + (0xaa, 0x1111) : a_with_control_params(1); + + (default, 0x1111) : a_with_control_params(2); + + (0xaa, default) : a_with_control_params(3); + + (default, default) : a_with_control_params(4); + + } + + } + apply { + t_optional.apply(); + } +} + +V1Switch(p(), vrfy(), ingress(), egress(), update(), deparser()) main; + diff --git a/testdata/p4_16_samples_outputs/table-entries-optional-bmv2.p4-stderr b/testdata/p4_16_samples_outputs/table-entries-optional-bmv2.p4-stderr new file mode 100644 index 00000000000..e69de29bb2d diff --git a/testdata/p4_16_samples_outputs/table-entries-optional-bmv2.p4.entries.txt b/testdata/p4_16_samples_outputs/table-entries-optional-bmv2.p4.entries.txt new file mode 100644 index 00000000000..e0a73803ae3 --- /dev/null +++ b/testdata/p4_16_samples_outputs/table-entries-optional-bmv2.p4.entries.txt @@ -0,0 +1,96 @@ +updates { + type: INSERT + entity { + table_entry { + table_id: 33609018 + match { + field_id: 1 + optional { + value: "\252" + } + } + match { + field_id: 2 + optional { + value: "\021\021" + } + } + action { + action { + action_id: 16837978 + params { + param_id: 1 + value: "\000\001" + } + } + } + priority: 4 + } + } +} +updates { + type: INSERT + entity { + table_entry { + table_id: 33609018 + match { + field_id: 2 + optional { + value: "\021\021" + } + } + action { + action { + action_id: 16837978 + params { + param_id: 1 + value: "\000\002" + } + } + } + priority: 3 + } + } +} +updates { + type: INSERT + entity { + table_entry { + table_id: 33609018 + match { + field_id: 1 + optional { + value: "\252" + } + } + action { + action { + action_id: 16837978 + params { + param_id: 1 + value: "\000\003" + } + } + } + priority: 2 + } + } +} +updates { + type: INSERT + entity { + table_entry { + table_id: 33609018 + action { + action { + action_id: 16837978 + params { + param_id: 1 + value: "\000\004" + } + } + } + priority: 1 + } + } +} diff --git a/testdata/p4_16_samples_outputs/table-entries-optional-bmv2.p4.p4info.txt b/testdata/p4_16_samples_outputs/table-entries-optional-bmv2.p4.p4info.txt new file mode 100644 index 00000000000..a0178dcea7e --- /dev/null +++ b/testdata/p4_16_samples_outputs/table-entries-optional-bmv2.p4.p4info.txt @@ -0,0 +1,49 @@ +pkg_info { + arch: "v1model" +} +tables { + preamble { + id: 33609018 + name: "ingress.t_optional" + alias: "t_optional" + } + match_fields { + id: 1 + name: "h.h.e" + bitwidth: 8 + match_type: OPTIONAL + } + match_fields { + id: 2 + name: "h.h.t" + bitwidth: 16 + match_type: OPTIONAL + } + action_refs { + id: 16795253 + } + action_refs { + id: 16837978 + } + size: 1024 + is_const_table: true +} +actions { + preamble { + id: 16795253 + name: "ingress.a" + alias: "a" + } +} +actions { + preamble { + id: 16837978 + name: "ingress.a_with_control_params" + alias: "a_with_control_params" + } + params { + id: 1 + name: "x" + bitwidth: 9 + } +} From e5b6c838d06e0075dd0d113600b01f5ae71498de Mon Sep 17 00:00:00 2001 From: Mihai Budiu Date: Tue, 4 Feb 2020 15:34:33 -0800 Subject: [PATCH 080/106] Use the type from the typeMap; fixes #2163 (#2179) --- backends/bmv2/common/parser.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/backends/bmv2/common/parser.cpp b/backends/bmv2/common/parser.cpp index e165b5712b9..92b3bf6eea2 100644 --- a/backends/bmv2/common/parser.cpp +++ b/backends/bmv2/common/parser.cpp @@ -446,7 +446,8 @@ bool ParserConverter::preorder(const IR::P4Parser* parser) { for (auto s : parser->parserLocals) { if (auto inst = s->to()) { - auto bitwidth = inst->elementType->width_bits(); + auto etype = ctxt->typeMap->getTypeType(inst->elementType, true); + auto bitwidth = etype->width_bits(); auto name = inst->controlPlaneName(); ctxt->json->add_parse_vset(name, bitwidth); } From 710e8cae539d08a38644959f2a0c089d47d86fcd Mon Sep 17 00:00:00 2001 From: Chris Dodd Date: Wed, 5 Feb 2020 14:14:13 -0800 Subject: [PATCH 081/106] Fixes for issues found by the klockwork static analyzer (#2189) --- backends/bmv2/psa_switch/psaSwitch.cpp | 5 +++-- frontends/common/constantFolding.cpp | 3 ++- frontends/p4/typeChecking/bindVariables.cpp | 2 +- frontends/p4/typeChecking/typeUnification.cpp | 3 +-- frontends/p4/validateParsedProgram.cpp | 3 ++- ir/ir-inline.h | 4 ++-- ir/json_loader.h | 3 +-- 7 files changed, 12 insertions(+), 11 deletions(-) diff --git a/backends/bmv2/psa_switch/psaSwitch.cpp b/backends/bmv2/psa_switch/psaSwitch.cpp index 5674e2a82c3..f4f8021b72b 100644 --- a/backends/bmv2/psa_switch/psaSwitch.cpp +++ b/backends/bmv2/psa_switch/psaSwitch.cpp @@ -771,7 +771,7 @@ void ExternConverter_Counter::convertExternInstance( // in conversion context will handle that for us auto tp = eb->findParameterValue("type"); if (!tp || !tp->is()) { - modelError("%1%: expected a declaration_id", tp->getNode()); + modelError("%1%: expected a declaration_id", tp ? tp->getNode() : eb->getNode()); return; } auto arg2 = tp->to(); @@ -813,7 +813,7 @@ void ExternConverter_DirectCounter::convertExternInstance( // converter in conversion context will handle this for us auto tp = eb->findParameterValue("type"); if (!tp || !tp->is()) { - modelError("%1%: expected a declaration_id", tp->getNode()); + modelError("%1%: expected a declaration_id", tp ? tp->getNode() : eb->getNode()); return; } if (eb->getConstructorParameters()->size() < 2) { @@ -993,6 +993,7 @@ void ExternConverter_ActionSelector::convertExternInstance( auto sz = eb->findParameterValue("size"); if (!sz->is()) { ::error(ErrorType::ERR_EXPECTED, "a constant", sz); + return; } action_profile->emplace("max_size", sz->to()->value); diff --git a/frontends/common/constantFolding.cpp b/frontends/common/constantFolding.cpp index 0dfb3e07f46..01f6c2d5fa7 100644 --- a/frontends/common/constantFolding.cpp +++ b/frontends/common/constantFolding.cpp @@ -659,8 +659,9 @@ const IR::Node* DoConstantFolding::postorder(IR::Mux* e) { if (cond == nullptr) return e; auto b = cond->to(); - if (b == nullptr) + if (b == nullptr) { ::error("%1%: expected a Boolean", cond); + return e; } if (b->value) return e->e1; else diff --git a/frontends/p4/typeChecking/bindVariables.cpp b/frontends/p4/typeChecking/bindVariables.cpp index 7434d94eba1..70a2bb2b0ea 100644 --- a/frontends/p4/typeChecking/bindVariables.cpp +++ b/frontends/p4/typeChecking/bindVariables.cpp @@ -43,7 +43,7 @@ class HasInfInt : public Inspector { /// Return nullptr if the type is not suitable to assign to a type variable. static const IR::Type* validateType( const IR::Type* type, const TypeMap* typeMap, const IR::Node* errorPosition) { - auto repl = type->getP4Type(); + auto repl = type ? type->getP4Type() : nullptr; if (type == nullptr || repl == nullptr || HasInfInt::find(type)) { auto eoi = new ErrorOnInfInt(typeMap); errorPosition->apply(*eoi); diff --git a/frontends/p4/typeChecking/typeUnification.cpp b/frontends/p4/typeChecking/typeUnification.cpp index 2bc3fe20d41..1ee985fc6d5 100644 --- a/frontends/p4/typeChecking/typeUnification.cpp +++ b/frontends/p4/typeChecking/typeUnification.cpp @@ -46,8 +46,7 @@ bool TypeUnification::unifyCall(const IR::Node* errorPosition, if (dest->typeParameters->size() != src->typeArguments->size()) { TypeInference::typeError( "%1% has %2% type parameters, but is invoked with %3% type arguments", - errorPosition, (dest->typeParameters ? dest->typeParameters->size() : 0), - src->typeArguments->size()); + errorPosition, dest->typeParameters->size(), src->typeArguments->size()); return false; } diff --git a/frontends/p4/validateParsedProgram.cpp b/frontends/p4/validateParsedProgram.cpp index 178212f273d..375ccb928ea 100644 --- a/frontends/p4/validateParsedProgram.cpp +++ b/frontends/p4/validateParsedProgram.cpp @@ -173,9 +173,10 @@ void ValidateParsedProgram::postorder(const IR::Declaration_Constant* decl) { */ void ValidateParsedProgram::postorder(const IR::EntriesList* l) { auto table = findContext(); - if (table == nullptr) + if (table == nullptr) { ::error(ErrorType::ERR_INVALID, "initializer. Table initializers must belong to a table.", l); + return; } auto ep = table->properties->getProperty(IR::TableProperties::entriesPropertyName); if (!ep->isConstant) ::error(ErrorType::ERR_INVALID, diff --git a/ir/ir-inline.h b/ir/ir-inline.h index ff724810e43..e887aba1349 100644 --- a/ir/ir-inline.h +++ b/ir/ir-inline.h @@ -60,7 +60,7 @@ template void IR::Vector::visit_children(Visitor &v) { *i++ = e; else BUG("visitor returned invalid type %s for Vector<%s>", - e->node_type_name(), T::static_type_name()); } } + el->node_type_name(), T::static_type_name()); } } } else if (auto e = dynamic_cast(n)) { *i++ = e; } else { @@ -97,7 +97,7 @@ template void IR::Vector::parallel_visit_children(Visitor &v) { *i++ = e; else BUG("visitor returned invalid type %s for Vector<%s>", - e->node_type_name(), T::static_type_name()); } } + el->node_type_name(), T::static_type_name()); } } } else if (auto e = dynamic_cast(n)) { *i++ = e; } else { diff --git a/ir/json_loader.h b/ir/json_loader.h index af10bc0794b..03744c2bc60 100644 --- a/ir/json_loader.h +++ b/ir/json_loader.h @@ -228,8 +228,7 @@ class JSONLoader { load("base", base); load("hasWidth", hasWidth); - UnparsedConstant result {text, skip, base, hasWidth}; - v = &result; + v = new UnparsedConstant({text, skip, base, hasWidth}); } template From 31478504cfbc88858ac3a62aa503cbbd8e399129 Mon Sep 17 00:00:00 2001 From: Antonin Bas Date: Wed, 5 Feb 2020 14:23:38 -0800 Subject: [PATCH 082/106] Remove unused function declaration in bmv2 backend (#2187) --- backends/bmv2/common/JsonObjects.h | 1 - 1 file changed, 1 deletion(-) diff --git a/backends/bmv2/common/JsonObjects.h b/backends/bmv2/common/JsonObjects.h index cd99b2253a5..f28a5eb7705 100644 --- a/backends/bmv2/common/JsonObjects.h +++ b/backends/bmv2/common/JsonObjects.h @@ -51,7 +51,6 @@ class JsonObjects { void add_parser_transition_key(const unsigned id, Util::IJson* key); void add_parse_vset(const cstring& name, const unsigned size); unsigned add_action(const cstring& name, Util::JsonArray*& params, Util::JsonArray*& body); - void add_pipeline(); void add_extern_attribute(const cstring& name, const cstring& type, const cstring& value, Util::JsonArray* attributes); void add_extern(const cstring& name, const cstring& type, Util::JsonArray* attributes); From 9a2abd7ead8f7f71f1a5387aa299fe5f81fc6c32 Mon Sep 17 00:00:00 2001 From: Andy Fingerhut Date: Wed, 5 Feb 2020 14:24:26 -0800 Subject: [PATCH 083/106] New and updated tests of parser value sets that exercise bmv2 back end (#2174) --- testdata/p4_16_samples/pvs-bitstring-bmv2.p4 | 63 +++++++++++++ .../{pvs-struct.p4 => pvs-struct-1-bmv2.p4} | 0 testdata/p4_16_samples/pvs-struct-2-bmv2.p4 | 68 ++++++++++++++ testdata/p4_16_samples/pvs-struct-3-bmv2.p4 | 70 ++++++++++++++ .../pvs-bitstring-bmv2-first.p4 | 70 ++++++++++++++ .../pvs-bitstring-bmv2-frontend.p4 | 72 +++++++++++++++ .../pvs-bitstring-bmv2-midend.p4 | 77 ++++++++++++++++ .../pvs-bitstring-bmv2.p4 | 68 ++++++++++++++ ...p4-stderr => pvs-bitstring-bmv2.p4-stderr} | 0 ....txt => pvs-bitstring-bmv2.p4.entries.txt} | 0 .../pvs-bitstring-bmv2.p4.p4info.txt | 52 +++++++++++ ...ct-first.p4 => pvs-struct-1-bmv2-first.p4} | 0 ...ntend.p4 => pvs-struct-1-bmv2-frontend.p4} | 0 ...-midend.p4 => pvs-struct-1-bmv2-midend.p4} | 0 .../{pvs-struct.p4 => pvs-struct-1-bmv2.p4} | 0 .../pvs-struct-1-bmv2.p4-stderr | 0 .../pvs-struct-1-bmv2.p4.entries.txt | 0 ...fo.txt => pvs-struct-1-bmv2.p4.p4info.txt} | 0 .../pvs-struct-2-bmv2-first.p4 | 75 +++++++++++++++ .../pvs-struct-2-bmv2-frontend.p4 | 77 ++++++++++++++++ .../pvs-struct-2-bmv2-midend.p4 | 82 +++++++++++++++++ .../pvs-struct-2-bmv2.p4 | 73 +++++++++++++++ .../pvs-struct-2-bmv2.p4-stderr | 0 .../pvs-struct-2-bmv2.p4.entries.txt | 0 .../pvs-struct-2-bmv2.p4.p4info.txt | 59 ++++++++++++ .../pvs-struct-3-bmv2-first.p4 | 81 +++++++++++++++++ .../pvs-struct-3-bmv2-frontend.p4 | 83 +++++++++++++++++ .../pvs-struct-3-bmv2-midend.p4 | 91 +++++++++++++++++++ .../pvs-struct-3-bmv2.p4 | 79 ++++++++++++++++ .../pvs-struct-3-bmv2.p4-stderr | 0 .../pvs-struct-3-bmv2.p4.entries.txt | 0 .../pvs-struct-3-bmv2.p4.p4info.txt | 71 +++++++++++++++ 32 files changed, 1311 insertions(+) create mode 100644 testdata/p4_16_samples/pvs-bitstring-bmv2.p4 rename testdata/p4_16_samples/{pvs-struct.p4 => pvs-struct-1-bmv2.p4} (100%) create mode 100644 testdata/p4_16_samples/pvs-struct-2-bmv2.p4 create mode 100644 testdata/p4_16_samples/pvs-struct-3-bmv2.p4 create mode 100644 testdata/p4_16_samples_outputs/pvs-bitstring-bmv2-first.p4 create mode 100644 testdata/p4_16_samples_outputs/pvs-bitstring-bmv2-frontend.p4 create mode 100644 testdata/p4_16_samples_outputs/pvs-bitstring-bmv2-midend.p4 create mode 100644 testdata/p4_16_samples_outputs/pvs-bitstring-bmv2.p4 rename testdata/p4_16_samples_outputs/{pvs-struct.p4-stderr => pvs-bitstring-bmv2.p4-stderr} (100%) rename testdata/p4_16_samples_outputs/{pvs-struct.p4.entries.txt => pvs-bitstring-bmv2.p4.entries.txt} (100%) create mode 100644 testdata/p4_16_samples_outputs/pvs-bitstring-bmv2.p4.p4info.txt rename testdata/p4_16_samples_outputs/{pvs-struct-first.p4 => pvs-struct-1-bmv2-first.p4} (100%) rename testdata/p4_16_samples_outputs/{pvs-struct-frontend.p4 => pvs-struct-1-bmv2-frontend.p4} (100%) rename testdata/p4_16_samples_outputs/{pvs-struct-midend.p4 => pvs-struct-1-bmv2-midend.p4} (100%) rename testdata/p4_16_samples_outputs/{pvs-struct.p4 => pvs-struct-1-bmv2.p4} (100%) create mode 100644 testdata/p4_16_samples_outputs/pvs-struct-1-bmv2.p4-stderr create mode 100644 testdata/p4_16_samples_outputs/pvs-struct-1-bmv2.p4.entries.txt rename testdata/p4_16_samples_outputs/{pvs-struct.p4.p4info.txt => pvs-struct-1-bmv2.p4.p4info.txt} (100%) create mode 100644 testdata/p4_16_samples_outputs/pvs-struct-2-bmv2-first.p4 create mode 100644 testdata/p4_16_samples_outputs/pvs-struct-2-bmv2-frontend.p4 create mode 100644 testdata/p4_16_samples_outputs/pvs-struct-2-bmv2-midend.p4 create mode 100644 testdata/p4_16_samples_outputs/pvs-struct-2-bmv2.p4 create mode 100644 testdata/p4_16_samples_outputs/pvs-struct-2-bmv2.p4-stderr create mode 100644 testdata/p4_16_samples_outputs/pvs-struct-2-bmv2.p4.entries.txt create mode 100644 testdata/p4_16_samples_outputs/pvs-struct-2-bmv2.p4.p4info.txt create mode 100644 testdata/p4_16_samples_outputs/pvs-struct-3-bmv2-first.p4 create mode 100644 testdata/p4_16_samples_outputs/pvs-struct-3-bmv2-frontend.p4 create mode 100644 testdata/p4_16_samples_outputs/pvs-struct-3-bmv2-midend.p4 create mode 100644 testdata/p4_16_samples_outputs/pvs-struct-3-bmv2.p4 create mode 100644 testdata/p4_16_samples_outputs/pvs-struct-3-bmv2.p4-stderr create mode 100644 testdata/p4_16_samples_outputs/pvs-struct-3-bmv2.p4.entries.txt create mode 100644 testdata/p4_16_samples_outputs/pvs-struct-3-bmv2.p4.p4info.txt diff --git a/testdata/p4_16_samples/pvs-bitstring-bmv2.p4 b/testdata/p4_16_samples/pvs-bitstring-bmv2.p4 new file mode 100644 index 00000000000..69c43d283b4 --- /dev/null +++ b/testdata/p4_16_samples/pvs-bitstring-bmv2.p4 @@ -0,0 +1,63 @@ +#include + +header data_h { + bit<32> da; + bit<32> db; +} + +struct my_packet { + data_h data; +} + +struct my_metadata { + data_h[2] data; +} + +parser MyParser(packet_in b, out my_packet p, inout my_metadata m, inout standard_metadata_t s) { + + value_set>(4) pvs; + + state start { + b.extract(p.data); + transition select(p.data.da) { + pvs: accept; + 0x810 : foo; + } + } + + state foo { + transition accept; + } +} + +control MyVerifyChecksum(inout my_packet hdr, inout my_metadata meta) { + apply { } +} + + +control MyIngress(inout my_packet p, inout my_metadata meta, inout standard_metadata_t s) { + action set_data() { + } + table t { + actions = { set_data; } + key = { meta.data[0].da : exact;} + } + apply { + t.apply(); + } +} + +control MyEgress(inout my_packet p, inout my_metadata m, inout standard_metadata_t s) { + apply { + } +} + +control MyComputeChecksum(inout my_packet p, inout my_metadata m) { + apply { } +} + +control MyDeparser(packet_out b, in my_packet p) { + apply { } +} + +V1Switch(MyParser(), MyVerifyChecksum(), MyIngress(), MyEgress(), MyComputeChecksum(), MyDeparser()) main; diff --git a/testdata/p4_16_samples/pvs-struct.p4 b/testdata/p4_16_samples/pvs-struct-1-bmv2.p4 similarity index 100% rename from testdata/p4_16_samples/pvs-struct.p4 rename to testdata/p4_16_samples/pvs-struct-1-bmv2.p4 diff --git a/testdata/p4_16_samples/pvs-struct-2-bmv2.p4 b/testdata/p4_16_samples/pvs-struct-2-bmv2.p4 new file mode 100644 index 00000000000..e4b8d4e51c9 --- /dev/null +++ b/testdata/p4_16_samples/pvs-struct-2-bmv2.p4 @@ -0,0 +1,68 @@ +#include + +header data_h { + bit<32> da; + bit<32> db; +} + +struct my_packet { + data_h data; +} + +struct my_metadata { + data_h[2] data; +} + +struct value_set_t { + bit<16> field; + bit<3> field2; +} + +parser MyParser(packet_in b, out my_packet p, inout my_metadata m, inout standard_metadata_t s) { + + value_set(4) pvs; + + state start { + b.extract(p.data); + transition select(p.data.da[15:0], p.data.db[7:5]) { + pvs: accept; + (0x810, 0x1) : foo; + } + } + + state foo { + transition accept; + } +} + +control MyVerifyChecksum(inout my_packet hdr, inout my_metadata meta) { + apply { } +} + + +control MyIngress(inout my_packet p, inout my_metadata meta, inout standard_metadata_t s) { + action set_data() { + } + table t { + actions = { set_data; } + key = { meta.data[0].da : exact;} + } + apply { + t.apply(); + } +} + +control MyEgress(inout my_packet p, inout my_metadata m, inout standard_metadata_t s) { + apply { + } +} + +control MyComputeChecksum(inout my_packet p, inout my_metadata m) { + apply { } +} + +control MyDeparser(packet_out b, in my_packet p) { + apply { } +} + +V1Switch(MyParser(), MyVerifyChecksum(), MyIngress(), MyEgress(), MyComputeChecksum(), MyDeparser()) main; diff --git a/testdata/p4_16_samples/pvs-struct-3-bmv2.p4 b/testdata/p4_16_samples/pvs-struct-3-bmv2.p4 new file mode 100644 index 00000000000..4661e91916d --- /dev/null +++ b/testdata/p4_16_samples/pvs-struct-3-bmv2.p4 @@ -0,0 +1,70 @@ +#include + +header data_h { + bit<32> da; + bit<32> db; +} + +struct my_packet { + data_h data; +} + +struct my_metadata { + data_h[2] data; +} + +struct value_set_t { + @match(ternary) bit<16> field1; + @match(lpm) bit<3> field2; + @match(exact) bit<6> field3; + @match(range) bit<5> field4; +} + +parser MyParser(packet_in b, out my_packet p, inout my_metadata m, inout standard_metadata_t s) { + + value_set(4) pvs; + + state start { + b.extract(p.data); + transition select(p.data.da[15:0], p.data.db[7:5], p.data.db[29:24], p.data.da[30:26]) { + pvs: accept; + (0x810, 0x4 &&& 0x6, 0x32 &&& 0x33, 10..20) : foo; + } + } + + state foo { + transition accept; + } +} + +control MyVerifyChecksum(inout my_packet hdr, inout my_metadata meta) { + apply { } +} + + +control MyIngress(inout my_packet p, inout my_metadata meta, inout standard_metadata_t s) { + action set_data() { + } + table t { + actions = { set_data; } + key = { meta.data[0].da : exact;} + } + apply { + t.apply(); + } +} + +control MyEgress(inout my_packet p, inout my_metadata m, inout standard_metadata_t s) { + apply { + } +} + +control MyComputeChecksum(inout my_packet p, inout my_metadata m) { + apply { } +} + +control MyDeparser(packet_out b, in my_packet p) { + apply { } +} + +V1Switch(MyParser(), MyVerifyChecksum(), MyIngress(), MyEgress(), MyComputeChecksum(), MyDeparser()) main; diff --git a/testdata/p4_16_samples_outputs/pvs-bitstring-bmv2-first.p4 b/testdata/p4_16_samples_outputs/pvs-bitstring-bmv2-first.p4 new file mode 100644 index 00000000000..5a172fb4b88 --- /dev/null +++ b/testdata/p4_16_samples_outputs/pvs-bitstring-bmv2-first.p4 @@ -0,0 +1,70 @@ +#include +#include + +header data_h { + bit<32> da; + bit<32> db; +} + +struct my_packet { + data_h data; +} + +struct my_metadata { + data_h[2] data; +} + +parser MyParser(packet_in b, out my_packet p, inout my_metadata m, inout standard_metadata_t s) { + value_set>(4) pvs; + state start { + b.extract(p.data); + transition select(p.data.da) { + pvs: accept; + 32w0x810: foo; + } + } + state foo { + transition accept; + } +} + +control MyVerifyChecksum(inout my_packet hdr, inout my_metadata meta) { + apply { + } +} + +control MyIngress(inout my_packet p, inout my_metadata meta, inout standard_metadata_t s) { + action set_data() { + } + table t { + actions = { + set_data(); + @defaultonly NoAction(); + } + key = { + meta.data[0].da: exact @name("meta.data[0].da") ; + } + default_action = NoAction(); + } + apply { + t.apply(); + } +} + +control MyEgress(inout my_packet p, inout my_metadata m, inout standard_metadata_t s) { + apply { + } +} + +control MyComputeChecksum(inout my_packet p, inout my_metadata m) { + apply { + } +} + +control MyDeparser(packet_out b, in my_packet p) { + apply { + } +} + +V1Switch(MyParser(), MyVerifyChecksum(), MyIngress(), MyEgress(), MyComputeChecksum(), MyDeparser()) main; + diff --git a/testdata/p4_16_samples_outputs/pvs-bitstring-bmv2-frontend.p4 b/testdata/p4_16_samples_outputs/pvs-bitstring-bmv2-frontend.p4 new file mode 100644 index 00000000000..d0f6790b5e3 --- /dev/null +++ b/testdata/p4_16_samples_outputs/pvs-bitstring-bmv2-frontend.p4 @@ -0,0 +1,72 @@ +#include +#include + +header data_h { + bit<32> da; + bit<32> db; +} + +struct my_packet { + data_h data; +} + +struct my_metadata { + data_h[2] data; +} + +parser MyParser(packet_in b, out my_packet p, inout my_metadata m, inout standard_metadata_t s) { + @name("MyParser.pvs") value_set>(4) pvs_0; + state start { + b.extract(p.data); + transition select(p.data.da) { + pvs_0: accept; + 32w0x810: foo; + } + } + state foo { + transition accept; + } +} + +control MyVerifyChecksum(inout my_packet hdr, inout my_metadata meta) { + apply { + } +} + +control MyIngress(inout my_packet p, inout my_metadata meta, inout standard_metadata_t s) { + @name(".NoAction") action NoAction_0() { + } + @name("MyIngress.set_data") action set_data() { + } + @name("MyIngress.t") table t_0 { + actions = { + set_data(); + @defaultonly NoAction_0(); + } + key = { + meta.data[0].da: exact @name("meta.data[0].da") ; + } + default_action = NoAction_0(); + } + apply { + t_0.apply(); + } +} + +control MyEgress(inout my_packet p, inout my_metadata m, inout standard_metadata_t s) { + apply { + } +} + +control MyComputeChecksum(inout my_packet p, inout my_metadata m) { + apply { + } +} + +control MyDeparser(packet_out b, in my_packet p) { + apply { + } +} + +V1Switch(MyParser(), MyVerifyChecksum(), MyIngress(), MyEgress(), MyComputeChecksum(), MyDeparser()) main; + diff --git a/testdata/p4_16_samples_outputs/pvs-bitstring-bmv2-midend.p4 b/testdata/p4_16_samples_outputs/pvs-bitstring-bmv2-midend.p4 new file mode 100644 index 00000000000..3cc2270c5b4 --- /dev/null +++ b/testdata/p4_16_samples_outputs/pvs-bitstring-bmv2-midend.p4 @@ -0,0 +1,77 @@ +#include +#include + +header data_h { + bit<32> da; + bit<32> db; +} + +struct my_packet { + data_h data; +} + +struct my_metadata { + data_h[2] data; +} + +parser MyParser(packet_in b, out my_packet p, inout my_metadata m, inout standard_metadata_t s) { + @name("MyParser.pvs") value_set>(4) pvs_0; + state start { + b.extract(p.data); + transition select(p.data.da) { + pvs_0: accept; + 32w0x810: foo; + default: noMatch; + } + } + state foo { + transition accept; + } + state noMatch { + verify(false, error.NoMatch); + transition reject; + } +} + +control MyVerifyChecksum(inout my_packet hdr, inout my_metadata meta) { + apply { + } +} + +control MyIngress(inout my_packet p, inout my_metadata meta, inout standard_metadata_t s) { + @name(".NoAction") action NoAction_0() { + } + @name("MyIngress.set_data") action set_data() { + } + @name("MyIngress.t") table t_0 { + actions = { + set_data(); + @defaultonly NoAction_0(); + } + key = { + meta.data[0].da: exact @name("meta.data[0].da") ; + } + default_action = NoAction_0(); + } + apply { + t_0.apply(); + } +} + +control MyEgress(inout my_packet p, inout my_metadata m, inout standard_metadata_t s) { + apply { + } +} + +control MyComputeChecksum(inout my_packet p, inout my_metadata m) { + apply { + } +} + +control MyDeparser(packet_out b, in my_packet p) { + apply { + } +} + +V1Switch(MyParser(), MyVerifyChecksum(), MyIngress(), MyEgress(), MyComputeChecksum(), MyDeparser()) main; + diff --git a/testdata/p4_16_samples_outputs/pvs-bitstring-bmv2.p4 b/testdata/p4_16_samples_outputs/pvs-bitstring-bmv2.p4 new file mode 100644 index 00000000000..abba51e6b7d --- /dev/null +++ b/testdata/p4_16_samples_outputs/pvs-bitstring-bmv2.p4 @@ -0,0 +1,68 @@ +#include +#include + +header data_h { + bit<32> da; + bit<32> db; +} + +struct my_packet { + data_h data; +} + +struct my_metadata { + data_h[2] data; +} + +parser MyParser(packet_in b, out my_packet p, inout my_metadata m, inout standard_metadata_t s) { + value_set>(4) pvs; + state start { + b.extract(p.data); + transition select(p.data.da) { + pvs: accept; + 0x810: foo; + } + } + state foo { + transition accept; + } +} + +control MyVerifyChecksum(inout my_packet hdr, inout my_metadata meta) { + apply { + } +} + +control MyIngress(inout my_packet p, inout my_metadata meta, inout standard_metadata_t s) { + action set_data() { + } + table t { + actions = { + set_data; + } + key = { + meta.data[0].da: exact; + } + } + apply { + t.apply(); + } +} + +control MyEgress(inout my_packet p, inout my_metadata m, inout standard_metadata_t s) { + apply { + } +} + +control MyComputeChecksum(inout my_packet p, inout my_metadata m) { + apply { + } +} + +control MyDeparser(packet_out b, in my_packet p) { + apply { + } +} + +V1Switch(MyParser(), MyVerifyChecksum(), MyIngress(), MyEgress(), MyComputeChecksum(), MyDeparser()) main; + diff --git a/testdata/p4_16_samples_outputs/pvs-struct.p4-stderr b/testdata/p4_16_samples_outputs/pvs-bitstring-bmv2.p4-stderr similarity index 100% rename from testdata/p4_16_samples_outputs/pvs-struct.p4-stderr rename to testdata/p4_16_samples_outputs/pvs-bitstring-bmv2.p4-stderr diff --git a/testdata/p4_16_samples_outputs/pvs-struct.p4.entries.txt b/testdata/p4_16_samples_outputs/pvs-bitstring-bmv2.p4.entries.txt similarity index 100% rename from testdata/p4_16_samples_outputs/pvs-struct.p4.entries.txt rename to testdata/p4_16_samples_outputs/pvs-bitstring-bmv2.p4.entries.txt diff --git a/testdata/p4_16_samples_outputs/pvs-bitstring-bmv2.p4.p4info.txt b/testdata/p4_16_samples_outputs/pvs-bitstring-bmv2.p4.p4info.txt new file mode 100644 index 00000000000..e421b111f81 --- /dev/null +++ b/testdata/p4_16_samples_outputs/pvs-bitstring-bmv2.p4.p4info.txt @@ -0,0 +1,52 @@ +pkg_info { + arch: "v1model" +} +tables { + preamble { + id: 33611905 + name: "MyIngress.t" + alias: "t" + } + match_fields { + id: 1 + name: "meta.data[0].da" + bitwidth: 32 + match_type: EXACT + } + action_refs { + id: 16777606 + } + action_refs { + id: 16800567 + annotations: "@defaultonly" + scope: DEFAULT_ONLY + } + size: 1024 +} +actions { + preamble { + id: 16800567 + name: "NoAction" + alias: "NoAction" + } +} +actions { + preamble { + id: 16777606 + name: "MyIngress.set_data" + alias: "set_data" + } +} +value_sets { + preamble { + id: 50332118 + name: "MyParser.pvs" + alias: "pvs" + } + match { + id: 1 + bitwidth: 32 + match_type: EXACT + } + size: 4 +} diff --git a/testdata/p4_16_samples_outputs/pvs-struct-first.p4 b/testdata/p4_16_samples_outputs/pvs-struct-1-bmv2-first.p4 similarity index 100% rename from testdata/p4_16_samples_outputs/pvs-struct-first.p4 rename to testdata/p4_16_samples_outputs/pvs-struct-1-bmv2-first.p4 diff --git a/testdata/p4_16_samples_outputs/pvs-struct-frontend.p4 b/testdata/p4_16_samples_outputs/pvs-struct-1-bmv2-frontend.p4 similarity index 100% rename from testdata/p4_16_samples_outputs/pvs-struct-frontend.p4 rename to testdata/p4_16_samples_outputs/pvs-struct-1-bmv2-frontend.p4 diff --git a/testdata/p4_16_samples_outputs/pvs-struct-midend.p4 b/testdata/p4_16_samples_outputs/pvs-struct-1-bmv2-midend.p4 similarity index 100% rename from testdata/p4_16_samples_outputs/pvs-struct-midend.p4 rename to testdata/p4_16_samples_outputs/pvs-struct-1-bmv2-midend.p4 diff --git a/testdata/p4_16_samples_outputs/pvs-struct.p4 b/testdata/p4_16_samples_outputs/pvs-struct-1-bmv2.p4 similarity index 100% rename from testdata/p4_16_samples_outputs/pvs-struct.p4 rename to testdata/p4_16_samples_outputs/pvs-struct-1-bmv2.p4 diff --git a/testdata/p4_16_samples_outputs/pvs-struct-1-bmv2.p4-stderr b/testdata/p4_16_samples_outputs/pvs-struct-1-bmv2.p4-stderr new file mode 100644 index 00000000000..e69de29bb2d diff --git a/testdata/p4_16_samples_outputs/pvs-struct-1-bmv2.p4.entries.txt b/testdata/p4_16_samples_outputs/pvs-struct-1-bmv2.p4.entries.txt new file mode 100644 index 00000000000..e69de29bb2d diff --git a/testdata/p4_16_samples_outputs/pvs-struct.p4.p4info.txt b/testdata/p4_16_samples_outputs/pvs-struct-1-bmv2.p4.p4info.txt similarity index 100% rename from testdata/p4_16_samples_outputs/pvs-struct.p4.p4info.txt rename to testdata/p4_16_samples_outputs/pvs-struct-1-bmv2.p4.p4info.txt diff --git a/testdata/p4_16_samples_outputs/pvs-struct-2-bmv2-first.p4 b/testdata/p4_16_samples_outputs/pvs-struct-2-bmv2-first.p4 new file mode 100644 index 00000000000..868cfbba348 --- /dev/null +++ b/testdata/p4_16_samples_outputs/pvs-struct-2-bmv2-first.p4 @@ -0,0 +1,75 @@ +#include +#include + +header data_h { + bit<32> da; + bit<32> db; +} + +struct my_packet { + data_h data; +} + +struct my_metadata { + data_h[2] data; +} + +struct value_set_t { + bit<16> field; + bit<3> field2; +} + +parser MyParser(packet_in b, out my_packet p, inout my_metadata m, inout standard_metadata_t s) { + value_set(4) pvs; + state start { + b.extract(p.data); + transition select(p.data.da[15:0], p.data.db[7:5]) { + pvs: accept; + (16w0x810, 3w0x1): foo; + } + } + state foo { + transition accept; + } +} + +control MyVerifyChecksum(inout my_packet hdr, inout my_metadata meta) { + apply { + } +} + +control MyIngress(inout my_packet p, inout my_metadata meta, inout standard_metadata_t s) { + action set_data() { + } + table t { + actions = { + set_data(); + @defaultonly NoAction(); + } + key = { + meta.data[0].da: exact @name("meta.data[0].da") ; + } + default_action = NoAction(); + } + apply { + t.apply(); + } +} + +control MyEgress(inout my_packet p, inout my_metadata m, inout standard_metadata_t s) { + apply { + } +} + +control MyComputeChecksum(inout my_packet p, inout my_metadata m) { + apply { + } +} + +control MyDeparser(packet_out b, in my_packet p) { + apply { + } +} + +V1Switch(MyParser(), MyVerifyChecksum(), MyIngress(), MyEgress(), MyComputeChecksum(), MyDeparser()) main; + diff --git a/testdata/p4_16_samples_outputs/pvs-struct-2-bmv2-frontend.p4 b/testdata/p4_16_samples_outputs/pvs-struct-2-bmv2-frontend.p4 new file mode 100644 index 00000000000..a3cd0f23908 --- /dev/null +++ b/testdata/p4_16_samples_outputs/pvs-struct-2-bmv2-frontend.p4 @@ -0,0 +1,77 @@ +#include +#include + +header data_h { + bit<32> da; + bit<32> db; +} + +struct my_packet { + data_h data; +} + +struct my_metadata { + data_h[2] data; +} + +struct value_set_t { + bit<16> field; + bit<3> field2; +} + +parser MyParser(packet_in b, out my_packet p, inout my_metadata m, inout standard_metadata_t s) { + @name("MyParser.pvs") value_set(4) pvs_0; + state start { + b.extract(p.data); + transition select(p.data.da[15:0], p.data.db[7:5]) { + pvs_0: accept; + (16w0x810, 3w0x1): foo; + } + } + state foo { + transition accept; + } +} + +control MyVerifyChecksum(inout my_packet hdr, inout my_metadata meta) { + apply { + } +} + +control MyIngress(inout my_packet p, inout my_metadata meta, inout standard_metadata_t s) { + @name(".NoAction") action NoAction_0() { + } + @name("MyIngress.set_data") action set_data() { + } + @name("MyIngress.t") table t_0 { + actions = { + set_data(); + @defaultonly NoAction_0(); + } + key = { + meta.data[0].da: exact @name("meta.data[0].da") ; + } + default_action = NoAction_0(); + } + apply { + t_0.apply(); + } +} + +control MyEgress(inout my_packet p, inout my_metadata m, inout standard_metadata_t s) { + apply { + } +} + +control MyComputeChecksum(inout my_packet p, inout my_metadata m) { + apply { + } +} + +control MyDeparser(packet_out b, in my_packet p) { + apply { + } +} + +V1Switch(MyParser(), MyVerifyChecksum(), MyIngress(), MyEgress(), MyComputeChecksum(), MyDeparser()) main; + diff --git a/testdata/p4_16_samples_outputs/pvs-struct-2-bmv2-midend.p4 b/testdata/p4_16_samples_outputs/pvs-struct-2-bmv2-midend.p4 new file mode 100644 index 00000000000..5863526a46d --- /dev/null +++ b/testdata/p4_16_samples_outputs/pvs-struct-2-bmv2-midend.p4 @@ -0,0 +1,82 @@ +#include +#include + +header data_h { + bit<32> da; + bit<32> db; +} + +struct my_packet { + data_h data; +} + +struct my_metadata { + data_h[2] data; +} + +struct value_set_t { + bit<16> field; + bit<3> field2; +} + +parser MyParser(packet_in b, out my_packet p, inout my_metadata m, inout standard_metadata_t s) { + @name("MyParser.pvs") value_set(4) pvs_0; + state start { + b.extract(p.data); + transition select(p.data.da[15:0], p.data.db[7:5]) { + pvs_0: accept; + (16w0x810, 3w0x1): foo; + default: noMatch; + } + } + state foo { + transition accept; + } + state noMatch { + verify(false, error.NoMatch); + transition reject; + } +} + +control MyVerifyChecksum(inout my_packet hdr, inout my_metadata meta) { + apply { + } +} + +control MyIngress(inout my_packet p, inout my_metadata meta, inout standard_metadata_t s) { + @name(".NoAction") action NoAction_0() { + } + @name("MyIngress.set_data") action set_data() { + } + @name("MyIngress.t") table t_0 { + actions = { + set_data(); + @defaultonly NoAction_0(); + } + key = { + meta.data[0].da: exact @name("meta.data[0].da") ; + } + default_action = NoAction_0(); + } + apply { + t_0.apply(); + } +} + +control MyEgress(inout my_packet p, inout my_metadata m, inout standard_metadata_t s) { + apply { + } +} + +control MyComputeChecksum(inout my_packet p, inout my_metadata m) { + apply { + } +} + +control MyDeparser(packet_out b, in my_packet p) { + apply { + } +} + +V1Switch(MyParser(), MyVerifyChecksum(), MyIngress(), MyEgress(), MyComputeChecksum(), MyDeparser()) main; + diff --git a/testdata/p4_16_samples_outputs/pvs-struct-2-bmv2.p4 b/testdata/p4_16_samples_outputs/pvs-struct-2-bmv2.p4 new file mode 100644 index 00000000000..947afcbdf48 --- /dev/null +++ b/testdata/p4_16_samples_outputs/pvs-struct-2-bmv2.p4 @@ -0,0 +1,73 @@ +#include +#include + +header data_h { + bit<32> da; + bit<32> db; +} + +struct my_packet { + data_h data; +} + +struct my_metadata { + data_h[2] data; +} + +struct value_set_t { + bit<16> field; + bit<3> field2; +} + +parser MyParser(packet_in b, out my_packet p, inout my_metadata m, inout standard_metadata_t s) { + value_set(4) pvs; + state start { + b.extract(p.data); + transition select(p.data.da[15:0], p.data.db[7:5]) { + pvs: accept; + (0x810, 0x1): foo; + } + } + state foo { + transition accept; + } +} + +control MyVerifyChecksum(inout my_packet hdr, inout my_metadata meta) { + apply { + } +} + +control MyIngress(inout my_packet p, inout my_metadata meta, inout standard_metadata_t s) { + action set_data() { + } + table t { + actions = { + set_data; + } + key = { + meta.data[0].da: exact; + } + } + apply { + t.apply(); + } +} + +control MyEgress(inout my_packet p, inout my_metadata m, inout standard_metadata_t s) { + apply { + } +} + +control MyComputeChecksum(inout my_packet p, inout my_metadata m) { + apply { + } +} + +control MyDeparser(packet_out b, in my_packet p) { + apply { + } +} + +V1Switch(MyParser(), MyVerifyChecksum(), MyIngress(), MyEgress(), MyComputeChecksum(), MyDeparser()) main; + diff --git a/testdata/p4_16_samples_outputs/pvs-struct-2-bmv2.p4-stderr b/testdata/p4_16_samples_outputs/pvs-struct-2-bmv2.p4-stderr new file mode 100644 index 00000000000..e69de29bb2d diff --git a/testdata/p4_16_samples_outputs/pvs-struct-2-bmv2.p4.entries.txt b/testdata/p4_16_samples_outputs/pvs-struct-2-bmv2.p4.entries.txt new file mode 100644 index 00000000000..e69de29bb2d diff --git a/testdata/p4_16_samples_outputs/pvs-struct-2-bmv2.p4.p4info.txt b/testdata/p4_16_samples_outputs/pvs-struct-2-bmv2.p4.p4info.txt new file mode 100644 index 00000000000..7501f213b3a --- /dev/null +++ b/testdata/p4_16_samples_outputs/pvs-struct-2-bmv2.p4.p4info.txt @@ -0,0 +1,59 @@ +pkg_info { + arch: "v1model" +} +tables { + preamble { + id: 33611905 + name: "MyIngress.t" + alias: "t" + } + match_fields { + id: 1 + name: "meta.data[0].da" + bitwidth: 32 + match_type: EXACT + } + action_refs { + id: 16777606 + } + action_refs { + id: 16800567 + annotations: "@defaultonly" + scope: DEFAULT_ONLY + } + size: 1024 +} +actions { + preamble { + id: 16800567 + name: "NoAction" + alias: "NoAction" + } +} +actions { + preamble { + id: 16777606 + name: "MyIngress.set_data" + alias: "set_data" + } +} +value_sets { + preamble { + id: 50332118 + name: "MyParser.pvs" + alias: "pvs" + } + match { + id: 1 + name: "field" + bitwidth: 16 + match_type: EXACT + } + match { + id: 2 + name: "field2" + bitwidth: 3 + match_type: EXACT + } + size: 4 +} diff --git a/testdata/p4_16_samples_outputs/pvs-struct-3-bmv2-first.p4 b/testdata/p4_16_samples_outputs/pvs-struct-3-bmv2-first.p4 new file mode 100644 index 00000000000..8eebe27152c --- /dev/null +++ b/testdata/p4_16_samples_outputs/pvs-struct-3-bmv2-first.p4 @@ -0,0 +1,81 @@ +#include +#include + +header data_h { + bit<32> da; + bit<32> db; +} + +struct my_packet { + data_h data; +} + +struct my_metadata { + data_h[2] data; +} + +struct value_set_t { + @match(ternary) + bit<16> field1; + @match(lpm) + bit<3> field2; + @match(exact) + bit<6> field3; + @match(range) + bit<5> field4; +} + +parser MyParser(packet_in b, out my_packet p, inout my_metadata m, inout standard_metadata_t s) { + value_set(4) pvs; + state start { + b.extract(p.data); + transition select(p.data.da[15:0], p.data.db[7:5], p.data.db[29:24], p.data.da[30:26]) { + pvs: accept; + (16w0x810, 3w0x4 &&& 3w0x6, 6w0x32 &&& 6w0x33, 5w10 .. 5w20): foo; + } + } + state foo { + transition accept; + } +} + +control MyVerifyChecksum(inout my_packet hdr, inout my_metadata meta) { + apply { + } +} + +control MyIngress(inout my_packet p, inout my_metadata meta, inout standard_metadata_t s) { + action set_data() { + } + table t { + actions = { + set_data(); + @defaultonly NoAction(); + } + key = { + meta.data[0].da: exact @name("meta.data[0].da") ; + } + default_action = NoAction(); + } + apply { + t.apply(); + } +} + +control MyEgress(inout my_packet p, inout my_metadata m, inout standard_metadata_t s) { + apply { + } +} + +control MyComputeChecksum(inout my_packet p, inout my_metadata m) { + apply { + } +} + +control MyDeparser(packet_out b, in my_packet p) { + apply { + } +} + +V1Switch(MyParser(), MyVerifyChecksum(), MyIngress(), MyEgress(), MyComputeChecksum(), MyDeparser()) main; + diff --git a/testdata/p4_16_samples_outputs/pvs-struct-3-bmv2-frontend.p4 b/testdata/p4_16_samples_outputs/pvs-struct-3-bmv2-frontend.p4 new file mode 100644 index 00000000000..6bc1d738bf1 --- /dev/null +++ b/testdata/p4_16_samples_outputs/pvs-struct-3-bmv2-frontend.p4 @@ -0,0 +1,83 @@ +#include +#include + +header data_h { + bit<32> da; + bit<32> db; +} + +struct my_packet { + data_h data; +} + +struct my_metadata { + data_h[2] data; +} + +struct value_set_t { + @match(ternary) + bit<16> field1; + @match(lpm) + bit<3> field2; + @match(exact) + bit<6> field3; + @match(range) + bit<5> field4; +} + +parser MyParser(packet_in b, out my_packet p, inout my_metadata m, inout standard_metadata_t s) { + @name("MyParser.pvs") value_set(4) pvs_0; + state start { + b.extract(p.data); + transition select(p.data.da[15:0], p.data.db[7:5], p.data.db[29:24], p.data.da[30:26]) { + pvs_0: accept; + (16w0x810, 3w0x4 &&& 3w0x6, 6w0x32 &&& 6w0x33, 5w10 .. 5w20): foo; + } + } + state foo { + transition accept; + } +} + +control MyVerifyChecksum(inout my_packet hdr, inout my_metadata meta) { + apply { + } +} + +control MyIngress(inout my_packet p, inout my_metadata meta, inout standard_metadata_t s) { + @name(".NoAction") action NoAction_0() { + } + @name("MyIngress.set_data") action set_data() { + } + @name("MyIngress.t") table t_0 { + actions = { + set_data(); + @defaultonly NoAction_0(); + } + key = { + meta.data[0].da: exact @name("meta.data[0].da") ; + } + default_action = NoAction_0(); + } + apply { + t_0.apply(); + } +} + +control MyEgress(inout my_packet p, inout my_metadata m, inout standard_metadata_t s) { + apply { + } +} + +control MyComputeChecksum(inout my_packet p, inout my_metadata m) { + apply { + } +} + +control MyDeparser(packet_out b, in my_packet p) { + apply { + } +} + +V1Switch(MyParser(), MyVerifyChecksum(), MyIngress(), MyEgress(), MyComputeChecksum(), MyDeparser()) main; + diff --git a/testdata/p4_16_samples_outputs/pvs-struct-3-bmv2-midend.p4 b/testdata/p4_16_samples_outputs/pvs-struct-3-bmv2-midend.p4 new file mode 100644 index 00000000000..c7a38af0b48 --- /dev/null +++ b/testdata/p4_16_samples_outputs/pvs-struct-3-bmv2-midend.p4 @@ -0,0 +1,91 @@ +#include +#include + +header data_h { + bit<32> da; + bit<32> db; +} + +struct my_packet { + data_h data; +} + +struct my_metadata { + data_h[2] data; +} + +struct value_set_t { + @match(ternary) + bit<16> field1; + @match(lpm) + bit<3> field2; + @match(exact) + bit<6> field3; + @match(range) + bit<5> field4; +} + +parser MyParser(packet_in b, out my_packet p, inout my_metadata m, inout standard_metadata_t s) { + @name("MyParser.pvs") value_set(4) pvs_0; + state start { + b.extract(p.data); + transition select(p.data.da[15:0], p.data.db[7:5], p.data.db[29:24], p.data.da[30:26]) { + pvs_0: accept; + (16w0x810, 3w0x4 &&& 3w0x6, 6w0x32 &&& 6w0x33, 5w10 &&& 5w30): foo; + (16w0x810, 3w0x4 &&& 3w0x6, 6w0x32 &&& 6w0x33, 5w12 &&& 5w28): foo; + (16w0x810, 3w0x4 &&& 3w0x6, 6w0x32 &&& 6w0x33, 5w16 &&& 5w28): foo; + (16w0x810, 3w0x4 &&& 3w0x6, 6w0x32 &&& 6w0x33, 5w20 &&& 5w31): foo; + default: noMatch; + } + } + state foo { + transition accept; + } + state noMatch { + verify(false, error.NoMatch); + transition reject; + } +} + +control MyVerifyChecksum(inout my_packet hdr, inout my_metadata meta) { + apply { + } +} + +control MyIngress(inout my_packet p, inout my_metadata meta, inout standard_metadata_t s) { + @name(".NoAction") action NoAction_0() { + } + @name("MyIngress.set_data") action set_data() { + } + @name("MyIngress.t") table t_0 { + actions = { + set_data(); + @defaultonly NoAction_0(); + } + key = { + meta.data[0].da: exact @name("meta.data[0].da") ; + } + default_action = NoAction_0(); + } + apply { + t_0.apply(); + } +} + +control MyEgress(inout my_packet p, inout my_metadata m, inout standard_metadata_t s) { + apply { + } +} + +control MyComputeChecksum(inout my_packet p, inout my_metadata m) { + apply { + } +} + +control MyDeparser(packet_out b, in my_packet p) { + apply { + } +} + +V1Switch(MyParser(), MyVerifyChecksum(), MyIngress(), MyEgress(), MyComputeChecksum(), MyDeparser()) main; + diff --git a/testdata/p4_16_samples_outputs/pvs-struct-3-bmv2.p4 b/testdata/p4_16_samples_outputs/pvs-struct-3-bmv2.p4 new file mode 100644 index 00000000000..c70ca3f5ee1 --- /dev/null +++ b/testdata/p4_16_samples_outputs/pvs-struct-3-bmv2.p4 @@ -0,0 +1,79 @@ +#include +#include + +header data_h { + bit<32> da; + bit<32> db; +} + +struct my_packet { + data_h data; +} + +struct my_metadata { + data_h[2] data; +} + +struct value_set_t { + @match(ternary) + bit<16> field1; + @match(lpm) + bit<3> field2; + @match(exact) + bit<6> field3; + @match(range) + bit<5> field4; +} + +parser MyParser(packet_in b, out my_packet p, inout my_metadata m, inout standard_metadata_t s) { + value_set(4) pvs; + state start { + b.extract(p.data); + transition select(p.data.da[15:0], p.data.db[7:5], p.data.db[29:24], p.data.da[30:26]) { + pvs: accept; + (0x810, 0x4 &&& 0x6, 0x32 &&& 0x33, 10 .. 20): foo; + } + } + state foo { + transition accept; + } +} + +control MyVerifyChecksum(inout my_packet hdr, inout my_metadata meta) { + apply { + } +} + +control MyIngress(inout my_packet p, inout my_metadata meta, inout standard_metadata_t s) { + action set_data() { + } + table t { + actions = { + set_data; + } + key = { + meta.data[0].da: exact; + } + } + apply { + t.apply(); + } +} + +control MyEgress(inout my_packet p, inout my_metadata m, inout standard_metadata_t s) { + apply { + } +} + +control MyComputeChecksum(inout my_packet p, inout my_metadata m) { + apply { + } +} + +control MyDeparser(packet_out b, in my_packet p) { + apply { + } +} + +V1Switch(MyParser(), MyVerifyChecksum(), MyIngress(), MyEgress(), MyComputeChecksum(), MyDeparser()) main; + diff --git a/testdata/p4_16_samples_outputs/pvs-struct-3-bmv2.p4-stderr b/testdata/p4_16_samples_outputs/pvs-struct-3-bmv2.p4-stderr new file mode 100644 index 00000000000..e69de29bb2d diff --git a/testdata/p4_16_samples_outputs/pvs-struct-3-bmv2.p4.entries.txt b/testdata/p4_16_samples_outputs/pvs-struct-3-bmv2.p4.entries.txt new file mode 100644 index 00000000000..e69de29bb2d diff --git a/testdata/p4_16_samples_outputs/pvs-struct-3-bmv2.p4.p4info.txt b/testdata/p4_16_samples_outputs/pvs-struct-3-bmv2.p4.p4info.txt new file mode 100644 index 00000000000..ae6dec302dc --- /dev/null +++ b/testdata/p4_16_samples_outputs/pvs-struct-3-bmv2.p4.p4info.txt @@ -0,0 +1,71 @@ +pkg_info { + arch: "v1model" +} +tables { + preamble { + id: 33611905 + name: "MyIngress.t" + alias: "t" + } + match_fields { + id: 1 + name: "meta.data[0].da" + bitwidth: 32 + match_type: EXACT + } + action_refs { + id: 16777606 + } + action_refs { + id: 16800567 + annotations: "@defaultonly" + scope: DEFAULT_ONLY + } + size: 1024 +} +actions { + preamble { + id: 16800567 + name: "NoAction" + alias: "NoAction" + } +} +actions { + preamble { + id: 16777606 + name: "MyIngress.set_data" + alias: "set_data" + } +} +value_sets { + preamble { + id: 50332118 + name: "MyParser.pvs" + alias: "pvs" + } + match { + id: 1 + name: "field1" + bitwidth: 16 + match_type: TERNARY + } + match { + id: 2 + name: "field2" + bitwidth: 3 + match_type: LPM + } + match { + id: 3 + name: "field3" + bitwidth: 6 + match_type: EXACT + } + match { + id: 4 + name: "field4" + bitwidth: 5 + match_type: RANGE + } + size: 4 +} From f4d458d845d84ab5721e88c1f51e637229d94f98 Mon Sep 17 00:00:00 2001 From: Hemant Singh <32817427+hesingh@users.noreply.github.com> Date: Thu, 6 Feb 2020 14:00:46 -0500 Subject: [PATCH 084/106] Add pvs size to bmv2 JSON (#2185) * Add pvs size to bmv2 JSON * Address review comments * Remove and add reference --- backends/bmv2/common/JsonObjects.cpp | 6 ++++-- backends/bmv2/common/JsonObjects.h | 3 ++- backends/bmv2/common/parser.cpp | 4 +++- ir/ir.def | 2 +- 4 files changed, 10 insertions(+), 5 deletions(-) diff --git a/backends/bmv2/common/JsonObjects.cpp b/backends/bmv2/common/JsonObjects.cpp index 0942e85459a..f2165571639 100644 --- a/backends/bmv2/common/JsonObjects.cpp +++ b/backends/bmv2/common/JsonObjects.cpp @@ -385,12 +385,14 @@ JsonObjects::add_parser_transition_key(const unsigned state_id, Util::IJson* new } void -JsonObjects::add_parse_vset(const cstring& name, const unsigned size) { +JsonObjects::add_parse_vset(const cstring& name, const unsigned bitwidth, + const big_int& size) { auto parse_vset = new Util::JsonObject(); unsigned id = BMV2::nextId("parse_vsets"); parse_vset->emplace("name", name); parse_vset->emplace("id", id); - parse_vset->emplace("compressed_bitwidth", size); + parse_vset->emplace("compressed_bitwidth", bitwidth); + parse_vset->emplace("size", size); parse_vsets->append(parse_vset); } diff --git a/backends/bmv2/common/JsonObjects.h b/backends/bmv2/common/JsonObjects.h index f28a5eb7705..9070e8bdda0 100644 --- a/backends/bmv2/common/JsonObjects.h +++ b/backends/bmv2/common/JsonObjects.h @@ -49,7 +49,8 @@ class JsonObjects { void add_parser_transition(const unsigned id, Util::IJson* transition); void add_parser_op(const unsigned id, Util::IJson* op); void add_parser_transition_key(const unsigned id, Util::IJson* key); - void add_parse_vset(const cstring& name, const unsigned size); + void add_parse_vset(const cstring& name, const unsigned bitwidth, + const big_int& size); unsigned add_action(const cstring& name, Util::JsonArray*& params, Util::JsonArray*& body); void add_extern_attribute(const cstring& name, const cstring& type, const cstring& value, Util::JsonArray* attributes); diff --git a/backends/bmv2/common/parser.cpp b/backends/bmv2/common/parser.cpp index 92b3bf6eea2..61b7621292c 100644 --- a/backends/bmv2/common/parser.cpp +++ b/backends/bmv2/common/parser.cpp @@ -449,7 +449,9 @@ bool ParserConverter::preorder(const IR::P4Parser* parser) { auto etype = ctxt->typeMap->getTypeType(inst->elementType, true); auto bitwidth = etype->width_bits(); auto name = inst->controlPlaneName(); - ctxt->json->add_parse_vset(name, bitwidth); + auto size = inst->size; + auto n = size->to()->value; + ctxt->json->add_parse_vset(name, bitwidth, n); } } diff --git a/ir/ir.def b/ir/ir.def index 4fc3887ab11..625998c410e 100644 --- a/ir/ir.def +++ b/ir/ir.def @@ -344,7 +344,7 @@ class P4Table : Declaration, IAnnotated, IApply { class P4ValueSet : Declaration, IAnnotated { optional Annotations annotations = Annotations::empty; Type elementType; - Expression size; + Expression size; // number of elements in set. Annotations getAnnotations() const override { return annotations; } } From 7586c001360c8deebfc384a55ad6e08e51344ff6 Mon Sep 17 00:00:00 2001 From: hesingh Date: Thu, 30 Jan 2020 11:22:24 -0800 Subject: [PATCH 085/106] Fix to Issue 1690 --- control-plane/CMakeLists.txt | 10 ++++++++-- control-plane/p4RuntimeArchStandard.cpp | 7 ++++--- control-plane/p4RuntimeSerializer.cpp | 26 ++++++++++++++----------- control-plane/typeSpecConverter.cpp | 3 ++- 4 files changed, 29 insertions(+), 17 deletions(-) diff --git a/control-plane/CMakeLists.txt b/control-plane/CMakeLists.txt index 16f1e467b79..49040cafc0a 100644 --- a/control-plane/CMakeLists.txt +++ b/control-plane/CMakeLists.txt @@ -83,19 +83,25 @@ set (CONTROLPLANE_SOURCES ${CONTROLPLANE_SRCS} ) -set (CONTROLPLANE_HDRS +set (CONTROLPLANE_SRCS bytestrings.h flattenHeader.h p4RuntimeArchHandler.h p4RuntimeArchStandard.h p4RuntimeSerializer.h typeSpecConverter.h + bytestrings.cpp + flattenHeader.cpp + p4RuntimeArchHandler.cpp + p4RuntimeArchStandard.cpp + p4RuntimeSerializer.cpp + typeSpecConverter.cpp ) # exclude p4RuntimeSerializer.cpp because it is has issues with # include order. It would be nice to implement region-based NOLINT to # handle this case. -add_cpplint_files (${CMAKE_CURRENT_SOURCE_DIR} "${CONTROLPLANE_HDRS}") +add_cpplint_files (${CMAKE_CURRENT_SOURCE_DIR} "${CONTROLPLANE_SRCS}") include_directories (${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR}) set_source_files_properties (${CONTROLPLANE_SOURCES} PROPERTIES COMPILE_FLAGS "-Wno-unused-parameter") diff --git a/control-plane/p4RuntimeArchStandard.cpp b/control-plane/p4RuntimeArchStandard.cpp index 145d2194292..3a9d27858a4 100644 --- a/control-plane/p4RuntimeArchStandard.cpp +++ b/control-plane/p4RuntimeArchStandard.cpp @@ -14,11 +14,11 @@ See the License for the specific language governing permissions and limitations under the License. */ +#include + #include #include -#include - #include "frontends/common/resolveReferences/referenceMap.h" #include "frontends/p4/fromv1.0/v1model.h" #include "frontends/p4/typeMap.h" @@ -869,7 +869,8 @@ class P4RuntimeArchHandlerV1Model final : public P4RuntimeArchHandlerCommon +#include +#include +#include +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-parameter" +#include + #include #include #include @@ -22,13 +30,6 @@ limitations under the License. #include #include -#include -#include -#include -#include -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wunused-parameter" -#include #include "p4/config/v1/p4info.pb.h" #include "p4/config/v1/p4types.pb.h" #include "p4/v1/p4runtime.pb.h" @@ -746,7 +747,7 @@ forEachPreamble(It first, It last, Fn fn) { for (It it = first; it != last; it++) fn(it->preamble()); } -} // namespace +} // namespace /// An analyzer which translates the information available in the P4 IR into a /// representation of the control plane API which is consumed by P4Runtime. @@ -1002,7 +1003,8 @@ class P4RuntimeAnalyzer { } if (isTableOnly) action_ref->set_scope(p4configv1::ActionRef::TABLE_ONLY); else if (isDefaultOnly) action_ref->set_scope(p4configv1::ActionRef::DEFAULT_ONLY); - else action_ref->set_scope(p4configv1::ActionRef::TABLE_AND_DEFAULT); + else + action_ref->set_scope(p4configv1::ActionRef::TABLE_AND_DEFAULT); } size_t index = 1; @@ -1333,7 +1335,7 @@ class P4RuntimeEntriesConverter { private: friend class P4RuntimeAnalyzer; - P4RuntimeEntriesConverter(const P4RuntimeSymbolTable& symbols) + explicit P4RuntimeEntriesConverter(const P4RuntimeSymbolTable& symbols) : entries(new p4v1::WriteRequest), symbols(symbols) { } /// @return the P4Runtime WriteRequest message generated by this analyzer. @@ -1688,7 +1690,9 @@ P4RuntimeAnalyzer::analyze(const IR::P4Program* program, auto symbols = P4RuntimeSymbolTable::create([=](P4RuntimeSymbolTable& symbols) { Helpers::forAllEvaluatedBlocks(evaluatedProgram, [&](const IR::Block* block) { if (block->is()) { - collectControlSymbols(symbols, archHandler, block->to(), refMap, typeMap); + collectControlSymbols(symbols, archHandler, + block->to(), + refMap, typeMap); } else if (block->is()) { collectExternSymbols(symbols, archHandler, block->to()); } else if (block->is()) { diff --git a/control-plane/typeSpecConverter.cpp b/control-plane/typeSpecConverter.cpp index e482bcfdd33..db7551bbb5a 100644 --- a/control-plane/typeSpecConverter.cpp +++ b/control-plane/typeSpecConverter.cpp @@ -58,7 +58,8 @@ bool TypeSpecConverter::preorder(const IR::Type_Bits* type) { auto bitTypeSpec = typeSpec->mutable_bitstring(); auto bw = type->width_bits(); if (type->isSigned) bitTypeSpec->mutable_int_()->set_bitwidth(bw); - else bitTypeSpec->mutable_bit()->set_bitwidth(bw); + else + bitTypeSpec->mutable_bit()->set_bitwidth(bw); map.emplace(type, typeSpec); return false; } From 8c9287dda43f0f7c86b679d8d137b3104ef1f540 Mon Sep 17 00:00:00 2001 From: hesingh Date: Thu, 30 Jan 2020 12:12:07 -0800 Subject: [PATCH 086/106] Change CMakeLists.txt --- control-plane/CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/control-plane/CMakeLists.txt b/control-plane/CMakeLists.txt index 49040cafc0a..df6b523e4be 100644 --- a/control-plane/CMakeLists.txt +++ b/control-plane/CMakeLists.txt @@ -83,7 +83,7 @@ set (CONTROLPLANE_SOURCES ${CONTROLPLANE_SRCS} ) -set (CONTROLPLANE_SRCS +set (CPPLINT_SRCS bytestrings.h flattenHeader.h p4RuntimeArchHandler.h @@ -101,7 +101,7 @@ set (CONTROLPLANE_SRCS # exclude p4RuntimeSerializer.cpp because it is has issues with # include order. It would be nice to implement region-based NOLINT to # handle this case. -add_cpplint_files (${CMAKE_CURRENT_SOURCE_DIR} "${CONTROLPLANE_SRCS}") +add_cpplint_files (${CMAKE_CURRENT_SOURCE_DIR} "${CPPLINT_SRCS}") include_directories (${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR}) set_source_files_properties (${CONTROLPLANE_SOURCES} PROPERTIES COMPILE_FLAGS "-Wno-unused-parameter") From ca7f45e7abda904474d28048997e422afb4a0bf2 Mon Sep 17 00:00:00 2001 From: hesingh Date: Thu, 30 Jan 2020 12:57:13 -0800 Subject: [PATCH 087/106] Remove comment from CMakeLists.txt --- control-plane/CMakeLists.txt | 3 --- 1 file changed, 3 deletions(-) diff --git a/control-plane/CMakeLists.txt b/control-plane/CMakeLists.txt index df6b523e4be..da63fe76d70 100644 --- a/control-plane/CMakeLists.txt +++ b/control-plane/CMakeLists.txt @@ -98,9 +98,6 @@ set (CPPLINT_SRCS typeSpecConverter.cpp ) -# exclude p4RuntimeSerializer.cpp because it is has issues with -# include order. It would be nice to implement region-based NOLINT to -# handle this case. add_cpplint_files (${CMAKE_CURRENT_SOURCE_DIR} "${CPPLINT_SRCS}") include_directories (${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR}) From 3b9775b1c1c4a0af9f57fcf8cc5d6707ccc96718 Mon Sep 17 00:00:00 2001 From: hesingh Date: Thu, 30 Jan 2020 13:30:53 -0800 Subject: [PATCH 088/106] Restore naming convention in CMakeLists.txt --- control-plane/CMakeLists.txt | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/control-plane/CMakeLists.txt b/control-plane/CMakeLists.txt index da63fe76d70..537422ec047 100644 --- a/control-plane/CMakeLists.txt +++ b/control-plane/CMakeLists.txt @@ -83,22 +83,16 @@ set (CONTROLPLANE_SOURCES ${CONTROLPLANE_SRCS} ) -set (CPPLINT_SRCS +set (CONTROLPLANE_HDRS bytestrings.h flattenHeader.h p4RuntimeArchHandler.h p4RuntimeArchStandard.h p4RuntimeSerializer.h typeSpecConverter.h - bytestrings.cpp - flattenHeader.cpp - p4RuntimeArchHandler.cpp - p4RuntimeArchStandard.cpp - p4RuntimeSerializer.cpp - typeSpecConverter.cpp ) -add_cpplint_files (${CMAKE_CURRENT_SOURCE_DIR} "${CPPLINT_SRCS}") +add_cpplint_files (${CMAKE_CURRENT_SOURCE_DIR} "${CONTROLPLANE_HDRS};${CONTROLPLANE_SRCS}") include_directories (${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR}) set_source_files_properties (${CONTROLPLANE_SOURCES} PROPERTIES COMPILE_FLAGS "-Wno-unused-parameter") From c71bd1f63b1674b6d87ba667a605f237f32bf79d Mon Sep 17 00:00:00 2001 From: Jed Liu Date: Thu, 6 Feb 2020 16:57:07 -0800 Subject: [PATCH 089/106] Constified some function parameters. (#2191) --- lib/ordered_set.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/ordered_set.h b/lib/ordered_set.h index 41f856c6579..76cf65ec445 100644 --- a/lib/ordered_set.h +++ b/lib/ordered_set.h @@ -238,11 +238,11 @@ auto operator&=(ordered_set &a, U &b) -> decltype(b.begin(), a) { return a; } template inline -auto contains(ordered_set &a, U &b) -> decltype(b.begin(), true) { +auto contains(const ordered_set &a, const U &b) -> decltype(b.begin(), true) { for (auto &el : b) if (!a.count(el)) return false; return true; } template inline -auto intersects(ordered_set &a, U &b) -> decltype(b.begin(), true) { +auto intersects(const ordered_set &a, const U &b) -> decltype(b.begin(), true) { for (auto &el : b) if (a.count(el)) return true; return false; } From c67f236eeb62a76e40414921e7eab1d1f6fe98bc Mon Sep 17 00:00:00 2001 From: Hemant Singh <32817427+hesingh@users.noreply.github.com> Date: Mon, 10 Feb 2020 12:42:16 -0500 Subject: [PATCH 090/106] Change JSON size to max_size (#2195) --- backends/bmv2/common/JsonObjects.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backends/bmv2/common/JsonObjects.cpp b/backends/bmv2/common/JsonObjects.cpp index f2165571639..4f80fce0003 100644 --- a/backends/bmv2/common/JsonObjects.cpp +++ b/backends/bmv2/common/JsonObjects.cpp @@ -392,7 +392,7 @@ JsonObjects::add_parse_vset(const cstring& name, const unsigned bitwidth, parse_vset->emplace("name", name); parse_vset->emplace("id", id); parse_vset->emplace("compressed_bitwidth", bitwidth); - parse_vset->emplace("size", size); + parse_vset->emplace("max_size", size); parse_vsets->append(parse_vset); } From 62fd40a0097b361c266ede5116ac0060d1b27406 Mon Sep 17 00:00:00 2001 From: Mihai Budiu Date: Thu, 13 Feb 2020 13:22:46 -0800 Subject: [PATCH 091/106] Remove format prefix from ::error; fixes #2197 (#2200) * Remove format prefix from ::error; fixes #2197 --- README.md | 12 +-- backends/bmv2/common/action.cpp | 5 +- backends/bmv2/common/control.cpp | 83 ++++++++++--------- backends/bmv2/common/controlFlowGraph.cpp | 2 +- backends/bmv2/common/deparser.cpp | 3 +- backends/bmv2/common/expression.cpp | 19 +++-- backends/bmv2/common/extern.cpp | 4 +- backends/bmv2/common/header.cpp | 8 +- backends/bmv2/common/lower.cpp | 2 +- backends/bmv2/common/metermap.cpp | 2 +- backends/bmv2/common/parser.cpp | 11 ++- .../bmv2/common/sharedActionSelectorCheck.cpp | 7 +- backends/bmv2/psa_switch/psaSwitch.cpp | 15 ++-- backends/bmv2/simple_switch/simpleSwitch.cpp | 7 +- backends/ebpf/codeGen.h | 2 +- backends/ebpf/ebpfTable.cpp | 14 ++-- control-plane/p4RuntimeSerializer.cpp | 11 +-- docs/CodingStandardPhilosophy.md | 5 +- frontends/common/constantFolding.cpp | 24 +++--- frontends/common/constantParsing.cpp | 2 +- frontends/common/parseInput.h | 5 +- .../resolveReferences/resolveReferences.cpp | 4 +- frontends/p4/actionsInlining.cpp | 3 +- frontends/p4/checkConstants.cpp | 2 +- frontends/p4/checkNamedArgs.cpp | 2 +- frontends/p4/fromv1.0/converters.h | 25 +++--- frontends/p4/fromv1.0/programStructure.cpp | 4 +- frontends/p4/validateParsedProgram.cpp | 48 ++++++----- ir/base.cpp | 4 +- ir/ir.cpp | 4 +- ir/ir.def | 8 +- ir/type.cpp | 4 +- ir/type.def | 14 +++- lib/error_catalog.cpp | 73 ++++++++-------- lib/error_catalog.h | 29 ++----- lib/error_reporter.h | 18 +--- midend/compileTimeOps.h | 2 +- midend/predication.h | 2 +- midend/replaceSelectRange.cpp | 12 +-- .../array_index.p4-stderr | 2 +- .../p4_14_errors_outputs/issue1092.p4-stderr | 2 +- .../p4_14_errors_outputs/issue1093.p4-stderr | 2 +- .../p4_14_errors_outputs/issue1238.p4-stderr | 2 +- .../p4_14_errors_outputs/issue1499.p4-stderr | 2 +- .../p4_14_errors_outputs/issue1745.p4-stderr | 2 +- .../p4_14_errors_outputs/issue187.p4-stderr | 2 +- .../p4_14_errors_outputs/issue747.p4-stderr | 2 +- .../p4_14_errors_outputs/issue763-1.p4-stderr | 4 +- .../p4_14_errors_outputs/issue763-2.p4-stderr | 4 +- .../p4_14_errors_outputs/issue763.p4-stderr | 2 +- .../issue780-10.p4-stderr | 4 +- .../p4_14_errors_outputs/issue780-4.p4-stderr | 4 +- .../p4_14_errors_outputs/issue780-6.p4-stderr | 4 +- .../p4_14_errors_outputs/issue905.p4-stderr | 2 +- .../p4_14_errors_outputs/nasty_meta.p4-stderr | 4 +- .../unknown-state.p4-stderr | 2 +- .../p4_14_samples_outputs/issue1873.p4-stderr | 2 +- .../p4_16_errors_outputs/accept_e.p4-stderr | 2 +- .../constructor1_e.p4-stderr | 2 +- .../constructor2_e.p4-stderr | 2 +- .../constructor_e.p4-stderr | 2 +- testdata/p4_16_errors_outputs/div3.p4-stderr | 2 +- .../expression_e.p4-stderr | 2 +- .../globalVar_e.p4-stderr | 2 +- .../p4_16_errors_outputs/header1_e.p4-stderr | 2 +- .../issue-2123_e.p4-stderr | 20 +---- .../p4_16_errors_outputs/issue1202.p4-stderr | 2 +- .../p4_16_errors_outputs/issue1336.p4-stderr | 2 +- .../issue1777-bmv2.p4-stderr | 2 +- .../issue1932-1.p4-stderr | 2 +- .../p4_16_errors_outputs/issue1944.p4-stderr | 2 +- .../issue1986-1.p4-stderr | 4 +- .../p4_16_errors_outputs/issue1986.p4-stderr | 4 +- .../p4_16_errors_outputs/issue435.p4-stderr | 2 +- .../p4_16_errors_outputs/issue513.p4-stderr | 2 +- .../missing_actions.p4-stderr | 2 +- .../missing_match.p4-stderr | 2 +- .../p4_16_errors_outputs/named-fail.p4-stderr | 2 +- testdata/p4_16_errors_outputs/p_e.p4-stderr | 2 +- .../p4_16_errors_outputs/package.p4-stderr | 2 +- .../push_nonconstant.p4-stderr | 2 +- .../p4_16_errors_outputs/shift_e.p4-stderr | 2 +- .../spec-ex32_e.p4-stderr | 2 +- .../table-entries-exact-ternary.p4-stderr | 2 +- .../table-entries-outside-table.p4-stderr | 2 +- .../table-entries-ternary.p4-stderr | 2 +- .../p4_16_errors_outputs/template_e.p4-stderr | 2 +- .../p4_16_errors_outputs/tuple-left.p4-stderr | 2 +- .../type-params_e.p4-stderr | 2 +- .../underscore1_e.p4-stderr | 2 +- .../underscore2_e.p4-stderr | 2 +- .../underscore3_e.p4-stderr | 2 +- .../underscore_e.p4-stderr | 2 +- .../p4_16_errors_outputs/width_e.p4-stderr | 2 +- 94 files changed, 322 insertions(+), 323 deletions(-) diff --git a/README.md b/README.md index 30369b2caf5..f3d2ea21b3b 100644 --- a/README.md +++ b/README.md @@ -438,11 +438,11 @@ install (FILES ${CMAKE_CURRENT_SOURCE_DIR}/driver/p4c.mybackend.cfg # Known issues -The P4C compiler is in early development. Issues with the compiler are -tracked on [GitHub](https://github.com/p4lang/p4c/issues). Before -opening a new issue, please check whether a similar issue is already -opened. Opening issues and submitting a pull request with fixes for -those issues is much appreciated. +Issues with the compiler are tracked on +[GitHub](https://github.com/p4lang/p4c/issues). Before opening a new +issue, please check whether a similar issue is already opened. Opening +issues and submitting a pull request with fixes for those issues is +much appreciated. In addition to the list of issues on Github, there are a number of currently unsupported features listed below: @@ -457,7 +457,7 @@ access them from the IR * Nonstandard extension primitives from P4_14 * Execute_meter extra arguments - * Recirculate variants + * Recirculate/clone/resubmit variants * Bypass_egress * Sample_ primitives * invalidate diff --git a/backends/bmv2/common/action.cpp b/backends/bmv2/common/action.cpp index 0caa92fa573..5e2252abf69 100644 --- a/backends/bmv2/common/action.cpp +++ b/backends/bmv2/common/action.cpp @@ -134,7 +134,8 @@ void ActionConverter::convertActionBody(const IR::Vector* body, continue; } } - ::error(ErrorType::ERR_UNSUPPORTED, "%1% not yet supported on this target", s); + ::error(ErrorType::ERR_UNSUPPORTED, + "%1% not yet supported on this target", s); } } @@ -150,7 +151,7 @@ ActionConverter::convertActionParams(const IR::ParameterList *parameters, auto type = ctxt->typeMap->getType(p, true); if (!type->is()) ::error(ErrorType::ERR_INVALID, - "action parameters must be bit<> or int<> on this target", p); + "%1%: action parameters must be bit<> or int<> on this target", p); param->emplace("bitwidth", type->width_bits()); params->append(param); } diff --git a/backends/bmv2/common/control.cpp b/backends/bmv2/common/control.cpp index af39d96793e..9031de865cc 100644 --- a/backends/bmv2/common/control.cpp +++ b/backends/bmv2/common/control.cpp @@ -57,7 +57,7 @@ void ControlConverter::convertTableEntries(const IR::P4Table *table, // booleans are converted to ints key->emplace("key", stringRepr(k->to()->value ? 1 : 0, k8)); else - ::error(ErrorType::ERR_UNSUPPORTED, "exact key expression", k); + ::error(ErrorType::ERR_UNSUPPORTED, "%1%: unsupported exact key expression", k); } else if (matchType == corelib.ternaryMatch.name) { if (k->is()) { auto km = k->to(); @@ -70,7 +70,8 @@ void ControlConverter::convertTableEntries(const IR::P4Table *table, key->emplace("key", stringRepr(0, k8)); key->emplace("mask", stringRepr(0, k8)); } else { - ::error(ErrorType::ERR_UNSUPPORTED, "ternary key expression", k); + ::error(ErrorType::ERR_UNSUPPORTED, + "%1%: unsupported ternary key expression", k); } } else if (matchType == corelib.lpmMatch.name) { if (k->is()) { @@ -81,7 +82,7 @@ void ControlConverter::convertTableEntries(const IR::P4Table *table, auto mask = static_cast(km->right->to()->value); auto len = trailing_zeros(mask); if (len + count_ones(mask) != keyWidth) // any remaining 0s in the prefix? - ::error(ErrorType::ERR_INVALID, "mask for LPM key", k); + ::error(ErrorType::ERR_INVALID, "%1%: invalid mask for LPM key", k); else key->emplace("prefix_length", keyWidth - len); } else if (k->is()) { @@ -91,7 +92,7 @@ void ControlConverter::convertTableEntries(const IR::P4Table *table, key->emplace("key", stringRepr(0, k8)); key->emplace("prefix_length", 0); } else { - ::error(ErrorType::ERR_UNSUPPORTED, "LPM key expression", k); + ::error(ErrorType::ERR_UNSUPPORTED, "%1%: unsupported LPM key expression", k); } } else if (matchType == "range") { if (k->is()) { @@ -105,7 +106,7 @@ void ControlConverter::convertTableEntries(const IR::P4Table *table, key->emplace("start", stringRepr(0, k8)); key->emplace("end", stringRepr((1 << keyWidth)-1, k8)); // 2^N -1 } else { - ::error(ErrorType::ERR_UNSUPPORTED, "range key expression", k); + ::error(ErrorType::ERR_UNSUPPORTED, "%1% unsupported range key expression", k); } } else if (matchType == "optional") { // Table key fields with match_kind optional with @@ -122,10 +123,12 @@ void ControlConverter::convertTableEntries(const IR::P4Table *table, key->emplace("key", stringRepr(0, k8)); key->emplace("mask", stringRepr(0, k8)); } else { - ::error(ErrorType::ERR_UNSUPPORTED, "optional key expression", k); + ::error(ErrorType::ERR_UNSUPPORTED, + "%1%: unsupported optional key expression", k); } } else { - ::error(ErrorType::ERR_UNKNOWN, "key match type '%2%' for key %1%", k, matchType); + ::error(ErrorType::ERR_UNKNOWN, + "unknown key match type '%2%' for key %1%", k, matchType); } matchKeys->append(key); keyIndex++; @@ -134,7 +137,7 @@ void ControlConverter::convertTableEntries(const IR::P4Table *table, auto action = new Util::JsonObject(); auto actionRef = e->getAction(); if (!actionRef->is()) - ::error(ErrorType::ERR_INVALID, "Invalid action %1% in entries list.", actionRef); + ::error(ErrorType::ERR_INVALID, "Invalid action '%1%' in entries list.", actionRef); auto actionCall = actionRef->to(); auto method = actionCall->method->to()->path; auto decl = ctxt->refMap->getDeclaration(method, true); @@ -156,7 +159,7 @@ void ControlConverter::convertTableEntries(const IR::P4Table *table, priorityAnnotation->expr); auto priValue = priorityAnnotation->expr.front(); if (!priValue->is()) - ::error(ErrorType::ERR_INVALID, "Invalid priority value %1%. Must be constant.", + ::error(ErrorType::ERR_INVALID, "Invalid priority value %1%; must be constant.", priorityAnnotation->expr); entry->emplace("priority", priValue->to()->value); } else { @@ -187,7 +190,7 @@ cstring ControlConverter::getKeyMatchType(const IR::KeyElement *ke) { return mt->name.name; } - ::error(ErrorType::ERR_UNSUPPORTED, "match type not supported on this target", mt); + ::error(ErrorType::ERR_UNSUPPORTED, "%1%: match type not supported on this target", mt); return "invalid"; } @@ -203,7 +206,7 @@ ControlConverter::handleTableImplementation(const IR::Property* implementation, } if (!implementation->value->is()) { - ::error(ErrorType::ERR_EXPECTED, "expected expression for property", implementation); + ::error(ErrorType::ERR_EXPECTED, "%1%: expected expression for property", implementation); return false; } auto propv = implementation->value->to(); @@ -217,7 +220,8 @@ ControlConverter::handleTableImplementation(const IR::Property* implementation, propv->expression->to(), ctxt->refMap, ctxt->typeMap); if (!cc->is()) { - ::error(ErrorType::ERR_EXPECTED, "extern object for property", implementation); + ::error(ErrorType::ERR_EXPECTED, + "%1%: expected extern object for property", implementation); return false; } auto ecc = cc->to(); @@ -253,7 +257,8 @@ ControlConverter::handleTableImplementation(const IR::Property* implementation, auto hash = arguments->at(0)->expression; auto ei = P4::EnumInstance::resolve(hash, ctxt->typeMap); if (ei == nullptr) { - ::error(ErrorType::ERR_EXPECTED, "hash must be a constant on this target", hash); + ::error(ErrorType::ERR_EXPECTED, + "%1%: hash must be a constant on this target", hash); } else { cstring algo = ei->name; selector->emplace("algo", algo); @@ -275,19 +280,19 @@ ControlConverter::handleTableImplementation(const IR::Property* implementation, table->emplace("type", "indirect"); add_size(0); } else { - ::error(ErrorType::ERR_UNEXPECTED, "value for property", propv); + ::error(ErrorType::ERR_UNEXPECTED, "%1%: expected value for property", propv); } } else if (propv->expression->is()) { auto pathe = propv->expression->to(); auto decl = ctxt->refMap->getDeclaration(pathe->path, true); if (!decl->is()) { - ::error(ErrorType::ERR_EXPECTED, "a reference to an instance", pathe); + ::error(ErrorType::ERR_EXPECTED, "%1%: expected a reference to an instance", pathe); return false; } apname = decl->controlPlaneName(); auto dcltype = ctxt->typeMap->getType(pathe, true); if (!dcltype->is()) { - ::error(ErrorType::ERR_UNEXPECTED, "type for implementation", dcltype); + ::error(ErrorType::ERR_UNEXPECTED, "%1%: unexpected type for implementation", dcltype); return false; } auto type_extern_name = dcltype->to()->name; @@ -296,7 +301,7 @@ ControlConverter::handleTableImplementation(const IR::Property* implementation, } else if (type_extern_name == BMV2::TableImplementation::actionSelectorName) { table->emplace("type", "indirect_ws"); } else { - ::error(ErrorType::ERR_UNEXPECTED, "type for implementation", dcltype); + ::error(ErrorType::ERR_UNEXPECTED, "%1%: unexpected type for implementation", dcltype); return false; } isSimpleTable = false; @@ -307,7 +312,7 @@ ControlConverter::handleTableImplementation(const IR::Property* implementation, eb->to(), emitExterns); } } else { - ::error(ErrorType::ERR_UNEXPECTED, "value for property", propv); + ::error(ErrorType::ERR_UNEXPECTED, "%1%: unexpected value for property", propv); return false; } table->emplace("action_profile", apname); @@ -358,7 +363,8 @@ ControlConverter::convertTable(const CFG::TableNode* node, table_match_type == corelib.exactMatch.name) table_match_type = corelib.lpmMatch.name; } else if (match_type == corelib.lpmMatch.name) { - ::error(ErrorType::ERR_UNSUPPORTED, "multiple LPM keys in table %1%", table); + ::error(ErrorType::ERR_UNSUPPORTED, + "multiple LPM keys in table %1% not supported", table); } big_int mask; @@ -370,7 +376,7 @@ ControlConverter::convertTable(const CFG::TableNode* node, mask = mexp->left->to()->value; expr = mexp->right; } else { - ::error(ErrorType::ERR_EXPECTED, "must be a constant", expr); } + ::error(ErrorType::ERR_EXPECTED, "%1% must be a constant", expr); } } else if (auto slice = expr->to()) { expr = slice->e0; int h = slice->getH(); @@ -417,13 +423,13 @@ ControlConverter::convertTable(const CFG::TableNode* node, if (sz->value->is()) { auto expr = sz->value->to()->expression; if (!expr->is()) { - ::error(ErrorType::ERR_EXPECTED, "must be a constant", sz); + ::error(ErrorType::ERR_EXPECTED, "%1% must be a constant", sz); size = 0; } else { size = expr->to()->asInt(); } } else { - ::error(ErrorType::ERR_EXPECTED, "a number", sz); + ::error(ErrorType::ERR_EXPECTED, "%1%: expected a number", sz); } } if (size == 0) @@ -442,13 +448,13 @@ ControlConverter::convertTable(const CFG::TableNode* node, if (type == nullptr) return result; if (!type->is()) { - ::error(ErrorType::ERR_UNEXPECTED, "Unexpected type %2% for property. " + ::error(ErrorType::ERR_UNEXPECTED, "%1%: Unexpected type %2% for property. " "Must be extern.", ctrs, type); return result; } auto te = type->to(); if (te->name != "direct_counter" && te->name != "counter") { - ::error(ErrorType::ERR_UNEXPECTED, "Unexpected type %2% for property. " + ::error(ErrorType::ERR_UNEXPECTED, "%1%: Unexpected type %2% for property. " "Must be 'counter' or 'direct_counter'.", ctrs, type); return result; } @@ -467,7 +473,7 @@ ControlConverter::convertTable(const CFG::TableNode* node, auto pe = expr->to(); auto decl = ctxt->refMap->getDeclaration(pe->path, true); if (!decl->is()) { - ::error(ErrorType::ERR_EXPECTED, "an instance", decl->getNode()); + ::error(ErrorType::ERR_EXPECTED, "%1%: expected an instance", decl->getNode()); return result; } cstring ctrname = decl->controlPlaneName(); @@ -475,13 +481,14 @@ ControlConverter::convertTable(const CFG::TableNode* node, LOG3("Looking up " << ctrname); if (it != ctxt->structure->directCounterMap.end()) { ::error(ErrorType::ERR_INVALID, - "Direct counters cannot be attached to multiple tables %2% and %3%", + "%1%: Direct counters cannot be attached to multiple tables" + " %2% and %3%", decl, it->second, table); return result; } ctxt->structure->directCounterMap.emplace(ctrname, table); } else { - ::error(ErrorType::ERR_EXPECTED, "a counter", ctrs); + ::error(ErrorType::ERR_EXPECTED, "%1%: expected a counter", ctrs); } } result->emplace("with_counters", true); @@ -495,12 +502,12 @@ ControlConverter::convertTable(const CFG::TableNode* node, if (timeout->value->is()) { auto expr = timeout->value->to()->expression; if (!expr->is()) { - ::error(ErrorType::ERR_EXPECTED, "must true/false", timeout); + ::error(ErrorType::ERR_EXPECTED, "%1%: must true/false", timeout); } else { sup_to = expr->to()->value; } } else { - ::error(ErrorType::ERR_EXPECTED, "a Boolean", timeout); + ::error(ErrorType::ERR_EXPECTED, "%1%: expected a Boolean", timeout); } } result->emplace("support_timeout", sup_to); @@ -510,7 +517,8 @@ ControlConverter::convertTable(const CFG::TableNode* node, if (dm->value->is()) { auto expr = dm->value->to()->expression; if (!expr->is()) { - ::error(ErrorType::ERR_EXPECTED, "a reference to a meter declaration", expr); + ::error(ErrorType::ERR_EXPECTED, + "%1%: expected a reference to a meter declaration", expr); } else { auto pe = expr->to(); auto decl = ctxt->refMap->getDeclaration(pe->path, true); @@ -520,18 +528,18 @@ ControlConverter::convertTable(const CFG::TableNode* node, if (type->is()) type = type->to()->baseType; if (!type->is()) { - ::error(ErrorType::ERR_UNEXPECTED, "Unexpected type %2% for property", + ::error(ErrorType::ERR_UNEXPECTED, "%1%: Unexpected type %2% for property", dm, type); return result; } auto te = type->to(); if (te->name != "direct_meter") { - ::error(ErrorType::ERR_UNEXPECTED, "Unexpected type %2% for property", + ::error(ErrorType::ERR_UNEXPECTED, "%1%: Unexpected type %2% for property", dm, type); return result; } if (!decl->is()) { - ::error(ErrorType::ERR_EXPECTED, "an instance", decl->getNode()); + ::error(ErrorType::ERR_EXPECTED, "%1%: expected an instance", decl->getNode()); return result; } ctxt->structure->directMeterMap.setTable(decl, table); @@ -542,7 +550,7 @@ ControlConverter::convertTable(const CFG::TableNode* node, result->emplace("direct_meters", name); } } else { - ::error(ErrorType::ERR_EXPECTED, "a meter", dm); + ::error(ErrorType::ERR_EXPECTED, "%1%: expected a meter", dm); } } else { result->emplace("direct_meters", Util::JsonValue::null); @@ -566,7 +574,8 @@ ControlConverter::convertTable(const CFG::TableNode* node, if (a->expression->is()) { auto mce = a->expression->to(); if (mce->arguments->size() > 0) - ::error(ErrorType::ERR_UNSUPPORTED, "actions in action list with arguments", a); + ::error(ErrorType::ERR_UNSUPPORTED, + "%1%: actions in action list with arguments not supported", a); } auto decl = ctxt->refMap->getDeclaration(a->getPath(), true); BUG_CHECK(decl->is(), "%1%: should be an action name", a); @@ -647,7 +656,7 @@ ControlConverter::convertTable(const CFG::TableNode* node, } if (!defact->value->is()) { - ::error(ErrorType::ERR_EXPECTED, "an action", defact); + ::error(ErrorType::ERR_EXPECTED, "%1%: expected an action", defact); return result; } auto expr = defact->value->to()->expression; @@ -686,7 +695,7 @@ ControlConverter::convertTable(const CFG::TableNode* node, fields->append(repr); } else { ::error(ErrorType::ERR_EXPECTED, - "argument must evaluate to a constant integer", a); + "%1%: argument must evaluate to a constant integer", a); return result; } } diff --git a/backends/bmv2/common/controlFlowGraph.cpp b/backends/bmv2/common/controlFlowGraph.cpp index 9fb3278ba7f..56d57d79bb6 100644 --- a/backends/bmv2/common/controlFlowGraph.cpp +++ b/backends/bmv2/common/controlFlowGraph.cpp @@ -209,7 +209,7 @@ class CFGBuilder : public Inspector { return false; auto am = instance->to(); if (!am->object->is()) { - ::error(ErrorType::ERR_INVALID, "apply method must be on a table", statement); + ::error(ErrorType::ERR_INVALID, "%1%: apply method must be on a table", statement); return false; } auto tc = am->object->to(); diff --git a/backends/bmv2/common/deparser.cpp b/backends/bmv2/common/deparser.cpp index 3d60e6a6bb8..8b37e83004b 100644 --- a/backends/bmv2/common/deparser.cpp +++ b/backends/bmv2/common/deparser.cpp @@ -68,7 +68,8 @@ void DeparserConverter::convertDeparserBody(const IR::Vector* bo continue; } } - ::error(ErrorType::ERR_UNSUPPORTED, "within a deparser on this target", s); + ::error(ErrorType::ERR_UNSUPPORTED, + "%1%: not supported within a deparser on this target", s); } ctxt->conv->simpleExpressionsOnly = false; } diff --git a/backends/bmv2/common/expression.cpp b/backends/bmv2/common/expression.cpp index 181a1484acd..5c1b8b9c9c8 100644 --- a/backends/bmv2/common/expression.cpp +++ b/backends/bmv2/common/expression.cpp @@ -356,7 +356,7 @@ void ExpressionConverter::postorder(const IR::Member* expression) { auto mem = expression->expr->to(); auto memtype = typeMap->getType(mem->expr, true); if (memtype->is() && mem->member == IR::Type_Stack::next) - ::error(ErrorType::ERR_UNINITIALIZED, "next field read", mem); + ::error(ErrorType::ERR_UNINITIALIZED, "%1% uninitialized: next field read", mem); // array.last.field => type: "stack_field", value: [ array, field ] if (memtype->is() && mem->member == IR::Type_Stack::last) { auto l = get(mem->expr); @@ -431,7 +431,7 @@ void ExpressionConverter::postorder(const IR::Member* expression) { } else if (auto jo = l->to()) { if (st) { if (index_pos < 0) { - ::error(ErrorType::ERR_INVALID, "Bmv2: Struct has no field " + ::error(ErrorType::ERR_INVALID, "BMV2: Struct has no field " "for runtime index computation %1%", st); } result->emplace("type", "expression"); @@ -481,7 +481,8 @@ void ExpressionConverter::postorder(const IR::Mux* expression) { auto result = new Util::JsonObject(); mapExpression(expression, result); if (simpleExpressionsOnly) { - ::error(ErrorType::ERR_UNSUPPORTED_ON_TARGET, "expression too complex", expression); + ::error(ErrorType::ERR_UNSUPPORTED_ON_TARGET, + "%1%: expression too complex for this target", expression); return; } @@ -521,7 +522,8 @@ void ExpressionConverter::binary(const IR::Operation_Binary* expression) { auto result = new Util::JsonObject(); mapExpression(expression, result); if (simpleExpressionsOnly) { - ::error(ErrorType::ERR_UNSUPPORTED_ON_TARGET, "expression too complex", expression); + ::error(ErrorType::ERR_UNSUPPORTED_ON_TARGET, + "%1%: expression too complex for this target", expression); return; } @@ -576,7 +578,8 @@ void ExpressionConverter::postorder(const IR::ListExpression* expression) { auto result = new Util::JsonArray(); mapExpression(expression, result); if (simpleExpressionsOnly) { - ::error(ErrorType::ERR_UNSUPPORTED_ON_TARGET, "expression too complex", expression); + ::error(ErrorType::ERR_UNSUPPORTED_ON_TARGET, + "%1%: expression too complex for this target", expression); return; } @@ -591,7 +594,8 @@ void ExpressionConverter::postorder(const IR::StructInitializerExpression* expre auto result = new Util::JsonArray(); mapExpression(expression, result); if (simpleExpressionsOnly) { - ::error(ErrorType::ERR_UNSUPPORTED_ON_TARGET, "expression too complex", expression); + ::error(ErrorType::ERR_UNSUPPORTED_ON_TARGET, + "%1%: expression too complex for this target", expression); return; } @@ -605,7 +609,8 @@ void ExpressionConverter::postorder(const IR::Operation_Unary* expression) { auto result = new Util::JsonObject(); mapExpression(expression, result); if (simpleExpressionsOnly) { - ::error(ErrorType::ERR_UNSUPPORTED_ON_TARGET, "expression too complex", expression); + ::error(ErrorType::ERR_UNSUPPORTED_ON_TARGET, + "%1%: expression too complex for this target", expression); return; } diff --git a/backends/bmv2/common/extern.cpp b/backends/bmv2/common/extern.cpp index 75248194be1..2d718d617a1 100644 --- a/backends/bmv2/common/extern.cpp +++ b/backends/bmv2/common/extern.cpp @@ -96,7 +96,7 @@ ExternConverter::convertExternInstance(ConversionContext* ctxt, const IR::ExternBlock* eb, const bool& emitExterns) { if (!emitExterns) { - ::error(ErrorType::ERR_UNKNOWN, "extern instance", eb->type->name); + ::error(ErrorType::ERR_UNKNOWN, "%1%: unknown extern instance", eb->type->name); return; } auto attrs = new Util::JsonArray(); @@ -127,7 +127,7 @@ ExternConverter::convertExternFunction(ConversionContext* ctxt, const IR::StatOrDecl* s, const bool emitExterns) { if (!emitExterns) { - ::error(ErrorType::ERR_UNKNOWN, "extern function", ef->method->name); + ::error(ErrorType::ERR_UNKNOWN, "%1%: unknown extern function", ef->method->name); return nullptr; } auto primitive = mkPrimitive(ef->method->name); diff --git a/backends/bmv2/common/header.cpp b/backends/bmv2/common/header.cpp index b5e817b05cb..858ac5886ea 100644 --- a/backends/bmv2/common/header.cpp +++ b/backends/bmv2/common/header.cpp @@ -46,7 +46,8 @@ void HeaderConverter::addTypesAndInstances(const IR::Type_StructLike* type, bool // The headers struct can not contain nested structures. if (!meta && ft->is()) { ::error(ErrorType::ERR_INVALID, - "type should only contain headers, header stacks, or header unions", type); + "%1%: type should only contain headers, header stacks, or header unions", + type); return; } auto st = ft->to(); @@ -240,7 +241,8 @@ void HeaderConverter::addHeaderType(const IR::Type_StructLike *st) { max_length += type->size; field->append("*"); if (varbitFound) - ::error(ErrorType::ERR_UNSUPPORTED, "headers with multiple varbit fields", st); + ::error(ErrorType::ERR_UNSUPPORTED, + "%1%: headers with multiple varbit fields not supported", st); varbitFound = true; } else if (ftype->is()) { // treat as bit<32> @@ -261,7 +263,7 @@ void HeaderConverter::addHeaderType(const IR::Type_StructLike *st) { if (padding != 0) { if (st->is()) { ::error(ErrorType::ERR_UNSUPPORTED_ON_TARGET, - "Found header with fields totaling %2% bits." + "%1%: Found header with fields totaling %2% bits." " BMv2 target only supports headers with fields" " totaling a multiple of 8 bits.", st, max_length); diff --git a/backends/bmv2/common/lower.cpp b/backends/bmv2/common/lower.cpp index 0b4fc1d975c..31281b55919 100644 --- a/backends/bmv2/common/lower.cpp +++ b/backends/bmv2/common/lower.cpp @@ -301,7 +301,7 @@ RemoveComplexExpressions::postorder(IR::MethodCallExpression* expression) { // one knew of this feature, since it was not very clearly // documented. if (expression->arguments->size() != 2) { - ::error(ErrorType::ERR_EXPECTED, "2 arguments", expression); + ::error(ErrorType::ERR_EXPECTED, "%1%: expected 2 arguments", expression); return expression; } auto vec = new IR::Vector(); diff --git a/backends/bmv2/common/metermap.cpp b/backends/bmv2/common/metermap.cpp index c7aa0a07f9a..033fa4619a4 100644 --- a/backends/bmv2/common/metermap.cpp +++ b/backends/bmv2/common/metermap.cpp @@ -40,7 +40,7 @@ void DirectMeterMap::setTable(const IR::IDeclaration* meter, const IR::P4Table* auto info = getInfo(meter); if (info == nullptr) { ::error(ErrorType::ERR_INVALID, - "table with direct meter %2% must have" + "%1%: table with direct meter %2% must have" " at least one action with a read method call", table, meter); return; diff --git a/backends/bmv2/common/parser.cpp b/backends/bmv2/common/parser.cpp index 61b7621292c..09fa72a8315 100644 --- a/backends/bmv2/common/parser.cpp +++ b/backends/bmv2/common/parser.cpp @@ -255,7 +255,7 @@ Util::IJson* ParserConverter::convertParserStatement(const IR::StatOrDecl* stat) return result; } } - ::error(ErrorType::ERR_UNSUPPORTED, "in parser on this target", stat); + ::error(ErrorType::ERR_UNSUPPORTED, "%1%: not supported in parser on this target", stat); return result; } @@ -265,11 +265,13 @@ void ParserConverter::convertSimpleKey(const IR::Expression* keySet, if (keySet->is()) { auto mk = keySet->to(); if (!mk->left->is()) { - ::error(ErrorType::ERR_INVALID, "must evaluate to a compile-time constant", mk->left); + ::error(ErrorType::ERR_INVALID, + "%1%: must evaluate to a compile-time constant", mk->left); return; } if (!mk->right->is()) { - ::error(ErrorType::ERR_INVALID, "must evaluate to a compile-time constant", mk->right); + ::error(ErrorType::ERR_INVALID, + "%1%: must evaluate to a compile-time constant", mk->right); return; } value = mk->left->to()->value; @@ -284,7 +286,8 @@ void ParserConverter::convertSimpleKey(const IR::Expression* keySet, value = 0; mask = 0; } else { - ::error(ErrorType::ERR_INVALID, "must evaluate to a compile-time constant", keySet); + ::error(ErrorType::ERR_INVALID, + "%1%: must evaluate to a compile-time constant", keySet); value = 0; mask = 0; } diff --git a/backends/bmv2/common/sharedActionSelectorCheck.cpp b/backends/bmv2/common/sharedActionSelectorCheck.cpp index ff00a34e50a..cc886733a0f 100644 --- a/backends/bmv2/common/sharedActionSelectorCheck.cpp +++ b/backends/bmv2/common/sharedActionSelectorCheck.cpp @@ -33,7 +33,8 @@ SharedActionSelectorCheck::preorder(const IR::P4Table* table) { auto implementation = table->properties->getProperty("implementation"); if (implementation == nullptr) return false; if (!implementation->value->is()) { - ::error(ErrorType::ERR_EXPECTED, "expression for property", implementation); + ::error(ErrorType::ERR_EXPECTED, + "%1%: expected expression for property", implementation); return false; } auto propv = implementation->value->to(); @@ -41,12 +42,12 @@ SharedActionSelectorCheck::preorder(const IR::P4Table* table) { auto pathe = propv->expression->to(); auto decl = refMap->getDeclaration(pathe->path, true); if (!decl->is()) { - ::error(ErrorType::ERR_EXPECTED, "a reference to an instance", pathe); + ::error(ErrorType::ERR_EXPECTED, "%1%: expected a reference to an instance", pathe); return false; } auto dcltype = typeMap->getType(pathe, true); if (!dcltype->is()) { - ::error(ErrorType::ERR_UNEXPECTED, "type for implementation", dcltype); + ::error(ErrorType::ERR_UNEXPECTED, "%1%: unexpected type for implementation", dcltype); return false; } auto type_extern_name = dcltype->to()->name; diff --git a/backends/bmv2/psa_switch/psaSwitch.cpp b/backends/bmv2/psa_switch/psaSwitch.cpp index f4f8021b72b..b41e0633bdf 100644 --- a/backends/bmv2/psa_switch/psaSwitch.cpp +++ b/backends/bmv2/psa_switch/psaSwitch.cpp @@ -59,7 +59,7 @@ void PsaProgramStructure::createStructLike(ConversionContext* ctxt, const IR::Ty field->append("*"); if (varbitFound) ::error(ErrorType::ERR_UNSUPPORTED, - "headers with multiple varbit fields are not supported", st); + "%1%: headers with multiple varbit fields are not supported", st); varbitFound = true; } else if (ftype->is()) { field->append(f->name.name); @@ -861,7 +861,7 @@ void ExternConverter_Meter::convertExternInstance( else if (mkind_name == "BYTES") type = "bytes"; else - ::error(ErrorType::ERR_UNEXPECTED, "meter type", mkind->getNode()); + ::error(ErrorType::ERR_UNEXPECTED, "%1%: unexpected meter type", mkind->getNode()); jmtr->emplace("type", type); ctxt->json->meter_arrays->append(jmtr); } @@ -923,7 +923,7 @@ void ExternConverter_Register::convertExternInstance( return; } if (sz->to()->value == 0) - error(ErrorType::ERR_UNSUPPORTED, "direct registers", inst); + error(ErrorType::ERR_UNSUPPORTED, "%1%: direct registers are not supported", inst); jreg->emplace("size", sz->to()->value); if (!eb->instanceType->is()) { modelError("%1%: Expected a generic specialized type", eb->instanceType); @@ -936,12 +936,13 @@ void ExternConverter_Register::convertExternInstance( } auto regType = st->arguments->at(0); if (!regType->is()) { - ::error(ErrorType::ERR_UNSUPPORTED, "registers with types other than bit or int", eb); + ::error(ErrorType::ERR_UNSUPPORTED, + "%1%: registers with types other than bit<> or int<> are not suppoted", eb); return; } unsigned width = regType->width_bits(); if (width == 0) { - ::error(ErrorType::ERR_UNKNOWN, "width", st->arguments->at(0)); + ::error(ErrorType::ERR_UNKNOWN, "%1%: unknown width", st->arguments->at(0)); return; } jreg->emplace("bitwidth", width); @@ -969,7 +970,7 @@ void ExternConverter_ActionProfile::convertExternInstance( auto sz = eb->findParameterValue("size"); if (!sz->is()) { - ::error(ErrorType::ERR_EXPECTED, "a constant", sz); + ::error(ErrorType::ERR_EXPECTED, "%1%: expected a constant", sz); } action_profile->emplace("max_size", sz->to()->value); @@ -992,7 +993,7 @@ void ExternConverter_ActionSelector::convertExternInstance( auto sz = eb->findParameterValue("size"); if (!sz->is()) { - ::error(ErrorType::ERR_EXPECTED, "a constant", sz); + ::error(ErrorType::ERR_EXPECTED, "%1%: expected a constant", sz); return; } action_profile->emplace("max_size", sz->to()->value); diff --git a/backends/bmv2/simple_switch/simpleSwitch.cpp b/backends/bmv2/simple_switch/simpleSwitch.cpp index 2ec39e39e23..a31ffb8cc55 100644 --- a/backends/bmv2/simple_switch/simpleSwitch.cpp +++ b/backends/bmv2/simple_switch/simpleSwitch.cpp @@ -35,8 +35,9 @@ using BMV2::stringRepr; namespace BMV2 { void ParseV1Architecture::modelError(const char* format, const IR::Node* node) { - ::error(ErrorType::ERR_UNSUPPORTED, format, node); - ::error("Are you using an up-to-date v1model.p4?"); + ::error(ErrorType::ERR_UNSUPPORTED, + (cstring("%1%") + format + + "\nAre you using an up-to-date v1model.p4?").c_str(), node); } bool ParseV1Architecture::preorder(const IR::PackageBlock* main) { @@ -644,7 +645,7 @@ void ExternConverter_direct_meter::convertExternInstance( // + the meter is incorrectly associated with a table via a // property like 'counters = my_meter;'. ::error(ErrorType::ERR_INVALID, - "direct meter is not associated with any table" + "%1%: direct meter is not associated with any table" " via 'meters' table property", inst); return; } diff --git a/backends/ebpf/codeGen.h b/backends/ebpf/codeGen.h index e1cd1b855d8..369674e25a7 100644 --- a/backends/ebpf/codeGen.h +++ b/backends/ebpf/codeGen.h @@ -65,7 +65,7 @@ class CodeGenInspector : public Inspector { bool notSupported(const IR::Expression* expression) { ::error(ErrorType::ERR_UNSUPPORTED, - "not yet implemented", expression); return false; } + "%1%: not yet implemented", expression); return false; } bool preorder(const IR::Expression* expression) override { return notSupported(expression); } diff --git a/backends/ebpf/ebpfTable.cpp b/backends/ebpf/ebpfTable.cpp index 8c93751941c..9465df8e117 100644 --- a/backends/ebpf/ebpfTable.cpp +++ b/backends/ebpf/ebpfTable.cpp @@ -248,7 +248,7 @@ void EBPFTable::emitInstance(CodeBuilder* builder) { if (matchType->name.name == P4::P4CoreLibrary::instance.lpmMatch.name) { if (tableKind == TableLPMTrie) { ::error(ErrorType::ERR_UNSUPPORTED, - "only one LPM field allowed", it->matchType); + "%1%: only one LPM field allowed", it->matchType); return; } tableKind = TableLPMTrie; @@ -258,17 +258,17 @@ void EBPFTable::emitInstance(CodeBuilder* builder) { auto sz = extBlock->getParameterValue(program->model.array_table.size.name); if (sz == nullptr || !sz->is()) { ::error(ErrorType::ERR_UNSUPPORTED, - "Expected an integer argument; is the model corrupted?", expr); + "%1%: Expected an integer argument; is the model corrupted?", expr); return; } auto cst = sz->to(); if (!cst->fitsInt()) { - ::error(ErrorType::ERR_UNSUPPORTED, "size too large", cst); + ::error(ErrorType::ERR_UNSUPPORTED, "%1%: size too large", cst); return; } int size = cst->asInt(); if (size <= 0) { - ::error(ErrorType::ERR_INVALID, "negative size", cst); + ::error(ErrorType::ERR_INVALID, "%1%: negative size", cst); return; } @@ -488,7 +488,7 @@ EBPFCounterTable::EBPFCounterTable(const EBPFProgram* program, const IR::ExternB auto sz = block->getParameterValue(program->model.counterArray.max_index.name); if (sz == nullptr || !sz->is()) { ::error(ErrorType::ERR_INVALID, - "(%2%): expected an integer argument; is the model corrupted?", + "%1% (%2%): expected an integer argument; is the model corrupted?", program->model.counterArray.max_index, name); return; } @@ -506,7 +506,7 @@ EBPFCounterTable::EBPFCounterTable(const EBPFProgram* program, const IR::ExternB auto sprs = block->getParameterValue(program->model.counterArray.sparse.name); if (sprs == nullptr || !sprs->is()) { ::error(ErrorType::ERR_INVALID, - "(%2%): Expected an integer argument; is the model corrupted?", + "%1% (%2%): Expected an integer argument; is the model corrupted?", program->model.counterArray.sparse, name); return; } @@ -645,7 +645,7 @@ EBPFCounterTable::emitMethodInvocation(CodeBuilder* builder, const P4::ExternMet return; } ::error(ErrorType::ERR_UNSUPPORTED, - "Unexpected method for %2%", method->expr, program->model.counterArray.name); + "Unexpected method %1% for %2%", method->expr, program->model.counterArray.name); } void EBPFCounterTable::emitTypes(CodeBuilder* builder) { diff --git a/control-plane/p4RuntimeSerializer.cpp b/control-plane/p4RuntimeSerializer.cpp index 0602cd191de..952aff5c3a8 100644 --- a/control-plane/p4RuntimeSerializer.cpp +++ b/control-plane/p4RuntimeSerializer.cpp @@ -1110,7 +1110,7 @@ class P4RuntimeAnalyzer { auto matchType = getMatchType(matchTypeName); if (matchType == boost::none) { ::error(ErrorType::ERR_UNSUPPORTED, - "match type for Value Set '@match' annotation", + "unsupported match type %1% for Value Set '@match' annotation", matchAnnotation); return; } @@ -1135,7 +1135,7 @@ class P4RuntimeAnalyzer { auto fType = f->type; if (!fType->is()) { ::error(ErrorType::ERR_UNSUPPORTED, - "type parameter for Value Set; " + "unsupported type argument for Value Set; " "this version of P4Runtime requires that when the type parameter " "of a Value Set is a struct, all the fields of the struct " "must be of type bit, but %1% is not", f); @@ -1154,13 +1154,14 @@ class P4RuntimeAnalyzer { } } else if (et->is()) { ::error(ErrorType::ERR_UNSUPPORTED, - "type parameter for Value Set; " + "type argument for for Value Set; " "this version of P4Runtime requires the type parameter of a Value Set " "to be a bit or a struct of bit fields", inst); } else { ::error(ErrorType::ERR_INVALID, - "type parameter for Value Set; it must be one of bit, struct or tuple", + "%1%: invalid type parameter for Value Set; " + "it must be one of bit, struct or tuple", inst); } } @@ -1788,7 +1789,7 @@ P4RuntimeSerializer::generateP4Runtime(const IR::P4Program* program, cstring arc if (!p4RuntimeProgram || !evaluatedProgram) { ::error(ErrorType::ERR_UNSUPPORTED, - "P4 program (cannot apply necessary program transformations)", + "%1%: unsupported P4 program (cannot apply necessary program transformations)", "Cannot generate P4Info message"); return P4RuntimeAPI{new p4configv1::P4Info(), new p4v1::WriteRequest()}; } diff --git a/docs/CodingStandardPhilosophy.md b/docs/CodingStandardPhilosophy.md index 7986eba203d..cc406aaf84e 100644 --- a/docs/CodingStandardPhilosophy.md +++ b/docs/CodingStandardPhilosophy.md @@ -133,13 +133,14 @@ SourceInfo objects smartly. Here is an example: ```C++ IR::NamedRef *ref; -error("%1%: No header or metadata named '%2%'", ref->srcInfo, ref->name); +error(ErrorType::ERR_INVALID, + "%1%: No header or metadata named '%2%'", ref->srcInfo, ref->name); ``` output: ``` -../testdata/v1_errors/missing_decls1.p4(6): Error: No header or metadata named 'data' +missing_decls1.p4(6): [-Werror=invalid] Error: No header or metadata named 'data' if (data.b2 == 0) { ^^^^ ``` diff --git a/frontends/common/constantFolding.cpp b/frontends/common/constantFolding.cpp index 01f6c2d5fa7..473900122f6 100644 --- a/frontends/common/constantFolding.cpp +++ b/frontends/common/constantFolding.cpp @@ -104,15 +104,13 @@ const IR::Node* DoConstantFolding::postorder(IR::Type_Bits* type) { type->size = cst->asInt(); type->expression = nullptr; if (type->size <= 0) { - ::error(ErrorType::ERR_INVALID, "type size", type); + ::error(ErrorType::ERR_INVALID, "%1%: invalid type size", type); // Convert it to something legal so we don't get // weird errors elsewhere. type->size = 64; } - if (type->size == 1 && type->isSigned) - ::error(ErrorType::ERR_INVALID, "signed type which is 1-bit wide", type); } else { - ::error(ErrorType::ERR_EXPECTED, "to evaluate to a constant", type->expression); + ::error(ErrorType::ERR_EXPECTED, "%1%: expected a constant", type->expression); } } return type; @@ -124,9 +122,9 @@ const IR::Node* DoConstantFolding::postorder(IR::Type_Varbits* type) { type->size = cst->asInt(); type->expression = nullptr; if (type->size <= 0) - ::error(ErrorType::ERR_INVALID, "type size", type); + ::error(ErrorType::ERR_INVALID, "%1%: invalid type size", type); } else { - ::error(ErrorType::ERR_EXPECTED, "to evaluate to a constant", type->expression); + ::error(ErrorType::ERR_EXPECTED, "%1%: expected a constant", type->expression); } } return type; @@ -190,7 +188,7 @@ const IR::Node* DoConstantFolding::postorder(IR::Cmpl* e) { auto cst = op->to(); if (cst == nullptr) { - ::error(ErrorType::ERR_EXPECTED, "an integer value", op); + ::error(ErrorType::ERR_EXPECTED, "%1%: expected an integer value", op); return e; } const IR::Type* t = op->type; @@ -217,7 +215,7 @@ const IR::Node* DoConstantFolding::postorder(IR::Neg* e) { auto cst = op->to(); if (cst == nullptr) { - ::error(ErrorType::ERR_EXPECTED, "an integer value", op); + ::error(ErrorType::ERR_EXPECTED, "%1%: expected an integer value", op); return e; } const IR::Type* t = op->type; @@ -530,17 +528,17 @@ const IR::Node* DoConstantFolding::postorder(IR::Slice* e) { auto cmsb = msb->to(); if (cmsb == nullptr) { - ::error(ErrorType::ERR_EXPECTED, "an integer value", msb); + ::error(ErrorType::ERR_EXPECTED, "%1%: expected an integer value", msb); return e; } auto clsb = lsb->to(); if (clsb == nullptr) { - ::error(ErrorType::ERR_EXPECTED, "an integer value", lsb); + ::error(ErrorType::ERR_EXPECTED, "%1%: expected an integer value", lsb); return e; } auto cbase = e0->to(); if (cbase == nullptr) { - ::error(ErrorType::ERR_EXPECTED, "an integer value", e->e0); + ::error(ErrorType::ERR_EXPECTED, "%1%: expected an integer value", e->e0); return e; } @@ -675,7 +673,7 @@ const IR::Node* DoConstantFolding::shift(const IR::Operation_Binary* e) { auto cr = right->to(); if (cr == nullptr) { - ::error(ErrorType::ERR_EXPECTED, "an integer value", right); + ::error(ErrorType::ERR_EXPECTED, "%1%: expected an integer value", right); return e; } if (cr->value < 0) { @@ -694,7 +692,7 @@ const IR::Node* DoConstantFolding::shift(const IR::Operation_Binary* e) { auto cl = left->to(); if (cl == nullptr) { - ::error(ErrorType::ERR_EXPECTED, "an integer value", left); + ::error(ErrorType::ERR_EXPECTED, "%1%: expected an integer value", left); return e; } diff --git a/frontends/common/constantParsing.cpp b/frontends/common/constantParsing.cpp index 0abbccc5315..0329636af92 100644 --- a/frontends/common/constantParsing.cpp +++ b/frontends/common/constantParsing.cpp @@ -40,7 +40,7 @@ parseConstantWithWidth(Util::SourceInfo srcInfo, const char* text, if (sep == nullptr || !*sep) BUG("Expected to find separator %1%", text); if (size <= 0) { - ::error(ErrorType::ERR_INVALID, "width; must be positive %2%", srcInfo, size); + ::error(ErrorType::ERR_INVALID, "%1%: invalid width; %2% must be positive", srcInfo, size); return nullptr; } if (size > P4CConfiguration::MaximumWidthSupported) { ::error(ErrorType::ERR_OVERLIMIT, "%1%: %2% size too large", srcInfo, size); diff --git a/frontends/common/parseInput.h b/frontends/common/parseInput.h index 0e6d1958c90..460a921427d 100644 --- a/frontends/common/parseInput.h +++ b/frontends/common/parseInput.h @@ -74,7 +74,7 @@ const IR::P4Program* parseP4File(CompilerOptions& options) { in = fopen(options.file, "r"); if (in == nullptr) { ::error(ErrorType::ERR_NOT_FOUND, - "No such file or directory.", options.file); + "%1%: No such file or directory.", options.file); return nullptr; } } else { @@ -89,8 +89,7 @@ const IR::P4Program* parseP4File(CompilerOptions& options) { options.closeInput(in); if (::errorCount() > 0) { - ::error(ErrorType::ERR_OVERLIMIT, - "%1% errors encountered, aborting compilation", ::errorCount()); + ::error("%1% errors encountered, aborting compilation", ::errorCount()); return nullptr; } BUG_CHECK(result != nullptr, "Parsing failed, but we didn't report an error"); diff --git a/frontends/common/resolveReferences/resolveReferences.cpp b/frontends/common/resolveReferences/resolveReferences.cpp index 0e95afdc20c..58decb634dd 100644 --- a/frontends/common/resolveReferences/resolveReferences.cpp +++ b/frontends/common/resolveReferences/resolveReferences.cpp @@ -138,13 +138,13 @@ ResolutionContext::resolveUnique(IR::ID name, } if (decls->empty()) { - ::error(ErrorType::ERR_NOT_FOUND, "declaration", name); + ::error(ErrorType::ERR_NOT_FOUND, "%1%: declaration not found", name); return nullptr; } if (decls->size() == 1) return decls->at(0); - ::error(ErrorType::ERR_INVALID, "multiple matching declarations", name); + ::error(ErrorType::ERR_INVALID, "%1%: multiple matching declarations", name); for (auto a : *decls) ::error("Candidate: %1%", a); return nullptr; diff --git a/frontends/p4/actionsInlining.cpp b/frontends/p4/actionsInlining.cpp index 080b4c90416..f65f9cf5c2e 100644 --- a/frontends/p4/actionsInlining.cpp +++ b/frontends/p4/actionsInlining.cpp @@ -32,7 +32,8 @@ void DiscoverActionsInlining::postorder(const IR::MethodCallStatement* mcs) { auto caller = findContext(); if (caller == nullptr) { if (findContext() != nullptr) { - ::error(ErrorType::ERR_UNSUPPORTED, "action invocation in parser", mcs); + ::error(ErrorType::ERR_UNSUPPORTED, + "%1%: action invocation in parser not allowed", mcs); } else if (findContext() == nullptr) { BUG("%1%: unexpected action invocation", mcs); } diff --git a/frontends/p4/checkConstants.cpp b/frontends/p4/checkConstants.cpp index a3b1fc64b99..9786a21a797 100644 --- a/frontends/p4/checkConstants.cpp +++ b/frontends/p4/checkConstants.cpp @@ -28,7 +28,7 @@ void DoCheckConstants::postorder(const IR::MethodCallExpression* expression) { "Expected 1 argument for %1%", expression); auto arg0 = expression->arguments->at(0)->expression; if (!arg0->is()) - ::error(ErrorType::ERR_INVALID, "argument must be a constant", arg0); + ::error(ErrorType::ERR_INVALID, "%1%: argument must be a constant", arg0); } } } diff --git a/frontends/p4/checkNamedArgs.cpp b/frontends/p4/checkNamedArgs.cpp index 68eebf56d1c..b75c874ffd6 100644 --- a/frontends/p4/checkNamedArgs.cpp +++ b/frontends/p4/checkNamedArgs.cpp @@ -32,7 +32,7 @@ bool CheckNamedArgs::checkArguments(const IR::Vector* arguments) { } else { if (argHasName != hasName) ::error(ErrorType::ERR_INVALID, - "either all or none of the arguments of a call must be named", arg); + "%1%: either all or none of the arguments of a call must be named", arg); if (argHasName) { auto it = found.find(argName); if (it != found.end()) diff --git a/frontends/p4/fromv1.0/converters.h b/frontends/p4/fromv1.0/converters.h index 13eda0ca7fd..93efc44a61d 100644 --- a/frontends/p4/fromv1.0/converters.h +++ b/frontends/p4/fromv1.0/converters.h @@ -176,7 +176,7 @@ class DiscoverStructure : public Inspector { return; if (it->second != kind) ::error(ErrorType::ERR_INVALID, - "name; it can only be used for %2%", node, it->second); + "%1%: invalid name; it can only be used for %2%", node, it->second); } void checkReserved(const IR::Node* node, cstring nodeName) const { checkReserved(node, nodeName, nullptr); @@ -279,7 +279,7 @@ class ComputeCallGraph : public Inspector { else if (auto nr = ctrref->to()) ctr = structure->counters.get(nr->path->name); if (ctr == nullptr) - ::error(ErrorType::ERR_NOT_FOUND, "Cannot find counter", ctrref); + ::error(ErrorType::ERR_NOT_FOUND, "%1%: Cannot find counter", ctrref); auto parent = findContext(); BUG_CHECK(parent != nullptr, "%1%: Counter call not within action", primitive); structure->calledCounters.calls(parent->name, ctr->name.name); @@ -292,7 +292,7 @@ class ComputeCallGraph : public Inspector { else if (auto nr = mtrref->to()) mtr = structure->meters.get(nr->path->name); if (mtr == nullptr) - ::error(ErrorType::ERR_NOT_FOUND, "Cannot find meter", mtrref); + ::error(ErrorType::ERR_NOT_FOUND, "%1%: Cannot find meter", mtrref); auto parent = findContext(); BUG_CHECK(parent != nullptr, "%1%: not within action", primitive); @@ -310,7 +310,7 @@ class ComputeCallGraph : public Inspector { else if (auto nr = regref->to()) reg = structure->registers.get(nr->path->name); if (reg == nullptr) - ::error(ErrorType::ERR_NOT_FOUND, "Cannot find register", regref); + ::error(ErrorType::ERR_NOT_FOUND, "%1%: Cannot find register", regref); auto parent = findContext(); BUG_CHECK(parent != nullptr, "%1%: not within action", primitive); @@ -361,7 +361,7 @@ class ComputeTableCallGraph : public Inspector { LOG3("Scanning " << apply->name); auto tbl = structure->tables.get(apply->name.name); if (tbl == nullptr) - ::error(ErrorType::ERR_NOT_FOUND, "Could not find table", apply->name); + ::error(ErrorType::ERR_NOT_FOUND, "%1%: Could not find table", apply->name); auto parent = findContext(); ERROR_CHECK(parent != nullptr, "%1%: Apply not within a control block?", apply); @@ -376,7 +376,7 @@ class ComputeTableCallGraph : public Inspector { if (ctrl != nullptr && ctrl != parent) { auto previous = get(structure->tableInvocation, tbl); ::error(ErrorType::ERR_INVALID, - "Table invoked from two different controls: %2% and %3%", + "%1%: Table invoked from two different controls: %2% and %3%", tbl, apply, previous); } LOG3("Invoking " << tbl << " in " << parent->name); @@ -477,7 +477,7 @@ class FixExtracts final : public Transform { cstring hname = structure->makeUniqueName(type->name); if (fixedHeaderType != nullptr) { ::error(ErrorType::ERR_INVALID, - "header types with multiple varbit fields are not supported", + "%1%: header types with multiple varbit fields are not supported", type); return nullptr; } @@ -687,7 +687,8 @@ class DetectDuplicates: public Inspector { ::error(ErrorType::ERR_DUPLICATE, "%1%: same name as %2%", e1, e2); else // This name is probably standard_metadata_t, a built-in declaration - ::error(ErrorType::ERR_INVALID, "; name %2% is reserved", e2, key); + ::error(ErrorType::ERR_INVALID, + "%1% is invalid; name %2% is reserved", e2, key); } } } @@ -847,7 +848,7 @@ class MoveIntrinsicMetadata : public Transform { BUG_CHECK(tn, "%1%: expected a Type_Name", intrTypeName); auto nt = program->getDeclsByName(tn->path->name)->nextOrDefault(); if (nt == nullptr || !nt->is()) { - ::error(ErrorType::ERR_INVALID, "expected a structure", tn); + ::error(ErrorType::ERR_INVALID, "%1%: expected a structure", tn); return program; } intrType = nt->to(); @@ -861,7 +862,7 @@ class MoveIntrinsicMetadata : public Transform { BUG_CHECK(tn, "%1%: expected a Type_Name", queueTypeName); auto nt = program->getDeclsByName(tn->path->name)->nextOrDefault(); if (nt == nullptr || !nt->is()) { - ::error(ErrorType::ERR_INVALID, "expected a structure", tn); + ::error(ErrorType::ERR_INVALID, "%1%: expected a structure", tn); return program; } queueType = nt->to(); @@ -876,7 +877,7 @@ class MoveIntrinsicMetadata : public Transform { for (auto f : intrType->fields) { if (type->fields.getDeclaration(f->name) == nullptr) { ::error(ErrorType::ERR_NOT_FOUND, - "no such field in standard_metadata", f->name); + "%1%: no such field in standard_metadata", f->name); LOG2("standard_metadata: " << type); } } @@ -885,7 +886,7 @@ class MoveIntrinsicMetadata : public Transform { for (auto f : queueType->fields) { if (type->fields.getDeclaration(f->name) == nullptr) { ::error(ErrorType::ERR_NOT_FOUND, - "no such field in standard_metadata", f->name); + "%1%: no such field in standard_metadata", f->name); LOG2("standard_metadata: " << type); } } diff --git a/frontends/p4/fromv1.0/programStructure.cpp b/frontends/p4/fromv1.0/programStructure.cpp index 52d9a824f06..9bfa3c027e8 100644 --- a/frontends/p4/fromv1.0/programStructure.cpp +++ b/frontends/p4/fromv1.0/programStructure.cpp @@ -228,7 +228,7 @@ void ProgramStructure::createStructures() { auto h = headers.get(it.first->name); if (h != nullptr) ::warning(ErrorType::ERR_DUPLICATE, - "header and metadata instances %2% with the same name", + "%1%: header and metadata instances %2% with the same name", it.first, h); auto ht = type->to(); auto path = new IR::Path(type_name); @@ -315,7 +315,7 @@ const IR::Statement* ProgramStructure::convertParserStatement(const IR::Expressi auto destType = dest->type; CHECK_NULL(destType); if (!destType->is()) { - ::error(ErrorType::ERR_INVALID, "argument. Expected a header not %2%", + ::error(ErrorType::ERR_INVALID, "%1%: invalid argument. Expected a header not %2%", primitive, destType->toString()); return nullptr; } diff --git a/frontends/p4/validateParsedProgram.cpp b/frontends/p4/validateParsedProgram.cpp index 375ccb928ea..837b83e368b 100644 --- a/frontends/p4/validateParsedProgram.cpp +++ b/frontends/p4/validateParsedProgram.cpp @@ -32,19 +32,20 @@ void ValidateParsedProgram::postorder(const IR::Constant* c) { /// Check that extern constructor names match the enclosing extern void ValidateParsedProgram::postorder(const IR::Method* m) { if (m->name.isDontCare()) - ::error(ErrorType::ERR_INVALID, "method/function name.", m->name); + ::error(ErrorType::ERR_INVALID, "%1%: invalid method/function name.", m->name); if (auto ext = findContext()) { if (m->name == ext->name && m->type->returnType != nullptr) - ::error(ErrorType::ERR_INVALID, "type. Constructor cannot have a return type.", m); + ::error(ErrorType::ERR_INVALID, + "%1%: invalid constructor; cannot have a return type.", m); if (m->type->returnType == nullptr) { if (m->name != ext->name) { - ::error(ErrorType::ERR_INVALID, "type. Method has no return type.", m); + ::error(ErrorType::ERR_INVALID, "%1%: invalid type; method has no return type.", m); return; } for (auto p : *m->type->parameters) if (p->direction != IR::Direction::None) ::error(ErrorType::ERR_INVALID, - "call. Constructor parameters cannot have a direction.", p); + "%1%: Constructor parameters cannot have a direction.", p); } } } @@ -52,7 +53,7 @@ void ValidateParsedProgram::postorder(const IR::Method* m) { /// Struct field names cannot be underscore void ValidateParsedProgram::postorder(const IR::StructField* f) { if (f->name.isDontCare()) - ::error(ErrorType::ERR_INVALID, "field name", f->name); + ::error(ErrorType::ERR_INVALID, "%1%: invalid field name", f->name); } /// Width of a bit<> or int<> type is greater than 0 @@ -61,7 +62,7 @@ void ValidateParsedProgram::postorder(const IR::Type_Bits* type) { // cannot validate yet return; if (type->size <= 0) - ::error(ErrorType::ERR_INVALID, "type size", type); + ::error(ErrorType::ERR_INVALID, "%1%: invalid type size", type); } void ValidateParsedProgram::postorder(const IR::Type_Varbits* type) { @@ -69,7 +70,7 @@ void ValidateParsedProgram::postorder(const IR::Type_Varbits* type) { // cannot validate yet return; if (type->size <= 0) - ::error(ErrorType::ERR_INVALID, "type size", type); + ::error(ErrorType::ERR_INVALID, "%1%: invalid type size", type); } /// The accept and reject states cannot be implemented @@ -77,7 +78,7 @@ void ValidateParsedProgram::postorder(const IR::ParserState* s) { if (s->name == IR::ParserState::accept || s->name == IR::ParserState::reject) ::error(ErrorType::ERR_INVALID, - "parser state. %1% should not be implemented, it is built-in", s->name); + "Invalid parser state: %1% should not be implemented, it is built-in", s->name); } /// All parameters of a constructor must be directionless. @@ -86,7 +87,7 @@ void ValidateParsedProgram::container(const IR::IContainer* type) { for (auto p : type->getConstructorParameters()->parameters) if (p->direction != IR::Direction::None) ::error(ErrorType::ERR_INVALID, - "aragument. Constructor parameters cannot have a direction", p); + "%1%: invalid direction. Constructor parameters cannot have a direction", p); } /// Tables must have an 'actions' property. @@ -94,7 +95,7 @@ void ValidateParsedProgram::postorder(const IR::P4Table* t) { auto ac = t->getActionList(); if (ac == nullptr) ::error(ErrorType::ERR_EXPECTED, - "`%2%' property", + "%1%: expected '%2%' property", t->name, IR::TableProperties::actionsPropertyName); } @@ -129,39 +130,40 @@ void ValidateParsedProgram::postorder(const IR::ConstructorCallExpression* expre auto inAction = findContext(); if (inAction != nullptr) ::error(ErrorType::ERR_INVALID, - "call. Constructor calls not allowed in actions.", expression); + "%1%: invalid call. Constructor calls not allowed in actions.", expression); } /// Variable names cannot be underscore void ValidateParsedProgram::postorder(const IR::Declaration_Variable* decl) { if (decl->name.isDontCare()) - ::error(ErrorType::ERR_INVALID, "variable name.", decl); + ::error(ErrorType::ERR_INVALID, "%1%: invalid variable name.", decl); } /// Instance names cannot be don't care /// Do not declare instances in apply {} blocks, parser states or actions void ValidateParsedProgram::postorder(const IR::Declaration_Instance* decl) { if (decl->name.isDontCare()) - ::error(ErrorType::ERR_INVALID, "instance name.", decl); + ::error(ErrorType::ERR_INVALID, "%1%: invalid instance name.", decl); if (findContext() && // we're looking for the apply block findContext() && // of a control !findContext()) { // but not in an instance initializer ::error(ErrorType::ERR_INVALID, - "declaration. Instantiations cannot be in a control 'apply' block.", decl); + "%1%: invalid declaration. Instantiations cannot be in a control 'apply' block.", + decl); } if (findContext()) ::error(ErrorType::ERR_INVALID, - "declaration. Instantiations cannot be in a parser state.", decl); + "%1%: invalid declaration. Instantiations cannot be in a parser state.", decl); auto inAction = findContext(); if (inAction != nullptr) ::error(ErrorType::ERR_INVALID, - "declaration. Instantiations not allowed in actions.", decl); + "%1%: declaration. Instantiations not allowed in actions.", decl); } /// Constant names cannot be underscore void ValidateParsedProgram::postorder(const IR::Declaration_Constant* decl) { if (decl->name.isDontCare()) - ::error(ErrorType::ERR_INVALID, "constant name.", decl); + ::error(ErrorType::ERR_INVALID, "%1%: invalid constant name.", decl); } /** @@ -175,12 +177,12 @@ void ValidateParsedProgram::postorder(const IR::EntriesList* l) { auto table = findContext(); if (table == nullptr) { ::error(ErrorType::ERR_INVALID, - "initializer. Table initializers must belong to a table.", l); + "%1%: invalid initializer. Table initializers must belong to a table.", l); return; } auto ep = table->properties->getProperty(IR::TableProperties::entriesPropertyName); if (!ep->isConstant) ::error(ErrorType::ERR_INVALID, - "initializer. Table initializers must be constant.", l); + "%1%: invalid initializer. Table initializers must be constant.", l); } /// Switch statements are not allowed in actions. @@ -189,7 +191,7 @@ void ValidateParsedProgram::postorder(const IR::SwitchStatement* statement) { auto inAction = findContext(); if (inAction != nullptr) ::error(ErrorType::ERR_INVALID, - "statement. 'switch' statements not allowed in actions.", statement); + "%1%: invalid statement. 'switch' statements not allowed in actions.", statement); bool defaultFound = false; for (auto c : statement->cases) { if (defaultFound) { @@ -206,7 +208,7 @@ void ValidateParsedProgram::postorder(const IR::ReturnStatement* statement) { auto inParser = findContext(); if (inParser != nullptr) ::error(ErrorType::ERR_INVALID, - "statement. 'return' statements not allowed in parsers.", statement); + "%1%: invalid statement. 'return' statements not allowed in parsers.", statement); } /// Exit statements are not allowed in parsers or functions @@ -214,10 +216,10 @@ void ValidateParsedProgram::postorder(const IR::ExitStatement* statement) { auto inParser = findContext(); if (inParser != nullptr) ::error(ErrorType::ERR_INVALID, - "statement. 'exit' statements not allowed in parsers.", statement); + "%1%: invalid statement. 'exit' statements not allowed in parsers.", statement); if (findContext()) ::error(ErrorType::ERR_INVALID, - "statement. 'exit' statements not allowed in functions.", statement); + "%1% invalid statement. 'exit' statements not allowed in functions.", statement); } void ValidateParsedProgram::postorder(const IR::P4Program* program) { diff --git a/ir/base.cpp b/ir/base.cpp index 9372cb2766f..d8add94b3c7 100644 --- a/ir/base.cpp +++ b/ir/base.cpp @@ -22,12 +22,12 @@ cstring Annotation::getName(const IR::Annotation* annotation) { BUG_CHECK(annotation->name == IR::Annotation::nameAnnotation, "%1%: Only works on name annotations", annotation); if (annotation->expr.size() != 1) { - ::error(ErrorType::ERR_INVALID, "should contain a string", annotation); + ::error(ErrorType::ERR_INVALID, "%1%: should contain a string", annotation); return ""; } auto str = annotation->expr[0]->to(); if (str == nullptr) { - ::error(ErrorType::ERR_INVALID, "should contain a string", annotation); + ::error(ErrorType::ERR_INVALID, "%1%: should contain a string", annotation); return ""; } return str->value; diff --git a/ir/ir.cpp b/ir/ir.cpp index 949cad17a67..e84d378f5f4 100644 --- a/ir/ir.cpp +++ b/ir/ir.cpp @@ -172,7 +172,7 @@ P4Table::getApplyMethodType() const { // Synthesize a new type for the return auto actions = properties->getProperty(IR::TableProperties::actionsPropertyName); if (actions == nullptr) { - ::error(ErrorType::ERR_INVALID, "table does not contain a list of actions", this); + ::error(ErrorType::ERR_INVALID, "%1%: table does not contain a list of actions", this); return nullptr; } if (!actions->value->is()) @@ -255,7 +255,7 @@ const IR::PackageBlock* ToplevelBlock::getMain() const { return nullptr; } if (!main->is()) { - ::error(ErrorType::ERR_INVALID, "must be a package declaration", main->getNode()); + ::error(ErrorType::ERR_INVALID, "%1$: must be a package declaration", main->getNode()); return nullptr; } auto block = getValue(main->getNode()); diff --git a/ir/ir.def b/ir/ir.def index 625998c410e..9f46258a157 100644 --- a/ir/ir.def +++ b/ir/ir.def @@ -300,7 +300,7 @@ class P4Table : Declaration, IAnnotated, IApply { if (ap == nullptr) return nullptr; if (!ap->value->is()) { - ::error(ErrorType::ERR_INVALID, "must be an action list", ap); + ::error(ErrorType::ERR_INVALID, "%1%: must be an action list", ap); return nullptr; } return ap->value->to(); } Key getKey() const { @@ -308,7 +308,7 @@ class P4Table : Declaration, IAnnotated, IApply { if (kp == nullptr) return nullptr; if (!kp->value->is()) { - ::error(ErrorType::ERR_INVALID, "must be a key", kp); + ::error(ErrorType::ERR_INVALID, "%1%: must be a key", kp); return nullptr; } return kp->value->to(); } Expression getDefaultAction() const { @@ -316,7 +316,7 @@ class P4Table : Declaration, IAnnotated, IApply { if (d == nullptr) return nullptr; if (!d->value->is()) { - ::error(ErrorType::ERR_INVALID, "must be an expression", d); + ::error(ErrorType::ERR_INVALID, "%1%: must be an expression", d); return nullptr; } return d->value->to()->expression; } Constant getConstantProperty(cstring name) const { @@ -334,7 +334,7 @@ class P4Table : Declaration, IAnnotated, IApply { if (ep == nullptr) return nullptr; if (!ep->value->is()) { - ::error(ErrorType::ERR_INVALID, "must be a list of entries", ep); + ::error(ErrorType::ERR_INVALID, "%1%: must be a list of entries", ep); return nullptr; } return ep->value->to(); diff --git a/ir/type.cpp b/ir/type.cpp index 559584626a1..f22041c3605 100644 --- a/ir/type.cpp +++ b/ir/type.cpp @@ -88,13 +88,13 @@ const Type_String *Type_String::get() { const Type::Bits *Type::Bits::get(Util::SourceInfo si, int sz, bool isSigned) { if (sz <= 0) - ::error(ErrorType::ERR_INVALID, "Width cannot be negative or zero", si); + ::error(ErrorType::ERR_INVALID, "%1%: Width cannot be negative or zero", si); return get(sz, isSigned); } const Type::Varbits *Type::Varbits::get(Util::SourceInfo si, int sz) { if (sz <= 0) - ::error(ErrorType::ERR_INVALID, "Width cannot be negative or zero", si); + ::error(ErrorType::ERR_INVALID, "%1%: Width cannot be negative or zero", si); return new Type::Varbits(si, sz); } diff --git a/ir/type.def b/ir/type.def index 22944f3d5c4..768933a6094 100644 --- a/ir/type.def +++ b/ir/type.def @@ -169,7 +169,19 @@ class Type_InfInt : Type, ITypeVar { dbprint { out << "int/" << declid; } toString { return "int"; } operator== { return declid == a.declid; } - equiv { return true; /* ignore declid */ } + equiv { + #if __llvm__ + #pragma unused (a) + #endif + #if __GNUC__ + #pragma GCC diagnostic push + #pragma GCC diagnostic ignored "-Wunused-variable" + #endif + return true; /* ignore declid */ + #if __GNUC__ + #pragma GCC diagnostic pop + #endif + } const Type* getP4Type() const override { return this; } } diff --git a/lib/error_catalog.cpp b/lib/error_catalog.cpp index 86af5241e54..0c135532b8d 100644 --- a/lib/error_catalog.cpp +++ b/lib/error_catalog.cpp @@ -58,45 +58,42 @@ const int ErrorType::WARN_SHADOWING = 1016; const int ErrorType::WARN_IGNORE = 1017; const int ErrorType::WARN_MAX_WARNINGS = 2142; -using ErrorSig = std::pair; - -// map from errorCode to pairs of (name, format) -std::map ErrorCatalog::errorCatalog = { +// map from errorCode to ErrorSig +std::map ErrorCatalog::errorCatalog = { // Errors - { ErrorType::LEGACY_ERROR, ErrorSig("legacy", "")}, - { ErrorType::ERR_UNKNOWN, ErrorSig("unknown", "%1%: Unknown")}, - { ErrorType::ERR_UNSUPPORTED, ErrorSig("unsupported", "%1%: Unsupported")}, - { ErrorType::ERR_UNEXPECTED, ErrorSig("unexpected", "%1%: Unexpected")}, - { ErrorType::ERR_EXPECTED, ErrorSig("expected", "%1%: Expected")}, - { ErrorType::ERR_NOT_FOUND, ErrorSig("not-found", "%1%: Not found")}, - { ErrorType::ERR_INVALID, ErrorSig("invalid", "%1%: Invalid")}, - { ErrorType::ERR_EXPRESSION, ErrorSig("expr", "%1%: Expression")}, - { ErrorType::ERR_OVERLIMIT, ErrorSig("overlimit", "")}, - { ErrorType::ERR_INSUFFICIENT, ErrorSig("insufficient", "%1%: Target requires")}, - { ErrorType::ERR_UNINITIALIZED, ErrorSig("uninitialized", "%1%: Uninitialized")}, - { ErrorType::ERR_TYPE_ERROR, ErrorSig("type-error", "")}, - { ErrorType::ERR_UNSUPPORTED_ON_TARGET, ErrorSig("target-error", - "%1%: Unsupported on target")}, - { ErrorType::ERR_DUPLICATE, ErrorSig("duplicate", "")}, - { ErrorType::ERR_IO, ErrorSig("I/O error", "")}, + { ErrorType::LEGACY_ERROR, "legacy"}, + { ErrorType::ERR_UNKNOWN, "unknown"}, + { ErrorType::ERR_UNSUPPORTED, "unsupported"}, + { ErrorType::ERR_UNEXPECTED, "unexpected"}, + { ErrorType::ERR_EXPECTED, "expected"}, + { ErrorType::ERR_NOT_FOUND, "not-found"}, + { ErrorType::ERR_INVALID, "invalid"}, + { ErrorType::ERR_EXPRESSION, "expr"}, + { ErrorType::ERR_OVERLIMIT, "overlimit"}, + { ErrorType::ERR_INSUFFICIENT, "insufficient"}, + { ErrorType::ERR_UNINITIALIZED, "uninitialized"}, + { ErrorType::ERR_TYPE_ERROR, "type-error"}, + { ErrorType::ERR_UNSUPPORTED_ON_TARGET, "target-error"}, + { ErrorType::ERR_DUPLICATE, "duplicate"}, + { ErrorType::ERR_IO, "I/O error"}, // Warnings - { ErrorType::LEGACY_WARNING, ErrorSig("legacy", "")}, - { ErrorType::WARN_FAILED, ErrorSig("failed", "")}, - { ErrorType::WARN_UNKNOWN, ErrorSig("unknown", "")}, - { ErrorType::WARN_INVALID, ErrorSig("invalid", "")}, - { ErrorType::WARN_UNSUPPORTED, ErrorSig("unsupported", "")}, - { ErrorType::WARN_DEPRECATED, ErrorSig("deprecated", "")}, - { ErrorType::WARN_UNINITIALIZED, ErrorSig("uninitialized", "")}, - { ErrorType::WARN_UNUSED, ErrorSig("unused", "")}, - { ErrorType::WARN_MISSING, ErrorSig("missing", "")}, - { ErrorType::WARN_ORDERING, ErrorSig("ordering", "")}, - { ErrorType::WARN_MISMATCH, ErrorSig("mismatch", "")}, - { ErrorType::WARN_OVERFLOW, ErrorSig("overflow", "")}, - { ErrorType::WARN_IGNORE_PROPERTY, ErrorSig("ignore-prop", "")}, - { ErrorType::WARN_TYPE_INFERENCE, ErrorSig("type-inference", "")}, - { ErrorType::WARN_PARSER_TRANSITION, ErrorSig("parser-transition", "")}, - { ErrorType::WARN_UNREACHABLE, ErrorSig("parser-transition", "")}, - { ErrorType::WARN_SHADOWING, ErrorSig("shadow", "")}, - { ErrorType::WARN_IGNORE, ErrorSig("ignore", "")}, + { ErrorType::LEGACY_WARNING, "legacy"}, + { ErrorType::WARN_FAILED, "failed"}, + { ErrorType::WARN_UNKNOWN, "unknown"}, + { ErrorType::WARN_INVALID, "invalid"}, + { ErrorType::WARN_UNSUPPORTED, "unsupported"}, + { ErrorType::WARN_DEPRECATED, "deprecated"}, + { ErrorType::WARN_UNINITIALIZED, "uninitialized"}, + { ErrorType::WARN_UNUSED, "unused"}, + { ErrorType::WARN_MISSING, "missing"}, + { ErrorType::WARN_ORDERING, "ordering"}, + { ErrorType::WARN_MISMATCH, "mismatch"}, + { ErrorType::WARN_OVERFLOW, "overflow"}, + { ErrorType::WARN_IGNORE_PROPERTY, "ignore-prop"}, + { ErrorType::WARN_TYPE_INFERENCE, "type-inference"}, + { ErrorType::WARN_PARSER_TRANSITION, "parser-transition"}, + { ErrorType::WARN_UNREACHABLE, "parser-transition"}, + { ErrorType::WARN_SHADOWING, "shadow"}, + { ErrorType::WARN_IGNORE, "ignore"} }; diff --git a/lib/error_catalog.h b/lib/error_catalog.h index d60de7a4384..9efbd7c39ad 100644 --- a/lib/error_catalog.h +++ b/lib/error_catalog.h @@ -19,6 +19,7 @@ limitations under the License. #include #include +#include "cstring.h" /// enumerate supported errors /// Backends should extend this class with additional errors in the range 500-999 and @@ -83,42 +84,26 @@ class ErrorCatalog { /// returns false if the code already exists and forceReplace was not set to true /// @param errorCode - integer value for the error/warning /// @param name - name for the error. Used to enable/disable all errors of that type - /// @param fmt - error string format /// @param forceReplace - override an existing error type in the catalog - bool add(int errorCode, const char *name, const std::string fmt, bool forceReplace = false) { + bool add(int errorCode, const char *name, bool forceReplace = false) { if (forceReplace) errorCatalog.erase(errorCode); - auto it = errorCatalog.emplace(errorCode, std::pair(name, fmt)); + auto it = errorCatalog.emplace(errorCode, name); return it.second; } - /// add to the catalog - /// returns false if the code already exists and forceReplace was not set to true - bool add(int errorCode, const char *name, const char *fmt, bool forceReplace = false) { - return add(errorCode, name, std::string(fmt), forceReplace); - } - /// retrieve the name for errorCode - const char *getName(int errorCode) { + const cstring getName(int errorCode) { if (errorCatalog.count(errorCode)) - return errorCatalog.at(errorCode).first; + return errorCatalog.at(errorCode); return "--unknown--"; } - /// retrieve the message format for errorCode - const char *getFormat(int errorCode) { - if (errorCatalog.count(errorCode)) - return errorCatalog.at(errorCode).second.c_str(); - static std::string msg("errorCatalog message not set for error code "); - msg += std::to_string(errorCode); - return msg.c_str(); - } - private: ErrorCatalog() {} - /// map from errorCode to pairs of (name, format) - static std::map> errorCatalog; + /// map from errorCode to name + static std::map errorCatalog; }; #endif // P4C_LIB_ERROR_CATALOG_H_ diff --git a/lib/error_reporter.h b/lib/error_reporter.h index 82d7be3701f..f14df7b378a 100644 --- a/lib/error_reporter.h +++ b/lib/error_reporter.h @@ -56,10 +56,6 @@ class ErrorReporter final { return !p.second; // if insertion took place, then we have not seen the error. } - /// retrieve the format from the error catalog - const char *get_format(int errorCode) { - return ErrorCatalog::getCatalog().getFormat(errorCode); - } /// retrieve the format from the error catalog const char *get_error_name(int errorCode) { return ErrorCatalog::getCatalog().getName(errorCode); @@ -95,15 +91,12 @@ class ErrorReporter final { void diagnose(DiagnosticAction action, const int errorCode, const char *format, const T *node, Args... args) { if (!error_reported(errorCode, node->getSourceInfo())) { - std::string fmt = std::string(get_format(errorCode)); - if (!fmt.empty()) fmt += std::string(" ") + format; - else fmt += format; const char *name = get_error_name(errorCode); auto da = getDiagnosticAction(name, action); if (name) - diagnose(da, name, fmt.c_str(), node, args...); + diagnose(da, name, format, node, args...); else - diagnose(action, nullptr, fmt.c_str(), node, std::forward(args)...); + diagnose(action, nullptr, format, node, std::forward(args)...); } } @@ -118,15 +111,12 @@ class ErrorReporter final { template void diagnose(DiagnosticAction action, const int errorCode, const char *format, Args... args) { - std::string fmt = std::string(get_format(errorCode)); - if (!fmt.empty()) fmt += std::string(" ") + format; - else fmt += format; const char *name = get_error_name(errorCode); auto da = getDiagnosticAction(name, action); if (name) - diagnose(da, name, fmt.c_str(), args...); + diagnose(da, name, format, args...); else - diagnose(action, nullptr, fmt.c_str(), std::forward(args)...); + diagnose(action, nullptr, format, std::forward(args)...); } /// The sink of all the diagnostic functions. Here the error gets printed diff --git a/midend/compileTimeOps.h b/midend/compileTimeOps.h index 5c0c656e489..63661a9f8e6 100644 --- a/midend/compileTimeOps.h +++ b/midend/compileTimeOps.h @@ -34,7 +34,7 @@ class CompileTimeOperations : public Inspector { CompileTimeOperations() { setName("CompileTimeOperations"); } void err(const IR::Node* expression) { ::error(ErrorType::ERR_INVALID, - "could not evaluate at compilation time", expression); } + "%1%: could not evaluate expression at compilation time", expression); } void postorder(const IR::Mod* expression) override { err(expression); } void postorder(const IR::Div* expression) override diff --git a/midend/predication.h b/midend/predication.h index e8fd00f680a..818e4571779 100644 --- a/midend/predication.h +++ b/midend/predication.h @@ -71,7 +71,7 @@ class Predication final : public Transform { const IR::Statement* error(const IR::Statement* statement) const { if (inside_action && ifNestingLevel > 0) ::error(ErrorType::ERR_UNSUPPORTED_ON_TARGET, - "Conditional execution in actions", + "%1%: Conditional execution in actions unsupported on this target", statement); return statement; } diff --git a/midend/replaceSelectRange.cpp b/midend/replaceSelectRange.cpp index de89556307c..77e0ce909f8 100644 --- a/midend/replaceSelectRange.cpp +++ b/midend/replaceSelectRange.cpp @@ -27,8 +27,8 @@ DoReplaceSelectRange::rangeToMasks(const IR::Range *r) { auto l = r->left->to(); if (!l) { ::error(ErrorType::ERR_UNSUPPORTED_ON_TARGET, - "%2%: Range min must be a compile-time constant.", - r, r->left); + "%1%: Range boundaries must be a compile-time constants.", + r->left); return masks; } auto left = l->value; @@ -36,14 +36,14 @@ DoReplaceSelectRange::rangeToMasks(const IR::Range *r) { auto ri = r->right->to(); if (!ri) { ::error(ErrorType::ERR_UNSUPPORTED_ON_TARGET, - "%2%: Range max must be a compile-time constant.", - r, r->right); + "%1%: Range boundaries must be a compile-time constants.", + r->right); return masks; } auto right = ri->value; if (right < left) { - ::error(ErrorType::ERR_INVALID, "%2%-%3%: Range end is less than start.", - r, r->left, r->right); + ::error(ErrorType::ERR_INVALID, "%1%-%2%: Range end is less than start.", + r->left, r->right); return masks; } diff --git a/testdata/p4_14_errors_outputs/array_index.p4-stderr b/testdata/p4_14_errors_outputs/array_index.p4-stderr index d7eb8a84f28..c2fe485caae 100644 --- a/testdata/p4_14_errors_outputs/array_index.p4-stderr +++ b/testdata/p4_14_errors_outputs/array_index.p4-stderr @@ -5,4 +5,4 @@ array_index.p4(31): error: Illegal array index hdr.data[port]: must be a constan modify_field(data[port].f1, val); ^^^^^^^^^^ error: Cannot locate action noop -[--Werror=overlimit] error: 2 errors encountered, aborting compilation +error: 2 errors encountered, aborting compilation diff --git a/testdata/p4_14_errors_outputs/issue1092.p4-stderr b/testdata/p4_14_errors_outputs/issue1092.p4-stderr index f7c6be5a147..ff51ebbdacd 100644 --- a/testdata/p4_14_errors_outputs/issue1092.p4-stderr +++ b/testdata/p4_14_errors_outputs/issue1092.p4-stderr @@ -1,2 +1,2 @@ error: No transition from a parser to ingress pipeline found -[--Werror=overlimit] error: 1 errors encountered, aborting compilation +error: 1 errors encountered, aborting compilation diff --git a/testdata/p4_14_errors_outputs/issue1093.p4-stderr b/testdata/p4_14_errors_outputs/issue1093.p4-stderr index f692b64e48b..945c5174643 100644 --- a/testdata/p4_14_errors_outputs/issue1093.p4-stderr +++ b/testdata/p4_14_errors_outputs/issue1093.p4-stderr @@ -1,4 +1,4 @@ issue1093.p4(8):syntax error, unexpected END if(0 == 1) { } ^ -[--Werror=overlimit] error: 1 errors encountered, aborting compilation +error: 1 errors encountered, aborting compilation diff --git a/testdata/p4_14_errors_outputs/issue1238.p4-stderr b/testdata/p4_14_errors_outputs/issue1238.p4-stderr index 0be2ff326b0..399bc07e70c 100644 --- a/testdata/p4_14_errors_outputs/issue1238.p4-stderr +++ b/testdata/p4_14_errors_outputs/issue1238.p4-stderr @@ -1,4 +1,4 @@ issue1238.p4(11): [--Werror=legacy] error: subtract: operation only defined for bit/int types subtract(palatalising, palatalising, 1); ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -[--Werror=overlimit] error: 1 errors encountered, aborting compilation +error: 1 errors encountered, aborting compilation diff --git a/testdata/p4_14_errors_outputs/issue1499.p4-stderr b/testdata/p4_14_errors_outputs/issue1499.p4-stderr index 1a7b08c7b96..4b0b185152f 100644 --- a/testdata/p4_14_errors_outputs/issue1499.p4-stderr +++ b/testdata/p4_14_errors_outputs/issue1499.p4-stderr @@ -4,4 +4,4 @@ issue1499.p4(18): error: latest: latest not yet defined issue1499.p4(21): [--Werror=legacy] error: ingress: unknown state 1024 : ingress; ^^^^^^^ -[--Werror=overlimit] error: 2 errors encountered, aborting compilation +error: 2 errors encountered, aborting compilation diff --git a/testdata/p4_14_errors_outputs/issue1745.p4-stderr b/testdata/p4_14_errors_outputs/issue1745.p4-stderr index 2aba2bbffd4..a97deed1c45 100644 --- a/testdata/p4_14_errors_outputs/issue1745.p4-stderr +++ b/testdata/p4_14_errors_outputs/issue1745.p4-stderr @@ -4,4 +4,4 @@ issue1745.p4(6): [--Werror=legacy] error: length_: header length must depend onl issue1745.p4(3) options : *; ^^^^^^^^^^^ -[--Werror=overlimit] error: 1 errors encountered, aborting compilation +error: 1 errors encountered, aborting compilation diff --git a/testdata/p4_14_errors_outputs/issue187.p4-stderr b/testdata/p4_14_errors_outputs/issue187.p4-stderr index 63767382e50..f32895fdb7b 100644 --- a/testdata/p4_14_errors_outputs/issue187.p4-stderr +++ b/testdata/p4_14_errors_outputs/issue187.p4-stderr @@ -1,2 +1,2 @@ error: Program contains recursive control blocks -[--Werror=overlimit] error: 1 errors encountered, aborting compilation +error: 1 errors encountered, aborting compilation diff --git a/testdata/p4_14_errors_outputs/issue747.p4-stderr b/testdata/p4_14_errors_outputs/issue747.p4-stderr index 39033715c1e..801853bdd2d 100644 --- a/testdata/p4_14_errors_outputs/issue747.p4-stderr +++ b/testdata/p4_14_errors_outputs/issue747.p4-stderr @@ -4,4 +4,4 @@ action local_recirc(local_port) { issue747.p4(31): [--Werror=legacy] error: local_port: expected a field list action local_recirc(local_port) { ^^^^^^^^^^ -[--Werror=overlimit] error: 1 errors encountered, aborting compilation +error: 1 errors encountered, aborting compilation diff --git a/testdata/p4_14_errors_outputs/issue763-1.p4-stderr b/testdata/p4_14_errors_outputs/issue763-1.p4-stderr index f129f594718..7d2ceabbbb1 100644 --- a/testdata/p4_14_errors_outputs/issue763-1.p4-stderr +++ b/testdata/p4_14_errors_outputs/issue763-1.p4-stderr @@ -1,4 +1,4 @@ -issue763-1.p4(7): [--Werror=invalid] error: Header: Invalid name; it can only be used for metadata +issue763-1.p4(7): [--Werror=invalid] error: Header: invalid name; it can only be used for metadata header X standard_metadata; ^^^^^^^^^^^^^^^^^^^^^^^^^^^ -[--Werror=overlimit] error: 1 errors encountered, aborting compilation +error: 1 errors encountered, aborting compilation diff --git a/testdata/p4_14_errors_outputs/issue763-2.p4-stderr b/testdata/p4_14_errors_outputs/issue763-2.p4-stderr index b09a84d1435..553185e7bb8 100644 --- a/testdata/p4_14_errors_outputs/issue763-2.p4-stderr +++ b/testdata/p4_14_errors_outputs/issue763-2.p4-stderr @@ -1,4 +1,4 @@ -issue763-2.p4(1): [--Werror=invalid] error: v1HeaderType: Invalid ; name standard_metadata_t is reserved +issue763-2.p4(1): [--Werror=invalid] error: v1HeaderType is invalid; name standard_metadata_t is reserved header_type standard_metadata_t { ^ -[--Werror=overlimit] error: 1 errors encountered, aborting compilation +error: 1 errors encountered, aborting compilation diff --git a/testdata/p4_14_errors_outputs/issue763.p4-stderr b/testdata/p4_14_errors_outputs/issue763.p4-stderr index c260b7ccd60..0b6f2b8175a 100644 --- a/testdata/p4_14_errors_outputs/issue763.p4-stderr +++ b/testdata/p4_14_errors_outputs/issue763.p4-stderr @@ -4,4 +4,4 @@ header_type X { issue763.p4(7) header_type X { ^ -[--Werror=overlimit] error: 1 errors encountered, aborting compilation +error: 1 errors encountered, aborting compilation diff --git a/testdata/p4_14_errors_outputs/issue780-10.p4-stderr b/testdata/p4_14_errors_outputs/issue780-10.p4-stderr index 41a77882ea1..e926fa2ce62 100644 --- a/testdata/p4_14_errors_outputs/issue780-10.p4-stderr +++ b/testdata/p4_14_errors_outputs/issue780-10.p4-stderr @@ -1,4 +1,4 @@ -issue780-10.p4(1): [--Werror=invalid] error: V1Control standard_metadata_t: Invalid name; it can only be used for type +issue780-10.p4(1): [--Werror=invalid] error: V1Control standard_metadata_t: invalid name; it can only be used for type control standard_metadata_t { } ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -[--Werror=overlimit] error: 1 errors encountered, aborting compilation +error: 1 errors encountered, aborting compilation diff --git a/testdata/p4_14_errors_outputs/issue780-4.p4-stderr b/testdata/p4_14_errors_outputs/issue780-4.p4-stderr index 6f55965ee69..daab0283595 100644 --- a/testdata/p4_14_errors_outputs/issue780-4.p4-stderr +++ b/testdata/p4_14_errors_outputs/issue780-4.p4-stderr @@ -1,4 +1,4 @@ -issue780-4.p4(1): [--Werror=invalid] error: header egress: Invalid name; it can only be used for control +issue780-4.p4(1): [--Werror=invalid] error: header egress: invalid name; it can only be used for control header_type egress { ^ -[--Werror=overlimit] error: 1 errors encountered, aborting compilation +error: 1 errors encountered, aborting compilation diff --git a/testdata/p4_14_errors_outputs/issue780-6.p4-stderr b/testdata/p4_14_errors_outputs/issue780-6.p4-stderr index 7bf5f83d050..c0b5bedc7e8 100644 --- a/testdata/p4_14_errors_outputs/issue780-6.p4-stderr +++ b/testdata/p4_14_errors_outputs/issue780-6.p4-stderr @@ -1,4 +1,4 @@ -issue780-6.p4(1): [--Werror=invalid] error: header standard_metadata: Invalid name; it can only be used for metadata +issue780-6.p4(1): [--Werror=invalid] error: header standard_metadata: invalid name; it can only be used for metadata header_type standard_metadata { ^ -[--Werror=overlimit] error: 1 errors encountered, aborting compilation +error: 1 errors encountered, aborting compilation diff --git a/testdata/p4_14_errors_outputs/issue905.p4-stderr b/testdata/p4_14_errors_outputs/issue905.p4-stderr index 15d2c379959..042a94422a3 100644 --- a/testdata/p4_14_errors_outputs/issue905.p4-stderr +++ b/testdata/p4_14_errors_outputs/issue905.p4-stderr @@ -1,4 +1,4 @@ issue905.p4(34): [--Werror=legacy] error: *: not defined on operands of type varbit<0> modify_field(can_data.value, can_data.value * 2); // error ^ -[--Werror=overlimit] error: 1 errors encountered, aborting compilation +error: 1 errors encountered, aborting compilation diff --git a/testdata/p4_14_errors_outputs/nasty_meta.p4-stderr b/testdata/p4_14_errors_outputs/nasty_meta.p4-stderr index e0627d472d8..2473c73dc31 100644 --- a/testdata/p4_14_errors_outputs/nasty_meta.p4-stderr +++ b/testdata/p4_14_errors_outputs/nasty_meta.p4-stderr @@ -1,4 +1,4 @@ -nasty_meta.p4(24): [--Werror=invalid] error: extract: Invalid argument. Expected a header not struct ethernet_t +nasty_meta.p4(24): [--Werror=invalid] error: extract: invalid argument. Expected a header not struct ethernet_t extract(ethernet); ^^^^^^^^^^^^^^^^^ -[--Werror=overlimit] error: 1 errors encountered, aborting compilation +error: 1 errors encountered, aborting compilation diff --git a/testdata/p4_14_errors_outputs/unknown-state.p4-stderr b/testdata/p4_14_errors_outputs/unknown-state.p4-stderr index c89607cebe6..860d947bbf4 100644 --- a/testdata/p4_14_errors_outputs/unknown-state.p4-stderr +++ b/testdata/p4_14_errors_outputs/unknown-state.p4-stderr @@ -1,4 +1,4 @@ unknown-state.p4(2): [--Werror=legacy] error: ingress: unknown state return ingress; ^^^^^^^ -[--Werror=overlimit] error: 1 errors encountered, aborting compilation +error: 1 errors encountered, aborting compilation diff --git a/testdata/p4_14_samples_outputs/issue1873.p4-stderr b/testdata/p4_14_samples_outputs/issue1873.p4-stderr index 97b98025b3c..44ee9b122fe 100644 --- a/testdata/p4_14_samples_outputs/issue1873.p4-stderr +++ b/testdata/p4_14_samples_outputs/issue1873.p4-stderr @@ -1,4 +1,4 @@ -issue1873.p4(7): [--Wwarn=duplicate] warning: header and metadata instances Header with the same name +issue1873.p4(7): [--Wwarn=duplicate] warning: Metadata: header and metadata instances Header with the same name metadata test_t test; ^^^^^^^^^^^^^^^^^^^^^ issue1873.p4(8) diff --git a/testdata/p4_16_errors_outputs/accept_e.p4-stderr b/testdata/p4_16_errors_outputs/accept_e.p4-stderr index 281dec89165..50811066f2e 100644 --- a/testdata/p4_16_errors_outputs/accept_e.p4-stderr +++ b/testdata/p4_16_errors_outputs/accept_e.p4-stderr @@ -1,3 +1,3 @@ -accept_e.p4(18): [--Werror=invalid] error: accept: Invalid parser state. accept should not be implemented, it is built-in +accept_e.p4(18): [--Werror=invalid] error: Invalid parser state: accept should not be implemented, it is built-in state accept { // reserved name ^^^^^^ diff --git a/testdata/p4_16_errors_outputs/constructor1_e.p4-stderr b/testdata/p4_16_errors_outputs/constructor1_e.p4-stderr index d4550e6552a..68b700dd9e2 100644 --- a/testdata/p4_16_errors_outputs/constructor1_e.p4-stderr +++ b/testdata/p4_16_errors_outputs/constructor1_e.p4-stderr @@ -1,4 +1,4 @@ constructor1_e.p4(18):syntax error, unexpected ( Y( ^ -[--Werror=overlimit] error: 1 errors encountered, aborting compilation +error: 1 errors encountered, aborting compilation diff --git a/testdata/p4_16_errors_outputs/constructor2_e.p4-stderr b/testdata/p4_16_errors_outputs/constructor2_e.p4-stderr index 06c4d69fb9a..408a16aabaa 100644 --- a/testdata/p4_16_errors_outputs/constructor2_e.p4-stderr +++ b/testdata/p4_16_errors_outputs/constructor2_e.p4-stderr @@ -1,4 +1,4 @@ constructor2_e.p4(18):syntax error, unexpected ( m( ^ -[--Werror=overlimit] error: 1 errors encountered, aborting compilation +error: 1 errors encountered, aborting compilation diff --git a/testdata/p4_16_errors_outputs/constructor_e.p4-stderr b/testdata/p4_16_errors_outputs/constructor_e.p4-stderr index b572c46997a..1d710d8f600 100644 --- a/testdata/p4_16_errors_outputs/constructor_e.p4-stderr +++ b/testdata/p4_16_errors_outputs/constructor_e.p4-stderr @@ -1,3 +1,3 @@ -constructor_e.p4(18): [--Werror=invalid] error: X: Invalid type. Constructor cannot have a return type. +constructor_e.p4(18): [--Werror=invalid] error: X: invalid constructor; cannot have a return type. void X(); // no return type allowed ^ diff --git a/testdata/p4_16_errors_outputs/div3.p4-stderr b/testdata/p4_16_errors_outputs/div3.p4-stderr index b786e569cb7..8db6f2540b6 100644 --- a/testdata/p4_16_errors_outputs/div3.p4-stderr +++ b/testdata/p4_16_errors_outputs/div3.p4-stderr @@ -1,3 +1,3 @@ -div3.p4(19): [--Werror=invalid] error: /: Invalid could not evaluate at compilation time +div3.p4(19): [--Werror=invalid] error: /: could not evaluate expression at compilation time a = a / b; // not a compile-time constant ^^^^^ diff --git a/testdata/p4_16_errors_outputs/expression_e.p4-stderr b/testdata/p4_16_errors_outputs/expression_e.p4-stderr index 11115d1c8c6..2e013e24e22 100644 --- a/testdata/p4_16_errors_outputs/expression_e.p4-stderr +++ b/testdata/p4_16_errors_outputs/expression_e.p4-stderr @@ -1,4 +1,4 @@ expression_e.p4(21):syntax error, unexpected _ b = 32w0 & _ ^ -[--Werror=overlimit] error: 1 errors encountered, aborting compilation +error: 1 errors encountered, aborting compilation diff --git a/testdata/p4_16_errors_outputs/globalVar_e.p4-stderr b/testdata/p4_16_errors_outputs/globalVar_e.p4-stderr index d3fae483989..1f51a0184d7 100644 --- a/testdata/p4_16_errors_outputs/globalVar_e.p4-stderr +++ b/testdata/p4_16_errors_outputs/globalVar_e.p4-stderr @@ -1,4 +1,4 @@ globalVar_e.p4(16):syntax error, unexpected ;, expecting ( bit x; ^ -[--Werror=overlimit] error: 1 errors encountered, aborting compilation +error: 1 errors encountered, aborting compilation diff --git a/testdata/p4_16_errors_outputs/header1_e.p4-stderr b/testdata/p4_16_errors_outputs/header1_e.p4-stderr index 466518ce36b..64c1667df9b 100644 --- a/testdata/p4_16_errors_outputs/header1_e.p4-stderr +++ b/testdata/p4_16_errors_outputs/header1_e.p4-stderr @@ -1,4 +1,4 @@ header1_e.p4(18):syntax error, unexpected _ _ ^ -[--Werror=overlimit] error: 1 errors encountered, aborting compilation +error: 1 errors encountered, aborting compilation diff --git a/testdata/p4_16_errors_outputs/issue-2123_e.p4-stderr b/testdata/p4_16_errors_outputs/issue-2123_e.p4-stderr index 5617e73c181..a2b35321ab6 100644 --- a/testdata/p4_16_errors_outputs/issue-2123_e.p4-stderr +++ b/testdata/p4_16_errors_outputs/issue-2123_e.p4-stderr @@ -4,33 +4,21 @@ issue-2123_e.p4(63): [--Wwarn=uninitialized_use] warning: hdr.ipv4.totalLen may issue-2123_e.p4(64): [--Wwarn=uninitialized_use] warning: hdr.ipv4.totalLen may be uninitialized 0x0800 .. hdr.ipv4.totalLen : parse_ipv4; ^^^^^^^^^^^^^^^^^ -issue-2123_e.p4(61): [--Werror=invalid] error: ..: Invalid 0x806-0x800: Range end is less than start. - 0x0806 .. 0x0800 : parse_ipv4; - ^^^^^^^^^^^^^^^^ -issue-2123_e.p4(61) +issue-2123_e.p4(61): [--Werror=invalid] error: 0x806-0x800: Range end is less than start. 0x0806 .. 0x0800 : parse_ipv4; ^^^^^^ issue-2123_e.p4(61) 0x0806 .. 0x0800 : parse_ipv4; ^^^^^^ -issue-2123_e.p4(62): [--Werror=invalid] error: ..: Invalid 2054-2048: Range end is less than start. - 2054 .. 2048 : parse_ipv4; - ^^^^^^^^^^^^ -issue-2123_e.p4(62) +issue-2123_e.p4(62): [--Werror=invalid] error: 2054-2048: Range end is less than start. 2054 .. 2048 : parse_ipv4; ^^^^ issue-2123_e.p4(62) 2054 .. 2048 : parse_ipv4; ^^^^ -issue-2123_e.p4(63): [--Werror=target-error] error: ..: Unsupported on target hdr.ipv4.totalLen: Range min must be a compile-time constant. - hdr.ipv4.totalLen .. 0x0800 : parse_ipv4; - ^^^^^^^^^^^^^^^^^^^^^^^^^^^ -issue-2123_e.p4(63) +issue-2123_e.p4(63): [--Werror=target-error] error: hdr.ipv4.totalLen: Range boundaries must be a compile-time constants. hdr.ipv4.totalLen .. 0x0800 : parse_ipv4; ^^^^^^^^^^^^^^^^^ -issue-2123_e.p4(64): [--Werror=target-error] error: ..: Unsupported on target hdr.ipv4.totalLen: Range max must be a compile-time constant. - 0x0800 .. hdr.ipv4.totalLen : parse_ipv4; - ^^^^^^^^^^^^^^^^^^^^^^^^^^^ -issue-2123_e.p4(64) +issue-2123_e.p4(64): [--Werror=target-error] error: hdr.ipv4.totalLen: Range boundaries must be a compile-time constants. 0x0800 .. hdr.ipv4.totalLen : parse_ipv4; ^^^^^^^^^^^^^^^^^ diff --git a/testdata/p4_16_errors_outputs/issue1202.p4-stderr b/testdata/p4_16_errors_outputs/issue1202.p4-stderr index 1e4af4fec5c..fee1d2db01c 100644 --- a/testdata/p4_16_errors_outputs/issue1202.p4-stderr +++ b/testdata/p4_16_errors_outputs/issue1202.p4-stderr @@ -1,4 +1,4 @@ issue1202.p4(1):syntax error, unexpected BIT const bit<32> x = bit ^^^ -[--Werror=overlimit] error: 1 errors encountered, aborting compilation +error: 1 errors encountered, aborting compilation diff --git a/testdata/p4_16_errors_outputs/issue1336.p4-stderr b/testdata/p4_16_errors_outputs/issue1336.p4-stderr index 77c6a743e1d..1df0e1c0da7 100644 --- a/testdata/p4_16_errors_outputs/issue1336.p4-stderr +++ b/testdata/p4_16_errors_outputs/issue1336.p4-stderr @@ -1,4 +1,4 @@ issue1336.p4(3):syntax error, unexpected ( type id ( ^ -[--Werror=overlimit] error: 1 errors encountered, aborting compilation +error: 1 errors encountered, aborting compilation diff --git a/testdata/p4_16_errors_outputs/issue1777-bmv2.p4-stderr b/testdata/p4_16_errors_outputs/issue1777-bmv2.p4-stderr index 9d2e7c1b998..ae777facf1e 100644 --- a/testdata/p4_16_errors_outputs/issue1777-bmv2.p4-stderr +++ b/testdata/p4_16_errors_outputs/issue1777-bmv2.p4-stderr @@ -1,3 +1,3 @@ -issue1777-bmv2.p4(64): [--Werror=unsupported] error: meta.reg_data2: Unsupported meta.reg_data2: writing to a structure is not supported on this target +issue1777-bmv2.p4(64): [--Werror=unsupported] error: meta.reg_data2: writing to a structure is not supported on this target reg2.read(meta.reg_data2, (bit<32>) reg_idx); ^^^^^^^^^^^^^^ diff --git a/testdata/p4_16_errors_outputs/issue1932-1.p4-stderr b/testdata/p4_16_errors_outputs/issue1932-1.p4-stderr index 0bc4342c78a..00660a5323d 100644 --- a/testdata/p4_16_errors_outputs/issue1932-1.p4-stderr +++ b/testdata/p4_16_errors_outputs/issue1932-1.p4-stderr @@ -4,4 +4,4 @@ issue1932-1.p4(10): [--Werror=duplicate] error: foo: Duplicates declaration foo issue1932-1.p4(9) action foo (in bit<8> x, out bit<8> y) { y = (x >> 2); } ^^^ -[--Werror=overlimit] error: 1 errors encountered, aborting compilation +error: 1 errors encountered, aborting compilation diff --git a/testdata/p4_16_errors_outputs/issue1944.p4-stderr b/testdata/p4_16_errors_outputs/issue1944.p4-stderr index 27858efed78..ea995e60c45 100644 --- a/testdata/p4_16_errors_outputs/issue1944.p4-stderr +++ b/testdata/p4_16_errors_outputs/issue1944.p4-stderr @@ -1,4 +1,4 @@ issue1944.p4(1): [--Werror=overlimit] error: 2147483648: this implementation does not support bitstrings this large const bit<2147483648> ^^^^^^^^^^ -[--Werror=overlimit] error: 1 errors encountered, aborting compilation +error: 1 errors encountered, aborting compilation diff --git a/testdata/p4_16_errors_outputs/issue1986-1.p4-stderr b/testdata/p4_16_errors_outputs/issue1986-1.p4-stderr index d17ec6527ec..b8276e9b6c6 100644 --- a/testdata/p4_16_errors_outputs/issue1986-1.p4-stderr +++ b/testdata/p4_16_errors_outputs/issue1986-1.p4-stderr @@ -1,4 +1,4 @@ -issue1986-1.p4(22): [--Werror=invalid] error: : Invalid width; must be positive 0 +issue1986-1.p4(22): [--Werror=invalid] error: : invalid width; 0 must be positive transition select(2w0) {0w0 ^^^ -[--Werror=overlimit] error: 1 errors encountered, aborting compilation +error: 1 errors encountered, aborting compilation diff --git a/testdata/p4_16_errors_outputs/issue1986.p4-stderr b/testdata/p4_16_errors_outputs/issue1986.p4-stderr index e8e8e814632..87b50fb7115 100644 --- a/testdata/p4_16_errors_outputs/issue1986.p4-stderr +++ b/testdata/p4_16_errors_outputs/issue1986.p4-stderr @@ -1,4 +1,4 @@ -issue1986.p4(18): [--Werror=invalid] error: : Invalid width; must be positive 0 +issue1986.p4(18): [--Werror=invalid] error: : invalid width; 0 must be positive {0w0 ^^^ -[--Werror=overlimit] error: 1 errors encountered, aborting compilation +error: 1 errors encountered, aborting compilation diff --git a/testdata/p4_16_errors_outputs/issue435.p4-stderr b/testdata/p4_16_errors_outputs/issue435.p4-stderr index 21e5e432a65..7c50f270920 100644 --- a/testdata/p4_16_errors_outputs/issue435.p4-stderr +++ b/testdata/p4_16_errors_outputs/issue435.p4-stderr @@ -1,3 +1,3 @@ -issue435.p4(7): [--Werror=invalid] error: mystruct1: Invalid type. Method has no return type. +issue435.p4(7): [--Werror=invalid] error: mystruct1: invalid type; method has no return type. mystruct1(in bit<8> a, out bit<16> b); ^^^^^^^^^ diff --git a/testdata/p4_16_errors_outputs/issue513.p4-stderr b/testdata/p4_16_errors_outputs/issue513.p4-stderr index 4e83fafabd4..6664b4d4fe3 100644 --- a/testdata/p4_16_errors_outputs/issue513.p4-stderr +++ b/testdata/p4_16_errors_outputs/issue513.p4-stderr @@ -4,6 +4,6 @@ issue513.p4(60): [--Wwarn=deprecated] warning: mark_to_drop: Using deprecated fe v1model.p4(365) extern void mark_to_drop(); ^^^^^^^^^^^^ -issue513.p4(60): [--Werror=target-error] error: MethodCallStatement: Unsupported on target Conditional execution in actions +issue513.p4(60): [--Werror=target-error] error: MethodCallStatement: Conditional execution in actions unsupported on this target mark_to_drop(); ^^^^^^^^^^^^^^ diff --git a/testdata/p4_16_errors_outputs/missing_actions.p4-stderr b/testdata/p4_16_errors_outputs/missing_actions.p4-stderr index 07eddb609c6..44c47a7a8fc 100644 --- a/testdata/p4_16_errors_outputs/missing_actions.p4-stderr +++ b/testdata/p4_16_errors_outputs/missing_actions.p4-stderr @@ -1,3 +1,3 @@ -missing_actions.p4(19): [--Werror=expected] error: t: Expected `actions' property +missing_actions.p4(19): [--Werror=expected] error: t: expected 'actions' property table t { ^ diff --git a/testdata/p4_16_errors_outputs/missing_match.p4-stderr b/testdata/p4_16_errors_outputs/missing_match.p4-stderr index 65a0ab0640b..15b96b32152 100644 --- a/testdata/p4_16_errors_outputs/missing_match.p4-stderr +++ b/testdata/p4_16_errors_outputs/missing_match.p4-stderr @@ -1,3 +1,3 @@ -missing_match.p4(20): [--Werror=not-found] error: noSuchMatch: Not found declaration +missing_match.p4(20): [--Werror=not-found] error: noSuchMatch: declaration not found key = { b : noSuchMatch; } ^^^^^^^^^^^ diff --git a/testdata/p4_16_errors_outputs/named-fail.p4-stderr b/testdata/p4_16_errors_outputs/named-fail.p4-stderr index c795d040f54..c55979d9f36 100644 --- a/testdata/p4_16_errors_outputs/named-fail.p4-stderr +++ b/testdata/p4_16_errors_outputs/named-fail.p4-stderr @@ -1,4 +1,4 @@ -named-fail.p4(8): [--Werror=invalid] error: xv: Invalid either all or none of the arguments of a call must be named +named-fail.p4(8): [--Werror=invalid] error: xv: either all or none of the arguments of a call must be named f(y = b, xv); // not all arguments named ^^ named-fail.p4(9): [--Werror=legacy] error: y = b and y = b: same argument name diff --git a/testdata/p4_16_errors_outputs/p_e.p4-stderr b/testdata/p4_16_errors_outputs/p_e.p4-stderr index f784022d30f..47afa9e227e 100644 --- a/testdata/p4_16_errors_outputs/p_e.p4-stderr +++ b/testdata/p4_16_errors_outputs/p_e.p4-stderr @@ -1,4 +1,4 @@ p_e.p4(17):syntax error, unexpected END x ^ -[--Werror=overlimit] error: 1 errors encountered, aborting compilation +error: 1 errors encountered, aborting compilation diff --git a/testdata/p4_16_errors_outputs/package.p4-stderr b/testdata/p4_16_errors_outputs/package.p4-stderr index 03c5738ab2d..29994ef3646 100644 --- a/testdata/p4_16_errors_outputs/package.p4-stderr +++ b/testdata/p4_16_errors_outputs/package.p4-stderr @@ -1,3 +1,3 @@ -package.p4(18): [--Werror=invalid] error: _c: Invalid aragument. Constructor parameters cannot have a direction +package.p4(18): [--Werror=invalid] error: _c: invalid direction. Constructor parameters cannot have a direction package top(in proto _c); // Package should not have in parameters ^^ diff --git a/testdata/p4_16_errors_outputs/push_nonconstant.p4-stderr b/testdata/p4_16_errors_outputs/push_nonconstant.p4-stderr index 19a86f0e982..287452fb963 100644 --- a/testdata/p4_16_errors_outputs/push_nonconstant.p4-stderr +++ b/testdata/p4_16_errors_outputs/push_nonconstant.p4-stderr @@ -1,3 +1,3 @@ -push_nonconstant.p4(10): [--Werror=invalid] error: x: Invalid argument must be a constant +push_nonconstant.p4(10): [--Werror=invalid] error: x: argument must be a constant h.push_front(x); ^ diff --git a/testdata/p4_16_errors_outputs/shift_e.p4-stderr b/testdata/p4_16_errors_outputs/shift_e.p4-stderr index f9a2bf94901..bef3aba2db3 100644 --- a/testdata/p4_16_errors_outputs/shift_e.p4-stderr +++ b/testdata/p4_16_errors_outputs/shift_e.p4-stderr @@ -1,4 +1,4 @@ shift_e.p4(20):syntax error, unexpected > int<32> b = a > > ^ -[--Werror=overlimit] error: 1 errors encountered, aborting compilation +error: 1 errors encountered, aborting compilation diff --git a/testdata/p4_16_errors_outputs/spec-ex32_e.p4-stderr b/testdata/p4_16_errors_outputs/spec-ex32_e.p4-stderr index be181f89c60..5c816e7c6fb 100644 --- a/testdata/p4_16_errors_outputs/spec-ex32_e.p4-stderr +++ b/testdata/p4_16_errors_outputs/spec-ex32_e.p4-stderr @@ -1,3 +1,3 @@ -spec-ex32_e.p4(22): [--Werror=not-found] error: size2: Not found declaration +spec-ex32_e.p4(22): [--Werror=not-found] error: size2: declaration not found @length(size2) // illegal: cannot use size2, defined after data2 ^^^^^ diff --git a/testdata/p4_16_errors_outputs/table-entries-exact-ternary.p4-stderr b/testdata/p4_16_errors_outputs/table-entries-exact-ternary.p4-stderr index 6e0b9592474..f704439b796 100644 --- a/testdata/p4_16_errors_outputs/table-entries-exact-ternary.p4-stderr +++ b/testdata/p4_16_errors_outputs/table-entries-exact-ternary.p4-stderr @@ -1,4 +1,4 @@ table-entries-exact-ternary.p4(74):syntax error, unexpected ), expecting "," (0x1111 &&& 0xF ) ^ -[--Werror=overlimit] error: 1 errors encountered, aborting compilation +error: 1 errors encountered, aborting compilation diff --git a/testdata/p4_16_errors_outputs/table-entries-outside-table.p4-stderr b/testdata/p4_16_errors_outputs/table-entries-outside-table.p4-stderr index 2427fdf8f37..ebf016f8dea 100644 --- a/testdata/p4_16_errors_outputs/table-entries-outside-table.p4-stderr +++ b/testdata/p4_16_errors_outputs/table-entries-outside-table.p4-stderr @@ -1,4 +1,4 @@ table-entries-outside-table.p4(68):syntax error, unexpected ENTRIES const entries ^^^^^^^ -[--Werror=overlimit] error: 1 errors encountered, aborting compilation +error: 1 errors encountered, aborting compilation diff --git a/testdata/p4_16_errors_outputs/table-entries-ternary.p4-stderr b/testdata/p4_16_errors_outputs/table-entries-ternary.p4-stderr index 90083d6277d..74cf5924287 100644 --- a/testdata/p4_16_errors_outputs/table-entries-ternary.p4-stderr +++ b/testdata/p4_16_errors_outputs/table-entries-ternary.p4-stderr @@ -1,3 +1,3 @@ -table-entries-ternary.p4(76): [--Werror=not-found] error: missing_a: Not found declaration +table-entries-ternary.p4(76): [--Werror=not-found] error: missing_a: declaration not found 0x1111 : missing_a(); // action not in action list ^^^^^^^^^ diff --git a/testdata/p4_16_errors_outputs/template_e.p4-stderr b/testdata/p4_16_errors_outputs/template_e.p4-stderr index a1e5c305b06..4564b4539e6 100644 --- a/testdata/p4_16_errors_outputs/template_e.p4-stderr +++ b/testdata/p4_16_errors_outputs/template_e.p4-stderr @@ -10,4 +10,4 @@ package S template_e.p4(16) package S ^ -[--Werror=overlimit] error: 2 errors encountered, aborting compilation +error: 2 errors encountered, aborting compilation diff --git a/testdata/p4_16_errors_outputs/tuple-left.p4-stderr b/testdata/p4_16_errors_outputs/tuple-left.p4-stderr index 5c781882785..eac9a3418f4 100644 --- a/testdata/p4_16_errors_outputs/tuple-left.p4-stderr +++ b/testdata/p4_16_errors_outputs/tuple-left.p4-stderr @@ -1,4 +1,4 @@ tuple-left.p4(21):syntax error, unexpected "," { a, ^ -[--Werror=overlimit] error: 1 errors encountered, aborting compilation +error: 1 errors encountered, aborting compilation diff --git a/testdata/p4_16_errors_outputs/type-params_e.p4-stderr b/testdata/p4_16_errors_outputs/type-params_e.p4-stderr index 9f936b61eeb..6d2b6afb221 100644 --- a/testdata/p4_16_errors_outputs/type-params_e.p4-stderr +++ b/testdata/p4_16_errors_outputs/type-params_e.p4-stderr @@ -1,3 +1,3 @@ -type-params_e.p4(18): [--Werror=not-found] error: D: Not found declaration +type-params_e.p4(18): [--Werror=not-found] error: D: declaration not found package m(p m); ^ diff --git a/testdata/p4_16_errors_outputs/underscore1_e.p4-stderr b/testdata/p4_16_errors_outputs/underscore1_e.p4-stderr index e2887390cdc..6a7140b38cd 100644 --- a/testdata/p4_16_errors_outputs/underscore1_e.p4-stderr +++ b/testdata/p4_16_errors_outputs/underscore1_e.p4-stderr @@ -1,4 +1,4 @@ underscore1_e.p4(17):syntax error, unexpected _ bit _ ^ -[--Werror=overlimit] error: 1 errors encountered, aborting compilation +error: 1 errors encountered, aborting compilation diff --git a/testdata/p4_16_errors_outputs/underscore2_e.p4-stderr b/testdata/p4_16_errors_outputs/underscore2_e.p4-stderr index 959c67b3a36..44468409282 100644 --- a/testdata/p4_16_errors_outputs/underscore2_e.p4-stderr +++ b/testdata/p4_16_errors_outputs/underscore2_e.p4-stderr @@ -1,4 +1,4 @@ underscore2_e.p4(19):syntax error, unexpected _ bit _ ^ -[--Werror=overlimit] error: 1 errors encountered, aborting compilation +error: 1 errors encountered, aborting compilation diff --git a/testdata/p4_16_errors_outputs/underscore3_e.p4-stderr b/testdata/p4_16_errors_outputs/underscore3_e.p4-stderr index 70d29b6d9c8..f4e54ee33c0 100644 --- a/testdata/p4_16_errors_outputs/underscore3_e.p4-stderr +++ b/testdata/p4_16_errors_outputs/underscore3_e.p4-stderr @@ -1,4 +1,4 @@ underscore3_e.p4(16):syntax error, unexpected _ const bit _ ^ -[--Werror=overlimit] error: 1 errors encountered, aborting compilation +error: 1 errors encountered, aborting compilation diff --git a/testdata/p4_16_errors_outputs/underscore_e.p4-stderr b/testdata/p4_16_errors_outputs/underscore_e.p4-stderr index 447400231dc..6bba63599a6 100644 --- a/testdata/p4_16_errors_outputs/underscore_e.p4-stderr +++ b/testdata/p4_16_errors_outputs/underscore_e.p4-stderr @@ -1,4 +1,4 @@ underscore_e.p4(16):syntax error, unexpected _ extern void _ ^ -[--Werror=overlimit] error: 1 errors encountered, aborting compilation +error: 1 errors encountered, aborting compilation diff --git a/testdata/p4_16_errors_outputs/width_e.p4-stderr b/testdata/p4_16_errors_outputs/width_e.p4-stderr index 5c145288b68..9fa86e26928 100644 --- a/testdata/p4_16_errors_outputs/width_e.p4-stderr +++ b/testdata/p4_16_errors_outputs/width_e.p4-stderr @@ -1,4 +1,4 @@ width_e.p4(16): [--Werror=overlimit] error: 12301923123132: this implementation does not support bitstrings this large const bit<12301923123132> ^^^^^^^^^^^^^^ -[--Werror=overlimit] error: 1 errors encountered, aborting compilation +error: 1 errors encountered, aborting compilation From b3daaa25ebe88271b20e26ba91fa4583eff7ddce Mon Sep 17 00:00:00 2001 From: Mihai Budiu Date: Mon, 24 Feb 2020 14:11:40 -0800 Subject: [PATCH 092/106] Print correctly negative constants with InfInt types (#2209) --- frontends/p4/toP4/toP4.cpp | 11 +-- testdata/p4_16_samples/issue2208.p4 | 73 +++++++++++++++++++ .../p4_16_samples_outputs/issue2208-first.p4 | 61 ++++++++++++++++ .../issue2208-frontend.p4 | 58 +++++++++++++++ .../p4_16_samples_outputs/issue2208-midend.p4 | 68 +++++++++++++++++ testdata/p4_16_samples_outputs/issue2208.p4 | 61 ++++++++++++++++ .../p4_16_samples_outputs/issue2208.p4-stderr | 3 + .../issue2208.p4.entries.txt | 0 .../issue2208.p4.p4info.txt | 3 + 9 files changed, 333 insertions(+), 5 deletions(-) create mode 100644 testdata/p4_16_samples/issue2208.p4 create mode 100644 testdata/p4_16_samples_outputs/issue2208-first.p4 create mode 100644 testdata/p4_16_samples_outputs/issue2208-frontend.p4 create mode 100644 testdata/p4_16_samples_outputs/issue2208-midend.p4 create mode 100644 testdata/p4_16_samples_outputs/issue2208.p4 create mode 100644 testdata/p4_16_samples_outputs/issue2208.p4-stderr create mode 100644 testdata/p4_16_samples_outputs/issue2208.p4.entries.txt create mode 100644 testdata/p4_16_samples_outputs/issue2208.p4.p4info.txt diff --git a/frontends/p4/toP4/toP4.cpp b/frontends/p4/toP4/toP4.cpp index 6d8f76220a1..b9e02ca432e 100644 --- a/frontends/p4/toP4/toP4.cpp +++ b/frontends/p4/toP4/toP4.cpp @@ -555,13 +555,14 @@ bool ToP4::preorder(const IR::Type_Control* t) { bool ToP4::preorder(const IR::Constant* c) { big_int value = c->value; + big_int zero = 0; + if (value < zero) { + builder.append("-"); + value = -value; + } + const IR::Type_Bits* tb = dynamic_cast(c->type); if (tb != nullptr) { - big_int zero = 0; - if (value < zero) { - builder.append("-"); - value = -value; - } builder.appendFormat("%d", tb->size); builder.append(tb->isSigned ? "s" : "w"); } diff --git a/testdata/p4_16_samples/issue2208.p4 b/testdata/p4_16_samples/issue2208.p4 new file mode 100644 index 00000000000..3621c226675 --- /dev/null +++ b/testdata/p4_16_samples/issue2208.p4 @@ -0,0 +1,73 @@ +/* +Copyright 2017 VMware, 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 +#include + +header ethernet_t { + bit<48> dstAddr; + bit<48> srcAddr; + bit<16> etherType; +} + +header H { + bit<8> a; +} + +struct Parsed_packet { + ethernet_t eth; + H h; +} + +struct Metadata { +} + +control deparser(packet_out packet, in Parsed_packet hdr) { + apply { + packet.emit(hdr); + } +} + +parser p(packet_in pkt, out Parsed_packet hdr, inout Metadata meta, inout standard_metadata_t stdmeta) { + state start { + pkt.extract(hdr.eth); + transition parse_h; + } + state parse_h { + pkt.extract(hdr.h); + transition accept; + } +} + +control ingress(inout Parsed_packet hdr, inout Metadata meta, inout standard_metadata_t stdmeta) { + apply { + // underflows + hdr.h.a = 0 - 1; + } +} + +control egress(inout Parsed_packet hdr, inout Metadata meta, inout standard_metadata_t stdmeta) { + apply {} +} + +control vrfy(inout Parsed_packet hdr, inout Metadata meta) { + apply {} +} + +control update(inout Parsed_packet hdr, inout Metadata meta) { + apply {} +} + +V1Switch(p(), vrfy(), ingress(), egress(), update(), deparser()) main; diff --git a/testdata/p4_16_samples_outputs/issue2208-first.p4 b/testdata/p4_16_samples_outputs/issue2208-first.p4 new file mode 100644 index 00000000000..7fdf921ba6c --- /dev/null +++ b/testdata/p4_16_samples_outputs/issue2208-first.p4 @@ -0,0 +1,61 @@ +#include +#include + +header ethernet_t { + bit<48> dstAddr; + bit<48> srcAddr; + bit<16> etherType; +} + +header H { + bit<8> a; +} + +struct Parsed_packet { + ethernet_t eth; + H h; +} + +struct Metadata { +} + +control deparser(packet_out packet, in Parsed_packet hdr) { + apply { + packet.emit(hdr); + } +} + +parser p(packet_in pkt, out Parsed_packet hdr, inout Metadata meta, inout standard_metadata_t stdmeta) { + state start { + pkt.extract(hdr.eth); + transition parse_h; + } + state parse_h { + pkt.extract(hdr.h); + transition accept; + } +} + +control ingress(inout Parsed_packet hdr, inout Metadata meta, inout standard_metadata_t stdmeta) { + apply { + hdr.h.a = 8w255; + } +} + +control egress(inout Parsed_packet hdr, inout Metadata meta, inout standard_metadata_t stdmeta) { + apply { + } +} + +control vrfy(inout Parsed_packet hdr, inout Metadata meta) { + apply { + } +} + +control update(inout Parsed_packet hdr, inout Metadata meta) { + apply { + } +} + +V1Switch(p(), vrfy(), ingress(), egress(), update(), deparser()) main; + diff --git a/testdata/p4_16_samples_outputs/issue2208-frontend.p4 b/testdata/p4_16_samples_outputs/issue2208-frontend.p4 new file mode 100644 index 00000000000..66eb7dd1daf --- /dev/null +++ b/testdata/p4_16_samples_outputs/issue2208-frontend.p4 @@ -0,0 +1,58 @@ +#include +#include + +header ethernet_t { + bit<48> dstAddr; + bit<48> srcAddr; + bit<16> etherType; +} + +header H { + bit<8> a; +} + +struct Parsed_packet { + ethernet_t eth; + H h; +} + +struct Metadata { +} + +control deparser(packet_out packet, in Parsed_packet hdr) { + apply { + packet.emit(hdr); + } +} + +parser p(packet_in pkt, out Parsed_packet hdr, inout Metadata meta, inout standard_metadata_t stdmeta) { + state start { + pkt.extract(hdr.eth); + pkt.extract(hdr.h); + transition accept; + } +} + +control ingress(inout Parsed_packet hdr, inout Metadata meta, inout standard_metadata_t stdmeta) { + apply { + hdr.h.a = 8w255; + } +} + +control egress(inout Parsed_packet hdr, inout Metadata meta, inout standard_metadata_t stdmeta) { + apply { + } +} + +control vrfy(inout Parsed_packet hdr, inout Metadata meta) { + apply { + } +} + +control update(inout Parsed_packet hdr, inout Metadata meta) { + apply { + } +} + +V1Switch(p(), vrfy(), ingress(), egress(), update(), deparser()) main; + diff --git a/testdata/p4_16_samples_outputs/issue2208-midend.p4 b/testdata/p4_16_samples_outputs/issue2208-midend.p4 new file mode 100644 index 00000000000..616a8864f83 --- /dev/null +++ b/testdata/p4_16_samples_outputs/issue2208-midend.p4 @@ -0,0 +1,68 @@ +#include +#include + +header ethernet_t { + bit<48> dstAddr; + bit<48> srcAddr; + bit<16> etherType; +} + +header H { + bit<8> a; +} + +struct Parsed_packet { + ethernet_t eth; + H h; +} + +struct Metadata { +} + +control deparser(packet_out packet, in Parsed_packet hdr) { + apply { + packet.emit(hdr.eth); + packet.emit(hdr.h); + } +} + +parser p(packet_in pkt, out Parsed_packet hdr, inout Metadata meta, inout standard_metadata_t stdmeta) { + state start { + pkt.extract(hdr.eth); + pkt.extract(hdr.h); + transition accept; + } +} + +control ingress(inout Parsed_packet hdr, inout Metadata meta, inout standard_metadata_t stdmeta) { + @hidden action issue2208l57() { + hdr.h.a = 8w255; + } + @hidden table tbl_issue2208l57 { + actions = { + issue2208l57(); + } + const default_action = issue2208l57(); + } + apply { + tbl_issue2208l57.apply(); + } +} + +control egress(inout Parsed_packet hdr, inout Metadata meta, inout standard_metadata_t stdmeta) { + apply { + } +} + +control vrfy(inout Parsed_packet hdr, inout Metadata meta) { + apply { + } +} + +control update(inout Parsed_packet hdr, inout Metadata meta) { + apply { + } +} + +V1Switch(p(), vrfy(), ingress(), egress(), update(), deparser()) main; + diff --git a/testdata/p4_16_samples_outputs/issue2208.p4 b/testdata/p4_16_samples_outputs/issue2208.p4 new file mode 100644 index 00000000000..8edd2e3ed5e --- /dev/null +++ b/testdata/p4_16_samples_outputs/issue2208.p4 @@ -0,0 +1,61 @@ +#include +#include + +header ethernet_t { + bit<48> dstAddr; + bit<48> srcAddr; + bit<16> etherType; +} + +header H { + bit<8> a; +} + +struct Parsed_packet { + ethernet_t eth; + H h; +} + +struct Metadata { +} + +control deparser(packet_out packet, in Parsed_packet hdr) { + apply { + packet.emit(hdr); + } +} + +parser p(packet_in pkt, out Parsed_packet hdr, inout Metadata meta, inout standard_metadata_t stdmeta) { + state start { + pkt.extract(hdr.eth); + transition parse_h; + } + state parse_h { + pkt.extract(hdr.h); + transition accept; + } +} + +control ingress(inout Parsed_packet hdr, inout Metadata meta, inout standard_metadata_t stdmeta) { + apply { + hdr.h.a = 0 - 1; + } +} + +control egress(inout Parsed_packet hdr, inout Metadata meta, inout standard_metadata_t stdmeta) { + apply { + } +} + +control vrfy(inout Parsed_packet hdr, inout Metadata meta) { + apply { + } +} + +control update(inout Parsed_packet hdr, inout Metadata meta) { + apply { + } +} + +V1Switch(p(), vrfy(), ingress(), egress(), update(), deparser()) main; + diff --git a/testdata/p4_16_samples_outputs/issue2208.p4-stderr b/testdata/p4_16_samples_outputs/issue2208.p4-stderr new file mode 100644 index 00000000000..ddf263b63fb --- /dev/null +++ b/testdata/p4_16_samples_outputs/issue2208.p4-stderr @@ -0,0 +1,3 @@ +issue2208.p4(57): [--Wwarn=mismatch] warning: -1: negative value with unsigned type + hdr.h.a = 0 - 1; + ^^^^^ diff --git a/testdata/p4_16_samples_outputs/issue2208.p4.entries.txt b/testdata/p4_16_samples_outputs/issue2208.p4.entries.txt new file mode 100644 index 00000000000..e69de29bb2d diff --git a/testdata/p4_16_samples_outputs/issue2208.p4.p4info.txt b/testdata/p4_16_samples_outputs/issue2208.p4.p4info.txt new file mode 100644 index 00000000000..9ec92493e4c --- /dev/null +++ b/testdata/p4_16_samples_outputs/issue2208.p4.p4info.txt @@ -0,0 +1,3 @@ +pkg_info { + arch: "v1model" +} From 5b1a5025fb7a3e2e1cdedabb7909e80e8f27a1a2 Mon Sep 17 00:00:00 2001 From: Mihai Budiu Date: Wed, 26 Feb 2020 09:38:29 -0800 Subject: [PATCH 093/106] Fix gcc warnings (#2211) --- backends/bmv2/common/expression.cpp | 5 ++++- frontends/common/options.cpp | 3 ++- ir/type.def | 11 +---------- lib/source_file.h | 1 + 4 files changed, 8 insertions(+), 12 deletions(-) diff --git a/backends/bmv2/common/expression.cpp b/backends/bmv2/common/expression.cpp index 5c1b8b9c9c8..f903bd52784 100644 --- a/backends/bmv2/common/expression.cpp +++ b/backends/bmv2/common/expression.cpp @@ -404,7 +404,7 @@ void ExpressionConverter::postorder(const IR::Member* expression) { e->emplace("right", l); } else { const char* fieldRef = parentType->is() ? "stack_field" : "field"; - Util::JsonArray* e; + Util::JsonArray* e = nullptr; bool st = isArrayIndexRuntime(expression); if (!st) { result->emplace("type", fieldRef); @@ -421,11 +421,13 @@ void ExpressionConverter::postorder(const IR::Member* expression) { auto first = array->at(0); auto second = array->at(1); BUG_CHECK(second->is(), "expected a value"); + CHECK_NULL(e); e->append(first); cstring nestedField = second->to()->getString(); nestedField += "." + fieldName; e->append(nestedField); } else if (lv->is()) { + CHECK_NULL(e); e->append(lv); e->append(fieldName); } else if (auto jo = l->to()) { @@ -445,6 +447,7 @@ void ExpressionConverter::postorder(const IR::Member* expression) { BUG("%1%: Unexpected json", lv); } } else { + CHECK_NULL(e); e->append(l); e->append(fieldName); } diff --git a/frontends/common/options.cpp b/frontends/common/options.cpp index 72fd21f4522..68f3ee2374b 100644 --- a/frontends/common/options.cpp +++ b/frontends/common/options.cpp @@ -276,7 +276,8 @@ static void convertToAbsPath(const char* const relPath, char (&output)[N]) { // Construct an absolute path. We're assuming that @relPath is relative to // the current working directory. - snprintf(output, N, "%s%s%s", cwd, separator, relPath); + int n = snprintf(output, N, "%s%s%s", cwd, separator, relPath); + BUG_CHECK(n >= 0, "Pathname too long"); } bool setIncludePathIfExists(const char*& includePathOut, diff --git a/ir/type.def b/ir/type.def index 768933a6094..f1c6b9e7191 100644 --- a/ir/type.def +++ b/ir/type.def @@ -170,17 +170,8 @@ class Type_InfInt : Type, ITypeVar { toString { return "int"; } operator== { return declid == a.declid; } equiv { - #if __llvm__ - #pragma unused (a) - #endif - #if __GNUC__ - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wunused-variable" - #endif + (void)a; // silence unused warning return true; /* ignore declid */ - #if __GNUC__ - #pragma GCC diagnostic pop - #endif } const Type* getP4Type() const override { return this; } } diff --git a/lib/source_file.h b/lib/source_file.h index f4e6d6c7e77..984b03d6bb8 100644 --- a/lib/source_file.h +++ b/lib/source_file.h @@ -56,6 +56,7 @@ class SourcePosition final { columnNumber(0) {} SourcePosition(unsigned lineNumber, unsigned columnNumber); + SourcePosition& operator=(const SourcePosition&) = default; SourcePosition(const SourcePosition& other) : lineNumber(other.lineNumber), From c30069511c4f9f5d16189630ecabe67967bd9a5c Mon Sep 17 00:00:00 2001 From: Chris Dodd Date: Wed, 26 Feb 2020 14:30:39 -0800 Subject: [PATCH 094/106] Use relative paths for symlinks (#2215) --- backends/bmv2/CMakeLists.txt | 8 ++++---- backends/ebpf/CMakeLists.txt | 6 +++--- backends/graphs/CMakeLists.txt | 2 +- backends/p4test/CMakeLists.txt | 6 +++--- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/backends/bmv2/CMakeLists.txt b/backends/bmv2/CMakeLists.txt index 77cfd75fe38..fe20d935a14 100644 --- a/backends/bmv2/CMakeLists.txt +++ b/backends/bmv2/CMakeLists.txt @@ -103,10 +103,10 @@ install(TARGETS p4c-bm2-psa RUNTIME DESTINATION ${P4C_RUNTIME_OUTPUT_DIRECTORY}) # binary to be in the top level directory. This should go away when we # remove automake and fix the scripts. add_custom_target(linkbmv2 - COMMAND ${CMAKE_COMMAND} -E create_symlink ${CMAKE_CURRENT_BINARY_DIR}/p4c-bm2-ss ${P4C_BINARY_DIR}/p4c-bm2-ss - COMMAND ${CMAKE_COMMAND} -E create_symlink ${CMAKE_CURRENT_BINARY_DIR}/p4c-bm2-psa ${P4C_BINARY_DIR}/p4c-bm2-psa - COMMAND ${CMAKE_COMMAND} -E create_symlink ${P4C_BINARY_DIR}/p4include ${CMAKE_CURRENT_BINARY_DIR}/p4include - COMMAND ${CMAKE_COMMAND} -E create_symlink ${P4C_BINARY_DIR}/p4_14include ${CMAKE_CURRENT_BINARY_DIR}/p4_14include + COMMAND ${CMAKE_COMMAND} -E create_symlink `realpath --relative-to=${P4C_BINARY_DIR} ${CMAKE_CURRENT_BINARY_DIR}/p4c-bm2-ss` ${P4C_BINARY_DIR}/p4c-bm2-ss + COMMAND ${CMAKE_COMMAND} -E create_symlink `realpath --relative-to=${P4C_BINARY_DIR} ${CMAKE_CURRENT_BINARY_DIR}/p4c-bm2-psa` ${P4C_BINARY_DIR}/p4c-bm2-psa + COMMAND ${CMAKE_COMMAND} -E create_symlink `realpath --relative-to=${CMAKE_CURRENT_BINARY_DIR} ${P4C_BINARY_DIR}/p4include` ${CMAKE_CURRENT_BINARY_DIR}/p4include + COMMAND ${CMAKE_COMMAND} -E create_symlink `realpath --relative-to=${CMAKE_CURRENT_BINARY_DIR} ${P4C_BINARY_DIR}/p4_14include` ${CMAKE_CURRENT_BINARY_DIR}/p4_14include ) add_dependencies(p4c_driver linkbmv2) diff --git a/backends/ebpf/CMakeLists.txt b/backends/ebpf/CMakeLists.txt index 728a85bb23c..16a7a408d13 100644 --- a/backends/ebpf/CMakeLists.txt +++ b/backends/ebpf/CMakeLists.txt @@ -83,11 +83,11 @@ install (DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/p4include # binary to be in the top level directory. This should go away when we # remove automake and fix the scripts. add_custom_target(linkp4cebpf - COMMAND ${CMAKE_COMMAND} -E create_symlink ${CMAKE_CURRENT_BINARY_DIR}/p4c-ebpf ${P4C_BINARY_DIR}/p4c-ebpf + COMMAND ${CMAKE_COMMAND} -E create_symlink `realpath --relative-to=${P4C_BINARY_DIR} ${CMAKE_CURRENT_BINARY_DIR}/p4c-ebpf` ${P4C_BINARY_DIR}/p4c-ebpf COMMAND ${CMAKE_COMMAND} -E make_directory ${P4C_BINARY_DIR}/p4include && ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/${P4C_EBPF_DIST_HEADERS} ${P4C_BINARY_DIR}/p4include - COMMAND ${CMAKE_COMMAND} -E create_symlink ${P4C_BINARY_DIR}/p4include ${CMAKE_CURRENT_BINARY_DIR}/p4include - COMMAND ${CMAKE_COMMAND} -E create_symlink ${P4C_BINARY_DIR}/p4_14include ${CMAKE_CURRENT_BINARY_DIR}/p4_14include + COMMAND ${CMAKE_COMMAND} -E create_symlink `realpath --relative-to=${CMAKE_CURRENT_BINARY_DIR} ${P4C_BINARY_DIR}/p4include` ${CMAKE_CURRENT_BINARY_DIR}/p4include + COMMAND ${CMAKE_COMMAND} -E create_symlink `realpath --relative-to=${CMAKE_CURRENT_BINARY_DIR} ${P4C_BINARY_DIR}/p4_14include` ${CMAKE_CURRENT_BINARY_DIR}/p4_14include ) add_dependencies(p4c_driver linkp4cebpf) diff --git a/backends/graphs/CMakeLists.txt b/backends/graphs/CMakeLists.txt index 8994d104dc9..d3e3b02b0c7 100644 --- a/backends/graphs/CMakeLists.txt +++ b/backends/graphs/CMakeLists.txt @@ -41,6 +41,6 @@ install (TARGETS p4c-graphs # This link is not required but it is convenient to have access to this # backend in the top-level build directory, along with all the other backends. add_custom_target(linkgraphs - COMMAND ${CMAKE_COMMAND} -E create_symlink ${CMAKE_CURRENT_BINARY_DIR}/p4c-graphs ${P4C_BINARY_DIR}/p4c-graphs + COMMAND ${CMAKE_COMMAND} -E create_symlink `realpath --relative-to=${P4C_BINARY_DIR} ${CMAKE_CURRENT_BINARY_DIR}/p4c-graphs` ${P4C_BINARY_DIR}/p4c-graphs ) add_dependencies(p4c_driver linkgraphs) diff --git a/backends/p4test/CMakeLists.txt b/backends/p4test/CMakeLists.txt index 4698f7a87c2..bc5b9bb99b5 100644 --- a/backends/p4test/CMakeLists.txt +++ b/backends/p4test/CMakeLists.txt @@ -39,9 +39,9 @@ install (TARGETS p4test # binary to be in the top level directory. This should go away when we # remove automake and fix the scripts. add_custom_target(linkp4test - COMMAND ${CMAKE_COMMAND} -E create_symlink ${CMAKE_CURRENT_BINARY_DIR}/p4test ${P4C_BINARY_DIR}/p4test - COMMAND ${CMAKE_COMMAND} -E create_symlink ${P4C_BINARY_DIR}/p4include ${CMAKE_CURRENT_BINARY_DIR}/p4include - COMMAND ${CMAKE_COMMAND} -E create_symlink ${P4C_BINARY_DIR}/p4_14include ${CMAKE_CURRENT_BINARY_DIR}/p4_14include + COMMAND ${CMAKE_COMMAND} -E create_symlink `realpath --relative-to=${P4C_BINARY_DIR} ${CMAKE_CURRENT_BINARY_DIR}/p4test` ${P4C_BINARY_DIR}/p4test + COMMAND ${CMAKE_COMMAND} -E create_symlink `realpath --relative-to=${CMAKE_CURRENT_BINARY_DIR} ${P4C_BINARY_DIR}/p4include` ${CMAKE_CURRENT_BINARY_DIR}/p4include + COMMAND ${CMAKE_COMMAND} -E create_symlink `realpath --relative-to=${CMAKE_CURRENT_BINARY_DIR} ${P4C_BINARY_DIR}/p4_14include` ${CMAKE_CURRENT_BINARY_DIR}/p4_14include ) add_dependencies(p4c_driver linkp4test) From 24eac9218db78307bf22924092a1202e11521ebc Mon Sep 17 00:00:00 2001 From: Antonin Bas Date: Wed, 26 Feb 2020 15:15:13 -0800 Subject: [PATCH 095/106] Warn in bmv2 backend about unsupported match types in value_sets (#2214) bmv2 only supports exact matches, and a warning is better than silently ignoring the @match annotation. --- backends/bmv2/common/parser.cpp | 45 +++++++++++++++---- backends/bmv2/common/parser.h | 1 + .../select-struct-frontend.p4 | 1 + .../select-struct-midend.p4 | 1 + 4 files changed, 39 insertions(+), 9 deletions(-) diff --git a/backends/bmv2/common/parser.cpp b/backends/bmv2/common/parser.cpp index 09fa72a8315..02a110c4320 100644 --- a/backends/bmv2/common/parser.cpp +++ b/backends/bmv2/common/parser.cpp @@ -18,6 +18,7 @@ limitations under the License. #include "JsonObjects.h" #include "backend.h" #include "extern.h" +#include "frontends/p4/coreLibrary.h" #include "frontends/p4/fromv1.0/v1model.h" namespace BMV2 { @@ -444,19 +445,45 @@ ParserConverter::createDefaultTransition() { return trans; } -bool ParserConverter::preorder(const IR::P4Parser* parser) { - auto parser_id = ctxt->json->add_parser(name); +void ParserConverter::addValueSets(const IR::P4Parser* parser) { + auto isExactMatch = [this](const IR::StructField* sf) { + auto matchAnnotation = sf->getAnnotation(IR::Annotation::matchAnnotation); + if (!matchAnnotation) return true; // default (missing annotation) is exact + auto matchPathExpr = matchAnnotation->expr[0]->to(); + CHECK_NULL(matchPathExpr); + auto matchTypeDecl = ctxt->refMap->getDeclaration(matchPathExpr->path, true) + ->to(); + BUG_CHECK(matchTypeDecl != nullptr, "No declaration for match type '%1%'", matchPathExpr); + return (matchTypeDecl->name.name == P4::P4CoreLibrary::instance.exactMatch.name); + }; for (auto s : parser->parserLocals) { - if (auto inst = s->to()) { - auto etype = ctxt->typeMap->getTypeType(inst->elementType, true); - auto bitwidth = etype->width_bits(); - auto name = inst->controlPlaneName(); - auto size = inst->size; - auto n = size->to()->value; - ctxt->json->add_parse_vset(name, bitwidth, n); + if (!s->is()) continue; + + auto inst = s->to(); + auto etype = ctxt->typeMap->getTypeType(inst->elementType, true); + + if (auto st = etype->to()) { + for (auto f : st->fields) { + if (isExactMatch(f)) continue; + ::warning(ErrorType::WARN_UNSUPPORTED, + "This backend only supports exact matches in value_sets but the match " + "on '%1%' is not exact; the annotation will be ignored", f); + } } + + auto bitwidth = etype->width_bits(); + auto name = inst->controlPlaneName(); + auto size = inst->size; + auto n = size->to()->value; + ctxt->json->add_parse_vset(name, bitwidth, n); } +} + +bool ParserConverter::preorder(const IR::P4Parser* parser) { + auto parser_id = ctxt->json->add_parser(name); + + addValueSets(parser); // convert parse state for (auto state : parser->states) { diff --git a/backends/bmv2/common/parser.h b/backends/bmv2/common/parser.h index 52dd7a33171..3af378e45e7 100644 --- a/backends/bmv2/common/parser.h +++ b/backends/bmv2/common/parser.h @@ -44,6 +44,7 @@ class ParserConverter : public Inspector { Util::IJson* createDefaultTransition(); cstring jsonAssignment(const IR::Type* type, bool inParser); std::vector convertSelectExpression(const IR::SelectExpression* expr); + void addValueSets(const IR::P4Parser* parser); public: bool preorder(const IR::P4Parser* p) override; diff --git a/testdata/p4_16_samples_outputs/select-struct-frontend.p4 b/testdata/p4_16_samples_outputs/select-struct-frontend.p4 index 46cad875b36..1693fe31d30 100644 --- a/testdata/p4_16_samples_outputs/select-struct-frontend.p4 +++ b/testdata/p4_16_samples_outputs/select-struct-frontend.p4 @@ -23,3 +23,4 @@ parser p() { parser s(); package top(s _s); top(p()) main; + diff --git a/testdata/p4_16_samples_outputs/select-struct-midend.p4 b/testdata/p4_16_samples_outputs/select-struct-midend.p4 index 5b7174a5c53..71840f95d21 100644 --- a/testdata/p4_16_samples_outputs/select-struct-midend.p4 +++ b/testdata/p4_16_samples_outputs/select-struct-midend.p4 @@ -14,3 +14,4 @@ parser p() { parser s(); package top(s _s); top(p()) main; + From 54af98a909fa2767a982114efa68b3e2807d8ca0 Mon Sep 17 00:00:00 2001 From: Mihai Budiu Date: Wed, 26 Feb 2020 18:23:47 -0800 Subject: [PATCH 096/106] Reject value sets with masks (#2199) * Report error for p4-14 value sets with masks * cpplint * Default mask is -1 --- frontends/p4/fromv1.0/programStructure.cpp | 9 ++++++- testdata/p4_14_errors/issue2188.p4 | 25 +++++++++++++++++++ .../p4_14_errors_outputs/issue2188.p4-stderr | 7 ++++++ 3 files changed, 40 insertions(+), 1 deletion(-) create mode 100644 testdata/p4_14_errors/issue2188.p4 create mode 100644 testdata/p4_14_errors_outputs/issue2188.p4-stderr diff --git a/frontends/p4/fromv1.0/programStructure.cpp b/frontends/p4/fromv1.0/programStructure.cpp index 9bfa3c027e8..a15516e2035 100644 --- a/frontends/p4/fromv1.0/programStructure.cpp +++ b/frontends/p4/fromv1.0/programStructure.cpp @@ -376,7 +376,7 @@ const IR::PathExpression* ProgramStructure::getState(IR::ID dest) { const IR::Expression* ProgramStructure::explodeLabel(const IR::Constant* value, const IR::Constant* mask, - const std::vector &fieldTypes) { + const std::vector &fieldTypes) { if (mask->value == 0) return new IR::DefaultExpression(value->srcInfo); bool useMask = mask->value != -1; @@ -492,6 +492,13 @@ const IR::ParserState* ProgramStructure::convertParser(const IR::V1Parser* parse auto sc = new IR::SelectCase(c->srcInfo, expr, deststate); cases.push_back(sc); } else { + auto c = v.second->to(); + CHECK_NULL(c); // this is enforced elsewhere + if (!c->fitsInt() || c->asInt() != -1) { + ::error(ErrorType::ERR_INVALID, + ": masks not supported for value sets", c); + continue; + } auto sc = new IR::SelectCase(c->srcInfo, v.first, deststate); cases.push_back(sc); } diff --git a/testdata/p4_14_errors/issue2188.p4 b/testdata/p4_14_errors/issue2188.p4 new file mode 100644 index 00000000000..5475125bca7 --- /dev/null +++ b/testdata/p4_14_errors/issue2188.p4 @@ -0,0 +1,25 @@ +header_type ethernet_t { + fields { + dst_addr : 48; // width in bits + src_addr : 48; + etherType : 16; + } +} +header ethernet_t ethernet; + +parser_value_set pvs0; + +parser start { + return parse_ethernet; +} + +parser parse_ethernet { + extract(ethernet); + return select(latest.etherType) { + pvs0 mask 0x0ff0 : ingress; // <--- this is the most significant line of the example + default : ingress; + } +} + +control ingress { +} \ No newline at end of file diff --git a/testdata/p4_14_errors_outputs/issue2188.p4-stderr b/testdata/p4_14_errors_outputs/issue2188.p4-stderr new file mode 100644 index 00000000000..8bf88413201 --- /dev/null +++ b/testdata/p4_14_errors_outputs/issue2188.p4-stderr @@ -0,0 +1,7 @@ +issue2188.p4(19): [--Wwarn=missing] warning: CaseEntry: parser_value_set has no @parser_value_set_size annotation.Using default size 4. + pvs0 mask 0x0ff0 : ingress; // <--- this is the most significant line of the example + ^^^^^^^^^^^^^^^^ +issue2188.p4(19): [--Werror=invalid] error: 0xff0: Invalid : masks not supported for value sets + pvs0 mask 0x0ff0 : ingress; // <--- this is the most significant line of the example + ^^^^^^ +[--Werror=overlimit] error: 1 errors encountered, aborting compilation From e9a53907b26a31c0b9572563362d6328a63b6e17 Mon Sep 17 00:00:00 2001 From: Mihai Budiu Date: Wed, 26 Feb 2020 20:06:21 -0800 Subject: [PATCH 097/106] Add only compatible values; fixes #2190 (#2193) * Add only compatible values; fixes #2190 --- frontends/p4/frontend.cpp | 9 +-- frontends/p4/strengthReduction.cpp | 22 +++++-- .../09-IPv4OptionsUnparsed-first.p4 | 4 +- .../09-IPv4OptionsUnparsed-frontend.p4 | 4 +- .../p4_14_samples_outputs/issue576-first.p4 | 6 +- .../issue576-frontend.p4 | 6 +- .../p4_14_samples_outputs/issue781-first.p4 | 4 +- .../issue781-frontend.p4 | 4 +- testdata/p4_16_samples/issue2190.p4 | 40 +++++++++++++ .../bitwise-and-first.p4 | 4 +- .../issue1713-bmv2-first.p4 | 2 +- .../p4_16_samples_outputs/issue2190-first.p4 | 50 ++++++++++++++++ .../issue2190-frontend.p4 | 49 ++++++++++++++++ .../p4_16_samples_outputs/issue2190-midend.p4 | 58 +++++++++++++++++++ testdata/p4_16_samples_outputs/issue2190.p4 | 50 ++++++++++++++++ .../p4_16_samples_outputs/issue2190.p4-stderr | 0 .../issue2190.p4.entries.txt | 0 .../issue2190.p4.p4info.txt | 3 + .../p4_16_samples_outputs/precedence-first.p4 | 2 +- .../p4_16_samples_outputs/strength-first.p4 | 2 +- .../p4_16_samples_outputs/strength3-first.p4 | 10 ++-- .../strength3-frontend.p4 | 4 +- .../p4_16_samples_outputs/strength4-first.p4 | 4 +- .../strength4-frontend.p4 | 2 +- .../p4_16_samples_outputs/strength5-first.p4 | 2 +- 25 files changed, 300 insertions(+), 41 deletions(-) create mode 100644 testdata/p4_16_samples/issue2190.p4 create mode 100644 testdata/p4_16_samples_outputs/issue2190-first.p4 create mode 100644 testdata/p4_16_samples_outputs/issue2190-frontend.p4 create mode 100644 testdata/p4_16_samples_outputs/issue2190-midend.p4 create mode 100644 testdata/p4_16_samples_outputs/issue2190.p4 create mode 100644 testdata/p4_16_samples_outputs/issue2190.p4-stderr create mode 100644 testdata/p4_16_samples_outputs/issue2190.p4.entries.txt create mode 100644 testdata/p4_16_samples_outputs/issue2190.p4.p4info.txt diff --git a/frontends/p4/frontend.cpp b/frontends/p4/frontend.cpp index c38e26a057f..195d03af545 100644 --- a/frontends/p4/frontend.cpp +++ b/frontends/p4/frontend.cpp @@ -151,10 +151,11 @@ const IR::P4Program *FrontEnd::run(const CompilerOptions &options, const IR::P4P new BindTypeVariables(&refMap, &typeMap), new StructInitializers(&refMap, &typeMap), new TableKeyNames(&refMap, &typeMap), - // Another round of constant folding, using type information. - new ConstantFolding(&refMap, &typeMap), - new StrengthReduction(&refMap, &typeMap), - new UselessCasts(&refMap, &typeMap), + new PassRepeated({ + new ConstantFolding(&refMap, &typeMap), + new StrengthReduction(&refMap, &typeMap), + new UselessCasts(&refMap, &typeMap) + }), new SimplifyControlFlow(&refMap, &typeMap), new SwitchAddDefault, new FrontEndDump(), // used for testing the program at this point diff --git a/frontends/p4/strengthReduction.cpp b/frontends/p4/strengthReduction.cpp index 933c84ede77..0fddaab64aa 100644 --- a/frontends/p4/strengthReduction.cpp +++ b/frontends/p4/strengthReduction.cpp @@ -189,9 +189,14 @@ const IR::Node* DoStrengthReduction::postorder(IR::Shl* expr) { if (isZero(expr->right) || isZero(expr->left)) return expr->left; if (auto sh2 = expr->left->to()) { - // (a << b) << c is a << (b + c) - return new IR::Shl(expr->srcInfo, sh2->left, - new IR::Add(expr->srcInfo, sh2->right, expr->right)); + if (sh2->right->type->is() && + expr->right->type->is()) { + // (a << b) << c is a << (b + c) + auto result = new IR::Shl(expr->srcInfo, sh2->left, + new IR::Add(expr->srcInfo, sh2->right, expr->right)); + LOG3("Replace " << expr << " with " << result); + return result; + } } return expr; } @@ -200,9 +205,14 @@ const IR::Node* DoStrengthReduction::postorder(IR::Shr* expr) { if (isZero(expr->right) || isZero(expr->left)) return expr->left; if (auto sh2 = expr->left->to()) { - // (a >> b) >> c is a >> (b + c) - return new IR::Shr(expr->srcInfo, sh2->left, - new IR::Add(expr->srcInfo, sh2->right, expr->right)); + if (sh2->right->type->is() && + expr->right->type->is()) { + // (a >> b) >> c is a >> (b + c) + auto result = new IR::Shr(expr->srcInfo, sh2->left, + new IR::Add(expr->srcInfo, sh2->right, expr->right)); + LOG3("Replace " << expr << " with " << result); + return result; + } } return expr; } diff --git a/testdata/p4_14_samples_outputs/09-IPv4OptionsUnparsed-first.p4 b/testdata/p4_14_samples_outputs/09-IPv4OptionsUnparsed-first.p4 index 7478e8e4e62..354dce33d05 100644 --- a/testdata/p4_14_samples_outputs/09-IPv4OptionsUnparsed-first.p4 +++ b/testdata/p4_14_samples_outputs/09-IPv4OptionsUnparsed-first.p4 @@ -39,7 +39,7 @@ header ipv4_t { bit<16> hdrChecksum; bit<32> srcAddr; bit<32> dstAddr; - @length(((bit<32>)ihl << 2 << 3) + 32w4294967136) + @length(((bit<32>)ihl << 5) + 32w4294967136) varbit<352> options; } @@ -74,7 +74,7 @@ parser ParserImpl(packet_in packet, out headers hdr, inout metadata meta, inout } @name(".parse_ipv4") state parse_ipv4 { tmp_hdr = packet.lookahead(); - packet.extract(hdr.ipv4, ((bit<32>)tmp_hdr.ihl << 2 << 3) + 32w4294967136); + packet.extract(hdr.ipv4, ((bit<32>)tmp_hdr.ihl << 5) + 32w4294967136); transition accept; } @name(".parse_vlan_tag") state parse_vlan_tag { diff --git a/testdata/p4_14_samples_outputs/09-IPv4OptionsUnparsed-frontend.p4 b/testdata/p4_14_samples_outputs/09-IPv4OptionsUnparsed-frontend.p4 index d2f37fd0b1e..57b90c222a9 100644 --- a/testdata/p4_14_samples_outputs/09-IPv4OptionsUnparsed-frontend.p4 +++ b/testdata/p4_14_samples_outputs/09-IPv4OptionsUnparsed-frontend.p4 @@ -39,7 +39,7 @@ header ipv4_t { bit<16> hdrChecksum; bit<32> srcAddr; bit<32> dstAddr; - @length(((bit<32>)ihl << 2 << 3) + 32w4294967136) + @length(((bit<32>)ihl << 5) + 32w4294967136) varbit<352> options; } @@ -74,7 +74,7 @@ parser ParserImpl(packet_in packet, out headers hdr, inout metadata meta, inout } @name(".parse_ipv4") state parse_ipv4 { tmp_hdr_0 = packet.lookahead(); - packet.extract(hdr.ipv4, ((bit<32>)tmp_hdr_0.ihl << 2 << 3) + 32w4294967136); + packet.extract(hdr.ipv4, ((bit<32>)tmp_hdr_0.ihl << 5) + 32w4294967136); transition accept; } @name(".parse_vlan_tag") state parse_vlan_tag { diff --git a/testdata/p4_14_samples_outputs/issue576-first.p4 b/testdata/p4_14_samples_outputs/issue576-first.p4 index f815c65a2da..d57ee04a72e 100644 --- a/testdata/p4_14_samples_outputs/issue576-first.p4 +++ b/testdata/p4_14_samples_outputs/issue576-first.p4 @@ -29,7 +29,7 @@ header ipv4_t { bit<16> hdrChecksum; bit<32> srcAddr; bit<32> dstAddr; - @length(((bit<32>)ihl << 2 << 3) + 32w4294967136) + @length(((bit<32>)ihl << 5) + 32w4294967136) varbit<320> options_ipv4; } @@ -65,9 +65,9 @@ parser ParserImpl(packet_in packet, out headers hdr, inout metadata meta, inout packet.extract(hdr.sh.next); packet.extract(hdr.sh.next); tmp_hdr = packet.lookahead(); - packet.extract(hdr.h.next, ((bit<32>)tmp_hdr.ihl << 2 << 3) + 32w4294967136); + packet.extract(hdr.h.next, ((bit<32>)tmp_hdr.ihl << 5) + 32w4294967136); tmp_hdr_0 = packet.lookahead(); - packet.extract(hdr.h.next, ((bit<32>)tmp_hdr_0.ihl << 2 << 3) + 32w4294967136); + packet.extract(hdr.h.next, ((bit<32>)tmp_hdr_0.ihl << 5) + 32w4294967136); transition accept; } } diff --git a/testdata/p4_14_samples_outputs/issue576-frontend.p4 b/testdata/p4_14_samples_outputs/issue576-frontend.p4 index 1bf109f1a8c..3737538db09 100644 --- a/testdata/p4_14_samples_outputs/issue576-frontend.p4 +++ b/testdata/p4_14_samples_outputs/issue576-frontend.p4 @@ -29,7 +29,7 @@ header ipv4_t { bit<16> hdrChecksum; bit<32> srcAddr; bit<32> dstAddr; - @length(((bit<32>)ihl << 2 << 3) + 32w4294967136) + @length(((bit<32>)ihl << 5) + 32w4294967136) varbit<320> options_ipv4; } @@ -65,9 +65,9 @@ parser ParserImpl(packet_in packet, out headers hdr, inout metadata meta, inout packet.extract(hdr.sh.next); packet.extract(hdr.sh.next); tmp_hdr_1 = packet.lookahead(); - packet.extract(hdr.h.next, ((bit<32>)tmp_hdr_1.ihl << 2 << 3) + 32w4294967136); + packet.extract(hdr.h.next, ((bit<32>)tmp_hdr_1.ihl << 5) + 32w4294967136); tmp_hdr_2 = packet.lookahead(); - packet.extract(hdr.h.next, ((bit<32>)tmp_hdr_2.ihl << 2 << 3) + 32w4294967136); + packet.extract(hdr.h.next, ((bit<32>)tmp_hdr_2.ihl << 5) + 32w4294967136); transition accept; } } diff --git a/testdata/p4_14_samples_outputs/issue781-first.p4 b/testdata/p4_14_samples_outputs/issue781-first.p4 index a3a337cef30..2365446f1a2 100644 --- a/testdata/p4_14_samples_outputs/issue781-first.p4 +++ b/testdata/p4_14_samples_outputs/issue781-first.p4 @@ -29,7 +29,7 @@ header ipv4_t { bit<16> hdrChecksum; bit<32> srcAddr; bit<32> dstAddr; - @length(((bit<32>)ihl << 2 << 3) + 32w4294967136) + @length(((bit<32>)ihl << 5) + 32w4294967136) varbit<320> options_ipv4; } @@ -45,7 +45,7 @@ parser ParserImpl(packet_in packet, out headers hdr, inout metadata meta, inout ipv4_t_1 tmp_hdr; @name(".start") state start { tmp_hdr = packet.lookahead(); - packet.extract(hdr.h, ((bit<32>)tmp_hdr.ihl << 2 << 3) + 32w4294967136); + packet.extract(hdr.h, ((bit<32>)tmp_hdr.ihl << 5) + 32w4294967136); transition accept; } } diff --git a/testdata/p4_14_samples_outputs/issue781-frontend.p4 b/testdata/p4_14_samples_outputs/issue781-frontend.p4 index bec95e7d744..286b5729954 100644 --- a/testdata/p4_14_samples_outputs/issue781-frontend.p4 +++ b/testdata/p4_14_samples_outputs/issue781-frontend.p4 @@ -29,7 +29,7 @@ header ipv4_t { bit<16> hdrChecksum; bit<32> srcAddr; bit<32> dstAddr; - @length(((bit<32>)ihl << 2 << 3) + 32w4294967136) + @length(((bit<32>)ihl << 5) + 32w4294967136) varbit<320> options_ipv4; } @@ -45,7 +45,7 @@ parser ParserImpl(packet_in packet, out headers hdr, inout metadata meta, inout ipv4_t_1 tmp_hdr_0; @name(".start") state start { tmp_hdr_0 = packet.lookahead(); - packet.extract(hdr.h, ((bit<32>)tmp_hdr_0.ihl << 2 << 3) + 32w4294967136); + packet.extract(hdr.h, ((bit<32>)tmp_hdr_0.ihl << 5) + 32w4294967136); transition accept; } } diff --git a/testdata/p4_16_samples/issue2190.p4 b/testdata/p4_16_samples/issue2190.p4 new file mode 100644 index 00000000000..45b7ec26e09 --- /dev/null +++ b/testdata/p4_16_samples/issue2190.p4 @@ -0,0 +1,40 @@ +#include +#include + +header H { + bit<8> a; + bit<8> b; +} + +struct Headers { + H h; +} + +struct Meta { +} + + +parser p(packet_in pkt, out Headers hdr, inout Meta m, inout standard_metadata_t sm) { + state start { + transition accept; + } +} + +control ingress(inout Headers h, inout Meta m, inout standard_metadata_t sm) { + + apply { + // both of these expressions lead to a crash + h.h.a = h.h.b / 8w2 >> h.h.b; + h.h.a = (h.h.b >> h.h.b) / 8w2; + } +} + +control vrfy(inout Headers h, inout Meta m) { apply {} } + +control update(inout Headers h, inout Meta m) { apply {} } + +control egress(inout Headers h, inout Meta m, inout standard_metadata_t sm) { apply {} } + +control deparser(packet_out b, in Headers h) { apply {} } + +V1Switch(p(), vrfy(), ingress(), egress(), update(), deparser()) main; diff --git a/testdata/p4_16_samples_outputs/bitwise-and-first.p4 b/testdata/p4_16_samples_outputs/bitwise-and-first.p4 index 07a3e814225..95eb5883b27 100644 --- a/testdata/p4_16_samples_outputs/bitwise-and-first.p4 +++ b/testdata/p4_16_samples_outputs/bitwise-and-first.p4 @@ -3,9 +3,7 @@ control C(bit<1> meta) { apply { - if (1w0x0 == 1w0) { - digest>(32w0, meta); - } + digest>(32w0, meta); } } diff --git a/testdata/p4_16_samples_outputs/issue1713-bmv2-first.p4 b/testdata/p4_16_samples_outputs/issue1713-bmv2-first.p4 index 135ce391163..121945898af 100644 --- a/testdata/p4_16_samples_outputs/issue1713-bmv2-first.p4 +++ b/testdata/p4_16_samples_outputs/issue1713-bmv2-first.p4 @@ -24,7 +24,7 @@ control ingress(inout Headers h, inout Meta m, inout standard_metadata_t sm) { h.h.c = (bit<8>)h.h.a[11:7]; } action case2() { - h.h.c = (bit<8>)(16w0[15:0] ++ h.h.a[15:8]); + h.h.c = (bit<8>)(16w0 ++ h.h.a[15:8]); } action case3() { h.h.c = ((int<32>)(int<16>)h.h.a)[12:5]; diff --git a/testdata/p4_16_samples_outputs/issue2190-first.p4 b/testdata/p4_16_samples_outputs/issue2190-first.p4 new file mode 100644 index 00000000000..1b2a51e4735 --- /dev/null +++ b/testdata/p4_16_samples_outputs/issue2190-first.p4 @@ -0,0 +1,50 @@ +#include +#include + +header H { + bit<8> a; + bit<8> b; +} + +struct Headers { + H h; +} + +struct Meta { +} + +parser p(packet_in pkt, out Headers hdr, inout Meta m, inout standard_metadata_t sm) { + state start { + transition accept; + } +} + +control ingress(inout Headers h, inout Meta m, inout standard_metadata_t sm) { + apply { + h.h.a = h.h.b >> 1 >> h.h.b; + h.h.a = h.h.b >> h.h.b >> 1; + } +} + +control vrfy(inout Headers h, inout Meta m) { + apply { + } +} + +control update(inout Headers h, inout Meta m) { + apply { + } +} + +control egress(inout Headers h, inout Meta m, inout standard_metadata_t sm) { + apply { + } +} + +control deparser(packet_out b, in Headers h) { + apply { + } +} + +V1Switch(p(), vrfy(), ingress(), egress(), update(), deparser()) main; + diff --git a/testdata/p4_16_samples_outputs/issue2190-frontend.p4 b/testdata/p4_16_samples_outputs/issue2190-frontend.p4 new file mode 100644 index 00000000000..d20a1e7eee8 --- /dev/null +++ b/testdata/p4_16_samples_outputs/issue2190-frontend.p4 @@ -0,0 +1,49 @@ +#include +#include + +header H { + bit<8> a; + bit<8> b; +} + +struct Headers { + H h; +} + +struct Meta { +} + +parser p(packet_in pkt, out Headers hdr, inout Meta m, inout standard_metadata_t sm) { + state start { + transition accept; + } +} + +control ingress(inout Headers h, inout Meta m, inout standard_metadata_t sm) { + apply { + h.h.a = h.h.b >> h.h.b >> 1; + } +} + +control vrfy(inout Headers h, inout Meta m) { + apply { + } +} + +control update(inout Headers h, inout Meta m) { + apply { + } +} + +control egress(inout Headers h, inout Meta m, inout standard_metadata_t sm) { + apply { + } +} + +control deparser(packet_out b, in Headers h) { + apply { + } +} + +V1Switch(p(), vrfy(), ingress(), egress(), update(), deparser()) main; + diff --git a/testdata/p4_16_samples_outputs/issue2190-midend.p4 b/testdata/p4_16_samples_outputs/issue2190-midend.p4 new file mode 100644 index 00000000000..188df962e2d --- /dev/null +++ b/testdata/p4_16_samples_outputs/issue2190-midend.p4 @@ -0,0 +1,58 @@ +#include +#include + +header H { + bit<8> a; + bit<8> b; +} + +struct Headers { + H h; +} + +struct Meta { +} + +parser p(packet_in pkt, out Headers hdr, inout Meta m, inout standard_metadata_t sm) { + state start { + transition accept; + } +} + +control ingress(inout Headers h, inout Meta m, inout standard_metadata_t sm) { + @hidden action issue2190l28() { + h.h.a = h.h.b >> h.h.b >> 1; + } + @hidden table tbl_issue2190l28 { + actions = { + issue2190l28(); + } + const default_action = issue2190l28(); + } + apply { + tbl_issue2190l28.apply(); + } +} + +control vrfy(inout Headers h, inout Meta m) { + apply { + } +} + +control update(inout Headers h, inout Meta m) { + apply { + } +} + +control egress(inout Headers h, inout Meta m, inout standard_metadata_t sm) { + apply { + } +} + +control deparser(packet_out b, in Headers h) { + apply { + } +} + +V1Switch(p(), vrfy(), ingress(), egress(), update(), deparser()) main; + diff --git a/testdata/p4_16_samples_outputs/issue2190.p4 b/testdata/p4_16_samples_outputs/issue2190.p4 new file mode 100644 index 00000000000..e87a41ac0ab --- /dev/null +++ b/testdata/p4_16_samples_outputs/issue2190.p4 @@ -0,0 +1,50 @@ +#include +#include + +header H { + bit<8> a; + bit<8> b; +} + +struct Headers { + H h; +} + +struct Meta { +} + +parser p(packet_in pkt, out Headers hdr, inout Meta m, inout standard_metadata_t sm) { + state start { + transition accept; + } +} + +control ingress(inout Headers h, inout Meta m, inout standard_metadata_t sm) { + apply { + h.h.a = h.h.b / 8w2 >> h.h.b; + h.h.a = (h.h.b >> h.h.b) / 8w2; + } +} + +control vrfy(inout Headers h, inout Meta m) { + apply { + } +} + +control update(inout Headers h, inout Meta m) { + apply { + } +} + +control egress(inout Headers h, inout Meta m, inout standard_metadata_t sm) { + apply { + } +} + +control deparser(packet_out b, in Headers h) { + apply { + } +} + +V1Switch(p(), vrfy(), ingress(), egress(), update(), deparser()) main; + diff --git a/testdata/p4_16_samples_outputs/issue2190.p4-stderr b/testdata/p4_16_samples_outputs/issue2190.p4-stderr new file mode 100644 index 00000000000..e69de29bb2d diff --git a/testdata/p4_16_samples_outputs/issue2190.p4.entries.txt b/testdata/p4_16_samples_outputs/issue2190.p4.entries.txt new file mode 100644 index 00000000000..e69de29bb2d diff --git a/testdata/p4_16_samples_outputs/issue2190.p4.p4info.txt b/testdata/p4_16_samples_outputs/issue2190.p4.p4info.txt new file mode 100644 index 00000000000..9ec92493e4c --- /dev/null +++ b/testdata/p4_16_samples_outputs/issue2190.p4.p4info.txt @@ -0,0 +1,3 @@ +pkg_info { + arch: "v1model" +} diff --git a/testdata/p4_16_samples_outputs/precedence-first.p4 b/testdata/p4_16_samples_outputs/precedence-first.p4 index 82cba1023b5..eeab5a8e6ef 100644 --- a/testdata/p4_16_samples_outputs/precedence-first.p4 +++ b/testdata/p4_16_samples_outputs/precedence-first.p4 @@ -69,7 +69,7 @@ action ac() { e = a < b == e; e = e == a < b; e = a < b == e; - a = a << b + c; + a = a << b << c; a = a << (b << c); a = a << b >> c; a = a << (b >> c); diff --git a/testdata/p4_16_samples_outputs/strength-first.p4 b/testdata/p4_16_samples_outputs/strength-first.p4 index bb26657c00a..3ca0276c24b 100644 --- a/testdata/p4_16_samples_outputs/strength-first.p4 +++ b/testdata/p4_16_samples_outputs/strength-first.p4 @@ -25,7 +25,7 @@ control strength() { y = y >> 3; y = y; y = 4w0; - y = y & 4w0; + y = 4w0; y = y & 4w3; y = y + 4w15; y = y + 4w0x1; diff --git a/testdata/p4_16_samples_outputs/strength3-first.p4 b/testdata/p4_16_samples_outputs/strength3-first.p4 index c0cd5c1f23f..a063cce8e49 100644 --- a/testdata/p4_16_samples_outputs/strength3-first.p4 +++ b/testdata/p4_16_samples_outputs/strength3-first.p4 @@ -18,25 +18,25 @@ struct Meta { control ingress(inout Headers h, inout Meta m, inout standard_metadata_t sm) { action case0() { - h.h.c = (bit<8>)((16w0 ++ h.h.a)[15:0] ++ 16w0[15:0]); + h.h.c = (bit<8>)(h.h.a ++ 16w0); } action case1() { h.h.c = (bit<8>)h.h.a; } action case2() { - h.h.c = (bit<8>)16w0; + h.h.c = 8w0; } action case3() { h.h.c = h.h.a[7:0]; } action case4() { - h.h.c = (bit<8>)(16w0[7:0] ++ h.h.a[15:0]); + h.h.c = (bit<8>)(8w0 ++ h.h.a); } action case5() { - h.h.c = (bit<8>)(16w0[7:0] ++ h.h.a[15:8]); + h.h.c = (bit<8>)(8w0 ++ h.h.a[15:8]); } action case6() { - h.h.c = (bit<8>)(16w0[15:0] ++ h.h.a[15:8]); + h.h.c = (bit<8>)(16w0 ++ h.h.a[15:8]); } action case7() { h.h.c = (bit<8>)(16w0 ++ h.h.a >> 3)[31:8]; diff --git a/testdata/p4_16_samples_outputs/strength3-frontend.p4 b/testdata/p4_16_samples_outputs/strength3-frontend.p4 index c3b8aedad9d..6c0380d97d9 100644 --- a/testdata/p4_16_samples_outputs/strength3-frontend.p4 +++ b/testdata/p4_16_samples_outputs/strength3-frontend.p4 @@ -18,7 +18,7 @@ struct Meta { control ingress(inout Headers h, inout Meta m, inout standard_metadata_t sm) { @name("ingress.case0") action case0() { - h.h.c = (bit<8>)((16w0 ++ h.h.a)[15:0] ++ 16w0); + h.h.c = (bit<8>)(h.h.a ++ 16w0); } @name("ingress.case1") action case1() { h.h.c = (bit<8>)h.h.a; @@ -30,7 +30,7 @@ control ingress(inout Headers h, inout Meta m, inout standard_metadata_t sm) { h.h.c = h.h.a[7:0]; } @name("ingress.case4") action case4() { - h.h.c = (bit<8>)(8w0 ++ h.h.a[15:0]); + h.h.c = (bit<8>)(8w0 ++ h.h.a); } @name("ingress.case5") action case5() { h.h.c = (bit<8>)(8w0 ++ h.h.a[15:8]); diff --git a/testdata/p4_16_samples_outputs/strength4-first.p4 b/testdata/p4_16_samples_outputs/strength4-first.p4 index eb5bbf1ce6c..c33f1f19af9 100644 --- a/testdata/p4_16_samples_outputs/strength4-first.p4 +++ b/testdata/p4_16_samples_outputs/strength4-first.p4 @@ -34,8 +34,8 @@ control ingress_impl(inout headers_t hdr, inout local_metadata_t local_metadata, control egress_impl(inout headers_t hdr, inout local_metadata_t local_metadata, inout standard_metadata_t standard_metadata) { apply { - local_metadata.m16 = (16w0 ++ local_metadata.f16)[14:0] ++ 1w0; - local_metadata.d16 = 16w0[0:0] ++ local_metadata.f16[15:1]; + local_metadata.m16 = local_metadata.f16[14:0] ++ 1w0; + local_metadata.d16 = 1w0 ++ local_metadata.f16[15:1]; local_metadata.a16 = (int<16>)(16s0 ++ local_metadata.x16 << 1)[15:0]; local_metadata.b16 = (int<16>)(16s0 ++ local_metadata.x16 >> 1)[15:0]; } diff --git a/testdata/p4_16_samples_outputs/strength4-frontend.p4 b/testdata/p4_16_samples_outputs/strength4-frontend.p4 index e8d4126ae67..c33f1f19af9 100644 --- a/testdata/p4_16_samples_outputs/strength4-frontend.p4 +++ b/testdata/p4_16_samples_outputs/strength4-frontend.p4 @@ -34,7 +34,7 @@ control ingress_impl(inout headers_t hdr, inout local_metadata_t local_metadata, control egress_impl(inout headers_t hdr, inout local_metadata_t local_metadata, inout standard_metadata_t standard_metadata) { apply { - local_metadata.m16 = (16w0 ++ local_metadata.f16)[14:0] ++ 1w0; + local_metadata.m16 = local_metadata.f16[14:0] ++ 1w0; local_metadata.d16 = 1w0 ++ local_metadata.f16[15:1]; local_metadata.a16 = (int<16>)(16s0 ++ local_metadata.x16 << 1)[15:0]; local_metadata.b16 = (int<16>)(16s0 ++ local_metadata.x16 >> 1)[15:0]; diff --git a/testdata/p4_16_samples_outputs/strength5-first.p4 b/testdata/p4_16_samples_outputs/strength5-first.p4 index 0bf0fa39aed..253cde9f08a 100644 --- a/testdata/p4_16_samples_outputs/strength5-first.p4 +++ b/testdata/p4_16_samples_outputs/strength5-first.p4 @@ -1,3 +1,3 @@ action a(inout bit<32> x) { - x = x >> 3 + 8; + x = x >> 11; } From eca8a5d73798bfef5557605f914364cf31815746 Mon Sep 17 00:00:00 2001 From: Chris Dodd Date: Thu, 27 Feb 2020 10:47:19 -0800 Subject: [PATCH 098/106] missing %1% in error messages --- control-plane/p4RuntimeSerializer.cpp | 4 ++-- frontends/p4/fromv1.0/programStructure.cpp | 2 +- testdata/p4_14_errors_outputs/issue2188.p4-stderr | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/control-plane/p4RuntimeSerializer.cpp b/control-plane/p4RuntimeSerializer.cpp index 952aff5c3a8..2589c7d3d48 100644 --- a/control-plane/p4RuntimeSerializer.cpp +++ b/control-plane/p4RuntimeSerializer.cpp @@ -1135,7 +1135,7 @@ class P4RuntimeAnalyzer { auto fType = f->type; if (!fType->is()) { ::error(ErrorType::ERR_UNSUPPORTED, - "unsupported type argument for Value Set; " + "Unsupported type argument for Value Set; " "this version of P4Runtime requires that when the type parameter " "of a Value Set is a struct, all the fields of the struct " "must be of type bit, but %1% is not", f); @@ -1154,7 +1154,7 @@ class P4RuntimeAnalyzer { } } else if (et->is()) { ::error(ErrorType::ERR_UNSUPPORTED, - "type argument for for Value Set; " + "%1%: Unsupported type argument for Value Set; " "this version of P4Runtime requires the type parameter of a Value Set " "to be a bit or a struct of bit fields", inst); diff --git a/frontends/p4/fromv1.0/programStructure.cpp b/frontends/p4/fromv1.0/programStructure.cpp index a15516e2035..cc2ba3c13d9 100644 --- a/frontends/p4/fromv1.0/programStructure.cpp +++ b/frontends/p4/fromv1.0/programStructure.cpp @@ -496,7 +496,7 @@ const IR::ParserState* ProgramStructure::convertParser(const IR::V1Parser* parse CHECK_NULL(c); // this is enforced elsewhere if (!c->fitsInt() || c->asInt() != -1) { ::error(ErrorType::ERR_INVALID, - ": masks not supported for value sets", c); + "%1%: masks not supported for value sets", c); continue; } auto sc = new IR::SelectCase(c->srcInfo, v.first, deststate); diff --git a/testdata/p4_14_errors_outputs/issue2188.p4-stderr b/testdata/p4_14_errors_outputs/issue2188.p4-stderr index 8bf88413201..fea0e406e9a 100644 --- a/testdata/p4_14_errors_outputs/issue2188.p4-stderr +++ b/testdata/p4_14_errors_outputs/issue2188.p4-stderr @@ -1,7 +1,7 @@ issue2188.p4(19): [--Wwarn=missing] warning: CaseEntry: parser_value_set has no @parser_value_set_size annotation.Using default size 4. pvs0 mask 0x0ff0 : ingress; // <--- this is the most significant line of the example ^^^^^^^^^^^^^^^^ -issue2188.p4(19): [--Werror=invalid] error: 0xff0: Invalid : masks not supported for value sets +issue2188.p4(19): [--Werror=invalid] error: 0xff0: masks not supported for value sets pvs0 mask 0x0ff0 : ingress; // <--- this is the most significant line of the example ^^^^^^ -[--Werror=overlimit] error: 1 errors encountered, aborting compilation +error: 1 errors encountered, aborting compilation From 908d06db3334cdd208cd2581248ad3ddf8ff42f6 Mon Sep 17 00:00:00 2001 From: Chris Dodd Date: Fri, 28 Feb 2020 12:48:01 -0800 Subject: [PATCH 099/106] Remove broken link-handling code (stat follows links anyways) --- frontends/common/options.cpp | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/frontends/common/options.cpp b/frontends/common/options.cpp index 68f3ee2374b..e953c798062 100644 --- a/frontends/common/options.cpp +++ b/frontends/common/options.cpp @@ -285,9 +285,6 @@ bool setIncludePathIfExists(const char*& includePathOut, struct stat st; char buffer[PATH_MAX]; int len; - if ((len = readlink(possiblePath, buffer, sizeof(buffer))) > 0) { - buffer[len] = 0; - possiblePath = buffer; } if (!(stat(possiblePath, &st) >= 0 && S_ISDIR(st.st_mode))) return false; includePathOut = strdup(possiblePath); return true; @@ -322,13 +319,11 @@ std::vector* CompilerOptions::process(int argc, char* const argv[]) snprintf(p, buffer + sizeof(buffer) - p, "p4include"); if (!setIncludePathIfExists(p4includePath, buffer)) { snprintf(p, buffer + sizeof(buffer) - p, "../p4include"); - setIncludePathIfExists(p4includePath, buffer); - } + setIncludePathIfExists(p4includePath, buffer); } snprintf(p, buffer + sizeof(buffer) - p, "p4_14include"); if (!setIncludePathIfExists(p4_14includePath, buffer)) { snprintf(p, buffer + sizeof(buffer) - p, "../p4_14include"); - setIncludePathIfExists(p4_14includePath, buffer); - } + setIncludePathIfExists(p4_14includePath, buffer); } } auto remainingOptions = Util::Options::process(argc, argv); From 5e8417f731c0cac4d60bd6eaee3d8e9870aa2582 Mon Sep 17 00:00:00 2001 From: Prathima Kotikalapudi <36422468+pkotikal@users.noreply.github.com> Date: Sat, 29 Feb 2020 14:37:16 -0800 Subject: [PATCH 100/106] Update stf test (#2219) --- testdata/p4_14_samples/counter3.stf | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/testdata/p4_14_samples/counter3.stf b/testdata/p4_14_samples/counter3.stf index ffecbc5ed35..793037b7257 100644 --- a/testdata/p4_14_samples/counter3.stf +++ b/testdata/p4_14_samples/counter3.stf @@ -7,13 +7,13 @@ expect 3 expect 5 packet 0 a1a2a3a4a5a6 0000 wait -check_counter cnt($A) bytes == 8 +check_counter cnt($A) bytes == 12 packet 0 a1a2a3a4a5a6 000100 wait -check_counter cnt($A) bytes == 17 +check_counter cnt($A) bytes == 25 packet 0 a1a2a3a4a5a6 00020000 wait -check_counter cnt($A) bytes == 27 +check_counter cnt($A) bytes == 39 packet 0 b1b2b3b4b5b6 0001 packet 0 b1b2b3b4b5b6 0002 @@ -37,5 +37,5 @@ packet 0 b1b2b3b4b5b6 0019 packet 0 b1b2b3b4b5b6 0020 wait -check_counter cnt($A) bytes == 27 -check_counter cnt($B) bytes == 160 +check_counter cnt($A) bytes == 39 +check_counter cnt($B) bytes == 240 From 2633c15300c9aded6fcbad2629a9f28dbbfea7d8 Mon Sep 17 00:00:00 2001 From: Mihai Budiu Date: Wed, 4 Mar 2020 10:10:24 -0800 Subject: [PATCH 101/106] Some small changes to run-bmv2-test.py (#2222) * Update run-bmv2-test.py --- backends/bmv2/run-bmv2-test.py | 56 ++++++++++++++++++++++++---------- 1 file changed, 40 insertions(+), 16 deletions(-) diff --git a/backends/bmv2/run-bmv2-test.py b/backends/bmv2/run-bmv2-test.py index 866a7a2b6a3..6051d4e9556 100755 --- a/backends/bmv2/run-bmv2-test.py +++ b/backends/bmv2/run-bmv2-test.py @@ -40,12 +40,15 @@ SUCCESS = 0 FAILURE = 1 + class Options(object): def __init__(self): self.binary = "" # this program's name self.cleanupTmp = True # if false do not remote tmp folder created self.p4Filename = "" # file that is being compiled self.compilerSrcDir = "" # path to compiler source tree + # default of the build dir is just the working directory + self.compilerBuildDir = "." self.verbose = False self.replace = False # replace previous outputs self.compilerOptions = [] @@ -54,20 +57,23 @@ def __init__(self): self.hasBMv2 = False # Is the behavioral model installed? self.usePsa = False # Use the psa switch behavioral model? self.runDebugger = False - self.observationLog = None # Log packets produced by the BMV2 model if path to log is supplied + # Log packets produced by the BMV2 model if path to log is supplied + self.observationLog = None self.initCommands = [] -def nextWord(text, sep = " "): + +def nextWord(text, sep=" "): # Split a text at the indicated separator. # Note that the separator can be a string. # Separator is discarded. pos = text.find(sep) if pos < 0: return text, "" - l, r = text[0:pos].strip(), text[pos+len(sep):len(text)].strip() + l, r = text[0:pos].strip(), text[pos + len(sep):len(text)].strip() # print(text, "/", sep, "->", l, "#", r) return l, r + class ConfigH(object): # Represents an autoconf config.h file # fortunately the structure of these files is very constrained @@ -78,6 +84,7 @@ def __init__(self, file): self.text = a.read() self.ok = False self.parse() + def parse(self): while self.text != "": self.text = self.text.strip() @@ -86,7 +93,7 @@ def parse(self): if end < 1: reportError("Unterminated comment in config file") return - self.text = self.text[end+2:len(self.text)] + self.text = self.text[end + 2:len(self.text)] elif self.text.startswith("#define"): define, self.text = nextWord(self.text) macro, self.text = nextWord(self.text) @@ -98,9 +105,11 @@ def parse(self): reportError("Unexpected text:", self.text) return self.ok = True + def __str__(self): return str(self.vars) + def usage(options): name = options.binary print(name, "usage:") @@ -119,24 +128,29 @@ def usage(options): print(" --pp file: pass this option to the compiler") print(" -observation-log : save packet output to ") print(" --init : Run before the start of the test") + print(" -bd : Specify the build in the compiler source directory") def isError(p4filename): # True if the filename represents a p4 program that should fail return "_errors" in p4filename + def reportError(*message): print("***", *message) + class Local(object): # object to hold local vars accessable to nested functions pass + def run_timeout(options, args, timeout, stderr): if options.verbose: print("Executing ", " ".join(args)) local = Local() local.process = None + def target(): procstderr = None if stderr is not None: @@ -158,8 +172,10 @@ def target(): print("Exit code ", local.process.returncode) return local.process.returncode + timeout = 10 * 60 + def run_model(options, tmpdir, jsonfile): if not options.hasBMv2: return SUCCESS @@ -187,6 +203,7 @@ def run_model(options, tmpdir, jsonfile): result = bmv2.checkOutputs() return result + def run_init_commands(options): if not options.initCommands: return SUCCESS @@ -197,6 +214,7 @@ def run_init_commands(options): return FAILURE return SUCCESS + def process_file(options, argv): assert isinstance(options, Options) @@ -220,13 +238,13 @@ def process_file(options, argv): raise Exception("No such file " + options.p4filename) if options.usePsa: - binary = "./p4c-bm2-psa" + binary = options.compilerBuildDir + "/p4c-bm2-psa" else: - binary = "./p4c-bm2-ss" + binary = options.compilerBuildDir + "/p4c-bm2-ss" args = [binary, "-o", jsonfile] + options.compilerOptions if "p4_14" in options.p4filename or "v1_samples" in options.p4filename: - args.extend(["--std", "p4-14"]); + args.extend(["--std", "p4-14"]) args.extend(argv) # includes p4filename if options.runDebugger: args[0:0] = options.runDebugger.split() @@ -250,7 +268,7 @@ def process_file(options, argv): result = SUCCESS if result == SUCCESS and not expected_error: - result = run_model(options, tmpdir, jsonfile); + result = run_model(options, tmpdir, jsonfile) if options.cleanupTmp: if options.verbose: @@ -290,7 +308,7 @@ def main(argv): usage(options) sys.exit(FAILURE) else: - options.compilerOptions += argv[1].split(); + options.compilerOptions += argv[1].split() argv = argv[1:] elif argv[0] == "--switch-arg": if len(argv) == 0: @@ -298,15 +316,16 @@ def main(argv): usage(options) sys.exit(FAILURE) else: - options.switchOptions += argv[1].split(); + options.switchOptions += argv[1].split() argv = argv[1:] elif argv[0] == "--target-specific-switch-arg": if len(argv) == 0: - reportError("Missing argument for --target-specific-switch-arg option") + reportError( + "Missing argument for --target-specific-switch-arg option") usage(options) sys.exit(FAILURE) else: - options.switchTargetSpecificOptions += argv[1].split(); + options.switchTargetSpecificOptions += argv[1].split() argv = argv[1:] elif argv[0][1] == 'D' or argv[0][1] == 'I' or argv[0][1] == 'T': options.compilerOptions.append(argv[0]) @@ -332,22 +351,26 @@ def main(argv): else: options.initCommands.append(argv[1]) argv = argv[1:] + elif argv[0] == "-bd": + print(argv) + options.compilerBuildDir = argv[1] + argv = argv[1:] else: reportError("Unknown option ", argv[0]) usage(options) sys.exit(FAILURE) argv = argv[1:] - - config = ConfigH("config.h") + config = ConfigH(options.compilerBuildDir + "/config.h") if not config.ok: print("Error parsing config.h") sys.exit(FAILURE) options.hasBMv2 = "HAVE_SIMPLE_SWITCH" in config.vars if not options.hasBMv2: - reportError("config.h indicates that BMv2 is not installed; will skip running BMv2 tests") + reportError( + "config.h indicates that BMv2 is not installed; will skip running BMv2 tests") - options.p4filename=argv[-1] + options.p4filename = argv[-1] options.testName = None if options.p4filename.startswith(options.compilerSrcDir): options.testName = options.p4filename[len(options.compilerSrcDir):]; @@ -376,5 +399,6 @@ def main(argv): reportError("Test failed") sys.exit(result) + if __name__ == "__main__": main(sys.argv) From 5a06a3c9f99dafe9c3284fcbc7c9e6991df023ee Mon Sep 17 00:00:00 2001 From: Mihai Budiu Date: Wed, 4 Mar 2020 10:11:20 -0800 Subject: [PATCH 102/106] p4c-ubpf: new uBPF back-end for p4c (#2134) p4c-ubpf back-end --- .travis.yml | 2 +- CMakeLists.txt | 4 + backends/ebpf/midend.h | 2 +- backends/ebpf/targets/ubpf_target.py | 1 + backends/ubpf/CMakeLists.txt | 85 +++ backends/ubpf/README.md | 82 +++ backends/ubpf/codeGen.h | 17 + backends/ubpf/docs/EXAMPLES.md | 216 ++++++ backends/ubpf/examples/gtp.p4 | 215 ++++++ backends/ubpf/examples/ipv4-actions.p4 | 1 + backends/ubpf/examples/ipv6-actions.p4 | 1 + backends/ubpf/examples/packet-counter.p4 | 101 +++ .../ubpf/examples/rate-limiter-structs.p4 | 85 +++ backends/ubpf/examples/rate-limiter.p4 | 68 ++ backends/ubpf/examples/simple-actions.p4 | 1 + backends/ubpf/examples/simple-firewall.p4 | 1 + backends/ubpf/examples/tunneling.p4 | 1 + backends/ubpf/examples/vxlan.p4 | 222 ++++++ backends/ubpf/midend.cpp | 135 ++++ backends/ubpf/midend.h | 37 + backends/ubpf/p4c-ubpf.cpp | 92 +++ backends/ubpf/p4include/ubpf_model.p4 | 137 ++++ backends/ubpf/run-ubpf-test.py | 44 ++ backends/ubpf/runtime/ebpf_runtime.c | 138 ++++ backends/ubpf/runtime/ebpf_runtime_ubpf.c | 70 ++ backends/ubpf/runtime/ebpf_runtime_ubpf.h | 62 ++ backends/ubpf/runtime/runtime.mk | 68 ++ backends/ubpf/runtime/ubpf_common.h | 86 +++ backends/ubpf/runtime/ubpf_test.h | 67 ++ backends/ubpf/target.cpp | 131 ++++ backends/ubpf/target.h | 66 ++ backends/ubpf/targets/ubpf_target.py | 109 +++ backends/ubpf/tests/README.md | 56 ++ backends/ubpf/tests/compile_testdata.py | 94 +++ backends/ubpf/tests/environment/Vagrantfile | 80 +++ .../ubpf/tests/environment/configure_dpdk.sh | 33 + backends/ubpf/tests/environment/run_switch.sh | 26 + .../ubpf/tests/environment/setup-pktgen.sh | 75 +++ .../ubpf/tests/environment/setup-switch.sh | 202 ++++++ backends/ubpf/tests/ptf/base_test.py | 96 +++ backends/ubpf/tests/ptf/ipv4_actions_test.py | 304 +++++++++ backends/ubpf/tests/ptf/ipv6_actions_test.py | 187 ++++++ backends/ubpf/tests/ptf/no_p4_test.py | 35 + .../ubpf/tests/ptf/simple_actions_test.py | 235 +++++++ .../ubpf/tests/ptf/simple_firewall_test.py | 255 +++++++ backends/ubpf/tests/ptf/tunneling_test.py | 64 ++ .../ubpf/tests/testdata/test-ipv4-actions.p4 | 179 +++++ .../ubpf/tests/testdata/test-ipv6-actions.p4 | 178 +++++ .../tests/testdata/test-simple-actions.p4 | 167 +++++ .../tests/testdata/test-simple-firewall.p4 | 178 +++++ .../ubpf/tests/testdata/test-tunneling.p4 | 144 ++++ backends/ubpf/ubpfBackend.cpp | 90 +++ backends/ubpf/ubpfBackend.h | 31 + backends/ubpf/ubpfControl.cpp | 630 ++++++++++++++++++ backends/ubpf/ubpfControl.h | 100 +++ backends/ubpf/ubpfDeparser.cpp | 357 ++++++++++ backends/ubpf/ubpfDeparser.h | 79 +++ backends/ubpf/ubpfHelpers.h | 28 + backends/ubpf/ubpfModel.cpp | 24 + backends/ubpf/ubpfModel.h | 98 +++ backends/ubpf/ubpfParser.cpp | 367 ++++++++++ backends/ubpf/ubpfParser.h | 49 ++ backends/ubpf/ubpfProgram.cpp | 253 +++++++ backends/ubpf/ubpfProgram.h | 73 ++ backends/ubpf/ubpfRegister.cpp | 156 +++++ backends/ubpf/ubpfRegister.h | 44 ++ backends/ubpf/ubpfTable.cpp | 412 ++++++++++++ backends/ubpf/ubpfTable.h | 84 +++ backends/ubpf/ubpfType.cpp | 234 +++++++ backends/ubpf/ubpfType.h | 110 +++ backends/ubpf/version.h.cmake | 38 ++ testdata/p4_16_samples/action_call_ubpf.p4 | 74 ++ testdata/p4_16_samples/action_call_ubpf.stf | 13 + testdata/p4_16_samples/csum_ubpf.p4 | 101 +++ testdata/p4_16_samples/csum_ubpf.stf | 2 + testdata/p4_16_samples/hash_ubpf.p4 | 78 +++ testdata/p4_16_samples/ipv4-actions_ubpf.p4 | 1 + testdata/p4_16_samples/ipv4-actions_ubpf.stf | 54 ++ testdata/p4_16_samples/ipv6-actions_ubpf.p4 | 1 + testdata/p4_16_samples/metadata_ubpf.p4 | 95 +++ testdata/p4_16_samples/metadata_ubpf.stf | 11 + testdata/p4_16_samples/simple-actions_ubpf.p4 | 1 + .../p4_16_samples/simple-actions_ubpf.stf | 28 + .../p4_16_samples/simple-firewall_ubpf.p4 | 1 + .../p4_16_samples/simple-firewall_ubpf.stf | 0 testdata/p4_16_samples/tunneling_ubpf.p4 | 1 + testdata/p4_16_samples/tunneling_ubpf.stf | 14 + .../action_call_ubpf-first.p4 | 55 ++ .../action_call_ubpf-frontend.p4 | 49 ++ .../action_call_ubpf-midend.p4 | 68 ++ .../p4_16_samples_outputs/action_call_ubpf.p4 | 55 ++ .../action_call_ubpf.p4-stderr | 0 .../p4_16_samples_outputs/csum_ubpf-first.p4 | 81 +++ .../csum_ubpf-frontend.p4 | 82 +++ .../p4_16_samples_outputs/csum_ubpf-midend.p4 | 96 +++ testdata/p4_16_samples_outputs/csum_ubpf.p4 | 81 +++ .../p4_16_samples_outputs/csum_ubpf.p4-stderr | 0 .../p4_16_samples_outputs/hash_ubpf-first.p4 | 59 ++ .../hash_ubpf-frontend.p4 | 59 ++ .../p4_16_samples_outputs/hash_ubpf-midend.p4 | 93 +++ testdata/p4_16_samples_outputs/hash_ubpf.p4 | 59 ++ .../p4_16_samples_outputs/hash_ubpf.p4-stderr | 0 .../ipv4-actions_ubpf-first.p4 | 141 ++++ .../ipv4-actions_ubpf-frontend.p4 | 143 ++++ .../ipv4-actions_ubpf-midend.p4 | 152 +++++ .../ipv4-actions_ubpf.p4 | 141 ++++ .../ipv4-actions_ubpf.p4-stderr | 0 .../ipv6-actions_ubpf-first.p4 | 142 ++++ .../ipv6-actions_ubpf-frontend.p4 | 142 ++++ .../ipv6-actions_ubpf-midend.p4 | 151 +++++ .../ipv6-actions_ubpf.p4 | 142 ++++ .../ipv6-actions_ubpf.p4-stderr | 0 .../metadata_ubpf-first.p4 | 66 ++ .../metadata_ubpf-frontend.p4 | 70 ++ .../metadata_ubpf-midend.p4 | 79 +++ .../p4_16_samples_outputs/metadata_ubpf.p4 | 66 ++ .../metadata_ubpf.p4-stderr | 0 .../simple-actions_ubpf-first.p4 | 130 ++++ .../simple-actions_ubpf-frontend.p4 | 133 ++++ .../simple-actions_ubpf-midend.p4 | 142 ++++ .../simple-actions_ubpf.p4 | 130 ++++ .../simple-actions_ubpf.p4-stderr | 0 .../simple-firewall_ubpf-first.p4 | 150 +++++ .../simple-firewall_ubpf-frontend.p4 | 155 +++++ .../simple-firewall_ubpf-midend.p4 | 236 +++++++ .../simple-firewall_ubpf.p4 | 152 +++++ .../simple-firewall_ubpf.p4-stderr | 0 .../tunneling_ubpf-first.p4 | 113 ++++ .../tunneling_ubpf-frontend.p4 | 117 ++++ .../tunneling_ubpf-midend.p4 | 126 ++++ .../p4_16_samples_outputs/tunneling_ubpf.p4 | 113 ++++ .../tunneling_ubpf.p4-stderr | 0 132 files changed, 12634 insertions(+), 2 deletions(-) create mode 120000 backends/ebpf/targets/ubpf_target.py create mode 100644 backends/ubpf/CMakeLists.txt create mode 100644 backends/ubpf/README.md create mode 100644 backends/ubpf/codeGen.h create mode 100644 backends/ubpf/docs/EXAMPLES.md create mode 100644 backends/ubpf/examples/gtp.p4 create mode 120000 backends/ubpf/examples/ipv4-actions.p4 create mode 120000 backends/ubpf/examples/ipv6-actions.p4 create mode 100644 backends/ubpf/examples/packet-counter.p4 create mode 100644 backends/ubpf/examples/rate-limiter-structs.p4 create mode 100644 backends/ubpf/examples/rate-limiter.p4 create mode 120000 backends/ubpf/examples/simple-actions.p4 create mode 120000 backends/ubpf/examples/simple-firewall.p4 create mode 120000 backends/ubpf/examples/tunneling.p4 create mode 100644 backends/ubpf/examples/vxlan.p4 create mode 100644 backends/ubpf/midend.cpp create mode 100644 backends/ubpf/midend.h create mode 100644 backends/ubpf/p4c-ubpf.cpp create mode 100644 backends/ubpf/p4include/ubpf_model.p4 create mode 100755 backends/ubpf/run-ubpf-test.py create mode 100644 backends/ubpf/runtime/ebpf_runtime.c create mode 100644 backends/ubpf/runtime/ebpf_runtime_ubpf.c create mode 100644 backends/ubpf/runtime/ebpf_runtime_ubpf.h create mode 100644 backends/ubpf/runtime/runtime.mk create mode 100644 backends/ubpf/runtime/ubpf_common.h create mode 100644 backends/ubpf/runtime/ubpf_test.h create mode 100644 backends/ubpf/target.cpp create mode 100644 backends/ubpf/target.h create mode 100644 backends/ubpf/targets/ubpf_target.py create mode 100644 backends/ubpf/tests/README.md create mode 100644 backends/ubpf/tests/compile_testdata.py create mode 100644 backends/ubpf/tests/environment/Vagrantfile create mode 100755 backends/ubpf/tests/environment/configure_dpdk.sh create mode 100755 backends/ubpf/tests/environment/run_switch.sh create mode 100755 backends/ubpf/tests/environment/setup-pktgen.sh create mode 100755 backends/ubpf/tests/environment/setup-switch.sh create mode 100644 backends/ubpf/tests/ptf/base_test.py create mode 100644 backends/ubpf/tests/ptf/ipv4_actions_test.py create mode 100644 backends/ubpf/tests/ptf/ipv6_actions_test.py create mode 100644 backends/ubpf/tests/ptf/no_p4_test.py create mode 100644 backends/ubpf/tests/ptf/simple_actions_test.py create mode 100644 backends/ubpf/tests/ptf/simple_firewall_test.py create mode 100644 backends/ubpf/tests/ptf/tunneling_test.py create mode 100644 backends/ubpf/tests/testdata/test-ipv4-actions.p4 create mode 100644 backends/ubpf/tests/testdata/test-ipv6-actions.p4 create mode 100644 backends/ubpf/tests/testdata/test-simple-actions.p4 create mode 100644 backends/ubpf/tests/testdata/test-simple-firewall.p4 create mode 100644 backends/ubpf/tests/testdata/test-tunneling.p4 create mode 100644 backends/ubpf/ubpfBackend.cpp create mode 100644 backends/ubpf/ubpfBackend.h create mode 100644 backends/ubpf/ubpfControl.cpp create mode 100644 backends/ubpf/ubpfControl.h create mode 100644 backends/ubpf/ubpfDeparser.cpp create mode 100644 backends/ubpf/ubpfDeparser.h create mode 100644 backends/ubpf/ubpfHelpers.h create mode 100644 backends/ubpf/ubpfModel.cpp create mode 100644 backends/ubpf/ubpfModel.h create mode 100644 backends/ubpf/ubpfParser.cpp create mode 100644 backends/ubpf/ubpfParser.h create mode 100644 backends/ubpf/ubpfProgram.cpp create mode 100644 backends/ubpf/ubpfProgram.h create mode 100644 backends/ubpf/ubpfRegister.cpp create mode 100644 backends/ubpf/ubpfRegister.h create mode 100644 backends/ubpf/ubpfTable.cpp create mode 100644 backends/ubpf/ubpfTable.h create mode 100644 backends/ubpf/ubpfType.cpp create mode 100644 backends/ubpf/ubpfType.h create mode 100644 backends/ubpf/version.h.cmake create mode 100644 testdata/p4_16_samples/action_call_ubpf.p4 create mode 100644 testdata/p4_16_samples/action_call_ubpf.stf create mode 100644 testdata/p4_16_samples/csum_ubpf.p4 create mode 100644 testdata/p4_16_samples/csum_ubpf.stf create mode 100644 testdata/p4_16_samples/hash_ubpf.p4 create mode 120000 testdata/p4_16_samples/ipv4-actions_ubpf.p4 create mode 100644 testdata/p4_16_samples/ipv4-actions_ubpf.stf create mode 120000 testdata/p4_16_samples/ipv6-actions_ubpf.p4 create mode 100644 testdata/p4_16_samples/metadata_ubpf.p4 create mode 100644 testdata/p4_16_samples/metadata_ubpf.stf create mode 120000 testdata/p4_16_samples/simple-actions_ubpf.p4 create mode 100644 testdata/p4_16_samples/simple-actions_ubpf.stf create mode 120000 testdata/p4_16_samples/simple-firewall_ubpf.p4 create mode 100644 testdata/p4_16_samples/simple-firewall_ubpf.stf create mode 120000 testdata/p4_16_samples/tunneling_ubpf.p4 create mode 100644 testdata/p4_16_samples/tunneling_ubpf.stf create mode 100644 testdata/p4_16_samples_outputs/action_call_ubpf-first.p4 create mode 100644 testdata/p4_16_samples_outputs/action_call_ubpf-frontend.p4 create mode 100644 testdata/p4_16_samples_outputs/action_call_ubpf-midend.p4 create mode 100644 testdata/p4_16_samples_outputs/action_call_ubpf.p4 create mode 100644 testdata/p4_16_samples_outputs/action_call_ubpf.p4-stderr create mode 100644 testdata/p4_16_samples_outputs/csum_ubpf-first.p4 create mode 100644 testdata/p4_16_samples_outputs/csum_ubpf-frontend.p4 create mode 100644 testdata/p4_16_samples_outputs/csum_ubpf-midend.p4 create mode 100644 testdata/p4_16_samples_outputs/csum_ubpf.p4 create mode 100644 testdata/p4_16_samples_outputs/csum_ubpf.p4-stderr create mode 100644 testdata/p4_16_samples_outputs/hash_ubpf-first.p4 create mode 100644 testdata/p4_16_samples_outputs/hash_ubpf-frontend.p4 create mode 100644 testdata/p4_16_samples_outputs/hash_ubpf-midend.p4 create mode 100644 testdata/p4_16_samples_outputs/hash_ubpf.p4 create mode 100644 testdata/p4_16_samples_outputs/hash_ubpf.p4-stderr create mode 100644 testdata/p4_16_samples_outputs/ipv4-actions_ubpf-first.p4 create mode 100644 testdata/p4_16_samples_outputs/ipv4-actions_ubpf-frontend.p4 create mode 100644 testdata/p4_16_samples_outputs/ipv4-actions_ubpf-midend.p4 create mode 100644 testdata/p4_16_samples_outputs/ipv4-actions_ubpf.p4 create mode 100644 testdata/p4_16_samples_outputs/ipv4-actions_ubpf.p4-stderr create mode 100644 testdata/p4_16_samples_outputs/ipv6-actions_ubpf-first.p4 create mode 100644 testdata/p4_16_samples_outputs/ipv6-actions_ubpf-frontend.p4 create mode 100644 testdata/p4_16_samples_outputs/ipv6-actions_ubpf-midend.p4 create mode 100644 testdata/p4_16_samples_outputs/ipv6-actions_ubpf.p4 create mode 100644 testdata/p4_16_samples_outputs/ipv6-actions_ubpf.p4-stderr create mode 100644 testdata/p4_16_samples_outputs/metadata_ubpf-first.p4 create mode 100644 testdata/p4_16_samples_outputs/metadata_ubpf-frontend.p4 create mode 100644 testdata/p4_16_samples_outputs/metadata_ubpf-midend.p4 create mode 100644 testdata/p4_16_samples_outputs/metadata_ubpf.p4 create mode 100644 testdata/p4_16_samples_outputs/metadata_ubpf.p4-stderr create mode 100644 testdata/p4_16_samples_outputs/simple-actions_ubpf-first.p4 create mode 100644 testdata/p4_16_samples_outputs/simple-actions_ubpf-frontend.p4 create mode 100644 testdata/p4_16_samples_outputs/simple-actions_ubpf-midend.p4 create mode 100644 testdata/p4_16_samples_outputs/simple-actions_ubpf.p4 create mode 100644 testdata/p4_16_samples_outputs/simple-actions_ubpf.p4-stderr create mode 100644 testdata/p4_16_samples_outputs/simple-firewall_ubpf-first.p4 create mode 100644 testdata/p4_16_samples_outputs/simple-firewall_ubpf-frontend.p4 create mode 100644 testdata/p4_16_samples_outputs/simple-firewall_ubpf-midend.p4 create mode 100644 testdata/p4_16_samples_outputs/simple-firewall_ubpf.p4 create mode 100644 testdata/p4_16_samples_outputs/simple-firewall_ubpf.p4-stderr create mode 100644 testdata/p4_16_samples_outputs/tunneling_ubpf-first.p4 create mode 100644 testdata/p4_16_samples_outputs/tunneling_ubpf-frontend.p4 create mode 100644 testdata/p4_16_samples_outputs/tunneling_ubpf-midend.p4 create mode 100644 testdata/p4_16_samples_outputs/tunneling_ubpf.p4 create mode 100644 testdata/p4_16_samples_outputs/tunneling_ubpf.p4-stderr diff --git a/.travis.yml b/.travis.yml index 99970272c55..7d06d0b83c4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -41,4 +41,4 @@ install: script: - if [[ $TRAVIS_OS_NAME == 'linux' && $UNIFIED == ON ]] ; then docker run -w /p4c/build -e CTEST_PARALLEL_LEVEL p4c ctest --output-on-failure --schedule-random ; fi - - if [[ $TRAVIS_OS_NAME == 'osx' && $UNIFIED == ON ]] ; then ctest --output-on-failure -j 2 --schedule-random -LE "ebpf$" ; fi + - if [[ $TRAVIS_OS_NAME == 'osx' && $UNIFIED == ON ]] ; then ctest --output-on-failure -j 2 --schedule-random -LE "bpf$" ; fi diff --git a/CMakeLists.txt b/CMakeLists.txt index d1c703a6930..2dad387f823 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -32,6 +32,7 @@ OPTION (ENABLE_DOCS "Build the documentation" OFF) OPTION (ENABLE_GTESTS "Enable building and running GTest unit tests" ON) OPTION (ENABLE_BMV2 "Build the BMV2 backend (required for the full test suite)" ON) OPTION (ENABLE_EBPF "Build the EBPF backend (required for the full test suite)" ON) +OPTION (ENABLE_UBPF "Build the uBPF backend (required for the full test suite)" ON) OPTION (ENABLE_P4TEST "Build the P4Test backend (required for the full test suite)" ON) OPTION (ENABLE_P4C_GRAPHS "Build the p4c-graphs backend" ON) OPTION (ENABLE_PROTOBUF_STATIC "Link against Protobuf statically" ON) @@ -277,6 +278,9 @@ endif () if (ENABLE_EBPF) add_subdirectory (backends/ebpf) endif () +if (ENABLE_UBPF) + add_subdirectory (backends/ubpf) +endif () if (ENABLE_P4TEST) add_subdirectory (backends/p4test) endif () diff --git a/backends/ebpf/midend.h b/backends/ebpf/midend.h index bc17705b0ff..441dd2ab7c2 100644 --- a/backends/ebpf/midend.h +++ b/backends/ebpf/midend.h @@ -25,8 +25,8 @@ limitations under the License. namespace EBPF { class MidEnd { - std::vector hooks; public: + std::vector hooks; P4::ReferenceMap refMap; P4::TypeMap typeMap; diff --git a/backends/ebpf/targets/ubpf_target.py b/backends/ebpf/targets/ubpf_target.py new file mode 120000 index 00000000000..4672ea6f139 --- /dev/null +++ b/backends/ebpf/targets/ubpf_target.py @@ -0,0 +1 @@ +../../ubpf/targets/ubpf_target.py \ No newline at end of file diff --git a/backends/ubpf/CMakeLists.txt b/backends/ubpf/CMakeLists.txt new file mode 100644 index 00000000000..a7968fa8faa --- /dev/null +++ b/backends/ubpf/CMakeLists.txt @@ -0,0 +1,85 @@ +# Copyright 2019 Orange +# +# 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. + +# CMakefile for the uBPF P4-16 backend. + +configure_file("${CMAKE_CURRENT_SOURCE_DIR}/version.h.cmake" + "${CMAKE_CURRENT_BINARY_DIR}/version.h" @ONLY) + +set(P4C_UBPF_SOURCES + p4c-ubpf.cpp + ubpfBackend.cpp + ubpfProgram.cpp + ubpfParser.cpp + ubpfDeparser.cpp + ubpfControl.cpp + ubpfType.cpp + ubpfTable.cpp + ubpfRegister.cpp + ubpfModel.cpp + target.cpp + midend.cpp + ../../backends/ebpf/ebpfProgram.cpp + ../../backends/ebpf/ebpfTable.cpp + ../../backends/ebpf/ebpfParser.cpp + ../../backends/ebpf/ebpfControl.cpp + ../../backends/ebpf/ebpfOptions.cpp + ../../backends/ebpf/target.cpp + ../../backends/ebpf/codeGen.cpp + ../../backends/ebpf/ebpfType.cpp + ../../backends/ebpf/ebpfModel.cpp + ../../backends/ebpf/midend.cpp + ../../backends/ebpf/lower.cpp) + +set(P4C_UBPF_HEADERS + codeGen.h + ubpfProgram.h + ubpfType.h + ubpfParser.h + ubpfDeparser.h + ubpfControl.h + ubpfRegister.h + ubpfModel.h + target.h + midend.h + ubpfBackend.h) + +set (P4C_UBPF_DIST_HEADERS p4include/ubpf_model.p4) + +add_cpplint_files(${CMAKE_CURRENT_SOURCE_DIR} "$(P4C_UBPF_SOURCES)") + +build_unified(P4C_UBPF_SOURCES ALL) +add_executable(p4c-ubpf ${P4C_UBPF_SOURCES}) +target_link_libraries (p4c-ubpf ${P4C_LIBRARIES} ${P4C_LIB_DEPS}) +add_dependencies(p4c-ubpf genIR frontend) + +install (TARGETS p4c-ubpf + RUNTIME DESTINATION ${P4C_RUNTIME_OUTPUT_DIRECTORY}) +install (DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/p4include + DESTINATION ${P4C_ARTIFACTS_OUTPUT_DIRECTORY}) + + +add_custom_target(linkp4cubpf + COMMAND ${CMAKE_COMMAND} -E create_symlink ${CMAKE_CURRENT_BINARY_DIR}/p4c-ubpf ${P4C_BINARY_DIR}/p4c-ubpf + COMMAND ${CMAKE_COMMAND} -E make_directory ${P4C_BINARY_DIR}/p4include && + ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/${P4C_UBPF_DIST_HEADERS} ${P4C_BINARY_DIR}/p4include + COMMAND ${CMAKE_COMMAND} -E create_symlink ${P4C_BINARY_DIR}/p4include ${CMAKE_CURRENT_BINARY_DIR}/p4include + ) + +add_dependencies(p4c_driver linkp4cubpf) + +set(UBPF_DRIVER "${CMAKE_CURRENT_SOURCE_DIR}/run-ubpf-test.py -t ubpf -c \"${P4C_BINARY_DIR}/p4c-ubpf\"") +set (UBPF_TEST_SUITES ${P4C_SOURCE_DIR}/testdata/p4_16_samples/*_ubpf.p4) +set (UBPF_XFAIL_TESTS) +p4c_add_tests("ubpf" ${UBPF_DRIVER} "${UBPF_TEST_SUITES}" "${UBPF_XFAIL_TESTS}") \ No newline at end of file diff --git a/backends/ubpf/README.md b/backends/ubpf/README.md new file mode 100644 index 00000000000..2f9eb2e27a9 --- /dev/null +++ b/backends/ubpf/README.md @@ -0,0 +1,82 @@ +# Introduction to uBPF Backend + +The **p4c-ubpf** compiler allows to translate P4 programs into the uBPF programs. We use the uBPF implementation provided +by [the P4rt-OVS switch](https://github.com/Orange-OpenSource/p4rt-ovs). The uBPF VM is based on the +open-source implementation provided by [IOVisor](https://github.com/iovisor/ubpf). + +The P4-to-uBPF compiler accepts only the P4_16 programs written for the [ubpf_model.p4](../ubpf/p4include/ubpf_model.p4) architecture model. + +The backend for uBPF is mostly based on [P4-to-eBPF compiler](../ebpf/README.md). In fact, it implements the same concepts, but +generates C code, which is compatible with the user space BPF implementation. + +## Background + +### P4 + +Please, refer to [the overview of P4 written in eBPF Backend](../ebpf#p4). + +### uBPF + +**Why uBPF?** The uBPF Virtual Machine can be used in any solution implementing the kernel bypass (e.g. DPDK apps). + +The uBPF project re-implements the [eBPF](../ebpf#ebpf) kernel-based Virtual Machine. While the BPF programs are +intented to run in the kernel, the uBPF project enables running the BPF programs in user-space applications. It contains +eBPF assembler, disassembler, interpreter, and JIT compiler for x86-64. + +Moreover, contrary to the eBPF implementation, uBPF is not licensed under GPL. The uBPF implementation is licensed under +Apache License, version 2.0. + +## Compiling P4 to uBPF + +The scope of the uBPF backend is wider than the scope of the eBPF backend. Except for simple packet filtering the +P4-to-uBPF compiler supports also P4 registers and programmable actions including packet's modifications and tunneling. For further details +refer to [uBPF architecture model](p4include/ubpf_model.p4). + +The current version of the P4-to-uBPF compiler translates P4_16 programs to programs written in the C language. This +program is compatible with the uBPF VM and the `clang` compiler can be used to generate uBPF bytecode. + +### Translation between P4 and C + +We follow the convention of the P4-to-eBPF compiler so the parser translation is presented in the table +[Translating parsers](../ebpf#translating-parsers) from P4-to-eBPF. The translation of match-action pipelines is presented +in the [Translating match-action pipelines](../ebpf#translating-match-action-pipelines) table from P4-to-eBPF. + +However, we introduced some modifications, which are listed below: + +* The generated code uses user-level data types (e.g. uint8_t, etc.). +* Methods to extract packet fields (e.g. load_dword, etc.) have been re-implemented to use user-space data types. +* The uBPF helpers are imported into the C programs. +* We have added `mark_to_drop()` extern to the `ubpf` model, so that packets to drop are marked in the P4-native way. +* We have added support for P4 registers implemented as BPF maps + +### How to use? + +The sample P4 programs are located in `examples/` directory. We have tested them with the [P4rt-OVS](https://github.com/Orange-OpenSource/p4rt-ovs) switch - +the Open vSwitch that can be extended with BPF programs at runtime. See [the detailed tutorial](./docs/EXAMPLES.md) on how to run and test those examples. + +In order to generate the C code use the following command: + +`p4c-ubpf PROGRAM.p4 -o out.c` + +This command will generate out.c and the corresponding out.h file containing definitions of the packet structures and BPF maps. + +Once the C program is generated it can be compiled using: + +`clang -O2 -target bpf -c out.c -o /tmp/out.o` + +The output file (`out.o`) can be injected to the uBPF VM. + +### Known limitations + +* No support for some P4 constructs (meters, counters, etc.) + +### Contact + +Tomasz Osiński <tomasz.osinski2@orange.com> + +Mateusz Kossakowski <mateusz.kossakowski@orange.com> + + + + + diff --git a/backends/ubpf/codeGen.h b/backends/ubpf/codeGen.h new file mode 100644 index 00000000000..a80d6209b60 --- /dev/null +++ b/backends/ubpf/codeGen.h @@ -0,0 +1,17 @@ +#ifndef P4C_CODEGEN_H +#define P4C_CODEGEN_H + +#include "lib/sourceCodeBuilder.h" +#include "ebpf/codeGen.h" +#include "target.h" + +namespace UBPF { + class UbpfCodeBuilder : public EBPF::CodeBuilder { + public: + const UbpfTarget *target; + explicit UbpfCodeBuilder(const UbpfTarget *target) : EBPF::CodeBuilder(target), target(target) {} + }; +} + + +#endif //P4C_CODEGEN_H diff --git a/backends/ubpf/docs/EXAMPLES.md b/backends/ubpf/docs/EXAMPLES.md new file mode 100644 index 00000000000..ca06633ecd1 --- /dev/null +++ b/backends/ubpf/docs/EXAMPLES.md @@ -0,0 +1,216 @@ +# Introduction + +This file contains description of the basic P4 programs, which were used to test the functionality of the P4-to-uBPF compiler. +All tests have been run on the [P4rt-OVS](https://github.com/Orange-OpenSource/p4rt-ovs) switch. +You can use [Vagrantfile](../tests/environment/Vagrantfile) to set up a test environment. + +Before any experiment the following commands need to be invoked: + +```bash +# compile P4 program to C code +$ p4c-ubpf -o test.c PROGRAM.p4 +$ sudo ovs-ofctl del-flows br0 +# compile test.c to BPF machine code +$ clang-6.0 -O2 -I .. -target bpf -c test.c -o /tmp/test.o +# Load filter BPF program +$ sudo ovs-ofctl load-bpf-prog br0 1 /tmp/test.o +# Setup rules to forward traffic (bidirectional) +$ sudo ovs-ofctl add-flow br0 in_port=2,actions=prog:1,output:1 +$ sudo ovs-ofctl add-flow br0 in_port=1,actions=prog:1,output:2 +``` + +**Note!** The P4-uBPF compiler works properly with `clang-6.0`. We noticed some problems when using older versions of clang (e.g. 3.9). + +# Examples + +This section presents how to run and test the P4-uBPF compiler. + +## Packet modification + +This section presents a P4 program, which modifies the packet's fields. + +### IPv4 + MPLS (simple-actions.p4) + +**Key:** Source IPv4 address + +**Actions:** + +* mpls_decrement_ttl +* mpls_set_label +* mpls_set_label_decrement_ttl +* mpls_modify_tc +* mpls_set_label_tc +* mpls_modify_stack +* change_ip_ver +* ip_swap_addrs +* ip_modify_saddr +* Reject + +Sample usage: + +```bash +# Template: ovs-ofctl update-bpf-map key value +$ sudo ovs-ofctl update-bpf-map br0 1 0 key 14 0 16 172 value 0 0 0 0 0 0 0 0 0 0 0 0 # decrements MPLS TTL +$ sudo ovs-ofctl update-bpf-map br0 1 0 key 14 0 16 172 value 1 0 0 0 24 0 0 0 0 0 0 0 # sets MPLS label to 24 +$ sudo ovs-ofctl update-bpf-map br0 1 0 key 14 0 16 172 value 2 0 0 0 24 0 0 0 0 0 0 0 # sets MPLS label to 24 and decrements TTL +$ sudo ovs-ofctl update-bpf-map br0 1 0 key 14 0 16 172 value 3 0 0 0 3 0 0 0 0 0 0 0 # modifies MPLS TC (set value to 3) +$ sudo ovs-ofctl update-bpf-map br0 1 0 key 14 0 16 172 value 4 0 0 0 24 0 0 0 1 0 0 0 # sets MPLS label to 24 and TC to 1 +$ sudo ovs-ofctl update-bpf-map br0 1 0 key 14 0 16 172 value 5 0 0 0 1 0 0 0 0 0 0 0 # modifies stack value of MPLS header +$ sudo ovs-ofctl update-bpf-map br0 1 0 key 14 0 16 172 value 6 0 0 0 6 0 0 0 0 0 0 0 # changes IP version to 6. +$ sudo ovs-ofctl update-bpf-map br0 1 0 key 14 0 16 172 value 7 0 0 0 0 0 0 0 0 0 0 0 # swaps IP addresses +$ sudo ovs-ofctl update-bpf-map br0 1 0 key 14 0 16 172 value 8 0 0 0 1 0 16 172 0 0 0 0 # sets source IP address to 172.16.0.1 +``` + +### IPv6 (ipv6-actions.p4) + +The aim of this example is to test modification of wider packet's fields. Thus, we have used the IPv6 headers. + +The match key is source IPv6 address. The P4 program implements three actions: + +* ipv6_modify_dstAddr - modifies IPv6 destination address; +* ipv6_swap_addr - swaps IPv6 addresses. +* set_flowlabel - tests modification of custom-length field, where `length % 8 != 0`. + +Sample usage: +```bash +# Changes destination IPv6 address from fe80::a00:27ff:fe7e:b95 to e00::: (simple, random value) +$ sudo ovs-ofctl update-bpf-map br0 1 0 key 254 128 0 0 0 0 0 0 10 0 39 255 254 21 180 17 value 0 0 0 0 14 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +# Swaps source and destination IPv6 addresses +$ sudo ovs-ofctl update-bpf-map br0 1 0 key 254 128 0 0 0 0 0 0 10 0 39 255 254 21 180 17 value 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +# Sets Flow Label to 1. +$ sudo ovs-ofctl update-bpf-map br0 1 0 key 254 128 0 0 0 0 0 0 10 0 39 255 254 21 180 17 value 2 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 +``` + +## Registers + +This section presents P4 programs, which use registers. Register can be declared this way: + +`Register(number_of_elements) register_t;` + +The parameters are as follows: + +- `value_type` - is bit array type (i.e. bit<32>) or struct like type +- `key_type` - is bit array type (i.e. bit<32>) or struct like type +- `number_of_elements` - the maximum number of key-value pairs + +Currently, the `ubpf` architecture model does not allow to initialize registers with default values. +Initialization has to be done by a control plane. + +### Rate limiter (rate-limiter.p4) + +The rate limiter uses two registers. First which counts the number of packets and second which holds timestamps. + +This rate limiter limits the number of packets per second. +Responsible for that are two variables BUCKET_SIZE and WINDOW_SIZE placed in rate-limiter.p4 file. +For instance now BUCKET_SIZE has value of 10 and WINDOW_SIZE has value of 100. +It means that 10 packets are passed in 100 ms window. It also means 100 packets per second. +If you send 1470 Bytes width packets the bit rate should not exceed 1.176 Mbit/s (1470B * 8 * (10/100ms)). + +Due to registers limitation before starting your own tests initialize rate limiter registers with zeros: + +```bash +# Initalizes timestamp_r register +$ sudo ovs-ofctl update-bpf-map br0 1 0 key 0 0 0 0 value 0 0 0 0 +# Initalizes count_r register +$ sudo ovs-ofctl update-bpf-map br0 1 1 key 0 0 0 0 value 0 0 0 0 +``` + +To measure the bandwidth use the `iperf` tool: + +Start a `iperf` UDP server + +```bash +$ iperf -s -u +``` + +Then, run `iperf` client: + +```bash +$ iperf -c -b 10M -l 1470 +``` + +### Rate limiter (rate-limiter-structs.p4) + +The same rate limiter as above, but implemented using structs. + +### Packet counter (packet-counter.p4) + +The packet counter counts every packet passed via the program. +Before tests initialize packet counter register with zeros: + +```bash +# Initalizes packet_counter_reg register +$ sudo ovs-ofctl update-bpf-map br0 1 0 key 0 0 0 0 value 0 0 0 0 +``` + +Then generate any network traffic. To check if the program counts packets use i.e. + +```bash +$ watch sudo ovs-ofctl dump-bpf-map br0 1 0 +``` + +### Simple firewall (simple-firewall.p4) + +This is very simple example of stateful firewall. Every TCP packet is analyzed to track the state of the TCP connection. +If the traffic belongs to known connection it is passed. Otherwise, it is dropped. +Notice that the example program uses hash function which is constrained to hash only 64 bit values - that's why TCP connection is identified via IP source and destination address. +This is the known limitation of the `uBPF` backend used in P4rt-OVS (to be fixed in the future). + +Due to registers limitation before starting your own tests initialize simple firewall registers with zeros: + +```bash +# Initalizes conn_state register (key is a output from a hash function for client(192.168.1.10) and server (192.168.1.1)) +$ sudo ovs-ofctl update-bpf-map br0 1 0 key 172 192 20 5 value 0 0 0 0 +# Initalizes conn_srv_addr register (key is a output from a hash function for client(192.168.1.10) and server (192.168.1.1)) +$ sudo ovs-ofctl update-bpf-map br0 1 1 key 172 192 20 5 value 0 0 0 0 +``` + +To test simple firewall you can use as an example `ptf/simple-firewall-test.py` test. + +## Tunneling + +This section presents more complex examples of packet tunneling operations. There are two P4 programs used: + +* `tunneling.p4`, which implements MPLS tunneling, +* `vxlan.p4`, which implements more complex packet tunneling: VXLAN. + +### VXLAN + +To run example compile `vxlan.p4` with `p4c` and then `clang-6.0`. + +Sample usage: + +```bash +# Sets action vxlan_decap() (value 0) for packets matching rule VNI=25 (key 25) +# handled by the table upstream_tbl (map id 0) and BPF prog 1. +sudo ovs-ofctl update-bpf-map br0 1 0 key 25 0 0 0 value 0 0 0 0 +# Sets action vxlan_encap() (value 0) for packets matching rule IP dstAddr=172.16.0.14 (key 14 0 16 172) +# handled by the table downstream_tbl (map id 1) and BPF prog 1. +sudo ovs-ofctl update-bpf-map br0 1 1 key 14 0 16 172 value 0 0 0 0 +``` + +### GPRS Tunneling Protocol (GTP) + +To run example compile `gtp.p4` with `p4c` and then `clang-6.0`. + +To test encapsulation: + +```bash +# For downstream_tbl (ID 1) sets action gtp_encap() (value 0) and GTP TEID=3 for packets with destination IP address 172.16.0.14. +$ sudo ovs-ofctl update-bpf-map br0 1 1 key 14 0 16 172 value 0 0 0 0 3 0 0 0 +``` + +To test decapsulation: + +```bash +# For upstream_tbl (ID 0) sets action gtp_decap() for packets matching GTP TEID=3. +$ sudo ovs-ofctl update-bpf-map br0 1 0 key 3 0 0 0 value 0 0 0 0 +``` + +Scapy can be used to easily test GTP protocol: + +```python +>>> load_contrib('gtp') +>>> p = Ether(dst='08:00:27:7e:0b:95', src='08:00:27:15:b4:11')/IP(dst='172.16.0.14', src='172.16.0.12')/UDP(sport=2152,dport=2152)/GTPHeader(teid=3)/IP(dst='172.16.0.14', src='172.16.0.12')/ICMP() +>>> sendp(p, iface='eth1') +``` \ No newline at end of file diff --git a/backends/ubpf/examples/gtp.p4 b/backends/ubpf/examples/gtp.p4 new file mode 100644 index 00000000000..7ba1197e2ff --- /dev/null +++ b/backends/ubpf/examples/gtp.p4 @@ -0,0 +1,215 @@ +/* +Copyright 2019 Orange + +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 +#include + +typedef bit<48> EthernetAddress; +typedef bit<32> IPv4Address; + +const bit<16> UDP_PORT_GTP = 2152; +const bit<8> UDP_PROTO = 17; +const bit<16> IPV4_ETHTYPE = 0x800; +const bit<16> ETH_HDR_SIZE = 14; +const bit<16> IPV4_HDR_SIZE = 20; +const bit<16> UDP_HDR_SIZE = 8; +const bit<16> GTP_HDR_SIZE = 8; +const bit<4> IP_VERSION_4 = 4; +const bit<4> IPV4_MIN_IHL = 5; + +// standard Ethernet header +header Ethernet_h +{ + EthernetAddress dstAddr; + EthernetAddress srcAddr; + bit<16> etherType; +} + +// IPv4 header without options +header IPv4_h { + bit<4> version; + bit<4> ihl; + bit<8> diffserv; + bit<16> totalLen; + bit<16> identification; + bit<3> flags; + bit<13> fragOffset; + bit<8> ttl; + bit<8> protocol; + bit<16> hdrChecksum; + IPv4Address srcAddr; + IPv4Address dstAddr; +} + +header udp_t { + bit<16> srcPort; + bit<16> dstPort; + bit<16> length; + bit<16> checksum; +} + +header gtp_t { + bit<3> version; + bit<1> ptFlag; + bit<1> spare; + bit<1> extHdrFlag; + bit<1> seqNumberFlag; + bit<1> npduFlag; + bit<8> msgType; + bit<16> len; + bit<32> tunnelEndID; +} + + +struct Headers_t { + Ethernet_h ethernet; + IPv4_h ipv4; + udp_t udp; + gtp_t gtp; + IPv4_h inner_ipv4; +} + +struct metadata {} + +parser prs(packet_in packet, out Headers_t hdr, inout metadata meta) { + state start { + transition parse_ethernet; + } + state parse_ethernet { + packet.extract(hdr.ethernet); + transition select(hdr.ethernet.etherType) { + IPV4_ETHTYPE: parse_ipv4; + default: accept; + } + } + + state parse_ipv4 { + packet.extract(hdr.ipv4); + transition select(hdr.ipv4.protocol) { + UDP_PROTO: parse_udp; + default: accept; + } + } + state parse_udp { + packet.extract(hdr.udp); + transition select(hdr.udp.dstPort) { + UDP_PORT_GTP: parse_gtp; + default: accept; + } + } + state parse_gtp { + packet.extract(hdr.gtp); + transition parse_inner_ipv4; + } + + state parse_inner_ipv4 { + packet.extract(hdr.inner_ipv4); + transition accept; + } +} + +control pipe(inout Headers_t hdr, inout metadata meta) { + + action gtp_decap() { + // as simple as set outer headers as invalid + hdr.ipv4.setInvalid(); + hdr.udp.setInvalid(); + hdr.gtp.setInvalid(); + } + + table upstream_tbl { + key = { + hdr.gtp.tunnelEndID : exact; + } + actions = { + gtp_decap; + NoAction; + } + } + + action gtp_encap(bit<32> tunnelId) { + hdr.inner_ipv4 = hdr.ipv4; + + hdr.ipv4.setValid(); + hdr.ipv4.version = IP_VERSION_4; + hdr.ipv4.ihl = IPV4_MIN_IHL; + hdr.ipv4.diffserv = 0; + hdr.ipv4.totalLen = hdr.ipv4.totalLen + + (IPV4_HDR_SIZE + UDP_HDR_SIZE + GTP_HDR_SIZE); + hdr.ipv4.identification = 0x1513; /* From NGIC */ + hdr.ipv4.flags = 0; + hdr.ipv4.fragOffset = 0; + hdr.ipv4.ttl = 64; + hdr.ipv4.protocol = UDP_PROTO; + hdr.ipv4.dstAddr = hdr.inner_ipv4.dstAddr; + hdr.ipv4.srcAddr = hdr.inner_ipv4.srcAddr; + hdr.ipv4.hdrChecksum = 0; + + hdr.udp.setValid(); + + hdr.udp.srcPort = 15221; // random port + hdr.udp.dstPort = UDP_PORT_GTP; + hdr.udp.length = hdr.inner_ipv4.totalLen + (UDP_HDR_SIZE + GTP_HDR_SIZE); + hdr.udp.checksum = 0; + + hdr.gtp.setValid(); + hdr.gtp.tunnelEndID = tunnelId; + hdr.gtp.version = 0x01; + hdr.gtp.ptFlag = 0x01; + hdr.gtp.spare =0; + hdr.gtp.extHdrFlag =0; + hdr.gtp.seqNumberFlag =0; + hdr.gtp.npduFlag = 0; + hdr.gtp.msgType = 0xff; + hdr.gtp.len = hdr.inner_ipv4.totalLen; + + } + + + table downstream_tbl { + key = { + hdr.ipv4.dstAddr : exact; + } + actions = { + gtp_encap; + NoAction; + } + } + + + apply { + if (hdr.gtp.isValid()) { + upstream_tbl.apply(); + } else { + if (hdr.ipv4.isValid()) { + downstream_tbl.apply(); + } + } + + } +} + +control dprs(packet_out packet, in Headers_t hdr) { + apply { + packet.emit(hdr.ethernet); + packet.emit(hdr.ipv4); + packet.emit(hdr.udp); + packet.emit(hdr.gtp); + packet.emit(hdr.inner_ipv4); + } +} + +ubpf(prs(), pipe(), dprs()) main; \ No newline at end of file diff --git a/backends/ubpf/examples/ipv4-actions.p4 b/backends/ubpf/examples/ipv4-actions.p4 new file mode 120000 index 00000000000..d147754244c --- /dev/null +++ b/backends/ubpf/examples/ipv4-actions.p4 @@ -0,0 +1 @@ +../tests/testdata/test-ipv4-actions.p4 \ No newline at end of file diff --git a/backends/ubpf/examples/ipv6-actions.p4 b/backends/ubpf/examples/ipv6-actions.p4 new file mode 120000 index 00000000000..d1af9c71ecf --- /dev/null +++ b/backends/ubpf/examples/ipv6-actions.p4 @@ -0,0 +1 @@ +../tests/testdata/test-ipv6-actions.p4 \ No newline at end of file diff --git a/backends/ubpf/examples/packet-counter.p4 b/backends/ubpf/examples/packet-counter.p4 new file mode 100644 index 00000000000..46954ff4bb6 --- /dev/null +++ b/backends/ubpf/examples/packet-counter.p4 @@ -0,0 +1,101 @@ +#include +#include + +typedef bit<48> EthernetAddress; +typedef bit<32> IPv4Address; + +#define IPV4_ETHTYPE 0x800 +#define ETH_HDR_SIZE 14 +#define IPV4_HDR_SIZE 20 +#define UDP_HDR_SIZE 8 +#define IP_VERSION_4 4 +#define IPV4_MIN_IHL 5 + +const bit<8> PROTO_ICMP = 1; + +// standard Ethernet header +header Ethernet_h +{ + EthernetAddress dstAddr; + EthernetAddress srcAddr; + bit<16> etherType; +} + +// IPv4 header without options +header IPv4_h { + bit<4> version; + bit<4> ihl; + bit<8> diffserv; + bit<16> totalLen; + bit<16> identification; + bit<3> flags; + bit<13> fragOffset; + bit<8> ttl; + bit<8> protocol; + bit<16> hdrChecksum; + IPv4Address srcAddr; + IPv4Address dstAddr; +} + +header icmp_t { + bit<8> type; + bit<8> code; + bit<16> checksum; + bit<32> rest; +} + +struct Headers_t { + Ethernet_h ethernet; + IPv4_h ipv4; + icmp_t icmp; +} + +struct metadata {} + +parser prs(packet_in packet, out Headers_t hdr, inout metadata meta) { + state start { + transition parse_ethernet; + } + state parse_ethernet { + packet.extract(hdr.ethernet); + transition select(hdr.ethernet.etherType) { + IPV4_ETHTYPE: parse_ipv4; + default: accept; + } + } + + state parse_ipv4 { + packet.extract(hdr.ipv4); + transition select(hdr.ipv4.protocol) { + PROTO_ICMP: parce_icmp; + default: accept; + } + } + + state parce_icmp { + packet.extract(hdr.icmp); + transition accept; + } +} + +control pipe(inout Headers_t hdr, inout metadata meta) { + + Register, bit<32>>(1) packet_counter_reg; + + apply { + bit<32> last_count; + bit<32> index = 0; + last_count = packet_counter_reg.read(index); + packet_counter_reg.write(index, last_count + 1); + } +} + +control dprs(packet_out packet, in Headers_t hdr) { + apply { + packet.emit(hdr.ethernet); + packet.emit(hdr.ipv4); + packet.emit(hdr.icmp); + } +} + +ubpf(prs(), pipe(), dprs()) main; \ No newline at end of file diff --git a/backends/ubpf/examples/rate-limiter-structs.p4 b/backends/ubpf/examples/rate-limiter-structs.p4 new file mode 100644 index 00000000000..a1810187f5c --- /dev/null +++ b/backends/ubpf/examples/rate-limiter-structs.p4 @@ -0,0 +1,85 @@ +/* +Copyright 2019 Orange + +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 +#include + +//BUCKET_SIZE is a number of packets passed in a time window that has WINDOW_SIZE size +#define BUCKET_SIZE 10 +//WINDOW_SIZE is in nanoseconds +#define WINDOW_SIZE 100 + +struct reg_value_time { + bit<48> value; +} + +struct reg_value_count { + bit<32> value; +} + +struct reg_key { + bit<32> value; +} + +struct Headers_t {} + +struct metadata {} + +parser prs(packet_in p, out Headers_t headers, inout metadata meta) { + state start { + transition accept; + } +} + +control pipe(inout Headers_t headers, inout metadata meta) { + Register(1) timestamp_r; + Register(1) count_r; + + apply { + reg_key r_k; + r_k.value = 0; + + reg_value_count last_count; + reg_value_time last_ts; + last_count = count_r.read(r_k); + last_ts = timestamp_r.read(r_k); + + reg_value_time time_diff; + time_diff.value = ubpf_time_get_ns() - last_ts.value;//All timestamps are in nanoseconds + + if (time_diff.value > WINDOW_SIZE * 1000000) { + reg_value_count zero_count; + zero_count.value = 0; + count_r.write(r_k, zero_count); + reg_value_time current_time; + current_time.value = ubpf_time_get_ns(); + timestamp_r.write(r_k, current_time); + } + + if (last_count.value < BUCKET_SIZE) { + last_count.value = last_count.value + 1; + count_r.write(r_k, last_count); + } else { + mark_to_drop(); + } + } +} + +control dprs(packet_out packet, in Headers_t headers) { + apply { } +} + +ubpf(prs(), pipe(), dprs()) main; diff --git a/backends/ubpf/examples/rate-limiter.p4 b/backends/ubpf/examples/rate-limiter.p4 new file mode 100644 index 00000000000..ac365f347ba --- /dev/null +++ b/backends/ubpf/examples/rate-limiter.p4 @@ -0,0 +1,68 @@ +/* +Copyright 2019 Orange + +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 +#include + +//BUCKET_SIZE is a number of packets passed in a time window that has WINDOW_SIZE size +#define BUCKET_SIZE 10 +//WINDOW_SIZE is in nanoseconds +#define WINDOW_SIZE 100 + +struct Headers_t {} + +struct metadata {} + +parser prs(packet_in p, out Headers_t headers, inout metadata meta) { + state start { + transition accept; + } +} + +control pipe(inout Headers_t headers, inout metadata meta) { + Register, bit<32>>(1) timestamp_r; + Register, bit<32>>(1) count_r; + + apply { + + bit<32> last_count; + bit<48> last_ts; + bit<32> index = 0; + last_count = count_r.read(index); + last_ts = timestamp_r.read(index); + + bit<48> time_diff; + time_diff = ubpf_time_get_ns() - last_ts;//All timestamps are in nanoseconds + + if (time_diff > WINDOW_SIZE * 1000000) { + count_r.write(index, 0); + timestamp_r.write(index, ubpf_time_get_ns()); + } + + if (last_count < BUCKET_SIZE) { + count_r.write(index, last_count + 1); + } else { + mark_to_drop(); + return; + } + } +} + +control dprs(packet_out packet, in Headers_t headers) { + apply { } +} + +ubpf(prs(), pipe(), dprs()) main; diff --git a/backends/ubpf/examples/simple-actions.p4 b/backends/ubpf/examples/simple-actions.p4 new file mode 120000 index 00000000000..1a565395565 --- /dev/null +++ b/backends/ubpf/examples/simple-actions.p4 @@ -0,0 +1 @@ +../tests/testdata/test-simple-actions.p4 \ No newline at end of file diff --git a/backends/ubpf/examples/simple-firewall.p4 b/backends/ubpf/examples/simple-firewall.p4 new file mode 120000 index 00000000000..da7ee315d41 --- /dev/null +++ b/backends/ubpf/examples/simple-firewall.p4 @@ -0,0 +1 @@ +../tests/testdata/test-simple-firewall.p4 \ No newline at end of file diff --git a/backends/ubpf/examples/tunneling.p4 b/backends/ubpf/examples/tunneling.p4 new file mode 120000 index 00000000000..40d056f26fd --- /dev/null +++ b/backends/ubpf/examples/tunneling.p4 @@ -0,0 +1 @@ +../tests/testdata/test-tunneling.p4 \ No newline at end of file diff --git a/backends/ubpf/examples/vxlan.p4 b/backends/ubpf/examples/vxlan.p4 new file mode 100644 index 00000000000..e25fb59c643 --- /dev/null +++ b/backends/ubpf/examples/vxlan.p4 @@ -0,0 +1,222 @@ +/* +Copyright 2019 Orange + +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 +#include + +const bit<16> UDP_PORT_VXLAN = 4789; +const bit<8> UDP_PROTO = 17; +const bit<16> IPV4_ETHTYPE = 0x800; +const bit<16> ETH_HDR_SIZE = 14; +const bit<16> IPV4_HDR_SIZE = 20; +const bit<16> UDP_HDR_SIZE = 8; +const bit<16> VXLAN_HDR_SIZE = 8; +const bit<4> IP_VERSION_4 = 4; +const bit<4> IPV4_MIN_IHL = 5; + +typedef bit<48> EthernetAddress; +typedef bit<32> IPv4Address; + +// standard Ethernet header +header Ethernet_h +{ + EthernetAddress dstAddr; + EthernetAddress srcAddr; + bit<16> etherType; +} + +// IPv4 header without options +header IPv4_h { + bit<4> version; + bit<4> ihl; + bit<8> diffserv; + bit<16> totalLen; + bit<16> identification; + bit<3> flags; + bit<13> fragOffset; + bit<8> ttl; + bit<8> protocol; + bit<16> hdrChecksum; + IPv4Address srcAddr; + IPv4Address dstAddr; +} + +header udp_t { + bit<16> srcPort; + bit<16> dstPort; + bit<16> length; + bit<16> checksum; +} + +header vxlan_t { + bit<8> flags; + bit<24> reserved; + bit<24> vni; + bit<8> reserved_2; +} + +struct Headers_t { + Ethernet_h ethernet; + IPv4_h ipv4; + udp_t udp; + vxlan_t vxlan; + + Ethernet_h inner_ethernet; + IPv4_h inner_ipv4; +} + +struct metadata { + bit<24> vxlan_vni; + bit<32> nexthop; + bit<32> vtepIP; +} + +parser prs(packet_in packet, out Headers_t hdr, inout metadata meta) { + state start { + transition parse_ethernet; + } + state parse_ethernet { + packet.extract(hdr.ethernet); + transition select(hdr.ethernet.etherType) { + IPV4_ETHTYPE: parse_ipv4; + default: accept; + } + } + + state parse_ipv4 { + packet.extract(hdr.ipv4); + transition select(hdr.ipv4.protocol) { + UDP_PROTO: parse_udp; + default: accept; + } + } + state parse_udp { + packet.extract(hdr.udp); + transition select(hdr.udp.dstPort) { + UDP_PORT_VXLAN: parse_vxlan; + default: accept; + } + } + state parse_vxlan { + packet.extract(hdr.vxlan); + transition parse_inner_ethernet; + } + state parse_inner_ethernet { + packet.extract(hdr.inner_ethernet); + transition select(hdr.ethernet.etherType) { + IPV4_ETHTYPE: parse_inner_ipv4; + default: accept; + } + } + state parse_inner_ipv4 { + packet.extract(hdr.inner_ipv4); + transition accept; + } +} + + +control pipe(inout Headers_t hdr, inout metadata meta) { + + action vxlan_decap() { + // as simple as set outer headers as invalid + hdr.ethernet.setInvalid(); + hdr.ipv4.setInvalid(); + hdr.udp.setInvalid(); + hdr.vxlan.setInvalid(); + } + + table upstream_tbl { + key = { + hdr.vxlan.vni : exact; + } + actions = { + vxlan_decap; + NoAction; + } + + } + + action vxlan_encap() { + hdr.inner_ethernet = hdr.ethernet; + hdr.inner_ipv4 = hdr.ipv4; + + hdr.ethernet.setValid(); + + hdr.ipv4.setValid(); + hdr.ipv4.version = IP_VERSION_4; + hdr.ipv4.ihl = IPV4_MIN_IHL; + hdr.ipv4.diffserv = 0; + hdr.ipv4.totalLen = hdr.ipv4.totalLen + + (ETH_HDR_SIZE + IPV4_HDR_SIZE + UDP_HDR_SIZE + VXLAN_HDR_SIZE); + hdr.ipv4.identification = 0x1513; /* From NGIC */ + hdr.ipv4.flags = 0; + hdr.ipv4.fragOffset = 0; + hdr.ipv4.ttl = 64; + hdr.ipv4.protocol = UDP_PROTO; + hdr.ipv4.dstAddr = hdr.inner_ipv4.dstAddr; + hdr.ipv4.srcAddr = hdr.inner_ipv4.srcAddr; + hdr.ipv4.hdrChecksum = 0; + + hdr.udp.setValid(); + + hdr.udp.srcPort = 15221; // random port + hdr.udp.dstPort = UDP_PORT_VXLAN; + hdr.udp.length = hdr.ipv4.totalLen + (UDP_HDR_SIZE + VXLAN_HDR_SIZE); + hdr.udp.checksum = 0; + + hdr.vxlan.setValid(); + hdr.vxlan.reserved = 0; + hdr.vxlan.reserved_2 = 0; + hdr.vxlan.flags = 0; + hdr.vxlan.vni = 25; + + } + + table downstream_tbl { + key = { + hdr.ipv4.dstAddr : exact; + } + actions = { + vxlan_encap; + NoAction; + } + + } + + apply { + if (hdr.vxlan.isValid()) { + upstream_tbl.apply(); + } else { + if (hdr.ipv4.isValid()) { + downstream_tbl.apply(); + } + } + + } +} + +control dprs(packet_out packet, in Headers_t hdr) { + apply { + packet.emit(hdr.ethernet); + packet.emit(hdr.ipv4); + packet.emit(hdr.udp); + packet.emit(hdr.vxlan); + packet.emit(hdr.inner_ethernet); + packet.emit(hdr.inner_ipv4); + } +} + +ubpf(prs(), pipe(), dprs()) main; \ No newline at end of file diff --git a/backends/ubpf/midend.cpp b/backends/ubpf/midend.cpp new file mode 100644 index 00000000000..b6a28c77ef3 --- /dev/null +++ b/backends/ubpf/midend.cpp @@ -0,0 +1,135 @@ +/* +Copyright 2019 Orange + +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 "midend.h" +#include "frontends/common/constantFolding.h" +#include "frontends/common/resolveReferences/resolveReferences.h" +#include "frontends/p4/evaluator/evaluator.h" +#include "frontends/p4/moveDeclarations.h" +#include "frontends/p4/simplify.h" +#include "frontends/p4/simplifyParsers.h" +#include "frontends/p4/strengthReduction.h" +#include "frontends/p4/toP4/toP4.h" +#include "frontends/p4/typeChecking/typeChecker.h" +#include "frontends/p4/typeMap.h" +#include "frontends/p4/uniqueNames.h" +#include "frontends/p4/unusedDeclarations.h" +#include "midend/actionSynthesis.h" +#include "midend/complexComparison.h" +#include "midend/convertEnums.h" +#include "midend/eliminateNewtype.h" +#include "midend/eliminateTuples.h" +#include "midend/local_copyprop.h" +#include "midend/midEndLast.h" +#include "midend/noMatch.h" +#include "midend/removeLeftSlices.h" +#include "midend/removeMiss.h" +#include "midend/removeParameters.h" +#include "midend/removeSelectBooleans.h" +#include "midend/simplifyKey.h" +#include "midend/simplifySelectCases.h" +#include "midend/simplifySelectList.h" +#include "midend/singleArgumentSelect.h" +#include "midend/tableHit.h" +#include "midend/validateProperties.h" +#include "backends/ebpf/lower.h" + +namespace UBPF { + + class EnumOn32Bits : public P4::ChooseEnumRepresentation { + bool convert(const IR::Type_Enum* type) const override { + if (type->srcInfo.isValid()) { + auto sourceFile = type->srcInfo.getSourceFile(); + if (sourceFile.endsWith("_model.p4")) + // Don't convert any of the standard enums + return false; + } + return true; + } + unsigned enumSize(unsigned) const override + { return 32; } + }; + + const IR::ToplevelBlock* + MidEnd::run(EbpfOptions& options, const IR::P4Program* program, std::ostream* outStream) { + if (program == nullptr && options.listMidendPasses == 0) + return nullptr; + + bool isv1 = options.langVersion == CompilerOptions::FrontendVersion::P4_14; + refMap.setIsV1(isv1); + auto evaluator = new P4::EvaluatorPass(&refMap, &typeMap); + + PassManager midEnd = {}; + if (options.loadIRFromJson == false) { + std::initializer_list midendPasses = { + new P4::ConvertEnums(&refMap, &typeMap, new EnumOn32Bits()), + new P4::RemoveMiss(&refMap, &typeMap), + new P4::ClearTypeMap(&typeMap), + new P4::EliminateNewtype(&refMap, &typeMap), + new P4::SimplifyControlFlow(&refMap, &typeMap), + new P4::RemoveActionParameters(&refMap, &typeMap), + new P4::SimplifyKey(&refMap, &typeMap, + new P4::OrPolicy( + new P4::IsValid(&refMap, &typeMap), + new P4::IsLikeLeftValue())), + new P4::ConstantFolding(&refMap, &typeMap), + new P4::SimplifySelectCases(&refMap, &typeMap, false), // accept non-constant keysets + new P4::HandleNoMatch(&refMap), + new P4::SimplifyParsers(&refMap), + new P4::StrengthReduction(&refMap, &typeMap), + new P4::SimplifyComparisons(&refMap, &typeMap), + new P4::LocalCopyPropagation(&refMap, &typeMap), + new P4::SimplifySelectList(&refMap, &typeMap), + new P4::MoveDeclarations(), // more may have been introduced + new P4::RemoveSelectBooleans(&refMap, &typeMap), + new P4::SingleArgumentSelect(), + new P4::ConstantFolding(&refMap, &typeMap), + new P4::SimplifyControlFlow(&refMap, &typeMap), + new P4::TableHit(&refMap, &typeMap), + new P4::RemoveLeftSlices(&refMap, &typeMap), + new EBPF::Lower(&refMap, &typeMap), + evaluator, + new P4::MidEndLast() + }; + if (options.listMidendPasses) { + for (auto it : midendPasses) { + if (it != nullptr) { + *outStream << it->name() <<'\n'; + } + } + return nullptr; + } + midEnd = midendPasses; + if (options.excludeMidendPasses) { + midEnd.removePasses(options.passesToExcludeMidend); + } + } else { + midEnd = { + new P4::ResolveReferences(&refMap), + new P4::TypeChecking(&refMap, &typeMap), + evaluator + }; + } + midEnd.setName("MidEnd"); + midEnd.addDebugHooks(hooks); + program = program->apply(midEnd); + if (::errorCount() > 0) + return nullptr; + + return evaluator->getToplevelBlock(); + } +} + diff --git a/backends/ubpf/midend.h b/backends/ubpf/midend.h new file mode 100644 index 00000000000..403906d61b4 --- /dev/null +++ b/backends/ubpf/midend.h @@ -0,0 +1,37 @@ +/* +Copyright 2019 Orange + +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. +*/ + +#ifndef _BACKENDS_UBPF_MIDEND_H_ +#define _BACKENDS_UBPF_MIDEND_H_ + +#include "ir/ir.h" +#include "backends/ebpf/midend.h" +#include "backends/ebpf/ebpfOptions.h" + +namespace UBPF { + +class MidEnd : public EBPF::MidEnd { + + +public: + explicit MidEnd() : EBPF::MidEnd() {} + const IR::ToplevelBlock* run(EbpfOptions& options, const IR::P4Program* program, + std::ostream* outStream = nullptr); +}; + +} // namespace UBPF + +#endif //_BACKENDS_UBPF_MIDEND_H_ \ No newline at end of file diff --git a/backends/ubpf/p4c-ubpf.cpp b/backends/ubpf/p4c-ubpf.cpp new file mode 100644 index 00000000000..c7da5730cb1 --- /dev/null +++ b/backends/ubpf/p4c-ubpf.cpp @@ -0,0 +1,92 @@ +/* +Copyright 2019 Orange + +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 +#include +#include + +#include "backends/ubpf/version.h" +#include "ir/ir.h" +#include "lib/log.h" +#include "lib/gc.h" +#include "lib/crash.h" +#include "lib/exceptions.h" +#include "lib/nullstream.h" + +#include "backends/ubpf/midend.h" +#include "backends/ebpf/ebpfOptions.h" +#include "ubpfBackend.h" +#include "frontends/p4/frontend.h" +#include "frontends/common/applyOptionsPragmas.h" +#include "frontends/common/parseInput.h" +#include "ir/json_loader.h" +#include "fstream" + +void compile(EbpfOptions& options) { + auto hook = options.getDebugHook(); + bool isv1 = options.langVersion == CompilerOptions::FrontendVersion::P4_14; + if (isv1) { + ::error(ErrorType::ERR_UNSUPPORTED, "- this compiler only handles P4-16"); + return; + } + auto program = P4::parseP4File(options); + if (::errorCount() > 0) + return; + + P4::FrontEnd frontend; + frontend.addDebugHook(hook); + program = frontend.run(options, program); + if (::errorCount() > 0) + return; + + UBPF::MidEnd midend; + midend.addDebugHook(hook); + auto toplevel = midend.run(options, program); + if (::errorCount() > 0) + return; + + UBPF::run_ubpf_backend(options, toplevel, &midend.refMap, &midend.typeMap); +} + + +int main(int argc, char *const argv[]) { + setup_gc_logging(); + setup_signals(); + + AutoCompileContext autoEbpfContext(new EbpfContext); + auto &options = EbpfContext::get().options(); + options.compilerVersion = P4C_UBPF_VERSION_STRING; + + if (options.process(argc, argv) != nullptr) { + options.setInputFile(); + } + + if (::errorCount() > 0) + exit(1); + + try { + compile(options); + } catch (const std::exception &bug) { + std::cerr << bug.what() << std::endl; + return 1; + } + + if (Log::verbose()) + std::cout << "Done." << std::endl; + + return ::errorCount() > 0; +} + diff --git a/backends/ubpf/p4include/ubpf_model.p4 b/backends/ubpf/p4include/ubpf_model.p4 new file mode 100644 index 00000000000..26551c500da --- /dev/null +++ b/backends/ubpf/p4include/ubpf_model.p4 @@ -0,0 +1,137 @@ +/* +Copyright 2019 Orange + +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. +*/ + +#ifndef _UBPF_MODEL_P4_ +#define _UBPF_MODEL_P4_ + +#include + +/* + * The uBPF target can currently pass the packet or drop it. + * By default, all packets are passed. + * The mark_to_drop() extern can be used to mark a packet to be dropped. + * The mark_to_drop() modifies only the state hidden from the user's P4 program. + * mark_to_drop() should be called only in the 'pipe' control. + */ +extern void mark_to_drop(); + +/* + * The uBPF target can currently pass the packet or drop it. + * By default, all packets are passed. + * The mark_to_pass() extern can be used to mark a packet to be passed (it cancels previous mark_to_drop() action). + * The mark_to_pass() modifies only the state hidden from the user's P4 program. + * mark_to_pass() should be called only in the 'pipe' control. + */ +extern void mark_to_pass(); + + +extern Register { + /*** + * A Register object is created by calling its constructor. + * You must provide a size of Register. The size specifies + * the maximum number of entries stored by Register. + * After constructing the Register object, you can use it in + * both actions or apply blocks. + * The Register is not intialized when created. + */ + Register(bit<32> size); + + /*** + * read() reads the state (T) of the register array stored at the + * specified index S, and returns it as the value written to the + * result parameter. + * + * @param index The index of the register array element to be + * read, normally a value in the range [0, size-1]. + * @return Returns result of type T. Only types T that are bit + * are currently supported. When index is in range, the value of + * result becomes the value read from the register + * array element. When index >= size, the final + * value of result is not specified, and should be + * ignored by the caller. + */ + T read (in S index); + + + void write (in S index, in T value); +} + +/* + * The extern used to get the current timestamp in nanoseconds. + */ +extern bit<48> ubpf_time_get_ns(); + + +enum HashAlgorithm { + lookup3 +} + +/*** + * Calculate a hash function of the value specified by the data + * parameter. Due to the limitation of uBPF back-end the maximum width of data is bit<64>. + * + * Note that the types of all of the parameters may be the same as, or + * different from, each other, and thus their bit widths are allowed + * to be different. + * + * Note that the result will have always the bit<32> width. + * + * @param D Must be a tuple type where all the fields are bit-fields (type bit or int) or varbits. + * Maximum width of D is 64 bit (limitation of uBPF back-end). + */ +extern void hash(out bit<32> result, in HashAlgorithm algo, in D data); + +/*** + * Compute the checksum via Incremental Update (RFC 1624). + * This function implements checksum computation for 16-bit wide fields. + */ +extern bit<16> csum_replace2(in bit<16> csum, // current csum + in bit<16> old, // old value of the field + in bit<16> new); + +/*** + * Compute the checksum via Incremental Update (RFC 1624). + * This function implements checksum computation for 32-bit wide fields. + */ +extern bit<16> csum_replace4(in bit<16> csum, + in bit<32> old, + in bit<32> new); + +/* + * Architecture. + * + * M must be a struct. + * + * H must be a struct where every one of its members is of type + * header, header stack, or header_union. + */ + +parser parse(packet_in packet, out H headers, inout M meta); +control pipeline(inout H headers, inout M meta); + +/* + * The only legal statements in the body of the deparser control are: + * calls to the packet_out.emit() method. + */ +@deparser +control deparser(packet_out b, in H headers); + +package ubpf(parse prs, + pipeline p, + deparser dprs); + +#endif /* _UBPF_MODEL_P4_ */ + diff --git a/backends/ubpf/run-ubpf-test.py b/backends/ubpf/run-ubpf-test.py new file mode 100755 index 00000000000..73477063329 --- /dev/null +++ b/backends/ubpf/run-ubpf-test.py @@ -0,0 +1,44 @@ +#!/usr/bin/env python3 +# Copyright 2019 Orange +# +# 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. + +import sys +import os +import importlib + +# path to the framework repository of the compiler +sys.path.insert(0, os.path.dirname( + os.path.realpath(__file__)) + '/../ebpf') +run_ebpf_test = importlib.import_module('run-ebpf-test') + +arg_parser = run_ebpf_test.PARSER + +if __name__ == "__main__": + # Parse options and process argv + args, argv = arg_parser.parse_known_args() + options = run_ebpf_test.Options() + options.compiler = run_ebpf_test.check_path(args.compiler) + options.p4filename = run_ebpf_test.check_path(args.p4filename) + options.verbose = args.verbose + options.replace = args.replace + options.cleanupTmp = args.nocleanup + options.target = args.target + # Switch test directory based on path to run-ubpf-test.py + options.testdir = os.path.dirname(os.path.realpath(__file__)) + + # All args after '--' are intended for the p4 compiler + argv = argv[1:] + # Run the test with the extracted options and modified argv + result = run_ebpf_test.run_test(options, argv) + sys.exit(result) diff --git a/backends/ubpf/runtime/ebpf_runtime.c b/backends/ubpf/runtime/ebpf_runtime.c new file mode 100644 index 00000000000..1bcd39d83b4 --- /dev/null +++ b/backends/ubpf/runtime/ebpf_runtime.c @@ -0,0 +1,138 @@ +/* +Copyright 2020 Orange + +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 // getopt() +#include // isprint() +#include // memcpy() +#include // malloc() +#ifdef CONTROL_PLANE +#include "control.h" +#endif +#include "../../ebpf/runtime/pcap_util.h" + +#define PCAPIN "_in.pcap" +#define DELIM '_' + +static int debug = 0; + +void usage(char *name) { + fprintf(stderr, "This program expects a pcap file pattern, " + "extracts all the packets out of the matched files" + "in the order given by the packet time," + "then feeds the individual packets into a filter function, " + "and returns the output.\n"); + fprintf(stderr, "Usage: %s [-d] -f file.pcap -n num_pcaps\n", name); + fprintf(stderr, "Options:\n"); + fprintf(stderr, "\t-d: Turn on debug messages\n"); + fprintf(stderr, "\t-f: The input pcap file\n"); + fprintf(stderr, "\t-n: Specifies the number of input pcap files\n"); + exit(EXIT_FAILURE); +} + +static pcap_list_t *get_packets(const char *pcap_base, uint16_t num_pcaps, pcap_list_t *merged_list) { + pcap_list_array_t *tmp_list_array = allocate_pkt_list_array(); + /* Retrieve a list for each file and append it to the temporary array */ + for (uint16_t i = 0; i < num_pcaps; i++) { + char *pcap_in_name = generate_pcap_name(pcap_base, i, PCAPIN); + if (debug) + printf("Processing input file: %s\n", pcap_in_name); + pcap_list_t *pkt_list = read_pkts_from_pcap(pcap_in_name, i); + tmp_list_array = insert_list(tmp_list_array, pkt_list, i); + free(pcap_in_name); + } + /* Merge the array into a newly allocated list. This destroys the array. */ + return merge_and_delete_lists(tmp_list_array, merged_list); +} + +void launch_runtime(const char *pcap_name, uint16_t num_pcaps) { + if (num_pcaps == 0) + return; + /* Initialize the list of input packets */ + pcap_list_t *input_list = allocate_pkt_list(); + + /* Create the basic pcap filename from the input */ + const char *suffix = strrchr(pcap_name, DELIM); + if (suffix == NULL) { + fprintf(stderr, "Expected a filename with delimiter \"%c\"." + "Not found in %s! Exiting...\n", DELIM, pcap_name); + exit(EXIT_FAILURE); + } + int baselen = suffix - pcap_name; + char pcap_base[baselen + 1]; + snprintf(pcap_base, baselen + 1 , "%s", pcap_name); + + /* Open all matching pcap files retrieve a merged list of packets */ + input_list = get_packets(pcap_base, num_pcaps, input_list); + /* Sort the list */ + sort_pcap_list(input_list); + /* Run the "program" and retrieve output lists */ + RUN(entry, pcap_base, num_pcaps, input_list, debug); + /* Delete the list of input packets */ + delete_list(input_list); +} + +int main(int argc, char **argv) { + const char *pcap_name = NULL; + int num_pcaps = -1; + int c; + opterr = 0; + + while ((c = getopt (argc, argv, "dn:f:")) != -1) { + switch (c) { + case 'd': + debug = 1; + break; + case 'n': + num_pcaps = (int)strtol(optarg, (char **)NULL, 10); + if (num_pcaps < 0 || num_pcaps > UINT16_MAX) { + fprintf(stderr, + "Number of inputs out of bounds! Maximum is %d\n", + UINT16_MAX); + return EXIT_FAILURE; + } + break; + case 'f': + pcap_name = optarg; + break; + case '?': + if (optopt == 'f') + fprintf(stderr, "The input trace file is missing. " + "Expected .pcap file as input argument.\n"); + else if (isprint (optopt)) + fprintf (stderr, "Unknown option `-%c'.\n", optopt); + else + fprintf(stderr,"Unknown option character `\\x%x'.\n", + optopt); + return EXIT_FAILURE; + default: + usage(argv[0]); + return EXIT_FAILURE; + } + } + + /* Check if there was actually any file or number input */ + if (!pcap_name || num_pcaps == -1) + usage(argv[0]); + +#ifdef CONTROL_PLANE + /* Run all commands specified in the control file */ + setup_control_plane(); +#endif + + launch_runtime(pcap_name, num_pcaps); + + return EXIT_SUCCESS; +} diff --git a/backends/ubpf/runtime/ebpf_runtime_ubpf.c b/backends/ubpf/runtime/ebpf_runtime_ubpf.c new file mode 100644 index 00000000000..dfb59c5ea2e --- /dev/null +++ b/backends/ubpf/runtime/ebpf_runtime_ubpf.c @@ -0,0 +1,70 @@ +/* +Copyright 2020 Orange + +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 +#include "ebpf_runtime_ubpf.h" + + +#define PCAPOUT "_out.pcap" + +pcap_list_t *feed_packets(packet_filter ebpf_filter, pcap_list_t *pkt_list, int debug) { + pcap_list_t *output_pkts = allocate_pkt_list(); + uint32_t list_len = get_pkt_list_length(pkt_list); + for (uint32_t i = 0; i < list_len; i++) { + /* Parse each packet in the list and check the result */ + struct dp_packet dp; + pcap_pkt *input_pkt = get_packet(pkt_list, i); + dp.data = (void *) input_pkt->data; + dp.size_ = input_pkt->pcap_hdr.len; + int result = ebpf_filter(&dp, dp.size_); + /* Updating input_pkt's length */ + input_pkt->pcap_hdr.len = dp.size_; + input_pkt->pcap_hdr.caplen = dp.size_; + if (result != 0) { + /* We copy the entire content to emulate an outgoing packet */ + pcap_pkt *out_pkt = copy_pkt(input_pkt); + output_pkts = append_packet(output_pkts, out_pkt); + } + if (debug) + printf("Result of the eBPF parsing is: %d\n", result); + } + return output_pkts; +} + +void write_pkts_to_pcaps(const char *pcap_base, pcap_list_array_t *output_array, int debug) { + uint16_t arr_len = get_list_array_length(output_array); + for (uint16_t i = 0; i < arr_len; i++) { + char *pcap_out_name = generate_pcap_name(pcap_base, i, PCAPOUT); + if (debug) + printf("Processing output file: %s\n", pcap_out_name); + pcap_list_t *out_list = get_list(output_array, i); + write_pkts_to_pcap(pcap_out_name, out_list); + free(pcap_out_name); + } +} + +void *run_and_record_output(packet_filter entry, const char *pcap_base, pcap_list_t *pkt_list, int debug) { + /* Create an array of packet lists */ + pcap_list_array_t *output_array = allocate_pkt_list_array(); + /* Feed the packets into our "loaded" program */ + pcap_list_t *output_pkts = feed_packets(entry, pkt_list, debug); + /* Split the output packet list by interface. This destroys the list. */ + output_array = split_and_delete_list(output_pkts, output_array); + /* Write each list to a separate pcap output file */ + write_pkts_to_pcaps(pcap_base, output_array, debug); + /* Delete the array, including the data it is holding */ + delete_array(output_array); +} \ No newline at end of file diff --git a/backends/ubpf/runtime/ebpf_runtime_ubpf.h b/backends/ubpf/runtime/ebpf_runtime_ubpf.h new file mode 100644 index 00000000000..8c6d6485767 --- /dev/null +++ b/backends/ubpf/runtime/ebpf_runtime_ubpf.h @@ -0,0 +1,62 @@ +/* +Copyright 2020 Orange + +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. +*/ + +#ifndef P4C_EBPF_RUNTIME_UBPF_H +#define P4C_EBPF_RUNTIME_UBPF_H + +#include +#include "../../ebpf/runtime/pcap_util.h" +#include "../../ebpf/runtime/ebpf_registry.h" +#include "ubpf_test.h" + +typedef uint64_t (*packet_filter)(void *dp, uint64_t pkt_len); + +extern uint64_t entry(void *dp, uint64_t pkt_len); + +void *run_and_record_output(packet_filter entry, const char *pcap_base, pcap_list_t *pkt_list, int debug); + +static void inline init_ubpf_table_test(char *name, unsigned int key_size, unsigned int value_size) { + struct bpf_table tbl = { + .name = name, + .type = 0, + .key_size = key_size, + .value_size = value_size, + .bpf_map = NULL + }; + registry_add(&tbl); +} + + +#define ubpf_printf(fmt, args) \ + ubpf_printf_test(fmt, args) +#define ubpf_packet_data(ctx) \ + ubpf_packet_data_test(ctx) +#define ubpf_adjust_head(ctx, ofs) \ + ubpf_adjust_head_test(ctx, ofs) +#define ubpf_map_lookup(table, key) \ + registry_lookup_table_elem(#table, key) +#define ubpf_map_update(table, key, value) \ + registry_update_table(#table, key, value, 0) + +#define INIT_UBPF_TABLE(name, key_size, value_size) init_ubpf_table_test("&"name, key_size, value_size) + +#define RUN(entry, pcap_base, num_pcaps, input_list, debug) \ + run_and_record_output(entry, pcap_base, input_list, debug) +#define INIT_EBPF_TABLES(debug) +#define DELETE_EBPF_TABLES(debug) + + +#endif //P4C_EBPF_RUNTIME_UBPF_H \ No newline at end of file diff --git a/backends/ubpf/runtime/runtime.mk b/backends/ubpf/runtime/runtime.mk new file mode 100644 index 00000000000..f786184b7ba --- /dev/null +++ b/backends/ubpf/runtime/runtime.mk @@ -0,0 +1,68 @@ +# If needed, bpf target files can be hardcoded here +# This can be any file with the extension ".c" +BPFOBJ= +# Get the source name of the object to match targets +BPFNAME=$(basename $(BPFOBJ)) +BPFDIR=$(dir $(BPFOBJ)) +override INCLUDES+= -I$(dir $(BPFOBJ)) + +# Arguments for the P4 Compiler +P4INCLUDE=-I./p4include +# P4 source file argument for the compiler (can be hardcoded) +P4FILE= +P4C=p4c-ubpf +# the default target is test but it can be overridden +TARGET=test +# Extra arguments for the compiler +P4ARGS= + +# Argument for the GCC compiler +GCC ?= gcc +SRCDIR=. +EBPFDIR=../../ebpf/runtime/ +BUILDDIR:= $(BPFDIR)build +override INCLUDES+= -I./$(SRCDIR) -include ebpf_runtime_$(TARGET).h +# Optimization flags to save space +override CFLAGS+=-O2 -g # -Wall -Werror +LIBS+=-lpcap +SOURCES=$(EBPFDIR)/ebpf_registry.c $(EBPFDIR)/ebpf_map.c $(BPFNAME).c +SRC_BASE+=$(SRCDIR)/ebpf_runtime.c $(EBPFDIR)/pcap_util.c $(SOURCES) +SRC_BASE+=$(SRCDIR)/ebpf_runtime_$(TARGET).c +OBJECTS = $(SRC_BASE:%.c=$(BUILDDIR)/%.o) +DEPS = $(OBJECTS:.o=.d) + +# checks the executable and symlinks to the output +all: $(BPFNAME).c $(BPFNAME) + # @$(RM) -rf $(BUILDDIR) + +# Creation of the executable +$(BPFNAME): $(OBJECTS) + @echo "Linking: $@" + $(GCC) $(CFLAGS) $(INCLUDES) $(OBJECTS) -o $@ $(LIBS) + +# Add dependency files, if they exist +-include $(DEPS) + +# Source file rules +# After the first compilation they will be joined with the rules from the +# dependency files to provide header dependencies +$(BUILDDIR)/%.o: $(SRCDIR)/%.c + @echo "Creating folder: $(dir $(OBJECTS))" + @mkdir -p $(dir $(OBJECTS)) + @echo "Compiling: $< -> $@" + $(GCC) $(CFLAGS) $(INCLUDES) $(LIBS) -MP -MMD -c $< -o $@ + +# If the target file is missing, generate .c files with the P4 compiler +$(BPFNAME).c: $(P4FILE) + @if ! ($(P4C) --help > /dev/null 2>&1); then \ + echo "*** ERROR: Cannot find $(P4C)"; \ + exit 1;\ + fi; + $(P4C) --Werror $(P4INCLUDE) --target $(TARGET) -o $@ $< $(P4ARGS) + +.PHONY: clean +clean: + @echo "Deleting build folder" + @$(RM) -rf $(BUILDDIR) + @$(RM) $(BPFNAME) + diff --git a/backends/ubpf/runtime/ubpf_common.h b/backends/ubpf/runtime/ubpf_common.h new file mode 100644 index 00000000000..e61fbef5ee7 --- /dev/null +++ b/backends/ubpf/runtime/ubpf_common.h @@ -0,0 +1,86 @@ +/* +Copyright 2019 Orange + +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. +*/ + +#ifndef ___constant_swab16 +#define ___constant_swab16(x) ((uint16_t)( \ + (((uint16_t)(x) & (uint16_t)0x00ffU) << 8) | \ + (((uint16_t)(x) & (uint16_t)0xff00U) >> 8))) +#endif + +#ifndef ___constant_swab32 +#define ___constant_swab32(x) ((uint32_t)( \ + (((uint32_t)(x) & (uint32_t)0x000000ffUL) << 24) | \ + (((uint32_t)(x) & (uint32_t)0x0000ff00UL) << 8) | \ + (((uint32_t)(x) & (uint32_t)0x00ff0000UL) >> 8) | \ + (((uint32_t)(x) & (uint32_t)0xff000000UL) >> 24))) +#endif + +#ifndef ___constant_swab64 +#define ___constant_swab64(x) ((uint64_t)( \ + (((uint64_t)(x) & (uint64_t)0x00000000000000ffULL) << 56) | \ + (((uint64_t)(x) & (uint64_t)0x000000000000ff00ULL) << 40) | \ + (((uint64_t)(x) & (uint64_t)0x0000000000ff0000ULL) << 24) | \ + (((uint64_t)(x) & (uint64_t)0x00000000ff000000ULL) << 8) | \ + (((uint64_t)(x) & (uint64_t)0x000000ff00000000ULL) >> 8) | \ + (((uint64_t)(x) & (uint64_t)0x0000ff0000000000ULL) >> 24) | \ + (((uint64_t)(x) & (uint64_t)0x00ff000000000000ULL) >> 40) | \ + (((uint64_t)(x) & (uint64_t)0xff00000000000000ULL) >> 56))) +#endif + +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ +#ifndef __constant_htonll +#define __constant_htonll(x) (___constant_swab64((x))) +#endif + +#ifndef __constant_ntohll +#define __constant_ntohll(x) (___constant_swab64((x))) +#endif + +#define __constant_htonl(x) (___constant_swab32((x))) +#define __constant_ntohl(x) (___constant_swab32(x)) +#define __constant_htons(x) (___constant_swab16((x))) +#define __constant_ntohs(x) ___constant_swab16((x)) + +#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ +# warning "I never tested BIG_ENDIAN machine!" +#define __constant_htonll(x) (x) +#define __constant_ntohll(X) (x) +#define __constant_htonl(x) (x) +#define __constant_ntohl(x) (x) +#define __constant_htons(x) (x) +#define __constant_ntohs(x) (x) + +#else +# error "Fix your compiler's __BYTE_ORDER__?!" +#endif + +#undef htonl +#define htonl(d) __constant_htonl(d) +#undef htons +#define htons(d) __constant_htons(d) +#undef htonll +#define htonll(d) __constant_htonll(d) +#undef ntohl +#define ntohl(d) __constant_ntohl(d) +#undef ntohs +#define ntohs(d) __constant_ntohs(d) +#undef ntohll +#define ntohll(d) __constant_ntohll(d) + +#define load_byte(data, b) (*(((uint8_t*)(data)) + (b))) +#define load_half(data, b) __constant_ntohs(*(uint16_t *)((uint8_t*)(data) + (b))) +#define load_word(data, b) __constant_ntohl(*(uint32_t *)((uint8_t*)(data) + (b))) +#define load_dword(data, b) __constant_ntohll(*(uint64_t *)((uint8_t*)(data) + (b))) \ No newline at end of file diff --git a/backends/ubpf/runtime/ubpf_test.h b/backends/ubpf/runtime/ubpf_test.h new file mode 100644 index 00000000000..bab624e1729 --- /dev/null +++ b/backends/ubpf/runtime/ubpf_test.h @@ -0,0 +1,67 @@ +/* +Copyright 2020 Orange + +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. +*/ + +#ifndef P4C_UBPF_TEST_H +#define P4C_UBPF_TEST_H + +#include +#include +#include + +#define MAX_PRINTF_LENGTH 80 + +/* simple descriptor which replaces the DPDK dp_packet structure */ +struct dp_packet { + void *data; /* First byte actually in use. */ + uint32_t size_; /* Number of bytes in use. */ +}; + +static inline void ubpf_printf_test(const char *fmt, ...) { + va_list args; + va_start(args, fmt); + char str[MAX_PRINTF_LENGTH]; + if (vsnprintf(str, MAX_PRINTF_LENGTH, fmt, args) >= 0) + printf("%s\n", str); + va_end(args); +} + +static inline void *ubpf_packet_data_test(void *ctx) { + struct dp_packet *dp = (struct dp_packet *) ctx; + return dp->data; +} + +static inline void *ubpf_adjust_head_test(void *ctx, int offset) { + struct dp_packet *dp = (struct dp_packet *) ctx; + + if (offset == 0) { + return dp->data; + } else if (offset > 0) { + dp->data = realloc(dp->data, dp->size_ + offset); + memcpy((char *) dp->data + offset, dp->data, dp->size_); + dp->size_ += offset; + return dp->data; + } else { + int ofs = abs(offset); + memcpy(dp->data, (char *) dp->data + ofs, dp->size_ - ofs); + dp->data = realloc(dp->data, dp->size_ - ofs); + dp->size_ -= ofs; + return dp->data; + } +} + + + +#endif //P4C_UBPF_TEST_H \ No newline at end of file diff --git a/backends/ubpf/target.cpp b/backends/ubpf/target.cpp new file mode 100644 index 00000000000..80cff47431b --- /dev/null +++ b/backends/ubpf/target.cpp @@ -0,0 +1,131 @@ +/* +Copyright 2019 Orange + +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 "target.h" + +namespace UBPF { + + void UbpfTarget::emitIncludes(Util::SourceCodeBuilder *builder) const { + builder->append( + "#include \n" + "#include \n" + "#include \n" + "#include \"ubpf_common.h\"\n" + "\n"); + } + + void UbpfTarget::emitMain(Util::SourceCodeBuilder *builder, + cstring functionName, + cstring argName, + cstring pktLen) const { + builder->appendFormat("uint64_t %s(void *%s, uint64_t %s)", + functionName.c_str(), argName.c_str(), pktLen.c_str()); + } + + void UbpfTarget::emitTableLookup(Util::SourceCodeBuilder *builder, + cstring tblName, + cstring key, + UNUSED cstring value) const { + builder->appendFormat("ubpf_map_lookup(&%s, &%s)", + tblName.c_str(), key.c_str()); + } + + void UbpfTarget::emitTableUpdate(Util::SourceCodeBuilder *builder, + cstring tblName, + cstring key, + cstring value) const { + builder->appendFormat("ubpf_map_update(&%s, &%s, %s)", + tblName.c_str(), key.c_str(), value.c_str()); + } + + void UbpfTarget::emitGetPacketData(Util::SourceCodeBuilder *builder, + cstring ctxVar) const { + builder->appendFormat("ubpf_packet_data(%s)", ctxVar.c_str()); + } + + void UbpfTarget::emitUbpfHelpers(EBPF::CodeBuilder *builder) const { + builder->append( + "static void *(*ubpf_map_lookup)(const void *, const void *) = (void *)1;\n" + "static int (*ubpf_map_update)(void *, const void *, void *) = (void *)2;\n" + "static int (*ubpf_map_delete)(void *, const void *) = (void *)3;\n" + "static int (*ubpf_map_add)(void *, const void *) = (void *)4;\n" + "static uint64_t (*ubpf_time_get_ns)() = (void *)5;\n" + "static uint32_t (*ubpf_hash)(const void *, uint64_t) = (void *)6;\n" + "static void (*ubpf_printf)(const char *fmt, ...) = (void *)7;\n" + "static void *(*ubpf_packet_data)(const void *) = (void *)9;\n" + "static void *(*ubpf_adjust_head)(const void *, uint64_t) = (void *)8;\n" + "\n"); + builder->newline(); + builder->appendLine( + "#define write_partial(a, w, s, v) do { *((uint8_t*)a) = ((*((uint8_t*)a)) " + "& ~(BPF_MASK(uint8_t, w) << s)) | (v << s) ; } while (0)"); + builder->appendLine("#define write_byte(base, offset, v) do { " + "*(uint8_t*)((base) + (offset)) = (v); " + "} while (0)"); + builder->newline(); + builder->append("static uint32_t\n" + "bpf_htonl(uint32_t val) {\n" + " return htonl(val);\n" + "}"); + builder->newline(); + builder->append("static uint16_t\n" + "bpf_htons(uint16_t val) {\n" + " return htons(val);\n" + "}"); + builder->newline(); + builder->append("static uint64_t\n" + "bpf_htonll(uint64_t val) {\n" + " return htonll(val);\n" + "}\n"); + builder->newline(); + } + + void UbpfTarget::emitChecksumHelpers(EBPF::CodeBuilder *builder) const { + builder->appendLine("inline uint16_t csum16_add(uint16_t csum, uint16_t addend) {\n" + " uint16_t res = csum;\n" + " res += addend;\n" + " return (res + (res < addend));\n" + "}\n" + "inline uint16_t csum16_sub(uint16_t csum, uint16_t addend) {\n" + " return csum16_add(csum, ~addend);\n" + "}\n" + "inline uint16_t csum_replace2(uint16_t csum, uint16_t old, uint16_t new) {\n" + " return (~csum16_add(csum16_sub(~csum, old), new));\n" + "}\n"); + builder->appendLine("inline uint16_t csum_fold(uint32_t csum) {\n" + " uint32_t r = csum << 16 | csum >> 16;\n" + " csum = ~csum;\n" + " csum -= r;\n" + " return (uint16_t)(csum >> 16);\n" + "}\n" + "inline uint32_t csum_unfold(uint16_t csum) {\n" + " return (uint32_t)csum;\n" + "}\n" + "inline uint32_t csum32_add(uint32_t csum, uint32_t addend) {\n" + " uint32_t res = csum;\n" + " res += addend;\n" + " return (res + (res < addend));\n" + "}\n" + "inline uint32_t csum32_sub(uint32_t csum, uint32_t addend) {\n" + " return csum32_add(csum, ~addend);\n" + "}\n" + "inline uint16_t csum_replace4(uint16_t csum, uint32_t from, uint32_t to) {\n" + " uint32_t tmp = csum32_sub(~csum_unfold(csum), from);\n" + " return csum_fold(csum32_add(tmp, to));\n" + "}"); + } + +} \ No newline at end of file diff --git a/backends/ubpf/target.h b/backends/ubpf/target.h new file mode 100644 index 00000000000..2f0d4d4e5a5 --- /dev/null +++ b/backends/ubpf/target.h @@ -0,0 +1,66 @@ +/* +Copyright 2019 Orange + +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. +*/ + +#ifndef P4C_TARGET_H +#define P4C_TARGET_H + +#include "backends/ebpf/target.h" +#include "backends/ebpf/ebpfObject.h" +#include "ubpfHelpers.h" + +namespace UBPF { + + class UBPFControlBodyTranslator; + + class UbpfTarget : public EBPF::Target { + public: + explicit UbpfTarget() : EBPF::Target("UBPF") {} + + void emitLicense(Util::SourceCodeBuilder *, cstring) const override {}; + void emitCodeSection(Util::SourceCodeBuilder *, cstring) const override {}; + void emitIncludes(Util::SourceCodeBuilder *builder) const override; + void emitTableLookup(Util::SourceCodeBuilder *builder, cstring tblName, + cstring key, cstring value) const override; + void emitTableUpdate(Util::SourceCodeBuilder *builder, cstring tblName, + cstring key, cstring value) const override; + void emitGetPacketData(Util::SourceCodeBuilder *builder, + cstring ctxVar) const; + void emitUserTableUpdate(UNUSED Util::SourceCodeBuilder *builder, UNUSED cstring tblName, + UNUSED cstring key, UNUSED cstring value) const override {}; + void emitTableDecl(UNUSED Util::SourceCodeBuilder *builder, + UNUSED cstring tblName, UNUSED EBPF::TableKind tableKind, + UNUSED cstring keyType, UNUSED cstring valueType, UNUSED unsigned size) const override {}; + void emitMain(UNUSED Util::SourceCodeBuilder *builder, + UNUSED cstring functionName, + UNUSED cstring argName) const override {}; + void emitMain(Util::SourceCodeBuilder *builder, + cstring functionName, + cstring argName, + cstring pktLen) const; + void emitUbpfHelpers(EBPF::CodeBuilder *builder) const; + void emitChecksumHelpers(EBPF::CodeBuilder *builder) const; + + cstring dataOffset(UNUSED cstring base) const override { return cstring(""); } + cstring dataEnd(UNUSED cstring base) const override { return cstring(""); } + cstring dropReturnCode() const override { return "0"; } + cstring abortReturnCode() const override { return "1"; } + cstring forwardReturnCode() const override { return "1"; } + cstring sysMapPath() const override { return ""; } + }; + +} + +#endif //P4C_TARGET_H diff --git a/backends/ubpf/targets/ubpf_target.py b/backends/ubpf/targets/ubpf_target.py new file mode 100644 index 00000000000..783ab381273 --- /dev/null +++ b/backends/ubpf/targets/ubpf_target.py @@ -0,0 +1,109 @@ +import sys +import os +from glob import glob +# path to the tools folder of the compiler +sys.path.insert(0, 'p4c/tools') +# path to the framework repository of the compiler +sys.path.insert(0, os.path.dirname( + os.path.realpath(__file__)) + '/../ebpf') +from targets.target import EBPFTarget +from targets.ebpfstf import parse_stf_file +from testutils import * + + +class Target(EBPFTarget): + + def __init__(self, tmpdir, options, template, outputs): + EBPFTarget.__init__(self, tmpdir, options, template, outputs) + # We use a different compiler, override the inherited default + components = options.compiler.split("/")[0:-1] + self.compiler = "/".join(components) + "/p4c-ubpf" + print("Compiler is", self.compiler) + + def compile_dataplane(self): + args = self.get_make_args(self.runtimedir, self.options.target) + # List of bpf programs to attach to the interface + args += "BPFOBJ=" + self.template + " " + args += "CFLAGS+=-DCONTROL_PLANE " + errmsg = "Failed to build the filter:" + return run_timeout(self.options.verbose, args, TIMEOUT, + self.outputs, errmsg) + + def run(self): + report_output(self.outputs["stdout"], + self.options.verbose, "Running model") + direction = "in" + pcap_pattern = self.filename('', direction) + num_files = len(glob(self.filename('*', direction))) + report_output(self.outputs["stdout"], + self.options.verbose, + "Input file: %s" % pcap_pattern) + # Main executable + args = self.template + " " + # Input pcap pattern + args += "-f " + pcap_pattern + " " + # Number of input interfaces + args += "-n " + str(num_files) + " " + # Debug flag (verbose output) + args += "-d" + errmsg = "Failed to execute the filter:" + result = run_timeout(self.options.verbose, args, + TIMEOUT, self.outputs, errmsg) + return result + + def _generate_control_actions(self, cmds): + generated = "" + + tables = { cmd.table for cmd in cmds } + for tbl in tables: + generated += "INIT_UBPF_TABLE(\"%s\", sizeof(struct %s_key), sizeof(struct %s_value));\n\t" \ + % (tbl, tbl, tbl) + + for index, cmd in enumerate(cmds): + key_name = "key_%s%d" % (cmd.table, index) + value_name = "value_%s%d" % (cmd.table, index) + if cmd.a_type == "add": + generated += "struct %s_key %s = {};\n\t" % (cmd.table, key_name) + for key_num, key_field in enumerate(cmd.match): + field = key_field[0].split('.')[1] + generated += ("%s.%s = %s;\n\t" + % (key_name, field, key_field[1])) + generated += ("struct %s_value %s = {\n\t\t" % ( + cmd.table, value_name)) + generated += ".action = %s,\n\t\t" % (cmd.action[0]) + generated += ".u = {.%s = {" % cmd.action[0] + for val_num, val_field in enumerate(cmd.action[1]): + generated += "%s," % val_field[1] + generated += "}},\n\t" + generated += "};\n\t" + generated += ("ubpf_map_update" + "(&%s, &%s, &%s);\n\t" + % (cmd.table, key_name, value_name)) + return generated + + def create_ubpf_table_file(self, actions, tmpdir, file_name): + err = "" + try: + with open(tmpdir + "/" + file_name, "w+") as control_file: + control_file.write("#include \"test.h\"\n\n") + control_file.write("static inline void setup_control_plane() {") + control_file.write("\n\t") + generated_cmds = self._generate_control_actions(actions) + control_file.write(generated_cmds) + control_file.write("}\n") + except OSError as e: + err = e + return FAILURE, err + return SUCCESS, err + + def generate_model_inputs(self, stffile): + with open(stffile) as raw_stf: + input_pkts, cmds, self.expected = parse_stf_file( + raw_stf) + result, err = self.create_ubpf_table_file(cmds, self.tmpdir, "control.h") + if result != SUCCESS: + return result + result = self._write_pcap_files(input_pkts) + if result != SUCCESS: + return result + return SUCCESS \ No newline at end of file diff --git a/backends/ubpf/tests/README.md b/backends/ubpf/tests/README.md new file mode 100644 index 00000000000..6b5d4f450f4 --- /dev/null +++ b/backends/ubpf/tests/README.md @@ -0,0 +1,56 @@ +# Steps to run tests + +Tests use two VMs: +- `switch` - on this VM we run PTF tests +- `generator` - expose two interfaces to P4rt-OVS switch installed on switch VM + +**Note.** As P4rt-OVS (the test uBPF target) is built on top of DPDK the tests require to be run in virtual +environment with two VMs (`generator` + `switch`). + +0. Install `Virtualbox` and `Vagrant` on you machine: + + `sudo apt install -y virtualbox vagrant` + +1. Install and configure environment for tests + + ```bash + $ cd environment + $ vagrant up + ``` + +2. Run PTF agent on generator machine + + ```bash + $ vagrant ssh generator + $ cd ptf/ptf_nn/ + $ sudo python ptf_nn_agent.py --device-socket 0@tcp://192.168.100.20:10001 -i 0-1@enp0s8 -i 0-2@enp0s9 -v + ``` + +3. Compile P4 programs on switch machine + + ```bash + $ vagrant ssh switch + $ cd p4c/backends/ubpf/tests + $ sudo python compile_testdata.py + ``` + +4. Run tests on switch machine + + ```bash + $ vagrant ssh switch + $ cd p4c/backends/ubpf/tests + $ sudo ptf --failfast --test-dir ptf/ --device-socket 0-{1-2}@tcp://192.168.100.20:10001 --platform nn + ``` + + **Important** + + After any system's reboot the below scripts have to be run again: + + ```bash + $ cd /vagrant + $ ./configure_dpdk.sh #This script configures dpdk interfaces that p4rt-ovs switch use + $ ./run_switch.sh # This script runs p4rt-switch + ``` + + In case of tests errors please check if the `p4rt-ovs` switch is up and running (ie. `ps aux`). + \ No newline at end of file diff --git a/backends/ubpf/tests/compile_testdata.py b/backends/ubpf/tests/compile_testdata.py new file mode 100644 index 00000000000..8668841cda2 --- /dev/null +++ b/backends/ubpf/tests/compile_testdata.py @@ -0,0 +1,94 @@ +#!/usr/bin/env python + +# Copyright 2019 Orange +# +# 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. + +import os +import subprocess +from os import listdir + + +def compile_p4_to_c(filename): + file = filename + ".p4" + p4_file_path = os.path.join("testdata", file) + output_file_path = os.path.join("build", filename + ".c") + + if os.path.exists(p4_file_path): + print "Compiling %s.p4 ..." % filename + cmd = ["p4c-ubpf", "-o", output_file_path, p4_file_path, "-vvv", "-I../p4include"] + print "Command: ", ' '.join(str(x) for x in cmd) + proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + output, error = proc.communicate() + + if error and "error" in error: + print "Error: ", error + raise Exception(error) + + if output: + print "Output: ", output + + else: + print "File %s was not found under testdata folder" % filename + return + + +def compile_c_to_o(filename): + print "Compiling %s.c ..." % filename + file = filename + ".c" + c_file_path = os.path.join("build", file) + output_file_path = os.path.join("build", filename + ".o") + cmd = ["$CLANG_DIR/build/bin/clang", "-O2", "-target", "bpf", "-c", c_file_path, "-o", output_file_path, + "-I../runtime"] + print "Command: ", ' '.join(str(x) for x in cmd) + proc = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) + output, error = proc.communicate() + + if output: + print "Output: ", output + + if error: + print "Error: ", error + + +def main(): + print "Creating build directory ..." + + if not os.path.exists("build"): + os.makedirs("build") + + print "Starting compiling P4 programs..." + + for file in listdir("testdata/"): + if file.endswith(".p4"): + + filename, extension = os.path.splitext(file) + + try: + compile_p4_to_c(filename) + except Exception as e: + print e + print "p4c - stopping compilation" + break + + try: + compile_c_to_o(filename) + print "\n" + except Exception as e: + print e + print "clang - stopping compilation" + break + + +if __name__ == '__main__': + main() diff --git a/backends/ubpf/tests/environment/Vagrantfile b/backends/ubpf/tests/environment/Vagrantfile new file mode 100644 index 00000000000..974eab057a3 --- /dev/null +++ b/backends/ubpf/tests/environment/Vagrantfile @@ -0,0 +1,80 @@ +# -*- mode: ruby -*- +# vi: set ft=ruby : + +# Copyright 2019 Orange +# +# 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. + +$script = <