Index: flang/include/flang/Common/MathOptionsBase.h =================================================================== --- /dev/null +++ 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 Index: flang/include/flang/Common/MathOptionsBase.def =================================================================== --- /dev/null +++ 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 Index: flang/include/flang/Lower/LoweringOptions.h =================================================================== --- flang/include/flang/Lower/LoweringOptions.h +++ 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 @@ #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: flang/include/flang/Optimizer/Builder/FIRBuilder.h =================================================================== --- flang/include/flang/Optimizer/Builder/FIRBuilder.h +++ 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 @@ 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: flang/lib/Frontend/CompilerInvocation.cpp =================================================================== --- flang/lib/Frontend/CompilerInvocation.cpp +++ flang/lib/Frontend/CompilerInvocation.cpp @@ -914,8 +914,18 @@ /// 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: flang/lib/Lower/Bridge.cpp =================================================================== --- flang/lib/Lower/Bridge.cpp +++ flang/lib/Lower/Bridge.cpp @@ -2884,6 +2884,7 @@ 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 @@ 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: flang/lib/Lower/LoweringOptions.cpp =================================================================== --- flang/lib/Lower/LoweringOptions.cpp +++ 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" Index: flang/lib/Optimizer/Builder/FIRBuilder.cpp =================================================================== --- flang/lib/Optimizer/Builder/FIRBuilder.cpp +++ flang/lib/Optimizer/Builder/FIRBuilder.cpp @@ -583,6 +583,18 @@ 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 //===--------------------------------------------------------------------===// Index: flang/test/Lower/fast-math-arithmetic.f90 =================================================================== --- /dev/null +++ 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