Skip to content

NonZero prevents values from being const-propagated properly #51346

Closed
@Amanieu

Description

@Amanieu

Found while tracking down the root cause of the slowdown in #51340. This is the minimized code which reproduces the performance issue (Playground link).

#![crate_type = "rlib"]

use std::num::NonZeroUsize;

unsafe fn repeat(c: bool) -> Option<NonZeroUsize> {
    if c {
        None
    } else {
        Some(NonZeroUsize::new_unchecked(8))
    }
}

pub unsafe fn calculate_layout(c: bool) -> usize {
    match repeat(c) {
        Some(x) => 8 - x.get(),
        None => std::hint::unreachable_unchecked(),
    }
}

This code produces the following output:

// ASM
playground::calculate_layout:
	mov	eax, edi
	shl	rax, 3
	ret

// LLVM
define i64 @_ZN10playground16calculate_layout17h33252013a8d7ec56E(i1 zeroext %c) unnamed_addr #0 {
start:
  %0 = select i1 %c, i64 8, i64 0
  ret i64 %0
}

Note that in practice, it is impossible for this function to return anything other than 0 (8 - 8) due to the call to unreachable_unchecked.

The version using usize does not suffer from this (Playground link):

#![crate_type = "rlib"]

unsafe fn repeat(c: bool) -> Option<usize> {
    if c {
        None
    } else {
        Some(8)
    }
}

pub unsafe fn calculate_layout(c: bool) -> usize {
    match repeat(c) {
        Some(x) => 8 - x,
        None => std::hint::unreachable_unchecked(),
    }
}

The new code produces the following output:

// ASM
playground::calculate_layout:
	xor	eax, eax
	ret

// LLVM
define i64 @_ZN10playground16calculate_layout17h33252013a8d7ec56E(i1 zeroext %c) unnamed_addr #0 {
start:
  ret i64 0
}

cc @gnzlbg @rkruppe

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-LLVMArea: Code generation parts specific to LLVM. Both correctness bugs and optimization-related issues.C-bugCategory: This is a bug.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