Ignore ALWAYS_ABORT_FLAG in count_is_zero fast path #106197
Closed
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Based on the assumption that always_abort usage is uncommon, change the count_is_zero() fast path to only check if GLOBAL_PANIC_COUNT is not zero, ignoring ALWAYS_ABORT_FLAG. This improves code generation for the fast path, since it no longer has to mask off the flag first.
This has a small but potentially widespread impact on code quality and size, since panicking::count_is_zero() is inlined at each Mutex lock and unlock call site.
Small test case that shows the improvement:
Code generation without this change (rustc 1.67.0-nightly (2585bce 2022-11-28) on x86_64 Linux (trimmed to just the fast path to highlight the changes):
The compiler backend is clever and optimizes the
& !ALWAYS_ABORT_FLAG
check into ashl ..., 1
to shift away the top bit in the lock fast path, but for some reason doesn't apply the same optimization in the unlock path (it emits amovabs
instruction with a large0x7fffffffffffffff
immediate to mask off the flag bit instead). In either case, omitting the flag check avoids an instruction or two in the critical path.With this change applied:
With this patch applied, the inlined
panicking()
function's fast path is now a load + test reg, reg + conditional jump in both the lock and unlock path.My assumption is that use of
panic::always_abort()
(#84438) is uncommon and performance is not as important in cases where it has been set; if that's not accurate, maybe this change is not a good idea, since it pessimizes the always_abort case (making it always read the thread-local panic count instead).