From 8118dc658ca88855e36ecc3f66705372d8c7265e Mon Sep 17 00:00:00 2001 From: David Gow Date: Sun, 12 Oct 2025 21:44:33 +0800 Subject: [PATCH] x86: Correctly pass larger structs/types in registers with -Zregparm MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes #145694. The -Zregparm option for 32-bit x86 modifies the calling convention to pass a number of arguments in registers instead of on the stack. (This is primarily used by the Linux kernel.) Currently, rustc will only pass primitive integer types in registers, which seems to match the gcc documentation[1], which says that arguments "of integral type" are passed as registers. This also matches the fastcall and vectorcall conventions on windows. However, it seems that _any_ type — most particularly structs — should be passed as a register if possible. This matches what clang and gcc do, and so avoids an ABI mismatch when linking with C code (which, after all, is the whole point of supporting -Zregparm). --- compiler/rustc_target/src/callconv/x86.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_target/src/callconv/x86.rs b/compiler/rustc_target/src/callconv/x86.rs index 918b71c80c4f0..a2bfbe11f006a 100644 --- a/compiler/rustc_target/src/callconv/x86.rs +++ b/compiler/rustc_target/src/callconv/x86.rs @@ -183,7 +183,9 @@ pub(crate) fn fill_inregs<'a, Ty, C>( free_regs -= size_in_regs; - if arg.layout.size.bits() <= 32 && unit.kind == RegKind::Integer { + if opts.flavor != Flavor::FastcallOrVectorcall + || arg.layout.size.bits() <= 32 && unit.kind == RegKind::Integer + { attrs.set(ArgAttribute::InReg); }