Skip to content

Commit 603b698

Browse files
committed
Support for arrays of extern instances
Signed-off-by: Chris Dodd <[email protected]>
1 parent 4a922a2 commit 603b698

File tree

13 files changed

+5916
-33
lines changed

13 files changed

+5916
-33
lines changed

frontends/p4/evaluator/evaluator.cpp

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -159,9 +159,9 @@ const IR::Block *Evaluator::processConstructor(
159159
LOG2("Eliminating typedef " << dbp(decl));
160160
type = decl->to<IR::Type_Typedef>()->type;
161161
}
162-
if (type->is<IR::Type_Specialized>()) type = type->to<IR::Type_Specialized>()->baseType;
163-
if (type->is<IR::Type_Name>()) {
164-
auto tn = type->to<IR::Type_Name>();
162+
while (auto at = type->to<IR::Type_Array>()) type = at->elementType;
163+
if (auto st = type->to<IR::Type_Specialized>()) type = st->baseType;
164+
if (auto tn = type->to<IR::Type_Name>()) {
165165
decl = refMap->getDeclaration(tn->path, true);
166166
} else {
167167
BUG_CHECK(type->is<IR::IDeclaration>(), "%1%: expected a type declaration", type);
@@ -176,8 +176,9 @@ const IR::Block *Evaluator::processConstructor(
176176
// We lookup the method in the instanceType, because it may contain compiler-synthesized
177177
// constructors with zero arguments that may not appear in the original extern declaration.
178178
auto canon = instanceType;
179-
if (canon->is<IR::Type_SpecializedCanonical>())
180-
canon = canon->to<IR::Type_SpecializedCanonical>()->substituted->to<IR::Type>();
179+
if (auto at = canon->to<IR::Type_Array>()) canon = at->elementType;
180+
if (auto tsc = canon->to<IR::Type_SpecializedCanonical>())
181+
canon = tsc->substituted->to<IR::Type>();
181182
BUG_CHECK(canon->is<IR::Type_Extern>(), "%1%: expected an extern", canon);
182183
auto constructor = canon->to<IR::Type_Extern>()->lookupConstructor(arguments);
183184
BUG_CHECK(constructor != nullptr, "Type %1% has no constructor with %2% arguments", exttype,

frontends/p4/methodInstance.cpp

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -68,24 +68,27 @@ MethodInstance *MethodInstance::resolve(const IR::MethodCallExpression *mce,
6868
} else {
6969
const IR::IDeclaration *decl = nullptr;
7070
const IR::Type *type = nullptr;
71-
if (auto th = mem->expr->to<IR::This>()) {
71+
const IR::Expression *receiver = mem->expr;
72+
while (auto ai = receiver->to<IR::ArrayIndex>()) receiver = ai->left;
73+
if (auto th = receiver->to<IR::This>()) {
7274
type = basetype;
7375
decl = refMap->getDeclaration(th, true);
74-
} else if (auto pe = mem->expr->to<IR::PathExpression>()) {
76+
} else if (auto pe = receiver->to<IR::PathExpression>()) {
7577
decl = refMap->getDeclaration(pe->path, true);
7678
type = typeMap ? typeMap->getType(decl->getNode(), true) : pe->type;
77-
} else if (auto mc = mem->expr->to<IR::MethodCallExpression>()) {
79+
} else if (auto mc = receiver->to<IR::MethodCallExpression>()) {
7880
auto mi = resolve(mc, refMap, typeMap, useExpressionType);
7981
decl = mi->object;
8082
type = mi->actualMethodType->returnType;
81-
} else if (auto cce = mem->expr->to<IR::ConstructorCallExpression>()) {
83+
} else if (auto cce = receiver->to<IR::ConstructorCallExpression>()) {
8284
auto cc = ConstructorCall::resolve(cce, refMap, typeMap);
8385
decl = cc->to<ExternConstructorCall>()->type;
8486
type = typeMap ? typeMap->getTypeType(cce->constructedType, true) : cce->type;
8587
} else {
86-
BUG("unexpected expression %1% resolving method instance", mem->expr);
88+
BUG("unexpected expression %1% resolving method instance", receiver);
8789
}
8890
BUG_CHECK(type != nullptr, "Could not resolve type for %1%", decl);
91+
while (auto st = type->to<IR::Type_Array>()) type = st->elementType;
8992
if (type->is<IR::Type_SpecializedCanonical>())
9093
type = type->to<IR::Type_SpecializedCanonical>()->substituted->to<IR::Type>();
9194
if (type->is<IR::IApply>() && mem->member == IR::IApply::applyMethodName) {
@@ -172,9 +175,10 @@ ConstructorCall *ConstructorCall::resolve(const IR::ConstructorCallExpression *c
172175
Instantiation *Instantiation::resolve(const IR::Declaration_Instance *instance, DeclarationLookup *,
173176
TypeMap *typeMap) {
174177
auto type = typeMap ? typeMap->getTypeType(instance->type, true) : instance->type;
175-
auto simpleType = type;
176178
const IR::Vector<IR::Type> *typeArguments;
177179

180+
while (auto at = type->to<IR::Type_Array>()) type = at->elementType;
181+
auto simpleType = type;
178182
if (auto st = type->to<IR::Type_SpecializedCanonical>()) {
179183
simpleType = st->baseType;
180184
typeArguments = st->arguments;

frontends/p4/typeChecking/bindVariables.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ const IR::Node *DoBindTypeVariables::postorder(IR::Expression *expression) {
7979
const IR::Node *DoBindTypeVariables::postorder(IR::Declaration_Instance *decl) {
8080
if (decl->type->is<IR::Type_Specialized>()) return decl;
8181
auto type = typeMap->getType(getOriginal(), true);
82+
while (auto at = type->to<IR::Type_Array>()) type = at->elementType;
8283
if (auto tsc = type->to<IR::Type_SpecializedCanonical>()) type = tsc->substituted;
8384
BUG_CHECK(type->is<IR::IMayBeGenericType>(), "%1%: unexpected type %2% for declaration", decl,
8485
type);

frontends/p4/typeChecking/typeCheckDecl.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,12 @@ bool TypeInferenceBase::checkAbstractMethods(const IR::Declaration_Instance *ins
221221
return rv;
222222
}
223223

224+
static const IR::Type *relayerArrayType(const IR::Type *base, const IR::Type_Array *arr) {
225+
if (auto *nest = arr->elementType->to<IR::Type_Array>())
226+
base = relayerArrayType(base, nest);
227+
return new IR::Type_Array(base, arr->size);
228+
}
229+
224230
template <class Node>
225231
TypeInferenceBase::PreorderResult TypeInferenceBase::preorderDeclarationInstanceImpl(Node *decl) {
226232
// We need to control the order of the type-checking: we want to do first
@@ -237,6 +243,8 @@ TypeInferenceBase::PreorderResult TypeInferenceBase::preorderDeclarationInstance
237243
}
238244
auto orig = getOriginal<IR::Declaration_Instance>();
239245

246+
auto *arrayType = type->template to<IR::Type_Array>();
247+
while (auto *at = type->template to<IR::Type_Array>()) type = at->elementType;
240248
auto simpleType = type;
241249
if (auto *sc = type->template to<IR::Type_SpecializedCanonical>()) simpleType = sc->substituted;
242250

@@ -251,6 +259,7 @@ TypeInferenceBase::PreorderResult TypeInferenceBase::preorderDeclarationInstance
251259
// Otherwise, we use the type received from checkExternConstructor, which
252260
// has substituted the type variables with fresh ones.
253261
if (type->template is<IR::Type_Extern>()) type = newType;
262+
if (arrayType) type = relayerArrayType(type, arrayType);
254263
setType(orig, type);
255264
setType(decl, type);
256265

@@ -269,6 +278,10 @@ TypeInferenceBase::PreorderResult TypeInferenceBase::preorderDeclarationInstance
269278
setType(decl, type);
270279
}
271280
} else if (simpleType->template is<IR::IContainer>()) {
281+
if (arrayType) {
282+
typeError("%1%: can't create arrays of %2%", decl, simpleType);
283+
return {decl, true};
284+
}
272285
if (decl->initializer != nullptr) {
273286
typeError("%1%: initializers only allowed for extern instances", decl->initializer);
274287
return {decl, true};

frontends/p4/validateParsedProgram.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -141,8 +141,10 @@ void ValidateParsedProgram::postorder(const IR::Declaration_Variable *decl) {
141141
/// Instance names cannot be don't care
142142
/// Do not declare instances in apply {} blocks, parser states or actions
143143
void ValidateParsedProgram::postorder(const IR::Declaration_Instance *decl) {
144-
if (!decl->type->is<IR::Type_Name>() && !decl->type->is<IR::Type_Specialized>() &&
145-
!decl->type->is<IR::Type_Extern>()) // P4_14 only?
144+
auto *type = decl->type;
145+
while (auto *at = type->to<IR::Type_Array>()) type = at->elementType;
146+
if (!type->is<IR::Type_Name>() && !type->is<IR::Type_Specialized>() &&
147+
!type->is<IR::Type_Extern>()) // P4_14 only?
146148
::P4::error(ErrorType::ERR_INVALID, "%1%: invalid type for declaration", decl->type);
147149
if (decl->name.isDontCare())
148150
::P4::error(ErrorType::ERR_INVALID, "%1%: invalid instance name.", decl);

frontends/parsers/p4/p4parser.ypp

Lines changed: 13 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -308,7 +308,7 @@ using namespace P4;
308308
directApplication
309309
forStatement breakStatement continueStatement
310310
%type<IR::BlockStatement*> blockStatement parserBlockStatement controlBody
311-
objInitializer
311+
optObjInitializer
312312
%type<IR::StatOrDecl*> statementOrDeclaration parserStatement
313313
declOrAssignmentOrMethodCallStatement
314314
%type<IR::IndexedVector<IR::StatOrDecl>*> objDeclarations statOrDeclList parserStatements
@@ -793,26 +793,19 @@ packageTypeDeclaration
793793
;
794794

795795
instantiation
796-
: annotations typeRef "(" argumentList ")" name ";"
797-
{ $$ = new IR::Declaration_Instance(@6, *$6, *$1,
798-
$2, $4);
799-
driver.structure->declareObject(*$6, $2->toString()); }
800-
| typeRef "(" argumentList ")" name ";"
801-
{ $$ = new IR::Declaration_Instance(@5, *$5, $1, $3);
802-
driver.structure->declareObject(*$5, $1->toString()); }
803-
| annotations typeRef "(" argumentList ")" name "=" objInitializer ";"
804-
{ $$ = new IR::Declaration_Instance(@6, *$6, *$1,
805-
$2, $4, $8);
806-
driver.structure->declareObject(*$6, $2->toString()); }
807-
| typeRef "(" argumentList ")" name "=" objInitializer ";"
808-
{ $$ = new IR::Declaration_Instance(@5, *$5, $1, $3, $7);
809-
driver.structure->declareObject(*$5, $1->toString()); }
810-
;
811-
812-
objInitializer
813-
: "{" { driver.structure->pushNamespace(@1, false); } objDeclarations "}"
796+
: annotations typeRef "(" argumentList ")" <ConstType*>{ $$ = $2; } declarator optObjInitializer ";"
797+
{ $$ = new IR::Declaration_Instance(@7, *$7.name, *$1, $7.type, $4, $8);
798+
driver.structure->declareObject(*$7.name, $2->toString()); }
799+
| typeRef "(" argumentList ")" <ConstType*>{ $$ = $1; } declarator optObjInitializer ";"
800+
{ $$ = new IR::Declaration_Instance(@6, *$6.name, $6.type, $3, $7);
801+
driver.structure->declareObject(*$6.name, $1->toString()); }
802+
;
803+
804+
optObjInitializer
805+
: %empty { $$ = nullptr; }
806+
| "=" "{" { driver.structure->pushNamespace(@1, false); } objDeclarations "}"
814807
{ driver.structure->pop();
815-
$$ = new IR::BlockStatement(@1+@4, *$3); }
808+
$$ = new IR::BlockStatement(@2+@5, *$4); }
816809
;
817810

818811
objDeclarations

ir/ir.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -421,6 +421,7 @@ class Declaration_Constant : Declaration, IAnnotated {
421421
class Declaration_Instance : Declaration, IAnnotated, IInstance {
422422
optional inline Vector<Annotation> annotations;
423423
Type type; // Either Type_Name or Type_Specialized or Type_Extern
424+
// or Type_Array of any of the above
424425
Vector<Argument> arguments;
425426
inline NameMap<Property> properties = {}; // P4_14 externs only, at the moment
426427
optional NullOK BlockStatement initializer = nullptr;
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
#include <core.p4>
2+
3+
struct metadata_t {}
4+
5+
header h1_t {
6+
bit<32> f1;
7+
bit<32> f2;
8+
bit<16> h1;
9+
bit<16> h2;
10+
bit<8> b1;
11+
bit<8> b2;
12+
bit<8> b3;
13+
bit<8> b4;
14+
}
15+
16+
struct headers_t {
17+
h1_t h1;
18+
}
19+
20+
extern persistent<T> {
21+
persistent();
22+
T read();
23+
void write(in T value);
24+
}
25+
26+
control c(
27+
inout headers_t hdr,
28+
inout metadata_t meta
29+
) {
30+
persistent<bit<32>>() data[256];
31+
32+
apply {
33+
if (hdr.h1.h1 > hdr.h1.h2)
34+
data[hdr.h1.b1].write(hdr.h1.f1);
35+
else
36+
hdr.h1.f2 = data[hdr.h1.b1].read();
37+
}
38+
}
39+
40+
control c_<H, M>(inout H h, inout M m);
41+
package top<H, M>(c_<H, M> c);
42+
top(c()) main;
43+
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
#include <core.p4>
2+
3+
struct metadata_t {
4+
}
5+
6+
header h1_t {
7+
bit<32> f1;
8+
bit<32> f2;
9+
bit<16> h1;
10+
bit<16> h2;
11+
bit<8> b1;
12+
bit<8> b2;
13+
bit<8> b3;
14+
bit<8> b4;
15+
}
16+
17+
struct headers_t {
18+
h1_t h1;
19+
}
20+
21+
extern persistent<T> {
22+
persistent();
23+
T read();
24+
void write(in T value);
25+
}
26+
27+
control c(inout headers_t hdr, inout metadata_t meta) {
28+
persistent<bit<32>>[256]() data;
29+
apply {
30+
if (hdr.h1.h1 > hdr.h1.h2) {
31+
data[hdr.h1.b1].write(hdr.h1.f1);
32+
} else {
33+
hdr.h1.f2 = data[hdr.h1.b1].read();
34+
}
35+
}
36+
}
37+
38+
control c_<H, M>(inout H h, inout M m);
39+
package top<H, M>(c_<H, M> c);
40+
top<headers_t, metadata_t>(c()) main;
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
#include <core.p4>
2+
3+
struct metadata_t {
4+
}
5+
6+
header h1_t {
7+
bit<32> f1;
8+
bit<32> f2;
9+
bit<16> h1;
10+
bit<16> h2;
11+
bit<8> b1;
12+
bit<8> b2;
13+
bit<8> b3;
14+
bit<8> b4;
15+
}
16+
17+
struct headers_t {
18+
h1_t h1;
19+
}
20+
21+
extern persistent<T> {
22+
persistent();
23+
T read();
24+
void write(in T value);
25+
}
26+
27+
control c(inout headers_t hdr, inout metadata_t meta) {
28+
@name("c.data") persistent<bit<32>>[256]() data_0;
29+
apply {
30+
if (hdr.h1.h1 > hdr.h1.h2) {
31+
data_0[hdr.h1.b1].write(hdr.h1.f1);
32+
} else {
33+
hdr.h1.f2 = data_0[hdr.h1.b1].read();
34+
}
35+
}
36+
}
37+
38+
control c_<H, M>(inout H h, inout M m);
39+
package top<H, M>(c_<H, M> c);
40+
top<headers_t, metadata_t>(c()) main;

0 commit comments

Comments
 (0)