aboutsummaryrefslogtreecommitdiff
path: root/flang
diff options
context:
space:
mode:
Diffstat (limited to 'flang')
-rw-r--r--flang/include/flang/Optimizer/Transforms/Passes.h4
-rw-r--r--flang/include/flang/Optimizer/Transforms/Passes.td15
-rw-r--r--flang/include/flang/Tools/CLOptions.inc13
-rw-r--r--flang/include/flang/Tools/CrossToolHelpers.h20
-rw-r--r--flang/lib/Frontend/FrontendActions.cpp3
-rw-r--r--flang/lib/Optimizer/Transforms/FunctionAttr.cpp39
-rw-r--r--flang/test/Driver/func-attr-fast-math.f9018
7 files changed, 104 insertions, 8 deletions
diff --git a/flang/include/flang/Optimizer/Transforms/Passes.h b/flang/include/flang/Optimizer/Transforms/Passes.h
index aefb277..e1d22c8 100644
--- a/flang/include/flang/Optimizer/Transforms/Passes.h
+++ b/flang/include/flang/Optimizer/Transforms/Passes.h
@@ -92,7 +92,9 @@ struct FunctionAttrTypes {
std::unique_ptr<mlir::Pass> createFunctionAttrPass();
std::unique_ptr<mlir::Pass>
-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 270b837..5fb576f 100644
--- a/flang/include/flang/Optimizer/Transforms/Passes.td
+++ b/flang/include/flang/Optimizer/Transforms/Passes.td
@@ -378,6 +378,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 8dee307..68e504d 100644
--- a/flang/include/flang/Tools/CLOptions.inc
+++ b/flang/include/flang/Tools/CLOptions.inc
@@ -316,15 +316,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 5c59c99..b7d84af 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 <cstdint>
@@ -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 09e861d..18bc168 100644
--- a/flang/lib/Frontend/FrontendActions.cpp
+++ b/flang/lib/Frontend/FrontendActions.cpp
@@ -782,6 +782,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);
@@ -794,7 +795,7 @@ void CodeGenAction::generateLLVMIR() {
pm.addPass(std::make_unique<Fortran::lower::VerifierPass>());
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 55b908b..f54080f 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<FunctionAttrPass> {
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<mlir::Pass>
-fir::createFunctionAttrPass(fir::FunctionAttrTypes &functionAttr) {
+std::unique_ptr<mlir::Pass> 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<FunctionAttrPass>(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 0000000..05824a6
--- /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"{{.*}} }