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