brintos

brintos / llvm-project-archived public Read only

0
0
Text · 73.7 KiB · b6c4e63 Raw
1915 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8//9// Coding style: https://mlir.llvm.org/getting_started/DeveloperGuide/10//11//===----------------------------------------------------------------------===//12 13#include "flang/Frontend/CompilerInvocation.h"14#include "flang/Frontend/CodeGenOptions.h"15#include "flang/Frontend/PreprocessorOptions.h"16#include "flang/Frontend/TargetOptions.h"17#include "flang/Optimizer/Passes/CommandLineOpts.h"18#include "flang/Semantics/semantics.h"19#include "flang/Support/Fortran-features.h"20#include "flang/Support/OpenMP-features.h"21#include "flang/Support/Version.h"22#include "flang/Tools/TargetSetup.h"23#include "flang/Version.inc"24#include "clang/Basic/DiagnosticDriver.h"25#include "clang/Basic/DiagnosticFrontend.h"26#include "clang/Basic/DiagnosticOptions.h"27#include "clang/Driver/CommonArgs.h"28#include "clang/Driver/Driver.h"29#include "clang/Options/OptionUtils.h"30#include "clang/Options/Options.h"31#include "llvm/ADT/ArrayRef.h"32#include "llvm/ADT/StringRef.h"33#include "llvm/ADT/StringSwitch.h"34#include "llvm/Frontend/Debug/Options.h"35#include "llvm/Frontend/Driver/CodeGenOptions.h"36#include "llvm/Option/Arg.h"37#include "llvm/Option/ArgList.h"38#include "llvm/Option/OptTable.h"39#include "llvm/Support/CodeGen.h"40#include "llvm/Support/FileSystem.h"41#include "llvm/Support/Path.h"42#include "llvm/Support/Process.h"43#include "llvm/Support/raw_ostream.h"44#include "llvm/TargetParser/Host.h"45#include "llvm/TargetParser/Triple.h"46#include <algorithm>47#include <cstdlib>48#include <memory>49#include <optional>50#include <sstream>51 52using namespace Fortran::frontend;53 54//===----------------------------------------------------------------------===//55// Initialization.56//===----------------------------------------------------------------------===//57CompilerInvocationBase::CompilerInvocationBase()58    : diagnosticOpts(new clang::DiagnosticOptions()),59      preprocessorOpts(new PreprocessorOptions()) {}60 61CompilerInvocationBase::CompilerInvocationBase(const CompilerInvocationBase &x)62    : diagnosticOpts(new clang::DiagnosticOptions(x.getDiagnosticOpts())),63      preprocessorOpts(new PreprocessorOptions(x.getPreprocessorOpts())) {}64 65CompilerInvocationBase::~CompilerInvocationBase() = default;66 67//===----------------------------------------------------------------------===//68// Deserialization (from args)69//===----------------------------------------------------------------------===//70static bool parseShowColorsArgs(const llvm::opt::ArgList &args,71                                bool defaultColor = true) {72  // Color diagnostics default to auto ("on" if terminal supports) in the73  // compiler driver `flang` but default to off in the frontend driver74  // `flang -fc1`, needing an explicit OPT_fdiagnostics_color.75  // Support both clang's -f[no-]color-diagnostics and gcc's76  // -f[no-]diagnostics-colors[=never|always|auto].77  enum {78    Colors_On,79    Colors_Off,80    Colors_Auto81  } showColors = defaultColor ? Colors_Auto : Colors_Off;82 83  for (auto *a : args) {84    const llvm::opt::Option &opt = a->getOption();85    if (opt.matches(clang::options::OPT_fcolor_diagnostics)) {86      showColors = Colors_On;87    } else if (opt.matches(clang::options::OPT_fno_color_diagnostics)) {88      showColors = Colors_Off;89    } else if (opt.matches(clang::options::OPT_fdiagnostics_color_EQ)) {90      llvm::StringRef value(a->getValue());91      if (value == "always")92        showColors = Colors_On;93      else if (value == "never")94        showColors = Colors_Off;95      else if (value == "auto")96        showColors = Colors_Auto;97    }98  }99 100  return showColors == Colors_On ||101         (showColors == Colors_Auto &&102          llvm::sys::Process::StandardErrHasColors());103}104 105/// Extracts the optimisation level from \a args.106static unsigned getOptimizationLevel(llvm::opt::ArgList &args,107                                     clang::DiagnosticsEngine &diags) {108  unsigned defaultOpt = 0;109 110  if (llvm::opt::Arg *a = args.getLastArg(clang::options::OPT_O_Group)) {111    if (a->getOption().matches(clang::options::OPT_O0))112      return 0;113 114    assert(a->getOption().matches(clang::options::OPT_O));115 116    return getLastArgIntValue(args, clang::options::OPT_O, defaultOpt, diags);117  }118 119  return defaultOpt;120}121 122bool Fortran::frontend::parseDiagnosticArgs(clang::DiagnosticOptions &opts,123                                            llvm::opt::ArgList &args) {124  opts.ShowColors = parseShowColorsArgs(args);125 126  return true;127}128 129static bool parseDebugArgs(Fortran::frontend::CodeGenOptions &opts,130                           llvm::opt::ArgList &args,131                           clang::DiagnosticsEngine &diags) {132  using DebugInfoKind = llvm::codegenoptions::DebugInfoKind;133  if (llvm::opt::Arg *arg =134          args.getLastArg(clang::options::OPT_debug_info_kind_EQ)) {135    std::optional<DebugInfoKind> val =136        llvm::StringSwitch<std::optional<DebugInfoKind>>(arg->getValue())137            .Case("line-tables-only", llvm::codegenoptions::DebugLineTablesOnly)138            .Case("line-directives-only",139                  llvm::codegenoptions::DebugDirectivesOnly)140            .Case("constructor", llvm::codegenoptions::DebugInfoConstructor)141            .Case("limited", llvm::codegenoptions::LimitedDebugInfo)142            .Case("standalone", llvm::codegenoptions::FullDebugInfo)143            .Case("unused-types", llvm::codegenoptions::UnusedTypeInfo)144            .Default(std::nullopt);145    if (!val.has_value()) {146      diags.Report(clang::diag::err_drv_invalid_value)147          << arg->getAsString(args) << arg->getValue();148      return false;149    }150    opts.setDebugInfo(val.value());151    if (val != llvm::codegenoptions::DebugLineTablesOnly &&152        val != llvm::codegenoptions::FullDebugInfo &&153        val != llvm::codegenoptions::NoDebugInfo) {154      const auto debugWarning = diags.getCustomDiagID(155          clang::DiagnosticsEngine::Warning, "Unsupported debug option: %0");156      diags.Report(debugWarning) << arg->getValue();157    }158    opts.DwarfVersion =159        getLastArgIntValue(args, clang::options::OPT_dwarf_version_EQ,160                           /*Default=*/0, diags);161    if (const llvm::opt::Arg *a =162            args.getLastArg(clang::options::OPT_split_dwarf_file))163      opts.SplitDwarfFile = a->getValue();164    if (const llvm::opt::Arg *a =165            args.getLastArg(clang::options::OPT_split_dwarf_output))166      opts.SplitDwarfOutput = a->getValue();167  }168  return true;169}170 171static void parseDoConcurrentMapping(Fortran::frontend::CodeGenOptions &opts,172                                     llvm::opt::ArgList &args,173                                     clang::DiagnosticsEngine &diags) {174  llvm::opt::Arg *arg =175      args.getLastArg(clang::options::OPT_fdo_concurrent_to_openmp_EQ);176  if (!arg)177    return;178 179  using DoConcurrentMappingKind =180      Fortran::frontend::CodeGenOptions::DoConcurrentMappingKind;181  std::optional<DoConcurrentMappingKind> val =182      llvm::StringSwitch<std::optional<DoConcurrentMappingKind>>(183          arg->getValue())184          .Case("none", DoConcurrentMappingKind::DCMK_None)185          .Case("host", DoConcurrentMappingKind::DCMK_Host)186          .Case("device", DoConcurrentMappingKind::DCMK_Device)187          .Default(std::nullopt);188 189  if (!val.has_value()) {190    diags.Report(clang::diag::err_drv_invalid_value)191        << arg->getAsString(args) << arg->getValue();192  }193 194  opts.setDoConcurrentMapping(val.value());195}196 197static bool parseVectorLibArg(Fortran::frontend::CodeGenOptions &opts,198                              llvm::opt::ArgList &args,199                              clang::DiagnosticsEngine &diags) {200  llvm::opt::Arg *arg = args.getLastArg(clang::options::OPT_fveclib);201  if (!arg)202    return true;203 204  using VectorLibrary = llvm::driver::VectorLibrary;205  std::optional<VectorLibrary> val =206      llvm::StringSwitch<std::optional<VectorLibrary>>(arg->getValue())207          .Case("Accelerate", VectorLibrary::Accelerate)208          .Case("libmvec", VectorLibrary::LIBMVEC)209          .Case("MASSV", VectorLibrary::MASSV)210          .Case("SVML", VectorLibrary::SVML)211          .Case("SLEEF", VectorLibrary::SLEEF)212          .Case("Darwin_libsystem_m", VectorLibrary::Darwin_libsystem_m)213          .Case("ArmPL", VectorLibrary::ArmPL)214          .Case("AMDLIBM", VectorLibrary::AMDLIBM)215          .Case("NoLibrary", VectorLibrary::NoLibrary)216          .Default(std::nullopt);217  if (!val.has_value()) {218    diags.Report(clang::diag::err_drv_invalid_value)219        << arg->getAsString(args) << arg->getValue();220    return false;221  }222  opts.setVecLib(val.value());223  return true;224}225 226// Generate an OptRemark object containing info on if the -Rgroup227// specified is enabled or not.228static CodeGenOptions::OptRemark229parseOptimizationRemark(clang::DiagnosticsEngine &diags,230                        llvm::opt::ArgList &args, llvm::opt::OptSpecifier optEq,231                        llvm::StringRef remarkOptName) {232  assert((remarkOptName == "pass" || remarkOptName == "pass-missed" ||233          remarkOptName == "pass-analysis") &&234         "Unsupported remark option name provided.");235  CodeGenOptions::OptRemark result;236 237  for (llvm::opt::Arg *a : args) {238    if (a->getOption().matches(clang::options::OPT_R_Joined)) {239      llvm::StringRef value = a->getValue();240 241      if (value == remarkOptName) {242        result.Kind = CodeGenOptions::RemarkKind::RK_Enabled;243        // Enable everything244        result.Pattern = ".*";245        result.Regex = std::make_shared<llvm::Regex>(result.Pattern);246 247      } else if (value.split('-') ==248                 std::make_pair(llvm::StringRef("no"), remarkOptName)) {249        result.Kind = CodeGenOptions::RemarkKind::RK_Disabled;250        // Disable everything251        result.Pattern = "";252        result.Regex = nullptr;253      }254    } else if (a->getOption().matches(optEq)) {255      result.Kind = CodeGenOptions::RemarkKind::RK_WithPattern;256      result.Pattern = a->getValue();257      result.Regex = std::make_shared<llvm::Regex>(result.Pattern);258      std::string regexError;259 260      if (!result.Regex->isValid(regexError)) {261        diags.Report(clang::diag::err_drv_optimization_remark_pattern)262            << regexError << a->getAsString(args);263        return CodeGenOptions::OptRemark();264      }265    }266  }267  return result;268}269 270static void parseCodeGenArgs(Fortran::frontend::CodeGenOptions &opts,271                             llvm::opt::ArgList &args,272                             clang::DiagnosticsEngine &diags) {273  opts.OptimizationLevel = getOptimizationLevel(args, diags);274 275  if (args.hasFlag(clang::options::OPT_fdebug_pass_manager,276                   clang::options::OPT_fno_debug_pass_manager, false))277    opts.DebugPassManager = 1;278 279  if (args.hasFlag(clang::options::OPT_fstack_arrays,280                   clang::options::OPT_fno_stack_arrays, false))281    opts.StackArrays = 1;282 283  if (args.getLastArg(clang::options::OPT_floop_interchange))284    opts.InterchangeLoops = 1;285 286  if (args.getLastArg(clang::options::OPT_fexperimental_loop_fusion))287    opts.FuseLoops = 1;288 289  if (args.getLastArg(clang::options::OPT_vectorize_loops))290    opts.VectorizeLoop = 1;291 292  if (args.getLastArg(clang::options::OPT_vectorize_slp))293    opts.VectorizeSLP = 1;294 295  if (args.hasFlag(clang::options::OPT_floop_versioning,296                   clang::options::OPT_fno_loop_versioning, false))297    opts.LoopVersioning = 1;298 299  opts.UnrollLoops = args.hasFlag(clang::options::OPT_funroll_loops,300                                  clang::options::OPT_fno_unroll_loops,301                                  (opts.OptimizationLevel > 1));302 303  opts.AliasAnalysis = opts.OptimizationLevel > 0;304 305  // -mframe-pointer=none/non-leaf/reserved/all option.306  if (const llvm::opt::Arg *a =307          args.getLastArg(clang::options::OPT_mframe_pointer_EQ)) {308    std::optional<llvm::FramePointerKind> val =309        llvm::StringSwitch<std::optional<llvm::FramePointerKind>>(a->getValue())310            .Case("none", llvm::FramePointerKind::None)311            .Case("non-leaf", llvm::FramePointerKind::NonLeaf)312            .Case("non-leaf-no-reserve",313                  llvm::FramePointerKind::NonLeafNoReserve)314            .Case("reserved", llvm::FramePointerKind::Reserved)315            .Case("all", llvm::FramePointerKind::All)316            .Default(std::nullopt);317 318    if (!val.has_value()) {319      diags.Report(clang::diag::err_drv_invalid_value)320          << a->getAsString(args) << a->getValue();321    } else322      opts.setFramePointer(val.value());323  }324 325  for (auto *a : args.filtered(clang::options::OPT_fpass_plugin_EQ))326    opts.LLVMPassPlugins.push_back(a->getValue());327 328  opts.Reciprocals = clang::parseMRecipOption(diags, args);329 330  opts.PreferVectorWidth = clang::parseMPreferVectorWidthOption(diags, args);331 332  // -fembed-offload-object option333  for (auto *a : args.filtered(clang::options::OPT_fembed_offload_object_EQ))334    opts.OffloadObjects.push_back(a->getValue());335 336  if (args.hasArg(clang::options::OPT_finstrument_functions))337    opts.InstrumentFunctions = 1;338 339  if (const llvm::opt::Arg *a =340          args.getLastArg(clang::options::OPT_mcode_object_version_EQ)) {341    llvm::StringRef s = a->getValue();342    if (s == "6")343      opts.CodeObjectVersion = llvm::CodeObjectVersionKind::COV_6;344    if (s == "5")345      opts.CodeObjectVersion = llvm::CodeObjectVersionKind::COV_5;346    if (s == "4")347      opts.CodeObjectVersion = llvm::CodeObjectVersionKind::COV_4;348    if (s == "none")349      opts.CodeObjectVersion = llvm::CodeObjectVersionKind::COV_None;350  }351 352  // -f[no-]save-optimization-record[=<format>]353  if (const llvm::opt::Arg *a =354          args.getLastArg(clang::options::OPT_opt_record_file))355    opts.OptRecordFile = a->getValue();356 357  // Optimization file format. Defaults to yaml358  if (const llvm::opt::Arg *a =359          args.getLastArg(clang::options::OPT_opt_record_format))360    opts.OptRecordFormat = a->getValue();361 362  // Specifies, using a regex, which successful optimization passes(middle and363  // backend), to include in the final optimization record file generated. If364  // not provided -fsave-optimization-record will include all passes.365  if (const llvm::opt::Arg *a =366          args.getLastArg(clang::options::OPT_opt_record_passes))367    opts.OptRecordPasses = a->getValue();368 369  // Create OptRemark that allows printing of all successful optimization370  // passes applied.371  opts.OptimizationRemark =372      parseOptimizationRemark(diags, args, clang::options::OPT_Rpass_EQ,373                              /*remarkOptName=*/"pass");374 375  // Create OptRemark that allows all missed optimization passes to be printed.376  opts.OptimizationRemarkMissed =377      parseOptimizationRemark(diags, args, clang::options::OPT_Rpass_missed_EQ,378                              /*remarkOptName=*/"pass-missed");379 380  // Create OptRemark that allows all optimization decisions made by LLVM381  // to be printed.382  opts.OptimizationRemarkAnalysis = parseOptimizationRemark(383      diags, args, clang::options::OPT_Rpass_analysis_EQ,384      /*remarkOptName=*/"pass-analysis");385 386  if (opts.getDebugInfo() == llvm::codegenoptions::NoDebugInfo) {387    // If the user requested a flag that requires source locations available in388    // the backend, make sure that the backend tracks source location389    // information.390    bool needLocTracking = !opts.OptRecordFile.empty() ||391                           !opts.OptRecordPasses.empty() ||392                           !opts.OptRecordFormat.empty() ||393                           opts.OptimizationRemark.hasValidPattern() ||394                           opts.OptimizationRemarkMissed.hasValidPattern() ||395                           opts.OptimizationRemarkAnalysis.hasValidPattern();396 397    if (needLocTracking)398      opts.setDebugInfo(llvm::codegenoptions::LocTrackingOnly);399  }400 401  if (auto *a = args.getLastArg(clang::options::OPT_save_temps_EQ))402    opts.SaveTempsDir = a->getValue();403 404  // -record-command-line option.405  if (const llvm::opt::Arg *a =406          args.getLastArg(clang::options::OPT_record_command_line)) {407    opts.RecordCommandLine = a->getValue();408  }409 410  // -mlink-builtin-bitcode411  for (auto *a : args.filtered(clang::options::OPT_mlink_builtin_bitcode))412    opts.BuiltinBCLibs.push_back(a->getValue());413 414  // -mrelocation-model option.415  if (const llvm::opt::Arg *a =416          args.getLastArg(clang::options::OPT_mrelocation_model)) {417    llvm::StringRef modelName = a->getValue();418    auto relocModel =419        llvm::StringSwitch<std::optional<llvm::Reloc::Model>>(modelName)420            .Case("static", llvm::Reloc::Static)421            .Case("pic", llvm::Reloc::PIC_)422            .Case("dynamic-no-pic", llvm::Reloc::DynamicNoPIC)423            .Case("ropi", llvm::Reloc::ROPI)424            .Case("rwpi", llvm::Reloc::RWPI)425            .Case("ropi-rwpi", llvm::Reloc::ROPI_RWPI)426            .Default(std::nullopt);427    if (relocModel.has_value())428      opts.setRelocationModel(*relocModel);429    else430      diags.Report(clang::diag::err_drv_invalid_value)431          << a->getAsString(args) << modelName;432  }433 434  // -pic-level and -pic-is-pie option.435  if (int picLevel =436          getLastArgIntValue(args, clang::options::OPT_pic_level, 0, diags)) {437    if (picLevel > 2)438      diags.Report(clang::diag::err_drv_invalid_value)439          << args.getLastArg(clang::options::OPT_pic_level)->getAsString(args)440          << picLevel;441 442    opts.PICLevel = picLevel;443    if (args.hasArg(clang::options::OPT_pic_is_pie))444      opts.IsPIE = 1;445  }446 447  if (args.hasArg(clang::options::OPT_fprofile_generate)) {448    opts.setProfileInstr(llvm::driver::ProfileInstrKind::ProfileIRInstr);449  }450 451  if (auto A = args.getLastArg(clang::options::OPT_fprofile_use_EQ)) {452    opts.setProfileUse(llvm::driver::ProfileInstrKind::ProfileIRInstr);453    opts.ProfileInstrumentUsePath = A->getValue();454  }455 456  // -mcmodel option.457  if (const llvm::opt::Arg *a =458          args.getLastArg(clang::options::OPT_mcmodel_EQ)) {459    llvm::StringRef modelName = a->getValue();460    std::optional<llvm::CodeModel::Model> codeModel = getCodeModel(modelName);461 462    if (codeModel.has_value())463      opts.CodeModel = modelName;464    else465      diags.Report(clang::diag::err_drv_invalid_value)466          << a->getAsString(args) << modelName;467  }468 469  if (const llvm::opt::Arg *arg =470          args.getLastArg(clang::options::OPT_mlarge_data_threshold_EQ)) {471    uint64_t LDT;472    if (llvm::StringRef(arg->getValue()).getAsInteger(/*Radix=*/10, LDT)) {473      diags.Report(clang::diag::err_drv_invalid_value)474          << arg->getSpelling() << arg->getValue();475    }476    opts.LargeDataThreshold = LDT;477  }478 479  // This option is compatible with -f[no-]underscoring in gfortran.480  if (args.hasFlag(clang::options::OPT_fno_underscoring,481                   clang::options::OPT_funderscoring, false)) {482    opts.Underscoring = 0;483  }484 485  parseDoConcurrentMapping(opts, args, diags);486 487  if (const llvm::opt::Arg *arg =488          args.getLastArg(clang::options::OPT_complex_range_EQ)) {489    llvm::StringRef argValue = llvm::StringRef(arg->getValue());490    if (argValue == "full") {491      opts.setComplexRange(CodeGenOptions::ComplexRangeKind::CX_Full);492    } else if (argValue == "improved") {493      opts.setComplexRange(CodeGenOptions::ComplexRangeKind::CX_Improved);494    } else if (argValue == "basic") {495      opts.setComplexRange(CodeGenOptions::ComplexRangeKind::CX_Basic);496    } else {497      diags.Report(clang::diag::err_drv_invalid_value)498          << arg->getAsString(args) << arg->getValue();499    }500  }501}502 503/// Parses all target input arguments and populates the target504/// options accordingly.505///506/// \param [in] opts The target options instance to update507/// \param [in] args The list of input arguments (from the compiler invocation)508static void parseTargetArgs(TargetOptions &opts, llvm::opt::ArgList &args) {509  if (const llvm::opt::Arg *a = args.getLastArg(clang::options::OPT_triple))510    opts.triple = a->getValue();511 512  opts.atomicIgnoreDenormalMode =513      args.hasFlag(clang::options::OPT_fatomic_ignore_denormal_mode,514                   clang::options::OPT_fno_atomic_ignore_denormal_mode, false);515  opts.atomicFineGrainedMemory =516      args.hasFlag(clang::options::OPT_fatomic_fine_grained_memory,517                   clang::options::OPT_fno_atomic_fine_grained_memory, false);518  opts.atomicRemoteMemory =519      args.hasFlag(clang::options::OPT_fatomic_remote_memory,520                   clang::options::OPT_fno_atomic_remote_memory, false);521 522  if (const llvm::opt::Arg *a = args.getLastArg(clang::options::OPT_target_cpu))523    opts.cpu = a->getValue();524 525  if (const llvm::opt::Arg *a = args.getLastArg(clang::options::OPT_tune_cpu))526    opts.cpuToTuneFor = a->getValue();527 528  for (const llvm::opt::Arg *currentArg :529       args.filtered(clang::options::OPT_target_feature))530    opts.featuresAsWritten.emplace_back(currentArg->getValue());531 532  if (args.hasArg(clang::options::OPT_fdisable_real_10))533    opts.disabledRealKinds.push_back(10);534 535  if (args.hasArg(clang::options::OPT_fdisable_real_3))536    opts.disabledRealKinds.push_back(3);537 538  if (args.hasArg(clang::options::OPT_fdisable_integer_2))539    opts.disabledIntegerKinds.push_back(2);540 541  if (args.hasArg(clang::options::OPT_fdisable_integer_16))542    opts.disabledIntegerKinds.push_back(16);543 544  if (const llvm::opt::Arg *a = args.getLastArg(clang::options::OPT_mabi_EQ)) {545    opts.abi = a->getValue();546    llvm::StringRef V = a->getValue();547    if (V == "vec-extabi") {548      opts.EnableAIXExtendedAltivecABI = true;549    } else if (V == "vec-default") {550      opts.EnableAIXExtendedAltivecABI = false;551    }552  }553 554  opts.asmVerbose = args.hasFlag(clang::options::OPT_fverbose_asm,555                                 clang::options::OPT_fno_verbose_asm, false);556}557// Tweak the frontend configuration based on the frontend action558static void setUpFrontendBasedOnAction(FrontendOptions &opts) {559  if (opts.programAction == DebugDumpParsingLog)560    opts.instrumentedParse = true;561 562  if (opts.programAction == DebugDumpProvenance ||563      opts.programAction == Fortran::frontend::GetDefinition)564    opts.needProvenanceRangeToCharBlockMappings = true;565}566 567/// Parse the argument specified for the -fconvert=<value> option568static std::optional<const char *> parseConvertArg(const char *s) {569  return llvm::StringSwitch<std::optional<const char *>>(s)570      .Case("unknown", "UNKNOWN")571      .Case("native", "NATIVE")572      .Case("little-endian", "LITTLE_ENDIAN")573      .Case("big-endian", "BIG_ENDIAN")574      .Case("swap", "SWAP")575      .Default(std::nullopt);576}577 578static bool parseFrontendArgs(FrontendOptions &opts, llvm::opt::ArgList &args,579                              clang::DiagnosticsEngine &diags) {580  unsigned numErrorsBefore = diags.getNumErrors();581 582  // By default the frontend driver creates a ParseSyntaxOnly action.583  opts.programAction = ParseSyntaxOnly;584 585  // Treat multiple action options as an invocation error. Note that `clang586  // -cc1` does accept multiple action options, but will only consider the587  // rightmost one.588  if (args.hasMultipleArgs(clang::options::OPT_Action_Group)) {589    llvm::SmallString<32> buf;590    llvm::raw_svector_ostream os(buf);591    for (const llvm::opt::Arg *arg :592         args.filtered(clang::options::OPT_Action_Group)) {593      if (buf.size())594        os << ", ";595      os << "'" << arg->getSpelling() << "'";596    }597    diags.Report(clang::diag::err_drv_too_many_actions) << buf;598    return false;599  }600 601  // Identify the action (i.e. opts.ProgramAction)602  if (const llvm::opt::Arg *a =603          args.getLastArg(clang::options::OPT_Action_Group)) {604    switch (a->getOption().getID()) {605    default: {606      llvm_unreachable("Invalid option in group!");607    }608    case clang::options::OPT_test_io:609      opts.programAction = InputOutputTest;610      break;611    case clang::options::OPT_E:612      opts.programAction = PrintPreprocessedInput;613      break;614    case clang::options::OPT_fsyntax_only:615      opts.programAction = ParseSyntaxOnly;616      break;617    case clang::options::OPT_emit_fir:618      opts.programAction = EmitFIR;619      break;620    case clang::options::OPT_emit_hlfir:621      opts.programAction = EmitHLFIR;622      break;623    case clang::options::OPT_emit_llvm:624      opts.programAction = EmitLLVM;625      break;626    case clang::options::OPT_emit_llvm_bc:627      opts.programAction = EmitLLVMBitcode;628      break;629    case clang::options::OPT_emit_obj:630      opts.programAction = EmitObj;631      break;632    case clang::options::OPT_S:633      opts.programAction = EmitAssembly;634      break;635    case clang::options::OPT_fdebug_unparse:636      opts.programAction = DebugUnparse;637      break;638    case clang::options::OPT_fdebug_unparse_no_sema:639      opts.programAction = DebugUnparseNoSema;640      break;641    case clang::options::OPT_fdebug_unparse_with_symbols:642      opts.programAction = DebugUnparseWithSymbols;643      break;644    case clang::options::OPT_fdebug_unparse_with_modules:645      opts.programAction = DebugUnparseWithModules;646      break;647    case clang::options::OPT_fdebug_dump_symbols:648      opts.programAction = DebugDumpSymbols;649      break;650    case clang::options::OPT_fdebug_dump_parse_tree:651      opts.programAction = DebugDumpParseTree;652      break;653    case clang::options::OPT_fdebug_dump_pft:654      opts.programAction = DebugDumpPFT;655      break;656    case clang::options::OPT_fdebug_dump_all:657      opts.programAction = DebugDumpAll;658      break;659    case clang::options::OPT_fdebug_dump_parse_tree_no_sema:660      opts.programAction = DebugDumpParseTreeNoSema;661      break;662    case clang::options::OPT_fdebug_dump_provenance:663      opts.programAction = DebugDumpProvenance;664      break;665    case clang::options::OPT_fdebug_dump_parsing_log:666      opts.programAction = DebugDumpParsingLog;667      break;668    case clang::options::OPT_fdebug_measure_parse_tree:669      opts.programAction = DebugMeasureParseTree;670      break;671    case clang::options::OPT_fdebug_pre_fir_tree:672      opts.programAction = DebugPreFIRTree;673      break;674    case clang::options::OPT_fget_symbols_sources:675      opts.programAction = GetSymbolsSources;676      break;677    case clang::options::OPT_fget_definition:678      opts.programAction = GetDefinition;679      break;680    case clang::options::OPT_init_only:681      opts.programAction = InitOnly;682      break;683 684      // TODO:685      // case clang::options::OPT_emit_llvm:686      // case clang::options::OPT_emit_llvm_only:687      // case clang::options::OPT_emit_codegen_only:688      // case clang::options::OPT_emit_module:689      // (...)690    }691 692    // Parse the values provided with `-fget-definition` (there should be 3693    // integers)694    if (llvm::opt::OptSpecifier(a->getOption().getID()) ==695        clang::options::OPT_fget_definition) {696      unsigned optVals[3] = {0, 0, 0};697 698      for (unsigned i = 0; i < 3; i++) {699        llvm::StringRef val = a->getValue(i);700 701        if (val.getAsInteger(10, optVals[i])) {702          // A non-integer was encountered - that's an error.703          diags.Report(clang::diag::err_drv_invalid_value)704              << a->getOption().getName() << val;705          break;706        }707      }708      opts.getDefVals.line = optVals[0];709      opts.getDefVals.startColumn = optVals[1];710      opts.getDefVals.endColumn = optVals[2];711    }712  }713 714  // Parsing -load <dsopath> option and storing shared object path715  if (llvm::opt::Arg *a = args.getLastArg(clang::options::OPT_load)) {716    opts.plugins.push_back(a->getValue());717  }718 719  // Parsing -plugin <name> option and storing plugin name and setting action720  if (const llvm::opt::Arg *a = args.getLastArg(clang::options::OPT_plugin)) {721    opts.programAction = PluginAction;722    opts.actionName = a->getValue();723  }724 725  opts.outputFile = args.getLastArgValue(clang::options::OPT_o);726  opts.showHelp = args.hasArg(clang::options::OPT_help);727  opts.showVersion = args.hasArg(clang::options::OPT_version);728  opts.printSupportedCPUs =729      args.hasArg(clang::options::OPT_print_supported_cpus);730 731  // Get the input kind (from the value passed via `-x`)732  InputKind dashX(Language::Unknown);733  if (const llvm::opt::Arg *a = args.getLastArg(clang::options::OPT_x)) {734    llvm::StringRef xValue = a->getValue();735    // Principal languages.736    dashX = llvm::StringSwitch<InputKind>(xValue)737                // Flang does not differentiate between pre-processed and not738                // pre-processed inputs.739                .Case("f95", Language::Fortran)740                .Case("f95-cpp-input", Language::Fortran)741                // CUDA Fortran742                .Case("cuda", Language::Fortran)743                .Default(Language::Unknown);744 745    // Flang's intermediate representations.746    if (dashX.isUnknown())747      dashX = llvm::StringSwitch<InputKind>(xValue)748                  .Case("ir", Language::LLVM_IR)749                  .Case("fir", Language::MLIR)750                  .Case("mlir", Language::MLIR)751                  .Default(Language::Unknown);752 753    if (dashX.isUnknown())754      diags.Report(clang::diag::err_drv_invalid_value)755          << a->getAsString(args) << a->getValue();756  }757 758  // Collect the input files and save them in our instance of FrontendOptions.759  std::vector<std::string> inputs =760      args.getAllArgValues(clang::options::OPT_INPUT);761  opts.inputs.clear();762  if (inputs.empty())763    // '-' is the default input if none is given.764    inputs.push_back("-");765  for (unsigned i = 0, e = inputs.size(); i != e; ++i) {766    InputKind ik = dashX;767    if (ik.isUnknown()) {768      ik = FrontendOptions::getInputKindForExtension(769          llvm::StringRef(inputs[i]).rsplit('.').second);770      if (ik.isUnknown())771        ik = Language::Unknown;772      if (i == 0)773        dashX = ik;774    }775 776    opts.inputs.emplace_back(std::move(inputs[i]), ik);777  }778 779  // Set fortranForm based on options -ffree-form and -ffixed-form.780  if (const auto *arg = args.getLastArg(clang::options::OPT_ffixed_form,781                                        clang::options::OPT_ffree_form)) {782    opts.fortranForm = arg->getOption().matches(clang::options::OPT_ffixed_form)783                           ? FortranForm::FixedForm784                           : FortranForm::FreeForm;785  }786 787  // Set fixedFormColumns based on -ffixed-line-length=<value>788  if (const auto *arg =789          args.getLastArg(clang::options::OPT_ffixed_line_length_EQ)) {790    llvm::StringRef argValue = llvm::StringRef(arg->getValue());791    std::int64_t columns = -1;792    if (argValue == "none") {793      columns = 0;794    } else if (argValue.getAsInteger(/*Radix=*/10, columns)) {795      columns = -1;796    }797    if (columns < 0) {798      diags.Report(clang::diag::err_drv_negative_columns)799          << arg->getOption().getName() << arg->getValue();800    } else if (columns == 0) {801      opts.fixedFormColumns = 1000000;802    } else if (columns < 7) {803      diags.Report(clang::diag::err_drv_small_columns)804          << arg->getOption().getName() << arg->getValue() << "7";805    } else {806      opts.fixedFormColumns = columns;807    }808  }809 810  // Set conversion based on -fconvert=<value>811  if (const auto *arg = args.getLastArg(clang::options::OPT_fconvert_EQ)) {812    const char *argValue = arg->getValue();813    if (auto convert = parseConvertArg(argValue))814      opts.envDefaults.push_back({"FORT_CONVERT", *convert});815    else816      diags.Report(clang::diag::err_drv_invalid_value)817          << arg->getAsString(args) << argValue;818  }819 820  // -f{no-}implicit-none821  opts.features.Enable(Fortran::common::LanguageFeature::ImplicitNoneTypeAlways,822                       args.hasFlag(clang::options::OPT_fimplicit_none,823                                    clang::options::OPT_fno_implicit_none,824                                    false));825 826  // -f{no-}implicit-none-ext827  opts.features.Enable(Fortran::common::LanguageFeature::ImplicitNoneExternal,828                       args.hasFlag(clang::options::OPT_fimplicit_none_ext,829                                    clang::options::OPT_fno_implicit_none_ext,830                                    false));831 832  // -f{no-}backslash833  opts.features.Enable(Fortran::common::LanguageFeature::BackslashEscapes,834                       args.hasFlag(clang::options::OPT_fbackslash,835                                    clang::options::OPT_fno_backslash, false));836 837  // -f{no-}logical-abbreviations838  opts.features.Enable(839      Fortran::common::LanguageFeature::LogicalAbbreviations,840      args.hasFlag(clang::options::OPT_flogical_abbreviations,841                   clang::options::OPT_fno_logical_abbreviations, false));842 843  // -f{no-}unsigned844  opts.features.Enable(Fortran::common::LanguageFeature::Unsigned,845                       args.hasFlag(clang::options::OPT_funsigned,846                                    clang::options::OPT_fno_unsigned, false));847 848  // -f{no-}xor-operator849  opts.features.Enable(Fortran::common::LanguageFeature::XOROperator,850                       args.hasFlag(clang::options::OPT_fxor_operator,851                                    clang::options::OPT_fno_xor_operator,852                                    false));853 854  // -fno-automatic855  if (args.hasArg(clang::options::OPT_fno_automatic)) {856    opts.features.Enable(Fortran::common::LanguageFeature::DefaultSave);857  }858 859  // -f{no}-save-main-program860  opts.features.Enable(Fortran::common::LanguageFeature::SaveMainProgram,861                       args.hasFlag(clang::options::OPT_fsave_main_program,862                                    clang::options::OPT_fno_save_main_program,863                                    false));864 865  if (args.hasArg(clang::options::OPT_falternative_parameter_statement)) {866    opts.features.Enable(Fortran::common::LanguageFeature::OldStyleParameter);867  }868  if (const llvm::opt::Arg *arg =869          args.getLastArg(clang::options::OPT_finput_charset_EQ)) {870    llvm::StringRef argValue = arg->getValue();871    if (argValue == "utf-8") {872      opts.encoding = Fortran::parser::Encoding::UTF_8;873    } else if (argValue == "latin-1") {874      opts.encoding = Fortran::parser::Encoding::LATIN_1;875    } else {876      diags.Report(clang::diag::err_drv_invalid_value)877          << arg->getAsString(args) << argValue;878    }879  }880 881  setUpFrontendBasedOnAction(opts);882  opts.dashX = dashX;883 884  return diags.getNumErrors() == numErrorsBefore;885}886 887// Generate the path to look for intrinsic modules888static std::string getIntrinsicDir(const char *argv) {889  // TODO: Find a system independent API890  llvm::SmallString<128> driverPath;891  driverPath.assign(llvm::sys::fs::getMainExecutable(argv, nullptr));892  llvm::sys::path::remove_filename(driverPath);893  driverPath.append("/../include/flang/");894  return std::string(driverPath);895}896 897// Generate the path to look for OpenMP headers898static std::string getOpenMPHeadersDir(const char *argv) {899  llvm::SmallString<128> includePath;900  includePath.assign(llvm::sys::fs::getMainExecutable(argv, nullptr));901  llvm::sys::path::remove_filename(includePath);902  includePath.append("/../include/flang/OpenMP/");903  return std::string(includePath);904}905 906/// Parses all preprocessor input arguments and populates the preprocessor907/// options accordingly.908///909/// \param [in] opts The preprocessor options instance910/// \param [out] args The list of input arguments911static void parsePreprocessorArgs(Fortran::frontend::PreprocessorOptions &opts,912                                  llvm::opt::ArgList &args) {913  // Add macros from the command line.914  for (const auto *currentArg :915       args.filtered(clang::options::OPT_D, clang::options::OPT_U)) {916    if (currentArg->getOption().matches(clang::options::OPT_D)) {917      opts.addMacroDef(currentArg->getValue());918    } else {919      opts.addMacroUndef(currentArg->getValue());920    }921  }922 923  // Add the ordered list of -I's.924  for (const auto *currentArg : args.filtered(clang::options::OPT_I))925    opts.searchDirectoriesFromDashI.emplace_back(currentArg->getValue());926 927  // Prepend the ordered list of -intrinsic-modules-path928  // to the default location to search.929  for (const auto *currentArg :930       args.filtered(clang::options::OPT_fintrinsic_modules_path))931    opts.searchDirectoriesFromIntrModPath.emplace_back(currentArg->getValue());932 933  // -cpp/-nocpp934  if (const auto *currentArg =935          args.getLastArg(clang::options::OPT_cpp, clang::options::OPT_nocpp))936    opts.macrosFlag = (currentArg->getOption().matches(clang::options::OPT_cpp))937                          ? PPMacrosFlag::Include938                          : PPMacrosFlag::Exclude;939  // Enable -cpp based on -x unless explicitly disabled with -nocpp940  if (opts.macrosFlag != PPMacrosFlag::Exclude)941    if (const auto *dashX = args.getLastArg(clang::options::OPT_x))942      opts.macrosFlag = llvm::StringSwitch<PPMacrosFlag>(dashX->getValue())943                            .Case("f95-cpp-input", PPMacrosFlag::Include)944                            .Default(opts.macrosFlag);945 946  opts.noReformat = args.hasArg(clang::options::OPT_fno_reformat);947  opts.preprocessIncludeLines =948      args.hasArg(clang::options::OPT_fpreprocess_include_lines);949  opts.noLineDirectives = args.hasArg(clang::options::OPT_P);950  opts.showMacros = args.hasArg(clang::options::OPT_dM);951}952 953/// Parses all semantic related arguments and populates the variables954/// options accordingly. Returns false if new errors are generated.955static bool parseSemaArgs(CompilerInvocation &res, llvm::opt::ArgList &args,956                          clang::DiagnosticsEngine &diags) {957  unsigned numErrorsBefore = diags.getNumErrors();958 959  // -J/module-dir option960  std::vector<std::string> moduleDirList =961      args.getAllArgValues(clang::options::OPT_module_dir);962  // User can only specify one -J/-module-dir directory, but may repeat963  // -J/-module-dir as long as the directory is the same each time.964  // https://gcc.gnu.org/onlinedocs/gfortran/Directory-Options.html965  std::sort(moduleDirList.begin(), moduleDirList.end());966  moduleDirList.erase(std::unique(moduleDirList.begin(), moduleDirList.end()),967                      moduleDirList.end());968  if (moduleDirList.size() > 1) {969    const unsigned diagID =970        diags.getCustomDiagID(clang::DiagnosticsEngine::Error,971                              "Only one '-module-dir/-J' directory allowed. "972                              "'-module-dir/-J' may be given multiple times "973                              "but the directory must be the same each time.");974    diags.Report(diagID);975  }976  if (moduleDirList.size() == 1)977    res.setModuleDir(moduleDirList[0]);978 979  // -fdebug-module-writer option980  if (args.hasArg(clang::options::OPT_fdebug_module_writer)) {981    res.setDebugModuleDir(true);982  }983 984  // -fhermetic-module-files option985  if (args.hasArg(clang::options::OPT_fhermetic_module_files)) {986    res.setHermeticModuleFileOutput(true);987  }988 989  // -module-suffix990  if (const auto *moduleSuffix =991          args.getLastArg(clang::options::OPT_module_suffix)) {992    res.setModuleFileSuffix(moduleSuffix->getValue());993  }994 995  // -f{no-}analyzed-objects-for-unparse996  res.setUseAnalyzedObjectsForUnparse(997      args.hasFlag(clang::options::OPT_fanalyzed_objects_for_unparse,998                   clang::options::OPT_fno_analyzed_objects_for_unparse, true));999 1000  return diags.getNumErrors() == numErrorsBefore;1001}1002 1003/// Parses all diagnostics related arguments and populates the variables1004/// options accordingly. Returns false if new errors are generated.1005/// FC1 driver entry point for parsing diagnostic arguments.1006static bool parseDiagArgs(CompilerInvocation &res, llvm::opt::ArgList &args,1007                          clang::DiagnosticsEngine &diags) {1008  unsigned numErrorsBefore = diags.getNumErrors();1009 1010  auto &features{res.getFrontendOpts().features};1011  // The order of these flags (-pedantic -W<feature> -w) is important and is1012  // chosen to match clang's behavior.1013 1014  // -pedantic1015  if (args.hasArg(clang::options::OPT_pedantic)) {1016    features.WarnOnAllNonstandard();1017    features.WarnOnAllUsage();1018    res.setEnableConformanceChecks();1019    res.setEnableUsageChecks();1020  }1021 1022  // -Werror option1023  // TODO: Currently throws a Diagnostic for anything other than -W<error>,1024  // this has to change when other -W<opt>'s are supported.1025  if (args.hasArg(clang::options::OPT_W_Joined)) {1026    const auto &wArgs = args.getAllArgValues(clang::options::OPT_W_Joined);1027    for (const auto &wArg : wArgs) {1028      if (wArg == "error") {1029        res.setWarnAsErr(true);1030        // -Wfatal-errors1031      } else if (wArg == "fatal-errors") {1032        res.setMaxErrors(1);1033        // -W[no-]<feature>1034      } else if (!features.EnableWarning(wArg)) {1035        const unsigned diagID = diags.getCustomDiagID(1036            clang::DiagnosticsEngine::Error, "Unknown diagnostic option: -W%0");1037        diags.Report(diagID) << wArg;1038      }1039    }1040  }1041 1042  // -w1043  if (args.hasArg(clang::options::OPT_w)) {1044    features.DisableAllWarnings();1045    res.setDisableWarnings();1046  }1047 1048  // Default to off for `flang -fc1`.1049  bool showColors{parseShowColorsArgs(args, false)};1050  diags.getDiagnosticOptions().ShowColors = showColors;1051  res.getDiagnosticOpts().ShowColors = showColors;1052  res.getFrontendOpts().showColors = showColors;1053  return diags.getNumErrors() == numErrorsBefore;1054}1055 1056/// Parses all Dialect related arguments and populates the variables1057/// options accordingly. Returns false if new errors are generated.1058static bool parseDialectArgs(CompilerInvocation &res, llvm::opt::ArgList &args,1059                             clang::DiagnosticsEngine &diags) {1060  unsigned numErrorsBefore = diags.getNumErrors();1061 1062  // -fd-lines-as-code1063  if (args.hasArg(clang::options::OPT_fd_lines_as_code)) {1064    if (res.getFrontendOpts().fortranForm == FortranForm::FreeForm) {1065      const unsigned fdLinesAsWarning = diags.getCustomDiagID(1066          clang::DiagnosticsEngine::Warning,1067          "‘-fd-lines-as-code’ has no effect in free form.");1068      diags.Report(fdLinesAsWarning);1069    } else {1070      res.getFrontendOpts().features.Enable(1071          Fortran::common::LanguageFeature::OldDebugLines, true);1072    }1073  }1074 1075  // -fd-lines-as-comments1076  if (args.hasArg(clang::options::OPT_fd_lines_as_comments)) {1077    if (res.getFrontendOpts().fortranForm == FortranForm::FreeForm) {1078      const unsigned fdLinesAsWarning = diags.getCustomDiagID(1079          clang::DiagnosticsEngine::Warning,1080          "‘-fd-lines-as-comments’ has no effect in free form.");1081      diags.Report(fdLinesAsWarning);1082    } else {1083      res.getFrontendOpts().features.Enable(1084          Fortran::common::LanguageFeature::OldDebugLines, false);1085    }1086  }1087 1088  // -fdefault* family1089  if (args.hasArg(clang::options::OPT_fdefault_real_8)) {1090    res.getDefaultKinds().set_defaultRealKind(8);1091    res.getDefaultKinds().set_doublePrecisionKind(16);1092  }1093  if (args.hasArg(clang::options::OPT_fdefault_integer_8)) {1094    res.getDefaultKinds().set_defaultIntegerKind(8);1095    res.getDefaultKinds().set_subscriptIntegerKind(8);1096    res.getDefaultKinds().set_sizeIntegerKind(8);1097    res.getDefaultKinds().set_defaultLogicalKind(8);1098  }1099  if (args.hasArg(clang::options::OPT_fdefault_double_8)) {1100    if (!args.hasArg(clang::options::OPT_fdefault_real_8)) {1101      // -fdefault-double-8 has to be used with -fdefault-real-81102      // to be compatible with gfortran1103      const unsigned diagID = diags.getCustomDiagID(1104          clang::DiagnosticsEngine::Error,1105          "Use of `-fdefault-double-8` requires `-fdefault-real-8`");1106      diags.Report(diagID);1107    }1108    // https://gcc.gnu.org/onlinedocs/gfortran/Fortran-Dialect-Options.html1109    res.getDefaultKinds().set_doublePrecisionKind(8);1110  }1111  if (args.hasArg(clang::options::OPT_flarge_sizes))1112    res.getDefaultKinds().set_sizeIntegerKind(8);1113 1114  // -x cuda1115  auto language = args.getLastArgValue(clang::options::OPT_x);1116  if (language == "cuda") {1117    res.getFrontendOpts().features.Enable(1118        Fortran::common::LanguageFeature::CUDA);1119  }1120 1121  // -fopenacc1122  if (args.hasArg(clang::options::OPT_fopenacc)) {1123    res.getFrontendOpts().features.Enable(1124        Fortran::common::LanguageFeature::OpenACC);1125  }1126 1127  // -std=f20181128  // TODO: Set proper options when more fortran standards1129  // are supported.1130  if (args.hasArg(clang::options::OPT_std_EQ)) {1131    auto standard = args.getLastArgValue(clang::options::OPT_std_EQ);1132    // We only allow f2018 as the given standard1133    if (standard == "f2018") {1134      res.setEnableConformanceChecks();1135      res.getFrontendOpts().features.WarnOnAllNonstandard();1136    } else {1137      const unsigned diagID =1138          diags.getCustomDiagID(clang::DiagnosticsEngine::Error,1139                                "Only -std=f2018 is allowed currently.");1140      diags.Report(diagID);1141    }1142  }1143  // -fcoarray1144  if (args.hasArg(clang::options::OPT_fcoarray)) {1145    res.getFrontendOpts().features.Enable(1146        Fortran::common::LanguageFeature::Coarray);1147    const unsigned diagID =1148        diags.getCustomDiagID(clang::DiagnosticsEngine::Warning,1149                              "Support for multi image Fortran features is "1150                              "still experimental and in development.");1151    diags.Report(diagID);1152  }1153 1154  return diags.getNumErrors() == numErrorsBefore;1155}1156 1157/// Parses all OpenMP related arguments if the -fopenmp option is present,1158/// populating the \c res object accordingly. Returns false if new errors are1159/// generated.1160static bool parseOpenMPArgs(CompilerInvocation &res, llvm::opt::ArgList &args,1161                            clang::DiagnosticsEngine &diags) {1162  llvm::opt::Arg *arg = args.getLastArg(clang::options::OPT_fopenmp,1163                                        clang::options::OPT_fno_openmp);1164  if (!arg || arg->getOption().matches(clang::options::OPT_fno_openmp)) {1165    bool isSimdSpecified =1166        args.hasFlag(clang::options::OPT_fopenmp_simd,1167                     clang::options::OPT_fno_openmp_simd, /*Default=*/false);1168    if (!isSimdSpecified)1169      return true;1170    res.getLangOpts().OpenMPSimd = 1;1171  }1172 1173  unsigned numErrorsBefore = diags.getNumErrors();1174  llvm::Triple t(res.getTargetOpts().triple);1175 1176  constexpr unsigned newestFullySupported = 31;1177  constexpr unsigned latestFinalized = 60;1178  // By default OpenMP is set to the most recent fully supported version1179  res.getLangOpts().OpenMPVersion = newestFullySupported;1180  res.getFrontendOpts().features.Enable(1181      Fortran::common::LanguageFeature::OpenMP);1182  if (auto *arg = args.getLastArg(clang::options::OPT_fopenmp_version_EQ)) {1183    llvm::ArrayRef<unsigned> ompVersions = llvm::omp::getOpenMPVersions();1184    unsigned oldVersions[] = {11, 20, 25, 30};1185    unsigned version = 0;1186 1187    auto reportBadVersion = [&](llvm::StringRef value) {1188      const unsigned diagID =1189          diags.getCustomDiagID(clang::DiagnosticsEngine::Error,1190                                "'%0' is not a valid OpenMP version in '%1', "1191                                "valid versions are %2");1192      std::string buffer;1193      llvm::raw_string_ostream versions(buffer);1194      llvm::interleaveComma(ompVersions, versions);1195 1196      diags.Report(diagID) << value << arg->getAsString(args) << versions.str();1197    };1198 1199    auto reportFutureVersion = [&](llvm::StringRef value) {1200      const unsigned diagID = diags.getCustomDiagID(1201          clang::DiagnosticsEngine::Warning,1202          "The specification for OpenMP version %0 is still under development; "1203          "the syntax and semantics of new features may be subject to change");1204      std::string buffer;1205      llvm::raw_string_ostream versions(buffer);1206      llvm::interleaveComma(ompVersions, versions);1207 1208      diags.Report(diagID) << value;1209    };1210 1211    llvm::StringRef value = arg->getValue();1212    if (!value.getAsInteger(/*radix=*/10, version)) {1213      if (llvm::is_contained(ompVersions, version)) {1214        res.getLangOpts().OpenMPVersion = version;1215 1216        if (version > latestFinalized)1217          reportFutureVersion(value);1218        else if (version > newestFullySupported)1219          diags.Report(clang::diag::warn_openmp_incomplete) << version;1220      } else if (llvm::is_contained(oldVersions, version)) {1221        const unsigned diagID =1222            diags.getCustomDiagID(clang::DiagnosticsEngine::Warning,1223                                  "OpenMP version %0 is no longer supported, "1224                                  "assuming version %1");1225        std::string assumed = std::to_string(res.getLangOpts().OpenMPVersion);1226        diags.Report(diagID) << value << assumed;1227      } else {1228        reportBadVersion(value);1229      }1230    } else {1231      reportBadVersion(value);1232    }1233  }1234 1235  if (args.hasArg(clang::options::OPT_fopenmp_force_usm)) {1236    res.getLangOpts().OpenMPForceUSM = 1;1237  }1238  if (args.hasArg(clang::options::OPT_fopenmp_is_target_device)) {1239    res.getLangOpts().OpenMPIsTargetDevice = 1;1240 1241    // Get OpenMP host file path if any and report if a non existent file is1242    // found1243    if (auto *arg =1244            args.getLastArg(clang::options::OPT_fopenmp_host_ir_file_path)) {1245      res.getLangOpts().OMPHostIRFile = arg->getValue();1246      if (!llvm::sys::fs::exists(res.getLangOpts().OMPHostIRFile))1247        diags.Report(clang::diag::err_omp_host_ir_file_not_found)1248            << res.getLangOpts().OMPHostIRFile;1249    }1250 1251    if (args.hasFlag(1252            clang::options::OPT_fopenmp_assume_teams_oversubscription,1253            clang::options::OPT_fno_openmp_assume_teams_oversubscription,1254            /*Default=*/false))1255      res.getLangOpts().OpenMPTeamSubscription = true;1256 1257    if (args.hasArg(clang::options::OPT_fopenmp_assume_no_thread_state))1258      res.getLangOpts().OpenMPNoThreadState = 1;1259 1260    if (args.hasArg(clang::options::OPT_fopenmp_assume_no_nested_parallelism))1261      res.getLangOpts().OpenMPNoNestedParallelism = 1;1262 1263    if (args.hasFlag(1264            clang::options::OPT_fopenmp_assume_threads_oversubscription,1265            clang::options::OPT_fno_openmp_assume_threads_oversubscription,1266            /*Default=*/false))1267      res.getLangOpts().OpenMPThreadSubscription = true;1268 1269    if ((args.hasArg(clang::options::OPT_fopenmp_target_debug) ||1270         args.hasArg(clang::options::OPT_fopenmp_target_debug_EQ))) {1271      res.getLangOpts().OpenMPTargetDebug =1272          getLastArgIntValue(args, clang::options::OPT_fopenmp_target_debug_EQ,1273                             res.getLangOpts().OpenMPTargetDebug, diags);1274 1275      if (!res.getLangOpts().OpenMPTargetDebug &&1276          args.hasArg(clang::options::OPT_fopenmp_target_debug))1277        res.getLangOpts().OpenMPTargetDebug = 1;1278    }1279    if (args.hasArg(clang::options::OPT_no_offloadlib))1280      res.getLangOpts().NoGPULib = 1;1281  }1282  if (llvm::Triple(res.getTargetOpts().triple).isGPU()) {1283    if (!res.getLangOpts().OpenMPIsTargetDevice) {1284      const unsigned diagID = diags.getCustomDiagID(1285          clang::DiagnosticsEngine::Error,1286          "OpenMP GPU is only prepared to deal with device code.");1287      diags.Report(diagID);1288    }1289    res.getLangOpts().OpenMPIsGPU = 1;1290  } else {1291    res.getLangOpts().OpenMPIsGPU = 0;1292  }1293 1294  // Get the OpenMP target triples if any.1295  if (auto *arg = args.getLastArg(clang::options::OPT_offload_targets_EQ)) {1296    enum ArchPtrSize { Arch16Bit, Arch32Bit, Arch64Bit };1297    auto getArchPtrSize = [](const llvm::Triple &triple) {1298      if (triple.isArch16Bit())1299        return Arch16Bit;1300      if (triple.isArch32Bit())1301        return Arch32Bit;1302      assert(triple.isArch64Bit() && "Expected 64-bit architecture");1303      return Arch64Bit;1304    };1305 1306    for (unsigned i = 0; i < arg->getNumValues(); ++i) {1307      llvm::Triple tt(arg->getValue(i));1308 1309      if (tt.getArch() == llvm::Triple::UnknownArch ||1310          !(tt.getArch() == llvm::Triple::aarch64 || tt.isPPC() ||1311            tt.getArch() == llvm::Triple::systemz ||1312            tt.getArch() == llvm::Triple::x86 ||1313            tt.getArch() == llvm::Triple::x86_64 || tt.isGPU()))1314        diags.Report(clang::diag::err_drv_invalid_omp_target)1315            << arg->getValue(i);1316      else if (getArchPtrSize(t) != getArchPtrSize(tt))1317        diags.Report(clang::diag::err_drv_incompatible_omp_arch)1318            << arg->getValue(i) << t.str();1319      else1320        res.getLangOpts().OMPTargetTriples.push_back(tt);1321    }1322  }1323  return diags.getNumErrors() == numErrorsBefore;1324}1325 1326/// Parses signed integer overflow options and populates the1327/// CompilerInvocation accordingly.1328/// Returns false if new errors are generated.1329///1330/// \param [out] invoc Stores the processed arguments1331/// \param [in] args The compiler invocation arguments to parse1332/// \param [out] diags DiagnosticsEngine to report erros with1333static bool parseIntegerOverflowArgs(CompilerInvocation &invoc,1334                                     llvm::opt::ArgList &args,1335                                     clang::DiagnosticsEngine &diags) {1336  Fortran::common::LangOptions &opts = invoc.getLangOpts();1337 1338  if (args.getLastArg(clang::options::OPT_fwrapv))1339    opts.setSignedOverflowBehavior(Fortran::common::LangOptions::SOB_Defined);1340 1341  return true;1342}1343 1344/// Parses all floating point related arguments and populates the1345/// CompilerInvocation accordingly.1346/// Returns false if new errors are generated.1347///1348/// \param [out] invoc Stores the processed arguments1349/// \param [in] args The compiler invocation arguments to parse1350/// \param [out] diags DiagnosticsEngine to report erros with1351static bool parseFloatingPointArgs(CompilerInvocation &invoc,1352                                   llvm::opt::ArgList &args,1353                                   clang::DiagnosticsEngine &diags) {1354  Fortran::common::LangOptions &opts = invoc.getLangOpts();1355 1356  if (const llvm::opt::Arg *a =1357          args.getLastArg(clang::options::OPT_ffp_contract)) {1358    const llvm::StringRef val = a->getValue();1359    enum Fortran::common::LangOptions::FPModeKind fpContractMode;1360 1361    if (val == "off")1362      fpContractMode = Fortran::common::LangOptions::FPM_Off;1363    else if (val == "fast")1364      fpContractMode = Fortran::common::LangOptions::FPM_Fast;1365    else {1366      diags.Report(clang::diag::err_drv_unsupported_option_argument)1367          << a->getSpelling() << val;1368      return false;1369    }1370 1371    opts.setFPContractMode(fpContractMode);1372  }1373 1374  if (args.getLastArg(clang::options::OPT_menable_no_infs)) {1375    opts.NoHonorInfs = true;1376  }1377 1378  if (args.getLastArg(clang::options::OPT_menable_no_nans)) {1379    opts.NoHonorNaNs = true;1380  }1381 1382  if (args.getLastArg(clang::options::OPT_fapprox_func)) {1383    opts.ApproxFunc = true;1384  }1385 1386  if (args.getLastArg(clang::options::OPT_fno_signed_zeros)) {1387    opts.NoSignedZeros = true;1388  }1389 1390  if (args.getLastArg(clang::options::OPT_mreassociate)) {1391    opts.AssociativeMath = true;1392  }1393 1394  if (args.getLastArg(clang::options::OPT_freciprocal_math)) {1395    opts.ReciprocalMath = true;1396  }1397 1398  if (args.getLastArg(clang::options::OPT_ffast_math)) {1399    opts.NoHonorInfs = true;1400    opts.NoHonorNaNs = true;1401    opts.AssociativeMath = true;1402    opts.ReciprocalMath = true;1403    opts.ApproxFunc = true;1404    opts.NoSignedZeros = true;1405    opts.FastRealMod = true;1406    opts.setFPContractMode(Fortran::common::LangOptions::FPM_Fast);1407  }1408 1409  if (llvm::opt::Arg *arg =1410          args.getLastArg(clang::options::OPT_ffast_real_mod,1411                          clang::options::OPT_fno_fast_real_mod)) {1412    if (arg->getOption().matches(clang::options::OPT_ffast_real_mod))1413      opts.FastRealMod = true;1414    if (arg->getOption().matches(clang::options::OPT_fno_fast_real_mod))1415      opts.FastRealMod = false;1416  }1417 1418  return true;1419}1420 1421/// Parses vscale range options and populates the CompilerInvocation1422/// accordingly.1423/// Returns false if new errors are generated.1424///1425/// \param [out] invoc Stores the processed arguments1426/// \param [in] args The compiler invocation arguments to parse1427/// \param [out] diags DiagnosticsEngine to report erros with1428static bool parseVScaleArgs(CompilerInvocation &invoc, llvm::opt::ArgList &args,1429                            clang::DiagnosticsEngine &diags) {1430  const auto *vscaleMin = args.getLastArg(clang::options::OPT_mvscale_min_EQ);1431  const auto *vscaleMax = args.getLastArg(clang::options::OPT_mvscale_max_EQ);1432 1433  if (!vscaleMin && !vscaleMax)1434    return true;1435 1436  llvm::Triple triple = llvm::Triple(invoc.getTargetOpts().triple);1437  if (!triple.isAArch64() && !triple.isRISCV()) {1438    const unsigned diagID =1439        diags.getCustomDiagID(clang::DiagnosticsEngine::Error,1440                              "`-mvscale-max` and `-mvscale-min` are not "1441                              "supported for this architecture: %0");1442    diags.Report(diagID) << triple.getArchName();1443    return false;1444  }1445 1446  Fortran::common::LangOptions &opts = invoc.getLangOpts();1447  if (vscaleMin) {1448    llvm::StringRef argValue = llvm::StringRef(vscaleMin->getValue());1449    unsigned vscaleMinVal;1450    if (argValue.getAsInteger(/*Radix=*/10, vscaleMinVal)) {1451      diags.Report(clang::diag::err_drv_unsupported_option_argument)1452          << vscaleMax->getSpelling() << argValue;1453      return false;1454    }1455    opts.VScaleMin = vscaleMinVal;1456  }1457 1458  if (vscaleMax) {1459    llvm::StringRef argValue = llvm::StringRef(vscaleMax->getValue());1460    unsigned vscaleMaxVal;1461    if (argValue.getAsInteger(/*Radix=w*/ 10, vscaleMaxVal)) {1462      diags.Report(clang::diag::err_drv_unsupported_option_argument)1463          << vscaleMax->getSpelling() << argValue;1464      return false;1465    }1466    opts.VScaleMax = vscaleMaxVal;1467  }1468  return true;1469}1470 1471static bool parseLinkerOptionsArgs(CompilerInvocation &invoc,1472                                   llvm::opt::ArgList &args,1473                                   clang::DiagnosticsEngine &diags) {1474  llvm::Triple triple = llvm::Triple(invoc.getTargetOpts().triple);1475  CodeGenOptions &opts = invoc.getCodeGenOpts();1476 1477  // TODO: support --dependent-lib on other platforms when MLIR supports1478  //       !llvm.dependent.lib1479  if (args.hasArg(clang::options::OPT_dependent_lib) && !triple.isOSWindows()) {1480    const unsigned diagID =1481        diags.getCustomDiagID(clang::DiagnosticsEngine::Error,1482                              "--dependent-lib is only supported on Windows");1483    diags.Report(diagID);1484    return false;1485  }1486 1487  opts.DependentLibs = args.getAllArgValues(clang::options::OPT_dependent_lib);1488 1489  // -flto=full/thin option.1490  if (const llvm::opt::Arg *a = args.getLastArg(clang::options::OPT_flto_EQ)) {1491    llvm::StringRef s = a->getValue();1492    assert((s == "full" || s == "thin") && "Unknown LTO mode.");1493    if (s == "full")1494      opts.PrepareForFullLTO = true;1495    else1496      opts.PrepareForThinLTO = true;1497  }1498 1499  // -ffat-lto-objects1500  if (const llvm::opt::Arg *arg =1501          args.getLastArg(clang::options::OPT_ffat_lto_objects,1502                          clang::options::OPT_fno_fat_lto_objects)) {1503    opts.PrepareForFatLTO =1504        arg->getOption().matches(clang::options::OPT_ffat_lto_objects);1505    if (opts.PrepareForFatLTO) {1506      assert((opts.PrepareForFullLTO || opts.PrepareForThinLTO) &&1507             "Unknown LTO mode");1508 1509      if (!triple.isOSBinFormatELF())1510        diags.Report(clang::diag::err_drv_unsupported_opt_for_target)1511            << arg->getAsString(args) << triple.getTriple();1512    }1513  }1514  return true;1515}1516 1517static bool parseLangOptionsArgs(CompilerInvocation &invoc,1518                                 llvm::opt::ArgList &args,1519                                 clang::DiagnosticsEngine &diags) {1520  bool success = true;1521 1522  success &= parseIntegerOverflowArgs(invoc, args, diags);1523  success &= parseFloatingPointArgs(invoc, args, diags);1524  success &= parseVScaleArgs(invoc, args, diags);1525 1526  return success;1527}1528 1529bool CompilerInvocation::createFromArgs(1530    CompilerInvocation &invoc, llvm::ArrayRef<const char *> commandLineArgs,1531    clang::DiagnosticsEngine &diags, const char *argv0) {1532 1533  bool success = true;1534 1535  // Set the default triple for this CompilerInvocation. This might be1536  // overridden by users with `-triple` (see the call to `ParseTargetArgs`1537  // below).1538  // NOTE: Like in Clang, it would be nice to use option marshalling1539  // for this so that the entire logic for setting-up the triple is in one1540  // place.1541  invoc.getTargetOpts().triple =1542      llvm::Triple::normalize(llvm::sys::getDefaultTargetTriple());1543 1544  // Parse the arguments1545  const llvm::opt::OptTable &opts = clang::getDriverOptTable();1546  llvm::opt::Visibility visibilityMask(clang::options::FC1Option);1547  unsigned missingArgIndex, missingArgCount;1548  llvm::opt::InputArgList args = opts.ParseArgs(1549      commandLineArgs, missingArgIndex, missingArgCount, visibilityMask);1550 1551  // Check for missing argument error.1552  if (missingArgCount) {1553    diags.Report(clang::diag::err_drv_missing_argument)1554        << args.getArgString(missingArgIndex) << missingArgCount;1555    success = false;1556  }1557 1558  // Issue errors on unknown arguments1559  for (const auto *a : args.filtered(clang::options::OPT_UNKNOWN)) {1560    auto argString = a->getAsString(args);1561    std::string nearest;1562    if (opts.findNearest(argString, nearest, visibilityMask) > 1)1563      diags.Report(clang::diag::err_drv_unknown_argument) << argString;1564    else1565      diags.Report(clang::diag::err_drv_unknown_argument_with_suggestion)1566          << argString << nearest;1567    success = false;1568  }1569 1570  // -flang-experimental-hlfir1571  if (args.hasArg(clang::options::OPT_flang_experimental_hlfir) ||1572      args.hasArg(clang::options::OPT_emit_hlfir)) {1573    invoc.loweringOpts.setLowerToHighLevelFIR(true);1574  }1575 1576  // -flang-deprecated-no-hlfir1577  if (args.hasArg(clang::options::OPT_flang_deprecated_no_hlfir) &&1578      !args.hasArg(clang::options::OPT_emit_hlfir)) {1579    if (args.hasArg(clang::options::OPT_flang_experimental_hlfir)) {1580      const unsigned diagID = diags.getCustomDiagID(1581          clang::DiagnosticsEngine::Error,1582          "Options '-flang-experimental-hlfir' and "1583          "'-flang-deprecated-no-hlfir' cannot be both specified");1584      diags.Report(diagID);1585    }1586    invoc.loweringOpts.setLowerToHighLevelFIR(false);1587  }1588 1589  // -fno-ppc-native-vector-element-order1590  if (args.hasArg(clang::options::OPT_fno_ppc_native_vec_elem_order)) {1591    invoc.loweringOpts.setNoPPCNativeVecElemOrder(true);1592  }1593 1594  // -f[no-]init-global-zero1595  if (args.hasFlag(clang::options::OPT_finit_global_zero,1596                   clang::options::OPT_fno_init_global_zero,1597                   /*default=*/true))1598    invoc.loweringOpts.setInitGlobalZero(true);1599  else1600    invoc.loweringOpts.setInitGlobalZero(false);1601 1602  // Preserve all the remark options requested, i.e. -Rpass, -Rpass-missed or1603  // -Rpass-analysis. This will be used later when processing and outputting the1604  // remarks generated by LLVM in ExecuteCompilerInvocation.cpp.1605  for (auto *a : args.filtered(clang::options::OPT_R_Group)) {1606    if (a->getOption().matches(clang::options::OPT_R_value_Group))1607      // This is -Rfoo=, where foo is the name of the diagnostic1608      // group. Add only the remark option name to the diagnostics. e.g. for1609      // -Rpass= we will add the string "pass".1610      invoc.getDiagnosticOpts().Remarks.push_back(1611          std::string(a->getOption().getName().drop_front(1).rtrim("=-")));1612    else1613      // If no regex was provided, add the provided value, e.g. for -Rpass add1614      // the string "pass".1615      invoc.getDiagnosticOpts().Remarks.push_back(a->getValue());1616  }1617 1618  // -frealloc-lhs is the default.1619  if (!args.hasFlag(clang::options::OPT_frealloc_lhs,1620                    clang::options::OPT_fno_realloc_lhs, true))1621    invoc.loweringOpts.setReallocateLHS(false);1622 1623  invoc.loweringOpts.setRepackArrays(args.hasFlag(1624      clang::options::OPT_frepack_arrays, clang::options::OPT_fno_repack_arrays,1625      /*default=*/false));1626  invoc.loweringOpts.setStackRepackArrays(1627      args.hasFlag(clang::options::OPT_fstack_repack_arrays,1628                   clang::options::OPT_fno_stack_repack_arrays,1629                   /*default=*/false));1630  if (auto *arg =1631          args.getLastArg(clang::options::OPT_frepack_arrays_contiguity_EQ))1632    invoc.loweringOpts.setRepackArraysWhole(arg->getValue() ==1633                                            llvm::StringRef{"whole"});1634 1635  success &= parseFrontendArgs(invoc.getFrontendOpts(), args, diags);1636  parseTargetArgs(invoc.getTargetOpts(), args);1637  parsePreprocessorArgs(invoc.getPreprocessorOpts(), args);1638  parseCodeGenArgs(invoc.getCodeGenOpts(), args, diags);1639  success &= parseDebugArgs(invoc.getCodeGenOpts(), args, diags);1640  success &= parseVectorLibArg(invoc.getCodeGenOpts(), args, diags);1641  success &= parseSemaArgs(invoc, args, diags);1642  success &= parseDialectArgs(invoc, args, diags);1643  success &= parseOpenMPArgs(invoc, args, diags);1644  success &= parseDiagArgs(invoc, args, diags);1645 1646  // Collect LLVM (-mllvm) and MLIR (-mmlir) options.1647  // NOTE: Try to avoid adding any options directly to `llvmArgs` or1648  // `mlirArgs`. Instead, you can use1649  //    * `-mllvm <your-llvm-option>`, or1650  //    * `-mmlir <your-mlir-option>`.1651  invoc.frontendOpts.llvmArgs = args.getAllArgValues(clang::options::OPT_mllvm);1652  invoc.frontendOpts.mlirArgs = args.getAllArgValues(clang::options::OPT_mmlir);1653 1654  success &= parseLangOptionsArgs(invoc, args, diags);1655 1656  success &= parseLinkerOptionsArgs(invoc, args, diags);1657 1658  // Set the string to be used as the return value of the COMPILER_OPTIONS1659  // intrinsic of iso_fortran_env. This is either passed in from the parent1660  // compiler driver invocation with an environment variable, or failing that1661  // set to the command line arguments of the frontend driver invocation.1662  invoc.allCompilerInvocOpts = std::string();1663  llvm::raw_string_ostream os(invoc.allCompilerInvocOpts);1664  char *compilerOptsEnv = std::getenv("FLANG_COMPILER_OPTIONS_STRING");1665  if (compilerOptsEnv != nullptr) {1666    os << compilerOptsEnv;1667  } else {1668    os << argv0 << ' ';1669    for (auto it = commandLineArgs.begin(), e = commandLineArgs.end(); it != e;1670         ++it) {1671      os << ' ' << *it;1672    }1673  }1674 1675  // Process the timing-related options.1676  if (args.hasArg(clang::options::OPT_ftime_report))1677    invoc.enableTimers = true;1678 1679  invoc.setArgv0(argv0);1680 1681  return success;1682}1683 1684void CompilerInvocation::collectMacroDefinitions() {1685  auto &ppOpts = this->getPreprocessorOpts();1686 1687  for (unsigned i = 0, n = ppOpts.macros.size(); i != n; ++i) {1688    llvm::StringRef macro = ppOpts.macros[i].first;1689    bool isUndef = ppOpts.macros[i].second;1690 1691    std::pair<llvm::StringRef, llvm::StringRef> macroPair = macro.split('=');1692    llvm::StringRef macroName = macroPair.first;1693    llvm::StringRef macroBody = macroPair.second;1694 1695    // For an #undef'd macro, we only care about the name.1696    if (isUndef) {1697      parserOpts.predefinitions.emplace_back(macroName.str(),1698                                             std::optional<std::string>{});1699      continue;1700    }1701 1702    // For a #define'd macro, figure out the actual definition.1703    if (macroName.size() == macro.size())1704      macroBody = "1";1705    else {1706      // Note: GCC drops anything following an end-of-line character.1707      llvm::StringRef::size_type end = macroBody.find_first_of("\n\r");1708      macroBody = macroBody.substr(0, end);1709    }1710    parserOpts.predefinitions.emplace_back(1711        macroName, std::optional<std::string>(macroBody.str()));1712  }1713}1714 1715void CompilerInvocation::setDefaultFortranOpts() {1716  auto &fortranOptions = getFortranOpts();1717 1718  std::vector<std::string> searchDirectories{"."s};1719  fortranOptions.searchDirectories = searchDirectories;1720 1721  // Add the location of omp_lib.h to the search directories. Currently this is1722  // identical to the modules' directory.1723  fortranOptions.searchDirectories.emplace_back(1724      getOpenMPHeadersDir(getArgv0()));1725 1726  fortranOptions.isFixedForm = false;1727}1728 1729// TODO: When expanding this method, consider creating a dedicated API for1730// this. Also at some point we will need to differentiate between different1731// targets and add dedicated predefines for each.1732void CompilerInvocation::setDefaultPredefinitions() {1733  auto &fortranOptions = getFortranOpts();1734  const auto &frontendOptions = getFrontendOpts();1735  // Populate the macro list with version numbers and other predefinitions.1736  fortranOptions.predefinitions.emplace_back("__flang__", "1");1737  fortranOptions.predefinitions.emplace_back("__flang_major__",1738                                             FLANG_VERSION_MAJOR_STRING);1739  fortranOptions.predefinitions.emplace_back("__flang_minor__",1740                                             FLANG_VERSION_MINOR_STRING);1741  fortranOptions.predefinitions.emplace_back("__flang_patchlevel__",1742                                             FLANG_VERSION_PATCHLEVEL_STRING);1743 1744  // Add predefinitions based on the relocation model1745  if (unsigned PICLevel = getCodeGenOpts().PICLevel) {1746    fortranOptions.predefinitions.emplace_back("__PIC__",1747                                               std::to_string(PICLevel));1748    fortranOptions.predefinitions.emplace_back("__pic__",1749                                               std::to_string(PICLevel));1750    if (getCodeGenOpts().IsPIE) {1751      fortranOptions.predefinitions.emplace_back("__PIE__",1752                                                 std::to_string(PICLevel));1753      fortranOptions.predefinitions.emplace_back("__pie__",1754                                                 std::to_string(PICLevel));1755    }1756  }1757 1758  // Add predefinitions based on extensions enabled1759  if (frontendOptions.features.IsEnabled(1760          Fortran::common::LanguageFeature::OpenACC)) {1761    fortranOptions.predefinitions.emplace_back("_OPENACC", "202211");1762  }1763  if (frontendOptions.features.IsEnabled(1764          Fortran::common::LanguageFeature::OpenMP)) {1765    Fortran::common::setOpenMPMacro(getLangOpts().OpenMPVersion,1766                                    fortranOptions.predefinitions);1767  }1768 1769  if (frontendOptions.features.IsEnabled(1770          Fortran::common::LanguageFeature::CUDA)) {1771    fortranOptions.predefinitions.emplace_back("_CUDA", "1");1772  }1773 1774  llvm::Triple targetTriple{llvm::Triple(this->targetOpts.triple)};1775  if (targetTriple.isOSLinux()) {1776    fortranOptions.predefinitions.emplace_back("__linux__", "1");1777  } else if (targetTriple.isOSAIX()) {1778    fortranOptions.predefinitions.emplace_back("_AIX", "1");1779  }1780 1781  switch (targetTriple.getArch()) {1782  default:1783    break;1784  case llvm::Triple::ArchType::x86_64:1785    fortranOptions.predefinitions.emplace_back("__x86_64__", "1");1786    fortranOptions.predefinitions.emplace_back("__x86_64", "1");1787    break;1788  case llvm::Triple::ArchType::ppc:1789  case llvm::Triple::ArchType::ppc64:1790  case llvm::Triple::ArchType::ppcle:1791  case llvm::Triple::ArchType::ppc64le:1792    // '__powerpc__' is a generic macro for any PowerPC.1793    fortranOptions.predefinitions.emplace_back("__powerpc__", "1");1794    if (targetTriple.isOSAIX() && targetTriple.isArch64Bit()) {1795      fortranOptions.predefinitions.emplace_back("__64BIT__", "1");1796    }1797    break;1798  case llvm::Triple::ArchType::aarch64:1799    fortranOptions.predefinitions.emplace_back("__aarch64__", "1");1800    fortranOptions.predefinitions.emplace_back("__aarch64", "1");1801    break;1802  }1803}1804 1805void CompilerInvocation::setFortranOpts() {1806  auto &fortranOptions = getFortranOpts();1807  const auto &frontendOptions = getFrontendOpts();1808  const auto &preprocessorOptions = getPreprocessorOpts();1809  auto &moduleDirJ = getModuleDir();1810 1811  if (frontendOptions.fortranForm != FortranForm::Unknown) {1812    fortranOptions.isFixedForm =1813        frontendOptions.fortranForm == FortranForm::FixedForm;1814  }1815  fortranOptions.fixedFormColumns = frontendOptions.fixedFormColumns;1816 1817  // -E1818  fortranOptions.prescanAndReformat =1819      frontendOptions.programAction == PrintPreprocessedInput;1820 1821  fortranOptions.features = frontendOptions.features;1822  fortranOptions.encoding = frontendOptions.encoding;1823 1824  // Adding search directories specified by -I1825  fortranOptions.searchDirectories.insert(1826      fortranOptions.searchDirectories.end(),1827      preprocessorOptions.searchDirectoriesFromDashI.begin(),1828      preprocessorOptions.searchDirectoriesFromDashI.end());1829 1830  // Add the ordered list of -intrinsic-modules-path1831  fortranOptions.searchDirectories.insert(1832      fortranOptions.searchDirectories.end(),1833      preprocessorOptions.searchDirectoriesFromIntrModPath.begin(),1834      preprocessorOptions.searchDirectoriesFromIntrModPath.end());1835 1836  //  Add the default intrinsic module directory1837  fortranOptions.intrinsicModuleDirectories.emplace_back(1838      getIntrinsicDir(getArgv0()));1839 1840  // Add the directory supplied through -J/-module-dir to the list of search1841  // directories1842  if (moduleDirJ != ".")1843    fortranOptions.searchDirectories.emplace_back(moduleDirJ);1844 1845  if (frontendOptions.instrumentedParse)1846    fortranOptions.instrumentedParse = true;1847 1848  if (frontendOptions.showColors)1849    fortranOptions.showColors = true;1850 1851  if (frontendOptions.needProvenanceRangeToCharBlockMappings)1852    fortranOptions.needProvenanceRangeToCharBlockMappings = true;1853 1854  fortranOptions.features = frontendOptions.features;1855}1856 1857std::unique_ptr<Fortran::semantics::SemanticsContext>1858CompilerInvocation::getSemanticsCtx(1859    Fortran::parser::AllCookedSources &allCookedSources,1860    const llvm::TargetMachine &targetMachine) {1861  auto &fortranOptions = getFortranOpts();1862 1863  auto semanticsContext = std::make_unique<semantics::SemanticsContext>(1864      getDefaultKinds(), fortranOptions.features, getLangOpts(),1865      allCookedSources);1866 1867  semanticsContext->set_moduleDirectory(getModuleDir())1868      .set_searchDirectories(fortranOptions.searchDirectories)1869      .set_intrinsicModuleDirectories(fortranOptions.intrinsicModuleDirectories)1870      .set_maxErrors(getMaxErrors())1871      .set_warningsAreErrors(getWarnAsErr())1872      .set_moduleFileSuffix(getModuleFileSuffix())1873      .set_underscoring(getCodeGenOpts().Underscoring);1874 1875  std::string compilerVersion = Fortran::common::getFlangFullVersion();1876  Fortran::tools::setUpTargetCharacteristics(1877      semanticsContext->targetCharacteristics(), targetMachine, getTargetOpts(),1878      compilerVersion, allCompilerInvocOpts);1879  return semanticsContext;1880}1881 1882/// Set \p loweringOptions controlling lowering behavior based1883/// on the \p optimizationLevel.1884void CompilerInvocation::setLoweringOptions() {1885  const CodeGenOptions &codegenOpts = getCodeGenOpts();1886 1887  // Lower TRANSPOSE as a runtime call under -O0.1888  loweringOpts.setOptimizeTranspose(codegenOpts.OptimizationLevel > 0);1889  loweringOpts.setUnderscoring(codegenOpts.Underscoring);1890  loweringOpts.setSkipExternalRttiDefinition(skipExternalRttiDefinition);1891 1892  const Fortran::common::LangOptions &langOptions = getLangOpts();1893  loweringOpts.setIntegerWrapAround(langOptions.getSignedOverflowBehavior() ==1894                                    Fortran::common::LangOptions::SOB_Defined);1895  Fortran::common::MathOptionsBase &mathOpts = loweringOpts.getMathOptions();1896  // TODO: when LangOptions are finalized, we can represent1897  //       the math related options using Fortran::commmon::MathOptionsBase,1898  //       so that we can just copy it into LoweringOptions.1899  mathOpts1900      .setFPContractEnabled(langOptions.getFPContractMode() ==1901                            Fortran::common::LangOptions::FPM_Fast)1902      .setNoHonorInfs(langOptions.NoHonorInfs)1903      .setNoHonorNaNs(langOptions.NoHonorNaNs)1904      .setApproxFunc(langOptions.ApproxFunc)1905      .setNoSignedZeros(langOptions.NoSignedZeros)1906      .setAssociativeMath(langOptions.AssociativeMath)1907      .setReciprocalMath(langOptions.ReciprocalMath);1908 1909  if (codegenOpts.getComplexRange() ==1910          CodeGenOptions::ComplexRangeKind::CX_Improved ||1911      codegenOpts.getComplexRange() ==1912          CodeGenOptions::ComplexRangeKind::CX_Basic)1913    loweringOpts.setComplexDivisionToRuntime(false);1914}1915