Inefficient code generation for u8 -> boolean conversion if bounds check already applied #121673
Labels
A-LLVM
Area: Code generation parts specific to LLVM. Both correctness bugs and optimization-related issues.
C-bug
Category: This is a bug.
C-optimization
Category: An issue highlighting optimization opportunities or PRs implementing such
S-has-mcve
Status: A Minimal Complete and Verifiable Example has been found for this issue
T-compiler
Relevant to the compiler team, which will review and decide on the PR/issue.
This occurs both on the latest stable and nightly with both
-C opt-level=2
and-C opt-level=3
, and looking back some versions this has been going on for quite a while, so this is not a regression AFAIK. Consider the following piece of code:I would expect that in a release build, the above code loads the u8, checks if it is a legal value for a bool, and if so return it, otherwise going to
something_dynamic()
. The motivation for this piece of code is something similar to aOnceLock<bool>
in an incredibly hot piece of code. Ideally the hot path only consists of a singlemov
,cmp
andjmp
. Compiled we see the following:It appears that Rust always emits code for turning an
u8
into abool
(cmp al, 1
followed bysete al
), regardless of whether this is necessary. In this case, since we checked that theu8
is<= 1
, this is not necessary at all. The same problem occurs on ARM:The problem even persists if we try to use transmute, or pointer casts to bypass the problem. All the following variants still cause a superfluous value test:
The weirdest thing is that this pessimization only occurs when there is a bounds check already applied. The following function avoids a test, directly loading the byte:
However, if you try to implement
test
in terms ofmaybe_load
, it gets inlined and the uselesscmp, sete
is back.The text was updated successfully, but these errors were encountered: