rust-lang / rust-lang/rust

Support calling functions with SIMD vectors that couldn't be used in the caller

Open
#132,865 2 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

A-ABI A-LLVM A-SIMD C-feature-request T-opsem WG-llvm
Dominant language
Rust
Stars
119k
Forks
16.1k
PR merge metrics
PR metrics pending

Description

We now lint and will eventually error on this program:

use std::mem::transmute;
#[cfg(target_arch = "x86")]
use std::arch::x86::*;
#[cfg(target_arch = "x86_64")]
use std::arch::x86_64::*;

#[target_feature(enable = "avx")]
#[allow(improper_ctypes_definitions)]
unsafe extern "C" fn with_target_feature(x: __m256) {
    let val = unsafe { transmute::<_, [u32; 8]>(x) };
    dbg!(val);
}

fn main() {
    assert!(is_x86_feature_detected!("avx"));
    // SAFETY: we checked that the `avx` feature is present.
    unsafe {
        with_target_feature(transmute([1; 8])); //~ ERROR: missing `avx` target feature
    }
}
warning: ABI error: this function call uses a vector type that requires the `avx` target feature, which is not enabled in the caller
  --> test.rs:18:9
   |
18 |         with_target_feature(transmute([1; 8]));
   |         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ function called here
   |
   = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
   = note: for more information, see issue #116558 <https://github.com/rust-lang/rust/issues/116558>
   = help: consider enabling it globally (`-C target-feature=+avx`) or locally (`#[target_feature(enable="avx")]`)
   = note: `#[warn(abi_unsupported_vector_types)]` on by default

The lint is necessary because the way we codegen this function would be unsound (and indeed, if you run this on the playground you can see that the argument value gets corrupted). See https://github.com/rust-lang/rust/issues/116558 for more context.

However, there's no fundamental reason that we couldn't compile this code! We "just" need to generate the call to with_target_feature using its proper ABI, i.e., using the AVX registers. This is sound because the function anyway requires that target feature, so the caller must have already ensured that this target feature is available.

The problem is that LLVM currently simply has no way to express such a call. So we have three options:

  • error (the easiest one, and what we are currently working towards)
  • fix this in LLVM (also see https://github.com/llvm/llvm-project/issues/70563) -- I am told this is quite hard
  • generate a shim that uses the Rust ABI (so it is not affected by these ABI shenanigans), and has the avx feature gate, and calls the actual callee -- not a pretty solution since the extra function call is bad for performance, and performance is the reason people manually write SIMD code to begin with

Lucky enough, this only affects non-Rust ABIs, so users should only rarely run into this.

Cc @rust-lang/wg-llvm @rust-lang/opsem @chorman0773 @veluca93

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the reproducer in the issue, then read issue #116558 and LLVM issue #70563 for the ABI constraints and prior context. Compare the LLVM fix and Rust shim approaches; done means the shown non-Rust ABI call compiles with the correct AVX register passing and no value corruption.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
compilers
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.