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 all commits
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
13 changes: 13 additions & 0 deletions frontends/p4/validateParsedProgram.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -251,4 +251,17 @@ void ValidateParsedProgram::postorder(const IR::Dots *dots) {
}
}

/// Check that continue and break statements are only used in the context of a foreach statement
void ValidateParsedProgram::postorder(const IR::BreakStatement *s) {
if (!findContext<IR::ForEachStatement>())
::error(ErrorType::ERR_INVALID,
"%1%: break statement must be used in the context of a foreach statement.", s);
}

void ValidateParsedProgram::postorder(const IR::ContinueStatement *s) {
if (!findContext<IR::ForEachStatement>())
::error(ErrorType::ERR_INVALID,
"%1%: continue statement must be used in the context of a foreach statement.", s);
}

} // namespace P4
3 changes: 3 additions & 0 deletions frontends/p4/validateParsedProgram.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ namespace P4 {
- names of all parameters are distinct
- no duplicate declarations in toplevel program
- Dots are the last field
- continue and break statements are only used in the context of a foreach statement
*/
class ValidateParsedProgram final : public Inspector {
void container(const IR::IContainer *type);
Expand Down Expand Up @@ -89,6 +90,8 @@ class ValidateParsedProgram final : public Inspector {
parser->getConstructorParameters());
}
void postorder(const IR::Dots *dots) override;
void postorder(const IR::BreakStatement *s) override;
void postorder(const IR::ContinueStatement *s) override;
};

} // namespace P4
Expand Down
6 changes: 6 additions & 0 deletions frontends/parsers/p4/p4lexer.ll
Original file line number Diff line number Diff line change
Expand Up @@ -115,8 +115,12 @@ using Parser = P4::P4Parser;
return makeToken(BOOL); }
"bit" { BEGIN(driver.saveState); driver.template_args = true;
return makeToken(BIT); }
"break" { BEGIN(driver.saveState); driver.template_args = false;
return makeToken(BREAK); }
"const" { BEGIN(driver.saveState); driver.template_args = false;
return makeToken(CONST); }
"continue" { BEGIN(driver.saveState); driver.template_args = false;
return makeToken(CONTINUE); }
"control" { BEGIN(driver.saveState); driver.template_args = false;
return makeToken(CONTROL); }
"default" { BEGIN(driver.saveState); driver.template_args = false;
Expand All @@ -135,6 +139,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
34 changes: 34 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 BREAK CONTINUE
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is structured in a way to simplify review. It could be merged into the token list above


%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::Range*> rangeExpression
%type<IR::Statement*> foreachStatement breakStatement continueStatement

// %precedence COMMA
%precedence QUESTION
Expand Down Expand Up @@ -558,7 +562,9 @@ annotationToken
| APPLY { $$ = $1; }
| BOOL { $$ = $1; }
| BIT { $$ = $1; }
| BREAK { $$ = $1; }
| CONST { $$ = $1; }
| CONTINUE { $$ = $1; }
| CONTROL { $$ = $1; }
| DEFAULT { $$ = $1; }
| ELSE { $$ = $1; }
Expand All @@ -568,6 +574,7 @@ annotationToken
| EXIT { $$ = $1; }
| EXTERN { $$ = $1; }
| FALSE { $$ = $1; }
| FOREACH { $$ = $1; }
| HEADER { $$ = $1; }
| HEADER_UNION { $$ = $1; }
| IF { $$ = $1; }
Expand Down Expand Up @@ -1216,6 +1223,32 @@ 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()); }

breakStatement
: BREAK ";" { $$ = new IR::BreakStatement(@1); }
;

continueStatement
: CONTINUE ";" { $$ = new IR::ContinueStatement(@1); }
;

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 +1267,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
46 changes: 46 additions & 0 deletions ir/ir.def
Original file line number Diff line number Diff line change
Expand Up @@ -454,6 +454,52 @@ class IfStatement : Statement {
SplitFlowVisit<Statement>(v, ifTrue, ifFalse).run_visit(); }
}

class BreakStatement : Statement {
toString{ return "break"; }
dbprint { out << "break"; }
}

class ContinueStatement : Statement {
toString{ return "continue"; }
dbprint { out << "continue"; }
}

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;
Range 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::Range *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::Range *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
4 changes: 3 additions & 1 deletion ir/write_context.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,8 @@ 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>() || ctxt->node->is<IR::ForEachStatement>())
return ctxt->child_index == 0;

return true;
}
Loading