diff options
Diffstat (limited to 'lib/Driver/ToolChains')
46 files changed, 2850 insertions, 2205 deletions
diff --git a/lib/Driver/ToolChains/AMDGPU.cpp b/lib/Driver/ToolChains/AMDGPU.cpp index 63e1749e0088..a313bc5c35de 100644 --- a/lib/Driver/ToolChains/AMDGPU.cpp +++ b/lib/Driver/ToolChains/AMDGPU.cpp @@ -8,9 +8,10 @@ //===----------------------------------------------------------------------===// #include "AMDGPU.h" -#include "InputInfo.h" #include "CommonArgs.h" +#include "InputInfo.h" #include "clang/Driver/Compilation.h" +#include "clang/Driver/DriverDiagnostic.h" #include "llvm/Option/ArgList.h" using namespace clang::driver; @@ -35,11 +36,66 @@ void amdgpu::Linker::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs, Inputs)); } +void amdgpu::getAMDGPUTargetFeatures(const Driver &D, + const llvm::opt::ArgList &Args, + std::vector<StringRef> &Features) { + if (const Arg *dAbi = Args.getLastArg(options::OPT_mamdgpu_debugger_abi)) { + StringRef value = dAbi->getValue(); + if (value == "1.0") { + Features.push_back("+amdgpu-debugger-insert-nops"); + Features.push_back("+amdgpu-debugger-reserve-regs"); + Features.push_back("+amdgpu-debugger-emit-prologue"); + } else { + D.Diag(diag::err_drv_clang_unsupported) << dAbi->getAsString(Args); + } + } + + handleTargetFeaturesGroup( + Args, Features, options::OPT_m_amdgpu_Features_Group); +} + /// AMDGPU Toolchain AMDGPUToolChain::AMDGPUToolChain(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) - : Generic_ELF(D, Triple, Args) { } + : Generic_ELF(D, Triple, Args), + OptionsDefault({{options::OPT_O, "3"}, + {options::OPT_cl_std_EQ, "CL1.2"}}) {} Tool *AMDGPUToolChain::buildLinker() const { return new tools::amdgpu::Linker(*this); } + +DerivedArgList * +AMDGPUToolChain::TranslateArgs(const DerivedArgList &Args, StringRef BoundArch, + Action::OffloadKind DeviceOffloadKind) const { + + DerivedArgList *DAL = + Generic_ELF::TranslateArgs(Args, BoundArch, DeviceOffloadKind); + + // Do nothing if not OpenCL (-x cl) + if (!Args.getLastArgValue(options::OPT_x).equals("cl")) + return DAL; + + if (!DAL) + DAL = new DerivedArgList(Args.getBaseArgs()); + for (auto *A : Args) + DAL->append(A); + + const OptTable &Opts = getDriver().getOpts(); + + // Phase 1 (.cl -> .bc) + if (Args.hasArg(options::OPT_c) && Args.hasArg(options::OPT_emit_llvm)) { + DAL->AddFlagArg(nullptr, Opts.getOption(getTriple().isArch64Bit() + ? options::OPT_m64 + : options::OPT_m32)); + + // Have to check OPT_O4, OPT_O0 & OPT_Ofast separately + // as they defined that way in Options.td + if (!Args.hasArg(options::OPT_O, options::OPT_O0, options::OPT_O4, + options::OPT_Ofast)) + DAL->AddJoinedArg(nullptr, Opts.getOption(options::OPT_O), + getOptionDefault(options::OPT_O)); + } + + return DAL; +} diff --git a/lib/Driver/ToolChains/AMDGPU.h b/lib/Driver/ToolChains/AMDGPU.h index 9af1e96489eb..36114d0dabc4 100644 --- a/lib/Driver/ToolChains/AMDGPU.h +++ b/lib/Driver/ToolChains/AMDGPU.h @@ -11,13 +11,14 @@ #define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_AMDGPU_H #include "Gnu.h" +#include "clang/Driver/Options.h" #include "clang/Driver/Tool.h" #include "clang/Driver/ToolChain.h" +#include <map> namespace clang { namespace driver { namespace tools { - namespace amdgpu { class LLVM_LIBRARY_VISIBILITY Linker : public GnuTool { @@ -31,20 +32,35 @@ public: const char *LinkingOutput) const override; }; +void getAMDGPUTargetFeatures(const Driver &D, const llvm::opt::ArgList &Args, + std::vector<StringRef> &Features); + } // end namespace amdgpu } // end namespace tools namespace toolchains { class LLVM_LIBRARY_VISIBILITY AMDGPUToolChain : public Generic_ELF { + +private: + const std::map<options::ID, const StringRef> OptionsDefault; + protected: Tool *buildLinker() const override; + const StringRef getOptionDefault(options::ID OptID) const { + auto opt = OptionsDefault.find(OptID); + assert(opt != OptionsDefault.end() && "No Default for Option"); + return opt->second; + } public: AMDGPUToolChain(const Driver &D, const llvm::Triple &Triple, - const llvm::opt::ArgList &Args); + const llvm::opt::ArgList &Args); unsigned GetDefaultDwarfVersion() const override { return 2; } bool IsIntegratedAssemblerDefault() const override { return true; } + llvm::opt::DerivedArgList * + TranslateArgs(const llvm::opt::DerivedArgList &Args, StringRef BoundArch, + Action::OffloadKind DeviceOffloadKind) const override; }; } // end namespace toolchains diff --git a/lib/Driver/ToolChains/Ananas.cpp b/lib/Driver/ToolChains/Ananas.cpp index a67e1d2378f5..ee072cc03e7c 100644 --- a/lib/Driver/ToolChains/Ananas.cpp +++ b/lib/Driver/ToolChains/Ananas.cpp @@ -91,11 +91,10 @@ void ananas::Linker::ConstructJob(Compilation &C, const JobAction &JA, AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA); - if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { - if (D.CCCIsCXX()) - ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs); + if (ToolChain.ShouldLinkCXXStdlib(Args)) + ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs); + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) CmdArgs.push_back("-lc"); - } if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) { CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtend.o"))); diff --git a/lib/Driver/ToolChains/Arch/AArch64.cpp b/lib/Driver/ToolChains/Arch/AArch64.cpp index 554d051fb155..ad04aedd098e 100644 --- a/lib/Driver/ToolChains/Arch/AArch64.cpp +++ b/lib/Driver/ToolChains/Arch/AArch64.cpp @@ -20,14 +20,12 @@ using namespace clang; using namespace llvm::opt; /// getAArch64TargetCPU - Get the (LLVM) name of the AArch64 cpu we are -/// targeting. Set \p A to the Arg corresponding to the -mcpu or -mtune -/// arguments if they are provided, or to nullptr otherwise. +/// targeting. Set \p A to the Arg corresponding to the -mcpu argument if it is +/// provided, or to nullptr otherwise. std::string aarch64::getAArch64TargetCPU(const ArgList &Args, Arg *&A) { std::string CPU; - // If we have -mtune or -mcpu, use that. - if ((A = Args.getLastArg(clang::driver::options::OPT_mtune_EQ))) { - CPU = StringRef(A->getValue()).lower(); - } else if ((A = Args.getLastArg(options::OPT_mcpu_EQ))) { + // If we have -mcpu, use that. + if ((A = Args.getLastArg(options::OPT_mcpu_EQ))) { StringRef Mcpu = A->getValue(); CPU = Mcpu.split("+").first.lower(); } @@ -74,7 +72,7 @@ static bool DecodeAArch64Mcpu(const Driver &D, StringRef Mcpu, StringRef &CPU, if (CPU == "generic") { Features.push_back("+neon"); } else { - unsigned ArchKind = llvm::AArch64::parseCPUArch(CPU); + llvm::AArch64::ArchKind ArchKind = llvm::AArch64::parseCPUArch(CPU); if (!llvm::AArch64::getArchFeatures(ArchKind, Features)) return false; @@ -96,8 +94,8 @@ getAArch64ArchFeaturesFromMarch(const Driver &D, StringRef March, std::string MarchLowerCase = March.lower(); std::pair<StringRef, StringRef> Split = StringRef(MarchLowerCase).split("+"); - unsigned ArchKind = llvm::AArch64::parseArch(Split.first); - if (ArchKind == static_cast<unsigned>(llvm::AArch64::ArchKind::AK_INVALID) || + llvm::AArch64::ArchKind ArchKind = llvm::AArch64::parseArch(Split.first); + if (ArchKind == llvm::AArch64::ArchKind::INVALID || !llvm::AArch64::getArchFeatures(ArchKind, Features) || (Split.second.size() && !DecodeAArch64Features(D, Split.second, Features))) return false; @@ -122,6 +120,12 @@ getAArch64MicroArchFeaturesFromMtune(const Driver &D, StringRef Mtune, const ArgList &Args, std::vector<StringRef> &Features) { std::string MtuneLowerCase = Mtune.lower(); + // Check CPU name is valid + std::vector<StringRef> MtuneFeatures; + StringRef Tune; + if (!DecodeAArch64Mcpu(D, MtuneLowerCase, Tune, MtuneFeatures)) + return false; + // Handle CPU name is 'native'. if (MtuneLowerCase == "native") MtuneLowerCase = llvm::sys::getHostCPUName(); diff --git a/lib/Driver/ToolChains/Arch/ARM.cpp b/lib/Driver/ToolChains/Arch/ARM.cpp index 95b86f784f91..44c8871d0e1f 100644 --- a/lib/Driver/ToolChains/Arch/ARM.cpp +++ b/lib/Driver/ToolChains/Arch/ARM.cpp @@ -29,8 +29,7 @@ int arm::getARMSubArchVersionNumber(const llvm::Triple &Triple) { // True if M-profile. bool arm::isARMMProfile(const llvm::Triple &Triple) { llvm::StringRef Arch = Triple.getArchName(); - unsigned Profile = llvm::ARM::parseArchProfile(Arch); - return Profile == llvm::ARM::PK_M; + return llvm::ARM::parseArchProfile(Arch) == llvm::ARM::ProfileKind::M; } // Get Arch/CPU from args. @@ -88,6 +87,15 @@ static bool DecodeARMFeatures(const Driver &D, StringRef text, return true; } +static void DecodeARMFeaturesFromCPU(const Driver &D, StringRef CPU, + std::vector<StringRef> &Features) { + if (CPU != "generic") { + llvm::ARM::ArchKind ArchKind = llvm::ARM::parseCPUArch(CPU); + unsigned Extension = llvm::ARM::getDefaultExtensions(CPU, ArchKind); + llvm::ARM::getExtensionFeatures(Extension, Features); + } +} + // Check if -march is valid by checking if it can be canonicalised and parsed. // getARMArch is used here instead of just checking the -march value in order // to handle -march=native correctly. @@ -98,7 +106,7 @@ static void checkARMArchName(const Driver &D, const Arg *A, const ArgList &Args, std::pair<StringRef, StringRef> Split = ArchName.split("+"); std::string MArch = arm::getARMArch(ArchName, Triple); - if (llvm::ARM::parseArch(MArch) == llvm::ARM::AK_INVALID || + if (llvm::ARM::parseArch(MArch) == llvm::ARM::ArchKind::INVALID || (Split.second.size() && !DecodeARMFeatures(D, Split.second, Features))) D.Diag(clang::diag::err_drv_clang_unsupported) << A->getAsString(Args); } @@ -123,6 +131,26 @@ bool arm::useAAPCSForMachO(const llvm::Triple &T) { T.getOS() == llvm::Triple::UnknownOS || isARMMProfile(T); } +// Select mode for reading thread pointer (-mtp=soft/cp15). +arm::ReadTPMode arm::getReadTPMode(const ToolChain &TC, const ArgList &Args) { + if (Arg *A = Args.getLastArg(options::OPT_mtp_mode_EQ)) { + const Driver &D = TC.getDriver(); + arm::ReadTPMode ThreadPointer = + llvm::StringSwitch<arm::ReadTPMode>(A->getValue()) + .Case("cp15", ReadTPMode::Cp15) + .Case("soft", ReadTPMode::Soft) + .Default(ReadTPMode::Invalid); + if (ThreadPointer != ReadTPMode::Invalid) + return ThreadPointer; + if (StringRef(A->getValue()).empty()) + D.Diag(diag::err_drv_missing_arg_mtp) << A->getAsString(Args); + else + D.Diag(diag::err_drv_invalid_mtp) << A->getAsString(Args); + return ReadTPMode::Invalid; + } + return ReadTPMode::Soft; +} + // Select the float ABI as determined by -msoft-float, -mhard-float, and // -mfloat-abi=. arm::FloatABI arm::getARMFloatABI(const ToolChain &TC, const ArgList &Args) { @@ -254,6 +282,7 @@ void arm::getARMTargetFeatures(const ToolChain &TC, bool KernelOrKext = Args.hasArg(options::OPT_mkernel, options::OPT_fapple_kext); arm::FloatABI ABI = arm::getARMFloatABI(TC, Args); + arm::ReadTPMode ThreadPointer = arm::getReadTPMode(TC, Args); const Arg *WaCPU = nullptr, *WaFPU = nullptr; const Arg *WaHDiv = nullptr, *WaArch = nullptr; @@ -295,6 +324,9 @@ void arm::getARMTargetFeatures(const ToolChain &TC, } } + if (ThreadPointer == arm::ReadTPMode::Cp15) + Features.push_back("+read-tp-hard"); + // Check -march. ClangAs gives preference to -Wa,-march=. const Arg *ArchArg = Args.getLastArg(options::OPT_march_EQ); StringRef ArchName; @@ -332,6 +364,8 @@ void arm::getARMTargetFeatures(const ToolChain &TC, for (auto &F : HostFeatures) Features.push_back( Args.MakeArgString((F.second ? "+" : "-") + F.first())); + } else if (!CPUName.empty()) { + DecodeARMFeaturesFromCPU(D, CPUName, Features); } // Honor -mfpu=. ClangAs gives preference to -Wa,-mfpu=. @@ -393,7 +427,7 @@ void arm::getARMTargetFeatures(const ToolChain &TC, if (Arg *A = Args.getLastArg(options::OPT_mexecute_only, options::OPT_mno_execute_only)) { if (A->getOption().matches(options::OPT_mexecute_only)) { if (getARMSubArchVersionNumber(Triple) < 7 && - llvm::ARM::parseArch(Triple.getArchName()) != llvm::ARM::AK_ARMV6T2) + llvm::ARM::parseArch(Triple.getArchName()) != llvm::ARM::ArchKind::ARMV6T2) D.Diag(diag::err_target_unsupported_execute_only) << Triple.getArchName(); else if (Arg *B = Args.getLastArg(options::OPT_mno_movt)) D.Diag(diag::err_opt_not_valid_with_opt) << A->getAsString(Args) << B->getAsString(Args); @@ -525,11 +559,11 @@ std::string arm::getARMTargetCPU(StringRef CPU, StringRef Arch, // FIXME: This is redundant with -mcpu, why does LLVM use this. StringRef arm::getLLVMArchSuffixForARM(StringRef CPU, StringRef Arch, const llvm::Triple &Triple) { - unsigned ArchKind; + llvm::ARM::ArchKind ArchKind; if (CPU == "generic") { std::string ARMArch = tools::arm::getARMArch(Arch, Triple); ArchKind = llvm::ARM::parseArch(ARMArch); - if (ArchKind == llvm::ARM::AK_INVALID) + if (ArchKind == llvm::ARM::ArchKind::INVALID) // In case of generic Arch, i.e. "arm", // extract arch from default cpu of the Triple ArchKind = llvm::ARM::parseCPUArch(Triple.getARMCPUForArch(ARMArch)); @@ -537,10 +571,10 @@ StringRef arm::getLLVMArchSuffixForARM(StringRef CPU, StringRef Arch, // FIXME: horrible hack to get around the fact that Cortex-A7 is only an // armv7k triple if it's actually been specified via "-arch armv7k". ArchKind = (Arch == "armv7k" || Arch == "thumbv7k") - ? (unsigned)llvm::ARM::AK_ARMV7K + ? llvm::ARM::ArchKind::ARMV7K : llvm::ARM::parseCPUArch(CPU); } - if (ArchKind == llvm::ARM::AK_INVALID) + if (ArchKind == llvm::ARM::ArchKind::INVALID) return ""; return llvm::ARM::getSubArch(ArchKind); } diff --git a/lib/Driver/ToolChains/Arch/ARM.h b/lib/Driver/ToolChains/Arch/ARM.h index 52afaab762d0..c1dc16884033 100644 --- a/lib/Driver/ToolChains/Arch/ARM.h +++ b/lib/Driver/ToolChains/Arch/ARM.h @@ -32,6 +32,12 @@ StringRef getLLVMArchSuffixForARM(llvm::StringRef CPU, llvm::StringRef Arch, void appendEBLinkFlags(const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs, const llvm::Triple &Triple); +enum class ReadTPMode { + Invalid, + Soft, + Cp15, +}; + enum class FloatABI { Invalid, Soft, @@ -40,6 +46,7 @@ enum class FloatABI { }; FloatABI getARMFloatABI(const ToolChain &TC, const llvm::opt::ArgList &Args); +ReadTPMode getReadTPMode(const ToolChain &TC, const llvm::opt::ArgList &Args); bool useAAPCSForMachO(const llvm::Triple &T); void getARMArchCPUFromArgs(const llvm::opt::ArgList &Args, diff --git a/lib/Driver/ToolChains/Arch/Mips.cpp b/lib/Driver/ToolChains/Arch/Mips.cpp index b45dcd6db678..61481a92d0b7 100644 --- a/lib/Driver/ToolChains/Arch/Mips.cpp +++ b/lib/Driver/ToolChains/Arch/Mips.cpp @@ -35,7 +35,7 @@ void mips::getMipsCPUAndABI(const ArgList &Args, const llvm::Triple &Triple, // MIPS32r6 is the default for mips(el)?-img-linux-gnu and MIPS64r6 is the // default for mips64(el)?-img-linux-gnu. if (Triple.getVendor() == llvm::Triple::ImaginationTechnologies && - Triple.getEnvironment() == llvm::Triple::GNU) { + Triple.isGNUEnvironment()) { DefMips32CPU = "mips32r6"; DefMips64CPU = "mips64r6"; } @@ -227,11 +227,32 @@ void mips::getMIPSTargetFeatures(const Driver &D, const llvm::Triple &Triple, O.matches(options::OPT_fno_PIE) || O.matches(options::OPT_fno_pie)); } - if (IsN64 && NonPIC) + bool UseAbiCalls = false; + + Arg *ABICallsArg = + Args.getLastArg(options::OPT_mabicalls, options::OPT_mno_abicalls); + UseAbiCalls = + !ABICallsArg || ABICallsArg->getOption().matches(options::OPT_mabicalls); + + if (UseAbiCalls && IsN64 && NonPIC) { + D.Diag(diag::warn_drv_unsupported_abicalls); + UseAbiCalls = false; + } + + if (!UseAbiCalls) Features.push_back("+noabicalls"); else - AddTargetFeature(Args, Features, options::OPT_mno_abicalls, - options::OPT_mabicalls, "noabicalls"); + Features.push_back("-noabicalls"); + + if (Arg *A = Args.getLastArg(options::OPT_mlong_calls, + options::OPT_mno_long_calls)) { + if (A->getOption().matches(options::OPT_mno_long_calls)) + Features.push_back("-long-calls"); + else if (!UseAbiCalls) + Features.push_back("+long-calls"); + else + D.Diag(diag::warn_drv_unsupported_longcalls) << (ABICallsArg ? 0 : 1); + } mips::FloatABI FloatABI = mips::getMipsFloatABI(D, Args); if (FloatABI == mips::FloatABI::Soft) { @@ -244,14 +265,14 @@ void mips::getMIPSTargetFeatures(const Driver &D, const llvm::Triple &Triple, if (Arg *A = Args.getLastArg(options::OPT_mnan_EQ)) { StringRef Val = StringRef(A->getValue()); if (Val == "2008") { - if (mips::getSupportedNanEncoding(CPUName) & mips::Nan2008) + if (mips::getIEEE754Standard(CPUName) & mips::Std2008) Features.push_back("+nan2008"); else { Features.push_back("-nan2008"); D.Diag(diag::warn_target_unsupported_nan2008) << CPUName; } } else if (Val == "legacy") { - if (mips::getSupportedNanEncoding(CPUName) & mips::NanLegacy) + if (mips::getIEEE754Standard(CPUName) & mips::Legacy) Features.push_back("-nan2008"); else { Features.push_back("+nan2008"); @@ -262,6 +283,28 @@ void mips::getMIPSTargetFeatures(const Driver &D, const llvm::Triple &Triple, << A->getOption().getName() << Val; } + if (Arg *A = Args.getLastArg(options::OPT_mabs_EQ)) { + StringRef Val = StringRef(A->getValue()); + if (Val == "2008") { + if (mips::getIEEE754Standard(CPUName) & mips::Std2008) { + Features.push_back("+abs2008"); + } else { + Features.push_back("-abs2008"); + D.Diag(diag::warn_target_unsupported_abs2008) << CPUName; + } + } else if (Val == "legacy") { + if (mips::getIEEE754Standard(CPUName) & mips::Legacy) { + Features.push_back("-abs2008"); + } else { + Features.push_back("+abs2008"); + D.Diag(diag::warn_target_unsupported_abslegacy) << CPUName; + } + } else { + D.Diag(diag::err_drv_unsupported_option_argument) + << A->getOption().getName() << Val; + } + } + AddTargetFeature(Args, Features, options::OPT_msingle_float, options::OPT_mdouble_float, "single-float"); AddTargetFeature(Args, Features, options::OPT_mips16, options::OPT_mno_mips16, @@ -299,32 +342,31 @@ void mips::getMIPSTargetFeatures(const Driver &D, const llvm::Triple &Triple, options::OPT_modd_spreg, "nooddspreg"); AddTargetFeature(Args, Features, options::OPT_mno_madd4, options::OPT_mmadd4, "nomadd4"); - AddTargetFeature(Args, Features, options::OPT_mlong_calls, - options::OPT_mno_long_calls, "long-calls"); - AddTargetFeature(Args, Features, options::OPT_mmt, options::OPT_mno_mt,"mt"); + AddTargetFeature(Args, Features, options::OPT_mmt, options::OPT_mno_mt, "mt"); } -mips::NanEncoding mips::getSupportedNanEncoding(StringRef &CPU) { - // Strictly speaking, mips32r2 and mips64r2 are NanLegacy-only since Nan2008 - // was first introduced in Release 3. However, other compilers have - // traditionally allowed it for Release 2 so we should do the same. - return (NanEncoding)llvm::StringSwitch<int>(CPU) - .Case("mips1", NanLegacy) - .Case("mips2", NanLegacy) - .Case("mips3", NanLegacy) - .Case("mips4", NanLegacy) - .Case("mips5", NanLegacy) - .Case("mips32", NanLegacy) - .Case("mips32r2", NanLegacy | Nan2008) - .Case("mips32r3", NanLegacy | Nan2008) - .Case("mips32r5", NanLegacy | Nan2008) - .Case("mips32r6", Nan2008) - .Case("mips64", NanLegacy) - .Case("mips64r2", NanLegacy | Nan2008) - .Case("mips64r3", NanLegacy | Nan2008) - .Case("mips64r5", NanLegacy | Nan2008) - .Case("mips64r6", Nan2008) - .Default(NanLegacy); +mips::IEEE754Standard mips::getIEEE754Standard(StringRef &CPU) { + // Strictly speaking, mips32r2 and mips64r2 do not conform to the + // IEEE754-2008 standard. Support for this standard was first introduced + // in Release 3. However, other compilers have traditionally allowed it + // for Release 2 so we should do the same. + return (IEEE754Standard)llvm::StringSwitch<int>(CPU) + .Case("mips1", Legacy) + .Case("mips2", Legacy) + .Case("mips3", Legacy) + .Case("mips4", Legacy) + .Case("mips5", Legacy) + .Case("mips32", Legacy) + .Case("mips32r2", Legacy | Std2008) + .Case("mips32r3", Legacy | Std2008) + .Case("mips32r5", Legacy | Std2008) + .Case("mips32r6", Std2008) + .Case("mips64", Legacy) + .Case("mips64r2", Legacy | Std2008) + .Case("mips64r3", Legacy | Std2008) + .Case("mips64r5", Legacy | Std2008) + .Case("mips64r6", Std2008) + .Default(Std2008); } bool mips::hasCompactBranches(StringRef &CPU) { diff --git a/lib/Driver/ToolChains/Arch/Mips.h b/lib/Driver/ToolChains/Arch/Mips.h index 0b788660948c..89eea9a1514c 100644 --- a/lib/Driver/ToolChains/Arch/Mips.h +++ b/lib/Driver/ToolChains/Arch/Mips.h @@ -24,7 +24,7 @@ namespace tools { bool isMipsArch(llvm::Triple::ArchType Arch); namespace mips { -typedef enum { NanLegacy = 1, Nan2008 = 2 } NanEncoding; +typedef enum { Legacy = 1, Std2008 = 2 } IEEE754Standard; enum class FloatABI { Invalid, @@ -32,7 +32,7 @@ enum class FloatABI { Hard, }; -NanEncoding getSupportedNanEncoding(StringRef &CPU); +IEEE754Standard getIEEE754Standard(StringRef &CPU); bool hasCompactBranches(StringRef &CPU); void getMipsCPUAndABI(const llvm::opt::ArgList &Args, const llvm::Triple &Triple, StringRef &CPUName, diff --git a/lib/Driver/ToolChains/Arch/PPC.cpp b/lib/Driver/ToolChains/Arch/PPC.cpp index 541323127f9a..7c7e1c70e550 100644 --- a/lib/Driver/ToolChains/Arch/PPC.cpp +++ b/lib/Driver/ToolChains/Arch/PPC.cpp @@ -86,6 +86,18 @@ std::string ppc::getPPCTargetCPU(const ArgList &Args) { return ""; } +const char *ppc::getPPCAsmModeForCPU(StringRef Name) { + return llvm::StringSwitch<const char *>(Name) + .Case("pwr7", "-mpower7") + .Case("power7", "-mpower7") + .Case("pwr8", "-mpower8") + .Case("power8", "-mpower8") + .Case("ppc64le", "-mpower8") + .Case("pwr9", "-mpower9") + .Case("power9", "-mpower9") + .Default("-many"); +} + void ppc::getPPCTargetFeatures(const Driver &D, const llvm::Triple &Triple, const ArgList &Args, std::vector<StringRef> &Features) { diff --git a/lib/Driver/ToolChains/Arch/PPC.h b/lib/Driver/ToolChains/Arch/PPC.h index 892eb2c34158..7d7c68101b7b 100644 --- a/lib/Driver/ToolChains/Arch/PPC.h +++ b/lib/Driver/ToolChains/Arch/PPC.h @@ -32,6 +32,7 @@ enum class FloatABI { FloatABI getPPCFloatABI(const Driver &D, const llvm::opt::ArgList &Args); std::string getPPCTargetCPU(const llvm::opt::ArgList &Args); +const char *getPPCAsmModeForCPU(StringRef Name); void getPPCTargetFeatures(const Driver &D, const llvm::Triple &Triple, const llvm::opt::ArgList &Args, diff --git a/lib/Driver/ToolChains/Arch/X86.cpp b/lib/Driver/ToolChains/Arch/X86.cpp index a85a7f1f6371..a18b2aa35b03 100644 --- a/lib/Driver/ToolChains/Arch/X86.cpp +++ b/lib/Driver/ToolChains/Arch/X86.cpp @@ -101,8 +101,6 @@ const char *x86::getX86TargetCPU(const ArgList &Args, return "i486"; case llvm::Triple::Haiku: return "i586"; - case llvm::Triple::Bitrig: - return "i686"; default: // Fallback to p4. return "pentium4"; diff --git a/lib/Driver/ToolChains/BareMetal.cpp b/lib/Driver/ToolChains/BareMetal.cpp index 28e4f5b0e583..57a668650e6b 100644 --- a/lib/Driver/ToolChains/BareMetal.cpp +++ b/lib/Driver/ToolChains/BareMetal.cpp @@ -184,10 +184,9 @@ void baremetal::Linker::ConstructJob(Compilation &C, const JobAction &JA, options::OPT_e, options::OPT_s, options::OPT_t, options::OPT_Z_Flag, options::OPT_r}); + if (TC.ShouldLinkCXXStdlib(Args)) + TC.AddCXXStdlibLibArgs(Args, CmdArgs); if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { - if (C.getDriver().CCCIsCXX()) - TC.AddCXXStdlibLibArgs(Args, CmdArgs); - CmdArgs.push_back("-lc"); CmdArgs.push_back("-lm"); diff --git a/lib/Driver/ToolChains/BareMetal.h b/lib/Driver/ToolChains/BareMetal.h index 5e9fd9bffdb9..0bed63332cad 100644 --- a/lib/Driver/ToolChains/BareMetal.h +++ b/lib/Driver/ToolChains/BareMetal.h @@ -37,7 +37,6 @@ public: bool isPIEDefault() const override { return false; } bool isPICDefaultForced() const override { return false; } bool SupportsProfiling() const override { return false; } - bool SupportsObjCGC() const override { return false; } RuntimeLibType GetDefaultRuntimeLibType() const override { return ToolChain::RLT_CompilerRT; diff --git a/lib/Driver/ToolChains/Bitrig.cpp b/lib/Driver/ToolChains/Bitrig.cpp deleted file mode 100644 index d8f541dfbaf1..000000000000 --- a/lib/Driver/ToolChains/Bitrig.cpp +++ /dev/null @@ -1,190 +0,0 @@ -//===--- Bitrig.cpp - Bitrig 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 "Bitrig.h" -#include "CommonArgs.h" -#include "clang/Driver/Compilation.h" -#include "clang/Driver/Options.h" -#include "llvm/Option/ArgList.h" - -using namespace clang::driver; -using namespace clang::driver::toolchains; -using namespace clang::driver::tools; -using namespace clang; -using namespace llvm::opt; - -void bitrig::Assembler::ConstructJob(Compilation &C, const JobAction &JA, - const InputInfo &Output, - const InputInfoList &Inputs, - const ArgList &Args, - const char *LinkingOutput) const { - claimNoWarnArgs(Args); - ArgStringList CmdArgs; - - 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)); -} - -void bitrig::Linker::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; - - if (!Args.hasArg(options::OPT_nostdlib, options::OPT_shared)) { - CmdArgs.push_back("-e"); - CmdArgs.push_back("__start"); - } - - if (Args.hasArg(options::OPT_static)) { - CmdArgs.push_back("-Bstatic"); - } else { - if (Args.hasArg(options::OPT_rdynamic)) - CmdArgs.push_back("-export-dynamic"); - CmdArgs.push_back("--eh-frame-hdr"); - CmdArgs.push_back("-Bdynamic"); - if (Args.hasArg(options::OPT_shared)) { - CmdArgs.push_back("-shared"); - } else { - CmdArgs.push_back("-dynamic-linker"); - CmdArgs.push_back("/usr/libexec/ld.so"); - } - } - - if (Output.isFilename()) { - CmdArgs.push_back("-o"); - CmdArgs.push_back(Output.getFilename()); - } else { - assert(Output.isNothing() && "Invalid output."); - } - - if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) { - if (!Args.hasArg(options::OPT_shared)) { - if (Args.hasArg(options::OPT_pg)) - CmdArgs.push_back( - Args.MakeArgString(getToolChain().GetFilePath("gcrt0.o"))); - else - CmdArgs.push_back( - Args.MakeArgString(getToolChain().GetFilePath("crt0.o"))); - CmdArgs.push_back( - Args.MakeArgString(getToolChain().GetFilePath("crtbegin.o"))); - } else { - CmdArgs.push_back( - Args.MakeArgString(getToolChain().GetFilePath("crtbeginS.o"))); - } - } - - Args.AddAllArgs(CmdArgs, - {options::OPT_L, options::OPT_T_Group, options::OPT_e}); - - AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA); - - if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { - if (D.CCCIsCXX()) { - getToolChain().AddCXXStdlibLibArgs(Args, CmdArgs); - if (Args.hasArg(options::OPT_pg)) - CmdArgs.push_back("-lm_p"); - else - CmdArgs.push_back("-lm"); - } - - if (Args.hasArg(options::OPT_pthread)) { - if (!Args.hasArg(options::OPT_shared) && Args.hasArg(options::OPT_pg)) - CmdArgs.push_back("-lpthread_p"); - else - CmdArgs.push_back("-lpthread"); - } - - if (!Args.hasArg(options::OPT_shared)) { - if (Args.hasArg(options::OPT_pg)) - CmdArgs.push_back("-lc_p"); - else - CmdArgs.push_back("-lc"); - } - - StringRef MyArch; - switch (getToolChain().getArch()) { - case llvm::Triple::arm: - MyArch = "arm"; - break; - case llvm::Triple::x86: - MyArch = "i386"; - break; - case llvm::Triple::x86_64: - MyArch = "amd64"; - break; - default: - llvm_unreachable("Unsupported architecture"); - } - CmdArgs.push_back(Args.MakeArgString("-lclang_rt." + MyArch)); - } - - if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) { - if (!Args.hasArg(options::OPT_shared)) - CmdArgs.push_back( - Args.MakeArgString(getToolChain().GetFilePath("crtend.o"))); - else - CmdArgs.push_back( - Args.MakeArgString(getToolChain().GetFilePath("crtendS.o"))); - } - - const char *Exec = Args.MakeArgString(getToolChain().GetLinkerPath()); - C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); -} - -/// Bitrig - Bitrig tool chain which can call as(1) and ld(1) directly. - -Bitrig::Bitrig(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) - : Generic_ELF(D, Triple, Args) { - getFilePaths().push_back(getDriver().Dir + "/../lib"); - getFilePaths().push_back("/usr/lib"); -} - -Tool *Bitrig::buildAssembler() const { - return new tools::bitrig::Assembler(*this); -} - -Tool *Bitrig::buildLinker() const { return new tools::bitrig::Linker(*this); } - -ToolChain::CXXStdlibType Bitrig::GetDefaultCXXStdlibType() const { - return ToolChain::CST_Libcxx; -} - -void Bitrig::addLibStdCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args) const { - std::string Triple = getTriple().str(); - if (StringRef(Triple).startswith("amd64")) - Triple = "x86_64" + Triple.substr(5); - addLibStdCXXIncludePaths(getDriver().SysRoot, "/usr/include/c++/stdc++", - Triple, "", "", "", DriverArgs, CC1Args); -} - -void Bitrig::AddCXXStdlibLibArgs(const ArgList &Args, - ArgStringList &CmdArgs) const { - switch (GetCXXStdlibType(Args)) { - case ToolChain::CST_Libcxx: - CmdArgs.push_back("-lc++"); - CmdArgs.push_back("-lc++abi"); - CmdArgs.push_back("-lpthread"); - break; - case ToolChain::CST_Libstdcxx: - CmdArgs.push_back("-lstdc++"); - break; - } -} diff --git a/lib/Driver/ToolChains/Bitrig.h b/lib/Driver/ToolChains/Bitrig.h deleted file mode 100644 index 6edb2e8c7e8c..000000000000 --- a/lib/Driver/ToolChains/Bitrig.h +++ /dev/null @@ -1,79 +0,0 @@ -//===--- Bitrig.h - Bitrig ToolChain Implementations ------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_BITRIG_H -#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_BITRIG_H - -#include "Gnu.h" -#include "clang/Driver/Driver.h" -#include "clang/Driver/ToolChain.h" - -namespace clang { -namespace driver { -namespace tools { -/// bitrig -- Directly call GNU Binutils assembler and linker -namespace bitrig { -class LLVM_LIBRARY_VISIBILITY Assembler : public GnuTool { -public: - Assembler(const ToolChain &TC) - : GnuTool("bitrig::Assembler", "assembler", TC) {} - - bool hasIntegratedCPP() const override { return false; } - - void ConstructJob(Compilation &C, const JobAction &JA, - const InputInfo &Output, const InputInfoList &Inputs, - const llvm::opt::ArgList &TCArgs, - const char *LinkingOutput) const override; -}; - -class LLVM_LIBRARY_VISIBILITY Linker : public GnuTool { -public: - Linker(const ToolChain &TC) : GnuTool("bitrig::Linker", "linker", TC) {} - - bool hasIntegratedCPP() const override { return false; } - bool isLinkJob() const override { return true; } - - void ConstructJob(Compilation &C, const JobAction &JA, - const InputInfo &Output, const InputInfoList &Inputs, - const llvm::opt::ArgList &TCArgs, - const char *LinkingOutput) const override; -}; -} // end namespace bitrig -} // end namespace tools - -namespace toolchains { - -class LLVM_LIBRARY_VISIBILITY Bitrig : public Generic_ELF { -public: - Bitrig(const Driver &D, const llvm::Triple &Triple, - const llvm::opt::ArgList &Args); - - bool IsMathErrnoDefault() const override { return false; } - bool IsObjCNonFragileABIDefault() const override { return true; } - - CXXStdlibType GetDefaultCXXStdlibType() const override; - void addLibStdCxxIncludePaths( - const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args) const override; - void AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args, - llvm::opt::ArgStringList &CmdArgs) const override; - unsigned GetDefaultStackProtectorLevel(bool KernelOrKext) const override { - return 1; - } - -protected: - Tool *buildAssembler() const override; - Tool *buildLinker() const override; -}; - -} // end namespace toolchains -} // end namespace driver -} // end namespace clang - -#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_BITRIG_H diff --git a/lib/Driver/ToolChains/Clang.cpp b/lib/Driver/ToolChains/Clang.cpp index 497f0b493261..0a89ff96d3c8 100644 --- a/lib/Driver/ToolChains/Clang.cpp +++ b/lib/Driver/ToolChains/Clang.cpp @@ -15,6 +15,7 @@ #include "Arch/Sparc.h" #include "Arch/SystemZ.h" #include "Arch/X86.h" +#include "AMDGPU.h" #include "CommonArgs.h" #include "Hexagon.h" #include "InputInfo.h" @@ -273,19 +274,25 @@ static void ParseMRecip(const Driver &D, const ArgList &Args, OutStrings.push_back(Args.MakeArgString(Out)); } -static void getHexagonTargetFeatures(const ArgList &Args, - std::vector<StringRef> &Features) { - handleTargetFeaturesGroup(Args, Features, - options::OPT_m_hexagon_Features_Group); +/// The -mprefer-vector-width option accepts either a positive integer +/// or the string "none". +static void ParseMPreferVectorWidth(const Driver &D, const ArgList &Args, + ArgStringList &CmdArgs) { + Arg *A = Args.getLastArg(options::OPT_mprefer_vector_width_EQ); + if (!A) + return; - bool UseLongCalls = false; - if (Arg *A = Args.getLastArg(options::OPT_mlong_calls, - options::OPT_mno_long_calls)) { - if (A->getOption().matches(options::OPT_mlong_calls)) - UseLongCalls = true; + StringRef Value = A->getValue(); + if (Value == "none") { + CmdArgs.push_back("-mprefer-vector-width=none"); + } else { + unsigned Width; + if (Value.getAsInteger(10, Width)) { + D.Diag(diag::err_drv_invalid_value) << A->getOption().getName() << Value; + return; + } + CmdArgs.push_back(Args.MakeArgString("-mprefer-vector-width=" + Value)); } - - Features.push_back(UseLongCalls ? "+long-calls" : "-long-calls"); } static void getWebAssemblyTargetFeatures(const ArgList &Args, @@ -293,23 +300,6 @@ static void getWebAssemblyTargetFeatures(const ArgList &Args, handleTargetFeaturesGroup(Args, Features, options::OPT_m_wasm_Features_Group); } -static void getAMDGPUTargetFeatures(const Driver &D, const ArgList &Args, - std::vector<StringRef> &Features) { - if (const Arg *dAbi = Args.getLastArg(options::OPT_mamdgpu_debugger_abi)) { - StringRef value = dAbi->getValue(); - if (value == "1.0") { - Features.push_back("+amdgpu-debugger-insert-nops"); - Features.push_back("+amdgpu-debugger-reserve-regs"); - Features.push_back("+amdgpu-debugger-emit-prologue"); - } else { - D.Diag(diag::err_drv_clang_unsupported) << dAbi->getAsString(Args); - } - } - - handleTargetFeaturesGroup( - Args, Features, options::OPT_m_amdgpu_Features_Group); -} - static void getTargetFeatures(const ToolChain &TC, const llvm::Triple &Triple, const ArgList &Args, ArgStringList &CmdArgs, bool ForAS) { @@ -349,7 +339,7 @@ static void getTargetFeatures(const ToolChain &TC, const llvm::Triple &Triple, x86::getX86TargetFeatures(D, Triple, Args, Features); break; case llvm::Triple::hexagon: - getHexagonTargetFeatures(Args, Features); + hexagon::getHexagonTargetFeatures(D, Args, Features); break; case llvm::Triple::wasm32: case llvm::Triple::wasm64: @@ -362,7 +352,7 @@ static void getTargetFeatures(const ToolChain &TC, const llvm::Triple &Triple, break; case llvm::Triple::r600: case llvm::Triple::amdgcn: - getAMDGPUTargetFeatures(D, Args, Features); + amdgpu::getAMDGPUTargetFeatures(D, Args, Features); break; } @@ -1360,6 +1350,77 @@ void Clang::AddARMTargetArgs(const llvm::Triple &Triple, const ArgList &Args, CmdArgs.push_back("-no-implicit-float"); } +void Clang::RenderTargetOptions(const llvm::Triple &EffectiveTriple, + const ArgList &Args, bool KernelOrKext, + ArgStringList &CmdArgs) const { + const ToolChain &TC = getToolChain(); + + // Add the target features + getTargetFeatures(TC, EffectiveTriple, Args, CmdArgs, false); + + // Add target specific flags. + switch (TC.getArch()) { + default: + break; + + case llvm::Triple::arm: + case llvm::Triple::armeb: + case llvm::Triple::thumb: + case llvm::Triple::thumbeb: + // Use the effective triple, which takes into account the deployment target. + AddARMTargetArgs(EffectiveTriple, Args, CmdArgs, KernelOrKext); + CmdArgs.push_back("-fallow-half-arguments-and-returns"); + break; + + case llvm::Triple::aarch64: + case llvm::Triple::aarch64_be: + AddAArch64TargetArgs(Args, CmdArgs); + CmdArgs.push_back("-fallow-half-arguments-and-returns"); + break; + + case llvm::Triple::mips: + case llvm::Triple::mipsel: + case llvm::Triple::mips64: + case llvm::Triple::mips64el: + AddMIPSTargetArgs(Args, CmdArgs); + break; + + case llvm::Triple::ppc: + case llvm::Triple::ppc64: + case llvm::Triple::ppc64le: + AddPPCTargetArgs(Args, CmdArgs); + break; + + case llvm::Triple::sparc: + case llvm::Triple::sparcel: + case llvm::Triple::sparcv9: + AddSparcTargetArgs(Args, CmdArgs); + break; + + case llvm::Triple::systemz: + AddSystemZTargetArgs(Args, CmdArgs); + break; + + case llvm::Triple::x86: + case llvm::Triple::x86_64: + AddX86TargetArgs(Args, CmdArgs); + break; + + case llvm::Triple::lanai: + AddLanaiTargetArgs(Args, CmdArgs); + break; + + case llvm::Triple::hexagon: + AddHexagonTargetArgs(Args, CmdArgs); + break; + + case llvm::Triple::wasm32: + case llvm::Triple::wasm64: + AddWebAssemblyTargetArgs(Args, CmdArgs); + break; + } +} + void Clang::AddAArch64TargetArgs(const ArgList &Args, ArgStringList &CmdArgs) const { const llvm::Triple &Triple = getToolChain().getEffectiveTriple(); @@ -1462,6 +1523,80 @@ void Clang::AddMIPSTargetArgs(const ArgList &Args, A->claim(); } + Arg *GPOpt = Args.getLastArg(options::OPT_mgpopt, options::OPT_mno_gpopt); + Arg *ABICalls = + Args.getLastArg(options::OPT_mabicalls, options::OPT_mno_abicalls); + + // -mabicalls is the default for many MIPS environments, even with -fno-pic. + // -mgpopt is the default for static, -fno-pic environments but these two + // options conflict. We want to be certain that -mno-abicalls -mgpopt is + // the only case where -mllvm -mgpopt is passed. + // NOTE: We need a warning here or in the backend to warn when -mgpopt is + // passed explicitly when compiling something with -mabicalls + // (implictly) in affect. Currently the warning is in the backend. + // + // When the ABI in use is N64, we also need to determine the PIC mode that + // is in use, as -fno-pic for N64 implies -mno-abicalls. + bool NoABICalls = + ABICalls && ABICalls->getOption().matches(options::OPT_mno_abicalls); + + llvm::Reloc::Model RelocationModel; + unsigned PICLevel; + bool IsPIE; + std::tie(RelocationModel, PICLevel, IsPIE) = + ParsePICArgs(getToolChain(), Args); + + NoABICalls = NoABICalls || + (RelocationModel == llvm::Reloc::Static && ABIName == "n64"); + + bool WantGPOpt = GPOpt && GPOpt->getOption().matches(options::OPT_mgpopt); + // We quietly ignore -mno-gpopt as the backend defaults to -mno-gpopt. + if (NoABICalls && (!GPOpt || WantGPOpt)) { + CmdArgs.push_back("-mllvm"); + CmdArgs.push_back("-mgpopt"); + + Arg *LocalSData = Args.getLastArg(options::OPT_mlocal_sdata, + options::OPT_mno_local_sdata); + Arg *ExternSData = Args.getLastArg(options::OPT_mextern_sdata, + options::OPT_mno_extern_sdata); + Arg *EmbeddedData = Args.getLastArg(options::OPT_membedded_data, + options::OPT_mno_embedded_data); + if (LocalSData) { + CmdArgs.push_back("-mllvm"); + if (LocalSData->getOption().matches(options::OPT_mlocal_sdata)) { + CmdArgs.push_back("-mlocal-sdata=1"); + } else { + CmdArgs.push_back("-mlocal-sdata=0"); + } + LocalSData->claim(); + } + + if (ExternSData) { + CmdArgs.push_back("-mllvm"); + if (ExternSData->getOption().matches(options::OPT_mextern_sdata)) { + CmdArgs.push_back("-mextern-sdata=1"); + } else { + CmdArgs.push_back("-mextern-sdata=0"); + } + ExternSData->claim(); + } + + if (EmbeddedData) { + CmdArgs.push_back("-mllvm"); + if (EmbeddedData->getOption().matches(options::OPT_membedded_data)) { + CmdArgs.push_back("-membedded-data=1"); + } else { + CmdArgs.push_back("-membedded-data=0"); + } + EmbeddedData->claim(); + } + + } else if ((!ABICalls || (!NoABICalls && ABICalls)) && WantGPOpt) + D.Diag(diag::warn_drv_unsupported_gpopt) << (ABICalls ? 0 : 1); + + if (GPOpt) + GPOpt->claim(); + if (Arg *A = Args.getLastArg(options::OPT_mcompact_branches_EQ)) { StringRef Val = StringRef(A->getValue()); if (mips::hasCompactBranches(CPUName)) { @@ -1755,7 +1890,7 @@ static void CollectArgsForIntegratedAssembler(Compilation &C, // arg after parsing the '-I' arg. bool TakeNextArg = false; - bool UseRelaxRelocations = ENABLE_X86_RELAX_RELOCATIONS; + bool UseRelaxRelocations = C.getDefaultToolChain().useRelaxRelocations(); const char *MipsTargetFeature = nullptr; for (const Arg *A : Args.filtered(options::OPT_Wa_COMMA, options::OPT_Xassembler)) { @@ -1775,6 +1910,15 @@ static void CollectArgsForIntegratedAssembler(Compilation &C, switch (C.getDefaultToolChain().getArch()) { default: break; + case llvm::Triple::thumb: + case llvm::Triple::thumbeb: + case llvm::Triple::arm: + case llvm::Triple::armeb: + if (Value == "-mthumb") + // -mthumb has already been processed in ComputeLLVMTriple() + // recognize but skip over here. + continue; + break; case llvm::Triple::mips: case llvm::Triple::mipsel: case llvm::Triple::mips64: @@ -1894,9 +2038,987 @@ static void CollectArgsForIntegratedAssembler(Compilation &C, } } +static void RenderFloatingPointOptions(const ToolChain &TC, const Driver &D, + bool OFastEnabled, const ArgList &Args, + ArgStringList &CmdArgs) { + // Handle various floating point optimization flags, mapping them to the + // appropriate LLVM code generation flags. This is complicated by several + // "umbrella" flags, so we do this by stepping through the flags incrementally + // adjusting what we think is enabled/disabled, then at the end settting the + // LLVM flags based on the final state. + bool HonorINFs = true; + bool HonorNaNs = true; + // -fmath-errno is the default on some platforms, e.g. BSD-derived OSes. + bool MathErrno = TC.IsMathErrnoDefault(); + bool AssociativeMath = false; + bool ReciprocalMath = false; + bool SignedZeros = true; + bool TrappingMath = true; + StringRef DenormalFPMath = ""; + StringRef FPContract = ""; + + for (const Arg *A : Args) { + switch (A->getOption().getID()) { + // If this isn't an FP option skip the claim below + default: continue; + + // Options controlling individual features + case options::OPT_fhonor_infinities: HonorINFs = true; break; + case options::OPT_fno_honor_infinities: HonorINFs = false; break; + case options::OPT_fhonor_nans: HonorNaNs = true; break; + case options::OPT_fno_honor_nans: HonorNaNs = false; break; + case options::OPT_fmath_errno: MathErrno = true; break; + case options::OPT_fno_math_errno: MathErrno = false; break; + case options::OPT_fassociative_math: AssociativeMath = true; break; + case options::OPT_fno_associative_math: AssociativeMath = false; break; + case options::OPT_freciprocal_math: ReciprocalMath = true; break; + case options::OPT_fno_reciprocal_math: ReciprocalMath = false; break; + case options::OPT_fsigned_zeros: SignedZeros = true; break; + case options::OPT_fno_signed_zeros: SignedZeros = false; break; + case options::OPT_ftrapping_math: TrappingMath = true; break; + case options::OPT_fno_trapping_math: TrappingMath = false; break; + + case options::OPT_fdenormal_fp_math_EQ: + DenormalFPMath = A->getValue(); + break; + + // Validate and pass through -fp-contract option. + case options::OPT_ffp_contract: { + StringRef Val = A->getValue(); + if (Val == "fast" || Val == "on" || Val == "off") + FPContract = Val; + else + D.Diag(diag::err_drv_unsupported_option_argument) + << A->getOption().getName() << Val; + break; + } + + case options::OPT_ffinite_math_only: + HonorINFs = false; + HonorNaNs = false; + break; + case options::OPT_fno_finite_math_only: + HonorINFs = true; + HonorNaNs = true; + break; + + case options::OPT_funsafe_math_optimizations: + AssociativeMath = true; + ReciprocalMath = true; + SignedZeros = false; + TrappingMath = false; + break; + case options::OPT_fno_unsafe_math_optimizations: + AssociativeMath = false; + ReciprocalMath = false; + SignedZeros = true; + TrappingMath = true; + // -fno_unsafe_math_optimizations restores default denormal handling + DenormalFPMath = ""; + break; + + case options::OPT_Ofast: + // If -Ofast is the optimization level, then -ffast-math should be enabled + if (!OFastEnabled) + continue; + LLVM_FALLTHROUGH; + case options::OPT_ffast_math: + HonorINFs = false; + HonorNaNs = false; + MathErrno = false; + AssociativeMath = true; + ReciprocalMath = true; + SignedZeros = false; + TrappingMath = false; + // If fast-math is set then set the fp-contract mode to fast. + FPContract = "fast"; + break; + case options::OPT_fno_fast_math: + HonorINFs = true; + HonorNaNs = true; + // Turning on -ffast-math (with either flag) removes the need for + // MathErrno. However, turning *off* -ffast-math merely restores the + // toolchain default (which may be false). + MathErrno = TC.IsMathErrnoDefault(); + AssociativeMath = false; + ReciprocalMath = false; + SignedZeros = true; + TrappingMath = true; + // -fno_fast_math restores default denormal and fpcontract handling + DenormalFPMath = ""; + FPContract = ""; + break; + } + + // If we handled this option claim it + A->claim(); + } + + if (!HonorINFs) + CmdArgs.push_back("-menable-no-infs"); + + if (!HonorNaNs) + CmdArgs.push_back("-menable-no-nans"); + + if (MathErrno) + CmdArgs.push_back("-fmath-errno"); + + if (!MathErrno && AssociativeMath && ReciprocalMath && !SignedZeros && + !TrappingMath) + CmdArgs.push_back("-menable-unsafe-fp-math"); + + if (!SignedZeros) + CmdArgs.push_back("-fno-signed-zeros"); + + if (AssociativeMath && !SignedZeros && !TrappingMath) + CmdArgs.push_back("-mreassociate"); + + if (ReciprocalMath) + CmdArgs.push_back("-freciprocal-math"); + + if (!TrappingMath) + CmdArgs.push_back("-fno-trapping-math"); + + if (!DenormalFPMath.empty()) + CmdArgs.push_back( + Args.MakeArgString("-fdenormal-fp-math=" + DenormalFPMath)); + + if (!FPContract.empty()) + CmdArgs.push_back(Args.MakeArgString("-ffp-contract=" + FPContract)); + + ParseMRecip(D, Args, CmdArgs); + + // -ffast-math enables the __FAST_MATH__ preprocessor macro, but check for the + // individual features enabled by -ffast-math instead of the option itself as + // that's consistent with gcc's behaviour. + if (!HonorINFs && !HonorNaNs && !MathErrno && AssociativeMath && + ReciprocalMath && !SignedZeros && !TrappingMath) + CmdArgs.push_back("-ffast-math"); + + // Handle __FINITE_MATH_ONLY__ similarly. + if (!HonorINFs && !HonorNaNs) + CmdArgs.push_back("-ffinite-math-only"); + + if (const Arg *A = Args.getLastArg(options::OPT_mfpmath_EQ)) { + CmdArgs.push_back("-mfpmath"); + CmdArgs.push_back(A->getValue()); + } +} + +static void RenderAnalyzerOptions(const ArgList &Args, ArgStringList &CmdArgs, + const llvm::Triple &Triple, + const InputInfo &Input) { + // Enable region store model by default. + CmdArgs.push_back("-analyzer-store=region"); + + // Treat blocks as analysis entry points. + CmdArgs.push_back("-analyzer-opt-analyze-nested-blocks"); + + CmdArgs.push_back("-analyzer-eagerly-assume"); + + // Add default argument set. + if (!Args.hasArg(options::OPT__analyzer_no_default_checks)) { + CmdArgs.push_back("-analyzer-checker=core"); + CmdArgs.push_back("-analyzer-checker=apiModeling"); + + if (!Triple.isWindowsMSVCEnvironment()) { + CmdArgs.push_back("-analyzer-checker=unix"); + } else { + // Enable "unix" checkers that also work on Windows. + CmdArgs.push_back("-analyzer-checker=unix.API"); + CmdArgs.push_back("-analyzer-checker=unix.Malloc"); + CmdArgs.push_back("-analyzer-checker=unix.MallocSizeof"); + CmdArgs.push_back("-analyzer-checker=unix.MismatchedDeallocator"); + CmdArgs.push_back("-analyzer-checker=unix.cstring.BadSizeArg"); + CmdArgs.push_back("-analyzer-checker=unix.cstring.NullArg"); + } + + // Disable some unix checkers for PS4. + if (Triple.isPS4CPU()) { + CmdArgs.push_back("-analyzer-disable-checker=unix.API"); + CmdArgs.push_back("-analyzer-disable-checker=unix.Vfork"); + } + + if (Triple.isOSDarwin()) + CmdArgs.push_back("-analyzer-checker=osx"); + + CmdArgs.push_back("-analyzer-checker=deadcode"); + + if (types::isCXX(Input.getType())) + CmdArgs.push_back("-analyzer-checker=cplusplus"); + + if (!Triple.isPS4CPU()) { + CmdArgs.push_back("-analyzer-checker=security.insecureAPI.UncheckedReturn"); + CmdArgs.push_back("-analyzer-checker=security.insecureAPI.getpw"); + CmdArgs.push_back("-analyzer-checker=security.insecureAPI.gets"); + CmdArgs.push_back("-analyzer-checker=security.insecureAPI.mktemp"); + CmdArgs.push_back("-analyzer-checker=security.insecureAPI.mkstemp"); + CmdArgs.push_back("-analyzer-checker=security.insecureAPI.vfork"); + } + + // Default nullability checks. + CmdArgs.push_back("-analyzer-checker=nullability.NullPassedToNonnull"); + CmdArgs.push_back("-analyzer-checker=nullability.NullReturnedFromNonnull"); + } + + // Set the output format. The default is plist, for (lame) historical reasons. + CmdArgs.push_back("-analyzer-output"); + if (Arg *A = Args.getLastArg(options::OPT__analyzer_output)) + CmdArgs.push_back(A->getValue()); + else + CmdArgs.push_back("plist"); + + // Disable the presentation of standard compiler warnings when using + // --analyze. We only want to show static analyzer diagnostics or frontend + // errors. + CmdArgs.push_back("-w"); + + // Add -Xanalyzer arguments when running as analyzer. + Args.AddAllArgValues(CmdArgs, options::OPT_Xanalyzer); +} + +static void RenderSSPOptions(const ToolChain &TC, const ArgList &Args, + ArgStringList &CmdArgs, bool KernelOrKext) { + const llvm::Triple &EffectiveTriple = TC.getEffectiveTriple(); + + // NVPTX doesn't support stack protectors; from the compiler's perspective, it + // doesn't even have a stack! + if (EffectiveTriple.isNVPTX()) + return; + + // -stack-protector=0 is default. + unsigned StackProtectorLevel = 0; + unsigned DefaultStackProtectorLevel = + TC.GetDefaultStackProtectorLevel(KernelOrKext); + + if (Arg *A = Args.getLastArg(options::OPT_fno_stack_protector, + options::OPT_fstack_protector_all, + options::OPT_fstack_protector_strong, + options::OPT_fstack_protector)) { + if (A->getOption().matches(options::OPT_fstack_protector)) + StackProtectorLevel = + std::max<unsigned>(LangOptions::SSPOn, DefaultStackProtectorLevel); + else if (A->getOption().matches(options::OPT_fstack_protector_strong)) + StackProtectorLevel = LangOptions::SSPStrong; + else if (A->getOption().matches(options::OPT_fstack_protector_all)) + StackProtectorLevel = LangOptions::SSPReq; + } else { + StackProtectorLevel = DefaultStackProtectorLevel; + } + + if (StackProtectorLevel) { + CmdArgs.push_back("-stack-protector"); + CmdArgs.push_back(Args.MakeArgString(Twine(StackProtectorLevel))); + } + + // --param ssp-buffer-size= + for (const Arg *A : Args.filtered(options::OPT__param)) { + StringRef Str(A->getValue()); + if (Str.startswith("ssp-buffer-size=")) { + if (StackProtectorLevel) { + CmdArgs.push_back("-stack-protector-buffer-size"); + // FIXME: Verify the argument is a valid integer. + CmdArgs.push_back(Args.MakeArgString(Str.drop_front(16))); + } + A->claim(); + } + } +} + +static void RenderOpenCLOptions(const ArgList &Args, ArgStringList &CmdArgs) { + const unsigned ForwardedArguments[] = { + options::OPT_cl_opt_disable, + options::OPT_cl_strict_aliasing, + options::OPT_cl_single_precision_constant, + options::OPT_cl_finite_math_only, + options::OPT_cl_kernel_arg_info, + options::OPT_cl_unsafe_math_optimizations, + options::OPT_cl_fast_relaxed_math, + options::OPT_cl_mad_enable, + options::OPT_cl_no_signed_zeros, + options::OPT_cl_denorms_are_zero, + options::OPT_cl_fp32_correctly_rounded_divide_sqrt, + }; + + if (Arg *A = Args.getLastArg(options::OPT_cl_std_EQ)) { + std::string CLStdStr = std::string("-cl-std=") + A->getValue(); + CmdArgs.push_back(Args.MakeArgString(CLStdStr)); + } + + for (const auto &Arg : ForwardedArguments) + if (const auto *A = Args.getLastArg(Arg)) + CmdArgs.push_back(Args.MakeArgString(A->getOption().getPrefixedName())); +} + +static void RenderARCMigrateToolOptions(const Driver &D, const ArgList &Args, + ArgStringList &CmdArgs) { + bool ARCMTEnabled = false; + if (!Args.hasArg(options::OPT_fno_objc_arc, options::OPT_fobjc_arc)) { + if (const Arg *A = Args.getLastArg(options::OPT_ccc_arcmt_check, + options::OPT_ccc_arcmt_modify, + options::OPT_ccc_arcmt_migrate)) { + ARCMTEnabled = true; + switch (A->getOption().getID()) { + default: llvm_unreachable("missed a case"); + case options::OPT_ccc_arcmt_check: + CmdArgs.push_back("-arcmt-check"); + break; + case options::OPT_ccc_arcmt_modify: + CmdArgs.push_back("-arcmt-modify"); + break; + case options::OPT_ccc_arcmt_migrate: + CmdArgs.push_back("-arcmt-migrate"); + CmdArgs.push_back("-mt-migrate-directory"); + CmdArgs.push_back(A->getValue()); + + Args.AddLastArg(CmdArgs, options::OPT_arcmt_migrate_report_output); + Args.AddLastArg(CmdArgs, options::OPT_arcmt_migrate_emit_arc_errors); + break; + } + } + } else { + Args.ClaimAllArgs(options::OPT_ccc_arcmt_check); + Args.ClaimAllArgs(options::OPT_ccc_arcmt_modify); + Args.ClaimAllArgs(options::OPT_ccc_arcmt_migrate); + } + + if (const Arg *A = Args.getLastArg(options::OPT_ccc_objcmt_migrate)) { + if (ARCMTEnabled) + D.Diag(diag::err_drv_argument_not_allowed_with) + << A->getAsString(Args) << "-ccc-arcmt-migrate"; + + CmdArgs.push_back("-mt-migrate-directory"); + CmdArgs.push_back(A->getValue()); + + if (!Args.hasArg(options::OPT_objcmt_migrate_literals, + options::OPT_objcmt_migrate_subscripting, + options::OPT_objcmt_migrate_property)) { + // None specified, means enable them all. + CmdArgs.push_back("-objcmt-migrate-literals"); + CmdArgs.push_back("-objcmt-migrate-subscripting"); + CmdArgs.push_back("-objcmt-migrate-property"); + } else { + Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_literals); + Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_subscripting); + Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_property); + } + } else { + Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_literals); + Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_subscripting); + Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_property); + Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_all); + Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_readonly_property); + Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_readwrite_property); + Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_property_dot_syntax); + Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_annotation); + Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_instancetype); + Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_nsmacros); + Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_protocol_conformance); + Args.AddLastArg(CmdArgs, options::OPT_objcmt_atomic_property); + Args.AddLastArg(CmdArgs, options::OPT_objcmt_returns_innerpointer_property); + Args.AddLastArg(CmdArgs, options::OPT_objcmt_ns_nonatomic_iosonly); + Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_designated_init); + Args.AddLastArg(CmdArgs, options::OPT_objcmt_whitelist_dir_path); + } +} + +static void RenderBuiltinOptions(const ToolChain &TC, const llvm::Triple &T, + const ArgList &Args, ArgStringList &CmdArgs) { + // -fbuiltin is default unless -mkernel is used. + bool UseBuiltins = + Args.hasFlag(options::OPT_fbuiltin, options::OPT_fno_builtin, + !Args.hasArg(options::OPT_mkernel)); + if (!UseBuiltins) + CmdArgs.push_back("-fno-builtin"); + + // -ffreestanding implies -fno-builtin. + if (Args.hasArg(options::OPT_ffreestanding)) + UseBuiltins = false; + + // Process the -fno-builtin-* options. + for (const auto &Arg : Args) { + const Option &O = Arg->getOption(); + if (!O.matches(options::OPT_fno_builtin_)) + continue; + + Arg->claim(); + + // If -fno-builtin is specified, then there's no need to pass the option to + // the frontend. + if (!UseBuiltins) + continue; + + StringRef FuncName = Arg->getValue(); + CmdArgs.push_back(Args.MakeArgString("-fno-builtin-" + FuncName)); + } + + // le32-specific flags: + // -fno-math-builtin: clang should not convert math builtins to intrinsics + // by default. + if (TC.getArch() == llvm::Triple::le32) + CmdArgs.push_back("-fno-math-builtin"); +} + +static void RenderModulesOptions(Compilation &C, const Driver &D, + const ArgList &Args, const InputInfo &Input, + const InputInfo &Output, + ArgStringList &CmdArgs, bool &HaveModules) { + // -fmodules enables the use of precompiled modules (off by default). + // Users can pass -fno-cxx-modules to turn off modules support for + // C++/Objective-C++ programs. + bool HaveClangModules = false; + if (Args.hasFlag(options::OPT_fmodules, options::OPT_fno_modules, false)) { + bool AllowedInCXX = Args.hasFlag(options::OPT_fcxx_modules, + options::OPT_fno_cxx_modules, true); + if (AllowedInCXX || !types::isCXX(Input.getType())) { + CmdArgs.push_back("-fmodules"); + HaveClangModules = true; + } + } + + HaveModules = HaveClangModules; + if (Args.hasArg(options::OPT_fmodules_ts)) { + CmdArgs.push_back("-fmodules-ts"); + HaveModules = true; + } + + // -fmodule-maps enables implicit reading of module map files. By default, + // this is enabled if we are using Clang's flavor of precompiled modules. + if (Args.hasFlag(options::OPT_fimplicit_module_maps, + options::OPT_fno_implicit_module_maps, HaveClangModules)) + CmdArgs.push_back("-fimplicit-module-maps"); + + // -fmodules-decluse checks that modules used are declared so (off by default) + if (Args.hasFlag(options::OPT_fmodules_decluse, + options::OPT_fno_modules_decluse, false)) + CmdArgs.push_back("-fmodules-decluse"); + + // -fmodules-strict-decluse is like -fmodule-decluse, but also checks that + // all #included headers are part of modules. + if (Args.hasFlag(options::OPT_fmodules_strict_decluse, + options::OPT_fno_modules_strict_decluse, false)) + CmdArgs.push_back("-fmodules-strict-decluse"); + + // -fno-implicit-modules turns off implicitly compiling modules on demand. + if (!Args.hasFlag(options::OPT_fimplicit_modules, + options::OPT_fno_implicit_modules, HaveClangModules)) { + if (HaveModules) + CmdArgs.push_back("-fno-implicit-modules"); + } else if (HaveModules) { + // -fmodule-cache-path specifies where our implicitly-built module files + // should be written. + SmallString<128> Path; + if (Arg *A = Args.getLastArg(options::OPT_fmodules_cache_path)) + Path = A->getValue(); + + if (C.isForDiagnostics()) { + // When generating crash reports, we want to emit the modules along with + // the reproduction sources, so we ignore any provided module path. + Path = Output.getFilename(); + llvm::sys::path::replace_extension(Path, ".cache"); + llvm::sys::path::append(Path, "modules"); + } else if (Path.empty()) { + // No module path was provided: use the default. + llvm::sys::path::system_temp_directory(/*erasedOnReboot=*/false, Path); + llvm::sys::path::append(Path, "org.llvm.clang."); + appendUserToPath(Path); + llvm::sys::path::append(Path, "ModuleCache"); + } + + const char Arg[] = "-fmodules-cache-path="; + Path.insert(Path.begin(), Arg, Arg + strlen(Arg)); + CmdArgs.push_back(Args.MakeArgString(Path)); + } + + if (HaveModules) { + // -fprebuilt-module-path specifies where to load the prebuilt module files. + for (const Arg *A : Args.filtered(options::OPT_fprebuilt_module_path)) { + CmdArgs.push_back(Args.MakeArgString( + std::string("-fprebuilt-module-path=") + A->getValue())); + A->claim(); + } + } + + // -fmodule-name specifies the module that is currently being built (or + // used for header checking by -fmodule-maps). + Args.AddLastArg(CmdArgs, options::OPT_fmodule_name_EQ); + + // -fmodule-map-file can be used to specify files containing module + // definitions. + Args.AddAllArgs(CmdArgs, options::OPT_fmodule_map_file); + + // -fbuiltin-module-map can be used to load the clang + // builtin headers modulemap file. + if (Args.hasArg(options::OPT_fbuiltin_module_map)) { + SmallString<128> BuiltinModuleMap(D.ResourceDir); + llvm::sys::path::append(BuiltinModuleMap, "include"); + llvm::sys::path::append(BuiltinModuleMap, "module.modulemap"); + if (llvm::sys::fs::exists(BuiltinModuleMap)) + CmdArgs.push_back( + Args.MakeArgString("-fmodule-map-file=" + BuiltinModuleMap)); + } + + // The -fmodule-file=<name>=<file> form specifies the mapping of module + // names to precompiled module files (the module is loaded only if used). + // The -fmodule-file=<file> form can be used to unconditionally load + // precompiled module files (whether used or not). + if (HaveModules) + Args.AddAllArgs(CmdArgs, options::OPT_fmodule_file); + else + Args.ClaimAllArgs(options::OPT_fmodule_file); + + // When building modules and generating crashdumps, we need to dump a module + // dependency VFS alongside the output. + if (HaveClangModules && C.isForDiagnostics()) { + SmallString<128> VFSDir(Output.getFilename()); + llvm::sys::path::replace_extension(VFSDir, ".cache"); + // Add the cache directory as a temp so the crash diagnostics pick it up. + C.addTempFile(Args.MakeArgString(VFSDir)); + + llvm::sys::path::append(VFSDir, "vfs"); + CmdArgs.push_back("-module-dependency-dir"); + CmdArgs.push_back(Args.MakeArgString(VFSDir)); + } + + if (HaveClangModules) + Args.AddLastArg(CmdArgs, options::OPT_fmodules_user_build_path); + + // Pass through all -fmodules-ignore-macro arguments. + Args.AddAllArgs(CmdArgs, options::OPT_fmodules_ignore_macro); + Args.AddLastArg(CmdArgs, options::OPT_fmodules_prune_interval); + Args.AddLastArg(CmdArgs, options::OPT_fmodules_prune_after); + + Args.AddLastArg(CmdArgs, options::OPT_fbuild_session_timestamp); + + if (Arg *A = Args.getLastArg(options::OPT_fbuild_session_file)) { + if (Args.hasArg(options::OPT_fbuild_session_timestamp)) + D.Diag(diag::err_drv_argument_not_allowed_with) + << A->getAsString(Args) << "-fbuild-session-timestamp"; + + llvm::sys::fs::file_status Status; + if (llvm::sys::fs::status(A->getValue(), Status)) + D.Diag(diag::err_drv_no_such_file) << A->getValue(); + CmdArgs.push_back( + Args.MakeArgString("-fbuild-session-timestamp=" + + Twine((uint64_t)Status.getLastModificationTime() + .time_since_epoch() + .count()))); + } + + if (Args.getLastArg(options::OPT_fmodules_validate_once_per_build_session)) { + if (!Args.getLastArg(options::OPT_fbuild_session_timestamp, + options::OPT_fbuild_session_file)) + D.Diag(diag::err_drv_modules_validate_once_requires_timestamp); + + Args.AddLastArg(CmdArgs, + options::OPT_fmodules_validate_once_per_build_session); + } + + Args.AddLastArg(CmdArgs, options::OPT_fmodules_validate_system_headers); + Args.AddLastArg(CmdArgs, options::OPT_fmodules_disable_diagnostic_validation); +} + +static void RenderCharacterOptions(const ArgList &Args, const llvm::Triple &T, + ArgStringList &CmdArgs) { + // -fsigned-char is default. + if (const Arg *A = Args.getLastArg(options::OPT_fsigned_char, + options::OPT_fno_signed_char, + options::OPT_funsigned_char, + options::OPT_fno_unsigned_char)) { + if (A->getOption().matches(options::OPT_funsigned_char) || + A->getOption().matches(options::OPT_fno_signed_char)) { + CmdArgs.push_back("-fno-signed-char"); + } + } else if (!isSignedCharDefault(T)) { + CmdArgs.push_back("-fno-signed-char"); + } + + if (const Arg *A = Args.getLastArg(options::OPT_fshort_wchar, + options::OPT_fno_short_wchar)) { + if (A->getOption().matches(options::OPT_fshort_wchar)) { + CmdArgs.push_back("-fwchar-type=short"); + CmdArgs.push_back("-fno-signed-wchar"); + } else { + bool IsARM = T.isARM() || T.isThumb() || T.isAArch64(); + CmdArgs.push_back("-fwchar-type=int"); + if (IsARM && !(T.isOSWindows() || T.getOS() == llvm::Triple::NetBSD || + T.getOS() == llvm::Triple::OpenBSD)) + CmdArgs.push_back("-fno-signed-wchar"); + else + CmdArgs.push_back("-fsigned-wchar"); + } + } +} + +static void RenderObjCOptions(const ToolChain &TC, const Driver &D, + const llvm::Triple &T, const ArgList &Args, + ObjCRuntime &Runtime, bool InferCovariantReturns, + const InputInfo &Input, ArgStringList &CmdArgs) { + const llvm::Triple::ArchType Arch = TC.getArch(); + + // -fobjc-dispatch-method is only relevant with the nonfragile-abi, and legacy + // is the default. Except for deployment target of 10.5, next runtime is + // always legacy dispatch and -fno-objc-legacy-dispatch gets ignored silently. + if (Runtime.isNonFragile()) { + if (!Args.hasFlag(options::OPT_fobjc_legacy_dispatch, + options::OPT_fno_objc_legacy_dispatch, + Runtime.isLegacyDispatchDefaultForArch(Arch))) { + if (TC.UseObjCMixedDispatch()) + CmdArgs.push_back("-fobjc-dispatch-method=mixed"); + else + CmdArgs.push_back("-fobjc-dispatch-method=non-legacy"); + } + } + + // When ObjectiveC legacy runtime is in effect on MacOSX, turn on the option + // to do Array/Dictionary subscripting by default. + if (Arch == llvm::Triple::x86 && T.isMacOSX() && + !T.isMacOSXVersionLT(10, 7) && + Runtime.getKind() == ObjCRuntime::FragileMacOSX && Runtime.isNeXTFamily()) + CmdArgs.push_back("-fobjc-subscripting-legacy-runtime"); + + // Allow -fno-objc-arr to trump -fobjc-arr/-fobjc-arc. + // NOTE: This logic is duplicated in ToolChains.cpp. + if (isObjCAutoRefCount(Args)) { + TC.CheckObjCARC(); + + CmdArgs.push_back("-fobjc-arc"); + + // FIXME: It seems like this entire block, and several around it should be + // wrapped in isObjC, but for now we just use it here as this is where it + // was being used previously. + if (types::isCXX(Input.getType()) && types::isObjC(Input.getType())) { + if (TC.GetCXXStdlibType(Args) == ToolChain::CST_Libcxx) + CmdArgs.push_back("-fobjc-arc-cxxlib=libc++"); + else + CmdArgs.push_back("-fobjc-arc-cxxlib=libstdc++"); + } + + // Allow the user to enable full exceptions code emission. + // We default off for Objective-C, on for Objective-C++. + if (Args.hasFlag(options::OPT_fobjc_arc_exceptions, + options::OPT_fno_objc_arc_exceptions, + /*default=*/types::isCXX(Input.getType()))) + CmdArgs.push_back("-fobjc-arc-exceptions"); + } + + // Silence warning for full exception code emission options when explicitly + // set to use no ARC. + if (Args.hasArg(options::OPT_fno_objc_arc)) { + Args.ClaimAllArgs(options::OPT_fobjc_arc_exceptions); + Args.ClaimAllArgs(options::OPT_fno_objc_arc_exceptions); + } + + // -fobjc-infer-related-result-type is the default, except in the Objective-C + // rewriter. + if (InferCovariantReturns) + CmdArgs.push_back("-fno-objc-infer-related-result-type"); + + // Pass down -fobjc-weak or -fno-objc-weak if present. + if (types::isObjC(Input.getType())) { + auto WeakArg = + Args.getLastArg(options::OPT_fobjc_weak, options::OPT_fno_objc_weak); + if (!WeakArg) { + // nothing to do + } else if (!Runtime.allowsWeak()) { + if (WeakArg->getOption().matches(options::OPT_fobjc_weak)) + D.Diag(diag::err_objc_weak_unsupported); + } else { + WeakArg->render(Args, CmdArgs); + } + } +} + +static void RenderDiagnosticsOptions(const Driver &D, const ArgList &Args, + ArgStringList &CmdArgs) { + bool CaretDefault = true; + bool ColumnDefault = true; + + if (const Arg *A = Args.getLastArg(options::OPT__SLASH_diagnostics_classic, + options::OPT__SLASH_diagnostics_column, + options::OPT__SLASH_diagnostics_caret)) { + switch (A->getOption().getID()) { + case options::OPT__SLASH_diagnostics_caret: + CaretDefault = true; + ColumnDefault = true; + break; + case options::OPT__SLASH_diagnostics_column: + CaretDefault = false; + ColumnDefault = true; + break; + case options::OPT__SLASH_diagnostics_classic: + CaretDefault = false; + ColumnDefault = false; + break; + } + } + + // -fcaret-diagnostics is default. + if (!Args.hasFlag(options::OPT_fcaret_diagnostics, + options::OPT_fno_caret_diagnostics, CaretDefault)) + CmdArgs.push_back("-fno-caret-diagnostics"); + + // -fdiagnostics-fixit-info is default, only pass non-default. + if (!Args.hasFlag(options::OPT_fdiagnostics_fixit_info, + options::OPT_fno_diagnostics_fixit_info)) + CmdArgs.push_back("-fno-diagnostics-fixit-info"); + + // Enable -fdiagnostics-show-option by default. + if (Args.hasFlag(options::OPT_fdiagnostics_show_option, + options::OPT_fno_diagnostics_show_option)) + CmdArgs.push_back("-fdiagnostics-show-option"); + + if (const Arg *A = + Args.getLastArg(options::OPT_fdiagnostics_show_category_EQ)) { + CmdArgs.push_back("-fdiagnostics-show-category"); + CmdArgs.push_back(A->getValue()); + } + + if (Args.hasFlag(options::OPT_fdiagnostics_show_hotness, + options::OPT_fno_diagnostics_show_hotness, false)) + CmdArgs.push_back("-fdiagnostics-show-hotness"); + + if (const Arg *A = + Args.getLastArg(options::OPT_fdiagnostics_hotness_threshold_EQ)) { + std::string Opt = + std::string("-fdiagnostics-hotness-threshold=") + A->getValue(); + CmdArgs.push_back(Args.MakeArgString(Opt)); + } + + if (const Arg *A = Args.getLastArg(options::OPT_fdiagnostics_format_EQ)) { + CmdArgs.push_back("-fdiagnostics-format"); + CmdArgs.push_back(A->getValue()); + } + + if (const Arg *A = Args.getLastArg( + options::OPT_fdiagnostics_show_note_include_stack, + options::OPT_fno_diagnostics_show_note_include_stack)) { + const Option &O = A->getOption(); + if (O.matches(options::OPT_fdiagnostics_show_note_include_stack)) + CmdArgs.push_back("-fdiagnostics-show-note-include-stack"); + else + CmdArgs.push_back("-fno-diagnostics-show-note-include-stack"); + } + + // Color diagnostics are parsed by the driver directly from argv and later + // re-parsed to construct this job; claim any possible color diagnostic here + // to avoid warn_drv_unused_argument and diagnose bad + // OPT_fdiagnostics_color_EQ values. + for (const Arg *A : Args) { + const Option &O = A->getOption(); + if (!O.matches(options::OPT_fcolor_diagnostics) && + !O.matches(options::OPT_fdiagnostics_color) && + !O.matches(options::OPT_fno_color_diagnostics) && + !O.matches(options::OPT_fno_diagnostics_color) && + !O.matches(options::OPT_fdiagnostics_color_EQ)) + continue; + + if (O.matches(options::OPT_fdiagnostics_color_EQ)) { + StringRef Value(A->getValue()); + if (Value != "always" && Value != "never" && Value != "auto") + D.Diag(diag::err_drv_clang_unsupported) + << ("-fdiagnostics-color=" + Value).str(); + } + A->claim(); + } + + if (D.getDiags().getDiagnosticOptions().ShowColors) + CmdArgs.push_back("-fcolor-diagnostics"); + + if (Args.hasArg(options::OPT_fansi_escape_codes)) + CmdArgs.push_back("-fansi-escape-codes"); + + if (!Args.hasFlag(options::OPT_fshow_source_location, + options::OPT_fno_show_source_location)) + CmdArgs.push_back("-fno-show-source-location"); + + if (Args.hasArg(options::OPT_fdiagnostics_absolute_paths)) + CmdArgs.push_back("-fdiagnostics-absolute-paths"); + + if (!Args.hasFlag(options::OPT_fshow_column, options::OPT_fno_show_column, + ColumnDefault)) + CmdArgs.push_back("-fno-show-column"); + + if (!Args.hasFlag(options::OPT_fspell_checking, + options::OPT_fno_spell_checking)) + CmdArgs.push_back("-fno-spell-checking"); +} + +static void RenderDebugOptions(const ToolChain &TC, const Driver &D, + const llvm::Triple &T, const ArgList &Args, + bool EmitCodeView, bool IsWindowsMSVC, + ArgStringList &CmdArgs, + codegenoptions::DebugInfoKind &DebugInfoKind, + const Arg *&SplitDWARFArg) { + if (Args.hasFlag(options::OPT_fdebug_info_for_profiling, + options::OPT_fno_debug_info_for_profiling, false)) + CmdArgs.push_back("-fdebug-info-for-profiling"); + + // The 'g' groups options involve a somewhat intricate sequence of decisions + // about what to pass from the driver to the frontend, but by the time they + // reach cc1 they've been factored into three well-defined orthogonal choices: + // * what level of debug info to generate + // * what dwarf version to write + // * what debugger tuning to use + // This avoids having to monkey around further in cc1 other than to disable + // codeview if not running in a Windows environment. Perhaps even that + // decision should be made in the driver as well though. + unsigned DWARFVersion = 0; + llvm::DebuggerKind DebuggerTuning = TC.getDefaultDebuggerTuning(); + + bool SplitDWARFInlining = + Args.hasFlag(options::OPT_fsplit_dwarf_inlining, + options::OPT_fno_split_dwarf_inlining, true); + + Args.ClaimAllArgs(options::OPT_g_Group); + + SplitDWARFArg = Args.getLastArg(options::OPT_gsplit_dwarf); + + if (const Arg *A = Args.getLastArg(options::OPT_g_Group)) { + // If the last option explicitly specified a debug-info level, use it. + if (A->getOption().matches(options::OPT_gN_Group)) { + DebugInfoKind = DebugLevelToInfoKind(*A); + // If you say "-gsplit-dwarf -gline-tables-only", -gsplit-dwarf loses. + // But -gsplit-dwarf is not a g_group option, hence we have to check the + // order explicitly. If -gsplit-dwarf wins, we fix DebugInfoKind later. + // This gets a bit more complicated if you've disabled inline info in the + // skeleton CUs (SplitDWARFInlining) - then there's value in composing + // split-dwarf and line-tables-only, so let those compose naturally in + // that case. + // And if you just turned off debug info, (-gsplit-dwarf -g0) - do that. + if (SplitDWARFArg) { + if (A->getIndex() > SplitDWARFArg->getIndex()) { + if (DebugInfoKind == codegenoptions::NoDebugInfo || + (DebugInfoKind == codegenoptions::DebugLineTablesOnly && + SplitDWARFInlining)) + SplitDWARFArg = nullptr; + } else if (SplitDWARFInlining) + DebugInfoKind = codegenoptions::NoDebugInfo; + } + } else { + // For any other 'g' option, use Limited. + DebugInfoKind = codegenoptions::LimitedDebugInfo; + } + } + + // If a debugger tuning argument appeared, remember it. + if (const Arg *A = + Args.getLastArg(options::OPT_gTune_Group, options::OPT_ggdbN_Group)) { + if (A->getOption().matches(options::OPT_glldb)) + DebuggerTuning = llvm::DebuggerKind::LLDB; + else if (A->getOption().matches(options::OPT_gsce)) + DebuggerTuning = llvm::DebuggerKind::SCE; + else + DebuggerTuning = llvm::DebuggerKind::GDB; + } + + // If a -gdwarf argument appeared, remember it. + if (const Arg *A = + Args.getLastArg(options::OPT_gdwarf_2, options::OPT_gdwarf_3, + options::OPT_gdwarf_4, options::OPT_gdwarf_5)) + DWARFVersion = DwarfVersionNum(A->getSpelling()); + + // Forward -gcodeview. EmitCodeView might have been set by CL-compatibility + // argument parsing. + if (Args.hasArg(options::OPT_gcodeview) || EmitCodeView) { + // DWARFVersion remains at 0 if no explicit choice was made. + CmdArgs.push_back("-gcodeview"); + } else if (DWARFVersion == 0 && + DebugInfoKind != codegenoptions::NoDebugInfo) { + DWARFVersion = TC.GetDefaultDwarfVersion(); + } + + // We ignore flag -gstrict-dwarf for now. + // And we handle flag -grecord-gcc-switches later with DWARFDebugFlags. + Args.ClaimAllArgs(options::OPT_g_flags_Group); + + // Column info is included by default for everything except SCE and CodeView. + // Clang doesn't track end columns, just starting columns, which, in theory, + // is fine for CodeView (and PDB). In practice, however, the Microsoft + // debuggers don't handle missing end columns well, so it's better not to + // include any column info. + if (Args.hasFlag(options::OPT_gcolumn_info, options::OPT_gno_column_info, + /*Default=*/!(IsWindowsMSVC && EmitCodeView) && + DebuggerTuning != llvm::DebuggerKind::SCE)) + CmdArgs.push_back("-dwarf-column-info"); + + // FIXME: Move backend command line options to the module. + // If -gline-tables-only is the last option it wins. + if (DebugInfoKind != codegenoptions::DebugLineTablesOnly && + Args.hasArg(options::OPT_gmodules)) { + DebugInfoKind = codegenoptions::LimitedDebugInfo; + CmdArgs.push_back("-dwarf-ext-refs"); + CmdArgs.push_back("-fmodule-format=obj"); + } + + // -gsplit-dwarf should turn on -g and enable the backend dwarf + // splitting and extraction. + // FIXME: Currently only works on Linux. + if (T.isOSLinux()) { + if (!SplitDWARFInlining) + CmdArgs.push_back("-fno-split-dwarf-inlining"); + + if (SplitDWARFArg) { + if (DebugInfoKind == codegenoptions::NoDebugInfo) + DebugInfoKind = codegenoptions::LimitedDebugInfo; + CmdArgs.push_back("-enable-split-dwarf"); + } + } + + // After we've dealt with all combinations of things that could + // make DebugInfoKind be other than None or DebugLineTablesOnly, + // figure out if we need to "upgrade" it to standalone debug info. + // We parse these two '-f' options whether or not they will be used, + // to claim them even if you wrote "-fstandalone-debug -gline-tables-only" + bool NeedFullDebug = Args.hasFlag(options::OPT_fstandalone_debug, + options::OPT_fno_standalone_debug, + TC.GetDefaultStandaloneDebug()); + if (DebugInfoKind == codegenoptions::LimitedDebugInfo && NeedFullDebug) + DebugInfoKind = codegenoptions::FullDebugInfo; + + RenderDebugEnablingArgs(Args, CmdArgs, DebugInfoKind, DWARFVersion, + DebuggerTuning); + + // -fdebug-macro turns on macro debug info generation. + if (Args.hasFlag(options::OPT_fdebug_macro, options::OPT_fno_debug_macro, + false)) + CmdArgs.push_back("-debug-info-macro"); + + // -ggnu-pubnames turns on gnu style pubnames in the backend. + if (Args.hasArg(options::OPT_ggnu_pubnames)) + CmdArgs.push_back("-ggnu-pubnames"); + + // -gdwarf-aranges turns on the emission of the aranges section in the + // backend. + // Always enabled for SCE tuning. + if (Args.hasArg(options::OPT_gdwarf_aranges) || + DebuggerTuning == llvm::DebuggerKind::SCE) { + CmdArgs.push_back("-backend-option"); + CmdArgs.push_back("-generate-arange-section"); + } + + if (Args.hasFlag(options::OPT_fdebug_types_section, + options::OPT_fno_debug_types_section, false)) { + CmdArgs.push_back("-backend-option"); + CmdArgs.push_back("-generate-type-units"); + } + + // Decide how to render forward declarations of template instantiations. + // SCE wants full descriptions, others just get them in the name. + if (DebuggerTuning == llvm::DebuggerKind::SCE) + CmdArgs.push_back("-debug-forward-template-params"); + + // Do we need to explicitly import anonymous namespaces into the parent scope? + if (DebuggerTuning == llvm::DebuggerKind::SCE) + CmdArgs.push_back("-dwarf-explicit-import"); + + RenderDebugInfoCompressionArgs(Args, CmdArgs, D); +} + void Clang::ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, const ArgList &Args, const char *LinkingOutput) const { + const llvm::Triple &RawTriple = getToolChain().getTriple(); const llvm::Triple &Triple = getToolChain().getEffectiveTriple(); const std::string &TripleStr = Triple.getTriple(); @@ -1918,18 +3040,18 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, Inputs.size() == 1) && "Unable to handle multiple inputs."); - bool IsWindowsGNU = getToolChain().getTriple().isWindowsGNUEnvironment(); - bool IsWindowsCygnus = - getToolChain().getTriple().isWindowsCygwinEnvironment(); - bool IsWindowsMSVC = getToolChain().getTriple().isWindowsMSVCEnvironment(); - bool IsPS4CPU = getToolChain().getTriple().isPS4CPU(); - bool IsIAMCU = getToolChain().getTriple().isOSIAMCU(); + const llvm::Triple *AuxTriple = + IsCuda ? getToolChain().getAuxTriple() : nullptr; + + bool IsWindowsGNU = RawTriple.isWindowsGNUEnvironment(); + bool IsWindowsCygnus = RawTriple.isWindowsCygwinEnvironment(); + bool IsWindowsMSVC = RawTriple.isWindowsMSVCEnvironment(); + bool IsIAMCU = RawTriple.isOSIAMCU(); // Adjust IsWindowsXYZ for CUDA compilations. Even when compiling in device // mode (i.e., getToolchain().getTriple() is NVPTX, not Windows), we need to // pass Windows-specific flags to cc1. if (IsCuda) { - const llvm::Triple *AuxTriple = getToolChain().getAuxTriple(); IsWindowsMSVC |= AuxTriple && AuxTriple->isWindowsMSVCEnvironment(); IsWindowsGNU |= AuxTriple && AuxTriple->isWindowsGNUEnvironment(); IsWindowsCygnus |= AuxTriple && AuxTriple->isWindowsCygwinEnvironment(); @@ -2073,8 +3195,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // The Darwin and PS4 linkers currently use the legacy LTO API, which // does not support LTO unit features (CFI, whole program vtable opt) // under ThinLTO. - if (!(getToolChain().getTriple().isOSDarwin() || - getToolChain().getTriple().isPS4()) || + if (!(RawTriple.isOSDarwin() || RawTriple.isPS4()) || D.getLTOMode() == LTOK_Full) CmdArgs.push_back("-flto-unit"); } @@ -2121,78 +3242,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, if (Args.hasArg(options::OPT_static)) CmdArgs.push_back("-static-define"); - if (isa<AnalyzeJobAction>(JA)) { - // Enable region store model by default. - CmdArgs.push_back("-analyzer-store=region"); - - // Treat blocks as analysis entry points. - CmdArgs.push_back("-analyzer-opt-analyze-nested-blocks"); - - CmdArgs.push_back("-analyzer-eagerly-assume"); - - // Add default argument set. - if (!Args.hasArg(options::OPT__analyzer_no_default_checks)) { - CmdArgs.push_back("-analyzer-checker=core"); - CmdArgs.push_back("-analyzer-checker=apiModeling"); - - if (!IsWindowsMSVC) { - CmdArgs.push_back("-analyzer-checker=unix"); - } else { - // Enable "unix" checkers that also work on Windows. - CmdArgs.push_back("-analyzer-checker=unix.API"); - CmdArgs.push_back("-analyzer-checker=unix.Malloc"); - CmdArgs.push_back("-analyzer-checker=unix.MallocSizeof"); - CmdArgs.push_back("-analyzer-checker=unix.MismatchedDeallocator"); - CmdArgs.push_back("-analyzer-checker=unix.cstring.BadSizeArg"); - CmdArgs.push_back("-analyzer-checker=unix.cstring.NullArg"); - } - - // Disable some unix checkers for PS4. - if (IsPS4CPU) { - CmdArgs.push_back("-analyzer-disable-checker=unix.API"); - CmdArgs.push_back("-analyzer-disable-checker=unix.Vfork"); - } - - if (getToolChain().getTriple().getVendor() == llvm::Triple::Apple) - CmdArgs.push_back("-analyzer-checker=osx"); - - CmdArgs.push_back("-analyzer-checker=deadcode"); - - if (types::isCXX(Input.getType())) - CmdArgs.push_back("-analyzer-checker=cplusplus"); - - if (!IsPS4CPU) { - CmdArgs.push_back( - "-analyzer-checker=security.insecureAPI.UncheckedReturn"); - CmdArgs.push_back("-analyzer-checker=security.insecureAPI.getpw"); - CmdArgs.push_back("-analyzer-checker=security.insecureAPI.gets"); - CmdArgs.push_back("-analyzer-checker=security.insecureAPI.mktemp"); - CmdArgs.push_back("-analyzer-checker=security.insecureAPI.mkstemp"); - CmdArgs.push_back("-analyzer-checker=security.insecureAPI.vfork"); - } - - // Default nullability checks. - CmdArgs.push_back("-analyzer-checker=nullability.NullPassedToNonnull"); - CmdArgs.push_back( - "-analyzer-checker=nullability.NullReturnedFromNonnull"); - } - - // Set the output format. The default is plist, for (lame) historical - // reasons. - CmdArgs.push_back("-analyzer-output"); - if (Arg *A = Args.getLastArg(options::OPT__analyzer_output)) - CmdArgs.push_back(A->getValue()); - else - CmdArgs.push_back("plist"); - - // Disable the presentation of standard compiler warnings when - // using --analyze. We only want to show static analyzer diagnostics - // or frontend errors. - CmdArgs.push_back("-w"); - - // Add -Xanalyzer arguments when running as analyzer. - Args.AddAllArgValues(CmdArgs, options::OPT_Xanalyzer); - } + if (isa<AnalyzeJobAction>(JA)) + RenderAnalyzerOptions(Args, CmdArgs, Triple, Input); CheckCodeGenerationOptions(D, Args); @@ -2270,6 +3321,10 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, true)) CmdArgs.push_back("-fno-jump-tables"); + if (Args.hasFlag(options::OPT_fprofile_sample_accurate, + options::OPT_fno_profile_sample_accurate, false)) + CmdArgs.push_back("-fprofile-sample-accurate"); + if (!Args.hasFlag(options::OPT_fpreserve_as_comments, options::OPT_fno_preserve_as_comments, true)) CmdArgs.push_back("-fno-preserve-as-comments"); @@ -2283,7 +3338,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, options::OPT_freg_struct_return)) { if (getToolChain().getArch() != llvm::Triple::x86) { D.Diag(diag::err_drv_unsupported_opt_for_target) - << A->getSpelling() << getToolChain().getTriple().str(); + << A->getSpelling() << RawTriple.str(); } else if (A->getOption().matches(options::OPT_fpcc_struct_return)) { CmdArgs.push_back("-fpcc-struct-return"); } else { @@ -2295,7 +3350,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, if (Args.hasFlag(options::OPT_mrtd, options::OPT_mno_rtd, false)) CmdArgs.push_back("-fdefault-calling-conv=stdcall"); - if (shouldUseFramePointer(Args, getToolChain().getTriple())) + if (shouldUseFramePointer(Args, RawTriple)) CmdArgs.push_back("-mdisable-fp-elim"); if (!Args.hasFlag(options::OPT_fzero_initialized_in_bss, options::OPT_fno_zero_initialized_in_bss)) @@ -2308,7 +3363,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, OFastEnabled ? options::OPT_Ofast : options::OPT_fstrict_aliasing; // We turn strict aliasing off by default if we're in CL mode, since MSVC // doesn't do any TBAA. - bool TBAAOnByDefault = !getToolChain().getDriver().IsCLMode(); + bool TBAAOnByDefault = !D.IsCLMode(); if (!Args.hasFlag(options::OPT_fstrict_aliasing, StrictAliasingAliasOption, options::OPT_fno_strict_aliasing, TBAAOnByDefault)) CmdArgs.push_back("-relaxed-aliasing"); @@ -2332,164 +3387,14 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, options::OPT_fno_optimize_sibling_calls)) CmdArgs.push_back("-mdisable-tail-calls"); + Args.AddLastArg(CmdArgs, options::OPT_ffine_grained_bitfield_accesses, + options::OPT_fno_fine_grained_bitfield_accesses); + // Handle segmented stacks. if (Args.hasArg(options::OPT_fsplit_stack)) CmdArgs.push_back("-split-stacks"); - // Handle various floating point optimization flags, mapping them to the - // appropriate LLVM code generation flags. This is complicated by several - // "umbrella" flags, so we do this by stepping through the flags incrementally - // adjusting what we think is enabled/disabled, then at the end settting the - // LLVM flags based on the final state. - bool HonorInfs = true; - bool HonorNans = true; - // -fmath-errno is the default on some platforms, e.g. BSD-derived OSes. - bool MathErrno = getToolChain().IsMathErrnoDefault(); - bool AssociativeMath = false; - bool ReciprocalMath = false; - bool SignedZeros = true; - bool TrappingMath = true; - StringRef DenormalFpMath = ""; - StringRef FpContract = ""; - - for (Arg *A : Args) { - switch (A->getOption().getID()) { - // If this isn't an FP option skip the claim below - default: - continue; - - // Options controlling individual features - case options::OPT_fhonor_infinities: HonorInfs = true; break; - case options::OPT_fno_honor_infinities: HonorInfs = false; break; - case options::OPT_fhonor_nans: HonorNans = true; break; - case options::OPT_fno_honor_nans: HonorNans = false; break; - case options::OPT_fmath_errno: MathErrno = true; break; - case options::OPT_fno_math_errno: MathErrno = false; break; - case options::OPT_fassociative_math: AssociativeMath = true; break; - case options::OPT_fno_associative_math: AssociativeMath = false; break; - case options::OPT_freciprocal_math: ReciprocalMath = true; break; - case options::OPT_fno_reciprocal_math: ReciprocalMath = false; break; - case options::OPT_fsigned_zeros: SignedZeros = true; break; - case options::OPT_fno_signed_zeros: SignedZeros = false; break; - case options::OPT_ftrapping_math: TrappingMath = true; break; - case options::OPT_fno_trapping_math: TrappingMath = false; break; - - case options::OPT_fdenormal_fp_math_EQ: - DenormalFpMath = A->getValue(); - break; - - // Validate and pass through -fp-contract option. - case options::OPT_ffp_contract: { - StringRef Val = A->getValue(); - if (Val == "fast" || Val == "on" || Val == "off") { - FpContract = Val; - } else { - D.Diag(diag::err_drv_unsupported_option_argument) - << A->getOption().getName() << Val; - } - break; - } - - case options::OPT_ffinite_math_only: - HonorInfs = false; - HonorNans = false; - break; - case options::OPT_fno_finite_math_only: - HonorInfs = true; - HonorNans = true; - break; - - case options::OPT_funsafe_math_optimizations: - AssociativeMath = true; - ReciprocalMath = true; - SignedZeros = false; - TrappingMath = false; - break; - case options::OPT_fno_unsafe_math_optimizations: - AssociativeMath = false; - ReciprocalMath = false; - SignedZeros = true; - TrappingMath = true; - // -fno_unsafe_math_optimizations restores default denormal handling - DenormalFpMath = ""; - break; - - case options::OPT_Ofast: - // If -Ofast is the optimization level, then -ffast-math should be enabled - if (!OFastEnabled) - continue; - LLVM_FALLTHROUGH; - case options::OPT_ffast_math: - HonorInfs = false; - HonorNans = false; - MathErrno = false; - AssociativeMath = true; - ReciprocalMath = true; - SignedZeros = false; - TrappingMath = false; - // If fast-math is set then set the fp-contract mode to fast. - FpContract = "fast"; - break; - case options::OPT_fno_fast_math: - HonorInfs = true; - HonorNans = true; - // Turning on -ffast-math (with either flag) removes the need for - // MathErrno. However, turning *off* -ffast-math merely restores the - // toolchain default (which may be false). - MathErrno = getToolChain().IsMathErrnoDefault(); - AssociativeMath = false; - ReciprocalMath = false; - SignedZeros = true; - TrappingMath = true; - // -fno_fast_math restores default denormal and fpcontract handling - DenormalFpMath = ""; - FpContract = ""; - break; - } - // If we handled this option claim it - A->claim(); - } - - if (!HonorInfs) - CmdArgs.push_back("-menable-no-infs"); - - if (!HonorNans) - CmdArgs.push_back("-menable-no-nans"); - - if (MathErrno) - CmdArgs.push_back("-fmath-errno"); - - if (!MathErrno && AssociativeMath && ReciprocalMath && !SignedZeros && - !TrappingMath) - CmdArgs.push_back("-menable-unsafe-fp-math"); - - if (!SignedZeros) - CmdArgs.push_back("-fno-signed-zeros"); - - if (ReciprocalMath) - CmdArgs.push_back("-freciprocal-math"); - - if (!TrappingMath) - CmdArgs.push_back("-fno-trapping-math"); - - if (!DenormalFpMath.empty()) - CmdArgs.push_back(Args.MakeArgString("-fdenormal-fp-math="+DenormalFpMath)); - - if (!FpContract.empty()) - CmdArgs.push_back(Args.MakeArgString("-ffp-contract="+FpContract)); - - ParseMRecip(getToolChain().getDriver(), Args, CmdArgs); - - // -ffast-math enables the __FAST_MATH__ preprocessor macro, but check for the - // individual features enabled by -ffast-math instead of the option itself as - // that's consistent with gcc's behaviour. - if (!HonorInfs && !HonorNans && !MathErrno && AssociativeMath && - ReciprocalMath && !SignedZeros && !TrappingMath) - CmdArgs.push_back("-ffast-math"); - - // Handle __FINITE_MATH_ONLY__ similarly. - if (!HonorInfs && !HonorNans) - CmdArgs.push_back("-ffinite-math-only"); + RenderFloatingPointOptions(getToolChain(), D, OFastEnabled, Args, CmdArgs); // Decide whether to use verbose asm. Verbose assembly is the default on // toolchains which have the integrated assembler on by default. @@ -2516,13 +3421,12 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // Enable -mconstructor-aliases except on darwin, where we have to work around // a linker bug (see <rdar://problem/7651567>), and CUDA device code, where // aliases aren't supported. - if (!getToolChain().getTriple().isOSDarwin() && - !getToolChain().getTriple().isNVPTX()) + if (!RawTriple.isOSDarwin() && !RawTriple.isNVPTX()) CmdArgs.push_back("-mconstructor-aliases"); // Darwin's kernel doesn't support guard variables; just die if we // try to use them. - if (KernelOrKext && getToolChain().getTriple().isOSDarwin()) + if (KernelOrKext && RawTriple.isOSDarwin()) CmdArgs.push_back("-fforbid-guard-variables"); if (Args.hasFlag(options::OPT_mms_bitfields, options::OPT_mno_ms_bitfields, @@ -2536,6 +3440,19 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-mpie-copy-relocations"); } + if (Args.hasFlag(options::OPT_fno_plt, options::OPT_fplt, false)) { + CmdArgs.push_back("-fno-plt"); + } + + // -fhosted is default. + // TODO: Audit uses of KernelOrKext and see where it'd be more appropriate to + // use Freestanding. + bool Freestanding = + Args.hasFlag(options::OPT_ffreestanding, options::OPT_fhosted, false) || + KernelOrKext; + if (Freestanding) + CmdArgs.push_back("-ffreestanding"); + // This is a coarse approximation of what llvm-gcc actually does, both // -fasynchronous-unwind-tables and -fnon-call-exceptions interact in more // complicated ways. @@ -2544,7 +3461,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, options::OPT_fno_asynchronous_unwind_tables, (getToolChain().IsUnwindTablesDefault(Args) || getToolChain().getSanitizerArgs().needsUnwindTables()) && - !KernelOrKext); + !Freestanding); if (Args.hasFlag(options::OPT_funwind_tables, options::OPT_fno_unwind_tables, AsynchronousUnwindTables)) CmdArgs.push_back("-munwind-tables"); @@ -2572,108 +3489,47 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(Args.MakeArgString(CPU)); } - if (const Arg *A = Args.getLastArg(options::OPT_mfpmath_EQ)) { - CmdArgs.push_back("-mfpmath"); - CmdArgs.push_back(A->getValue()); - } - - // Add the target features - getTargetFeatures(getToolChain(), Triple, Args, CmdArgs, false); - - // Add target specific flags. - switch (getToolChain().getArch()) { - default: - break; - - case llvm::Triple::arm: - case llvm::Triple::armeb: - case llvm::Triple::thumb: - case llvm::Triple::thumbeb: - // Use the effective triple, which takes into account the deployment target. - AddARMTargetArgs(Triple, Args, CmdArgs, KernelOrKext); - break; - - case llvm::Triple::aarch64: - case llvm::Triple::aarch64_be: - AddAArch64TargetArgs(Args, CmdArgs); - break; - - case llvm::Triple::mips: - case llvm::Triple::mipsel: - case llvm::Triple::mips64: - case llvm::Triple::mips64el: - AddMIPSTargetArgs(Args, CmdArgs); - break; - - case llvm::Triple::ppc: - case llvm::Triple::ppc64: - case llvm::Triple::ppc64le: - AddPPCTargetArgs(Args, CmdArgs); - break; - - case llvm::Triple::sparc: - case llvm::Triple::sparcel: - case llvm::Triple::sparcv9: - AddSparcTargetArgs(Args, CmdArgs); - break; - - case llvm::Triple::systemz: - AddSystemZTargetArgs(Args, CmdArgs); - break; - - case llvm::Triple::x86: - case llvm::Triple::x86_64: - AddX86TargetArgs(Args, CmdArgs); - break; - - case llvm::Triple::lanai: - AddLanaiTargetArgs(Args, CmdArgs); - break; - - case llvm::Triple::hexagon: - AddHexagonTargetArgs(Args, CmdArgs); - break; - - case llvm::Triple::wasm32: - case llvm::Triple::wasm64: - AddWebAssemblyTargetArgs(Args, CmdArgs); - break; - } + RenderTargetOptions(Triple, Args, KernelOrKext, CmdArgs); - // The 'g' groups options involve a somewhat intricate sequence of decisions - // about what to pass from the driver to the frontend, but by the time they - // reach cc1 they've been factored into three well-defined orthogonal choices: - // * what level of debug info to generate - // * what dwarf version to write - // * what debugger tuning to use - // This avoids having to monkey around further in cc1 other than to disable - // codeview if not running in a Windows environment. Perhaps even that - // decision should be made in the driver as well though. - unsigned DwarfVersion = 0; - llvm::DebuggerKind DebuggerTuning = getToolChain().getDefaultDebuggerTuning(); // These two are potentially updated by AddClangCLArgs. codegenoptions::DebugInfoKind DebugInfoKind = codegenoptions::NoDebugInfo; bool EmitCodeView = false; // Add clang-cl arguments. types::ID InputType = Input.getType(); - if (getToolChain().getDriver().IsCLMode()) + if (D.IsCLMode()) AddClangCLArgs(Args, InputType, CmdArgs, &DebugInfoKind, &EmitCodeView); + const Arg *SplitDWARFArg = nullptr; + RenderDebugOptions(getToolChain(), D, RawTriple, Args, EmitCodeView, + IsWindowsMSVC, CmdArgs, DebugInfoKind, SplitDWARFArg); + + // Add the split debug info name to the command lines here so we + // can propagate it to the backend. + bool SplitDWARF = SplitDWARFArg && RawTriple.isOSLinux() && + (isa<AssembleJobAction>(JA) || isa<CompileJobAction>(JA) || + isa<BackendJobAction>(JA)); + const char *SplitDWARFOut; + if (SplitDWARF) { + CmdArgs.push_back("-split-dwarf-file"); + SplitDWARFOut = SplitDebugName(Args, Input); + CmdArgs.push_back(SplitDWARFOut); + } + // Pass the linker version in use. if (Arg *A = Args.getLastArg(options::OPT_mlinker_version_EQ)) { CmdArgs.push_back("-target-linker-version"); CmdArgs.push_back(A->getValue()); } - if (!shouldUseLeafFramePointer(Args, getToolChain().getTriple())) + if (!shouldUseLeafFramePointer(Args, RawTriple)) CmdArgs.push_back("-momit-leaf-frame-pointer"); // Explicitly error on some things we know we don't support and can't just // ignore. if (!Args.hasArg(options::OPT_fallow_unsupported)) { Arg *Unsupported; - if (types::isCXX(InputType) && getToolChain().getTriple().isOSDarwin() && + if (types::isCXX(InputType) && RawTriple.isOSDarwin() && getToolChain().getArch() == llvm::Triple::x86) { if ((Unsupported = Args.getLastArg(options::OPT_fapple_kext)) || (Unsupported = Args.getLastArg(options::OPT_mkernel))) @@ -2706,139 +3562,6 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, : "-"); } - bool splitDwarfInlining = - Args.hasFlag(options::OPT_fsplit_dwarf_inlining, - options::OPT_fno_split_dwarf_inlining, true); - - Args.ClaimAllArgs(options::OPT_g_Group); - Arg *SplitDwarfArg = Args.getLastArg(options::OPT_gsplit_dwarf); - if (Arg *A = Args.getLastArg(options::OPT_g_Group)) { - // If the last option explicitly specified a debug-info level, use it. - if (A->getOption().matches(options::OPT_gN_Group)) { - DebugInfoKind = DebugLevelToInfoKind(*A); - // If you say "-gsplit-dwarf -gline-tables-only", -gsplit-dwarf loses. - // But -gsplit-dwarf is not a g_group option, hence we have to check the - // order explicitly. (If -gsplit-dwarf wins, we fix DebugInfoKind later.) - // This gets a bit more complicated if you've disabled inline info in the - // skeleton CUs (splitDwarfInlining) - then there's value in composing - // split-dwarf and line-tables-only, so let those compose naturally in - // that case. - // And if you just turned off debug info, (-gsplit-dwarf -g0) - do that. - if (SplitDwarfArg) { - if (A->getIndex() > SplitDwarfArg->getIndex()) { - if (DebugInfoKind == codegenoptions::NoDebugInfo || - (DebugInfoKind == codegenoptions::DebugLineTablesOnly && - splitDwarfInlining)) - SplitDwarfArg = nullptr; - } else if (splitDwarfInlining) - DebugInfoKind = codegenoptions::NoDebugInfo; - } - } else - // For any other 'g' option, use Limited. - DebugInfoKind = codegenoptions::LimitedDebugInfo; - } - - // If a debugger tuning argument appeared, remember it. - if (Arg *A = Args.getLastArg(options::OPT_gTune_Group, - options::OPT_ggdbN_Group)) { - if (A->getOption().matches(options::OPT_glldb)) - DebuggerTuning = llvm::DebuggerKind::LLDB; - else if (A->getOption().matches(options::OPT_gsce)) - DebuggerTuning = llvm::DebuggerKind::SCE; - else - DebuggerTuning = llvm::DebuggerKind::GDB; - } - - // If a -gdwarf argument appeared, remember it. - if (Arg *A = Args.getLastArg(options::OPT_gdwarf_2, options::OPT_gdwarf_3, - options::OPT_gdwarf_4, options::OPT_gdwarf_5)) - DwarfVersion = DwarfVersionNum(A->getSpelling()); - - // Forward -gcodeview. EmitCodeView might have been set by CL-compatibility - // argument parsing. - if (Args.hasArg(options::OPT_gcodeview) || EmitCodeView) { - // DwarfVersion remains at 0 if no explicit choice was made. - CmdArgs.push_back("-gcodeview"); - } else if (DwarfVersion == 0 && - DebugInfoKind != codegenoptions::NoDebugInfo) { - DwarfVersion = getToolChain().GetDefaultDwarfVersion(); - } - - // We ignore flag -gstrict-dwarf for now. - // And we handle flag -grecord-gcc-switches later with DwarfDebugFlags. - Args.ClaimAllArgs(options::OPT_g_flags_Group); - - // Column info is included by default for everything except PS4 and CodeView. - // Clang doesn't track end columns, just starting columns, which, in theory, - // is fine for CodeView (and PDB). In practice, however, the Microsoft - // debuggers don't handle missing end columns well, so it's better not to - // include any column info. - if (Args.hasFlag(options::OPT_gcolumn_info, options::OPT_gno_column_info, - /*Default=*/ !IsPS4CPU && !(IsWindowsMSVC && EmitCodeView))) - CmdArgs.push_back("-dwarf-column-info"); - - // FIXME: Move backend command line options to the module. - // If -gline-tables-only is the last option it wins. - if (DebugInfoKind != codegenoptions::DebugLineTablesOnly && - Args.hasArg(options::OPT_gmodules)) { - DebugInfoKind = codegenoptions::LimitedDebugInfo; - CmdArgs.push_back("-dwarf-ext-refs"); - CmdArgs.push_back("-fmodule-format=obj"); - } - - // -gsplit-dwarf should turn on -g and enable the backend dwarf - // splitting and extraction. - // FIXME: Currently only works on Linux. - if (getToolChain().getTriple().isOSLinux()) { - if (!splitDwarfInlining) - CmdArgs.push_back("-fno-split-dwarf-inlining"); - if (SplitDwarfArg) { - if (DebugInfoKind == codegenoptions::NoDebugInfo) - DebugInfoKind = codegenoptions::LimitedDebugInfo; - CmdArgs.push_back("-enable-split-dwarf"); - } - } - - // After we've dealt with all combinations of things that could - // make DebugInfoKind be other than None or DebugLineTablesOnly, - // figure out if we need to "upgrade" it to standalone debug info. - // We parse these two '-f' options whether or not they will be used, - // to claim them even if you wrote "-fstandalone-debug -gline-tables-only" - bool NeedFullDebug = Args.hasFlag(options::OPT_fstandalone_debug, - options::OPT_fno_standalone_debug, - getToolChain().GetDefaultStandaloneDebug()); - if (DebugInfoKind == codegenoptions::LimitedDebugInfo && NeedFullDebug) - DebugInfoKind = codegenoptions::FullDebugInfo; - RenderDebugEnablingArgs(Args, CmdArgs, DebugInfoKind, DwarfVersion, - DebuggerTuning); - - // -fdebug-macro turns on macro debug info generation. - if (Args.hasFlag(options::OPT_fdebug_macro, options::OPT_fno_debug_macro, - false)) - CmdArgs.push_back("-debug-info-macro"); - - // -ggnu-pubnames turns on gnu style pubnames in the backend. - if (Args.hasArg(options::OPT_ggnu_pubnames)) { - CmdArgs.push_back("-backend-option"); - CmdArgs.push_back("-generate-gnu-dwarf-pub-sections"); - } - - // -gdwarf-aranges turns on the emission of the aranges section in the - // backend. - // Always enabled on the PS4. - if (Args.hasArg(options::OPT_gdwarf_aranges) || IsPS4CPU) { - CmdArgs.push_back("-backend-option"); - CmdArgs.push_back("-generate-arange-section"); - } - - if (Args.hasFlag(options::OPT_fdebug_types_section, - options::OPT_fno_debug_types_section, false)) { - CmdArgs.push_back("-backend-option"); - CmdArgs.push_back("-generate-type-units"); - } - - RenderDebugInfoCompressionArgs(Args, CmdArgs, D); - bool UseSeparateSections = isUseSeparateSections(Triple); if (Args.hasFlag(options::OPT_ffunction_sections, @@ -2855,7 +3578,11 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, options::OPT_fno_unique_section_names, true)) CmdArgs.push_back("-fno-unique-section-names"); - Args.AddAllArgs(CmdArgs, options::OPT_finstrument_functions); + if (auto *A = Args.getLastArg( + options::OPT_finstrument_functions, + options::OPT_finstrument_functions_after_inlining, + options::OPT_finstrument_function_entry_bare)) + A->render(Args, CmdArgs); addPGOAndCoverageFlags(C, D, Output, Args, CmdArgs); @@ -2863,7 +3590,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, ABICompatArg->render(Args, CmdArgs); // Add runtime flag for PS4 when PGO or Coverage are enabled. - if (getToolChain().getTriple().isPS4CPU()) + if (RawTriple.isPS4CPU()) PS4cpu::addProfileRTArgs(getToolChain(), Args, CmdArgs); // Pass options for controlling the default header search paths. @@ -2883,75 +3610,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, Args.AddLastArg(CmdArgs, options::OPT_working_directory); - bool ARCMTEnabled = false; - if (!Args.hasArg(options::OPT_fno_objc_arc, options::OPT_fobjc_arc)) { - if (const Arg *A = Args.getLastArg(options::OPT_ccc_arcmt_check, - options::OPT_ccc_arcmt_modify, - options::OPT_ccc_arcmt_migrate)) { - ARCMTEnabled = true; - switch (A->getOption().getID()) { - default: - llvm_unreachable("missed a case"); - case options::OPT_ccc_arcmt_check: - CmdArgs.push_back("-arcmt-check"); - break; - case options::OPT_ccc_arcmt_modify: - CmdArgs.push_back("-arcmt-modify"); - break; - case options::OPT_ccc_arcmt_migrate: - CmdArgs.push_back("-arcmt-migrate"); - CmdArgs.push_back("-mt-migrate-directory"); - CmdArgs.push_back(A->getValue()); - - Args.AddLastArg(CmdArgs, options::OPT_arcmt_migrate_report_output); - Args.AddLastArg(CmdArgs, options::OPT_arcmt_migrate_emit_arc_errors); - break; - } - } - } else { - Args.ClaimAllArgs(options::OPT_ccc_arcmt_check); - Args.ClaimAllArgs(options::OPT_ccc_arcmt_modify); - Args.ClaimAllArgs(options::OPT_ccc_arcmt_migrate); - } - - if (const Arg *A = Args.getLastArg(options::OPT_ccc_objcmt_migrate)) { - if (ARCMTEnabled) { - D.Diag(diag::err_drv_argument_not_allowed_with) << A->getAsString(Args) - << "-ccc-arcmt-migrate"; - } - CmdArgs.push_back("-mt-migrate-directory"); - CmdArgs.push_back(A->getValue()); - - if (!Args.hasArg(options::OPT_objcmt_migrate_literals, - options::OPT_objcmt_migrate_subscripting, - options::OPT_objcmt_migrate_property)) { - // None specified, means enable them all. - CmdArgs.push_back("-objcmt-migrate-literals"); - CmdArgs.push_back("-objcmt-migrate-subscripting"); - CmdArgs.push_back("-objcmt-migrate-property"); - } else { - Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_literals); - Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_subscripting); - Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_property); - } - } else { - Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_literals); - Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_subscripting); - Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_property); - Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_all); - Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_readonly_property); - Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_readwrite_property); - Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_property_dot_syntax); - Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_annotation); - Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_instancetype); - Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_nsmacros); - Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_protocol_conformance); - Args.AddLastArg(CmdArgs, options::OPT_objcmt_atomic_property); - Args.AddLastArg(CmdArgs, options::OPT_objcmt_returns_innerpointer_property); - Args.AddLastArg(CmdArgs, options::OPT_objcmt_ns_nonatomic_iosonly); - Args.AddLastArg(CmdArgs, options::OPT_objcmt_migrate_designated_init); - Args.AddLastArg(CmdArgs, options::OPT_objcmt_whitelist_dir_path); - } + RenderARCMigrateToolOptions(D, Args, CmdArgs); // Add preprocessing options like -I, -D, etc. if we are using the // preprocessor. @@ -3196,14 +3855,6 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, Args.AddLastArg(CmdArgs, options::OPT_ftlsmodel_EQ); - // -fhosted is default. - bool IsHosted = true; - if (Args.hasFlag(options::OPT_ffreestanding, options::OPT_fhosted, false) || - KernelOrKext) { - CmdArgs.push_back("-ffreestanding"); - IsHosted = false; - } - // Forward -f (flag) options which we can pass directly. Args.AddLastArg(CmdArgs, options::OPT_femit_all_decls); Args.AddLastArg(CmdArgs, options::OPT_fheinous_gnu_extensions); @@ -3228,7 +3879,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, options::OPT_fno_openmp, false) && (JA.isDeviceOffloading(Action::OFK_None) || JA.isDeviceOffloading(Action::OFK_OpenMP))) { - switch (getToolChain().getDriver().getOpenMPRuntime(Args)) { + switch (D.getOpenMPRuntime(Args)) { case Driver::OMPRT_OMP: case Driver::OMPRT_IOMP5: // Clang can generate useful OpenMP code for these two runtime libraries. @@ -3309,49 +3960,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, Args.AddLastArg(CmdArgs, options::OPT_pthread); - // -stack-protector=0 is default. - unsigned StackProtectorLevel = 0; - // NVPTX doesn't support stack protectors; from the compiler's perspective, it - // doesn't even have a stack! - if (!Triple.isNVPTX()) { - if (Arg *A = Args.getLastArg(options::OPT_fno_stack_protector, - options::OPT_fstack_protector_all, - options::OPT_fstack_protector_strong, - options::OPT_fstack_protector)) { - if (A->getOption().matches(options::OPT_fstack_protector)) { - StackProtectorLevel = std::max<unsigned>( - LangOptions::SSPOn, - getToolChain().GetDefaultStackProtectorLevel(KernelOrKext)); - } else if (A->getOption().matches(options::OPT_fstack_protector_strong)) - StackProtectorLevel = LangOptions::SSPStrong; - else if (A->getOption().matches(options::OPT_fstack_protector_all)) - StackProtectorLevel = LangOptions::SSPReq; - } else { - StackProtectorLevel = - getToolChain().GetDefaultStackProtectorLevel(KernelOrKext); - // Only use a default stack protector on Darwin in case -ffreestanding - // is not specified. - if (Triple.isOSDarwin() && !IsHosted) - StackProtectorLevel = 0; - } - } - if (StackProtectorLevel) { - CmdArgs.push_back("-stack-protector"); - CmdArgs.push_back(Args.MakeArgString(Twine(StackProtectorLevel))); - } - - // --param ssp-buffer-size= - for (const Arg *A : Args.filtered(options::OPT__param)) { - StringRef Str(A->getValue()); - if (Str.startswith("ssp-buffer-size=")) { - if (StackProtectorLevel) { - CmdArgs.push_back("-stack-protector-buffer-size"); - // FIXME: Verify the argument is a valid integer. - CmdArgs.push_back(Args.MakeArgString(Str.drop_front(16))); - } - A->claim(); - } - } + RenderSSPOptions(getToolChain(), Args, CmdArgs, KernelOrKext); // Translate -mstackrealign if (Args.hasFlag(options::OPT_mstackrealign, options::OPT_mno_stackrealign, @@ -3372,20 +3981,6 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-mstack-probe-size=0"); } - switch (getToolChain().getArch()) { - case llvm::Triple::aarch64: - case llvm::Triple::aarch64_be: - case llvm::Triple::arm: - case llvm::Triple::armeb: - case llvm::Triple::thumb: - case llvm::Triple::thumbeb: - CmdArgs.push_back("-fallow-half-arguments-and-returns"); - break; - - default: - break; - } - if (Arg *A = Args.getLastArg(options::OPT_mrestrict_it, options::OPT_mno_restrict_it)) { if (A->getOption().matches(options::OPT_mrestrict_it)) { @@ -3404,44 +3999,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, } // Forward -cl options to -cc1 - if (Args.getLastArg(options::OPT_cl_opt_disable)) { - CmdArgs.push_back("-cl-opt-disable"); - } - if (Args.getLastArg(options::OPT_cl_strict_aliasing)) { - CmdArgs.push_back("-cl-strict-aliasing"); - } - if (Args.getLastArg(options::OPT_cl_single_precision_constant)) { - CmdArgs.push_back("-cl-single-precision-constant"); - } - if (Args.getLastArg(options::OPT_cl_finite_math_only)) { - CmdArgs.push_back("-cl-finite-math-only"); - } - if (Args.getLastArg(options::OPT_cl_kernel_arg_info)) { - CmdArgs.push_back("-cl-kernel-arg-info"); - } - if (Args.getLastArg(options::OPT_cl_unsafe_math_optimizations)) { - CmdArgs.push_back("-cl-unsafe-math-optimizations"); - } - if (Args.getLastArg(options::OPT_cl_fast_relaxed_math)) { - CmdArgs.push_back("-cl-fast-relaxed-math"); - } - if (Args.getLastArg(options::OPT_cl_mad_enable)) { - CmdArgs.push_back("-cl-mad-enable"); - } - if (Args.getLastArg(options::OPT_cl_no_signed_zeros)) { - CmdArgs.push_back("-cl-no-signed-zeros"); - } - if (Arg *A = Args.getLastArg(options::OPT_cl_std_EQ)) { - std::string CLStdStr = "-cl-std="; - CLStdStr += A->getValue(); - CmdArgs.push_back(Args.MakeArgString(CLStdStr)); - } - if (Args.getLastArg(options::OPT_cl_denorms_are_zero)) { - CmdArgs.push_back("-cl-denorms-are-zero"); - } - if (Args.getLastArg(options::OPT_cl_fp32_correctly_rounded_divide_sqrt)) { - CmdArgs.push_back("-cl-fp32-correctly-rounded-divide-sqrt"); - } + RenderOpenCLOptions(Args, CmdArgs); // Forward -f options with positive and negative forms; we translate // these by hand. @@ -3453,36 +4011,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, A->render(Args, CmdArgs); } - if (Args.hasFlag(options::OPT_fdebug_info_for_profiling, - options::OPT_fno_debug_info_for_profiling, false)) - CmdArgs.push_back("-fdebug-info-for-profiling"); - - // -fbuiltin is default unless -mkernel is used. - bool UseBuiltins = - Args.hasFlag(options::OPT_fbuiltin, options::OPT_fno_builtin, - !Args.hasArg(options::OPT_mkernel)); - if (!UseBuiltins) - CmdArgs.push_back("-fno-builtin"); - - // -ffreestanding implies -fno-builtin. - if (Args.hasArg(options::OPT_ffreestanding)) - UseBuiltins = false; - - // Process the -fno-builtin-* options. - for (const auto &Arg : Args) { - const Option &O = Arg->getOption(); - if (!O.matches(options::OPT_fno_builtin_)) - continue; - - Arg->claim(); - // If -fno-builtin is specified, then there's no need to pass the option to - // the frontend. - if (!UseBuiltins) - continue; - - StringRef FuncName = Arg->getValue(); - CmdArgs.push_back(Args.MakeArgString("-fno-builtin-" + FuncName)); - } + RenderBuiltinOptions(getToolChain(), RawTriple, Args, CmdArgs); if (!Args.hasFlag(options::OPT_fassume_sane_operator_new, options::OPT_fno_assume_sane_operator_new)) @@ -3501,163 +4030,21 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-fblocks-runtime-optional"); } + // -fencode-extended-block-signature=1 is default. + if (getToolChain().IsEncodeExtendedBlockSignatureDefault()) + CmdArgs.push_back("-fencode-extended-block-signature"); + if (Args.hasFlag(options::OPT_fcoroutines_ts, options::OPT_fno_coroutines_ts, false) && types::isCXX(InputType)) { CmdArgs.push_back("-fcoroutines-ts"); } - // -fmodules enables the use of precompiled modules (off by default). - // Users can pass -fno-cxx-modules to turn off modules support for - // C++/Objective-C++ programs. - bool HaveClangModules = false; - if (Args.hasFlag(options::OPT_fmodules, options::OPT_fno_modules, false)) { - bool AllowedInCXX = Args.hasFlag(options::OPT_fcxx_modules, - options::OPT_fno_cxx_modules, true); - if (AllowedInCXX || !types::isCXX(InputType)) { - CmdArgs.push_back("-fmodules"); - HaveClangModules = true; - } - } - - bool HaveAnyModules = HaveClangModules; - if (Args.hasArg(options::OPT_fmodules_ts)) { - CmdArgs.push_back("-fmodules-ts"); - HaveAnyModules = true; - } - - // -fmodule-maps enables implicit reading of module map files. By default, - // this is enabled if we are using Clang's flavor of precompiled modules. - if (Args.hasFlag(options::OPT_fimplicit_module_maps, - options::OPT_fno_implicit_module_maps, HaveClangModules)) { - CmdArgs.push_back("-fimplicit-module-maps"); - } - - // -fmodules-decluse checks that modules used are declared so (off by - // default). - if (Args.hasFlag(options::OPT_fmodules_decluse, - options::OPT_fno_modules_decluse, false)) { - CmdArgs.push_back("-fmodules-decluse"); - } - - // -fmodules-strict-decluse is like -fmodule-decluse, but also checks that - // all #included headers are part of modules. - if (Args.hasFlag(options::OPT_fmodules_strict_decluse, - options::OPT_fno_modules_strict_decluse, false)) { - CmdArgs.push_back("-fmodules-strict-decluse"); - } - - // -fno-implicit-modules turns off implicitly compiling modules on demand. - if (!Args.hasFlag(options::OPT_fimplicit_modules, - options::OPT_fno_implicit_modules, HaveClangModules)) { - if (HaveAnyModules) - CmdArgs.push_back("-fno-implicit-modules"); - } else if (HaveAnyModules) { - // -fmodule-cache-path specifies where our implicitly-built module files - // should be written. - SmallString<128> Path; - if (Arg *A = Args.getLastArg(options::OPT_fmodules_cache_path)) - Path = A->getValue(); - if (C.isForDiagnostics()) { - // When generating crash reports, we want to emit the modules along with - // the reproduction sources, so we ignore any provided module path. - Path = Output.getFilename(); - llvm::sys::path::replace_extension(Path, ".cache"); - llvm::sys::path::append(Path, "modules"); - } else if (Path.empty()) { - // No module path was provided: use the default. - llvm::sys::path::system_temp_directory(/*erasedOnReboot=*/false, Path); - llvm::sys::path::append(Path, "org.llvm.clang."); - appendUserToPath(Path); - llvm::sys::path::append(Path, "ModuleCache"); - } - const char Arg[] = "-fmodules-cache-path="; - Path.insert(Path.begin(), Arg, Arg + strlen(Arg)); - CmdArgs.push_back(Args.MakeArgString(Path)); - } - - if (HaveAnyModules) { - // -fprebuilt-module-path specifies where to load the prebuilt module files. - for (const Arg *A : Args.filtered(options::OPT_fprebuilt_module_path)) - CmdArgs.push_back(Args.MakeArgString( - std::string("-fprebuilt-module-path=") + A->getValue())); - } + Args.AddLastArg(CmdArgs, options::OPT_fdouble_square_bracket_attributes, + options::OPT_fno_double_square_bracket_attributes); - // -fmodule-name specifies the module that is currently being built (or - // used for header checking by -fmodule-maps). - Args.AddLastArg(CmdArgs, options::OPT_fmodule_name_EQ); - - // -fmodule-map-file can be used to specify files containing module - // definitions. - Args.AddAllArgs(CmdArgs, options::OPT_fmodule_map_file); - - // -fbuiltin-module-map can be used to load the clang - // builtin headers modulemap file. - if (Args.hasArg(options::OPT_fbuiltin_module_map)) { - SmallString<128> BuiltinModuleMap(getToolChain().getDriver().ResourceDir); - llvm::sys::path::append(BuiltinModuleMap, "include"); - llvm::sys::path::append(BuiltinModuleMap, "module.modulemap"); - if (llvm::sys::fs::exists(BuiltinModuleMap)) { - CmdArgs.push_back(Args.MakeArgString("-fmodule-map-file=" + - BuiltinModuleMap)); - } - } - - // -fmodule-file can be used to specify files containing precompiled modules. - if (HaveAnyModules) - Args.AddAllArgs(CmdArgs, options::OPT_fmodule_file); - else - Args.ClaimAllArgs(options::OPT_fmodule_file); - - // When building modules and generating crashdumps, we need to dump a module - // dependency VFS alongside the output. - if (HaveClangModules && C.isForDiagnostics()) { - SmallString<128> VFSDir(Output.getFilename()); - llvm::sys::path::replace_extension(VFSDir, ".cache"); - // Add the cache directory as a temp so the crash diagnostics pick it up. - C.addTempFile(Args.MakeArgString(VFSDir)); - - llvm::sys::path::append(VFSDir, "vfs"); - CmdArgs.push_back("-module-dependency-dir"); - CmdArgs.push_back(Args.MakeArgString(VFSDir)); - } - - if (HaveClangModules) - Args.AddLastArg(CmdArgs, options::OPT_fmodules_user_build_path); - - // Pass through all -fmodules-ignore-macro arguments. - Args.AddAllArgs(CmdArgs, options::OPT_fmodules_ignore_macro); - Args.AddLastArg(CmdArgs, options::OPT_fmodules_prune_interval); - Args.AddLastArg(CmdArgs, options::OPT_fmodules_prune_after); - - Args.AddLastArg(CmdArgs, options::OPT_fbuild_session_timestamp); - - if (Arg *A = Args.getLastArg(options::OPT_fbuild_session_file)) { - if (Args.hasArg(options::OPT_fbuild_session_timestamp)) - D.Diag(diag::err_drv_argument_not_allowed_with) - << A->getAsString(Args) << "-fbuild-session-timestamp"; - - llvm::sys::fs::file_status Status; - if (llvm::sys::fs::status(A->getValue(), Status)) - D.Diag(diag::err_drv_no_such_file) << A->getValue(); - CmdArgs.push_back( - Args.MakeArgString("-fbuild-session-timestamp=" + - Twine((uint64_t)Status.getLastModificationTime() - .time_since_epoch() - .count()))); - } - - if (Args.getLastArg(options::OPT_fmodules_validate_once_per_build_session)) { - if (!Args.getLastArg(options::OPT_fbuild_session_timestamp, - options::OPT_fbuild_session_file)) - D.Diag(diag::err_drv_modules_validate_once_requires_timestamp); - - Args.AddLastArg(CmdArgs, - options::OPT_fmodules_validate_once_per_build_session); - } - - Args.AddLastArg(CmdArgs, options::OPT_fmodules_validate_system_headers); - Args.AddLastArg(CmdArgs, options::OPT_fmodules_disable_diagnostic_validation); + bool HaveModules = false; + RenderModulesOptions(C, D, Args, Input, Output, CmdArgs, HaveModules); // -faccess-control is default. if (Args.hasFlag(options::OPT_fno_access_control, @@ -3681,28 +4068,17 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, getToolChain().getArch() == llvm::Triple::hexagon)) CmdArgs.push_back("-fshort-enums"); - // -fsigned-char is default. - if (Arg *A = Args.getLastArg( - options::OPT_fsigned_char, options::OPT_fno_signed_char, - options::OPT_funsigned_char, options::OPT_fno_unsigned_char)) { - if (A->getOption().matches(options::OPT_funsigned_char) || - A->getOption().matches(options::OPT_fno_signed_char)) { - CmdArgs.push_back("-fno-signed-char"); - } - } else if (!isSignedCharDefault(getToolChain().getTriple())) { - CmdArgs.push_back("-fno-signed-char"); - } + RenderCharacterOptions(Args, AuxTriple ? *AuxTriple : RawTriple, CmdArgs); // -fuse-cxa-atexit is default. if (!Args.hasFlag( options::OPT_fuse_cxa_atexit, options::OPT_fno_use_cxa_atexit, - !IsWindowsCygnus && !IsWindowsGNU && - getToolChain().getTriple().getOS() != llvm::Triple::Solaris && + !RawTriple.isOSWindows() && + RawTriple.getOS() != llvm::Triple::Solaris && getToolChain().getArch() != llvm::Triple::hexagon && getToolChain().getArch() != llvm::Triple::xcore && - ((getToolChain().getTriple().getVendor() != - llvm::Triple::MipsTechnologies) || - getToolChain().getTriple().hasEnvironment())) || + ((RawTriple.getVendor() != llvm::Triple::MipsTechnologies) || + RawTriple.hasEnvironment())) || KernelOrKext) CmdArgs.push_back("-fno-use-cxa-atexit"); @@ -3724,8 +4100,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, options::OPT_fno_ms_extensions, true)))) CmdArgs.push_back("-fms-compatibility"); - VersionTuple MSVT = - getToolChain().computeMSVCVersion(&getToolChain().getDriver(), Args); + VersionTuple MSVT = getToolChain().computeMSVCVersion(&D, Args); if (!MSVT.empty()) CmdArgs.push_back( Args.MakeArgString("-fms-compatibility-version=" + MSVT.getAsString())); @@ -3736,7 +4111,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, if (const Arg *StdArg = Args.getLastArg(options::OPT__SLASH_std)) { LanguageStandard = llvm::StringSwitch<StringRef>(StdArg->getValue()) .Case("c++14", "-std=c++14") - .Case("c++latest", "-std=c++1z") + .Case("c++17", "-std=c++17") + .Case("c++latest", "-std=c++2a") .Default(""); if (LanguageStandard.empty()) D.Diag(clang::diag::warn_drv_unused_argument) @@ -3760,7 +4136,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // -fno-declspec is default, except for PS4. if (Args.hasFlag(options::OPT_fdeclspec, options::OPT_fno_declspec, - getToolChain().getTriple().isPS4())) + RawTriple.isPS4())) CmdArgs.push_back("-fdeclspec"); else if (Args.hasArg(options::OPT_fno_declspec)) CmdArgs.push_back("-fno-declspec"); // Explicitly disabling __declspec. @@ -3772,8 +4148,10 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, !IsWindowsMSVC || IsMSVC2015Compatible)) CmdArgs.push_back("-fno-threadsafe-statics"); - // -fno-delayed-template-parsing is default, except for Windows where MSVC STL - // needs it. + // -fno-delayed-template-parsing is default, except when targetting MSVC. + // Many old Windows SDK versions require this to parse. + // FIXME: MSVC introduced /Zc:twoPhase- to disable this behavior in their + // compiler. We should be able to disable this by default at some point. if (Args.hasFlag(options::OPT_fdelayed_template_parsing, options::OPT_fno_delayed_template_parsing, IsWindowsMSVC)) CmdArgs.push_back("-fdelayed-template-parsing"); @@ -3799,90 +4177,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, Args.AddLastArg(CmdArgs, options::OPT_fexperimental_new_pass_manager, options::OPT_fno_experimental_new_pass_manager); - ObjCRuntime objcRuntime = AddObjCRuntimeArgs(Args, CmdArgs, rewriteKind); - - // -fobjc-dispatch-method is only relevant with the nonfragile-abi, and - // legacy is the default. Except for deployment target of 10.5, - // next runtime is always legacy dispatch and -fno-objc-legacy-dispatch - // gets ignored silently. - if (objcRuntime.isNonFragile()) { - if (!Args.hasFlag(options::OPT_fobjc_legacy_dispatch, - options::OPT_fno_objc_legacy_dispatch, - objcRuntime.isLegacyDispatchDefaultForArch( - getToolChain().getArch()))) { - if (getToolChain().UseObjCMixedDispatch()) - CmdArgs.push_back("-fobjc-dispatch-method=mixed"); - else - CmdArgs.push_back("-fobjc-dispatch-method=non-legacy"); - } - } - - // When ObjectiveC legacy runtime is in effect on MacOSX, - // turn on the option to do Array/Dictionary subscripting - // by default. - if (getToolChain().getArch() == llvm::Triple::x86 && - getToolChain().getTriple().isMacOSX() && - !getToolChain().getTriple().isMacOSXVersionLT(10, 7) && - objcRuntime.getKind() == ObjCRuntime::FragileMacOSX && - objcRuntime.isNeXTFamily()) - CmdArgs.push_back("-fobjc-subscripting-legacy-runtime"); - - // -fencode-extended-block-signature=1 is default. - if (getToolChain().IsEncodeExtendedBlockSignatureDefault()) { - CmdArgs.push_back("-fencode-extended-block-signature"); - } - - // Allow -fno-objc-arr to trump -fobjc-arr/-fobjc-arc. - // NOTE: This logic is duplicated in ToolChains.cpp. - bool ARC = isObjCAutoRefCount(Args); - if (ARC) { - getToolChain().CheckObjCARC(); - - CmdArgs.push_back("-fobjc-arc"); - - // FIXME: It seems like this entire block, and several around it should be - // wrapped in isObjC, but for now we just use it here as this is where it - // was being used previously. - if (types::isCXX(InputType) && types::isObjC(InputType)) { - if (getToolChain().GetCXXStdlibType(Args) == ToolChain::CST_Libcxx) - CmdArgs.push_back("-fobjc-arc-cxxlib=libc++"); - else - CmdArgs.push_back("-fobjc-arc-cxxlib=libstdc++"); - } - - // Allow the user to enable full exceptions code emission. - // We define off for Objective-CC, on for Objective-C++. - if (Args.hasFlag(options::OPT_fobjc_arc_exceptions, - options::OPT_fno_objc_arc_exceptions, - /*default*/ types::isCXX(InputType))) - CmdArgs.push_back("-fobjc-arc-exceptions"); - } - - // Silence warning for full exception code emission options when explicitly - // set to use no ARC. - if (Args.hasArg(options::OPT_fno_objc_arc)) { - Args.ClaimAllArgs(options::OPT_fobjc_arc_exceptions); - Args.ClaimAllArgs(options::OPT_fno_objc_arc_exceptions); - } - - // -fobjc-infer-related-result-type is the default, except in the Objective-C - // rewriter. - if (rewriteKind != RK_None) - CmdArgs.push_back("-fno-objc-infer-related-result-type"); - - // Pass down -fobjc-weak or -fno-objc-weak if present. - if (types::isObjC(InputType)) { - auto WeakArg = Args.getLastArg(options::OPT_fobjc_weak, - options::OPT_fno_objc_weak); - if (!WeakArg) { - // nothing to do - } else if (!objcRuntime.allowsWeak()) { - if (WeakArg->getOption().matches(options::OPT_fobjc_weak)) - D.Diag(diag::err_objc_weak_unsupported); - } else { - WeakArg->render(Args, CmdArgs); - } - } + ObjCRuntime Runtime = AddObjCRuntimeArgs(Args, CmdArgs, rewriteKind); + RenderObjCOptions(getToolChain(), D, RawTriple, Args, Runtime, + rewriteKind != RK_None, Input, CmdArgs); if (Args.hasFlag(options::OPT_fapplication_extension, options::OPT_fno_application_extension, false)) @@ -3890,12 +4187,36 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // Handle GCC-style exception args. if (!C.getDriver().IsCLMode()) - addExceptionArgs(Args, InputType, getToolChain(), KernelOrKext, objcRuntime, + addExceptionArgs(Args, InputType, getToolChain(), KernelOrKext, Runtime, CmdArgs); - if (Args.hasArg(options::OPT_fsjlj_exceptions) || - getToolChain().UseSjLjExceptions(Args)) - CmdArgs.push_back("-fsjlj-exceptions"); + // Handle exception personalities + Arg *A = Args.getLastArg(options::OPT_fsjlj_exceptions, + options::OPT_fseh_exceptions, + options::OPT_fdwarf_exceptions); + if (A) { + const Option &Opt = A->getOption(); + if (Opt.matches(options::OPT_fsjlj_exceptions)) + CmdArgs.push_back("-fsjlj-exceptions"); + if (Opt.matches(options::OPT_fseh_exceptions)) + CmdArgs.push_back("-fseh-exceptions"); + if (Opt.matches(options::OPT_fdwarf_exceptions)) + CmdArgs.push_back("-fdwarf-exceptions"); + } else { + switch (getToolChain().GetExceptionModel(Args)) { + default: + break; + case llvm::ExceptionHandling::DwarfCFI: + CmdArgs.push_back("-fdwarf-exceptions"); + break; + case llvm::ExceptionHandling::SjLj: + CmdArgs.push_back("-fsjlj-exceptions"); + break; + case llvm::ExceptionHandling::WinEH: + CmdArgs.push_back("-fseh-exceptions"); + break; + } + } // C++ "sane" operator new. if (!Args.hasFlag(options::OPT_fassume_sane_operator_new, @@ -3941,12 +4262,6 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, options::OPT_mno_constant_cfstrings)) CmdArgs.push_back("-fno-constant-cfstrings"); - // -fshort-wchar default varies depending on platform; only - // pass if specified. - if (Arg *A = Args.getLastArg(options::OPT_fshort_wchar, - options::OPT_fno_short_wchar)) - A->render(Args, CmdArgs); - // -fno-pascal-strings is default, only pass non-default. if (Args.hasFlag(options::OPT_fpascal_strings, options::OPT_fno_pascal_strings, false)) @@ -3971,7 +4286,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, MaxTypeAlignStr += A->getValue(); CmdArgs.push_back(Args.MakeArgString(MaxTypeAlignStr)); } - } else if (getToolChain().getTriple().isOSDarwin()) { + } else if (RawTriple.isOSDarwin()) { if (!SkipMaxTypeAlign) { std::string MaxTypeAlignStr = "-fmax-type-align=16"; CmdArgs.push_back(Args.MakeArgString(MaxTypeAlignStr)); @@ -3979,8 +4294,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, } // -fcommon is the default unless compiling kernel code or the target says so - bool NoCommonDefault = - KernelOrKext || isNoCommonDefault(getToolChain().getTriple()); + bool NoCommonDefault = KernelOrKext || isNoCommonDefault(RawTriple); if (!Args.hasFlag(options::OPT_fcommon, options::OPT_fno_common, !NoCommonDefault)) CmdArgs.push_back("-fno-common"); @@ -4013,113 +4327,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, << value; } - bool CaretDefault = true; - bool ColumnDefault = true; - if (Arg *DiagArg = Args.getLastArg(options::OPT__SLASH_diagnostics_classic, - options::OPT__SLASH_diagnostics_column, - options::OPT__SLASH_diagnostics_caret)) { - switch (DiagArg->getOption().getID()) { - case options::OPT__SLASH_diagnostics_caret: - CaretDefault = true; - ColumnDefault = true; - break; - case options::OPT__SLASH_diagnostics_column: - CaretDefault = false; - ColumnDefault = true; - break; - case options::OPT__SLASH_diagnostics_classic: - CaretDefault = false; - ColumnDefault = false; - break; - } - } - - // -fcaret-diagnostics is default. - if (!Args.hasFlag(options::OPT_fcaret_diagnostics, - options::OPT_fno_caret_diagnostics, CaretDefault)) - CmdArgs.push_back("-fno-caret-diagnostics"); - - // -fdiagnostics-fixit-info is default, only pass non-default. - if (!Args.hasFlag(options::OPT_fdiagnostics_fixit_info, - options::OPT_fno_diagnostics_fixit_info)) - CmdArgs.push_back("-fno-diagnostics-fixit-info"); - - // Enable -fdiagnostics-show-option by default. - if (Args.hasFlag(options::OPT_fdiagnostics_show_option, - options::OPT_fno_diagnostics_show_option)) - CmdArgs.push_back("-fdiagnostics-show-option"); - - if (const Arg *A = - Args.getLastArg(options::OPT_fdiagnostics_show_category_EQ)) { - CmdArgs.push_back("-fdiagnostics-show-category"); - CmdArgs.push_back(A->getValue()); - } - - if (Args.hasFlag(options::OPT_fdiagnostics_show_hotness, - options::OPT_fno_diagnostics_show_hotness, false)) - CmdArgs.push_back("-fdiagnostics-show-hotness"); - - if (const Arg *A = - Args.getLastArg(options::OPT_fdiagnostics_hotness_threshold_EQ)) { - std::string Opt = std::string("-fdiagnostics-hotness-threshold=") + A->getValue(); - CmdArgs.push_back(Args.MakeArgString(Opt)); - } - - if (const Arg *A = Args.getLastArg(options::OPT_fdiagnostics_format_EQ)) { - CmdArgs.push_back("-fdiagnostics-format"); - CmdArgs.push_back(A->getValue()); - } - - if (Arg *A = Args.getLastArg( - options::OPT_fdiagnostics_show_note_include_stack, - options::OPT_fno_diagnostics_show_note_include_stack)) { - if (A->getOption().matches( - options::OPT_fdiagnostics_show_note_include_stack)) - CmdArgs.push_back("-fdiagnostics-show-note-include-stack"); - else - CmdArgs.push_back("-fno-diagnostics-show-note-include-stack"); - } - - // Color diagnostics are parsed by the driver directly from argv - // and later re-parsed to construct this job; claim any possible - // color diagnostic here to avoid warn_drv_unused_argument and - // diagnose bad OPT_fdiagnostics_color_EQ values. - for (Arg *A : Args) { - const Option &O = A->getOption(); - if (!O.matches(options::OPT_fcolor_diagnostics) && - !O.matches(options::OPT_fdiagnostics_color) && - !O.matches(options::OPT_fno_color_diagnostics) && - !O.matches(options::OPT_fno_diagnostics_color) && - !O.matches(options::OPT_fdiagnostics_color_EQ)) - continue; - if (O.matches(options::OPT_fdiagnostics_color_EQ)) { - StringRef Value(A->getValue()); - if (Value != "always" && Value != "never" && Value != "auto") - getToolChain().getDriver().Diag(diag::err_drv_clang_unsupported) - << ("-fdiagnostics-color=" + Value).str(); - } - A->claim(); - } - if (D.getDiags().getDiagnosticOptions().ShowColors) - CmdArgs.push_back("-fcolor-diagnostics"); - - if (Args.hasArg(options::OPT_fansi_escape_codes)) - CmdArgs.push_back("-fansi-escape-codes"); - - if (!Args.hasFlag(options::OPT_fshow_source_location, - options::OPT_fno_show_source_location)) - CmdArgs.push_back("-fno-show-source-location"); - - if (Args.hasArg(options::OPT_fdiagnostics_absolute_paths)) - CmdArgs.push_back("-fdiagnostics-absolute-paths"); - - if (!Args.hasFlag(options::OPT_fshow_column, options::OPT_fno_show_column, - ColumnDefault)) - CmdArgs.push_back("-fno-show-column"); - - if (!Args.hasFlag(options::OPT_fspell_checking, - options::OPT_fno_spell_checking)) - CmdArgs.push_back("-fno-spell-checking"); + RenderDiagnosticsOptions(D, Args, CmdArgs); // -fno-asm-blocks is default. if (Args.hasFlag(options::OPT_fasm_blocks, options::OPT_fno_asm_blocks, @@ -4149,6 +4357,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, options::OPT_fno_slp_vectorize, EnableSLPVec)) CmdArgs.push_back("-vectorize-slp"); + ParseMPreferVectorWidth(D, Args, CmdArgs); + if (Arg *A = Args.getLastArg(options::OPT_fshow_overloads_EQ)) A->render(Args, CmdArgs); @@ -4178,13 +4388,6 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, options::OPT_fno_apple_pragma_pack, false)) CmdArgs.push_back("-fapple-pragma-pack"); - // le32-specific flags: - // -fno-math-builtin: clang should not convert math builtins to intrinsics - // by default. - if (getToolChain().getArch() == llvm::Triple::le32) { - CmdArgs.push_back("-fno-math-builtin"); - } - if (Args.hasFlag(options::OPT_fsave_optimization_record, options::OPT_fno_save_optimization_record, false)) { CmdArgs.push_back("-opt-record-file"); @@ -4194,10 +4397,13 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(A->getValue()); } else { SmallString<128> F; - if (Output.isFilename() && (Args.hasArg(options::OPT_c) || - Args.hasArg(options::OPT_S))) { - F = Output.getFilename(); - } else { + + if (Args.hasArg(options::OPT_c) || Args.hasArg(options::OPT_S)) { + if (Arg *FinalOutput = Args.getLastArg(options::OPT_o)) + F = FinalOutput->getValue(); + } + + if (F.empty()) { // Use the input filename. F = llvm::sys::path::stem(Input.getBaseInput()); @@ -4219,20 +4425,6 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, } } -// Default to -fno-builtin-str{cat,cpy} on Darwin for ARM. -// -// FIXME: Now that PR4941 has been fixed this can be enabled. -#if 0 - if (getToolChain().getTriple().isOSDarwin() && - (getToolChain().getArch() == llvm::Triple::arm || - getToolChain().getArch() == llvm::Triple::thumb)) { - if (!Args.hasArg(options::OPT_fbuiltin_strcat)) - CmdArgs.push_back("-fno-builtin-strcat"); - if (!Args.hasArg(options::OPT_fbuiltin_strcpy)) - CmdArgs.push_back("-fno-builtin-strcpy"); - } -#endif - bool RewriteImports = Args.hasFlag(options::OPT_frewrite_imports, options::OPT_fno_rewrite_imports, false); if (RewriteImports) @@ -4244,7 +4436,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // nice to enable this when doing a crashdump for modules as well. if (Args.hasFlag(options::OPT_frewrite_includes, options::OPT_fno_rewrite_includes, false) || - (C.isForDiagnostics() && (RewriteImports || !HaveAnyModules))) + (C.isForDiagnostics() && (RewriteImports || !HaveModules))) CmdArgs.push_back("-frewrite-includes"); // Only allow -traditional or -traditional-cpp outside in preprocessing modes. @@ -4366,7 +4558,7 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, Args.AddAllArgs(CmdArgs, options::OPT_undef); - const char *Exec = getToolChain().getDriver().getClangProgramPath(); + const char *Exec = D.getClangProgramPath(); // Optionally embed the -cc1 level arguments into the debug info, for build // analysis. @@ -4392,18 +4584,6 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(Args.MakeArgString(Flags)); } - // Add the split debug info name to the command lines here so we - // can propagate it to the backend. - bool SplitDwarf = SplitDwarfArg && getToolChain().getTriple().isOSLinux() && - (isa<AssembleJobAction>(JA) || isa<CompileJobAction>(JA) || - isa<BackendJobAction>(JA)); - const char *SplitDwarfOut; - if (SplitDwarf) { - CmdArgs.push_back("-split-dwarf-file"); - SplitDwarfOut = SplitDebugName(Args, Input); - CmdArgs.push_back(SplitDwarfOut); - } - // Host-side cuda compilation receives device-side outputs as Inputs[1...]. // Include them with -fcuda-include-gpubinary. if (IsCuda && Inputs.size() > 1) @@ -4476,8 +4656,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // 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 (SplitDwarf && Output.getType() == types::TY_Object) - SplitDebugInfo(getToolChain(), C, *this, JA, Args, Output, SplitDwarfOut); + if (SplitDWARF && Output.getType() == types::TY_Object) + SplitDebugInfo(getToolChain(), C, *this, JA, Args, Output, SplitDWARFOut); if (Arg *A = Args.getLastArg(options::OPT_pg)) if (Args.hasArg(options::OPT_fomit_frame_pointer)) @@ -4752,7 +4932,9 @@ void Clang::AddClangCLArgs(const ArgList &Args, types::ID InputType, // Both /showIncludes and /E (and /EP) write to stdout. Allowing both // would produce interleaved output, so ignore /showIncludes in such cases. - if (!Args.hasArg(options::OPT_E) && !Args.hasArg(options::OPT__SLASH_EP)) + if ((!Args.hasArg(options::OPT_E) && !Args.hasArg(options::OPT__SLASH_EP)) || + (Args.hasArg(options::OPT__SLASH_P) && + Args.hasArg(options::OPT__SLASH_EP) && !Args.hasArg(options::OPT_E))) if (Arg *A = Args.getLastArg(options::OPT_show_includes)) A->render(Args, CmdArgs); @@ -4841,7 +5023,8 @@ void Clang::AddClangCLArgs(const ArgList &Args, types::ID InputType, // Parse the default calling convention options. if (Arg *CCArg = Args.getLastArg(options::OPT__SLASH_Gd, options::OPT__SLASH_Gr, - options::OPT__SLASH_Gz, options::OPT__SLASH_Gv)) { + options::OPT__SLASH_Gz, options::OPT__SLASH_Gv, + options::OPT__SLASH_Gregcall)) { unsigned DCCOptId = CCArg->getOption().getID(); const char *DCCFlag = nullptr; bool ArchSupported = true; @@ -4862,6 +5045,10 @@ void Clang::AddClangCLArgs(const ArgList &Args, types::ID InputType, ArchSupported = Arch == llvm::Triple::x86 || Arch == llvm::Triple::x86_64; DCCFlag = "-fdefault-calling-conv=vectorcall"; break; + case options::OPT__SLASH_Gregcall: + ArchSupported = Arch == llvm::Triple::x86 || Arch == llvm::Triple::x86_64; + DCCFlag = "-fdefault-calling-conv=regcall"; + break; } // MSVC doesn't warn if /Gr or /Gz is used on x64, so we don't either. @@ -5176,12 +5363,15 @@ void OffloadBundler::ConstructJob(Compilation &C, const JobAction &JA, if (I) Triples += ','; + // Find ToolChain for this input. Action::OffloadKind CurKind = Action::OFK_Host; const ToolChain *CurTC = &getToolChain(); const Action *CurDep = JA.getInputs()[I]; if (const auto *OA = dyn_cast<OffloadAction>(CurDep)) { + CurTC = nullptr; OA->doOnEachDependence([&](Action *A, const ToolChain *TC, const char *) { + assert(CurTC == nullptr && "Expected one dependence!"); CurKind = A->getOffloadingDeviceKind(); CurTC = TC; }); @@ -5202,7 +5392,17 @@ void OffloadBundler::ConstructJob(Compilation &C, const JobAction &JA, for (unsigned I = 0; I < Inputs.size(); ++I) { if (I) UB += ','; - UB += Inputs[I].getFilename(); + + // Find ToolChain for this input. + const ToolChain *CurTC = &getToolChain(); + if (const auto *OA = dyn_cast<OffloadAction>(JA.getInputs()[I])) { + CurTC = nullptr; + OA->doOnEachDependence([&](Action *, const ToolChain *TC, const char *) { + assert(CurTC == nullptr && "Expected one dependence!"); + CurTC = TC; + }); + } + UB += CurTC->getInputFilename(Inputs[I]); } CmdArgs.push_back(TCArgs.MakeArgString(UB)); @@ -5262,7 +5462,7 @@ void OffloadBundler::ConstructJobMultipleOutputs( for (unsigned I = 0; I < Outputs.size(); ++I) { if (I) UB += ','; - UB += Outputs[I].getFilename(); + UB += DepInfo[I].DependentToolChain->getInputFilename(Outputs[I]); } CmdArgs.push_back(TCArgs.MakeArgString(UB)); CmdArgs.push_back("-unbundle"); diff --git a/lib/Driver/ToolChains/Clang.h b/lib/Driver/ToolChains/Clang.h index d53c3b4413c8..e23822b9c678 100644 --- a/lib/Driver/ToolChains/Clang.h +++ b/lib/Driver/ToolChains/Clang.h @@ -42,6 +42,10 @@ private: const InputInfo &Output, const InputInfoList &Inputs) const; + void RenderTargetOptions(const llvm::Triple &EffectiveTriple, + const llvm::opt::ArgList &Args, bool KernelOrKext, + llvm::opt::ArgStringList &CmdArgs) const; + void AddAArch64TargetArgs(const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs) const; void AddARMTargetArgs(const llvm::Triple &Triple, diff --git a/lib/Driver/ToolChains/CloudABI.cpp b/lib/Driver/ToolChains/CloudABI.cpp index 0f6c712c5d28..cdf807f7f91f 100644 --- a/lib/Driver/ToolChains/CloudABI.cpp +++ b/lib/Driver/ToolChains/CloudABI.cpp @@ -80,9 +80,9 @@ void cloudabi::Linker::ConstructJob(Compilation &C, const JobAction &JA, AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA); + if (ToolChain.ShouldLinkCXXStdlib(Args)) + ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs); if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { - if (D.CCCIsCXX()) - ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs); CmdArgs.push_back("-lc"); CmdArgs.push_back("-lcompiler_rt"); } diff --git a/lib/Driver/ToolChains/CommonArgs.cpp b/lib/Driver/ToolChains/CommonArgs.cpp index 00bd60bc24bb..ab51a8c3cc90 100644 --- a/lib/Driver/ToolChains/CommonArgs.cpp +++ b/lib/Driver/ToolChains/CommonArgs.cpp @@ -320,6 +320,8 @@ std::string tools::getCPUName(const ArgList &Args, const llvm::Triple &T, return TargetCPUName; } + case llvm::Triple::bpfel: + case llvm::Triple::bpfeb: case llvm::Triple::sparc: case llvm::Triple::sparcel: case llvm::Triple::sparcv9: @@ -376,8 +378,20 @@ void tools::AddGoldPlugin(const ToolChain &ToolChain, const ArgList &Args, // as gold requires -plugin to come before any -plugin-opt that -Wl might // forward. CmdArgs.push_back("-plugin"); - std::string Plugin = - ToolChain.getDriver().Dir + "/../lib" CLANG_LIBDIR_SUFFIX "/LLVMgold.so"; + +#if defined(LLVM_ON_WIN32) + const char *Suffix = ".dll"; +#elif defined(__APPLE__) + const char *Suffix = ".dylib"; +#else + const char *Suffix = ".so"; +#endif + + SmallString<1024> Plugin; + llvm::sys::path::native(Twine(ToolChain.getDriver().Dir) + + "/../lib" CLANG_LIBDIR_SUFFIX "/LLVMgold" + + Suffix, + Plugin); CmdArgs.push_back(Args.MakeArgString(Plugin)); // Try to pass driver level flags relevant to LTO code generation down to @@ -440,6 +454,14 @@ void tools::AddGoldPlugin(const ToolChain &ToolChain, const ArgList &Args, CmdArgs.push_back( Args.MakeArgString(Twine("-plugin-opt=sample-profile=") + FName)); } + + // Need this flag to turn on new pass manager via Gold plugin. + if (Args.hasFlag(options::OPT_fexperimental_new_pass_manager, + options::OPT_fno_experimental_new_pass_manager, + /* Default */ false)) { + CmdArgs.push_back("-plugin-opt=new-pass-manager"); + } + } void tools::addArchSpecificRPath(const ToolChain &TC, const ArgList &Args, @@ -522,7 +544,7 @@ void tools::linkSanitizerRuntimeDeps(const ToolChain &TC, CmdArgs.push_back("-lrt"); } CmdArgs.push_back("-lm"); - // There's no libdl on FreeBSD or RTEMS. + // There's no libdl on all OSes. if (TC.getTriple().getOS() != llvm::Triple::FreeBSD && TC.getTriple().getOS() != llvm::Triple::NetBSD && TC.getTriple().getOS() != llvm::Triple::RTEMS) @@ -538,26 +560,44 @@ collectSanitizerRuntimes(const ToolChain &TC, const ArgList &Args, SmallVectorImpl<StringRef> &RequiredSymbols) { const SanitizerArgs &SanArgs = TC.getSanitizerArgs(); // Collect shared runtimes. - if (SanArgs.needsAsanRt() && SanArgs.needsSharedAsanRt()) { - SharedRuntimes.push_back("asan"); + if (SanArgs.needsSharedRt()) { + if (SanArgs.needsAsanRt()) { + SharedRuntimes.push_back("asan"); + if (!Args.hasArg(options::OPT_shared) && !TC.getTriple().isAndroid()) + HelperStaticRuntimes.push_back("asan-preinit"); + } + if (SanArgs.needsUbsanRt()) { + if (SanArgs.requiresMinimalRuntime()) { + SharedRuntimes.push_back("ubsan_minimal"); + } else { + SharedRuntimes.push_back("ubsan_standalone"); + } + } + if (SanArgs.needsScudoRt()) + SharedRuntimes.push_back("scudo"); + if (SanArgs.needsHwasanRt()) + SharedRuntimes.push_back("hwasan"); } + // The stats_client library is also statically linked into DSOs. if (SanArgs.needsStatsRt()) StaticRuntimes.push_back("stats_client"); // Collect static runtimes. - if (Args.hasArg(options::OPT_shared) || TC.getTriple().isAndroid()) { - // Don't link static runtimes into DSOs or if compiling for Android. + if (Args.hasArg(options::OPT_shared) || SanArgs.needsSharedRt()) { + // Don't link static runtimes into DSOs or if -shared-libasan. return; } if (SanArgs.needsAsanRt()) { - if (SanArgs.needsSharedAsanRt()) { - HelperStaticRuntimes.push_back("asan-preinit"); - } else { - StaticRuntimes.push_back("asan"); - if (SanArgs.linkCXXRuntimes()) - StaticRuntimes.push_back("asan_cxx"); - } + StaticRuntimes.push_back("asan"); + if (SanArgs.linkCXXRuntimes()) + StaticRuntimes.push_back("asan_cxx"); + } + + if (SanArgs.needsHwasanRt()) { + StaticRuntimes.push_back("hwasan"); + if (SanArgs.linkCXXRuntimes()) + StaticRuntimes.push_back("hwasan_cxx"); } if (SanArgs.needsDfsanRt()) StaticRuntimes.push_back("dfsan"); @@ -574,9 +614,13 @@ collectSanitizerRuntimes(const ToolChain &TC, const ArgList &Args, StaticRuntimes.push_back("tsan_cxx"); } if (SanArgs.needsUbsanRt()) { - StaticRuntimes.push_back("ubsan_standalone"); - if (SanArgs.linkCXXRuntimes()) - StaticRuntimes.push_back("ubsan_standalone_cxx"); + if (SanArgs.requiresMinimalRuntime()) { + StaticRuntimes.push_back("ubsan_minimal"); + } else { + StaticRuntimes.push_back("ubsan_standalone"); + if (SanArgs.linkCXXRuntimes()) + StaticRuntimes.push_back("ubsan_standalone_cxx"); + } } if (SanArgs.needsSafeStackRt()) { NonWholeStaticRuntimes.push_back("safestack"); @@ -595,19 +639,13 @@ collectSanitizerRuntimes(const ToolChain &TC, const ArgList &Args, } if (SanArgs.needsEsanRt()) StaticRuntimes.push_back("esan"); + if (SanArgs.needsScudoRt()) { + StaticRuntimes.push_back("scudo"); + if (SanArgs.linkCXXRuntimes()) + StaticRuntimes.push_back("scudo_cxx"); + } } -static void addLibFuzzerRuntime(const ToolChain &TC, - const ArgList &Args, - ArgStringList &CmdArgs) { - StringRef ParentDir = llvm::sys::path::parent_path(TC.getDriver().InstalledDir); - SmallString<128> P(ParentDir); - llvm::sys::path::append(P, "lib", "libLLVMFuzzer.a"); - CmdArgs.push_back(Args.MakeArgString(P)); - TC.AddCXXStdlibLibArgs(Args, CmdArgs); -} - - // Should be called before we add system libraries (C++ ABI, libstdc++/libc++, // C runtime, etc). Returns true if sanitizer system deps need to be linked in. bool tools::addSanitizerRuntimes(const ToolChain &TC, const ArgList &Args, @@ -617,10 +655,14 @@ bool tools::addSanitizerRuntimes(const ToolChain &TC, const ArgList &Args, collectSanitizerRuntimes(TC, Args, SharedRuntimes, StaticRuntimes, NonWholeStaticRuntimes, HelperStaticRuntimes, RequiredSymbols); + // Inject libfuzzer dependencies. if (TC.getSanitizerArgs().needsFuzzer() && !Args.hasArg(options::OPT_shared)) { - addLibFuzzerRuntime(TC, Args, CmdArgs); + + addSanitizerRuntime(TC, Args, CmdArgs, "fuzzer", false, true); + if (!Args.hasArg(clang::driver::options::OPT_nostdlibxx)) + TC.AddCXXStdlibLibArgs(Args, CmdArgs); } for (auto RT : SharedRuntimes) @@ -691,7 +733,8 @@ void tools::SplitDebugInfo(const ToolChain &TC, Compilation &C, const Tool &T, ExtractArgs.push_back(Output.getFilename()); ExtractArgs.push_back(OutFile); - const char *Exec = Args.MakeArgString(TC.GetProgramPath("objcopy")); + const char *Exec = + Args.MakeArgString(TC.GetProgramPath(CLANG_DEFAULT_OBJCOPY)); InputInfo II(types::TY_Object, Output.getFilename(), Output.getFilename()); // First extract the dwo sections. @@ -999,15 +1042,7 @@ void tools::AddRunTimeLibs(const ToolChain &TC, const Driver &D, switch (RLT) { case ToolChain::RLT_CompilerRT: - switch (TC.getTriple().getOS()) { - default: - llvm_unreachable("unsupported OS"); - case llvm::Triple::Win32: - case llvm::Triple::Linux: - case llvm::Triple::Fuchsia: - CmdArgs.push_back(TC.getCompilerRTArgString(Args, "builtins")); - break; - } + CmdArgs.push_back(TC.getCompilerRTArgString(Args, "builtins")); break; case ToolChain::RLT_Libgcc: // Make sure libgcc is not used under MSVC environment by default @@ -1023,3 +1058,128 @@ void tools::AddRunTimeLibs(const ToolChain &TC, const Driver &D, break; } } + +/// 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. +void tools::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"; + + // Put each target binary into a separate section. + for (const auto &BI : InputBinaryInfo) { + LksStream << " .omp_offloading." << BI.first << " :\n"; + LksStream << " ALIGN(0x10)\n"; + LksStream << " {\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; +} diff --git a/lib/Driver/ToolChains/CommonArgs.h b/lib/Driver/ToolChains/CommonArgs.h index fdeb6669b0a8..012f5b9f87ae 100644 --- a/lib/Driver/ToolChains/CommonArgs.h +++ b/lib/Driver/ToolChains/CommonArgs.h @@ -39,6 +39,13 @@ void AddRunTimeLibs(const ToolChain &TC, const Driver &D, llvm::opt::ArgStringList &CmdArgs, const llvm::opt::ArgList &Args); +void AddOpenMPLinkerScript(const ToolChain &TC, Compilation &C, + const InputInfo &Output, + const InputInfoList &Inputs, + const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs, + const JobAction &JA); + const char *SplitDebugName(const llvm::opt::ArgList &Args, const InputInfo &Input); diff --git a/lib/Driver/ToolChains/CrossWindows.cpp b/lib/Driver/ToolChains/CrossWindows.cpp index 04b71c48cd4c..5049033c4137 100644 --- a/lib/Driver/ToolChains/CrossWindows.cpp +++ b/lib/Driver/ToolChains/CrossWindows.cpp @@ -36,6 +36,7 @@ void tools::CrossWindows::Assembler::ConstructJob( llvm_unreachable("unsupported architecture"); case llvm::Triple::arm: case llvm::Triple::thumb: + case llvm::Triple::aarch64: break; case llvm::Triple::x86: CmdArgs.push_back("--32"); @@ -98,6 +99,9 @@ void tools::CrossWindows::Linker::ConstructJob( // FIXME: this is incorrect for WinCE CmdArgs.push_back("thumb2pe"); break; + case llvm::Triple::aarch64: + CmdArgs.push_back("arm64pe"); + break; case llvm::Triple::x86: CmdArgs.push_back("i386pe"); EntryPoint.append("_"); @@ -111,6 +115,7 @@ void tools::CrossWindows::Linker::ConstructJob( switch (T.getArch()) { default: llvm_unreachable("unsupported architecture"); + case llvm::Triple::aarch64: case llvm::Triple::arm: case llvm::Triple::thumb: case llvm::Triple::x86_64: @@ -160,8 +165,7 @@ void tools::CrossWindows::Linker::ConstructJob( TC.AddFilePathLibArgs(Args, CmdArgs); AddLinkerInputs(TC, Inputs, Args, CmdArgs, JA); - if (D.CCCIsCXX() && !Args.hasArg(options::OPT_nostdlib) && - !Args.hasArg(options::OPT_nodefaultlibs)) { + if (TC.ShouldLinkCXXStdlib(Args)) { bool StaticCXX = Args.hasArg(options::OPT_static_libstdcxx) && !Args.hasArg(options::OPT_static); if (StaticCXX) @@ -203,16 +207,7 @@ void tools::CrossWindows::Linker::ConstructJob( CrossWindowsToolChain::CrossWindowsToolChain(const Driver &D, const llvm::Triple &T, const llvm::opt::ArgList &Args) - : Generic_GCC(D, T, Args) { - if (D.CCCIsCXX() && GetCXXStdlibType(Args) == ToolChain::CST_Libstdcxx) { - const std::string &SysRoot = D.SysRoot; - - // libstdc++ resides in /usr/lib, but depends on libgcc which is placed in - // /usr/lib/gcc. - getFilePaths().push_back(SysRoot + "/usr/lib"); - getFilePaths().push_back(SysRoot + "/usr/lib/gcc"); - } -} + : Generic_GCC(D, T, Args) {} bool CrossWindowsToolChain::IsUnwindTablesDefault(const ArgList &Args) const { // FIXME: all non-x86 targets need unwind tables, however, LLVM currently does @@ -261,43 +256,21 @@ AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, void CrossWindowsToolChain:: AddClangCXXStdlibIncludeArgs(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const { - const llvm::Triple &Triple = getTriple(); const std::string &SysRoot = getDriver().SysRoot; if (DriverArgs.hasArg(options::OPT_nostdinc) || DriverArgs.hasArg(options::OPT_nostdincxx)) return; - switch (GetCXXStdlibType(DriverArgs)) { - case ToolChain::CST_Libcxx: + if (GetCXXStdlibType(DriverArgs) == ToolChain::CST_Libcxx) addSystemInclude(DriverArgs, CC1Args, SysRoot + "/usr/include/c++/v1"); - break; - - case ToolChain::CST_Libstdcxx: - addSystemInclude(DriverArgs, CC1Args, SysRoot + "/usr/include/c++"); - addSystemInclude(DriverArgs, CC1Args, - SysRoot + "/usr/include/c++/" + Triple.str()); - addSystemInclude(DriverArgs, CC1Args, - SysRoot + "/usr/include/c++/backwards"); - } } void CrossWindowsToolChain:: AddCXXStdlibLibArgs(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const { - switch (GetCXXStdlibType(DriverArgs)) { - case ToolChain::CST_Libcxx: + if (GetCXXStdlibType(DriverArgs) == ToolChain::CST_Libcxx) CC1Args.push_back("-lc++"); - break; - case ToolChain::CST_Libstdcxx: - CC1Args.push_back("-lstdc++"); - CC1Args.push_back("-lmingw32"); - CC1Args.push_back("-lmingwex"); - CC1Args.push_back("-lgcc"); - CC1Args.push_back("-lmoldname"); - CC1Args.push_back("-lmingw32"); - break; - } } clang::SanitizerMask CrossWindowsToolChain::getSupportedSanitizers() const { diff --git a/lib/Driver/ToolChains/Cuda.cpp b/lib/Driver/ToolChains/Cuda.cpp index 935a5a37ada5..bc4820797b2f 100644 --- a/lib/Driver/ToolChains/Cuda.cpp +++ b/lib/Driver/ToolChains/Cuda.cpp @@ -9,8 +9,11 @@ #include "Cuda.h" #include "InputInfo.h" +#include "CommonArgs.h" #include "clang/Basic/Cuda.h" +#include "clang/Config/config.h" #include "clang/Basic/VirtualFileSystem.h" +#include "clang/Driver/Distro.h" #include "clang/Driver/Compilation.h" #include "clang/Driver/Driver.h" #include "clang/Driver/DriverDiagnostic.h" @@ -47,6 +50,8 @@ static CudaVersion ParseCudaVersionFile(llvm::StringRef V) { return CudaVersion::CUDA_75; if (Major == 8 && Minor == 0) return CudaVersion::CUDA_80; + if (Major == 9 && Minor == 0) + return CudaVersion::CUDA_90; return CudaVersion::UNKNOWN; } @@ -71,6 +76,11 @@ CudaInstallationDetector::CudaInstallationDetector( CudaPathCandidates.push_back(D.SysRoot + "/usr/local/cuda"); for (const char *Ver : Versions) CudaPathCandidates.push_back(D.SysRoot + "/usr/local/cuda-" + Ver); + + if (Distro(D.getVFS()).IsDebian()) + // Special case for Debian to have nvidia-cuda-toolkit work + // out of the box. More info on http://bugs.debian.org/882505 + CudaPathCandidates.push_back(D.SysRoot + "/usr/lib/cuda"); } for (const auto &CudaPath : CudaPathCandidates) { @@ -83,8 +93,7 @@ CudaInstallationDetector::CudaInstallationDetector( LibDevicePath = InstallPath + "/nvvm/libdevice"; auto &FS = D.getVFS(); - if (!(FS.exists(IncludePath) && FS.exists(BinPath) && - FS.exists(LibDevicePath))) + if (!(FS.exists(IncludePath) && FS.exists(BinPath))) continue; // On Linux, we have both lib and lib64 directories, and we need to choose @@ -110,47 +119,64 @@ CudaInstallationDetector::CudaInstallationDetector( Version = ParseCudaVersionFile((*VersionFile)->getBuffer()); } - std::error_code EC; - for (llvm::sys::fs::directory_iterator LI(LibDevicePath, EC), LE; - !EC && LI != LE; LI = LI.increment(EC)) { - StringRef FilePath = LI->path(); - StringRef FileName = llvm::sys::path::filename(FilePath); - // Process all bitcode filenames that look like libdevice.compute_XX.YY.bc - const StringRef LibDeviceName = "libdevice."; - if (!(FileName.startswith(LibDeviceName) && FileName.endswith(".bc"))) - continue; - StringRef GpuArch = FileName.slice( - LibDeviceName.size(), FileName.find('.', LibDeviceName.size())); - LibDeviceMap[GpuArch] = FilePath.str(); - // Insert map entries for specifc devices with this compute - // capability. NVCC's choice of the libdevice library version is - // rather peculiar and depends on the CUDA version. - if (GpuArch == "compute_20") { - LibDeviceMap["sm_20"] = FilePath; - LibDeviceMap["sm_21"] = FilePath; - LibDeviceMap["sm_32"] = FilePath; - } else if (GpuArch == "compute_30") { - LibDeviceMap["sm_30"] = FilePath; - if (Version < CudaVersion::CUDA_80) { - LibDeviceMap["sm_50"] = FilePath; - LibDeviceMap["sm_52"] = FilePath; - LibDeviceMap["sm_53"] = FilePath; - } - LibDeviceMap["sm_60"] = FilePath; - LibDeviceMap["sm_61"] = FilePath; - LibDeviceMap["sm_62"] = FilePath; - } else if (GpuArch == "compute_35") { - LibDeviceMap["sm_35"] = FilePath; - LibDeviceMap["sm_37"] = FilePath; - } else if (GpuArch == "compute_50") { - if (Version >= CudaVersion::CUDA_80) { - LibDeviceMap["sm_50"] = FilePath; - LibDeviceMap["sm_52"] = FilePath; - LibDeviceMap["sm_53"] = FilePath; + if (Version == CudaVersion::CUDA_90) { + // CUDA-9 uses single libdevice file for all GPU variants. + std::string FilePath = LibDevicePath + "/libdevice.10.bc"; + if (FS.exists(FilePath)) { + for (const char *GpuArch : + {"sm_20", "sm_30", "sm_32", "sm_35", "sm_50", "sm_52", "sm_53", + "sm_60", "sm_61", "sm_62", "sm_70"}) + LibDeviceMap[GpuArch] = FilePath; + } + } else { + std::error_code EC; + for (llvm::sys::fs::directory_iterator LI(LibDevicePath, EC), LE; + !EC && LI != LE; LI = LI.increment(EC)) { + StringRef FilePath = LI->path(); + StringRef FileName = llvm::sys::path::filename(FilePath); + // Process all bitcode filenames that look like + // libdevice.compute_XX.YY.bc + const StringRef LibDeviceName = "libdevice."; + if (!(FileName.startswith(LibDeviceName) && FileName.endswith(".bc"))) + continue; + StringRef GpuArch = FileName.slice( + LibDeviceName.size(), FileName.find('.', LibDeviceName.size())); + LibDeviceMap[GpuArch] = FilePath.str(); + // Insert map entries for specifc devices with this compute + // capability. NVCC's choice of the libdevice library version is + // rather peculiar and depends on the CUDA version. + if (GpuArch == "compute_20") { + LibDeviceMap["sm_20"] = FilePath; + LibDeviceMap["sm_21"] = FilePath; + LibDeviceMap["sm_32"] = FilePath; + } else if (GpuArch == "compute_30") { + LibDeviceMap["sm_30"] = FilePath; + if (Version < CudaVersion::CUDA_80) { + LibDeviceMap["sm_50"] = FilePath; + LibDeviceMap["sm_52"] = FilePath; + LibDeviceMap["sm_53"] = FilePath; + } + LibDeviceMap["sm_60"] = FilePath; + LibDeviceMap["sm_61"] = FilePath; + LibDeviceMap["sm_62"] = FilePath; + } else if (GpuArch == "compute_35") { + LibDeviceMap["sm_35"] = FilePath; + LibDeviceMap["sm_37"] = FilePath; + } else if (GpuArch == "compute_50") { + if (Version >= CudaVersion::CUDA_80) { + LibDeviceMap["sm_50"] = FilePath; + LibDeviceMap["sm_52"] = FilePath; + LibDeviceMap["sm_53"] = FilePath; + } } } } + // Check that we have found at least one libdevice that we can link in if + // -nocudalib hasn't been specified. + if (LibDeviceMap.empty() && !Args.hasArg(options::OPT_nocudalib)) + continue; + IsValid = true; break; } @@ -185,15 +211,17 @@ void CudaInstallationDetector::AddCudaIncludeArgs( void CudaInstallationDetector::CheckCudaVersionSupportsArch( CudaArch Arch) const { if (Arch == CudaArch::UNKNOWN || Version == CudaVersion::UNKNOWN || - ArchsWithVersionTooLowErrors.count(Arch) > 0) + ArchsWithBadVersion.count(Arch) > 0) return; - auto RequiredVersion = MinVersionForCudaArch(Arch); - if (Version < RequiredVersion) { - ArchsWithVersionTooLowErrors.insert(Arch); - D.Diag(diag::err_drv_cuda_version_too_low) - << InstallPath << CudaArchToString(Arch) << CudaVersionToString(Version) - << CudaVersionToString(RequiredVersion); + auto MinVersion = MinVersionForCudaArch(Arch); + auto MaxVersion = MaxVersionForCudaArch(Arch); + if (Version < MinVersion || Version > MaxVersion) { + ArchsWithBadVersion.insert(Arch); + D.Diag(diag::err_drv_cuda_version_unsupported) + << CudaArchToString(Arch) << CudaVersionToString(MinVersion) + << CudaVersionToString(MaxVersion) << InstallPath + << CudaVersionToString(Version); } } @@ -212,8 +240,18 @@ void NVPTX::Assembler::ConstructJob(Compilation &C, const JobAction &JA, static_cast<const toolchains::CudaToolChain &>(getToolChain()); assert(TC.getTriple().isNVPTX() && "Wrong platform"); + StringRef GPUArchName; + // If this is an OpenMP action we need to extract the device architecture + // from the -march=arch option. This option may come from -Xopenmp-target + // flag or the default value. + if (JA.isDeviceOffloading(Action::OFK_OpenMP)) { + GPUArchName = Args.getLastArgValue(options::OPT_march_EQ); + assert(!GPUArchName.empty() && "Must have an architecture passed in."); + } else + GPUArchName = JA.getOffloadingArch(); + // Obtain architecture from the action. - CudaArch gpu_arch = StringToCudaArch(JA.getOffloadingArch()); + CudaArch gpu_arch = StringToCudaArch(GPUArchName); assert(gpu_arch != CudaArch::UNKNOWN && "Device action expected to have an architecture."); @@ -262,16 +300,27 @@ void NVPTX::Assembler::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-O0"); } + // Pass -v to ptxas if it was passed to the driver. + if (Args.hasArg(options::OPT_v)) + CmdArgs.push_back("-v"); + CmdArgs.push_back("--gpu-name"); CmdArgs.push_back(Args.MakeArgString(CudaArchToString(gpu_arch))); CmdArgs.push_back("--output-file"); - CmdArgs.push_back(Args.MakeArgString(Output.getFilename())); + CmdArgs.push_back(Args.MakeArgString(TC.getInputFilename(Output))); for (const auto& II : Inputs) CmdArgs.push_back(Args.MakeArgString(II.getFilename())); for (const auto& A : Args.getAllArgValues(options::OPT_Xcuda_ptxas)) CmdArgs.push_back(Args.MakeArgString(A)); + // In OpenMP we need to generate relocatable code. + if (JA.isOffloading(Action::OFK_OpenMP) && + Args.hasFlag(options::OPT_fopenmp_relocatable_target, + options::OPT_fnoopenmp_relocatable_target, + /*Default=*/ true)) + CmdArgs.push_back("-c"); + const char *Exec; if (Arg *A = Args.getLastArg(options::OPT_ptxas_path_EQ)) Exec = A->getValue(); @@ -324,16 +373,108 @@ void NVPTX::Linker::ConstructJob(Compilation &C, const JobAction &JA, C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); } +void NVPTX::OpenMPLinker::ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, + const InputInfoList &Inputs, + const ArgList &Args, + const char *LinkingOutput) const { + const auto &TC = + static_cast<const toolchains::CudaToolChain &>(getToolChain()); + assert(TC.getTriple().isNVPTX() && "Wrong platform"); + + ArgStringList CmdArgs; + + // OpenMP uses nvlink to link cubin files. The result will be embedded in the + // host binary by the host linker. + assert(!JA.isHostOffloading(Action::OFK_OpenMP) && + "CUDA toolchain not expected for an OpenMP host device."); + + if (Output.isFilename()) { + CmdArgs.push_back("-o"); + CmdArgs.push_back(Output.getFilename()); + } else + assert(Output.isNothing() && "Invalid output."); + if (Args.hasArg(options::OPT_g_Flag)) + CmdArgs.push_back("-g"); + + if (Args.hasArg(options::OPT_v)) + CmdArgs.push_back("-v"); + + StringRef GPUArch = + Args.getLastArgValue(options::OPT_march_EQ); + assert(!GPUArch.empty() && "At least one GPU Arch required for ptxas."); + + CmdArgs.push_back("-arch"); + CmdArgs.push_back(Args.MakeArgString(GPUArch)); + + // Add paths specified in LIBRARY_PATH environment variable as -L options. + addDirectoryList(Args, CmdArgs, "-L", "LIBRARY_PATH"); + + // Add paths for the default clang library path. + SmallString<256> DefaultLibPath = + llvm::sys::path::parent_path(TC.getDriver().Dir); + llvm::sys::path::append(DefaultLibPath, "lib" CLANG_LIBDIR_SUFFIX); + CmdArgs.push_back(Args.MakeArgString(Twine("-L") + DefaultLibPath)); + + // Add linking against library implementing OpenMP calls on NVPTX target. + CmdArgs.push_back("-lomptarget-nvptx"); + + for (const auto &II : Inputs) { + if (II.getType() == types::TY_LLVM_IR || + II.getType() == types::TY_LTO_IR || + II.getType() == types::TY_LTO_BC || + II.getType() == types::TY_LLVM_BC) { + C.getDriver().Diag(diag::err_drv_no_linker_llvm_support) + << getToolChain().getTripleString(); + continue; + } + + // Currently, we only pass the input files to the linker, we do not pass + // any libraries that may be valid only for the host. + if (!II.isFilename()) + continue; + + const char *CubinF = C.addTempFile( + C.getArgs().MakeArgString(getToolChain().getInputFilename(II))); + + CmdArgs.push_back(CubinF); + } + + AddOpenMPLinkerScript(getToolChain(), C, Output, Inputs, Args, CmdArgs, JA); + + const char *Exec = + Args.MakeArgString(getToolChain().GetProgramPath("nvlink")); + C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); +} + /// CUDA toolchain. Our assembler is ptxas, and our "linker" is fatbinary, /// which isn't properly a linker but nonetheless performs the step of stitching /// together object files from the assembler into a single blob. CudaToolChain::CudaToolChain(const Driver &D, const llvm::Triple &Triple, - const ToolChain &HostTC, const ArgList &Args) + const ToolChain &HostTC, const ArgList &Args, + const Action::OffloadKind OK) : ToolChain(D, Triple, Args), HostTC(HostTC), - CudaInstallation(D, HostTC.getTriple(), Args) { + CudaInstallation(D, HostTC.getTriple(), Args), OK(OK) { if (CudaInstallation.isValid()) getProgramPaths().push_back(CudaInstallation.getBinPath()); + // Lookup binaries into the driver directory, this is used to + // discover the clang-offload-bundler executable. + getProgramPaths().push_back(getDriver().Dir); +} + +std::string CudaToolChain::getInputFilename(const InputInfo &Input) const { + // Only object files are changed, for example assembly files keep their .s + // extensions. CUDA also continues to use .o as they don't use nvlink but + // fatbinary. + if (!(OK == Action::OFK_OpenMP && Input.getType() == types::TY_Object)) + return ToolChain::getInputFilename(Input); + + // Replace extension for object files with cubin because nvlink relies on + // these particular file names. + SmallString<256> Filename(ToolChain::getInputFilename(Input)); + llvm::sys::path::replace_extension(Filename, "cubin"); + return Filename.str(); } void CudaToolChain::addClangTargetOptions( @@ -358,14 +499,18 @@ void CudaToolChain::addClangTargetOptions( if (DriverArgs.hasFlag(options::OPT_fcuda_approx_transcendentals, options::OPT_fno_cuda_approx_transcendentals, false)) CC1Args.push_back("-fcuda-approx-transcendentals"); - - if (DriverArgs.hasArg(options::OPT_nocudalib)) - return; } + if (DriverArgs.hasArg(options::OPT_nocudalib)) + return; + std::string LibDeviceFile = CudaInstallation.getLibDeviceFile(GpuArch); if (LibDeviceFile.empty()) { + if (DeviceOffloadingKind == Action::OFK_OpenMP && + DriverArgs.hasArg(options::OPT_S)) + return; + getDriver().Diag(diag::err_drv_no_cuda_libdevice) << GpuArch; return; } @@ -373,11 +518,17 @@ void CudaToolChain::addClangTargetOptions( CC1Args.push_back("-mlink-cuda-bitcode"); CC1Args.push_back(DriverArgs.MakeArgString(LibDeviceFile)); - // Libdevice in CUDA-7.0 requires PTX version that's more recent - // than LLVM defaults to. Use PTX4.2 which is the PTX version that - // came with CUDA-7.0. - CC1Args.push_back("-target-feature"); - CC1Args.push_back("+ptx42"); + if (CudaInstallation.version() >= CudaVersion::CUDA_90) { + // CUDA-9 uses new instructions that are only available in PTX6.0 + CC1Args.push_back("-target-feature"); + CC1Args.push_back("+ptx60"); + } else { + // Libdevice in CUDA-7.0 requires PTX version that's more recent + // than LLVM defaults to. Use PTX4.2 which is the PTX version that + // came with CUDA-7.0. + CC1Args.push_back("-target-feature"); + CC1Args.push_back("+ptx42"); + } } void CudaToolChain::AddCudaIncludeArgs(const ArgList &DriverArgs, @@ -405,11 +556,11 @@ CudaToolChain::TranslateArgs(const llvm::opt::DerivedArgList &Args, // For OpenMP device offloading, append derived arguments. Make sure // flags are not duplicated. - // TODO: Append the compute capability. + // Also append the compute capability. if (DeviceOffloadKind == Action::OFK_OpenMP) { - for (Arg *A : Args){ + for (Arg *A : Args) { bool IsDuplicate = false; - for (Arg *DALArg : *DAL){ + for (Arg *DALArg : *DAL) { if (A == DALArg) { IsDuplicate = true; break; @@ -418,6 +569,12 @@ CudaToolChain::TranslateArgs(const llvm::opt::DerivedArgList &Args, if (!IsDuplicate) DAL->append(A); } + + StringRef Arch = DAL->getLastArgValue(options::OPT_march_EQ); + if (Arch.empty()) + DAL->AddJoinedArg(nullptr, Opts.getOption(options::OPT_march_EQ), + CLANG_OPENMP_NVPTX_DEFAULT_ARCH); + return DAL; } @@ -467,6 +624,8 @@ Tool *CudaToolChain::buildAssembler() const { } Tool *CudaToolChain::buildLinker() const { + if (OK == Action::OFK_OpenMP) + return new tools::NVPTX::OpenMPLinker(*this); return new tools::NVPTX::Linker(*this); } diff --git a/lib/Driver/ToolChains/Cuda.h b/lib/Driver/ToolChains/Cuda.h index e66fc23d82f3..3d08cec1643e 100644 --- a/lib/Driver/ToolChains/Cuda.h +++ b/lib/Driver/ToolChains/Cuda.h @@ -40,7 +40,7 @@ private: // CUDA architectures for which we have raised an error in // CheckCudaVersionSupportsArch. - mutable llvm::SmallSet<CudaArch, 4> ArchsWithVersionTooLowErrors; + mutable llvm::SmallSet<CudaArch, 4> ArchsWithBadVersion; public: CudaInstallationDetector(const Driver &D, const llvm::Triple &HostTriple, @@ -112,6 +112,20 @@ class LLVM_LIBRARY_VISIBILITY Linker : public Tool { const char *LinkingOutput) const override; }; +class LLVM_LIBRARY_VISIBILITY OpenMPLinker : public Tool { + public: + OpenMPLinker(const ToolChain &TC) + : Tool("NVPTX::OpenMPLinker", "fatbinary", TC, RF_Full, llvm::sys::WEM_UTF8, + "--options-file") {} + + bool hasIntegratedCPP() const override { return false; } + + void ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, const InputInfoList &Inputs, + const llvm::opt::ArgList &TCArgs, + const char *LinkingOutput) const override; +}; + } // end namespace NVPTX } // end namespace tools @@ -120,12 +134,15 @@ namespace toolchains { class LLVM_LIBRARY_VISIBILITY CudaToolChain : public ToolChain { public: CudaToolChain(const Driver &D, const llvm::Triple &Triple, - const ToolChain &HostTC, const llvm::opt::ArgList &Args); + const ToolChain &HostTC, const llvm::opt::ArgList &Args, + const Action::OffloadKind OK); - virtual const llvm::Triple *getAuxTriple() const override { + const llvm::Triple *getAuxTriple() const override { return &HostTC.getTriple(); } + std::string getInputFilename(const InputInfo &Input) const override; + llvm::opt::DerivedArgList * TranslateArgs(const llvm::opt::DerivedArgList &Args, StringRef BoundArch, Action::OffloadKind DeviceOffloadKind) const override; @@ -141,7 +158,7 @@ public: bool isPIEDefault() const override { return false; } bool isPICDefaultForced() const override { return false; } bool SupportsProfiling() const override { return false; } - bool SupportsObjCGC() const override { return false; } + bool IsMathErrnoDefault() const override { return false; } void AddCudaIncludeArgs(const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override; @@ -169,6 +186,9 @@ public: protected: Tool *buildAssembler() const override; // ptxas Tool *buildLinker() const override; // fatbinary (ok, not really a linker) + +private: + const Action::OffloadKind OK; }; } // end namespace toolchains diff --git a/lib/Driver/ToolChains/Darwin.cpp b/lib/Driver/ToolChains/Darwin.cpp index 32103a6120d4..28efa86538ed 100644 --- a/lib/Driver/ToolChains/Darwin.cpp +++ b/lib/Driver/ToolChains/Darwin.cpp @@ -10,6 +10,7 @@ #include "Darwin.h" #include "Arch/ARM.h" #include "CommonArgs.h" +#include "clang/Basic/AlignedAllocation.h" #include "clang/Basic/ObjCRuntime.h" #include "clang/Basic/VirtualFileSystem.h" #include "clang/Driver/Compilation.h" @@ -67,14 +68,14 @@ llvm::Triple::ArchType darwin::getArchTypeForMachOArchName(StringRef Str) { void darwin::setTripleTypeForMachOArchName(llvm::Triple &T, StringRef Str) { const llvm::Triple::ArchType Arch = getArchTypeForMachOArchName(Str); - unsigned ArchKind = llvm::ARM::parseArch(Str); + llvm::ARM::ArchKind ArchKind = llvm::ARM::parseArch(Str); T.setArch(Arch); if (Str == "x86_64h") T.setArchName(Str); - else if (ArchKind == llvm::ARM::AK_ARMV6M || - ArchKind == llvm::ARM::AK_ARMV7M || - ArchKind == llvm::ARM::AK_ARMV7EM) { + else if (ArchKind == llvm::ARM::ArchKind::ARMV6M || + ArchKind == llvm::ARM::ArchKind::ARMV7M || + ArchKind == llvm::ARM::ArchKind::ARMV7EM) { T.setOS(llvm::Triple::UnknownOS); T.setObjectFormat(llvm::Triple::MachO); } @@ -493,7 +494,7 @@ void darwin::Linker::ConstructJob(Compilation &C, const JobAction &JA, if (getToolChain().getSanitizerArgs().needsSafeStackRt()) { getMachOToolChain().AddLinkRuntimeLib(Args, CmdArgs, "libclang_rt.safestack_osx.a", - /*AlwaysLink=*/true); + toolchains::Darwin::RLO_AlwaysLink); } Args.AddAllArgs(CmdArgs, options::OPT_L); @@ -548,10 +549,9 @@ void darwin::Linker::ConstructJob(Compilation &C, const JobAction &JA, Args.MakeArgString(Twine("-threads=") + llvm::to_string(Parallelism))); } + if (getToolChain().ShouldLinkCXXStdlib(Args)) + getToolChain().AddCXXStdlibLibArgs(Args, CmdArgs); if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { - if (getToolChain().getDriver().CCCIsCXX()) - getToolChain().AddCXXStdlibLibArgs(Args, CmdArgs); - // link_ssp spec is empty. // Let the tool chain choose which runtime library to link. @@ -739,8 +739,8 @@ static const char *ArmMachOArchName(StringRef Arch) { } static const char *ArmMachOArchNameCPU(StringRef CPU) { - unsigned ArchKind = llvm::ARM::parseCPUArch(CPU); - if (ArchKind == llvm::ARM::AK_INVALID) + llvm::ARM::ArchKind ArchKind = llvm::ARM::parseCPUArch(CPU); + if (ArchKind == llvm::ARM::ArchKind::INVALID) return nullptr; StringRef Arch = llvm::ARM::getArchName(ArchKind); @@ -897,10 +897,11 @@ unsigned DarwinClang::GetDefaultDwarfVersion() const { } void MachO::AddLinkRuntimeLib(const ArgList &Args, ArgStringList &CmdArgs, - StringRef DarwinLibName, bool AlwaysLink, - bool IsEmbedded, bool AddRPath) const { + StringRef DarwinLibName, + RuntimeLinkOptions Opts) const { SmallString<128> Dir(getDriver().ResourceDir); - llvm::sys::path::append(Dir, "lib", IsEmbedded ? "macho_embedded" : "darwin"); + llvm::sys::path::append( + Dir, "lib", (Opts & RLO_IsEmbedded) ? "macho_embedded" : "darwin"); SmallString<128> P(Dir); llvm::sys::path::append(P, DarwinLibName); @@ -908,14 +909,19 @@ void MachO::AddLinkRuntimeLib(const ArgList &Args, ArgStringList &CmdArgs, // For now, allow missing resource libraries to support developers who may // not have compiler-rt checked out or integrated into their build (unless // we explicitly force linking with this library). - if (AlwaysLink || getVFS().exists(P)) - CmdArgs.push_back(Args.MakeArgString(P)); + if ((Opts & RLO_AlwaysLink) || getVFS().exists(P)) { + const char *LibArg = Args.MakeArgString(P); + if (Opts & RLO_FirstLink) + CmdArgs.insert(CmdArgs.begin(), LibArg); + else + CmdArgs.push_back(LibArg); + } // Adding the rpaths might negatively interact when other rpaths are involved, // so we should make sure we add the rpaths last, after all user-specified // rpaths. This is currently true from this place, but we need to be // careful if this function is ever called before user's rpaths are emitted. - if (AddRPath) { + if (Opts & RLO_AddRPath) { assert(DarwinLibName.endswith(".dylib") && "must be a dynamic library"); // Add @executable_path to rpath to support having the dylib copied with @@ -930,30 +936,15 @@ void MachO::AddLinkRuntimeLib(const ArgList &Args, ArgStringList &CmdArgs, } } -void MachO::AddFuzzerLinkArgs(const ArgList &Args, ArgStringList &CmdArgs) const { - - // Go up one directory from Clang to find the libfuzzer archive file. - StringRef ParentDir = llvm::sys::path::parent_path(getDriver().InstalledDir); - SmallString<128> P(ParentDir); - llvm::sys::path::append(P, "lib", "libLLVMFuzzer.a"); - CmdArgs.push_back(Args.MakeArgString(P)); - - // Libfuzzer is written in C++ and requires libcxx. - AddCXXStdlibLibArgs(Args, CmdArgs); -} - StringRef Darwin::getPlatformFamily() const { switch (TargetPlatform) { case DarwinPlatformKind::MacOS: return "MacOSX"; case DarwinPlatformKind::IPhoneOS: - case DarwinPlatformKind::IPhoneOSSimulator: return "iPhone"; case DarwinPlatformKind::TvOS: - case DarwinPlatformKind::TvOSSimulator: return "AppleTV"; case DarwinPlatformKind::WatchOS: - case DarwinPlatformKind::WatchOSSimulator: return "Watch"; } llvm_unreachable("Unsupported platform"); @@ -977,39 +968,65 @@ StringRef Darwin::getOSLibraryNameSuffix() const { case DarwinPlatformKind::MacOS: return "osx"; case DarwinPlatformKind::IPhoneOS: - return "ios"; - case DarwinPlatformKind::IPhoneOSSimulator: - return "iossim"; + return TargetEnvironment == NativeEnvironment ? "ios" : "iossim"; case DarwinPlatformKind::TvOS: - return "tvos"; - case DarwinPlatformKind::TvOSSimulator: - return "tvossim"; + return TargetEnvironment == NativeEnvironment ? "tvos" : "tvossim"; case DarwinPlatformKind::WatchOS: - return "watchos"; - case DarwinPlatformKind::WatchOSSimulator: - return "watchossim"; + return TargetEnvironment == NativeEnvironment ? "watchos" : "watchossim"; } llvm_unreachable("Unsupported platform"); } +/// Check if the link command contains a symbol export directive. +static bool hasExportSymbolDirective(const ArgList &Args) { + for (Arg *A : Args) { + if (!A->getOption().matches(options::OPT_Wl_COMMA) && + !A->getOption().matches(options::OPT_Xlinker)) + continue; + if (A->containsValue("-exported_symbols_list") || + A->containsValue("-exported_symbol")) + return true; + } + return false; +} + +/// Add an export directive for \p Symbol to the link command. +static void addExportedSymbol(ArgStringList &CmdArgs, const char *Symbol) { + CmdArgs.push_back("-exported_symbol"); + CmdArgs.push_back(Symbol); +} + void Darwin::addProfileRTLibs(const ArgList &Args, ArgStringList &CmdArgs) const { if (!needsProfileRT(Args)) return; - AddLinkRuntimeLib(Args, CmdArgs, (Twine("libclang_rt.profile_") + - getOSLibraryNameSuffix() + ".a").str(), - /*AlwaysLink*/ true); + AddLinkRuntimeLib( + Args, CmdArgs, + (Twine("libclang_rt.profile_") + getOSLibraryNameSuffix() + ".a").str(), + RuntimeLinkOptions(RLO_AlwaysLink | RLO_FirstLink)); + + // If we have a symbol export directive and we're linking in the profile + // runtime, automatically export symbols necessary to implement some of the + // runtime's functionality. + if (hasExportSymbolDirective(Args)) { + addExportedSymbol(CmdArgs, "_VPMergeHook"); + addExportedSymbol(CmdArgs, "___llvm_profile_filename"); + addExportedSymbol(CmdArgs, "___llvm_profile_raw_version"); + addExportedSymbol(CmdArgs, "_lprofCurFilename"); + } } void DarwinClang::AddLinkSanitizerLibArgs(const ArgList &Args, ArgStringList &CmdArgs, - StringRef Sanitizer) const { - AddLinkRuntimeLib( - Args, CmdArgs, - (Twine("libclang_rt.") + Sanitizer + "_" + - getOSLibraryNameSuffix() + "_dynamic.dylib").str(), - /*AlwaysLink*/ true, /*IsEmbedded*/ false, - /*AddRPath*/ true); + StringRef Sanitizer, + bool Shared) const { + auto RLO = RuntimeLinkOptions(RLO_AlwaysLink | (Shared ? RLO_AddRPath : 0U)); + AddLinkRuntimeLib(Args, CmdArgs, + (Twine("libclang_rt.") + Sanitizer + "_" + + getOSLibraryNameSuffix() + + (Shared ? "_dynamic.dylib" : ".a")) + .str(), + RLO); } ToolChain::RuntimeLibType DarwinClang::GetRuntimeLibType( @@ -1050,16 +1067,23 @@ void DarwinClang::AddLinkRuntimeLibArgs(const ArgList &Args, if (Sanitize.needsLsanRt()) AddLinkSanitizerLibArgs(Args, CmdArgs, "lsan"); if (Sanitize.needsUbsanRt()) - AddLinkSanitizerLibArgs(Args, CmdArgs, "ubsan"); + AddLinkSanitizerLibArgs(Args, CmdArgs, + Sanitize.requiresMinimalRuntime() ? "ubsan_minimal" + : "ubsan", + Sanitize.needsSharedRt()); if (Sanitize.needsTsanRt()) AddLinkSanitizerLibArgs(Args, CmdArgs, "tsan"); - if (Sanitize.needsFuzzer() && !Args.hasArg(options::OPT_dynamiclib)) - AddFuzzerLinkArgs(Args, CmdArgs); + if (Sanitize.needsFuzzer() && !Args.hasArg(options::OPT_dynamiclib)) { + AddLinkSanitizerLibArgs(Args, CmdArgs, "fuzzer", /*shared=*/false); + + // Libfuzzer is written in C++ and requires libcxx. + AddCXXStdlibLibArgs(Args, CmdArgs); + } if (Sanitize.needsStatsRt()) { StringRef OS = isTargetMacOS() ? "osx" : "iossim"; AddLinkRuntimeLib(Args, CmdArgs, (Twine("libclang_rt.stats_client_") + OS + ".a").str(), - /*AlwaysLink=*/true); + RLO_AlwaysLink); AddLinkSanitizerLibArgs(Args, CmdArgs, "stats"); } if (Sanitize.needsEsanRt()) @@ -1139,28 +1163,132 @@ static std::string getSystemOrSDKMacOSVersion(StringRef MacOSSDKVersion) { return MacOSSDKVersion; } -void Darwin::AddDeploymentTarget(DerivedArgList &Args) const { - const OptTable &Opts = getDriver().getOpts(); +namespace { + +/// The Darwin OS that was selected or inferred from arguments / environment. +struct DarwinPlatform { + enum SourceKind { + /// The OS was specified using the -target argument. + TargetArg, + /// The OS was specified using the -m<os>-version-min argument. + OSVersionArg, + /// The OS was specified using the OS_DEPLOYMENT_TARGET environment. + DeploymentTargetEnv, + /// The OS was inferred from the SDK. + InferredFromSDK, + /// The OS was inferred from the -arch. + InferredFromArch + }; + + using DarwinPlatformKind = Darwin::DarwinPlatformKind; + + DarwinPlatformKind getPlatform() const { return Platform; } + + StringRef getOSVersion() const { + if (Kind == OSVersionArg) + return Argument->getValue(); + return OSVersion; + } - // Support allowing the SDKROOT environment variable used by xcrun and other - // Xcode tools to define the default sysroot, by making it the default for - // isysroot. - if (const Arg *A = Args.getLastArg(options::OPT_isysroot)) { - // Warn if the path does not exist. - if (!getVFS().exists(A->getValue())) - getDriver().Diag(clang::diag::warn_missing_sysroot) << A->getValue(); - } else { - if (char *env = ::getenv("SDKROOT")) { - // We only use this value as the default if it is an absolute path, - // exists, and it is not the root path. - if (llvm::sys::path::is_absolute(env) && getVFS().exists(env) && - StringRef(env) != "/") { - Args.append(Args.MakeSeparateArg( - nullptr, Opts.getOption(options::OPT_isysroot), env)); - } + /// Returns true if the target OS was explicitly specified. + bool isExplicitlySpecified() const { return Kind <= DeploymentTargetEnv; } + + /// Adds the -m<os>-version-min argument to the compiler invocation. + void addOSVersionMinArgument(DerivedArgList &Args, const OptTable &Opts) { + if (Argument) + return; + assert(Kind != TargetArg && Kind != OSVersionArg && "Invalid kind"); + options::ID Opt; + switch (Platform) { + case DarwinPlatformKind::MacOS: + Opt = options::OPT_mmacosx_version_min_EQ; + break; + case DarwinPlatformKind::IPhoneOS: + Opt = options::OPT_miphoneos_version_min_EQ; + break; + case DarwinPlatformKind::TvOS: + Opt = options::OPT_mtvos_version_min_EQ; + break; + case DarwinPlatformKind::WatchOS: + Opt = options::OPT_mwatchos_version_min_EQ; + break; + } + Argument = Args.MakeJoinedArg(nullptr, Opts.getOption(Opt), OSVersion); + Args.append(Argument); + } + + /// Returns the OS version with the argument / environment variable that + /// specified it. + std::string getAsString(DerivedArgList &Args, const OptTable &Opts) { + switch (Kind) { + case TargetArg: + case OSVersionArg: + case InferredFromSDK: + case InferredFromArch: + assert(Argument && "OS version argument not yet inferred"); + return Argument->getAsString(Args); + case DeploymentTargetEnv: + return (llvm::Twine(EnvVarName) + "=" + OSVersion).str(); + } + llvm_unreachable("Unsupported Darwin Source Kind"); + } + + static DarwinPlatform createOSVersionArg(DarwinPlatformKind Platform, + Arg *A) { + return DarwinPlatform(OSVersionArg, Platform, A); + } + static DarwinPlatform createDeploymentTargetEnv(DarwinPlatformKind Platform, + StringRef EnvVarName, + StringRef Value) { + DarwinPlatform Result(DeploymentTargetEnv, Platform, Value); + Result.EnvVarName = EnvVarName; + return Result; + } + static DarwinPlatform createFromSDK(DarwinPlatformKind Platform, + StringRef Value) { + return DarwinPlatform(InferredFromSDK, Platform, Value); + } + static DarwinPlatform createFromArch(llvm::Triple::OSType OS, + StringRef Value) { + DarwinPlatformKind Platform; + switch (OS) { + case llvm::Triple::Darwin: + case llvm::Triple::MacOSX: + Platform = DarwinPlatformKind::MacOS; + break; + case llvm::Triple::IOS: + Platform = DarwinPlatformKind::IPhoneOS; + break; + case llvm::Triple::TvOS: + Platform = DarwinPlatformKind::TvOS; + break; + case llvm::Triple::WatchOS: + Platform = DarwinPlatformKind::WatchOS; + break; + default: + llvm_unreachable("Unable to infer Darwin variant"); } + return DarwinPlatform(InferredFromArch, Platform, Value); } +private: + DarwinPlatform(SourceKind Kind, DarwinPlatformKind Platform, Arg *Argument) + : Kind(Kind), Platform(Platform), Argument(Argument) {} + DarwinPlatform(SourceKind Kind, DarwinPlatformKind Platform, StringRef Value) + : Kind(Kind), Platform(Platform), OSVersion(Value), Argument(nullptr) {} + + SourceKind Kind; + DarwinPlatformKind Platform; + std::string OSVersion; + Arg *Argument; + StringRef EnvVarName; +}; + +/// Returns the deployment target that's specified using the -m<os>-version-min +/// argument. +Optional<DarwinPlatform> +getDeploymentTargetFromOSVersionArg(DerivedArgList &Args, + const Driver &TheDriver) { Arg *OSXVersion = Args.getLastArg(options::OPT_mmacosx_version_min_EQ); Arg *iOSVersion = Args.getLastArg(options::OPT_miphoneos_version_min_EQ, options::OPT_mios_simulator_version_min_EQ); @@ -1170,232 +1298,249 @@ void Darwin::AddDeploymentTarget(DerivedArgList &Args) const { Arg *WatchOSVersion = Args.getLastArg(options::OPT_mwatchos_version_min_EQ, options::OPT_mwatchos_simulator_version_min_EQ); + if (OSXVersion) { + if (iOSVersion || TvOSVersion || WatchOSVersion) { + TheDriver.Diag(diag::err_drv_argument_not_allowed_with) + << OSXVersion->getAsString(Args) + << (iOSVersion ? iOSVersion + : TvOSVersion ? TvOSVersion : WatchOSVersion) + ->getAsString(Args); + } + return DarwinPlatform::createOSVersionArg(Darwin::MacOS, OSXVersion); + } else if (iOSVersion) { + if (TvOSVersion || WatchOSVersion) { + TheDriver.Diag(diag::err_drv_argument_not_allowed_with) + << iOSVersion->getAsString(Args) + << (TvOSVersion ? TvOSVersion : WatchOSVersion)->getAsString(Args); + } + return DarwinPlatform::createOSVersionArg(Darwin::IPhoneOS, iOSVersion); + } else if (TvOSVersion) { + if (WatchOSVersion) { + TheDriver.Diag(diag::err_drv_argument_not_allowed_with) + << TvOSVersion->getAsString(Args) + << WatchOSVersion->getAsString(Args); + } + return DarwinPlatform::createOSVersionArg(Darwin::TvOS, TvOSVersion); + } else if (WatchOSVersion) + return DarwinPlatform::createOSVersionArg(Darwin::WatchOS, WatchOSVersion); + return None; +} - unsigned Major, Minor, Micro; - bool HadExtra; +/// Returns the deployment target that's specified using the +/// OS_DEPLOYMENT_TARGET environment variable. +Optional<DarwinPlatform> +getDeploymentTargetFromEnvironmentVariables(const Driver &TheDriver, + const llvm::Triple &Triple) { + std::string Targets[Darwin::LastDarwinPlatform + 1]; + const char *EnvVars[] = { + "MACOSX_DEPLOYMENT_TARGET", + "IPHONEOS_DEPLOYMENT_TARGET", + "TVOS_DEPLOYMENT_TARGET", + "WATCHOS_DEPLOYMENT_TARGET", + }; + static_assert(llvm::array_lengthof(EnvVars) == Darwin::LastDarwinPlatform + 1, + "Missing platform"); + for (const auto &I : llvm::enumerate(llvm::makeArrayRef(EnvVars))) { + if (char *Env = ::getenv(I.value())) + Targets[I.index()] = Env; + } - // The iOS deployment target that is explicitly specified via a command line - // option or an environment variable. - std::string ExplicitIOSDeploymentTargetStr; - - if (iOSVersion) - ExplicitIOSDeploymentTargetStr = iOSVersion->getAsString(Args); - - // Add a macro to differentiate between m(iphone|tv|watch)os-version-min=X.Y and - // -m(iphone|tv|watch)simulator-version-min=X.Y. - if (Args.hasArg(options::OPT_mios_simulator_version_min_EQ) || - Args.hasArg(options::OPT_mtvos_simulator_version_min_EQ) || - Args.hasArg(options::OPT_mwatchos_simulator_version_min_EQ)) - Args.append(Args.MakeSeparateArg(nullptr, Opts.getOption(options::OPT_D), - " __APPLE_EMBEDDED_SIMULATOR__=1")); - - if (OSXVersion && (iOSVersion || TvOSVersion || WatchOSVersion)) { - getDriver().Diag(diag::err_drv_argument_not_allowed_with) - << OSXVersion->getAsString(Args) - << (iOSVersion ? iOSVersion : - TvOSVersion ? TvOSVersion : WatchOSVersion)->getAsString(Args); - iOSVersion = TvOSVersion = WatchOSVersion = nullptr; - } else if (iOSVersion && (TvOSVersion || WatchOSVersion)) { - getDriver().Diag(diag::err_drv_argument_not_allowed_with) - << iOSVersion->getAsString(Args) - << (TvOSVersion ? TvOSVersion : WatchOSVersion)->getAsString(Args); - TvOSVersion = WatchOSVersion = nullptr; - } else if (TvOSVersion && WatchOSVersion) { - getDriver().Diag(diag::err_drv_argument_not_allowed_with) - << TvOSVersion->getAsString(Args) - << WatchOSVersion->getAsString(Args); - WatchOSVersion = nullptr; - } else if (!OSXVersion && !iOSVersion && !TvOSVersion && !WatchOSVersion) { - // If no deployment target was specified on the command line, check for - // environment defines. - std::string OSXTarget; - std::string iOSTarget; - std::string TvOSTarget; - std::string WatchOSTarget; - - if (char *env = ::getenv("MACOSX_DEPLOYMENT_TARGET")) - OSXTarget = env; - if (char *env = ::getenv("IPHONEOS_DEPLOYMENT_TARGET")) - iOSTarget = env; - if (char *env = ::getenv("TVOS_DEPLOYMENT_TARGET")) - TvOSTarget = env; - if (char *env = ::getenv("WATCHOS_DEPLOYMENT_TARGET")) - WatchOSTarget = env; - - if (!iOSTarget.empty()) - ExplicitIOSDeploymentTargetStr = - std::string("IPHONEOS_DEPLOYMENT_TARGET=") + iOSTarget; - - // If there is no command-line argument to specify the Target version and - // no environment variable defined, see if we can set the default based - // on -isysroot. - if (OSXTarget.empty() && iOSTarget.empty() && WatchOSTarget.empty() && - TvOSTarget.empty() && Args.hasArg(options::OPT_isysroot)) { - if (const Arg *A = Args.getLastArg(options::OPT_isysroot)) { - StringRef isysroot = A->getValue(); - StringRef SDK = getSDKName(isysroot); - if (SDK.size() > 0) { - // Slice the version number out. - // Version number is between the first and the last number. - size_t StartVer = SDK.find_first_of("0123456789"); - size_t EndVer = SDK.find_last_of("0123456789"); - if (StartVer != StringRef::npos && EndVer > StartVer) { - StringRef Version = SDK.slice(StartVer, EndVer + 1); - if (SDK.startswith("iPhoneOS") || - SDK.startswith("iPhoneSimulator")) - iOSTarget = Version; - else if (SDK.startswith("MacOSX")) - OSXTarget = getSystemOrSDKMacOSVersion(Version); - else if (SDK.startswith("WatchOS") || - SDK.startswith("WatchSimulator")) - WatchOSTarget = Version; - else if (SDK.startswith("AppleTVOS") || - SDK.startswith("AppleTVSimulator")) - TvOSTarget = Version; - } - } - } - } + // Do not allow conflicts with the watchOS target. + if (!Targets[Darwin::WatchOS].empty() && + (!Targets[Darwin::IPhoneOS].empty() || !Targets[Darwin::TvOS].empty())) { + TheDriver.Diag(diag::err_drv_conflicting_deployment_targets) + << "WATCHOS_DEPLOYMENT_TARGET" + << (!Targets[Darwin::IPhoneOS].empty() ? "IPHONEOS_DEPLOYMENT_TARGET" + : "TVOS_DEPLOYMENT_TARGET"); + } - // If no OS targets have been specified, try to guess platform from -target - // or arch name and compute the version from the triple. - if (OSXTarget.empty() && iOSTarget.empty() && TvOSTarget.empty() && - WatchOSTarget.empty()) { - llvm::Triple::OSType OSTy = llvm::Triple::UnknownOS; + // Do not allow conflicts with the tvOS target. + if (!Targets[Darwin::TvOS].empty() && !Targets[Darwin::IPhoneOS].empty()) { + TheDriver.Diag(diag::err_drv_conflicting_deployment_targets) + << "TVOS_DEPLOYMENT_TARGET" + << "IPHONEOS_DEPLOYMENT_TARGET"; + } - // Set the OSTy based on -target if -arch isn't present. - if (Args.hasArg(options::OPT_target) && !Args.hasArg(options::OPT_arch)) { - OSTy = getTriple().getOS(); - } else { - StringRef MachOArchName = getMachOArchName(Args); - if (MachOArchName == "armv7" || MachOArchName == "armv7s" || - MachOArchName == "arm64") - OSTy = llvm::Triple::IOS; - else if (MachOArchName == "armv7k") - OSTy = llvm::Triple::WatchOS; - else if (MachOArchName != "armv6m" && MachOArchName != "armv7m" && - MachOArchName != "armv7em") - OSTy = llvm::Triple::MacOSX; - } + // Allow conflicts among OSX and iOS for historical reasons, but choose the + // default platform. + if (!Targets[Darwin::MacOS].empty() && + (!Targets[Darwin::IPhoneOS].empty() || + !Targets[Darwin::WatchOS].empty() || !Targets[Darwin::TvOS].empty())) { + if (Triple.getArch() == llvm::Triple::arm || + Triple.getArch() == llvm::Triple::aarch64 || + Triple.getArch() == llvm::Triple::thumb) + Targets[Darwin::MacOS] = ""; + else + Targets[Darwin::IPhoneOS] = Targets[Darwin::WatchOS] = + Targets[Darwin::TvOS] = ""; + } + for (const auto &Target : llvm::enumerate(llvm::makeArrayRef(Targets))) { + if (!Target.value().empty()) + return DarwinPlatform::createDeploymentTargetEnv( + (Darwin::DarwinPlatformKind)Target.index(), EnvVars[Target.index()], + Target.value()); + } + return None; +} - if (OSTy != llvm::Triple::UnknownOS) { - unsigned Major, Minor, Micro; - std::string *OSTarget; - - switch (OSTy) { - case llvm::Triple::Darwin: - case llvm::Triple::MacOSX: - if (!getTriple().getMacOSXVersion(Major, Minor, Micro)) - getDriver().Diag(diag::err_drv_invalid_darwin_version) - << getTriple().getOSName(); - OSTarget = &OSXTarget; - break; - case llvm::Triple::IOS: - getTriple().getiOSVersion(Major, Minor, Micro); - OSTarget = &iOSTarget; - break; - case llvm::Triple::TvOS: - getTriple().getOSVersion(Major, Minor, Micro); - OSTarget = &TvOSTarget; - break; - case llvm::Triple::WatchOS: - getTriple().getWatchOSVersion(Major, Minor, Micro); - OSTarget = &WatchOSTarget; - break; - default: - llvm_unreachable("Unexpected OS type"); - break; - } +/// Tries to infer the deployment target from the SDK specified by -isysroot +/// (or SDKROOT). +Optional<DarwinPlatform> inferDeploymentTargetFromSDK(DerivedArgList &Args) { + const Arg *A = Args.getLastArg(options::OPT_isysroot); + if (!A) + return None; + StringRef isysroot = A->getValue(); + StringRef SDK = Darwin::getSDKName(isysroot); + if (!SDK.size()) + return None; + // Slice the version number out. + // Version number is between the first and the last number. + size_t StartVer = SDK.find_first_of("0123456789"); + size_t EndVer = SDK.find_last_of("0123456789"); + if (StartVer != StringRef::npos && EndVer > StartVer) { + StringRef Version = SDK.slice(StartVer, EndVer + 1); + if (SDK.startswith("iPhoneOS") || SDK.startswith("iPhoneSimulator")) + return DarwinPlatform::createFromSDK(Darwin::IPhoneOS, Version); + else if (SDK.startswith("MacOSX")) + return DarwinPlatform::createFromSDK(Darwin::MacOS, + getSystemOrSDKMacOSVersion(Version)); + else if (SDK.startswith("WatchOS") || SDK.startswith("WatchSimulator")) + return DarwinPlatform::createFromSDK(Darwin::WatchOS, Version); + else if (SDK.startswith("AppleTVOS") || SDK.startswith("AppleTVSimulator")) + return DarwinPlatform::createFromSDK(Darwin::TvOS, Version); + } + return None; +} - llvm::raw_string_ostream(*OSTarget) << Major << '.' << Minor << '.' - << Micro; - } - } +std::string getOSVersion(llvm::Triple::OSType OS, const llvm::Triple &Triple, + const Driver &TheDriver) { + unsigned Major, Minor, Micro; + switch (OS) { + case llvm::Triple::Darwin: + case llvm::Triple::MacOSX: + if (!Triple.getMacOSXVersion(Major, Minor, Micro)) + TheDriver.Diag(diag::err_drv_invalid_darwin_version) + << Triple.getOSName(); + break; + case llvm::Triple::IOS: + Triple.getiOSVersion(Major, Minor, Micro); + break; + case llvm::Triple::TvOS: + Triple.getOSVersion(Major, Minor, Micro); + break; + case llvm::Triple::WatchOS: + Triple.getWatchOSVersion(Major, Minor, Micro); + break; + default: + llvm_unreachable("Unexpected OS type"); + break; + } - // Do not allow conflicts with the watchOS target. - if (!WatchOSTarget.empty() && (!iOSTarget.empty() || !TvOSTarget.empty())) { - getDriver().Diag(diag::err_drv_conflicting_deployment_targets) - << "WATCHOS_DEPLOYMENT_TARGET" - << (!iOSTarget.empty() ? "IPHONEOS_DEPLOYMENT_TARGET" : - "TVOS_DEPLOYMENT_TARGET"); - } + std::string OSVersion; + llvm::raw_string_ostream(OSVersion) << Major << '.' << Minor << '.' << Micro; + return OSVersion; +} - // Do not allow conflicts with the tvOS target. - if (!TvOSTarget.empty() && !iOSTarget.empty()) { - getDriver().Diag(diag::err_drv_conflicting_deployment_targets) - << "TVOS_DEPLOYMENT_TARGET" - << "IPHONEOS_DEPLOYMENT_TARGET"; - } +/// Tries to infer the target OS from the -arch. +Optional<DarwinPlatform> +inferDeploymentTargetFromArch(DerivedArgList &Args, const Darwin &Toolchain, + const llvm::Triple &Triple, + const Driver &TheDriver) { + llvm::Triple::OSType OSTy = llvm::Triple::UnknownOS; - // Allow conflicts among OSX and iOS for historical reasons, but choose the - // default platform. - if (!OSXTarget.empty() && (!iOSTarget.empty() || - !WatchOSTarget.empty() || - !TvOSTarget.empty())) { - if (getTriple().getArch() == llvm::Triple::arm || - getTriple().getArch() == llvm::Triple::aarch64 || - getTriple().getArch() == llvm::Triple::thumb) - OSXTarget = ""; - else - iOSTarget = WatchOSTarget = TvOSTarget = ""; - } + // Set the OSTy based on -target if -arch isn't present. + if (Args.hasArg(options::OPT_target) && !Args.hasArg(options::OPT_arch)) { + OSTy = Triple.getOS(); + } else { + StringRef MachOArchName = Toolchain.getMachOArchName(Args); + if (MachOArchName == "armv7" || MachOArchName == "armv7s" || + MachOArchName == "arm64") + OSTy = llvm::Triple::IOS; + else if (MachOArchName == "armv7k") + OSTy = llvm::Triple::WatchOS; + else if (MachOArchName != "armv6m" && MachOArchName != "armv7m" && + MachOArchName != "armv7em") + OSTy = llvm::Triple::MacOSX; + } - if (!OSXTarget.empty()) { - const Option O = Opts.getOption(options::OPT_mmacosx_version_min_EQ); - OSXVersion = Args.MakeJoinedArg(nullptr, O, OSXTarget); - Args.append(OSXVersion); - } else if (!iOSTarget.empty()) { - const Option O = Opts.getOption(options::OPT_miphoneos_version_min_EQ); - iOSVersion = Args.MakeJoinedArg(nullptr, O, iOSTarget); - Args.append(iOSVersion); - } else if (!TvOSTarget.empty()) { - const Option O = Opts.getOption(options::OPT_mtvos_version_min_EQ); - TvOSVersion = Args.MakeJoinedArg(nullptr, O, TvOSTarget); - Args.append(TvOSVersion); - } else if (!WatchOSTarget.empty()) { - const Option O = Opts.getOption(options::OPT_mwatchos_version_min_EQ); - WatchOSVersion = Args.MakeJoinedArg(nullptr, O, WatchOSTarget); - Args.append(WatchOSVersion); + if (OSTy == llvm::Triple::UnknownOS) + return None; + return DarwinPlatform::createFromArch(OSTy, + getOSVersion(OSTy, Triple, TheDriver)); +} + +} // namespace + +void Darwin::AddDeploymentTarget(DerivedArgList &Args) const { + const OptTable &Opts = getDriver().getOpts(); + + // Support allowing the SDKROOT environment variable used by xcrun and other + // Xcode tools to define the default sysroot, by making it the default for + // isysroot. + if (const Arg *A = Args.getLastArg(options::OPT_isysroot)) { + // Warn if the path does not exist. + if (!getVFS().exists(A->getValue())) + getDriver().Diag(clang::diag::warn_missing_sysroot) << A->getValue(); + } else { + if (char *env = ::getenv("SDKROOT")) { + // We only use this value as the default if it is an absolute path, + // exists, and it is not the root path. + if (llvm::sys::path::is_absolute(env) && getVFS().exists(env) && + StringRef(env) != "/") { + Args.append(Args.MakeSeparateArg( + nullptr, Opts.getOption(options::OPT_isysroot), env)); + } } } - DarwinPlatformKind Platform; - if (OSXVersion) - Platform = MacOS; - else if (iOSVersion) - Platform = IPhoneOS; - else if (TvOSVersion) - Platform = TvOS; - else if (WatchOSVersion) - Platform = WatchOS; - else - llvm_unreachable("Unable to infer Darwin variant"); + // The OS target can be specified using the -m<os>version-min argument. + Optional<DarwinPlatform> OSTarget = + getDeploymentTargetFromOSVersionArg(Args, getDriver()); + // If no deployment target was specified on the command line, check for + // environment defines. + if (!OSTarget) + OSTarget = + getDeploymentTargetFromEnvironmentVariables(getDriver(), getTriple()); + // If there is no command-line argument to specify the Target version and + // no environment variable defined, see if we can set the default based + // on -isysroot. + if (!OSTarget) + OSTarget = inferDeploymentTargetFromSDK(Args); + // If no OS targets have been specified, try to guess platform from -target + // or arch name and compute the version from the triple. + if (!OSTarget) + OSTarget = + inferDeploymentTargetFromArch(Args, *this, getTriple(), getDriver()); + + assert(OSTarget && "Unable to infer Darwin variant"); + OSTarget->addOSVersionMinArgument(Args, Opts); + DarwinPlatformKind Platform = OSTarget->getPlatform(); + unsigned Major, Minor, Micro; + bool HadExtra; // Set the tool chain target information. if (Platform == MacOS) { - assert((!iOSVersion && !TvOSVersion && !WatchOSVersion) && - "Unknown target platform!"); - if (!Driver::GetReleaseVersion(OSXVersion->getValue(), Major, Minor, Micro, - HadExtra) || + if (!Driver::GetReleaseVersion(OSTarget->getOSVersion(), Major, Minor, + Micro, HadExtra) || HadExtra || Major != 10 || Minor >= 100 || Micro >= 100) getDriver().Diag(diag::err_drv_invalid_version_number) - << OSXVersion->getAsString(Args); + << OSTarget->getAsString(Args, Opts); } else if (Platform == IPhoneOS) { - assert(iOSVersion && "Unknown target platform!"); - if (!Driver::GetReleaseVersion(iOSVersion->getValue(), Major, Minor, Micro, - HadExtra) || + if (!Driver::GetReleaseVersion(OSTarget->getOSVersion(), Major, Minor, + Micro, HadExtra) || HadExtra || Major >= 100 || Minor >= 100 || Micro >= 100) getDriver().Diag(diag::err_drv_invalid_version_number) - << iOSVersion->getAsString(Args); + << OSTarget->getAsString(Args, Opts); + ; // For 32-bit targets, the deployment target for iOS has to be earlier than // iOS 11. if (getTriple().isArch32Bit() && Major >= 11) { // If the deployment target is explicitly specified, print a diagnostic. - if (!ExplicitIOSDeploymentTargetStr.empty()) { + if (OSTarget->isExplicitlySpecified()) { getDriver().Diag(diag::warn_invalid_ios_deployment_target) - << ExplicitIOSDeploymentTargetStr; - // Otherwise, set it to 10.99.99. + << OSTarget->getAsString(Args, Opts); + // Otherwise, set it to 10.99.99. } else { Major = 10; Minor = 99; @@ -1403,32 +1548,27 @@ void Darwin::AddDeploymentTarget(DerivedArgList &Args) const { } } } else if (Platform == TvOS) { - if (!Driver::GetReleaseVersion(TvOSVersion->getValue(), Major, Minor, - Micro, HadExtra) || HadExtra || - Major >= 100 || Minor >= 100 || Micro >= 100) + if (!Driver::GetReleaseVersion(OSTarget->getOSVersion(), Major, Minor, + Micro, HadExtra) || + HadExtra || Major >= 100 || Minor >= 100 || Micro >= 100) getDriver().Diag(diag::err_drv_invalid_version_number) - << TvOSVersion->getAsString(Args); + << OSTarget->getAsString(Args, Opts); } else if (Platform == WatchOS) { - if (!Driver::GetReleaseVersion(WatchOSVersion->getValue(), Major, Minor, - Micro, HadExtra) || HadExtra || - Major >= 10 || Minor >= 100 || Micro >= 100) + if (!Driver::GetReleaseVersion(OSTarget->getOSVersion(), Major, Minor, + Micro, HadExtra) || + HadExtra || Major >= 10 || Minor >= 100 || Micro >= 100) getDriver().Diag(diag::err_drv_invalid_version_number) - << WatchOSVersion->getAsString(Args); + << OSTarget->getAsString(Args, Opts); } else llvm_unreachable("unknown kind of Darwin platform"); + DarwinEnvironmentKind Environment = NativeEnvironment; // Recognize iOS targets with an x86 architecture as the iOS simulator. - if (iOSVersion && (getTriple().getArch() == llvm::Triple::x86 || - getTriple().getArch() == llvm::Triple::x86_64)) - Platform = IPhoneOSSimulator; - if (TvOSVersion && (getTriple().getArch() == llvm::Triple::x86 || - getTriple().getArch() == llvm::Triple::x86_64)) - Platform = TvOSSimulator; - if (WatchOSVersion && (getTriple().getArch() == llvm::Triple::x86 || - getTriple().getArch() == llvm::Triple::x86_64)) - Platform = WatchOSSimulator; - - setTarget(Platform, Major, Minor, Micro); + if (Platform != MacOS && (getTriple().getArch() == llvm::Triple::x86 || + getTriple().getArch() == llvm::Triple::x86_64)) + Environment = Simulator; + + setTarget(Platform, Environment, Major, Minor, Micro); if (const Arg *A = Args.getLastArg(options::OPT_isysroot)) { StringRef SDK = getSDKName(A->getValue()); @@ -1741,23 +1881,28 @@ void MachO::AddLinkRuntimeLibArgs(const ArgList &Args, : "soft"; CompilerRT += Args.hasArg(options::OPT_fPIC) ? "_pic.a" : "_static.a"; - AddLinkRuntimeLib(Args, CmdArgs, CompilerRT, false, true); + AddLinkRuntimeLib(Args, CmdArgs, CompilerRT, RLO_IsEmbedded); } bool Darwin::isAlignedAllocationUnavailable() const { + llvm::Triple::OSType OS; + switch (TargetPlatform) { case MacOS: // Earlier than 10.13. - return TargetVersion < VersionTuple(10U, 13U, 0U); + OS = llvm::Triple::MacOSX; + break; case IPhoneOS: - case IPhoneOSSimulator: - case TvOS: - case TvOSSimulator: // Earlier than 11.0. - return TargetVersion < VersionTuple(11U, 0U, 0U); - case WatchOS: - case WatchOSSimulator: // Earlier than 4.0. - return TargetVersion < VersionTuple(4U, 0U, 0U); + OS = llvm::Triple::IOS; + break; + case TvOS: // Earlier than 11.0. + OS = llvm::Triple::TvOS; + break; + case WatchOS: // Earlier than 4.0. + OS = llvm::Triple::WatchOS; + break; } - llvm_unreachable("Unsupported platform"); + + return TargetVersion < alignedAllocMinVersion(OS); } void Darwin::addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, @@ -1840,7 +1985,7 @@ bool MachO::IsUnwindTablesDefault(const ArgList &Args) const { // Unwind tables are not emitted if -fno-exceptions is supplied (except when // targeting x86_64). return getArch() == llvm::Triple::x86_64 || - (!UseSjLjExceptions(Args) && + (GetExceptionModel(Args) != llvm::ExceptionHandling::SjLj && Args.hasFlag(options::OPT_fexceptions, options::OPT_fno_exceptions, true)); } @@ -1851,15 +1996,18 @@ bool MachO::UseDwarfDebugFlags() const { return false; } -bool Darwin::UseSjLjExceptions(const ArgList &Args) const { +llvm::ExceptionHandling Darwin::GetExceptionModel(const ArgList &Args) const { // Darwin uses SjLj exceptions on ARM. if (getTriple().getArch() != llvm::Triple::arm && getTriple().getArch() != llvm::Triple::thumb) - return false; + return llvm::ExceptionHandling::None; // Only watchOS uses the new DWARF/Compact unwinding method. llvm::Triple Triple(ComputeLLVMTriple(Args)); - return !Triple.isWatchABI(); + if(Triple.isWatchABI()) + return llvm::ExceptionHandling::DwarfCFI; + + return llvm::ExceptionHandling::SjLj; } bool Darwin::SupportsEmbeddedBitcode() const { @@ -2000,8 +2148,6 @@ void Darwin::addStartObjectFileArgs(const ArgList &Args, } } -bool Darwin::SupportsObjCGC() const { return isTargetMacOS(); } - void Darwin::CheckObjCARC() const { if (isTargetIOSBased() || isTargetWatchOSBased() || (isTargetMacOS() && !isMacosxVersionLT(10, 6))) @@ -2015,6 +2161,8 @@ SanitizerMask Darwin::getSupportedSanitizers() const { Res |= SanitizerKind::Address; Res |= SanitizerKind::Leak; Res |= SanitizerKind::Fuzzer; + Res |= SanitizerKind::FuzzerNoLink; + Res |= SanitizerKind::Function; if (isTargetMacOS()) { if (!isMacosxVersionLT(10, 9)) Res |= SanitizerKind::Vptr; diff --git a/lib/Driver/ToolChains/Darwin.h b/lib/Driver/ToolChains/Darwin.h index 77c569e8f865..87d553bd7e0b 100644 --- a/lib/Driver/ToolChains/Darwin.h +++ b/lib/Driver/ToolChains/Darwin.h @@ -152,10 +152,11 @@ public: llvm::opt::ArgStringList &CmdArgs) const {} /// Add the linker arguments to link the compiler runtime library. + /// + /// FIXME: This API is intended for use with embedded libraries only, and is + /// misleadingly named. virtual void AddLinkRuntimeLibArgs(const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs) const; - virtual void AddFuzzerLinkArgs(const llvm::opt::ArgList &Args, - llvm::opt::ArgStringList &CmdArgs) const; virtual void addStartObjectFileArgs(const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs) const { @@ -171,10 +172,26 @@ public: /// Is the target either iOS or an iOS simulator? bool isTargetIOSBased() const { return false; } + /// Options to control how a runtime library is linked. + enum RuntimeLinkOptions : unsigned { + /// Link the library in even if it can't be found in the VFS. + RLO_AlwaysLink = 1 << 0, + + /// Use the embedded runtime from the macho_embedded directory. + RLO_IsEmbedded = 1 << 1, + + /// Emit rpaths for @executable_path as well as the resource directory. + RLO_AddRPath = 1 << 2, + + /// Link the library in before any others. + RLO_FirstLink = 1 << 3, + }; + + /// Add a runtime library to the list of items to link. void AddLinkRuntimeLib(const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs, - StringRef DarwinLibName, bool AlwaysLink = false, - bool IsEmbedded = false, bool AddRPath = false) const; + StringRef DarwinLibName, + RuntimeLinkOptions Opts = RuntimeLinkOptions()) const; /// Add any profiling runtime libraries that are needed. This is essentially a /// MachO specific version of addProfileRT in Tools.cpp. @@ -228,12 +245,11 @@ public: bool SupportsProfiling() const override; - bool SupportsObjCGC() const override { return false; } - bool UseDwarfDebugFlags() const override; - bool UseSjLjExceptions(const llvm::opt::ArgList &Args) const override { - return false; + llvm::ExceptionHandling + GetExceptionModel(const llvm::opt::ArgList &Args) const override { + return llvm::ExceptionHandling::None; } /// } @@ -252,14 +268,17 @@ public: enum DarwinPlatformKind { MacOS, IPhoneOS, - IPhoneOSSimulator, TvOS, - TvOSSimulator, WatchOS, - WatchOSSimulator + LastDarwinPlatform = WatchOS + }; + enum DarwinEnvironmentKind { + NativeEnvironment, + Simulator, }; mutable DarwinPlatformKind TargetPlatform; + mutable DarwinEnvironmentKind TargetEnvironment; /// The OS version we are targeting. mutable VersionTuple TargetVersion; @@ -301,29 +320,34 @@ protected: // FIXME: Eliminate these ...Target functions and derive separate tool chains // for these targets and put version in constructor. - void setTarget(DarwinPlatformKind Platform, unsigned Major, unsigned Minor, - unsigned Micro) const { + void setTarget(DarwinPlatformKind Platform, DarwinEnvironmentKind Environment, + unsigned Major, unsigned Minor, unsigned Micro) const { // FIXME: For now, allow reinitialization as long as values don't // change. This will go away when we move away from argument translation. if (TargetInitialized && TargetPlatform == Platform && + TargetEnvironment == Environment && TargetVersion == VersionTuple(Major, Minor, Micro)) return; assert(!TargetInitialized && "Target already initialized!"); TargetInitialized = true; TargetPlatform = Platform; + TargetEnvironment = Environment; TargetVersion = VersionTuple(Major, Minor, Micro); + if (Environment == Simulator) + const_cast<Darwin *>(this)->setTripleEnvironment(llvm::Triple::Simulator); } bool isTargetIPhoneOS() const { assert(TargetInitialized && "Target not initialized!"); - return TargetPlatform == IPhoneOS || TargetPlatform == TvOS; + return (TargetPlatform == IPhoneOS || TargetPlatform == TvOS) && + TargetEnvironment == NativeEnvironment; } bool isTargetIOSSimulator() const { assert(TargetInitialized && "Target not initialized!"); - return TargetPlatform == IPhoneOSSimulator || - TargetPlatform == TvOSSimulator; + return (TargetPlatform == IPhoneOS || TargetPlatform == TvOS) && + TargetEnvironment == Simulator; } bool isTargetIOSBased() const { @@ -333,32 +357,32 @@ protected: bool isTargetTvOS() const { assert(TargetInitialized && "Target not initialized!"); - return TargetPlatform == TvOS; + return TargetPlatform == TvOS && TargetEnvironment == NativeEnvironment; } bool isTargetTvOSSimulator() const { assert(TargetInitialized && "Target not initialized!"); - return TargetPlatform == TvOSSimulator; + return TargetPlatform == TvOS && TargetEnvironment == Simulator; } bool isTargetTvOSBased() const { assert(TargetInitialized && "Target not initialized!"); - return TargetPlatform == TvOS || TargetPlatform == TvOSSimulator; + return TargetPlatform == TvOS; } bool isTargetWatchOS() const { assert(TargetInitialized && "Target not initialized!"); - return TargetPlatform == WatchOS; + return TargetPlatform == WatchOS && TargetEnvironment == NativeEnvironment; } bool isTargetWatchOSSimulator() const { assert(TargetInitialized && "Target not initialized!"); - return TargetPlatform == WatchOSSimulator; + return TargetPlatform == WatchOS && TargetEnvironment == Simulator; } bool isTargetWatchOSBased() const { assert(TargetInitialized && "Target not initialized!"); - return TargetPlatform == WatchOS || TargetPlatform == WatchOSSimulator; + return TargetPlatform == WatchOS; } bool isTargetMacOS() const { @@ -394,10 +418,11 @@ protected: Action::OffloadKind DeviceOffloadKind) const override; StringRef getPlatformFamily() const; - static StringRef getSDKName(StringRef isysroot); StringRef getOSLibraryNameSuffix() const; public: + static StringRef getSDKName(StringRef isysroot); + /// } /// @name ToolChain Implementation /// { @@ -438,11 +463,10 @@ public: return 0; } - bool SupportsObjCGC() const override; - void CheckObjCARC() const override; - bool UseSjLjExceptions(const llvm::opt::ArgList &Args) const override; + llvm::ExceptionHandling GetExceptionModel( + const llvm::opt::ArgList &Args) const override; bool SupportsEmbeddedBitcode() const override; @@ -489,7 +513,8 @@ public: private: void AddLinkSanitizerLibArgs(const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs, - StringRef Sanitizer) const; + StringRef Sanitizer, + bool shared = true) const; }; } // end namespace toolchains diff --git a/lib/Driver/ToolChains/DragonFly.cpp b/lib/Driver/ToolChains/DragonFly.cpp index bd2c7fc6c4bd..648469e4cec5 100644 --- a/lib/Driver/ToolChains/DragonFly.cpp +++ b/lib/Driver/ToolChains/DragonFly.cpp @@ -127,7 +127,8 @@ void dragonfly::Linker::ConstructJob(Compilation &C, const JobAction &JA, } if (D.CCCIsCXX()) { - getToolChain().AddCXXStdlibLibArgs(Args, CmdArgs); + if (getToolChain().ShouldLinkCXXStdlib(Args)) + getToolChain().AddCXXStdlibLibArgs(Args, CmdArgs); CmdArgs.push_back("-lm"); } diff --git a/lib/Driver/ToolChains/FreeBSD.cpp b/lib/Driver/ToolChains/FreeBSD.cpp index c6626e922eef..dd0334b9c28b 100644 --- a/lib/Driver/ToolChains/FreeBSD.cpp +++ b/lib/Driver/ToolChains/FreeBSD.cpp @@ -240,7 +240,8 @@ void freebsd::Linker::ConstructJob(Compilation &C, const JobAction &JA, if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { addOpenMPRuntime(CmdArgs, ToolChain, Args); if (D.CCCIsCXX()) { - ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs); + if (ToolChain.ShouldLinkCXXStdlib(Args)) + ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs); if (Args.hasArg(options::OPT_pg)) CmdArgs.push_back("-lm_p"); else @@ -358,17 +359,18 @@ Tool *FreeBSD::buildAssembler() const { Tool *FreeBSD::buildLinker() const { return new tools::freebsd::Linker(*this); } -bool FreeBSD::UseSjLjExceptions(const ArgList &Args) const { +llvm::ExceptionHandling FreeBSD::GetExceptionModel(const ArgList &Args) const { // FreeBSD uses SjLj exceptions on ARM oabi. switch (getTriple().getEnvironment()) { case llvm::Triple::GNUEABIHF: case llvm::Triple::GNUEABI: case llvm::Triple::EABI: - return false; - + return llvm::ExceptionHandling::None; default: - return (getTriple().getArch() == llvm::Triple::arm || - getTriple().getArch() == llvm::Triple::thumb); + if (getTriple().getArch() == llvm::Triple::arm || + getTriple().getArch() == llvm::Triple::thumb) + return llvm::ExceptionHandling::SjLj; + return llvm::ExceptionHandling::None; } } diff --git a/lib/Driver/ToolChains/FreeBSD.h b/lib/Driver/ToolChains/FreeBSD.h index 25e9df72bc80..2943e1cacfbb 100644 --- a/lib/Driver/ToolChains/FreeBSD.h +++ b/lib/Driver/ToolChains/FreeBSD.h @@ -66,7 +66,8 @@ public: void AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args, llvm::opt::ArgStringList &CmdArgs) const override; - bool UseSjLjExceptions(const llvm::opt::ArgList &Args) const override; + llvm::ExceptionHandling GetExceptionModel( + const llvm::opt::ArgList &Args) const override; bool isPIEDefault() const override; SanitizerMask getSupportedSanitizers() const override; unsigned GetDefaultDwarfVersion() const override { return 2; } diff --git a/lib/Driver/ToolChains/Fuchsia.cpp b/lib/Driver/ToolChains/Fuchsia.cpp index 78053aafd16e..10ee7b7829be 100644 --- a/lib/Driver/ToolChains/Fuchsia.cpp +++ b/lib/Driver/ToolChains/Fuchsia.cpp @@ -14,6 +14,7 @@ #include "clang/Driver/Driver.h" #include "clang/Driver/DriverDiagnostic.h" #include "clang/Driver/Options.h" +#include "clang/Driver/SanitizerArgs.h" #include "llvm/Option/ArgList.h" #include "llvm/Support/Path.h" @@ -43,10 +44,8 @@ void fuchsia::Linker::ConstructJob(Compilation &C, const JobAction &JA, Args.ClaimAllArgs(options::OPT_w); const char *Exec = Args.MakeArgString(ToolChain.GetLinkerPath()); - if (llvm::sys::path::stem(Exec).equals_lower("lld")) { - CmdArgs.push_back("-flavor"); - CmdArgs.push_back("gnu"); - + if (llvm::sys::path::filename(Exec).equals_lower("ld.lld") || + llvm::sys::path::stem(Exec).equals_lower("ld.lld")) { CmdArgs.push_back("-z"); CmdArgs.push_back("rodynamic"); } @@ -63,27 +62,28 @@ void fuchsia::Linker::ConstructJob(Compilation &C, const JobAction &JA, if (Args.hasArg(options::OPT_s)) CmdArgs.push_back("-s"); - if (Args.hasArg(options::OPT_r)) + if (Args.hasArg(options::OPT_r)) { CmdArgs.push_back("-r"); - else + } else { CmdArgs.push_back("--build-id"); + CmdArgs.push_back("--hash-style=gnu"); + } - if (!Args.hasArg(options::OPT_static)) - CmdArgs.push_back("--eh-frame-hdr"); + CmdArgs.push_back("--eh-frame-hdr"); if (Args.hasArg(options::OPT_static)) CmdArgs.push_back("-Bstatic"); 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)) { - CmdArgs.push_back("-dynamic-linker"); - CmdArgs.push_back(Args.MakeArgString(D.DyldPrefix + "ld.so.1")); - } + if (!Args.hasArg(options::OPT_shared)) { + std::string Dyld = D.DyldPrefix; + if (ToolChain.getSanitizerArgs().needsAsanRt() && + ToolChain.getSanitizerArgs().needsSharedRt()) + Dyld += "asan/"; + Dyld += "ld.so.1"; + CmdArgs.push_back("-dynamic-linker"); + CmdArgs.push_back(Args.MakeArgString(Dyld)); } CmdArgs.push_back("-o"); @@ -100,6 +100,8 @@ void fuchsia::Linker::ConstructJob(Compilation &C, const JobAction &JA, ToolChain.AddFilePathLibArgs(Args, CmdArgs); + addSanitizerRuntimes(ToolChain, Args, CmdArgs); + AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA); if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { @@ -107,13 +109,8 @@ void fuchsia::Linker::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-Bdynamic"); if (D.CCCIsCXX()) { - 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"); + if (ToolChain.ShouldLinkCXXStdlib(Args)) + ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs); CmdArgs.push_back("-lm"); } @@ -282,5 +279,6 @@ void Fuchsia::AddCXXStdlibLibArgs(const ArgList &Args, SanitizerMask Fuchsia::getSupportedSanitizers() const { SanitizerMask Res = ToolChain::getSupportedSanitizers(); Res |= SanitizerKind::SafeStack; + Res |= SanitizerKind::Address; return Res; } diff --git a/lib/Driver/ToolChains/Fuchsia.h b/lib/Driver/ToolChains/Fuchsia.h index a723a99dfa3b..6f438deca7ff 100644 --- a/lib/Driver/ToolChains/Fuchsia.h +++ b/lib/Driver/ToolChains/Fuchsia.h @@ -42,12 +42,17 @@ public: bool HasNativeLLVMSupport() const override { return true; } bool IsIntegratedAssemblerDefault() const override { return true; } + bool IsMathErrnoDefault() const override { return false; } + bool useRelaxRelocations() const override { return true; }; RuntimeLibType GetDefaultRuntimeLibType() const override { return ToolChain::RLT_CompilerRT; } CXXStdlibType GetDefaultCXXStdlibType() const override { return ToolChain::CST_Libcxx; } + bool IsUnwindTablesDefault(const llvm::opt::ArgList &Args) const override { + return true; + } bool isPICDefault() const override { return false; } bool isPIEDefault() const override { return true; } bool isPICDefaultForced() const override { return false; } @@ -78,7 +83,7 @@ public: llvm::opt::ArgStringList &CmdArgs) const override; const char *getDefaultLinker() const override { - return "lld"; + return "ld.lld"; } protected: diff --git a/lib/Driver/ToolChains/Gnu.cpp b/lib/Driver/ToolChains/Gnu.cpp index 72a9f85ba389..7845781f12c4 100644 --- a/lib/Driver/ToolChains/Gnu.cpp +++ b/lib/Driver/ToolChains/Gnu.cpp @@ -11,6 +11,7 @@ #include "Linux.h" #include "Arch/ARM.h" #include "Arch/Mips.h" +#include "Arch/PPC.h" #include "Arch/Sparc.h" #include "Arch/SystemZ.h" #include "CommonArgs.h" @@ -41,6 +42,22 @@ static bool forwardToGCC(const Option &O) { !O.hasFlag(options::DriverOption) && !O.hasFlag(options::LinkerInput); } +// Switch CPU names not recognized by GNU assembler to a close CPU that it does +// recognize, instead of a lower march from being picked in the absence of a cpu +// flag. +static void normalizeCPUNamesForAssembler(const ArgList &Args, + ArgStringList &CmdArgs) { + if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) { + StringRef CPUArg(A->getValue()); + if (CPUArg.equals_lower("krait")) + CmdArgs.push_back("-mcpu=cortex-a15"); + else if(CPUArg.equals_lower("kryo")) + CmdArgs.push_back("-mcpu=cortex-a57"); + else + Args.AddLastArg(CmdArgs, options::OPT_mcpu_EQ); + } +} + void tools::gcc::Common::ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, @@ -203,133 +220,12 @@ void tools::gcc::Linker::RenderExtraToolArgs(const JobAction &JA, // 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"; - - // Put each target binary into a separate section. - for (const auto &BI : InputBinaryInfo) { - LksStream << " .omp_offloading." << BI.first << " :\n"; - LksStream << " ALIGN(0x10)\n"; - LksStream << " {\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) { + // Do not add the XRay runtime to shared libraries. + if (Args.hasArg(options::OPT_shared)) + return false; + if (Args.hasFlag(options::OPT_fxray_instrument, options::OPT_fnoxray_instrument, false)) { CmdArgs.push_back("-whole-archive"); @@ -337,6 +233,7 @@ static bool addXRayRuntime(const ToolChain &TC, const ArgList &Args, CmdArgs.push_back("-no-whole-archive"); return true; } + return false; } @@ -347,7 +244,8 @@ static void linkXRayRuntimeDeps(const ToolChain &TC, const ArgList &Args, CmdArgs.push_back("-lrt"); CmdArgs.push_back("-lm"); - if (TC.getTriple().getOS() != llvm::Triple::FreeBSD) + if (TC.getTriple().getOS() != llvm::Triple::FreeBSD && + TC.getTriple().getOS() != llvm::Triple::NetBSD) CmdArgs.push_back("-ldl"); } @@ -401,6 +299,17 @@ static const char *getLDMOption(const llvm::Triple &T, const ArgList &Args) { } } +static bool getPIE(const ArgList &Args, const toolchains::Linux &ToolChain) { + if (Args.hasArg(options::OPT_shared) || Args.hasArg(options::OPT_static)) + return false; + + Arg *A = Args.getLastArg(options::OPT_pie, options::OPT_no_pie, + options::OPT_nopie); + if (!A) + return ToolChain.isPIEDefault(); + return A->getOption().matches(options::OPT_pie); +} + void tools::gnutools::Linker::ConstructJob(Compilation &C, const JobAction &JA, const InputInfo &Output, const InputInfoList &Inputs, @@ -415,9 +324,7 @@ void tools::gnutools::Linker::ConstructJob(Compilation &C, const JobAction &JA, 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 IsPIE = getPIE(Args, ToolChain); const bool HasCRTBeginEndFiles = ToolChain.getTriple().hasEnvironment() || (ToolChain.getTriple().getVendor() != llvm::Triple::MipsTechnologies); @@ -560,13 +467,15 @@ void tools::gnutools::Linker::ConstructJob(Compilation &C, const JobAction &JA, 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"); + if (ToolChain.ShouldLinkCXXStdlib(Args)) { + 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. @@ -693,22 +602,28 @@ void tools::gnutools::Assembler::ConstructJob(Compilation &C, else CmdArgs.push_back("--64"); break; - case llvm::Triple::ppc: + case llvm::Triple::ppc: { CmdArgs.push_back("-a32"); CmdArgs.push_back("-mppc"); - CmdArgs.push_back("-many"); + CmdArgs.push_back( + ppc::getPPCAsmModeForCPU(getCPUName(Args, getToolChain().getTriple()))); break; - case llvm::Triple::ppc64: + } + case llvm::Triple::ppc64: { CmdArgs.push_back("-a64"); CmdArgs.push_back("-mppc64"); - CmdArgs.push_back("-many"); + CmdArgs.push_back( + ppc::getPPCAsmModeForCPU(getCPUName(Args, getToolChain().getTriple()))); break; - case llvm::Triple::ppc64le: + } + case llvm::Triple::ppc64le: { CmdArgs.push_back("-a64"); CmdArgs.push_back("-mppc64"); - CmdArgs.push_back("-many"); CmdArgs.push_back("-mlittle-endian"); + CmdArgs.push_back( + ppc::getPPCAsmModeForCPU(getCPUName(Args, getToolChain().getTriple()))); break; + } case llvm::Triple::sparc: case llvm::Triple::sparcel: { CmdArgs.push_back("-32"); @@ -754,23 +669,16 @@ void tools::gnutools::Assembler::ConstructJob(Compilation &C, } Args.AddLastArg(CmdArgs, options::OPT_march_EQ); + normalizeCPUNamesForAssembler(Args, CmdArgs); - // 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::aarch64: case llvm::Triple::aarch64_be: { Args.AddLastArg(CmdArgs, options::OPT_march_EQ); - Args.AddLastArg(CmdArgs, options::OPT_mcpu_EQ); + normalizeCPUNamesForAssembler(Args, CmdArgs); + break; } case llvm::Triple::mips: @@ -1427,12 +1335,12 @@ bool clang::driver::findMIPSMultilibs(const Driver &D, if (TargetTriple.getVendor() == llvm::Triple::MipsTechnologies && TargetTriple.getOS() == llvm::Triple::Linux && - TargetTriple.getEnvironment() == llvm::Triple::GNU) + TargetTriple.isGNUEnvironment()) return findMipsMtiMultilibs(Flags, NonExistent, Result); if (TargetTriple.getVendor() == llvm::Triple::ImaginationTechnologies && TargetTriple.getOS() == llvm::Triple::Linux && - TargetTriple.getEnvironment() == llvm::Triple::GNU) + TargetTriple.isGNUEnvironment()) return findMipsImgMultilibs(Flags, NonExistent, Result); if (findMipsCsMultilibs(Flags, NonExistent, Result)) @@ -1482,7 +1390,7 @@ static void findAndroidArmMultilibs(const Driver &D, 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); + (IsArmArch && llvm::ARM::parseArchISA(Arch) == llvm::ARM::ISAKind::THUMB); bool IsArmV7Mode = (IsArmArch || IsThumbArch) && (llvm::ARM::parseArchVersion(Arch) == 7 || (IsArmArch && Arch == "" && IsV7SubArch)); @@ -2468,7 +2376,8 @@ void Generic_ELF::addClangTargetOptions(const ArgList &DriverArgs, getTriple().getArch() == llvm::Triple::aarch64 || getTriple().getArch() == llvm::Triple::aarch64_be || (getTriple().getOS() == llvm::Triple::Linux && - (!V.isOlderThan(4, 7, 0) || getTriple().isAndroid())) || + ((!GCCInstallation.isValid() || !V.isOlderThan(4, 7, 0)) || + getTriple().isAndroid())) || getTriple().getOS() == llvm::Triple::NaCl || (getTriple().getVendor() == llvm::Triple::MipsTechnologies && !getTriple().hasEnvironment()) || diff --git a/lib/Driver/ToolChains/Hexagon.cpp b/lib/Driver/ToolChains/Hexagon.cpp index 9bf1590e6a37..f21af5b4dcf5 100644 --- a/lib/Driver/ToolChains/Hexagon.cpp +++ b/lib/Driver/ToolChains/Hexagon.cpp @@ -27,6 +27,101 @@ using namespace clang::driver::toolchains; using namespace clang; using namespace llvm::opt; +// Default hvx-length for various versions. +static StringRef getDefaultHvxLength(StringRef Cpu) { + return llvm::StringSwitch<StringRef>(Cpu) + .Case("v60", "64b") + .Case("v62", "64b") + .Case("v65", "64b") + .Default("128b"); +} + +static void handleHVXWarnings(const Driver &D, const ArgList &Args) { + // Handle deprecated HVX double warnings. + if (Arg *A = Args.getLastArg(options::OPT_mhexagon_hvx_double)) + D.Diag(diag::warn_drv_deprecated_arg) + << A->getAsString(Args) << "-mhvx-length=128B"; + if (Arg *A = Args.getLastArg(options::OPT_mno_hexagon_hvx_double)) + D.Diag(diag::warn_drv_deprecated_arg) << A->getAsString(Args) << "-mno-hvx"; + // Handle the unsupported values passed to mhvx-length. + if (Arg *A = Args.getLastArg(options::OPT_mhexagon_hvx_length_EQ)) { + StringRef Val = A->getValue(); + if (Val != "64B" && Val != "128B") + D.Diag(diag::err_drv_unsupported_option_argument) + << A->getOption().getName() << Val; + } +} + +// Handle hvx target features explicitly. +static void handleHVXTargetFeatures(const Driver &D, const ArgList &Args, + std::vector<StringRef> &Features, + bool &HasHVX) { + // Handle HVX warnings. + handleHVXWarnings(D, Args); + + // Add the +hvx* features based on commandline flags. + StringRef HVXFeature, HVXLength; + StringRef Cpu(toolchains::HexagonToolChain::GetTargetCPUVersion(Args)); + + // Handle -mhvx, -mhvx=, -mno-hvx, -mno-hvx-double. + if (Arg *A = Args.getLastArg( + options::OPT_mno_hexagon_hvx, options::OPT_mno_hexagon_hvx_double, + options::OPT_mhexagon_hvx, options::OPT_mhexagon_hvx_EQ)) { + if (A->getOption().matches(options::OPT_mno_hexagon_hvx) || + A->getOption().matches(options::OPT_mno_hexagon_hvx_double)) { + return; + } else if (A->getOption().matches(options::OPT_mhexagon_hvx_EQ)) { + HasHVX = true; + HVXFeature = Cpu = A->getValue(); + HVXFeature = Args.MakeArgString(llvm::Twine("+hvx") + HVXFeature.lower()); + } else if (A->getOption().matches(options::OPT_mhexagon_hvx)) { + HasHVX = true; + HVXFeature = Args.MakeArgString(llvm::Twine("+hvx") + Cpu); + } + Features.push_back(HVXFeature); + } + + // Handle -mhvx-length=, -mhvx-double. + if (Arg *A = Args.getLastArg(options::OPT_mhexagon_hvx_length_EQ, + options::OPT_mhexagon_hvx_double)) { + // These falgs are valid only if HVX in enabled. + if (!HasHVX) + D.Diag(diag::err_drv_invalid_hvx_length); + else if (A->getOption().matches(options::OPT_mhexagon_hvx_length_EQ)) + HVXLength = A->getValue(); + else if (A->getOption().matches(options::OPT_mhexagon_hvx_double)) + HVXLength = "128b"; + } + // Default hvx-length based on Cpu. + else if (HasHVX) + HVXLength = getDefaultHvxLength(Cpu); + + if (!HVXLength.empty()) { + HVXFeature = + Args.MakeArgString(llvm::Twine("+hvx-length") + HVXLength.lower()); + Features.push_back(HVXFeature); + } +} + +// Hexagon target features. +void hexagon::getHexagonTargetFeatures(const Driver &D, const ArgList &Args, + std::vector<StringRef> &Features) { + handleTargetFeaturesGroup(Args, Features, + options::OPT_m_hexagon_Features_Group); + + bool UseLongCalls = false; + if (Arg *A = Args.getLastArg(options::OPT_mlong_calls, + options::OPT_mno_long_calls)) { + if (A->getOption().matches(options::OPT_mlong_calls)) + UseLongCalls = true; + } + + Features.push_back(UseLongCalls ? "+long-calls" : "-long-calls"); + + bool HasHVX(false); + handleHVXTargetFeatures(D, Args, Features, HasHVX); +} + // Hexagon tools start. void hexagon::Assembler::RenderExtraToolArgs(const JobAction &JA, ArgStringList &CmdArgs) const { @@ -248,7 +343,8 @@ constructHexagonLinkArgs(Compilation &C, const JobAction &JA, //---------------------------------------------------------------------------- if (IncStdLib && IncDefLibs) { if (D.CCCIsCXX()) { - HTC.AddCXXStdlibLibArgs(Args, CmdArgs); + if (HTC.ShouldLinkCXXStdlib(Args)) + HTC.AddCXXStdlibLibArgs(Args, CmdArgs); CmdArgs.push_back("-lm"); } diff --git a/lib/Driver/ToolChains/Hexagon.h b/lib/Driver/ToolChains/Hexagon.h index 7f9a6b2f34b9..229a08c76dfb 100644 --- a/lib/Driver/ToolChains/Hexagon.h +++ b/lib/Driver/ToolChains/Hexagon.h @@ -50,6 +50,10 @@ public: const llvm::opt::ArgList &TCArgs, const char *LinkingOutput) const override; }; + +void getHexagonTargetFeatures(const Driver &D, const llvm::opt::ArgList &Args, + std::vector<StringRef> &Features); + } // end namespace hexagon. } // end namespace tools diff --git a/lib/Driver/ToolChains/Linux.cpp b/lib/Driver/ToolChains/Linux.cpp index 08a27fa7fed1..1301cdf114ae 100644 --- a/lib/Driver/ToolChains/Linux.cpp +++ b/lib/Driver/ToolChains/Linux.cpp @@ -210,7 +210,12 @@ Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) Distro Distro(D.getVFS()); - if (Distro.IsOpenSUSE() || Distro.IsUbuntu()) { + if (Distro.IsAlpineLinux()) { + ExtraOpts.push_back("-z"); + ExtraOpts.push_back("now"); + } + + if (Distro.IsOpenSUSE() || Distro.IsUbuntu() || Distro.IsAlpineLinux()) { ExtraOpts.push_back("-z"); ExtraOpts.push_back("relro"); } @@ -232,7 +237,7 @@ Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) // Android loader does not support .gnu.hash. // Hexagon linker/loader does not support .gnu.hash if (!IsMips && !IsAndroid && !IsHexagon) { - if (Distro.IsRedhat() || Distro.IsOpenSUSE() || + if (Distro.IsRedhat() || Distro.IsOpenSUSE() || Distro.IsAlpineLinux() || (Distro.IsUbuntu() && Distro >= Distro::UbuntuMaverick)) ExtraOpts.push_back("--hash-style=gnu"); @@ -248,7 +253,7 @@ Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) ExtraOpts.push_back("--build-id"); #endif - if (Distro.IsOpenSUSE()) + if (IsAndroid || Distro.IsOpenSUSE()) ExtraOpts.push_back("--enable-new-dtags"); // The selection of paths to try here is designed to match the patterns which @@ -810,7 +815,10 @@ void Linux::AddIAMCUIncludeArgs(const ArgList &DriverArgs, } } -bool Linux::isPIEDefault() const { return getSanitizerArgs().requiresPIE(); } +bool Linux::isPIEDefault() const { + return (getTriple().isAndroid() && !getTriple().isAndroidVersionLT(16)) || + getTriple().isMusl() || getSanitizerArgs().requiresPIE(); +} SanitizerMask Linux::getSupportedSanitizers() const { const bool IsX86 = getTriple().getArch() == llvm::Triple::x86; @@ -828,12 +836,13 @@ SanitizerMask Linux::getSupportedSanitizers() const { SanitizerMask Res = ToolChain::getSupportedSanitizers(); Res |= SanitizerKind::Address; Res |= SanitizerKind::Fuzzer; + Res |= SanitizerKind::FuzzerNoLink; Res |= SanitizerKind::KernelAddress; Res |= SanitizerKind::Vptr; Res |= SanitizerKind::SafeStack; if (IsX86_64 || IsMIPS64 || IsAArch64) Res |= SanitizerKind::DataFlow; - if (IsX86_64 || IsMIPS64 || IsAArch64 || IsX86 || IsArmArch) + if (IsX86_64 || IsMIPS64 || IsAArch64 || IsX86 || IsArmArch || IsPowerPC64) Res |= SanitizerKind::Leak; if (IsX86_64 || IsMIPS64 || IsAArch64 || IsPowerPC64) Res |= SanitizerKind::Thread; @@ -841,9 +850,12 @@ SanitizerMask Linux::getSupportedSanitizers() const { Res |= SanitizerKind::Memory; if (IsX86_64 || IsMIPS64) Res |= SanitizerKind::Efficiency; - if (IsX86 || IsX86_64) { + if (IsX86 || IsX86_64) Res |= SanitizerKind::Function; - } + if (IsX86_64 || IsMIPS64 || IsAArch64 || IsX86 || IsArmArch) + Res |= SanitizerKind::Scudo; + if (IsAArch64) + Res |= SanitizerKind::HWAddress; return Res; } diff --git a/lib/Driver/ToolChains/MSVC.cpp b/lib/Driver/ToolChains/MSVC.cpp index 7978a6941cb8..ae41ee9e22cf 100644 --- a/lib/Driver/ToolChains/MSVC.cpp +++ b/lib/Driver/ToolChains/MSVC.cpp @@ -375,7 +375,7 @@ void visualstudio::Linker::ConstructJob(Compilation &C, const JobAction &JA, if (TC.getSanitizerArgs().needsAsanRt()) { CmdArgs.push_back(Args.MakeArgString("-debug")); CmdArgs.push_back(Args.MakeArgString("-incremental:no")); - if (TC.getSanitizerArgs().needsSharedAsanRt() || + if (TC.getSanitizerArgs().needsSharedRt() || Args.hasArg(options::OPT__SLASH_MD, options::OPT__SLASH_MDd)) { for (const auto &Lib : {"asan_dynamic", "asan_dynamic_runtime_thunk"}) CmdArgs.push_back(TC.getCompilerRTArgString(Args, Lib)); @@ -1266,9 +1266,8 @@ VersionTuple MSVCToolChain::computeMSVCVersion(const Driver *D, if (MSVT.empty() && Args.hasFlag(options::OPT_fms_extensions, options::OPT_fno_ms_extensions, IsWindowsMSVC)) { - // -fms-compatibility-version=18.00 is default. - // FIXME: Consider bumping this to 19 (MSVC2015) soon. - MSVT = VersionTuple(18); + // -fms-compatibility-version=19.11 is default, aka 2017 + MSVT = VersionTuple(19, 11); } return MSVT; } @@ -1317,24 +1316,26 @@ static void TranslateOptArg(Arg *A, llvm::opt::DerivedArgList &DAL, case '2': case 'x': case 'd': - if (&OptChar == ExpandChar) { - if (OptChar == 'd') { - DAL.AddFlagArg(A, Opts.getOption(options::OPT_O0)); - } else { - if (OptChar == '1') { - DAL.AddJoinedArg(A, Opts.getOption(options::OPT_O), "s"); - } else if (OptChar == '2' || OptChar == 'x') { - DAL.AddFlagArg(A, Opts.getOption(options::OPT_fbuiltin)); - DAL.AddJoinedArg(A, Opts.getOption(options::OPT_O), "2"); - } - if (SupportsForcingFramePointer && - !DAL.hasArgNoClaim(options::OPT_fno_omit_frame_pointer)) - DAL.AddFlagArg(A, - Opts.getOption(options::OPT_fomit_frame_pointer)); - if (OptChar == '1' || OptChar == '2') - DAL.AddFlagArg(A, - Opts.getOption(options::OPT_ffunction_sections)); + // Ignore /O[12xd] flags that aren't the last one on the command line. + // Only the last one gets expanded. + if (&OptChar != ExpandChar) { + A->claim(); + break; + } + if (OptChar == 'd') { + DAL.AddFlagArg(A, Opts.getOption(options::OPT_O0)); + } else { + if (OptChar == '1') { + DAL.AddJoinedArg(A, Opts.getOption(options::OPT_O), "s"); + } else if (OptChar == '2' || OptChar == 'x') { + DAL.AddFlagArg(A, Opts.getOption(options::OPT_fbuiltin)); + DAL.AddJoinedArg(A, Opts.getOption(options::OPT_O), "2"); } + if (SupportsForcingFramePointer && + !DAL.hasArgNoClaim(options::OPT_fno_omit_frame_pointer)) + DAL.AddFlagArg(A, Opts.getOption(options::OPT_fomit_frame_pointer)); + if (OptChar == '1' || OptChar == '2') + DAL.AddFlagArg(A, Opts.getOption(options::OPT_ffunction_sections)); } break; case 'b': @@ -1430,9 +1431,7 @@ MSVCToolChain::TranslateArgs(const llvm::opt::DerivedArgList &Args, // First step is to search for the character we'd like to expand. const char *ExpandChar = nullptr; - for (Arg *A : Args) { - if (!A->getOption().matches(options::OPT__SLASH_O)) - continue; + for (Arg *A : Args.filtered(options::OPT__SLASH_O)) { StringRef OptStr = A->getValue(); for (size_t I = 0, E = OptStr.size(); I != E; ++I) { char OptChar = OptStr[I]; diff --git a/lib/Driver/ToolChains/MinGW.cpp b/lib/Driver/ToolChains/MinGW.cpp index 632b76d92bdd..572ea803f2dc 100644 --- a/lib/Driver/ToolChains/MinGW.cpp +++ b/lib/Driver/ToolChains/MinGW.cpp @@ -82,6 +82,9 @@ void tools::MinGW::Linker::AddLibGCC(const ArgList &Args, CmdArgs.push_back("-lmoldname"); CmdArgs.push_back("-lmingwex"); + for (auto Lib : Args.getAllArgValues(options::OPT_l)) + if (StringRef(Lib).startswith("msvcr") || Lib == "ucrtbase") + return; CmdArgs.push_back("-lmsvcrt"); } @@ -104,14 +107,6 @@ void tools::MinGW::Linker::ConstructJob(Compilation &C, const JobAction &JA, // handled somewhere else. Args.ClaimAllArgs(options::OPT_w); - StringRef LinkerName = Args.getLastArgValue(options::OPT_fuse_ld_EQ, "ld"); - if (LinkerName.equals_lower("lld")) { - CmdArgs.push_back("-flavor"); - CmdArgs.push_back("gnu"); - } else if (!LinkerName.equals_lower("ld")) { - D.Diag(diag::err_drv_unsupported_linker) << LinkerName; - } - if (!D.SysRoot.empty()) CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot)); @@ -119,12 +114,24 @@ void tools::MinGW::Linker::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-s"); CmdArgs.push_back("-m"); - if (TC.getArch() == llvm::Triple::x86) + switch (TC.getArch()) { + case llvm::Triple::x86: CmdArgs.push_back("i386pe"); - if (TC.getArch() == llvm::Triple::x86_64) + break; + case llvm::Triple::x86_64: CmdArgs.push_back("i386pep"); - if (TC.getArch() == llvm::Triple::arm) + break; + case llvm::Triple::arm: + case llvm::Triple::thumb: + // FIXME: this is incorrect for WinCE CmdArgs.push_back("thumb2pe"); + break; + case llvm::Triple::aarch64: + CmdArgs.push_back("arm64pe"); + break; + default: + llvm_unreachable("Unsupported target architecture."); + } if (Args.hasArg(options::OPT_mwindows)) { CmdArgs.push_back("--subsystem"); @@ -185,8 +192,7 @@ void tools::MinGW::Linker::ConstructJob(Compilation &C, const JobAction &JA, // TODO: Add profile stuff here - if (D.CCCIsCXX() && - !Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { + if (TC.ShouldLinkCXXStdlib(Args)) { bool OnlyLibstdcxxStatic = Args.hasArg(options::OPT_static_libstdcxx) && !Args.hasArg(options::OPT_static); if (OnlyLibstdcxxStatic) @@ -230,7 +236,7 @@ void tools::MinGW::Linker::ConstructJob(Compilation &C, const JobAction &JA, if (Args.hasArg(options::OPT_static)) CmdArgs.push_back("--end-group"); - else if (!LinkerName.equals_lower("lld")) + else AddLibGCC(Args, CmdArgs); } @@ -241,7 +247,7 @@ void tools::MinGW::Linker::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back(Args.MakeArgString(TC.GetFilePath("crtend.o"))); } } - const char *Exec = Args.MakeArgString(TC.GetProgramPath(LinkerName.data())); + const char *Exec = Args.MakeArgString(TC.GetLinkerPath()); C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); } @@ -361,8 +367,11 @@ bool toolchains::MinGW::isPICDefaultForced() const { return getArch() == llvm::Triple::x86_64; } -bool toolchains::MinGW::UseSEHExceptions() const { - return getArch() == llvm::Triple::x86_64; +llvm::ExceptionHandling +toolchains::MinGW::GetExceptionModel(const ArgList &Args) const { + if (getArch() == llvm::Triple::x86_64) + return llvm::ExceptionHandling::WinEH; + return llvm::ExceptionHandling::DwarfCFI; } void toolchains::MinGW::AddCudaIncludeArgs(const ArgList &DriverArgs, diff --git a/lib/Driver/ToolChains/MinGW.h b/lib/Driver/ToolChains/MinGW.h index 9b3d7c553f1d..f8dbcae62756 100644 --- a/lib/Driver/ToolChains/MinGW.h +++ b/lib/Driver/ToolChains/MinGW.h @@ -64,7 +64,9 @@ public: bool isPICDefault() const override; bool isPIEDefault() const override; bool isPICDefaultForced() const override; - bool UseSEHExceptions() const; + + llvm::ExceptionHandling GetExceptionModel( + const llvm::opt::ArgList &Args) const override; void AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, diff --git a/lib/Driver/ToolChains/Minix.cpp b/lib/Driver/ToolChains/Minix.cpp index 2e8939c40150..39e6f90b6ef0 100644 --- a/lib/Driver/ToolChains/Minix.cpp +++ b/lib/Driver/ToolChains/Minix.cpp @@ -72,7 +72,8 @@ void tools::minix::Linker::ConstructJob(Compilation &C, const JobAction &JA, if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { if (D.CCCIsCXX()) { - getToolChain().AddCXXStdlibLibArgs(Args, CmdArgs); + if (getToolChain().ShouldLinkCXXStdlib(Args)) + getToolChain().AddCXXStdlibLibArgs(Args, CmdArgs); CmdArgs.push_back("-lm"); } } diff --git a/lib/Driver/ToolChains/NaCl.cpp b/lib/Driver/ToolChains/NaCl.cpp index 5eb5c74f1310..128478d63871 100644 --- a/lib/Driver/ToolChains/NaCl.cpp +++ b/lib/Driver/ToolChains/NaCl.cpp @@ -133,13 +133,15 @@ void nacltools::Linker::ConstructJob(Compilation &C, const JobAction &JA, if (D.CCCIsCXX() && !Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { - bool OnlyLibstdcxxStatic = - Args.hasArg(options::OPT_static_libstdcxx) && !IsStatic; - if (OnlyLibstdcxxStatic) - CmdArgs.push_back("-Bstatic"); - ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs); - if (OnlyLibstdcxxStatic) - CmdArgs.push_back("-Bdynamic"); + if (ToolChain.ShouldLinkCXXStdlib(Args)) { + bool OnlyLibstdcxxStatic = + Args.hasArg(options::OPT_static_libstdcxx) && !IsStatic; + if (OnlyLibstdcxxStatic) + CmdArgs.push_back("-Bstatic"); + ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs); + if (OnlyLibstdcxxStatic) + CmdArgs.push_back("-Bdynamic"); + } CmdArgs.push_back("-lm"); } diff --git a/lib/Driver/ToolChains/NetBSD.cpp b/lib/Driver/ToolChains/NetBSD.cpp index a1a3108cb28d..0db6578f7407 100644 --- a/lib/Driver/ToolChains/NetBSD.cpp +++ b/lib/Driver/ToolChains/NetBSD.cpp @@ -278,7 +278,8 @@ void netbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA, if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { addOpenMPRuntime(CmdArgs, getToolChain(), Args); if (D.CCCIsCXX()) { - getToolChain().AddCXXStdlibLibArgs(Args, CmdArgs); + if (getToolChain().ShouldLinkCXXStdlib(Args)) + getToolChain().AddCXXStdlibLibArgs(Args, CmdArgs); CmdArgs.push_back("-lm"); } if (NeedsSanitizerDeps) @@ -324,7 +325,7 @@ void netbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA, NetBSD::NetBSD(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) : Generic_ELF(D, Triple, Args) { - if (getDriver().UseStdLib) { + if (!Args.hasArg(options::OPT_nostdlib)) { // When targeting a 32-bit platform, try the special directory used on // 64-bit hosts, and only fall back to the main library directory if that // doesn't work. @@ -415,11 +416,34 @@ void NetBSD::addLibStdCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, "", DriverArgs, CC1Args); } +llvm::ExceptionHandling NetBSD::GetExceptionModel(const ArgList &Args) const { + // NetBSD uses Dwarf exceptions on ARM. + llvm::Triple::ArchType TArch = getTriple().getArch(); + if (TArch == llvm::Triple::arm || TArch == llvm::Triple::armeb || + TArch == llvm::Triple::thumb || TArch == llvm::Triple::thumbeb) + return llvm::ExceptionHandling::DwarfCFI; + return llvm::ExceptionHandling::None; +} + SanitizerMask NetBSD::getSupportedSanitizers() const { + const bool IsX86 = getTriple().getArch() == llvm::Triple::x86; const bool IsX86_64 = getTriple().getArch() == llvm::Triple::x86_64; SanitizerMask Res = ToolChain::getSupportedSanitizers(); - if (IsX86_64) { + if (IsX86 || IsX86_64) { Res |= SanitizerKind::Address; + Res |= SanitizerKind::Function; + Res |= SanitizerKind::Leak; + Res |= SanitizerKind::SafeStack; + Res |= SanitizerKind::Scudo; + Res |= SanitizerKind::Vptr; + } + if (IsX86_64) { + Res |= SanitizerKind::Efficiency; + Res |= SanitizerKind::Fuzzer; + Res |= SanitizerKind::FuzzerNoLink; + Res |= SanitizerKind::KernelAddress; + Res |= SanitizerKind::Memory; + Res |= SanitizerKind::Thread; } return Res; } diff --git a/lib/Driver/ToolChains/NetBSD.h b/lib/Driver/ToolChains/NetBSD.h index 5163ff72d81b..e98df72ce65c 100644 --- a/lib/Driver/ToolChains/NetBSD.h +++ b/lib/Driver/ToolChains/NetBSD.h @@ -69,6 +69,9 @@ public: return true; } + llvm::ExceptionHandling GetExceptionModel( + const llvm::opt::ArgList &Args) const override; + SanitizerMask getSupportedSanitizers() const override; protected: diff --git a/lib/Driver/ToolChains/OpenBSD.cpp b/lib/Driver/ToolChains/OpenBSD.cpp index 1d54a1e9cbb0..fbb84a62ca89 100644 --- a/lib/Driver/ToolChains/OpenBSD.cpp +++ b/lib/Driver/ToolChains/OpenBSD.cpp @@ -179,7 +179,8 @@ void openbsd::Linker::ConstructJob(Compilation &C, const JobAction &JA, if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { if (D.CCCIsCXX()) { - getToolChain().AddCXXStdlibLibArgs(Args, CmdArgs); + if (getToolChain().ShouldLinkCXXStdlib(Args)) + getToolChain().AddCXXStdlibLibArgs(Args, CmdArgs); if (Args.hasArg(options::OPT_pg)) CmdArgs.push_back("-lm_p"); else diff --git a/lib/Driver/ToolChains/PS4CPU.cpp b/lib/Driver/ToolChains/PS4CPU.cpp index c1b8c3d66077..b37fe7d1f9b9 100644 --- a/lib/Driver/ToolChains/PS4CPU.cpp +++ b/lib/Driver/ToolChains/PS4CPU.cpp @@ -227,7 +227,8 @@ static void ConstructGoldLinkJob(const Tool &T, Compilation &C, // libraries for both C and C++ compilations. CmdArgs.push_back("-lkernel"); if (D.CCCIsCXX()) { - ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs); + if (ToolChain.ShouldLinkCXXStdlib(Args)) + ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs); if (Args.hasArg(options::OPT_pg)) CmdArgs.push_back("-lm_p"); else diff --git a/lib/Driver/ToolChains/Solaris.cpp b/lib/Driver/ToolChains/Solaris.cpp index de98d11b2dc7..9fe6e9d520d0 100644 --- a/lib/Driver/ToolChains/Solaris.cpp +++ b/lib/Driver/ToolChains/Solaris.cpp @@ -100,7 +100,7 @@ void solaris::Linker::ConstructJob(Compilation &C, const JobAction &JA, AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA); if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { - if (getToolChain().getDriver().CCCIsCXX()) + if (getToolChain().ShouldLinkCXXStdlib(Args)) getToolChain().AddCXXStdlibLibArgs(Args, CmdArgs); CmdArgs.push_back("-lgcc_s"); CmdArgs.push_back("-lc"); diff --git a/lib/Driver/ToolChains/WebAssembly.cpp b/lib/Driver/ToolChains/WebAssembly.cpp index 058bc42323e2..8ae1b6c2f55d 100644 --- a/lib/Driver/ToolChains/WebAssembly.cpp +++ b/lib/Driver/ToolChains/WebAssembly.cpp @@ -38,46 +38,25 @@ void wasm::Linker::ConstructJob(Compilation &C, const JobAction &JA, const char *LinkingOutput) const { const ToolChain &ToolChain = getToolChain(); - const Driver &D = ToolChain.getDriver(); const char *Linker = Args.MakeArgString(ToolChain.GetLinkerPath()); ArgStringList CmdArgs; CmdArgs.push_back("-flavor"); CmdArgs.push_back("wasm"); - // Enable garbage collection of unused input sections by default, since code - // size is of particular importance. This is significantly facilitated by - // the enabling of -ffunction-sections and -fdata-sections in - // Clang::ConstructJob. - if (areOptimizationsEnabled(Args)) - CmdArgs.push_back("--gc-sections"); - - if (Args.hasArg(options::OPT_rdynamic)) - CmdArgs.push_back("-export-dynamic"); if (Args.hasArg(options::OPT_s)) CmdArgs.push_back("--strip-all"); - if (Args.hasArg(options::OPT_shared)) - CmdArgs.push_back("-shared"); - if (Args.hasArg(options::OPT_static)) - CmdArgs.push_back("-Bstatic"); Args.AddAllArgs(CmdArgs, options::OPT_L); + Args.AddAllArgs(CmdArgs, options::OPT_u); ToolChain.AddFilePathLibArgs(Args, CmdArgs); - if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) { - if (Args.hasArg(options::OPT_shared)) - CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("rcrt1.o"))); - else if (Args.hasArg(options::OPT_pie)) - CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("Scrt1.o"))); - else - CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crt1.o"))); - - CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crti.o"))); - } + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) + CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crt1.o"))); AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA); if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { - if (D.CCCIsCXX()) + if (ToolChain.ShouldLinkCXXStdlib(Args)) ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs); if (Args.hasArg(options::OPT_pthread)) @@ -86,12 +65,9 @@ void wasm::Linker::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-allow-undefined-file"); CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("wasm.syms"))); CmdArgs.push_back("-lc"); - CmdArgs.push_back("-lcompiler_rt"); + AddRunTimeLibs(ToolChain, ToolChain.getDriver(), CmdArgs, Args); } - if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) - CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtn.o"))); - CmdArgs.push_back("-o"); CmdArgs.push_back(Output.getFilename()); @@ -123,9 +99,6 @@ bool WebAssembly::isPICDefaultForced() const { return false; } bool WebAssembly::IsIntegratedAssemblerDefault() const { return true; } -// TODO: Support Objective C stuff. -bool WebAssembly::SupportsObjCGC() const { return false; } - bool WebAssembly::hasBlocksRuntime() const { return false; } // TODO: Support profiling. @@ -163,6 +136,14 @@ void WebAssembly::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs, getDriver().SysRoot + "/include/c++/v1"); } +std::string WebAssembly::getThreadModel() const { + // The WebAssembly MVP does not yet support threads; for now, use the + // "single" threading model, which lowers atomics to non-atomic operations. + // When threading support is standardized and implemented in popular engines, + // this override should be removed. + return "single"; +} + Tool *WebAssembly::buildLinker() const { return new tools::wasm::Linker(*this); } diff --git a/lib/Driver/ToolChains/WebAssembly.h b/lib/Driver/ToolChains/WebAssembly.h index 2999db477f79..8784e12dfb0e 100644 --- a/lib/Driver/ToolChains/WebAssembly.h +++ b/lib/Driver/ToolChains/WebAssembly.h @@ -49,7 +49,6 @@ private: bool isPICDefaultForced() const override; bool IsIntegratedAssemblerDefault() const override; bool hasBlocksRuntime() const override; - bool SupportsObjCGC() const override; bool SupportsProfiling() const override; bool HasNativeLLVMSupport() const override; void addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, @@ -63,6 +62,7 @@ private: void AddClangCXXStdlibIncludeArgs( const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args) const override; + std::string getThreadModel() const override; const char *getDefaultLinker() const override { return "lld"; |