Hi fellow Rustaceans,
TL;DR: Is there some way to specify that a function (either on the callee or caller side) cannot use SIMD (SSE)
XMM registers in its calling convention?
As part of an unusual research OS project, I have two crates that run in the same address space:
lib_reg: a crate that is compiled without SIMD support (
soft_floattarget feature enabled), and exposes several public functions.
lib_sse: a crate that is compiled with SIMD support (
sse2target feature enabled).
I want to call
lib_reg's functions from the
However, the caller site in the
lib_sse crate places arguments inside the
XMM registers, but the callee function in the
lib_reg crate expects those arguments to be placed in
RSI, etc, so linking the two doesn’t work when they are compiled separately. Additionally, the XMM registers are sometimes used to pass the return value back from the callee function, which the
lib_sse crate expects to happen, but the
lib_reg crate cannot do.
A typical disassembly of the caller code in
lib_sse looks like this:
movsd -0x40(%rbp),%xmm0 movsd -0x38(%rbp),%xmm1 movsd -0x30(%rbp),%xmm2 movsd -0x28(%rbp),%xmm3 ... callq *%rcx # calls a function in lib_reg
One potential solution to this would be to declare the
lib_reg functions with a calling convention that stipulates that only normal registers (and stack space) could be used, and disallows using XMM registers for passing arguments. This could look something like:
extern "no_sse_regs" fn my_public_func(...)
However, no such calling convention exists, and when I compile the
lib_sse crate with
target_features = +sse2, the compiler is allowed to use SIMD registers for every single function in that crate. It’d be nice if I could specify which functions are allowed to use SIMD registers in their calling convention, and which ones aren’t.
I looked into the
#[target_feature(enable = ...)] feature, but it doesn’t quite do what I need it to.
One way to circumvent this would be to use unsafe inline assembly blocks to, which is kind of what system calls require, i.e., manually placing arguments into specific registers, but that loses the language-level info like types, borrowing/lifetimes, mutability, etc. It’s also intractable to manually specify argument placement for hundreds of functions.
Any ideas on how to realize this? Thanks!