Open
Description
I'm fairly certain foo
and bar
are equivalent (though let me know if I'm overlooking something!):
use std::num::NonZeroUsize;
pub fn foo(x: Option<NonZeroUsize>, y: Option<NonZeroUsize>) -> Option<NonZeroUsize> {
if let (Some(x2), Some(y2)) = (x, y) {
NonZeroUsize::new(x2.get() + y2.get())
} else {
None
}
}
pub fn bar(x: Option<NonZeroUsize>, y: Option<NonZeroUsize>) -> Option<NonZeroUsize> {
x.zip(y)
.map(|(x2, y2)| NonZeroUsize::new(x2.get() + y2.get()))
.flatten()
}
but the compilation of bar
seems suboptimal (current stable, 1.49.0):
playground::foo:
leaq (%rsi,%rdi), %rax
testq %rsi, %rsi
cmoveq %rsi, %rax
testq %rdi, %rdi
cmoveq %rdi, %rax
retq
playground::bar:
testq %rsi, %rsi
movq %rdi, %rcx
cmoveq %rsi, %rcx
testq %rdi, %rdi
cmoveq %rdi, %rcx
leaq (%rsi,%rcx), %rax
testq %rcx, %rcx
cmoveq %rcx, %rax
retq
Same result with 1.51.0-nightly (2021-01-23 4d0dd02).
In particular, the middle testq
/ cmoveq
pair -- immediately preceding the leaq
-- seem entirely redundant unless I'm missing something, as:
- After the
movq
,rcx
is equal tordi
. - After the first
cmoveq
,rcx
is therefore either equal tordi
, or 0, - The second
cmoveq
movesrdi
intorcx
whenrdi
is 0. But whenrdi
is 0,rcx
must already be 0.
I played around with some other NonZero*
types (including some signed) and observed the same pattern.
Metadata
Metadata
Assignees
Labels
Area: Result and Option combinatorsCategory: An issue highlighting optimization opportunities or PRs implementing suchCall for participation: An issue has been fixed and does not reproduce, but no test has been added.Issue: Problems and improvements with respect to performance of generated code.Relevant to the compiler team, which will review and decide on the PR/issue.