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

source code of flang/tools/bbc/bbc.cpp