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