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)
  • Loading branch information
ChrisDodd committed Sep 17, 2024
1 parent b90f777 commit 4a72192
Show file tree
Hide file tree
Showing 25 changed files with 374 additions and 37 deletions.
2 changes: 1 addition & 1 deletion backends/dpdk/dpdkArch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -611,7 +611,7 @@ const IR::Node *AlignHdrMetaField::preorder(IR::Member *m) {
// two different headers have field with same name.
if (memVec.headerStr != hdrStrName) continue;
auto mem = new IR::Member(m->expr, IR::ID(memVec.modifiedName));
auto sliceMem = new IR::Slice(mem->clone(), memVec.msb, memVec.lsb);
auto sliceMem = new IR::AbsSlice(mem->clone(), memVec.msb, memVec.lsb);
return sliceMem;
}
}
Expand Down
47 changes: 46 additions & 1 deletion frontends/common/constantFolding.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -622,7 +622,7 @@ static bool overflowWidth(const IR::Node *node, int width) {
return false;
}

const IR::Node *DoConstantFolding::postorder(IR::Slice *e) {
const IR::Node *DoConstantFolding::postorder(IR::AbsSlice *e) {
const IR::Expression *msb = getConstant(e->e1);
const IR::Expression *lsb = getConstant(e->e2);
if (msb == nullptr) {
Expand Down 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
3 changes: 2 additions & 1 deletion frontends/common/constantFolding.h
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,8 @@ class DoConstantFolding : public Transform, public ResolutionContext {
const IR::Node *postorder(IR::LNot *e) override;
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::AbsSlice *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
7 changes: 3 additions & 4 deletions frontends/p4/fromv1.0/converters.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,8 @@ const IR::Node *ExpressionConverter::postorder(IR::Mask *expression) {
auto range = Util::findOnes(value);
if (range.lowIndex == 0 && range.highIndex >= exp->type->width_bits() - 1U) return exp;
if (value != range.value) return new IR::BAnd(expression->srcInfo, exp, cst);
return new IR::Slice(exp, new IR::Constant(expression->srcInfo, range.highIndex),
new IR::Constant(expression->srcInfo, range.lowIndex));
return new IR::AbsSlice(exp, new IR::Constant(expression->srcInfo, range.highIndex),
new IR::Constant(expression->srcInfo, range.lowIndex));
}

const IR::Node *ExpressionConverter::postorder(IR::Constant *expression) {
Expand Down 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::AbsSlice(primitive->srcInfo, lookahead, bval - 1, 0);
result->type = IR::Type_Bits::get(bval);
return result;
} else if (primitive->name == "valid") {
Expand Down
4 changes: 2 additions & 2 deletions frontends/p4/fromv1.0/programStructure.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1169,8 +1169,8 @@ const IR::Statement *ProgramStructure::sliceAssign(const IR::Primitive *primitiv
if (cst->value == range.value) {
auto h = new IR::Constant(range.highIndex);
auto l = new IR::Constant(range.lowIndex);
left = new IR::Slice(left->srcInfo, left, h, l);
right = new IR::Slice(right->srcInfo, right, h, l);
left = new IR::AbsSlice(left->srcInfo, left, h, l);
right = new IR::AbsSlice(right->srcInfo, right, h, l);
return assign(primitive->srcInfo, left, right, nullptr);
}
}
Expand Down
27 changes: 23 additions & 4 deletions frontends/p4/strengthReduction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -345,7 +345,7 @@ const IR::Node *DoStrengthReduction::postorder(IR::ArrayIndex *expr) {
return expr;
}

const IR::Node *DoStrengthReduction::postorder(IR::Slice *expr) {
const IR::Node *DoStrengthReduction::postorder(IR::AbsSlice *expr) {
int shift_amt = 0;
const IR::Expression *shift_of = nullptr;
if (auto sh = expr->e0->to<IR::Shr>()) {
Expand Down Expand Up @@ -407,8 +407,8 @@ const IR::Node *DoStrengthReduction::postorder(IR::Slice *expr) {
return new IR::Concat(
expr->srcInfo, expr->type,
// type of slice is calculated by its constructor
new IR::Slice(cat->left->srcInfo, cat->left, expr->getH() - rwidth, 0),
new IR::Slice(cat->right->srcInfo, cat->right, rwidth - 1, expr->getL()));
new IR::AbsSlice(cat->left->srcInfo, cat->left, expr->getH() - rwidth, 0),
new IR::AbsSlice(cat->right->srcInfo, cat->right, rwidth - 1, expr->getL()));
}
}

Expand All @@ -426,7 +426,7 @@ const IR::Node *DoStrengthReduction::postorder(IR::Slice *expr) {
}

// out-of-bound error has been caught in type checking
if (auto sl = expr->e0->to<IR::Slice>()) {
if (auto sl = expr->e0->to<IR::AbsSlice>()) {
int delta = sl->getL();
expr->e0 = sl->e0;
if (delta != 0) {
Expand All @@ -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::AbsSlice(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
3 changes: 2 additions & 1 deletion frontends/p4/strengthReduction.h
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,8 @@ class DoStrengthReduction final : public Transform {
const IR::Node *postorder(IR::Div *expr) override;
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::AbsSlice *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
1 change: 1 addition & 0 deletions frontends/p4/toP4/toP4.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -780,6 +780,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
3 changes: 2 additions & 1 deletion frontends/p4/typeChecking/readOnlyTypeInference.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,8 @@ DEFINE_POSTORDER(IR::UPlus)
DEFINE_POSTORDER(IR::Cmpl)
DEFINE_POSTORDER(IR::Cast)
DEFINE_POSTORDER(IR::Mux)
DEFINE_POSTORDER(IR::Slice)
DEFINE_POSTORDER(IR::AbsSlice)
DEFINE_POSTORDER(IR::PlusSlice)
DEFINE_POSTORDER(IR::PathExpression)
DEFINE_POSTORDER(IR::Member)
DEFINE_POSTORDER(IR::TypeNameExpression)
Expand Down
76 changes: 74 additions & 2 deletions frontends/p4/typeChecking/typeCheckExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1347,7 +1347,7 @@ const IR::Node *TypeInferenceBase::postorder(const IR::PathExpression *expressio
return expression;
}

const IR::Node *TypeInferenceBase::postorder(const IR::Slice *expression) {
const IR::Node *TypeInferenceBase::postorder(const IR::AbsSlice *expression) {
if (done()) return expression;
const IR::Type *type = getType(expression->e0);
if (type == nullptr) return expression;
Expand All @@ -1359,7 +1359,7 @@ const IR::Node *TypeInferenceBase::postorder(const IR::Slice *expression) {
return expression;
}

IR::Slice *cloned = nullptr;
IR::AbsSlice *cloned = nullptr;
auto e1type = getType(expression->e1);
if (e1type && e1type->is<IR::Type_SerEnum>()) {
auto ei = EnumInstance::resolve(expression->e1, typeMap);
Expand Down 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
9 changes: 6 additions & 3 deletions frontends/p4/typeChecking/typeChecker.h
Original file line number Diff line number Diff line change
Expand Up @@ -304,7 +304,8 @@ class TypeInferenceBase : public virtual Visitor, public ResolutionContext {
const IR::Node *postorder(const IR::Cmpl *expression);
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::AbsSlice *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 @@ -446,7 +447,8 @@ class ReadOnlyTypeInference : public virtual Inspector, public TypeInferenceBase
void postorder(const IR::Cmpl *expression) override;
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::AbsSlice *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 @@ -581,7 +583,8 @@ class TypeInference : public virtual Transform, public TypeInferenceBase {
const IR::Node *postorder(IR::Cmpl *expression) override;
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::AbsSlice *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
3 changes: 2 additions & 1 deletion frontends/p4/typeChecking/typeInference.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,8 @@ DEFINE_POSTORDER(IR::UPlus)
DEFINE_POSTORDER(IR::Cmpl)
DEFINE_POSTORDER(IR::Cast)
DEFINE_POSTORDER(IR::Mux)
DEFINE_POSTORDER(IR::Slice)
DEFINE_POSTORDER(IR::AbsSlice)
DEFINE_POSTORDER(IR::PlusSlice)
DEFINE_POSTORDER(IR::PathExpression)
DEFINE_POSTORDER(IR::Member)
DEFINE_POSTORDER(IR::TypeNameExpression)
Expand Down
13 changes: 10 additions & 3 deletions frontends/parsers/p4/p4parser.ypp
Original file line number Diff line number Diff line change
Expand Up @@ -1549,7 +1549,8 @@ lvalue
| THIS { $$ = new IR::This(@1); }
| 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::AbsSlice(@1 + @6, $1, $3, $5); }
| lvalue "[" expression "+" ":" expression "]" { $$ = new IR::PlusSlice(@1 + @7, $1, $3, $6); }
| "(" lvalue ")" { $$ = $2; }
;

Expand All @@ -1562,7 +1563,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::AbsSlice(@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 @@ -1626,7 +1630,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::AbsSlice(@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
9 changes: 8 additions & 1 deletion ir/dbprint-expression.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -75,13 +75,20 @@ ALL_UNARY_OPS(UNOP_DBPRINT)
}
ALL_BINARY_OPS(BINOP_DBPRINT)

void IR::Slice::dbprint(std::ostream &out) const {
void IR::AbsSlice::dbprint(std::ostream &out) const {
int prec = getprec(out);
out << setprec(Prec_Postfix) << e0 << "[" << setprec(Prec_Low) << e1 << ":" << setprec(Prec_Low)
<< e2 << setprec(prec) << ']';
if (prec == 0) out << ';';
}

void IR::PlusSlice::dbprint(std::ostream &out) const {
int prec = getprec(out);
out << setprec(Prec_Postfix) << e0 << "[" << setprec(Prec_Low) << e1 << "+:"
<< setprec(Prec_Low) << e2 << setprec(prec) << ']';
if (prec == 0) out << ';';
}

void IR::Primitive::dbprint(std::ostream &out) const {
const char *sep = "";
int prec = getprec(out);
Expand Down
Loading

0 comments on commit 4a72192

Please sign in to comment.