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 enableDoConcurrentOffload("fdoconcurrent-offload",
228 llvm::cl::desc("enable do concurrent offload"),
229 llvm::cl::init(Val: false));
230
231static llvm::cl::opt<bool>
232 disableCUDAWarpFunction("fcuda-disable-warp-function",
233 llvm::cl::desc("Disable CUDA Warp Function"),
234 llvm::cl::init(Val: false));
235
236static llvm::cl::opt<std::string>
237 enableGPUMode("gpu", llvm::cl::desc("Enable GPU Mode managed|unified"),
238 llvm::cl::init(Val: ""));
239
240static llvm::cl::opt<bool> fixedForm("ffixed-form",
241 llvm::cl::desc("enable fixed form"),
242 llvm::cl::init(Val: false));
243static llvm::cl::opt<std::string>
244 targetTripleOverride("target",
245 llvm::cl::desc("Override host target triple"),
246 llvm::cl::init(Val: ""));
247
248static llvm::cl::opt<bool> integerWrapAround(
249 "fwrapv",
250 llvm::cl::desc("Treat signed integer overflow as two's complement"),
251 llvm::cl::init(Val: false));
252
253static llvm::cl::opt<bool> initGlobalZero(
254 "finit-global-zero",
255 llvm::cl::desc("Zero initialize globals without default initialization"),
256 llvm::cl::init(Val: true));
257
258static llvm::cl::opt<bool>
259 reallocateLHS("frealloc-lhs",
260 llvm::cl::desc("Follow Fortran 2003 rules for (re)allocating "
261 "the LHS of the intrinsic assignment"),
262 llvm::cl::init(Val: true));
263
264static llvm::cl::opt<bool> stackRepackArrays(
265 "fstack-repack-arrays",
266 llvm::cl::desc("Allocate temporary arrays for -frepack-arrays "
267 "in stack memory"),
268 llvm::cl::init(Val: false));
269
270static llvm::cl::opt<bool>
271 repackArrays("frepack-arrays",
272 llvm::cl::desc("Pack non-contiguous assummed shape arrays "
273 "into contiguous memory"),
274 llvm::cl::init(Val: false));
275
276static llvm::cl::opt<bool>
277 repackArraysWhole("frepack-arrays-continuity-whole",
278 llvm::cl::desc("Repack arrays that are non-contiguous "
279 "in any dimension. If set to false, "
280 "only the arrays non-contiguous in the "
281 "leading dimension will be repacked"),
282 llvm::cl::init(Val: true));
283
284static llvm::cl::opt<std::string> complexRange(
285 "complex-range",
286 llvm::cl::desc("Controls the various implementations for complex "
287 "multiplication and division [full|improved|basic]"),
288 llvm::cl::init(Val: ""));
289
290#define FLANG_EXCLUDE_CODEGEN
291#include "flang/Optimizer/Passes/CommandLineOpts.h"
292#include "flang/Optimizer/Passes/Pipelines.h"
293
294//===----------------------------------------------------------------------===//
295
296using ProgramName = std::string;
297
298// Print the module with the "module { ... }" wrapper, preventing
299// information loss from attribute information appended to the module
300static void printModule(mlir::ModuleOp mlirModule, llvm::raw_ostream &out) {
301 out << mlirModule << '\n';
302}
303
304static void registerAllPasses() {
305 fir::support::registerMLIRPassesForFortranTools();
306 fir::registerOptTransformPasses();
307}
308
309/// Create a target machine that is at least sufficient to get data-layout
310/// information required by flang semantics and lowering. Note that it may not
311/// contain all the CPU feature information to get optimized assembly generation
312/// from LLVM IR. Drivers that needs to generate assembly from LLVM IR should
313/// create a target machine according to their specific options.
314static std::unique_ptr<llvm::TargetMachine>
315createTargetMachine(llvm::StringRef targetTriple, std::string &error) {
316 std::string triple{targetTriple};
317 if (triple.empty())
318 triple = llvm::sys::getDefaultTargetTriple();
319
320 const llvm::Target *theTarget =
321 llvm::TargetRegistry::lookupTarget(TripleStr: triple, Error&: error);
322 if (!theTarget)
323 return nullptr;
324 return std::unique_ptr<llvm::TargetMachine>{
325 theTarget->createTargetMachine(TT: llvm::Triple(triple), /*CPU=*/"",
326 /*Features=*/"", Options: llvm::TargetOptions(),
327 /*Reloc::Model=*/RM: std::nullopt)};
328}
329
330/// Build and execute the OpenMPFIRPassPipeline with its own instance
331/// of the pass manager, allowing it to be invoked as soon as it's
332/// required without impacting the main pass pipeline that may be invoked
333/// more than once for verification.
334static llvm::LogicalResult runOpenMPPasses(mlir::ModuleOp mlirModule) {
335 mlir::PassManager pm(mlirModule->getName(),
336 mlir::OpPassManager::Nesting::Implicit);
337 using DoConcurrentMappingKind =
338 Fortran::frontend::CodeGenOptions::DoConcurrentMappingKind;
339
340 fir::OpenMPFIRPassPipelineOpts opts;
341 opts.isTargetDevice = enableOpenMPDevice;
342 opts.doConcurrentMappingKind =
343 llvm::StringSwitch<DoConcurrentMappingKind>(
344 enableDoConcurrentToOpenMPConversion)
345 .Case("host", DoConcurrentMappingKind::DCMK_Host)
346 .Case("device", DoConcurrentMappingKind::DCMK_Device)
347 .Default(DoConcurrentMappingKind::DCMK_None);
348
349 fir::createOpenMPFIRPassPipeline(pm, opts);
350 (void)mlir::applyPassManagerCLOptions(pm);
351 if (mlir::failed(pm.run(mlirModule))) {
352 llvm::errs() << "FATAL: failed to correctly apply OpenMP pass pipeline";
353 return mlir::failure();
354 }
355 return mlir::success();
356}
357
358//===----------------------------------------------------------------------===//
359// Translate Fortran input to FIR, a dialect of MLIR.
360//===----------------------------------------------------------------------===//
361
362static llvm::LogicalResult convertFortranSourceToMLIR(
363 std::string path, Fortran::parser::Options options,
364 const ProgramName &programPrefix,
365 Fortran::semantics::SemanticsContext &semanticsContext,
366 const mlir::PassPipelineCLParser &passPipeline,
367 const llvm::TargetMachine &targetMachine) {
368
369 // prep for prescan and parse
370 Fortran::parser::Parsing parsing{semanticsContext.allCookedSources()};
371 parsing.Prescan(path, options);
372 if (!parsing.messages().empty() && (parsing.messages().AnyFatalError())) {
373 llvm::errs() << programPrefix << "could not scan " << path << '\n';
374 parsing.messages().Emit(llvm::errs(), parsing.allCooked());
375 return mlir::failure();
376 }
377
378 // parse the input Fortran
379 parsing.Parse(llvm::outs());
380 if (!parsing.consumedWholeFile()) {
381 parsing.messages().Emit(llvm::errs(), parsing.allCooked());
382 parsing.EmitMessage(llvm::errs(), parsing.finalRestingPlace(),
383 "parser FAIL (final position)",
384 "error: ", llvm::raw_ostream::RED);
385 return mlir::failure();
386 } else if ((!parsing.messages().empty() &&
387 (parsing.messages().AnyFatalError())) ||
388 !parsing.parseTree().has_value()) {
389 parsing.messages().Emit(llvm::errs(), parsing.allCooked());
390 llvm::errs() << programPrefix << "could not parse " << path << '\n';
391 return mlir::failure();
392 } else {
393 semanticsContext.messages().Annex(std::move(parsing.messages()));
394 }
395
396 // run semantics
397 auto &parseTree = *parsing.parseTree();
398 Fortran::semantics::Semantics semantics(semanticsContext, parseTree);
399 semantics.Perform();
400 semantics.EmitMessages(llvm::errs());
401 if (semantics.AnyFatalError()) {
402 llvm::errs() << programPrefix << "semantic errors in " << path << '\n';
403 return mlir::failure();
404 }
405 Fortran::semantics::RuntimeDerivedTypeTables tables;
406 if (!semantics.AnyFatalError()) {
407 tables =
408 Fortran::semantics::BuildRuntimeDerivedTypeTables(semanticsContext);
409 if (!tables.schemata)
410 llvm::errs() << programPrefix
411 << "could not find module file for __fortran_type_info\n";
412 }
413
414 if (dumpSymbols) {
415 semantics.DumpSymbols(llvm::outs());
416 return mlir::success();
417 }
418
419 if (pftDumpTest) {
420 if (auto ast = Fortran::lower::createPFT(parseTree, semanticsContext)) {
421 Fortran::lower::dumpPFT(llvm::outs(), *ast);
422 return mlir::success();
423 }
424 llvm::errs() << "Pre FIR Tree is NULL.\n";
425 return mlir::failure();
426 }
427
428 // translate to FIR dialect of MLIR
429 mlir::DialectRegistry registry;
430 fir::support::registerNonCodegenDialects(registry);
431 fir::support::addFIRExtensions(registry);
432 mlir::MLIRContext ctx(registry);
433 fir::support::loadNonCodegenDialects(ctx);
434 auto &defKinds = semanticsContext.defaultKinds();
435 fir::KindMapping kindMap(
436 &ctx, llvm::ArrayRef<fir::KindTy>{fir::fromDefaultKinds(defKinds)});
437 std::string targetTriple = targetMachine.getTargetTriple().normalize();
438 // Use default lowering options for bbc.
439 Fortran::lower::LoweringOptions loweringOptions{};
440 loweringOptions.setNoPPCNativeVecElemOrder(enableNoPPCNativeVecElemOrder);
441 loweringOptions.setLowerToHighLevelFIR(useHLFIR || emitHLFIR);
442 loweringOptions.setIntegerWrapAround(integerWrapAround);
443 loweringOptions.setInitGlobalZero(initGlobalZero);
444 loweringOptions.setReallocateLHS(reallocateLHS);
445 loweringOptions.setStackRepackArrays(stackRepackArrays);
446 loweringOptions.setRepackArrays(repackArrays);
447 loweringOptions.setRepackArraysWhole(repackArraysWhole);
448 loweringOptions.setSkipExternalRttiDefinition(skipExternalRttiDefinition);
449 if (enableCUDA)
450 loweringOptions.setCUDARuntimeCheck(true);
451 if (complexRange == "improved" || complexRange == "basic")
452 loweringOptions.setComplexDivisionToRuntime(false);
453 std::vector<Fortran::lower::EnvironmentDefault> envDefaults = {};
454 Fortran::frontend::TargetOptions targetOpts;
455 Fortran::frontend::CodeGenOptions cgOpts;
456 auto burnside = Fortran::lower::LoweringBridge::create(
457 ctx, semanticsContext, defKinds, semanticsContext.intrinsics(),
458 semanticsContext.targetCharacteristics(), parsing.allCooked(),
459 targetTriple, kindMap, loweringOptions, envDefaults,
460 semanticsContext.languageFeatures(), targetMachine, targetOpts, cgOpts);
461 mlir::ModuleOp mlirModule = burnside.getModule();
462 if (enableOpenMP) {
463 if (enableOpenMPGPU && !enableOpenMPDevice) {
464 llvm::errs() << "FATAL: -fopenmp-is-gpu can only be set if "
465 "-fopenmp-is-target-device is also set";
466 return mlir::failure();
467 }
468 // Construct offloading target triples vector.
469 std::vector<llvm::Triple> targetTriples;
470 targetTriples.reserve(n: targetTriplesOpenMP.size());
471 for (llvm::StringRef s : targetTriplesOpenMP)
472 targetTriples.emplace_back(args&: s);
473
474 auto offloadModuleOpts = OffloadModuleOpts(
475 setOpenMPTargetDebug, setOpenMPTeamSubscription,
476 setOpenMPThreadSubscription, setOpenMPNoThreadState,
477 setOpenMPNoNestedParallelism, enableOpenMPDevice, enableOpenMPGPU,
478 enableOpenMPForceUSM, setOpenMPVersion, "", targetTriples, setNoGPULib);
479 setOffloadModuleInterfaceAttributes(mlirModule, offloadModuleOpts);
480 setOpenMPVersionAttribute(mlirModule, setOpenMPVersion);
481 }
482 burnside.lower(parseTree, semanticsContext);
483 std::error_code ec;
484 std::string outputName = outputFilename;
485 if (!outputName.size())
486 outputName = llvm::sys::path::stem(path: inputFilename).str().append(s: ".mlir");
487 llvm::raw_fd_ostream out(outputName, ec);
488 if (ec)
489 return mlir::emitError(mlir::UnknownLoc::get(&ctx),
490 "could not open output file ")
491 << outputName;
492
493 // WARNING: This pipeline must be run immediately after the lowering to
494 // ensure that the FIR is correct with respect to OpenMP operations/
495 // attributes.
496 if (enableOpenMP)
497 if (mlir::failed(runOpenMPPasses(mlirModule)))
498 return mlir::failure();
499
500 // Otherwise run the default passes.
501 mlir::PassManager pm(mlirModule->getName(),
502 mlir::OpPassManager::Nesting::Implicit);
503 pm.enableVerifier(/*verifyPasses=*/true);
504 (void)mlir::applyPassManagerCLOptions(pm);
505 if (passPipeline.hasAnyOccurrences()) {
506 // run the command-line specified pipeline
507 hlfir::registerHLFIRPasses();
508 (void)passPipeline.addToPipeline(pm, [&](const llvm::Twine &msg) {
509 mlir::emitError(mlir::UnknownLoc::get(&ctx)) << msg;
510 return mlir::failure();
511 });
512 } else if (emitFIR || emitHLFIR) {
513 // --emit-fir: Build the IR, verify it, and dump the IR if the IR passes
514 // verification. Use --dump-module-on-failure to dump invalid IR.
515 pm.addPass(std::make_unique<Fortran::lower::VerifierPass>());
516 if (mlir::failed(pm.run(mlirModule))) {
517 llvm::errs() << "FATAL: verification of lowering to FIR failed";
518 return mlir::failure();
519 }
520
521 if (emitFIR && useHLFIR) {
522 // lower HLFIR to FIR
523 fir::createHLFIRToFIRPassPipeline(pm, enableOpenMP,
524 llvm::OptimizationLevel::O2);
525 if (mlir::failed(pm.run(mlirModule))) {
526 llvm::errs() << "FATAL: lowering from HLFIR to FIR failed";
527 return mlir::failure();
528 }
529 }
530
531 printModule(mlirModule, out);
532 return mlir::success();
533 } else {
534 // run the default canned pipeline
535 pm.addPass(std::make_unique<Fortran::lower::VerifierPass>());
536
537 // Add O2 optimizer pass pipeline.
538 MLIRToLLVMPassPipelineConfig config(llvm::OptimizationLevel::O2);
539 if (enableOpenMP)
540 config.EnableOpenMP = true;
541 config.NSWOnLoopVarInc = !integerWrapAround;
542 fir::registerDefaultInlinerPass(config);
543 fir::createDefaultFIROptimizerPassPipeline(pm, config);
544 }
545
546 if (mlir::succeeded(pm.run(mlirModule))) {
547 // Emit MLIR and do not lower to LLVM IR.
548 printModule(mlirModule, out);
549 return mlir::success();
550 }
551 // Something went wrong. Try to dump the MLIR module.
552 llvm::errs() << "oops, pass manager reported failure\n";
553 return mlir::failure();
554}
555
556int main(int argc, char **argv) {
557 [[maybe_unused]] llvm::InitLLVM y(argc, argv);
558 llvm::InitializeAllTargets();
559 llvm::InitializeAllTargetMCs();
560 registerAllPasses();
561
562 mlir::registerMLIRContextCLOptions();
563 mlir::registerAsmPrinterCLOptions();
564 mlir::registerPassManagerCLOptions();
565 mlir::PassPipelineCLParser passPipe("", "Compiler passes to run");
566 llvm::cl::ParseCommandLineOptions(argc, argv, Overview: "Burnside Bridge Compiler\n");
567
568 ProgramName programPrefix;
569 programPrefix = argv[0] + ": "s;
570
571 if (includeDirs.size() == 0) {
572 includeDirs.push_back(value: ".");
573 // Default Fortran modules should be installed in include/flang (a sibling
574 // to the bin) directory.
575 intrinsicIncludeDirs.push_back(
576 value: llvm::sys::path::parent_path(
577 path: llvm::sys::path::parent_path(
578 path: llvm::sys::fs::getMainExecutable(argv0: argv[0], MainExecAddr: nullptr)))
579 .str() +
580 "/include/flang");
581 }
582
583 Fortran::parser::Options options;
584 options.predefinitions.emplace_back("__flang__"s, "1"s);
585 options.predefinitions.emplace_back("__flang_major__"s,
586 std::string{FLANG_VERSION_MAJOR_STRING});
587 options.predefinitions.emplace_back("__flang_minor__"s,
588 std::string{FLANG_VERSION_MINOR_STRING});
589 options.predefinitions.emplace_back(
590 "__flang_patchlevel__"s, std::string{FLANG_VERSION_PATCHLEVEL_STRING});
591
592 Fortran::common::LangOptions langOpts;
593 langOpts.NoGPULib = setNoGPULib;
594 langOpts.OpenMPVersion = setOpenMPVersion;
595 langOpts.OpenMPIsTargetDevice = enableOpenMPDevice;
596 langOpts.OpenMPIsGPU = enableOpenMPGPU;
597 langOpts.OpenMPForceUSM = enableOpenMPForceUSM;
598 langOpts.OpenMPTargetDebug = setOpenMPTargetDebug;
599 langOpts.OpenMPThreadSubscription = setOpenMPThreadSubscription;
600 langOpts.OpenMPTeamSubscription = setOpenMPTeamSubscription;
601 langOpts.OpenMPNoThreadState = setOpenMPNoThreadState;
602 langOpts.OpenMPNoNestedParallelism = setOpenMPNoNestedParallelism;
603 std::transform(targetTriplesOpenMP.begin(), targetTriplesOpenMP.end(),
604 std::back_inserter(langOpts.OMPTargetTriples),
605 [](const std::string &str) { return llvm::Triple(str); });
606
607 // enable parsing of OpenMP
608 if (enableOpenMP) {
609 options.features.Enable(Fortran::common::LanguageFeature::OpenMP);
610 Fortran::common::setOpenMPMacro(setOpenMPVersion, options.predefinitions);
611 }
612
613 // enable parsing of OpenACC
614 if (enableOpenACC) {
615 options.features.Enable(Fortran::common::LanguageFeature::OpenACC);
616 options.predefinitions.emplace_back("_OPENACC", "202211");
617 }
618
619 // enable parsing of CUDA Fortran
620 if (enableCUDA) {
621 options.features.Enable(Fortran::common::LanguageFeature::CUDA);
622 }
623
624 if (enableDoConcurrentOffload) {
625 options.features.Enable(
626 Fortran::common::LanguageFeature::DoConcurrentOffload);
627 }
628
629 if (disableCUDAWarpFunction) {
630 options.features.Enable(
631 Fortran::common::LanguageFeature::CudaWarpMatchFunction, false);
632 }
633
634 if (enableGPUMode == "managed") {
635 options.features.Enable(Fortran::common::LanguageFeature::CudaManaged);
636 } else if (enableGPUMode == "unified") {
637 options.features.Enable(Fortran::common::LanguageFeature::CudaUnified);
638 }
639
640 if (fixedForm) {
641 options.isFixedForm = fixedForm;
642 }
643
644 Fortran::common::IntrinsicTypeDefaultKinds defaultKinds;
645 Fortran::parser::AllSources allSources;
646 Fortran::parser::AllCookedSources allCookedSources(allSources);
647 Fortran::semantics::SemanticsContext semanticsContext{
648 defaultKinds, options.features, langOpts, allCookedSources};
649 semanticsContext.set_moduleDirectory(moduleDir)
650 .set_moduleFileSuffix(moduleSuffix)
651 .set_searchDirectories(includeDirs)
652 .set_intrinsicModuleDirectories(intrinsicIncludeDirs)
653 .set_warnOnNonstandardUsage(warnStdViolation)
654 .set_warningsAreErrors(warnIsError);
655
656 std::string error;
657 // Create host target machine.
658 std::unique_ptr<llvm::TargetMachine> targetMachine =
659 createTargetMachine(targetTriple: targetTripleOverride, error);
660 if (!targetMachine) {
661 llvm::errs() << "failed to create target machine: " << error << "\n";
662 return mlir::failed(mlir::failure());
663 }
664 std::string compilerVersion = Fortran::common::getFlangToolFullVersion("bbc");
665 std::string compilerOptions = "";
666 Fortran::tools::setUpTargetCharacteristics(
667 semanticsContext.targetCharacteristics(), *targetMachine, {},
668 compilerVersion, compilerOptions);
669
670 return mlir::failed(
671 convertFortranSourceToMLIR(inputFilename, options, programPrefix,
672 semanticsContext, passPipe, *targetMachine));
673}
674

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