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