问题标签 [fma]
For questions regarding programming in ECMAScript (JavaScript/JS) and its various dialects/implementations (excluding ActionScript). Note JavaScript is NOT the same as Java! Please include all relevant tags on your question; e.g., [node.js], [jquery], [json], [reactjs], [angular], [ember.js], [vue.js], [typescript], [svelte], etc.
c - 融合乘加和默认舍入模式
使用 GCC 5.3,以下代码与-O3 -fma
产生以下程序集
-O3 -mfma
带有产品的 Clang 3.7
但 Clang 3.7 with-Ofast -mfma
产生与 GCC 相同的代码-O3 fast
。
我很惊讶 GCC 这样做,-O3
因为从这个答案中它说
除非您允许宽松的浮点模型,否则不允许编译器融合分离的加法和乘法。
这是因为 FMA 只有一个舍入,而 ADD + MUL 有两个。因此编译器将通过融合违反严格的 IEEE 浮点行为。
但是,从这个链接它说
无论 FLT_EVAL_METHOD 的值如何,任何浮点表达式都可以收缩,也就是说,计算好像所有中间结果都具有无限范围和精度。
所以现在我很困惑和担心。
- GCC 使用 FMA 是否合理
-O3
? - 融合是否违反严格的 IEEE 浮点行为?
- 如果融合确实违反了 IEEE 浮点行为,并且由于GCC 返回
__STDC_IEC_559__
,这不是矛盾吗?
由于 FMA可以在软件中模拟,因此 FMA似乎应该有两个编译器开关:一个告诉编译器在计算中使用 FMA,另一个告诉编译器硬件具有 FMA。
显然这可以通过选项来控制-ffp-contract
。使用 GCC 默认是-ffp-contract=fast
,而使用 Clang 则不是。其他选项,例如-ffp-contract=on
和-ffp-contract=off
不产生 FMA 指令。
例如带有-O3 -mfma -ffp-contract=fast
产生的 Clang 3.7 vfmadd132ss
。
#pragma STDC FP_CONTRACT
我检查了set toON
和OFF
with -ffp-contract
set to on
、off
和的一些排列fast
。在所有情况下,我也使用了-O3 -mfma
.
使用 GCC,答案很简单。#pragma STDC FP_CONTRACT
ON 或 OFF 没有区别。只-ffp-contract
重要。
fma
它使用的GCC
-ffp-contract=fast
(默认)。
使用 Clang 它使用fma
- 与
-ffp-contract=fast
. - 使用
-ffp-contract=on
(默认)和#pragma STDC FP_CONTRACT ON
(默认为OFF
)。
换句话说,使用 Clang 您可以fma
使用#pragma STDC FP_CONTRACT ON
(因为-ffp-contract=on
是默认设置)或使用-ffp-contract=fast
. -ffast-math
(因此-Ofast
)设置-ffp-contract=fast
。
我研究了 MSVC 和 ICC。
对于 MSVC,它使用 fma 指令和/O2 /arch:AVX2 /fp:fast
. 使用 MSVC/fp:precise
是默认设置。
对于 ICC,它使用 fma with -O3 -march=core-avx2
(-O1
实际上就足够了)。这是因为默认情况下 ICC 使用-fp-model fast
. 但是 ICC 使用 fma 甚至-fp-model precise
. 要使用 ICC 禁用 fma,请使用-fp-model strict
或-no-fma
。
因此,默认情况下,GCC 和 ICC 在启用 fma 时使用 fma(使用-mfma
GCC/Clang 或-march=core-avx2
使用 ICC),但 Clang 和 MSVC 不使用。
gcc - 我需要做什么才能让 GCC 4.9 认识到使用 AVX FMA 的机会?
我有std::vector<double> X,Y
两个尺寸N
(和N%16==0
),我想计算sum(X[i]*Y[i])
。这是融合乘加(FMA)的经典用例,它在支持 AVX 的处理器上应该很快。我知道我所有的目标 CPU 都是 Intel、Haswell 或更新的。
如何让 GCC 发出该 AVX 代码?-mfma
是解决方案的一部分,但我需要其他开关吗?
并std::vector<double>::operator[]
阻碍了这一点?我知道我可以转变
至
所以编译器可以发现&X[0]
循环中没有改变。但这是否足够甚至必要?
当前编译器是 GCC 4.9.2、Debian 8,但如有必要可以升级到 GCC 5。
c - 英特尔 FMA 指令提供零性能优势
考虑使用 Haswell 的 FMA 指令的以下指令序列:
可以使用非 FMA 指令表示相同的计算,如下所示:
人们会期望 FMA 版本比非 FMA 版本提供一些性能优势。
但不幸的是,在这种情况下,性能改进为零 (0)。
谁能帮我理解为什么?
我在基于核心 i7-4790 的机器上测量了这两种方法。
更新:
因此,我分析了生成的机器代码并确定 MSFT VS2013 C++ 编译器正在生成机器代码,因此 r1 和 r2 的依赖链可以并行调度,因为 Haswell 有 2 个 FMA 管道。
r3 必须在 r1 之后调度,因此在这种情况下,第二个 FMA 管道是空闲的。
我认为如果我展开循环以执行 6 组 FMA 而不是 3 组,那么我可以让所有 FMA 管道在每次迭代时都处于忙碌状态。
不幸的是,当我在这种情况下检查程序集转储时,MSFT 编译器没有选择允许我正在寻找的并行调度类型的寄存器分配,并且我证实我没有得到我正在寻找的性能提升为了。
有没有办法可以更改我的 C 代码(使用内在函数)以使编译器能够生成更好的代码?
assembly - 为什么 FMA _mm256_fmadd_pd() 内在函数有 3 个 asm 助记符,“vfmadd132pd”、“231”和“213”?
有人可以向我解释为什么融合乘法累加指令有 3 种变体:vfmadd132pd
,vfmadd231pd
和vfmadd213pd
, 而只有一个 C 内在函数_mm256_fmadd_pd
?
为简单起见,(在 AT&T 语法中)有什么区别
我没有从英特尔的内在指南中得到任何想法。我问是因为我在我编写的一段 C 代码的汇编器输出中看到了所有这些。谢谢。
一个干净的答案(在下面重新格式化答案)
对于变体ijk
,的含义vfmaddijkpd
:
- 英特尔语法:
op(i) * op(j) + op(k) -> op(1)
- AT&T 语法:
op(4-i) * op(4-j) + op(4-k) -> op(3)
其中op(n)
表示指令后的第 n 个操作数。所以两者之间有一个逆变换:
c# - C# 可以使用融合乘加吗?
如果 C# 编译器/抖动在所使用的硬件上可用,是否使用融合乘加操作?如果是这样,是否需要设置任何特定的编译器设置才能利用它?
c++ - 如何从 AVX 寄存器中获取数据?
使用 MSVC 2013 和 AVX 1,我在寄存器中有 8 个浮点数:
现在我想调用inline void print(float) {...}
所有 8 个花车。看起来英特尔AVX intrisics 会使这变得相当复杂:
但是 MSVC 甚至没有这两个内在函数中的任何一个。当然,我可以将值写回内存并从那里加载,但我怀疑在汇编级别没有必要溢出寄存器。
奖金问:我当然想写
但 MSVC 不明白许多内在函数需要循环展开。如何在 8x32 浮点数上编写循环__m256 foo
?
floating-point - 我可以使用 AVX FMA 单元进行位精确的 52 位整数乘法吗?
AXV2 没有任何大于 32 位源的整数乘法。它确实提供32 x 32 -> 32乘法,以及32 x 32 -> 64乘法1,但没有 64 位源。
假设我需要输入大于 32 位但小于或等于 52 位的无符号乘法 - 我可以简单地使用浮点DP 乘法或 FMA 指令,并且当整数输入和结果可以用 52 位或更少的位表示(即,在 [0, 2^52-1] 范围内)?
我想要产品的所有 104 位的更一般的情况怎么样?或者整数乘积超过 52 位的情况(即,乘积在位索引 > 52 中具有非零值) - 但我只想要低 52 位?在后一种情况下,MUL
它将给我更高的位并舍入一些较低的位(也许这就是 IFMA 的帮助?)。
编辑:事实上,根据这个答案,它也许可以做任何高达 2^53 的事情——我忘记1
了尾数之前的隐含前导有效地给了你一点。
1有趣的是,正如 Mysticial在评论中解释的那样,64 位产品PMULDQ
操作的延迟是 32 位版本的一半,吞吐量是 32 位版本的两倍。PMULLD
floating-point - 了解 FMA 指令性能
我想了解如何最大限度地利用我的 CPU 上的操作数。我正在做一个简单的矩阵乘法程序,并且我有一个 Skylake 处理器。我正在查看维基百科页面以获取有关此架构的失败信息,但我很难理解它。
据我了解,FMA 指令允许 3 路 FP 输入对吗?并允许在它们之间的加法和乘法之间混合。但是当我只添加两个浮点数时会发生什么?它只是将它乘以一吗?我可以在 1 个周期中添加 3 个浮点数,还是会拆分?我看到 skylake,单精度输入有 32 个 FLOPs/cycle,但是“两个 8 宽 FMA 指令”是什么意思?
预先感谢您的解释
c++ - 处理融合乘加浮点不准确的通用方法
昨天我正在跟踪我的项目中的一个错误,几个小时后,我已经缩小到一段代码,它或多或少是在做这样的事情:
编译执行后:
从我的角度来看,有些地方是错误的,因为我要求对两个按位相同的对进行 2 次减法(我希望得到两个零),然后将它们平方(再次两个零)并将它们加在一起(零)。
事实证明,问题的根本原因是使用了 fused-multiply-add 操作,这使得结果不准确(从我的角度来看)。一般来说,我不反对这种优化,因为它承诺给出更准确的结果,但在这种情况下,1.34925e-06 与我期望的 0 相差甚远。
测试用例非常“脆弱”——如果您启用更多打印或更多断言,它将停止断言,因为编译器不再使用 fused-multiply-add。例如,如果我取消注释所有行:
由于我认为这是编译器中的一个错误,因此我已经报告了这一点,但由于解释这是正确的行为而关闭了它。
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=79436
所以我想知道-应该如何编写这样的计算来避免这个问题?我在考虑一个通用的解决方案,但比:
我想修复或改进我的代码 - 如果有任何需要修复/改进的东西 - 而不是-ffp-contract=off
为我的整个项目设置,因为无论如何在编译器库内部使用了 fused-multiply-add (我在 sinf 中看到了很多这样的内容( ) 和 cosf()),所以这将是一个“部分解决方法”,而不是一个解决方案......我也想避免像“不要使用浮点”这样的解决方案(;
c++ - _mm_fmadd_pd 程序收到信号SIGILL,非法指令
我收到以下代码的奇怪错误:
将代码编译为:
当我运行可执行文件时,我收到以下消息:
使用 gdb 以获取更多详细信息:
但是,当使用 valgrind 时,如下所示:
该程序似乎正在运行。我在这里缺少什么?如何以稳健的方式使用 _mm_fmadd_pd?无论在 Intel 或 AMD 处理器中运行,是否都可以使示例正常工作?无论使用g ++还是icpc都可以编译吗?