[llvm-dev] RFC: change -fp-contract=off to actually disable FMAs
Scott Manley via llvm-dev
llvm-dev at lists.llvm.org
Wed Jul 10 12:27:17 PDT 2019
There is no way to disable FMAs with 'fast' ops in LLVM. I would like to
propose that LLVM's -fp-contract=off should disable fusion, regardless of
any other flags since the Clang option suggests this to be the case:
$ clang --help | grep fp-contract
-ffp-contract=<value> Form fused FP ops (e.g. FMAs): fast (everywhere)
| on (according to FP_CONTRACT pragma, default) | off (never fuse)
Current behaviour in LLVM 8.0 below:
$ cat fma.ll
define double @fmadd(double %a, double %b, double %c) {
%mul = fmul fast double %b, %a
%add = fadd fast double %mul, %c
ret double %add
}
$ llc -mattr=+fma fma.ll -fp-contract=off -o - | grep vfmadd
vfmadd213sd %xmm2, %xmm1, %xmm0 # xmm0 = (xmm1 * xmm0) + xmm2
It still generates an fma due to the logic in DAGCombiner:
bool CanFuse = Options.UnsafeFPMath || isContractable(N);
bool AllowFusionGlobally = (Options.AllowFPOpFusion == FPOpFusion::Fast ||
CanFuse || HasFMAD);
In this case, UnsafeFPMath is false but isContractable() is true since the
FADD node is tagged as 'fast'. A simple fix would just be to check for
-fp-contract=off, however, I also found there is disagreement in the LLVM
-fp-contract option itself:
in TargetOptions.h, =off maps to FPOpFusion::Strict and says "Never fuse
FP-ops", yet the actual cl::opt for =off/Strict says: "Only fuse FP ops
when the result won't be affected".
Which is it supposed to be? At a minimum we should clear up the
discrepancy, but there are two general approaches I see:
Option 1:
- rename Strict to Off in llvm and always diable FMAs with this option
- does not require changes to Clang
Example logic:
bool AllowFusionGlobally = Options.AllowFPOpFusion != FPOpFusion::Off &&
(Options.AllowFPOpFusion == FPOpFusion::Fast ||
CanFuse || HasFMAD);
Option 2:
- keep =strict, add =off to turn off FMAs
- add =strict to clang as it does not currently exist
- tie uses of ::Strict to the presence of FMAD (which might have been the
intention?)
Example logic:
bool AllowFusionGlobally = Options.AllowFPOpFusion != FPOpFusion::Off &&
(Options.AllowFPOpFusion == FPOpFusion::Fast ||
CanFuse ||
(HasFMAD && Options.AllowFPOpFusion ==
FPOpFusion::Strict));
Is there context I am not aware of for ::Strict and ISD::FMAD? I could see
value in generating FMAs when its expanded form would be identical -- but
curious if that was actually the intent or not. If it is, perhaps we could
allow "Standard/on" to fuse ops if FMAD is available instead of the
"Strict" level? In any case, we should still have a way to explicitly turn
off FMAs.
Thanks,
Scott
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20190710/4012c144/attachment.html>
More information about the llvm-dev
mailing list