Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] Add example implementation for bounded foreach-style loops #4558

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion frontends/p4/moveDeclarations.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -79,11 +79,13 @@ const IR::Node *MoveDeclarations::postorder(IR::Declaration_Variable *decl) {
auto varRef = new IR::PathExpression(decl->name);
auto keep = new IR::AssignmentStatement(decl->srcInfo, varRef, decl->initializer);
return keep;
} else {
} else if (!parent->is<IR::ForEachStatement>()) { // never move loop index decl out of foreach
LOG1("Moving " << decl);
addMove(decl);
return nullptr;
}

return decl;
}

const IR::Node *MoveDeclarations::postorder(IR::Declaration_Constant *decl) {
Expand Down
13 changes: 13 additions & 0 deletions frontends/p4/sideEffects.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -674,6 +674,19 @@ const IR::Node *DoSimplifyExpressions::preorder(IR::SwitchStatement *statement)
return rv;
}

const IR::Node *DoSimplifyExpressions::preorder(IR::ForEachStatement *statement) {
IR::Statement *rv = statement;
visit(statement->range, "index");
if (!statements.empty()) {
statements.push_back(statement);
rv = new IR::BlockStatement(statements);
statements.clear();
}
visit(statement->body, "body");
prune();
return rv;
}

void DoSimplifyExpressions::end_apply(const IR::Node *) {
BUG_CHECK(toInsert.empty(), "DoSimplifyExpressions::end_apply orphaned declarations");
BUG_CHECK(statements.empty(), "DoSimplifyExpressions::end_apply orphaned statements");
Expand Down
1 change: 1 addition & 0 deletions frontends/p4/sideEffects.h
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,7 @@ class DoSimplifyExpressions : public Transform, P4WriteContext {
const IR::Node *postorder(IR::ReturnStatement *statement) override;
const IR::Node *preorder(IR::SwitchStatement *statement) override;
const IR::Node *preorder(IR::IfStatement *statement) override;
const IR::Node *preorder(IR::ForEachStatement *statement) override;

void end_apply(const IR::Node *) override;
};
Expand Down
27 changes: 27 additions & 0 deletions frontends/p4/toP4/toP4.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1192,6 +1192,33 @@ bool ToP4::preorder(const IR::IfStatement *s) {
return false;
}

bool ToP4::preorder(const IR::ForEachStatement *s) {
dump(2);
builder.append("foreach (");
auto type = s->index[0]->to<IR::Declaration_Variable>()->type->getP4Type();
CHECK_NULL(type);
visit(type);
builder.spc();
builder.append(s->index[0]->name);
builder.append(" in ");
visit(s->range);
builder.append(") ");
if (!s->body->is<IR::BlockStatement>()) {
builder.append("{");
builder.increaseIndent();
builder.newline();
builder.emitIndent();
}
visit(s->body);
if (!s->body->is<IR::BlockStatement>()) {
builder.newline();
builder.decreaseIndent();
builder.emitIndent();
builder.append("}");
}
return false;
}

bool ToP4::preorder(const IR::MethodCallStatement *s) {
dump(3);
visit(s->methodCall);
Expand Down
1 change: 1 addition & 0 deletions frontends/p4/toP4/toP4.h
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,7 @@ class ToP4 : public Inspector {
bool preorder(const IR::SwitchCase *s) override;
bool preorder(const IR::SwitchStatement *s) override;
bool preorder(const IR::IfStatement *s) override;
bool preorder(const IR::ForEachStatement *s) override;

// misc
bool preorder(const IR::NamedExpression *ne) override;
Expand Down
2 changes: 2 additions & 0 deletions frontends/parsers/p4/p4lexer.ll
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,8 @@ using Parser = P4::P4Parser;
return makeToken(EXTERN); }
"false" { BEGIN(driver.saveState); driver.template_args = false;
return makeToken(FALSE); }
"foreach" { BEGIN(driver.saveState); driver.template_args = false;
return makeToken(FOREACH); }
"header" { BEGIN(driver.saveState); driver.template_args = false;
return makeToken(HEADER); }
"header_union" { BEGIN(driver.saveState); driver.template_args = false;
Expand Down
24 changes: 24 additions & 0 deletions frontends/parsers/p4/p4parser.ypp
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,7 @@ inline std::ostream& operator<<(std::ostream& out, const P4::Token& t) {
ELSE ENTRIES ENUM ERROR EXIT EXTERN HEADER HEADER_UNION IF IN INOUT
INT KEY LIST SELECT MATCH_KIND TYPE OUT PACKAGE PARSER PRAGMA PRIORITY RETURN
STATE STRING STRUCT SWITCH TABLE TRANSITION TUPLE TYPEDEF VARBIT VALUESET VOID
%token<Token> FOREACH

%token<cstring> IDENTIFIER TYPE_IDENTIFIER STRING_LITERAL
%token<UnparsedConstant> INTEGER
Expand Down Expand Up @@ -315,6 +316,9 @@ inline std::ostream& operator<<(std::ostream& out, const P4::Token& t) {
%type<IR::Vector<IR::Expression>*> intOrStrList
%type<IR::Vector<IR::Expression>*> strList
%type<IR::Expression*> intOrStr
%type<IR::Declaration*> loopIndexDeclaration
%type<IR::Expression*> rangeExpression
%type<IR::Statement*> foreachStatement

// %precedence COMMA
%precedence QUESTION
Expand Down Expand Up @@ -568,6 +572,7 @@ annotationToken
| EXIT { $$ = $1; }
| EXTERN { $$ = $1; }
| FALSE { $$ = $1; }
| FOREACH { $$ = $1; }
| HEADER { $$ = $1; }
| HEADER_UNION { $$ = $1; }
| IF { $$ = $1; }
Expand Down Expand Up @@ -1216,6 +1221,24 @@ conditionalStatement
{ $$ = new IR::IfStatement(@1, $3, $5, $7); }
;

rangeExpression
: expression ".." expression { $$ = new IR::Range(@1 + @3, $1, $3); }
;

loopIndexDeclaration
: typeRef name
{ $$ = new IR::Declaration_Variable(@1, *$2, $1);
driver.structure->declareObject(*$2, $1->toString()); }

foreachStatement
: FOREACH "("
{ driver.structure->pushNamespace(@2, false); }
loopIndexDeclaration IN rangeExpression ")"
statement %prec THEN
{ driver.structure->pop();
$$ = new IR::ForEachStatement(@1, $4, $6, $8); }
;

// To support direct invocation of a control or parser without instantiation
directApplication
: typeName "." APPLY "(" argumentList ")" ";" {
Expand All @@ -1234,6 +1257,7 @@ statement
: assignmentOrMethodCallStatement { $$ = $1; }
| directApplication { $$ = $1; }
| conditionalStatement { $$ = $1; }
| foreachStatement { $$ = $1; }
| emptyStatement { $$ = $1; }
| blockStatement { $$ = $1; }
| returnStatement { $$ = $1; }
Expand Down
8 changes: 8 additions & 0 deletions ir/dbprint-stmt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,14 @@ void IR::IfStatement::dbprint(std::ostream &out) const {
out << " }" << unindent << setprec(prec);
}

void IR::ForEachStatement::dbprint(std::ostream &out) const {
int prec = getprec(out);
out << Prec_Low << "foreach (" << index << " in " << range << ") {" << indent << setprec(0)
<< Log::endl
<< body;
out << " }" << unindent << setprec(prec);
}

void IR::MethodCallStatement::dbprint(std::ostream &out) const {
int prec = getprec(out);
out << Prec_Low << methodCall << setprec(prec);
Expand Down
36 changes: 36 additions & 0 deletions ir/ir.def
Original file line number Diff line number Diff line change
Expand Up @@ -454,6 +454,42 @@ class IfStatement : Statement {
SplitFlowVisit<Statement>(v, ifTrue, ifFalse).run_visit(); }
}

class ForEachStatement : Statement, ISimpleNamespace {
// This is hack: index is always of length 1, but we use it to simplify the
// construction of the namespace
inline IndexedVector<Declaration> index;
// Another small hack: use PathExpression to capture reference to index.
// This will make it visible to various resolvers and preserve even if
// it is not referenced in the loop body.
PathExpression indexHolder;
Expression range;
Statement body;
IDeclaration getDeclByName(cstring name) const override {
return index.getDeclaration(name); }
Util::Enumerator<IDeclaration>* getDeclarations() const override {
return index.getDeclarations(); }
ForEachStatement(Util::SourceInfo srcInfo,
const IR::Declaration* idx,
const IR::Expression* range, const IR::Statement* body)
: Statement(srcInfo),
indexHolder(new PathExpression(ID(idx->getName()))),
range(range), body(body) {
index.push_back(idx);
validate();
}
ForEachStatement(const IR::Declaration* idx,
const IR::Expression* range, const IR::Statement* body)
: indexHolder(new PathExpression(ID(idx->getName()))),
range(range), body(body) {
index.push_back(idx);
validate();
}

validate {
BUG_CHECK(index.size() == 1, "index must be a single decl");
}
}

class BlockStatement : Statement, ISimpleNamespace, IAnnotated {
optional Annotations annotations = Annotations::empty;
optional inline IndexedVector<StatOrDecl> components;
Expand Down
5 changes: 4 additions & 1 deletion ir/write_context.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,9 @@ bool P4WriteContext::isRead(bool root_value) {
}
}
if (ctxt->node->is<IR::IndexedVector<IR::StatOrDecl>>()) return false;
if (ctxt->node->is<IR::IfStatement>()) return ctxt->child_index == 0;
if (ctxt->node->is<IR::IfStatement>())
if (ctxt->node->is<IR::IfStatement>() || ctxt->node->is<IR::ForEachStatement>())
return ctxt->child_index == 0;
asl marked this conversation as resolved.
Show resolved Hide resolved

return true;
}