Skip to content

Commit a316909

Browse files
author
Mihai Budiu
authored
Support for structure-valued expressions (#1951)
* Added Type_StructUnknown * Support for structure-valued expressions
1 parent 285cacb commit a316909

File tree

125 files changed

+2340
-231
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

125 files changed

+2340
-231
lines changed

backends/bmv2/common/lower.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -211,7 +211,7 @@ RemoveComplexExpressions::simplifyExpression(const IR::Expression* expression, b
211211
auto simpl = simplifyExpressions(&si->components);
212212
if (simpl != &si->components)
213213
return new IR::StructInitializerExpression(
214-
si->srcInfo, si->name, *simpl, si->isHeader);
214+
si->srcInfo, si->typeName, si->typeName, *simpl);
215215
return expression;
216216
} else {
217217
ComplexExpression ce;
@@ -316,7 +316,7 @@ RemoveComplexExpressions::postorder(IR::MethodCallExpression* expression) {
316316
} else if (auto si = arg1->to<IR::StructInitializerExpression>()) {
317317
auto list = simplifyExpressions(&si->components);
318318
arg1 = new IR::StructInitializerExpression(
319-
si->srcInfo, si->name, *list, si->isHeader);
319+
si->srcInfo, si->typeName, si->typeName, *list);
320320
vec->push_back(new IR::Argument(arg1));
321321
} else {
322322
auto tmp = new IR::Argument(

frontends/common/constantFolding.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -581,7 +581,7 @@ const IR::Node* DoConstantFolding::postorder(IR::Member* e) {
581581
BUG("Could not find field %1% in type %2%", e->member, type);
582582
result = CloneConstants::clone(list->components.at(index));
583583
} else if (auto si = expr->to<IR::StructInitializerExpression>()) {
584-
if (si->isHeader && e->member.name == IR::Type_Header::isValid)
584+
if (origtype->is<IR::Type_Header>() && e->member.name == IR::Type_Header::isValid)
585585
return e;
586586
auto ne = si->components.getDeclaration<IR::NamedExpression>(e->member.name);
587587
BUG_CHECK(ne != nullptr, "Could not find field %1% in initializer %2%", e->member, si);

frontends/p4/structInitializers.cpp

+4-2
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,9 @@ convert(const IR::Expression* expression, const IR::Type* type) {
3535
si->push_back(ne);
3636
index++;
3737
}
38+
auto type = st->getP4Type()->to<IR::Type_Name>();
3839
auto result = new IR::StructInitializerExpression(
39-
expression->srcInfo, st->name, *si, st->is<IR::Type_Header>());
40+
expression->srcInfo, type, type, *si);
4041
return result;
4142
} else if (auto sli = expression->to<IR::StructInitializerExpression>()) {
4243
for (auto f : st->fields) {
@@ -49,8 +50,9 @@ convert(const IR::Expression* expression, const IR::Type* type) {
4950
si->push_back(ne);
5051
}
5152
if (modified) {
53+
auto type = st->getP4Type()->to<IR::Type_Name>();
5254
auto result = new IR::StructInitializerExpression(
53-
expression->srcInfo, st->name, *si, st->is<IR::Type_Header>());
55+
expression->srcInfo, type, type, *si);
5456
return result;
5557
}
5658
}

frontends/p4/toP4/toP4.cpp

+6-4
Original file line numberDiff line numberDiff line change
@@ -859,10 +859,10 @@ bool ToP4::preorder(const IR::NamedExpression* e) {
859859
}
860860

861861
bool ToP4::preorder(const IR::StructInitializerExpression* e) {
862-
// Currently the P4 language does not have a syntax
863-
// for struct initializers, so we use the same syntax as for list expressions.
864-
// TODO: this is incorrect if the fields are not in the same order as
865-
// in the type.
862+
if (e->typeName != nullptr) {
863+
visit(e->typeName);
864+
builder.append(" ");
865+
}
866866
builder.append("{");
867867
int prec = expressionPrecedence;
868868
expressionPrecedence = DBPrint::Prec_Low;
@@ -871,6 +871,8 @@ bool ToP4::preorder(const IR::StructInitializerExpression* e) {
871871
if (!first)
872872
builder.append(",");
873873
first = false;
874+
builder.append(c->name.name);
875+
builder.append(" = ");
874876
visit(c->expression);
875877
}
876878
expressionPrecedence = prec;

frontends/p4/typeChecking/typeChecker.cpp

+105-50
Original file line numberDiff line numberDiff line change
@@ -206,8 +206,10 @@ TypeVariableSubstitution* TypeInference::unify(const IR::Node* errorPosition,
206206
return tvs;
207207
}
208208

209-
const IR::IndexedVector<IR::StructField>*
210-
TypeInference::canonicalizeFields(const IR::Type_StructLike* type) {
209+
const IR::Type*
210+
TypeInference::canonicalizeFields(
211+
const IR::Type_StructLike* type,
212+
std::function<const IR::Type*(const IR::IndexedVector<IR::StructField>*)> constructor) {
211213
bool changes = false;
212214
auto fields = new IR::IndexedVector<IR::StructField>();
213215
for (auto field : type->fields) {
@@ -221,9 +223,9 @@ TypeInference::canonicalizeFields(const IR::Type_StructLike* type) {
221223
fields->push_back(newField);
222224
}
223225
if (changes)
224-
return fields;
226+
return constructor(fields);
225227
else
226-
return &type->fields;
228+
return type;
227229
}
228230

229231
const IR::ParameterList* TypeInference::canonicalizeParameters(const IR::ParameterList* params) {
@@ -492,39 +494,22 @@ const IR::Type* TypeInference::canonicalize(const IR::Type* type) {
492494
if (changes)
493495
resultType = new IR::Type_Method(mt->getSourceInfo(), tps, res, pl);
494496
return resultType;
495-
} else if (type->is<IR::Type_Header>()) {
496-
auto hdr = type->to<IR::Type_Header>();
497-
auto fields = canonicalizeFields(hdr);
498-
if (fields == nullptr)
499-
return nullptr;
500-
const IR::Type* canon;
501-
if (fields != &hdr->fields)
502-
canon = new IR::Type_Header(hdr->srcInfo, hdr->name, hdr->annotations, *fields);
503-
else
504-
canon = hdr;
505-
return canon;
506-
} else if (type->is<IR::Type_Struct>()) {
507-
auto str = type->to<IR::Type_Struct>();
508-
auto fields = canonicalizeFields(str);
509-
if (fields == nullptr)
510-
return nullptr;
511-
const IR::Type* canon;
512-
if (fields != &str->fields)
513-
canon = new IR::Type_Struct(str->srcInfo, str->name, str->annotations, *fields);
514-
else
515-
canon = str;
516-
return canon;
517-
} else if (type->is<IR::Type_HeaderUnion>()) {
518-
auto str = type->to<IR::Type_HeaderUnion>();
519-
auto fields = canonicalizeFields(str);
520-
if (fields == nullptr)
521-
return nullptr;
522-
const IR::Type* canon;
523-
if (fields != &str->fields)
524-
canon = new IR::Type_HeaderUnion(str->srcInfo, str->name, str->annotations, *fields);
525-
else
526-
canon = str;
527-
return canon;
497+
} else if (auto hdr = type->to<IR::Type_Header>()) {
498+
return canonicalizeFields(hdr, [hdr](const IR::IndexedVector<IR::StructField>* fields) {
499+
return new IR::Type_Header(hdr->srcInfo, hdr->name, hdr->annotations, *fields);
500+
});
501+
} else if (auto str = type->to<IR::Type_Struct>()) {
502+
return canonicalizeFields(str, [str](const IR::IndexedVector<IR::StructField>* fields) {
503+
return new IR::Type_Struct(str->srcInfo, str->name, str->annotations, *fields);
504+
});
505+
} else if (auto hu = type->to<IR::Type_HeaderUnion>()) {
506+
return canonicalizeFields(hu, [hu](const IR::IndexedVector<IR::StructField>* fields) {
507+
return new IR::Type_HeaderUnion(hu->srcInfo, hu->name, hu->annotations, *fields);
508+
});
509+
} else if (auto su = type->to<IR::Type_UnknownStruct>()) {
510+
return canonicalizeFields(su, [su](const IR::IndexedVector<IR::StructField>* fields) {
511+
return new IR::Type_UnknownStruct(su->srcInfo, su->name, su->annotations, *fields);
512+
});
528513
} else if (type->is<IR::Type_Specialized>()) {
529514
auto st = type->to<IR::Type_Specialized>();
530515
auto baseCanon = canonicalize(st->baseType);
@@ -752,6 +737,20 @@ TypeInference::assignment(const IR::Node* errorPosition, const IR::Type* destTyp
752737
setType(sourceExpression, destType);
753738
setCompileTimeConstant(sourceExpression);
754739
}
740+
if (initType->is<IR::Type_UnknownStruct>()) {
741+
if (auto ts = destType->to<IR::Type_StructLike>()) {
742+
auto si = sourceExpression->to<IR::StructInitializerExpression>();
743+
CHECK_NULL(si);
744+
bool cst = isCompileTimeConstant(sourceExpression);
745+
auto type = new IR::Type_Name(ts->name);
746+
sourceExpression = new IR::StructInitializerExpression(
747+
type, type, si->components);
748+
setType(sourceExpression, destType);
749+
if (cst)
750+
setCompileTimeConstant(sourceExpression);
751+
}
752+
}
753+
755754
return sourceExpression;
756755
}
757756

@@ -1522,6 +1521,53 @@ const IR::Node* TypeInference::postorder(IR::Operation_Relation* expression) {
15221521
}
15231522
defined = true;
15241523
} else {
1524+
auto ls = ltype->to<IR::Type_UnknownStruct>();
1525+
auto rs = rtype->to<IR::Type_UnknownStruct>();
1526+
if (ls != nullptr || rs != nullptr) {
1527+
if (ls != nullptr && rs != nullptr) {
1528+
typeError("%1%: cannot compare initializers with unknown types", expression);
1529+
return expression;
1530+
}
1531+
1532+
bool lcst = isCompileTimeConstant(expression->left);
1533+
bool rcst = isCompileTimeConstant(expression->right);
1534+
1535+
auto tvs = unify(expression, ltype, rtype);
1536+
if (tvs == nullptr)
1537+
// error already signalled
1538+
return expression;
1539+
if (!tvs->isIdentity()) {
1540+
ConstantTypeSubstitution cts(tvs, refMap, typeMap, this);
1541+
expression->left = cts.convert(expression->left);
1542+
expression->right = cts.convert(expression->right);
1543+
}
1544+
1545+
if (ls != nullptr) {
1546+
auto l = expression->left->to<IR::StructInitializerExpression>();
1547+
CHECK_NULL(l); // struct initializers are the only expressions that can
1548+
// have StructUnknown types
1549+
BUG_CHECK(rtype->is<IR::Type_StructLike>(), "%1%: expected a struct", rtype);
1550+
auto type = new IR::Type_Name(rtype->to<IR::Type_StructLike>()->name);
1551+
expression->left = new IR::StructInitializerExpression(
1552+
expression->left->srcInfo, type, type, l->components);
1553+
setType(expression->left, rtype);
1554+
if (lcst)
1555+
setCompileTimeConstant(expression->left);
1556+
} else {
1557+
auto r = expression->right->to<IR::StructInitializerExpression>();
1558+
CHECK_NULL(r); // struct initializers are the only expressions that can
1559+
// have StructUnknown types
1560+
BUG_CHECK(ltype->is<IR::Type_StructLike>(), "%1%: expected a struct", ltype);
1561+
auto type = new IR::Type_Name(ltype->to<IR::Type_StructLike>()->name);
1562+
expression->right = new IR::StructInitializerExpression(
1563+
expression->right->srcInfo, type, type, r->components);
1564+
setType(expression->right, rtype);
1565+
if (rcst)
1566+
setCompileTimeConstant(expression->right);
1567+
}
1568+
defined = true;
1569+
}
1570+
15251571
// comparison between structs and list expressions is allowed only
15261572
// if the expression with tuple type is a list expression
15271573
if ((ltype->is<IR::Type_StructLike>() &&
@@ -1769,23 +1815,32 @@ const IR::Node* TypeInference::postorder(IR::StructInitializerExpression* expres
17691815
components->push_back(new IR::StructField(c->name, type));
17701816
}
17711817

1772-
const IR::Type* structType;
1773-
if (expression->isHeader)
1774-
structType = new IR::Type_Header(
1775-
expression->srcInfo, expression->name, *components);
1776-
else
1777-
structType = new IR::Type_Struct(
1778-
expression->srcInfo, expression->name, *components);
1779-
auto type = canonicalize(structType);
1780-
if (type == nullptr)
1781-
return expression;
1782-
setType(getOriginal(), type);
1783-
setType(expression, type);
1818+
const IR::Type* structType = new IR::Type_UnknownStruct(
1819+
expression->srcInfo, "unknown struct", *components);
1820+
structType = canonicalize(structType);
1821+
1822+
const IR::Expression* result = expression;
1823+
if (expression->typeName != nullptr) {
1824+
// We know the exact type of the initializer
1825+
auto desired = getTypeType(expression->typeName);
1826+
if (desired == nullptr)
1827+
return expression;
1828+
auto tvs = unify(expression, desired, structType);
1829+
if (tvs == nullptr)
1830+
return expression;
1831+
if (!tvs->isIdentity()) {
1832+
ConstantTypeSubstitution cts(tvs, refMap, typeMap, this);
1833+
result = cts.convert(expression);
1834+
}
1835+
structType = desired;
1836+
}
1837+
setType(getOriginal(), structType);
1838+
setType(expression, structType);
17841839
if (constant) {
17851840
setCompileTimeConstant(expression);
17861841
setCompileTimeConstant(getOriginal<IR::Expression>());
17871842
}
1788-
return expression;
1843+
return result;
17891844
}
17901845

17911846
const IR::Node* TypeInference::postorder(IR::ArrayIndex* expression) {

frontends/p4/typeChecking/typeChecker.h

+7-7
Original file line numberDiff line numberDiff line change
@@ -90,11 +90,6 @@ class TypeInference : public Transform {
9090
bool isCompileTimeConstant(const IR::Expression* expression) const
9191
{ return typeMap->isCompileTimeConstant(expression); }
9292

93-
template<typename... T>
94-
void typeError(const char* format, T... args) const {
95-
::error(ErrorType::ERR_TYPE_ERROR, format, args...);
96-
}
97-
9893
// This is needed because sometimes we invoke visitors recursively on subtrees explicitly.
9994
// (visitDagOnce cannot take care of this).
10095
bool done() const;
@@ -123,8 +118,9 @@ class TypeInference : public Transform {
123118
* Made virtual to enable private midend passes to extend standard IR with custom IR classes.
124119
*/
125120
virtual const IR::Type* canonicalize(const IR::Type* type);
126-
virtual const IR::IndexedVector<IR::StructField>*
127-
canonicalizeFields(const IR::Type_StructLike* type);
121+
const IR::Type* canonicalizeFields(
122+
const IR::Type_StructLike* type,
123+
std::function<const IR::Type*(const IR::IndexedVector<IR::StructField>*)> constructor);
128124
virtual const IR::ParameterList* canonicalizeParameters(const IR::ParameterList* params);
129125

130126
// various helpers
@@ -173,6 +169,10 @@ class TypeInference : public Transform {
173169
using Transform::postorder;
174170
using Transform::preorder;
175171

172+
template<typename... T>
173+
static void typeError(const char* format, T... args) {
174+
::error(ErrorType::ERR_TYPE_ERROR, format, args...);
175+
}
176176
static const IR::Type* specialize(const IR::IMayBeGenericType* type,
177177
const IR::Vector<IR::Type>* arguments);
178178
const IR::Node* pruneIfDone(const IR::Node* node)

0 commit comments

Comments
 (0)