Skip to content

Addition of Option<NonZero*> can compile suboptimally #81342

Open
@cevans-uk

Description

@cevans-uk

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()
}

(Playground)

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 to rdi.
  • After the first cmoveq, rcx is therefore either equal to rdi, or 0,
  • The second cmoveq moves rdi into rcx when rdi is 0. But when rdi 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

No one assigned

    Labels

    A-result-optionArea: Result and Option combinatorsC-optimizationCategory: 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.I-slowIssue: 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.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions