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