Skip to content

Commit

Permalink
Support for [lsb+:width] slices
Browse files Browse the repository at this point in the history
- allows for non-const lsb slices (width must still be const)

Signed-off-by: Chris Dodd <[email protected]>
  • Loading branch information
ChrisDodd committed Oct 3, 2024
1 parent 49e835c commit 4cac585
Show file tree
Hide file tree
Showing 35 changed files with 370 additions and 33 deletions.
2 changes: 1 addition & 1 deletion backends/p4tools/common/lib/symbolic_env.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ bool SymbolicEnv::isSymbolicValue(const IR::Node *node) {
binary->is<IR::Concat>() || binary->is<IR::Mask>()) &&
isSymbolicValue(binary->left) && isSymbolicValue(binary->right);
}
if (const auto *slice = expr->to<IR::Slice>()) {
if (const auto *slice = expr->to<IR::AbstractSlice>()) {
return isSymbolicValue(slice->e0) && isSymbolicValue(slice->e1) &&
isSymbolicValue(slice->e2);
}
Expand Down
2 changes: 1 addition & 1 deletion backends/p4tools/modules/smith/common/statements.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ void StatementGenerator::removeLval(const IR::Expression *left, const IR::Type *
lvalStr = path->path->name.name;
} else if (const auto *mem = left->to<IR::Member>()) {
lvalStr = mem->member.name;
} else if (const auto *slice = left->to<IR::Slice>()) {
} else if (const auto *slice = left->to<IR::AbstractSlice>()) {
lvalStr = slice->e0->to<IR::PathExpression>()->path->name.name;
} else if (const auto *arrIdx = left->to<IR::ArrayIndex>()) {
lvalStr = arrIdx->left->to<IR::PathExpression>()->path->name.name;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -491,7 +491,7 @@ bool ExprStepper::preorder(const IR::StructExpression *structExpression) {
return stepSymbolicValue(structExpression);
}

bool ExprStepper::preorder(const IR::Slice *slice) {
bool ExprStepper::preorder(const IR::AbstractSlice *slice) {
logStep(slice);

if (!SymbolicEnv::isSymbolicValue(slice->e0)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -292,7 +292,7 @@ class ExprStepper : public AbstractStepper {
bool preorder(const IR::SelectExpression *selectExpression) override;
bool preorder(const IR::BaseListExpression *listExpression) override;
bool preorder(const IR::StructExpression *structExpression) override;
bool preorder(const IR::Slice *slice) override;
bool preorder(const IR::AbstractSlice *slice) override;
bool preorder(const IR::P4Table *table) override;
};

Expand Down
45 changes: 45 additions & 0 deletions frontends/common/constantFolding.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -678,6 +678,51 @@ const IR::Node *DoConstantFolding::postorder(IR::Slice *e) {
return new IR::Constant(e->srcInfo, resultType, value, cbase->base, true);
}

const IR::Node *DoConstantFolding::postorder(IR::PlusSlice *e) {
auto *e0 = getConstant(e->e0);
auto *lsb = getConstant(e->e1);
auto *width = getConstant(e->e2);
if (!width) {
if (typesKnown)
error(ErrorType::ERR_EXPECTED, "%1%: slice indexes must be compile-time constants",
e->e2);
return e;
}

if (!e0 || !lsb) return e;

auto clsb = lsb->to<IR::Constant>();
if (clsb == nullptr) {
error(ErrorType::ERR_EXPECTED, "%1%: expected an integer value", lsb);
return e;
}
auto cwidth = width->to<IR::Constant>();
if (cwidth == nullptr) {
error(ErrorType::ERR_EXPECTED, "%1%: expected an integer value", width);
return e;
}
auto cbase = e0->to<IR::Constant>();
if (cbase == nullptr) {
error(ErrorType::ERR_EXPECTED, "%1%: expected an integer value", e->e0);
return e;
}

int w = cwidth->asInt();
int l = clsb->asInt();
if (l < 0) {
::P4::error(ErrorType::ERR_EXPECTED, "%1%: expected slice indexes to be non-negative",
e->e2);
return e;
}
if (overflowWidth(e, l) || overflowWidth(e, l + w)) return e;
big_int value = cbase->value >> l;
big_int mask = 1;
mask = (mask << w) - 1;
value = value & mask;
auto resultType = IR::Type_Bits::get(w);
return new IR::Constant(e->srcInfo, resultType, value, cbase->base, true);
}

const IR::Node *DoConstantFolding::postorder(IR::Member *e) {
if (!typesKnown) return e;
auto orig = getOriginal<IR::Member>();
Expand Down
1 change: 1 addition & 0 deletions frontends/common/constantFolding.h
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@ class DoConstantFolding : public Transform, public ResolutionContext {
const IR::Node *postorder(IR::LAnd *e) override;
const IR::Node *postorder(IR::LOr *e) override;
const IR::Node *postorder(IR::Slice *e) override;
const IR::Node *postorder(IR::PlusSlice *e) override;
const IR::Node *postorder(IR::Add *e) override;
const IR::Node *postorder(IR::AddSat *e) override;
const IR::Node *postorder(IR::Sub *e) override;
Expand Down
3 changes: 1 addition & 2 deletions frontends/p4-14/fromv1.0/converters.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -110,8 +110,7 @@ const IR::Node *ExpressionConverter::postorder(IR::Primitive *primitive) {
auto typeargs = new IR::Vector<IR::Type>();
typeargs->push_back(IR::Type_Bits::get(aval + bval));
auto lookahead = new IR::MethodCallExpression(method, typeargs);
auto result = new IR::Slice(primitive->srcInfo, lookahead, new IR::Constant(bval - 1),
new IR::Constant(0));
auto result = new IR::Slice(primitive->srcInfo, lookahead, bval - 1, 0);
result->type = IR::Type_Bits::get(bval);
return result;
} else if (primitive->name == "valid") {
Expand Down
2 changes: 1 addition & 1 deletion frontends/p4/alias.h
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ class ReadsWrites : public Inspector, public ResolutionContext {
rw.emplace(expression, e0->join(e1)->join(e2));
}

void postorder(const IR::Slice *expression) override {
void postorder(const IR::AbstractSlice *expression) override {
auto e = ::P4::get(rw, expression->e0);
CHECK_NULL(e);
rw.emplace(expression, e);
Expand Down
2 changes: 1 addition & 1 deletion frontends/p4/def_use.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -536,7 +536,7 @@ bool ComputeWriteSet::preorder(const IR::Literal *expression) {
return false;
}

bool ComputeWriteSet::preorder(const IR::Slice *expression) {
bool ComputeWriteSet::preorder(const IR::AbstractSlice *expression) {
visit(expression->e0);
expressionWrites(expression, lhs ? getWrites(expression->e0) : LocationSet::empty);
return false;
Expand Down
2 changes: 1 addition & 1 deletion frontends/p4/def_use.h
Original file line number Diff line number Diff line change
Expand Up @@ -624,7 +624,7 @@ class ComputeWriteSet : public Inspector, public IHasDbPrint {

// expressions
bool preorder(const IR::Literal *expression) override;
bool preorder(const IR::Slice *expression) override;
bool preorder(const IR::AbstractSlice *expression) override;
bool preorder(const IR::TypeNameExpression *expression) override;
bool preorder(const IR::PathExpression *expression) override;
bool preorder(const IR::Member *expression) override;
Expand Down
2 changes: 1 addition & 1 deletion frontends/p4/inlining.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ class FindLocationSets : public Inspector {
return false;
}

bool preorder(const IR::Slice *expression) {
bool preorder(const IR::AbstractSlice *expression) {
visit(expression->e0);
auto base = get(expression->e0);
set(expression, base);
Expand Down
2 changes: 1 addition & 1 deletion frontends/p4/sideEffects.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -435,7 +435,7 @@ const IR::Node *DoSimplifyExpressions::preorder(IR::MethodCallExpression *mce) {

// If the parameter is out and the argument is a slice then
// also use a temporary; makes the job of def-use analysis easier
if (arg->expression->is<IR::Slice>() && p->hasOut()) {
if (arg->expression->is<IR::AbstractSlice>() && p->hasOut()) {
LOG3("Using temporary for " << dbp(mce) << " param " << dbp(p)
<< " since it is an out slice");
useTemporary.emplace(p);
Expand Down
10 changes: 6 additions & 4 deletions frontends/p4/simplifyDefUse.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -644,7 +644,7 @@ class FindUninitialized : public Inspector {
loc = new LocationSet(storage);
else
loc = LocationSet::empty;
} else if (auto slice = parent->to<IR::Slice>()) {
} else if (auto slice = parent->to<IR::AbstractSlice>()) {
loc = checkHeaderFieldWrite(expr, slice->e0);
} else {
BUG("%1%: unexpected expression on LHS", parent);
Expand Down Expand Up @@ -1380,20 +1380,22 @@ class FindUninitialized : public Inspector {
return false;
}

bool preorder(const IR::Slice *expression) override {
bool preorder(const IR::AbstractSlice *expression) override {
LOG3("FU Visiting [" << expression->id << "]: " << expression);

auto *slice_stmt = findContext<IR::AssignmentStatement>();
if (slice_stmt != nullptr && lhs) {
auto *slice = expression->to<IR::Slice>();
if (slice_stmt != nullptr && lhs && slice) {
// track this slice statement
hasUses.watchForOverwrites(expression);
hasUses.watchForOverwrites(slice);
LOG4("Tracking " << dbp(slice_stmt) << " " << slice_stmt
<< " for potential overwrites");
}

bool save = lhs;
lhs = false; // slices on the LHS also read the data
visit(expression->e0);
visit(expression->e1); // this might not be a constant (for a PlusSlice)
LOG3("FU Returned from " << expression);
auto storage = getReads(expression->e0, true);
reads(expression, storage); // true even in LHS
Expand Down
19 changes: 19 additions & 0 deletions frontends/p4/strengthReduction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -448,4 +448,23 @@ const IR::Node *DoStrengthReduction::postorder(IR::Slice *expr) {
return expr;
}

const IR::Node *DoStrengthReduction::postorder(IR::PlusSlice *expr) {
if (expr->e1->is<IR::Constant>() && expr->e2->is<IR::Constant>()) {
auto *rv = new IR::Slice(expr->srcInfo, expr->e0, expr->getH(), expr->getL());
return postorder(rv);
}
if (auto sh = expr->e0->to<IR::Shr>()) {
if (!sh->left->type->is<IR::Type_Bits>()) return expr;
if (sh->left->type->to<IR::Type_Bits>()->isSigned) return expr;
expr->e0 = sh->left;
expr->e1 = new IR::Add(sh->srcInfo, expr->e1, sh->right);
}
if (auto sh = expr->e0->to<IR::Shl>()) {
if (!sh->left->type->is<IR::Type_Bits>()) return expr;
expr->e0 = sh->left;
expr->e1 = new IR::Sub(sh->srcInfo, expr->e1, sh->right);
}
return expr;
}

} // namespace P4
1 change: 1 addition & 0 deletions frontends/p4/strengthReduction.h
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ class DoStrengthReduction final : public Transform {
const IR::Node *postorder(IR::Mod *expr) override;
const IR::Node *postorder(IR::Mux *expr) override;
const IR::Node *postorder(IR::Slice *expr) override;
const IR::Node *postorder(IR::PlusSlice *expr) override;
const IR::Node *postorder(IR::Mask *expr) override;
const IR::Node *postorder(IR::Range *expr) override;
const IR::Node *postorder(IR::Concat *expr) override;
Expand Down
3 changes: 2 additions & 1 deletion frontends/p4/toP4/toP4.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -772,7 +772,7 @@ VECTOR_VISIT(IndexedVector, StatOrDecl)

///////////////////////////////////////////

bool ToP4::preorder(const IR::Slice *slice) {
bool ToP4::preorder(const IR::AbstractSlice *slice) {
int prec = expressionPrecedence;
bool useParens = prec > slice->getPrecedence();
if (useParens) builder.append("(");
Expand All @@ -782,6 +782,7 @@ bool ToP4::preorder(const IR::Slice *slice) {
builder.append("[");
expressionPrecedence = DBPrint::Prec_Low;
visit(slice->e1);
if (slice->is<IR::PlusSlice>()) builder.append("+");
builder.append(":");
expressionPrecedence = DBPrint::Prec_Low;
visit(slice->e2);
Expand Down
2 changes: 1 addition & 1 deletion frontends/p4/toP4/toP4.h
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ class ToP4 : public Inspector, ResolutionContext {
bool preorder(const IR::Dots *e) override;
bool preorder(const IR::NamedDots *e) override;
bool preorder(const IR::Constant *c) override;
bool preorder(const IR::Slice *slice) override;
bool preorder(const IR::AbstractSlice *slice) override;
bool preorder(const IR::BoolLiteral *b) override;
bool preorder(const IR::StringLiteral *s) override;
bool preorder(const IR::PathExpression *p) override;
Expand Down
1 change: 1 addition & 0 deletions frontends/p4/typeChecking/readOnlyTypeInference.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ DEFINE_POSTORDER(IR::Cmpl)
DEFINE_POSTORDER(IR::Cast)
DEFINE_POSTORDER(IR::Mux)
DEFINE_POSTORDER(IR::Slice)
DEFINE_POSTORDER(IR::PlusSlice)
DEFINE_POSTORDER(IR::PathExpression)
DEFINE_POSTORDER(IR::Member)
DEFINE_POSTORDER(IR::TypeNameExpression)
Expand Down
72 changes: 72 additions & 0 deletions frontends/p4/typeChecking/typeCheckExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1452,6 +1452,78 @@ const IR::Node *TypeInferenceBase::postorder(const IR::Slice *expression) {
return expression;
}

const IR::Node *TypeInferenceBase::postorder(const IR::PlusSlice *expression) {
if (done()) return expression;
const IR::Type *type = getType(expression->e0);
if (type == nullptr) return expression;

if (auto se = type->to<IR::Type_SerEnum>()) type = getTypeType(se->type);

if (!type->is<IR::Type_Bits>()) {
typeError("%1%: bit extraction only defined for bit<> types", expression);
return expression;
}

IR::PlusSlice *cloned = nullptr;
auto e1type = getType(expression->e1);
if (e1type && e1type->is<IR::Type_SerEnum>()) {
auto ei = EnumInstance::resolve(expression->e1, typeMap);
CHECK_NULL(ei);
if (auto sei = ei->to<SerEnumInstance>(); sei && expression->e1 != sei->value) {
cloned = expression->clone();
cloned->e1 = sei->value;
}
}
auto e2type = getType(expression->e2);
if (e2type && e2type->is<IR::Type_SerEnum>()) {
auto ei = EnumInstance::resolve(expression->e2, typeMap);
CHECK_NULL(ei);
auto sei = ei->to<SerEnumInstance>();
if (sei == nullptr) {
typeError("%1%: slice bit index values must be constants", expression->e2);
return expression;
}

if (expression->e1 != sei->value) {
cloned = (cloned ? cloned : expression->clone());
cloned->e2 = sei->value;
}
}
if (cloned) expression = cloned;

if (!expression->e2->is<IR::Constant>()) {
typeError("%1%: slice bit index values must be constants", expression->e2);
return expression;
}
auto width = expression->e2->checkedTo<IR::Constant>();
if (!width->fitsInt()) {
typeError("%1%: width too large", width);
return expression;
}
int w = width->asInt();
if (w < 0) {
typeError("%1%: negative width %2%", expression, width);
return expression;
}

const IR::Type *resultType = IR::Type_Bits::get(type->srcInfo, w, false);
resultType = canonicalize(resultType);
if (resultType == nullptr) return expression;
setType(getOriginal(), resultType);
setType(expression, resultType);
if (isLeftValue(expression->e0)) {
setLeftValue(expression);
setLeftValue(getOriginal<IR::Expression>());
}
if (isCompileTimeConstant(expression->e0) && isCompileTimeConstant(expression->e1)) {
auto result = constantFold(expression);
setCompileTimeConstant(result);
setCompileTimeConstant(getOriginal<IR::Expression>());
return result;
}
return expression;
}

const IR::Node *TypeInferenceBase::postorder(const IR::Dots *expression) {
if (done()) return expression;
setType(expression, IR::Type_Any::get());
Expand Down
3 changes: 3 additions & 0 deletions frontends/p4/typeChecking/typeChecker.h
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,7 @@ class TypeInferenceBase : public virtual Visitor, public ResolutionContext {
const IR::Node *postorder(const IR::Cast *expression);
const IR::Node *postorder(const IR::Mux *expression);
const IR::Node *postorder(const IR::Slice *expression);
const IR::Node *postorder(const IR::PlusSlice *expression);
const IR::Node *postorder(const IR::PathExpression *expression);
const IR::Node *postorder(const IR::Member *expression);
const IR::Node *postorder(const IR::TypeNameExpression *expression);
Expand Down Expand Up @@ -447,6 +448,7 @@ class ReadOnlyTypeInference : public virtual Inspector, public TypeInferenceBase
void postorder(const IR::Cast *expression) override;
void postorder(const IR::Mux *expression) override;
void postorder(const IR::Slice *expression) override;
void postorder(const IR::PlusSlice *expression) override;
void postorder(const IR::PathExpression *expression) override;
void postorder(const IR::Member *expression) override;
void postorder(const IR::TypeNameExpression *expression) override;
Expand Down Expand Up @@ -582,6 +584,7 @@ class TypeInference : public virtual Transform, public TypeInferenceBase {
const IR::Node *postorder(IR::Cast *expression) override;
const IR::Node *postorder(IR::Mux *expression) override;
const IR::Node *postorder(IR::Slice *expression) override;
const IR::Node *postorder(IR::PlusSlice *expression) override;
const IR::Node *postorder(IR::PathExpression *expression) override;
const IR::Node *postorder(IR::Member *expression) override;
const IR::Node *postorder(IR::TypeNameExpression *expression) override;
Expand Down
1 change: 1 addition & 0 deletions frontends/p4/typeChecking/typeInference.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ DEFINE_POSTORDER(IR::Cmpl)
DEFINE_POSTORDER(IR::Cast)
DEFINE_POSTORDER(IR::Mux)
DEFINE_POSTORDER(IR::Slice)
DEFINE_POSTORDER(IR::PlusSlice)
DEFINE_POSTORDER(IR::PathExpression)
DEFINE_POSTORDER(IR::Member)
DEFINE_POSTORDER(IR::TypeNameExpression)
Expand Down
11 changes: 9 additions & 2 deletions frontends/parsers/p4/p4parser.ypp
Original file line number Diff line number Diff line change
Expand Up @@ -1604,6 +1604,7 @@ lvalue
| lvalue dot_name %prec DOT { $$ = new IR::Member(@1 + @2, $1, *$2); }
| lvalue "[" expression "]" { $$ = new IR::ArrayIndex(@1 + @4, $1, $3); }
| lvalue "[" expression ":" expression "]" { $$ = new IR::Slice(@1 + @6, $1, $3, $5); }
| lvalue "[" expression "+" ":" expression "]" { $$ = new IR::PlusSlice(@1 + @7, $1, $3, $6); }
| "(" lvalue ")" { $$ = $2; }
;

Expand All @@ -1616,7 +1617,10 @@ expression
| THIS { $$ = new IR::This(@1); }
| prefixedNonTypeName { $$ = new IR::PathExpression($1); }
| expression "[" expression "]" { $$ = new IR::ArrayIndex(@1 + @4, $1, $3); }
| expression "[" expression ":" expression "]" { $$ = new IR::Slice(@1 + @6, $1, $3, $5); }
| expression "[" expression ":" expression "]"
{ $$ = new IR::Slice(@1 + @6, $1, $3, $5); }
| expression "[" expression "+" ":" expression "]"
{ $$ = new IR::PlusSlice(@1 + @7, $1, $3, $6); }
| "{" expressionList optTrailingComma "}" { $$ = new IR::ListExpression(@1 + @4, *$2); }
| INVALID { $$ = new IR::Invalid(@1, IR::Type::Unknown::get()); }
| "{" kvList optTrailingComma "}" { $$ = new IR::StructExpression(
Expand Down Expand Up @@ -1680,7 +1684,10 @@ nonBraceExpression
| THIS { $$ = new IR::This(@1); }
| prefixedNonTypeName { $$ = new IR::PathExpression($1); }
| nonBraceExpression "[" expression "]" { $$ = new IR::ArrayIndex(@1 + @4, $1, $3); }
| nonBraceExpression "[" expression ":" expression "]" { $$ = new IR::Slice(@1 + @6, $1, $3, $5); }
| nonBraceExpression "[" expression ":" expression "]"
{ $$ = new IR::Slice(@1 + @6, $1, $3, $5); }
| nonBraceExpression "[" expression "+" ":" expression "]"
{ $$ = new IR::PlusSlice(@1 + @7, $1, $3, $6); }
| "(" expression ")" { $$ = $2; }
| "!" expression %prec PREFIX { $$ = new IR::LNot(@1 + @2, $2); }
| "~" expression %prec PREFIX { $$ = new IR::Cmpl(@1 + @2, $2); }
Expand Down
Loading

0 comments on commit 4cac585

Please sign in to comment.