-
Notifications
You must be signed in to change notification settings - Fork 12.2k
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
Missed optimization: nonnull assumptions cannot reason over select #48319
Comments
assigned to @aqjune |
I believe the lack of an passingValueIsAlwaysUndefined()-style optimization for select came up in recent SimplifyCFG patch as well. Though here the desired semantics would be more along the lines of passingValueIsAlwaysPoison(), so as to cover the nonnull attribute case as well. |
Would it make sense if the optimization we'd like to implement goes into InstCombine? |
https://reviews.llvm.org/D96663 BTW, is it okay to return an uninitialized value or pass such value to a function argument if 'unsafe' keyword is used in Rust? If it is UB, it might be a good idea to attach noundef attributes to the return value and function arguments from the Rust side. It will bring more optimization opportunities to LLVM. |
Thanks a lot! That was quick. With the current semantics, AFAIK, all variables are assumed to be properly initialized, including parameters and return values. This is true regardless of So yeah, Rust is able to use |
It should be fixed now. Can you reproduce the fix? |
Compiler Explorer has not picked up yet the new HEAD, I will confirm the fix as soon as that happens. |
The compiler test added works in CE: https://godbolt.org/z/1vcj63xc8 As soon as By the way, what about the reduced example in the top? i.e.
|
Starting with |
Thanks for confirming. I'm closing the issue now, please feel free to reach out in case there's still an issue. |
It's nothing! There is the pending question about the reduced example, but perhaps it should go into a new issue:
|
Extended Description
LLVM fails to optimize:
into:
which Alive2 confirms as valid (i.e. return type is nonnull => %4 is nonnull => the second branch of select was taken => %4 is %3).
Uncommenting the explicit assume (instead of relying on the nonnull return attribute) doesn't help either. However, providing the assume directly on %2 or a !nonnull on the load both work:
Thus it would seem like LLVM is not realizing that if %4 is nonnull, then the select must come from the false branch, which implies %1 is false.
This is a reduction from Rust code such as:
There, the unwrap_unchecked() provides the nonnull assumption, while as_mut() generates the select. However, if one manually expands the Rust code, LLVM finds the optimization, though:
because this ends up at:
i.e. the branch on %7 (after the select) is transformed into a branch on %4 (before the select).
However, when Rust code uses unwrap_unchecked() and similar functions, LLVM optimizes those first, then integrates, but by then the branches aren't there anymore (similar to what is shown in the reduction), and the optimization above does not take place. Then, since it cannot reason over the select, the suboptimal code is generated.
In Rust, using macros instead of functions for those that contain unreachable() hints can be a workaround.
The text was updated successfully, but these errors were encountered: