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" 10*297eecfbSDimitry 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*297eecfbSDimitry Andric #include "llvm/Support/RISCVISAInfo.h" 19*297eecfbSDimitry Andric #include "llvm/TargetParser/RISCVTargetParser.h" 20480093f4SDimitry Andric 21480093f4SDimitry Andric #include <cassert> 22480093f4SDimitry Andric 23480093f4SDimitry Andric using namespace clang::driver; 24480093f4SDimitry Andric using namespace clang::driver::tools; 25480093f4SDimitry Andric using namespace clang; 26480093f4SDimitry Andric using namespace llvm::opt; 27480093f4SDimitry Andric 2881ad6265SDimitry Andric /// Add -x lang to \p CmdArgs for \p Input. 2981ad6265SDimitry Andric static void addDashXForInput(const ArgList &Args, const InputInfo &Input, 3081ad6265SDimitry Andric ArgStringList &CmdArgs) { 3181ad6265SDimitry Andric CmdArgs.push_back("-x"); 3281ad6265SDimitry Andric // Map the driver type to the frontend type. 3381ad6265SDimitry Andric CmdArgs.push_back(types::getTypeName(Input.getType())); 3481ad6265SDimitry Andric } 3581ad6265SDimitry Andric 36bdd1243dSDimitry Andric void Flang::addFortranDialectOptions(const ArgList &Args, 37fe6060f1SDimitry Andric ArgStringList &CmdArgs) const { 385f757f3fSDimitry Andric Args.addAllArgs(CmdArgs, {options::OPT_ffixed_form, 3906c3fb27SDimitry Andric options::OPT_ffree_form, 4006c3fb27SDimitry Andric options::OPT_ffixed_line_length_EQ, 4106c3fb27SDimitry Andric options::OPT_fopenmp, 4206c3fb27SDimitry Andric options::OPT_fopenmp_version_EQ, 4306c3fb27SDimitry Andric options::OPT_fopenacc, 4406c3fb27SDimitry Andric options::OPT_finput_charset_EQ, 4506c3fb27SDimitry Andric options::OPT_fimplicit_none, 4606c3fb27SDimitry Andric options::OPT_fno_implicit_none, 4706c3fb27SDimitry Andric options::OPT_fbackslash, 4806c3fb27SDimitry Andric options::OPT_fno_backslash, 49fe6060f1SDimitry Andric options::OPT_flogical_abbreviations, 50fe6060f1SDimitry Andric options::OPT_fno_logical_abbreviations, 5106c3fb27SDimitry Andric options::OPT_fxor_operator, 5206c3fb27SDimitry Andric options::OPT_fno_xor_operator, 53fe6060f1SDimitry Andric options::OPT_falternative_parameter_statement, 5406c3fb27SDimitry Andric options::OPT_fdefault_real_8, 5506c3fb27SDimitry Andric options::OPT_fdefault_integer_8, 5606c3fb27SDimitry Andric options::OPT_fdefault_double_8, 5706c3fb27SDimitry Andric options::OPT_flarge_sizes, 584824e7fdSDimitry Andric options::OPT_fno_automatic}); 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)) { 13006c3fb27SDimitry Andric DebugInfoKind = llvm::codegenoptions::DebugLineTablesOnly; 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, 1515f757f3fSDimitry Andric options::OPT_flang_experimental_polymorphism, 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(); 1835f757f3fSDimitry Andric if (Val.equals("128") || Val.equals("256") || Val.equals("512") || 1845f757f3fSDimitry Andric Val.equals("1024") || Val.equals("2048") || Val.equals("128+") || 1855f757f3fSDimitry Andric Val.equals("256+") || Val.equals("512+") || Val.equals("1024+") || 1865f757f3fSDimitry Andric Val.equals("2048+")) { 1875f757f3fSDimitry Andric unsigned Bits = 0; 1885f757f3fSDimitry Andric if (Val.ends_with("+")) 1895f757f3fSDimitry Andric Val = Val.substr(0, Val.size() - 1); 1905f757f3fSDimitry Andric else { 1915f757f3fSDimitry Andric [[maybe_unused]] bool Invalid = Val.getAsInteger(10, Bits); 1925f757f3fSDimitry Andric assert(!Invalid && "Failed to parse value"); 1935f757f3fSDimitry Andric CmdArgs.push_back( 1945f757f3fSDimitry Andric Args.MakeArgString("-mvscale-max=" + llvm::Twine(Bits / 128))); 1955f757f3fSDimitry Andric } 1965f757f3fSDimitry Andric 1975f757f3fSDimitry Andric [[maybe_unused]] bool Invalid = Val.getAsInteger(10, Bits); 1985f757f3fSDimitry Andric assert(!Invalid && "Failed to parse value"); 1995f757f3fSDimitry Andric CmdArgs.push_back( 2005f757f3fSDimitry Andric Args.MakeArgString("-mvscale-min=" + llvm::Twine(Bits / 128))); 2015f757f3fSDimitry Andric // Silently drop requests for vector-length agnostic code as it's implied. 2025f757f3fSDimitry Andric } else if (!Val.equals("scalable")) 2035f757f3fSDimitry Andric // Handle the unsupported values passed to msve-vector-bits. 2045f757f3fSDimitry Andric D.Diag(diag::err_drv_unsupported_option_argument) 2055f757f3fSDimitry Andric << A->getSpelling() << Val; 2065f757f3fSDimitry Andric } 2075f757f3fSDimitry Andric } 2085f757f3fSDimitry Andric 209*297eecfbSDimitry Andric void Flang::AddRISCVTargetArgs(const ArgList &Args, 210*297eecfbSDimitry Andric ArgStringList &CmdArgs) const { 211*297eecfbSDimitry Andric const llvm::Triple &Triple = getToolChain().getTriple(); 212*297eecfbSDimitry Andric // Handle -mrvv-vector-bits=<bits> 213*297eecfbSDimitry Andric if (Arg *A = Args.getLastArg(options::OPT_mrvv_vector_bits_EQ)) { 214*297eecfbSDimitry Andric StringRef Val = A->getValue(); 215*297eecfbSDimitry Andric const Driver &D = getToolChain().getDriver(); 216*297eecfbSDimitry Andric 217*297eecfbSDimitry Andric // Get minimum VLen from march. 218*297eecfbSDimitry Andric unsigned MinVLen = 0; 219*297eecfbSDimitry Andric StringRef Arch = riscv::getRISCVArch(Args, Triple); 220*297eecfbSDimitry Andric auto ISAInfo = llvm::RISCVISAInfo::parseArchString( 221*297eecfbSDimitry Andric Arch, /*EnableExperimentalExtensions*/ true); 222*297eecfbSDimitry Andric // Ignore parsing error. 223*297eecfbSDimitry Andric if (!errorToBool(ISAInfo.takeError())) 224*297eecfbSDimitry Andric MinVLen = (*ISAInfo)->getMinVLen(); 225*297eecfbSDimitry Andric 226*297eecfbSDimitry Andric // If the value is "zvl", use MinVLen from march. Otherwise, try to parse 227*297eecfbSDimitry Andric // as integer as long as we have a MinVLen. 228*297eecfbSDimitry Andric unsigned Bits = 0; 229*297eecfbSDimitry Andric if (Val.equals("zvl") && MinVLen >= llvm::RISCV::RVVBitsPerBlock) { 230*297eecfbSDimitry Andric Bits = MinVLen; 231*297eecfbSDimitry Andric } else if (!Val.getAsInteger(10, Bits)) { 232*297eecfbSDimitry Andric // Only accept power of 2 values beteen RVVBitsPerBlock and 65536 that 233*297eecfbSDimitry Andric // at least MinVLen. 234*297eecfbSDimitry Andric if (Bits < MinVLen || Bits < llvm::RISCV::RVVBitsPerBlock || 235*297eecfbSDimitry Andric Bits > 65536 || !llvm::isPowerOf2_32(Bits)) 236*297eecfbSDimitry Andric Bits = 0; 237*297eecfbSDimitry Andric } 238*297eecfbSDimitry Andric 239*297eecfbSDimitry Andric // If we got a valid value try to use it. 240*297eecfbSDimitry Andric if (Bits != 0) { 241*297eecfbSDimitry Andric unsigned VScaleMin = Bits / llvm::RISCV::RVVBitsPerBlock; 242*297eecfbSDimitry Andric CmdArgs.push_back( 243*297eecfbSDimitry Andric Args.MakeArgString("-mvscale-max=" + llvm::Twine(VScaleMin))); 244*297eecfbSDimitry Andric CmdArgs.push_back( 245*297eecfbSDimitry Andric Args.MakeArgString("-mvscale-min=" + llvm::Twine(VScaleMin))); 246*297eecfbSDimitry Andric } else if (!Val.equals("scalable")) { 247*297eecfbSDimitry Andric // Handle the unsupported values passed to mrvv-vector-bits. 248*297eecfbSDimitry Andric D.Diag(diag::err_drv_unsupported_option_argument) 249*297eecfbSDimitry Andric << A->getSpelling() << Val; 250*297eecfbSDimitry Andric } 251*297eecfbSDimitry Andric } 252*297eecfbSDimitry Andric } 253*297eecfbSDimitry Andric 2545f757f3fSDimitry Andric static void addVSDefines(const ToolChain &TC, const ArgList &Args, 2555f757f3fSDimitry Andric ArgStringList &CmdArgs) { 2565f757f3fSDimitry Andric 2575f757f3fSDimitry Andric unsigned ver = 0; 2585f757f3fSDimitry Andric const VersionTuple vt = TC.computeMSVCVersion(nullptr, Args); 2595f757f3fSDimitry Andric ver = vt.getMajor() * 10000000 + vt.getMinor().value_or(0) * 100000 + 2605f757f3fSDimitry Andric vt.getSubminor().value_or(0); 2615f757f3fSDimitry Andric CmdArgs.push_back(Args.MakeArgString("-D_MSC_VER=" + Twine(ver / 100000))); 2625f757f3fSDimitry Andric CmdArgs.push_back(Args.MakeArgString("-D_MSC_FULL_VER=" + Twine(ver))); 2635f757f3fSDimitry Andric CmdArgs.push_back(Args.MakeArgString("-D_WIN32")); 2645f757f3fSDimitry Andric 2655f757f3fSDimitry Andric llvm::Triple triple = TC.getTriple(); 2665f757f3fSDimitry Andric if (triple.isAArch64()) { 2675f757f3fSDimitry Andric CmdArgs.push_back("-D_M_ARM64=1"); 2685f757f3fSDimitry Andric } else if (triple.isX86() && triple.isArch32Bit()) { 2695f757f3fSDimitry Andric CmdArgs.push_back("-D_M_IX86=600"); 2705f757f3fSDimitry Andric } else if (triple.isX86() && triple.isArch64Bit()) { 2715f757f3fSDimitry Andric CmdArgs.push_back("-D_M_X64=100"); 2725f757f3fSDimitry Andric } else { 2735f757f3fSDimitry Andric llvm_unreachable( 2745f757f3fSDimitry Andric "Flang on Windows only supports X86_32, X86_64 and AArch64"); 2755f757f3fSDimitry Andric } 2765f757f3fSDimitry Andric } 2775f757f3fSDimitry Andric 2785f757f3fSDimitry Andric static void processVSRuntimeLibrary(const ToolChain &TC, const ArgList &Args, 2795f757f3fSDimitry Andric ArgStringList &CmdArgs) { 2805f757f3fSDimitry Andric assert(TC.getTriple().isKnownWindowsMSVCEnvironment() && 2815f757f3fSDimitry Andric "can only add VS runtime library on Windows!"); 2825f757f3fSDimitry Andric // if -fno-fortran-main has been passed, skip linking Fortran_main.a 2835f757f3fSDimitry Andric bool LinkFortranMain = !Args.hasArg(options::OPT_no_fortran_main); 2845f757f3fSDimitry Andric if (TC.getTriple().isKnownWindowsMSVCEnvironment()) { 2855f757f3fSDimitry Andric CmdArgs.push_back(Args.MakeArgString( 2865f757f3fSDimitry Andric "--dependent-lib=" + TC.getCompilerRTBasename(Args, "builtins"))); 2875f757f3fSDimitry Andric } 2885f757f3fSDimitry Andric unsigned RTOptionID = options::OPT__SLASH_MT; 2895f757f3fSDimitry Andric if (auto *rtl = Args.getLastArg(options::OPT_fms_runtime_lib_EQ)) { 2905f757f3fSDimitry Andric RTOptionID = llvm::StringSwitch<unsigned>(rtl->getValue()) 2915f757f3fSDimitry Andric .Case("static", options::OPT__SLASH_MT) 2925f757f3fSDimitry Andric .Case("static_dbg", options::OPT__SLASH_MTd) 2935f757f3fSDimitry Andric .Case("dll", options::OPT__SLASH_MD) 2945f757f3fSDimitry Andric .Case("dll_dbg", options::OPT__SLASH_MDd) 2955f757f3fSDimitry Andric .Default(options::OPT__SLASH_MT); 2965f757f3fSDimitry Andric } 2975f757f3fSDimitry Andric switch (RTOptionID) { 2985f757f3fSDimitry Andric case options::OPT__SLASH_MT: 2995f757f3fSDimitry Andric CmdArgs.push_back("-D_MT"); 3005f757f3fSDimitry Andric CmdArgs.push_back("--dependent-lib=libcmt"); 3015f757f3fSDimitry Andric if (LinkFortranMain) 3025f757f3fSDimitry Andric CmdArgs.push_back("--dependent-lib=Fortran_main.static.lib"); 3035f757f3fSDimitry Andric CmdArgs.push_back("--dependent-lib=FortranRuntime.static.lib"); 3045f757f3fSDimitry Andric CmdArgs.push_back("--dependent-lib=FortranDecimal.static.lib"); 3055f757f3fSDimitry Andric break; 3065f757f3fSDimitry Andric case options::OPT__SLASH_MTd: 3075f757f3fSDimitry Andric CmdArgs.push_back("-D_MT"); 3085f757f3fSDimitry Andric CmdArgs.push_back("-D_DEBUG"); 3095f757f3fSDimitry Andric CmdArgs.push_back("--dependent-lib=libcmtd"); 3105f757f3fSDimitry Andric if (LinkFortranMain) 3115f757f3fSDimitry Andric CmdArgs.push_back("--dependent-lib=Fortran_main.static_dbg.lib"); 3125f757f3fSDimitry Andric CmdArgs.push_back("--dependent-lib=FortranRuntime.static_dbg.lib"); 3135f757f3fSDimitry Andric CmdArgs.push_back("--dependent-lib=FortranDecimal.static_dbg.lib"); 3145f757f3fSDimitry Andric break; 3155f757f3fSDimitry Andric case options::OPT__SLASH_MD: 3165f757f3fSDimitry Andric CmdArgs.push_back("-D_MT"); 3175f757f3fSDimitry Andric CmdArgs.push_back("-D_DLL"); 3185f757f3fSDimitry Andric CmdArgs.push_back("--dependent-lib=msvcrt"); 3195f757f3fSDimitry Andric if (LinkFortranMain) 3205f757f3fSDimitry Andric CmdArgs.push_back("--dependent-lib=Fortran_main.dynamic.lib"); 3215f757f3fSDimitry Andric CmdArgs.push_back("--dependent-lib=FortranRuntime.dynamic.lib"); 3225f757f3fSDimitry Andric CmdArgs.push_back("--dependent-lib=FortranDecimal.dynamic.lib"); 3235f757f3fSDimitry Andric break; 3245f757f3fSDimitry Andric case options::OPT__SLASH_MDd: 3255f757f3fSDimitry Andric CmdArgs.push_back("-D_MT"); 3265f757f3fSDimitry Andric CmdArgs.push_back("-D_DEBUG"); 3275f757f3fSDimitry Andric CmdArgs.push_back("-D_DLL"); 3285f757f3fSDimitry Andric CmdArgs.push_back("--dependent-lib=msvcrtd"); 3295f757f3fSDimitry Andric if (LinkFortranMain) 3305f757f3fSDimitry Andric CmdArgs.push_back("--dependent-lib=Fortran_main.dynamic_dbg.lib"); 3315f757f3fSDimitry Andric CmdArgs.push_back("--dependent-lib=FortranRuntime.dynamic_dbg.lib"); 3325f757f3fSDimitry Andric CmdArgs.push_back("--dependent-lib=FortranDecimal.dynamic_dbg.lib"); 3335f757f3fSDimitry Andric break; 3345f757f3fSDimitry Andric } 3355f757f3fSDimitry Andric } 3365f757f3fSDimitry Andric 3375f757f3fSDimitry Andric void Flang::AddAMDGPUTargetArgs(const ArgList &Args, 3385f757f3fSDimitry Andric ArgStringList &CmdArgs) const { 3395f757f3fSDimitry Andric if (Arg *A = Args.getLastArg(options::OPT_mcode_object_version_EQ)) { 3405f757f3fSDimitry Andric StringRef Val = A->getValue(); 3415f757f3fSDimitry Andric CmdArgs.push_back(Args.MakeArgString("-mcode-object-version=" + Val)); 3425f757f3fSDimitry Andric } 3435f757f3fSDimitry Andric } 3445f757f3fSDimitry Andric 345bdd1243dSDimitry Andric void Flang::addTargetOptions(const ArgList &Args, 346bdd1243dSDimitry Andric ArgStringList &CmdArgs) const { 347bdd1243dSDimitry Andric const ToolChain &TC = getToolChain(); 348bdd1243dSDimitry Andric const llvm::Triple &Triple = TC.getEffectiveTriple(); 349bdd1243dSDimitry Andric const Driver &D = TC.getDriver(); 350bdd1243dSDimitry Andric 351bdd1243dSDimitry Andric std::string CPU = getCPUName(D, Args, Triple); 352bdd1243dSDimitry Andric if (!CPU.empty()) { 353bdd1243dSDimitry Andric CmdArgs.push_back("-target-cpu"); 354bdd1243dSDimitry Andric CmdArgs.push_back(Args.MakeArgString(CPU)); 355bdd1243dSDimitry Andric } 356bdd1243dSDimitry Andric 357bdd1243dSDimitry Andric // Add the target features. 358bdd1243dSDimitry Andric switch (TC.getArch()) { 359bdd1243dSDimitry Andric default: 360bdd1243dSDimitry Andric break; 3615f757f3fSDimitry Andric case llvm::Triple::aarch64: 3625f757f3fSDimitry Andric getTargetFeatures(D, Triple, Args, CmdArgs, /*ForAs*/ false); 3635f757f3fSDimitry Andric AddAArch64TargetArgs(Args, CmdArgs); 3645f757f3fSDimitry Andric break; 3655f757f3fSDimitry Andric 36606c3fb27SDimitry Andric case llvm::Triple::r600: 36706c3fb27SDimitry Andric case llvm::Triple::amdgcn: 3685f757f3fSDimitry Andric getTargetFeatures(D, Triple, Args, CmdArgs, /*ForAs*/ false); 3695f757f3fSDimitry Andric AddAMDGPUTargetArgs(Args, CmdArgs); 3705f757f3fSDimitry Andric break; 37106c3fb27SDimitry Andric case llvm::Triple::riscv64: 372*297eecfbSDimitry Andric getTargetFeatures(D, Triple, Args, CmdArgs, /*ForAs*/ false); 373*297eecfbSDimitry Andric AddRISCVTargetArgs(Args, CmdArgs); 374*297eecfbSDimitry Andric break; 375bdd1243dSDimitry Andric case llvm::Triple::x86_64: 376bdd1243dSDimitry Andric getTargetFeatures(D, Triple, Args, CmdArgs, /*ForAs*/ false); 377bdd1243dSDimitry Andric break; 378bdd1243dSDimitry Andric } 379bdd1243dSDimitry Andric 3805f757f3fSDimitry Andric if (Arg *A = Args.getLastArg(options::OPT_fveclib)) { 3815f757f3fSDimitry Andric StringRef Name = A->getValue(); 3825f757f3fSDimitry Andric if (Name == "SVML") { 3835f757f3fSDimitry Andric if (Triple.getArch() != llvm::Triple::x86 && 3845f757f3fSDimitry Andric Triple.getArch() != llvm::Triple::x86_64) 3855f757f3fSDimitry Andric D.Diag(diag::err_drv_unsupported_opt_for_target) 3865f757f3fSDimitry Andric << Name << Triple.getArchName(); 3875f757f3fSDimitry Andric } else if (Name == "LIBMVEC-X86") { 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 == "SLEEF" || Name == "ArmPL") { 3935f757f3fSDimitry Andric if (Triple.getArch() != llvm::Triple::aarch64 && 3945f757f3fSDimitry Andric Triple.getArch() != llvm::Triple::aarch64_be) 3955f757f3fSDimitry Andric D.Diag(diag::err_drv_unsupported_opt_for_target) 3965f757f3fSDimitry Andric << Name << Triple.getArchName(); 3975f757f3fSDimitry Andric } 3985f757f3fSDimitry Andric 3995f757f3fSDimitry Andric if (Triple.isOSDarwin()) { 4005f757f3fSDimitry Andric // flang doesn't currently suport nostdlib, nodefaultlibs. Adding these 4015f757f3fSDimitry Andric // here incase they are added someday 4025f757f3fSDimitry Andric if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { 4035f757f3fSDimitry Andric if (A->getValue() == StringRef{"Accelerate"}) { 4045f757f3fSDimitry Andric CmdArgs.push_back("-framework"); 4055f757f3fSDimitry Andric CmdArgs.push_back("Accelerate"); 406*297eecfbSDimitry Andric } 407*297eecfbSDimitry Andric } 408*297eecfbSDimitry Andric } 4095f757f3fSDimitry Andric A->render(Args, CmdArgs); 4105f757f3fSDimitry Andric } 4115f757f3fSDimitry Andric 4125f757f3fSDimitry Andric if (Triple.isKnownWindowsMSVCEnvironment()) { 4135f757f3fSDimitry Andric processVSRuntimeLibrary(TC, Args, CmdArgs); 4145f757f3fSDimitry Andric addVSDefines(TC, Args, CmdArgs); 4155f757f3fSDimitry Andric } 4165f757f3fSDimitry Andric 417bdd1243dSDimitry Andric // TODO: Add target specific flags, ABI, mtune option etc. 418bdd1243dSDimitry Andric } 419bdd1243dSDimitry Andric 42006c3fb27SDimitry Andric void Flang::addOffloadOptions(Compilation &C, const InputInfoList &Inputs, 42106c3fb27SDimitry Andric const JobAction &JA, const ArgList &Args, 42206c3fb27SDimitry Andric ArgStringList &CmdArgs) const { 42306c3fb27SDimitry Andric bool IsOpenMPDevice = JA.isDeviceOffloading(Action::OFK_OpenMP); 42406c3fb27SDimitry Andric bool IsHostOffloadingAction = JA.isHostOffloading(Action::OFK_OpenMP) || 42506c3fb27SDimitry Andric JA.isHostOffloading(C.getActiveOffloadKinds()); 42606c3fb27SDimitry Andric 42706c3fb27SDimitry Andric // Skips the primary input file, which is the input file that the compilation 42806c3fb27SDimitry Andric // proccess will be executed upon (e.g. the host bitcode file) and 42906c3fb27SDimitry Andric // adds other secondary input (e.g. device bitcode files for embedding to the 43006c3fb27SDimitry Andric // -fembed-offload-object argument or the host IR file for proccessing 43106c3fb27SDimitry Andric // during device compilation to the fopenmp-host-ir-file-path argument via 43206c3fb27SDimitry Andric // OpenMPDeviceInput). This is condensed logic from the ConstructJob 43306c3fb27SDimitry Andric // function inside of the Clang driver for pushing on further input arguments 43406c3fb27SDimitry Andric // needed for offloading during various phases of compilation. 43506c3fb27SDimitry Andric for (size_t i = 1; i < Inputs.size(); ++i) { 43606c3fb27SDimitry Andric if (Inputs[i].getType() == types::TY_Nothing) { 43706c3fb27SDimitry Andric // contains nothing, so it's skippable 43806c3fb27SDimitry Andric } else if (IsHostOffloadingAction) { 43906c3fb27SDimitry Andric CmdArgs.push_back( 44006c3fb27SDimitry Andric Args.MakeArgString("-fembed-offload-object=" + 44106c3fb27SDimitry Andric getToolChain().getInputFilename(Inputs[i]))); 44206c3fb27SDimitry Andric } else if (IsOpenMPDevice) { 44306c3fb27SDimitry Andric if (Inputs[i].getFilename()) { 44406c3fb27SDimitry Andric CmdArgs.push_back("-fopenmp-host-ir-file-path"); 44506c3fb27SDimitry Andric CmdArgs.push_back(Args.MakeArgString(Inputs[i].getFilename())); 44606c3fb27SDimitry Andric } else { 44706c3fb27SDimitry Andric llvm_unreachable("missing openmp host-ir file for device offloading"); 44806c3fb27SDimitry Andric } 44906c3fb27SDimitry Andric } else { 45006c3fb27SDimitry Andric llvm_unreachable( 45106c3fb27SDimitry Andric "unexpectedly given multiple inputs or given unknown input"); 45206c3fb27SDimitry Andric } 45306c3fb27SDimitry Andric } 45406c3fb27SDimitry Andric 45506c3fb27SDimitry Andric if (IsOpenMPDevice) { 45606c3fb27SDimitry Andric // -fopenmp-is-target-device is passed along to tell the frontend that it is 45706c3fb27SDimitry Andric // generating code for a device, so that only the relevant code is emitted. 45806c3fb27SDimitry Andric CmdArgs.push_back("-fopenmp-is-target-device"); 45906c3fb27SDimitry Andric 46006c3fb27SDimitry Andric // When in OpenMP offloading mode, enable debugging on the device. 46106c3fb27SDimitry Andric Args.AddAllArgs(CmdArgs, options::OPT_fopenmp_target_debug_EQ); 46206c3fb27SDimitry Andric if (Args.hasFlag(options::OPT_fopenmp_target_debug, 46306c3fb27SDimitry Andric options::OPT_fno_openmp_target_debug, /*Default=*/false)) 46406c3fb27SDimitry Andric CmdArgs.push_back("-fopenmp-target-debug"); 46506c3fb27SDimitry Andric 46606c3fb27SDimitry Andric // When in OpenMP offloading mode, forward assumptions information about 46706c3fb27SDimitry Andric // thread and team counts in the device. 46806c3fb27SDimitry Andric if (Args.hasFlag(options::OPT_fopenmp_assume_teams_oversubscription, 46906c3fb27SDimitry Andric options::OPT_fno_openmp_assume_teams_oversubscription, 47006c3fb27SDimitry Andric /*Default=*/false)) 47106c3fb27SDimitry Andric CmdArgs.push_back("-fopenmp-assume-teams-oversubscription"); 47206c3fb27SDimitry Andric if (Args.hasFlag(options::OPT_fopenmp_assume_threads_oversubscription, 47306c3fb27SDimitry Andric options::OPT_fno_openmp_assume_threads_oversubscription, 47406c3fb27SDimitry Andric /*Default=*/false)) 47506c3fb27SDimitry Andric CmdArgs.push_back("-fopenmp-assume-threads-oversubscription"); 47606c3fb27SDimitry Andric if (Args.hasArg(options::OPT_fopenmp_assume_no_thread_state)) 47706c3fb27SDimitry Andric CmdArgs.push_back("-fopenmp-assume-no-thread-state"); 47806c3fb27SDimitry Andric if (Args.hasArg(options::OPT_fopenmp_assume_no_nested_parallelism)) 47906c3fb27SDimitry Andric CmdArgs.push_back("-fopenmp-assume-no-nested-parallelism"); 480*297eecfbSDimitry Andric if (Args.hasArg(options::OPT_nogpulib)) 481*297eecfbSDimitry Andric CmdArgs.push_back("-nogpulib"); 48206c3fb27SDimitry Andric } 48306c3fb27SDimitry Andric } 48406c3fb27SDimitry Andric 485bdd1243dSDimitry Andric static void addFloatingPointOptions(const Driver &D, const ArgList &Args, 486bdd1243dSDimitry Andric ArgStringList &CmdArgs) { 487bdd1243dSDimitry Andric StringRef FPContract; 488bdd1243dSDimitry Andric bool HonorINFs = true; 489bdd1243dSDimitry Andric bool HonorNaNs = true; 490bdd1243dSDimitry Andric bool ApproxFunc = false; 491bdd1243dSDimitry Andric bool SignedZeros = true; 492bdd1243dSDimitry Andric bool AssociativeMath = false; 493bdd1243dSDimitry Andric bool ReciprocalMath = false; 494bdd1243dSDimitry Andric 495bdd1243dSDimitry Andric if (const Arg *A = Args.getLastArg(options::OPT_ffp_contract)) { 496bdd1243dSDimitry Andric const StringRef Val = A->getValue(); 497bdd1243dSDimitry Andric if (Val == "fast" || Val == "off") { 498bdd1243dSDimitry Andric FPContract = Val; 499bdd1243dSDimitry Andric } else if (Val == "on") { 500bdd1243dSDimitry Andric // Warn instead of error because users might have makefiles written for 501bdd1243dSDimitry Andric // gfortran (which accepts -ffp-contract=on) 502bdd1243dSDimitry Andric D.Diag(diag::warn_drv_unsupported_option_for_flang) 503bdd1243dSDimitry Andric << Val << A->getOption().getName() << "off"; 504bdd1243dSDimitry Andric FPContract = "off"; 505bdd1243dSDimitry Andric } else 506bdd1243dSDimitry Andric // Clang's "fast-honor-pragmas" option is not supported because it is 507bdd1243dSDimitry Andric // non-standard 508bdd1243dSDimitry Andric D.Diag(diag::err_drv_unsupported_option_argument) 509bdd1243dSDimitry Andric << A->getSpelling() << Val; 510bdd1243dSDimitry Andric } 511bdd1243dSDimitry Andric 512bdd1243dSDimitry Andric for (const Arg *A : Args) { 513bdd1243dSDimitry Andric auto optId = A->getOption().getID(); 514bdd1243dSDimitry Andric switch (optId) { 515bdd1243dSDimitry Andric // if this isn't an FP option, skip the claim below 516bdd1243dSDimitry Andric default: 517bdd1243dSDimitry Andric continue; 518bdd1243dSDimitry Andric 519bdd1243dSDimitry Andric case options::OPT_fhonor_infinities: 520bdd1243dSDimitry Andric HonorINFs = true; 521bdd1243dSDimitry Andric break; 522bdd1243dSDimitry Andric case options::OPT_fno_honor_infinities: 523bdd1243dSDimitry Andric HonorINFs = false; 524bdd1243dSDimitry Andric break; 525bdd1243dSDimitry Andric case options::OPT_fhonor_nans: 526bdd1243dSDimitry Andric HonorNaNs = true; 527bdd1243dSDimitry Andric break; 528bdd1243dSDimitry Andric case options::OPT_fno_honor_nans: 529bdd1243dSDimitry Andric HonorNaNs = false; 530bdd1243dSDimitry Andric break; 531bdd1243dSDimitry Andric case options::OPT_fapprox_func: 532bdd1243dSDimitry Andric ApproxFunc = true; 533bdd1243dSDimitry Andric break; 534bdd1243dSDimitry Andric case options::OPT_fno_approx_func: 535bdd1243dSDimitry Andric ApproxFunc = false; 536bdd1243dSDimitry Andric break; 537bdd1243dSDimitry Andric case options::OPT_fsigned_zeros: 538bdd1243dSDimitry Andric SignedZeros = true; 539bdd1243dSDimitry Andric break; 540bdd1243dSDimitry Andric case options::OPT_fno_signed_zeros: 541bdd1243dSDimitry Andric SignedZeros = false; 542bdd1243dSDimitry Andric break; 543bdd1243dSDimitry Andric case options::OPT_fassociative_math: 544bdd1243dSDimitry Andric AssociativeMath = true; 545bdd1243dSDimitry Andric break; 546bdd1243dSDimitry Andric case options::OPT_fno_associative_math: 547bdd1243dSDimitry Andric AssociativeMath = false; 548bdd1243dSDimitry Andric break; 549bdd1243dSDimitry Andric case options::OPT_freciprocal_math: 550bdd1243dSDimitry Andric ReciprocalMath = true; 551bdd1243dSDimitry Andric break; 552bdd1243dSDimitry Andric case options::OPT_fno_reciprocal_math: 553bdd1243dSDimitry Andric ReciprocalMath = false; 554bdd1243dSDimitry Andric break; 555bdd1243dSDimitry Andric case options::OPT_Ofast: 556bdd1243dSDimitry Andric [[fallthrough]]; 557bdd1243dSDimitry Andric case options::OPT_ffast_math: 558bdd1243dSDimitry Andric HonorINFs = false; 559bdd1243dSDimitry Andric HonorNaNs = false; 560bdd1243dSDimitry Andric AssociativeMath = true; 561bdd1243dSDimitry Andric ReciprocalMath = true; 562bdd1243dSDimitry Andric ApproxFunc = true; 563bdd1243dSDimitry Andric SignedZeros = false; 564bdd1243dSDimitry Andric FPContract = "fast"; 565bdd1243dSDimitry Andric break; 566bdd1243dSDimitry Andric case options::OPT_fno_fast_math: 567bdd1243dSDimitry Andric HonorINFs = true; 568bdd1243dSDimitry Andric HonorNaNs = true; 569bdd1243dSDimitry Andric AssociativeMath = false; 570bdd1243dSDimitry Andric ReciprocalMath = false; 571bdd1243dSDimitry Andric ApproxFunc = false; 572bdd1243dSDimitry Andric SignedZeros = true; 573bdd1243dSDimitry Andric // -fno-fast-math should undo -ffast-math so I return FPContract to the 574bdd1243dSDimitry Andric // default. It is important to check it is "fast" (the default) so that 575bdd1243dSDimitry Andric // --ffp-contract=off -fno-fast-math --> -ffp-contract=off 576bdd1243dSDimitry Andric if (FPContract == "fast") 577bdd1243dSDimitry Andric FPContract = ""; 578bdd1243dSDimitry Andric break; 579bdd1243dSDimitry Andric } 580bdd1243dSDimitry Andric 581bdd1243dSDimitry Andric // If we handled this option claim it 582bdd1243dSDimitry Andric A->claim(); 583bdd1243dSDimitry Andric } 584bdd1243dSDimitry Andric 585bdd1243dSDimitry Andric if (!HonorINFs && !HonorNaNs && AssociativeMath && ReciprocalMath && 586bdd1243dSDimitry Andric ApproxFunc && !SignedZeros && 587bdd1243dSDimitry Andric (FPContract == "fast" || FPContract == "")) { 588bdd1243dSDimitry Andric CmdArgs.push_back("-ffast-math"); 589bdd1243dSDimitry Andric return; 590bdd1243dSDimitry Andric } 591bdd1243dSDimitry Andric 592bdd1243dSDimitry Andric if (!FPContract.empty()) 593bdd1243dSDimitry Andric CmdArgs.push_back(Args.MakeArgString("-ffp-contract=" + FPContract)); 594bdd1243dSDimitry Andric 595bdd1243dSDimitry Andric if (!HonorINFs) 596bdd1243dSDimitry Andric CmdArgs.push_back("-menable-no-infs"); 597bdd1243dSDimitry Andric 598bdd1243dSDimitry Andric if (!HonorNaNs) 599bdd1243dSDimitry Andric CmdArgs.push_back("-menable-no-nans"); 600bdd1243dSDimitry Andric 601bdd1243dSDimitry Andric if (ApproxFunc) 602bdd1243dSDimitry Andric CmdArgs.push_back("-fapprox-func"); 603bdd1243dSDimitry Andric 604bdd1243dSDimitry Andric if (!SignedZeros) 605bdd1243dSDimitry Andric CmdArgs.push_back("-fno-signed-zeros"); 606bdd1243dSDimitry Andric 607bdd1243dSDimitry Andric if (AssociativeMath && !SignedZeros) 608bdd1243dSDimitry Andric CmdArgs.push_back("-mreassociate"); 609bdd1243dSDimitry Andric 610bdd1243dSDimitry Andric if (ReciprocalMath) 611bdd1243dSDimitry Andric CmdArgs.push_back("-freciprocal-math"); 612e8d8bef9SDimitry Andric } 613e8d8bef9SDimitry Andric 6145f757f3fSDimitry Andric static void renderRemarksOptions(const ArgList &Args, ArgStringList &CmdArgs, 6155f757f3fSDimitry Andric const InputInfo &Input) { 6165f757f3fSDimitry Andric StringRef Format = "yaml"; 6175f757f3fSDimitry Andric if (const Arg *A = Args.getLastArg(options::OPT_fsave_optimization_record_EQ)) 6185f757f3fSDimitry Andric Format = A->getValue(); 6195f757f3fSDimitry Andric 6205f757f3fSDimitry Andric CmdArgs.push_back("-opt-record-file"); 6215f757f3fSDimitry Andric 6225f757f3fSDimitry Andric const Arg *A = Args.getLastArg(options::OPT_foptimization_record_file_EQ); 6235f757f3fSDimitry Andric if (A) { 6245f757f3fSDimitry Andric CmdArgs.push_back(A->getValue()); 6255f757f3fSDimitry Andric } else { 6265f757f3fSDimitry Andric SmallString<128> F; 6275f757f3fSDimitry Andric 6285f757f3fSDimitry Andric if (Args.hasArg(options::OPT_c) || Args.hasArg(options::OPT_S)) { 6295f757f3fSDimitry Andric if (Arg *FinalOutput = Args.getLastArg(options::OPT_o)) 6305f757f3fSDimitry Andric F = FinalOutput->getValue(); 6315f757f3fSDimitry Andric } 6325f757f3fSDimitry Andric 6335f757f3fSDimitry Andric if (F.empty()) { 6345f757f3fSDimitry Andric // Use the input filename. 6355f757f3fSDimitry Andric F = llvm::sys::path::stem(Input.getBaseInput()); 6365f757f3fSDimitry Andric } 6375f757f3fSDimitry Andric 6385f757f3fSDimitry Andric SmallString<32> Extension; 6395f757f3fSDimitry Andric Extension += "opt."; 6405f757f3fSDimitry Andric Extension += Format; 6415f757f3fSDimitry Andric 6425f757f3fSDimitry Andric llvm::sys::path::replace_extension(F, Extension); 6435f757f3fSDimitry Andric CmdArgs.push_back(Args.MakeArgString(F)); 6445f757f3fSDimitry Andric } 6455f757f3fSDimitry Andric 6465f757f3fSDimitry Andric if (const Arg *A = 6475f757f3fSDimitry Andric Args.getLastArg(options::OPT_foptimization_record_passes_EQ)) { 6485f757f3fSDimitry Andric CmdArgs.push_back("-opt-record-passes"); 6495f757f3fSDimitry Andric CmdArgs.push_back(A->getValue()); 6505f757f3fSDimitry Andric } 6515f757f3fSDimitry Andric 6525f757f3fSDimitry Andric if (!Format.empty()) { 6535f757f3fSDimitry Andric CmdArgs.push_back("-opt-record-format"); 6545f757f3fSDimitry Andric CmdArgs.push_back(Format.data()); 6555f757f3fSDimitry Andric } 6565f757f3fSDimitry Andric } 6575f757f3fSDimitry Andric 658480093f4SDimitry Andric void Flang::ConstructJob(Compilation &C, const JobAction &JA, 659480093f4SDimitry Andric const InputInfo &Output, const InputInfoList &Inputs, 660480093f4SDimitry Andric const ArgList &Args, const char *LinkingOutput) const { 661480093f4SDimitry Andric const auto &TC = getToolChain(); 66281ad6265SDimitry Andric const llvm::Triple &Triple = TC.getEffectiveTriple(); 66381ad6265SDimitry Andric const std::string &TripleStr = Triple.getTriple(); 664480093f4SDimitry Andric 66581ad6265SDimitry Andric const Driver &D = TC.getDriver(); 666480093f4SDimitry Andric ArgStringList CmdArgs; 66706c3fb27SDimitry Andric DiagnosticsEngine &Diags = D.getDiags(); 668480093f4SDimitry Andric 669e8d8bef9SDimitry Andric // Invoke ourselves in -fc1 mode. 670480093f4SDimitry Andric CmdArgs.push_back("-fc1"); 671480093f4SDimitry Andric 672e8d8bef9SDimitry Andric // Add the "effective" target triple. 67381ad6265SDimitry Andric CmdArgs.push_back("-triple"); 67481ad6265SDimitry Andric CmdArgs.push_back(Args.MakeArgString(TripleStr)); 675480093f4SDimitry Andric 676480093f4SDimitry Andric if (isa<PreprocessJobAction>(JA)) { 677480093f4SDimitry Andric CmdArgs.push_back("-E"); 678480093f4SDimitry Andric } else if (isa<CompileJobAction>(JA) || isa<BackendJobAction>(JA)) { 679480093f4SDimitry Andric if (JA.getType() == types::TY_Nothing) { 680480093f4SDimitry Andric CmdArgs.push_back("-fsyntax-only"); 681480093f4SDimitry Andric } else if (JA.getType() == types::TY_AST) { 682480093f4SDimitry Andric CmdArgs.push_back("-emit-ast"); 683480093f4SDimitry Andric } else if (JA.getType() == types::TY_LLVM_IR || 684480093f4SDimitry Andric JA.getType() == types::TY_LTO_IR) { 685480093f4SDimitry Andric CmdArgs.push_back("-emit-llvm"); 686480093f4SDimitry Andric } else if (JA.getType() == types::TY_LLVM_BC || 687480093f4SDimitry Andric JA.getType() == types::TY_LTO_BC) { 688480093f4SDimitry Andric CmdArgs.push_back("-emit-llvm-bc"); 689480093f4SDimitry Andric } else if (JA.getType() == types::TY_PP_Asm) { 690480093f4SDimitry Andric CmdArgs.push_back("-S"); 691480093f4SDimitry Andric } else { 692480093f4SDimitry Andric assert(false && "Unexpected output type!"); 693480093f4SDimitry Andric } 694480093f4SDimitry Andric } else if (isa<AssembleJobAction>(JA)) { 695480093f4SDimitry Andric CmdArgs.push_back("-emit-obj"); 696480093f4SDimitry Andric } else { 697480093f4SDimitry Andric assert(false && "Unexpected action class for Flang tool."); 698480093f4SDimitry Andric } 699480093f4SDimitry Andric 700e8d8bef9SDimitry Andric const InputInfo &Input = Inputs[0]; 701e8d8bef9SDimitry Andric types::ID InputType = Input.getType(); 702e8d8bef9SDimitry Andric 703e8d8bef9SDimitry Andric // Add preprocessing options like -I, -D, etc. if we are using the 704e8d8bef9SDimitry Andric // preprocessor (i.e. skip when dealing with e.g. binary files). 705e8d8bef9SDimitry Andric if (types::getPreprocessedType(InputType) != types::TY_INVALID) 706bdd1243dSDimitry Andric addPreprocessingOptions(Args, CmdArgs); 707e8d8bef9SDimitry Andric 708bdd1243dSDimitry Andric addFortranDialectOptions(Args, CmdArgs); 709fe6060f1SDimitry Andric 71081ad6265SDimitry Andric // Color diagnostics are parsed by the driver directly from argv and later 71181ad6265SDimitry Andric // re-parsed to construct this job; claim any possible color diagnostic here 71281ad6265SDimitry Andric // to avoid warn_drv_unused_argument. 71381ad6265SDimitry Andric Args.getLastArg(options::OPT_fcolor_diagnostics, 71481ad6265SDimitry Andric options::OPT_fno_color_diagnostics); 71506c3fb27SDimitry Andric if (Diags.getDiagnosticOptions().ShowColors) 71681ad6265SDimitry Andric CmdArgs.push_back("-fcolor-diagnostics"); 71781ad6265SDimitry Andric 71806c3fb27SDimitry Andric // LTO mode is parsed by the Clang driver library. 71906c3fb27SDimitry Andric LTOKind LTOMode = D.getLTOMode(/* IsOffload */ false); 72006c3fb27SDimitry Andric assert(LTOMode != LTOK_Unknown && "Unknown LTO mode."); 72106c3fb27SDimitry Andric if (LTOMode == LTOK_Full) 72206c3fb27SDimitry Andric CmdArgs.push_back("-flto=full"); 72306c3fb27SDimitry Andric else if (LTOMode == LTOK_Thin) { 72406c3fb27SDimitry Andric Diags.Report( 72506c3fb27SDimitry Andric Diags.getCustomDiagID(DiagnosticsEngine::Warning, 72606c3fb27SDimitry Andric "the option '-flto=thin' is a work in progress")); 72706c3fb27SDimitry Andric CmdArgs.push_back("-flto=thin"); 72806c3fb27SDimitry Andric } 72906c3fb27SDimitry Andric 730bdd1243dSDimitry Andric // -fPIC and related options. 731bdd1243dSDimitry Andric addPicOptions(Args, CmdArgs); 732bdd1243dSDimitry Andric 733bdd1243dSDimitry Andric // Floating point related options 734bdd1243dSDimitry Andric addFloatingPointOptions(D, Args, CmdArgs); 735bdd1243dSDimitry Andric 736bdd1243dSDimitry Andric // Add target args, features, etc. 737bdd1243dSDimitry Andric addTargetOptions(Args, CmdArgs); 738bdd1243dSDimitry Andric 73906c3fb27SDimitry Andric // Add Codegen options 74006c3fb27SDimitry Andric addCodegenOptions(Args, CmdArgs); 74106c3fb27SDimitry Andric 7425f757f3fSDimitry Andric // Add R Group options 7435f757f3fSDimitry Andric Args.AddAllArgs(CmdArgs, options::OPT_R_Group); 7445f757f3fSDimitry Andric 7455f757f3fSDimitry Andric // Remarks can be enabled with any of the `-f.*optimization-record.*` flags. 7465f757f3fSDimitry Andric if (willEmitRemarks(Args)) 7475f757f3fSDimitry Andric renderRemarksOptions(Args, CmdArgs, Input); 7485f757f3fSDimitry Andric 749fe6060f1SDimitry Andric // Add other compile options 750bdd1243dSDimitry Andric addOtherOptions(Args, CmdArgs); 751fe6060f1SDimitry Andric 75206c3fb27SDimitry Andric // Offloading related options 75306c3fb27SDimitry Andric addOffloadOptions(C, Inputs, JA, Args, CmdArgs); 75406c3fb27SDimitry Andric 755fe6060f1SDimitry Andric // Forward -Xflang arguments to -fc1 756fe6060f1SDimitry Andric Args.AddAllArgValues(CmdArgs, options::OPT_Xflang); 757fe6060f1SDimitry Andric 7585f757f3fSDimitry Andric CodeGenOptions::FramePointerKind FPKeepKind = 7595f757f3fSDimitry Andric getFramePointerKind(Args, Triple); 7605f757f3fSDimitry Andric 7615f757f3fSDimitry Andric const char *FPKeepKindStr = nullptr; 7625f757f3fSDimitry Andric switch (FPKeepKind) { 7635f757f3fSDimitry Andric case CodeGenOptions::FramePointerKind::None: 7645f757f3fSDimitry Andric FPKeepKindStr = "-mframe-pointer=none"; 7655f757f3fSDimitry Andric break; 7665f757f3fSDimitry Andric case CodeGenOptions::FramePointerKind::NonLeaf: 7675f757f3fSDimitry Andric FPKeepKindStr = "-mframe-pointer=non-leaf"; 7685f757f3fSDimitry Andric break; 7695f757f3fSDimitry Andric case CodeGenOptions::FramePointerKind::All: 7705f757f3fSDimitry Andric FPKeepKindStr = "-mframe-pointer=all"; 7715f757f3fSDimitry Andric break; 7725f757f3fSDimitry Andric } 7735f757f3fSDimitry Andric assert(FPKeepKindStr && "unknown FramePointerKind"); 7745f757f3fSDimitry Andric CmdArgs.push_back(FPKeepKindStr); 7755f757f3fSDimitry Andric 77681ad6265SDimitry Andric // Forward -mllvm options to the LLVM option parser. In practice, this means 77781ad6265SDimitry Andric // forwarding to `-fc1` as that's where the LLVM parser is run. 77881ad6265SDimitry Andric for (const Arg *A : Args.filtered(options::OPT_mllvm)) { 77981ad6265SDimitry Andric A->claim(); 78081ad6265SDimitry Andric A->render(Args, CmdArgs); 78181ad6265SDimitry Andric } 78281ad6265SDimitry Andric 78381ad6265SDimitry Andric for (const Arg *A : Args.filtered(options::OPT_mmlir)) { 78481ad6265SDimitry Andric A->claim(); 78581ad6265SDimitry Andric A->render(Args, CmdArgs); 78681ad6265SDimitry Andric } 78781ad6265SDimitry Andric 78806c3fb27SDimitry Andric // Remove any unsupported gfortran diagnostic options 78906c3fb27SDimitry Andric for (const Arg *A : Args.filtered(options::OPT_flang_ignored_w_Group)) { 79006c3fb27SDimitry Andric A->claim(); 79106c3fb27SDimitry Andric D.Diag(diag::warn_drv_unsupported_diag_option_for_flang) 79206c3fb27SDimitry Andric << A->getOption().getName(); 79306c3fb27SDimitry Andric } 79406c3fb27SDimitry Andric 79581ad6265SDimitry Andric // Optimization level for CodeGen. 79681ad6265SDimitry Andric if (const Arg *A = Args.getLastArg(options::OPT_O_Group)) { 79781ad6265SDimitry Andric if (A->getOption().matches(options::OPT_O4)) { 79881ad6265SDimitry Andric CmdArgs.push_back("-O3"); 79981ad6265SDimitry Andric D.Diag(diag::warn_O4_is_O3); 800bdd1243dSDimitry Andric } else if (A->getOption().matches(options::OPT_Ofast)) { 801bdd1243dSDimitry Andric CmdArgs.push_back("-O3"); 80281ad6265SDimitry Andric } else { 80381ad6265SDimitry Andric A->render(Args, CmdArgs); 80481ad6265SDimitry Andric } 80581ad6265SDimitry Andric } 80681ad6265SDimitry Andric 8075f757f3fSDimitry Andric assert((Output.isFilename() || Output.isNothing()) && "Invalid output."); 808480093f4SDimitry Andric if (Output.isFilename()) { 809480093f4SDimitry Andric CmdArgs.push_back("-o"); 810480093f4SDimitry Andric CmdArgs.push_back(Output.getFilename()); 811480093f4SDimitry Andric } 812480093f4SDimitry Andric 813480093f4SDimitry Andric assert(Input.isFilename() && "Invalid input."); 81481ad6265SDimitry Andric 81506c3fb27SDimitry Andric if (Args.getLastArg(options::OPT_save_temps_EQ)) 81606c3fb27SDimitry Andric Args.AddLastArg(CmdArgs, options::OPT_save_temps_EQ); 81706c3fb27SDimitry Andric 81881ad6265SDimitry Andric addDashXForInput(Args, Input, CmdArgs); 81981ad6265SDimitry Andric 820480093f4SDimitry Andric CmdArgs.push_back(Input.getFilename()); 821480093f4SDimitry Andric 822e8d8bef9SDimitry Andric // TODO: Replace flang-new with flang once the new driver replaces the 823e8d8bef9SDimitry Andric // throwaway driver 824e8d8bef9SDimitry Andric const char *Exec = Args.MakeArgString(D.GetProgramPath("flang-new", TC)); 825e8d8bef9SDimitry Andric C.addCommand(std::make_unique<Command>(JA, *this, 826e8d8bef9SDimitry Andric ResponseFileSupport::AtFileUTF8(), 827e8d8bef9SDimitry Andric Exec, CmdArgs, Inputs, Output)); 828480093f4SDimitry Andric } 829480093f4SDimitry Andric 830e8d8bef9SDimitry Andric Flang::Flang(const ToolChain &TC) : Tool("flang-new", "flang frontend", TC) {} 831480093f4SDimitry Andric 832480093f4SDimitry Andric Flang::~Flang() {} 833