678 lines · cpp
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-exception6//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 options76//===----------------------------------------------------------------------===//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::alias97 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("."));104 105static llvm::cl::opt<std::string>106 moduleSuffix("module-suffix", llvm::cl::desc("module file suffix override"),107 llvm::cl::init(".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(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(false));118 119static llvm::cl::opt<bool> warnStdViolation("Mstandard",120 llvm::cl::desc("emit warnings"),121 llvm::cl::init(false));122 123static llvm::cl::opt<bool> warnIsError("Werror",124 llvm::cl::desc("warnings are errors"),125 llvm::cl::init(false));126 127static llvm::cl::opt<bool> dumpSymbols("dump-symbols",128 llvm::cl::desc("dump the symbol table"),129 llvm::cl::init(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(false));135 136static llvm::cl::opt<bool> enableOpenMP("fopenmp",137 llvm::cl::desc("enable openmp"),138 llvm::cl::init(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(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("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(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(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 primary167// positive options are available, no negative options e.g. fopen_assume* vs168// fno_open_assume*169static llvm::cl::opt<uint32_t>170 setOpenMPVersion("fopenmp-version",171 llvm::cl::desc("OpenMP standard version"),172 llvm::cl::init(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(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(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(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(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(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(false));208 209static llvm::cl::opt<bool> enableOpenACC("fopenacc",210 llvm::cl::desc("enable openacc"),211 llvm::cl::init(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(false));217 218static llvm::cl::opt<bool> useHLFIR("hlfir",219 llvm::cl::desc("Lower to high level FIR"),220 llvm::cl::init(true));221 222static llvm::cl::opt<bool> enableCUDA("fcuda",223 llvm::cl::desc("enable CUDA Fortran"),224 llvm::cl::init(false));225 226static llvm::cl::opt<bool>227 enableDoConcurrentOffload("fdoconcurrent-offload",228 llvm::cl::desc("enable do concurrent offload"),229 llvm::cl::init(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(false));235 236static llvm::cl::opt<std::string>237 enableGPUMode("gpu", llvm::cl::desc("Enable GPU Mode managed|unified"),238 llvm::cl::init(""));239 240static llvm::cl::opt<bool> fixedForm("ffixed-form",241 llvm::cl::desc("enable fixed form"),242 llvm::cl::init(false));243static llvm::cl::opt<std::string>244 targetTripleOverride("target",245 llvm::cl::desc("Override host target triple"),246 llvm::cl::init(""));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(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(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(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(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(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(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(""));289 290#define FLANG_EXCLUDE_CODEGEN291#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, preventing299// information loss from attribute information appended to the module300static 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-layout310/// information required by flang semantics and lowering. Note that it may not311/// contain all the CPU feature information to get optimized assembly generation312/// from LLVM IR. Drivers that needs to generate assembly from LLVM IR should313/// 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 llvm::Triple parsedTriple(triple);320 321 const llvm::Target *theTarget =322 llvm::TargetRegistry::lookupTarget(parsedTriple, error);323 if (!theTarget)324 return nullptr;325 return std::unique_ptr<llvm::TargetMachine>{326 theTarget->createTargetMachine(parsedTriple, /*CPU=*/"",327 /*Features=*/"", llvm::TargetOptions(),328 /*Reloc::Model=*/std::nullopt)};329}330 331/// Build and execute the OpenMPFIRPassPipeline with its own instance332/// of the pass manager, allowing it to be invoked as soon as it's333/// required without impacting the main pass pipeline that may be invoked334/// more than once for verification.335static llvm::LogicalResult runOpenMPPasses(mlir::ModuleOp mlirModule) {336 mlir::PassManager pm(mlirModule->getName(),337 mlir::OpPassManager::Nesting::Implicit);338 using DoConcurrentMappingKind =339 Fortran::frontend::CodeGenOptions::DoConcurrentMappingKind;340 341 fir::OpenMPFIRPassPipelineOpts opts;342 opts.isTargetDevice = enableOpenMPDevice;343 opts.doConcurrentMappingKind =344 llvm::StringSwitch<DoConcurrentMappingKind>(345 enableDoConcurrentToOpenMPConversion)346 .Case("host", DoConcurrentMappingKind::DCMK_Host)347 .Case("device", DoConcurrentMappingKind::DCMK_Device)348 .Default(DoConcurrentMappingKind::DCMK_None);349 350 fir::createOpenMPFIRPassPipeline(pm, opts);351 (void)mlir::applyPassManagerCLOptions(pm);352 if (mlir::failed(pm.run(mlirModule))) {353 llvm::errs() << "FATAL: failed to correctly apply OpenMP pass pipeline";354 return mlir::failure();355 }356 return mlir::success();357}358 359//===----------------------------------------------------------------------===//360// Translate Fortran input to FIR, a dialect of MLIR.361//===----------------------------------------------------------------------===//362 363static llvm::LogicalResult convertFortranSourceToMLIR(364 std::string path, Fortran::parser::Options options,365 const ProgramName &programPrefix,366 Fortran::semantics::SemanticsContext &semanticsContext,367 const mlir::PassPipelineCLParser &passPipeline,368 const llvm::TargetMachine &targetMachine) {369 370 // prep for prescan and parse371 Fortran::parser::Parsing parsing{semanticsContext.allCookedSources()};372 parsing.Prescan(path, options);373 if (!parsing.messages().empty() && (parsing.messages().AnyFatalError())) {374 llvm::errs() << programPrefix << "could not scan " << path << '\n';375 parsing.messages().Emit(llvm::errs(), parsing.allCooked());376 return mlir::failure();377 }378 379 // parse the input Fortran380 parsing.Parse(llvm::outs());381 if (!parsing.consumedWholeFile()) {382 parsing.messages().Emit(llvm::errs(), parsing.allCooked());383 parsing.EmitMessage(llvm::errs(), parsing.finalRestingPlace(),384 "parser FAIL (final position)",385 "error: ", llvm::raw_ostream::RED);386 return mlir::failure();387 } else if ((!parsing.messages().empty() &&388 (parsing.messages().AnyFatalError())) ||389 !parsing.parseTree().has_value()) {390 parsing.messages().Emit(llvm::errs(), parsing.allCooked());391 llvm::errs() << programPrefix << "could not parse " << path << '\n';392 return mlir::failure();393 } else {394 semanticsContext.messages().Annex(std::move(parsing.messages()));395 }396 397 // run semantics398 auto &parseTree = *parsing.parseTree();399 Fortran::semantics::Semantics semantics(semanticsContext, parseTree);400 semantics.Perform();401 semantics.EmitMessages(llvm::errs());402 if (semantics.AnyFatalError()) {403 llvm::errs() << programPrefix << "semantic errors in " << path << '\n';404 return mlir::failure();405 }406 Fortran::semantics::RuntimeDerivedTypeTables tables;407 if (!semantics.AnyFatalError()) {408 tables =409 Fortran::semantics::BuildRuntimeDerivedTypeTables(semanticsContext);410 if (!tables.schemata)411 llvm::errs() << programPrefix412 << "could not find module file for __fortran_type_info\n";413 }414 415 if (dumpSymbols) {416 semantics.DumpSymbols(llvm::outs());417 return mlir::success();418 }419 420 if (pftDumpTest) {421 if (auto ast = Fortran::lower::createPFT(parseTree, semanticsContext)) {422 Fortran::lower::dumpPFT(llvm::outs(), *ast);423 return mlir::success();424 }425 llvm::errs() << "Pre FIR Tree is NULL.\n";426 return mlir::failure();427 }428 429 // translate to FIR dialect of MLIR430 mlir::DialectRegistry registry;431 fir::support::registerNonCodegenDialects(registry);432 fir::support::addFIRExtensions(registry);433 mlir::MLIRContext ctx(registry);434 fir::support::loadNonCodegenDialects(ctx);435 auto &defKinds = semanticsContext.defaultKinds();436 fir::KindMapping kindMap(437 &ctx, llvm::ArrayRef<fir::KindTy>{fir::fromDefaultKinds(defKinds)});438 std::string targetTriple = targetMachine.getTargetTriple().normalize();439 // Use default lowering options for bbc.440 Fortran::lower::LoweringOptions loweringOptions{};441 loweringOptions.setNoPPCNativeVecElemOrder(enableNoPPCNativeVecElemOrder);442 loweringOptions.setLowerToHighLevelFIR(useHLFIR || emitHLFIR);443 loweringOptions.setIntegerWrapAround(integerWrapAround);444 loweringOptions.setInitGlobalZero(initGlobalZero);445 loweringOptions.setReallocateLHS(reallocateLHS);446 loweringOptions.setStackRepackArrays(stackRepackArrays);447 loweringOptions.setRepackArrays(repackArrays);448 loweringOptions.setRepackArraysWhole(repackArraysWhole);449 loweringOptions.setSkipExternalRttiDefinition(skipExternalRttiDefinition);450 if (enableCUDA)451 loweringOptions.setCUDARuntimeCheck(true);452 if (complexRange == "improved" || complexRange == "basic")453 loweringOptions.setComplexDivisionToRuntime(false);454 std::vector<Fortran::lower::EnvironmentDefault> envDefaults = {};455 Fortran::frontend::TargetOptions targetOpts;456 Fortran::frontend::CodeGenOptions cgOpts;457 auto burnside = Fortran::lower::LoweringBridge::create(458 ctx, semanticsContext, defKinds, semanticsContext.intrinsics(),459 semanticsContext.targetCharacteristics(), parsing.allCooked(),460 targetTriple, kindMap, loweringOptions, envDefaults,461 semanticsContext.languageFeatures(), targetMachine, targetOpts, cgOpts);462 mlir::ModuleOp mlirModule = burnside.getModule();463 if (enableOpenMP) {464 if (enableOpenMPGPU && !enableOpenMPDevice) {465 llvm::errs() << "FATAL: -fopenmp-is-gpu can only be set if "466 "-fopenmp-is-target-device is also set";467 return mlir::failure();468 }469 // Construct offloading target triples vector.470 std::vector<llvm::Triple> targetTriples;471 targetTriples.reserve(targetTriplesOpenMP.size());472 for (llvm::StringRef s : targetTriplesOpenMP)473 targetTriples.emplace_back(s);474 475 auto offloadModuleOpts = OffloadModuleOpts(476 setOpenMPTargetDebug, setOpenMPTeamSubscription,477 setOpenMPThreadSubscription, setOpenMPNoThreadState,478 setOpenMPNoNestedParallelism, enableOpenMPDevice, enableOpenMPGPU,479 enableOpenMPForceUSM, setOpenMPVersion, "", targetTriples, setNoGPULib);480 setOffloadModuleInterfaceAttributes(mlirModule, offloadModuleOpts);481 setOpenMPVersionAttribute(mlirModule, setOpenMPVersion);482 }483 burnside.lower(parseTree, semanticsContext);484 std::error_code ec;485 std::string outputName = outputFilename;486 if (!outputName.size())487 outputName = llvm::sys::path::stem(inputFilename).str().append(".mlir");488 llvm::raw_fd_ostream out(outputName, ec);489 if (ec)490 return mlir::emitError(mlir::UnknownLoc::get(&ctx),491 "could not open output file ")492 << outputName;493 494 // WARNING: This pipeline must be run immediately after the lowering to495 // ensure that the FIR is correct with respect to OpenMP operations/496 // attributes.497 if (enableOpenMP)498 if (mlir::failed(runOpenMPPasses(mlirModule)))499 return mlir::failure();500 501 // Otherwise run the default passes.502 mlir::PassManager pm(mlirModule->getName(),503 mlir::OpPassManager::Nesting::Implicit);504 pm.enableVerifier(/*verifyPasses=*/true);505 (void)mlir::applyPassManagerCLOptions(pm);506 if (passPipeline.hasAnyOccurrences()) {507 // run the command-line specified pipeline508 hlfir::registerHLFIRPasses();509 (void)passPipeline.addToPipeline(pm, [&](const llvm::Twine &msg) {510 mlir::emitError(mlir::UnknownLoc::get(&ctx)) << msg;511 return mlir::failure();512 });513 } else if (emitFIR || emitHLFIR) {514 // --emit-fir: Build the IR, verify it, and dump the IR if the IR passes515 // verification. Use --dump-module-on-failure to dump invalid IR.516 pm.addPass(std::make_unique<Fortran::lower::VerifierPass>());517 if (mlir::failed(pm.run(mlirModule))) {518 llvm::errs() << "FATAL: verification of lowering to FIR failed";519 return mlir::failure();520 }521 522 if (emitFIR && useHLFIR) {523 // lower HLFIR to FIR524 fir::EnableOpenMP enableOmp =525 enableOpenMP ? fir::EnableOpenMP::Full : fir::EnableOpenMP::None;526 fir::createHLFIRToFIRPassPipeline(pm, enableOmp,527 llvm::OptimizationLevel::O2);528 if (mlir::failed(pm.run(mlirModule))) {529 llvm::errs() << "FATAL: lowering from HLFIR to FIR failed";530 return mlir::failure();531 }532 }533 534 printModule(mlirModule, out);535 return mlir::success();536 } else {537 // run the default canned pipeline538 pm.addPass(std::make_unique<Fortran::lower::VerifierPass>());539 540 // Add O2 optimizer pass pipeline.541 MLIRToLLVMPassPipelineConfig config(llvm::OptimizationLevel::O2);542 config.SkipConvertComplexPow = targetMachine.getTargetTriple().isAMDGCN();543 if (enableOpenMP)544 config.EnableOpenMP = true;545 config.NSWOnLoopVarInc = !integerWrapAround;546 fir::registerDefaultInlinerPass(config);547 fir::createDefaultFIROptimizerPassPipeline(pm, config);548 }549 550 if (mlir::succeeded(pm.run(mlirModule))) {551 // Emit MLIR and do not lower to LLVM IR.552 printModule(mlirModule, out);553 return mlir::success();554 }555 // Something went wrong. Try to dump the MLIR module.556 llvm::errs() << "oops, pass manager reported failure\n";557 return mlir::failure();558}559 560int main(int argc, char **argv) {561 [[maybe_unused]] llvm::InitLLVM y(argc, argv);562 llvm::InitializeAllTargets();563 llvm::InitializeAllTargetMCs();564 registerAllPasses();565 566 mlir::registerMLIRContextCLOptions();567 mlir::registerAsmPrinterCLOptions();568 mlir::registerPassManagerCLOptions();569 mlir::PassPipelineCLParser passPipe("", "Compiler passes to run");570 llvm::cl::ParseCommandLineOptions(argc, argv, "Burnside Bridge Compiler\n");571 572 ProgramName programPrefix;573 programPrefix = argv[0] + ": "s;574 575 if (includeDirs.size() == 0) {576 includeDirs.push_back(".");577 // Default Fortran modules should be installed in include/flang (a sibling578 // to the bin) directory.579 intrinsicIncludeDirs.push_back(580 llvm::sys::path::parent_path(581 llvm::sys::path::parent_path(582 llvm::sys::fs::getMainExecutable(argv[0], nullptr)))583 .str() +584 "/include/flang");585 }586 587 Fortran::parser::Options options;588 options.predefinitions.emplace_back("__flang__"s, "1"s);589 options.predefinitions.emplace_back("__flang_major__"s,590 std::string{FLANG_VERSION_MAJOR_STRING});591 options.predefinitions.emplace_back("__flang_minor__"s,592 std::string{FLANG_VERSION_MINOR_STRING});593 options.predefinitions.emplace_back(594 "__flang_patchlevel__"s, std::string{FLANG_VERSION_PATCHLEVEL_STRING});595 596 Fortran::common::LangOptions langOpts;597 langOpts.NoGPULib = setNoGPULib;598 langOpts.OpenMPVersion = setOpenMPVersion;599 langOpts.OpenMPIsTargetDevice = enableOpenMPDevice;600 langOpts.OpenMPIsGPU = enableOpenMPGPU;601 langOpts.OpenMPForceUSM = enableOpenMPForceUSM;602 langOpts.OpenMPTargetDebug = setOpenMPTargetDebug;603 langOpts.OpenMPThreadSubscription = setOpenMPThreadSubscription;604 langOpts.OpenMPTeamSubscription = setOpenMPTeamSubscription;605 langOpts.OpenMPNoThreadState = setOpenMPNoThreadState;606 langOpts.OpenMPNoNestedParallelism = setOpenMPNoNestedParallelism;607 std::transform(targetTriplesOpenMP.begin(), targetTriplesOpenMP.end(),608 std::back_inserter(langOpts.OMPTargetTriples),609 [](const std::string &str) { return llvm::Triple(str); });610 611 // enable parsing of OpenMP612 if (enableOpenMP) {613 options.features.Enable(Fortran::common::LanguageFeature::OpenMP);614 Fortran::common::setOpenMPMacro(setOpenMPVersion, options.predefinitions);615 }616 617 // enable parsing of OpenACC618 if (enableOpenACC) {619 options.features.Enable(Fortran::common::LanguageFeature::OpenACC);620 options.predefinitions.emplace_back("_OPENACC", "202211");621 }622 623 // enable parsing of CUDA Fortran624 if (enableCUDA) {625 options.features.Enable(Fortran::common::LanguageFeature::CUDA);626 }627 628 if (enableDoConcurrentOffload) {629 options.features.Enable(630 Fortran::common::LanguageFeature::DoConcurrentOffload);631 }632 633 if (disableCUDAWarpFunction) {634 options.features.Enable(635 Fortran::common::LanguageFeature::CudaWarpMatchFunction, false);636 }637 638 if (enableGPUMode == "managed") {639 options.features.Enable(Fortran::common::LanguageFeature::CudaManaged);640 } else if (enableGPUMode == "unified") {641 options.features.Enable(Fortran::common::LanguageFeature::CudaUnified);642 }643 644 if (fixedForm) {645 options.isFixedForm = fixedForm;646 }647 648 Fortran::common::IntrinsicTypeDefaultKinds defaultKinds;649 Fortran::parser::AllSources allSources;650 Fortran::parser::AllCookedSources allCookedSources(allSources);651 Fortran::semantics::SemanticsContext semanticsContext{652 defaultKinds, options.features, langOpts, allCookedSources};653 semanticsContext.set_moduleDirectory(moduleDir)654 .set_moduleFileSuffix(moduleSuffix)655 .set_searchDirectories(includeDirs)656 .set_intrinsicModuleDirectories(intrinsicIncludeDirs)657 .set_warnOnNonstandardUsage(warnStdViolation)658 .set_warningsAreErrors(warnIsError);659 660 std::string error;661 // Create host target machine.662 std::unique_ptr<llvm::TargetMachine> targetMachine =663 createTargetMachine(targetTripleOverride, error);664 if (!targetMachine) {665 llvm::errs() << "failed to create target machine: " << error << "\n";666 return mlir::failed(mlir::failure());667 }668 std::string compilerVersion = Fortran::common::getFlangToolFullVersion("bbc");669 std::string compilerOptions = "";670 Fortran::tools::setUpTargetCharacteristics(671 semanticsContext.targetCharacteristics(), *targetMachine, {},672 compilerVersion, compilerOptions);673 674 return mlir::failed(675 convertFortranSourceToMLIR(inputFilename, options, programPrefix,676 semanticsContext, passPipe, *targetMachine));677}678