Skip to content
Open
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
31 changes: 31 additions & 0 deletions p4-16/spec/P4-16-spec.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -5872,6 +5872,8 @@ element in a list expression, array or header stack. The list or range expressi
will only be evaluated once, before the first iteration of the loop. All side effects
in the list or range expression will occur before the first iteration of the loop body.

Instantiations are not allowed within `for` statements.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I'm not sure if this is necessary, or is opening another can of worms -- generally, instantiations happen at compile time/config time, so are not allowed in constructs that run at runtime (apply blocks, actions, or functions). But loops are (currently) only allowed in those places (so run at runtime). We don't have a good description of this elsewhere, however.

@jaehyun1ee jaehyun1ee Feb 24, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Yes, it indeed opens another can of worms. It is generally true that loops are allowed in apply blocks, actions, or functions that are (conceptually) irrelevant to instantiation.

The tricky case is directApplication within statement:

statement
    : assignmentOrMethodCallStatement
    | directApplication (* this! *)
    | conditionalStatement
    | emptyStatement
    | blockStatement
    | returnStatement
    | exitStatement
    | switchStatement
    ;

Direct application is a syntactic sugar for instantiation + apply invocation. And if we have such within a loop (which is syntactically allowed as per the grammar):

for (bit<8> i = 0; i < 8; i ++) {
   subcontrol.apply();
}

There is no way to statically give unique control-plane names to each of the instances made within the loop.

But also seems like a more general discussion should be made on a separate issue, regarding directApplication, since they may also be nested within conditionalStatements.

if (... some non-trivial condition ...) subcontrol.apply();
else subcontrol.apply();


A `break;` statement may be executed in a loop body to immediately exit the loop,
without executing the rest of the body or the update statements.

Expand All @@ -5881,6 +5883,35 @@ either execute the loop body again, or terminate the loop.

The scope of any declaration in a `for` statement is limited to the `for` statement and its body.

==== Bounded for statement

A P4 implementation may support a bounded version of `for` statements with stronger syntactic constraints instead of general `for` statements to ensure its boundedness statically.

This is intended to be a _minimal_ subset of bounded `for` statements. A P4 implementation that supports bounded `for` statements may choose to implement a larger subset; furthermore, it may reject a `for` statement if its bound is too large, even if it is statically bounded.

[source,bison]
----
include::grammar.adoc[tag=boundedForStatement]

include::grammar.adoc[tag=boundedForInitStatement]

include::grammar.adoc[tag=boundedForCondExpr]

include::grammar.adoc[tag=boundedForUpdateStatement]
----

`for`-`in` statements remain the same as general `for`-`in` statements as a `forCollectionExpr` always contains finitely many values. However, 3-clause `for` statements are not guaranteed to be bounded in general. The following constraints are added to bounded 3-clause `for` statements:

- Only one variable is mentioned in the initialization statement, condition expression, and the update statement. We call this variable the "loop variable". The type of the loop variable must be `bit<W>` or `int<W>`.
- The condition expression must be a binary expression `i < n` where `i` is the loop variable and `n` is a local compile-time known value.
- There is only one update statement, which must be an assignment statement `i += c` where `i` is the loop variable and `c` is a positive local compile-time known value.
- Referring to `n` and `c` above, the sum `n + c` should not overflow with respect to the type of the loop variable.
- The loop variable is a read-only variable within the loop body and the condition expression. It can only be overwritten by the update statement.

The above constraints guarantee boundedness since the loop variable monotonically increases and has an upper bound.

The runtime semantics of bounded `for` statements are the same as general `for` statements.

[#sec-packet-parsing]
== Packet parsing

Expand Down
27 changes: 27 additions & 0 deletions p4-16/spec/grammar.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -926,6 +926,33 @@ forCollectionExpr
;
// end::forCollectionExpr[]

// tag::boundedForStatement[]
forStatement
: optAnnotations FOR "(" boundedForInitStatement ";" boundedForCondExpr ";"
boundedForUpdateStatement ")" statement
| optAnnotations FOR "(" typeRef name IN forCollectionExpr ")" statement
| optAnnotations FOR "(" annotations typeRef name IN forCollectionExpr ")" statement
;
// end::boundedForStatement[]

// tag::boundedForInitStatement[]
boundedForInitStatement
: typeRef name "=" initializer
;
// end::boundedForInitStatement[]

// tag::boundedForCondExpr[]
boundedForCondExpr
: name '<' expression
;
// end::boundedForCondExpr[]

// tag::boundedForUpdateStatement[]
boundedForUpdateStatement
: name "+=" INTEGER
;
// end::boundedForUpdateStatement[]

/************************* TABLE *********************************/

// tag::tableDeclaration[]
Expand Down