Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

rustc: SIMD types use pointers in Rust's ABI #47743

Merged
merged 1 commit into from
Jan 26, 2018

Commits on Jan 25, 2018

  1. rustc: SIMD types use pointers in Rust's ABI

    This commit changes the ABI of SIMD types in the "Rust" ABI to unconditionally
    be passed via pointers instead of being passed as immediates. This should fix a
    longstanding issue, rust-lang#44367, where SIMD-using programs ended up showing very odd
    behavior at runtime because the ABI between functions was mismatched.
    
    As a bit of a recap, this is sort of an LLVM bug and sort of an LLVM feature
    (today's behavior). LLVM will generate code for a function solely looking at the
    function it's generating, including calls to other functions. Let's then say
    you've got something that looks like:
    
    ```llvm
    define void @foo() { ; no target features enabled
      call void @bar(<i64 x 4> zeroinitializer)
      ret void
    }
    
    define void @bar(<i64 x 4>) #0 { ; enables the AVX feature
      ...
    }
    ```
    
    LLVM will codegen the call to `bar` *without* using AVX registers becauase `foo`
    doesn't have access to these registers. Instead it's generated with emulation
    that uses two 128-bit registers. The `bar` function, on the other hand, will
    expect its argument in an AVX register (as it has AVX enabled). This means we've
    got a codegen problem!
    
    Comments on rust-lang#44367 have some more contexutal information but the crux of the
    issue is that if we want SIMD to work in general we'll need to ensure that
    whenever a function calls another they ABI of the arguments being passed is in
    agreement.
    
    One possible solution to this would be to insert "shim functions" where whenever
    a `target_feature` mismatch is detected the compiler inserts a shim function
    where you pass arguments via memory to the shim and then the shim loads the
    values and calls the target function (where the shim and the target have the
    same target features enabled). This unfortunately is quite nontrivial to
    implement in rustc today (especially when accounting for function pointers and
    such).
    
    This commit takes a different solution, *always* passing SIMD arguments through
    memory instead of passing as immediates. This strategy solves the problem at the
    LLVM layer because the ABI between two functions never uses SIMD registers. This
    also shouldn't be a hit to performance because SIMD performance is thought to
    often rely on inlining anyway, where a `call` instruction, even if using SIMD
    registers, would be disastrous to performance regardless. LLVM should then be
    more than capable of fixing all our memory usage to use registers instead after
    enough inlining has been performed.
    
    Note that there's a few caveats to this commit though:
    
    * The "platform intrinsic" ABI is omitted from "always pass via memory". This
      ABI is used to define intrinsics like `simd_shuffle4` where LLVM and rustc
      need to have the arguments as an immediate.
    
    * Additionally this commit does *not* fix the `extern` ("C") ABI. This means
      that the bug in rust-lang#44367 can still happen when using non-Rust-ABI functions. My
      hope is that before stabilization we can ban and/or warn about SIMD types in
      these functions (as AFAIK there's not much motivation to belong there anyway),
      but I'll leave that for a later commit and if this is merged I'll file a
      follow-up issue.
    
    All in all this...
    
    Closes rust-lang#44367
    alexcrichton committed Jan 25, 2018
    Configuration menu
    Copy the full SHA
    502de01 View commit details
    Browse the repository at this point in the history