-
Notifications
You must be signed in to change notification settings - Fork 445
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
More questions on setInvalid #2323
Comments
I agree this is unsound. It is only safe to propagate an equality |
When an input program has some undefined values/behavior involved, is it a goal of a compiler to "preserve" as much of the undefined values/behavior as exist in the input program? I would have thought that it is acceptable for a compiler to eliminate some of the undefined behavior, as long as the resulting possible behaviors of the output program are a subset of the possible behaviors of the input program. At least, it seems from the examples in the original comment that the behaviors of the compiler's resulting program are a subset of the behaviors of the input program. |
In general, you're right. End-to-end, the entire compiler is free to generate an implementation that is a refinement the semantics of the input program. And there are lots of places in the spec where we give significant freedom to architectures and specific implementation to make decisions -- e.g., about what happens with reads and writes to invalid headers. On the other hand, it seems problematic for the front-end of the |
As long as this behavior is one of the "undefined" ones mandated by the spec I think it's correct. |
Sure. The spec says that reading a field in an undefined header can return any value, and even a different value from one read to the next. I wrote unsound above and maybe that's too strong. If I were a backend compiler writer, I might expect the front-end to not tie my hands. Anyway, hopefully we agree it will be difficult-to-impossible for any compilers built on |
Thanks! So, to summarize that I get the semantics right. When On the other hand, what happens when `setValid´ is called? I am seeing two cases:
Which case is more in line with the spec? Case 2? |
The spec says that reads to a field in an invalid header or where the field has not yet been initialized may return an arbitrary value. Writing to an invalid header may not change any of the defined state in the program -- e.g., making invalid headers valid or changing fields in valid headers. So both semantics are in line with the spec. The front-end is optimizing with a particular semantics in various places. |
Okay, thank you, that makes sense. I will go with the first option then. |
If If p4c could guarantee that a header was invalid at the time of an assignment to one of its fields, it seems perfectly reasonable to me to (a) warn the user that this is a no-op according to the language spec, and on some non-spec-conforming implementations may do much worse things, and (b) eliminate the assignment. One can easily write a P4 program containing assignments to header fields where it is impossible to determine at compile time whether the header is valid at that time, or not, because that valid/invalid status can only be determined at run time (e.g. the control flow before that time could have branches where one leaves the header valid, and other branches that leave the header invalid, and the condition of the branch is a run-time input to the program, e.g. another field of an input packet, or the contents of a control-plane-written table entry). For an assignment where it cannot be determined at compile time whether the header is valid or invalid (or that the compiler did not implement a complete enough check to determine it, even if there was enough information at compile time to do so), it isn't clear to me what a P4 compiler front end is allowed to do as far as transformations or optimizations, if you want to maximally preserve undefined behavior. Maybe no such transformations should be allowed, if that is the goal? I am not clear what you mean in your point #2 "it is up to the programmer or the backend developer to make sure the values after the |
In essence, I had a little bit of trouble consolidating the transformations in the front-end with target-specific interpretations of For example, looking at this sequence of operations:
the outcome may either be
The front-end assumes the third case and removes all assignments preceding I just had to pick semantics that are consistent across each compiler pass and do not produce false positives, which rules out interpretation 1 and 2. Because I would also like to perform automatic test case generation for bmv2, I can not use interpretation 3, which leaves interpretation 4 (also okay as @jnfoster said). |
The frontend is assuming "soon as a field in an invalid header is written to, the header becomes valid". I think this is incorrect because unless all fields of the header are written to or initialized to zero, the header should not change to valid. Should the spec make such a clarification? |
According to the spec, interpretation #4 is correct, I believe, but as a reason I would not give " Rather, I would say that initially all headers have undefined field values, and have valid=false. If you ever do bmv2 simple_switch does not represent "undefined" as a specific value. One could imagine a modified version of simple_switch that did have an explicit "undefined" value for a field, but that isn't what it does today. It seems the best one can do is if you have some kind of validation tool that expects a field value to be undefined, do not do any kind of checking on its bmv2 simple_switch value at all, since it might be anything. |
Regarding a backend for an asic, no value should be undefined for hardware. I have worked with the MIPS Tensilica compiler for a router asic where the compiler initializes any C code var, if not initialized, to zero. Why doesn't the bmv2 simple_switch backend mimic the asic hardware which does not allow any un-initiazlied var? |
@hesingh In the context of the language specification, a header value being undefined does not mean that there must be some special magical "undefined" value that is different than the other values for a field with type In the context of the spec, undefined means the implementation can return any of those 256 possible values when you read it, and you cannot predict which one, unless you know something about the specific implementation that you work with. An implementation is allowed to return a pseudo-random value each time you read an undefined value, or always 0, or the value you most dread it will read. |
@jafingerhut I see, thanks for the clarification. |
@jafingerhut
will generate the following stf test: packet 0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
expect 0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ** 02 ** |
A note of explanation on the simple_switch behavior. p4c translates
Ideally, we should have a |
@fruffy Is it reasonable to close this issue now? |
I left this open because of Antonin's comment but I do not think we will ever implement this primitive. So this can be closed. |
Hello.
I have another clarification question on
setInvalid
, this is a follow-up to #2212.This issue is quite esoteric but has given me some trouble recently.
So for a program like this:
the
LocalCopyPropagation
pass collapses the values intoh.eth_hdr
is a valid header and its value is now always16w2 * h.eth_hdr.eth_type
after the pass instead of being undefined. However, since the alternative is undefined behaviour does it matter? The only case I can think of where this may affect the output is something likewhich is eventually turned into
because the assumption is that
h.eth_hdr.src_addr
is always1
.There may be undefined cases where the inequality is true, however. Or can this be treated as a case where all bets are off?
strange_set_valid.p4.txt
strange_set_valid.stf.txt
The text was updated successfully, but these errors were encountered: