Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Generalized array support #5115

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 0 additions & 3 deletions backends/p4tools/common/core/abstract_execution_state.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -158,9 +158,6 @@ std::vector<IR::StateVariable> AbstractExecutionState::getFlatFields(
for (size_t arrayIndex = 0; arrayIndex < typeStack->getSize(); arrayIndex++) {
const auto *newArr =
HSIndexToMember::produceStackIndex(stackElementsType, parent, arrayIndex);
BUG_CHECK(stackElementsType->is<IR::Type_StructLike>(),
"Trying to get the flat fields for a non Type_StructLike element : %1%",
stackElementsType);
auto subFields = getFlatFields(newArr, validVector);
flatFields.insert(flatFields.end(), subFields.begin(), subFields.end());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,14 @@ p4tools_add_xfail_reason(
loop-3-clause-tricky2.p4
)

p4tools_add_xfail_reason(
"testgen-p4c-bmv2-metadata"
"Cast failed"
# testgen has issues with arrays
array1.p4
array2.p4
)

####################################################################################################
# 3. WONTFIX
####################################################################################################
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,14 @@ p4tools_add_xfail_reason(
loop-3-clause-tricky2.p4
)

p4tools_add_xfail_reason(
"testgen-p4c-bmv2-ptf"
"Cast failed"
# testgen has issues with arrays
array1.p4
array2.p4
)

####################################################################################################
# 3. WONTFIX
# These are failures that can not be solved by changing P4Testgen
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,14 @@ p4tools_add_xfail_reason(
loop-3-clause-tricky2.p4
)

p4tools_add_xfail_reason(
"testgen-p4c-bmv2-protobuf-ir"
"Cast failed"
# testgen has issues with arrays
array1.p4
array2.p4
)

####################################################################################################
# 3. WONTFIX
####################################################################################################
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,14 @@ p4tools_add_xfail_reason(
loop-3-clause-tricky2.p4
)

p4tools_add_xfail_reason(
"testgen-p4c-bmv2-stf"
"Cast failed"
# testgen has issues with arrays
array1.p4
array2.p4
)

####################################################################################################
# 3. WONTFIX
# These are failures that can not be solved by changing P4Testgen
Expand Down
7 changes: 6 additions & 1 deletion frontends/p4/typeChecking/typeCheckExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1706,7 +1706,12 @@ const IR::Node *TypeInferenceBase::postorder(const IR::Member *expression) {

if (auto *stack = type->to<IR::Type_Stack>()) {
auto parser = findContext<IR::P4Parser>();
if (member == IR::Type_Stack::next || member == IR::Type_Stack::last) {
auto eltype = stack->elementType;
if (auto sc = eltype->to<IR::Type_SpecializedCanonical>()) eltype = sc->baseType;
if (!eltype->is<IR::Type_Header>() && !eltype->is<IR::Type_HeaderUnion>()) {
typeError("%1%: '%2%' can only be used on header stacks", expression, member);
return expression;
} else if (member == IR::Type_Stack::next || member == IR::Type_Stack::last) {
if (parser == nullptr) {
typeError("%1%: 'last', and 'next' for stacks can only be used in a parser",
expression);
Expand Down
11 changes: 10 additions & 1 deletion frontends/p4/typeChecking/typeCheckTypes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -382,9 +382,11 @@ const IR::Node *TypeInferenceBase::postorder(const IR::Type_Stack *type) {
auto etype = canon->to<IR::Type_Stack>()->elementType;
if (etype == nullptr) return type;

#if 0
if (!etype->is<IR::Type_Header>() && !etype->is<IR::Type_HeaderUnion>() &&
!etype->is<IR::Type_SpecializedCanonical>())
typeError("Header stack %1% used with non-header type %2%", type, etype->toString());
#endif
return type;
}

Expand Down Expand Up @@ -422,7 +424,14 @@ const IR::Node *TypeInferenceBase::postorder(const IR::StructField *field) {
const IR::Node *TypeInferenceBase::postorder(const IR::Type_Header *type) {
auto canon = setTypeType(type);
auto validator = [this](const IR::Type *t) {
while (t->is<IR::Type_Newtype>()) t = getTypeType(t->to<IR::Type_Newtype>()->type);
while (1) {
if (t->is<IR::Type_Newtype>())
t = getTypeType(t->to<IR::Type_Newtype>()->type);
else if (auto *st = t->to<IR::Type_Stack>())
t = st->elementType;
else
break;
}
return t->is<IR::Type_Bits>() || t->is<IR::Type_Varbits>() ||
(t->is<IR::Type_Struct>() && onlyBitsOrBitStructs(t)) || t->is<IR::Type_SerEnum>() ||
t->is<IR::Type_Boolean>() || t->is<IR::Type_Var>() ||
Expand Down
67 changes: 47 additions & 20 deletions frontends/parsers/p4/p4parser.ypp
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,15 @@ inline std::ostream& operator<<(std::ostream& out, const OptionalConst& oc) {
// forbidden in C++. We avoid the problem using a typedef.
typedef const IR::Type ConstType;

struct NameTypePair {
const IR::ID *name;
const IR::Type *type;
};

inline std::ostream &operator<<(std::ostream &out, const NameTypePair &nt) {
return out << nt.name << ":" << nt.type;
}

} // namespace P4

#ifndef YYDEBUG
Expand Down Expand Up @@ -251,6 +260,7 @@ using namespace P4;


%type<IR::ID*> name dot_name nonTypeName nonTableKwName annotationName
%type<NameTypePair> declarator
%type<IR::Direction> direction
%type<IR::Path*> prefixedNonTypeName prefixedType
%type<IR::IndexedVector<IR::Type_Var>*> typeParameterList
Expand All @@ -262,6 +272,7 @@ using namespace P4;
nonBraceExpression forCollectionExpr
%type<ConstType*> baseType typeOrVoid specializedType headerStackType
typeRef tupleType typeArg realTypeArg namedType p4listType
derivedTypeDeclarationAsType
%type<IR::Type_Name*> typeName
%type<IR::Argument*> argument
%type<IR::Vector<IR::Argument>*> argumentList nonEmptyArgList
Expand Down Expand Up @@ -745,8 +756,10 @@ nonEmptyParameterList
;

parameter
: optAnnotations direction typeRef name { $$ = new IR::Parameter(@4, *$4, *$1, $2, $3, nullptr); }
| optAnnotations direction typeRef name "=" expression { $$ = new IR::Parameter(@4, *$4, *$1, $2, $3, $6); }
: optAnnotations direction typeRef declarator {
$$ = new IR::Parameter(@4, *$4.name, *$1, $2, $4.type, nullptr); }
| optAnnotations direction typeRef declarator "=" expression {
$$ = new IR::Parameter(@4, *$4.name, *$1, $2, $4.type, $6); }
;

direction
Expand Down Expand Up @@ -1075,8 +1088,7 @@ tupleType
;

headerStackType
: typeName "[" expression "]" { $$ = new IR::Type_Stack(@1+@4, $1, $3); }
| specializedType "[" expression "]" { $$ = new IR::Type_Stack(@1+@4, $1, $3); }
: typeRef "[" expression "]" { $$ = new IR::Type_Stack(@1+@4, $1, $3); }
;

specializedType
Expand Down Expand Up @@ -1169,6 +1181,12 @@ derivedTypeDeclaration
| enumDeclaration { $$ = $1; }
;

// workaround for bison's broken type variant handling that needs an explicit conversion
// to the base class
derivedTypeDeclarationAsType
: derivedTypeDeclaration { $$ = static_cast<const IR::Type *>($1); }
;

headerTypeDeclaration
: optAnnotations HEADER name { driver.structure->pushContainerType(*$3, true); } optTypeParameters {
driver.structure->markAsTemplate(*$3);
Expand Down Expand Up @@ -1199,7 +1217,7 @@ structFieldList
;

structField
: optAnnotations typeRef name ";" { $$ = new IR::StructField(@3, *$3, *$1, $2); }
: optAnnotations typeRef declarator ";" { $$ = new IR::StructField(@3, *$3.name, *$1, $3.type); }
;

enumDeclaration
Expand Down Expand Up @@ -1241,12 +1259,15 @@ identifierList
;

typedefDeclaration
: optAnnotations TYPEDEF typeRef name { driver.structure->declareType(*$4);
$$ = new IR::Type_Typedef(@4, *$4, *$1, $3); }
| optAnnotations TYPEDEF derivedTypeDeclaration name { driver.structure->declareType(*$4);
$$ = new IR::Type_Typedef(@4, *$4, *$1, $3); }
| optAnnotations TYPE typeRef name { driver.structure->declareType(*$4);
$$ = new IR::Type_Newtype(@4, *$4, *$1, $3); }
: optAnnotations TYPEDEF typeRef declarator {
driver.structure->declareType(*$4.name);
$$ = new IR::Type_Typedef(@4, *$4.name, *$1, $4.type); }
| optAnnotations TYPEDEF derivedTypeDeclarationAsType declarator {
driver.structure->declareType(*$4.name);
$$ = new IR::Type_Typedef(@4, *$4.name, *$1, $4.type); }
| optAnnotations TYPE typeRef declarator {
driver.structure->declareType(*$4.name);
$$ = new IR::Type_Newtype(@4, *$4.name, *$1, $4.type); }
;

/*************************** STATEMENTS *************************/
Expand Down Expand Up @@ -1525,18 +1546,24 @@ variableDeclaration
;

variableDeclarationWithoutSemicolon
: annotations typeRef name optInitializer
{ $$ = new IR::Declaration_Variable(@1+@4, *$3, *$1, $2, $4);
driver.structure->declareObject(*$3, $2->toString()); }
| typeRef name optInitializer
{ $$ = new IR::Declaration_Variable(@1+@3, *$2, $1, $3);
driver.structure->declareObject(*$2, $1->toString()); }
: annotations typeRef declarator optInitializer
{ $$ = new IR::Declaration_Variable(@1+@4, *$3.name, *$1, $3.type, $4);
driver.structure->declareObject(*$3.name, $3.type->toString()); }
| typeRef declarator optInitializer
{ $$ = new IR::Declaration_Variable(@1+@3, *$2.name, $2.type, $3);
driver.structure->declareObject(*$2.name, $2.type->toString()); }
;

constantDeclaration
: optAnnotations CONST typeRef name "=" initializer ";"
{ $$ = new IR::Declaration_Constant(@4, *$4, *$1, $3, $6);
driver.structure->declareObject(*$4, $3->toString()); }
: optAnnotations CONST typeRef declarator "=" initializer ";"
{ $$ = new IR::Declaration_Constant(@4, *$4.name, *$1, $4.type, $6);
driver.structure->declareObject(*$4.name, $4.type->toString()); }
;

declarator
: name { $$.name = $1; $$.type = $<ConstType *>0; }
| declarator "[" expression "]"
{ $$ = $1; $$.type = new IR::Type_Stack(@2+@4, $1.type, $3); }
;

optInitializer
Expand Down
3 changes: 2 additions & 1 deletion testdata/p4_16_errors/stack_e.p4
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,12 @@ control p()
{
apply {
h[5] stack;
s[5] stack1; // non-header illegal in header stack
s[5] stack1; // 'normal' array can't use stack operations

// out of range indexes
h b = stack[1231092310293];
h c = stack[-2];
h d = stack[6];
s e = stack1.next;
}
}
1 change: 1 addition & 0 deletions testdata/p4_16_errors_outputs/stack_e.p4
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ control p() {
h b = stack[1231092310293];
h c = stack[-2];
h d = stack[6];
s e = stack1.next;
}
}

6 changes: 3 additions & 3 deletions testdata/p4_16_errors_outputs/stack_e.p4-stderr
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
stack_e.p4(23): [--Werror=type-error] error: Header stack struct s[5] used with non-header type struct s
s[5] stack1; // non-header illegal in header stack
^^^^
stack_e.p4(26): [--Werror=overlimit] error: 1231092310293: Value too large for int
h b = stack[1231092310293];
^^^^^^^^^^^^^
stack_e.p4(29): [--Werror=type-error] error: stack1.next: 'next' can only be used on header stacks
s e = stack1.next;
^^^^^^^^^^^
71 changes: 71 additions & 0 deletions testdata/p4_16_samples/array1.p4
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
#include <core.p4>
#include <v1model.p4>

header data_t {
bit<32> f1;
bit<32> f2;
bit<16> h1;
bit<16> h2;
bit<8>[16] arr;
}
Comment on lines +4 to +10
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you please add positive and/or error test cases similar to the following to demonstrate what is expected when the array type is an array type or contains array types?

struct S {
    bit<16> f1;
    bit<8>[16] nested_arr;
    bit<16> f2;
}

header data_t {
    bit<32>     f1;
    bit<32>     f2;
    bit<16>     h1;
    bit<16>     h2;
    S[16]  arr;
}
...
    hdr.data.arr[x].nested_arr[y] = ...;
    ... = hdr.data.arr[z].nested_arr[w];
...

and (if the grammar allows it (I did not look very closely at changes to p4parser.ypp)):

header data_t {
    bit<32>     f1;
    bit<32>     f2;
    bit<16>     h1;
    bit<16>     h2;
    bit<8>[16][16]  arr;
}
...
    hdr.data.arr[x][y] = ...;
    ... = hdr.data.arr[z][w];
...


struct metadata {}

struct headers {
data_t data;
}

parser p(packet_in b,
out headers hdr,
inout metadata meta,
inout standard_metadata_t stdmeta) {
state start {
b.extract(hdr.data);
transition accept;
}
}

control ingress(inout headers hdr,
inout metadata meta,
inout standard_metadata_t stdmeta) {
apply {
hdr.data.arr[0] = hdr.data.f1[0+:8];
hdr.data.arr[1] = hdr.data.f1[8+:8];
hdr.data.arr[2] = hdr.data.f1[16+:8];
hdr.data.arr[3] = hdr.data.f1[24+:8];
hdr.data.arr[4] = hdr.data.f2[0+:8];
hdr.data.arr[5] = hdr.data.f2[8+:8];
hdr.data.arr[6] = hdr.data.f2[16+:8];
hdr.data.arr[7] = hdr.data.f2[24+:8];
}
}

control egress(inout headers hdr,
inout metadata meta,
inout standard_metadata_t stdmeta) {
apply {}
}

control vc(inout headers hdr,
inout metadata meta) {
apply {}
}

control uc(inout headers hdr,
inout metadata meta) {
apply {}
}

control deparser(packet_out packet,
in headers hdr) {
apply {
packet.emit(hdr);
}
}

V1Switch<headers, metadata>(p(),
vc(),
ingress(),
egress(),
uc(),
deparser()) main;
Loading
Loading