Skip to content

-Zregparm does not work correctly for LLVM builtins #145271

@tgross35

Description

@tgross35

The following code:

use std::ffi::c_void;

unsafe extern "C" {
    fn memset(p: *mut c_void, val: i32, len: usize) -> *mut c_void;
}

#[unsafe(no_mangle)]
pub unsafe extern "C" fn entrypoint(
    len: usize, val: i32, ptr: *mut c_void
)  -> *mut c_void {
    unsafe { memset(ptr, val, len) }
}

Generates this asm:

entrypoint:
        push    esi
        sub     esp, 8
        mov     esi, ecx
        sub     esp, 4
        push    eax
        push    edx
        push    ecx
        call    memset
        add     esp, 16
        mov     eax, esi
        add     esp, 8
        pop     esi
        ret

Which isn't right: it's taking the incoming args in eax, edx, ecx (correct) and making pushing them to the stack before calling memset (incorrect). regparm should make both be passed in regs.

Generated IR:

define dso_local noundef ptr @entrypoint(i32 inreg noundef %len, i32 inreg noundef %val, ptr inreg noundef returned writeonly captures(ret: address, provenance) %ptr) unnamed_addr {
start:
  %0 = trunc i32 %val to i8
  tail call void @llvm.memset.p0.i32(ptr inreg noundef align 1 %ptr, i8 inreg noundef %0, i32 inreg noundef %len, i1 false) #2
  ret ptr %ptr
}

declare void @llvm.memset.p0.i32(ptr writeonly captures(none), i8, i32, i1 immarg) #1

If we add the following, the output looks correct:

!llvm.module.flags = !{!2}
!2 = !{i32 1, !"NumRegisterParameters", i32 3}
entrypoint:                             # @entrypoint
        push    esi
        mov     esi, eax
        mov     eax, ecx
        mov     ecx, esi
        pop     esi
        jmp     memset                          # TAILCALL

So it seems like we need to add that module flag. Clang does this as well.

Demo of everything at https://rust.godbolt.org/z/ehnTjTx9b

Tracking issue: #131749

Metadata

Metadata

Assignees

Labels

A-LLVMArea: Code generation parts specific to LLVM. Both correctness bugs and optimization-related issues.A-rust-for-linuxRelevant for the Rust-for-Linux projectC-bugCategory: This is a bug.E-mediumCall for participation: Medium difficulty. Experience needed to fix: Intermediate.O-x86_32Target: x86 processors, 32 bit (like i686-*) (also known as IA-32, i386, i586, i686)T-compilerRelevant to the compiler team, which will review and decide on the PR/issue.WG-llvmWorking group: LLVM backend code generation

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions