Skip to content

Rust LLVMIR causes errors after LTO on x86-32 #143818

@jrmuizel

Description

@jrmuizel
#[repr(C)]
pub struct UrlpPattern(pub *mut c_void);

#[unsafe(no_mangle)]
pub unsafe extern "C" fn square(num: UrlpPattern) -> *mut c_void {
    num.0
}

generates

define noundef ptr @square(ptr noalias nocapture noundef readonly byval([4 x i8]) align 4 dereferenceable(4) %num) unnamed_addr {
start:
  %_0 = load ptr, ptr %num, align 4
  ret ptr %_0
}

but

struct wrapper {
    void *p;
};


void *square(wrapper p) {
    return p.p;
}

generates

define dso_local i8* @square(wrapper)(i8* readnone returned %p.0) local_unnamed_addr {
entry:
  ret i8* %p.0
}

It seems like this mostly works because it compiles to the same thing x86-32 code:

square(wrapper):                      # @square(wrapper)
        mov     eax, dword ptr [esp + 4]
        ret

However, if the rust code is inlined into C++ with LTO we end up with an extra dereference.

We ran into this in Firefox here: https://bugzilla.mozilla.org/show_bug.cgi?id=1973805

rustc --version --verbose:

rustc 1.88.0 (6b00bc388 2025-06-23)

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-ABIArea: Concerning the application binary interface (ABI)A-LLVMArea: Code generation parts specific to LLVM. Both correctness bugs and optimization-related issues.A-LTOArea: Link-time optimization (LTO)C-bugCategory: This is a bug.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.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions