如何从 Rust 调用 _mm256_mul_ph ?

dme*_*ter 2 intrinsics rust avx512 half-precision-float

_mm256_mul_ps是“乘法打包单精度(32 位)浮点元素”的 Intel 内在函数。_mm256_mul_ph是“乘法打包半精度(16 位)浮点元素”的内在函数。

我可以_mm256_mul_ps使用 using 来调用use std::arch::x86_64::*;,例如

#[inline]
fn mul(v: __m256, w: __m256) -> __m256 {
     unsafe { _mm256_mul_ps(v, w) }
}
Run Code Online (Sandbox Code Playgroud)

不过,似乎很难调用_mm256_mul_ph。可以调用_mm256_mul_phRust 吗?

kmd*_*eko 5

您正在寻找的内容需要 AVX-512 FP16 和 AVX-512 VL 指令集 - 前者目前似乎在 Rust 中没有任何支持。

您可以根据需要使用asm!宏创建自己的内在函数。的程序集_mm256_mul_ph如下所示:

vmulph ymm, ymm, ymm
Run Code Online (Sandbox Code Playgroud)

所以 Rust 中的等价物可以这样写:

#[cfg(target_feature = "avx2")]
unsafe fn _mm256_mul_ph(a: __m256i, b: __m256i) -> __m256i {
    let dst: __m256i;

    asm!(
        "vmulph {0}, {1}, {2}",
        out(ymm_reg) dst,
        in(ymm_reg) a,
        in(ymm_reg) b,
        options(pure, nomem, nostack),
    );

    dst
}
Run Code Online (Sandbox Code Playgroud)

要为其他指令创建您自己的内在函数,请确保遵循 Rust内联汇编的指南并仔细理解指令的作用。如果指定不正确,内联汇编unsafe可能会导致非常奇怪的行为。

注意事项:

  • 这仅在底层机器(Rust 1.76 起的 LLVM 17)确实支持此指令集时才有效。如果您尝试在全新的指令集(或使用较旧的工具链)上尝试此方法,它可能无法工作,并且由于“无效指令”而无法编译。

  • __m256i用于代替类型,__m256h因为后者不存在。目前__m256i用作“位袋”(文档中的文字),因此您必须自己跟踪它是否保存了f16x16值。

  • 不幸的是,该target_feature = "avx2"条件不足以将其正确限制为实际可以运行此功能的目标。avx512fp16Rust 中没有可用的目标功能标志(_mm256_mul_ph特别avx512vl是还需要目标功能标志,但也不支持)。

    您需要小心,只为支持它的架构编译和运行此代码 - 据我所知,目前是 Intel Sapphire Rapids CPU。或者引入您自己的编译标志可能会更好,虽然它并不完美,但有望限制出错的范围。

    如果在不受支持的体系结构上编译和执行,您将收到“非法指令”错误(在最好的情况下)。

  • 当然,另一个需要注意的是,它是内联汇编,而不是真正的内在函数,因此无法通过它进行常量传播和其他优化(例如通过洗牌跟踪值)。还有诸如将 mul+add 纳入 FMA 等内容。使用 AVX-512,将混合折叠到合并屏蔽输出中,或加载到内存源操作数中。(如果 LLVM 不会像 clang 那样总是溢出来搬起石头砸自己的脚,那么可以在有约束的情况下允许 mem src。)一旦存在真正的内在函数,就更喜欢这样做,除非优化器做得不好而你*想要*强制这个 asm 存在。 (3认同)