FMA 内在函数不起作用:是硬件还是编译器?
FMA intrinsics not working: is it Hardware or Compiler?
我正在尝试使用英特尔 FMA 内部函数,例如 _mm_fmadd_ps (__m128 a, __m128 b, __m128 c) 为了在我的代码中获得更好的性能。
所以,首先,我做了一个小测试程序,看看它能做什么以及我如何使用它们。
#include <stdio.h>
#include <stdlib.h>
#include "xmmintrin.h"
int main()
{
__m128 v1,v2,v3,vr;
v1 = _mm_set_ps (5.0, 5.0, 5.0, 5.0);
v2 = _mm_set_ps (2.0, 2.0, 2.0, 2.0);
v3 = _mm_set_ps (3.0, 3.0, 3.0, 3.0);
vr = _mm_fmadd_ps (v1, v2, v3);
}
我遇到了这个错误:
vr = 错误:从类型 'int' 分配给类型 '__m128' 时类型不兼容 vr = _mm_fmadd_ps (v1, v2, v3);
我认为可能是处理器功能不允许使用此类指令,所以我在互联网上查找我的处理器型号 (Intel® Core™ i7-4700MQ Processor),我发现它仅支持 SSE4.1/4.2、AVX 2.0 内在函数,这对我来说有点奇怪!!
所以我查看了 proc/cpuinfo 文件和标志部分,我找到了 ** fma ** 标志。这是关于硬件的令人困惑的部分。
至于软件,我在互联网上进行了一些研究后使用了这个 makefile 选项,我希望这不是问题所在。
CC=gcc
CFLAGS=-g -c -Wall -O2 -mavx2 -mfma
我在 Ubuntu 12.04 LTS 上使用 eclipse,GCC 版本为 4.9.4
谢谢。
C 语言的一个怪癖是,如果您像调用函数一样调用它,该语言指示编译器假定一个以前未见过的符号必须 return int
。由于您没有包含实际定义 _mm_fmadd_ps
签名的 header,因此您会收到有关将 int
转换为 __m128
.
的奇怪错误
内在函数 headers 的原始组织是每个指令代都有一个唯一的 header,所以你有:
mmintrin.h The original MMX instruction set (deprecated for x64 native)
mm3dnow.h The AMD 3D Now! instruction set (deprecated for x64 native)
emmintrin.h SSE (i.e. single-precision 4-wide SIMD)
xmmintrin.h SSE2 (i.e. double-precision and integer 4-wide SIMD)
之后,他们开始使用引入新指令的处理器架构的代号。
pmmintrin.h SSE3 (the p stands for Prescott)
tmmintrin.h Supplemental SSE3 (the t stands for Tejas)
smmintrin.h SSE4.1 (not sure what the s is here for.
They were added for Penryn but p
was already used for Prescott)
nmmintrin.h SSE4.2 (the n stands for Nehalem)
wmmintrin.h AES (the w stands for Westmere)
如今,新指令集往往以 ammintrin.h
用于 AMD-originated 东西(ABM、BMI、LWP、TBM、XOP、FMA4、SSE4a、SSE5)或 immintrin.h
用于 Intel-originated 东西(AVX、FMA3、F16C、AVX2 等)。 AVX-512 在 zmmintrin.h
.
旧系统不是特别直观,但新系统也不是。 immintrin.h
中定义了许多 AMD 指令子集,因为它们是相同的指令。在文档或 header 中查找它确实是了解哪个内部函数在哪里的唯一方法。
对于英特尔 this website is a good reference. Otherwise you need to see the developer guides for AMD and/or Intel。
您可能会发现 this blog series of mine 有用。
-mfma 可能看起来有点麻烦,但它的存在是有充分理由的。
的结果
_mm_add_ps(_mm_mul_ps(a, b), c)
_mm_fmadd_ps(a, b, c)
其实不一样。如果您编写的代码必须在您 运行 代码(确定性)的所有机器上计算完全相同的结果,那么您可能需要禁用 fma!这基本上就是为什么您需要在构建中使用 -fma 启用它。
不过,至少它没有启用 avx512 的 SkyLake-X CPU 所需的六个编译标志那么糟糕:(
我正在尝试使用英特尔 FMA 内部函数,例如 _mm_fmadd_ps (__m128 a, __m128 b, __m128 c) 为了在我的代码中获得更好的性能。
所以,首先,我做了一个小测试程序,看看它能做什么以及我如何使用它们。
#include <stdio.h>
#include <stdlib.h>
#include "xmmintrin.h"
int main()
{
__m128 v1,v2,v3,vr;
v1 = _mm_set_ps (5.0, 5.0, 5.0, 5.0);
v2 = _mm_set_ps (2.0, 2.0, 2.0, 2.0);
v3 = _mm_set_ps (3.0, 3.0, 3.0, 3.0);
vr = _mm_fmadd_ps (v1, v2, v3);
}
我遇到了这个错误:
vr = 错误:从类型 'int' 分配给类型 '__m128' 时类型不兼容 vr = _mm_fmadd_ps (v1, v2, v3);
我认为可能是处理器功能不允许使用此类指令,所以我在互联网上查找我的处理器型号 (Intel® Core™ i7-4700MQ Processor),我发现它仅支持 SSE4.1/4.2、AVX 2.0 内在函数,这对我来说有点奇怪!! 所以我查看了 proc/cpuinfo 文件和标志部分,我找到了 ** fma ** 标志。这是关于硬件的令人困惑的部分。
至于软件,我在互联网上进行了一些研究后使用了这个 makefile 选项,我希望这不是问题所在。
CC=gcc
CFLAGS=-g -c -Wall -O2 -mavx2 -mfma
我在 Ubuntu 12.04 LTS 上使用 eclipse,GCC 版本为 4.9.4 谢谢。
C 语言的一个怪癖是,如果您像调用函数一样调用它,该语言指示编译器假定一个以前未见过的符号必须 return int
。由于您没有包含实际定义 _mm_fmadd_ps
签名的 header,因此您会收到有关将 int
转换为 __m128
.
内在函数 headers 的原始组织是每个指令代都有一个唯一的 header,所以你有:
mmintrin.h The original MMX instruction set (deprecated for x64 native)
mm3dnow.h The AMD 3D Now! instruction set (deprecated for x64 native)
emmintrin.h SSE (i.e. single-precision 4-wide SIMD)
xmmintrin.h SSE2 (i.e. double-precision and integer 4-wide SIMD)
之后,他们开始使用引入新指令的处理器架构的代号。
pmmintrin.h SSE3 (the p stands for Prescott)
tmmintrin.h Supplemental SSE3 (the t stands for Tejas)
smmintrin.h SSE4.1 (not sure what the s is here for.
They were added for Penryn but p
was already used for Prescott)
nmmintrin.h SSE4.2 (the n stands for Nehalem)
wmmintrin.h AES (the w stands for Westmere)
如今,新指令集往往以 ammintrin.h
用于 AMD-originated 东西(ABM、BMI、LWP、TBM、XOP、FMA4、SSE4a、SSE5)或 immintrin.h
用于 Intel-originated 东西(AVX、FMA3、F16C、AVX2 等)。 AVX-512 在 zmmintrin.h
.
旧系统不是特别直观,但新系统也不是。 immintrin.h
中定义了许多 AMD 指令子集,因为它们是相同的指令。在文档或 header 中查找它确实是了解哪个内部函数在哪里的唯一方法。
对于英特尔 this website is a good reference. Otherwise you need to see the developer guides for AMD and/or Intel。
您可能会发现 this blog series of mine 有用。
-mfma 可能看起来有点麻烦,但它的存在是有充分理由的。
的结果_mm_add_ps(_mm_mul_ps(a, b), c)
_mm_fmadd_ps(a, b, c)
其实不一样。如果您编写的代码必须在您 运行 代码(确定性)的所有机器上计算完全相同的结果,那么您可能需要禁用 fma!这基本上就是为什么您需要在构建中使用 -fma 启用它。
不过,至少它没有启用 avx512 的 SkyLake-X CPU 所需的六个编译标志那么糟糕:(