diff --git a/flang/include/flang/Optimizer/Transforms/Passes.h b/flang/include/flang/Optimizer/Transforms/Passes.h index 6970da8698ae8..d33623c690489 100644 --- a/flang/include/flang/Optimizer/Transforms/Passes.h +++ b/flang/include/flang/Optimizer/Transforms/Passes.h @@ -91,7 +91,9 @@ struct FunctionAttrTypes { std::unique_ptr createFunctionAttrPass(); std::unique_ptr -createFunctionAttrPass(FunctionAttrTypes &functionAttr); +createFunctionAttrPass(FunctionAttrTypes &functionAttr, bool noInfsFPMath, + bool noNaNsFPMath, bool approxFuncFPMath, + bool noSignedZerosFPMath, bool unsafeFPMath); // declarative passes #define GEN_PASS_REGISTRATION diff --git a/flang/include/flang/Optimizer/Transforms/Passes.td b/flang/include/flang/Optimizer/Transforms/Passes.td index e3c45d41f04cc..397985383b226 100644 --- a/flang/include/flang/Optimizer/Transforms/Passes.td +++ b/flang/include/flang/Optimizer/Transforms/Passes.td @@ -366,6 +366,21 @@ def FunctionAttr : Pass<"function-attr", "mlir::func::FuncOp"> { "mlir::LLVM::framePointerKind::FramePointerKind", /*default=*/"mlir::LLVM::framePointerKind::FramePointerKind{}", "frame pointer">, + Option<"noInfsFPMath", "no-infs-fp-math", + "bool", /*default=*/"false", + "Set the no-infs-fp-math attribute on functions in the module.">, + Option<"noNaNsFPMath", "no-nans-fp-math", + "bool", /*default=*/"false", + "Set the no-nans-fp-math attribute on functions in the module.">, + Option<"approxFuncFPMath", "approx-func-fp-math", + "bool", /*default=*/"false", + "Set the approx-func-fp-math attribute on functions in the module.">, + Option<"noSignedZerosFPMath", "no-signed-zeros-fp-math", + "bool", /*default=*/"false", + "Set the no-signed-zeros-fp-math attribute on functions in the module.">, + Option<"unsafeFPMath", "unsafe-fp-math", + "bool", /*default=*/"false", + "Set the unsafe-fp-math attribute on functions in the module.">, ]; let constructor = "::fir::createFunctionAttrPass()"; } diff --git a/flang/include/flang/Tools/CLOptions.inc b/flang/include/flang/Tools/CLOptions.inc index 96d3869cd0939..166ba5f58774d 100644 --- a/flang/include/flang/Tools/CLOptions.inc +++ b/flang/include/flang/Tools/CLOptions.inc @@ -315,15 +315,22 @@ inline void createDefaultFIRCodeGenPassPipeline( // Add function attributes fir::FunctionAttrTypes functionAttrs; - if (config.FramePointerKind != llvm::FramePointerKind::None) { + if (config.FramePointerKind != llvm::FramePointerKind::None || + config.NoInfsFPMath || config.NoNaNsFPMath || config.ApproxFuncFPMath || + config.NoSignedZerosFPMath || config.UnsafeFPMath) { if (config.FramePointerKind == llvm::FramePointerKind::NonLeaf) functionAttrs.framePointerKind = mlir::LLVM::framePointerKind::FramePointerKind::NonLeaf; - else + else if (config.FramePointerKind == llvm::FramePointerKind::All) functionAttrs.framePointerKind = mlir::LLVM::framePointerKind::FramePointerKind::All; + else + functionAttrs.framePointerKind = + mlir::LLVM::framePointerKind::FramePointerKind::None; - pm.addPass(fir::createFunctionAttrPass(functionAttrs)); + pm.addPass(fir::createFunctionAttrPass(functionAttrs, config.NoInfsFPMath, + config.NoNaNsFPMath, config.ApproxFuncFPMath, + config.NoSignedZerosFPMath, config.UnsafeFPMath)); } fir::addFIRToLLVMPass(pm, config); diff --git a/flang/include/flang/Tools/CrossToolHelpers.h b/flang/include/flang/Tools/CrossToolHelpers.h index b61224ff4f1b3..0f39bdb86102f 100644 --- a/flang/include/flang/Tools/CrossToolHelpers.h +++ b/flang/include/flang/Tools/CrossToolHelpers.h @@ -13,6 +13,7 @@ #ifndef FORTRAN_TOOLS_CROSS_TOOL_HELPERS_H #define FORTRAN_TOOLS_CROSS_TOOL_HELPERS_H +#include "flang/Common/MathOptionsBase.h" #include "flang/Frontend/CodeGenOptions.h" #include "flang/Frontend/LangOptions.h" #include @@ -28,7 +29,8 @@ struct MLIRToLLVMPassPipelineConfig { OptLevel = level; } explicit MLIRToLLVMPassPipelineConfig(llvm::OptimizationLevel level, - const Fortran::frontend::CodeGenOptions &opts) { + const Fortran::frontend::CodeGenOptions &opts, + const Fortran::common::MathOptionsBase &mathOpts) { OptLevel = level; StackArrays = opts.StackArrays; Underscoring = opts.Underscoring; @@ -36,6 +38,15 @@ struct MLIRToLLVMPassPipelineConfig { DebugInfo = opts.getDebugInfo(); AliasAnalysis = opts.AliasAnalysis; FramePointerKind = opts.getFramePointer(); + // The logic for setting these attributes is intended to match the logic + // used in Clang. + NoInfsFPMath = mathOpts.getNoHonorInfs(); + NoNaNsFPMath = mathOpts.getNoHonorNaNs(); + ApproxFuncFPMath = mathOpts.getApproxFunc(); + NoSignedZerosFPMath = mathOpts.getNoSignedZeros(); + UnsafeFPMath = mathOpts.getAssociativeMath() && + mathOpts.getReciprocalMath() && NoSignedZerosFPMath && + ApproxFuncFPMath && mathOpts.getFPContractEnabled(); } llvm::OptimizationLevel OptLevel; ///< optimisation level @@ -49,6 +60,13 @@ struct MLIRToLLVMPassPipelineConfig { llvm::FramePointerKind::None; ///< Add frame pointer to functions. unsigned VScaleMin = 0; ///< SVE vector range minimum. unsigned VScaleMax = 0; ///< SVE vector range maximum. + bool NoInfsFPMath = false; ///< Set no-infs-fp-math attribute for functions. + bool NoNaNsFPMath = false; ///< Set no-nans-fp-math attribute for functions. + bool ApproxFuncFPMath = + false; ///< Set approx-func-fp-math attribute for functions. + bool NoSignedZerosFPMath = + false; ///< Set no-signed-zeros-fp-math attribute for functions. + bool UnsafeFPMath = false; ///< Set unsafe-fp-math attribute for functions. }; struct OffloadModuleOpts { diff --git a/flang/lib/Frontend/FrontendActions.cpp b/flang/lib/Frontend/FrontendActions.cpp index 4738f7ba57042..25e0fe847876d 100644 --- a/flang/lib/Frontend/FrontendActions.cpp +++ b/flang/lib/Frontend/FrontendActions.cpp @@ -785,6 +785,7 @@ void CodeGenAction::generateLLVMIR() { CompilerInstance &ci = this->getInstance(); auto opts = ci.getInvocation().getCodeGenOpts(); + auto mathOpts = ci.getInvocation().getLoweringOpts().getMathOptions(); llvm::OptimizationLevel level = mapToLevel(opts); fir::support::loadDialects(*mlirCtx); @@ -797,7 +798,7 @@ void CodeGenAction::generateLLVMIR() { pm.addPass(std::make_unique()); pm.enableVerifier(/*verifyPasses=*/true); - MLIRToLLVMPassPipelineConfig config(level, opts); + MLIRToLLVMPassPipelineConfig config(level, opts, mathOpts); if (auto vsr = getVScaleRange(ci)) { config.VScaleMin = vsr->first; diff --git a/flang/lib/Optimizer/Transforms/FunctionAttr.cpp b/flang/lib/Optimizer/Transforms/FunctionAttr.cpp index 55b908ba5d861..f54080f21b967 100644 --- a/flang/lib/Optimizer/Transforms/FunctionAttr.cpp +++ b/flang/lib/Optimizer/Transforms/FunctionAttr.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "flang/Optimizer/Transforms/Passes.h" #include "mlir/Dialect/LLVMIR/LLVMAttrs.h" +#include "mlir/Dialect/LLVMIR/LLVMDialect.h" namespace fir { #define GEN_PASS_DECL_FUNCTIONATTR @@ -27,6 +28,11 @@ class FunctionAttrPass : public fir::impl::FunctionAttrBase { public: FunctionAttrPass(const fir::FunctionAttrOptions &options) { framePointerKind = options.framePointerKind; + noInfsFPMath = options.noInfsFPMath; + noNaNsFPMath = options.noNaNsFPMath; + approxFuncFPMath = options.approxFuncFPMath; + noSignedZerosFPMath = options.noSignedZerosFPMath; + unsafeFPMath = options.unsafeFPMath; } FunctionAttrPass() {} void runOnOperation() override; @@ -45,14 +51,43 @@ void FunctionAttrPass::runOnOperation() { func->setAttr("frame_pointer", mlir::LLVM::FramePointerKindAttr::get( context, framePointerKind)); + auto llvmFuncOpName = + mlir::OperationName(mlir::LLVM::LLVMFuncOp::getOperationName(), context); + if (noInfsFPMath) + func->setAttr( + mlir::LLVM::LLVMFuncOp::getNoInfsFpMathAttrName(llvmFuncOpName), + mlir::BoolAttr::get(context, true)); + if (noNaNsFPMath) + func->setAttr( + mlir::LLVM::LLVMFuncOp::getNoNansFpMathAttrName(llvmFuncOpName), + mlir::BoolAttr::get(context, true)); + if (approxFuncFPMath) + func->setAttr( + mlir::LLVM::LLVMFuncOp::getApproxFuncFpMathAttrName(llvmFuncOpName), + mlir::BoolAttr::get(context, true)); + if (noSignedZerosFPMath) + func->setAttr( + mlir::LLVM::LLVMFuncOp::getNoSignedZerosFpMathAttrName(llvmFuncOpName), + mlir::BoolAttr::get(context, true)); + if (unsafeFPMath) + func->setAttr( + mlir::LLVM::LLVMFuncOp::getUnsafeFpMathAttrName(llvmFuncOpName), + mlir::BoolAttr::get(context, true)); + LLVM_DEBUG(llvm::dbgs() << "=== End " DEBUG_TYPE " ===\n"); } -std::unique_ptr -fir::createFunctionAttrPass(fir::FunctionAttrTypes &functionAttr) { +std::unique_ptr fir::createFunctionAttrPass( + fir::FunctionAttrTypes &functionAttr, bool noInfsFPMath, bool noNaNsFPMath, + bool approxFuncFPMath, bool noSignedZerosFPMath, bool unsafeFPMath) { FunctionAttrOptions opts; // Frame pointer opts.framePointerKind = functionAttr.framePointerKind; + opts.noInfsFPMath = noInfsFPMath; + opts.noNaNsFPMath = noNaNsFPMath; + opts.approxFuncFPMath = approxFuncFPMath; + opts.noSignedZerosFPMath = noSignedZerosFPMath; + opts.unsafeFPMath = unsafeFPMath; return std::make_unique(opts); } diff --git a/flang/test/Driver/func-attr-fast-math.f90 b/flang/test/Driver/func-attr-fast-math.f90 new file mode 100644 index 0000000000000..05824a6078a09 --- /dev/null +++ b/flang/test/Driver/func-attr-fast-math.f90 @@ -0,0 +1,18 @@ +! RUN: %flang -O1 -emit-llvm -S -o - %s 2>&1| FileCheck %s --check-prefix=CHECK-NOFASTMATH +! RUN: %flang -Ofast -emit-llvm -S -o - %s 2>&1| FileCheck %s --check-prefix=CHECK-OFAST +! RUN: %flang -O1 -ffast-math -emit-llvm -S -o - %s 2>&1| FileCheck %s --check-prefix=CHECK-FFAST-MATH + +subroutine func +end subroutine func + +! CHECK-NOFASTMATH-LABEL: define void @func_() local_unnamed_addr +! CHECK-NOFASTMATH-SAME: #[[ATTRS:[0-9]+]] +! CHECK-NOT fp-math"= + +! CHECK-OFAST-LABEL: define void @func_() local_unnamed_addr +! CHECK-OFAST-SAME: #[[ATTRS:[0-9]+]] +! CHECK-OFAST: attributes #[[ATTRS]] = { {{.*}}"approx-func-fp-math"="true" {{.*}}"no-infs-fp-math"="true" {{.*}}"no-nans-fp-math"="true" {{.*}}"no-signed-zeros-fp-math"="true" {{.*}}"unsafe-fp-math"="true"{{.*}} } + +! CHECK-FFAST-MATH-LABEL: define void @func_() local_unnamed_addr +! CHECK-FFAST-MATH-SAME: #[[ATTRS:[0-9]+]] +! CHECK-FFAST-MATH: attributes #[[ATTRS]] = { {{.*}}"approx-func-fp-math"="true" {{.*}}"no-infs-fp-math"="true" {{.*}}"no-nans-fp-math"="true" {{.*}}"no-signed-zeros-fp-math"="true" {{.*}}"unsafe-fp-math"="true"{{.*}} }