Skip to content

fn(...) -> Option<T>, where T is returned by invisible reference, could use null pointer for None #144310

@zackw

Description

@zackw

Consider a function that returns Option<T> where T is too large to be returned in registers, such as

const N: usize = 8;

pub fn fill_v(val: u64) -> Option<[u32; N]> {
    let v = u32::try_from(val).ok()?;
    Some(core::array::from_fn(|_| v))
}

Because [u32;8] doesn't fit in the ABI's return value registers, instead it's returned by "invisible reference"; at the assembly level, caller provides fill_v with two arguments, val and also a pointer to space for the return value. Right now, when you return Option<[u32;8]>, the Option discriminator takes up part of that space:

playground::fill_v: # @playground::fill_v
# %bb.0:
	movq	%rdi, %rax
	xorl	%ecx, %ecx
	movq	%rsi, %rdx
	shrq	$32, %rdx
	jne	.LBB0_2
# %bb.1:
	movd	%esi, %xmm0
	pshufd	$0, %xmm0, %xmm0                # xmm0 = xmm0[0,0,0,0]
	movdqu	%xmm0, 4(%rax)
	movdqu	%xmm0, 20(%rax)
	movl	$1, %ecx

.LBB0_2:
	movl	%ecx, (%rax)
	retq

(The invisible reference is the first argument at the assembly level, in %rdi; the Rust-level first argument val is in %rsi.)

But the invisible reference argument is necessarily non-NULL, so we could apply the null pointer optimization for Option in this case, even though we can't do it in general for Option<[T;N]>, and generate code like this instead:

playground::fill_v: # @playground::fill_v
# %bb.0:
	xorl	%eax, %eax
	movq	%rsi, %rdx
	shrq	$32, %rdx
	jne	.LBB0_2
# %bb.1:
	movd	%esi, %xmm0
	pshufd	$0, %xmm0, %xmm0                # xmm0 = xmm0[0,0,0,0]
	movdqu	%xmm0, (%rdi)
	movdqu	%xmm0, 16(%rdi)
	movq	%rdi, %rax
.LBB0_2:
	retq

This would save a word of stack space and would probably also be more efficient for the caller.

The example is an array, but the optimization is equally applicable to Option<LargeStruct>, etc.

Meta

rustc --version --verbose:

1.90.0-nightly (2025-07-21 9748d87dc70a9a6725c5)

Metadata

Metadata

Assignees

No one assigned

    Labels

    C-discussionCategory: Discussion or questions that doesn't represent real issues.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions