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

Do not print confusing warning when a parser state contains an assignment to an l-value slice #4948

Merged
merged 4 commits into from
Oct 12, 2024

Conversation

kfcripps
Copy link
Contributor

@kfcripps kfcripps commented Oct 7, 2024

I don't think it makes sense to print a warning about an l-value being uninitialized when either the entire l-value or a slice of said l-value is written to.

On main branch, the added P4 program results in:

$ p4test tmp.p4 --dump t --loopsUnroll
tmp.p4(9): [--Wwarn=uninitialized_use] warning: s.f may be uninitialized
        s.f[3:0] = 2;
        ^^^
tmp.p4(9): [--Wwarn=ignore-prop] warning: Result of 's.f[3:0] = 4w2' is not defined: Error: Uninitialized
        s.f[3:0] = 2;
                 ^

and on this branch:

$ p4test tmp.p4 --dump t --loopsUnroll
tmp.p4(9): [--Wwarn=uninitialized_use] warning: s.f may be uninitialized
        s.f[3:0] = 2;
        ^^^

Ideally both warnings would be gotten rid of, but I don't know how to get rid of the first one, and the second one is the most confusing to me. This is at least an improvement over the previous behavior. I am open to suggestions if anyone has any ideas of how to get rid of the first warning also.

@kfcripps kfcripps added the core Topics concerning the core segments of the compiler (frontend, midend, parser) label Oct 7, 2024
@kfcripps kfcripps requested review from asl, ChrisDodd and fruffy October 7, 2024 16:46
@kfcripps kfcripps force-pushed the fix-parser-slice-assignment-warning branch 2 times, most recently from c0fa2d6 to 364b582 Compare October 7, 2024 17:10
Comment on lines +10 to +12
parser-unroll-uninitialized-slice-read.p4(5): [--Wwarn=ignore-prop] warning: Result of 'g = f[3:0]' is not defined: Error: Uninitialized
g = f[3:0];
^
Copy link
Contributor Author

Choose a reason for hiding this comment

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

The fact that this warning is worded this way is not great - I opened #4945 to improve this and similar warnings

@fruffy
Copy link
Collaborator

fruffy commented Oct 8, 2024

It makes sense to print a warning if only parts of the lvalue are written to but I agree, if we are assigning to the whole slice this warning is unnecessary.

On that note, which passes require this interpreter? It is rather hard to maintain and produces lots of confusing warnings like this one.

@fruffy
Copy link
Collaborator

fruffy commented Oct 8, 2024

The warning itself occurs in the parserUnroll pass. I think to get rid of it you need to insert some logic to check that the slice being assigned properly. We can also fix the warning there.

@kfcripps
Copy link
Contributor Author

kfcripps commented Oct 9, 2024

It makes sense to print a warning if only parts of the lvalue are written to but I agree, if we are assigning to the whole slice this warning is unnecessary.

Can you elaborate why it makes sense to emit an "uninitialized" warning when even a partial slice is written? My motivation for this PR is that no warning should even be emitted in this case.

Why should writing to an uninitialized field slice be treated any differently than writing to an uninitialized whole field, which results in no such warning?

On that note, which passes require this interpreter? It is rather hard to maintain and produces lots of confusing warnings like this one.

My understanding is that it is used by the ParsersUnroll pass, but I am not very familiar with this pass and not sure at this moment how to improve these warnings.

The warning itself occurs in the parserUnroll pass. I think to get rid of it you need to insert some logic to check that the slice being assigned properly. We can also fix the warning there.

Are you referring to the "s.f may be uninitialized" or "Result of 's.f[3:0] = 4w2' is not defined: Error: Uninitialized" warning? The SimplifyDefUse pass is responsible for the former, and ParsersUnroll for the latter.

@fruffy
Copy link
Collaborator

fruffy commented Oct 9, 2024

Can you elaborate why it makes sense to emit an "uninitialized" warning when even a partial slice is written? My motivation for this PR is that no warning should even be emitted in this case.

Well, this was assuming the warning makes sense at all and there was a particular motivation why it was put there for an assignment statement. In the case of a partial write, there are still some uninitialized bits which could have unpredictable values.

My understanding is that it is used by the ParsersUnroll pass, but I am not very familiar with this pass and not sure at this moment how to improve these warnings.

I think there is no one left that understands this pass but it might make sense to change the success criterion here: https://github.com/p4lang/p4c/blob/main/midend/parserUnroll.cpp#L470

Are you referring to the "s.f may be uninitialized" or "Result of 's.f[3:0] = 4w2' is not defined: Error: Uninitialized" warning? The SimplifyDefUse pass is responsible for the former, and ParsersUnroll for the latter.

