-
Notifications
You must be signed in to change notification settings - Fork 14.1k
Open
Labels
A-LLVMArea: Code generation parts specific to LLVM. Both correctness bugs and optimization-related issues.Area: Code generation parts specific to LLVM. Both correctness bugs and optimization-related issues.C-optimizationCategory: An issue highlighting optimization opportunities or PRs implementing suchCategory: An issue highlighting optimization opportunities or PRs implementing suchE-needs-testCall for participation: An issue has been fixed and does not reproduce, but no test has been added.Call for participation: An issue has been fixed and does not reproduce, but no test has been added.I-slowIssue: Problems and improvements with respect to performance of generated code.Issue: Problems and improvements with respect to performance of generated code.T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.Relevant to the compiler team, which will review and decide on the PR/issue.
Description
Godbolt link
When a NonZeroUsize is created through new_unchecked and wrapped in a Some, the optimizer does not recognize that the value is always Some. This can be fixed by adding a std::intrinsics::assume(value != 0) line before creating the NonZero type.
use std::num::NonZeroUsize;
use std::sync::atomic::AtomicUsize;
use std::sync::atomic::Ordering::Relaxed;
pub static X: AtomicUsize = AtomicUsize::new(1);
pub unsafe fn get() -> Option<NonZeroUsize> {
let x = X.load(Relaxed);
Some(NonZeroUsize::new_unchecked(x))
}
pub unsafe fn get2() -> usize {
match get() {
Some(x) => x.get(),
None => unreachable!(), // not optimized out
}
}Lots of panicking code gets generated in this example.
Fixed by:
#![feature(core_intrinsics)]
use std::num::NonZeroUsize;
use std::sync::atomic::AtomicUsize;
use std::sync::atomic::Ordering::Relaxed;
pub static X: AtomicUsize = AtomicUsize::new(1);
pub unsafe fn get() -> Option<NonZeroUsize> {
let x = X.load(Relaxed);
std::intrinsics::assume(x != 0); // gets rid of the panicking code
Some(NonZeroUsize::new_unchecked(x))
}
pub unsafe fn get2() -> usize {
match get() {
Some(x) => x.get(),
None => unreachable!(), // optimized away
}
}I would guess that adding assume inside of new_unchecked would be ok, since it's already UB if it's not zero.
Related: #51346. Posted as a new issue, because it can be fixed without any LLVM pass changes.
hellow554LifeIsStrange
Metadata
Metadata
Assignees
Labels
A-LLVMArea: Code generation parts specific to LLVM. Both correctness bugs and optimization-related issues.Area: Code generation parts specific to LLVM. Both correctness bugs and optimization-related issues.C-optimizationCategory: An issue highlighting optimization opportunities or PRs implementing suchCategory: An issue highlighting optimization opportunities or PRs implementing suchE-needs-testCall for participation: An issue has been fixed and does not reproduce, but no test has been added.Call for participation: An issue has been fixed and does not reproduce, but no test has been added.I-slowIssue: Problems and improvements with respect to performance of generated code.Issue: Problems and improvements with respect to performance of generated code.T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.Relevant to the compiler team, which will review and decide on the PR/issue.