1480093f4SDimitry Andric //===-- Flang.cpp - Flang+LLVM ToolChain Implementations --------*- C++ -*-===// 2480093f4SDimitry Andric // 3480093f4SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4480093f4SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5480093f4SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6480093f4SDimitry Andric // 7480093f4SDimitry Andric //===----------------------------------------------------------------------===// 8480093f4SDimitry Andric 9480093f4SDimitry Andric 10480093f4SDimitry Andric #include "Flang.h" 11480093f4SDimitry Andric #include "CommonArgs.h" 12480093f4SDimitry Andric 13480093f4SDimitry Andric #include "clang/Driver/Options.h" 14*06c3fb27SDimitry Andric #include "llvm/Frontend/Debug/Options.h" 15480093f4SDimitry Andric 16480093f4SDimitry Andric #include <cassert> 17480093f4SDimitry Andric 18480093f4SDimitry Andric using namespace clang::driver; 19480093f4SDimitry Andric using namespace clang::driver::tools; 20480093f4SDimitry Andric using namespace clang; 21480093f4SDimitry Andric using namespace llvm::opt; 22480093f4SDimitry Andric 2381ad6265SDimitry Andric /// Add -x lang to \p CmdArgs for \p Input. 2481ad6265SDimitry Andric static void addDashXForInput(const ArgList &Args, const InputInfo &Input, 2581ad6265SDimitry Andric ArgStringList &CmdArgs) { 2681ad6265SDimitry Andric CmdArgs.push_back("-x"); 2781ad6265SDimitry Andric // Map the driver type to the frontend type. 2881ad6265SDimitry Andric CmdArgs.push_back(types::getTypeName(Input.getType())); 2981ad6265SDimitry Andric } 3081ad6265SDimitry Andric 31bdd1243dSDimitry Andric void Flang::addFortranDialectOptions(const ArgList &Args, 32fe6060f1SDimitry Andric ArgStringList &CmdArgs) const { 33*06c3fb27SDimitry Andric Args.AddAllArgs(CmdArgs, {options::OPT_ffixed_form, 34*06c3fb27SDimitry Andric options::OPT_ffree_form, 35*06c3fb27SDimitry Andric options::OPT_ffixed_line_length_EQ, 36*06c3fb27SDimitry Andric options::OPT_fopenmp, 37*06c3fb27SDimitry Andric options::OPT_fopenmp_version_EQ, 38*06c3fb27SDimitry Andric options::OPT_fopenacc, 39*06c3fb27SDimitry Andric options::OPT_finput_charset_EQ, 40*06c3fb27SDimitry Andric options::OPT_fimplicit_none, 41*06c3fb27SDimitry Andric options::OPT_fno_implicit_none, 42*06c3fb27SDimitry Andric options::OPT_fbackslash, 43*06c3fb27SDimitry Andric options::OPT_fno_backslash, 44fe6060f1SDimitry Andric options::OPT_flogical_abbreviations, 45fe6060f1SDimitry Andric options::OPT_fno_logical_abbreviations, 46*06c3fb27SDimitry Andric options::OPT_fxor_operator, 47*06c3fb27SDimitry Andric options::OPT_fno_xor_operator, 48fe6060f1SDimitry Andric options::OPT_falternative_parameter_statement, 49*06c3fb27SDimitry Andric options::OPT_fdefault_real_8, 50*06c3fb27SDimitry Andric options::OPT_fdefault_integer_8, 51*06c3fb27SDimitry Andric options::OPT_fdefault_double_8, 52*06c3fb27SDimitry Andric options::OPT_flarge_sizes, 534824e7fdSDimitry Andric options::OPT_fno_automatic}); 54fe6060f1SDimitry Andric } 55fe6060f1SDimitry Andric 56bdd1243dSDimitry Andric void Flang::addPreprocessingOptions(const ArgList &Args, 57e8d8bef9SDimitry Andric ArgStringList &CmdArgs) const { 58349cc55cSDimitry Andric Args.AddAllArgs(CmdArgs, 59349cc55cSDimitry Andric {options::OPT_P, options::OPT_D, options::OPT_U, 60349cc55cSDimitry Andric options::OPT_I, options::OPT_cpp, options::OPT_nocpp}); 61fe6060f1SDimitry Andric } 62fe6060f1SDimitry Andric 63*06c3fb27SDimitry Andric /// @C shouldLoopVersion 64*06c3fb27SDimitry Andric /// 65*06c3fb27SDimitry Andric /// Check if Loop Versioning should be enabled. 66*06c3fb27SDimitry Andric /// We look for the last of one of the following: 67*06c3fb27SDimitry Andric /// -Ofast, -O4, -O<number> and -f[no-]version-loops-for-stride. 68*06c3fb27SDimitry Andric /// Loop versioning is disabled if the last option is 69*06c3fb27SDimitry Andric /// -fno-version-loops-for-stride. 70*06c3fb27SDimitry Andric /// Loop versioning is enabled if the last option is one of: 71*06c3fb27SDimitry Andric /// -floop-versioning 72*06c3fb27SDimitry Andric /// -Ofast 73*06c3fb27SDimitry Andric /// -O4 74*06c3fb27SDimitry Andric /// -O3 75*06c3fb27SDimitry Andric /// For all other cases, loop versioning is is disabled. 76*06c3fb27SDimitry Andric /// 77*06c3fb27SDimitry Andric /// The gfortran compiler automatically enables the option for -O3 or -Ofast. 78*06c3fb27SDimitry Andric /// 79*06c3fb27SDimitry Andric /// @return true if loop-versioning should be enabled, otherwise false. 80*06c3fb27SDimitry Andric static bool shouldLoopVersion(const ArgList &Args) { 81*06c3fb27SDimitry Andric const Arg *LoopVersioningArg = Args.getLastArg( 82*06c3fb27SDimitry Andric options::OPT_Ofast, options::OPT_O, options::OPT_O4, 83*06c3fb27SDimitry Andric options::OPT_floop_versioning, options::OPT_fno_loop_versioning); 84*06c3fb27SDimitry Andric if (!LoopVersioningArg) 85*06c3fb27SDimitry Andric return false; 86*06c3fb27SDimitry Andric 87*06c3fb27SDimitry Andric if (LoopVersioningArg->getOption().matches(options::OPT_fno_loop_versioning)) 88*06c3fb27SDimitry Andric return false; 89*06c3fb27SDimitry Andric 90*06c3fb27SDimitry Andric if (LoopVersioningArg->getOption().matches(options::OPT_floop_versioning)) 91*06c3fb27SDimitry Andric return true; 92*06c3fb27SDimitry Andric 93*06c3fb27SDimitry Andric if (LoopVersioningArg->getOption().matches(options::OPT_Ofast) || 94*06c3fb27SDimitry Andric LoopVersioningArg->getOption().matches(options::OPT_O4)) 95*06c3fb27SDimitry Andric return true; 96*06c3fb27SDimitry Andric 97*06c3fb27SDimitry Andric if (LoopVersioningArg->getOption().matches(options::OPT_O)) { 98*06c3fb27SDimitry Andric StringRef S(LoopVersioningArg->getValue()); 99*06c3fb27SDimitry Andric unsigned OptLevel = 0; 100*06c3fb27SDimitry Andric // Note -Os or Oz woould "fail" here, so return false. Which is the 101*06c3fb27SDimitry Andric // desiered behavior. 102*06c3fb27SDimitry Andric if (S.getAsInteger(10, OptLevel)) 103*06c3fb27SDimitry Andric return false; 104*06c3fb27SDimitry Andric 105*06c3fb27SDimitry Andric return OptLevel > 2; 106*06c3fb27SDimitry Andric } 107*06c3fb27SDimitry Andric 108*06c3fb27SDimitry Andric llvm_unreachable("We should not end up here"); 109*06c3fb27SDimitry Andric return false; 110*06c3fb27SDimitry Andric } 111*06c3fb27SDimitry Andric 112bdd1243dSDimitry Andric void Flang::addOtherOptions(const ArgList &Args, ArgStringList &CmdArgs) const { 113fe6060f1SDimitry Andric Args.AddAllArgs(CmdArgs, 114fe6060f1SDimitry Andric {options::OPT_module_dir, options::OPT_fdebug_module_writer, 115fe6060f1SDimitry Andric options::OPT_fintrinsic_modules_path, options::OPT_pedantic, 116bdd1243dSDimitry Andric options::OPT_std_EQ, options::OPT_W_Joined, 117*06c3fb27SDimitry Andric options::OPT_fconvert_EQ, options::OPT_fpass_plugin_EQ, 118*06c3fb27SDimitry Andric options::OPT_funderscoring, options::OPT_fno_underscoring}); 119*06c3fb27SDimitry Andric 120*06c3fb27SDimitry Andric llvm::codegenoptions::DebugInfoKind DebugInfoKind; 121*06c3fb27SDimitry Andric if (Args.hasArg(options::OPT_gN_Group)) { 122*06c3fb27SDimitry Andric Arg *gNArg = Args.getLastArg(options::OPT_gN_Group); 123*06c3fb27SDimitry Andric DebugInfoKind = debugLevelToInfoKind(*gNArg); 124*06c3fb27SDimitry Andric } else if (Args.hasArg(options::OPT_g_Flag)) { 125*06c3fb27SDimitry Andric DebugInfoKind = llvm::codegenoptions::DebugLineTablesOnly; 126*06c3fb27SDimitry Andric } else { 127*06c3fb27SDimitry Andric DebugInfoKind = llvm::codegenoptions::NoDebugInfo; 128*06c3fb27SDimitry Andric } 129*06c3fb27SDimitry Andric addDebugInfoKind(CmdArgs, DebugInfoKind); 130*06c3fb27SDimitry Andric } 131*06c3fb27SDimitry Andric 132*06c3fb27SDimitry Andric void Flang::addCodegenOptions(const ArgList &Args, 133*06c3fb27SDimitry Andric ArgStringList &CmdArgs) const { 134*06c3fb27SDimitry Andric Arg *stackArrays = 135*06c3fb27SDimitry Andric Args.getLastArg(options::OPT_Ofast, options::OPT_fstack_arrays, 136*06c3fb27SDimitry Andric options::OPT_fno_stack_arrays); 137*06c3fb27SDimitry Andric if (stackArrays && 138*06c3fb27SDimitry Andric !stackArrays->getOption().matches(options::OPT_fno_stack_arrays)) 139*06c3fb27SDimitry Andric CmdArgs.push_back("-fstack-arrays"); 140*06c3fb27SDimitry Andric 141*06c3fb27SDimitry Andric if (Args.hasArg(options::OPT_flang_experimental_hlfir)) 142*06c3fb27SDimitry Andric CmdArgs.push_back("-flang-experimental-hlfir"); 143*06c3fb27SDimitry Andric if (Args.hasArg(options::OPT_flang_experimental_polymorphism)) 144*06c3fb27SDimitry Andric CmdArgs.push_back("-flang-experimental-polymorphism"); 145*06c3fb27SDimitry Andric if (shouldLoopVersion(Args)) 146*06c3fb27SDimitry Andric CmdArgs.push_back("-fversion-loops-for-stride"); 147bdd1243dSDimitry Andric } 148bdd1243dSDimitry Andric 149bdd1243dSDimitry Andric void Flang::addPicOptions(const ArgList &Args, ArgStringList &CmdArgs) const { 150bdd1243dSDimitry Andric // ParsePICArgs parses -fPIC/-fPIE and their variants and returns a tuple of 151bdd1243dSDimitry Andric // (RelocationModel, PICLevel, IsPIE). 152bdd1243dSDimitry Andric llvm::Reloc::Model RelocationModel; 153bdd1243dSDimitry Andric unsigned PICLevel; 154bdd1243dSDimitry Andric bool IsPIE; 155bdd1243dSDimitry Andric std::tie(RelocationModel, PICLevel, IsPIE) = 156bdd1243dSDimitry Andric ParsePICArgs(getToolChain(), Args); 157bdd1243dSDimitry Andric 158bdd1243dSDimitry Andric if (auto *RMName = RelocationModelName(RelocationModel)) { 159bdd1243dSDimitry Andric CmdArgs.push_back("-mrelocation-model"); 160bdd1243dSDimitry Andric CmdArgs.push_back(RMName); 161bdd1243dSDimitry Andric } 162bdd1243dSDimitry Andric if (PICLevel > 0) { 163bdd1243dSDimitry Andric CmdArgs.push_back("-pic-level"); 164bdd1243dSDimitry Andric CmdArgs.push_back(PICLevel == 1 ? "1" : "2"); 165bdd1243dSDimitry Andric if (IsPIE) 166bdd1243dSDimitry Andric CmdArgs.push_back("-pic-is-pie"); 167bdd1243dSDimitry Andric } 168bdd1243dSDimitry Andric } 169bdd1243dSDimitry Andric 170bdd1243dSDimitry Andric void Flang::addTargetOptions(const ArgList &Args, 171bdd1243dSDimitry Andric ArgStringList &CmdArgs) const { 172bdd1243dSDimitry Andric const ToolChain &TC = getToolChain(); 173bdd1243dSDimitry Andric const llvm::Triple &Triple = TC.getEffectiveTriple(); 174bdd1243dSDimitry Andric const Driver &D = TC.getDriver(); 175bdd1243dSDimitry Andric 176bdd1243dSDimitry Andric std::string CPU = getCPUName(D, Args, Triple); 177bdd1243dSDimitry Andric if (!CPU.empty()) { 178bdd1243dSDimitry Andric CmdArgs.push_back("-target-cpu"); 179bdd1243dSDimitry Andric CmdArgs.push_back(Args.MakeArgString(CPU)); 180bdd1243dSDimitry Andric } 181bdd1243dSDimitry Andric 182bdd1243dSDimitry Andric // Add the target features. 183bdd1243dSDimitry Andric switch (TC.getArch()) { 184bdd1243dSDimitry Andric default: 185bdd1243dSDimitry Andric break; 186*06c3fb27SDimitry Andric case llvm::Triple::r600: 187*06c3fb27SDimitry Andric case llvm::Triple::amdgcn: 188bdd1243dSDimitry Andric case llvm::Triple::aarch64: 189*06c3fb27SDimitry Andric case llvm::Triple::riscv64: 190bdd1243dSDimitry Andric case llvm::Triple::x86_64: 191bdd1243dSDimitry Andric getTargetFeatures(D, Triple, Args, CmdArgs, /*ForAs*/ false); 192bdd1243dSDimitry Andric break; 193bdd1243dSDimitry Andric } 194bdd1243dSDimitry Andric 195bdd1243dSDimitry Andric // TODO: Add target specific flags, ABI, mtune option etc. 196bdd1243dSDimitry Andric } 197bdd1243dSDimitry Andric 198*06c3fb27SDimitry Andric void Flang::addOffloadOptions(Compilation &C, const InputInfoList &Inputs, 199*06c3fb27SDimitry Andric const JobAction &JA, const ArgList &Args, 200*06c3fb27SDimitry Andric ArgStringList &CmdArgs) const { 201*06c3fb27SDimitry Andric bool IsOpenMPDevice = JA.isDeviceOffloading(Action::OFK_OpenMP); 202*06c3fb27SDimitry Andric bool IsHostOffloadingAction = JA.isHostOffloading(Action::OFK_OpenMP) || 203*06c3fb27SDimitry Andric JA.isHostOffloading(C.getActiveOffloadKinds()); 204*06c3fb27SDimitry Andric 205*06c3fb27SDimitry Andric // Skips the primary input file, which is the input file that the compilation 206*06c3fb27SDimitry Andric // proccess will be executed upon (e.g. the host bitcode file) and 207*06c3fb27SDimitry Andric // adds other secondary input (e.g. device bitcode files for embedding to the 208*06c3fb27SDimitry Andric // -fembed-offload-object argument or the host IR file for proccessing 209*06c3fb27SDimitry Andric // during device compilation to the fopenmp-host-ir-file-path argument via 210*06c3fb27SDimitry Andric // OpenMPDeviceInput). This is condensed logic from the ConstructJob 211*06c3fb27SDimitry Andric // function inside of the Clang driver for pushing on further input arguments 212*06c3fb27SDimitry Andric // needed for offloading during various phases of compilation. 213*06c3fb27SDimitry Andric for (size_t i = 1; i < Inputs.size(); ++i) { 214*06c3fb27SDimitry Andric if (Inputs[i].getType() == types::TY_Nothing) { 215*06c3fb27SDimitry Andric // contains nothing, so it's skippable 216*06c3fb27SDimitry Andric } else if (IsHostOffloadingAction) { 217*06c3fb27SDimitry Andric CmdArgs.push_back( 218*06c3fb27SDimitry Andric Args.MakeArgString("-fembed-offload-object=" + 219*06c3fb27SDimitry Andric getToolChain().getInputFilename(Inputs[i]))); 220*06c3fb27SDimitry Andric } else if (IsOpenMPDevice) { 221*06c3fb27SDimitry Andric if (Inputs[i].getFilename()) { 222*06c3fb27SDimitry Andric CmdArgs.push_back("-fopenmp-host-ir-file-path"); 223*06c3fb27SDimitry Andric CmdArgs.push_back(Args.MakeArgString(Inputs[i].getFilename())); 224*06c3fb27SDimitry Andric } else { 225*06c3fb27SDimitry Andric llvm_unreachable("missing openmp host-ir file for device offloading"); 226*06c3fb27SDimitry Andric } 227*06c3fb27SDimitry Andric } else { 228*06c3fb27SDimitry Andric llvm_unreachable( 229*06c3fb27SDimitry Andric "unexpectedly given multiple inputs or given unknown input"); 230*06c3fb27SDimitry Andric } 231*06c3fb27SDimitry Andric } 232*06c3fb27SDimitry Andric 233*06c3fb27SDimitry Andric if (IsOpenMPDevice) { 234*06c3fb27SDimitry Andric // -fopenmp-is-target-device is passed along to tell the frontend that it is 235*06c3fb27SDimitry Andric // generating code for a device, so that only the relevant code is emitted. 236*06c3fb27SDimitry Andric CmdArgs.push_back("-fopenmp-is-target-device"); 237*06c3fb27SDimitry Andric 238*06c3fb27SDimitry Andric // When in OpenMP offloading mode, enable debugging on the device. 239*06c3fb27SDimitry Andric Args.AddAllArgs(CmdArgs, options::OPT_fopenmp_target_debug_EQ); 240*06c3fb27SDimitry Andric if (Args.hasFlag(options::OPT_fopenmp_target_debug, 241*06c3fb27SDimitry Andric options::OPT_fno_openmp_target_debug, /*Default=*/false)) 242*06c3fb27SDimitry Andric CmdArgs.push_back("-fopenmp-target-debug"); 243*06c3fb27SDimitry Andric 244*06c3fb27SDimitry Andric // When in OpenMP offloading mode, forward assumptions information about 245*06c3fb27SDimitry Andric // thread and team counts in the device. 246*06c3fb27SDimitry Andric if (Args.hasFlag(options::OPT_fopenmp_assume_teams_oversubscription, 247*06c3fb27SDimitry Andric options::OPT_fno_openmp_assume_teams_oversubscription, 248*06c3fb27SDimitry Andric /*Default=*/false)) 249*06c3fb27SDimitry Andric CmdArgs.push_back("-fopenmp-assume-teams-oversubscription"); 250*06c3fb27SDimitry Andric if (Args.hasFlag(options::OPT_fopenmp_assume_threads_oversubscription, 251*06c3fb27SDimitry Andric options::OPT_fno_openmp_assume_threads_oversubscription, 252*06c3fb27SDimitry Andric /*Default=*/false)) 253*06c3fb27SDimitry Andric CmdArgs.push_back("-fopenmp-assume-threads-oversubscription"); 254*06c3fb27SDimitry Andric if (Args.hasArg(options::OPT_fopenmp_assume_no_thread_state)) 255*06c3fb27SDimitry Andric CmdArgs.push_back("-fopenmp-assume-no-thread-state"); 256*06c3fb27SDimitry Andric if (Args.hasArg(options::OPT_fopenmp_assume_no_nested_parallelism)) 257*06c3fb27SDimitry Andric CmdArgs.push_back("-fopenmp-assume-no-nested-parallelism"); 258*06c3fb27SDimitry Andric } 259*06c3fb27SDimitry Andric } 260*06c3fb27SDimitry Andric 261bdd1243dSDimitry Andric static void addFloatingPointOptions(const Driver &D, const ArgList &Args, 262bdd1243dSDimitry Andric ArgStringList &CmdArgs) { 263bdd1243dSDimitry Andric StringRef FPContract; 264bdd1243dSDimitry Andric bool HonorINFs = true; 265bdd1243dSDimitry Andric bool HonorNaNs = true; 266bdd1243dSDimitry Andric bool ApproxFunc = false; 267bdd1243dSDimitry Andric bool SignedZeros = true; 268bdd1243dSDimitry Andric bool AssociativeMath = false; 269bdd1243dSDimitry Andric bool ReciprocalMath = false; 270bdd1243dSDimitry Andric 271bdd1243dSDimitry Andric if (const Arg *A = Args.getLastArg(options::OPT_ffp_contract)) { 272bdd1243dSDimitry Andric const StringRef Val = A->getValue(); 273bdd1243dSDimitry Andric if (Val == "fast" || Val == "off") { 274bdd1243dSDimitry Andric FPContract = Val; 275bdd1243dSDimitry Andric } else if (Val == "on") { 276bdd1243dSDimitry Andric // Warn instead of error because users might have makefiles written for 277bdd1243dSDimitry Andric // gfortran (which accepts -ffp-contract=on) 278bdd1243dSDimitry Andric D.Diag(diag::warn_drv_unsupported_option_for_flang) 279bdd1243dSDimitry Andric << Val << A->getOption().getName() << "off"; 280bdd1243dSDimitry Andric FPContract = "off"; 281bdd1243dSDimitry Andric } else 282bdd1243dSDimitry Andric // Clang's "fast-honor-pragmas" option is not supported because it is 283bdd1243dSDimitry Andric // non-standard 284bdd1243dSDimitry Andric D.Diag(diag::err_drv_unsupported_option_argument) 285bdd1243dSDimitry Andric << A->getSpelling() << Val; 286bdd1243dSDimitry Andric } 287bdd1243dSDimitry Andric 288bdd1243dSDimitry Andric for (const Arg *A : Args) { 289bdd1243dSDimitry Andric auto optId = A->getOption().getID(); 290bdd1243dSDimitry Andric switch (optId) { 291bdd1243dSDimitry Andric // if this isn't an FP option, skip the claim below 292bdd1243dSDimitry Andric default: 293bdd1243dSDimitry Andric continue; 294bdd1243dSDimitry Andric 295bdd1243dSDimitry Andric case options::OPT_fhonor_infinities: 296bdd1243dSDimitry Andric HonorINFs = true; 297bdd1243dSDimitry Andric break; 298bdd1243dSDimitry Andric case options::OPT_fno_honor_infinities: 299bdd1243dSDimitry Andric HonorINFs = false; 300bdd1243dSDimitry Andric break; 301bdd1243dSDimitry Andric case options::OPT_fhonor_nans: 302bdd1243dSDimitry Andric HonorNaNs = true; 303bdd1243dSDimitry Andric break; 304bdd1243dSDimitry Andric case options::OPT_fno_honor_nans: 305bdd1243dSDimitry Andric HonorNaNs = false; 306bdd1243dSDimitry Andric break; 307bdd1243dSDimitry Andric case options::OPT_fapprox_func: 308bdd1243dSDimitry Andric ApproxFunc = true; 309bdd1243dSDimitry Andric break; 310bdd1243dSDimitry Andric case options::OPT_fno_approx_func: 311bdd1243dSDimitry Andric ApproxFunc = false; 312bdd1243dSDimitry Andric break; 313bdd1243dSDimitry Andric case options::OPT_fsigned_zeros: 314bdd1243dSDimitry Andric SignedZeros = true; 315bdd1243dSDimitry Andric break; 316bdd1243dSDimitry Andric case options::OPT_fno_signed_zeros: 317bdd1243dSDimitry Andric SignedZeros = false; 318bdd1243dSDimitry Andric break; 319bdd1243dSDimitry Andric case options::OPT_fassociative_math: 320bdd1243dSDimitry Andric AssociativeMath = true; 321bdd1243dSDimitry Andric break; 322bdd1243dSDimitry Andric case options::OPT_fno_associative_math: 323bdd1243dSDimitry Andric AssociativeMath = false; 324bdd1243dSDimitry Andric break; 325bdd1243dSDimitry Andric case options::OPT_freciprocal_math: 326bdd1243dSDimitry Andric ReciprocalMath = true; 327bdd1243dSDimitry Andric break; 328bdd1243dSDimitry Andric case options::OPT_fno_reciprocal_math: 329bdd1243dSDimitry Andric ReciprocalMath = false; 330bdd1243dSDimitry Andric break; 331bdd1243dSDimitry Andric case options::OPT_Ofast: 332bdd1243dSDimitry Andric [[fallthrough]]; 333bdd1243dSDimitry Andric case options::OPT_ffast_math: 334bdd1243dSDimitry Andric HonorINFs = false; 335bdd1243dSDimitry Andric HonorNaNs = false; 336bdd1243dSDimitry Andric AssociativeMath = true; 337bdd1243dSDimitry Andric ReciprocalMath = true; 338bdd1243dSDimitry Andric ApproxFunc = true; 339bdd1243dSDimitry Andric SignedZeros = false; 340bdd1243dSDimitry Andric FPContract = "fast"; 341bdd1243dSDimitry Andric break; 342bdd1243dSDimitry Andric case options::OPT_fno_fast_math: 343bdd1243dSDimitry Andric HonorINFs = true; 344bdd1243dSDimitry Andric HonorNaNs = true; 345bdd1243dSDimitry Andric AssociativeMath = false; 346bdd1243dSDimitry Andric ReciprocalMath = false; 347bdd1243dSDimitry Andric ApproxFunc = false; 348bdd1243dSDimitry Andric SignedZeros = true; 349bdd1243dSDimitry Andric // -fno-fast-math should undo -ffast-math so I return FPContract to the 350bdd1243dSDimitry Andric // default. It is important to check it is "fast" (the default) so that 351bdd1243dSDimitry Andric // --ffp-contract=off -fno-fast-math --> -ffp-contract=off 352bdd1243dSDimitry Andric if (FPContract == "fast") 353bdd1243dSDimitry Andric FPContract = ""; 354bdd1243dSDimitry Andric break; 355bdd1243dSDimitry Andric } 356bdd1243dSDimitry Andric 357bdd1243dSDimitry Andric // If we handled this option claim it 358bdd1243dSDimitry Andric A->claim(); 359bdd1243dSDimitry Andric } 360bdd1243dSDimitry Andric 361bdd1243dSDimitry Andric if (!HonorINFs && !HonorNaNs && AssociativeMath && ReciprocalMath && 362bdd1243dSDimitry Andric ApproxFunc && !SignedZeros && 363bdd1243dSDimitry Andric (FPContract == "fast" || FPContract == "")) { 364bdd1243dSDimitry Andric CmdArgs.push_back("-ffast-math"); 365bdd1243dSDimitry Andric return; 366bdd1243dSDimitry Andric } 367bdd1243dSDimitry Andric 368bdd1243dSDimitry Andric if (!FPContract.empty()) 369bdd1243dSDimitry Andric CmdArgs.push_back(Args.MakeArgString("-ffp-contract=" + FPContract)); 370bdd1243dSDimitry Andric 371bdd1243dSDimitry Andric if (!HonorINFs) 372bdd1243dSDimitry Andric CmdArgs.push_back("-menable-no-infs"); 373bdd1243dSDimitry Andric 374bdd1243dSDimitry Andric if (!HonorNaNs) 375bdd1243dSDimitry Andric CmdArgs.push_back("-menable-no-nans"); 376bdd1243dSDimitry Andric 377bdd1243dSDimitry Andric if (ApproxFunc) 378bdd1243dSDimitry Andric CmdArgs.push_back("-fapprox-func"); 379bdd1243dSDimitry Andric 380bdd1243dSDimitry Andric if (!SignedZeros) 381bdd1243dSDimitry Andric CmdArgs.push_back("-fno-signed-zeros"); 382bdd1243dSDimitry Andric 383bdd1243dSDimitry Andric if (AssociativeMath && !SignedZeros) 384bdd1243dSDimitry Andric CmdArgs.push_back("-mreassociate"); 385bdd1243dSDimitry Andric 386bdd1243dSDimitry Andric if (ReciprocalMath) 387bdd1243dSDimitry Andric CmdArgs.push_back("-freciprocal-math"); 388e8d8bef9SDimitry Andric } 389e8d8bef9SDimitry Andric 390480093f4SDimitry Andric void Flang::ConstructJob(Compilation &C, const JobAction &JA, 391480093f4SDimitry Andric const InputInfo &Output, const InputInfoList &Inputs, 392480093f4SDimitry Andric const ArgList &Args, const char *LinkingOutput) const { 393480093f4SDimitry Andric const auto &TC = getToolChain(); 39481ad6265SDimitry Andric const llvm::Triple &Triple = TC.getEffectiveTriple(); 39581ad6265SDimitry Andric const std::string &TripleStr = Triple.getTriple(); 396480093f4SDimitry Andric 39781ad6265SDimitry Andric const Driver &D = TC.getDriver(); 398480093f4SDimitry Andric ArgStringList CmdArgs; 399*06c3fb27SDimitry Andric DiagnosticsEngine &Diags = D.getDiags(); 400480093f4SDimitry Andric 401e8d8bef9SDimitry Andric // Invoke ourselves in -fc1 mode. 402480093f4SDimitry Andric CmdArgs.push_back("-fc1"); 403480093f4SDimitry Andric 404e8d8bef9SDimitry Andric // Add the "effective" target triple. 40581ad6265SDimitry Andric CmdArgs.push_back("-triple"); 40681ad6265SDimitry Andric CmdArgs.push_back(Args.MakeArgString(TripleStr)); 407480093f4SDimitry Andric 408480093f4SDimitry Andric if (isa<PreprocessJobAction>(JA)) { 409480093f4SDimitry Andric CmdArgs.push_back("-E"); 410480093f4SDimitry Andric } else if (isa<CompileJobAction>(JA) || isa<BackendJobAction>(JA)) { 411480093f4SDimitry Andric if (JA.getType() == types::TY_Nothing) { 412480093f4SDimitry Andric CmdArgs.push_back("-fsyntax-only"); 413480093f4SDimitry Andric } else if (JA.getType() == types::TY_AST) { 414480093f4SDimitry Andric CmdArgs.push_back("-emit-ast"); 415480093f4SDimitry Andric } else if (JA.getType() == types::TY_LLVM_IR || 416480093f4SDimitry Andric JA.getType() == types::TY_LTO_IR) { 417480093f4SDimitry Andric CmdArgs.push_back("-emit-llvm"); 418480093f4SDimitry Andric } else if (JA.getType() == types::TY_LLVM_BC || 419480093f4SDimitry Andric JA.getType() == types::TY_LTO_BC) { 420480093f4SDimitry Andric CmdArgs.push_back("-emit-llvm-bc"); 421480093f4SDimitry Andric } else if (JA.getType() == types::TY_PP_Asm) { 422480093f4SDimitry Andric CmdArgs.push_back("-S"); 423480093f4SDimitry Andric } else { 424480093f4SDimitry Andric assert(false && "Unexpected output type!"); 425480093f4SDimitry Andric } 426480093f4SDimitry Andric } else if (isa<AssembleJobAction>(JA)) { 427480093f4SDimitry Andric CmdArgs.push_back("-emit-obj"); 428480093f4SDimitry Andric } else { 429480093f4SDimitry Andric assert(false && "Unexpected action class for Flang tool."); 430480093f4SDimitry Andric } 431480093f4SDimitry Andric 432e8d8bef9SDimitry Andric const InputInfo &Input = Inputs[0]; 433e8d8bef9SDimitry Andric types::ID InputType = Input.getType(); 434e8d8bef9SDimitry Andric 435e8d8bef9SDimitry Andric // Add preprocessing options like -I, -D, etc. if we are using the 436e8d8bef9SDimitry Andric // preprocessor (i.e. skip when dealing with e.g. binary files). 437e8d8bef9SDimitry Andric if (types::getPreprocessedType(InputType) != types::TY_INVALID) 438bdd1243dSDimitry Andric addPreprocessingOptions(Args, CmdArgs); 439e8d8bef9SDimitry Andric 440bdd1243dSDimitry Andric addFortranDialectOptions(Args, CmdArgs); 441fe6060f1SDimitry Andric 44281ad6265SDimitry Andric // Color diagnostics are parsed by the driver directly from argv and later 44381ad6265SDimitry Andric // re-parsed to construct this job; claim any possible color diagnostic here 44481ad6265SDimitry Andric // to avoid warn_drv_unused_argument. 44581ad6265SDimitry Andric Args.getLastArg(options::OPT_fcolor_diagnostics, 44681ad6265SDimitry Andric options::OPT_fno_color_diagnostics); 447*06c3fb27SDimitry Andric if (Diags.getDiagnosticOptions().ShowColors) 44881ad6265SDimitry Andric CmdArgs.push_back("-fcolor-diagnostics"); 44981ad6265SDimitry Andric 450*06c3fb27SDimitry Andric // LTO mode is parsed by the Clang driver library. 451*06c3fb27SDimitry Andric LTOKind LTOMode = D.getLTOMode(/* IsOffload */ false); 452*06c3fb27SDimitry Andric assert(LTOMode != LTOK_Unknown && "Unknown LTO mode."); 453*06c3fb27SDimitry Andric if (LTOMode == LTOK_Full) 454*06c3fb27SDimitry Andric CmdArgs.push_back("-flto=full"); 455*06c3fb27SDimitry Andric else if (LTOMode == LTOK_Thin) { 456*06c3fb27SDimitry Andric Diags.Report( 457*06c3fb27SDimitry Andric Diags.getCustomDiagID(DiagnosticsEngine::Warning, 458*06c3fb27SDimitry Andric "the option '-flto=thin' is a work in progress")); 459*06c3fb27SDimitry Andric CmdArgs.push_back("-flto=thin"); 460*06c3fb27SDimitry Andric } 461*06c3fb27SDimitry Andric 462bdd1243dSDimitry Andric // -fPIC and related options. 463bdd1243dSDimitry Andric addPicOptions(Args, CmdArgs); 464bdd1243dSDimitry Andric 465bdd1243dSDimitry Andric // Floating point related options 466bdd1243dSDimitry Andric addFloatingPointOptions(D, Args, CmdArgs); 467bdd1243dSDimitry Andric 468bdd1243dSDimitry Andric // Add target args, features, etc. 469bdd1243dSDimitry Andric addTargetOptions(Args, CmdArgs); 470bdd1243dSDimitry Andric 471*06c3fb27SDimitry Andric // Add Codegen options 472*06c3fb27SDimitry Andric addCodegenOptions(Args, CmdArgs); 473*06c3fb27SDimitry Andric 474fe6060f1SDimitry Andric // Add other compile options 475bdd1243dSDimitry Andric addOtherOptions(Args, CmdArgs); 476fe6060f1SDimitry Andric 477*06c3fb27SDimitry Andric // Offloading related options 478*06c3fb27SDimitry Andric addOffloadOptions(C, Inputs, JA, Args, CmdArgs); 479*06c3fb27SDimitry Andric 480fe6060f1SDimitry Andric // Forward -Xflang arguments to -fc1 481fe6060f1SDimitry Andric Args.AddAllArgValues(CmdArgs, options::OPT_Xflang); 482fe6060f1SDimitry Andric 48381ad6265SDimitry Andric // Forward -mllvm options to the LLVM option parser. In practice, this means 48481ad6265SDimitry Andric // forwarding to `-fc1` as that's where the LLVM parser is run. 48581ad6265SDimitry Andric for (const Arg *A : Args.filtered(options::OPT_mllvm)) { 48681ad6265SDimitry Andric A->claim(); 48781ad6265SDimitry Andric A->render(Args, CmdArgs); 48881ad6265SDimitry Andric } 48981ad6265SDimitry Andric 49081ad6265SDimitry Andric for (const Arg *A : Args.filtered(options::OPT_mmlir)) { 49181ad6265SDimitry Andric A->claim(); 49281ad6265SDimitry Andric A->render(Args, CmdArgs); 49381ad6265SDimitry Andric } 49481ad6265SDimitry Andric 495*06c3fb27SDimitry Andric // Remove any unsupported gfortran diagnostic options 496*06c3fb27SDimitry Andric for (const Arg *A : Args.filtered(options::OPT_flang_ignored_w_Group)) { 497*06c3fb27SDimitry Andric A->claim(); 498*06c3fb27SDimitry Andric D.Diag(diag::warn_drv_unsupported_diag_option_for_flang) 499*06c3fb27SDimitry Andric << A->getOption().getName(); 500*06c3fb27SDimitry Andric } 501*06c3fb27SDimitry Andric 50281ad6265SDimitry Andric // Optimization level for CodeGen. 50381ad6265SDimitry Andric if (const Arg *A = Args.getLastArg(options::OPT_O_Group)) { 50481ad6265SDimitry Andric if (A->getOption().matches(options::OPT_O4)) { 50581ad6265SDimitry Andric CmdArgs.push_back("-O3"); 50681ad6265SDimitry Andric D.Diag(diag::warn_O4_is_O3); 507bdd1243dSDimitry Andric } else if (A->getOption().matches(options::OPT_Ofast)) { 508bdd1243dSDimitry Andric CmdArgs.push_back("-O3"); 50981ad6265SDimitry Andric } else { 51081ad6265SDimitry Andric A->render(Args, CmdArgs); 51181ad6265SDimitry Andric } 51281ad6265SDimitry Andric } 51381ad6265SDimitry Andric 514480093f4SDimitry Andric if (Output.isFilename()) { 515480093f4SDimitry Andric CmdArgs.push_back("-o"); 516480093f4SDimitry Andric CmdArgs.push_back(Output.getFilename()); 517480093f4SDimitry Andric } else { 518480093f4SDimitry Andric assert(Output.isNothing() && "Invalid output."); 519480093f4SDimitry Andric } 520480093f4SDimitry Andric 521480093f4SDimitry Andric assert(Input.isFilename() && "Invalid input."); 52281ad6265SDimitry Andric 523*06c3fb27SDimitry Andric if (Args.getLastArg(options::OPT_save_temps_EQ)) 524*06c3fb27SDimitry Andric Args.AddLastArg(CmdArgs, options::OPT_save_temps_EQ); 525*06c3fb27SDimitry Andric 52681ad6265SDimitry Andric addDashXForInput(Args, Input, CmdArgs); 52781ad6265SDimitry Andric 528480093f4SDimitry Andric CmdArgs.push_back(Input.getFilename()); 529480093f4SDimitry Andric 530e8d8bef9SDimitry Andric // TODO: Replace flang-new with flang once the new driver replaces the 531e8d8bef9SDimitry Andric // throwaway driver 532e8d8bef9SDimitry Andric const char *Exec = Args.MakeArgString(D.GetProgramPath("flang-new", TC)); 533e8d8bef9SDimitry Andric C.addCommand(std::make_unique<Command>(JA, *this, 534e8d8bef9SDimitry Andric ResponseFileSupport::AtFileUTF8(), 535e8d8bef9SDimitry Andric Exec, CmdArgs, Inputs, Output)); 536480093f4SDimitry Andric } 537480093f4SDimitry Andric 538e8d8bef9SDimitry Andric Flang::Flang(const ToolChain &TC) : Tool("flang-new", "flang frontend", TC) {} 539480093f4SDimitry Andric 540480093f4SDimitry Andric Flang::~Flang() {} 541