Skip to content

Missed optimization: unnecessary copies returning 3-tuple of u32 #137488

Open
@zackw

Description

@zackw

This function provides a safe wrapper for the (Linux-specific) system call getresuid.

use libc::uid_t;
use std::mem::MaybeUninit;

pub fn getresuid() -> (uid_t, uid_t, uid_t) {
    let mut ruid = MaybeUninit::uninit();
    let mut euid = MaybeUninit::uninit();
    let mut suid = MaybeUninit::uninit();

    unsafe {
        let _ = libc::getresuid(ruid.as_mut_ptr(), euid.as_mut_ptr(), suid.as_mut_ptr());
        (ruid.assume_init(), euid.assume_init(), suid.assume_init())
    }
}

With rustc 1.87.0-nightly (2025-02-22 46420c9), on x86-64, suboptimal assembly code is generated:

playground::getresuid:
	pushq	%rbx
	subq	$16, %rsp
	movq	%rdi, %rbx
	leaq	8(%rsp), %rsi
	leaq	12(%rsp), %rdx
	callq	*getresuid@GOTPCREL(%rip)
	movl	8(%rsp), %eax
	movl	12(%rsp), %ecx
	movl	%eax, 4(%rbx)
	movl	%ecx, 8(%rbx)
	movq	%rbx, %rax
	addq	$16, %rsp
	popq	%rbx
	retq

Playground link.

The 3-tuple return value is being returned by "invisible reference", i.e. caller supplied a pointer to space for 3 uid_t (== u32) quantities. The compiler could have had libc::getresuid write all three of its outputs directly into that space, but instead it only had it write one of its outputs directly into that space, and supplied scratch stack locations for the other two, which then had to be copied into place.

Better code would be like this:

playground::getresuid:
	pushq	%rbx
	movq	%rdi, %rbx
	leaq	4(%rdi), %rsi
	leaq	8(%rdi), %rdx
	callq	*getresuid@GOTPCREL(%rip)
	movq	%rbx, %rax
	popq	%rbx
	retq

This does not seem to be a regression, at least not from current stable.

Metadata

Metadata

Assignees

No one assigned

    Labels

    C-optimizationCategory: An issue highlighting optimization opportunities or PRs implementing suchT-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