rust-lang / rustc_codegen_cranelift

Cranelift based backend for rustc
Apache License 2.0
1.52k stars 94 forks source link

arm64 macOS variadic arguments ABI needs Cranelift support #1451

Closed bjorn3 closed 1 week ago

bjorn3 commented 5 months ago

On pretty much every target variadic functions almost the exact same ABI (on x86 you need to set %al to the upper bound of the amount of float args, so float args are currently forbidden by cg_clif) as non-variadic functions with the same arguments passed (after integer promotion, but rust denies vararg calls that need integer promotion anyway). This means that I can work around the lack of vararg support in Cranelift by changing the function signature of the imported function declaration to match the non-variadic counterpart. On arm64 macOS however variadic arguments are passed differently from non-variadic arguments: https://developer.apple.com/documentation/xcode/writing-arm64-code-for-apple-platforms#Update-code-that-passes-arguments-to-variadic-functions As such we can't support vararg functions on arm64 macOS until Cranelift gets native vararg support: https://github.com/bytecodealliance/wasmtime/issues/1030

beetrees commented 2 weeks ago

While native Cranelift support would be ideal, I believe it's possible to support varargs on arm64 macOS to a similar extent as x86-64 by just padding the argument list to use up all the registers and force the varargs into stack slots. For example, the following calls result in the same argument placements on arm64 macOS:

use std::mem::MaybeUninit;

type Pad = MaybeUninit<usize>;
const PAD: Pad = MaybeUninit::uninit();

unsafe fn call_va(path: *const i8, flags: i32, mode: i32) -> i32 {
    extern "C" {
        fn open(path: *const i8, flags: i32, ...) -> i32;
    }
    open(path, flags, mode)
}

unsafe fn call_explicit(path: *const i8, flags: i32, mode: i32) -> i32 {
    extern "C" {
        fn open(path: *const i8, flags: i32, _: Pad, _: Pad, _: Pad, _: Pad, _: Pad, _: Pad, mode: i32) -> i32;
    }
    // There are 8 integer registers to consume.
    open(path, flags, PAD, PAD, PAD, PAD, PAD, PAD, mode)
}
bjorn3 commented 1 week ago

@beetrees implemented support for varargs without needing Cranelift changes in https://github.com/rust-lang/rustc_codegen_cranelift/pull/1500.