Skip to content

Commit 67d6b43

Browse files
committed
x86: Correctly pass large integers in registers with -Zregparm
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 integers of size <= 32 bits in registers, but gcc (and clang) will pass larger integers (e.g., 64-bit integers) across two registers if possible. This is not the case with fastcall/vectorcall. Note that gcc/clang with -mregparm will also pass some structs in registers: this patch does not attempt to fix that case.
1 parent 33cab8c commit 67d6b43

File tree

2 files changed

+23
-1
lines changed

2 files changed

+23
-1
lines changed

compiler/rustc_target/src/callconv/x86.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -183,7 +183,9 @@ pub(crate) fn fill_inregs<'a, Ty, C>(
183183

184184
free_regs -= size_in_regs;
185185

186-
if arg.layout.size.bits() <= 32 && unit.kind == RegKind::Integer {
186+
if opts.flavor != Flavor::FastcallOrVectorcall
187+
|| arg.layout.size.bits() <= 32 && unit.kind == RegKind::Integer
188+
{
187189
attrs.set(ArgAttribute::InReg);
188190
}
189191

tests/assembly-llvm/regparm-module-flag.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,26 @@ use minicore::*;
1919
unsafe extern "C" {
2020
fn memset(p: *mut c_void, val: i32, len: usize) -> *mut c_void;
2121
fn non_builtin_memset(p: *mut c_void, val: i32, len: usize) -> *mut c_void;
22+
fn test_i64_arg(s: i64) -> i64;
23+
}
24+
25+
#[unsafe(no_mangle)]
26+
pub unsafe extern "C" fn test_i64() -> i64 {
27+
// REGPARM1-LABEL: test_i64
28+
// REGPARM1: pushl
29+
// REGPARM1: pushl
30+
// REGPARM1: calll test_i64_arg
31+
32+
// REGPARM2-LABEL: test_i64
33+
// REGPARM2: movl $42, %eax
34+
// REGPARM2: xorl %edx, %edx
35+
// REGPARM2: jmp test_i64_arg
36+
37+
// REGPARM3-LABEL: test_i64
38+
// REGPARM3: movl $42, %eax
39+
// REGPARM3: xorl %edx, %edx
40+
// REGPARM3: jmp test_i64_arg
41+
unsafe { test_i64_arg(42) }
2242
}
2343

2444
#[unsafe(no_mangle)]

0 commit comments

Comments
 (0)