Skip to content

Commit b0ed76e

Browse files
author
Mihai Budiu
authored
Support minSizeInBits and minSizeInBytes for scalars and type names (#2917)
* Support minSizeInBits and minSizeInBytes for scalars and type names
1 parent 2be448f commit b0ed76e

30 files changed

+461
-142
lines changed

backends/bmv2/psa_switch/psaSwitch.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -1054,7 +1054,7 @@ void ExternConverter_Counter::convertExternInstance(
10541054
auto attr_obj = new Util::JsonObject();
10551055
auto arg1 = sz->to<IR::Constant>();
10561056
auto param1 = eb->getConstructorParameters()->getParameter(0);
1057-
auto bitwidth = ctxt->typeMap->minWidthBits(arg1->type, sz->getNode());
1057+
auto bitwidth = ctxt->typeMap->widthBits(arg1->type, sz->getNode(), false);
10581058
cstring repr = BMV2::stringRepr(arg1->value, ROUNDUP(bitwidth, 8));
10591059
attr_obj->emplace("name", param1->toString());
10601060
attr_obj->emplace("type", "hexstr");
@@ -1162,7 +1162,7 @@ void ExternConverter_Meter::convertExternInstance(
11621162
}
11631163
auto attr_name = eb->getConstructorParameters()->getParameter(0);
11641164
auto s = sz->to<IR::Constant>();
1165-
auto bitwidth = ctxt->typeMap->minWidthBits(s->type, sz->getNode());
1165+
auto bitwidth = ctxt->typeMap->widthBits(s->type, sz->getNode(), false);
11661166
cstring val = BMV2::stringRepr(s->value, ROUNDUP(bitwidth, 8));
11671167
auto msz = new Util::JsonObject();
11681168
msz->emplace("name", attr_name->toString());

backends/ebpf/targets/xdp_target.py

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
/home/mbudiu/git/p4c/extensions/p4c-xdp/xdp_target.py

control-plane/p4RuntimeSerializer.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -733,7 +733,7 @@ getTypeWidth(const IR::Type* type, TypeMap* typeMap) {
733733
if (type->is<IR::Type_Error>())
734734
return 0;
735735

736-
return typeMap->minWidthBits(type, type->getNode());
736+
return typeMap->widthBits(type, type->getNode(), false);
737737
}
738738

739739
/// @return the header instance fields matched against by @table's key. The

frontends/p4/directCalls.cpp

+1-4
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,8 @@ const IR::Node* DoInstantiateCalls::postorder(IR::MethodCallExpression* expressi
2626
return expression;
2727

2828
auto ref = refMap->getDeclaration(tn->typeName->path, true);
29-
if (!ref->is<IR::P4Control>() && !ref->is<IR::P4Parser>()) {
30-
::error(ErrorType::ERR_INVALID,
31-
"%1%: cannot invoke method of %2%", expression, ref);
29+
if (!ref->is<IR::P4Control>() && !ref->is<IR::P4Parser>())
3230
return expression;
33-
}
3431

3532
auto name = refMap->newName(tn->typeName->path->name + "_inst");
3633
LOG3("Inserting instance " << name);

frontends/p4/frontend.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,7 @@ const IR::P4Program *FrontEnd::run(const CompilerOptions &options, const IR::P4P
153153
new CheckNamedArgs(),
154154
// Type checking and type inference. Also inserts
155155
// explicit casts where implicit casts exist.
156-
new TypeInference(&refMap, &typeMap, false), // insert casts
156+
new TypeInference(&refMap, &typeMap, false, false), // insert casts, dont' check arrays
157157
new ValidateMatchAnnotations(&typeMap),
158158
new BindTypeVariables(&refMap, &typeMap),
159159
new SpecializeGenericTypes(&refMap, &typeMap),

frontends/p4/typeChecking/typeChecker.cpp

+74-53
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ limitations under the License.
2323
#include "frontends/p4/toP4/toP4.h"
2424
#include "syntacticEquivalence.h"
2525
#include "frontends/common/resolveReferences/resolveReferences.h"
26+
#include "frontends/common/constantFolding.h"
2627
#include "frontends/p4/methodInstance.h"
2728

2829
namespace P4 {
@@ -102,6 +103,15 @@ TypeChecking::TypeChecking(ReferenceMap* refMap, TypeMap* typeMap,
102103

103104
//////////////////////////////////////////////////////////////////////////
104105

106+
const IR::Expression* TypeInference::constantFold(const IR::Expression* expression) {
107+
if (readOnly)
108+
return expression;
109+
DoConstantFolding cf(refMap, typeMap, false);
110+
auto result = expression->apply(cf);
111+
LOG3("Folded " << expression << " into " << result);
112+
return result;
113+
}
114+
105115
// Make a clone of the type where all type variables in
106116
// the type parameters are replaced with fresh ones.
107117
// This should only be applied to canonical types.
@@ -124,9 +134,10 @@ const IR::Type* TypeInference::cloneWithFreshTypeVariables(const IR::IMayBeGener
124134
return cl->to<IR::Type>();
125135
}
126136

127-
TypeInference::TypeInference(ReferenceMap* refMap, TypeMap* typeMap, bool readOnly) :
137+
TypeInference::TypeInference(ReferenceMap* refMap, TypeMap* typeMap,
138+
bool readOnly, bool checkArrays) :
128139
refMap(refMap), typeMap(typeMap),
129-
initialNode(nullptr), readOnly(readOnly) {
140+
initialNode(nullptr), readOnly(readOnly), checkArrays(checkArrays) {
130141
CHECK_NULL(typeMap);
131142
CHECK_NULL(refMap);
132143
visitDagOnce = false; // the done() method will take care of this
@@ -1752,11 +1763,12 @@ const IR::Node* TypeInference::postorder(IR::Operation_Relation* expression) {
17521763
if (ltype->is<IR::Type_InfInt>() && rtype->is<IR::Type_InfInt>()) {
17531764
// This can happen because we are replacing some constant functions with
17541765
// constants during type checking
1766+
auto result = constantFold(expression);
17551767
setType(getOriginal(), IR::Type_Boolean::get());
1756-
setType(expression, IR::Type_Boolean::get());
1757-
setCompileTimeConstant(expression);
1768+
setType(result, IR::Type_Boolean::get());
1769+
setCompileTimeConstant(result);
17581770
setCompileTimeConstant(getOriginal<IR::Expression>());
1759-
return expression;
1771+
return result;
17601772
} else if (ltype->is<IR::Type_InfInt>() && rtype->is<IR::Type_Bits>()) {
17611773
auto e = expression->clone();
17621774
auto cst = expression->left->to<IR::Constant>();
@@ -2040,31 +2052,33 @@ const IR::Node* TypeInference::postorder(IR::ArrayIndex* expression) {
20402052
auto rtype = getType(expression->right);
20412053
if (ltype == nullptr || rtype == nullptr)
20422054
return expression;
2055+
auto hst = ltype->to<IR::Type_Stack>();
20432056

20442057
int index = -1;
20452058
if (auto cst = expression->right->to<IR::Constant>()) {
2046-
if (!cst->fitsInt()) {
2059+
if (hst && checkArrays && !cst->fitsInt()) {
20472060
typeError("Index too large: %1%", cst);
20482061
return expression;
20492062
}
20502063
index = cst->asInt();
2051-
if (index < 0) {
2064+
if (hst && checkArrays && index < 0) {
20522065
typeError("%1%: Negative array index %2%", expression, cst);
20532066
return expression;
20542067
}
20552068
}
20562069
// if index is negative here it means it's not a constant
20572070

20582071
if ((index < 0) && !rtype->is<IR::Type_Bits>()
2059-
&& !rtype->is<IR::Type_SerEnum>()) {
2072+
&& !rtype->is<IR::Type_SerEnum>()
2073+
&& !rtype->is<IR::Type_InfInt>()) {
20602074
typeError("Array index %1% must be an integer, but it has type %2%",
20612075
expression->right, rtype->toString());
20622076
return expression;
20632077
}
20642078

20652079
const IR::Type* type = nullptr;
2066-
if (auto hst = ltype->to<IR::Type_Stack>()) {
2067-
if (hst->sizeKnown()) {
2080+
if (hst) {
2081+
if (checkArrays && hst->sizeKnown()) {
20682082
int size = hst->getSize();
20692083
if (index >= 0 && index >= size) {
20702084
typeError("Array index %1% larger or equal to array size %2%",
@@ -2148,11 +2162,12 @@ const IR::Node* TypeInference::binaryArith(const IR::Operation_Binary* expressio
21482162
return expression;
21492163
} else if (ltype->is<IR::Type_InfInt>() && rtype->is<IR::Type_InfInt>()) {
21502164
auto t = new IR::Type_InfInt();
2165+
auto result = constantFold(expression);
2166+
setType(result, t);
21512167
setType(getOriginal(), t);
2152-
setType(expression, t);
2153-
setCompileTimeConstant(expression);
2168+
setCompileTimeConstant(result);
21542169
setCompileTimeConstant(getOriginal<IR::Expression>());
2155-
return expression;
2170+
return result;
21562171
}
21572172

21582173
const IR::Type* resultType = ltype;
@@ -2285,8 +2300,10 @@ const IR::Node* TypeInference::shift(const IR::Operation_Binary* expression) {
22852300
setType(expression, ltype);
22862301
setType(getOriginal(), ltype);
22872302
if (isCompileTimeConstant(expression->left) && isCompileTimeConstant(expression->right)) {
2288-
setCompileTimeConstant(expression);
2303+
auto result = constantFold(expression);
2304+
setCompileTimeConstant(result);
22892305
setCompileTimeConstant(getOriginal<IR::Expression>());
2306+
return result;
22902307
}
22912308
return expression;
22922309
}
@@ -2317,10 +2334,11 @@ const IR::Node* TypeInference::bitwise(const IR::Operation_Binary* expression) {
23172334
} else if (ltype->is<IR::Type_InfInt>() && rtype->is<IR::Type_InfInt>()) {
23182335
auto t = new IR::Type_InfInt();
23192336
setType(getOriginal(), t);
2320-
setType(expression, t);
2321-
setCompileTimeConstant(expression);
2337+
auto result = constantFold(expression);
2338+
setType(result, t);
2339+
setCompileTimeConstant(result);
23222340
setCompileTimeConstant(getOriginal<IR::Expression>());
2323-
return expression;
2341+
return result;
23242342
}
23252343

23262344
const IR::Type* resultType = ltype;
@@ -2446,8 +2464,10 @@ const IR::Node* TypeInference::postorder(IR::LNot* expression) {
24462464
setType(getOriginal(), IR::Type_Boolean::get());
24472465
}
24482466
if (isCompileTimeConstant(expression->expr)) {
2449-
setCompileTimeConstant(expression);
2467+
auto result = constantFold(expression);
2468+
setCompileTimeConstant(result);
24502469
setCompileTimeConstant(getOriginal<IR::Expression>());
2470+
return result;
24512471
}
24522472
return expression;
24532473
}
@@ -2473,8 +2493,10 @@ const IR::Node* TypeInference::postorder(IR::Neg* expression) {
24732493
expression->getStringOp(), expression->expr, type->toString());
24742494
}
24752495
if (isCompileTimeConstant(expression->expr)) {
2476-
setCompileTimeConstant(expression);
2496+
auto result = constantFold(expression);
2497+
setCompileTimeConstant(result);
24772498
setCompileTimeConstant(getOriginal<IR::Expression>());
2499+
return result;
24782500
}
24792501
return expression;
24802502
}
@@ -2499,8 +2521,10 @@ const IR::Node* TypeInference::postorder(IR::Cmpl* expression) {
24992521
expression->getStringOp(), expression->expr, type->toString());
25002522
}
25012523
if (isCompileTimeConstant(expression->expr)) {
2502-
setCompileTimeConstant(expression);
2524+
auto result = constantFold(expression);
2525+
setCompileTimeConstant(result);
25032526
setCompileTimeConstant(getOriginal<IR::Expression>());
2527+
return result;
25042528
}
25052529
return expression;
25062530
}
@@ -2732,8 +2756,10 @@ const IR::Node* TypeInference::postorder(IR::Slice* expression) {
27322756
setLeftValue(getOriginal<IR::Expression>());
27332757
}
27342758
if (isCompileTimeConstant(expression->e0)) {
2735-
setCompileTimeConstant(expression);
2759+
auto result = constantFold(expression);
2760+
setCompileTimeConstant(result);
27362761
setCompileTimeConstant(getOriginal<IR::Expression>());
2762+
return result;
27372763
}
27382764
return expression;
27392765
}
@@ -2776,8 +2802,10 @@ const IR::Node* TypeInference::postorder(IR::Mux* expression) {
27762802
if (isCompileTimeConstant(expression->e0) &&
27772803
isCompileTimeConstant(expression->e1) &&
27782804
isCompileTimeConstant(expression->e2)) {
2779-
setCompileTimeConstant(expression);
2805+
auto result = constantFold(expression);
2806+
setCompileTimeConstant(result);
27802807
setCompileTimeConstant(getOriginal<IR::Expression>());
2808+
return result;
27812809
}
27822810
}
27832811
return expression;
@@ -2834,6 +2862,21 @@ const IR::Node* TypeInference::postorder(IR::Member* expression) {
28342862
}
28352863

28362864
bool inMethod = getParent<IR::MethodCallExpression>() != nullptr;
2865+
// Built-in methods
2866+
if (inMethod && (member == IR::Type::minSizeInBits ||
2867+
member == IR::Type::minSizeInBytes ||
2868+
member == IR::Type::maxSizeInBits ||
2869+
member == IR::Type::maxSizeInBytes)) {
2870+
auto type = new IR::Type_Method(
2871+
new IR::Type_InfInt(), new IR::ParameterList(), member);
2872+
auto ctype = canonicalize(type);
2873+
if (ctype == nullptr)
2874+
return expression;
2875+
setType(getOriginal(), ctype);
2876+
setType(expression, ctype);
2877+
return expression;
2878+
}
2879+
28372880
if (type->is<IR::Type_StructLike>()) {
28382881
if (type->is<IR::Type_Header>() || type->is<IR::Type_HeaderUnion>()) {
28392882
if (inMethod && (member == IR::Type_Header::isValid)) {
@@ -2848,18 +2891,6 @@ const IR::Node* TypeInference::postorder(IR::Member* expression) {
28482891
return expression;
28492892
}
28502893
}
2851-
if (inMethod && (member == IR::Type_Header::minSizeInBits ||
2852-
member == IR::Type_Header::minSizeInBytes)) {
2853-
// Built-in method
2854-
auto type = new IR::Type_Method(
2855-
new IR::Type_InfInt(), new IR::ParameterList(), member);
2856-
auto ctype = canonicalize(type);
2857-
if (ctype == nullptr)
2858-
return expression;
2859-
setType(getOriginal(), ctype);
2860-
setType(expression, ctype);
2861-
return expression;
2862-
}
28632894
if (type->is<IR::Type_Header>()) {
28642895
if (inMethod && (member == IR::Type_Header::setValid ||
28652896
member == IR::Type_Header::setInvalid)) {
@@ -2966,17 +2997,6 @@ const IR::Node* TypeInference::postorder(IR::Member* expression) {
29662997
setType(getOriginal(), canon);
29672998
setType(expression, canon);
29682999
return expression;
2969-
} else if (inMethod && (
2970-
member == IR::Type_StructLike::minSizeInBytes ||
2971-
member == IR::Type_StructLike::minSizeInBits)) {
2972-
// Built-in method
2973-
auto type = new IR::Type_Method(new IR::Type_InfInt(), new IR::ParameterList(), member);
2974-
auto ctype = canonicalize(type);
2975-
if (ctype == nullptr)
2976-
return expression;
2977-
setType(getOriginal(), ctype);
2978-
setType(expression, ctype);
2979-
return expression;
29803000
}
29813001
}
29823002

@@ -3204,18 +3224,19 @@ const IR::Node* TypeInference::postorder(IR::MethodCallExpression* expression) {
32043224
inActionsList = true;
32053225
return actionCall(inActionsList, expression);
32063226
} else {
3207-
// Constant-fold minSizeInBits, minSizeInBytes
3227+
// Constant-fold constant expressions
32083228
if (auto mem = expression->method->to<IR::Member>()) {
32093229
auto type = typeMap->getType(mem->expr, true);
3210-
if ((mem->member == IR::Type_StructLike::minSizeInBits ||
3211-
mem->member == IR::Type_StructLike::minSizeInBytes) &&
3212-
(type->is<IR::Type_StructLike>() ||
3213-
type->is<IR::Type_Stack>())) {
3214-
LOG3("Folding " << mem->member);
3215-
int w = typeMap->minWidthBits(type, expression);
3230+
if ((mem->member == IR::Type::minSizeInBits ||
3231+
mem->member == IR::Type::minSizeInBytes ||
3232+
mem->member == IR::Type::maxSizeInBits ||
3233+
mem->member == IR::Type::maxSizeInBytes)) {
3234+
auto max = mem->member.name.startsWith("max");
3235+
int w = typeMap->widthBits(type, expression, max);
3236+
LOG3("Folding " << mem << " to " << w);
32163237
if (w < 0)
32173238
return expression;
3218-
if (mem->member == IR::Type_StructLike::minSizeInBytes)
3239+
if (mem->member.name.endsWith("Bytes"))
32193240
w = ROUNDUP(w, 8);
32203241
auto result = new IR::Constant(w);
32213242
auto tt = new IR::Type_Type(result->type);

frontends/p4/typeChecking/typeChecker.h

+6-1
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,9 @@ bool hasVarbitsOrUnions(const TypeMap* typeMap, const IR::Type* type);
7474
// with readOnly = true, it will assert that the program is not changed.
7575
// It is expected that once a program has been type-checked and all casts have
7676
// been inserted it will not need to change ever again during type-checking.
77+
// In fact, several passes do modify the program such that types are invalidated.
78+
// For example, enum elimination converts enum values into integers. After such
79+
// changes the typemap has to be cleared and types must be recomputed from scratch.
7780
class TypeInference : public Transform {
7881
// Input: reference map
7982
ReferenceMap* refMap;
@@ -85,11 +88,12 @@ class TypeInference : public Transform {
8588
// If readOnly=true it will assert that it behaves like
8689
// an Inspector.
8790
TypeInference(ReferenceMap* refMap, TypeMap* typeMap,
88-
bool readOnly = false);
91+
bool readOnly = false, bool checkArrays = true);
8992

9093
protected:
9194
// If true we expect to leave the program unchanged
9295
bool readOnly;
96+
bool checkArrays = true;
9397
const IR::Type* getType(const IR::Node* element) const;
9498
const IR::Type* getTypeType(const IR::Node* element) const;
9599
void setType(const IR::Node* element, const IR::Type* type);
@@ -125,6 +129,7 @@ class TypeInference : public Transform {
125129
bool checkAbstractMethods(const IR::Declaration_Instance* inst, const IR::Type_Extern* type);
126130
void addSubstitutions(const TypeVariableSubstitution* tvs);
127131

132+
const IR::Expression* constantFold(const IR::Expression* expression);
128133

129134
/** Converts each type to a canonical representation.
130135
* Made virtual to enable private midend passes to extend standard IR with custom IR classes.

0 commit comments

Comments
 (0)