diff options
author | David L. Jones <dlj@google.com> | 2017-03-08 01:02:16 +0000 |
---|---|---|
committer | David L. Jones <dlj@google.com> | 2017-03-08 01:02:16 +0000 |
commit | 1c814d10cf1a5085e5b0496c6707b3c44ba86eb5 (patch) | |
tree | 4ed99109d1c3686579c17615e526479fb7b58bfe /lib/Driver | |
parent | 8e9494e0deb9375409f9fe35996d67145bc5fde1 (diff) | |
download | clang-1c814d10cf1a5085e5b0496c6707b3c44ba86eb5.tar.gz |
[Driver] Consolidate tools and toolchains by target platform. (NFC)
Summary:
(This is a move-only refactoring patch. There are no functionality changes.)
This patch splits apart the Clang driver's tool and toolchain implementation
files. Each target platform toolchain is moved to its own file, along with the
closest-related tools. Each target platform toolchain has separate headers and
implementation files, so the hierarchy of classes is unchanged.
There are some remaining shared free functions, mostly from Tools.cpp. Several
of these move to their own architecture-specific files, similar to r296056. Some
of them are only used by a single target platform; since the tools and
toolchains are now together, some helpers now live in a platform-specific file.
The balance are helpers related to manipulating argument lists, so they are now
in a new file pair, CommonArgs.h and .cpp.
I've tried to cluster the code logically, which is fairly straightforward for
most of the target platforms and shared architectures. I think I've made
reasonable choices for these, as well as the various shared helpers; but of
course, I'm happy to hear feedback in the review.
There are some particular things I don't like about this patch, but haven't been
able to find a better overall solution. The first is the proliferation of files:
there are several files that are tiny because the toolchain is not very
different from its base (usually the Gnu tools/toolchain). I think this is
mostly a reflection of the true complexity, though, so it may not be "fixable"
in any reasonable sense. The second thing I don't like are the includes like
"../Something.h". I've avoided this largely by clustering into the current file
structure. However, a few of these includes remain, and in those cases it
doesn't make sense to me to sink an existing file any deeper.
Reviewers: rsmith, mehdi_amini, compnerd, rnk, javed.absar
Subscribers: emaste, jfb, danalbert, srhines, dschuff, jyknight, nemanjai, nhaehnle, mgorny, cfe-commits
Differential Revision: https://reviews.llvm.org/D30372
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@297250 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Driver')
86 files changed, 20919 insertions, 19213 deletions
diff --git a/lib/Driver/CMakeLists.txt b/lib/Driver/CMakeLists.txt index 3d03da04d1..24230195ec 100644 --- a/lib/Driver/CMakeLists.txt +++ b/lib/Driver/CMakeLists.txt @@ -10,28 +10,53 @@ endif() add_clang_library(clangDriver Action.cpp - Arch/AArch64.cpp - Arch/ARM.cpp - Arch/Mips.cpp - Arch/PPC.cpp - Arch/Sparc.cpp - Arch/SystemZ.cpp - Arch/X86.cpp Compilation.cpp - CrossWindowsToolChain.cpp Distro.cpp Driver.cpp DriverOptions.cpp Job.cpp - MSVCToolChain.cpp - MinGWToolChain.cpp Multilib.cpp Phases.cpp SanitizerArgs.cpp Tool.cpp ToolChain.cpp - ToolChains.cpp - Tools.cpp + ToolChains/Arch/AArch64.cpp + ToolChains/Arch/ARM.cpp + ToolChains/Arch/Mips.cpp + ToolChains/Arch/PPC.cpp + ToolChains/Arch/Sparc.cpp + ToolChains/Arch/SystemZ.cpp + ToolChains/Arch/X86.cpp + ToolChains/AMDGPU.cpp + ToolChains/AVR.cpp + ToolChains/Bitrig.cpp + ToolChains/Clang.cpp + ToolChains/CloudABI.cpp + ToolChains/CommonArgs.cpp + ToolChains/Contiki.cpp + ToolChains/CrossWindows.cpp + ToolChains/Cuda.cpp + ToolChains/Darwin.cpp + ToolChains/DragonFly.cpp + ToolChains/FreeBSD.cpp + ToolChains/Fuchsia.cpp + ToolChains/Gnu.cpp + ToolChains/Haiku.cpp + ToolChains/Hexagon.cpp + ToolChains/Linux.cpp + ToolChains/Mips.cpp + ToolChains/MinGW.cpp + ToolChains/Minix.cpp + ToolChains/MSVC.cpp + ToolChains/Myriad.cpp + ToolChains/NaCl.cpp + ToolChains/NetBSD.cpp + ToolChains/OpenBSD.cpp + ToolChains/PS4CPU.cpp + ToolChains/Solaris.cpp + ToolChains/TCE.cpp + ToolChains/WebAssembly.cpp + ToolChains/XCore.cpp Types.cpp DEPENDS diff --git a/lib/Driver/CrossWindowsToolChain.cpp b/lib/Driver/CrossWindowsToolChain.cpp deleted file mode 100644 index 28036ea51c..0000000000 --- a/lib/Driver/CrossWindowsToolChain.cpp +++ /dev/null @@ -1,125 +0,0 @@ -//===--- CrossWindowsToolChain.cpp - Cross Windows Tool Chain -------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "ToolChains.h" -#include "clang/Driver/Driver.h" -#include "clang/Driver/Options.h" -#include "llvm/Option/ArgList.h" -#include "llvm/Support/Path.h" - -using namespace clang::driver; -using namespace clang::driver::toolchains; - -CrossWindowsToolChain::CrossWindowsToolChain(const Driver &D, - const llvm::Triple &T, - const llvm::opt::ArgList &Args) - : Generic_GCC(D, T, Args) { - if (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"); - } -} - -bool CrossWindowsToolChain::IsUnwindTablesDefault() const { - // FIXME: all non-x86 targets need unwind tables, however, LLVM currently does - // not know how to emit them. - return getArch() == llvm::Triple::x86_64; -} - -bool CrossWindowsToolChain::isPICDefault() const { - return getArch() == llvm::Triple::x86_64; -} - -bool CrossWindowsToolChain::isPIEDefault() const { - return getArch() == llvm::Triple::x86_64; -} - -bool CrossWindowsToolChain::isPICDefaultForced() const { - return getArch() == llvm::Triple::x86_64; -} - -void CrossWindowsToolChain:: -AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args) const { - const Driver &D = getDriver(); - const std::string &SysRoot = D.SysRoot; - - if (DriverArgs.hasArg(options::OPT_nostdlibinc)) - return; - - addSystemInclude(DriverArgs, CC1Args, SysRoot + "/usr/local/include"); - if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) { - SmallString<128> ResourceDir(D.ResourceDir); - llvm::sys::path::append(ResourceDir, "include"); - addSystemInclude(DriverArgs, CC1Args, ResourceDir); - } - for (const auto &P : DriverArgs.getAllArgValues(options::OPT_isystem_after)) - addSystemInclude(DriverArgs, CC1Args, P); - addExternCSystemInclude(DriverArgs, CC1Args, SysRoot + "/usr/include"); -} - -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_nostdlibinc) || - DriverArgs.hasArg(options::OPT_nostdincxx)) - return; - - switch (GetCXXStdlibType(DriverArgs)) { - case 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: - 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 { - SanitizerMask Res = ToolChain::getSupportedSanitizers(); - Res |= SanitizerKind::Address; - return Res; -} - -Tool *CrossWindowsToolChain::buildLinker() const { - return new tools::CrossWindows::Linker(*this); -} - -Tool *CrossWindowsToolChain::buildAssembler() const { - return new tools::CrossWindows::Assembler(*this); -} diff --git a/lib/Driver/Driver.cpp b/lib/Driver/Driver.cpp index 78e99d43dd..f509205bd6 100644 --- a/lib/Driver/Driver.cpp +++ b/lib/Driver/Driver.cpp @@ -9,7 +9,36 @@ #include "clang/Driver/Driver.h" #include "InputInfo.h" -#include "ToolChains.h" +#include "ToolChains/AMDGPU.h" +#include "ToolChains/AVR.h" +#include "ToolChains/Bitrig.h" +#include "ToolChains/Clang.h" +#include "ToolChains/CloudABI.h" +#include "ToolChains/Contiki.h" +#include "ToolChains/CrossWindows.h" +#include "ToolChains/Cuda.h" +#include "ToolChains/Darwin.h" +#include "ToolChains/DragonFly.h" +#include "ToolChains/FreeBSD.h" +#include "ToolChains/Fuchsia.h" +#include "ToolChains/Gnu.h" +#include "ToolChains/Haiku.h" +#include "ToolChains/Hexagon.h" +#include "ToolChains/Lanai.h" +#include "ToolChains/Linux.h" +#include "ToolChains/MinGW.h" +#include "ToolChains/Minix.h" +#include "ToolChains/Mips.h" +#include "ToolChains/MSVC.h" +#include "ToolChains/Myriad.h" +#include "ToolChains/NaCl.h" +#include "ToolChains/NetBSD.h" +#include "ToolChains/OpenBSD.h" +#include "ToolChains/PS4CPU.h" +#include "ToolChains/Solaris.h" +#include "ToolChains/TCE.h" +#include "ToolChains/WebAssembly.h" +#include "ToolChains/XCore.h" #include "clang/Basic/Version.h" #include "clang/Basic/VirtualFileSystem.h" #include "clang/Config/config.h" diff --git a/lib/Driver/MinGWToolChain.cpp b/lib/Driver/MinGWToolChain.cpp deleted file mode 100644 index 7fa786ef1c..0000000000 --- a/lib/Driver/MinGWToolChain.cpp +++ /dev/null @@ -1,241 +0,0 @@ -//===--- MinGWToolChain.cpp - MinGWToolChain Implementation ---------------===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "ToolChains.h" -#include "clang/Driver/Driver.h" -#include "clang/Driver/Options.h" -#include "llvm/Option/ArgList.h" -#include "llvm/Support/FileSystem.h" -#include "llvm/Support/Path.h" - -using namespace clang::diag; -using namespace clang::driver; -using namespace clang::driver::toolchains; -using namespace clang; -using namespace llvm::opt; - -// Simplified from Generic_GCC::GCCInstallationDetector::ScanLibDirForGCCTriple. -static bool findGccVersion(StringRef LibDir, std::string &GccLibDir, - std::string &Ver) { - Generic_GCC::GCCVersion Version = Generic_GCC::GCCVersion::Parse("0.0.0"); - std::error_code EC; - for (llvm::sys::fs::directory_iterator LI(LibDir, EC), LE; !EC && LI != LE; - LI = LI.increment(EC)) { - StringRef VersionText = llvm::sys::path::filename(LI->path()); - Generic_GCC::GCCVersion CandidateVersion = - Generic_GCC::GCCVersion::Parse(VersionText); - if (CandidateVersion.Major == -1) - continue; - if (CandidateVersion <= Version) - continue; - Ver = VersionText; - GccLibDir = LI->path(); - } - return Ver.size(); -} - -void MinGW::findGccLibDir() { - llvm::SmallVector<llvm::SmallString<32>, 2> Archs; - Archs.emplace_back(getTriple().getArchName()); - Archs[0] += "-w64-mingw32"; - Archs.emplace_back("mingw32"); - Arch = Archs[0].str(); - // lib: Arch Linux, Ubuntu, Windows - // lib64: openSUSE Linux - for (StringRef CandidateLib : {"lib", "lib64"}) { - for (StringRef CandidateArch : Archs) { - llvm::SmallString<1024> LibDir(Base); - llvm::sys::path::append(LibDir, CandidateLib, "gcc", CandidateArch); - if (findGccVersion(LibDir, GccLibDir, Ver)) { - Arch = CandidateArch; - return; - } - } - } -} - -MinGW::MinGW(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) - : ToolChain(D, Triple, Args), CudaInstallation(D, Triple, Args) { - getProgramPaths().push_back(getDriver().getInstalledDir()); - -// In Windows there aren't any standard install locations, we search -// for gcc on the PATH. In Linux the base is always /usr. -#ifdef LLVM_ON_WIN32 - if (getDriver().SysRoot.size()) - Base = getDriver().SysRoot; - else if (llvm::ErrorOr<std::string> GPPName = - llvm::sys::findProgramByName("gcc")) - Base = llvm::sys::path::parent_path( - llvm::sys::path::parent_path(GPPName.get())); - else - Base = llvm::sys::path::parent_path(getDriver().getInstalledDir()); -#else - if (getDriver().SysRoot.size()) - Base = getDriver().SysRoot; - else - Base = "/usr"; -#endif - - Base += llvm::sys::path::get_separator(); - findGccLibDir(); - // GccLibDir must precede Base/lib so that the - // correct crtbegin.o ,cetend.o would be found. - getFilePaths().push_back(GccLibDir); - getFilePaths().push_back( - (Base + Arch + llvm::sys::path::get_separator() + "lib").str()); - getFilePaths().push_back(Base + "lib"); - // openSUSE - getFilePaths().push_back(Base + Arch + "/sys-root/mingw/lib"); -} - -bool MinGW::IsIntegratedAssemblerDefault() const { return true; } - -Tool *MinGW::getTool(Action::ActionClass AC) const { - switch (AC) { - case Action::PreprocessJobClass: - if (!Preprocessor) - Preprocessor.reset(new tools::gcc::Preprocessor(*this)); - return Preprocessor.get(); - case Action::CompileJobClass: - if (!Compiler) - Compiler.reset(new tools::gcc::Compiler(*this)); - return Compiler.get(); - default: - return ToolChain::getTool(AC); - } -} - -Tool *MinGW::buildAssembler() const { - return new tools::MinGW::Assembler(*this); -} - -Tool *MinGW::buildLinker() const { return new tools::MinGW::Linker(*this); } - -bool MinGW::IsUnwindTablesDefault() const { - return getArch() == llvm::Triple::x86_64; -} - -bool MinGW::isPICDefault() const { return getArch() == llvm::Triple::x86_64; } - -bool MinGW::isPIEDefault() const { return false; } - -bool MinGW::isPICDefaultForced() const { - return getArch() == llvm::Triple::x86_64; -} - -bool MinGW::UseSEHExceptions() const { - return getArch() == llvm::Triple::x86_64; -} - -void MinGW::AddCudaIncludeArgs(const ArgList &DriverArgs, - ArgStringList &CC1Args) const { - CudaInstallation.AddCudaIncludeArgs(DriverArgs, CC1Args); -} - -void MinGW::printVerboseInfo(raw_ostream &OS) const { - CudaInstallation.print(OS); -} - -// Include directories for various hosts: - -// Windows, mingw.org -// c:\mingw\lib\gcc\mingw32\4.8.1\include\c++ -// c:\mingw\lib\gcc\mingw32\4.8.1\include\c++\mingw32 -// c:\mingw\lib\gcc\mingw32\4.8.1\include\c++\backward -// c:\mingw\include -// c:\mingw\mingw32\include - -// Windows, mingw-w64 mingw-builds -// c:\mingw32\i686-w64-mingw32\include -// c:\mingw32\i686-w64-mingw32\include\c++ -// c:\mingw32\i686-w64-mingw32\include\c++\i686-w64-mingw32 -// c:\mingw32\i686-w64-mingw32\include\c++\backward - -// Windows, mingw-w64 msys2 -// c:\msys64\mingw32\include -// c:\msys64\mingw32\i686-w64-mingw32\include -// c:\msys64\mingw32\include\c++\4.9.2 -// c:\msys64\mingw32\include\c++\4.9.2\i686-w64-mingw32 -// c:\msys64\mingw32\include\c++\4.9.2\backward - -// openSUSE -// /usr/lib64/gcc/x86_64-w64-mingw32/5.1.0/include/c++ -// /usr/lib64/gcc/x86_64-w64-mingw32/5.1.0/include/c++/x86_64-w64-mingw32 -// /usr/lib64/gcc/x86_64-w64-mingw32/5.1.0/include/c++/backward -// /usr/x86_64-w64-mingw32/sys-root/mingw/include - -// Arch Linux -// /usr/i686-w64-mingw32/include/c++/5.1.0 -// /usr/i686-w64-mingw32/include/c++/5.1.0/i686-w64-mingw32 -// /usr/i686-w64-mingw32/include/c++/5.1.0/backward -// /usr/i686-w64-mingw32/include - -// Ubuntu -// /usr/include/c++/4.8 -// /usr/include/c++/4.8/x86_64-w64-mingw32 -// /usr/include/c++/4.8/backward -// /usr/x86_64-w64-mingw32/include - -void MinGW::AddClangSystemIncludeArgs(const ArgList &DriverArgs, - ArgStringList &CC1Args) const { - if (DriverArgs.hasArg(options::OPT_nostdinc)) - return; - - if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) { - SmallString<1024> P(getDriver().ResourceDir); - llvm::sys::path::append(P, "include"); - addSystemInclude(DriverArgs, CC1Args, P.str()); - } - - if (DriverArgs.hasArg(options::OPT_nostdlibinc)) - return; - - if (GetRuntimeLibType(DriverArgs) == ToolChain::RLT_Libgcc) { - // openSUSE - addSystemInclude(DriverArgs, CC1Args, - Base + Arch + "/sys-root/mingw/include"); - } - - addSystemInclude(DriverArgs, CC1Args, - Base + Arch + llvm::sys::path::get_separator() + "include"); - addSystemInclude(DriverArgs, CC1Args, Base + "include"); -} - -void MinGW::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs, - ArgStringList &CC1Args) const { - if (DriverArgs.hasArg(options::OPT_nostdlibinc) || - DriverArgs.hasArg(options::OPT_nostdincxx)) - return; - - switch (GetCXXStdlibType(DriverArgs)) { - case ToolChain::CST_Libcxx: - addSystemInclude(DriverArgs, CC1Args, - Base + "include" + llvm::sys::path::get_separator() + - "c++" + llvm::sys::path::get_separator() + "v1"); - break; - - case ToolChain::CST_Libstdcxx: - llvm::SmallVector<llvm::SmallString<1024>, 4> CppIncludeBases; - CppIncludeBases.emplace_back(Base); - llvm::sys::path::append(CppIncludeBases[0], Arch, "include", "c++"); - CppIncludeBases.emplace_back(Base); - llvm::sys::path::append(CppIncludeBases[1], Arch, "include", "c++", Ver); - CppIncludeBases.emplace_back(Base); - llvm::sys::path::append(CppIncludeBases[2], "include", "c++", Ver); - CppIncludeBases.emplace_back(GccLibDir); - llvm::sys::path::append(CppIncludeBases[3], "include", "c++"); - for (auto &CppIncludeBase : CppIncludeBases) { - addSystemInclude(DriverArgs, CC1Args, CppIncludeBase); - CppIncludeBase += llvm::sys::path::get_separator(); - addSystemInclude(DriverArgs, CC1Args, CppIncludeBase + Arch); - addSystemInclude(DriverArgs, CC1Args, CppIncludeBase + "backward"); - } - break; - } -} diff --git a/lib/Driver/Multilib.cpp b/lib/Driver/Multilib.cpp index a88edf7f04..43b62f7b36 100644 --- a/lib/Driver/Multilib.cpp +++ b/lib/Driver/Multilib.cpp @@ -8,7 +8,7 @@ //===----------------------------------------------------------------------===// #include "clang/Driver/Multilib.h" -#include "Tools.h" +#include "ToolChains/CommonArgs.h" #include "clang/Driver/Options.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringRef.h" diff --git a/lib/Driver/SanitizerArgs.cpp b/lib/Driver/SanitizerArgs.cpp index f4f6dad9f2..b0f2caefc9 100644 --- a/lib/Driver/SanitizerArgs.cpp +++ b/lib/Driver/SanitizerArgs.cpp @@ -7,7 +7,7 @@ // //===----------------------------------------------------------------------===// #include "clang/Driver/SanitizerArgs.h" -#include "Tools.h" +#include "ToolChains/CommonArgs.h" #include "clang/Basic/Sanitizers.h" #include "clang/Driver/Driver.h" #include "clang/Driver/DriverDiagnostic.h" diff --git a/lib/Driver/ToolChain.cpp b/lib/Driver/ToolChain.cpp index 5a2ed0bd69..fbbdb1a19a 100644 --- a/lib/Driver/ToolChain.cpp +++ b/lib/Driver/ToolChain.cpp @@ -8,7 +8,9 @@ //===----------------------------------------------------------------------===// #include "clang/Driver/ToolChain.h" -#include "Tools.h" +#include "ToolChains/CommonArgs.h" +#include "ToolChains/Arch/ARM.h" +#include "ToolChains/Clang.h" #include "clang/Basic/ObjCRuntime.h" #include "clang/Basic/VirtualFileSystem.h" #include "clang/Config/config.h" diff --git a/lib/Driver/ToolChains.cpp b/lib/Driver/ToolChains.cpp deleted file mode 100644 index 26c4fca9aa..0000000000 --- a/lib/Driver/ToolChains.cpp +++ /dev/null @@ -1,5360 +0,0 @@ -//===--- ToolChains.cpp - 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 "ToolChains.h" -#include "clang/Basic/Cuda.h" -#include "clang/Basic/ObjCRuntime.h" -#include "clang/Basic/Version.h" -#include "clang/Basic/VirtualFileSystem.h" -#include "clang/Config/config.h" // for GCC_INSTALL_PREFIX -#include "clang/Driver/Compilation.h" -#include "clang/Driver/Distro.h" -#include "clang/Driver/Driver.h" -#include "clang/Driver/DriverDiagnostic.h" -#include "clang/Driver/Options.h" -#include "clang/Driver/SanitizerArgs.h" -#include "llvm/ADT/STLExtras.h" -#include "llvm/ADT/SmallString.h" -#include "llvm/ADT/StringExtras.h" -#include "llvm/ADT/StringSwitch.h" -#include "llvm/Option/Arg.h" -#include "llvm/Option/ArgList.h" -#include "llvm/Option/OptTable.h" -#include "llvm/Option/Option.h" -#include "llvm/ProfileData/InstrProf.h" -#include "llvm/Support/ErrorHandling.h" -#include "llvm/Support/FileSystem.h" -#include "llvm/Support/MemoryBuffer.h" -#include "llvm/Support/Path.h" -#include "llvm/Support/Program.h" -#include "llvm/Support/TargetParser.h" -#include "llvm/Support/raw_ostream.h" -#include <cstdlib> // ::getenv -#include <system_error> - -using namespace clang::driver; -using namespace clang::driver::toolchains; -using namespace clang; -using namespace llvm::opt; - -MachO::MachO(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) - : ToolChain(D, Triple, Args) { - // We expect 'as', 'ld', etc. to be adjacent to our install dir. - getProgramPaths().push_back(getDriver().getInstalledDir()); - if (getDriver().getInstalledDir() != getDriver().Dir) - getProgramPaths().push_back(getDriver().Dir); -} - -/// Darwin - Darwin tool chain for i386 and x86_64. -Darwin::Darwin(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) - : MachO(D, Triple, Args), TargetInitialized(false), - CudaInstallation(D, Triple, Args) {} - -types::ID MachO::LookupTypeForExtension(StringRef Ext) const { - types::ID Ty = types::lookupTypeForExtension(Ext); - - // Darwin always preprocesses assembly files (unless -x is used explicitly). - if (Ty == types::TY_PP_Asm) - return types::TY_Asm; - - return Ty; -} - -bool MachO::HasNativeLLVMSupport() const { return true; } - -ToolChain::CXXStdlibType Darwin::GetDefaultCXXStdlibType() const { - // Default to use libc++ on OS X 10.9+ and iOS 7+. - if ((isTargetMacOS() && !isMacosxVersionLT(10, 9)) || - (isTargetIOSBased() && !isIPhoneOSVersionLT(7, 0)) || - isTargetWatchOSBased()) - return ToolChain::CST_Libcxx; - - return ToolChain::CST_Libstdcxx; -} - -/// Darwin provides an ARC runtime starting in MacOS X 10.7 and iOS 5.0. -ObjCRuntime Darwin::getDefaultObjCRuntime(bool isNonFragile) const { - if (isTargetWatchOSBased()) - return ObjCRuntime(ObjCRuntime::WatchOS, TargetVersion); - if (isTargetIOSBased()) - return ObjCRuntime(ObjCRuntime::iOS, TargetVersion); - if (isNonFragile) - return ObjCRuntime(ObjCRuntime::MacOSX, TargetVersion); - return ObjCRuntime(ObjCRuntime::FragileMacOSX, TargetVersion); -} - -/// Darwin provides a blocks runtime starting in MacOS X 10.6 and iOS 3.2. -bool Darwin::hasBlocksRuntime() const { - if (isTargetWatchOSBased()) - return true; - else if (isTargetIOSBased()) - return !isIPhoneOSVersionLT(3, 2); - else { - assert(isTargetMacOS() && "unexpected darwin target"); - return !isMacosxVersionLT(10, 6); - } -} - -void Darwin::AddCudaIncludeArgs(const ArgList &DriverArgs, - ArgStringList &CC1Args) const { - CudaInstallation.AddCudaIncludeArgs(DriverArgs, CC1Args); -} - -// This is just a MachO name translation routine and there's no -// way to join this into ARMTargetParser without breaking all -// other assumptions. Maybe MachO should consider standardising -// their nomenclature. -static const char *ArmMachOArchName(StringRef Arch) { - return llvm::StringSwitch<const char *>(Arch) - .Case("armv6k", "armv6") - .Case("armv6m", "armv6m") - .Case("armv5tej", "armv5") - .Case("xscale", "xscale") - .Case("armv4t", "armv4t") - .Case("armv7", "armv7") - .Cases("armv7a", "armv7-a", "armv7") - .Cases("armv7r", "armv7-r", "armv7") - .Cases("armv7em", "armv7e-m", "armv7em") - .Cases("armv7k", "armv7-k", "armv7k") - .Cases("armv7m", "armv7-m", "armv7m") - .Cases("armv7s", "armv7-s", "armv7s") - .Default(nullptr); -} - -static const char *ArmMachOArchNameCPU(StringRef CPU) { - unsigned ArchKind = llvm::ARM::parseCPUArch(CPU); - if (ArchKind == llvm::ARM::AK_INVALID) - return nullptr; - StringRef Arch = llvm::ARM::getArchName(ArchKind); - - // FIXME: Make sure this MachO triple mangling is really necessary. - // ARMv5* normalises to ARMv5. - if (Arch.startswith("armv5")) - Arch = Arch.substr(0, 5); - // ARMv6*, except ARMv6M, normalises to ARMv6. - else if (Arch.startswith("armv6") && !Arch.endswith("6m")) - Arch = Arch.substr(0, 5); - // ARMv7A normalises to ARMv7. - else if (Arch.endswith("v7a")) - Arch = Arch.substr(0, 5); - return Arch.data(); -} - -static bool isSoftFloatABI(const ArgList &Args) { - Arg *A = Args.getLastArg(options::OPT_msoft_float, options::OPT_mhard_float, - options::OPT_mfloat_abi_EQ); - if (!A) - return false; - - return A->getOption().matches(options::OPT_msoft_float) || - (A->getOption().matches(options::OPT_mfloat_abi_EQ) && - A->getValue() == StringRef("soft")); -} - -StringRef MachO::getMachOArchName(const ArgList &Args) const { - switch (getTriple().getArch()) { - default: - return getDefaultUniversalArchName(); - - case llvm::Triple::aarch64: - return "arm64"; - - case llvm::Triple::thumb: - case llvm::Triple::arm: - if (const Arg *A = Args.getLastArg(options::OPT_march_EQ)) - if (const char *Arch = ArmMachOArchName(A->getValue())) - return Arch; - - if (const Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) - if (const char *Arch = ArmMachOArchNameCPU(A->getValue())) - return Arch; - - return "arm"; - } -} - -Darwin::~Darwin() {} - -MachO::~MachO() {} - -std::string Darwin::ComputeEffectiveClangTriple(const ArgList &Args, - types::ID InputType) const { - llvm::Triple Triple(ComputeLLVMTriple(Args, InputType)); - - // If the target isn't initialized (e.g., an unknown Darwin platform, return - // the default triple). - if (!isTargetInitialized()) - return Triple.getTriple(); - - SmallString<16> Str; - if (isTargetWatchOSBased()) - Str += "watchos"; - else if (isTargetTvOSBased()) - Str += "tvos"; - else if (isTargetIOSBased()) - Str += "ios"; - else - Str += "macosx"; - Str += getTargetVersion().getAsString(); - Triple.setOSName(Str); - - return Triple.getTriple(); -} - -void Generic_ELF::anchor() {} - -Tool *MachO::getTool(Action::ActionClass AC) const { - switch (AC) { - case Action::LipoJobClass: - if (!Lipo) - Lipo.reset(new tools::darwin::Lipo(*this)); - return Lipo.get(); - case Action::DsymutilJobClass: - if (!Dsymutil) - Dsymutil.reset(new tools::darwin::Dsymutil(*this)); - return Dsymutil.get(); - case Action::VerifyDebugInfoJobClass: - if (!VerifyDebug) - VerifyDebug.reset(new tools::darwin::VerifyDebug(*this)); - return VerifyDebug.get(); - default: - return ToolChain::getTool(AC); - } -} - -Tool *MachO::buildLinker() const { return new tools::darwin::Linker(*this); } - -Tool *MachO::buildAssembler() const { - return new tools::darwin::Assembler(*this); -} - -DarwinClang::DarwinClang(const Driver &D, const llvm::Triple &Triple, - const ArgList &Args) - : Darwin(D, Triple, Args) {} - -void DarwinClang::addClangWarningOptions(ArgStringList &CC1Args) const { - // For modern targets, promote certain warnings to errors. - if (isTargetWatchOSBased() || getTriple().isArch64Bit()) { - // Always enable -Wdeprecated-objc-isa-usage and promote it - // to an error. - CC1Args.push_back("-Wdeprecated-objc-isa-usage"); - CC1Args.push_back("-Werror=deprecated-objc-isa-usage"); - - // For iOS and watchOS, also error about implicit function declarations, - // as that can impact calling conventions. - if (!isTargetMacOS()) - CC1Args.push_back("-Werror=implicit-function-declaration"); - } -} - -/// \brief Determine whether Objective-C automated reference counting is -/// enabled. -static bool isObjCAutoRefCount(const ArgList &Args) { - return Args.hasFlag(options::OPT_fobjc_arc, options::OPT_fno_objc_arc, false); -} - -void DarwinClang::AddLinkARCArgs(const ArgList &Args, - ArgStringList &CmdArgs) const { - // Avoid linking compatibility stubs on i386 mac. - if (isTargetMacOS() && getArch() == llvm::Triple::x86) - return; - - ObjCRuntime runtime = getDefaultObjCRuntime(/*nonfragile*/ true); - - if ((runtime.hasNativeARC() || !isObjCAutoRefCount(Args)) && - runtime.hasSubscripting()) - return; - - CmdArgs.push_back("-force_load"); - SmallString<128> P(getDriver().ClangExecutable); - llvm::sys::path::remove_filename(P); // 'clang' - llvm::sys::path::remove_filename(P); // 'bin' - llvm::sys::path::append(P, "lib", "arc", "libarclite_"); - // Mash in the platform. - if (isTargetWatchOSSimulator()) - P += "watchsimulator"; - else if (isTargetWatchOS()) - P += "watchos"; - else if (isTargetTvOSSimulator()) - P += "appletvsimulator"; - else if (isTargetTvOS()) - P += "appletvos"; - else if (isTargetIOSSimulator()) - P += "iphonesimulator"; - else if (isTargetIPhoneOS()) - P += "iphoneos"; - else - P += "macosx"; - P += ".a"; - - CmdArgs.push_back(Args.MakeArgString(P)); -} - -unsigned DarwinClang::GetDefaultDwarfVersion() const { - // Default to use DWARF 2 on OS X 10.10 / iOS 8 and lower. - if ((isTargetMacOS() && isMacosxVersionLT(10, 11)) || - (isTargetIOSBased() && isIPhoneOSVersionLT(9))) - return 2; - return 4; -} - -void MachO::AddLinkRuntimeLib(const ArgList &Args, ArgStringList &CmdArgs, - StringRef DarwinLibName, bool AlwaysLink, - bool IsEmbedded, bool AddRPath) const { - SmallString<128> Dir(getDriver().ResourceDir); - llvm::sys::path::append(Dir, "lib", IsEmbedded ? "macho_embedded" : "darwin"); - - SmallString<128> P(Dir); - llvm::sys::path::append(P, DarwinLibName); - - // 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)); - - // 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) { - assert(DarwinLibName.endswith(".dylib") && "must be a dynamic library"); - - // Add @executable_path to rpath to support having the dylib copied with - // the executable. - CmdArgs.push_back("-rpath"); - CmdArgs.push_back("@executable_path"); - - // Add the path to the resource dir to rpath to support using the dylib - // from the default location without copying. - CmdArgs.push_back("-rpath"); - CmdArgs.push_back(Args.MakeArgString(Dir)); - } -} - -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"); -} - -StringRef Darwin::getSDKName(StringRef isysroot) { - // Assume SDK has path: SOME_PATH/SDKs/PlatformXX.YY.sdk - llvm::sys::path::const_iterator SDKDir; - auto BeginSDK = llvm::sys::path::begin(isysroot); - auto EndSDK = llvm::sys::path::end(isysroot); - for (auto IT = BeginSDK; IT != EndSDK; ++IT) { - StringRef SDK = *IT; - if (SDK.endswith(".sdk")) - return SDK.slice(0, SDK.size() - 4); - } - return ""; -} - -StringRef Darwin::getOSLibraryNameSuffix() const { - switch(TargetPlatform) { - case DarwinPlatformKind::MacOS: - return "osx"; - case DarwinPlatformKind::IPhoneOS: - return "ios"; - case DarwinPlatformKind::IPhoneOSSimulator: - return "iossim"; - case DarwinPlatformKind::TvOS: - return "tvos"; - case DarwinPlatformKind::TvOSSimulator: - return "tvossim"; - case DarwinPlatformKind::WatchOS: - return "watchos"; - case DarwinPlatformKind::WatchOSSimulator: - return "watchossim"; - } - llvm_unreachable("Unsupported platform"); -} - -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); -} - -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); -} - -ToolChain::RuntimeLibType DarwinClang::GetRuntimeLibType( - const ArgList &Args) const { - if (Arg* A = Args.getLastArg(options::OPT_rtlib_EQ)) { - StringRef Value = A->getValue(); - if (Value != "compiler-rt") - getDriver().Diag(diag::err_drv_unsupported_rtlib_for_platform) - << Value << "darwin"; - } - - return ToolChain::RLT_CompilerRT; -} - -void DarwinClang::AddLinkRuntimeLibArgs(const ArgList &Args, - ArgStringList &CmdArgs) const { - // Call once to ensure diagnostic is printed if wrong value was specified - GetRuntimeLibType(Args); - - // Darwin doesn't support real static executables, don't link any runtime - // libraries with -static. - if (Args.hasArg(options::OPT_static) || - Args.hasArg(options::OPT_fapple_kext) || - Args.hasArg(options::OPT_mkernel)) - return; - - // Reject -static-libgcc for now, we can deal with this when and if someone - // cares. This is useful in situations where someone wants to statically link - // something like libstdc++, and needs its runtime support routines. - if (const Arg *A = Args.getLastArg(options::OPT_static_libgcc)) { - getDriver().Diag(diag::err_drv_unsupported_opt) << A->getAsString(Args); - return; - } - - const SanitizerArgs &Sanitize = getSanitizerArgs(); - if (Sanitize.needsAsanRt()) - AddLinkSanitizerLibArgs(Args, CmdArgs, "asan"); - if (Sanitize.needsUbsanRt()) - AddLinkSanitizerLibArgs(Args, CmdArgs, "ubsan"); - if (Sanitize.needsTsanRt()) - AddLinkSanitizerLibArgs(Args, CmdArgs, "tsan"); - if (Sanitize.needsStatsRt()) { - StringRef OS = isTargetMacOS() ? "osx" : "iossim"; - AddLinkRuntimeLib(Args, CmdArgs, - (Twine("libclang_rt.stats_client_") + OS + ".a").str(), - /*AlwaysLink=*/true); - AddLinkSanitizerLibArgs(Args, CmdArgs, "stats"); - } - if (Sanitize.needsEsanRt()) - AddLinkSanitizerLibArgs(Args, CmdArgs, "esan"); - - // Otherwise link libSystem, then the dynamic runtime library, and finally any - // target specific static runtime library. - CmdArgs.push_back("-lSystem"); - - // Select the dynamic runtime library and the target specific static library. - if (isTargetWatchOSBased()) { - // We currently always need a static runtime library for watchOS. - AddLinkRuntimeLib(Args, CmdArgs, "libclang_rt.watchos.a"); - } else if (isTargetTvOSBased()) { - // We currently always need a static runtime library for tvOS. - AddLinkRuntimeLib(Args, CmdArgs, "libclang_rt.tvos.a"); - } else if (isTargetIOSBased()) { - // If we are compiling as iOS / simulator, don't attempt to link libgcc_s.1, - // it never went into the SDK. - // Linking against libgcc_s.1 isn't needed for iOS 5.0+ - if (isIPhoneOSVersionLT(5, 0) && !isTargetIOSSimulator() && - getTriple().getArch() != llvm::Triple::aarch64) - CmdArgs.push_back("-lgcc_s.1"); - - // We currently always need a static runtime library for iOS. - AddLinkRuntimeLib(Args, CmdArgs, "libclang_rt.ios.a"); - } else { - assert(isTargetMacOS() && "unexpected non MacOS platform"); - // The dynamic runtime library was merged with libSystem for 10.6 and - // beyond; only 10.4 and 10.5 need an additional runtime library. - if (isMacosxVersionLT(10, 5)) - CmdArgs.push_back("-lgcc_s.10.4"); - else if (isMacosxVersionLT(10, 6)) - CmdArgs.push_back("-lgcc_s.10.5"); - - // Originally for OS X, we thought we would only need a static runtime - // library when targeting 10.4, to provide versions of the static functions - // which were omitted from 10.4.dylib. This led to the creation of the 10.4 - // builtins library. - // - // Unfortunately, that turned out to not be true, because Darwin system - // headers can still use eprintf on i386, and it is not exported from - // libSystem. Therefore, we still must provide a runtime library just for - // the tiny tiny handful of projects that *might* use that symbol. - // - // Then over time, we figured out it was useful to add more things to the - // runtime so we created libclang_rt.osx.a to provide new functions when - // deploying to old OS builds, and for a long time we had both eprintf and - // osx builtin libraries. Which just seems excessive. So with PR 28855, we - // are removing the eprintf library and expecting eprintf to be provided by - // the OS X builtins library. - if (isMacosxVersionLT(10, 5)) - AddLinkRuntimeLib(Args, CmdArgs, "libclang_rt.10.4.a"); - else - AddLinkRuntimeLib(Args, CmdArgs, "libclang_rt.osx.a"); - } -} - -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)); - } - } - } - - Arg *OSXVersion = Args.getLastArg(options::OPT_mmacosx_version_min_EQ); - Arg *iOSVersion = Args.getLastArg(options::OPT_miphoneos_version_min_EQ); - Arg *TvOSVersion = Args.getLastArg(options::OPT_mtvos_version_min_EQ); - Arg *WatchOSVersion = Args.getLastArg(options::OPT_mwatchos_version_min_EQ); - - 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 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 = Version; - else if (SDK.startswith("WatchOS") || - SDK.startswith("WatchSimulator")) - WatchOSTarget = Version; - else if (SDK.startswith("AppleTVOS") || - SDK.startswith("AppleTVSimulator")) - TvOSTarget = Version; - } - } - } - } - - // If no OSX or iOS target has been specified, try to guess platform - // from arch name and compute the version from the triple. - if (OSXTarget.empty() && iOSTarget.empty() && TvOSTarget.empty() && - WatchOSTarget.empty()) { - StringRef MachOArchName = getMachOArchName(Args); - unsigned Major, Minor, Micro; - if (MachOArchName == "armv7" || MachOArchName == "armv7s" || - MachOArchName == "arm64") { - getTriple().getiOSVersion(Major, Minor, Micro); - llvm::raw_string_ostream(iOSTarget) << Major << '.' << Minor << '.' - << Micro; - } else if (MachOArchName == "armv7k") { - getTriple().getWatchOSVersion(Major, Minor, Micro); - llvm::raw_string_ostream(WatchOSTarget) << Major << '.' << Minor << '.' - << Micro; - } else if (MachOArchName != "armv6m" && MachOArchName != "armv7m" && - MachOArchName != "armv7em") { - if (!getTriple().getMacOSXVersion(Major, Minor, Micro)) { - getDriver().Diag(diag::err_drv_invalid_darwin_version) - << getTriple().getOSName(); - } - llvm::raw_string_ostream(OSXTarget) << Major << '.' << Minor << '.' - << Micro; - } - } - - // 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"); - } - - // 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"; - } - - // 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 = ""; - } - - 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); - } - } - - 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"); - - // Set the tool chain target information. - unsigned Major, Minor, Micro; - bool HadExtra; - if (Platform == MacOS) { - assert((!iOSVersion && !TvOSVersion && !WatchOSVersion) && - "Unknown target platform!"); - if (!Driver::GetReleaseVersion(OSXVersion->getValue(), Major, Minor, Micro, - HadExtra) || - HadExtra || Major != 10 || Minor >= 100 || Micro >= 100) - getDriver().Diag(diag::err_drv_invalid_version_number) - << OSXVersion->getAsString(Args); - } else if (Platform == IPhoneOS) { - assert(iOSVersion && "Unknown target platform!"); - if (!Driver::GetReleaseVersion(iOSVersion->getValue(), Major, Minor, Micro, - HadExtra) || - HadExtra || Major >= 100 || Minor >= 100 || Micro >= 100) - getDriver().Diag(diag::err_drv_invalid_version_number) - << iOSVersion->getAsString(Args); - } else if (Platform == TvOS) { - if (!Driver::GetReleaseVersion(TvOSVersion->getValue(), Major, Minor, - Micro, HadExtra) || HadExtra || - Major >= 100 || Minor >= 100 || Micro >= 100) - getDriver().Diag(diag::err_drv_invalid_version_number) - << TvOSVersion->getAsString(Args); - } else if (Platform == WatchOS) { - if (!Driver::GetReleaseVersion(WatchOSVersion->getValue(), Major, Minor, - Micro, HadExtra) || HadExtra || - Major >= 10 || Minor >= 100 || Micro >= 100) - getDriver().Diag(diag::err_drv_invalid_version_number) - << WatchOSVersion->getAsString(Args); - } else - llvm_unreachable("unknown kind of Darwin platform"); - - // 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 (const Arg *A = Args.getLastArg(options::OPT_isysroot)) { - StringRef SDK = getSDKName(A->getValue()); - if (SDK.size() > 0) { - size_t StartVer = SDK.find_first_of("0123456789"); - StringRef SDKName = SDK.slice(0, StartVer); - if (!SDKName.startswith(getPlatformFamily())) - getDriver().Diag(diag::warn_incompatible_sysroot) - << SDKName << getPlatformFamily(); - } - } -} - -void DarwinClang::AddCXXStdlibLibArgs(const ArgList &Args, - ArgStringList &CmdArgs) const { - CXXStdlibType Type = GetCXXStdlibType(Args); - - switch (Type) { - case ToolChain::CST_Libcxx: - CmdArgs.push_back("-lc++"); - break; - - case ToolChain::CST_Libstdcxx: - // Unfortunately, -lstdc++ doesn't always exist in the standard search path; - // it was previously found in the gcc lib dir. However, for all the Darwin - // platforms we care about it was -lstdc++.6, so we search for that - // explicitly if we can't see an obvious -lstdc++ candidate. - - // Check in the sysroot first. - if (const Arg *A = Args.getLastArg(options::OPT_isysroot)) { - SmallString<128> P(A->getValue()); - llvm::sys::path::append(P, "usr", "lib", "libstdc++.dylib"); - - if (!getVFS().exists(P)) { - llvm::sys::path::remove_filename(P); - llvm::sys::path::append(P, "libstdc++.6.dylib"); - if (getVFS().exists(P)) { - CmdArgs.push_back(Args.MakeArgString(P)); - return; - } - } - } - - // Otherwise, look in the root. - // FIXME: This should be removed someday when we don't have to care about - // 10.6 and earlier, where /usr/lib/libstdc++.dylib does not exist. - if (!getVFS().exists("/usr/lib/libstdc++.dylib") && - getVFS().exists("/usr/lib/libstdc++.6.dylib")) { - CmdArgs.push_back("/usr/lib/libstdc++.6.dylib"); - return; - } - - // Otherwise, let the linker search. - CmdArgs.push_back("-lstdc++"); - break; - } -} - -void DarwinClang::AddCCKextLibArgs(const ArgList &Args, - ArgStringList &CmdArgs) const { - // For Darwin platforms, use the compiler-rt-based support library - // instead of the gcc-provided one (which is also incidentally - // only present in the gcc lib dir, which makes it hard to find). - - SmallString<128> P(getDriver().ResourceDir); - llvm::sys::path::append(P, "lib", "darwin"); - - // Use the newer cc_kext for iOS ARM after 6.0. - if (isTargetWatchOS()) { - llvm::sys::path::append(P, "libclang_rt.cc_kext_watchos.a"); - } else if (isTargetTvOS()) { - llvm::sys::path::append(P, "libclang_rt.cc_kext_tvos.a"); - } else if (isTargetIPhoneOS()) { - llvm::sys::path::append(P, "libclang_rt.cc_kext_ios.a"); - } else { - llvm::sys::path::append(P, "libclang_rt.cc_kext.a"); - } - - // For now, allow missing resource libraries to support developers who may - // not have compiler-rt checked out or integrated into their build. - if (getVFS().exists(P)) - CmdArgs.push_back(Args.MakeArgString(P)); -} - -DerivedArgList *MachO::TranslateArgs(const DerivedArgList &Args, - StringRef BoundArch, - Action::OffloadKind) const { - DerivedArgList *DAL = new DerivedArgList(Args.getBaseArgs()); - const OptTable &Opts = getDriver().getOpts(); - - // FIXME: We really want to get out of the tool chain level argument - // translation business, as it makes the driver functionality much - // more opaque. For now, we follow gcc closely solely for the - // purpose of easily achieving feature parity & testability. Once we - // have something that works, we should reevaluate each translation - // and try to push it down into tool specific logic. - - for (Arg *A : Args) { - if (A->getOption().matches(options::OPT_Xarch__)) { - // Skip this argument unless the architecture matches either the toolchain - // triple arch, or the arch being bound. - llvm::Triple::ArchType XarchArch = - tools::darwin::getArchTypeForMachOArchName(A->getValue(0)); - if (!(XarchArch == getArch() || - (!BoundArch.empty() && - XarchArch == - tools::darwin::getArchTypeForMachOArchName(BoundArch)))) - continue; - - Arg *OriginalArg = A; - unsigned Index = Args.getBaseArgs().MakeIndex(A->getValue(1)); - unsigned Prev = Index; - std::unique_ptr<Arg> XarchArg(Opts.ParseOneArg(Args, Index)); - - // If the argument parsing failed or more than one argument was - // consumed, the -Xarch_ argument's parameter tried to consume - // extra arguments. Emit an error and ignore. - // - // We also want to disallow any options which would alter the - // driver behavior; that isn't going to work in our model. We - // use isDriverOption() as an approximation, although things - // like -O4 are going to slip through. - if (!XarchArg || Index > Prev + 1) { - getDriver().Diag(diag::err_drv_invalid_Xarch_argument_with_args) - << A->getAsString(Args); - continue; - } else if (XarchArg->getOption().hasFlag(options::DriverOption)) { - getDriver().Diag(diag::err_drv_invalid_Xarch_argument_isdriver) - << A->getAsString(Args); - continue; - } - - XarchArg->setBaseArg(A); - - A = XarchArg.release(); - DAL->AddSynthesizedArg(A); - - // Linker input arguments require custom handling. The problem is that we - // have already constructed the phase actions, so we can not treat them as - // "input arguments". - if (A->getOption().hasFlag(options::LinkerInput)) { - // Convert the argument into individual Zlinker_input_args. - for (const char *Value : A->getValues()) { - DAL->AddSeparateArg( - OriginalArg, Opts.getOption(options::OPT_Zlinker_input), Value); - } - continue; - } - } - - // Sob. These is strictly gcc compatible for the time being. Apple - // gcc translates options twice, which means that self-expanding - // options add duplicates. - switch ((options::ID)A->getOption().getID()) { - default: - DAL->append(A); - break; - - case options::OPT_mkernel: - case options::OPT_fapple_kext: - DAL->append(A); - DAL->AddFlagArg(A, Opts.getOption(options::OPT_static)); - break; - - case options::OPT_dependency_file: - DAL->AddSeparateArg(A, Opts.getOption(options::OPT_MF), A->getValue()); - break; - - case options::OPT_gfull: - DAL->AddFlagArg(A, Opts.getOption(options::OPT_g_Flag)); - DAL->AddFlagArg( - A, Opts.getOption(options::OPT_fno_eliminate_unused_debug_symbols)); - break; - - case options::OPT_gused: - DAL->AddFlagArg(A, Opts.getOption(options::OPT_g_Flag)); - DAL->AddFlagArg( - A, Opts.getOption(options::OPT_feliminate_unused_debug_symbols)); - break; - - case options::OPT_shared: - DAL->AddFlagArg(A, Opts.getOption(options::OPT_dynamiclib)); - break; - - case options::OPT_fconstant_cfstrings: - DAL->AddFlagArg(A, Opts.getOption(options::OPT_mconstant_cfstrings)); - break; - - case options::OPT_fno_constant_cfstrings: - DAL->AddFlagArg(A, Opts.getOption(options::OPT_mno_constant_cfstrings)); - break; - - case options::OPT_Wnonportable_cfstrings: - DAL->AddFlagArg(A, - Opts.getOption(options::OPT_mwarn_nonportable_cfstrings)); - break; - - case options::OPT_Wno_nonportable_cfstrings: - DAL->AddFlagArg( - A, Opts.getOption(options::OPT_mno_warn_nonportable_cfstrings)); - break; - - case options::OPT_fpascal_strings: - DAL->AddFlagArg(A, Opts.getOption(options::OPT_mpascal_strings)); - break; - - case options::OPT_fno_pascal_strings: - DAL->AddFlagArg(A, Opts.getOption(options::OPT_mno_pascal_strings)); - break; - } - } - - if (getTriple().getArch() == llvm::Triple::x86 || - getTriple().getArch() == llvm::Triple::x86_64) - if (!Args.hasArgNoClaim(options::OPT_mtune_EQ)) - DAL->AddJoinedArg(nullptr, Opts.getOption(options::OPT_mtune_EQ), - "core2"); - - // Add the arch options based on the particular spelling of -arch, to match - // how the driver driver works. - if (!BoundArch.empty()) { - StringRef Name = BoundArch; - const Option MCpu = Opts.getOption(options::OPT_mcpu_EQ); - const Option MArch = Opts.getOption(options::OPT_march_EQ); - - // This code must be kept in sync with LLVM's getArchTypeForDarwinArch, - // which defines the list of which architectures we accept. - if (Name == "ppc") - ; - else if (Name == "ppc601") - DAL->AddJoinedArg(nullptr, MCpu, "601"); - else if (Name == "ppc603") - DAL->AddJoinedArg(nullptr, MCpu, "603"); - else if (Name == "ppc604") - DAL->AddJoinedArg(nullptr, MCpu, "604"); - else if (Name == "ppc604e") - DAL->AddJoinedArg(nullptr, MCpu, "604e"); - else if (Name == "ppc750") - DAL->AddJoinedArg(nullptr, MCpu, "750"); - else if (Name == "ppc7400") - DAL->AddJoinedArg(nullptr, MCpu, "7400"); - else if (Name == "ppc7450") - DAL->AddJoinedArg(nullptr, MCpu, "7450"); - else if (Name == "ppc970") - DAL->AddJoinedArg(nullptr, MCpu, "970"); - - else if (Name == "ppc64" || Name == "ppc64le") - DAL->AddFlagArg(nullptr, Opts.getOption(options::OPT_m64)); - - else if (Name == "i386") - ; - else if (Name == "i486") - DAL->AddJoinedArg(nullptr, MArch, "i486"); - else if (Name == "i586") - DAL->AddJoinedArg(nullptr, MArch, "i586"); - else if (Name == "i686") - DAL->AddJoinedArg(nullptr, MArch, "i686"); - else if (Name == "pentium") - DAL->AddJoinedArg(nullptr, MArch, "pentium"); - else if (Name == "pentium2") - DAL->AddJoinedArg(nullptr, MArch, "pentium2"); - else if (Name == "pentpro") - DAL->AddJoinedArg(nullptr, MArch, "pentiumpro"); - else if (Name == "pentIIm3") - DAL->AddJoinedArg(nullptr, MArch, "pentium2"); - - else if (Name == "x86_64") - DAL->AddFlagArg(nullptr, Opts.getOption(options::OPT_m64)); - else if (Name == "x86_64h") { - DAL->AddFlagArg(nullptr, Opts.getOption(options::OPT_m64)); - DAL->AddJoinedArg(nullptr, MArch, "x86_64h"); - } - - else if (Name == "arm") - DAL->AddJoinedArg(nullptr, MArch, "armv4t"); - else if (Name == "armv4t") - DAL->AddJoinedArg(nullptr, MArch, "armv4t"); - else if (Name == "armv5") - DAL->AddJoinedArg(nullptr, MArch, "armv5tej"); - else if (Name == "xscale") - DAL->AddJoinedArg(nullptr, MArch, "xscale"); - else if (Name == "armv6") - DAL->AddJoinedArg(nullptr, MArch, "armv6k"); - else if (Name == "armv6m") - DAL->AddJoinedArg(nullptr, MArch, "armv6m"); - else if (Name == "armv7") - DAL->AddJoinedArg(nullptr, MArch, "armv7a"); - else if (Name == "armv7em") - DAL->AddJoinedArg(nullptr, MArch, "armv7em"); - else if (Name == "armv7k") - DAL->AddJoinedArg(nullptr, MArch, "armv7k"); - else if (Name == "armv7m") - DAL->AddJoinedArg(nullptr, MArch, "armv7m"); - else if (Name == "armv7s") - DAL->AddJoinedArg(nullptr, MArch, "armv7s"); - } - - return DAL; -} - -void MachO::AddLinkRuntimeLibArgs(const ArgList &Args, - ArgStringList &CmdArgs) const { - // Embedded targets are simple at the moment, not supporting sanitizers and - // with different libraries for each member of the product { static, PIC } x - // { hard-float, soft-float } - llvm::SmallString<32> CompilerRT = StringRef("libclang_rt."); - CompilerRT += - (tools::arm::getARMFloatABI(*this, Args) == tools::arm::FloatABI::Hard) - ? "hard" - : "soft"; - CompilerRT += Args.hasArg(options::OPT_fPIC) ? "_pic.a" : "_static.a"; - - AddLinkRuntimeLib(Args, CmdArgs, CompilerRT, false, true); -} - -DerivedArgList * -Darwin::TranslateArgs(const DerivedArgList &Args, StringRef BoundArch, - Action::OffloadKind DeviceOffloadKind) const { - // First get the generic Apple args, before moving onto Darwin-specific ones. - DerivedArgList *DAL = - MachO::TranslateArgs(Args, BoundArch, DeviceOffloadKind); - const OptTable &Opts = getDriver().getOpts(); - - // If no architecture is bound, none of the translations here are relevant. - if (BoundArch.empty()) - return DAL; - - // Add an explicit version min argument for the deployment target. We do this - // after argument translation because -Xarch_ arguments may add a version min - // argument. - AddDeploymentTarget(*DAL); - - // For iOS 6, undo the translation to add -static for -mkernel/-fapple-kext. - // FIXME: It would be far better to avoid inserting those -static arguments, - // but we can't check the deployment target in the translation code until - // it is set here. - if (isTargetWatchOSBased() || - (isTargetIOSBased() && !isIPhoneOSVersionLT(6, 0))) { - for (ArgList::iterator it = DAL->begin(), ie = DAL->end(); it != ie; ) { - Arg *A = *it; - ++it; - if (A->getOption().getID() != options::OPT_mkernel && - A->getOption().getID() != options::OPT_fapple_kext) - continue; - assert(it != ie && "unexpected argument translation"); - A = *it; - assert(A->getOption().getID() == options::OPT_static && - "missing expected -static argument"); - it = DAL->getArgs().erase(it); - } - } - - if (!Args.getLastArg(options::OPT_stdlib_EQ) && - GetCXXStdlibType(Args) == ToolChain::CST_Libcxx) - DAL->AddJoinedArg(nullptr, Opts.getOption(options::OPT_stdlib_EQ), - "libc++"); - - // Validate the C++ standard library choice. - CXXStdlibType Type = GetCXXStdlibType(*DAL); - if (Type == ToolChain::CST_Libcxx) { - // Check whether the target provides libc++. - StringRef where; - - // Complain about targeting iOS < 5.0 in any way. - if (isTargetIOSBased() && isIPhoneOSVersionLT(5, 0)) - where = "iOS 5.0"; - - if (where != StringRef()) { - getDriver().Diag(clang::diag::err_drv_invalid_libcxx_deployment) << where; - } - } - - auto Arch = tools::darwin::getArchTypeForMachOArchName(BoundArch); - if ((Arch == llvm::Triple::arm || Arch == llvm::Triple::thumb)) { - if (Args.hasFlag(options::OPT_fomit_frame_pointer, - options::OPT_fno_omit_frame_pointer, false)) - getDriver().Diag(clang::diag::warn_drv_unsupported_opt_for_target) - << "-fomit-frame-pointer" << BoundArch; - } - - return DAL; -} - -bool MachO::IsUnwindTablesDefault() const { - return getArch() == llvm::Triple::x86_64; -} - -bool MachO::UseDwarfDebugFlags() const { - if (const char *S = ::getenv("RC_DEBUG_OPTIONS")) - return S[0] != '\0'; - return false; -} - -bool Darwin::UseSjLjExceptions(const ArgList &Args) const { - // Darwin uses SjLj exceptions on ARM. - if (getTriple().getArch() != llvm::Triple::arm && - getTriple().getArch() != llvm::Triple::thumb) - return false; - - // Only watchOS uses the new DWARF/Compact unwinding method. - llvm::Triple Triple(ComputeLLVMTriple(Args)); - return !Triple.isWatchABI(); -} - -bool Darwin::SupportsEmbeddedBitcode() const { - assert(TargetInitialized && "Target not initialized!"); - if (isTargetIPhoneOS() && isIPhoneOSVersionLT(6, 0)) - return false; - return true; -} - -bool MachO::isPICDefault() const { return true; } - -bool MachO::isPIEDefault() const { return false; } - -bool MachO::isPICDefaultForced() const { - return (getArch() == llvm::Triple::x86_64 || - getArch() == llvm::Triple::aarch64); -} - -bool MachO::SupportsProfiling() const { - // Profiling instrumentation is only supported on x86. - return getArch() == llvm::Triple::x86 || getArch() == llvm::Triple::x86_64; -} - -void Darwin::addMinVersionArgs(const ArgList &Args, - ArgStringList &CmdArgs) const { - VersionTuple TargetVersion = getTargetVersion(); - - if (isTargetWatchOS()) - CmdArgs.push_back("-watchos_version_min"); - else if (isTargetWatchOSSimulator()) - CmdArgs.push_back("-watchos_simulator_version_min"); - else if (isTargetTvOS()) - CmdArgs.push_back("-tvos_version_min"); - else if (isTargetTvOSSimulator()) - CmdArgs.push_back("-tvos_simulator_version_min"); - else if (isTargetIOSSimulator()) - CmdArgs.push_back("-ios_simulator_version_min"); - else if (isTargetIOSBased()) - CmdArgs.push_back("-iphoneos_version_min"); - else { - assert(isTargetMacOS() && "unexpected target"); - CmdArgs.push_back("-macosx_version_min"); - } - - CmdArgs.push_back(Args.MakeArgString(TargetVersion.getAsString())); -} - -void Darwin::addStartObjectFileArgs(const ArgList &Args, - ArgStringList &CmdArgs) const { - // Derived from startfile spec. - if (Args.hasArg(options::OPT_dynamiclib)) { - // Derived from darwin_dylib1 spec. - if (isTargetWatchOSBased()) { - ; // watchOS does not need dylib1.o. - } else if (isTargetIOSSimulator()) { - ; // iOS simulator does not need dylib1.o. - } else if (isTargetIPhoneOS()) { - if (isIPhoneOSVersionLT(3, 1)) - CmdArgs.push_back("-ldylib1.o"); - } else { - if (isMacosxVersionLT(10, 5)) - CmdArgs.push_back("-ldylib1.o"); - else if (isMacosxVersionLT(10, 6)) - CmdArgs.push_back("-ldylib1.10.5.o"); - } - } else { - if (Args.hasArg(options::OPT_bundle)) { - if (!Args.hasArg(options::OPT_static)) { - // Derived from darwin_bundle1 spec. - if (isTargetWatchOSBased()) { - ; // watchOS does not need bundle1.o. - } else if (isTargetIOSSimulator()) { - ; // iOS simulator does not need bundle1.o. - } else if (isTargetIPhoneOS()) { - if (isIPhoneOSVersionLT(3, 1)) - CmdArgs.push_back("-lbundle1.o"); - } else { - if (isMacosxVersionLT(10, 6)) - CmdArgs.push_back("-lbundle1.o"); - } - } - } else { - if (Args.hasArg(options::OPT_pg) && SupportsProfiling()) { - if (Args.hasArg(options::OPT_static) || - Args.hasArg(options::OPT_object) || - Args.hasArg(options::OPT_preload)) { - CmdArgs.push_back("-lgcrt0.o"); - } else { - CmdArgs.push_back("-lgcrt1.o"); - - // darwin_crt2 spec is empty. - } - // By default on OS X 10.8 and later, we don't link with a crt1.o - // file and the linker knows to use _main as the entry point. But, - // when compiling with -pg, we need to link with the gcrt1.o file, - // so pass the -no_new_main option to tell the linker to use the - // "start" symbol as the entry point. - if (isTargetMacOS() && !isMacosxVersionLT(10, 8)) - CmdArgs.push_back("-no_new_main"); - } else { - if (Args.hasArg(options::OPT_static) || - Args.hasArg(options::OPT_object) || - Args.hasArg(options::OPT_preload)) { - CmdArgs.push_back("-lcrt0.o"); - } else { - // Derived from darwin_crt1 spec. - if (isTargetWatchOSBased()) { - ; // watchOS does not need crt1.o. - } else if (isTargetIOSSimulator()) { - ; // iOS simulator does not need crt1.o. - } else if (isTargetIPhoneOS()) { - if (getArch() == llvm::Triple::aarch64) - ; // iOS does not need any crt1 files for arm64 - else if (isIPhoneOSVersionLT(3, 1)) - CmdArgs.push_back("-lcrt1.o"); - else if (isIPhoneOSVersionLT(6, 0)) - CmdArgs.push_back("-lcrt1.3.1.o"); - } else { - if (isMacosxVersionLT(10, 5)) - CmdArgs.push_back("-lcrt1.o"); - else if (isMacosxVersionLT(10, 6)) - CmdArgs.push_back("-lcrt1.10.5.o"); - else if (isMacosxVersionLT(10, 8)) - CmdArgs.push_back("-lcrt1.10.6.o"); - - // darwin_crt2 spec is empty. - } - } - } - } - } - - if (!isTargetIPhoneOS() && Args.hasArg(options::OPT_shared_libgcc) && - !isTargetWatchOS() && - isMacosxVersionLT(10, 5)) { - const char *Str = Args.MakeArgString(GetFilePath("crt3.o")); - CmdArgs.push_back(Str); - } -} - -bool Darwin::SupportsObjCGC() const { return isTargetMacOS(); } - -void Darwin::CheckObjCARC() const { - if (isTargetIOSBased() || isTargetWatchOSBased() || - (isTargetMacOS() && !isMacosxVersionLT(10, 6))) - return; - getDriver().Diag(diag::err_arc_unsupported_on_toolchain); -} - -SanitizerMask Darwin::getSupportedSanitizers() const { - const bool IsX86_64 = getTriple().getArch() == llvm::Triple::x86_64; - SanitizerMask Res = ToolChain::getSupportedSanitizers(); - Res |= SanitizerKind::Address; - if (isTargetMacOS()) { - if (!isMacosxVersionLT(10, 9)) - Res |= SanitizerKind::Vptr; - Res |= SanitizerKind::SafeStack; - if (IsX86_64) - Res |= SanitizerKind::Thread; - } else if (isTargetIOSSimulator() || isTargetTvOSSimulator()) { - if (IsX86_64) - Res |= SanitizerKind::Thread; - } - return Res; -} - -void Darwin::printVerboseInfo(raw_ostream &OS) const { - CudaInstallation.print(OS); -} - -/// Generic_GCC - A tool chain using the 'gcc' command to perform -/// all subcommands; this relies on gcc translating the majority of -/// command line options. - -/// \brief Parse a GCCVersion object out of a string of text. -/// -/// This is the primary means of forming GCCVersion objects. -/*static*/ -Generic_GCC::GCCVersion Linux::GCCVersion::Parse(StringRef VersionText) { - const GCCVersion BadVersion = {VersionText.str(), -1, -1, -1, "", "", ""}; - std::pair<StringRef, StringRef> First = VersionText.split('.'); - std::pair<StringRef, StringRef> Second = First.second.split('.'); - - GCCVersion GoodVersion = {VersionText.str(), -1, -1, -1, "", "", ""}; - if (First.first.getAsInteger(10, GoodVersion.Major) || GoodVersion.Major < 0) - return BadVersion; - GoodVersion.MajorStr = First.first.str(); - if (First.second.empty()) - return GoodVersion; - if (Second.first.getAsInteger(10, GoodVersion.Minor) || GoodVersion.Minor < 0) - return BadVersion; - GoodVersion.MinorStr = Second.first.str(); - - // First look for a number prefix and parse that if present. Otherwise just - // stash the entire patch string in the suffix, and leave the number - // unspecified. This covers versions strings such as: - // 5 (handled above) - // 4.4 - // 4.4.0 - // 4.4.x - // 4.4.2-rc4 - // 4.4.x-patched - // And retains any patch number it finds. - StringRef PatchText = GoodVersion.PatchSuffix = Second.second.str(); - if (!PatchText.empty()) { - if (size_t EndNumber = PatchText.find_first_not_of("0123456789")) { - // Try to parse the number and any suffix. - if (PatchText.slice(0, EndNumber).getAsInteger(10, GoodVersion.Patch) || - GoodVersion.Patch < 0) - return BadVersion; - GoodVersion.PatchSuffix = PatchText.substr(EndNumber); - } - } - - return GoodVersion; -} - -/// \brief Less-than for GCCVersion, implementing a Strict Weak Ordering. -bool Generic_GCC::GCCVersion::isOlderThan(int RHSMajor, int RHSMinor, - int RHSPatch, - StringRef RHSPatchSuffix) const { - if (Major != RHSMajor) - return Major < RHSMajor; - if (Minor != RHSMinor) - return Minor < RHSMinor; - if (Patch != RHSPatch) { - // Note that versions without a specified patch sort higher than those with - // a patch. - if (RHSPatch == -1) - return true; - if (Patch == -1) - return false; - - // Otherwise just sort on the patch itself. - return Patch < RHSPatch; - } - if (PatchSuffix != RHSPatchSuffix) { - // Sort empty suffixes higher. - if (RHSPatchSuffix.empty()) - return true; - if (PatchSuffix.empty()) - return false; - - // Provide a lexicographic sort to make this a total ordering. - return PatchSuffix < RHSPatchSuffix; - } - - // The versions are equal. - return false; -} - -static llvm::StringRef getGCCToolchainDir(const ArgList &Args) { - const Arg *A = Args.getLastArg(options::OPT_gcc_toolchain); - if (A) - return A->getValue(); - return GCC_INSTALL_PREFIX; -} - -/// \brief Initialize a GCCInstallationDetector from the driver. -/// -/// This performs all of the autodetection and sets up the various paths. -/// Once constructed, a GCCInstallationDetector is essentially immutable. -/// -/// FIXME: We shouldn't need an explicit TargetTriple parameter here, and -/// should instead pull the target out of the driver. This is currently -/// necessary because the driver doesn't store the final version of the target -/// triple. -void Generic_GCC::GCCInstallationDetector::init( - const llvm::Triple &TargetTriple, const ArgList &Args, - ArrayRef<std::string> ExtraTripleAliases) { - llvm::Triple BiarchVariantTriple = TargetTriple.isArch32Bit() - ? TargetTriple.get64BitArchVariant() - : TargetTriple.get32BitArchVariant(); - // The library directories which may contain GCC installations. - SmallVector<StringRef, 4> CandidateLibDirs, CandidateBiarchLibDirs; - // The compatible GCC triples for this particular architecture. - SmallVector<StringRef, 16> CandidateTripleAliases; - SmallVector<StringRef, 16> CandidateBiarchTripleAliases; - CollectLibDirsAndTriples(TargetTriple, BiarchVariantTriple, CandidateLibDirs, - CandidateTripleAliases, CandidateBiarchLibDirs, - CandidateBiarchTripleAliases); - - // Compute the set of prefixes for our search. - SmallVector<std::string, 8> Prefixes(D.PrefixDirs.begin(), - D.PrefixDirs.end()); - - StringRef GCCToolchainDir = getGCCToolchainDir(Args); - if (GCCToolchainDir != "") { - if (GCCToolchainDir.back() == '/') - GCCToolchainDir = GCCToolchainDir.drop_back(); // remove the / - - Prefixes.push_back(GCCToolchainDir); - } else { - // If we have a SysRoot, try that first. - if (!D.SysRoot.empty()) { - Prefixes.push_back(D.SysRoot); - Prefixes.push_back(D.SysRoot + "/usr"); - } - - // Then look for gcc installed alongside clang. - Prefixes.push_back(D.InstalledDir + "/.."); - - // Then look for distribution supplied gcc installations. - if (D.SysRoot.empty()) { - // Look for RHEL devtoolsets. - Prefixes.push_back("/opt/rh/devtoolset-6/root/usr"); - Prefixes.push_back("/opt/rh/devtoolset-4/root/usr"); - Prefixes.push_back("/opt/rh/devtoolset-3/root/usr"); - Prefixes.push_back("/opt/rh/devtoolset-2/root/usr"); - // And finally in /usr. - Prefixes.push_back("/usr"); - } - } - - // Try to respect gcc-config on Gentoo. However, do that only - // if --gcc-toolchain is not provided or equal to the Gentoo install - // in /usr. This avoids accidentally enforcing the system GCC version - // when using a custom toolchain. - if (GCCToolchainDir == "" || GCCToolchainDir == D.SysRoot + "/usr") { - for (StringRef CandidateTriple : ExtraTripleAliases) { - if (ScanGentooGccConfig(TargetTriple, Args, CandidateTriple)) - return; - } - for (StringRef CandidateTriple : CandidateTripleAliases) { - if (ScanGentooGccConfig(TargetTriple, Args, CandidateTriple)) - return; - } - for (StringRef CandidateTriple : CandidateBiarchTripleAliases) { - if (ScanGentooGccConfig(TargetTriple, Args, CandidateTriple, true)) - return; - } - } - - // Loop over the various components which exist and select the best GCC - // installation available. GCC installs are ranked by version number. - Version = GCCVersion::Parse("0.0.0"); - for (const std::string &Prefix : Prefixes) { - if (!D.getVFS().exists(Prefix)) - continue; - for (StringRef Suffix : CandidateLibDirs) { - const std::string LibDir = Prefix + Suffix.str(); - if (!D.getVFS().exists(LibDir)) - continue; - for (StringRef Candidate : ExtraTripleAliases) // Try these first. - ScanLibDirForGCCTriple(TargetTriple, Args, LibDir, Candidate); - for (StringRef Candidate : CandidateTripleAliases) - ScanLibDirForGCCTriple(TargetTriple, Args, LibDir, Candidate); - } - for (StringRef Suffix : CandidateBiarchLibDirs) { - const std::string LibDir = Prefix + Suffix.str(); - if (!D.getVFS().exists(LibDir)) - continue; - for (StringRef Candidate : CandidateBiarchTripleAliases) - ScanLibDirForGCCTriple(TargetTriple, Args, LibDir, Candidate, - /*NeedsBiarchSuffix=*/ true); - } - } -} - -void Generic_GCC::GCCInstallationDetector::print(raw_ostream &OS) const { - for (const auto &InstallPath : CandidateGCCInstallPaths) - OS << "Found candidate GCC installation: " << InstallPath << "\n"; - - if (!GCCInstallPath.empty()) - OS << "Selected GCC installation: " << GCCInstallPath << "\n"; - - for (const auto &Multilib : Multilibs) - OS << "Candidate multilib: " << Multilib << "\n"; - - if (Multilibs.size() != 0 || !SelectedMultilib.isDefault()) - OS << "Selected multilib: " << SelectedMultilib << "\n"; -} - -bool Generic_GCC::GCCInstallationDetector::getBiarchSibling(Multilib &M) const { - if (BiarchSibling.hasValue()) { - M = BiarchSibling.getValue(); - return true; - } - return false; -} - -/*static*/ void Generic_GCC::GCCInstallationDetector::CollectLibDirsAndTriples( - const llvm::Triple &TargetTriple, const llvm::Triple &BiarchTriple, - SmallVectorImpl<StringRef> &LibDirs, - SmallVectorImpl<StringRef> &TripleAliases, - SmallVectorImpl<StringRef> &BiarchLibDirs, - SmallVectorImpl<StringRef> &BiarchTripleAliases) { - // Declare a bunch of static data sets that we'll select between below. These - // are specifically designed to always refer to string literals to avoid any - // lifetime or initialization issues. - static const char *const AArch64LibDirs[] = {"/lib64", "/lib"}; - static const char *const AArch64Triples[] = { - "aarch64-none-linux-gnu", "aarch64-linux-gnu", "aarch64-linux-android", - "aarch64-redhat-linux", "aarch64-suse-linux"}; - static const char *const AArch64beLibDirs[] = {"/lib"}; - static const char *const AArch64beTriples[] = {"aarch64_be-none-linux-gnu", - "aarch64_be-linux-gnu"}; - - static const char *const ARMLibDirs[] = {"/lib"}; - static const char *const ARMTriples[] = {"arm-linux-gnueabi", - "arm-linux-androideabi"}; - static const char *const ARMHFTriples[] = {"arm-linux-gnueabihf", - "armv7hl-redhat-linux-gnueabi"}; - static const char *const ARMebLibDirs[] = {"/lib"}; - static const char *const ARMebTriples[] = {"armeb-linux-gnueabi", - "armeb-linux-androideabi"}; - static const char *const ARMebHFTriples[] = { - "armeb-linux-gnueabihf", "armebv7hl-redhat-linux-gnueabi"}; - - static const char *const X86_64LibDirs[] = {"/lib64", "/lib"}; - static const char *const X86_64Triples[] = { - "x86_64-linux-gnu", "x86_64-unknown-linux-gnu", - "x86_64-pc-linux-gnu", "x86_64-redhat-linux6E", - "x86_64-redhat-linux", "x86_64-suse-linux", - "x86_64-manbo-linux-gnu", "x86_64-linux-gnu", - "x86_64-slackware-linux", "x86_64-linux-android", - "x86_64-unknown-linux"}; - static const char *const X32LibDirs[] = {"/libx32"}; - static const char *const X86LibDirs[] = {"/lib32", "/lib"}; - static const char *const X86Triples[] = { - "i686-linux-gnu", "i686-pc-linux-gnu", "i486-linux-gnu", - "i386-linux-gnu", "i386-redhat-linux6E", "i686-redhat-linux", - "i586-redhat-linux", "i386-redhat-linux", "i586-suse-linux", - "i486-slackware-linux", "i686-montavista-linux", "i686-linux-android", - "i586-linux-gnu"}; - - static const char *const MIPSLibDirs[] = {"/lib"}; - static const char *const MIPSTriples[] = {"mips-linux-gnu", "mips-mti-linux", - "mips-mti-linux-gnu", - "mips-img-linux-gnu"}; - static const char *const MIPSELLibDirs[] = {"/lib"}; - static const char *const MIPSELTriples[] = {"mipsel-linux-gnu", - "mips-img-linux-gnu"}; - - static const char *const MIPS64LibDirs[] = {"/lib64", "/lib"}; - static const char *const MIPS64Triples[] = { - "mips64-linux-gnu", "mips-mti-linux-gnu", "mips-img-linux-gnu", - "mips64-linux-gnuabi64"}; - static const char *const MIPS64ELLibDirs[] = {"/lib64", "/lib"}; - static const char *const MIPS64ELTriples[] = { - "mips64el-linux-gnu", "mips-mti-linux-gnu", "mips-img-linux-gnu", - "mips64el-linux-gnuabi64"}; - - static const char *const MIPSELAndroidLibDirs[] = {"/lib", "/libr2", - "/libr6"}; - static const char *const MIPSELAndroidTriples[] = {"mipsel-linux-android"}; - static const char *const MIPS64ELAndroidLibDirs[] = {"/lib64", "/lib", - "/libr2", "/libr6"}; - static const char *const MIPS64ELAndroidTriples[] = { - "mips64el-linux-android"}; - - static const char *const PPCLibDirs[] = {"/lib32", "/lib"}; - static const char *const PPCTriples[] = { - "powerpc-linux-gnu", "powerpc-unknown-linux-gnu", "powerpc-linux-gnuspe", - "powerpc-suse-linux", "powerpc-montavista-linuxspe"}; - static const char *const PPC64LibDirs[] = {"/lib64", "/lib"}; - static const char *const PPC64Triples[] = { - "powerpc64-linux-gnu", "powerpc64-unknown-linux-gnu", - "powerpc64-suse-linux", "ppc64-redhat-linux"}; - static const char *const PPC64LELibDirs[] = {"/lib64", "/lib"}; - static const char *const PPC64LETriples[] = { - "powerpc64le-linux-gnu", "powerpc64le-unknown-linux-gnu", - "powerpc64le-suse-linux", "ppc64le-redhat-linux"}; - - static const char *const SPARCv8LibDirs[] = {"/lib32", "/lib"}; - static const char *const SPARCv8Triples[] = {"sparc-linux-gnu", - "sparcv8-linux-gnu"}; - static const char *const SPARCv9LibDirs[] = {"/lib64", "/lib"}; - static const char *const SPARCv9Triples[] = {"sparc64-linux-gnu", - "sparcv9-linux-gnu"}; - - static const char *const SystemZLibDirs[] = {"/lib64", "/lib"}; - static const char *const SystemZTriples[] = { - "s390x-linux-gnu", "s390x-unknown-linux-gnu", "s390x-ibm-linux-gnu", - "s390x-suse-linux", "s390x-redhat-linux"}; - - // Solaris. - static const char *const SolarisSPARCLibDirs[] = {"/gcc"}; - static const char *const SolarisSPARCTriples[] = {"sparc-sun-solaris2.11", - "i386-pc-solaris2.11"}; - - using std::begin; - using std::end; - - if (TargetTriple.getOS() == llvm::Triple::Solaris) { - LibDirs.append(begin(SolarisSPARCLibDirs), end(SolarisSPARCLibDirs)); - TripleAliases.append(begin(SolarisSPARCTriples), end(SolarisSPARCTriples)); - return; - } - - switch (TargetTriple.getArch()) { - case llvm::Triple::aarch64: - LibDirs.append(begin(AArch64LibDirs), end(AArch64LibDirs)); - TripleAliases.append(begin(AArch64Triples), end(AArch64Triples)); - BiarchLibDirs.append(begin(AArch64LibDirs), end(AArch64LibDirs)); - BiarchTripleAliases.append(begin(AArch64Triples), end(AArch64Triples)); - break; - case llvm::Triple::aarch64_be: - LibDirs.append(begin(AArch64beLibDirs), end(AArch64beLibDirs)); - TripleAliases.append(begin(AArch64beTriples), end(AArch64beTriples)); - BiarchLibDirs.append(begin(AArch64beLibDirs), end(AArch64beLibDirs)); - BiarchTripleAliases.append(begin(AArch64beTriples), end(AArch64beTriples)); - break; - case llvm::Triple::arm: - case llvm::Triple::thumb: - LibDirs.append(begin(ARMLibDirs), end(ARMLibDirs)); - if (TargetTriple.getEnvironment() == llvm::Triple::GNUEABIHF) { - TripleAliases.append(begin(ARMHFTriples), end(ARMHFTriples)); - } else { - TripleAliases.append(begin(ARMTriples), end(ARMTriples)); - } - break; - case llvm::Triple::armeb: - case llvm::Triple::thumbeb: - LibDirs.append(begin(ARMebLibDirs), end(ARMebLibDirs)); - if (TargetTriple.getEnvironment() == llvm::Triple::GNUEABIHF) { - TripleAliases.append(begin(ARMebHFTriples), end(ARMebHFTriples)); - } else { - TripleAliases.append(begin(ARMebTriples), end(ARMebTriples)); - } - break; - case llvm::Triple::x86_64: - LibDirs.append(begin(X86_64LibDirs), end(X86_64LibDirs)); - TripleAliases.append(begin(X86_64Triples), end(X86_64Triples)); - // x32 is always available when x86_64 is available, so adding it as - // secondary arch with x86_64 triples - if (TargetTriple.getEnvironment() == llvm::Triple::GNUX32) { - BiarchLibDirs.append(begin(X32LibDirs), end(X32LibDirs)); - BiarchTripleAliases.append(begin(X86_64Triples), end(X86_64Triples)); - } else { - BiarchLibDirs.append(begin(X86LibDirs), end(X86LibDirs)); - BiarchTripleAliases.append(begin(X86Triples), end(X86Triples)); - } - break; - case llvm::Triple::x86: - LibDirs.append(begin(X86LibDirs), end(X86LibDirs)); - // MCU toolchain is 32 bit only and its triple alias is TargetTriple - // itself, which will be appended below. - if (!TargetTriple.isOSIAMCU()) { - TripleAliases.append(begin(X86Triples), end(X86Triples)); - BiarchLibDirs.append(begin(X86_64LibDirs), end(X86_64LibDirs)); - BiarchTripleAliases.append(begin(X86_64Triples), end(X86_64Triples)); - } - break; - case llvm::Triple::mips: - LibDirs.append(begin(MIPSLibDirs), end(MIPSLibDirs)); - TripleAliases.append(begin(MIPSTriples), end(MIPSTriples)); - BiarchLibDirs.append(begin(MIPS64LibDirs), end(MIPS64LibDirs)); - BiarchTripleAliases.append(begin(MIPS64Triples), end(MIPS64Triples)); - break; - case llvm::Triple::mipsel: - if (TargetTriple.isAndroid()) { - LibDirs.append(begin(MIPSELAndroidLibDirs), end(MIPSELAndroidLibDirs)); - TripleAliases.append(begin(MIPSELAndroidTriples), - end(MIPSELAndroidTriples)); - BiarchLibDirs.append(begin(MIPS64ELAndroidLibDirs), - end(MIPS64ELAndroidLibDirs)); - BiarchTripleAliases.append(begin(MIPS64ELAndroidTriples), - end(MIPS64ELAndroidTriples)); - - } else { - LibDirs.append(begin(MIPSELLibDirs), end(MIPSELLibDirs)); - TripleAliases.append(begin(MIPSELTriples), end(MIPSELTriples)); - TripleAliases.append(begin(MIPSTriples), end(MIPSTriples)); - BiarchLibDirs.append(begin(MIPS64ELLibDirs), end(MIPS64ELLibDirs)); - BiarchTripleAliases.append(begin(MIPS64ELTriples), end(MIPS64ELTriples)); - } - break; - case llvm::Triple::mips64: - LibDirs.append(begin(MIPS64LibDirs), end(MIPS64LibDirs)); - TripleAliases.append(begin(MIPS64Triples), end(MIPS64Triples)); - BiarchLibDirs.append(begin(MIPSLibDirs), end(MIPSLibDirs)); - BiarchTripleAliases.append(begin(MIPSTriples), end(MIPSTriples)); - break; - case llvm::Triple::mips64el: - if (TargetTriple.isAndroid()) { - LibDirs.append(begin(MIPS64ELAndroidLibDirs), - end(MIPS64ELAndroidLibDirs)); - TripleAliases.append(begin(MIPS64ELAndroidTriples), - end(MIPS64ELAndroidTriples)); - BiarchLibDirs.append(begin(MIPSELAndroidLibDirs), - end(MIPSELAndroidLibDirs)); - BiarchTripleAliases.append(begin(MIPSELAndroidTriples), - end(MIPSELAndroidTriples)); - - } else { - LibDirs.append(begin(MIPS64ELLibDirs), end(MIPS64ELLibDirs)); - TripleAliases.append(begin(MIPS64ELTriples), end(MIPS64ELTriples)); - BiarchLibDirs.append(begin(MIPSELLibDirs), end(MIPSELLibDirs)); - BiarchTripleAliases.append(begin(MIPSELTriples), end(MIPSELTriples)); - BiarchTripleAliases.append(begin(MIPSTriples), end(MIPSTriples)); - } - break; - case llvm::Triple::ppc: - LibDirs.append(begin(PPCLibDirs), end(PPCLibDirs)); - TripleAliases.append(begin(PPCTriples), end(PPCTriples)); - BiarchLibDirs.append(begin(PPC64LibDirs), end(PPC64LibDirs)); - BiarchTripleAliases.append(begin(PPC64Triples), end(PPC64Triples)); - break; - case llvm::Triple::ppc64: - LibDirs.append(begin(PPC64LibDirs), end(PPC64LibDirs)); - TripleAliases.append(begin(PPC64Triples), end(PPC64Triples)); - BiarchLibDirs.append(begin(PPCLibDirs), end(PPCLibDirs)); - BiarchTripleAliases.append(begin(PPCTriples), end(PPCTriples)); - break; - case llvm::Triple::ppc64le: - LibDirs.append(begin(PPC64LELibDirs), end(PPC64LELibDirs)); - TripleAliases.append(begin(PPC64LETriples), end(PPC64LETriples)); - break; - case llvm::Triple::sparc: - case llvm::Triple::sparcel: - LibDirs.append(begin(SPARCv8LibDirs), end(SPARCv8LibDirs)); - TripleAliases.append(begin(SPARCv8Triples), end(SPARCv8Triples)); - BiarchLibDirs.append(begin(SPARCv9LibDirs), end(SPARCv9LibDirs)); - BiarchTripleAliases.append(begin(SPARCv9Triples), end(SPARCv9Triples)); - break; - case llvm::Triple::sparcv9: - LibDirs.append(begin(SPARCv9LibDirs), end(SPARCv9LibDirs)); - TripleAliases.append(begin(SPARCv9Triples), end(SPARCv9Triples)); - BiarchLibDirs.append(begin(SPARCv8LibDirs), end(SPARCv8LibDirs)); - BiarchTripleAliases.append(begin(SPARCv8Triples), end(SPARCv8Triples)); - break; - case llvm::Triple::systemz: - LibDirs.append(begin(SystemZLibDirs), end(SystemZLibDirs)); - TripleAliases.append(begin(SystemZTriples), end(SystemZTriples)); - break; - default: - // By default, just rely on the standard lib directories and the original - // triple. - break; - } - - // Always append the drivers target triple to the end, in case it doesn't - // match any of our aliases. - TripleAliases.push_back(TargetTriple.str()); - - // Also include the multiarch variant if it's different. - if (TargetTriple.str() != BiarchTriple.str()) - BiarchTripleAliases.push_back(BiarchTriple.str()); -} - -// Parses the contents of version.txt in an CUDA installation. It should -// contain one line of the from e.g. "CUDA Version 7.5.2". -static CudaVersion ParseCudaVersionFile(llvm::StringRef V) { - if (!V.startswith("CUDA Version ")) - return CudaVersion::UNKNOWN; - V = V.substr(strlen("CUDA Version ")); - int Major = -1, Minor = -1; - auto First = V.split('.'); - auto Second = First.second.split('.'); - if (First.first.getAsInteger(10, Major) || - Second.first.getAsInteger(10, Minor)) - return CudaVersion::UNKNOWN; - - if (Major == 7 && Minor == 0) { - // This doesn't appear to ever happen -- version.txt doesn't exist in the - // CUDA 7 installs I've seen. But no harm in checking. - return CudaVersion::CUDA_70; - } - if (Major == 7 && Minor == 5) - return CudaVersion::CUDA_75; - if (Major == 8 && Minor == 0) - return CudaVersion::CUDA_80; - return CudaVersion::UNKNOWN; -} - -CudaInstallationDetector::CudaInstallationDetector( - const Driver &D, const llvm::Triple &HostTriple, - const llvm::opt::ArgList &Args) - : D(D) { - SmallVector<std::string, 4> CudaPathCandidates; - - // In decreasing order so we prefer newer versions to older versions. - std::initializer_list<const char *> Versions = {"8.0", "7.5", "7.0"}; - - if (Args.hasArg(options::OPT_cuda_path_EQ)) { - CudaPathCandidates.push_back( - Args.getLastArgValue(options::OPT_cuda_path_EQ)); - } else if (HostTriple.isOSWindows()) { - for (const char *Ver : Versions) - CudaPathCandidates.push_back( - D.SysRoot + "/Program Files/NVIDIA GPU Computing Toolkit/CUDA/v" + - Ver); - } else { - CudaPathCandidates.push_back(D.SysRoot + "/usr/local/cuda"); - for (const char *Ver : Versions) - CudaPathCandidates.push_back(D.SysRoot + "/usr/local/cuda-" + Ver); - } - - for (const auto &CudaPath : CudaPathCandidates) { - if (CudaPath.empty() || !D.getVFS().exists(CudaPath)) - continue; - - InstallPath = CudaPath; - BinPath = CudaPath + "/bin"; - IncludePath = InstallPath + "/include"; - LibDevicePath = InstallPath + "/nvvm/libdevice"; - - auto &FS = D.getVFS(); - if (!(FS.exists(IncludePath) && FS.exists(BinPath) && - FS.exists(LibDevicePath))) - continue; - - // On Linux, we have both lib and lib64 directories, and we need to choose - // based on our triple. On MacOS, we have only a lib directory. - // - // It's sufficient for our purposes to be flexible: If both lib and lib64 - // exist, we choose whichever one matches our triple. Otherwise, if only - // lib exists, we use it. - if (HostTriple.isArch64Bit() && FS.exists(InstallPath + "/lib64")) - LibPath = InstallPath + "/lib64"; - else if (FS.exists(InstallPath + "/lib")) - LibPath = InstallPath + "/lib"; - else - continue; - - llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> VersionFile = - FS.getBufferForFile(InstallPath + "/version.txt"); - if (!VersionFile) { - // CUDA 7.0 doesn't have a version.txt, so guess that's our version if - // version.txt isn't present. - Version = CudaVersion::CUDA_70; - } else { - 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; - } - } - } - - IsValid = true; - break; - } -} - -void CudaInstallationDetector::AddCudaIncludeArgs( - const ArgList &DriverArgs, ArgStringList &CC1Args) const { - if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) { - // Add cuda_wrappers/* to our system include path. This lets us wrap - // standard library headers. - SmallString<128> P(D.ResourceDir); - llvm::sys::path::append(P, "include"); - llvm::sys::path::append(P, "cuda_wrappers"); - CC1Args.push_back("-internal-isystem"); - CC1Args.push_back(DriverArgs.MakeArgString(P)); - } - - if (DriverArgs.hasArg(options::OPT_nocudainc)) - return; - - if (!isValid()) { - D.Diag(diag::err_drv_no_cuda_installation); - return; - } - - CC1Args.push_back("-internal-isystem"); - CC1Args.push_back(DriverArgs.MakeArgString(getIncludePath())); - CC1Args.push_back("-include"); - CC1Args.push_back("__clang_cuda_runtime_wrapper.h"); -} - -void CudaInstallationDetector::CheckCudaVersionSupportsArch( - CudaArch Arch) const { - if (Arch == CudaArch::UNKNOWN || Version == CudaVersion::UNKNOWN || - ArchsWithVersionTooLowErrors.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); - } -} - -void CudaInstallationDetector::print(raw_ostream &OS) const { - if (isValid()) - OS << "Found CUDA installation: " << InstallPath << ", version " - << CudaVersionToString(Version) << "\n"; -} - -namespace { -// Filter to remove Multilibs that don't exist as a suffix to Path -class FilterNonExistent { - StringRef Base, File; - vfs::FileSystem &VFS; - -public: - FilterNonExistent(StringRef Base, StringRef File, vfs::FileSystem &VFS) - : Base(Base), File(File), VFS(VFS) {} - bool operator()(const Multilib &M) { - return !VFS.exists(Base + M.gccSuffix() + File); - } -}; -} // end anonymous namespace - -static void addMultilibFlag(bool Enabled, const char *const Flag, - std::vector<std::string> &Flags) { - if (Enabled) - Flags.push_back(std::string("+") + Flag); - else - Flags.push_back(std::string("-") + Flag); -} - -static bool isArmOrThumbArch(llvm::Triple::ArchType Arch) { - return Arch == llvm::Triple::arm || Arch == llvm::Triple::thumb; -} - -static bool isMipsArch(llvm::Triple::ArchType Arch) { - return Arch == llvm::Triple::mips || Arch == llvm::Triple::mipsel || - Arch == llvm::Triple::mips64 || Arch == llvm::Triple::mips64el; -} - -static bool isMips32(llvm::Triple::ArchType Arch) { - return Arch == llvm::Triple::mips || Arch == llvm::Triple::mipsel; -} - -static bool isMips64(llvm::Triple::ArchType Arch) { - return Arch == llvm::Triple::mips64 || Arch == llvm::Triple::mips64el; -} - -static bool isMipsEL(llvm::Triple::ArchType Arch) { - return Arch == llvm::Triple::mipsel || Arch == llvm::Triple::mips64el; -} - -static bool isMips16(const ArgList &Args) { - Arg *A = Args.getLastArg(options::OPT_mips16, options::OPT_mno_mips16); - return A && A->getOption().matches(options::OPT_mips16); -} - -static bool isMicroMips(const ArgList &Args) { - Arg *A = Args.getLastArg(options::OPT_mmicromips, options::OPT_mno_micromips); - return A && A->getOption().matches(options::OPT_mmicromips); -} - -namespace { -struct DetectedMultilibs { - /// The set of multilibs that the detected installation supports. - MultilibSet Multilibs; - - /// The primary multilib appropriate for the given flags. - Multilib SelectedMultilib; - - /// On Biarch systems, this corresponds to the default multilib when - /// targeting the non-default multilib. Otherwise, it is empty. - llvm::Optional<Multilib> BiarchSibling; -}; -} // end anonymous namespace - -static Multilib makeMultilib(StringRef commonSuffix) { - return Multilib(commonSuffix, commonSuffix, commonSuffix); -} - -static bool findMipsCsMultilibs(const Multilib::flags_list &Flags, - FilterNonExistent &NonExistent, - DetectedMultilibs &Result) { - // Check for Code Sourcery toolchain multilibs - MultilibSet CSMipsMultilibs; - { - auto MArchMips16 = makeMultilib("/mips16").flag("+m32").flag("+mips16"); - - auto MArchMicroMips = - makeMultilib("/micromips").flag("+m32").flag("+mmicromips"); - - auto MArchDefault = makeMultilib("").flag("-mips16").flag("-mmicromips"); - - auto UCLibc = makeMultilib("/uclibc").flag("+muclibc"); - - auto SoftFloat = makeMultilib("/soft-float").flag("+msoft-float"); - - auto Nan2008 = makeMultilib("/nan2008").flag("+mnan=2008"); - - auto DefaultFloat = - makeMultilib("").flag("-msoft-float").flag("-mnan=2008"); - - auto BigEndian = makeMultilib("").flag("+EB").flag("-EL"); - - auto LittleEndian = makeMultilib("/el").flag("+EL").flag("-EB"); - - // Note that this one's osSuffix is "" - auto MAbi64 = makeMultilib("") - .gccSuffix("/64") - .includeSuffix("/64") - .flag("+mabi=n64") - .flag("-mabi=n32") - .flag("-m32"); - - CSMipsMultilibs = - MultilibSet() - .Either(MArchMips16, MArchMicroMips, MArchDefault) - .Maybe(UCLibc) - .Either(SoftFloat, Nan2008, DefaultFloat) - .FilterOut("/micromips/nan2008") - .FilterOut("/mips16/nan2008") - .Either(BigEndian, LittleEndian) - .Maybe(MAbi64) - .FilterOut("/mips16.*/64") - .FilterOut("/micromips.*/64") - .FilterOut(NonExistent) - .setIncludeDirsCallback([](const Multilib &M) { - std::vector<std::string> Dirs({"/include"}); - if (StringRef(M.includeSuffix()).startswith("/uclibc")) - Dirs.push_back( - "/../../../../mips-linux-gnu/libc/uclibc/usr/include"); - else - Dirs.push_back("/../../../../mips-linux-gnu/libc/usr/include"); - return Dirs; - }); - } - - MultilibSet DebianMipsMultilibs; - { - Multilib MAbiN32 = - Multilib().gccSuffix("/n32").includeSuffix("/n32").flag("+mabi=n32"); - - Multilib M64 = Multilib() - .gccSuffix("/64") - .includeSuffix("/64") - .flag("+m64") - .flag("-m32") - .flag("-mabi=n32"); - - Multilib M32 = Multilib().flag("-m64").flag("+m32").flag("-mabi=n32"); - - DebianMipsMultilibs = - MultilibSet().Either(M32, M64, MAbiN32).FilterOut(NonExistent); - } - - // Sort candidates. Toolchain that best meets the directories tree goes first. - // Then select the first toolchains matches command line flags. - MultilibSet *Candidates[] = {&CSMipsMultilibs, &DebianMipsMultilibs}; - if (CSMipsMultilibs.size() < DebianMipsMultilibs.size()) - std::iter_swap(Candidates, Candidates + 1); - for (const MultilibSet *Candidate : Candidates) { - if (Candidate->select(Flags, Result.SelectedMultilib)) { - if (Candidate == &DebianMipsMultilibs) - Result.BiarchSibling = Multilib(); - Result.Multilibs = *Candidate; - return true; - } - } - return false; -} - -static bool findMipsAndroidMultilibs(vfs::FileSystem &VFS, StringRef Path, - const Multilib::flags_list &Flags, - FilterNonExistent &NonExistent, - DetectedMultilibs &Result) { - - MultilibSet AndroidMipsMultilibs = - MultilibSet() - .Maybe(Multilib("/mips-r2").flag("+march=mips32r2")) - .Maybe(Multilib("/mips-r6").flag("+march=mips32r6")) - .FilterOut(NonExistent); - - MultilibSet AndroidMipselMultilibs = - MultilibSet() - .Either(Multilib().flag("+march=mips32"), - Multilib("/mips-r2", "", "/mips-r2").flag("+march=mips32r2"), - Multilib("/mips-r6", "", "/mips-r6").flag("+march=mips32r6")) - .FilterOut(NonExistent); - - MultilibSet AndroidMips64elMultilibs = - MultilibSet() - .Either( - Multilib().flag("+march=mips64r6"), - Multilib("/32/mips-r1", "", "/mips-r1").flag("+march=mips32"), - Multilib("/32/mips-r2", "", "/mips-r2").flag("+march=mips32r2"), - Multilib("/32/mips-r6", "", "/mips-r6").flag("+march=mips32r6")) - .FilterOut(NonExistent); - - MultilibSet *MS = &AndroidMipsMultilibs; - if (VFS.exists(Path + "/mips-r6")) - MS = &AndroidMipselMultilibs; - else if (VFS.exists(Path + "/32")) - MS = &AndroidMips64elMultilibs; - if (MS->select(Flags, Result.SelectedMultilib)) { - Result.Multilibs = *MS; - return true; - } - return false; -} - -static bool findMipsMuslMultilibs(const Multilib::flags_list &Flags, - FilterNonExistent &NonExistent, - DetectedMultilibs &Result) { - // Musl toolchain multilibs - MultilibSet MuslMipsMultilibs; - { - auto MArchMipsR2 = makeMultilib("") - .osSuffix("/mips-r2-hard-musl") - .flag("+EB") - .flag("-EL") - .flag("+march=mips32r2"); - - auto MArchMipselR2 = makeMultilib("/mipsel-r2-hard-musl") - .flag("-EB") - .flag("+EL") - .flag("+march=mips32r2"); - - MuslMipsMultilibs = MultilibSet().Either(MArchMipsR2, MArchMipselR2); - - // Specify the callback that computes the include directories. - MuslMipsMultilibs.setIncludeDirsCallback([](const Multilib &M) { - return std::vector<std::string>( - {"/../sysroot" + M.osSuffix() + "/usr/include"}); - }); - } - if (MuslMipsMultilibs.select(Flags, Result.SelectedMultilib)) { - Result.Multilibs = MuslMipsMultilibs; - return true; - } - return false; -} - -static bool findMipsMtiMultilibs(const Multilib::flags_list &Flags, - FilterNonExistent &NonExistent, - DetectedMultilibs &Result) { - // CodeScape MTI toolchain v1.2 and early. - MultilibSet MtiMipsMultilibsV1; - { - auto MArchMips32 = makeMultilib("/mips32") - .flag("+m32") - .flag("-m64") - .flag("-mmicromips") - .flag("+march=mips32"); - - auto MArchMicroMips = makeMultilib("/micromips") - .flag("+m32") - .flag("-m64") - .flag("+mmicromips"); - - auto MArchMips64r2 = makeMultilib("/mips64r2") - .flag("-m32") - .flag("+m64") - .flag("+march=mips64r2"); - - auto MArchMips64 = makeMultilib("/mips64").flag("-m32").flag("+m64").flag( - "-march=mips64r2"); - - auto MArchDefault = makeMultilib("") - .flag("+m32") - .flag("-m64") - .flag("-mmicromips") - .flag("+march=mips32r2"); - - auto Mips16 = makeMultilib("/mips16").flag("+mips16"); - - auto UCLibc = makeMultilib("/uclibc").flag("+muclibc"); - - auto MAbi64 = - makeMultilib("/64").flag("+mabi=n64").flag("-mabi=n32").flag("-m32"); - - auto BigEndian = makeMultilib("").flag("+EB").flag("-EL"); - - auto LittleEndian = makeMultilib("/el").flag("+EL").flag("-EB"); - - auto SoftFloat = makeMultilib("/sof").flag("+msoft-float"); - - auto Nan2008 = makeMultilib("/nan2008").flag("+mnan=2008"); - - MtiMipsMultilibsV1 = - MultilibSet() - .Either(MArchMips32, MArchMicroMips, MArchMips64r2, MArchMips64, - MArchDefault) - .Maybe(UCLibc) - .Maybe(Mips16) - .FilterOut("/mips64/mips16") - .FilterOut("/mips64r2/mips16") - .FilterOut("/micromips/mips16") - .Maybe(MAbi64) - .FilterOut("/micromips/64") - .FilterOut("/mips32/64") - .FilterOut("^/64") - .FilterOut("/mips16/64") - .Either(BigEndian, LittleEndian) - .Maybe(SoftFloat) - .Maybe(Nan2008) - .FilterOut(".*sof/nan2008") - .FilterOut(NonExistent) - .setIncludeDirsCallback([](const Multilib &M) { - std::vector<std::string> Dirs({"/include"}); - if (StringRef(M.includeSuffix()).startswith("/uclibc")) - Dirs.push_back("/../../../../sysroot/uclibc/usr/include"); - else - Dirs.push_back("/../../../../sysroot/usr/include"); - return Dirs; - }); - } - - // CodeScape IMG toolchain starting from v1.3. - MultilibSet MtiMipsMultilibsV2; - { - auto BeHard = makeMultilib("/mips-r2-hard") - .flag("+EB") - .flag("-msoft-float") - .flag("-mnan=2008") - .flag("-muclibc"); - auto BeSoft = makeMultilib("/mips-r2-soft") - .flag("+EB") - .flag("+msoft-float") - .flag("-mnan=2008"); - auto ElHard = makeMultilib("/mipsel-r2-hard") - .flag("+EL") - .flag("-msoft-float") - .flag("-mnan=2008") - .flag("-muclibc"); - auto ElSoft = makeMultilib("/mipsel-r2-soft") - .flag("+EL") - .flag("+msoft-float") - .flag("-mnan=2008") - .flag("-mmicromips"); - auto BeHardNan = makeMultilib("/mips-r2-hard-nan2008") - .flag("+EB") - .flag("-msoft-float") - .flag("+mnan=2008") - .flag("-muclibc"); - auto ElHardNan = makeMultilib("/mipsel-r2-hard-nan2008") - .flag("+EL") - .flag("-msoft-float") - .flag("+mnan=2008") - .flag("-muclibc") - .flag("-mmicromips"); - auto BeHardNanUclibc = makeMultilib("/mips-r2-hard-nan2008-uclibc") - .flag("+EB") - .flag("-msoft-float") - .flag("+mnan=2008") - .flag("+muclibc"); - auto ElHardNanUclibc = makeMultilib("/mipsel-r2-hard-nan2008-uclibc") - .flag("+EL") - .flag("-msoft-float") - .flag("+mnan=2008") - .flag("+muclibc"); - auto BeHardUclibc = makeMultilib("/mips-r2-hard-uclibc") - .flag("+EB") - .flag("-msoft-float") - .flag("-mnan=2008") - .flag("+muclibc"); - auto ElHardUclibc = makeMultilib("/mipsel-r2-hard-uclibc") - .flag("+EL") - .flag("-msoft-float") - .flag("-mnan=2008") - .flag("+muclibc"); - auto ElMicroHardNan = makeMultilib("/micromipsel-r2-hard-nan2008") - .flag("+EL") - .flag("-msoft-float") - .flag("+mnan=2008") - .flag("+mmicromips"); - auto ElMicroSoft = makeMultilib("/micromipsel-r2-soft") - .flag("+EL") - .flag("+msoft-float") - .flag("-mnan=2008") - .flag("+mmicromips"); - - auto O32 = - makeMultilib("/lib").osSuffix("").flag("-mabi=n32").flag("-mabi=n64"); - auto N32 = - makeMultilib("/lib32").osSuffix("").flag("+mabi=n32").flag("-mabi=n64"); - auto N64 = - makeMultilib("/lib64").osSuffix("").flag("-mabi=n32").flag("+mabi=n64"); - - MtiMipsMultilibsV2 = - MultilibSet() - .Either({BeHard, BeSoft, ElHard, ElSoft, BeHardNan, ElHardNan, - BeHardNanUclibc, ElHardNanUclibc, BeHardUclibc, - ElHardUclibc, ElMicroHardNan, ElMicroSoft}) - .Either(O32, N32, N64) - .FilterOut(NonExistent) - .setIncludeDirsCallback([](const Multilib &M) { - return std::vector<std::string>({"/../../../../sysroot" + - M.includeSuffix() + - "/../usr/include"}); - }) - .setFilePathsCallback([](const Multilib &M) { - return std::vector<std::string>( - {"/../../../../mips-mti-linux-gnu/lib" + M.gccSuffix()}); - }); - } - for (auto Candidate : {&MtiMipsMultilibsV1, &MtiMipsMultilibsV2}) { - if (Candidate->select(Flags, Result.SelectedMultilib)) { - Result.Multilibs = *Candidate; - return true; - } - } - return false; -} - -static bool findMipsImgMultilibs(const Multilib::flags_list &Flags, - FilterNonExistent &NonExistent, - DetectedMultilibs &Result) { - // CodeScape IMG toolchain v1.2 and early. - MultilibSet ImgMultilibsV1; - { - auto Mips64r6 = makeMultilib("/mips64r6").flag("+m64").flag("-m32"); - - auto LittleEndian = makeMultilib("/el").flag("+EL").flag("-EB"); - - auto MAbi64 = - makeMultilib("/64").flag("+mabi=n64").flag("-mabi=n32").flag("-m32"); - - ImgMultilibsV1 = - MultilibSet() - .Maybe(Mips64r6) - .Maybe(MAbi64) - .Maybe(LittleEndian) - .FilterOut(NonExistent) - .setIncludeDirsCallback([](const Multilib &M) { - return std::vector<std::string>( - {"/include", "/../../../../sysroot/usr/include"}); - }); - } - - // CodeScape IMG toolchain starting from v1.3. - MultilibSet ImgMultilibsV2; - { - auto BeHard = makeMultilib("/mips-r6-hard") - .flag("+EB") - .flag("-msoft-float") - .flag("-mmicromips"); - auto BeSoft = makeMultilib("/mips-r6-soft") - .flag("+EB") - .flag("+msoft-float") - .flag("-mmicromips"); - auto ElHard = makeMultilib("/mipsel-r6-hard") - .flag("+EL") - .flag("-msoft-float") - .flag("-mmicromips"); - auto ElSoft = makeMultilib("/mipsel-r6-soft") - .flag("+EL") - .flag("+msoft-float") - .flag("-mmicromips"); - auto BeMicroHard = makeMultilib("/micromips-r6-hard") - .flag("+EB") - .flag("-msoft-float") - .flag("+mmicromips"); - auto BeMicroSoft = makeMultilib("/micromips-r6-soft") - .flag("+EB") - .flag("+msoft-float") - .flag("+mmicromips"); - auto ElMicroHard = makeMultilib("/micromipsel-r6-hard") - .flag("+EL") - .flag("-msoft-float") - .flag("+mmicromips"); - auto ElMicroSoft = makeMultilib("/micromipsel-r6-soft") - .flag("+EL") - .flag("+msoft-float") - .flag("+mmicromips"); - - auto O32 = - makeMultilib("/lib").osSuffix("").flag("-mabi=n32").flag("-mabi=n64"); - auto N32 = - makeMultilib("/lib32").osSuffix("").flag("+mabi=n32").flag("-mabi=n64"); - auto N64 = - makeMultilib("/lib64").osSuffix("").flag("-mabi=n32").flag("+mabi=n64"); - - ImgMultilibsV2 = - MultilibSet() - .Either({BeHard, BeSoft, ElHard, ElSoft, BeMicroHard, BeMicroSoft, - ElMicroHard, ElMicroSoft}) - .Either(O32, N32, N64) - .FilterOut(NonExistent) - .setIncludeDirsCallback([](const Multilib &M) { - return std::vector<std::string>({"/../../../../sysroot" + - M.includeSuffix() + - "/../usr/include"}); - }) - .setFilePathsCallback([](const Multilib &M) { - return std::vector<std::string>( - {"/../../../../mips-img-linux-gnu/lib" + M.gccSuffix()}); - }); - } - for (auto Candidate : {&ImgMultilibsV1, &ImgMultilibsV2}) { - if (Candidate->select(Flags, Result.SelectedMultilib)) { - Result.Multilibs = *Candidate; - return true; - } - } - return false; -} - -static bool findMIPSMultilibs(const Driver &D, const llvm::Triple &TargetTriple, - StringRef Path, const ArgList &Args, - DetectedMultilibs &Result) { - FilterNonExistent NonExistent(Path, "/crtbegin.o", D.getVFS()); - - StringRef CPUName; - StringRef ABIName; - tools::mips::getMipsCPUAndABI(Args, TargetTriple, CPUName, ABIName); - - llvm::Triple::ArchType TargetArch = TargetTriple.getArch(); - - Multilib::flags_list Flags; - addMultilibFlag(isMips32(TargetArch), "m32", Flags); - addMultilibFlag(isMips64(TargetArch), "m64", Flags); - addMultilibFlag(isMips16(Args), "mips16", Flags); - addMultilibFlag(CPUName == "mips32", "march=mips32", Flags); - addMultilibFlag(CPUName == "mips32r2" || CPUName == "mips32r3" || - CPUName == "mips32r5" || CPUName == "p5600", - "march=mips32r2", Flags); - addMultilibFlag(CPUName == "mips32r6", "march=mips32r6", Flags); - addMultilibFlag(CPUName == "mips64", "march=mips64", Flags); - addMultilibFlag(CPUName == "mips64r2" || CPUName == "mips64r3" || - CPUName == "mips64r5" || CPUName == "octeon", - "march=mips64r2", Flags); - addMultilibFlag(CPUName == "mips64r6", "march=mips64r6", Flags); - addMultilibFlag(isMicroMips(Args), "mmicromips", Flags); - addMultilibFlag(tools::mips::isUCLibc(Args), "muclibc", Flags); - addMultilibFlag(tools::mips::isNaN2008(Args, TargetTriple), "mnan=2008", - Flags); - addMultilibFlag(ABIName == "n32", "mabi=n32", Flags); - addMultilibFlag(ABIName == "n64", "mabi=n64", Flags); - addMultilibFlag(isSoftFloatABI(Args), "msoft-float", Flags); - addMultilibFlag(!isSoftFloatABI(Args), "mhard-float", Flags); - addMultilibFlag(isMipsEL(TargetArch), "EL", Flags); - addMultilibFlag(!isMipsEL(TargetArch), "EB", Flags); - - if (TargetTriple.isAndroid()) - return findMipsAndroidMultilibs(D.getVFS(), Path, Flags, NonExistent, - Result); - - if (TargetTriple.getVendor() == llvm::Triple::MipsTechnologies && - TargetTriple.getOS() == llvm::Triple::Linux && - TargetTriple.getEnvironment() == llvm::Triple::UnknownEnvironment) - return findMipsMuslMultilibs(Flags, NonExistent, Result); - - if (TargetTriple.getVendor() == llvm::Triple::MipsTechnologies && - TargetTriple.getOS() == llvm::Triple::Linux && - TargetTriple.getEnvironment() == llvm::Triple::GNU) - return findMipsMtiMultilibs(Flags, NonExistent, Result); - - if (TargetTriple.getVendor() == llvm::Triple::ImaginationTechnologies && - TargetTriple.getOS() == llvm::Triple::Linux && - TargetTriple.getEnvironment() == llvm::Triple::GNU) - return findMipsImgMultilibs(Flags, NonExistent, Result); - - if (findMipsCsMultilibs(Flags, NonExistent, Result)) - return true; - - // Fallback to the regular toolchain-tree structure. - Multilib Default; - Result.Multilibs.push_back(Default); - Result.Multilibs.FilterOut(NonExistent); - - if (Result.Multilibs.select(Flags, Result.SelectedMultilib)) { - Result.BiarchSibling = Multilib(); - return true; - } - - return false; -} - -static void findAndroidArmMultilibs(const Driver &D, - const llvm::Triple &TargetTriple, - StringRef Path, const ArgList &Args, - DetectedMultilibs &Result) { - // Find multilibs with subdirectories like armv7-a, thumb, armv7-a/thumb. - FilterNonExistent NonExistent(Path, "/crtbegin.o", D.getVFS()); - Multilib ArmV7Multilib = makeMultilib("/armv7-a") - .flag("+armv7") - .flag("-thumb"); - Multilib ThumbMultilib = makeMultilib("/thumb") - .flag("-armv7") - .flag("+thumb"); - Multilib ArmV7ThumbMultilib = makeMultilib("/armv7-a/thumb") - .flag("+armv7") - .flag("+thumb"); - Multilib DefaultMultilib = makeMultilib("") - .flag("-armv7") - .flag("-thumb"); - MultilibSet AndroidArmMultilibs = - MultilibSet() - .Either(ThumbMultilib, ArmV7Multilib, - ArmV7ThumbMultilib, DefaultMultilib) - .FilterOut(NonExistent); - - Multilib::flags_list Flags; - llvm::StringRef Arch = Args.getLastArgValue(options::OPT_march_EQ); - bool IsArmArch = TargetTriple.getArch() == llvm::Triple::arm; - bool IsThumbArch = TargetTriple.getArch() == llvm::Triple::thumb; - bool IsV7SubArch = TargetTriple.getSubArch() == llvm::Triple::ARMSubArch_v7; - bool IsThumbMode = IsThumbArch || - Args.hasFlag(options::OPT_mthumb, options::OPT_mno_thumb, false) || - (IsArmArch && llvm::ARM::parseArchISA(Arch) == llvm::ARM::IK_THUMB); - bool IsArmV7Mode = (IsArmArch || IsThumbArch) && - (llvm::ARM::parseArchVersion(Arch) == 7 || - (IsArmArch && Arch == "" && IsV7SubArch)); - addMultilibFlag(IsArmV7Mode, "armv7", Flags); - addMultilibFlag(IsThumbMode, "thumb", Flags); - - if (AndroidArmMultilibs.select(Flags, Result.SelectedMultilib)) - Result.Multilibs = AndroidArmMultilibs; -} - -static bool findBiarchMultilibs(const Driver &D, - const llvm::Triple &TargetTriple, - StringRef Path, const ArgList &Args, - bool NeedsBiarchSuffix, - DetectedMultilibs &Result) { - // Some versions of SUSE and Fedora on ppc64 put 32-bit libs - // in what would normally be GCCInstallPath and put the 64-bit - // libs in a subdirectory named 64. The simple logic we follow is that - // *if* there is a subdirectory of the right name with crtbegin.o in it, - // we use that. If not, and if not a biarch triple alias, we look for - // crtbegin.o without the subdirectory. - - Multilib Default; - Multilib Alt64 = Multilib() - .gccSuffix("/64") - .includeSuffix("/64") - .flag("-m32") - .flag("+m64") - .flag("-mx32"); - Multilib Alt32 = Multilib() - .gccSuffix("/32") - .includeSuffix("/32") - .flag("+m32") - .flag("-m64") - .flag("-mx32"); - Multilib Altx32 = Multilib() - .gccSuffix("/x32") - .includeSuffix("/x32") - .flag("-m32") - .flag("-m64") - .flag("+mx32"); - - // GCC toolchain for IAMCU doesn't have crtbegin.o, so look for libgcc.a. - FilterNonExistent NonExistent( - Path, TargetTriple.isOSIAMCU() ? "/libgcc.a" : "/crtbegin.o", D.getVFS()); - - // Determine default multilib from: 32, 64, x32 - // Also handle cases such as 64 on 32, 32 on 64, etc. - enum { UNKNOWN, WANT32, WANT64, WANTX32 } Want = UNKNOWN; - const bool IsX32 = TargetTriple.getEnvironment() == llvm::Triple::GNUX32; - if (TargetTriple.isArch32Bit() && !NonExistent(Alt32)) - Want = WANT64; - else if (TargetTriple.isArch64Bit() && IsX32 && !NonExistent(Altx32)) - Want = WANT64; - else if (TargetTriple.isArch64Bit() && !IsX32 && !NonExistent(Alt64)) - Want = WANT32; - else { - if (TargetTriple.isArch32Bit()) - Want = NeedsBiarchSuffix ? WANT64 : WANT32; - else if (IsX32) - Want = NeedsBiarchSuffix ? WANT64 : WANTX32; - else - Want = NeedsBiarchSuffix ? WANT32 : WANT64; - } - - if (Want == WANT32) - Default.flag("+m32").flag("-m64").flag("-mx32"); - else if (Want == WANT64) - Default.flag("-m32").flag("+m64").flag("-mx32"); - else if (Want == WANTX32) - Default.flag("-m32").flag("-m64").flag("+mx32"); - else - return false; - - Result.Multilibs.push_back(Default); - Result.Multilibs.push_back(Alt64); - Result.Multilibs.push_back(Alt32); - Result.Multilibs.push_back(Altx32); - - Result.Multilibs.FilterOut(NonExistent); - - Multilib::flags_list Flags; - addMultilibFlag(TargetTriple.isArch64Bit() && !IsX32, "m64", Flags); - addMultilibFlag(TargetTriple.isArch32Bit(), "m32", Flags); - addMultilibFlag(TargetTriple.isArch64Bit() && IsX32, "mx32", Flags); - - if (!Result.Multilibs.select(Flags, Result.SelectedMultilib)) - return false; - - if (Result.SelectedMultilib == Alt64 || Result.SelectedMultilib == Alt32 || - Result.SelectedMultilib == Altx32) - Result.BiarchSibling = Default; - - return true; -} - -void Generic_GCC::GCCInstallationDetector::scanLibDirForGCCTripleSolaris( - const llvm::Triple &TargetArch, const llvm::opt::ArgList &Args, - const std::string &LibDir, StringRef CandidateTriple, - bool NeedsBiarchSuffix) { - // Solaris is a special case. The GCC installation is under - // /usr/gcc/<major>.<minor>/lib/gcc/<triple>/<major>.<minor>.<patch>/, so we - // need to iterate twice. - std::error_code EC; - for (vfs::directory_iterator LI = D.getVFS().dir_begin(LibDir, EC), LE; - !EC && LI != LE; LI = LI.increment(EC)) { - StringRef VersionText = llvm::sys::path::filename(LI->getName()); - GCCVersion CandidateVersion = GCCVersion::Parse(VersionText); - - if (CandidateVersion.Major != -1) // Filter obviously bad entries. - if (!CandidateGCCInstallPaths.insert(LI->getName()).second) - continue; // Saw this path before; no need to look at it again. - if (CandidateVersion.isOlderThan(4, 1, 1)) - continue; - if (CandidateVersion <= Version) - continue; - - GCCInstallPath = - LibDir + "/" + VersionText.str() + "/lib/gcc/" + CandidateTriple.str(); - if (!D.getVFS().exists(GCCInstallPath)) - continue; - - // If we make it here there has to be at least one GCC version, let's just - // use the latest one. - std::error_code EEC; - for (vfs::directory_iterator - LLI = D.getVFS().dir_begin(GCCInstallPath, EEC), - LLE; - !EEC && LLI != LLE; LLI = LLI.increment(EEC)) { - - StringRef SubVersionText = llvm::sys::path::filename(LLI->getName()); - GCCVersion CandidateSubVersion = GCCVersion::Parse(SubVersionText); - - if (CandidateSubVersion > Version) - Version = CandidateSubVersion; - } - - GCCTriple.setTriple(CandidateTriple); - - GCCInstallPath += "/" + Version.Text; - GCCParentLibPath = GCCInstallPath + "/../../../../"; - - IsValid = true; - } -} - -bool Generic_GCC::GCCInstallationDetector::ScanGCCForMultilibs( - const llvm::Triple &TargetTriple, const ArgList &Args, - StringRef Path, bool NeedsBiarchSuffix) { - llvm::Triple::ArchType TargetArch = TargetTriple.getArch(); - DetectedMultilibs Detected; - - // Android standalone toolchain could have multilibs for ARM and Thumb. - // Debian mips multilibs behave more like the rest of the biarch ones, - // so handle them there - if (isArmOrThumbArch(TargetArch) && TargetTriple.isAndroid()) { - // It should also work without multilibs in a simplified toolchain. - findAndroidArmMultilibs(D, TargetTriple, Path, Args, Detected); - } else if (isMipsArch(TargetArch)) { - if (!findMIPSMultilibs(D, TargetTriple, Path, Args, Detected)) - return false; - } else if (!findBiarchMultilibs(D, TargetTriple, Path, Args, - NeedsBiarchSuffix, Detected)) { - return false; - } - - Multilibs = Detected.Multilibs; - SelectedMultilib = Detected.SelectedMultilib; - BiarchSibling = Detected.BiarchSibling; - - return true; -} - -void Generic_GCC::GCCInstallationDetector::ScanLibDirForGCCTriple( - const llvm::Triple &TargetTriple, const ArgList &Args, - const std::string &LibDir, StringRef CandidateTriple, - bool NeedsBiarchSuffix) { - if (TargetTriple.getOS() == llvm::Triple::Solaris) { - scanLibDirForGCCTripleSolaris(TargetTriple, Args, LibDir, CandidateTriple, - NeedsBiarchSuffix); - return; - } - - llvm::Triple::ArchType TargetArch = TargetTriple.getArch(); - // Locations relative to the system lib directory where GCC's triple-specific - // directories might reside. - struct GCCLibSuffix { - // Path from system lib directory to GCC triple-specific directory. - std::string LibSuffix; - // Path from GCC triple-specific directory back to system lib directory. - // This is one '..' component per component in LibSuffix. - StringRef ReversePath; - // Whether this library suffix is relevant for the triple. - bool Active; - } Suffixes[] = { - // This is the normal place. - {"gcc/" + CandidateTriple.str(), "../..", true}, - - // Debian puts cross-compilers in gcc-cross. - {"gcc-cross/" + CandidateTriple.str(), "../..", true}, - - // The Freescale PPC SDK has the gcc libraries in - // <sysroot>/usr/lib/<triple>/x.y.z so have a look there as well. Only do - // this on Freescale triples, though, since some systems put a *lot* of - // files in that location, not just GCC installation data. - {CandidateTriple.str(), "..", - TargetTriple.getVendor() == llvm::Triple::Freescale}, - - // Natively multiarch systems sometimes put the GCC triple-specific - // directory within their multiarch lib directory, resulting in the - // triple appearing twice. - {CandidateTriple.str() + "/gcc/" + CandidateTriple.str(), "../../..", true}, - - // Deal with cases (on Ubuntu) where the system architecture could be i386 - // but the GCC target architecture could be (say) i686. - // FIXME: It may be worthwhile to generalize this and look for a second - // triple. - {"i386-linux-gnu/gcc/" + CandidateTriple.str(), "../../..", - TargetArch == llvm::Triple::x86} - }; - - for (auto &Suffix : Suffixes) { - if (!Suffix.Active) - continue; - - StringRef LibSuffix = Suffix.LibSuffix; - std::error_code EC; - for (vfs::directory_iterator - LI = D.getVFS().dir_begin(LibDir + "/" + LibSuffix, EC), - LE; - !EC && LI != LE; LI = LI.increment(EC)) { - StringRef VersionText = llvm::sys::path::filename(LI->getName()); - GCCVersion CandidateVersion = GCCVersion::Parse(VersionText); - if (CandidateVersion.Major != -1) // Filter obviously bad entries. - if (!CandidateGCCInstallPaths.insert(LI->getName()).second) - continue; // Saw this path before; no need to look at it again. - if (CandidateVersion.isOlderThan(4, 1, 1)) - continue; - if (CandidateVersion <= Version) - continue; - - if (!ScanGCCForMultilibs(TargetTriple, Args, LI->getName(), - NeedsBiarchSuffix)) - continue; - - Version = CandidateVersion; - GCCTriple.setTriple(CandidateTriple); - // FIXME: We hack together the directory name here instead of - // using LI to ensure stable path separators across Windows and - // Linux. - GCCInstallPath = (LibDir + "/" + LibSuffix + "/" + VersionText).str(); - GCCParentLibPath = (GCCInstallPath + "/../" + Suffix.ReversePath).str(); - IsValid = true; - } - } -} - -bool Generic_GCC::GCCInstallationDetector::ScanGentooGccConfig( - const llvm::Triple &TargetTriple, const ArgList &Args, - StringRef CandidateTriple, bool NeedsBiarchSuffix) { - llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> File = - D.getVFS().getBufferForFile(D.SysRoot + "/etc/env.d/gcc/config-" + - CandidateTriple.str()); - if (File) { - SmallVector<StringRef, 2> Lines; - File.get()->getBuffer().split(Lines, "\n"); - for (StringRef Line : Lines) { - // CURRENT=triple-version - if (Line.consume_front("CURRENT=")) { - const std::pair<StringRef, StringRef> ActiveVersion = - Line.rsplit('-'); - // Note: Strictly speaking, we should be reading - // /etc/env.d/gcc/${CURRENT} now. However, the file doesn't - // contain anything new or especially useful to us. - const std::string GentooPath = D.SysRoot + "/usr/lib/gcc/" + - ActiveVersion.first.str() + "/" + - ActiveVersion.second.str(); - if (D.getVFS().exists(GentooPath + "/crtbegin.o")) { - if (!ScanGCCForMultilibs(TargetTriple, Args, GentooPath, - NeedsBiarchSuffix)) - return false; - - Version = GCCVersion::Parse(ActiveVersion.second); - GCCInstallPath = GentooPath; - GCCParentLibPath = GentooPath + "/../../.."; - GCCTriple.setTriple(ActiveVersion.first); - IsValid = true; - return true; - } - } - } - } - - return false; -} - -Generic_GCC::Generic_GCC(const Driver &D, const llvm::Triple &Triple, - const ArgList &Args) - : ToolChain(D, Triple, Args), GCCInstallation(D), - CudaInstallation(D, Triple, Args) { - getProgramPaths().push_back(getDriver().getInstalledDir()); - if (getDriver().getInstalledDir() != getDriver().Dir) - getProgramPaths().push_back(getDriver().Dir); -} - -Generic_GCC::~Generic_GCC() {} - -Tool *Generic_GCC::getTool(Action::ActionClass AC) const { - switch (AC) { - case Action::PreprocessJobClass: - if (!Preprocess) - Preprocess.reset(new tools::gcc::Preprocessor(*this)); - return Preprocess.get(); - case Action::CompileJobClass: - if (!Compile) - Compile.reset(new tools::gcc::Compiler(*this)); - return Compile.get(); - default: - return ToolChain::getTool(AC); - } -} - -Tool *Generic_GCC::buildAssembler() const { - return new tools::gnutools::Assembler(*this); -} - -Tool *Generic_GCC::buildLinker() const { return new tools::gcc::Linker(*this); } - -void Generic_GCC::printVerboseInfo(raw_ostream &OS) const { - // Print the information about how we detected the GCC installation. - GCCInstallation.print(OS); - CudaInstallation.print(OS); -} - -bool Generic_GCC::IsUnwindTablesDefault() const { - return getArch() == llvm::Triple::x86_64; -} - -bool Generic_GCC::isPICDefault() const { - switch (getArch()) { - case llvm::Triple::x86_64: - return getTriple().isOSWindows(); - case llvm::Triple::ppc64: - case llvm::Triple::ppc64le: - return !getTriple().isOSBinFormatMachO() && !getTriple().isMacOSX(); - case llvm::Triple::mips64: - case llvm::Triple::mips64el: - return true; - default: - return false; - } -} - -bool Generic_GCC::isPIEDefault() const { return false; } - -bool Generic_GCC::isPICDefaultForced() const { - return getArch() == llvm::Triple::x86_64 && getTriple().isOSWindows(); -} - -bool Generic_GCC::IsIntegratedAssemblerDefault() const { - switch (getTriple().getArch()) { - case llvm::Triple::x86: - case llvm::Triple::x86_64: - case llvm::Triple::aarch64: - case llvm::Triple::aarch64_be: - case llvm::Triple::arm: - case llvm::Triple::armeb: - case llvm::Triple::avr: - case llvm::Triple::bpfel: - case llvm::Triple::bpfeb: - case llvm::Triple::thumb: - case llvm::Triple::thumbeb: - case llvm::Triple::ppc: - case llvm::Triple::ppc64: - case llvm::Triple::ppc64le: - case llvm::Triple::systemz: - case llvm::Triple::mips: - case llvm::Triple::mipsel: - return true; - case llvm::Triple::mips64: - case llvm::Triple::mips64el: - // Enabled for Debian mips64/mips64el only. Other targets are unable to - // distinguish N32 from N64. - if (getTriple().getEnvironment() == llvm::Triple::GNUABI64) - return true; - return false; - default: - return false; - } -} - -void Generic_GCC::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs, - ArgStringList &CC1Args) const { - if (DriverArgs.hasArg(options::OPT_nostdlibinc) || - DriverArgs.hasArg(options::OPT_nostdincxx)) - return; - - switch (GetCXXStdlibType(DriverArgs)) { - case ToolChain::CST_Libcxx: { - std::string Path = findLibCxxIncludePath(); - if (!Path.empty()) - addSystemInclude(DriverArgs, CC1Args, Path); - break; - } - - case ToolChain::CST_Libstdcxx: - addLibStdCxxIncludePaths(DriverArgs, CC1Args); - break; - } -} - -std::string Generic_GCC::findLibCxxIncludePath() const { - // FIXME: The Linux behavior would probaby be a better approach here. - return getDriver().SysRoot + "/usr/include/c++/v1"; -} - -void -Generic_GCC::addLibStdCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args) const { - // By default, we don't assume we know where libstdc++ might be installed. - // FIXME: If we have a valid GCCInstallation, use it. -} - -/// \brief Helper to add the variant paths of a libstdc++ installation. -bool Generic_GCC::addLibStdCXXIncludePaths( - Twine Base, Twine Suffix, StringRef GCCTriple, StringRef GCCMultiarchTriple, - StringRef TargetMultiarchTriple, Twine IncludeSuffix, - const ArgList &DriverArgs, ArgStringList &CC1Args) const { - if (!getVFS().exists(Base + Suffix)) - return false; - - addSystemInclude(DriverArgs, CC1Args, Base + Suffix); - - // The vanilla GCC layout of libstdc++ headers uses a triple subdirectory. If - // that path exists or we have neither a GCC nor target multiarch triple, use - // this vanilla search path. - if ((GCCMultiarchTriple.empty() && TargetMultiarchTriple.empty()) || - getVFS().exists(Base + Suffix + "/" + GCCTriple + IncludeSuffix)) { - addSystemInclude(DriverArgs, CC1Args, - Base + Suffix + "/" + GCCTriple + IncludeSuffix); - } else { - // Otherwise try to use multiarch naming schemes which have normalized the - // triples and put the triple before the suffix. - // - // GCC surprisingly uses *both* the GCC triple with a multilib suffix and - // the target triple, so we support that here. - addSystemInclude(DriverArgs, CC1Args, - Base + "/" + GCCMultiarchTriple + Suffix + IncludeSuffix); - addSystemInclude(DriverArgs, CC1Args, - Base + "/" + TargetMultiarchTriple + Suffix); - } - - addSystemInclude(DriverArgs, CC1Args, Base + Suffix + "/backward"); - return true; -} - -llvm::opt::DerivedArgList * -Generic_GCC::TranslateArgs(const llvm::opt::DerivedArgList &Args, StringRef, - Action::OffloadKind DeviceOffloadKind) const { - - // If this tool chain is used for an OpenMP offloading device we have to make - // sure we always generate a shared library regardless of the commands the - // user passed to the host. This is required because the runtime library - // is required to load the device image dynamically at run time. - if (DeviceOffloadKind == Action::OFK_OpenMP) { - DerivedArgList *DAL = new DerivedArgList(Args.getBaseArgs()); - const OptTable &Opts = getDriver().getOpts(); - - // Request the shared library. Given that these options are decided - // implicitly, they do not refer to any base argument. - DAL->AddFlagArg(/*BaseArg=*/nullptr, Opts.getOption(options::OPT_shared)); - DAL->AddFlagArg(/*BaseArg=*/nullptr, Opts.getOption(options::OPT_fPIC)); - - // Filter all the arguments we don't care passing to the offloading - // toolchain as they can mess up with the creation of a shared library. - for (auto *A : Args) { - switch ((options::ID)A->getOption().getID()) { - default: - DAL->append(A); - break; - case options::OPT_shared: - case options::OPT_dynamic: - case options::OPT_static: - case options::OPT_fPIC: - case options::OPT_fno_PIC: - case options::OPT_fpic: - case options::OPT_fno_pic: - case options::OPT_fPIE: - case options::OPT_fno_PIE: - case options::OPT_fpie: - case options::OPT_fno_pie: - break; - } - } - return DAL; - } - return nullptr; -} - -void Generic_ELF::addClangTargetOptions(const ArgList &DriverArgs, - ArgStringList &CC1Args) const { - const Generic_GCC::GCCVersion &V = GCCInstallation.getVersion(); - bool UseInitArrayDefault = - getTriple().getArch() == llvm::Triple::aarch64 || - getTriple().getArch() == llvm::Triple::aarch64_be || - (getTriple().getOS() == llvm::Triple::Linux && - (!V.isOlderThan(4, 7, 0) || getTriple().isAndroid())) || - getTriple().getOS() == llvm::Triple::NaCl || - (getTriple().getVendor() == llvm::Triple::MipsTechnologies && - !getTriple().hasEnvironment()); - - if (DriverArgs.hasFlag(options::OPT_fuse_init_array, - options::OPT_fno_use_init_array, UseInitArrayDefault)) - CC1Args.push_back("-fuse-init-array"); -} - -/// Mips Toolchain -MipsLLVMToolChain::MipsLLVMToolChain(const Driver &D, - const llvm::Triple &Triple, - const ArgList &Args) - : Linux(D, Triple, Args) { - // Select the correct multilib according to the given arguments. - DetectedMultilibs Result; - findMIPSMultilibs(D, Triple, "", Args, Result); - Multilibs = Result.Multilibs; - SelectedMultilib = Result.SelectedMultilib; - - // Find out the library suffix based on the ABI. - LibSuffix = tools::mips::getMipsABILibSuffix(Args, Triple); - getFilePaths().clear(); - getFilePaths().push_back(computeSysRoot() + "/usr/lib" + LibSuffix); -} - -void MipsLLVMToolChain::AddClangSystemIncludeArgs( - const ArgList &DriverArgs, ArgStringList &CC1Args) const { - if (DriverArgs.hasArg(options::OPT_nostdinc)) - return; - - const Driver &D = getDriver(); - - if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) { - SmallString<128> P(D.ResourceDir); - llvm::sys::path::append(P, "include"); - addSystemInclude(DriverArgs, CC1Args, P); - } - - if (DriverArgs.hasArg(options::OPT_nostdlibinc)) - return; - - const auto &Callback = Multilibs.includeDirsCallback(); - if (Callback) { - for (const auto &Path : Callback(SelectedMultilib)) - addExternCSystemIncludeIfExists(DriverArgs, CC1Args, - D.getInstalledDir() + Path); - } -} - -Tool *MipsLLVMToolChain::buildLinker() const { - return new tools::gnutools::Linker(*this); -} - -std::string MipsLLVMToolChain::computeSysRoot() const { - if (!getDriver().SysRoot.empty()) - return getDriver().SysRoot + SelectedMultilib.osSuffix(); - - const std::string InstalledDir(getDriver().getInstalledDir()); - std::string SysRootPath = - InstalledDir + "/../sysroot" + SelectedMultilib.osSuffix(); - if (llvm::sys::fs::exists(SysRootPath)) - return SysRootPath; - - return std::string(); -} - -ToolChain::CXXStdlibType -MipsLLVMToolChain::GetCXXStdlibType(const ArgList &Args) const { - Arg *A = Args.getLastArg(options::OPT_stdlib_EQ); - if (A) { - StringRef Value = A->getValue(); - if (Value != "libc++") - getDriver().Diag(diag::err_drv_invalid_stdlib_name) - << A->getAsString(Args); - } - - return ToolChain::CST_Libcxx; -} - -std::string MipsLLVMToolChain::findLibCxxIncludePath() const { - if (const auto &Callback = Multilibs.includeDirsCallback()) { - for (std::string Path : Callback(SelectedMultilib)) { - Path = getDriver().getInstalledDir() + Path + "/c++/v1"; - if (llvm::sys::fs::exists(Path)) { - return Path; - } - } - } - return ""; -} - -void MipsLLVMToolChain::AddCXXStdlibLibArgs(const ArgList &Args, - ArgStringList &CmdArgs) const { - assert((GetCXXStdlibType(Args) == ToolChain::CST_Libcxx) && - "Only -lc++ (aka libxx) is suported in this toolchain."); - - CmdArgs.push_back("-lc++"); - CmdArgs.push_back("-lc++abi"); - CmdArgs.push_back("-lunwind"); -} - -std::string MipsLLVMToolChain::getCompilerRT(const ArgList &Args, - StringRef Component, - bool Shared) const { - SmallString<128> Path(getDriver().ResourceDir); - llvm::sys::path::append(Path, SelectedMultilib.osSuffix(), "lib" + LibSuffix, - getOS()); - llvm::sys::path::append(Path, Twine("libclang_rt." + Component + "-" + - "mips" + (Shared ? ".so" : ".a"))); - return Path.str(); -} - -/// Hexagon Toolchain - -std::string HexagonToolChain::getHexagonTargetDir( - const std::string &InstalledDir, - const SmallVectorImpl<std::string> &PrefixDirs) const { - std::string InstallRelDir; - const Driver &D = getDriver(); - - // Locate the rest of the toolchain ... - for (auto &I : PrefixDirs) - if (D.getVFS().exists(I)) - return I; - - if (getVFS().exists(InstallRelDir = InstalledDir + "/../target")) - return InstallRelDir; - - return InstalledDir; -} - -Optional<unsigned> HexagonToolChain::getSmallDataThreshold( - const ArgList &Args) { - StringRef Gn = ""; - if (Arg *A = Args.getLastArg(options::OPT_G)) { - Gn = A->getValue(); - } else if (Args.getLastArg(options::OPT_shared, options::OPT_fpic, - options::OPT_fPIC)) { - Gn = "0"; - } - - unsigned G; - if (!Gn.getAsInteger(10, G)) - return G; - - return None; -} - -void HexagonToolChain::getHexagonLibraryPaths(const ArgList &Args, - ToolChain::path_list &LibPaths) const { - const Driver &D = getDriver(); - - //---------------------------------------------------------------------------- - // -L Args - //---------------------------------------------------------------------------- - for (Arg *A : Args.filtered(options::OPT_L)) - for (const char *Value : A->getValues()) - LibPaths.push_back(Value); - - //---------------------------------------------------------------------------- - // Other standard paths - //---------------------------------------------------------------------------- - std::vector<std::string> RootDirs; - std::copy(D.PrefixDirs.begin(), D.PrefixDirs.end(), - std::back_inserter(RootDirs)); - - std::string TargetDir = getHexagonTargetDir(D.getInstalledDir(), - D.PrefixDirs); - if (std::find(RootDirs.begin(), RootDirs.end(), TargetDir) == RootDirs.end()) - RootDirs.push_back(TargetDir); - - bool HasPIC = Args.hasArg(options::OPT_fpic, options::OPT_fPIC); - // Assume G0 with -shared. - bool HasG0 = Args.hasArg(options::OPT_shared); - if (auto G = getSmallDataThreshold(Args)) - HasG0 = G.getValue() == 0; - - const std::string CpuVer = GetTargetCPUVersion(Args).str(); - for (auto &Dir : RootDirs) { - std::string LibDir = Dir + "/hexagon/lib"; - std::string LibDirCpu = LibDir + '/' + CpuVer; - if (HasG0) { - if (HasPIC) - LibPaths.push_back(LibDirCpu + "/G0/pic"); - LibPaths.push_back(LibDirCpu + "/G0"); - } - LibPaths.push_back(LibDirCpu); - LibPaths.push_back(LibDir); - } -} - -HexagonToolChain::HexagonToolChain(const Driver &D, const llvm::Triple &Triple, - const llvm::opt::ArgList &Args) - : Linux(D, Triple, Args) { - const std::string TargetDir = getHexagonTargetDir(D.getInstalledDir(), - D.PrefixDirs); - - // Note: Generic_GCC::Generic_GCC adds InstalledDir and getDriver().Dir to - // program paths - const std::string BinDir(TargetDir + "/bin"); - if (D.getVFS().exists(BinDir)) - getProgramPaths().push_back(BinDir); - - ToolChain::path_list &LibPaths = getFilePaths(); - - // Remove paths added by Linux toolchain. Currently Hexagon_TC really targets - // 'elf' OS type, so the Linux paths are not appropriate. When we actually - // support 'linux' we'll need to fix this up - LibPaths.clear(); - getHexagonLibraryPaths(Args, LibPaths); -} - -HexagonToolChain::~HexagonToolChain() {} - -Tool *HexagonToolChain::buildAssembler() const { - return new tools::hexagon::Assembler(*this); -} - -Tool *HexagonToolChain::buildLinker() const { - return new tools::hexagon::Linker(*this); -} - -void HexagonToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs, - ArgStringList &CC1Args) const { - if (DriverArgs.hasArg(options::OPT_nostdinc) || - DriverArgs.hasArg(options::OPT_nostdlibinc)) - return; - - const Driver &D = getDriver(); - std::string TargetDir = getHexagonTargetDir(D.getInstalledDir(), - D.PrefixDirs); - addExternCSystemInclude(DriverArgs, CC1Args, TargetDir + "/hexagon/include"); -} - - -void HexagonToolChain::addLibStdCxxIncludePaths( - const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args) const { - const Driver &D = getDriver(); - std::string TargetDir = getHexagonTargetDir(D.InstalledDir, D.PrefixDirs); - addLibStdCXXIncludePaths(TargetDir, "/hexagon/include/c++", "", "", "", "", - DriverArgs, CC1Args); -} - -ToolChain::CXXStdlibType -HexagonToolChain::GetCXXStdlibType(const ArgList &Args) const { - Arg *A = Args.getLastArg(options::OPT_stdlib_EQ); - if (!A) - return ToolChain::CST_Libstdcxx; - - StringRef Value = A->getValue(); - if (Value != "libstdc++") - getDriver().Diag(diag::err_drv_invalid_stdlib_name) << A->getAsString(Args); - - return ToolChain::CST_Libstdcxx; -} - -// -// Returns the default CPU for Hexagon. This is the default compilation target -// if no Hexagon processor is selected at the command-line. -// -const StringRef HexagonToolChain::GetDefaultCPU() { - return "hexagonv60"; -} - -const StringRef HexagonToolChain::GetTargetCPUVersion(const ArgList &Args) { - Arg *CpuArg = nullptr; - if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ, options::OPT_march_EQ)) - CpuArg = A; - - StringRef CPU = CpuArg ? CpuArg->getValue() : GetDefaultCPU(); - if (CPU.startswith("hexagon")) - return CPU.substr(sizeof("hexagon") - 1); - return CPU; -} -// End Hexagon - -/// AMDGPU Toolchain -AMDGPUToolChain::AMDGPUToolChain(const Driver &D, const llvm::Triple &Triple, - const ArgList &Args) - : Generic_ELF(D, Triple, Args) { } - -Tool *AMDGPUToolChain::buildLinker() const { - return new tools::amdgpu::Linker(*this); -} -// End AMDGPU - -/// NaCl Toolchain -NaClToolChain::NaClToolChain(const Driver &D, const llvm::Triple &Triple, - const ArgList &Args) - : Generic_ELF(D, Triple, Args) { - - // Remove paths added by Generic_GCC. NaCl Toolchain cannot use the - // default paths, and must instead only use the paths provided - // with this toolchain based on architecture. - path_list &file_paths = getFilePaths(); - path_list &prog_paths = getProgramPaths(); - - file_paths.clear(); - prog_paths.clear(); - - // Path for library files (libc.a, ...) - std::string FilePath(getDriver().Dir + "/../"); - - // Path for tools (clang, ld, etc..) - std::string ProgPath(getDriver().Dir + "/../"); - - // Path for toolchain libraries (libgcc.a, ...) - std::string ToolPath(getDriver().ResourceDir + "/lib/"); - - switch (Triple.getArch()) { - case llvm::Triple::x86: - file_paths.push_back(FilePath + "x86_64-nacl/lib32"); - file_paths.push_back(FilePath + "i686-nacl/usr/lib"); - prog_paths.push_back(ProgPath + "x86_64-nacl/bin"); - file_paths.push_back(ToolPath + "i686-nacl"); - break; - case llvm::Triple::x86_64: - file_paths.push_back(FilePath + "x86_64-nacl/lib"); - file_paths.push_back(FilePath + "x86_64-nacl/usr/lib"); - prog_paths.push_back(ProgPath + "x86_64-nacl/bin"); - file_paths.push_back(ToolPath + "x86_64-nacl"); - break; - case llvm::Triple::arm: - file_paths.push_back(FilePath + "arm-nacl/lib"); - file_paths.push_back(FilePath + "arm-nacl/usr/lib"); - prog_paths.push_back(ProgPath + "arm-nacl/bin"); - file_paths.push_back(ToolPath + "arm-nacl"); - break; - case llvm::Triple::mipsel: - file_paths.push_back(FilePath + "mipsel-nacl/lib"); - file_paths.push_back(FilePath + "mipsel-nacl/usr/lib"); - prog_paths.push_back(ProgPath + "bin"); - file_paths.push_back(ToolPath + "mipsel-nacl"); - break; - default: - break; - } - - NaClArmMacrosPath = GetFilePath("nacl-arm-macros.s"); -} - -void NaClToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs, - ArgStringList &CC1Args) const { - const Driver &D = getDriver(); - if (DriverArgs.hasArg(options::OPT_nostdinc)) - return; - - if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) { - SmallString<128> P(D.ResourceDir); - llvm::sys::path::append(P, "include"); - addSystemInclude(DriverArgs, CC1Args, P.str()); - } - - if (DriverArgs.hasArg(options::OPT_nostdlibinc)) - return; - - SmallString<128> P(D.Dir + "/../"); - switch (getTriple().getArch()) { - case llvm::Triple::x86: - // x86 is special because multilib style uses x86_64-nacl/include for libc - // headers but the SDK wants i686-nacl/usr/include. The other architectures - // have the same substring. - llvm::sys::path::append(P, "i686-nacl/usr/include"); - addSystemInclude(DriverArgs, CC1Args, P.str()); - llvm::sys::path::remove_filename(P); - llvm::sys::path::remove_filename(P); - llvm::sys::path::remove_filename(P); - llvm::sys::path::append(P, "x86_64-nacl/include"); - addSystemInclude(DriverArgs, CC1Args, P.str()); - return; - case llvm::Triple::arm: - llvm::sys::path::append(P, "arm-nacl/usr/include"); - break; - case llvm::Triple::x86_64: - llvm::sys::path::append(P, "x86_64-nacl/usr/include"); - break; - case llvm::Triple::mipsel: - llvm::sys::path::append(P, "mipsel-nacl/usr/include"); - break; - default: - return; - } - - addSystemInclude(DriverArgs, CC1Args, P.str()); - llvm::sys::path::remove_filename(P); - llvm::sys::path::remove_filename(P); - llvm::sys::path::append(P, "include"); - addSystemInclude(DriverArgs, CC1Args, P.str()); -} - -void NaClToolChain::AddCXXStdlibLibArgs(const ArgList &Args, - ArgStringList &CmdArgs) const { - // Check for -stdlib= flags. We only support libc++ but this consumes the arg - // if the value is libc++, and emits an error for other values. - GetCXXStdlibType(Args); - CmdArgs.push_back("-lc++"); -} - -std::string NaClToolChain::findLibCxxIncludePath() const { - const Driver &D = getDriver(); - - SmallString<128> P(D.Dir + "/../"); - switch (getTriple().getArch()) { - case llvm::Triple::arm: - llvm::sys::path::append(P, "arm-nacl/include/c++/v1"); - return P.str(); - case llvm::Triple::x86: - llvm::sys::path::append(P, "x86_64-nacl/include/c++/v1"); - return P.str(); - case llvm::Triple::x86_64: - llvm::sys::path::append(P, "x86_64-nacl/include/c++/v1"); - return P.str(); - case llvm::Triple::mipsel: - llvm::sys::path::append(P, "mipsel-nacl/include/c++/v1"); - return P.str(); - default: - return ""; - } -} - -ToolChain::CXXStdlibType -NaClToolChain::GetCXXStdlibType(const ArgList &Args) const { - if (Arg *A = Args.getLastArg(options::OPT_stdlib_EQ)) { - StringRef Value = A->getValue(); - if (Value == "libc++") - return ToolChain::CST_Libcxx; - getDriver().Diag(diag::err_drv_invalid_stdlib_name) << A->getAsString(Args); - } - - return ToolChain::CST_Libcxx; -} - -std::string -NaClToolChain::ComputeEffectiveClangTriple(const ArgList &Args, - types::ID InputType) const { - llvm::Triple TheTriple(ComputeLLVMTriple(Args, InputType)); - if (TheTriple.getArch() == llvm::Triple::arm && - TheTriple.getEnvironment() == llvm::Triple::UnknownEnvironment) - TheTriple.setEnvironment(llvm::Triple::GNUEABIHF); - return TheTriple.getTriple(); -} - -Tool *NaClToolChain::buildLinker() const { - return new tools::nacltools::Linker(*this); -} - -Tool *NaClToolChain::buildAssembler() const { - if (getTriple().getArch() == llvm::Triple::arm) - return new tools::nacltools::AssemblerARM(*this); - return new tools::gnutools::Assembler(*this); -} -// End NaCl - -/// TCEToolChain - A tool chain using the llvm bitcode tools to perform -/// all subcommands. See http://tce.cs.tut.fi for our peculiar target. -/// Currently does not support anything else but compilation. - -TCEToolChain::TCEToolChain(const Driver &D, const llvm::Triple &Triple, - const ArgList &Args) - : ToolChain(D, Triple, Args) { - // Path mangling to find libexec - std::string Path(getDriver().Dir); - - Path += "/../libexec"; - getProgramPaths().push_back(Path); -} - -TCEToolChain::~TCEToolChain() {} - -bool TCEToolChain::IsMathErrnoDefault() const { return true; } - -bool TCEToolChain::isPICDefault() const { return false; } - -bool TCEToolChain::isPIEDefault() const { return false; } - -bool TCEToolChain::isPICDefaultForced() const { return false; } - -TCELEToolChain::TCELEToolChain(const Driver &D, const llvm::Triple& Triple, - const ArgList &Args) - : TCEToolChain(D, Triple, Args) { -} - -TCELEToolChain::~TCELEToolChain() {} - -// CloudABI - CloudABI tool chain which can call ld(1) directly. - -CloudABI::CloudABI(const Driver &D, const llvm::Triple &Triple, - const ArgList &Args) - : Generic_ELF(D, Triple, Args) { - SmallString<128> P(getDriver().Dir); - llvm::sys::path::append(P, "..", getTriple().str(), "lib"); - getFilePaths().push_back(P.str()); -} - -std::string CloudABI::findLibCxxIncludePath() const { - SmallString<128> P(getDriver().Dir); - llvm::sys::path::append(P, "..", getTriple().str(), "include/c++/v1"); - return P.str(); -} - -void CloudABI::AddCXXStdlibLibArgs(const ArgList &Args, - ArgStringList &CmdArgs) const { - CmdArgs.push_back("-lc++"); - CmdArgs.push_back("-lc++abi"); - CmdArgs.push_back("-lunwind"); -} - -Tool *CloudABI::buildLinker() const { - return new tools::cloudabi::Linker(*this); -} - -bool CloudABI::isPIEDefault() const { - // Only enable PIE on architectures that support PC-relative - // addressing. PC-relative addressing is required, as the process - // startup code must be able to relocate itself. - switch (getTriple().getArch()) { - case llvm::Triple::aarch64: - case llvm::Triple::x86_64: - return true; - default: - return false; - } -} - -SanitizerMask CloudABI::getSupportedSanitizers() const { - SanitizerMask Res = ToolChain::getSupportedSanitizers(); - Res |= SanitizerKind::SafeStack; - return Res; -} - -SanitizerMask CloudABI::getDefaultSanitizers() const { - return SanitizerKind::SafeStack; -} - -/// Haiku - Haiku tool chain which can call as(1) and ld(1) directly. - -Haiku::Haiku(const Driver &D, const llvm::Triple& Triple, const ArgList &Args) - : Generic_ELF(D, Triple, Args) { - -} - -std::string Haiku::findLibCxxIncludePath() const { - return getDriver().SysRoot + "/system/develop/headers/c++/v1"; -} - -void Haiku::addLibStdCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args) const { - addLibStdCXXIncludePaths(getDriver().SysRoot, "/system/develop/headers/c++", - getTriple().str(), "", "", "", DriverArgs, CC1Args); -} - -/// OpenBSD - OpenBSD tool chain which can call as(1) and ld(1) directly. - -OpenBSD::OpenBSD(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 *OpenBSD::buildAssembler() const { - return new tools::openbsd::Assembler(*this); -} - -Tool *OpenBSD::buildLinker() const { return new tools::openbsd::Linker(*this); } - -/// 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; - } -} - -/// FreeBSD - FreeBSD tool chain which can call as(1) and ld(1) directly. - -FreeBSD::FreeBSD(const Driver &D, const llvm::Triple &Triple, - const ArgList &Args) - : Generic_ELF(D, Triple, Args) { - - // When targeting 32-bit platforms, look for '/usr/lib32/crt1.o' and fall - // back to '/usr/lib' if it doesn't exist. - if ((Triple.getArch() == llvm::Triple::x86 || - Triple.getArch() == llvm::Triple::ppc) && - D.getVFS().exists(getDriver().SysRoot + "/usr/lib32/crt1.o")) - getFilePaths().push_back(getDriver().SysRoot + "/usr/lib32"); - else - getFilePaths().push_back(getDriver().SysRoot + "/usr/lib"); -} - -ToolChain::CXXStdlibType FreeBSD::GetDefaultCXXStdlibType() const { - if (getTriple().getOSMajorVersion() >= 10) - return ToolChain::CST_Libcxx; - return ToolChain::CST_Libstdcxx; -} - -void FreeBSD::addLibStdCxxIncludePaths( - const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args) const { - addLibStdCXXIncludePaths(getDriver().SysRoot, "/usr/include/c++/4.2", "", "", - "", "", DriverArgs, CC1Args); -} - -void FreeBSD::AddCXXStdlibLibArgs(const ArgList &Args, - ArgStringList &CmdArgs) const { - CXXStdlibType Type = GetCXXStdlibType(Args); - bool Profiling = Args.hasArg(options::OPT_pg); - - switch (Type) { - case ToolChain::CST_Libcxx: - CmdArgs.push_back(Profiling ? "-lc++_p" : "-lc++"); - break; - - case ToolChain::CST_Libstdcxx: - CmdArgs.push_back(Profiling ? "-lstdc++_p" : "-lstdc++"); - break; - } -} - -Tool *FreeBSD::buildAssembler() const { - return new tools::freebsd::Assembler(*this); -} - -Tool *FreeBSD::buildLinker() const { return new tools::freebsd::Linker(*this); } - -bool FreeBSD::UseSjLjExceptions(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; - - default: - return (getTriple().getArch() == llvm::Triple::arm || - getTriple().getArch() == llvm::Triple::thumb); - } -} - -bool FreeBSD::HasNativeLLVMSupport() const { return true; } - -bool FreeBSD::isPIEDefault() const { return getSanitizerArgs().requiresPIE(); } - -SanitizerMask FreeBSD::getSupportedSanitizers() const { - const bool IsX86 = getTriple().getArch() == llvm::Triple::x86; - const bool IsX86_64 = getTriple().getArch() == llvm::Triple::x86_64; - const bool IsMIPS64 = getTriple().getArch() == llvm::Triple::mips64 || - getTriple().getArch() == llvm::Triple::mips64el; - SanitizerMask Res = ToolChain::getSupportedSanitizers(); - Res |= SanitizerKind::Address; - Res |= SanitizerKind::Vptr; - if (IsX86_64 || IsMIPS64) { - Res |= SanitizerKind::Leak; - Res |= SanitizerKind::Thread; - } - if (IsX86 || IsX86_64) { - Res |= SanitizerKind::SafeStack; - } - return Res; -} - -/// NetBSD - NetBSD tool chain which can call as(1) and ld(1) directly. - -NetBSD::NetBSD(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) - : Generic_ELF(D, Triple, Args) { - if (getDriver().UseStdLib) { - // 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. - // FIXME: It'd be nicer to test if this directory exists, but I'm not sure - // what all logic is needed to emulate the '=' prefix here. - switch (Triple.getArch()) { - case llvm::Triple::x86: - getFilePaths().push_back("=/usr/lib/i386"); - break; - case llvm::Triple::arm: - case llvm::Triple::armeb: - case llvm::Triple::thumb: - case llvm::Triple::thumbeb: - switch (Triple.getEnvironment()) { - case llvm::Triple::EABI: - case llvm::Triple::GNUEABI: - getFilePaths().push_back("=/usr/lib/eabi"); - break; - case llvm::Triple::EABIHF: - case llvm::Triple::GNUEABIHF: - getFilePaths().push_back("=/usr/lib/eabihf"); - break; - default: - getFilePaths().push_back("=/usr/lib/oabi"); - break; - } - break; - case llvm::Triple::mips64: - case llvm::Triple::mips64el: - if (tools::mips::hasMipsAbiArg(Args, "o32")) - getFilePaths().push_back("=/usr/lib/o32"); - else if (tools::mips::hasMipsAbiArg(Args, "64")) - getFilePaths().push_back("=/usr/lib/64"); - break; - case llvm::Triple::ppc: - getFilePaths().push_back("=/usr/lib/powerpc"); - break; - case llvm::Triple::sparc: - getFilePaths().push_back("=/usr/lib/sparc"); - break; - default: - break; - } - - getFilePaths().push_back("=/usr/lib"); - } -} - -Tool *NetBSD::buildAssembler() const { - return new tools::netbsd::Assembler(*this); -} - -Tool *NetBSD::buildLinker() const { return new tools::netbsd::Linker(*this); } - -ToolChain::CXXStdlibType NetBSD::GetDefaultCXXStdlibType() const { - unsigned Major, Minor, Micro; - getTriple().getOSVersion(Major, Minor, Micro); - if (Major >= 7 || Major == 0) { - switch (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: - case llvm::Triple::ppc: - case llvm::Triple::ppc64: - case llvm::Triple::ppc64le: - case llvm::Triple::sparc: - case llvm::Triple::sparcv9: - case llvm::Triple::x86: - case llvm::Triple::x86_64: - return ToolChain::CST_Libcxx; - default: - break; - } - } - return ToolChain::CST_Libstdcxx; -} - -std::string NetBSD::findLibCxxIncludePath() const { - return getDriver().SysRoot + "/usr/include/c++/"; -} - -void NetBSD::addLibStdCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args) const { - addLibStdCXXIncludePaths(getDriver().SysRoot, "/usr/include/g++", "", "", "", - "", DriverArgs, CC1Args); -} - -/// Minix - Minix tool chain which can call as(1) and ld(1) directly. - -Minix::Minix(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 *Minix::buildAssembler() const { - return new tools::minix::Assembler(*this); -} - -Tool *Minix::buildLinker() const { return new tools::minix::Linker(*this); } - -static void addPathIfExists(const Driver &D, const Twine &Path, - ToolChain::path_list &Paths) { - if (D.getVFS().exists(Path)) - Paths.push_back(Path.str()); -} - -/// Solaris - Solaris tool chain which can call as(1) and ld(1) directly. - -Solaris::Solaris(const Driver &D, const llvm::Triple &Triple, - const ArgList &Args) - : Generic_GCC(D, Triple, Args) { - - GCCInstallation.init(Triple, Args); - - path_list &Paths = getFilePaths(); - if (GCCInstallation.isValid()) - addPathIfExists(D, GCCInstallation.getInstallPath(), Paths); - - addPathIfExists(D, getDriver().getInstalledDir(), Paths); - if (getDriver().getInstalledDir() != getDriver().Dir) - addPathIfExists(D, getDriver().Dir, Paths); - - addPathIfExists(D, getDriver().SysRoot + getDriver().Dir + "/../lib", Paths); - - std::string LibPath = "/usr/lib/"; - switch (Triple.getArch()) { - case llvm::Triple::x86: - case llvm::Triple::sparc: - break; - case llvm::Triple::x86_64: - LibPath += "amd64/"; - break; - case llvm::Triple::sparcv9: - LibPath += "sparcv9/"; - break; - default: - llvm_unreachable("Unsupported architecture"); - } - - addPathIfExists(D, getDriver().SysRoot + LibPath, Paths); -} - -Tool *Solaris::buildAssembler() const { - return new tools::solaris::Assembler(*this); -} - -Tool *Solaris::buildLinker() const { return new tools::solaris::Linker(*this); } - -void Solaris::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs, - ArgStringList &CC1Args) const { - if (DriverArgs.hasArg(options::OPT_nostdlibinc) || - DriverArgs.hasArg(options::OPT_nostdincxx)) - return; - - // Include the support directory for things like xlocale and fudged system - // headers. - // FIXME: This is a weird mix of libc++ and libstdc++. We should also be - // checking the value of -stdlib= here and adding the includes for libc++ - // rather than libstdc++ if it's requested. - addSystemInclude(DriverArgs, CC1Args, "/usr/include/c++/v1/support/solaris"); - - if (GCCInstallation.isValid()) { - GCCVersion Version = GCCInstallation.getVersion(); - addSystemInclude(DriverArgs, CC1Args, - getDriver().SysRoot + "/usr/gcc/" + - Version.MajorStr + "." + - Version.MinorStr + - "/include/c++/" + Version.Text); - addSystemInclude(DriverArgs, CC1Args, - getDriver().SysRoot + "/usr/gcc/" + Version.MajorStr + - "." + Version.MinorStr + "/include/c++/" + - Version.Text + "/" + - GCCInstallation.getTriple().str()); - } -} - -/// \brief Get our best guess at the multiarch triple for a target. -/// -/// Debian-based systems are starting to use a multiarch setup where they use -/// a target-triple directory in the library and header search paths. -/// Unfortunately, this triple does not align with the vanilla target triple, -/// so we provide a rough mapping here. -static std::string getMultiarchTriple(const Driver &D, - const llvm::Triple &TargetTriple, - StringRef SysRoot) { - llvm::Triple::EnvironmentType TargetEnvironment = - TargetTriple.getEnvironment(); - - // For most architectures, just use whatever we have rather than trying to be - // clever. - switch (TargetTriple.getArch()) { - default: - break; - - // We use the existence of '/lib/<triple>' as a directory to detect some - // common linux triples that don't quite match the Clang triple for both - // 32-bit and 64-bit targets. Multiarch fixes its install triples to these - // regardless of what the actual target triple is. - case llvm::Triple::arm: - case llvm::Triple::thumb: - if (TargetEnvironment == llvm::Triple::GNUEABIHF) { - if (D.getVFS().exists(SysRoot + "/lib/arm-linux-gnueabihf")) - return "arm-linux-gnueabihf"; - } else { - if (D.getVFS().exists(SysRoot + "/lib/arm-linux-gnueabi")) - return "arm-linux-gnueabi"; - } - break; - case llvm::Triple::armeb: - case llvm::Triple::thumbeb: - if (TargetEnvironment == llvm::Triple::GNUEABIHF) { - if (D.getVFS().exists(SysRoot + "/lib/armeb-linux-gnueabihf")) - return "armeb-linux-gnueabihf"; - } else { - if (D.getVFS().exists(SysRoot + "/lib/armeb-linux-gnueabi")) - return "armeb-linux-gnueabi"; - } - break; - case llvm::Triple::x86: - if (D.getVFS().exists(SysRoot + "/lib/i386-linux-gnu")) - return "i386-linux-gnu"; - break; - case llvm::Triple::x86_64: - // We don't want this for x32, otherwise it will match x86_64 libs - if (TargetEnvironment != llvm::Triple::GNUX32 && - D.getVFS().exists(SysRoot + "/lib/x86_64-linux-gnu")) - return "x86_64-linux-gnu"; - break; - case llvm::Triple::aarch64: - if (D.getVFS().exists(SysRoot + "/lib/aarch64-linux-gnu")) - return "aarch64-linux-gnu"; - break; - case llvm::Triple::aarch64_be: - if (D.getVFS().exists(SysRoot + "/lib/aarch64_be-linux-gnu")) - return "aarch64_be-linux-gnu"; - break; - case llvm::Triple::mips: - if (D.getVFS().exists(SysRoot + "/lib/mips-linux-gnu")) - return "mips-linux-gnu"; - break; - case llvm::Triple::mipsel: - if (D.getVFS().exists(SysRoot + "/lib/mipsel-linux-gnu")) - return "mipsel-linux-gnu"; - break; - case llvm::Triple::mips64: - if (D.getVFS().exists(SysRoot + "/lib/mips64-linux-gnu")) - return "mips64-linux-gnu"; - if (D.getVFS().exists(SysRoot + "/lib/mips64-linux-gnuabi64")) - return "mips64-linux-gnuabi64"; - break; - case llvm::Triple::mips64el: - if (D.getVFS().exists(SysRoot + "/lib/mips64el-linux-gnu")) - return "mips64el-linux-gnu"; - if (D.getVFS().exists(SysRoot + "/lib/mips64el-linux-gnuabi64")) - return "mips64el-linux-gnuabi64"; - break; - case llvm::Triple::ppc: - if (D.getVFS().exists(SysRoot + "/lib/powerpc-linux-gnuspe")) - return "powerpc-linux-gnuspe"; - if (D.getVFS().exists(SysRoot + "/lib/powerpc-linux-gnu")) - return "powerpc-linux-gnu"; - break; - case llvm::Triple::ppc64: - if (D.getVFS().exists(SysRoot + "/lib/powerpc64-linux-gnu")) - return "powerpc64-linux-gnu"; - break; - case llvm::Triple::ppc64le: - if (D.getVFS().exists(SysRoot + "/lib/powerpc64le-linux-gnu")) - return "powerpc64le-linux-gnu"; - break; - case llvm::Triple::sparc: - if (D.getVFS().exists(SysRoot + "/lib/sparc-linux-gnu")) - return "sparc-linux-gnu"; - break; - case llvm::Triple::sparcv9: - if (D.getVFS().exists(SysRoot + "/lib/sparc64-linux-gnu")) - return "sparc64-linux-gnu"; - break; - case llvm::Triple::systemz: - if (D.getVFS().exists(SysRoot + "/lib/s390x-linux-gnu")) - return "s390x-linux-gnu"; - break; - } - return TargetTriple.str(); -} - -static StringRef getOSLibDir(const llvm::Triple &Triple, const ArgList &Args) { - if (isMipsArch(Triple.getArch())) { - if (Triple.isAndroid()) { - StringRef CPUName; - StringRef ABIName; - tools::mips::getMipsCPUAndABI(Args, Triple, CPUName, ABIName); - if (CPUName == "mips32r6") - return "libr6"; - if (CPUName == "mips32r2") - return "libr2"; - } - // lib32 directory has a special meaning on MIPS targets. - // It contains N32 ABI binaries. Use this folder if produce - // code for N32 ABI only. - if (tools::mips::hasMipsAbiArg(Args, "n32")) - return "lib32"; - return Triple.isArch32Bit() ? "lib" : "lib64"; - } - - // It happens that only x86 and PPC use the 'lib32' variant of oslibdir, and - // using that variant while targeting other architectures causes problems - // because the libraries are laid out in shared system roots that can't cope - // with a 'lib32' library search path being considered. So we only enable - // them when we know we may need it. - // - // FIXME: This is a bit of a hack. We should really unify this code for - // reasoning about oslibdir spellings with the lib dir spellings in the - // GCCInstallationDetector, but that is a more significant refactoring. - if (Triple.getArch() == llvm::Triple::x86 || - Triple.getArch() == llvm::Triple::ppc) - return "lib32"; - - if (Triple.getArch() == llvm::Triple::x86_64 && - Triple.getEnvironment() == llvm::Triple::GNUX32) - return "libx32"; - - return Triple.isArch32Bit() ? "lib" : "lib64"; -} - -static void addMultilibsFilePaths(const Driver &D, const MultilibSet &Multilibs, - const Multilib &Multilib, - StringRef InstallPath, - ToolChain::path_list &Paths) { - if (const auto &PathsCallback = Multilibs.filePathsCallback()) - for (const auto &Path : PathsCallback(Multilib)) - addPathIfExists(D, InstallPath + Path, Paths); -} - -Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) - : Generic_ELF(D, Triple, Args) { - GCCInstallation.init(Triple, Args); - Multilibs = GCCInstallation.getMultilibs(); - llvm::Triple::ArchType Arch = Triple.getArch(); - std::string SysRoot = computeSysRoot(); - - // Cross-compiling binutils and GCC installations (vanilla and openSUSE at - // least) put various tools in a triple-prefixed directory off of the parent - // of the GCC installation. We use the GCC triple here to ensure that we end - // up with tools that support the same amount of cross compiling as the - // detected GCC installation. For example, if we find a GCC installation - // targeting x86_64, but it is a bi-arch GCC installation, it can also be - // used to target i386. - // FIXME: This seems unlikely to be Linux-specific. - ToolChain::path_list &PPaths = getProgramPaths(); - PPaths.push_back(Twine(GCCInstallation.getParentLibPath() + "/../" + - GCCInstallation.getTriple().str() + "/bin") - .str()); - - Distro Distro(D.getVFS()); - - if (Distro.IsOpenSUSE() || Distro.IsUbuntu()) { - ExtraOpts.push_back("-z"); - ExtraOpts.push_back("relro"); - } - - if (Arch == llvm::Triple::arm || Arch == llvm::Triple::thumb) - ExtraOpts.push_back("-X"); - - const bool IsAndroid = Triple.isAndroid(); - const bool IsMips = isMipsArch(Arch); - const bool IsHexagon = Arch == llvm::Triple::hexagon; - - if (IsMips && !SysRoot.empty()) - ExtraOpts.push_back("--sysroot=" + SysRoot); - - // Do not use 'gnu' hash style for Mips targets because .gnu.hash - // and the MIPS ABI require .dynsym to be sorted in different ways. - // .gnu.hash needs symbols to be grouped by hash code whereas the MIPS - // ABI requires a mapping between the GOT and the symbol table. - // Android loader does not support .gnu.hash. - // Hexagon linker/loader does not support .gnu.hash - if (!IsMips && !IsAndroid && !IsHexagon) { - if (Distro.IsRedhat() || Distro.IsOpenSUSE() || - (Distro.IsUbuntu() && Distro >= Distro::UbuntuMaverick)) - ExtraOpts.push_back("--hash-style=gnu"); - - if (Distro.IsDebian() || Distro.IsOpenSUSE() || Distro == Distro::UbuntuLucid || - Distro == Distro::UbuntuJaunty || Distro == Distro::UbuntuKarmic) - ExtraOpts.push_back("--hash-style=both"); - } - - if (Distro.IsRedhat() && Distro != Distro::RHEL5 && Distro != Distro::RHEL6) - ExtraOpts.push_back("--no-add-needed"); - -#ifdef ENABLE_LINKER_BUILD_ID - ExtraOpts.push_back("--build-id"); -#endif - - if (Distro.IsOpenSUSE()) - ExtraOpts.push_back("--enable-new-dtags"); - - // The selection of paths to try here is designed to match the patterns which - // the GCC driver itself uses, as this is part of the GCC-compatible driver. - // This was determined by running GCC in a fake filesystem, creating all - // possible permutations of these directories, and seeing which ones it added - // to the link paths. - path_list &Paths = getFilePaths(); - - const std::string OSLibDir = getOSLibDir(Triple, Args); - const std::string MultiarchTriple = getMultiarchTriple(D, Triple, SysRoot); - - // Add the multilib suffixed paths where they are available. - if (GCCInstallation.isValid()) { - const llvm::Triple &GCCTriple = GCCInstallation.getTriple(); - const std::string &LibPath = GCCInstallation.getParentLibPath(); - const Multilib &Multilib = GCCInstallation.getMultilib(); - const MultilibSet &Multilibs = GCCInstallation.getMultilibs(); - - // Add toolchain / multilib specific file paths. - addMultilibsFilePaths(D, Multilibs, Multilib, - GCCInstallation.getInstallPath(), Paths); - - // Sourcery CodeBench MIPS toolchain holds some libraries under - // a biarch-like suffix of the GCC installation. - addPathIfExists(D, GCCInstallation.getInstallPath() + Multilib.gccSuffix(), - Paths); - - // GCC cross compiling toolchains will install target libraries which ship - // as part of the toolchain under <prefix>/<triple>/<libdir> rather than as - // any part of the GCC installation in - // <prefix>/<libdir>/gcc/<triple>/<version>. This decision is somewhat - // debatable, but is the reality today. We need to search this tree even - // when we have a sysroot somewhere else. It is the responsibility of - // whomever is doing the cross build targeting a sysroot using a GCC - // installation that is *not* within the system root to ensure two things: - // - // 1) Any DSOs that are linked in from this tree or from the install path - // above must be present on the system root and found via an - // appropriate rpath. - // 2) There must not be libraries installed into - // <prefix>/<triple>/<libdir> unless they should be preferred over - // those within the system root. - // - // Note that this matches the GCC behavior. See the below comment for where - // Clang diverges from GCC's behavior. - addPathIfExists(D, LibPath + "/../" + GCCTriple.str() + "/lib/../" + - OSLibDir + Multilib.osSuffix(), - Paths); - - // If the GCC installation we found is inside of the sysroot, we want to - // prefer libraries installed in the parent prefix of the GCC installation. - // It is important to *not* use these paths when the GCC installation is - // outside of the system root as that can pick up unintended libraries. - // This usually happens when there is an external cross compiler on the - // host system, and a more minimal sysroot available that is the target of - // the cross. Note that GCC does include some of these directories in some - // configurations but this seems somewhere between questionable and simply - // a bug. - if (StringRef(LibPath).startswith(SysRoot)) { - addPathIfExists(D, LibPath + "/" + MultiarchTriple, Paths); - addPathIfExists(D, LibPath + "/../" + OSLibDir, Paths); - } - } - - // Similar to the logic for GCC above, if we currently running Clang inside - // of the requested system root, add its parent library paths to - // those searched. - // FIXME: It's not clear whether we should use the driver's installed - // directory ('Dir' below) or the ResourceDir. - if (StringRef(D.Dir).startswith(SysRoot)) { - addPathIfExists(D, D.Dir + "/../lib/" + MultiarchTriple, Paths); - addPathIfExists(D, D.Dir + "/../" + OSLibDir, Paths); - } - - addPathIfExists(D, SysRoot + "/lib/" + MultiarchTriple, Paths); - addPathIfExists(D, SysRoot + "/lib/../" + OSLibDir, Paths); - addPathIfExists(D, SysRoot + "/usr/lib/" + MultiarchTriple, Paths); - addPathIfExists(D, SysRoot + "/usr/lib/../" + OSLibDir, Paths); - - // Try walking via the GCC triple path in case of biarch or multiarch GCC - // installations with strange symlinks. - if (GCCInstallation.isValid()) { - addPathIfExists(D, - SysRoot + "/usr/lib/" + GCCInstallation.getTriple().str() + - "/../../" + OSLibDir, - Paths); - - // Add the 'other' biarch variant path - Multilib BiarchSibling; - if (GCCInstallation.getBiarchSibling(BiarchSibling)) { - addPathIfExists(D, GCCInstallation.getInstallPath() + - BiarchSibling.gccSuffix(), - Paths); - } - - // See comments above on the multilib variant for details of why this is - // included even from outside the sysroot. - const std::string &LibPath = GCCInstallation.getParentLibPath(); - const llvm::Triple &GCCTriple = GCCInstallation.getTriple(); - const Multilib &Multilib = GCCInstallation.getMultilib(); - addPathIfExists(D, LibPath + "/../" + GCCTriple.str() + "/lib" + - Multilib.osSuffix(), - Paths); - - // See comments above on the multilib variant for details of why this is - // only included from within the sysroot. - if (StringRef(LibPath).startswith(SysRoot)) - addPathIfExists(D, LibPath, Paths); - } - - // Similar to the logic for GCC above, if we are currently running Clang - // inside of the requested system root, add its parent library path to those - // searched. - // FIXME: It's not clear whether we should use the driver's installed - // directory ('Dir' below) or the ResourceDir. - if (StringRef(D.Dir).startswith(SysRoot)) - addPathIfExists(D, D.Dir + "/../lib", Paths); - - addPathIfExists(D, SysRoot + "/lib", Paths); - addPathIfExists(D, SysRoot + "/usr/lib", Paths); -} - -bool Linux::HasNativeLLVMSupport() const { return true; } - -Tool *Linux::buildLinker() const { return new tools::gnutools::Linker(*this); } - -Tool *Linux::buildAssembler() const { - return new tools::gnutools::Assembler(*this); -} - -std::string Linux::computeSysRoot() const { - if (!getDriver().SysRoot.empty()) - return getDriver().SysRoot; - - if (!GCCInstallation.isValid() || !isMipsArch(getTriple().getArch())) - return std::string(); - - // Standalone MIPS toolchains use different names for sysroot folder - // and put it into different places. Here we try to check some known - // variants. - - const StringRef InstallDir = GCCInstallation.getInstallPath(); - const StringRef TripleStr = GCCInstallation.getTriple().str(); - const Multilib &Multilib = GCCInstallation.getMultilib(); - - std::string Path = - (InstallDir + "/../../../../" + TripleStr + "/libc" + Multilib.osSuffix()) - .str(); - - if (getVFS().exists(Path)) - return Path; - - Path = (InstallDir + "/../../../../sysroot" + Multilib.osSuffix()).str(); - - if (getVFS().exists(Path)) - return Path; - - return std::string(); -} - -std::string Linux::getDynamicLinker(const ArgList &Args) const { - const llvm::Triple::ArchType Arch = getArch(); - const llvm::Triple &Triple = getTriple(); - - const Distro Distro(getDriver().getVFS()); - - if (Triple.isAndroid()) - return Triple.isArch64Bit() ? "/system/bin/linker64" : "/system/bin/linker"; - - if (Triple.isMusl()) { - std::string ArchName; - bool IsArm = false; - - switch (Arch) { - case llvm::Triple::arm: - case llvm::Triple::thumb: - ArchName = "arm"; - IsArm = true; - break; - case llvm::Triple::armeb: - case llvm::Triple::thumbeb: - ArchName = "armeb"; - IsArm = true; - break; - default: - ArchName = Triple.getArchName().str(); - } - if (IsArm && - (Triple.getEnvironment() == llvm::Triple::MuslEABIHF || - tools::arm::getARMFloatABI(*this, Args) == tools::arm::FloatABI::Hard)) - ArchName += "hf"; - - return "/lib/ld-musl-" + ArchName + ".so.1"; - } - - std::string LibDir; - std::string Loader; - - switch (Arch) { - default: - llvm_unreachable("unsupported architecture"); - - case llvm::Triple::aarch64: - LibDir = "lib"; - Loader = "ld-linux-aarch64.so.1"; - break; - case llvm::Triple::aarch64_be: - LibDir = "lib"; - Loader = "ld-linux-aarch64_be.so.1"; - break; - case llvm::Triple::arm: - case llvm::Triple::thumb: - case llvm::Triple::armeb: - case llvm::Triple::thumbeb: { - const bool HF = - Triple.getEnvironment() == llvm::Triple::GNUEABIHF || - tools::arm::getARMFloatABI(*this, Args) == tools::arm::FloatABI::Hard; - - LibDir = "lib"; - Loader = HF ? "ld-linux-armhf.so.3" : "ld-linux.so.3"; - break; - } - case llvm::Triple::mips: - case llvm::Triple::mipsel: - case llvm::Triple::mips64: - case llvm::Triple::mips64el: { - bool LE = (Triple.getArch() == llvm::Triple::mipsel) || - (Triple.getArch() == llvm::Triple::mips64el); - bool IsNaN2008 = tools::mips::isNaN2008(Args, Triple); - - LibDir = "lib" + tools::mips::getMipsABILibSuffix(Args, Triple); - - if (tools::mips::isUCLibc(Args)) - Loader = IsNaN2008 ? "ld-uClibc-mipsn8.so.0" : "ld-uClibc.so.0"; - else if (!Triple.hasEnvironment() && - Triple.getVendor() == llvm::Triple::VendorType::MipsTechnologies) - Loader = LE ? "ld-musl-mipsel.so.1" : "ld-musl-mips.so.1"; - else - Loader = IsNaN2008 ? "ld-linux-mipsn8.so.1" : "ld.so.1"; - - break; - } - case llvm::Triple::ppc: - LibDir = "lib"; - Loader = "ld.so.1"; - break; - case llvm::Triple::ppc64: - LibDir = "lib64"; - Loader = - (tools::ppc::hasPPCAbiArg(Args, "elfv2")) ? "ld64.so.2" : "ld64.so.1"; - break; - case llvm::Triple::ppc64le: - LibDir = "lib64"; - Loader = - (tools::ppc::hasPPCAbiArg(Args, "elfv1")) ? "ld64.so.1" : "ld64.so.2"; - break; - case llvm::Triple::sparc: - case llvm::Triple::sparcel: - LibDir = "lib"; - Loader = "ld-linux.so.2"; - break; - case llvm::Triple::sparcv9: - LibDir = "lib64"; - Loader = "ld-linux.so.2"; - break; - case llvm::Triple::systemz: - LibDir = "lib"; - Loader = "ld64.so.1"; - break; - case llvm::Triple::x86: - LibDir = "lib"; - Loader = "ld-linux.so.2"; - break; - case llvm::Triple::x86_64: { - bool X32 = Triple.getEnvironment() == llvm::Triple::GNUX32; - - LibDir = X32 ? "libx32" : "lib64"; - Loader = X32 ? "ld-linux-x32.so.2" : "ld-linux-x86-64.so.2"; - break; - } - } - - if (Distro == Distro::Exherbo && (Triple.getVendor() == llvm::Triple::UnknownVendor || - Triple.getVendor() == llvm::Triple::PC)) - return "/usr/" + Triple.str() + "/lib/" + Loader; - return "/" + LibDir + "/" + Loader; -} - -void Linux::AddClangSystemIncludeArgs(const ArgList &DriverArgs, - ArgStringList &CC1Args) const { - const Driver &D = getDriver(); - std::string SysRoot = computeSysRoot(); - - if (DriverArgs.hasArg(options::OPT_nostdinc)) - return; - - if (!DriverArgs.hasArg(options::OPT_nostdlibinc)) - addSystemInclude(DriverArgs, CC1Args, SysRoot + "/usr/local/include"); - - if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) { - SmallString<128> P(D.ResourceDir); - llvm::sys::path::append(P, "include"); - addSystemInclude(DriverArgs, CC1Args, P); - } - - if (DriverArgs.hasArg(options::OPT_nostdlibinc)) - return; - - // Check for configure-time C include directories. - StringRef CIncludeDirs(C_INCLUDE_DIRS); - if (CIncludeDirs != "") { - SmallVector<StringRef, 5> dirs; - CIncludeDirs.split(dirs, ":"); - for (StringRef dir : dirs) { - StringRef Prefix = - llvm::sys::path::is_absolute(dir) ? StringRef(SysRoot) : ""; - addExternCSystemInclude(DriverArgs, CC1Args, Prefix + dir); - } - return; - } - - // Lacking those, try to detect the correct set of system includes for the - // target triple. - - // Add include directories specific to the selected multilib set and multilib. - if (GCCInstallation.isValid()) { - const auto &Callback = Multilibs.includeDirsCallback(); - if (Callback) { - for (const auto &Path : Callback(GCCInstallation.getMultilib())) - addExternCSystemIncludeIfExists( - DriverArgs, CC1Args, GCCInstallation.getInstallPath() + Path); - } - } - - // Implement generic Debian multiarch support. - const StringRef X86_64MultiarchIncludeDirs[] = { - "/usr/include/x86_64-linux-gnu", - - // FIXME: These are older forms of multiarch. It's not clear that they're - // in use in any released version of Debian, so we should consider - // removing them. - "/usr/include/i686-linux-gnu/64", "/usr/include/i486-linux-gnu/64"}; - const StringRef X86MultiarchIncludeDirs[] = { - "/usr/include/i386-linux-gnu", - - // FIXME: These are older forms of multiarch. It's not clear that they're - // in use in any released version of Debian, so we should consider - // removing them. - "/usr/include/x86_64-linux-gnu/32", "/usr/include/i686-linux-gnu", - "/usr/include/i486-linux-gnu"}; - const StringRef AArch64MultiarchIncludeDirs[] = { - "/usr/include/aarch64-linux-gnu"}; - const StringRef ARMMultiarchIncludeDirs[] = { - "/usr/include/arm-linux-gnueabi"}; - const StringRef ARMHFMultiarchIncludeDirs[] = { - "/usr/include/arm-linux-gnueabihf"}; - const StringRef ARMEBMultiarchIncludeDirs[] = { - "/usr/include/armeb-linux-gnueabi"}; - const StringRef ARMEBHFMultiarchIncludeDirs[] = { - "/usr/include/armeb-linux-gnueabihf"}; - const StringRef MIPSMultiarchIncludeDirs[] = {"/usr/include/mips-linux-gnu"}; - const StringRef MIPSELMultiarchIncludeDirs[] = { - "/usr/include/mipsel-linux-gnu"}; - const StringRef MIPS64MultiarchIncludeDirs[] = { - "/usr/include/mips64-linux-gnu", "/usr/include/mips64-linux-gnuabi64"}; - const StringRef MIPS64ELMultiarchIncludeDirs[] = { - "/usr/include/mips64el-linux-gnu", - "/usr/include/mips64el-linux-gnuabi64"}; - const StringRef PPCMultiarchIncludeDirs[] = { - "/usr/include/powerpc-linux-gnu"}; - const StringRef PPC64MultiarchIncludeDirs[] = { - "/usr/include/powerpc64-linux-gnu"}; - const StringRef PPC64LEMultiarchIncludeDirs[] = { - "/usr/include/powerpc64le-linux-gnu"}; - const StringRef SparcMultiarchIncludeDirs[] = { - "/usr/include/sparc-linux-gnu"}; - const StringRef Sparc64MultiarchIncludeDirs[] = { - "/usr/include/sparc64-linux-gnu"}; - const StringRef SYSTEMZMultiarchIncludeDirs[] = { - "/usr/include/s390x-linux-gnu"}; - ArrayRef<StringRef> MultiarchIncludeDirs; - switch (getTriple().getArch()) { - case llvm::Triple::x86_64: - MultiarchIncludeDirs = X86_64MultiarchIncludeDirs; - break; - case llvm::Triple::x86: - MultiarchIncludeDirs = X86MultiarchIncludeDirs; - break; - case llvm::Triple::aarch64: - case llvm::Triple::aarch64_be: - MultiarchIncludeDirs = AArch64MultiarchIncludeDirs; - break; - case llvm::Triple::arm: - case llvm::Triple::thumb: - if (getTriple().getEnvironment() == llvm::Triple::GNUEABIHF) - MultiarchIncludeDirs = ARMHFMultiarchIncludeDirs; - else - MultiarchIncludeDirs = ARMMultiarchIncludeDirs; - break; - case llvm::Triple::armeb: - case llvm::Triple::thumbeb: - if (getTriple().getEnvironment() == llvm::Triple::GNUEABIHF) - MultiarchIncludeDirs = ARMEBHFMultiarchIncludeDirs; - else - MultiarchIncludeDirs = ARMEBMultiarchIncludeDirs; - break; - case llvm::Triple::mips: - MultiarchIncludeDirs = MIPSMultiarchIncludeDirs; - break; - case llvm::Triple::mipsel: - MultiarchIncludeDirs = MIPSELMultiarchIncludeDirs; - break; - case llvm::Triple::mips64: - MultiarchIncludeDirs = MIPS64MultiarchIncludeDirs; - break; - case llvm::Triple::mips64el: - MultiarchIncludeDirs = MIPS64ELMultiarchIncludeDirs; - break; - case llvm::Triple::ppc: - MultiarchIncludeDirs = PPCMultiarchIncludeDirs; - break; - case llvm::Triple::ppc64: - MultiarchIncludeDirs = PPC64MultiarchIncludeDirs; - break; - case llvm::Triple::ppc64le: - MultiarchIncludeDirs = PPC64LEMultiarchIncludeDirs; - break; - case llvm::Triple::sparc: - MultiarchIncludeDirs = SparcMultiarchIncludeDirs; - break; - case llvm::Triple::sparcv9: - MultiarchIncludeDirs = Sparc64MultiarchIncludeDirs; - break; - case llvm::Triple::systemz: - MultiarchIncludeDirs = SYSTEMZMultiarchIncludeDirs; - break; - default: - break; - } - for (StringRef Dir : MultiarchIncludeDirs) { - if (D.getVFS().exists(SysRoot + Dir)) { - addExternCSystemInclude(DriverArgs, CC1Args, SysRoot + Dir); - break; - } - } - - if (getTriple().getOS() == llvm::Triple::RTEMS) - return; - - // Add an include of '/include' directly. This isn't provided by default by - // system GCCs, but is often used with cross-compiling GCCs, and harmless to - // add even when Clang is acting as-if it were a system compiler. - addExternCSystemInclude(DriverArgs, CC1Args, SysRoot + "/include"); - - addExternCSystemInclude(DriverArgs, CC1Args, SysRoot + "/usr/include"); -} - -static std::string DetectLibcxxIncludePath(StringRef base) { - std::error_code EC; - int MaxVersion = 0; - std::string MaxVersionString = ""; - for (llvm::sys::fs::directory_iterator LI(base, EC), LE; !EC && LI != LE; - LI = LI.increment(EC)) { - StringRef VersionText = llvm::sys::path::filename(LI->path()); - int Version; - if (VersionText[0] == 'v' && - !VersionText.slice(1, StringRef::npos).getAsInteger(10, Version)) { - if (Version > MaxVersion) { - MaxVersion = Version; - MaxVersionString = VersionText; - } - } - } - return MaxVersion ? (base + "/" + MaxVersionString).str() : ""; -} - -std::string Linux::findLibCxxIncludePath() const { - const std::string LibCXXIncludePathCandidates[] = { - DetectLibcxxIncludePath(getDriver().Dir + "/../include/c++"), - // If this is a development, non-installed, clang, libcxx will - // not be found at ../include/c++ but it likely to be found at - // one of the following two locations: - DetectLibcxxIncludePath(getDriver().SysRoot + "/usr/local/include/c++"), - DetectLibcxxIncludePath(getDriver().SysRoot + "/usr/include/c++") }; - for (const auto &IncludePath : LibCXXIncludePathCandidates) { - if (IncludePath.empty() || !getVFS().exists(IncludePath)) - continue; - // Use the first candidate that exists. - return IncludePath; - } - return ""; -} - -void Linux::addLibStdCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args) const { - // We need a detected GCC installation on Linux to provide libstdc++'s - // headers. - if (!GCCInstallation.isValid()) - return; - - // By default, look for the C++ headers in an include directory adjacent to - // the lib directory of the GCC installation. Note that this is expect to be - // equivalent to '/usr/include/c++/X.Y' in almost all cases. - StringRef LibDir = GCCInstallation.getParentLibPath(); - StringRef InstallDir = GCCInstallation.getInstallPath(); - StringRef TripleStr = GCCInstallation.getTriple().str(); - const Multilib &Multilib = GCCInstallation.getMultilib(); - const std::string GCCMultiarchTriple = getMultiarchTriple( - getDriver(), GCCInstallation.getTriple(), getDriver().SysRoot); - const std::string TargetMultiarchTriple = - getMultiarchTriple(getDriver(), getTriple(), getDriver().SysRoot); - const GCCVersion &Version = GCCInstallation.getVersion(); - - // The primary search for libstdc++ supports multiarch variants. - if (addLibStdCXXIncludePaths(LibDir.str() + "/../include", - "/c++/" + Version.Text, TripleStr, - GCCMultiarchTriple, TargetMultiarchTriple, - Multilib.includeSuffix(), DriverArgs, CC1Args)) - return; - - // Otherwise, fall back on a bunch of options which don't use multiarch - // layouts for simplicity. - const std::string LibStdCXXIncludePathCandidates[] = { - // Gentoo is weird and places its headers inside the GCC install, - // so if the first attempt to find the headers fails, try these patterns. - InstallDir.str() + "/include/g++-v" + Version.Text, - InstallDir.str() + "/include/g++-v" + Version.MajorStr + "." + - Version.MinorStr, - InstallDir.str() + "/include/g++-v" + Version.MajorStr, - // Android standalone toolchain has C++ headers in yet another place. - LibDir.str() + "/../" + TripleStr.str() + "/include/c++/" + Version.Text, - // Freescale SDK C++ headers are directly in <sysroot>/usr/include/c++, - // without a subdirectory corresponding to the gcc version. - LibDir.str() + "/../include/c++", - }; - - for (const auto &IncludePath : LibStdCXXIncludePathCandidates) { - if (addLibStdCXXIncludePaths(IncludePath, /*Suffix*/ "", TripleStr, - /*GCCMultiarchTriple*/ "", - /*TargetMultiarchTriple*/ "", - Multilib.includeSuffix(), DriverArgs, CC1Args)) - break; - } -} - -void Linux::AddCudaIncludeArgs(const ArgList &DriverArgs, - ArgStringList &CC1Args) const { - CudaInstallation.AddCudaIncludeArgs(DriverArgs, CC1Args); -} - -void Linux::AddIAMCUIncludeArgs(const ArgList &DriverArgs, - ArgStringList &CC1Args) const { - if (GCCInstallation.isValid()) { - CC1Args.push_back("-isystem"); - CC1Args.push_back(DriverArgs.MakeArgString( - GCCInstallation.getParentLibPath() + "/../" + - GCCInstallation.getTriple().str() + "/include")); - } -} - -bool Linux::isPIEDefault() const { return getSanitizerArgs().requiresPIE(); } - -SanitizerMask Linux::getSupportedSanitizers() const { - const bool IsX86 = getTriple().getArch() == llvm::Triple::x86; - const bool IsX86_64 = getTriple().getArch() == llvm::Triple::x86_64; - const bool IsMIPS64 = getTriple().getArch() == llvm::Triple::mips64 || - getTriple().getArch() == llvm::Triple::mips64el; - const bool IsPowerPC64 = getTriple().getArch() == llvm::Triple::ppc64 || - getTriple().getArch() == llvm::Triple::ppc64le; - const bool IsAArch64 = getTriple().getArch() == llvm::Triple::aarch64 || - getTriple().getArch() == llvm::Triple::aarch64_be; - SanitizerMask Res = ToolChain::getSupportedSanitizers(); - Res |= SanitizerKind::Address; - Res |= SanitizerKind::KernelAddress; - Res |= SanitizerKind::Vptr; - Res |= SanitizerKind::SafeStack; - if (IsX86_64 || IsMIPS64 || IsAArch64) - Res |= SanitizerKind::DataFlow; - if (IsX86_64 || IsMIPS64 || IsAArch64 || IsX86) - Res |= SanitizerKind::Leak; - if (IsX86_64 || IsMIPS64 || IsAArch64 || IsPowerPC64) - Res |= SanitizerKind::Thread; - if (IsX86_64 || IsMIPS64 || IsPowerPC64 || IsAArch64) - Res |= SanitizerKind::Memory; - if (IsX86_64 || IsMIPS64) - Res |= SanitizerKind::Efficiency; - if (IsX86 || IsX86_64) { - Res |= SanitizerKind::Function; - } - return Res; -} - -void Linux::addProfileRTLibs(const llvm::opt::ArgList &Args, - llvm::opt::ArgStringList &CmdArgs) const { - if (!needsProfileRT(Args)) return; - - // Add linker option -u__llvm_runtime_variable to cause runtime - // initialization module to be linked in. - if (!Args.hasArg(options::OPT_coverage)) - CmdArgs.push_back(Args.MakeArgString( - Twine("-u", llvm::getInstrProfRuntimeHookVarName()))); - ToolChain::addProfileRTLibs(Args, CmdArgs); -} - -/// Fuchsia - Fuchsia tool chain which can call as(1) and ld(1) directly. - -Fuchsia::Fuchsia(const Driver &D, const llvm::Triple &Triple, - const ArgList &Args) - : Generic_ELF(D, Triple, Args) { - - getFilePaths().push_back(D.SysRoot + "/lib"); - getFilePaths().push_back(D.ResourceDir + "/lib/fuchsia"); -} - -Tool *Fuchsia::buildAssembler() const { - return new tools::gnutools::Assembler(*this); -} - -Tool *Fuchsia::buildLinker() const { - return new tools::fuchsia::Linker(*this); -} - -ToolChain::RuntimeLibType Fuchsia::GetRuntimeLibType( - const ArgList &Args) const { - if (Arg *A = Args.getLastArg(options::OPT_rtlib_EQ)) { - StringRef Value = A->getValue(); - if (Value != "compiler-rt") - getDriver().Diag(diag::err_drv_invalid_rtlib_name) - << A->getAsString(Args); - } - - return ToolChain::RLT_CompilerRT; -} - -ToolChain::CXXStdlibType -Fuchsia::GetCXXStdlibType(const ArgList &Args) const { - if (Arg *A = Args.getLastArg(options::OPT_stdlib_EQ)) { - StringRef Value = A->getValue(); - if (Value != "libc++") - getDriver().Diag(diag::err_drv_invalid_stdlib_name) - << A->getAsString(Args); - } - - return ToolChain::CST_Libcxx; -} - -void Fuchsia::addClangTargetOptions(const ArgList &DriverArgs, - ArgStringList &CC1Args) const { - if (DriverArgs.hasFlag(options::OPT_fuse_init_array, - options::OPT_fno_use_init_array, true)) - CC1Args.push_back("-fuse-init-array"); -} - -void Fuchsia::AddClangSystemIncludeArgs(const ArgList &DriverArgs, - ArgStringList &CC1Args) const { - const Driver &D = getDriver(); - - if (DriverArgs.hasArg(options::OPT_nostdinc)) - return; - - if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) { - SmallString<128> P(D.ResourceDir); - llvm::sys::path::append(P, "include"); - addSystemInclude(DriverArgs, CC1Args, P); - } - - if (DriverArgs.hasArg(options::OPT_nostdlibinc)) - return; - - // Check for configure-time C include directories. - StringRef CIncludeDirs(C_INCLUDE_DIRS); - if (CIncludeDirs != "") { - SmallVector<StringRef, 5> dirs; - CIncludeDirs.split(dirs, ":"); - for (StringRef dir : dirs) { - StringRef Prefix = - llvm::sys::path::is_absolute(dir) ? StringRef(D.SysRoot) : ""; - addExternCSystemInclude(DriverArgs, CC1Args, Prefix + dir); - } - return; - } - - addExternCSystemInclude(DriverArgs, CC1Args, D.SysRoot + "/include"); -} - -std::string Fuchsia::findLibCxxIncludePath() const { - return getDriver().SysRoot + "/include/c++/v1"; -} - -void Fuchsia::AddCXXStdlibLibArgs(const ArgList &Args, - ArgStringList &CmdArgs) const { - (void) GetCXXStdlibType(Args); - CmdArgs.push_back("-lc++"); - CmdArgs.push_back("-lc++abi"); - CmdArgs.push_back("-lunwind"); -} - -SanitizerMask Fuchsia::getSupportedSanitizers() const { - SanitizerMask Res = ToolChain::getSupportedSanitizers(); - Res |= SanitizerKind::SafeStack; - return Res; -} - -/// DragonFly - DragonFly tool chain which can call as(1) and ld(1) directly. - -DragonFly::DragonFly(const Driver &D, const llvm::Triple &Triple, - const ArgList &Args) - : Generic_ELF(D, Triple, Args) { - - // Path mangling to find libexec - getProgramPaths().push_back(getDriver().getInstalledDir()); - if (getDriver().getInstalledDir() != getDriver().Dir) - getProgramPaths().push_back(getDriver().Dir); - - getFilePaths().push_back(getDriver().Dir + "/../lib"); - getFilePaths().push_back("/usr/lib"); - getFilePaths().push_back("/usr/lib/gcc50"); -} - -Tool *DragonFly::buildAssembler() const { - return new tools::dragonfly::Assembler(*this); -} - -Tool *DragonFly::buildLinker() const { - return new tools::dragonfly::Linker(*this); -} - -/// 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) - : ToolChain(D, Triple, Args), HostTC(HostTC), - CudaInstallation(D, HostTC.getTriple(), Args) { - if (CudaInstallation.isValid()) - getProgramPaths().push_back(CudaInstallation.getBinPath()); -} - -void CudaToolChain::addClangTargetOptions( - const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args) const { - HostTC.addClangTargetOptions(DriverArgs, CC1Args); - - CC1Args.push_back("-fcuda-is-device"); - - if (DriverArgs.hasFlag(options::OPT_fcuda_flush_denormals_to_zero, - options::OPT_fno_cuda_flush_denormals_to_zero, false)) - CC1Args.push_back("-fcuda-flush-denormals-to-zero"); - - 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; - - StringRef GpuArch = DriverArgs.getLastArgValue(options::OPT_march_EQ); - assert(!GpuArch.empty() && "Must have an explicit GPU arch."); - std::string LibDeviceFile = CudaInstallation.getLibDeviceFile(GpuArch); - - if (LibDeviceFile.empty()) { - getDriver().Diag(diag::err_drv_no_cuda_libdevice) << GpuArch; - return; - } - - 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"); -} - -void CudaToolChain::AddCudaIncludeArgs(const ArgList &DriverArgs, - ArgStringList &CC1Args) const { - // Check our CUDA version if we're going to include the CUDA headers. - if (!DriverArgs.hasArg(options::OPT_nocudainc) && - !DriverArgs.hasArg(options::OPT_no_cuda_version_check)) { - StringRef Arch = DriverArgs.getLastArgValue(options::OPT_march_EQ); - assert(!Arch.empty() && "Must have an explicit GPU arch."); - CudaInstallation.CheckCudaVersionSupportsArch(StringToCudaArch(Arch)); - } - CudaInstallation.AddCudaIncludeArgs(DriverArgs, CC1Args); -} - -llvm::opt::DerivedArgList * -CudaToolChain::TranslateArgs(const llvm::opt::DerivedArgList &Args, - StringRef BoundArch, - Action::OffloadKind DeviceOffloadKind) const { - DerivedArgList *DAL = - HostTC.TranslateArgs(Args, BoundArch, DeviceOffloadKind); - if (!DAL) - DAL = new DerivedArgList(Args.getBaseArgs()); - - const OptTable &Opts = getDriver().getOpts(); - - for (Arg *A : Args) { - if (A->getOption().matches(options::OPT_Xarch__)) { - // Skip this argument unless the architecture matches BoundArch - if (BoundArch.empty() || A->getValue(0) != BoundArch) - continue; - - unsigned Index = Args.getBaseArgs().MakeIndex(A->getValue(1)); - unsigned Prev = Index; - std::unique_ptr<Arg> XarchArg(Opts.ParseOneArg(Args, Index)); - - // If the argument parsing failed or more than one argument was - // consumed, the -Xarch_ argument's parameter tried to consume - // extra arguments. Emit an error and ignore. - // - // We also want to disallow any options which would alter the - // driver behavior; that isn't going to work in our model. We - // use isDriverOption() as an approximation, although things - // like -O4 are going to slip through. - if (!XarchArg || Index > Prev + 1) { - getDriver().Diag(diag::err_drv_invalid_Xarch_argument_with_args) - << A->getAsString(Args); - continue; - } else if (XarchArg->getOption().hasFlag(options::DriverOption)) { - getDriver().Diag(diag::err_drv_invalid_Xarch_argument_isdriver) - << A->getAsString(Args); - continue; - } - XarchArg->setBaseArg(A); - A = XarchArg.release(); - DAL->AddSynthesizedArg(A); - } - DAL->append(A); - } - - if (!BoundArch.empty()) { - DAL->eraseArg(options::OPT_march_EQ); - DAL->AddJoinedArg(nullptr, Opts.getOption(options::OPT_march_EQ), BoundArch); - } - return DAL; -} - -Tool *CudaToolChain::buildAssembler() const { - return new tools::NVPTX::Assembler(*this); -} - -Tool *CudaToolChain::buildLinker() const { - return new tools::NVPTX::Linker(*this); -} - -void CudaToolChain::addClangWarningOptions(ArgStringList &CC1Args) const { - HostTC.addClangWarningOptions(CC1Args); -} - -ToolChain::CXXStdlibType -CudaToolChain::GetCXXStdlibType(const ArgList &Args) const { - return HostTC.GetCXXStdlibType(Args); -} - -void CudaToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs, - ArgStringList &CC1Args) const { - HostTC.AddClangSystemIncludeArgs(DriverArgs, CC1Args); -} - -void CudaToolChain::AddClangCXXStdlibIncludeArgs(const ArgList &Args, - ArgStringList &CC1Args) const { - HostTC.AddClangCXXStdlibIncludeArgs(Args, CC1Args); -} - -void CudaToolChain::AddIAMCUIncludeArgs(const ArgList &Args, - ArgStringList &CC1Args) const { - HostTC.AddIAMCUIncludeArgs(Args, CC1Args); -} - -SanitizerMask CudaToolChain::getSupportedSanitizers() const { - // The CudaToolChain only supports sanitizers in the sense that it allows - // sanitizer arguments on the command line if they are supported by the host - // toolchain. The CudaToolChain will actually ignore any command line - // arguments for any of these "supported" sanitizers. That means that no - // sanitization of device code is actually supported at this time. - // - // This behavior is necessary because the host and device toolchains - // invocations often share the command line, so the device toolchain must - // tolerate flags meant only for the host toolchain. - return HostTC.getSupportedSanitizers(); -} - -VersionTuple CudaToolChain::computeMSVCVersion(const Driver *D, - const ArgList &Args) const { - return HostTC.computeMSVCVersion(D, Args); -} - -/// XCore tool chain -XCoreToolChain::XCoreToolChain(const Driver &D, const llvm::Triple &Triple, - const ArgList &Args) - : ToolChain(D, Triple, Args) { - // ProgramPaths are found via 'PATH' environment variable. -} - -Tool *XCoreToolChain::buildAssembler() const { - return new tools::XCore::Assembler(*this); -} - -Tool *XCoreToolChain::buildLinker() const { - return new tools::XCore::Linker(*this); -} - -bool XCoreToolChain::isPICDefault() const { return false; } - -bool XCoreToolChain::isPIEDefault() const { return false; } - -bool XCoreToolChain::isPICDefaultForced() const { return false; } - -bool XCoreToolChain::SupportsProfiling() const { return false; } - -bool XCoreToolChain::hasBlocksRuntime() const { return false; } - -void XCoreToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs, - ArgStringList &CC1Args) const { - if (DriverArgs.hasArg(options::OPT_nostdinc) || - DriverArgs.hasArg(options::OPT_nostdlibinc)) - return; - if (const char *cl_include_dir = getenv("XCC_C_INCLUDE_PATH")) { - SmallVector<StringRef, 4> Dirs; - const char EnvPathSeparatorStr[] = {llvm::sys::EnvPathSeparator, '\0'}; - StringRef(cl_include_dir).split(Dirs, StringRef(EnvPathSeparatorStr)); - ArrayRef<StringRef> DirVec(Dirs); - addSystemIncludes(DriverArgs, CC1Args, DirVec); - } -} - -void XCoreToolChain::addClangTargetOptions(const ArgList &DriverArgs, - ArgStringList &CC1Args) const { - CC1Args.push_back("-nostdsysteminc"); -} - -void XCoreToolChain::AddClangCXXStdlibIncludeArgs( - const ArgList &DriverArgs, ArgStringList &CC1Args) const { - if (DriverArgs.hasArg(options::OPT_nostdinc) || - DriverArgs.hasArg(options::OPT_nostdlibinc) || - DriverArgs.hasArg(options::OPT_nostdincxx)) - return; - if (const char *cl_include_dir = getenv("XCC_CPLUS_INCLUDE_PATH")) { - SmallVector<StringRef, 4> Dirs; - const char EnvPathSeparatorStr[] = {llvm::sys::EnvPathSeparator, '\0'}; - StringRef(cl_include_dir).split(Dirs, StringRef(EnvPathSeparatorStr)); - ArrayRef<StringRef> DirVec(Dirs); - addSystemIncludes(DriverArgs, CC1Args, DirVec); - } -} - -void XCoreToolChain::AddCXXStdlibLibArgs(const ArgList &Args, - ArgStringList &CmdArgs) const { - // We don't output any lib args. This is handled by xcc. -} - -MyriadToolChain::MyriadToolChain(const Driver &D, const llvm::Triple &Triple, - const ArgList &Args) - : Generic_ELF(D, Triple, Args) { - // If a target of 'sparc-myriad-elf' is specified to clang, it wants to use - // 'sparc-myriad--elf' (note the unknown OS) as the canonical triple. - // This won't work to find gcc. Instead we give the installation detector an - // extra triple, which is preferable to further hacks of the logic that at - // present is based solely on getArch(). In particular, it would be wrong to - // choose the myriad installation when targeting a non-myriad sparc install. - switch (Triple.getArch()) { - default: - D.Diag(diag::err_target_unsupported_arch) << Triple.getArchName() - << "myriad"; - case llvm::Triple::sparc: - case llvm::Triple::sparcel: - case llvm::Triple::shave: - GCCInstallation.init(Triple, Args, {"sparc-myriad-elf"}); - } - - if (GCCInstallation.isValid()) { - // This directory contains crt{i,n,begin,end}.o as well as libgcc. - // These files are tied to a particular version of gcc. - SmallString<128> CompilerSupportDir(GCCInstallation.getInstallPath()); - addPathIfExists(D, CompilerSupportDir, getFilePaths()); - } - // libstd++ and libc++ must both be found in this one place. - addPathIfExists(D, D.Dir + "/../sparc-myriad-elf/lib", getFilePaths()); -} - -MyriadToolChain::~MyriadToolChain() {} - -void MyriadToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs, - ArgStringList &CC1Args) const { - if (!DriverArgs.hasArg(options::OPT_nostdinc)) - addSystemInclude(DriverArgs, CC1Args, getDriver().SysRoot + "/include"); -} - -std::string MyriadToolChain::findLibCxxIncludePath() const { - std::string Path(getDriver().getInstalledDir()); - return Path + "/../include/c++/v1"; -} - -void MyriadToolChain::addLibStdCxxIncludePaths( - const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args) const { - StringRef LibDir = GCCInstallation.getParentLibPath(); - const GCCVersion &Version = GCCInstallation.getVersion(); - StringRef TripleStr = GCCInstallation.getTriple().str(); - const Multilib &Multilib = GCCInstallation.getMultilib(); - addLibStdCXXIncludePaths( - LibDir.str() + "/../" + TripleStr.str() + "/include/c++/" + Version.Text, - "", TripleStr, "", "", Multilib.includeSuffix(), DriverArgs, CC1Args); -} - -// MyriadToolChain handles several triples: -// {shave,sparc{,el}}-myriad-{rtems,unknown}-elf -Tool *MyriadToolChain::SelectTool(const JobAction &JA) const { - // The inherited method works fine if not targeting the SHAVE. - if (!isShaveCompilation(getTriple())) - return ToolChain::SelectTool(JA); - switch (JA.getKind()) { - case Action::PreprocessJobClass: - case Action::CompileJobClass: - if (!Compiler) - Compiler.reset(new tools::SHAVE::Compiler(*this)); - return Compiler.get(); - case Action::AssembleJobClass: - if (!Assembler) - Assembler.reset(new tools::SHAVE::Assembler(*this)); - return Assembler.get(); - default: - return ToolChain::getTool(JA.getKind()); - } -} - -Tool *MyriadToolChain::buildLinker() const { - return new tools::Myriad::Linker(*this); -} - -SanitizerMask MyriadToolChain::getSupportedSanitizers() const { - return SanitizerKind::Address; -} - -WebAssembly::WebAssembly(const Driver &D, const llvm::Triple &Triple, - const llvm::opt::ArgList &Args) - : ToolChain(D, Triple, Args) { - - assert(Triple.isArch32Bit() != Triple.isArch64Bit()); - getFilePaths().push_back( - getDriver().SysRoot + "/lib" + (Triple.isArch32Bit() ? "32" : "64")); -} - -bool WebAssembly::IsMathErrnoDefault() const { return false; } - -bool WebAssembly::IsObjCNonFragileABIDefault() const { return true; } - -bool WebAssembly::UseObjCMixedDispatch() const { return true; } - -bool WebAssembly::isPICDefault() const { return false; } - -bool WebAssembly::isPIEDefault() const { return false; } - -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. -bool WebAssembly::SupportsProfiling() const { return false; } - -bool WebAssembly::HasNativeLLVMSupport() const { return true; } - -void WebAssembly::addClangTargetOptions(const ArgList &DriverArgs, - ArgStringList &CC1Args) const { - if (DriverArgs.hasFlag(options::OPT_fuse_init_array, - options::OPT_fno_use_init_array, true)) - CC1Args.push_back("-fuse-init-array"); -} - -ToolChain::RuntimeLibType WebAssembly::GetDefaultRuntimeLibType() const { - return ToolChain::RLT_CompilerRT; -} - -ToolChain::CXXStdlibType WebAssembly::GetCXXStdlibType(const ArgList &Args) const { - return ToolChain::CST_Libcxx; -} - -void WebAssembly::AddClangSystemIncludeArgs(const ArgList &DriverArgs, - ArgStringList &CC1Args) const { - if (!DriverArgs.hasArg(options::OPT_nostdinc)) - addSystemInclude(DriverArgs, CC1Args, getDriver().SysRoot + "/include"); -} - -void WebAssembly::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs, - ArgStringList &CC1Args) const { - if (!DriverArgs.hasArg(options::OPT_nostdlibinc) && - !DriverArgs.hasArg(options::OPT_nostdincxx)) - addSystemInclude(DriverArgs, CC1Args, - getDriver().SysRoot + "/include/c++/v1"); -} - -Tool *WebAssembly::buildLinker() const { - return new tools::wasm::Linker(*this); -} - -PS4CPU::PS4CPU(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) - : Generic_ELF(D, Triple, Args) { - if (Args.hasArg(options::OPT_static)) - D.Diag(diag::err_drv_unsupported_opt_for_target) << "-static" << "PS4"; - - // Determine where to find the PS4 libraries. We use SCE_ORBIS_SDK_DIR - // if it exists; otherwise use the driver's installation path, which - // should be <SDK_DIR>/host_tools/bin. - - SmallString<512> PS4SDKDir; - if (const char *EnvValue = getenv("SCE_ORBIS_SDK_DIR")) { - if (!llvm::sys::fs::exists(EnvValue)) - getDriver().Diag(clang::diag::warn_drv_ps4_sdk_dir) << EnvValue; - PS4SDKDir = EnvValue; - } else { - PS4SDKDir = getDriver().Dir; - llvm::sys::path::append(PS4SDKDir, "/../../"); - } - - // By default, the driver won't report a warning if it can't find - // PS4's include or lib directories. This behavior could be changed if - // -Weverything or -Winvalid-or-nonexistent-directory options are passed. - // If -isysroot was passed, use that as the SDK base path. - std::string PrefixDir; - if (const Arg *A = Args.getLastArg(options::OPT_isysroot)) { - PrefixDir = A->getValue(); - if (!llvm::sys::fs::exists(PrefixDir)) - getDriver().Diag(clang::diag::warn_missing_sysroot) << PrefixDir; - } else - PrefixDir = PS4SDKDir.str(); - - SmallString<512> PS4SDKIncludeDir(PrefixDir); - llvm::sys::path::append(PS4SDKIncludeDir, "target/include"); - if (!Args.hasArg(options::OPT_nostdinc) && - !Args.hasArg(options::OPT_nostdlibinc) && - !Args.hasArg(options::OPT_isysroot) && - !Args.hasArg(options::OPT__sysroot_EQ) && - !llvm::sys::fs::exists(PS4SDKIncludeDir)) { - getDriver().Diag(clang::diag::warn_drv_unable_to_find_directory_expected) - << "PS4 system headers" << PS4SDKIncludeDir; - } - - SmallString<512> PS4SDKLibDir(PS4SDKDir); - llvm::sys::path::append(PS4SDKLibDir, "target/lib"); - if (!Args.hasArg(options::OPT_nostdlib) && - !Args.hasArg(options::OPT_nodefaultlibs) && - !Args.hasArg(options::OPT__sysroot_EQ) && !Args.hasArg(options::OPT_E) && - !Args.hasArg(options::OPT_c) && !Args.hasArg(options::OPT_S) && - !Args.hasArg(options::OPT_emit_ast) && - !llvm::sys::fs::exists(PS4SDKLibDir)) { - getDriver().Diag(clang::diag::warn_drv_unable_to_find_directory_expected) - << "PS4 system libraries" << PS4SDKLibDir; - return; - } - getFilePaths().push_back(PS4SDKLibDir.str()); -} - -Tool *PS4CPU::buildAssembler() const { - return new tools::PS4cpu::Assemble(*this); -} - -Tool *PS4CPU::buildLinker() const { return new tools::PS4cpu::Link(*this); } - -bool PS4CPU::isPICDefault() const { return true; } - -bool PS4CPU::HasNativeLLVMSupport() const { return true; } - -SanitizerMask PS4CPU::getSupportedSanitizers() const { - SanitizerMask Res = ToolChain::getSupportedSanitizers(); - Res |= SanitizerKind::Address; - Res |= SanitizerKind::Vptr; - return Res; -} - -Contiki::Contiki(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) - : Generic_ELF(D, Triple, Args) {} - -SanitizerMask Contiki::getSupportedSanitizers() const { - const bool IsX86 = getTriple().getArch() == llvm::Triple::x86; - SanitizerMask Res = ToolChain::getSupportedSanitizers(); - if (IsX86) - Res |= SanitizerKind::SafeStack; - return Res; -} - -/// AVR Toolchain -AVRToolChain::AVRToolChain(const Driver &D, const llvm::Triple &Triple, - const ArgList &Args) - : Generic_ELF(D, Triple, Args) { } -Tool *AVRToolChain::buildLinker() const { - return new tools::AVR::Linker(*this); -} -// End AVR diff --git a/lib/Driver/ToolChains.h b/lib/Driver/ToolChains.h deleted file mode 100644 index 7810b76d1b..0000000000 --- a/lib/Driver/ToolChains.h +++ /dev/null @@ -1,1389 +0,0 @@ -//===--- ToolChains.h - 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_H -#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_H - -#include "Tools.h" -#include "clang/Basic/Cuda.h" -#include "clang/Basic/VersionTuple.h" -#include "clang/Driver/Action.h" -#include "clang/Driver/Multilib.h" -#include "clang/Driver/ToolChain.h" -#include "llvm/ADT/Optional.h" -#include "llvm/ADT/SmallSet.h" -#include "llvm/Support/Compiler.h" -#include <set> -#include <vector> - -namespace clang { -namespace driver { - -/// A class to find a viable CUDA installation -class CudaInstallationDetector { -private: - const Driver &D; - bool IsValid = false; - CudaVersion Version = CudaVersion::UNKNOWN; - std::string InstallPath; - std::string BinPath; - std::string LibPath; - std::string LibDevicePath; - std::string IncludePath; - llvm::StringMap<std::string> LibDeviceMap; - - // CUDA architectures for which we have raised an error in - // CheckCudaVersionSupportsArch. - mutable llvm::SmallSet<CudaArch, 4> ArchsWithVersionTooLowErrors; - -public: - CudaInstallationDetector(const Driver &D, const llvm::Triple &HostTriple, - const llvm::opt::ArgList &Args); - - void AddCudaIncludeArgs(const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args) const; - - /// \brief Emit an error if Version does not support the given Arch. - /// - /// If either Version or Arch is unknown, does not emit an error. Emits at - /// most one error per Arch. - void CheckCudaVersionSupportsArch(CudaArch Arch) const; - - /// \brief Check whether we detected a valid Cuda install. - bool isValid() const { return IsValid; } - /// \brief Print information about the detected CUDA installation. - void print(raw_ostream &OS) const; - - /// \brief Get the detected Cuda install's version. - CudaVersion version() const { return Version; } - /// \brief Get the detected Cuda installation path. - StringRef getInstallPath() const { return InstallPath; } - /// \brief Get the detected path to Cuda's bin directory. - StringRef getBinPath() const { return BinPath; } - /// \brief Get the detected Cuda Include path. - StringRef getIncludePath() const { return IncludePath; } - /// \brief Get the detected Cuda library path. - StringRef getLibPath() const { return LibPath; } - /// \brief Get the detected Cuda device library path. - StringRef getLibDevicePath() const { return LibDevicePath; } - /// \brief Get libdevice file for given architecture - std::string getLibDeviceFile(StringRef Gpu) const { - return LibDeviceMap.lookup(Gpu); - } -}; - -namespace toolchains { - -/// Generic_GCC - A tool chain using the 'gcc' command to perform -/// all subcommands; this relies on gcc translating the majority of -/// command line options. -class LLVM_LIBRARY_VISIBILITY Generic_GCC : public ToolChain { -public: - /// \brief Struct to store and manipulate GCC versions. - /// - /// We rely on assumptions about the form and structure of GCC version - /// numbers: they consist of at most three '.'-separated components, and each - /// component is a non-negative integer except for the last component. For - /// the last component we are very flexible in order to tolerate release - /// candidates or 'x' wildcards. - /// - /// Note that the ordering established among GCCVersions is based on the - /// preferred version string to use. For example we prefer versions without - /// a hard-coded patch number to those with a hard coded patch number. - /// - /// Currently this doesn't provide any logic for textual suffixes to patches - /// in the way that (for example) Debian's version format does. If that ever - /// becomes necessary, it can be added. - struct GCCVersion { - /// \brief The unparsed text of the version. - std::string Text; - - /// \brief The parsed major, minor, and patch numbers. - int Major, Minor, Patch; - - /// \brief The text of the parsed major, and major+minor versions. - std::string MajorStr, MinorStr; - - /// \brief Any textual suffix on the patch number. - std::string PatchSuffix; - - static GCCVersion Parse(StringRef VersionText); - bool isOlderThan(int RHSMajor, int RHSMinor, int RHSPatch, - StringRef RHSPatchSuffix = StringRef()) const; - bool operator<(const GCCVersion &RHS) const { - return isOlderThan(RHS.Major, RHS.Minor, RHS.Patch, RHS.PatchSuffix); - } - bool operator>(const GCCVersion &RHS) const { return RHS < *this; } - bool operator<=(const GCCVersion &RHS) const { return !(*this > RHS); } - bool operator>=(const GCCVersion &RHS) const { return !(*this < RHS); } - }; - - /// \brief This is a class to find a viable GCC installation for Clang to - /// use. - /// - /// This class tries to find a GCC installation on the system, and report - /// information about it. It starts from the host information provided to the - /// Driver, and has logic for fuzzing that where appropriate. - class GCCInstallationDetector { - bool IsValid; - llvm::Triple GCCTriple; - const Driver &D; - - // FIXME: These might be better as path objects. - std::string GCCInstallPath; - std::string GCCParentLibPath; - - /// The primary multilib appropriate for the given flags. - Multilib SelectedMultilib; - /// On Biarch systems, this corresponds to the default multilib when - /// targeting the non-default multilib. Otherwise, it is empty. - llvm::Optional<Multilib> BiarchSibling; - - GCCVersion Version; - - // We retain the list of install paths that were considered and rejected in - // order to print out detailed information in verbose mode. - std::set<std::string> CandidateGCCInstallPaths; - - /// The set of multilibs that the detected installation supports. - MultilibSet Multilibs; - - public: - explicit GCCInstallationDetector(const Driver &D) : IsValid(false), D(D) {} - void init(const llvm::Triple &TargetTriple, const llvm::opt::ArgList &Args, - ArrayRef<std::string> ExtraTripleAliases = None); - - /// \brief Check whether we detected a valid GCC install. - bool isValid() const { return IsValid; } - - /// \brief Get the GCC triple for the detected install. - const llvm::Triple &getTriple() const { return GCCTriple; } - - /// \brief Get the detected GCC installation path. - StringRef getInstallPath() const { return GCCInstallPath; } - - /// \brief Get the detected GCC parent lib path. - StringRef getParentLibPath() const { return GCCParentLibPath; } - - /// \brief Get the detected Multilib - const Multilib &getMultilib() const { return SelectedMultilib; } - - /// \brief Get the whole MultilibSet - const MultilibSet &getMultilibs() const { return Multilibs; } - - /// Get the biarch sibling multilib (if it exists). - /// \return true iff such a sibling exists - bool getBiarchSibling(Multilib &M) const; - - /// \brief Get the detected GCC version string. - const GCCVersion &getVersion() const { return Version; } - - /// \brief Print information about the detected GCC installation. - void print(raw_ostream &OS) const; - - private: - static void - CollectLibDirsAndTriples(const llvm::Triple &TargetTriple, - const llvm::Triple &BiarchTriple, - SmallVectorImpl<StringRef> &LibDirs, - SmallVectorImpl<StringRef> &TripleAliases, - SmallVectorImpl<StringRef> &BiarchLibDirs, - SmallVectorImpl<StringRef> &BiarchTripleAliases); - - bool ScanGCCForMultilibs(const llvm::Triple &TargetTriple, - const llvm::opt::ArgList &Args, - StringRef Path, - bool NeedsBiarchSuffix = false); - - void ScanLibDirForGCCTriple(const llvm::Triple &TargetArch, - const llvm::opt::ArgList &Args, - const std::string &LibDir, - StringRef CandidateTriple, - bool NeedsBiarchSuffix = false); - - void scanLibDirForGCCTripleSolaris(const llvm::Triple &TargetArch, - const llvm::opt::ArgList &Args, - const std::string &LibDir, - StringRef CandidateTriple, - bool NeedsBiarchSuffix = false); - - bool ScanGentooGccConfig(const llvm::Triple &TargetTriple, - const llvm::opt::ArgList &Args, - StringRef CandidateTriple, - bool NeedsBiarchSuffix = false); - }; - -protected: - GCCInstallationDetector GCCInstallation; - CudaInstallationDetector CudaInstallation; - -public: - Generic_GCC(const Driver &D, const llvm::Triple &Triple, - const llvm::opt::ArgList &Args); - ~Generic_GCC() override; - - void printVerboseInfo(raw_ostream &OS) const override; - - bool IsUnwindTablesDefault() const override; - bool isPICDefault() const override; - bool isPIEDefault() const override; - bool isPICDefaultForced() const override; - bool IsIntegratedAssemblerDefault() const override; - llvm::opt::DerivedArgList * - TranslateArgs(const llvm::opt::DerivedArgList &Args, StringRef BoundArch, - Action::OffloadKind DeviceOffloadKind) const override; - -protected: - Tool *getTool(Action::ActionClass AC) const override; - Tool *buildAssembler() const override; - Tool *buildLinker() const override; - - /// \name ToolChain Implementation Helper Functions - /// @{ - - /// \brief Check whether the target triple's architecture is 64-bits. - bool isTarget64Bit() const { return getTriple().isArch64Bit(); } - - /// \brief Check whether the target triple's architecture is 32-bits. - bool isTarget32Bit() const { return getTriple().isArch32Bit(); } - - // FIXME: This should be final, but the Solaris tool chain does weird - // things we can't easily represent. - void AddClangCXXStdlibIncludeArgs( - const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args) const override; - - virtual std::string findLibCxxIncludePath() const; - virtual void - addLibStdCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args) const; - - bool addLibStdCXXIncludePaths(Twine Base, Twine Suffix, StringRef GCCTriple, - StringRef GCCMultiarchTriple, - StringRef TargetMultiarchTriple, - Twine IncludeSuffix, - const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args) const; - - /// @} - -private: - mutable std::unique_ptr<tools::gcc::Preprocessor> Preprocess; - mutable std::unique_ptr<tools::gcc::Compiler> Compile; -}; - -class LLVM_LIBRARY_VISIBILITY MachO : public ToolChain { -protected: - Tool *buildAssembler() const override; - Tool *buildLinker() const override; - Tool *getTool(Action::ActionClass AC) const override; - -private: - mutable std::unique_ptr<tools::darwin::Lipo> Lipo; - mutable std::unique_ptr<tools::darwin::Dsymutil> Dsymutil; - mutable std::unique_ptr<tools::darwin::VerifyDebug> VerifyDebug; - -public: - MachO(const Driver &D, const llvm::Triple &Triple, - const llvm::opt::ArgList &Args); - ~MachO() override; - - /// @name MachO specific toolchain API - /// { - - /// Get the "MachO" arch name for a particular compiler invocation. For - /// example, Apple treats different ARM variations as distinct architectures. - StringRef getMachOArchName(const llvm::opt::ArgList &Args) const; - - /// Add the linker arguments to link the ARC runtime library. - virtual void AddLinkARCArgs(const llvm::opt::ArgList &Args, - llvm::opt::ArgStringList &CmdArgs) const {} - - /// Add the linker arguments to link the compiler runtime library. - virtual void AddLinkRuntimeLibArgs(const llvm::opt::ArgList &Args, - llvm::opt::ArgStringList &CmdArgs) const; - - virtual void addStartObjectFileArgs(const llvm::opt::ArgList &Args, - llvm::opt::ArgStringList &CmdArgs) const { - } - - virtual void addMinVersionArgs(const llvm::opt::ArgList &Args, - llvm::opt::ArgStringList &CmdArgs) const {} - - /// On some iOS platforms, kernel and kernel modules were built statically. Is - /// this such a target? - virtual bool isKernelStatic() const { return false; } - - /// Is the target either iOS or an iOS simulator? - bool isTargetIOSBased() const { return false; } - - void AddLinkRuntimeLib(const llvm::opt::ArgList &Args, - llvm::opt::ArgStringList &CmdArgs, - StringRef DarwinLibName, bool AlwaysLink = false, - bool IsEmbedded = false, bool AddRPath = false) const; - - /// Add any profiling runtime libraries that are needed. This is essentially a - /// MachO specific version of addProfileRT in Tools.cpp. - void addProfileRTLibs(const llvm::opt::ArgList &Args, - llvm::opt::ArgStringList &CmdArgs) const override { - // There aren't any profiling libs for embedded targets currently. - } - - /// } - /// @name ToolChain Implementation - /// { - - types::ID LookupTypeForExtension(StringRef Ext) const override; - - bool HasNativeLLVMSupport() const override; - - llvm::opt::DerivedArgList * - TranslateArgs(const llvm::opt::DerivedArgList &Args, StringRef BoundArch, - Action::OffloadKind DeviceOffloadKind) const override; - - bool IsBlocksDefault() const override { - // Always allow blocks on Apple; users interested in versioning are - // expected to use /usr/include/Block.h. - return true; - } - bool IsIntegratedAssemblerDefault() const override { - // Default integrated assembler to on for Apple's MachO targets. - return true; - } - - bool IsMathErrnoDefault() const override { return false; } - - bool IsEncodeExtendedBlockSignatureDefault() const override { return true; } - - bool IsObjCNonFragileABIDefault() const override { - // Non-fragile ABI is default for everything but i386. - return getTriple().getArch() != llvm::Triple::x86; - } - - bool UseObjCMixedDispatch() const override { return true; } - - bool IsUnwindTablesDefault() const override; - - RuntimeLibType GetDefaultRuntimeLibType() const override { - return ToolChain::RLT_CompilerRT; - } - - bool isPICDefault() const override; - bool isPIEDefault() const override; - bool isPICDefaultForced() const override; - - 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; - } - - /// } -}; - -/// Darwin - The base Darwin tool chain. -class LLVM_LIBRARY_VISIBILITY Darwin : public MachO { -public: - /// Whether the information on the target has been initialized. - // - // FIXME: This should be eliminated. What we want to do is make this part of - // the "default target for arguments" selection process, once we get out of - // the argument translation business. - mutable bool TargetInitialized; - - enum DarwinPlatformKind { - MacOS, - IPhoneOS, - IPhoneOSSimulator, - TvOS, - TvOSSimulator, - WatchOS, - WatchOSSimulator - }; - - mutable DarwinPlatformKind TargetPlatform; - - /// The OS version we are targeting. - mutable VersionTuple TargetVersion; - - CudaInstallationDetector CudaInstallation; - -private: - void AddDeploymentTarget(llvm::opt::DerivedArgList &Args) const; - -public: - Darwin(const Driver &D, const llvm::Triple &Triple, - const llvm::opt::ArgList &Args); - ~Darwin() override; - - std::string ComputeEffectiveClangTriple(const llvm::opt::ArgList &Args, - types::ID InputType) const override; - - /// @name Apple Specific Toolchain Implementation - /// { - - void addMinVersionArgs(const llvm::opt::ArgList &Args, - llvm::opt::ArgStringList &CmdArgs) const override; - - void addStartObjectFileArgs(const llvm::opt::ArgList &Args, - llvm::opt::ArgStringList &CmdArgs) const override; - - bool isKernelStatic() const override { - return (!(isTargetIPhoneOS() && !isIPhoneOSVersionLT(6, 0)) && - !isTargetWatchOS()); - } - - void addProfileRTLibs(const llvm::opt::ArgList &Args, - llvm::opt::ArgStringList &CmdArgs) const override; - -protected: - /// } - /// @name Darwin specific Toolchain functions - /// { - - // 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 { - // 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 && - TargetVersion == VersionTuple(Major, Minor, Micro)) - return; - - assert(!TargetInitialized && "Target already initialized!"); - TargetInitialized = true; - TargetPlatform = Platform; - TargetVersion = VersionTuple(Major, Minor, Micro); - } - - bool isTargetIPhoneOS() const { - assert(TargetInitialized && "Target not initialized!"); - return TargetPlatform == IPhoneOS || TargetPlatform == TvOS; - } - - bool isTargetIOSSimulator() const { - assert(TargetInitialized && "Target not initialized!"); - return TargetPlatform == IPhoneOSSimulator || - TargetPlatform == TvOSSimulator; - } - - bool isTargetIOSBased() const { - assert(TargetInitialized && "Target not initialized!"); - return isTargetIPhoneOS() || isTargetIOSSimulator(); - } - - bool isTargetTvOS() const { - assert(TargetInitialized && "Target not initialized!"); - return TargetPlatform == TvOS; - } - - bool isTargetTvOSSimulator() const { - assert(TargetInitialized && "Target not initialized!"); - return TargetPlatform == TvOSSimulator; - } - - bool isTargetTvOSBased() const { - assert(TargetInitialized && "Target not initialized!"); - return TargetPlatform == TvOS || TargetPlatform == TvOSSimulator; - } - - bool isTargetWatchOS() const { - assert(TargetInitialized && "Target not initialized!"); - return TargetPlatform == WatchOS; - } - - bool isTargetWatchOSSimulator() const { - assert(TargetInitialized && "Target not initialized!"); - return TargetPlatform == WatchOSSimulator; - } - - bool isTargetWatchOSBased() const { - assert(TargetInitialized && "Target not initialized!"); - return TargetPlatform == WatchOS || TargetPlatform == WatchOSSimulator; - } - - bool isTargetMacOS() const { - assert(TargetInitialized && "Target not initialized!"); - return TargetPlatform == MacOS; - } - - bool isTargetInitialized() const { return TargetInitialized; } - - VersionTuple getTargetVersion() const { - assert(TargetInitialized && "Target not initialized!"); - return TargetVersion; - } - - bool isIPhoneOSVersionLT(unsigned V0, unsigned V1 = 0, - unsigned V2 = 0) const { - assert(isTargetIOSBased() && "Unexpected call for non iOS target!"); - return TargetVersion < VersionTuple(V0, V1, V2); - } - - bool isMacosxVersionLT(unsigned V0, unsigned V1 = 0, unsigned V2 = 0) const { - assert(isTargetMacOS() && "Unexpected call for non OS X target!"); - return TargetVersion < VersionTuple(V0, V1, V2); - } - - StringRef getPlatformFamily() const; - static StringRef getSDKName(StringRef isysroot); - StringRef getOSLibraryNameSuffix() const; - -public: - /// } - /// @name ToolChain Implementation - /// { - - // Darwin tools support multiple architecture (e.g., i386 and x86_64) and - // most development is done against SDKs, so compiling for a different - // architecture should not get any special treatment. - bool isCrossCompiling() const override { return false; } - - llvm::opt::DerivedArgList * - TranslateArgs(const llvm::opt::DerivedArgList &Args, StringRef BoundArch, - Action::OffloadKind DeviceOffloadKind) const override; - - CXXStdlibType GetDefaultCXXStdlibType() const override; - ObjCRuntime getDefaultObjCRuntime(bool isNonFragile) const override; - bool hasBlocksRuntime() const override; - - void AddCudaIncludeArgs(const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args) const override; - - bool UseObjCMixedDispatch() const override { - // This is only used with the non-fragile ABI and non-legacy dispatch. - - // Mixed dispatch is used everywhere except OS X before 10.6. - return !(isTargetMacOS() && isMacosxVersionLT(10, 6)); - } - - unsigned GetDefaultStackProtectorLevel(bool KernelOrKext) const override { - // Stack protectors default to on for user code on 10.5, - // and for everything in 10.6 and beyond - if (isTargetIOSBased() || isTargetWatchOSBased()) - return 1; - else if (isTargetMacOS() && !isMacosxVersionLT(10, 6)) - return 1; - else if (isTargetMacOS() && !isMacosxVersionLT(10, 5) && !KernelOrKext) - return 1; - - return 0; - } - - bool SupportsObjCGC() const override; - - void CheckObjCARC() const override; - - bool UseSjLjExceptions(const llvm::opt::ArgList &Args) const override; - - bool SupportsEmbeddedBitcode() const override; - - SanitizerMask getSupportedSanitizers() const override; - - void printVerboseInfo(raw_ostream &OS) const override; -}; - -/// DarwinClang - The Darwin toolchain used by Clang. -class LLVM_LIBRARY_VISIBILITY DarwinClang : public Darwin { -public: - DarwinClang(const Driver &D, const llvm::Triple &Triple, - const llvm::opt::ArgList &Args); - - /// @name Apple ToolChain Implementation - /// { - - RuntimeLibType GetRuntimeLibType(const llvm::opt::ArgList &Args) const override; - - void AddLinkRuntimeLibArgs(const llvm::opt::ArgList &Args, - llvm::opt::ArgStringList &CmdArgs) const override; - - void AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args, - llvm::opt::ArgStringList &CmdArgs) const override; - - void AddCCKextLibArgs(const llvm::opt::ArgList &Args, - llvm::opt::ArgStringList &CmdArgs) const override; - - void addClangWarningOptions(llvm::opt::ArgStringList &CC1Args) const override; - - void AddLinkARCArgs(const llvm::opt::ArgList &Args, - llvm::opt::ArgStringList &CmdArgs) const override; - - unsigned GetDefaultDwarfVersion() const override; - // Until dtrace (via CTF) and LLDB can deal with distributed debug info, - // Darwin defaults to standalone/full debug info. - bool GetDefaultStandaloneDebug() const override { return true; } - llvm::DebuggerKind getDefaultDebuggerTuning() const override { - return llvm::DebuggerKind::LLDB; - } - - /// } - -private: - void AddLinkSanitizerLibArgs(const llvm::opt::ArgList &Args, - llvm::opt::ArgStringList &CmdArgs, - StringRef Sanitizer) const; -}; - -class LLVM_LIBRARY_VISIBILITY Generic_ELF : public Generic_GCC { - virtual void anchor(); - -public: - Generic_ELF(const Driver &D, const llvm::Triple &Triple, - const llvm::opt::ArgList &Args) - : Generic_GCC(D, Triple, Args) {} - - void addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args) const override; -}; - -class LLVM_LIBRARY_VISIBILITY CloudABI : public Generic_ELF { -public: - CloudABI(const Driver &D, const llvm::Triple &Triple, - const llvm::opt::ArgList &Args); - bool HasNativeLLVMSupport() const override { return true; } - - bool IsMathErrnoDefault() const override { return false; } - bool IsObjCNonFragileABIDefault() const override { return true; } - - CXXStdlibType - GetCXXStdlibType(const llvm::opt::ArgList &Args) const override { - return ToolChain::CST_Libcxx; - } - std::string findLibCxxIncludePath() const override; - void AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args, - llvm::opt::ArgStringList &CmdArgs) const override; - - bool isPIEDefault() const override; - SanitizerMask getSupportedSanitizers() const override; - SanitizerMask getDefaultSanitizers() const override; - -protected: - Tool *buildLinker() const override; -}; - -class LLVM_LIBRARY_VISIBILITY Solaris : public Generic_GCC { -public: - Solaris(const Driver &D, const llvm::Triple &Triple, - const llvm::opt::ArgList &Args); - - bool IsIntegratedAssemblerDefault() const override { return true; } - - void AddClangCXXStdlibIncludeArgs( - const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args) const override; - - unsigned GetDefaultDwarfVersion() const override { return 2; } - -protected: - Tool *buildAssembler() const override; - Tool *buildLinker() const override; -}; - -class LLVM_LIBRARY_VISIBILITY MinGW : public ToolChain { -public: - MinGW(const Driver &D, const llvm::Triple &Triple, - const llvm::opt::ArgList &Args); - - bool IsIntegratedAssemblerDefault() const override; - bool IsUnwindTablesDefault() const override; - bool isPICDefault() const override; - bool isPIEDefault() const override; - bool isPICDefaultForced() const override; - bool UseSEHExceptions() const; - - void - AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args) const override; - void AddClangCXXStdlibIncludeArgs( - const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args) const override; - - void AddCudaIncludeArgs(const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args) const override; - - void printVerboseInfo(raw_ostream &OS) const override; - -protected: - Tool *getTool(Action::ActionClass AC) const override; - Tool *buildLinker() const override; - Tool *buildAssembler() const override; - -private: - CudaInstallationDetector CudaInstallation; - - std::string Base; - std::string GccLibDir; - std::string Ver; - std::string Arch; - mutable std::unique_ptr<tools::gcc::Preprocessor> Preprocessor; - mutable std::unique_ptr<tools::gcc::Compiler> Compiler; - void findGccLibDir(); -}; - -class LLVM_LIBRARY_VISIBILITY Haiku : public Generic_ELF { -public: - Haiku(const Driver &D, const llvm::Triple &Triple, - const llvm::opt::ArgList &Args); - - bool isPIEDefault() const override { - return getTriple().getArch() == llvm::Triple::x86_64; - } - - std::string findLibCxxIncludePath() const override; - void addLibStdCxxIncludePaths( - const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args) const override; -}; - -class LLVM_LIBRARY_VISIBILITY OpenBSD : public Generic_ELF { -public: - OpenBSD(const Driver &D, const llvm::Triple &Triple, - const llvm::opt::ArgList &Args); - - bool IsMathErrnoDefault() const override { return false; } - bool IsObjCNonFragileABIDefault() const override { return true; } - bool isPIEDefault() const override { return true; } - - unsigned GetDefaultStackProtectorLevel(bool KernelOrKext) const override { - return 2; - } - unsigned GetDefaultDwarfVersion() const override { return 2; } - -protected: - Tool *buildAssembler() const override; - Tool *buildLinker() const override; -}; - -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; -}; - -class LLVM_LIBRARY_VISIBILITY FreeBSD : public Generic_ELF { -public: - FreeBSD(const Driver &D, const llvm::Triple &Triple, - const llvm::opt::ArgList &Args); - bool HasNativeLLVMSupport() const override; - - 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; - - bool UseSjLjExceptions(const llvm::opt::ArgList &Args) const override; - bool isPIEDefault() const override; - SanitizerMask getSupportedSanitizers() const override; - unsigned GetDefaultDwarfVersion() const override { return 2; } - // Until dtrace (via CTF) and LLDB can deal with distributed debug info, - // FreeBSD defaults to standalone/full debug info. - bool GetDefaultStandaloneDebug() const override { return true; } - -protected: - Tool *buildAssembler() const override; - Tool *buildLinker() const override; -}; - -class LLVM_LIBRARY_VISIBILITY NetBSD : public Generic_ELF { -public: - NetBSD(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; - - std::string findLibCxxIncludePath() const override; - void addLibStdCxxIncludePaths( - const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args) const override; - - bool IsUnwindTablesDefault() const override { return true; } - -protected: - Tool *buildAssembler() const override; - Tool *buildLinker() const override; -}; - -class LLVM_LIBRARY_VISIBILITY Minix : public Generic_ELF { -public: - Minix(const Driver &D, const llvm::Triple &Triple, - const llvm::opt::ArgList &Args); - -protected: - Tool *buildAssembler() const override; - Tool *buildLinker() const override; -}; - -class LLVM_LIBRARY_VISIBILITY DragonFly : public Generic_ELF { -public: - DragonFly(const Driver &D, const llvm::Triple &Triple, - const llvm::opt::ArgList &Args); - - bool IsMathErrnoDefault() const override { return false; } - -protected: - Tool *buildAssembler() const override; - Tool *buildLinker() const override; -}; - -class LLVM_LIBRARY_VISIBILITY Linux : public Generic_ELF { -public: - Linux(const Driver &D, const llvm::Triple &Triple, - const llvm::opt::ArgList &Args); - - bool HasNativeLLVMSupport() const override; - - void - AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args) const override; - std::string findLibCxxIncludePath() const override; - void addLibStdCxxIncludePaths( - const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args) const override; - void AddCudaIncludeArgs(const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args) const override; - void AddIAMCUIncludeArgs(const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args) const override; - bool isPIEDefault() const override; - SanitizerMask getSupportedSanitizers() const override; - void addProfileRTLibs(const llvm::opt::ArgList &Args, - llvm::opt::ArgStringList &CmdArgs) const override; - virtual std::string computeSysRoot() const; - - virtual std::string getDynamicLinker(const llvm::opt::ArgList &Args) const; - - std::vector<std::string> ExtraOpts; - -protected: - Tool *buildAssembler() const override; - Tool *buildLinker() const override; -}; - -class LLVM_LIBRARY_VISIBILITY CudaToolChain : public ToolChain { -public: - CudaToolChain(const Driver &D, const llvm::Triple &Triple, - const ToolChain &HostTC, const llvm::opt::ArgList &Args); - - virtual const llvm::Triple *getAuxTriple() const override { - return &HostTC.getTriple(); - } - - llvm::opt::DerivedArgList * - TranslateArgs(const llvm::opt::DerivedArgList &Args, StringRef BoundArch, - Action::OffloadKind DeviceOffloadKind) const override; - void addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args) const override; - - // Never try to use the integrated assembler with CUDA; always fork out to - // ptxas. - bool useIntegratedAs() const override { return false; } - bool isCrossCompiling() const override { return true; } - bool isPICDefault() const override { return false; } - bool isPIEDefault() const override { return false; } - bool isPICDefaultForced() const override { return false; } - bool SupportsProfiling() const override { return false; } - bool SupportsObjCGC() const override { return false; } - - void AddCudaIncludeArgs(const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args) const override; - - void addClangWarningOptions(llvm::opt::ArgStringList &CC1Args) const override; - CXXStdlibType GetCXXStdlibType(const llvm::opt::ArgList &Args) const override; - void - AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args) const override; - void AddClangCXXStdlibIncludeArgs( - const llvm::opt::ArgList &Args, - llvm::opt::ArgStringList &CC1Args) const override; - void AddIAMCUIncludeArgs(const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args) const override; - - SanitizerMask getSupportedSanitizers() const override; - - VersionTuple - computeMSVCVersion(const Driver *D, - const llvm::opt::ArgList &Args) const override; - - const ToolChain &HostTC; - CudaInstallationDetector CudaInstallation; - -protected: - Tool *buildAssembler() const override; // ptxas - Tool *buildLinker() const override; // fatbinary (ok, not really a linker) -}; - -class LLVM_LIBRARY_VISIBILITY MipsLLVMToolChain : public Linux { -protected: - Tool *buildLinker() const override; - -public: - MipsLLVMToolChain(const Driver &D, const llvm::Triple &Triple, - const llvm::opt::ArgList &Args); - - void - AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args) const override; - - CXXStdlibType GetCXXStdlibType(const llvm::opt::ArgList &Args) const override; - - std::string findLibCxxIncludePath() const override; - - void AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args, - llvm::opt::ArgStringList &CmdArgs) const override; - - std::string getCompilerRT(const llvm::opt::ArgList &Args, StringRef Component, - bool Shared = false) const override; - - std::string computeSysRoot() const override; - - RuntimeLibType GetDefaultRuntimeLibType() const override { - return GCCInstallation.isValid() ? RuntimeLibType::RLT_Libgcc - : RuntimeLibType::RLT_CompilerRT; - } - - const char *getDefaultLinker() const override { - return "lld"; - } - -private: - Multilib SelectedMultilib; - std::string LibSuffix; -}; - -class LLVM_LIBRARY_VISIBILITY LanaiToolChain : public Generic_ELF { -public: - LanaiToolChain(const Driver &D, const llvm::Triple &Triple, - const llvm::opt::ArgList &Args) - : Generic_ELF(D, Triple, Args) {} - - // No support for finding a C++ standard library yet. - std::string findLibCxxIncludePath() const override { return ""; } - void addLibStdCxxIncludePaths( - const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args) const override {} - - bool IsIntegratedAssemblerDefault() const override { return true; } -}; - -class LLVM_LIBRARY_VISIBILITY HexagonToolChain : public Linux { -protected: - GCCVersion GCCLibAndIncVersion; - Tool *buildAssembler() const override; - Tool *buildLinker() const override; - -public: - HexagonToolChain(const Driver &D, const llvm::Triple &Triple, - const llvm::opt::ArgList &Args); - ~HexagonToolChain() override; - - void - AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args) const override; - void addLibStdCxxIncludePaths( - const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args) const override; - CXXStdlibType GetCXXStdlibType(const llvm::opt::ArgList &Args) const override; - - StringRef GetGCCLibAndIncVersion() const { return GCCLibAndIncVersion.Text; } - bool IsIntegratedAssemblerDefault() const override { - return true; - } - - std::string getHexagonTargetDir( - const std::string &InstalledDir, - const SmallVectorImpl<std::string> &PrefixDirs) const; - void getHexagonLibraryPaths(const llvm::opt::ArgList &Args, - ToolChain::path_list &LibPaths) const; - - static const StringRef GetDefaultCPU(); - static const StringRef GetTargetCPUVersion(const llvm::opt::ArgList &Args); - - static Optional<unsigned> getSmallDataThreshold( - const llvm::opt::ArgList &Args); -}; - -class LLVM_LIBRARY_VISIBILITY AMDGPUToolChain : public Generic_ELF { -protected: - Tool *buildLinker() const override; - -public: - AMDGPUToolChain(const Driver &D, const llvm::Triple &Triple, - const llvm::opt::ArgList &Args); - unsigned GetDefaultDwarfVersion() const override { return 2; } - bool IsIntegratedAssemblerDefault() const override { return true; } -}; - -class LLVM_LIBRARY_VISIBILITY NaClToolChain : public Generic_ELF { -public: - NaClToolChain(const Driver &D, const llvm::Triple &Triple, - const llvm::opt::ArgList &Args); - - void - AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args) const override; - std::string findLibCxxIncludePath() const override; - - CXXStdlibType GetCXXStdlibType(const llvm::opt::ArgList &Args) const override; - - void AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args, - llvm::opt::ArgStringList &CmdArgs) const override; - - bool IsIntegratedAssemblerDefault() const override { - return getTriple().getArch() == llvm::Triple::mipsel; - } - - // Get the path to the file containing NaCl's ARM macros. - // It lives in NaClToolChain because the ARMAssembler tool needs a - // const char * that it can pass around, - const char *GetNaClArmMacrosPath() const { return NaClArmMacrosPath.c_str(); } - - std::string ComputeEffectiveClangTriple(const llvm::opt::ArgList &Args, - types::ID InputType) const override; - -protected: - Tool *buildLinker() const override; - Tool *buildAssembler() const override; - -private: - std::string NaClArmMacrosPath; -}; - -class LLVM_LIBRARY_VISIBILITY Fuchsia : public Generic_ELF { -public: - Fuchsia(const Driver &D, const llvm::Triple &Triple, - const llvm::opt::ArgList &Args); - - bool isPIEDefault() const override { return true; } - bool HasNativeLLVMSupport() const override { return true; } - bool IsIntegratedAssemblerDefault() const override { return true; } - llvm::DebuggerKind getDefaultDebuggerTuning() const override { - return llvm::DebuggerKind::GDB; - } - - SanitizerMask getSupportedSanitizers() const override; - - RuntimeLibType - GetRuntimeLibType(const llvm::opt::ArgList &Args) const override; - CXXStdlibType - GetCXXStdlibType(const llvm::opt::ArgList &Args) const override; - - void addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args) const override; - void - AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args) const override; - std::string findLibCxxIncludePath() const override; - void AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args, - llvm::opt::ArgStringList &CmdArgs) const override; - - const char *getDefaultLinker() const override { - return "lld"; - } - -protected: - Tool *buildAssembler() const override; - Tool *buildLinker() const override; -}; - -/// TCEToolChain - A tool chain using the llvm bitcode tools to perform -/// all subcommands. See http://tce.cs.tut.fi for our peculiar target. -class LLVM_LIBRARY_VISIBILITY TCEToolChain : public ToolChain { -public: - TCEToolChain(const Driver &D, const llvm::Triple &Triple, - const llvm::opt::ArgList &Args); - ~TCEToolChain() override; - - bool IsMathErrnoDefault() const override; - bool isPICDefault() const override; - bool isPIEDefault() const override; - bool isPICDefaultForced() const override; -}; - -/// Toolchain for little endian TCE cores. -class LLVM_LIBRARY_VISIBILITY TCELEToolChain : public TCEToolChain { -public: - TCELEToolChain(const Driver &D, const llvm::Triple &Triple, - const llvm::opt::ArgList &Args); - ~TCELEToolChain() override; -}; - -class LLVM_LIBRARY_VISIBILITY MSVCToolChain : public ToolChain { -public: - MSVCToolChain(const Driver &D, const llvm::Triple &Triple, - const llvm::opt::ArgList &Args); - - llvm::opt::DerivedArgList * - TranslateArgs(const llvm::opt::DerivedArgList &Args, StringRef BoundArch, - Action::OffloadKind DeviceOffloadKind) const override; - - bool IsIntegratedAssemblerDefault() const override; - bool IsUnwindTablesDefault() const override; - bool isPICDefault() const override; - bool isPIEDefault() const override; - bool isPICDefaultForced() const override; - - void - AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args) const override; - void AddClangCXXStdlibIncludeArgs( - const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args) const override; - - void AddCudaIncludeArgs(const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args) const override; - - bool getWindowsSDKDir(std::string &path, int &major, - std::string &windowsSDKIncludeVersion, - std::string &windowsSDKLibVersion) const; - bool getWindowsSDKLibraryPath(std::string &path) const; - /// \brief Check if Universal CRT should be used if available - bool useUniversalCRT(std::string &visualStudioDir) const; - bool getUniversalCRTSdkDir(std::string &path, std::string &ucrtVersion) const; - bool getUniversalCRTLibraryPath(std::string &path) const; - bool getVisualStudioInstallDir(std::string &path) const; - bool getVisualStudioBinariesFolder(const char *clangProgramPath, - std::string &path) const; - VersionTuple - computeMSVCVersion(const Driver *D, - const llvm::opt::ArgList &Args) const override; - - std::string ComputeEffectiveClangTriple(const llvm::opt::ArgList &Args, - types::ID InputType) const override; - SanitizerMask getSupportedSanitizers() const override; - - void printVerboseInfo(raw_ostream &OS) const override; - -protected: - void AddSystemIncludeWithSubfolder(const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args, - const std::string &folder, - const Twine &subfolder1, - const Twine &subfolder2 = "", - const Twine &subfolder3 = "") const; - - Tool *buildLinker() const override; - Tool *buildAssembler() const override; -private: - VersionTuple getMSVCVersionFromTriple() const; - VersionTuple getMSVCVersionFromExe() const; - - CudaInstallationDetector CudaInstallation; -}; - -class LLVM_LIBRARY_VISIBILITY CrossWindowsToolChain : public Generic_GCC { -public: - CrossWindowsToolChain(const Driver &D, const llvm::Triple &T, - const llvm::opt::ArgList &Args); - - bool IsIntegratedAssemblerDefault() const override { return true; } - bool IsUnwindTablesDefault() const override; - bool isPICDefault() const override; - bool isPIEDefault() const override; - bool isPICDefaultForced() const override; - - unsigned int GetDefaultStackProtectorLevel(bool KernelOrKext) const override { - return 0; - } - - void - AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args) const override; - void AddClangCXXStdlibIncludeArgs( - const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args) const override; - void AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args, - llvm::opt::ArgStringList &CmdArgs) const override; - - SanitizerMask getSupportedSanitizers() const override; - -protected: - Tool *buildLinker() const override; - Tool *buildAssembler() const override; -}; - -class LLVM_LIBRARY_VISIBILITY XCoreToolChain : public ToolChain { -public: - XCoreToolChain(const Driver &D, const llvm::Triple &Triple, - const llvm::opt::ArgList &Args); - -protected: - Tool *buildAssembler() const override; - Tool *buildLinker() const override; - -public: - bool isPICDefault() const override; - bool isPIEDefault() const override; - bool isPICDefaultForced() const override; - bool SupportsProfiling() const override; - bool hasBlocksRuntime() const override; - void - AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args) const override; - void addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args) const override; - void AddClangCXXStdlibIncludeArgs( - const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args) const override; - void AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args, - llvm::opt::ArgStringList &CmdArgs) const override; -}; - -/// MyriadToolChain - A tool chain using either clang or the external compiler -/// installed by the Movidius SDK to perform all subcommands. -class LLVM_LIBRARY_VISIBILITY MyriadToolChain : public Generic_ELF { -public: - MyriadToolChain(const Driver &D, const llvm::Triple &Triple, - const llvm::opt::ArgList &Args); - ~MyriadToolChain() override; - - void - AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args) const override; - std::string findLibCxxIncludePath() const override; - void addLibStdCxxIncludePaths( - const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args) const override; - Tool *SelectTool(const JobAction &JA) const override; - unsigned GetDefaultDwarfVersion() const override { return 2; } - SanitizerMask getSupportedSanitizers() const override; - -protected: - Tool *buildLinker() const override; - bool isShaveCompilation(const llvm::Triple &T) const { - return T.getArch() == llvm::Triple::shave; - } - -private: - mutable std::unique_ptr<Tool> Compiler; - mutable std::unique_ptr<Tool> Assembler; -}; - -class LLVM_LIBRARY_VISIBILITY WebAssembly final : public ToolChain { -public: - WebAssembly(const Driver &D, const llvm::Triple &Triple, - const llvm::opt::ArgList &Args); - -private: - bool IsMathErrnoDefault() const override; - bool IsObjCNonFragileABIDefault() const override; - bool UseObjCMixedDispatch() const override; - bool isPICDefault() const override; - bool isPIEDefault() const override; - 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, - llvm::opt::ArgStringList &CC1Args) const override; - RuntimeLibType GetDefaultRuntimeLibType() const override; - CXXStdlibType GetCXXStdlibType(const llvm::opt::ArgList &Args) const override; - void AddClangSystemIncludeArgs( - const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args) const override; - void AddClangCXXStdlibIncludeArgs( - const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args) const override; - - const char *getDefaultLinker() const override { - return "lld"; - } - - Tool *buildLinker() const override; -}; - -class LLVM_LIBRARY_VISIBILITY PS4CPU : public Generic_ELF { -public: - PS4CPU(const Driver &D, const llvm::Triple &Triple, - const llvm::opt::ArgList &Args); - - // No support for finding a C++ standard library yet. - std::string findLibCxxIncludePath() const override { return ""; } - void addLibStdCxxIncludePaths( - const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args) const override {} - - bool IsMathErrnoDefault() const override { return false; } - bool IsObjCNonFragileABIDefault() const override { return true; } - bool HasNativeLLVMSupport() const override; - bool isPICDefault() const override; - - unsigned GetDefaultStackProtectorLevel(bool KernelOrKext) const override { - return 2; // SSPStrong - } - - llvm::DebuggerKind getDefaultDebuggerTuning() const override { - return llvm::DebuggerKind::SCE; - } - - SanitizerMask getSupportedSanitizers() const override; - -protected: - Tool *buildAssembler() const override; - Tool *buildLinker() const override; -}; - -class LLVM_LIBRARY_VISIBILITY Contiki : public Generic_ELF { -public: - Contiki(const Driver &D, const llvm::Triple &Triple, - const llvm::opt::ArgList &Args); - - // No support for finding a C++ standard library yet. - std::string findLibCxxIncludePath() const override { return ""; } - void addLibStdCxxIncludePaths( - const llvm::opt::ArgList &DriverArgs, - llvm::opt::ArgStringList &CC1Args) const override {} - - SanitizerMask getSupportedSanitizers() const override; -}; - -class LLVM_LIBRARY_VISIBILITY AVRToolChain : public Generic_ELF { -protected: - Tool *buildLinker() const override; -public: - AVRToolChain(const Driver &D, const llvm::Triple &Triple, - const llvm::opt::ArgList &Args); -}; - - -} // end namespace toolchains -} // end namespace driver -} // end namespace clang - -#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_H diff --git a/lib/Driver/ToolChains/AMDGPU.cpp b/lib/Driver/ToolChains/AMDGPU.cpp new file mode 100644 index 0000000000..63e1749e00 --- /dev/null +++ b/lib/Driver/ToolChains/AMDGPU.cpp @@ -0,0 +1,45 @@ +//===--- AMDGPU.cpp - AMDGPU 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 "AMDGPU.h" +#include "InputInfo.h" +#include "CommonArgs.h" +#include "clang/Driver/Compilation.h" +#include "llvm/Option/ArgList.h" + +using namespace clang::driver; +using namespace clang::driver::tools; +using namespace clang::driver::toolchains; +using namespace clang; +using namespace llvm::opt; + +void amdgpu::Linker::ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, + const InputInfoList &Inputs, + const ArgList &Args, + const char *LinkingOutput) const { + + std::string Linker = getToolChain().GetProgramPath(getShortName()); + ArgStringList CmdArgs; + AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA); + CmdArgs.push_back("-shared"); + CmdArgs.push_back("-o"); + CmdArgs.push_back(Output.getFilename()); + C.addCommand(llvm::make_unique<Command>(JA, *this, Args.MakeArgString(Linker), + CmdArgs, Inputs)); +} + +/// AMDGPU Toolchain +AMDGPUToolChain::AMDGPUToolChain(const Driver &D, const llvm::Triple &Triple, + const ArgList &Args) + : Generic_ELF(D, Triple, Args) { } + +Tool *AMDGPUToolChain::buildLinker() const { + return new tools::amdgpu::Linker(*this); +} diff --git a/lib/Driver/ToolChains/AMDGPU.h b/lib/Driver/ToolChains/AMDGPU.h new file mode 100644 index 0000000000..9af1e96489 --- /dev/null +++ b/lib/Driver/ToolChains/AMDGPU.h @@ -0,0 +1,54 @@ +//===--- AMDGPU.h - AMDGPU 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_AMDGPU_H +#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_AMDGPU_H + +#include "Gnu.h" +#include "clang/Driver/Tool.h" +#include "clang/Driver/ToolChain.h" + +namespace clang { +namespace driver { +namespace tools { + +namespace amdgpu { + +class LLVM_LIBRARY_VISIBILITY Linker : public GnuTool { +public: + Linker(const ToolChain &TC) : GnuTool("amdgpu::Linker", "ld.lld", TC) {} + bool isLinkJob() const override { return true; } + 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 amdgpu +} // end namespace tools + +namespace toolchains { + +class LLVM_LIBRARY_VISIBILITY AMDGPUToolChain : public Generic_ELF { +protected: + Tool *buildLinker() const override; + +public: + AMDGPUToolChain(const Driver &D, const llvm::Triple &Triple, + const llvm::opt::ArgList &Args); + unsigned GetDefaultDwarfVersion() const override { return 2; } + bool IsIntegratedAssemblerDefault() const override { return true; } +}; + +} // end namespace toolchains +} // end namespace driver +} // end namespace clang + +#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_AMDGPU_H diff --git a/lib/Driver/ToolChains/AVR.cpp b/lib/Driver/ToolChains/AVR.cpp new file mode 100644 index 0000000000..877009af8a --- /dev/null +++ b/lib/Driver/ToolChains/AVR.cpp @@ -0,0 +1,44 @@ +//===--- AVR.cpp - AVR 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 "AVR.h" +#include "CommonArgs.h" +#include "InputInfo.h" +#include "clang/Driver/Compilation.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; + +/// AVR Toolchain +AVRToolChain::AVRToolChain(const Driver &D, const llvm::Triple &Triple, + const ArgList &Args) + : Generic_ELF(D, Triple, Args) { } +Tool *AVRToolChain::buildLinker() const { + return new tools::AVR::Linker(*this); +} + +void AVR::Linker::ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, + const InputInfoList &Inputs, + const ArgList &Args, + const char *LinkingOutput) const { + + std::string Linker = getToolChain().GetProgramPath(getShortName()); + ArgStringList CmdArgs; + AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA); + CmdArgs.push_back("-o"); + CmdArgs.push_back(Output.getFilename()); + C.addCommand(llvm::make_unique<Command>(JA, *this, Args.MakeArgString(Linker), + CmdArgs, Inputs)); +} +// AVR tools end. diff --git a/lib/Driver/ToolChains/AVR.h b/lib/Driver/ToolChains/AVR.h new file mode 100644 index 0000000000..a7479a7f56 --- /dev/null +++ b/lib/Driver/ToolChains/AVR.h @@ -0,0 +1,49 @@ +//===--- AVR.h - AVR Tool and ToolChain Implementations ---------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_AVR_H +#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_AVR_H + +#include "Gnu.h" +#include "InputInfo.h" +#include "clang/Driver/ToolChain.h" +#include "clang/Driver/Tool.h" + +namespace clang { +namespace driver { +namespace toolchains { + +class LLVM_LIBRARY_VISIBILITY AVRToolChain : public Generic_ELF { +protected: + Tool *buildLinker() const override; +public: + AVRToolChain(const Driver &D, const llvm::Triple &Triple, + const llvm::opt::ArgList &Args); +}; + +} // end namespace toolchains + +namespace tools { +namespace AVR { +class LLVM_LIBRARY_VISIBILITY Linker : public GnuTool { +public: + Linker(const ToolChain &TC) : GnuTool("AVR::Linker", "avr-ld", 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 AVR +} // end namespace tools +} // end namespace driver +} // end namespace clang + +#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_AVR_H diff --git a/lib/Driver/Arch/AArch64.cpp b/lib/Driver/ToolChains/Arch/AArch64.cpp index b2e6ca48d9..7dc2f57d82 100644 --- a/lib/Driver/Arch/AArch64.cpp +++ b/lib/Driver/ToolChains/Arch/AArch64.cpp @@ -7,7 +7,7 @@ // //===----------------------------------------------------------------------===// -#include "Tools.h" +#include "AArch64.h" #include "clang/Driver/Driver.h" #include "clang/Driver/DriverDiagnostic.h" #include "clang/Driver/Options.h" diff --git a/lib/Driver/ToolChains/Arch/AArch64.h b/lib/Driver/ToolChains/Arch/AArch64.h new file mode 100644 index 0000000000..62e419cc19 --- /dev/null +++ b/lib/Driver/ToolChains/Arch/AArch64.h @@ -0,0 +1,35 @@ +//===--- AArch64.h - AArch64-specific (not ARM) Tool Helpers ----*- 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_ARCH_AARCH64_H +#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_ARCH_AARCH64_H + +#include "clang/Driver/Driver.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Option/Option.h" +#include <string> +#include <vector> + +namespace clang { +namespace driver { +namespace tools { +namespace aarch64 { + +void getAArch64TargetFeatures(const Driver &D, const llvm::opt::ArgList &Args, + std::vector<llvm::StringRef> &Features); + +std::string getAArch64TargetCPU(const llvm::opt::ArgList &Args, + llvm::opt::Arg *&A); + +} // end namespace aarch64 +} // end namespace target +} // end namespace driver +} // end namespace clang + +#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_ARCH_AARCH64_H diff --git a/lib/Driver/Arch/ARM.cpp b/lib/Driver/ToolChains/Arch/ARM.cpp index d7d58c1f69..15f224bb22 100644 --- a/lib/Driver/Arch/ARM.cpp +++ b/lib/Driver/ToolChains/Arch/ARM.cpp @@ -7,7 +7,7 @@ // //===----------------------------------------------------------------------===// -#include "Tools.h" +#include "ARM.h" #include "clang/Driver/Driver.h" #include "clang/Driver/DriverDiagnostic.h" #include "clang/Driver/Options.h" @@ -450,3 +450,95 @@ void arm::getARMTargetFeatures(const ToolChain &TC, if (KernelOrKext || Args.hasArg(options::OPT_mno_movt)) Features.push_back("+no-movt"); } + +const std::string arm::getARMArch(StringRef Arch, const llvm::Triple &Triple) { + std::string MArch; + if (!Arch.empty()) + MArch = Arch; + else + MArch = Triple.getArchName(); + MArch = StringRef(MArch).split("+").first.lower(); + + // Handle -march=native. + if (MArch == "native") { + std::string CPU = llvm::sys::getHostCPUName(); + if (CPU != "generic") { + // Translate the native cpu into the architecture suffix for that CPU. + StringRef Suffix = arm::getLLVMArchSuffixForARM(CPU, MArch, Triple); + // If there is no valid architecture suffix for this CPU we don't know how + // to handle it, so return no architecture. + if (Suffix.empty()) + MArch = ""; + else + MArch = std::string("arm") + Suffix.str(); + } + } + + return MArch; +} + +/// Get the (LLVM) name of the minimum ARM CPU for the arch we are targeting. +StringRef arm::getARMCPUForMArch(StringRef Arch, const llvm::Triple &Triple) { + std::string MArch = getARMArch(Arch, Triple); + // getARMCPUForArch defaults to the triple if MArch is empty, but empty MArch + // here means an -march=native that we can't handle, so instead return no CPU. + if (MArch.empty()) + return StringRef(); + + // We need to return an empty string here on invalid MArch values as the + // various places that call this function can't cope with a null result. + return Triple.getARMCPUForArch(MArch); +} + +/// getARMTargetCPU - Get the (LLVM) name of the ARM cpu we are targeting. +std::string arm::getARMTargetCPU(StringRef CPU, StringRef Arch, + const llvm::Triple &Triple) { + // FIXME: Warn on inconsistent use of -mcpu and -march. + // If we have -mcpu=, use that. + if (!CPU.empty()) { + std::string MCPU = StringRef(CPU).split("+").first.lower(); + // Handle -mcpu=native. + if (MCPU == "native") + return llvm::sys::getHostCPUName(); + else + return MCPU; + } + + return getARMCPUForMArch(Arch, Triple); +} + +/// getLLVMArchSuffixForARM - Get the LLVM arch name to use for a particular +/// CPU (or Arch, if CPU is generic). +// FIXME: This is redundant with -mcpu, why does LLVM use this. +StringRef arm::getLLVMArchSuffixForARM(StringRef CPU, StringRef Arch, + const llvm::Triple &Triple) { + unsigned ArchKind; + if (CPU == "generic") { + std::string ARMArch = tools::arm::getARMArch(Arch, Triple); + ArchKind = llvm::ARM::parseArch(ARMArch); + if (ArchKind == llvm::ARM::AK_INVALID) + // In case of generic Arch, i.e. "arm", + // extract arch from default cpu of the Triple + ArchKind = llvm::ARM::parseCPUArch(Triple.getARMCPUForArch(ARMArch)); + } else { + // 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::parseCPUArch(CPU); + } + if (ArchKind == llvm::ARM::AK_INVALID) + return ""; + return llvm::ARM::getSubArch(ArchKind); +} + +void arm::appendEBLinkFlags(const ArgList &Args, ArgStringList &CmdArgs, + const llvm::Triple &Triple) { + if (Args.hasArg(options::OPT_r)) + return; + + // ARMv7 (and later) and ARMv6-M do not support BE-32, so instruct the linker + // to generate BE-8 executables. + if (arm::getARMSubArchVersionNumber(Triple) >= 7 || arm::isARMMProfile(Triple)) + CmdArgs.push_back("--be8"); +} diff --git a/lib/Driver/ToolChains/Arch/ARM.h b/lib/Driver/ToolChains/Arch/ARM.h new file mode 100644 index 0000000000..5601799127 --- /dev/null +++ b/lib/Driver/ToolChains/Arch/ARM.h @@ -0,0 +1,60 @@ +//===--- ARM.h - ARM-specific (not AArch64) Tool Helpers --------*- 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_ARCH_ARM_H +#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_ARCH_ARM_H + +#include "clang/Driver/ToolChain.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/Triple.h" +#include "llvm/Option/Option.h" +#include <string> +#include <vector> + +namespace clang { +namespace driver { +namespace tools { +namespace arm { + +std::string getARMTargetCPU(StringRef CPU, llvm::StringRef Arch, + const llvm::Triple &Triple); +const std::string getARMArch(llvm::StringRef Arch, const llvm::Triple &Triple); +StringRef getARMCPUForMArch(llvm::StringRef Arch, const llvm::Triple &Triple); +StringRef getLLVMArchSuffixForARM(llvm::StringRef CPU, llvm::StringRef Arch, + const llvm::Triple &Triple); + +void appendEBLinkFlags(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs, + const llvm::Triple &Triple); +enum class FloatABI { + Invalid, + Soft, + SoftFP, + Hard, +}; + +FloatABI getARMFloatABI(const ToolChain &TC, const llvm::opt::ArgList &Args); + +bool useAAPCSForMachO(const llvm::Triple &T); +void getARMArchCPUFromArgs(const llvm::opt::ArgList &Args, + llvm::StringRef &Arch, llvm::StringRef &CPU, + bool FromAs = false); +void getARMTargetFeatures(const ToolChain &TC, const llvm::Triple &Triple, + const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs, + std::vector<llvm::StringRef> &Features, bool ForAS); +int getARMSubArchVersionNumber(const llvm::Triple &Triple); +bool isARMMProfile(const llvm::Triple &Triple); + +} // end namespace arm +} // end namespace target +} // end namespace driver +} // end namespace clang + +#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_ARCH_ARM_H diff --git a/lib/Driver/Arch/Mips.cpp b/lib/Driver/ToolChains/Arch/Mips.cpp index 5f8296e9eb..cd791af832 100644 --- a/lib/Driver/Arch/Mips.cpp +++ b/lib/Driver/ToolChains/Arch/Mips.cpp @@ -7,7 +7,8 @@ // //===----------------------------------------------------------------------===// -#include "Tools.h" +#include "Mips.h" +#include "ToolChains/CommonArgs.h" #include "clang/Driver/Driver.h" #include "clang/Driver/DriverDiagnostic.h" #include "clang/Driver/Options.h" @@ -19,6 +20,11 @@ using namespace clang::driver::tools; using namespace clang; using namespace llvm::opt; +bool tools::isMipsArch(llvm::Triple::ArchType Arch) { + return Arch == llvm::Triple::mips || Arch == llvm::Triple::mipsel || + Arch == llvm::Triple::mips64 || Arch == llvm::Triple::mips64el; +} + // Get CPU and ABI names. They are not independent // so we have to calculate them together. void mips::getMipsCPUAndABI(const ArgList &Args, const llvm::Triple &Triple, diff --git a/lib/Driver/ToolChains/Arch/Mips.h b/lib/Driver/ToolChains/Arch/Mips.h new file mode 100644 index 0000000000..0b78866094 --- /dev/null +++ b/lib/Driver/ToolChains/Arch/Mips.h @@ -0,0 +1,62 @@ +//===--- Mips.h - Mips-specific Tool Helpers ----------------------*- 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_ARCH_MIPS_H +#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_ARCH_MIPS_H + +#include "clang/Driver/Driver.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/Triple.h" +#include "llvm/Option/Option.h" +#include <string> +#include <vector> + +namespace clang { +namespace driver { +namespace tools { + +bool isMipsArch(llvm::Triple::ArchType Arch); + +namespace mips { +typedef enum { NanLegacy = 1, Nan2008 = 2 } NanEncoding; + +enum class FloatABI { + Invalid, + Soft, + Hard, +}; + +NanEncoding getSupportedNanEncoding(StringRef &CPU); +bool hasCompactBranches(StringRef &CPU); +void getMipsCPUAndABI(const llvm::opt::ArgList &Args, + const llvm::Triple &Triple, StringRef &CPUName, + StringRef &ABIName); +void getMIPSTargetFeatures(const Driver &D, const llvm::Triple &Triple, + const llvm::opt::ArgList &Args, + std::vector<StringRef> &Features); +StringRef getGnuCompatibleMipsABIName(StringRef ABI); +mips::FloatABI getMipsFloatABI(const Driver &D, const llvm::opt::ArgList &Args); +std::string getMipsABILibSuffix(const llvm::opt::ArgList &Args, + const llvm::Triple &Triple); +bool hasMipsAbiArg(const llvm::opt::ArgList &Args, const char *Value); +bool isUCLibc(const llvm::opt::ArgList &Args); +bool isNaN2008(const llvm::opt::ArgList &Args, const llvm::Triple &Triple); +bool isFP64ADefault(const llvm::Triple &Triple, StringRef CPUName); +bool isFPXXDefault(const llvm::Triple &Triple, StringRef CPUName, + StringRef ABIName, mips::FloatABI FloatABI); +bool shouldUseFPXX(const llvm::opt::ArgList &Args, const llvm::Triple &Triple, + StringRef CPUName, StringRef ABIName, + mips::FloatABI FloatABI); + +} // end namespace mips +} // end namespace target +} // end namespace driver +} // end namespace clang + +#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_ARCH_MIPS_H diff --git a/lib/Driver/Arch/PPC.cpp b/lib/Driver/ToolChains/Arch/PPC.cpp index 31417a2505..e83b4fe7f9 100644 --- a/lib/Driver/Arch/PPC.cpp +++ b/lib/Driver/ToolChains/Arch/PPC.cpp @@ -7,7 +7,8 @@ // //===----------------------------------------------------------------------===// -#include "Tools.h" +#include "PPC.h" +#include "ToolChains/CommonArgs.h" #include "clang/Driver/Driver.h" #include "clang/Driver/DriverDiagnostic.h" #include "clang/Driver/Options.h" diff --git a/lib/Driver/ToolChains/Arch/PPC.h b/lib/Driver/ToolChains/Arch/PPC.h new file mode 100644 index 0000000000..892eb2c341 --- /dev/null +++ b/lib/Driver/ToolChains/Arch/PPC.h @@ -0,0 +1,45 @@ +//===--- PPC.h - PPC-specific Tool Helpers ----------------------*- 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_ARCH_PPC_H +#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_ARCH_PPC_H + +#include "clang/Driver/Driver.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Option/Option.h" +#include <string> +#include <vector> + +namespace clang { +namespace driver { +namespace tools { +namespace ppc { + +bool hasPPCAbiArg(const llvm::opt::ArgList &Args, const char *Value); + +enum class FloatABI { + Invalid, + Soft, + Hard, +}; + +FloatABI getPPCFloatABI(const Driver &D, const llvm::opt::ArgList &Args); + +std::string getPPCTargetCPU(const llvm::opt::ArgList &Args); + +void getPPCTargetFeatures(const Driver &D, const llvm::Triple &Triple, + const llvm::opt::ArgList &Args, + std::vector<llvm::StringRef> &Features); + +} // end namespace ppc +} // end namespace target +} // end namespace driver +} // end namespace clang + +#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_ARCH_PPC_H diff --git a/lib/Driver/Arch/Sparc.cpp b/lib/Driver/ToolChains/Arch/Sparc.cpp index 07d2725076..594ec9986d 100644 --- a/lib/Driver/Arch/Sparc.cpp +++ b/lib/Driver/ToolChains/Arch/Sparc.cpp @@ -7,7 +7,7 @@ // //===----------------------------------------------------------------------===// -#include "Tools.h" +#include "Sparc.h" #include "clang/Driver/Driver.h" #include "clang/Driver/DriverDiagnostic.h" #include "clang/Driver/Options.h" diff --git a/lib/Driver/ToolChains/Arch/Sparc.h b/lib/Driver/ToolChains/Arch/Sparc.h new file mode 100644 index 0000000000..082b2808a9 --- /dev/null +++ b/lib/Driver/ToolChains/Arch/Sparc.h @@ -0,0 +1,42 @@ +//===--- Sparc.h - Sparc-specific Tool Helpers ----------------------*- 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_ARCH_SPARC_H +#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_ARCH_SPARC_H + +#include "clang/Driver/Driver.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Option/Option.h" +#include <string> +#include <vector> + +namespace clang { +namespace driver { +namespace tools { +namespace sparc { + +enum class FloatABI { + Invalid, + Soft, + Hard, +}; + +FloatABI getSparcFloatABI(const Driver &D, const llvm::opt::ArgList &Args); + +void getSparcTargetFeatures(const Driver &D, const llvm::opt::ArgList &Args, + std::vector<llvm::StringRef> &Features); +const char *getSparcAsmModeForCPU(llvm::StringRef Name, + const llvm::Triple &Triple); + +} // end namespace sparc +} // end namespace target +} // end namespace driver +} // end namespace clang + +#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_ARCH_SPARC_H diff --git a/lib/Driver/Arch/SystemZ.cpp b/lib/Driver/ToolChains/Arch/SystemZ.cpp index d9c4577581..6ee724d008 100644 --- a/lib/Driver/Arch/SystemZ.cpp +++ b/lib/Driver/ToolChains/Arch/SystemZ.cpp @@ -7,7 +7,7 @@ // //===----------------------------------------------------------------------===// -#include "Tools.h" +#include "SystemZ.h" #include "clang/Driver/Options.h" #include "llvm/Option/ArgList.h" @@ -23,7 +23,7 @@ const char *systemz::getSystemZTargetCPU(const ArgList &Args) { } void systemz::getSystemZTargetFeatures(const ArgList &Args, - std::vector<StringRef> &Features) { + std::vector<llvm::StringRef> &Features) { // -m(no-)htm overrides use of the transactional-execution facility. if (Arg *A = Args.getLastArg(options::OPT_mhtm, options::OPT_mno_htm)) { if (A->getOption().matches(options::OPT_mhtm)) diff --git a/lib/Driver/ToolChains/Arch/SystemZ.h b/lib/Driver/ToolChains/Arch/SystemZ.h new file mode 100644 index 0000000000..521f8c2aad --- /dev/null +++ b/lib/Driver/ToolChains/Arch/SystemZ.h @@ -0,0 +1,32 @@ +//===--- SystemZ.h - SystemZ-specific Tool Helpers --------------*- 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_ARCH_SYSTEMZ_H +#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_ARCH_SYSTEMZ_H + +#include "llvm/ADT/StringRef.h" +#include "llvm/Option/Option.h" +#include <vector> + +namespace clang { +namespace driver { +namespace tools { +namespace systemz { + +const char *getSystemZTargetCPU(const llvm::opt::ArgList &Args); + +void getSystemZTargetFeatures(const llvm::opt::ArgList &Args, + std::vector<llvm::StringRef> &Features); + +} // end namespace systemz +} // end namespace target +} // end namespace driver +} // end namespace clang + +#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_ARCH_SYSTEMZ_H diff --git a/lib/Driver/Arch/X86.cpp b/lib/Driver/ToolChains/Arch/X86.cpp index 7254ffbe85..fde4476c6b 100644 --- a/lib/Driver/Arch/X86.cpp +++ b/lib/Driver/ToolChains/Arch/X86.cpp @@ -7,7 +7,8 @@ // //===----------------------------------------------------------------------===// -#include "Tools.h" +#include "X86.h" +#include "ToolChains/CommonArgs.h" #include "clang/Driver/Driver.h" #include "clang/Driver/DriverDiagnostic.h" #include "clang/Driver/Options.h" diff --git a/lib/Driver/ToolChains/Arch/X86.h b/lib/Driver/ToolChains/Arch/X86.h new file mode 100644 index 0000000000..20bf27a2b6 --- /dev/null +++ b/lib/Driver/ToolChains/Arch/X86.h @@ -0,0 +1,37 @@ +//===--- X86.h - X86-specific Tool Helpers ----------------------*- 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_ARCH_X86_H +#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_ARCH_X86_H + +#include "clang/Driver/Driver.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/ADT/Triple.h" +#include "llvm/Option/Option.h" +#include <string> +#include <vector> + +namespace clang { +namespace driver { +namespace tools { +namespace x86 { + +const char *getX86TargetCPU(const llvm::opt::ArgList &Args, + const llvm::Triple &Triple); + +void getX86TargetFeatures(const Driver &D, const llvm::Triple &Triple, + const llvm::opt::ArgList &Args, + std::vector<llvm::StringRef> &Features); + +} // end namespace x86 +} // end namespace target +} // end namespace driver +} // end namespace clang + +#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_ARCH_X86_H diff --git a/lib/Driver/ToolChains/Bitrig.cpp b/lib/Driver/ToolChains/Bitrig.cpp new file mode 100644 index 0000000000..d8f541dfba --- /dev/null +++ b/lib/Driver/ToolChains/Bitrig.cpp @@ -0,0 +1,190 @@ +//===--- 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 new file mode 100644 index 0000000000..6edb2e8c7e --- /dev/null +++ b/lib/Driver/ToolChains/Bitrig.h @@ -0,0 +1,79 @@ +//===--- 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 new file mode 100644 index 0000000000..fcb8c3ede1 --- /dev/null +++ b/lib/Driver/ToolChains/Clang.cpp @@ -0,0 +1,5172 @@ +//===--- LLVM.cpp - Clang+LLVM 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 "Clang.h" +#include "Arch/AArch64.h" +#include "Arch/ARM.h" +#include "Arch/Mips.h" +#include "Arch/PPC.h" +#include "Arch/Sparc.h" +#include "Arch/SystemZ.h" +#include "Arch/X86.h" +#include "CommonArgs.h" +#include "Hexagon.h" +#include "InputInfo.h" +#include "PS4CPU.h" +#include "clang/Basic/CharInfo.h" +#include "clang/Basic/LangOptions.h" +#include "clang/Basic/ObjCRuntime.h" +#include "clang/Basic/Version.h" +#include "clang/Config/config.h" +#include "clang/Driver/DriverDiagnostic.h" +#include "clang/Driver/Options.h" +#include "clang/Driver/SanitizerArgs.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/Option/ArgList.h" +#include "llvm/Support/CodeGen.h" +#include "llvm/Support/Compression.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/Process.h" +#include "llvm/Support/YAMLParser.h" + +#ifdef LLVM_ON_UNIX +#include <unistd.h> // For getuid(). +#endif + +using namespace clang::driver; +using namespace clang::driver::tools; +using namespace clang; +using namespace llvm::opt; + +static void CheckPreprocessingOptions(const Driver &D, const ArgList &Args) { + if (Arg *A = + Args.getLastArg(clang::driver::options::OPT_C, options::OPT_CC)) { + if (!Args.hasArg(options::OPT_E) && !Args.hasArg(options::OPT__SLASH_P) && + !Args.hasArg(options::OPT__SLASH_EP) && !D.CCCIsCPP()) { + D.Diag(clang::diag::err_drv_argument_only_allowed_with) + << A->getBaseArg().getAsString(Args) + << (D.IsCLMode() ? "/E, /P or /EP" : "-E"); + } + } +} + +static void CheckCodeGenerationOptions(const Driver &D, const ArgList &Args) { + // In gcc, only ARM checks this, but it seems reasonable to check universally. + if (Args.hasArg(options::OPT_static)) + if (const Arg *A = + Args.getLastArg(options::OPT_dynamic, options::OPT_mdynamic_no_pic)) + D.Diag(diag::err_drv_argument_not_allowed_with) << A->getAsString(Args) + << "-static"; +} + +// Add backslashes to escape spaces and other backslashes. +// This is used for the space-separated argument list specified with +// the -dwarf-debug-flags option. +static void EscapeSpacesAndBackslashes(const char *Arg, + SmallVectorImpl<char> &Res) { + for (; *Arg; ++Arg) { + switch (*Arg) { + default: + break; + case ' ': + case '\\': + Res.push_back('\\'); + break; + } + Res.push_back(*Arg); + } +} + +// Quote target names for inclusion in GNU Make dependency files. +// Only the characters '$', '#', ' ', '\t' are quoted. +static void QuoteTarget(StringRef Target, SmallVectorImpl<char> &Res) { + for (unsigned i = 0, e = Target.size(); i != e; ++i) { + switch (Target[i]) { + case ' ': + case '\t': + // Escape the preceding backslashes + for (int j = i - 1; j >= 0 && Target[j] == '\\'; --j) + Res.push_back('\\'); + + // Escape the space/tab + Res.push_back('\\'); + break; + case '$': + Res.push_back('$'); + break; + case '#': + Res.push_back('\\'); + break; + default: + break; + } + + Res.push_back(Target[i]); + } +} + +/// Apply \a Work on the current tool chain \a RegularToolChain and any other +/// offloading tool chain that is associated with the current action \a JA. +static void +forAllAssociatedToolChains(Compilation &C, const JobAction &JA, + const ToolChain &RegularToolChain, + llvm::function_ref<void(const ToolChain &)> Work) { + // Apply Work on the current/regular tool chain. + Work(RegularToolChain); + + // Apply Work on all the offloading tool chains associated with the current + // action. + if (JA.isHostOffloading(Action::OFK_Cuda)) + Work(*C.getSingleOffloadToolChain<Action::OFK_Cuda>()); + else if (JA.isDeviceOffloading(Action::OFK_Cuda)) + Work(*C.getSingleOffloadToolChain<Action::OFK_Host>()); + + // + // TODO: Add support for other offloading programming models here. + // +} + +/// This is a helper function for validating the optional refinement step +/// parameter in reciprocal argument strings. Return false if there is an error +/// parsing the refinement step. Otherwise, return true and set the Position +/// of the refinement step in the input string. +static bool getRefinementStep(StringRef In, const Driver &D, + const Arg &A, size_t &Position) { + const char RefinementStepToken = ':'; + Position = In.find(RefinementStepToken); + if (Position != StringRef::npos) { + StringRef Option = A.getOption().getName(); + StringRef RefStep = In.substr(Position + 1); + // Allow exactly one numeric character for the additional refinement + // step parameter. This is reasonable for all currently-supported + // operations and architectures because we would expect that a larger value + // of refinement steps would cause the estimate "optimization" to + // under-perform the native operation. Also, if the estimate does not + // converge quickly, it probably will not ever converge, so further + // refinement steps will not produce a better answer. + if (RefStep.size() != 1) { + D.Diag(diag::err_drv_invalid_value) << Option << RefStep; + return false; + } + char RefStepChar = RefStep[0]; + if (RefStepChar < '0' || RefStepChar > '9') { + D.Diag(diag::err_drv_invalid_value) << Option << RefStep; + return false; + } + } + return true; +} + +/// The -mrecip flag requires processing of many optional parameters. +static void ParseMRecip(const Driver &D, const ArgList &Args, + ArgStringList &OutStrings) { + StringRef DisabledPrefixIn = "!"; + StringRef DisabledPrefixOut = "!"; + StringRef EnabledPrefixOut = ""; + StringRef Out = "-mrecip="; + + Arg *A = Args.getLastArg(options::OPT_mrecip, options::OPT_mrecip_EQ); + if (!A) + return; + + unsigned NumOptions = A->getNumValues(); + if (NumOptions == 0) { + // No option is the same as "all". + OutStrings.push_back(Args.MakeArgString(Out + "all")); + return; + } + + // Pass through "all", "none", or "default" with an optional refinement step. + if (NumOptions == 1) { + StringRef Val = A->getValue(0); + size_t RefStepLoc; + if (!getRefinementStep(Val, D, *A, RefStepLoc)) + return; + StringRef ValBase = Val.slice(0, RefStepLoc); + if (ValBase == "all" || ValBase == "none" || ValBase == "default") { + OutStrings.push_back(Args.MakeArgString(Out + Val)); + return; + } + } + + // Each reciprocal type may be enabled or disabled individually. + // Check each input value for validity, concatenate them all back together, + // and pass through. + + llvm::StringMap<bool> OptionStrings; + OptionStrings.insert(std::make_pair("divd", false)); + OptionStrings.insert(std::make_pair("divf", false)); + OptionStrings.insert(std::make_pair("vec-divd", false)); + OptionStrings.insert(std::make_pair("vec-divf", false)); + OptionStrings.insert(std::make_pair("sqrtd", false)); + OptionStrings.insert(std::make_pair("sqrtf", false)); + OptionStrings.insert(std::make_pair("vec-sqrtd", false)); + OptionStrings.insert(std::make_pair("vec-sqrtf", false)); + + for (unsigned i = 0; i != NumOptions; ++i) { + StringRef Val = A->getValue(i); + + bool IsDisabled = Val.startswith(DisabledPrefixIn); + // Ignore the disablement token for string matching. + if (IsDisabled) + Val = Val.substr(1); + + size_t RefStep; + if (!getRefinementStep(Val, D, *A, RefStep)) + return; + + StringRef ValBase = Val.slice(0, RefStep); + llvm::StringMap<bool>::iterator OptionIter = OptionStrings.find(ValBase); + if (OptionIter == OptionStrings.end()) { + // Try again specifying float suffix. + OptionIter = OptionStrings.find(ValBase.str() + 'f'); + if (OptionIter == OptionStrings.end()) { + // The input name did not match any known option string. + D.Diag(diag::err_drv_unknown_argument) << Val; + return; + } + // The option was specified without a float or double suffix. + // Make sure that the double entry was not already specified. + // The float entry will be checked below. + if (OptionStrings[ValBase.str() + 'd']) { + D.Diag(diag::err_drv_invalid_value) << A->getOption().getName() << Val; + return; + } + } + + if (OptionIter->second == true) { + // Duplicate option specified. + D.Diag(diag::err_drv_invalid_value) << A->getOption().getName() << Val; + return; + } + + // Mark the matched option as found. Do not allow duplicate specifiers. + OptionIter->second = true; + + // If the precision was not specified, also mark the double entry as found. + if (ValBase.back() != 'f' && ValBase.back() != 'd') + OptionStrings[ValBase.str() + 'd'] = true; + + // Build the output string. + StringRef Prefix = IsDisabled ? DisabledPrefixOut : EnabledPrefixOut; + Out = Args.MakeArgString(Out + Prefix + Val); + if (i != NumOptions - 1) + Out = Args.MakeArgString(Out + ","); + } + + 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); + + 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"); +} + +static void getWebAssemblyTargetFeatures(const ArgList &Args, + std::vector<StringRef> &Features) { + 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) { + const Driver &D = TC.getDriver(); + std::vector<StringRef> Features; + switch (Triple.getArch()) { + default: + break; + case llvm::Triple::mips: + case llvm::Triple::mipsel: + case llvm::Triple::mips64: + case llvm::Triple::mips64el: + mips::getMIPSTargetFeatures(D, Triple, Args, Features); + break; + + case llvm::Triple::arm: + case llvm::Triple::armeb: + case llvm::Triple::thumb: + case llvm::Triple::thumbeb: + arm::getARMTargetFeatures(TC, Triple, Args, CmdArgs, Features, ForAS); + break; + + case llvm::Triple::ppc: + case llvm::Triple::ppc64: + case llvm::Triple::ppc64le: + ppc::getPPCTargetFeatures(D, Triple, Args, Features); + break; + case llvm::Triple::systemz: + systemz::getSystemZTargetFeatures(Args, Features); + break; + case llvm::Triple::aarch64: + case llvm::Triple::aarch64_be: + aarch64::getAArch64TargetFeatures(D, Args, Features); + break; + case llvm::Triple::x86: + case llvm::Triple::x86_64: + x86::getX86TargetFeatures(D, Triple, Args, Features); + break; + case llvm::Triple::hexagon: + getHexagonTargetFeatures(Args, Features); + break; + case llvm::Triple::wasm32: + case llvm::Triple::wasm64: + getWebAssemblyTargetFeatures(Args, Features); + break; + case llvm::Triple::sparc: + case llvm::Triple::sparcel: + case llvm::Triple::sparcv9: + sparc::getSparcTargetFeatures(D, Args, Features); + break; + case llvm::Triple::r600: + case llvm::Triple::amdgcn: + getAMDGPUTargetFeatures(D, Args, Features); + break; + } + + // Find the last of each feature. + llvm::StringMap<unsigned> LastOpt; + for (unsigned I = 0, N = Features.size(); I < N; ++I) { + StringRef Name = Features[I]; + assert(Name[0] == '-' || Name[0] == '+'); + LastOpt[Name.drop_front(1)] = I; + } + + for (unsigned I = 0, N = Features.size(); I < N; ++I) { + // If this feature was overridden, ignore it. + StringRef Name = Features[I]; + llvm::StringMap<unsigned>::iterator LastI = LastOpt.find(Name.drop_front(1)); + assert(LastI != LastOpt.end()); + unsigned Last = LastI->second; + if (Last != I) + continue; + + CmdArgs.push_back("-target-feature"); + CmdArgs.push_back(Name.data()); + } +} + +static bool +shouldUseExceptionTablesForObjCExceptions(const ObjCRuntime &runtime, + const llvm::Triple &Triple) { + // We use the zero-cost exception tables for Objective-C if the non-fragile + // ABI is enabled or when compiling for x86_64 and ARM on Snow Leopard and + // later. + if (runtime.isNonFragile()) + return true; + + if (!Triple.isMacOSX()) + return false; + + return (!Triple.isMacOSXVersionLT(10, 5) && + (Triple.getArch() == llvm::Triple::x86_64 || + Triple.getArch() == llvm::Triple::arm)); +} + +/// Adds exception related arguments to the driver command arguments. There's a +/// master flag, -fexceptions and also language specific flags to enable/disable +/// C++ and Objective-C exceptions. This makes it possible to for example +/// disable C++ exceptions but enable Objective-C exceptions. +static void addExceptionArgs(const ArgList &Args, types::ID InputType, + const ToolChain &TC, bool KernelOrKext, + const ObjCRuntime &objcRuntime, + ArgStringList &CmdArgs) { + const Driver &D = TC.getDriver(); + const llvm::Triple &Triple = TC.getTriple(); + + if (KernelOrKext) { + // -mkernel and -fapple-kext imply no exceptions, so claim exception related + // arguments now to avoid warnings about unused arguments. + Args.ClaimAllArgs(options::OPT_fexceptions); + Args.ClaimAllArgs(options::OPT_fno_exceptions); + Args.ClaimAllArgs(options::OPT_fobjc_exceptions); + Args.ClaimAllArgs(options::OPT_fno_objc_exceptions); + Args.ClaimAllArgs(options::OPT_fcxx_exceptions); + Args.ClaimAllArgs(options::OPT_fno_cxx_exceptions); + return; + } + + // See if the user explicitly enabled exceptions. + bool EH = Args.hasFlag(options::OPT_fexceptions, options::OPT_fno_exceptions, + false); + + // Obj-C exceptions are enabled by default, regardless of -fexceptions. This + // is not necessarily sensible, but follows GCC. + if (types::isObjC(InputType) && + Args.hasFlag(options::OPT_fobjc_exceptions, + options::OPT_fno_objc_exceptions, true)) { + CmdArgs.push_back("-fobjc-exceptions"); + + EH |= shouldUseExceptionTablesForObjCExceptions(objcRuntime, Triple); + } + + if (types::isCXX(InputType)) { + // Disable C++ EH by default on XCore and PS4. + bool CXXExceptionsEnabled = + Triple.getArch() != llvm::Triple::xcore && !Triple.isPS4CPU(); + Arg *ExceptionArg = Args.getLastArg( + options::OPT_fcxx_exceptions, options::OPT_fno_cxx_exceptions, + options::OPT_fexceptions, options::OPT_fno_exceptions); + if (ExceptionArg) + CXXExceptionsEnabled = + ExceptionArg->getOption().matches(options::OPT_fcxx_exceptions) || + ExceptionArg->getOption().matches(options::OPT_fexceptions); + + if (CXXExceptionsEnabled) { + if (Triple.isPS4CPU()) { + ToolChain::RTTIMode RTTIMode = TC.getRTTIMode(); + assert(ExceptionArg && + "On the PS4 exceptions should only be enabled if passing " + "an argument"); + if (RTTIMode == ToolChain::RM_DisabledExplicitly) { + const Arg *RTTIArg = TC.getRTTIArg(); + assert(RTTIArg && "RTTI disabled explicitly but no RTTIArg!"); + D.Diag(diag::err_drv_argument_not_allowed_with) + << RTTIArg->getAsString(Args) << ExceptionArg->getAsString(Args); + } else if (RTTIMode == ToolChain::RM_EnabledImplicitly) + D.Diag(diag::warn_drv_enabling_rtti_with_exceptions); + } else + assert(TC.getRTTIMode() != ToolChain::RM_DisabledImplicitly); + + CmdArgs.push_back("-fcxx-exceptions"); + + EH = true; + } + } + + if (EH) + CmdArgs.push_back("-fexceptions"); +} + +static bool ShouldDisableAutolink(const ArgList &Args, const ToolChain &TC) { + bool Default = true; + if (TC.getTriple().isOSDarwin()) { + // The native darwin assembler doesn't support the linker_option directives, + // so we disable them if we think the .s file will be passed to it. + Default = TC.useIntegratedAs(); + } + return !Args.hasFlag(options::OPT_fautolink, options::OPT_fno_autolink, + Default); +} + +static bool ShouldDisableDwarfDirectory(const ArgList &Args, + const ToolChain &TC) { + bool UseDwarfDirectory = + Args.hasFlag(options::OPT_fdwarf_directory_asm, + options::OPT_fno_dwarf_directory_asm, TC.useIntegratedAs()); + return !UseDwarfDirectory; +} + +// Convert an arg of the form "-gN" or "-ggdbN" or one of their aliases +// to the corresponding DebugInfoKind. +static codegenoptions::DebugInfoKind DebugLevelToInfoKind(const Arg &A) { + assert(A.getOption().matches(options::OPT_gN_Group) && + "Not a -g option that specifies a debug-info level"); + if (A.getOption().matches(options::OPT_g0) || + A.getOption().matches(options::OPT_ggdb0)) + return codegenoptions::NoDebugInfo; + if (A.getOption().matches(options::OPT_gline_tables_only) || + A.getOption().matches(options::OPT_ggdb1)) + return codegenoptions::DebugLineTablesOnly; + return codegenoptions::LimitedDebugInfo; +} + +static bool mustUseNonLeafFramePointerForTarget(const llvm::Triple &Triple) { + switch (Triple.getArch()){ + default: + return false; + case llvm::Triple::arm: + case llvm::Triple::thumb: + // ARM Darwin targets require a frame pointer to be always present to aid + // offline debugging via backtraces. + return Triple.isOSDarwin(); + } +} + +static bool useFramePointerForTargetByDefault(const ArgList &Args, + const llvm::Triple &Triple) { + switch (Triple.getArch()) { + case llvm::Triple::xcore: + case llvm::Triple::wasm32: + case llvm::Triple::wasm64: + // XCore never wants frame pointers, regardless of OS. + // WebAssembly never wants frame pointers. + return false; + default: + break; + } + + if (Triple.isOSLinux() || Triple.getOS() == llvm::Triple::CloudABI) { + switch (Triple.getArch()) { + // Don't use a frame pointer on linux if optimizing for certain targets. + case llvm::Triple::mips64: + case llvm::Triple::mips64el: + case llvm::Triple::mips: + case llvm::Triple::mipsel: + case llvm::Triple::ppc: + case llvm::Triple::ppc64: + case llvm::Triple::ppc64le: + case llvm::Triple::systemz: + case llvm::Triple::x86: + case llvm::Triple::x86_64: + return !areOptimizationsEnabled(Args); + default: + return true; + } + } + + if (Triple.isOSWindows()) { + switch (Triple.getArch()) { + case llvm::Triple::x86: + return !areOptimizationsEnabled(Args); + case llvm::Triple::x86_64: + return Triple.isOSBinFormatMachO(); + case llvm::Triple::arm: + case llvm::Triple::thumb: + // Windows on ARM builds with FPO disabled to aid fast stack walking + return true; + default: + // All other supported Windows ISAs use xdata unwind information, so frame + // pointers are not generally useful. + return false; + } + } + + return true; +} + +static bool shouldUseFramePointer(const ArgList &Args, + const llvm::Triple &Triple) { + if (Arg *A = Args.getLastArg(options::OPT_fno_omit_frame_pointer, + options::OPT_fomit_frame_pointer)) + return A->getOption().matches(options::OPT_fno_omit_frame_pointer) || + mustUseNonLeafFramePointerForTarget(Triple); + + if (Args.hasArg(options::OPT_pg)) + return true; + + return useFramePointerForTargetByDefault(Args, Triple); +} + +static bool shouldUseLeafFramePointer(const ArgList &Args, + const llvm::Triple &Triple) { + if (Arg *A = Args.getLastArg(options::OPT_mno_omit_leaf_frame_pointer, + options::OPT_momit_leaf_frame_pointer)) + return A->getOption().matches(options::OPT_mno_omit_leaf_frame_pointer); + + if (Args.hasArg(options::OPT_pg)) + return true; + + if (Triple.isPS4CPU()) + return false; + + return useFramePointerForTargetByDefault(Args, Triple); +} + +/// Add a CC1 option to specify the debug compilation directory. +static void addDebugCompDirArg(const ArgList &Args, ArgStringList &CmdArgs) { + SmallString<128> cwd; + if (!llvm::sys::fs::current_path(cwd)) { + CmdArgs.push_back("-fdebug-compilation-dir"); + CmdArgs.push_back(Args.MakeArgString(cwd)); + } +} + +/// \brief Vectorize at all optimization levels greater than 1 except for -Oz. +/// For -Oz the loop vectorizer is disable, while the slp vectorizer is enabled. +static bool shouldEnableVectorizerAtOLevel(const ArgList &Args, bool isSlpVec) { + if (Arg *A = Args.getLastArg(options::OPT_O_Group)) { + if (A->getOption().matches(options::OPT_O4) || + A->getOption().matches(options::OPT_Ofast)) + return true; + + if (A->getOption().matches(options::OPT_O0)) + return false; + + assert(A->getOption().matches(options::OPT_O) && "Must have a -O flag"); + + // Vectorize -Os. + StringRef S(A->getValue()); + if (S == "s") + return true; + + // Don't vectorize -Oz, unless it's the slp vectorizer. + if (S == "z") + return isSlpVec; + + unsigned OptLevel = 0; + if (S.getAsInteger(10, OptLevel)) + return false; + + return OptLevel > 1; + } + + return false; +} + +/// Add -x lang to \p CmdArgs for \p Input. +static void addDashXForInput(const ArgList &Args, const InputInfo &Input, + ArgStringList &CmdArgs) { + // When using -verify-pch, we don't want to provide the type + // 'precompiled-header' if it was inferred from the file extension + if (Args.hasArg(options::OPT_verify_pch) && Input.getType() == types::TY_PCH) + return; + + CmdArgs.push_back("-x"); + if (Args.hasArg(options::OPT_rewrite_objc)) + CmdArgs.push_back(types::getTypeName(types::TY_PP_ObjCXX)); + else + CmdArgs.push_back(types::getTypeName(Input.getType())); +} + +static void appendUserToPath(SmallVectorImpl<char> &Result) { +#ifdef LLVM_ON_UNIX + const char *Username = getenv("LOGNAME"); +#else + const char *Username = getenv("USERNAME"); +#endif + if (Username) { + // Validate that LoginName can be used in a path, and get its length. + size_t Len = 0; + for (const char *P = Username; *P; ++P, ++Len) { + if (!clang::isAlphanumeric(*P) && *P != '_') { + Username = nullptr; + break; + } + } + + if (Username && Len > 0) { + Result.append(Username, Username + Len); + return; + } + } + +// Fallback to user id. +#ifdef LLVM_ON_UNIX + std::string UID = llvm::utostr(getuid()); +#else + // FIXME: Windows seems to have an 'SID' that might work. + std::string UID = "9999"; +#endif + Result.append(UID.begin(), UID.end()); +} + +static void addPGOAndCoverageFlags(Compilation &C, const Driver &D, + const InputInfo &Output, const ArgList &Args, + ArgStringList &CmdArgs) { + + auto *PGOGenerateArg = Args.getLastArg(options::OPT_fprofile_generate, + options::OPT_fprofile_generate_EQ, + options::OPT_fno_profile_generate); + if (PGOGenerateArg && + PGOGenerateArg->getOption().matches(options::OPT_fno_profile_generate)) + PGOGenerateArg = nullptr; + + auto *ProfileGenerateArg = Args.getLastArg( + options::OPT_fprofile_instr_generate, + options::OPT_fprofile_instr_generate_EQ, + options::OPT_fno_profile_instr_generate); + if (ProfileGenerateArg && + ProfileGenerateArg->getOption().matches( + options::OPT_fno_profile_instr_generate)) + ProfileGenerateArg = nullptr; + + if (PGOGenerateArg && ProfileGenerateArg) + D.Diag(diag::err_drv_argument_not_allowed_with) + << PGOGenerateArg->getSpelling() << ProfileGenerateArg->getSpelling(); + + auto *ProfileUseArg = getLastProfileUseArg(Args); + + if (PGOGenerateArg && ProfileUseArg) + D.Diag(diag::err_drv_argument_not_allowed_with) + << ProfileUseArg->getSpelling() << PGOGenerateArg->getSpelling(); + + if (ProfileGenerateArg && ProfileUseArg) + D.Diag(diag::err_drv_argument_not_allowed_with) + << ProfileGenerateArg->getSpelling() << ProfileUseArg->getSpelling(); + + if (ProfileGenerateArg) { + if (ProfileGenerateArg->getOption().matches( + options::OPT_fprofile_instr_generate_EQ)) + CmdArgs.push_back(Args.MakeArgString(Twine("-fprofile-instrument-path=") + + ProfileGenerateArg->getValue())); + // The default is to use Clang Instrumentation. + CmdArgs.push_back("-fprofile-instrument=clang"); + } + + if (PGOGenerateArg) { + CmdArgs.push_back("-fprofile-instrument=llvm"); + if (PGOGenerateArg->getOption().matches( + options::OPT_fprofile_generate_EQ)) { + SmallString<128> Path(PGOGenerateArg->getValue()); + llvm::sys::path::append(Path, "default_%m.profraw"); + CmdArgs.push_back( + Args.MakeArgString(Twine("-fprofile-instrument-path=") + Path)); + } + } + + if (ProfileUseArg) { + if (ProfileUseArg->getOption().matches(options::OPT_fprofile_instr_use_EQ)) + CmdArgs.push_back(Args.MakeArgString( + Twine("-fprofile-instrument-use-path=") + ProfileUseArg->getValue())); + else if ((ProfileUseArg->getOption().matches( + options::OPT_fprofile_use_EQ) || + ProfileUseArg->getOption().matches( + options::OPT_fprofile_instr_use))) { + SmallString<128> Path( + ProfileUseArg->getNumValues() == 0 ? "" : ProfileUseArg->getValue()); + if (Path.empty() || llvm::sys::fs::is_directory(Path)) + llvm::sys::path::append(Path, "default.profdata"); + CmdArgs.push_back( + Args.MakeArgString(Twine("-fprofile-instrument-use-path=") + Path)); + } + } + + if (Args.hasArg(options::OPT_ftest_coverage) || + Args.hasArg(options::OPT_coverage)) + CmdArgs.push_back("-femit-coverage-notes"); + if (Args.hasFlag(options::OPT_fprofile_arcs, options::OPT_fno_profile_arcs, + false) || + Args.hasArg(options::OPT_coverage)) + CmdArgs.push_back("-femit-coverage-data"); + + if (Args.hasFlag(options::OPT_fcoverage_mapping, + options::OPT_fno_coverage_mapping, false) && + !ProfileGenerateArg) + D.Diag(clang::diag::err_drv_argument_only_allowed_with) + << "-fcoverage-mapping" + << "-fprofile-instr-generate"; + + if (Args.hasFlag(options::OPT_fcoverage_mapping, + options::OPT_fno_coverage_mapping, false)) + CmdArgs.push_back("-fcoverage-mapping"); + + if (C.getArgs().hasArg(options::OPT_c) || + C.getArgs().hasArg(options::OPT_S)) { + if (Output.isFilename()) { + CmdArgs.push_back("-coverage-notes-file"); + SmallString<128> OutputFilename; + if (Arg *FinalOutput = C.getArgs().getLastArg(options::OPT_o)) + OutputFilename = FinalOutput->getValue(); + else + OutputFilename = llvm::sys::path::filename(Output.getBaseInput()); + SmallString<128> CoverageFilename = OutputFilename; + if (llvm::sys::path::is_relative(CoverageFilename)) { + SmallString<128> Pwd; + if (!llvm::sys::fs::current_path(Pwd)) { + llvm::sys::path::append(Pwd, CoverageFilename); + CoverageFilename.swap(Pwd); + } + } + llvm::sys::path::replace_extension(CoverageFilename, "gcno"); + CmdArgs.push_back(Args.MakeArgString(CoverageFilename)); + + // Leave -fprofile-dir= an unused argument unless .gcda emission is + // enabled. To be polite, with '-fprofile-arcs -fno-profile-arcs' consider + // the flag used. There is no -fno-profile-dir, so the user has no + // targeted way to suppress the warning. + if (Args.hasArg(options::OPT_fprofile_arcs) || + Args.hasArg(options::OPT_coverage)) { + CmdArgs.push_back("-coverage-data-file"); + if (Arg *FProfileDir = Args.getLastArg(options::OPT_fprofile_dir)) { + CoverageFilename = FProfileDir->getValue(); + llvm::sys::path::append(CoverageFilename, OutputFilename); + } + llvm::sys::path::replace_extension(CoverageFilename, "gcda"); + CmdArgs.push_back(Args.MakeArgString(CoverageFilename)); + } + } + } +} + +/// \brief Check whether the given input tree contains any compilation actions. +static bool ContainsCompileAction(const Action *A) { + if (isa<CompileJobAction>(A) || isa<BackendJobAction>(A)) + return true; + + for (const auto &AI : A->inputs()) + if (ContainsCompileAction(AI)) + return true; + + return false; +} + +/// \brief Check if -relax-all should be passed to the internal assembler. +/// This is done by default when compiling non-assembler source with -O0. +static bool UseRelaxAll(Compilation &C, const ArgList &Args) { + bool RelaxDefault = true; + + if (Arg *A = Args.getLastArg(options::OPT_O_Group)) + RelaxDefault = A->getOption().matches(options::OPT_O0); + + if (RelaxDefault) { + RelaxDefault = false; + for (const auto &Act : C.getActions()) { + if (ContainsCompileAction(Act)) { + RelaxDefault = true; + break; + } + } + } + + return Args.hasFlag(options::OPT_mrelax_all, options::OPT_mno_relax_all, + RelaxDefault); +} + +// Extract the integer N from a string spelled "-dwarf-N", returning 0 +// on mismatch. The StringRef input (rather than an Arg) allows +// for use by the "-Xassembler" option parser. +static unsigned DwarfVersionNum(StringRef ArgValue) { + return llvm::StringSwitch<unsigned>(ArgValue) + .Case("-gdwarf-2", 2) + .Case("-gdwarf-3", 3) + .Case("-gdwarf-4", 4) + .Case("-gdwarf-5", 5) + .Default(0); +} + +static void RenderDebugEnablingArgs(const ArgList &Args, ArgStringList &CmdArgs, + codegenoptions::DebugInfoKind DebugInfoKind, + unsigned DwarfVersion, + llvm::DebuggerKind DebuggerTuning) { + switch (DebugInfoKind) { + case codegenoptions::DebugLineTablesOnly: + CmdArgs.push_back("-debug-info-kind=line-tables-only"); + break; + case codegenoptions::LimitedDebugInfo: + CmdArgs.push_back("-debug-info-kind=limited"); + break; + case codegenoptions::FullDebugInfo: + CmdArgs.push_back("-debug-info-kind=standalone"); + break; + default: + break; + } + if (DwarfVersion > 0) + CmdArgs.push_back( + Args.MakeArgString("-dwarf-version=" + Twine(DwarfVersion))); + switch (DebuggerTuning) { + case llvm::DebuggerKind::GDB: + CmdArgs.push_back("-debugger-tuning=gdb"); + break; + case llvm::DebuggerKind::LLDB: + CmdArgs.push_back("-debugger-tuning=lldb"); + break; + case llvm::DebuggerKind::SCE: + CmdArgs.push_back("-debugger-tuning=sce"); + break; + default: + break; + } +} + +static const char *RelocationModelName(llvm::Reloc::Model Model) { + switch (Model) { + case llvm::Reloc::Static: + return "static"; + case llvm::Reloc::PIC_: + return "pic"; + case llvm::Reloc::DynamicNoPIC: + return "dynamic-no-pic"; + case llvm::Reloc::ROPI: + return "ropi"; + case llvm::Reloc::RWPI: + return "rwpi"; + case llvm::Reloc::ROPI_RWPI: + return "ropi-rwpi"; + } + llvm_unreachable("Unknown Reloc::Model kind"); +} + +void Clang::AddPreprocessingOptions(Compilation &C, const JobAction &JA, + const Driver &D, const ArgList &Args, + ArgStringList &CmdArgs, + const InputInfo &Output, + const InputInfoList &Inputs) const { + Arg *A; + const bool IsIAMCU = getToolChain().getTriple().isOSIAMCU(); + + CheckPreprocessingOptions(D, Args); + + Args.AddLastArg(CmdArgs, options::OPT_C); + Args.AddLastArg(CmdArgs, options::OPT_CC); + + // Handle dependency file generation. + if ((A = Args.getLastArg(options::OPT_M, options::OPT_MM)) || + (A = Args.getLastArg(options::OPT_MD)) || + (A = Args.getLastArg(options::OPT_MMD))) { + // Determine the output location. + const char *DepFile; + if (Arg *MF = Args.getLastArg(options::OPT_MF)) { + DepFile = MF->getValue(); + C.addFailureResultFile(DepFile, &JA); + } else if (Output.getType() == types::TY_Dependencies) { + DepFile = Output.getFilename(); + } else if (A->getOption().matches(options::OPT_M) || + A->getOption().matches(options::OPT_MM)) { + DepFile = "-"; + } else { + DepFile = getDependencyFileName(Args, Inputs); + C.addFailureResultFile(DepFile, &JA); + } + CmdArgs.push_back("-dependency-file"); + CmdArgs.push_back(DepFile); + + // Add a default target if one wasn't specified. + if (!Args.hasArg(options::OPT_MT) && !Args.hasArg(options::OPT_MQ)) { + const char *DepTarget; + + // If user provided -o, that is the dependency target, except + // when we are only generating a dependency file. + Arg *OutputOpt = Args.getLastArg(options::OPT_o); + if (OutputOpt && Output.getType() != types::TY_Dependencies) { + DepTarget = OutputOpt->getValue(); + } else { + // Otherwise derive from the base input. + // + // FIXME: This should use the computed output file location. + SmallString<128> P(Inputs[0].getBaseInput()); + llvm::sys::path::replace_extension(P, "o"); + DepTarget = Args.MakeArgString(llvm::sys::path::filename(P)); + } + + CmdArgs.push_back("-MT"); + SmallString<128> Quoted; + QuoteTarget(DepTarget, Quoted); + CmdArgs.push_back(Args.MakeArgString(Quoted)); + } + + if (A->getOption().matches(options::OPT_M) || + A->getOption().matches(options::OPT_MD)) + CmdArgs.push_back("-sys-header-deps"); + if ((isa<PrecompileJobAction>(JA) && + !Args.hasArg(options::OPT_fno_module_file_deps)) || + Args.hasArg(options::OPT_fmodule_file_deps)) + CmdArgs.push_back("-module-file-deps"); + } + + if (Args.hasArg(options::OPT_MG)) { + if (!A || A->getOption().matches(options::OPT_MD) || + A->getOption().matches(options::OPT_MMD)) + D.Diag(diag::err_drv_mg_requires_m_or_mm); + CmdArgs.push_back("-MG"); + } + + Args.AddLastArg(CmdArgs, options::OPT_MP); + Args.AddLastArg(CmdArgs, options::OPT_MV); + + // Convert all -MQ <target> args to -MT <quoted target> + for (const Arg *A : Args.filtered(options::OPT_MT, options::OPT_MQ)) { + A->claim(); + + if (A->getOption().matches(options::OPT_MQ)) { + CmdArgs.push_back("-MT"); + SmallString<128> Quoted; + QuoteTarget(A->getValue(), Quoted); + CmdArgs.push_back(Args.MakeArgString(Quoted)); + + // -MT flag - no change + } else { + A->render(Args, CmdArgs); + } + } + + // Add offload include arguments specific for CUDA. This must happen before + // we -I or -include anything else, because we must pick up the CUDA headers + // from the particular CUDA installation, rather than from e.g. + // /usr/local/include. + if (JA.isOffloading(Action::OFK_Cuda)) + getToolChain().AddCudaIncludeArgs(Args, CmdArgs); + + // Add -i* options, and automatically translate to + // -include-pch/-include-pth for transparent PCH support. It's + // wonky, but we include looking for .gch so we can support seamless + // replacement into a build system already set up to be generating + // .gch files. + int YcIndex = -1, YuIndex = -1; + { + int AI = -1; + const Arg *YcArg = Args.getLastArg(options::OPT__SLASH_Yc); + const Arg *YuArg = Args.getLastArg(options::OPT__SLASH_Yu); + for (const Arg *A : Args.filtered(options::OPT_clang_i_Group)) { + // Walk the whole i_Group and skip non "-include" flags so that the index + // here matches the index in the next loop below. + ++AI; + if (!A->getOption().matches(options::OPT_include)) + continue; + if (YcArg && strcmp(A->getValue(), YcArg->getValue()) == 0) + YcIndex = AI; + if (YuArg && strcmp(A->getValue(), YuArg->getValue()) == 0) + YuIndex = AI; + } + } + if (isa<PrecompileJobAction>(JA) && YcIndex != -1) { + Driver::InputList Inputs; + D.BuildInputs(getToolChain(), C.getArgs(), Inputs); + assert(Inputs.size() == 1 && "Need one input when building pch"); + CmdArgs.push_back(Args.MakeArgString(Twine("-find-pch-source=") + + Inputs[0].second->getValue())); + } + + bool RenderedImplicitInclude = false; + int AI = -1; + for (const Arg *A : Args.filtered(options::OPT_clang_i_Group)) { + ++AI; + + if (getToolChain().getDriver().IsCLMode() && + A->getOption().matches(options::OPT_include)) { + // In clang-cl mode, /Ycfoo.h means that all code up to a foo.h + // include is compiled into foo.h, and everything after goes into + // the .obj file. /Yufoo.h means that all includes prior to and including + // foo.h are completely skipped and replaced with a use of the pch file + // for foo.h. (Each flag can have at most one value, multiple /Yc flags + // just mean that the last one wins.) If /Yc and /Yu are both present + // and refer to the same file, /Yc wins. + // Note that OPT__SLASH_FI gets mapped to OPT_include. + // FIXME: The code here assumes that /Yc and /Yu refer to the same file. + // cl.exe seems to support both flags with different values, but that + // seems strange (which flag does /Fp now refer to?), so don't implement + // that until someone needs it. + int PchIndex = YcIndex != -1 ? YcIndex : YuIndex; + if (PchIndex != -1) { + if (isa<PrecompileJobAction>(JA)) { + // When building the pch, skip all includes after the pch. + assert(YcIndex != -1 && PchIndex == YcIndex); + if (AI >= YcIndex) + continue; + } else { + // When using the pch, skip all includes prior to the pch. + if (AI < PchIndex) { + A->claim(); + continue; + } + if (AI == PchIndex) { + A->claim(); + CmdArgs.push_back("-include-pch"); + CmdArgs.push_back( + Args.MakeArgString(D.GetClPchPath(C, A->getValue()))); + continue; + } + } + } + } else if (A->getOption().matches(options::OPT_include)) { + // Handling of gcc-style gch precompiled headers. + bool IsFirstImplicitInclude = !RenderedImplicitInclude; + RenderedImplicitInclude = true; + + // Use PCH if the user requested it. + bool UsePCH = D.CCCUsePCH; + + bool FoundPTH = false; + bool FoundPCH = false; + SmallString<128> P(A->getValue()); + // We want the files to have a name like foo.h.pch. Add a dummy extension + // so that replace_extension does the right thing. + P += ".dummy"; + if (UsePCH) { + llvm::sys::path::replace_extension(P, "pch"); + if (llvm::sys::fs::exists(P)) + FoundPCH = true; + } + + if (!FoundPCH) { + llvm::sys::path::replace_extension(P, "pth"); + if (llvm::sys::fs::exists(P)) + FoundPTH = true; + } + + if (!FoundPCH && !FoundPTH) { + llvm::sys::path::replace_extension(P, "gch"); + if (llvm::sys::fs::exists(P)) { + FoundPCH = UsePCH; + FoundPTH = !UsePCH; + } + } + + if (FoundPCH || FoundPTH) { + if (IsFirstImplicitInclude) { + A->claim(); + if (UsePCH) + CmdArgs.push_back("-include-pch"); + else + CmdArgs.push_back("-include-pth"); + CmdArgs.push_back(Args.MakeArgString(P)); + continue; + } else { + // Ignore the PCH if not first on command line and emit warning. + D.Diag(diag::warn_drv_pch_not_first_include) << P + << A->getAsString(Args); + } + } + } else if (A->getOption().matches(options::OPT_isystem_after)) { + // Handling of paths which must come late. These entries are handled by + // the toolchain itself after the resource dir is inserted in the right + // search order. + // Do not claim the argument so that the use of the argument does not + // silently go unnoticed on toolchains which do not honour the option. + continue; + } + + // Not translated, render as usual. + A->claim(); + A->render(Args, CmdArgs); + } + + Args.AddAllArgs(CmdArgs, + {options::OPT_D, options::OPT_U, options::OPT_I_Group, + options::OPT_F, options::OPT_index_header_map}); + + // Add -Wp, and -Xpreprocessor if using the preprocessor. + + // FIXME: There is a very unfortunate problem here, some troubled + // souls abuse -Wp, to pass preprocessor options in gcc syntax. To + // really support that we would have to parse and then translate + // those options. :( + Args.AddAllArgValues(CmdArgs, options::OPT_Wp_COMMA, + options::OPT_Xpreprocessor); + + // -I- is a deprecated GCC feature, reject it. + if (Arg *A = Args.getLastArg(options::OPT_I_)) + D.Diag(diag::err_drv_I_dash_not_supported) << A->getAsString(Args); + + // If we have a --sysroot, and don't have an explicit -isysroot flag, add an + // -isysroot to the CC1 invocation. + StringRef sysroot = C.getSysRoot(); + if (sysroot != "") { + if (!Args.hasArg(options::OPT_isysroot)) { + CmdArgs.push_back("-isysroot"); + CmdArgs.push_back(C.getArgs().MakeArgString(sysroot)); + } + } + + // Parse additional include paths from environment variables. + // FIXME: We should probably sink the logic for handling these from the + // frontend into the driver. It will allow deleting 4 otherwise unused flags. + // CPATH - included following the user specified includes (but prior to + // builtin and standard includes). + addDirectoryList(Args, CmdArgs, "-I", "CPATH"); + // C_INCLUDE_PATH - system includes enabled when compiling C. + addDirectoryList(Args, CmdArgs, "-c-isystem", "C_INCLUDE_PATH"); + // CPLUS_INCLUDE_PATH - system includes enabled when compiling C++. + addDirectoryList(Args, CmdArgs, "-cxx-isystem", "CPLUS_INCLUDE_PATH"); + // OBJC_INCLUDE_PATH - system includes enabled when compiling ObjC. + addDirectoryList(Args, CmdArgs, "-objc-isystem", "OBJC_INCLUDE_PATH"); + // OBJCPLUS_INCLUDE_PATH - system includes enabled when compiling ObjC++. + addDirectoryList(Args, CmdArgs, "-objcxx-isystem", "OBJCPLUS_INCLUDE_PATH"); + + // While adding the include arguments, we also attempt to retrieve the + // arguments of related offloading toolchains or arguments that are specific + // of an offloading programming model. + + // Add C++ include arguments, if needed. + if (types::isCXX(Inputs[0].getType())) + forAllAssociatedToolChains(C, JA, getToolChain(), + [&Args, &CmdArgs](const ToolChain &TC) { + TC.AddClangCXXStdlibIncludeArgs(Args, CmdArgs); + }); + + // Add system include arguments for all targets but IAMCU. + if (!IsIAMCU) + forAllAssociatedToolChains(C, JA, getToolChain(), + [&Args, &CmdArgs](const ToolChain &TC) { + TC.AddClangSystemIncludeArgs(Args, CmdArgs); + }); + else { + // For IAMCU add special include arguments. + getToolChain().AddIAMCUIncludeArgs(Args, CmdArgs); + } +} + +// FIXME: Move to target hook. +static bool isSignedCharDefault(const llvm::Triple &Triple) { + switch (Triple.getArch()) { + default: + return true; + + 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: + if (Triple.isOSDarwin() || Triple.isOSWindows()) + return true; + return false; + + case llvm::Triple::ppc: + case llvm::Triple::ppc64: + if (Triple.isOSDarwin()) + return true; + return false; + + case llvm::Triple::hexagon: + case llvm::Triple::ppc64le: + case llvm::Triple::systemz: + case llvm::Triple::xcore: + return false; + } +} + +static bool isNoCommonDefault(const llvm::Triple &Triple) { + switch (Triple.getArch()) { + default: + return false; + + case llvm::Triple::xcore: + case llvm::Triple::wasm32: + case llvm::Triple::wasm64: + return true; + } +} + +void Clang::AddARMTargetArgs(const llvm::Triple &Triple, const ArgList &Args, + ArgStringList &CmdArgs, bool KernelOrKext) const { + // Select the ABI to use. + // FIXME: Support -meabi. + // FIXME: Parts of this are duplicated in the backend, unify this somehow. + const char *ABIName = nullptr; + if (Arg *A = Args.getLastArg(options::OPT_mabi_EQ)) { + ABIName = A->getValue(); + } else if (Triple.isOSBinFormatMachO()) { + if (arm::useAAPCSForMachO(Triple)) { + ABIName = "aapcs"; + } else if (Triple.isWatchABI()) { + ABIName = "aapcs16"; + } else { + ABIName = "apcs-gnu"; + } + } else if (Triple.isOSWindows()) { + // FIXME: this is invalid for WindowsCE + ABIName = "aapcs"; + } else { + // Select the default based on the platform. + switch (Triple.getEnvironment()) { + case llvm::Triple::Android: + case llvm::Triple::GNUEABI: + case llvm::Triple::GNUEABIHF: + case llvm::Triple::MuslEABI: + case llvm::Triple::MuslEABIHF: + ABIName = "aapcs-linux"; + break; + case llvm::Triple::EABIHF: + case llvm::Triple::EABI: + ABIName = "aapcs"; + break; + default: + if (Triple.getOS() == llvm::Triple::NetBSD) + ABIName = "apcs-gnu"; + else if (Triple.getOS() == llvm::Triple::OpenBSD) + ABIName = "aapcs-linux"; + else + ABIName = "aapcs"; + break; + } + } + CmdArgs.push_back("-target-abi"); + CmdArgs.push_back(ABIName); + + // Determine floating point ABI from the options & target defaults. + arm::FloatABI ABI = arm::getARMFloatABI(getToolChain(), Args); + if (ABI == arm::FloatABI::Soft) { + // Floating point operations and argument passing are soft. + // FIXME: This changes CPP defines, we need -target-soft-float. + CmdArgs.push_back("-msoft-float"); + CmdArgs.push_back("-mfloat-abi"); + CmdArgs.push_back("soft"); + } else if (ABI == arm::FloatABI::SoftFP) { + // Floating point operations are hard, but argument passing is soft. + CmdArgs.push_back("-mfloat-abi"); + CmdArgs.push_back("soft"); + } else { + // Floating point operations and argument passing are hard. + assert(ABI == arm::FloatABI::Hard && "Invalid float abi!"); + CmdArgs.push_back("-mfloat-abi"); + CmdArgs.push_back("hard"); + } + + // Forward the -mglobal-merge option for explicit control over the pass. + if (Arg *A = Args.getLastArg(options::OPT_mglobal_merge, + options::OPT_mno_global_merge)) { + CmdArgs.push_back("-backend-option"); + if (A->getOption().matches(options::OPT_mno_global_merge)) + CmdArgs.push_back("-arm-global-merge=false"); + else + CmdArgs.push_back("-arm-global-merge=true"); + } + + if (!Args.hasFlag(options::OPT_mimplicit_float, + options::OPT_mno_implicit_float, true)) + CmdArgs.push_back("-no-implicit-float"); +} + +void Clang::AddAArch64TargetArgs(const ArgList &Args, + ArgStringList &CmdArgs) const { + const llvm::Triple &Triple = getToolChain().getEffectiveTriple(); + + if (!Args.hasFlag(options::OPT_mred_zone, options::OPT_mno_red_zone, true) || + Args.hasArg(options::OPT_mkernel) || + Args.hasArg(options::OPT_fapple_kext)) + CmdArgs.push_back("-disable-red-zone"); + + if (!Args.hasFlag(options::OPT_mimplicit_float, + options::OPT_mno_implicit_float, true)) + CmdArgs.push_back("-no-implicit-float"); + + const char *ABIName = nullptr; + if (Arg *A = Args.getLastArg(options::OPT_mabi_EQ)) + ABIName = A->getValue(); + else if (Triple.isOSDarwin()) + ABIName = "darwinpcs"; + else + ABIName = "aapcs"; + + CmdArgs.push_back("-target-abi"); + CmdArgs.push_back(ABIName); + + if (Arg *A = Args.getLastArg(options::OPT_mfix_cortex_a53_835769, + options::OPT_mno_fix_cortex_a53_835769)) { + CmdArgs.push_back("-backend-option"); + if (A->getOption().matches(options::OPT_mfix_cortex_a53_835769)) + CmdArgs.push_back("-aarch64-fix-cortex-a53-835769=1"); + else + CmdArgs.push_back("-aarch64-fix-cortex-a53-835769=0"); + } else if (Triple.isAndroid()) { + // Enabled A53 errata (835769) workaround by default on android + CmdArgs.push_back("-backend-option"); + CmdArgs.push_back("-aarch64-fix-cortex-a53-835769=1"); + } + + // Forward the -mglobal-merge option for explicit control over the pass. + if (Arg *A = Args.getLastArg(options::OPT_mglobal_merge, + options::OPT_mno_global_merge)) { + CmdArgs.push_back("-backend-option"); + if (A->getOption().matches(options::OPT_mno_global_merge)) + CmdArgs.push_back("-aarch64-enable-global-merge=false"); + else + CmdArgs.push_back("-aarch64-enable-global-merge=true"); + } +} + +void Clang::AddMIPSTargetArgs(const ArgList &Args, + ArgStringList &CmdArgs) const { + const Driver &D = getToolChain().getDriver(); + StringRef CPUName; + StringRef ABIName; + const llvm::Triple &Triple = getToolChain().getTriple(); + mips::getMipsCPUAndABI(Args, Triple, CPUName, ABIName); + + CmdArgs.push_back("-target-abi"); + CmdArgs.push_back(ABIName.data()); + + mips::FloatABI ABI = mips::getMipsFloatABI(D, Args); + if (ABI == mips::FloatABI::Soft) { + // Floating point operations and argument passing are soft. + CmdArgs.push_back("-msoft-float"); + CmdArgs.push_back("-mfloat-abi"); + CmdArgs.push_back("soft"); + } else { + // Floating point operations and argument passing are hard. + assert(ABI == mips::FloatABI::Hard && "Invalid float abi!"); + CmdArgs.push_back("-mfloat-abi"); + CmdArgs.push_back("hard"); + } + + if (Arg *A = Args.getLastArg(options::OPT_mxgot, options::OPT_mno_xgot)) { + if (A->getOption().matches(options::OPT_mxgot)) { + CmdArgs.push_back("-mllvm"); + CmdArgs.push_back("-mxgot"); + } + } + + if (Arg *A = Args.getLastArg(options::OPT_mldc1_sdc1, + options::OPT_mno_ldc1_sdc1)) { + if (A->getOption().matches(options::OPT_mno_ldc1_sdc1)) { + CmdArgs.push_back("-mllvm"); + CmdArgs.push_back("-mno-ldc1-sdc1"); + } + } + + if (Arg *A = Args.getLastArg(options::OPT_mcheck_zero_division, + options::OPT_mno_check_zero_division)) { + if (A->getOption().matches(options::OPT_mno_check_zero_division)) { + CmdArgs.push_back("-mllvm"); + CmdArgs.push_back("-mno-check-zero-division"); + } + } + + if (Arg *A = Args.getLastArg(options::OPT_G)) { + StringRef v = A->getValue(); + CmdArgs.push_back("-mllvm"); + CmdArgs.push_back(Args.MakeArgString("-mips-ssection-threshold=" + v)); + A->claim(); + } + + if (Arg *A = Args.getLastArg(options::OPT_mcompact_branches_EQ)) { + StringRef Val = StringRef(A->getValue()); + if (mips::hasCompactBranches(CPUName)) { + if (Val == "never" || Val == "always" || Val == "optimal") { + CmdArgs.push_back("-mllvm"); + CmdArgs.push_back(Args.MakeArgString("-mips-compact-branches=" + Val)); + } else + D.Diag(diag::err_drv_unsupported_option_argument) + << A->getOption().getName() << Val; + } else + D.Diag(diag::warn_target_unsupported_compact_branches) << CPUName; + } +} + +void Clang::AddPPCTargetArgs(const ArgList &Args, + ArgStringList &CmdArgs) const { + // Select the ABI to use. + const char *ABIName = nullptr; + if (getToolChain().getTriple().isOSLinux()) + switch (getToolChain().getArch()) { + case llvm::Triple::ppc64: { + // When targeting a processor that supports QPX, or if QPX is + // specifically enabled, default to using the ABI that supports QPX (so + // long as it is not specifically disabled). + bool HasQPX = false; + if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) + HasQPX = A->getValue() == StringRef("a2q"); + HasQPX = Args.hasFlag(options::OPT_mqpx, options::OPT_mno_qpx, HasQPX); + if (HasQPX) { + ABIName = "elfv1-qpx"; + break; + } + + ABIName = "elfv1"; + break; + } + case llvm::Triple::ppc64le: + ABIName = "elfv2"; + break; + default: + break; + } + + if (Arg *A = Args.getLastArg(options::OPT_mabi_EQ)) + // The ppc64 linux abis are all "altivec" abis by default. Accept and ignore + // the option if given as we don't have backend support for any targets + // that don't use the altivec abi. + if (StringRef(A->getValue()) != "altivec") + ABIName = A->getValue(); + + ppc::FloatABI FloatABI = + ppc::getPPCFloatABI(getToolChain().getDriver(), Args); + + if (FloatABI == ppc::FloatABI::Soft) { + // Floating point operations and argument passing are soft. + CmdArgs.push_back("-msoft-float"); + CmdArgs.push_back("-mfloat-abi"); + CmdArgs.push_back("soft"); + } else { + // Floating point operations and argument passing are hard. + assert(FloatABI == ppc::FloatABI::Hard && "Invalid float abi!"); + CmdArgs.push_back("-mfloat-abi"); + CmdArgs.push_back("hard"); + } + + if (ABIName) { + CmdArgs.push_back("-target-abi"); + CmdArgs.push_back(ABIName); + } +} + +void Clang::AddSparcTargetArgs(const ArgList &Args, + ArgStringList &CmdArgs) const { + sparc::FloatABI FloatABI = + sparc::getSparcFloatABI(getToolChain().getDriver(), Args); + + if (FloatABI == sparc::FloatABI::Soft) { + // Floating point operations and argument passing are soft. + CmdArgs.push_back("-msoft-float"); + CmdArgs.push_back("-mfloat-abi"); + CmdArgs.push_back("soft"); + } else { + // Floating point operations and argument passing are hard. + assert(FloatABI == sparc::FloatABI::Hard && "Invalid float abi!"); + CmdArgs.push_back("-mfloat-abi"); + CmdArgs.push_back("hard"); + } +} + +void Clang::AddSystemZTargetArgs(const ArgList &Args, + ArgStringList &CmdArgs) const { + if (Args.hasFlag(options::OPT_mbackchain, options::OPT_mno_backchain, false)) + CmdArgs.push_back("-mbackchain"); +} + +void Clang::AddX86TargetArgs(const ArgList &Args, + ArgStringList &CmdArgs) const { + if (!Args.hasFlag(options::OPT_mred_zone, options::OPT_mno_red_zone, true) || + Args.hasArg(options::OPT_mkernel) || + Args.hasArg(options::OPT_fapple_kext)) + CmdArgs.push_back("-disable-red-zone"); + + // Default to avoid implicit floating-point for kernel/kext code, but allow + // that to be overridden with -mno-soft-float. + bool NoImplicitFloat = (Args.hasArg(options::OPT_mkernel) || + Args.hasArg(options::OPT_fapple_kext)); + if (Arg *A = Args.getLastArg( + options::OPT_msoft_float, options::OPT_mno_soft_float, + options::OPT_mimplicit_float, options::OPT_mno_implicit_float)) { + const Option &O = A->getOption(); + NoImplicitFloat = (O.matches(options::OPT_mno_implicit_float) || + O.matches(options::OPT_msoft_float)); + } + if (NoImplicitFloat) + CmdArgs.push_back("-no-implicit-float"); + + if (Arg *A = Args.getLastArg(options::OPT_masm_EQ)) { + StringRef Value = A->getValue(); + if (Value == "intel" || Value == "att") { + CmdArgs.push_back("-mllvm"); + CmdArgs.push_back(Args.MakeArgString("-x86-asm-syntax=" + Value)); + } else { + getToolChain().getDriver().Diag(diag::err_drv_unsupported_option_argument) + << A->getOption().getName() << Value; + } + } + + // Set flags to support MCU ABI. + if (Args.hasFlag(options::OPT_miamcu, options::OPT_mno_iamcu, false)) { + CmdArgs.push_back("-mfloat-abi"); + CmdArgs.push_back("soft"); + CmdArgs.push_back("-mstack-alignment=4"); + } +} + +void Clang::AddHexagonTargetArgs(const ArgList &Args, + ArgStringList &CmdArgs) const { + CmdArgs.push_back("-mqdsp6-compat"); + CmdArgs.push_back("-Wreturn-type"); + + if (auto G = toolchains::HexagonToolChain::getSmallDataThreshold(Args)) { + std::string N = llvm::utostr(G.getValue()); + std::string Opt = std::string("-hexagon-small-data-threshold=") + N; + CmdArgs.push_back("-mllvm"); + CmdArgs.push_back(Args.MakeArgString(Opt)); + } + + if (!Args.hasArg(options::OPT_fno_short_enums)) + CmdArgs.push_back("-fshort-enums"); + if (Args.getLastArg(options::OPT_mieee_rnd_near)) { + CmdArgs.push_back("-mllvm"); + CmdArgs.push_back("-enable-hexagon-ieee-rnd-near"); + } + CmdArgs.push_back("-mllvm"); + CmdArgs.push_back("-machine-sink-split=0"); +} + +void Clang::AddLanaiTargetArgs(const ArgList &Args, + ArgStringList &CmdArgs) const { + if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) { + StringRef CPUName = A->getValue(); + + CmdArgs.push_back("-target-cpu"); + CmdArgs.push_back(Args.MakeArgString(CPUName)); + } + if (Arg *A = Args.getLastArg(options::OPT_mregparm_EQ)) { + StringRef Value = A->getValue(); + // Only support mregparm=4 to support old usage. Report error for all other + // cases. + int Mregparm; + if (Value.getAsInteger(10, Mregparm)) { + if (Mregparm != 4) { + getToolChain().getDriver().Diag( + diag::err_drv_unsupported_option_argument) + << A->getOption().getName() << Value; + } + } + } +} + +void Clang::AddWebAssemblyTargetArgs(const ArgList &Args, + ArgStringList &CmdArgs) const { + // Default to "hidden" visibility. + if (!Args.hasArg(options::OPT_fvisibility_EQ, + options::OPT_fvisibility_ms_compat)) { + CmdArgs.push_back("-fvisibility"); + CmdArgs.push_back("hidden"); + } +} + +void Clang::DumpCompilationDatabase(Compilation &C, StringRef Filename, + StringRef Target, const InputInfo &Output, + const InputInfo &Input, const ArgList &Args) const { + // If this is a dry run, do not create the compilation database file. + if (C.getArgs().hasArg(options::OPT__HASH_HASH_HASH)) + return; + + using llvm::yaml::escape; + const Driver &D = getToolChain().getDriver(); + + if (!CompilationDatabase) { + std::error_code EC; + auto File = llvm::make_unique<llvm::raw_fd_ostream>(Filename, EC, llvm::sys::fs::F_Text); + if (EC) { + D.Diag(clang::diag::err_drv_compilationdatabase) << Filename + << EC.message(); + return; + } + CompilationDatabase = std::move(File); + } + auto &CDB = *CompilationDatabase; + SmallString<128> Buf; + if (llvm::sys::fs::current_path(Buf)) + Buf = "."; + CDB << "{ \"directory\": \"" << escape(Buf) << "\""; + CDB << ", \"file\": \"" << escape(Input.getFilename()) << "\""; + CDB << ", \"output\": \"" << escape(Output.getFilename()) << "\""; + CDB << ", \"arguments\": [\"" << escape(D.ClangExecutable) << "\""; + Buf = "-x"; + Buf += types::getTypeName(Input.getType()); + CDB << ", \"" << escape(Buf) << "\""; + if (!D.SysRoot.empty() && !Args.hasArg(options::OPT__sysroot_EQ)) { + Buf = "--sysroot="; + Buf += D.SysRoot; + CDB << ", \"" << escape(Buf) << "\""; + } + CDB << ", \"" << escape(Input.getFilename()) << "\""; + for (auto &A: Args) { + auto &O = A->getOption(); + // Skip language selection, which is positional. + if (O.getID() == options::OPT_x) + continue; + // Skip writing dependency output and the compilation database itself. + if (O.getGroup().isValid() && O.getGroup().getID() == options::OPT_M_Group) + continue; + // Skip inputs. + if (O.getKind() == Option::InputClass) + continue; + // All other arguments are quoted and appended. + ArgStringList ASL; + A->render(Args, ASL); + for (auto &it: ASL) + CDB << ", \"" << escape(it) << "\""; + } + Buf = "--target="; + Buf += Target; + CDB << ", \"" << escape(Buf) << "\"]},\n"; +} + +static void CollectArgsForIntegratedAssembler(Compilation &C, + const ArgList &Args, + ArgStringList &CmdArgs, + const Driver &D) { + if (UseRelaxAll(C, Args)) + CmdArgs.push_back("-mrelax-all"); + + // Only default to -mincremental-linker-compatible if we think we are + // targeting the MSVC linker. + bool DefaultIncrementalLinkerCompatible = + C.getDefaultToolChain().getTriple().isWindowsMSVCEnvironment(); + if (Args.hasFlag(options::OPT_mincremental_linker_compatible, + options::OPT_mno_incremental_linker_compatible, + DefaultIncrementalLinkerCompatible)) + CmdArgs.push_back("-mincremental-linker-compatible"); + + switch (C.getDefaultToolChain().getArch()) { + case llvm::Triple::arm: + case llvm::Triple::armeb: + case llvm::Triple::thumb: + case llvm::Triple::thumbeb: + if (Arg *A = Args.getLastArg(options::OPT_mimplicit_it_EQ)) { + StringRef Value = A->getValue(); + if (Value == "always" || Value == "never" || Value == "arm" || + Value == "thumb") { + CmdArgs.push_back("-mllvm"); + CmdArgs.push_back(Args.MakeArgString("-arm-implicit-it=" + Value)); + } else { + D.Diag(diag::err_drv_unsupported_option_argument) + << A->getOption().getName() << Value; + } + } + break; + default: + break; + } + + // When passing -I arguments to the assembler we sometimes need to + // unconditionally take the next argument. For example, when parsing + // '-Wa,-I -Wa,foo' we need to accept the -Wa,foo arg after seeing the + // -Wa,-I arg and when parsing '-Wa,-I,foo' we need to accept the 'foo' + // arg after parsing the '-I' arg. + bool TakeNextArg = false; + + // When using an integrated assembler, translate -Wa, and -Xassembler + // options. + bool CompressDebugSections = false; + + bool UseRelaxRelocations = ENABLE_X86_RELAX_RELOCATIONS; + const char *MipsTargetFeature = nullptr; + for (const Arg *A : + Args.filtered(options::OPT_Wa_COMMA, options::OPT_Xassembler)) { + A->claim(); + + for (StringRef Value : A->getValues()) { + if (TakeNextArg) { + CmdArgs.push_back(Value.data()); + TakeNextArg = false; + continue; + } + + if (C.getDefaultToolChain().getTriple().isOSBinFormatCOFF() && + Value == "-mbig-obj") + continue; // LLVM handles bigobj automatically + + switch (C.getDefaultToolChain().getArch()) { + default: + break; + case llvm::Triple::mips: + case llvm::Triple::mipsel: + case llvm::Triple::mips64: + case llvm::Triple::mips64el: + if (Value == "--trap") { + CmdArgs.push_back("-target-feature"); + CmdArgs.push_back("+use-tcc-in-div"); + continue; + } + if (Value == "--break") { + CmdArgs.push_back("-target-feature"); + CmdArgs.push_back("-use-tcc-in-div"); + continue; + } + if (Value.startswith("-msoft-float")) { + CmdArgs.push_back("-target-feature"); + CmdArgs.push_back("+soft-float"); + continue; + } + if (Value.startswith("-mhard-float")) { + CmdArgs.push_back("-target-feature"); + CmdArgs.push_back("-soft-float"); + continue; + } + + MipsTargetFeature = llvm::StringSwitch<const char *>(Value) + .Case("-mips1", "+mips1") + .Case("-mips2", "+mips2") + .Case("-mips3", "+mips3") + .Case("-mips4", "+mips4") + .Case("-mips5", "+mips5") + .Case("-mips32", "+mips32") + .Case("-mips32r2", "+mips32r2") + .Case("-mips32r3", "+mips32r3") + .Case("-mips32r5", "+mips32r5") + .Case("-mips32r6", "+mips32r6") + .Case("-mips64", "+mips64") + .Case("-mips64r2", "+mips64r2") + .Case("-mips64r3", "+mips64r3") + .Case("-mips64r5", "+mips64r5") + .Case("-mips64r6", "+mips64r6") + .Default(nullptr); + if (MipsTargetFeature) + continue; + } + + if (Value == "-force_cpusubtype_ALL") { + // Do nothing, this is the default and we don't support anything else. + } else if (Value == "-L") { + CmdArgs.push_back("-msave-temp-labels"); + } else if (Value == "--fatal-warnings") { + CmdArgs.push_back("-massembler-fatal-warnings"); + } else if (Value == "--noexecstack") { + CmdArgs.push_back("-mnoexecstack"); + } else if (Value == "-compress-debug-sections" || + Value == "--compress-debug-sections") { + CompressDebugSections = true; + } else if (Value == "-nocompress-debug-sections" || + Value == "--nocompress-debug-sections") { + CompressDebugSections = false; + } else if (Value == "-mrelax-relocations=yes" || + Value == "--mrelax-relocations=yes") { + UseRelaxRelocations = true; + } else if (Value == "-mrelax-relocations=no" || + Value == "--mrelax-relocations=no") { + UseRelaxRelocations = false; + } else if (Value.startswith("-I")) { + CmdArgs.push_back(Value.data()); + // We need to consume the next argument if the current arg is a plain + // -I. The next arg will be the include directory. + if (Value == "-I") + TakeNextArg = true; + } else if (Value.startswith("-gdwarf-")) { + // "-gdwarf-N" options are not cc1as options. + unsigned DwarfVersion = DwarfVersionNum(Value); + if (DwarfVersion == 0) { // Send it onward, and let cc1as complain. + CmdArgs.push_back(Value.data()); + } else { + RenderDebugEnablingArgs(Args, CmdArgs, + codegenoptions::LimitedDebugInfo, + DwarfVersion, llvm::DebuggerKind::Default); + } + } else if (Value.startswith("-mcpu") || Value.startswith("-mfpu") || + Value.startswith("-mhwdiv") || Value.startswith("-march")) { + // Do nothing, we'll validate it later. + } else if (Value == "-defsym") { + if (A->getNumValues() != 2) { + D.Diag(diag::err_drv_defsym_invalid_format) << Value; + break; + } + const char *S = A->getValue(1); + auto Pair = StringRef(S).split('='); + auto Sym = Pair.first; + auto SVal = Pair.second; + + if (Sym.empty() || SVal.empty()) { + D.Diag(diag::err_drv_defsym_invalid_format) << S; + break; + } + int64_t IVal; + if (SVal.getAsInteger(0, IVal)) { + D.Diag(diag::err_drv_defsym_invalid_symval) << SVal; + break; + } + CmdArgs.push_back(Value.data()); + TakeNextArg = true; + } else { + D.Diag(diag::err_drv_unsupported_option_argument) + << A->getOption().getName() << Value; + } + } + } + if (CompressDebugSections) { + if (llvm::zlib::isAvailable()) + CmdArgs.push_back("-compress-debug-sections"); + else + D.Diag(diag::warn_debug_compression_unavailable); + } + if (UseRelaxRelocations) + CmdArgs.push_back("--mrelax-relocations"); + if (MipsTargetFeature != nullptr) { + CmdArgs.push_back("-target-feature"); + CmdArgs.push_back(MipsTargetFeature); + } +} + +void Clang::ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, const InputInfoList &Inputs, + const ArgList &Args, const char *LinkingOutput) const { + const llvm::Triple &Triple = getToolChain().getEffectiveTriple(); + const std::string &TripleStr = Triple.getTriple(); + + bool KernelOrKext = + Args.hasArg(options::OPT_mkernel, options::OPT_fapple_kext); + const Driver &D = getToolChain().getDriver(); + ArgStringList CmdArgs; + + // Check number of inputs for sanity. We need at least one input. + assert(Inputs.size() >= 1 && "Must have at least one input."); + const InputInfo &Input = Inputs[0]; + // CUDA compilation may have multiple inputs (source file + results of + // device-side compilations). OpenMP device jobs also take the host IR as a + // second input. All other jobs are expected to have exactly one + // input. + bool IsCuda = JA.isOffloading(Action::OFK_Cuda); + bool IsOpenMPDevice = JA.isDeviceOffloading(Action::OFK_OpenMP); + assert((IsCuda || (IsOpenMPDevice && Inputs.size() == 2) || + 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(); + + // 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(); + } + + // C++ is not supported for IAMCU. + if (IsIAMCU && types::isCXX(Input.getType())) + D.Diag(diag::err_drv_clang_unsupported) << "C++ for IAMCU"; + + // Invoke ourselves in -cc1 mode. + // + // FIXME: Implement custom jobs for internal actions. + CmdArgs.push_back("-cc1"); + + // Add the "effective" target triple. + CmdArgs.push_back("-triple"); + CmdArgs.push_back(Args.MakeArgString(TripleStr)); + + if (const Arg *MJ = Args.getLastArg(options::OPT_MJ)) { + DumpCompilationDatabase(C, MJ->getValue(), TripleStr, Output, Input, Args); + Args.ClaimAllArgs(options::OPT_MJ); + } + + if (IsCuda) { + // We have to pass the triple of the host if compiling for a CUDA device and + // vice-versa. + std::string NormalizedTriple; + if (JA.isDeviceOffloading(Action::OFK_Cuda)) + NormalizedTriple = C.getSingleOffloadToolChain<Action::OFK_Host>() + ->getTriple() + .normalize(); + else + NormalizedTriple = C.getSingleOffloadToolChain<Action::OFK_Cuda>() + ->getTriple() + .normalize(); + + CmdArgs.push_back("-aux-triple"); + CmdArgs.push_back(Args.MakeArgString(NormalizedTriple)); + } + + if (Triple.isOSWindows() && (Triple.getArch() == llvm::Triple::arm || + Triple.getArch() == llvm::Triple::thumb)) { + unsigned Offset = Triple.getArch() == llvm::Triple::arm ? 4 : 6; + unsigned Version; + Triple.getArchName().substr(Offset).getAsInteger(10, Version); + if (Version < 7) + D.Diag(diag::err_target_unsupported_arch) << Triple.getArchName() + << TripleStr; + } + + // Push all default warning arguments that are specific to + // the given target. These come before user provided warning options + // are provided. + getToolChain().addClangWarningOptions(CmdArgs); + + // Select the appropriate action. + RewriteKind rewriteKind = RK_None; + + if (isa<AnalyzeJobAction>(JA)) { + assert(JA.getType() == types::TY_Plist && "Invalid output type."); + CmdArgs.push_back("-analyze"); + } else if (isa<MigrateJobAction>(JA)) { + CmdArgs.push_back("-migrate"); + } else if (isa<PreprocessJobAction>(JA)) { + if (Output.getType() == types::TY_Dependencies) + CmdArgs.push_back("-Eonly"); + else { + CmdArgs.push_back("-E"); + if (Args.hasArg(options::OPT_rewrite_objc) && + !Args.hasArg(options::OPT_g_Group)) + CmdArgs.push_back("-P"); + } + } else if (isa<AssembleJobAction>(JA)) { + CmdArgs.push_back("-emit-obj"); + + CollectArgsForIntegratedAssembler(C, Args, CmdArgs, D); + + // Also ignore explicit -force_cpusubtype_ALL option. + (void)Args.hasArg(options::OPT_force__cpusubtype__ALL); + } else if (isa<PrecompileJobAction>(JA)) { + // Use PCH if the user requested it. + bool UsePCH = D.CCCUsePCH; + + if (JA.getType() == types::TY_Nothing) + CmdArgs.push_back("-fsyntax-only"); + else if (JA.getType() == types::TY_ModuleFile) + CmdArgs.push_back("-emit-module-interface"); + else if (UsePCH) + CmdArgs.push_back("-emit-pch"); + else + CmdArgs.push_back("-emit-pth"); + } else if (isa<VerifyPCHJobAction>(JA)) { + CmdArgs.push_back("-verify-pch"); + } else { + assert((isa<CompileJobAction>(JA) || isa<BackendJobAction>(JA)) && + "Invalid action for clang tool."); + if (JA.getType() == types::TY_Nothing) { + CmdArgs.push_back("-fsyntax-only"); + } else if (JA.getType() == types::TY_LLVM_IR || + JA.getType() == types::TY_LTO_IR) { + CmdArgs.push_back("-emit-llvm"); + } else if (JA.getType() == types::TY_LLVM_BC || + JA.getType() == types::TY_LTO_BC) { + CmdArgs.push_back("-emit-llvm-bc"); + } else if (JA.getType() == types::TY_PP_Asm) { + CmdArgs.push_back("-S"); + } else if (JA.getType() == types::TY_AST) { + CmdArgs.push_back("-emit-pch"); + } else if (JA.getType() == types::TY_ModuleFile) { + CmdArgs.push_back("-module-file-info"); + } else if (JA.getType() == types::TY_RewrittenObjC) { + CmdArgs.push_back("-rewrite-objc"); + rewriteKind = RK_NonFragile; + } else if (JA.getType() == types::TY_RewrittenLegacyObjC) { + CmdArgs.push_back("-rewrite-objc"); + rewriteKind = RK_Fragile; + } else { + assert(JA.getType() == types::TY_PP_Asm && "Unexpected output type!"); + } + + // Preserve use-list order by default when emitting bitcode, so that + // loading the bitcode up in 'opt' or 'llc' and running passes gives the + // same result as running passes here. For LTO, we don't need to preserve + // the use-list order, since serialization to bitcode is part of the flow. + if (JA.getType() == types::TY_LLVM_BC) + CmdArgs.push_back("-emit-llvm-uselists"); + + if (D.isUsingLTO()) { + Args.AddLastArg(CmdArgs, options::OPT_flto, options::OPT_flto_EQ); + + // The Darwin linker currently uses the legacy LTO API, which does not + // support LTO unit features (CFI, whole program vtable opt) under + // ThinLTO. + if (!getToolChain().getTriple().isOSDarwin() || + D.getLTOMode() == LTOK_Full) + CmdArgs.push_back("-flto-unit"); + } + } + + if (const Arg *A = Args.getLastArg(options::OPT_fthinlto_index_EQ)) { + if (!types::isLLVMIR(Input.getType())) + D.Diag(diag::err_drv_argument_only_allowed_with) << A->getAsString(Args) + << "-x ir"; + Args.AddLastArg(CmdArgs, options::OPT_fthinlto_index_EQ); + } + + // Embed-bitcode option. + if (C.getDriver().embedBitcodeInObject() && !C.getDriver().isUsingLTO() && + (isa<BackendJobAction>(JA) || isa<AssembleJobAction>(JA))) { + // Add flags implied by -fembed-bitcode. + Args.AddLastArg(CmdArgs, options::OPT_fembed_bitcode_EQ); + // Disable all llvm IR level optimizations. + CmdArgs.push_back("-disable-llvm-passes"); + } + if (C.getDriver().embedBitcodeMarkerOnly() && !C.getDriver().isUsingLTO()) + CmdArgs.push_back("-fembed-bitcode=marker"); + + // We normally speed up the clang process a bit by skipping destructors at + // exit, but when we're generating diagnostics we can rely on some of the + // cleanup. + if (!C.isForDiagnostics()) + CmdArgs.push_back("-disable-free"); + +// Disable the verification pass in -asserts builds. +#ifdef NDEBUG + CmdArgs.push_back("-disable-llvm-verifier"); + // Discard LLVM value names in -asserts builds. + CmdArgs.push_back("-discard-value-names"); +#endif + + // Set the main file name, so that debug info works even with + // -save-temps. + CmdArgs.push_back("-main-file-name"); + CmdArgs.push_back(getBaseInputName(Args, Input)); + + // Some flags which affect the language (via preprocessor + // defines). + 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); + } + + CheckCodeGenerationOptions(D, Args); + + llvm::Reloc::Model RelocationModel; + unsigned PICLevel; + bool IsPIE; + std::tie(RelocationModel, PICLevel, IsPIE) = + ParsePICArgs(getToolChain(), Args); + + const char *RMName = RelocationModelName(RelocationModel); + + if ((RelocationModel == llvm::Reloc::ROPI || + RelocationModel == llvm::Reloc::ROPI_RWPI) && + types::isCXX(Input.getType()) && + !Args.hasArg(options::OPT_fallow_unsupported)) + D.Diag(diag::err_drv_ropi_incompatible_with_cxx); + + if (RMName) { + CmdArgs.push_back("-mrelocation-model"); + CmdArgs.push_back(RMName); + } + if (PICLevel > 0) { + CmdArgs.push_back("-pic-level"); + CmdArgs.push_back(PICLevel == 1 ? "1" : "2"); + if (IsPIE) + CmdArgs.push_back("-pic-is-pie"); + } + + if (Arg *A = Args.getLastArg(options::OPT_meabi)) { + CmdArgs.push_back("-meabi"); + CmdArgs.push_back(A->getValue()); + } + + CmdArgs.push_back("-mthread-model"); + if (Arg *A = Args.getLastArg(options::OPT_mthread_model)) + CmdArgs.push_back(A->getValue()); + else + CmdArgs.push_back(Args.MakeArgString(getToolChain().getThreadModel())); + + Args.AddLastArg(CmdArgs, options::OPT_fveclib); + + if (!Args.hasFlag(options::OPT_fmerge_all_constants, + options::OPT_fno_merge_all_constants)) + CmdArgs.push_back("-fno-merge-all-constants"); + + // LLVM Code Generator Options. + + if (Args.hasArg(options::OPT_frewrite_map_file) || + Args.hasArg(options::OPT_frewrite_map_file_EQ)) { + for (const Arg *A : Args.filtered(options::OPT_frewrite_map_file, + options::OPT_frewrite_map_file_EQ)) { + StringRef Map = A->getValue(); + if (!llvm::sys::fs::exists(Map)) { + D.Diag(diag::err_drv_no_such_file) << Map; + } else { + CmdArgs.push_back("-frewrite-map-file"); + CmdArgs.push_back(A->getValue()); + A->claim(); + } + } + } + + if (Arg *A = Args.getLastArg(options::OPT_Wframe_larger_than_EQ)) { + StringRef v = A->getValue(); + CmdArgs.push_back("-mllvm"); + CmdArgs.push_back(Args.MakeArgString("-warn-stack-size=" + v)); + A->claim(); + } + + if (!Args.hasFlag(options::OPT_fjump_tables, options::OPT_fno_jump_tables, + true)) + CmdArgs.push_back("-fno-jump-tables"); + + if (!Args.hasFlag(options::OPT_fpreserve_as_comments, + options::OPT_fno_preserve_as_comments, true)) + CmdArgs.push_back("-fno-preserve-as-comments"); + + if (Arg *A = Args.getLastArg(options::OPT_mregparm_EQ)) { + CmdArgs.push_back("-mregparm"); + CmdArgs.push_back(A->getValue()); + } + + if (Arg *A = Args.getLastArg(options::OPT_fpcc_struct_return, + 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(); + } else if (A->getOption().matches(options::OPT_fpcc_struct_return)) { + CmdArgs.push_back("-fpcc-struct-return"); + } else { + assert(A->getOption().matches(options::OPT_freg_struct_return)); + CmdArgs.push_back("-freg-struct-return"); + } + } + + if (Args.hasFlag(options::OPT_mrtd, options::OPT_mno_rtd, false)) + CmdArgs.push_back("-fdefault-calling-conv=stdcall"); + + if (shouldUseFramePointer(Args, getToolChain().getTriple())) + CmdArgs.push_back("-mdisable-fp-elim"); + if (!Args.hasFlag(options::OPT_fzero_initialized_in_bss, + options::OPT_fno_zero_initialized_in_bss)) + CmdArgs.push_back("-mno-zero-initialized-in-bss"); + + bool OFastEnabled = isOptimizationLevelFast(Args); + // If -Ofast is the optimization level, then -fstrict-aliasing should be + // enabled. This alias option is being used to simplify the hasFlag logic. + OptSpecifier StrictAliasingAliasOption = + 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(); + if (!Args.hasFlag(options::OPT_fstrict_aliasing, StrictAliasingAliasOption, + options::OPT_fno_strict_aliasing, TBAAOnByDefault)) + CmdArgs.push_back("-relaxed-aliasing"); + if (!Args.hasFlag(options::OPT_fstruct_path_tbaa, + options::OPT_fno_struct_path_tbaa)) + CmdArgs.push_back("-no-struct-path-tbaa"); + if (Args.hasFlag(options::OPT_fstrict_enums, options::OPT_fno_strict_enums, + false)) + CmdArgs.push_back("-fstrict-enums"); + if (!Args.hasFlag(options::OPT_fstrict_return, options::OPT_fno_strict_return, + true)) + CmdArgs.push_back("-fno-strict-return"); + if (Args.hasFlag(options::OPT_fstrict_vtable_pointers, + options::OPT_fno_strict_vtable_pointers, + false)) + CmdArgs.push_back("-fstrict-vtable-pointers"); + if (!Args.hasFlag(options::OPT_foptimize_sibling_calls, + options::OPT_fno_optimize_sibling_calls)) + CmdArgs.push_back("-mdisable-tail-calls"); + + // Handle segmented stacks. + if (Args.hasArg(options::OPT_fsplit_stack)) + CmdArgs.push_back("-split-stacks"); + + // If -Ofast is the optimization level, then -ffast-math should be enabled. + // This alias option is being used to simplify the getLastArg logic. + OptSpecifier FastMathAliasOption = + OFastEnabled ? options::OPT_Ofast : options::OPT_ffast_math; + + // Handle various floating point optimization flags, mapping them to the + // appropriate LLVM code generation flags. The pattern for all of these is to + // default off the codegen optimizations, and if any flag enables them and no + // flag disables them after the flag enabling them, enable the codegen + // optimization. This is complicated by several "umbrella" flags. + if (Arg *A = Args.getLastArg( + options::OPT_ffast_math, FastMathAliasOption, + options::OPT_fno_fast_math, options::OPT_ffinite_math_only, + options::OPT_fno_finite_math_only, options::OPT_fhonor_infinities, + options::OPT_fno_honor_infinities)) + if (A->getOption().getID() != options::OPT_fno_fast_math && + A->getOption().getID() != options::OPT_fno_finite_math_only && + A->getOption().getID() != options::OPT_fhonor_infinities) + CmdArgs.push_back("-menable-no-infs"); + if (Arg *A = Args.getLastArg( + options::OPT_ffast_math, FastMathAliasOption, + options::OPT_fno_fast_math, options::OPT_ffinite_math_only, + options::OPT_fno_finite_math_only, options::OPT_fhonor_nans, + options::OPT_fno_honor_nans)) + if (A->getOption().getID() != options::OPT_fno_fast_math && + A->getOption().getID() != options::OPT_fno_finite_math_only && + A->getOption().getID() != options::OPT_fhonor_nans) + CmdArgs.push_back("-menable-no-nans"); + + // -fmath-errno is the default on some platforms, e.g. BSD-derived OSes. + bool MathErrno = getToolChain().IsMathErrnoDefault(); + if (Arg *A = + Args.getLastArg(options::OPT_ffast_math, FastMathAliasOption, + options::OPT_fno_fast_math, options::OPT_fmath_errno, + options::OPT_fno_math_errno)) { + // 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). + if (A->getOption().getID() == options::OPT_fno_math_errno || + A->getOption().getID() == options::OPT_ffast_math || + A->getOption().getID() == options::OPT_Ofast) + MathErrno = false; + else if (A->getOption().getID() == options::OPT_fmath_errno) + MathErrno = true; + } + if (MathErrno) + CmdArgs.push_back("-fmath-errno"); + + // There are several flags which require disabling very specific + // optimizations. Any of these being disabled forces us to turn off the + // entire set of LLVM optimizations, so collect them through all the flag + // madness. + bool AssociativeMath = false; + if (Arg *A = Args.getLastArg( + options::OPT_ffast_math, FastMathAliasOption, + options::OPT_fno_fast_math, options::OPT_funsafe_math_optimizations, + options::OPT_fno_unsafe_math_optimizations, + options::OPT_fassociative_math, options::OPT_fno_associative_math)) + if (A->getOption().getID() != options::OPT_fno_fast_math && + A->getOption().getID() != options::OPT_fno_unsafe_math_optimizations && + A->getOption().getID() != options::OPT_fno_associative_math) + AssociativeMath = true; + bool ReciprocalMath = false; + if (Arg *A = Args.getLastArg( + options::OPT_ffast_math, FastMathAliasOption, + options::OPT_fno_fast_math, options::OPT_funsafe_math_optimizations, + options::OPT_fno_unsafe_math_optimizations, + options::OPT_freciprocal_math, options::OPT_fno_reciprocal_math)) + if (A->getOption().getID() != options::OPT_fno_fast_math && + A->getOption().getID() != options::OPT_fno_unsafe_math_optimizations && + A->getOption().getID() != options::OPT_fno_reciprocal_math) + ReciprocalMath = true; + bool SignedZeros = true; + if (Arg *A = Args.getLastArg( + options::OPT_ffast_math, FastMathAliasOption, + options::OPT_fno_fast_math, options::OPT_funsafe_math_optimizations, + options::OPT_fno_unsafe_math_optimizations, + options::OPT_fsigned_zeros, options::OPT_fno_signed_zeros)) + if (A->getOption().getID() != options::OPT_fno_fast_math && + A->getOption().getID() != options::OPT_fno_unsafe_math_optimizations && + A->getOption().getID() != options::OPT_fsigned_zeros) + SignedZeros = false; + bool TrappingMath = true; + if (Arg *A = Args.getLastArg( + options::OPT_ffast_math, FastMathAliasOption, + options::OPT_fno_fast_math, options::OPT_funsafe_math_optimizations, + options::OPT_fno_unsafe_math_optimizations, + options::OPT_ftrapping_math, options::OPT_fno_trapping_math)) + if (A->getOption().getID() != options::OPT_fno_fast_math && + A->getOption().getID() != options::OPT_fno_unsafe_math_optimizations && + A->getOption().getID() != options::OPT_ftrapping_math) + TrappingMath = false; + 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 (Arg *A = Args.getLastArg(options::OPT_ffast_math, FastMathAliasOption, + options::OPT_fno_fast_math, + options::OPT_funsafe_math_optimizations, + options::OPT_fno_unsafe_math_optimizations, + options::OPT_fdenormal_fp_math_EQ)) + if (A->getOption().getID() != options::OPT_fno_fast_math && + A->getOption().getID() != options::OPT_fno_unsafe_math_optimizations) + Args.AddLastArg(CmdArgs, options::OPT_fdenormal_fp_math_EQ); + + // Validate and pass through -fp-contract option. + if (Arg *A = Args.getLastArg(options::OPT_ffast_math, FastMathAliasOption, + options::OPT_fno_fast_math, + options::OPT_ffp_contract)) { + if (A->getOption().getID() == options::OPT_ffp_contract) { + StringRef Val = A->getValue(); + if (Val == "fast" || Val == "on" || Val == "off") { + CmdArgs.push_back(Args.MakeArgString("-ffp-contract=" + Val)); + } else { + D.Diag(diag::err_drv_unsupported_option_argument) + << A->getOption().getName() << Val; + } + } else if (A->getOption().matches(options::OPT_ffast_math) || + (OFastEnabled && A->getOption().matches(options::OPT_Ofast))) { + // If fast-math is set then set the fp-contract mode to fast. + CmdArgs.push_back(Args.MakeArgString("-ffp-contract=fast")); + } + } + + ParseMRecip(getToolChain().getDriver(), Args, CmdArgs); + + // We separately look for the '-ffast-math' and '-ffinite-math-only' flags, + // and if we find them, tell the frontend to provide the appropriate + // preprocessor macros. This is distinct from enabling any optimizations as + // these options induce language changes which must survive serialization + // and deserialization, etc. + if (Arg *A = Args.getLastArg(options::OPT_ffast_math, FastMathAliasOption, + options::OPT_fno_fast_math)) + if (!A->getOption().matches(options::OPT_fno_fast_math)) + CmdArgs.push_back("-ffast-math"); + if (Arg *A = Args.getLastArg(options::OPT_ffinite_math_only, + options::OPT_fno_fast_math)) + if (A->getOption().matches(options::OPT_ffinite_math_only)) + CmdArgs.push_back("-ffinite-math-only"); + + // Decide whether to use verbose asm. Verbose assembly is the default on + // toolchains which have the integrated assembler on by default. + bool IsIntegratedAssemblerDefault = + getToolChain().IsIntegratedAssemblerDefault(); + if (Args.hasFlag(options::OPT_fverbose_asm, options::OPT_fno_verbose_asm, + IsIntegratedAssemblerDefault) || + Args.hasArg(options::OPT_dA)) + CmdArgs.push_back("-masm-verbose"); + + if (!Args.hasFlag(options::OPT_fintegrated_as, options::OPT_fno_integrated_as, + IsIntegratedAssemblerDefault)) + CmdArgs.push_back("-no-integrated-as"); + + if (Args.hasArg(options::OPT_fdebug_pass_structure)) { + CmdArgs.push_back("-mdebug-pass"); + CmdArgs.push_back("Structure"); + } + if (Args.hasArg(options::OPT_fdebug_pass_arguments)) { + CmdArgs.push_back("-mdebug-pass"); + CmdArgs.push_back("Arguments"); + } + + // 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()) + 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()) + CmdArgs.push_back("-fforbid-guard-variables"); + + if (Args.hasFlag(options::OPT_mms_bitfields, options::OPT_mno_ms_bitfields, + false)) { + CmdArgs.push_back("-mms-bitfields"); + } + + if (Args.hasFlag(options::OPT_mpie_copy_relocations, + options::OPT_mno_pie_copy_relocations, + false)) { + CmdArgs.push_back("-mpie-copy-relocations"); + } + + // This is a coarse approximation of what llvm-gcc actually does, both + // -fasynchronous-unwind-tables and -fnon-call-exceptions interact in more + // complicated ways. + bool AsynchronousUnwindTables = + Args.hasFlag(options::OPT_fasynchronous_unwind_tables, + options::OPT_fno_asynchronous_unwind_tables, + (getToolChain().IsUnwindTablesDefault() || + getToolChain().getSanitizerArgs().needsUnwindTables()) && + !KernelOrKext); + if (Args.hasFlag(options::OPT_funwind_tables, options::OPT_fno_unwind_tables, + AsynchronousUnwindTables)) + CmdArgs.push_back("-munwind-tables"); + + getToolChain().addClangTargetOptions(Args, CmdArgs); + + if (Arg *A = Args.getLastArg(options::OPT_flimited_precision_EQ)) { + CmdArgs.push_back("-mlimit-float-precision"); + CmdArgs.push_back(A->getValue()); + } + + // FIXME: Handle -mtune=. + (void)Args.hasArg(options::OPT_mtune_EQ); + + if (Arg *A = Args.getLastArg(options::OPT_mcmodel_EQ)) { + CmdArgs.push_back("-mcode-model"); + CmdArgs.push_back(A->getValue()); + } + + // Add the target cpu + std::string CPU = getCPUName(Args, Triple, /*FromAs*/ false); + if (!CPU.empty()) { + CmdArgs.push_back("-target-cpu"); + 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; + } + + // 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()) + AddClangCLArgs(Args, InputType, CmdArgs, &DebugInfoKind, &EmitCodeView); + + // 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())) + 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() && + getToolChain().getArch() == llvm::Triple::x86) { + if ((Unsupported = Args.getLastArg(options::OPT_fapple_kext)) || + (Unsupported = Args.getLastArg(options::OPT_mkernel))) + D.Diag(diag::err_drv_clang_unsupported_opt_cxx_darwin_i386) + << Unsupported->getOption().getName(); + } + } + + Args.AddAllArgs(CmdArgs, options::OPT_v); + Args.AddLastArg(CmdArgs, options::OPT_H); + if (D.CCPrintHeaders && !D.CCGenDiagnostics) { + CmdArgs.push_back("-header-include-file"); + CmdArgs.push_back(D.CCPrintHeadersFilename ? D.CCPrintHeadersFilename + : "-"); + } + Args.AddLastArg(CmdArgs, options::OPT_P); + Args.AddLastArg(CmdArgs, options::OPT_print_ivar_layout); + + if (D.CCLogDiagnostics && !D.CCGenDiagnostics) { + CmdArgs.push_back("-diagnostic-log-file"); + CmdArgs.push_back(D.CCLogDiagnosticsFilename ? D.CCLogDiagnosticsFilename + : "-"); + } + + 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 flags -gstrict-dwarf and -grecord-gcc-switches for now. + 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() && SplitDwarfArg) { + if (!splitDwarfInlining) + CmdArgs.push_back("-fno-split-dwarf-inlining"); + if (DebugInfoKind == codegenoptions::NoDebugInfo) + DebugInfoKind = codegenoptions::LimitedDebugInfo; + CmdArgs.push_back("-backend-option"); + CmdArgs.push_back("-split-dwarf=Enable"); + } + + // 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"); + } + + bool UseSeparateSections = isUseSeparateSections(Triple); + + if (Args.hasFlag(options::OPT_ffunction_sections, + options::OPT_fno_function_sections, UseSeparateSections)) { + CmdArgs.push_back("-ffunction-sections"); + } + + if (Args.hasFlag(options::OPT_fdata_sections, options::OPT_fno_data_sections, + UseSeparateSections)) { + CmdArgs.push_back("-fdata-sections"); + } + + if (!Args.hasFlag(options::OPT_funique_section_names, + options::OPT_fno_unique_section_names, true)) + CmdArgs.push_back("-fno-unique-section-names"); + + Args.AddAllArgs(CmdArgs, options::OPT_finstrument_functions); + + if (Args.hasFlag(options::OPT_fxray_instrument, + options::OPT_fnoxray_instrument, false)) { + const char *const XRayInstrumentOption = "-fxray-instrument"; + if (Triple.getOS() == llvm::Triple::Linux) + switch (Triple.getArch()) { + case llvm::Triple::x86_64: + case llvm::Triple::arm: + case llvm::Triple::aarch64: + case llvm::Triple::ppc64le: + case llvm::Triple::mips: + case llvm::Triple::mipsel: + case llvm::Triple::mips64: + case llvm::Triple::mips64el: + // Supported. + break; + default: + D.Diag(diag::err_drv_clang_unsupported) + << (std::string(XRayInstrumentOption) + " on " + Triple.str()); + } + else + D.Diag(diag::err_drv_clang_unsupported) + << (std::string(XRayInstrumentOption) + " on non-Linux target OS"); + CmdArgs.push_back(XRayInstrumentOption); + if (const Arg *A = + Args.getLastArg(options::OPT_fxray_instruction_threshold_, + options::OPT_fxray_instruction_threshold_EQ)) { + CmdArgs.push_back("-fxray-instruction-threshold"); + CmdArgs.push_back(A->getValue()); + } + } + + addPGOAndCoverageFlags(C, D, Output, Args, CmdArgs); + + // Add runtime flag for PS4 when PGO or Coverage are enabled. + if (getToolChain().getTriple().isPS4CPU()) + PS4cpu::addProfileRTArgs(getToolChain(), Args, CmdArgs); + + // Pass options for controlling the default header search paths. + if (Args.hasArg(options::OPT_nostdinc)) { + CmdArgs.push_back("-nostdsysteminc"); + CmdArgs.push_back("-nobuiltininc"); + } else { + if (Args.hasArg(options::OPT_nostdlibinc)) + CmdArgs.push_back("-nostdsysteminc"); + Args.AddLastArg(CmdArgs, options::OPT_nostdincxx); + Args.AddLastArg(CmdArgs, options::OPT_nobuiltininc); + } + + // Pass the path to compiler resource files. + CmdArgs.push_back("-resource-dir"); + CmdArgs.push_back(D.ResourceDir.c_str()); + + 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); + } + + // Add preprocessing options like -I, -D, etc. if we are using the + // preprocessor. + // + // FIXME: Support -fpreprocessed + if (types::getPreprocessedType(InputType) != types::TY_INVALID) + AddPreprocessingOptions(C, JA, D, Args, CmdArgs, Output, Inputs); + + // Don't warn about "clang -c -DPIC -fPIC test.i" because libtool.m4 assumes + // that "The compiler can only warn and ignore the option if not recognized". + // When building with ccache, it will pass -D options to clang even on + // preprocessed inputs and configure concludes that -fPIC is not supported. + Args.ClaimAllArgs(options::OPT_D); + + // Manually translate -O4 to -O3; let clang reject others. + if (Arg *A = Args.getLastArg(options::OPT_O_Group)) { + if (A->getOption().matches(options::OPT_O4)) { + CmdArgs.push_back("-O3"); + D.Diag(diag::warn_O4_is_O3); + } else { + A->render(Args, CmdArgs); + } + } + + // Warn about ignored options to clang. + for (const Arg *A : + Args.filtered(options::OPT_clang_ignored_gcc_optimization_f_Group)) { + D.Diag(diag::warn_ignored_gcc_optimization) << A->getAsString(Args); + A->claim(); + } + + claimNoWarnArgs(Args); + + Args.AddAllArgs(CmdArgs, options::OPT_R_Group); + + Args.AddAllArgs(CmdArgs, options::OPT_W_Group); + if (Args.hasFlag(options::OPT_pedantic, options::OPT_no_pedantic, false)) + CmdArgs.push_back("-pedantic"); + Args.AddLastArg(CmdArgs, options::OPT_pedantic_errors); + Args.AddLastArg(CmdArgs, options::OPT_w); + + // Handle -{std, ansi, trigraphs} -- take the last of -{std, ansi} + // (-ansi is equivalent to -std=c89 or -std=c++98). + // + // If a std is supplied, only add -trigraphs if it follows the + // option. + bool ImplyVCPPCXXVer = false; + if (Arg *Std = Args.getLastArg(options::OPT_std_EQ, options::OPT_ansi)) { + if (Std->getOption().matches(options::OPT_ansi)) + if (types::isCXX(InputType)) + CmdArgs.push_back("-std=c++98"); + else + CmdArgs.push_back("-std=c89"); + else + Std->render(Args, CmdArgs); + + // If -f(no-)trigraphs appears after the language standard flag, honor it. + if (Arg *A = Args.getLastArg(options::OPT_std_EQ, options::OPT_ansi, + options::OPT_ftrigraphs, + options::OPT_fno_trigraphs)) + if (A != Std) + A->render(Args, CmdArgs); + } else { + // Honor -std-default. + // + // FIXME: Clang doesn't correctly handle -std= when the input language + // doesn't match. For the time being just ignore this for C++ inputs; + // eventually we want to do all the standard defaulting here instead of + // splitting it between the driver and clang -cc1. + if (!types::isCXX(InputType)) + Args.AddAllArgsTranslated(CmdArgs, options::OPT_std_default_EQ, "-std=", + /*Joined=*/true); + else if (IsWindowsMSVC) + ImplyVCPPCXXVer = true; + + Args.AddLastArg(CmdArgs, options::OPT_ftrigraphs, + options::OPT_fno_trigraphs); + } + + // GCC's behavior for -Wwrite-strings is a bit strange: + // * In C, this "warning flag" changes the types of string literals from + // 'char[N]' to 'const char[N]', and thus triggers an unrelated warning + // for the discarded qualifier. + // * In C++, this is just a normal warning flag. + // + // Implementing this warning correctly in C is hard, so we follow GCC's + // behavior for now. FIXME: Directly diagnose uses of a string literal as + // a non-const char* in C, rather than using this crude hack. + if (!types::isCXX(InputType)) { + // FIXME: This should behave just like a warning flag, and thus should also + // respect -Weverything, -Wno-everything, -Werror=write-strings, and so on. + Arg *WriteStrings = + Args.getLastArg(options::OPT_Wwrite_strings, + options::OPT_Wno_write_strings, options::OPT_w); + if (WriteStrings && + WriteStrings->getOption().matches(options::OPT_Wwrite_strings)) + CmdArgs.push_back("-fconst-strings"); + } + + // GCC provides a macro definition '__DEPRECATED' when -Wdeprecated is active + // during C++ compilation, which it is by default. GCC keeps this define even + // in the presence of '-w', match this behavior bug-for-bug. + if (types::isCXX(InputType) && + Args.hasFlag(options::OPT_Wdeprecated, options::OPT_Wno_deprecated, + true)) { + CmdArgs.push_back("-fdeprecated-macro"); + } + + // Translate GCC's misnamer '-fasm' arguments to '-fgnu-keywords'. + if (Arg *Asm = Args.getLastArg(options::OPT_fasm, options::OPT_fno_asm)) { + if (Asm->getOption().matches(options::OPT_fasm)) + CmdArgs.push_back("-fgnu-keywords"); + else + CmdArgs.push_back("-fno-gnu-keywords"); + } + + if (ShouldDisableDwarfDirectory(Args, getToolChain())) + CmdArgs.push_back("-fno-dwarf-directory-asm"); + + if (ShouldDisableAutolink(Args, getToolChain())) + CmdArgs.push_back("-fno-autolink"); + + // Add in -fdebug-compilation-dir if necessary. + addDebugCompDirArg(Args, CmdArgs); + + for (const Arg *A : Args.filtered(options::OPT_fdebug_prefix_map_EQ)) { + StringRef Map = A->getValue(); + if (Map.find('=') == StringRef::npos) + D.Diag(diag::err_drv_invalid_argument_to_fdebug_prefix_map) << Map; + else + CmdArgs.push_back(Args.MakeArgString("-fdebug-prefix-map=" + Map)); + A->claim(); + } + + if (Arg *A = Args.getLastArg(options::OPT_ftemplate_depth_, + options::OPT_ftemplate_depth_EQ)) { + CmdArgs.push_back("-ftemplate-depth"); + CmdArgs.push_back(A->getValue()); + } + + if (Arg *A = Args.getLastArg(options::OPT_foperator_arrow_depth_EQ)) { + CmdArgs.push_back("-foperator-arrow-depth"); + CmdArgs.push_back(A->getValue()); + } + + if (Arg *A = Args.getLastArg(options::OPT_fconstexpr_depth_EQ)) { + CmdArgs.push_back("-fconstexpr-depth"); + CmdArgs.push_back(A->getValue()); + } + + if (Arg *A = Args.getLastArg(options::OPT_fconstexpr_steps_EQ)) { + CmdArgs.push_back("-fconstexpr-steps"); + CmdArgs.push_back(A->getValue()); + } + + if (Arg *A = Args.getLastArg(options::OPT_fbracket_depth_EQ)) { + CmdArgs.push_back("-fbracket-depth"); + CmdArgs.push_back(A->getValue()); + } + + if (Arg *A = Args.getLastArg(options::OPT_Wlarge_by_value_copy_EQ, + options::OPT_Wlarge_by_value_copy_def)) { + if (A->getNumValues()) { + StringRef bytes = A->getValue(); + CmdArgs.push_back(Args.MakeArgString("-Wlarge-by-value-copy=" + bytes)); + } else + CmdArgs.push_back("-Wlarge-by-value-copy=64"); // default value + } + + if (Args.hasArg(options::OPT_relocatable_pch)) + CmdArgs.push_back("-relocatable-pch"); + + if (Arg *A = Args.getLastArg(options::OPT_fconstant_string_class_EQ)) { + CmdArgs.push_back("-fconstant-string-class"); + CmdArgs.push_back(A->getValue()); + } + + if (Arg *A = Args.getLastArg(options::OPT_ftabstop_EQ)) { + CmdArgs.push_back("-ftabstop"); + CmdArgs.push_back(A->getValue()); + } + + CmdArgs.push_back("-ferror-limit"); + if (Arg *A = Args.getLastArg(options::OPT_ferror_limit_EQ)) + CmdArgs.push_back(A->getValue()); + else + CmdArgs.push_back("19"); + + if (Arg *A = Args.getLastArg(options::OPT_fmacro_backtrace_limit_EQ)) { + CmdArgs.push_back("-fmacro-backtrace-limit"); + CmdArgs.push_back(A->getValue()); + } + + if (Arg *A = Args.getLastArg(options::OPT_ftemplate_backtrace_limit_EQ)) { + CmdArgs.push_back("-ftemplate-backtrace-limit"); + CmdArgs.push_back(A->getValue()); + } + + if (Arg *A = Args.getLastArg(options::OPT_fconstexpr_backtrace_limit_EQ)) { + CmdArgs.push_back("-fconstexpr-backtrace-limit"); + CmdArgs.push_back(A->getValue()); + } + + if (Arg *A = Args.getLastArg(options::OPT_fspell_checking_limit_EQ)) { + CmdArgs.push_back("-fspell-checking-limit"); + CmdArgs.push_back(A->getValue()); + } + + // Pass -fmessage-length=. + CmdArgs.push_back("-fmessage-length"); + if (Arg *A = Args.getLastArg(options::OPT_fmessage_length_EQ)) { + CmdArgs.push_back(A->getValue()); + } else { + // If -fmessage-length=N was not specified, determine whether this is a + // terminal and, if so, implicitly define -fmessage-length appropriately. + unsigned N = llvm::sys::Process::StandardErrColumns(); + CmdArgs.push_back(Args.MakeArgString(Twine(N))); + } + + // -fvisibility= and -fvisibility-ms-compat are of a piece. + if (const Arg *A = Args.getLastArg(options::OPT_fvisibility_EQ, + options::OPT_fvisibility_ms_compat)) { + if (A->getOption().matches(options::OPT_fvisibility_EQ)) { + CmdArgs.push_back("-fvisibility"); + CmdArgs.push_back(A->getValue()); + } else { + assert(A->getOption().matches(options::OPT_fvisibility_ms_compat)); + CmdArgs.push_back("-fvisibility"); + CmdArgs.push_back("hidden"); + CmdArgs.push_back("-ftype-visibility"); + CmdArgs.push_back("default"); + } + } + + Args.AddLastArg(CmdArgs, options::OPT_fvisibility_inlines_hidden); + + 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); + Args.AddLastArg(CmdArgs, options::OPT_fno_operator_names); + // Emulated TLS is enabled by default on Android, and can be enabled manually + // with -femulated-tls. + bool EmulatedTLSDefault = Triple.isAndroid() || Triple.isWindowsCygwinEnvironment(); + if (Args.hasFlag(options::OPT_femulated_tls, options::OPT_fno_emulated_tls, + EmulatedTLSDefault)) + CmdArgs.push_back("-femulated-tls"); + // AltiVec-like language extensions aren't relevant for assembling. + if (!isa<PreprocessJobAction>(JA) || Output.getType() != types::TY_PP_Asm) { + Args.AddLastArg(CmdArgs, options::OPT_faltivec); + Args.AddLastArg(CmdArgs, options::OPT_fzvector); + } + Args.AddLastArg(CmdArgs, options::OPT_fdiagnostics_show_template_tree); + Args.AddLastArg(CmdArgs, options::OPT_fno_elide_type); + + // Forward flags for OpenMP. We don't do this if the current action is an + // device offloading action other than OpenMP. + if (Args.hasFlag(options::OPT_fopenmp, options::OPT_fopenmp_EQ, + options::OPT_fno_openmp, false) && + (JA.isDeviceOffloading(Action::OFK_None) || + JA.isDeviceOffloading(Action::OFK_OpenMP))) { + switch (getToolChain().getDriver().getOpenMPRuntime(Args)) { + case Driver::OMPRT_OMP: + case Driver::OMPRT_IOMP5: + // Clang can generate useful OpenMP code for these two runtime libraries. + CmdArgs.push_back("-fopenmp"); + + // If no option regarding the use of TLS in OpenMP codegeneration is + // given, decide a default based on the target. Otherwise rely on the + // options and pass the right information to the frontend. + if (!Args.hasFlag(options::OPT_fopenmp_use_tls, + options::OPT_fnoopenmp_use_tls, /*Default=*/true)) + CmdArgs.push_back("-fnoopenmp-use-tls"); + Args.AddAllArgs(CmdArgs, options::OPT_fopenmp_version_EQ); + break; + default: + // By default, if Clang doesn't know how to generate useful OpenMP code + // for a specific runtime library, we just don't pass the '-fopenmp' flag + // down to the actual compilation. + // FIXME: It would be better to have a mode which *only* omits IR + // generation based on the OpenMP support so that we get consistent + // semantic analysis, etc. + break; + } + } + + const SanitizerArgs &Sanitize = getToolChain().getSanitizerArgs(); + Sanitize.addArgs(getToolChain(), Args, CmdArgs, InputType); + + // Report an error for -faltivec on anything other than PowerPC. + if (const Arg *A = Args.getLastArg(options::OPT_faltivec)) { + const llvm::Triple::ArchType Arch = getToolChain().getArch(); + if (!(Arch == llvm::Triple::ppc || Arch == llvm::Triple::ppc64 || + Arch == llvm::Triple::ppc64le)) + D.Diag(diag::err_drv_argument_only_allowed_with) << A->getAsString(Args) + << "ppc/ppc64/ppc64le"; + } + + // -fzvector is incompatible with -faltivec. + if (Arg *A = Args.getLastArg(options::OPT_fzvector)) + if (Args.hasArg(options::OPT_faltivec)) + D.Diag(diag::err_drv_argument_not_allowed_with) << A->getAsString(Args) + << "-faltivec"; + + if (getToolChain().SupportsProfiling()) + Args.AddLastArg(CmdArgs, options::OPT_pg); + + if (getToolChain().SupportsProfiling()) + Args.AddLastArg(CmdArgs, options::OPT_mfentry); + + // -flax-vector-conversions is default. + if (!Args.hasFlag(options::OPT_flax_vector_conversions, + options::OPT_fno_lax_vector_conversions)) + CmdArgs.push_back("-fno-lax-vector-conversions"); + + if (Args.getLastArg(options::OPT_fapple_kext) || + (Args.hasArg(options::OPT_mkernel) && types::isCXX(InputType))) + CmdArgs.push_back("-fapple-kext"); + + Args.AddLastArg(CmdArgs, options::OPT_fobjc_sender_dependent_dispatch); + Args.AddLastArg(CmdArgs, options::OPT_fdiagnostics_print_source_range_info); + Args.AddLastArg(CmdArgs, options::OPT_fdiagnostics_parseable_fixits); + Args.AddLastArg(CmdArgs, options::OPT_ftime_report); + Args.AddLastArg(CmdArgs, options::OPT_ftrapv); + + if (Arg *A = Args.getLastArg(options::OPT_ftrapv_handler_EQ)) { + CmdArgs.push_back("-ftrapv-handler"); + CmdArgs.push_back(A->getValue()); + } + + Args.AddLastArg(CmdArgs, options::OPT_ftrap_function_EQ); + + // -fno-strict-overflow implies -fwrapv if it isn't disabled, but + // -fstrict-overflow won't turn off an explicitly enabled -fwrapv. + if (Arg *A = Args.getLastArg(options::OPT_fwrapv, options::OPT_fno_wrapv)) { + if (A->getOption().matches(options::OPT_fwrapv)) + CmdArgs.push_back("-fwrapv"); + } else if (Arg *A = Args.getLastArg(options::OPT_fstrict_overflow, + options::OPT_fno_strict_overflow)) { + if (A->getOption().matches(options::OPT_fno_strict_overflow)) + CmdArgs.push_back("-fwrapv"); + } + + if (Arg *A = Args.getLastArg(options::OPT_freroll_loops, + options::OPT_fno_reroll_loops)) + if (A->getOption().matches(options::OPT_freroll_loops)) + CmdArgs.push_back("-freroll-loops"); + + Args.AddLastArg(CmdArgs, options::OPT_fwritable_strings); + Args.AddLastArg(CmdArgs, options::OPT_funroll_loops, + options::OPT_fno_unroll_loops); + + 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(); + } + } + + // Translate -mstackrealign + if (Args.hasFlag(options::OPT_mstackrealign, options::OPT_mno_stackrealign, + false)) + CmdArgs.push_back(Args.MakeArgString("-mstackrealign")); + + if (Args.hasArg(options::OPT_mstack_alignment)) { + StringRef alignment = Args.getLastArgValue(options::OPT_mstack_alignment); + CmdArgs.push_back(Args.MakeArgString("-mstack-alignment=" + alignment)); + } + + if (Args.hasArg(options::OPT_mstack_probe_size)) { + StringRef Size = Args.getLastArgValue(options::OPT_mstack_probe_size); + + if (!Size.empty()) + CmdArgs.push_back(Args.MakeArgString("-mstack-probe-size=" + Size)); + else + 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)) { + CmdArgs.push_back("-backend-option"); + CmdArgs.push_back("-arm-restrict-it"); + } else { + CmdArgs.push_back("-backend-option"); + CmdArgs.push_back("-arm-no-restrict-it"); + } + } else if (Triple.isOSWindows() && + (Triple.getArch() == llvm::Triple::arm || + Triple.getArch() == llvm::Triple::thumb)) { + // Windows on ARM expects restricted IT blocks + CmdArgs.push_back("-backend-option"); + CmdArgs.push_back("-arm-restrict-it"); + } + + // 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"); + } + + // Forward -f options with positive and negative forms; we translate + // these by hand. + if (Arg *A = Args.getLastArg(options::OPT_fprofile_sample_use_EQ)) { + StringRef fname = A->getValue(); + if (!llvm::sys::fs::exists(fname)) + D.Diag(diag::err_drv_no_such_file) << fname; + else + 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)); + } + + if (!Args.hasFlag(options::OPT_fassume_sane_operator_new, + options::OPT_fno_assume_sane_operator_new)) + CmdArgs.push_back("-fno-assume-sane-operator-new"); + + // -fblocks=0 is default. + if (Args.hasFlag(options::OPT_fblocks, options::OPT_fno_blocks, + getToolChain().IsBlocksDefault()) || + (Args.hasArg(options::OPT_fgnu_runtime) && + Args.hasArg(options::OPT_fobjc_nonfragile_abi) && + !Args.hasArg(options::OPT_fno_blocks))) { + CmdArgs.push_back("-fblocks"); + + if (!Args.hasArg(options::OPT_fgnu_runtime) && + !getToolChain().hasBlocksRuntime()) + CmdArgs.push_back("-fblocks-runtime-optional"); + } + + 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())); + } + + // -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); + + // -faccess-control is default. + if (Args.hasFlag(options::OPT_fno_access_control, + options::OPT_faccess_control, false)) + CmdArgs.push_back("-fno-access-control"); + + // -felide-constructors is the default. + if (Args.hasFlag(options::OPT_fno_elide_constructors, + options::OPT_felide_constructors, false)) + CmdArgs.push_back("-fno-elide-constructors"); + + ToolChain::RTTIMode RTTIMode = getToolChain().getRTTIMode(); + + if (KernelOrKext || (types::isCXX(InputType) && + (RTTIMode == ToolChain::RM_DisabledExplicitly || + RTTIMode == ToolChain::RM_DisabledImplicitly))) + CmdArgs.push_back("-fno-rtti"); + + // -fshort-enums=0 is default for all architectures except Hexagon. + if (Args.hasFlag(options::OPT_fshort_enums, options::OPT_fno_short_enums, + 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"); + } + + // -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 && + getToolChain().getArch() != llvm::Triple::hexagon && + getToolChain().getArch() != llvm::Triple::xcore && + ((getToolChain().getTriple().getVendor() != + llvm::Triple::MipsTechnologies) || + getToolChain().getTriple().hasEnvironment())) || + KernelOrKext) + CmdArgs.push_back("-fno-use-cxa-atexit"); + + // -fms-extensions=0 is default. + if (Args.hasFlag(options::OPT_fms_extensions, options::OPT_fno_ms_extensions, + IsWindowsMSVC)) + CmdArgs.push_back("-fms-extensions"); + + // -fno-use-line-directives is default. + if (Args.hasFlag(options::OPT_fuse_line_directives, + options::OPT_fno_use_line_directives, false)) + CmdArgs.push_back("-fuse-line-directives"); + + // -fms-compatibility=0 is default. + if (Args.hasFlag(options::OPT_fms_compatibility, + options::OPT_fno_ms_compatibility, + (IsWindowsMSVC && + Args.hasFlag(options::OPT_fms_extensions, + options::OPT_fno_ms_extensions, true)))) + CmdArgs.push_back("-fms-compatibility"); + + VersionTuple MSVT = + getToolChain().computeMSVCVersion(&getToolChain().getDriver(), Args); + if (!MSVT.empty()) + CmdArgs.push_back( + Args.MakeArgString("-fms-compatibility-version=" + MSVT.getAsString())); + + bool IsMSVC2015Compatible = MSVT.getMajor() >= 19; + if (ImplyVCPPCXXVer) { + StringRef LanguageStandard; + 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") + .Default(""); + if (LanguageStandard.empty()) + D.Diag(clang::diag::warn_drv_unused_argument) + << StdArg->getAsString(Args); + } + + if (LanguageStandard.empty()) { + if (IsMSVC2015Compatible) + LanguageStandard = "-std=c++14"; + else + LanguageStandard = "-std=c++11"; + } + + CmdArgs.push_back(LanguageStandard.data()); + } + + // -fno-borland-extensions is default. + if (Args.hasFlag(options::OPT_fborland_extensions, + options::OPT_fno_borland_extensions, false)) + CmdArgs.push_back("-fborland-extensions"); + + // -fno-declspec is default, except for PS4. + if (Args.hasFlag(options::OPT_fdeclspec, options::OPT_fno_declspec, + getToolChain().getTriple().isPS4())) + CmdArgs.push_back("-fdeclspec"); + else if (Args.hasArg(options::OPT_fno_declspec)) + CmdArgs.push_back("-fno-declspec"); // Explicitly disabling __declspec. + + // -fthreadsafe-static is default, except for MSVC compatibility versions less + // than 19. + if (!Args.hasFlag(options::OPT_fthreadsafe_statics, + options::OPT_fno_threadsafe_statics, + !IsWindowsMSVC || IsMSVC2015Compatible)) + CmdArgs.push_back("-fno-threadsafe-statics"); + + // -fno-delayed-template-parsing is default, except for Windows where MSVC STL + // needs it. + if (Args.hasFlag(options::OPT_fdelayed_template_parsing, + options::OPT_fno_delayed_template_parsing, IsWindowsMSVC)) + CmdArgs.push_back("-fdelayed-template-parsing"); + + // -fgnu-keywords default varies depending on language; only pass if + // specified. + if (Arg *A = Args.getLastArg(options::OPT_fgnu_keywords, + options::OPT_fno_gnu_keywords)) + A->render(Args, CmdArgs); + + if (Args.hasFlag(options::OPT_fgnu89_inline, options::OPT_fno_gnu89_inline, + false)) + CmdArgs.push_back("-fgnu89-inline"); + + if (Args.hasArg(options::OPT_fno_inline)) + CmdArgs.push_back("-fno-inline"); + + if (Arg* InlineArg = Args.getLastArg(options::OPT_finline_functions, + options::OPT_finline_hint_functions, + options::OPT_fno_inline_functions)) + InlineArg->render(Args, CmdArgs); + + 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); + } + } + + if (Args.hasFlag(options::OPT_fapplication_extension, + options::OPT_fno_application_extension, false)) + CmdArgs.push_back("-fapplication-extension"); + + // Handle GCC-style exception args. + if (!C.getDriver().IsCLMode()) + addExceptionArgs(Args, InputType, getToolChain(), KernelOrKext, objcRuntime, + CmdArgs); + + if (Args.hasArg(options::OPT_fsjlj_exceptions) || + getToolChain().UseSjLjExceptions(Args)) + CmdArgs.push_back("-fsjlj-exceptions"); + + // C++ "sane" operator new. + if (!Args.hasFlag(options::OPT_fassume_sane_operator_new, + options::OPT_fno_assume_sane_operator_new)) + CmdArgs.push_back("-fno-assume-sane-operator-new"); + + // -frelaxed-template-template-args is off by default, as it is a severe + // breaking change until a corresponding change to template partial ordering + // is provided. + if (Args.hasFlag(options::OPT_frelaxed_template_template_args, + options::OPT_fno_relaxed_template_template_args, false)) + CmdArgs.push_back("-frelaxed-template-template-args"); + + // -fsized-deallocation is off by default, as it is an ABI-breaking change for + // most platforms. + if (Args.hasFlag(options::OPT_fsized_deallocation, + options::OPT_fno_sized_deallocation, false)) + CmdArgs.push_back("-fsized-deallocation"); + + // -faligned-allocation is on by default in C++17 onwards and otherwise off + // by default. + if (Arg *A = Args.getLastArg(options::OPT_faligned_allocation, + options::OPT_fno_aligned_allocation, + options::OPT_faligned_new_EQ)) { + if (A->getOption().matches(options::OPT_fno_aligned_allocation)) + CmdArgs.push_back("-fno-aligned-allocation"); + else + CmdArgs.push_back("-faligned-allocation"); + } + + // The default new alignment can be specified using a dedicated option or via + // a GCC-compatible option that also turns on aligned allocation. + if (Arg *A = Args.getLastArg(options::OPT_fnew_alignment_EQ, + options::OPT_faligned_new_EQ)) + CmdArgs.push_back( + Args.MakeArgString(Twine("-fnew-alignment=") + A->getValue())); + + // -fconstant-cfstrings is default, and may be subject to argument translation + // on Darwin. + if (!Args.hasFlag(options::OPT_fconstant_cfstrings, + options::OPT_fno_constant_cfstrings) || + !Args.hasFlag(options::OPT_mconstant_cfstrings, + 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)) + CmdArgs.push_back("-fpascal-strings"); + + // Honor -fpack-struct= and -fpack-struct, if given. Note that + // -fno-pack-struct doesn't apply to -fpack-struct=. + if (Arg *A = Args.getLastArg(options::OPT_fpack_struct_EQ)) { + std::string PackStructStr = "-fpack-struct="; + PackStructStr += A->getValue(); + CmdArgs.push_back(Args.MakeArgString(PackStructStr)); + } else if (Args.hasFlag(options::OPT_fpack_struct, + options::OPT_fno_pack_struct, false)) { + CmdArgs.push_back("-fpack-struct=1"); + } + + // Handle -fmax-type-align=N and -fno-type-align + bool SkipMaxTypeAlign = Args.hasArg(options::OPT_fno_max_type_align); + if (Arg *A = Args.getLastArg(options::OPT_fmax_type_align_EQ)) { + if (!SkipMaxTypeAlign) { + std::string MaxTypeAlignStr = "-fmax-type-align="; + MaxTypeAlignStr += A->getValue(); + CmdArgs.push_back(Args.MakeArgString(MaxTypeAlignStr)); + } + } else if (getToolChain().getTriple().isOSDarwin()) { + if (!SkipMaxTypeAlign) { + std::string MaxTypeAlignStr = "-fmax-type-align=16"; + CmdArgs.push_back(Args.MakeArgString(MaxTypeAlignStr)); + } + } + + // -fcommon is the default unless compiling kernel code or the target says so + bool NoCommonDefault = + KernelOrKext || isNoCommonDefault(getToolChain().getTriple()); + if (!Args.hasFlag(options::OPT_fcommon, options::OPT_fno_common, + !NoCommonDefault)) + CmdArgs.push_back("-fno-common"); + + // -fsigned-bitfields is default, and clang doesn't yet support + // -funsigned-bitfields. + if (!Args.hasFlag(options::OPT_fsigned_bitfields, + options::OPT_funsigned_bitfields)) + D.Diag(diag::warn_drv_clang_unsupported) + << Args.getLastArg(options::OPT_funsigned_bitfields)->getAsString(Args); + + // -fsigned-bitfields is default, and clang doesn't support -fno-for-scope. + if (!Args.hasFlag(options::OPT_ffor_scope, options::OPT_fno_for_scope)) + D.Diag(diag::err_drv_clang_unsupported) + << Args.getLastArg(options::OPT_fno_for_scope)->getAsString(Args); + + // -finput_charset=UTF-8 is default. Reject others + if (Arg *inputCharset = Args.getLastArg(options::OPT_finput_charset_EQ)) { + StringRef value = inputCharset->getValue(); + if (!value.equals_lower("utf-8")) + D.Diag(diag::err_drv_invalid_value) << inputCharset->getAsString(Args) + << value; + } + + // -fexec_charset=UTF-8 is default. Reject others + if (Arg *execCharset = Args.getLastArg(options::OPT_fexec_charset_EQ)) { + StringRef value = execCharset->getValue(); + if (!value.equals_lower("utf-8")) + D.Diag(diag::err_drv_invalid_value) << execCharset->getAsString(Args) + << value; + } + + // -fcaret-diagnostics is default. + if (!Args.hasFlag(options::OPT_fcaret_diagnostics, + options::OPT_fno_caret_diagnostics, true)) + 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_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, + true)) + CmdArgs.push_back("-fno-show-column"); + + if (!Args.hasFlag(options::OPT_fspell_checking, + options::OPT_fno_spell_checking)) + CmdArgs.push_back("-fno-spell-checking"); + + // -fno-asm-blocks is default. + if (Args.hasFlag(options::OPT_fasm_blocks, options::OPT_fno_asm_blocks, + false)) + CmdArgs.push_back("-fasm-blocks"); + + // -fgnu-inline-asm is default. + if (!Args.hasFlag(options::OPT_fgnu_inline_asm, + options::OPT_fno_gnu_inline_asm, true)) + CmdArgs.push_back("-fno-gnu-inline-asm"); + + // Enable vectorization per default according to the optimization level + // selected. For optimization levels that want vectorization we use the alias + // option to simplify the hasFlag logic. + bool EnableVec = shouldEnableVectorizerAtOLevel(Args, false); + OptSpecifier VectorizeAliasOption = + EnableVec ? options::OPT_O_Group : options::OPT_fvectorize; + if (Args.hasFlag(options::OPT_fvectorize, VectorizeAliasOption, + options::OPT_fno_vectorize, EnableVec)) + CmdArgs.push_back("-vectorize-loops"); + + // -fslp-vectorize is enabled based on the optimization level selected. + bool EnableSLPVec = shouldEnableVectorizerAtOLevel(Args, true); + OptSpecifier SLPVectAliasOption = + EnableSLPVec ? options::OPT_O_Group : options::OPT_fslp_vectorize; + if (Args.hasFlag(options::OPT_fslp_vectorize, SLPVectAliasOption, + options::OPT_fno_slp_vectorize, EnableSLPVec)) + CmdArgs.push_back("-vectorize-slp"); + + // -fno-slp-vectorize-aggressive is default. + if (Args.hasFlag(options::OPT_fslp_vectorize_aggressive, + options::OPT_fno_slp_vectorize_aggressive, false)) + CmdArgs.push_back("-vectorize-slp-aggressive"); + + if (Arg *A = Args.getLastArg(options::OPT_fshow_overloads_EQ)) + A->render(Args, CmdArgs); + + if (Arg *A = Args.getLastArg( + options::OPT_fsanitize_undefined_strip_path_components_EQ)) + A->render(Args, CmdArgs); + + // -fdollars-in-identifiers default varies depending on platform and + // language; only pass if specified. + if (Arg *A = Args.getLastArg(options::OPT_fdollars_in_identifiers, + options::OPT_fno_dollars_in_identifiers)) { + if (A->getOption().matches(options::OPT_fdollars_in_identifiers)) + CmdArgs.push_back("-fdollars-in-identifiers"); + else + CmdArgs.push_back("-fno-dollars-in-identifiers"); + } + + // -funit-at-a-time is default, and we don't support -fno-unit-at-a-time for + // practical purposes. + if (Arg *A = Args.getLastArg(options::OPT_funit_at_a_time, + options::OPT_fno_unit_at_a_time)) { + if (A->getOption().matches(options::OPT_fno_unit_at_a_time)) + D.Diag(diag::warn_drv_clang_unsupported) << A->getAsString(Args); + } + + if (Args.hasFlag(options::OPT_fapple_pragma_pack, + 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"); + + const Arg *A = Args.getLastArg(options::OPT_foptimization_record_file_EQ); + if (A) { + 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 { + // Use the input filename. + F = llvm::sys::path::stem(Input.getBaseInput()); + + // If we're compiling for an offload architecture (i.e. a CUDA device), + // we need to make the file name for the device compilation different + // from the host compilation. + if (!JA.isDeviceOffloading(Action::OFK_None) && + !JA.isDeviceOffloading(Action::OFK_Host)) { + llvm::sys::path::replace_extension(F, ""); + F += Action::GetOffloadingFileNamePrefix(JA.getOffloadingDeviceKind(), + Triple.normalize()); + F += "-"; + F += JA.getOffloadingArch(); + } + } + + llvm::sys::path::replace_extension(F, "opt.yaml"); + CmdArgs.push_back(Args.MakeArgString(F)); + } + } + +// 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 + + // Enable rewrite includes if the user's asked for it or if we're generating + // diagnostics. + // TODO: Once -module-dependency-dir works with -frewrite-includes it'd be + // 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() && !HaveAnyModules)) + CmdArgs.push_back("-frewrite-includes"); + + // Only allow -traditional or -traditional-cpp outside in preprocessing modes. + if (Arg *A = Args.getLastArg(options::OPT_traditional, + options::OPT_traditional_cpp)) { + if (isa<PreprocessJobAction>(JA)) + CmdArgs.push_back("-traditional-cpp"); + else + D.Diag(diag::err_drv_clang_unsupported) << A->getAsString(Args); + } + + Args.AddLastArg(CmdArgs, options::OPT_dM); + Args.AddLastArg(CmdArgs, options::OPT_dD); + + // Handle serialized diagnostics. + if (Arg *A = Args.getLastArg(options::OPT__serialize_diags)) { + CmdArgs.push_back("-serialize-diagnostic-file"); + CmdArgs.push_back(Args.MakeArgString(A->getValue())); + } + + if (Args.hasArg(options::OPT_fretain_comments_from_system_headers)) + CmdArgs.push_back("-fretain-comments-from-system-headers"); + + // Forward -fcomment-block-commands to -cc1. + Args.AddAllArgs(CmdArgs, options::OPT_fcomment_block_commands); + // Forward -fparse-all-comments to -cc1. + Args.AddAllArgs(CmdArgs, options::OPT_fparse_all_comments); + + // Turn -fplugin=name.so into -load name.so + for (const Arg *A : Args.filtered(options::OPT_fplugin_EQ)) { + CmdArgs.push_back("-load"); + CmdArgs.push_back(A->getValue()); + A->claim(); + } + + // Setup statistics file output. + if (const Arg *A = Args.getLastArg(options::OPT_save_stats_EQ)) { + StringRef SaveStats = A->getValue(); + + SmallString<128> StatsFile; + bool DoSaveStats = false; + if (SaveStats == "obj") { + if (Output.isFilename()) { + StatsFile.assign(Output.getFilename()); + llvm::sys::path::remove_filename(StatsFile); + } + DoSaveStats = true; + } else if (SaveStats == "cwd") { + DoSaveStats = true; + } else { + D.Diag(diag::err_drv_invalid_value) << A->getAsString(Args) << SaveStats; + } + + if (DoSaveStats) { + StringRef BaseName = llvm::sys::path::filename(Input.getBaseInput()); + llvm::sys::path::append(StatsFile, BaseName); + llvm::sys::path::replace_extension(StatsFile, "stats"); + CmdArgs.push_back(Args.MakeArgString(Twine("-stats-file=") + + StatsFile)); + } + } + + // Forward -Xclang arguments to -cc1, and -mllvm arguments to the LLVM option + // parser. + Args.AddAllArgValues(CmdArgs, options::OPT_Xclang); + for (const Arg *A : Args.filtered(options::OPT_mllvm)) { + A->claim(); + + // We translate this by hand to the -cc1 argument, since nightly test uses + // it and developers have been trained to spell it with -mllvm. Both + // spellings are now deprecated and should be removed. + if (StringRef(A->getValue(0)) == "-disable-llvm-optzns") { + CmdArgs.push_back("-disable-llvm-optzns"); + } else { + A->render(Args, CmdArgs); + } + } + + // With -save-temps, we want to save the unoptimized bitcode output from the + // CompileJobAction, use -disable-llvm-passes to get pristine IR generated + // by the frontend. + // When -fembed-bitcode is enabled, optimized bitcode is emitted because it + // has slightly different breakdown between stages. + // FIXME: -fembed-bitcode -save-temps will save optimized bitcode instead of + // pristine IR generated by the frontend. Ideally, a new compile action should + // be added so both IR can be captured. + if (C.getDriver().isSaveTempsEnabled() && + !(C.getDriver().embedBitcodeInObject() && !C.getDriver().isUsingLTO()) && + isa<CompileJobAction>(JA)) + CmdArgs.push_back("-disable-llvm-passes"); + + if (Output.getType() == types::TY_Dependencies) { + // Handled with other dependency code. + } else if (Output.isFilename()) { + CmdArgs.push_back("-o"); + CmdArgs.push_back(Output.getFilename()); + } else { + assert(Output.isNothing() && "Invalid output."); + } + + addDashXForInput(Args, Input, CmdArgs); + + if (Input.isFilename()) + CmdArgs.push_back(Input.getFilename()); + else + Input.getInputArg().renderAsInput(Args, CmdArgs); + + Args.AddAllArgs(CmdArgs, options::OPT_undef); + + const char *Exec = getToolChain().getDriver().getClangProgramPath(); + + // Optionally embed the -cc1 level arguments into the debug info, for build + // analysis. + if (getToolChain().UseDwarfDebugFlags()) { + ArgStringList OriginalArgs; + for (const auto &Arg : Args) + Arg->render(Args, OriginalArgs); + + SmallString<256> Flags; + Flags += Exec; + for (const char *OriginalArg : OriginalArgs) { + SmallString<128> EscapedArg; + EscapeSpacesAndBackslashes(OriginalArg, EscapedArg); + Flags += " "; + Flags += EscapedArg; + } + CmdArgs.push_back("-dwarf-debug-flags"); + 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) + for (auto I = std::next(Inputs.begin()), E = Inputs.end(); I != E; ++I) { + CmdArgs.push_back("-fcuda-include-gpubinary"); + CmdArgs.push_back(I->getFilename()); + } + + // OpenMP offloading device jobs take the argument -fopenmp-host-ir-file-path + // to specify the result of the compile phase on the host, so the meaningful + // device declarations can be identified. Also, -fopenmp-is-device is passed + // along to tell the frontend that it is generating code for a device, so that + // only the relevant declarations are emitted. + if (IsOpenMPDevice && Inputs.size() == 2) { + CmdArgs.push_back("-fopenmp-is-device"); + CmdArgs.push_back("-fopenmp-host-ir-file-path"); + CmdArgs.push_back(Args.MakeArgString(Inputs.back().getFilename())); + } + + // For all the host OpenMP offloading compile jobs we need to pass the targets + // information using -fopenmp-targets= option. + if (isa<CompileJobAction>(JA) && JA.isHostOffloading(Action::OFK_OpenMP)) { + SmallString<128> TargetInfo("-fopenmp-targets="); + + Arg *Tgts = Args.getLastArg(options::OPT_fopenmp_targets_EQ); + assert(Tgts && Tgts->getNumValues() && + "OpenMP offloading has to have targets specified."); + for (unsigned i = 0; i < Tgts->getNumValues(); ++i) { + if (i) + TargetInfo += ','; + // We need to get the string from the triple because it may be not exactly + // the same as the one we get directly from the arguments. + llvm::Triple T(Tgts->getValue(i)); + TargetInfo += T.getTriple(); + } + CmdArgs.push_back(Args.MakeArgString(TargetInfo.str())); + } + + bool WholeProgramVTables = + Args.hasFlag(options::OPT_fwhole_program_vtables, + options::OPT_fno_whole_program_vtables, false); + if (WholeProgramVTables) { + if (!D.isUsingLTO()) + D.Diag(diag::err_drv_argument_only_allowed_with) + << "-fwhole-program-vtables" + << "-flto"; + CmdArgs.push_back("-fwhole-program-vtables"); + } + + // Finally add the compile command to the compilation. + if (Args.hasArg(options::OPT__SLASH_fallback) && + Output.getType() == types::TY_Object && + (InputType == types::TY_C || InputType == types::TY_CXX)) { + auto CLCommand = + getCLFallback()->GetCommand(C, JA, Output, Inputs, Args, LinkingOutput); + C.addCommand(llvm::make_unique<FallbackCommand>( + JA, *this, Exec, CmdArgs, Inputs, std::move(CLCommand))); + } else if (Args.hasArg(options::OPT__SLASH_fallback) && + isa<PrecompileJobAction>(JA)) { + // In /fallback builds, run the main compilation even if the pch generation + // fails, so that the main compilation's fallback to cl.exe runs. + C.addCommand(llvm::make_unique<ForceSuccessCommand>(JA, *this, Exec, + CmdArgs, Inputs)); + } else { + C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); + } + + // Handle the debug info splitting at object creation time if we're + // creating an object. + // TODO: Currently only works on linux with newer objcopy. + if (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)) + D.Diag(diag::err_drv_argument_not_allowed_with) << "-fomit-frame-pointer" + << A->getAsString(Args); + + // Claim some arguments which clang supports automatically. + + // -fpch-preprocess is used with gcc to add a special marker in the output to + // include the PCH file. Clang's PTH solution is completely transparent, so we + // do not need to deal with it at all. + Args.ClaimAllArgs(options::OPT_fpch_preprocess); + + // Claim some arguments which clang doesn't support, but we don't + // care to warn the user about. + Args.ClaimAllArgs(options::OPT_clang_ignored_f_Group); + Args.ClaimAllArgs(options::OPT_clang_ignored_m_Group); + + // Disable warnings for clang -E -emit-llvm foo.c + Args.ClaimAllArgs(options::OPT_emit_llvm); +} + +Clang::Clang(const ToolChain &TC) + // CAUTION! The first constructor argument ("clang") is not arbitrary, + // as it is for other tools. Some operations on a Tool actually test + // whether that tool is Clang based on the Tool's Name as a string. + : Tool("clang", "clang frontend", TC, RF_Full) {} + +Clang::~Clang() {} + +/// Add options related to the Objective-C runtime/ABI. +/// +/// Returns true if the runtime is non-fragile. +ObjCRuntime Clang::AddObjCRuntimeArgs(const ArgList &args, + ArgStringList &cmdArgs, + RewriteKind rewriteKind) const { + // Look for the controlling runtime option. + Arg *runtimeArg = + args.getLastArg(options::OPT_fnext_runtime, options::OPT_fgnu_runtime, + options::OPT_fobjc_runtime_EQ); + + // Just forward -fobjc-runtime= to the frontend. This supercedes + // options about fragility. + if (runtimeArg && + runtimeArg->getOption().matches(options::OPT_fobjc_runtime_EQ)) { + ObjCRuntime runtime; + StringRef value = runtimeArg->getValue(); + if (runtime.tryParse(value)) { + getToolChain().getDriver().Diag(diag::err_drv_unknown_objc_runtime) + << value; + } + + runtimeArg->render(args, cmdArgs); + return runtime; + } + + // Otherwise, we'll need the ABI "version". Version numbers are + // slightly confusing for historical reasons: + // 1 - Traditional "fragile" ABI + // 2 - Non-fragile ABI, version 1 + // 3 - Non-fragile ABI, version 2 + unsigned objcABIVersion = 1; + // If -fobjc-abi-version= is present, use that to set the version. + if (Arg *abiArg = args.getLastArg(options::OPT_fobjc_abi_version_EQ)) { + StringRef value = abiArg->getValue(); + if (value == "1") + objcABIVersion = 1; + else if (value == "2") + objcABIVersion = 2; + else if (value == "3") + objcABIVersion = 3; + else + getToolChain().getDriver().Diag(diag::err_drv_clang_unsupported) << value; + } else { + // Otherwise, determine if we are using the non-fragile ABI. + bool nonFragileABIIsDefault = + (rewriteKind == RK_NonFragile || + (rewriteKind == RK_None && + getToolChain().IsObjCNonFragileABIDefault())); + if (args.hasFlag(options::OPT_fobjc_nonfragile_abi, + options::OPT_fno_objc_nonfragile_abi, + nonFragileABIIsDefault)) { +// Determine the non-fragile ABI version to use. +#ifdef DISABLE_DEFAULT_NONFRAGILEABI_TWO + unsigned nonFragileABIVersion = 1; +#else + unsigned nonFragileABIVersion = 2; +#endif + + if (Arg *abiArg = + args.getLastArg(options::OPT_fobjc_nonfragile_abi_version_EQ)) { + StringRef value = abiArg->getValue(); + if (value == "1") + nonFragileABIVersion = 1; + else if (value == "2") + nonFragileABIVersion = 2; + else + getToolChain().getDriver().Diag(diag::err_drv_clang_unsupported) + << value; + } + + objcABIVersion = 1 + nonFragileABIVersion; + } else { + objcABIVersion = 1; + } + } + + // We don't actually care about the ABI version other than whether + // it's non-fragile. + bool isNonFragile = objcABIVersion != 1; + + // If we have no runtime argument, ask the toolchain for its default runtime. + // However, the rewriter only really supports the Mac runtime, so assume that. + ObjCRuntime runtime; + if (!runtimeArg) { + switch (rewriteKind) { + case RK_None: + runtime = getToolChain().getDefaultObjCRuntime(isNonFragile); + break; + case RK_Fragile: + runtime = ObjCRuntime(ObjCRuntime::FragileMacOSX, VersionTuple()); + break; + case RK_NonFragile: + runtime = ObjCRuntime(ObjCRuntime::MacOSX, VersionTuple()); + break; + } + + // -fnext-runtime + } else if (runtimeArg->getOption().matches(options::OPT_fnext_runtime)) { + // On Darwin, make this use the default behavior for the toolchain. + if (getToolChain().getTriple().isOSDarwin()) { + runtime = getToolChain().getDefaultObjCRuntime(isNonFragile); + + // Otherwise, build for a generic macosx port. + } else { + runtime = ObjCRuntime(ObjCRuntime::MacOSX, VersionTuple()); + } + + // -fgnu-runtime + } else { + assert(runtimeArg->getOption().matches(options::OPT_fgnu_runtime)); + // Legacy behaviour is to target the gnustep runtime if we are in + // non-fragile mode or the GCC runtime in fragile mode. + if (isNonFragile) + runtime = ObjCRuntime(ObjCRuntime::GNUstep, VersionTuple(1, 6)); + else + runtime = ObjCRuntime(ObjCRuntime::GCC, VersionTuple()); + } + + cmdArgs.push_back( + args.MakeArgString("-fobjc-runtime=" + runtime.getAsString())); + return runtime; +} + +static bool maybeConsumeDash(const std::string &EH, size_t &I) { + bool HaveDash = (I + 1 < EH.size() && EH[I + 1] == '-'); + I += HaveDash; + return !HaveDash; +} + +namespace { +struct EHFlags { + bool Synch = false; + bool Asynch = false; + bool NoUnwindC = false; +}; +} // end anonymous namespace + +/// /EH controls whether to run destructor cleanups when exceptions are +/// thrown. There are three modifiers: +/// - s: Cleanup after "synchronous" exceptions, aka C++ exceptions. +/// - a: Cleanup after "asynchronous" exceptions, aka structured exceptions. +/// The 'a' modifier is unimplemented and fundamentally hard in LLVM IR. +/// - c: Assume that extern "C" functions are implicitly nounwind. +/// The default is /EHs-c-, meaning cleanups are disabled. +static EHFlags parseClangCLEHFlags(const Driver &D, const ArgList &Args) { + EHFlags EH; + + std::vector<std::string> EHArgs = + Args.getAllArgValues(options::OPT__SLASH_EH); + for (auto EHVal : EHArgs) { + for (size_t I = 0, E = EHVal.size(); I != E; ++I) { + switch (EHVal[I]) { + case 'a': + EH.Asynch = maybeConsumeDash(EHVal, I); + if (EH.Asynch) + EH.Synch = false; + continue; + case 'c': + EH.NoUnwindC = maybeConsumeDash(EHVal, I); + continue; + case 's': + EH.Synch = maybeConsumeDash(EHVal, I); + if (EH.Synch) + EH.Asynch = false; + continue; + default: + break; + } + D.Diag(clang::diag::err_drv_invalid_value) << "/EH" << EHVal; + break; + } + } + // The /GX, /GX- flags are only processed if there are not /EH flags. + // The default is that /GX is not specified. + if (EHArgs.empty() && + Args.hasFlag(options::OPT__SLASH_GX, options::OPT__SLASH_GX_, + /*default=*/false)) { + EH.Synch = true; + EH.NoUnwindC = true; + } + + return EH; +} + +void Clang::AddClangCLArgs(const ArgList &Args, types::ID InputType, + ArgStringList &CmdArgs, + codegenoptions::DebugInfoKind *DebugInfoKind, + bool *EmitCodeView) const { + unsigned RTOptionID = options::OPT__SLASH_MT; + + if (Args.hasArg(options::OPT__SLASH_LDd)) + // The /LDd option implies /MTd. The dependent lib part can be overridden, + // but defining _DEBUG is sticky. + RTOptionID = options::OPT__SLASH_MTd; + + if (Arg *A = Args.getLastArg(options::OPT__SLASH_M_Group)) + RTOptionID = A->getOption().getID(); + + StringRef FlagForCRT; + switch (RTOptionID) { + case options::OPT__SLASH_MD: + if (Args.hasArg(options::OPT__SLASH_LDd)) + CmdArgs.push_back("-D_DEBUG"); + CmdArgs.push_back("-D_MT"); + CmdArgs.push_back("-D_DLL"); + FlagForCRT = "--dependent-lib=msvcrt"; + break; + case options::OPT__SLASH_MDd: + CmdArgs.push_back("-D_DEBUG"); + CmdArgs.push_back("-D_MT"); + CmdArgs.push_back("-D_DLL"); + FlagForCRT = "--dependent-lib=msvcrtd"; + break; + case options::OPT__SLASH_MT: + if (Args.hasArg(options::OPT__SLASH_LDd)) + CmdArgs.push_back("-D_DEBUG"); + CmdArgs.push_back("-D_MT"); + CmdArgs.push_back("-flto-visibility-public-std"); + FlagForCRT = "--dependent-lib=libcmt"; + break; + case options::OPT__SLASH_MTd: + CmdArgs.push_back("-D_DEBUG"); + CmdArgs.push_back("-D_MT"); + CmdArgs.push_back("-flto-visibility-public-std"); + FlagForCRT = "--dependent-lib=libcmtd"; + break; + default: + llvm_unreachable("Unexpected option ID."); + } + + if (Args.hasArg(options::OPT__SLASH_Zl)) { + CmdArgs.push_back("-D_VC_NODEFAULTLIB"); + } else { + CmdArgs.push_back(FlagForCRT.data()); + + // This provides POSIX compatibility (maps 'open' to '_open'), which most + // users want. The /Za flag to cl.exe turns this off, but it's not + // implemented in clang. + CmdArgs.push_back("--dependent-lib=oldnames"); + } + + // 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 (Arg *A = Args.getLastArg(options::OPT_show_includes)) + A->render(Args, CmdArgs); + + // This controls whether or not we emit RTTI data for polymorphic types. + if (Args.hasFlag(options::OPT__SLASH_GR_, options::OPT__SLASH_GR, + /*default=*/false)) + CmdArgs.push_back("-fno-rtti-data"); + + // This controls whether or not we emit stack-protector instrumentation. + // In MSVC, Buffer Security Check (/GS) is on by default. + if (Args.hasFlag(options::OPT__SLASH_GS, options::OPT__SLASH_GS_, + /*default=*/true)) { + CmdArgs.push_back("-stack-protector"); + CmdArgs.push_back(Args.MakeArgString(Twine(LangOptions::SSPStrong))); + } + + // Emit CodeView if -Z7, -Zd, or -gline-tables-only are present. + if (Arg *DebugInfoArg = + Args.getLastArg(options::OPT__SLASH_Z7, options::OPT__SLASH_Zd, + options::OPT_gline_tables_only)) { + *EmitCodeView = true; + if (DebugInfoArg->getOption().matches(options::OPT__SLASH_Z7)) + *DebugInfoKind = codegenoptions::LimitedDebugInfo; + else + *DebugInfoKind = codegenoptions::DebugLineTablesOnly; + CmdArgs.push_back("-gcodeview"); + } else { + *EmitCodeView = false; + } + + const Driver &D = getToolChain().getDriver(); + EHFlags EH = parseClangCLEHFlags(D, Args); + if (EH.Synch || EH.Asynch) { + if (types::isCXX(InputType)) + CmdArgs.push_back("-fcxx-exceptions"); + CmdArgs.push_back("-fexceptions"); + } + if (types::isCXX(InputType) && EH.Synch && EH.NoUnwindC) + CmdArgs.push_back("-fexternc-nounwind"); + + // /EP should expand to -E -P. + if (Args.hasArg(options::OPT__SLASH_EP)) { + CmdArgs.push_back("-E"); + CmdArgs.push_back("-P"); + } + + unsigned VolatileOptionID; + if (getToolChain().getArch() == llvm::Triple::x86_64 || + getToolChain().getArch() == llvm::Triple::x86) + VolatileOptionID = options::OPT__SLASH_volatile_ms; + else + VolatileOptionID = options::OPT__SLASH_volatile_iso; + + if (Arg *A = Args.getLastArg(options::OPT__SLASH_volatile_Group)) + VolatileOptionID = A->getOption().getID(); + + if (VolatileOptionID == options::OPT__SLASH_volatile_ms) + CmdArgs.push_back("-fms-volatile"); + + Arg *MostGeneralArg = Args.getLastArg(options::OPT__SLASH_vmg); + Arg *BestCaseArg = Args.getLastArg(options::OPT__SLASH_vmb); + if (MostGeneralArg && BestCaseArg) + D.Diag(clang::diag::err_drv_argument_not_allowed_with) + << MostGeneralArg->getAsString(Args) << BestCaseArg->getAsString(Args); + + if (MostGeneralArg) { + Arg *SingleArg = Args.getLastArg(options::OPT__SLASH_vms); + Arg *MultipleArg = Args.getLastArg(options::OPT__SLASH_vmm); + Arg *VirtualArg = Args.getLastArg(options::OPT__SLASH_vmv); + + Arg *FirstConflict = SingleArg ? SingleArg : MultipleArg; + Arg *SecondConflict = VirtualArg ? VirtualArg : MultipleArg; + if (FirstConflict && SecondConflict && FirstConflict != SecondConflict) + D.Diag(clang::diag::err_drv_argument_not_allowed_with) + << FirstConflict->getAsString(Args) + << SecondConflict->getAsString(Args); + + if (SingleArg) + CmdArgs.push_back("-fms-memptr-rep=single"); + else if (MultipleArg) + CmdArgs.push_back("-fms-memptr-rep=multiple"); + else + CmdArgs.push_back("-fms-memptr-rep=virtual"); + } + + if (Args.getLastArg(options::OPT__SLASH_Gd)) + CmdArgs.push_back("-fdefault-calling-conv=cdecl"); + else if (Args.getLastArg(options::OPT__SLASH_Gr)) + CmdArgs.push_back("-fdefault-calling-conv=fastcall"); + else if (Args.getLastArg(options::OPT__SLASH_Gz)) + CmdArgs.push_back("-fdefault-calling-conv=stdcall"); + else if (Args.getLastArg(options::OPT__SLASH_Gv)) + CmdArgs.push_back("-fdefault-calling-conv=vectorcall"); + + if (Arg *A = Args.getLastArg(options::OPT_vtordisp_mode_EQ)) + A->render(Args, CmdArgs); + + if (!Args.hasArg(options::OPT_fdiagnostics_format_EQ)) { + CmdArgs.push_back("-fdiagnostics-format"); + if (Args.hasArg(options::OPT__SLASH_fallback)) + CmdArgs.push_back("msvc-fallback"); + else + CmdArgs.push_back("msvc"); + } +} + +visualstudio::Compiler *Clang::getCLFallback() const { + if (!CLFallback) + CLFallback.reset(new visualstudio::Compiler(getToolChain())); + return CLFallback.get(); +} + + +const char *Clang::getBaseInputName(const ArgList &Args, + const InputInfo &Input) { + return Args.MakeArgString(llvm::sys::path::filename(Input.getBaseInput())); +} + +const char *Clang::getBaseInputStem(const ArgList &Args, + const InputInfoList &Inputs) { + const char *Str = getBaseInputName(Args, Inputs[0]); + + if (const char *End = strrchr(Str, '.')) + return Args.MakeArgString(std::string(Str, End)); + + return Str; +} + +const char *Clang::getDependencyFileName(const ArgList &Args, + const InputInfoList &Inputs) { + // FIXME: Think about this more. + std::string Res; + + if (Arg *OutputOpt = Args.getLastArg(options::OPT_o)) { + std::string Str(OutputOpt->getValue()); + Res = Str.substr(0, Str.rfind('.')); + } else { + Res = getBaseInputStem(Args, Inputs); + } + return Args.MakeArgString(Res + ".d"); +} + +// Begin ClangAs + +void ClangAs::AddMIPSTargetArgs(const ArgList &Args, + ArgStringList &CmdArgs) const { + StringRef CPUName; + StringRef ABIName; + const llvm::Triple &Triple = getToolChain().getTriple(); + mips::getMipsCPUAndABI(Args, Triple, CPUName, ABIName); + + CmdArgs.push_back("-target-abi"); + CmdArgs.push_back(ABIName.data()); +} + +void ClangAs::AddX86TargetArgs(const ArgList &Args, + ArgStringList &CmdArgs) const { + if (Arg *A = Args.getLastArg(options::OPT_masm_EQ)) { + StringRef Value = A->getValue(); + if (Value == "intel" || Value == "att") { + CmdArgs.push_back("-mllvm"); + CmdArgs.push_back(Args.MakeArgString("-x86-asm-syntax=" + Value)); + } else { + getToolChain().getDriver().Diag(diag::err_drv_unsupported_option_argument) + << A->getOption().getName() << Value; + } + } +} + +void ClangAs::ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, const InputInfoList &Inputs, + const ArgList &Args, + const char *LinkingOutput) const { + ArgStringList CmdArgs; + + assert(Inputs.size() == 1 && "Unexpected number of inputs."); + const InputInfo &Input = Inputs[0]; + + const llvm::Triple &Triple = getToolChain().getEffectiveTriple(); + const std::string &TripleStr = Triple.getTriple(); + + // Don't warn about "clang -w -c foo.s" + Args.ClaimAllArgs(options::OPT_w); + // and "clang -emit-llvm -c foo.s" + Args.ClaimAllArgs(options::OPT_emit_llvm); + + claimNoWarnArgs(Args); + + // Invoke ourselves in -cc1as mode. + // + // FIXME: Implement custom jobs for internal actions. + CmdArgs.push_back("-cc1as"); + + // Add the "effective" target triple. + CmdArgs.push_back("-triple"); + CmdArgs.push_back(Args.MakeArgString(TripleStr)); + + // Set the output mode, we currently only expect to be used as a real + // assembler. + CmdArgs.push_back("-filetype"); + CmdArgs.push_back("obj"); + + // Set the main file name, so that debug info works even with + // -save-temps or preprocessed assembly. + CmdArgs.push_back("-main-file-name"); + CmdArgs.push_back(Clang::getBaseInputName(Args, Input)); + + // Add the target cpu + std::string CPU = getCPUName(Args, Triple, /*FromAs*/ true); + if (!CPU.empty()) { + CmdArgs.push_back("-target-cpu"); + CmdArgs.push_back(Args.MakeArgString(CPU)); + } + + // Add the target features + getTargetFeatures(getToolChain(), Triple, Args, CmdArgs, true); + + // Ignore explicit -force_cpusubtype_ALL option. + (void)Args.hasArg(options::OPT_force__cpusubtype__ALL); + + // Pass along any -I options so we get proper .include search paths. + Args.AddAllArgs(CmdArgs, options::OPT_I_Group); + + // Determine the original source input. + const Action *SourceAction = &JA; + while (SourceAction->getKind() != Action::InputClass) { + assert(!SourceAction->getInputs().empty() && "unexpected root action!"); + SourceAction = SourceAction->getInputs()[0]; + } + + // Forward -g and handle debug info related flags, assuming we are dealing + // with an actual assembly file. + bool WantDebug = false; + unsigned DwarfVersion = 0; + Args.ClaimAllArgs(options::OPT_g_Group); + if (Arg *A = Args.getLastArg(options::OPT_g_Group)) { + WantDebug = !A->getOption().matches(options::OPT_g0) && + !A->getOption().matches(options::OPT_ggdb0); + if (WantDebug) + DwarfVersion = DwarfVersionNum(A->getSpelling()); + } + if (DwarfVersion == 0) + DwarfVersion = getToolChain().GetDefaultDwarfVersion(); + + codegenoptions::DebugInfoKind DebugInfoKind = codegenoptions::NoDebugInfo; + + if (SourceAction->getType() == types::TY_Asm || + SourceAction->getType() == types::TY_PP_Asm) { + // You might think that it would be ok to set DebugInfoKind outside of + // the guard for source type, however there is a test which asserts + // that some assembler invocation receives no -debug-info-kind, + // and it's not clear whether that test is just overly restrictive. + DebugInfoKind = (WantDebug ? codegenoptions::LimitedDebugInfo + : codegenoptions::NoDebugInfo); + // Add the -fdebug-compilation-dir flag if needed. + addDebugCompDirArg(Args, CmdArgs); + + // Set the AT_producer to the clang version when using the integrated + // assembler on assembly source files. + CmdArgs.push_back("-dwarf-debug-producer"); + CmdArgs.push_back(Args.MakeArgString(getClangFullVersion())); + + // And pass along -I options + Args.AddAllArgs(CmdArgs, options::OPT_I); + } + RenderDebugEnablingArgs(Args, CmdArgs, DebugInfoKind, DwarfVersion, + llvm::DebuggerKind::Default); + + // Handle -fPIC et al -- the relocation-model affects the assembler + // for some targets. + llvm::Reloc::Model RelocationModel; + unsigned PICLevel; + bool IsPIE; + std::tie(RelocationModel, PICLevel, IsPIE) = + ParsePICArgs(getToolChain(), Args); + + const char *RMName = RelocationModelName(RelocationModel); + if (RMName) { + CmdArgs.push_back("-mrelocation-model"); + CmdArgs.push_back(RMName); + } + + // Optionally embed the -cc1as level arguments into the debug info, for build + // analysis. + if (getToolChain().UseDwarfDebugFlags()) { + ArgStringList OriginalArgs; + for (const auto &Arg : Args) + Arg->render(Args, OriginalArgs); + + SmallString<256> Flags; + const char *Exec = getToolChain().getDriver().getClangProgramPath(); + Flags += Exec; + for (const char *OriginalArg : OriginalArgs) { + SmallString<128> EscapedArg; + EscapeSpacesAndBackslashes(OriginalArg, EscapedArg); + Flags += " "; + Flags += EscapedArg; + } + CmdArgs.push_back("-dwarf-debug-flags"); + CmdArgs.push_back(Args.MakeArgString(Flags)); + } + + // FIXME: Add -static support, once we have it. + + // Add target specific flags. + switch (getToolChain().getArch()) { + default: + break; + + case llvm::Triple::mips: + case llvm::Triple::mipsel: + case llvm::Triple::mips64: + case llvm::Triple::mips64el: + AddMIPSTargetArgs(Args, CmdArgs); + break; + + case llvm::Triple::x86: + case llvm::Triple::x86_64: + AddX86TargetArgs(Args, CmdArgs); + break; + } + + // Consume all the warning flags. Usually this would be handled more + // gracefully by -cc1 (warning about unknown warning flags, etc) but -cc1as + // doesn't handle that so rather than warning about unused flags that are + // actually used, we'll lie by omission instead. + // FIXME: Stop lying and consume only the appropriate driver flags + Args.ClaimAllArgs(options::OPT_W_Group); + + CollectArgsForIntegratedAssembler(C, Args, CmdArgs, + getToolChain().getDriver()); + + Args.AddAllArgs(CmdArgs, options::OPT_mllvm); + + assert(Output.isFilename() && "Unexpected lipo output."); + CmdArgs.push_back("-o"); + CmdArgs.push_back(Output.getFilename()); + + assert(Input.isFilename() && "Invalid input."); + CmdArgs.push_back(Input.getFilename()); + + const char *Exec = getToolChain().getDriver().getClangProgramPath(); + C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); + + // Handle the debug info splitting at object creation time if we're + // creating an object. + // TODO: Currently only works on linux with newer objcopy. + if (Args.hasArg(options::OPT_gsplit_dwarf) && + getToolChain().getTriple().isOSLinux()) + SplitDebugInfo(getToolChain(), C, *this, JA, Args, Output, + SplitDebugName(Args, Input)); +} + +// Begin OffloadBundler + +void OffloadBundler::ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, + const InputInfoList &Inputs, + const llvm::opt::ArgList &TCArgs, + const char *LinkingOutput) const { + // The version with only one output is expected to refer to a bundling job. + assert(isa<OffloadBundlingJobAction>(JA) && "Expecting bundling job!"); + + // The bundling command looks like this: + // clang-offload-bundler -type=bc + // -targets=host-triple,openmp-triple1,openmp-triple2 + // -outputs=input_file + // -inputs=unbundle_file_host,unbundle_file_tgt1,unbundle_file_tgt2" + + ArgStringList CmdArgs; + + // Get the type. + CmdArgs.push_back(TCArgs.MakeArgString( + Twine("-type=") + types::getTypeTempSuffix(Output.getType()))); + + assert(JA.getInputs().size() == Inputs.size() && + "Not have inputs for all dependence actions??"); + + // Get the targets. + SmallString<128> Triples; + Triples += "-targets="; + for (unsigned I = 0; I < Inputs.size(); ++I) { + if (I) + Triples += ','; + + Action::OffloadKind CurKind = Action::OFK_Host; + const ToolChain *CurTC = &getToolChain(); + const Action *CurDep = JA.getInputs()[I]; + + if (const auto *OA = dyn_cast<OffloadAction>(CurDep)) { + OA->doOnEachDependence([&](Action *A, const ToolChain *TC, const char *) { + CurKind = A->getOffloadingDeviceKind(); + CurTC = TC; + }); + } + Triples += Action::GetOffloadKindName(CurKind); + Triples += '-'; + Triples += CurTC->getTriple().normalize(); + } + CmdArgs.push_back(TCArgs.MakeArgString(Triples)); + + // Get bundled file command. + CmdArgs.push_back( + TCArgs.MakeArgString(Twine("-outputs=") + Output.getFilename())); + + // Get unbundled files command. + SmallString<128> UB; + UB += "-inputs="; + for (unsigned I = 0; I < Inputs.size(); ++I) { + if (I) + UB += ','; + UB += Inputs[I].getFilename(); + } + CmdArgs.push_back(TCArgs.MakeArgString(UB)); + + // All the inputs are encoded as commands. + C.addCommand(llvm::make_unique<Command>( + JA, *this, + TCArgs.MakeArgString(getToolChain().GetProgramPath(getShortName())), + CmdArgs, None)); +} + +void OffloadBundler::ConstructJobMultipleOutputs( + Compilation &C, const JobAction &JA, const InputInfoList &Outputs, + const InputInfoList &Inputs, const llvm::opt::ArgList &TCArgs, + const char *LinkingOutput) const { + // The version with multiple outputs is expected to refer to a unbundling job. + auto &UA = cast<OffloadUnbundlingJobAction>(JA); + + // The unbundling command looks like this: + // clang-offload-bundler -type=bc + // -targets=host-triple,openmp-triple1,openmp-triple2 + // -inputs=input_file + // -outputs=unbundle_file_host,unbundle_file_tgt1,unbundle_file_tgt2" + // -unbundle + + ArgStringList CmdArgs; + + assert(Inputs.size() == 1 && "Expecting to unbundle a single file!"); + InputInfo Input = Inputs.front(); + + // Get the type. + CmdArgs.push_back(TCArgs.MakeArgString( + Twine("-type=") + types::getTypeTempSuffix(Input.getType()))); + + // Get the targets. + SmallString<128> Triples; + Triples += "-targets="; + auto DepInfo = UA.getDependentActionsInfo(); + for (unsigned I = 0; I < DepInfo.size(); ++I) { + if (I) + Triples += ','; + + auto &Dep = DepInfo[I]; + Triples += Action::GetOffloadKindName(Dep.DependentOffloadKind); + Triples += '-'; + Triples += Dep.DependentToolChain->getTriple().normalize(); + } + + CmdArgs.push_back(TCArgs.MakeArgString(Triples)); + + // Get bundled file command. + CmdArgs.push_back( + TCArgs.MakeArgString(Twine("-inputs=") + Input.getFilename())); + + // Get unbundled files command. + SmallString<128> UB; + UB += "-outputs="; + for (unsigned I = 0; I < Outputs.size(); ++I) { + if (I) + UB += ','; + UB += Outputs[I].getFilename(); + } + CmdArgs.push_back(TCArgs.MakeArgString(UB)); + CmdArgs.push_back("-unbundle"); + + // All the inputs are encoded as commands. + C.addCommand(llvm::make_unique<Command>( + JA, *this, + TCArgs.MakeArgString(getToolChain().GetProgramPath(getShortName())), + CmdArgs, None)); +} diff --git a/lib/Driver/ToolChains/Clang.h b/lib/Driver/ToolChains/Clang.h new file mode 100644 index 0000000000..d53c3b4413 --- /dev/null +++ b/lib/Driver/ToolChains/Clang.h @@ -0,0 +1,149 @@ +//===--- Clang.h - Clang Tool and ToolChain Implementations ====-*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_Clang_H +#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_Clang_H + +#include "MSVC.h" +#include "clang/Basic/DebugInfoOptions.h" +#include "clang/Driver/Driver.h" +#include "clang/Driver/Tool.h" +#include "clang/Driver/Types.h" +#include "llvm/ADT/Triple.h" +#include "llvm/Option/Option.h" +#include "llvm/Support/raw_ostream.h" + +namespace clang { +class ObjCRuntime; +namespace driver { + +namespace tools { + +/// \brief Clang compiler tool. +class LLVM_LIBRARY_VISIBILITY Clang : public Tool { +public: + static const char *getBaseInputName(const llvm::opt::ArgList &Args, + const InputInfo &Input); + static const char *getBaseInputStem(const llvm::opt::ArgList &Args, + const InputInfoList &Inputs); + static const char *getDependencyFileName(const llvm::opt::ArgList &Args, + const InputInfoList &Inputs); + +private: + void AddPreprocessingOptions(Compilation &C, const JobAction &JA, + const Driver &D, const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs, + const InputInfo &Output, + const InputInfoList &Inputs) const; + + void AddAArch64TargetArgs(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) const; + void AddARMTargetArgs(const llvm::Triple &Triple, + const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs, + bool KernelOrKext) const; + void AddARM64TargetArgs(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) const; + void AddMIPSTargetArgs(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) const; + void AddPPCTargetArgs(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) const; + void AddR600TargetArgs(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) const; + void AddSparcTargetArgs(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) const; + void AddSystemZTargetArgs(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) const; + void AddX86TargetArgs(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) const; + void AddHexagonTargetArgs(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) const; + void AddLanaiTargetArgs(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) const; + void AddWebAssemblyTargetArgs(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) const; + + enum RewriteKind { RK_None, RK_Fragile, RK_NonFragile }; + + ObjCRuntime AddObjCRuntimeArgs(const llvm::opt::ArgList &args, + llvm::opt::ArgStringList &cmdArgs, + RewriteKind rewrite) const; + + void AddClangCLArgs(const llvm::opt::ArgList &Args, types::ID InputType, + llvm::opt::ArgStringList &CmdArgs, + codegenoptions::DebugInfoKind *DebugInfoKind, + bool *EmitCodeView) const; + + visualstudio::Compiler *getCLFallback() const; + + mutable std::unique_ptr<visualstudio::Compiler> CLFallback; + + mutable std::unique_ptr<llvm::raw_fd_ostream> CompilationDatabase = nullptr; + void DumpCompilationDatabase(Compilation &C, StringRef Filename, + StringRef Target, + const InputInfo &Output, const InputInfo &Input, + const llvm::opt::ArgList &Args) const; + +public: + Clang(const ToolChain &TC); + ~Clang() override; + + bool hasGoodDiagnostics() const override { return true; } + bool hasIntegratedAssembler() const override { return true; } + bool hasIntegratedCPP() const override { return true; } + bool canEmitIR() 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; +}; + +/// \brief Clang integrated assembler tool. +class LLVM_LIBRARY_VISIBILITY ClangAs : public Tool { +public: + ClangAs(const ToolChain &TC) + : Tool("clang::as", "clang integrated assembler", TC, RF_Full) {} + void AddMIPSTargetArgs(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) const; + void AddX86TargetArgs(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) const; + bool hasGoodDiagnostics() const override { return true; } + bool hasIntegratedAssembler() const override { return false; } + 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; +}; + +/// Offload bundler tool. +class LLVM_LIBRARY_VISIBILITY OffloadBundler final : public Tool { +public: + OffloadBundler(const ToolChain &TC) + : Tool("offload bundler", "clang-offload-bundler", 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; + void ConstructJobMultipleOutputs(Compilation &C, const JobAction &JA, + const InputInfoList &Outputs, + const InputInfoList &Inputs, + const llvm::opt::ArgList &TCArgs, + const char *LinkingOutput) const override; +}; +} // end namespace tools + +} // end namespace driver +} // end namespace clang + +#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_CLANG_H diff --git a/lib/Driver/ToolChains/CloudABI.cpp b/lib/Driver/ToolChains/CloudABI.cpp new file mode 100644 index 0000000000..0f6c712c5d --- /dev/null +++ b/lib/Driver/ToolChains/CloudABI.cpp @@ -0,0 +1,145 @@ +//===--- CloudABI.cpp - CloudABI 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 "CloudABI.h" +#include "InputInfo.h" +#include "CommonArgs.h" +#include "clang/Config/config.h" +#include "clang/Driver/Compilation.h" +#include "clang/Driver/Driver.h" +#include "clang/Driver/Options.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/Option/ArgList.h" +#include "llvm/Support/Path.h" + +using namespace clang::driver; +using namespace clang::driver::tools; +using namespace clang::driver::toolchains; +using namespace clang; +using namespace llvm::opt; + +void cloudabi::Linker::ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, + const InputInfoList &Inputs, + const ArgList &Args, + const char *LinkingOutput) const { + const ToolChain &ToolChain = getToolChain(); + const Driver &D = ToolChain.getDriver(); + ArgStringList CmdArgs; + + // Silence warning for "clang -g foo.o -o foo" + Args.ClaimAllArgs(options::OPT_g_Group); + // and "clang -emit-llvm foo.o -o foo" + Args.ClaimAllArgs(options::OPT_emit_llvm); + // and for "clang -w foo.o -o foo". Other warning options are already + // handled somewhere else. + Args.ClaimAllArgs(options::OPT_w); + + if (!D.SysRoot.empty()) + CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot)); + + // CloudABI only supports static linkage. + CmdArgs.push_back("-Bstatic"); + CmdArgs.push_back("--no-dynamic-linker"); + + // Provide PIE linker flags in case PIE is default for the architecture. + if (ToolChain.isPIEDefault()) { + CmdArgs.push_back("-pie"); + CmdArgs.push_back("-zrelro"); + } + + CmdArgs.push_back("--eh-frame-hdr"); + CmdArgs.push_back("--gc-sections"); + + 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)) { + CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crt0.o"))); + CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtbegin.o"))); + } + + Args.AddAllArgs(CmdArgs, options::OPT_L); + ToolChain.AddFilePathLibArgs(Args, CmdArgs); + Args.AddAllArgs(CmdArgs, + {options::OPT_T_Group, options::OPT_e, options::OPT_s, + options::OPT_t, options::OPT_Z_Flag, options::OPT_r}); + + if (D.isUsingLTO()) + AddGoldPlugin(ToolChain, Args, CmdArgs, D.getLTOMode() == LTOK_Thin, D); + + AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA); + + 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"); + } + + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) + CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtend.o"))); + + const char *Exec = Args.MakeArgString(ToolChain.GetLinkerPath()); + C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); +} + +// CloudABI - CloudABI tool chain which can call ld(1) directly. + +CloudABI::CloudABI(const Driver &D, const llvm::Triple &Triple, + const ArgList &Args) + : Generic_ELF(D, Triple, Args) { + SmallString<128> P(getDriver().Dir); + llvm::sys::path::append(P, "..", getTriple().str(), "lib"); + getFilePaths().push_back(P.str()); +} + +std::string CloudABI::findLibCxxIncludePath() const { + SmallString<128> P(getDriver().Dir); + llvm::sys::path::append(P, "..", getTriple().str(), "include/c++/v1"); + return P.str(); +} + +void CloudABI::AddCXXStdlibLibArgs(const ArgList &Args, + ArgStringList &CmdArgs) const { + CmdArgs.push_back("-lc++"); + CmdArgs.push_back("-lc++abi"); + CmdArgs.push_back("-lunwind"); +} + +Tool *CloudABI::buildLinker() const { + return new tools::cloudabi::Linker(*this); +} + +bool CloudABI::isPIEDefault() const { + // Only enable PIE on architectures that support PC-relative + // addressing. PC-relative addressing is required, as the process + // startup code must be able to relocate itself. + switch (getTriple().getArch()) { + case llvm::Triple::aarch64: + case llvm::Triple::x86_64: + return true; + default: + return false; + } +} + +SanitizerMask CloudABI::getSupportedSanitizers() const { + SanitizerMask Res = ToolChain::getSupportedSanitizers(); + Res |= SanitizerKind::SafeStack; + return Res; +} + +SanitizerMask CloudABI::getDefaultSanitizers() const { + return SanitizerKind::SafeStack; +} diff --git a/lib/Driver/ToolChains/CloudABI.h b/lib/Driver/ToolChains/CloudABI.h new file mode 100644 index 0000000000..a284eb3dc0 --- /dev/null +++ b/lib/Driver/ToolChains/CloudABI.h @@ -0,0 +1,69 @@ +//===--- CloudABI.h - CloudABI 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_CLOUDABI_H +#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_CLOUDABI_H + +#include "Gnu.h" +#include "clang/Driver/Tool.h" +#include "clang/Driver/ToolChain.h" + +namespace clang { +namespace driver { +namespace tools { + +/// cloudabi -- Directly call GNU Binutils linker +namespace cloudabi { +class LLVM_LIBRARY_VISIBILITY Linker : public GnuTool { +public: + Linker(const ToolChain &TC) : GnuTool("cloudabi::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 cloudabi +} // end namespace tools + +namespace toolchains { + +class LLVM_LIBRARY_VISIBILITY CloudABI : public Generic_ELF { +public: + CloudABI(const Driver &D, const llvm::Triple &Triple, + const llvm::opt::ArgList &Args); + bool HasNativeLLVMSupport() const override { return true; } + + bool IsMathErrnoDefault() const override { return false; } + bool IsObjCNonFragileABIDefault() const override { return true; } + + CXXStdlibType + GetCXXStdlibType(const llvm::opt::ArgList &Args) const override { + return ToolChain::CST_Libcxx; + } + std::string findLibCxxIncludePath() const override; + void AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) const override; + + bool isPIEDefault() const override; + SanitizerMask getSupportedSanitizers() const override; + SanitizerMask getDefaultSanitizers() const override; + +protected: + Tool *buildLinker() const override; +}; + +} // end namespace toolchains +} // end namespace driver +} // end namespace clang + +#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_CLOUDABI_H diff --git a/lib/Driver/ToolChains/CommonArgs.cpp b/lib/Driver/ToolChains/CommonArgs.cpp new file mode 100644 index 0000000000..5afe135865 --- /dev/null +++ b/lib/Driver/ToolChains/CommonArgs.cpp @@ -0,0 +1,959 @@ +//===--- CommonArgs.cpp - Args handling for multiple toolchains -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "CommonArgs.h" +#include "InputInfo.h" +#include "Hexagon.h" +#include "Arch/AArch64.h" +#include "Arch/ARM.h" +#include "Arch/Mips.h" +#include "Arch/PPC.h" +#include "Arch/SystemZ.h" +#include "Arch/X86.h" +#include "clang/Basic/CharInfo.h" +#include "clang/Basic/LangOptions.h" +#include "clang/Basic/ObjCRuntime.h" +#include "clang/Basic/Version.h" +#include "clang/Basic/VirtualFileSystem.h" +#include "clang/Config/config.h" +#include "clang/Driver/Action.h" +#include "clang/Driver/Compilation.h" +#include "clang/Driver/Driver.h" +#include "clang/Driver/DriverDiagnostic.h" +#include "clang/Driver/Job.h" +#include "clang/Driver/Options.h" +#include "clang/Driver/SanitizerArgs.h" +#include "clang/Driver/ToolChain.h" +#include "clang/Driver/Util.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/ADT/Twine.h" +#include "llvm/Option/Arg.h" +#include "llvm/Option/ArgList.h" +#include "llvm/Option/Option.h" +#include "llvm/Support/CodeGen.h" +#include "llvm/Support/Compression.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/Host.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/Process.h" +#include "llvm/Support/Program.h" +#include "llvm/Support/ScopedPrinter.h" +#include "llvm/Support/TargetParser.h" +#include "llvm/Support/YAMLParser.h" + +using namespace clang::driver; +using namespace clang::driver::tools; +using namespace clang; +using namespace llvm::opt; + +void tools::addPathIfExists(const Driver &D, const Twine &Path, + ToolChain::path_list &Paths) { + if (D.getVFS().exists(Path)) + Paths.push_back(Path.str()); +} + +void tools::handleTargetFeaturesGroup(const ArgList &Args, + std::vector<StringRef> &Features, + OptSpecifier Group) { + for (const Arg *A : Args.filtered(Group)) { + StringRef Name = A->getOption().getName(); + A->claim(); + + // Skip over "-m". + assert(Name.startswith("m") && "Invalid feature name."); + Name = Name.substr(1); + + bool IsNegative = Name.startswith("no-"); + if (IsNegative) + Name = Name.substr(3); + Features.push_back(Args.MakeArgString((IsNegative ? "-" : "+") + Name)); + } +} + +void tools::addDirectoryList(const ArgList &Args, ArgStringList &CmdArgs, + const char *ArgName, const char *EnvVar) { + const char *DirList = ::getenv(EnvVar); + bool CombinedArg = false; + + if (!DirList) + return; // Nothing to do. + + StringRef Name(ArgName); + if (Name.equals("-I") || Name.equals("-L")) + CombinedArg = true; + + StringRef Dirs(DirList); + if (Dirs.empty()) // Empty string should not add '.'. + return; + + StringRef::size_type Delim; + while ((Delim = Dirs.find(llvm::sys::EnvPathSeparator)) != StringRef::npos) { + if (Delim == 0) { // Leading colon. + if (CombinedArg) { + CmdArgs.push_back(Args.MakeArgString(std::string(ArgName) + ".")); + } else { + CmdArgs.push_back(ArgName); + CmdArgs.push_back("."); + } + } else { + if (CombinedArg) { + CmdArgs.push_back( + Args.MakeArgString(std::string(ArgName) + Dirs.substr(0, Delim))); + } else { + CmdArgs.push_back(ArgName); + CmdArgs.push_back(Args.MakeArgString(Dirs.substr(0, Delim))); + } + } + Dirs = Dirs.substr(Delim + 1); + } + + if (Dirs.empty()) { // Trailing colon. + if (CombinedArg) { + CmdArgs.push_back(Args.MakeArgString(std::string(ArgName) + ".")); + } else { + CmdArgs.push_back(ArgName); + CmdArgs.push_back("."); + } + } else { // Add the last path. + if (CombinedArg) { + CmdArgs.push_back(Args.MakeArgString(std::string(ArgName) + Dirs)); + } else { + CmdArgs.push_back(ArgName); + CmdArgs.push_back(Args.MakeArgString(Dirs)); + } + } +} + +void tools::AddLinkerInputs(const ToolChain &TC, const InputInfoList &Inputs, + const ArgList &Args, ArgStringList &CmdArgs, + const JobAction &JA) { + const Driver &D = TC.getDriver(); + + // Add extra linker input arguments which are not treated as inputs + // (constructed via -Xarch_). + Args.AddAllArgValues(CmdArgs, options::OPT_Zlinker_input); + + for (const auto &II : Inputs) { + // If the current tool chain refers to an OpenMP offloading host, we should + // ignore inputs that refer to OpenMP offloading devices - they will be + // embedded according to a proper linker script. + if (auto *IA = II.getAction()) + if (JA.isHostOffloading(Action::OFK_OpenMP) && + IA->isDeviceOffloading(Action::OFK_OpenMP)) + continue; + + if (!TC.HasNativeLLVMSupport() && types::isLLVMIR(II.getType())) + // Don't try to pass LLVM inputs unless we have native support. + D.Diag(diag::err_drv_no_linker_llvm_support) << TC.getTripleString(); + + // Add filenames immediately. + if (II.isFilename()) { + CmdArgs.push_back(II.getFilename()); + continue; + } + + // Otherwise, this is a linker input argument. + const Arg &A = II.getInputArg(); + + // Handle reserved library options. + if (A.getOption().matches(options::OPT_Z_reserved_lib_stdcxx)) + TC.AddCXXStdlibLibArgs(Args, CmdArgs); + else if (A.getOption().matches(options::OPT_Z_reserved_lib_cckext)) + TC.AddCCKextLibArgs(Args, CmdArgs); + else if (A.getOption().matches(options::OPT_z)) { + // Pass -z prefix for gcc linker compatibility. + A.claim(); + A.render(Args, CmdArgs); + } else { + A.renderAsInput(Args, CmdArgs); + } + } + + // LIBRARY_PATH - included following the user specified library paths. + // and only supported on native toolchains. + if (!TC.isCrossCompiling()) { + addDirectoryList(Args, CmdArgs, "-L", "LIBRARY_PATH"); + } +} + +void tools::AddTargetFeature(const ArgList &Args, + std::vector<StringRef> &Features, + OptSpecifier OnOpt, OptSpecifier OffOpt, + StringRef FeatureName) { + if (Arg *A = Args.getLastArg(OnOpt, OffOpt)) { + if (A->getOption().matches(OnOpt)) + Features.push_back(Args.MakeArgString("+" + FeatureName)); + else + Features.push_back(Args.MakeArgString("-" + FeatureName)); + } +} + +/// Get the (LLVM) name of the R600 gpu we are targeting. +static std::string getR600TargetGPU(const ArgList &Args) { + if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) { + const char *GPUName = A->getValue(); + return llvm::StringSwitch<const char *>(GPUName) + .Cases("rv630", "rv635", "r600") + .Cases("rv610", "rv620", "rs780", "rs880") + .Case("rv740", "rv770") + .Case("palm", "cedar") + .Cases("sumo", "sumo2", "sumo") + .Case("hemlock", "cypress") + .Case("aruba", "cayman") + .Default(GPUName); + } + return ""; +} + +static std::string getLanaiTargetCPU(const ArgList &Args) { + if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) { + return A->getValue(); + } + return ""; +} + +/// Get the (LLVM) name of the WebAssembly cpu we are targeting. +static StringRef getWebAssemblyTargetCPU(const ArgList &Args) { + // If we have -mcpu=, use that. + if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) { + StringRef CPU = A->getValue(); + +#ifdef __wasm__ + // Handle "native" by examining the host. "native" isn't meaningful when + // cross compiling, so only support this when the host is also WebAssembly. + if (CPU == "native") + return llvm::sys::getHostCPUName(); +#endif + + return CPU; + } + + return "generic"; +} + +std::string tools::getCPUName(const ArgList &Args, const llvm::Triple &T, + bool FromAs) { + Arg *A; + + switch (T.getArch()) { + default: + return ""; + + case llvm::Triple::aarch64: + case llvm::Triple::aarch64_be: + return aarch64::getAArch64TargetCPU(Args, A); + + case llvm::Triple::arm: + case llvm::Triple::armeb: + case llvm::Triple::thumb: + case llvm::Triple::thumbeb: { + StringRef MArch, MCPU; + arm::getARMArchCPUFromArgs(Args, MArch, MCPU, FromAs); + return arm::getARMTargetCPU(MCPU, MArch, T); + } + case llvm::Triple::mips: + case llvm::Triple::mipsel: + case llvm::Triple::mips64: + case llvm::Triple::mips64el: { + StringRef CPUName; + StringRef ABIName; + mips::getMipsCPUAndABI(Args, T, CPUName, ABIName); + return CPUName; + } + + case llvm::Triple::nvptx: + case llvm::Triple::nvptx64: + if (const Arg *A = Args.getLastArg(options::OPT_march_EQ)) + return A->getValue(); + return ""; + + case llvm::Triple::ppc: + case llvm::Triple::ppc64: + case llvm::Triple::ppc64le: { + std::string TargetCPUName = ppc::getPPCTargetCPU(Args); + // LLVM may default to generating code for the native CPU, + // but, like gcc, we default to a more generic option for + // each architecture. (except on Darwin) + if (TargetCPUName.empty() && !T.isOSDarwin()) { + if (T.getArch() == llvm::Triple::ppc64) + TargetCPUName = "ppc64"; + else if (T.getArch() == llvm::Triple::ppc64le) + TargetCPUName = "ppc64le"; + else + TargetCPUName = "ppc"; + } + return TargetCPUName; + } + + case llvm::Triple::sparc: + case llvm::Triple::sparcel: + case llvm::Triple::sparcv9: + if (const Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) + return A->getValue(); + return ""; + + case llvm::Triple::x86: + case llvm::Triple::x86_64: + return x86::getX86TargetCPU(Args, T); + + case llvm::Triple::hexagon: + return "hexagon" + + toolchains::HexagonToolChain::GetTargetCPUVersion(Args).str(); + + case llvm::Triple::lanai: + return getLanaiTargetCPU(Args); + + case llvm::Triple::systemz: + return systemz::getSystemZTargetCPU(Args); + + case llvm::Triple::r600: + case llvm::Triple::amdgcn: + return getR600TargetGPU(Args); + + case llvm::Triple::wasm32: + case llvm::Triple::wasm64: + return getWebAssemblyTargetCPU(Args); + } +} + +unsigned tools::getLTOParallelism(const ArgList &Args, const Driver &D) { + unsigned Parallelism = 0; + Arg *LtoJobsArg = Args.getLastArg(options::OPT_flto_jobs_EQ); + if (LtoJobsArg && + StringRef(LtoJobsArg->getValue()).getAsInteger(10, Parallelism)) + D.Diag(diag::err_drv_invalid_int_value) << LtoJobsArg->getAsString(Args) + << LtoJobsArg->getValue(); + return Parallelism; +} + +// CloudABI and WebAssembly use -ffunction-sections and -fdata-sections by +// default. +bool tools::isUseSeparateSections(const llvm::Triple &Triple) { + return Triple.getOS() == llvm::Triple::CloudABI || + Triple.getArch() == llvm::Triple::wasm32 || + Triple.getArch() == llvm::Triple::wasm64; +} + +void tools::AddGoldPlugin(const ToolChain &ToolChain, const ArgList &Args, + ArgStringList &CmdArgs, bool IsThinLTO, + const Driver &D) { + // Tell the linker to load the plugin. This has to come before AddLinkerInputs + // 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"; + CmdArgs.push_back(Args.MakeArgString(Plugin)); + + // Try to pass driver level flags relevant to LTO code generation down to + // the plugin. + + // Handle flags for selecting CPU variants. + std::string CPU = getCPUName(Args, ToolChain.getTriple()); + if (!CPU.empty()) + CmdArgs.push_back(Args.MakeArgString(Twine("-plugin-opt=mcpu=") + CPU)); + + if (Arg *A = Args.getLastArg(options::OPT_O_Group)) { + StringRef OOpt; + if (A->getOption().matches(options::OPT_O4) || + A->getOption().matches(options::OPT_Ofast)) + OOpt = "3"; + else if (A->getOption().matches(options::OPT_O)) + OOpt = A->getValue(); + else if (A->getOption().matches(options::OPT_O0)) + OOpt = "0"; + if (!OOpt.empty()) + CmdArgs.push_back(Args.MakeArgString(Twine("-plugin-opt=O") + OOpt)); + } + + if (IsThinLTO) + CmdArgs.push_back("-plugin-opt=thinlto"); + + if (unsigned Parallelism = getLTOParallelism(Args, D)) + CmdArgs.push_back(Args.MakeArgString(Twine("-plugin-opt=jobs=") + + llvm::to_string(Parallelism))); + + // If an explicit debugger tuning argument appeared, pass it along. + if (Arg *A = Args.getLastArg(options::OPT_gTune_Group, + options::OPT_ggdbN_Group)) { + if (A->getOption().matches(options::OPT_glldb)) + CmdArgs.push_back("-plugin-opt=-debugger-tune=lldb"); + else if (A->getOption().matches(options::OPT_gsce)) + CmdArgs.push_back("-plugin-opt=-debugger-tune=sce"); + else + CmdArgs.push_back("-plugin-opt=-debugger-tune=gdb"); + } + + bool UseSeparateSections = + isUseSeparateSections(ToolChain.getEffectiveTriple()); + + if (Args.hasFlag(options::OPT_ffunction_sections, + options::OPT_fno_function_sections, UseSeparateSections)) { + CmdArgs.push_back("-plugin-opt=-function-sections"); + } + + if (Args.hasFlag(options::OPT_fdata_sections, options::OPT_fno_data_sections, + UseSeparateSections)) { + CmdArgs.push_back("-plugin-opt=-data-sections"); + } + + if (Arg *A = Args.getLastArg(options::OPT_fprofile_sample_use_EQ)) { + StringRef FName = A->getValue(); + if (!llvm::sys::fs::exists(FName)) + D.Diag(diag::err_drv_no_such_file) << FName; + else + CmdArgs.push_back( + Args.MakeArgString(Twine("-plugin-opt=sample-profile=") + FName)); + } +} + +void tools::addArchSpecificRPath(const ToolChain &TC, const ArgList &Args, + ArgStringList &CmdArgs) { + // In the cross-compilation case, arch-specific library path is likely + // unavailable at runtime. + if (TC.isCrossCompiling()) return; + + std::string CandidateRPath = TC.getArchSpecificLibPath(); + if (TC.getVFS().exists(CandidateRPath)) { + CmdArgs.push_back("-rpath"); + CmdArgs.push_back(Args.MakeArgString(CandidateRPath.c_str())); + } +} + +void tools::addOpenMPRuntime(ArgStringList &CmdArgs, const ToolChain &TC, + const ArgList &Args) { + if (!Args.hasFlag(options::OPT_fopenmp, options::OPT_fopenmp_EQ, + options::OPT_fno_openmp, false)) + return; + + switch (TC.getDriver().getOpenMPRuntime(Args)) { + case Driver::OMPRT_OMP: + CmdArgs.push_back("-lomp"); + break; + case Driver::OMPRT_GOMP: + CmdArgs.push_back("-lgomp"); + break; + case Driver::OMPRT_IOMP5: + CmdArgs.push_back("-liomp5"); + break; + case Driver::OMPRT_Unknown: + // Already diagnosed. + break; + } + + addArchSpecificRPath(TC, Args, CmdArgs); +} + +static void addSanitizerRuntime(const ToolChain &TC, const ArgList &Args, + ArgStringList &CmdArgs, StringRef Sanitizer, + bool IsShared, bool IsWhole) { + // Wrap any static runtimes that must be forced into executable in + // whole-archive. + if (IsWhole) CmdArgs.push_back("-whole-archive"); + CmdArgs.push_back(TC.getCompilerRTArgString(Args, Sanitizer, IsShared)); + if (IsWhole) CmdArgs.push_back("-no-whole-archive"); + + if (IsShared) { + addArchSpecificRPath(TC, Args, CmdArgs); + } +} + +// Tries to use a file with the list of dynamic symbols that need to be exported +// from the runtime library. Returns true if the file was found. +static bool addSanitizerDynamicList(const ToolChain &TC, const ArgList &Args, + ArgStringList &CmdArgs, + StringRef Sanitizer) { + SmallString<128> SanRT(TC.getCompilerRT(Args, Sanitizer)); + if (llvm::sys::fs::exists(SanRT + ".syms")) { + CmdArgs.push_back(Args.MakeArgString("--dynamic-list=" + SanRT + ".syms")); + return true; + } + return false; +} + +void tools::linkSanitizerRuntimeDeps(const ToolChain &TC, + ArgStringList &CmdArgs) { + // Force linking against the system libraries sanitizers depends on + // (see PR15823 why this is necessary). + CmdArgs.push_back("--no-as-needed"); + // There's no libpthread or librt on RTEMS. + if (TC.getTriple().getOS() != llvm::Triple::RTEMS) { + CmdArgs.push_back("-lpthread"); + CmdArgs.push_back("-lrt"); + } + CmdArgs.push_back("-lm"); + // There's no libdl on FreeBSD or RTEMS. + if (TC.getTriple().getOS() != llvm::Triple::FreeBSD && + TC.getTriple().getOS() != llvm::Triple::RTEMS) + CmdArgs.push_back("-ldl"); +} + +static void +collectSanitizerRuntimes(const ToolChain &TC, const ArgList &Args, + SmallVectorImpl<StringRef> &SharedRuntimes, + SmallVectorImpl<StringRef> &StaticRuntimes, + SmallVectorImpl<StringRef> &NonWholeStaticRuntimes, + SmallVectorImpl<StringRef> &HelperStaticRuntimes, + SmallVectorImpl<StringRef> &RequiredSymbols) { + const SanitizerArgs &SanArgs = TC.getSanitizerArgs(); + // Collect shared runtimes. + if (SanArgs.needsAsanRt() && SanArgs.needsSharedAsanRt()) { + SharedRuntimes.push_back("asan"); + } + // 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. + 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"); + } + } + if (SanArgs.needsDfsanRt()) + StaticRuntimes.push_back("dfsan"); + if (SanArgs.needsLsanRt()) + StaticRuntimes.push_back("lsan"); + if (SanArgs.needsMsanRt()) { + StaticRuntimes.push_back("msan"); + if (SanArgs.linkCXXRuntimes()) + StaticRuntimes.push_back("msan_cxx"); + } + if (SanArgs.needsTsanRt()) { + StaticRuntimes.push_back("tsan"); + if (SanArgs.linkCXXRuntimes()) + StaticRuntimes.push_back("tsan_cxx"); + } + if (SanArgs.needsUbsanRt()) { + StaticRuntimes.push_back("ubsan_standalone"); + if (SanArgs.linkCXXRuntimes()) + StaticRuntimes.push_back("ubsan_standalone_cxx"); + } + if (SanArgs.needsSafeStackRt()) { + NonWholeStaticRuntimes.push_back("safestack"); + RequiredSymbols.push_back("__safestack_init"); + } + if (SanArgs.needsCfiRt()) + StaticRuntimes.push_back("cfi"); + if (SanArgs.needsCfiDiagRt()) { + StaticRuntimes.push_back("cfi_diag"); + if (SanArgs.linkCXXRuntimes()) + StaticRuntimes.push_back("ubsan_standalone_cxx"); + } + if (SanArgs.needsStatsRt()) { + NonWholeStaticRuntimes.push_back("stats"); + RequiredSymbols.push_back("__sanitizer_stats_register"); + } + if (SanArgs.needsEsanRt()) + StaticRuntimes.push_back("esan"); +} + +// 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, + ArgStringList &CmdArgs) { + SmallVector<StringRef, 4> SharedRuntimes, StaticRuntimes, + NonWholeStaticRuntimes, HelperStaticRuntimes, RequiredSymbols; + collectSanitizerRuntimes(TC, Args, SharedRuntimes, StaticRuntimes, + NonWholeStaticRuntimes, HelperStaticRuntimes, + RequiredSymbols); + for (auto RT : SharedRuntimes) + addSanitizerRuntime(TC, Args, CmdArgs, RT, true, false); + for (auto RT : HelperStaticRuntimes) + addSanitizerRuntime(TC, Args, CmdArgs, RT, false, true); + bool AddExportDynamic = false; + for (auto RT : StaticRuntimes) { + addSanitizerRuntime(TC, Args, CmdArgs, RT, false, true); + AddExportDynamic |= !addSanitizerDynamicList(TC, Args, CmdArgs, RT); + } + for (auto RT : NonWholeStaticRuntimes) { + addSanitizerRuntime(TC, Args, CmdArgs, RT, false, false); + AddExportDynamic |= !addSanitizerDynamicList(TC, Args, CmdArgs, RT); + } + for (auto S : RequiredSymbols) { + CmdArgs.push_back("-u"); + CmdArgs.push_back(Args.MakeArgString(S)); + } + // If there is a static runtime with no dynamic list, force all the symbols + // to be dynamic to be sure we export sanitizer interface functions. + if (AddExportDynamic) + CmdArgs.push_back("-export-dynamic"); + + const SanitizerArgs &SanArgs = TC.getSanitizerArgs(); + if (SanArgs.hasCrossDsoCfi() && !AddExportDynamic) + CmdArgs.push_back("-export-dynamic-symbol=__cfi_check"); + + return !StaticRuntimes.empty() || !NonWholeStaticRuntimes.empty(); +} + +bool tools::areOptimizationsEnabled(const ArgList &Args) { + // Find the last -O arg and see if it is non-zero. + if (Arg *A = Args.getLastArg(options::OPT_O_Group)) + return !A->getOption().matches(options::OPT_O0); + // Defaults to -O0. + return false; +} + +const char *tools::SplitDebugName(const ArgList &Args, const InputInfo &Input) { + Arg *FinalOutput = Args.getLastArg(options::OPT_o); + if (FinalOutput && Args.hasArg(options::OPT_c)) { + SmallString<128> T(FinalOutput->getValue()); + llvm::sys::path::replace_extension(T, "dwo"); + return Args.MakeArgString(T); + } else { + // Use the compilation dir. + SmallString<128> T( + Args.getLastArgValue(options::OPT_fdebug_compilation_dir)); + SmallString<128> F(llvm::sys::path::stem(Input.getBaseInput())); + llvm::sys::path::replace_extension(F, "dwo"); + T += F; + return Args.MakeArgString(F); + } +} + +void tools::SplitDebugInfo(const ToolChain &TC, Compilation &C, const Tool &T, + const JobAction &JA, const ArgList &Args, + const InputInfo &Output, const char *OutFile) { + ArgStringList ExtractArgs; + ExtractArgs.push_back("--extract-dwo"); + + ArgStringList StripArgs; + StripArgs.push_back("--strip-dwo"); + + // Grabbing the output of the earlier compile step. + StripArgs.push_back(Output.getFilename()); + ExtractArgs.push_back(Output.getFilename()); + ExtractArgs.push_back(OutFile); + + const char *Exec = Args.MakeArgString(TC.GetProgramPath("objcopy")); + InputInfo II(types::TY_Object, Output.getFilename(), Output.getFilename()); + + // First extract the dwo sections. + C.addCommand(llvm::make_unique<Command>(JA, T, Exec, ExtractArgs, II)); + + // Then remove them from the original .o file. + C.addCommand(llvm::make_unique<Command>(JA, T, Exec, StripArgs, II)); +} + +// Claim options we don't want to warn if they are unused. We do this for +// options that build systems might add but are unused when assembling or only +// running the preprocessor for example. +void tools::claimNoWarnArgs(const ArgList &Args) { + // Don't warn about unused -f(no-)?lto. This can happen when we're + // preprocessing, precompiling or assembling. + Args.ClaimAllArgs(options::OPT_flto_EQ); + Args.ClaimAllArgs(options::OPT_flto); + Args.ClaimAllArgs(options::OPT_fno_lto); +} + +Arg *tools::getLastProfileUseArg(const ArgList &Args) { + auto *ProfileUseArg = Args.getLastArg( + options::OPT_fprofile_instr_use, options::OPT_fprofile_instr_use_EQ, + options::OPT_fprofile_use, options::OPT_fprofile_use_EQ, + options::OPT_fno_profile_instr_use); + + if (ProfileUseArg && + ProfileUseArg->getOption().matches(options::OPT_fno_profile_instr_use)) + ProfileUseArg = nullptr; + + return ProfileUseArg; +} + +/// Parses the various -fpic/-fPIC/-fpie/-fPIE arguments. Then, +/// smooshes them together with platform defaults, to decide whether +/// this compile should be using PIC mode or not. Returns a tuple of +/// (RelocationModel, PICLevel, IsPIE). +std::tuple<llvm::Reloc::Model, unsigned, bool> +tools::ParsePICArgs(const ToolChain &ToolChain, const ArgList &Args) { + const llvm::Triple &EffectiveTriple = ToolChain.getEffectiveTriple(); + const llvm::Triple &Triple = ToolChain.getTriple(); + + bool PIE = ToolChain.isPIEDefault(); + bool PIC = PIE || ToolChain.isPICDefault(); + // The Darwin/MachO default to use PIC does not apply when using -static. + if (Triple.isOSBinFormatMachO() && Args.hasArg(options::OPT_static)) + PIE = PIC = false; + bool IsPICLevelTwo = PIC; + + bool KernelOrKext = + Args.hasArg(options::OPT_mkernel, options::OPT_fapple_kext); + + // Android-specific defaults for PIC/PIE + if (Triple.isAndroid()) { + switch (Triple.getArch()) { + case llvm::Triple::arm: + case llvm::Triple::armeb: + case llvm::Triple::thumb: + case llvm::Triple::thumbeb: + case llvm::Triple::aarch64: + case llvm::Triple::mips: + case llvm::Triple::mipsel: + case llvm::Triple::mips64: + case llvm::Triple::mips64el: + PIC = true; // "-fpic" + break; + + case llvm::Triple::x86: + case llvm::Triple::x86_64: + PIC = true; // "-fPIC" + IsPICLevelTwo = true; + break; + + default: + break; + } + } + + // OpenBSD-specific defaults for PIE + if (Triple.getOS() == llvm::Triple::OpenBSD) { + switch (ToolChain.getArch()) { + case llvm::Triple::mips64: + case llvm::Triple::mips64el: + case llvm::Triple::sparcel: + case llvm::Triple::x86: + case llvm::Triple::x86_64: + IsPICLevelTwo = false; // "-fpie" + break; + + case llvm::Triple::ppc: + case llvm::Triple::sparc: + case llvm::Triple::sparcv9: + IsPICLevelTwo = true; // "-fPIE" + break; + + default: + break; + } + } + + // The last argument relating to either PIC or PIE wins, and no + // other argument is used. If the last argument is any flavor of the + // '-fno-...' arguments, both PIC and PIE are disabled. Any PIE + // option implicitly enables PIC at the same level. + Arg *LastPICArg = Args.getLastArg(options::OPT_fPIC, options::OPT_fno_PIC, + options::OPT_fpic, options::OPT_fno_pic, + options::OPT_fPIE, options::OPT_fno_PIE, + options::OPT_fpie, options::OPT_fno_pie); + if (Triple.isOSWindows() && LastPICArg && + LastPICArg == + Args.getLastArg(options::OPT_fPIC, options::OPT_fpic, + options::OPT_fPIE, options::OPT_fpie)) { + ToolChain.getDriver().Diag(diag::err_drv_unsupported_opt_for_target) + << LastPICArg->getSpelling() << Triple.str(); + if (Triple.getArch() == llvm::Triple::x86_64) + return std::make_tuple(llvm::Reloc::PIC_, 2U, false); + return std::make_tuple(llvm::Reloc::Static, 0U, false); + } + + // Check whether the tool chain trumps the PIC-ness decision. If the PIC-ness + // is forced, then neither PIC nor PIE flags will have no effect. + if (!ToolChain.isPICDefaultForced()) { + if (LastPICArg) { + Option O = LastPICArg->getOption(); + if (O.matches(options::OPT_fPIC) || O.matches(options::OPT_fpic) || + O.matches(options::OPT_fPIE) || O.matches(options::OPT_fpie)) { + PIE = O.matches(options::OPT_fPIE) || O.matches(options::OPT_fpie); + PIC = + PIE || O.matches(options::OPT_fPIC) || O.matches(options::OPT_fpic); + IsPICLevelTwo = + O.matches(options::OPT_fPIE) || O.matches(options::OPT_fPIC); + } else { + PIE = PIC = false; + if (EffectiveTriple.isPS4CPU()) { + Arg *ModelArg = Args.getLastArg(options::OPT_mcmodel_EQ); + StringRef Model = ModelArg ? ModelArg->getValue() : ""; + if (Model != "kernel") { + PIC = true; + ToolChain.getDriver().Diag(diag::warn_drv_ps4_force_pic) + << LastPICArg->getSpelling(); + } + } + } + } + } + + // Introduce a Darwin and PS4-specific hack. If the default is PIC, but the + // PIC level would've been set to level 1, force it back to level 2 PIC + // instead. + if (PIC && (Triple.isOSDarwin() || EffectiveTriple.isPS4CPU())) + IsPICLevelTwo |= ToolChain.isPICDefault(); + + // This kernel flags are a trump-card: they will disable PIC/PIE + // generation, independent of the argument order. + if (KernelOrKext && + ((!EffectiveTriple.isiOS() || EffectiveTriple.isOSVersionLT(6)) && + !EffectiveTriple.isWatchOS())) + PIC = PIE = false; + + if (Arg *A = Args.getLastArg(options::OPT_mdynamic_no_pic)) { + // This is a very special mode. It trumps the other modes, almost no one + // uses it, and it isn't even valid on any OS but Darwin. + if (!Triple.isOSDarwin()) + ToolChain.getDriver().Diag(diag::err_drv_unsupported_opt_for_target) + << A->getSpelling() << Triple.str(); + + // FIXME: Warn when this flag trumps some other PIC or PIE flag. + + // Only a forced PIC mode can cause the actual compile to have PIC defines + // etc., no flags are sufficient. This behavior was selected to closely + // match that of llvm-gcc and Apple GCC before that. + PIC = ToolChain.isPICDefault() && ToolChain.isPICDefaultForced(); + + return std::make_tuple(llvm::Reloc::DynamicNoPIC, PIC ? 2U : 0U, false); + } + + bool EmbeddedPISupported; + switch (Triple.getArch()) { + case llvm::Triple::arm: + case llvm::Triple::armeb: + case llvm::Triple::thumb: + case llvm::Triple::thumbeb: + EmbeddedPISupported = true; + break; + default: + EmbeddedPISupported = false; + break; + } + + bool ROPI = false, RWPI = false; + Arg* LastROPIArg = Args.getLastArg(options::OPT_fropi, options::OPT_fno_ropi); + if (LastROPIArg && LastROPIArg->getOption().matches(options::OPT_fropi)) { + if (!EmbeddedPISupported) + ToolChain.getDriver().Diag(diag::err_drv_unsupported_opt_for_target) + << LastROPIArg->getSpelling() << Triple.str(); + ROPI = true; + } + Arg *LastRWPIArg = Args.getLastArg(options::OPT_frwpi, options::OPT_fno_rwpi); + if (LastRWPIArg && LastRWPIArg->getOption().matches(options::OPT_frwpi)) { + if (!EmbeddedPISupported) + ToolChain.getDriver().Diag(diag::err_drv_unsupported_opt_for_target) + << LastRWPIArg->getSpelling() << Triple.str(); + RWPI = true; + } + + // ROPI and RWPI are not comaptible with PIC or PIE. + if ((ROPI || RWPI) && (PIC || PIE)) + ToolChain.getDriver().Diag(diag::err_drv_ropi_rwpi_incompatible_with_pic); + + // When targettng MIPS64 with N64, the default is PIC, unless -mno-abicalls is + // used. + if ((Triple.getArch() == llvm::Triple::mips64 || + Triple.getArch() == llvm::Triple::mips64el) && + Args.hasArg(options::OPT_mno_abicalls)) + return std::make_tuple(llvm::Reloc::Static, 0U, false); + + if (PIC) + return std::make_tuple(llvm::Reloc::PIC_, IsPICLevelTwo ? 2U : 1U, PIE); + + llvm::Reloc::Model RelocM = llvm::Reloc::Static; + if (ROPI && RWPI) + RelocM = llvm::Reloc::ROPI_RWPI; + else if (ROPI) + RelocM = llvm::Reloc::ROPI; + else if (RWPI) + RelocM = llvm::Reloc::RWPI; + + return std::make_tuple(RelocM, 0U, false); +} + +void tools::AddAssemblerKPIC(const ToolChain &ToolChain, const ArgList &Args, + ArgStringList &CmdArgs) { + llvm::Reloc::Model RelocationModel; + unsigned PICLevel; + bool IsPIE; + std::tie(RelocationModel, PICLevel, IsPIE) = ParsePICArgs(ToolChain, Args); + + if (RelocationModel != llvm::Reloc::Static) + CmdArgs.push_back("-KPIC"); +} + +/// \brief Determine whether Objective-C automated reference counting is +/// enabled. +bool tools::isObjCAutoRefCount(const ArgList &Args) { + return Args.hasFlag(options::OPT_fobjc_arc, options::OPT_fno_objc_arc, false); +} + +static void AddLibgcc(const llvm::Triple &Triple, const Driver &D, + ArgStringList &CmdArgs, const ArgList &Args) { + bool isAndroid = Triple.isAndroid(); + bool isCygMing = Triple.isOSCygMing(); + bool IsIAMCU = Triple.isOSIAMCU(); + bool StaticLibgcc = Args.hasArg(options::OPT_static_libgcc) || + Args.hasArg(options::OPT_static); + if (!D.CCCIsCXX()) + CmdArgs.push_back("-lgcc"); + + if (StaticLibgcc || isAndroid) { + if (D.CCCIsCXX()) + CmdArgs.push_back("-lgcc"); + } else { + if (!D.CCCIsCXX() && !isCygMing) + CmdArgs.push_back("--as-needed"); + CmdArgs.push_back("-lgcc_s"); + if (!D.CCCIsCXX() && !isCygMing) + CmdArgs.push_back("--no-as-needed"); + } + + if (StaticLibgcc && !isAndroid && !IsIAMCU) + CmdArgs.push_back("-lgcc_eh"); + else if (!Args.hasArg(options::OPT_shared) && D.CCCIsCXX()) + CmdArgs.push_back("-lgcc"); + + // According to Android ABI, we have to link with libdl if we are + // linking with non-static libgcc. + // + // NOTE: This fixes a link error on Android MIPS as well. The non-static + // libgcc for MIPS relies on _Unwind_Find_FDE and dl_iterate_phdr from libdl. + if (isAndroid && !StaticLibgcc) + CmdArgs.push_back("-ldl"); +} + +void tools::AddRunTimeLibs(const ToolChain &TC, const Driver &D, + ArgStringList &CmdArgs, const ArgList &Args) { + // Make use of compiler-rt if --rtlib option is used + ToolChain::RuntimeLibType RLT = TC.GetRuntimeLibType(Args); + + 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; + } + break; + case ToolChain::RLT_Libgcc: + // Make sure libgcc is not used under MSVC environment by default + if (TC.getTriple().isKnownWindowsMSVCEnvironment()) { + // Issue error diagnostic if libgcc is explicitly specified + // through command line as --rtlib option argument. + if (Args.hasArg(options::OPT_rtlib_EQ)) { + TC.getDriver().Diag(diag::err_drv_unsupported_rtlib_for_platform) + << Args.getLastArg(options::OPT_rtlib_EQ)->getValue() << "MSVC"; + } + } else + AddLibgcc(TC.getTriple(), D, CmdArgs, Args); + break; + } +} diff --git a/lib/Driver/ToolChains/CommonArgs.h b/lib/Driver/ToolChains/CommonArgs.h new file mode 100644 index 0000000000..252dbf590b --- /dev/null +++ b/lib/Driver/ToolChains/CommonArgs.h @@ -0,0 +1,95 @@ +//===--- CommonArgs.h - Args handling for multiple toolchains ---*- 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_COMMONARGS_H +#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_COMMONARGS_H + +#include "InputInfo.h" +#include "clang/Driver/Driver.h" +#include "clang/Driver/Tool.h" +#include "clang/Driver/ToolChain.h" +#include "llvm/Support/CodeGen.h" + +namespace clang { +namespace driver { +namespace tools { + +void addPathIfExists(const Driver &D, const Twine &Path, + ToolChain::path_list &Paths); + +void AddLinkerInputs(const ToolChain &TC, const InputInfoList &Inputs, + const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs, const JobAction &JA); + +void claimNoWarnArgs(const llvm::opt::ArgList &Args); + +bool addSanitizerRuntimes(const ToolChain &TC, const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs); + +void linkSanitizerRuntimeDeps(const ToolChain &TC, + llvm::opt::ArgStringList &CmdArgs); + +void AddRunTimeLibs(const ToolChain &TC, const Driver &D, + llvm::opt::ArgStringList &CmdArgs, + const llvm::opt::ArgList &Args); + +const char *SplitDebugName(const llvm::opt::ArgList &Args, + const InputInfo &Input); + +void SplitDebugInfo(const ToolChain &TC, Compilation &C, const Tool &T, + const JobAction &JA, const llvm::opt::ArgList &Args, + const InputInfo &Output, const char *OutFile); + +void AddGoldPlugin(const ToolChain &ToolChain, const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs, bool IsThinLTO, + const Driver &D); + +std::tuple<llvm::Reloc::Model, unsigned, bool> +ParsePICArgs(const ToolChain &ToolChain, const llvm::opt::ArgList &Args); + +void AddAssemblerKPIC(const ToolChain &ToolChain, + const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs); + +void addArchSpecificRPath(const ToolChain &TC, const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs); +void addOpenMPRuntime(llvm::opt::ArgStringList &CmdArgs, const ToolChain &TC, + const llvm::opt::ArgList &Args); + +llvm::opt::Arg *getLastProfileUseArg(const llvm::opt::ArgList &Args); + +bool isObjCAutoRefCount(const llvm::opt::ArgList &Args); + +unsigned getLTOParallelism(const llvm::opt::ArgList &Args, const Driver &D); + +bool areOptimizationsEnabled(const llvm::opt::ArgList &Args); + +bool isUseSeparateSections(const llvm::Triple &Triple); + +void addDirectoryList(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs, const char *ArgName, + const char *EnvVar); + +void AddTargetFeature(const llvm::opt::ArgList &Args, + std::vector<StringRef> &Features, + llvm::opt::OptSpecifier OnOpt, + llvm::opt::OptSpecifier OffOpt, StringRef FeatureName); + +std::string getCPUName(const llvm::opt::ArgList &Args, const llvm::Triple &T, + bool FromAs = false); + +void handleTargetFeaturesGroup(const llvm::opt::ArgList &Args, + std::vector<StringRef> &Features, + llvm::opt::OptSpecifier Group); + +} // end namespace tools +} // end namespace driver +} // end namespace clang + +#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_COMMONARGS_H diff --git a/lib/Driver/ToolChains/Contiki.cpp b/lib/Driver/ToolChains/Contiki.cpp new file mode 100644 index 0000000000..7f74bfcb4b --- /dev/null +++ b/lib/Driver/ToolChains/Contiki.cpp @@ -0,0 +1,28 @@ +//===--- Contiki.cpp - Contiki 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 "Contiki.h" +#include "CommonArgs.h" + +using namespace clang::driver; +using namespace clang::driver::toolchains; +using namespace clang; +using namespace llvm::opt; + +Contiki::Contiki(const Driver &D, const llvm::Triple &Triple, + const ArgList &Args) + : Generic_ELF(D, Triple, Args) {} + +SanitizerMask Contiki::getSupportedSanitizers() const { + const bool IsX86 = getTriple().getArch() == llvm::Triple::x86; + SanitizerMask Res = ToolChain::getSupportedSanitizers(); + if (IsX86) + Res |= SanitizerKind::SafeStack; + return Res; +} diff --git a/lib/Driver/ToolChains/Contiki.h b/lib/Driver/ToolChains/Contiki.h new file mode 100644 index 0000000000..f6e1507388 --- /dev/null +++ b/lib/Driver/ToolChains/Contiki.h @@ -0,0 +1,38 @@ +//===--- Contiki.h - Contiki 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_CONTIKI_H +#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_CONTIKI_H + +#include "Gnu.h" +#include "clang/Driver/ToolChain.h" + +namespace clang { +namespace driver { +namespace toolchains { + +class LLVM_LIBRARY_VISIBILITY Contiki : public Generic_ELF { +public: + Contiki(const Driver &D, const llvm::Triple &Triple, + const llvm::opt::ArgList &Args); + + // No support for finding a C++ standard library yet. + std::string findLibCxxIncludePath() const override { return ""; } + void addLibStdCxxIncludePaths( + const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const override {} + + SanitizerMask getSupportedSanitizers() const override; +}; + +} // end namespace toolchains +} // end namespace driver +} // end namespace clang + +#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_CONTIKI_H diff --git a/lib/Driver/ToolChains/CrossWindows.cpp b/lib/Driver/ToolChains/CrossWindows.cpp new file mode 100644 index 0000000000..dcf085a45d --- /dev/null +++ b/lib/Driver/ToolChains/CrossWindows.cpp @@ -0,0 +1,318 @@ +//===--- CrossWindowsToolChain.cpp - Cross Windows Tool Chain -------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "CrossWindows.h" +#include "CommonArgs.h" +#include "clang/Driver/Compilation.h" +#include "clang/Driver/Driver.h" +#include "clang/Driver/Options.h" +#include "clang/Driver/SanitizerArgs.h" +#include "llvm/Option/ArgList.h" +#include "llvm/Support/Path.h" + +using namespace clang::driver; +using namespace clang::driver::toolchains; + +using llvm::opt::ArgList; + +void tools::CrossWindows::Assembler::ConstructJob( + Compilation &C, const JobAction &JA, const InputInfo &Output, + const InputInfoList &Inputs, const ArgList &Args, + const char *LinkingOutput) const { + claimNoWarnArgs(Args); + const auto &TC = + static_cast<const toolchains::CrossWindowsToolChain &>(getToolChain()); + ArgStringList CmdArgs; + const char *Exec; + + switch (TC.getArch()) { + default: + llvm_unreachable("unsupported architecture"); + case llvm::Triple::arm: + case llvm::Triple::thumb: + break; + case llvm::Triple::x86: + CmdArgs.push_back("--32"); + break; + case llvm::Triple::x86_64: + CmdArgs.push_back("--64"); + break; + } + + Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler); + + CmdArgs.push_back("-o"); + CmdArgs.push_back(Output.getFilename()); + + for (const auto &Input : Inputs) + CmdArgs.push_back(Input.getFilename()); + + const std::string Assembler = TC.GetProgramPath("as"); + Exec = Args.MakeArgString(Assembler); + + C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); +} + +void tools::CrossWindows::Linker::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::CrossWindowsToolChain &>(getToolChain()); + const llvm::Triple &T = TC.getTriple(); + const Driver &D = TC.getDriver(); + SmallString<128> EntryPoint; + ArgStringList CmdArgs; + const char *Exec; + + // Silence warning for "clang -g foo.o -o foo" + Args.ClaimAllArgs(options::OPT_g_Group); + // and "clang -emit-llvm foo.o -o foo" + Args.ClaimAllArgs(options::OPT_emit_llvm); + // and for "clang -w foo.o -o foo" + Args.ClaimAllArgs(options::OPT_w); + // Other warning options are already handled somewhere else. + + if (!D.SysRoot.empty()) + CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot)); + + if (Args.hasArg(options::OPT_pie)) + CmdArgs.push_back("-pie"); + if (Args.hasArg(options::OPT_rdynamic)) + CmdArgs.push_back("-export-dynamic"); + if (Args.hasArg(options::OPT_s)) + CmdArgs.push_back("--strip-all"); + + CmdArgs.push_back("-m"); + switch (TC.getArch()) { + default: + llvm_unreachable("unsupported architecture"); + case llvm::Triple::arm: + case llvm::Triple::thumb: + // FIXME: this is incorrect for WinCE + CmdArgs.push_back("thumb2pe"); + break; + case llvm::Triple::x86: + CmdArgs.push_back("i386pe"); + EntryPoint.append("_"); + break; + case llvm::Triple::x86_64: + CmdArgs.push_back("i386pep"); + break; + } + + if (Args.hasArg(options::OPT_shared)) { + switch (T.getArch()) { + default: + llvm_unreachable("unsupported architecture"); + case llvm::Triple::arm: + case llvm::Triple::thumb: + case llvm::Triple::x86_64: + EntryPoint.append("_DllMainCRTStartup"); + break; + case llvm::Triple::x86: + EntryPoint.append("_DllMainCRTStartup@12"); + break; + } + + CmdArgs.push_back("-shared"); + CmdArgs.push_back("-Bdynamic"); + + CmdArgs.push_back("--enable-auto-image-base"); + + CmdArgs.push_back("--entry"); + CmdArgs.push_back(Args.MakeArgString(EntryPoint)); + } else { + EntryPoint.append("mainCRTStartup"); + + CmdArgs.push_back(Args.hasArg(options::OPT_static) ? "-Bstatic" + : "-Bdynamic"); + + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) { + CmdArgs.push_back("--entry"); + CmdArgs.push_back(Args.MakeArgString(EntryPoint)); + } + + // FIXME: handle subsystem + } + + // NOTE: deal with multiple definitions on Windows (e.g. COMDAT) + CmdArgs.push_back("--allow-multiple-definition"); + + CmdArgs.push_back("-o"); + CmdArgs.push_back(Output.getFilename()); + + if (Args.hasArg(options::OPT_shared) || Args.hasArg(options::OPT_rdynamic)) { + SmallString<261> ImpLib(Output.getFilename()); + llvm::sys::path::replace_extension(ImpLib, ".lib"); + + CmdArgs.push_back("--out-implib"); + CmdArgs.push_back(Args.MakeArgString(ImpLib)); + } + + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) { + const std::string CRTPath(D.SysRoot + "/usr/lib/"); + const char *CRTBegin; + + CRTBegin = + Args.hasArg(options::OPT_shared) ? "crtbeginS.obj" : "crtbegin.obj"; + CmdArgs.push_back(Args.MakeArgString(CRTPath + CRTBegin)); + } + + Args.AddAllArgs(CmdArgs, options::OPT_L); + TC.AddFilePathLibArgs(Args, CmdArgs); + AddLinkerInputs(TC, Inputs, Args, CmdArgs, JA); + + if (D.CCCIsCXX() && !Args.hasArg(options::OPT_nostdlib) && + !Args.hasArg(options::OPT_nodefaultlibs)) { + bool StaticCXX = Args.hasArg(options::OPT_static_libstdcxx) && + !Args.hasArg(options::OPT_static); + if (StaticCXX) + CmdArgs.push_back("-Bstatic"); + TC.AddCXXStdlibLibArgs(Args, CmdArgs); + if (StaticCXX) + CmdArgs.push_back("-Bdynamic"); + } + + if (!Args.hasArg(options::OPT_nostdlib)) { + if (!Args.hasArg(options::OPT_nodefaultlibs)) { + // TODO handle /MT[d] /MD[d] + CmdArgs.push_back("-lmsvcrt"); + AddRunTimeLibs(TC, D, CmdArgs, Args); + } + } + + if (TC.getSanitizerArgs().needsAsanRt()) { + // TODO handle /MT[d] /MD[d] + if (Args.hasArg(options::OPT_shared)) { + CmdArgs.push_back(TC.getCompilerRTArgString(Args, "asan_dll_thunk")); + } else { + for (const auto &Lib : {"asan_dynamic", "asan_dynamic_runtime_thunk"}) + CmdArgs.push_back(TC.getCompilerRTArgString(Args, Lib)); + // Make sure the dynamic runtime thunk is not optimized out at link time + // to ensure proper SEH handling. + CmdArgs.push_back(Args.MakeArgString("--undefined")); + CmdArgs.push_back(Args.MakeArgString(TC.getArch() == llvm::Triple::x86 + ? "___asan_seh_interceptor" + : "__asan_seh_interceptor")); + } + } + + Exec = Args.MakeArgString(TC.GetLinkerPath()); + + C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); +} + +CrossWindowsToolChain::CrossWindowsToolChain(const Driver &D, + const llvm::Triple &T, + const llvm::opt::ArgList &Args) + : Generic_GCC(D, T, Args) { + if (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"); + } +} + +bool CrossWindowsToolChain::IsUnwindTablesDefault() const { + // FIXME: all non-x86 targets need unwind tables, however, LLVM currently does + // not know how to emit them. + return getArch() == llvm::Triple::x86_64; +} + +bool CrossWindowsToolChain::isPICDefault() const { + return getArch() == llvm::Triple::x86_64; +} + +bool CrossWindowsToolChain::isPIEDefault() const { + return getArch() == llvm::Triple::x86_64; +} + +bool CrossWindowsToolChain::isPICDefaultForced() const { + return getArch() == llvm::Triple::x86_64; +} + +void CrossWindowsToolChain:: +AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const { + const Driver &D = getDriver(); + const std::string &SysRoot = D.SysRoot; + + if (DriverArgs.hasArg(options::OPT_nostdlibinc)) + return; + + addSystemInclude(DriverArgs, CC1Args, SysRoot + "/usr/local/include"); + if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) { + SmallString<128> ResourceDir(D.ResourceDir); + llvm::sys::path::append(ResourceDir, "include"); + addSystemInclude(DriverArgs, CC1Args, ResourceDir); + } + for (const auto &P : DriverArgs.getAllArgValues(options::OPT_isystem_after)) + addSystemInclude(DriverArgs, CC1Args, P); + addExternCSystemInclude(DriverArgs, CC1Args, SysRoot + "/usr/include"); +} + +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_nostdlibinc) || + DriverArgs.hasArg(options::OPT_nostdincxx)) + return; + + switch (GetCXXStdlibType(DriverArgs)) { + case 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: + 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 { + SanitizerMask Res = ToolChain::getSupportedSanitizers(); + Res |= SanitizerKind::Address; + return Res; +} + +Tool *CrossWindowsToolChain::buildLinker() const { + return new tools::CrossWindows::Linker(*this); +} + +Tool *CrossWindowsToolChain::buildAssembler() const { + return new tools::CrossWindows::Assembler(*this); +} diff --git a/lib/Driver/ToolChains/CrossWindows.h b/lib/Driver/ToolChains/CrossWindows.h new file mode 100644 index 0000000000..5375a6324a --- /dev/null +++ b/lib/Driver/ToolChains/CrossWindows.h @@ -0,0 +1,88 @@ +//===--- CrossWindows.h - CrossWindows ToolChain Implementation -*- 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_CROSSWINDOWS_H +#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_CROSSWINDOWS_H + +#include "Cuda.h" +#include "Gnu.h" +#include "clang/Driver/Tool.h" +#include "clang/Driver/ToolChain.h" + +namespace clang { +namespace driver { +namespace tools { + +namespace CrossWindows { +class LLVM_LIBRARY_VISIBILITY Assembler : public Tool { +public: + Assembler(const ToolChain &TC) : Tool("CrossWindows::Assembler", "as", 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 Tool { +public: + Linker(const ToolChain &TC) + : Tool("CrossWindows::Linker", "ld", TC, RF_Full) {} + + 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 CrossWindows +} // end namespace tools + +namespace toolchains { + +class LLVM_LIBRARY_VISIBILITY CrossWindowsToolChain : public Generic_GCC { +public: + CrossWindowsToolChain(const Driver &D, const llvm::Triple &T, + const llvm::opt::ArgList &Args); + + bool IsIntegratedAssemblerDefault() const override { return true; } + bool IsUnwindTablesDefault() const override; + bool isPICDefault() const override; + bool isPIEDefault() const override; + bool isPICDefaultForced() const override; + + unsigned int GetDefaultStackProtectorLevel(bool KernelOrKext) const override { + return 0; + } + + void + AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const override; + void AddClangCXXStdlibIncludeArgs( + const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const override; + void AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) const override; + + SanitizerMask getSupportedSanitizers() const override; + +protected: + Tool *buildLinker() const override; + Tool *buildAssembler() const override; +}; + +} // end namespace toolchains +} // end namespace driver +} // end namespace clang + +#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_CROSSWINDOWS_H diff --git a/lib/Driver/ToolChains/Cuda.cpp b/lib/Driver/ToolChains/Cuda.cpp new file mode 100644 index 0000000000..42bf164f1b --- /dev/null +++ b/lib/Driver/ToolChains/Cuda.cpp @@ -0,0 +1,488 @@ +//===--- Cuda.cpp - Cuda Tool and ToolChain Implementations -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "Cuda.h" +#include "InputInfo.h" +#include "clang/Basic/Cuda.h" +#include "clang/Basic/VirtualFileSystem.h" +#include "clang/Driver/Compilation.h" +#include "clang/Driver/Driver.h" +#include "clang/Driver/DriverDiagnostic.h" +#include "clang/Driver/Options.h" +#include "llvm/Option/ArgList.h" +#include "llvm/Support/Path.h" +#include <system_error> + +using namespace clang::driver; +using namespace clang::driver::toolchains; +using namespace clang::driver::tools; +using namespace clang; +using namespace llvm::opt; + +// Parses the contents of version.txt in an CUDA installation. It should +// contain one line of the from e.g. "CUDA Version 7.5.2". +static CudaVersion ParseCudaVersionFile(llvm::StringRef V) { + if (!V.startswith("CUDA Version ")) + return CudaVersion::UNKNOWN; + V = V.substr(strlen("CUDA Version ")); + int Major = -1, Minor = -1; + auto First = V.split('.'); + auto Second = First.second.split('.'); + if (First.first.getAsInteger(10, Major) || + Second.first.getAsInteger(10, Minor)) + return CudaVersion::UNKNOWN; + + if (Major == 7 && Minor == 0) { + // This doesn't appear to ever happen -- version.txt doesn't exist in the + // CUDA 7 installs I've seen. But no harm in checking. + return CudaVersion::CUDA_70; + } + if (Major == 7 && Minor == 5) + return CudaVersion::CUDA_75; + if (Major == 8 && Minor == 0) + return CudaVersion::CUDA_80; + return CudaVersion::UNKNOWN; +} + +CudaInstallationDetector::CudaInstallationDetector( + const Driver &D, const llvm::Triple &HostTriple, + const llvm::opt::ArgList &Args) + : D(D) { + SmallVector<std::string, 4> CudaPathCandidates; + + // In decreasing order so we prefer newer versions to older versions. + std::initializer_list<const char *> Versions = {"8.0", "7.5", "7.0"}; + + if (Args.hasArg(clang::driver::options::OPT_cuda_path_EQ)) { + CudaPathCandidates.push_back( + Args.getLastArgValue(clang::driver::options::OPT_cuda_path_EQ)); + } else if (HostTriple.isOSWindows()) { + for (const char *Ver : Versions) + CudaPathCandidates.push_back( + D.SysRoot + "/Program Files/NVIDIA GPU Computing Toolkit/CUDA/v" + + Ver); + } else { + CudaPathCandidates.push_back(D.SysRoot + "/usr/local/cuda"); + for (const char *Ver : Versions) + CudaPathCandidates.push_back(D.SysRoot + "/usr/local/cuda-" + Ver); + } + + for (const auto &CudaPath : CudaPathCandidates) { + if (CudaPath.empty() || !D.getVFS().exists(CudaPath)) + continue; + + InstallPath = CudaPath; + BinPath = CudaPath + "/bin"; + IncludePath = InstallPath + "/include"; + LibDevicePath = InstallPath + "/nvvm/libdevice"; + + auto &FS = D.getVFS(); + if (!(FS.exists(IncludePath) && FS.exists(BinPath) && + FS.exists(LibDevicePath))) + continue; + + // On Linux, we have both lib and lib64 directories, and we need to choose + // based on our triple. On MacOS, we have only a lib directory. + // + // It's sufficient for our purposes to be flexible: If both lib and lib64 + // exist, we choose whichever one matches our triple. Otherwise, if only + // lib exists, we use it. + if (HostTriple.isArch64Bit() && FS.exists(InstallPath + "/lib64")) + LibPath = InstallPath + "/lib64"; + else if (FS.exists(InstallPath + "/lib")) + LibPath = InstallPath + "/lib"; + else + continue; + + llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> VersionFile = + FS.getBufferForFile(InstallPath + "/version.txt"); + if (!VersionFile) { + // CUDA 7.0 doesn't have a version.txt, so guess that's our version if + // version.txt isn't present. + Version = CudaVersion::CUDA_70; + } else { + 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; + } + } + } + + IsValid = true; + break; + } +} + +void CudaInstallationDetector::AddCudaIncludeArgs( + const ArgList &DriverArgs, ArgStringList &CC1Args) const { + if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) { + // Add cuda_wrappers/* to our system include path. This lets us wrap + // standard library headers. + SmallString<128> P(D.ResourceDir); + llvm::sys::path::append(P, "include"); + llvm::sys::path::append(P, "cuda_wrappers"); + CC1Args.push_back("-internal-isystem"); + CC1Args.push_back(DriverArgs.MakeArgString(P)); + } + + if (DriverArgs.hasArg(options::OPT_nocudainc)) + return; + + if (!isValid()) { + D.Diag(diag::err_drv_no_cuda_installation); + return; + } + + CC1Args.push_back("-internal-isystem"); + CC1Args.push_back(DriverArgs.MakeArgString(getIncludePath())); + CC1Args.push_back("-include"); + CC1Args.push_back("__clang_cuda_runtime_wrapper.h"); +} + +void CudaInstallationDetector::CheckCudaVersionSupportsArch( + CudaArch Arch) const { + if (Arch == CudaArch::UNKNOWN || Version == CudaVersion::UNKNOWN || + ArchsWithVersionTooLowErrors.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); + } +} + +void CudaInstallationDetector::print(raw_ostream &OS) const { + if (isValid()) + OS << "Found CUDA installation: " << InstallPath << ", version " + << CudaVersionToString(Version) << "\n"; +} + +void NVPTX::Assembler::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"); + + // Obtain architecture from the action. + CudaArch gpu_arch = StringToCudaArch(JA.getOffloadingArch()); + assert(gpu_arch != CudaArch::UNKNOWN && + "Device action expected to have an architecture."); + + // Check that our installation's ptxas supports gpu_arch. + if (!Args.hasArg(options::OPT_no_cuda_version_check)) { + TC.CudaInstallation.CheckCudaVersionSupportsArch(gpu_arch); + } + + ArgStringList CmdArgs; + CmdArgs.push_back(TC.getTriple().isArch64Bit() ? "-m64" : "-m32"); + if (Args.hasFlag(options::OPT_cuda_noopt_device_debug, + options::OPT_no_cuda_noopt_device_debug, false)) { + // ptxas does not accept -g option if optimization is enabled, so + // we ignore the compiler's -O* options if we want debug info. + CmdArgs.push_back("-g"); + CmdArgs.push_back("--dont-merge-basicblocks"); + CmdArgs.push_back("--return-at-end"); + } else if (Arg *A = Args.getLastArg(options::OPT_O_Group)) { + // Map the -O we received to -O{0,1,2,3}. + // + // TODO: Perhaps we should map host -O2 to ptxas -O3. -O3 is ptxas's + // default, so it may correspond more closely to the spirit of clang -O2. + + // -O3 seems like the least-bad option when -Osomething is specified to + // clang but it isn't handled below. + StringRef OOpt = "3"; + if (A->getOption().matches(options::OPT_O4) || + A->getOption().matches(options::OPT_Ofast)) + OOpt = "3"; + else if (A->getOption().matches(options::OPT_O0)) + OOpt = "0"; + else if (A->getOption().matches(options::OPT_O)) { + // -Os, -Oz, and -O(anything else) map to -O2, for lack of better options. + OOpt = llvm::StringSwitch<const char *>(A->getValue()) + .Case("1", "1") + .Case("2", "2") + .Case("3", "3") + .Case("s", "2") + .Case("z", "2") + .Default("2"); + } + CmdArgs.push_back(Args.MakeArgString(llvm::Twine("-O") + OOpt)); + } else { + // If no -O was passed, pass -O0 to ptxas -- no opt flag should correspond + // to no optimizations, but ptxas's default is -O3. + CmdArgs.push_back("-O0"); + } + + 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())); + 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)); + + const char *Exec; + if (Arg *A = Args.getLastArg(options::OPT_ptxas_path_EQ)) + Exec = A->getValue(); + else + Exec = Args.MakeArgString(TC.GetProgramPath("ptxas")); + C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); +} + +// All inputs to this linker must be from CudaDeviceActions, as we need to look +// at the Inputs' Actions in order to figure out which GPU architecture they +// correspond to. +void NVPTX::Linker::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; + CmdArgs.push_back("--cuda"); + CmdArgs.push_back(TC.getTriple().isArch64Bit() ? "-64" : "-32"); + CmdArgs.push_back(Args.MakeArgString("--create")); + CmdArgs.push_back(Args.MakeArgString(Output.getFilename())); + + for (const auto& II : Inputs) { + auto *A = II.getAction(); + assert(A->getInputs().size() == 1 && + "Device offload action is expected to have a single input"); + const char *gpu_arch_str = A->getOffloadingArch(); + assert(gpu_arch_str && + "Device action expected to have associated a GPU architecture!"); + CudaArch gpu_arch = StringToCudaArch(gpu_arch_str); + + // We need to pass an Arch of the form "sm_XX" for cubin files and + // "compute_XX" for ptx. + const char *Arch = + (II.getType() == types::TY_PP_Asm) + ? CudaVirtualArchToString(VirtualArchForCudaArch(gpu_arch)) + : gpu_arch_str; + CmdArgs.push_back(Args.MakeArgString(llvm::Twine("--image=profile=") + + Arch + ",file=" + II.getFilename())); + } + + for (const auto& A : Args.getAllArgValues(options::OPT_Xcuda_fatbinary)) + CmdArgs.push_back(Args.MakeArgString(A)); + + const char *Exec = Args.MakeArgString(TC.GetProgramPath("fatbinary")); + 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) + : ToolChain(D, Triple, Args), HostTC(HostTC), + CudaInstallation(D, HostTC.getTriple(), Args) { + if (CudaInstallation.isValid()) + getProgramPaths().push_back(CudaInstallation.getBinPath()); +} + +void CudaToolChain::addClangTargetOptions( + const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const { + HostTC.addClangTargetOptions(DriverArgs, CC1Args); + + CC1Args.push_back("-fcuda-is-device"); + + if (DriverArgs.hasFlag(options::OPT_fcuda_flush_denormals_to_zero, + options::OPT_fno_cuda_flush_denormals_to_zero, false)) + CC1Args.push_back("-fcuda-flush-denormals-to-zero"); + + 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; + + StringRef GpuArch = DriverArgs.getLastArgValue(options::OPT_march_EQ); + assert(!GpuArch.empty() && "Must have an explicit GPU arch."); + std::string LibDeviceFile = CudaInstallation.getLibDeviceFile(GpuArch); + + if (LibDeviceFile.empty()) { + getDriver().Diag(diag::err_drv_no_cuda_libdevice) << GpuArch; + return; + } + + 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"); +} + +void CudaToolChain::AddCudaIncludeArgs(const ArgList &DriverArgs, + ArgStringList &CC1Args) const { + // Check our CUDA version if we're going to include the CUDA headers. + if (!DriverArgs.hasArg(options::OPT_nocudainc) && + !DriverArgs.hasArg(options::OPT_no_cuda_version_check)) { + StringRef Arch = DriverArgs.getLastArgValue(options::OPT_march_EQ); + assert(!Arch.empty() && "Must have an explicit GPU arch."); + CudaInstallation.CheckCudaVersionSupportsArch(StringToCudaArch(Arch)); + } + CudaInstallation.AddCudaIncludeArgs(DriverArgs, CC1Args); +} + +llvm::opt::DerivedArgList * +CudaToolChain::TranslateArgs(const llvm::opt::DerivedArgList &Args, + StringRef BoundArch, + Action::OffloadKind DeviceOffloadKind) const { + DerivedArgList *DAL = + HostTC.TranslateArgs(Args, BoundArch, DeviceOffloadKind); + if (!DAL) + DAL = new DerivedArgList(Args.getBaseArgs()); + + const OptTable &Opts = getDriver().getOpts(); + + for (Arg *A : Args) { + if (A->getOption().matches(options::OPT_Xarch__)) { + // Skip this argument unless the architecture matches BoundArch + if (BoundArch.empty() || A->getValue(0) != BoundArch) + continue; + + unsigned Index = Args.getBaseArgs().MakeIndex(A->getValue(1)); + unsigned Prev = Index; + std::unique_ptr<Arg> XarchArg(Opts.ParseOneArg(Args, Index)); + + // If the argument parsing failed or more than one argument was + // consumed, the -Xarch_ argument's parameter tried to consume + // extra arguments. Emit an error and ignore. + // + // We also want to disallow any options which would alter the + // driver behavior; that isn't going to work in our model. We + // use isDriverOption() as an approximation, although things + // like -O4 are going to slip through. + if (!XarchArg || Index > Prev + 1) { + getDriver().Diag(diag::err_drv_invalid_Xarch_argument_with_args) + << A->getAsString(Args); + continue; + } else if (XarchArg->getOption().hasFlag(options::DriverOption)) { + getDriver().Diag(diag::err_drv_invalid_Xarch_argument_isdriver) + << A->getAsString(Args); + continue; + } + XarchArg->setBaseArg(A); + A = XarchArg.release(); + DAL->AddSynthesizedArg(A); + } + DAL->append(A); + } + + if (!BoundArch.empty()) { + DAL->eraseArg(options::OPT_march_EQ); + DAL->AddJoinedArg(nullptr, Opts.getOption(options::OPT_march_EQ), BoundArch); + } + return DAL; +} + +Tool *CudaToolChain::buildAssembler() const { + return new tools::NVPTX::Assembler(*this); +} + +Tool *CudaToolChain::buildLinker() const { + return new tools::NVPTX::Linker(*this); +} + +void CudaToolChain::addClangWarningOptions(ArgStringList &CC1Args) const { + HostTC.addClangWarningOptions(CC1Args); +} + +ToolChain::CXXStdlibType +CudaToolChain::GetCXXStdlibType(const ArgList &Args) const { + return HostTC.GetCXXStdlibType(Args); +} + +void CudaToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs, + ArgStringList &CC1Args) const { + HostTC.AddClangSystemIncludeArgs(DriverArgs, CC1Args); +} + +void CudaToolChain::AddClangCXXStdlibIncludeArgs(const ArgList &Args, + ArgStringList &CC1Args) const { + HostTC.AddClangCXXStdlibIncludeArgs(Args, CC1Args); +} + +void CudaToolChain::AddIAMCUIncludeArgs(const ArgList &Args, + ArgStringList &CC1Args) const { + HostTC.AddIAMCUIncludeArgs(Args, CC1Args); +} + +SanitizerMask CudaToolChain::getSupportedSanitizers() const { + // The CudaToolChain only supports sanitizers in the sense that it allows + // sanitizer arguments on the command line if they are supported by the host + // toolchain. The CudaToolChain will actually ignore any command line + // arguments for any of these "supported" sanitizers. That means that no + // sanitization of device code is actually supported at this time. + // + // This behavior is necessary because the host and device toolchains + // invocations often share the command line, so the device toolchain must + // tolerate flags meant only for the host toolchain. + return HostTC.getSupportedSanitizers(); +} + +VersionTuple CudaToolChain::computeMSVCVersion(const Driver *D, + const ArgList &Args) const { + return HostTC.computeMSVCVersion(D, Args); +} diff --git a/lib/Driver/ToolChains/Cuda.h b/lib/Driver/ToolChains/Cuda.h new file mode 100644 index 0000000000..acdb4c4efd --- /dev/null +++ b/lib/Driver/ToolChains/Cuda.h @@ -0,0 +1,177 @@ +//===--- Cuda.h - Cuda 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_CUDA_H +#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_CUDA_H + +#include "clang/Basic/Cuda.h" +#include "clang/Basic/VersionTuple.h" +#include "clang/Driver/Action.h" +#include "clang/Driver/Multilib.h" +#include "clang/Driver/ToolChain.h" +#include "clang/Driver/Tool.h" +#include "llvm/ADT/Optional.h" +#include "llvm/ADT/SmallSet.h" +#include "llvm/Support/Compiler.h" +#include <set> +#include <vector> + +namespace clang { +namespace driver { + +/// A class to find a viable CUDA installation +class CudaInstallationDetector { +private: + const Driver &D; + bool IsValid = false; + CudaVersion Version = CudaVersion::UNKNOWN; + std::string InstallPath; + std::string BinPath; + std::string LibPath; + std::string LibDevicePath; + std::string IncludePath; + llvm::StringMap<std::string> LibDeviceMap; + + // CUDA architectures for which we have raised an error in + // CheckCudaVersionSupportsArch. + mutable llvm::SmallSet<CudaArch, 4> ArchsWithVersionTooLowErrors; + +public: + CudaInstallationDetector(const Driver &D, const llvm::Triple &HostTriple, + const llvm::opt::ArgList &Args); + + void AddCudaIncludeArgs(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const; + + /// \brief Emit an error if Version does not support the given Arch. + /// + /// If either Version or Arch is unknown, does not emit an error. Emits at + /// most one error per Arch. + void CheckCudaVersionSupportsArch(CudaArch Arch) const; + + /// \brief Check whether we detected a valid Cuda install. + bool isValid() const { return IsValid; } + /// \brief Print information about the detected CUDA installation. + void print(raw_ostream &OS) const; + + /// \brief Get the detected Cuda install's version. + CudaVersion version() const { return Version; } + /// \brief Get the detected Cuda installation path. + StringRef getInstallPath() const { return InstallPath; } + /// \brief Get the detected path to Cuda's bin directory. + StringRef getBinPath() const { return BinPath; } + /// \brief Get the detected Cuda Include path. + StringRef getIncludePath() const { return IncludePath; } + /// \brief Get the detected Cuda library path. + StringRef getLibPath() const { return LibPath; } + /// \brief Get the detected Cuda device library path. + StringRef getLibDevicePath() const { return LibDevicePath; } + /// \brief Get libdevice file for given architecture + std::string getLibDeviceFile(StringRef Gpu) const { + return LibDeviceMap.lookup(Gpu); + } +}; + +namespace tools { +namespace NVPTX { + +// Run ptxas, the NVPTX assembler. +class LLVM_LIBRARY_VISIBILITY Assembler : public Tool { + public: + Assembler(const ToolChain &TC) + : Tool("NVPTX::Assembler", "ptxas", 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; +}; + +// Runs fatbinary, which combines GPU object files ("cubin" files) and/or PTX +// assembly into a single output file. +class LLVM_LIBRARY_VISIBILITY Linker : public Tool { + public: + Linker(const ToolChain &TC) + : Tool("NVPTX::Linker", "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 + +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); + + virtual const llvm::Triple *getAuxTriple() const override { + return &HostTC.getTriple(); + } + + llvm::opt::DerivedArgList * + TranslateArgs(const llvm::opt::DerivedArgList &Args, StringRef BoundArch, + Action::OffloadKind DeviceOffloadKind) const override; + void addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const override; + + // Never try to use the integrated assembler with CUDA; always fork out to + // ptxas. + bool useIntegratedAs() const override { return false; } + bool isCrossCompiling() const override { return true; } + bool isPICDefault() const override { return false; } + bool isPIEDefault() const override { return false; } + bool isPICDefaultForced() const override { return false; } + bool SupportsProfiling() const override { return false; } + bool SupportsObjCGC() const override { return false; } + + void AddCudaIncludeArgs(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const override; + + void addClangWarningOptions(llvm::opt::ArgStringList &CC1Args) const override; + CXXStdlibType GetCXXStdlibType(const llvm::opt::ArgList &Args) const override; + void + AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const override; + void AddClangCXXStdlibIncludeArgs( + const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CC1Args) const override; + void AddIAMCUIncludeArgs(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const override; + + SanitizerMask getSupportedSanitizers() const override; + + VersionTuple + computeMSVCVersion(const Driver *D, + const llvm::opt::ArgList &Args) const override; + + const ToolChain &HostTC; + CudaInstallationDetector CudaInstallation; + +protected: + Tool *buildAssembler() const override; // ptxas + Tool *buildLinker() const override; // fatbinary (ok, not really a linker) +}; + +} // end namespace toolchains +} // end namespace driver +} // end namespace clang + +#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_CUDA_H diff --git a/lib/Driver/ToolChains/Darwin.cpp b/lib/Driver/ToolChains/Darwin.cpp new file mode 100644 index 0000000000..4cddf65c6c --- /dev/null +++ b/lib/Driver/ToolChains/Darwin.cpp @@ -0,0 +1,1896 @@ +//===--- Darwin.cpp - Darwin Tool and ToolChain Implementations -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "Darwin.h" +#include "Arch/ARM.h" +#include "CommonArgs.h" +#include "clang/Basic/ObjCRuntime.h" +#include "clang/Basic/VirtualFileSystem.h" +#include "clang/Driver/Compilation.h" +#include "clang/Driver/Driver.h" +#include "clang/Driver/DriverDiagnostic.h" +#include "clang/Driver/Options.h" +#include "clang/Driver/SanitizerArgs.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/Option/ArgList.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/ScopedPrinter.h" +#include "llvm/Support/TargetParser.h" +#include <cstdlib> // ::getenv + +using namespace clang::driver; +using namespace clang::driver::tools; +using namespace clang::driver::toolchains; +using namespace clang; +using namespace llvm::opt; + +llvm::Triple::ArchType darwin::getArchTypeForMachOArchName(StringRef Str) { + // See arch(3) and llvm-gcc's driver-driver.c. We don't implement support for + // archs which Darwin doesn't use. + + // The matching this routine does is fairly pointless, since it is neither the + // complete architecture list, nor a reasonable subset. The problem is that + // historically the driver driver accepts this and also ties its -march= + // handling to the architecture name, so we need to be careful before removing + // support for it. + + // This code must be kept in sync with Clang's Darwin specific argument + // translation. + + return llvm::StringSwitch<llvm::Triple::ArchType>(Str) + .Cases("ppc", "ppc601", "ppc603", "ppc604", "ppc604e", llvm::Triple::ppc) + .Cases("ppc750", "ppc7400", "ppc7450", "ppc970", llvm::Triple::ppc) + .Case("ppc64", llvm::Triple::ppc64) + .Cases("i386", "i486", "i486SX", "i586", "i686", llvm::Triple::x86) + .Cases("pentium", "pentpro", "pentIIm3", "pentIIm5", "pentium4", + llvm::Triple::x86) + .Cases("x86_64", "x86_64h", llvm::Triple::x86_64) + // This is derived from the driver driver. + .Cases("arm", "armv4t", "armv5", "armv6", "armv6m", llvm::Triple::arm) + .Cases("armv7", "armv7em", "armv7k", "armv7m", llvm::Triple::arm) + .Cases("armv7s", "xscale", llvm::Triple::arm) + .Case("arm64", llvm::Triple::aarch64) + .Case("r600", llvm::Triple::r600) + .Case("amdgcn", llvm::Triple::amdgcn) + .Case("nvptx", llvm::Triple::nvptx) + .Case("nvptx64", llvm::Triple::nvptx64) + .Case("amdil", llvm::Triple::amdil) + .Case("spir", llvm::Triple::spir) + .Default(llvm::Triple::UnknownArch); +} + +void darwin::setTripleTypeForMachOArchName(llvm::Triple &T, StringRef Str) { + const llvm::Triple::ArchType Arch = getArchTypeForMachOArchName(Str); + unsigned 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) { + T.setOS(llvm::Triple::UnknownOS); + T.setObjectFormat(llvm::Triple::MachO); + } +} + +void darwin::Assembler::ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, + const InputInfoList &Inputs, + const ArgList &Args, + const char *LinkingOutput) const { + ArgStringList CmdArgs; + + assert(Inputs.size() == 1 && "Unexpected number of inputs."); + const InputInfo &Input = Inputs[0]; + + // Determine the original source input. + const Action *SourceAction = &JA; + while (SourceAction->getKind() != Action::InputClass) { + assert(!SourceAction->getInputs().empty() && "unexpected root action!"); + SourceAction = SourceAction->getInputs()[0]; + } + + // If -fno-integrated-as is used add -Q to the darwin assember driver to make + // sure it runs its system assembler not clang's integrated assembler. + // Applicable to darwin11+ and Xcode 4+. darwin<10 lacked integrated-as. + // FIXME: at run-time detect assembler capabilities or rely on version + // information forwarded by -target-assembler-version. + if (Args.hasArg(options::OPT_fno_integrated_as)) { + const llvm::Triple &T(getToolChain().getTriple()); + if (!(T.isMacOSX() && T.isMacOSXVersionLT(10, 7))) + CmdArgs.push_back("-Q"); + } + + // Forward -g, assuming we are dealing with an actual assembly file. + if (SourceAction->getType() == types::TY_Asm || + SourceAction->getType() == types::TY_PP_Asm) { + if (Args.hasArg(options::OPT_gstabs)) + CmdArgs.push_back("--gstabs"); + else if (Args.hasArg(options::OPT_g_Group)) + CmdArgs.push_back("-g"); + } + + // Derived from asm spec. + AddMachOArch(Args, CmdArgs); + + // Use -force_cpusubtype_ALL on x86 by default. + if (getToolChain().getArch() == llvm::Triple::x86 || + getToolChain().getArch() == llvm::Triple::x86_64 || + Args.hasArg(options::OPT_force__cpusubtype__ALL)) + CmdArgs.push_back("-force_cpusubtype_ALL"); + + if (getToolChain().getArch() != llvm::Triple::x86_64 && + (((Args.hasArg(options::OPT_mkernel) || + Args.hasArg(options::OPT_fapple_kext)) && + getMachOToolChain().isKernelStatic()) || + Args.hasArg(options::OPT_static))) + CmdArgs.push_back("-static"); + + Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler); + + assert(Output.isFilename() && "Unexpected lipo output."); + CmdArgs.push_back("-o"); + CmdArgs.push_back(Output.getFilename()); + + assert(Input.isFilename() && "Invalid input."); + CmdArgs.push_back(Input.getFilename()); + + // asm_final spec is empty. + + const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("as")); + C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); +} + +void darwin::MachOTool::anchor() {} + +void darwin::MachOTool::AddMachOArch(const ArgList &Args, + ArgStringList &CmdArgs) const { + StringRef ArchName = getMachOToolChain().getMachOArchName(Args); + + // Derived from darwin_arch spec. + CmdArgs.push_back("-arch"); + CmdArgs.push_back(Args.MakeArgString(ArchName)); + + // FIXME: Is this needed anymore? + if (ArchName == "arm") + CmdArgs.push_back("-force_cpusubtype_ALL"); +} + +bool darwin::Linker::NeedsTempPath(const InputInfoList &Inputs) const { + // We only need to generate a temp path for LTO if we aren't compiling object + // files. When compiling source files, we run 'dsymutil' after linking. We + // don't run 'dsymutil' when compiling object files. + for (const auto &Input : Inputs) + if (Input.getType() != types::TY_Object) + return true; + + return false; +} + +/// \brief Pass -no_deduplicate to ld64 under certain conditions: +/// +/// - Either -O0 or -O1 is explicitly specified +/// - No -O option is specified *and* this is a compile+link (implicit -O0) +/// +/// Also do *not* add -no_deduplicate when no -O option is specified and this +/// is just a link (we can't imply -O0) +static bool shouldLinkerNotDedup(bool IsLinkerOnlyAction, const ArgList &Args) { + if (Arg *A = Args.getLastArg(options::OPT_O_Group)) { + if (A->getOption().matches(options::OPT_O0)) + return true; + if (A->getOption().matches(options::OPT_O)) + return llvm::StringSwitch<bool>(A->getValue()) + .Case("1", true) + .Default(false); + return false; // OPT_Ofast & OPT_O4 + } + + if (!IsLinkerOnlyAction) // Implicit -O0 for compile+linker only. + return true; + return false; +} + +void darwin::Linker::AddLinkArgs(Compilation &C, const ArgList &Args, + ArgStringList &CmdArgs, + const InputInfoList &Inputs) const { + const Driver &D = getToolChain().getDriver(); + const toolchains::MachO &MachOTC = getMachOToolChain(); + + unsigned Version[5] = {0, 0, 0, 0, 0}; + if (Arg *A = Args.getLastArg(options::OPT_mlinker_version_EQ)) { + if (!Driver::GetReleaseVersion(A->getValue(), Version)) + D.Diag(diag::err_drv_invalid_version_number) << A->getAsString(Args); + } + + // Newer linkers support -demangle. Pass it if supported and not disabled by + // the user. + if (Version[0] >= 100 && !Args.hasArg(options::OPT_Z_Xlinker__no_demangle)) + CmdArgs.push_back("-demangle"); + + if (Args.hasArg(options::OPT_rdynamic) && Version[0] >= 137) + CmdArgs.push_back("-export_dynamic"); + + // If we are using App Extension restrictions, pass a flag to the linker + // telling it that the compiled code has been audited. + if (Args.hasFlag(options::OPT_fapplication_extension, + options::OPT_fno_application_extension, false)) + CmdArgs.push_back("-application_extension"); + + if (D.isUsingLTO()) { + // If we are using LTO, then automatically create a temporary file path for + // the linker to use, so that it's lifetime will extend past a possible + // dsymutil step. + if (Version[0] >= 116 && NeedsTempPath(Inputs)) { + const char *TmpPath = C.getArgs().MakeArgString( + D.GetTemporaryPath("cc", types::getTypeTempSuffix(types::TY_Object))); + C.addTempFile(TmpPath); + CmdArgs.push_back("-object_path_lto"); + CmdArgs.push_back(TmpPath); + } + } + + // Use -lto_library option to specify the libLTO.dylib path. Try to find + // it in clang installed libraries. ld64 will only look at this argument + // when it actually uses LTO, so libLTO.dylib only needs to exist at link + // time if ld64 decides that it needs to use LTO. + // Since this is passed unconditionally, ld64 will never look for libLTO.dylib + // next to it. That's ok since ld64 using a libLTO.dylib not matching the + // clang version won't work anyways. + if (Version[0] >= 133) { + // Search for libLTO in <InstalledDir>/../lib/libLTO.dylib + StringRef P = llvm::sys::path::parent_path(D.Dir); + SmallString<128> LibLTOPath(P); + llvm::sys::path::append(LibLTOPath, "lib"); + llvm::sys::path::append(LibLTOPath, "libLTO.dylib"); + CmdArgs.push_back("-lto_library"); + CmdArgs.push_back(C.getArgs().MakeArgString(LibLTOPath)); + } + + // ld64 version 262 and above run the deduplicate pass by default. + if (Version[0] >= 262 && shouldLinkerNotDedup(C.getJobs().empty(), Args)) + CmdArgs.push_back("-no_deduplicate"); + + // Derived from the "link" spec. + Args.AddAllArgs(CmdArgs, options::OPT_static); + if (!Args.hasArg(options::OPT_static)) + CmdArgs.push_back("-dynamic"); + if (Args.hasArg(options::OPT_fgnu_runtime)) { + // FIXME: gcc replaces -lobjc in forward args with -lobjc-gnu + // here. How do we wish to handle such things? + } + + if (!Args.hasArg(options::OPT_dynamiclib)) { + AddMachOArch(Args, CmdArgs); + // FIXME: Why do this only on this path? + Args.AddLastArg(CmdArgs, options::OPT_force__cpusubtype__ALL); + + Args.AddLastArg(CmdArgs, options::OPT_bundle); + Args.AddAllArgs(CmdArgs, options::OPT_bundle__loader); + Args.AddAllArgs(CmdArgs, options::OPT_client__name); + + Arg *A; + if ((A = Args.getLastArg(options::OPT_compatibility__version)) || + (A = Args.getLastArg(options::OPT_current__version)) || + (A = Args.getLastArg(options::OPT_install__name))) + D.Diag(diag::err_drv_argument_only_allowed_with) << A->getAsString(Args) + << "-dynamiclib"; + + Args.AddLastArg(CmdArgs, options::OPT_force__flat__namespace); + Args.AddLastArg(CmdArgs, options::OPT_keep__private__externs); + Args.AddLastArg(CmdArgs, options::OPT_private__bundle); + } else { + CmdArgs.push_back("-dylib"); + + Arg *A; + if ((A = Args.getLastArg(options::OPT_bundle)) || + (A = Args.getLastArg(options::OPT_bundle__loader)) || + (A = Args.getLastArg(options::OPT_client__name)) || + (A = Args.getLastArg(options::OPT_force__flat__namespace)) || + (A = Args.getLastArg(options::OPT_keep__private__externs)) || + (A = Args.getLastArg(options::OPT_private__bundle))) + D.Diag(diag::err_drv_argument_not_allowed_with) << A->getAsString(Args) + << "-dynamiclib"; + + Args.AddAllArgsTranslated(CmdArgs, options::OPT_compatibility__version, + "-dylib_compatibility_version"); + Args.AddAllArgsTranslated(CmdArgs, options::OPT_current__version, + "-dylib_current_version"); + + AddMachOArch(Args, CmdArgs); + + Args.AddAllArgsTranslated(CmdArgs, options::OPT_install__name, + "-dylib_install_name"); + } + + Args.AddLastArg(CmdArgs, options::OPT_all__load); + Args.AddAllArgs(CmdArgs, options::OPT_allowable__client); + Args.AddLastArg(CmdArgs, options::OPT_bind__at__load); + if (MachOTC.isTargetIOSBased()) + Args.AddLastArg(CmdArgs, options::OPT_arch__errors__fatal); + Args.AddLastArg(CmdArgs, options::OPT_dead__strip); + Args.AddLastArg(CmdArgs, options::OPT_no__dead__strip__inits__and__terms); + Args.AddAllArgs(CmdArgs, options::OPT_dylib__file); + Args.AddLastArg(CmdArgs, options::OPT_dynamic); + Args.AddAllArgs(CmdArgs, options::OPT_exported__symbols__list); + Args.AddLastArg(CmdArgs, options::OPT_flat__namespace); + Args.AddAllArgs(CmdArgs, options::OPT_force__load); + Args.AddAllArgs(CmdArgs, options::OPT_headerpad__max__install__names); + Args.AddAllArgs(CmdArgs, options::OPT_image__base); + Args.AddAllArgs(CmdArgs, options::OPT_init); + + // Add the deployment target. + MachOTC.addMinVersionArgs(Args, CmdArgs); + + Args.AddLastArg(CmdArgs, options::OPT_nomultidefs); + Args.AddLastArg(CmdArgs, options::OPT_multi__module); + Args.AddLastArg(CmdArgs, options::OPT_single__module); + Args.AddAllArgs(CmdArgs, options::OPT_multiply__defined); + Args.AddAllArgs(CmdArgs, options::OPT_multiply__defined__unused); + + if (const Arg *A = + Args.getLastArg(options::OPT_fpie, options::OPT_fPIE, + options::OPT_fno_pie, options::OPT_fno_PIE)) { + if (A->getOption().matches(options::OPT_fpie) || + A->getOption().matches(options::OPT_fPIE)) + CmdArgs.push_back("-pie"); + else + CmdArgs.push_back("-no_pie"); + } + + // for embed-bitcode, use -bitcode_bundle in linker command + if (C.getDriver().embedBitcodeEnabled()) { + // Check if the toolchain supports bitcode build flow. + if (MachOTC.SupportsEmbeddedBitcode()) { + CmdArgs.push_back("-bitcode_bundle"); + if (C.getDriver().embedBitcodeMarkerOnly() && Version[0] >= 278) { + CmdArgs.push_back("-bitcode_process_mode"); + CmdArgs.push_back("marker"); + } + } else + D.Diag(diag::err_drv_bitcode_unsupported_on_toolchain); + } + + Args.AddLastArg(CmdArgs, options::OPT_prebind); + Args.AddLastArg(CmdArgs, options::OPT_noprebind); + Args.AddLastArg(CmdArgs, options::OPT_nofixprebinding); + Args.AddLastArg(CmdArgs, options::OPT_prebind__all__twolevel__modules); + Args.AddLastArg(CmdArgs, options::OPT_read__only__relocs); + Args.AddAllArgs(CmdArgs, options::OPT_sectcreate); + Args.AddAllArgs(CmdArgs, options::OPT_sectorder); + Args.AddAllArgs(CmdArgs, options::OPT_seg1addr); + Args.AddAllArgs(CmdArgs, options::OPT_segprot); + Args.AddAllArgs(CmdArgs, options::OPT_segaddr); + Args.AddAllArgs(CmdArgs, options::OPT_segs__read__only__addr); + Args.AddAllArgs(CmdArgs, options::OPT_segs__read__write__addr); + Args.AddAllArgs(CmdArgs, options::OPT_seg__addr__table); + Args.AddAllArgs(CmdArgs, options::OPT_seg__addr__table__filename); + Args.AddAllArgs(CmdArgs, options::OPT_sub__library); + Args.AddAllArgs(CmdArgs, options::OPT_sub__umbrella); + + // Give --sysroot= preference, over the Apple specific behavior to also use + // --isysroot as the syslibroot. + StringRef sysroot = C.getSysRoot(); + if (sysroot != "") { + CmdArgs.push_back("-syslibroot"); + CmdArgs.push_back(C.getArgs().MakeArgString(sysroot)); + } else if (const Arg *A = Args.getLastArg(options::OPT_isysroot)) { + CmdArgs.push_back("-syslibroot"); + CmdArgs.push_back(A->getValue()); + } + + Args.AddLastArg(CmdArgs, options::OPT_twolevel__namespace); + Args.AddLastArg(CmdArgs, options::OPT_twolevel__namespace__hints); + Args.AddAllArgs(CmdArgs, options::OPT_umbrella); + Args.AddAllArgs(CmdArgs, options::OPT_undefined); + Args.AddAllArgs(CmdArgs, options::OPT_unexported__symbols__list); + Args.AddAllArgs(CmdArgs, options::OPT_weak__reference__mismatches); + Args.AddLastArg(CmdArgs, options::OPT_X_Flag); + Args.AddAllArgs(CmdArgs, options::OPT_y); + Args.AddLastArg(CmdArgs, options::OPT_w); + Args.AddAllArgs(CmdArgs, options::OPT_pagezero__size); + Args.AddAllArgs(CmdArgs, options::OPT_segs__read__); + Args.AddLastArg(CmdArgs, options::OPT_seglinkedit); + Args.AddLastArg(CmdArgs, options::OPT_noseglinkedit); + Args.AddAllArgs(CmdArgs, options::OPT_sectalign); + Args.AddAllArgs(CmdArgs, options::OPT_sectobjectsymbols); + Args.AddAllArgs(CmdArgs, options::OPT_segcreate); + Args.AddLastArg(CmdArgs, options::OPT_whyload); + Args.AddLastArg(CmdArgs, options::OPT_whatsloaded); + Args.AddAllArgs(CmdArgs, options::OPT_dylinker__install__name); + Args.AddLastArg(CmdArgs, options::OPT_dylinker); + Args.AddLastArg(CmdArgs, options::OPT_Mach); +} + +/// \brief Determine whether we are linking the ObjC runtime. +static bool isObjCRuntimeLinked(const ArgList &Args) { + if (isObjCAutoRefCount(Args)) { + Args.ClaimAllArgs(options::OPT_fobjc_link_runtime); + return true; + } + return Args.hasArg(options::OPT_fobjc_link_runtime); +} + +void darwin::Linker::ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, + const InputInfoList &Inputs, + const ArgList &Args, + const char *LinkingOutput) const { + assert(Output.getType() == types::TY_Image && "Invalid linker output type."); + + // If the number of arguments surpasses the system limits, we will encode the + // input files in a separate file, shortening the command line. To this end, + // build a list of input file names that can be passed via a file with the + // -filelist linker option. + llvm::opt::ArgStringList InputFileList; + + // The logic here is derived from gcc's behavior; most of which + // comes from specs (starting with link_command). Consult gcc for + // more information. + ArgStringList CmdArgs; + + /// Hack(tm) to ignore linking errors when we are doing ARC migration. + if (Args.hasArg(options::OPT_ccc_arcmt_check, + options::OPT_ccc_arcmt_migrate)) { + for (const auto &Arg : Args) + Arg->claim(); + const char *Exec = + Args.MakeArgString(getToolChain().GetProgramPath("touch")); + CmdArgs.push_back(Output.getFilename()); + C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, None)); + return; + } + + // I'm not sure why this particular decomposition exists in gcc, but + // we follow suite for ease of comparison. + AddLinkArgs(C, Args, CmdArgs, Inputs); + + // For LTO, pass the name of the optimization record file. + if (Args.hasFlag(options::OPT_fsave_optimization_record, + options::OPT_fno_save_optimization_record, false)) { + CmdArgs.push_back("-mllvm"); + CmdArgs.push_back("-lto-pass-remarks-output"); + CmdArgs.push_back("-mllvm"); + + SmallString<128> F; + F = Output.getFilename(); + F += ".opt.yaml"; + CmdArgs.push_back(Args.MakeArgString(F)); + + if (getLastProfileUseArg(Args)) { + CmdArgs.push_back("-mllvm"); + CmdArgs.push_back("-lto-pass-remarks-with-hotness"); + } + } + + // It seems that the 'e' option is completely ignored for dynamic executables + // (the default), and with static executables, the last one wins, as expected. + Args.AddAllArgs(CmdArgs, {options::OPT_d_Flag, options::OPT_s, options::OPT_t, + options::OPT_Z_Flag, options::OPT_u_Group, + options::OPT_e, options::OPT_r}); + + // Forward -ObjC when either -ObjC or -ObjC++ is used, to force loading + // members of static archive libraries which implement Objective-C classes or + // categories. + if (Args.hasArg(options::OPT_ObjC) || Args.hasArg(options::OPT_ObjCXX)) + CmdArgs.push_back("-ObjC"); + + CmdArgs.push_back("-o"); + CmdArgs.push_back(Output.getFilename()); + + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) + getMachOToolChain().addStartObjectFileArgs(Args, CmdArgs); + + // SafeStack requires its own runtime libraries + // These libraries should be linked first, to make sure the + // __safestack_init constructor executes before everything else + if (getToolChain().getSanitizerArgs().needsSafeStackRt()) { + getMachOToolChain().AddLinkRuntimeLib(Args, CmdArgs, + "libclang_rt.safestack_osx.a", + /*AlwaysLink=*/true); + } + + Args.AddAllArgs(CmdArgs, options::OPT_L); + + AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA); + // Build the input file for -filelist (list of linker input files) in case we + // need it later + for (const auto &II : Inputs) { + if (!II.isFilename()) { + // This is a linker input argument. + // We cannot mix input arguments and file names in a -filelist input, thus + // we prematurely stop our list (remaining files shall be passed as + // arguments). + if (InputFileList.size() > 0) + break; + + continue; + } + + InputFileList.push_back(II.getFilename()); + } + + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) + addOpenMPRuntime(CmdArgs, getToolChain(), Args); + + if (isObjCRuntimeLinked(Args) && + !Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { + // We use arclite library for both ARC and subscripting support. + getMachOToolChain().AddLinkARCArgs(Args, CmdArgs); + + CmdArgs.push_back("-framework"); + CmdArgs.push_back("Foundation"); + // Link libobj. + CmdArgs.push_back("-lobjc"); + } + + if (LinkingOutput) { + CmdArgs.push_back("-arch_multiple"); + CmdArgs.push_back("-final_output"); + CmdArgs.push_back(LinkingOutput); + } + + if (Args.hasArg(options::OPT_fnested_functions)) + CmdArgs.push_back("-allow_stack_execute"); + + getMachOToolChain().addProfileRTLibs(Args, CmdArgs); + + if (unsigned Parallelism = + getLTOParallelism(Args, getToolChain().getDriver())) { + CmdArgs.push_back("-mllvm"); + CmdArgs.push_back( + Args.MakeArgString(Twine("-threads=") + llvm::to_string(Parallelism))); + } + + 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. + getMachOToolChain().AddLinkRuntimeLibArgs(Args, CmdArgs); + + // No need to do anything for pthreads. Claim argument to avoid warning. + Args.ClaimAllArgs(options::OPT_pthread); + Args.ClaimAllArgs(options::OPT_pthreads); + } + + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) { + // endfile_spec is empty. + } + + Args.AddAllArgs(CmdArgs, options::OPT_T_Group); + Args.AddAllArgs(CmdArgs, options::OPT_F); + + // -iframework should be forwarded as -F. + for (const Arg *A : Args.filtered(options::OPT_iframework)) + CmdArgs.push_back(Args.MakeArgString(std::string("-F") + A->getValue())); + + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { + if (Arg *A = Args.getLastArg(options::OPT_fveclib)) { + if (A->getValue() == StringRef("Accelerate")) { + CmdArgs.push_back("-framework"); + CmdArgs.push_back("Accelerate"); + } + } + } + + const char *Exec = Args.MakeArgString(getToolChain().GetLinkerPath()); + std::unique_ptr<Command> Cmd = + llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs); + Cmd->setInputFileList(std::move(InputFileList)); + C.addCommand(std::move(Cmd)); +} + +void darwin::Lipo::ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, + const InputInfoList &Inputs, + const ArgList &Args, + const char *LinkingOutput) const { + ArgStringList CmdArgs; + + CmdArgs.push_back("-create"); + assert(Output.isFilename() && "Unexpected lipo output."); + + CmdArgs.push_back("-output"); + CmdArgs.push_back(Output.getFilename()); + + for (const auto &II : Inputs) { + assert(II.isFilename() && "Unexpected lipo input."); + CmdArgs.push_back(II.getFilename()); + } + + const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("lipo")); + C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); +} + +void darwin::Dsymutil::ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, + const InputInfoList &Inputs, + const ArgList &Args, + const char *LinkingOutput) const { + ArgStringList CmdArgs; + + CmdArgs.push_back("-o"); + CmdArgs.push_back(Output.getFilename()); + + assert(Inputs.size() == 1 && "Unable to handle multiple inputs."); + const InputInfo &Input = Inputs[0]; + assert(Input.isFilename() && "Unexpected dsymutil input."); + CmdArgs.push_back(Input.getFilename()); + + const char *Exec = + Args.MakeArgString(getToolChain().GetProgramPath("dsymutil")); + C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); +} + +void darwin::VerifyDebug::ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, + const InputInfoList &Inputs, + const ArgList &Args, + const char *LinkingOutput) const { + ArgStringList CmdArgs; + CmdArgs.push_back("--verify"); + CmdArgs.push_back("--debug-info"); + CmdArgs.push_back("--eh-frame"); + CmdArgs.push_back("--quiet"); + + assert(Inputs.size() == 1 && "Unable to handle multiple inputs."); + const InputInfo &Input = Inputs[0]; + assert(Input.isFilename() && "Unexpected verify input"); + + // Grabbing the output of the earlier dsymutil run. + CmdArgs.push_back(Input.getFilename()); + + const char *Exec = + Args.MakeArgString(getToolChain().GetProgramPath("dwarfdump")); + C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); +} + +MachO::MachO(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) + : ToolChain(D, Triple, Args) { + // We expect 'as', 'ld', etc. to be adjacent to our install dir. + getProgramPaths().push_back(getDriver().getInstalledDir()); + if (getDriver().getInstalledDir() != getDriver().Dir) + getProgramPaths().push_back(getDriver().Dir); +} + +/// Darwin - Darwin tool chain for i386 and x86_64. +Darwin::Darwin(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) + : MachO(D, Triple, Args), TargetInitialized(false), + CudaInstallation(D, Triple, Args) {} + +types::ID MachO::LookupTypeForExtension(StringRef Ext) const { + types::ID Ty = types::lookupTypeForExtension(Ext); + + // Darwin always preprocesses assembly files (unless -x is used explicitly). + if (Ty == types::TY_PP_Asm) + return types::TY_Asm; + + return Ty; +} + +bool MachO::HasNativeLLVMSupport() const { return true; } + +ToolChain::CXXStdlibType Darwin::GetDefaultCXXStdlibType() const { + // Default to use libc++ on OS X 10.9+ and iOS 7+. + if ((isTargetMacOS() && !isMacosxVersionLT(10, 9)) || + (isTargetIOSBased() && !isIPhoneOSVersionLT(7, 0)) || + isTargetWatchOSBased()) + return ToolChain::CST_Libcxx; + + return ToolChain::CST_Libstdcxx; +} + +/// Darwin provides an ARC runtime starting in MacOS X 10.7 and iOS 5.0. +ObjCRuntime Darwin::getDefaultObjCRuntime(bool isNonFragile) const { + if (isTargetWatchOSBased()) + return ObjCRuntime(ObjCRuntime::WatchOS, TargetVersion); + if (isTargetIOSBased()) + return ObjCRuntime(ObjCRuntime::iOS, TargetVersion); + if (isNonFragile) + return ObjCRuntime(ObjCRuntime::MacOSX, TargetVersion); + return ObjCRuntime(ObjCRuntime::FragileMacOSX, TargetVersion); +} + +/// Darwin provides a blocks runtime starting in MacOS X 10.6 and iOS 3.2. +bool Darwin::hasBlocksRuntime() const { + if (isTargetWatchOSBased()) + return true; + else if (isTargetIOSBased()) + return !isIPhoneOSVersionLT(3, 2); + else { + assert(isTargetMacOS() && "unexpected darwin target"); + return !isMacosxVersionLT(10, 6); + } +} + +void Darwin::AddCudaIncludeArgs(const ArgList &DriverArgs, + ArgStringList &CC1Args) const { + CudaInstallation.AddCudaIncludeArgs(DriverArgs, CC1Args); +} + +// This is just a MachO name translation routine and there's no +// way to join this into ARMTargetParser without breaking all +// other assumptions. Maybe MachO should consider standardising +// their nomenclature. +static const char *ArmMachOArchName(StringRef Arch) { + return llvm::StringSwitch<const char *>(Arch) + .Case("armv6k", "armv6") + .Case("armv6m", "armv6m") + .Case("armv5tej", "armv5") + .Case("xscale", "xscale") + .Case("armv4t", "armv4t") + .Case("armv7", "armv7") + .Cases("armv7a", "armv7-a", "armv7") + .Cases("armv7r", "armv7-r", "armv7") + .Cases("armv7em", "armv7e-m", "armv7em") + .Cases("armv7k", "armv7-k", "armv7k") + .Cases("armv7m", "armv7-m", "armv7m") + .Cases("armv7s", "armv7-s", "armv7s") + .Default(nullptr); +} + +static const char *ArmMachOArchNameCPU(StringRef CPU) { + unsigned ArchKind = llvm::ARM::parseCPUArch(CPU); + if (ArchKind == llvm::ARM::AK_INVALID) + return nullptr; + StringRef Arch = llvm::ARM::getArchName(ArchKind); + + // FIXME: Make sure this MachO triple mangling is really necessary. + // ARMv5* normalises to ARMv5. + if (Arch.startswith("armv5")) + Arch = Arch.substr(0, 5); + // ARMv6*, except ARMv6M, normalises to ARMv6. + else if (Arch.startswith("armv6") && !Arch.endswith("6m")) + Arch = Arch.substr(0, 5); + // ARMv7A normalises to ARMv7. + else if (Arch.endswith("v7a")) + Arch = Arch.substr(0, 5); + return Arch.data(); +} + +StringRef MachO::getMachOArchName(const ArgList &Args) const { + switch (getTriple().getArch()) { + default: + return getDefaultUniversalArchName(); + + case llvm::Triple::aarch64: + return "arm64"; + + case llvm::Triple::thumb: + case llvm::Triple::arm: + if (const Arg *A = Args.getLastArg(clang::driver::options::OPT_march_EQ)) + if (const char *Arch = ArmMachOArchName(A->getValue())) + return Arch; + + if (const Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) + if (const char *Arch = ArmMachOArchNameCPU(A->getValue())) + return Arch; + + return "arm"; + } +} + +Darwin::~Darwin() {} + +MachO::~MachO() {} + +std::string Darwin::ComputeEffectiveClangTriple(const ArgList &Args, + types::ID InputType) const { + llvm::Triple Triple(ComputeLLVMTriple(Args, InputType)); + + // If the target isn't initialized (e.g., an unknown Darwin platform, return + // the default triple). + if (!isTargetInitialized()) + return Triple.getTriple(); + + SmallString<16> Str; + if (isTargetWatchOSBased()) + Str += "watchos"; + else if (isTargetTvOSBased()) + Str += "tvos"; + else if (isTargetIOSBased()) + Str += "ios"; + else + Str += "macosx"; + Str += getTargetVersion().getAsString(); + Triple.setOSName(Str); + + return Triple.getTriple(); +} + +Tool *MachO::getTool(Action::ActionClass AC) const { + switch (AC) { + case Action::LipoJobClass: + if (!Lipo) + Lipo.reset(new tools::darwin::Lipo(*this)); + return Lipo.get(); + case Action::DsymutilJobClass: + if (!Dsymutil) + Dsymutil.reset(new tools::darwin::Dsymutil(*this)); + return Dsymutil.get(); + case Action::VerifyDebugInfoJobClass: + if (!VerifyDebug) + VerifyDebug.reset(new tools::darwin::VerifyDebug(*this)); + return VerifyDebug.get(); + default: + return ToolChain::getTool(AC); + } +} + +Tool *MachO::buildLinker() const { return new tools::darwin::Linker(*this); } + +Tool *MachO::buildAssembler() const { + return new tools::darwin::Assembler(*this); +} + +DarwinClang::DarwinClang(const Driver &D, const llvm::Triple &Triple, + const ArgList &Args) + : Darwin(D, Triple, Args) {} + +void DarwinClang::addClangWarningOptions(ArgStringList &CC1Args) const { + // For modern targets, promote certain warnings to errors. + if (isTargetWatchOSBased() || getTriple().isArch64Bit()) { + // Always enable -Wdeprecated-objc-isa-usage and promote it + // to an error. + CC1Args.push_back("-Wdeprecated-objc-isa-usage"); + CC1Args.push_back("-Werror=deprecated-objc-isa-usage"); + + // For iOS and watchOS, also error about implicit function declarations, + // as that can impact calling conventions. + if (!isTargetMacOS()) + CC1Args.push_back("-Werror=implicit-function-declaration"); + } +} + +void DarwinClang::AddLinkARCArgs(const ArgList &Args, + ArgStringList &CmdArgs) const { + // Avoid linking compatibility stubs on i386 mac. + if (isTargetMacOS() && getArch() == llvm::Triple::x86) + return; + + ObjCRuntime runtime = getDefaultObjCRuntime(/*nonfragile*/ true); + + if ((runtime.hasNativeARC() || !isObjCAutoRefCount(Args)) && + runtime.hasSubscripting()) + return; + + CmdArgs.push_back("-force_load"); + SmallString<128> P(getDriver().ClangExecutable); + llvm::sys::path::remove_filename(P); // 'clang' + llvm::sys::path::remove_filename(P); // 'bin' + llvm::sys::path::append(P, "lib", "arc", "libarclite_"); + // Mash in the platform. + if (isTargetWatchOSSimulator()) + P += "watchsimulator"; + else if (isTargetWatchOS()) + P += "watchos"; + else if (isTargetTvOSSimulator()) + P += "appletvsimulator"; + else if (isTargetTvOS()) + P += "appletvos"; + else if (isTargetIOSSimulator()) + P += "iphonesimulator"; + else if (isTargetIPhoneOS()) + P += "iphoneos"; + else + P += "macosx"; + P += ".a"; + + CmdArgs.push_back(Args.MakeArgString(P)); +} + +unsigned DarwinClang::GetDefaultDwarfVersion() const { + // Default to use DWARF 2 on OS X 10.10 / iOS 8 and lower. + if ((isTargetMacOS() && isMacosxVersionLT(10, 11)) || + (isTargetIOSBased() && isIPhoneOSVersionLT(9))) + return 2; + return 4; +} + +void MachO::AddLinkRuntimeLib(const ArgList &Args, ArgStringList &CmdArgs, + StringRef DarwinLibName, bool AlwaysLink, + bool IsEmbedded, bool AddRPath) const { + SmallString<128> Dir(getDriver().ResourceDir); + llvm::sys::path::append(Dir, "lib", IsEmbedded ? "macho_embedded" : "darwin"); + + SmallString<128> P(Dir); + llvm::sys::path::append(P, DarwinLibName); + + // 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)); + + // 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) { + assert(DarwinLibName.endswith(".dylib") && "must be a dynamic library"); + + // Add @executable_path to rpath to support having the dylib copied with + // the executable. + CmdArgs.push_back("-rpath"); + CmdArgs.push_back("@executable_path"); + + // Add the path to the resource dir to rpath to support using the dylib + // from the default location without copying. + CmdArgs.push_back("-rpath"); + CmdArgs.push_back(Args.MakeArgString(Dir)); + } +} + +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"); +} + +StringRef Darwin::getSDKName(StringRef isysroot) { + // Assume SDK has path: SOME_PATH/SDKs/PlatformXX.YY.sdk + llvm::sys::path::const_iterator SDKDir; + auto BeginSDK = llvm::sys::path::begin(isysroot); + auto EndSDK = llvm::sys::path::end(isysroot); + for (auto IT = BeginSDK; IT != EndSDK; ++IT) { + StringRef SDK = *IT; + if (SDK.endswith(".sdk")) + return SDK.slice(0, SDK.size() - 4); + } + return ""; +} + +StringRef Darwin::getOSLibraryNameSuffix() const { + switch(TargetPlatform) { + case DarwinPlatformKind::MacOS: + return "osx"; + case DarwinPlatformKind::IPhoneOS: + return "ios"; + case DarwinPlatformKind::IPhoneOSSimulator: + return "iossim"; + case DarwinPlatformKind::TvOS: + return "tvos"; + case DarwinPlatformKind::TvOSSimulator: + return "tvossim"; + case DarwinPlatformKind::WatchOS: + return "watchos"; + case DarwinPlatformKind::WatchOSSimulator: + return "watchossim"; + } + llvm_unreachable("Unsupported platform"); +} + +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); +} + +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); +} + +ToolChain::RuntimeLibType DarwinClang::GetRuntimeLibType( + const ArgList &Args) const { + if (Arg* A = Args.getLastArg(options::OPT_rtlib_EQ)) { + StringRef Value = A->getValue(); + if (Value != "compiler-rt") + getDriver().Diag(clang::diag::err_drv_unsupported_rtlib_for_platform) + << Value << "darwin"; + } + + return ToolChain::RLT_CompilerRT; +} + +void DarwinClang::AddLinkRuntimeLibArgs(const ArgList &Args, + ArgStringList &CmdArgs) const { + // Call once to ensure diagnostic is printed if wrong value was specified + GetRuntimeLibType(Args); + + // Darwin doesn't support real static executables, don't link any runtime + // libraries with -static. + if (Args.hasArg(options::OPT_static) || + Args.hasArg(options::OPT_fapple_kext) || + Args.hasArg(options::OPT_mkernel)) + return; + + // Reject -static-libgcc for now, we can deal with this when and if someone + // cares. This is useful in situations where someone wants to statically link + // something like libstdc++, and needs its runtime support routines. + if (const Arg *A = Args.getLastArg(options::OPT_static_libgcc)) { + getDriver().Diag(diag::err_drv_unsupported_opt) << A->getAsString(Args); + return; + } + + const SanitizerArgs &Sanitize = getSanitizerArgs(); + if (Sanitize.needsAsanRt()) + AddLinkSanitizerLibArgs(Args, CmdArgs, "asan"); + if (Sanitize.needsUbsanRt()) + AddLinkSanitizerLibArgs(Args, CmdArgs, "ubsan"); + if (Sanitize.needsTsanRt()) + AddLinkSanitizerLibArgs(Args, CmdArgs, "tsan"); + if (Sanitize.needsStatsRt()) { + StringRef OS = isTargetMacOS() ? "osx" : "iossim"; + AddLinkRuntimeLib(Args, CmdArgs, + (Twine("libclang_rt.stats_client_") + OS + ".a").str(), + /*AlwaysLink=*/true); + AddLinkSanitizerLibArgs(Args, CmdArgs, "stats"); + } + if (Sanitize.needsEsanRt()) + AddLinkSanitizerLibArgs(Args, CmdArgs, "esan"); + + // Otherwise link libSystem, then the dynamic runtime library, and finally any + // target specific static runtime library. + CmdArgs.push_back("-lSystem"); + + // Select the dynamic runtime library and the target specific static library. + if (isTargetWatchOSBased()) { + // We currently always need a static runtime library for watchOS. + AddLinkRuntimeLib(Args, CmdArgs, "libclang_rt.watchos.a"); + } else if (isTargetTvOSBased()) { + // We currently always need a static runtime library for tvOS. + AddLinkRuntimeLib(Args, CmdArgs, "libclang_rt.tvos.a"); + } else if (isTargetIOSBased()) { + // If we are compiling as iOS / simulator, don't attempt to link libgcc_s.1, + // it never went into the SDK. + // Linking against libgcc_s.1 isn't needed for iOS 5.0+ + if (isIPhoneOSVersionLT(5, 0) && !isTargetIOSSimulator() && + getTriple().getArch() != llvm::Triple::aarch64) + CmdArgs.push_back("-lgcc_s.1"); + + // We currently always need a static runtime library for iOS. + AddLinkRuntimeLib(Args, CmdArgs, "libclang_rt.ios.a"); + } else { + assert(isTargetMacOS() && "unexpected non MacOS platform"); + // The dynamic runtime library was merged with libSystem for 10.6 and + // beyond; only 10.4 and 10.5 need an additional runtime library. + if (isMacosxVersionLT(10, 5)) + CmdArgs.push_back("-lgcc_s.10.4"); + else if (isMacosxVersionLT(10, 6)) + CmdArgs.push_back("-lgcc_s.10.5"); + + // Originally for OS X, we thought we would only need a static runtime + // library when targeting 10.4, to provide versions of the static functions + // which were omitted from 10.4.dylib. This led to the creation of the 10.4 + // builtins library. + // + // Unfortunately, that turned out to not be true, because Darwin system + // headers can still use eprintf on i386, and it is not exported from + // libSystem. Therefore, we still must provide a runtime library just for + // the tiny tiny handful of projects that *might* use that symbol. + // + // Then over time, we figured out it was useful to add more things to the + // runtime so we created libclang_rt.osx.a to provide new functions when + // deploying to old OS builds, and for a long time we had both eprintf and + // osx builtin libraries. Which just seems excessive. So with PR 28855, we + // are removing the eprintf library and expecting eprintf to be provided by + // the OS X builtins library. + if (isMacosxVersionLT(10, 5)) + AddLinkRuntimeLib(Args, CmdArgs, "libclang_rt.10.4.a"); + else + AddLinkRuntimeLib(Args, CmdArgs, "libclang_rt.osx.a"); + } +} + +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)); + } + } + } + + Arg *OSXVersion = Args.getLastArg(options::OPT_mmacosx_version_min_EQ); + Arg *iOSVersion = Args.getLastArg(options::OPT_miphoneos_version_min_EQ); + Arg *TvOSVersion = Args.getLastArg(options::OPT_mtvos_version_min_EQ); + Arg *WatchOSVersion = Args.getLastArg(options::OPT_mwatchos_version_min_EQ); + + 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 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 = Version; + else if (SDK.startswith("WatchOS") || + SDK.startswith("WatchSimulator")) + WatchOSTarget = Version; + else if (SDK.startswith("AppleTVOS") || + SDK.startswith("AppleTVSimulator")) + TvOSTarget = Version; + } + } + } + } + + // If no OSX or iOS target has been specified, try to guess platform + // from arch name and compute the version from the triple. + if (OSXTarget.empty() && iOSTarget.empty() && TvOSTarget.empty() && + WatchOSTarget.empty()) { + StringRef MachOArchName = getMachOArchName(Args); + unsigned Major, Minor, Micro; + if (MachOArchName == "armv7" || MachOArchName == "armv7s" || + MachOArchName == "arm64") { + getTriple().getiOSVersion(Major, Minor, Micro); + llvm::raw_string_ostream(iOSTarget) << Major << '.' << Minor << '.' + << Micro; + } else if (MachOArchName == "armv7k") { + getTriple().getWatchOSVersion(Major, Minor, Micro); + llvm::raw_string_ostream(WatchOSTarget) << Major << '.' << Minor << '.' + << Micro; + } else if (MachOArchName != "armv6m" && MachOArchName != "armv7m" && + MachOArchName != "armv7em") { + if (!getTriple().getMacOSXVersion(Major, Minor, Micro)) { + getDriver().Diag(diag::err_drv_invalid_darwin_version) + << getTriple().getOSName(); + } + llvm::raw_string_ostream(OSXTarget) << Major << '.' << Minor << '.' + << Micro; + } + } + + // 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"); + } + + // 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"; + } + + // 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 = ""; + } + + 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); + } + } + + 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"); + + // Set the tool chain target information. + unsigned Major, Minor, Micro; + bool HadExtra; + if (Platform == MacOS) { + assert((!iOSVersion && !TvOSVersion && !WatchOSVersion) && + "Unknown target platform!"); + if (!Driver::GetReleaseVersion(OSXVersion->getValue(), Major, Minor, Micro, + HadExtra) || + HadExtra || Major != 10 || Minor >= 100 || Micro >= 100) + getDriver().Diag(diag::err_drv_invalid_version_number) + << OSXVersion->getAsString(Args); + } else if (Platform == IPhoneOS) { + assert(iOSVersion && "Unknown target platform!"); + if (!Driver::GetReleaseVersion(iOSVersion->getValue(), Major, Minor, Micro, + HadExtra) || + HadExtra || Major >= 100 || Minor >= 100 || Micro >= 100) + getDriver().Diag(diag::err_drv_invalid_version_number) + << iOSVersion->getAsString(Args); + } else if (Platform == TvOS) { + if (!Driver::GetReleaseVersion(TvOSVersion->getValue(), Major, Minor, + Micro, HadExtra) || HadExtra || + Major >= 100 || Minor >= 100 || Micro >= 100) + getDriver().Diag(diag::err_drv_invalid_version_number) + << TvOSVersion->getAsString(Args); + } else if (Platform == WatchOS) { + if (!Driver::GetReleaseVersion(WatchOSVersion->getValue(), Major, Minor, + Micro, HadExtra) || HadExtra || + Major >= 10 || Minor >= 100 || Micro >= 100) + getDriver().Diag(diag::err_drv_invalid_version_number) + << WatchOSVersion->getAsString(Args); + } else + llvm_unreachable("unknown kind of Darwin platform"); + + // 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 (const Arg *A = Args.getLastArg(options::OPT_isysroot)) { + StringRef SDK = getSDKName(A->getValue()); + if (SDK.size() > 0) { + size_t StartVer = SDK.find_first_of("0123456789"); + StringRef SDKName = SDK.slice(0, StartVer); + if (!SDKName.startswith(getPlatformFamily())) + getDriver().Diag(diag::warn_incompatible_sysroot) + << SDKName << getPlatformFamily(); + } + } +} + +void DarwinClang::AddCXXStdlibLibArgs(const ArgList &Args, + ArgStringList &CmdArgs) const { + CXXStdlibType Type = GetCXXStdlibType(Args); + + switch (Type) { + case ToolChain::CST_Libcxx: + CmdArgs.push_back("-lc++"); + break; + + case ToolChain::CST_Libstdcxx: + // Unfortunately, -lstdc++ doesn't always exist in the standard search path; + // it was previously found in the gcc lib dir. However, for all the Darwin + // platforms we care about it was -lstdc++.6, so we search for that + // explicitly if we can't see an obvious -lstdc++ candidate. + + // Check in the sysroot first. + if (const Arg *A = Args.getLastArg(options::OPT_isysroot)) { + SmallString<128> P(A->getValue()); + llvm::sys::path::append(P, "usr", "lib", "libstdc++.dylib"); + + if (!getVFS().exists(P)) { + llvm::sys::path::remove_filename(P); + llvm::sys::path::append(P, "libstdc++.6.dylib"); + if (getVFS().exists(P)) { + CmdArgs.push_back(Args.MakeArgString(P)); + return; + } + } + } + + // Otherwise, look in the root. + // FIXME: This should be removed someday when we don't have to care about + // 10.6 and earlier, where /usr/lib/libstdc++.dylib does not exist. + if (!getVFS().exists("/usr/lib/libstdc++.dylib") && + getVFS().exists("/usr/lib/libstdc++.6.dylib")) { + CmdArgs.push_back("/usr/lib/libstdc++.6.dylib"); + return; + } + + // Otherwise, let the linker search. + CmdArgs.push_back("-lstdc++"); + break; + } +} + +void DarwinClang::AddCCKextLibArgs(const ArgList &Args, + ArgStringList &CmdArgs) const { + // For Darwin platforms, use the compiler-rt-based support library + // instead of the gcc-provided one (which is also incidentally + // only present in the gcc lib dir, which makes it hard to find). + + SmallString<128> P(getDriver().ResourceDir); + llvm::sys::path::append(P, "lib", "darwin"); + + // Use the newer cc_kext for iOS ARM after 6.0. + if (isTargetWatchOS()) { + llvm::sys::path::append(P, "libclang_rt.cc_kext_watchos.a"); + } else if (isTargetTvOS()) { + llvm::sys::path::append(P, "libclang_rt.cc_kext_tvos.a"); + } else if (isTargetIPhoneOS()) { + llvm::sys::path::append(P, "libclang_rt.cc_kext_ios.a"); + } else { + llvm::sys::path::append(P, "libclang_rt.cc_kext.a"); + } + + // For now, allow missing resource libraries to support developers who may + // not have compiler-rt checked out or integrated into their build. + if (getVFS().exists(P)) + CmdArgs.push_back(Args.MakeArgString(P)); +} + +DerivedArgList *MachO::TranslateArgs(const DerivedArgList &Args, + StringRef BoundArch, + Action::OffloadKind) const { + DerivedArgList *DAL = new DerivedArgList(Args.getBaseArgs()); + const OptTable &Opts = getDriver().getOpts(); + + // FIXME: We really want to get out of the tool chain level argument + // translation business, as it makes the driver functionality much + // more opaque. For now, we follow gcc closely solely for the + // purpose of easily achieving feature parity & testability. Once we + // have something that works, we should reevaluate each translation + // and try to push it down into tool specific logic. + + for (Arg *A : Args) { + if (A->getOption().matches(options::OPT_Xarch__)) { + // Skip this argument unless the architecture matches either the toolchain + // triple arch, or the arch being bound. + llvm::Triple::ArchType XarchArch = + tools::darwin::getArchTypeForMachOArchName(A->getValue(0)); + if (!(XarchArch == getArch() || + (!BoundArch.empty() && + XarchArch == + tools::darwin::getArchTypeForMachOArchName(BoundArch)))) + continue; + + Arg *OriginalArg = A; + unsigned Index = Args.getBaseArgs().MakeIndex(A->getValue(1)); + unsigned Prev = Index; + std::unique_ptr<Arg> XarchArg(Opts.ParseOneArg(Args, Index)); + + // If the argument parsing failed or more than one argument was + // consumed, the -Xarch_ argument's parameter tried to consume + // extra arguments. Emit an error and ignore. + // + // We also want to disallow any options which would alter the + // driver behavior; that isn't going to work in our model. We + // use isDriverOption() as an approximation, although things + // like -O4 are going to slip through. + if (!XarchArg || Index > Prev + 1) { + getDriver().Diag(diag::err_drv_invalid_Xarch_argument_with_args) + << A->getAsString(Args); + continue; + } else if (XarchArg->getOption().hasFlag(options::DriverOption)) { + getDriver().Diag(diag::err_drv_invalid_Xarch_argument_isdriver) + << A->getAsString(Args); + continue; + } + + XarchArg->setBaseArg(A); + + A = XarchArg.release(); + DAL->AddSynthesizedArg(A); + + // Linker input arguments require custom handling. The problem is that we + // have already constructed the phase actions, so we can not treat them as + // "input arguments". + if (A->getOption().hasFlag(options::LinkerInput)) { + // Convert the argument into individual Zlinker_input_args. + for (const char *Value : A->getValues()) { + DAL->AddSeparateArg( + OriginalArg, Opts.getOption(options::OPT_Zlinker_input), Value); + } + continue; + } + } + + // Sob. These is strictly gcc compatible for the time being. Apple + // gcc translates options twice, which means that self-expanding + // options add duplicates. + switch ((options::ID)A->getOption().getID()) { + default: + DAL->append(A); + break; + + case options::OPT_mkernel: + case options::OPT_fapple_kext: + DAL->append(A); + DAL->AddFlagArg(A, Opts.getOption(options::OPT_static)); + break; + + case options::OPT_dependency_file: + DAL->AddSeparateArg(A, Opts.getOption(options::OPT_MF), A->getValue()); + break; + + case options::OPT_gfull: + DAL->AddFlagArg(A, Opts.getOption(options::OPT_g_Flag)); + DAL->AddFlagArg( + A, Opts.getOption(options::OPT_fno_eliminate_unused_debug_symbols)); + break; + + case options::OPT_gused: + DAL->AddFlagArg(A, Opts.getOption(options::OPT_g_Flag)); + DAL->AddFlagArg( + A, Opts.getOption(options::OPT_feliminate_unused_debug_symbols)); + break; + + case options::OPT_shared: + DAL->AddFlagArg(A, Opts.getOption(options::OPT_dynamiclib)); + break; + + case options::OPT_fconstant_cfstrings: + DAL->AddFlagArg(A, Opts.getOption(options::OPT_mconstant_cfstrings)); + break; + + case options::OPT_fno_constant_cfstrings: + DAL->AddFlagArg(A, Opts.getOption(options::OPT_mno_constant_cfstrings)); + break; + + case options::OPT_Wnonportable_cfstrings: + DAL->AddFlagArg(A, + Opts.getOption(options::OPT_mwarn_nonportable_cfstrings)); + break; + + case options::OPT_Wno_nonportable_cfstrings: + DAL->AddFlagArg( + A, Opts.getOption(options::OPT_mno_warn_nonportable_cfstrings)); + break; + + case options::OPT_fpascal_strings: + DAL->AddFlagArg(A, Opts.getOption(options::OPT_mpascal_strings)); + break; + + case options::OPT_fno_pascal_strings: + DAL->AddFlagArg(A, Opts.getOption(options::OPT_mno_pascal_strings)); + break; + } + } + + if (getTriple().getArch() == llvm::Triple::x86 || + getTriple().getArch() == llvm::Triple::x86_64) + if (!Args.hasArgNoClaim(options::OPT_mtune_EQ)) + DAL->AddJoinedArg(nullptr, Opts.getOption(options::OPT_mtune_EQ), + "core2"); + + // Add the arch options based on the particular spelling of -arch, to match + // how the driver driver works. + if (!BoundArch.empty()) { + StringRef Name = BoundArch; + const Option MCpu = Opts.getOption(options::OPT_mcpu_EQ); + const Option MArch = Opts.getOption(clang::driver::options::OPT_march_EQ); + + // This code must be kept in sync with LLVM's getArchTypeForDarwinArch, + // which defines the list of which architectures we accept. + if (Name == "ppc") + ; + else if (Name == "ppc601") + DAL->AddJoinedArg(nullptr, MCpu, "601"); + else if (Name == "ppc603") + DAL->AddJoinedArg(nullptr, MCpu, "603"); + else if (Name == "ppc604") + DAL->AddJoinedArg(nullptr, MCpu, "604"); + else if (Name == "ppc604e") + DAL->AddJoinedArg(nullptr, MCpu, "604e"); + else if (Name == "ppc750") + DAL->AddJoinedArg(nullptr, MCpu, "750"); + else if (Name == "ppc7400") + DAL->AddJoinedArg(nullptr, MCpu, "7400"); + else if (Name == "ppc7450") + DAL->AddJoinedArg(nullptr, MCpu, "7450"); + else if (Name == "ppc970") + DAL->AddJoinedArg(nullptr, MCpu, "970"); + + else if (Name == "ppc64" || Name == "ppc64le") + DAL->AddFlagArg(nullptr, Opts.getOption(options::OPT_m64)); + + else if (Name == "i386") + ; + else if (Name == "i486") + DAL->AddJoinedArg(nullptr, MArch, "i486"); + else if (Name == "i586") + DAL->AddJoinedArg(nullptr, MArch, "i586"); + else if (Name == "i686") + DAL->AddJoinedArg(nullptr, MArch, "i686"); + else if (Name == "pentium") + DAL->AddJoinedArg(nullptr, MArch, "pentium"); + else if (Name == "pentium2") + DAL->AddJoinedArg(nullptr, MArch, "pentium2"); + else if (Name == "pentpro") + DAL->AddJoinedArg(nullptr, MArch, "pentiumpro"); + else if (Name == "pentIIm3") + DAL->AddJoinedArg(nullptr, MArch, "pentium2"); + + else if (Name == "x86_64") + DAL->AddFlagArg(nullptr, Opts.getOption(options::OPT_m64)); + else if (Name == "x86_64h") { + DAL->AddFlagArg(nullptr, Opts.getOption(options::OPT_m64)); + DAL->AddJoinedArg(nullptr, MArch, "x86_64h"); + } + + else if (Name == "arm") + DAL->AddJoinedArg(nullptr, MArch, "armv4t"); + else if (Name == "armv4t") + DAL->AddJoinedArg(nullptr, MArch, "armv4t"); + else if (Name == "armv5") + DAL->AddJoinedArg(nullptr, MArch, "armv5tej"); + else if (Name == "xscale") + DAL->AddJoinedArg(nullptr, MArch, "xscale"); + else if (Name == "armv6") + DAL->AddJoinedArg(nullptr, MArch, "armv6k"); + else if (Name == "armv6m") + DAL->AddJoinedArg(nullptr, MArch, "armv6m"); + else if (Name == "armv7") + DAL->AddJoinedArg(nullptr, MArch, "armv7a"); + else if (Name == "armv7em") + DAL->AddJoinedArg(nullptr, MArch, "armv7em"); + else if (Name == "armv7k") + DAL->AddJoinedArg(nullptr, MArch, "armv7k"); + else if (Name == "armv7m") + DAL->AddJoinedArg(nullptr, MArch, "armv7m"); + else if (Name == "armv7s") + DAL->AddJoinedArg(nullptr, MArch, "armv7s"); + } + + return DAL; +} + +void MachO::AddLinkRuntimeLibArgs(const ArgList &Args, + ArgStringList &CmdArgs) const { + // Embedded targets are simple at the moment, not supporting sanitizers and + // with different libraries for each member of the product { static, PIC } x + // { hard-float, soft-float } + llvm::SmallString<32> CompilerRT = StringRef("libclang_rt."); + CompilerRT += + (tools::arm::getARMFloatABI(*this, Args) == tools::arm::FloatABI::Hard) + ? "hard" + : "soft"; + CompilerRT += Args.hasArg(options::OPT_fPIC) ? "_pic.a" : "_static.a"; + + AddLinkRuntimeLib(Args, CmdArgs, CompilerRT, false, true); +} + +DerivedArgList * +Darwin::TranslateArgs(const DerivedArgList &Args, StringRef BoundArch, + Action::OffloadKind DeviceOffloadKind) const { + // First get the generic Apple args, before moving onto Darwin-specific ones. + DerivedArgList *DAL = + MachO::TranslateArgs(Args, BoundArch, DeviceOffloadKind); + const OptTable &Opts = getDriver().getOpts(); + + // If no architecture is bound, none of the translations here are relevant. + if (BoundArch.empty()) + return DAL; + + // Add an explicit version min argument for the deployment target. We do this + // after argument translation because -Xarch_ arguments may add a version min + // argument. + AddDeploymentTarget(*DAL); + + // For iOS 6, undo the translation to add -static for -mkernel/-fapple-kext. + // FIXME: It would be far better to avoid inserting those -static arguments, + // but we can't check the deployment target in the translation code until + // it is set here. + if (isTargetWatchOSBased() || + (isTargetIOSBased() && !isIPhoneOSVersionLT(6, 0))) { + for (ArgList::iterator it = DAL->begin(), ie = DAL->end(); it != ie; ) { + Arg *A = *it; + ++it; + if (A->getOption().getID() != options::OPT_mkernel && + A->getOption().getID() != options::OPT_fapple_kext) + continue; + assert(it != ie && "unexpected argument translation"); + A = *it; + assert(A->getOption().getID() == options::OPT_static && + "missing expected -static argument"); + it = DAL->getArgs().erase(it); + } + } + + if (!Args.getLastArg(options::OPT_stdlib_EQ) && + GetCXXStdlibType(Args) == ToolChain::CST_Libcxx) + DAL->AddJoinedArg(nullptr, Opts.getOption(options::OPT_stdlib_EQ), + "libc++"); + + // Validate the C++ standard library choice. + CXXStdlibType Type = GetCXXStdlibType(*DAL); + if (Type == ToolChain::CST_Libcxx) { + // Check whether the target provides libc++. + StringRef where; + + // Complain about targeting iOS < 5.0 in any way. + if (isTargetIOSBased() && isIPhoneOSVersionLT(5, 0)) + where = "iOS 5.0"; + + if (where != StringRef()) { + getDriver().Diag(clang::diag::err_drv_invalid_libcxx_deployment) << where; + } + } + + auto Arch = tools::darwin::getArchTypeForMachOArchName(BoundArch); + if ((Arch == llvm::Triple::arm || Arch == llvm::Triple::thumb)) { + if (Args.hasFlag(options::OPT_fomit_frame_pointer, + options::OPT_fno_omit_frame_pointer, false)) + getDriver().Diag(clang::diag::warn_drv_unsupported_opt_for_target) + << "-fomit-frame-pointer" << BoundArch; + } + + return DAL; +} + +bool MachO::IsUnwindTablesDefault() const { + return getArch() == llvm::Triple::x86_64; +} + +bool MachO::UseDwarfDebugFlags() const { + if (const char *S = ::getenv("RC_DEBUG_OPTIONS")) + return S[0] != '\0'; + return false; +} + +bool Darwin::UseSjLjExceptions(const ArgList &Args) const { + // Darwin uses SjLj exceptions on ARM. + if (getTriple().getArch() != llvm::Triple::arm && + getTriple().getArch() != llvm::Triple::thumb) + return false; + + // Only watchOS uses the new DWARF/Compact unwinding method. + llvm::Triple Triple(ComputeLLVMTriple(Args)); + return !Triple.isWatchABI(); +} + +bool Darwin::SupportsEmbeddedBitcode() const { + assert(TargetInitialized && "Target not initialized!"); + if (isTargetIPhoneOS() && isIPhoneOSVersionLT(6, 0)) + return false; + return true; +} + +bool MachO::isPICDefault() const { return true; } + +bool MachO::isPIEDefault() const { return false; } + +bool MachO::isPICDefaultForced() const { + return (getArch() == llvm::Triple::x86_64 || + getArch() == llvm::Triple::aarch64); +} + +bool MachO::SupportsProfiling() const { + // Profiling instrumentation is only supported on x86. + return getArch() == llvm::Triple::x86 || getArch() == llvm::Triple::x86_64; +} + +void Darwin::addMinVersionArgs(const ArgList &Args, + ArgStringList &CmdArgs) const { + VersionTuple TargetVersion = getTargetVersion(); + + if (isTargetWatchOS()) + CmdArgs.push_back("-watchos_version_min"); + else if (isTargetWatchOSSimulator()) + CmdArgs.push_back("-watchos_simulator_version_min"); + else if (isTargetTvOS()) + CmdArgs.push_back("-tvos_version_min"); + else if (isTargetTvOSSimulator()) + CmdArgs.push_back("-tvos_simulator_version_min"); + else if (isTargetIOSSimulator()) + CmdArgs.push_back("-ios_simulator_version_min"); + else if (isTargetIOSBased()) + CmdArgs.push_back("-iphoneos_version_min"); + else { + assert(isTargetMacOS() && "unexpected target"); + CmdArgs.push_back("-macosx_version_min"); + } + + CmdArgs.push_back(Args.MakeArgString(TargetVersion.getAsString())); +} + +void Darwin::addStartObjectFileArgs(const ArgList &Args, + ArgStringList &CmdArgs) const { + // Derived from startfile spec. + if (Args.hasArg(options::OPT_dynamiclib)) { + // Derived from darwin_dylib1 spec. + if (isTargetWatchOSBased()) { + ; // watchOS does not need dylib1.o. + } else if (isTargetIOSSimulator()) { + ; // iOS simulator does not need dylib1.o. + } else if (isTargetIPhoneOS()) { + if (isIPhoneOSVersionLT(3, 1)) + CmdArgs.push_back("-ldylib1.o"); + } else { + if (isMacosxVersionLT(10, 5)) + CmdArgs.push_back("-ldylib1.o"); + else if (isMacosxVersionLT(10, 6)) + CmdArgs.push_back("-ldylib1.10.5.o"); + } + } else { + if (Args.hasArg(options::OPT_bundle)) { + if (!Args.hasArg(options::OPT_static)) { + // Derived from darwin_bundle1 spec. + if (isTargetWatchOSBased()) { + ; // watchOS does not need bundle1.o. + } else if (isTargetIOSSimulator()) { + ; // iOS simulator does not need bundle1.o. + } else if (isTargetIPhoneOS()) { + if (isIPhoneOSVersionLT(3, 1)) + CmdArgs.push_back("-lbundle1.o"); + } else { + if (isMacosxVersionLT(10, 6)) + CmdArgs.push_back("-lbundle1.o"); + } + } + } else { + if (Args.hasArg(options::OPT_pg) && SupportsProfiling()) { + if (Args.hasArg(options::OPT_static) || + Args.hasArg(options::OPT_object) || + Args.hasArg(options::OPT_preload)) { + CmdArgs.push_back("-lgcrt0.o"); + } else { + CmdArgs.push_back("-lgcrt1.o"); + + // darwin_crt2 spec is empty. + } + // By default on OS X 10.8 and later, we don't link with a crt1.o + // file and the linker knows to use _main as the entry point. But, + // when compiling with -pg, we need to link with the gcrt1.o file, + // so pass the -no_new_main option to tell the linker to use the + // "start" symbol as the entry point. + if (isTargetMacOS() && !isMacosxVersionLT(10, 8)) + CmdArgs.push_back("-no_new_main"); + } else { + if (Args.hasArg(options::OPT_static) || + Args.hasArg(options::OPT_object) || + Args.hasArg(options::OPT_preload)) { + CmdArgs.push_back("-lcrt0.o"); + } else { + // Derived from darwin_crt1 spec. + if (isTargetWatchOSBased()) { + ; // watchOS does not need crt1.o. + } else if (isTargetIOSSimulator()) { + ; // iOS simulator does not need crt1.o. + } else if (isTargetIPhoneOS()) { + if (getArch() == llvm::Triple::aarch64) + ; // iOS does not need any crt1 files for arm64 + else if (isIPhoneOSVersionLT(3, 1)) + CmdArgs.push_back("-lcrt1.o"); + else if (isIPhoneOSVersionLT(6, 0)) + CmdArgs.push_back("-lcrt1.3.1.o"); + } else { + if (isMacosxVersionLT(10, 5)) + CmdArgs.push_back("-lcrt1.o"); + else if (isMacosxVersionLT(10, 6)) + CmdArgs.push_back("-lcrt1.10.5.o"); + else if (isMacosxVersionLT(10, 8)) + CmdArgs.push_back("-lcrt1.10.6.o"); + + // darwin_crt2 spec is empty. + } + } + } + } + } + + if (!isTargetIPhoneOS() && Args.hasArg(options::OPT_shared_libgcc) && + !isTargetWatchOS() && + isMacosxVersionLT(10, 5)) { + const char *Str = Args.MakeArgString(GetFilePath("crt3.o")); + CmdArgs.push_back(Str); + } +} + +bool Darwin::SupportsObjCGC() const { return isTargetMacOS(); } + +void Darwin::CheckObjCARC() const { + if (isTargetIOSBased() || isTargetWatchOSBased() || + (isTargetMacOS() && !isMacosxVersionLT(10, 6))) + return; + getDriver().Diag(diag::err_arc_unsupported_on_toolchain); +} + +SanitizerMask Darwin::getSupportedSanitizers() const { + const bool IsX86_64 = getTriple().getArch() == llvm::Triple::x86_64; + SanitizerMask Res = ToolChain::getSupportedSanitizers(); + Res |= SanitizerKind::Address; + if (isTargetMacOS()) { + if (!isMacosxVersionLT(10, 9)) + Res |= SanitizerKind::Vptr; + Res |= SanitizerKind::SafeStack; + if (IsX86_64) + Res |= SanitizerKind::Thread; + } else if (isTargetIOSSimulator() || isTargetTvOSSimulator()) { + if (IsX86_64) + Res |= SanitizerKind::Thread; + } + return Res; +} + +void Darwin::printVerboseInfo(raw_ostream &OS) const { + CudaInstallation.print(OS); +} diff --git a/lib/Driver/ToolChains/Darwin.h b/lib/Driver/ToolChains/Darwin.h new file mode 100644 index 0000000000..984f8ef0c4 --- /dev/null +++ b/lib/Driver/ToolChains/Darwin.h @@ -0,0 +1,488 @@ +//===--- Darwin.h - Darwin 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_DARWIN_H +#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_DARWIN_H + +#include "Cuda.h" +#include "clang/Driver/Tool.h" +#include "clang/Driver/ToolChain.h" + +namespace clang { +namespace driver { + +namespace toolchains { +class MachO; +} // end namespace toolchains + +namespace tools { + +namespace darwin { +llvm::Triple::ArchType getArchTypeForMachOArchName(StringRef Str); +void setTripleTypeForMachOArchName(llvm::Triple &T, StringRef Str); + +class LLVM_LIBRARY_VISIBILITY MachOTool : public Tool { + virtual void anchor(); + +protected: + void AddMachOArch(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) const; + + const toolchains::MachO &getMachOToolChain() const { + return reinterpret_cast<const toolchains::MachO &>(getToolChain()); + } + +public: + MachOTool( + const char *Name, const char *ShortName, const ToolChain &TC, + ResponseFileSupport ResponseSupport = RF_None, + llvm::sys::WindowsEncodingMethod ResponseEncoding = llvm::sys::WEM_UTF8, + const char *ResponseFlag = "@") + : Tool(Name, ShortName, TC, ResponseSupport, ResponseEncoding, + ResponseFlag) {} +}; + +class LLVM_LIBRARY_VISIBILITY Assembler : public MachOTool { +public: + Assembler(const ToolChain &TC) + : MachOTool("darwin::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 MachOTool { + bool NeedsTempPath(const InputInfoList &Inputs) const; + void AddLinkArgs(Compilation &C, const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs, + const InputInfoList &Inputs) const; + +public: + Linker(const ToolChain &TC) + : MachOTool("darwin::Linker", "linker", TC, RF_FileList, + llvm::sys::WEM_UTF8, "-filelist") {} + + 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; +}; + +class LLVM_LIBRARY_VISIBILITY Lipo : public MachOTool { +public: + Lipo(const ToolChain &TC) : MachOTool("darwin::Lipo", "lipo", 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 Dsymutil : public MachOTool { +public: + Dsymutil(const ToolChain &TC) + : MachOTool("darwin::Dsymutil", "dsymutil", TC) {} + + bool hasIntegratedCPP() const override { return false; } + bool isDsymutilJob() 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; +}; + +class LLVM_LIBRARY_VISIBILITY VerifyDebug : public MachOTool { +public: + VerifyDebug(const ToolChain &TC) + : MachOTool("darwin::VerifyDebug", "dwarfdump", 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; +}; +} // end namespace darwin +} // end namespace tools + +namespace toolchains { + +class LLVM_LIBRARY_VISIBILITY MachO : public ToolChain { +protected: + Tool *buildAssembler() const override; + Tool *buildLinker() const override; + Tool *getTool(Action::ActionClass AC) const override; + +private: + mutable std::unique_ptr<tools::darwin::Lipo> Lipo; + mutable std::unique_ptr<tools::darwin::Dsymutil> Dsymutil; + mutable std::unique_ptr<tools::darwin::VerifyDebug> VerifyDebug; + +public: + MachO(const Driver &D, const llvm::Triple &Triple, + const llvm::opt::ArgList &Args); + ~MachO() override; + + /// @name MachO specific toolchain API + /// { + + /// Get the "MachO" arch name for a particular compiler invocation. For + /// example, Apple treats different ARM variations as distinct architectures. + StringRef getMachOArchName(const llvm::opt::ArgList &Args) const; + + /// Add the linker arguments to link the ARC runtime library. + virtual void AddLinkARCArgs(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) const {} + + /// Add the linker arguments to link the compiler runtime library. + virtual void AddLinkRuntimeLibArgs(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) const; + + virtual void addStartObjectFileArgs(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) const { + } + + virtual void addMinVersionArgs(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) const {} + + /// On some iOS platforms, kernel and kernel modules were built statically. Is + /// this such a target? + virtual bool isKernelStatic() const { return false; } + + /// Is the target either iOS or an iOS simulator? + bool isTargetIOSBased() const { return false; } + + void AddLinkRuntimeLib(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs, + StringRef DarwinLibName, bool AlwaysLink = false, + bool IsEmbedded = false, bool AddRPath = false) const; + + /// Add any profiling runtime libraries that are needed. This is essentially a + /// MachO specific version of addProfileRT in Tools.cpp. + void addProfileRTLibs(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) const override { + // There aren't any profiling libs for embedded targets currently. + } + + /// } + /// @name ToolChain Implementation + /// { + + types::ID LookupTypeForExtension(StringRef Ext) const override; + + bool HasNativeLLVMSupport() const override; + + llvm::opt::DerivedArgList * + TranslateArgs(const llvm::opt::DerivedArgList &Args, StringRef BoundArch, + Action::OffloadKind DeviceOffloadKind) const override; + + bool IsBlocksDefault() const override { + // Always allow blocks on Apple; users interested in versioning are + // expected to use /usr/include/Block.h. + return true; + } + bool IsIntegratedAssemblerDefault() const override { + // Default integrated assembler to on for Apple's MachO targets. + return true; + } + + bool IsMathErrnoDefault() const override { return false; } + + bool IsEncodeExtendedBlockSignatureDefault() const override { return true; } + + bool IsObjCNonFragileABIDefault() const override { + // Non-fragile ABI is default for everything but i386. + return getTriple().getArch() != llvm::Triple::x86; + } + + bool UseObjCMixedDispatch() const override { return true; } + + bool IsUnwindTablesDefault() const override; + + RuntimeLibType GetDefaultRuntimeLibType() const override { + return ToolChain::RLT_CompilerRT; + } + + bool isPICDefault() const override; + bool isPIEDefault() const override; + bool isPICDefaultForced() const override; + + 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; + } + + /// } +}; + +/// Darwin - The base Darwin tool chain. +class LLVM_LIBRARY_VISIBILITY Darwin : public MachO { +public: + /// Whether the information on the target has been initialized. + // + // FIXME: This should be eliminated. What we want to do is make this part of + // the "default target for arguments" selection process, once we get out of + // the argument translation business. + mutable bool TargetInitialized; + + enum DarwinPlatformKind { + MacOS, + IPhoneOS, + IPhoneOSSimulator, + TvOS, + TvOSSimulator, + WatchOS, + WatchOSSimulator + }; + + mutable DarwinPlatformKind TargetPlatform; + + /// The OS version we are targeting. + mutable VersionTuple TargetVersion; + + CudaInstallationDetector CudaInstallation; + +private: + void AddDeploymentTarget(llvm::opt::DerivedArgList &Args) const; + +public: + Darwin(const Driver &D, const llvm::Triple &Triple, + const llvm::opt::ArgList &Args); + ~Darwin() override; + + std::string ComputeEffectiveClangTriple(const llvm::opt::ArgList &Args, + types::ID InputType) const override; + + /// @name Apple Specific Toolchain Implementation + /// { + + void addMinVersionArgs(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) const override; + + void addStartObjectFileArgs(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) const override; + + bool isKernelStatic() const override { + return (!(isTargetIPhoneOS() && !isIPhoneOSVersionLT(6, 0)) && + !isTargetWatchOS()); + } + + void addProfileRTLibs(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) const override; + +protected: + /// } + /// @name Darwin specific Toolchain functions + /// { + + // 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 { + // 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 && + TargetVersion == VersionTuple(Major, Minor, Micro)) + return; + + assert(!TargetInitialized && "Target already initialized!"); + TargetInitialized = true; + TargetPlatform = Platform; + TargetVersion = VersionTuple(Major, Minor, Micro); + } + + bool isTargetIPhoneOS() const { + assert(TargetInitialized && "Target not initialized!"); + return TargetPlatform == IPhoneOS || TargetPlatform == TvOS; + } + + bool isTargetIOSSimulator() const { + assert(TargetInitialized && "Target not initialized!"); + return TargetPlatform == IPhoneOSSimulator || + TargetPlatform == TvOSSimulator; + } + + bool isTargetIOSBased() const { + assert(TargetInitialized && "Target not initialized!"); + return isTargetIPhoneOS() || isTargetIOSSimulator(); + } + + bool isTargetTvOS() const { + assert(TargetInitialized && "Target not initialized!"); + return TargetPlatform == TvOS; + } + + bool isTargetTvOSSimulator() const { + assert(TargetInitialized && "Target not initialized!"); + return TargetPlatform == TvOSSimulator; + } + + bool isTargetTvOSBased() const { + assert(TargetInitialized && "Target not initialized!"); + return TargetPlatform == TvOS || TargetPlatform == TvOSSimulator; + } + + bool isTargetWatchOS() const { + assert(TargetInitialized && "Target not initialized!"); + return TargetPlatform == WatchOS; + } + + bool isTargetWatchOSSimulator() const { + assert(TargetInitialized && "Target not initialized!"); + return TargetPlatform == WatchOSSimulator; + } + + bool isTargetWatchOSBased() const { + assert(TargetInitialized && "Target not initialized!"); + return TargetPlatform == WatchOS || TargetPlatform == WatchOSSimulator; + } + + bool isTargetMacOS() const { + assert(TargetInitialized && "Target not initialized!"); + return TargetPlatform == MacOS; + } + + bool isTargetInitialized() const { return TargetInitialized; } + + VersionTuple getTargetVersion() const { + assert(TargetInitialized && "Target not initialized!"); + return TargetVersion; + } + + bool isIPhoneOSVersionLT(unsigned V0, unsigned V1 = 0, + unsigned V2 = 0) const { + assert(isTargetIOSBased() && "Unexpected call for non iOS target!"); + return TargetVersion < VersionTuple(V0, V1, V2); + } + + bool isMacosxVersionLT(unsigned V0, unsigned V1 = 0, unsigned V2 = 0) const { + assert(isTargetMacOS() && "Unexpected call for non OS X target!"); + return TargetVersion < VersionTuple(V0, V1, V2); + } + + StringRef getPlatformFamily() const; + static StringRef getSDKName(StringRef isysroot); + StringRef getOSLibraryNameSuffix() const; + +public: + /// } + /// @name ToolChain Implementation + /// { + + // Darwin tools support multiple architecture (e.g., i386 and x86_64) and + // most development is done against SDKs, so compiling for a different + // architecture should not get any special treatment. + bool isCrossCompiling() const override { return false; } + + llvm::opt::DerivedArgList * + TranslateArgs(const llvm::opt::DerivedArgList &Args, StringRef BoundArch, + Action::OffloadKind DeviceOffloadKind) const override; + + CXXStdlibType GetDefaultCXXStdlibType() const override; + ObjCRuntime getDefaultObjCRuntime(bool isNonFragile) const override; + bool hasBlocksRuntime() const override; + + void AddCudaIncludeArgs(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const override; + + bool UseObjCMixedDispatch() const override { + // This is only used with the non-fragile ABI and non-legacy dispatch. + + // Mixed dispatch is used everywhere except OS X before 10.6. + return !(isTargetMacOS() && isMacosxVersionLT(10, 6)); + } + + unsigned GetDefaultStackProtectorLevel(bool KernelOrKext) const override { + // Stack protectors default to on for user code on 10.5, + // and for everything in 10.6 and beyond + if (isTargetIOSBased() || isTargetWatchOSBased()) + return 1; + else if (isTargetMacOS() && !isMacosxVersionLT(10, 6)) + return 1; + else if (isTargetMacOS() && !isMacosxVersionLT(10, 5) && !KernelOrKext) + return 1; + + return 0; + } + + bool SupportsObjCGC() const override; + + void CheckObjCARC() const override; + + bool UseSjLjExceptions(const llvm::opt::ArgList &Args) const override; + + bool SupportsEmbeddedBitcode() const override; + + SanitizerMask getSupportedSanitizers() const override; + + void printVerboseInfo(raw_ostream &OS) const override; +}; + +/// DarwinClang - The Darwin toolchain used by Clang. +class LLVM_LIBRARY_VISIBILITY DarwinClang : public Darwin { +public: + DarwinClang(const Driver &D, const llvm::Triple &Triple, + const llvm::opt::ArgList &Args); + + /// @name Apple ToolChain Implementation + /// { + + RuntimeLibType GetRuntimeLibType(const llvm::opt::ArgList &Args) const override; + + void AddLinkRuntimeLibArgs(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) const override; + + void AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) const override; + + void AddCCKextLibArgs(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) const override; + + void addClangWarningOptions(llvm::opt::ArgStringList &CC1Args) const override; + + void AddLinkARCArgs(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) const override; + + unsigned GetDefaultDwarfVersion() const override; + // Until dtrace (via CTF) and LLDB can deal with distributed debug info, + // Darwin defaults to standalone/full debug info. + bool GetDefaultStandaloneDebug() const override { return true; } + llvm::DebuggerKind getDefaultDebuggerTuning() const override { + return llvm::DebuggerKind::LLDB; + } + + /// } + +private: + void AddLinkSanitizerLibArgs(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs, + StringRef Sanitizer) const; +}; + +} // end namespace toolchains +} // end namespace driver +} // end namespace clang + +#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_DARWIN_H diff --git a/lib/Driver/ToolChains/DragonFly.cpp b/lib/Driver/ToolChains/DragonFly.cpp new file mode 100644 index 0000000000..bd2c7fc6c4 --- /dev/null +++ b/lib/Driver/ToolChains/DragonFly.cpp @@ -0,0 +1,197 @@ +//===--- DragonFly.cpp - DragonFly 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 "DragonFly.h" +#include "CommonArgs.h" +#include "clang/Driver/Compilation.h" +#include "clang/Driver/Driver.h" +#include "clang/Driver/Options.h" +#include "llvm/Option/ArgList.h" + +using namespace clang::driver; +using namespace clang::driver::tools; +using namespace clang::driver::toolchains; +using namespace clang; +using namespace llvm::opt; + +/// DragonFly Tools + +// For now, DragonFly Assemble does just about the same as for +// FreeBSD, but this may change soon. +void dragonfly::Assembler::ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, + const InputInfoList &Inputs, + const ArgList &Args, + const char *LinkingOutput) const { + claimNoWarnArgs(Args); + ArgStringList CmdArgs; + + // When building 32-bit code on DragonFly/pc64, we have to explicitly + // instruct as in the base system to assemble 32-bit code. + if (getToolChain().getArch() == llvm::Triple::x86) + CmdArgs.push_back("--32"); + + 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 dragonfly::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 (!D.SysRoot.empty()) + CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot)); + + CmdArgs.push_back("--eh-frame-hdr"); + if (Args.hasArg(options::OPT_static)) { + CmdArgs.push_back("-Bstatic"); + } else { + if (Args.hasArg(options::OPT_rdynamic)) + CmdArgs.push_back("-export-dynamic"); + if (Args.hasArg(options::OPT_shared)) + CmdArgs.push_back("-Bshareable"); + else { + CmdArgs.push_back("-dynamic-linker"); + CmdArgs.push_back("/usr/libexec/ld-elf.so.2"); + } + CmdArgs.push_back("--hash-style=gnu"); + CmdArgs.push_back("--enable-new-dtags"); + } + + // When building 32-bit code on DragonFly/pc64, we have to explicitly + // instruct ld in the base system to link 32-bit code. + if (getToolChain().getArch() == llvm::Triple::x86) { + CmdArgs.push_back("-m"); + CmdArgs.push_back("elf_i386"); + } + + 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("gcrt1.o"))); + else { + if (Args.hasArg(options::OPT_pie)) + CmdArgs.push_back( + Args.MakeArgString(getToolChain().GetFilePath("Scrt1.o"))); + else + CmdArgs.push_back( + Args.MakeArgString(getToolChain().GetFilePath("crt1.o"))); + } + } + CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath("crti.o"))); + if (Args.hasArg(options::OPT_shared) || Args.hasArg(options::OPT_pie)) + CmdArgs.push_back( + Args.MakeArgString(getToolChain().GetFilePath("crtbeginS.o"))); + else + CmdArgs.push_back( + Args.MakeArgString(getToolChain().GetFilePath("crtbegin.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)) { + CmdArgs.push_back("-L/usr/lib/gcc50"); + + if (!Args.hasArg(options::OPT_static)) { + CmdArgs.push_back("-rpath"); + CmdArgs.push_back("/usr/lib/gcc50"); + } + + if (D.CCCIsCXX()) { + getToolChain().AddCXXStdlibLibArgs(Args, CmdArgs); + CmdArgs.push_back("-lm"); + } + + if (Args.hasArg(options::OPT_pthread)) + CmdArgs.push_back("-lpthread"); + + if (!Args.hasArg(options::OPT_nolibc)) { + CmdArgs.push_back("-lc"); + } + + if (Args.hasArg(options::OPT_static) || + Args.hasArg(options::OPT_static_libgcc)) { + CmdArgs.push_back("-lgcc"); + CmdArgs.push_back("-lgcc_eh"); + } else { + if (Args.hasArg(options::OPT_shared_libgcc)) { + CmdArgs.push_back("-lgcc_pic"); + if (!Args.hasArg(options::OPT_shared)) + CmdArgs.push_back("-lgcc"); + } else { + CmdArgs.push_back("-lgcc"); + CmdArgs.push_back("--as-needed"); + CmdArgs.push_back("-lgcc_pic"); + CmdArgs.push_back("--no-as-needed"); + } + } + } + + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) { + if (Args.hasArg(options::OPT_shared) || Args.hasArg(options::OPT_pie)) + CmdArgs.push_back( + Args.MakeArgString(getToolChain().GetFilePath("crtendS.o"))); + else + CmdArgs.push_back( + Args.MakeArgString(getToolChain().GetFilePath("crtend.o"))); + CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath("crtn.o"))); + } + + getToolChain().addProfileRTLibs(Args, CmdArgs); + + const char *Exec = Args.MakeArgString(getToolChain().GetLinkerPath()); + C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); +} + +/// DragonFly - DragonFly tool chain which can call as(1) and ld(1) directly. + +DragonFly::DragonFly(const Driver &D, const llvm::Triple &Triple, + const ArgList &Args) + : Generic_ELF(D, Triple, Args) { + + // Path mangling to find libexec + getProgramPaths().push_back(getDriver().getInstalledDir()); + if (getDriver().getInstalledDir() != getDriver().Dir) + getProgramPaths().push_back(getDriver().Dir); + + getFilePaths().push_back(getDriver().Dir + "/../lib"); + getFilePaths().push_back("/usr/lib"); + getFilePaths().push_back("/usr/lib/gcc50"); +} + +Tool *DragonFly::buildAssembler() const { + return new tools::dragonfly::Assembler(*this); +} + +Tool *DragonFly::buildLinker() const { + return new tools::dragonfly::Linker(*this); +} diff --git a/lib/Driver/ToolChains/DragonFly.h b/lib/Driver/ToolChains/DragonFly.h new file mode 100644 index 0000000000..9a06fbd0d3 --- /dev/null +++ b/lib/Driver/ToolChains/DragonFly.h @@ -0,0 +1,68 @@ +//===--- DragonFly.h - DragonFly 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_DRAGONFLY_H +#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_DRAGONFLY_H + +#include "Gnu.h" +#include "clang/Driver/Tool.h" +#include "clang/Driver/ToolChain.h" + +namespace clang { +namespace driver { +namespace tools { +/// dragonfly -- Directly call GNU Binutils assembler and linker +namespace dragonfly { +class LLVM_LIBRARY_VISIBILITY Assembler : public GnuTool { +public: + Assembler(const ToolChain &TC) + : GnuTool("dragonfly::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("dragonfly::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 dragonfly +} // end namespace tools + +namespace toolchains { + +class LLVM_LIBRARY_VISIBILITY DragonFly : public Generic_ELF { +public: + DragonFly(const Driver &D, const llvm::Triple &Triple, + const llvm::opt::ArgList &Args); + + bool IsMathErrnoDefault() const override { return false; } + +protected: + Tool *buildAssembler() const override; + Tool *buildLinker() const override; +}; + +} // end namespace toolchains +} // end namespace driver +} // end namespace clang + +#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_DRAGONFLY_H diff --git a/lib/Driver/ToolChains/FreeBSD.cpp b/lib/Driver/ToolChains/FreeBSD.cpp new file mode 100644 index 0000000000..c6626e922e --- /dev/null +++ b/lib/Driver/ToolChains/FreeBSD.cpp @@ -0,0 +1,395 @@ +//===--- FreeBSD.cpp - FreeBSD 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 "FreeBSD.h" +#include "Arch/ARM.h" +#include "Arch/Mips.h" +#include "Arch/Sparc.h" +#include "CommonArgs.h" +#include "clang/Basic/VirtualFileSystem.h" +#include "clang/Driver/Compilation.h" +#include "clang/Driver/Options.h" +#include "clang/Driver/SanitizerArgs.h" +#include "llvm/Option/ArgList.h" + +using namespace clang::driver; +using namespace clang::driver::tools; +using namespace clang::driver::toolchains; +using namespace clang; +using namespace llvm::opt; + +void freebsd::Assembler::ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, + const InputInfoList &Inputs, + const ArgList &Args, + const char *LinkingOutput) const { + claimNoWarnArgs(Args); + ArgStringList CmdArgs; + + // When building 32-bit code on FreeBSD/amd64, we have to explicitly + // instruct as in the base system to assemble 32-bit code. + switch (getToolChain().getArch()) { + default: + break; + case llvm::Triple::x86: + CmdArgs.push_back("--32"); + break; + case llvm::Triple::ppc: + CmdArgs.push_back("-a32"); + break; + case llvm::Triple::mips: + case llvm::Triple::mipsel: + case llvm::Triple::mips64: + case llvm::Triple::mips64el: { + StringRef CPUName; + StringRef ABIName; + mips::getMipsCPUAndABI(Args, getToolChain().getTriple(), CPUName, ABIName); + + CmdArgs.push_back("-march"); + CmdArgs.push_back(CPUName.data()); + + CmdArgs.push_back("-mabi"); + CmdArgs.push_back(mips::getGnuCompatibleMipsABIName(ABIName).data()); + + if (getToolChain().getArch() == llvm::Triple::mips || + getToolChain().getArch() == llvm::Triple::mips64) + CmdArgs.push_back("-EB"); + else + CmdArgs.push_back("-EL"); + + if (Arg *A = Args.getLastArg(options::OPT_G)) { + StringRef v = A->getValue(); + CmdArgs.push_back(Args.MakeArgString("-G" + v)); + A->claim(); + } + + AddAssemblerKPIC(getToolChain(), Args, CmdArgs); + break; + } + case llvm::Triple::arm: + case llvm::Triple::armeb: + case llvm::Triple::thumb: + case llvm::Triple::thumbeb: { + arm::FloatABI ABI = arm::getARMFloatABI(getToolChain(), Args); + + if (ABI == arm::FloatABI::Hard) + CmdArgs.push_back("-mfpu=vfp"); + else + CmdArgs.push_back("-mfpu=softvfp"); + + switch (getToolChain().getTriple().getEnvironment()) { + case llvm::Triple::GNUEABIHF: + case llvm::Triple::GNUEABI: + case llvm::Triple::EABI: + CmdArgs.push_back("-meabi=5"); + break; + + default: + CmdArgs.push_back("-matpcs"); + } + break; + } + case llvm::Triple::sparc: + case llvm::Triple::sparcel: + case llvm::Triple::sparcv9: { + std::string CPU = getCPUName(Args, getToolChain().getTriple()); + CmdArgs.push_back(sparc::getSparcAsmModeForCPU(CPU, getToolChain().getTriple())); + AddAssemblerKPIC(getToolChain(), Args, CmdArgs); + break; + } + } + + 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 freebsd::Linker::ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, + const InputInfoList &Inputs, + const ArgList &Args, + const char *LinkingOutput) const { + const toolchains::FreeBSD &ToolChain = + static_cast<const toolchains::FreeBSD &>(getToolChain()); + const Driver &D = ToolChain.getDriver(); + const llvm::Triple::ArchType Arch = ToolChain.getArch(); + const bool IsPIE = + !Args.hasArg(options::OPT_shared) && + (Args.hasArg(options::OPT_pie) || ToolChain.isPIEDefault()); + ArgStringList CmdArgs; + + // Silence warning for "clang -g foo.o -o foo" + Args.ClaimAllArgs(options::OPT_g_Group); + // and "clang -emit-llvm foo.o -o foo" + Args.ClaimAllArgs(options::OPT_emit_llvm); + // and for "clang -w foo.o -o foo". Other warning options are already + // handled somewhere else. + Args.ClaimAllArgs(options::OPT_w); + + if (!D.SysRoot.empty()) + CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot)); + + if (IsPIE) + CmdArgs.push_back("-pie"); + + CmdArgs.push_back("--eh-frame-hdr"); + if (Args.hasArg(options::OPT_static)) { + CmdArgs.push_back("-Bstatic"); + } else { + if (Args.hasArg(options::OPT_rdynamic)) + CmdArgs.push_back("-export-dynamic"); + if (Args.hasArg(options::OPT_shared)) { + CmdArgs.push_back("-Bshareable"); + } else { + CmdArgs.push_back("-dynamic-linker"); + CmdArgs.push_back("/libexec/ld-elf.so.1"); + } + if (ToolChain.getTriple().getOSMajorVersion() >= 9) { + if (Arch == llvm::Triple::arm || Arch == llvm::Triple::sparc || + Arch == llvm::Triple::x86 || Arch == llvm::Triple::x86_64) { + CmdArgs.push_back("--hash-style=both"); + } + } + CmdArgs.push_back("--enable-new-dtags"); + } + + // When building 32-bit code on FreeBSD/amd64, we have to explicitly + // instruct ld in the base system to link 32-bit code. + if (Arch == llvm::Triple::x86) { + CmdArgs.push_back("-m"); + CmdArgs.push_back("elf_i386_fbsd"); + } + + if (Arch == llvm::Triple::ppc) { + CmdArgs.push_back("-m"); + CmdArgs.push_back("elf32ppc_fbsd"); + } + + if (Arg *A = Args.getLastArg(options::OPT_G)) { + if (ToolChain.getArch() == llvm::Triple::mips || + ToolChain.getArch() == llvm::Triple::mipsel || + ToolChain.getArch() == llvm::Triple::mips64 || + ToolChain.getArch() == llvm::Triple::mips64el) { + StringRef v = A->getValue(); + CmdArgs.push_back(Args.MakeArgString("-G" + v)); + A->claim(); + } + } + + 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)) { + const char *crt1 = nullptr; + if (!Args.hasArg(options::OPT_shared)) { + if (Args.hasArg(options::OPT_pg)) + crt1 = "gcrt1.o"; + else if (IsPIE) + crt1 = "Scrt1.o"; + else + crt1 = "crt1.o"; + } + if (crt1) + CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crt1))); + + CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crti.o"))); + + const char *crtbegin = nullptr; + if (Args.hasArg(options::OPT_static)) + crtbegin = "crtbeginT.o"; + else if (Args.hasArg(options::OPT_shared) || IsPIE) + crtbegin = "crtbeginS.o"; + else + crtbegin = "crtbegin.o"; + + CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crtbegin))); + } + + Args.AddAllArgs(CmdArgs, options::OPT_L); + ToolChain.AddFilePathLibArgs(Args, CmdArgs); + Args.AddAllArgs(CmdArgs, options::OPT_T_Group); + Args.AddAllArgs(CmdArgs, options::OPT_e); + Args.AddAllArgs(CmdArgs, options::OPT_s); + Args.AddAllArgs(CmdArgs, options::OPT_t); + Args.AddAllArgs(CmdArgs, options::OPT_Z_Flag); + Args.AddAllArgs(CmdArgs, options::OPT_r); + + if (D.isUsingLTO()) + AddGoldPlugin(ToolChain, Args, CmdArgs, D.getLTOMode() == LTOK_Thin, D); + + bool NeedsSanitizerDeps = addSanitizerRuntimes(ToolChain, Args, CmdArgs); + AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA); + + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { + addOpenMPRuntime(CmdArgs, ToolChain, Args); + if (D.CCCIsCXX()) { + ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs); + if (Args.hasArg(options::OPT_pg)) + CmdArgs.push_back("-lm_p"); + else + CmdArgs.push_back("-lm"); + } + if (NeedsSanitizerDeps) + linkSanitizerRuntimeDeps(ToolChain, CmdArgs); + // FIXME: For some reason GCC passes -lgcc and -lgcc_s before adding + // the default system libraries. Just mimic this for now. + if (Args.hasArg(options::OPT_pg)) + CmdArgs.push_back("-lgcc_p"); + else + CmdArgs.push_back("-lgcc"); + if (Args.hasArg(options::OPT_static)) { + CmdArgs.push_back("-lgcc_eh"); + } else if (Args.hasArg(options::OPT_pg)) { + CmdArgs.push_back("-lgcc_eh_p"); + } else { + CmdArgs.push_back("--as-needed"); + CmdArgs.push_back("-lgcc_s"); + CmdArgs.push_back("--no-as-needed"); + } + + if (Args.hasArg(options::OPT_pthread)) { + if (Args.hasArg(options::OPT_pg)) + CmdArgs.push_back("-lpthread_p"); + else + CmdArgs.push_back("-lpthread"); + } + + if (Args.hasArg(options::OPT_pg)) { + if (Args.hasArg(options::OPT_shared)) + CmdArgs.push_back("-lc"); + else + CmdArgs.push_back("-lc_p"); + CmdArgs.push_back("-lgcc_p"); + } else { + CmdArgs.push_back("-lc"); + CmdArgs.push_back("-lgcc"); + } + + if (Args.hasArg(options::OPT_static)) { + CmdArgs.push_back("-lgcc_eh"); + } else if (Args.hasArg(options::OPT_pg)) { + CmdArgs.push_back("-lgcc_eh_p"); + } else { + CmdArgs.push_back("--as-needed"); + CmdArgs.push_back("-lgcc_s"); + CmdArgs.push_back("--no-as-needed"); + } + } + + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) { + if (Args.hasArg(options::OPT_shared) || IsPIE) + CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtendS.o"))); + else + CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtend.o"))); + CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtn.o"))); + } + + ToolChain.addProfileRTLibs(Args, CmdArgs); + + const char *Exec = Args.MakeArgString(getToolChain().GetLinkerPath()); + C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); +} + +/// FreeBSD - FreeBSD tool chain which can call as(1) and ld(1) directly. + +FreeBSD::FreeBSD(const Driver &D, const llvm::Triple &Triple, + const ArgList &Args) + : Generic_ELF(D, Triple, Args) { + + // When targeting 32-bit platforms, look for '/usr/lib32/crt1.o' and fall + // back to '/usr/lib' if it doesn't exist. + if ((Triple.getArch() == llvm::Triple::x86 || + Triple.getArch() == llvm::Triple::ppc) && + D.getVFS().exists(getDriver().SysRoot + "/usr/lib32/crt1.o")) + getFilePaths().push_back(getDriver().SysRoot + "/usr/lib32"); + else + getFilePaths().push_back(getDriver().SysRoot + "/usr/lib"); +} + +ToolChain::CXXStdlibType FreeBSD::GetDefaultCXXStdlibType() const { + if (getTriple().getOSMajorVersion() >= 10) + return ToolChain::CST_Libcxx; + return ToolChain::CST_Libstdcxx; +} + +void FreeBSD::addLibStdCxxIncludePaths( + const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const { + addLibStdCXXIncludePaths(getDriver().SysRoot, "/usr/include/c++/4.2", "", "", + "", "", DriverArgs, CC1Args); +} + +void FreeBSD::AddCXXStdlibLibArgs(const ArgList &Args, + ArgStringList &CmdArgs) const { + CXXStdlibType Type = GetCXXStdlibType(Args); + bool Profiling = Args.hasArg(options::OPT_pg); + + switch (Type) { + case ToolChain::CST_Libcxx: + CmdArgs.push_back(Profiling ? "-lc++_p" : "-lc++"); + break; + + case ToolChain::CST_Libstdcxx: + CmdArgs.push_back(Profiling ? "-lstdc++_p" : "-lstdc++"); + break; + } +} + +Tool *FreeBSD::buildAssembler() const { + return new tools::freebsd::Assembler(*this); +} + +Tool *FreeBSD::buildLinker() const { return new tools::freebsd::Linker(*this); } + +bool FreeBSD::UseSjLjExceptions(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; + + default: + return (getTriple().getArch() == llvm::Triple::arm || + getTriple().getArch() == llvm::Triple::thumb); + } +} + +bool FreeBSD::HasNativeLLVMSupport() const { return true; } + +bool FreeBSD::isPIEDefault() const { return getSanitizerArgs().requiresPIE(); } + +SanitizerMask FreeBSD::getSupportedSanitizers() const { + const bool IsX86 = getTriple().getArch() == llvm::Triple::x86; + const bool IsX86_64 = getTriple().getArch() == llvm::Triple::x86_64; + const bool IsMIPS64 = getTriple().getArch() == llvm::Triple::mips64 || + getTriple().getArch() == llvm::Triple::mips64el; + SanitizerMask Res = ToolChain::getSupportedSanitizers(); + Res |= SanitizerKind::Address; + Res |= SanitizerKind::Vptr; + if (IsX86_64 || IsMIPS64) { + Res |= SanitizerKind::Leak; + Res |= SanitizerKind::Thread; + } + if (IsX86 || IsX86_64) { + Res |= SanitizerKind::SafeStack; + } + return Res; +} diff --git a/lib/Driver/ToolChains/FreeBSD.h b/lib/Driver/ToolChains/FreeBSD.h new file mode 100644 index 0000000000..25e9df72bc --- /dev/null +++ b/lib/Driver/ToolChains/FreeBSD.h @@ -0,0 +1,86 @@ +//===--- FreeBSD.h - FreeBSD 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_FREEBSD_H +#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_FREEBSD_H + +#include "Gnu.h" +#include "clang/Driver/Driver.h" +#include "clang/Driver/ToolChain.h" + +namespace clang { +namespace driver { +namespace tools { + +/// freebsd -- Directly call GNU Binutils assembler and linker +namespace freebsd { +class LLVM_LIBRARY_VISIBILITY Assembler : public GnuTool { +public: + Assembler(const ToolChain &TC) + : GnuTool("freebsd::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("freebsd::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 freebsd +} // end namespace tools + +namespace toolchains { + +class LLVM_LIBRARY_VISIBILITY FreeBSD : public Generic_ELF { +public: + FreeBSD(const Driver &D, const llvm::Triple &Triple, + const llvm::opt::ArgList &Args); + bool HasNativeLLVMSupport() const override; + + 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; + + bool UseSjLjExceptions(const llvm::opt::ArgList &Args) const override; + bool isPIEDefault() const override; + SanitizerMask getSupportedSanitizers() const override; + unsigned GetDefaultDwarfVersion() const override { return 2; } + // Until dtrace (via CTF) and LLDB can deal with distributed debug info, + // FreeBSD defaults to standalone/full debug info. + bool GetDefaultStandaloneDebug() const override { return true; } + +protected: + Tool *buildAssembler() const override; + Tool *buildLinker() const override; +}; + +} // end namespace toolchains +} // end namespace driver +} // end namespace clang + +#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_FREEBSD_H diff --git a/lib/Driver/ToolChains/Fuchsia.cpp b/lib/Driver/ToolChains/Fuchsia.cpp new file mode 100644 index 0000000000..b8757cf4aa --- /dev/null +++ b/lib/Driver/ToolChains/Fuchsia.cpp @@ -0,0 +1,229 @@ +//===--- Fuchsia.cpp - Fuchsia 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 "Fuchsia.h" +#include "CommonArgs.h" +#include "clang/Config/config.h" +#include "clang/Driver/Compilation.h" +#include "clang/Driver/Driver.h" +#include "clang/Driver/DriverDiagnostic.h" +#include "clang/Driver/Options.h" +#include "llvm/Option/ArgList.h" +#include "llvm/Support/Path.h" + +using namespace clang::driver; +using namespace clang::driver::toolchains; +using namespace clang::driver::tools; +using namespace clang; +using namespace llvm::opt; + +void fuchsia::Linker::ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, + const InputInfoList &Inputs, + const ArgList &Args, + const char *LinkingOutput) const { + const toolchains::Fuchsia &ToolChain = + static_cast<const toolchains::Fuchsia &>(getToolChain()); + const Driver &D = ToolChain.getDriver(); + + ArgStringList CmdArgs; + + // Silence warning for "clang -g foo.o -o foo" + Args.ClaimAllArgs(options::OPT_g_Group); + // and "clang -emit-llvm foo.o -o foo" + Args.ClaimAllArgs(options::OPT_emit_llvm); + // and for "clang -w foo.o -o foo". Other warning options are already + // handled somewhere else. + Args.ClaimAllArgs(options::OPT_w); + + const char *Exec = Args.MakeArgString(ToolChain.GetLinkerPath()); + if (llvm::sys::path::stem(Exec).equals_lower("lld")) { + CmdArgs.push_back("-flavor"); + CmdArgs.push_back("gnu"); + } + + if (!D.SysRoot.empty()) + CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot)); + + if (!Args.hasArg(options::OPT_shared) && !Args.hasArg(options::OPT_r)) + CmdArgs.push_back("-pie"); + + if (Args.hasArg(options::OPT_rdynamic)) + CmdArgs.push_back("-export-dynamic"); + + if (Args.hasArg(options::OPT_s)) + CmdArgs.push_back("-s"); + + if (Args.hasArg(options::OPT_r)) + CmdArgs.push_back("-r"); + else + CmdArgs.push_back("--build-id"); + + if (!Args.hasArg(options::OPT_static)) + 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")); + } + } + + CmdArgs.push_back("-o"); + CmdArgs.push_back(Output.getFilename()); + + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) { + if (!Args.hasArg(options::OPT_shared)) { + CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("Scrt1.o"))); + } + } + + Args.AddAllArgs(CmdArgs, options::OPT_L); + Args.AddAllArgs(CmdArgs, options::OPT_u); + + ToolChain.AddFilePathLibArgs(Args, CmdArgs); + + AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA); + + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { + if (Args.hasArg(options::OPT_static)) + 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"); + CmdArgs.push_back("-lm"); + } + + AddRunTimeLibs(ToolChain, D, CmdArgs, Args); + + if (Args.hasArg(options::OPT_pthread) || + Args.hasArg(options::OPT_pthreads)) + CmdArgs.push_back("-lpthread"); + + if (Args.hasArg(options::OPT_fsplit_stack)) + CmdArgs.push_back("--wrap=pthread_create"); + + CmdArgs.push_back("-lc"); + } + + C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); +} + +/// Fuchsia - Fuchsia tool chain which can call as(1) and ld(1) directly. + +Fuchsia::Fuchsia(const Driver &D, const llvm::Triple &Triple, + const ArgList &Args) + : Generic_ELF(D, Triple, Args) { + + getFilePaths().push_back(D.SysRoot + "/lib"); + getFilePaths().push_back(D.ResourceDir + "/lib/fuchsia"); +} + +Tool *Fuchsia::buildAssembler() const { + return new tools::gnutools::Assembler(*this); +} + +Tool *Fuchsia::buildLinker() const { + return new tools::fuchsia::Linker(*this); +} + +ToolChain::RuntimeLibType Fuchsia::GetRuntimeLibType( + const ArgList &Args) const { + if (Arg *A = Args.getLastArg(clang::driver::options::OPT_rtlib_EQ)) { + StringRef Value = A->getValue(); + if (Value != "compiler-rt") + getDriver().Diag(clang::diag::err_drv_invalid_rtlib_name) + << A->getAsString(Args); + } + + return ToolChain::RLT_CompilerRT; +} + +ToolChain::CXXStdlibType +Fuchsia::GetCXXStdlibType(const ArgList &Args) const { + if (Arg *A = Args.getLastArg(options::OPT_stdlib_EQ)) { + StringRef Value = A->getValue(); + if (Value != "libc++") + getDriver().Diag(diag::err_drv_invalid_stdlib_name) + << A->getAsString(Args); + } + + return ToolChain::CST_Libcxx; +} + +void Fuchsia::addClangTargetOptions(const ArgList &DriverArgs, + ArgStringList &CC1Args) const { + if (DriverArgs.hasFlag(options::OPT_fuse_init_array, + options::OPT_fno_use_init_array, true)) + CC1Args.push_back("-fuse-init-array"); +} + +void Fuchsia::AddClangSystemIncludeArgs(const ArgList &DriverArgs, + ArgStringList &CC1Args) const { + const Driver &D = getDriver(); + + if (DriverArgs.hasArg(options::OPT_nostdinc)) + return; + + if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) { + SmallString<128> P(D.ResourceDir); + llvm::sys::path::append(P, "include"); + addSystemInclude(DriverArgs, CC1Args, P); + } + + if (DriverArgs.hasArg(options::OPT_nostdlibinc)) + return; + + // Check for configure-time C include directories. + StringRef CIncludeDirs(C_INCLUDE_DIRS); + if (CIncludeDirs != "") { + SmallVector<StringRef, 5> dirs; + CIncludeDirs.split(dirs, ":"); + for (StringRef dir : dirs) { + StringRef Prefix = + llvm::sys::path::is_absolute(dir) ? StringRef(D.SysRoot) : ""; + addExternCSystemInclude(DriverArgs, CC1Args, Prefix + dir); + } + return; + } + + addExternCSystemInclude(DriverArgs, CC1Args, D.SysRoot + "/include"); +} + +std::string Fuchsia::findLibCxxIncludePath() const { + return getDriver().SysRoot + "/include/c++/v1"; +} + +void Fuchsia::AddCXXStdlibLibArgs(const ArgList &Args, + ArgStringList &CmdArgs) const { + (void) GetCXXStdlibType(Args); + CmdArgs.push_back("-lc++"); + CmdArgs.push_back("-lc++abi"); + CmdArgs.push_back("-lunwind"); +} + +SanitizerMask Fuchsia::getSupportedSanitizers() const { + SanitizerMask Res = ToolChain::getSupportedSanitizers(); + Res |= SanitizerKind::SafeStack; + return Res; +} diff --git a/lib/Driver/ToolChains/Fuchsia.h b/lib/Driver/ToolChains/Fuchsia.h new file mode 100644 index 0000000000..1a8c9903fe --- /dev/null +++ b/lib/Driver/ToolChains/Fuchsia.h @@ -0,0 +1,79 @@ +//===--- Fuchsia.h - Fuchsia 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_FUCHSIA_H +#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_FUCHSIA_H + +#include "Gnu.h" +#include "clang/Driver/Tool.h" +#include "clang/Driver/ToolChain.h" + +namespace clang { +namespace driver { +namespace tools { +namespace fuchsia { +class LLVM_LIBRARY_VISIBILITY Linker : public GnuTool { +public: + Linker(const ToolChain &TC) : GnuTool("fuchsia::Linker", "ld.lld", 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 fuchsia +} // end namespace tools + +namespace toolchains { + +class LLVM_LIBRARY_VISIBILITY Fuchsia : public Generic_ELF { +public: + Fuchsia(const Driver &D, const llvm::Triple &Triple, + const llvm::opt::ArgList &Args); + + bool isPIEDefault() const override { return true; } + bool HasNativeLLVMSupport() const override { return true; } + bool IsIntegratedAssemblerDefault() const override { return true; } + llvm::DebuggerKind getDefaultDebuggerTuning() const override { + return llvm::DebuggerKind::GDB; + } + + SanitizerMask getSupportedSanitizers() const override; + + RuntimeLibType + GetRuntimeLibType(const llvm::opt::ArgList &Args) const override; + CXXStdlibType + GetCXXStdlibType(const llvm::opt::ArgList &Args) const override; + + void addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const override; + void + AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const override; + std::string findLibCxxIncludePath() const override; + void AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) const override; + + const char *getDefaultLinker() const override { + return "lld"; + } + +protected: + Tool *buildAssembler() const override; + Tool *buildLinker() const override; +}; + +} // end namespace toolchains +} // end namespace driver +} // end namespace clang + +#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_FUCHSIA_H diff --git a/lib/Driver/ToolChains/Gnu.cpp b/lib/Driver/ToolChains/Gnu.cpp new file mode 100644 index 0000000000..6425850cd8 --- /dev/null +++ b/lib/Driver/ToolChains/Gnu.cpp @@ -0,0 +1,2429 @@ +//===--- Gnu.cpp - Gnu Tool and ToolChain Implementations -------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "Gnu.h" +#include "Linux.h" +#include "Arch/ARM.h" +#include "Arch/Mips.h" +#include "Arch/Sparc.h" +#include "Arch/SystemZ.h" +#include "CommonArgs.h" +#include "clang/Basic/VirtualFileSystem.h" +#include "clang/Config/config.h" // for GCC_INSTALL_PREFIX +#include "clang/Driver/Compilation.h" +#include "clang/Driver/Driver.h" +#include "clang/Driver/DriverDiagnostic.h" +#include "clang/Driver/Options.h" +#include "clang/Driver/Tool.h" +#include "llvm/Option/ArgList.h" +#include "llvm/Support/CodeGen.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/TargetParser.h" +#include <system_error> + +using namespace clang::driver; +using namespace clang::driver::toolchains; +using namespace clang; +using namespace llvm::opt; + +void tools::GnuTool::anchor() {} + +static bool forwardToGCC(const Option &O) { + // Don't forward inputs from the original command line. They are added from + // InputInfoList. + return O.getKind() != Option::InputClass && + !O.hasFlag(options::DriverOption) && !O.hasFlag(options::LinkerInput); +} + +void tools::gcc::Common::ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, + const InputInfoList &Inputs, + const ArgList &Args, + const char *LinkingOutput) const { + const Driver &D = getToolChain().getDriver(); + ArgStringList CmdArgs; + + for (const auto &A : Args) { + if (forwardToGCC(A->getOption())) { + // It is unfortunate that we have to claim here, as this means + // we will basically never report anything interesting for + // platforms using a generic gcc, even if we are just using gcc + // to get to the assembler. + A->claim(); + + // Don't forward any -g arguments to assembly steps. + if (isa<AssembleJobAction>(JA) && + A->getOption().matches(options::OPT_g_Group)) + continue; + + // Don't forward any -W arguments to assembly and link steps. + if ((isa<AssembleJobAction>(JA) || isa<LinkJobAction>(JA)) && + A->getOption().matches(options::OPT_W_Group)) + continue; + + A->render(Args, CmdArgs); + } + } + + RenderExtraToolArgs(JA, CmdArgs); + + // If using a driver driver, force the arch. + if (getToolChain().getTriple().isOSDarwin()) { + CmdArgs.push_back("-arch"); + CmdArgs.push_back( + Args.MakeArgString(getToolChain().getDefaultUniversalArchName())); + } + + // Try to force gcc to match the tool chain we want, if we recognize + // the arch. + // + // FIXME: The triple class should directly provide the information we want + // here. + switch (getToolChain().getArch()) { + default: + break; + case llvm::Triple::x86: + case llvm::Triple::ppc: + CmdArgs.push_back("-m32"); + break; + case llvm::Triple::x86_64: + case llvm::Triple::ppc64: + case llvm::Triple::ppc64le: + CmdArgs.push_back("-m64"); + break; + case llvm::Triple::sparcel: + CmdArgs.push_back("-EL"); + break; + } + + if (Output.isFilename()) { + CmdArgs.push_back("-o"); + CmdArgs.push_back(Output.getFilename()); + } else { + assert(Output.isNothing() && "Unexpected output"); + CmdArgs.push_back("-fsyntax-only"); + } + + Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler); + + // Only pass -x if gcc will understand it; otherwise hope gcc + // understands the suffix correctly. The main use case this would go + // wrong in is for linker inputs if they happened to have an odd + // suffix; really the only way to get this to happen is a command + // like '-x foobar a.c' which will treat a.c like a linker input. + // + // FIXME: For the linker case specifically, can we safely convert + // inputs into '-Wl,' options? + for (const auto &II : Inputs) { + // Don't try to pass LLVM or AST inputs to a generic gcc. + if (types::isLLVMIR(II.getType())) + D.Diag(clang::diag::err_drv_no_linker_llvm_support) + << getToolChain().getTripleString(); + else if (II.getType() == types::TY_AST) + D.Diag(diag::err_drv_no_ast_support) << getToolChain().getTripleString(); + else if (II.getType() == types::TY_ModuleFile) + D.Diag(diag::err_drv_no_module_support) + << getToolChain().getTripleString(); + + if (types::canTypeBeUserSpecified(II.getType())) { + CmdArgs.push_back("-x"); + CmdArgs.push_back(types::getTypeName(II.getType())); + } + + if (II.isFilename()) + CmdArgs.push_back(II.getFilename()); + else { + const Arg &A = II.getInputArg(); + + // Reverse translate some rewritten options. + if (A.getOption().matches(options::OPT_Z_reserved_lib_stdcxx)) { + CmdArgs.push_back("-lstdc++"); + continue; + } + + // Don't render as input, we need gcc to do the translations. + A.render(Args, CmdArgs); + } + } + + const std::string &customGCCName = D.getCCCGenericGCCName(); + const char *GCCName; + if (!customGCCName.empty()) + GCCName = customGCCName.c_str(); + else if (D.CCCIsCXX()) { + GCCName = "g++"; + } else + GCCName = "gcc"; + + const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath(GCCName)); + C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); +} + +void tools::gcc::Preprocessor::RenderExtraToolArgs( + const JobAction &JA, ArgStringList &CmdArgs) const { + CmdArgs.push_back("-E"); +} + +void tools::gcc::Compiler::RenderExtraToolArgs(const JobAction &JA, + ArgStringList &CmdArgs) const { + const Driver &D = getToolChain().getDriver(); + + switch (JA.getType()) { + // If -flto, etc. are present then make sure not to force assembly output. + case types::TY_LLVM_IR: + case types::TY_LTO_IR: + case types::TY_LLVM_BC: + case types::TY_LTO_BC: + CmdArgs.push_back("-c"); + break; + // We assume we've got an "integrated" assembler in that gcc will produce an + // object file itself. + case types::TY_Object: + CmdArgs.push_back("-c"); + break; + case types::TY_PP_Asm: + CmdArgs.push_back("-S"); + break; + case types::TY_Nothing: + CmdArgs.push_back("-fsyntax-only"); + break; + default: + D.Diag(diag::err_drv_invalid_gcc_output_type) << getTypeName(JA.getType()); + } +} + +void tools::gcc::Linker::RenderExtraToolArgs(const JobAction &JA, + ArgStringList &CmdArgs) const { + // The types are (hopefully) good enough. +} + +/// Add OpenMP linker script arguments at the end of the argument list so that +/// the fat binary is built by embedding each of the device images into the +/// host. The linker script also defines a few symbols required by the code +/// generation so that the images can be easily retrieved at runtime by the +/// offloading library. This should be used only in tool chains that support +/// linker scripts. +static void AddOpenMPLinkerScript(const ToolChain &TC, Compilation &C, + const InputInfo &Output, + const InputInfoList &Inputs, + const ArgList &Args, ArgStringList &CmdArgs, + const JobAction &JA) { + + // If this is not an OpenMP host toolchain, we don't need to do anything. + if (!JA.isHostOffloading(Action::OFK_OpenMP)) + return; + + // Create temporary linker script. Keep it if save-temps is enabled. + const char *LKS; + SmallString<256> Name = llvm::sys::path::filename(Output.getFilename()); + if (C.getDriver().isSaveTempsEnabled()) { + llvm::sys::path::replace_extension(Name, "lk"); + LKS = C.getArgs().MakeArgString(Name.c_str()); + } else { + llvm::sys::path::replace_extension(Name, ""); + Name = C.getDriver().GetTemporaryPath(Name, "lk"); + LKS = C.addTempFile(C.getArgs().MakeArgString(Name.c_str())); + } + + // Add linker script option to the command. + CmdArgs.push_back("-T"); + CmdArgs.push_back(LKS); + + // Create a buffer to write the contents of the linker script. + std::string LksBuffer; + llvm::raw_string_ostream LksStream(LksBuffer); + + // Get the OpenMP offload tool chains so that we can extract the triple + // associated with each device input. + auto OpenMPToolChains = C.getOffloadToolChains<Action::OFK_OpenMP>(); + assert(OpenMPToolChains.first != OpenMPToolChains.second && + "No OpenMP toolchains??"); + + // Track the input file name and device triple in order to build the script, + // inserting binaries in the designated sections. + SmallVector<std::pair<std::string, const char *>, 8> InputBinaryInfo; + + // Add commands to embed target binaries. We ensure that each section and + // image is 16-byte aligned. This is not mandatory, but increases the + // likelihood of data to be aligned with a cache block in several main host + // machines. + LksStream << "/*\n"; + LksStream << " OpenMP Offload Linker Script\n"; + LksStream << " *** Automatically generated by Clang ***\n"; + LksStream << "*/\n"; + LksStream << "TARGET(binary)\n"; + auto DTC = OpenMPToolChains.first; + for (auto &II : Inputs) { + const Action *A = II.getAction(); + // Is this a device linking action? + if (A && isa<LinkJobAction>(A) && + A->isDeviceOffloading(Action::OFK_OpenMP)) { + assert(DTC != OpenMPToolChains.second && + "More device inputs than device toolchains??"); + InputBinaryInfo.push_back(std::make_pair( + DTC->second->getTriple().normalize(), II.getFilename())); + ++DTC; + LksStream << "INPUT(" << II.getFilename() << ")\n"; + } + } + + assert(DTC == OpenMPToolChains.second && + "Less device inputs than device toolchains??"); + + LksStream << "SECTIONS\n"; + LksStream << "{\n"; + LksStream << " .omp_offloading :\n"; + LksStream << " ALIGN(0x10)\n"; + LksStream << " {\n"; + + for (auto &BI : InputBinaryInfo) { + LksStream << " . = ALIGN(0x10);\n"; + LksStream << " PROVIDE_HIDDEN(.omp_offloading.img_start." << BI.first + << " = .);\n"; + LksStream << " " << BI.second << "\n"; + LksStream << " PROVIDE_HIDDEN(.omp_offloading.img_end." << BI.first + << " = .);\n"; + } + + LksStream << " }\n"; + // Add commands to define host entries begin and end. We use 1-byte subalign + // so that the linker does not add any padding and the elements in this + // section form an array. + LksStream << " .omp_offloading.entries :\n"; + LksStream << " ALIGN(0x10)\n"; + LksStream << " SUBALIGN(0x01)\n"; + LksStream << " {\n"; + LksStream << " PROVIDE_HIDDEN(.omp_offloading.entries_begin = .);\n"; + LksStream << " *(.omp_offloading.entries)\n"; + LksStream << " PROVIDE_HIDDEN(.omp_offloading.entries_end = .);\n"; + LksStream << " }\n"; + LksStream << "}\n"; + LksStream << "INSERT BEFORE .data\n"; + LksStream.flush(); + + // Dump the contents of the linker script if the user requested that. We + // support this option to enable testing of behavior with -###. + if (C.getArgs().hasArg(options::OPT_fopenmp_dump_offload_linker_script)) + llvm::errs() << LksBuffer; + + // If this is a dry run, do not create the linker script file. + if (C.getArgs().hasArg(options::OPT__HASH_HASH_HASH)) + return; + + // Open script file and write the contents. + std::error_code EC; + llvm::raw_fd_ostream Lksf(LKS, EC, llvm::sys::fs::F_None); + + if (EC) { + C.getDriver().Diag(clang::diag::err_unable_to_make_temp) << EC.message(); + return; + } + + Lksf << LksBuffer; +} + +static bool addXRayRuntime(const ToolChain &TC, const ArgList &Args, + ArgStringList &CmdArgs) { + if (Args.hasFlag(options::OPT_fxray_instrument, + options::OPT_fnoxray_instrument, false)) { + CmdArgs.push_back("-whole-archive"); + CmdArgs.push_back(TC.getCompilerRTArgString(Args, "xray", false)); + CmdArgs.push_back("-no-whole-archive"); + return true; + } + return false; +} + +static void linkXRayRuntimeDeps(const ToolChain &TC, const ArgList &Args, + ArgStringList &CmdArgs) { + CmdArgs.push_back("--no-as-needed"); + CmdArgs.push_back("-lpthread"); + CmdArgs.push_back("-lrt"); + CmdArgs.push_back("-lm"); + CmdArgs.push_back("-latomic"); + if (TC.GetCXXStdlibType(Args) == ToolChain::CST_Libcxx) + CmdArgs.push_back("-lc++"); + else + CmdArgs.push_back("-lstdc++"); + if (TC.getTriple().getOS() != llvm::Triple::FreeBSD) + CmdArgs.push_back("-ldl"); +} + +static const char *getLDMOption(const llvm::Triple &T, const ArgList &Args) { + switch (T.getArch()) { + case llvm::Triple::x86: + if (T.isOSIAMCU()) + return "elf_iamcu"; + return "elf_i386"; + case llvm::Triple::aarch64: + return "aarch64linux"; + case llvm::Triple::aarch64_be: + return "aarch64_be_linux"; + case llvm::Triple::arm: + case llvm::Triple::thumb: + return "armelf_linux_eabi"; + case llvm::Triple::armeb: + case llvm::Triple::thumbeb: + return "armelfb_linux_eabi"; + case llvm::Triple::ppc: + return "elf32ppclinux"; + case llvm::Triple::ppc64: + return "elf64ppc"; + case llvm::Triple::ppc64le: + return "elf64lppc"; + case llvm::Triple::sparc: + case llvm::Triple::sparcel: + return "elf32_sparc"; + case llvm::Triple::sparcv9: + return "elf64_sparc"; + case llvm::Triple::mips: + return "elf32btsmip"; + case llvm::Triple::mipsel: + return "elf32ltsmip"; + case llvm::Triple::mips64: + if (tools::mips::hasMipsAbiArg(Args, "n32")) + return "elf32btsmipn32"; + return "elf64btsmip"; + case llvm::Triple::mips64el: + if (tools::mips::hasMipsAbiArg(Args, "n32")) + return "elf32ltsmipn32"; + return "elf64ltsmip"; + case llvm::Triple::systemz: + return "elf64_s390"; + case llvm::Triple::x86_64: + if (T.getEnvironment() == llvm::Triple::GNUX32) + return "elf32_x86_64"; + return "elf_x86_64"; + default: + return nullptr; + } +} + +void tools::gnutools::Linker::ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, + const InputInfoList &Inputs, + const ArgList &Args, + const char *LinkingOutput) const { + const toolchains::Linux &ToolChain = + static_cast<const toolchains::Linux &>(getToolChain()); + const Driver &D = ToolChain.getDriver(); + + const llvm::Triple &Triple = getToolChain().getEffectiveTriple(); + + const llvm::Triple::ArchType Arch = ToolChain.getArch(); + const bool isAndroid = ToolChain.getTriple().isAndroid(); + const bool IsIAMCU = ToolChain.getTriple().isOSIAMCU(); + const bool IsPIE = + !Args.hasArg(options::OPT_shared) && !Args.hasArg(options::OPT_static) && + (Args.hasArg(options::OPT_pie) || ToolChain.isPIEDefault()); + const bool HasCRTBeginEndFiles = + ToolChain.getTriple().hasEnvironment() || + (ToolChain.getTriple().getVendor() != llvm::Triple::MipsTechnologies); + + ArgStringList CmdArgs; + + // Silence warning for "clang -g foo.o -o foo" + Args.ClaimAllArgs(options::OPT_g_Group); + // and "clang -emit-llvm foo.o -o foo" + Args.ClaimAllArgs(options::OPT_emit_llvm); + // and for "clang -w foo.o -o foo". Other warning options are already + // handled somewhere else. + Args.ClaimAllArgs(options::OPT_w); + + const char *Exec = Args.MakeArgString(ToolChain.GetLinkerPath()); + if (llvm::sys::path::stem(Exec) == "lld") { + CmdArgs.push_back("-flavor"); + CmdArgs.push_back("old-gnu"); + CmdArgs.push_back("-target"); + CmdArgs.push_back(Args.MakeArgString(getToolChain().getTripleString())); + } + + if (!D.SysRoot.empty()) + CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot)); + + if (IsPIE) + CmdArgs.push_back("-pie"); + + if (Args.hasArg(options::OPT_rdynamic)) + CmdArgs.push_back("-export-dynamic"); + + if (Args.hasArg(options::OPT_s)) + CmdArgs.push_back("-s"); + + if (Arch == llvm::Triple::armeb || Arch == llvm::Triple::thumbeb) + arm::appendEBLinkFlags(Args, CmdArgs, Triple); + + // Most Android ARM64 targets should enable the linker fix for erratum + // 843419. Only non-Cortex-A53 devices are allowed to skip this flag. + if (Arch == llvm::Triple::aarch64 && isAndroid) { + std::string CPU = getCPUName(Args, Triple); + if (CPU.empty() || CPU == "generic" || CPU == "cortex-a53") + CmdArgs.push_back("--fix-cortex-a53-843419"); + } + + for (const auto &Opt : ToolChain.ExtraOpts) + CmdArgs.push_back(Opt.c_str()); + + if (!Args.hasArg(options::OPT_static)) { + CmdArgs.push_back("--eh-frame-hdr"); + } + + if (const char *LDMOption = getLDMOption(ToolChain.getTriple(), Args)) { + CmdArgs.push_back("-m"); + CmdArgs.push_back(LDMOption); + } else { + D.Diag(diag::err_target_unknown_triple) << Triple.str(); + return; + } + + if (Args.hasArg(options::OPT_static)) { + if (Arch == llvm::Triple::arm || Arch == llvm::Triple::armeb || + Arch == llvm::Triple::thumb || Arch == llvm::Triple::thumbeb) + CmdArgs.push_back("-Bstatic"); + else + CmdArgs.push_back("-static"); + } else if (Args.hasArg(options::OPT_shared)) { + CmdArgs.push_back("-shared"); + } + + if (!Args.hasArg(options::OPT_static)) { + if (Args.hasArg(options::OPT_rdynamic)) + CmdArgs.push_back("-export-dynamic"); + + if (!Args.hasArg(options::OPT_shared)) { + const std::string Loader = + D.DyldPrefix + ToolChain.getDynamicLinker(Args); + CmdArgs.push_back("-dynamic-linker"); + CmdArgs.push_back(Args.MakeArgString(Loader)); + } + } + + CmdArgs.push_back("-o"); + CmdArgs.push_back(Output.getFilename()); + + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) { + if (!isAndroid && !IsIAMCU) { + const char *crt1 = nullptr; + if (!Args.hasArg(options::OPT_shared)) { + if (Args.hasArg(options::OPT_pg)) + crt1 = "gcrt1.o"; + else if (IsPIE) + crt1 = "Scrt1.o"; + else + crt1 = "crt1.o"; + } + if (crt1) + CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crt1))); + + CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crti.o"))); + } + + if (IsIAMCU) + CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crt0.o"))); + else { + const char *crtbegin; + if (Args.hasArg(options::OPT_static)) + crtbegin = isAndroid ? "crtbegin_static.o" : "crtbeginT.o"; + else if (Args.hasArg(options::OPT_shared)) + crtbegin = isAndroid ? "crtbegin_so.o" : "crtbeginS.o"; + else if (IsPIE) + crtbegin = isAndroid ? "crtbegin_dynamic.o" : "crtbeginS.o"; + else + crtbegin = isAndroid ? "crtbegin_dynamic.o" : "crtbegin.o"; + + if (HasCRTBeginEndFiles) + CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crtbegin))); + } + + // Add crtfastmath.o if available and fast math is enabled. + ToolChain.AddFastMathRuntimeIfAvailable(Args, CmdArgs); + } + + Args.AddAllArgs(CmdArgs, options::OPT_L); + Args.AddAllArgs(CmdArgs, options::OPT_u); + + ToolChain.AddFilePathLibArgs(Args, CmdArgs); + + if (D.isUsingLTO()) + AddGoldPlugin(ToolChain, Args, CmdArgs, D.getLTOMode() == LTOK_Thin, D); + + if (Args.hasArg(options::OPT_Z_Xlinker__no_demangle)) + CmdArgs.push_back("--no-demangle"); + + bool NeedsSanitizerDeps = addSanitizerRuntimes(ToolChain, Args, CmdArgs); + bool NeedsXRayDeps = addXRayRuntime(ToolChain, Args, CmdArgs); + AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA); + // The profile runtime also needs access to system libraries. + getToolChain().addProfileRTLibs(Args, CmdArgs); + + if (D.CCCIsCXX() && + !Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { + bool OnlyLibstdcxxStatic = Args.hasArg(options::OPT_static_libstdcxx) && + !Args.hasArg(options::OPT_static); + if (OnlyLibstdcxxStatic) + CmdArgs.push_back("-Bstatic"); + ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs); + if (OnlyLibstdcxxStatic) + CmdArgs.push_back("-Bdynamic"); + CmdArgs.push_back("-lm"); + } + // Silence warnings when linking C code with a C++ '-stdlib' argument. + Args.ClaimAllArgs(options::OPT_stdlib_EQ); + + if (!Args.hasArg(options::OPT_nostdlib)) { + if (!Args.hasArg(options::OPT_nodefaultlibs)) { + if (Args.hasArg(options::OPT_static)) + CmdArgs.push_back("--start-group"); + + if (NeedsSanitizerDeps) + linkSanitizerRuntimeDeps(ToolChain, CmdArgs); + + if (NeedsXRayDeps) + linkXRayRuntimeDeps(ToolChain, Args, CmdArgs); + + bool WantPthread = Args.hasArg(options::OPT_pthread) || + Args.hasArg(options::OPT_pthreads); + + if (Args.hasFlag(options::OPT_fopenmp, options::OPT_fopenmp_EQ, + options::OPT_fno_openmp, false)) { + // OpenMP runtimes implies pthreads when using the GNU toolchain. + // FIXME: Does this really make sense for all GNU toolchains? + WantPthread = true; + + // Also link the particular OpenMP runtimes. + switch (ToolChain.getDriver().getOpenMPRuntime(Args)) { + case Driver::OMPRT_OMP: + CmdArgs.push_back("-lomp"); + break; + case Driver::OMPRT_GOMP: + CmdArgs.push_back("-lgomp"); + + // FIXME: Exclude this for platforms with libgomp that don't require + // librt. Most modern Linux platforms require it, but some may not. + CmdArgs.push_back("-lrt"); + break; + case Driver::OMPRT_IOMP5: + CmdArgs.push_back("-liomp5"); + break; + case Driver::OMPRT_Unknown: + // Already diagnosed. + break; + } + if (JA.isHostOffloading(Action::OFK_OpenMP)) + CmdArgs.push_back("-lomptarget"); + + addArchSpecificRPath(ToolChain, Args, CmdArgs); + } + + AddRunTimeLibs(ToolChain, D, CmdArgs, Args); + + if (WantPthread && !isAndroid) + CmdArgs.push_back("-lpthread"); + + if (Args.hasArg(options::OPT_fsplit_stack)) + CmdArgs.push_back("--wrap=pthread_create"); + + CmdArgs.push_back("-lc"); + + // Add IAMCU specific libs, if needed. + if (IsIAMCU) + CmdArgs.push_back("-lgloss"); + + if (Args.hasArg(options::OPT_static)) + CmdArgs.push_back("--end-group"); + else + AddRunTimeLibs(ToolChain, D, CmdArgs, Args); + + // Add IAMCU specific libs (outside the group), if needed. + if (IsIAMCU) { + CmdArgs.push_back("--as-needed"); + CmdArgs.push_back("-lsoftfp"); + CmdArgs.push_back("--no-as-needed"); + } + } + + if (!Args.hasArg(options::OPT_nostartfiles) && !IsIAMCU) { + const char *crtend; + if (Args.hasArg(options::OPT_shared)) + crtend = isAndroid ? "crtend_so.o" : "crtendS.o"; + else if (IsPIE) + crtend = isAndroid ? "crtend_android.o" : "crtendS.o"; + else + crtend = isAndroid ? "crtend_android.o" : "crtend.o"; + + if (HasCRTBeginEndFiles) + CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crtend))); + if (!isAndroid) + CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtn.o"))); + } + } + + // Add OpenMP offloading linker script args if required. + AddOpenMPLinkerScript(getToolChain(), C, Output, Inputs, Args, CmdArgs, JA); + + C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); +} + +void tools::gnutools::Assembler::ConstructJob(Compilation &C, + const JobAction &JA, + const InputInfo &Output, + const InputInfoList &Inputs, + const ArgList &Args, + const char *LinkingOutput) const { + claimNoWarnArgs(Args); + + ArgStringList CmdArgs; + + llvm::Reloc::Model RelocationModel; + unsigned PICLevel; + bool IsPIE; + std::tie(RelocationModel, PICLevel, IsPIE) = + ParsePICArgs(getToolChain(), Args); + + switch (getToolChain().getArch()) { + default: + break; + // Add --32/--64 to make sure we get the format we want. + // This is incomplete + case llvm::Triple::x86: + CmdArgs.push_back("--32"); + break; + case llvm::Triple::x86_64: + if (getToolChain().getTriple().getEnvironment() == llvm::Triple::GNUX32) + CmdArgs.push_back("--x32"); + else + CmdArgs.push_back("--64"); + break; + case llvm::Triple::ppc: + CmdArgs.push_back("-a32"); + CmdArgs.push_back("-mppc"); + CmdArgs.push_back("-many"); + break; + case llvm::Triple::ppc64: + CmdArgs.push_back("-a64"); + CmdArgs.push_back("-mppc64"); + CmdArgs.push_back("-many"); + break; + case llvm::Triple::ppc64le: + CmdArgs.push_back("-a64"); + CmdArgs.push_back("-mppc64"); + CmdArgs.push_back("-many"); + CmdArgs.push_back("-mlittle-endian"); + break; + case llvm::Triple::sparc: + case llvm::Triple::sparcel: { + CmdArgs.push_back("-32"); + std::string CPU = getCPUName(Args, getToolChain().getTriple()); + CmdArgs.push_back(sparc::getSparcAsmModeForCPU(CPU, getToolChain().getTriple())); + AddAssemblerKPIC(getToolChain(), Args, CmdArgs); + break; + } + case llvm::Triple::sparcv9: { + CmdArgs.push_back("-64"); + std::string CPU = getCPUName(Args, getToolChain().getTriple()); + CmdArgs.push_back(sparc::getSparcAsmModeForCPU(CPU, getToolChain().getTriple())); + AddAssemblerKPIC(getToolChain(), Args, CmdArgs); + break; + } + case llvm::Triple::arm: + case llvm::Triple::armeb: + case llvm::Triple::thumb: + case llvm::Triple::thumbeb: { + const llvm::Triple &Triple2 = getToolChain().getTriple(); + switch (Triple2.getSubArch()) { + case llvm::Triple::ARMSubArch_v7: + CmdArgs.push_back("-mfpu=neon"); + break; + case llvm::Triple::ARMSubArch_v8: + CmdArgs.push_back("-mfpu=crypto-neon-fp-armv8"); + break; + default: + break; + } + + switch (arm::getARMFloatABI(getToolChain(), Args)) { + case arm::FloatABI::Invalid: llvm_unreachable("must have an ABI!"); + case arm::FloatABI::Soft: + CmdArgs.push_back(Args.MakeArgString("-mfloat-abi=soft")); + break; + case arm::FloatABI::SoftFP: + CmdArgs.push_back(Args.MakeArgString("-mfloat-abi=softfp")); + break; + case arm::FloatABI::Hard: + CmdArgs.push_back(Args.MakeArgString("-mfloat-abi=hard")); + break; + } + + Args.AddLastArg(CmdArgs, options::OPT_march_EQ); + + // FIXME: remove krait check when GNU tools support krait cpu + // for now replace it with -mcpu=cortex-a15 to avoid a lower + // march from being picked in the absence of a cpu flag. + Arg *A; + if ((A = Args.getLastArg(options::OPT_mcpu_EQ)) && + StringRef(A->getValue()).equals_lower("krait")) + CmdArgs.push_back("-mcpu=cortex-a15"); + else + Args.AddLastArg(CmdArgs, options::OPT_mcpu_EQ); + Args.AddLastArg(CmdArgs, options::OPT_mfpu_EQ); + break; + } + case llvm::Triple::mips: + case llvm::Triple::mipsel: + case llvm::Triple::mips64: + case llvm::Triple::mips64el: { + StringRef CPUName; + StringRef ABIName; + mips::getMipsCPUAndABI(Args, getToolChain().getTriple(), CPUName, ABIName); + ABIName = mips::getGnuCompatibleMipsABIName(ABIName); + + CmdArgs.push_back("-march"); + CmdArgs.push_back(CPUName.data()); + + CmdArgs.push_back("-mabi"); + CmdArgs.push_back(ABIName.data()); + + // -mno-shared should be emitted unless -fpic, -fpie, -fPIC, -fPIE, + // or -mshared (not implemented) is in effect. + if (RelocationModel == llvm::Reloc::Static) + CmdArgs.push_back("-mno-shared"); + + // LLVM doesn't support -mplt yet and acts as if it is always given. + // However, -mplt has no effect with the N64 ABI. + if (ABIName != "64" && !Args.hasArg(options::OPT_mno_abicalls)) + CmdArgs.push_back("-call_nonpic"); + + if (getToolChain().getArch() == llvm::Triple::mips || + getToolChain().getArch() == llvm::Triple::mips64) + CmdArgs.push_back("-EB"); + else + CmdArgs.push_back("-EL"); + + if (Arg *A = Args.getLastArg(options::OPT_mnan_EQ)) { + if (StringRef(A->getValue()) == "2008") + CmdArgs.push_back(Args.MakeArgString("-mnan=2008")); + } + + // Add the last -mfp32/-mfpxx/-mfp64 or -mfpxx if it is enabled by default. + if (Arg *A = Args.getLastArg(options::OPT_mfp32, options::OPT_mfpxx, + options::OPT_mfp64)) { + A->claim(); + A->render(Args, CmdArgs); + } else if (mips::shouldUseFPXX( + Args, getToolChain().getTriple(), CPUName, ABIName, + mips::getMipsFloatABI(getToolChain().getDriver(), Args))) + CmdArgs.push_back("-mfpxx"); + + // Pass on -mmips16 or -mno-mips16. However, the assembler equivalent of + // -mno-mips16 is actually -no-mips16. + if (Arg *A = + Args.getLastArg(options::OPT_mips16, options::OPT_mno_mips16)) { + if (A->getOption().matches(options::OPT_mips16)) { + A->claim(); + A->render(Args, CmdArgs); + } else { + A->claim(); + CmdArgs.push_back("-no-mips16"); + } + } + + Args.AddLastArg(CmdArgs, options::OPT_mmicromips, + options::OPT_mno_micromips); + Args.AddLastArg(CmdArgs, options::OPT_mdsp, options::OPT_mno_dsp); + Args.AddLastArg(CmdArgs, options::OPT_mdspr2, options::OPT_mno_dspr2); + + if (Arg *A = Args.getLastArg(options::OPT_mmsa, options::OPT_mno_msa)) { + // Do not use AddLastArg because not all versions of MIPS assembler + // support -mmsa / -mno-msa options. + if (A->getOption().matches(options::OPT_mmsa)) + CmdArgs.push_back(Args.MakeArgString("-mmsa")); + } + + Args.AddLastArg(CmdArgs, options::OPT_mhard_float, + options::OPT_msoft_float); + + Args.AddLastArg(CmdArgs, options::OPT_mdouble_float, + options::OPT_msingle_float); + + Args.AddLastArg(CmdArgs, options::OPT_modd_spreg, + options::OPT_mno_odd_spreg); + + AddAssemblerKPIC(getToolChain(), Args, CmdArgs); + break; + } + case llvm::Triple::systemz: { + // Always pass an -march option, since our default of z10 is later + // than the GNU assembler's default. + StringRef CPUName = systemz::getSystemZTargetCPU(Args); + CmdArgs.push_back(Args.MakeArgString("-march=" + CPUName)); + break; + } + } + + Args.AddAllArgs(CmdArgs, options::OPT_I); + Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler); + + CmdArgs.push_back("-o"); + CmdArgs.push_back(Output.getFilename()); + + for (const auto &II : Inputs) + CmdArgs.push_back(II.getFilename()); + + const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("as")); + C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); + + // Handle the debug info splitting at object creation time if we're + // creating an object. + // TODO: Currently only works on linux with newer objcopy. + if (Args.hasArg(options::OPT_gsplit_dwarf) && + getToolChain().getTriple().isOSLinux()) + SplitDebugInfo(getToolChain(), C, *this, JA, Args, Output, + SplitDebugName(Args, Inputs[0])); +} + +namespace { +// Filter to remove Multilibs that don't exist as a suffix to Path +class FilterNonExistent { + StringRef Base, File; + vfs::FileSystem &VFS; + +public: + FilterNonExistent(StringRef Base, StringRef File, vfs::FileSystem &VFS) + : Base(Base), File(File), VFS(VFS) {} + bool operator()(const Multilib &M) { + return !VFS.exists(Base + M.gccSuffix() + File); + } +}; +} // end anonymous namespace + +static bool isSoftFloatABI(const ArgList &Args) { + Arg *A = Args.getLastArg(options::OPT_msoft_float, options::OPT_mhard_float, + options::OPT_mfloat_abi_EQ); + if (!A) + return false; + + return A->getOption().matches(options::OPT_msoft_float) || + (A->getOption().matches(options::OPT_mfloat_abi_EQ) && + A->getValue() == StringRef("soft")); +} + +static void addMultilibFlag(bool Enabled, const char *const Flag, + std::vector<std::string> &Flags) { + if (Enabled) + Flags.push_back(std::string("+") + Flag); + else + Flags.push_back(std::string("-") + Flag); +} + +static bool isArmOrThumbArch(llvm::Triple::ArchType Arch) { + return Arch == llvm::Triple::arm || Arch == llvm::Triple::thumb; +} + +static bool isMips32(llvm::Triple::ArchType Arch) { + return Arch == llvm::Triple::mips || Arch == llvm::Triple::mipsel; +} + +static bool isMips64(llvm::Triple::ArchType Arch) { + return Arch == llvm::Triple::mips64 || Arch == llvm::Triple::mips64el; +} + +static bool isMipsEL(llvm::Triple::ArchType Arch) { + return Arch == llvm::Triple::mipsel || Arch == llvm::Triple::mips64el; +} + +static bool isMips16(const ArgList &Args) { + Arg *A = Args.getLastArg(options::OPT_mips16, options::OPT_mno_mips16); + return A && A->getOption().matches(options::OPT_mips16); +} + +static bool isMicroMips(const ArgList &Args) { + Arg *A = Args.getLastArg(options::OPT_mmicromips, options::OPT_mno_micromips); + return A && A->getOption().matches(options::OPT_mmicromips); +} + +static Multilib makeMultilib(StringRef commonSuffix) { + return Multilib(commonSuffix, commonSuffix, commonSuffix); +} + +static bool findMipsCsMultilibs(const Multilib::flags_list &Flags, + FilterNonExistent &NonExistent, + DetectedMultilibs &Result) { + // Check for Code Sourcery toolchain multilibs + MultilibSet CSMipsMultilibs; + { + auto MArchMips16 = makeMultilib("/mips16").flag("+m32").flag("+mips16"); + + auto MArchMicroMips = + makeMultilib("/micromips").flag("+m32").flag("+mmicromips"); + + auto MArchDefault = makeMultilib("").flag("-mips16").flag("-mmicromips"); + + auto UCLibc = makeMultilib("/uclibc").flag("+muclibc"); + + auto SoftFloat = makeMultilib("/soft-float").flag("+msoft-float"); + + auto Nan2008 = makeMultilib("/nan2008").flag("+mnan=2008"); + + auto DefaultFloat = + makeMultilib("").flag("-msoft-float").flag("-mnan=2008"); + + auto BigEndian = makeMultilib("").flag("+EB").flag("-EL"); + + auto LittleEndian = makeMultilib("/el").flag("+EL").flag("-EB"); + + // Note that this one's osSuffix is "" + auto MAbi64 = makeMultilib("") + .gccSuffix("/64") + .includeSuffix("/64") + .flag("+mabi=n64") + .flag("-mabi=n32") + .flag("-m32"); + + CSMipsMultilibs = + MultilibSet() + .Either(MArchMips16, MArchMicroMips, MArchDefault) + .Maybe(UCLibc) + .Either(SoftFloat, Nan2008, DefaultFloat) + .FilterOut("/micromips/nan2008") + .FilterOut("/mips16/nan2008") + .Either(BigEndian, LittleEndian) + .Maybe(MAbi64) + .FilterOut("/mips16.*/64") + .FilterOut("/micromips.*/64") + .FilterOut(NonExistent) + .setIncludeDirsCallback([](const Multilib &M) { + std::vector<std::string> Dirs({"/include"}); + if (StringRef(M.includeSuffix()).startswith("/uclibc")) + Dirs.push_back( + "/../../../../mips-linux-gnu/libc/uclibc/usr/include"); + else + Dirs.push_back("/../../../../mips-linux-gnu/libc/usr/include"); + return Dirs; + }); + } + + MultilibSet DebianMipsMultilibs; + { + Multilib MAbiN32 = + Multilib().gccSuffix("/n32").includeSuffix("/n32").flag("+mabi=n32"); + + Multilib M64 = Multilib() + .gccSuffix("/64") + .includeSuffix("/64") + .flag("+m64") + .flag("-m32") + .flag("-mabi=n32"); + + Multilib M32 = Multilib().flag("-m64").flag("+m32").flag("-mabi=n32"); + + DebianMipsMultilibs = + MultilibSet().Either(M32, M64, MAbiN32).FilterOut(NonExistent); + } + + // Sort candidates. Toolchain that best meets the directories tree goes first. + // Then select the first toolchains matches command line flags. + MultilibSet *Candidates[] = {&CSMipsMultilibs, &DebianMipsMultilibs}; + if (CSMipsMultilibs.size() < DebianMipsMultilibs.size()) + std::iter_swap(Candidates, Candidates + 1); + for (const MultilibSet *Candidate : Candidates) { + if (Candidate->select(Flags, Result.SelectedMultilib)) { + if (Candidate == &DebianMipsMultilibs) + Result.BiarchSibling = Multilib(); + Result.Multilibs = *Candidate; + return true; + } + } + return false; +} + +static bool findMipsAndroidMultilibs(vfs::FileSystem &VFS, StringRef Path, + const Multilib::flags_list &Flags, + FilterNonExistent &NonExistent, + DetectedMultilibs &Result) { + + MultilibSet AndroidMipsMultilibs = + MultilibSet() + .Maybe(Multilib("/mips-r2").flag("+march=mips32r2")) + .Maybe(Multilib("/mips-r6").flag("+march=mips32r6")) + .FilterOut(NonExistent); + + MultilibSet AndroidMipselMultilibs = + MultilibSet() + .Either(Multilib().flag("+march=mips32"), + Multilib("/mips-r2", "", "/mips-r2").flag("+march=mips32r2"), + Multilib("/mips-r6", "", "/mips-r6").flag("+march=mips32r6")) + .FilterOut(NonExistent); + + MultilibSet AndroidMips64elMultilibs = + MultilibSet() + .Either( + Multilib().flag("+march=mips64r6"), + Multilib("/32/mips-r1", "", "/mips-r1").flag("+march=mips32"), + Multilib("/32/mips-r2", "", "/mips-r2").flag("+march=mips32r2"), + Multilib("/32/mips-r6", "", "/mips-r6").flag("+march=mips32r6")) + .FilterOut(NonExistent); + + MultilibSet *MS = &AndroidMipsMultilibs; + if (VFS.exists(Path + "/mips-r6")) + MS = &AndroidMipselMultilibs; + else if (VFS.exists(Path + "/32")) + MS = &AndroidMips64elMultilibs; + if (MS->select(Flags, Result.SelectedMultilib)) { + Result.Multilibs = *MS; + return true; + } + return false; +} + +static bool findMipsMuslMultilibs(const Multilib::flags_list &Flags, + FilterNonExistent &NonExistent, + DetectedMultilibs &Result) { + // Musl toolchain multilibs + MultilibSet MuslMipsMultilibs; + { + auto MArchMipsR2 = makeMultilib("") + .osSuffix("/mips-r2-hard-musl") + .flag("+EB") + .flag("-EL") + .flag("+march=mips32r2"); + + auto MArchMipselR2 = makeMultilib("/mipsel-r2-hard-musl") + .flag("-EB") + .flag("+EL") + .flag("+march=mips32r2"); + + MuslMipsMultilibs = MultilibSet().Either(MArchMipsR2, MArchMipselR2); + + // Specify the callback that computes the include directories. + MuslMipsMultilibs.setIncludeDirsCallback([](const Multilib &M) { + return std::vector<std::string>( + {"/../sysroot" + M.osSuffix() + "/usr/include"}); + }); + } + if (MuslMipsMultilibs.select(Flags, Result.SelectedMultilib)) { + Result.Multilibs = MuslMipsMultilibs; + return true; + } + return false; +} + +static bool findMipsMtiMultilibs(const Multilib::flags_list &Flags, + FilterNonExistent &NonExistent, + DetectedMultilibs &Result) { + // CodeScape MTI toolchain v1.2 and early. + MultilibSet MtiMipsMultilibsV1; + { + auto MArchMips32 = makeMultilib("/mips32") + .flag("+m32") + .flag("-m64") + .flag("-mmicromips") + .flag("+march=mips32"); + + auto MArchMicroMips = makeMultilib("/micromips") + .flag("+m32") + .flag("-m64") + .flag("+mmicromips"); + + auto MArchMips64r2 = makeMultilib("/mips64r2") + .flag("-m32") + .flag("+m64") + .flag("+march=mips64r2"); + + auto MArchMips64 = makeMultilib("/mips64").flag("-m32").flag("+m64").flag( + "-march=mips64r2"); + + auto MArchDefault = makeMultilib("") + .flag("+m32") + .flag("-m64") + .flag("-mmicromips") + .flag("+march=mips32r2"); + + auto Mips16 = makeMultilib("/mips16").flag("+mips16"); + + auto UCLibc = makeMultilib("/uclibc").flag("+muclibc"); + + auto MAbi64 = + makeMultilib("/64").flag("+mabi=n64").flag("-mabi=n32").flag("-m32"); + + auto BigEndian = makeMultilib("").flag("+EB").flag("-EL"); + + auto LittleEndian = makeMultilib("/el").flag("+EL").flag("-EB"); + + auto SoftFloat = makeMultilib("/sof").flag("+msoft-float"); + + auto Nan2008 = makeMultilib("/nan2008").flag("+mnan=2008"); + + MtiMipsMultilibsV1 = + MultilibSet() + .Either(MArchMips32, MArchMicroMips, MArchMips64r2, MArchMips64, + MArchDefault) + .Maybe(UCLibc) + .Maybe(Mips16) + .FilterOut("/mips64/mips16") + .FilterOut("/mips64r2/mips16") + .FilterOut("/micromips/mips16") + .Maybe(MAbi64) + .FilterOut("/micromips/64") + .FilterOut("/mips32/64") + .FilterOut("^/64") + .FilterOut("/mips16/64") + .Either(BigEndian, LittleEndian) + .Maybe(SoftFloat) + .Maybe(Nan2008) + .FilterOut(".*sof/nan2008") + .FilterOut(NonExistent) + .setIncludeDirsCallback([](const Multilib &M) { + std::vector<std::string> Dirs({"/include"}); + if (StringRef(M.includeSuffix()).startswith("/uclibc")) + Dirs.push_back("/../../../../sysroot/uclibc/usr/include"); + else + Dirs.push_back("/../../../../sysroot/usr/include"); + return Dirs; + }); + } + + // CodeScape IMG toolchain starting from v1.3. + MultilibSet MtiMipsMultilibsV2; + { + auto BeHard = makeMultilib("/mips-r2-hard") + .flag("+EB") + .flag("-msoft-float") + .flag("-mnan=2008") + .flag("-muclibc"); + auto BeSoft = makeMultilib("/mips-r2-soft") + .flag("+EB") + .flag("+msoft-float") + .flag("-mnan=2008"); + auto ElHard = makeMultilib("/mipsel-r2-hard") + .flag("+EL") + .flag("-msoft-float") + .flag("-mnan=2008") + .flag("-muclibc"); + auto ElSoft = makeMultilib("/mipsel-r2-soft") + .flag("+EL") + .flag("+msoft-float") + .flag("-mnan=2008") + .flag("-mmicromips"); + auto BeHardNan = makeMultilib("/mips-r2-hard-nan2008") + .flag("+EB") + .flag("-msoft-float") + .flag("+mnan=2008") + .flag("-muclibc"); + auto ElHardNan = makeMultilib("/mipsel-r2-hard-nan2008") + .flag("+EL") + .flag("-msoft-float") + .flag("+mnan=2008") + .flag("-muclibc") + .flag("-mmicromips"); + auto BeHardNanUclibc = makeMultilib("/mips-r2-hard-nan2008-uclibc") + .flag("+EB") + .flag("-msoft-float") + .flag("+mnan=2008") + .flag("+muclibc"); + auto ElHardNanUclibc = makeMultilib("/mipsel-r2-hard-nan2008-uclibc") + .flag("+EL") + .flag("-msoft-float") + .flag("+mnan=2008") + .flag("+muclibc"); + auto BeHardUclibc = makeMultilib("/mips-r2-hard-uclibc") + .flag("+EB") + .flag("-msoft-float") + .flag("-mnan=2008") + .flag("+muclibc"); + auto ElHardUclibc = makeMultilib("/mipsel-r2-hard-uclibc") + .flag("+EL") + .flag("-msoft-float") + .flag("-mnan=2008") + .flag("+muclibc"); + auto ElMicroHardNan = makeMultilib("/micromipsel-r2-hard-nan2008") + .flag("+EL") + .flag("-msoft-float") + .flag("+mnan=2008") + .flag("+mmicromips"); + auto ElMicroSoft = makeMultilib("/micromipsel-r2-soft") + .flag("+EL") + .flag("+msoft-float") + .flag("-mnan=2008") + .flag("+mmicromips"); + + auto O32 = + makeMultilib("/lib").osSuffix("").flag("-mabi=n32").flag("-mabi=n64"); + auto N32 = + makeMultilib("/lib32").osSuffix("").flag("+mabi=n32").flag("-mabi=n64"); + auto N64 = + makeMultilib("/lib64").osSuffix("").flag("-mabi=n32").flag("+mabi=n64"); + + MtiMipsMultilibsV2 = + MultilibSet() + .Either({BeHard, BeSoft, ElHard, ElSoft, BeHardNan, ElHardNan, + BeHardNanUclibc, ElHardNanUclibc, BeHardUclibc, + ElHardUclibc, ElMicroHardNan, ElMicroSoft}) + .Either(O32, N32, N64) + .FilterOut(NonExistent) + .setIncludeDirsCallback([](const Multilib &M) { + return std::vector<std::string>({"/../../../../sysroot" + + M.includeSuffix() + + "/../usr/include"}); + }) + .setFilePathsCallback([](const Multilib &M) { + return std::vector<std::string>( + {"/../../../../mips-mti-linux-gnu/lib" + M.gccSuffix()}); + }); + } + for (auto Candidate : {&MtiMipsMultilibsV1, &MtiMipsMultilibsV2}) { + if (Candidate->select(Flags, Result.SelectedMultilib)) { + Result.Multilibs = *Candidate; + return true; + } + } + return false; +} + +static bool findMipsImgMultilibs(const Multilib::flags_list &Flags, + FilterNonExistent &NonExistent, + DetectedMultilibs &Result) { + // CodeScape IMG toolchain v1.2 and early. + MultilibSet ImgMultilibsV1; + { + auto Mips64r6 = makeMultilib("/mips64r6").flag("+m64").flag("-m32"); + + auto LittleEndian = makeMultilib("/el").flag("+EL").flag("-EB"); + + auto MAbi64 = + makeMultilib("/64").flag("+mabi=n64").flag("-mabi=n32").flag("-m32"); + + ImgMultilibsV1 = + MultilibSet() + .Maybe(Mips64r6) + .Maybe(MAbi64) + .Maybe(LittleEndian) + .FilterOut(NonExistent) + .setIncludeDirsCallback([](const Multilib &M) { + return std::vector<std::string>( + {"/include", "/../../../../sysroot/usr/include"}); + }); + } + + // CodeScape IMG toolchain starting from v1.3. + MultilibSet ImgMultilibsV2; + { + auto BeHard = makeMultilib("/mips-r6-hard") + .flag("+EB") + .flag("-msoft-float") + .flag("-mmicromips"); + auto BeSoft = makeMultilib("/mips-r6-soft") + .flag("+EB") + .flag("+msoft-float") + .flag("-mmicromips"); + auto ElHard = makeMultilib("/mipsel-r6-hard") + .flag("+EL") + .flag("-msoft-float") + .flag("-mmicromips"); + auto ElSoft = makeMultilib("/mipsel-r6-soft") + .flag("+EL") + .flag("+msoft-float") + .flag("-mmicromips"); + auto BeMicroHard = makeMultilib("/micromips-r6-hard") + .flag("+EB") + .flag("-msoft-float") + .flag("+mmicromips"); + auto BeMicroSoft = makeMultilib("/micromips-r6-soft") + .flag("+EB") + .flag("+msoft-float") + .flag("+mmicromips"); + auto ElMicroHard = makeMultilib("/micromipsel-r6-hard") + .flag("+EL") + .flag("-msoft-float") + .flag("+mmicromips"); + auto ElMicroSoft = makeMultilib("/micromipsel-r6-soft") + .flag("+EL") + .flag("+msoft-float") + .flag("+mmicromips"); + + auto O32 = + makeMultilib("/lib").osSuffix("").flag("-mabi=n32").flag("-mabi=n64"); + auto N32 = + makeMultilib("/lib32").osSuffix("").flag("+mabi=n32").flag("-mabi=n64"); + auto N64 = + makeMultilib("/lib64").osSuffix("").flag("-mabi=n32").flag("+mabi=n64"); + + ImgMultilibsV2 = + MultilibSet() + .Either({BeHard, BeSoft, ElHard, ElSoft, BeMicroHard, BeMicroSoft, + ElMicroHard, ElMicroSoft}) + .Either(O32, N32, N64) + .FilterOut(NonExistent) + .setIncludeDirsCallback([](const Multilib &M) { + return std::vector<std::string>({"/../../../../sysroot" + + M.includeSuffix() + + "/../usr/include"}); + }) + .setFilePathsCallback([](const Multilib &M) { + return std::vector<std::string>( + {"/../../../../mips-img-linux-gnu/lib" + M.gccSuffix()}); + }); + } + for (auto Candidate : {&ImgMultilibsV1, &ImgMultilibsV2}) { + if (Candidate->select(Flags, Result.SelectedMultilib)) { + Result.Multilibs = *Candidate; + return true; + } + } + return false; +} + +bool clang::driver::findMIPSMultilibs(const Driver &D, + const llvm::Triple &TargetTriple, + StringRef Path, const ArgList &Args, + DetectedMultilibs &Result) { + FilterNonExistent NonExistent(Path, "/crtbegin.o", D.getVFS()); + + StringRef CPUName; + StringRef ABIName; + tools::mips::getMipsCPUAndABI(Args, TargetTriple, CPUName, ABIName); + + llvm::Triple::ArchType TargetArch = TargetTriple.getArch(); + + Multilib::flags_list Flags; + addMultilibFlag(isMips32(TargetArch), "m32", Flags); + addMultilibFlag(isMips64(TargetArch), "m64", Flags); + addMultilibFlag(isMips16(Args), "mips16", Flags); + addMultilibFlag(CPUName == "mips32", "march=mips32", Flags); + addMultilibFlag(CPUName == "mips32r2" || CPUName == "mips32r3" || + CPUName == "mips32r5" || CPUName == "p5600", + "march=mips32r2", Flags); + addMultilibFlag(CPUName == "mips32r6", "march=mips32r6", Flags); + addMultilibFlag(CPUName == "mips64", "march=mips64", Flags); + addMultilibFlag(CPUName == "mips64r2" || CPUName == "mips64r3" || + CPUName == "mips64r5" || CPUName == "octeon", + "march=mips64r2", Flags); + addMultilibFlag(CPUName == "mips64r6", "march=mips64r6", Flags); + addMultilibFlag(isMicroMips(Args), "mmicromips", Flags); + addMultilibFlag(tools::mips::isUCLibc(Args), "muclibc", Flags); + addMultilibFlag(tools::mips::isNaN2008(Args, TargetTriple), "mnan=2008", + Flags); + addMultilibFlag(ABIName == "n32", "mabi=n32", Flags); + addMultilibFlag(ABIName == "n64", "mabi=n64", Flags); + addMultilibFlag(isSoftFloatABI(Args), "msoft-float", Flags); + addMultilibFlag(!isSoftFloatABI(Args), "mhard-float", Flags); + addMultilibFlag(isMipsEL(TargetArch), "EL", Flags); + addMultilibFlag(!isMipsEL(TargetArch), "EB", Flags); + + if (TargetTriple.isAndroid()) + return findMipsAndroidMultilibs(D.getVFS(), Path, Flags, NonExistent, + Result); + + if (TargetTriple.getVendor() == llvm::Triple::MipsTechnologies && + TargetTriple.getOS() == llvm::Triple::Linux && + TargetTriple.getEnvironment() == llvm::Triple::UnknownEnvironment) + return findMipsMuslMultilibs(Flags, NonExistent, Result); + + if (TargetTriple.getVendor() == llvm::Triple::MipsTechnologies && + TargetTriple.getOS() == llvm::Triple::Linux && + TargetTriple.getEnvironment() == llvm::Triple::GNU) + return findMipsMtiMultilibs(Flags, NonExistent, Result); + + if (TargetTriple.getVendor() == llvm::Triple::ImaginationTechnologies && + TargetTriple.getOS() == llvm::Triple::Linux && + TargetTriple.getEnvironment() == llvm::Triple::GNU) + return findMipsImgMultilibs(Flags, NonExistent, Result); + + if (findMipsCsMultilibs(Flags, NonExistent, Result)) + return true; + + // Fallback to the regular toolchain-tree structure. + Multilib Default; + Result.Multilibs.push_back(Default); + Result.Multilibs.FilterOut(NonExistent); + + if (Result.Multilibs.select(Flags, Result.SelectedMultilib)) { + Result.BiarchSibling = Multilib(); + return true; + } + + return false; +} + +static void findAndroidArmMultilibs(const Driver &D, + const llvm::Triple &TargetTriple, + StringRef Path, const ArgList &Args, + DetectedMultilibs &Result) { + // Find multilibs with subdirectories like armv7-a, thumb, armv7-a/thumb. + FilterNonExistent NonExistent(Path, "/crtbegin.o", D.getVFS()); + Multilib ArmV7Multilib = makeMultilib("/armv7-a") + .flag("+armv7") + .flag("-thumb"); + Multilib ThumbMultilib = makeMultilib("/thumb") + .flag("-armv7") + .flag("+thumb"); + Multilib ArmV7ThumbMultilib = makeMultilib("/armv7-a/thumb") + .flag("+armv7") + .flag("+thumb"); + Multilib DefaultMultilib = makeMultilib("") + .flag("-armv7") + .flag("-thumb"); + MultilibSet AndroidArmMultilibs = + MultilibSet() + .Either(ThumbMultilib, ArmV7Multilib, + ArmV7ThumbMultilib, DefaultMultilib) + .FilterOut(NonExistent); + + Multilib::flags_list Flags; + llvm::StringRef Arch = Args.getLastArgValue(options::OPT_march_EQ); + bool IsArmArch = TargetTriple.getArch() == llvm::Triple::arm; + bool IsThumbArch = TargetTriple.getArch() == llvm::Triple::thumb; + bool IsV7SubArch = TargetTriple.getSubArch() == llvm::Triple::ARMSubArch_v7; + bool IsThumbMode = IsThumbArch || + Args.hasFlag(options::OPT_mthumb, options::OPT_mno_thumb, false) || + (IsArmArch && llvm::ARM::parseArchISA(Arch) == llvm::ARM::IK_THUMB); + bool IsArmV7Mode = (IsArmArch || IsThumbArch) && + (llvm::ARM::parseArchVersion(Arch) == 7 || + (IsArmArch && Arch == "" && IsV7SubArch)); + addMultilibFlag(IsArmV7Mode, "armv7", Flags); + addMultilibFlag(IsThumbMode, "thumb", Flags); + + if (AndroidArmMultilibs.select(Flags, Result.SelectedMultilib)) + Result.Multilibs = AndroidArmMultilibs; +} + +static bool findBiarchMultilibs(const Driver &D, + const llvm::Triple &TargetTriple, + StringRef Path, const ArgList &Args, + bool NeedsBiarchSuffix, + DetectedMultilibs &Result) { + // Some versions of SUSE and Fedora on ppc64 put 32-bit libs + // in what would normally be GCCInstallPath and put the 64-bit + // libs in a subdirectory named 64. The simple logic we follow is that + // *if* there is a subdirectory of the right name with crtbegin.o in it, + // we use that. If not, and if not a biarch triple alias, we look for + // crtbegin.o without the subdirectory. + + Multilib Default; + Multilib Alt64 = Multilib() + .gccSuffix("/64") + .includeSuffix("/64") + .flag("-m32") + .flag("+m64") + .flag("-mx32"); + Multilib Alt32 = Multilib() + .gccSuffix("/32") + .includeSuffix("/32") + .flag("+m32") + .flag("-m64") + .flag("-mx32"); + Multilib Altx32 = Multilib() + .gccSuffix("/x32") + .includeSuffix("/x32") + .flag("-m32") + .flag("-m64") + .flag("+mx32"); + + // GCC toolchain for IAMCU doesn't have crtbegin.o, so look for libgcc.a. + FilterNonExistent NonExistent( + Path, TargetTriple.isOSIAMCU() ? "/libgcc.a" : "/crtbegin.o", D.getVFS()); + + // Determine default multilib from: 32, 64, x32 + // Also handle cases such as 64 on 32, 32 on 64, etc. + enum { UNKNOWN, WANT32, WANT64, WANTX32 } Want = UNKNOWN; + const bool IsX32 = TargetTriple.getEnvironment() == llvm::Triple::GNUX32; + if (TargetTriple.isArch32Bit() && !NonExistent(Alt32)) + Want = WANT64; + else if (TargetTriple.isArch64Bit() && IsX32 && !NonExistent(Altx32)) + Want = WANT64; + else if (TargetTriple.isArch64Bit() && !IsX32 && !NonExistent(Alt64)) + Want = WANT32; + else { + if (TargetTriple.isArch32Bit()) + Want = NeedsBiarchSuffix ? WANT64 : WANT32; + else if (IsX32) + Want = NeedsBiarchSuffix ? WANT64 : WANTX32; + else + Want = NeedsBiarchSuffix ? WANT32 : WANT64; + } + + if (Want == WANT32) + Default.flag("+m32").flag("-m64").flag("-mx32"); + else if (Want == WANT64) + Default.flag("-m32").flag("+m64").flag("-mx32"); + else if (Want == WANTX32) + Default.flag("-m32").flag("-m64").flag("+mx32"); + else + return false; + + Result.Multilibs.push_back(Default); + Result.Multilibs.push_back(Alt64); + Result.Multilibs.push_back(Alt32); + Result.Multilibs.push_back(Altx32); + + Result.Multilibs.FilterOut(NonExistent); + + Multilib::flags_list Flags; + addMultilibFlag(TargetTriple.isArch64Bit() && !IsX32, "m64", Flags); + addMultilibFlag(TargetTriple.isArch32Bit(), "m32", Flags); + addMultilibFlag(TargetTriple.isArch64Bit() && IsX32, "mx32", Flags); + + if (!Result.Multilibs.select(Flags, Result.SelectedMultilib)) + return false; + + if (Result.SelectedMultilib == Alt64 || Result.SelectedMultilib == Alt32 || + Result.SelectedMultilib == Altx32) + Result.BiarchSibling = Default; + + return true; +} + +/// Generic_GCC - A tool chain using the 'gcc' command to perform +/// all subcommands; this relies on gcc translating the majority of +/// command line options. + +/// \brief Less-than for GCCVersion, implementing a Strict Weak Ordering. +bool Generic_GCC::GCCVersion::isOlderThan(int RHSMajor, int RHSMinor, + int RHSPatch, + StringRef RHSPatchSuffix) const { + if (Major != RHSMajor) + return Major < RHSMajor; + if (Minor != RHSMinor) + return Minor < RHSMinor; + if (Patch != RHSPatch) { + // Note that versions without a specified patch sort higher than those with + // a patch. + if (RHSPatch == -1) + return true; + if (Patch == -1) + return false; + + // Otherwise just sort on the patch itself. + return Patch < RHSPatch; + } + if (PatchSuffix != RHSPatchSuffix) { + // Sort empty suffixes higher. + if (RHSPatchSuffix.empty()) + return true; + if (PatchSuffix.empty()) + return false; + + // Provide a lexicographic sort to make this a total ordering. + return PatchSuffix < RHSPatchSuffix; + } + + // The versions are equal. + return false; +} + +static llvm::StringRef getGCCToolchainDir(const ArgList &Args) { + const Arg *A = Args.getLastArg(clang::driver::options::OPT_gcc_toolchain); + if (A) + return A->getValue(); + return GCC_INSTALL_PREFIX; +} + +/// \brief Initialize a GCCInstallationDetector from the driver. +/// +/// This performs all of the autodetection and sets up the various paths. +/// Once constructed, a GCCInstallationDetector is essentially immutable. +/// +/// FIXME: We shouldn't need an explicit TargetTriple parameter here, and +/// should instead pull the target out of the driver. This is currently +/// necessary because the driver doesn't store the final version of the target +/// triple. +void Generic_GCC::GCCInstallationDetector::init( + const llvm::Triple &TargetTriple, const ArgList &Args, + ArrayRef<std::string> ExtraTripleAliases) { + llvm::Triple BiarchVariantTriple = TargetTriple.isArch32Bit() + ? TargetTriple.get64BitArchVariant() + : TargetTriple.get32BitArchVariant(); + // The library directories which may contain GCC installations. + SmallVector<StringRef, 4> CandidateLibDirs, CandidateBiarchLibDirs; + // The compatible GCC triples for this particular architecture. + SmallVector<StringRef, 16> CandidateTripleAliases; + SmallVector<StringRef, 16> CandidateBiarchTripleAliases; + CollectLibDirsAndTriples(TargetTriple, BiarchVariantTriple, CandidateLibDirs, + CandidateTripleAliases, CandidateBiarchLibDirs, + CandidateBiarchTripleAliases); + + // Compute the set of prefixes for our search. + SmallVector<std::string, 8> Prefixes(D.PrefixDirs.begin(), + D.PrefixDirs.end()); + + StringRef GCCToolchainDir = getGCCToolchainDir(Args); + if (GCCToolchainDir != "") { + if (GCCToolchainDir.back() == '/') + GCCToolchainDir = GCCToolchainDir.drop_back(); // remove the / + + Prefixes.push_back(GCCToolchainDir); + } else { + // If we have a SysRoot, try that first. + if (!D.SysRoot.empty()) { + Prefixes.push_back(D.SysRoot); + Prefixes.push_back(D.SysRoot + "/usr"); + } + + // Then look for gcc installed alongside clang. + Prefixes.push_back(D.InstalledDir + "/.."); + + // Then look for distribution supplied gcc installations. + if (D.SysRoot.empty()) { + // Look for RHEL devtoolsets. + Prefixes.push_back("/opt/rh/devtoolset-6/root/usr"); + Prefixes.push_back("/opt/rh/devtoolset-4/root/usr"); + Prefixes.push_back("/opt/rh/devtoolset-3/root/usr"); + Prefixes.push_back("/opt/rh/devtoolset-2/root/usr"); + // And finally in /usr. + Prefixes.push_back("/usr"); + } + } + + // Try to respect gcc-config on Gentoo. However, do that only + // if --gcc-toolchain is not provided or equal to the Gentoo install + // in /usr. This avoids accidentally enforcing the system GCC version + // when using a custom toolchain. + if (GCCToolchainDir == "" || GCCToolchainDir == D.SysRoot + "/usr") { + for (StringRef CandidateTriple : ExtraTripleAliases) { + if (ScanGentooGccConfig(TargetTriple, Args, CandidateTriple)) + return; + } + for (StringRef CandidateTriple : CandidateTripleAliases) { + if (ScanGentooGccConfig(TargetTriple, Args, CandidateTriple)) + return; + } + for (StringRef CandidateTriple : CandidateBiarchTripleAliases) { + if (ScanGentooGccConfig(TargetTriple, Args, CandidateTriple, true)) + return; + } + } + + // Loop over the various components which exist and select the best GCC + // installation available. GCC installs are ranked by version number. + Version = GCCVersion::Parse("0.0.0"); + for (const std::string &Prefix : Prefixes) { + if (!D.getVFS().exists(Prefix)) + continue; + for (StringRef Suffix : CandidateLibDirs) { + const std::string LibDir = Prefix + Suffix.str(); + if (!D.getVFS().exists(LibDir)) + continue; + for (StringRef Candidate : ExtraTripleAliases) // Try these first. + ScanLibDirForGCCTriple(TargetTriple, Args, LibDir, Candidate); + for (StringRef Candidate : CandidateTripleAliases) + ScanLibDirForGCCTriple(TargetTriple, Args, LibDir, Candidate); + } + for (StringRef Suffix : CandidateBiarchLibDirs) { + const std::string LibDir = Prefix + Suffix.str(); + if (!D.getVFS().exists(LibDir)) + continue; + for (StringRef Candidate : CandidateBiarchTripleAliases) + ScanLibDirForGCCTriple(TargetTriple, Args, LibDir, Candidate, + /*NeedsBiarchSuffix=*/ true); + } + } +} + +void Generic_GCC::GCCInstallationDetector::print(raw_ostream &OS) const { + for (const auto &InstallPath : CandidateGCCInstallPaths) + OS << "Found candidate GCC installation: " << InstallPath << "\n"; + + if (!GCCInstallPath.empty()) + OS << "Selected GCC installation: " << GCCInstallPath << "\n"; + + for (const auto &Multilib : Multilibs) + OS << "Candidate multilib: " << Multilib << "\n"; + + if (Multilibs.size() != 0 || !SelectedMultilib.isDefault()) + OS << "Selected multilib: " << SelectedMultilib << "\n"; +} + +bool Generic_GCC::GCCInstallationDetector::getBiarchSibling(Multilib &M) const { + if (BiarchSibling.hasValue()) { + M = BiarchSibling.getValue(); + return true; + } + return false; +} + +/*static*/ void Generic_GCC::GCCInstallationDetector::CollectLibDirsAndTriples( + const llvm::Triple &TargetTriple, const llvm::Triple &BiarchTriple, + SmallVectorImpl<StringRef> &LibDirs, + SmallVectorImpl<StringRef> &TripleAliases, + SmallVectorImpl<StringRef> &BiarchLibDirs, + SmallVectorImpl<StringRef> &BiarchTripleAliases) { + // Declare a bunch of static data sets that we'll select between below. These + // are specifically designed to always refer to string literals to avoid any + // lifetime or initialization issues. + static const char *const AArch64LibDirs[] = {"/lib64", "/lib"}; + static const char *const AArch64Triples[] = { + "aarch64-none-linux-gnu", "aarch64-linux-gnu", "aarch64-linux-android", + "aarch64-redhat-linux", "aarch64-suse-linux"}; + static const char *const AArch64beLibDirs[] = {"/lib"}; + static const char *const AArch64beTriples[] = {"aarch64_be-none-linux-gnu", + "aarch64_be-linux-gnu"}; + + static const char *const ARMLibDirs[] = {"/lib"}; + static const char *const ARMTriples[] = {"arm-linux-gnueabi", + "arm-linux-androideabi"}; + static const char *const ARMHFTriples[] = {"arm-linux-gnueabihf", + "armv7hl-redhat-linux-gnueabi"}; + static const char *const ARMebLibDirs[] = {"/lib"}; + static const char *const ARMebTriples[] = {"armeb-linux-gnueabi", + "armeb-linux-androideabi"}; + static const char *const ARMebHFTriples[] = { + "armeb-linux-gnueabihf", "armebv7hl-redhat-linux-gnueabi"}; + + static const char *const X86_64LibDirs[] = {"/lib64", "/lib"}; + static const char *const X86_64Triples[] = { + "x86_64-linux-gnu", "x86_64-unknown-linux-gnu", + "x86_64-pc-linux-gnu", "x86_64-redhat-linux6E", + "x86_64-redhat-linux", "x86_64-suse-linux", + "x86_64-manbo-linux-gnu", "x86_64-linux-gnu", + "x86_64-slackware-linux", "x86_64-linux-android", + "x86_64-unknown-linux"}; + static const char *const X32LibDirs[] = {"/libx32"}; + static const char *const X86LibDirs[] = {"/lib32", "/lib"}; + static const char *const X86Triples[] = { + "i686-linux-gnu", "i686-pc-linux-gnu", "i486-linux-gnu", + "i386-linux-gnu", "i386-redhat-linux6E", "i686-redhat-linux", + "i586-redhat-linux", "i386-redhat-linux", "i586-suse-linux", + "i486-slackware-linux", "i686-montavista-linux", "i686-linux-android", + "i586-linux-gnu"}; + + static const char *const MIPSLibDirs[] = {"/lib"}; + static const char *const MIPSTriples[] = {"mips-linux-gnu", "mips-mti-linux", + "mips-mti-linux-gnu", + "mips-img-linux-gnu"}; + static const char *const MIPSELLibDirs[] = {"/lib"}; + static const char *const MIPSELTriples[] = {"mipsel-linux-gnu", + "mips-img-linux-gnu"}; + + static const char *const MIPS64LibDirs[] = {"/lib64", "/lib"}; + static const char *const MIPS64Triples[] = { + "mips64-linux-gnu", "mips-mti-linux-gnu", "mips-img-linux-gnu", + "mips64-linux-gnuabi64"}; + static const char *const MIPS64ELLibDirs[] = {"/lib64", "/lib"}; + static const char *const MIPS64ELTriples[] = { + "mips64el-linux-gnu", "mips-mti-linux-gnu", "mips-img-linux-gnu", + "mips64el-linux-gnuabi64"}; + + static const char *const MIPSELAndroidLibDirs[] = {"/lib", "/libr2", + "/libr6"}; + static const char *const MIPSELAndroidTriples[] = {"mipsel-linux-android"}; + static const char *const MIPS64ELAndroidLibDirs[] = {"/lib64", "/lib", + "/libr2", "/libr6"}; + static const char *const MIPS64ELAndroidTriples[] = { + "mips64el-linux-android"}; + + static const char *const PPCLibDirs[] = {"/lib32", "/lib"}; + static const char *const PPCTriples[] = { + "powerpc-linux-gnu", "powerpc-unknown-linux-gnu", "powerpc-linux-gnuspe", + "powerpc-suse-linux", "powerpc-montavista-linuxspe"}; + static const char *const PPC64LibDirs[] = {"/lib64", "/lib"}; + static const char *const PPC64Triples[] = { + "powerpc64-linux-gnu", "powerpc64-unknown-linux-gnu", + "powerpc64-suse-linux", "ppc64-redhat-linux"}; + static const char *const PPC64LELibDirs[] = {"/lib64", "/lib"}; + static const char *const PPC64LETriples[] = { + "powerpc64le-linux-gnu", "powerpc64le-unknown-linux-gnu", + "powerpc64le-suse-linux", "ppc64le-redhat-linux"}; + + static const char *const SPARCv8LibDirs[] = {"/lib32", "/lib"}; + static const char *const SPARCv8Triples[] = {"sparc-linux-gnu", + "sparcv8-linux-gnu"}; + static const char *const SPARCv9LibDirs[] = {"/lib64", "/lib"}; + static const char *const SPARCv9Triples[] = {"sparc64-linux-gnu", + "sparcv9-linux-gnu"}; + + static const char *const SystemZLibDirs[] = {"/lib64", "/lib"}; + static const char *const SystemZTriples[] = { + "s390x-linux-gnu", "s390x-unknown-linux-gnu", "s390x-ibm-linux-gnu", + "s390x-suse-linux", "s390x-redhat-linux"}; + + // Solaris. + static const char *const SolarisSPARCLibDirs[] = {"/gcc"}; + static const char *const SolarisSPARCTriples[] = {"sparc-sun-solaris2.11", + "i386-pc-solaris2.11"}; + + using std::begin; + using std::end; + + if (TargetTriple.getOS() == llvm::Triple::Solaris) { + LibDirs.append(begin(SolarisSPARCLibDirs), end(SolarisSPARCLibDirs)); + TripleAliases.append(begin(SolarisSPARCTriples), end(SolarisSPARCTriples)); + return; + } + + switch (TargetTriple.getArch()) { + case llvm::Triple::aarch64: + LibDirs.append(begin(AArch64LibDirs), end(AArch64LibDirs)); + TripleAliases.append(begin(AArch64Triples), end(AArch64Triples)); + BiarchLibDirs.append(begin(AArch64LibDirs), end(AArch64LibDirs)); + BiarchTripleAliases.append(begin(AArch64Triples), end(AArch64Triples)); + break; + case llvm::Triple::aarch64_be: + LibDirs.append(begin(AArch64beLibDirs), end(AArch64beLibDirs)); + TripleAliases.append(begin(AArch64beTriples), end(AArch64beTriples)); + BiarchLibDirs.append(begin(AArch64beLibDirs), end(AArch64beLibDirs)); + BiarchTripleAliases.append(begin(AArch64beTriples), end(AArch64beTriples)); + break; + case llvm::Triple::arm: + case llvm::Triple::thumb: + LibDirs.append(begin(ARMLibDirs), end(ARMLibDirs)); + if (TargetTriple.getEnvironment() == llvm::Triple::GNUEABIHF) { + TripleAliases.append(begin(ARMHFTriples), end(ARMHFTriples)); + } else { + TripleAliases.append(begin(ARMTriples), end(ARMTriples)); + } + break; + case llvm::Triple::armeb: + case llvm::Triple::thumbeb: + LibDirs.append(begin(ARMebLibDirs), end(ARMebLibDirs)); + if (TargetTriple.getEnvironment() == llvm::Triple::GNUEABIHF) { + TripleAliases.append(begin(ARMebHFTriples), end(ARMebHFTriples)); + } else { + TripleAliases.append(begin(ARMebTriples), end(ARMebTriples)); + } + break; + case llvm::Triple::x86_64: + LibDirs.append(begin(X86_64LibDirs), end(X86_64LibDirs)); + TripleAliases.append(begin(X86_64Triples), end(X86_64Triples)); + // x32 is always available when x86_64 is available, so adding it as + // secondary arch with x86_64 triples + if (TargetTriple.getEnvironment() == llvm::Triple::GNUX32) { + BiarchLibDirs.append(begin(X32LibDirs), end(X32LibDirs)); + BiarchTripleAliases.append(begin(X86_64Triples), end(X86_64Triples)); + } else { + BiarchLibDirs.append(begin(X86LibDirs), end(X86LibDirs)); + BiarchTripleAliases.append(begin(X86Triples), end(X86Triples)); + } + break; + case llvm::Triple::x86: + LibDirs.append(begin(X86LibDirs), end(X86LibDirs)); + // MCU toolchain is 32 bit only and its triple alias is TargetTriple + // itself, which will be appended below. + if (!TargetTriple.isOSIAMCU()) { + TripleAliases.append(begin(X86Triples), end(X86Triples)); + BiarchLibDirs.append(begin(X86_64LibDirs), end(X86_64LibDirs)); + BiarchTripleAliases.append(begin(X86_64Triples), end(X86_64Triples)); + } + break; + case llvm::Triple::mips: + LibDirs.append(begin(MIPSLibDirs), end(MIPSLibDirs)); + TripleAliases.append(begin(MIPSTriples), end(MIPSTriples)); + BiarchLibDirs.append(begin(MIPS64LibDirs), end(MIPS64LibDirs)); + BiarchTripleAliases.append(begin(MIPS64Triples), end(MIPS64Triples)); + break; + case llvm::Triple::mipsel: + if (TargetTriple.isAndroid()) { + LibDirs.append(begin(MIPSELAndroidLibDirs), end(MIPSELAndroidLibDirs)); + TripleAliases.append(begin(MIPSELAndroidTriples), + end(MIPSELAndroidTriples)); + BiarchLibDirs.append(begin(MIPS64ELAndroidLibDirs), + end(MIPS64ELAndroidLibDirs)); + BiarchTripleAliases.append(begin(MIPS64ELAndroidTriples), + end(MIPS64ELAndroidTriples)); + + } else { + LibDirs.append(begin(MIPSELLibDirs), end(MIPSELLibDirs)); + TripleAliases.append(begin(MIPSELTriples), end(MIPSELTriples)); + TripleAliases.append(begin(MIPSTriples), end(MIPSTriples)); + BiarchLibDirs.append(begin(MIPS64ELLibDirs), end(MIPS64ELLibDirs)); + BiarchTripleAliases.append(begin(MIPS64ELTriples), end(MIPS64ELTriples)); + } + break; + case llvm::Triple::mips64: + LibDirs.append(begin(MIPS64LibDirs), end(MIPS64LibDirs)); + TripleAliases.append(begin(MIPS64Triples), end(MIPS64Triples)); + BiarchLibDirs.append(begin(MIPSLibDirs), end(MIPSLibDirs)); + BiarchTripleAliases.append(begin(MIPSTriples), end(MIPSTriples)); + break; + case llvm::Triple::mips64el: + if (TargetTriple.isAndroid()) { + LibDirs.append(begin(MIPS64ELAndroidLibDirs), + end(MIPS64ELAndroidLibDirs)); + TripleAliases.append(begin(MIPS64ELAndroidTriples), + end(MIPS64ELAndroidTriples)); + BiarchLibDirs.append(begin(MIPSELAndroidLibDirs), + end(MIPSELAndroidLibDirs)); + BiarchTripleAliases.append(begin(MIPSELAndroidTriples), + end(MIPSELAndroidTriples)); + + } else { + LibDirs.append(begin(MIPS64ELLibDirs), end(MIPS64ELLibDirs)); + TripleAliases.append(begin(MIPS64ELTriples), end(MIPS64ELTriples)); + BiarchLibDirs.append(begin(MIPSELLibDirs), end(MIPSELLibDirs)); + BiarchTripleAliases.append(begin(MIPSELTriples), end(MIPSELTriples)); + BiarchTripleAliases.append(begin(MIPSTriples), end(MIPSTriples)); + } + break; + case llvm::Triple::ppc: + LibDirs.append(begin(PPCLibDirs), end(PPCLibDirs)); + TripleAliases.append(begin(PPCTriples), end(PPCTriples)); + BiarchLibDirs.append(begin(PPC64LibDirs), end(PPC64LibDirs)); + BiarchTripleAliases.append(begin(PPC64Triples), end(PPC64Triples)); + break; + case llvm::Triple::ppc64: + LibDirs.append(begin(PPC64LibDirs), end(PPC64LibDirs)); + TripleAliases.append(begin(PPC64Triples), end(PPC64Triples)); + BiarchLibDirs.append(begin(PPCLibDirs), end(PPCLibDirs)); + BiarchTripleAliases.append(begin(PPCTriples), end(PPCTriples)); + break; + case llvm::Triple::ppc64le: + LibDirs.append(begin(PPC64LELibDirs), end(PPC64LELibDirs)); + TripleAliases.append(begin(PPC64LETriples), end(PPC64LETriples)); + break; + case llvm::Triple::sparc: + case llvm::Triple::sparcel: + LibDirs.append(begin(SPARCv8LibDirs), end(SPARCv8LibDirs)); + TripleAliases.append(begin(SPARCv8Triples), end(SPARCv8Triples)); + BiarchLibDirs.append(begin(SPARCv9LibDirs), end(SPARCv9LibDirs)); + BiarchTripleAliases.append(begin(SPARCv9Triples), end(SPARCv9Triples)); + break; + case llvm::Triple::sparcv9: + LibDirs.append(begin(SPARCv9LibDirs), end(SPARCv9LibDirs)); + TripleAliases.append(begin(SPARCv9Triples), end(SPARCv9Triples)); + BiarchLibDirs.append(begin(SPARCv8LibDirs), end(SPARCv8LibDirs)); + BiarchTripleAliases.append(begin(SPARCv8Triples), end(SPARCv8Triples)); + break; + case llvm::Triple::systemz: + LibDirs.append(begin(SystemZLibDirs), end(SystemZLibDirs)); + TripleAliases.append(begin(SystemZTriples), end(SystemZTriples)); + break; + default: + // By default, just rely on the standard lib directories and the original + // triple. + break; + } + + // Always append the drivers target triple to the end, in case it doesn't + // match any of our aliases. + TripleAliases.push_back(TargetTriple.str()); + + // Also include the multiarch variant if it's different. + if (TargetTriple.str() != BiarchTriple.str()) + BiarchTripleAliases.push_back(BiarchTriple.str()); +} + +void Generic_GCC::GCCInstallationDetector::scanLibDirForGCCTripleSolaris( + const llvm::Triple &TargetArch, const llvm::opt::ArgList &Args, + const std::string &LibDir, StringRef CandidateTriple, + bool NeedsBiarchSuffix) { + // Solaris is a special case. The GCC installation is under + // /usr/gcc/<major>.<minor>/lib/gcc/<triple>/<major>.<minor>.<patch>/, so we + // need to iterate twice. + std::error_code EC; + for (vfs::directory_iterator LI = D.getVFS().dir_begin(LibDir, EC), LE; + !EC && LI != LE; LI = LI.increment(EC)) { + StringRef VersionText = llvm::sys::path::filename(LI->getName()); + GCCVersion CandidateVersion = GCCVersion::Parse(VersionText); + + if (CandidateVersion.Major != -1) // Filter obviously bad entries. + if (!CandidateGCCInstallPaths.insert(LI->getName()).second) + continue; // Saw this path before; no need to look at it again. + if (CandidateVersion.isOlderThan(4, 1, 1)) + continue; + if (CandidateVersion <= Version) + continue; + + GCCInstallPath = + LibDir + "/" + VersionText.str() + "/lib/gcc/" + CandidateTriple.str(); + if (!D.getVFS().exists(GCCInstallPath)) + continue; + + // If we make it here there has to be at least one GCC version, let's just + // use the latest one. + std::error_code EEC; + for (vfs::directory_iterator + LLI = D.getVFS().dir_begin(GCCInstallPath, EEC), + LLE; + !EEC && LLI != LLE; LLI = LLI.increment(EEC)) { + + StringRef SubVersionText = llvm::sys::path::filename(LLI->getName()); + GCCVersion CandidateSubVersion = GCCVersion::Parse(SubVersionText); + + if (CandidateSubVersion > Version) + Version = CandidateSubVersion; + } + + GCCTriple.setTriple(CandidateTriple); + + GCCInstallPath += "/" + Version.Text; + GCCParentLibPath = GCCInstallPath + "/../../../../"; + + IsValid = true; + } +} + +bool Generic_GCC::GCCInstallationDetector::ScanGCCForMultilibs( + const llvm::Triple &TargetTriple, const ArgList &Args, + StringRef Path, bool NeedsBiarchSuffix) { + llvm::Triple::ArchType TargetArch = TargetTriple.getArch(); + DetectedMultilibs Detected; + + // Android standalone toolchain could have multilibs for ARM and Thumb. + // Debian mips multilibs behave more like the rest of the biarch ones, + // so handle them there + if (isArmOrThumbArch(TargetArch) && TargetTriple.isAndroid()) { + // It should also work without multilibs in a simplified toolchain. + findAndroidArmMultilibs(D, TargetTriple, Path, Args, Detected); + } else if (tools::isMipsArch(TargetArch)) { + if (!findMIPSMultilibs(D, TargetTriple, Path, Args, Detected)) + return false; + } else if (!findBiarchMultilibs(D, TargetTriple, Path, Args, + NeedsBiarchSuffix, Detected)) { + return false; + } + + Multilibs = Detected.Multilibs; + SelectedMultilib = Detected.SelectedMultilib; + BiarchSibling = Detected.BiarchSibling; + + return true; +} + +void Generic_GCC::GCCInstallationDetector::ScanLibDirForGCCTriple( + const llvm::Triple &TargetTriple, const ArgList &Args, + const std::string &LibDir, StringRef CandidateTriple, + bool NeedsBiarchSuffix) { + if (TargetTriple.getOS() == llvm::Triple::Solaris) { + scanLibDirForGCCTripleSolaris(TargetTriple, Args, LibDir, CandidateTriple, + NeedsBiarchSuffix); + return; + } + + llvm::Triple::ArchType TargetArch = TargetTriple.getArch(); + // Locations relative to the system lib directory where GCC's triple-specific + // directories might reside. + struct GCCLibSuffix { + // Path from system lib directory to GCC triple-specific directory. + std::string LibSuffix; + // Path from GCC triple-specific directory back to system lib directory. + // This is one '..' component per component in LibSuffix. + StringRef ReversePath; + // Whether this library suffix is relevant for the triple. + bool Active; + } Suffixes[] = { + // This is the normal place. + {"gcc/" + CandidateTriple.str(), "../..", true}, + + // Debian puts cross-compilers in gcc-cross. + {"gcc-cross/" + CandidateTriple.str(), "../..", true}, + + // The Freescale PPC SDK has the gcc libraries in + // <sysroot>/usr/lib/<triple>/x.y.z so have a look there as well. Only do + // this on Freescale triples, though, since some systems put a *lot* of + // files in that location, not just GCC installation data. + {CandidateTriple.str(), "..", + TargetTriple.getVendor() == llvm::Triple::Freescale}, + + // Natively multiarch systems sometimes put the GCC triple-specific + // directory within their multiarch lib directory, resulting in the + // triple appearing twice. + {CandidateTriple.str() + "/gcc/" + CandidateTriple.str(), "../../..", true}, + + // Deal with cases (on Ubuntu) where the system architecture could be i386 + // but the GCC target architecture could be (say) i686. + // FIXME: It may be worthwhile to generalize this and look for a second + // triple. + {"i386-linux-gnu/gcc/" + CandidateTriple.str(), "../../..", + TargetArch == llvm::Triple::x86} + }; + + for (auto &Suffix : Suffixes) { + if (!Suffix.Active) + continue; + + StringRef LibSuffix = Suffix.LibSuffix; + std::error_code EC; + for (vfs::directory_iterator + LI = D.getVFS().dir_begin(LibDir + "/" + LibSuffix, EC), + LE; + !EC && LI != LE; LI = LI.increment(EC)) { + StringRef VersionText = llvm::sys::path::filename(LI->getName()); + GCCVersion CandidateVersion = GCCVersion::Parse(VersionText); + if (CandidateVersion.Major != -1) // Filter obviously bad entries. + if (!CandidateGCCInstallPaths.insert(LI->getName()).second) + continue; // Saw this path before; no need to look at it again. + if (CandidateVersion.isOlderThan(4, 1, 1)) + continue; + if (CandidateVersion <= Version) + continue; + + if (!ScanGCCForMultilibs(TargetTriple, Args, LI->getName(), + NeedsBiarchSuffix)) + continue; + + Version = CandidateVersion; + GCCTriple.setTriple(CandidateTriple); + // FIXME: We hack together the directory name here instead of + // using LI to ensure stable path separators across Windows and + // Linux. + GCCInstallPath = (LibDir + "/" + LibSuffix + "/" + VersionText).str(); + GCCParentLibPath = (GCCInstallPath + "/../" + Suffix.ReversePath).str(); + IsValid = true; + } + } +} + +bool Generic_GCC::GCCInstallationDetector::ScanGentooGccConfig( + const llvm::Triple &TargetTriple, const ArgList &Args, + StringRef CandidateTriple, bool NeedsBiarchSuffix) { + llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> File = + D.getVFS().getBufferForFile(D.SysRoot + "/etc/env.d/gcc/config-" + + CandidateTriple.str()); + if (File) { + SmallVector<StringRef, 2> Lines; + File.get()->getBuffer().split(Lines, "\n"); + for (StringRef Line : Lines) { + // CURRENT=triple-version + if (Line.consume_front("CURRENT=")) { + const std::pair<StringRef, StringRef> ActiveVersion = + Line.rsplit('-'); + // Note: Strictly speaking, we should be reading + // /etc/env.d/gcc/${CURRENT} now. However, the file doesn't + // contain anything new or especially useful to us. + const std::string GentooPath = D.SysRoot + "/usr/lib/gcc/" + + ActiveVersion.first.str() + "/" + + ActiveVersion.second.str(); + if (D.getVFS().exists(GentooPath + "/crtbegin.o")) { + if (!ScanGCCForMultilibs(TargetTriple, Args, GentooPath, + NeedsBiarchSuffix)) + return false; + + Version = GCCVersion::Parse(ActiveVersion.second); + GCCInstallPath = GentooPath; + GCCParentLibPath = GentooPath + "/../../.."; + GCCTriple.setTriple(ActiveVersion.first); + IsValid = true; + return true; + } + } + } + } + + return false; +} + +Generic_GCC::Generic_GCC(const Driver &D, const llvm::Triple &Triple, + const ArgList &Args) + : ToolChain(D, Triple, Args), GCCInstallation(D), + CudaInstallation(D, Triple, Args) { + getProgramPaths().push_back(getDriver().getInstalledDir()); + if (getDriver().getInstalledDir() != getDriver().Dir) + getProgramPaths().push_back(getDriver().Dir); +} + +Generic_GCC::~Generic_GCC() {} + +Tool *Generic_GCC::getTool(Action::ActionClass AC) const { + switch (AC) { + case Action::PreprocessJobClass: + if (!Preprocess) + Preprocess.reset(new clang::driver::tools::gcc::Preprocessor(*this)); + return Preprocess.get(); + case Action::CompileJobClass: + if (!Compile) + Compile.reset(new tools::gcc::Compiler(*this)); + return Compile.get(); + default: + return ToolChain::getTool(AC); + } +} + +Tool *Generic_GCC::buildAssembler() const { + return new tools::gnutools::Assembler(*this); +} + +Tool *Generic_GCC::buildLinker() const { return new tools::gcc::Linker(*this); } + +void Generic_GCC::printVerboseInfo(raw_ostream &OS) const { + // Print the information about how we detected the GCC installation. + GCCInstallation.print(OS); + CudaInstallation.print(OS); +} + +bool Generic_GCC::IsUnwindTablesDefault() const { + return getArch() == llvm::Triple::x86_64; +} + +bool Generic_GCC::isPICDefault() const { + switch (getArch()) { + case llvm::Triple::x86_64: + return getTriple().isOSWindows(); + case llvm::Triple::ppc64: + case llvm::Triple::ppc64le: + return !getTriple().isOSBinFormatMachO() && !getTriple().isMacOSX(); + case llvm::Triple::mips64: + case llvm::Triple::mips64el: + return true; + default: + return false; + } +} + +bool Generic_GCC::isPIEDefault() const { return false; } + +bool Generic_GCC::isPICDefaultForced() const { + return getArch() == llvm::Triple::x86_64 && getTriple().isOSWindows(); +} + +bool Generic_GCC::IsIntegratedAssemblerDefault() const { + switch (getTriple().getArch()) { + case llvm::Triple::x86: + case llvm::Triple::x86_64: + case llvm::Triple::aarch64: + case llvm::Triple::aarch64_be: + case llvm::Triple::arm: + case llvm::Triple::armeb: + case llvm::Triple::avr: + case llvm::Triple::bpfel: + case llvm::Triple::bpfeb: + case llvm::Triple::thumb: + case llvm::Triple::thumbeb: + case llvm::Triple::ppc: + case llvm::Triple::ppc64: + case llvm::Triple::ppc64le: + case llvm::Triple::systemz: + case llvm::Triple::mips: + case llvm::Triple::mipsel: + return true; + case llvm::Triple::mips64: + case llvm::Triple::mips64el: + // Enabled for Debian mips64/mips64el only. Other targets are unable to + // distinguish N32 from N64. + if (getTriple().getEnvironment() == llvm::Triple::GNUABI64) + return true; + return false; + default: + return false; + } +} + +void Generic_GCC::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs, + ArgStringList &CC1Args) const { + if (DriverArgs.hasArg(options::OPT_nostdlibinc) || + DriverArgs.hasArg(options::OPT_nostdincxx)) + return; + + switch (GetCXXStdlibType(DriverArgs)) { + case ToolChain::CST_Libcxx: { + std::string Path = findLibCxxIncludePath(); + if (!Path.empty()) + addSystemInclude(DriverArgs, CC1Args, Path); + break; + } + + case ToolChain::CST_Libstdcxx: + addLibStdCxxIncludePaths(DriverArgs, CC1Args); + break; + } +} + +std::string Generic_GCC::findLibCxxIncludePath() const { + // FIXME: The Linux behavior would probaby be a better approach here. + return getDriver().SysRoot + "/usr/include/c++/v1"; +} + +void +Generic_GCC::addLibStdCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const { + // By default, we don't assume we know where libstdc++ might be installed. + // FIXME: If we have a valid GCCInstallation, use it. +} + +/// \brief Helper to add the variant paths of a libstdc++ installation. +bool Generic_GCC::addLibStdCXXIncludePaths( + Twine Base, Twine Suffix, StringRef GCCTriple, StringRef GCCMultiarchTriple, + StringRef TargetMultiarchTriple, Twine IncludeSuffix, + const ArgList &DriverArgs, ArgStringList &CC1Args) const { + if (!getVFS().exists(Base + Suffix)) + return false; + + addSystemInclude(DriverArgs, CC1Args, Base + Suffix); + + // The vanilla GCC layout of libstdc++ headers uses a triple subdirectory. If + // that path exists or we have neither a GCC nor target multiarch triple, use + // this vanilla search path. + if ((GCCMultiarchTriple.empty() && TargetMultiarchTriple.empty()) || + getVFS().exists(Base + Suffix + "/" + GCCTriple + IncludeSuffix)) { + addSystemInclude(DriverArgs, CC1Args, + Base + Suffix + "/" + GCCTriple + IncludeSuffix); + } else { + // Otherwise try to use multiarch naming schemes which have normalized the + // triples and put the triple before the suffix. + // + // GCC surprisingly uses *both* the GCC triple with a multilib suffix and + // the target triple, so we support that here. + addSystemInclude(DriverArgs, CC1Args, + Base + "/" + GCCMultiarchTriple + Suffix + IncludeSuffix); + addSystemInclude(DriverArgs, CC1Args, + Base + "/" + TargetMultiarchTriple + Suffix); + } + + addSystemInclude(DriverArgs, CC1Args, Base + Suffix + "/backward"); + return true; +} + +llvm::opt::DerivedArgList * +Generic_GCC::TranslateArgs(const llvm::opt::DerivedArgList &Args, StringRef, + Action::OffloadKind DeviceOffloadKind) const { + + // If this tool chain is used for an OpenMP offloading device we have to make + // sure we always generate a shared library regardless of the commands the + // user passed to the host. This is required because the runtime library + // is required to load the device image dynamically at run time. + if (DeviceOffloadKind == Action::OFK_OpenMP) { + DerivedArgList *DAL = new DerivedArgList(Args.getBaseArgs()); + const OptTable &Opts = getDriver().getOpts(); + + // Request the shared library. Given that these options are decided + // implicitly, they do not refer to any base argument. + DAL->AddFlagArg(/*BaseArg=*/nullptr, Opts.getOption(options::OPT_shared)); + DAL->AddFlagArg(/*BaseArg=*/nullptr, Opts.getOption(options::OPT_fPIC)); + + // Filter all the arguments we don't care passing to the offloading + // toolchain as they can mess up with the creation of a shared library. + for (auto *A : Args) { + switch ((options::ID)A->getOption().getID()) { + default: + DAL->append(A); + break; + case options::OPT_shared: + case options::OPT_dynamic: + case options::OPT_static: + case options::OPT_fPIC: + case options::OPT_fno_PIC: + case options::OPT_fpic: + case options::OPT_fno_pic: + case options::OPT_fPIE: + case options::OPT_fno_PIE: + case options::OPT_fpie: + case options::OPT_fno_pie: + break; + } + } + return DAL; + } + return nullptr; +} + +void Generic_ELF::anchor() {} + +void Generic_ELF::addClangTargetOptions(const ArgList &DriverArgs, + ArgStringList &CC1Args) const { + const Generic_GCC::GCCVersion &V = GCCInstallation.getVersion(); + bool UseInitArrayDefault = + getTriple().getArch() == llvm::Triple::aarch64 || + getTriple().getArch() == llvm::Triple::aarch64_be || + (getTriple().getOS() == llvm::Triple::Linux && + (!V.isOlderThan(4, 7, 0) || getTriple().isAndroid())) || + getTriple().getOS() == llvm::Triple::NaCl || + (getTriple().getVendor() == llvm::Triple::MipsTechnologies && + !getTriple().hasEnvironment()); + + if (DriverArgs.hasFlag(options::OPT_fuse_init_array, + options::OPT_fno_use_init_array, UseInitArrayDefault)) + CC1Args.push_back("-fuse-init-array"); +} diff --git a/lib/Driver/ToolChains/Gnu.h b/lib/Driver/ToolChains/Gnu.h new file mode 100644 index 0000000000..1dc1ad49e3 --- /dev/null +++ b/lib/Driver/ToolChains/Gnu.h @@ -0,0 +1,351 @@ +//===--- Gnu.h - Gnu Tool and ToolChain Implementations ---------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_GNU_H +#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_GNU_H + +#include "Cuda.h" +#include "clang/Driver/Tool.h" +#include "clang/Driver/ToolChain.h" +#include <set> + +namespace clang { +namespace driver { + +struct DetectedMultilibs { + /// The set of multilibs that the detected installation supports. + MultilibSet Multilibs; + + /// The primary multilib appropriate for the given flags. + Multilib SelectedMultilib; + + /// On Biarch systems, this corresponds to the default multilib when + /// targeting the non-default multilib. Otherwise, it is empty. + llvm::Optional<Multilib> BiarchSibling; +}; + +bool findMIPSMultilibs(const Driver &D, const llvm::Triple &TargetTriple, + StringRef Path, const llvm::opt::ArgList &Args, + DetectedMultilibs &Result); + +namespace tools { + +/// \brief Base class for all GNU tools that provide the same behavior when +/// it comes to response files support +class LLVM_LIBRARY_VISIBILITY GnuTool : public Tool { + virtual void anchor(); + +public: + GnuTool(const char *Name, const char *ShortName, const ToolChain &TC) + : Tool(Name, ShortName, TC, RF_Full, llvm::sys::WEM_CurrentCodePage) {} +}; + +/// Directly call GNU Binutils' assembler and linker. +namespace gnutools { +class LLVM_LIBRARY_VISIBILITY Assembler : public GnuTool { +public: + Assembler(const ToolChain &TC) : GnuTool("GNU::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("GNU::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 gnutools + +/// gcc - Generic GCC tool implementations. +namespace gcc { +class LLVM_LIBRARY_VISIBILITY Common : public GnuTool { +public: + Common(const char *Name, const char *ShortName, const ToolChain &TC) + : GnuTool(Name, ShortName, TC) {} + + // A gcc tool has an "integrated" assembler that it will call to produce an + // object. Let it use that assembler so that we don't have to deal with + // assembly syntax incompatibilities. + bool hasIntegratedAssembler() 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; + + /// RenderExtraToolArgs - Render any arguments necessary to force + /// the particular tool mode. + virtual void RenderExtraToolArgs(const JobAction &JA, + llvm::opt::ArgStringList &CmdArgs) const = 0; +}; + +class LLVM_LIBRARY_VISIBILITY Preprocessor : public Common { +public: + Preprocessor(const ToolChain &TC) + : Common("gcc::Preprocessor", "gcc preprocessor", TC) {} + + bool hasGoodDiagnostics() const override { return true; } + bool hasIntegratedCPP() const override { return false; } + + void RenderExtraToolArgs(const JobAction &JA, + llvm::opt::ArgStringList &CmdArgs) const override; +}; + +class LLVM_LIBRARY_VISIBILITY Compiler : public Common { +public: + Compiler(const ToolChain &TC) : Common("gcc::Compiler", "gcc frontend", TC) {} + + bool hasGoodDiagnostics() const override { return true; } + bool hasIntegratedCPP() const override { return true; } + + void RenderExtraToolArgs(const JobAction &JA, + llvm::opt::ArgStringList &CmdArgs) const override; +}; + +class LLVM_LIBRARY_VISIBILITY Linker : public Common { +public: + Linker(const ToolChain &TC) : Common("gcc::Linker", "linker (via gcc)", TC) {} + + bool hasIntegratedCPP() const override { return false; } + bool isLinkJob() const override { return true; } + + void RenderExtraToolArgs(const JobAction &JA, + llvm::opt::ArgStringList &CmdArgs) const override; +}; +} // end namespace gcc +} // end namespace tools + +namespace toolchains { + +/// Generic_GCC - A tool chain using the 'gcc' command to perform +/// all subcommands; this relies on gcc translating the majority of +/// command line options. +class LLVM_LIBRARY_VISIBILITY Generic_GCC : public ToolChain { +public: + /// \brief Struct to store and manipulate GCC versions. + /// + /// We rely on assumptions about the form and structure of GCC version + /// numbers: they consist of at most three '.'-separated components, and each + /// component is a non-negative integer except for the last component. For + /// the last component we are very flexible in order to tolerate release + /// candidates or 'x' wildcards. + /// + /// Note that the ordering established among GCCVersions is based on the + /// preferred version string to use. For example we prefer versions without + /// a hard-coded patch number to those with a hard coded patch number. + /// + /// Currently this doesn't provide any logic for textual suffixes to patches + /// in the way that (for example) Debian's version format does. If that ever + /// becomes necessary, it can be added. + struct GCCVersion { + /// \brief The unparsed text of the version. + std::string Text; + + /// \brief The parsed major, minor, and patch numbers. + int Major, Minor, Patch; + + /// \brief The text of the parsed major, and major+minor versions. + std::string MajorStr, MinorStr; + + /// \brief Any textual suffix on the patch number. + std::string PatchSuffix; + + static GCCVersion Parse(StringRef VersionText); + bool isOlderThan(int RHSMajor, int RHSMinor, int RHSPatch, + StringRef RHSPatchSuffix = StringRef()) const; + bool operator<(const GCCVersion &RHS) const { + return isOlderThan(RHS.Major, RHS.Minor, RHS.Patch, RHS.PatchSuffix); + } + bool operator>(const GCCVersion &RHS) const { return RHS < *this; } + bool operator<=(const GCCVersion &RHS) const { return !(*this > RHS); } + bool operator>=(const GCCVersion &RHS) const { return !(*this < RHS); } + }; + + /// \brief This is a class to find a viable GCC installation for Clang to + /// use. + /// + /// This class tries to find a GCC installation on the system, and report + /// information about it. It starts from the host information provided to the + /// Driver, and has logic for fuzzing that where appropriate. + class GCCInstallationDetector { + bool IsValid; + llvm::Triple GCCTriple; + const Driver &D; + + // FIXME: These might be better as path objects. + std::string GCCInstallPath; + std::string GCCParentLibPath; + + /// The primary multilib appropriate for the given flags. + Multilib SelectedMultilib; + /// On Biarch systems, this corresponds to the default multilib when + /// targeting the non-default multilib. Otherwise, it is empty. + llvm::Optional<Multilib> BiarchSibling; + + GCCVersion Version; + + // We retain the list of install paths that were considered and rejected in + // order to print out detailed information in verbose mode. + std::set<std::string> CandidateGCCInstallPaths; + + /// The set of multilibs that the detected installation supports. + MultilibSet Multilibs; + + public: + explicit GCCInstallationDetector(const Driver &D) : IsValid(false), D(D) {} + void init(const llvm::Triple &TargetTriple, const llvm::opt::ArgList &Args, + ArrayRef<std::string> ExtraTripleAliases = None); + + /// \brief Check whether we detected a valid GCC install. + bool isValid() const { return IsValid; } + + /// \brief Get the GCC triple for the detected install. + const llvm::Triple &getTriple() const { return GCCTriple; } + + /// \brief Get the detected GCC installation path. + StringRef getInstallPath() const { return GCCInstallPath; } + + /// \brief Get the detected GCC parent lib path. + StringRef getParentLibPath() const { return GCCParentLibPath; } + + /// \brief Get the detected Multilib + const Multilib &getMultilib() const { return SelectedMultilib; } + + /// \brief Get the whole MultilibSet + const MultilibSet &getMultilibs() const { return Multilibs; } + + /// Get the biarch sibling multilib (if it exists). + /// \return true iff such a sibling exists + bool getBiarchSibling(Multilib &M) const; + + /// \brief Get the detected GCC version string. + const GCCVersion &getVersion() const { return Version; } + + /// \brief Print information about the detected GCC installation. + void print(raw_ostream &OS) const; + + private: + static void + CollectLibDirsAndTriples(const llvm::Triple &TargetTriple, + const llvm::Triple &BiarchTriple, + SmallVectorImpl<StringRef> &LibDirs, + SmallVectorImpl<StringRef> &TripleAliases, + SmallVectorImpl<StringRef> &BiarchLibDirs, + SmallVectorImpl<StringRef> &BiarchTripleAliases); + + bool ScanGCCForMultilibs(const llvm::Triple &TargetTriple, + const llvm::opt::ArgList &Args, + StringRef Path, + bool NeedsBiarchSuffix = false); + + void ScanLibDirForGCCTriple(const llvm::Triple &TargetArch, + const llvm::opt::ArgList &Args, + const std::string &LibDir, + StringRef CandidateTriple, + bool NeedsBiarchSuffix = false); + + void scanLibDirForGCCTripleSolaris(const llvm::Triple &TargetArch, + const llvm::opt::ArgList &Args, + const std::string &LibDir, + StringRef CandidateTriple, + bool NeedsBiarchSuffix = false); + + bool ScanGentooGccConfig(const llvm::Triple &TargetTriple, + const llvm::opt::ArgList &Args, + StringRef CandidateTriple, + bool NeedsBiarchSuffix = false); + }; + +protected: + GCCInstallationDetector GCCInstallation; + CudaInstallationDetector CudaInstallation; + +public: + Generic_GCC(const Driver &D, const llvm::Triple &Triple, + const llvm::opt::ArgList &Args); + ~Generic_GCC() override; + + void printVerboseInfo(raw_ostream &OS) const override; + + bool IsUnwindTablesDefault() const override; + bool isPICDefault() const override; + bool isPIEDefault() const override; + bool isPICDefaultForced() const override; + bool IsIntegratedAssemblerDefault() const override; + llvm::opt::DerivedArgList * + TranslateArgs(const llvm::opt::DerivedArgList &Args, StringRef BoundArch, + Action::OffloadKind DeviceOffloadKind) const override; + +protected: + Tool *getTool(Action::ActionClass AC) const override; + Tool *buildAssembler() const override; + Tool *buildLinker() const override; + + /// \name ToolChain Implementation Helper Functions + /// @{ + + /// \brief Check whether the target triple's architecture is 64-bits. + bool isTarget64Bit() const { return getTriple().isArch64Bit(); } + + /// \brief Check whether the target triple's architecture is 32-bits. + bool isTarget32Bit() const { return getTriple().isArch32Bit(); } + + // FIXME: This should be final, but the Solaris tool chain does weird + // things we can't easily represent. + void AddClangCXXStdlibIncludeArgs( + const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const override; + + virtual std::string findLibCxxIncludePath() const; + virtual void + addLibStdCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const; + + bool addLibStdCXXIncludePaths(Twine Base, Twine Suffix, StringRef GCCTriple, + StringRef GCCMultiarchTriple, + StringRef TargetMultiarchTriple, + Twine IncludeSuffix, + const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const; + + /// @} + +private: + mutable std::unique_ptr<tools::gcc::Preprocessor> Preprocess; + mutable std::unique_ptr<tools::gcc::Compiler> Compile; +}; + +class LLVM_LIBRARY_VISIBILITY Generic_ELF : public Generic_GCC { + virtual void anchor(); + +public: + Generic_ELF(const Driver &D, const llvm::Triple &Triple, + const llvm::opt::ArgList &Args) + : Generic_GCC(D, Triple, Args) {} + + void addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const override; +}; + +} // end namespace toolchains +} // end namespace driver +} // end namespace clang + +#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_GNU_H diff --git a/lib/Driver/ToolChains/Haiku.cpp b/lib/Driver/ToolChains/Haiku.cpp new file mode 100644 index 0000000000..d41deccba9 --- /dev/null +++ b/lib/Driver/ToolChains/Haiku.cpp @@ -0,0 +1,33 @@ +//===--- Haiku.cpp - Haiku 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 "Haiku.h" +#include "CommonArgs.h" + +using namespace clang::driver; +using namespace clang::driver::toolchains;; +using namespace clang; +using namespace llvm::opt; + +/// Haiku - Haiku tool chain which can call as(1) and ld(1) directly. + +Haiku::Haiku(const Driver &D, const llvm::Triple& Triple, const ArgList &Args) + : Generic_ELF(D, Triple, Args) { + +} + +std::string Haiku::findLibCxxIncludePath() const { + return getDriver().SysRoot + "/system/develop/headers/c++/v1"; +} + +void Haiku::addLibStdCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const { + addLibStdCXXIncludePaths(getDriver().SysRoot, "/system/develop/headers/c++", + getTriple().str(), "", "", "", DriverArgs, CC1Args); +} diff --git a/lib/Driver/ToolChains/Haiku.h b/lib/Driver/ToolChains/Haiku.h new file mode 100644 index 0000000000..8b5b48e590 --- /dev/null +++ b/lib/Driver/ToolChains/Haiku.h @@ -0,0 +1,40 @@ +//===--- Haiku.h - Haiku 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_HAIKU_H +#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_HAIKU_H + +#include "Gnu.h" +#include "clang/Driver/Driver.h" +#include "clang/Driver/ToolChain.h" + +namespace clang { +namespace driver { +namespace toolchains { + +class LLVM_LIBRARY_VISIBILITY Haiku : public Generic_ELF { +public: + Haiku(const Driver &D, const llvm::Triple &Triple, + const llvm::opt::ArgList &Args); + + bool isPIEDefault() const override { + return getTriple().getArch() == llvm::Triple::x86_64; + } + + std::string findLibCxxIncludePath() const override; + void addLibStdCxxIncludePaths( + const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const override; +}; + +} // end namespace toolchains +} // end namespace driver +} // end namespace clang + +#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_HAIKU_H diff --git a/lib/Driver/ToolChains/Hexagon.cpp b/lib/Driver/ToolChains/Hexagon.cpp new file mode 100644 index 0000000000..c143b7f898 --- /dev/null +++ b/lib/Driver/ToolChains/Hexagon.cpp @@ -0,0 +1,457 @@ +//===--- Hexagon.cpp - Hexagon 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 "Hexagon.h" +#include "InputInfo.h" +#include "CommonArgs.h" +#include "clang/Basic/VirtualFileSystem.h" +#include "clang/Config/config.h" +#include "clang/Driver/Compilation.h" +#include "clang/Driver/Driver.h" +#include "clang/Driver/DriverDiagnostic.h" +#include "clang/Driver/Options.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/Option/ArgList.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/Path.h" + +using namespace clang::driver; +using namespace clang::driver::tools; +using namespace clang::driver::toolchains; +using namespace clang; +using namespace llvm::opt; + +// Hexagon tools start. +void hexagon::Assembler::RenderExtraToolArgs(const JobAction &JA, + ArgStringList &CmdArgs) const { +} + +void hexagon::Assembler::ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, + const InputInfoList &Inputs, + const ArgList &Args, + const char *LinkingOutput) const { + claimNoWarnArgs(Args); + + auto &HTC = static_cast<const toolchains::HexagonToolChain&>(getToolChain()); + const Driver &D = HTC.getDriver(); + ArgStringList CmdArgs; + + std::string MArchString = "-march=hexagon"; + CmdArgs.push_back(Args.MakeArgString(MArchString)); + + RenderExtraToolArgs(JA, CmdArgs); + + std::string AsName = "hexagon-llvm-mc"; + std::string MCpuString = "-mcpu=hexagon" + + toolchains::HexagonToolChain::GetTargetCPUVersion(Args).str(); + CmdArgs.push_back("-filetype=obj"); + CmdArgs.push_back(Args.MakeArgString(MCpuString)); + + if (Output.isFilename()) { + CmdArgs.push_back("-o"); + CmdArgs.push_back(Output.getFilename()); + } else { + assert(Output.isNothing() && "Unexpected output"); + CmdArgs.push_back("-fsyntax-only"); + } + + if (auto G = toolchains::HexagonToolChain::getSmallDataThreshold(Args)) { + std::string N = llvm::utostr(G.getValue()); + CmdArgs.push_back(Args.MakeArgString(std::string("-gpsize=") + N)); + } + + Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler); + + // Only pass -x if gcc will understand it; otherwise hope gcc + // understands the suffix correctly. The main use case this would go + // wrong in is for linker inputs if they happened to have an odd + // suffix; really the only way to get this to happen is a command + // like '-x foobar a.c' which will treat a.c like a linker input. + // + // FIXME: For the linker case specifically, can we safely convert + // inputs into '-Wl,' options? + for (const auto &II : Inputs) { + // Don't try to pass LLVM or AST inputs to a generic gcc. + if (types::isLLVMIR(II.getType())) + D.Diag(clang::diag::err_drv_no_linker_llvm_support) + << HTC.getTripleString(); + else if (II.getType() == types::TY_AST) + D.Diag(clang::diag::err_drv_no_ast_support) + << HTC.getTripleString(); + else if (II.getType() == types::TY_ModuleFile) + D.Diag(diag::err_drv_no_module_support) + << HTC.getTripleString(); + + if (II.isFilename()) + CmdArgs.push_back(II.getFilename()); + else + // Don't render as input, we need gcc to do the translations. + // FIXME: What is this? + II.getInputArg().render(Args, CmdArgs); + } + + auto *Exec = Args.MakeArgString(HTC.GetProgramPath(AsName.c_str())); + C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); +} + +void hexagon::Linker::RenderExtraToolArgs(const JobAction &JA, + ArgStringList &CmdArgs) const { +} + +static void +constructHexagonLinkArgs(Compilation &C, const JobAction &JA, + const toolchains::HexagonToolChain &HTC, + const InputInfo &Output, const InputInfoList &Inputs, + const ArgList &Args, ArgStringList &CmdArgs, + const char *LinkingOutput) { + + const Driver &D = HTC.getDriver(); + + //---------------------------------------------------------------------------- + // + //---------------------------------------------------------------------------- + bool IsStatic = Args.hasArg(options::OPT_static); + bool IsShared = Args.hasArg(options::OPT_shared); + bool IsPIE = Args.hasArg(options::OPT_pie); + bool IncStdLib = !Args.hasArg(options::OPT_nostdlib); + bool IncStartFiles = !Args.hasArg(options::OPT_nostartfiles); + bool IncDefLibs = !Args.hasArg(options::OPT_nodefaultlibs); + bool UseG0 = false; + bool UseShared = IsShared && !IsStatic; + + //---------------------------------------------------------------------------- + // Silence warnings for various options + //---------------------------------------------------------------------------- + Args.ClaimAllArgs(options::OPT_g_Group); + Args.ClaimAllArgs(options::OPT_emit_llvm); + Args.ClaimAllArgs(options::OPT_w); // Other warning options are already + // handled somewhere else. + Args.ClaimAllArgs(options::OPT_static_libgcc); + + //---------------------------------------------------------------------------- + // + //---------------------------------------------------------------------------- + if (Args.hasArg(options::OPT_s)) + CmdArgs.push_back("-s"); + + if (Args.hasArg(options::OPT_r)) + CmdArgs.push_back("-r"); + + for (const auto &Opt : HTC.ExtraOpts) + CmdArgs.push_back(Opt.c_str()); + + CmdArgs.push_back("-march=hexagon"); + std::string CpuVer = + toolchains::HexagonToolChain::GetTargetCPUVersion(Args).str(); + std::string MCpuString = "-mcpu=hexagon" + CpuVer; + CmdArgs.push_back(Args.MakeArgString(MCpuString)); + + if (IsShared) { + CmdArgs.push_back("-shared"); + // The following should be the default, but doing as hexagon-gcc does. + CmdArgs.push_back("-call_shared"); + } + + if (IsStatic) + CmdArgs.push_back("-static"); + + if (IsPIE && !IsShared) + CmdArgs.push_back("-pie"); + + if (auto G = toolchains::HexagonToolChain::getSmallDataThreshold(Args)) { + std::string N = llvm::utostr(G.getValue()); + CmdArgs.push_back(Args.MakeArgString(std::string("-G") + N)); + UseG0 = G.getValue() == 0; + } + + //---------------------------------------------------------------------------- + // + //---------------------------------------------------------------------------- + CmdArgs.push_back("-o"); + CmdArgs.push_back(Output.getFilename()); + + //---------------------------------------------------------------------------- + // moslib + //---------------------------------------------------------------------------- + std::vector<std::string> OsLibs; + bool HasStandalone = false; + + for (const Arg *A : Args.filtered(options::OPT_moslib_EQ)) { + A->claim(); + OsLibs.emplace_back(A->getValue()); + HasStandalone = HasStandalone || (OsLibs.back() == "standalone"); + } + if (OsLibs.empty()) { + OsLibs.push_back("standalone"); + HasStandalone = true; + } + + //---------------------------------------------------------------------------- + // Start Files + //---------------------------------------------------------------------------- + const std::string MCpuSuffix = "/" + CpuVer; + const std::string MCpuG0Suffix = MCpuSuffix + "/G0"; + const std::string RootDir = + HTC.getHexagonTargetDir(D.InstalledDir, D.PrefixDirs) + "/"; + const std::string StartSubDir = + "hexagon/lib" + (UseG0 ? MCpuG0Suffix : MCpuSuffix); + + auto Find = [&HTC] (const std::string &RootDir, const std::string &SubDir, + const char *Name) -> std::string { + std::string RelName = SubDir + Name; + std::string P = HTC.GetFilePath(RelName.c_str()); + if (llvm::sys::fs::exists(P)) + return P; + return RootDir + RelName; + }; + + if (IncStdLib && IncStartFiles) { + if (!IsShared) { + if (HasStandalone) { + std::string Crt0SA = Find(RootDir, StartSubDir, "/crt0_standalone.o"); + CmdArgs.push_back(Args.MakeArgString(Crt0SA)); + } + std::string Crt0 = Find(RootDir, StartSubDir, "/crt0.o"); + CmdArgs.push_back(Args.MakeArgString(Crt0)); + } + std::string Init = UseShared + ? Find(RootDir, StartSubDir + "/pic", "/initS.o") + : Find(RootDir, StartSubDir, "/init.o"); + CmdArgs.push_back(Args.MakeArgString(Init)); + } + + //---------------------------------------------------------------------------- + // Library Search Paths + //---------------------------------------------------------------------------- + const ToolChain::path_list &LibPaths = HTC.getFilePaths(); + for (const auto &LibPath : LibPaths) + CmdArgs.push_back(Args.MakeArgString(StringRef("-L") + LibPath)); + + //---------------------------------------------------------------------------- + // + //---------------------------------------------------------------------------- + Args.AddAllArgs(CmdArgs, + {options::OPT_T_Group, options::OPT_e, options::OPT_s, + options::OPT_t, options::OPT_u_Group}); + + AddLinkerInputs(HTC, Inputs, Args, CmdArgs, JA); + + //---------------------------------------------------------------------------- + // Libraries + //---------------------------------------------------------------------------- + if (IncStdLib && IncDefLibs) { + if (D.CCCIsCXX()) { + HTC.AddCXXStdlibLibArgs(Args, CmdArgs); + CmdArgs.push_back("-lm"); + } + + CmdArgs.push_back("--start-group"); + + if (!IsShared) { + for (const std::string &Lib : OsLibs) + CmdArgs.push_back(Args.MakeArgString("-l" + Lib)); + CmdArgs.push_back("-lc"); + } + CmdArgs.push_back("-lgcc"); + + CmdArgs.push_back("--end-group"); + } + + //---------------------------------------------------------------------------- + // End files + //---------------------------------------------------------------------------- + if (IncStdLib && IncStartFiles) { + std::string Fini = UseShared + ? Find(RootDir, StartSubDir + "/pic", "/finiS.o") + : Find(RootDir, StartSubDir, "/fini.o"); + CmdArgs.push_back(Args.MakeArgString(Fini)); + } +} + +void hexagon::Linker::ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, + const InputInfoList &Inputs, + const ArgList &Args, + const char *LinkingOutput) const { + auto &HTC = static_cast<const toolchains::HexagonToolChain&>(getToolChain()); + + ArgStringList CmdArgs; + constructHexagonLinkArgs(C, JA, HTC, Output, Inputs, Args, CmdArgs, + LinkingOutput); + + std::string Linker = HTC.GetProgramPath("hexagon-link"); + C.addCommand(llvm::make_unique<Command>(JA, *this, Args.MakeArgString(Linker), + CmdArgs, Inputs)); +} +// Hexagon tools end. + +/// Hexagon Toolchain + +std::string HexagonToolChain::getHexagonTargetDir( + const std::string &InstalledDir, + const SmallVectorImpl<std::string> &PrefixDirs) const { + std::string InstallRelDir; + const Driver &D = getDriver(); + + // Locate the rest of the toolchain ... + for (auto &I : PrefixDirs) + if (D.getVFS().exists(I)) + return I; + + if (getVFS().exists(InstallRelDir = InstalledDir + "/../target")) + return InstallRelDir; + + return InstalledDir; +} + +Optional<unsigned> HexagonToolChain::getSmallDataThreshold( + const ArgList &Args) { + StringRef Gn = ""; + if (Arg *A = Args.getLastArg(options::OPT_G)) { + Gn = A->getValue(); + } else if (Args.getLastArg(options::OPT_shared, options::OPT_fpic, + options::OPT_fPIC)) { + Gn = "0"; + } + + unsigned G; + if (!Gn.getAsInteger(10, G)) + return G; + + return None; +} + +void HexagonToolChain::getHexagonLibraryPaths(const ArgList &Args, + ToolChain::path_list &LibPaths) const { + const Driver &D = getDriver(); + + //---------------------------------------------------------------------------- + // -L Args + //---------------------------------------------------------------------------- + for (Arg *A : Args.filtered(options::OPT_L)) + for (const char *Value : A->getValues()) + LibPaths.push_back(Value); + + //---------------------------------------------------------------------------- + // Other standard paths + //---------------------------------------------------------------------------- + std::vector<std::string> RootDirs; + std::copy(D.PrefixDirs.begin(), D.PrefixDirs.end(), + std::back_inserter(RootDirs)); + + std::string TargetDir = getHexagonTargetDir(D.getInstalledDir(), + D.PrefixDirs); + if (std::find(RootDirs.begin(), RootDirs.end(), TargetDir) == RootDirs.end()) + RootDirs.push_back(TargetDir); + + bool HasPIC = Args.hasArg(options::OPT_fpic, options::OPT_fPIC); + // Assume G0 with -shared. + bool HasG0 = Args.hasArg(options::OPT_shared); + if (auto G = getSmallDataThreshold(Args)) + HasG0 = G.getValue() == 0; + + const std::string CpuVer = GetTargetCPUVersion(Args).str(); + for (auto &Dir : RootDirs) { + std::string LibDir = Dir + "/hexagon/lib"; + std::string LibDirCpu = LibDir + '/' + CpuVer; + if (HasG0) { + if (HasPIC) + LibPaths.push_back(LibDirCpu + "/G0/pic"); + LibPaths.push_back(LibDirCpu + "/G0"); + } + LibPaths.push_back(LibDirCpu); + LibPaths.push_back(LibDir); + } +} + +HexagonToolChain::HexagonToolChain(const Driver &D, const llvm::Triple &Triple, + const llvm::opt::ArgList &Args) + : Linux(D, Triple, Args) { + const std::string TargetDir = getHexagonTargetDir(D.getInstalledDir(), + D.PrefixDirs); + + // Note: Generic_GCC::Generic_GCC adds InstalledDir and getDriver().Dir to + // program paths + const std::string BinDir(TargetDir + "/bin"); + if (D.getVFS().exists(BinDir)) + getProgramPaths().push_back(BinDir); + + ToolChain::path_list &LibPaths = getFilePaths(); + + // Remove paths added by Linux toolchain. Currently Hexagon_TC really targets + // 'elf' OS type, so the Linux paths are not appropriate. When we actually + // support 'linux' we'll need to fix this up + LibPaths.clear(); + getHexagonLibraryPaths(Args, LibPaths); +} + +HexagonToolChain::~HexagonToolChain() {} + +Tool *HexagonToolChain::buildAssembler() const { + return new tools::hexagon::Assembler(*this); +} + +Tool *HexagonToolChain::buildLinker() const { + return new tools::hexagon::Linker(*this); +} + +void HexagonToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs, + ArgStringList &CC1Args) const { + if (DriverArgs.hasArg(options::OPT_nostdinc) || + DriverArgs.hasArg(options::OPT_nostdlibinc)) + return; + + const Driver &D = getDriver(); + std::string TargetDir = getHexagonTargetDir(D.getInstalledDir(), + D.PrefixDirs); + addExternCSystemInclude(DriverArgs, CC1Args, TargetDir + "/hexagon/include"); +} + + +void HexagonToolChain::addLibStdCxxIncludePaths( + const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const { + const Driver &D = getDriver(); + std::string TargetDir = getHexagonTargetDir(D.InstalledDir, D.PrefixDirs); + addLibStdCXXIncludePaths(TargetDir, "/hexagon/include/c++", "", "", "", "", + DriverArgs, CC1Args); +} + +ToolChain::CXXStdlibType +HexagonToolChain::GetCXXStdlibType(const ArgList &Args) const { + Arg *A = Args.getLastArg(options::OPT_stdlib_EQ); + if (!A) + return ToolChain::CST_Libstdcxx; + + StringRef Value = A->getValue(); + if (Value != "libstdc++") + getDriver().Diag(diag::err_drv_invalid_stdlib_name) << A->getAsString(Args); + + return ToolChain::CST_Libstdcxx; +} + +// +// Returns the default CPU for Hexagon. This is the default compilation target +// if no Hexagon processor is selected at the command-line. +// +const StringRef HexagonToolChain::GetDefaultCPU() { + return "hexagonv60"; +} + +const StringRef HexagonToolChain::GetTargetCPUVersion(const ArgList &Args) { + Arg *CpuArg = nullptr; + if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ, options::OPT_march_EQ)) + CpuArg = A; + + StringRef CPU = CpuArg ? CpuArg->getValue() : GetDefaultCPU(); + if (CPU.startswith("hexagon")) + return CPU.substr(sizeof("hexagon") - 1); + return CPU; +} diff --git a/lib/Driver/ToolChains/Hexagon.h b/lib/Driver/ToolChains/Hexagon.h new file mode 100644 index 0000000000..fb50ba3c72 --- /dev/null +++ b/lib/Driver/ToolChains/Hexagon.h @@ -0,0 +1,99 @@ +//===--- Hexagon.h - Hexagon 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_HEXAGON_H +#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_HEXAGON_H + +#include "Linux.h" +#include "clang/Driver/Tool.h" +#include "clang/Driver/ToolChain.h" + +namespace clang { +namespace driver { +namespace tools { +namespace hexagon { +// For Hexagon, we do not need to instantiate tools for PreProcess, PreCompile +// and Compile. +// We simply use "clang -cc1" for those actions. +class LLVM_LIBRARY_VISIBILITY Assembler : public GnuTool { +public: + Assembler(const ToolChain &TC) + : GnuTool("hexagon::Assembler", "hexagon-as", TC) {} + + bool hasIntegratedCPP() const override { return false; } + + void RenderExtraToolArgs(const JobAction &JA, + llvm::opt::ArgStringList &CmdArgs) const; + 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("hexagon::Linker", "hexagon-ld", TC) {} + + bool hasIntegratedCPP() const override { return false; } + bool isLinkJob() const override { return true; } + + virtual void RenderExtraToolArgs(const JobAction &JA, + llvm::opt::ArgStringList &CmdArgs) const; + 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 hexagon. +} // end namespace tools + +namespace toolchains { + +class LLVM_LIBRARY_VISIBILITY HexagonToolChain : public Linux { +protected: + GCCVersion GCCLibAndIncVersion; + Tool *buildAssembler() const override; + Tool *buildLinker() const override; + +public: + HexagonToolChain(const Driver &D, const llvm::Triple &Triple, + const llvm::opt::ArgList &Args); + ~HexagonToolChain() override; + + void + AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const override; + void addLibStdCxxIncludePaths( + const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const override; + CXXStdlibType GetCXXStdlibType(const llvm::opt::ArgList &Args) const override; + + StringRef GetGCCLibAndIncVersion() const { return GCCLibAndIncVersion.Text; } + bool IsIntegratedAssemblerDefault() const override { + return true; + } + + std::string getHexagonTargetDir( + const std::string &InstalledDir, + const SmallVectorImpl<std::string> &PrefixDirs) const; + void getHexagonLibraryPaths(const llvm::opt::ArgList &Args, + ToolChain::path_list &LibPaths) const; + + static const StringRef GetDefaultCPU(); + static const StringRef GetTargetCPUVersion(const llvm::opt::ArgList &Args); + + static Optional<unsigned> getSmallDataThreshold( + const llvm::opt::ArgList &Args); +}; + +} // end namespace toolchains +} // end namespace driver +} // end namespace clang + +#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_HEXAGON_H diff --git a/lib/Driver/ToolChains/Lanai.h b/lib/Driver/ToolChains/Lanai.h new file mode 100644 index 0000000000..4ce658dc77 --- /dev/null +++ b/lib/Driver/ToolChains/Lanai.h @@ -0,0 +1,39 @@ +//===--- Lanai.h - Lanai 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_LANAI_H +#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_LANAI_H + +#include "Gnu.h" +#include "clang/Driver/ToolChain.h" + +namespace clang { +namespace driver { +namespace toolchains { + +class LLVM_LIBRARY_VISIBILITY LanaiToolChain : public Generic_ELF { +public: + LanaiToolChain(const Driver &D, const llvm::Triple &Triple, + const llvm::opt::ArgList &Args) + : Generic_ELF(D, Triple, Args) {} + + // No support for finding a C++ standard library yet. + std::string findLibCxxIncludePath() const override { return ""; } + void addLibStdCxxIncludePaths( + const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const override {} + + bool IsIntegratedAssemblerDefault() const override { return true; } +}; + +} // end namespace toolchains +} // end namespace driver +} // end namespace clang + +#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_LANAI_H diff --git a/lib/Driver/ToolChains/Linux.cpp b/lib/Driver/ToolChains/Linux.cpp new file mode 100644 index 0000000000..e87ef08e90 --- /dev/null +++ b/lib/Driver/ToolChains/Linux.cpp @@ -0,0 +1,898 @@ +//===--- Linux.h - Linux 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 "Linux.h" +#include "Arch/ARM.h" +#include "Arch/Mips.h" +#include "Arch/PPC.h" +#include "CommonArgs.h" +#include "clang/Basic/VirtualFileSystem.h" +#include "clang/Config/config.h" +#include "clang/Driver/Distro.h" +#include "clang/Driver/Driver.h" +#include "clang/Driver/Options.h" +#include "clang/Driver/SanitizerArgs.h" +#include "llvm/Option/ArgList.h" +#include "llvm/ProfileData/InstrProf.h" +#include "llvm/Support/Path.h" +#include <system_error> + +using namespace clang::driver; +using namespace clang::driver::toolchains; +using namespace clang; +using namespace llvm::opt; + +using tools::addPathIfExists; + +/// \brief Get our best guess at the multiarch triple for a target. +/// +/// Debian-based systems are starting to use a multiarch setup where they use +/// a target-triple directory in the library and header search paths. +/// Unfortunately, this triple does not align with the vanilla target triple, +/// so we provide a rough mapping here. +static std::string getMultiarchTriple(const Driver &D, + const llvm::Triple &TargetTriple, + StringRef SysRoot) { + llvm::Triple::EnvironmentType TargetEnvironment = + TargetTriple.getEnvironment(); + + // For most architectures, just use whatever we have rather than trying to be + // clever. + switch (TargetTriple.getArch()) { + default: + break; + + // We use the existence of '/lib/<triple>' as a directory to detect some + // common linux triples that don't quite match the Clang triple for both + // 32-bit and 64-bit targets. Multiarch fixes its install triples to these + // regardless of what the actual target triple is. + case llvm::Triple::arm: + case llvm::Triple::thumb: + if (TargetEnvironment == llvm::Triple::GNUEABIHF) { + if (D.getVFS().exists(SysRoot + "/lib/arm-linux-gnueabihf")) + return "arm-linux-gnueabihf"; + } else { + if (D.getVFS().exists(SysRoot + "/lib/arm-linux-gnueabi")) + return "arm-linux-gnueabi"; + } + break; + case llvm::Triple::armeb: + case llvm::Triple::thumbeb: + if (TargetEnvironment == llvm::Triple::GNUEABIHF) { + if (D.getVFS().exists(SysRoot + "/lib/armeb-linux-gnueabihf")) + return "armeb-linux-gnueabihf"; + } else { + if (D.getVFS().exists(SysRoot + "/lib/armeb-linux-gnueabi")) + return "armeb-linux-gnueabi"; + } + break; + case llvm::Triple::x86: + if (D.getVFS().exists(SysRoot + "/lib/i386-linux-gnu")) + return "i386-linux-gnu"; + break; + case llvm::Triple::x86_64: + // We don't want this for x32, otherwise it will match x86_64 libs + if (TargetEnvironment != llvm::Triple::GNUX32 && + D.getVFS().exists(SysRoot + "/lib/x86_64-linux-gnu")) + return "x86_64-linux-gnu"; + break; + case llvm::Triple::aarch64: + if (D.getVFS().exists(SysRoot + "/lib/aarch64-linux-gnu")) + return "aarch64-linux-gnu"; + break; + case llvm::Triple::aarch64_be: + if (D.getVFS().exists(SysRoot + "/lib/aarch64_be-linux-gnu")) + return "aarch64_be-linux-gnu"; + break; + case llvm::Triple::mips: + if (D.getVFS().exists(SysRoot + "/lib/mips-linux-gnu")) + return "mips-linux-gnu"; + break; + case llvm::Triple::mipsel: + if (D.getVFS().exists(SysRoot + "/lib/mipsel-linux-gnu")) + return "mipsel-linux-gnu"; + break; + case llvm::Triple::mips64: + if (D.getVFS().exists(SysRoot + "/lib/mips64-linux-gnu")) + return "mips64-linux-gnu"; + if (D.getVFS().exists(SysRoot + "/lib/mips64-linux-gnuabi64")) + return "mips64-linux-gnuabi64"; + break; + case llvm::Triple::mips64el: + if (D.getVFS().exists(SysRoot + "/lib/mips64el-linux-gnu")) + return "mips64el-linux-gnu"; + if (D.getVFS().exists(SysRoot + "/lib/mips64el-linux-gnuabi64")) + return "mips64el-linux-gnuabi64"; + break; + case llvm::Triple::ppc: + if (D.getVFS().exists(SysRoot + "/lib/powerpc-linux-gnuspe")) + return "powerpc-linux-gnuspe"; + if (D.getVFS().exists(SysRoot + "/lib/powerpc-linux-gnu")) + return "powerpc-linux-gnu"; + break; + case llvm::Triple::ppc64: + if (D.getVFS().exists(SysRoot + "/lib/powerpc64-linux-gnu")) + return "powerpc64-linux-gnu"; + break; + case llvm::Triple::ppc64le: + if (D.getVFS().exists(SysRoot + "/lib/powerpc64le-linux-gnu")) + return "powerpc64le-linux-gnu"; + break; + case llvm::Triple::sparc: + if (D.getVFS().exists(SysRoot + "/lib/sparc-linux-gnu")) + return "sparc-linux-gnu"; + break; + case llvm::Triple::sparcv9: + if (D.getVFS().exists(SysRoot + "/lib/sparc64-linux-gnu")) + return "sparc64-linux-gnu"; + break; + case llvm::Triple::systemz: + if (D.getVFS().exists(SysRoot + "/lib/s390x-linux-gnu")) + return "s390x-linux-gnu"; + break; + } + return TargetTriple.str(); +} + +static StringRef getOSLibDir(const llvm::Triple &Triple, const ArgList &Args) { + if (tools::isMipsArch(Triple.getArch())) { + if (Triple.isAndroid()) { + StringRef CPUName; + StringRef ABIName; + tools::mips::getMipsCPUAndABI(Args, Triple, CPUName, ABIName); + if (CPUName == "mips32r6") + return "libr6"; + if (CPUName == "mips32r2") + return "libr2"; + } + // lib32 directory has a special meaning on MIPS targets. + // It contains N32 ABI binaries. Use this folder if produce + // code for N32 ABI only. + if (tools::mips::hasMipsAbiArg(Args, "n32")) + return "lib32"; + return Triple.isArch32Bit() ? "lib" : "lib64"; + } + + // It happens that only x86 and PPC use the 'lib32' variant of oslibdir, and + // using that variant while targeting other architectures causes problems + // because the libraries are laid out in shared system roots that can't cope + // with a 'lib32' library search path being considered. So we only enable + // them when we know we may need it. + // + // FIXME: This is a bit of a hack. We should really unify this code for + // reasoning about oslibdir spellings with the lib dir spellings in the + // GCCInstallationDetector, but that is a more significant refactoring. + if (Triple.getArch() == llvm::Triple::x86 || + Triple.getArch() == llvm::Triple::ppc) + return "lib32"; + + if (Triple.getArch() == llvm::Triple::x86_64 && + Triple.getEnvironment() == llvm::Triple::GNUX32) + return "libx32"; + + return Triple.isArch32Bit() ? "lib" : "lib64"; +} + +static void addMultilibsFilePaths(const Driver &D, const MultilibSet &Multilibs, + const Multilib &Multilib, + StringRef InstallPath, + ToolChain::path_list &Paths) { + if (const auto &PathsCallback = Multilibs.filePathsCallback()) + for (const auto &Path : PathsCallback(Multilib)) + addPathIfExists(D, InstallPath + Path, Paths); +} + +Linux::Linux(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) + : Generic_ELF(D, Triple, Args) { + GCCInstallation.init(Triple, Args); + Multilibs = GCCInstallation.getMultilibs(); + llvm::Triple::ArchType Arch = Triple.getArch(); + std::string SysRoot = computeSysRoot(); + + // Cross-compiling binutils and GCC installations (vanilla and openSUSE at + // least) put various tools in a triple-prefixed directory off of the parent + // of the GCC installation. We use the GCC triple here to ensure that we end + // up with tools that support the same amount of cross compiling as the + // detected GCC installation. For example, if we find a GCC installation + // targeting x86_64, but it is a bi-arch GCC installation, it can also be + // used to target i386. + // FIXME: This seems unlikely to be Linux-specific. + ToolChain::path_list &PPaths = getProgramPaths(); + PPaths.push_back(Twine(GCCInstallation.getParentLibPath() + "/../" + + GCCInstallation.getTriple().str() + "/bin") + .str()); + + Distro Distro(D.getVFS()); + + if (Distro.IsOpenSUSE() || Distro.IsUbuntu()) { + ExtraOpts.push_back("-z"); + ExtraOpts.push_back("relro"); + } + + if (Arch == llvm::Triple::arm || Arch == llvm::Triple::thumb) + ExtraOpts.push_back("-X"); + + const bool IsAndroid = Triple.isAndroid(); + const bool IsMips = tools::isMipsArch(Arch); + const bool IsHexagon = Arch == llvm::Triple::hexagon; + + if (IsMips && !SysRoot.empty()) + ExtraOpts.push_back("--sysroot=" + SysRoot); + + // Do not use 'gnu' hash style for Mips targets because .gnu.hash + // and the MIPS ABI require .dynsym to be sorted in different ways. + // .gnu.hash needs symbols to be grouped by hash code whereas the MIPS + // ABI requires a mapping between the GOT and the symbol table. + // Android loader does not support .gnu.hash. + // Hexagon linker/loader does not support .gnu.hash + if (!IsMips && !IsAndroid && !IsHexagon) { + if (Distro.IsRedhat() || Distro.IsOpenSUSE() || + (Distro.IsUbuntu() && Distro >= Distro::UbuntuMaverick)) + ExtraOpts.push_back("--hash-style=gnu"); + + if (Distro.IsDebian() || Distro.IsOpenSUSE() || Distro == Distro::UbuntuLucid || + Distro == Distro::UbuntuJaunty || Distro == Distro::UbuntuKarmic) + ExtraOpts.push_back("--hash-style=both"); + } + + if (Distro.IsRedhat() && Distro != Distro::RHEL5 && Distro != Distro::RHEL6) + ExtraOpts.push_back("--no-add-needed"); + +#ifdef ENABLE_LINKER_BUILD_ID + ExtraOpts.push_back("--build-id"); +#endif + + if (Distro.IsOpenSUSE()) + ExtraOpts.push_back("--enable-new-dtags"); + + // The selection of paths to try here is designed to match the patterns which + // the GCC driver itself uses, as this is part of the GCC-compatible driver. + // This was determined by running GCC in a fake filesystem, creating all + // possible permutations of these directories, and seeing which ones it added + // to the link paths. + path_list &Paths = getFilePaths(); + + const std::string OSLibDir = getOSLibDir(Triple, Args); + const std::string MultiarchTriple = getMultiarchTriple(D, Triple, SysRoot); + + // Add the multilib suffixed paths where they are available. + if (GCCInstallation.isValid()) { + const llvm::Triple &GCCTriple = GCCInstallation.getTriple(); + const std::string &LibPath = GCCInstallation.getParentLibPath(); + const Multilib &Multilib = GCCInstallation.getMultilib(); + const MultilibSet &Multilibs = GCCInstallation.getMultilibs(); + + // Add toolchain / multilib specific file paths. + addMultilibsFilePaths(D, Multilibs, Multilib, + GCCInstallation.getInstallPath(), Paths); + + // Sourcery CodeBench MIPS toolchain holds some libraries under + // a biarch-like suffix of the GCC installation. + addPathIfExists(D, GCCInstallation.getInstallPath() + Multilib.gccSuffix(), + Paths); + + // GCC cross compiling toolchains will install target libraries which ship + // as part of the toolchain under <prefix>/<triple>/<libdir> rather than as + // any part of the GCC installation in + // <prefix>/<libdir>/gcc/<triple>/<version>. This decision is somewhat + // debatable, but is the reality today. We need to search this tree even + // when we have a sysroot somewhere else. It is the responsibility of + // whomever is doing the cross build targeting a sysroot using a GCC + // installation that is *not* within the system root to ensure two things: + // + // 1) Any DSOs that are linked in from this tree or from the install path + // above must be present on the system root and found via an + // appropriate rpath. + // 2) There must not be libraries installed into + // <prefix>/<triple>/<libdir> unless they should be preferred over + // those within the system root. + // + // Note that this matches the GCC behavior. See the below comment for where + // Clang diverges from GCC's behavior. + addPathIfExists(D, LibPath + "/../" + GCCTriple.str() + "/lib/../" + + OSLibDir + Multilib.osSuffix(), + Paths); + + // If the GCC installation we found is inside of the sysroot, we want to + // prefer libraries installed in the parent prefix of the GCC installation. + // It is important to *not* use these paths when the GCC installation is + // outside of the system root as that can pick up unintended libraries. + // This usually happens when there is an external cross compiler on the + // host system, and a more minimal sysroot available that is the target of + // the cross. Note that GCC does include some of these directories in some + // configurations but this seems somewhere between questionable and simply + // a bug. + if (StringRef(LibPath).startswith(SysRoot)) { + addPathIfExists(D, LibPath + "/" + MultiarchTriple, Paths); + addPathIfExists(D, LibPath + "/../" + OSLibDir, Paths); + } + } + + // Similar to the logic for GCC above, if we currently running Clang inside + // of the requested system root, add its parent library paths to + // those searched. + // FIXME: It's not clear whether we should use the driver's installed + // directory ('Dir' below) or the ResourceDir. + if (StringRef(D.Dir).startswith(SysRoot)) { + addPathIfExists(D, D.Dir + "/../lib/" + MultiarchTriple, Paths); + addPathIfExists(D, D.Dir + "/../" + OSLibDir, Paths); + } + + addPathIfExists(D, SysRoot + "/lib/" + MultiarchTriple, Paths); + addPathIfExists(D, SysRoot + "/lib/../" + OSLibDir, Paths); + addPathIfExists(D, SysRoot + "/usr/lib/" + MultiarchTriple, Paths); + addPathIfExists(D, SysRoot + "/usr/lib/../" + OSLibDir, Paths); + + // Try walking via the GCC triple path in case of biarch or multiarch GCC + // installations with strange symlinks. + if (GCCInstallation.isValid()) { + addPathIfExists(D, + SysRoot + "/usr/lib/" + GCCInstallation.getTriple().str() + + "/../../" + OSLibDir, + Paths); + + // Add the 'other' biarch variant path + Multilib BiarchSibling; + if (GCCInstallation.getBiarchSibling(BiarchSibling)) { + addPathIfExists(D, GCCInstallation.getInstallPath() + + BiarchSibling.gccSuffix(), + Paths); + } + + // See comments above on the multilib variant for details of why this is + // included even from outside the sysroot. + const std::string &LibPath = GCCInstallation.getParentLibPath(); + const llvm::Triple &GCCTriple = GCCInstallation.getTriple(); + const Multilib &Multilib = GCCInstallation.getMultilib(); + addPathIfExists(D, LibPath + "/../" + GCCTriple.str() + "/lib" + + Multilib.osSuffix(), + Paths); + + // See comments above on the multilib variant for details of why this is + // only included from within the sysroot. + if (StringRef(LibPath).startswith(SysRoot)) + addPathIfExists(D, LibPath, Paths); + } + + // Similar to the logic for GCC above, if we are currently running Clang + // inside of the requested system root, add its parent library path to those + // searched. + // FIXME: It's not clear whether we should use the driver's installed + // directory ('Dir' below) or the ResourceDir. + if (StringRef(D.Dir).startswith(SysRoot)) + addPathIfExists(D, D.Dir + "/../lib", Paths); + + addPathIfExists(D, SysRoot + "/lib", Paths); + addPathIfExists(D, SysRoot + "/usr/lib", Paths); +} + +/// \brief Parse a GCCVersion object out of a string of text. +/// +/// This is the primary means of forming GCCVersion objects. +/*static*/ +Generic_GCC::GCCVersion Linux::GCCVersion::Parse(StringRef VersionText) { + const GCCVersion BadVersion = {VersionText.str(), -1, -1, -1, "", "", ""}; + std::pair<StringRef, StringRef> First = VersionText.split('.'); + std::pair<StringRef, StringRef> Second = First.second.split('.'); + + GCCVersion GoodVersion = {VersionText.str(), -1, -1, -1, "", "", ""}; + if (First.first.getAsInteger(10, GoodVersion.Major) || GoodVersion.Major < 0) + return BadVersion; + GoodVersion.MajorStr = First.first.str(); + if (First.second.empty()) + return GoodVersion; + if (Second.first.getAsInteger(10, GoodVersion.Minor) || GoodVersion.Minor < 0) + return BadVersion; + GoodVersion.MinorStr = Second.first.str(); + + // First look for a number prefix and parse that if present. Otherwise just + // stash the entire patch string in the suffix, and leave the number + // unspecified. This covers versions strings such as: + // 5 (handled above) + // 4.4 + // 4.4.0 + // 4.4.x + // 4.4.2-rc4 + // 4.4.x-patched + // And retains any patch number it finds. + StringRef PatchText = GoodVersion.PatchSuffix = Second.second.str(); + if (!PatchText.empty()) { + if (size_t EndNumber = PatchText.find_first_not_of("0123456789")) { + // Try to parse the number and any suffix. + if (PatchText.slice(0, EndNumber).getAsInteger(10, GoodVersion.Patch) || + GoodVersion.Patch < 0) + return BadVersion; + GoodVersion.PatchSuffix = PatchText.substr(EndNumber); + } + } + + return GoodVersion; +} + +bool Linux::HasNativeLLVMSupport() const { return true; } + +Tool *Linux::buildLinker() const { return new tools::gnutools::Linker(*this); } + +Tool *Linux::buildAssembler() const { + return new tools::gnutools::Assembler(*this); +} + +std::string Linux::computeSysRoot() const { + if (!getDriver().SysRoot.empty()) + return getDriver().SysRoot; + + if (!GCCInstallation.isValid() || !tools::isMipsArch(getTriple().getArch())) + return std::string(); + + // Standalone MIPS toolchains use different names for sysroot folder + // and put it into different places. Here we try to check some known + // variants. + + const StringRef InstallDir = GCCInstallation.getInstallPath(); + const StringRef TripleStr = GCCInstallation.getTriple().str(); + const Multilib &Multilib = GCCInstallation.getMultilib(); + + std::string Path = + (InstallDir + "/../../../../" + TripleStr + "/libc" + Multilib.osSuffix()) + .str(); + + if (getVFS().exists(Path)) + return Path; + + Path = (InstallDir + "/../../../../sysroot" + Multilib.osSuffix()).str(); + + if (getVFS().exists(Path)) + return Path; + + return std::string(); +} + +std::string Linux::getDynamicLinker(const ArgList &Args) const { + const llvm::Triple::ArchType Arch = getArch(); + const llvm::Triple &Triple = getTriple(); + + const Distro Distro(getDriver().getVFS()); + + if (Triple.isAndroid()) + return Triple.isArch64Bit() ? "/system/bin/linker64" : "/system/bin/linker"; + + if (Triple.isMusl()) { + std::string ArchName; + bool IsArm = false; + + switch (Arch) { + case llvm::Triple::arm: + case llvm::Triple::thumb: + ArchName = "arm"; + IsArm = true; + break; + case llvm::Triple::armeb: + case llvm::Triple::thumbeb: + ArchName = "armeb"; + IsArm = true; + break; + default: + ArchName = Triple.getArchName().str(); + } + if (IsArm && + (Triple.getEnvironment() == llvm::Triple::MuslEABIHF || + tools::arm::getARMFloatABI(*this, Args) == tools::arm::FloatABI::Hard)) + ArchName += "hf"; + + return "/lib/ld-musl-" + ArchName + ".so.1"; + } + + std::string LibDir; + std::string Loader; + + switch (Arch) { + default: + llvm_unreachable("unsupported architecture"); + + case llvm::Triple::aarch64: + LibDir = "lib"; + Loader = "ld-linux-aarch64.so.1"; + break; + case llvm::Triple::aarch64_be: + LibDir = "lib"; + Loader = "ld-linux-aarch64_be.so.1"; + break; + case llvm::Triple::arm: + case llvm::Triple::thumb: + case llvm::Triple::armeb: + case llvm::Triple::thumbeb: { + const bool HF = + Triple.getEnvironment() == llvm::Triple::GNUEABIHF || + tools::arm::getARMFloatABI(*this, Args) == tools::arm::FloatABI::Hard; + + LibDir = "lib"; + Loader = HF ? "ld-linux-armhf.so.3" : "ld-linux.so.3"; + break; + } + case llvm::Triple::mips: + case llvm::Triple::mipsel: + case llvm::Triple::mips64: + case llvm::Triple::mips64el: { + bool LE = (Triple.getArch() == llvm::Triple::mipsel) || + (Triple.getArch() == llvm::Triple::mips64el); + bool IsNaN2008 = tools::mips::isNaN2008(Args, Triple); + + LibDir = "lib" + tools::mips::getMipsABILibSuffix(Args, Triple); + + if (tools::mips::isUCLibc(Args)) + Loader = IsNaN2008 ? "ld-uClibc-mipsn8.so.0" : "ld-uClibc.so.0"; + else if (!Triple.hasEnvironment() && + Triple.getVendor() == llvm::Triple::VendorType::MipsTechnologies) + Loader = LE ? "ld-musl-mipsel.so.1" : "ld-musl-mips.so.1"; + else + Loader = IsNaN2008 ? "ld-linux-mipsn8.so.1" : "ld.so.1"; + + break; + } + case llvm::Triple::ppc: + LibDir = "lib"; + Loader = "ld.so.1"; + break; + case llvm::Triple::ppc64: + LibDir = "lib64"; + Loader = + (tools::ppc::hasPPCAbiArg(Args, "elfv2")) ? "ld64.so.2" : "ld64.so.1"; + break; + case llvm::Triple::ppc64le: + LibDir = "lib64"; + Loader = + (tools::ppc::hasPPCAbiArg(Args, "elfv1")) ? "ld64.so.1" : "ld64.so.2"; + break; + case llvm::Triple::sparc: + case llvm::Triple::sparcel: + LibDir = "lib"; + Loader = "ld-linux.so.2"; + break; + case llvm::Triple::sparcv9: + LibDir = "lib64"; + Loader = "ld-linux.so.2"; + break; + case llvm::Triple::systemz: + LibDir = "lib"; + Loader = "ld64.so.1"; + break; + case llvm::Triple::x86: + LibDir = "lib"; + Loader = "ld-linux.so.2"; + break; + case llvm::Triple::x86_64: { + bool X32 = Triple.getEnvironment() == llvm::Triple::GNUX32; + + LibDir = X32 ? "libx32" : "lib64"; + Loader = X32 ? "ld-linux-x32.so.2" : "ld-linux-x86-64.so.2"; + break; + } + } + + if (Distro == Distro::Exherbo && (Triple.getVendor() == llvm::Triple::UnknownVendor || + Triple.getVendor() == llvm::Triple::PC)) + return "/usr/" + Triple.str() + "/lib/" + Loader; + return "/" + LibDir + "/" + Loader; +} + +void Linux::AddClangSystemIncludeArgs(const ArgList &DriverArgs, + ArgStringList &CC1Args) const { + const Driver &D = getDriver(); + std::string SysRoot = computeSysRoot(); + + if (DriverArgs.hasArg(clang::driver::options::OPT_nostdinc)) + return; + + if (!DriverArgs.hasArg(options::OPT_nostdlibinc)) + addSystemInclude(DriverArgs, CC1Args, SysRoot + "/usr/local/include"); + + if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) { + SmallString<128> P(D.ResourceDir); + llvm::sys::path::append(P, "include"); + addSystemInclude(DriverArgs, CC1Args, P); + } + + if (DriverArgs.hasArg(options::OPT_nostdlibinc)) + return; + + // Check for configure-time C include directories. + StringRef CIncludeDirs(C_INCLUDE_DIRS); + if (CIncludeDirs != "") { + SmallVector<StringRef, 5> dirs; + CIncludeDirs.split(dirs, ":"); + for (StringRef dir : dirs) { + StringRef Prefix = + llvm::sys::path::is_absolute(dir) ? StringRef(SysRoot) : ""; + addExternCSystemInclude(DriverArgs, CC1Args, Prefix + dir); + } + return; + } + + // Lacking those, try to detect the correct set of system includes for the + // target triple. + + // Add include directories specific to the selected multilib set and multilib. + if (GCCInstallation.isValid()) { + const auto &Callback = Multilibs.includeDirsCallback(); + if (Callback) { + for (const auto &Path : Callback(GCCInstallation.getMultilib())) + addExternCSystemIncludeIfExists( + DriverArgs, CC1Args, GCCInstallation.getInstallPath() + Path); + } + } + + // Implement generic Debian multiarch support. + const StringRef X86_64MultiarchIncludeDirs[] = { + "/usr/include/x86_64-linux-gnu", + + // FIXME: These are older forms of multiarch. It's not clear that they're + // in use in any released version of Debian, so we should consider + // removing them. + "/usr/include/i686-linux-gnu/64", "/usr/include/i486-linux-gnu/64"}; + const StringRef X86MultiarchIncludeDirs[] = { + "/usr/include/i386-linux-gnu", + + // FIXME: These are older forms of multiarch. It's not clear that they're + // in use in any released version of Debian, so we should consider + // removing them. + "/usr/include/x86_64-linux-gnu/32", "/usr/include/i686-linux-gnu", + "/usr/include/i486-linux-gnu"}; + const StringRef AArch64MultiarchIncludeDirs[] = { + "/usr/include/aarch64-linux-gnu"}; + const StringRef ARMMultiarchIncludeDirs[] = { + "/usr/include/arm-linux-gnueabi"}; + const StringRef ARMHFMultiarchIncludeDirs[] = { + "/usr/include/arm-linux-gnueabihf"}; + const StringRef ARMEBMultiarchIncludeDirs[] = { + "/usr/include/armeb-linux-gnueabi"}; + const StringRef ARMEBHFMultiarchIncludeDirs[] = { + "/usr/include/armeb-linux-gnueabihf"}; + const StringRef MIPSMultiarchIncludeDirs[] = {"/usr/include/mips-linux-gnu"}; + const StringRef MIPSELMultiarchIncludeDirs[] = { + "/usr/include/mipsel-linux-gnu"}; + const StringRef MIPS64MultiarchIncludeDirs[] = { + "/usr/include/mips64-linux-gnu", "/usr/include/mips64-linux-gnuabi64"}; + const StringRef MIPS64ELMultiarchIncludeDirs[] = { + "/usr/include/mips64el-linux-gnu", + "/usr/include/mips64el-linux-gnuabi64"}; + const StringRef PPCMultiarchIncludeDirs[] = { + "/usr/include/powerpc-linux-gnu"}; + const StringRef PPC64MultiarchIncludeDirs[] = { + "/usr/include/powerpc64-linux-gnu"}; + const StringRef PPC64LEMultiarchIncludeDirs[] = { + "/usr/include/powerpc64le-linux-gnu"}; + const StringRef SparcMultiarchIncludeDirs[] = { + "/usr/include/sparc-linux-gnu"}; + const StringRef Sparc64MultiarchIncludeDirs[] = { + "/usr/include/sparc64-linux-gnu"}; + const StringRef SYSTEMZMultiarchIncludeDirs[] = { + "/usr/include/s390x-linux-gnu"}; + ArrayRef<StringRef> MultiarchIncludeDirs; + switch (getTriple().getArch()) { + case llvm::Triple::x86_64: + MultiarchIncludeDirs = X86_64MultiarchIncludeDirs; + break; + case llvm::Triple::x86: + MultiarchIncludeDirs = X86MultiarchIncludeDirs; + break; + case llvm::Triple::aarch64: + case llvm::Triple::aarch64_be: + MultiarchIncludeDirs = AArch64MultiarchIncludeDirs; + break; + case llvm::Triple::arm: + case llvm::Triple::thumb: + if (getTriple().getEnvironment() == llvm::Triple::GNUEABIHF) + MultiarchIncludeDirs = ARMHFMultiarchIncludeDirs; + else + MultiarchIncludeDirs = ARMMultiarchIncludeDirs; + break; + case llvm::Triple::armeb: + case llvm::Triple::thumbeb: + if (getTriple().getEnvironment() == llvm::Triple::GNUEABIHF) + MultiarchIncludeDirs = ARMEBHFMultiarchIncludeDirs; + else + MultiarchIncludeDirs = ARMEBMultiarchIncludeDirs; + break; + case llvm::Triple::mips: + MultiarchIncludeDirs = MIPSMultiarchIncludeDirs; + break; + case llvm::Triple::mipsel: + MultiarchIncludeDirs = MIPSELMultiarchIncludeDirs; + break; + case llvm::Triple::mips64: + MultiarchIncludeDirs = MIPS64MultiarchIncludeDirs; + break; + case llvm::Triple::mips64el: + MultiarchIncludeDirs = MIPS64ELMultiarchIncludeDirs; + break; + case llvm::Triple::ppc: + MultiarchIncludeDirs = PPCMultiarchIncludeDirs; + break; + case llvm::Triple::ppc64: + MultiarchIncludeDirs = PPC64MultiarchIncludeDirs; + break; + case llvm::Triple::ppc64le: + MultiarchIncludeDirs = PPC64LEMultiarchIncludeDirs; + break; + case llvm::Triple::sparc: + MultiarchIncludeDirs = SparcMultiarchIncludeDirs; + break; + case llvm::Triple::sparcv9: + MultiarchIncludeDirs = Sparc64MultiarchIncludeDirs; + break; + case llvm::Triple::systemz: + MultiarchIncludeDirs = SYSTEMZMultiarchIncludeDirs; + break; + default: + break; + } + for (StringRef Dir : MultiarchIncludeDirs) { + if (D.getVFS().exists(SysRoot + Dir)) { + addExternCSystemInclude(DriverArgs, CC1Args, SysRoot + Dir); + break; + } + } + + if (getTriple().getOS() == llvm::Triple::RTEMS) + return; + + // Add an include of '/include' directly. This isn't provided by default by + // system GCCs, but is often used with cross-compiling GCCs, and harmless to + // add even when Clang is acting as-if it were a system compiler. + addExternCSystemInclude(DriverArgs, CC1Args, SysRoot + "/include"); + + addExternCSystemInclude(DriverArgs, CC1Args, SysRoot + "/usr/include"); +} + +static std::string DetectLibcxxIncludePath(StringRef base) { + std::error_code EC; + int MaxVersion = 0; + std::string MaxVersionString = ""; + for (llvm::sys::fs::directory_iterator LI(base, EC), LE; !EC && LI != LE; + LI = LI.increment(EC)) { + StringRef VersionText = llvm::sys::path::filename(LI->path()); + int Version; + if (VersionText[0] == 'v' && + !VersionText.slice(1, StringRef::npos).getAsInteger(10, Version)) { + if (Version > MaxVersion) { + MaxVersion = Version; + MaxVersionString = VersionText; + } + } + } + return MaxVersion ? (base + "/" + MaxVersionString).str() : ""; +} + +std::string Linux::findLibCxxIncludePath() const { + const std::string LibCXXIncludePathCandidates[] = { + DetectLibcxxIncludePath(getDriver().Dir + "/../include/c++"), + // If this is a development, non-installed, clang, libcxx will + // not be found at ../include/c++ but it likely to be found at + // one of the following two locations: + DetectLibcxxIncludePath(getDriver().SysRoot + "/usr/local/include/c++"), + DetectLibcxxIncludePath(getDriver().SysRoot + "/usr/include/c++") }; + for (const auto &IncludePath : LibCXXIncludePathCandidates) { + if (IncludePath.empty() || !getVFS().exists(IncludePath)) + continue; + // Use the first candidate that exists. + return IncludePath; + } + return ""; +} + +void Linux::addLibStdCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const { + // We need a detected GCC installation on Linux to provide libstdc++'s + // headers. + if (!GCCInstallation.isValid()) + return; + + // By default, look for the C++ headers in an include directory adjacent to + // the lib directory of the GCC installation. Note that this is expect to be + // equivalent to '/usr/include/c++/X.Y' in almost all cases. + StringRef LibDir = GCCInstallation.getParentLibPath(); + StringRef InstallDir = GCCInstallation.getInstallPath(); + StringRef TripleStr = GCCInstallation.getTriple().str(); + const Multilib &Multilib = GCCInstallation.getMultilib(); + const std::string GCCMultiarchTriple = getMultiarchTriple( + getDriver(), GCCInstallation.getTriple(), getDriver().SysRoot); + const std::string TargetMultiarchTriple = + getMultiarchTriple(getDriver(), getTriple(), getDriver().SysRoot); + const GCCVersion &Version = GCCInstallation.getVersion(); + + // The primary search for libstdc++ supports multiarch variants. + if (addLibStdCXXIncludePaths(LibDir.str() + "/../include", + "/c++/" + Version.Text, TripleStr, + GCCMultiarchTriple, TargetMultiarchTriple, + Multilib.includeSuffix(), DriverArgs, CC1Args)) + return; + + // Otherwise, fall back on a bunch of options which don't use multiarch + // layouts for simplicity. + const std::string LibStdCXXIncludePathCandidates[] = { + // Gentoo is weird and places its headers inside the GCC install, + // so if the first attempt to find the headers fails, try these patterns. + InstallDir.str() + "/include/g++-v" + Version.Text, + InstallDir.str() + "/include/g++-v" + Version.MajorStr + "." + + Version.MinorStr, + InstallDir.str() + "/include/g++-v" + Version.MajorStr, + // Android standalone toolchain has C++ headers in yet another place. + LibDir.str() + "/../" + TripleStr.str() + "/include/c++/" + Version.Text, + // Freescale SDK C++ headers are directly in <sysroot>/usr/include/c++, + // without a subdirectory corresponding to the gcc version. + LibDir.str() + "/../include/c++", + }; + + for (const auto &IncludePath : LibStdCXXIncludePathCandidates) { + if (addLibStdCXXIncludePaths(IncludePath, /*Suffix*/ "", TripleStr, + /*GCCMultiarchTriple*/ "", + /*TargetMultiarchTriple*/ "", + Multilib.includeSuffix(), DriverArgs, CC1Args)) + break; + } +} + +void Linux::AddCudaIncludeArgs(const ArgList &DriverArgs, + ArgStringList &CC1Args) const { + CudaInstallation.AddCudaIncludeArgs(DriverArgs, CC1Args); +} + +void Linux::AddIAMCUIncludeArgs(const ArgList &DriverArgs, + ArgStringList &CC1Args) const { + if (GCCInstallation.isValid()) { + CC1Args.push_back("-isystem"); + CC1Args.push_back(DriverArgs.MakeArgString( + GCCInstallation.getParentLibPath() + "/../" + + GCCInstallation.getTriple().str() + "/include")); + } +} + +bool Linux::isPIEDefault() const { return getSanitizerArgs().requiresPIE(); } + +SanitizerMask Linux::getSupportedSanitizers() const { + const bool IsX86 = getTriple().getArch() == llvm::Triple::x86; + const bool IsX86_64 = getTriple().getArch() == llvm::Triple::x86_64; + const bool IsMIPS64 = getTriple().getArch() == llvm::Triple::mips64 || + getTriple().getArch() == llvm::Triple::mips64el; + const bool IsPowerPC64 = getTriple().getArch() == llvm::Triple::ppc64 || + getTriple().getArch() == llvm::Triple::ppc64le; + const bool IsAArch64 = getTriple().getArch() == llvm::Triple::aarch64 || + getTriple().getArch() == llvm::Triple::aarch64_be; + SanitizerMask Res = ToolChain::getSupportedSanitizers(); + Res |= SanitizerKind::Address; + Res |= SanitizerKind::KernelAddress; + Res |= SanitizerKind::Vptr; + Res |= SanitizerKind::SafeStack; + if (IsX86_64 || IsMIPS64 || IsAArch64) + Res |= SanitizerKind::DataFlow; + if (IsX86_64 || IsMIPS64 || IsAArch64 || IsX86) + Res |= SanitizerKind::Leak; + if (IsX86_64 || IsMIPS64 || IsAArch64 || IsPowerPC64) + Res |= SanitizerKind::Thread; + if (IsX86_64 || IsMIPS64 || IsPowerPC64 || IsAArch64) + Res |= SanitizerKind::Memory; + if (IsX86_64 || IsMIPS64) + Res |= SanitizerKind::Efficiency; + if (IsX86 || IsX86_64) { + Res |= SanitizerKind::Function; + } + return Res; +} + +void Linux::addProfileRTLibs(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) const { + if (!needsProfileRT(Args)) return; + + // Add linker option -u__llvm_runtime_variable to cause runtime + // initialization module to be linked in. + if (!Args.hasArg(options::OPT_coverage)) + CmdArgs.push_back(Args.MakeArgString( + Twine("-u", llvm::getInstrProfRuntimeHookVarName()))); + ToolChain::addProfileRTLibs(Args, CmdArgs); +} diff --git a/lib/Driver/ToolChains/Linux.h b/lib/Driver/ToolChains/Linux.h new file mode 100644 index 0000000000..9778c1832c --- /dev/null +++ b/lib/Driver/ToolChains/Linux.h @@ -0,0 +1,57 @@ +//===--- Linux.h - Linux 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_LINUX_H +#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_LINUX_H + +#include "Gnu.h" +#include "clang/Driver/ToolChain.h" + +namespace clang { +namespace driver { +namespace toolchains { + +class LLVM_LIBRARY_VISIBILITY Linux : public Generic_ELF { +public: + Linux(const Driver &D, const llvm::Triple &Triple, + const llvm::opt::ArgList &Args); + + bool HasNativeLLVMSupport() const override; + + void + AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const override; + std::string findLibCxxIncludePath() const override; + void addLibStdCxxIncludePaths( + const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const override; + void AddCudaIncludeArgs(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const override; + void AddIAMCUIncludeArgs(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const override; + bool isPIEDefault() const override; + SanitizerMask getSupportedSanitizers() const override; + void addProfileRTLibs(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) const override; + virtual std::string computeSysRoot() const; + + virtual std::string getDynamicLinker(const llvm::opt::ArgList &Args) const; + + std::vector<std::string> ExtraOpts; + +protected: + Tool *buildAssembler() const override; + Tool *buildLinker() const override; +}; + +} // end namespace toolchains +} // end namespace driver +} // end namespace clang + +#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_LINUX_H diff --git a/lib/Driver/MSVCToolChain.cpp b/lib/Driver/ToolChains/MSVC.cpp index 17fd6ac6f7..7996627f57 100644 --- a/lib/Driver/MSVCToolChain.cpp +++ b/lib/Driver/ToolChains/MSVC.cpp @@ -7,14 +7,16 @@ // //===----------------------------------------------------------------------===// -#include "ToolChains.h" -#include "Tools.h" +#include "Darwin.h" +#include "MSVC.h" +#include "CommonArgs.h" #include "clang/Basic/CharInfo.h" #include "clang/Basic/Version.h" #include "clang/Driver/Compilation.h" #include "clang/Driver/Driver.h" #include "clang/Driver/DriverDiagnostic.h" #include "clang/Driver/Options.h" +#include "clang/Driver/SanitizerArgs.h" #include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringSwitch.h" #include "llvm/Config/llvm-config.h" @@ -44,9 +46,348 @@ using namespace clang::driver; using namespace clang::driver::toolchains; +using namespace clang::driver::tools; using namespace clang; using namespace llvm::opt; +// Try to find Exe from a Visual Studio distribution. This first tries to find +// an installed copy of Visual Studio and, failing that, looks in the PATH, +// making sure that whatever executable that's found is not a same-named exe +// from clang itself to prevent clang from falling back to itself. +static std::string FindVisualStudioExecutable(const ToolChain &TC, + const char *Exe, + const char *ClangProgramPath) { + const auto &MSVC = static_cast<const toolchains::MSVCToolChain &>(TC); + std::string visualStudioBinDir; + if (MSVC.getVisualStudioBinariesFolder(ClangProgramPath, + visualStudioBinDir)) { + SmallString<128> FilePath(visualStudioBinDir); + llvm::sys::path::append(FilePath, Exe); + if (llvm::sys::fs::can_execute(FilePath.c_str())) + return FilePath.str(); + } + + return Exe; +} + +void visualstudio::Linker::ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, + const InputInfoList &Inputs, + const ArgList &Args, + const char *LinkingOutput) const { + ArgStringList CmdArgs; + const ToolChain &TC = getToolChain(); + + assert((Output.isFilename() || Output.isNothing()) && "invalid output"); + if (Output.isFilename()) + CmdArgs.push_back( + Args.MakeArgString(std::string("-out:") + Output.getFilename())); + + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles) && + !C.getDriver().IsCLMode()) + CmdArgs.push_back("-defaultlib:libcmt"); + + if (!llvm::sys::Process::GetEnv("LIB")) { + // If the VC environment hasn't been configured (perhaps because the user + // did not run vcvarsall), try to build a consistent link environment. If + // the environment variable is set however, assume the user knows what + // they're doing. + std::string VisualStudioDir; + const auto &MSVC = static_cast<const toolchains::MSVCToolChain &>(TC); + if (MSVC.getVisualStudioInstallDir(VisualStudioDir)) { + SmallString<128> LibDir(VisualStudioDir); + llvm::sys::path::append(LibDir, "VC", "lib"); + switch (MSVC.getArch()) { + case llvm::Triple::x86: + // x86 just puts the libraries directly in lib + break; + case llvm::Triple::x86_64: + llvm::sys::path::append(LibDir, "amd64"); + break; + case llvm::Triple::arm: + llvm::sys::path::append(LibDir, "arm"); + break; + default: + break; + } + CmdArgs.push_back( + Args.MakeArgString(std::string("-libpath:") + LibDir.c_str())); + + if (MSVC.useUniversalCRT(VisualStudioDir)) { + std::string UniversalCRTLibPath; + if (MSVC.getUniversalCRTLibraryPath(UniversalCRTLibPath)) + CmdArgs.push_back(Args.MakeArgString(std::string("-libpath:") + + UniversalCRTLibPath)); + } + } + + std::string WindowsSdkLibPath; + if (MSVC.getWindowsSDKLibraryPath(WindowsSdkLibPath)) + CmdArgs.push_back( + Args.MakeArgString(std::string("-libpath:") + WindowsSdkLibPath)); + } + + if (!C.getDriver().IsCLMode() && Args.hasArg(options::OPT_L)) + for (const auto &LibPath : Args.getAllArgValues(options::OPT_L)) + CmdArgs.push_back(Args.MakeArgString("-libpath:" + LibPath)); + + CmdArgs.push_back("-nologo"); + + if (Args.hasArg(options::OPT_g_Group, options::OPT__SLASH_Z7, + options::OPT__SLASH_Zd)) + CmdArgs.push_back("-debug"); + + bool DLL = Args.hasArg(options::OPT__SLASH_LD, options::OPT__SLASH_LDd, + options::OPT_shared); + if (DLL) { + CmdArgs.push_back(Args.MakeArgString("-dll")); + + SmallString<128> ImplibName(Output.getFilename()); + llvm::sys::path::replace_extension(ImplibName, "lib"); + CmdArgs.push_back(Args.MakeArgString(std::string("-implib:") + ImplibName)); + } + + if (TC.getSanitizerArgs().needsAsanRt()) { + CmdArgs.push_back(Args.MakeArgString("-debug")); + CmdArgs.push_back(Args.MakeArgString("-incremental:no")); + if (TC.getSanitizerArgs().needsSharedAsanRt() || + 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)); + // Make sure the dynamic runtime thunk is not optimized out at link time + // to ensure proper SEH handling. + CmdArgs.push_back(Args.MakeArgString( + TC.getArch() == llvm::Triple::x86 + ? "-include:___asan_seh_interceptor" + : "-include:__asan_seh_interceptor")); + // Make sure the linker consider all object files from the dynamic runtime + // thunk. + CmdArgs.push_back(Args.MakeArgString(std::string("-wholearchive:") + + TC.getCompilerRT(Args, "asan_dynamic_runtime_thunk"))); + } else if (DLL) { + CmdArgs.push_back(TC.getCompilerRTArgString(Args, "asan_dll_thunk")); + } else { + for (const auto &Lib : {"asan", "asan_cxx"}) { + CmdArgs.push_back(TC.getCompilerRTArgString(Args, Lib)); + // Make sure the linker consider all object files from the static lib. + // This is necessary because instrumented dlls need access to all the + // interface exported by the static lib in the main executable. + CmdArgs.push_back(Args.MakeArgString(std::string("-wholearchive:") + + TC.getCompilerRT(Args, Lib))); + } + } + } + + Args.AddAllArgValues(CmdArgs, options::OPT__SLASH_link); + + if (Args.hasFlag(options::OPT_fopenmp, options::OPT_fopenmp_EQ, + options::OPT_fno_openmp, false)) { + CmdArgs.push_back("-nodefaultlib:vcomp.lib"); + CmdArgs.push_back("-nodefaultlib:vcompd.lib"); + CmdArgs.push_back(Args.MakeArgString(std::string("-libpath:") + + TC.getDriver().Dir + "/../lib")); + switch (TC.getDriver().getOpenMPRuntime(Args)) { + case Driver::OMPRT_OMP: + CmdArgs.push_back("-defaultlib:libomp.lib"); + break; + case Driver::OMPRT_IOMP5: + CmdArgs.push_back("-defaultlib:libiomp5md.lib"); + break; + case Driver::OMPRT_GOMP: + break; + case Driver::OMPRT_Unknown: + // Already diagnosed. + break; + } + } + + // Add compiler-rt lib in case if it was explicitly + // specified as an argument for --rtlib option. + if (!Args.hasArg(options::OPT_nostdlib)) { + AddRunTimeLibs(TC, TC.getDriver(), CmdArgs, Args); + } + + // Add filenames, libraries, and other linker inputs. + for (const auto &Input : Inputs) { + if (Input.isFilename()) { + CmdArgs.push_back(Input.getFilename()); + continue; + } + + const Arg &A = Input.getInputArg(); + + // Render -l options differently for the MSVC linker. + if (A.getOption().matches(options::OPT_l)) { + StringRef Lib = A.getValue(); + const char *LinkLibArg; + if (Lib.endswith(".lib")) + LinkLibArg = Args.MakeArgString(Lib); + else + LinkLibArg = Args.MakeArgString(Lib + ".lib"); + CmdArgs.push_back(LinkLibArg); + continue; + } + + // Otherwise, this is some other kind of linker input option like -Wl, -z, + // or -L. Render it, even if MSVC doesn't understand it. + A.renderAsInput(Args, CmdArgs); + } + + TC.addProfileRTLibs(Args, CmdArgs); + + // We need to special case some linker paths. In the case of lld, we need to + // translate 'lld' into 'lld-link', and in the case of the regular msvc + // linker, we need to use a special search algorithm. + llvm::SmallString<128> linkPath; + StringRef Linker = Args.getLastArgValue(options::OPT_fuse_ld_EQ, "link"); + if (Linker.equals_lower("lld")) + Linker = "lld-link"; + + if (Linker.equals_lower("link")) { + // If we're using the MSVC linker, it's not sufficient to just use link + // from the program PATH, because other environments like GnuWin32 install + // their own link.exe which may come first. + linkPath = FindVisualStudioExecutable(TC, "link.exe", + C.getDriver().getClangProgramPath()); + } else { + linkPath = Linker; + llvm::sys::path::replace_extension(linkPath, "exe"); + linkPath = TC.GetProgramPath(linkPath.c_str()); + } + + const char *Exec = Args.MakeArgString(linkPath); + C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); +} + +void visualstudio::Compiler::ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, + const InputInfoList &Inputs, + const ArgList &Args, + const char *LinkingOutput) const { + C.addCommand(GetCommand(C, JA, Output, Inputs, Args, LinkingOutput)); +} + +std::unique_ptr<Command> visualstudio::Compiler::GetCommand( + Compilation &C, const JobAction &JA, const InputInfo &Output, + const InputInfoList &Inputs, const ArgList &Args, + const char *LinkingOutput) const { + ArgStringList CmdArgs; + CmdArgs.push_back("/nologo"); + CmdArgs.push_back("/c"); // Compile only. + CmdArgs.push_back("/W0"); // No warnings. + + // The goal is to be able to invoke this tool correctly based on + // any flag accepted by clang-cl. + + // These are spelled the same way in clang and cl.exe,. + Args.AddAllArgs(CmdArgs, {options::OPT_D, options::OPT_U, options::OPT_I}); + + // Optimization level. + if (Arg *A = Args.getLastArg(options::OPT_fbuiltin, options::OPT_fno_builtin)) + CmdArgs.push_back(A->getOption().getID() == options::OPT_fbuiltin ? "/Oi" + : "/Oi-"); + if (Arg *A = Args.getLastArg(options::OPT_O, options::OPT_O0)) { + if (A->getOption().getID() == options::OPT_O0) { + CmdArgs.push_back("/Od"); + } else { + CmdArgs.push_back("/Og"); + + StringRef OptLevel = A->getValue(); + if (OptLevel == "s" || OptLevel == "z") + CmdArgs.push_back("/Os"); + else + CmdArgs.push_back("/Ot"); + + CmdArgs.push_back("/Ob2"); + } + } + if (Arg *A = Args.getLastArg(options::OPT_fomit_frame_pointer, + options::OPT_fno_omit_frame_pointer)) + CmdArgs.push_back(A->getOption().getID() == options::OPT_fomit_frame_pointer + ? "/Oy" + : "/Oy-"); + if (!Args.hasArg(options::OPT_fwritable_strings)) + CmdArgs.push_back("/GF"); + + // Flags for which clang-cl has an alias. + // FIXME: How can we ensure this stays in sync with relevant clang-cl options? + + if (Args.hasFlag(options::OPT__SLASH_GR_, options::OPT__SLASH_GR, + /*default=*/false)) + CmdArgs.push_back("/GR-"); + + if (Args.hasFlag(options::OPT__SLASH_GS_, options::OPT__SLASH_GS, + /*default=*/false)) + CmdArgs.push_back("/GS-"); + + if (Arg *A = Args.getLastArg(options::OPT_ffunction_sections, + options::OPT_fno_function_sections)) + CmdArgs.push_back(A->getOption().getID() == options::OPT_ffunction_sections + ? "/Gy" + : "/Gy-"); + if (Arg *A = Args.getLastArg(options::OPT_fdata_sections, + options::OPT_fno_data_sections)) + CmdArgs.push_back( + A->getOption().getID() == options::OPT_fdata_sections ? "/Gw" : "/Gw-"); + if (Args.hasArg(options::OPT_fsyntax_only)) + CmdArgs.push_back("/Zs"); + if (Args.hasArg(options::OPT_g_Flag, options::OPT_gline_tables_only, + options::OPT__SLASH_Z7)) + CmdArgs.push_back("/Z7"); + + std::vector<std::string> Includes = + Args.getAllArgValues(options::OPT_include); + for (const auto &Include : Includes) + CmdArgs.push_back(Args.MakeArgString(std::string("/FI") + Include)); + + // Flags that can simply be passed through. + Args.AddAllArgs(CmdArgs, options::OPT__SLASH_LD); + Args.AddAllArgs(CmdArgs, options::OPT__SLASH_LDd); + Args.AddAllArgs(CmdArgs, options::OPT__SLASH_GX); + Args.AddAllArgs(CmdArgs, options::OPT__SLASH_GX_); + Args.AddAllArgs(CmdArgs, options::OPT__SLASH_EH); + Args.AddAllArgs(CmdArgs, options::OPT__SLASH_Zl); + + // The order of these flags is relevant, so pick the last one. + if (Arg *A = Args.getLastArg(options::OPT__SLASH_MD, options::OPT__SLASH_MDd, + options::OPT__SLASH_MT, options::OPT__SLASH_MTd)) + A->render(Args, CmdArgs); + + // Use MSVC's default threadsafe statics behaviour unless there was a flag. + if (Arg *A = Args.getLastArg(options::OPT_fthreadsafe_statics, + options::OPT_fno_threadsafe_statics)) { + CmdArgs.push_back(A->getOption().getID() == options::OPT_fthreadsafe_statics + ? "/Zc:threadSafeInit" + : "/Zc:threadSafeInit-"); + } + + // Pass through all unknown arguments so that the fallback command can see + // them too. + Args.AddAllArgs(CmdArgs, options::OPT_UNKNOWN); + + // Input filename. + assert(Inputs.size() == 1); + const InputInfo &II = Inputs[0]; + assert(II.getType() == types::TY_C || II.getType() == types::TY_CXX); + CmdArgs.push_back(II.getType() == types::TY_C ? "/Tc" : "/Tp"); + if (II.isFilename()) + CmdArgs.push_back(II.getFilename()); + else + II.getInputArg().renderAsInput(Args, CmdArgs); + + // Output filename. + assert(Output.getType() == types::TY_Object); + const char *Fo = + Args.MakeArgString(std::string("/Fo") + Output.getFilename()); + CmdArgs.push_back(Fo); + + const Driver &D = getToolChain().getDriver(); + std::string Exec = FindVisualStudioExecutable(getToolChain(), "cl.exe", + D.getClangProgramPath()); + return llvm::make_unique<Command>(JA, *this, Args.MakeArgString(Exec), + CmdArgs, Inputs); +} + MSVCToolChain::MSVCToolChain(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) : ToolChain(D, Triple, Args), CudaInstallation(D, Triple, Args) { diff --git a/lib/Driver/ToolChains/MSVC.h b/lib/Driver/ToolChains/MSVC.h new file mode 100644 index 0000000000..2b2f3e2d20 --- /dev/null +++ b/lib/Driver/ToolChains/MSVC.h @@ -0,0 +1,133 @@ +//===--- MSVC.h - MSVC 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_MSVC_H +#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_MSVC_H + +#include "Cuda.h" +#include "clang/Driver/Compilation.h" +#include "clang/Driver/Tool.h" +#include "clang/Driver/ToolChain.h" + +namespace clang { +namespace driver { +namespace tools { + +/// Visual studio tools. +namespace visualstudio { +class LLVM_LIBRARY_VISIBILITY Linker : public Tool { +public: + Linker(const ToolChain &TC) + : Tool("visualstudio::Linker", "linker", TC, RF_Full, + llvm::sys::WEM_UTF16) {} + + 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; +}; + +class LLVM_LIBRARY_VISIBILITY Compiler : public Tool { +public: + Compiler(const ToolChain &TC) + : Tool("visualstudio::Compiler", "compiler", TC, RF_Full, + llvm::sys::WEM_UTF16) {} + + bool hasIntegratedAssembler() const override { return true; } + bool hasIntegratedCPP() const override { return true; } + bool isLinkJob() 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; + + std::unique_ptr<Command> GetCommand(Compilation &C, const JobAction &JA, + const InputInfo &Output, + const InputInfoList &Inputs, + const llvm::opt::ArgList &TCArgs, + const char *LinkingOutput) const; +}; +} // end namespace visualstudio + +} // end namespace tools + +namespace toolchains { + +class LLVM_LIBRARY_VISIBILITY MSVCToolChain : public ToolChain { +public: + MSVCToolChain(const Driver &D, const llvm::Triple &Triple, + const llvm::opt::ArgList &Args); + + llvm::opt::DerivedArgList * + TranslateArgs(const llvm::opt::DerivedArgList &Args, StringRef BoundArch, + Action::OffloadKind DeviceOffloadKind) const override; + + bool IsIntegratedAssemblerDefault() const override; + bool IsUnwindTablesDefault() const override; + bool isPICDefault() const override; + bool isPIEDefault() const override; + bool isPICDefaultForced() const override; + + void + AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const override; + void AddClangCXXStdlibIncludeArgs( + const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const override; + + void AddCudaIncludeArgs(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const override; + + bool getWindowsSDKDir(std::string &path, int &major, + std::string &windowsSDKIncludeVersion, + std::string &windowsSDKLibVersion) const; + bool getWindowsSDKLibraryPath(std::string &path) const; + /// \brief Check if Universal CRT should be used if available + bool useUniversalCRT(std::string &visualStudioDir) const; + bool getUniversalCRTSdkDir(std::string &path, std::string &ucrtVersion) const; + bool getUniversalCRTLibraryPath(std::string &path) const; + bool getVisualStudioInstallDir(std::string &path) const; + bool getVisualStudioBinariesFolder(const char *clangProgramPath, + std::string &path) const; + VersionTuple + computeMSVCVersion(const Driver *D, + const llvm::opt::ArgList &Args) const override; + + std::string ComputeEffectiveClangTriple(const llvm::opt::ArgList &Args, + types::ID InputType) const override; + SanitizerMask getSupportedSanitizers() const override; + + void printVerboseInfo(raw_ostream &OS) const override; + +protected: + void AddSystemIncludeWithSubfolder(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args, + const std::string &folder, + const Twine &subfolder1, + const Twine &subfolder2 = "", + const Twine &subfolder3 = "") const; + + Tool *buildLinker() const override; + Tool *buildAssembler() const override; +private: + VersionTuple getMSVCVersionFromTriple() const; + VersionTuple getMSVCVersionFromExe() const; + + CudaInstallationDetector CudaInstallation; +}; + +} // end namespace toolchains +} // end namespace driver +} // end namespace clang + +#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_MSVC_H diff --git a/lib/Driver/ToolChains/MinGW.cpp b/lib/Driver/ToolChains/MinGW.cpp new file mode 100644 index 0000000000..ca5bf06f7e --- /dev/null +++ b/lib/Driver/ToolChains/MinGW.cpp @@ -0,0 +1,471 @@ +//===--- MinGW.cpp - MinGWToolChain Implementation ------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "MinGW.h" +#include "InputInfo.h" +#include "CommonArgs.h" +#include "clang/Driver/Compilation.h" +#include "clang/Driver/Driver.h" +#include "clang/Driver/DriverDiagnostic.h" +#include "clang/Driver/Options.h" +#include "llvm/Option/ArgList.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/Path.h" +#include <system_error> + +using namespace clang::diag; +using namespace clang::driver; +using namespace clang; +using namespace llvm::opt; + +/// MinGW Tools +void tools::MinGW::Assembler::ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, + const InputInfoList &Inputs, + const ArgList &Args, + const char *LinkingOutput) const { + claimNoWarnArgs(Args); + ArgStringList CmdArgs; + + if (getToolChain().getArch() == llvm::Triple::x86) { + CmdArgs.push_back("--32"); + } else if (getToolChain().getArch() == llvm::Triple::x86_64) { + CmdArgs.push_back("--64"); + } + + 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)); + + if (Args.hasArg(options::OPT_gsplit_dwarf)) + SplitDebugInfo(getToolChain(), C, *this, JA, Args, Output, + SplitDebugName(Args, Inputs[0])); +} + +void tools::MinGW::Linker::AddLibGCC(const ArgList &Args, + ArgStringList &CmdArgs) const { + if (Args.hasArg(options::OPT_mthreads)) + CmdArgs.push_back("-lmingwthrd"); + CmdArgs.push_back("-lmingw32"); + + // Make use of compiler-rt if --rtlib option is used + ToolChain::RuntimeLibType RLT = getToolChain().GetRuntimeLibType(Args); + if (RLT == ToolChain::RLT_Libgcc) { + bool Static = Args.hasArg(options::OPT_static_libgcc) || + Args.hasArg(options::OPT_static); + bool Shared = Args.hasArg(options::OPT_shared); + bool CXX = getToolChain().getDriver().CCCIsCXX(); + + if (Static || (!CXX && !Shared)) { + CmdArgs.push_back("-lgcc"); + CmdArgs.push_back("-lgcc_eh"); + } else { + CmdArgs.push_back("-lgcc_s"); + CmdArgs.push_back("-lgcc"); + } + } else { + AddRunTimeLibs(getToolChain(), getToolChain().getDriver(), CmdArgs, Args); + } + + CmdArgs.push_back("-lmoldname"); + CmdArgs.push_back("-lmingwex"); + CmdArgs.push_back("-lmsvcrt"); +} + +void tools::MinGW::Linker::ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, + const InputInfoList &Inputs, + const ArgList &Args, + const char *LinkingOutput) const { + const ToolChain &TC = getToolChain(); + const Driver &D = TC.getDriver(); + // const SanitizerArgs &Sanitize = TC.getSanitizerArgs(); + + ArgStringList CmdArgs; + + // Silence warning for "clang -g foo.o -o foo" + Args.ClaimAllArgs(options::OPT_g_Group); + // and "clang -emit-llvm foo.o -o foo" + Args.ClaimAllArgs(options::OPT_emit_llvm); + // and for "clang -w foo.o -o foo". Other warning options are already + // handled somewhere else. + Args.ClaimAllArgs(options::OPT_w); + + 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)); + + if (Args.hasArg(options::OPT_s)) + CmdArgs.push_back("-s"); + + CmdArgs.push_back("-m"); + if (TC.getArch() == llvm::Triple::x86) + CmdArgs.push_back("i386pe"); + if (TC.getArch() == llvm::Triple::x86_64) + CmdArgs.push_back("i386pep"); + if (TC.getArch() == llvm::Triple::arm) + CmdArgs.push_back("thumb2pe"); + + if (Args.hasArg(options::OPT_mwindows)) { + CmdArgs.push_back("--subsystem"); + CmdArgs.push_back("windows"); + } else if (Args.hasArg(options::OPT_mconsole)) { + CmdArgs.push_back("--subsystem"); + CmdArgs.push_back("console"); + } + + if (Args.hasArg(options::OPT_static)) + CmdArgs.push_back("-Bstatic"); + else { + if (Args.hasArg(options::OPT_mdll)) + CmdArgs.push_back("--dll"); + else if (Args.hasArg(options::OPT_shared)) + CmdArgs.push_back("--shared"); + CmdArgs.push_back("-Bdynamic"); + if (Args.hasArg(options::OPT_mdll) || Args.hasArg(options::OPT_shared)) { + CmdArgs.push_back("-e"); + if (TC.getArch() == llvm::Triple::x86) + CmdArgs.push_back("_DllMainCRTStartup@12"); + else + CmdArgs.push_back("DllMainCRTStartup"); + CmdArgs.push_back("--enable-auto-image-base"); + } + } + + CmdArgs.push_back("-o"); + CmdArgs.push_back(Output.getFilename()); + + Args.AddAllArgs(CmdArgs, options::OPT_e); + // FIXME: add -N, -n flags + Args.AddLastArg(CmdArgs, options::OPT_r); + Args.AddLastArg(CmdArgs, options::OPT_s); + Args.AddLastArg(CmdArgs, options::OPT_t); + Args.AddAllArgs(CmdArgs, options::OPT_u_Group); + Args.AddLastArg(CmdArgs, options::OPT_Z_Flag); + + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) { + if (Args.hasArg(options::OPT_shared) || Args.hasArg(options::OPT_mdll)) { + CmdArgs.push_back(Args.MakeArgString(TC.GetFilePath("dllcrt2.o"))); + } else { + if (Args.hasArg(options::OPT_municode)) + CmdArgs.push_back(Args.MakeArgString(TC.GetFilePath("crt2u.o"))); + else + CmdArgs.push_back(Args.MakeArgString(TC.GetFilePath("crt2.o"))); + } + if (Args.hasArg(options::OPT_pg)) + CmdArgs.push_back(Args.MakeArgString(TC.GetFilePath("gcrt2.o"))); + CmdArgs.push_back(Args.MakeArgString(TC.GetFilePath("crtbegin.o"))); + } + + Args.AddAllArgs(CmdArgs, options::OPT_L); + TC.AddFilePathLibArgs(Args, CmdArgs); + AddLinkerInputs(TC, Inputs, Args, CmdArgs, JA); + + // TODO: Add ASan stuff here + + // TODO: Add profile stuff here + + 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"); + TC.AddCXXStdlibLibArgs(Args, CmdArgs); + if (OnlyLibstdcxxStatic) + CmdArgs.push_back("-Bdynamic"); + } + + if (!Args.hasArg(options::OPT_nostdlib)) { + if (!Args.hasArg(options::OPT_nodefaultlibs)) { + if (Args.hasArg(options::OPT_static)) + CmdArgs.push_back("--start-group"); + + if (Args.hasArg(options::OPT_fstack_protector) || + Args.hasArg(options::OPT_fstack_protector_strong) || + Args.hasArg(options::OPT_fstack_protector_all)) { + CmdArgs.push_back("-lssp_nonshared"); + CmdArgs.push_back("-lssp"); + } + if (Args.hasArg(options::OPT_fopenmp)) + CmdArgs.push_back("-lgomp"); + + AddLibGCC(Args, CmdArgs); + + if (Args.hasArg(options::OPT_pg)) + CmdArgs.push_back("-lgmon"); + + if (Args.hasArg(options::OPT_pthread)) + CmdArgs.push_back("-lpthread"); + + // add system libraries + if (Args.hasArg(options::OPT_mwindows)) { + CmdArgs.push_back("-lgdi32"); + CmdArgs.push_back("-lcomdlg32"); + } + CmdArgs.push_back("-ladvapi32"); + CmdArgs.push_back("-lshell32"); + CmdArgs.push_back("-luser32"); + CmdArgs.push_back("-lkernel32"); + + if (Args.hasArg(options::OPT_static)) + CmdArgs.push_back("--end-group"); + else if (!LinkerName.equals_lower("lld")) + AddLibGCC(Args, CmdArgs); + } + + if (!Args.hasArg(options::OPT_nostartfiles)) { + // Add crtfastmath.o if available and fast math is enabled. + TC.AddFastMathRuntimeIfAvailable(Args, CmdArgs); + + CmdArgs.push_back(Args.MakeArgString(TC.GetFilePath("crtend.o"))); + } + } + const char *Exec = Args.MakeArgString(TC.GetProgramPath(LinkerName.data())); + C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); +} + +// Simplified from Generic_GCC::GCCInstallationDetector::ScanLibDirForGCCTriple. +static bool findGccVersion(StringRef LibDir, std::string &GccLibDir, + std::string &Ver) { + auto Version = toolchains::Generic_GCC::GCCVersion::Parse("0.0.0"); + std::error_code EC; + for (llvm::sys::fs::directory_iterator LI(LibDir, EC), LE; !EC && LI != LE; + LI = LI.increment(EC)) { + StringRef VersionText = llvm::sys::path::filename(LI->path()); + auto CandidateVersion = + toolchains::Generic_GCC::GCCVersion::Parse(VersionText); + if (CandidateVersion.Major == -1) + continue; + if (CandidateVersion <= Version) + continue; + Ver = VersionText; + GccLibDir = LI->path(); + } + return Ver.size(); +} + +void toolchains::MinGW::findGccLibDir() { + llvm::SmallVector<llvm::SmallString<32>, 2> Archs; + Archs.emplace_back(getTriple().getArchName()); + Archs[0] += "-w64-mingw32"; + Archs.emplace_back("mingw32"); + Arch = Archs[0].str(); + // lib: Arch Linux, Ubuntu, Windows + // lib64: openSUSE Linux + for (StringRef CandidateLib : {"lib", "lib64"}) { + for (StringRef CandidateArch : Archs) { + llvm::SmallString<1024> LibDir(Base); + llvm::sys::path::append(LibDir, CandidateLib, "gcc", CandidateArch); + if (findGccVersion(LibDir, GccLibDir, Ver)) { + Arch = CandidateArch; + return; + } + } + } +} + +toolchains::MinGW::MinGW(const Driver &D, const llvm::Triple &Triple, + const ArgList &Args) + : ToolChain(D, Triple, Args), CudaInstallation(D, Triple, Args) { + getProgramPaths().push_back(getDriver().getInstalledDir()); + +// In Windows there aren't any standard install locations, we search +// for gcc on the PATH. In Linux the base is always /usr. +#ifdef LLVM_ON_WIN32 + if (getDriver().SysRoot.size()) + Base = getDriver().SysRoot; + else if (llvm::ErrorOr<std::string> GPPName = + llvm::sys::findProgramByName("gcc")) + Base = llvm::sys::path::parent_path( + llvm::sys::path::parent_path(GPPName.get())); + else + Base = llvm::sys::path::parent_path(getDriver().getInstalledDir()); +#else + if (getDriver().SysRoot.size()) + Base = getDriver().SysRoot; + else + Base = "/usr"; +#endif + + Base += llvm::sys::path::get_separator(); + findGccLibDir(); + // GccLibDir must precede Base/lib so that the + // correct crtbegin.o ,cetend.o would be found. + getFilePaths().push_back(GccLibDir); + getFilePaths().push_back( + (Base + Arch + llvm::sys::path::get_separator() + "lib").str()); + getFilePaths().push_back(Base + "lib"); + // openSUSE + getFilePaths().push_back(Base + Arch + "/sys-root/mingw/lib"); +} + +bool toolchains::MinGW::IsIntegratedAssemblerDefault() const { return true; } + +Tool *toolchains::MinGW::getTool(Action::ActionClass AC) const { + switch (AC) { + case Action::PreprocessJobClass: + if (!Preprocessor) + Preprocessor.reset(new tools::gcc::Preprocessor(*this)); + return Preprocessor.get(); + case Action::CompileJobClass: + if (!Compiler) + Compiler.reset(new tools::gcc::Compiler(*this)); + return Compiler.get(); + default: + return ToolChain::getTool(AC); + } +} + +Tool *toolchains::MinGW::buildAssembler() const { + return new tools::MinGW::Assembler(*this); +} + +Tool *toolchains::MinGW::buildLinker() const { + return new tools::MinGW::Linker(*this); +} + +bool toolchains::MinGW::IsUnwindTablesDefault() const { + return getArch() == llvm::Triple::x86_64; +} + +bool toolchains::MinGW::isPICDefault() const { + return getArch() == llvm::Triple::x86_64; +} + +bool toolchains::MinGW::isPIEDefault() const { return false; } + +bool toolchains::MinGW::isPICDefaultForced() const { + return getArch() == llvm::Triple::x86_64; +} + +bool toolchains::MinGW::UseSEHExceptions() const { + return getArch() == llvm::Triple::x86_64; +} + +void toolchains::MinGW::AddCudaIncludeArgs(const ArgList &DriverArgs, + ArgStringList &CC1Args) const { + CudaInstallation.AddCudaIncludeArgs(DriverArgs, CC1Args); +} + +void toolchains::MinGW::printVerboseInfo(raw_ostream &OS) const { + CudaInstallation.print(OS); +} + +// Include directories for various hosts: + +// Windows, mingw.org +// c:\mingw\lib\gcc\mingw32\4.8.1\include\c++ +// c:\mingw\lib\gcc\mingw32\4.8.1\include\c++\mingw32 +// c:\mingw\lib\gcc\mingw32\4.8.1\include\c++\backward +// c:\mingw\include +// c:\mingw\mingw32\include + +// Windows, mingw-w64 mingw-builds +// c:\mingw32\i686-w64-mingw32\include +// c:\mingw32\i686-w64-mingw32\include\c++ +// c:\mingw32\i686-w64-mingw32\include\c++\i686-w64-mingw32 +// c:\mingw32\i686-w64-mingw32\include\c++\backward + +// Windows, mingw-w64 msys2 +// c:\msys64\mingw32\include +// c:\msys64\mingw32\i686-w64-mingw32\include +// c:\msys64\mingw32\include\c++\4.9.2 +// c:\msys64\mingw32\include\c++\4.9.2\i686-w64-mingw32 +// c:\msys64\mingw32\include\c++\4.9.2\backward + +// openSUSE +// /usr/lib64/gcc/x86_64-w64-mingw32/5.1.0/include/c++ +// /usr/lib64/gcc/x86_64-w64-mingw32/5.1.0/include/c++/x86_64-w64-mingw32 +// /usr/lib64/gcc/x86_64-w64-mingw32/5.1.0/include/c++/backward +// /usr/x86_64-w64-mingw32/sys-root/mingw/include + +// Arch Linux +// /usr/i686-w64-mingw32/include/c++/5.1.0 +// /usr/i686-w64-mingw32/include/c++/5.1.0/i686-w64-mingw32 +// /usr/i686-w64-mingw32/include/c++/5.1.0/backward +// /usr/i686-w64-mingw32/include + +// Ubuntu +// /usr/include/c++/4.8 +// /usr/include/c++/4.8/x86_64-w64-mingw32 +// /usr/include/c++/4.8/backward +// /usr/x86_64-w64-mingw32/include + +void toolchains::MinGW::AddClangSystemIncludeArgs(const ArgList &DriverArgs, + ArgStringList &CC1Args) const { + if (DriverArgs.hasArg(options::OPT_nostdinc)) + return; + + if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) { + SmallString<1024> P(getDriver().ResourceDir); + llvm::sys::path::append(P, "include"); + addSystemInclude(DriverArgs, CC1Args, P.str()); + } + + if (DriverArgs.hasArg(options::OPT_nostdlibinc)) + return; + + if (GetRuntimeLibType(DriverArgs) == ToolChain::RLT_Libgcc) { + // openSUSE + addSystemInclude(DriverArgs, CC1Args, + Base + Arch + "/sys-root/mingw/include"); + } + + addSystemInclude(DriverArgs, CC1Args, + Base + Arch + llvm::sys::path::get_separator() + "include"); + addSystemInclude(DriverArgs, CC1Args, Base + "include"); +} + +void toolchains::MinGW::AddClangCXXStdlibIncludeArgs( + const ArgList &DriverArgs, ArgStringList &CC1Args) const { + if (DriverArgs.hasArg(options::OPT_nostdlibinc) || + DriverArgs.hasArg(options::OPT_nostdincxx)) + return; + + switch (GetCXXStdlibType(DriverArgs)) { + case ToolChain::CST_Libcxx: + addSystemInclude(DriverArgs, CC1Args, + Base + "include" + llvm::sys::path::get_separator() + + "c++" + llvm::sys::path::get_separator() + "v1"); + break; + + case ToolChain::CST_Libstdcxx: + llvm::SmallVector<llvm::SmallString<1024>, 4> CppIncludeBases; + CppIncludeBases.emplace_back(Base); + llvm::sys::path::append(CppIncludeBases[0], Arch, "include", "c++"); + CppIncludeBases.emplace_back(Base); + llvm::sys::path::append(CppIncludeBases[1], Arch, "include", "c++", Ver); + CppIncludeBases.emplace_back(Base); + llvm::sys::path::append(CppIncludeBases[2], "include", "c++", Ver); + CppIncludeBases.emplace_back(GccLibDir); + llvm::sys::path::append(CppIncludeBases[3], "include", "c++"); + for (auto &CppIncludeBase : CppIncludeBases) { + addSystemInclude(DriverArgs, CC1Args, CppIncludeBase); + CppIncludeBase += llvm::sys::path::get_separator(); + addSystemInclude(DriverArgs, CC1Args, CppIncludeBase + Arch); + addSystemInclude(DriverArgs, CC1Args, CppIncludeBase + "backward"); + } + break; + } +} diff --git a/lib/Driver/ToolChains/MinGW.h b/lib/Driver/ToolChains/MinGW.h new file mode 100644 index 0000000000..9d2468ffa2 --- /dev/null +++ b/lib/Driver/ToolChains/MinGW.h @@ -0,0 +1,102 @@ +//===--- MinGW.h - MinGW 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_MINGW_H +#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_MINGW_H + +#include "Cuda.h" +#include "Gnu.h" +#include "clang/Driver/Tool.h" +#include "clang/Driver/ToolChain.h" + +namespace clang { +namespace driver { +namespace tools { + +/// MinGW -- Directly call GNU Binutils assembler and linker +namespace MinGW { +class LLVM_LIBRARY_VISIBILITY Assembler : public Tool { +public: + Assembler(const ToolChain &TC) : Tool("MinGW::Assemble", "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 Tool { +public: + Linker(const ToolChain &TC) : Tool("MinGW::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; + +private: + void AddLibGCC(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) const; +}; +} // end namespace MinGW +} // end namespace tools + +namespace toolchains { + +class LLVM_LIBRARY_VISIBILITY MinGW : public ToolChain { +public: + MinGW(const Driver &D, const llvm::Triple &Triple, + const llvm::opt::ArgList &Args); + + bool IsIntegratedAssemblerDefault() const override; + bool IsUnwindTablesDefault() const override; + bool isPICDefault() const override; + bool isPIEDefault() const override; + bool isPICDefaultForced() const override; + bool UseSEHExceptions() const; + + void + AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const override; + void AddClangCXXStdlibIncludeArgs( + const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const override; + + void AddCudaIncludeArgs(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const override; + + void printVerboseInfo(raw_ostream &OS) const override; + +protected: + Tool *getTool(Action::ActionClass AC) const override; + Tool *buildLinker() const override; + Tool *buildAssembler() const override; + +private: + CudaInstallationDetector CudaInstallation; + + std::string Base; + std::string GccLibDir; + std::string Ver; + std::string Arch; + mutable std::unique_ptr<tools::gcc::Preprocessor> Preprocessor; + mutable std::unique_ptr<tools::gcc::Compiler> Compiler; + void findGccLibDir(); +}; + +} // end namespace toolchains +} // end namespace driver +} // end namespace clang + +#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_MINGW_H diff --git a/lib/Driver/ToolChains/Minix.cpp b/lib/Driver/ToolChains/Minix.cpp new file mode 100644 index 0000000000..2e8939c401 --- /dev/null +++ b/lib/Driver/ToolChains/Minix.cpp @@ -0,0 +1,109 @@ +//===--- Minix.cpp - Minix 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 "Minix.h" +#include "InputInfo.h" +#include "CommonArgs.h" +#include "clang/Basic/VirtualFileSystem.h" +#include "clang/Driver/Compilation.h" +#include "clang/Driver/Driver.h" +#include "clang/Driver/Options.h" +#include "llvm/Option/ArgList.h" + +using namespace clang::driver; +using namespace clang; +using namespace llvm::opt; + +void tools::minix::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 tools::minix::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 (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)) { + CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath("crt1.o"))); + CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath("crti.o"))); + CmdArgs.push_back( + Args.MakeArgString(getToolChain().GetFilePath("crtbegin.o"))); + CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath("crtn.o"))); + } + + Args.AddAllArgs(CmdArgs, + {options::OPT_L, options::OPT_T_Group, options::OPT_e}); + + AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA); + + getToolChain().addProfileRTLibs(Args, CmdArgs); + + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { + if (D.CCCIsCXX()) { + getToolChain().AddCXXStdlibLibArgs(Args, CmdArgs); + CmdArgs.push_back("-lm"); + } + } + + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) { + if (Args.hasArg(options::OPT_pthread)) + CmdArgs.push_back("-lpthread"); + CmdArgs.push_back("-lc"); + CmdArgs.push_back("-lCompilerRT-Generic"); + CmdArgs.push_back("-L/usr/pkg/compiler-rt/lib"); + CmdArgs.push_back( + Args.MakeArgString(getToolChain().GetFilePath("crtend.o"))); + } + + const char *Exec = Args.MakeArgString(getToolChain().GetLinkerPath()); + C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); +} + +/// Minix - Minix tool chain which can call as(1) and ld(1) directly. + +toolchains::Minix::Minix(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 *toolchains::Minix::buildAssembler() const { + return new tools::minix::Assembler(*this); +} + +Tool *toolchains::Minix::buildLinker() const { + return new tools::minix::Linker(*this); +} diff --git a/lib/Driver/ToolChains/Minix.h b/lib/Driver/ToolChains/Minix.h new file mode 100644 index 0000000000..6fd71850ad --- /dev/null +++ b/lib/Driver/ToolChains/Minix.h @@ -0,0 +1,66 @@ +//===--- Minix.h - Minix 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_MINIX_H +#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_MINIX_H + +#include "Gnu.h" +#include "clang/Driver/Tool.h" +#include "clang/Driver/ToolChain.h" + +namespace clang { +namespace driver { +namespace tools { +/// minix -- Directly call GNU Binutils assembler and linker +namespace minix { +class LLVM_LIBRARY_VISIBILITY Assembler : public GnuTool { +public: + Assembler(const ToolChain &TC) + : GnuTool("minix::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("minix::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 minix +} // end namespace tools + +namespace toolchains { + +class LLVM_LIBRARY_VISIBILITY Minix : public Generic_ELF { +public: + Minix(const Driver &D, const llvm::Triple &Triple, + const llvm::opt::ArgList &Args); + +protected: + Tool *buildAssembler() const override; + Tool *buildLinker() const override; +}; + +} // end namespace toolchains +} // end namespace driver +} // end namespace clang + +#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_MINIX_H diff --git a/lib/Driver/ToolChains/Mips.cpp b/lib/Driver/ToolChains/Mips.cpp new file mode 100644 index 0000000000..88dfa9dd6e --- /dev/null +++ b/lib/Driver/ToolChains/Mips.cpp @@ -0,0 +1,128 @@ +//===--- Mips.cpp - Mips 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 "Mips.h" +#include "Arch/Mips.h" +#include "CommonArgs.h" +#include "clang/Config/config.h" +#include "clang/Driver/Driver.h" +#include "clang/Driver/DriverDiagnostic.h" +#include "clang/Driver/Options.h" +#include "llvm/Option/ArgList.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/Path.h" + +using namespace clang::driver; +using namespace clang::driver::toolchains; +using namespace clang; +using namespace llvm::opt; + +/// Mips Toolchain +MipsLLVMToolChain::MipsLLVMToolChain(const Driver &D, + const llvm::Triple &Triple, + const ArgList &Args) + : Linux(D, Triple, Args) { + // Select the correct multilib according to the given arguments. + DetectedMultilibs Result; + findMIPSMultilibs(D, Triple, "", Args, Result); + Multilibs = Result.Multilibs; + SelectedMultilib = Result.SelectedMultilib; + + // Find out the library suffix based on the ABI. + LibSuffix = tools::mips::getMipsABILibSuffix(Args, Triple); + getFilePaths().clear(); + getFilePaths().push_back(computeSysRoot() + "/usr/lib" + LibSuffix); +} + +void MipsLLVMToolChain::AddClangSystemIncludeArgs( + const ArgList &DriverArgs, ArgStringList &CC1Args) const { + if (DriverArgs.hasArg(clang::driver::options::OPT_nostdinc)) + return; + + const Driver &D = getDriver(); + + if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) { + SmallString<128> P(D.ResourceDir); + llvm::sys::path::append(P, "include"); + addSystemInclude(DriverArgs, CC1Args, P); + } + + if (DriverArgs.hasArg(options::OPT_nostdlibinc)) + return; + + const auto &Callback = Multilibs.includeDirsCallback(); + if (Callback) { + for (const auto &Path : Callback(SelectedMultilib)) + addExternCSystemIncludeIfExists(DriverArgs, CC1Args, + D.getInstalledDir() + Path); + } +} + +Tool *MipsLLVMToolChain::buildLinker() const { + return new tools::gnutools::Linker(*this); +} + +std::string MipsLLVMToolChain::computeSysRoot() const { + if (!getDriver().SysRoot.empty()) + return getDriver().SysRoot + SelectedMultilib.osSuffix(); + + const std::string InstalledDir(getDriver().getInstalledDir()); + std::string SysRootPath = + InstalledDir + "/../sysroot" + SelectedMultilib.osSuffix(); + if (llvm::sys::fs::exists(SysRootPath)) + return SysRootPath; + + return std::string(); +} + +ToolChain::CXXStdlibType +MipsLLVMToolChain::GetCXXStdlibType(const ArgList &Args) const { + Arg *A = Args.getLastArg(options::OPT_stdlib_EQ); + if (A) { + StringRef Value = A->getValue(); + if (Value != "libc++") + getDriver().Diag(clang::diag::err_drv_invalid_stdlib_name) + << A->getAsString(Args); + } + + return ToolChain::CST_Libcxx; +} + +std::string MipsLLVMToolChain::findLibCxxIncludePath() const { + if (const auto &Callback = Multilibs.includeDirsCallback()) { + for (std::string Path : Callback(SelectedMultilib)) { + Path = getDriver().getInstalledDir() + Path + "/c++/v1"; + if (llvm::sys::fs::exists(Path)) { + return Path; + } + } + } + return ""; +} + +void MipsLLVMToolChain::AddCXXStdlibLibArgs(const ArgList &Args, + ArgStringList &CmdArgs) const { + assert((GetCXXStdlibType(Args) == ToolChain::CST_Libcxx) && + "Only -lc++ (aka libxx) is suported in this toolchain."); + + CmdArgs.push_back("-lc++"); + CmdArgs.push_back("-lc++abi"); + CmdArgs.push_back("-lunwind"); +} + +std::string MipsLLVMToolChain::getCompilerRT(const ArgList &Args, + StringRef Component, + bool Shared) const { + SmallString<128> Path(getDriver().ResourceDir); + llvm::sys::path::append(Path, SelectedMultilib.osSuffix(), "lib" + LibSuffix, + getOS()); + llvm::sys::path::append(Path, Twine("libclang_rt." + Component + "-" + + "mips" + (Shared ? ".so" : ".a"))); + return Path.str(); +} diff --git a/lib/Driver/ToolChains/Mips.h b/lib/Driver/ToolChains/Mips.h new file mode 100644 index 0000000000..7f9db656ab --- /dev/null +++ b/lib/Driver/ToolChains/Mips.h @@ -0,0 +1,62 @@ +//===--- Mips.h - Mips 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_MIPS_H +#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_MIPS_H + +#include "Linux.h" +#include "clang/Driver/ToolChain.h" + +namespace clang { +namespace driver { +namespace toolchains { + +class LLVM_LIBRARY_VISIBILITY MipsLLVMToolChain : public Linux { +protected: + Tool *buildLinker() const override; + +public: + MipsLLVMToolChain(const Driver &D, const llvm::Triple &Triple, + const llvm::opt::ArgList &Args); + + void + AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const override; + + CXXStdlibType GetCXXStdlibType(const llvm::opt::ArgList &Args) const override; + + std::string findLibCxxIncludePath() const override; + + void AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) const override; + + std::string getCompilerRT(const llvm::opt::ArgList &Args, StringRef Component, + bool Shared = false) const override; + + std::string computeSysRoot() const override; + + RuntimeLibType GetDefaultRuntimeLibType() const override { + return GCCInstallation.isValid() ? RuntimeLibType::RLT_Libgcc + : RuntimeLibType::RLT_CompilerRT; + } + + const char *getDefaultLinker() const override { + return "lld"; + } + +private: + Multilib SelectedMultilib; + std::string LibSuffix; +}; + +} // end namespace toolchains +} // end namespace driver +} // end namespace clang + +#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_MIPS_H diff --git a/lib/Driver/ToolChains/Myriad.cpp b/lib/Driver/ToolChains/Myriad.cpp new file mode 100644 index 0000000000..2935755c12 --- /dev/null +++ b/lib/Driver/ToolChains/Myriad.cpp @@ -0,0 +1,286 @@ +//===--- Myriad.cpp - Myriad 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 "Myriad.h" +#include "CommonArgs.h" +#include "clang/Driver/Compilation.h" +#include "clang/Driver/Driver.h" +#include "clang/Driver/DriverDiagnostic.h" +#include "clang/Driver/Options.h" +#include "llvm/Option/ArgList.h" + +using namespace clang::driver; +using namespace clang::driver::toolchains; +using namespace clang; +using namespace llvm::opt; + +using tools::addPathIfExists; + +void tools::SHAVE::Compiler::ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, + const InputInfoList &Inputs, + const ArgList &Args, + const char *LinkingOutput) const { + ArgStringList CmdArgs; + assert(Inputs.size() == 1); + const InputInfo &II = Inputs[0]; + assert(II.getType() == types::TY_C || II.getType() == types::TY_CXX || + II.getType() == types::TY_PP_CXX); + + if (JA.getKind() == Action::PreprocessJobClass) { + Args.ClaimAllArgs(); + CmdArgs.push_back("-E"); + } else { + assert(Output.getType() == types::TY_PP_Asm); // Require preprocessed asm. + CmdArgs.push_back("-S"); + CmdArgs.push_back("-fno-exceptions"); // Always do this even if unspecified. + } + CmdArgs.push_back("-DMYRIAD2"); + + // Append all -I, -iquote, -isystem paths, defines/undefines, + // 'f' flags, optimize flags, and warning options. + // These are spelled the same way in clang and moviCompile. + Args.AddAllArgsExcept( + CmdArgs, + {options::OPT_I_Group, options::OPT_clang_i_Group, options::OPT_std_EQ, + options::OPT_D, options::OPT_U, options::OPT_f_Group, + options::OPT_f_clang_Group, options::OPT_g_Group, options::OPT_M_Group, + options::OPT_O_Group, options::OPT_W_Group, options::OPT_mcpu_EQ}, + {options::OPT_fno_split_dwarf_inlining}); + Args.hasArg(options::OPT_fno_split_dwarf_inlining); // Claim it if present. + + // If we're producing a dependency file, and assembly is the final action, + // then the name of the target in the dependency file should be the '.o' + // file, not the '.s' file produced by this step. For example, instead of + // /tmp/mumble.s: mumble.c .../someheader.h + // the filename on the lefthand side should be "mumble.o" + if (Args.getLastArg(options::OPT_MF) && !Args.getLastArg(options::OPT_MT) && + C.getActions().size() == 1 && + C.getActions()[0]->getKind() == Action::AssembleJobClass) { + Arg *A = Args.getLastArg(options::OPT_o); + if (A) { + CmdArgs.push_back("-MT"); + CmdArgs.push_back(Args.MakeArgString(A->getValue())); + } + } + + CmdArgs.push_back(II.getFilename()); + CmdArgs.push_back("-o"); + CmdArgs.push_back(Output.getFilename()); + + std::string Exec = + Args.MakeArgString(getToolChain().GetProgramPath("moviCompile")); + C.addCommand(llvm::make_unique<Command>(JA, *this, Args.MakeArgString(Exec), + CmdArgs, Inputs)); +} + +void tools::SHAVE::Assembler::ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, + const InputInfoList &Inputs, + const ArgList &Args, + const char *LinkingOutput) const { + ArgStringList CmdArgs; + + assert(Inputs.size() == 1); + const InputInfo &II = Inputs[0]; + assert(II.getType() == types::TY_PP_Asm); // Require preprocessed asm input. + assert(Output.getType() == types::TY_Object); + + CmdArgs.push_back("-no6thSlotCompression"); + const Arg *CPUArg = Args.getLastArg(options::OPT_mcpu_EQ); + if (CPUArg) + CmdArgs.push_back( + Args.MakeArgString("-cv:" + StringRef(CPUArg->getValue()))); + CmdArgs.push_back("-noSPrefixing"); + CmdArgs.push_back("-a"); // Mystery option. + Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler); + for (const Arg *A : Args.filtered(options::OPT_I, options::OPT_isystem)) { + A->claim(); + CmdArgs.push_back( + Args.MakeArgString(std::string("-i:") + A->getValue(0))); + } + CmdArgs.push_back("-elf"); // Output format. + CmdArgs.push_back(II.getFilename()); + CmdArgs.push_back( + Args.MakeArgString(std::string("-o:") + Output.getFilename())); + + std::string Exec = + Args.MakeArgString(getToolChain().GetProgramPath("moviAsm")); + C.addCommand(llvm::make_unique<Command>(JA, *this, Args.MakeArgString(Exec), + CmdArgs, Inputs)); +} + +void tools::Myriad::Linker::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::MyriadToolChain &>(getToolChain()); + const llvm::Triple &T = TC.getTriple(); + ArgStringList CmdArgs; + bool UseStartfiles = + !Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles); + bool UseDefaultLibs = + !Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs); + // Silence warning if the args contain both -nostdlib and -stdlib=. + Args.getLastArg(options::OPT_stdlib_EQ); + + if (T.getArch() == llvm::Triple::sparc) + CmdArgs.push_back("-EB"); + else // SHAVE assumes little-endian, and sparcel is expressly so. + CmdArgs.push_back("-EL"); + + // The remaining logic is mostly like gnutools::Linker::ConstructJob, + // but we never pass through a --sysroot option and various other bits. + // For example, there are no sanitizers (yet) nor gold linker. + + // Eat some arguments that may be present but have no effect. + Args.ClaimAllArgs(options::OPT_g_Group); + Args.ClaimAllArgs(options::OPT_w); + Args.ClaimAllArgs(options::OPT_static_libgcc); + + if (Args.hasArg(options::OPT_s)) // Pass the 'strip' option. + CmdArgs.push_back("-s"); + + CmdArgs.push_back("-o"); + CmdArgs.push_back(Output.getFilename()); + + if (UseStartfiles) { + // If you want startfiles, it means you want the builtin crti and crtbegin, + // but not crt0. Myriad link commands provide their own crt0.o as needed. + CmdArgs.push_back(Args.MakeArgString(TC.GetFilePath("crti.o"))); + CmdArgs.push_back(Args.MakeArgString(TC.GetFilePath("crtbegin.o"))); + } + + Args.AddAllArgs(CmdArgs, {options::OPT_L, options::OPT_T_Group, + options::OPT_e, options::OPT_s, options::OPT_t, + options::OPT_Z_Flag, options::OPT_r}); + + TC.AddFilePathLibArgs(Args, CmdArgs); + + bool NeedsSanitizerDeps = addSanitizerRuntimes(TC, Args, CmdArgs); + AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA); + + if (UseDefaultLibs) { + if (NeedsSanitizerDeps) + linkSanitizerRuntimeDeps(TC, CmdArgs); + if (C.getDriver().CCCIsCXX()) { + if (TC.GetCXXStdlibType(Args) == ToolChain::CST_Libcxx) { + CmdArgs.push_back("-lc++"); + CmdArgs.push_back("-lc++abi"); + } else + CmdArgs.push_back("-lstdc++"); + } + if (T.getOS() == llvm::Triple::RTEMS) { + CmdArgs.push_back("--start-group"); + CmdArgs.push_back("-lc"); + CmdArgs.push_back("-lgcc"); // circularly dependent on rtems + // You must provide your own "-L" option to enable finding these. + CmdArgs.push_back("-lrtemscpu"); + CmdArgs.push_back("-lrtemsbsp"); + CmdArgs.push_back("--end-group"); + } else { + CmdArgs.push_back("-lc"); + CmdArgs.push_back("-lgcc"); + } + } + if (UseStartfiles) { + CmdArgs.push_back(Args.MakeArgString(TC.GetFilePath("crtend.o"))); + CmdArgs.push_back(Args.MakeArgString(TC.GetFilePath("crtn.o"))); + } + + std::string Exec = + Args.MakeArgString(TC.GetProgramPath("sparc-myriad-elf-ld")); + C.addCommand(llvm::make_unique<Command>(JA, *this, Args.MakeArgString(Exec), + CmdArgs, Inputs)); +} + +MyriadToolChain::MyriadToolChain(const Driver &D, const llvm::Triple &Triple, + const ArgList &Args) + : Generic_ELF(D, Triple, Args) { + // If a target of 'sparc-myriad-elf' is specified to clang, it wants to use + // 'sparc-myriad--elf' (note the unknown OS) as the canonical triple. + // This won't work to find gcc. Instead we give the installation detector an + // extra triple, which is preferable to further hacks of the logic that at + // present is based solely on getArch(). In particular, it would be wrong to + // choose the myriad installation when targeting a non-myriad sparc install. + switch (Triple.getArch()) { + default: + D.Diag(clang::diag::err_target_unsupported_arch) + << Triple.getArchName() << "myriad"; + case llvm::Triple::sparc: + case llvm::Triple::sparcel: + case llvm::Triple::shave: + GCCInstallation.init(Triple, Args, {"sparc-myriad-elf"}); + } + + if (GCCInstallation.isValid()) { + // This directory contains crt{i,n,begin,end}.o as well as libgcc. + // These files are tied to a particular version of gcc. + SmallString<128> CompilerSupportDir(GCCInstallation.getInstallPath()); + addPathIfExists(D, CompilerSupportDir, getFilePaths()); + } + // libstd++ and libc++ must both be found in this one place. + addPathIfExists(D, D.Dir + "/../sparc-myriad-elf/lib", getFilePaths()); +} + +MyriadToolChain::~MyriadToolChain() {} + +void MyriadToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs, + ArgStringList &CC1Args) const { + if (!DriverArgs.hasArg(clang::driver::options::OPT_nostdinc)) + addSystemInclude(DriverArgs, CC1Args, getDriver().SysRoot + "/include"); +} + +std::string MyriadToolChain::findLibCxxIncludePath() const { + std::string Path(getDriver().getInstalledDir()); + return Path + "/../include/c++/v1"; +} + +void MyriadToolChain::addLibStdCxxIncludePaths( + const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const { + StringRef LibDir = GCCInstallation.getParentLibPath(); + const GCCVersion &Version = GCCInstallation.getVersion(); + StringRef TripleStr = GCCInstallation.getTriple().str(); + const Multilib &Multilib = GCCInstallation.getMultilib(); + addLibStdCXXIncludePaths( + LibDir.str() + "/../" + TripleStr.str() + "/include/c++/" + Version.Text, + "", TripleStr, "", "", Multilib.includeSuffix(), DriverArgs, CC1Args); +} + +// MyriadToolChain handles several triples: +// {shave,sparc{,el}}-myriad-{rtems,unknown}-elf +Tool *MyriadToolChain::SelectTool(const JobAction &JA) const { + // The inherited method works fine if not targeting the SHAVE. + if (!isShaveCompilation(getTriple())) + return ToolChain::SelectTool(JA); + switch (JA.getKind()) { + case Action::PreprocessJobClass: + case Action::CompileJobClass: + if (!Compiler) + Compiler.reset(new tools::SHAVE::Compiler(*this)); + return Compiler.get(); + case Action::AssembleJobClass: + if (!Assembler) + Assembler.reset(new tools::SHAVE::Assembler(*this)); + return Assembler.get(); + default: + return ToolChain::getTool(JA.getKind()); + } +} + +Tool *MyriadToolChain::buildLinker() const { + return new tools::Myriad::Linker(*this); +} + +SanitizerMask MyriadToolChain::getSupportedSanitizers() const { + return SanitizerKind::Address; +} diff --git a/lib/Driver/ToolChains/Myriad.h b/lib/Driver/ToolChains/Myriad.h new file mode 100644 index 0000000000..4c213c7262 --- /dev/null +++ b/lib/Driver/ToolChains/Myriad.h @@ -0,0 +1,102 @@ +//===--- Myriad.h - Myriad 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_MYRIAD_H +#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_MYRIAD_H + +#include "Gnu.h" +#include "clang/Driver/Tool.h" +#include "clang/Driver/ToolChain.h" + +namespace clang { +namespace driver { +namespace tools { + +/// SHAVE tools -- Directly call moviCompile and moviAsm +namespace SHAVE { +class LLVM_LIBRARY_VISIBILITY Compiler : public Tool { +public: + Compiler(const ToolChain &TC) : Tool("moviCompile", "movicompile", TC) {} + + bool hasIntegratedCPP() 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; +}; + +class LLVM_LIBRARY_VISIBILITY Assembler : public Tool { +public: + Assembler(const ToolChain &TC) : Tool("moviAsm", "moviAsm", TC) {} + + bool hasIntegratedCPP() const override { return false; } // not sure. + + 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 SHAVE + +/// The Myriad toolchain uses tools that are in two different namespaces. +/// The Compiler and Assembler as defined above are in the SHAVE namespace, +/// whereas the linker, which accepts code for a mixture of Sparc and SHAVE, +/// is in the Myriad namespace. +namespace Myriad { +class LLVM_LIBRARY_VISIBILITY Linker : public GnuTool { +public: + Linker(const ToolChain &TC) : GnuTool("shave::Linker", "ld", 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 Myriad +} // end namespace tools + +namespace toolchains { + +/// MyriadToolChain - A tool chain using either clang or the external compiler +/// installed by the Movidius SDK to perform all subcommands. +class LLVM_LIBRARY_VISIBILITY MyriadToolChain : public Generic_ELF { +public: + MyriadToolChain(const Driver &D, const llvm::Triple &Triple, + const llvm::opt::ArgList &Args); + ~MyriadToolChain() override; + + void + AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const override; + std::string findLibCxxIncludePath() const override; + void addLibStdCxxIncludePaths( + const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const override; + Tool *SelectTool(const JobAction &JA) const override; + unsigned GetDefaultDwarfVersion() const override { return 2; } + SanitizerMask getSupportedSanitizers() const override; + +protected: + Tool *buildLinker() const override; + bool isShaveCompilation(const llvm::Triple &T) const { + return T.getArch() == llvm::Triple::shave; + } + +private: + mutable std::unique_ptr<Tool> Compiler; + mutable std::unique_ptr<Tool> Assembler; +}; + +} // end namespace toolchains +} // end namespace driver +} // end namespace clang + +#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_MYRIAD_H diff --git a/lib/Driver/ToolChains/NaCl.cpp b/lib/Driver/ToolChains/NaCl.cpp new file mode 100644 index 0000000000..5eb5c74f13 --- /dev/null +++ b/lib/Driver/ToolChains/NaCl.cpp @@ -0,0 +1,363 @@ +//===--- NaCl.cpp - Native Client 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 "NaCl.h" +#include "InputInfo.h" +#include "CommonArgs.h" +#include "clang/Driver/Compilation.h" +#include "clang/Driver/Driver.h" +#include "clang/Driver/DriverDiagnostic.h" +#include "clang/Driver/Options.h" +#include "llvm/Option/ArgList.h" +#include "llvm/Support/Path.h" + +using namespace clang::driver; +using namespace clang::driver::tools; +using namespace clang::driver::toolchains; +using namespace clang; +using namespace llvm::opt; + +// NaCl ARM assembly (inline or standalone) can be written with a set of macros +// for the various SFI requirements like register masking. The assembly tool +// inserts the file containing the macros as an input into all the assembly +// jobs. +void nacltools::AssemblerARM::ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, + const InputInfoList &Inputs, + const ArgList &Args, + const char *LinkingOutput) const { + const toolchains::NaClToolChain &ToolChain = + static_cast<const toolchains::NaClToolChain &>(getToolChain()); + InputInfo NaClMacros(types::TY_PP_Asm, ToolChain.GetNaClArmMacrosPath(), + "nacl-arm-macros.s"); + InputInfoList NewInputs; + NewInputs.push_back(NaClMacros); + NewInputs.append(Inputs.begin(), Inputs.end()); + gnutools::Assembler::ConstructJob(C, JA, Output, NewInputs, Args, + LinkingOutput); +} + +// This is quite similar to gnutools::Linker::ConstructJob with changes that +// we use static by default, do not yet support sanitizers or LTO, and a few +// others. Eventually we can support more of that and hopefully migrate back +// to gnutools::Linker. +void nacltools::Linker::ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, + const InputInfoList &Inputs, + const ArgList &Args, + const char *LinkingOutput) const { + + const toolchains::NaClToolChain &ToolChain = + static_cast<const toolchains::NaClToolChain &>(getToolChain()); + const Driver &D = ToolChain.getDriver(); + const llvm::Triple::ArchType Arch = ToolChain.getArch(); + const bool IsStatic = + !Args.hasArg(options::OPT_dynamic) && !Args.hasArg(options::OPT_shared); + + ArgStringList CmdArgs; + + // Silence warning for "clang -g foo.o -o foo" + Args.ClaimAllArgs(options::OPT_g_Group); + // and "clang -emit-llvm foo.o -o foo" + Args.ClaimAllArgs(options::OPT_emit_llvm); + // and for "clang -w foo.o -o foo". Other warning options are already + // handled somewhere else. + Args.ClaimAllArgs(options::OPT_w); + + if (!D.SysRoot.empty()) + CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot)); + + if (Args.hasArg(options::OPT_rdynamic)) + CmdArgs.push_back("-export-dynamic"); + + if (Args.hasArg(options::OPT_s)) + CmdArgs.push_back("-s"); + + // NaClToolChain doesn't have ExtraOpts like Linux; the only relevant flag + // from there is --build-id, which we do want. + CmdArgs.push_back("--build-id"); + + if (!IsStatic) + CmdArgs.push_back("--eh-frame-hdr"); + + CmdArgs.push_back("-m"); + if (Arch == llvm::Triple::x86) + CmdArgs.push_back("elf_i386_nacl"); + else if (Arch == llvm::Triple::arm) + CmdArgs.push_back("armelf_nacl"); + else if (Arch == llvm::Triple::x86_64) + CmdArgs.push_back("elf_x86_64_nacl"); + else if (Arch == llvm::Triple::mipsel) + CmdArgs.push_back("mipselelf_nacl"); + else + D.Diag(diag::err_target_unsupported_arch) << ToolChain.getArchName() + << "Native Client"; + + if (IsStatic) + CmdArgs.push_back("-static"); + else if (Args.hasArg(options::OPT_shared)) + CmdArgs.push_back("-shared"); + + CmdArgs.push_back("-o"); + CmdArgs.push_back(Output.getFilename()); + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) { + if (!Args.hasArg(options::OPT_shared)) + CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crt1.o"))); + CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crti.o"))); + + const char *crtbegin; + if (IsStatic) + crtbegin = "crtbeginT.o"; + else if (Args.hasArg(options::OPT_shared)) + crtbegin = "crtbeginS.o"; + else + crtbegin = "crtbegin.o"; + CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crtbegin))); + } + + Args.AddAllArgs(CmdArgs, options::OPT_L); + Args.AddAllArgs(CmdArgs, options::OPT_u); + + ToolChain.AddFilePathLibArgs(Args, CmdArgs); + + if (Args.hasArg(options::OPT_Z_Xlinker__no_demangle)) + CmdArgs.push_back("--no-demangle"); + + AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, 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"); + CmdArgs.push_back("-lm"); + } + + if (!Args.hasArg(options::OPT_nostdlib)) { + if (!Args.hasArg(options::OPT_nodefaultlibs)) { + // Always use groups, since it has no effect on dynamic libraries. + CmdArgs.push_back("--start-group"); + CmdArgs.push_back("-lc"); + // NaCl's libc++ currently requires libpthread, so just always include it + // in the group for C++. + if (Args.hasArg(options::OPT_pthread) || + Args.hasArg(options::OPT_pthreads) || D.CCCIsCXX()) { + // Gold, used by Mips, handles nested groups differently than ld, and + // without '-lnacl' it prefers symbols from libpthread.a over libnacl.a, + // which is not a desired behaviour here. + // See https://sourceware.org/ml/binutils/2015-03/msg00034.html + if (getToolChain().getArch() == llvm::Triple::mipsel) + CmdArgs.push_back("-lnacl"); + + CmdArgs.push_back("-lpthread"); + } + + CmdArgs.push_back("-lgcc"); + CmdArgs.push_back("--as-needed"); + if (IsStatic) + CmdArgs.push_back("-lgcc_eh"); + else + CmdArgs.push_back("-lgcc_s"); + CmdArgs.push_back("--no-as-needed"); + + // Mips needs to create and use pnacl_legacy library that contains + // definitions from bitcode/pnaclmm.c and definitions for + // __nacl_tp_tls_offset() and __nacl_tp_tdb_offset(). + if (getToolChain().getArch() == llvm::Triple::mipsel) + CmdArgs.push_back("-lpnacl_legacy"); + + CmdArgs.push_back("--end-group"); + } + + if (!Args.hasArg(options::OPT_nostartfiles)) { + const char *crtend; + if (Args.hasArg(options::OPT_shared)) + crtend = "crtendS.o"; + else + crtend = "crtend.o"; + + CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crtend))); + CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtn.o"))); + } + } + + const char *Exec = Args.MakeArgString(ToolChain.GetLinkerPath()); + C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); +} + +/// NaCl Toolchain +NaClToolChain::NaClToolChain(const Driver &D, const llvm::Triple &Triple, + const ArgList &Args) + : Generic_ELF(D, Triple, Args) { + + // Remove paths added by Generic_GCC. NaCl Toolchain cannot use the + // default paths, and must instead only use the paths provided + // with this toolchain based on architecture. + path_list &file_paths = getFilePaths(); + path_list &prog_paths = getProgramPaths(); + + file_paths.clear(); + prog_paths.clear(); + + // Path for library files (libc.a, ...) + std::string FilePath(getDriver().Dir + "/../"); + + // Path for tools (clang, ld, etc..) + std::string ProgPath(getDriver().Dir + "/../"); + + // Path for toolchain libraries (libgcc.a, ...) + std::string ToolPath(getDriver().ResourceDir + "/lib/"); + + switch (Triple.getArch()) { + case llvm::Triple::x86: + file_paths.push_back(FilePath + "x86_64-nacl/lib32"); + file_paths.push_back(FilePath + "i686-nacl/usr/lib"); + prog_paths.push_back(ProgPath + "x86_64-nacl/bin"); + file_paths.push_back(ToolPath + "i686-nacl"); + break; + case llvm::Triple::x86_64: + file_paths.push_back(FilePath + "x86_64-nacl/lib"); + file_paths.push_back(FilePath + "x86_64-nacl/usr/lib"); + prog_paths.push_back(ProgPath + "x86_64-nacl/bin"); + file_paths.push_back(ToolPath + "x86_64-nacl"); + break; + case llvm::Triple::arm: + file_paths.push_back(FilePath + "arm-nacl/lib"); + file_paths.push_back(FilePath + "arm-nacl/usr/lib"); + prog_paths.push_back(ProgPath + "arm-nacl/bin"); + file_paths.push_back(ToolPath + "arm-nacl"); + break; + case llvm::Triple::mipsel: + file_paths.push_back(FilePath + "mipsel-nacl/lib"); + file_paths.push_back(FilePath + "mipsel-nacl/usr/lib"); + prog_paths.push_back(ProgPath + "bin"); + file_paths.push_back(ToolPath + "mipsel-nacl"); + break; + default: + break; + } + + NaClArmMacrosPath = GetFilePath("nacl-arm-macros.s"); +} + +void NaClToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs, + ArgStringList &CC1Args) const { + const Driver &D = getDriver(); + if (DriverArgs.hasArg(clang::driver::options::OPT_nostdinc)) + return; + + if (!DriverArgs.hasArg(options::OPT_nobuiltininc)) { + SmallString<128> P(D.ResourceDir); + llvm::sys::path::append(P, "include"); + addSystemInclude(DriverArgs, CC1Args, P.str()); + } + + if (DriverArgs.hasArg(options::OPT_nostdlibinc)) + return; + + SmallString<128> P(D.Dir + "/../"); + switch (getTriple().getArch()) { + case llvm::Triple::x86: + // x86 is special because multilib style uses x86_64-nacl/include for libc + // headers but the SDK wants i686-nacl/usr/include. The other architectures + // have the same substring. + llvm::sys::path::append(P, "i686-nacl/usr/include"); + addSystemInclude(DriverArgs, CC1Args, P.str()); + llvm::sys::path::remove_filename(P); + llvm::sys::path::remove_filename(P); + llvm::sys::path::remove_filename(P); + llvm::sys::path::append(P, "x86_64-nacl/include"); + addSystemInclude(DriverArgs, CC1Args, P.str()); + return; + case llvm::Triple::arm: + llvm::sys::path::append(P, "arm-nacl/usr/include"); + break; + case llvm::Triple::x86_64: + llvm::sys::path::append(P, "x86_64-nacl/usr/include"); + break; + case llvm::Triple::mipsel: + llvm::sys::path::append(P, "mipsel-nacl/usr/include"); + break; + default: + return; + } + + addSystemInclude(DriverArgs, CC1Args, P.str()); + llvm::sys::path::remove_filename(P); + llvm::sys::path::remove_filename(P); + llvm::sys::path::append(P, "include"); + addSystemInclude(DriverArgs, CC1Args, P.str()); +} + +void NaClToolChain::AddCXXStdlibLibArgs(const ArgList &Args, + ArgStringList &CmdArgs) const { + // Check for -stdlib= flags. We only support libc++ but this consumes the arg + // if the value is libc++, and emits an error for other values. + GetCXXStdlibType(Args); + CmdArgs.push_back("-lc++"); +} + +std::string NaClToolChain::findLibCxxIncludePath() const { + const Driver &D = getDriver(); + + SmallString<128> P(D.Dir + "/../"); + switch (getTriple().getArch()) { + case llvm::Triple::arm: + llvm::sys::path::append(P, "arm-nacl/include/c++/v1"); + return P.str(); + case llvm::Triple::x86: + llvm::sys::path::append(P, "x86_64-nacl/include/c++/v1"); + return P.str(); + case llvm::Triple::x86_64: + llvm::sys::path::append(P, "x86_64-nacl/include/c++/v1"); + return P.str(); + case llvm::Triple::mipsel: + llvm::sys::path::append(P, "mipsel-nacl/include/c++/v1"); + return P.str(); + default: + return ""; + } +} + +ToolChain::CXXStdlibType +NaClToolChain::GetCXXStdlibType(const ArgList &Args) const { + if (Arg *A = Args.getLastArg(options::OPT_stdlib_EQ)) { + StringRef Value = A->getValue(); + if (Value == "libc++") + return ToolChain::CST_Libcxx; + getDriver().Diag(clang::diag::err_drv_invalid_stdlib_name) + << A->getAsString(Args); + } + + return ToolChain::CST_Libcxx; +} + +std::string +NaClToolChain::ComputeEffectiveClangTriple(const ArgList &Args, + types::ID InputType) const { + llvm::Triple TheTriple(ComputeLLVMTriple(Args, InputType)); + if (TheTriple.getArch() == llvm::Triple::arm && + TheTriple.getEnvironment() == llvm::Triple::UnknownEnvironment) + TheTriple.setEnvironment(llvm::Triple::GNUEABIHF); + return TheTriple.getTriple(); +} + +Tool *NaClToolChain::buildLinker() const { + return new tools::nacltools::Linker(*this); +} + +Tool *NaClToolChain::buildAssembler() const { + if (getTriple().getArch() == llvm::Triple::arm) + return new tools::nacltools::AssemblerARM(*this); + return new tools::gnutools::Assembler(*this); +} diff --git a/lib/Driver/ToolChains/NaCl.h b/lib/Driver/ToolChains/NaCl.h new file mode 100644 index 0000000000..31af3a53ad --- /dev/null +++ b/lib/Driver/ToolChains/NaCl.h @@ -0,0 +1,87 @@ +//===--- NaCl.h - Native Client 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_NACL_H +#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_NACL_H + +#include "Gnu.h" +#include "clang/Driver/Tool.h" +#include "clang/Driver/ToolChain.h" + +namespace clang { +namespace driver { +namespace tools { +namespace nacltools { +class LLVM_LIBRARY_VISIBILITY AssemblerARM : public gnutools::Assembler { +public: + AssemblerARM(const ToolChain &TC) : gnutools::Assembler(TC) {} + + 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("NaCl::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 nacltools +} // end namespace tools + +namespace toolchains { + +class LLVM_LIBRARY_VISIBILITY NaClToolChain : public Generic_ELF { +public: + NaClToolChain(const Driver &D, const llvm::Triple &Triple, + const llvm::opt::ArgList &Args); + + void + AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const override; + std::string findLibCxxIncludePath() const override; + + CXXStdlibType GetCXXStdlibType(const llvm::opt::ArgList &Args) const override; + + void AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) const override; + + bool IsIntegratedAssemblerDefault() const override { + return getTriple().getArch() == llvm::Triple::mipsel; + } + + // Get the path to the file containing NaCl's ARM macros. + // It lives in NaClToolChain because the ARMAssembler tool needs a + // const char * that it can pass around, + const char *GetNaClArmMacrosPath() const { return NaClArmMacrosPath.c_str(); } + + std::string ComputeEffectiveClangTriple(const llvm::opt::ArgList &Args, + types::ID InputType) const override; + +protected: + Tool *buildLinker() const override; + Tool *buildAssembler() const override; + +private: + std::string NaClArmMacrosPath; +}; + +} // end namespace toolchains +} // end namespace driver +} // end namespace clang + +#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_NACL_H diff --git a/lib/Driver/ToolChains/NetBSD.cpp b/lib/Driver/ToolChains/NetBSD.cpp new file mode 100644 index 0000000000..d7d3ad61df --- /dev/null +++ b/lib/Driver/ToolChains/NetBSD.cpp @@ -0,0 +1,412 @@ +//===--- NetBSD.cpp - NetBSD 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 "NetBSD.h" +#include "Arch/ARM.h" +#include "Arch/Mips.h" +#include "Arch/Sparc.h" +#include "CommonArgs.h" +#include "clang/Driver/Compilation.h" +#include "clang/Driver/Driver.h" +#include "clang/Driver/Options.h" +#include "llvm/Option/ArgList.h" + +using namespace clang::driver; +using namespace clang::driver::tools; +using namespace clang::driver::toolchains; +using namespace clang; +using namespace llvm::opt; + +void netbsd::Assembler::ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, + const InputInfoList &Inputs, + const ArgList &Args, + const char *LinkingOutput) const { + claimNoWarnArgs(Args); + ArgStringList CmdArgs; + + // GNU as needs different flags for creating the correct output format + // on architectures with different ABIs or optional feature sets. + switch (getToolChain().getArch()) { + case llvm::Triple::x86: + CmdArgs.push_back("--32"); + break; + case llvm::Triple::arm: + case llvm::Triple::armeb: + case llvm::Triple::thumb: + case llvm::Triple::thumbeb: { + StringRef MArch, MCPU; + arm::getARMArchCPUFromArgs(Args, MArch, MCPU, /*FromAs*/ true); + std::string Arch = + arm::getARMTargetCPU(MCPU, MArch, getToolChain().getTriple()); + CmdArgs.push_back(Args.MakeArgString("-mcpu=" + Arch)); + break; + } + + case llvm::Triple::mips: + case llvm::Triple::mipsel: + case llvm::Triple::mips64: + case llvm::Triple::mips64el: { + StringRef CPUName; + StringRef ABIName; + mips::getMipsCPUAndABI(Args, getToolChain().getTriple(), CPUName, ABIName); + + CmdArgs.push_back("-march"); + CmdArgs.push_back(CPUName.data()); + + CmdArgs.push_back("-mabi"); + CmdArgs.push_back(mips::getGnuCompatibleMipsABIName(ABIName).data()); + + if (getToolChain().getArch() == llvm::Triple::mips || + getToolChain().getArch() == llvm::Triple::mips64) + CmdArgs.push_back("-EB"); + else + CmdArgs.push_back("-EL"); + + AddAssemblerKPIC(getToolChain(), Args, CmdArgs); + break; + } + + case llvm::Triple::sparc: + case llvm::Triple::sparcel: { + CmdArgs.push_back("-32"); + std::string CPU = getCPUName(Args, getToolChain().getTriple()); + CmdArgs.push_back(sparc::getSparcAsmModeForCPU(CPU, getToolChain().getTriple())); + AddAssemblerKPIC(getToolChain(), Args, CmdArgs); + break; + } + + case llvm::Triple::sparcv9: { + CmdArgs.push_back("-64"); + std::string CPU = getCPUName(Args, getToolChain().getTriple()); + CmdArgs.push_back(sparc::getSparcAsmModeForCPU(CPU, getToolChain().getTriple())); + AddAssemblerKPIC(getToolChain(), Args, CmdArgs); + break; + } + + default: + break; + } + + 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 netbsd::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 (!D.SysRoot.empty()) + CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot)); + + CmdArgs.push_back("--eh-frame-hdr"); + if (Args.hasArg(options::OPT_static)) { + CmdArgs.push_back("-Bstatic"); + } else { + if (Args.hasArg(options::OPT_rdynamic)) + CmdArgs.push_back("-export-dynamic"); + if (Args.hasArg(options::OPT_shared)) { + CmdArgs.push_back("-Bshareable"); + } else { + Args.AddAllArgs(CmdArgs, options::OPT_pie); + CmdArgs.push_back("-dynamic-linker"); + CmdArgs.push_back("/libexec/ld.elf_so"); + } + } + + // Many NetBSD architectures support more than one ABI. + // Determine the correct emulation for ld. + switch (getToolChain().getArch()) { + case llvm::Triple::x86: + CmdArgs.push_back("-m"); + CmdArgs.push_back("elf_i386"); + break; + case llvm::Triple::arm: + case llvm::Triple::thumb: + CmdArgs.push_back("-m"); + switch (getToolChain().getTriple().getEnvironment()) { + case llvm::Triple::EABI: + case llvm::Triple::GNUEABI: + CmdArgs.push_back("armelf_nbsd_eabi"); + break; + case llvm::Triple::EABIHF: + case llvm::Triple::GNUEABIHF: + CmdArgs.push_back("armelf_nbsd_eabihf"); + break; + default: + CmdArgs.push_back("armelf_nbsd"); + break; + } + break; + case llvm::Triple::armeb: + case llvm::Triple::thumbeb: + arm::appendEBLinkFlags(Args, CmdArgs, getToolChain().getEffectiveTriple()); + CmdArgs.push_back("-m"); + switch (getToolChain().getTriple().getEnvironment()) { + case llvm::Triple::EABI: + case llvm::Triple::GNUEABI: + CmdArgs.push_back("armelfb_nbsd_eabi"); + break; + case llvm::Triple::EABIHF: + case llvm::Triple::GNUEABIHF: + CmdArgs.push_back("armelfb_nbsd_eabihf"); + break; + default: + CmdArgs.push_back("armelfb_nbsd"); + break; + } + break; + case llvm::Triple::mips64: + case llvm::Triple::mips64el: + if (mips::hasMipsAbiArg(Args, "32")) { + CmdArgs.push_back("-m"); + if (getToolChain().getArch() == llvm::Triple::mips64) + CmdArgs.push_back("elf32btsmip"); + else + CmdArgs.push_back("elf32ltsmip"); + } else if (mips::hasMipsAbiArg(Args, "64")) { + CmdArgs.push_back("-m"); + if (getToolChain().getArch() == llvm::Triple::mips64) + CmdArgs.push_back("elf64btsmip"); + else + CmdArgs.push_back("elf64ltsmip"); + } + break; + case llvm::Triple::ppc: + CmdArgs.push_back("-m"); + CmdArgs.push_back("elf32ppc_nbsd"); + break; + + case llvm::Triple::ppc64: + case llvm::Triple::ppc64le: + CmdArgs.push_back("-m"); + CmdArgs.push_back("elf64ppc"); + break; + + case llvm::Triple::sparc: + CmdArgs.push_back("-m"); + CmdArgs.push_back("elf32_sparc"); + break; + + case llvm::Triple::sparcv9: + CmdArgs.push_back("-m"); + CmdArgs.push_back("elf64_sparc"); + break; + + default: + break; + } + + 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)) { + CmdArgs.push_back( + Args.MakeArgString(getToolChain().GetFilePath("crt0.o"))); + } + CmdArgs.push_back( + Args.MakeArgString(getToolChain().GetFilePath("crti.o"))); + if (Args.hasArg(options::OPT_shared) || Args.hasArg(options::OPT_pie)) { + CmdArgs.push_back( + Args.MakeArgString(getToolChain().GetFilePath("crtbeginS.o"))); + } else { + CmdArgs.push_back( + Args.MakeArgString(getToolChain().GetFilePath("crtbegin.o"))); + } + } + + Args.AddAllArgs(CmdArgs, options::OPT_L); + Args.AddAllArgs(CmdArgs, options::OPT_T_Group); + Args.AddAllArgs(CmdArgs, options::OPT_e); + Args.AddAllArgs(CmdArgs, options::OPT_s); + Args.AddAllArgs(CmdArgs, options::OPT_t); + Args.AddAllArgs(CmdArgs, options::OPT_Z_Flag); + Args.AddAllArgs(CmdArgs, options::OPT_r); + + AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA); + + unsigned Major, Minor, Micro; + getToolChain().getTriple().getOSVersion(Major, Minor, Micro); + bool useLibgcc = true; + if (Major >= 7 || Major == 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: + case llvm::Triple::ppc: + case llvm::Triple::ppc64: + case llvm::Triple::ppc64le: + case llvm::Triple::sparc: + case llvm::Triple::sparcv9: + case llvm::Triple::x86: + case llvm::Triple::x86_64: + useLibgcc = false; + break; + default: + break; + } + } + + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { + addOpenMPRuntime(CmdArgs, getToolChain(), Args); + if (D.CCCIsCXX()) { + getToolChain().AddCXXStdlibLibArgs(Args, CmdArgs); + CmdArgs.push_back("-lm"); + } + if (Args.hasArg(options::OPT_pthread)) + CmdArgs.push_back("-lpthread"); + CmdArgs.push_back("-lc"); + + if (useLibgcc) { + if (Args.hasArg(options::OPT_static)) { + // libgcc_eh depends on libc, so resolve as much as possible, + // pull in any new requirements from libc and then get the rest + // of libgcc. + CmdArgs.push_back("-lgcc_eh"); + CmdArgs.push_back("-lc"); + CmdArgs.push_back("-lgcc"); + } else { + CmdArgs.push_back("-lgcc"); + CmdArgs.push_back("--as-needed"); + CmdArgs.push_back("-lgcc_s"); + CmdArgs.push_back("--no-as-needed"); + } + } + } + + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) { + if (Args.hasArg(options::OPT_shared) || Args.hasArg(options::OPT_pie)) + CmdArgs.push_back( + Args.MakeArgString(getToolChain().GetFilePath("crtendS.o"))); + else + CmdArgs.push_back( + Args.MakeArgString(getToolChain().GetFilePath("crtend.o"))); + CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath("crtn.o"))); + } + + getToolChain().addProfileRTLibs(Args, CmdArgs); + + const char *Exec = Args.MakeArgString(getToolChain().GetLinkerPath()); + C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); +} + +/// NetBSD - NetBSD tool chain which can call as(1) and ld(1) directly. + +NetBSD::NetBSD(const Driver &D, const llvm::Triple &Triple, const ArgList &Args) + : Generic_ELF(D, Triple, Args) { + if (getDriver().UseStdLib) { + // 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. + // FIXME: It'd be nicer to test if this directory exists, but I'm not sure + // what all logic is needed to emulate the '=' prefix here. + switch (Triple.getArch()) { + case llvm::Triple::x86: + getFilePaths().push_back("=/usr/lib/i386"); + break; + case llvm::Triple::arm: + case llvm::Triple::armeb: + case llvm::Triple::thumb: + case llvm::Triple::thumbeb: + switch (Triple.getEnvironment()) { + case llvm::Triple::EABI: + case llvm::Triple::GNUEABI: + getFilePaths().push_back("=/usr/lib/eabi"); + break; + case llvm::Triple::EABIHF: + case llvm::Triple::GNUEABIHF: + getFilePaths().push_back("=/usr/lib/eabihf"); + break; + default: + getFilePaths().push_back("=/usr/lib/oabi"); + break; + } + break; + case llvm::Triple::mips64: + case llvm::Triple::mips64el: + if (tools::mips::hasMipsAbiArg(Args, "o32")) + getFilePaths().push_back("=/usr/lib/o32"); + else if (tools::mips::hasMipsAbiArg(Args, "64")) + getFilePaths().push_back("=/usr/lib/64"); + break; + case llvm::Triple::ppc: + getFilePaths().push_back("=/usr/lib/powerpc"); + break; + case llvm::Triple::sparc: + getFilePaths().push_back("=/usr/lib/sparc"); + break; + default: + break; + } + + getFilePaths().push_back("=/usr/lib"); + } +} + +Tool *NetBSD::buildAssembler() const { + return new tools::netbsd::Assembler(*this); +} + +Tool *NetBSD::buildLinker() const { return new tools::netbsd::Linker(*this); } + +ToolChain::CXXStdlibType NetBSD::GetDefaultCXXStdlibType() const { + unsigned Major, Minor, Micro; + getTriple().getOSVersion(Major, Minor, Micro); + if (Major >= 7 || Major == 0) { + switch (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: + case llvm::Triple::ppc: + case llvm::Triple::ppc64: + case llvm::Triple::ppc64le: + case llvm::Triple::sparc: + case llvm::Triple::sparcv9: + case llvm::Triple::x86: + case llvm::Triple::x86_64: + return ToolChain::CST_Libcxx; + default: + break; + } + } + return ToolChain::CST_Libstdcxx; +} + +std::string NetBSD::findLibCxxIncludePath() const { + return getDriver().SysRoot + "/usr/include/c++/"; +} + +void NetBSD::addLibStdCxxIncludePaths(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const { + addLibStdCXXIncludePaths(getDriver().SysRoot, "/usr/include/g++", "", "", "", + "", DriverArgs, CC1Args); +} diff --git a/lib/Driver/ToolChains/NetBSD.h b/lib/Driver/ToolChains/NetBSD.h new file mode 100644 index 0000000000..d53aa68678 --- /dev/null +++ b/lib/Driver/ToolChains/NetBSD.h @@ -0,0 +1,79 @@ +//===--- NetBSD.h - NetBSD 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_NETBSD_H +#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_NETBSD_H + +#include "Gnu.h" +#include "clang/Driver/Tool.h" +#include "clang/Driver/ToolChain.h" + +namespace clang { +namespace driver { +namespace tools { + +/// netbsd -- Directly call GNU Binutils assembler and linker +namespace netbsd { +class LLVM_LIBRARY_VISIBILITY Assembler : public GnuTool { +public: + Assembler(const ToolChain &TC) + : GnuTool("netbsd::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("netbsd::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 netbsd +} // end namespace tools + +namespace toolchains { + +class LLVM_LIBRARY_VISIBILITY NetBSD : public Generic_ELF { +public: + NetBSD(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; + + std::string findLibCxxIncludePath() const override; + void addLibStdCxxIncludePaths( + const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const override; + + bool IsUnwindTablesDefault() const override { return true; } + +protected: + Tool *buildAssembler() const override; + Tool *buildLinker() const override; +}; + +} // end namespace toolchains +} // end namespace driver +} // end namespace clang + +#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_NETBSD_H diff --git a/lib/Driver/ToolChains/OpenBSD.cpp b/lib/Driver/ToolChains/OpenBSD.cpp new file mode 100644 index 0000000000..c5f266ec8f --- /dev/null +++ b/lib/Driver/ToolChains/OpenBSD.cpp @@ -0,0 +1,234 @@ +//===--- OpenBSD.cpp - OpenBSD 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 "OpenBSD.h" +#include "Arch/Mips.h" +#include "Arch/Sparc.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::tools; +using namespace clang::driver::toolchains; +using namespace clang; +using namespace llvm::opt; + +void openbsd::Assembler::ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, + const InputInfoList &Inputs, + const ArgList &Args, + const char *LinkingOutput) const { + claimNoWarnArgs(Args); + ArgStringList CmdArgs; + + switch (getToolChain().getArch()) { + case llvm::Triple::x86: + // When building 32-bit code on OpenBSD/amd64, we have to explicitly + // instruct as in the base system to assemble 32-bit code. + CmdArgs.push_back("--32"); + break; + + case llvm::Triple::ppc: + CmdArgs.push_back("-mppc"); + CmdArgs.push_back("-many"); + break; + + case llvm::Triple::sparc: + case llvm::Triple::sparcel: { + CmdArgs.push_back("-32"); + std::string CPU = getCPUName(Args, getToolChain().getTriple()); + CmdArgs.push_back(sparc::getSparcAsmModeForCPU(CPU, getToolChain().getTriple())); + AddAssemblerKPIC(getToolChain(), Args, CmdArgs); + break; + } + + case llvm::Triple::sparcv9: { + CmdArgs.push_back("-64"); + std::string CPU = getCPUName(Args, getToolChain().getTriple()); + CmdArgs.push_back(sparc::getSparcAsmModeForCPU(CPU, getToolChain().getTriple())); + AddAssemblerKPIC(getToolChain(), Args, CmdArgs); + break; + } + + case llvm::Triple::mips64: + case llvm::Triple::mips64el: { + StringRef CPUName; + StringRef ABIName; + mips::getMipsCPUAndABI(Args, getToolChain().getTriple(), CPUName, ABIName); + + CmdArgs.push_back("-mabi"); + CmdArgs.push_back(mips::getGnuCompatibleMipsABIName(ABIName).data()); + + if (getToolChain().getArch() == llvm::Triple::mips64) + CmdArgs.push_back("-EB"); + else + CmdArgs.push_back("-EL"); + + AddAssemblerKPIC(getToolChain(), Args, CmdArgs); + break; + } + + default: + break; + } + + 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 openbsd::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; + + // Silence warning for "clang -g foo.o -o foo" + Args.ClaimAllArgs(options::OPT_g_Group); + // and "clang -emit-llvm foo.o -o foo" + Args.ClaimAllArgs(options::OPT_emit_llvm); + // and for "clang -w foo.o -o foo". Other warning options are already + // handled somewhere else. + Args.ClaimAllArgs(options::OPT_w); + + if (getToolChain().getArch() == llvm::Triple::mips64) + CmdArgs.push_back("-EB"); + else if (getToolChain().getArch() == llvm::Triple::mips64el) + CmdArgs.push_back("-EL"); + + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_shared)) { + CmdArgs.push_back("-e"); + CmdArgs.push_back("__start"); + } + + CmdArgs.push_back("--eh-frame-hdr"); + 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("-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 (Args.hasArg(options::OPT_nopie)) + CmdArgs.push_back("-nopie"); + + 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 if (Args.hasArg(options::OPT_static) && + !Args.hasArg(options::OPT_nopie)) + CmdArgs.push_back( + Args.MakeArgString(getToolChain().GetFilePath("rcrt0.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"))); + } + } + + std::string Triple = getToolChain().getTripleString(); + if (Triple.substr(0, 6) == "x86_64") + Triple.replace(0, 6, "amd64"); + CmdArgs.push_back( + Args.MakeArgString("-L/usr/lib/gcc-lib/" + Triple + "/4.2.1")); + + Args.AddAllArgs(CmdArgs, {options::OPT_L, options::OPT_T_Group, + options::OPT_e, options::OPT_s, options::OPT_t, + options::OPT_Z_Flag, options::OPT_r}); + + 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"); + } + + // FIXME: For some reason GCC passes -lgcc before adding + // the default system libraries. Just mimic this for now. + CmdArgs.push_back("-lgcc"); + + 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"); + } + + CmdArgs.push_back("-lgcc"); + } + + 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)); +} + +/// OpenBSD - OpenBSD tool chain which can call as(1) and ld(1) directly. + +OpenBSD::OpenBSD(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 *OpenBSD::buildAssembler() const { + return new tools::openbsd::Assembler(*this); +} + +Tool *OpenBSD::buildLinker() const { return new tools::openbsd::Linker(*this); } diff --git a/lib/Driver/ToolChains/OpenBSD.h b/lib/Driver/ToolChains/OpenBSD.h new file mode 100644 index 0000000000..1cc0ca7198 --- /dev/null +++ b/lib/Driver/ToolChains/OpenBSD.h @@ -0,0 +1,76 @@ +//===--- OpenBSD.h - OpenBSD 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_OPENBSD_H +#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_OPENBSD_H + +#include "Gnu.h" +#include "clang/Driver/Tool.h" +#include "clang/Driver/ToolChain.h" + +namespace clang { +namespace driver { +namespace tools { + +/// openbsd -- Directly call GNU Binutils assembler and linker +namespace openbsd { +class LLVM_LIBRARY_VISIBILITY Assembler : public GnuTool { +public: + Assembler(const ToolChain &TC) + : GnuTool("openbsd::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("openbsd::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 openbsd +} // end namespace tools + +namespace toolchains { + +class LLVM_LIBRARY_VISIBILITY OpenBSD : public Generic_ELF { +public: + OpenBSD(const Driver &D, const llvm::Triple &Triple, + const llvm::opt::ArgList &Args); + + bool IsMathErrnoDefault() const override { return false; } + bool IsObjCNonFragileABIDefault() const override { return true; } + bool isPIEDefault() const override { return true; } + + unsigned GetDefaultStackProtectorLevel(bool KernelOrKext) const override { + return 2; + } + unsigned GetDefaultDwarfVersion() const override { return 2; } + +protected: + Tool *buildAssembler() const override; + Tool *buildLinker() const override; +}; + +} // end namespace toolchains +} // end namespace driver +} // end namespace clang + +#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_OPENBSD_H diff --git a/lib/Driver/ToolChains/PS4CPU.cpp b/lib/Driver/ToolChains/PS4CPU.cpp new file mode 100644 index 0000000000..c1b8c3d660 --- /dev/null +++ b/lib/Driver/ToolChains/PS4CPU.cpp @@ -0,0 +1,419 @@ +//===--- PS4CPU.cpp - PS4CPU 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 "PS4CPU.h" +#include "FreeBSD.h" +#include "CommonArgs.h" +#include "clang/Driver/Compilation.h" +#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/FileSystem.h" +#include "llvm/Support/Path.h" +#include <cstdlib> // ::getenv + +using namespace clang::driver; +using namespace clang; +using namespace llvm::opt; + +using clang::driver::tools::AddLinkerInputs; + +void tools::PS4cpu::addProfileRTArgs(const ToolChain &TC, const ArgList &Args, + ArgStringList &CmdArgs) { + if ((Args.hasFlag(options::OPT_fprofile_arcs, options::OPT_fno_profile_arcs, + false) || + Args.hasFlag(options::OPT_fprofile_generate, + options::OPT_fno_profile_instr_generate, false) || + Args.hasFlag(options::OPT_fprofile_generate_EQ, + options::OPT_fno_profile_instr_generate, false) || + Args.hasFlag(options::OPT_fprofile_instr_generate, + options::OPT_fno_profile_instr_generate, false) || + Args.hasFlag(options::OPT_fprofile_instr_generate_EQ, + options::OPT_fno_profile_instr_generate, false) || + Args.hasArg(options::OPT_fcreate_profile) || + Args.hasArg(options::OPT_coverage))) + CmdArgs.push_back("--dependent-lib=libclang_rt.profile-x86_64.a"); +} + +void tools::PS4cpu::Assemble::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()); + + assert(Inputs.size() == 1 && "Unexpected number of inputs."); + const InputInfo &Input = Inputs[0]; + assert(Input.isFilename() && "Invalid input."); + CmdArgs.push_back(Input.getFilename()); + + const char *Exec = + Args.MakeArgString(getToolChain().GetProgramPath("orbis-as")); + C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); +} + +static void AddPS4SanitizerArgs(const ToolChain &TC, ArgStringList &CmdArgs) { + const SanitizerArgs &SanArgs = TC.getSanitizerArgs(); + if (SanArgs.needsUbsanRt()) { + CmdArgs.push_back("-lSceDbgUBSanitizer_stub_weak"); + } + if (SanArgs.needsAsanRt()) { + CmdArgs.push_back("-lSceDbgAddressSanitizer_stub_weak"); + } +} + +static void ConstructPS4LinkJob(const Tool &T, Compilation &C, + const JobAction &JA, const InputInfo &Output, + const InputInfoList &Inputs, + const ArgList &Args, + const char *LinkingOutput) { + const toolchains::FreeBSD &ToolChain = + static_cast<const toolchains::FreeBSD &>(T.getToolChain()); + const Driver &D = ToolChain.getDriver(); + ArgStringList CmdArgs; + + // Silence warning for "clang -g foo.o -o foo" + Args.ClaimAllArgs(options::OPT_g_Group); + // and "clang -emit-llvm foo.o -o foo" + Args.ClaimAllArgs(options::OPT_emit_llvm); + // and for "clang -w foo.o -o foo". Other warning options are already + // handled somewhere else. + Args.ClaimAllArgs(options::OPT_w); + + if (!D.SysRoot.empty()) + CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot)); + + if (Args.hasArg(options::OPT_pie)) + CmdArgs.push_back("-pie"); + + if (Args.hasArg(options::OPT_rdynamic)) + CmdArgs.push_back("-export-dynamic"); + if (Args.hasArg(options::OPT_shared)) + CmdArgs.push_back("--oformat=so"); + + if (Output.isFilename()) { + CmdArgs.push_back("-o"); + CmdArgs.push_back(Output.getFilename()); + } else { + assert(Output.isNothing() && "Invalid output."); + } + + AddPS4SanitizerArgs(ToolChain, CmdArgs); + + Args.AddAllArgs(CmdArgs, options::OPT_L); + Args.AddAllArgs(CmdArgs, options::OPT_T_Group); + Args.AddAllArgs(CmdArgs, options::OPT_e); + Args.AddAllArgs(CmdArgs, options::OPT_s); + Args.AddAllArgs(CmdArgs, options::OPT_t); + Args.AddAllArgs(CmdArgs, options::OPT_r); + + if (Args.hasArg(options::OPT_Z_Xlinker__no_demangle)) + CmdArgs.push_back("--no-demangle"); + + AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA); + + if (Args.hasArg(options::OPT_pthread)) { + CmdArgs.push_back("-lpthread"); + } + + const char *Exec = Args.MakeArgString(ToolChain.GetProgramPath("orbis-ld")); + + C.addCommand(llvm::make_unique<Command>(JA, T, Exec, CmdArgs, Inputs)); +} + +static void ConstructGoldLinkJob(const Tool &T, Compilation &C, + const JobAction &JA, const InputInfo &Output, + const InputInfoList &Inputs, + const ArgList &Args, + const char *LinkingOutput) { + const toolchains::FreeBSD &ToolChain = + static_cast<const toolchains::FreeBSD &>(T.getToolChain()); + const Driver &D = ToolChain.getDriver(); + ArgStringList CmdArgs; + + // Silence warning for "clang -g foo.o -o foo" + Args.ClaimAllArgs(options::OPT_g_Group); + // and "clang -emit-llvm foo.o -o foo" + Args.ClaimAllArgs(options::OPT_emit_llvm); + // and for "clang -w foo.o -o foo". Other warning options are already + // handled somewhere else. + Args.ClaimAllArgs(options::OPT_w); + + if (!D.SysRoot.empty()) + CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot)); + + if (Args.hasArg(options::OPT_pie)) + CmdArgs.push_back("-pie"); + + 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"); + if (Args.hasArg(options::OPT_shared)) { + CmdArgs.push_back("-Bshareable"); + } else { + CmdArgs.push_back("-dynamic-linker"); + CmdArgs.push_back("/libexec/ld-elf.so.1"); + } + CmdArgs.push_back("--enable-new-dtags"); + } + + if (Output.isFilename()) { + CmdArgs.push_back("-o"); + CmdArgs.push_back(Output.getFilename()); + } else { + assert(Output.isNothing() && "Invalid output."); + } + + AddPS4SanitizerArgs(ToolChain, CmdArgs); + + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) { + const char *crt1 = nullptr; + if (!Args.hasArg(options::OPT_shared)) { + if (Args.hasArg(options::OPT_pg)) + crt1 = "gcrt1.o"; + else if (Args.hasArg(options::OPT_pie)) + crt1 = "Scrt1.o"; + else + crt1 = "crt1.o"; + } + if (crt1) + CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crt1))); + + CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crti.o"))); + + const char *crtbegin = nullptr; + if (Args.hasArg(options::OPT_static)) + crtbegin = "crtbeginT.o"; + else if (Args.hasArg(options::OPT_shared) || Args.hasArg(options::OPT_pie)) + crtbegin = "crtbeginS.o"; + else + crtbegin = "crtbegin.o"; + + CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crtbegin))); + } + + Args.AddAllArgs(CmdArgs, options::OPT_L); + ToolChain.AddFilePathLibArgs(Args, CmdArgs); + Args.AddAllArgs(CmdArgs, options::OPT_T_Group); + Args.AddAllArgs(CmdArgs, options::OPT_e); + Args.AddAllArgs(CmdArgs, options::OPT_s); + Args.AddAllArgs(CmdArgs, options::OPT_t); + Args.AddAllArgs(CmdArgs, options::OPT_r); + + if (Args.hasArg(options::OPT_Z_Xlinker__no_demangle)) + CmdArgs.push_back("--no-demangle"); + + AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA); + + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { + // For PS4, we always want to pass libm, libstdc++ and libkernel + // libraries for both C and C++ compilations. + CmdArgs.push_back("-lkernel"); + if (D.CCCIsCXX()) { + ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs); + if (Args.hasArg(options::OPT_pg)) + CmdArgs.push_back("-lm_p"); + else + CmdArgs.push_back("-lm"); + } + // FIXME: For some reason GCC passes -lgcc and -lgcc_s before adding + // the default system libraries. Just mimic this for now. + if (Args.hasArg(options::OPT_pg)) + CmdArgs.push_back("-lgcc_p"); + else + CmdArgs.push_back("-lcompiler_rt"); + if (Args.hasArg(options::OPT_static)) { + CmdArgs.push_back("-lstdc++"); + } else if (Args.hasArg(options::OPT_pg)) { + CmdArgs.push_back("-lgcc_eh_p"); + } else { + CmdArgs.push_back("--as-needed"); + CmdArgs.push_back("-lstdc++"); + CmdArgs.push_back("--no-as-needed"); + } + + if (Args.hasArg(options::OPT_pthread)) { + if (Args.hasArg(options::OPT_pg)) + CmdArgs.push_back("-lpthread_p"); + else + CmdArgs.push_back("-lpthread"); + } + + if (Args.hasArg(options::OPT_pg)) { + if (Args.hasArg(options::OPT_shared)) + CmdArgs.push_back("-lc"); + else { + if (Args.hasArg(options::OPT_static)) { + CmdArgs.push_back("--start-group"); + CmdArgs.push_back("-lc_p"); + CmdArgs.push_back("-lpthread_p"); + CmdArgs.push_back("--end-group"); + } else { + CmdArgs.push_back("-lc_p"); + } + } + CmdArgs.push_back("-lgcc_p"); + } else { + if (Args.hasArg(options::OPT_static)) { + CmdArgs.push_back("--start-group"); + CmdArgs.push_back("-lc"); + CmdArgs.push_back("-lpthread"); + CmdArgs.push_back("--end-group"); + } else { + CmdArgs.push_back("-lc"); + } + CmdArgs.push_back("-lcompiler_rt"); + } + + if (Args.hasArg(options::OPT_static)) { + CmdArgs.push_back("-lstdc++"); + } else if (Args.hasArg(options::OPT_pg)) { + CmdArgs.push_back("-lgcc_eh_p"); + } else { + CmdArgs.push_back("--as-needed"); + CmdArgs.push_back("-lstdc++"); + CmdArgs.push_back("--no-as-needed"); + } + } + + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) { + if (Args.hasArg(options::OPT_shared) || Args.hasArg(options::OPT_pie)) + CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtendS.o"))); + else + CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtend.o"))); + CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtn.o"))); + } + + const char *Exec = +#ifdef LLVM_ON_WIN32 + Args.MakeArgString(ToolChain.GetProgramPath("orbis-ld.gold")); +#else + Args.MakeArgString(ToolChain.GetProgramPath("orbis-ld")); +#endif + + C.addCommand(llvm::make_unique<Command>(JA, T, Exec, CmdArgs, Inputs)); +} + +void tools::PS4cpu::Link::ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, + const InputInfoList &Inputs, + const ArgList &Args, + const char *LinkingOutput) const { + const toolchains::FreeBSD &ToolChain = + static_cast<const toolchains::FreeBSD &>(getToolChain()); + const Driver &D = ToolChain.getDriver(); + bool PS4Linker; + StringRef LinkerOptName; + if (const Arg *A = Args.getLastArg(options::OPT_fuse_ld_EQ)) { + LinkerOptName = A->getValue(); + if (LinkerOptName != "ps4" && LinkerOptName != "gold") + D.Diag(diag::err_drv_unsupported_linker) << LinkerOptName; + } + + if (LinkerOptName == "gold") + PS4Linker = false; + else if (LinkerOptName == "ps4") + PS4Linker = true; + else + PS4Linker = !Args.hasArg(options::OPT_shared); + + if (PS4Linker) + ConstructPS4LinkJob(*this, C, JA, Output, Inputs, Args, LinkingOutput); + else + ConstructGoldLinkJob(*this, C, JA, Output, Inputs, Args, LinkingOutput); +} + +toolchains::PS4CPU::PS4CPU(const Driver &D, const llvm::Triple &Triple, + const ArgList &Args) + : Generic_ELF(D, Triple, Args) { + if (Args.hasArg(clang::driver::options::OPT_static)) + D.Diag(clang::diag::err_drv_unsupported_opt_for_target) << "-static" + << "PS4"; + + // Determine where to find the PS4 libraries. We use SCE_ORBIS_SDK_DIR + // if it exists; otherwise use the driver's installation path, which + // should be <SDK_DIR>/host_tools/bin. + + SmallString<512> PS4SDKDir; + if (const char *EnvValue = getenv("SCE_ORBIS_SDK_DIR")) { + if (!llvm::sys::fs::exists(EnvValue)) + getDriver().Diag(clang::diag::warn_drv_ps4_sdk_dir) << EnvValue; + PS4SDKDir = EnvValue; + } else { + PS4SDKDir = getDriver().Dir; + llvm::sys::path::append(PS4SDKDir, "/../../"); + } + + // By default, the driver won't report a warning if it can't find + // PS4's include or lib directories. This behavior could be changed if + // -Weverything or -Winvalid-or-nonexistent-directory options are passed. + // If -isysroot was passed, use that as the SDK base path. + std::string PrefixDir; + if (const Arg *A = Args.getLastArg(options::OPT_isysroot)) { + PrefixDir = A->getValue(); + if (!llvm::sys::fs::exists(PrefixDir)) + getDriver().Diag(clang::diag::warn_missing_sysroot) << PrefixDir; + } else + PrefixDir = PS4SDKDir.str(); + + SmallString<512> PS4SDKIncludeDir(PrefixDir); + llvm::sys::path::append(PS4SDKIncludeDir, "target/include"); + if (!Args.hasArg(options::OPT_nostdinc) && + !Args.hasArg(options::OPT_nostdlibinc) && + !Args.hasArg(options::OPT_isysroot) && + !Args.hasArg(options::OPT__sysroot_EQ) && + !llvm::sys::fs::exists(PS4SDKIncludeDir)) { + getDriver().Diag(clang::diag::warn_drv_unable_to_find_directory_expected) + << "PS4 system headers" << PS4SDKIncludeDir; + } + + SmallString<512> PS4SDKLibDir(PS4SDKDir); + llvm::sys::path::append(PS4SDKLibDir, "target/lib"); + if (!Args.hasArg(options::OPT_nostdlib) && + !Args.hasArg(options::OPT_nodefaultlibs) && + !Args.hasArg(options::OPT__sysroot_EQ) && !Args.hasArg(options::OPT_E) && + !Args.hasArg(options::OPT_c) && !Args.hasArg(options::OPT_S) && + !Args.hasArg(options::OPT_emit_ast) && + !llvm::sys::fs::exists(PS4SDKLibDir)) { + getDriver().Diag(clang::diag::warn_drv_unable_to_find_directory_expected) + << "PS4 system libraries" << PS4SDKLibDir; + return; + } + getFilePaths().push_back(PS4SDKLibDir.str()); +} + +Tool *toolchains::PS4CPU::buildAssembler() const { + return new tools::PS4cpu::Assemble(*this); +} + +Tool *toolchains::PS4CPU::buildLinker() const { + return new tools::PS4cpu::Link(*this); +} + +bool toolchains::PS4CPU::isPICDefault() const { return true; } + +bool toolchains::PS4CPU::HasNativeLLVMSupport() const { return true; } + +SanitizerMask toolchains::PS4CPU::getSupportedSanitizers() const { + SanitizerMask Res = ToolChain::getSupportedSanitizers(); + Res |= SanitizerKind::Address; + Res |= SanitizerKind::Vptr; + return Res; +} diff --git a/lib/Driver/ToolChains/PS4CPU.h b/lib/Driver/ToolChains/PS4CPU.h new file mode 100644 index 0000000000..e507edbad4 --- /dev/null +++ b/lib/Driver/ToolChains/PS4CPU.h @@ -0,0 +1,93 @@ +//===--- PS4CPU.h - PS4CPU 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_PS4CPU_H +#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_PS4CPU_H + +#include "Gnu.h" +#include "clang/Driver/Tool.h" +#include "clang/Driver/ToolChain.h" + +namespace clang { +namespace driver { +namespace tools { + +namespace PS4cpu { + +void addProfileRTArgs(const ToolChain &TC, const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs); + +class LLVM_LIBRARY_VISIBILITY Assemble : public Tool { +public: + Assemble(const ToolChain &TC) + : Tool("PS4cpu::Assemble", "assembler", TC, RF_Full) {} + + 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 Link : public Tool { +public: + Link(const ToolChain &TC) : Tool("PS4cpu::Link", "linker", TC, RF_Full) {} + + 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 PS4cpu +} // namespace tools + +namespace toolchains { + +class LLVM_LIBRARY_VISIBILITY PS4CPU : public Generic_ELF { +public: + PS4CPU(const Driver &D, const llvm::Triple &Triple, + const llvm::opt::ArgList &Args); + + // No support for finding a C++ standard library yet. + std::string findLibCxxIncludePath() const override { return ""; } + void addLibStdCxxIncludePaths( + const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const override {} + + bool IsMathErrnoDefault() const override { return false; } + bool IsObjCNonFragileABIDefault() const override { return true; } + bool HasNativeLLVMSupport() const override; + bool isPICDefault() const override; + + unsigned GetDefaultStackProtectorLevel(bool KernelOrKext) const override { + return 2; // SSPStrong + } + + llvm::DebuggerKind getDefaultDebuggerTuning() const override { + return llvm::DebuggerKind::SCE; + } + + SanitizerMask getSupportedSanitizers() const override; + +protected: + Tool *buildAssembler() const override; + Tool *buildLinker() const override; +}; + +} // end namespace toolchains +} // end namespace driver +} // end namespace clang + +#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_PS4CPU_H diff --git a/lib/Driver/ToolChains/Solaris.cpp b/lib/Driver/ToolChains/Solaris.cpp new file mode 100644 index 0000000000..78797c49d7 --- /dev/null +++ b/lib/Driver/ToolChains/Solaris.cpp @@ -0,0 +1,193 @@ +//===--- Solaris.cpp - Solaris 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 "Solaris.h" +#include "CommonArgs.h" +#include "clang/Config/config.h" +#include "clang/Driver/Compilation.h" +#include "clang/Driver/Driver.h" +#include "clang/Driver/DriverDiagnostic.h" +#include "clang/Driver/Options.h" +#include "llvm/Option/ArgList.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/Path.h" + +using namespace clang::driver; +using namespace clang::driver::tools; +using namespace clang::driver::toolchains; +using namespace clang; +using namespace llvm::opt; + +void solaris::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 solaris::Linker::ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, + const InputInfoList &Inputs, + const ArgList &Args, + const char *LinkingOutput) const { + ArgStringList CmdArgs; + + // Demangle C++ names in errors + CmdArgs.push_back("-C"); + + 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"); + CmdArgs.push_back("-dn"); + } else { + CmdArgs.push_back("-Bdynamic"); + if (Args.hasArg(options::OPT_shared)) { + CmdArgs.push_back("-shared"); + } else { + CmdArgs.push_back("--dynamic-linker"); + CmdArgs.push_back( + Args.MakeArgString(getToolChain().GetFilePath("ld.so.1"))); + } + } + + 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)) + CmdArgs.push_back( + Args.MakeArgString(getToolChain().GetFilePath("crt1.o"))); + + CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath("crti.o"))); + CmdArgs.push_back( + Args.MakeArgString(getToolChain().GetFilePath("values-Xa.o"))); + CmdArgs.push_back( + Args.MakeArgString(getToolChain().GetFilePath("crtbegin.o"))); + } + + getToolChain().AddFilePathLibArgs(Args, CmdArgs); + + Args.AddAllArgs(CmdArgs, {options::OPT_L, options::OPT_T_Group, + options::OPT_e, options::OPT_r}); + + AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA); + + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { + if (getToolChain().getDriver().CCCIsCXX()) + getToolChain().AddCXXStdlibLibArgs(Args, CmdArgs); + CmdArgs.push_back("-lgcc_s"); + CmdArgs.push_back("-lc"); + if (!Args.hasArg(options::OPT_shared)) { + CmdArgs.push_back("-lgcc"); + CmdArgs.push_back("-lm"); + } + } + + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) { + CmdArgs.push_back( + Args.MakeArgString(getToolChain().GetFilePath("crtend.o"))); + } + CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath("crtn.o"))); + + getToolChain().addProfileRTLibs(Args, CmdArgs); + + const char *Exec = Args.MakeArgString(getToolChain().GetLinkerPath()); + C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); +} + +/// Solaris - Solaris tool chain which can call as(1) and ld(1) directly. + +Solaris::Solaris(const Driver &D, const llvm::Triple &Triple, + const ArgList &Args) + : Generic_GCC(D, Triple, Args) { + + GCCInstallation.init(Triple, Args); + + path_list &Paths = getFilePaths(); + if (GCCInstallation.isValid()) + addPathIfExists(D, GCCInstallation.getInstallPath(), Paths); + + addPathIfExists(D, getDriver().getInstalledDir(), Paths); + if (getDriver().getInstalledDir() != getDriver().Dir) + addPathIfExists(D, getDriver().Dir, Paths); + + addPathIfExists(D, getDriver().SysRoot + getDriver().Dir + "/../lib", Paths); + + std::string LibPath = "/usr/lib/"; + switch (Triple.getArch()) { + case llvm::Triple::x86: + case llvm::Triple::sparc: + break; + case llvm::Triple::x86_64: + LibPath += "amd64/"; + break; + case llvm::Triple::sparcv9: + LibPath += "sparcv9/"; + break; + default: + llvm_unreachable("Unsupported architecture"); + } + + addPathIfExists(D, getDriver().SysRoot + LibPath, Paths); +} + +Tool *Solaris::buildAssembler() const { + return new tools::solaris::Assembler(*this); +} + +Tool *Solaris::buildLinker() const { return new tools::solaris::Linker(*this); } + +void Solaris::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs, + ArgStringList &CC1Args) const { + if (DriverArgs.hasArg(options::OPT_nostdlibinc) || + DriverArgs.hasArg(options::OPT_nostdincxx)) + return; + + // Include the support directory for things like xlocale and fudged system + // headers. + // FIXME: This is a weird mix of libc++ and libstdc++. We should also be + // checking the value of -stdlib= here and adding the includes for libc++ + // rather than libstdc++ if it's requested. + addSystemInclude(DriverArgs, CC1Args, "/usr/include/c++/v1/support/solaris"); + + if (GCCInstallation.isValid()) { + GCCVersion Version = GCCInstallation.getVersion(); + addSystemInclude(DriverArgs, CC1Args, + getDriver().SysRoot + "/usr/gcc/" + + Version.MajorStr + "." + + Version.MinorStr + + "/include/c++/" + Version.Text); + addSystemInclude(DriverArgs, CC1Args, + getDriver().SysRoot + "/usr/gcc/" + Version.MajorStr + + "." + Version.MinorStr + "/include/c++/" + + Version.Text + "/" + + GCCInstallation.getTriple().str()); + } +} diff --git a/lib/Driver/ToolChains/Solaris.h b/lib/Driver/ToolChains/Solaris.h new file mode 100644 index 0000000000..edb44373b3 --- /dev/null +++ b/lib/Driver/ToolChains/Solaris.h @@ -0,0 +1,75 @@ +//===--- Solaris.h - Solaris 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_SOLARIS_H +#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_SOLARIS_H + +#include "Gnu.h" +#include "clang/Driver/Tool.h" +#include "clang/Driver/ToolChain.h" + +namespace clang { +namespace driver { +namespace tools { + +/// solaris -- Directly call Solaris assembler and linker +namespace solaris { +class LLVM_LIBRARY_VISIBILITY Assembler : public Tool { +public: + Assembler(const ToolChain &TC) + : Tool("solaris::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 Tool { +public: + Linker(const ToolChain &TC) : Tool("solaris::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 solaris +} // end namespace tools + +namespace toolchains { + +class LLVM_LIBRARY_VISIBILITY Solaris : public Generic_GCC { +public: + Solaris(const Driver &D, const llvm::Triple &Triple, + const llvm::opt::ArgList &Args); + + bool IsIntegratedAssemblerDefault() const override { return true; } + + void AddClangCXXStdlibIncludeArgs( + const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const override; + + unsigned GetDefaultDwarfVersion() const override { return 2; } + +protected: + Tool *buildAssembler() const override; + Tool *buildLinker() const override; +}; + +} // end namespace toolchains +} // end namespace driver +} // end namespace clang + +#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_SOLARIS_H diff --git a/lib/Driver/ToolChains/TCE.cpp b/lib/Driver/ToolChains/TCE.cpp new file mode 100644 index 0000000000..e4f7180c11 --- /dev/null +++ b/lib/Driver/ToolChains/TCE.cpp @@ -0,0 +1,47 @@ +//===--- TCE.cpp - TCE 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 "TCE.h" +#include "CommonArgs.h" + +using namespace clang::driver; +using namespace clang::driver::toolchains;; +using namespace clang; +using namespace llvm::opt; + +/// TCEToolChain - A tool chain using the llvm bitcode tools to perform +/// all subcommands. See http://tce.cs.tut.fi for our peculiar target. +/// Currently does not support anything else but compilation. + +TCEToolChain::TCEToolChain(const Driver &D, const llvm::Triple &Triple, + const ArgList &Args) + : ToolChain(D, Triple, Args) { + // Path mangling to find libexec + std::string Path(getDriver().Dir); + + Path += "/../libexec"; + getProgramPaths().push_back(Path); +} + +TCEToolChain::~TCEToolChain() {} + +bool TCEToolChain::IsMathErrnoDefault() const { return true; } + +bool TCEToolChain::isPICDefault() const { return false; } + +bool TCEToolChain::isPIEDefault() const { return false; } + +bool TCEToolChain::isPICDefaultForced() const { return false; } + +TCELEToolChain::TCELEToolChain(const Driver &D, const llvm::Triple& Triple, + const ArgList &Args) + : TCEToolChain(D, Triple, Args) { +} + +TCELEToolChain::~TCELEToolChain() {} diff --git a/lib/Driver/ToolChains/TCE.h b/lib/Driver/ToolChains/TCE.h new file mode 100644 index 0000000000..4644f4eedb --- /dev/null +++ b/lib/Driver/ToolChains/TCE.h @@ -0,0 +1,47 @@ +//===--- TCE.h - TCE Tool and ToolChain Implementations ---------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_TCE_H +#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_TCE_H + +#include "clang/Driver/Driver.h" +#include "clang/Driver/ToolChain.h" +#include <set> + +namespace clang { +namespace driver { +namespace toolchains { + +/// TCEToolChain - A tool chain using the llvm bitcode tools to perform +/// all subcommands. See http://tce.cs.tut.fi for our peculiar target. +class LLVM_LIBRARY_VISIBILITY TCEToolChain : public ToolChain { +public: + TCEToolChain(const Driver &D, const llvm::Triple &Triple, + const llvm::opt::ArgList &Args); + ~TCEToolChain() override; + + bool IsMathErrnoDefault() const override; + bool isPICDefault() const override; + bool isPIEDefault() const override; + bool isPICDefaultForced() const override; +}; + +/// Toolchain for little endian TCE cores. +class LLVM_LIBRARY_VISIBILITY TCELEToolChain : public TCEToolChain { +public: + TCELEToolChain(const Driver &D, const llvm::Triple &Triple, + const llvm::opt::ArgList &Args); + ~TCELEToolChain() override; +}; + +} // end namespace toolchains +} // end namespace driver +} // end namespace clang + +#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_TCE_H diff --git a/lib/Driver/ToolChains/WebAssembly.cpp b/lib/Driver/ToolChains/WebAssembly.cpp new file mode 100644 index 0000000000..123a1516f1 --- /dev/null +++ b/lib/Driver/ToolChains/WebAssembly.cpp @@ -0,0 +1,163 @@ +//===--- WebAssembly.cpp - WebAssembly ToolChain Implementation -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "WebAssembly.h" +#include "CommonArgs.h" +#include "clang/Driver/Compilation.h" +#include "clang/Driver/Driver.h" +#include "clang/Driver/Options.h" +#include "llvm/Option/ArgList.h" + +using namespace clang::driver; +using namespace clang::driver::tools; +using namespace clang::driver::toolchains; +using namespace clang; +using namespace llvm::opt; + +wasm::Linker::Linker(const ToolChain &TC) + : GnuTool("wasm::Linker", "lld", TC) {} + +bool wasm::Linker::isLinkJob() const { + return true; +} + +bool wasm::Linker::hasIntegratedCPP() const { + return false; +} + +void wasm::Linker::ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, + const InputInfoList &Inputs, + const ArgList &Args, + 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("ld"); + + // 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); + 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"))); + } + + AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA); + + if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { + if (D.CCCIsCXX()) + ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs); + + if (Args.hasArg(options::OPT_pthread)) + CmdArgs.push_back("-lpthread"); + + CmdArgs.push_back("-lc"); + CmdArgs.push_back("-lcompiler_rt"); + } + + 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()); + + C.addCommand(llvm::make_unique<Command>(JA, *this, Linker, CmdArgs, Inputs)); +} + +WebAssembly::WebAssembly(const Driver &D, const llvm::Triple &Triple, + const llvm::opt::ArgList &Args) + : ToolChain(D, Triple, Args) { + + assert(Triple.isArch32Bit() != Triple.isArch64Bit()); + getFilePaths().push_back( + getDriver().SysRoot + "/lib" + (Triple.isArch32Bit() ? "32" : "64")); +} + +bool WebAssembly::IsMathErrnoDefault() const { return false; } + +bool WebAssembly::IsObjCNonFragileABIDefault() const { return true; } + +bool WebAssembly::UseObjCMixedDispatch() const { return true; } + +bool WebAssembly::isPICDefault() const { return false; } + +bool WebAssembly::isPIEDefault() const { return false; } + +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. +bool WebAssembly::SupportsProfiling() const { return false; } + +bool WebAssembly::HasNativeLLVMSupport() const { return true; } + +void WebAssembly::addClangTargetOptions(const ArgList &DriverArgs, + ArgStringList &CC1Args) const { + if (DriverArgs.hasFlag(clang::driver::options::OPT_fuse_init_array, + options::OPT_fno_use_init_array, true)) + CC1Args.push_back("-fuse-init-array"); +} + +ToolChain::RuntimeLibType WebAssembly::GetDefaultRuntimeLibType() const { + return ToolChain::RLT_CompilerRT; +} + +ToolChain::CXXStdlibType WebAssembly::GetCXXStdlibType(const ArgList &Args) const { + return ToolChain::CST_Libcxx; +} + +void WebAssembly::AddClangSystemIncludeArgs(const ArgList &DriverArgs, + ArgStringList &CC1Args) const { + if (!DriverArgs.hasArg(options::OPT_nostdinc)) + addSystemInclude(DriverArgs, CC1Args, getDriver().SysRoot + "/include"); +} + +void WebAssembly::AddClangCXXStdlibIncludeArgs(const ArgList &DriverArgs, + ArgStringList &CC1Args) const { + if (!DriverArgs.hasArg(options::OPT_nostdlibinc) && + !DriverArgs.hasArg(options::OPT_nostdincxx)) + addSystemInclude(DriverArgs, CC1Args, + getDriver().SysRoot + "/include/c++/v1"); +} + +Tool *WebAssembly::buildLinker() const { + return new tools::wasm::Linker(*this); +} diff --git a/lib/Driver/ToolChains/WebAssembly.h b/lib/Driver/ToolChains/WebAssembly.h new file mode 100644 index 0000000000..ca42fc651a --- /dev/null +++ b/lib/Driver/ToolChains/WebAssembly.h @@ -0,0 +1,77 @@ +//===--- WebAssembly.h - WebAssembly 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_WEBASSEMBLY_H +#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_WEBASSEMBLY_H + +#include "Gnu.h" +#include "clang/Driver/Tool.h" +#include "clang/Driver/ToolChain.h" + +namespace clang { +namespace driver { +namespace tools { +namespace wasm { + +class LLVM_LIBRARY_VISIBILITY Linker : public GnuTool { +public: + explicit Linker(const ToolChain &TC); + bool isLinkJob() const override; + bool hasIntegratedCPP() const override; + 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 wasm +} // end namespace tools + +namespace toolchains { + +class LLVM_LIBRARY_VISIBILITY WebAssembly final : public ToolChain { +public: + WebAssembly(const Driver &D, const llvm::Triple &Triple, + const llvm::opt::ArgList &Args); + +private: + bool IsMathErrnoDefault() const override; + bool IsObjCNonFragileABIDefault() const override; + bool UseObjCMixedDispatch() const override; + bool isPICDefault() const override; + bool isPIEDefault() const override; + 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, + llvm::opt::ArgStringList &CC1Args) const override; + RuntimeLibType GetDefaultRuntimeLibType() const override; + CXXStdlibType GetCXXStdlibType(const llvm::opt::ArgList &Args) const override; + void AddClangSystemIncludeArgs( + const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const override; + void AddClangCXXStdlibIncludeArgs( + const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const override; + + const char *getDefaultLinker() const override { + return "lld"; + } + + Tool *buildLinker() const override; +}; + +} // end namespace toolchains +} // end namespace driver +} // end namespace clang + +#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_WEBASSEMBLY_H diff --git a/lib/Driver/ToolChains/XCore.cpp b/lib/Driver/ToolChains/XCore.cpp new file mode 100644 index 0000000000..cc9ee119d0 --- /dev/null +++ b/lib/Driver/ToolChains/XCore.cpp @@ -0,0 +1,149 @@ +//===--- XCore.cpp - XCore 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 "XCore.h" +#include "CommonArgs.h" +#include "clang/Driver/Compilation.h" +#include "clang/Driver/Driver.h" +#include "clang/Driver/Options.h" +#include "llvm/Option/ArgList.h" +#include <cstdlib> // ::getenv + +using namespace clang::driver; +using namespace clang::driver::toolchains;; +using namespace clang; +using namespace llvm::opt; + +/// XCore Tools +// We pass assemble and link construction to the xcc tool. + +void tools::XCore::Assembler::ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, + const InputInfoList &Inputs, + const ArgList &Args, + const char *LinkingOutput) const { + claimNoWarnArgs(Args); + ArgStringList CmdArgs; + + CmdArgs.push_back("-o"); + CmdArgs.push_back(Output.getFilename()); + + CmdArgs.push_back("-c"); + + if (Args.hasArg(options::OPT_v)) + CmdArgs.push_back("-v"); + + if (Arg *A = Args.getLastArg(options::OPT_g_Group)) + if (!A->getOption().matches(options::OPT_g0)) + CmdArgs.push_back("-g"); + + if (Args.hasFlag(options::OPT_fverbose_asm, options::OPT_fno_verbose_asm, + false)) + CmdArgs.push_back("-fverbose-asm"); + + Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler); + + for (const auto &II : Inputs) + CmdArgs.push_back(II.getFilename()); + + const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("xcc")); + C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); +} + +void tools::XCore::Linker::ConstructJob(Compilation &C, const JobAction &JA, + const InputInfo &Output, + const InputInfoList &Inputs, + const ArgList &Args, + const char *LinkingOutput) const { + ArgStringList CmdArgs; + + if (Output.isFilename()) { + CmdArgs.push_back("-o"); + CmdArgs.push_back(Output.getFilename()); + } else { + assert(Output.isNothing() && "Invalid output."); + } + + if (Args.hasArg(options::OPT_v)) + CmdArgs.push_back("-v"); + + // Pass -fexceptions through to the linker if it was present. + if (Args.hasFlag(options::OPT_fexceptions, options::OPT_fno_exceptions, + false)) + CmdArgs.push_back("-fexceptions"); + + AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA); + + const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("xcc")); + C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); +} + +/// XCore tool chain +XCoreToolChain::XCoreToolChain(const Driver &D, const llvm::Triple &Triple, + const ArgList &Args) + : ToolChain(D, Triple, Args) { + // ProgramPaths are found via 'PATH' environment variable. +} + +Tool *XCoreToolChain::buildAssembler() const { + return new tools::XCore::Assembler(*this); +} + +Tool *XCoreToolChain::buildLinker() const { + return new tools::XCore::Linker(*this); +} + +bool XCoreToolChain::isPICDefault() const { return false; } + +bool XCoreToolChain::isPIEDefault() const { return false; } + +bool XCoreToolChain::isPICDefaultForced() const { return false; } + +bool XCoreToolChain::SupportsProfiling() const { return false; } + +bool XCoreToolChain::hasBlocksRuntime() const { return false; } + +void XCoreToolChain::AddClangSystemIncludeArgs(const ArgList &DriverArgs, + ArgStringList &CC1Args) const { + if (DriverArgs.hasArg(clang::driver::options::OPT_nostdinc) || + DriverArgs.hasArg(options::OPT_nostdlibinc)) + return; + if (const char *cl_include_dir = getenv("XCC_C_INCLUDE_PATH")) { + SmallVector<StringRef, 4> Dirs; + const char EnvPathSeparatorStr[] = {llvm::sys::EnvPathSeparator, '\0'}; + StringRef(cl_include_dir).split(Dirs, StringRef(EnvPathSeparatorStr)); + ArrayRef<StringRef> DirVec(Dirs); + addSystemIncludes(DriverArgs, CC1Args, DirVec); + } +} + +void XCoreToolChain::addClangTargetOptions(const ArgList &DriverArgs, + ArgStringList &CC1Args) const { + CC1Args.push_back("-nostdsysteminc"); +} + +void XCoreToolChain::AddClangCXXStdlibIncludeArgs( + const ArgList &DriverArgs, ArgStringList &CC1Args) const { + if (DriverArgs.hasArg(clang::driver::options::OPT_nostdinc) || + DriverArgs.hasArg(options::OPT_nostdlibinc) || + DriverArgs.hasArg(options::OPT_nostdincxx)) + return; + if (const char *cl_include_dir = getenv("XCC_CPLUS_INCLUDE_PATH")) { + SmallVector<StringRef, 4> Dirs; + const char EnvPathSeparatorStr[] = {llvm::sys::EnvPathSeparator, '\0'}; + StringRef(cl_include_dir).split(Dirs, StringRef(EnvPathSeparatorStr)); + ArrayRef<StringRef> DirVec(Dirs); + addSystemIncludes(DriverArgs, CC1Args, DirVec); + } +} + +void XCoreToolChain::AddCXXStdlibLibArgs(const ArgList &Args, + ArgStringList &CmdArgs) const { + // We don't output any lib args. This is handled by xcc. +} diff --git a/lib/Driver/ToolChains/XCore.h b/lib/Driver/ToolChains/XCore.h new file mode 100644 index 0000000000..4084b1cdec --- /dev/null +++ b/lib/Driver/ToolChains/XCore.h @@ -0,0 +1,82 @@ +//===--- XCore.h - XCore 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_XCORE_H +#define LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_XCORE_H + +#include "clang/Driver/Tool.h" +#include "clang/Driver/ToolChain.h" + +namespace clang { +namespace driver { +namespace tools { + +namespace XCore { +// For XCore, we do not need to instantiate tools for PreProcess, PreCompile and +// Compile. +// We simply use "clang -cc1" for those actions. +class LLVM_LIBRARY_VISIBILITY Assembler : public Tool { +public: + Assembler(const ToolChain &TC) : Tool("XCore::Assembler", "XCore-as", 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 Tool { +public: + Linker(const ToolChain &TC) : Tool("XCore::Linker", "XCore-ld", 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 XCore. +} // end namespace tools + +namespace toolchains { + +class LLVM_LIBRARY_VISIBILITY XCoreToolChain : public ToolChain { +public: + XCoreToolChain(const Driver &D, const llvm::Triple &Triple, + const llvm::opt::ArgList &Args); + +protected: + Tool *buildAssembler() const override; + Tool *buildLinker() const override; + +public: + bool isPICDefault() const override; + bool isPIEDefault() const override; + bool isPICDefaultForced() const override; + bool SupportsProfiling() const override; + bool hasBlocksRuntime() const override; + void + AddClangSystemIncludeArgs(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const override; + void addClangTargetOptions(const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const override; + void AddClangCXXStdlibIncludeArgs( + const llvm::opt::ArgList &DriverArgs, + llvm::opt::ArgStringList &CC1Args) const override; + void AddCXXStdlibLibArgs(const llvm::opt::ArgList &Args, + llvm::opt::ArgStringList &CmdArgs) const override; +}; + +} // end namespace toolchains +} // end namespace driver +} // end namespace clang + +#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_XCORE_H diff --git a/lib/Driver/Tools.cpp b/lib/Driver/Tools.cpp deleted file mode 100644 index 139fceadc1..0000000000 --- a/lib/Driver/Tools.cpp +++ /dev/null @@ -1,11005 +0,0 @@ -//===--- Tools.cpp - Tools Implementations ----------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "Tools.h" -#include "InputInfo.h" -#include "ToolChains.h" -#include "clang/Basic/CharInfo.h" -#include "clang/Basic/LangOptions.h" -#include "clang/Basic/ObjCRuntime.h" -#include "clang/Basic/Version.h" -#include "clang/Basic/VirtualFileSystem.h" -#include "clang/Config/config.h" -#include "clang/Driver/Action.h" -#include "clang/Driver/Compilation.h" -#include "clang/Driver/Driver.h" -#include "clang/Driver/DriverDiagnostic.h" -#include "clang/Driver/Job.h" -#include "clang/Driver/Options.h" -#include "clang/Driver/SanitizerArgs.h" -#include "clang/Driver/ToolChain.h" -#include "clang/Driver/Util.h" -#include "llvm/ADT/STLExtras.h" -#include "llvm/ADT/SmallString.h" -#include "llvm/ADT/StringExtras.h" -#include "llvm/ADT/StringSwitch.h" -#include "llvm/ADT/Twine.h" -#include "llvm/Option/Arg.h" -#include "llvm/Option/ArgList.h" -#include "llvm/Option/Option.h" -#include "llvm/Support/CodeGen.h" -#include "llvm/Support/Compression.h" -#include "llvm/Support/ErrorHandling.h" -#include "llvm/Support/FileSystem.h" -#include "llvm/Support/Host.h" -#include "llvm/Support/Path.h" -#include "llvm/Support/Process.h" -#include "llvm/Support/Program.h" -#include "llvm/Support/ScopedPrinter.h" -#include "llvm/Support/TargetParser.h" -#include "llvm/Support/YAMLParser.h" - -#ifdef LLVM_ON_UNIX -#include <unistd.h> // For getuid(). -#endif - -using namespace clang::driver; -using namespace clang::driver::tools; -using namespace clang; -using namespace llvm::opt; - -void tools::handleTargetFeaturesGroup(const ArgList &Args, - std::vector<StringRef> &Features, - OptSpecifier Group) { - for (const Arg *A : Args.filtered(Group)) { - StringRef Name = A->getOption().getName(); - A->claim(); - - // Skip over "-m". - assert(Name.startswith("m") && "Invalid feature name."); - Name = Name.substr(1); - - bool IsNegative = Name.startswith("no-"); - if (IsNegative) - Name = Name.substr(3); - Features.push_back(Args.MakeArgString((IsNegative ? "-" : "+") + Name)); - } -} - -static void CheckPreprocessingOptions(const Driver &D, const ArgList &Args) { - if (Arg *A = Args.getLastArg(options::OPT_C, options::OPT_CC)) { - if (!Args.hasArg(options::OPT_E) && !Args.hasArg(options::OPT__SLASH_P) && - !Args.hasArg(options::OPT__SLASH_EP) && !D.CCCIsCPP()) { - D.Diag(diag::err_drv_argument_only_allowed_with) - << A->getBaseArg().getAsString(Args) - << (D.IsCLMode() ? "/E, /P or /EP" : "-E"); - } - } -} - -static void CheckCodeGenerationOptions(const Driver &D, const ArgList &Args) { - // In gcc, only ARM checks this, but it seems reasonable to check universally. - if (Args.hasArg(options::OPT_static)) - if (const Arg *A = - Args.getLastArg(options::OPT_dynamic, options::OPT_mdynamic_no_pic)) - D.Diag(diag::err_drv_argument_not_allowed_with) << A->getAsString(Args) - << "-static"; -} - -// Add backslashes to escape spaces and other backslashes. -// This is used for the space-separated argument list specified with -// the -dwarf-debug-flags option. -static void EscapeSpacesAndBackslashes(const char *Arg, - SmallVectorImpl<char> &Res) { - for (; *Arg; ++Arg) { - switch (*Arg) { - default: - break; - case ' ': - case '\\': - Res.push_back('\\'); - break; - } - Res.push_back(*Arg); - } -} - -// Quote target names for inclusion in GNU Make dependency files. -// Only the characters '$', '#', ' ', '\t' are quoted. -static void QuoteTarget(StringRef Target, SmallVectorImpl<char> &Res) { - for (unsigned i = 0, e = Target.size(); i != e; ++i) { - switch (Target[i]) { - case ' ': - case '\t': - // Escape the preceding backslashes - for (int j = i - 1; j >= 0 && Target[j] == '\\'; --j) - Res.push_back('\\'); - - // Escape the space/tab - Res.push_back('\\'); - break; - case '$': - Res.push_back('$'); - break; - case '#': - Res.push_back('\\'); - break; - default: - break; - } - - Res.push_back(Target[i]); - } -} - -static void addDirectoryList(const ArgList &Args, ArgStringList &CmdArgs, - const char *ArgName, const char *EnvVar) { - const char *DirList = ::getenv(EnvVar); - bool CombinedArg = false; - - if (!DirList) - return; // Nothing to do. - - StringRef Name(ArgName); - if (Name.equals("-I") || Name.equals("-L")) - CombinedArg = true; - - StringRef Dirs(DirList); - if (Dirs.empty()) // Empty string should not add '.'. - return; - - StringRef::size_type Delim; - while ((Delim = Dirs.find(llvm::sys::EnvPathSeparator)) != StringRef::npos) { - if (Delim == 0) { // Leading colon. - if (CombinedArg) { - CmdArgs.push_back(Args.MakeArgString(std::string(ArgName) + ".")); - } else { - CmdArgs.push_back(ArgName); - CmdArgs.push_back("."); - } - } else { - if (CombinedArg) { - CmdArgs.push_back( - Args.MakeArgString(std::string(ArgName) + Dirs.substr(0, Delim))); - } else { - CmdArgs.push_back(ArgName); - CmdArgs.push_back(Args.MakeArgString(Dirs.substr(0, Delim))); - } - } - Dirs = Dirs.substr(Delim + 1); - } - - if (Dirs.empty()) { // Trailing colon. - if (CombinedArg) { - CmdArgs.push_back(Args.MakeArgString(std::string(ArgName) + ".")); - } else { - CmdArgs.push_back(ArgName); - CmdArgs.push_back("."); - } - } else { // Add the last path. - if (CombinedArg) { - CmdArgs.push_back(Args.MakeArgString(std::string(ArgName) + Dirs)); - } else { - CmdArgs.push_back(ArgName); - CmdArgs.push_back(Args.MakeArgString(Dirs)); - } - } -} - -static void AddLinkerInputs(const ToolChain &TC, const InputInfoList &Inputs, - const ArgList &Args, ArgStringList &CmdArgs, - const JobAction &JA) { - const Driver &D = TC.getDriver(); - - // Add extra linker input arguments which are not treated as inputs - // (constructed via -Xarch_). - Args.AddAllArgValues(CmdArgs, options::OPT_Zlinker_input); - - for (const auto &II : Inputs) { - // If the current tool chain refers to an OpenMP offloading host, we should - // ignore inputs that refer to OpenMP offloading devices - they will be - // embedded according to a proper linker script. - if (auto *IA = II.getAction()) - if (JA.isHostOffloading(Action::OFK_OpenMP) && - IA->isDeviceOffloading(Action::OFK_OpenMP)) - continue; - - if (!TC.HasNativeLLVMSupport() && types::isLLVMIR(II.getType())) - // Don't try to pass LLVM inputs unless we have native support. - D.Diag(diag::err_drv_no_linker_llvm_support) << TC.getTripleString(); - - // Add filenames immediately. - if (II.isFilename()) { - CmdArgs.push_back(II.getFilename()); - continue; - } - - // Otherwise, this is a linker input argument. - const Arg &A = II.getInputArg(); - - // Handle reserved library options. - if (A.getOption().matches(options::OPT_Z_reserved_lib_stdcxx)) - TC.AddCXXStdlibLibArgs(Args, CmdArgs); - else if (A.getOption().matches(options::OPT_Z_reserved_lib_cckext)) - TC.AddCCKextLibArgs(Args, CmdArgs); - else if (A.getOption().matches(options::OPT_z)) { - // Pass -z prefix for gcc linker compatibility. - A.claim(); - A.render(Args, CmdArgs); - } else { - A.renderAsInput(Args, CmdArgs); - } - } - - // LIBRARY_PATH - included following the user specified library paths. - // and only supported on native toolchains. - if (!TC.isCrossCompiling()) { - addDirectoryList(Args, CmdArgs, "-L", "LIBRARY_PATH"); - } -} - -/// Add OpenMP linker script arguments at the end of the argument list so that -/// the fat binary is built by embedding each of the device images into the -/// host. The linker script also defines a few symbols required by the code -/// generation so that the images can be easily retrieved at runtime by the -/// offloading library. This should be used only in tool chains that support -/// linker scripts. -static void AddOpenMPLinkerScript(const ToolChain &TC, Compilation &C, - const InputInfo &Output, - const InputInfoList &Inputs, - const ArgList &Args, ArgStringList &CmdArgs, - const JobAction &JA) { - - // If this is not an OpenMP host toolchain, we don't need to do anything. - if (!JA.isHostOffloading(Action::OFK_OpenMP)) - return; - - // Create temporary linker script. Keep it if save-temps is enabled. - const char *LKS; - SmallString<256> Name = llvm::sys::path::filename(Output.getFilename()); - if (C.getDriver().isSaveTempsEnabled()) { - llvm::sys::path::replace_extension(Name, "lk"); - LKS = C.getArgs().MakeArgString(Name.c_str()); - } else { - llvm::sys::path::replace_extension(Name, ""); - Name = C.getDriver().GetTemporaryPath(Name, "lk"); - LKS = C.addTempFile(C.getArgs().MakeArgString(Name.c_str())); - } - - // Add linker script option to the command. - CmdArgs.push_back("-T"); - CmdArgs.push_back(LKS); - - // Create a buffer to write the contents of the linker script. - std::string LksBuffer; - llvm::raw_string_ostream LksStream(LksBuffer); - - // Get the OpenMP offload tool chains so that we can extract the triple - // associated with each device input. - auto OpenMPToolChains = C.getOffloadToolChains<Action::OFK_OpenMP>(); - assert(OpenMPToolChains.first != OpenMPToolChains.second && - "No OpenMP toolchains??"); - - // Track the input file name and device triple in order to build the script, - // inserting binaries in the designated sections. - SmallVector<std::pair<std::string, const char *>, 8> InputBinaryInfo; - - // Add commands to embed target binaries. We ensure that each section and - // image is 16-byte aligned. This is not mandatory, but increases the - // likelihood of data to be aligned with a cache block in several main host - // machines. - LksStream << "/*\n"; - LksStream << " OpenMP Offload Linker Script\n"; - LksStream << " *** Automatically generated by Clang ***\n"; - LksStream << "*/\n"; - LksStream << "TARGET(binary)\n"; - auto DTC = OpenMPToolChains.first; - for (auto &II : Inputs) { - const Action *A = II.getAction(); - // Is this a device linking action? - if (A && isa<LinkJobAction>(A) && - A->isDeviceOffloading(Action::OFK_OpenMP)) { - assert(DTC != OpenMPToolChains.second && - "More device inputs than device toolchains??"); - InputBinaryInfo.push_back(std::make_pair( - DTC->second->getTriple().normalize(), II.getFilename())); - ++DTC; - LksStream << "INPUT(" << II.getFilename() << ")\n"; - } - } - - assert(DTC == OpenMPToolChains.second && - "Less device inputs than device toolchains??"); - - LksStream << "SECTIONS\n"; - LksStream << "{\n"; - LksStream << " .omp_offloading :\n"; - LksStream << " ALIGN(0x10)\n"; - LksStream << " {\n"; - - for (auto &BI : InputBinaryInfo) { - LksStream << " . = ALIGN(0x10);\n"; - LksStream << " PROVIDE_HIDDEN(.omp_offloading.img_start." << BI.first - << " = .);\n"; - LksStream << " " << BI.second << "\n"; - LksStream << " PROVIDE_HIDDEN(.omp_offloading.img_end." << BI.first - << " = .);\n"; - } - - LksStream << " }\n"; - // Add commands to define host entries begin and end. We use 1-byte subalign - // so that the linker does not add any padding and the elements in this - // section form an array. - LksStream << " .omp_offloading.entries :\n"; - LksStream << " ALIGN(0x10)\n"; - LksStream << " SUBALIGN(0x01)\n"; - LksStream << " {\n"; - LksStream << " PROVIDE_HIDDEN(.omp_offloading.entries_begin = .);\n"; - LksStream << " *(.omp_offloading.entries)\n"; - LksStream << " PROVIDE_HIDDEN(.omp_offloading.entries_end = .);\n"; - LksStream << " }\n"; - LksStream << "}\n"; - LksStream << "INSERT BEFORE .data\n"; - LksStream.flush(); - - // Dump the contents of the linker script if the user requested that. We - // support this option to enable testing of behavior with -###. - if (C.getArgs().hasArg(options::OPT_fopenmp_dump_offload_linker_script)) - llvm::errs() << LksBuffer; - - // If this is a dry run, do not create the linker script file. - if (C.getArgs().hasArg(options::OPT__HASH_HASH_HASH)) - return; - - // Open script file and write the contents. - std::error_code EC; - llvm::raw_fd_ostream Lksf(LKS, EC, llvm::sys::fs::F_None); - - if (EC) { - C.getDriver().Diag(clang::diag::err_unable_to_make_temp) << EC.message(); - return; - } - - Lksf << LksBuffer; -} - -/// \brief Determine whether Objective-C automated reference counting is -/// enabled. -static bool isObjCAutoRefCount(const ArgList &Args) { - return Args.hasFlag(options::OPT_fobjc_arc, options::OPT_fno_objc_arc, false); -} - -/// \brief Determine whether we are linking the ObjC runtime. -static bool isObjCRuntimeLinked(const ArgList &Args) { - if (isObjCAutoRefCount(Args)) { - Args.ClaimAllArgs(options::OPT_fobjc_link_runtime); - return true; - } - return Args.hasArg(options::OPT_fobjc_link_runtime); -} - -static bool forwardToGCC(const Option &O) { - // Don't forward inputs from the original command line. They are added from - // InputInfoList. - return O.getKind() != Option::InputClass && - !O.hasFlag(options::DriverOption) && !O.hasFlag(options::LinkerInput); -} - -/// Apply \a Work on the current tool chain \a RegularToolChain and any other -/// offloading tool chain that is associated with the current action \a JA. -static void -forAllAssociatedToolChains(Compilation &C, const JobAction &JA, - const ToolChain &RegularToolChain, - llvm::function_ref<void(const ToolChain &)> Work) { - // Apply Work on the current/regular tool chain. - Work(RegularToolChain); - - // Apply Work on all the offloading tool chains associated with the current - // action. - if (JA.isHostOffloading(Action::OFK_Cuda)) - Work(*C.getSingleOffloadToolChain<Action::OFK_Cuda>()); - else if (JA.isDeviceOffloading(Action::OFK_Cuda)) - Work(*C.getSingleOffloadToolChain<Action::OFK_Host>()); - - // - // TODO: Add support for other offloading programming models here. - // -} - -void Clang::AddPreprocessingOptions(Compilation &C, const JobAction &JA, - const Driver &D, const ArgList &Args, - ArgStringList &CmdArgs, - const InputInfo &Output, - const InputInfoList &Inputs) const { - Arg *A; - const bool IsIAMCU = getToolChain().getTriple().isOSIAMCU(); - - CheckPreprocessingOptions(D, Args); - - Args.AddLastArg(CmdArgs, options::OPT_C); - Args.AddLastArg(CmdArgs, options::OPT_CC); - - // Handle dependency file generation. - if ((A = Args.getLastArg(options::OPT_M, options::OPT_MM)) || - (A = Args.getLastArg(options::OPT_MD)) || - (A = Args.getLastArg(options::OPT_MMD))) { - // Determine the output location. - const char *DepFile; - if (Arg *MF = Args.getLastArg(options::OPT_MF)) { - DepFile = MF->getValue(); - C.addFailureResultFile(DepFile, &JA); - } else if (Output.getType() == types::TY_Dependencies) { - DepFile = Output.getFilename(); - } else if (A->getOption().matches(options::OPT_M) || - A->getOption().matches(options::OPT_MM)) { - DepFile = "-"; - } else { - DepFile = getDependencyFileName(Args, Inputs); - C.addFailureResultFile(DepFile, &JA); - } - CmdArgs.push_back("-dependency-file"); - CmdArgs.push_back(DepFile); - - // Add a default target if one wasn't specified. - if (!Args.hasArg(options::OPT_MT) && !Args.hasArg(options::OPT_MQ)) { - const char *DepTarget; - - // If user provided -o, that is the dependency target, except - // when we are only generating a dependency file. - Arg *OutputOpt = Args.getLastArg(options::OPT_o); - if (OutputOpt && Output.getType() != types::TY_Dependencies) { - DepTarget = OutputOpt->getValue(); - } else { - // Otherwise derive from the base input. - // - // FIXME: This should use the computed output file location. - SmallString<128> P(Inputs[0].getBaseInput()); - llvm::sys::path::replace_extension(P, "o"); - DepTarget = Args.MakeArgString(llvm::sys::path::filename(P)); - } - - CmdArgs.push_back("-MT"); - SmallString<128> Quoted; - QuoteTarget(DepTarget, Quoted); - CmdArgs.push_back(Args.MakeArgString(Quoted)); - } - - if (A->getOption().matches(options::OPT_M) || - A->getOption().matches(options::OPT_MD)) - CmdArgs.push_back("-sys-header-deps"); - if ((isa<PrecompileJobAction>(JA) && - !Args.hasArg(options::OPT_fno_module_file_deps)) || - Args.hasArg(options::OPT_fmodule_file_deps)) - CmdArgs.push_back("-module-file-deps"); - } - - if (Args.hasArg(options::OPT_MG)) { - if (!A || A->getOption().matches(options::OPT_MD) || - A->getOption().matches(options::OPT_MMD)) - D.Diag(diag::err_drv_mg_requires_m_or_mm); - CmdArgs.push_back("-MG"); - } - - Args.AddLastArg(CmdArgs, options::OPT_MP); - Args.AddLastArg(CmdArgs, options::OPT_MV); - - // Convert all -MQ <target> args to -MT <quoted target> - for (const Arg *A : Args.filtered(options::OPT_MT, options::OPT_MQ)) { - A->claim(); - - if (A->getOption().matches(options::OPT_MQ)) { - CmdArgs.push_back("-MT"); - SmallString<128> Quoted; - QuoteTarget(A->getValue(), Quoted); - CmdArgs.push_back(Args.MakeArgString(Quoted)); - - // -MT flag - no change - } else { - A->render(Args, CmdArgs); - } - } - - // Add offload include arguments specific for CUDA. This must happen before - // we -I or -include anything else, because we must pick up the CUDA headers - // from the particular CUDA installation, rather than from e.g. - // /usr/local/include. - if (JA.isOffloading(Action::OFK_Cuda)) - getToolChain().AddCudaIncludeArgs(Args, CmdArgs); - - // Add -i* options, and automatically translate to - // -include-pch/-include-pth for transparent PCH support. It's - // wonky, but we include looking for .gch so we can support seamless - // replacement into a build system already set up to be generating - // .gch files. - int YcIndex = -1, YuIndex = -1; - { - int AI = -1; - const Arg *YcArg = Args.getLastArg(options::OPT__SLASH_Yc); - const Arg *YuArg = Args.getLastArg(options::OPT__SLASH_Yu); - for (const Arg *A : Args.filtered(options::OPT_clang_i_Group)) { - // Walk the whole i_Group and skip non "-include" flags so that the index - // here matches the index in the next loop below. - ++AI; - if (!A->getOption().matches(options::OPT_include)) - continue; - if (YcArg && strcmp(A->getValue(), YcArg->getValue()) == 0) - YcIndex = AI; - if (YuArg && strcmp(A->getValue(), YuArg->getValue()) == 0) - YuIndex = AI; - } - } - if (isa<PrecompileJobAction>(JA) && YcIndex != -1) { - Driver::InputList Inputs; - D.BuildInputs(getToolChain(), C.getArgs(), Inputs); - assert(Inputs.size() == 1 && "Need one input when building pch"); - CmdArgs.push_back(Args.MakeArgString(Twine("-find-pch-source=") + - Inputs[0].second->getValue())); - } - - bool RenderedImplicitInclude = false; - int AI = -1; - for (const Arg *A : Args.filtered(options::OPT_clang_i_Group)) { - ++AI; - - if (getToolChain().getDriver().IsCLMode() && - A->getOption().matches(options::OPT_include)) { - // In clang-cl mode, /Ycfoo.h means that all code up to a foo.h - // include is compiled into foo.h, and everything after goes into - // the .obj file. /Yufoo.h means that all includes prior to and including - // foo.h are completely skipped and replaced with a use of the pch file - // for foo.h. (Each flag can have at most one value, multiple /Yc flags - // just mean that the last one wins.) If /Yc and /Yu are both present - // and refer to the same file, /Yc wins. - // Note that OPT__SLASH_FI gets mapped to OPT_include. - // FIXME: The code here assumes that /Yc and /Yu refer to the same file. - // cl.exe seems to support both flags with different values, but that - // seems strange (which flag does /Fp now refer to?), so don't implement - // that until someone needs it. - int PchIndex = YcIndex != -1 ? YcIndex : YuIndex; - if (PchIndex != -1) { - if (isa<PrecompileJobAction>(JA)) { - // When building the pch, skip all includes after the pch. - assert(YcIndex != -1 && PchIndex == YcIndex); - if (AI >= YcIndex) - continue; - } else { - // When using the pch, skip all includes prior to the pch. - if (AI < PchIndex) { - A->claim(); - continue; - } - if (AI == PchIndex) { - A->claim(); - CmdArgs.push_back("-include-pch"); - CmdArgs.push_back( - Args.MakeArgString(D.GetClPchPath(C, A->getValue()))); - continue; - } - } - } - } else if (A->getOption().matches(options::OPT_include)) { - // Handling of gcc-style gch precompiled headers. - bool IsFirstImplicitInclude = !RenderedImplicitInclude; - RenderedImplicitInclude = true; - - // Use PCH if the user requested it. - bool UsePCH = D.CCCUsePCH; - - bool FoundPTH = false; - bool FoundPCH = false; - SmallString<128> P(A->getValue()); - // We want the files to have a name like foo.h.pch. Add a dummy extension - // so that replace_extension does the right thing. - P += ".dummy"; - if (UsePCH) { - llvm::sys::path::replace_extension(P, "pch"); - if (llvm::sys::fs::exists(P)) - FoundPCH = true; - } - - if (!FoundPCH) { - llvm::sys::path::replace_extension(P, "pth"); - if (llvm::sys::fs::exists(P)) - FoundPTH = true; - } - - if (!FoundPCH && !FoundPTH) { - llvm::sys::path::replace_extension(P, "gch"); - if (llvm::sys::fs::exists(P)) { - FoundPCH = UsePCH; - FoundPTH = !UsePCH; - } - } - - if (FoundPCH || FoundPTH) { - if (IsFirstImplicitInclude) { - A->claim(); - if (UsePCH) - CmdArgs.push_back("-include-pch"); - else - CmdArgs.push_back("-include-pth"); - CmdArgs.push_back(Args.MakeArgString(P)); - continue; - } else { - // Ignore the PCH if not first on command line and emit warning. - D.Diag(diag::warn_drv_pch_not_first_include) << P - << A->getAsString(Args); - } - } - } else if (A->getOption().matches(options::OPT_isystem_after)) { - // Handling of paths which must come late. These entries are handled by - // the toolchain itself after the resource dir is inserted in the right - // search order. - // Do not claim the argument so that the use of the argument does not - // silently go unnoticed on toolchains which do not honour the option. - continue; - } - - // Not translated, render as usual. - A->claim(); - A->render(Args, CmdArgs); - } - - Args.AddAllArgs(CmdArgs, - {options::OPT_D, options::OPT_U, options::OPT_I_Group, - options::OPT_F, options::OPT_index_header_map}); - - // Add -Wp, and -Xpreprocessor if using the preprocessor. - - // FIXME: There is a very unfortunate problem here, some troubled - // souls abuse -Wp, to pass preprocessor options in gcc syntax. To - // really support that we would have to parse and then translate - // those options. :( - Args.AddAllArgValues(CmdArgs, options::OPT_Wp_COMMA, - options::OPT_Xpreprocessor); - - // -I- is a deprecated GCC feature, reject it. - if (Arg *A = Args.getLastArg(options::OPT_I_)) - D.Diag(diag::err_drv_I_dash_not_supported) << A->getAsString(Args); - - // If we have a --sysroot, and don't have an explicit -isysroot flag, add an - // -isysroot to the CC1 invocation. - StringRef sysroot = C.getSysRoot(); - if (sysroot != "") { - if (!Args.hasArg(options::OPT_isysroot)) { - CmdArgs.push_back("-isysroot"); - CmdArgs.push_back(C.getArgs().MakeArgString(sysroot)); - } - } - - // Parse additional include paths from environment variables. - // FIXME: We should probably sink the logic for handling these from the - // frontend into the driver. It will allow deleting 4 otherwise unused flags. - // CPATH - included following the user specified includes (but prior to - // builtin and standard includes). - addDirectoryList(Args, CmdArgs, "-I", "CPATH"); - // C_INCLUDE_PATH - system includes enabled when compiling C. - addDirectoryList(Args, CmdArgs, "-c-isystem", "C_INCLUDE_PATH"); - // CPLUS_INCLUDE_PATH - system includes enabled when compiling C++. - addDirectoryList(Args, CmdArgs, "-cxx-isystem", "CPLUS_INCLUDE_PATH"); - // OBJC_INCLUDE_PATH - system includes enabled when compiling ObjC. - addDirectoryList(Args, CmdArgs, "-objc-isystem", "OBJC_INCLUDE_PATH"); - // OBJCPLUS_INCLUDE_PATH - system includes enabled when compiling ObjC++. - addDirectoryList(Args, CmdArgs, "-objcxx-isystem", "OBJCPLUS_INCLUDE_PATH"); - - // While adding the include arguments, we also attempt to retrieve the - // arguments of related offloading toolchains or arguments that are specific - // of an offloading programming model. - - // Add C++ include arguments, if needed. - if (types::isCXX(Inputs[0].getType())) - forAllAssociatedToolChains(C, JA, getToolChain(), - [&Args, &CmdArgs](const ToolChain &TC) { - TC.AddClangCXXStdlibIncludeArgs(Args, CmdArgs); - }); - - // Add system include arguments for all targets but IAMCU. - if (!IsIAMCU) - forAllAssociatedToolChains(C, JA, getToolChain(), - [&Args, &CmdArgs](const ToolChain &TC) { - TC.AddClangSystemIncludeArgs(Args, CmdArgs); - }); - else { - // For IAMCU add special include arguments. - getToolChain().AddIAMCUIncludeArgs(Args, CmdArgs); - } -} - -// FIXME: Move to target hook. -static bool isSignedCharDefault(const llvm::Triple &Triple) { - switch (Triple.getArch()) { - default: - return true; - - 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: - if (Triple.isOSDarwin() || Triple.isOSWindows()) - return true; - return false; - - case llvm::Triple::ppc: - case llvm::Triple::ppc64: - if (Triple.isOSDarwin()) - return true; - return false; - - case llvm::Triple::hexagon: - case llvm::Triple::ppc64le: - case llvm::Triple::systemz: - case llvm::Triple::xcore: - return false; - } -} - -static bool isNoCommonDefault(const llvm::Triple &Triple) { - switch (Triple.getArch()) { - default: - return false; - - case llvm::Triple::xcore: - case llvm::Triple::wasm32: - case llvm::Triple::wasm64: - return true; - } -} - -void Clang::AddARMTargetArgs(const llvm::Triple &Triple, const ArgList &Args, - ArgStringList &CmdArgs, bool KernelOrKext) const { - // Select the ABI to use. - // FIXME: Support -meabi. - // FIXME: Parts of this are duplicated in the backend, unify this somehow. - const char *ABIName = nullptr; - if (Arg *A = Args.getLastArg(options::OPT_mabi_EQ)) { - ABIName = A->getValue(); - } else if (Triple.isOSBinFormatMachO()) { - if (arm::useAAPCSForMachO(Triple)) { - ABIName = "aapcs"; - } else if (Triple.isWatchABI()) { - ABIName = "aapcs16"; - } else { - ABIName = "apcs-gnu"; - } - } else if (Triple.isOSWindows()) { - // FIXME: this is invalid for WindowsCE - ABIName = "aapcs"; - } else { - // Select the default based on the platform. - switch (Triple.getEnvironment()) { - case llvm::Triple::Android: - case llvm::Triple::GNUEABI: - case llvm::Triple::GNUEABIHF: - case llvm::Triple::MuslEABI: - case llvm::Triple::MuslEABIHF: - ABIName = "aapcs-linux"; - break; - case llvm::Triple::EABIHF: - case llvm::Triple::EABI: - ABIName = "aapcs"; - break; - default: - if (Triple.getOS() == llvm::Triple::NetBSD) - ABIName = "apcs-gnu"; - else if (Triple.getOS() == llvm::Triple::OpenBSD) - ABIName = "aapcs-linux"; - else - ABIName = "aapcs"; - break; - } - } - CmdArgs.push_back("-target-abi"); - CmdArgs.push_back(ABIName); - - // Determine floating point ABI from the options & target defaults. - arm::FloatABI ABI = arm::getARMFloatABI(getToolChain(), Args); - if (ABI == arm::FloatABI::Soft) { - // Floating point operations and argument passing are soft. - // FIXME: This changes CPP defines, we need -target-soft-float. - CmdArgs.push_back("-msoft-float"); - CmdArgs.push_back("-mfloat-abi"); - CmdArgs.push_back("soft"); - } else if (ABI == arm::FloatABI::SoftFP) { - // Floating point operations are hard, but argument passing is soft. - CmdArgs.push_back("-mfloat-abi"); - CmdArgs.push_back("soft"); - } else { - // Floating point operations and argument passing are hard. - assert(ABI == arm::FloatABI::Hard && "Invalid float abi!"); - CmdArgs.push_back("-mfloat-abi"); - CmdArgs.push_back("hard"); - } - - // Forward the -mglobal-merge option for explicit control over the pass. - if (Arg *A = Args.getLastArg(options::OPT_mglobal_merge, - options::OPT_mno_global_merge)) { - CmdArgs.push_back("-backend-option"); - if (A->getOption().matches(options::OPT_mno_global_merge)) - CmdArgs.push_back("-arm-global-merge=false"); - else - CmdArgs.push_back("-arm-global-merge=true"); - } - - if (!Args.hasFlag(options::OPT_mimplicit_float, - options::OPT_mno_implicit_float, true)) - CmdArgs.push_back("-no-implicit-float"); -} - -void Clang::AddAArch64TargetArgs(const ArgList &Args, - ArgStringList &CmdArgs) const { - const llvm::Triple &Triple = getToolChain().getEffectiveTriple(); - - if (!Args.hasFlag(options::OPT_mred_zone, options::OPT_mno_red_zone, true) || - Args.hasArg(options::OPT_mkernel) || - Args.hasArg(options::OPT_fapple_kext)) - CmdArgs.push_back("-disable-red-zone"); - - if (!Args.hasFlag(options::OPT_mimplicit_float, - options::OPT_mno_implicit_float, true)) - CmdArgs.push_back("-no-implicit-float"); - - const char *ABIName = nullptr; - if (Arg *A = Args.getLastArg(options::OPT_mabi_EQ)) - ABIName = A->getValue(); - else if (Triple.isOSDarwin()) - ABIName = "darwinpcs"; - else - ABIName = "aapcs"; - - CmdArgs.push_back("-target-abi"); - CmdArgs.push_back(ABIName); - - if (Arg *A = Args.getLastArg(options::OPT_mfix_cortex_a53_835769, - options::OPT_mno_fix_cortex_a53_835769)) { - CmdArgs.push_back("-backend-option"); - if (A->getOption().matches(options::OPT_mfix_cortex_a53_835769)) - CmdArgs.push_back("-aarch64-fix-cortex-a53-835769=1"); - else - CmdArgs.push_back("-aarch64-fix-cortex-a53-835769=0"); - } else if (Triple.isAndroid()) { - // Enabled A53 errata (835769) workaround by default on android - CmdArgs.push_back("-backend-option"); - CmdArgs.push_back("-aarch64-fix-cortex-a53-835769=1"); - } - - // Forward the -mglobal-merge option for explicit control over the pass. - if (Arg *A = Args.getLastArg(options::OPT_mglobal_merge, - options::OPT_mno_global_merge)) { - CmdArgs.push_back("-backend-option"); - if (A->getOption().matches(options::OPT_mno_global_merge)) - CmdArgs.push_back("-aarch64-enable-global-merge=false"); - else - CmdArgs.push_back("-aarch64-enable-global-merge=true"); - } -} - -void tools::AddTargetFeature(const ArgList &Args, - std::vector<StringRef> &Features, - OptSpecifier OnOpt, OptSpecifier OffOpt, - StringRef FeatureName) { - if (Arg *A = Args.getLastArg(OnOpt, OffOpt)) { - if (A->getOption().matches(OnOpt)) - Features.push_back(Args.MakeArgString("+" + FeatureName)); - else - Features.push_back(Args.MakeArgString("-" + FeatureName)); - } -} - -void Clang::AddMIPSTargetArgs(const ArgList &Args, - ArgStringList &CmdArgs) const { - const Driver &D = getToolChain().getDriver(); - StringRef CPUName; - StringRef ABIName; - const llvm::Triple &Triple = getToolChain().getTriple(); - mips::getMipsCPUAndABI(Args, Triple, CPUName, ABIName); - - CmdArgs.push_back("-target-abi"); - CmdArgs.push_back(ABIName.data()); - - mips::FloatABI ABI = mips::getMipsFloatABI(D, Args); - if (ABI == mips::FloatABI::Soft) { - // Floating point operations and argument passing are soft. - CmdArgs.push_back("-msoft-float"); - CmdArgs.push_back("-mfloat-abi"); - CmdArgs.push_back("soft"); - } else { - // Floating point operations and argument passing are hard. - assert(ABI == mips::FloatABI::Hard && "Invalid float abi!"); - CmdArgs.push_back("-mfloat-abi"); - CmdArgs.push_back("hard"); - } - - if (Arg *A = Args.getLastArg(options::OPT_mxgot, options::OPT_mno_xgot)) { - if (A->getOption().matches(options::OPT_mxgot)) { - CmdArgs.push_back("-mllvm"); - CmdArgs.push_back("-mxgot"); - } - } - - if (Arg *A = Args.getLastArg(options::OPT_mldc1_sdc1, - options::OPT_mno_ldc1_sdc1)) { - if (A->getOption().matches(options::OPT_mno_ldc1_sdc1)) { - CmdArgs.push_back("-mllvm"); - CmdArgs.push_back("-mno-ldc1-sdc1"); - } - } - - if (Arg *A = Args.getLastArg(options::OPT_mcheck_zero_division, - options::OPT_mno_check_zero_division)) { - if (A->getOption().matches(options::OPT_mno_check_zero_division)) { - CmdArgs.push_back("-mllvm"); - CmdArgs.push_back("-mno-check-zero-division"); - } - } - - if (Arg *A = Args.getLastArg(options::OPT_G)) { - StringRef v = A->getValue(); - CmdArgs.push_back("-mllvm"); - CmdArgs.push_back(Args.MakeArgString("-mips-ssection-threshold=" + v)); - A->claim(); - } - - if (Arg *A = Args.getLastArg(options::OPT_mcompact_branches_EQ)) { - StringRef Val = StringRef(A->getValue()); - if (mips::hasCompactBranches(CPUName)) { - if (Val == "never" || Val == "always" || Val == "optimal") { - CmdArgs.push_back("-mllvm"); - CmdArgs.push_back(Args.MakeArgString("-mips-compact-branches=" + Val)); - } else - D.Diag(diag::err_drv_unsupported_option_argument) - << A->getOption().getName() << Val; - } else - D.Diag(diag::warn_target_unsupported_compact_branches) << CPUName; - } -} - -void Clang::AddPPCTargetArgs(const ArgList &Args, - ArgStringList &CmdArgs) const { - // Select the ABI to use. - const char *ABIName = nullptr; - if (getToolChain().getTriple().isOSLinux()) - switch (getToolChain().getArch()) { - case llvm::Triple::ppc64: { - // When targeting a processor that supports QPX, or if QPX is - // specifically enabled, default to using the ABI that supports QPX (so - // long as it is not specifically disabled). - bool HasQPX = false; - if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) - HasQPX = A->getValue() == StringRef("a2q"); - HasQPX = Args.hasFlag(options::OPT_mqpx, options::OPT_mno_qpx, HasQPX); - if (HasQPX) { - ABIName = "elfv1-qpx"; - break; - } - - ABIName = "elfv1"; - break; - } - case llvm::Triple::ppc64le: - ABIName = "elfv2"; - break; - default: - break; - } - - if (Arg *A = Args.getLastArg(options::OPT_mabi_EQ)) - // The ppc64 linux abis are all "altivec" abis by default. Accept and ignore - // the option if given as we don't have backend support for any targets - // that don't use the altivec abi. - if (StringRef(A->getValue()) != "altivec") - ABIName = A->getValue(); - - ppc::FloatABI FloatABI = - ppc::getPPCFloatABI(getToolChain().getDriver(), Args); - - if (FloatABI == ppc::FloatABI::Soft) { - // Floating point operations and argument passing are soft. - CmdArgs.push_back("-msoft-float"); - CmdArgs.push_back("-mfloat-abi"); - CmdArgs.push_back("soft"); - } else { - // Floating point operations and argument passing are hard. - assert(FloatABI == ppc::FloatABI::Hard && "Invalid float abi!"); - CmdArgs.push_back("-mfloat-abi"); - CmdArgs.push_back("hard"); - } - - if (ABIName) { - CmdArgs.push_back("-target-abi"); - CmdArgs.push_back(ABIName); - } -} - -/// Get the (LLVM) name of the R600 gpu we are targeting. -static std::string getR600TargetGPU(const ArgList &Args) { - if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) { - const char *GPUName = A->getValue(); - return llvm::StringSwitch<const char *>(GPUName) - .Cases("rv630", "rv635", "r600") - .Cases("rv610", "rv620", "rs780", "rs880") - .Case("rv740", "rv770") - .Case("palm", "cedar") - .Cases("sumo", "sumo2", "sumo") - .Case("hemlock", "cypress") - .Case("aruba", "cayman") - .Default(GPUName); - } - return ""; -} - -static std::string getLanaiTargetCPU(const ArgList &Args) { - if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) { - return A->getValue(); - } - return ""; -} - -void Clang::AddSparcTargetArgs(const ArgList &Args, - ArgStringList &CmdArgs) const { - sparc::FloatABI FloatABI = - sparc::getSparcFloatABI(getToolChain().getDriver(), Args); - - if (FloatABI == sparc::FloatABI::Soft) { - // Floating point operations and argument passing are soft. - CmdArgs.push_back("-msoft-float"); - CmdArgs.push_back("-mfloat-abi"); - CmdArgs.push_back("soft"); - } else { - // Floating point operations and argument passing are hard. - assert(FloatABI == sparc::FloatABI::Hard && "Invalid float abi!"); - CmdArgs.push_back("-mfloat-abi"); - CmdArgs.push_back("hard"); - } -} - -void Clang::AddSystemZTargetArgs(const ArgList &Args, - ArgStringList &CmdArgs) const { - if (Args.hasFlag(options::OPT_mbackchain, options::OPT_mno_backchain, false)) - CmdArgs.push_back("-mbackchain"); -} - -/// Get the (LLVM) name of the WebAssembly cpu we are targeting. -static StringRef getWebAssemblyTargetCPU(const ArgList &Args) { - // If we have -mcpu=, use that. - if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) { - StringRef CPU = A->getValue(); - -#ifdef __wasm__ - // Handle "native" by examining the host. "native" isn't meaningful when - // cross compiling, so only support this when the host is also WebAssembly. - if (CPU == "native") - return llvm::sys::getHostCPUName(); -#endif - - return CPU; - } - - return "generic"; -} - -std::string tools::getCPUName(const ArgList &Args, const llvm::Triple &T, - bool FromAs) { - Arg *A; - - switch (T.getArch()) { - default: - return ""; - - case llvm::Triple::aarch64: - case llvm::Triple::aarch64_be: - return aarch64::getAArch64TargetCPU(Args, A); - - case llvm::Triple::arm: - case llvm::Triple::armeb: - case llvm::Triple::thumb: - case llvm::Triple::thumbeb: { - StringRef MArch, MCPU; - arm::getARMArchCPUFromArgs(Args, MArch, MCPU, FromAs); - return arm::getARMTargetCPU(MCPU, MArch, T); - } - case llvm::Triple::mips: - case llvm::Triple::mipsel: - case llvm::Triple::mips64: - case llvm::Triple::mips64el: { - StringRef CPUName; - StringRef ABIName; - mips::getMipsCPUAndABI(Args, T, CPUName, ABIName); - return CPUName; - } - - case llvm::Triple::nvptx: - case llvm::Triple::nvptx64: - if (const Arg *A = Args.getLastArg(options::OPT_march_EQ)) - return A->getValue(); - return ""; - - case llvm::Triple::ppc: - case llvm::Triple::ppc64: - case llvm::Triple::ppc64le: { - std::string TargetCPUName = ppc::getPPCTargetCPU(Args); - // LLVM may default to generating code for the native CPU, - // but, like gcc, we default to a more generic option for - // each architecture. (except on Darwin) - if (TargetCPUName.empty() && !T.isOSDarwin()) { - if (T.getArch() == llvm::Triple::ppc64) - TargetCPUName = "ppc64"; - else if (T.getArch() == llvm::Triple::ppc64le) - TargetCPUName = "ppc64le"; - else - TargetCPUName = "ppc"; - } - return TargetCPUName; - } - - case llvm::Triple::sparc: - case llvm::Triple::sparcel: - case llvm::Triple::sparcv9: - if (const Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) - return A->getValue(); - return ""; - - case llvm::Triple::x86: - case llvm::Triple::x86_64: - return x86::getX86TargetCPU(Args, T); - - case llvm::Triple::hexagon: - return "hexagon" + - toolchains::HexagonToolChain::GetTargetCPUVersion(Args).str(); - - case llvm::Triple::lanai: - return getLanaiTargetCPU(Args); - - case llvm::Triple::systemz: - return systemz::getSystemZTargetCPU(Args); - - case llvm::Triple::r600: - case llvm::Triple::amdgcn: - return getR600TargetGPU(Args); - - case llvm::Triple::wasm32: - case llvm::Triple::wasm64: - return getWebAssemblyTargetCPU(Args); - } -} - -static unsigned getLTOParallelism(const ArgList &Args, const Driver &D) { - unsigned Parallelism = 0; - Arg *LtoJobsArg = Args.getLastArg(options::OPT_flto_jobs_EQ); - if (LtoJobsArg && - StringRef(LtoJobsArg->getValue()).getAsInteger(10, Parallelism)) - D.Diag(diag::err_drv_invalid_int_value) << LtoJobsArg->getAsString(Args) - << LtoJobsArg->getValue(); - return Parallelism; -} - -// CloudABI and WebAssembly use -ffunction-sections and -fdata-sections by -// default. -static bool isUseSeparateSections(const llvm::Triple &Triple) { - return Triple.getOS() == llvm::Triple::CloudABI || - Triple.getArch() == llvm::Triple::wasm32 || - Triple.getArch() == llvm::Triple::wasm64; -} - -static void AddGoldPlugin(const ToolChain &ToolChain, const ArgList &Args, - ArgStringList &CmdArgs, bool IsThinLTO, - const Driver &D) { - // Tell the linker to load the plugin. This has to come before AddLinkerInputs - // 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"; - CmdArgs.push_back(Args.MakeArgString(Plugin)); - - // Try to pass driver level flags relevant to LTO code generation down to - // the plugin. - - // Handle flags for selecting CPU variants. - std::string CPU = getCPUName(Args, ToolChain.getTriple()); - if (!CPU.empty()) - CmdArgs.push_back(Args.MakeArgString(Twine("-plugin-opt=mcpu=") + CPU)); - - if (Arg *A = Args.getLastArg(options::OPT_O_Group)) { - StringRef OOpt; - if (A->getOption().matches(options::OPT_O4) || - A->getOption().matches(options::OPT_Ofast)) - OOpt = "3"; - else if (A->getOption().matches(options::OPT_O)) - OOpt = A->getValue(); - else if (A->getOption().matches(options::OPT_O0)) - OOpt = "0"; - if (!OOpt.empty()) - CmdArgs.push_back(Args.MakeArgString(Twine("-plugin-opt=O") + OOpt)); - } - - if (IsThinLTO) - CmdArgs.push_back("-plugin-opt=thinlto"); - - if (unsigned Parallelism = getLTOParallelism(Args, D)) - CmdArgs.push_back(Args.MakeArgString(Twine("-plugin-opt=jobs=") + - llvm::to_string(Parallelism))); - - // If an explicit debugger tuning argument appeared, pass it along. - if (Arg *A = Args.getLastArg(options::OPT_gTune_Group, - options::OPT_ggdbN_Group)) { - if (A->getOption().matches(options::OPT_glldb)) - CmdArgs.push_back("-plugin-opt=-debugger-tune=lldb"); - else if (A->getOption().matches(options::OPT_gsce)) - CmdArgs.push_back("-plugin-opt=-debugger-tune=sce"); - else - CmdArgs.push_back("-plugin-opt=-debugger-tune=gdb"); - } - - bool UseSeparateSections = - isUseSeparateSections(ToolChain.getEffectiveTriple()); - - if (Args.hasFlag(options::OPT_ffunction_sections, - options::OPT_fno_function_sections, UseSeparateSections)) { - CmdArgs.push_back("-plugin-opt=-function-sections"); - } - - if (Args.hasFlag(options::OPT_fdata_sections, options::OPT_fno_data_sections, - UseSeparateSections)) { - CmdArgs.push_back("-plugin-opt=-data-sections"); - } - - if (Arg *A = Args.getLastArg(options::OPT_fprofile_sample_use_EQ)) { - StringRef FName = A->getValue(); - if (!llvm::sys::fs::exists(FName)) - D.Diag(diag::err_drv_no_such_file) << FName; - else - CmdArgs.push_back( - Args.MakeArgString(Twine("-plugin-opt=sample-profile=") + FName)); - } -} - -/// This is a helper function for validating the optional refinement step -/// parameter in reciprocal argument strings. Return false if there is an error -/// parsing the refinement step. Otherwise, return true and set the Position -/// of the refinement step in the input string. -static bool getRefinementStep(StringRef In, const Driver &D, - const Arg &A, size_t &Position) { - const char RefinementStepToken = ':'; - Position = In.find(RefinementStepToken); - if (Position != StringRef::npos) { - StringRef Option = A.getOption().getName(); - StringRef RefStep = In.substr(Position + 1); - // Allow exactly one numeric character for the additional refinement - // step parameter. This is reasonable for all currently-supported - // operations and architectures because we would expect that a larger value - // of refinement steps would cause the estimate "optimization" to - // under-perform the native operation. Also, if the estimate does not - // converge quickly, it probably will not ever converge, so further - // refinement steps will not produce a better answer. - if (RefStep.size() != 1) { - D.Diag(diag::err_drv_invalid_value) << Option << RefStep; - return false; - } - char RefStepChar = RefStep[0]; - if (RefStepChar < '0' || RefStepChar > '9') { - D.Diag(diag::err_drv_invalid_value) << Option << RefStep; - return false; - } - } - return true; -} - -/// The -mrecip flag requires processing of many optional parameters. -static void ParseMRecip(const Driver &D, const ArgList &Args, - ArgStringList &OutStrings) { - StringRef DisabledPrefixIn = "!"; - StringRef DisabledPrefixOut = "!"; - StringRef EnabledPrefixOut = ""; - StringRef Out = "-mrecip="; - - Arg *A = Args.getLastArg(options::OPT_mrecip, options::OPT_mrecip_EQ); - if (!A) - return; - - unsigned NumOptions = A->getNumValues(); - if (NumOptions == 0) { - // No option is the same as "all". - OutStrings.push_back(Args.MakeArgString(Out + "all")); - return; - } - - // Pass through "all", "none", or "default" with an optional refinement step. - if (NumOptions == 1) { - StringRef Val = A->getValue(0); - size_t RefStepLoc; - if (!getRefinementStep(Val, D, *A, RefStepLoc)) - return; - StringRef ValBase = Val.slice(0, RefStepLoc); - if (ValBase == "all" || ValBase == "none" || ValBase == "default") { - OutStrings.push_back(Args.MakeArgString(Out + Val)); - return; - } - } - - // Each reciprocal type may be enabled or disabled individually. - // Check each input value for validity, concatenate them all back together, - // and pass through. - - llvm::StringMap<bool> OptionStrings; - OptionStrings.insert(std::make_pair("divd", false)); - OptionStrings.insert(std::make_pair("divf", false)); - OptionStrings.insert(std::make_pair("vec-divd", false)); - OptionStrings.insert(std::make_pair("vec-divf", false)); - OptionStrings.insert(std::make_pair("sqrtd", false)); - OptionStrings.insert(std::make_pair("sqrtf", false)); - OptionStrings.insert(std::make_pair("vec-sqrtd", false)); - OptionStrings.insert(std::make_pair("vec-sqrtf", false)); - - for (unsigned i = 0; i != NumOptions; ++i) { - StringRef Val = A->getValue(i); - - bool IsDisabled = Val.startswith(DisabledPrefixIn); - // Ignore the disablement token for string matching. - if (IsDisabled) - Val = Val.substr(1); - - size_t RefStep; - if (!getRefinementStep(Val, D, *A, RefStep)) - return; - - StringRef ValBase = Val.slice(0, RefStep); - llvm::StringMap<bool>::iterator OptionIter = OptionStrings.find(ValBase); - if (OptionIter == OptionStrings.end()) { - // Try again specifying float suffix. - OptionIter = OptionStrings.find(ValBase.str() + 'f'); - if (OptionIter == OptionStrings.end()) { - // The input name did not match any known option string. - D.Diag(diag::err_drv_unknown_argument) << Val; - return; - } - // The option was specified without a float or double suffix. - // Make sure that the double entry was not already specified. - // The float entry will be checked below. - if (OptionStrings[ValBase.str() + 'd']) { - D.Diag(diag::err_drv_invalid_value) << A->getOption().getName() << Val; - return; - } - } - - if (OptionIter->second == true) { - // Duplicate option specified. - D.Diag(diag::err_drv_invalid_value) << A->getOption().getName() << Val; - return; - } - - // Mark the matched option as found. Do not allow duplicate specifiers. - OptionIter->second = true; - - // If the precision was not specified, also mark the double entry as found. - if (ValBase.back() != 'f' && ValBase.back() != 'd') - OptionStrings[ValBase.str() + 'd'] = true; - - // Build the output string. - StringRef Prefix = IsDisabled ? DisabledPrefixOut : EnabledPrefixOut; - Out = Args.MakeArgString(Out + Prefix + Val); - if (i != NumOptions - 1) - Out = Args.MakeArgString(Out + ","); - } - - OutStrings.push_back(Args.MakeArgString(Out)); -} - -void Clang::AddX86TargetArgs(const ArgList &Args, - ArgStringList &CmdArgs) const { - if (!Args.hasFlag(options::OPT_mred_zone, options::OPT_mno_red_zone, true) || - Args.hasArg(options::OPT_mkernel) || - Args.hasArg(options::OPT_fapple_kext)) - CmdArgs.push_back("-disable-red-zone"); - - // Default to avoid implicit floating-point for kernel/kext code, but allow - // that to be overridden with -mno-soft-float. - bool NoImplicitFloat = (Args.hasArg(options::OPT_mkernel) || - Args.hasArg(options::OPT_fapple_kext)); - if (Arg *A = Args.getLastArg( - options::OPT_msoft_float, options::OPT_mno_soft_float, - options::OPT_mimplicit_float, options::OPT_mno_implicit_float)) { - const Option &O = A->getOption(); - NoImplicitFloat = (O.matches(options::OPT_mno_implicit_float) || - O.matches(options::OPT_msoft_float)); - } - if (NoImplicitFloat) - CmdArgs.push_back("-no-implicit-float"); - - if (Arg *A = Args.getLastArg(options::OPT_masm_EQ)) { - StringRef Value = A->getValue(); - if (Value == "intel" || Value == "att") { - CmdArgs.push_back("-mllvm"); - CmdArgs.push_back(Args.MakeArgString("-x86-asm-syntax=" + Value)); - } else { - getToolChain().getDriver().Diag(diag::err_drv_unsupported_option_argument) - << A->getOption().getName() << Value; - } - } - - // Set flags to support MCU ABI. - if (Args.hasFlag(options::OPT_miamcu, options::OPT_mno_iamcu, false)) { - CmdArgs.push_back("-mfloat-abi"); - CmdArgs.push_back("soft"); - CmdArgs.push_back("-mstack-alignment=4"); - } -} - -void Clang::AddHexagonTargetArgs(const ArgList &Args, - ArgStringList &CmdArgs) const { - CmdArgs.push_back("-mqdsp6-compat"); - CmdArgs.push_back("-Wreturn-type"); - - if (auto G = toolchains::HexagonToolChain::getSmallDataThreshold(Args)) { - std::string N = llvm::utostr(G.getValue()); - std::string Opt = std::string("-hexagon-small-data-threshold=") + N; - CmdArgs.push_back("-mllvm"); - CmdArgs.push_back(Args.MakeArgString(Opt)); - } - - if (!Args.hasArg(options::OPT_fno_short_enums)) - CmdArgs.push_back("-fshort-enums"); - if (Args.getLastArg(options::OPT_mieee_rnd_near)) { - CmdArgs.push_back("-mllvm"); - CmdArgs.push_back("-enable-hexagon-ieee-rnd-near"); - } - CmdArgs.push_back("-mllvm"); - CmdArgs.push_back("-machine-sink-split=0"); -} - -void Clang::AddLanaiTargetArgs(const ArgList &Args, - ArgStringList &CmdArgs) const { - if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) { - StringRef CPUName = A->getValue(); - - CmdArgs.push_back("-target-cpu"); - CmdArgs.push_back(Args.MakeArgString(CPUName)); - } - if (Arg *A = Args.getLastArg(options::OPT_mregparm_EQ)) { - StringRef Value = A->getValue(); - // Only support mregparm=4 to support old usage. Report error for all other - // cases. - int Mregparm; - if (Value.getAsInteger(10, Mregparm)) { - if (Mregparm != 4) { - getToolChain().getDriver().Diag( - diag::err_drv_unsupported_option_argument) - << A->getOption().getName() << Value; - } - } - } -} - -void Clang::AddWebAssemblyTargetArgs(const ArgList &Args, - ArgStringList &CmdArgs) const { - // Default to "hidden" visibility. - if (!Args.hasArg(options::OPT_fvisibility_EQ, - options::OPT_fvisibility_ms_compat)) { - CmdArgs.push_back("-fvisibility"); - CmdArgs.push_back("hidden"); - } -} - -static void getHexagonTargetFeatures(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"); -} - -static void getWebAssemblyTargetFeatures(const ArgList &Args, - std::vector<StringRef> &Features) { - 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) { - const Driver &D = TC.getDriver(); - std::vector<StringRef> Features; - switch (Triple.getArch()) { - default: - break; - case llvm::Triple::mips: - case llvm::Triple::mipsel: - case llvm::Triple::mips64: - case llvm::Triple::mips64el: - mips::getMIPSTargetFeatures(D, Triple, Args, Features); - break; - - case llvm::Triple::arm: - case llvm::Triple::armeb: - case llvm::Triple::thumb: - case llvm::Triple::thumbeb: - arm::getARMTargetFeatures(TC, Triple, Args, CmdArgs, Features, ForAS); - break; - - case llvm::Triple::ppc: - case llvm::Triple::ppc64: - case llvm::Triple::ppc64le: - ppc::getPPCTargetFeatures(D, Triple, Args, Features); - break; - case llvm::Triple::systemz: - systemz::getSystemZTargetFeatures(Args, Features); - break; - case llvm::Triple::aarch64: - case llvm::Triple::aarch64_be: - aarch64::getAArch64TargetFeatures(D, Args, Features); - break; - case llvm::Triple::x86: - case llvm::Triple::x86_64: - x86::getX86TargetFeatures(D, Triple, Args, Features); - break; - case llvm::Triple::hexagon: - getHexagonTargetFeatures(Args, Features); - break; - case llvm::Triple::wasm32: - case llvm::Triple::wasm64: - getWebAssemblyTargetFeatures(Args, Features); - break; - case llvm::Triple::sparc: - case llvm::Triple::sparcel: - case llvm::Triple::sparcv9: - sparc::getSparcTargetFeatures(D, Args, Features); - break; - case llvm::Triple::r600: - case llvm::Triple::amdgcn: - getAMDGPUTargetFeatures(D, Args, Features); - break; - } - - // Find the last of each feature. - llvm::StringMap<unsigned> LastOpt; - for (unsigned I = 0, N = Features.size(); I < N; ++I) { - StringRef Name = Features[I]; - assert(Name[0] == '-' || Name[0] == '+'); - LastOpt[Name.drop_front(1)] = I; - } - - for (unsigned I = 0, N = Features.size(); I < N; ++I) { - // If this feature was overridden, ignore it. - StringRef Name = Features[I]; - llvm::StringMap<unsigned>::iterator LastI = LastOpt.find(Name.drop_front(1)); - assert(LastI != LastOpt.end()); - unsigned Last = LastI->second; - if (Last != I) - continue; - - CmdArgs.push_back("-target-feature"); - CmdArgs.push_back(Name.data()); - } -} - -static bool -shouldUseExceptionTablesForObjCExceptions(const ObjCRuntime &runtime, - const llvm::Triple &Triple) { - // We use the zero-cost exception tables for Objective-C if the non-fragile - // ABI is enabled or when compiling for x86_64 and ARM on Snow Leopard and - // later. - if (runtime.isNonFragile()) - return true; - - if (!Triple.isMacOSX()) - return false; - - return (!Triple.isMacOSXVersionLT(10, 5) && - (Triple.getArch() == llvm::Triple::x86_64 || - Triple.getArch() == llvm::Triple::arm)); -} - -/// Adds exception related arguments to the driver command arguments. There's a -/// master flag, -fexceptions and also language specific flags to enable/disable -/// C++ and Objective-C exceptions. This makes it possible to for example -/// disable C++ exceptions but enable Objective-C exceptions. -static void addExceptionArgs(const ArgList &Args, types::ID InputType, - const ToolChain &TC, bool KernelOrKext, - const ObjCRuntime &objcRuntime, - ArgStringList &CmdArgs) { - const Driver &D = TC.getDriver(); - const llvm::Triple &Triple = TC.getTriple(); - - if (KernelOrKext) { - // -mkernel and -fapple-kext imply no exceptions, so claim exception related - // arguments now to avoid warnings about unused arguments. - Args.ClaimAllArgs(options::OPT_fexceptions); - Args.ClaimAllArgs(options::OPT_fno_exceptions); - Args.ClaimAllArgs(options::OPT_fobjc_exceptions); - Args.ClaimAllArgs(options::OPT_fno_objc_exceptions); - Args.ClaimAllArgs(options::OPT_fcxx_exceptions); - Args.ClaimAllArgs(options::OPT_fno_cxx_exceptions); - return; - } - - // See if the user explicitly enabled exceptions. - bool EH = Args.hasFlag(options::OPT_fexceptions, options::OPT_fno_exceptions, - false); - - // Obj-C exceptions are enabled by default, regardless of -fexceptions. This - // is not necessarily sensible, but follows GCC. - if (types::isObjC(InputType) && - Args.hasFlag(options::OPT_fobjc_exceptions, - options::OPT_fno_objc_exceptions, true)) { - CmdArgs.push_back("-fobjc-exceptions"); - - EH |= shouldUseExceptionTablesForObjCExceptions(objcRuntime, Triple); - } - - if (types::isCXX(InputType)) { - // Disable C++ EH by default on XCore and PS4. - bool CXXExceptionsEnabled = - Triple.getArch() != llvm::Triple::xcore && !Triple.isPS4CPU(); - Arg *ExceptionArg = Args.getLastArg( - options::OPT_fcxx_exceptions, options::OPT_fno_cxx_exceptions, - options::OPT_fexceptions, options::OPT_fno_exceptions); - if (ExceptionArg) - CXXExceptionsEnabled = - ExceptionArg->getOption().matches(options::OPT_fcxx_exceptions) || - ExceptionArg->getOption().matches(options::OPT_fexceptions); - - if (CXXExceptionsEnabled) { - if (Triple.isPS4CPU()) { - ToolChain::RTTIMode RTTIMode = TC.getRTTIMode(); - assert(ExceptionArg && - "On the PS4 exceptions should only be enabled if passing " - "an argument"); - if (RTTIMode == ToolChain::RM_DisabledExplicitly) { - const Arg *RTTIArg = TC.getRTTIArg(); - assert(RTTIArg && "RTTI disabled explicitly but no RTTIArg!"); - D.Diag(diag::err_drv_argument_not_allowed_with) - << RTTIArg->getAsString(Args) << ExceptionArg->getAsString(Args); - } else if (RTTIMode == ToolChain::RM_EnabledImplicitly) - D.Diag(diag::warn_drv_enabling_rtti_with_exceptions); - } else - assert(TC.getRTTIMode() != ToolChain::RM_DisabledImplicitly); - - CmdArgs.push_back("-fcxx-exceptions"); - - EH = true; - } - } - - if (EH) - CmdArgs.push_back("-fexceptions"); -} - -static bool ShouldDisableAutolink(const ArgList &Args, const ToolChain &TC) { - bool Default = true; - if (TC.getTriple().isOSDarwin()) { - // The native darwin assembler doesn't support the linker_option directives, - // so we disable them if we think the .s file will be passed to it. - Default = TC.useIntegratedAs(); - } - return !Args.hasFlag(options::OPT_fautolink, options::OPT_fno_autolink, - Default); -} - -static bool ShouldDisableDwarfDirectory(const ArgList &Args, - const ToolChain &TC) { - bool UseDwarfDirectory = - Args.hasFlag(options::OPT_fdwarf_directory_asm, - options::OPT_fno_dwarf_directory_asm, TC.useIntegratedAs()); - return !UseDwarfDirectory; -} - -/// \brief Check whether the given input tree contains any compilation actions. -static bool ContainsCompileAction(const Action *A) { - if (isa<CompileJobAction>(A) || isa<BackendJobAction>(A)) - return true; - - for (const auto &AI : A->inputs()) - if (ContainsCompileAction(AI)) - return true; - - return false; -} - -/// \brief Check if -relax-all should be passed to the internal assembler. -/// This is done by default when compiling non-assembler source with -O0. -static bool UseRelaxAll(Compilation &C, const ArgList &Args) { - bool RelaxDefault = true; - - if (Arg *A = Args.getLastArg(options::OPT_O_Group)) - RelaxDefault = A->getOption().matches(options::OPT_O0); - - if (RelaxDefault) { - RelaxDefault = false; - for (const auto &Act : C.getActions()) { - if (ContainsCompileAction(Act)) { - RelaxDefault = true; - break; - } - } - } - - return Args.hasFlag(options::OPT_mrelax_all, options::OPT_mno_relax_all, - RelaxDefault); -} - -// Convert an arg of the form "-gN" or "-ggdbN" or one of their aliases -// to the corresponding DebugInfoKind. -static codegenoptions::DebugInfoKind DebugLevelToInfoKind(const Arg &A) { - assert(A.getOption().matches(options::OPT_gN_Group) && - "Not a -g option that specifies a debug-info level"); - if (A.getOption().matches(options::OPT_g0) || - A.getOption().matches(options::OPT_ggdb0)) - return codegenoptions::NoDebugInfo; - if (A.getOption().matches(options::OPT_gline_tables_only) || - A.getOption().matches(options::OPT_ggdb1)) - return codegenoptions::DebugLineTablesOnly; - return codegenoptions::LimitedDebugInfo; -} - -// Extract the integer N from a string spelled "-dwarf-N", returning 0 -// on mismatch. The StringRef input (rather than an Arg) allows -// for use by the "-Xassembler" option parser. -static unsigned DwarfVersionNum(StringRef ArgValue) { - return llvm::StringSwitch<unsigned>(ArgValue) - .Case("-gdwarf-2", 2) - .Case("-gdwarf-3", 3) - .Case("-gdwarf-4", 4) - .Case("-gdwarf-5", 5) - .Default(0); -} - -static void RenderDebugEnablingArgs(const ArgList &Args, ArgStringList &CmdArgs, - codegenoptions::DebugInfoKind DebugInfoKind, - unsigned DwarfVersion, - llvm::DebuggerKind DebuggerTuning) { - switch (DebugInfoKind) { - case codegenoptions::DebugLineTablesOnly: - CmdArgs.push_back("-debug-info-kind=line-tables-only"); - break; - case codegenoptions::LimitedDebugInfo: - CmdArgs.push_back("-debug-info-kind=limited"); - break; - case codegenoptions::FullDebugInfo: - CmdArgs.push_back("-debug-info-kind=standalone"); - break; - default: - break; - } - if (DwarfVersion > 0) - CmdArgs.push_back( - Args.MakeArgString("-dwarf-version=" + Twine(DwarfVersion))); - switch (DebuggerTuning) { - case llvm::DebuggerKind::GDB: - CmdArgs.push_back("-debugger-tuning=gdb"); - break; - case llvm::DebuggerKind::LLDB: - CmdArgs.push_back("-debugger-tuning=lldb"); - break; - case llvm::DebuggerKind::SCE: - CmdArgs.push_back("-debugger-tuning=sce"); - break; - default: - break; - } -} - -static void CollectArgsForIntegratedAssembler(Compilation &C, - const ArgList &Args, - ArgStringList &CmdArgs, - const Driver &D) { - if (UseRelaxAll(C, Args)) - CmdArgs.push_back("-mrelax-all"); - - // Only default to -mincremental-linker-compatible if we think we are - // targeting the MSVC linker. - bool DefaultIncrementalLinkerCompatible = - C.getDefaultToolChain().getTriple().isWindowsMSVCEnvironment(); - if (Args.hasFlag(options::OPT_mincremental_linker_compatible, - options::OPT_mno_incremental_linker_compatible, - DefaultIncrementalLinkerCompatible)) - CmdArgs.push_back("-mincremental-linker-compatible"); - - switch (C.getDefaultToolChain().getArch()) { - case llvm::Triple::arm: - case llvm::Triple::armeb: - case llvm::Triple::thumb: - case llvm::Triple::thumbeb: - if (Arg *A = Args.getLastArg(options::OPT_mimplicit_it_EQ)) { - StringRef Value = A->getValue(); - if (Value == "always" || Value == "never" || Value == "arm" || - Value == "thumb") { - CmdArgs.push_back("-mllvm"); - CmdArgs.push_back(Args.MakeArgString("-arm-implicit-it=" + Value)); - } else { - D.Diag(diag::err_drv_unsupported_option_argument) - << A->getOption().getName() << Value; - } - } - break; - default: - break; - } - - // When passing -I arguments to the assembler we sometimes need to - // unconditionally take the next argument. For example, when parsing - // '-Wa,-I -Wa,foo' we need to accept the -Wa,foo arg after seeing the - // -Wa,-I arg and when parsing '-Wa,-I,foo' we need to accept the 'foo' - // arg after parsing the '-I' arg. - bool TakeNextArg = false; - - // When using an integrated assembler, translate -Wa, and -Xassembler - // options. - bool CompressDebugSections = false; - - bool UseRelaxRelocations = ENABLE_X86_RELAX_RELOCATIONS; - const char *MipsTargetFeature = nullptr; - for (const Arg *A : - Args.filtered(options::OPT_Wa_COMMA, options::OPT_Xassembler)) { - A->claim(); - - for (StringRef Value : A->getValues()) { - if (TakeNextArg) { - CmdArgs.push_back(Value.data()); - TakeNextArg = false; - continue; - } - - if (C.getDefaultToolChain().getTriple().isOSBinFormatCOFF() && - Value == "-mbig-obj") - continue; // LLVM handles bigobj automatically - - switch (C.getDefaultToolChain().getArch()) { - default: - break; - case llvm::Triple::mips: - case llvm::Triple::mipsel: - case llvm::Triple::mips64: - case llvm::Triple::mips64el: - if (Value == "--trap") { - CmdArgs.push_back("-target-feature"); - CmdArgs.push_back("+use-tcc-in-div"); - continue; - } - if (Value == "--break") { - CmdArgs.push_back("-target-feature"); - CmdArgs.push_back("-use-tcc-in-div"); - continue; - } - if (Value.startswith("-msoft-float")) { - CmdArgs.push_back("-target-feature"); - CmdArgs.push_back("+soft-float"); - continue; - } - if (Value.startswith("-mhard-float")) { - CmdArgs.push_back("-target-feature"); - CmdArgs.push_back("-soft-float"); - continue; - } - - MipsTargetFeature = llvm::StringSwitch<const char *>(Value) - .Case("-mips1", "+mips1") - .Case("-mips2", "+mips2") - .Case("-mips3", "+mips3") - .Case("-mips4", "+mips4") - .Case("-mips5", "+mips5") - .Case("-mips32", "+mips32") - .Case("-mips32r2", "+mips32r2") - .Case("-mips32r3", "+mips32r3") - .Case("-mips32r5", "+mips32r5") - .Case("-mips32r6", "+mips32r6") - .Case("-mips64", "+mips64") - .Case("-mips64r2", "+mips64r2") - .Case("-mips64r3", "+mips64r3") - .Case("-mips64r5", "+mips64r5") - .Case("-mips64r6", "+mips64r6") - .Default(nullptr); - if (MipsTargetFeature) - continue; - } - - if (Value == "-force_cpusubtype_ALL") { - // Do nothing, this is the default and we don't support anything else. - } else if (Value == "-L") { - CmdArgs.push_back("-msave-temp-labels"); - } else if (Value == "--fatal-warnings") { - CmdArgs.push_back("-massembler-fatal-warnings"); - } else if (Value == "--noexecstack") { - CmdArgs.push_back("-mnoexecstack"); - } else if (Value == "-compress-debug-sections" || - Value == "--compress-debug-sections") { - CompressDebugSections = true; - } else if (Value == "-nocompress-debug-sections" || - Value == "--nocompress-debug-sections") { - CompressDebugSections = false; - } else if (Value == "-mrelax-relocations=yes" || - Value == "--mrelax-relocations=yes") { - UseRelaxRelocations = true; - } else if (Value == "-mrelax-relocations=no" || - Value == "--mrelax-relocations=no") { - UseRelaxRelocations = false; - } else if (Value.startswith("-I")) { - CmdArgs.push_back(Value.data()); - // We need to consume the next argument if the current arg is a plain - // -I. The next arg will be the include directory. - if (Value == "-I") - TakeNextArg = true; - } else if (Value.startswith("-gdwarf-")) { - // "-gdwarf-N" options are not cc1as options. - unsigned DwarfVersion = DwarfVersionNum(Value); - if (DwarfVersion == 0) { // Send it onward, and let cc1as complain. - CmdArgs.push_back(Value.data()); - } else { - RenderDebugEnablingArgs(Args, CmdArgs, - codegenoptions::LimitedDebugInfo, - DwarfVersion, llvm::DebuggerKind::Default); - } - } else if (Value.startswith("-mcpu") || Value.startswith("-mfpu") || - Value.startswith("-mhwdiv") || Value.startswith("-march")) { - // Do nothing, we'll validate it later. - } else if (Value == "-defsym") { - if (A->getNumValues() != 2) { - D.Diag(diag::err_drv_defsym_invalid_format) << Value; - break; - } - const char *S = A->getValue(1); - auto Pair = StringRef(S).split('='); - auto Sym = Pair.first; - auto SVal = Pair.second; - - if (Sym.empty() || SVal.empty()) { - D.Diag(diag::err_drv_defsym_invalid_format) << S; - break; - } - int64_t IVal; - if (SVal.getAsInteger(0, IVal)) { - D.Diag(diag::err_drv_defsym_invalid_symval) << SVal; - break; - } - CmdArgs.push_back(Value.data()); - TakeNextArg = true; - } else { - D.Diag(diag::err_drv_unsupported_option_argument) - << A->getOption().getName() << Value; - } - } - } - if (CompressDebugSections) { - if (llvm::zlib::isAvailable()) - CmdArgs.push_back("-compress-debug-sections"); - else - D.Diag(diag::warn_debug_compression_unavailable); - } - if (UseRelaxRelocations) - CmdArgs.push_back("--mrelax-relocations"); - if (MipsTargetFeature != nullptr) { - CmdArgs.push_back("-target-feature"); - CmdArgs.push_back(MipsTargetFeature); - } -} - -static void addArchSpecificRPath(const ToolChain &TC, const ArgList &Args, - ArgStringList &CmdArgs) { - // In the cross-compilation case, arch-specific library path is likely - // unavailable at runtime. - if (TC.isCrossCompiling()) return; - - std::string CandidateRPath = TC.getArchSpecificLibPath(); - if (TC.getVFS().exists(CandidateRPath)) { - CmdArgs.push_back("-rpath"); - CmdArgs.push_back(Args.MakeArgString(CandidateRPath.c_str())); - } -} - -static void addOpenMPRuntime(ArgStringList &CmdArgs, const ToolChain &TC, - const ArgList &Args) { - if (!Args.hasFlag(options::OPT_fopenmp, options::OPT_fopenmp_EQ, - options::OPT_fno_openmp, false)) - return; - - switch (TC.getDriver().getOpenMPRuntime(Args)) { - case Driver::OMPRT_OMP: - CmdArgs.push_back("-lomp"); - break; - case Driver::OMPRT_GOMP: - CmdArgs.push_back("-lgomp"); - break; - case Driver::OMPRT_IOMP5: - CmdArgs.push_back("-liomp5"); - break; - case Driver::OMPRT_Unknown: - // Already diagnosed. - break; - } - - addArchSpecificRPath(TC, Args, CmdArgs); -} - -static void addSanitizerRuntime(const ToolChain &TC, const ArgList &Args, - ArgStringList &CmdArgs, StringRef Sanitizer, - bool IsShared, bool IsWhole) { - // Wrap any static runtimes that must be forced into executable in - // whole-archive. - if (IsWhole) CmdArgs.push_back("-whole-archive"); - CmdArgs.push_back(TC.getCompilerRTArgString(Args, Sanitizer, IsShared)); - if (IsWhole) CmdArgs.push_back("-no-whole-archive"); - - if (IsShared) { - addArchSpecificRPath(TC, Args, CmdArgs); - } -} - -// Tries to use a file with the list of dynamic symbols that need to be exported -// from the runtime library. Returns true if the file was found. -static bool addSanitizerDynamicList(const ToolChain &TC, const ArgList &Args, - ArgStringList &CmdArgs, - StringRef Sanitizer) { - SmallString<128> SanRT(TC.getCompilerRT(Args, Sanitizer)); - if (llvm::sys::fs::exists(SanRT + ".syms")) { - CmdArgs.push_back(Args.MakeArgString("--dynamic-list=" + SanRT + ".syms")); - return true; - } - return false; -} - -static void linkSanitizerRuntimeDeps(const ToolChain &TC, - ArgStringList &CmdArgs) { - // Force linking against the system libraries sanitizers depends on - // (see PR15823 why this is necessary). - CmdArgs.push_back("--no-as-needed"); - // There's no libpthread or librt on RTEMS. - if (TC.getTriple().getOS() != llvm::Triple::RTEMS) { - CmdArgs.push_back("-lpthread"); - CmdArgs.push_back("-lrt"); - } - CmdArgs.push_back("-lm"); - // There's no libdl on FreeBSD or RTEMS. - if (TC.getTriple().getOS() != llvm::Triple::FreeBSD && - TC.getTriple().getOS() != llvm::Triple::RTEMS) - CmdArgs.push_back("-ldl"); -} - -static void -collectSanitizerRuntimes(const ToolChain &TC, const ArgList &Args, - SmallVectorImpl<StringRef> &SharedRuntimes, - SmallVectorImpl<StringRef> &StaticRuntimes, - SmallVectorImpl<StringRef> &NonWholeStaticRuntimes, - SmallVectorImpl<StringRef> &HelperStaticRuntimes, - SmallVectorImpl<StringRef> &RequiredSymbols) { - const SanitizerArgs &SanArgs = TC.getSanitizerArgs(); - // Collect shared runtimes. - if (SanArgs.needsAsanRt() && SanArgs.needsSharedAsanRt()) { - SharedRuntimes.push_back("asan"); - } - // 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. - 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"); - } - } - if (SanArgs.needsDfsanRt()) - StaticRuntimes.push_back("dfsan"); - if (SanArgs.needsLsanRt()) - StaticRuntimes.push_back("lsan"); - if (SanArgs.needsMsanRt()) { - StaticRuntimes.push_back("msan"); - if (SanArgs.linkCXXRuntimes()) - StaticRuntimes.push_back("msan_cxx"); - } - if (SanArgs.needsTsanRt()) { - StaticRuntimes.push_back("tsan"); - if (SanArgs.linkCXXRuntimes()) - StaticRuntimes.push_back("tsan_cxx"); - } - if (SanArgs.needsUbsanRt()) { - StaticRuntimes.push_back("ubsan_standalone"); - if (SanArgs.linkCXXRuntimes()) - StaticRuntimes.push_back("ubsan_standalone_cxx"); - } - if (SanArgs.needsSafeStackRt()) { - NonWholeStaticRuntimes.push_back("safestack"); - RequiredSymbols.push_back("__safestack_init"); - } - if (SanArgs.needsCfiRt()) - StaticRuntimes.push_back("cfi"); - if (SanArgs.needsCfiDiagRt()) { - StaticRuntimes.push_back("cfi_diag"); - if (SanArgs.linkCXXRuntimes()) - StaticRuntimes.push_back("ubsan_standalone_cxx"); - } - if (SanArgs.needsStatsRt()) { - NonWholeStaticRuntimes.push_back("stats"); - RequiredSymbols.push_back("__sanitizer_stats_register"); - } - if (SanArgs.needsEsanRt()) - StaticRuntimes.push_back("esan"); -} - -// 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. -static bool addSanitizerRuntimes(const ToolChain &TC, const ArgList &Args, - ArgStringList &CmdArgs) { - SmallVector<StringRef, 4> SharedRuntimes, StaticRuntimes, - NonWholeStaticRuntimes, HelperStaticRuntimes, RequiredSymbols; - collectSanitizerRuntimes(TC, Args, SharedRuntimes, StaticRuntimes, - NonWholeStaticRuntimes, HelperStaticRuntimes, - RequiredSymbols); - for (auto RT : SharedRuntimes) - addSanitizerRuntime(TC, Args, CmdArgs, RT, true, false); - for (auto RT : HelperStaticRuntimes) - addSanitizerRuntime(TC, Args, CmdArgs, RT, false, true); - bool AddExportDynamic = false; - for (auto RT : StaticRuntimes) { - addSanitizerRuntime(TC, Args, CmdArgs, RT, false, true); - AddExportDynamic |= !addSanitizerDynamicList(TC, Args, CmdArgs, RT); - } - for (auto RT : NonWholeStaticRuntimes) { - addSanitizerRuntime(TC, Args, CmdArgs, RT, false, false); - AddExportDynamic |= !addSanitizerDynamicList(TC, Args, CmdArgs, RT); - } - for (auto S : RequiredSymbols) { - CmdArgs.push_back("-u"); - CmdArgs.push_back(Args.MakeArgString(S)); - } - // If there is a static runtime with no dynamic list, force all the symbols - // to be dynamic to be sure we export sanitizer interface functions. - if (AddExportDynamic) - CmdArgs.push_back("-export-dynamic"); - - const SanitizerArgs &SanArgs = TC.getSanitizerArgs(); - if (SanArgs.hasCrossDsoCfi() && !AddExportDynamic) - CmdArgs.push_back("-export-dynamic-symbol=__cfi_check"); - - return !StaticRuntimes.empty() || !NonWholeStaticRuntimes.empty(); -} - -static bool addXRayRuntime(const ToolChain &TC, const ArgList &Args, - ArgStringList &CmdArgs) { - if (Args.hasFlag(options::OPT_fxray_instrument, - options::OPT_fnoxray_instrument, false)) { - CmdArgs.push_back("-whole-archive"); - CmdArgs.push_back(TC.getCompilerRTArgString(Args, "xray", false)); - CmdArgs.push_back("-no-whole-archive"); - return true; - } - return false; -} - -static void linkXRayRuntimeDeps(const ToolChain &TC, const ArgList &Args, - ArgStringList &CmdArgs) { - CmdArgs.push_back("--no-as-needed"); - CmdArgs.push_back("-lpthread"); - CmdArgs.push_back("-lrt"); - CmdArgs.push_back("-lm"); - CmdArgs.push_back("-latomic"); - if (TC.GetCXXStdlibType(Args) == ToolChain::CST_Libcxx) - CmdArgs.push_back("-lc++"); - else - CmdArgs.push_back("-lstdc++"); - if (TC.getTriple().getOS() != llvm::Triple::FreeBSD) - CmdArgs.push_back("-ldl"); -} - -static bool areOptimizationsEnabled(const ArgList &Args) { - // Find the last -O arg and see if it is non-zero. - if (Arg *A = Args.getLastArg(options::OPT_O_Group)) - return !A->getOption().matches(options::OPT_O0); - // Defaults to -O0. - return false; -} - -static bool mustUseNonLeafFramePointerForTarget(const llvm::Triple &Triple) { - switch (Triple.getArch()){ - default: - return false; - case llvm::Triple::arm: - case llvm::Triple::thumb: - // ARM Darwin targets require a frame pointer to be always present to aid - // offline debugging via backtraces. - return Triple.isOSDarwin(); - } -} - -static bool useFramePointerForTargetByDefault(const ArgList &Args, - const llvm::Triple &Triple) { - switch (Triple.getArch()) { - case llvm::Triple::xcore: - case llvm::Triple::wasm32: - case llvm::Triple::wasm64: - // XCore never wants frame pointers, regardless of OS. - // WebAssembly never wants frame pointers. - return false; - default: - break; - } - - if (Triple.isOSLinux() || Triple.getOS() == llvm::Triple::CloudABI) { - switch (Triple.getArch()) { - // Don't use a frame pointer on linux if optimizing for certain targets. - case llvm::Triple::mips64: - case llvm::Triple::mips64el: - case llvm::Triple::mips: - case llvm::Triple::mipsel: - case llvm::Triple::ppc: - case llvm::Triple::ppc64: - case llvm::Triple::ppc64le: - case llvm::Triple::systemz: - case llvm::Triple::x86: - case llvm::Triple::x86_64: - return !areOptimizationsEnabled(Args); - default: - return true; - } - } - - if (Triple.isOSWindows()) { - switch (Triple.getArch()) { - case llvm::Triple::x86: - return !areOptimizationsEnabled(Args); - case llvm::Triple::x86_64: - return Triple.isOSBinFormatMachO(); - case llvm::Triple::arm: - case llvm::Triple::thumb: - // Windows on ARM builds with FPO disabled to aid fast stack walking - return true; - default: - // All other supported Windows ISAs use xdata unwind information, so frame - // pointers are not generally useful. - return false; - } - } - - return true; -} - -static bool shouldUseFramePointer(const ArgList &Args, - const llvm::Triple &Triple) { - if (Arg *A = Args.getLastArg(options::OPT_fno_omit_frame_pointer, - options::OPT_fomit_frame_pointer)) - return A->getOption().matches(options::OPT_fno_omit_frame_pointer) || - mustUseNonLeafFramePointerForTarget(Triple); - - if (Args.hasArg(options::OPT_pg)) - return true; - - return useFramePointerForTargetByDefault(Args, Triple); -} - -static bool shouldUseLeafFramePointer(const ArgList &Args, - const llvm::Triple &Triple) { - if (Arg *A = Args.getLastArg(options::OPT_mno_omit_leaf_frame_pointer, - options::OPT_momit_leaf_frame_pointer)) - return A->getOption().matches(options::OPT_mno_omit_leaf_frame_pointer); - - if (Args.hasArg(options::OPT_pg)) - return true; - - if (Triple.isPS4CPU()) - return false; - - return useFramePointerForTargetByDefault(Args, Triple); -} - -/// Add a CC1 option to specify the debug compilation directory. -static void addDebugCompDirArg(const ArgList &Args, ArgStringList &CmdArgs) { - SmallString<128> cwd; - if (!llvm::sys::fs::current_path(cwd)) { - CmdArgs.push_back("-fdebug-compilation-dir"); - CmdArgs.push_back(Args.MakeArgString(cwd)); - } -} - -static const char *SplitDebugName(const ArgList &Args, const InputInfo &Input) { - Arg *FinalOutput = Args.getLastArg(options::OPT_o); - if (FinalOutput && Args.hasArg(options::OPT_c)) { - SmallString<128> T(FinalOutput->getValue()); - llvm::sys::path::replace_extension(T, "dwo"); - return Args.MakeArgString(T); - } else { - // Use the compilation dir. - SmallString<128> T( - Args.getLastArgValue(options::OPT_fdebug_compilation_dir)); - SmallString<128> F(llvm::sys::path::stem(Input.getBaseInput())); - llvm::sys::path::replace_extension(F, "dwo"); - T += F; - return Args.MakeArgString(F); - } -} - -static void SplitDebugInfo(const ToolChain &TC, Compilation &C, const Tool &T, - const JobAction &JA, const ArgList &Args, - const InputInfo &Output, const char *OutFile) { - ArgStringList ExtractArgs; - ExtractArgs.push_back("--extract-dwo"); - - ArgStringList StripArgs; - StripArgs.push_back("--strip-dwo"); - - // Grabbing the output of the earlier compile step. - StripArgs.push_back(Output.getFilename()); - ExtractArgs.push_back(Output.getFilename()); - ExtractArgs.push_back(OutFile); - - const char *Exec = Args.MakeArgString(TC.GetProgramPath("objcopy")); - InputInfo II(types::TY_Object, Output.getFilename(), Output.getFilename()); - - // First extract the dwo sections. - C.addCommand(llvm::make_unique<Command>(JA, T, Exec, ExtractArgs, II)); - - // Then remove them from the original .o file. - C.addCommand(llvm::make_unique<Command>(JA, T, Exec, StripArgs, II)); -} - -/// \brief Vectorize at all optimization levels greater than 1 except for -Oz. -/// For -Oz the loop vectorizer is disable, while the slp vectorizer is enabled. -static bool shouldEnableVectorizerAtOLevel(const ArgList &Args, bool isSlpVec) { - if (Arg *A = Args.getLastArg(options::OPT_O_Group)) { - if (A->getOption().matches(options::OPT_O4) || - A->getOption().matches(options::OPT_Ofast)) - return true; - - if (A->getOption().matches(options::OPT_O0)) - return false; - - assert(A->getOption().matches(options::OPT_O) && "Must have a -O flag"); - - // Vectorize -Os. - StringRef S(A->getValue()); - if (S == "s") - return true; - - // Don't vectorize -Oz, unless it's the slp vectorizer. - if (S == "z") - return isSlpVec; - - unsigned OptLevel = 0; - if (S.getAsInteger(10, OptLevel)) - return false; - - return OptLevel > 1; - } - - return false; -} - -/// Add -x lang to \p CmdArgs for \p Input. -static void addDashXForInput(const ArgList &Args, const InputInfo &Input, - ArgStringList &CmdArgs) { - // When using -verify-pch, we don't want to provide the type - // 'precompiled-header' if it was inferred from the file extension - if (Args.hasArg(options::OPT_verify_pch) && Input.getType() == types::TY_PCH) - return; - - CmdArgs.push_back("-x"); - if (Args.hasArg(options::OPT_rewrite_objc)) - CmdArgs.push_back(types::getTypeName(types::TY_PP_ObjCXX)); - else - CmdArgs.push_back(types::getTypeName(Input.getType())); -} - -// Claim options we don't want to warn if they are unused. We do this for -// options that build systems might add but are unused when assembling or only -// running the preprocessor for example. -static void claimNoWarnArgs(const ArgList &Args) { - // Don't warn about unused -f(no-)?lto. This can happen when we're - // preprocessing, precompiling or assembling. - Args.ClaimAllArgs(options::OPT_flto_EQ); - Args.ClaimAllArgs(options::OPT_flto); - Args.ClaimAllArgs(options::OPT_fno_lto); -} - -static void appendUserToPath(SmallVectorImpl<char> &Result) { -#ifdef LLVM_ON_UNIX - const char *Username = getenv("LOGNAME"); -#else - const char *Username = getenv("USERNAME"); -#endif - if (Username) { - // Validate that LoginName can be used in a path, and get its length. - size_t Len = 0; - for (const char *P = Username; *P; ++P, ++Len) { - if (!isAlphanumeric(*P) && *P != '_') { - Username = nullptr; - break; - } - } - - if (Username && Len > 0) { - Result.append(Username, Username + Len); - return; - } - } - -// Fallback to user id. -#ifdef LLVM_ON_UNIX - std::string UID = llvm::utostr(getuid()); -#else - // FIXME: Windows seems to have an 'SID' that might work. - std::string UID = "9999"; -#endif - Result.append(UID.begin(), UID.end()); -} - -static Arg *getLastProfileUseArg(const ArgList &Args) { - auto *ProfileUseArg = Args.getLastArg( - options::OPT_fprofile_instr_use, options::OPT_fprofile_instr_use_EQ, - options::OPT_fprofile_use, options::OPT_fprofile_use_EQ, - options::OPT_fno_profile_instr_use); - - if (ProfileUseArg && - ProfileUseArg->getOption().matches(options::OPT_fno_profile_instr_use)) - ProfileUseArg = nullptr; - - return ProfileUseArg; -} - -static void addPGOAndCoverageFlags(Compilation &C, const Driver &D, - const InputInfo &Output, const ArgList &Args, - ArgStringList &CmdArgs) { - - auto *PGOGenerateArg = Args.getLastArg(options::OPT_fprofile_generate, - options::OPT_fprofile_generate_EQ, - options::OPT_fno_profile_generate); - if (PGOGenerateArg && - PGOGenerateArg->getOption().matches(options::OPT_fno_profile_generate)) - PGOGenerateArg = nullptr; - - auto *ProfileGenerateArg = Args.getLastArg( - options::OPT_fprofile_instr_generate, - options::OPT_fprofile_instr_generate_EQ, - options::OPT_fno_profile_instr_generate); - if (ProfileGenerateArg && - ProfileGenerateArg->getOption().matches( - options::OPT_fno_profile_instr_generate)) - ProfileGenerateArg = nullptr; - - if (PGOGenerateArg && ProfileGenerateArg) - D.Diag(diag::err_drv_argument_not_allowed_with) - << PGOGenerateArg->getSpelling() << ProfileGenerateArg->getSpelling(); - - auto *ProfileUseArg = getLastProfileUseArg(Args); - - if (PGOGenerateArg && ProfileUseArg) - D.Diag(diag::err_drv_argument_not_allowed_with) - << ProfileUseArg->getSpelling() << PGOGenerateArg->getSpelling(); - - if (ProfileGenerateArg && ProfileUseArg) - D.Diag(diag::err_drv_argument_not_allowed_with) - << ProfileGenerateArg->getSpelling() << ProfileUseArg->getSpelling(); - - if (ProfileGenerateArg) { - if (ProfileGenerateArg->getOption().matches( - options::OPT_fprofile_instr_generate_EQ)) - CmdArgs.push_back(Args.MakeArgString(Twine("-fprofile-instrument-path=") + - ProfileGenerateArg->getValue())); - // The default is to use Clang Instrumentation. - CmdArgs.push_back("-fprofile-instrument=clang"); - } - - if (PGOGenerateArg) { - CmdArgs.push_back("-fprofile-instrument=llvm"); - if (PGOGenerateArg->getOption().matches( - options::OPT_fprofile_generate_EQ)) { - SmallString<128> Path(PGOGenerateArg->getValue()); - llvm::sys::path::append(Path, "default_%m.profraw"); - CmdArgs.push_back( - Args.MakeArgString(Twine("-fprofile-instrument-path=") + Path)); - } - } - - if (ProfileUseArg) { - if (ProfileUseArg->getOption().matches(options::OPT_fprofile_instr_use_EQ)) - CmdArgs.push_back(Args.MakeArgString( - Twine("-fprofile-instrument-use-path=") + ProfileUseArg->getValue())); - else if ((ProfileUseArg->getOption().matches( - options::OPT_fprofile_use_EQ) || - ProfileUseArg->getOption().matches( - options::OPT_fprofile_instr_use))) { - SmallString<128> Path( - ProfileUseArg->getNumValues() == 0 ? "" : ProfileUseArg->getValue()); - if (Path.empty() || llvm::sys::fs::is_directory(Path)) - llvm::sys::path::append(Path, "default.profdata"); - CmdArgs.push_back( - Args.MakeArgString(Twine("-fprofile-instrument-use-path=") + Path)); - } - } - - if (Args.hasArg(options::OPT_ftest_coverage) || - Args.hasArg(options::OPT_coverage)) - CmdArgs.push_back("-femit-coverage-notes"); - if (Args.hasFlag(options::OPT_fprofile_arcs, options::OPT_fno_profile_arcs, - false) || - Args.hasArg(options::OPT_coverage)) - CmdArgs.push_back("-femit-coverage-data"); - - if (Args.hasFlag(options::OPT_fcoverage_mapping, - options::OPT_fno_coverage_mapping, false) && - !ProfileGenerateArg) - D.Diag(diag::err_drv_argument_only_allowed_with) - << "-fcoverage-mapping" - << "-fprofile-instr-generate"; - - if (Args.hasFlag(options::OPT_fcoverage_mapping, - options::OPT_fno_coverage_mapping, false)) - CmdArgs.push_back("-fcoverage-mapping"); - - if (C.getArgs().hasArg(options::OPT_c) || - C.getArgs().hasArg(options::OPT_S)) { - if (Output.isFilename()) { - CmdArgs.push_back("-coverage-notes-file"); - SmallString<128> OutputFilename; - if (Arg *FinalOutput = C.getArgs().getLastArg(options::OPT_o)) - OutputFilename = FinalOutput->getValue(); - else - OutputFilename = llvm::sys::path::filename(Output.getBaseInput()); - SmallString<128> CoverageFilename = OutputFilename; - if (llvm::sys::path::is_relative(CoverageFilename)) { - SmallString<128> Pwd; - if (!llvm::sys::fs::current_path(Pwd)) { - llvm::sys::path::append(Pwd, CoverageFilename); - CoverageFilename.swap(Pwd); - } - } - llvm::sys::path::replace_extension(CoverageFilename, "gcno"); - CmdArgs.push_back(Args.MakeArgString(CoverageFilename)); - - // Leave -fprofile-dir= an unused argument unless .gcda emission is - // enabled. To be polite, with '-fprofile-arcs -fno-profile-arcs' consider - // the flag used. There is no -fno-profile-dir, so the user has no - // targeted way to suppress the warning. - if (Args.hasArg(options::OPT_fprofile_arcs) || - Args.hasArg(options::OPT_coverage)) { - CmdArgs.push_back("-coverage-data-file"); - if (Arg *FProfileDir = Args.getLastArg(options::OPT_fprofile_dir)) { - CoverageFilename = FProfileDir->getValue(); - llvm::sys::path::append(CoverageFilename, OutputFilename); - } - llvm::sys::path::replace_extension(CoverageFilename, "gcda"); - CmdArgs.push_back(Args.MakeArgString(CoverageFilename)); - } - } - } -} - -static void addPS4ProfileRTArgs(const ToolChain &TC, const ArgList &Args, - ArgStringList &CmdArgs) { - if ((Args.hasFlag(options::OPT_fprofile_arcs, options::OPT_fno_profile_arcs, - false) || - Args.hasFlag(options::OPT_fprofile_generate, - options::OPT_fno_profile_instr_generate, false) || - Args.hasFlag(options::OPT_fprofile_generate_EQ, - options::OPT_fno_profile_instr_generate, false) || - Args.hasFlag(options::OPT_fprofile_instr_generate, - options::OPT_fno_profile_instr_generate, false) || - Args.hasFlag(options::OPT_fprofile_instr_generate_EQ, - options::OPT_fno_profile_instr_generate, false) || - Args.hasArg(options::OPT_fcreate_profile) || - Args.hasArg(options::OPT_coverage))) - CmdArgs.push_back("--dependent-lib=libclang_rt.profile-x86_64.a"); -} - -/// Parses the various -fpic/-fPIC/-fpie/-fPIE arguments. Then, -/// smooshes them together with platform defaults, to decide whether -/// this compile should be using PIC mode or not. Returns a tuple of -/// (RelocationModel, PICLevel, IsPIE). -static std::tuple<llvm::Reloc::Model, unsigned, bool> -ParsePICArgs(const ToolChain &ToolChain, const ArgList &Args) { - const llvm::Triple &EffectiveTriple = ToolChain.getEffectiveTriple(); - const llvm::Triple &Triple = ToolChain.getTriple(); - - bool PIE = ToolChain.isPIEDefault(); - bool PIC = PIE || ToolChain.isPICDefault(); - // The Darwin/MachO default to use PIC does not apply when using -static. - if (Triple.isOSBinFormatMachO() && Args.hasArg(options::OPT_static)) - PIE = PIC = false; - bool IsPICLevelTwo = PIC; - - bool KernelOrKext = - Args.hasArg(options::OPT_mkernel, options::OPT_fapple_kext); - - // Android-specific defaults for PIC/PIE - if (Triple.isAndroid()) { - switch (Triple.getArch()) { - case llvm::Triple::arm: - case llvm::Triple::armeb: - case llvm::Triple::thumb: - case llvm::Triple::thumbeb: - case llvm::Triple::aarch64: - case llvm::Triple::mips: - case llvm::Triple::mipsel: - case llvm::Triple::mips64: - case llvm::Triple::mips64el: - PIC = true; // "-fpic" - break; - - case llvm::Triple::x86: - case llvm::Triple::x86_64: - PIC = true; // "-fPIC" - IsPICLevelTwo = true; - break; - - default: - break; - } - } - - // OpenBSD-specific defaults for PIE - if (Triple.getOS() == llvm::Triple::OpenBSD) { - switch (ToolChain.getArch()) { - case llvm::Triple::mips64: - case llvm::Triple::mips64el: - case llvm::Triple::sparcel: - case llvm::Triple::x86: - case llvm::Triple::x86_64: - IsPICLevelTwo = false; // "-fpie" - break; - - case llvm::Triple::ppc: - case llvm::Triple::sparc: - case llvm::Triple::sparcv9: - IsPICLevelTwo = true; // "-fPIE" - break; - - default: - break; - } - } - - // The last argument relating to either PIC or PIE wins, and no - // other argument is used. If the last argument is any flavor of the - // '-fno-...' arguments, both PIC and PIE are disabled. Any PIE - // option implicitly enables PIC at the same level. - Arg *LastPICArg = Args.getLastArg(options::OPT_fPIC, options::OPT_fno_PIC, - options::OPT_fpic, options::OPT_fno_pic, - options::OPT_fPIE, options::OPT_fno_PIE, - options::OPT_fpie, options::OPT_fno_pie); - if (Triple.isOSWindows() && LastPICArg && - LastPICArg == - Args.getLastArg(options::OPT_fPIC, options::OPT_fpic, - options::OPT_fPIE, options::OPT_fpie)) { - ToolChain.getDriver().Diag(diag::err_drv_unsupported_opt_for_target) - << LastPICArg->getSpelling() << Triple.str(); - if (Triple.getArch() == llvm::Triple::x86_64) - return std::make_tuple(llvm::Reloc::PIC_, 2U, false); - return std::make_tuple(llvm::Reloc::Static, 0U, false); - } - - // Check whether the tool chain trumps the PIC-ness decision. If the PIC-ness - // is forced, then neither PIC nor PIE flags will have no effect. - if (!ToolChain.isPICDefaultForced()) { - if (LastPICArg) { - Option O = LastPICArg->getOption(); - if (O.matches(options::OPT_fPIC) || O.matches(options::OPT_fpic) || - O.matches(options::OPT_fPIE) || O.matches(options::OPT_fpie)) { - PIE = O.matches(options::OPT_fPIE) || O.matches(options::OPT_fpie); - PIC = - PIE || O.matches(options::OPT_fPIC) || O.matches(options::OPT_fpic); - IsPICLevelTwo = - O.matches(options::OPT_fPIE) || O.matches(options::OPT_fPIC); - } else { - PIE = PIC = false; - if (EffectiveTriple.isPS4CPU()) { - Arg *ModelArg = Args.getLastArg(options::OPT_mcmodel_EQ); - StringRef Model = ModelArg ? ModelArg->getValue() : ""; - if (Model != "kernel") { - PIC = true; - ToolChain.getDriver().Diag(diag::warn_drv_ps4_force_pic) - << LastPICArg->getSpelling(); - } - } - } - } - } - - // Introduce a Darwin and PS4-specific hack. If the default is PIC, but the - // PIC level would've been set to level 1, force it back to level 2 PIC - // instead. - if (PIC && (Triple.isOSDarwin() || EffectiveTriple.isPS4CPU())) - IsPICLevelTwo |= ToolChain.isPICDefault(); - - // This kernel flags are a trump-card: they will disable PIC/PIE - // generation, independent of the argument order. - if (KernelOrKext && - ((!EffectiveTriple.isiOS() || EffectiveTriple.isOSVersionLT(6)) && - !EffectiveTriple.isWatchOS())) - PIC = PIE = false; - - if (Arg *A = Args.getLastArg(options::OPT_mdynamic_no_pic)) { - // This is a very special mode. It trumps the other modes, almost no one - // uses it, and it isn't even valid on any OS but Darwin. - if (!Triple.isOSDarwin()) - ToolChain.getDriver().Diag(diag::err_drv_unsupported_opt_for_target) - << A->getSpelling() << Triple.str(); - - // FIXME: Warn when this flag trumps some other PIC or PIE flag. - - // Only a forced PIC mode can cause the actual compile to have PIC defines - // etc., no flags are sufficient. This behavior was selected to closely - // match that of llvm-gcc and Apple GCC before that. - PIC = ToolChain.isPICDefault() && ToolChain.isPICDefaultForced(); - - return std::make_tuple(llvm::Reloc::DynamicNoPIC, PIC ? 2U : 0U, false); - } - - bool EmbeddedPISupported; - switch (Triple.getArch()) { - case llvm::Triple::arm: - case llvm::Triple::armeb: - case llvm::Triple::thumb: - case llvm::Triple::thumbeb: - EmbeddedPISupported = true; - break; - default: - EmbeddedPISupported = false; - break; - } - - bool ROPI = false, RWPI = false; - Arg* LastROPIArg = Args.getLastArg(options::OPT_fropi, options::OPT_fno_ropi); - if (LastROPIArg && LastROPIArg->getOption().matches(options::OPT_fropi)) { - if (!EmbeddedPISupported) - ToolChain.getDriver().Diag(diag::err_drv_unsupported_opt_for_target) - << LastROPIArg->getSpelling() << Triple.str(); - ROPI = true; - } - Arg *LastRWPIArg = Args.getLastArg(options::OPT_frwpi, options::OPT_fno_rwpi); - if (LastRWPIArg && LastRWPIArg->getOption().matches(options::OPT_frwpi)) { - if (!EmbeddedPISupported) - ToolChain.getDriver().Diag(diag::err_drv_unsupported_opt_for_target) - << LastRWPIArg->getSpelling() << Triple.str(); - RWPI = true; - } - - // ROPI and RWPI are not comaptible with PIC or PIE. - if ((ROPI || RWPI) && (PIC || PIE)) - ToolChain.getDriver().Diag(diag::err_drv_ropi_rwpi_incompatible_with_pic); - - // When targettng MIPS64 with N64, the default is PIC, unless -mno-abicalls is - // used. - if ((Triple.getArch() == llvm::Triple::mips64 || - Triple.getArch() == llvm::Triple::mips64el) && - Args.hasArg(options::OPT_mno_abicalls)) - return std::make_tuple(llvm::Reloc::Static, 0U, false); - - if (PIC) - return std::make_tuple(llvm::Reloc::PIC_, IsPICLevelTwo ? 2U : 1U, PIE); - - llvm::Reloc::Model RelocM = llvm::Reloc::Static; - if (ROPI && RWPI) - RelocM = llvm::Reloc::ROPI_RWPI; - else if (ROPI) - RelocM = llvm::Reloc::ROPI; - else if (RWPI) - RelocM = llvm::Reloc::RWPI; - - return std::make_tuple(RelocM, 0U, false); -} - -static const char *RelocationModelName(llvm::Reloc::Model Model) { - switch (Model) { - case llvm::Reloc::Static: - return "static"; - case llvm::Reloc::PIC_: - return "pic"; - case llvm::Reloc::DynamicNoPIC: - return "dynamic-no-pic"; - case llvm::Reloc::ROPI: - return "ropi"; - case llvm::Reloc::RWPI: - return "rwpi"; - case llvm::Reloc::ROPI_RWPI: - return "ropi-rwpi"; - } - llvm_unreachable("Unknown Reloc::Model kind"); -} - -static void AddAssemblerKPIC(const ToolChain &ToolChain, const ArgList &Args, - ArgStringList &CmdArgs) { - llvm::Reloc::Model RelocationModel; - unsigned PICLevel; - bool IsPIE; - std::tie(RelocationModel, PICLevel, IsPIE) = ParsePICArgs(ToolChain, Args); - - if (RelocationModel != llvm::Reloc::Static) - CmdArgs.push_back("-KPIC"); -} - -void Clang::DumpCompilationDatabase(Compilation &C, StringRef Filename, - StringRef Target, const InputInfo &Output, - const InputInfo &Input, const ArgList &Args) const { - // If this is a dry run, do not create the compilation database file. - if (C.getArgs().hasArg(options::OPT__HASH_HASH_HASH)) - return; - - using llvm::yaml::escape; - const Driver &D = getToolChain().getDriver(); - - if (!CompilationDatabase) { - std::error_code EC; - auto File = llvm::make_unique<llvm::raw_fd_ostream>(Filename, EC, llvm::sys::fs::F_Text); - if (EC) { - D.Diag(clang::diag::err_drv_compilationdatabase) << Filename - << EC.message(); - return; - } - CompilationDatabase = std::move(File); - } - auto &CDB = *CompilationDatabase; - SmallString<128> Buf; - if (llvm::sys::fs::current_path(Buf)) - Buf = "."; - CDB << "{ \"directory\": \"" << escape(Buf) << "\""; - CDB << ", \"file\": \"" << escape(Input.getFilename()) << "\""; - CDB << ", \"output\": \"" << escape(Output.getFilename()) << "\""; - CDB << ", \"arguments\": [\"" << escape(D.ClangExecutable) << "\""; - Buf = "-x"; - Buf += types::getTypeName(Input.getType()); - CDB << ", \"" << escape(Buf) << "\""; - if (!D.SysRoot.empty() && !Args.hasArg(options::OPT__sysroot_EQ)) { - Buf = "--sysroot="; - Buf += D.SysRoot; - CDB << ", \"" << escape(Buf) << "\""; - } - CDB << ", \"" << escape(Input.getFilename()) << "\""; - for (auto &A: Args) { - auto &O = A->getOption(); - // Skip language selection, which is positional. - if (O.getID() == options::OPT_x) - continue; - // Skip writing dependency output and the compilation database itself. - if (O.getGroup().isValid() && O.getGroup().getID() == options::OPT_M_Group) - continue; - // Skip inputs. - if (O.getKind() == Option::InputClass) - continue; - // All other arguments are quoted and appended. - ArgStringList ASL; - A->render(Args, ASL); - for (auto &it: ASL) - CDB << ", \"" << escape(it) << "\""; - } - Buf = "--target="; - Buf += Target; - CDB << ", \"" << escape(Buf) << "\"]},\n"; -} - -void Clang::ConstructJob(Compilation &C, const JobAction &JA, - const InputInfo &Output, const InputInfoList &Inputs, - const ArgList &Args, const char *LinkingOutput) const { - const llvm::Triple &Triple = getToolChain().getEffectiveTriple(); - const std::string &TripleStr = Triple.getTriple(); - - bool KernelOrKext = - Args.hasArg(options::OPT_mkernel, options::OPT_fapple_kext); - const Driver &D = getToolChain().getDriver(); - ArgStringList CmdArgs; - - // Check number of inputs for sanity. We need at least one input. - assert(Inputs.size() >= 1 && "Must have at least one input."); - const InputInfo &Input = Inputs[0]; - // CUDA compilation may have multiple inputs (source file + results of - // device-side compilations). OpenMP device jobs also take the host IR as a - // second input. All other jobs are expected to have exactly one - // input. - bool IsCuda = JA.isOffloading(Action::OFK_Cuda); - bool IsOpenMPDevice = JA.isDeviceOffloading(Action::OFK_OpenMP); - assert((IsCuda || (IsOpenMPDevice && Inputs.size() == 2) || - 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(); - - // 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(); - } - - // C++ is not supported for IAMCU. - if (IsIAMCU && types::isCXX(Input.getType())) - D.Diag(diag::err_drv_clang_unsupported) << "C++ for IAMCU"; - - // Invoke ourselves in -cc1 mode. - // - // FIXME: Implement custom jobs for internal actions. - CmdArgs.push_back("-cc1"); - - // Add the "effective" target triple. - CmdArgs.push_back("-triple"); - CmdArgs.push_back(Args.MakeArgString(TripleStr)); - - if (const Arg *MJ = Args.getLastArg(options::OPT_MJ)) { - DumpCompilationDatabase(C, MJ->getValue(), TripleStr, Output, Input, Args); - Args.ClaimAllArgs(options::OPT_MJ); - } - - if (IsCuda) { - // We have to pass the triple of the host if compiling for a CUDA device and - // vice-versa. - std::string NormalizedTriple; - if (JA.isDeviceOffloading(Action::OFK_Cuda)) - NormalizedTriple = C.getSingleOffloadToolChain<Action::OFK_Host>() - ->getTriple() - .normalize(); - else - NormalizedTriple = C.getSingleOffloadToolChain<Action::OFK_Cuda>() - ->getTriple() - .normalize(); - - CmdArgs.push_back("-aux-triple"); - CmdArgs.push_back(Args.MakeArgString(NormalizedTriple)); - } - - if (Triple.isOSWindows() && (Triple.getArch() == llvm::Triple::arm || - Triple.getArch() == llvm::Triple::thumb)) { - unsigned Offset = Triple.getArch() == llvm::Triple::arm ? 4 : 6; - unsigned Version; - Triple.getArchName().substr(Offset).getAsInteger(10, Version); - if (Version < 7) - D.Diag(diag::err_target_unsupported_arch) << Triple.getArchName() - << TripleStr; - } - - // Push all default warning arguments that are specific to - // the given target. These come before user provided warning options - // are provided. - getToolChain().addClangWarningOptions(CmdArgs); - - // Select the appropriate action. - RewriteKind rewriteKind = RK_None; - - if (isa<AnalyzeJobAction>(JA)) { - assert(JA.getType() == types::TY_Plist && "Invalid output type."); - CmdArgs.push_back("-analyze"); - } else if (isa<MigrateJobAction>(JA)) { - CmdArgs.push_back("-migrate"); - } else if (isa<PreprocessJobAction>(JA)) { - if (Output.getType() == types::TY_Dependencies) - CmdArgs.push_back("-Eonly"); - else { - CmdArgs.push_back("-E"); - if (Args.hasArg(options::OPT_rewrite_objc) && - !Args.hasArg(options::OPT_g_Group)) - CmdArgs.push_back("-P"); - } - } else if (isa<AssembleJobAction>(JA)) { - CmdArgs.push_back("-emit-obj"); - - CollectArgsForIntegratedAssembler(C, Args, CmdArgs, D); - - // Also ignore explicit -force_cpusubtype_ALL option. - (void)Args.hasArg(options::OPT_force__cpusubtype__ALL); - } else if (isa<PrecompileJobAction>(JA)) { - // Use PCH if the user requested it. - bool UsePCH = D.CCCUsePCH; - - if (JA.getType() == types::TY_Nothing) - CmdArgs.push_back("-fsyntax-only"); - else if (JA.getType() == types::TY_ModuleFile) - CmdArgs.push_back("-emit-module-interface"); - else if (UsePCH) - CmdArgs.push_back("-emit-pch"); - else - CmdArgs.push_back("-emit-pth"); - } else if (isa<VerifyPCHJobAction>(JA)) { - CmdArgs.push_back("-verify-pch"); - } else { - assert((isa<CompileJobAction>(JA) || isa<BackendJobAction>(JA)) && - "Invalid action for clang tool."); - if (JA.getType() == types::TY_Nothing) { - CmdArgs.push_back("-fsyntax-only"); - } else if (JA.getType() == types::TY_LLVM_IR || - JA.getType() == types::TY_LTO_IR) { - CmdArgs.push_back("-emit-llvm"); - } else if (JA.getType() == types::TY_LLVM_BC || - JA.getType() == types::TY_LTO_BC) { - CmdArgs.push_back("-emit-llvm-bc"); - } else if (JA.getType() == types::TY_PP_Asm) { - CmdArgs.push_back("-S"); - } else if (JA.getType() == types::TY_AST) { - CmdArgs.push_back("-emit-pch"); - } else if (JA.getType() == types::TY_ModuleFile) { - CmdArgs.push_back("-module-file-info"); - } else if (JA.getType() == types::TY_RewrittenObjC) { - CmdArgs.push_back("-rewrite-objc"); - rewriteKind = RK_NonFragile; - } else if (JA.getType() == types::TY_RewrittenLegacyObjC) { - CmdArgs.push_back("-rewrite-objc"); - rewriteKind = RK_Fragile; - } else { - assert(JA.getType() == types::TY_PP_Asm && "Unexpected output type!"); - } - - // Preserve use-list order by default when emitting bitcode, so that - // loading the bitcode up in 'opt' or 'llc' and running passes gives the - // same result as running passes here. For LTO, we don't need to preserve - // the use-list order, since serialization to bitcode is part of the flow. - if (JA.getType() == types::TY_LLVM_BC) - CmdArgs.push_back("-emit-llvm-uselists"); - - if (D.isUsingLTO()) { - Args.AddLastArg(CmdArgs, options::OPT_flto, options::OPT_flto_EQ); - - // The Darwin linker currently uses the legacy LTO API, which does not - // support LTO unit features (CFI, whole program vtable opt) under - // ThinLTO. - if (!getToolChain().getTriple().isOSDarwin() || - D.getLTOMode() == LTOK_Full) - CmdArgs.push_back("-flto-unit"); - } - } - - if (const Arg *A = Args.getLastArg(options::OPT_fthinlto_index_EQ)) { - if (!types::isLLVMIR(Input.getType())) - D.Diag(diag::err_drv_argument_only_allowed_with) << A->getAsString(Args) - << "-x ir"; - Args.AddLastArg(CmdArgs, options::OPT_fthinlto_index_EQ); - } - - // Embed-bitcode option. - if (C.getDriver().embedBitcodeInObject() && !C.getDriver().isUsingLTO() && - (isa<BackendJobAction>(JA) || isa<AssembleJobAction>(JA))) { - // Add flags implied by -fembed-bitcode. - Args.AddLastArg(CmdArgs, options::OPT_fembed_bitcode_EQ); - // Disable all llvm IR level optimizations. - CmdArgs.push_back("-disable-llvm-passes"); - } - if (C.getDriver().embedBitcodeMarkerOnly() && !C.getDriver().isUsingLTO()) - CmdArgs.push_back("-fembed-bitcode=marker"); - - // We normally speed up the clang process a bit by skipping destructors at - // exit, but when we're generating diagnostics we can rely on some of the - // cleanup. - if (!C.isForDiagnostics()) - CmdArgs.push_back("-disable-free"); - -// Disable the verification pass in -asserts builds. -#ifdef NDEBUG - CmdArgs.push_back("-disable-llvm-verifier"); - // Discard LLVM value names in -asserts builds. - CmdArgs.push_back("-discard-value-names"); -#endif - - // Set the main file name, so that debug info works even with - // -save-temps. - CmdArgs.push_back("-main-file-name"); - CmdArgs.push_back(getBaseInputName(Args, Input)); - - // Some flags which affect the language (via preprocessor - // defines). - 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); - } - - CheckCodeGenerationOptions(D, Args); - - llvm::Reloc::Model RelocationModel; - unsigned PICLevel; - bool IsPIE; - std::tie(RelocationModel, PICLevel, IsPIE) = - ParsePICArgs(getToolChain(), Args); - - const char *RMName = RelocationModelName(RelocationModel); - - if ((RelocationModel == llvm::Reloc::ROPI || - RelocationModel == llvm::Reloc::ROPI_RWPI) && - types::isCXX(Input.getType()) && - !Args.hasArg(options::OPT_fallow_unsupported)) - D.Diag(diag::err_drv_ropi_incompatible_with_cxx); - - if (RMName) { - CmdArgs.push_back("-mrelocation-model"); - CmdArgs.push_back(RMName); - } - if (PICLevel > 0) { - CmdArgs.push_back("-pic-level"); - CmdArgs.push_back(PICLevel == 1 ? "1" : "2"); - if (IsPIE) - CmdArgs.push_back("-pic-is-pie"); - } - - if (Arg *A = Args.getLastArg(options::OPT_meabi)) { - CmdArgs.push_back("-meabi"); - CmdArgs.push_back(A->getValue()); - } - - CmdArgs.push_back("-mthread-model"); - if (Arg *A = Args.getLastArg(options::OPT_mthread_model)) - CmdArgs.push_back(A->getValue()); - else - CmdArgs.push_back(Args.MakeArgString(getToolChain().getThreadModel())); - - Args.AddLastArg(CmdArgs, options::OPT_fveclib); - - if (!Args.hasFlag(options::OPT_fmerge_all_constants, - options::OPT_fno_merge_all_constants)) - CmdArgs.push_back("-fno-merge-all-constants"); - - // LLVM Code Generator Options. - - if (Args.hasArg(options::OPT_frewrite_map_file) || - Args.hasArg(options::OPT_frewrite_map_file_EQ)) { - for (const Arg *A : Args.filtered(options::OPT_frewrite_map_file, - options::OPT_frewrite_map_file_EQ)) { - StringRef Map = A->getValue(); - if (!llvm::sys::fs::exists(Map)) { - D.Diag(diag::err_drv_no_such_file) << Map; - } else { - CmdArgs.push_back("-frewrite-map-file"); - CmdArgs.push_back(A->getValue()); - A->claim(); - } - } - } - - if (Arg *A = Args.getLastArg(options::OPT_Wframe_larger_than_EQ)) { - StringRef v = A->getValue(); - CmdArgs.push_back("-mllvm"); - CmdArgs.push_back(Args.MakeArgString("-warn-stack-size=" + v)); - A->claim(); - } - - if (!Args.hasFlag(options::OPT_fjump_tables, options::OPT_fno_jump_tables, - true)) - CmdArgs.push_back("-fno-jump-tables"); - - if (!Args.hasFlag(options::OPT_fpreserve_as_comments, - options::OPT_fno_preserve_as_comments, true)) - CmdArgs.push_back("-fno-preserve-as-comments"); - - if (Arg *A = Args.getLastArg(options::OPT_mregparm_EQ)) { - CmdArgs.push_back("-mregparm"); - CmdArgs.push_back(A->getValue()); - } - - if (Arg *A = Args.getLastArg(options::OPT_fpcc_struct_return, - 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(); - } else if (A->getOption().matches(options::OPT_fpcc_struct_return)) { - CmdArgs.push_back("-fpcc-struct-return"); - } else { - assert(A->getOption().matches(options::OPT_freg_struct_return)); - CmdArgs.push_back("-freg-struct-return"); - } - } - - if (Args.hasFlag(options::OPT_mrtd, options::OPT_mno_rtd, false)) - CmdArgs.push_back("-fdefault-calling-conv=stdcall"); - - if (shouldUseFramePointer(Args, getToolChain().getTriple())) - CmdArgs.push_back("-mdisable-fp-elim"); - if (!Args.hasFlag(options::OPT_fzero_initialized_in_bss, - options::OPT_fno_zero_initialized_in_bss)) - CmdArgs.push_back("-mno-zero-initialized-in-bss"); - - bool OFastEnabled = isOptimizationLevelFast(Args); - // If -Ofast is the optimization level, then -fstrict-aliasing should be - // enabled. This alias option is being used to simplify the hasFlag logic. - OptSpecifier StrictAliasingAliasOption = - 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(); - if (!Args.hasFlag(options::OPT_fstrict_aliasing, StrictAliasingAliasOption, - options::OPT_fno_strict_aliasing, TBAAOnByDefault)) - CmdArgs.push_back("-relaxed-aliasing"); - if (!Args.hasFlag(options::OPT_fstruct_path_tbaa, - options::OPT_fno_struct_path_tbaa)) - CmdArgs.push_back("-no-struct-path-tbaa"); - if (Args.hasFlag(options::OPT_fstrict_enums, options::OPT_fno_strict_enums, - false)) - CmdArgs.push_back("-fstrict-enums"); - if (!Args.hasFlag(options::OPT_fstrict_return, options::OPT_fno_strict_return, - true)) - CmdArgs.push_back("-fno-strict-return"); - if (Args.hasFlag(options::OPT_fstrict_vtable_pointers, - options::OPT_fno_strict_vtable_pointers, - false)) - CmdArgs.push_back("-fstrict-vtable-pointers"); - if (!Args.hasFlag(options::OPT_foptimize_sibling_calls, - options::OPT_fno_optimize_sibling_calls)) - CmdArgs.push_back("-mdisable-tail-calls"); - - // Handle segmented stacks. - if (Args.hasArg(options::OPT_fsplit_stack)) - CmdArgs.push_back("-split-stacks"); - - // If -Ofast is the optimization level, then -ffast-math should be enabled. - // This alias option is being used to simplify the getLastArg logic. - OptSpecifier FastMathAliasOption = - OFastEnabled ? options::OPT_Ofast : options::OPT_ffast_math; - - // Handle various floating point optimization flags, mapping them to the - // appropriate LLVM code generation flags. The pattern for all of these is to - // default off the codegen optimizations, and if any flag enables them and no - // flag disables them after the flag enabling them, enable the codegen - // optimization. This is complicated by several "umbrella" flags. - if (Arg *A = Args.getLastArg( - options::OPT_ffast_math, FastMathAliasOption, - options::OPT_fno_fast_math, options::OPT_ffinite_math_only, - options::OPT_fno_finite_math_only, options::OPT_fhonor_infinities, - options::OPT_fno_honor_infinities)) - if (A->getOption().getID() != options::OPT_fno_fast_math && - A->getOption().getID() != options::OPT_fno_finite_math_only && - A->getOption().getID() != options::OPT_fhonor_infinities) - CmdArgs.push_back("-menable-no-infs"); - if (Arg *A = Args.getLastArg( - options::OPT_ffast_math, FastMathAliasOption, - options::OPT_fno_fast_math, options::OPT_ffinite_math_only, - options::OPT_fno_finite_math_only, options::OPT_fhonor_nans, - options::OPT_fno_honor_nans)) - if (A->getOption().getID() != options::OPT_fno_fast_math && - A->getOption().getID() != options::OPT_fno_finite_math_only && - A->getOption().getID() != options::OPT_fhonor_nans) - CmdArgs.push_back("-menable-no-nans"); - - // -fmath-errno is the default on some platforms, e.g. BSD-derived OSes. - bool MathErrno = getToolChain().IsMathErrnoDefault(); - if (Arg *A = - Args.getLastArg(options::OPT_ffast_math, FastMathAliasOption, - options::OPT_fno_fast_math, options::OPT_fmath_errno, - options::OPT_fno_math_errno)) { - // 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). - if (A->getOption().getID() == options::OPT_fno_math_errno || - A->getOption().getID() == options::OPT_ffast_math || - A->getOption().getID() == options::OPT_Ofast) - MathErrno = false; - else if (A->getOption().getID() == options::OPT_fmath_errno) - MathErrno = true; - } - if (MathErrno) - CmdArgs.push_back("-fmath-errno"); - - // There are several flags which require disabling very specific - // optimizations. Any of these being disabled forces us to turn off the - // entire set of LLVM optimizations, so collect them through all the flag - // madness. - bool AssociativeMath = false; - if (Arg *A = Args.getLastArg( - options::OPT_ffast_math, FastMathAliasOption, - options::OPT_fno_fast_math, options::OPT_funsafe_math_optimizations, - options::OPT_fno_unsafe_math_optimizations, - options::OPT_fassociative_math, options::OPT_fno_associative_math)) - if (A->getOption().getID() != options::OPT_fno_fast_math && - A->getOption().getID() != options::OPT_fno_unsafe_math_optimizations && - A->getOption().getID() != options::OPT_fno_associative_math) - AssociativeMath = true; - bool ReciprocalMath = false; - if (Arg *A = Args.getLastArg( - options::OPT_ffast_math, FastMathAliasOption, - options::OPT_fno_fast_math, options::OPT_funsafe_math_optimizations, - options::OPT_fno_unsafe_math_optimizations, - options::OPT_freciprocal_math, options::OPT_fno_reciprocal_math)) - if (A->getOption().getID() != options::OPT_fno_fast_math && - A->getOption().getID() != options::OPT_fno_unsafe_math_optimizations && - A->getOption().getID() != options::OPT_fno_reciprocal_math) - ReciprocalMath = true; - bool SignedZeros = true; - if (Arg *A = Args.getLastArg( - options::OPT_ffast_math, FastMathAliasOption, - options::OPT_fno_fast_math, options::OPT_funsafe_math_optimizations, - options::OPT_fno_unsafe_math_optimizations, - options::OPT_fsigned_zeros, options::OPT_fno_signed_zeros)) - if (A->getOption().getID() != options::OPT_fno_fast_math && - A->getOption().getID() != options::OPT_fno_unsafe_math_optimizations && - A->getOption().getID() != options::OPT_fsigned_zeros) - SignedZeros = false; - bool TrappingMath = true; - if (Arg *A = Args.getLastArg( - options::OPT_ffast_math, FastMathAliasOption, - options::OPT_fno_fast_math, options::OPT_funsafe_math_optimizations, - options::OPT_fno_unsafe_math_optimizations, - options::OPT_ftrapping_math, options::OPT_fno_trapping_math)) - if (A->getOption().getID() != options::OPT_fno_fast_math && - A->getOption().getID() != options::OPT_fno_unsafe_math_optimizations && - A->getOption().getID() != options::OPT_ftrapping_math) - TrappingMath = false; - 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 (Arg *A = Args.getLastArg(options::OPT_ffast_math, FastMathAliasOption, - options::OPT_fno_fast_math, - options::OPT_funsafe_math_optimizations, - options::OPT_fno_unsafe_math_optimizations, - options::OPT_fdenormal_fp_math_EQ)) - if (A->getOption().getID() != options::OPT_fno_fast_math && - A->getOption().getID() != options::OPT_fno_unsafe_math_optimizations) - Args.AddLastArg(CmdArgs, options::OPT_fdenormal_fp_math_EQ); - - // Validate and pass through -fp-contract option. - if (Arg *A = Args.getLastArg(options::OPT_ffast_math, FastMathAliasOption, - options::OPT_fno_fast_math, - options::OPT_ffp_contract)) { - if (A->getOption().getID() == options::OPT_ffp_contract) { - StringRef Val = A->getValue(); - if (Val == "fast" || Val == "on" || Val == "off") { - CmdArgs.push_back(Args.MakeArgString("-ffp-contract=" + Val)); - } else { - D.Diag(diag::err_drv_unsupported_option_argument) - << A->getOption().getName() << Val; - } - } else if (A->getOption().matches(options::OPT_ffast_math) || - (OFastEnabled && A->getOption().matches(options::OPT_Ofast))) { - // If fast-math is set then set the fp-contract mode to fast. - CmdArgs.push_back(Args.MakeArgString("-ffp-contract=fast")); - } - } - - ParseMRecip(getToolChain().getDriver(), Args, CmdArgs); - - // We separately look for the '-ffast-math' and '-ffinite-math-only' flags, - // and if we find them, tell the frontend to provide the appropriate - // preprocessor macros. This is distinct from enabling any optimizations as - // these options induce language changes which must survive serialization - // and deserialization, etc. - if (Arg *A = Args.getLastArg(options::OPT_ffast_math, FastMathAliasOption, - options::OPT_fno_fast_math)) - if (!A->getOption().matches(options::OPT_fno_fast_math)) - CmdArgs.push_back("-ffast-math"); - if (Arg *A = Args.getLastArg(options::OPT_ffinite_math_only, - options::OPT_fno_fast_math)) - if (A->getOption().matches(options::OPT_ffinite_math_only)) - CmdArgs.push_back("-ffinite-math-only"); - - // Decide whether to use verbose asm. Verbose assembly is the default on - // toolchains which have the integrated assembler on by default. - bool IsIntegratedAssemblerDefault = - getToolChain().IsIntegratedAssemblerDefault(); - if (Args.hasFlag(options::OPT_fverbose_asm, options::OPT_fno_verbose_asm, - IsIntegratedAssemblerDefault) || - Args.hasArg(options::OPT_dA)) - CmdArgs.push_back("-masm-verbose"); - - if (!Args.hasFlag(options::OPT_fintegrated_as, options::OPT_fno_integrated_as, - IsIntegratedAssemblerDefault)) - CmdArgs.push_back("-no-integrated-as"); - - if (Args.hasArg(options::OPT_fdebug_pass_structure)) { - CmdArgs.push_back("-mdebug-pass"); - CmdArgs.push_back("Structure"); - } - if (Args.hasArg(options::OPT_fdebug_pass_arguments)) { - CmdArgs.push_back("-mdebug-pass"); - CmdArgs.push_back("Arguments"); - } - - // 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()) - 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()) - CmdArgs.push_back("-fforbid-guard-variables"); - - if (Args.hasFlag(options::OPT_mms_bitfields, options::OPT_mno_ms_bitfields, - false)) { - CmdArgs.push_back("-mms-bitfields"); - } - - if (Args.hasFlag(options::OPT_mpie_copy_relocations, - options::OPT_mno_pie_copy_relocations, - false)) { - CmdArgs.push_back("-mpie-copy-relocations"); - } - - // This is a coarse approximation of what llvm-gcc actually does, both - // -fasynchronous-unwind-tables and -fnon-call-exceptions interact in more - // complicated ways. - bool AsynchronousUnwindTables = - Args.hasFlag(options::OPT_fasynchronous_unwind_tables, - options::OPT_fno_asynchronous_unwind_tables, - (getToolChain().IsUnwindTablesDefault() || - getToolChain().getSanitizerArgs().needsUnwindTables()) && - !KernelOrKext); - if (Args.hasFlag(options::OPT_funwind_tables, options::OPT_fno_unwind_tables, - AsynchronousUnwindTables)) - CmdArgs.push_back("-munwind-tables"); - - getToolChain().addClangTargetOptions(Args, CmdArgs); - - if (Arg *A = Args.getLastArg(options::OPT_flimited_precision_EQ)) { - CmdArgs.push_back("-mlimit-float-precision"); - CmdArgs.push_back(A->getValue()); - } - - // FIXME: Handle -mtune=. - (void)Args.hasArg(options::OPT_mtune_EQ); - - if (Arg *A = Args.getLastArg(options::OPT_mcmodel_EQ)) { - CmdArgs.push_back("-mcode-model"); - CmdArgs.push_back(A->getValue()); - } - - // Add the target cpu - std::string CPU = getCPUName(Args, Triple, /*FromAs*/ false); - if (!CPU.empty()) { - CmdArgs.push_back("-target-cpu"); - 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; - } - - // 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()) - AddClangCLArgs(Args, InputType, CmdArgs, &DebugInfoKind, &EmitCodeView); - - // 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())) - 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() && - getToolChain().getArch() == llvm::Triple::x86) { - if ((Unsupported = Args.getLastArg(options::OPT_fapple_kext)) || - (Unsupported = Args.getLastArg(options::OPT_mkernel))) - D.Diag(diag::err_drv_clang_unsupported_opt_cxx_darwin_i386) - << Unsupported->getOption().getName(); - } - } - - Args.AddAllArgs(CmdArgs, options::OPT_v); - Args.AddLastArg(CmdArgs, options::OPT_H); - if (D.CCPrintHeaders && !D.CCGenDiagnostics) { - CmdArgs.push_back("-header-include-file"); - CmdArgs.push_back(D.CCPrintHeadersFilename ? D.CCPrintHeadersFilename - : "-"); - } - Args.AddLastArg(CmdArgs, options::OPT_P); - Args.AddLastArg(CmdArgs, options::OPT_print_ivar_layout); - - if (D.CCLogDiagnostics && !D.CCGenDiagnostics) { - CmdArgs.push_back("-diagnostic-log-file"); - CmdArgs.push_back(D.CCLogDiagnosticsFilename ? D.CCLogDiagnosticsFilename - : "-"); - } - - 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 flags -gstrict-dwarf and -grecord-gcc-switches for now. - 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() && SplitDwarfArg) { - if (!splitDwarfInlining) - CmdArgs.push_back("-fno-split-dwarf-inlining"); - if (DebugInfoKind == codegenoptions::NoDebugInfo) - DebugInfoKind = codegenoptions::LimitedDebugInfo; - CmdArgs.push_back("-backend-option"); - CmdArgs.push_back("-split-dwarf=Enable"); - } - - // 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"); - } - - bool UseSeparateSections = isUseSeparateSections(Triple); - - if (Args.hasFlag(options::OPT_ffunction_sections, - options::OPT_fno_function_sections, UseSeparateSections)) { - CmdArgs.push_back("-ffunction-sections"); - } - - if (Args.hasFlag(options::OPT_fdata_sections, options::OPT_fno_data_sections, - UseSeparateSections)) { - CmdArgs.push_back("-fdata-sections"); - } - - if (!Args.hasFlag(options::OPT_funique_section_names, - options::OPT_fno_unique_section_names, true)) - CmdArgs.push_back("-fno-unique-section-names"); - - Args.AddAllArgs(CmdArgs, options::OPT_finstrument_functions); - - if (Args.hasFlag(options::OPT_fxray_instrument, - options::OPT_fnoxray_instrument, false)) { - const char *const XRayInstrumentOption = "-fxray-instrument"; - if (Triple.getOS() == llvm::Triple::Linux) - switch (Triple.getArch()) { - case llvm::Triple::x86_64: - case llvm::Triple::arm: - case llvm::Triple::aarch64: - case llvm::Triple::ppc64le: - case llvm::Triple::mips: - case llvm::Triple::mipsel: - case llvm::Triple::mips64: - case llvm::Triple::mips64el: - // Supported. - break; - default: - D.Diag(diag::err_drv_clang_unsupported) - << (std::string(XRayInstrumentOption) + " on " + Triple.str()); - } - else - D.Diag(diag::err_drv_clang_unsupported) - << (std::string(XRayInstrumentOption) + " on non-Linux target OS"); - CmdArgs.push_back(XRayInstrumentOption); - if (const Arg *A = - Args.getLastArg(options::OPT_fxray_instruction_threshold_, - options::OPT_fxray_instruction_threshold_EQ)) { - CmdArgs.push_back("-fxray-instruction-threshold"); - CmdArgs.push_back(A->getValue()); - } - } - - addPGOAndCoverageFlags(C, D, Output, Args, CmdArgs); - - // Add runtime flag for PS4 when PGO or Coverage are enabled. - if (getToolChain().getTriple().isPS4CPU()) - addPS4ProfileRTArgs(getToolChain(), Args, CmdArgs); - - // Pass options for controlling the default header search paths. - if (Args.hasArg(options::OPT_nostdinc)) { - CmdArgs.push_back("-nostdsysteminc"); - CmdArgs.push_back("-nobuiltininc"); - } else { - if (Args.hasArg(options::OPT_nostdlibinc)) - CmdArgs.push_back("-nostdsysteminc"); - Args.AddLastArg(CmdArgs, options::OPT_nostdincxx); - Args.AddLastArg(CmdArgs, options::OPT_nobuiltininc); - } - - // Pass the path to compiler resource files. - CmdArgs.push_back("-resource-dir"); - CmdArgs.push_back(D.ResourceDir.c_str()); - - 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); - } - - // Add preprocessing options like -I, -D, etc. if we are using the - // preprocessor. - // - // FIXME: Support -fpreprocessed - if (types::getPreprocessedType(InputType) != types::TY_INVALID) - AddPreprocessingOptions(C, JA, D, Args, CmdArgs, Output, Inputs); - - // Don't warn about "clang -c -DPIC -fPIC test.i" because libtool.m4 assumes - // that "The compiler can only warn and ignore the option if not recognized". - // When building with ccache, it will pass -D options to clang even on - // preprocessed inputs and configure concludes that -fPIC is not supported. - Args.ClaimAllArgs(options::OPT_D); - - // Manually translate -O4 to -O3; let clang reject others. - if (Arg *A = Args.getLastArg(options::OPT_O_Group)) { - if (A->getOption().matches(options::OPT_O4)) { - CmdArgs.push_back("-O3"); - D.Diag(diag::warn_O4_is_O3); - } else { - A->render(Args, CmdArgs); - } - } - - // Warn about ignored options to clang. - for (const Arg *A : - Args.filtered(options::OPT_clang_ignored_gcc_optimization_f_Group)) { - D.Diag(diag::warn_ignored_gcc_optimization) << A->getAsString(Args); - A->claim(); - } - - claimNoWarnArgs(Args); - - Args.AddAllArgs(CmdArgs, options::OPT_R_Group); - - Args.AddAllArgs(CmdArgs, options::OPT_W_Group); - if (Args.hasFlag(options::OPT_pedantic, options::OPT_no_pedantic, false)) - CmdArgs.push_back("-pedantic"); - Args.AddLastArg(CmdArgs, options::OPT_pedantic_errors); - Args.AddLastArg(CmdArgs, options::OPT_w); - - // Handle -{std, ansi, trigraphs} -- take the last of -{std, ansi} - // (-ansi is equivalent to -std=c89 or -std=c++98). - // - // If a std is supplied, only add -trigraphs if it follows the - // option. - bool ImplyVCPPCXXVer = false; - if (Arg *Std = Args.getLastArg(options::OPT_std_EQ, options::OPT_ansi)) { - if (Std->getOption().matches(options::OPT_ansi)) - if (types::isCXX(InputType)) - CmdArgs.push_back("-std=c++98"); - else - CmdArgs.push_back("-std=c89"); - else - Std->render(Args, CmdArgs); - - // If -f(no-)trigraphs appears after the language standard flag, honor it. - if (Arg *A = Args.getLastArg(options::OPT_std_EQ, options::OPT_ansi, - options::OPT_ftrigraphs, - options::OPT_fno_trigraphs)) - if (A != Std) - A->render(Args, CmdArgs); - } else { - // Honor -std-default. - // - // FIXME: Clang doesn't correctly handle -std= when the input language - // doesn't match. For the time being just ignore this for C++ inputs; - // eventually we want to do all the standard defaulting here instead of - // splitting it between the driver and clang -cc1. - if (!types::isCXX(InputType)) - Args.AddAllArgsTranslated(CmdArgs, options::OPT_std_default_EQ, "-std=", - /*Joined=*/true); - else if (IsWindowsMSVC) - ImplyVCPPCXXVer = true; - - Args.AddLastArg(CmdArgs, options::OPT_ftrigraphs, - options::OPT_fno_trigraphs); - } - - // GCC's behavior for -Wwrite-strings is a bit strange: - // * In C, this "warning flag" changes the types of string literals from - // 'char[N]' to 'const char[N]', and thus triggers an unrelated warning - // for the discarded qualifier. - // * In C++, this is just a normal warning flag. - // - // Implementing this warning correctly in C is hard, so we follow GCC's - // behavior for now. FIXME: Directly diagnose uses of a string literal as - // a non-const char* in C, rather than using this crude hack. - if (!types::isCXX(InputType)) { - // FIXME: This should behave just like a warning flag, and thus should also - // respect -Weverything, -Wno-everything, -Werror=write-strings, and so on. - Arg *WriteStrings = - Args.getLastArg(options::OPT_Wwrite_strings, - options::OPT_Wno_write_strings, options::OPT_w); - if (WriteStrings && - WriteStrings->getOption().matches(options::OPT_Wwrite_strings)) - CmdArgs.push_back("-fconst-strings"); - } - - // GCC provides a macro definition '__DEPRECATED' when -Wdeprecated is active - // during C++ compilation, which it is by default. GCC keeps this define even - // in the presence of '-w', match this behavior bug-for-bug. - if (types::isCXX(InputType) && - Args.hasFlag(options::OPT_Wdeprecated, options::OPT_Wno_deprecated, - true)) { - CmdArgs.push_back("-fdeprecated-macro"); - } - - // Translate GCC's misnamer '-fasm' arguments to '-fgnu-keywords'. - if (Arg *Asm = Args.getLastArg(options::OPT_fasm, options::OPT_fno_asm)) { - if (Asm->getOption().matches(options::OPT_fasm)) - CmdArgs.push_back("-fgnu-keywords"); - else - CmdArgs.push_back("-fno-gnu-keywords"); - } - - if (ShouldDisableDwarfDirectory(Args, getToolChain())) - CmdArgs.push_back("-fno-dwarf-directory-asm"); - - if (ShouldDisableAutolink(Args, getToolChain())) - CmdArgs.push_back("-fno-autolink"); - - // Add in -fdebug-compilation-dir if necessary. - addDebugCompDirArg(Args, CmdArgs); - - for (const Arg *A : Args.filtered(options::OPT_fdebug_prefix_map_EQ)) { - StringRef Map = A->getValue(); - if (Map.find('=') == StringRef::npos) - D.Diag(diag::err_drv_invalid_argument_to_fdebug_prefix_map) << Map; - else - CmdArgs.push_back(Args.MakeArgString("-fdebug-prefix-map=" + Map)); - A->claim(); - } - - if (Arg *A = Args.getLastArg(options::OPT_ftemplate_depth_, - options::OPT_ftemplate_depth_EQ)) { - CmdArgs.push_back("-ftemplate-depth"); - CmdArgs.push_back(A->getValue()); - } - - if (Arg *A = Args.getLastArg(options::OPT_foperator_arrow_depth_EQ)) { - CmdArgs.push_back("-foperator-arrow-depth"); - CmdArgs.push_back(A->getValue()); - } - - if (Arg *A = Args.getLastArg(options::OPT_fconstexpr_depth_EQ)) { - CmdArgs.push_back("-fconstexpr-depth"); - CmdArgs.push_back(A->getValue()); - } - - if (Arg *A = Args.getLastArg(options::OPT_fconstexpr_steps_EQ)) { - CmdArgs.push_back("-fconstexpr-steps"); - CmdArgs.push_back(A->getValue()); - } - - if (Arg *A = Args.getLastArg(options::OPT_fbracket_depth_EQ)) { - CmdArgs.push_back("-fbracket-depth"); - CmdArgs.push_back(A->getValue()); - } - - if (Arg *A = Args.getLastArg(options::OPT_Wlarge_by_value_copy_EQ, - options::OPT_Wlarge_by_value_copy_def)) { - if (A->getNumValues()) { - StringRef bytes = A->getValue(); - CmdArgs.push_back(Args.MakeArgString("-Wlarge-by-value-copy=" + bytes)); - } else - CmdArgs.push_back("-Wlarge-by-value-copy=64"); // default value - } - - if (Args.hasArg(options::OPT_relocatable_pch)) - CmdArgs.push_back("-relocatable-pch"); - - if (Arg *A = Args.getLastArg(options::OPT_fconstant_string_class_EQ)) { - CmdArgs.push_back("-fconstant-string-class"); - CmdArgs.push_back(A->getValue()); - } - - if (Arg *A = Args.getLastArg(options::OPT_ftabstop_EQ)) { - CmdArgs.push_back("-ftabstop"); - CmdArgs.push_back(A->getValue()); - } - - CmdArgs.push_back("-ferror-limit"); - if (Arg *A = Args.getLastArg(options::OPT_ferror_limit_EQ)) - CmdArgs.push_back(A->getValue()); - else - CmdArgs.push_back("19"); - - if (Arg *A = Args.getLastArg(options::OPT_fmacro_backtrace_limit_EQ)) { - CmdArgs.push_back("-fmacro-backtrace-limit"); - CmdArgs.push_back(A->getValue()); - } - - if (Arg *A = Args.getLastArg(options::OPT_ftemplate_backtrace_limit_EQ)) { - CmdArgs.push_back("-ftemplate-backtrace-limit"); - CmdArgs.push_back(A->getValue()); - } - - if (Arg *A = Args.getLastArg(options::OPT_fconstexpr_backtrace_limit_EQ)) { - CmdArgs.push_back("-fconstexpr-backtrace-limit"); - CmdArgs.push_back(A->getValue()); - } - - if (Arg *A = Args.getLastArg(options::OPT_fspell_checking_limit_EQ)) { - CmdArgs.push_back("-fspell-checking-limit"); - CmdArgs.push_back(A->getValue()); - } - - // Pass -fmessage-length=. - CmdArgs.push_back("-fmessage-length"); - if (Arg *A = Args.getLastArg(options::OPT_fmessage_length_EQ)) { - CmdArgs.push_back(A->getValue()); - } else { - // If -fmessage-length=N was not specified, determine whether this is a - // terminal and, if so, implicitly define -fmessage-length appropriately. - unsigned N = llvm::sys::Process::StandardErrColumns(); - CmdArgs.push_back(Args.MakeArgString(Twine(N))); - } - - // -fvisibility= and -fvisibility-ms-compat are of a piece. - if (const Arg *A = Args.getLastArg(options::OPT_fvisibility_EQ, - options::OPT_fvisibility_ms_compat)) { - if (A->getOption().matches(options::OPT_fvisibility_EQ)) { - CmdArgs.push_back("-fvisibility"); - CmdArgs.push_back(A->getValue()); - } else { - assert(A->getOption().matches(options::OPT_fvisibility_ms_compat)); - CmdArgs.push_back("-fvisibility"); - CmdArgs.push_back("hidden"); - CmdArgs.push_back("-ftype-visibility"); - CmdArgs.push_back("default"); - } - } - - Args.AddLastArg(CmdArgs, options::OPT_fvisibility_inlines_hidden); - - 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); - Args.AddLastArg(CmdArgs, options::OPT_fno_operator_names); - // Emulated TLS is enabled by default on Android, and can be enabled manually - // with -femulated-tls. - bool EmulatedTLSDefault = Triple.isAndroid() || Triple.isWindowsCygwinEnvironment(); - if (Args.hasFlag(options::OPT_femulated_tls, options::OPT_fno_emulated_tls, - EmulatedTLSDefault)) - CmdArgs.push_back("-femulated-tls"); - // AltiVec-like language extensions aren't relevant for assembling. - if (!isa<PreprocessJobAction>(JA) || Output.getType() != types::TY_PP_Asm) { - Args.AddLastArg(CmdArgs, options::OPT_faltivec); - Args.AddLastArg(CmdArgs, options::OPT_fzvector); - } - Args.AddLastArg(CmdArgs, options::OPT_fdiagnostics_show_template_tree); - Args.AddLastArg(CmdArgs, options::OPT_fno_elide_type); - - // Forward flags for OpenMP. We don't do this if the current action is an - // device offloading action other than OpenMP. - if (Args.hasFlag(options::OPT_fopenmp, options::OPT_fopenmp_EQ, - options::OPT_fno_openmp, false) && - (JA.isDeviceOffloading(Action::OFK_None) || - JA.isDeviceOffloading(Action::OFK_OpenMP))) { - switch (getToolChain().getDriver().getOpenMPRuntime(Args)) { - case Driver::OMPRT_OMP: - case Driver::OMPRT_IOMP5: - // Clang can generate useful OpenMP code for these two runtime libraries. - CmdArgs.push_back("-fopenmp"); - - // If no option regarding the use of TLS in OpenMP codegeneration is - // given, decide a default based on the target. Otherwise rely on the - // options and pass the right information to the frontend. - if (!Args.hasFlag(options::OPT_fopenmp_use_tls, - options::OPT_fnoopenmp_use_tls, /*Default=*/true)) - CmdArgs.push_back("-fnoopenmp-use-tls"); - Args.AddAllArgs(CmdArgs, options::OPT_fopenmp_version_EQ); - break; - default: - // By default, if Clang doesn't know how to generate useful OpenMP code - // for a specific runtime library, we just don't pass the '-fopenmp' flag - // down to the actual compilation. - // FIXME: It would be better to have a mode which *only* omits IR - // generation based on the OpenMP support so that we get consistent - // semantic analysis, etc. - break; - } - } - - const SanitizerArgs &Sanitize = getToolChain().getSanitizerArgs(); - Sanitize.addArgs(getToolChain(), Args, CmdArgs, InputType); - - // Report an error for -faltivec on anything other than PowerPC. - if (const Arg *A = Args.getLastArg(options::OPT_faltivec)) { - const llvm::Triple::ArchType Arch = getToolChain().getArch(); - if (!(Arch == llvm::Triple::ppc || Arch == llvm::Triple::ppc64 || - Arch == llvm::Triple::ppc64le)) - D.Diag(diag::err_drv_argument_only_allowed_with) << A->getAsString(Args) - << "ppc/ppc64/ppc64le"; - } - - // -fzvector is incompatible with -faltivec. - if (Arg *A = Args.getLastArg(options::OPT_fzvector)) - if (Args.hasArg(options::OPT_faltivec)) - D.Diag(diag::err_drv_argument_not_allowed_with) << A->getAsString(Args) - << "-faltivec"; - - if (getToolChain().SupportsProfiling()) - Args.AddLastArg(CmdArgs, options::OPT_pg); - - if (getToolChain().SupportsProfiling()) - Args.AddLastArg(CmdArgs, options::OPT_mfentry); - - // -flax-vector-conversions is default. - if (!Args.hasFlag(options::OPT_flax_vector_conversions, - options::OPT_fno_lax_vector_conversions)) - CmdArgs.push_back("-fno-lax-vector-conversions"); - - if (Args.getLastArg(options::OPT_fapple_kext) || - (Args.hasArg(options::OPT_mkernel) && types::isCXX(InputType))) - CmdArgs.push_back("-fapple-kext"); - - Args.AddLastArg(CmdArgs, options::OPT_fobjc_sender_dependent_dispatch); - Args.AddLastArg(CmdArgs, options::OPT_fdiagnostics_print_source_range_info); - Args.AddLastArg(CmdArgs, options::OPT_fdiagnostics_parseable_fixits); - Args.AddLastArg(CmdArgs, options::OPT_ftime_report); - Args.AddLastArg(CmdArgs, options::OPT_ftrapv); - - if (Arg *A = Args.getLastArg(options::OPT_ftrapv_handler_EQ)) { - CmdArgs.push_back("-ftrapv-handler"); - CmdArgs.push_back(A->getValue()); - } - - Args.AddLastArg(CmdArgs, options::OPT_ftrap_function_EQ); - - // -fno-strict-overflow implies -fwrapv if it isn't disabled, but - // -fstrict-overflow won't turn off an explicitly enabled -fwrapv. - if (Arg *A = Args.getLastArg(options::OPT_fwrapv, options::OPT_fno_wrapv)) { - if (A->getOption().matches(options::OPT_fwrapv)) - CmdArgs.push_back("-fwrapv"); - } else if (Arg *A = Args.getLastArg(options::OPT_fstrict_overflow, - options::OPT_fno_strict_overflow)) { - if (A->getOption().matches(options::OPT_fno_strict_overflow)) - CmdArgs.push_back("-fwrapv"); - } - - if (Arg *A = Args.getLastArg(options::OPT_freroll_loops, - options::OPT_fno_reroll_loops)) - if (A->getOption().matches(options::OPT_freroll_loops)) - CmdArgs.push_back("-freroll-loops"); - - Args.AddLastArg(CmdArgs, options::OPT_fwritable_strings); - Args.AddLastArg(CmdArgs, options::OPT_funroll_loops, - options::OPT_fno_unroll_loops); - - 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(); - } - } - - // Translate -mstackrealign - if (Args.hasFlag(options::OPT_mstackrealign, options::OPT_mno_stackrealign, - false)) - CmdArgs.push_back(Args.MakeArgString("-mstackrealign")); - - if (Args.hasArg(options::OPT_mstack_alignment)) { - StringRef alignment = Args.getLastArgValue(options::OPT_mstack_alignment); - CmdArgs.push_back(Args.MakeArgString("-mstack-alignment=" + alignment)); - } - - if (Args.hasArg(options::OPT_mstack_probe_size)) { - StringRef Size = Args.getLastArgValue(options::OPT_mstack_probe_size); - - if (!Size.empty()) - CmdArgs.push_back(Args.MakeArgString("-mstack-probe-size=" + Size)); - else - 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)) { - CmdArgs.push_back("-backend-option"); - CmdArgs.push_back("-arm-restrict-it"); - } else { - CmdArgs.push_back("-backend-option"); - CmdArgs.push_back("-arm-no-restrict-it"); - } - } else if (Triple.isOSWindows() && - (Triple.getArch() == llvm::Triple::arm || - Triple.getArch() == llvm::Triple::thumb)) { - // Windows on ARM expects restricted IT blocks - CmdArgs.push_back("-backend-option"); - CmdArgs.push_back("-arm-restrict-it"); - } - - // 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"); - } - - // Forward -f options with positive and negative forms; we translate - // these by hand. - if (Arg *A = Args.getLastArg(options::OPT_fprofile_sample_use_EQ)) { - StringRef fname = A->getValue(); - if (!llvm::sys::fs::exists(fname)) - D.Diag(diag::err_drv_no_such_file) << fname; - else - 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)); - } - - if (!Args.hasFlag(options::OPT_fassume_sane_operator_new, - options::OPT_fno_assume_sane_operator_new)) - CmdArgs.push_back("-fno-assume-sane-operator-new"); - - // -fblocks=0 is default. - if (Args.hasFlag(options::OPT_fblocks, options::OPT_fno_blocks, - getToolChain().IsBlocksDefault()) || - (Args.hasArg(options::OPT_fgnu_runtime) && - Args.hasArg(options::OPT_fobjc_nonfragile_abi) && - !Args.hasArg(options::OPT_fno_blocks))) { - CmdArgs.push_back("-fblocks"); - - if (!Args.hasArg(options::OPT_fgnu_runtime) && - !getToolChain().hasBlocksRuntime()) - CmdArgs.push_back("-fblocks-runtime-optional"); - } - - 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())); - } - - // -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); - - // -faccess-control is default. - if (Args.hasFlag(options::OPT_fno_access_control, - options::OPT_faccess_control, false)) - CmdArgs.push_back("-fno-access-control"); - - // -felide-constructors is the default. - if (Args.hasFlag(options::OPT_fno_elide_constructors, - options::OPT_felide_constructors, false)) - CmdArgs.push_back("-fno-elide-constructors"); - - ToolChain::RTTIMode RTTIMode = getToolChain().getRTTIMode(); - - if (KernelOrKext || (types::isCXX(InputType) && - (RTTIMode == ToolChain::RM_DisabledExplicitly || - RTTIMode == ToolChain::RM_DisabledImplicitly))) - CmdArgs.push_back("-fno-rtti"); - - // -fshort-enums=0 is default for all architectures except Hexagon. - if (Args.hasFlag(options::OPT_fshort_enums, options::OPT_fno_short_enums, - 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"); - } - - // -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 && - getToolChain().getArch() != llvm::Triple::hexagon && - getToolChain().getArch() != llvm::Triple::xcore && - ((getToolChain().getTriple().getVendor() != - llvm::Triple::MipsTechnologies) || - getToolChain().getTriple().hasEnvironment())) || - KernelOrKext) - CmdArgs.push_back("-fno-use-cxa-atexit"); - - // -fms-extensions=0 is default. - if (Args.hasFlag(options::OPT_fms_extensions, options::OPT_fno_ms_extensions, - IsWindowsMSVC)) - CmdArgs.push_back("-fms-extensions"); - - // -fno-use-line-directives is default. - if (Args.hasFlag(options::OPT_fuse_line_directives, - options::OPT_fno_use_line_directives, false)) - CmdArgs.push_back("-fuse-line-directives"); - - // -fms-compatibility=0 is default. - if (Args.hasFlag(options::OPT_fms_compatibility, - options::OPT_fno_ms_compatibility, - (IsWindowsMSVC && - Args.hasFlag(options::OPT_fms_extensions, - options::OPT_fno_ms_extensions, true)))) - CmdArgs.push_back("-fms-compatibility"); - - VersionTuple MSVT = - getToolChain().computeMSVCVersion(&getToolChain().getDriver(), Args); - if (!MSVT.empty()) - CmdArgs.push_back( - Args.MakeArgString("-fms-compatibility-version=" + MSVT.getAsString())); - - bool IsMSVC2015Compatible = MSVT.getMajor() >= 19; - if (ImplyVCPPCXXVer) { - StringRef LanguageStandard; - 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") - .Default(""); - if (LanguageStandard.empty()) - D.Diag(clang::diag::warn_drv_unused_argument) - << StdArg->getAsString(Args); - } - - if (LanguageStandard.empty()) { - if (IsMSVC2015Compatible) - LanguageStandard = "-std=c++14"; - else - LanguageStandard = "-std=c++11"; - } - - CmdArgs.push_back(LanguageStandard.data()); - } - - // -fno-borland-extensions is default. - if (Args.hasFlag(options::OPT_fborland_extensions, - options::OPT_fno_borland_extensions, false)) - CmdArgs.push_back("-fborland-extensions"); - - // -fno-declspec is default, except for PS4. - if (Args.hasFlag(options::OPT_fdeclspec, options::OPT_fno_declspec, - getToolChain().getTriple().isPS4())) - CmdArgs.push_back("-fdeclspec"); - else if (Args.hasArg(options::OPT_fno_declspec)) - CmdArgs.push_back("-fno-declspec"); // Explicitly disabling __declspec. - - // -fthreadsafe-static is default, except for MSVC compatibility versions less - // than 19. - if (!Args.hasFlag(options::OPT_fthreadsafe_statics, - options::OPT_fno_threadsafe_statics, - !IsWindowsMSVC || IsMSVC2015Compatible)) - CmdArgs.push_back("-fno-threadsafe-statics"); - - // -fno-delayed-template-parsing is default, except for Windows where MSVC STL - // needs it. - if (Args.hasFlag(options::OPT_fdelayed_template_parsing, - options::OPT_fno_delayed_template_parsing, IsWindowsMSVC)) - CmdArgs.push_back("-fdelayed-template-parsing"); - - // -fgnu-keywords default varies depending on language; only pass if - // specified. - if (Arg *A = Args.getLastArg(options::OPT_fgnu_keywords, - options::OPT_fno_gnu_keywords)) - A->render(Args, CmdArgs); - - if (Args.hasFlag(options::OPT_fgnu89_inline, options::OPT_fno_gnu89_inline, - false)) - CmdArgs.push_back("-fgnu89-inline"); - - if (Args.hasArg(options::OPT_fno_inline)) - CmdArgs.push_back("-fno-inline"); - - if (Arg* InlineArg = Args.getLastArg(options::OPT_finline_functions, - options::OPT_finline_hint_functions, - options::OPT_fno_inline_functions)) - InlineArg->render(Args, CmdArgs); - - 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); - } - } - - if (Args.hasFlag(options::OPT_fapplication_extension, - options::OPT_fno_application_extension, false)) - CmdArgs.push_back("-fapplication-extension"); - - // Handle GCC-style exception args. - if (!C.getDriver().IsCLMode()) - addExceptionArgs(Args, InputType, getToolChain(), KernelOrKext, objcRuntime, - CmdArgs); - - if (Args.hasArg(options::OPT_fsjlj_exceptions) || - getToolChain().UseSjLjExceptions(Args)) - CmdArgs.push_back("-fsjlj-exceptions"); - - // C++ "sane" operator new. - if (!Args.hasFlag(options::OPT_fassume_sane_operator_new, - options::OPT_fno_assume_sane_operator_new)) - CmdArgs.push_back("-fno-assume-sane-operator-new"); - - // -frelaxed-template-template-args is off by default, as it is a severe - // breaking change until a corresponding change to template partial ordering - // is provided. - if (Args.hasFlag(options::OPT_frelaxed_template_template_args, - options::OPT_fno_relaxed_template_template_args, false)) - CmdArgs.push_back("-frelaxed-template-template-args"); - - // -fsized-deallocation is off by default, as it is an ABI-breaking change for - // most platforms. - if (Args.hasFlag(options::OPT_fsized_deallocation, - options::OPT_fno_sized_deallocation, false)) - CmdArgs.push_back("-fsized-deallocation"); - - // -faligned-allocation is on by default in C++17 onwards and otherwise off - // by default. - if (Arg *A = Args.getLastArg(options::OPT_faligned_allocation, - options::OPT_fno_aligned_allocation, - options::OPT_faligned_new_EQ)) { - if (A->getOption().matches(options::OPT_fno_aligned_allocation)) - CmdArgs.push_back("-fno-aligned-allocation"); - else - CmdArgs.push_back("-faligned-allocation"); - } - - // The default new alignment can be specified using a dedicated option or via - // a GCC-compatible option that also turns on aligned allocation. - if (Arg *A = Args.getLastArg(options::OPT_fnew_alignment_EQ, - options::OPT_faligned_new_EQ)) - CmdArgs.push_back( - Args.MakeArgString(Twine("-fnew-alignment=") + A->getValue())); - - // -fconstant-cfstrings is default, and may be subject to argument translation - // on Darwin. - if (!Args.hasFlag(options::OPT_fconstant_cfstrings, - options::OPT_fno_constant_cfstrings) || - !Args.hasFlag(options::OPT_mconstant_cfstrings, - 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)) - CmdArgs.push_back("-fpascal-strings"); - - // Honor -fpack-struct= and -fpack-struct, if given. Note that - // -fno-pack-struct doesn't apply to -fpack-struct=. - if (Arg *A = Args.getLastArg(options::OPT_fpack_struct_EQ)) { - std::string PackStructStr = "-fpack-struct="; - PackStructStr += A->getValue(); - CmdArgs.push_back(Args.MakeArgString(PackStructStr)); - } else if (Args.hasFlag(options::OPT_fpack_struct, - options::OPT_fno_pack_struct, false)) { - CmdArgs.push_back("-fpack-struct=1"); - } - - // Handle -fmax-type-align=N and -fno-type-align - bool SkipMaxTypeAlign = Args.hasArg(options::OPT_fno_max_type_align); - if (Arg *A = Args.getLastArg(options::OPT_fmax_type_align_EQ)) { - if (!SkipMaxTypeAlign) { - std::string MaxTypeAlignStr = "-fmax-type-align="; - MaxTypeAlignStr += A->getValue(); - CmdArgs.push_back(Args.MakeArgString(MaxTypeAlignStr)); - } - } else if (getToolChain().getTriple().isOSDarwin()) { - if (!SkipMaxTypeAlign) { - std::string MaxTypeAlignStr = "-fmax-type-align=16"; - CmdArgs.push_back(Args.MakeArgString(MaxTypeAlignStr)); - } - } - - // -fcommon is the default unless compiling kernel code or the target says so - bool NoCommonDefault = - KernelOrKext || isNoCommonDefault(getToolChain().getTriple()); - if (!Args.hasFlag(options::OPT_fcommon, options::OPT_fno_common, - !NoCommonDefault)) - CmdArgs.push_back("-fno-common"); - - // -fsigned-bitfields is default, and clang doesn't yet support - // -funsigned-bitfields. - if (!Args.hasFlag(options::OPT_fsigned_bitfields, - options::OPT_funsigned_bitfields)) - D.Diag(diag::warn_drv_clang_unsupported) - << Args.getLastArg(options::OPT_funsigned_bitfields)->getAsString(Args); - - // -fsigned-bitfields is default, and clang doesn't support -fno-for-scope. - if (!Args.hasFlag(options::OPT_ffor_scope, options::OPT_fno_for_scope)) - D.Diag(diag::err_drv_clang_unsupported) - << Args.getLastArg(options::OPT_fno_for_scope)->getAsString(Args); - - // -finput_charset=UTF-8 is default. Reject others - if (Arg *inputCharset = Args.getLastArg(options::OPT_finput_charset_EQ)) { - StringRef value = inputCharset->getValue(); - if (!value.equals_lower("utf-8")) - D.Diag(diag::err_drv_invalid_value) << inputCharset->getAsString(Args) - << value; - } - - // -fexec_charset=UTF-8 is default. Reject others - if (Arg *execCharset = Args.getLastArg(options::OPT_fexec_charset_EQ)) { - StringRef value = execCharset->getValue(); - if (!value.equals_lower("utf-8")) - D.Diag(diag::err_drv_invalid_value) << execCharset->getAsString(Args) - << value; - } - - // -fcaret-diagnostics is default. - if (!Args.hasFlag(options::OPT_fcaret_diagnostics, - options::OPT_fno_caret_diagnostics, true)) - 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_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, - true)) - CmdArgs.push_back("-fno-show-column"); - - if (!Args.hasFlag(options::OPT_fspell_checking, - options::OPT_fno_spell_checking)) - CmdArgs.push_back("-fno-spell-checking"); - - // -fno-asm-blocks is default. - if (Args.hasFlag(options::OPT_fasm_blocks, options::OPT_fno_asm_blocks, - false)) - CmdArgs.push_back("-fasm-blocks"); - - // -fgnu-inline-asm is default. - if (!Args.hasFlag(options::OPT_fgnu_inline_asm, - options::OPT_fno_gnu_inline_asm, true)) - CmdArgs.push_back("-fno-gnu-inline-asm"); - - // Enable vectorization per default according to the optimization level - // selected. For optimization levels that want vectorization we use the alias - // option to simplify the hasFlag logic. - bool EnableVec = shouldEnableVectorizerAtOLevel(Args, false); - OptSpecifier VectorizeAliasOption = - EnableVec ? options::OPT_O_Group : options::OPT_fvectorize; - if (Args.hasFlag(options::OPT_fvectorize, VectorizeAliasOption, - options::OPT_fno_vectorize, EnableVec)) - CmdArgs.push_back("-vectorize-loops"); - - // -fslp-vectorize is enabled based on the optimization level selected. - bool EnableSLPVec = shouldEnableVectorizerAtOLevel(Args, true); - OptSpecifier SLPVectAliasOption = - EnableSLPVec ? options::OPT_O_Group : options::OPT_fslp_vectorize; - if (Args.hasFlag(options::OPT_fslp_vectorize, SLPVectAliasOption, - options::OPT_fno_slp_vectorize, EnableSLPVec)) - CmdArgs.push_back("-vectorize-slp"); - - // -fno-slp-vectorize-aggressive is default. - if (Args.hasFlag(options::OPT_fslp_vectorize_aggressive, - options::OPT_fno_slp_vectorize_aggressive, false)) - CmdArgs.push_back("-vectorize-slp-aggressive"); - - if (Arg *A = Args.getLastArg(options::OPT_fshow_overloads_EQ)) - A->render(Args, CmdArgs); - - if (Arg *A = Args.getLastArg( - options::OPT_fsanitize_undefined_strip_path_components_EQ)) - A->render(Args, CmdArgs); - - // -fdollars-in-identifiers default varies depending on platform and - // language; only pass if specified. - if (Arg *A = Args.getLastArg(options::OPT_fdollars_in_identifiers, - options::OPT_fno_dollars_in_identifiers)) { - if (A->getOption().matches(options::OPT_fdollars_in_identifiers)) - CmdArgs.push_back("-fdollars-in-identifiers"); - else - CmdArgs.push_back("-fno-dollars-in-identifiers"); - } - - // -funit-at-a-time is default, and we don't support -fno-unit-at-a-time for - // practical purposes. - if (Arg *A = Args.getLastArg(options::OPT_funit_at_a_time, - options::OPT_fno_unit_at_a_time)) { - if (A->getOption().matches(options::OPT_fno_unit_at_a_time)) - D.Diag(diag::warn_drv_clang_unsupported) << A->getAsString(Args); - } - - if (Args.hasFlag(options::OPT_fapple_pragma_pack, - 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"); - - const Arg *A = Args.getLastArg(options::OPT_foptimization_record_file_EQ); - if (A) { - 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 { - // Use the input filename. - F = llvm::sys::path::stem(Input.getBaseInput()); - - // If we're compiling for an offload architecture (i.e. a CUDA device), - // we need to make the file name for the device compilation different - // from the host compilation. - if (!JA.isDeviceOffloading(Action::OFK_None) && - !JA.isDeviceOffloading(Action::OFK_Host)) { - llvm::sys::path::replace_extension(F, ""); - F += Action::GetOffloadingFileNamePrefix(JA.getOffloadingDeviceKind(), - Triple.normalize()); - F += "-"; - F += JA.getOffloadingArch(); - } - } - - llvm::sys::path::replace_extension(F, "opt.yaml"); - CmdArgs.push_back(Args.MakeArgString(F)); - } - } - -// 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 - - // Enable rewrite includes if the user's asked for it or if we're generating - // diagnostics. - // TODO: Once -module-dependency-dir works with -frewrite-includes it'd be - // 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() && !HaveAnyModules)) - CmdArgs.push_back("-frewrite-includes"); - - // Only allow -traditional or -traditional-cpp outside in preprocessing modes. - if (Arg *A = Args.getLastArg(options::OPT_traditional, - options::OPT_traditional_cpp)) { - if (isa<PreprocessJobAction>(JA)) - CmdArgs.push_back("-traditional-cpp"); - else - D.Diag(diag::err_drv_clang_unsupported) << A->getAsString(Args); - } - - Args.AddLastArg(CmdArgs, options::OPT_dM); - Args.AddLastArg(CmdArgs, options::OPT_dD); - - // Handle serialized diagnostics. - if (Arg *A = Args.getLastArg(options::OPT__serialize_diags)) { - CmdArgs.push_back("-serialize-diagnostic-file"); - CmdArgs.push_back(Args.MakeArgString(A->getValue())); - } - - if (Args.hasArg(options::OPT_fretain_comments_from_system_headers)) - CmdArgs.push_back("-fretain-comments-from-system-headers"); - - // Forward -fcomment-block-commands to -cc1. - Args.AddAllArgs(CmdArgs, options::OPT_fcomment_block_commands); - // Forward -fparse-all-comments to -cc1. - Args.AddAllArgs(CmdArgs, options::OPT_fparse_all_comments); - - // Turn -fplugin=name.so into -load name.so - for (const Arg *A : Args.filtered(options::OPT_fplugin_EQ)) { - CmdArgs.push_back("-load"); - CmdArgs.push_back(A->getValue()); - A->claim(); - } - - // Setup statistics file output. - if (const Arg *A = Args.getLastArg(options::OPT_save_stats_EQ)) { - StringRef SaveStats = A->getValue(); - - SmallString<128> StatsFile; - bool DoSaveStats = false; - if (SaveStats == "obj") { - if (Output.isFilename()) { - StatsFile.assign(Output.getFilename()); - llvm::sys::path::remove_filename(StatsFile); - } - DoSaveStats = true; - } else if (SaveStats == "cwd") { - DoSaveStats = true; - } else { - D.Diag(diag::err_drv_invalid_value) << A->getAsString(Args) << SaveStats; - } - - if (DoSaveStats) { - StringRef BaseName = llvm::sys::path::filename(Input.getBaseInput()); - llvm::sys::path::append(StatsFile, BaseName); - llvm::sys::path::replace_extension(StatsFile, "stats"); - CmdArgs.push_back(Args.MakeArgString(Twine("-stats-file=") + - StatsFile)); - } - } - - // Forward -Xclang arguments to -cc1, and -mllvm arguments to the LLVM option - // parser. - Args.AddAllArgValues(CmdArgs, options::OPT_Xclang); - for (const Arg *A : Args.filtered(options::OPT_mllvm)) { - A->claim(); - - // We translate this by hand to the -cc1 argument, since nightly test uses - // it and developers have been trained to spell it with -mllvm. Both - // spellings are now deprecated and should be removed. - if (StringRef(A->getValue(0)) == "-disable-llvm-optzns") { - CmdArgs.push_back("-disable-llvm-optzns"); - } else { - A->render(Args, CmdArgs); - } - } - - // With -save-temps, we want to save the unoptimized bitcode output from the - // CompileJobAction, use -disable-llvm-passes to get pristine IR generated - // by the frontend. - // When -fembed-bitcode is enabled, optimized bitcode is emitted because it - // has slightly different breakdown between stages. - // FIXME: -fembed-bitcode -save-temps will save optimized bitcode instead of - // pristine IR generated by the frontend. Ideally, a new compile action should - // be added so both IR can be captured. - if (C.getDriver().isSaveTempsEnabled() && - !(C.getDriver().embedBitcodeInObject() && !C.getDriver().isUsingLTO()) && - isa<CompileJobAction>(JA)) - CmdArgs.push_back("-disable-llvm-passes"); - - if (Output.getType() == types::TY_Dependencies) { - // Handled with other dependency code. - } else if (Output.isFilename()) { - CmdArgs.push_back("-o"); - CmdArgs.push_back(Output.getFilename()); - } else { - assert(Output.isNothing() && "Invalid output."); - } - - addDashXForInput(Args, Input, CmdArgs); - - if (Input.isFilename()) - CmdArgs.push_back(Input.getFilename()); - else - Input.getInputArg().renderAsInput(Args, CmdArgs); - - Args.AddAllArgs(CmdArgs, options::OPT_undef); - - const char *Exec = getToolChain().getDriver().getClangProgramPath(); - - // Optionally embed the -cc1 level arguments into the debug info, for build - // analysis. - if (getToolChain().UseDwarfDebugFlags()) { - ArgStringList OriginalArgs; - for (const auto &Arg : Args) - Arg->render(Args, OriginalArgs); - - SmallString<256> Flags; - Flags += Exec; - for (const char *OriginalArg : OriginalArgs) { - SmallString<128> EscapedArg; - EscapeSpacesAndBackslashes(OriginalArg, EscapedArg); - Flags += " "; - Flags += EscapedArg; - } - CmdArgs.push_back("-dwarf-debug-flags"); - 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) - for (auto I = std::next(Inputs.begin()), E = Inputs.end(); I != E; ++I) { - CmdArgs.push_back("-fcuda-include-gpubinary"); - CmdArgs.push_back(I->getFilename()); - } - - // OpenMP offloading device jobs take the argument -fopenmp-host-ir-file-path - // to specify the result of the compile phase on the host, so the meaningful - // device declarations can be identified. Also, -fopenmp-is-device is passed - // along to tell the frontend that it is generating code for a device, so that - // only the relevant declarations are emitted. - if (IsOpenMPDevice && Inputs.size() == 2) { - CmdArgs.push_back("-fopenmp-is-device"); - CmdArgs.push_back("-fopenmp-host-ir-file-path"); - CmdArgs.push_back(Args.MakeArgString(Inputs.back().getFilename())); - } - - // For all the host OpenMP offloading compile jobs we need to pass the targets - // information using -fopenmp-targets= option. - if (isa<CompileJobAction>(JA) && JA.isHostOffloading(Action::OFK_OpenMP)) { - SmallString<128> TargetInfo("-fopenmp-targets="); - - Arg *Tgts = Args.getLastArg(options::OPT_fopenmp_targets_EQ); - assert(Tgts && Tgts->getNumValues() && - "OpenMP offloading has to have targets specified."); - for (unsigned i = 0; i < Tgts->getNumValues(); ++i) { - if (i) - TargetInfo += ','; - // We need to get the string from the triple because it may be not exactly - // the same as the one we get directly from the arguments. - llvm::Triple T(Tgts->getValue(i)); - TargetInfo += T.getTriple(); - } - CmdArgs.push_back(Args.MakeArgString(TargetInfo.str())); - } - - bool WholeProgramVTables = - Args.hasFlag(options::OPT_fwhole_program_vtables, - options::OPT_fno_whole_program_vtables, false); - if (WholeProgramVTables) { - if (!D.isUsingLTO()) - D.Diag(diag::err_drv_argument_only_allowed_with) - << "-fwhole-program-vtables" - << "-flto"; - CmdArgs.push_back("-fwhole-program-vtables"); - } - - // Finally add the compile command to the compilation. - if (Args.hasArg(options::OPT__SLASH_fallback) && - Output.getType() == types::TY_Object && - (InputType == types::TY_C || InputType == types::TY_CXX)) { - auto CLCommand = - getCLFallback()->GetCommand(C, JA, Output, Inputs, Args, LinkingOutput); - C.addCommand(llvm::make_unique<FallbackCommand>( - JA, *this, Exec, CmdArgs, Inputs, std::move(CLCommand))); - } else if (Args.hasArg(options::OPT__SLASH_fallback) && - isa<PrecompileJobAction>(JA)) { - // In /fallback builds, run the main compilation even if the pch generation - // fails, so that the main compilation's fallback to cl.exe runs. - C.addCommand(llvm::make_unique<ForceSuccessCommand>(JA, *this, Exec, - CmdArgs, Inputs)); - } else { - C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); - } - - // Handle the debug info splitting at object creation time if we're - // creating an object. - // TODO: Currently only works on linux with newer objcopy. - if (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)) - D.Diag(diag::err_drv_argument_not_allowed_with) << "-fomit-frame-pointer" - << A->getAsString(Args); - - // Claim some arguments which clang supports automatically. - - // -fpch-preprocess is used with gcc to add a special marker in the output to - // include the PCH file. Clang's PTH solution is completely transparent, so we - // do not need to deal with it at all. - Args.ClaimAllArgs(options::OPT_fpch_preprocess); - - // Claim some arguments which clang doesn't support, but we don't - // care to warn the user about. - Args.ClaimAllArgs(options::OPT_clang_ignored_f_Group); - Args.ClaimAllArgs(options::OPT_clang_ignored_m_Group); - - // Disable warnings for clang -E -emit-llvm foo.c - Args.ClaimAllArgs(options::OPT_emit_llvm); -} - -/// Add options related to the Objective-C runtime/ABI. -/// -/// Returns true if the runtime is non-fragile. -ObjCRuntime Clang::AddObjCRuntimeArgs(const ArgList &args, - ArgStringList &cmdArgs, - RewriteKind rewriteKind) const { - // Look for the controlling runtime option. - Arg *runtimeArg = - args.getLastArg(options::OPT_fnext_runtime, options::OPT_fgnu_runtime, - options::OPT_fobjc_runtime_EQ); - - // Just forward -fobjc-runtime= to the frontend. This supercedes - // options about fragility. - if (runtimeArg && - runtimeArg->getOption().matches(options::OPT_fobjc_runtime_EQ)) { - ObjCRuntime runtime; - StringRef value = runtimeArg->getValue(); - if (runtime.tryParse(value)) { - getToolChain().getDriver().Diag(diag::err_drv_unknown_objc_runtime) - << value; - } - - runtimeArg->render(args, cmdArgs); - return runtime; - } - - // Otherwise, we'll need the ABI "version". Version numbers are - // slightly confusing for historical reasons: - // 1 - Traditional "fragile" ABI - // 2 - Non-fragile ABI, version 1 - // 3 - Non-fragile ABI, version 2 - unsigned objcABIVersion = 1; - // If -fobjc-abi-version= is present, use that to set the version. - if (Arg *abiArg = args.getLastArg(options::OPT_fobjc_abi_version_EQ)) { - StringRef value = abiArg->getValue(); - if (value == "1") - objcABIVersion = 1; - else if (value == "2") - objcABIVersion = 2; - else if (value == "3") - objcABIVersion = 3; - else - getToolChain().getDriver().Diag(diag::err_drv_clang_unsupported) << value; - } else { - // Otherwise, determine if we are using the non-fragile ABI. - bool nonFragileABIIsDefault = - (rewriteKind == RK_NonFragile || - (rewriteKind == RK_None && - getToolChain().IsObjCNonFragileABIDefault())); - if (args.hasFlag(options::OPT_fobjc_nonfragile_abi, - options::OPT_fno_objc_nonfragile_abi, - nonFragileABIIsDefault)) { -// Determine the non-fragile ABI version to use. -#ifdef DISABLE_DEFAULT_NONFRAGILEABI_TWO - unsigned nonFragileABIVersion = 1; -#else - unsigned nonFragileABIVersion = 2; -#endif - - if (Arg *abiArg = - args.getLastArg(options::OPT_fobjc_nonfragile_abi_version_EQ)) { - StringRef value = abiArg->getValue(); - if (value == "1") - nonFragileABIVersion = 1; - else if (value == "2") - nonFragileABIVersion = 2; - else - getToolChain().getDriver().Diag(diag::err_drv_clang_unsupported) - << value; - } - - objcABIVersion = 1 + nonFragileABIVersion; - } else { - objcABIVersion = 1; - } - } - - // We don't actually care about the ABI version other than whether - // it's non-fragile. - bool isNonFragile = objcABIVersion != 1; - - // If we have no runtime argument, ask the toolchain for its default runtime. - // However, the rewriter only really supports the Mac runtime, so assume that. - ObjCRuntime runtime; - if (!runtimeArg) { - switch (rewriteKind) { - case RK_None: - runtime = getToolChain().getDefaultObjCRuntime(isNonFragile); - break; - case RK_Fragile: - runtime = ObjCRuntime(ObjCRuntime::FragileMacOSX, VersionTuple()); - break; - case RK_NonFragile: - runtime = ObjCRuntime(ObjCRuntime::MacOSX, VersionTuple()); - break; - } - - // -fnext-runtime - } else if (runtimeArg->getOption().matches(options::OPT_fnext_runtime)) { - // On Darwin, make this use the default behavior for the toolchain. - if (getToolChain().getTriple().isOSDarwin()) { - runtime = getToolChain().getDefaultObjCRuntime(isNonFragile); - - // Otherwise, build for a generic macosx port. - } else { - runtime = ObjCRuntime(ObjCRuntime::MacOSX, VersionTuple()); - } - - // -fgnu-runtime - } else { - assert(runtimeArg->getOption().matches(options::OPT_fgnu_runtime)); - // Legacy behaviour is to target the gnustep runtime if we are in - // non-fragile mode or the GCC runtime in fragile mode. - if (isNonFragile) - runtime = ObjCRuntime(ObjCRuntime::GNUstep, VersionTuple(1, 6)); - else - runtime = ObjCRuntime(ObjCRuntime::GCC, VersionTuple()); - } - - cmdArgs.push_back( - args.MakeArgString("-fobjc-runtime=" + runtime.getAsString())); - return runtime; -} - -static bool maybeConsumeDash(const std::string &EH, size_t &I) { - bool HaveDash = (I + 1 < EH.size() && EH[I + 1] == '-'); - I += HaveDash; - return !HaveDash; -} - -namespace { -struct EHFlags { - bool Synch = false; - bool Asynch = false; - bool NoUnwindC = false; -}; -} // end anonymous namespace - -/// /EH controls whether to run destructor cleanups when exceptions are -/// thrown. There are three modifiers: -/// - s: Cleanup after "synchronous" exceptions, aka C++ exceptions. -/// - a: Cleanup after "asynchronous" exceptions, aka structured exceptions. -/// The 'a' modifier is unimplemented and fundamentally hard in LLVM IR. -/// - c: Assume that extern "C" functions are implicitly nounwind. -/// The default is /EHs-c-, meaning cleanups are disabled. -static EHFlags parseClangCLEHFlags(const Driver &D, const ArgList &Args) { - EHFlags EH; - - std::vector<std::string> EHArgs = - Args.getAllArgValues(options::OPT__SLASH_EH); - for (auto EHVal : EHArgs) { - for (size_t I = 0, E = EHVal.size(); I != E; ++I) { - switch (EHVal[I]) { - case 'a': - EH.Asynch = maybeConsumeDash(EHVal, I); - if (EH.Asynch) - EH.Synch = false; - continue; - case 'c': - EH.NoUnwindC = maybeConsumeDash(EHVal, I); - continue; - case 's': - EH.Synch = maybeConsumeDash(EHVal, I); - if (EH.Synch) - EH.Asynch = false; - continue; - default: - break; - } - D.Diag(clang::diag::err_drv_invalid_value) << "/EH" << EHVal; - break; - } - } - // The /GX, /GX- flags are only processed if there are not /EH flags. - // The default is that /GX is not specified. - if (EHArgs.empty() && - Args.hasFlag(options::OPT__SLASH_GX, options::OPT__SLASH_GX_, - /*default=*/false)) { - EH.Synch = true; - EH.NoUnwindC = true; - } - - return EH; -} - -void Clang::AddClangCLArgs(const ArgList &Args, types::ID InputType, - ArgStringList &CmdArgs, - codegenoptions::DebugInfoKind *DebugInfoKind, - bool *EmitCodeView) const { - unsigned RTOptionID = options::OPT__SLASH_MT; - - if (Args.hasArg(options::OPT__SLASH_LDd)) - // The /LDd option implies /MTd. The dependent lib part can be overridden, - // but defining _DEBUG is sticky. - RTOptionID = options::OPT__SLASH_MTd; - - if (Arg *A = Args.getLastArg(options::OPT__SLASH_M_Group)) - RTOptionID = A->getOption().getID(); - - StringRef FlagForCRT; - switch (RTOptionID) { - case options::OPT__SLASH_MD: - if (Args.hasArg(options::OPT__SLASH_LDd)) - CmdArgs.push_back("-D_DEBUG"); - CmdArgs.push_back("-D_MT"); - CmdArgs.push_back("-D_DLL"); - FlagForCRT = "--dependent-lib=msvcrt"; - break; - case options::OPT__SLASH_MDd: - CmdArgs.push_back("-D_DEBUG"); - CmdArgs.push_back("-D_MT"); - CmdArgs.push_back("-D_DLL"); - FlagForCRT = "--dependent-lib=msvcrtd"; - break; - case options::OPT__SLASH_MT: - if (Args.hasArg(options::OPT__SLASH_LDd)) - CmdArgs.push_back("-D_DEBUG"); - CmdArgs.push_back("-D_MT"); - CmdArgs.push_back("-flto-visibility-public-std"); - FlagForCRT = "--dependent-lib=libcmt"; - break; - case options::OPT__SLASH_MTd: - CmdArgs.push_back("-D_DEBUG"); - CmdArgs.push_back("-D_MT"); - CmdArgs.push_back("-flto-visibility-public-std"); - FlagForCRT = "--dependent-lib=libcmtd"; - break; - default: - llvm_unreachable("Unexpected option ID."); - } - - if (Args.hasArg(options::OPT__SLASH_Zl)) { - CmdArgs.push_back("-D_VC_NODEFAULTLIB"); - } else { - CmdArgs.push_back(FlagForCRT.data()); - - // This provides POSIX compatibility (maps 'open' to '_open'), which most - // users want. The /Za flag to cl.exe turns this off, but it's not - // implemented in clang. - CmdArgs.push_back("--dependent-lib=oldnames"); - } - - // 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 (Arg *A = Args.getLastArg(options::OPT_show_includes)) - A->render(Args, CmdArgs); - - // This controls whether or not we emit RTTI data for polymorphic types. - if (Args.hasFlag(options::OPT__SLASH_GR_, options::OPT__SLASH_GR, - /*default=*/false)) - CmdArgs.push_back("-fno-rtti-data"); - - // This controls whether or not we emit stack-protector instrumentation. - // In MSVC, Buffer Security Check (/GS) is on by default. - if (Args.hasFlag(options::OPT__SLASH_GS, options::OPT__SLASH_GS_, - /*default=*/true)) { - CmdArgs.push_back("-stack-protector"); - CmdArgs.push_back(Args.MakeArgString(Twine(LangOptions::SSPStrong))); - } - - // Emit CodeView if -Z7, -Zd, or -gline-tables-only are present. - if (Arg *DebugInfoArg = - Args.getLastArg(options::OPT__SLASH_Z7, options::OPT__SLASH_Zd, - options::OPT_gline_tables_only)) { - *EmitCodeView = true; - if (DebugInfoArg->getOption().matches(options::OPT__SLASH_Z7)) - *DebugInfoKind = codegenoptions::LimitedDebugInfo; - else - *DebugInfoKind = codegenoptions::DebugLineTablesOnly; - CmdArgs.push_back("-gcodeview"); - } else { - *EmitCodeView = false; - } - - const Driver &D = getToolChain().getDriver(); - EHFlags EH = parseClangCLEHFlags(D, Args); - if (EH.Synch || EH.Asynch) { - if (types::isCXX(InputType)) - CmdArgs.push_back("-fcxx-exceptions"); - CmdArgs.push_back("-fexceptions"); - } - if (types::isCXX(InputType) && EH.Synch && EH.NoUnwindC) - CmdArgs.push_back("-fexternc-nounwind"); - - // /EP should expand to -E -P. - if (Args.hasArg(options::OPT__SLASH_EP)) { - CmdArgs.push_back("-E"); - CmdArgs.push_back("-P"); - } - - unsigned VolatileOptionID; - if (getToolChain().getArch() == llvm::Triple::x86_64 || - getToolChain().getArch() == llvm::Triple::x86) - VolatileOptionID = options::OPT__SLASH_volatile_ms; - else - VolatileOptionID = options::OPT__SLASH_volatile_iso; - - if (Arg *A = Args.getLastArg(options::OPT__SLASH_volatile_Group)) - VolatileOptionID = A->getOption().getID(); - - if (VolatileOptionID == options::OPT__SLASH_volatile_ms) - CmdArgs.push_back("-fms-volatile"); - - Arg *MostGeneralArg = Args.getLastArg(options::OPT__SLASH_vmg); - Arg *BestCaseArg = Args.getLastArg(options::OPT__SLASH_vmb); - if (MostGeneralArg && BestCaseArg) - D.Diag(clang::diag::err_drv_argument_not_allowed_with) - << MostGeneralArg->getAsString(Args) << BestCaseArg->getAsString(Args); - - if (MostGeneralArg) { - Arg *SingleArg = Args.getLastArg(options::OPT__SLASH_vms); - Arg *MultipleArg = Args.getLastArg(options::OPT__SLASH_vmm); - Arg *VirtualArg = Args.getLastArg(options::OPT__SLASH_vmv); - - Arg *FirstConflict = SingleArg ? SingleArg : MultipleArg; - Arg *SecondConflict = VirtualArg ? VirtualArg : MultipleArg; - if (FirstConflict && SecondConflict && FirstConflict != SecondConflict) - D.Diag(clang::diag::err_drv_argument_not_allowed_with) - << FirstConflict->getAsString(Args) - << SecondConflict->getAsString(Args); - - if (SingleArg) - CmdArgs.push_back("-fms-memptr-rep=single"); - else if (MultipleArg) - CmdArgs.push_back("-fms-memptr-rep=multiple"); - else - CmdArgs.push_back("-fms-memptr-rep=virtual"); - } - - if (Args.getLastArg(options::OPT__SLASH_Gd)) - CmdArgs.push_back("-fdefault-calling-conv=cdecl"); - else if (Args.getLastArg(options::OPT__SLASH_Gr)) - CmdArgs.push_back("-fdefault-calling-conv=fastcall"); - else if (Args.getLastArg(options::OPT__SLASH_Gz)) - CmdArgs.push_back("-fdefault-calling-conv=stdcall"); - else if (Args.getLastArg(options::OPT__SLASH_Gv)) - CmdArgs.push_back("-fdefault-calling-conv=vectorcall"); - - if (Arg *A = Args.getLastArg(options::OPT_vtordisp_mode_EQ)) - A->render(Args, CmdArgs); - - if (!Args.hasArg(options::OPT_fdiagnostics_format_EQ)) { - CmdArgs.push_back("-fdiagnostics-format"); - if (Args.hasArg(options::OPT__SLASH_fallback)) - CmdArgs.push_back("msvc-fallback"); - else - CmdArgs.push_back("msvc"); - } -} - -visualstudio::Compiler *Clang::getCLFallback() const { - if (!CLFallback) - CLFallback.reset(new visualstudio::Compiler(getToolChain())); - return CLFallback.get(); -} - -void ClangAs::AddMIPSTargetArgs(const ArgList &Args, - ArgStringList &CmdArgs) const { - StringRef CPUName; - StringRef ABIName; - const llvm::Triple &Triple = getToolChain().getTriple(); - mips::getMipsCPUAndABI(Args, Triple, CPUName, ABIName); - - CmdArgs.push_back("-target-abi"); - CmdArgs.push_back(ABIName.data()); -} - -void ClangAs::AddX86TargetArgs(const ArgList &Args, - ArgStringList &CmdArgs) const { - if (Arg *A = Args.getLastArg(options::OPT_masm_EQ)) { - StringRef Value = A->getValue(); - if (Value == "intel" || Value == "att") { - CmdArgs.push_back("-mllvm"); - CmdArgs.push_back(Args.MakeArgString("-x86-asm-syntax=" + Value)); - } else { - getToolChain().getDriver().Diag(diag::err_drv_unsupported_option_argument) - << A->getOption().getName() << Value; - } - } -} - -void ClangAs::ConstructJob(Compilation &C, const JobAction &JA, - const InputInfo &Output, const InputInfoList &Inputs, - const ArgList &Args, - const char *LinkingOutput) const { - ArgStringList CmdArgs; - - assert(Inputs.size() == 1 && "Unexpected number of inputs."); - const InputInfo &Input = Inputs[0]; - - const llvm::Triple &Triple = getToolChain().getEffectiveTriple(); - const std::string &TripleStr = Triple.getTriple(); - - // Don't warn about "clang -w -c foo.s" - Args.ClaimAllArgs(options::OPT_w); - // and "clang -emit-llvm -c foo.s" - Args.ClaimAllArgs(options::OPT_emit_llvm); - - claimNoWarnArgs(Args); - - // Invoke ourselves in -cc1as mode. - // - // FIXME: Implement custom jobs for internal actions. - CmdArgs.push_back("-cc1as"); - - // Add the "effective" target triple. - CmdArgs.push_back("-triple"); - CmdArgs.push_back(Args.MakeArgString(TripleStr)); - - // Set the output mode, we currently only expect to be used as a real - // assembler. - CmdArgs.push_back("-filetype"); - CmdArgs.push_back("obj"); - - // Set the main file name, so that debug info works even with - // -save-temps or preprocessed assembly. - CmdArgs.push_back("-main-file-name"); - CmdArgs.push_back(Clang::getBaseInputName(Args, Input)); - - // Add the target cpu - std::string CPU = getCPUName(Args, Triple, /*FromAs*/ true); - if (!CPU.empty()) { - CmdArgs.push_back("-target-cpu"); - CmdArgs.push_back(Args.MakeArgString(CPU)); - } - - // Add the target features - getTargetFeatures(getToolChain(), Triple, Args, CmdArgs, true); - - // Ignore explicit -force_cpusubtype_ALL option. - (void)Args.hasArg(options::OPT_force__cpusubtype__ALL); - - // Pass along any -I options so we get proper .include search paths. - Args.AddAllArgs(CmdArgs, options::OPT_I_Group); - - // Determine the original source input. - const Action *SourceAction = &JA; - while (SourceAction->getKind() != Action::InputClass) { - assert(!SourceAction->getInputs().empty() && "unexpected root action!"); - SourceAction = SourceAction->getInputs()[0]; - } - - // Forward -g and handle debug info related flags, assuming we are dealing - // with an actual assembly file. - bool WantDebug = false; - unsigned DwarfVersion = 0; - Args.ClaimAllArgs(options::OPT_g_Group); - if (Arg *A = Args.getLastArg(options::OPT_g_Group)) { - WantDebug = !A->getOption().matches(options::OPT_g0) && - !A->getOption().matches(options::OPT_ggdb0); - if (WantDebug) - DwarfVersion = DwarfVersionNum(A->getSpelling()); - } - if (DwarfVersion == 0) - DwarfVersion = getToolChain().GetDefaultDwarfVersion(); - - codegenoptions::DebugInfoKind DebugInfoKind = codegenoptions::NoDebugInfo; - - if (SourceAction->getType() == types::TY_Asm || - SourceAction->getType() == types::TY_PP_Asm) { - // You might think that it would be ok to set DebugInfoKind outside of - // the guard for source type, however there is a test which asserts - // that some assembler invocation receives no -debug-info-kind, - // and it's not clear whether that test is just overly restrictive. - DebugInfoKind = (WantDebug ? codegenoptions::LimitedDebugInfo - : codegenoptions::NoDebugInfo); - // Add the -fdebug-compilation-dir flag if needed. - addDebugCompDirArg(Args, CmdArgs); - - // Set the AT_producer to the clang version when using the integrated - // assembler on assembly source files. - CmdArgs.push_back("-dwarf-debug-producer"); - CmdArgs.push_back(Args.MakeArgString(getClangFullVersion())); - - // And pass along -I options - Args.AddAllArgs(CmdArgs, options::OPT_I); - } - RenderDebugEnablingArgs(Args, CmdArgs, DebugInfoKind, DwarfVersion, - llvm::DebuggerKind::Default); - - // Handle -fPIC et al -- the relocation-model affects the assembler - // for some targets. - llvm::Reloc::Model RelocationModel; - unsigned PICLevel; - bool IsPIE; - std::tie(RelocationModel, PICLevel, IsPIE) = - ParsePICArgs(getToolChain(), Args); - - const char *RMName = RelocationModelName(RelocationModel); - if (RMName) { - CmdArgs.push_back("-mrelocation-model"); - CmdArgs.push_back(RMName); - } - - // Optionally embed the -cc1as level arguments into the debug info, for build - // analysis. - if (getToolChain().UseDwarfDebugFlags()) { - ArgStringList OriginalArgs; - for (const auto &Arg : Args) - Arg->render(Args, OriginalArgs); - - SmallString<256> Flags; - const char *Exec = getToolChain().getDriver().getClangProgramPath(); - Flags += Exec; - for (const char *OriginalArg : OriginalArgs) { - SmallString<128> EscapedArg; - EscapeSpacesAndBackslashes(OriginalArg, EscapedArg); - Flags += " "; - Flags += EscapedArg; - } - CmdArgs.push_back("-dwarf-debug-flags"); - CmdArgs.push_back(Args.MakeArgString(Flags)); - } - - // FIXME: Add -static support, once we have it. - - // Add target specific flags. - switch (getToolChain().getArch()) { - default: - break; - - case llvm::Triple::mips: - case llvm::Triple::mipsel: - case llvm::Triple::mips64: - case llvm::Triple::mips64el: - AddMIPSTargetArgs(Args, CmdArgs); - break; - - case llvm::Triple::x86: - case llvm::Triple::x86_64: - AddX86TargetArgs(Args, CmdArgs); - break; - } - - // Consume all the warning flags. Usually this would be handled more - // gracefully by -cc1 (warning about unknown warning flags, etc) but -cc1as - // doesn't handle that so rather than warning about unused flags that are - // actually used, we'll lie by omission instead. - // FIXME: Stop lying and consume only the appropriate driver flags - Args.ClaimAllArgs(options::OPT_W_Group); - - CollectArgsForIntegratedAssembler(C, Args, CmdArgs, - getToolChain().getDriver()); - - Args.AddAllArgs(CmdArgs, options::OPT_mllvm); - - assert(Output.isFilename() && "Unexpected lipo output."); - CmdArgs.push_back("-o"); - CmdArgs.push_back(Output.getFilename()); - - assert(Input.isFilename() && "Invalid input."); - CmdArgs.push_back(Input.getFilename()); - - const char *Exec = getToolChain().getDriver().getClangProgramPath(); - C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); - - // Handle the debug info splitting at object creation time if we're - // creating an object. - // TODO: Currently only works on linux with newer objcopy. - if (Args.hasArg(options::OPT_gsplit_dwarf) && - getToolChain().getTriple().isOSLinux()) - SplitDebugInfo(getToolChain(), C, *this, JA, Args, Output, - SplitDebugName(Args, Input)); -} - -void OffloadBundler::ConstructJob(Compilation &C, const JobAction &JA, - const InputInfo &Output, - const InputInfoList &Inputs, - const llvm::opt::ArgList &TCArgs, - const char *LinkingOutput) const { - // The version with only one output is expected to refer to a bundling job. - assert(isa<OffloadBundlingJobAction>(JA) && "Expecting bundling job!"); - - // The bundling command looks like this: - // clang-offload-bundler -type=bc - // -targets=host-triple,openmp-triple1,openmp-triple2 - // -outputs=input_file - // -inputs=unbundle_file_host,unbundle_file_tgt1,unbundle_file_tgt2" - - ArgStringList CmdArgs; - - // Get the type. - CmdArgs.push_back(TCArgs.MakeArgString( - Twine("-type=") + types::getTypeTempSuffix(Output.getType()))); - - assert(JA.getInputs().size() == Inputs.size() && - "Not have inputs for all dependence actions??"); - - // Get the targets. - SmallString<128> Triples; - Triples += "-targets="; - for (unsigned I = 0; I < Inputs.size(); ++I) { - if (I) - Triples += ','; - - Action::OffloadKind CurKind = Action::OFK_Host; - const ToolChain *CurTC = &getToolChain(); - const Action *CurDep = JA.getInputs()[I]; - - if (const auto *OA = dyn_cast<OffloadAction>(CurDep)) { - OA->doOnEachDependence([&](Action *A, const ToolChain *TC, const char *) { - CurKind = A->getOffloadingDeviceKind(); - CurTC = TC; - }); - } - Triples += Action::GetOffloadKindName(CurKind); - Triples += '-'; - Triples += CurTC->getTriple().normalize(); - } - CmdArgs.push_back(TCArgs.MakeArgString(Triples)); - - // Get bundled file command. - CmdArgs.push_back( - TCArgs.MakeArgString(Twine("-outputs=") + Output.getFilename())); - - // Get unbundled files command. - SmallString<128> UB; - UB += "-inputs="; - for (unsigned I = 0; I < Inputs.size(); ++I) { - if (I) - UB += ','; - UB += Inputs[I].getFilename(); - } - CmdArgs.push_back(TCArgs.MakeArgString(UB)); - - // All the inputs are encoded as commands. - C.addCommand(llvm::make_unique<Command>( - JA, *this, - TCArgs.MakeArgString(getToolChain().GetProgramPath(getShortName())), - CmdArgs, None)); -} - -void OffloadBundler::ConstructJobMultipleOutputs( - Compilation &C, const JobAction &JA, const InputInfoList &Outputs, - const InputInfoList &Inputs, const llvm::opt::ArgList &TCArgs, - const char *LinkingOutput) const { - // The version with multiple outputs is expected to refer to a unbundling job. - auto &UA = cast<OffloadUnbundlingJobAction>(JA); - - // The unbundling command looks like this: - // clang-offload-bundler -type=bc - // -targets=host-triple,openmp-triple1,openmp-triple2 - // -inputs=input_file - // -outputs=unbundle_file_host,unbundle_file_tgt1,unbundle_file_tgt2" - // -unbundle - - ArgStringList CmdArgs; - - assert(Inputs.size() == 1 && "Expecting to unbundle a single file!"); - InputInfo Input = Inputs.front(); - - // Get the type. - CmdArgs.push_back(TCArgs.MakeArgString( - Twine("-type=") + types::getTypeTempSuffix(Input.getType()))); - - // Get the targets. - SmallString<128> Triples; - Triples += "-targets="; - auto DepInfo = UA.getDependentActionsInfo(); - for (unsigned I = 0; I < DepInfo.size(); ++I) { - if (I) - Triples += ','; - - auto &Dep = DepInfo[I]; - Triples += Action::GetOffloadKindName(Dep.DependentOffloadKind); - Triples += '-'; - Triples += Dep.DependentToolChain->getTriple().normalize(); - } - - CmdArgs.push_back(TCArgs.MakeArgString(Triples)); - - // Get bundled file command. - CmdArgs.push_back( - TCArgs.MakeArgString(Twine("-inputs=") + Input.getFilename())); - - // Get unbundled files command. - SmallString<128> UB; - UB += "-outputs="; - for (unsigned I = 0; I < Outputs.size(); ++I) { - if (I) - UB += ','; - UB += Outputs[I].getFilename(); - } - CmdArgs.push_back(TCArgs.MakeArgString(UB)); - CmdArgs.push_back("-unbundle"); - - // All the inputs are encoded as commands. - C.addCommand(llvm::make_unique<Command>( - JA, *this, - TCArgs.MakeArgString(getToolChain().GetProgramPath(getShortName())), - CmdArgs, None)); -} - -void GnuTool::anchor() {} - -void gcc::Common::ConstructJob(Compilation &C, const JobAction &JA, - const InputInfo &Output, - const InputInfoList &Inputs, const ArgList &Args, - const char *LinkingOutput) const { - const Driver &D = getToolChain().getDriver(); - ArgStringList CmdArgs; - - for (const auto &A : Args) { - if (forwardToGCC(A->getOption())) { - // It is unfortunate that we have to claim here, as this means - // we will basically never report anything interesting for - // platforms using a generic gcc, even if we are just using gcc - // to get to the assembler. - A->claim(); - - // Don't forward any -g arguments to assembly steps. - if (isa<AssembleJobAction>(JA) && - A->getOption().matches(options::OPT_g_Group)) - continue; - - // Don't forward any -W arguments to assembly and link steps. - if ((isa<AssembleJobAction>(JA) || isa<LinkJobAction>(JA)) && - A->getOption().matches(options::OPT_W_Group)) - continue; - - A->render(Args, CmdArgs); - } - } - - RenderExtraToolArgs(JA, CmdArgs); - - // If using a driver driver, force the arch. - if (getToolChain().getTriple().isOSDarwin()) { - CmdArgs.push_back("-arch"); - CmdArgs.push_back( - Args.MakeArgString(getToolChain().getDefaultUniversalArchName())); - } - - // Try to force gcc to match the tool chain we want, if we recognize - // the arch. - // - // FIXME: The triple class should directly provide the information we want - // here. - switch (getToolChain().getArch()) { - default: - break; - case llvm::Triple::x86: - case llvm::Triple::ppc: - CmdArgs.push_back("-m32"); - break; - case llvm::Triple::x86_64: - case llvm::Triple::ppc64: - case llvm::Triple::ppc64le: - CmdArgs.push_back("-m64"); - break; - case llvm::Triple::sparcel: - CmdArgs.push_back("-EL"); - break; - } - - if (Output.isFilename()) { - CmdArgs.push_back("-o"); - CmdArgs.push_back(Output.getFilename()); - } else { - assert(Output.isNothing() && "Unexpected output"); - CmdArgs.push_back("-fsyntax-only"); - } - - Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler); - - // Only pass -x if gcc will understand it; otherwise hope gcc - // understands the suffix correctly. The main use case this would go - // wrong in is for linker inputs if they happened to have an odd - // suffix; really the only way to get this to happen is a command - // like '-x foobar a.c' which will treat a.c like a linker input. - // - // FIXME: For the linker case specifically, can we safely convert - // inputs into '-Wl,' options? - for (const auto &II : Inputs) { - // Don't try to pass LLVM or AST inputs to a generic gcc. - if (types::isLLVMIR(II.getType())) - D.Diag(diag::err_drv_no_linker_llvm_support) - << getToolChain().getTripleString(); - else if (II.getType() == types::TY_AST) - D.Diag(diag::err_drv_no_ast_support) << getToolChain().getTripleString(); - else if (II.getType() == types::TY_ModuleFile) - D.Diag(diag::err_drv_no_module_support) - << getToolChain().getTripleString(); - - if (types::canTypeBeUserSpecified(II.getType())) { - CmdArgs.push_back("-x"); - CmdArgs.push_back(types::getTypeName(II.getType())); - } - - if (II.isFilename()) - CmdArgs.push_back(II.getFilename()); - else { - const Arg &A = II.getInputArg(); - - // Reverse translate some rewritten options. - if (A.getOption().matches(options::OPT_Z_reserved_lib_stdcxx)) { - CmdArgs.push_back("-lstdc++"); - continue; - } - - // Don't render as input, we need gcc to do the translations. - A.render(Args, CmdArgs); - } - } - - const std::string &customGCCName = D.getCCCGenericGCCName(); - const char *GCCName; - if (!customGCCName.empty()) - GCCName = customGCCName.c_str(); - else if (D.CCCIsCXX()) { - GCCName = "g++"; - } else - GCCName = "gcc"; - - const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath(GCCName)); - C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); -} - -void gcc::Preprocessor::RenderExtraToolArgs(const JobAction &JA, - ArgStringList &CmdArgs) const { - CmdArgs.push_back("-E"); -} - -void gcc::Compiler::RenderExtraToolArgs(const JobAction &JA, - ArgStringList &CmdArgs) const { - const Driver &D = getToolChain().getDriver(); - - switch (JA.getType()) { - // If -flto, etc. are present then make sure not to force assembly output. - case types::TY_LLVM_IR: - case types::TY_LTO_IR: - case types::TY_LLVM_BC: - case types::TY_LTO_BC: - CmdArgs.push_back("-c"); - break; - // We assume we've got an "integrated" assembler in that gcc will produce an - // object file itself. - case types::TY_Object: - CmdArgs.push_back("-c"); - break; - case types::TY_PP_Asm: - CmdArgs.push_back("-S"); - break; - case types::TY_Nothing: - CmdArgs.push_back("-fsyntax-only"); - break; - default: - D.Diag(diag::err_drv_invalid_gcc_output_type) << getTypeName(JA.getType()); - } -} - -void gcc::Linker::RenderExtraToolArgs(const JobAction &JA, - ArgStringList &CmdArgs) const { - // The types are (hopefully) good enough. -} - -// Hexagon tools start. -void hexagon::Assembler::RenderExtraToolArgs(const JobAction &JA, - ArgStringList &CmdArgs) const { -} - -void hexagon::Assembler::ConstructJob(Compilation &C, const JobAction &JA, - const InputInfo &Output, - const InputInfoList &Inputs, - const ArgList &Args, - const char *LinkingOutput) const { - claimNoWarnArgs(Args); - - auto &HTC = static_cast<const toolchains::HexagonToolChain&>(getToolChain()); - const Driver &D = HTC.getDriver(); - ArgStringList CmdArgs; - - std::string MArchString = "-march=hexagon"; - CmdArgs.push_back(Args.MakeArgString(MArchString)); - - RenderExtraToolArgs(JA, CmdArgs); - - std::string AsName = "hexagon-llvm-mc"; - std::string MCpuString = "-mcpu=hexagon" + - toolchains::HexagonToolChain::GetTargetCPUVersion(Args).str(); - CmdArgs.push_back("-filetype=obj"); - CmdArgs.push_back(Args.MakeArgString(MCpuString)); - - if (Output.isFilename()) { - CmdArgs.push_back("-o"); - CmdArgs.push_back(Output.getFilename()); - } else { - assert(Output.isNothing() && "Unexpected output"); - CmdArgs.push_back("-fsyntax-only"); - } - - if (auto G = toolchains::HexagonToolChain::getSmallDataThreshold(Args)) { - std::string N = llvm::utostr(G.getValue()); - CmdArgs.push_back(Args.MakeArgString(std::string("-gpsize=") + N)); - } - - Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler); - - // Only pass -x if gcc will understand it; otherwise hope gcc - // understands the suffix correctly. The main use case this would go - // wrong in is for linker inputs if they happened to have an odd - // suffix; really the only way to get this to happen is a command - // like '-x foobar a.c' which will treat a.c like a linker input. - // - // FIXME: For the linker case specifically, can we safely convert - // inputs into '-Wl,' options? - for (const auto &II : Inputs) { - // Don't try to pass LLVM or AST inputs to a generic gcc. - if (types::isLLVMIR(II.getType())) - D.Diag(clang::diag::err_drv_no_linker_llvm_support) - << HTC.getTripleString(); - else if (II.getType() == types::TY_AST) - D.Diag(clang::diag::err_drv_no_ast_support) - << HTC.getTripleString(); - else if (II.getType() == types::TY_ModuleFile) - D.Diag(diag::err_drv_no_module_support) - << HTC.getTripleString(); - - if (II.isFilename()) - CmdArgs.push_back(II.getFilename()); - else - // Don't render as input, we need gcc to do the translations. - // FIXME: What is this? - II.getInputArg().render(Args, CmdArgs); - } - - auto *Exec = Args.MakeArgString(HTC.GetProgramPath(AsName.c_str())); - C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); -} - -void hexagon::Linker::RenderExtraToolArgs(const JobAction &JA, - ArgStringList &CmdArgs) const { -} - -static void -constructHexagonLinkArgs(Compilation &C, const JobAction &JA, - const toolchains::HexagonToolChain &HTC, - const InputInfo &Output, const InputInfoList &Inputs, - const ArgList &Args, ArgStringList &CmdArgs, - const char *LinkingOutput) { - - const Driver &D = HTC.getDriver(); - - //---------------------------------------------------------------------------- - // - //---------------------------------------------------------------------------- - bool IsStatic = Args.hasArg(options::OPT_static); - bool IsShared = Args.hasArg(options::OPT_shared); - bool IsPIE = Args.hasArg(options::OPT_pie); - bool IncStdLib = !Args.hasArg(options::OPT_nostdlib); - bool IncStartFiles = !Args.hasArg(options::OPT_nostartfiles); - bool IncDefLibs = !Args.hasArg(options::OPT_nodefaultlibs); - bool UseG0 = false; - bool UseShared = IsShared && !IsStatic; - - //---------------------------------------------------------------------------- - // Silence warnings for various options - //---------------------------------------------------------------------------- - Args.ClaimAllArgs(options::OPT_g_Group); - Args.ClaimAllArgs(options::OPT_emit_llvm); - Args.ClaimAllArgs(options::OPT_w); // Other warning options are already - // handled somewhere else. - Args.ClaimAllArgs(options::OPT_static_libgcc); - - //---------------------------------------------------------------------------- - // - //---------------------------------------------------------------------------- - if (Args.hasArg(options::OPT_s)) - CmdArgs.push_back("-s"); - - if (Args.hasArg(options::OPT_r)) - CmdArgs.push_back("-r"); - - for (const auto &Opt : HTC.ExtraOpts) - CmdArgs.push_back(Opt.c_str()); - - CmdArgs.push_back("-march=hexagon"); - std::string CpuVer = - toolchains::HexagonToolChain::GetTargetCPUVersion(Args).str(); - std::string MCpuString = "-mcpu=hexagon" + CpuVer; - CmdArgs.push_back(Args.MakeArgString(MCpuString)); - - if (IsShared) { - CmdArgs.push_back("-shared"); - // The following should be the default, but doing as hexagon-gcc does. - CmdArgs.push_back("-call_shared"); - } - - if (IsStatic) - CmdArgs.push_back("-static"); - - if (IsPIE && !IsShared) - CmdArgs.push_back("-pie"); - - if (auto G = toolchains::HexagonToolChain::getSmallDataThreshold(Args)) { - std::string N = llvm::utostr(G.getValue()); - CmdArgs.push_back(Args.MakeArgString(std::string("-G") + N)); - UseG0 = G.getValue() == 0; - } - - //---------------------------------------------------------------------------- - // - //---------------------------------------------------------------------------- - CmdArgs.push_back("-o"); - CmdArgs.push_back(Output.getFilename()); - - //---------------------------------------------------------------------------- - // moslib - //---------------------------------------------------------------------------- - std::vector<std::string> OsLibs; - bool HasStandalone = false; - - for (const Arg *A : Args.filtered(options::OPT_moslib_EQ)) { - A->claim(); - OsLibs.emplace_back(A->getValue()); - HasStandalone = HasStandalone || (OsLibs.back() == "standalone"); - } - if (OsLibs.empty()) { - OsLibs.push_back("standalone"); - HasStandalone = true; - } - - //---------------------------------------------------------------------------- - // Start Files - //---------------------------------------------------------------------------- - const std::string MCpuSuffix = "/" + CpuVer; - const std::string MCpuG0Suffix = MCpuSuffix + "/G0"; - const std::string RootDir = - HTC.getHexagonTargetDir(D.InstalledDir, D.PrefixDirs) + "/"; - const std::string StartSubDir = - "hexagon/lib" + (UseG0 ? MCpuG0Suffix : MCpuSuffix); - - auto Find = [&HTC] (const std::string &RootDir, const std::string &SubDir, - const char *Name) -> std::string { - std::string RelName = SubDir + Name; - std::string P = HTC.GetFilePath(RelName.c_str()); - if (llvm::sys::fs::exists(P)) - return P; - return RootDir + RelName; - }; - - if (IncStdLib && IncStartFiles) { - if (!IsShared) { - if (HasStandalone) { - std::string Crt0SA = Find(RootDir, StartSubDir, "/crt0_standalone.o"); - CmdArgs.push_back(Args.MakeArgString(Crt0SA)); - } - std::string Crt0 = Find(RootDir, StartSubDir, "/crt0.o"); - CmdArgs.push_back(Args.MakeArgString(Crt0)); - } - std::string Init = UseShared - ? Find(RootDir, StartSubDir + "/pic", "/initS.o") - : Find(RootDir, StartSubDir, "/init.o"); - CmdArgs.push_back(Args.MakeArgString(Init)); - } - - //---------------------------------------------------------------------------- - // Library Search Paths - //---------------------------------------------------------------------------- - const ToolChain::path_list &LibPaths = HTC.getFilePaths(); - for (const auto &LibPath : LibPaths) - CmdArgs.push_back(Args.MakeArgString(StringRef("-L") + LibPath)); - - //---------------------------------------------------------------------------- - // - //---------------------------------------------------------------------------- - Args.AddAllArgs(CmdArgs, - {options::OPT_T_Group, options::OPT_e, options::OPT_s, - options::OPT_t, options::OPT_u_Group}); - - AddLinkerInputs(HTC, Inputs, Args, CmdArgs, JA); - - //---------------------------------------------------------------------------- - // Libraries - //---------------------------------------------------------------------------- - if (IncStdLib && IncDefLibs) { - if (D.CCCIsCXX()) { - HTC.AddCXXStdlibLibArgs(Args, CmdArgs); - CmdArgs.push_back("-lm"); - } - - CmdArgs.push_back("--start-group"); - - if (!IsShared) { - for (const std::string &Lib : OsLibs) - CmdArgs.push_back(Args.MakeArgString("-l" + Lib)); - CmdArgs.push_back("-lc"); - } - CmdArgs.push_back("-lgcc"); - - CmdArgs.push_back("--end-group"); - } - - //---------------------------------------------------------------------------- - // End files - //---------------------------------------------------------------------------- - if (IncStdLib && IncStartFiles) { - std::string Fini = UseShared - ? Find(RootDir, StartSubDir + "/pic", "/finiS.o") - : Find(RootDir, StartSubDir, "/fini.o"); - CmdArgs.push_back(Args.MakeArgString(Fini)); - } -} - -void hexagon::Linker::ConstructJob(Compilation &C, const JobAction &JA, - const InputInfo &Output, - const InputInfoList &Inputs, - const ArgList &Args, - const char *LinkingOutput) const { - auto &HTC = static_cast<const toolchains::HexagonToolChain&>(getToolChain()); - - ArgStringList CmdArgs; - constructHexagonLinkArgs(C, JA, HTC, Output, Inputs, Args, CmdArgs, - LinkingOutput); - - std::string Linker = HTC.GetProgramPath("hexagon-link"); - C.addCommand(llvm::make_unique<Command>(JA, *this, Args.MakeArgString(Linker), - CmdArgs, Inputs)); -} -// Hexagon tools end. - -void amdgpu::Linker::ConstructJob(Compilation &C, const JobAction &JA, - const InputInfo &Output, - const InputInfoList &Inputs, - const ArgList &Args, - const char *LinkingOutput) const { - - std::string Linker = getToolChain().GetProgramPath(getShortName()); - ArgStringList CmdArgs; - AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA); - CmdArgs.push_back("-shared"); - CmdArgs.push_back("-o"); - CmdArgs.push_back(Output.getFilename()); - C.addCommand(llvm::make_unique<Command>(JA, *this, Args.MakeArgString(Linker), - CmdArgs, Inputs)); -} -// AMDGPU tools end. - -wasm::Linker::Linker(const ToolChain &TC) - : GnuTool("wasm::Linker", "lld", TC) {} - -bool wasm::Linker::isLinkJob() const { - return true; -} - -bool wasm::Linker::hasIntegratedCPP() const { - return false; -} - -void wasm::Linker::ConstructJob(Compilation &C, const JobAction &JA, - const InputInfo &Output, - const InputInfoList &Inputs, - const ArgList &Args, - 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("ld"); - - // 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); - 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"))); - } - - AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA); - - if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { - if (D.CCCIsCXX()) - ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs); - - if (Args.hasArg(options::OPT_pthread)) - CmdArgs.push_back("-lpthread"); - - CmdArgs.push_back("-lc"); - CmdArgs.push_back("-lcompiler_rt"); - } - - 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()); - - C.addCommand(llvm::make_unique<Command>(JA, *this, Linker, CmdArgs, Inputs)); -} - -const std::string arm::getARMArch(StringRef Arch, const llvm::Triple &Triple) { - std::string MArch; - if (!Arch.empty()) - MArch = Arch; - else - MArch = Triple.getArchName(); - MArch = StringRef(MArch).split("+").first.lower(); - - // Handle -march=native. - if (MArch == "native") { - std::string CPU = llvm::sys::getHostCPUName(); - if (CPU != "generic") { - // Translate the native cpu into the architecture suffix for that CPU. - StringRef Suffix = arm::getLLVMArchSuffixForARM(CPU, MArch, Triple); - // If there is no valid architecture suffix for this CPU we don't know how - // to handle it, so return no architecture. - if (Suffix.empty()) - MArch = ""; - else - MArch = std::string("arm") + Suffix.str(); - } - } - - return MArch; -} - -/// Get the (LLVM) name of the minimum ARM CPU for the arch we are targeting. -StringRef arm::getARMCPUForMArch(StringRef Arch, const llvm::Triple &Triple) { - std::string MArch = getARMArch(Arch, Triple); - // getARMCPUForArch defaults to the triple if MArch is empty, but empty MArch - // here means an -march=native that we can't handle, so instead return no CPU. - if (MArch.empty()) - return StringRef(); - - // We need to return an empty string here on invalid MArch values as the - // various places that call this function can't cope with a null result. - return Triple.getARMCPUForArch(MArch); -} - -/// getARMTargetCPU - Get the (LLVM) name of the ARM cpu we are targeting. -std::string arm::getARMTargetCPU(StringRef CPU, StringRef Arch, - const llvm::Triple &Triple) { - // FIXME: Warn on inconsistent use of -mcpu and -march. - // If we have -mcpu=, use that. - if (!CPU.empty()) { - std::string MCPU = StringRef(CPU).split("+").first.lower(); - // Handle -mcpu=native. - if (MCPU == "native") - return llvm::sys::getHostCPUName(); - else - return MCPU; - } - - return getARMCPUForMArch(Arch, Triple); -} - -/// getLLVMArchSuffixForARM - Get the LLVM arch name to use for a particular -/// CPU (or Arch, if CPU is generic). -// FIXME: This is redundant with -mcpu, why does LLVM use this. -StringRef arm::getLLVMArchSuffixForARM(StringRef CPU, StringRef Arch, - const llvm::Triple &Triple) { - unsigned ArchKind; - if (CPU == "generic") { - std::string ARMArch = tools::arm::getARMArch(Arch, Triple); - ArchKind = llvm::ARM::parseArch(ARMArch); - if (ArchKind == llvm::ARM::AK_INVALID) - // In case of generic Arch, i.e. "arm", - // extract arch from default cpu of the Triple - ArchKind = llvm::ARM::parseCPUArch(Triple.getARMCPUForArch(ARMArch)); - } else { - // 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::parseCPUArch(CPU); - } - if (ArchKind == llvm::ARM::AK_INVALID) - return ""; - return llvm::ARM::getSubArch(ArchKind); -} - -void arm::appendEBLinkFlags(const ArgList &Args, ArgStringList &CmdArgs, - const llvm::Triple &Triple) { - if (Args.hasArg(options::OPT_r)) - return; - - // ARMv7 (and later) and ARMv6-M do not support BE-32, so instruct the linker - // to generate BE-8 executables. - if (arm::getARMSubArchVersionNumber(Triple) >= 7 || arm::isARMMProfile(Triple)) - CmdArgs.push_back("--be8"); -} - -llvm::Triple::ArchType darwin::getArchTypeForMachOArchName(StringRef Str) { - // See arch(3) and llvm-gcc's driver-driver.c. We don't implement support for - // archs which Darwin doesn't use. - - // The matching this routine does is fairly pointless, since it is neither the - // complete architecture list, nor a reasonable subset. The problem is that - // historically the driver driver accepts this and also ties its -march= - // handling to the architecture name, so we need to be careful before removing - // support for it. - - // This code must be kept in sync with Clang's Darwin specific argument - // translation. - - return llvm::StringSwitch<llvm::Triple::ArchType>(Str) - .Cases("ppc", "ppc601", "ppc603", "ppc604", "ppc604e", llvm::Triple::ppc) - .Cases("ppc750", "ppc7400", "ppc7450", "ppc970", llvm::Triple::ppc) - .Case("ppc64", llvm::Triple::ppc64) - .Cases("i386", "i486", "i486SX", "i586", "i686", llvm::Triple::x86) - .Cases("pentium", "pentpro", "pentIIm3", "pentIIm5", "pentium4", - llvm::Triple::x86) - .Cases("x86_64", "x86_64h", llvm::Triple::x86_64) - // This is derived from the driver driver. - .Cases("arm", "armv4t", "armv5", "armv6", "armv6m", llvm::Triple::arm) - .Cases("armv7", "armv7em", "armv7k", "armv7m", llvm::Triple::arm) - .Cases("armv7s", "xscale", llvm::Triple::arm) - .Case("arm64", llvm::Triple::aarch64) - .Case("r600", llvm::Triple::r600) - .Case("amdgcn", llvm::Triple::amdgcn) - .Case("nvptx", llvm::Triple::nvptx) - .Case("nvptx64", llvm::Triple::nvptx64) - .Case("amdil", llvm::Triple::amdil) - .Case("spir", llvm::Triple::spir) - .Default(llvm::Triple::UnknownArch); -} - -void darwin::setTripleTypeForMachOArchName(llvm::Triple &T, StringRef Str) { - const llvm::Triple::ArchType Arch = getArchTypeForMachOArchName(Str); - unsigned 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) { - T.setOS(llvm::Triple::UnknownOS); - T.setObjectFormat(llvm::Triple::MachO); - } -} - -const char *Clang::getBaseInputName(const ArgList &Args, - const InputInfo &Input) { - return Args.MakeArgString(llvm::sys::path::filename(Input.getBaseInput())); -} - -const char *Clang::getBaseInputStem(const ArgList &Args, - const InputInfoList &Inputs) { - const char *Str = getBaseInputName(Args, Inputs[0]); - - if (const char *End = strrchr(Str, '.')) - return Args.MakeArgString(std::string(Str, End)); - - return Str; -} - -const char *Clang::getDependencyFileName(const ArgList &Args, - const InputInfoList &Inputs) { - // FIXME: Think about this more. - std::string Res; - - if (Arg *OutputOpt = Args.getLastArg(options::OPT_o)) { - std::string Str(OutputOpt->getValue()); - Res = Str.substr(0, Str.rfind('.')); - } else { - Res = getBaseInputStem(Args, Inputs); - } - return Args.MakeArgString(Res + ".d"); -} - -void cloudabi::Linker::ConstructJob(Compilation &C, const JobAction &JA, - const InputInfo &Output, - const InputInfoList &Inputs, - const ArgList &Args, - const char *LinkingOutput) const { - const ToolChain &ToolChain = getToolChain(); - const Driver &D = ToolChain.getDriver(); - ArgStringList CmdArgs; - - // Silence warning for "clang -g foo.o -o foo" - Args.ClaimAllArgs(options::OPT_g_Group); - // and "clang -emit-llvm foo.o -o foo" - Args.ClaimAllArgs(options::OPT_emit_llvm); - // and for "clang -w foo.o -o foo". Other warning options are already - // handled somewhere else. - Args.ClaimAllArgs(options::OPT_w); - - if (!D.SysRoot.empty()) - CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot)); - - // CloudABI only supports static linkage. - CmdArgs.push_back("-Bstatic"); - CmdArgs.push_back("--no-dynamic-linker"); - - // Provide PIE linker flags in case PIE is default for the architecture. - if (ToolChain.isPIEDefault()) { - CmdArgs.push_back("-pie"); - CmdArgs.push_back("-zrelro"); - } - - CmdArgs.push_back("--eh-frame-hdr"); - CmdArgs.push_back("--gc-sections"); - - 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)) { - CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crt0.o"))); - CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtbegin.o"))); - } - - Args.AddAllArgs(CmdArgs, options::OPT_L); - ToolChain.AddFilePathLibArgs(Args, CmdArgs); - Args.AddAllArgs(CmdArgs, - {options::OPT_T_Group, options::OPT_e, options::OPT_s, - options::OPT_t, options::OPT_Z_Flag, options::OPT_r}); - - if (D.isUsingLTO()) - AddGoldPlugin(ToolChain, Args, CmdArgs, D.getLTOMode() == LTOK_Thin, D); - - AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA); - - 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"); - } - - if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) - CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtend.o"))); - - const char *Exec = Args.MakeArgString(ToolChain.GetLinkerPath()); - C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); -} - -void darwin::Assembler::ConstructJob(Compilation &C, const JobAction &JA, - const InputInfo &Output, - const InputInfoList &Inputs, - const ArgList &Args, - const char *LinkingOutput) const { - ArgStringList CmdArgs; - - assert(Inputs.size() == 1 && "Unexpected number of inputs."); - const InputInfo &Input = Inputs[0]; - - // Determine the original source input. - const Action *SourceAction = &JA; - while (SourceAction->getKind() != Action::InputClass) { - assert(!SourceAction->getInputs().empty() && "unexpected root action!"); - SourceAction = SourceAction->getInputs()[0]; - } - - // If -fno-integrated-as is used add -Q to the darwin assember driver to make - // sure it runs its system assembler not clang's integrated assembler. - // Applicable to darwin11+ and Xcode 4+. darwin<10 lacked integrated-as. - // FIXME: at run-time detect assembler capabilities or rely on version - // information forwarded by -target-assembler-version. - if (Args.hasArg(options::OPT_fno_integrated_as)) { - const llvm::Triple &T(getToolChain().getTriple()); - if (!(T.isMacOSX() && T.isMacOSXVersionLT(10, 7))) - CmdArgs.push_back("-Q"); - } - - // Forward -g, assuming we are dealing with an actual assembly file. - if (SourceAction->getType() == types::TY_Asm || - SourceAction->getType() == types::TY_PP_Asm) { - if (Args.hasArg(options::OPT_gstabs)) - CmdArgs.push_back("--gstabs"); - else if (Args.hasArg(options::OPT_g_Group)) - CmdArgs.push_back("-g"); - } - - // Derived from asm spec. - AddMachOArch(Args, CmdArgs); - - // Use -force_cpusubtype_ALL on x86 by default. - if (getToolChain().getArch() == llvm::Triple::x86 || - getToolChain().getArch() == llvm::Triple::x86_64 || - Args.hasArg(options::OPT_force__cpusubtype__ALL)) - CmdArgs.push_back("-force_cpusubtype_ALL"); - - if (getToolChain().getArch() != llvm::Triple::x86_64 && - (((Args.hasArg(options::OPT_mkernel) || - Args.hasArg(options::OPT_fapple_kext)) && - getMachOToolChain().isKernelStatic()) || - Args.hasArg(options::OPT_static))) - CmdArgs.push_back("-static"); - - Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler); - - assert(Output.isFilename() && "Unexpected lipo output."); - CmdArgs.push_back("-o"); - CmdArgs.push_back(Output.getFilename()); - - assert(Input.isFilename() && "Invalid input."); - CmdArgs.push_back(Input.getFilename()); - - // asm_final spec is empty. - - const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("as")); - C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); -} - -void darwin::MachOTool::anchor() {} - -void darwin::MachOTool::AddMachOArch(const ArgList &Args, - ArgStringList &CmdArgs) const { - StringRef ArchName = getMachOToolChain().getMachOArchName(Args); - - // Derived from darwin_arch spec. - CmdArgs.push_back("-arch"); - CmdArgs.push_back(Args.MakeArgString(ArchName)); - - // FIXME: Is this needed anymore? - if (ArchName == "arm") - CmdArgs.push_back("-force_cpusubtype_ALL"); -} - -bool darwin::Linker::NeedsTempPath(const InputInfoList &Inputs) const { - // We only need to generate a temp path for LTO if we aren't compiling object - // files. When compiling source files, we run 'dsymutil' after linking. We - // don't run 'dsymutil' when compiling object files. - for (const auto &Input : Inputs) - if (Input.getType() != types::TY_Object) - return true; - - return false; -} - -/// \brief Pass -no_deduplicate to ld64 under certain conditions: -/// -/// - Either -O0 or -O1 is explicitly specified -/// - No -O option is specified *and* this is a compile+link (implicit -O0) -/// -/// Also do *not* add -no_deduplicate when no -O option is specified and this -/// is just a link (we can't imply -O0) -static bool shouldLinkerNotDedup(bool IsLinkerOnlyAction, const ArgList &Args) { - if (Arg *A = Args.getLastArg(options::OPT_O_Group)) { - if (A->getOption().matches(options::OPT_O0)) - return true; - if (A->getOption().matches(options::OPT_O)) - return llvm::StringSwitch<bool>(A->getValue()) - .Case("1", true) - .Default(false); - return false; // OPT_Ofast & OPT_O4 - } - - if (!IsLinkerOnlyAction) // Implicit -O0 for compile+linker only. - return true; - return false; -} - -void darwin::Linker::AddLinkArgs(Compilation &C, const ArgList &Args, - ArgStringList &CmdArgs, - const InputInfoList &Inputs) const { - const Driver &D = getToolChain().getDriver(); - const toolchains::MachO &MachOTC = getMachOToolChain(); - - unsigned Version[5] = {0, 0, 0, 0, 0}; - if (Arg *A = Args.getLastArg(options::OPT_mlinker_version_EQ)) { - if (!Driver::GetReleaseVersion(A->getValue(), Version)) - D.Diag(diag::err_drv_invalid_version_number) << A->getAsString(Args); - } - - // Newer linkers support -demangle. Pass it if supported and not disabled by - // the user. - if (Version[0] >= 100 && !Args.hasArg(options::OPT_Z_Xlinker__no_demangle)) - CmdArgs.push_back("-demangle"); - - if (Args.hasArg(options::OPT_rdynamic) && Version[0] >= 137) - CmdArgs.push_back("-export_dynamic"); - - // If we are using App Extension restrictions, pass a flag to the linker - // telling it that the compiled code has been audited. - if (Args.hasFlag(options::OPT_fapplication_extension, - options::OPT_fno_application_extension, false)) - CmdArgs.push_back("-application_extension"); - - if (D.isUsingLTO()) { - // If we are using LTO, then automatically create a temporary file path for - // the linker to use, so that it's lifetime will extend past a possible - // dsymutil step. - if (Version[0] >= 116 && NeedsTempPath(Inputs)) { - const char *TmpPath = C.getArgs().MakeArgString( - D.GetTemporaryPath("cc", types::getTypeTempSuffix(types::TY_Object))); - C.addTempFile(TmpPath); - CmdArgs.push_back("-object_path_lto"); - CmdArgs.push_back(TmpPath); - } - } - - // Use -lto_library option to specify the libLTO.dylib path. Try to find - // it in clang installed libraries. ld64 will only look at this argument - // when it actually uses LTO, so libLTO.dylib only needs to exist at link - // time if ld64 decides that it needs to use LTO. - // Since this is passed unconditionally, ld64 will never look for libLTO.dylib - // next to it. That's ok since ld64 using a libLTO.dylib not matching the - // clang version won't work anyways. - if (Version[0] >= 133) { - // Search for libLTO in <InstalledDir>/../lib/libLTO.dylib - StringRef P = llvm::sys::path::parent_path(D.Dir); - SmallString<128> LibLTOPath(P); - llvm::sys::path::append(LibLTOPath, "lib"); - llvm::sys::path::append(LibLTOPath, "libLTO.dylib"); - CmdArgs.push_back("-lto_library"); - CmdArgs.push_back(C.getArgs().MakeArgString(LibLTOPath)); - } - - // ld64 version 262 and above run the deduplicate pass by default. - if (Version[0] >= 262 && shouldLinkerNotDedup(C.getJobs().empty(), Args)) - CmdArgs.push_back("-no_deduplicate"); - - // Derived from the "link" spec. - Args.AddAllArgs(CmdArgs, options::OPT_static); - if (!Args.hasArg(options::OPT_static)) - CmdArgs.push_back("-dynamic"); - if (Args.hasArg(options::OPT_fgnu_runtime)) { - // FIXME: gcc replaces -lobjc in forward args with -lobjc-gnu - // here. How do we wish to handle such things? - } - - if (!Args.hasArg(options::OPT_dynamiclib)) { - AddMachOArch(Args, CmdArgs); - // FIXME: Why do this only on this path? - Args.AddLastArg(CmdArgs, options::OPT_force__cpusubtype__ALL); - - Args.AddLastArg(CmdArgs, options::OPT_bundle); - Args.AddAllArgs(CmdArgs, options::OPT_bundle__loader); - Args.AddAllArgs(CmdArgs, options::OPT_client__name); - - Arg *A; - if ((A = Args.getLastArg(options::OPT_compatibility__version)) || - (A = Args.getLastArg(options::OPT_current__version)) || - (A = Args.getLastArg(options::OPT_install__name))) - D.Diag(diag::err_drv_argument_only_allowed_with) << A->getAsString(Args) - << "-dynamiclib"; - - Args.AddLastArg(CmdArgs, options::OPT_force__flat__namespace); - Args.AddLastArg(CmdArgs, options::OPT_keep__private__externs); - Args.AddLastArg(CmdArgs, options::OPT_private__bundle); - } else { - CmdArgs.push_back("-dylib"); - - Arg *A; - if ((A = Args.getLastArg(options::OPT_bundle)) || - (A = Args.getLastArg(options::OPT_bundle__loader)) || - (A = Args.getLastArg(options::OPT_client__name)) || - (A = Args.getLastArg(options::OPT_force__flat__namespace)) || - (A = Args.getLastArg(options::OPT_keep__private__externs)) || - (A = Args.getLastArg(options::OPT_private__bundle))) - D.Diag(diag::err_drv_argument_not_allowed_with) << A->getAsString(Args) - << "-dynamiclib"; - - Args.AddAllArgsTranslated(CmdArgs, options::OPT_compatibility__version, - "-dylib_compatibility_version"); - Args.AddAllArgsTranslated(CmdArgs, options::OPT_current__version, - "-dylib_current_version"); - - AddMachOArch(Args, CmdArgs); - - Args.AddAllArgsTranslated(CmdArgs, options::OPT_install__name, - "-dylib_install_name"); - } - - Args.AddLastArg(CmdArgs, options::OPT_all__load); - Args.AddAllArgs(CmdArgs, options::OPT_allowable__client); - Args.AddLastArg(CmdArgs, options::OPT_bind__at__load); - if (MachOTC.isTargetIOSBased()) - Args.AddLastArg(CmdArgs, options::OPT_arch__errors__fatal); - Args.AddLastArg(CmdArgs, options::OPT_dead__strip); - Args.AddLastArg(CmdArgs, options::OPT_no__dead__strip__inits__and__terms); - Args.AddAllArgs(CmdArgs, options::OPT_dylib__file); - Args.AddLastArg(CmdArgs, options::OPT_dynamic); - Args.AddAllArgs(CmdArgs, options::OPT_exported__symbols__list); - Args.AddLastArg(CmdArgs, options::OPT_flat__namespace); - Args.AddAllArgs(CmdArgs, options::OPT_force__load); - Args.AddAllArgs(CmdArgs, options::OPT_headerpad__max__install__names); - Args.AddAllArgs(CmdArgs, options::OPT_image__base); - Args.AddAllArgs(CmdArgs, options::OPT_init); - - // Add the deployment target. - MachOTC.addMinVersionArgs(Args, CmdArgs); - - Args.AddLastArg(CmdArgs, options::OPT_nomultidefs); - Args.AddLastArg(CmdArgs, options::OPT_multi__module); - Args.AddLastArg(CmdArgs, options::OPT_single__module); - Args.AddAllArgs(CmdArgs, options::OPT_multiply__defined); - Args.AddAllArgs(CmdArgs, options::OPT_multiply__defined__unused); - - if (const Arg *A = - Args.getLastArg(options::OPT_fpie, options::OPT_fPIE, - options::OPT_fno_pie, options::OPT_fno_PIE)) { - if (A->getOption().matches(options::OPT_fpie) || - A->getOption().matches(options::OPT_fPIE)) - CmdArgs.push_back("-pie"); - else - CmdArgs.push_back("-no_pie"); - } - - // for embed-bitcode, use -bitcode_bundle in linker command - if (C.getDriver().embedBitcodeEnabled()) { - // Check if the toolchain supports bitcode build flow. - if (MachOTC.SupportsEmbeddedBitcode()) { - CmdArgs.push_back("-bitcode_bundle"); - if (C.getDriver().embedBitcodeMarkerOnly() && Version[0] >= 278) { - CmdArgs.push_back("-bitcode_process_mode"); - CmdArgs.push_back("marker"); - } - } else - D.Diag(diag::err_drv_bitcode_unsupported_on_toolchain); - } - - Args.AddLastArg(CmdArgs, options::OPT_prebind); - Args.AddLastArg(CmdArgs, options::OPT_noprebind); - Args.AddLastArg(CmdArgs, options::OPT_nofixprebinding); - Args.AddLastArg(CmdArgs, options::OPT_prebind__all__twolevel__modules); - Args.AddLastArg(CmdArgs, options::OPT_read__only__relocs); - Args.AddAllArgs(CmdArgs, options::OPT_sectcreate); - Args.AddAllArgs(CmdArgs, options::OPT_sectorder); - Args.AddAllArgs(CmdArgs, options::OPT_seg1addr); - Args.AddAllArgs(CmdArgs, options::OPT_segprot); - Args.AddAllArgs(CmdArgs, options::OPT_segaddr); - Args.AddAllArgs(CmdArgs, options::OPT_segs__read__only__addr); - Args.AddAllArgs(CmdArgs, options::OPT_segs__read__write__addr); - Args.AddAllArgs(CmdArgs, options::OPT_seg__addr__table); - Args.AddAllArgs(CmdArgs, options::OPT_seg__addr__table__filename); - Args.AddAllArgs(CmdArgs, options::OPT_sub__library); - Args.AddAllArgs(CmdArgs, options::OPT_sub__umbrella); - - // Give --sysroot= preference, over the Apple specific behavior to also use - // --isysroot as the syslibroot. - StringRef sysroot = C.getSysRoot(); - if (sysroot != "") { - CmdArgs.push_back("-syslibroot"); - CmdArgs.push_back(C.getArgs().MakeArgString(sysroot)); - } else if (const Arg *A = Args.getLastArg(options::OPT_isysroot)) { - CmdArgs.push_back("-syslibroot"); - CmdArgs.push_back(A->getValue()); - } - - Args.AddLastArg(CmdArgs, options::OPT_twolevel__namespace); - Args.AddLastArg(CmdArgs, options::OPT_twolevel__namespace__hints); - Args.AddAllArgs(CmdArgs, options::OPT_umbrella); - Args.AddAllArgs(CmdArgs, options::OPT_undefined); - Args.AddAllArgs(CmdArgs, options::OPT_unexported__symbols__list); - Args.AddAllArgs(CmdArgs, options::OPT_weak__reference__mismatches); - Args.AddLastArg(CmdArgs, options::OPT_X_Flag); - Args.AddAllArgs(CmdArgs, options::OPT_y); - Args.AddLastArg(CmdArgs, options::OPT_w); - Args.AddAllArgs(CmdArgs, options::OPT_pagezero__size); - Args.AddAllArgs(CmdArgs, options::OPT_segs__read__); - Args.AddLastArg(CmdArgs, options::OPT_seglinkedit); - Args.AddLastArg(CmdArgs, options::OPT_noseglinkedit); - Args.AddAllArgs(CmdArgs, options::OPT_sectalign); - Args.AddAllArgs(CmdArgs, options::OPT_sectobjectsymbols); - Args.AddAllArgs(CmdArgs, options::OPT_segcreate); - Args.AddLastArg(CmdArgs, options::OPT_whyload); - Args.AddLastArg(CmdArgs, options::OPT_whatsloaded); - Args.AddAllArgs(CmdArgs, options::OPT_dylinker__install__name); - Args.AddLastArg(CmdArgs, options::OPT_dylinker); - Args.AddLastArg(CmdArgs, options::OPT_Mach); -} - -void darwin::Linker::ConstructJob(Compilation &C, const JobAction &JA, - const InputInfo &Output, - const InputInfoList &Inputs, - const ArgList &Args, - const char *LinkingOutput) const { - assert(Output.getType() == types::TY_Image && "Invalid linker output type."); - - // If the number of arguments surpasses the system limits, we will encode the - // input files in a separate file, shortening the command line. To this end, - // build a list of input file names that can be passed via a file with the - // -filelist linker option. - llvm::opt::ArgStringList InputFileList; - - // The logic here is derived from gcc's behavior; most of which - // comes from specs (starting with link_command). Consult gcc for - // more information. - ArgStringList CmdArgs; - - /// Hack(tm) to ignore linking errors when we are doing ARC migration. - if (Args.hasArg(options::OPT_ccc_arcmt_check, - options::OPT_ccc_arcmt_migrate)) { - for (const auto &Arg : Args) - Arg->claim(); - const char *Exec = - Args.MakeArgString(getToolChain().GetProgramPath("touch")); - CmdArgs.push_back(Output.getFilename()); - C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, None)); - return; - } - - // I'm not sure why this particular decomposition exists in gcc, but - // we follow suite for ease of comparison. - AddLinkArgs(C, Args, CmdArgs, Inputs); - - // For LTO, pass the name of the optimization record file. - if (Args.hasFlag(options::OPT_fsave_optimization_record, - options::OPT_fno_save_optimization_record, false)) { - CmdArgs.push_back("-mllvm"); - CmdArgs.push_back("-lto-pass-remarks-output"); - CmdArgs.push_back("-mllvm"); - - SmallString<128> F; - F = Output.getFilename(); - F += ".opt.yaml"; - CmdArgs.push_back(Args.MakeArgString(F)); - - if (getLastProfileUseArg(Args)) { - CmdArgs.push_back("-mllvm"); - CmdArgs.push_back("-lto-pass-remarks-with-hotness"); - } - } - - // It seems that the 'e' option is completely ignored for dynamic executables - // (the default), and with static executables, the last one wins, as expected. - Args.AddAllArgs(CmdArgs, {options::OPT_d_Flag, options::OPT_s, options::OPT_t, - options::OPT_Z_Flag, options::OPT_u_Group, - options::OPT_e, options::OPT_r}); - - // Forward -ObjC when either -ObjC or -ObjC++ is used, to force loading - // members of static archive libraries which implement Objective-C classes or - // categories. - if (Args.hasArg(options::OPT_ObjC) || Args.hasArg(options::OPT_ObjCXX)) - CmdArgs.push_back("-ObjC"); - - CmdArgs.push_back("-o"); - CmdArgs.push_back(Output.getFilename()); - - if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) - getMachOToolChain().addStartObjectFileArgs(Args, CmdArgs); - - // SafeStack requires its own runtime libraries - // These libraries should be linked first, to make sure the - // __safestack_init constructor executes before everything else - if (getToolChain().getSanitizerArgs().needsSafeStackRt()) { - getMachOToolChain().AddLinkRuntimeLib(Args, CmdArgs, - "libclang_rt.safestack_osx.a", - /*AlwaysLink=*/true); - } - - Args.AddAllArgs(CmdArgs, options::OPT_L); - - AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA); - // Build the input file for -filelist (list of linker input files) in case we - // need it later - for (const auto &II : Inputs) { - if (!II.isFilename()) { - // This is a linker input argument. - // We cannot mix input arguments and file names in a -filelist input, thus - // we prematurely stop our list (remaining files shall be passed as - // arguments). - if (InputFileList.size() > 0) - break; - - continue; - } - - InputFileList.push_back(II.getFilename()); - } - - if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) - addOpenMPRuntime(CmdArgs, getToolChain(), Args); - - if (isObjCRuntimeLinked(Args) && - !Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { - // We use arclite library for both ARC and subscripting support. - getMachOToolChain().AddLinkARCArgs(Args, CmdArgs); - - CmdArgs.push_back("-framework"); - CmdArgs.push_back("Foundation"); - // Link libobj. - CmdArgs.push_back("-lobjc"); - } - - if (LinkingOutput) { - CmdArgs.push_back("-arch_multiple"); - CmdArgs.push_back("-final_output"); - CmdArgs.push_back(LinkingOutput); - } - - if (Args.hasArg(options::OPT_fnested_functions)) - CmdArgs.push_back("-allow_stack_execute"); - - getMachOToolChain().addProfileRTLibs(Args, CmdArgs); - - if (unsigned Parallelism = - getLTOParallelism(Args, getToolChain().getDriver())) { - CmdArgs.push_back("-mllvm"); - CmdArgs.push_back( - Args.MakeArgString(Twine("-threads=") + llvm::to_string(Parallelism))); - } - - 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. - getMachOToolChain().AddLinkRuntimeLibArgs(Args, CmdArgs); - - // No need to do anything for pthreads. Claim argument to avoid warning. - Args.ClaimAllArgs(options::OPT_pthread); - Args.ClaimAllArgs(options::OPT_pthreads); - } - - if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) { - // endfile_spec is empty. - } - - Args.AddAllArgs(CmdArgs, options::OPT_T_Group); - Args.AddAllArgs(CmdArgs, options::OPT_F); - - // -iframework should be forwarded as -F. - for (const Arg *A : Args.filtered(options::OPT_iframework)) - CmdArgs.push_back(Args.MakeArgString(std::string("-F") + A->getValue())); - - if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { - if (Arg *A = Args.getLastArg(options::OPT_fveclib)) { - if (A->getValue() == StringRef("Accelerate")) { - CmdArgs.push_back("-framework"); - CmdArgs.push_back("Accelerate"); - } - } - } - - const char *Exec = Args.MakeArgString(getToolChain().GetLinkerPath()); - std::unique_ptr<Command> Cmd = - llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs); - Cmd->setInputFileList(std::move(InputFileList)); - C.addCommand(std::move(Cmd)); -} - -void darwin::Lipo::ConstructJob(Compilation &C, const JobAction &JA, - const InputInfo &Output, - const InputInfoList &Inputs, - const ArgList &Args, - const char *LinkingOutput) const { - ArgStringList CmdArgs; - - CmdArgs.push_back("-create"); - assert(Output.isFilename() && "Unexpected lipo output."); - - CmdArgs.push_back("-output"); - CmdArgs.push_back(Output.getFilename()); - - for (const auto &II : Inputs) { - assert(II.isFilename() && "Unexpected lipo input."); - CmdArgs.push_back(II.getFilename()); - } - - const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("lipo")); - C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); -} - -void darwin::Dsymutil::ConstructJob(Compilation &C, const JobAction &JA, - const InputInfo &Output, - const InputInfoList &Inputs, - const ArgList &Args, - const char *LinkingOutput) const { - ArgStringList CmdArgs; - - CmdArgs.push_back("-o"); - CmdArgs.push_back(Output.getFilename()); - - assert(Inputs.size() == 1 && "Unable to handle multiple inputs."); - const InputInfo &Input = Inputs[0]; - assert(Input.isFilename() && "Unexpected dsymutil input."); - CmdArgs.push_back(Input.getFilename()); - - const char *Exec = - Args.MakeArgString(getToolChain().GetProgramPath("dsymutil")); - C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); -} - -void darwin::VerifyDebug::ConstructJob(Compilation &C, const JobAction &JA, - const InputInfo &Output, - const InputInfoList &Inputs, - const ArgList &Args, - const char *LinkingOutput) const { - ArgStringList CmdArgs; - CmdArgs.push_back("--verify"); - CmdArgs.push_back("--debug-info"); - CmdArgs.push_back("--eh-frame"); - CmdArgs.push_back("--quiet"); - - assert(Inputs.size() == 1 && "Unable to handle multiple inputs."); - const InputInfo &Input = Inputs[0]; - assert(Input.isFilename() && "Unexpected verify input"); - - // Grabbing the output of the earlier dsymutil run. - CmdArgs.push_back(Input.getFilename()); - - const char *Exec = - Args.MakeArgString(getToolChain().GetProgramPath("dwarfdump")); - C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); -} - -void solaris::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 solaris::Linker::ConstructJob(Compilation &C, const JobAction &JA, - const InputInfo &Output, - const InputInfoList &Inputs, - const ArgList &Args, - const char *LinkingOutput) const { - ArgStringList CmdArgs; - - // Demangle C++ names in errors - CmdArgs.push_back("-C"); - - 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"); - CmdArgs.push_back("-dn"); - } else { - CmdArgs.push_back("-Bdynamic"); - if (Args.hasArg(options::OPT_shared)) { - CmdArgs.push_back("-shared"); - } else { - CmdArgs.push_back("--dynamic-linker"); - CmdArgs.push_back( - Args.MakeArgString(getToolChain().GetFilePath("ld.so.1"))); - } - } - - 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)) - CmdArgs.push_back( - Args.MakeArgString(getToolChain().GetFilePath("crt1.o"))); - - CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath("crti.o"))); - CmdArgs.push_back( - Args.MakeArgString(getToolChain().GetFilePath("values-Xa.o"))); - CmdArgs.push_back( - Args.MakeArgString(getToolChain().GetFilePath("crtbegin.o"))); - } - - getToolChain().AddFilePathLibArgs(Args, CmdArgs); - - Args.AddAllArgs(CmdArgs, {options::OPT_L, options::OPT_T_Group, - options::OPT_e, options::OPT_r}); - - AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA); - - if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { - if (getToolChain().getDriver().CCCIsCXX()) - getToolChain().AddCXXStdlibLibArgs(Args, CmdArgs); - CmdArgs.push_back("-lgcc_s"); - CmdArgs.push_back("-lc"); - if (!Args.hasArg(options::OPT_shared)) { - CmdArgs.push_back("-lgcc"); - CmdArgs.push_back("-lm"); - } - } - - if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) { - CmdArgs.push_back( - Args.MakeArgString(getToolChain().GetFilePath("crtend.o"))); - } - CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath("crtn.o"))); - - getToolChain().addProfileRTLibs(Args, CmdArgs); - - const char *Exec = Args.MakeArgString(getToolChain().GetLinkerPath()); - C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); -} - -void openbsd::Assembler::ConstructJob(Compilation &C, const JobAction &JA, - const InputInfo &Output, - const InputInfoList &Inputs, - const ArgList &Args, - const char *LinkingOutput) const { - claimNoWarnArgs(Args); - ArgStringList CmdArgs; - - switch (getToolChain().getArch()) { - case llvm::Triple::x86: - // When building 32-bit code on OpenBSD/amd64, we have to explicitly - // instruct as in the base system to assemble 32-bit code. - CmdArgs.push_back("--32"); - break; - - case llvm::Triple::ppc: - CmdArgs.push_back("-mppc"); - CmdArgs.push_back("-many"); - break; - - case llvm::Triple::sparc: - case llvm::Triple::sparcel: { - CmdArgs.push_back("-32"); - std::string CPU = getCPUName(Args, getToolChain().getTriple()); - CmdArgs.push_back(sparc::getSparcAsmModeForCPU(CPU, getToolChain().getTriple())); - AddAssemblerKPIC(getToolChain(), Args, CmdArgs); - break; - } - - case llvm::Triple::sparcv9: { - CmdArgs.push_back("-64"); - std::string CPU = getCPUName(Args, getToolChain().getTriple()); - CmdArgs.push_back(sparc::getSparcAsmModeForCPU(CPU, getToolChain().getTriple())); - AddAssemblerKPIC(getToolChain(), Args, CmdArgs); - break; - } - - case llvm::Triple::mips64: - case llvm::Triple::mips64el: { - StringRef CPUName; - StringRef ABIName; - mips::getMipsCPUAndABI(Args, getToolChain().getTriple(), CPUName, ABIName); - - CmdArgs.push_back("-mabi"); - CmdArgs.push_back(mips::getGnuCompatibleMipsABIName(ABIName).data()); - - if (getToolChain().getArch() == llvm::Triple::mips64) - CmdArgs.push_back("-EB"); - else - CmdArgs.push_back("-EL"); - - AddAssemblerKPIC(getToolChain(), Args, CmdArgs); - break; - } - - default: - break; - } - - 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 openbsd::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; - - // Silence warning for "clang -g foo.o -o foo" - Args.ClaimAllArgs(options::OPT_g_Group); - // and "clang -emit-llvm foo.o -o foo" - Args.ClaimAllArgs(options::OPT_emit_llvm); - // and for "clang -w foo.o -o foo". Other warning options are already - // handled somewhere else. - Args.ClaimAllArgs(options::OPT_w); - - if (getToolChain().getArch() == llvm::Triple::mips64) - CmdArgs.push_back("-EB"); - else if (getToolChain().getArch() == llvm::Triple::mips64el) - CmdArgs.push_back("-EL"); - - if (!Args.hasArg(options::OPT_nostdlib, options::OPT_shared)) { - CmdArgs.push_back("-e"); - CmdArgs.push_back("__start"); - } - - CmdArgs.push_back("--eh-frame-hdr"); - 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("-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 (Args.hasArg(options::OPT_nopie)) - CmdArgs.push_back("-nopie"); - - 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 if (Args.hasArg(options::OPT_static) && - !Args.hasArg(options::OPT_nopie)) - CmdArgs.push_back( - Args.MakeArgString(getToolChain().GetFilePath("rcrt0.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"))); - } - } - - std::string Triple = getToolChain().getTripleString(); - if (Triple.substr(0, 6) == "x86_64") - Triple.replace(0, 6, "amd64"); - CmdArgs.push_back( - Args.MakeArgString("-L/usr/lib/gcc-lib/" + Triple + "/4.2.1")); - - Args.AddAllArgs(CmdArgs, {options::OPT_L, options::OPT_T_Group, - options::OPT_e, options::OPT_s, options::OPT_t, - options::OPT_Z_Flag, options::OPT_r}); - - 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"); - } - - // FIXME: For some reason GCC passes -lgcc before adding - // the default system libraries. Just mimic this for now. - CmdArgs.push_back("-lgcc"); - - 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"); - } - - CmdArgs.push_back("-lgcc"); - } - - 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)); -} - -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)); -} - -void freebsd::Assembler::ConstructJob(Compilation &C, const JobAction &JA, - const InputInfo &Output, - const InputInfoList &Inputs, - const ArgList &Args, - const char *LinkingOutput) const { - claimNoWarnArgs(Args); - ArgStringList CmdArgs; - - // When building 32-bit code on FreeBSD/amd64, we have to explicitly - // instruct as in the base system to assemble 32-bit code. - switch (getToolChain().getArch()) { - default: - break; - case llvm::Triple::x86: - CmdArgs.push_back("--32"); - break; - case llvm::Triple::ppc: - CmdArgs.push_back("-a32"); - break; - case llvm::Triple::mips: - case llvm::Triple::mipsel: - case llvm::Triple::mips64: - case llvm::Triple::mips64el: { - StringRef CPUName; - StringRef ABIName; - mips::getMipsCPUAndABI(Args, getToolChain().getTriple(), CPUName, ABIName); - - CmdArgs.push_back("-march"); - CmdArgs.push_back(CPUName.data()); - - CmdArgs.push_back("-mabi"); - CmdArgs.push_back(mips::getGnuCompatibleMipsABIName(ABIName).data()); - - if (getToolChain().getArch() == llvm::Triple::mips || - getToolChain().getArch() == llvm::Triple::mips64) - CmdArgs.push_back("-EB"); - else - CmdArgs.push_back("-EL"); - - if (Arg *A = Args.getLastArg(options::OPT_G)) { - StringRef v = A->getValue(); - CmdArgs.push_back(Args.MakeArgString("-G" + v)); - A->claim(); - } - - AddAssemblerKPIC(getToolChain(), Args, CmdArgs); - break; - } - case llvm::Triple::arm: - case llvm::Triple::armeb: - case llvm::Triple::thumb: - case llvm::Triple::thumbeb: { - arm::FloatABI ABI = arm::getARMFloatABI(getToolChain(), Args); - - if (ABI == arm::FloatABI::Hard) - CmdArgs.push_back("-mfpu=vfp"); - else - CmdArgs.push_back("-mfpu=softvfp"); - - switch (getToolChain().getTriple().getEnvironment()) { - case llvm::Triple::GNUEABIHF: - case llvm::Triple::GNUEABI: - case llvm::Triple::EABI: - CmdArgs.push_back("-meabi=5"); - break; - - default: - CmdArgs.push_back("-matpcs"); - } - break; - } - case llvm::Triple::sparc: - case llvm::Triple::sparcel: - case llvm::Triple::sparcv9: { - std::string CPU = getCPUName(Args, getToolChain().getTriple()); - CmdArgs.push_back(sparc::getSparcAsmModeForCPU(CPU, getToolChain().getTriple())); - AddAssemblerKPIC(getToolChain(), Args, CmdArgs); - break; - } - } - - 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 freebsd::Linker::ConstructJob(Compilation &C, const JobAction &JA, - const InputInfo &Output, - const InputInfoList &Inputs, - const ArgList &Args, - const char *LinkingOutput) const { - const toolchains::FreeBSD &ToolChain = - static_cast<const toolchains::FreeBSD &>(getToolChain()); - const Driver &D = ToolChain.getDriver(); - const llvm::Triple::ArchType Arch = ToolChain.getArch(); - const bool IsPIE = - !Args.hasArg(options::OPT_shared) && - (Args.hasArg(options::OPT_pie) || ToolChain.isPIEDefault()); - ArgStringList CmdArgs; - - // Silence warning for "clang -g foo.o -o foo" - Args.ClaimAllArgs(options::OPT_g_Group); - // and "clang -emit-llvm foo.o -o foo" - Args.ClaimAllArgs(options::OPT_emit_llvm); - // and for "clang -w foo.o -o foo". Other warning options are already - // handled somewhere else. - Args.ClaimAllArgs(options::OPT_w); - - if (!D.SysRoot.empty()) - CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot)); - - if (IsPIE) - CmdArgs.push_back("-pie"); - - CmdArgs.push_back("--eh-frame-hdr"); - if (Args.hasArg(options::OPT_static)) { - CmdArgs.push_back("-Bstatic"); - } else { - if (Args.hasArg(options::OPT_rdynamic)) - CmdArgs.push_back("-export-dynamic"); - if (Args.hasArg(options::OPT_shared)) { - CmdArgs.push_back("-Bshareable"); - } else { - CmdArgs.push_back("-dynamic-linker"); - CmdArgs.push_back("/libexec/ld-elf.so.1"); - } - if (ToolChain.getTriple().getOSMajorVersion() >= 9) { - if (Arch == llvm::Triple::arm || Arch == llvm::Triple::sparc || - Arch == llvm::Triple::x86 || Arch == llvm::Triple::x86_64) { - CmdArgs.push_back("--hash-style=both"); - } - } - CmdArgs.push_back("--enable-new-dtags"); - } - - // When building 32-bit code on FreeBSD/amd64, we have to explicitly - // instruct ld in the base system to link 32-bit code. - if (Arch == llvm::Triple::x86) { - CmdArgs.push_back("-m"); - CmdArgs.push_back("elf_i386_fbsd"); - } - - if (Arch == llvm::Triple::ppc) { - CmdArgs.push_back("-m"); - CmdArgs.push_back("elf32ppc_fbsd"); - } - - if (Arg *A = Args.getLastArg(options::OPT_G)) { - if (ToolChain.getArch() == llvm::Triple::mips || - ToolChain.getArch() == llvm::Triple::mipsel || - ToolChain.getArch() == llvm::Triple::mips64 || - ToolChain.getArch() == llvm::Triple::mips64el) { - StringRef v = A->getValue(); - CmdArgs.push_back(Args.MakeArgString("-G" + v)); - A->claim(); - } - } - - 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)) { - const char *crt1 = nullptr; - if (!Args.hasArg(options::OPT_shared)) { - if (Args.hasArg(options::OPT_pg)) - crt1 = "gcrt1.o"; - else if (IsPIE) - crt1 = "Scrt1.o"; - else - crt1 = "crt1.o"; - } - if (crt1) - CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crt1))); - - CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crti.o"))); - - const char *crtbegin = nullptr; - if (Args.hasArg(options::OPT_static)) - crtbegin = "crtbeginT.o"; - else if (Args.hasArg(options::OPT_shared) || IsPIE) - crtbegin = "crtbeginS.o"; - else - crtbegin = "crtbegin.o"; - - CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crtbegin))); - } - - Args.AddAllArgs(CmdArgs, options::OPT_L); - ToolChain.AddFilePathLibArgs(Args, CmdArgs); - Args.AddAllArgs(CmdArgs, options::OPT_T_Group); - Args.AddAllArgs(CmdArgs, options::OPT_e); - Args.AddAllArgs(CmdArgs, options::OPT_s); - Args.AddAllArgs(CmdArgs, options::OPT_t); - Args.AddAllArgs(CmdArgs, options::OPT_Z_Flag); - Args.AddAllArgs(CmdArgs, options::OPT_r); - - if (D.isUsingLTO()) - AddGoldPlugin(ToolChain, Args, CmdArgs, D.getLTOMode() == LTOK_Thin, D); - - bool NeedsSanitizerDeps = addSanitizerRuntimes(ToolChain, Args, CmdArgs); - AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA); - - if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { - addOpenMPRuntime(CmdArgs, ToolChain, Args); - if (D.CCCIsCXX()) { - ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs); - if (Args.hasArg(options::OPT_pg)) - CmdArgs.push_back("-lm_p"); - else - CmdArgs.push_back("-lm"); - } - if (NeedsSanitizerDeps) - linkSanitizerRuntimeDeps(ToolChain, CmdArgs); - // FIXME: For some reason GCC passes -lgcc and -lgcc_s before adding - // the default system libraries. Just mimic this for now. - if (Args.hasArg(options::OPT_pg)) - CmdArgs.push_back("-lgcc_p"); - else - CmdArgs.push_back("-lgcc"); - if (Args.hasArg(options::OPT_static)) { - CmdArgs.push_back("-lgcc_eh"); - } else if (Args.hasArg(options::OPT_pg)) { - CmdArgs.push_back("-lgcc_eh_p"); - } else { - CmdArgs.push_back("--as-needed"); - CmdArgs.push_back("-lgcc_s"); - CmdArgs.push_back("--no-as-needed"); - } - - if (Args.hasArg(options::OPT_pthread)) { - if (Args.hasArg(options::OPT_pg)) - CmdArgs.push_back("-lpthread_p"); - else - CmdArgs.push_back("-lpthread"); - } - - if (Args.hasArg(options::OPT_pg)) { - if (Args.hasArg(options::OPT_shared)) - CmdArgs.push_back("-lc"); - else - CmdArgs.push_back("-lc_p"); - CmdArgs.push_back("-lgcc_p"); - } else { - CmdArgs.push_back("-lc"); - CmdArgs.push_back("-lgcc"); - } - - if (Args.hasArg(options::OPT_static)) { - CmdArgs.push_back("-lgcc_eh"); - } else if (Args.hasArg(options::OPT_pg)) { - CmdArgs.push_back("-lgcc_eh_p"); - } else { - CmdArgs.push_back("--as-needed"); - CmdArgs.push_back("-lgcc_s"); - CmdArgs.push_back("--no-as-needed"); - } - } - - if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) { - if (Args.hasArg(options::OPT_shared) || IsPIE) - CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtendS.o"))); - else - CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtend.o"))); - CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtn.o"))); - } - - ToolChain.addProfileRTLibs(Args, CmdArgs); - - const char *Exec = Args.MakeArgString(getToolChain().GetLinkerPath()); - C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); -} - -void netbsd::Assembler::ConstructJob(Compilation &C, const JobAction &JA, - const InputInfo &Output, - const InputInfoList &Inputs, - const ArgList &Args, - const char *LinkingOutput) const { - claimNoWarnArgs(Args); - ArgStringList CmdArgs; - - // GNU as needs different flags for creating the correct output format - // on architectures with different ABIs or optional feature sets. - switch (getToolChain().getArch()) { - case llvm::Triple::x86: - CmdArgs.push_back("--32"); - break; - case llvm::Triple::arm: - case llvm::Triple::armeb: - case llvm::Triple::thumb: - case llvm::Triple::thumbeb: { - StringRef MArch, MCPU; - arm::getARMArchCPUFromArgs(Args, MArch, MCPU, /*FromAs*/ true); - std::string Arch = - arm::getARMTargetCPU(MCPU, MArch, getToolChain().getTriple()); - CmdArgs.push_back(Args.MakeArgString("-mcpu=" + Arch)); - break; - } - - case llvm::Triple::mips: - case llvm::Triple::mipsel: - case llvm::Triple::mips64: - case llvm::Triple::mips64el: { - StringRef CPUName; - StringRef ABIName; - mips::getMipsCPUAndABI(Args, getToolChain().getTriple(), CPUName, ABIName); - - CmdArgs.push_back("-march"); - CmdArgs.push_back(CPUName.data()); - - CmdArgs.push_back("-mabi"); - CmdArgs.push_back(mips::getGnuCompatibleMipsABIName(ABIName).data()); - - if (getToolChain().getArch() == llvm::Triple::mips || - getToolChain().getArch() == llvm::Triple::mips64) - CmdArgs.push_back("-EB"); - else - CmdArgs.push_back("-EL"); - - AddAssemblerKPIC(getToolChain(), Args, CmdArgs); - break; - } - - case llvm::Triple::sparc: - case llvm::Triple::sparcel: { - CmdArgs.push_back("-32"); - std::string CPU = getCPUName(Args, getToolChain().getTriple()); - CmdArgs.push_back(sparc::getSparcAsmModeForCPU(CPU, getToolChain().getTriple())); - AddAssemblerKPIC(getToolChain(), Args, CmdArgs); - break; - } - - case llvm::Triple::sparcv9: { - CmdArgs.push_back("-64"); - std::string CPU = getCPUName(Args, getToolChain().getTriple()); - CmdArgs.push_back(sparc::getSparcAsmModeForCPU(CPU, getToolChain().getTriple())); - AddAssemblerKPIC(getToolChain(), Args, CmdArgs); - break; - } - - default: - break; - } - - 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 netbsd::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 (!D.SysRoot.empty()) - CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot)); - - CmdArgs.push_back("--eh-frame-hdr"); - if (Args.hasArg(options::OPT_static)) { - CmdArgs.push_back("-Bstatic"); - } else { - if (Args.hasArg(options::OPT_rdynamic)) - CmdArgs.push_back("-export-dynamic"); - if (Args.hasArg(options::OPT_shared)) { - CmdArgs.push_back("-Bshareable"); - } else { - Args.AddAllArgs(CmdArgs, options::OPT_pie); - CmdArgs.push_back("-dynamic-linker"); - CmdArgs.push_back("/libexec/ld.elf_so"); - } - } - - // Many NetBSD architectures support more than one ABI. - // Determine the correct emulation for ld. - switch (getToolChain().getArch()) { - case llvm::Triple::x86: - CmdArgs.push_back("-m"); - CmdArgs.push_back("elf_i386"); - break; - case llvm::Triple::arm: - case llvm::Triple::thumb: - CmdArgs.push_back("-m"); - switch (getToolChain().getTriple().getEnvironment()) { - case llvm::Triple::EABI: - case llvm::Triple::GNUEABI: - CmdArgs.push_back("armelf_nbsd_eabi"); - break; - case llvm::Triple::EABIHF: - case llvm::Triple::GNUEABIHF: - CmdArgs.push_back("armelf_nbsd_eabihf"); - break; - default: - CmdArgs.push_back("armelf_nbsd"); - break; - } - break; - case llvm::Triple::armeb: - case llvm::Triple::thumbeb: - arm::appendEBLinkFlags(Args, CmdArgs, getToolChain().getEffectiveTriple()); - CmdArgs.push_back("-m"); - switch (getToolChain().getTriple().getEnvironment()) { - case llvm::Triple::EABI: - case llvm::Triple::GNUEABI: - CmdArgs.push_back("armelfb_nbsd_eabi"); - break; - case llvm::Triple::EABIHF: - case llvm::Triple::GNUEABIHF: - CmdArgs.push_back("armelfb_nbsd_eabihf"); - break; - default: - CmdArgs.push_back("armelfb_nbsd"); - break; - } - break; - case llvm::Triple::mips64: - case llvm::Triple::mips64el: - if (mips::hasMipsAbiArg(Args, "32")) { - CmdArgs.push_back("-m"); - if (getToolChain().getArch() == llvm::Triple::mips64) - CmdArgs.push_back("elf32btsmip"); - else - CmdArgs.push_back("elf32ltsmip"); - } else if (mips::hasMipsAbiArg(Args, "64")) { - CmdArgs.push_back("-m"); - if (getToolChain().getArch() == llvm::Triple::mips64) - CmdArgs.push_back("elf64btsmip"); - else - CmdArgs.push_back("elf64ltsmip"); - } - break; - case llvm::Triple::ppc: - CmdArgs.push_back("-m"); - CmdArgs.push_back("elf32ppc_nbsd"); - break; - - case llvm::Triple::ppc64: - case llvm::Triple::ppc64le: - CmdArgs.push_back("-m"); - CmdArgs.push_back("elf64ppc"); - break; - - case llvm::Triple::sparc: - CmdArgs.push_back("-m"); - CmdArgs.push_back("elf32_sparc"); - break; - - case llvm::Triple::sparcv9: - CmdArgs.push_back("-m"); - CmdArgs.push_back("elf64_sparc"); - break; - - default: - break; - } - - 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)) { - CmdArgs.push_back( - Args.MakeArgString(getToolChain().GetFilePath("crt0.o"))); - } - CmdArgs.push_back( - Args.MakeArgString(getToolChain().GetFilePath("crti.o"))); - if (Args.hasArg(options::OPT_shared) || Args.hasArg(options::OPT_pie)) { - CmdArgs.push_back( - Args.MakeArgString(getToolChain().GetFilePath("crtbeginS.o"))); - } else { - CmdArgs.push_back( - Args.MakeArgString(getToolChain().GetFilePath("crtbegin.o"))); - } - } - - Args.AddAllArgs(CmdArgs, options::OPT_L); - Args.AddAllArgs(CmdArgs, options::OPT_T_Group); - Args.AddAllArgs(CmdArgs, options::OPT_e); - Args.AddAllArgs(CmdArgs, options::OPT_s); - Args.AddAllArgs(CmdArgs, options::OPT_t); - Args.AddAllArgs(CmdArgs, options::OPT_Z_Flag); - Args.AddAllArgs(CmdArgs, options::OPT_r); - - AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA); - - unsigned Major, Minor, Micro; - getToolChain().getTriple().getOSVersion(Major, Minor, Micro); - bool useLibgcc = true; - if (Major >= 7 || Major == 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: - case llvm::Triple::ppc: - case llvm::Triple::ppc64: - case llvm::Triple::ppc64le: - case llvm::Triple::sparc: - case llvm::Triple::sparcv9: - case llvm::Triple::x86: - case llvm::Triple::x86_64: - useLibgcc = false; - break; - default: - break; - } - } - - if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { - addOpenMPRuntime(CmdArgs, getToolChain(), Args); - if (D.CCCIsCXX()) { - getToolChain().AddCXXStdlibLibArgs(Args, CmdArgs); - CmdArgs.push_back("-lm"); - } - if (Args.hasArg(options::OPT_pthread)) - CmdArgs.push_back("-lpthread"); - CmdArgs.push_back("-lc"); - - if (useLibgcc) { - if (Args.hasArg(options::OPT_static)) { - // libgcc_eh depends on libc, so resolve as much as possible, - // pull in any new requirements from libc and then get the rest - // of libgcc. - CmdArgs.push_back("-lgcc_eh"); - CmdArgs.push_back("-lc"); - CmdArgs.push_back("-lgcc"); - } else { - CmdArgs.push_back("-lgcc"); - CmdArgs.push_back("--as-needed"); - CmdArgs.push_back("-lgcc_s"); - CmdArgs.push_back("--no-as-needed"); - } - } - } - - if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) { - if (Args.hasArg(options::OPT_shared) || Args.hasArg(options::OPT_pie)) - CmdArgs.push_back( - Args.MakeArgString(getToolChain().GetFilePath("crtendS.o"))); - else - CmdArgs.push_back( - Args.MakeArgString(getToolChain().GetFilePath("crtend.o"))); - CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath("crtn.o"))); - } - - getToolChain().addProfileRTLibs(Args, CmdArgs); - - const char *Exec = Args.MakeArgString(getToolChain().GetLinkerPath()); - C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); -} - -void gnutools::Assembler::ConstructJob(Compilation &C, const JobAction &JA, - const InputInfo &Output, - const InputInfoList &Inputs, - const ArgList &Args, - const char *LinkingOutput) const { - claimNoWarnArgs(Args); - - ArgStringList CmdArgs; - - llvm::Reloc::Model RelocationModel; - unsigned PICLevel; - bool IsPIE; - std::tie(RelocationModel, PICLevel, IsPIE) = - ParsePICArgs(getToolChain(), Args); - - switch (getToolChain().getArch()) { - default: - break; - // Add --32/--64 to make sure we get the format we want. - // This is incomplete - case llvm::Triple::x86: - CmdArgs.push_back("--32"); - break; - case llvm::Triple::x86_64: - if (getToolChain().getTriple().getEnvironment() == llvm::Triple::GNUX32) - CmdArgs.push_back("--x32"); - else - CmdArgs.push_back("--64"); - break; - case llvm::Triple::ppc: - CmdArgs.push_back("-a32"); - CmdArgs.push_back("-mppc"); - CmdArgs.push_back("-many"); - break; - case llvm::Triple::ppc64: - CmdArgs.push_back("-a64"); - CmdArgs.push_back("-mppc64"); - CmdArgs.push_back("-many"); - break; - case llvm::Triple::ppc64le: - CmdArgs.push_back("-a64"); - CmdArgs.push_back("-mppc64"); - CmdArgs.push_back("-many"); - CmdArgs.push_back("-mlittle-endian"); - break; - case llvm::Triple::sparc: - case llvm::Triple::sparcel: { - CmdArgs.push_back("-32"); - std::string CPU = getCPUName(Args, getToolChain().getTriple()); - CmdArgs.push_back(sparc::getSparcAsmModeForCPU(CPU, getToolChain().getTriple())); - AddAssemblerKPIC(getToolChain(), Args, CmdArgs); - break; - } - case llvm::Triple::sparcv9: { - CmdArgs.push_back("-64"); - std::string CPU = getCPUName(Args, getToolChain().getTriple()); - CmdArgs.push_back(sparc::getSparcAsmModeForCPU(CPU, getToolChain().getTriple())); - AddAssemblerKPIC(getToolChain(), Args, CmdArgs); - break; - } - case llvm::Triple::arm: - case llvm::Triple::armeb: - case llvm::Triple::thumb: - case llvm::Triple::thumbeb: { - const llvm::Triple &Triple2 = getToolChain().getTriple(); - switch (Triple2.getSubArch()) { - case llvm::Triple::ARMSubArch_v7: - CmdArgs.push_back("-mfpu=neon"); - break; - case llvm::Triple::ARMSubArch_v8: - CmdArgs.push_back("-mfpu=crypto-neon-fp-armv8"); - break; - default: - break; - } - - switch (arm::getARMFloatABI(getToolChain(), Args)) { - case arm::FloatABI::Invalid: llvm_unreachable("must have an ABI!"); - case arm::FloatABI::Soft: - CmdArgs.push_back(Args.MakeArgString("-mfloat-abi=soft")); - break; - case arm::FloatABI::SoftFP: - CmdArgs.push_back(Args.MakeArgString("-mfloat-abi=softfp")); - break; - case arm::FloatABI::Hard: - CmdArgs.push_back(Args.MakeArgString("-mfloat-abi=hard")); - break; - } - - Args.AddLastArg(CmdArgs, options::OPT_march_EQ); - - // FIXME: remove krait check when GNU tools support krait cpu - // for now replace it with -mcpu=cortex-a15 to avoid a lower - // march from being picked in the absence of a cpu flag. - Arg *A; - if ((A = Args.getLastArg(options::OPT_mcpu_EQ)) && - StringRef(A->getValue()).equals_lower("krait")) - CmdArgs.push_back("-mcpu=cortex-a15"); - else - Args.AddLastArg(CmdArgs, options::OPT_mcpu_EQ); - Args.AddLastArg(CmdArgs, options::OPT_mfpu_EQ); - break; - } - case llvm::Triple::mips: - case llvm::Triple::mipsel: - case llvm::Triple::mips64: - case llvm::Triple::mips64el: { - StringRef CPUName; - StringRef ABIName; - mips::getMipsCPUAndABI(Args, getToolChain().getTriple(), CPUName, ABIName); - ABIName = mips::getGnuCompatibleMipsABIName(ABIName); - - CmdArgs.push_back("-march"); - CmdArgs.push_back(CPUName.data()); - - CmdArgs.push_back("-mabi"); - CmdArgs.push_back(ABIName.data()); - - // -mno-shared should be emitted unless -fpic, -fpie, -fPIC, -fPIE, - // or -mshared (not implemented) is in effect. - if (RelocationModel == llvm::Reloc::Static) - CmdArgs.push_back("-mno-shared"); - - // LLVM doesn't support -mplt yet and acts as if it is always given. - // However, -mplt has no effect with the N64 ABI. - if (ABIName != "64" && !Args.hasArg(options::OPT_mno_abicalls)) - CmdArgs.push_back("-call_nonpic"); - - if (getToolChain().getArch() == llvm::Triple::mips || - getToolChain().getArch() == llvm::Triple::mips64) - CmdArgs.push_back("-EB"); - else - CmdArgs.push_back("-EL"); - - if (Arg *A = Args.getLastArg(options::OPT_mnan_EQ)) { - if (StringRef(A->getValue()) == "2008") - CmdArgs.push_back(Args.MakeArgString("-mnan=2008")); - } - - // Add the last -mfp32/-mfpxx/-mfp64 or -mfpxx if it is enabled by default. - if (Arg *A = Args.getLastArg(options::OPT_mfp32, options::OPT_mfpxx, - options::OPT_mfp64)) { - A->claim(); - A->render(Args, CmdArgs); - } else if (mips::shouldUseFPXX( - Args, getToolChain().getTriple(), CPUName, ABIName, - mips::getMipsFloatABI(getToolChain().getDriver(), Args))) - CmdArgs.push_back("-mfpxx"); - - // Pass on -mmips16 or -mno-mips16. However, the assembler equivalent of - // -mno-mips16 is actually -no-mips16. - if (Arg *A = - Args.getLastArg(options::OPT_mips16, options::OPT_mno_mips16)) { - if (A->getOption().matches(options::OPT_mips16)) { - A->claim(); - A->render(Args, CmdArgs); - } else { - A->claim(); - CmdArgs.push_back("-no-mips16"); - } - } - - Args.AddLastArg(CmdArgs, options::OPT_mmicromips, - options::OPT_mno_micromips); - Args.AddLastArg(CmdArgs, options::OPT_mdsp, options::OPT_mno_dsp); - Args.AddLastArg(CmdArgs, options::OPT_mdspr2, options::OPT_mno_dspr2); - - if (Arg *A = Args.getLastArg(options::OPT_mmsa, options::OPT_mno_msa)) { - // Do not use AddLastArg because not all versions of MIPS assembler - // support -mmsa / -mno-msa options. - if (A->getOption().matches(options::OPT_mmsa)) - CmdArgs.push_back(Args.MakeArgString("-mmsa")); - } - - Args.AddLastArg(CmdArgs, options::OPT_mhard_float, - options::OPT_msoft_float); - - Args.AddLastArg(CmdArgs, options::OPT_mdouble_float, - options::OPT_msingle_float); - - Args.AddLastArg(CmdArgs, options::OPT_modd_spreg, - options::OPT_mno_odd_spreg); - - AddAssemblerKPIC(getToolChain(), Args, CmdArgs); - break; - } - case llvm::Triple::systemz: { - // Always pass an -march option, since our default of z10 is later - // than the GNU assembler's default. - StringRef CPUName = systemz::getSystemZTargetCPU(Args); - CmdArgs.push_back(Args.MakeArgString("-march=" + CPUName)); - break; - } - } - - Args.AddAllArgs(CmdArgs, options::OPT_I); - Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler); - - CmdArgs.push_back("-o"); - CmdArgs.push_back(Output.getFilename()); - - for (const auto &II : Inputs) - CmdArgs.push_back(II.getFilename()); - - const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("as")); - C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); - - // Handle the debug info splitting at object creation time if we're - // creating an object. - // TODO: Currently only works on linux with newer objcopy. - if (Args.hasArg(options::OPT_gsplit_dwarf) && - getToolChain().getTriple().isOSLinux()) - SplitDebugInfo(getToolChain(), C, *this, JA, Args, Output, - SplitDebugName(Args, Inputs[0])); -} - -static void AddLibgcc(const llvm::Triple &Triple, const Driver &D, - ArgStringList &CmdArgs, const ArgList &Args) { - bool isAndroid = Triple.isAndroid(); - bool isCygMing = Triple.isOSCygMing(); - bool IsIAMCU = Triple.isOSIAMCU(); - bool StaticLibgcc = Args.hasArg(options::OPT_static_libgcc) || - Args.hasArg(options::OPT_static); - if (!D.CCCIsCXX()) - CmdArgs.push_back("-lgcc"); - - if (StaticLibgcc || isAndroid) { - if (D.CCCIsCXX()) - CmdArgs.push_back("-lgcc"); - } else { - if (!D.CCCIsCXX() && !isCygMing) - CmdArgs.push_back("--as-needed"); - CmdArgs.push_back("-lgcc_s"); - if (!D.CCCIsCXX() && !isCygMing) - CmdArgs.push_back("--no-as-needed"); - } - - if (StaticLibgcc && !isAndroid && !IsIAMCU) - CmdArgs.push_back("-lgcc_eh"); - else if (!Args.hasArg(options::OPT_shared) && D.CCCIsCXX()) - CmdArgs.push_back("-lgcc"); - - // According to Android ABI, we have to link with libdl if we are - // linking with non-static libgcc. - // - // NOTE: This fixes a link error on Android MIPS as well. The non-static - // libgcc for MIPS relies on _Unwind_Find_FDE and dl_iterate_phdr from libdl. - if (isAndroid && !StaticLibgcc) - CmdArgs.push_back("-ldl"); -} - -static void AddRunTimeLibs(const ToolChain &TC, const Driver &D, - ArgStringList &CmdArgs, const ArgList &Args) { - // Make use of compiler-rt if --rtlib option is used - ToolChain::RuntimeLibType RLT = TC.GetRuntimeLibType(Args); - - 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; - } - break; - case ToolChain::RLT_Libgcc: - // Make sure libgcc is not used under MSVC environment by default - if (TC.getTriple().isKnownWindowsMSVCEnvironment()) { - // Issue error diagnostic if libgcc is explicitly specified - // through command line as --rtlib option argument. - if (Args.hasArg(options::OPT_rtlib_EQ)) { - TC.getDriver().Diag(diag::err_drv_unsupported_rtlib_for_platform) - << Args.getLastArg(options::OPT_rtlib_EQ)->getValue() << "MSVC"; - } - } else - AddLibgcc(TC.getTriple(), D, CmdArgs, Args); - break; - } -} - -static const char *getLDMOption(const llvm::Triple &T, const ArgList &Args) { - switch (T.getArch()) { - case llvm::Triple::x86: - if (T.isOSIAMCU()) - return "elf_iamcu"; - return "elf_i386"; - case llvm::Triple::aarch64: - return "aarch64linux"; - case llvm::Triple::aarch64_be: - return "aarch64_be_linux"; - case llvm::Triple::arm: - case llvm::Triple::thumb: - return "armelf_linux_eabi"; - case llvm::Triple::armeb: - case llvm::Triple::thumbeb: - return "armelfb_linux_eabi"; - case llvm::Triple::ppc: - return "elf32ppclinux"; - case llvm::Triple::ppc64: - return "elf64ppc"; - case llvm::Triple::ppc64le: - return "elf64lppc"; - case llvm::Triple::sparc: - case llvm::Triple::sparcel: - return "elf32_sparc"; - case llvm::Triple::sparcv9: - return "elf64_sparc"; - case llvm::Triple::mips: - return "elf32btsmip"; - case llvm::Triple::mipsel: - return "elf32ltsmip"; - case llvm::Triple::mips64: - if (mips::hasMipsAbiArg(Args, "n32")) - return "elf32btsmipn32"; - return "elf64btsmip"; - case llvm::Triple::mips64el: - if (mips::hasMipsAbiArg(Args, "n32")) - return "elf32ltsmipn32"; - return "elf64ltsmip"; - case llvm::Triple::systemz: - return "elf64_s390"; - case llvm::Triple::x86_64: - if (T.getEnvironment() == llvm::Triple::GNUX32) - return "elf32_x86_64"; - return "elf_x86_64"; - default: - return nullptr; - } -} - -void gnutools::Linker::ConstructJob(Compilation &C, const JobAction &JA, - const InputInfo &Output, - const InputInfoList &Inputs, - const ArgList &Args, - const char *LinkingOutput) const { - const toolchains::Linux &ToolChain = - static_cast<const toolchains::Linux &>(getToolChain()); - const Driver &D = ToolChain.getDriver(); - - const llvm::Triple &Triple = getToolChain().getEffectiveTriple(); - - const llvm::Triple::ArchType Arch = ToolChain.getArch(); - const bool isAndroid = ToolChain.getTriple().isAndroid(); - const bool IsIAMCU = ToolChain.getTriple().isOSIAMCU(); - const bool IsPIE = - !Args.hasArg(options::OPT_shared) && !Args.hasArg(options::OPT_static) && - (Args.hasArg(options::OPT_pie) || ToolChain.isPIEDefault()); - const bool HasCRTBeginEndFiles = - ToolChain.getTriple().hasEnvironment() || - (ToolChain.getTriple().getVendor() != llvm::Triple::MipsTechnologies); - - ArgStringList CmdArgs; - - // Silence warning for "clang -g foo.o -o foo" - Args.ClaimAllArgs(options::OPT_g_Group); - // and "clang -emit-llvm foo.o -o foo" - Args.ClaimAllArgs(options::OPT_emit_llvm); - // and for "clang -w foo.o -o foo". Other warning options are already - // handled somewhere else. - Args.ClaimAllArgs(options::OPT_w); - - const char *Exec = Args.MakeArgString(ToolChain.GetLinkerPath()); - if (llvm::sys::path::stem(Exec) == "lld") { - CmdArgs.push_back("-flavor"); - CmdArgs.push_back("old-gnu"); - CmdArgs.push_back("-target"); - CmdArgs.push_back(Args.MakeArgString(getToolChain().getTripleString())); - } - - if (!D.SysRoot.empty()) - CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot)); - - if (IsPIE) - CmdArgs.push_back("-pie"); - - if (Args.hasArg(options::OPT_rdynamic)) - CmdArgs.push_back("-export-dynamic"); - - if (Args.hasArg(options::OPT_s)) - CmdArgs.push_back("-s"); - - if (Arch == llvm::Triple::armeb || Arch == llvm::Triple::thumbeb) - arm::appendEBLinkFlags(Args, CmdArgs, Triple); - - // Most Android ARM64 targets should enable the linker fix for erratum - // 843419. Only non-Cortex-A53 devices are allowed to skip this flag. - if (Arch == llvm::Triple::aarch64 && isAndroid) { - std::string CPU = getCPUName(Args, Triple); - if (CPU.empty() || CPU == "generic" || CPU == "cortex-a53") - CmdArgs.push_back("--fix-cortex-a53-843419"); - } - - for (const auto &Opt : ToolChain.ExtraOpts) - CmdArgs.push_back(Opt.c_str()); - - if (!Args.hasArg(options::OPT_static)) { - CmdArgs.push_back("--eh-frame-hdr"); - } - - if (const char *LDMOption = getLDMOption(ToolChain.getTriple(), Args)) { - CmdArgs.push_back("-m"); - CmdArgs.push_back(LDMOption); - } else { - D.Diag(diag::err_target_unknown_triple) << Triple.str(); - return; - } - - if (Args.hasArg(options::OPT_static)) { - if (Arch == llvm::Triple::arm || Arch == llvm::Triple::armeb || - Arch == llvm::Triple::thumb || Arch == llvm::Triple::thumbeb) - CmdArgs.push_back("-Bstatic"); - else - CmdArgs.push_back("-static"); - } else if (Args.hasArg(options::OPT_shared)) { - CmdArgs.push_back("-shared"); - } - - if (!Args.hasArg(options::OPT_static)) { - if (Args.hasArg(options::OPT_rdynamic)) - CmdArgs.push_back("-export-dynamic"); - - if (!Args.hasArg(options::OPT_shared)) { - const std::string Loader = - D.DyldPrefix + ToolChain.getDynamicLinker(Args); - CmdArgs.push_back("-dynamic-linker"); - CmdArgs.push_back(Args.MakeArgString(Loader)); - } - } - - CmdArgs.push_back("-o"); - CmdArgs.push_back(Output.getFilename()); - - if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) { - if (!isAndroid && !IsIAMCU) { - const char *crt1 = nullptr; - if (!Args.hasArg(options::OPT_shared)) { - if (Args.hasArg(options::OPT_pg)) - crt1 = "gcrt1.o"; - else if (IsPIE) - crt1 = "Scrt1.o"; - else - crt1 = "crt1.o"; - } - if (crt1) - CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crt1))); - - CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crti.o"))); - } - - if (IsIAMCU) - CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crt0.o"))); - else { - const char *crtbegin; - if (Args.hasArg(options::OPT_static)) - crtbegin = isAndroid ? "crtbegin_static.o" : "crtbeginT.o"; - else if (Args.hasArg(options::OPT_shared)) - crtbegin = isAndroid ? "crtbegin_so.o" : "crtbeginS.o"; - else if (IsPIE) - crtbegin = isAndroid ? "crtbegin_dynamic.o" : "crtbeginS.o"; - else - crtbegin = isAndroid ? "crtbegin_dynamic.o" : "crtbegin.o"; - - if (HasCRTBeginEndFiles) - CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crtbegin))); - } - - // Add crtfastmath.o if available and fast math is enabled. - ToolChain.AddFastMathRuntimeIfAvailable(Args, CmdArgs); - } - - Args.AddAllArgs(CmdArgs, options::OPT_L); - Args.AddAllArgs(CmdArgs, options::OPT_u); - - ToolChain.AddFilePathLibArgs(Args, CmdArgs); - - if (D.isUsingLTO()) - AddGoldPlugin(ToolChain, Args, CmdArgs, D.getLTOMode() == LTOK_Thin, D); - - if (Args.hasArg(options::OPT_Z_Xlinker__no_demangle)) - CmdArgs.push_back("--no-demangle"); - - bool NeedsSanitizerDeps = addSanitizerRuntimes(ToolChain, Args, CmdArgs); - bool NeedsXRayDeps = addXRayRuntime(ToolChain, Args, CmdArgs); - AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA); - // The profile runtime also needs access to system libraries. - getToolChain().addProfileRTLibs(Args, CmdArgs); - - if (D.CCCIsCXX() && - !Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { - bool OnlyLibstdcxxStatic = Args.hasArg(options::OPT_static_libstdcxx) && - !Args.hasArg(options::OPT_static); - if (OnlyLibstdcxxStatic) - CmdArgs.push_back("-Bstatic"); - ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs); - if (OnlyLibstdcxxStatic) - CmdArgs.push_back("-Bdynamic"); - CmdArgs.push_back("-lm"); - } - // Silence warnings when linking C code with a C++ '-stdlib' argument. - Args.ClaimAllArgs(options::OPT_stdlib_EQ); - - if (!Args.hasArg(options::OPT_nostdlib)) { - if (!Args.hasArg(options::OPT_nodefaultlibs)) { - if (Args.hasArg(options::OPT_static)) - CmdArgs.push_back("--start-group"); - - if (NeedsSanitizerDeps) - linkSanitizerRuntimeDeps(ToolChain, CmdArgs); - - if (NeedsXRayDeps) - linkXRayRuntimeDeps(ToolChain, Args, CmdArgs); - - bool WantPthread = Args.hasArg(options::OPT_pthread) || - Args.hasArg(options::OPT_pthreads); - - if (Args.hasFlag(options::OPT_fopenmp, options::OPT_fopenmp_EQ, - options::OPT_fno_openmp, false)) { - // OpenMP runtimes implies pthreads when using the GNU toolchain. - // FIXME: Does this really make sense for all GNU toolchains? - WantPthread = true; - - // Also link the particular OpenMP runtimes. - switch (ToolChain.getDriver().getOpenMPRuntime(Args)) { - case Driver::OMPRT_OMP: - CmdArgs.push_back("-lomp"); - break; - case Driver::OMPRT_GOMP: - CmdArgs.push_back("-lgomp"); - - // FIXME: Exclude this for platforms with libgomp that don't require - // librt. Most modern Linux platforms require it, but some may not. - CmdArgs.push_back("-lrt"); - break; - case Driver::OMPRT_IOMP5: - CmdArgs.push_back("-liomp5"); - break; - case Driver::OMPRT_Unknown: - // Already diagnosed. - break; - } - if (JA.isHostOffloading(Action::OFK_OpenMP)) - CmdArgs.push_back("-lomptarget"); - - addArchSpecificRPath(ToolChain, Args, CmdArgs); - } - - AddRunTimeLibs(ToolChain, D, CmdArgs, Args); - - if (WantPthread && !isAndroid) - CmdArgs.push_back("-lpthread"); - - if (Args.hasArg(options::OPT_fsplit_stack)) - CmdArgs.push_back("--wrap=pthread_create"); - - CmdArgs.push_back("-lc"); - - // Add IAMCU specific libs, if needed. - if (IsIAMCU) - CmdArgs.push_back("-lgloss"); - - if (Args.hasArg(options::OPT_static)) - CmdArgs.push_back("--end-group"); - else - AddRunTimeLibs(ToolChain, D, CmdArgs, Args); - - // Add IAMCU specific libs (outside the group), if needed. - if (IsIAMCU) { - CmdArgs.push_back("--as-needed"); - CmdArgs.push_back("-lsoftfp"); - CmdArgs.push_back("--no-as-needed"); - } - } - - if (!Args.hasArg(options::OPT_nostartfiles) && !IsIAMCU) { - const char *crtend; - if (Args.hasArg(options::OPT_shared)) - crtend = isAndroid ? "crtend_so.o" : "crtendS.o"; - else if (IsPIE) - crtend = isAndroid ? "crtend_android.o" : "crtendS.o"; - else - crtend = isAndroid ? "crtend_android.o" : "crtend.o"; - - if (HasCRTBeginEndFiles) - CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crtend))); - if (!isAndroid) - CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtn.o"))); - } - } - - // Add OpenMP offloading linker script args if required. - AddOpenMPLinkerScript(getToolChain(), C, Output, Inputs, Args, CmdArgs, JA); - - C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); -} - -// NaCl ARM assembly (inline or standalone) can be written with a set of macros -// for the various SFI requirements like register masking. The assembly tool -// inserts the file containing the macros as an input into all the assembly -// jobs. -void nacltools::AssemblerARM::ConstructJob(Compilation &C, const JobAction &JA, - const InputInfo &Output, - const InputInfoList &Inputs, - const ArgList &Args, - const char *LinkingOutput) const { - const toolchains::NaClToolChain &ToolChain = - static_cast<const toolchains::NaClToolChain &>(getToolChain()); - InputInfo NaClMacros(types::TY_PP_Asm, ToolChain.GetNaClArmMacrosPath(), - "nacl-arm-macros.s"); - InputInfoList NewInputs; - NewInputs.push_back(NaClMacros); - NewInputs.append(Inputs.begin(), Inputs.end()); - gnutools::Assembler::ConstructJob(C, JA, Output, NewInputs, Args, - LinkingOutput); -} - -// This is quite similar to gnutools::Linker::ConstructJob with changes that -// we use static by default, do not yet support sanitizers or LTO, and a few -// others. Eventually we can support more of that and hopefully migrate back -// to gnutools::Linker. -void nacltools::Linker::ConstructJob(Compilation &C, const JobAction &JA, - const InputInfo &Output, - const InputInfoList &Inputs, - const ArgList &Args, - const char *LinkingOutput) const { - - const toolchains::NaClToolChain &ToolChain = - static_cast<const toolchains::NaClToolChain &>(getToolChain()); - const Driver &D = ToolChain.getDriver(); - const llvm::Triple::ArchType Arch = ToolChain.getArch(); - const bool IsStatic = - !Args.hasArg(options::OPT_dynamic) && !Args.hasArg(options::OPT_shared); - - ArgStringList CmdArgs; - - // Silence warning for "clang -g foo.o -o foo" - Args.ClaimAllArgs(options::OPT_g_Group); - // and "clang -emit-llvm foo.o -o foo" - Args.ClaimAllArgs(options::OPT_emit_llvm); - // and for "clang -w foo.o -o foo". Other warning options are already - // handled somewhere else. - Args.ClaimAllArgs(options::OPT_w); - - if (!D.SysRoot.empty()) - CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot)); - - if (Args.hasArg(options::OPT_rdynamic)) - CmdArgs.push_back("-export-dynamic"); - - if (Args.hasArg(options::OPT_s)) - CmdArgs.push_back("-s"); - - // NaClToolChain doesn't have ExtraOpts like Linux; the only relevant flag - // from there is --build-id, which we do want. - CmdArgs.push_back("--build-id"); - - if (!IsStatic) - CmdArgs.push_back("--eh-frame-hdr"); - - CmdArgs.push_back("-m"); - if (Arch == llvm::Triple::x86) - CmdArgs.push_back("elf_i386_nacl"); - else if (Arch == llvm::Triple::arm) - CmdArgs.push_back("armelf_nacl"); - else if (Arch == llvm::Triple::x86_64) - CmdArgs.push_back("elf_x86_64_nacl"); - else if (Arch == llvm::Triple::mipsel) - CmdArgs.push_back("mipselelf_nacl"); - else - D.Diag(diag::err_target_unsupported_arch) << ToolChain.getArchName() - << "Native Client"; - - if (IsStatic) - CmdArgs.push_back("-static"); - else if (Args.hasArg(options::OPT_shared)) - CmdArgs.push_back("-shared"); - - CmdArgs.push_back("-o"); - CmdArgs.push_back(Output.getFilename()); - if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) { - if (!Args.hasArg(options::OPT_shared)) - CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crt1.o"))); - CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crti.o"))); - - const char *crtbegin; - if (IsStatic) - crtbegin = "crtbeginT.o"; - else if (Args.hasArg(options::OPT_shared)) - crtbegin = "crtbeginS.o"; - else - crtbegin = "crtbegin.o"; - CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crtbegin))); - } - - Args.AddAllArgs(CmdArgs, options::OPT_L); - Args.AddAllArgs(CmdArgs, options::OPT_u); - - ToolChain.AddFilePathLibArgs(Args, CmdArgs); - - if (Args.hasArg(options::OPT_Z_Xlinker__no_demangle)) - CmdArgs.push_back("--no-demangle"); - - AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, 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"); - CmdArgs.push_back("-lm"); - } - - if (!Args.hasArg(options::OPT_nostdlib)) { - if (!Args.hasArg(options::OPT_nodefaultlibs)) { - // Always use groups, since it has no effect on dynamic libraries. - CmdArgs.push_back("--start-group"); - CmdArgs.push_back("-lc"); - // NaCl's libc++ currently requires libpthread, so just always include it - // in the group for C++. - if (Args.hasArg(options::OPT_pthread) || - Args.hasArg(options::OPT_pthreads) || D.CCCIsCXX()) { - // Gold, used by Mips, handles nested groups differently than ld, and - // without '-lnacl' it prefers symbols from libpthread.a over libnacl.a, - // which is not a desired behaviour here. - // See https://sourceware.org/ml/binutils/2015-03/msg00034.html - if (getToolChain().getArch() == llvm::Triple::mipsel) - CmdArgs.push_back("-lnacl"); - - CmdArgs.push_back("-lpthread"); - } - - CmdArgs.push_back("-lgcc"); - CmdArgs.push_back("--as-needed"); - if (IsStatic) - CmdArgs.push_back("-lgcc_eh"); - else - CmdArgs.push_back("-lgcc_s"); - CmdArgs.push_back("--no-as-needed"); - - // Mips needs to create and use pnacl_legacy library that contains - // definitions from bitcode/pnaclmm.c and definitions for - // __nacl_tp_tls_offset() and __nacl_tp_tdb_offset(). - if (getToolChain().getArch() == llvm::Triple::mipsel) - CmdArgs.push_back("-lpnacl_legacy"); - - CmdArgs.push_back("--end-group"); - } - - if (!Args.hasArg(options::OPT_nostartfiles)) { - const char *crtend; - if (Args.hasArg(options::OPT_shared)) - crtend = "crtendS.o"; - else - crtend = "crtend.o"; - - CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crtend))); - CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtn.o"))); - } - } - - const char *Exec = Args.MakeArgString(ToolChain.GetLinkerPath()); - C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); -} - -void fuchsia::Linker::ConstructJob(Compilation &C, const JobAction &JA, - const InputInfo &Output, - const InputInfoList &Inputs, - const ArgList &Args, - const char *LinkingOutput) const { - const toolchains::Fuchsia &ToolChain = - static_cast<const toolchains::Fuchsia &>(getToolChain()); - const Driver &D = ToolChain.getDriver(); - - ArgStringList CmdArgs; - - // Silence warning for "clang -g foo.o -o foo" - Args.ClaimAllArgs(options::OPT_g_Group); - // and "clang -emit-llvm foo.o -o foo" - Args.ClaimAllArgs(options::OPT_emit_llvm); - // and for "clang -w foo.o -o foo". Other warning options are already - // handled somewhere else. - Args.ClaimAllArgs(options::OPT_w); - - const char *Exec = Args.MakeArgString(ToolChain.GetLinkerPath()); - if (llvm::sys::path::stem(Exec).equals_lower("lld")) { - CmdArgs.push_back("-flavor"); - CmdArgs.push_back("gnu"); - } - - if (!D.SysRoot.empty()) - CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot)); - - if (!Args.hasArg(options::OPT_shared) && !Args.hasArg(options::OPT_r)) - CmdArgs.push_back("-pie"); - - if (Args.hasArg(options::OPT_rdynamic)) - CmdArgs.push_back("-export-dynamic"); - - if (Args.hasArg(options::OPT_s)) - CmdArgs.push_back("-s"); - - if (Args.hasArg(options::OPT_r)) - CmdArgs.push_back("-r"); - else - CmdArgs.push_back("--build-id"); - - if (!Args.hasArg(options::OPT_static)) - 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")); - } - } - - CmdArgs.push_back("-o"); - CmdArgs.push_back(Output.getFilename()); - - if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) { - if (!Args.hasArg(options::OPT_shared)) { - CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("Scrt1.o"))); - } - } - - Args.AddAllArgs(CmdArgs, options::OPT_L); - Args.AddAllArgs(CmdArgs, options::OPT_u); - - ToolChain.AddFilePathLibArgs(Args, CmdArgs); - - AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA); - - if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { - if (Args.hasArg(options::OPT_static)) - 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"); - CmdArgs.push_back("-lm"); - } - - AddRunTimeLibs(ToolChain, D, CmdArgs, Args); - - if (Args.hasArg(options::OPT_pthread) || - Args.hasArg(options::OPT_pthreads)) - CmdArgs.push_back("-lpthread"); - - if (Args.hasArg(options::OPT_fsplit_stack)) - CmdArgs.push_back("--wrap=pthread_create"); - - CmdArgs.push_back("-lc"); - } - - C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); -} - -void minix::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 minix::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 (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)) { - CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath("crt1.o"))); - CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath("crti.o"))); - CmdArgs.push_back( - Args.MakeArgString(getToolChain().GetFilePath("crtbegin.o"))); - CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath("crtn.o"))); - } - - Args.AddAllArgs(CmdArgs, - {options::OPT_L, options::OPT_T_Group, options::OPT_e}); - - AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA); - - getToolChain().addProfileRTLibs(Args, CmdArgs); - - if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { - if (D.CCCIsCXX()) { - getToolChain().AddCXXStdlibLibArgs(Args, CmdArgs); - CmdArgs.push_back("-lm"); - } - } - - if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) { - if (Args.hasArg(options::OPT_pthread)) - CmdArgs.push_back("-lpthread"); - CmdArgs.push_back("-lc"); - CmdArgs.push_back("-lCompilerRT-Generic"); - CmdArgs.push_back("-L/usr/pkg/compiler-rt/lib"); - CmdArgs.push_back( - Args.MakeArgString(getToolChain().GetFilePath("crtend.o"))); - } - - const char *Exec = Args.MakeArgString(getToolChain().GetLinkerPath()); - C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); -} - -/// DragonFly Tools - -// For now, DragonFly Assemble does just about the same as for -// FreeBSD, but this may change soon. -void dragonfly::Assembler::ConstructJob(Compilation &C, const JobAction &JA, - const InputInfo &Output, - const InputInfoList &Inputs, - const ArgList &Args, - const char *LinkingOutput) const { - claimNoWarnArgs(Args); - ArgStringList CmdArgs; - - // When building 32-bit code on DragonFly/pc64, we have to explicitly - // instruct as in the base system to assemble 32-bit code. - if (getToolChain().getArch() == llvm::Triple::x86) - CmdArgs.push_back("--32"); - - 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 dragonfly::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 (!D.SysRoot.empty()) - CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot)); - - CmdArgs.push_back("--eh-frame-hdr"); - if (Args.hasArg(options::OPT_static)) { - CmdArgs.push_back("-Bstatic"); - } else { - if (Args.hasArg(options::OPT_rdynamic)) - CmdArgs.push_back("-export-dynamic"); - if (Args.hasArg(options::OPT_shared)) - CmdArgs.push_back("-Bshareable"); - else { - CmdArgs.push_back("-dynamic-linker"); - CmdArgs.push_back("/usr/libexec/ld-elf.so.2"); - } - CmdArgs.push_back("--hash-style=gnu"); - CmdArgs.push_back("--enable-new-dtags"); - } - - // When building 32-bit code on DragonFly/pc64, we have to explicitly - // instruct ld in the base system to link 32-bit code. - if (getToolChain().getArch() == llvm::Triple::x86) { - CmdArgs.push_back("-m"); - CmdArgs.push_back("elf_i386"); - } - - 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("gcrt1.o"))); - else { - if (Args.hasArg(options::OPT_pie)) - CmdArgs.push_back( - Args.MakeArgString(getToolChain().GetFilePath("Scrt1.o"))); - else - CmdArgs.push_back( - Args.MakeArgString(getToolChain().GetFilePath("crt1.o"))); - } - } - CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath("crti.o"))); - if (Args.hasArg(options::OPT_shared) || Args.hasArg(options::OPT_pie)) - CmdArgs.push_back( - Args.MakeArgString(getToolChain().GetFilePath("crtbeginS.o"))); - else - CmdArgs.push_back( - Args.MakeArgString(getToolChain().GetFilePath("crtbegin.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)) { - CmdArgs.push_back("-L/usr/lib/gcc50"); - - if (!Args.hasArg(options::OPT_static)) { - CmdArgs.push_back("-rpath"); - CmdArgs.push_back("/usr/lib/gcc50"); - } - - if (D.CCCIsCXX()) { - getToolChain().AddCXXStdlibLibArgs(Args, CmdArgs); - CmdArgs.push_back("-lm"); - } - - if (Args.hasArg(options::OPT_pthread)) - CmdArgs.push_back("-lpthread"); - - if (!Args.hasArg(options::OPT_nolibc)) { - CmdArgs.push_back("-lc"); - } - - if (Args.hasArg(options::OPT_static) || - Args.hasArg(options::OPT_static_libgcc)) { - CmdArgs.push_back("-lgcc"); - CmdArgs.push_back("-lgcc_eh"); - } else { - if (Args.hasArg(options::OPT_shared_libgcc)) { - CmdArgs.push_back("-lgcc_pic"); - if (!Args.hasArg(options::OPT_shared)) - CmdArgs.push_back("-lgcc"); - } else { - CmdArgs.push_back("-lgcc"); - CmdArgs.push_back("--as-needed"); - CmdArgs.push_back("-lgcc_pic"); - CmdArgs.push_back("--no-as-needed"); - } - } - } - - if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) { - if (Args.hasArg(options::OPT_shared) || Args.hasArg(options::OPT_pie)) - CmdArgs.push_back( - Args.MakeArgString(getToolChain().GetFilePath("crtendS.o"))); - else - CmdArgs.push_back( - Args.MakeArgString(getToolChain().GetFilePath("crtend.o"))); - CmdArgs.push_back(Args.MakeArgString(getToolChain().GetFilePath("crtn.o"))); - } - - getToolChain().addProfileRTLibs(Args, CmdArgs); - - const char *Exec = Args.MakeArgString(getToolChain().GetLinkerPath()); - C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); -} - -// Try to find Exe from a Visual Studio distribution. This first tries to find -// an installed copy of Visual Studio and, failing that, looks in the PATH, -// making sure that whatever executable that's found is not a same-named exe -// from clang itself to prevent clang from falling back to itself. -static std::string FindVisualStudioExecutable(const ToolChain &TC, - const char *Exe, - const char *ClangProgramPath) { - const auto &MSVC = static_cast<const toolchains::MSVCToolChain &>(TC); - std::string visualStudioBinDir; - if (MSVC.getVisualStudioBinariesFolder(ClangProgramPath, - visualStudioBinDir)) { - SmallString<128> FilePath(visualStudioBinDir); - llvm::sys::path::append(FilePath, Exe); - if (llvm::sys::fs::can_execute(FilePath.c_str())) - return FilePath.str(); - } - - return Exe; -} - -void visualstudio::Linker::ConstructJob(Compilation &C, const JobAction &JA, - const InputInfo &Output, - const InputInfoList &Inputs, - const ArgList &Args, - const char *LinkingOutput) const { - ArgStringList CmdArgs; - const ToolChain &TC = getToolChain(); - - assert((Output.isFilename() || Output.isNothing()) && "invalid output"); - if (Output.isFilename()) - CmdArgs.push_back( - Args.MakeArgString(std::string("-out:") + Output.getFilename())); - - if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles) && - !C.getDriver().IsCLMode()) - CmdArgs.push_back("-defaultlib:libcmt"); - - if (!llvm::sys::Process::GetEnv("LIB")) { - // If the VC environment hasn't been configured (perhaps because the user - // did not run vcvarsall), try to build a consistent link environment. If - // the environment variable is set however, assume the user knows what - // they're doing. - std::string VisualStudioDir; - const auto &MSVC = static_cast<const toolchains::MSVCToolChain &>(TC); - if (MSVC.getVisualStudioInstallDir(VisualStudioDir)) { - SmallString<128> LibDir(VisualStudioDir); - llvm::sys::path::append(LibDir, "VC", "lib"); - switch (MSVC.getArch()) { - case llvm::Triple::x86: - // x86 just puts the libraries directly in lib - break; - case llvm::Triple::x86_64: - llvm::sys::path::append(LibDir, "amd64"); - break; - case llvm::Triple::arm: - llvm::sys::path::append(LibDir, "arm"); - break; - default: - break; - } - CmdArgs.push_back( - Args.MakeArgString(std::string("-libpath:") + LibDir.c_str())); - - if (MSVC.useUniversalCRT(VisualStudioDir)) { - std::string UniversalCRTLibPath; - if (MSVC.getUniversalCRTLibraryPath(UniversalCRTLibPath)) - CmdArgs.push_back(Args.MakeArgString(std::string("-libpath:") + - UniversalCRTLibPath)); - } - } - - std::string WindowsSdkLibPath; - if (MSVC.getWindowsSDKLibraryPath(WindowsSdkLibPath)) - CmdArgs.push_back( - Args.MakeArgString(std::string("-libpath:") + WindowsSdkLibPath)); - } - - if (!C.getDriver().IsCLMode() && Args.hasArg(options::OPT_L)) - for (const auto &LibPath : Args.getAllArgValues(options::OPT_L)) - CmdArgs.push_back(Args.MakeArgString("-libpath:" + LibPath)); - - CmdArgs.push_back("-nologo"); - - if (Args.hasArg(options::OPT_g_Group, options::OPT__SLASH_Z7, - options::OPT__SLASH_Zd)) - CmdArgs.push_back("-debug"); - - bool DLL = Args.hasArg(options::OPT__SLASH_LD, options::OPT__SLASH_LDd, - options::OPT_shared); - if (DLL) { - CmdArgs.push_back(Args.MakeArgString("-dll")); - - SmallString<128> ImplibName(Output.getFilename()); - llvm::sys::path::replace_extension(ImplibName, "lib"); - CmdArgs.push_back(Args.MakeArgString(std::string("-implib:") + ImplibName)); - } - - if (TC.getSanitizerArgs().needsAsanRt()) { - CmdArgs.push_back(Args.MakeArgString("-debug")); - CmdArgs.push_back(Args.MakeArgString("-incremental:no")); - if (TC.getSanitizerArgs().needsSharedAsanRt() || - 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)); - // Make sure the dynamic runtime thunk is not optimized out at link time - // to ensure proper SEH handling. - CmdArgs.push_back(Args.MakeArgString( - TC.getArch() == llvm::Triple::x86 - ? "-include:___asan_seh_interceptor" - : "-include:__asan_seh_interceptor")); - // Make sure the linker consider all object files from the dynamic runtime - // thunk. - CmdArgs.push_back(Args.MakeArgString(std::string("-wholearchive:") + - TC.getCompilerRT(Args, "asan_dynamic_runtime_thunk"))); - } else if (DLL) { - CmdArgs.push_back(TC.getCompilerRTArgString(Args, "asan_dll_thunk")); - } else { - for (const auto &Lib : {"asan", "asan_cxx"}) { - CmdArgs.push_back(TC.getCompilerRTArgString(Args, Lib)); - // Make sure the linker consider all object files from the static lib. - // This is necessary because instrumented dlls need access to all the - // interface exported by the static lib in the main executable. - CmdArgs.push_back(Args.MakeArgString(std::string("-wholearchive:") + - TC.getCompilerRT(Args, Lib))); - } - } - } - - Args.AddAllArgValues(CmdArgs, options::OPT__SLASH_link); - - if (Args.hasFlag(options::OPT_fopenmp, options::OPT_fopenmp_EQ, - options::OPT_fno_openmp, false)) { - CmdArgs.push_back("-nodefaultlib:vcomp.lib"); - CmdArgs.push_back("-nodefaultlib:vcompd.lib"); - CmdArgs.push_back(Args.MakeArgString(std::string("-libpath:") + - TC.getDriver().Dir + "/../lib")); - switch (TC.getDriver().getOpenMPRuntime(Args)) { - case Driver::OMPRT_OMP: - CmdArgs.push_back("-defaultlib:libomp.lib"); - break; - case Driver::OMPRT_IOMP5: - CmdArgs.push_back("-defaultlib:libiomp5md.lib"); - break; - case Driver::OMPRT_GOMP: - break; - case Driver::OMPRT_Unknown: - // Already diagnosed. - break; - } - } - - // Add compiler-rt lib in case if it was explicitly - // specified as an argument for --rtlib option. - if (!Args.hasArg(options::OPT_nostdlib)) { - AddRunTimeLibs(TC, TC.getDriver(), CmdArgs, Args); - } - - // Add filenames, libraries, and other linker inputs. - for (const auto &Input : Inputs) { - if (Input.isFilename()) { - CmdArgs.push_back(Input.getFilename()); - continue; - } - - const Arg &A = Input.getInputArg(); - - // Render -l options differently for the MSVC linker. - if (A.getOption().matches(options::OPT_l)) { - StringRef Lib = A.getValue(); - const char *LinkLibArg; - if (Lib.endswith(".lib")) - LinkLibArg = Args.MakeArgString(Lib); - else - LinkLibArg = Args.MakeArgString(Lib + ".lib"); - CmdArgs.push_back(LinkLibArg); - continue; - } - - // Otherwise, this is some other kind of linker input option like -Wl, -z, - // or -L. Render it, even if MSVC doesn't understand it. - A.renderAsInput(Args, CmdArgs); - } - - TC.addProfileRTLibs(Args, CmdArgs); - - // We need to special case some linker paths. In the case of lld, we need to - // translate 'lld' into 'lld-link', and in the case of the regular msvc - // linker, we need to use a special search algorithm. - llvm::SmallString<128> linkPath; - StringRef Linker = Args.getLastArgValue(options::OPT_fuse_ld_EQ, "link"); - if (Linker.equals_lower("lld")) - Linker = "lld-link"; - - if (Linker.equals_lower("link")) { - // If we're using the MSVC linker, it's not sufficient to just use link - // from the program PATH, because other environments like GnuWin32 install - // their own link.exe which may come first. - linkPath = FindVisualStudioExecutable(TC, "link.exe", - C.getDriver().getClangProgramPath()); - } else { - linkPath = Linker; - llvm::sys::path::replace_extension(linkPath, "exe"); - linkPath = TC.GetProgramPath(linkPath.c_str()); - } - - const char *Exec = Args.MakeArgString(linkPath); - C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); -} - -void visualstudio::Compiler::ConstructJob(Compilation &C, const JobAction &JA, - const InputInfo &Output, - const InputInfoList &Inputs, - const ArgList &Args, - const char *LinkingOutput) const { - C.addCommand(GetCommand(C, JA, Output, Inputs, Args, LinkingOutput)); -} - -std::unique_ptr<Command> visualstudio::Compiler::GetCommand( - Compilation &C, const JobAction &JA, const InputInfo &Output, - const InputInfoList &Inputs, const ArgList &Args, - const char *LinkingOutput) const { - ArgStringList CmdArgs; - CmdArgs.push_back("/nologo"); - CmdArgs.push_back("/c"); // Compile only. - CmdArgs.push_back("/W0"); // No warnings. - - // The goal is to be able to invoke this tool correctly based on - // any flag accepted by clang-cl. - - // These are spelled the same way in clang and cl.exe,. - Args.AddAllArgs(CmdArgs, {options::OPT_D, options::OPT_U, options::OPT_I}); - - // Optimization level. - if (Arg *A = Args.getLastArg(options::OPT_fbuiltin, options::OPT_fno_builtin)) - CmdArgs.push_back(A->getOption().getID() == options::OPT_fbuiltin ? "/Oi" - : "/Oi-"); - if (Arg *A = Args.getLastArg(options::OPT_O, options::OPT_O0)) { - if (A->getOption().getID() == options::OPT_O0) { - CmdArgs.push_back("/Od"); - } else { - CmdArgs.push_back("/Og"); - - StringRef OptLevel = A->getValue(); - if (OptLevel == "s" || OptLevel == "z") - CmdArgs.push_back("/Os"); - else - CmdArgs.push_back("/Ot"); - - CmdArgs.push_back("/Ob2"); - } - } - if (Arg *A = Args.getLastArg(options::OPT_fomit_frame_pointer, - options::OPT_fno_omit_frame_pointer)) - CmdArgs.push_back(A->getOption().getID() == options::OPT_fomit_frame_pointer - ? "/Oy" - : "/Oy-"); - if (!Args.hasArg(options::OPT_fwritable_strings)) - CmdArgs.push_back("/GF"); - - // Flags for which clang-cl has an alias. - // FIXME: How can we ensure this stays in sync with relevant clang-cl options? - - if (Args.hasFlag(options::OPT__SLASH_GR_, options::OPT__SLASH_GR, - /*default=*/false)) - CmdArgs.push_back("/GR-"); - - if (Args.hasFlag(options::OPT__SLASH_GS_, options::OPT__SLASH_GS, - /*default=*/false)) - CmdArgs.push_back("/GS-"); - - if (Arg *A = Args.getLastArg(options::OPT_ffunction_sections, - options::OPT_fno_function_sections)) - CmdArgs.push_back(A->getOption().getID() == options::OPT_ffunction_sections - ? "/Gy" - : "/Gy-"); - if (Arg *A = Args.getLastArg(options::OPT_fdata_sections, - options::OPT_fno_data_sections)) - CmdArgs.push_back( - A->getOption().getID() == options::OPT_fdata_sections ? "/Gw" : "/Gw-"); - if (Args.hasArg(options::OPT_fsyntax_only)) - CmdArgs.push_back("/Zs"); - if (Args.hasArg(options::OPT_g_Flag, options::OPT_gline_tables_only, - options::OPT__SLASH_Z7)) - CmdArgs.push_back("/Z7"); - - std::vector<std::string> Includes = - Args.getAllArgValues(options::OPT_include); - for (const auto &Include : Includes) - CmdArgs.push_back(Args.MakeArgString(std::string("/FI") + Include)); - - // Flags that can simply be passed through. - Args.AddAllArgs(CmdArgs, options::OPT__SLASH_LD); - Args.AddAllArgs(CmdArgs, options::OPT__SLASH_LDd); - Args.AddAllArgs(CmdArgs, options::OPT__SLASH_GX); - Args.AddAllArgs(CmdArgs, options::OPT__SLASH_GX_); - Args.AddAllArgs(CmdArgs, options::OPT__SLASH_EH); - Args.AddAllArgs(CmdArgs, options::OPT__SLASH_Zl); - - // The order of these flags is relevant, so pick the last one. - if (Arg *A = Args.getLastArg(options::OPT__SLASH_MD, options::OPT__SLASH_MDd, - options::OPT__SLASH_MT, options::OPT__SLASH_MTd)) - A->render(Args, CmdArgs); - - // Use MSVC's default threadsafe statics behaviour unless there was a flag. - if (Arg *A = Args.getLastArg(options::OPT_fthreadsafe_statics, - options::OPT_fno_threadsafe_statics)) { - CmdArgs.push_back(A->getOption().getID() == options::OPT_fthreadsafe_statics - ? "/Zc:threadSafeInit" - : "/Zc:threadSafeInit-"); - } - - // Pass through all unknown arguments so that the fallback command can see - // them too. - Args.AddAllArgs(CmdArgs, options::OPT_UNKNOWN); - - // Input filename. - assert(Inputs.size() == 1); - const InputInfo &II = Inputs[0]; - assert(II.getType() == types::TY_C || II.getType() == types::TY_CXX); - CmdArgs.push_back(II.getType() == types::TY_C ? "/Tc" : "/Tp"); - if (II.isFilename()) - CmdArgs.push_back(II.getFilename()); - else - II.getInputArg().renderAsInput(Args, CmdArgs); - - // Output filename. - assert(Output.getType() == types::TY_Object); - const char *Fo = - Args.MakeArgString(std::string("/Fo") + Output.getFilename()); - CmdArgs.push_back(Fo); - - const Driver &D = getToolChain().getDriver(); - std::string Exec = FindVisualStudioExecutable(getToolChain(), "cl.exe", - D.getClangProgramPath()); - return llvm::make_unique<Command>(JA, *this, Args.MakeArgString(Exec), - CmdArgs, Inputs); -} - -/// MinGW Tools -void MinGW::Assembler::ConstructJob(Compilation &C, const JobAction &JA, - const InputInfo &Output, - const InputInfoList &Inputs, - const ArgList &Args, - const char *LinkingOutput) const { - claimNoWarnArgs(Args); - ArgStringList CmdArgs; - - if (getToolChain().getArch() == llvm::Triple::x86) { - CmdArgs.push_back("--32"); - } else if (getToolChain().getArch() == llvm::Triple::x86_64) { - CmdArgs.push_back("--64"); - } - - 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)); - - if (Args.hasArg(options::OPT_gsplit_dwarf)) - SplitDebugInfo(getToolChain(), C, *this, JA, Args, Output, - SplitDebugName(Args, Inputs[0])); -} - -void MinGW::Linker::AddLibGCC(const ArgList &Args, - ArgStringList &CmdArgs) const { - if (Args.hasArg(options::OPT_mthreads)) - CmdArgs.push_back("-lmingwthrd"); - CmdArgs.push_back("-lmingw32"); - - // Make use of compiler-rt if --rtlib option is used - ToolChain::RuntimeLibType RLT = getToolChain().GetRuntimeLibType(Args); - if (RLT == ToolChain::RLT_Libgcc) { - bool Static = Args.hasArg(options::OPT_static_libgcc) || - Args.hasArg(options::OPT_static); - bool Shared = Args.hasArg(options::OPT_shared); - bool CXX = getToolChain().getDriver().CCCIsCXX(); - - if (Static || (!CXX && !Shared)) { - CmdArgs.push_back("-lgcc"); - CmdArgs.push_back("-lgcc_eh"); - } else { - CmdArgs.push_back("-lgcc_s"); - CmdArgs.push_back("-lgcc"); - } - } else { - AddRunTimeLibs(getToolChain(), getToolChain().getDriver(), CmdArgs, Args); - } - - CmdArgs.push_back("-lmoldname"); - CmdArgs.push_back("-lmingwex"); - CmdArgs.push_back("-lmsvcrt"); -} - -void MinGW::Linker::ConstructJob(Compilation &C, const JobAction &JA, - const InputInfo &Output, - const InputInfoList &Inputs, - const ArgList &Args, - const char *LinkingOutput) const { - const ToolChain &TC = getToolChain(); - const Driver &D = TC.getDriver(); - // const SanitizerArgs &Sanitize = TC.getSanitizerArgs(); - - ArgStringList CmdArgs; - - // Silence warning for "clang -g foo.o -o foo" - Args.ClaimAllArgs(options::OPT_g_Group); - // and "clang -emit-llvm foo.o -o foo" - Args.ClaimAllArgs(options::OPT_emit_llvm); - // and for "clang -w foo.o -o foo". Other warning options are already - // handled somewhere else. - Args.ClaimAllArgs(options::OPT_w); - - 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)); - - if (Args.hasArg(options::OPT_s)) - CmdArgs.push_back("-s"); - - CmdArgs.push_back("-m"); - if (TC.getArch() == llvm::Triple::x86) - CmdArgs.push_back("i386pe"); - if (TC.getArch() == llvm::Triple::x86_64) - CmdArgs.push_back("i386pep"); - if (TC.getArch() == llvm::Triple::arm) - CmdArgs.push_back("thumb2pe"); - - if (Args.hasArg(options::OPT_mwindows)) { - CmdArgs.push_back("--subsystem"); - CmdArgs.push_back("windows"); - } else if (Args.hasArg(options::OPT_mconsole)) { - CmdArgs.push_back("--subsystem"); - CmdArgs.push_back("console"); - } - - if (Args.hasArg(options::OPT_static)) - CmdArgs.push_back("-Bstatic"); - else { - if (Args.hasArg(options::OPT_mdll)) - CmdArgs.push_back("--dll"); - else if (Args.hasArg(options::OPT_shared)) - CmdArgs.push_back("--shared"); - CmdArgs.push_back("-Bdynamic"); - if (Args.hasArg(options::OPT_mdll) || Args.hasArg(options::OPT_shared)) { - CmdArgs.push_back("-e"); - if (TC.getArch() == llvm::Triple::x86) - CmdArgs.push_back("_DllMainCRTStartup@12"); - else - CmdArgs.push_back("DllMainCRTStartup"); - CmdArgs.push_back("--enable-auto-image-base"); - } - } - - CmdArgs.push_back("-o"); - CmdArgs.push_back(Output.getFilename()); - - Args.AddAllArgs(CmdArgs, options::OPT_e); - // FIXME: add -N, -n flags - Args.AddLastArg(CmdArgs, options::OPT_r); - Args.AddLastArg(CmdArgs, options::OPT_s); - Args.AddLastArg(CmdArgs, options::OPT_t); - Args.AddAllArgs(CmdArgs, options::OPT_u_Group); - Args.AddLastArg(CmdArgs, options::OPT_Z_Flag); - - if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) { - if (Args.hasArg(options::OPT_shared) || Args.hasArg(options::OPT_mdll)) { - CmdArgs.push_back(Args.MakeArgString(TC.GetFilePath("dllcrt2.o"))); - } else { - if (Args.hasArg(options::OPT_municode)) - CmdArgs.push_back(Args.MakeArgString(TC.GetFilePath("crt2u.o"))); - else - CmdArgs.push_back(Args.MakeArgString(TC.GetFilePath("crt2.o"))); - } - if (Args.hasArg(options::OPT_pg)) - CmdArgs.push_back(Args.MakeArgString(TC.GetFilePath("gcrt2.o"))); - CmdArgs.push_back(Args.MakeArgString(TC.GetFilePath("crtbegin.o"))); - } - - Args.AddAllArgs(CmdArgs, options::OPT_L); - TC.AddFilePathLibArgs(Args, CmdArgs); - AddLinkerInputs(TC, Inputs, Args, CmdArgs, JA); - - // TODO: Add ASan stuff here - - // TODO: Add profile stuff here - - 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"); - TC.AddCXXStdlibLibArgs(Args, CmdArgs); - if (OnlyLibstdcxxStatic) - CmdArgs.push_back("-Bdynamic"); - } - - if (!Args.hasArg(options::OPT_nostdlib)) { - if (!Args.hasArg(options::OPT_nodefaultlibs)) { - if (Args.hasArg(options::OPT_static)) - CmdArgs.push_back("--start-group"); - - if (Args.hasArg(options::OPT_fstack_protector) || - Args.hasArg(options::OPT_fstack_protector_strong) || - Args.hasArg(options::OPT_fstack_protector_all)) { - CmdArgs.push_back("-lssp_nonshared"); - CmdArgs.push_back("-lssp"); - } - if (Args.hasArg(options::OPT_fopenmp)) - CmdArgs.push_back("-lgomp"); - - AddLibGCC(Args, CmdArgs); - - if (Args.hasArg(options::OPT_pg)) - CmdArgs.push_back("-lgmon"); - - if (Args.hasArg(options::OPT_pthread)) - CmdArgs.push_back("-lpthread"); - - // add system libraries - if (Args.hasArg(options::OPT_mwindows)) { - CmdArgs.push_back("-lgdi32"); - CmdArgs.push_back("-lcomdlg32"); - } - CmdArgs.push_back("-ladvapi32"); - CmdArgs.push_back("-lshell32"); - CmdArgs.push_back("-luser32"); - CmdArgs.push_back("-lkernel32"); - - if (Args.hasArg(options::OPT_static)) - CmdArgs.push_back("--end-group"); - else if (!LinkerName.equals_lower("lld")) - AddLibGCC(Args, CmdArgs); - } - - if (!Args.hasArg(options::OPT_nostartfiles)) { - // Add crtfastmath.o if available and fast math is enabled. - TC.AddFastMathRuntimeIfAvailable(Args, CmdArgs); - - CmdArgs.push_back(Args.MakeArgString(TC.GetFilePath("crtend.o"))); - } - } - const char *Exec = Args.MakeArgString(TC.GetProgramPath(LinkerName.data())); - C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); -} - -/// XCore Tools -// We pass assemble and link construction to the xcc tool. - -void XCore::Assembler::ConstructJob(Compilation &C, const JobAction &JA, - const InputInfo &Output, - const InputInfoList &Inputs, - const ArgList &Args, - const char *LinkingOutput) const { - claimNoWarnArgs(Args); - ArgStringList CmdArgs; - - CmdArgs.push_back("-o"); - CmdArgs.push_back(Output.getFilename()); - - CmdArgs.push_back("-c"); - - if (Args.hasArg(options::OPT_v)) - CmdArgs.push_back("-v"); - - if (Arg *A = Args.getLastArg(options::OPT_g_Group)) - if (!A->getOption().matches(options::OPT_g0)) - CmdArgs.push_back("-g"); - - if (Args.hasFlag(options::OPT_fverbose_asm, options::OPT_fno_verbose_asm, - false)) - CmdArgs.push_back("-fverbose-asm"); - - Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler); - - for (const auto &II : Inputs) - CmdArgs.push_back(II.getFilename()); - - const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("xcc")); - C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); -} - -void XCore::Linker::ConstructJob(Compilation &C, const JobAction &JA, - const InputInfo &Output, - const InputInfoList &Inputs, - const ArgList &Args, - const char *LinkingOutput) const { - ArgStringList CmdArgs; - - if (Output.isFilename()) { - CmdArgs.push_back("-o"); - CmdArgs.push_back(Output.getFilename()); - } else { - assert(Output.isNothing() && "Invalid output."); - } - - if (Args.hasArg(options::OPT_v)) - CmdArgs.push_back("-v"); - - // Pass -fexceptions through to the linker if it was present. - if (Args.hasFlag(options::OPT_fexceptions, options::OPT_fno_exceptions, - false)) - CmdArgs.push_back("-fexceptions"); - - AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA); - - const char *Exec = Args.MakeArgString(getToolChain().GetProgramPath("xcc")); - C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); -} - -void CrossWindows::Assembler::ConstructJob(Compilation &C, const JobAction &JA, - const InputInfo &Output, - const InputInfoList &Inputs, - const ArgList &Args, - const char *LinkingOutput) const { - claimNoWarnArgs(Args); - const auto &TC = - static_cast<const toolchains::CrossWindowsToolChain &>(getToolChain()); - ArgStringList CmdArgs; - const char *Exec; - - switch (TC.getArch()) { - default: - llvm_unreachable("unsupported architecture"); - case llvm::Triple::arm: - case llvm::Triple::thumb: - break; - case llvm::Triple::x86: - CmdArgs.push_back("--32"); - break; - case llvm::Triple::x86_64: - CmdArgs.push_back("--64"); - break; - } - - Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler); - - CmdArgs.push_back("-o"); - CmdArgs.push_back(Output.getFilename()); - - for (const auto &Input : Inputs) - CmdArgs.push_back(Input.getFilename()); - - const std::string Assembler = TC.GetProgramPath("as"); - Exec = Args.MakeArgString(Assembler); - - C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); -} - -void CrossWindows::Linker::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::CrossWindowsToolChain &>(getToolChain()); - const llvm::Triple &T = TC.getTriple(); - const Driver &D = TC.getDriver(); - SmallString<128> EntryPoint; - ArgStringList CmdArgs; - const char *Exec; - - // Silence warning for "clang -g foo.o -o foo" - Args.ClaimAllArgs(options::OPT_g_Group); - // and "clang -emit-llvm foo.o -o foo" - Args.ClaimAllArgs(options::OPT_emit_llvm); - // and for "clang -w foo.o -o foo" - Args.ClaimAllArgs(options::OPT_w); - // Other warning options are already handled somewhere else. - - if (!D.SysRoot.empty()) - CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot)); - - if (Args.hasArg(options::OPT_pie)) - CmdArgs.push_back("-pie"); - if (Args.hasArg(options::OPT_rdynamic)) - CmdArgs.push_back("-export-dynamic"); - if (Args.hasArg(options::OPT_s)) - CmdArgs.push_back("--strip-all"); - - CmdArgs.push_back("-m"); - switch (TC.getArch()) { - default: - llvm_unreachable("unsupported architecture"); - case llvm::Triple::arm: - case llvm::Triple::thumb: - // FIXME: this is incorrect for WinCE - CmdArgs.push_back("thumb2pe"); - break; - case llvm::Triple::x86: - CmdArgs.push_back("i386pe"); - EntryPoint.append("_"); - break; - case llvm::Triple::x86_64: - CmdArgs.push_back("i386pep"); - break; - } - - if (Args.hasArg(options::OPT_shared)) { - switch (T.getArch()) { - default: - llvm_unreachable("unsupported architecture"); - case llvm::Triple::arm: - case llvm::Triple::thumb: - case llvm::Triple::x86_64: - EntryPoint.append("_DllMainCRTStartup"); - break; - case llvm::Triple::x86: - EntryPoint.append("_DllMainCRTStartup@12"); - break; - } - - CmdArgs.push_back("-shared"); - CmdArgs.push_back("-Bdynamic"); - - CmdArgs.push_back("--enable-auto-image-base"); - - CmdArgs.push_back("--entry"); - CmdArgs.push_back(Args.MakeArgString(EntryPoint)); - } else { - EntryPoint.append("mainCRTStartup"); - - CmdArgs.push_back(Args.hasArg(options::OPT_static) ? "-Bstatic" - : "-Bdynamic"); - - if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) { - CmdArgs.push_back("--entry"); - CmdArgs.push_back(Args.MakeArgString(EntryPoint)); - } - - // FIXME: handle subsystem - } - - // NOTE: deal with multiple definitions on Windows (e.g. COMDAT) - CmdArgs.push_back("--allow-multiple-definition"); - - CmdArgs.push_back("-o"); - CmdArgs.push_back(Output.getFilename()); - - if (Args.hasArg(options::OPT_shared) || Args.hasArg(options::OPT_rdynamic)) { - SmallString<261> ImpLib(Output.getFilename()); - llvm::sys::path::replace_extension(ImpLib, ".lib"); - - CmdArgs.push_back("--out-implib"); - CmdArgs.push_back(Args.MakeArgString(ImpLib)); - } - - if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) { - const std::string CRTPath(D.SysRoot + "/usr/lib/"); - const char *CRTBegin; - - CRTBegin = - Args.hasArg(options::OPT_shared) ? "crtbeginS.obj" : "crtbegin.obj"; - CmdArgs.push_back(Args.MakeArgString(CRTPath + CRTBegin)); - } - - Args.AddAllArgs(CmdArgs, options::OPT_L); - TC.AddFilePathLibArgs(Args, CmdArgs); - AddLinkerInputs(TC, Inputs, Args, CmdArgs, JA); - - if (D.CCCIsCXX() && !Args.hasArg(options::OPT_nostdlib) && - !Args.hasArg(options::OPT_nodefaultlibs)) { - bool StaticCXX = Args.hasArg(options::OPT_static_libstdcxx) && - !Args.hasArg(options::OPT_static); - if (StaticCXX) - CmdArgs.push_back("-Bstatic"); - TC.AddCXXStdlibLibArgs(Args, CmdArgs); - if (StaticCXX) - CmdArgs.push_back("-Bdynamic"); - } - - if (!Args.hasArg(options::OPT_nostdlib)) { - if (!Args.hasArg(options::OPT_nodefaultlibs)) { - // TODO handle /MT[d] /MD[d] - CmdArgs.push_back("-lmsvcrt"); - AddRunTimeLibs(TC, D, CmdArgs, Args); - } - } - - if (TC.getSanitizerArgs().needsAsanRt()) { - // TODO handle /MT[d] /MD[d] - if (Args.hasArg(options::OPT_shared)) { - CmdArgs.push_back(TC.getCompilerRTArgString(Args, "asan_dll_thunk")); - } else { - for (const auto &Lib : {"asan_dynamic", "asan_dynamic_runtime_thunk"}) - CmdArgs.push_back(TC.getCompilerRTArgString(Args, Lib)); - // Make sure the dynamic runtime thunk is not optimized out at link time - // to ensure proper SEH handling. - CmdArgs.push_back(Args.MakeArgString("--undefined")); - CmdArgs.push_back(Args.MakeArgString(TC.getArch() == llvm::Triple::x86 - ? "___asan_seh_interceptor" - : "__asan_seh_interceptor")); - } - } - - Exec = Args.MakeArgString(TC.GetLinkerPath()); - - C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); -} - -void tools::SHAVE::Compiler::ConstructJob(Compilation &C, const JobAction &JA, - const InputInfo &Output, - const InputInfoList &Inputs, - const ArgList &Args, - const char *LinkingOutput) const { - ArgStringList CmdArgs; - assert(Inputs.size() == 1); - const InputInfo &II = Inputs[0]; - assert(II.getType() == types::TY_C || II.getType() == types::TY_CXX || - II.getType() == types::TY_PP_CXX); - - if (JA.getKind() == Action::PreprocessJobClass) { - Args.ClaimAllArgs(); - CmdArgs.push_back("-E"); - } else { - assert(Output.getType() == types::TY_PP_Asm); // Require preprocessed asm. - CmdArgs.push_back("-S"); - CmdArgs.push_back("-fno-exceptions"); // Always do this even if unspecified. - } - CmdArgs.push_back("-DMYRIAD2"); - - // Append all -I, -iquote, -isystem paths, defines/undefines, - // 'f' flags, optimize flags, and warning options. - // These are spelled the same way in clang and moviCompile. - Args.AddAllArgsExcept( - CmdArgs, - {options::OPT_I_Group, options::OPT_clang_i_Group, options::OPT_std_EQ, - options::OPT_D, options::OPT_U, options::OPT_f_Group, - options::OPT_f_clang_Group, options::OPT_g_Group, options::OPT_M_Group, - options::OPT_O_Group, options::OPT_W_Group, options::OPT_mcpu_EQ}, - {options::OPT_fno_split_dwarf_inlining}); - Args.hasArg(options::OPT_fno_split_dwarf_inlining); // Claim it if present. - - // If we're producing a dependency file, and assembly is the final action, - // then the name of the target in the dependency file should be the '.o' - // file, not the '.s' file produced by this step. For example, instead of - // /tmp/mumble.s: mumble.c .../someheader.h - // the filename on the lefthand side should be "mumble.o" - if (Args.getLastArg(options::OPT_MF) && !Args.getLastArg(options::OPT_MT) && - C.getActions().size() == 1 && - C.getActions()[0]->getKind() == Action::AssembleJobClass) { - Arg *A = Args.getLastArg(options::OPT_o); - if (A) { - CmdArgs.push_back("-MT"); - CmdArgs.push_back(Args.MakeArgString(A->getValue())); - } - } - - CmdArgs.push_back(II.getFilename()); - CmdArgs.push_back("-o"); - CmdArgs.push_back(Output.getFilename()); - - std::string Exec = - Args.MakeArgString(getToolChain().GetProgramPath("moviCompile")); - C.addCommand(llvm::make_unique<Command>(JA, *this, Args.MakeArgString(Exec), - CmdArgs, Inputs)); -} - -void tools::SHAVE::Assembler::ConstructJob(Compilation &C, const JobAction &JA, - const InputInfo &Output, - const InputInfoList &Inputs, - const ArgList &Args, - const char *LinkingOutput) const { - ArgStringList CmdArgs; - - assert(Inputs.size() == 1); - const InputInfo &II = Inputs[0]; - assert(II.getType() == types::TY_PP_Asm); // Require preprocessed asm input. - assert(Output.getType() == types::TY_Object); - - CmdArgs.push_back("-no6thSlotCompression"); - const Arg *CPUArg = Args.getLastArg(options::OPT_mcpu_EQ); - if (CPUArg) - CmdArgs.push_back( - Args.MakeArgString("-cv:" + StringRef(CPUArg->getValue()))); - CmdArgs.push_back("-noSPrefixing"); - CmdArgs.push_back("-a"); // Mystery option. - Args.AddAllArgValues(CmdArgs, options::OPT_Wa_COMMA, options::OPT_Xassembler); - for (const Arg *A : Args.filtered(options::OPT_I, options::OPT_isystem)) { - A->claim(); - CmdArgs.push_back( - Args.MakeArgString(std::string("-i:") + A->getValue(0))); - } - CmdArgs.push_back("-elf"); // Output format. - CmdArgs.push_back(II.getFilename()); - CmdArgs.push_back( - Args.MakeArgString(std::string("-o:") + Output.getFilename())); - - std::string Exec = - Args.MakeArgString(getToolChain().GetProgramPath("moviAsm")); - C.addCommand(llvm::make_unique<Command>(JA, *this, Args.MakeArgString(Exec), - CmdArgs, Inputs)); -} - -void tools::Myriad::Linker::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::MyriadToolChain &>(getToolChain()); - const llvm::Triple &T = TC.getTriple(); - ArgStringList CmdArgs; - bool UseStartfiles = - !Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles); - bool UseDefaultLibs = - !Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs); - // Silence warning if the args contain both -nostdlib and -stdlib=. - Args.getLastArg(options::OPT_stdlib_EQ); - - if (T.getArch() == llvm::Triple::sparc) - CmdArgs.push_back("-EB"); - else // SHAVE assumes little-endian, and sparcel is expressly so. - CmdArgs.push_back("-EL"); - - // The remaining logic is mostly like gnutools::Linker::ConstructJob, - // but we never pass through a --sysroot option and various other bits. - // For example, there are no sanitizers (yet) nor gold linker. - - // Eat some arguments that may be present but have no effect. - Args.ClaimAllArgs(options::OPT_g_Group); - Args.ClaimAllArgs(options::OPT_w); - Args.ClaimAllArgs(options::OPT_static_libgcc); - - if (Args.hasArg(options::OPT_s)) // Pass the 'strip' option. - CmdArgs.push_back("-s"); - - CmdArgs.push_back("-o"); - CmdArgs.push_back(Output.getFilename()); - - if (UseStartfiles) { - // If you want startfiles, it means you want the builtin crti and crtbegin, - // but not crt0. Myriad link commands provide their own crt0.o as needed. - CmdArgs.push_back(Args.MakeArgString(TC.GetFilePath("crti.o"))); - CmdArgs.push_back(Args.MakeArgString(TC.GetFilePath("crtbegin.o"))); - } - - Args.AddAllArgs(CmdArgs, {options::OPT_L, options::OPT_T_Group, - options::OPT_e, options::OPT_s, options::OPT_t, - options::OPT_Z_Flag, options::OPT_r}); - - TC.AddFilePathLibArgs(Args, CmdArgs); - - bool NeedsSanitizerDeps = addSanitizerRuntimes(TC, Args, CmdArgs); - AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA); - - if (UseDefaultLibs) { - if (NeedsSanitizerDeps) - linkSanitizerRuntimeDeps(TC, CmdArgs); - if (C.getDriver().CCCIsCXX()) { - if (TC.GetCXXStdlibType(Args) == ToolChain::CST_Libcxx) { - CmdArgs.push_back("-lc++"); - CmdArgs.push_back("-lc++abi"); - } else - CmdArgs.push_back("-lstdc++"); - } - if (T.getOS() == llvm::Triple::RTEMS) { - CmdArgs.push_back("--start-group"); - CmdArgs.push_back("-lc"); - CmdArgs.push_back("-lgcc"); // circularly dependent on rtems - // You must provide your own "-L" option to enable finding these. - CmdArgs.push_back("-lrtemscpu"); - CmdArgs.push_back("-lrtemsbsp"); - CmdArgs.push_back("--end-group"); - } else { - CmdArgs.push_back("-lc"); - CmdArgs.push_back("-lgcc"); - } - } - if (UseStartfiles) { - CmdArgs.push_back(Args.MakeArgString(TC.GetFilePath("crtend.o"))); - CmdArgs.push_back(Args.MakeArgString(TC.GetFilePath("crtn.o"))); - } - - std::string Exec = - Args.MakeArgString(TC.GetProgramPath("sparc-myriad-elf-ld")); - C.addCommand(llvm::make_unique<Command>(JA, *this, Args.MakeArgString(Exec), - CmdArgs, Inputs)); -} - -void PS4cpu::Assemble::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()); - - assert(Inputs.size() == 1 && "Unexpected number of inputs."); - const InputInfo &Input = Inputs[0]; - assert(Input.isFilename() && "Invalid input."); - CmdArgs.push_back(Input.getFilename()); - - const char *Exec = - Args.MakeArgString(getToolChain().GetProgramPath("orbis-as")); - C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); -} - -static void AddPS4SanitizerArgs(const ToolChain &TC, ArgStringList &CmdArgs) { - const SanitizerArgs &SanArgs = TC.getSanitizerArgs(); - if (SanArgs.needsUbsanRt()) { - CmdArgs.push_back("-lSceDbgUBSanitizer_stub_weak"); - } - if (SanArgs.needsAsanRt()) { - CmdArgs.push_back("-lSceDbgAddressSanitizer_stub_weak"); - } -} - -static void ConstructPS4LinkJob(const Tool &T, Compilation &C, - const JobAction &JA, const InputInfo &Output, - const InputInfoList &Inputs, - const ArgList &Args, - const char *LinkingOutput) { - const toolchains::FreeBSD &ToolChain = - static_cast<const toolchains::FreeBSD &>(T.getToolChain()); - const Driver &D = ToolChain.getDriver(); - ArgStringList CmdArgs; - - // Silence warning for "clang -g foo.o -o foo" - Args.ClaimAllArgs(options::OPT_g_Group); - // and "clang -emit-llvm foo.o -o foo" - Args.ClaimAllArgs(options::OPT_emit_llvm); - // and for "clang -w foo.o -o foo". Other warning options are already - // handled somewhere else. - Args.ClaimAllArgs(options::OPT_w); - - if (!D.SysRoot.empty()) - CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot)); - - if (Args.hasArg(options::OPT_pie)) - CmdArgs.push_back("-pie"); - - if (Args.hasArg(options::OPT_rdynamic)) - CmdArgs.push_back("-export-dynamic"); - if (Args.hasArg(options::OPT_shared)) - CmdArgs.push_back("--oformat=so"); - - if (Output.isFilename()) { - CmdArgs.push_back("-o"); - CmdArgs.push_back(Output.getFilename()); - } else { - assert(Output.isNothing() && "Invalid output."); - } - - AddPS4SanitizerArgs(ToolChain, CmdArgs); - - Args.AddAllArgs(CmdArgs, options::OPT_L); - Args.AddAllArgs(CmdArgs, options::OPT_T_Group); - Args.AddAllArgs(CmdArgs, options::OPT_e); - Args.AddAllArgs(CmdArgs, options::OPT_s); - Args.AddAllArgs(CmdArgs, options::OPT_t); - Args.AddAllArgs(CmdArgs, options::OPT_r); - - if (Args.hasArg(options::OPT_Z_Xlinker__no_demangle)) - CmdArgs.push_back("--no-demangle"); - - AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA); - - if (Args.hasArg(options::OPT_pthread)) { - CmdArgs.push_back("-lpthread"); - } - - const char *Exec = Args.MakeArgString(ToolChain.GetProgramPath("orbis-ld")); - - C.addCommand(llvm::make_unique<Command>(JA, T, Exec, CmdArgs, Inputs)); -} - -static void ConstructGoldLinkJob(const Tool &T, Compilation &C, - const JobAction &JA, const InputInfo &Output, - const InputInfoList &Inputs, - const ArgList &Args, - const char *LinkingOutput) { - const toolchains::FreeBSD &ToolChain = - static_cast<const toolchains::FreeBSD &>(T.getToolChain()); - const Driver &D = ToolChain.getDriver(); - ArgStringList CmdArgs; - - // Silence warning for "clang -g foo.o -o foo" - Args.ClaimAllArgs(options::OPT_g_Group); - // and "clang -emit-llvm foo.o -o foo" - Args.ClaimAllArgs(options::OPT_emit_llvm); - // and for "clang -w foo.o -o foo". Other warning options are already - // handled somewhere else. - Args.ClaimAllArgs(options::OPT_w); - - if (!D.SysRoot.empty()) - CmdArgs.push_back(Args.MakeArgString("--sysroot=" + D.SysRoot)); - - if (Args.hasArg(options::OPT_pie)) - CmdArgs.push_back("-pie"); - - 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"); - if (Args.hasArg(options::OPT_shared)) { - CmdArgs.push_back("-Bshareable"); - } else { - CmdArgs.push_back("-dynamic-linker"); - CmdArgs.push_back("/libexec/ld-elf.so.1"); - } - CmdArgs.push_back("--enable-new-dtags"); - } - - if (Output.isFilename()) { - CmdArgs.push_back("-o"); - CmdArgs.push_back(Output.getFilename()); - } else { - assert(Output.isNothing() && "Invalid output."); - } - - AddPS4SanitizerArgs(ToolChain, CmdArgs); - - if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) { - const char *crt1 = nullptr; - if (!Args.hasArg(options::OPT_shared)) { - if (Args.hasArg(options::OPT_pg)) - crt1 = "gcrt1.o"; - else if (Args.hasArg(options::OPT_pie)) - crt1 = "Scrt1.o"; - else - crt1 = "crt1.o"; - } - if (crt1) - CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crt1))); - - CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crti.o"))); - - const char *crtbegin = nullptr; - if (Args.hasArg(options::OPT_static)) - crtbegin = "crtbeginT.o"; - else if (Args.hasArg(options::OPT_shared) || Args.hasArg(options::OPT_pie)) - crtbegin = "crtbeginS.o"; - else - crtbegin = "crtbegin.o"; - - CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath(crtbegin))); - } - - Args.AddAllArgs(CmdArgs, options::OPT_L); - ToolChain.AddFilePathLibArgs(Args, CmdArgs); - Args.AddAllArgs(CmdArgs, options::OPT_T_Group); - Args.AddAllArgs(CmdArgs, options::OPT_e); - Args.AddAllArgs(CmdArgs, options::OPT_s); - Args.AddAllArgs(CmdArgs, options::OPT_t); - Args.AddAllArgs(CmdArgs, options::OPT_r); - - if (Args.hasArg(options::OPT_Z_Xlinker__no_demangle)) - CmdArgs.push_back("--no-demangle"); - - AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs, JA); - - if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) { - // For PS4, we always want to pass libm, libstdc++ and libkernel - // libraries for both C and C++ compilations. - CmdArgs.push_back("-lkernel"); - if (D.CCCIsCXX()) { - ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs); - if (Args.hasArg(options::OPT_pg)) - CmdArgs.push_back("-lm_p"); - else - CmdArgs.push_back("-lm"); - } - // FIXME: For some reason GCC passes -lgcc and -lgcc_s before adding - // the default system libraries. Just mimic this for now. - if (Args.hasArg(options::OPT_pg)) - CmdArgs.push_back("-lgcc_p"); - else - CmdArgs.push_back("-lcompiler_rt"); - if (Args.hasArg(options::OPT_static)) { - CmdArgs.push_back("-lstdc++"); - } else if (Args.hasArg(options::OPT_pg)) { - CmdArgs.push_back("-lgcc_eh_p"); - } else { - CmdArgs.push_back("--as-needed"); - CmdArgs.push_back("-lstdc++"); - CmdArgs.push_back("--no-as-needed"); - } - - if (Args.hasArg(options::OPT_pthread)) { - if (Args.hasArg(options::OPT_pg)) - CmdArgs.push_back("-lpthread_p"); - else - CmdArgs.push_back("-lpthread"); - } - - if (Args.hasArg(options::OPT_pg)) { - if (Args.hasArg(options::OPT_shared)) - CmdArgs.push_back("-lc"); - else { - if (Args.hasArg(options::OPT_static)) { - CmdArgs.push_back("--start-group"); - CmdArgs.push_back("-lc_p"); - CmdArgs.push_back("-lpthread_p"); - CmdArgs.push_back("--end-group"); - } else { - CmdArgs.push_back("-lc_p"); - } - } - CmdArgs.push_back("-lgcc_p"); - } else { - if (Args.hasArg(options::OPT_static)) { - CmdArgs.push_back("--start-group"); - CmdArgs.push_back("-lc"); - CmdArgs.push_back("-lpthread"); - CmdArgs.push_back("--end-group"); - } else { - CmdArgs.push_back("-lc"); - } - CmdArgs.push_back("-lcompiler_rt"); - } - - if (Args.hasArg(options::OPT_static)) { - CmdArgs.push_back("-lstdc++"); - } else if (Args.hasArg(options::OPT_pg)) { - CmdArgs.push_back("-lgcc_eh_p"); - } else { - CmdArgs.push_back("--as-needed"); - CmdArgs.push_back("-lstdc++"); - CmdArgs.push_back("--no-as-needed"); - } - } - - if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) { - if (Args.hasArg(options::OPT_shared) || Args.hasArg(options::OPT_pie)) - CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtendS.o"))); - else - CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtend.o"))); - CmdArgs.push_back(Args.MakeArgString(ToolChain.GetFilePath("crtn.o"))); - } - - const char *Exec = -#ifdef LLVM_ON_WIN32 - Args.MakeArgString(ToolChain.GetProgramPath("orbis-ld.gold")); -#else - Args.MakeArgString(ToolChain.GetProgramPath("orbis-ld")); -#endif - - C.addCommand(llvm::make_unique<Command>(JA, T, Exec, CmdArgs, Inputs)); -} - -void PS4cpu::Link::ConstructJob(Compilation &C, const JobAction &JA, - const InputInfo &Output, - const InputInfoList &Inputs, - const ArgList &Args, - const char *LinkingOutput) const { - const toolchains::FreeBSD &ToolChain = - static_cast<const toolchains::FreeBSD &>(getToolChain()); - const Driver &D = ToolChain.getDriver(); - bool PS4Linker; - StringRef LinkerOptName; - if (const Arg *A = Args.getLastArg(options::OPT_fuse_ld_EQ)) { - LinkerOptName = A->getValue(); - if (LinkerOptName != "ps4" && LinkerOptName != "gold") - D.Diag(diag::err_drv_unsupported_linker) << LinkerOptName; - } - - if (LinkerOptName == "gold") - PS4Linker = false; - else if (LinkerOptName == "ps4") - PS4Linker = true; - else - PS4Linker = !Args.hasArg(options::OPT_shared); - - if (PS4Linker) - ConstructPS4LinkJob(*this, C, JA, Output, Inputs, Args, LinkingOutput); - else - ConstructGoldLinkJob(*this, C, JA, Output, Inputs, Args, LinkingOutput); -} - -void NVPTX::Assembler::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"); - - // Obtain architecture from the action. - CudaArch gpu_arch = StringToCudaArch(JA.getOffloadingArch()); - assert(gpu_arch != CudaArch::UNKNOWN && - "Device action expected to have an architecture."); - - // Check that our installation's ptxas supports gpu_arch. - if (!Args.hasArg(options::OPT_no_cuda_version_check)) { - TC.CudaInstallation.CheckCudaVersionSupportsArch(gpu_arch); - } - - ArgStringList CmdArgs; - CmdArgs.push_back(TC.getTriple().isArch64Bit() ? "-m64" : "-m32"); - if (Args.hasFlag(options::OPT_cuda_noopt_device_debug, - options::OPT_no_cuda_noopt_device_debug, false)) { - // ptxas does not accept -g option if optimization is enabled, so - // we ignore the compiler's -O* options if we want debug info. - CmdArgs.push_back("-g"); - CmdArgs.push_back("--dont-merge-basicblocks"); - CmdArgs.push_back("--return-at-end"); - } else if (Arg *A = Args.getLastArg(options::OPT_O_Group)) { - // Map the -O we received to -O{0,1,2,3}. - // - // TODO: Perhaps we should map host -O2 to ptxas -O3. -O3 is ptxas's - // default, so it may correspond more closely to the spirit of clang -O2. - - // -O3 seems like the least-bad option when -Osomething is specified to - // clang but it isn't handled below. - StringRef OOpt = "3"; - if (A->getOption().matches(options::OPT_O4) || - A->getOption().matches(options::OPT_Ofast)) - OOpt = "3"; - else if (A->getOption().matches(options::OPT_O0)) - OOpt = "0"; - else if (A->getOption().matches(options::OPT_O)) { - // -Os, -Oz, and -O(anything else) map to -O2, for lack of better options. - OOpt = llvm::StringSwitch<const char *>(A->getValue()) - .Case("1", "1") - .Case("2", "2") - .Case("3", "3") - .Case("s", "2") - .Case("z", "2") - .Default("2"); - } - CmdArgs.push_back(Args.MakeArgString(llvm::Twine("-O") + OOpt)); - } else { - // If no -O was passed, pass -O0 to ptxas -- no opt flag should correspond - // to no optimizations, but ptxas's default is -O3. - CmdArgs.push_back("-O0"); - } - - 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())); - 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)); - - const char *Exec; - if (Arg *A = Args.getLastArg(options::OPT_ptxas_path_EQ)) - Exec = A->getValue(); - else - Exec = Args.MakeArgString(TC.GetProgramPath("ptxas")); - C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); -} - -// All inputs to this linker must be from CudaDeviceActions, as we need to look -// at the Inputs' Actions in order to figure out which GPU architecture they -// correspond to. -void NVPTX::Linker::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; - CmdArgs.push_back("--cuda"); - CmdArgs.push_back(TC.getTriple().isArch64Bit() ? "-64" : "-32"); - CmdArgs.push_back(Args.MakeArgString("--create")); - CmdArgs.push_back(Args.MakeArgString(Output.getFilename())); - - for (const auto& II : Inputs) { - auto *A = II.getAction(); - assert(A->getInputs().size() == 1 && - "Device offload action is expected to have a single input"); - const char *gpu_arch_str = A->getOffloadingArch(); - assert(gpu_arch_str && - "Device action expected to have associated a GPU architecture!"); - CudaArch gpu_arch = StringToCudaArch(gpu_arch_str); - - // We need to pass an Arch of the form "sm_XX" for cubin files and - // "compute_XX" for ptx. - const char *Arch = - (II.getType() == types::TY_PP_Asm) - ? CudaVirtualArchToString(VirtualArchForCudaArch(gpu_arch)) - : gpu_arch_str; - CmdArgs.push_back(Args.MakeArgString(llvm::Twine("--image=profile=") + - Arch + ",file=" + II.getFilename())); - } - - for (const auto& A : Args.getAllArgValues(options::OPT_Xcuda_fatbinary)) - CmdArgs.push_back(Args.MakeArgString(A)); - - const char *Exec = Args.MakeArgString(TC.GetProgramPath("fatbinary")); - C.addCommand(llvm::make_unique<Command>(JA, *this, Exec, CmdArgs, Inputs)); -} - -void AVR::Linker::ConstructJob(Compilation &C, const JobAction &JA, - const InputInfo &Output, - const InputInfoList &Inputs, - const ArgList &Args, - const char *LinkingOutput) const { - - std::string Linker = getToolChain().GetProgramPath(getShortName()); - ArgStringList CmdArgs; - AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA); - CmdArgs.push_back("-o"); - CmdArgs.push_back(Output.getFilename()); - C.addCommand(llvm::make_unique<Command>(JA, *this, Args.MakeArgString(Linker), - CmdArgs, Inputs)); -} -// AVR tools end. diff --git a/lib/Driver/Tools.h b/lib/Driver/Tools.h deleted file mode 100644 index 33f940ae42..0000000000 --- a/lib/Driver/Tools.h +++ /dev/null @@ -1,1067 +0,0 @@ -//===--- Tools.h - Tool 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_TOOLS_H -#define LLVM_CLANG_LIB_DRIVER_TOOLS_H - -#include "clang/Basic/DebugInfoOptions.h" -#include "clang/Basic/VersionTuple.h" -#include "clang/Driver/Tool.h" -#include "clang/Driver/Types.h" -#include "clang/Driver/Util.h" -#include "llvm/ADT/Triple.h" -#include "llvm/Option/Option.h" -#include "llvm/Support/raw_ostream.h" -#include "llvm/Support/Compiler.h" - -namespace clang { -class ObjCRuntime; - -namespace driver { -class Command; -class Driver; - -namespace toolchains { -class MachO; -} - -namespace tools { - -namespace visualstudio { -class Compiler; -} - -using llvm::opt::ArgStringList; -using llvm::opt::ArgList; - -SmallString<128> getCompilerRT(const ToolChain &TC, - const llvm::opt::ArgList &Args, - StringRef Component, bool Shared = false); - -std::string getCPUName(const ArgList &Args, const llvm::Triple &T, - bool FromAs = false); - -void AddTargetFeature(const ArgList &Args, std::vector<StringRef> &Features, - llvm::opt::OptSpecifier OnOpt, - llvm::opt::OptSpecifier OffOpt, StringRef FeatureName); - -void handleTargetFeaturesGroup(const ArgList &Args, - std::vector<StringRef> &Features, - llvm::opt::OptSpecifier Group); - -/// \brief Clang compiler tool. -class LLVM_LIBRARY_VISIBILITY Clang : public Tool { -public: - static const char *getBaseInputName(const llvm::opt::ArgList &Args, - const InputInfo &Input); - static const char *getBaseInputStem(const llvm::opt::ArgList &Args, - const InputInfoList &Inputs); - static const char *getDependencyFileName(const llvm::opt::ArgList &Args, - const InputInfoList &Inputs); - -private: - void AddPreprocessingOptions(Compilation &C, const JobAction &JA, - const Driver &D, const llvm::opt::ArgList &Args, - llvm::opt::ArgStringList &CmdArgs, - const InputInfo &Output, - const InputInfoList &Inputs) const; - - void AddAArch64TargetArgs(const llvm::opt::ArgList &Args, - llvm::opt::ArgStringList &CmdArgs) const; - void AddARMTargetArgs(const llvm::Triple &Triple, - const llvm::opt::ArgList &Args, - llvm::opt::ArgStringList &CmdArgs, - bool KernelOrKext) const; - void AddARM64TargetArgs(const llvm::opt::ArgList &Args, - llvm::opt::ArgStringList &CmdArgs) const; - void AddMIPSTargetArgs(const llvm::opt::ArgList &Args, - llvm::opt::ArgStringList &CmdArgs) const; - void AddPPCTargetArgs(const llvm::opt::ArgList &Args, - llvm::opt::ArgStringList &CmdArgs) const; - void AddR600TargetArgs(const llvm::opt::ArgList &Args, - llvm::opt::ArgStringList &CmdArgs) const; - void AddSparcTargetArgs(const llvm::opt::ArgList &Args, - llvm::opt::ArgStringList &CmdArgs) const; - void AddSystemZTargetArgs(const llvm::opt::ArgList &Args, - llvm::opt::ArgStringList &CmdArgs) const; - void AddX86TargetArgs(const llvm::opt::ArgList &Args, - llvm::opt::ArgStringList &CmdArgs) const; - void AddHexagonTargetArgs(const llvm::opt::ArgList &Args, - llvm::opt::ArgStringList &CmdArgs) const; - void AddLanaiTargetArgs(const llvm::opt::ArgList &Args, - llvm::opt::ArgStringList &CmdArgs) const; - void AddWebAssemblyTargetArgs(const llvm::opt::ArgList &Args, - llvm::opt::ArgStringList &CmdArgs) const; - - enum RewriteKind { RK_None, RK_Fragile, RK_NonFragile }; - - ObjCRuntime AddObjCRuntimeArgs(const llvm::opt::ArgList &args, - llvm::opt::ArgStringList &cmdArgs, - RewriteKind rewrite) const; - - void AddClangCLArgs(const llvm::opt::ArgList &Args, types::ID InputType, - llvm::opt::ArgStringList &CmdArgs, - codegenoptions::DebugInfoKind *DebugInfoKind, - bool *EmitCodeView) const; - - visualstudio::Compiler *getCLFallback() const; - - mutable std::unique_ptr<visualstudio::Compiler> CLFallback; - - mutable std::unique_ptr<llvm::raw_fd_ostream> CompilationDatabase = nullptr; - void DumpCompilationDatabase(Compilation &C, StringRef Filename, - StringRef Target, - const InputInfo &Output, const InputInfo &Input, - const llvm::opt::ArgList &Args) const; - -public: - // CAUTION! The first constructor argument ("clang") is not arbitrary, - // as it is for other tools. Some operations on a Tool actually test - // whether that tool is Clang based on the Tool's Name as a string. - Clang(const ToolChain &TC) : Tool("clang", "clang frontend", TC, RF_Full) {} - - bool hasGoodDiagnostics() const override { return true; } - bool hasIntegratedAssembler() const override { return true; } - bool hasIntegratedCPP() const override { return true; } - bool canEmitIR() 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; -}; - -/// \brief Clang integrated assembler tool. -class LLVM_LIBRARY_VISIBILITY ClangAs : public Tool { -public: - ClangAs(const ToolChain &TC) - : Tool("clang::as", "clang integrated assembler", TC, RF_Full) {} - void AddMIPSTargetArgs(const llvm::opt::ArgList &Args, - llvm::opt::ArgStringList &CmdArgs) const; - void AddX86TargetArgs(const llvm::opt::ArgList &Args, - llvm::opt::ArgStringList &CmdArgs) const; - bool hasGoodDiagnostics() const override { return true; } - bool hasIntegratedAssembler() const override { return false; } - 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; -}; - -/// Offload bundler tool. -class LLVM_LIBRARY_VISIBILITY OffloadBundler final : public Tool { -public: - OffloadBundler(const ToolChain &TC) - : Tool("offload bundler", "clang-offload-bundler", 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; - void ConstructJobMultipleOutputs(Compilation &C, const JobAction &JA, - const InputInfoList &Outputs, - const InputInfoList &Inputs, - const llvm::opt::ArgList &TCArgs, - const char *LinkingOutput) const override; -}; - -/// \brief Base class for all GNU tools that provide the same behavior when -/// it comes to response files support -class LLVM_LIBRARY_VISIBILITY GnuTool : public Tool { - virtual void anchor(); - -public: - GnuTool(const char *Name, const char *ShortName, const ToolChain &TC) - : Tool(Name, ShortName, TC, RF_Full, llvm::sys::WEM_CurrentCodePage) {} -}; - -/// gcc - Generic GCC tool implementations. -namespace gcc { -class LLVM_LIBRARY_VISIBILITY Common : public GnuTool { -public: - Common(const char *Name, const char *ShortName, const ToolChain &TC) - : GnuTool(Name, ShortName, TC) {} - - // A gcc tool has an "integrated" assembler that it will call to produce an - // object. Let it use that assembler so that we don't have to deal with - // assembly syntax incompatibilities. - bool hasIntegratedAssembler() 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; - - /// RenderExtraToolArgs - Render any arguments necessary to force - /// the particular tool mode. - virtual void RenderExtraToolArgs(const JobAction &JA, - llvm::opt::ArgStringList &CmdArgs) const = 0; -}; - -class LLVM_LIBRARY_VISIBILITY Preprocessor : public Common { -public: - Preprocessor(const ToolChain &TC) - : Common("gcc::Preprocessor", "gcc preprocessor", TC) {} - - bool hasGoodDiagnostics() const override { return true; } - bool hasIntegratedCPP() const override { return false; } - - void RenderExtraToolArgs(const JobAction &JA, - llvm::opt::ArgStringList &CmdArgs) const override; -}; - -class LLVM_LIBRARY_VISIBILITY Compiler : public Common { -public: - Compiler(const ToolChain &TC) : Common("gcc::Compiler", "gcc frontend", TC) {} - - bool hasGoodDiagnostics() const override { return true; } - bool hasIntegratedCPP() const override { return true; } - - void RenderExtraToolArgs(const JobAction &JA, - llvm::opt::ArgStringList &CmdArgs) const override; -}; - -class LLVM_LIBRARY_VISIBILITY Linker : public Common { -public: - Linker(const ToolChain &TC) : Common("gcc::Linker", "linker (via gcc)", TC) {} - - bool hasIntegratedCPP() const override { return false; } - bool isLinkJob() const override { return true; } - - void RenderExtraToolArgs(const JobAction &JA, - llvm::opt::ArgStringList &CmdArgs) const override; -}; -} // end namespace gcc - -namespace hexagon { -// For Hexagon, we do not need to instantiate tools for PreProcess, PreCompile -// and Compile. -// We simply use "clang -cc1" for those actions. -class LLVM_LIBRARY_VISIBILITY Assembler : public GnuTool { -public: - Assembler(const ToolChain &TC) - : GnuTool("hexagon::Assembler", "hexagon-as", TC) {} - - bool hasIntegratedCPP() const override { return false; } - - void RenderExtraToolArgs(const JobAction &JA, - llvm::opt::ArgStringList &CmdArgs) const; - 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("hexagon::Linker", "hexagon-ld", TC) {} - - bool hasIntegratedCPP() const override { return false; } - bool isLinkJob() const override { return true; } - - virtual void RenderExtraToolArgs(const JobAction &JA, - llvm::opt::ArgStringList &CmdArgs) const; - 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 hexagon. - -namespace amdgpu { - -class LLVM_LIBRARY_VISIBILITY Linker : public GnuTool { -public: - Linker(const ToolChain &TC) : GnuTool("amdgpu::Linker", "ld.lld", TC) {} - bool isLinkJob() const override { return true; } - 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 amdgpu - -namespace wasm { - -class LLVM_LIBRARY_VISIBILITY Linker : public GnuTool { -public: - explicit Linker(const ToolChain &TC); - bool isLinkJob() const override; - bool hasIntegratedCPP() const override; - 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 wasm - -namespace arm { -std::string getARMTargetCPU(StringRef CPU, StringRef Arch, - const llvm::Triple &Triple); -const std::string getARMArch(StringRef Arch, - const llvm::Triple &Triple); -StringRef getARMCPUForMArch(StringRef Arch, const llvm::Triple &Triple); -StringRef getLLVMArchSuffixForARM(StringRef CPU, StringRef Arch, - const llvm::Triple &Triple); - -void appendEBLinkFlags(const llvm::opt::ArgList &Args, ArgStringList &CmdArgs, - const llvm::Triple &Triple); -} // end namespace arm - -namespace mips { -typedef enum { NanLegacy = 1, Nan2008 = 2 } NanEncoding; - -enum class FloatABI { - Invalid, - Soft, - Hard, -}; - -NanEncoding getSupportedNanEncoding(StringRef &CPU); -bool hasCompactBranches(StringRef &CPU); -void getMipsCPUAndABI(const llvm::opt::ArgList &Args, - const llvm::Triple &Triple, StringRef &CPUName, - StringRef &ABIName); -void getMIPSTargetFeatures(const Driver &D, const llvm::Triple &Triple, - const ArgList &Args, - std::vector<StringRef> &Features); -StringRef getGnuCompatibleMipsABIName(StringRef ABI); -mips::FloatABI getMipsFloatABI(const Driver &D, const ArgList &Args); -std::string getMipsABILibSuffix(const llvm::opt::ArgList &Args, - const llvm::Triple &Triple); -bool hasMipsAbiArg(const llvm::opt::ArgList &Args, const char *Value); -bool isUCLibc(const llvm::opt::ArgList &Args); -bool isNaN2008(const llvm::opt::ArgList &Args, const llvm::Triple &Triple); -bool isFP64ADefault(const llvm::Triple &Triple, StringRef CPUName); -bool isFPXXDefault(const llvm::Triple &Triple, StringRef CPUName, - StringRef ABIName, mips::FloatABI FloatABI); -bool shouldUseFPXX(const llvm::opt::ArgList &Args, const llvm::Triple &Triple, - StringRef CPUName, StringRef ABIName, - mips::FloatABI FloatABI); - -} // end namespace mips - -namespace ppc { -bool hasPPCAbiArg(const llvm::opt::ArgList &Args, const char *Value); -} // end namespace ppc - -/// cloudabi -- Directly call GNU Binutils linker -namespace cloudabi { -class LLVM_LIBRARY_VISIBILITY Linker : public GnuTool { -public: - Linker(const ToolChain &TC) : GnuTool("cloudabi::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 cloudabi - -namespace darwin { -llvm::Triple::ArchType getArchTypeForMachOArchName(StringRef Str); -void setTripleTypeForMachOArchName(llvm::Triple &T, StringRef Str); - -class LLVM_LIBRARY_VISIBILITY MachOTool : public Tool { - virtual void anchor(); - -protected: - void AddMachOArch(const llvm::opt::ArgList &Args, - llvm::opt::ArgStringList &CmdArgs) const; - - const toolchains::MachO &getMachOToolChain() const { - return reinterpret_cast<const toolchains::MachO &>(getToolChain()); - } - -public: - MachOTool( - const char *Name, const char *ShortName, const ToolChain &TC, - ResponseFileSupport ResponseSupport = RF_None, - llvm::sys::WindowsEncodingMethod ResponseEncoding = llvm::sys::WEM_UTF8, - const char *ResponseFlag = "@") - : Tool(Name, ShortName, TC, ResponseSupport, ResponseEncoding, - ResponseFlag) {} -}; - -class LLVM_LIBRARY_VISIBILITY Assembler : public MachOTool { -public: - Assembler(const ToolChain &TC) - : MachOTool("darwin::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 MachOTool { - bool NeedsTempPath(const InputInfoList &Inputs) const; - void AddLinkArgs(Compilation &C, const llvm::opt::ArgList &Args, - llvm::opt::ArgStringList &CmdArgs, - const InputInfoList &Inputs) const; - -public: - Linker(const ToolChain &TC) - : MachOTool("darwin::Linker", "linker", TC, RF_FileList, - llvm::sys::WEM_UTF8, "-filelist") {} - - 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; -}; - -class LLVM_LIBRARY_VISIBILITY Lipo : public MachOTool { -public: - Lipo(const ToolChain &TC) : MachOTool("darwin::Lipo", "lipo", 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 Dsymutil : public MachOTool { -public: - Dsymutil(const ToolChain &TC) - : MachOTool("darwin::Dsymutil", "dsymutil", TC) {} - - bool hasIntegratedCPP() const override { return false; } - bool isDsymutilJob() 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; -}; - -class LLVM_LIBRARY_VISIBILITY VerifyDebug : public MachOTool { -public: - VerifyDebug(const ToolChain &TC) - : MachOTool("darwin::VerifyDebug", "dwarfdump", 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; -}; -} // end namespace darwin - -/// openbsd -- Directly call GNU Binutils assembler and linker -namespace openbsd { -class LLVM_LIBRARY_VISIBILITY Assembler : public GnuTool { -public: - Assembler(const ToolChain &TC) - : GnuTool("openbsd::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("openbsd::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 openbsd - -/// 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 - -/// freebsd -- Directly call GNU Binutils assembler and linker -namespace freebsd { -class LLVM_LIBRARY_VISIBILITY Assembler : public GnuTool { -public: - Assembler(const ToolChain &TC) - : GnuTool("freebsd::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("freebsd::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 freebsd - -/// netbsd -- Directly call GNU Binutils assembler and linker -namespace netbsd { -class LLVM_LIBRARY_VISIBILITY Assembler : public GnuTool { -public: - Assembler(const ToolChain &TC) - : GnuTool("netbsd::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("netbsd::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 netbsd - -/// Directly call GNU Binutils' assembler and linker. -namespace gnutools { -class LLVM_LIBRARY_VISIBILITY Assembler : public GnuTool { -public: - Assembler(const ToolChain &TC) : GnuTool("GNU::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("GNU::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 gnutools - -namespace nacltools { -class LLVM_LIBRARY_VISIBILITY AssemblerARM : public gnutools::Assembler { -public: - AssemblerARM(const ToolChain &TC) : gnutools::Assembler(TC) {} - - 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("NaCl::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 nacltools - -namespace fuchsia { -class LLVM_LIBRARY_VISIBILITY Linker : public GnuTool { -public: - Linker(const ToolChain &TC) : GnuTool("fuchsia::Linker", "ld.lld", 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 fuchsia - -/// minix -- Directly call GNU Binutils assembler and linker -namespace minix { -class LLVM_LIBRARY_VISIBILITY Assembler : public GnuTool { -public: - Assembler(const ToolChain &TC) - : GnuTool("minix::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("minix::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 minix - -/// solaris -- Directly call Solaris assembler and linker -namespace solaris { -class LLVM_LIBRARY_VISIBILITY Assembler : public Tool { -public: - Assembler(const ToolChain &TC) - : Tool("solaris::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 Tool { -public: - Linker(const ToolChain &TC) : Tool("solaris::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 solaris - -/// dragonfly -- Directly call GNU Binutils assembler and linker -namespace dragonfly { -class LLVM_LIBRARY_VISIBILITY Assembler : public GnuTool { -public: - Assembler(const ToolChain &TC) - : GnuTool("dragonfly::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("dragonfly::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 dragonfly - -/// Visual studio tools. -namespace visualstudio { -class LLVM_LIBRARY_VISIBILITY Linker : public Tool { -public: - Linker(const ToolChain &TC) - : Tool("visualstudio::Linker", "linker", TC, RF_Full, - llvm::sys::WEM_UTF16) {} - - 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; -}; - -class LLVM_LIBRARY_VISIBILITY Compiler : public Tool { -public: - Compiler(const ToolChain &TC) - : Tool("visualstudio::Compiler", "compiler", TC, RF_Full, - llvm::sys::WEM_UTF16) {} - - bool hasIntegratedAssembler() const override { return true; } - bool hasIntegratedCPP() const override { return true; } - bool isLinkJob() 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; - - std::unique_ptr<Command> GetCommand(Compilation &C, const JobAction &JA, - const InputInfo &Output, - const InputInfoList &Inputs, - const llvm::opt::ArgList &TCArgs, - const char *LinkingOutput) const; -}; -} // end namespace visualstudio - -/// MinGW -- Directly call GNU Binutils assembler and linker -namespace MinGW { -class LLVM_LIBRARY_VISIBILITY Assembler : public Tool { -public: - Assembler(const ToolChain &TC) : Tool("MinGW::Assemble", "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 Tool { -public: - Linker(const ToolChain &TC) : Tool("MinGW::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; - -private: - void AddLibGCC(const llvm::opt::ArgList &Args, ArgStringList &CmdArgs) const; -}; -} // end namespace MinGW - -namespace arm { -enum class FloatABI { - Invalid, - Soft, - SoftFP, - Hard, -}; - -FloatABI getARMFloatABI(const ToolChain &TC, const llvm::opt::ArgList &Args); - -bool useAAPCSForMachO(const llvm::Triple &T); -void getARMArchCPUFromArgs(const ArgList &Args, llvm::StringRef &Arch, - llvm::StringRef &CPU, bool FromAs = false); -void getARMTargetFeatures(const ToolChain &TC, const llvm::Triple &Triple, - const ArgList &Args, ArgStringList &CmdArgs, - std::vector<StringRef> &Features, bool ForAS); -int getARMSubArchVersionNumber(const llvm::Triple &Triple); -bool isARMMProfile(const llvm::Triple &Triple); -} // end namespace arm - -namespace aarch64 { -void getAArch64TargetFeatures(const Driver &D, const ArgList &Args, - std::vector<StringRef> &Features); -std::string getAArch64TargetCPU(const ArgList &Args, llvm::opt::Arg *&A); -} // end namespace aarch64 - -namespace ppc { -enum class FloatABI { - Invalid, - Soft, - Hard, -}; - -FloatABI getPPCFloatABI(const Driver &D, const llvm::opt::ArgList &Args); - -std::string getPPCTargetCPU(const ArgList &Args); -void getPPCTargetFeatures(const Driver &D, const llvm::Triple &Triple, - const ArgList &Args, - std::vector<StringRef> &Features); -} // end namespace ppc - -namespace sparc { -enum class FloatABI { - Invalid, - Soft, - Hard, -}; - -FloatABI getSparcFloatABI(const Driver &D, const llvm::opt::ArgList &Args); - -void getSparcTargetFeatures(const Driver &D, const ArgList &Args, - std::vector<StringRef> &Features); -const char *getSparcAsmModeForCPU(StringRef Name, - const llvm::Triple &Triple); -} // end namespace sparc - -namespace XCore { -// For XCore, we do not need to instantiate tools for PreProcess, PreCompile and -// Compile. -// We simply use "clang -cc1" for those actions. -class LLVM_LIBRARY_VISIBILITY Assembler : public Tool { -public: - Assembler(const ToolChain &TC) : Tool("XCore::Assembler", "XCore-as", 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 Tool { -public: - Linker(const ToolChain &TC) : Tool("XCore::Linker", "XCore-ld", 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 XCore. - -namespace CrossWindows { -class LLVM_LIBRARY_VISIBILITY Assembler : public Tool { -public: - Assembler(const ToolChain &TC) : Tool("CrossWindows::Assembler", "as", 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 Tool { -public: - Linker(const ToolChain &TC) - : Tool("CrossWindows::Linker", "ld", TC, RF_Full) {} - - 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 CrossWindows - -/// SHAVE tools -- Directly call moviCompile and moviAsm -namespace SHAVE { -class LLVM_LIBRARY_VISIBILITY Compiler : public Tool { -public: - Compiler(const ToolChain &TC) : Tool("moviCompile", "movicompile", TC) {} - - bool hasIntegratedCPP() 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; -}; - -class LLVM_LIBRARY_VISIBILITY Assembler : public Tool { -public: - Assembler(const ToolChain &TC) : Tool("moviAsm", "moviAsm", TC) {} - - bool hasIntegratedCPP() const override { return false; } // not sure. - - 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 SHAVE - -/// The Myriad toolchain uses tools that are in two different namespaces. -/// The Compiler and Assembler as defined above are in the SHAVE namespace, -/// whereas the linker, which accepts code for a mixture of Sparc and SHAVE, -/// is in the Myriad namespace. -namespace Myriad { -class LLVM_LIBRARY_VISIBILITY Linker : public GnuTool { -public: - Linker(const ToolChain &TC) : GnuTool("shave::Linker", "ld", 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 Myriad - -namespace PS4cpu { -class LLVM_LIBRARY_VISIBILITY Assemble : public Tool { -public: - Assemble(const ToolChain &TC) - : Tool("PS4cpu::Assemble", "assembler", TC, RF_Full) {} - - 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 Link : public Tool { -public: - Link(const ToolChain &TC) : Tool("PS4cpu::Link", "linker", TC, RF_Full) {} - - 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 PS4cpu - -namespace NVPTX { - -// Run ptxas, the NVPTX assembler. -class LLVM_LIBRARY_VISIBILITY Assembler : public Tool { - public: - Assembler(const ToolChain &TC) - : Tool("NVPTX::Assembler", "ptxas", 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; -}; - -// Runs fatbinary, which combines GPU object files ("cubin" files) and/or PTX -// assembly into a single output file. -class LLVM_LIBRARY_VISIBILITY Linker : public Tool { - public: - Linker(const ToolChain &TC) - : Tool("NVPTX::Linker", "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 - -namespace AVR { -class LLVM_LIBRARY_VISIBILITY Linker : public GnuTool { -public: - Linker(const ToolChain &TC) : GnuTool("AVR::Linker", "avr-ld", 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 AVR - -namespace systemz { -const char *getSystemZTargetCPU(const ArgList &Args); -void getSystemZTargetFeatures(const ArgList &Args, - std::vector<StringRef> &Features); -} // end namespace systemz - -namespace x86 { -const char *getX86TargetCPU(const ArgList &Args, - const llvm::Triple &Triple); -void getX86TargetFeatures(const Driver &D, const llvm::Triple &Triple, - const ArgList &Args, - std::vector<StringRef> &Features); -} // end namespace x86 - -} // end namespace tools -} // end namespace driver -} // end namespace clang - -#endif // LLVM_CLANG_LIB_DRIVER_TOOLS_H |