首页 > 解决方案 > 什么是内在序列函数?

问题描述

Intel Intrinsics Guide中有一些函数未映射到汇编指令,因此...在右侧标有 ,并且没有性能(延迟和吞吐量)信息。这些被标记为Sequence说明,所以我的猜测是这些是它们提供的实际功能immintrin.h,可以用来代替这些任务的手动实现。
但我不明白的是,这些只是英特尔不能/不会作为真正指令实现的有用功能,还是它们包装到可能的未来版本的 avx/avx2/avx512 扩展?
我找不到有关此主题的任何官方信息或其他来源(我的主要来源是 Intel Intrinsics Guide 以及英特尔编译器用户指南(虽然我使用 gcc))

标签: intelintrinsicsavx

解决方案


_mm_set_epi32(int, int, int, int)像单个机器指令这样的事情毫无意义。它需要四个r/m32或仅寄存器源操作数(和一个 XMM 目标),但 x86 机器代码最多只有 3 个操作数,包括目标。(尽管对于 FMA,所有 3 个都是输入)。vblendvps/pd唯一的例外是vpblendvb立即字节编码第 4 个操作数,但这仍然只有 4 个,而不是 4 个 reg/mem 和一个单独的目标。

另请参阅为什么不允许从内存到内存的 movl?x86 cpu有什么样的地址指令?


通常您_mm_set使用常量,并希望编译器进行常量传播以使单个向量常量。如果你想要一个聚集负载的指针,你可以使用_mm_i32gather_epi32一个索引向量。

所以通常不,它们不是计划的未来指令的占位符,它们基本上只是便利功能,其实现可能会根据输入操作数是在内存中还是在寄存器中而有很大差异。(例如矢量洗牌)。并且取决于可用的功能级别,例如 SSE4.1pinsrd可以用作_mm_set_epi32(0,0,b,a).

或者 SVML 数学函数的原型,比如_mm_sin_ps,根本不是内在函数。英特尔使用相同的_mm命名方案并将其包含在内部函数指南的一部分中,部分是为了方便使用英特尔自己的编译器(随 SVML 提供)的人,可能部分是为了诱骗/诱骗人们依赖英特尔 API,从而使其更难将他们的代码移植到其他具有内在函数但没有 SVML 的编译器。

或者它们就像_mm256_castsi256_si128在 asm 中免费的那样,只需使用寄存器的 XMM 低半部分。

C 内在函数 API 甚至没有办法询问__m128低元素是 scalar 的位置float,而高元素是无关紧要的,您只有_mm_set1_ps广播或_mm_set_ss零扩展,并非所有编译器都可以优化它如果你只使用__m128那些不关心上层元素的东西,那就离开。(Clang 的 shuffle 优化器可以看到发生了什么。)这很烦人,因为寄存器的标量浮点数只是 XMM 的低元素,但没有等价于_mm256_castps128_ps256(它给你一个带有无关上半部分的向量) .


对于某些未来的 CPU 来说,引入一条指令就像vsinps在硬件中执行 SVML 库函数所做的那样是合理的,但不太可能。 sin对于一个合理长度的流水线执行单元来说工作量太大了。例如, x87fsin在 Skylake 上被微编码为 53-105 uops ( https://agner.org/optimize/ / https://uops.info/ ),而且它通常并不比经过良好优化的软件实现快。完整的硬件/微代码fsin对于用 asm 编写的玩具程序很方便,但对于将其留给编译器/数学库的实际代码来说,这两种方式都不是什么大问题。

此外,sin在硬件/微码中进行的操作以人们可能不想要的方式确定了速度与精度的权衡。还相关:英特尔将错误界限低估了 1.3 quintillion - fsin 对于非常接近 Pi 的输入非常不准确,英特尔最近才修复了他们的文档。(虽然您可以使用扩展精度来获得精度,但软件的时间并不容易。)据推测,同一指令的 SIMD 浮点版本也会有相同的精度问题。


推荐阅读