xref: /llvm-project/flang/include/flang/Tools/CrossToolHelpers.h (revision c870632ef6162fbdccaad8cd09420728220ad344)
1 //===-- Tools/CrossToolHelpers.h --------------------------------- *-C++-*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 // A header file for containing functionallity that is used across Flang tools,
9 // such as helper functions which apply or generate information needed accross
10 // tools like bbc and flang.
11 //===----------------------------------------------------------------------===//
12 
13 #ifndef FORTRAN_TOOLS_CROSS_TOOL_HELPERS_H
14 #define FORTRAN_TOOLS_CROSS_TOOL_HELPERS_H
15 
16 #include "flang/Common/LangOptions.h"
17 #include "flang/Common/MathOptionsBase.h"
18 #include "flang/Frontend/CodeGenOptions.h"
19 #include <cstdint>
20 
21 #include "mlir/Dialect/OpenMP/OpenMPDialect.h"
22 #include "mlir/IR/BuiltinOps.h"
23 #include "mlir/Pass/PassRegistry.h"
24 #include "llvm/ADT/SmallVector.h"
25 #include "llvm/Frontend/Debug/Options.h"
26 #include "llvm/Passes/OptimizationLevel.h"
27 
28 // Flang Extension Point Callbacks
29 class FlangEPCallBacks {
30 public:
31   void registerFIROptEarlyEPCallbacks(
32       const std::function<void(mlir::PassManager &, llvm::OptimizationLevel)>
33           &C) {
34     FIROptEarlyEPCallbacks.push_back(C);
35   }
36 
37   void registerFIRInlinerCallback(
38       const std::function<void(mlir::PassManager &, llvm::OptimizationLevel)>
39           &C) {
40     FIRInlinerCallback.push_back(C);
41   }
42 
43   void registerFIROptLastEPCallbacks(
44       const std::function<void(mlir::PassManager &, llvm::OptimizationLevel)>
45           &C) {
46     FIROptLastEPCallbacks.push_back(C);
47   }
48 
49   void invokeFIROptEarlyEPCallbacks(
50       mlir::PassManager &pm, llvm::OptimizationLevel optLevel) {
51     for (auto &C : FIROptEarlyEPCallbacks)
52       C(pm, optLevel);
53   };
54 
55   void invokeFIRInlinerCallback(
56       mlir::PassManager &pm, llvm::OptimizationLevel optLevel) {
57     for (auto &C : FIRInlinerCallback)
58       C(pm, optLevel);
59   };
60 
61   void invokeFIROptLastEPCallbacks(
62       mlir::PassManager &pm, llvm::OptimizationLevel optLevel) {
63     for (auto &C : FIROptLastEPCallbacks)
64       C(pm, optLevel);
65   };
66 
67 private:
68   llvm::SmallVector<
69       std::function<void(mlir::PassManager &, llvm::OptimizationLevel)>, 1>
70       FIROptEarlyEPCallbacks;
71 
72   llvm::SmallVector<
73       std::function<void(mlir::PassManager &, llvm::OptimizationLevel)>, 1>
74       FIRInlinerCallback;
75 
76   llvm::SmallVector<
77       std::function<void(mlir::PassManager &, llvm::OptimizationLevel)>, 1>
78       FIROptLastEPCallbacks;
79 };
80 
81 /// Configuriation for the MLIR to LLVM pass pipeline.
82 struct MLIRToLLVMPassPipelineConfig : public FlangEPCallBacks {
83   explicit MLIRToLLVMPassPipelineConfig(llvm::OptimizationLevel level) {
84     OptLevel = level;
85   }
86   explicit MLIRToLLVMPassPipelineConfig(llvm::OptimizationLevel level,
87       const Fortran::frontend::CodeGenOptions &opts,
88       const Fortran::common::MathOptionsBase &mathOpts) {
89     OptLevel = level;
90     StackArrays = opts.StackArrays;
91     Underscoring = opts.Underscoring;
92     LoopVersioning = opts.LoopVersioning;
93     DebugInfo = opts.getDebugInfo();
94     AliasAnalysis = opts.AliasAnalysis;
95     FramePointerKind = opts.getFramePointer();
96     // The logic for setting these attributes is intended to match the logic
97     // used in Clang.
98     NoInfsFPMath = mathOpts.getNoHonorInfs();
99     NoNaNsFPMath = mathOpts.getNoHonorNaNs();
100     ApproxFuncFPMath = mathOpts.getApproxFunc();
101     NoSignedZerosFPMath = mathOpts.getNoSignedZeros();
102     UnsafeFPMath = mathOpts.getAssociativeMath() &&
103         mathOpts.getReciprocalMath() && NoSignedZerosFPMath &&
104         ApproxFuncFPMath && mathOpts.getFPContractEnabled();
105   }
106 
107   llvm::OptimizationLevel OptLevel; ///< optimisation level
108   bool StackArrays = false; ///< convert memory allocations to alloca.
109   bool Underscoring = true; ///< add underscores to function names.
110   bool LoopVersioning = false; ///< Run the version loop pass.
111   bool AliasAnalysis = false; ///< Add TBAA tags to generated LLVMIR
112   llvm::codegenoptions::DebugInfoKind DebugInfo =
113       llvm::codegenoptions::NoDebugInfo; ///< Debug info generation.
114   llvm::FramePointerKind FramePointerKind =
115       llvm::FramePointerKind::None; ///< Add frame pointer to functions.
116   unsigned VScaleMin = 0; ///< SVE vector range minimum.
117   unsigned VScaleMax = 0; ///< SVE vector range maximum.
118   bool NoInfsFPMath = false; ///< Set no-infs-fp-math attribute for functions.
119   bool NoNaNsFPMath = false; ///< Set no-nans-fp-math attribute for functions.
120   bool ApproxFuncFPMath =
121       false; ///< Set approx-func-fp-math attribute for functions.
122   bool NoSignedZerosFPMath =
123       false; ///< Set no-signed-zeros-fp-math attribute for functions.
124   bool UnsafeFPMath = false; ///< Set unsafe-fp-math attribute for functions.
125   bool NSWOnLoopVarInc = true; ///< Add nsw flag to loop variable increments.
126   bool EnableOpenMP = false; ///< Enable OpenMP lowering.
127 };
128 
129 struct OffloadModuleOpts {
130   OffloadModuleOpts() {}
131   OffloadModuleOpts(uint32_t OpenMPTargetDebug, bool OpenMPTeamSubscription,
132       bool OpenMPThreadSubscription, bool OpenMPNoThreadState,
133       bool OpenMPNoNestedParallelism, bool OpenMPIsTargetDevice,
134       bool OpenMPIsGPU, bool OpenMPForceUSM, uint32_t OpenMPVersion,
135       std::string OMPHostIRFile = {},
136       const std::vector<llvm::Triple> &OMPTargetTriples = {},
137       bool NoGPULib = false)
138       : OpenMPTargetDebug(OpenMPTargetDebug),
139         OpenMPTeamSubscription(OpenMPTeamSubscription),
140         OpenMPThreadSubscription(OpenMPThreadSubscription),
141         OpenMPNoThreadState(OpenMPNoThreadState),
142         OpenMPNoNestedParallelism(OpenMPNoNestedParallelism),
143         OpenMPIsTargetDevice(OpenMPIsTargetDevice), OpenMPIsGPU(OpenMPIsGPU),
144         OpenMPForceUSM(OpenMPForceUSM), OpenMPVersion(OpenMPVersion),
145         OMPHostIRFile(OMPHostIRFile),
146         OMPTargetTriples(OMPTargetTriples.begin(), OMPTargetTriples.end()),
147         NoGPULib(NoGPULib) {}
148 
149   OffloadModuleOpts(Fortran::common::LangOptions &Opts)
150       : OpenMPTargetDebug(Opts.OpenMPTargetDebug),
151         OpenMPTeamSubscription(Opts.OpenMPTeamSubscription),
152         OpenMPThreadSubscription(Opts.OpenMPThreadSubscription),
153         OpenMPNoThreadState(Opts.OpenMPNoThreadState),
154         OpenMPNoNestedParallelism(Opts.OpenMPNoNestedParallelism),
155         OpenMPIsTargetDevice(Opts.OpenMPIsTargetDevice),
156         OpenMPIsGPU(Opts.OpenMPIsGPU), OpenMPForceUSM(Opts.OpenMPForceUSM),
157         OpenMPVersion(Opts.OpenMPVersion), OMPHostIRFile(Opts.OMPHostIRFile),
158         OMPTargetTriples(Opts.OMPTargetTriples), NoGPULib(Opts.NoGPULib) {}
159 
160   uint32_t OpenMPTargetDebug = 0;
161   bool OpenMPTeamSubscription = false;
162   bool OpenMPThreadSubscription = false;
163   bool OpenMPNoThreadState = false;
164   bool OpenMPNoNestedParallelism = false;
165   bool OpenMPIsTargetDevice = false;
166   bool OpenMPIsGPU = false;
167   bool OpenMPForceUSM = false;
168   uint32_t OpenMPVersion = 11;
169   std::string OMPHostIRFile = {};
170   std::vector<llvm::Triple> OMPTargetTriples = {};
171   bool NoGPULib = false;
172 };
173 
174 //  Shares assinging of the OpenMP OffloadModuleInterface and its assorted
175 //  attributes accross Flang tools (bbc/flang)
176 [[maybe_unused]] static void setOffloadModuleInterfaceAttributes(
177     mlir::ModuleOp module, OffloadModuleOpts Opts) {
178   // Should be registered by the OpenMPDialect
179   if (auto offloadMod = llvm::dyn_cast<mlir::omp::OffloadModuleInterface>(
180           module.getOperation())) {
181     offloadMod.setIsTargetDevice(Opts.OpenMPIsTargetDevice);
182     offloadMod.setIsGPU(Opts.OpenMPIsGPU);
183     if (Opts.OpenMPForceUSM) {
184       offloadMod.setRequires(mlir::omp::ClauseRequires::unified_shared_memory);
185     }
186     if (Opts.OpenMPIsTargetDevice) {
187       offloadMod.setFlags(Opts.OpenMPTargetDebug, Opts.OpenMPTeamSubscription,
188           Opts.OpenMPThreadSubscription, Opts.OpenMPNoThreadState,
189           Opts.OpenMPNoNestedParallelism, Opts.OpenMPVersion, Opts.NoGPULib);
190 
191       if (!Opts.OMPHostIRFile.empty())
192         offloadMod.setHostIRFilePath(Opts.OMPHostIRFile);
193     }
194     auto strTriples = llvm::to_vector(llvm::map_range(Opts.OMPTargetTriples,
195         [](llvm::Triple triple) { return triple.normalize(); }));
196     offloadMod.setTargetTriples(strTriples);
197   }
198 }
199 
200 [[maybe_unused]] static void setOpenMPVersionAttribute(
201     mlir::ModuleOp module, int64_t version) {
202   module.getOperation()->setAttr(
203       mlir::StringAttr::get(module.getContext(), llvm::Twine{"omp.version"}),
204       mlir::omp::VersionAttr::get(module.getContext(), version));
205 }
206 
207 [[maybe_unused]] static int64_t getOpenMPVersionAttribute(
208     mlir::ModuleOp module, int64_t fallback = -1) {
209   if (mlir::Attribute verAttr = module->getAttr("omp.version"))
210     return llvm::cast<mlir::omp::VersionAttr>(verAttr).getVersion();
211   return fallback;
212 }
213 
214 #endif // FORTRAN_TOOLS_CROSS_TOOL_HELPERS_H
215