FMA内在函数不起作用:它是硬件还是编译器?

时间:2017-06-19 12:11:56

标签: c x86 simd intrinsics fma

我正在尝试使用英特尔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'vr = _mm_fmadd_ps(v1,v2,v3)中分配类型'__m128'时出现不兼容的类型;

我认为处理器功能可能不允许使用这些指令,因此我在互联网上查看我的处理器型号(Intel® Core™ i7-4700MQ Processor),我发现它只支持 SSE4.1 /4.2,AVX 2.0 内在函数对我来说有点奇怪! 所以我查看了proc / cpuinfo文件和flags部分,我找到了** fma **标志。这是关于硬件的令人困惑的部分。

至于软件,我在互联网上挖掘后使用了这个makefile选项,我希望不是问题。

CC=gcc
CFLAGS=-g -c -Wall -O2 -mavx2 -mfma 

我在使用GCC版本4.9.4的Ubuntu 12.04 LTS上使用eclipse 谢谢。

2 个答案:

答案 0 :(得分:3)

C的一个怪癖是语言表明编译器假设一个它以前没有见过的符号,如果你把它称为函数,则必须返回int。由于您没有包含实际定义_mm_fmadd_ps签名的标头,因此您会收到有关将int转换为__m128的奇怪错误。

内在函数标题的原始组织是每个指令生成一个唯一的标题,所以你有:

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发起的东西(ABM,BMI,LWP,TBM,XOP,FMA4,SSE4a,SSE5)或immintrin.h的英特尔 - 原始物(AVX,FMA3,F16C,AVX2等)。 AVX-512位于zmmintrin.h

旧系统并不是特别直观,但也不是新系统。 immintrin.h中定义了许多AMD指令子集,因为它们是相同的指令。在文档或标题中查找它实际上是了解哪个内在函数在哪里的唯一方法。

英特尔this website是一个很好的参考。否则,您需要查看AMD和/或Intel的开发人员指南。

您可能会发现this blog series of mine有用。

答案 1 :(得分:1)

-mfma可能看起来有点麻烦,但它有充分的理由。

的结果
begin
  raise B.new
rescue e : A | C
  puts "A or C"
rescue B
  puts "B"
rescue
  puts "any other kind of exception"
end

实际上有所不同。如果你编写的代码必须在你运行代码的所有机器上计算完全相同的结果(确定性),那么你可能需要禁用fma!这基本上就是为什么你需要在-fma的构建中启用它。

尽管如此,至少它并不像启用avx512的SkyLake-X CPU需要的六个编译标志那么糟糕:(