Skip to content

Commit 6ad7944

Browse files
committed
[flang] Set the unsafe-fp-math=true if -ffast-math is set
Although the fast-math flag is set on individual IR operations, the function attribute isn't set. Clang sets both, and matching that seems sensible. Currently investigating if the lack of the function-level attribute is causing missed optimisations (although this would indicate an LLVM bug/omission, matching clang's IR codegen approach still doesn't seem a bad strategy).
1 parent 5052832 commit 6ad7944

File tree

6 files changed

+26
-6
lines changed

6 files changed

+26
-6
lines changed

flang/include/flang/Optimizer/Transforms/Passes.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ struct FunctionAttrTypes {
9191

9292
std::unique_ptr<mlir::Pass> createFunctionAttrPass();
9393
std::unique_ptr<mlir::Pass>
94-
createFunctionAttrPass(FunctionAttrTypes &functionAttr);
94+
createFunctionAttrPass(FunctionAttrTypes &functionAttr, bool unsafeFPMath);
9595

9696
// declarative passes
9797
#define GEN_PASS_REGISTRATION

flang/include/flang/Optimizer/Transforms/Passes.td

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -366,6 +366,9 @@ def FunctionAttr : Pass<"function-attr", "mlir::func::FuncOp"> {
366366
"mlir::LLVM::framePointerKind::FramePointerKind",
367367
/*default=*/"mlir::LLVM::framePointerKind::FramePointerKind{}",
368368
"frame pointer">,
369+
Option<"unsafeFPMath", "unsafe-fp-math",
370+
"bool", /*default=*/"false",
371+
"Set the unsafe-fp-math attribute on functions in the module.">,
369372
];
370373
let constructor = "::fir::createFunctionAttrPass()";
371374
}

