Search code examples
assemblyrustinline-assembly

Vector registers in rust inline asm: Cannot use value of type `Simd<i64, 8>` for inline assembly


Compiling the following inline assembly:

#![feature(portable_simd)]

use std::simd::{i64x8, f64x8};
use std::arch::asm;


pub fn convert(a: i64x8) -> f64x8{
    let converted: f64x8;
    unsafe {
        asm!(
        "vcvtqq2pd {converted} {a}",
        a = in(zmm_reg) a,
        converted = out(zmm_reg) converted,
        );
    }
    converted
}


Leads to the errors:

error: cannot use value of type `Simd<i64, 8>` for inline assembly
  --> <source>:12:25
   |
12 |         a = in(zmm_reg) a,
   |                         ^
   |
   = note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly

error: cannot use value of type `Simd<f64, 8>` for inline assembly
  --> <source>:13:34
   |
13 |         converted = out(zmm_reg) converted,
   |                                  ^^^^^^^^^
   |
   = note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly

error: aborting due to 2 previous errors

You will need -C target-feature=+avx512f to compile the above. Alternatively see this godbolt

This doesn't make a ton of sense to me because the inline assembly docs clearly state that f64x8 and i64x8 are acceptable input types for zmm_reg.

Additionally the error message states that SIMD vectors are acceptable, but thats what I'm inputting.

If its relevant this reproduces on:

active toolchain
----------------

nightly-x86_64-unknown-linux-gnu (default)
rustc 1.68.0-nightly (afaf3e07a 2023-01-14)

Is this a rust bug or am I doing something wrong?


Solution

  • As mentioned in the comments, the compiler doesn't yet support using portable simd types in assembly (relevant issue). Note that not all portable simd types can be sent to assembly, things like using an f64x16 type is perfectly legal, but I do not know of any supported architecture that could handle the equivalent type. As a workaround, use the platform specific vector types, such as __m512i or __m512d.

    #![feature(portable_simd)]
    #![feature(stdsimd)]
    
    use std::simd::{i64x8, f64x8};
    use std::arch::asm;
    use std::arch::x86_64::*;
    
    pub fn convert(a: i64x8) -> f64x8{
        let a = __mm512i::from(a);
        let converted: __mm512d;
        unsafe {
            asm!(
            "vcvtqq2pd {converted}, {a}",
            a = in(zmm_reg) a,
            converted = out(zmm_reg) converted,
            );
        }
        converted.into()
    }
    

    Godbolt

    Of course, if you're doing that, try to write your code with the appropriate simd intrinsics instead of assembly if possible, to help enable the compiler to optimize your code.