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/Frontend/CodeGenOptions.h" 16 #include "flang/Frontend/PreprocessorOptions.h" 17 #include "flang/Frontend/TargetOptions.h" 18 #include "flang/Semantics/semantics.h" 19 #include "flang/Version.inc" 20 #include "clang/Basic/AllDiagnostics.h" 21 #include "clang/Basic/DiagnosticDriver.h" 22 #include "clang/Basic/DiagnosticOptions.h" 23 #include "clang/Driver/DriverDiagnostic.h" 24 #include "clang/Driver/OptionUtils.h" 25 #include "clang/Driver/Options.h" 26 #include "llvm/ADT/StringRef.h" 27 #include "llvm/ADT/StringSwitch.h" 28 #include "llvm/Option/Arg.h" 29 #include "llvm/Option/ArgList.h" 30 #include "llvm/Option/OptTable.h" 31 #include "llvm/Support/FileSystem.h" 32 #include "llvm/Support/FileUtilities.h" 33 #include "llvm/Support/Path.h" 34 #include "llvm/Support/Process.h" 35 #include "llvm/Support/raw_ostream.h" 36 #include "llvm/TargetParser/Host.h" 37 #include "llvm/TargetParser/Triple.h" 38 #include <memory> 39 #include <optional> 40 41 using namespace Fortran::frontend; 42 43 //===----------------------------------------------------------------------===// 44 // Initialization. 45 //===----------------------------------------------------------------------===// 46 CompilerInvocationBase::CompilerInvocationBase() 47 : diagnosticOpts(new clang::DiagnosticOptions()), 48 preprocessorOpts(new PreprocessorOptions()) {} 49 50 CompilerInvocationBase::CompilerInvocationBase(const CompilerInvocationBase &x) 51 : diagnosticOpts(new clang::DiagnosticOptions(x.getDiagnosticOpts())), 52 preprocessorOpts(new PreprocessorOptions(x.getPreprocessorOpts())) {} 53 54 CompilerInvocationBase::~CompilerInvocationBase() = default; 55 56 //===----------------------------------------------------------------------===// 57 // Deserialization (from args) 58 //===----------------------------------------------------------------------===// 59 static bool parseShowColorsArgs(const llvm::opt::ArgList &args, 60 bool defaultColor = true) { 61 // Color diagnostics default to auto ("on" if terminal supports) in the 62 // compiler driver `flang-new` but default to off in the frontend driver 63 // `flang-new -fc1`, needing an explicit OPT_fdiagnostics_color. 64 // Support both clang's -f[no-]color-diagnostics and gcc's 65 // -f[no-]diagnostics-colors[=never|always|auto]. 66 enum { 67 Colors_On, 68 Colors_Off, 69 Colors_Auto 70 } showColors = defaultColor ? Colors_Auto : Colors_Off; 71 72 for (auto *a : args) { 73 const llvm::opt::Option &opt = a->getOption(); 74 if (opt.matches(clang::driver::options::OPT_fcolor_diagnostics)) { 75 showColors = Colors_On; 76 } else if (opt.matches(clang::driver::options::OPT_fno_color_diagnostics)) { 77 showColors = Colors_Off; 78 } else if (opt.matches(clang::driver::options::OPT_fdiagnostics_color_EQ)) { 79 llvm::StringRef value(a->getValue()); 80 if (value == "always") 81 showColors = Colors_On; 82 else if (value == "never") 83 showColors = Colors_Off; 84 else if (value == "auto") 85 showColors = Colors_Auto; 86 } 87 } 88 89 return showColors == Colors_On || 90 (showColors == Colors_Auto && 91 llvm::sys::Process::StandardErrHasColors()); 92 } 93 94 /// Extracts the optimisation level from \a args. 95 static unsigned getOptimizationLevel(llvm::opt::ArgList &args, 96 clang::DiagnosticsEngine &diags) { 97 unsigned defaultOpt = llvm::CodeGenOpt::None; 98 99 if (llvm::opt::Arg *a = 100 args.getLastArg(clang::driver::options::OPT_O_Group)) { 101 if (a->getOption().matches(clang::driver::options::OPT_O0)) 102 return llvm::CodeGenOpt::None; 103 104 assert(a->getOption().matches(clang::driver::options::OPT_O)); 105 106 return getLastArgIntValue(args, clang::driver::options::OPT_O, defaultOpt, 107 diags); 108 } 109 110 return defaultOpt; 111 } 112 113 bool Fortran::frontend::parseDiagnosticArgs(clang::DiagnosticOptions &opts, 114 llvm::opt::ArgList &args) { 115 opts.ShowColors = parseShowColorsArgs(args); 116 117 return true; 118 } 119 120 static void parseCodeGenArgs(Fortran::frontend::CodeGenOptions &opts, 121 llvm::opt::ArgList &args, 122 clang::DiagnosticsEngine &diags) { 123 opts.OptimizationLevel = getOptimizationLevel(args, diags); 124 125 if (args.hasFlag(clang::driver::options::OPT_fdebug_pass_manager, 126 clang::driver::options::OPT_fno_debug_pass_manager, false)) 127 opts.DebugPassManager = 1; 128 129 if (args.hasFlag(clang::driver::options::OPT_fstack_arrays, 130 clang::driver::options::OPT_fno_stack_arrays, false)) { 131 opts.StackArrays = 1; 132 } 133 134 for (auto *a : args.filtered(clang::driver::options::OPT_fpass_plugin_EQ)) 135 opts.LLVMPassPlugins.push_back(a->getValue()); 136 137 // -fembed-offload-object option 138 for (auto *a : 139 args.filtered(clang::driver::options::OPT_fembed_offload_object_EQ)) 140 opts.OffloadObjects.push_back(a->getValue()); 141 142 // -flto=full/thin option. 143 if (const llvm::opt::Arg *a = 144 args.getLastArg(clang::driver::options::OPT_flto_EQ)) { 145 llvm::StringRef s = a->getValue(); 146 assert((s == "full" || s == "thin") && "Unknown LTO mode."); 147 if (s == "full") 148 opts.PrepareForFullLTO = true; 149 else 150 opts.PrepareForThinLTO = true; 151 } 152 153 if (auto *a = args.getLastArg(clang::driver::options::OPT_save_temps_EQ)) 154 opts.SaveTempsDir = a->getValue(); 155 156 // -mrelocation-model option. 157 if (const llvm::opt::Arg *a = 158 args.getLastArg(clang::driver::options::OPT_mrelocation_model)) { 159 llvm::StringRef modelName = a->getValue(); 160 auto relocModel = 161 llvm::StringSwitch<std::optional<llvm::Reloc::Model>>(modelName) 162 .Case("static", llvm::Reloc::Static) 163 .Case("pic", llvm::Reloc::PIC_) 164 .Case("dynamic-no-pic", llvm::Reloc::DynamicNoPIC) 165 .Case("ropi", llvm::Reloc::ROPI) 166 .Case("rwpi", llvm::Reloc::RWPI) 167 .Case("ropi-rwpi", llvm::Reloc::ROPI_RWPI) 168 .Default(std::nullopt); 169 if (relocModel.has_value()) 170 opts.setRelocationModel(*relocModel); 171 else 172 diags.Report(clang::diag::err_drv_invalid_value) 173 << a->getAsString(args) << modelName; 174 } 175 176 // -pic-level and -pic-is-pie option. 177 if (int picLevel = getLastArgIntValue( 178 args, clang::driver::options::OPT_pic_level, 0, diags)) { 179 if (picLevel > 2) 180 diags.Report(clang::diag::err_drv_invalid_value) 181 << args.getLastArg(clang::driver::options::OPT_pic_level) 182 ->getAsString(args) 183 << picLevel; 184 185 opts.PICLevel = picLevel; 186 if (args.hasArg(clang::driver::options::OPT_pic_is_pie)) 187 opts.IsPIE = 1; 188 } 189 190 // This option is compatible with -f[no-]underscoring in gfortran. 191 if (args.hasFlag(clang::driver::options::OPT_fno_underscoring, 192 clang::driver::options::OPT_funderscoring, false)) { 193 opts.Underscoring = 0; 194 } 195 } 196 197 /// Parses all target input arguments and populates the target 198 /// options accordingly. 199 /// 200 /// \param [in] opts The target options instance to update 201 /// \param [in] args The list of input arguments (from the compiler invocation) 202 static void parseTargetArgs(TargetOptions &opts, llvm::opt::ArgList &args) { 203 if (const llvm::opt::Arg *a = 204 args.getLastArg(clang::driver::options::OPT_triple)) 205 opts.triple = a->getValue(); 206 207 if (const llvm::opt::Arg *a = 208 args.getLastArg(clang::driver::options::OPT_target_cpu)) 209 opts.cpu = a->getValue(); 210 211 for (const llvm::opt::Arg *currentArg : 212 args.filtered(clang::driver::options::OPT_target_feature)) 213 opts.featuresAsWritten.emplace_back(currentArg->getValue()); 214 } 215 216 // Tweak the frontend configuration based on the frontend action 217 static void setUpFrontendBasedOnAction(FrontendOptions &opts) { 218 if (opts.programAction == DebugDumpParsingLog) 219 opts.instrumentedParse = true; 220 221 if (opts.programAction == DebugDumpProvenance || 222 opts.programAction == Fortran::frontend::GetDefinition) 223 opts.needProvenanceRangeToCharBlockMappings = true; 224 } 225 226 /// Parse the argument specified for the -fconvert=<value> option 227 static std::optional<const char *> parseConvertArg(const char *s) { 228 return llvm::StringSwitch<std::optional<const char *>>(s) 229 .Case("unknown", "UNKNOWN") 230 .Case("native", "NATIVE") 231 .Case("little-endian", "LITTLE_ENDIAN") 232 .Case("big-endian", "BIG_ENDIAN") 233 .Case("swap", "SWAP") 234 .Default(std::nullopt); 235 } 236 237 static bool parseFrontendArgs(FrontendOptions &opts, llvm::opt::ArgList &args, 238 clang::DiagnosticsEngine &diags) { 239 unsigned numErrorsBefore = diags.getNumErrors(); 240 241 // By default the frontend driver creates a ParseSyntaxOnly action. 242 opts.programAction = ParseSyntaxOnly; 243 244 // Treat multiple action options as an invocation error. Note that `clang 245 // -cc1` does accept multiple action options, but will only consider the 246 // rightmost one. 247 if (args.hasMultipleArgs(clang::driver::options::OPT_Action_Group)) { 248 const unsigned diagID = diags.getCustomDiagID( 249 clang::DiagnosticsEngine::Error, "Only one action option is allowed"); 250 diags.Report(diagID); 251 return false; 252 } 253 254 // Identify the action (i.e. opts.ProgramAction) 255 if (const llvm::opt::Arg *a = 256 args.getLastArg(clang::driver::options::OPT_Action_Group)) { 257 switch (a->getOption().getID()) { 258 default: { 259 llvm_unreachable("Invalid option in group!"); 260 } 261 case clang::driver::options::OPT_test_io: 262 opts.programAction = InputOutputTest; 263 break; 264 case clang::driver::options::OPT_E: 265 opts.programAction = PrintPreprocessedInput; 266 break; 267 case clang::driver::options::OPT_fsyntax_only: 268 opts.programAction = ParseSyntaxOnly; 269 break; 270 case clang::driver::options::OPT_emit_mlir: 271 opts.programAction = EmitMLIR; 272 break; 273 case clang::driver::options::OPT_emit_llvm: 274 opts.programAction = EmitLLVM; 275 break; 276 case clang::driver::options::OPT_emit_llvm_bc: 277 opts.programAction = EmitLLVMBitcode; 278 break; 279 case clang::driver::options::OPT_emit_obj: 280 opts.programAction = EmitObj; 281 break; 282 case clang::driver::options::OPT_S: 283 opts.programAction = EmitAssembly; 284 break; 285 case clang::driver::options::OPT_fdebug_unparse: 286 opts.programAction = DebugUnparse; 287 break; 288 case clang::driver::options::OPT_fdebug_unparse_no_sema: 289 opts.programAction = DebugUnparseNoSema; 290 break; 291 case clang::driver::options::OPT_fdebug_unparse_with_symbols: 292 opts.programAction = DebugUnparseWithSymbols; 293 break; 294 case clang::driver::options::OPT_fdebug_dump_symbols: 295 opts.programAction = DebugDumpSymbols; 296 break; 297 case clang::driver::options::OPT_fdebug_dump_parse_tree: 298 opts.programAction = DebugDumpParseTree; 299 break; 300 case clang::driver::options::OPT_fdebug_dump_pft: 301 opts.programAction = DebugDumpPFT; 302 break; 303 case clang::driver::options::OPT_fdebug_dump_all: 304 opts.programAction = DebugDumpAll; 305 break; 306 case clang::driver::options::OPT_fdebug_dump_parse_tree_no_sema: 307 opts.programAction = DebugDumpParseTreeNoSema; 308 break; 309 case clang::driver::options::OPT_fdebug_dump_provenance: 310 opts.programAction = DebugDumpProvenance; 311 break; 312 case clang::driver::options::OPT_fdebug_dump_parsing_log: 313 opts.programAction = DebugDumpParsingLog; 314 break; 315 case clang::driver::options::OPT_fdebug_measure_parse_tree: 316 opts.programAction = DebugMeasureParseTree; 317 break; 318 case clang::driver::options::OPT_fdebug_pre_fir_tree: 319 opts.programAction = DebugPreFIRTree; 320 break; 321 case clang::driver::options::OPT_fget_symbols_sources: 322 opts.programAction = GetSymbolsSources; 323 break; 324 case clang::driver::options::OPT_fget_definition: 325 opts.programAction = GetDefinition; 326 break; 327 case clang::driver::options::OPT_init_only: 328 opts.programAction = InitOnly; 329 break; 330 331 // TODO: 332 // case clang::driver::options::OPT_emit_llvm: 333 // case clang::driver::options::OPT_emit_llvm_only: 334 // case clang::driver::options::OPT_emit_codegen_only: 335 // case clang::driver::options::OPT_emit_module: 336 // (...) 337 } 338 339 // Parse the values provided with `-fget-definition` (there should be 3 340 // integers) 341 if (llvm::opt::OptSpecifier(a->getOption().getID()) == 342 clang::driver::options::OPT_fget_definition) { 343 unsigned optVals[3] = {0, 0, 0}; 344 345 for (unsigned i = 0; i < 3; i++) { 346 llvm::StringRef val = a->getValue(i); 347 348 if (val.getAsInteger(10, optVals[i])) { 349 // A non-integer was encountered - that's an error. 350 diags.Report(clang::diag::err_drv_invalid_value) 351 << a->getOption().getName() << val; 352 break; 353 } 354 } 355 opts.getDefVals.line = optVals[0]; 356 opts.getDefVals.startColumn = optVals[1]; 357 opts.getDefVals.endColumn = optVals[2]; 358 } 359 } 360 361 // Parsing -load <dsopath> option and storing shared object path 362 if (llvm::opt::Arg *a = args.getLastArg(clang::driver::options::OPT_load)) { 363 opts.plugins.push_back(a->getValue()); 364 } 365 366 // Parsing -plugin <name> option and storing plugin name and setting action 367 if (const llvm::opt::Arg *a = 368 args.getLastArg(clang::driver::options::OPT_plugin)) { 369 opts.programAction = PluginAction; 370 opts.actionName = a->getValue(); 371 } 372 373 opts.outputFile = args.getLastArgValue(clang::driver::options::OPT_o); 374 opts.showHelp = args.hasArg(clang::driver::options::OPT_help); 375 opts.showVersion = args.hasArg(clang::driver::options::OPT_version); 376 377 // Get the input kind (from the value passed via `-x`) 378 InputKind dashX(Language::Unknown); 379 if (const llvm::opt::Arg *a = 380 args.getLastArg(clang::driver::options::OPT_x)) { 381 llvm::StringRef xValue = a->getValue(); 382 // Principal languages. 383 dashX = llvm::StringSwitch<InputKind>(xValue) 384 // Flang does not differentiate between pre-processed and not 385 // pre-processed inputs. 386 .Case("f95", Language::Fortran) 387 .Case("f95-cpp-input", Language::Fortran) 388 .Default(Language::Unknown); 389 390 // Flang's intermediate representations. 391 if (dashX.isUnknown()) 392 dashX = llvm::StringSwitch<InputKind>(xValue) 393 .Case("ir", Language::LLVM_IR) 394 .Case("fir", Language::MLIR) 395 .Case("mlir", Language::MLIR) 396 .Default(Language::Unknown); 397 398 if (dashX.isUnknown()) 399 diags.Report(clang::diag::err_drv_invalid_value) 400 << a->getAsString(args) << a->getValue(); 401 } 402 403 // Collect the input files and save them in our instance of FrontendOptions. 404 std::vector<std::string> inputs = 405 args.getAllArgValues(clang::driver::options::OPT_INPUT); 406 opts.inputs.clear(); 407 if (inputs.empty()) 408 // '-' is the default input if none is given. 409 inputs.push_back("-"); 410 for (unsigned i = 0, e = inputs.size(); i != e; ++i) { 411 InputKind ik = dashX; 412 if (ik.isUnknown()) { 413 ik = FrontendOptions::getInputKindForExtension( 414 llvm::StringRef(inputs[i]).rsplit('.').second); 415 if (ik.isUnknown()) 416 ik = Language::Unknown; 417 if (i == 0) 418 dashX = ik; 419 } 420 421 opts.inputs.emplace_back(std::move(inputs[i]), ik); 422 } 423 424 // Set fortranForm based on options -ffree-form and -ffixed-form. 425 if (const auto *arg = 426 args.getLastArg(clang::driver::options::OPT_ffixed_form, 427 clang::driver::options::OPT_ffree_form)) { 428 opts.fortranForm = 429 arg->getOption().matches(clang::driver::options::OPT_ffixed_form) 430 ? FortranForm::FixedForm 431 : FortranForm::FreeForm; 432 } 433 434 // Set fixedFormColumns based on -ffixed-line-length=<value> 435 if (const auto *arg = 436 args.getLastArg(clang::driver::options::OPT_ffixed_line_length_EQ)) { 437 llvm::StringRef argValue = llvm::StringRef(arg->getValue()); 438 std::int64_t columns = -1; 439 if (argValue == "none") { 440 columns = 0; 441 } else if (argValue.getAsInteger(/*Radix=*/10, columns)) { 442 columns = -1; 443 } 444 if (columns < 0) { 445 diags.Report(clang::diag::err_drv_negative_columns) 446 << arg->getOption().getName() << arg->getValue(); 447 } else if (columns == 0) { 448 opts.fixedFormColumns = 1000000; 449 } else if (columns < 7) { 450 diags.Report(clang::diag::err_drv_small_columns) 451 << arg->getOption().getName() << arg->getValue() << "7"; 452 } else { 453 opts.fixedFormColumns = columns; 454 } 455 } 456 457 // Set conversion based on -fconvert=<value> 458 if (const auto *arg = 459 args.getLastArg(clang::driver::options::OPT_fconvert_EQ)) { 460 const char *argValue = arg->getValue(); 461 if (auto convert = parseConvertArg(argValue)) 462 opts.envDefaults.push_back({"FORT_CONVERT", *convert}); 463 else 464 diags.Report(clang::diag::err_drv_invalid_value) 465 << arg->getAsString(args) << argValue; 466 } 467 468 // -f{no-}implicit-none 469 opts.features.Enable( 470 Fortran::common::LanguageFeature::ImplicitNoneTypeAlways, 471 args.hasFlag(clang::driver::options::OPT_fimplicit_none, 472 clang::driver::options::OPT_fno_implicit_none, false)); 473 474 // -f{no-}backslash 475 opts.features.Enable(Fortran::common::LanguageFeature::BackslashEscapes, 476 args.hasFlag(clang::driver::options::OPT_fbackslash, 477 clang::driver::options::OPT_fno_backslash, 478 false)); 479 480 // -f{no-}logical-abbreviations 481 opts.features.Enable( 482 Fortran::common::LanguageFeature::LogicalAbbreviations, 483 args.hasFlag(clang::driver::options::OPT_flogical_abbreviations, 484 clang::driver::options::OPT_fno_logical_abbreviations, 485 false)); 486 487 // -f{no-}xor-operator 488 opts.features.Enable( 489 Fortran::common::LanguageFeature::XOROperator, 490 args.hasFlag(clang::driver::options::OPT_fxor_operator, 491 clang::driver::options::OPT_fno_xor_operator, false)); 492 493 // -fno-automatic 494 if (args.hasArg(clang::driver::options::OPT_fno_automatic)) { 495 opts.features.Enable(Fortran::common::LanguageFeature::DefaultSave); 496 } 497 498 if (args.hasArg( 499 clang::driver::options::OPT_falternative_parameter_statement)) { 500 opts.features.Enable(Fortran::common::LanguageFeature::OldStyleParameter); 501 } 502 if (const llvm::opt::Arg *arg = 503 args.getLastArg(clang::driver::options::OPT_finput_charset_EQ)) { 504 llvm::StringRef argValue = arg->getValue(); 505 if (argValue == "utf-8") { 506 opts.encoding = Fortran::parser::Encoding::UTF_8; 507 } else if (argValue == "latin-1") { 508 opts.encoding = Fortran::parser::Encoding::LATIN_1; 509 } else { 510 diags.Report(clang::diag::err_drv_invalid_value) 511 << arg->getAsString(args) << argValue; 512 } 513 } 514 515 setUpFrontendBasedOnAction(opts); 516 opts.dashX = dashX; 517 518 return diags.getNumErrors() == numErrorsBefore; 519 } 520 521 // Generate the path to look for intrinsic modules 522 static std::string getIntrinsicDir() { 523 // TODO: Find a system independent API 524 llvm::SmallString<128> driverPath; 525 driverPath.assign(llvm::sys::fs::getMainExecutable(nullptr, nullptr)); 526 llvm::sys::path::remove_filename(driverPath); 527 driverPath.append("/../include/flang/"); 528 return std::string(driverPath); 529 } 530 531 // Generate the path to look for OpenMP headers 532 static std::string getOpenMPHeadersDir() { 533 llvm::SmallString<128> includePath; 534 includePath.assign(llvm::sys::fs::getMainExecutable(nullptr, nullptr)); 535 llvm::sys::path::remove_filename(includePath); 536 includePath.append("/../include/flang/OpenMP/"); 537 return std::string(includePath); 538 } 539 540 /// Parses all preprocessor input arguments and populates the preprocessor 541 /// options accordingly. 542 /// 543 /// \param [in] opts The preprocessor options instance 544 /// \param [out] args The list of input arguments 545 static void parsePreprocessorArgs(Fortran::frontend::PreprocessorOptions &opts, 546 llvm::opt::ArgList &args) { 547 // Add macros from the command line. 548 for (const auto *currentArg : args.filtered(clang::driver::options::OPT_D, 549 clang::driver::options::OPT_U)) { 550 if (currentArg->getOption().matches(clang::driver::options::OPT_D)) { 551 opts.addMacroDef(currentArg->getValue()); 552 } else { 553 opts.addMacroUndef(currentArg->getValue()); 554 } 555 } 556 557 // Add the ordered list of -I's. 558 for (const auto *currentArg : args.filtered(clang::driver::options::OPT_I)) 559 opts.searchDirectoriesFromDashI.emplace_back(currentArg->getValue()); 560 561 // Prepend the ordered list of -intrinsic-modules-path 562 // to the default location to search. 563 for (const auto *currentArg : 564 args.filtered(clang::driver::options::OPT_fintrinsic_modules_path)) 565 opts.searchDirectoriesFromIntrModPath.emplace_back(currentArg->getValue()); 566 567 // -cpp/-nocpp 568 if (const auto *currentArg = args.getLastArg( 569 clang::driver::options::OPT_cpp, clang::driver::options::OPT_nocpp)) 570 opts.macrosFlag = 571 (currentArg->getOption().matches(clang::driver::options::OPT_cpp)) 572 ? PPMacrosFlag::Include 573 : PPMacrosFlag::Exclude; 574 575 opts.noReformat = args.hasArg(clang::driver::options::OPT_fno_reformat); 576 opts.noLineDirectives = args.hasArg(clang::driver::options::OPT_P); 577 } 578 579 /// Parses all semantic related arguments and populates the variables 580 /// options accordingly. Returns false if new errors are generated. 581 static bool parseSemaArgs(CompilerInvocation &res, llvm::opt::ArgList &args, 582 clang::DiagnosticsEngine &diags) { 583 unsigned numErrorsBefore = diags.getNumErrors(); 584 585 // -J/module-dir option 586 auto moduleDirList = 587 args.getAllArgValues(clang::driver::options::OPT_module_dir); 588 // User can only specify -J/-module-dir once 589 // https://gcc.gnu.org/onlinedocs/gfortran/Directory-Options.html 590 if (moduleDirList.size() > 1) { 591 const unsigned diagID = 592 diags.getCustomDiagID(clang::DiagnosticsEngine::Error, 593 "Only one '-module-dir/-J' option allowed"); 594 diags.Report(diagID); 595 } 596 if (moduleDirList.size() == 1) 597 res.setModuleDir(moduleDirList[0]); 598 599 // -fdebug-module-writer option 600 if (args.hasArg(clang::driver::options::OPT_fdebug_module_writer)) { 601 res.setDebugModuleDir(true); 602 } 603 604 // -module-suffix 605 if (const auto *moduleSuffix = 606 args.getLastArg(clang::driver::options::OPT_module_suffix)) { 607 res.setModuleFileSuffix(moduleSuffix->getValue()); 608 } 609 610 // -f{no-}analyzed-objects-for-unparse 611 res.setUseAnalyzedObjectsForUnparse(args.hasFlag( 612 clang::driver::options::OPT_fanalyzed_objects_for_unparse, 613 clang::driver::options::OPT_fno_analyzed_objects_for_unparse, true)); 614 615 return diags.getNumErrors() == numErrorsBefore; 616 } 617 618 /// Parses all diagnostics related arguments and populates the variables 619 /// options accordingly. Returns false if new errors are generated. 620 static bool parseDiagArgs(CompilerInvocation &res, llvm::opt::ArgList &args, 621 clang::DiagnosticsEngine &diags) { 622 unsigned numErrorsBefore = diags.getNumErrors(); 623 624 // -Werror option 625 // TODO: Currently throws a Diagnostic for anything other than -W<error>, 626 // this has to change when other -W<opt>'s are supported. 627 if (args.hasArg(clang::driver::options::OPT_W_Joined)) { 628 const auto &wArgs = 629 args.getAllArgValues(clang::driver::options::OPT_W_Joined); 630 for (const auto &wArg : wArgs) { 631 if (wArg == "error") { 632 res.setWarnAsErr(true); 633 } else { 634 const unsigned diagID = 635 diags.getCustomDiagID(clang::DiagnosticsEngine::Error, 636 "Only `-Werror` is supported currently."); 637 diags.Report(diagID); 638 } 639 } 640 } 641 642 // Default to off for `flang-new -fc1`. 643 res.getFrontendOpts().showColors = 644 parseShowColorsArgs(args, /*defaultDiagColor=*/false); 645 646 return diags.getNumErrors() == numErrorsBefore; 647 } 648 649 /// Parses all Dialect related arguments and populates the variables 650 /// options accordingly. Returns false if new errors are generated. 651 static bool parseDialectArgs(CompilerInvocation &res, llvm::opt::ArgList &args, 652 clang::DiagnosticsEngine &diags) { 653 unsigned numErrorsBefore = diags.getNumErrors(); 654 655 // -fdefault* family 656 if (args.hasArg(clang::driver::options::OPT_fdefault_real_8)) { 657 res.getDefaultKinds().set_defaultRealKind(8); 658 res.getDefaultKinds().set_doublePrecisionKind(16); 659 } 660 if (args.hasArg(clang::driver::options::OPT_fdefault_integer_8)) { 661 res.getDefaultKinds().set_defaultIntegerKind(8); 662 res.getDefaultKinds().set_subscriptIntegerKind(8); 663 res.getDefaultKinds().set_sizeIntegerKind(8); 664 } 665 if (args.hasArg(clang::driver::options::OPT_fdefault_double_8)) { 666 if (!args.hasArg(clang::driver::options::OPT_fdefault_real_8)) { 667 // -fdefault-double-8 has to be used with -fdefault-real-8 668 // to be compatible with gfortran 669 const unsigned diagID = diags.getCustomDiagID( 670 clang::DiagnosticsEngine::Error, 671 "Use of `-fdefault-double-8` requires `-fdefault-real-8`"); 672 diags.Report(diagID); 673 } 674 // https://gcc.gnu.org/onlinedocs/gfortran/Fortran-Dialect-Options.html 675 res.getDefaultKinds().set_doublePrecisionKind(8); 676 } 677 if (args.hasArg(clang::driver::options::OPT_flarge_sizes)) 678 res.getDefaultKinds().set_sizeIntegerKind(8); 679 680 // -fopenmp and -fopenacc 681 if (args.hasArg(clang::driver::options::OPT_fopenacc)) { 682 res.getFrontendOpts().features.Enable( 683 Fortran::common::LanguageFeature::OpenACC); 684 } 685 if (args.hasArg(clang::driver::options::OPT_fopenmp)) { 686 res.getFrontendOpts().features.Enable( 687 Fortran::common::LanguageFeature::OpenMP); 688 689 if (args.hasArg(clang::driver::options::OPT_fopenmp_is_device)) { 690 res.getLangOpts().OpenMPIsDevice = 1; 691 } 692 } 693 694 // -pedantic 695 if (args.hasArg(clang::driver::options::OPT_pedantic)) { 696 res.setEnableConformanceChecks(); 697 } 698 // -std=f2018 (currently this implies -pedantic) 699 // TODO: Set proper options when more fortran standards 700 // are supported. 701 if (args.hasArg(clang::driver::options::OPT_std_EQ)) { 702 auto standard = args.getLastArgValue(clang::driver::options::OPT_std_EQ); 703 // We only allow f2018 as the given standard 704 if (standard.equals("f2018")) { 705 res.setEnableConformanceChecks(); 706 } else { 707 const unsigned diagID = 708 diags.getCustomDiagID(clang::DiagnosticsEngine::Error, 709 "Only -std=f2018 is allowed currently."); 710 diags.Report(diagID); 711 } 712 } 713 return diags.getNumErrors() == numErrorsBefore; 714 } 715 716 /// Parses all floating point related arguments and populates the 717 /// CompilerInvocation accordingly. 718 /// Returns false if new errors are generated. 719 /// 720 /// \param [out] invoc Stores the processed arguments 721 /// \param [in] args The compiler invocation arguments to parse 722 /// \param [out] diags DiagnosticsEngine to report erros with 723 static bool parseFloatingPointArgs(CompilerInvocation &invoc, 724 llvm::opt::ArgList &args, 725 clang::DiagnosticsEngine &diags) { 726 LangOptions &opts = invoc.getLangOpts(); 727 728 if (const llvm::opt::Arg *a = 729 args.getLastArg(clang::driver::options::OPT_ffp_contract)) { 730 const llvm::StringRef val = a->getValue(); 731 enum LangOptions::FPModeKind fpContractMode; 732 733 if (val == "off") 734 fpContractMode = LangOptions::FPM_Off; 735 else if (val == "fast") 736 fpContractMode = LangOptions::FPM_Fast; 737 else { 738 diags.Report(clang::diag::err_drv_unsupported_option_argument) 739 << a->getSpelling() << val; 740 return false; 741 } 742 743 opts.setFPContractMode(fpContractMode); 744 } 745 746 if (args.getLastArg(clang::driver::options::OPT_menable_no_infinities)) { 747 opts.NoHonorInfs = true; 748 } 749 750 if (args.getLastArg(clang::driver::options::OPT_menable_no_nans)) { 751 opts.NoHonorNaNs = true; 752 } 753 754 if (args.getLastArg(clang::driver::options::OPT_fapprox_func)) { 755 opts.ApproxFunc = true; 756 } 757 758 if (args.getLastArg(clang::driver::options::OPT_fno_signed_zeros)) { 759 opts.NoSignedZeros = true; 760 } 761 762 if (args.getLastArg(clang::driver::options::OPT_mreassociate)) { 763 opts.AssociativeMath = true; 764 } 765 766 if (args.getLastArg(clang::driver::options::OPT_freciprocal_math)) { 767 opts.ReciprocalMath = true; 768 } 769 770 if (args.getLastArg(clang::driver::options::OPT_ffast_math)) { 771 opts.NoHonorInfs = true; 772 opts.NoHonorNaNs = true; 773 opts.AssociativeMath = true; 774 opts.ReciprocalMath = true; 775 opts.ApproxFunc = true; 776 opts.NoSignedZeros = true; 777 opts.setFPContractMode(LangOptions::FPM_Fast); 778 } 779 780 return true; 781 } 782 783 bool CompilerInvocation::createFromArgs( 784 CompilerInvocation &res, llvm::ArrayRef<const char *> commandLineArgs, 785 clang::DiagnosticsEngine &diags) { 786 787 bool success = true; 788 789 // Set the default triple for this CompilerInvocation. This might be 790 // overridden by users with `-triple` (see the call to `ParseTargetArgs` 791 // below). 792 // NOTE: Like in Clang, it would be nice to use option marshalling 793 // for this so that the entire logic for setting-up the triple is in one 794 // place. 795 res.getTargetOpts().triple = 796 llvm::Triple::normalize(llvm::sys::getDefaultTargetTriple()); 797 798 // Parse the arguments 799 const llvm::opt::OptTable &opts = clang::driver::getDriverOptTable(); 800 const unsigned includedFlagsBitmask = clang::driver::options::FC1Option; 801 unsigned missingArgIndex, missingArgCount; 802 llvm::opt::InputArgList args = opts.ParseArgs( 803 commandLineArgs, missingArgIndex, missingArgCount, includedFlagsBitmask); 804 805 // Check for missing argument error. 806 if (missingArgCount) { 807 diags.Report(clang::diag::err_drv_missing_argument) 808 << args.getArgString(missingArgIndex) << missingArgCount; 809 success = false; 810 } 811 812 // Issue errors on unknown arguments 813 for (const auto *a : args.filtered(clang::driver::options::OPT_UNKNOWN)) { 814 auto argString = a->getAsString(args); 815 std::string nearest; 816 if (opts.findNearest(argString, nearest, includedFlagsBitmask) > 1) 817 diags.Report(clang::diag::err_drv_unknown_argument) << argString; 818 else 819 diags.Report(clang::diag::err_drv_unknown_argument_with_suggestion) 820 << argString << nearest; 821 success = false; 822 } 823 824 // -flang-experimental-hlfir 825 if (args.hasArg(clang::driver::options::OPT_flang_experimental_hlfir)) { 826 res.loweringOpts.setLowerToHighLevelFIR(true); 827 } 828 829 success &= parseFrontendArgs(res.getFrontendOpts(), args, diags); 830 parseTargetArgs(res.getTargetOpts(), args); 831 parsePreprocessorArgs(res.getPreprocessorOpts(), args); 832 parseCodeGenArgs(res.getCodeGenOpts(), args, diags); 833 success &= parseSemaArgs(res, args, diags); 834 success &= parseDialectArgs(res, args, diags); 835 success &= parseDiagArgs(res, args, diags); 836 res.frontendOpts.llvmArgs = 837 args.getAllArgValues(clang::driver::options::OPT_mllvm); 838 839 res.frontendOpts.mlirArgs = 840 args.getAllArgValues(clang::driver::options::OPT_mmlir); 841 842 success &= parseFloatingPointArgs(res, args, diags); 843 844 return success; 845 } 846 847 void CompilerInvocation::collectMacroDefinitions() { 848 auto &ppOpts = this->getPreprocessorOpts(); 849 850 for (unsigned i = 0, n = ppOpts.macros.size(); i != n; ++i) { 851 llvm::StringRef macro = ppOpts.macros[i].first; 852 bool isUndef = ppOpts.macros[i].second; 853 854 std::pair<llvm::StringRef, llvm::StringRef> macroPair = macro.split('='); 855 llvm::StringRef macroName = macroPair.first; 856 llvm::StringRef macroBody = macroPair.second; 857 858 // For an #undef'd macro, we only care about the name. 859 if (isUndef) { 860 parserOpts.predefinitions.emplace_back(macroName.str(), 861 std::optional<std::string>{}); 862 continue; 863 } 864 865 // For a #define'd macro, figure out the actual definition. 866 if (macroName.size() == macro.size()) 867 macroBody = "1"; 868 else { 869 // Note: GCC drops anything following an end-of-line character. 870 llvm::StringRef::size_type end = macroBody.find_first_of("\n\r"); 871 macroBody = macroBody.substr(0, end); 872 } 873 parserOpts.predefinitions.emplace_back( 874 macroName, std::optional<std::string>(macroBody.str())); 875 } 876 } 877 878 void CompilerInvocation::setDefaultFortranOpts() { 879 auto &fortranOptions = getFortranOpts(); 880 881 std::vector<std::string> searchDirectories{"."s}; 882 fortranOptions.searchDirectories = searchDirectories; 883 884 // Add the location of omp_lib.h to the search directories. Currently this is 885 // identical to the modules' directory. 886 fortranOptions.searchDirectories.emplace_back(getOpenMPHeadersDir()); 887 888 fortranOptions.isFixedForm = false; 889 } 890 891 // TODO: When expanding this method, consider creating a dedicated API for 892 // this. Also at some point we will need to differentiate between different 893 // targets and add dedicated predefines for each. 894 void CompilerInvocation::setDefaultPredefinitions() { 895 auto &fortranOptions = getFortranOpts(); 896 const auto &frontendOptions = getFrontendOpts(); 897 898 // Populate the macro list with version numbers and other predefinitions. 899 fortranOptions.predefinitions.emplace_back("__flang__", "1"); 900 fortranOptions.predefinitions.emplace_back("__flang_major__", 901 FLANG_VERSION_MAJOR_STRING); 902 fortranOptions.predefinitions.emplace_back("__flang_minor__", 903 FLANG_VERSION_MINOR_STRING); 904 fortranOptions.predefinitions.emplace_back("__flang_patchlevel__", 905 FLANG_VERSION_PATCHLEVEL_STRING); 906 907 // Add predefinitions based on extensions enabled 908 if (frontendOptions.features.IsEnabled( 909 Fortran::common::LanguageFeature::OpenACC)) { 910 fortranOptions.predefinitions.emplace_back("_OPENACC", "202011"); 911 } 912 if (frontendOptions.features.IsEnabled( 913 Fortran::common::LanguageFeature::OpenMP)) { 914 fortranOptions.predefinitions.emplace_back("_OPENMP", "201511"); 915 } 916 llvm::Triple targetTriple{llvm::Triple(this->targetOpts.triple)}; 917 if (targetTriple.getArch() == llvm::Triple::ArchType::x86_64) { 918 fortranOptions.predefinitions.emplace_back("__x86_64__", "1"); 919 fortranOptions.predefinitions.emplace_back("__x86_64", "1"); 920 } 921 } 922 923 void CompilerInvocation::setFortranOpts() { 924 auto &fortranOptions = getFortranOpts(); 925 const auto &frontendOptions = getFrontendOpts(); 926 const auto &preprocessorOptions = getPreprocessorOpts(); 927 auto &moduleDirJ = getModuleDir(); 928 929 if (frontendOptions.fortranForm != FortranForm::Unknown) { 930 fortranOptions.isFixedForm = 931 frontendOptions.fortranForm == FortranForm::FixedForm; 932 } 933 fortranOptions.fixedFormColumns = frontendOptions.fixedFormColumns; 934 935 fortranOptions.features = frontendOptions.features; 936 fortranOptions.encoding = frontendOptions.encoding; 937 938 // Adding search directories specified by -I 939 fortranOptions.searchDirectories.insert( 940 fortranOptions.searchDirectories.end(), 941 preprocessorOptions.searchDirectoriesFromDashI.begin(), 942 preprocessorOptions.searchDirectoriesFromDashI.end()); 943 944 // Add the ordered list of -intrinsic-modules-path 945 fortranOptions.searchDirectories.insert( 946 fortranOptions.searchDirectories.end(), 947 preprocessorOptions.searchDirectoriesFromIntrModPath.begin(), 948 preprocessorOptions.searchDirectoriesFromIntrModPath.end()); 949 950 // Add the default intrinsic module directory 951 fortranOptions.intrinsicModuleDirectories.emplace_back(getIntrinsicDir()); 952 953 // Add the directory supplied through -J/-module-dir to the list of search 954 // directories 955 if (moduleDirJ != ".") 956 fortranOptions.searchDirectories.emplace_back(moduleDirJ); 957 958 if (frontendOptions.instrumentedParse) 959 fortranOptions.instrumentedParse = true; 960 961 if (frontendOptions.showColors) 962 fortranOptions.showColors = true; 963 964 if (frontendOptions.needProvenanceRangeToCharBlockMappings) 965 fortranOptions.needProvenanceRangeToCharBlockMappings = true; 966 967 if (getEnableConformanceChecks()) { 968 fortranOptions.features.WarnOnAllNonstandard(); 969 } 970 } 971 972 void CompilerInvocation::setSemanticsOpts( 973 Fortran::parser::AllCookedSources &allCookedSources) { 974 auto &fortranOptions = getFortranOpts(); 975 976 semanticsContext = std::make_unique<semantics::SemanticsContext>( 977 getDefaultKinds(), fortranOptions.features, allCookedSources); 978 979 semanticsContext->set_moduleDirectory(getModuleDir()) 980 .set_searchDirectories(fortranOptions.searchDirectories) 981 .set_intrinsicModuleDirectories(fortranOptions.intrinsicModuleDirectories) 982 .set_warnOnNonstandardUsage(getEnableConformanceChecks()) 983 .set_warningsAreErrors(getWarnAsErr()) 984 .set_moduleFileSuffix(getModuleFileSuffix()); 985 986 llvm::Triple targetTriple{llvm::Triple(this->targetOpts.triple)}; 987 // FIXME: Handle real(3) ? 988 if (targetTriple.getArch() != llvm::Triple::ArchType::x86_64) { 989 semanticsContext->targetCharacteristics().DisableType( 990 Fortran::common::TypeCategory::Real, /*kind=*/10); 991 } 992 } 993 994 /// Set \p loweringOptions controlling lowering behavior based 995 /// on the \p optimizationLevel. 996 void CompilerInvocation::setLoweringOptions() { 997 const CodeGenOptions &codegenOpts = getCodeGenOpts(); 998 999 // Lower TRANSPOSE as a runtime call under -O0. 1000 loweringOpts.setOptimizeTranspose(codegenOpts.OptimizationLevel > 0); 1001 1002 const LangOptions &langOptions = getLangOpts(); 1003 Fortran::common::MathOptionsBase &mathOpts = loweringOpts.getMathOptions(); 1004 // TODO: when LangOptions are finalized, we can represent 1005 // the math related options using Fortran::commmon::MathOptionsBase, 1006 // so that we can just copy it into LoweringOptions. 1007 mathOpts 1008 .setFPContractEnabled(langOptions.getFPContractMode() == 1009 LangOptions::FPM_Fast) 1010 .setNoHonorInfs(langOptions.NoHonorInfs) 1011 .setNoHonorNaNs(langOptions.NoHonorNaNs) 1012 .setApproxFunc(langOptions.ApproxFunc) 1013 .setNoSignedZeros(langOptions.NoSignedZeros) 1014 .setAssociativeMath(langOptions.AssociativeMath) 1015 .setReciprocalMath(langOptions.ReciprocalMath); 1016 } 1017