[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

Example logic:

  bool AllowFusionGlobally = Options.AllowFPOpFusion != FPOpFusion::Off &&
                             (Options.AllowFPOpFusion == FPOpFusion::Fast ||
                              CanFuse ||
                             (HasFMAD && Options.AllowFPOpFusion ==

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.


-------------- 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