From 8f3f15c1a208932689a8bdef22d6ca3d4c3408c5 Mon Sep 17 00:00:00 2001 From: Slava Zakharin Date: Mon, 7 Nov 2022 09:05:27 -0800 Subject: [PATCH] [flang] Configure FirOpBuilder based on math driver options. 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 | 25 ++++++++++++ flang/include/flang/Common/MathOptionsBase.h | 44 ++++++++++++++++++++++ flang/include/flang/Lower/LoweringOptions.h | 12 ++++++ flang/include/flang/Optimizer/Builder/FIRBuilder.h | 5 +++ flang/lib/Frontend/CompilerInvocation.cpp | 12 +++++- flang/lib/Lower/Bridge.cpp | 3 ++ flang/lib/Lower/LoweringOptions.cpp | 2 +- flang/lib/Optimizer/Builder/FIRBuilder.cpp | 12 ++++++ flang/test/Lower/fast-math-arithmetic.f90 | 13 +++++++ 9 files changed, 126 insertions(+), 2 deletions(-) create mode 100644 flang/include/flang/Common/MathOptionsBase.def create mode 100644 flang/include/flang/Common/MathOptionsBase.h create mode 100644 flang/test/Lower/fast-math-arithmetic.f90 diff --git a/flang/include/flang/Common/MathOptionsBase.def b/flang/include/flang/Common/MathOptionsBase.def new file mode 100644 index 0000000..64b3959 --- /dev/null +++ b/flang/include/flang/Common/MathOptionsBase.def @@ -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 index 0000000..7f8ebdb --- /dev/null +++ b/flang/include/flang/Common/MathOptionsBase.h @@ -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(Name); } \ + MathOptionsBase &set##Name(Type Value) { \ + Name = static_cast(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 diff --git a/flang/include/flang/Lower/LoweringOptions.h b/flang/include/flang/Lower/LoweringOptions.h index dd297e41..8105ccd 100644 --- a/flang/include/flang/Lower/LoweringOptions.h +++ b/flang/include/flang/Lower/LoweringOptions.h @@ -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 diff --git a/flang/include/flang/Optimizer/Builder/FIRBuilder.h b/flang/include/flang/Optimizer/Builder/FIRBuilder.h index 5a43b17..a28ada9 100644 --- a/flang/include/flang/Optimizer/Builder/FIRBuilder.h +++ b/flang/include/flang/Optimizer/Builder/FIRBuilder.h @@ -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(); diff --git a/flang/lib/Frontend/CompilerInvocation.cpp b/flang/lib/Frontend/CompilerInvocation.cpp index bb87ea2..f218014 100644 --- a/flang/lib/Frontend/CompilerInvocation.cpp +++ b/flang/lib/Frontend/CompilerInvocation.cpp @@ -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); } diff --git a/flang/lib/Lower/Bridge.cpp b/flang/lib/Lower/Bridge.cpp index e9490b8..6ab001b 100644 --- a/flang/lib/Lower/Bridge.cpp +++ b/flang/lib/Lower/Bridge.cpp @@ -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(); diff --git a/flang/lib/Lower/LoweringOptions.cpp b/flang/lib/Lower/LoweringOptions.cpp index 22247fa..9456abf 100644 --- a/flang/lib/Lower/LoweringOptions.cpp +++ b/flang/lib/Lower/LoweringOptions.cpp @@ -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" diff --git a/flang/lib/Optimizer/Builder/FIRBuilder.cpp b/flang/lib/Optimizer/Builder/FIRBuilder.cpp index 59cc058..50fc21b 100644 --- a/flang/lib/Optimizer/Builder/FIRBuilder.cpp +++ b/flang/lib/Optimizer/Builder/FIRBuilder.cpp @@ -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 index 0000000..cc7a7dc --- /dev/null +++ b/flang/test/Lower/fast-math-arithmetic.f90 @@ -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 -- 2.7.4