flang/include/flang/Tools/CLOptions.inc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -315,15 +315,15 @@ inline void createDefaultFIRCodeGenPassPipeline(
315315
// Add function attributes
316316
fir::FunctionAttrTypes functionAttrs;
317317

318-
if (config.FramePointerKind != llvm::FramePointerKind::None) {
318+
if (config.FramePointerKind != llvm::FramePointerKind::None || config.UnsafeFPMath) {
319319
if (config.FramePointerKind == llvm::FramePointerKind::NonLeaf)
320320
functionAttrs.framePointerKind =
321321
mlir::LLVM::framePointerKind::FramePointerKind::NonLeaf;
322322
else
323323
functionAttrs.framePointerKind =
324324
mlir::LLVM::framePointerKind::FramePointerKind::All;
325325

326-
pm.addPass(fir::createFunctionAttrPass(functionAttrs));
326+
pm.addPass(fir::createFunctionAttrPass(functionAttrs, config.UnsafeFPMath));
327327
}
328328

329329
fir::addFIRToLLVMPass(pm, config);

flang/include/flang/Tools/CrossToolHelpers.h

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#ifndef FORTRAN_TOOLS_CROSS_TOOL_HELPERS_H
1414
#define FORTRAN_TOOLS_CROSS_TOOL_HELPERS_H
1515

16+
#include "flang/Common/MathOptionsBase.h"
1617
#include "flang/Frontend/CodeGenOptions.h"
1718
#include "flang/Frontend/LangOptions.h"
1819
#include <cstdint>
@@ -28,14 +29,22 @@ struct MLIRToLLVMPassPipelineConfig {
2829
OptLevel = level;
2930
}
3031
explicit MLIRToLLVMPassPipelineConfig(llvm::OptimizationLevel level,
31-
const Fortran::frontend::CodeGenOptions &opts) {
32+
const Fortran::frontend::CodeGenOptions &opts,
33+
const Fortran::common::MathOptionsBase &mathOpts) {
3234
OptLevel = level;
3335
StackArrays = opts.StackArrays;
3436
Underscoring = opts.Underscoring;
3537
LoopVersioning = opts.LoopVersioning;
3638
DebugInfo = opts.getDebugInfo();
3739
AliasAnalysis = opts.AliasAnalysis;
3840
FramePointerKind = opts.getFramePointer();
41+
// TODO: This matches the set of options enabled for Ofast, but this is
42+
// probably overkill. Sadly the precise semantics of unsafe-fp-math=true
43+
// don't seem to be clearly documented.
44+
UnsafeFPMath = mathOpts.getNoHonorNaNs() && mathOpts.getNoHonorInfs() &&
45+
mathOpts.getNoSignedZeros() && mathOpts.getReciprocalMath() &&
46+
mathOpts.getFPContractEnabled() && mathOpts.getApproxFunc() &&
47+
mathOpts.getAssociativeMath();
3948
}
4049

4150
llvm::OptimizationLevel OptLevel; ///< optimisation level
@@ -49,6 +58,7 @@ struct MLIRToLLVMPassPipelineConfig {
4958
llvm::FramePointerKind::None; ///< Add frame pointer to functions.
5059
unsigned VScaleMin = 0; ///< SVE vector range minimum.
5160
unsigned VScaleMax = 0; ///< SVE vector range maximum.
61+
bool UnsafeFPMath = false; ///< Set unsafe-fp-math attribute for functions.
5262
};
5363

5464
struct OffloadModuleOpts {

flang/lib/Frontend/FrontendActions.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -787,6 +787,7 @@ void CodeGenAction::generateLLVMIR() {
787787

788788
CompilerInstance &ci = this->getInstance();
789789
auto opts = ci.getInvocation().getCodeGenOpts();
790+
auto mathOpts = ci.getInvocation().getLoweringOpts().getMathOptions();
790791
llvm::OptimizationLevel level = mapToLevel(opts);
791792

792793
fir::support::loadDialects(*mlirCtx);
@@ -799,7 +800,7 @@ void CodeGenAction::generateLLVMIR() {
799800
pm.addPass(std::make_unique<Fortran::lower::VerifierPass>());
800801
pm.enableVerifier(/*verifyPasses=*/true);
801802

802-
MLIRToLLVMPassPipelineConfig config(level, opts);
803+
MLIRToLLVMPassPipelineConfig config(level, opts, mathOpts);
803804

804805
if (auto vsr = getVScaleRange(ci)) {
805806
config.VScaleMin = vsr->first;

flang/lib/Optimizer/Transforms/FunctionAttr.cpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ class FunctionAttrPass : public fir::impl::FunctionAttrBase<FunctionAttrPass> {
2727
public:
2828
FunctionAttrPass(const fir::FunctionAttrOptions &options) {
2929
framePointerKind = options.framePointerKind;
30+
unsafeFPMath = options.unsafeFPMath;
3031
}
3132
FunctionAttrPass() {}
3233
void runOnOperation() override;
@@ -45,14 +46,19 @@ void FunctionAttrPass::runOnOperation() {
4546
func->setAttr("frame_pointer", mlir::LLVM::FramePointerKindAttr::get(
4647
context, framePointerKind));
4748

49+
if (unsafeFPMath)
50+
func->setAttr("unsafe_fp_math", mlir::BoolAttr::get(context, true));
51+
4852
LLVM_DEBUG(llvm::dbgs() << "=== End " DEBUG_TYPE " ===\n");
4953
}
5054

5155
std::unique_ptr<mlir::Pass>
52-
fir::createFunctionAttrPass(fir::FunctionAttrTypes &functionAttr) {
56+
fir::createFunctionAttrPass(fir::FunctionAttrTypes &functionAttr,
57+
bool unsafeFPMath) {
5358
FunctionAttrOptions opts;
5459
// Frame pointer
5560
opts.framePointerKind = functionAttr.framePointerKind;
61+
opts.unsafeFPMath = unsafeFPMath;
5662

5763
return std::make_unique<FunctionAttrPass>(opts);
5864
}

0 commit comments

Comments
 (0)