[flang] Configure FirOpBuilder based on math driver options.
authorSlava Zakharin <szakharin@nvidia.com>
Mon, 7 Nov 2022 17:05:27 +0000 (09:05 -0800)
committerSlava Zakharin <szakharin@nvidia.com>
Mon, 7 Nov 2022 17:26:46 +0000 (09:26 -0800)
Added MathOptionsBase to share fastmath config between different
components. Frontend driver translates LangOptions into MathOptionsBase.
FirConverter configures FirOpBuilder using MathOptionsBase
config passed to it via LoweringOptions.

Depends on D137390

Reviewed By: jeanPerier

Differential Revision: https://reviews.llvm.org/D137391

flang/include/flang/Common/MathOptionsBase.def [new file with mode: 0644]
flang/include/flang/Common/MathOptionsBase.h [new file with mode: 0644]
flang/include/flang/Lower/LoweringOptions.h
flang/include/flang/Optimizer/Builder/FIRBuilder.h
flang/lib/Frontend/CompilerInvocation.cpp
flang/lib/Lower/Bridge.cpp
flang/lib/Lower/LoweringOptions.cpp
flang/lib/Optimizer/Builder/FIRBuilder.cpp
flang/test/Lower/fast-math-arithmetic.f90 [new file with mode: 0644]

diff --git a/flang/include/flang/Common/MathOptionsBase.def b/flang/include/flang/Common/MathOptionsBase.def
new file mode 100644 (file)
index 0000000..64b3959
--- /dev/null
@@ -0,0 +1,25 @@
+//===--- MathOptionsBase.def - Math options config ---------------- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// This file defines math options. Users of this file must define
+/// ENUM_MATHOPT macro to make use of this information.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef ENUM_MATHOPT
+#  error Define the ENUM_MATHOPT macro to handle lowering options
+#endif
+
+/// Allow fusing FP operations (e.g. create FMAs from mul/add).
+ENUM_MATHOPT(FPContractEnabled, unsigned, 1, 0)
+
+/// Permit floating point optimizations without regard to infinities.
+ENUM_MATHOPT(NoHonorInfs, unsigned, 1, 0)
+
+#undef ENUM_MATHOPT
diff --git a/flang/include/flang/Common/MathOptionsBase.h b/flang/include/flang/Common/MathOptionsBase.h
new file mode 100644 (file)
index 0000000..7f8ebdb
--- /dev/null
@@ -0,0 +1,44 @@
+//===- MathOptionsBase.h - Math options config ------------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Options controlling mathematical computations generated in FIR.
+/// This is intended to be header-only implementation without extra
+/// dependencies so that multiple components can use it to exchange
+/// math configuration.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef FORTRAN_COMMON_MATHOPTIONSBASE_H
+#define FORTRAN_COMMON_MATHOPTIONSBASE_H
+
+namespace Fortran::common {
+
+class MathOptionsBase {
+public:
+#define ENUM_MATHOPT(Name, Type, Bits, Default) \
+  Type get##Name() const { return static_cast<Type>(Name); } \
+  MathOptionsBase &set##Name(Type Value) { \
+    Name = static_cast<unsigned>(Value); \
+    return *this; \
+  }
+#include "flang/Common/MathOptionsBase.def"
+
+  MathOptionsBase() {
+#define ENUM_MATHOPT(Name, Type, Bits, Default) set##Name(Default);
+#include "flang/Common/MathOptionsBase.def"
+  }
+
+private:
+#define ENUM_MATHOPT(Name, Type, Bits, Default) unsigned Name : Bits;
+#include "flang/Common/MathOptionsBase.def"
+};
+
+} // namespace Fortran::common
+
+#endif // FORTRAN_COMMON_MATHOPTIONSBASE_H
index dd297e4..8105ccd 100644 (file)
@@ -15,6 +15,8 @@
 #ifndef FLANG_LOWER_LOWERINGOPTIONS_H
 #define FLANG_LOWER_LOWERINGOPTIONS_H
 
+#include "flang/Common/MathOptionsBase.h"
+
 namespace Fortran::lower {
 
 class LoweringOptionsBase {
@@ -42,6 +44,16 @@ public:
 #include "flang/Lower/LoweringOptions.def"
 
   LoweringOptions();
+
+  const Fortran::common::MathOptionsBase &getMathOptions() const {
+    return MathOptions;
+  }
+
+  Fortran::common::MathOptionsBase &getMathOptions() { return MathOptions; }
+
+private:
+  /// Options for handling/optimizing mathematical computations.
+  Fortran::common::MathOptionsBase MathOptions;
 };
 
 } // namespace Fortran::lower
index 5a43b17..a28ada9 100644 (file)
@@ -16,6 +16,7 @@
 #ifndef FORTRAN_OPTIMIZER_BUILDER_FIRBUILDER_H
 #define FORTRAN_OPTIMIZER_BUILDER_FIRBUILDER_H
 
+#include "flang/Common/MathOptionsBase.h"
 #include "flang/Optimizer/Dialect/FIROps.h"
 #include "flang/Optimizer/Dialect/FIRType.h"
 #include "flang/Optimizer/Support/KindMapping.h"
@@ -409,6 +410,10 @@ public:
     fastMathFlags = flags;
   }
 
+  /// Set default FastMathFlags value from the passed MathOptionsBase
+  /// config.
+  void setFastMathFlags(Fortran::common::MathOptionsBase options);
+
   /// Dump the current function. (debug)
   LLVM_DUMP_METHOD void dumpFunc();
 
index bb87ea2..f218014 100644 (file)
@@ -944,8 +944,18 @@ void CompilerInvocation::setSemanticsOpts(
 /// Set \p loweringOptions controlling lowering behavior based
 /// on the \p optimizationLevel.
 void CompilerInvocation::setLoweringOptions() {
-  const auto &codegenOpts = getCodeGenOpts();
+  const CodeGenOptions &codegenOpts = getCodeGenOpts();
 
   // Lower TRANSPOSE as a runtime call under -O0.
   loweringOpts.setOptimizeTranspose(codegenOpts.OptimizationLevel > 0);
+
+  const LangOptions &langOptions = getLangOpts();
+  Fortran::common::MathOptionsBase &mathOpts = loweringOpts.getMathOptions();
+  // TODO: when LangOptions are finalized, we can represent
+  //       the math related options using Fortran::commmon::MathOptionsBase,
+  //       so that we can just copy it into LoweringOptions.
+  mathOpts
+      .setFPContractEnabled(langOptions.getFPContractMode() ==
+                            LangOptions::FPM_Fast)
+      .setNoHonorInfs(langOptions.NoHonorInfs);
 }
index e9490b8..6ab001b 100644 (file)
@@ -2884,6 +2884,7 @@ private:
     mlir::func::FuncOp func = callee.addEntryBlockAndMapArguments();
     builder = new fir::FirOpBuilder(func, bridge.getKindMap());
     assert(builder && "FirOpBuilder did not instantiate");
+    builder->setFastMathFlags(bridge.getLoweringOptions().getMathOptions());
     builder->setInsertionPointToStart(&func.front());
     func.setVisibility(mlir::SymbolTable::Visibility::Public);
 
@@ -3087,6 +3088,8 @@ private:
         mlir::FunctionType::get(context, llvm::None, llvm::None));
     func.addEntryBlock();
     builder = new fir::FirOpBuilder(func, bridge.getKindMap());
+    assert(builder && "FirOpBuilder did not instantiate");
+    builder->setFastMathFlags(bridge.getLoweringOptions().getMathOptions());
     createGlobals();
     if (mlir::Region *region = func.getCallableRegion())
       region->dropAllReferences();
index 22247fa..9456abf 100644 (file)
@@ -14,7 +14,7 @@
 
 namespace Fortran::lower {
 
-LoweringOptions::LoweringOptions() {
+LoweringOptions::LoweringOptions() : MathOptions{} {
 #define LOWERINGOPT(Name, Bits, Default) Name = Default;
 #define ENUM_LOWERINGOPT(Name, Type, Bits, Default) set##Name(Default);
 #include "flang/Lower/LoweringOptions.def"
index 59cc058..50fc21b 100644 (file)
@@ -583,6 +583,18 @@ void fir::FirOpBuilder::setCommonAttributes(mlir::Operation *op) const {
                                       op->getContext(), fastMathFlags));
 }
 
+void fir::FirOpBuilder::setFastMathFlags(
+    Fortran::common::MathOptionsBase options) {
+  mlir::arith::FastMathFlags arithFMF{};
+  if (options.getFPContractEnabled()) {
+    arithFMF = arithFMF | mlir::arith::FastMathFlags::contract;
+  }
+  if (options.getNoHonorInfs()) {
+    arithFMF = arithFMF | mlir::arith::FastMathFlags::ninf;
+  }
+  setFastMathFlags(arithFMF);
+}
+
 //===--------------------------------------------------------------------===//
 // ExtendedValue inquiry helper implementation
 //===--------------------------------------------------------------------===//
diff --git a/flang/test/Lower/fast-math-arithmetic.f90 b/flang/test/Lower/fast-math-arithmetic.f90
new file mode 100644 (file)
index 0000000..cc7a7dc
--- /dev/null
@@ -0,0 +1,13 @@
+! RUN: %flang_fc1 -emit-fir -ffp-contract=fast %s -o - 2>&1 | FileCheck --check-prefixes=CONTRACT,ALL %s
+! RUN: %flang_fc1 -emit-fir -menable-no-infs %s -o - 2>&1 | FileCheck --check-prefixes=NINF,ALL %s
+
+! ALL-LABEL: func.func @_QPtest
+subroutine test(x)
+  real x
+! CONTRACT: arith.mulf{{.*}}, {{.*}} fastmath<[[ATTRS:contract]]> : f32
+! NINF: arith.mulf{{.*}}, {{.*}} fastmath<[[ATTRS:ninf]]> : f32
+! ALL: arith.divf{{.*}}, {{.*}} fastmath<[[ATTRS]]> : f32
+! ALL: arith.addf{{.*}}, {{.*}} fastmath<[[ATTRS]]> : f32
+! ALL: arith.subf{{.*}}, {{.*}} fastmath<[[ATTRS]]> : f32
+  x = x * x + x / x - x
+end subroutine test