The latter, although I also assumed that this pass triggered SimplifyDefUse in some form. If that pass is throwing the warning we should fix probably fix it because it is a much more commonly used pass.

@kfcripps
Copy link
Contributor Author

kfcripps commented Oct 10, 2024

Well, this was assuming the warning makes sense at all and there was a particular motivation why it was put there for an assignment statement. In the case of a partial write, there are still some uninitialized bits which could have unpredictable values.

The point of this PR is that I don't believe this warning makes sense at all. Yes, a read of a potentially uninitialized slice should result in a warning, but a warning for a write to such slice is useless. You can see from the attached tests that the latter now results in no warning, but the former still does result in a warning.

Furthermore, I have found no evidence in the code or in the history that this warning was intentionally added. It seems more likely to be an oversight to me (the author of ExpressionEvaluator::postorder(const IR::Operation_Ternary *expression) could have forgotten that an IR::Operation_Ternary can be an IR::Slice on the LHS of an assignment).

I think there is no one left that understands this pass but it might make sense to change the success criterion here: https://github.com/p4lang/p4c/blob/main/midend/parserUnroll.cpp#L470

Is there a particular reason that modifying the success criterion here is preferable to the changes I have made to ExpressionEvaluator::postorder(const IR::Operation_Ternary *expression) in this PR?

The latter, although I also assumed that this pass triggered SimplifyDefUse in some form. If that pass is throwing the warning we should fix probably fix it because it is a much more commonly used pass.

To my knowledge ParsersUnroll and SimplifyDefUse are unrelated, and SimplifyDefUse is only called at the top-level from frontend.cpp. If you have a concrete suggestion on how to fix the similar warning in SimplifyDefUse, I will try it, but otherwise I'd prefer to merge this PR first and address this other warning in a different PR.

Copy link
Collaborator

@fruffy fruffy left a comment

Choose a reason for hiding this comment

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

My main concern is understanding how or what it even means in the interpreter to evaluate an lvalue in postorder here. Is that even supposed to happen? I think your solution is fine but it might be more of a band-aid.

It makes sense to handle this warning on higher-levels, e.g., in the parserUnroll pass, which is throwing an error on resolving an lvalue.

The reason I am concerned about SimplifyDefUse is that it has a different logic but is throwing the same type of error.

return;
// This cannot be an uninitialized read if 'expression' is the LHS of
// an assignment to a sliced l-value.
if (!evaluatingLeftValue) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

I would throw a BUG if the value is an lval and the ternary is not a slice. To make sure we do not end up in weird states.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

@kfcripps
Copy link
Contributor Author

kfcripps commented Oct 11, 2024

My main concern is understanding how or what it even means in the interpreter to evaluate an lvalue in postorder here. Is that even supposed to happen? I think your solution is fine but it might be more of a band-aid.

It makes sense to handle this warning on higher-levels, e.g., in the parserUnroll pass, which is throwing an error on resolving an lvalue.

In theory, I think an error may still occur when evaluating LHS in other cases. For example, an assignment to an ArrayIndex in which the index is uninitialized (for example, a[x] = rhs; where x is uninitialized). Another example is an assignment to a PlusSlice, for example a[x+:y] = rhs, where x in uninitialized. In both cases, the LHS expression actually reads uninitialized data (unlike with LHS Slice expressions), so the warning would be valid. I don't think a SymbolicStaticError is created in either of these cases currently, and I don't know the pass well enough to know if they should result in a SymbolicStaticError, but my guess is that they should and that it probably should be propagated up to executeStatement where IR::Assignment is handled.

@kfcripps kfcripps force-pushed the fix-parser-slice-assignment-warning branch from 5c6884a to a24abc9 Compare October 11, 2024 22:51
…ment to an l-value slice

Signed-off-by: Kyle Cripps <kyle@pensando.io>
Signed-off-by: Kyle Cripps <kyle@pensando.io>
Signed-off-by: Kyle Cripps <kyle@pensando.io>
Signed-off-by: Kyle Cripps <kyle@pensando.io>
@kfcripps kfcripps force-pushed the fix-parser-slice-assignment-warning branch from a24abc9 to ede58b6 Compare October 11, 2024 23:46
@kfcripps kfcripps enabled auto-merge October 11, 2024 23:46
@kfcripps kfcripps added this pull request to the merge queue Oct 12, 2024
Merged via the queue into p4lang:main with commit 88a4ae8 Oct 12, 2024
17 of 18 checks passed
@kfcripps kfcripps deleted the fix-parser-slice-assignment-warning branch October 12, 2024 01:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
core Topics concerning the core segments of the compiler (frontend, midend, parser)
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants