[TargetVersion] Only enable on RISC-V and AArch64 (#115991)
[llvm-project.git] / flang / tools / bbc / bbc.cpp
blob1c24979bbcdafb5f6668e88815a939415a15f40c
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/
11 //===----------------------------------------------------------------------===//
12 ///
13 /// This is a tool for translating Fortran sources to the FIR dialect of MLIR.
14 ///
15 //===----------------------------------------------------------------------===//
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>
74 //===----------------------------------------------------------------------===//
75 // Some basic command-line options
76 //===----------------------------------------------------------------------===//
78 static llvm::cl::opt<std::string> inputFilename(llvm::cl::Positional,
79 llvm::cl::Required,
80 llvm::cl::desc("<input file>"));
82 static llvm::cl::opt<std::string>
83 outputFilename("o", llvm::cl::desc("Specify the output filename"),
84 llvm::cl::value_desc("filename"));
86 static llvm::cl::list<std::string>
87 includeDirs("I", llvm::cl::desc("include module search paths"));
89 static llvm::cl::alias includeAlias("module-directory",
90 llvm::cl::desc("module search directory"),
91 llvm::cl::aliasopt(includeDirs));
93 static llvm::cl::list<std::string>
94 intrinsicIncludeDirs("J", llvm::cl::desc("intrinsic module search paths"));
96 static llvm::cl::alias
97 intrinsicIncludeAlias("intrinsic-module-directory",
98 llvm::cl::desc("intrinsic module directory"),
99 llvm::cl::aliasopt(intrinsicIncludeDirs));
101 static llvm::cl::opt<std::string>
102 moduleDir("module", llvm::cl::desc("module output directory (default .)"),
103 llvm::cl::init("."));
105 static llvm::cl::opt<std::string>
106 moduleSuffix("module-suffix", llvm::cl::desc("module file suffix override"),
107 llvm::cl::init(".mod"));
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));
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));
119 static llvm::cl::opt<bool> warnStdViolation("Mstandard",
120 llvm::cl::desc("emit warnings"),
121 llvm::cl::init(false));
123 static llvm::cl::opt<bool> warnIsError("Werror",
124 llvm::cl::desc("warnings are errors"),
125 llvm::cl::init(false));
127 static llvm::cl::opt<bool> dumpSymbols("dump-symbols",
128 llvm::cl::desc("dump the symbol table"),
129 llvm::cl::init(false));
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));
136 static llvm::cl::opt<bool> enableOpenMP("fopenmp",
137 llvm::cl::desc("enable openmp"),
138 llvm::cl::init(false));
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));
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));
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));
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);
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));
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));
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));
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));
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));
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));
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));
203 static llvm::cl::opt<bool> enableOpenACC("fopenacc",
204 llvm::cl::desc("enable openacc"),
205 llvm::cl::init(false));
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));
212 static llvm::cl::opt<bool> useHLFIR("hlfir",
213 llvm::cl::desc("Lower to high level FIR"),
214 llvm::cl::init(true));
216 static llvm::cl::opt<bool> enableCUDA("fcuda",
217 llvm::cl::desc("enable CUDA Fortran"),
218 llvm::cl::init(false));
220 static llvm::cl::opt<std::string>
221 enableGPUMode("gpu", llvm::cl::desc("Enable GPU Mode managed|unified"),
222 llvm::cl::init(""));
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(""));
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));
237 // TODO: integrate this option with the above
238 static llvm::cl::opt<bool>
239 setNSW("integer-overflow",
240 llvm::cl::desc("add nsw flag to internal operations"),
241 llvm::cl::init(false));
243 #define FLANG_EXCLUDE_CODEGEN
244 #include "flang/Optimizer/Passes/CommandLineOpts.h"
245 #include "flang/Optimizer/Passes/Pipelines.h"
247 //===----------------------------------------------------------------------===//
249 using ProgramName = std::string;
251 // Print the module with the "module { ... }" wrapper, preventing
252 // information loss from attribute information appended to the module
253 static void printModule(mlir::ModuleOp mlirModule, llvm::raw_ostream &out) {
254 out << mlirModule << '\n';
257 static void registerAllPasses() {
258 fir::support::registerMLIRPassesForFortranTools();
259 fir::registerOptTransformPasses();
262 /// Create a target machine that is at least sufficient to get data-layout
263 /// information required by flang semantics and lowering. Note that it may not
264 /// contain all the CPU feature information to get optimized assembly generation
265 /// from LLVM IR. Drivers that needs to generate assembly from LLVM IR should
266 /// create a target machine according to their specific options.
267 static std::unique_ptr<llvm::TargetMachine>
268 createTargetMachine(llvm::StringRef targetTriple, std::string &error) {
269 std::string triple{targetTriple};
270 if (triple.empty())
271 triple = llvm::sys::getDefaultTargetTriple();
273 const llvm::Target *theTarget =
274 llvm::TargetRegistry::lookupTarget(triple, error);
275 if (!theTarget)
276 return nullptr;
277 return std::unique_ptr<llvm::TargetMachine>{
278 theTarget->createTargetMachine(triple, /*CPU=*/"",
279 /*Features=*/"", llvm::TargetOptions(),
280 /*Reloc::Model=*/std::nullopt)};
283 /// Build and execute the OpenMPFIRPassPipeline with its own instance
284 /// of the pass manager, allowing it to be invoked as soon as it's
285 /// required without impacting the main pass pipeline that may be invoked
286 /// more than once for verification.
287 static llvm::LogicalResult runOpenMPPasses(mlir::ModuleOp mlirModule) {
288 mlir::PassManager pm(mlirModule->getName(),
289 mlir::OpPassManager::Nesting::Implicit);
290 fir::createOpenMPFIRPassPipeline(pm, enableOpenMPDevice);
291 (void)mlir::applyPassManagerCLOptions(pm);
292 if (mlir::failed(pm.run(mlirModule))) {
293 llvm::errs() << "FATAL: failed to correctly apply OpenMP pass pipeline";
294 return mlir::failure();
296 return mlir::success();
299 //===----------------------------------------------------------------------===//
300 // Translate Fortran input to FIR, a dialect of MLIR.
301 //===----------------------------------------------------------------------===//
303 static llvm::LogicalResult convertFortranSourceToMLIR(
304 std::string path, Fortran::parser::Options options,
305 const ProgramName &programPrefix,
306 Fortran::semantics::SemanticsContext &semanticsContext,
307 const mlir::PassPipelineCLParser &passPipeline,
308 const llvm::TargetMachine &targetMachine) {
310 // prep for prescan and parse
311 Fortran::parser::Parsing parsing{semanticsContext.allCookedSources()};
312 parsing.Prescan(path, options);
313 if (!parsing.messages().empty() && (parsing.messages().AnyFatalError())) {
314 llvm::errs() << programPrefix << "could not scan " << path << '\n';
315 parsing.messages().Emit(llvm::errs(), parsing.allCooked());
316 return mlir::failure();
319 // parse the input Fortran
320 parsing.Parse(llvm::outs());
321 if (!parsing.consumedWholeFile()) {
322 parsing.messages().Emit(llvm::errs(), parsing.allCooked());
323 parsing.EmitMessage(llvm::errs(), parsing.finalRestingPlace(),
324 "parser FAIL (final position)",
325 "error: ", llvm::raw_ostream::RED);
326 return mlir::failure();
327 } else if ((!parsing.messages().empty() &&
328 (parsing.messages().AnyFatalError())) ||
329 !parsing.parseTree().has_value()) {
330 parsing.messages().Emit(llvm::errs(), parsing.allCooked());
331 llvm::errs() << programPrefix << "could not parse " << path << '\n';
332 return mlir::failure();
333 } else {
334 semanticsContext.messages().Annex(std::move(parsing.messages()));
337 // run semantics
338 auto &parseTree = *parsing.parseTree();
339 Fortran::semantics::Semantics semantics(semanticsContext, parseTree);
340 semantics.Perform();
341 semantics.EmitMessages(llvm::errs());
342 if (semantics.AnyFatalError()) {
343 llvm::errs() << programPrefix << "semantic errors in " << path << '\n';
344 return mlir::failure();
346 Fortran::semantics::RuntimeDerivedTypeTables tables;
347 if (!semantics.AnyFatalError()) {
348 tables =
349 Fortran::semantics::BuildRuntimeDerivedTypeTables(semanticsContext);
350 if (!tables.schemata)
351 llvm::errs() << programPrefix
352 << "could not find module file for __fortran_type_info\n";
355 if (dumpSymbols) {
356 semantics.DumpSymbols(llvm::outs());
357 return mlir::success();
360 if (pftDumpTest) {
361 if (auto ast = Fortran::lower::createPFT(parseTree, semanticsContext)) {
362 Fortran::lower::dumpPFT(llvm::outs(), *ast);
363 return mlir::success();
365 llvm::errs() << "Pre FIR Tree is NULL.\n";
366 return mlir::failure();
369 // translate to FIR dialect of MLIR
370 mlir::DialectRegistry registry;
371 fir::support::registerNonCodegenDialects(registry);
372 fir::support::addFIRExtensions(registry);
373 mlir::MLIRContext ctx(registry);
374 fir::support::loadNonCodegenDialects(ctx);
375 auto &defKinds = semanticsContext.defaultKinds();
376 fir::KindMapping kindMap(
377 &ctx, llvm::ArrayRef<fir::KindTy>{fir::fromDefaultKinds(defKinds)});
378 std::string targetTriple = targetMachine.getTargetTriple().normalize();
379 // Use default lowering options for bbc.
380 Fortran::lower::LoweringOptions loweringOptions{};
381 loweringOptions.setNoPPCNativeVecElemOrder(enableNoPPCNativeVecElemOrder);
382 loweringOptions.setLowerToHighLevelFIR(useHLFIR || emitHLFIR);
383 loweringOptions.setIntegerWrapAround(integerWrapAround);
384 loweringOptions.setNSWOnLoopVarInc(setNSW);
385 std::vector<Fortran::lower::EnvironmentDefault> envDefaults = {};
386 Fortran::frontend::TargetOptions targetOpts;
387 Fortran::frontend::CodeGenOptions cgOpts;
388 auto burnside = Fortran::lower::LoweringBridge::create(
389 ctx, semanticsContext, defKinds, semanticsContext.intrinsics(),
390 semanticsContext.targetCharacteristics(), parsing.allCooked(),
391 targetTriple, kindMap, loweringOptions, envDefaults,
392 semanticsContext.languageFeatures(), targetMachine, targetOpts, cgOpts);
393 mlir::ModuleOp mlirModule = burnside.getModule();
394 if (enableOpenMP) {
395 if (enableOpenMPGPU && !enableOpenMPDevice) {
396 llvm::errs() << "FATAL: -fopenmp-is-gpu can only be set if "
397 "-fopenmp-is-target-device is also set";
398 return mlir::failure();
400 // Construct offloading target triples vector.
401 std::vector<llvm::Triple> targetTriples;
402 targetTriples.reserve(targetTriplesOpenMP.size());
403 for (llvm::StringRef s : targetTriplesOpenMP)
404 targetTriples.emplace_back(s);
406 auto offloadModuleOpts = OffloadModuleOpts(
407 setOpenMPTargetDebug, setOpenMPTeamSubscription,
408 setOpenMPThreadSubscription, setOpenMPNoThreadState,
409 setOpenMPNoNestedParallelism, enableOpenMPDevice, enableOpenMPGPU,
410 enableOpenMPForceUSM, setOpenMPVersion, "", targetTriples, setNoGPULib);
411 setOffloadModuleInterfaceAttributes(mlirModule, offloadModuleOpts);
412 setOpenMPVersionAttribute(mlirModule, setOpenMPVersion);
414 burnside.lower(parseTree, semanticsContext);
415 std::error_code ec;
416 std::string outputName = outputFilename;
417 if (!outputName.size())
418 outputName = llvm::sys::path::stem(inputFilename).str().append(".mlir");
419 llvm::raw_fd_ostream out(outputName, ec);
420 if (ec)
421 return mlir::emitError(mlir::UnknownLoc::get(&ctx),
422 "could not open output file ")
423 << outputName;
425 // WARNING: This pipeline must be run immediately after the lowering to
426 // ensure that the FIR is correct with respect to OpenMP operations/
427 // attributes.
428 if (enableOpenMP)
429 if (mlir::failed(runOpenMPPasses(mlirModule)))
430 return mlir::failure();
432 // Otherwise run the default passes.
433 mlir::PassManager pm(mlirModule->getName(),
434 mlir::OpPassManager::Nesting::Implicit);
435 pm.enableVerifier(/*verifyPasses=*/true);
436 (void)mlir::applyPassManagerCLOptions(pm);
437 if (passPipeline.hasAnyOccurrences()) {
438 // run the command-line specified pipeline
439 hlfir::registerHLFIRPasses();
440 (void)passPipeline.addToPipeline(pm, [&](const llvm::Twine &msg) {
441 mlir::emitError(mlir::UnknownLoc::get(&ctx)) << msg;
442 return mlir::failure();
444 } else if (emitFIR || emitHLFIR) {
445 // --emit-fir: Build the IR, verify it, and dump the IR if the IR passes
446 // verification. Use --dump-module-on-failure to dump invalid IR.
447 pm.addPass(std::make_unique<Fortran::lower::VerifierPass>());
448 if (mlir::failed(pm.run(mlirModule))) {
449 llvm::errs() << "FATAL: verification of lowering to FIR failed";
450 return mlir::failure();
453 if (emitFIR && useHLFIR) {
454 // lower HLFIR to FIR
455 fir::createHLFIRToFIRPassPipeline(pm, enableOpenMP,
456 llvm::OptimizationLevel::O2);
457 if (mlir::failed(pm.run(mlirModule))) {
458 llvm::errs() << "FATAL: lowering from HLFIR to FIR failed";
459 return mlir::failure();
463 printModule(mlirModule, out);
464 return mlir::success();
465 } else {
466 // run the default canned pipeline
467 pm.addPass(std::make_unique<Fortran::lower::VerifierPass>());
469 // Add O2 optimizer pass pipeline.
470 MLIRToLLVMPassPipelineConfig config(llvm::OptimizationLevel::O2);
471 if (enableOpenMP)
472 config.EnableOpenMP = true;
473 config.NSWOnLoopVarInc = setNSW;
474 fir::registerDefaultInlinerPass(config);
475 fir::createDefaultFIROptimizerPassPipeline(pm, config);
478 if (mlir::succeeded(pm.run(mlirModule))) {
479 // Emit MLIR and do not lower to LLVM IR.
480 printModule(mlirModule, out);
481 return mlir::success();
483 // Something went wrong. Try to dump the MLIR module.
484 llvm::errs() << "oops, pass manager reported failure\n";
485 return mlir::failure();
488 int main(int argc, char **argv) {
489 [[maybe_unused]] llvm::InitLLVM y(argc, argv);
490 llvm::InitializeAllTargets();
491 llvm::InitializeAllTargetMCs();
492 registerAllPasses();
494 mlir::registerMLIRContextCLOptions();
495 mlir::registerAsmPrinterCLOptions();
496 mlir::registerPassManagerCLOptions();
497 mlir::PassPipelineCLParser passPipe("", "Compiler passes to run");
498 llvm::cl::ParseCommandLineOptions(argc, argv, "Burnside Bridge Compiler\n");
500 ProgramName programPrefix;
501 programPrefix = argv[0] + ": "s;
503 if (includeDirs.size() == 0) {
504 includeDirs.push_back(".");
505 // Default Fortran modules should be installed in include/flang (a sibling
506 // to the bin) directory.
507 intrinsicIncludeDirs.push_back(
508 llvm::sys::path::parent_path(
509 llvm::sys::path::parent_path(
510 llvm::sys::fs::getMainExecutable(argv[0], nullptr)))
511 .str() +
512 "/include/flang");
515 Fortran::parser::Options options;
516 options.predefinitions.emplace_back("__flang__"s, "1"s);
517 options.predefinitions.emplace_back("__flang_major__"s,
518 std::string{FLANG_VERSION_MAJOR_STRING});
519 options.predefinitions.emplace_back("__flang_minor__"s,
520 std::string{FLANG_VERSION_MINOR_STRING});
521 options.predefinitions.emplace_back(
522 "__flang_patchlevel__"s, std::string{FLANG_VERSION_PATCHLEVEL_STRING});
524 Fortran::common::LangOptions langOpts;
525 langOpts.NoGPULib = setNoGPULib;
526 langOpts.OpenMPVersion = setOpenMPVersion;
527 langOpts.OpenMPIsTargetDevice = enableOpenMPDevice;
528 langOpts.OpenMPIsGPU = enableOpenMPGPU;
529 langOpts.OpenMPForceUSM = enableOpenMPForceUSM;
530 langOpts.OpenMPTargetDebug = setOpenMPTargetDebug;
531 langOpts.OpenMPThreadSubscription = setOpenMPThreadSubscription;
532 langOpts.OpenMPTeamSubscription = setOpenMPTeamSubscription;
533 langOpts.OpenMPNoThreadState = setOpenMPNoThreadState;
534 langOpts.OpenMPNoNestedParallelism = setOpenMPNoNestedParallelism;
535 std::transform(targetTriplesOpenMP.begin(), targetTriplesOpenMP.end(),
536 std::back_inserter(langOpts.OMPTargetTriples),
537 [](const std::string &str) { return llvm::Triple(str); });
539 // enable parsing of OpenMP
540 if (enableOpenMP) {
541 options.features.Enable(Fortran::common::LanguageFeature::OpenMP);
542 Fortran::common::setOpenMPMacro(setOpenMPVersion, options.predefinitions);
545 // enable parsing of OpenACC
546 if (enableOpenACC) {
547 options.features.Enable(Fortran::common::LanguageFeature::OpenACC);
548 options.predefinitions.emplace_back("_OPENACC", "202211");
551 // enable parsing of CUDA Fortran
552 if (enableCUDA) {
553 options.features.Enable(Fortran::common::LanguageFeature::CUDA);
556 if (enableGPUMode == "managed") {
557 options.features.Enable(Fortran::common::LanguageFeature::CudaManaged);
558 } else if (enableGPUMode == "unified") {
559 options.features.Enable(Fortran::common::LanguageFeature::CudaUnified);
562 if (fixedForm) {
563 options.isFixedForm = fixedForm;
566 Fortran::common::IntrinsicTypeDefaultKinds defaultKinds;
567 Fortran::parser::AllSources allSources;
568 Fortran::parser::AllCookedSources allCookedSources(allSources);
569 Fortran::semantics::SemanticsContext semanticsContext{
570 defaultKinds, options.features, langOpts, allCookedSources};
571 semanticsContext.set_moduleDirectory(moduleDir)
572 .set_moduleFileSuffix(moduleSuffix)
573 .set_searchDirectories(includeDirs)
574 .set_intrinsicModuleDirectories(intrinsicIncludeDirs)
575 .set_warnOnNonstandardUsage(warnStdViolation)
576 .set_warningsAreErrors(warnIsError);
578 std::string error;
579 // Create host target machine.
580 std::unique_ptr<llvm::TargetMachine> targetMachine =
581 createTargetMachine(targetTripleOverride, error);
582 if (!targetMachine) {
583 llvm::errs() << "failed to create target machine: " << error << "\n";
584 return mlir::failed(mlir::failure());
586 std::string compilerVersion = Fortran::common::getFlangToolFullVersion("bbc");
587 std::string compilerOptions = "";
588 Fortran::tools::setUpTargetCharacteristics(
589 semanticsContext.targetCharacteristics(), *targetMachine, {},
590 compilerVersion, compilerOptions);
592 return mlir::failed(
593 convertFortranSourceToMLIR(inputFilename, options, programPrefix,
594 semanticsContext, passPipe, *targetMachine));