Skip to content

Commit

Permalink
Allow arrays of non-header types in frontend
Browse files Browse the repository at this point in the history
Relax the requirement that IR::Type_Stack element types are headers,
which allows using arrays of any type, though non-headers cannot
support push/pop/last/next stuff which looks at header valid bits.

Signed-off-by: Chris Dodd <[email protected]>
  • Loading branch information
ChrisDodd committed Jan 30, 2025
1 parent 2776b19 commit 8df3c2a
Show file tree
Hide file tree
Showing 14 changed files with 353 additions and 8 deletions.
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 (!eltype->is<IR::Type_Header>() && !eltype->is<IR::Type_HeaderUnion>() /* &&
!eltype->is<IR::Type_SpecializedCanonical>() */) {
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
8 changes: 7 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,11 @@ 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
3 changes: 1 addition & 2 deletions frontends/parsers/p4/p4parser.ypp
Original file line number Diff line number Diff line change
Expand Up @@ -1075,8 +1075,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
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;
}

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;
61 changes: 61 additions & 0 deletions testdata/p4_16_samples_outputs/array1-first.p4
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
#include <core.p4>
#define V1MODEL_VERSION 20180101
#include <v1model.p4>

header data_t {
bit<32> f1;
bit<32> f2;
bit<16> h1;
bit<16> h2;
bit<8>[16] arr;
}

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<data_t>(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[7:0];
hdr.data.arr[1] = hdr.data.f1[15:8];
hdr.data.arr[2] = hdr.data.f1[23:16];
hdr.data.arr[3] = hdr.data.f1[31:24];
hdr.data.arr[4] = hdr.data.f2[7:0];
hdr.data.arr[5] = hdr.data.f2[15:8];
hdr.data.arr[6] = hdr.data.f2[23:16];
hdr.data.arr[7] = hdr.data.f2[31:24];
}
}

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<headers>(hdr);
}
}

V1Switch<headers, metadata>(p(), vc(), ingress(), egress(), uc(), deparser()) main;
61 changes: 61 additions & 0 deletions testdata/p4_16_samples_outputs/array1-frontend.p4
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
#include <core.p4>
#define V1MODEL_VERSION 20180101
#include <v1model.p4>

header data_t {
bit<32> f1;
bit<32> f2;
bit<16> h1;
bit<16> h2;
bit<8>[16] arr;
}

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<data_t>(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[7:0];
hdr.data.arr[1] = hdr.data.f1[15:8];
hdr.data.arr[2] = hdr.data.f1[23:16];
hdr.data.arr[3] = hdr.data.f1[31:24];
hdr.data.arr[4] = hdr.data.f2[7:0];
hdr.data.arr[5] = hdr.data.f2[15:8];
hdr.data.arr[6] = hdr.data.f2[23:16];
hdr.data.arr[7] = hdr.data.f2[31:24];
}
}

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<headers>(hdr);
}
}

V1Switch<headers, metadata>(p(), vc(), ingress(), egress(), uc(), deparser()) main;
70 changes: 70 additions & 0 deletions testdata/p4_16_samples_outputs/array1-midend.p4
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
#include <core.p4>
#define V1MODEL_VERSION 20180101
#include <v1model.p4>

header data_t {
bit<32> f1;
bit<32> f2;
bit<16> h1;
bit<16> h2;
bit<8>[16] arr;
}

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<data_t>(hdr.data);
transition accept;
}
}

control ingress(inout headers hdr, inout metadata meta, inout standard_metadata_t stdmeta) {
@hidden action array1l32() {
hdr.data.arr[0] = hdr.data.f1[7:0];
hdr.data.arr[1] = hdr.data.f1[15:8];
hdr.data.arr[2] = hdr.data.f1[23:16];
hdr.data.arr[3] = hdr.data.f1[31:24];
hdr.data.arr[4] = hdr.data.f2[7:0];
hdr.data.arr[5] = hdr.data.f2[15:8];
hdr.data.arr[6] = hdr.data.f2[23:16];
hdr.data.arr[7] = hdr.data.f2[31:24];
}
@hidden table tbl_array1l32 {
actions = {
array1l32();
}
const default_action = array1l32();
}
apply {
tbl_array1l32.apply();
}
}

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<data_t>(hdr.data);
}
}

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

0 comments on commit 8df3c2a

Please sign in to comment.