diff options
Diffstat (limited to 'lib/Driver/ToolChains/Gnu.cpp')
-rw-r--r-- | lib/Driver/ToolChains/Gnu.cpp | 2429 |
1 files changed, 2429 insertions, 0 deletions
diff --git a/lib/Driver/ToolChains/Gnu.cpp b/lib/Driver/ToolChains/Gnu.cpp new file mode 100644 index 0000000000..6425850cd8 --- /dev/null +++ b/lib/Driver/ToolChains/Gnu.cpp @@ -0,0 +1,2429 @@ +//===--- Gnu.cpp - Gnu Tool and ToolChain Implementations -------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "Gnu.h" +#include "Linux.h" +#include "Arch/ARM.h" +#include "Arch/Mips.h" +#include "Arch/Sparc.h" +#include "Arch/SystemZ.h" +#include "CommonArgs.h" +#include "clang/Basic/VirtualFileSystem.h" +#include "clang/Config/config.h" // for GCC_INSTALL_PREFIX +#include "clang/Driver/Compilation.h" +#include "clang/Driver/Driver.h" +#include "clang/Driver/DriverDiagnostic.h" +#include "clang/Driver/Options.h" +#include "clang/Driver/Tool.h" +#include "llvm/Option/ArgList.h" +#include "llvm/Support/CodeGen.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/TargetParser.h" +#include <system_error> + +using namespace clang::driver; +using namespace clang::driver::toolchains; +using namespace clang; +using namespace llvm::opt; + +void tools::GnuTool::anchor() {} + +static bool forwardToGCC(const Option &O) { + // Don't forward inputs from the original command line. They are added from + // InputInfoList. + return O.getKind() != Option::InputClass && + !O.hasFlag(options::DriverOption) && !O.hasFlag(options::LinkerInput); +} + +void tools::gcc::Common::ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, + const InputInfoList &Inputs, + const ArgList &Args, + const char *LinkingOutput) const { + const Driver &D = getToolChain().getDriver(); + ArgStringList CmdArgs; + + for (const auto &A : Args) { + if (forwardToGCC(A->getOption())) { + // It is unfortunate that we have to claim here, as this means + // we will basically never report anything interesting for + // platforms using a generic gcc, even if we are just using gcc + // to get to the assembler. + A->claim(); + + // Don't forward any -g arguments to assembly steps. + if (isa<AssembleJobAction>(JA) && + A->getOption().matches(options::OPT_g_Group)) + continue; + + // Don't forward any -W arguments to assembly and link steps. + if ((isa<AssembleJobAction>(JA) || isa<LinkJobAction>(JA)) && + A->getOption().matches(options::OPT_W_Group)) + continue; + + A->render(Args, CmdArgs); + } + } + + RenderExtraToolArgs(JA, CmdArgs); + + // If using a driver driver, force the arch. + if (getToolChain().getTriple().isOSDarwin()) { + CmdArgs.push_back("-arch"); + CmdArgs.push_back( + Args.MakeArgString(getToolChain().getDefaultUniversalArchName())); + } + + // Try to force gcc to match the tool chain we want, if we recognize + // the arch. + // + // FIXME: The triple class should directly provide the information we want + // here. + switch (getToolChain().getArch()) { + default: + break; + case llvm::Triple::x86: + case llvm::Triple::ppc: + CmdArgs.push_back("-m32"); + break; + case llvm::Triple::x86_64: + case llvm::Triple::ppc64: + case llvm::Triple::ppc64le: + CmdArgs.push_back("-m64"); + break; + case llvm::Triple::sparcel: + CmdArgs.push_back("-EL"); + break; + } + + if (Output.isFilename()) { + CmdArgs.push_back("-o"); + CmdArgs.push_back(Output.getFilename()); + } else { + assert(Output.isNothing() && "Unexpected output"); + CmdArgs.push_back("-fsyntax-only"); + } + + Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler); + + // Only pass -x if gcc will understand it; otherwise hope gcc + // understands the suffix correctly. The main use case this would go + // wrong in is for linker inputs if they happened to have an odd + // suffix; really the only way to get this to happen is a command + // like '-x foobar a.c' which will treat a.c like a linker input. + // + // FIXME: For the linker case specifically, can we safely convert + // inputs into '-Wl,' options? + for (const auto &II : Inputs) { + // Don't try to pass LLVM or AST inputs to a generic gcc. + if (types::isLLVMIR(II.getType())) + D.Diag(clang::diag::err_drv_no_linker_llvm_support) + << getToolChain().getTripleString(); + else if (II.getType() == types::TY_AST) + D.Diag(diag::err_drv_no_ast_support) << getToolChain().getTripleString(); + else if (II.getType() == types::TY_ModuleFile) + D.Diag(diag::err_drv_no_module_support) + << getToolChain().getTripleString(); + + if (types::canTypeBeUserSpecified(II.getType())) { + CmdArgs.push_back("-x"); + CmdArgs.push_back(types::getTypeName(II.getType())); + } + + if (II.isFilename()) + CmdArgs.push_back(II.getFilename()); + else { + const Arg &A = II.getInputArg(); + + // Reverse translate some rewritten options. + if (A.getOption().matches(options::OPT_Z_reserved_lib_stdcxx)) { + CmdArgs.push_back("-lstdc++"); + continue; + } + + // Don't render as input, we need gcc to do the translations. + A.render(Args, CmdArgs); + } + } + + const std::string &customGCCName = D.getCCCGenericGCCName(); + const char *GCCName; + if (!customGCCName.empty()) + GCCName = customGCCName.c_str(); + else if (D.CCCIsCXX()) { + GCCName = "g++"; + } else + GCCName = "gcc"; + + const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath(GCCName)); + C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); +} + +void tools::gcc::Preprocessor::RenderExtraToolArgs( + const JobAction &JA, ArgStringList &CmdArgs) const { + CmdArgs.push_back("-E"); +} + +void tools::gcc::Compiler::RenderExtraToolArgs(const JobAction &JA, + ArgStringList &CmdArgs) const { + const Driver &D = getToolChain().getDriver(); + + switch (JA.getType()) { + // If -flto, etc. are present then make sure not to force assembly output. + case types::TY_LLVM_IR: + case types::TY_LTO_IR: + case types::TY_LLVM_BC: + case types::TY_LTO_BC: + CmdArgs.push_back("-c"); + break; + // We assume we've got an "integrated" assembler in that gcc will produce an + // object file itself. + case types::TY_Object: + CmdArgs.push_back("-c"); + break; + case types::TY_PP_Asm: + CmdArgs.push_back("-S"); + break; + case types::TY_Nothing: + CmdArgs.push_back("-fsyntax-only"); + break; + default: + D.Diag(diag::err_drv_invalid_gcc_output_type) << getTypeName(JA.getType()); + } +} + +void tools::gcc::Linker::RenderExtraToolArgs(const JobAction &JA, + ArgStringList &CmdArgs) const { + // The types are (hopefully) good enough. +} + +/// Add OpenMP linker script arguments at the end of the argument list so that +/// the fat binary is built by embedding each of the device images into the +/// host. The linker script also defines a few symbols required by the code +/// generation so that the images can be easily retrieved at runtime by the +/// offloading library. This should be used only in tool chains that support +/// linker scripts. +static void AddOpenMPLinkerScript(const ToolChain &TC, Compilation &C, + const InputInfo &Output, + const InputInfoList &Inputs, + const ArgList &Args, ArgStringList &CmdArgs, + const JobAction &JA) { + + // If this is not an OpenMP host toolchain, we don't need to do anything. + if (!JA.isHostOffloading(Action::OFK_OpenMP)) + return; + + // Create temporary linker script. Keep it if save-temps is enabled. + const char *LKS; + SmallString<256> Name = llvm::sys::path::filename(Output.getFilename()); + if (C.getDriver().isSaveTempsEnabled()) { + llvm::sys::path::replace_extension(Name, "lk"); + LKS = C.getArgs().MakeArgString(Name.c_str()); + } else { + llvm::sys::path::replace_extension(Name, ""); + Name = C.getDriver().GetTemporaryPath(Name, "lk"); + LKS = C.addTempFile(C.getArgs().MakeArgString(Name.c_str())); + } + + // Add linker script option to the command. + CmdArgs.push_back("-T"); + CmdArgs.push_back(LKS); + + // Create a buffer to write the contents of the linker script. + std::string LksBuffer; + llvm::raw_string_ostream LksStream(LksBuffer); + + // Get the OpenMP offload tool chains so that we can extract the triple + // associated with each device input. + auto OpenMPToolChains = C.getOffloadToolChains<Action::OFK_OpenMP>(); + assert(OpenMPToolChains.first != OpenMPToolChains.second && + "No OpenMP toolchains??"); + + // Track the input file name and device triple in order to build the script, + // inserting binaries in the designated sections. + SmallVector<std::pair<std::string, const char *>, 8> InputBinaryInfo; + + // Add commands to embed target binaries. We ensure that each section and + // image is 16-byte aligned. This is not mandatory, but increases the + // likelihood of data to be aligned with a cache block in several main host + // machines. + LksStream << "/*\n"; + LksStream << " OpenMP Offload Linker Script\n"; + LksStream << " *** Automatically generated by Clang ***\n"; + LksStream << "*/\n"; + LksStream << "TARGET(binary)\n"; + auto DTC = OpenMPToolChains.first; + for (auto &II : Inputs) { + const Action *A = II.getAction(); + // Is this a device linking action? + if (A && isa<LinkJobAction>(A) && + A->isDeviceOffloading(Action::OFK_OpenMP)) { + assert(DTC != OpenMPToolChains.second && + "More device inputs than device toolchains??"); + InputBinaryInfo.push_back(std::make_pair( + DTC->second->getTriple().normalize(), II.getFilename())); + ++DTC; + LksStream << "INPUT(" << II.getFilename() << ")\n"; + } + } + + assert(DTC == OpenMPToolChains.second && + "Less device inputs than device toolchains??"); + + LksStream << "SECTIONS\n"; + LksStream << "{\n"; + LksStream << " .omp_offloading :\n"; + LksStream << " ALIGN(0x10)\n"; + LksStream << " {\n"; + + for (auto &BI : InputBinaryInfo) { + LksStream << " . = ALIGN(0x10);\n"; + LksStream << " PROVIDE_HIDDEN(.omp_offloading.img_start." << BI.first + << " = .);\n"; + LksStream << " " << BI.second << "\n"; + LksStream << " PROVIDE_HIDDEN(.omp_offloading.img_end." << BI.first + << " = .);\n"; + } + + LksStream << " }\n"; + // Add commands to define host entries begin and end. We use 1-byte subalign + // so that the linker does not add any padding and the elements in this + // section form an array. + LksStream << " .omp_offloading.entries :\n"; + LksStream << " ALIGN(0x10)\n"; + LksStream << " SUBALIGN(0x01)\n"; + LksStream << " {\n"; + LksStream << " PROVIDE_HIDDEN(.omp_offloading.entries_begin = .);\n"; + LksStream << " *(.omp_offloading.entries)\n"; + LksStream << " PROVIDE_HIDDEN(.omp_offloading.entries_end = .);\n"; + LksStream << " }\n"; + LksStream << "}\n"; + LksStream << "INSERT BEFORE .data\n"; + LksStream.flush(); + + // Dump the contents of the linker script if the user requested that. We + // support this option to enable testing of behavior with -###. + if (C.getArgs().hasArg(options::OPT_fopenmp_dump_offload_linker_script)) + llvm::errs() << LksBuffer; + + // If this is a dry run, do not create the linker script file. + if (C.getArgs().hasArg(options::OPT__HASH_HASH_HASH)) + return; + + // Open script file and write the contents. + std::error_code EC; + llvm::raw_fd_ostream Lksf(LKS, EC, llvm::sys::fs::F_None); + + if (EC) { + C.getDriver().Diag(clang::diag::err_unable_to_make_temp) << EC.message(); + return; + } + + Lksf << LksBuffer; +} + +static bool addXRayRuntime(const ToolChain &TC, const ArgList &Args, + ArgStringList &CmdArgs) { + if (Args.hasFlag(options::OPT_fxray_instrument, + options::OPT_fnoxray_instrument, false)) { + CmdArgs.push_back("-whole-archive"); + CmdArgs.push_back(TC.getCompilerRTArgString(Args, "xray", false)); + CmdArgs.push_back("-no-whole-archive"); + return true; + } + return false; +} + +static void linkXRayRuntimeDeps(const ToolChain &TC, const ArgList &Args, + ArgStringList &CmdArgs) { + CmdArgs.push_back("--no-as-needed"); + CmdArgs.push_back("-lpthread"); + CmdArgs.push_back("-lrt"); + CmdArgs.push_back("-lm"); + CmdArgs.push_back("-latomic"); + if (TC.GetCXXStdlibType(Args) == ToolChain::CST_Libcxx) + CmdArgs.push_back("-lc++"); + else + CmdArgs.push_back("-lstdc++"); + if (TC.getTriple().getOS() != llvm::Triple::FreeBSD) + CmdArgs.push_back("-ldl"); +} + +static const char *getLDMOption(const llvm::Triple &T, const ArgList &Args) { + switch (T.getArch()) { + case llvm::Triple::x86: + if (T.isOSIAMCU()) + return "elf_iamcu"; + return "elf_i386"; + case llvm::Triple::aarch64: + return "aarch64linux"; + case llvm::Triple::aarch64_be: + return "aarch64_be_linux"; + case llvm::Triple::arm: + case llvm::Triple::thumb: + return "armelf_linux_eabi"; + case llvm::Triple::armeb: + case llvm::Triple::thumbeb: + return "armelfb_linux_eabi"; + case llvm::Triple::ppc: + return "elf32ppclinux"; + case llvm::Triple::ppc64: + return "elf64ppc"; + case llvm::Triple::ppc64le: + return "elf64lppc"; + case llvm::Triple::sparc: + case llvm::Triple::sparcel: + return "elf32_sparc"; + case llvm::Triple::sparcv9: + return "elf64_sparc"; + case llvm::Triple::mips: + return "elf32btsmip"; + case llvm::Triple::mipsel: + return "elf32ltsmip"; + case llvm::Triple::mips64: + if (tools::mips::hasMipsAbiArg(Args, "n32")) + return "elf32btsmipn32"; + return "elf64btsmip"; + case llvm::Triple::mips64el: + if (tools::mips::hasMipsAbiArg(Args, "n32")) + return "elf32ltsmipn32"; + return "elf64ltsmip"; + case llvm::Triple::systemz: + return "elf64_s390"; + case llvm::Triple::x86_64: + if (T.getEnvironment() == llvm::Triple::GNUX32) + return "elf32_x86_64"; + return "elf_x86_64"; + default: + return nullptr; + } +} + +void tools::gnutools::Linker::ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, + const InputInfoList &Inputs, + const ArgList &Args, + const char *LinkingOutput) const { + const toolchains::Linux &ToolChain = + static_cast<const toolchains::Linux &>(getToolChain()); + const Driver &D = ToolChain.getDriver(); + + const llvm::Triple &Triple = getToolChain().getEffectiveTriple(); + + const llvm::Triple::ArchType Arch = ToolChain.getArch(); + const bool isAndroid = ToolChain.getTriple().isAndroid(); + const bool IsIAMCU = ToolChain.getTriple().isOSIAMCU(); + const bool IsPIE = + !Args.hasArg(options::OPT_shared) && !Args.hasArg(options::OPT_static) && + (Args.hasArg(options::OPT_pie) || ToolChain.isPIEDefault()); + const bool HasCRTBeginEndFiles = + ToolChain.getTriple().hasEnvironment() || + (ToolChain.getTriple().getVendor() != llvm::Triple::MipsTechnologies); + + ArgStringList CmdArgs; + + // Silence warning for "clang -g foo.o -o foo" + Args.ClaimAllArgs(options::OPT_g_Group); + // and "clang -emit-llvm foo.o -o foo" + Args.ClaimAllArgs(options::OPT_emit_llvm); + // and for "clang -w foo.o -o foo". Other warning options are already + // handled somewhere else. + Args.ClaimAllArgs(options::OPT_w); + + const char *Exec = Args.MakeArgString(ToolChain.GetLinkerPath()); + if (llvm::sys::path::stem(Exec) == "lld") { + CmdArgs.push_back("-flavor"); + CmdArgs.push_back("old-gnu"); + CmdArgs.push_back("-target"); + CmdArgs.push_back(Args.MakeArgString(getToolChain().getTripleString())); + } + + if (!D.SysRoot.empty()) + CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot)); + + if (IsPIE) + CmdArgs.push_back("-pie"); + + if (Args.hasArg(options::OPT_rdynamic)) + CmdArgs.push_back("-export-dynamic"); + + if (Args.hasArg(options::OPT_s)) + CmdArgs.push_back("-s"); + + if (Arch == llvm::Triple::armeb || Arch == llvm::Triple::thumbeb) + arm::appendEBLinkFlags(Args, CmdArgs, Triple); + + // Most Android ARM64 targets should enable the linker fix for erratum + // 843419. Only non-Cortex-A53 devices are allowed to skip this flag. + if (Arch == llvm::Triple::aarch64 && isAndroid) { + std::string CPU = getCPUName(Args, Triple); + if (CPU.empty() || CPU == "generic" || CPU == "cortex-a53") + CmdArgs.push_back("--fix-cortex-a53-843419"); + } + + for (const auto &Opt : ToolChain.ExtraOpts) + CmdArgs.push_back(Opt.c_str()); + + if (!Args.hasArg(options::OPT_static)) { + CmdArgs.push_back("--eh-frame-hdr"); + } + + if (const char *LDMOption = getLDMOption(ToolChain.getTriple(), Args)) { + CmdArgs.push_back("-m"); + CmdArgs.push_back(LDMOption); + } else { + D.Diag(diag::err_target_unknown_triple) << Triple.str(); + return; + } + + if (Args.hasArg(options::OPT_static)) { + if (Arch == llvm::Triple::arm || Arch == llvm::Triple::armeb || + Arch == llvm::Triple::thumb || Arch == llvm::Triple::thumbeb) + CmdArgs.push_back("-Bstatic"); + else + CmdArgs.push_back("-static"); + } else if (Args.hasArg(options::OPT_shared)) { + CmdArgs.push_back("-shared"); + } + + if (!Args.hasArg(options::OPT_static)) { + if (Args.hasArg(options::OPT_rdynamic)) + CmdArgs.push_back("-export-dynamic"); + + if (!Args.hasArg(options::OPT_shared)) { + const std::string Loader = + D.DyldPrefix + ToolChain.getDynamicLinker(Args); + CmdArgs.push_back("-dynamic-linker"); + CmdArgs.push_back(Args.MakeArgString(Loader)); + } + } + + CmdArgs.push_back("-o"); + CmdArgs.push_back(Output.getFilename()); + + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) { + if (!isAndroid && !IsIAMCU) { + const char *crt1 = nullptr; + if (!Args.hasArg(options::OPT_shared)) { + if (Args.hasArg(options::OPT_pg)) + crt1 = "gcrt1.o"; + else if (IsPIE) + crt1 = "Scrt1.o"; + else + crt1 = "crt1.o"; + } + if (crt1) + CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crt1))); + + CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crti.o"))); + } + + if (IsIAMCU) + CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crt0.o"))); + else { + const char *crtbegin; + if (Args.hasArg(options::OPT_static)) + crtbegin = isAndroid ? "crtbegin_static.o" : "crtbeginT.o"; + else if (Args.hasArg(options::OPT_shared)) + crtbegin = isAndroid ? "crtbegin_so.o" : "crtbeginS.o"; + else if (IsPIE) + crtbegin = isAndroid ? "crtbegin_dynamic.o" : "crtbeginS.o"; + else + crtbegin = isAndroid ? "crtbegin_dynamic.o" : "crtbegin.o"; + + if (HasCRTBeginEndFiles) + CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crtbegin))); + } + + // Add crtfastmath.o if available and fast math is enabled. + ToolChain.AddFastMathRuntimeIfAvailable(Args, CmdArgs); + } + + Args.AddAllArgs(CmdArgs, options::OPT_L); + Args.AddAllArgs(CmdArgs, options::OPT_u); + + ToolChain.AddFilePathLibArgs(Args, CmdArgs); + + if (D.isUsingLTO()) + AddGoldPlugin(ToolChain, Args, CmdArgs, D.getLTOMode() == LTOK_Thin, D); + + if (Args.hasArg(options::OPT_Z_Xlinker__no_demangle)) + CmdArgs.push_back("--no-demangle"); + + bool NeedsSanitizerDeps = addSanitizerRuntimes(ToolChain, Args, CmdArgs); + bool NeedsXRayDeps = addXRayRuntime(ToolChain, Args, CmdArgs); + AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA); + // The profile runtime also needs access to system libraries. + getToolChain().addProfileRTLibs(Args, CmdArgs); + + if (D.CCCIsCXX() && + !Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { + bool OnlyLibstdcxxStatic = Args.hasArg(options::OPT_static_libstdcxx) && + !Args.hasArg(options::OPT_static); + if (OnlyLibstdcxxStatic) + CmdArgs.push_back("-Bstatic"); + ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs); + if (OnlyLibstdcxxStatic) + CmdArgs.push_back("-Bdynamic"); + CmdArgs.push_back("-lm"); + } + // Silence warnings when linking C code with a C++ '-stdlib' argument. + Args.ClaimAllArgs(options::OPT_stdlib_EQ); + + if (!Args.hasArg(options::OPT_nostdlib)) { + if (!Args.hasArg(options::OPT_nodefaultlibs)) { + if (Args.hasArg(options::OPT_static)) + CmdArgs.push_back("--start-group"); + + if (NeedsSanitizerDeps) + linkSanitizerRuntimeDeps(ToolChain, CmdArgs); + + if (NeedsXRayDeps) + linkXRayRuntimeDeps(ToolChain, Args, CmdArgs); + + bool WantPthread = Args.hasArg(options::OPT_pthread) || + Args.hasArg(options::OPT_pthreads); + + if (Args.hasFlag(options::OPT_fopenmp, options::OPT_fopenmp_EQ, + options::OPT_fno_openmp, false)) { + // OpenMP runtimes implies pthreads when using the GNU toolchain. + // FIXME: Does this really make sense for all GNU toolchains? + WantPthread = true; + + // Also link the particular OpenMP runtimes. + switch (ToolChain.getDriver().getOpenMPRuntime(Args)) { + case Driver::OMPRT_OMP: + CmdArgs.push_back("-lomp"); + break; + case Driver::OMPRT_GOMP: + CmdArgs.push_back("-lgomp"); + + // FIXME: Exclude this for platforms with libgomp that don't require + // librt. Most modern Linux platforms require it, but some may not. + CmdArgs.push_back("-lrt"); + break; + case Driver::OMPRT_IOMP5: + CmdArgs.push_back("-liomp5"); + break; + case Driver::OMPRT_Unknown: + // Already diagnosed. + break; + } + if (JA.isHostOffloading(Action::OFK_OpenMP)) + CmdArgs.push_back("-lomptarget"); + + addArchSpecificRPath(ToolChain, Args, CmdArgs); + } + + AddRunTimeLibs(ToolChain, D, CmdArgs, Args); + + if (WantPthread && !isAndroid) + CmdArgs.push_back("-lpthread"); + + if (Args.hasArg(options::OPT_fsplit_stack)) + CmdArgs.push_back("--wrap=pthread_create"); + + CmdArgs.push_back("-lc"); + + // Add IAMCU specific libs, if needed. + if (IsIAMCU) + CmdArgs.push_back("-lgloss"); + + if (Args.hasArg(options::OPT_static)) + CmdArgs.push_back("--end-group"); + else + AddRunTimeLibs(ToolChain, D, CmdArgs, Args); + + // Add IAMCU specific libs (outside the group), if needed. + if (IsIAMCU) { + CmdArgs.push_back("--as-needed"); + CmdArgs.push_back("-lsoftfp"); + CmdArgs.push_back("--no-as-needed"); + } + } + + if (!Args.hasArg(options::OPT_nostartfiles) && !IsIAMCU) { + const char *crtend; + if (Args.hasArg(options::OPT_shared)) + crtend = isAndroid ? "crtend_so.o" : "crtendS.o"; + else if (IsPIE) + crtend = isAndroid ? "crtend_android.o" : "crtendS.o"; + else + crtend = isAndroid ? "crtend_android.o" : "crtend.o"; + + if (HasCRTBeginEndFiles) + CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crtend))); + if (!isAndroid) + CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtn.o"))); + } + } + + // Add OpenMP offloading linker script args if required. + AddOpenMPLinkerScript(getToolChain(), C, Output, Inputs, Args, CmdArgs, JA); + + C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); +} + +void tools::gnutools::Assembler::ConstructJob(Compilation &C, + const JobAction &JA, + const InputInfo &Output, + const InputInfoList &Inputs, + const ArgList &Args, + const char *LinkingOutput) const { + claimNoWarnArgs(Args); + + ArgStringList CmdArgs; + + llvm::Reloc::Model RelocationModel; + unsigned PICLevel; + bool IsPIE; + std::tie(RelocationModel, PICLevel, IsPIE) = + ParsePICArgs(getToolChain(), Args); + + switch (getToolChain().getArch()) { + default: + break; + // Add --32/--64 to make sure we get the format we want. + // This is incomplete + case llvm::Triple::x86: + CmdArgs.push_back("--32"); + break; + case llvm::Triple::x86_64: + if (getToolChain().getTriple().getEnvironment() == llvm::Triple::GNUX32) + CmdArgs.push_back("--x32"); + else + CmdArgs.push_back("--64"); + break; + case llvm::Triple::ppc: + CmdArgs.push_back("-a32"); + CmdArgs.push_back("-mppc"); + CmdArgs.push_back("-many"); + break; + case llvm::Triple::ppc64: + CmdArgs.push_back("-a64"); + CmdArgs.push_back("-mppc64"); + CmdArgs.push_back("-many"); + break; + case llvm::Triple::ppc64le: + CmdArgs.push_back("-a64"); + CmdArgs.push_back("-mppc64"); + CmdArgs.push_back("-many"); + CmdArgs.push_back("-mlittle-endian"); + break; + case llvm::Triple::sparc: + case llvm::Triple::sparcel: { + CmdArgs.push_back("-32"); + std::string CPU = getCPUName(Args, getToolChain().getTriple()); + CmdArgs.push_back(sparc::getSparcAsmModeForCPU(CPU, getToolChain().getTriple())); + AddAssemblerKPIC(getToolChain(), Args, CmdArgs); + break; + } + case llvm::Triple::sparcv9: { + CmdArgs.push_back("-64"); + std::string CPU = getCPUName(Args, getToolChain().getTriple()); + CmdArgs.push_back(sparc::getSparcAsmModeForCPU(CPU, getToolChain().getTriple())); + AddAssemblerKPIC(getToolChain(), Args, CmdArgs); + break; + } + case llvm::Triple::arm: + case llvm::Triple::armeb: + case llvm::Triple::thumb: + case llvm::Triple::thumbeb: { + const llvm::Triple &Triple2 = getToolChain().getTriple(); + switch (Triple2.getSubArch()) { + case llvm::Triple::ARMSubArch_v7: + CmdArgs.push_back("-mfpu=neon"); + break; + case llvm::Triple::ARMSubArch_v8: + CmdArgs.push_back("-mfpu=crypto-neon-fp-armv8"); + break; + default: + break; + } + + switch (arm::getARMFloatABI(getToolChain(), Args)) { + case arm::FloatABI::Invalid: llvm_unreachable("must have an ABI!"); + case arm::FloatABI::Soft: + CmdArgs.push_back(Args.MakeArgString("-mfloat-abi=soft")); + break; + case arm::FloatABI::SoftFP: + CmdArgs.push_back(Args.MakeArgString("-mfloat-abi=softfp")); + break; + case arm::FloatABI::Hard: + CmdArgs.push_back(Args.MakeArgString("-mfloat-abi=hard")); + break; + } + + Args.AddLastArg(CmdArgs, options::OPT_march_EQ); + + // FIXME: remove krait check when GNU tools support krait cpu + // for now replace it with -mcpu=cortex-a15 to avoid a lower + // march from being picked in the absence of a cpu flag. + Arg *A; + if ((A = Args.getLastArg(options::OPT_mcpu_EQ)) && + StringRef(A->getValue()).equals_lower("krait")) + CmdArgs.push_back("-mcpu=cortex-a15"); + else + Args.AddLastArg(CmdArgs, options::OPT_mcpu_EQ); + Args.AddLastArg(CmdArgs, options::OPT_mfpu_EQ); + break; + } + case llvm::Triple::mips: + case llvm::Triple::mipsel: + case llvm::Triple::mips64: + case llvm::Triple::mips64el: { + StringRef CPUName; + StringRef ABIName; + mips::getMipsCPUAndABI(Args, getToolChain().getTriple(), CPUName, ABIName); + ABIName = mips::getGnuCompatibleMipsABIName(ABIName); + + CmdArgs.push_back("-march"); + CmdArgs.push_back(CPUName.data()); + + CmdArgs.push_back("-mabi"); + CmdArgs.push_back(ABIName.data()); + + // -mno-shared should be emitted unless -fpic, -fpie, -fPIC, -fPIE, + // or -mshared (not implemented) is in effect. + if (RelocationModel == llvm::Reloc::Static) + CmdArgs.push_back("-mno-shared"); + + // LLVM doesn't support -mplt yet and acts as if it is always given. + // However, -mplt has no effect with the N64 ABI. + if (ABIName != "64" && !Args.hasArg(options::OPT_mno_abicalls)) + CmdArgs.push_back("-call_nonpic"); + + if (getToolChain().getArch() == llvm::Triple::mips || + getToolChain().getArch() == llvm::Triple::mips64) + CmdArgs.push_back("-EB"); + else + CmdArgs.push_back("-EL"); + + if (Arg *A = Args.getLastArg(options::OPT_mnan_EQ)) { + if (StringRef(A->getValue()) == "2008") + CmdArgs.push_back(Args.MakeArgString("-mnan=2008")); + } + + // Add the last -mfp32/-mfpxx/-mfp64 or -mfpxx if it is enabled by default. + if (Arg *A = Args.getLastArg(options::OPT_mfp32, options::OPT_mfpxx, + options::OPT_mfp64)) { + A->claim(); + A->render(Args, CmdArgs); + } else if (mips::shouldUseFPXX( + Args, getToolChain().getTriple(), CPUName, ABIName, + mips::getMipsFloatABI(getToolChain().getDriver(), Args))) + CmdArgs.push_back("-mfpxx"); + + // Pass on -mmips16 or -mno-mips16. However, the assembler equivalent of + // -mno-mips16 is actually -no-mips16. + if (Arg *A = + Args.getLastArg(options::OPT_mips16, options::OPT_mno_mips16)) { + if (A->getOption().matches(options::OPT_mips16)) { + A->claim(); + A->render(Args, CmdArgs); + } else { + A->claim(); + CmdArgs.push_back("-no-mips16"); + } + } + + Args.AddLastArg(CmdArgs, options::OPT_mmicromips, + options::OPT_mno_micromips); + Args.AddLastArg(CmdArgs, options::OPT_mdsp, options::OPT_mno_dsp); + Args.AddLastArg(CmdArgs, options::OPT_mdspr2, options::OPT_mno_dspr2); + + if (Arg *A = Args.getLastArg(options::OPT_mmsa, options::OPT_mno_msa)) { + // Do not use AddLastArg because not all versions of MIPS assembler + // support -mmsa / -mno-msa options. + if (A->getOption().matches(options::OPT_mmsa)) + CmdArgs.push_back(Args.MakeArgString("-mmsa")); + } + + Args.AddLastArg(CmdArgs, options::OPT_mhard_float, + options::OPT_msoft_float); + + Args.AddLastArg(CmdArgs, options::OPT_mdouble_float, + options::OPT_msingle_float); + + Args.AddLastArg(CmdArgs, options::OPT_modd_spreg, + options::OPT_mno_odd_spreg); + + AddAssemblerKPIC(getToolChain(), Args, CmdArgs); + break; + } + case llvm::Triple::systemz: { + // Always pass an -march option, since our default of z10 is later + // than the GNU assembler's default. + StringRef CPUName = systemz::getSystemZTargetCPU(Args); + CmdArgs.push_back(Args.MakeArgString("-march=" + CPUName)); + break; + } + } + + Args.AddAllArgs(CmdArgs, options::OPT_I); + Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler); + + CmdArgs.push_back("-o"); + CmdArgs.push_back(Output.getFilename()); + + for (const auto &II : Inputs) + CmdArgs.push_back(II.getFilename()); + + const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("as")); + C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); + + // Handle the debug info splitting at object creation time if we're + // creating an object. + // TODO: Currently only works on linux with newer objcopy. + if (Args.hasArg(options::OPT_gsplit_dwarf) && + getToolChain().getTriple().isOSLinux()) + SplitDebugInfo(getToolChain(), C, *this, JA, Args, Output, + SplitDebugName(Args, Inputs[0])); +} + +namespace { +// Filter to remove Multilibs that don't exist as a suffix to Path +class FilterNonExistent { + StringRef Base, File; + vfs::FileSystem &VFS; + +public: + FilterNonExistent(StringRef Base, StringRef File, vfs::FileSystem &VFS) + : Base(Base), File(File), VFS(VFS) {} + bool operator()(const Multilib &M) { + return !VFS.exists(Base + M.gccSuffix() + File); + } +}; +} // end anonymous namespace + +static bool isSoftFloatABI(const ArgList &Args) { + Arg *A = Args.getLastArg(options::OPT_msoft_float, options::OPT_mhard_float, + options::OPT_mfloat_abi_EQ); + if (!A) + return false; + + return A->getOption().matches(options::OPT_msoft_float) || + (A->getOption().matches(options::OPT_mfloat_abi_EQ) && + A->getValue() == StringRef("soft")); +} + +static void addMultilibFlag(bool Enabled, const char *const Flag, + std::vector<std::string> &Flags) { + if (Enabled) + Flags.push_back(std::string("+") + Flag); + else + Flags.push_back(std::string("-") + Flag); +} + +static bool isArmOrThumbArch(llvm::Triple::ArchType Arch) { + return Arch == llvm::Triple::arm || Arch == llvm::Triple::thumb; +} + +static bool isMips32(llvm::Triple::ArchType Arch) { + return Arch == llvm::Triple::mips || Arch == llvm::Triple::mipsel; +} + +static bool isMips64(llvm::Triple::ArchType Arch) { + return Arch == llvm::Triple::mips64 || Arch == llvm::Triple::mips64el; +} + +static bool isMipsEL(llvm::Triple::ArchType Arch) { + return Arch == llvm::Triple::mipsel || Arch == llvm::Triple::mips64el; +} + +static bool isMips16(const ArgList &Args) { + Arg *A = Args.getLastArg(options::OPT_mips16, options::OPT_mno_mips16); + return A && A->getOption().matches(options::OPT_mips16); +} + +static bool isMicroMips(const ArgList &Args) { + Arg *A = Args.getLastArg(options::OPT_mmicromips, options::OPT_mno_micromips); + return A && A->getOption().matches(options::OPT_mmicromips); +} + +static Multilib makeMultilib(StringRef commonSuffix) { + return Multilib(commonSuffix, commonSuffix, commonSuffix); +} + +static bool findMipsCsMultilibs(const Multilib::flags_list &Flags, + FilterNonExistent &NonExistent, + DetectedMultilibs &Result) { + // Check for Code Sourcery toolchain multilibs + MultilibSet CSMipsMultilibs; + { + auto MArchMips16 = makeMultilib("/mips16").flag("+m32").flag("+mips16"); + + auto MArchMicroMips = + makeMultilib("/micromips").flag("+m32").flag("+mmicromips"); + + auto MArchDefault = makeMultilib("").flag("-mips16").flag("-mmicromips"); + + auto UCLibc = makeMultilib("/uclibc").flag("+muclibc"); + + auto SoftFloat = makeMultilib("/soft-float").flag("+msoft-float"); + + auto Nan2008 = makeMultilib("/nan2008").flag("+mnan=2008"); + + auto DefaultFloat = + makeMultilib("").flag("-msoft-float").flag("-mnan=2008"); + + auto BigEndian = makeMultilib("").flag("+EB").flag("-EL"); + + auto LittleEndian = makeMultilib("/el").flag("+EL").flag("-EB"); + + // Note that this one's osSuffix is "" + auto MAbi64 = makeMultilib("") + .gccSuffix("/64") + .includeSuffix("/64") + .flag("+mabi=n64") + .flag("-mabi=n32") + .flag("-m32"); + + CSMipsMultilibs = + MultilibSet() + .Either(MArchMips16, MArchMicroMips, MArchDefault) + .Maybe(UCLibc) + .Either(SoftFloat, Nan2008, DefaultFloat) + .FilterOut("/micromips/nan2008") + .FilterOut("/mips16/nan2008") + .Either(BigEndian, LittleEndian) + .Maybe(MAbi64) + .FilterOut("/mips16.*/64") + .FilterOut("/micromips.*/64") + .FilterOut(NonExistent) + .setIncludeDirsCallback([](const Multilib &M) { + std::vector<std::string> Dirs({"/include"}); + if (StringRef(M.includeSuffix()).startswith("/uclibc")) + Dirs.push_back( + "/../../../../mips-linux-gnu/libc/uclibc/usr/include"); + else + Dirs.push_back("/../../../../mips-linux-gnu/libc/usr/include"); + return Dirs; + }); + } + + MultilibSet DebianMipsMultilibs; + { + Multilib MAbiN32 = + Multilib().gccSuffix("/n32").includeSuffix("/n32").flag("+mabi=n32"); + + Multilib M64 = Multilib() + .gccSuffix("/64") + .includeSuffix("/64") + .flag("+m64") + .flag("-m32") + .flag("-mabi=n32"); + + Multilib M32 = Multilib().flag("-m64").flag("+m32").flag("-mabi=n32"); + + DebianMipsMultilibs = + MultilibSet().Either(M32, M64, MAbiN32).FilterOut(NonExistent); + } + + // Sort candidates. Toolchain that best meets the directories tree goes first. + // Then select the first toolchains matches command line flags. + MultilibSet *Candidates[] = {&CSMipsMultilibs, &DebianMipsMultilibs}; + if (CSMipsMultilibs.size() < DebianMipsMultilibs.size()) + std::iter_swap(Candidates, Candidates + 1); + for (const MultilibSet *Candidate : Candidates) { + if (Candidate->select(Flags, Result.SelectedMultilib)) { + if (Candidate == &DebianMipsMultilibs) + Result.BiarchSibling = Multilib(); + Result.Multilibs = *Candidate; + return true; + } + } + return false; +} + +static bool findMipsAndroidMultilibs(vfs::FileSystem &VFS, StringRef Path, + const Multilib::flags_list &Flags, + FilterNonExistent &NonExistent, + DetectedMultilibs &Result) { + + MultilibSet AndroidMipsMultilibs = + MultilibSet() + .Maybe(Multilib("/mips-r2").flag("+march=mips32r2")) + .Maybe(Multilib("/mips-r6").flag("+march=mips32r6")) + .FilterOut(NonExistent); + + MultilibSet AndroidMipselMultilibs = + MultilibSet() + .Either(Multilib().flag("+march=mips32"), + Multilib("/mips-r2", "", "/mips-r2").flag("+march=mips32r2"), + Multilib("/mips-r6", "", "/mips-r6").flag("+march=mips32r6")) + .FilterOut(NonExistent); + + MultilibSet AndroidMips64elMultilibs = + MultilibSet() + .Either( + Multilib().flag("+march=mips64r6"), + Multilib("/32/mips-r1", "", "/mips-r1").flag("+march=mips32"), + Multilib("/32/mips-r2", "", "/mips-r2").flag("+march=mips32r2"), + Multilib("/32/mips-r6", "", "/mips-r6").flag("+march=mips32r6")) + .FilterOut(NonExistent); + + MultilibSet *MS = &AndroidMipsMultilibs; + if (VFS.exists(Path + "/mips-r6")) + MS = &AndroidMipselMultilibs; + else if (VFS.exists(Path + "/32")) + MS = &AndroidMips64elMultilibs; + if (MS->select(Flags, Result.SelectedMultilib)) { + Result.Multilibs = *MS; + return true; + } + return false; +} + +static bool findMipsMuslMultilibs(const Multilib::flags_list &Flags, + FilterNonExistent &NonExistent, + DetectedMultilibs &Result) { + // Musl toolchain multilibs + MultilibSet MuslMipsMultilibs; + { + auto MArchMipsR2 = makeMultilib("") + .osSuffix("/mips-r2-hard-musl") + .flag("+EB") + .flag("-EL") + .flag("+march=mips32r2"); + + auto MArchMipselR2 = makeMultilib("/mipsel-r2-hard-musl") + .flag("-EB") + .flag("+EL") + .flag("+march=mips32r2"); + + MuslMipsMultilibs = MultilibSet().Either(MArchMipsR2, MArchMipselR2); + + // Specify the callback that computes the include directories. + MuslMipsMultilibs.setIncludeDirsCallback([](const Multilib &M) { + return std::vector<std::string>( + {"/../sysroot" + M.osSuffix() + "/usr/include"}); + }); + } + if (MuslMipsMultilibs.select(Flags, Result.SelectedMultilib)) { + Result.Multilibs = MuslMipsMultilibs; + return true; + } + return false; +} + +static bool findMipsMtiMultilibs(const Multilib::flags_list &Flags, + FilterNonExistent &NonExistent, + DetectedMultilibs &Result) { + // CodeScape MTI toolchain v1.2 and early. + MultilibSet MtiMipsMultilibsV1; + { + auto MArchMips32 = makeMultilib("/mips32") + .flag("+m32") + .flag("-m64") + .flag("-mmicromips") + .flag("+march=mips32"); + + auto MArchMicroMips = makeMultilib("/micromips") + .flag("+m32") + .flag("-m64") + .flag("+mmicromips"); + + auto MArchMips64r2 = makeMultilib("/mips64r2") + .flag("-m32") + .flag("+m64") + .flag("+march=mips64r2"); + + auto MArchMips64 = makeMultilib("/mips64").flag("-m32").flag("+m64").flag( + "-march=mips64r2"); + + auto MArchDefault = makeMultilib("") + .flag("+m32") + .flag("-m64") + .flag("-mmicromips") + .flag("+march=mips32r2"); + + auto Mips16 = makeMultilib("/mips16").flag("+mips16"); + + auto UCLibc = makeMultilib("/uclibc").flag("+muclibc"); + + auto MAbi64 = + makeMultilib("/64").flag("+mabi=n64").flag("-mabi=n32").flag("-m32"); + + auto BigEndian = makeMultilib("").flag("+EB").flag("-EL"); + + auto LittleEndian = makeMultilib("/el").flag("+EL").flag("-EB"); + + auto SoftFloat = makeMultilib("/sof").flag("+msoft-float"); + + auto Nan2008 = makeMultilib("/nan2008").flag("+mnan=2008"); + + MtiMipsMultilibsV1 = + MultilibSet() + .Either(MArchMips32, MArchMicroMips, MArchMips64r2, MArchMips64, + MArchDefault) + .Maybe(UCLibc) + .Maybe(Mips16) + .FilterOut("/mips64/mips16") + .FilterOut("/mips64r2/mips16") + .FilterOut("/micromips/mips16") + .Maybe(MAbi64) + .FilterOut("/micromips/64") + .FilterOut("/mips32/64") + .FilterOut("^/64") + .FilterOut("/mips16/64") + .Either(BigEndian, LittleEndian) + .Maybe(SoftFloat) + .Maybe(Nan2008) + .FilterOut(".*sof/nan2008") + .FilterOut(NonExistent) + .setIncludeDirsCallback([](const Multilib &M) { + std::vector<std::string> Dirs({"/include"}); + if (StringRef(M.includeSuffix()).startswith("/uclibc")) + Dirs.push_back("/../../../../sysroot/uclibc/usr/include"); + else + Dirs.push_back("/../../../../sysroot/usr/include"); + return Dirs; + }); + } + + // CodeScape IMG toolchain starting from v1.3. + MultilibSet MtiMipsMultilibsV2; + { + auto BeHard = makeMultilib("/mips-r2-hard") + .flag("+EB") + .flag("-msoft-float") + .flag("-mnan=2008") + .flag("-muclibc"); + auto BeSoft = makeMultilib("/mips-r2-soft") + .flag("+EB") + .flag("+msoft-float") + .flag("-mnan=2008"); + auto ElHard = makeMultilib("/mipsel-r2-hard") + .flag("+EL") + .flag("-msoft-float") + .flag("-mnan=2008") + .flag("-muclibc"); + auto ElSoft = makeMultilib("/mipsel-r2-soft") + .flag("+EL") + .flag("+msoft-float") + .flag("-mnan=2008") + .flag("-mmicromips"); + auto BeHardNan = makeMultilib("/mips-r2-hard-nan2008") + .flag("+EB") + .flag("-msoft-float") + .flag("+mnan=2008") + .flag("-muclibc"); + auto ElHardNan = makeMultilib("/mipsel-r2-hard-nan2008") + .flag("+EL") + .flag("-msoft-float") + .flag("+mnan=2008") + .flag("-muclibc") + .flag("-mmicromips"); + auto BeHardNanUclibc = makeMultilib("/mips-r2-hard-nan2008-uclibc") + .flag("+EB") + .flag("-msoft-float") + .flag("+mnan=2008") + .flag("+muclibc"); + auto ElHardNanUclibc = makeMultilib("/mipsel-r2-hard-nan2008-uclibc") + .flag("+EL") + .flag("-msoft-float") + .flag("+mnan=2008") + .flag("+muclibc"); + auto BeHardUclibc = makeMultilib("/mips-r2-hard-uclibc") + .flag("+EB") + .flag("-msoft-float") + .flag("-mnan=2008") + .flag("+muclibc"); + auto ElHardUclibc = makeMultilib("/mipsel-r2-hard-uclibc") + .flag("+EL") + .flag("-msoft-float") + .flag("-mnan=2008") + .flag("+muclibc"); + auto ElMicroHardNan = makeMultilib("/micromipsel-r2-hard-nan2008") + .flag("+EL") + .flag("-msoft-float") + .flag("+mnan=2008") + .flag("+mmicromips"); + auto ElMicroSoft = makeMultilib("/micromipsel-r2-soft") + .flag("+EL") + .flag("+msoft-float") + .flag("-mnan=2008") + .flag("+mmicromips"); + + auto O32 = + makeMultilib("/lib").osSuffix("").flag("-mabi=n32").flag("-mabi=n64"); + auto N32 = + makeMultilib("/lib32").osSuffix("").flag("+mabi=n32").flag("-mabi=n64"); + auto N64 = + makeMultilib("/lib64").osSuffix("").flag("-mabi=n32").flag("+mabi=n64"); + + MtiMipsMultilibsV2 = + MultilibSet() + .Either({BeHard, BeSoft, ElHard, ElSoft, BeHardNan, ElHardNan, + BeHardNanUclibc, ElHardNanUclibc, BeHardUclibc, + ElHardUclibc, ElMicroHardNan, ElMicroSoft}) + .Either(O32, N32, N64) + .FilterOut(NonExistent) + .setIncludeDirsCallback([](const Multilib &M) { + return std::vector<std::string>({"/../../../../sysroot" + + M.includeSuffix() + + "/../usr/include"}); + }) + .setFilePathsCallback([](const Multilib &M) { + return std::vector<std::string>( + {"/../../../../mips-mti-linux-gnu/lib" + M.gccSuffix()}); + }); + } + for (auto Candidate : {&MtiMipsMultilibsV1, &MtiMipsMultilibsV2}) { + if (Candidate->select(Flags, Result.SelectedMultilib)) { + Result.Multilibs = *Candidate; + return true; + } + } + return false; +} + +static bool findMipsImgMultilibs(const Multilib::flags_list &Flags, + FilterNonExistent &NonExistent, + DetectedMultilibs &Result) { + // CodeScape IMG toolchain v1.2 and early. + MultilibSet ImgMultilibsV1; + { + auto Mips64r6 = makeMultilib("/mips64r6").flag("+m64").flag("-m32"); + + auto LittleEndian = makeMultilib("/el").flag("+EL").flag("-EB"); + + auto MAbi64 = + makeMultilib("/64").flag("+mabi=n64").flag("-mabi=n32").flag("-m32"); + + ImgMultilibsV1 = + MultilibSet() + .Maybe(Mips64r6) + .Maybe(MAbi64) + .Maybe(LittleEndian) + .FilterOut(NonExistent) + .setIncludeDirsCallback([](const Multilib &M) { + return std::vector<std::string>( + {"/include", "/../../../../sysroot/usr/include"}); + }); + } + + // CodeScape IMG toolchain starting from v1.3. + MultilibSet ImgMultilibsV2; + { + auto BeHard = makeMultilib("/mips-r6-hard") + .flag("+EB") + .flag("-msoft-float") + .flag("-mmicromips"); + auto BeSoft = makeMultilib("/mips-r6-soft") + .flag("+EB") + .flag("+msoft-float") + .flag("-mmicromips"); + auto ElHard = makeMultilib("/mipsel-r6-hard") + .flag("+EL") + .flag("-msoft-float") + .flag("-mmicromips"); + auto ElSoft = makeMultilib("/mipsel-r6-soft") + .flag("+EL") + .flag("+msoft-float") + .flag("-mmicromips"); + auto BeMicroHard = makeMultilib("/micromips-r6-hard") + .flag("+EB") + .flag("-msoft-float") + .flag("+mmicromips"); + auto BeMicroSoft = makeMultilib("/micromips-r6-soft") + .flag("+EB") + .flag("+msoft-float") + .flag("+mmicromips"); + auto ElMicroHard = makeMultilib("/micromipsel-r6-hard") + .flag("+EL") + .flag("-msoft-float") + .flag("+mmicromips"); + auto ElMicroSoft = makeMultilib("/micromipsel-r6-soft") + .flag("+EL") + .flag("+msoft-float") + .flag("+mmicromips"); + + auto O32 = + makeMultilib("/lib").osSuffix("").flag("-mabi=n32").flag("-mabi=n64"); + auto N32 = + makeMultilib("/lib32").osSuffix("").flag("+mabi=n32").flag("-mabi=n64"); + auto N64 = + makeMultilib("/lib64").osSuffix("").flag("-mabi=n32").flag("+mabi=n64"); + + ImgMultilibsV2 = + MultilibSet() + .Either({BeHard, BeSoft, ElHard, ElSoft, BeMicroHard, BeMicroSoft, + ElMicroHard, ElMicroSoft}) + .Either(O32, N32, N64) + .FilterOut(NonExistent) + .setIncludeDirsCallback([](const Multilib &M) { + return std::vector<std::string>({"/../../../../sysroot" + + M.includeSuffix() + + "/../usr/include"}); + }) + .setFilePathsCallback([](const Multilib &M) { + return std::vector<std::string>( + {"/../../../../mips-img-linux-gnu/lib" + M.gccSuffix()}); + }); + } + for (auto Candidate : {&ImgMultilibsV1, &ImgMultilibsV2}) { + if (Candidate->select(Flags, Result.SelectedMultilib)) { + Result.Multilibs = *Candidate; + return true; + } + } + return false; +} + +bool clang::driver::findMIPSMultilibs(const Driver &D, + const llvm::Triple &TargetTriple, + StringRef Path, const ArgList &Args, + DetectedMultilibs &Result) { + FilterNonExistent NonExistent(Path, "/crtbegin.o", D.getVFS()); + + StringRef CPUName; + StringRef ABIName; + tools::mips::getMipsCPUAndABI(Args, TargetTriple, CPUName, ABIName); + + llvm::Triple::ArchType TargetArch = TargetTriple.getArch(); + + Multilib::flags_list Flags; + addMultilibFlag(isMips32(TargetArch), "m32", Flags); + addMultilibFlag(isMips64(TargetArch), "m64", Flags); + addMultilibFlag(isMips16(Args), "mips16", Flags); + addMultilibFlag(CPUName == "mips32", "march=mips32", Flags); + addMultilibFlag(CPUName == "mips32r2" || CPUName == "mips32r3" || + CPUName == "mips32r5" || CPUName == "p5600", + "march=mips32r2", Flags); + addMultilibFlag(CPUName == "mips32r6", "march=mips32r6", Flags); + addMultilibFlag(CPUName == "mips64", "march=mips64", Flags); + addMultilibFlag(CPUName == "mips64r2" || CPUName == "mips64r3" || + CPUName == "mips64r5" || CPUName == "octeon", + "march=mips64r2", Flags); + addMultilibFlag(CPUName == "mips64r6", "march=mips64r6", Flags); + addMultilibFlag(isMicroMips(Args), "mmicromips", Flags); + addMultilibFlag(tools::mips::isUCLibc(Args), "muclibc", Flags); + addMultilibFlag(tools::mips::isNaN2008(Args, TargetTriple), "mnan=2008", + Flags); + addMultilibFlag(ABIName == "n32", "mabi=n32", Flags); + addMultilibFlag(ABIName == "n64", "mabi=n64", Flags); + addMultilibFlag(isSoftFloatABI(Args), "msoft-float", Flags); + addMultilibFlag(!isSoftFloatABI(Args), "mhard-float", Flags); + addMultilibFlag(isMipsEL(TargetArch), "EL", Flags); + addMultilibFlag(!isMipsEL(TargetArch), "EB", Flags); + + if (TargetTriple.isAndroid()) + return findMipsAndroidMultilibs(D.getVFS(), Path, Flags, NonExistent, + Result); + + if (TargetTriple.getVendor() == llvm::Triple::MipsTechnologies && + TargetTriple.getOS() == llvm::Triple::Linux && + TargetTriple.getEnvironment() == llvm::Triple::UnknownEnvironment) + return findMipsMuslMultilibs(Flags, NonExistent, Result); + + if (TargetTriple.getVendor() == llvm::Triple::MipsTechnologies && + TargetTriple.getOS() == llvm::Triple::Linux && + TargetTriple.getEnvironment() == llvm::Triple::GNU) + return findMipsMtiMultilibs(Flags, NonExistent, Result); + + if (TargetTriple.getVendor() == llvm::Triple::ImaginationTechnologies && + TargetTriple.getOS() == llvm::Triple::Linux && + TargetTriple.getEnvironment() == llvm::Triple::GNU) + return findMipsImgMultilibs(Flags, NonExistent, Result); + + if (findMipsCsMultilibs(Flags, NonExistent, Result)) + return true; + + // Fallback to the regular toolchain-tree structure. + Multilib Default; + Result.Multilibs.push_back(Default); + Result.Multilibs.FilterOut(NonExistent); + + if (Result.Multilibs.select(Flags, Result.SelectedMultilib)) { + Result.BiarchSibling = Multilib(); + return true; + } + + return false; +} + +static void findAndroidArmMultilibs(const Driver &D, + const llvm::Triple &TargetTriple, + StringRef Path, const ArgList &Args, + DetectedMultilibs &Result) { + // Find multilibs with subdirectories like armv7-a, thumb, armv7-a/thumb. + FilterNonExistent NonExistent(Path, "/crtbegin.o", D.getVFS()); + Multilib ArmV7Multilib = makeMultilib("/armv7-a") + .flag("+armv7") + .flag("-thumb"); + Multilib ThumbMultilib = makeMultilib("/thumb") + .flag("-armv7") + .flag("+thumb"); + Multilib ArmV7ThumbMultilib = makeMultilib("/armv7-a/thumb") + .flag("+armv7") + .flag("+thumb"); + Multilib DefaultMultilib = makeMultilib("") + .flag("-armv7") + .flag("-thumb"); + MultilibSet AndroidArmMultilibs = + MultilibSet() + .Either(ThumbMultilib, ArmV7Multilib, + ArmV7ThumbMultilib, DefaultMultilib) + .FilterOut(NonExistent); + + Multilib::flags_list Flags; + llvm::StringRef Arch = Args.getLastArgValue(options::OPT_march_EQ); + bool IsArmArch = TargetTriple.getArch() == llvm::Triple::arm; + bool IsThumbArch = TargetTriple.getArch() == llvm::Triple::thumb; + bool IsV7SubArch = TargetTriple.getSubArch() == llvm::Triple::ARMSubArch_v7; + bool IsThumbMode = IsThumbArch || + Args.hasFlag(options::OPT_mthumb, options::OPT_mno_thumb, false) || + (IsArmArch && llvm::ARM::parseArchISA(Arch) == llvm::ARM::IK_THUMB); + bool IsArmV7Mode = (IsArmArch || IsThumbArch) && + (llvm::ARM::parseArchVersion(Arch) == 7 || + (IsArmArch && Arch == "" && IsV7SubArch)); + addMultilibFlag(IsArmV7Mode, "armv7", Flags); + addMultilibFlag(IsThumbMode, "thumb", Flags); + + if (AndroidArmMultilibs.select(Flags, Result.SelectedMultilib)) + Result.Multilibs = AndroidArmMultilibs; +} + +static bool findBiarchMultilibs(const Driver &D, + const llvm::Triple &TargetTriple, + StringRef Path, const ArgList &Args, + bool NeedsBiarchSuffix, + DetectedMultilibs &Result) { + // Some versions of SUSE and Fedora on ppc64 put 32-bit libs + // in what would normally be GCCInstallPath and put the 64-bit + // libs in a subdirectory named 64. The simple logic we follow is that + // *if* there is a subdirectory of the right name with crtbegin.o in it, + // we use that. If not, and if not a biarch triple alias, we look for + // crtbegin.o without the subdirectory. + + Multilib Default; + Multilib Alt64 = Multilib() + .gccSuffix("/64") + .includeSuffix("/64") + .flag("-m32") + .flag("+m64") + .flag("-mx32"); + Multilib Alt32 = Multilib() + .gccSuffix("/32") + .includeSuffix("/32") + .flag("+m32") + .flag("-m64") + .flag("-mx32"); + Multilib Altx32 = Multilib() + .gccSuffix("/x32") + .includeSuffix("/x32") + .flag("-m32") + .flag("-m64") + .flag("+mx32"); + + // GCC toolchain for IAMCU doesn't have crtbegin.o, so look for libgcc.a. + FilterNonExistent NonExistent( + Path, TargetTriple.isOSIAMCU() ? "/libgcc.a" : "/crtbegin.o", D.getVFS()); + + // Determine default multilib from: 32, 64, x32 + // Also handle cases such as 64 on 32, 32 on 64, etc. + enum { UNKNOWN, WANT32, WANT64, WANTX32 } Want = UNKNOWN; + const bool IsX32 = TargetTriple.getEnvironment() == llvm::Triple::GNUX32; + if (TargetTriple.isArch32Bit() && !NonExistent(Alt32)) + Want = WANT64; + else if (TargetTriple.isArch64Bit() && IsX32 && !NonExistent(Altx32)) + Want = WANT64; + else if (TargetTriple.isArch64Bit() && !IsX32 && !NonExistent(Alt64)) + Want = WANT32; + else { + if (TargetTriple.isArch32Bit()) + Want = NeedsBiarchSuffix ? WANT64 : WANT32; + else if (IsX32) + Want = NeedsBiarchSuffix ? WANT64 : WANTX32; + else + Want = NeedsBiarchSuffix ? WANT32 : WANT64; + } + + if (Want == WANT32) + Default.flag("+m32").flag("-m64").flag("-mx32"); + else if (Want == WANT64) + Default.flag("-m32").flag("+m64").flag("-mx32"); + else if (Want == WANTX32) + Default.flag("-m32").flag("-m64").flag("+mx32"); + else + return false; + + Result.Multilibs.push_back(Default); + Result.Multilibs.push_back(Alt64); + Result.Multilibs.push_back(Alt32); + Result.Multilibs.push_back(Altx32); + + Result.Multilibs.FilterOut(NonExistent); + + Multilib::flags_list Flags; + addMultilibFlag(TargetTriple.isArch64Bit() && !IsX32, "m64", Flags); + addMultilibFlag(TargetTriple.isArch32Bit(), "m32", Flags); + addMultilibFlag(TargetTriple.isArch64Bit() && IsX32, "mx32", Flags); + + if (!Result.Multilibs.select(Flags, Result.SelectedMultilib)) + return false; + + if (Result.SelectedMultilib == Alt64 || Result.SelectedMultilib == Alt32 || + Result.SelectedMultilib == Altx32) + Result.BiarchSibling = Default; + + return true; +} + +/// Generic_GCC - A tool chain using the 'gcc' command to perform +/// all subcommands; this relies on gcc translating the majority of +/// command line options. + +/// \brief Less-than for GCCVersion, implementing a Strict Weak Ordering. +bool Generic_GCC::GCCVersion::isOlderThan(int RHSMajor, int RHSMinor, + int RHSPatch, + StringRef RHSPatchSuffix) const { + if (Major != RHSMajor) + return Major < RHSMajor; + if (Minor != RHSMinor) + return Minor < RHSMinor; + if (Patch != RHSPatch) { + // Note that versions without a specified patch sort higher than those with + // a patch. + if (RHSPatch == -1) + return true; + if (Patch == -1) + return false; + + // Otherwise just sort on the patch itself. + return Patch < RHSPatch; + } + if (PatchSuffix != RHSPatchSuffix) { + // Sort empty suffixes higher. + if (RHSPatchSuffix.empty()) + return true; + if (PatchSuffix.empty()) + return false; + + // Provide a lexicographic sort to make this a total ordering. + return PatchSuffix < RHSPatchSuffix; + } + + // The versions are equal. + return false; +} + +static llvm::StringRef getGCCToolchainDir(const ArgList &Args) { + const Arg *A = Args.getLastArg(clang::driver::options::OPT_gcc_toolchain); + if (A) + return A->getValue(); + return GCC_INSTALL_PREFIX; +} + +/// \brief Initialize a GCCInstallationDetector from the driver. +/// +/// This performs all of the autodetection and sets up the various paths. +/// Once constructed, a GCCInstallationDetector is essentially immutable. +/// +/// FIXME: We shouldn't need an explicit TargetTriple parameter here, and +/// should instead pull the target out of the driver. This is currently +/// necessary because the driver doesn't store the final version of the target +/// triple. +void Generic_GCC::GCCInstallationDetector::init( + const llvm::Triple &TargetTriple, const ArgList &Args, + ArrayRef<std::string> ExtraTripleAliases) { + llvm::Triple BiarchVariantTriple = TargetTriple.isArch32Bit() + ? TargetTriple.get64BitArchVariant() + : TargetTriple.get32BitArchVariant(); + // The library directories which may contain GCC installations. + SmallVector<StringRef, 4> CandidateLibDirs, CandidateBiarchLibDirs; + // The compatible GCC triples for this particular architecture. + SmallVector<StringRef, 16> CandidateTripleAliases; + SmallVector<StringRef, 16> CandidateBiarchTripleAliases; + CollectLibDirsAndTriples(TargetTriple, BiarchVariantTriple, CandidateLibDirs, + CandidateTripleAliases, CandidateBiarchLibDirs, + CandidateBiarchTripleAliases); + + // Compute the set of prefixes for our search. + SmallVector<std::string, 8> Prefixes(D.PrefixDirs.begin(), + D.PrefixDirs.end()); + + StringRef GCCToolchainDir = getGCCToolchainDir(Args); + if (GCCToolchainDir != "") { + if (GCCToolchainDir.back() == '/') + GCCToolchainDir = GCCToolchainDir.drop_back(); // remove the / + + Prefixes.push_back(GCCToolchainDir); + } else { + // If we have a SysRoot, try that first. + if (!D.SysRoot.empty()) { + Prefixes.push_back(D.SysRoot); + Prefixes.push_back(D.SysRoot + "/usr"); + } + + // Then look for gcc installed alongside clang. + Prefixes.push_back(D.InstalledDir + "/.."); + + // Then look for distribution supplied gcc installations. + if (D.SysRoot.empty()) { + // Look for RHEL devtoolsets. + Prefixes.push_back("/opt/rh/devtoolset-6/root/usr"); + Prefixes.push_back("/opt/rh/devtoolset-4/root/usr"); + Prefixes.push_back("/opt/rh/devtoolset-3/root/usr"); + Prefixes.push_back("/opt/rh/devtoolset-2/root/usr"); + // And finally in /usr. + Prefixes.push_back("/usr"); + } + } + + // Try to respect gcc-config on Gentoo. However, do that only + // if --gcc-toolchain is not provided or equal to the Gentoo install + // in /usr. This avoids accidentally enforcing the system GCC version + // when using a custom toolchain. + if (GCCToolchainDir == "" || GCCToolchainDir == D.SysRoot + "/usr") { + for (StringRef CandidateTriple : ExtraTripleAliases) { + if (ScanGentooGccConfig(TargetTriple, Args, CandidateTriple)) + return; + } + for (StringRef CandidateTriple : CandidateTripleAliases) { + if (ScanGentooGccConfig(TargetTriple, Args, CandidateTriple)) + return; + } + for (StringRef CandidateTriple : CandidateBiarchTripleAliases) { + if (ScanGentooGccConfig(TargetTriple, Args, CandidateTriple, true)) + return; + } + } + + // Loop over the various components which exist and select the best GCC + // installation available. GCC installs are ranked by version number. + Version = GCCVersion::Parse("0.0.0"); + for (const std::string &Prefix : Prefixes) { + if (!D.getVFS().exists(Prefix)) + continue; + for (StringRef Suffix : CandidateLibDirs) { + const std::string LibDir = Prefix + Suffix.str(); + if (!D.getVFS().exists(LibDir)) + continue; + for (StringRef Candidate : ExtraTripleAliases) // Try these first. + ScanLibDirForGCCTriple(TargetTriple, Args, LibDir, Candidate); + for (StringRef Candidate : CandidateTripleAliases) + ScanLibDirForGCCTriple(TargetTriple, Args, LibDir, Candidate); + } + for (StringRef Suffix : CandidateBiarchLibDirs) { + const std::string LibDir = Prefix + Suffix.str(); + if (!D.getVFS().exists(LibDir)) + continue; + for (StringRef Candidate : CandidateBiarchTripleAliases) + ScanLibDirForGCCTriple(TargetTriple, Args, LibDir, Candidate, + /*NeedsBiarchSuffix=*/ true); + } + } +} + +void Generic_GCC::GCCInstallationDetector::print(raw_ostream &OS) const { + for (const auto &InstallPath : CandidateGCCInstallPaths) + OS << "Found candidate GCC installation: " << InstallPath << "\n"; + + if (!GCCInstallPath.empty()) + OS << "Selected GCC installation: " << GCCInstallPath << "\n"; + + for (const auto &Multilib : Multilibs) + OS << "Candidate multilib: " << Multilib << "\n"; + + if (Multilibs.size() != 0 || !SelectedMultilib.isDefault()) + OS << "Selected multilib: " << SelectedMultilib << "\n"; +} + +bool Generic_GCC::GCCInstallationDetector::getBiarchSibling(Multilib &M) const { + if (BiarchSibling.hasValue()) { + M = BiarchSibling.getValue(); + return true; + } + return false; +} + +/*static*/ void Generic_GCC::GCCInstallationDetector::CollectLibDirsAndTriples( + const llvm::Triple &TargetTriple, const llvm::Triple &BiarchTriple, + SmallVectorImpl<StringRef> &LibDirs, + SmallVectorImpl<StringRef> &TripleAliases, + SmallVectorImpl<StringRef> &BiarchLibDirs, + SmallVectorImpl<StringRef> &BiarchTripleAliases) { + // Declare a bunch of static data sets that we'll select between below. These + // are specifically designed to always refer to string literals to avoid any + // lifetime or initialization issues. + static const char *const AArch64LibDirs[] = {"/lib64", "/lib"}; + static const char *const AArch64Triples[] = { + "aarch64-none-linux-gnu", "aarch64-linux-gnu", "aarch64-linux-android", + "aarch64-redhat-linux", "aarch64-suse-linux"}; + static const char *const AArch64beLibDirs[] = {"/lib"}; + static const char *const AArch64beTriples[] = {"aarch64_be-none-linux-gnu", + "aarch64_be-linux-gnu"}; + + static const char *const ARMLibDirs[] = {"/lib"}; + static const char *const ARMTriples[] = {"arm-linux-gnueabi", + "arm-linux-androideabi"}; + static const char *const ARMHFTriples[] = {"arm-linux-gnueabihf", + "armv7hl-redhat-linux-gnueabi"}; + static const char *const ARMebLibDirs[] = {"/lib"}; + static const char *const ARMebTriples[] = {"armeb-linux-gnueabi", + "armeb-linux-androideabi"}; + static const char *const ARMebHFTriples[] = { + "armeb-linux-gnueabihf", "armebv7hl-redhat-linux-gnueabi"}; + + static const char *const X86_64LibDirs[] = {"/lib64", "/lib"}; + static const char *const X86_64Triples[] = { + "x86_64-linux-gnu", "x86_64-unknown-linux-gnu", + "x86_64-pc-linux-gnu", "x86_64-redhat-linux6E", + "x86_64-redhat-linux", "x86_64-suse-linux", + "x86_64-manbo-linux-gnu", "x86_64-linux-gnu", + "x86_64-slackware-linux", "x86_64-linux-android", + "x86_64-unknown-linux"}; + static const char *const X32LibDirs[] = {"/libx32"}; + static const char *const X86LibDirs[] = {"/lib32", "/lib"}; + static const char *const X86Triples[] = { + "i686-linux-gnu", "i686-pc-linux-gnu", "i486-linux-gnu", + "i386-linux-gnu", "i386-redhat-linux6E", "i686-redhat-linux", + "i586-redhat-linux", "i386-redhat-linux", "i586-suse-linux", + "i486-slackware-linux", "i686-montavista-linux", "i686-linux-android", + "i586-linux-gnu"}; + + static const char *const MIPSLibDirs[] = {"/lib"}; + static const char *const MIPSTriples[] = {"mips-linux-gnu", "mips-mti-linux", + "mips-mti-linux-gnu", + "mips-img-linux-gnu"}; + static const char *const MIPSELLibDirs[] = {"/lib"}; + static const char *const MIPSELTriples[] = {"mipsel-linux-gnu", + "mips-img-linux-gnu"}; + + static const char *const MIPS64LibDirs[] = {"/lib64", "/lib"}; + static const char *const MIPS64Triples[] = { + "mips64-linux-gnu", "mips-mti-linux-gnu", "mips-img-linux-gnu", + "mips64-linux-gnuabi64"}; + static const char *const MIPS64ELLibDirs[] = {"/lib64", "/lib"}; + static const char *const MIPS64ELTriples[] = { + "mips64el-linux-gnu", "mips-mti-linux-gnu", "mips-img-linux-gnu", + "mips64el-linux-gnuabi64"}; + + static const char *const MIPSELAndroidLibDirs[] = {"/lib", "/libr2", + "/libr6"}; + static const char *const MIPSELAndroidTriples[] = {"mipsel-linux-android"}; + static const char *const MIPS64ELAndroidLibDirs[] = {"/lib64", "/lib", + "/libr2", "/libr6"}; + static const char *const MIPS64ELAndroidTriples[] = { + "mips64el-linux-android"}; + + static const char *const PPCLibDirs[] = {"/lib32", "/lib"}; + static const char *const PPCTriples[] = { + "powerpc-linux-gnu", "powerpc-unknown-linux-gnu", "powerpc-linux-gnuspe", + "powerpc-suse-linux", "powerpc-montavista-linuxspe"}; + static const char *const PPC64LibDirs[] = {"/lib64", "/lib"}; + static const char *const PPC64Triples[] = { + "powerpc64-linux-gnu", "powerpc64-unknown-linux-gnu", + "powerpc64-suse-linux", "ppc64-redhat-linux"}; + static const char *const PPC64LELibDirs[] = {"/lib64", "/lib"}; + static const char *const PPC64LETriples[] = { + "powerpc64le-linux-gnu", "powerpc64le-unknown-linux-gnu", + "powerpc64le-suse-linux", "ppc64le-redhat-linux"}; + + static const char *const SPARCv8LibDirs[] = {"/lib32", "/lib"}; + static const char *const SPARCv8Triples[] = {"sparc-linux-gnu", + "sparcv8-linux-gnu"}; + static const char *const SPARCv9LibDirs[] = {"/lib64", "/lib"}; + static const char *const SPARCv9Triples[] = {"sparc64-linux-gnu", + "sparcv9-linux-gnu"}; + + static const char *const SystemZLibDirs[] = {"/lib64", "/lib"}; + static const char *const SystemZTriples[] = { + "s390x-linux-gnu", "s390x-unknown-linux-gnu", "s390x-ibm-linux-gnu", + "s390x-suse-linux", "s390x-redhat-linux"}; + + // Solaris. + static const char *const SolarisSPARCLibDirs[] = {"/gcc"}; + static const char *const SolarisSPARCTriples[] = {"sparc-sun-solaris2.11", + "i386-pc-solaris2.11"}; + + using std::begin; + using std::end; + + if (TargetTriple.getOS() == llvm::Triple::Solaris) { + LibDirs.append(begin(SolarisSPARCLibDirs), end(SolarisSPARCLibDirs)); + TripleAliases.append(begin(SolarisSPARCTriples), end(SolarisSPARCTriples)); + return; + } + + switch (TargetTriple.getArch()) { + case llvm::Triple::aarch64: + LibDirs.append(begin(AArch64LibDirs), end(AArch64LibDirs)); + TripleAliases.append(begin(AArch64Triples), end(AArch64Triples)); + BiarchLibDirs.append(begin(AArch64LibDirs), end(AArch64LibDirs)); + BiarchTripleAliases.append(begin(AArch64Triples), end(AArch64Triples)); + break; + case llvm::Triple::aarch64_be: + LibDirs.append(begin(AArch64beLibDirs), end(AArch64beLibDirs)); + TripleAliases.append(begin(AArch64beTriples), end(AArch64beTriples)); + BiarchLibDirs.append(begin(AArch64beLibDirs), end(AArch64beLibDirs)); + BiarchTripleAliases.append(begin(AArch64beTriples), end(AArch64beTriples)); + break; + case llvm::Triple::arm: + case llvm::Triple::thumb: + LibDirs.append(begin(ARMLibDirs), end(ARMLibDirs)); + if (TargetTriple.getEnvironment() == llvm::Triple::GNUEABIHF) { + TripleAliases.append(begin(ARMHFTriples), end(ARMHFTriples)); + } else { + TripleAliases.append(begin(ARMTriples), end(ARMTriples)); + } + break; + case llvm::Triple::armeb: + case llvm::Triple::thumbeb: + LibDirs.append(begin(ARMebLibDirs), end(ARMebLibDirs)); + if (TargetTriple.getEnvironment() == llvm::Triple::GNUEABIHF) { + TripleAliases.append(begin(ARMebHFTriples), end(ARMebHFTriples)); + } else { + TripleAliases.append(begin(ARMebTriples), end(ARMebTriples)); + } + break; + case llvm::Triple::x86_64: + LibDirs.append(begin(X86_64LibDirs), end(X86_64LibDirs)); + TripleAliases.append(begin(X86_64Triples), end(X86_64Triples)); + // x32 is always available when x86_64 is available, so adding it as + // secondary arch with x86_64 triples + if (TargetTriple.getEnvironment() == llvm::Triple::GNUX32) { + BiarchLibDirs.append(begin(X32LibDirs), end(X32LibDirs)); + BiarchTripleAliases.append(begin(X86_64Triples), end(X86_64Triples)); + } else { + BiarchLibDirs.append(begin(X86LibDirs), end(X86LibDirs)); + BiarchTripleAliases.append(begin(X86Triples), end(X86Triples)); + } + break; + case llvm::Triple::x86: + LibDirs.append(begin(X86LibDirs), end(X86LibDirs)); + // MCU toolchain is 32 bit only and its triple alias is TargetTriple + // itself, which will be appended below. + if (!TargetTriple.isOSIAMCU()) { + TripleAliases.append(begin(X86Triples), end(X86Triples)); + BiarchLibDirs.append(begin(X86_64LibDirs), end(X86_64LibDirs)); + BiarchTripleAliases.append(begin(X86_64Triples), end(X86_64Triples)); + } + break; + case llvm::Triple::mips: + LibDirs.append(begin(MIPSLibDirs), end(MIPSLibDirs)); + TripleAliases.append(begin(MIPSTriples), end(MIPSTriples)); + BiarchLibDirs.append(begin(MIPS64LibDirs), end(MIPS64LibDirs)); + BiarchTripleAliases.append(begin(MIPS64Triples), end(MIPS64Triples)); + break; + case llvm::Triple::mipsel: + if (TargetTriple.isAndroid()) { + LibDirs.append(begin(MIPSELAndroidLibDirs), end(MIPSELAndroidLibDirs)); + TripleAliases.append(begin(MIPSELAndroidTriples), + end(MIPSELAndroidTriples)); + BiarchLibDirs.append(begin(MIPS64ELAndroidLibDirs), + end(MIPS64ELAndroidLibDirs)); + BiarchTripleAliases.append(begin(MIPS64ELAndroidTriples), + end(MIPS64ELAndroidTriples)); + + } else { + LibDirs.append(begin(MIPSELLibDirs), end(MIPSELLibDirs)); + TripleAliases.append(begin(MIPSELTriples), end(MIPSELTriples)); + TripleAliases.append(begin(MIPSTriples), end(MIPSTriples)); + BiarchLibDirs.append(begin(MIPS64ELLibDirs), end(MIPS64ELLibDirs)); + BiarchTripleAliases.append(begin(MIPS64ELTriples), end(MIPS64ELTriples)); + } + break; + case llvm::Triple::mips64: + LibDirs.append(begin(MIPS64LibDirs), end(MIPS64LibDirs)); + TripleAliases.append(begin(MIPS64Triples), end(MIPS64Triples)); + BiarchLibDirs.append(begin(MIPSLibDirs), end(MIPSLibDirs)); + BiarchTripleAliases.append(begin(MIPSTriples), end(MIPSTriples)); + break; + case llvm::Triple::mips64el: + if (TargetTriple.isAndroid()) { + LibDirs.append(begin(MIPS64ELAndroidLibDirs), + end(MIPS64ELAndroidLibDirs)); + TripleAliases.append(begin(MIPS64ELAndroidTriples), + end(MIPS64ELAndroidTriples)); + BiarchLibDirs.append(begin(MIPSELAndroidLibDirs), + end(MIPSELAndroidLibDirs)); + BiarchTripleAliases.append(begin(MIPSELAndroidTriples), + end(MIPSELAndroidTriples)); + + } else { + LibDirs.append(begin(MIPS64ELLibDirs), end(MIPS64ELLibDirs)); + TripleAliases.append(begin(MIPS64ELTriples), end(MIPS64ELTriples)); + BiarchLibDirs.append(begin(MIPSELLibDirs), end(MIPSELLibDirs)); + BiarchTripleAliases.append(begin(MIPSELTriples), end(MIPSELTriples)); + BiarchTripleAliases.append(begin(MIPSTriples), end(MIPSTriples)); + } + break; + case llvm::Triple::ppc: + LibDirs.append(begin(PPCLibDirs), end(PPCLibDirs)); + TripleAliases.append(begin(PPCTriples), end(PPCTriples)); + BiarchLibDirs.append(begin(PPC64LibDirs), end(PPC64LibDirs)); + BiarchTripleAliases.append(begin(PPC64Triples), end(PPC64Triples)); + break; + case llvm::Triple::ppc64: + LibDirs.append(begin(PPC64LibDirs), end(PPC64LibDirs)); + TripleAliases.append(begin(PPC64Triples), end(PPC64Triples)); + BiarchLibDirs.append(begin(PPCLibDirs), end(PPCLibDirs)); + BiarchTripleAliases.append(begin(PPCTriples), end(PPCTriples)); + break; + case llvm::Triple::ppc64le: + LibDirs.append(begin(PPC64LELibDirs), end(PPC64LELibDirs)); + TripleAliases.append(begin(PPC64LETriples), end(PPC64LETriples)); + break; + case llvm::Triple::sparc: + case llvm::Triple::sparcel: + LibDirs.append(begin(SPARCv8LibDirs), end(SPARCv8LibDirs)); + TripleAliases.append(begin(SPARCv8Triples), end(SPARCv8Triples)); + BiarchLibDirs.append(begin(SPARCv9LibDirs), end(SPARCv9LibDirs)); + BiarchTripleAliases.append(begin(SPARCv9Triples), end(SPARCv9Triples)); + break; + case llvm::Triple::sparcv9: + LibDirs.append(begin(SPARCv9LibDirs), end(SPARCv9LibDirs)); + TripleAliases.append(begin(SPARCv9Triples), end(SPARCv9Triples)); + BiarchLibDirs.append(begin(SPARCv8LibDirs), end(SPARCv8LibDirs)); + BiarchTripleAliases.append(begin(SPARCv8Triples), end(SPARCv8Triples)); + break; + case llvm::Triple::systemz: + LibDirs.append(begin(SystemZLibDirs), end(SystemZLibDirs)); + TripleAliases.append(begin(SystemZTriples), end(SystemZTriples)); + break; + default: + // By default, just rely on the standard lib directories and the original + // triple. + break; + } + + // Always append the drivers target triple to the end, in case it doesn't + // match any of our aliases. + TripleAliases.push_back(TargetTriple.str()); + + // Also include the multiarch variant if it's different. + if (TargetTriple.str() != BiarchTriple.str()) + BiarchTripleAliases.push_back(BiarchTriple.str()); +} + +void Generic_GCC::GCCInstallationDetector::scanLibDirForGCCTripleSolaris( + const llvm::Triple &TargetArch, const llvm::opt::ArgList &Args, + const std::string &LibDir, StringRef CandidateTriple, + bool NeedsBiarchSuffix) { + // Solaris is a special case. The GCC installation is under + // /usr/gcc/<major>.<minor>/lib/gcc/<triple>/<major>.<minor>.<patch>/, so we + // need to iterate twice. + std::error_code EC; + for (vfs::directory_iterator LI = D.getVFS().dir_begin(LibDir, EC), LE; + !EC && LI != LE; LI = LI.increment(EC)) { + StringRef VersionText = llvm::sys::path::filename(LI->getName()); + GCCVersion CandidateVersion = GCCVersion::Parse(VersionText); + + if (CandidateVersion.Major != -1) // Filter obviously bad entries. + if (!CandidateGCCInstallPaths.insert(LI->getName()).second) + continue; // Saw this path before; no need to look at it again. + if (CandidateVersion.isOlderThan(4, 1, 1)) + continue; + if (CandidateVersion <= Version) + continue; + + GCCInstallPath = + LibDir + "/" + VersionText.str() + "/lib/gcc/" + CandidateTriple.str(); + if (!D.getVFS().exists(GCCInstallPath)) + continue; + + // If we make it here there has to be at least one GCC version, let's just + // use the latest one. + std::error_code EEC; + for (vfs::directory_iterator + LLI = D.getVFS().dir_begin(GCCInstallPath, EEC), + LLE; + !EEC && LLI != LLE; LLI = LLI.increment(EEC)) { + + StringRef SubVersionText = llvm::sys::path::filename(LLI->getName()); + GCCVersion CandidateSubVersion = GCCVersion::Parse(SubVersionText); + + if (CandidateSubVersion > Version) + Version = CandidateSubVersion; + } + + GCCTriple.setTriple(CandidateTriple); + + GCCInstallPath += "/" + Version.Text; + GCCParentLibPath = GCCInstallPath + "/../../../../"; + + IsValid = true; + } +} + +bool Generic_GCC::GCCInstallationDetector::ScanGCCForMultilibs( + const llvm::Triple &TargetTriple, const ArgList &Args, + StringRef Path, bool NeedsBiarchSuffix) { + llvm::Triple::ArchType TargetArch = TargetTriple.getArch(); + DetectedMultilibs Detected; + + // Android standalone toolchain could have multilibs for ARM and Thumb. + // Debian mips multilibs behave more like the rest of the biarch ones, + // so handle them there + if (isArmOrThumbArch(TargetArch) && TargetTriple.isAndroid()) { + // It should also work without multilibs in a simplified toolchain. + findAndroidArmMultilibs(D, TargetTriple, Path, Args, Detected); + } else if (tools::isMipsArch(TargetArch)) { + if (!findMIPSMultilibs(D, TargetTriple, Path, Args, Detected)) + return false; + } else if (!findBiarchMultilibs(D, TargetTriple, Path, Args, + NeedsBiarchSuffix, Detected)) { + return false; + } + + Multilibs = Detected.Multilibs; + SelectedMultilib = Detected.SelectedMultilib; + BiarchSibling = Detected.BiarchSibling; + + return true; +} + +void Generic_GCC::GCCInstallationDetector::ScanLibDirForGCCTriple( + const llvm::Triple &TargetTriple, const ArgList &Args, + const std::string &LibDir, StringRef CandidateTriple, + bool NeedsBiarchSuffix) { + if (TargetTriple.getOS() == llvm::Triple::Solaris) { + scanLibDirForGCCTripleSolaris(TargetTriple, Args, LibDir, CandidateTriple, + NeedsBiarchSuffix); + return; + } + + llvm::Triple::ArchType TargetArch = TargetTriple.getArch(); + // Locations relative to the system lib directory where GCC's triple-specific + // directories might reside. + struct GCCLibSuffix { + // Path from system lib directory to GCC triple-specific directory. + std::string LibSuffix; + // Path from GCC triple-specific directory back to system lib directory. + // This is one '..' component per component in LibSuffix. + StringRef ReversePath; + // Whether this library suffix is relevant for the triple. + bool Active; + } Suffixes[] = { + // This is the normal place. + {"gcc/" + CandidateTriple.str(), "../..", true}, + + // Debian puts cross-compilers in gcc-cross. + {"gcc-cross/" + CandidateTriple.str(), "../..", true}, + + // The Freescale PPC SDK has the gcc libraries in + // <sysroot>/usr/lib/<triple>/x.y.z so have a look there as well. Only do + // this on Freescale triples, though, since some systems put a *lot* of + // files in that location, not just GCC installation data. + {CandidateTriple.str(), "..", + TargetTriple.getVendor() == llvm::Triple::Freescale}, + + // Natively multiarch systems sometimes put the GCC triple-specific + // directory within their multiarch lib directory, resulting in the + // triple appearing twice. + {CandidateTriple.str() + "/gcc/" + CandidateTriple.str(), "../../..", true}, + + // Deal with cases (on Ubuntu) where the system architecture could be i386 + // but the GCC target architecture could be (say) i686. + // FIXME: It may be worthwhile to generalize this and look for a second + // triple. + {"i386-linux-gnu/gcc/" + CandidateTriple.str(), "../../..", + TargetArch == llvm::Triple::x86} + }; + + for (auto &Suffix : Suffixes) { + if (!Suffix.Active) + continue; + + StringRef LibSuffix = Suffix.LibSuffix; + std::error_code EC; + for (vfs::directory_iterator + LI = D.getVFS().dir_begin(LibDir + "/" + LibSuffix, EC), + LE; + !EC && LI != LE; LI = LI.increment(EC)) { + StringRef VersionText = llvm::sys::path::filename(LI->getName()); + GCCVersion CandidateVersion = GCCVersion::Parse(VersionText); + if (CandidateVersion.Major != -1) // Filter obviously bad entries. + if (!CandidateGCCInstallPaths.insert(LI->getName()).second) + continue; // Saw this path before; no need to look at it again. + if (CandidateVersion.isOlderThan(4, 1, 1)) + continue; + if (CandidateVersion <= Version) + continue; + + if (!ScanGCCForMultilibs(TargetTriple, Args, LI->getName(), + NeedsBiarchSuffix)) + continue; + + Version = CandidateVersion; + GCCTriple.setTriple(CandidateTriple); + // FIXME: We hack together the directory name here instead of + // using LI to ensure stable path separators across Windows and + // Linux. + GCCInstallPath = (LibDir + "/" + LibSuffix + "/" + VersionText).str(); + GCCParentLibPath = (GCCInstallPath + "/../" + Suffix.ReversePath).str(); + IsValid = true; + } + } +} + +bool Generic_GCC::GCCInstallationDetector::ScanGentooGccConfig( + const llvm::Triple &TargetTriple, const ArgList &Args, + StringRef CandidateTriple, bool NeedsBiarchSuffix) { + llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> File = + D.getVFS().getBufferForFile(D.SysRoot + "/etc/env.d/gcc/config-" + + CandidateTriple.str()); + if (File) { + SmallVector<StringRef, 2> Lines; + File.get()->getBuffer().split(Lines, "\n"); + for (StringRef Line : Lines) { + // CURRENT=triple-version + if (Line.consume_front("CURRENT=")) { + const std::pair<StringRef, StringRef> ActiveVersion = + Line.rsplit('-'); + // Note: Strictly speaking, we should be reading + // /etc/env.d/gcc/${CURRENT} now. However, the file doesn't + // contain anything new or especially useful to us. + const std::string GentooPath = D.SysRoot + "/usr/lib/gcc/" + + ActiveVersion.first.str() + "/" + + ActiveVersion.second.str(); + if (D.getVFS().exists(GentooPath + "/crtbegin.o")) { + if (!ScanGCCForMultilibs(TargetTriple, Args, GentooPath, + NeedsBiarchSuffix)) + return false; + + Version = GCCVersion::Parse(ActiveVersion.second); + GCCInstallPath = GentooPath; + GCCParentLibPath = GentooPath + "/../../.."; + GCCTriple.setTriple(ActiveVersion.first); + IsValid = true; + return true; + } + } + } + } + + return false; +} + +Generic_GCC::Generic_GCC(const Driver &D, const llvm::Triple &Triple, + const ArgList &Args) + : ToolChain(D, Triple, Args), GCCInstallation(D), + CudaInstallation(D, Triple, Args) { + getProgramPaths().push_back(getDriver().getInstalledDir()); + if (getDriver().getInstalledDir() != getDriver().Dir) + getProgramPaths().push_back(getDriver().Dir); +} + +Generic_GCC::~Generic_GCC() {} + +Tool *Generic_GCC::getTool(Action::ActionClass AC) const { + switch (AC) { + case Action::PreprocessJobClass: + if (!Preprocess) + Preprocess.reset(new clang::driver::tools::gcc::Preprocessor(*this)); + return Preprocess.get(); + case Action::CompileJobClass: + if (!Compile) + Compile.reset(new tools::gcc::Compiler(*this)); + return Compile.get(); + default: + return ToolChain::getTool(AC); + } +} + +Tool *Generic_GCC::buildAssembler() const { + return new tools::gnutools::Assembler(*this); +} + +Tool *Generic_GCC::buildLinker() const { return new tools::gcc::Linker(*this); } + +void Generic_GCC::printVerboseInfo(raw_ostream &OS) const { + // Print the information about how we detected the GCC installation. + GCCInstallation.print(OS); + CudaInstallation.print(OS); +} + +bool Generic_GCC::IsUnwindTablesDefault() const { + return getArch() == llvm::Triple::x86_64; +} + +bool Generic_GCC::isPICDefault() const { + switch (getArch()) { + case llvm::Triple::x86_64: + return getTriple().isOSWindows(); + case llvm::Triple::ppc64: + case llvm::Triple::ppc64le: + return !getTriple().isOSBinFormatMachO() && !getTriple().isMacOSX(); + case llvm::Triple::mips64: + case llvm::Triple::mips64el: + return true; + default: + return false; + } +} + +bool Generic_GCC::isPIEDefault() const { return false; } + +bool Generic_GCC::isPICDefaultForced() const { + return getArch() == llvm::Triple::x86_64 && getTriple().isOSWindows(); +} + +bool Generic_GCC::IsIntegratedAssemblerDefault() const { + switch (getTriple().getArch()) { + case llvm::Triple::x86: + case llvm::Triple::x86_64: + case llvm::Triple::aarch64: + case llvm::Triple::aarch64_be: + case llvm::Triple::arm: + case llvm::Triple::armeb: + case llvm::Triple::avr: + case llvm::Triple::bpfel: + case llvm::Triple::bpfeb: + case llvm::Triple::thumb: + case llvm::Triple::thumbeb: + case llvm::Triple::ppc: + case llvm::Triple::ppc64: + case llvm::Triple::ppc64le: + case llvm::Triple::systemz: + case llvm::Triple::mips: + case llvm::Triple::mipsel: + return true; + case llvm::Triple::mips64: + case llvm::Triple::mips64el: + // Enabled for Debian mips64/mips64el only. Other targets are unable to + // distinguish N32 from N64. + if (getTriple().getEnvironment() == llvm::Triple::GNUABI64) + return true; + return false; + default: + return false; + } +} + +void Generic_GCC::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs, + ArgStringList &CC1Args) const { + if (DriverArgs.hasArg(options::OPT_nostdlibinc) || + DriverArgs.hasArg(options::OPT_nostdincxx)) + return; + + switch (GetCXXStdlibType(DriverArgs)) { + case ToolChain::CST_Libcxx: { + std::string Path = findLibCxxIncludePath(); + if (!Path.empty()) + addSystemInclude(DriverArgs, CC1Args, Path); + break; + } + + case ToolChain::CST_Libstdcxx: + addLibStdCxxIncludePaths(DriverArgs, CC1Args); + break; + } +} + +std::string Generic_GCC::findLibCxxIncludePath() const { + // FIXME: The Linux behavior would probaby be a better approach here. + return getDriver().SysRoot + "/usr/include/c++/v1"; +} + +void +Generic_GCC::addLibStdCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const { + // By default, we don't assume we know where libstdc++ might be installed. + // FIXME: If we have a valid GCCInstallation, use it. +} + +/// \brief Helper to add the variant paths of a libstdc++ installation. +bool Generic_GCC::addLibStdCXXIncludePaths( + Twine Base, Twine Suffix, StringRef GCCTriple, StringRef GCCMultiarchTriple, + StringRef TargetMultiarchTriple, Twine IncludeSuffix, + const ArgList &DriverArgs, ArgStringList &CC1Args) const { + if (!getVFS().exists(Base + Suffix)) + return false; + + addSystemInclude(DriverArgs, CC1Args, Base + Suffix); + + // The vanilla GCC layout of libstdc++ headers uses a triple subdirectory. If + // that path exists or we have neither a GCC nor target multiarch triple, use + // this vanilla search path. + if ((GCCMultiarchTriple.empty() && TargetMultiarchTriple.empty()) || + getVFS().exists(Base + Suffix + "/" + GCCTriple + IncludeSuffix)) { + addSystemInclude(DriverArgs, CC1Args, + Base + Suffix + "/" + GCCTriple + IncludeSuffix); + } else { + // Otherwise try to use multiarch naming schemes which have normalized the + // triples and put the triple before the suffix. + // + // GCC surprisingly uses *both* the GCC triple with a multilib suffix and + // the target triple, so we support that here. + addSystemInclude(DriverArgs, CC1Args, + Base + "/" + GCCMultiarchTriple + Suffix + IncludeSuffix); + addSystemInclude(DriverArgs, CC1Args, + Base + "/" + TargetMultiarchTriple + Suffix); + } + + addSystemInclude(DriverArgs, CC1Args, Base + Suffix + "/backward"); + return true; +} + +llvm::opt::DerivedArgList * +Generic_GCC::TranslateArgs(const llvm::opt::DerivedArgList &Args, StringRef, + Action::OffloadKind DeviceOffloadKind) const { + + // If this tool chain is used for an OpenMP offloading device we have to make + // sure we always generate a shared library regardless of the commands the + // user passed to the host. This is required because the runtime library + // is required to load the device image dynamically at run time. + if (DeviceOffloadKind == Action::OFK_OpenMP) { + DerivedArgList *DAL = new DerivedArgList(Args.getBaseArgs()); + const OptTable &Opts = getDriver().getOpts(); + + // Request the shared library. Given that these options are decided + // implicitly, they do not refer to any base argument. + DAL->AddFlagArg(/*BaseArg=*/nullptr, Opts.getOption(options::OPT_shared)); + DAL->AddFlagArg(/*BaseArg=*/nullptr, Opts.getOption(options::OPT_fPIC)); + + // Filter all the arguments we don't care passing to the offloading + // toolchain as they can mess up with the creation of a shared library. + for (auto *A : Args) { + switch ((options::ID)A->getOption().getID()) { + default: + DAL->append(A); + break; + case options::OPT_shared: + case options::OPT_dynamic: + case options::OPT_static: + case options::OPT_fPIC: + case options::OPT_fno_PIC: + case options::OPT_fpic: + case options::OPT_fno_pic: + case options::OPT_fPIE: + case options::OPT_fno_PIE: + case options::OPT_fpie: + case options::OPT_fno_pie: + break; + } + } + return DAL; + } + return nullptr; +} + +void Generic_ELF::anchor() {} + +void Generic_ELF::addClangTargetOptions(const ArgList &DriverArgs, + ArgStringList &CC1Args) const { + const Generic_GCC::GCCVersion &V = GCCInstallation.getVersion(); + bool UseInitArrayDefault = + getTriple().getArch() == llvm::Triple::aarch64 || + getTriple().getArch() == llvm::Triple::aarch64_be || + (getTriple().getOS() == llvm::Triple::Linux && + (!V.isOlderThan(4, 7, 0) || getTriple().isAndroid())) || + getTriple().getOS() == llvm::Triple::NaCl || + (getTriple().getVendor() == llvm::Triple::MipsTechnologies && + !getTriple().hasEnvironment()); + + if (DriverArgs.hasFlag(options::OPT_fuse_init_array, + options::OPT_fno_use_init_array, UseInitArrayDefault)) + CC1Args.push_back("-fuse-init-array"); +} |