1 | //===- bbc.cpp - Burnside Bridge Compiler -----------------------*- 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 | // |
9 | // Coding style: https://mlir.llvm.org/getting_started/DeveloperGuide/ |
10 | // |
11 | //===----------------------------------------------------------------------===// |
12 | /// |
13 | /// This is a tool for translating Fortran sources to the FIR dialect of MLIR. |
14 | /// |
15 | //===----------------------------------------------------------------------===// |
16 | |
17 | #include "flang/Common/Fortran-features.h" |
18 | #include "flang/Common/OpenMP-features.h" |
19 | #include "flang/Common/Version.h" |
20 | #include "flang/Common/default-kinds.h" |
21 | #include "flang/Lower/Bridge.h" |
22 | #include "flang/Lower/PFTBuilder.h" |
23 | #include "flang/Lower/Support/Verifier.h" |
24 | #include "flang/Optimizer/Dialect/Support/FIRContext.h" |
25 | #include "flang/Optimizer/Dialect/Support/KindMapping.h" |
26 | #include "flang/Optimizer/Support/InitFIR.h" |
27 | #include "flang/Optimizer/Support/InternalNames.h" |
28 | #include "flang/Optimizer/Support/Utils.h" |
29 | #include "flang/Optimizer/Transforms/Passes.h" |
30 | #include "flang/Parser/characters.h" |
31 | #include "flang/Parser/dump-parse-tree.h" |
32 | #include "flang/Parser/message.h" |
33 | #include "flang/Parser/parse-tree-visitor.h" |
34 | #include "flang/Parser/parse-tree.h" |
35 | #include "flang/Parser/parsing.h" |
36 | #include "flang/Parser/provenance.h" |
37 | #include "flang/Parser/unparse.h" |
38 | #include "flang/Semantics/expression.h" |
39 | #include "flang/Semantics/runtime-type-info.h" |
40 | #include "flang/Semantics/semantics.h" |
41 | #include "flang/Semantics/unparse-with-symbols.h" |
42 | #include "flang/Tools/CrossToolHelpers.h" |
43 | #include "flang/Tools/TargetSetup.h" |
44 | #include "flang/Version.inc" |
45 | #include "mlir/Dialect/OpenMP/OpenMPDialect.h" |
46 | #include "mlir/IR/AsmState.h" |
47 | #include "mlir/IR/BuiltinOps.h" |
48 | #include "mlir/IR/MLIRContext.h" |
49 | #include "mlir/Parser/Parser.h" |
50 | #include "mlir/Pass/Pass.h" |
51 | #include "mlir/Pass/PassManager.h" |
52 | #include "mlir/Pass/PassRegistry.h" |
53 | #include "mlir/Transforms/GreedyPatternRewriteDriver.h" |
54 | #include "mlir/Transforms/Passes.h" |
55 | #include "llvm/MC/TargetRegistry.h" |
56 | #include "llvm/Passes/OptimizationLevel.h" |
57 | #include "llvm/Support/CommandLine.h" |
58 | #include "llvm/Support/ErrorOr.h" |
59 | #include "llvm/Support/FileSystem.h" |
60 | #include "llvm/Support/InitLLVM.h" |
61 | #include "llvm/Support/MemoryBuffer.h" |
62 | #include "llvm/Support/Path.h" |
63 | #include "llvm/Support/SourceMgr.h" |
64 | #include "llvm/Support/TargetSelect.h" |
65 | #include "llvm/Support/ToolOutputFile.h" |
66 | #include "llvm/Support/raw_ostream.h" |
67 | #include "llvm/TargetParser/Host.h" |
68 | #include "llvm/TargetParser/Triple.h" |
69 | #include <memory> |
70 | |
71 | //===----------------------------------------------------------------------===// |
72 | // Some basic command-line options |
73 | //===----------------------------------------------------------------------===// |
74 | |
75 | static llvm::cl::opt<std::string> inputFilename(llvm::cl::Positional, |
76 | llvm::cl::Required, |
77 | llvm::cl::desc("<input file>" )); |
78 | |
79 | static llvm::cl::opt<std::string> |
80 | outputFilename("o" , llvm::cl::desc("Specify the output filename" ), |
81 | llvm::cl::value_desc("filename" )); |
82 | |
83 | static llvm::cl::list<std::string> |
84 | includeDirs("I" , llvm::cl::desc("include module search paths" )); |
85 | |
86 | static llvm::cl::alias includeAlias("module-directory" , |
87 | llvm::cl::desc("module search directory" ), |
88 | llvm::cl::aliasopt(includeDirs)); |
89 | |
90 | static llvm::cl::list<std::string> |
91 | intrinsicIncludeDirs("J" , llvm::cl::desc("intrinsic module search paths" )); |
92 | |
93 | static llvm::cl::alias |
94 | intrinsicIncludeAlias("intrinsic-module-directory" , |
95 | llvm::cl::desc("intrinsic module directory" ), |
96 | llvm::cl::aliasopt(intrinsicIncludeDirs)); |
97 | |
98 | static llvm::cl::opt<std::string> |
99 | moduleDir("module" , llvm::cl::desc("module output directory (default .)" ), |
100 | llvm::cl::init(Val: "." )); |
101 | |
102 | static llvm::cl::opt<std::string> |
103 | moduleSuffix("module-suffix" , llvm::cl::desc("module file suffix override" ), |
104 | llvm::cl::init(Val: ".mod" )); |
105 | |
106 | static llvm::cl::opt<bool> |
107 | emitFIR("emit-fir" , |
108 | llvm::cl::desc("Dump the FIR created by lowering and exit" ), |
109 | llvm::cl::init(Val: false)); |
110 | |
111 | static llvm::cl::opt<bool> |
112 | emitHLFIR("emit-hlfir" , |
113 | llvm::cl::desc("Dump the HLFIR created by lowering and exit" ), |
114 | llvm::cl::init(Val: false)); |
115 | |
116 | static llvm::cl::opt<bool> warnStdViolation("Mstandard" , |
117 | llvm::cl::desc("emit warnings" ), |
118 | llvm::cl::init(Val: false)); |
119 | |
120 | static llvm::cl::opt<bool> warnIsError("Werror" , |
121 | llvm::cl::desc("warnings are errors" ), |
122 | llvm::cl::init(Val: false)); |
123 | |
124 | static llvm::cl::opt<bool> dumpSymbols("dump-symbols" , |
125 | llvm::cl::desc("dump the symbol table" ), |
126 | llvm::cl::init(Val: false)); |
127 | |
128 | static llvm::cl::opt<bool> pftDumpTest( |
129 | "pft-test" , |
130 | llvm::cl::desc("parse the input, create a PFT, dump it, and exit" ), |
131 | llvm::cl::init(Val: false)); |
132 | |
133 | static llvm::cl::opt<bool> enableOpenMP("fopenmp" , |
134 | llvm::cl::desc("enable openmp" ), |
135 | llvm::cl::init(Val: false)); |
136 | |
137 | static llvm::cl::opt<bool> |
138 | enableOpenMPDevice("fopenmp-is-target-device" , |
139 | llvm::cl::desc("enable openmp device compilation" ), |
140 | llvm::cl::init(Val: false)); |
141 | |
142 | static llvm::cl::opt<bool> |
143 | enableOpenMPGPU("fopenmp-is-gpu" , |
144 | llvm::cl::desc("enable openmp GPU target codegen" ), |
145 | llvm::cl::init(Val: false)); |
146 | |
147 | // A simplified subset of the OpenMP RTL Flags from Flang, only the primary |
148 | // positive options are available, no negative options e.g. fopen_assume* vs |
149 | // fno_open_assume* |
150 | static llvm::cl::opt<uint32_t> |
151 | setOpenMPVersion("fopenmp-version" , |
152 | llvm::cl::desc("OpenMP standard version" ), |
153 | llvm::cl::init(Val: 11)); |
154 | |
155 | static llvm::cl::opt<uint32_t> setOpenMPTargetDebug( |
156 | "fopenmp-target-debug" , |
157 | llvm::cl::desc("Enable debugging in the OpenMP offloading device RTL" ), |
158 | llvm::cl::init(Val: 0)); |
159 | |
160 | static llvm::cl::opt<bool> setOpenMPThreadSubscription( |
161 | "fopenmp-assume-threads-oversubscription" , |
162 | llvm::cl::desc("Assume work-shared loops do not have more " |
163 | "iterations than participating threads." ), |
164 | llvm::cl::init(Val: false)); |
165 | |
166 | static llvm::cl::opt<bool> setOpenMPTeamSubscription( |
167 | "fopenmp-assume-teams-oversubscription" , |
168 | llvm::cl::desc("Assume distributed loops do not have more iterations than " |
169 | "participating teams." ), |
170 | llvm::cl::init(Val: false)); |
171 | |
172 | static llvm::cl::opt<bool> setOpenMPNoThreadState( |
173 | "fopenmp-assume-no-thread-state" , |
174 | llvm::cl::desc( |
175 | "Assume that no thread in a parallel region will modify an ICV." ), |
176 | llvm::cl::init(Val: false)); |
177 | |
178 | static llvm::cl::opt<bool> setOpenMPNoNestedParallelism( |
179 | "fopenmp-assume-no-nested-parallelism" , |
180 | llvm::cl::desc("Assume that no thread in a parallel region will encounter " |
181 | "a parallel region." ), |
182 | llvm::cl::init(Val: false)); |
183 | |
184 | static llvm::cl::opt<bool> |
185 | setNoGPULib("nogpulib" , |
186 | llvm::cl::desc("Do not link device library for CUDA/HIP device " |
187 | "compilation" ), |
188 | llvm::cl::init(Val: false)); |
189 | |
190 | static llvm::cl::opt<bool> enableOpenACC("fopenacc" , |
191 | llvm::cl::desc("enable openacc" ), |
192 | llvm::cl::init(Val: false)); |
193 | |
194 | static llvm::cl::opt<bool> enableNoPPCNativeVecElemOrder( |
195 | "fno-ppc-native-vector-element-order" , |
196 | llvm::cl::desc("no PowerPC native vector element order." ), |
197 | llvm::cl::init(Val: false)); |
198 | |
199 | static llvm::cl::opt<bool> useHLFIR("hlfir" , |
200 | llvm::cl::desc("Lower to high level FIR" ), |
201 | llvm::cl::init(Val: true)); |
202 | |
203 | static llvm::cl::opt<bool> enableCUDA("fcuda" , |
204 | llvm::cl::desc("enable CUDA Fortran" ), |
205 | llvm::cl::init(Val: false)); |
206 | |
207 | static llvm::cl::opt<bool> fixedForm("ffixed-form" , |
208 | llvm::cl::desc("enable fixed form" ), |
209 | llvm::cl::init(Val: false)); |
210 | static llvm::cl::opt<std::string> |
211 | targetTripleOverride("target" , |
212 | llvm::cl::desc("Override host target triple" ), |
213 | llvm::cl::init(Val: "" )); |
214 | |
215 | #define FLANG_EXCLUDE_CODEGEN |
216 | #include "flang/Tools/CLOptions.inc" |
217 | |
218 | //===----------------------------------------------------------------------===// |
219 | |
220 | using ProgramName = std::string; |
221 | |
222 | // Print the module with the "module { ... }" wrapper, preventing |
223 | // information loss from attribute information appended to the module |
224 | static void printModule(mlir::ModuleOp mlirModule, llvm::raw_ostream &out) { |
225 | out << mlirModule << '\n'; |
226 | } |
227 | |
228 | static void registerAllPasses() { |
229 | fir::support::registerMLIRPassesForFortranTools(); |
230 | fir::registerOptTransformPasses(); |
231 | } |
232 | |
233 | /// Create a target machine that is at least sufficient to get data-layout |
234 | /// information required by flang semantics and lowering. Note that it may not |
235 | /// contain all the CPU feature information to get optimized assembly generation |
236 | /// from LLVM IR. Drivers that needs to generate assembly from LLVM IR should |
237 | /// create a target machine according to their specific options. |
238 | static std::unique_ptr<llvm::TargetMachine> |
239 | createTargetMachine(llvm::StringRef targetTriple, std::string &error) { |
240 | std::string triple{targetTriple}; |
241 | if (triple.empty()) |
242 | triple = llvm::sys::getDefaultTargetTriple(); |
243 | |
244 | const llvm::Target *theTarget = |
245 | llvm::TargetRegistry::lookupTarget(Triple: triple, Error&: error); |
246 | if (!theTarget) |
247 | return nullptr; |
248 | return std::unique_ptr<llvm::TargetMachine>{ |
249 | theTarget->createTargetMachine(TT: triple, /*CPU=*/"" , |
250 | /*Features=*/"" , Options: llvm::TargetOptions(), |
251 | /*Reloc::Model=*/RM: std::nullopt)}; |
252 | } |
253 | |
254 | /// Build and execute the OpenMPFIRPassPipeline with its own instance |
255 | /// of the pass manager, allowing it to be invoked as soon as it's |
256 | /// required without impacting the main pass pipeline that may be invoked |
257 | /// more than once for verification. |
258 | static mlir::LogicalResult runOpenMPPasses(mlir::ModuleOp mlirModule) { |
259 | mlir::PassManager pm(mlirModule->getName(), |
260 | mlir::OpPassManager::Nesting::Implicit); |
261 | fir::createOpenMPFIRPassPipeline(pm, enableOpenMPDevice); |
262 | (void)mlir::applyPassManagerCLOptions(pm); |
263 | if (mlir::failed(pm.run(mlirModule))) { |
264 | llvm::errs() << "FATAL: failed to correctly apply OpenMP pass pipeline" ; |
265 | return mlir::failure(); |
266 | } |
267 | return mlir::success(); |
268 | } |
269 | |
270 | //===----------------------------------------------------------------------===// |
271 | // Translate Fortran input to FIR, a dialect of MLIR. |
272 | //===----------------------------------------------------------------------===// |
273 | |
274 | static mlir::LogicalResult convertFortranSourceToMLIR( |
275 | std::string path, Fortran::parser::Options options, |
276 | const ProgramName &programPrefix, |
277 | Fortran::semantics::SemanticsContext &semanticsContext, |
278 | const mlir::PassPipelineCLParser &passPipeline, |
279 | const llvm::TargetMachine &targetMachine) { |
280 | |
281 | // prep for prescan and parse |
282 | Fortran::parser::Parsing parsing{semanticsContext.allCookedSources()}; |
283 | parsing.Prescan(path, options); |
284 | if (!parsing.messages().empty() && (parsing.messages().AnyFatalError())) { |
285 | llvm::errs() << programPrefix << "could not scan " << path << '\n'; |
286 | parsing.messages().Emit(llvm::errs(), parsing.allCooked()); |
287 | return mlir::failure(); |
288 | } |
289 | |
290 | // parse the input Fortran |
291 | parsing.Parse(llvm::outs()); |
292 | parsing.messages().Emit(llvm::errs(), parsing.allCooked()); |
293 | if (!parsing.consumedWholeFile()) { |
294 | parsing.EmitMessage(llvm::errs(), parsing.finalRestingPlace(), |
295 | "parser FAIL (final position)" , |
296 | "error: " , llvm::raw_ostream::RED); |
297 | return mlir::failure(); |
298 | } |
299 | if ((!parsing.messages().empty() && (parsing.messages().AnyFatalError())) || |
300 | !parsing.parseTree().has_value()) { |
301 | llvm::errs() << programPrefix << "could not parse " << path << '\n'; |
302 | return mlir::failure(); |
303 | } |
304 | |
305 | // run semantics |
306 | auto &parseTree = *parsing.parseTree(); |
307 | Fortran::semantics::Semantics semantics(semanticsContext, parseTree); |
308 | semantics.Perform(); |
309 | semantics.EmitMessages(llvm::errs()); |
310 | if (semantics.AnyFatalError()) { |
311 | llvm::errs() << programPrefix << "semantic errors in " << path << '\n'; |
312 | return mlir::failure(); |
313 | } |
314 | Fortran::semantics::RuntimeDerivedTypeTables tables; |
315 | if (!semantics.AnyFatalError()) { |
316 | tables = |
317 | Fortran::semantics::BuildRuntimeDerivedTypeTables(semanticsContext); |
318 | if (!tables.schemata) |
319 | llvm::errs() << programPrefix |
320 | << "could not find module file for __fortran_type_info\n" ; |
321 | } |
322 | |
323 | if (dumpSymbols) { |
324 | semantics.DumpSymbols(llvm::outs()); |
325 | return mlir::success(); |
326 | } |
327 | |
328 | if (pftDumpTest) { |
329 | if (auto ast = Fortran::lower::createPFT(parseTree, semanticsContext)) { |
330 | Fortran::lower::dumpPFT(llvm::outs(), *ast); |
331 | return mlir::success(); |
332 | } |
333 | llvm::errs() << "Pre FIR Tree is NULL.\n" ; |
334 | return mlir::failure(); |
335 | } |
336 | |
337 | // translate to FIR dialect of MLIR |
338 | mlir::DialectRegistry registry; |
339 | fir::support::registerNonCodegenDialects(registry); |
340 | fir::support::addFIRExtensions(registry); |
341 | mlir::MLIRContext ctx(registry); |
342 | fir::support::loadNonCodegenDialects(ctx); |
343 | auto &defKinds = semanticsContext.defaultKinds(); |
344 | fir::KindMapping kindMap( |
345 | &ctx, llvm::ArrayRef<fir::KindTy>{fir::fromDefaultKinds(defKinds)}); |
346 | std::string targetTriple = targetMachine.getTargetTriple().normalize(); |
347 | // Use default lowering options for bbc. |
348 | Fortran::lower::LoweringOptions loweringOptions{}; |
349 | loweringOptions.setNoPPCNativeVecElemOrder(enableNoPPCNativeVecElemOrder); |
350 | loweringOptions.setLowerToHighLevelFIR(useHLFIR || emitHLFIR); |
351 | std::vector<Fortran::lower::EnvironmentDefault> envDefaults = {}; |
352 | auto burnside = Fortran::lower::LoweringBridge::create( |
353 | ctx, semanticsContext, defKinds, semanticsContext.intrinsics(), |
354 | semanticsContext.targetCharacteristics(), parsing.allCooked(), |
355 | targetTriple, kindMap, loweringOptions, envDefaults, |
356 | semanticsContext.languageFeatures(), targetMachine); |
357 | mlir::ModuleOp mlirModule = burnside.getModule(); |
358 | if (enableOpenMP) { |
359 | if (enableOpenMPGPU && !enableOpenMPDevice) { |
360 | llvm::errs() << "FATAL: -fopenmp-is-gpu can only be set if " |
361 | "-fopenmp-is-target-device is also set" ; |
362 | return mlir::failure(); |
363 | } |
364 | auto offloadModuleOpts = |
365 | OffloadModuleOpts(setOpenMPTargetDebug, setOpenMPTeamSubscription, |
366 | setOpenMPThreadSubscription, setOpenMPNoThreadState, |
367 | setOpenMPNoNestedParallelism, enableOpenMPDevice, |
368 | enableOpenMPGPU, setOpenMPVersion, "" , setNoGPULib); |
369 | setOffloadModuleInterfaceAttributes(mlirModule, offloadModuleOpts); |
370 | setOpenMPVersionAttribute(mlirModule, setOpenMPVersion); |
371 | } |
372 | burnside.lower(parseTree, semanticsContext); |
373 | std::error_code ec; |
374 | std::string outputName = outputFilename; |
375 | if (!outputName.size()) |
376 | outputName = llvm::sys::path::stem(path: inputFilename).str().append(s: ".mlir" ); |
377 | llvm::raw_fd_ostream out(outputName, ec); |
378 | if (ec) |
379 | return mlir::emitError(mlir::UnknownLoc::get(&ctx), |
380 | "could not open output file " ) |
381 | << outputName; |
382 | |
383 | // WARNING: This pipeline must be run immediately after the lowering to |
384 | // ensure that the FIR is correct with respect to OpenMP operations/ |
385 | // attributes. |
386 | if (enableOpenMP) |
387 | if (mlir::failed(runOpenMPPasses(mlirModule))) |
388 | return mlir::failure(); |
389 | |
390 | // Otherwise run the default passes. |
391 | mlir::PassManager pm(mlirModule->getName(), |
392 | mlir::OpPassManager::Nesting::Implicit); |
393 | pm.enableVerifier(/*verifyPasses=*/true); |
394 | (void)mlir::applyPassManagerCLOptions(pm); |
395 | if (passPipeline.hasAnyOccurrences()) { |
396 | // run the command-line specified pipeline |
397 | hlfir::registerHLFIRPasses(); |
398 | (void)passPipeline.addToPipeline(pm, [&](const llvm::Twine &msg) { |
399 | mlir::emitError(mlir::UnknownLoc::get(&ctx)) << msg; |
400 | return mlir::failure(); |
401 | }); |
402 | } else if (emitFIR || emitHLFIR) { |
403 | // --emit-fir: Build the IR, verify it, and dump the IR if the IR passes |
404 | // verification. Use --dump-module-on-failure to dump invalid IR. |
405 | pm.addPass(std::make_unique<Fortran::lower::VerifierPass>()); |
406 | if (mlir::failed(pm.run(mlirModule))) { |
407 | llvm::errs() << "FATAL: verification of lowering to FIR failed" ; |
408 | return mlir::failure(); |
409 | } |
410 | |
411 | if (emitFIR && useHLFIR) { |
412 | // lower HLFIR to FIR |
413 | fir::createHLFIRToFIRPassPipeline(pm, llvm::OptimizationLevel::O2); |
414 | if (mlir::failed(pm.run(mlirModule))) { |
415 | llvm::errs() << "FATAL: lowering from HLFIR to FIR failed" ; |
416 | return mlir::failure(); |
417 | } |
418 | } |
419 | |
420 | printModule(mlirModule, out); |
421 | return mlir::success(); |
422 | } else { |
423 | // run the default canned pipeline |
424 | pm.addPass(std::make_unique<Fortran::lower::VerifierPass>()); |
425 | |
426 | // Add O2 optimizer pass pipeline. |
427 | fir::createDefaultFIROptimizerPassPipeline( |
428 | pm, MLIRToLLVMPassPipelineConfig(llvm::OptimizationLevel::O2)); |
429 | } |
430 | |
431 | if (mlir::succeeded(pm.run(mlirModule))) { |
432 | // Emit MLIR and do not lower to LLVM IR. |
433 | printModule(mlirModule, out); |
434 | return mlir::success(); |
435 | } |
436 | // Something went wrong. Try to dump the MLIR module. |
437 | llvm::errs() << "oops, pass manager reported failure\n" ; |
438 | return mlir::failure(); |
439 | } |
440 | |
441 | int main(int argc, char **argv) { |
442 | [[maybe_unused]] llvm::InitLLVM y(argc, argv); |
443 | llvm::InitializeAllTargets(); |
444 | llvm::InitializeAllTargetMCs(); |
445 | registerAllPasses(); |
446 | |
447 | mlir::registerMLIRContextCLOptions(); |
448 | mlir::registerAsmPrinterCLOptions(); |
449 | mlir::registerPassManagerCLOptions(); |
450 | mlir::PassPipelineCLParser passPipe("" , "Compiler passes to run" ); |
451 | llvm::cl::ParseCommandLineOptions(argc, argv, Overview: "Burnside Bridge Compiler\n" ); |
452 | |
453 | ProgramName programPrefix; |
454 | programPrefix = argv[0] + ": "s ; |
455 | |
456 | if (includeDirs.size() == 0) { |
457 | includeDirs.push_back(value: "." ); |
458 | // Default Fortran modules should be installed in include/flang (a sibling |
459 | // to the bin) directory. |
460 | intrinsicIncludeDirs.push_back( |
461 | value: llvm::sys::path::parent_path( |
462 | path: llvm::sys::path::parent_path( |
463 | path: llvm::sys::fs::getMainExecutable(argv0: argv[0], MainExecAddr: nullptr))) |
464 | .str() + |
465 | "/include/flang" ); |
466 | } |
467 | |
468 | Fortran::parser::Options options; |
469 | options.predefinitions.emplace_back("__flang__"s , "1"s ); |
470 | options.predefinitions.emplace_back("__flang_major__"s , |
471 | std::string{FLANG_VERSION_MAJOR_STRING}); |
472 | options.predefinitions.emplace_back("__flang_minor__"s , |
473 | std::string{FLANG_VERSION_MINOR_STRING}); |
474 | options.predefinitions.emplace_back( |
475 | "__flang_patchlevel__"s , std::string{FLANG_VERSION_PATCHLEVEL_STRING}); |
476 | |
477 | // enable parsing of OpenMP |
478 | if (enableOpenMP) { |
479 | options.features.Enable(Fortran::common::LanguageFeature::OpenMP); |
480 | Fortran::common::setOpenMPMacro(setOpenMPVersion, options.predefinitions); |
481 | } |
482 | |
483 | // enable parsing of OpenACC |
484 | if (enableOpenACC) { |
485 | options.features.Enable(Fortran::common::LanguageFeature::OpenACC); |
486 | options.predefinitions.emplace_back("_OPENACC" , "202211" ); |
487 | } |
488 | |
489 | // enable parsing of CUDA Fortran |
490 | if (enableCUDA) { |
491 | options.features.Enable(Fortran::common::LanguageFeature::CUDA); |
492 | } |
493 | |
494 | if (fixedForm) { |
495 | options.isFixedForm = fixedForm; |
496 | } |
497 | |
498 | Fortran::common::IntrinsicTypeDefaultKinds defaultKinds; |
499 | Fortran::parser::AllSources allSources; |
500 | Fortran::parser::AllCookedSources allCookedSources(allSources); |
501 | Fortran::semantics::SemanticsContext semanticsContext{ |
502 | defaultKinds, options.features, allCookedSources}; |
503 | semanticsContext.set_moduleDirectory(moduleDir) |
504 | .set_moduleFileSuffix(moduleSuffix) |
505 | .set_searchDirectories(includeDirs) |
506 | .set_intrinsicModuleDirectories(intrinsicIncludeDirs) |
507 | .set_warnOnNonstandardUsage(warnStdViolation) |
508 | .set_warningsAreErrors(warnIsError); |
509 | |
510 | std::string error; |
511 | // Create host target machine. |
512 | std::unique_ptr<llvm::TargetMachine> targetMachine = |
513 | createTargetMachine(targetTriple: targetTripleOverride, error); |
514 | if (!targetMachine) { |
515 | llvm::errs() << "failed to create target machine: " << error << "\n" ; |
516 | return mlir::failed(mlir::failure()); |
517 | } |
518 | std::string compilerVersion = Fortran::common::getFlangToolFullVersion("bbc" ); |
519 | std::string compilerOptions = "" ; |
520 | Fortran::tools::setUpTargetCharacteristics( |
521 | semanticsContext.targetCharacteristics(), *targetMachine, compilerVersion, |
522 | compilerOptions); |
523 | |
524 | return mlir::failed( |
525 | convertFortranSourceToMLIR(inputFilename, options, programPrefix, |
526 | semanticsContext, passPipe, *targetMachine)); |
527 | } |
528 | |