-
Notifications
You must be signed in to change notification settings - Fork 444
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
Changes for for loops #4562
Changes for for loops #4562
Conversation
// FIXME -- should we try to directly convert this to a ForStatement in the parser? | ||
class ForInStatement : Statement, ISimpleNamespace { | ||
NullOK Declaration_Variable decl; | ||
// the declaration will be moved to the enclosing block by MoveDeclarations, but |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I do not recall all the details, but iirc the change in MoveDeclarations was necessary for nested loops like + some shadowing:
action a0(bit<8> x, bit<8> y) {
// Reduce
bit<64> idx = -1;
foreach (bit<8> i in 0 .. x) {
foreach (bit<8> j in i .. y) {
idx = foo(j);
if (idx == -1)
break;
}
}
}
4c1b7c7
to
f0c86f8
Compare
@ChrisDodd Consider the following P4 code: bit<64> _popcount(in bit<64> val) {
bit<64> n = 0;
bit<64> v = val;
for (bit<64> popcnti in 1 .. 64w63) {
if (v == 0)
return n;
n = n + 1;
v = v & (v - 1);
}
return n;
} There are two issues with existing PR:
My solution for 1. was factoring out loop index variable and loop container into a separate For 2. I marked all defs in the loop body to be used by loop itself. But maybe you might have some different solution for this issue as you know the underlying code much better than myself :) |
I've added support for loops for frontend DefUse, midend DefUse, midend localCopyprop and general ControlFlowVisitor use. Midend Defuse uses that generic ControlFlowVisitor, but it turned out localCopyprop didn't work properly for that, so it needed an additional stuff -- basically due ti the fact that it did analysis and transform in one pass, it could not use an iterative loop closure, so instead needed one analysis pass of the loop body to remove potential copies that are dependent on the loop body, followed by the normal analysis+rewrite pass to to copyprop into and within the loop body. At this point, the simple test cases I've looked at look good, though it is still giving the spurious "uninitialized variable" for the loop var in for..in loops. There are a number of hacky things in a coupld of places that probably could be done better too. |
I think issue 2 was likely coming from local copyprop -- I've fixed that so it doesn't incorrectly propagate into the loop the first time through. The warning is still an issue I need to look into, though. |
@ChrisDodd Both issues are from |
The warning is coming from FindUninitialized, which does its own flow analysis independent of DefUse (and likewise not using the builting visitor infrastructure for flow analysis), so needs to be updated for loops. But I don't see a problem with the |
Oh, indeed, you are right. I was looking into an old set of dumps. With your latest changes to frontend SimplifyDefUse indeed it is not removed anymore. So, this is a viable solution that could subsume what we are having downstream.
I believe it does use DefUse, e.g. in LOG3("LocationSet for '" << expression << "' is <<" << read << ">>");
auto points = currentDefinitions->getPoints(read);
if (reportUninitialized && !lhs && points->containsBeforeStart() &&
hasUninitializedHeaderUnion(expression, currentDefinitions, read)) {
... Here the points for loop index variable is
hence the warning. My solution was to introduce |
3e0d5e2
to
f1e234b
Compare
@ChrisDodd I am seeing null checks failed at https://github.com/p4lang/p4c/pull/4562/files#diff-6eaf37d31585aaaa76257fcc3f96a3d523ad39cd3adb88a225389df8b60814c8R959:
(line 204 downstream is So, apparently, action a0(bit<8> x, bit<8> y) {
bit<64> idx = -1;
for (bit<8> i1 in 0 .. x) {
for (bit<8> j in i1 .. y) {
idx = foo(j);
if (idx == -1)
break;
}
}
} |
f003fa6
to
101e00d
Compare
I don't see any Compiler Bugs with this code but I do see spurious "maybe uninitialized" warnings for i1 and j -- turns out there was a small bug in def_use for ForInStatements setting reachable defs for the body of the loop (was unioning in the state from before the loop, which should only be done for after the loop, not the loop body itself), and I'd missed a place in FindUninitialized setting the current point after the condition in ForIn loops. Things would be much simpler if these passes used the ControlFlowVisitor infrastructure which handles all this in one place, rather than having to reimplement it for every pass. I've added your two testcase here, but more testcases would be nice |
Let me see what I'm having downstream. I cannot submit them directly as they use private packages, etc. So, I will extract one-by-one |
Here are the tests: bit<8> foo(in bit<8> aa, in bit<8> bb) {
// Do some magic to ensure aa / bb will not be simplified
return aa - bb;
}
action a0(bit<8> x, bit<8> y) {
// Simple loops: with and w/o use of index variable.
foreach (bit<8> i in 1 .. (x+y)) {
foo(x, y);
}
foreach (bit<8> i in 1 .. (x+y)) {
foo(x, y + i);
}
// And with constant range as well
foreach (bit<8> i in 8w1 .. 42) {
foo(x, y + i);
}
}
action a1(bit<8> x, bit<8> y) {
// Nested loops
foreach (bit<8> i in 1 .. x) {
foreach (bit<8> j in i .. y)
foo(x, y + i);
}
}
// Scope test
action a2(bit<8> x, bit<8> y) {
bit<8> i = 10;
foreach (bit<8> i in 1 .. x) {
foo(x, y + i);
}
foreach (bit<8> k in i .. (x+y)) {
foo(i, 2*i+x);
}
} Same as action a1(bit<8> x, bit<8> y) {
bit<64> idx = -1;
foreach (bit<8> i in 0 .. x) {
foreach (bit<8> j in 0 .. y) {
idx = foo(j);
if (idx == -1) {
continue;
}
idx = foo(i);
}
}
} I am afraid all other testcases are much tighter integrated downstream |
Have you pushed these fixes? I do see only tests were added... |
101e00d
to
79cc132
Compare
Ok, there were some more issues with the flow analysis over loops that wer breaking the forloop2 test, so I've fixed that too. Flow analysis over loops is non-trivial with a bunch of corner cases, so it is particularly good to have it in one place in the infrastructure rather than having to reimplement it for every visitor. |
325675f
to
7be3fc9
Compare
I'm still working on code to unroll loops to support targets that don't support loops natively, but this is already a pretty large change and has all the necessary support for targets that do suppoert loops. |
So loops in an action like this:
where the loop count depends on an action data parameter (rather than a constant) can't be easily bounded (other than by the possible range of the type, so 255 here), so don't seem to fit in with the intent of p4lang/p4-spec#1261 or #4120. However, they do seem fine with general loops, which this PR supports. Unrolling this loop seems impractical, and would really require a different action for each possible loop count, deciding on which one to use based on the actual parameter value of any particular entry. |
- 'for' instead of 'foreach' in comments/error messages - fix constant in loop-visitor
- flow state after loop needs to be union of state after the condition check (not bottom of loop) and all break states. - condition of for..in is before setting index var
- only handles simple for v in k1..k2 loops; general for TBD
b4564ce
to
2786a46
Compare
- allow more patterns of tests and increments - deal properly with updates in the presence of break&continue - single test to skip rest of loop after break rather than rechecking the flag every time. - remove redundant inits of flags
bcedfe3
to
fa3380d
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi, @ChrisDodd. I was wondering what compiler you've used to compile the examples you provided (e.g., ./testdata/p4_16_samples/forloop1.p4) since it's apparent that ”BMV2 does not support loops” (so I assume that p4c-bm2-psa and p4c-bm2-ss won’t work). Thanks!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The p4test compiler compiles these loops
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for clarifying!
Pulling together changes from #4120 and #4558 for for loops