1 //===- CompilerInvocation.cpp ---------------------------------------------===// 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 #include "flang/Frontend/CompilerInvocation.h" 14 #include "flang/Common/Fortran-features.h" 15 #include "flang/Common/OpenMP-features.h" 16 #include "flang/Common/Version.h" 17 #include "flang/Frontend/CodeGenOptions.h" 18 #include "flang/Frontend/PreprocessorOptions.h" 19 #include "flang/Frontend/TargetOptions.h" 20 #include "flang/Semantics/semantics.h" 21 #include "flang/Tools/TargetSetup.h" 22 #include "flang/Version.inc" 23 #include "clang/Basic/AllDiagnostics.h" 24 #include "clang/Basic/DiagnosticDriver.h" 25 #include "clang/Basic/DiagnosticOptions.h" 26 #include "clang/Driver/DriverDiagnostic.h" 27 #include "clang/Driver/OptionUtils.h" 28 #include "clang/Driver/Options.h" 29 #include "llvm/ADT/StringRef.h" 30 #include "llvm/ADT/StringSwitch.h" 31 #include "llvm/Frontend/Debug/Options.h" 32 #include "llvm/Option/Arg.h" 33 #include "llvm/Option/ArgList.h" 34 #include "llvm/Option/OptTable.h" 35 #include "llvm/Support/FileSystem.h" 36 #include "llvm/Support/FileUtilities.h" 37 #include "llvm/Support/Path.h" 38 #include "llvm/Support/Process.h" 39 #include "llvm/Support/raw_ostream.h" 40 #include "llvm/TargetParser/Host.h" 41 #include "llvm/TargetParser/Triple.h" 42 #include <cstdlib> 43 #include <memory> 44 #include <optional> 45 46 using namespace Fortran::frontend; 47 48 //===----------------------------------------------------------------------===// 49 // Initialization. 50 //===----------------------------------------------------------------------===// 51 CompilerInvocationBase::CompilerInvocationBase() 52 : diagnosticOpts(new clang::DiagnosticOptions()), 53 preprocessorOpts(new PreprocessorOptions()) {} 54 55 CompilerInvocationBase::CompilerInvocationBase(const CompilerInvocationBase &x) 56 : diagnosticOpts(new clang::DiagnosticOptions(x.getDiagnosticOpts())), 57 preprocessorOpts(new PreprocessorOptions(x.getPreprocessorOpts())) {} 58 59 CompilerInvocationBase::~CompilerInvocationBase() = default; 60 61 //===----------------------------------------------------------------------===// 62 // Deserialization (from args) 63 //===----------------------------------------------------------------------===// 64 static bool parseShowColorsArgs(const llvm::opt::ArgList &args, 65 bool defaultColor = true) { 66 // Color diagnostics default to auto ("on" if terminal supports) in the 67 // compiler driver `flang-new` but default to off in the frontend driver 68 // `flang-new -fc1`, needing an explicit OPT_fdiagnostics_color. 69 // Support both clang's -f[no-]color-diagnostics and gcc's 70 // -f[no-]diagnostics-colors[=never|always|auto]. 71 enum { 72 Colors_On, 73 Colors_Off, 74 Colors_Auto 75 } showColors = defaultColor ? Colors_Auto : Colors_Off; 76 77 for (auto *a : args) { 78 const llvm::opt::Option &opt = a->getOption(); 79 if (opt.matches(clang::driver::options::OPT_fcolor_diagnostics)) { 80 showColors = Colors_On; 81 } else if (opt.matches(clang::driver::options::OPT_fno_color_diagnostics)) { 82 showColors = Colors_Off; 83 } else if (opt.matches(clang::driver::options::OPT_fdiagnostics_color_EQ)) { 84 llvm::StringRef value(a->getValue()); 85 if (value == "always") 86 showColors = Colors_On; 87 else if (value == "never") 88 showColors = Colors_Off; 89 else if (value == "auto") 90 showColors = Colors_Auto; 91 } 92 } 93 94 return showColors == Colors_On || 95 (showColors == Colors_Auto && 96 llvm::sys::Process::StandardErrHasColors()); 97 } 98 99 /// Extracts the optimisation level from \a args. 100 static unsigned getOptimizationLevel(llvm::opt::ArgList &args, 101 clang::DiagnosticsEngine &diags) { 102 unsigned defaultOpt = 0; 103 104 if (llvm::opt::Arg *a = 105 args.getLastArg(clang::driver::options::OPT_O_Group)) { 106 if (a->getOption().matches(clang::driver::options::OPT_O0)) 107 return 0; 108 109 assert(a->getOption().matches(clang::driver::options::OPT_O)); 110 111 return getLastArgIntValue(args, clang::driver::options::OPT_O, defaultOpt, 112 diags); 113 } 114 115 return defaultOpt; 116 } 117 118 bool Fortran::frontend::parseDiagnosticArgs(clang::DiagnosticOptions &opts, 119 llvm::opt::ArgList &args) { 120 opts.ShowColors = parseShowColorsArgs(args); 121 122 return true; 123 } 124 125 static bool parseDebugArgs(Fortran::frontend::CodeGenOptions &opts, 126 llvm::opt::ArgList &args, 127 clang::DiagnosticsEngine &diags) { 128 using DebugInfoKind = llvm::codegenoptions::DebugInfoKind; 129 if (llvm::opt::Arg *arg = 130 args.getLastArg(clang::driver::options::OPT_debug_info_kind_EQ)) { 131 std::optional<DebugInfoKind> val = 132 llvm::StringSwitch<std::optional<DebugInfoKind>>(arg->getValue()) 133 .Case("line-tables-only", llvm::codegenoptions::DebugLineTablesOnly) 134 .Case("line-directives-only", 135 llvm::codegenoptions::DebugDirectivesOnly) 136 .Case("constructor", llvm::codegenoptions::DebugInfoConstructor) 137 .Case("limited", llvm::codegenoptions::LimitedDebugInfo) 138 .Case("standalone", llvm::codegenoptions::FullDebugInfo) 139 .Case("unused-types", llvm::codegenoptions::UnusedTypeInfo) 140 .Default(std::nullopt); 141 if (!val.has_value()) { 142 diags.Report(clang::diag::err_drv_invalid_value) 143 << arg->getAsString(args) << arg->getValue(); 144 return false; 145 } 146 opts.setDebugInfo(val.value()); 147 if (val != llvm::codegenoptions::DebugLineTablesOnly && 148 val != llvm::codegenoptions::NoDebugInfo) { 149 const auto debugWarning = diags.getCustomDiagID( 150 clang::DiagnosticsEngine::Warning, "Unsupported debug option: %0"); 151 diags.Report(debugWarning) << arg->getValue(); 152 } 153 } 154 return true; 155 } 156 157 static bool parseVectorLibArg(Fortran::frontend::CodeGenOptions &opts, 158 llvm::opt::ArgList &args, 159 clang::DiagnosticsEngine &diags) { 160 llvm::opt::Arg *arg = args.getLastArg(clang::driver::options::OPT_fveclib); 161 if (!arg) 162 return true; 163 164 using VectorLibrary = llvm::driver::VectorLibrary; 165 std::optional<VectorLibrary> val = 166 llvm::StringSwitch<std::optional<VectorLibrary>>(arg->getValue()) 167 .Case("Accelerate", VectorLibrary::Accelerate) 168 .Case("LIBMVEC", VectorLibrary::LIBMVEC) 169 .Case("MASSV", VectorLibrary::MASSV) 170 .Case("SVML", VectorLibrary::SVML) 171 .Case("SLEEF", VectorLibrary::SLEEF) 172 .Case("Darwin_libsystem_m", VectorLibrary::Darwin_libsystem_m) 173 .Case("ArmPL", VectorLibrary::ArmPL) 174 .Case("NoLibrary", VectorLibrary::NoLibrary) 175 .Default(std::nullopt); 176 if (!val.has_value()) { 177 diags.Report(clang::diag::err_drv_invalid_value) 178 << arg->getAsString(args) << arg->getValue(); 179 return false; 180 } 181 opts.setVecLib(val.value()); 182 return true; 183 } 184 185 // Generate an OptRemark object containing info on if the -Rgroup 186 // specified is enabled or not. 187 static CodeGenOptions::OptRemark 188 parseOptimizationRemark(clang::DiagnosticsEngine &diags, 189 llvm::opt::ArgList &args, llvm::opt::OptSpecifier optEq, 190 llvm::StringRef remarkOptName) { 191 assert((remarkOptName == "pass" || remarkOptName == "pass-missed" || 192 remarkOptName == "pass-analysis") && 193 "Unsupported remark option name provided."); 194 CodeGenOptions::OptRemark result; 195 196 for (llvm::opt::Arg *a : args) { 197 if (a->getOption().matches(clang::driver::options::OPT_R_Joined)) { 198 llvm::StringRef value = a->getValue(); 199 200 if (value == remarkOptName) { 201 result.Kind = CodeGenOptions::RemarkKind::RK_Enabled; 202 // Enable everything 203 result.Pattern = ".*"; 204 result.Regex = std::make_shared<llvm::Regex>(result.Pattern); 205 206 } else if (value.split('-') == 207 std::make_pair(llvm::StringRef("no"), remarkOptName)) { 208 result.Kind = CodeGenOptions::RemarkKind::RK_Disabled; 209 // Disable everything 210 result.Pattern = ""; 211 result.Regex = nullptr; 212 } 213 } else if (a->getOption().matches(optEq)) { 214 result.Kind = CodeGenOptions::RemarkKind::RK_WithPattern; 215 result.Pattern = a->getValue(); 216 result.Regex = std::make_shared<llvm::Regex>(result.Pattern); 217 std::string regexError; 218 219 if (!result.Regex->isValid(regexError)) { 220 diags.Report(clang::diag::err_drv_optimization_remark_pattern) 221 << regexError << a->getAsString(args); 222 return CodeGenOptions::OptRemark(); 223 } 224 } 225 } 226 return result; 227 } 228 229 static void parseCodeGenArgs(Fortran::frontend::CodeGenOptions &opts, 230 llvm::opt::ArgList &args, 231 clang::DiagnosticsEngine &diags) { 232 opts.OptimizationLevel = getOptimizationLevel(args, diags); 233 234 if (args.hasFlag(clang::driver::options::OPT_fdebug_pass_manager, 235 clang::driver::options::OPT_fno_debug_pass_manager, false)) 236 opts.DebugPassManager = 1; 237 238 if (args.hasFlag(clang::driver::options::OPT_fstack_arrays, 239 clang::driver::options::OPT_fno_stack_arrays, false)) 240 opts.StackArrays = 1; 241 242 if (args.hasFlag(clang::driver::options::OPT_floop_versioning, 243 clang::driver::options::OPT_fno_loop_versioning, false)) 244 opts.LoopVersioning = 1; 245 246 opts.AliasAnalysis = opts.OptimizationLevel > 0; 247 248 for (auto *a : args.filtered(clang::driver::options::OPT_fpass_plugin_EQ)) 249 opts.LLVMPassPlugins.push_back(a->getValue()); 250 251 // -fembed-offload-object option 252 for (auto *a : 253 args.filtered(clang::driver::options::OPT_fembed_offload_object_EQ)) 254 opts.OffloadObjects.push_back(a->getValue()); 255 256 // -flto=full/thin option. 257 if (const llvm::opt::Arg *a = 258 args.getLastArg(clang::driver::options::OPT_flto_EQ)) { 259 llvm::StringRef s = a->getValue(); 260 assert((s == "full" || s == "thin") && "Unknown LTO mode."); 261 if (s == "full") 262 opts.PrepareForFullLTO = true; 263 else 264 opts.PrepareForThinLTO = true; 265 } 266 267 if (const llvm::opt::Arg *a = args.getLastArg( 268 clang::driver::options::OPT_mcode_object_version_EQ)) { 269 llvm::StringRef s = a->getValue(); 270 if (s == "5") 271 opts.CodeObjectVersion = llvm::CodeObjectVersionKind::COV_5; 272 if (s == "4") 273 opts.CodeObjectVersion = llvm::CodeObjectVersionKind::COV_4; 274 if (s == "none") 275 opts.CodeObjectVersion = llvm::CodeObjectVersionKind::COV_None; 276 } 277 278 // -f[no-]save-optimization-record[=<format>] 279 if (const llvm::opt::Arg *a = 280 args.getLastArg(clang::driver::options::OPT_opt_record_file)) 281 opts.OptRecordFile = a->getValue(); 282 283 // Optimization file format. Defaults to yaml 284 if (const llvm::opt::Arg *a = 285 args.getLastArg(clang::driver::options::OPT_opt_record_format)) 286 opts.OptRecordFormat = a->getValue(); 287 288 // Specifies, using a regex, which successful optimization passes(middle and 289 // backend), to include in the final optimization record file generated. If 290 // not provided -fsave-optimization-record will include all passes. 291 if (const llvm::opt::Arg *a = 292 args.getLastArg(clang::driver::options::OPT_opt_record_passes)) 293 opts.OptRecordPasses = a->getValue(); 294 295 // Create OptRemark that allows printing of all successful optimization 296 // passes applied. 297 opts.OptimizationRemark = 298 parseOptimizationRemark(diags, args, clang::driver::options::OPT_Rpass_EQ, 299 /*remarkOptName=*/"pass"); 300 301 // Create OptRemark that allows all missed optimization passes to be printed. 302 opts.OptimizationRemarkMissed = parseOptimizationRemark( 303 diags, args, clang::driver::options::OPT_Rpass_missed_EQ, 304 /*remarkOptName=*/"pass-missed"); 305 306 // Create OptRemark that allows all optimization decisions made by LLVM 307 // to be printed. 308 opts.OptimizationRemarkAnalysis = parseOptimizationRemark( 309 diags, args, clang::driver::options::OPT_Rpass_analysis_EQ, 310 /*remarkOptName=*/"pass-analysis"); 311 312 if (opts.getDebugInfo() == llvm::codegenoptions::NoDebugInfo) { 313 // If the user requested a flag that requires source locations available in 314 // the backend, make sure that the backend tracks source location 315 // information. 316 bool needLocTracking = !opts.OptRecordFile.empty() || 317 !opts.OptRecordPasses.empty() || 318 !opts.OptRecordFormat.empty() || 319 opts.OptimizationRemark.hasValidPattern() || 320 opts.OptimizationRemarkMissed.hasValidPattern() || 321 opts.OptimizationRemarkAnalysis.hasValidPattern(); 322 323 if (needLocTracking) 324 opts.setDebugInfo(llvm::codegenoptions::LocTrackingOnly); 325 } 326 327 if (auto *a = args.getLastArg(clang::driver::options::OPT_save_temps_EQ)) 328 opts.SaveTempsDir = a->getValue(); 329 330 // -mrelocation-model option. 331 if (const llvm::opt::Arg *a = 332 args.getLastArg(clang::driver::options::OPT_mrelocation_model)) { 333 llvm::StringRef modelName = a->getValue(); 334 auto relocModel = 335 llvm::StringSwitch<std::optional<llvm::Reloc::Model>>(modelName) 336 .Case("static", llvm::Reloc::Static) 337 .Case("pic", llvm::Reloc::PIC_) 338 .Case("dynamic-no-pic", llvm::Reloc::DynamicNoPIC) 339 .Case("ropi", llvm::Reloc::ROPI) 340 .Case("rwpi", llvm::Reloc::RWPI) 341 .Case("ropi-rwpi", llvm::Reloc::ROPI_RWPI) 342 .Default(std::nullopt); 343 if (relocModel.has_value()) 344 opts.setRelocationModel(*relocModel); 345 else 346 diags.Report(clang::diag::err_drv_invalid_value) 347 << a->getAsString(args) << modelName; 348 } 349 350 // -pic-level and -pic-is-pie option. 351 if (int picLevel = getLastArgIntValue( 352 args, clang::driver::options::OPT_pic_level, 0, diags)) { 353 if (picLevel > 2) 354 diags.Report(clang::diag::err_drv_invalid_value) 355 << args.getLastArg(clang::driver::options::OPT_pic_level) 356 ->getAsString(args) 357 << picLevel; 358 359 opts.PICLevel = picLevel; 360 if (args.hasArg(clang::driver::options::OPT_pic_is_pie)) 361 opts.IsPIE = 1; 362 } 363 364 // This option is compatible with -f[no-]underscoring in gfortran. 365 if (args.hasFlag(clang::driver::options::OPT_fno_underscoring, 366 clang::driver::options::OPT_funderscoring, false)) { 367 opts.Underscoring = 0; 368 } 369 } 370 371 /// Parses all target input arguments and populates the target 372 /// options accordingly. 373 /// 374 /// \param [in] opts The target options instance to update 375 /// \param [in] args The list of input arguments (from the compiler invocation) 376 static void parseTargetArgs(TargetOptions &opts, llvm::opt::ArgList &args) { 377 if (const llvm::opt::Arg *a = 378 args.getLastArg(clang::driver::options::OPT_triple)) 379 opts.triple = a->getValue(); 380 381 if (const llvm::opt::Arg *a = 382 args.getLastArg(clang::driver::options::OPT_target_cpu)) 383 opts.cpu = a->getValue(); 384 385 for (const llvm::opt::Arg *currentArg : 386 args.filtered(clang::driver::options::OPT_target_feature)) 387 opts.featuresAsWritten.emplace_back(currentArg->getValue()); 388 } 389 390 // Tweak the frontend configuration based on the frontend action 391 static void setUpFrontendBasedOnAction(FrontendOptions &opts) { 392 if (opts.programAction == DebugDumpParsingLog) 393 opts.instrumentedParse = true; 394 395 if (opts.programAction == DebugDumpProvenance || 396 opts.programAction == Fortran::frontend::GetDefinition) 397 opts.needProvenanceRangeToCharBlockMappings = true; 398 } 399 400 /// Parse the argument specified for the -fconvert=<value> option 401 static std::optional<const char *> parseConvertArg(const char *s) { 402 return llvm::StringSwitch<std::optional<const char *>>(s) 403 .Case("unknown", "UNKNOWN") 404 .Case("native", "NATIVE") 405 .Case("little-endian", "LITTLE_ENDIAN") 406 .Case("big-endian", "BIG_ENDIAN") 407 .Case("swap", "SWAP") 408 .Default(std::nullopt); 409 } 410 411 static bool parseFrontendArgs(FrontendOptions &opts, llvm::opt::ArgList &args, 412 clang::DiagnosticsEngine &diags) { 413 unsigned numErrorsBefore = diags.getNumErrors(); 414 415 // By default the frontend driver creates a ParseSyntaxOnly action. 416 opts.programAction = ParseSyntaxOnly; 417 418 // Treat multiple action options as an invocation error. Note that `clang 419 // -cc1` does accept multiple action options, but will only consider the 420 // rightmost one. 421 if (args.hasMultipleArgs(clang::driver::options::OPT_Action_Group)) { 422 const unsigned diagID = diags.getCustomDiagID( 423 clang::DiagnosticsEngine::Error, "Only one action option is allowed"); 424 diags.Report(diagID); 425 return false; 426 } 427 428 // Identify the action (i.e. opts.ProgramAction) 429 if (const llvm::opt::Arg *a = 430 args.getLastArg(clang::driver::options::OPT_Action_Group)) { 431 switch (a->getOption().getID()) { 432 default: { 433 llvm_unreachable("Invalid option in group!"); 434 } 435 case clang::driver::options::OPT_test_io: 436 opts.programAction = InputOutputTest; 437 break; 438 case clang::driver::options::OPT_E: 439 opts.programAction = PrintPreprocessedInput; 440 break; 441 case clang::driver::options::OPT_fsyntax_only: 442 opts.programAction = ParseSyntaxOnly; 443 break; 444 case clang::driver::options::OPT_emit_fir: 445 opts.programAction = EmitFIR; 446 break; 447 case clang::driver::options::OPT_emit_hlfir: 448 opts.programAction = EmitHLFIR; 449 break; 450 case clang::driver::options::OPT_emit_llvm: 451 opts.programAction = EmitLLVM; 452 break; 453 case clang::driver::options::OPT_emit_llvm_bc: 454 opts.programAction = EmitLLVMBitcode; 455 break; 456 case clang::driver::options::OPT_emit_obj: 457 opts.programAction = EmitObj; 458 break; 459 case clang::driver::options::OPT_S: 460 opts.programAction = EmitAssembly; 461 break; 462 case clang::driver::options::OPT_fdebug_unparse: 463 opts.programAction = DebugUnparse; 464 break; 465 case clang::driver::options::OPT_fdebug_unparse_no_sema: 466 opts.programAction = DebugUnparseNoSema; 467 break; 468 case clang::driver::options::OPT_fdebug_unparse_with_symbols: 469 opts.programAction = DebugUnparseWithSymbols; 470 break; 471 case clang::driver::options::OPT_fdebug_dump_symbols: 472 opts.programAction = DebugDumpSymbols; 473 break; 474 case clang::driver::options::OPT_fdebug_dump_parse_tree: 475 opts.programAction = DebugDumpParseTree; 476 break; 477 case clang::driver::options::OPT_fdebug_dump_pft: 478 opts.programAction = DebugDumpPFT; 479 break; 480 case clang::driver::options::OPT_fdebug_dump_all: 481 opts.programAction = DebugDumpAll; 482 break; 483 case clang::driver::options::OPT_fdebug_dump_parse_tree_no_sema: 484 opts.programAction = DebugDumpParseTreeNoSema; 485 break; 486 case clang::driver::options::OPT_fdebug_dump_provenance: 487 opts.programAction = DebugDumpProvenance; 488 break; 489 case clang::driver::options::OPT_fdebug_dump_parsing_log: 490 opts.programAction = DebugDumpParsingLog; 491 break; 492 case clang::driver::options::OPT_fdebug_measure_parse_tree: 493 opts.programAction = DebugMeasureParseTree; 494 break; 495 case clang::driver::options::OPT_fdebug_pre_fir_tree: 496 opts.programAction = DebugPreFIRTree; 497 break; 498 case clang::driver::options::OPT_fget_symbols_sources: 499 opts.programAction = GetSymbolsSources; 500 break; 501 case clang::driver::options::OPT_fget_definition: 502 opts.programAction = GetDefinition; 503 break; 504 case clang::driver::options::OPT_init_only: 505 opts.programAction = InitOnly; 506 break; 507 508 // TODO: 509 // case clang::driver::options::OPT_emit_llvm: 510 // case clang::driver::options::OPT_emit_llvm_only: 511 // case clang::driver::options::OPT_emit_codegen_only: 512 // case clang::driver::options::OPT_emit_module: 513 // (...) 514 } 515 516 // Parse the values provided with `-fget-definition` (there should be 3 517 // integers) 518 if (llvm::opt::OptSpecifier(a->getOption().getID()) == 519 clang::driver::options::OPT_fget_definition) { 520 unsigned optVals[3] = {0, 0, 0}; 521 522 for (unsigned i = 0; i < 3; i++) { 523 llvm::StringRef val = a->getValue(i); 524 525 if (val.getAsInteger(10, optVals[i])) { 526 // A non-integer was encountered - that's an error. 527 diags.Report(clang::diag::err_drv_invalid_value) 528 << a->getOption().getName() << val; 529 break; 530 } 531 } 532 opts.getDefVals.line = optVals[0]; 533 opts.getDefVals.startColumn = optVals[1]; 534 opts.getDefVals.endColumn = optVals[2]; 535 } 536 } 537 538 // Parsing -load <dsopath> option and storing shared object path 539 if (llvm::opt::Arg *a = args.getLastArg(clang::driver::options::OPT_load)) { 540 opts.plugins.push_back(a->getValue()); 541 } 542 543 // Parsing -plugin <name> option and storing plugin name and setting action 544 if (const llvm::opt::Arg *a = 545 args.getLastArg(clang::driver::options::OPT_plugin)) { 546 opts.programAction = PluginAction; 547 opts.actionName = a->getValue(); 548 } 549 550 opts.outputFile = args.getLastArgValue(clang::driver::options::OPT_o); 551 opts.showHelp = args.hasArg(clang::driver::options::OPT_help); 552 opts.showVersion = args.hasArg(clang::driver::options::OPT_version); 553 554 // Get the input kind (from the value passed via `-x`) 555 InputKind dashX(Language::Unknown); 556 if (const llvm::opt::Arg *a = 557 args.getLastArg(clang::driver::options::OPT_x)) { 558 llvm::StringRef xValue = a->getValue(); 559 // Principal languages. 560 dashX = llvm::StringSwitch<InputKind>(xValue) 561 // Flang does not differentiate between pre-processed and not 562 // pre-processed inputs. 563 .Case("f95", Language::Fortran) 564 .Case("f95-cpp-input", Language::Fortran) 565 .Default(Language::Unknown); 566 567 // Flang's intermediate representations. 568 if (dashX.isUnknown()) 569 dashX = llvm::StringSwitch<InputKind>(xValue) 570 .Case("ir", Language::LLVM_IR) 571 .Case("fir", Language::MLIR) 572 .Case("mlir", Language::MLIR) 573 .Default(Language::Unknown); 574 575 if (dashX.isUnknown()) 576 diags.Report(clang::diag::err_drv_invalid_value) 577 << a->getAsString(args) << a->getValue(); 578 } 579 580 // Collect the input files and save them in our instance of FrontendOptions. 581 std::vector<std::string> inputs = 582 args.getAllArgValues(clang::driver::options::OPT_INPUT); 583 opts.inputs.clear(); 584 if (inputs.empty()) 585 // '-' is the default input if none is given. 586 inputs.push_back("-"); 587 for (unsigned i = 0, e = inputs.size(); i != e; ++i) { 588 InputKind ik = dashX; 589 if (ik.isUnknown()) { 590 ik = FrontendOptions::getInputKindForExtension( 591 llvm::StringRef(inputs[i]).rsplit('.').second); 592 if (ik.isUnknown()) 593 ik = Language::Unknown; 594 if (i == 0) 595 dashX = ik; 596 } 597 598 opts.inputs.emplace_back(std::move(inputs[i]), ik); 599 } 600 601 // Set fortranForm based on options -ffree-form and -ffixed-form. 602 if (const auto *arg = 603 args.getLastArg(clang::driver::options::OPT_ffixed_form, 604 clang::driver::options::OPT_ffree_form)) { 605 opts.fortranForm = 606 arg->getOption().matches(clang::driver::options::OPT_ffixed_form) 607 ? FortranForm::FixedForm 608 : FortranForm::FreeForm; 609 } 610 611 // Set fixedFormColumns based on -ffixed-line-length=<value> 612 if (const auto *arg = 613 args.getLastArg(clang::driver::options::OPT_ffixed_line_length_EQ)) { 614 llvm::StringRef argValue = llvm::StringRef(arg->getValue()); 615 std::int64_t columns = -1; 616 if (argValue == "none") { 617 columns = 0; 618 } else if (argValue.getAsInteger(/*Radix=*/10, columns)) { 619 columns = -1; 620 } 621 if (columns < 0) { 622 diags.Report(clang::diag::err_drv_negative_columns) 623 << arg->getOption().getName() << arg->getValue(); 624 } else if (columns == 0) { 625 opts.fixedFormColumns = 1000000; 626 } else if (columns < 7) { 627 diags.Report(clang::diag::err_drv_small_columns) 628 << arg->getOption().getName() << arg->getValue() << "7"; 629 } else { 630 opts.fixedFormColumns = columns; 631 } 632 } 633 634 // Set conversion based on -fconvert=<value> 635 if (const auto *arg = 636 args.getLastArg(clang::driver::options::OPT_fconvert_EQ)) { 637 const char *argValue = arg->getValue(); 638 if (auto convert = parseConvertArg(argValue)) 639 opts.envDefaults.push_back({"FORT_CONVERT", *convert}); 640 else 641 diags.Report(clang::diag::err_drv_invalid_value) 642 << arg->getAsString(args) << argValue; 643 } 644 645 // -f{no-}implicit-none 646 opts.features.Enable( 647 Fortran::common::LanguageFeature::ImplicitNoneTypeAlways, 648 args.hasFlag(clang::driver::options::OPT_fimplicit_none, 649 clang::driver::options::OPT_fno_implicit_none, false)); 650 651 // -f{no-}backslash 652 opts.features.Enable(Fortran::common::LanguageFeature::BackslashEscapes, 653 args.hasFlag(clang::driver::options::OPT_fbackslash, 654 clang::driver::options::OPT_fno_backslash, 655 false)); 656 657 // -f{no-}logical-abbreviations 658 opts.features.Enable( 659 Fortran::common::LanguageFeature::LogicalAbbreviations, 660 args.hasFlag(clang::driver::options::OPT_flogical_abbreviations, 661 clang::driver::options::OPT_fno_logical_abbreviations, 662 false)); 663 664 // -f{no-}xor-operator 665 opts.features.Enable( 666 Fortran::common::LanguageFeature::XOROperator, 667 args.hasFlag(clang::driver::options::OPT_fxor_operator, 668 clang::driver::options::OPT_fno_xor_operator, false)); 669 670 // -fno-automatic 671 if (args.hasArg(clang::driver::options::OPT_fno_automatic)) { 672 opts.features.Enable(Fortran::common::LanguageFeature::DefaultSave); 673 } 674 675 if (args.hasArg( 676 clang::driver::options::OPT_falternative_parameter_statement)) { 677 opts.features.Enable(Fortran::common::LanguageFeature::OldStyleParameter); 678 } 679 if (const llvm::opt::Arg *arg = 680 args.getLastArg(clang::driver::options::OPT_finput_charset_EQ)) { 681 llvm::StringRef argValue = arg->getValue(); 682 if (argValue == "utf-8") { 683 opts.encoding = Fortran::parser::Encoding::UTF_8; 684 } else if (argValue == "latin-1") { 685 opts.encoding = Fortran::parser::Encoding::LATIN_1; 686 } else { 687 diags.Report(clang::diag::err_drv_invalid_value) 688 << arg->getAsString(args) << argValue; 689 } 690 } 691 692 setUpFrontendBasedOnAction(opts); 693 opts.dashX = dashX; 694 695 return diags.getNumErrors() == numErrorsBefore; 696 } 697 698 // Generate the path to look for intrinsic modules 699 static std::string getIntrinsicDir(const char *argv) { 700 // TODO: Find a system independent API 701 llvm::SmallString<128> driverPath; 702 driverPath.assign(llvm::sys::fs::getMainExecutable(argv, nullptr)); 703 llvm::sys::path::remove_filename(driverPath); 704 driverPath.append("/../include/flang/"); 705 return std::string(driverPath); 706 } 707 708 // Generate the path to look for OpenMP headers 709 static std::string getOpenMPHeadersDir(const char *argv) { 710 llvm::SmallString<128> includePath; 711 includePath.assign(llvm::sys::fs::getMainExecutable(argv, nullptr)); 712 llvm::sys::path::remove_filename(includePath); 713 includePath.append("/../include/flang/OpenMP/"); 714 return std::string(includePath); 715 } 716 717 /// Parses all preprocessor input arguments and populates the preprocessor 718 /// options accordingly. 719 /// 720 /// \param [in] opts The preprocessor options instance 721 /// \param [out] args The list of input arguments 722 static void parsePreprocessorArgs(Fortran::frontend::PreprocessorOptions &opts, 723 llvm::opt::ArgList &args) { 724 // Add macros from the command line. 725 for (const auto *currentArg : args.filtered(clang::driver::options::OPT_D, 726 clang::driver::options::OPT_U)) { 727 if (currentArg->getOption().matches(clang::driver::options::OPT_D)) { 728 opts.addMacroDef(currentArg->getValue()); 729 } else { 730 opts.addMacroUndef(currentArg->getValue()); 731 } 732 } 733 734 // Add the ordered list of -I's. 735 for (const auto *currentArg : args.filtered(clang::driver::options::OPT_I)) 736 opts.searchDirectoriesFromDashI.emplace_back(currentArg->getValue()); 737 738 // Prepend the ordered list of -intrinsic-modules-path 739 // to the default location to search. 740 for (const auto *currentArg : 741 args.filtered(clang::driver::options::OPT_fintrinsic_modules_path)) 742 opts.searchDirectoriesFromIntrModPath.emplace_back(currentArg->getValue()); 743 744 // -cpp/-nocpp 745 if (const auto *currentArg = args.getLastArg( 746 clang::driver::options::OPT_cpp, clang::driver::options::OPT_nocpp)) 747 opts.macrosFlag = 748 (currentArg->getOption().matches(clang::driver::options::OPT_cpp)) 749 ? PPMacrosFlag::Include 750 : PPMacrosFlag::Exclude; 751 752 opts.noReformat = args.hasArg(clang::driver::options::OPT_fno_reformat); 753 opts.noLineDirectives = args.hasArg(clang::driver::options::OPT_P); 754 } 755 756 /// Parses all semantic related arguments and populates the variables 757 /// options accordingly. Returns false if new errors are generated. 758 static bool parseSemaArgs(CompilerInvocation &res, llvm::opt::ArgList &args, 759 clang::DiagnosticsEngine &diags) { 760 unsigned numErrorsBefore = diags.getNumErrors(); 761 762 // -J/module-dir option 763 auto moduleDirList = 764 args.getAllArgValues(clang::driver::options::OPT_module_dir); 765 // User can only specify -J/-module-dir once 766 // https://gcc.gnu.org/onlinedocs/gfortran/Directory-Options.html 767 if (moduleDirList.size() > 1) { 768 const unsigned diagID = 769 diags.getCustomDiagID(clang::DiagnosticsEngine::Error, 770 "Only one '-module-dir/-J' option allowed"); 771 diags.Report(diagID); 772 } 773 if (moduleDirList.size() == 1) 774 res.setModuleDir(moduleDirList[0]); 775 776 // -fdebug-module-writer option 777 if (args.hasArg(clang::driver::options::OPT_fdebug_module_writer)) { 778 res.setDebugModuleDir(true); 779 } 780 781 // -module-suffix 782 if (const auto *moduleSuffix = 783 args.getLastArg(clang::driver::options::OPT_module_suffix)) { 784 res.setModuleFileSuffix(moduleSuffix->getValue()); 785 } 786 787 // -f{no-}analyzed-objects-for-unparse 788 res.setUseAnalyzedObjectsForUnparse(args.hasFlag( 789 clang::driver::options::OPT_fanalyzed_objects_for_unparse, 790 clang::driver::options::OPT_fno_analyzed_objects_for_unparse, true)); 791 792 return diags.getNumErrors() == numErrorsBefore; 793 } 794 795 /// Parses all diagnostics related arguments and populates the variables 796 /// options accordingly. Returns false if new errors are generated. 797 static bool parseDiagArgs(CompilerInvocation &res, llvm::opt::ArgList &args, 798 clang::DiagnosticsEngine &diags) { 799 unsigned numErrorsBefore = diags.getNumErrors(); 800 801 // -Werror option 802 // TODO: Currently throws a Diagnostic for anything other than -W<error>, 803 // this has to change when other -W<opt>'s are supported. 804 if (args.hasArg(clang::driver::options::OPT_W_Joined)) { 805 const auto &wArgs = 806 args.getAllArgValues(clang::driver::options::OPT_W_Joined); 807 for (const auto &wArg : wArgs) { 808 if (wArg == "error") { 809 res.setWarnAsErr(true); 810 } else { 811 const unsigned diagID = 812 diags.getCustomDiagID(clang::DiagnosticsEngine::Error, 813 "Only `-Werror` is supported currently."); 814 diags.Report(diagID); 815 } 816 } 817 } 818 819 // Default to off for `flang-new -fc1`. 820 res.getFrontendOpts().showColors = 821 parseShowColorsArgs(args, /*defaultDiagColor=*/false); 822 823 // Honor color diagnostics. 824 res.getDiagnosticOpts().ShowColors = res.getFrontendOpts().showColors; 825 826 return diags.getNumErrors() == numErrorsBefore; 827 } 828 829 /// Parses all Dialect related arguments and populates the variables 830 /// options accordingly. Returns false if new errors are generated. 831 static bool parseDialectArgs(CompilerInvocation &res, llvm::opt::ArgList &args, 832 clang::DiagnosticsEngine &diags) { 833 unsigned numErrorsBefore = diags.getNumErrors(); 834 835 // -fdefault* family 836 if (args.hasArg(clang::driver::options::OPT_fdefault_real_8)) { 837 res.getDefaultKinds().set_defaultRealKind(8); 838 res.getDefaultKinds().set_doublePrecisionKind(16); 839 } 840 if (args.hasArg(clang::driver::options::OPT_fdefault_integer_8)) { 841 res.getDefaultKinds().set_defaultIntegerKind(8); 842 res.getDefaultKinds().set_subscriptIntegerKind(8); 843 res.getDefaultKinds().set_sizeIntegerKind(8); 844 res.getDefaultKinds().set_defaultLogicalKind(8); 845 } 846 if (args.hasArg(clang::driver::options::OPT_fdefault_double_8)) { 847 if (!args.hasArg(clang::driver::options::OPT_fdefault_real_8)) { 848 // -fdefault-double-8 has to be used with -fdefault-real-8 849 // to be compatible with gfortran 850 const unsigned diagID = diags.getCustomDiagID( 851 clang::DiagnosticsEngine::Error, 852 "Use of `-fdefault-double-8` requires `-fdefault-real-8`"); 853 diags.Report(diagID); 854 } 855 // https://gcc.gnu.org/onlinedocs/gfortran/Fortran-Dialect-Options.html 856 res.getDefaultKinds().set_doublePrecisionKind(8); 857 } 858 if (args.hasArg(clang::driver::options::OPT_flarge_sizes)) 859 res.getDefaultKinds().set_sizeIntegerKind(8); 860 861 // -fopenmp and -fopenacc 862 if (args.hasArg(clang::driver::options::OPT_fopenacc)) { 863 res.getFrontendOpts().features.Enable( 864 Fortran::common::LanguageFeature::OpenACC); 865 } 866 if (args.hasArg(clang::driver::options::OPT_fopenmp)) { 867 // By default OpenMP is set to 1.1 version 868 res.getLangOpts().OpenMPVersion = 11; 869 res.getFrontendOpts().features.Enable( 870 Fortran::common::LanguageFeature::OpenMP); 871 if (int Version = getLastArgIntValue( 872 args, clang::driver::options::OPT_fopenmp_version_EQ, 873 res.getLangOpts().OpenMPVersion, diags)) { 874 res.getLangOpts().OpenMPVersion = Version; 875 } 876 if (args.hasArg(clang::driver::options::OPT_fopenmp_is_target_device)) { 877 res.getLangOpts().OpenMPIsTargetDevice = 1; 878 879 // Get OpenMP host file path if any and report if a non existent file is 880 // found 881 if (auto *arg = args.getLastArg( 882 clang::driver::options::OPT_fopenmp_host_ir_file_path)) { 883 res.getLangOpts().OMPHostIRFile = arg->getValue(); 884 if (!llvm::sys::fs::exists(res.getLangOpts().OMPHostIRFile)) 885 diags.Report(clang::diag::err_drv_omp_host_ir_file_not_found) 886 << res.getLangOpts().OMPHostIRFile; 887 } 888 889 if (args.hasFlag( 890 clang::driver::options::OPT_fopenmp_assume_teams_oversubscription, 891 clang::driver::options:: 892 OPT_fno_openmp_assume_teams_oversubscription, 893 /*Default=*/false)) 894 res.getLangOpts().OpenMPTeamSubscription = true; 895 896 if (args.hasArg( 897 clang::driver::options::OPT_fopenmp_assume_no_thread_state)) 898 res.getLangOpts().OpenMPNoThreadState = 1; 899 900 if (args.hasArg( 901 clang::driver::options::OPT_fopenmp_assume_no_nested_parallelism)) 902 res.getLangOpts().OpenMPNoNestedParallelism = 1; 903 904 if (args.hasFlag(clang::driver::options:: 905 OPT_fopenmp_assume_threads_oversubscription, 906 clang::driver::options:: 907 OPT_fno_openmp_assume_threads_oversubscription, 908 /*Default=*/false)) 909 res.getLangOpts().OpenMPThreadSubscription = true; 910 911 if ((args.hasArg(clang::driver::options::OPT_fopenmp_target_debug) || 912 args.hasArg(clang::driver::options::OPT_fopenmp_target_debug_EQ))) { 913 res.getLangOpts().OpenMPTargetDebug = getLastArgIntValue( 914 args, clang::driver::options::OPT_fopenmp_target_debug_EQ, 915 res.getLangOpts().OpenMPTargetDebug, diags); 916 917 if (!res.getLangOpts().OpenMPTargetDebug && 918 args.hasArg(clang::driver::options::OPT_fopenmp_target_debug)) 919 res.getLangOpts().OpenMPTargetDebug = 1; 920 } 921 } 922 923 switch (llvm::Triple(res.getTargetOpts().triple).getArch()) { 924 case llvm::Triple::nvptx: 925 case llvm::Triple::nvptx64: 926 case llvm::Triple::amdgcn: 927 if (!res.getLangOpts().OpenMPIsTargetDevice) { 928 const unsigned diagID = diags.getCustomDiagID( 929 clang::DiagnosticsEngine::Error, 930 "OpenMP AMDGPU/NVPTX is only prepared to deal with device code."); 931 diags.Report(diagID); 932 } 933 res.getLangOpts().OpenMPIsGPU = 1; 934 break; 935 default: 936 res.getLangOpts().OpenMPIsGPU = 0; 937 break; 938 } 939 } 940 941 // -pedantic 942 if (args.hasArg(clang::driver::options::OPT_pedantic)) { 943 res.setEnableConformanceChecks(); 944 res.setEnableUsageChecks(); 945 } 946 // -std=f2018 947 // TODO: Set proper options when more fortran standards 948 // are supported. 949 if (args.hasArg(clang::driver::options::OPT_std_EQ)) { 950 auto standard = args.getLastArgValue(clang::driver::options::OPT_std_EQ); 951 // We only allow f2018 as the given standard 952 if (standard.equals("f2018")) { 953 res.setEnableConformanceChecks(); 954 } else { 955 const unsigned diagID = 956 diags.getCustomDiagID(clang::DiagnosticsEngine::Error, 957 "Only -std=f2018 is allowed currently."); 958 diags.Report(diagID); 959 } 960 } 961 return diags.getNumErrors() == numErrorsBefore; 962 } 963 964 /// Parses all floating point related arguments and populates the 965 /// CompilerInvocation accordingly. 966 /// Returns false if new errors are generated. 967 /// 968 /// \param [out] invoc Stores the processed arguments 969 /// \param [in] args The compiler invocation arguments to parse 970 /// \param [out] diags DiagnosticsEngine to report erros with 971 static bool parseFloatingPointArgs(CompilerInvocation &invoc, 972 llvm::opt::ArgList &args, 973 clang::DiagnosticsEngine &diags) { 974 LangOptions &opts = invoc.getLangOpts(); 975 976 if (const llvm::opt::Arg *a = 977 args.getLastArg(clang::driver::options::OPT_ffp_contract)) { 978 const llvm::StringRef val = a->getValue(); 979 enum LangOptions::FPModeKind fpContractMode; 980 981 if (val == "off") 982 fpContractMode = LangOptions::FPM_Off; 983 else if (val == "fast") 984 fpContractMode = LangOptions::FPM_Fast; 985 else { 986 diags.Report(clang::diag::err_drv_unsupported_option_argument) 987 << a->getSpelling() << val; 988 return false; 989 } 990 991 opts.setFPContractMode(fpContractMode); 992 } 993 994 if (args.getLastArg(clang::driver::options::OPT_menable_no_infinities)) { 995 opts.NoHonorInfs = true; 996 } 997 998 if (args.getLastArg(clang::driver::options::OPT_menable_no_nans)) { 999 opts.NoHonorNaNs = true; 1000 } 1001 1002 if (args.getLastArg(clang::driver::options::OPT_fapprox_func)) { 1003 opts.ApproxFunc = true; 1004 } 1005 1006 if (args.getLastArg(clang::driver::options::OPT_fno_signed_zeros)) { 1007 opts.NoSignedZeros = true; 1008 } 1009 1010 if (args.getLastArg(clang::driver::options::OPT_mreassociate)) { 1011 opts.AssociativeMath = true; 1012 } 1013 1014 if (args.getLastArg(clang::driver::options::OPT_freciprocal_math)) { 1015 opts.ReciprocalMath = true; 1016 } 1017 1018 if (args.getLastArg(clang::driver::options::OPT_ffast_math)) { 1019 opts.NoHonorInfs = true; 1020 opts.NoHonorNaNs = true; 1021 opts.AssociativeMath = true; 1022 opts.ReciprocalMath = true; 1023 opts.ApproxFunc = true; 1024 opts.NoSignedZeros = true; 1025 opts.setFPContractMode(LangOptions::FPM_Fast); 1026 } 1027 1028 return true; 1029 } 1030 1031 /// Parses vscale range options and populates the CompilerInvocation 1032 /// accordingly. 1033 /// Returns false if new errors are generated. 1034 /// 1035 /// \param [out] invoc Stores the processed arguments 1036 /// \param [in] args The compiler invocation arguments to parse 1037 /// \param [out] diags DiagnosticsEngine to report erros with 1038 static bool parseVScaleArgs(CompilerInvocation &invoc, llvm::opt::ArgList &args, 1039 clang::DiagnosticsEngine &diags) { 1040 LangOptions &opts = invoc.getLangOpts(); 1041 if (const auto arg = 1042 args.getLastArg(clang::driver::options::OPT_mvscale_min_EQ)) { 1043 llvm::StringRef argValue = llvm::StringRef(arg->getValue()); 1044 unsigned VScaleMin; 1045 if (argValue.getAsInteger(/*Radix=*/10, VScaleMin)) { 1046 diags.Report(clang::diag::err_drv_unsupported_option_argument) 1047 << arg->getSpelling() << argValue; 1048 return false; 1049 } 1050 opts.VScaleMin = VScaleMin; 1051 } 1052 if (const auto arg = 1053 args.getLastArg(clang::driver::options::OPT_mvscale_max_EQ)) { 1054 llvm::StringRef argValue = llvm::StringRef(arg->getValue()); 1055 unsigned VScaleMax; 1056 if (argValue.getAsInteger(/*Radix=w*/ 10, VScaleMax)) { 1057 diags.Report(clang::diag::err_drv_unsupported_option_argument) 1058 << arg->getSpelling() << argValue; 1059 return false; 1060 } 1061 opts.VScaleMax = VScaleMax; 1062 } 1063 return true; 1064 } 1065 1066 static bool parseLinkerOptionsArgs(CompilerInvocation &invoc, 1067 llvm::opt::ArgList &args, 1068 clang::DiagnosticsEngine &diags) { 1069 llvm::Triple triple = llvm::Triple(invoc.getTargetOpts().triple); 1070 1071 // TODO: support --dependent-lib on other platforms when MLIR supports 1072 // !llvm.dependent.lib 1073 if (args.hasArg(clang::driver::options::OPT_dependent_lib) && 1074 !triple.isOSWindows()) { 1075 const unsigned diagID = 1076 diags.getCustomDiagID(clang::DiagnosticsEngine::Error, 1077 "--dependent-lib is only supported on Windows"); 1078 diags.Report(diagID); 1079 return false; 1080 } 1081 1082 invoc.getCodeGenOpts().DependentLibs = 1083 args.getAllArgValues(clang::driver::options::OPT_dependent_lib); 1084 return true; 1085 } 1086 1087 bool CompilerInvocation::createFromArgs( 1088 CompilerInvocation &res, llvm::ArrayRef<const char *> commandLineArgs, 1089 clang::DiagnosticsEngine &diags, const char *argv0) { 1090 1091 bool success = true; 1092 1093 // Set the default triple for this CompilerInvocation. This might be 1094 // overridden by users with `-triple` (see the call to `ParseTargetArgs` 1095 // below). 1096 // NOTE: Like in Clang, it would be nice to use option marshalling 1097 // for this so that the entire logic for setting-up the triple is in one 1098 // place. 1099 res.getTargetOpts().triple = 1100 llvm::Triple::normalize(llvm::sys::getDefaultTargetTriple()); 1101 1102 // Parse the arguments 1103 const llvm::opt::OptTable &opts = clang::driver::getDriverOptTable(); 1104 llvm::opt::Visibility visibilityMask(clang::driver::options::FC1Option); 1105 unsigned missingArgIndex, missingArgCount; 1106 llvm::opt::InputArgList args = opts.ParseArgs( 1107 commandLineArgs, missingArgIndex, missingArgCount, visibilityMask); 1108 1109 // Check for missing argument error. 1110 if (missingArgCount) { 1111 diags.Report(clang::diag::err_drv_missing_argument) 1112 << args.getArgString(missingArgIndex) << missingArgCount; 1113 success = false; 1114 } 1115 1116 // Issue errors on unknown arguments 1117 for (const auto *a : args.filtered(clang::driver::options::OPT_UNKNOWN)) { 1118 auto argString = a->getAsString(args); 1119 std::string nearest; 1120 if (opts.findNearest(argString, nearest, visibilityMask) > 1) 1121 diags.Report(clang::diag::err_drv_unknown_argument) << argString; 1122 else 1123 diags.Report(clang::diag::err_drv_unknown_argument_with_suggestion) 1124 << argString << nearest; 1125 success = false; 1126 } 1127 1128 // -flang-experimental-hlfir 1129 if (args.hasArg(clang::driver::options::OPT_flang_experimental_hlfir) || 1130 args.hasArg(clang::driver::options::OPT_emit_hlfir)) { 1131 res.loweringOpts.setLowerToHighLevelFIR(true); 1132 } 1133 1134 // -flang-deprecated-no-hlfir 1135 if (args.hasArg(clang::driver::options::OPT_flang_deprecated_no_hlfir) && 1136 !args.hasArg(clang::driver::options::OPT_emit_hlfir)) { 1137 if (args.hasArg(clang::driver::options::OPT_flang_experimental_hlfir)) { 1138 const unsigned diagID = diags.getCustomDiagID( 1139 clang::DiagnosticsEngine::Error, 1140 "Options '-flang-experimental-hlfir' and " 1141 "'-flang-deprecated-no-hlfir' cannot be both specified"); 1142 diags.Report(diagID); 1143 } 1144 res.loweringOpts.setLowerToHighLevelFIR(false); 1145 } 1146 1147 if (args.hasArg(clang::driver::options::OPT_flang_experimental_polymorphism)) { 1148 res.loweringOpts.setPolymorphicTypeImpl(true); 1149 } 1150 1151 // -fno-ppc-native-vector-element-order 1152 if (args.hasArg(clang::driver::options::OPT_fno_ppc_native_vec_elem_order)) { 1153 res.loweringOpts.setNoPPCNativeVecElemOrder(true); 1154 } 1155 1156 // Preserve all the remark options requested, i.e. -Rpass, -Rpass-missed or 1157 // -Rpass-analysis. This will be used later when processing and outputting the 1158 // remarks generated by LLVM in ExecuteCompilerInvocation.cpp. 1159 for (auto *a : args.filtered(clang::driver::options::OPT_R_Group)) { 1160 if (a->getOption().matches(clang::driver::options::OPT_R_value_Group)) 1161 // This is -Rfoo=, where foo is the name of the diagnostic 1162 // group. Add only the remark option name to the diagnostics. e.g. for 1163 // -Rpass= we will add the string "pass". 1164 res.getDiagnosticOpts().Remarks.push_back( 1165 std::string(a->getOption().getName().drop_front(1).rtrim("=-"))); 1166 else 1167 // If no regex was provided, add the provided value, e.g. for -Rpass add 1168 // the string "pass". 1169 res.getDiagnosticOpts().Remarks.push_back(a->getValue()); 1170 } 1171 1172 success &= parseFrontendArgs(res.getFrontendOpts(), args, diags); 1173 parseTargetArgs(res.getTargetOpts(), args); 1174 parsePreprocessorArgs(res.getPreprocessorOpts(), args); 1175 parseCodeGenArgs(res.getCodeGenOpts(), args, diags); 1176 success &= parseDebugArgs(res.getCodeGenOpts(), args, diags); 1177 success &= parseVectorLibArg(res.getCodeGenOpts(), args, diags); 1178 success &= parseSemaArgs(res, args, diags); 1179 success &= parseDialectArgs(res, args, diags); 1180 success &= parseDiagArgs(res, args, diags); 1181 1182 // Collect LLVM (-mllvm) and MLIR (-mmlir) options. 1183 // NOTE: Try to avoid adding any options directly to `llvmArgs` or 1184 // `mlirArgs`. Instead, you can use 1185 // * `-mllvm <your-llvm-option>`, or 1186 // * `-mmlir <your-mlir-option>`. 1187 res.frontendOpts.llvmArgs = 1188 args.getAllArgValues(clang::driver::options::OPT_mllvm); 1189 res.frontendOpts.mlirArgs = 1190 args.getAllArgValues(clang::driver::options::OPT_mmlir); 1191 1192 success &= parseFloatingPointArgs(res, args, diags); 1193 1194 success &= parseVScaleArgs(res, args, diags); 1195 1196 success &= parseLinkerOptionsArgs(res, args, diags); 1197 1198 // Set the string to be used as the return value of the COMPILER_OPTIONS 1199 // intrinsic of iso_fortran_env. This is either passed in from the parent 1200 // compiler driver invocation with an environment variable, or failing that 1201 // set to the command line arguments of the frontend driver invocation. 1202 res.allCompilerInvocOpts = std::string(); 1203 llvm::raw_string_ostream os(res.allCompilerInvocOpts); 1204 char *compilerOptsEnv = std::getenv("FLANG_COMPILER_OPTIONS_STRING"); 1205 if (compilerOptsEnv != nullptr) { 1206 os << compilerOptsEnv; 1207 } else { 1208 os << argv0 << ' '; 1209 for (auto it = commandLineArgs.begin(), e = commandLineArgs.end(); it != e; 1210 ++it) { 1211 os << ' ' << *it; 1212 } 1213 } 1214 1215 res.setArgv0(argv0); 1216 1217 return success; 1218 } 1219 1220 void CompilerInvocation::collectMacroDefinitions() { 1221 auto &ppOpts = this->getPreprocessorOpts(); 1222 1223 for (unsigned i = 0, n = ppOpts.macros.size(); i != n; ++i) { 1224 llvm::StringRef macro = ppOpts.macros[i].first; 1225 bool isUndef = ppOpts.macros[i].second; 1226 1227 std::pair<llvm::StringRef, llvm::StringRef> macroPair = macro.split('='); 1228 llvm::StringRef macroName = macroPair.first; 1229 llvm::StringRef macroBody = macroPair.second; 1230 1231 // For an #undef'd macro, we only care about the name. 1232 if (isUndef) { 1233 parserOpts.predefinitions.emplace_back(macroName.str(), 1234 std::optional<std::string>{}); 1235 continue; 1236 } 1237 1238 // For a #define'd macro, figure out the actual definition. 1239 if (macroName.size() == macro.size()) 1240 macroBody = "1"; 1241 else { 1242 // Note: GCC drops anything following an end-of-line character. 1243 llvm::StringRef::size_type end = macroBody.find_first_of("\n\r"); 1244 macroBody = macroBody.substr(0, end); 1245 } 1246 parserOpts.predefinitions.emplace_back( 1247 macroName, std::optional<std::string>(macroBody.str())); 1248 } 1249 } 1250 1251 void CompilerInvocation::setDefaultFortranOpts() { 1252 auto &fortranOptions = getFortranOpts(); 1253 1254 std::vector<std::string> searchDirectories{"."s}; 1255 fortranOptions.searchDirectories = searchDirectories; 1256 1257 // Add the location of omp_lib.h to the search directories. Currently this is 1258 // identical to the modules' directory. 1259 fortranOptions.searchDirectories.emplace_back( 1260 getOpenMPHeadersDir(getArgv0())); 1261 1262 fortranOptions.isFixedForm = false; 1263 } 1264 1265 // TODO: When expanding this method, consider creating a dedicated API for 1266 // this. Also at some point we will need to differentiate between different 1267 // targets and add dedicated predefines for each. 1268 void CompilerInvocation::setDefaultPredefinitions() { 1269 auto &fortranOptions = getFortranOpts(); 1270 const auto &frontendOptions = getFrontendOpts(); 1271 // Populate the macro list with version numbers and other predefinitions. 1272 fortranOptions.predefinitions.emplace_back("__flang__", "1"); 1273 fortranOptions.predefinitions.emplace_back("__flang_major__", 1274 FLANG_VERSION_MAJOR_STRING); 1275 fortranOptions.predefinitions.emplace_back("__flang_minor__", 1276 FLANG_VERSION_MINOR_STRING); 1277 fortranOptions.predefinitions.emplace_back("__flang_patchlevel__", 1278 FLANG_VERSION_PATCHLEVEL_STRING); 1279 1280 // Add predefinitions based on extensions enabled 1281 if (frontendOptions.features.IsEnabled( 1282 Fortran::common::LanguageFeature::OpenACC)) { 1283 fortranOptions.predefinitions.emplace_back("_OPENACC", "202211"); 1284 } 1285 if (frontendOptions.features.IsEnabled( 1286 Fortran::common::LanguageFeature::OpenMP)) { 1287 Fortran::common::setOpenMPMacro(getLangOpts().OpenMPVersion, 1288 fortranOptions.predefinitions); 1289 } 1290 llvm::Triple targetTriple{llvm::Triple(this->targetOpts.triple)}; 1291 if (targetTriple.getArch() == llvm::Triple::ArchType::x86_64) { 1292 fortranOptions.predefinitions.emplace_back("__x86_64__", "1"); 1293 fortranOptions.predefinitions.emplace_back("__x86_64", "1"); 1294 } 1295 } 1296 1297 void CompilerInvocation::setFortranOpts() { 1298 auto &fortranOptions = getFortranOpts(); 1299 const auto &frontendOptions = getFrontendOpts(); 1300 const auto &preprocessorOptions = getPreprocessorOpts(); 1301 auto &moduleDirJ = getModuleDir(); 1302 1303 if (frontendOptions.fortranForm != FortranForm::Unknown) { 1304 fortranOptions.isFixedForm = 1305 frontendOptions.fortranForm == FortranForm::FixedForm; 1306 } 1307 fortranOptions.fixedFormColumns = frontendOptions.fixedFormColumns; 1308 1309 fortranOptions.features = frontendOptions.features; 1310 fortranOptions.encoding = frontendOptions.encoding; 1311 1312 // Adding search directories specified by -I 1313 fortranOptions.searchDirectories.insert( 1314 fortranOptions.searchDirectories.end(), 1315 preprocessorOptions.searchDirectoriesFromDashI.begin(), 1316 preprocessorOptions.searchDirectoriesFromDashI.end()); 1317 1318 // Add the ordered list of -intrinsic-modules-path 1319 fortranOptions.searchDirectories.insert( 1320 fortranOptions.searchDirectories.end(), 1321 preprocessorOptions.searchDirectoriesFromIntrModPath.begin(), 1322 preprocessorOptions.searchDirectoriesFromIntrModPath.end()); 1323 1324 // Add the default intrinsic module directory 1325 fortranOptions.intrinsicModuleDirectories.emplace_back( 1326 getIntrinsicDir(getArgv0())); 1327 1328 // Add the directory supplied through -J/-module-dir to the list of search 1329 // directories 1330 if (moduleDirJ != ".") 1331 fortranOptions.searchDirectories.emplace_back(moduleDirJ); 1332 1333 if (frontendOptions.instrumentedParse) 1334 fortranOptions.instrumentedParse = true; 1335 1336 if (frontendOptions.showColors) 1337 fortranOptions.showColors = true; 1338 1339 if (frontendOptions.needProvenanceRangeToCharBlockMappings) 1340 fortranOptions.needProvenanceRangeToCharBlockMappings = true; 1341 1342 if (getEnableConformanceChecks()) 1343 fortranOptions.features.WarnOnAllNonstandard(); 1344 1345 if (getEnableUsageChecks()) 1346 fortranOptions.features.WarnOnAllUsage(); 1347 } 1348 1349 std::unique_ptr<Fortran::semantics::SemanticsContext> 1350 CompilerInvocation::getSemanticsCtx( 1351 Fortran::parser::AllCookedSources &allCookedSources, 1352 const llvm::TargetMachine &targetMachine) { 1353 auto &fortranOptions = getFortranOpts(); 1354 1355 auto semanticsContext = std::make_unique<semantics::SemanticsContext>( 1356 getDefaultKinds(), fortranOptions.features, allCookedSources); 1357 1358 semanticsContext->set_moduleDirectory(getModuleDir()) 1359 .set_searchDirectories(fortranOptions.searchDirectories) 1360 .set_intrinsicModuleDirectories(fortranOptions.intrinsicModuleDirectories) 1361 .set_warningsAreErrors(getWarnAsErr()) 1362 .set_moduleFileSuffix(getModuleFileSuffix()) 1363 .set_underscoring(getCodeGenOpts().Underscoring); 1364 1365 std::string compilerVersion = Fortran::common::getFlangFullVersion(); 1366 Fortran::tools::setUpTargetCharacteristics( 1367 semanticsContext->targetCharacteristics(), targetMachine, compilerVersion, 1368 allCompilerInvocOpts); 1369 return semanticsContext; 1370 } 1371 1372 /// Set \p loweringOptions controlling lowering behavior based 1373 /// on the \p optimizationLevel. 1374 void CompilerInvocation::setLoweringOptions() { 1375 const CodeGenOptions &codegenOpts = getCodeGenOpts(); 1376 1377 // Lower TRANSPOSE as a runtime call under -O0. 1378 loweringOpts.setOptimizeTranspose(codegenOpts.OptimizationLevel > 0); 1379 loweringOpts.setUnderscoring(codegenOpts.Underscoring); 1380 1381 const LangOptions &langOptions = getLangOpts(); 1382 Fortran::common::MathOptionsBase &mathOpts = loweringOpts.getMathOptions(); 1383 // TODO: when LangOptions are finalized, we can represent 1384 // the math related options using Fortran::commmon::MathOptionsBase, 1385 // so that we can just copy it into LoweringOptions. 1386 mathOpts 1387 .setFPContractEnabled(langOptions.getFPContractMode() == 1388 LangOptions::FPM_Fast) 1389 .setNoHonorInfs(langOptions.NoHonorInfs) 1390 .setNoHonorNaNs(langOptions.NoHonorNaNs) 1391 .setApproxFunc(langOptions.ApproxFunc) 1392 .setNoSignedZeros(langOptions.NoSignedZeros) 1393 .setAssociativeMath(langOptions.AssociativeMath) 1394 .setReciprocalMath(langOptions.ReciprocalMath); 1395 } 1396