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 #include "Flang.h" 10297eecfbSDimitry Andric #include "Arch/RISCV.h" 11480093f4SDimitry Andric #include "CommonArgs.h" 12480093f4SDimitry Andric 135f757f3fSDimitry Andric #include "clang/Basic/CodeGenOptions.h" 14480093f4SDimitry Andric #include "clang/Driver/Options.h" 1506c3fb27SDimitry Andric #include "llvm/Frontend/Debug/Options.h" 165f757f3fSDimitry Andric #include "llvm/Support/FileSystem.h" 175f757f3fSDimitry Andric #include "llvm/Support/Path.h" 18*0fca6ea1SDimitry Andric #include "llvm/TargetParser/Host.h" 19*0fca6ea1SDimitry Andric #include "llvm/TargetParser/RISCVISAInfo.h" 20297eecfbSDimitry Andric #include "llvm/TargetParser/RISCVTargetParser.h" 21480093f4SDimitry Andric 22480093f4SDimitry Andric #include <cassert> 23480093f4SDimitry Andric 24480093f4SDimitry Andric using namespace clang::driver; 25480093f4SDimitry Andric using namespace clang::driver::tools; 26480093f4SDimitry Andric using namespace clang; 27480093f4SDimitry Andric using namespace llvm::opt; 28480093f4SDimitry Andric 2981ad6265SDimitry Andric /// Add -x lang to \p CmdArgs for \p Input. 3081ad6265SDimitry Andric static void addDashXForInput(const ArgList &Args, const InputInfo &Input, 3181ad6265SDimitry Andric ArgStringList &CmdArgs) { 3281ad6265SDimitry Andric CmdArgs.push_back("-x"); 3381ad6265SDimitry Andric // Map the driver type to the frontend type. 3481ad6265SDimitry Andric CmdArgs.push_back(types::getTypeName(Input.getType())); 3581ad6265SDimitry Andric } 3681ad6265SDimitry Andric 37bdd1243dSDimitry Andric void Flang::addFortranDialectOptions(const ArgList &Args, 38fe6060f1SDimitry Andric ArgStringList &CmdArgs) const { 395f757f3fSDimitry Andric Args.addAllArgs(CmdArgs, {options::OPT_ffixed_form, 4006c3fb27SDimitry Andric options::OPT_ffree_form, 4106c3fb27SDimitry Andric options::OPT_ffixed_line_length_EQ, 4206c3fb27SDimitry Andric options::OPT_fopenacc, 4306c3fb27SDimitry Andric options::OPT_finput_charset_EQ, 4406c3fb27SDimitry Andric options::OPT_fimplicit_none, 4506c3fb27SDimitry Andric options::OPT_fno_implicit_none, 4606c3fb27SDimitry Andric options::OPT_fbackslash, 4706c3fb27SDimitry Andric options::OPT_fno_backslash, 48fe6060f1SDimitry Andric options::OPT_flogical_abbreviations, 49fe6060f1SDimitry Andric options::OPT_fno_logical_abbreviations, 5006c3fb27SDimitry Andric options::OPT_fxor_operator, 5106c3fb27SDimitry Andric options::OPT_fno_xor_operator, 52fe6060f1SDimitry Andric options::OPT_falternative_parameter_statement, 5306c3fb27SDimitry Andric options::OPT_fdefault_real_8, 5406c3fb27SDimitry Andric options::OPT_fdefault_integer_8, 5506c3fb27SDimitry Andric options::OPT_fdefault_double_8, 5606c3fb27SDimitry Andric options::OPT_flarge_sizes, 57*0fca6ea1SDimitry Andric options::OPT_fno_automatic, 58*0fca6ea1SDimitry Andric options::OPT_fhermetic_module_files}); 59fe6060f1SDimitry Andric } 60fe6060f1SDimitry Andric 61bdd1243dSDimitry Andric void Flang::addPreprocessingOptions(const ArgList &Args, 62e8d8bef9SDimitry Andric ArgStringList &CmdArgs) const { 635f757f3fSDimitry Andric Args.addAllArgs(CmdArgs, 64349cc55cSDimitry Andric {options::OPT_P, options::OPT_D, options::OPT_U, 65349cc55cSDimitry Andric options::OPT_I, options::OPT_cpp, options::OPT_nocpp}); 66fe6060f1SDimitry Andric } 67fe6060f1SDimitry Andric 6806c3fb27SDimitry Andric /// @C shouldLoopVersion 6906c3fb27SDimitry Andric /// 7006c3fb27SDimitry Andric /// Check if Loop Versioning should be enabled. 7106c3fb27SDimitry Andric /// We look for the last of one of the following: 7206c3fb27SDimitry Andric /// -Ofast, -O4, -O<number> and -f[no-]version-loops-for-stride. 7306c3fb27SDimitry Andric /// Loop versioning is disabled if the last option is 7406c3fb27SDimitry Andric /// -fno-version-loops-for-stride. 7506c3fb27SDimitry Andric /// Loop versioning is enabled if the last option is one of: 7606c3fb27SDimitry Andric /// -floop-versioning 7706c3fb27SDimitry Andric /// -Ofast 7806c3fb27SDimitry Andric /// -O4 7906c3fb27SDimitry Andric /// -O3 8006c3fb27SDimitry Andric /// For all other cases, loop versioning is is disabled. 8106c3fb27SDimitry Andric /// 8206c3fb27SDimitry Andric /// The gfortran compiler automatically enables the option for -O3 or -Ofast. 8306c3fb27SDimitry Andric /// 8406c3fb27SDimitry Andric /// @return true if loop-versioning should be enabled, otherwise false. 8506c3fb27SDimitry Andric static bool shouldLoopVersion(const ArgList &Args) { 8606c3fb27SDimitry Andric const Arg *LoopVersioningArg = Args.getLastArg( 8706c3fb27SDimitry Andric options::OPT_Ofast, options::OPT_O, options::OPT_O4, 8806c3fb27SDimitry Andric options::OPT_floop_versioning, options::OPT_fno_loop_versioning); 8906c3fb27SDimitry Andric if (!LoopVersioningArg) 9006c3fb27SDimitry Andric return false; 9106c3fb27SDimitry Andric 9206c3fb27SDimitry Andric if (LoopVersioningArg->getOption().matches(options::OPT_fno_loop_versioning)) 9306c3fb27SDimitry Andric return false; 9406c3fb27SDimitry Andric 9506c3fb27SDimitry Andric if (LoopVersioningArg->getOption().matches(options::OPT_floop_versioning)) 9606c3fb27SDimitry Andric return true; 9706c3fb27SDimitry Andric 9806c3fb27SDimitry Andric if (LoopVersioningArg->getOption().matches(options::OPT_Ofast) || 9906c3fb27SDimitry Andric LoopVersioningArg->getOption().matches(options::OPT_O4)) 10006c3fb27SDimitry Andric return true; 10106c3fb27SDimitry Andric 10206c3fb27SDimitry Andric if (LoopVersioningArg->getOption().matches(options::OPT_O)) { 10306c3fb27SDimitry Andric StringRef S(LoopVersioningArg->getValue()); 10406c3fb27SDimitry Andric unsigned OptLevel = 0; 10506c3fb27SDimitry Andric // Note -Os or Oz woould "fail" here, so return false. Which is the 10606c3fb27SDimitry Andric // desiered behavior. 10706c3fb27SDimitry Andric if (S.getAsInteger(10, OptLevel)) 10806c3fb27SDimitry Andric return false; 10906c3fb27SDimitry Andric 11006c3fb27SDimitry Andric return OptLevel > 2; 11106c3fb27SDimitry Andric } 11206c3fb27SDimitry Andric 11306c3fb27SDimitry Andric llvm_unreachable("We should not end up here"); 11406c3fb27SDimitry Andric return false; 11506c3fb27SDimitry Andric } 11606c3fb27SDimitry Andric 117bdd1243dSDimitry Andric void Flang::addOtherOptions(const ArgList &Args, ArgStringList &CmdArgs) const { 1185f757f3fSDimitry Andric Args.addAllArgs(CmdArgs, 119fe6060f1SDimitry Andric {options::OPT_module_dir, options::OPT_fdebug_module_writer, 120fe6060f1SDimitry Andric options::OPT_fintrinsic_modules_path, options::OPT_pedantic, 121bdd1243dSDimitry Andric options::OPT_std_EQ, options::OPT_W_Joined, 12206c3fb27SDimitry Andric options::OPT_fconvert_EQ, options::OPT_fpass_plugin_EQ, 12306c3fb27SDimitry Andric options::OPT_funderscoring, options::OPT_fno_underscoring}); 12406c3fb27SDimitry Andric 12506c3fb27SDimitry Andric llvm::codegenoptions::DebugInfoKind DebugInfoKind; 12606c3fb27SDimitry Andric if (Args.hasArg(options::OPT_gN_Group)) { 12706c3fb27SDimitry Andric Arg *gNArg = Args.getLastArg(options::OPT_gN_Group); 12806c3fb27SDimitry Andric DebugInfoKind = debugLevelToInfoKind(*gNArg); 12906c3fb27SDimitry Andric } else if (Args.hasArg(options::OPT_g_Flag)) { 130*0fca6ea1SDimitry Andric DebugInfoKind = llvm::codegenoptions::FullDebugInfo; 13106c3fb27SDimitry Andric } else { 13206c3fb27SDimitry Andric DebugInfoKind = llvm::codegenoptions::NoDebugInfo; 13306c3fb27SDimitry Andric } 13406c3fb27SDimitry Andric addDebugInfoKind(CmdArgs, DebugInfoKind); 13506c3fb27SDimitry Andric } 13606c3fb27SDimitry Andric 13706c3fb27SDimitry Andric void Flang::addCodegenOptions(const ArgList &Args, 13806c3fb27SDimitry Andric ArgStringList &CmdArgs) const { 13906c3fb27SDimitry Andric Arg *stackArrays = 14006c3fb27SDimitry Andric Args.getLastArg(options::OPT_Ofast, options::OPT_fstack_arrays, 14106c3fb27SDimitry Andric options::OPT_fno_stack_arrays); 14206c3fb27SDimitry Andric if (stackArrays && 14306c3fb27SDimitry Andric !stackArrays->getOption().matches(options::OPT_fno_stack_arrays)) 14406c3fb27SDimitry Andric CmdArgs.push_back("-fstack-arrays"); 14506c3fb27SDimitry Andric 14606c3fb27SDimitry Andric if (shouldLoopVersion(Args)) 14706c3fb27SDimitry Andric CmdArgs.push_back("-fversion-loops-for-stride"); 1485f757f3fSDimitry Andric 1495f757f3fSDimitry Andric Args.addAllArgs(CmdArgs, {options::OPT_flang_experimental_hlfir, 1505f757f3fSDimitry Andric options::OPT_flang_deprecated_no_hlfir, 151*0fca6ea1SDimitry Andric options::OPT_flang_experimental_integer_overflow, 1525f757f3fSDimitry Andric options::OPT_fno_ppc_native_vec_elem_order, 1535f757f3fSDimitry Andric options::OPT_fppc_native_vec_elem_order}); 154bdd1243dSDimitry Andric } 155bdd1243dSDimitry Andric 156bdd1243dSDimitry Andric void Flang::addPicOptions(const ArgList &Args, ArgStringList &CmdArgs) const { 157bdd1243dSDimitry Andric // ParsePICArgs parses -fPIC/-fPIE and their variants and returns a tuple of 158bdd1243dSDimitry Andric // (RelocationModel, PICLevel, IsPIE). 159bdd1243dSDimitry Andric llvm::Reloc::Model RelocationModel; 160bdd1243dSDimitry Andric unsigned PICLevel; 161bdd1243dSDimitry Andric bool IsPIE; 162bdd1243dSDimitry Andric std::tie(RelocationModel, PICLevel, IsPIE) = 163bdd1243dSDimitry Andric ParsePICArgs(getToolChain(), Args); 164bdd1243dSDimitry Andric 165bdd1243dSDimitry Andric if (auto *RMName = RelocationModelName(RelocationModel)) { 166bdd1243dSDimitry Andric CmdArgs.push_back("-mrelocation-model"); 167bdd1243dSDimitry Andric CmdArgs.push_back(RMName); 168bdd1243dSDimitry Andric } 169bdd1243dSDimitry Andric if (PICLevel > 0) { 170bdd1243dSDimitry Andric CmdArgs.push_back("-pic-level"); 171bdd1243dSDimitry Andric CmdArgs.push_back(PICLevel == 1 ? "1" : "2"); 172bdd1243dSDimitry Andric if (IsPIE) 173bdd1243dSDimitry Andric CmdArgs.push_back("-pic-is-pie"); 174bdd1243dSDimitry Andric } 175bdd1243dSDimitry Andric } 176bdd1243dSDimitry Andric 1775f757f3fSDimitry Andric void Flang::AddAArch64TargetArgs(const ArgList &Args, 1785f757f3fSDimitry Andric ArgStringList &CmdArgs) const { 1795f757f3fSDimitry Andric // Handle -msve_vector_bits=<bits> 1805f757f3fSDimitry Andric if (Arg *A = Args.getLastArg(options::OPT_msve_vector_bits_EQ)) { 1815f757f3fSDimitry Andric StringRef Val = A->getValue(); 1825f757f3fSDimitry Andric const Driver &D = getToolChain().getDriver(); 183*0fca6ea1SDimitry Andric if (Val == "128" || Val == "256" || Val == "512" || Val == "1024" || 184*0fca6ea1SDimitry Andric Val == "2048" || Val == "128+" || Val == "256+" || Val == "512+" || 185*0fca6ea1SDimitry Andric Val == "1024+" || Val == "2048+") { 1865f757f3fSDimitry Andric unsigned Bits = 0; 187*0fca6ea1SDimitry Andric if (!Val.consume_back("+")) { 1885f757f3fSDimitry Andric [[maybe_unused]] bool Invalid = Val.getAsInteger(10, Bits); 1895f757f3fSDimitry Andric assert(!Invalid && "Failed to parse value"); 1905f757f3fSDimitry Andric CmdArgs.push_back( 1915f757f3fSDimitry Andric Args.MakeArgString("-mvscale-max=" + llvm::Twine(Bits / 128))); 1925f757f3fSDimitry Andric } 1935f757f3fSDimitry Andric 1945f757f3fSDimitry Andric [[maybe_unused]] bool Invalid = Val.getAsInteger(10, Bits); 1955f757f3fSDimitry Andric assert(!Invalid && "Failed to parse value"); 1965f757f3fSDimitry Andric CmdArgs.push_back( 1975f757f3fSDimitry Andric Args.MakeArgString("-mvscale-min=" + llvm::Twine(Bits / 128))); 1985f757f3fSDimitry Andric // Silently drop requests for vector-length agnostic code as it's implied. 199*0fca6ea1SDimitry Andric } else if (Val != "scalable") 2005f757f3fSDimitry Andric // Handle the unsupported values passed to msve-vector-bits. 2015f757f3fSDimitry Andric D.Diag(diag::err_drv_unsupported_option_argument) 2025f757f3fSDimitry Andric << A->getSpelling() << Val; 2035f757f3fSDimitry Andric } 2045f757f3fSDimitry Andric } 2055f757f3fSDimitry Andric 206297eecfbSDimitry Andric void Flang::AddRISCVTargetArgs(const ArgList &Args, 207297eecfbSDimitry Andric ArgStringList &CmdArgs) const { 208297eecfbSDimitry Andric const llvm::Triple &Triple = getToolChain().getTriple(); 209297eecfbSDimitry Andric // Handle -mrvv-vector-bits=<bits> 210297eecfbSDimitry Andric if (Arg *A = Args.getLastArg(options::OPT_mrvv_vector_bits_EQ)) { 211297eecfbSDimitry Andric StringRef Val = A->getValue(); 212297eecfbSDimitry Andric const Driver &D = getToolChain().getDriver(); 213297eecfbSDimitry Andric 214297eecfbSDimitry Andric // Get minimum VLen from march. 215297eecfbSDimitry Andric unsigned MinVLen = 0; 216*0fca6ea1SDimitry Andric std::string Arch = riscv::getRISCVArch(Args, Triple); 217297eecfbSDimitry Andric auto ISAInfo = llvm::RISCVISAInfo::parseArchString( 218297eecfbSDimitry Andric Arch, /*EnableExperimentalExtensions*/ true); 219297eecfbSDimitry Andric // Ignore parsing error. 220297eecfbSDimitry Andric if (!errorToBool(ISAInfo.takeError())) 221297eecfbSDimitry Andric MinVLen = (*ISAInfo)->getMinVLen(); 222297eecfbSDimitry Andric 223297eecfbSDimitry Andric // If the value is "zvl", use MinVLen from march. Otherwise, try to parse 224297eecfbSDimitry Andric // as integer as long as we have a MinVLen. 225297eecfbSDimitry Andric unsigned Bits = 0; 226*0fca6ea1SDimitry Andric if (Val == "zvl" && MinVLen >= llvm::RISCV::RVVBitsPerBlock) { 227297eecfbSDimitry Andric Bits = MinVLen; 228297eecfbSDimitry Andric } else if (!Val.getAsInteger(10, Bits)) { 229297eecfbSDimitry Andric // Only accept power of 2 values beteen RVVBitsPerBlock and 65536 that 230297eecfbSDimitry Andric // at least MinVLen. 231297eecfbSDimitry Andric if (Bits < MinVLen || Bits < llvm::RISCV::RVVBitsPerBlock || 232297eecfbSDimitry Andric Bits > 65536 || !llvm::isPowerOf2_32(Bits)) 233297eecfbSDimitry Andric Bits = 0; 234297eecfbSDimitry Andric } 235297eecfbSDimitry Andric 236297eecfbSDimitry Andric // If we got a valid value try to use it. 237297eecfbSDimitry Andric if (Bits != 0) { 238297eecfbSDimitry Andric unsigned VScaleMin = Bits / llvm::RISCV::RVVBitsPerBlock; 239297eecfbSDimitry Andric CmdArgs.push_back( 240297eecfbSDimitry Andric Args.MakeArgString("-mvscale-max=" + llvm::Twine(VScaleMin))); 241297eecfbSDimitry Andric CmdArgs.push_back( 242297eecfbSDimitry Andric Args.MakeArgString("-mvscale-min=" + llvm::Twine(VScaleMin))); 243*0fca6ea1SDimitry Andric } else if (Val != "scalable") { 244297eecfbSDimitry Andric // Handle the unsupported values passed to mrvv-vector-bits. 245297eecfbSDimitry Andric D.Diag(diag::err_drv_unsupported_option_argument) 246297eecfbSDimitry Andric << A->getSpelling() << Val; 247297eecfbSDimitry Andric } 248297eecfbSDimitry Andric } 249297eecfbSDimitry Andric } 250297eecfbSDimitry Andric 251*0fca6ea1SDimitry Andric void Flang::AddX86_64TargetArgs(const ArgList &Args, 252*0fca6ea1SDimitry Andric ArgStringList &CmdArgs) const { 253*0fca6ea1SDimitry Andric if (Arg *A = Args.getLastArg(options::OPT_masm_EQ)) { 254*0fca6ea1SDimitry Andric StringRef Value = A->getValue(); 255*0fca6ea1SDimitry Andric if (Value == "intel" || Value == "att") { 256*0fca6ea1SDimitry Andric CmdArgs.push_back(Args.MakeArgString("-mllvm")); 257*0fca6ea1SDimitry Andric CmdArgs.push_back(Args.MakeArgString("-x86-asm-syntax=" + Value)); 258*0fca6ea1SDimitry Andric } else { 259*0fca6ea1SDimitry Andric getToolChain().getDriver().Diag(diag::err_drv_unsupported_option_argument) 260*0fca6ea1SDimitry Andric << A->getSpelling() << Value; 261*0fca6ea1SDimitry Andric } 262*0fca6ea1SDimitry Andric } 263*0fca6ea1SDimitry Andric } 264*0fca6ea1SDimitry Andric 2655f757f3fSDimitry Andric static void addVSDefines(const ToolChain &TC, const ArgList &Args, 2665f757f3fSDimitry Andric ArgStringList &CmdArgs) { 2675f757f3fSDimitry Andric 2685f757f3fSDimitry Andric unsigned ver = 0; 2695f757f3fSDimitry Andric const VersionTuple vt = TC.computeMSVCVersion(nullptr, Args); 2705f757f3fSDimitry Andric ver = vt.getMajor() * 10000000 + vt.getMinor().value_or(0) * 100000 + 2715f757f3fSDimitry Andric vt.getSubminor().value_or(0); 2725f757f3fSDimitry Andric CmdArgs.push_back(Args.MakeArgString("-D_MSC_VER=" + Twine(ver / 100000))); 2735f757f3fSDimitry Andric CmdArgs.push_back(Args.MakeArgString("-D_MSC_FULL_VER=" + Twine(ver))); 2745f757f3fSDimitry Andric CmdArgs.push_back(Args.MakeArgString("-D_WIN32")); 2755f757f3fSDimitry Andric 276*0fca6ea1SDimitry Andric const llvm::Triple &triple = TC.getTriple(); 2775f757f3fSDimitry Andric if (triple.isAArch64()) { 2785f757f3fSDimitry Andric CmdArgs.push_back("-D_M_ARM64=1"); 2795f757f3fSDimitry Andric } else if (triple.isX86() && triple.isArch32Bit()) { 2805f757f3fSDimitry Andric CmdArgs.push_back("-D_M_IX86=600"); 2815f757f3fSDimitry Andric } else if (triple.isX86() && triple.isArch64Bit()) { 2825f757f3fSDimitry Andric CmdArgs.push_back("-D_M_X64=100"); 2835f757f3fSDimitry Andric } else { 2845f757f3fSDimitry Andric llvm_unreachable( 2855f757f3fSDimitry Andric "Flang on Windows only supports X86_32, X86_64 and AArch64"); 2865f757f3fSDimitry Andric } 2875f757f3fSDimitry Andric } 2885f757f3fSDimitry Andric 2895f757f3fSDimitry Andric static void processVSRuntimeLibrary(const ToolChain &TC, const ArgList &Args, 2905f757f3fSDimitry Andric ArgStringList &CmdArgs) { 2915f757f3fSDimitry Andric assert(TC.getTriple().isKnownWindowsMSVCEnvironment() && 2925f757f3fSDimitry Andric "can only add VS runtime library on Windows!"); 2935f757f3fSDimitry Andric // if -fno-fortran-main has been passed, skip linking Fortran_main.a 2945f757f3fSDimitry Andric if (TC.getTriple().isKnownWindowsMSVCEnvironment()) { 2955f757f3fSDimitry Andric CmdArgs.push_back(Args.MakeArgString( 2965f757f3fSDimitry Andric "--dependent-lib=" + TC.getCompilerRTBasename(Args, "builtins"))); 2975f757f3fSDimitry Andric } 2985f757f3fSDimitry Andric unsigned RTOptionID = options::OPT__SLASH_MT; 2995f757f3fSDimitry Andric if (auto *rtl = Args.getLastArg(options::OPT_fms_runtime_lib_EQ)) { 3005f757f3fSDimitry Andric RTOptionID = llvm::StringSwitch<unsigned>(rtl->getValue()) 3015f757f3fSDimitry Andric .Case("static", options::OPT__SLASH_MT) 3025f757f3fSDimitry Andric .Case("static_dbg", options::OPT__SLASH_MTd) 3035f757f3fSDimitry Andric .Case("dll", options::OPT__SLASH_MD) 3045f757f3fSDimitry Andric .Case("dll_dbg", options::OPT__SLASH_MDd) 3055f757f3fSDimitry Andric .Default(options::OPT__SLASH_MT); 3065f757f3fSDimitry Andric } 3075f757f3fSDimitry Andric switch (RTOptionID) { 3085f757f3fSDimitry Andric case options::OPT__SLASH_MT: 3095f757f3fSDimitry Andric CmdArgs.push_back("-D_MT"); 3105f757f3fSDimitry Andric CmdArgs.push_back("--dependent-lib=libcmt"); 3115f757f3fSDimitry Andric CmdArgs.push_back("--dependent-lib=FortranRuntime.static.lib"); 3125f757f3fSDimitry Andric CmdArgs.push_back("--dependent-lib=FortranDecimal.static.lib"); 3135f757f3fSDimitry Andric break; 3145f757f3fSDimitry Andric case options::OPT__SLASH_MTd: 3155f757f3fSDimitry Andric CmdArgs.push_back("-D_MT"); 3165f757f3fSDimitry Andric CmdArgs.push_back("-D_DEBUG"); 3175f757f3fSDimitry Andric CmdArgs.push_back("--dependent-lib=libcmtd"); 3185f757f3fSDimitry Andric CmdArgs.push_back("--dependent-lib=FortranRuntime.static_dbg.lib"); 3195f757f3fSDimitry Andric CmdArgs.push_back("--dependent-lib=FortranDecimal.static_dbg.lib"); 3205f757f3fSDimitry Andric break; 3215f757f3fSDimitry Andric case options::OPT__SLASH_MD: 3225f757f3fSDimitry Andric CmdArgs.push_back("-D_MT"); 3235f757f3fSDimitry Andric CmdArgs.push_back("-D_DLL"); 3245f757f3fSDimitry Andric CmdArgs.push_back("--dependent-lib=msvcrt"); 3255f757f3fSDimitry Andric CmdArgs.push_back("--dependent-lib=FortranRuntime.dynamic.lib"); 3265f757f3fSDimitry Andric CmdArgs.push_back("--dependent-lib=FortranDecimal.dynamic.lib"); 3275f757f3fSDimitry Andric break; 3285f757f3fSDimitry Andric case options::OPT__SLASH_MDd: 3295f757f3fSDimitry Andric CmdArgs.push_back("-D_MT"); 3305f757f3fSDimitry Andric CmdArgs.push_back("-D_DEBUG"); 3315f757f3fSDimitry Andric CmdArgs.push_back("-D_DLL"); 3325f757f3fSDimitry Andric CmdArgs.push_back("--dependent-lib=msvcrtd"); 3335f757f3fSDimitry Andric CmdArgs.push_back("--dependent-lib=FortranRuntime.dynamic_dbg.lib"); 3345f757f3fSDimitry Andric CmdArgs.push_back("--dependent-lib=FortranDecimal.dynamic_dbg.lib"); 3355f757f3fSDimitry Andric break; 3365f757f3fSDimitry Andric } 3375f757f3fSDimitry Andric } 3385f757f3fSDimitry Andric 3395f757f3fSDimitry Andric void Flang::AddAMDGPUTargetArgs(const ArgList &Args, 3405f757f3fSDimitry Andric ArgStringList &CmdArgs) const { 3415f757f3fSDimitry Andric if (Arg *A = Args.getLastArg(options::OPT_mcode_object_version_EQ)) { 3425f757f3fSDimitry Andric StringRef Val = A->getValue(); 3435f757f3fSDimitry Andric CmdArgs.push_back(Args.MakeArgString("-mcode-object-version=" + Val)); 3445f757f3fSDimitry Andric } 3455f757f3fSDimitry Andric } 3465f757f3fSDimitry Andric 347bdd1243dSDimitry Andric void Flang::addTargetOptions(const ArgList &Args, 348bdd1243dSDimitry Andric ArgStringList &CmdArgs) const { 349bdd1243dSDimitry Andric const ToolChain &TC = getToolChain(); 350bdd1243dSDimitry Andric const llvm::Triple &Triple = TC.getEffectiveTriple(); 351bdd1243dSDimitry Andric const Driver &D = TC.getDriver(); 352bdd1243dSDimitry Andric 353bdd1243dSDimitry Andric std::string CPU = getCPUName(D, Args, Triple); 354bdd1243dSDimitry Andric if (!CPU.empty()) { 355bdd1243dSDimitry Andric CmdArgs.push_back("-target-cpu"); 356bdd1243dSDimitry Andric CmdArgs.push_back(Args.MakeArgString(CPU)); 357bdd1243dSDimitry Andric } 358bdd1243dSDimitry Andric 359*0fca6ea1SDimitry Andric addOutlineAtomicsArgs(D, getToolChain(), Args, CmdArgs, Triple); 360*0fca6ea1SDimitry Andric 361bdd1243dSDimitry Andric // Add the target features. 362bdd1243dSDimitry Andric switch (TC.getArch()) { 363bdd1243dSDimitry Andric default: 364bdd1243dSDimitry Andric break; 3655f757f3fSDimitry Andric case llvm::Triple::aarch64: 3665f757f3fSDimitry Andric getTargetFeatures(D, Triple, Args, CmdArgs, /*ForAs*/ false); 3675f757f3fSDimitry Andric AddAArch64TargetArgs(Args, CmdArgs); 3685f757f3fSDimitry Andric break; 3695f757f3fSDimitry Andric 37006c3fb27SDimitry Andric case llvm::Triple::r600: 37106c3fb27SDimitry Andric case llvm::Triple::amdgcn: 3725f757f3fSDimitry Andric getTargetFeatures(D, Triple, Args, CmdArgs, /*ForAs*/ false); 3735f757f3fSDimitry Andric AddAMDGPUTargetArgs(Args, CmdArgs); 3745f757f3fSDimitry Andric break; 37506c3fb27SDimitry Andric case llvm::Triple::riscv64: 376297eecfbSDimitry Andric getTargetFeatures(D, Triple, Args, CmdArgs, /*ForAs*/ false); 377297eecfbSDimitry Andric AddRISCVTargetArgs(Args, CmdArgs); 378297eecfbSDimitry Andric break; 379bdd1243dSDimitry Andric case llvm::Triple::x86_64: 380bdd1243dSDimitry Andric getTargetFeatures(D, Triple, Args, CmdArgs, /*ForAs*/ false); 381*0fca6ea1SDimitry Andric AddX86_64TargetArgs(Args, CmdArgs); 382bdd1243dSDimitry Andric break; 383bdd1243dSDimitry Andric } 384bdd1243dSDimitry Andric 3855f757f3fSDimitry Andric if (Arg *A = Args.getLastArg(options::OPT_fveclib)) { 3865f757f3fSDimitry Andric StringRef Name = A->getValue(); 3875f757f3fSDimitry Andric if (Name == "SVML") { 3885f757f3fSDimitry Andric if (Triple.getArch() != llvm::Triple::x86 && 3895f757f3fSDimitry Andric Triple.getArch() != llvm::Triple::x86_64) 3905f757f3fSDimitry Andric D.Diag(diag::err_drv_unsupported_opt_for_target) 3915f757f3fSDimitry Andric << Name << Triple.getArchName(); 3925f757f3fSDimitry Andric } else if (Name == "LIBMVEC-X86") { 3935f757f3fSDimitry Andric if (Triple.getArch() != llvm::Triple::x86 && 3945f757f3fSDimitry Andric Triple.getArch() != llvm::Triple::x86_64) 3955f757f3fSDimitry Andric D.Diag(diag::err_drv_unsupported_opt_for_target) 3965f757f3fSDimitry Andric << Name << Triple.getArchName(); 3975f757f3fSDimitry Andric } else if (Name == "SLEEF" || Name == "ArmPL") { 3985f757f3fSDimitry Andric if (Triple.getArch() != llvm::Triple::aarch64 && 3995f757f3fSDimitry Andric Triple.getArch() != llvm::Triple::aarch64_be) 4005f757f3fSDimitry Andric D.Diag(diag::err_drv_unsupported_opt_for_target) 4015f757f3fSDimitry Andric << Name << Triple.getArchName(); 4025f757f3fSDimitry Andric } 4035f757f3fSDimitry Andric 4045f757f3fSDimitry Andric if (Triple.isOSDarwin()) { 4055f757f3fSDimitry Andric // flang doesn't currently suport nostdlib, nodefaultlibs. Adding these 4065f757f3fSDimitry Andric // here incase they are added someday 4075f757f3fSDimitry Andric if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { 4085f757f3fSDimitry Andric if (A->getValue() == StringRef{"Accelerate"}) { 4095f757f3fSDimitry Andric CmdArgs.push_back("-framework"); 4105f757f3fSDimitry Andric CmdArgs.push_back("Accelerate"); 411297eecfbSDimitry Andric } 412297eecfbSDimitry Andric } 413297eecfbSDimitry Andric } 4145f757f3fSDimitry Andric A->render(Args, CmdArgs); 4155f757f3fSDimitry Andric } 4165f757f3fSDimitry Andric 4175f757f3fSDimitry Andric if (Triple.isKnownWindowsMSVCEnvironment()) { 4185f757f3fSDimitry Andric processVSRuntimeLibrary(TC, Args, CmdArgs); 4195f757f3fSDimitry Andric addVSDefines(TC, Args, CmdArgs); 4205f757f3fSDimitry Andric } 4215f757f3fSDimitry Andric 422bdd1243dSDimitry Andric // TODO: Add target specific flags, ABI, mtune option etc. 423*0fca6ea1SDimitry Andric if (const Arg *A = Args.getLastArg(options::OPT_mtune_EQ)) { 424*0fca6ea1SDimitry Andric CmdArgs.push_back("-tune-cpu"); 425*0fca6ea1SDimitry Andric if (A->getValue() == StringRef{"native"}) 426*0fca6ea1SDimitry Andric CmdArgs.push_back(Args.MakeArgString(llvm::sys::getHostCPUName())); 427*0fca6ea1SDimitry Andric else 428*0fca6ea1SDimitry Andric CmdArgs.push_back(A->getValue()); 429*0fca6ea1SDimitry Andric } 430bdd1243dSDimitry Andric } 431bdd1243dSDimitry Andric 43206c3fb27SDimitry Andric void Flang::addOffloadOptions(Compilation &C, const InputInfoList &Inputs, 43306c3fb27SDimitry Andric const JobAction &JA, const ArgList &Args, 43406c3fb27SDimitry Andric ArgStringList &CmdArgs) const { 43506c3fb27SDimitry Andric bool IsOpenMPDevice = JA.isDeviceOffloading(Action::OFK_OpenMP); 43606c3fb27SDimitry Andric bool IsHostOffloadingAction = JA.isHostOffloading(Action::OFK_OpenMP) || 43706c3fb27SDimitry Andric JA.isHostOffloading(C.getActiveOffloadKinds()); 43806c3fb27SDimitry Andric 43906c3fb27SDimitry Andric // Skips the primary input file, which is the input file that the compilation 44006c3fb27SDimitry Andric // proccess will be executed upon (e.g. the host bitcode file) and 44106c3fb27SDimitry Andric // adds other secondary input (e.g. device bitcode files for embedding to the 44206c3fb27SDimitry Andric // -fembed-offload-object argument or the host IR file for proccessing 44306c3fb27SDimitry Andric // during device compilation to the fopenmp-host-ir-file-path argument via 44406c3fb27SDimitry Andric // OpenMPDeviceInput). This is condensed logic from the ConstructJob 44506c3fb27SDimitry Andric // function inside of the Clang driver for pushing on further input arguments 44606c3fb27SDimitry Andric // needed for offloading during various phases of compilation. 44706c3fb27SDimitry Andric for (size_t i = 1; i < Inputs.size(); ++i) { 44806c3fb27SDimitry Andric if (Inputs[i].getType() == types::TY_Nothing) { 44906c3fb27SDimitry Andric // contains nothing, so it's skippable 45006c3fb27SDimitry Andric } else if (IsHostOffloadingAction) { 45106c3fb27SDimitry Andric CmdArgs.push_back( 45206c3fb27SDimitry Andric Args.MakeArgString("-fembed-offload-object=" + 45306c3fb27SDimitry Andric getToolChain().getInputFilename(Inputs[i]))); 45406c3fb27SDimitry Andric } else if (IsOpenMPDevice) { 45506c3fb27SDimitry Andric if (Inputs[i].getFilename()) { 45606c3fb27SDimitry Andric CmdArgs.push_back("-fopenmp-host-ir-file-path"); 45706c3fb27SDimitry Andric CmdArgs.push_back(Args.MakeArgString(Inputs[i].getFilename())); 45806c3fb27SDimitry Andric } else { 45906c3fb27SDimitry Andric llvm_unreachable("missing openmp host-ir file for device offloading"); 46006c3fb27SDimitry Andric } 46106c3fb27SDimitry Andric } else { 46206c3fb27SDimitry Andric llvm_unreachable( 46306c3fb27SDimitry Andric "unexpectedly given multiple inputs or given unknown input"); 46406c3fb27SDimitry Andric } 46506c3fb27SDimitry Andric } 46606c3fb27SDimitry Andric 46706c3fb27SDimitry Andric if (IsOpenMPDevice) { 46806c3fb27SDimitry Andric // -fopenmp-is-target-device is passed along to tell the frontend that it is 46906c3fb27SDimitry Andric // generating code for a device, so that only the relevant code is emitted. 47006c3fb27SDimitry Andric CmdArgs.push_back("-fopenmp-is-target-device"); 47106c3fb27SDimitry Andric 47206c3fb27SDimitry Andric // When in OpenMP offloading mode, enable debugging on the device. 47306c3fb27SDimitry Andric Args.AddAllArgs(CmdArgs, options::OPT_fopenmp_target_debug_EQ); 47406c3fb27SDimitry Andric if (Args.hasFlag(options::OPT_fopenmp_target_debug, 47506c3fb27SDimitry Andric options::OPT_fno_openmp_target_debug, /*Default=*/false)) 47606c3fb27SDimitry Andric CmdArgs.push_back("-fopenmp-target-debug"); 47706c3fb27SDimitry Andric 47806c3fb27SDimitry Andric // When in OpenMP offloading mode, forward assumptions information about 47906c3fb27SDimitry Andric // thread and team counts in the device. 48006c3fb27SDimitry Andric if (Args.hasFlag(options::OPT_fopenmp_assume_teams_oversubscription, 48106c3fb27SDimitry Andric options::OPT_fno_openmp_assume_teams_oversubscription, 48206c3fb27SDimitry Andric /*Default=*/false)) 48306c3fb27SDimitry Andric CmdArgs.push_back("-fopenmp-assume-teams-oversubscription"); 48406c3fb27SDimitry Andric if (Args.hasFlag(options::OPT_fopenmp_assume_threads_oversubscription, 48506c3fb27SDimitry Andric options::OPT_fno_openmp_assume_threads_oversubscription, 48606c3fb27SDimitry Andric /*Default=*/false)) 48706c3fb27SDimitry Andric CmdArgs.push_back("-fopenmp-assume-threads-oversubscription"); 48806c3fb27SDimitry Andric if (Args.hasArg(options::OPT_fopenmp_assume_no_thread_state)) 48906c3fb27SDimitry Andric CmdArgs.push_back("-fopenmp-assume-no-thread-state"); 49006c3fb27SDimitry Andric if (Args.hasArg(options::OPT_fopenmp_assume_no_nested_parallelism)) 49106c3fb27SDimitry Andric CmdArgs.push_back("-fopenmp-assume-no-nested-parallelism"); 492297eecfbSDimitry Andric if (Args.hasArg(options::OPT_nogpulib)) 493297eecfbSDimitry Andric CmdArgs.push_back("-nogpulib"); 49406c3fb27SDimitry Andric } 49506c3fb27SDimitry Andric } 49606c3fb27SDimitry Andric 497bdd1243dSDimitry Andric static void addFloatingPointOptions(const Driver &D, const ArgList &Args, 498bdd1243dSDimitry Andric ArgStringList &CmdArgs) { 499bdd1243dSDimitry Andric StringRef FPContract; 500bdd1243dSDimitry Andric bool HonorINFs = true; 501bdd1243dSDimitry Andric bool HonorNaNs = true; 502bdd1243dSDimitry Andric bool ApproxFunc = false; 503bdd1243dSDimitry Andric bool SignedZeros = true; 504bdd1243dSDimitry Andric bool AssociativeMath = false; 505bdd1243dSDimitry Andric bool ReciprocalMath = false; 506bdd1243dSDimitry Andric 507bdd1243dSDimitry Andric if (const Arg *A = Args.getLastArg(options::OPT_ffp_contract)) { 508bdd1243dSDimitry Andric const StringRef Val = A->getValue(); 509bdd1243dSDimitry Andric if (Val == "fast" || Val == "off") { 510bdd1243dSDimitry Andric FPContract = Val; 511bdd1243dSDimitry Andric } else if (Val == "on") { 512bdd1243dSDimitry Andric // Warn instead of error because users might have makefiles written for 513bdd1243dSDimitry Andric // gfortran (which accepts -ffp-contract=on) 514bdd1243dSDimitry Andric D.Diag(diag::warn_drv_unsupported_option_for_flang) 515bdd1243dSDimitry Andric << Val << A->getOption().getName() << "off"; 516bdd1243dSDimitry Andric FPContract = "off"; 517bdd1243dSDimitry Andric } else 518bdd1243dSDimitry Andric // Clang's "fast-honor-pragmas" option is not supported because it is 519bdd1243dSDimitry Andric // non-standard 520bdd1243dSDimitry Andric D.Diag(diag::err_drv_unsupported_option_argument) 521bdd1243dSDimitry Andric << A->getSpelling() << Val; 522bdd1243dSDimitry Andric } 523bdd1243dSDimitry Andric 524bdd1243dSDimitry Andric for (const Arg *A : Args) { 525bdd1243dSDimitry Andric auto optId = A->getOption().getID(); 526bdd1243dSDimitry Andric switch (optId) { 527bdd1243dSDimitry Andric // if this isn't an FP option, skip the claim below 528bdd1243dSDimitry Andric default: 529bdd1243dSDimitry Andric continue; 530bdd1243dSDimitry Andric 531bdd1243dSDimitry Andric case options::OPT_fhonor_infinities: 532bdd1243dSDimitry Andric HonorINFs = true; 533bdd1243dSDimitry Andric break; 534bdd1243dSDimitry Andric case options::OPT_fno_honor_infinities: 535bdd1243dSDimitry Andric HonorINFs = false; 536bdd1243dSDimitry Andric break; 537bdd1243dSDimitry Andric case options::OPT_fhonor_nans: 538bdd1243dSDimitry Andric HonorNaNs = true; 539bdd1243dSDimitry Andric break; 540bdd1243dSDimitry Andric case options::OPT_fno_honor_nans: 541bdd1243dSDimitry Andric HonorNaNs = false; 542bdd1243dSDimitry Andric break; 543bdd1243dSDimitry Andric case options::OPT_fapprox_func: 544bdd1243dSDimitry Andric ApproxFunc = true; 545bdd1243dSDimitry Andric break; 546bdd1243dSDimitry Andric case options::OPT_fno_approx_func: 547bdd1243dSDimitry Andric ApproxFunc = false; 548bdd1243dSDimitry Andric break; 549bdd1243dSDimitry Andric case options::OPT_fsigned_zeros: 550bdd1243dSDimitry Andric SignedZeros = true; 551bdd1243dSDimitry Andric break; 552bdd1243dSDimitry Andric case options::OPT_fno_signed_zeros: 553bdd1243dSDimitry Andric SignedZeros = false; 554bdd1243dSDimitry Andric break; 555bdd1243dSDimitry Andric case options::OPT_fassociative_math: 556bdd1243dSDimitry Andric AssociativeMath = true; 557bdd1243dSDimitry Andric break; 558bdd1243dSDimitry Andric case options::OPT_fno_associative_math: 559bdd1243dSDimitry Andric AssociativeMath = false; 560bdd1243dSDimitry Andric break; 561bdd1243dSDimitry Andric case options::OPT_freciprocal_math: 562bdd1243dSDimitry Andric ReciprocalMath = true; 563bdd1243dSDimitry Andric break; 564bdd1243dSDimitry Andric case options::OPT_fno_reciprocal_math: 565bdd1243dSDimitry Andric ReciprocalMath = false; 566bdd1243dSDimitry Andric break; 567bdd1243dSDimitry Andric case options::OPT_Ofast: 568bdd1243dSDimitry Andric [[fallthrough]]; 569bdd1243dSDimitry Andric case options::OPT_ffast_math: 570bdd1243dSDimitry Andric HonorINFs = false; 571bdd1243dSDimitry Andric HonorNaNs = false; 572bdd1243dSDimitry Andric AssociativeMath = true; 573bdd1243dSDimitry Andric ReciprocalMath = true; 574bdd1243dSDimitry Andric ApproxFunc = true; 575bdd1243dSDimitry Andric SignedZeros = false; 576bdd1243dSDimitry Andric FPContract = "fast"; 577bdd1243dSDimitry Andric break; 578bdd1243dSDimitry Andric case options::OPT_fno_fast_math: 579bdd1243dSDimitry Andric HonorINFs = true; 580bdd1243dSDimitry Andric HonorNaNs = true; 581bdd1243dSDimitry Andric AssociativeMath = false; 582bdd1243dSDimitry Andric ReciprocalMath = false; 583bdd1243dSDimitry Andric ApproxFunc = false; 584bdd1243dSDimitry Andric SignedZeros = true; 585bdd1243dSDimitry Andric // -fno-fast-math should undo -ffast-math so I return FPContract to the 586bdd1243dSDimitry Andric // default. It is important to check it is "fast" (the default) so that 587bdd1243dSDimitry Andric // --ffp-contract=off -fno-fast-math --> -ffp-contract=off 588bdd1243dSDimitry Andric if (FPContract == "fast") 589bdd1243dSDimitry Andric FPContract = ""; 590bdd1243dSDimitry Andric break; 591bdd1243dSDimitry Andric } 592bdd1243dSDimitry Andric 593bdd1243dSDimitry Andric // If we handled this option claim it 594bdd1243dSDimitry Andric A->claim(); 595bdd1243dSDimitry Andric } 596bdd1243dSDimitry Andric 597bdd1243dSDimitry Andric if (!HonorINFs && !HonorNaNs && AssociativeMath && ReciprocalMath && 598bdd1243dSDimitry Andric ApproxFunc && !SignedZeros && 599*0fca6ea1SDimitry Andric (FPContract == "fast" || FPContract.empty())) { 600bdd1243dSDimitry Andric CmdArgs.push_back("-ffast-math"); 601bdd1243dSDimitry Andric return; 602bdd1243dSDimitry Andric } 603bdd1243dSDimitry Andric 604bdd1243dSDimitry Andric if (!FPContract.empty()) 605bdd1243dSDimitry Andric CmdArgs.push_back(Args.MakeArgString("-ffp-contract=" + FPContract)); 606bdd1243dSDimitry Andric 607bdd1243dSDimitry Andric if (!HonorINFs) 608bdd1243dSDimitry Andric CmdArgs.push_back("-menable-no-infs"); 609bdd1243dSDimitry Andric 610bdd1243dSDimitry Andric if (!HonorNaNs) 611bdd1243dSDimitry Andric CmdArgs.push_back("-menable-no-nans"); 612bdd1243dSDimitry Andric 613bdd1243dSDimitry Andric if (ApproxFunc) 614bdd1243dSDimitry Andric CmdArgs.push_back("-fapprox-func"); 615bdd1243dSDimitry Andric 616bdd1243dSDimitry Andric if (!SignedZeros) 617bdd1243dSDimitry Andric CmdArgs.push_back("-fno-signed-zeros"); 618bdd1243dSDimitry Andric 619bdd1243dSDimitry Andric if (AssociativeMath && !SignedZeros) 620bdd1243dSDimitry Andric CmdArgs.push_back("-mreassociate"); 621bdd1243dSDimitry Andric 622bdd1243dSDimitry Andric if (ReciprocalMath) 623bdd1243dSDimitry Andric CmdArgs.push_back("-freciprocal-math"); 624e8d8bef9SDimitry Andric } 625e8d8bef9SDimitry Andric 6265f757f3fSDimitry Andric static void renderRemarksOptions(const ArgList &Args, ArgStringList &CmdArgs, 6275f757f3fSDimitry Andric const InputInfo &Input) { 6285f757f3fSDimitry Andric StringRef Format = "yaml"; 6295f757f3fSDimitry Andric if (const Arg *A = Args.getLastArg(options::OPT_fsave_optimization_record_EQ)) 6305f757f3fSDimitry Andric Format = A->getValue(); 6315f757f3fSDimitry Andric 6325f757f3fSDimitry Andric CmdArgs.push_back("-opt-record-file"); 6335f757f3fSDimitry Andric 6345f757f3fSDimitry Andric const Arg *A = Args.getLastArg(options::OPT_foptimization_record_file_EQ); 6355f757f3fSDimitry Andric if (A) { 6365f757f3fSDimitry Andric CmdArgs.push_back(A->getValue()); 6375f757f3fSDimitry Andric } else { 6385f757f3fSDimitry Andric SmallString<128> F; 6395f757f3fSDimitry Andric 6405f757f3fSDimitry Andric if (Args.hasArg(options::OPT_c) || Args.hasArg(options::OPT_S)) { 6415f757f3fSDimitry Andric if (Arg *FinalOutput = Args.getLastArg(options::OPT_o)) 6425f757f3fSDimitry Andric F = FinalOutput->getValue(); 6435f757f3fSDimitry Andric } 6445f757f3fSDimitry Andric 6455f757f3fSDimitry Andric if (F.empty()) { 6465f757f3fSDimitry Andric // Use the input filename. 6475f757f3fSDimitry Andric F = llvm::sys::path::stem(Input.getBaseInput()); 6485f757f3fSDimitry Andric } 6495f757f3fSDimitry Andric 6505f757f3fSDimitry Andric SmallString<32> Extension; 6515f757f3fSDimitry Andric Extension += "opt."; 6525f757f3fSDimitry Andric Extension += Format; 6535f757f3fSDimitry Andric 6545f757f3fSDimitry Andric llvm::sys::path::replace_extension(F, Extension); 6555f757f3fSDimitry Andric CmdArgs.push_back(Args.MakeArgString(F)); 6565f757f3fSDimitry Andric } 6575f757f3fSDimitry Andric 6585f757f3fSDimitry Andric if (const Arg *A = 6595f757f3fSDimitry Andric Args.getLastArg(options::OPT_foptimization_record_passes_EQ)) { 6605f757f3fSDimitry Andric CmdArgs.push_back("-opt-record-passes"); 6615f757f3fSDimitry Andric CmdArgs.push_back(A->getValue()); 6625f757f3fSDimitry Andric } 6635f757f3fSDimitry Andric 6645f757f3fSDimitry Andric if (!Format.empty()) { 6655f757f3fSDimitry Andric CmdArgs.push_back("-opt-record-format"); 6665f757f3fSDimitry Andric CmdArgs.push_back(Format.data()); 6675f757f3fSDimitry Andric } 6685f757f3fSDimitry Andric } 6695f757f3fSDimitry Andric 670480093f4SDimitry Andric void Flang::ConstructJob(Compilation &C, const JobAction &JA, 671480093f4SDimitry Andric const InputInfo &Output, const InputInfoList &Inputs, 672480093f4SDimitry Andric const ArgList &Args, const char *LinkingOutput) const { 673480093f4SDimitry Andric const auto &TC = getToolChain(); 67481ad6265SDimitry Andric const llvm::Triple &Triple = TC.getEffectiveTriple(); 67581ad6265SDimitry Andric const std::string &TripleStr = Triple.getTriple(); 676480093f4SDimitry Andric 67781ad6265SDimitry Andric const Driver &D = TC.getDriver(); 678480093f4SDimitry Andric ArgStringList CmdArgs; 67906c3fb27SDimitry Andric DiagnosticsEngine &Diags = D.getDiags(); 680480093f4SDimitry Andric 681e8d8bef9SDimitry Andric // Invoke ourselves in -fc1 mode. 682480093f4SDimitry Andric CmdArgs.push_back("-fc1"); 683480093f4SDimitry Andric 684e8d8bef9SDimitry Andric // Add the "effective" target triple. 68581ad6265SDimitry Andric CmdArgs.push_back("-triple"); 68681ad6265SDimitry Andric CmdArgs.push_back(Args.MakeArgString(TripleStr)); 687480093f4SDimitry Andric 688480093f4SDimitry Andric if (isa<PreprocessJobAction>(JA)) { 689480093f4SDimitry Andric CmdArgs.push_back("-E"); 690*0fca6ea1SDimitry Andric if (Args.getLastArg(options::OPT_dM)) { 691*0fca6ea1SDimitry Andric CmdArgs.push_back("-dM"); 692*0fca6ea1SDimitry Andric } 693480093f4SDimitry Andric } else if (isa<CompileJobAction>(JA) || isa<BackendJobAction>(JA)) { 694480093f4SDimitry Andric if (JA.getType() == types::TY_Nothing) { 695480093f4SDimitry Andric CmdArgs.push_back("-fsyntax-only"); 696480093f4SDimitry Andric } else if (JA.getType() == types::TY_AST) { 697480093f4SDimitry Andric CmdArgs.push_back("-emit-ast"); 698480093f4SDimitry Andric } else if (JA.getType() == types::TY_LLVM_IR || 699480093f4SDimitry Andric JA.getType() == types::TY_LTO_IR) { 700480093f4SDimitry Andric CmdArgs.push_back("-emit-llvm"); 701480093f4SDimitry Andric } else if (JA.getType() == types::TY_LLVM_BC || 702480093f4SDimitry Andric JA.getType() == types::TY_LTO_BC) { 703480093f4SDimitry Andric CmdArgs.push_back("-emit-llvm-bc"); 704480093f4SDimitry Andric } else if (JA.getType() == types::TY_PP_Asm) { 705480093f4SDimitry Andric CmdArgs.push_back("-S"); 706480093f4SDimitry Andric } else { 707480093f4SDimitry Andric assert(false && "Unexpected output type!"); 708480093f4SDimitry Andric } 709480093f4SDimitry Andric } else if (isa<AssembleJobAction>(JA)) { 710480093f4SDimitry Andric CmdArgs.push_back("-emit-obj"); 711480093f4SDimitry Andric } else { 712480093f4SDimitry Andric assert(false && "Unexpected action class for Flang tool."); 713480093f4SDimitry Andric } 714480093f4SDimitry Andric 715e8d8bef9SDimitry Andric const InputInfo &Input = Inputs[0]; 716e8d8bef9SDimitry Andric types::ID InputType = Input.getType(); 717e8d8bef9SDimitry Andric 718e8d8bef9SDimitry Andric // Add preprocessing options like -I, -D, etc. if we are using the 719e8d8bef9SDimitry Andric // preprocessor (i.e. skip when dealing with e.g. binary files). 720e8d8bef9SDimitry Andric if (types::getPreprocessedType(InputType) != types::TY_INVALID) 721bdd1243dSDimitry Andric addPreprocessingOptions(Args, CmdArgs); 722e8d8bef9SDimitry Andric 723bdd1243dSDimitry Andric addFortranDialectOptions(Args, CmdArgs); 724fe6060f1SDimitry Andric 72581ad6265SDimitry Andric // Color diagnostics are parsed by the driver directly from argv and later 72681ad6265SDimitry Andric // re-parsed to construct this job; claim any possible color diagnostic here 72781ad6265SDimitry Andric // to avoid warn_drv_unused_argument. 72881ad6265SDimitry Andric Args.getLastArg(options::OPT_fcolor_diagnostics, 72981ad6265SDimitry Andric options::OPT_fno_color_diagnostics); 73006c3fb27SDimitry Andric if (Diags.getDiagnosticOptions().ShowColors) 73181ad6265SDimitry Andric CmdArgs.push_back("-fcolor-diagnostics"); 73281ad6265SDimitry Andric 73306c3fb27SDimitry Andric // LTO mode is parsed by the Clang driver library. 73406c3fb27SDimitry Andric LTOKind LTOMode = D.getLTOMode(/* IsOffload */ false); 73506c3fb27SDimitry Andric assert(LTOMode != LTOK_Unknown && "Unknown LTO mode."); 73606c3fb27SDimitry Andric if (LTOMode == LTOK_Full) 73706c3fb27SDimitry Andric CmdArgs.push_back("-flto=full"); 73806c3fb27SDimitry Andric else if (LTOMode == LTOK_Thin) { 73906c3fb27SDimitry Andric Diags.Report( 74006c3fb27SDimitry Andric Diags.getCustomDiagID(DiagnosticsEngine::Warning, 74106c3fb27SDimitry Andric "the option '-flto=thin' is a work in progress")); 74206c3fb27SDimitry Andric CmdArgs.push_back("-flto=thin"); 74306c3fb27SDimitry Andric } 74406c3fb27SDimitry Andric 745bdd1243dSDimitry Andric // -fPIC and related options. 746bdd1243dSDimitry Andric addPicOptions(Args, CmdArgs); 747bdd1243dSDimitry Andric 748bdd1243dSDimitry Andric // Floating point related options 749bdd1243dSDimitry Andric addFloatingPointOptions(D, Args, CmdArgs); 750bdd1243dSDimitry Andric 751bdd1243dSDimitry Andric // Add target args, features, etc. 752bdd1243dSDimitry Andric addTargetOptions(Args, CmdArgs); 753bdd1243dSDimitry Andric 754*0fca6ea1SDimitry Andric llvm::Reloc::Model RelocationModel = 755*0fca6ea1SDimitry Andric std::get<0>(ParsePICArgs(getToolChain(), Args)); 756*0fca6ea1SDimitry Andric // Add MCModel information 757*0fca6ea1SDimitry Andric addMCModel(D, Args, Triple, RelocationModel, CmdArgs); 758*0fca6ea1SDimitry Andric 75906c3fb27SDimitry Andric // Add Codegen options 76006c3fb27SDimitry Andric addCodegenOptions(Args, CmdArgs); 76106c3fb27SDimitry Andric 7625f757f3fSDimitry Andric // Add R Group options 7635f757f3fSDimitry Andric Args.AddAllArgs(CmdArgs, options::OPT_R_Group); 7645f757f3fSDimitry Andric 7655f757f3fSDimitry Andric // Remarks can be enabled with any of the `-f.*optimization-record.*` flags. 7665f757f3fSDimitry Andric if (willEmitRemarks(Args)) 7675f757f3fSDimitry Andric renderRemarksOptions(Args, CmdArgs, Input); 7685f757f3fSDimitry Andric 769fe6060f1SDimitry Andric // Add other compile options 770bdd1243dSDimitry Andric addOtherOptions(Args, CmdArgs); 771fe6060f1SDimitry Andric 772*0fca6ea1SDimitry Andric // Disable all warnings 773*0fca6ea1SDimitry Andric // TODO: Handle interactions between -w, -pedantic, -Wall, -WOption 774*0fca6ea1SDimitry Andric Args.AddLastArg(CmdArgs, options::OPT_w); 775*0fca6ea1SDimitry Andric 776*0fca6ea1SDimitry Andric // Forward flags for OpenMP. We don't do this if the current action is an 777*0fca6ea1SDimitry Andric // device offloading action other than OpenMP. 778*0fca6ea1SDimitry Andric if (Args.hasFlag(options::OPT_fopenmp, options::OPT_fopenmp_EQ, 779*0fca6ea1SDimitry Andric options::OPT_fno_openmp, false) && 780*0fca6ea1SDimitry Andric (JA.isDeviceOffloading(Action::OFK_None) || 781*0fca6ea1SDimitry Andric JA.isDeviceOffloading(Action::OFK_OpenMP))) { 782*0fca6ea1SDimitry Andric switch (D.getOpenMPRuntime(Args)) { 783*0fca6ea1SDimitry Andric case Driver::OMPRT_OMP: 784*0fca6ea1SDimitry Andric case Driver::OMPRT_IOMP5: 785*0fca6ea1SDimitry Andric // Clang can generate useful OpenMP code for these two runtime libraries. 786*0fca6ea1SDimitry Andric CmdArgs.push_back("-fopenmp"); 787*0fca6ea1SDimitry Andric Args.AddAllArgs(CmdArgs, options::OPT_fopenmp_version_EQ); 788*0fca6ea1SDimitry Andric 789*0fca6ea1SDimitry Andric if (Args.hasArg(options::OPT_fopenmp_force_usm)) 790*0fca6ea1SDimitry Andric CmdArgs.push_back("-fopenmp-force-usm"); 791*0fca6ea1SDimitry Andric 792*0fca6ea1SDimitry Andric // FIXME: Clang supports a whole bunch more flags here. 793*0fca6ea1SDimitry Andric break; 794*0fca6ea1SDimitry Andric default: 795*0fca6ea1SDimitry Andric // By default, if Clang doesn't know how to generate useful OpenMP code 796*0fca6ea1SDimitry Andric // for a specific runtime library, we just don't pass the '-fopenmp' flag 797*0fca6ea1SDimitry Andric // down to the actual compilation. 798*0fca6ea1SDimitry Andric // FIXME: It would be better to have a mode which *only* omits IR 799*0fca6ea1SDimitry Andric // generation based on the OpenMP support so that we get consistent 800*0fca6ea1SDimitry Andric // semantic analysis, etc. 801*0fca6ea1SDimitry Andric const Arg *A = Args.getLastArg(options::OPT_fopenmp_EQ); 802*0fca6ea1SDimitry Andric D.Diag(diag::warn_drv_unsupported_openmp_library) 803*0fca6ea1SDimitry Andric << A->getSpelling() << A->getValue(); 804*0fca6ea1SDimitry Andric break; 805*0fca6ea1SDimitry Andric } 806*0fca6ea1SDimitry Andric } 807*0fca6ea1SDimitry Andric 808*0fca6ea1SDimitry Andric // Pass the path to compiler resource files. 809*0fca6ea1SDimitry Andric CmdArgs.push_back("-resource-dir"); 810*0fca6ea1SDimitry Andric CmdArgs.push_back(D.ResourceDir.c_str()); 811*0fca6ea1SDimitry Andric 81206c3fb27SDimitry Andric // Offloading related options 81306c3fb27SDimitry Andric addOffloadOptions(C, Inputs, JA, Args, CmdArgs); 81406c3fb27SDimitry Andric 815fe6060f1SDimitry Andric // Forward -Xflang arguments to -fc1 816fe6060f1SDimitry Andric Args.AddAllArgValues(CmdArgs, options::OPT_Xflang); 817fe6060f1SDimitry Andric 8185f757f3fSDimitry Andric CodeGenOptions::FramePointerKind FPKeepKind = 8195f757f3fSDimitry Andric getFramePointerKind(Args, Triple); 8205f757f3fSDimitry Andric 8215f757f3fSDimitry Andric const char *FPKeepKindStr = nullptr; 8225f757f3fSDimitry Andric switch (FPKeepKind) { 8235f757f3fSDimitry Andric case CodeGenOptions::FramePointerKind::None: 8245f757f3fSDimitry Andric FPKeepKindStr = "-mframe-pointer=none"; 8255f757f3fSDimitry Andric break; 826*0fca6ea1SDimitry Andric case CodeGenOptions::FramePointerKind::Reserved: 827*0fca6ea1SDimitry Andric FPKeepKindStr = "-mframe-pointer=reserved"; 828*0fca6ea1SDimitry Andric break; 8295f757f3fSDimitry Andric case CodeGenOptions::FramePointerKind::NonLeaf: 8305f757f3fSDimitry Andric FPKeepKindStr = "-mframe-pointer=non-leaf"; 8315f757f3fSDimitry Andric break; 8325f757f3fSDimitry Andric case CodeGenOptions::FramePointerKind::All: 8335f757f3fSDimitry Andric FPKeepKindStr = "-mframe-pointer=all"; 8345f757f3fSDimitry Andric break; 8355f757f3fSDimitry Andric } 8365f757f3fSDimitry Andric assert(FPKeepKindStr && "unknown FramePointerKind"); 8375f757f3fSDimitry Andric CmdArgs.push_back(FPKeepKindStr); 8385f757f3fSDimitry Andric 83981ad6265SDimitry Andric // Forward -mllvm options to the LLVM option parser. In practice, this means 84081ad6265SDimitry Andric // forwarding to `-fc1` as that's where the LLVM parser is run. 84181ad6265SDimitry Andric for (const Arg *A : Args.filtered(options::OPT_mllvm)) { 84281ad6265SDimitry Andric A->claim(); 84381ad6265SDimitry Andric A->render(Args, CmdArgs); 84481ad6265SDimitry Andric } 84581ad6265SDimitry Andric 84681ad6265SDimitry Andric for (const Arg *A : Args.filtered(options::OPT_mmlir)) { 84781ad6265SDimitry Andric A->claim(); 84881ad6265SDimitry Andric A->render(Args, CmdArgs); 84981ad6265SDimitry Andric } 85081ad6265SDimitry Andric 85106c3fb27SDimitry Andric // Remove any unsupported gfortran diagnostic options 85206c3fb27SDimitry Andric for (const Arg *A : Args.filtered(options::OPT_flang_ignored_w_Group)) { 85306c3fb27SDimitry Andric A->claim(); 85406c3fb27SDimitry Andric D.Diag(diag::warn_drv_unsupported_diag_option_for_flang) 85506c3fb27SDimitry Andric << A->getOption().getName(); 85606c3fb27SDimitry Andric } 85706c3fb27SDimitry Andric 85881ad6265SDimitry Andric // Optimization level for CodeGen. 85981ad6265SDimitry Andric if (const Arg *A = Args.getLastArg(options::OPT_O_Group)) { 86081ad6265SDimitry Andric if (A->getOption().matches(options::OPT_O4)) { 86181ad6265SDimitry Andric CmdArgs.push_back("-O3"); 86281ad6265SDimitry Andric D.Diag(diag::warn_O4_is_O3); 863bdd1243dSDimitry Andric } else if (A->getOption().matches(options::OPT_Ofast)) { 864bdd1243dSDimitry Andric CmdArgs.push_back("-O3"); 86581ad6265SDimitry Andric } else { 86681ad6265SDimitry Andric A->render(Args, CmdArgs); 86781ad6265SDimitry Andric } 86881ad6265SDimitry Andric } 86981ad6265SDimitry Andric 8705f757f3fSDimitry Andric assert((Output.isFilename() || Output.isNothing()) && "Invalid output."); 871480093f4SDimitry Andric if (Output.isFilename()) { 872480093f4SDimitry Andric CmdArgs.push_back("-o"); 873480093f4SDimitry Andric CmdArgs.push_back(Output.getFilename()); 874480093f4SDimitry Andric } 875480093f4SDimitry Andric 876480093f4SDimitry Andric assert(Input.isFilename() && "Invalid input."); 87781ad6265SDimitry Andric 87806c3fb27SDimitry Andric if (Args.getLastArg(options::OPT_save_temps_EQ)) 87906c3fb27SDimitry Andric Args.AddLastArg(CmdArgs, options::OPT_save_temps_EQ); 88006c3fb27SDimitry Andric 88181ad6265SDimitry Andric addDashXForInput(Args, Input, CmdArgs); 88281ad6265SDimitry Andric 883480093f4SDimitry Andric CmdArgs.push_back(Input.getFilename()); 884480093f4SDimitry Andric 885e8d8bef9SDimitry Andric // TODO: Replace flang-new with flang once the new driver replaces the 886e8d8bef9SDimitry Andric // throwaway driver 887e8d8bef9SDimitry Andric const char *Exec = Args.MakeArgString(D.GetProgramPath("flang-new", TC)); 888e8d8bef9SDimitry Andric C.addCommand(std::make_unique<Command>(JA, *this, 889e8d8bef9SDimitry Andric ResponseFileSupport::AtFileUTF8(), 890e8d8bef9SDimitry Andric Exec, CmdArgs, Inputs, Output)); 891480093f4SDimitry Andric } 892480093f4SDimitry Andric 893e8d8bef9SDimitry Andric Flang::Flang(const ToolChain &TC) : Tool("flang-new", "flang frontend", TC) {} 894480093f4SDimitry Andric 895480093f4SDimitry Andric Flang::~Flang() {} 896