我正在对科学应用进行一些数值优化.我注意到的一件事是GCC会pow(a,2)
通过编译来优化调用a*a
,但调用pow(a,6)
没有优化,实际上会调用库函数pow
,这会大大降低性能.(相比之下,英特尔C++编译器,可执行文件icc
,将消除库调用pow(a,6)
.)
我很好奇的是,当我更换pow(a,6)
与a*a*a*a*a*a
使用GCC 4.5.1和选项" -O3 -lm -funroll-loops -msse4
",它采用5分mulsd
的说明:
movapd %xmm14, %xmm13
mulsd %xmm14, %xmm13
mulsd %xmm14, %xmm13
mulsd %xmm14, %xmm13
mulsd %xmm14, %xmm13
mulsd %xmm14, %xmm13
Run Code Online (Sandbox Code Playgroud)
如果我写(a*a*a)*(a*a*a)
,它会产生
movapd %xmm14, %xmm13
mulsd %xmm14, %xmm13
mulsd %xmm14, %xmm13
mulsd %xmm13, %xmm13
Run Code Online (Sandbox Code Playgroud)
这将乘法指令的数量减少到3. icc
具有类似的行为.
为什么编译器不能识别这种优化技巧?
我理解gcc的--ffast-math
标志可以大大提高浮动操作的速度,并超出IEEE标准,但我似乎无法找到有关它正在发生的事情的信息.任何人都可以解释一些细节,并可能给出一个明确的例子,说明如果标志开启或关闭会有什么变化?
我确实尝试过挖掘SO以寻找类似的问题,但却找不到任何解释ffast-math工作原理的东西.
在编写一些测试用例时,有些测试会检查NaN的结果.
我尝试使用std::isnan
但断言错误:
Assertion `std::isnan(x)' failed.
Run Code Online (Sandbox Code Playgroud)
打印出值后x
,结果显示它是负NaN(-nan
),在我的情况下是完全可以接受的.
在尝试使用NaN != NaN
和使用的事实之后assert(x == x)
,编译器给我一个'恩惠'并优化断言.
制作我自己的isNaN
功能也正在优化.
如何检查NaN 和 -NaN的相等性?
我正在尝试对一些Rust代码进行基准测试,但我无法弄清楚如何设置"ffast-math"选项.
% rustc -C opt-level=3 -C llvm-args='-enable-unsafe-fp-math' unrolled.rs
rustc: Unknown command line argument '-enable-unsafe-fp-math'. Try: 'rustc -help'
rustc: Did you mean '-enable-load-pre'?
Run Code Online (Sandbox Code Playgroud)
llvm-args='-ffast-math'
并且llvm-args='-fast'
也没有工作.我应该使用什么旗帜?
有谁知道为什么GCC/Clang不会在下面的代码示例中优化函数test1,只是在使用fast-math选项时只使用RCPPS指令?是否有另一个编译器标志会生成此代码?
typedef float float4 __attribute__((vector_size(16)));
float4 test1(float4 v)
{
return 1.0f / v;
}
Run Code Online (Sandbox Code Playgroud)
您可以在此处查看已编译的输出:https://goo.gl/jXsqat
考虑以下程序:
#include <iostream>
#include <cmath>
#include <cstring>
#include <xmmintrin.h>
using namespace std;
int main()
{
// 4 float32s.
__m128 nans;
// Set them all to 0xffffffff which should be NaN.
memset(&nans, 0xff, 4*4);
// cmpord should return a mask of 0xffffffff for any non-NaNs, and 0x00000000 for NaNs.
__m128 mask = _mm_cmpord_ps(nans, nans);
// AND the mask with nans to zero any of the nans. The result should be 0x00000000 for every component.
__m128 z = _mm_and_ps(mask, nans);
cout << …
Run Code Online (Sandbox Code Playgroud) 大家好:)
我试图抓住一些关于浮点,SIMD /数学内在函数和gcc的快速数学标志的概念.更具体地说,我在x86 cpu上使用MinGW和gcc v4.5.0.
我现在已经搜索了一会儿,这就是我(我想)我现在所理解的:
当我没有标志编译时,任何fp代码将是标准x87,没有simd内在函数,math.h函数将从msvcrt.dll链接.
当我使用mfpmath,mssen和/或march使得mmx/sse/avx代码被启用时,gcc实际上只有在我还指定一些优化标志时才使用simd指令,如On或ftree-vectorize.在这种情况下,内部函数是由gcc自动选择的,并且一些数学函数(我仍在谈论math.h上的标准数学函数)将成为内在函数或通过内联代码进行优化,其他函数仍将来自msvcrt. DLL.如果我没有指定优化标志,这会改变吗?
当我使用特定的simd数据类型(那些可用作gcc扩展,如v4si或v8qi)时,我可以选择直接调用内部函数,或者再次将自动决定留给gcc.如果我没有通过正确的标志启用simd指令,Gcc仍然可以选择标准的x87代码.同样,如果我没有指定优化标志,这会改变吗?
如果我的任何陈述错误,请纠正我:p
现在的问题是:
感谢任何想要帮助的人:D
由于gcc
选项-ffast-math
有效地禁止NaN
和-/+inf
,我在寻找可能的表示下一个最好的选择,NaN
在我的性能关键数学代码.理想情况下,如果对(add,mul,div,sub等)进行操作,哨兵值会产生哨兵值,NaN
但我怀疑这是可能的,因为我认为这NaN
是实现这一目标的唯一价值. -0.0
可能不太适合,因为它也被禁用,-ffast-math
并可能阻止某些优化,如(x+0.0)
等.
也许我的问题应该是,是否有任何方法可以使用NaN
或其他"特殊双重",同时能够启用大量的数学优化而不会崩溃?
系统是Linux/x64, gcc 4.8.1
.
我正在使用带有标志/Ox
(完全优化)的Visual Studio 2013附带的默认C++编译器(我猜它称为"Visual Studio C++编译器" ).由于浮点副作用,我必须-ffast-math
在使用gcc
编译器时禁用该标志.在Visual Studio C++编译器的配置中是否存在此标志的等效选项?
是否可以在运行时选择性地打开/关闭-ffast-math?例如,使用公共基类Math创建类FastMath和AccurateMath,以便一个人能够在运行时使用这两个实现?将次正常闪烁归零等同样如此.
特别是,我不知道使用-ffast-math进行编译是否会发出一条指令,该指令一旦执行就会影响线程中的所有数值计算(例如,设置一个标志以将subnormals刷新为零).
fast-math ×10
gcc ×5
c++ ×3
c ×2
nan ×2
optimization ×2
performance ×2
simd ×2
sse ×2
assembly ×1
clang ×1
double ×1
intrinsics ×1
llvm ×1
llvm-codegen ×1
math ×1
rust ×1