zero_alloc: fix treatment of caml_flambda2_invalid#2112
zero_alloc: fix treatment of caml_flambda2_invalid#2112gretay-js merged 6 commits intooxcaml:mainfrom
Conversation
but will hopefully prevent us from running into this bug again when we add new properties.
for zero_alloc checking, pretend this extcall returns, otherwise it gets eliminated and the check is not sound.
3965232 to
45591db
Compare
|
It doesn't seem that this is the right fix: if the simplified body of the function contains a flambda2 Considering that an flambda2 |
even if the function is unreachable/dead/inlined away, then we still want to check its (original) body if the function was unnotated with
thanks! @mshinwell had an explanation, which I don't fully understand. |
|
Ok, so after a bit more debugging, the main problem is the following:
My opinion on all that is that we should try and find a more proper way to keep the code alive (since there will always be the possibility of a new analysis that could see the code as dead and make optimisations based on that) that would also be easily erasable to as to not have any runtime cost in the generated program. |
|
@Gbury You analysis sounds similar to what Mark said. We should consider moving zero_alloc check earlier (to flambda2) after removing flambda1 and closure. In the meantime, I believe this PR improves the usability of zero_alloc analysis and the code seems no worse than the existing hack. |
|
If moving the analysis to operate on flambda2 is possible (now that flambda1 and closure are no more), that would certainly avoid having to hack things in flambda2 to keep those alive. In the meantime, the fix should be okay, at least concerning the invalids generated by |
45591db to
8ec6f17
Compare
Can we do the equivalent of |
|
@Gbury said
This is a nice property, with it we don't need this PR at all and we don't need to fix anything, but I'm not sure if it does what users expect in the presence of code changes. Consider a situation where the check starts failing on an annotated function whose code hasn't changed but a new call to this function was added or even worse - completely unrelated new code was added that uses a previously-unused slot in the sets of closures. It would make the check fail (correctly) but can be hard to debug for the user |
I don't know if it makes the debugging harder, but it sure makes the appearance of the warning/error quite surprising/puzzling. That being said, I don't expect that to happen in real cases, because to get to that situation, you have to have a function for which every use is dead code, so the function is completely dead: not exposed in any interface and every use of it is also dead code. In such a case, it could even make sense to emit a dedicated dead code warning, because that seems very much like a programming error (or a compiler error). Also, note that the invariant I describe above is true when considering the flambda2 code, but since |
This hack was introduced before we started propagating "zero_alloc assume" information as part of Debuginfo from |
|
@Gbury if you are okay with this approach for now, can you please review and approve the PR? |
xclerc
left a comment
There was a problem hiding this comment.
I agree with others that this does
not appear like a good long-term
solution. For this particular check,
I think my preference would be to
have a principled way of keeping
the function closer to its original
form until we perform the check.
Approving as a temporary workaround.
Fixes a soundness problem in zero_alloc checking.
It turns out that
zero_allocannotations are ignored in some cases on functions that became dead because all calls to them were inlined (the functions themselves are not deleted, thanks to #1378). The culprit isreturns=falsefield of theextcalltocaml_flambda2_invalid, which is sometimes inserted by flambda2 in dead code. It allowsselectgento eliminate the rest of the code of the function, including any allocations, sozero_alloccheck that runs later on does not report an error. However, the inlined copy of these allocatons may not have been eliminated. This is not sound: the user expects that if the original function iszero_allocthen its inlined copies have no allocations.The fix is to pretend that a call to
caml_flambda2_invalidreturns when it appears inside a function annotated with[@zero_alloc]. This is done inselectgenbut can probably be done earlier.Here is an example (can probably be simplied):
The inner function
unsafe_set_int64allocates (it contains anallocand anextcalltocaml_ba_set_1that is not marked as@noalloc):but
zero_alloccheck used to succeed because the above cmm code was compiled to: