
Summary: MSVC's driver accepts all unknown arguments but warns about them. clang by default rejects all unknown arguments. This causes issues specifically with build systems such as autoconf which liberally pass things such as $LDFLAGS to the compiler and expect everything to work. This patch teaches clang-cl to ignore unknown driver arguments. Reviewers: rnk Subscribers: cfe-commits Differential Revision: http://reviews.llvm.org/D16511 llvm-svn: 258720
10774 lines
392 KiB
C++
10774 lines
392 KiB
C++
//===--- 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/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/raw_ostream.h"
|
|
#include "llvm/Support/TargetParser.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 handleTargetFeaturesGroup(const ArgList &Args,
|
|
std::vector<const char *> &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 const char *getSparcAsmModeForCPU(StringRef Name,
|
|
const llvm::Triple &Triple) {
|
|
if (Triple.getArch() == llvm::Triple::sparcv9) {
|
|
return llvm::StringSwitch<const char *>(Name)
|
|
.Case("niagara", "-Av9b")
|
|
.Case("niagara2", "-Av9b")
|
|
.Case("niagara3", "-Av9d")
|
|
.Case("niagara4", "-Av9d")
|
|
.Default("-Av9");
|
|
} else {
|
|
return llvm::StringSwitch<const char *>(Name)
|
|
.Case("v8", "-Av8")
|
|
.Case("supersparc", "-Av8")
|
|
.Case("sparclite", "-Asparclite")
|
|
.Case("f934", "-Asparclite")
|
|
.Case("hypersparc", "-Av8")
|
|
.Case("sparclite86x", "-Asparclite")
|
|
.Case("sparclet", "-Asparclet")
|
|
.Case("tsc701", "-Asparclet")
|
|
.Case("v9", "-Av8plus")
|
|
.Case("ultrasparc", "-Av8plus")
|
|
.Case("ultrasparc3", "-Av8plus")
|
|
.Case("niagara", "-Av8plusb")
|
|
.Case("niagara2", "-Av8plusb")
|
|
.Case("niagara3", "-Av8plusd")
|
|
.Case("niagara4", "-Av8plusd")
|
|
.Default("-Av8");
|
|
}
|
|
}
|
|
|
|
/// CheckPreprocessingOptions - Perform some validation of preprocessing
|
|
/// arguments that is shared with gcc.
|
|
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");
|
|
}
|
|
}
|
|
}
|
|
|
|
/// CheckCodeGenerationOptions - Perform some validation of code generation
|
|
/// arguments that is shared with gcc.
|
|
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 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 (!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");
|
|
}
|
|
|
|
/// \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);
|
|
}
|
|
|
|
void Clang::AddPreprocessingOptions(Compilation &C, const JobAction &JA,
|
|
const Driver &D, const ArgList &Args,
|
|
ArgStringList &CmdArgs,
|
|
const InputInfo &Output,
|
|
const InputInfoList &Inputs,
|
|
const ToolChain *AuxToolChain) const {
|
|
Arg *A;
|
|
|
|
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 -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.
|
|
bool RenderedImplicitInclude = false;
|
|
for (const Arg *A : Args.filtered(options::OPT_clang_i_Group)) {
|
|
if (A->getOption().matches(options::OPT_include)) {
|
|
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);
|
|
}
|
|
}
|
|
}
|
|
|
|
// 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");
|
|
|
|
// Optional AuxToolChain indicates that we need to include headers
|
|
// for more than one target. If that's the case, add include paths
|
|
// from AuxToolChain right after include paths of the same kind for
|
|
// the current target.
|
|
|
|
// Add C++ include arguments, if needed.
|
|
if (types::isCXX(Inputs[0].getType())) {
|
|
getToolChain().AddClangCXXStdlibIncludeArgs(Args, CmdArgs);
|
|
if (AuxToolChain)
|
|
AuxToolChain->AddClangCXXStdlibIncludeArgs(Args, CmdArgs);
|
|
}
|
|
|
|
// Add system include arguments.
|
|
getToolChain().AddClangSystemIncludeArgs(Args, CmdArgs);
|
|
if (AuxToolChain)
|
|
AuxToolChain->AddClangCXXStdlibIncludeArgs(Args, CmdArgs);
|
|
|
|
// Add CUDA include arguments, if needed.
|
|
if (types::isCuda(Inputs[0].getType()))
|
|
getToolChain().AddCudaIncludeArgs(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;
|
|
}
|
|
}
|
|
|
|
// ARM tools start.
|
|
|
|
// Get SubArch (vN).
|
|
static int getARMSubArchVersionNumber(const llvm::Triple &Triple) {
|
|
llvm::StringRef Arch = Triple.getArchName();
|
|
return llvm::ARM::parseArchVersion(Arch);
|
|
}
|
|
|
|
// True if M-profile.
|
|
static bool isARMMProfile(const llvm::Triple &Triple) {
|
|
llvm::StringRef Arch = Triple.getArchName();
|
|
unsigned Profile = llvm::ARM::parseArchProfile(Arch);
|
|
return Profile == llvm::ARM::PK_M;
|
|
}
|
|
|
|
// Get Arch/CPU from args.
|
|
static void getARMArchCPUFromArgs(const ArgList &Args, llvm::StringRef &Arch,
|
|
llvm::StringRef &CPU, bool FromAs = false) {
|
|
if (const Arg *A = Args.getLastArg(options::OPT_mcpu_EQ))
|
|
CPU = A->getValue();
|
|
if (const Arg *A = Args.getLastArg(options::OPT_march_EQ))
|
|
Arch = A->getValue();
|
|
if (!FromAs)
|
|
return;
|
|
|
|
for (const Arg *A :
|
|
Args.filtered(options::OPT_Wa_COMMA, options::OPT_Xassembler)) {
|
|
StringRef Value = A->getValue();
|
|
if (Value.startswith("-mcpu="))
|
|
CPU = Value.substr(6);
|
|
if (Value.startswith("-march="))
|
|
Arch = Value.substr(7);
|
|
}
|
|
}
|
|
|
|
// Handle -mhwdiv=.
|
|
// FIXME: Use ARMTargetParser.
|
|
static void getARMHWDivFeatures(const Driver &D, const Arg *A,
|
|
const ArgList &Args, StringRef HWDiv,
|
|
std::vector<const char *> &Features) {
|
|
unsigned HWDivID = llvm::ARM::parseHWDiv(HWDiv);
|
|
if (!llvm::ARM::getHWDivFeatures(HWDivID, Features))
|
|
D.Diag(diag::err_drv_clang_unsupported) << A->getAsString(Args);
|
|
}
|
|
|
|
// Handle -mfpu=.
|
|
static void getARMFPUFeatures(const Driver &D, const Arg *A,
|
|
const ArgList &Args, StringRef FPU,
|
|
std::vector<const char *> &Features) {
|
|
unsigned FPUID = llvm::ARM::parseFPU(FPU);
|
|
if (!llvm::ARM::getFPUFeatures(FPUID, Features))
|
|
D.Diag(diag::err_drv_clang_unsupported) << A->getAsString(Args);
|
|
}
|
|
|
|
// Decode ARM features from string like +[no]featureA+[no]featureB+...
|
|
static bool DecodeARMFeatures(const Driver &D, StringRef text,
|
|
std::vector<const char *> &Features) {
|
|
SmallVector<StringRef, 8> Split;
|
|
text.split(Split, StringRef("+"), -1, false);
|
|
|
|
for (StringRef Feature : Split) {
|
|
const char *FeatureName = llvm::ARM::getArchExtFeature(Feature);
|
|
if (FeatureName)
|
|
Features.push_back(FeatureName);
|
|
else
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
// Check if -march is valid by checking if it can be canonicalised and parsed.
|
|
// getARMArch is used here instead of just checking the -march value in order
|
|
// to handle -march=native correctly.
|
|
static void checkARMArchName(const Driver &D, const Arg *A, const ArgList &Args,
|
|
llvm::StringRef ArchName,
|
|
std::vector<const char *> &Features,
|
|
const llvm::Triple &Triple) {
|
|
std::pair<StringRef, StringRef> Split = ArchName.split("+");
|
|
|
|
std::string MArch = arm::getARMArch(ArchName, Triple);
|
|
if (llvm::ARM::parseArch(MArch) == llvm::ARM::AK_INVALID ||
|
|
(Split.second.size() && !DecodeARMFeatures(D, Split.second, Features)))
|
|
D.Diag(diag::err_drv_clang_unsupported) << A->getAsString(Args);
|
|
}
|
|
|
|
// Check -mcpu=. Needs ArchName to handle -mcpu=generic.
|
|
static void checkARMCPUName(const Driver &D, const Arg *A, const ArgList &Args,
|
|
llvm::StringRef CPUName, llvm::StringRef ArchName,
|
|
std::vector<const char *> &Features,
|
|
const llvm::Triple &Triple) {
|
|
std::pair<StringRef, StringRef> Split = CPUName.split("+");
|
|
|
|
std::string CPU = arm::getARMTargetCPU(CPUName, ArchName, Triple);
|
|
if (arm::getLLVMArchSuffixForARM(CPU, ArchName, Triple).empty() ||
|
|
(Split.second.size() && !DecodeARMFeatures(D, Split.second, Features)))
|
|
D.Diag(diag::err_drv_clang_unsupported) << A->getAsString(Args);
|
|
}
|
|
|
|
static bool useAAPCSForMachO(const llvm::Triple &T) {
|
|
// The backend is hardwired to assume AAPCS for M-class processors, ensure
|
|
// the frontend matches that.
|
|
return T.getEnvironment() == llvm::Triple::EABI ||
|
|
T.getOS() == llvm::Triple::UnknownOS || isARMMProfile(T);
|
|
}
|
|
|
|
// Select the float ABI as determined by -msoft-float, -mhard-float, and
|
|
// -mfloat-abi=.
|
|
arm::FloatABI arm::getARMFloatABI(const ToolChain &TC, const ArgList &Args) {
|
|
const Driver &D = TC.getDriver();
|
|
const llvm::Triple Triple(TC.ComputeEffectiveClangTriple(Args));
|
|
auto SubArch = getARMSubArchVersionNumber(Triple);
|
|
arm::FloatABI ABI = FloatABI::Invalid;
|
|
if (Arg *A =
|
|
Args.getLastArg(options::OPT_msoft_float, options::OPT_mhard_float,
|
|
options::OPT_mfloat_abi_EQ)) {
|
|
if (A->getOption().matches(options::OPT_msoft_float)) {
|
|
ABI = FloatABI::Soft;
|
|
} else if (A->getOption().matches(options::OPT_mhard_float)) {
|
|
ABI = FloatABI::Hard;
|
|
} else {
|
|
ABI = llvm::StringSwitch<arm::FloatABI>(A->getValue())
|
|
.Case("soft", FloatABI::Soft)
|
|
.Case("softfp", FloatABI::SoftFP)
|
|
.Case("hard", FloatABI::Hard)
|
|
.Default(FloatABI::Invalid);
|
|
if (ABI == FloatABI::Invalid && !StringRef(A->getValue()).empty()) {
|
|
D.Diag(diag::err_drv_invalid_mfloat_abi) << A->getAsString(Args);
|
|
ABI = FloatABI::Soft;
|
|
}
|
|
}
|
|
|
|
// It is incorrect to select hard float ABI on MachO platforms if the ABI is
|
|
// "apcs-gnu".
|
|
if (Triple.isOSBinFormatMachO() && !useAAPCSForMachO(Triple) &&
|
|
ABI == FloatABI::Hard) {
|
|
D.Diag(diag::err_drv_unsupported_opt_for_target) << A->getAsString(Args)
|
|
<< Triple.getArchName();
|
|
}
|
|
}
|
|
|
|
// If unspecified, choose the default based on the platform.
|
|
if (ABI == FloatABI::Invalid) {
|
|
switch (Triple.getOS()) {
|
|
case llvm::Triple::Darwin:
|
|
case llvm::Triple::MacOSX:
|
|
case llvm::Triple::IOS:
|
|
case llvm::Triple::TvOS: {
|
|
// Darwin defaults to "softfp" for v6 and v7.
|
|
ABI = (SubArch == 6 || SubArch == 7) ? FloatABI::SoftFP : FloatABI::Soft;
|
|
break;
|
|
}
|
|
case llvm::Triple::WatchOS:
|
|
ABI = FloatABI::Hard;
|
|
break;
|
|
|
|
// FIXME: this is invalid for WindowsCE
|
|
case llvm::Triple::Win32:
|
|
ABI = FloatABI::Hard;
|
|
break;
|
|
|
|
case llvm::Triple::FreeBSD:
|
|
switch (Triple.getEnvironment()) {
|
|
case llvm::Triple::GNUEABIHF:
|
|
ABI = FloatABI::Hard;
|
|
break;
|
|
default:
|
|
// FreeBSD defaults to soft float
|
|
ABI = FloatABI::Soft;
|
|
break;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
switch (Triple.getEnvironment()) {
|
|
case llvm::Triple::GNUEABIHF:
|
|
case llvm::Triple::EABIHF:
|
|
ABI = FloatABI::Hard;
|
|
break;
|
|
case llvm::Triple::GNUEABI:
|
|
case llvm::Triple::EABI:
|
|
// EABI is always AAPCS, and if it was not marked 'hard', it's softfp
|
|
ABI = FloatABI::SoftFP;
|
|
break;
|
|
case llvm::Triple::Android:
|
|
ABI = (SubArch == 7) ? FloatABI::SoftFP : FloatABI::Soft;
|
|
break;
|
|
default:
|
|
// Assume "soft", but warn the user we are guessing.
|
|
ABI = FloatABI::Soft;
|
|
if (Triple.getOS() != llvm::Triple::UnknownOS ||
|
|
!Triple.isOSBinFormatMachO())
|
|
D.Diag(diag::warn_drv_assuming_mfloat_abi_is) << "soft";
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
assert(ABI != FloatABI::Invalid && "must select an ABI");
|
|
return ABI;
|
|
}
|
|
|
|
static void getARMTargetFeatures(const ToolChain &TC,
|
|
const llvm::Triple &Triple,
|
|
const ArgList &Args,
|
|
std::vector<const char *> &Features,
|
|
bool ForAS) {
|
|
const Driver &D = TC.getDriver();
|
|
|
|
bool KernelOrKext =
|
|
Args.hasArg(options::OPT_mkernel, options::OPT_fapple_kext);
|
|
arm::FloatABI ABI = arm::getARMFloatABI(TC, Args);
|
|
const Arg *WaCPU = nullptr, *WaFPU = nullptr;
|
|
const Arg *WaHDiv = nullptr, *WaArch = nullptr;
|
|
|
|
if (!ForAS) {
|
|
// FIXME: Note, this is a hack, the LLVM backend doesn't actually use these
|
|
// yet (it uses the -mfloat-abi and -msoft-float options), and it is
|
|
// stripped out by the ARM target. We should probably pass this a new
|
|
// -target-option, which is handled by the -cc1/-cc1as invocation.
|
|
//
|
|
// FIXME2: For consistency, it would be ideal if we set up the target
|
|
// machine state the same when using the frontend or the assembler. We don't
|
|
// currently do that for the assembler, we pass the options directly to the
|
|
// backend and never even instantiate the frontend TargetInfo. If we did,
|
|
// and used its handleTargetFeatures hook, then we could ensure the
|
|
// assembler and the frontend behave the same.
|
|
|
|
// Use software floating point operations?
|
|
if (ABI == arm::FloatABI::Soft)
|
|
Features.push_back("+soft-float");
|
|
|
|
// Use software floating point argument passing?
|
|
if (ABI != arm::FloatABI::Hard)
|
|
Features.push_back("+soft-float-abi");
|
|
} else {
|
|
// Here, we make sure that -Wa,-mfpu/cpu/arch/hwdiv will be passed down
|
|
// to the assembler correctly.
|
|
for (const Arg *A :
|
|
Args.filtered(options::OPT_Wa_COMMA, options::OPT_Xassembler)) {
|
|
StringRef Value = A->getValue();
|
|
if (Value.startswith("-mfpu=")) {
|
|
WaFPU = A;
|
|
} else if (Value.startswith("-mcpu=")) {
|
|
WaCPU = A;
|
|
} else if (Value.startswith("-mhwdiv=")) {
|
|
WaHDiv = A;
|
|
} else if (Value.startswith("-march=")) {
|
|
WaArch = A;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Check -march. ClangAs gives preference to -Wa,-march=.
|
|
const Arg *ArchArg = Args.getLastArg(options::OPT_march_EQ);
|
|
StringRef ArchName;
|
|
if (WaArch) {
|
|
if (ArchArg)
|
|
D.Diag(clang::diag::warn_drv_unused_argument)
|
|
<< ArchArg->getAsString(Args);
|
|
ArchName = StringRef(WaArch->getValue()).substr(7);
|
|
checkARMArchName(D, WaArch, Args, ArchName, Features, Triple);
|
|
// FIXME: Set Arch.
|
|
D.Diag(clang::diag::warn_drv_unused_argument) << WaArch->getAsString(Args);
|
|
} else if (ArchArg) {
|
|
ArchName = ArchArg->getValue();
|
|
checkARMArchName(D, ArchArg, Args, ArchName, Features, Triple);
|
|
}
|
|
|
|
// Check -mcpu. ClangAs gives preference to -Wa,-mcpu=.
|
|
const Arg *CPUArg = Args.getLastArg(options::OPT_mcpu_EQ);
|
|
StringRef CPUName;
|
|
if (WaCPU) {
|
|
if (CPUArg)
|
|
D.Diag(clang::diag::warn_drv_unused_argument)
|
|
<< CPUArg->getAsString(Args);
|
|
CPUName = StringRef(WaCPU->getValue()).substr(6);
|
|
checkARMCPUName(D, WaCPU, Args, CPUName, ArchName, Features, Triple);
|
|
} else if (CPUArg) {
|
|
CPUName = CPUArg->getValue();
|
|
checkARMCPUName(D, CPUArg, Args, CPUName, ArchName, Features, Triple);
|
|
}
|
|
|
|
// Add CPU features for generic CPUs
|
|
if (CPUName == "native") {
|
|
llvm::StringMap<bool> HostFeatures;
|
|
if (llvm::sys::getHostCPUFeatures(HostFeatures))
|
|
for (auto &F : HostFeatures)
|
|
Features.push_back(
|
|
Args.MakeArgString((F.second ? "+" : "-") + F.first()));
|
|
}
|
|
|
|
// Honor -mfpu=. ClangAs gives preference to -Wa,-mfpu=.
|
|
const Arg *FPUArg = Args.getLastArg(options::OPT_mfpu_EQ);
|
|
if (WaFPU) {
|
|
if (FPUArg)
|
|
D.Diag(clang::diag::warn_drv_unused_argument)
|
|
<< FPUArg->getAsString(Args);
|
|
getARMFPUFeatures(D, WaFPU, Args, StringRef(WaFPU->getValue()).substr(6),
|
|
Features);
|
|
} else if (FPUArg) {
|
|
getARMFPUFeatures(D, FPUArg, Args, FPUArg->getValue(), Features);
|
|
}
|
|
|
|
// Honor -mhwdiv=. ClangAs gives preference to -Wa,-mhwdiv=.
|
|
const Arg *HDivArg = Args.getLastArg(options::OPT_mhwdiv_EQ);
|
|
if (WaHDiv) {
|
|
if (HDivArg)
|
|
D.Diag(clang::diag::warn_drv_unused_argument)
|
|
<< HDivArg->getAsString(Args);
|
|
getARMHWDivFeatures(D, WaHDiv, Args,
|
|
StringRef(WaHDiv->getValue()).substr(8), Features);
|
|
} else if (HDivArg)
|
|
getARMHWDivFeatures(D, HDivArg, Args, HDivArg->getValue(), Features);
|
|
|
|
// Setting -msoft-float effectively disables NEON because of the GCC
|
|
// implementation, although the same isn't true of VFP or VFP3.
|
|
if (ABI == arm::FloatABI::Soft) {
|
|
Features.push_back("-neon");
|
|
// Also need to explicitly disable features which imply NEON.
|
|
Features.push_back("-crypto");
|
|
}
|
|
|
|
// En/disable crc code generation.
|
|
if (Arg *A = Args.getLastArg(options::OPT_mcrc, options::OPT_mnocrc)) {
|
|
if (A->getOption().matches(options::OPT_mcrc))
|
|
Features.push_back("+crc");
|
|
else
|
|
Features.push_back("-crc");
|
|
}
|
|
|
|
if (Triple.getSubArch() == llvm::Triple::SubArchType::ARMSubArch_v8_1a) {
|
|
Features.insert(Features.begin(), "+v8.1a");
|
|
}
|
|
|
|
// Look for the last occurrence of -mlong-calls or -mno-long-calls. If
|
|
// neither options are specified, see if we are compiling for kernel/kext and
|
|
// decide whether to pass "+long-calls" based on the OS and its version.
|
|
if (Arg *A = Args.getLastArg(options::OPT_mlong_calls,
|
|
options::OPT_mno_long_calls)) {
|
|
if (A->getOption().matches(options::OPT_mlong_calls))
|
|
Features.push_back("+long-calls");
|
|
} else if (KernelOrKext && (!Triple.isiOS() || Triple.isOSVersionLT(6)) &&
|
|
!Triple.isWatchOS()) {
|
|
Features.push_back("+long-calls");
|
|
}
|
|
|
|
// Kernel code has more strict alignment requirements.
|
|
if (KernelOrKext)
|
|
Features.push_back("+strict-align");
|
|
else if (Arg *A = Args.getLastArg(options::OPT_mno_unaligned_access,
|
|
options::OPT_munaligned_access)) {
|
|
if (A->getOption().matches(options::OPT_munaligned_access)) {
|
|
// No v6M core supports unaligned memory access (v6M ARM ARM A3.2).
|
|
if (Triple.getSubArch() == llvm::Triple::SubArchType::ARMSubArch_v6m)
|
|
D.Diag(diag::err_target_unsupported_unaligned) << "v6m";
|
|
} else
|
|
Features.push_back("+strict-align");
|
|
} else {
|
|
// Assume pre-ARMv6 doesn't support unaligned accesses.
|
|
//
|
|
// ARMv6 may or may not support unaligned accesses depending on the
|
|
// SCTLR.U bit, which is architecture-specific. We assume ARMv6
|
|
// Darwin and NetBSD targets support unaligned accesses, and others don't.
|
|
//
|
|
// ARMv7 always has SCTLR.U set to 1, but it has a new SCTLR.A bit
|
|
// which raises an alignment fault on unaligned accesses. Linux
|
|
// defaults this bit to 0 and handles it as a system-wide (not
|
|
// per-process) setting. It is therefore safe to assume that ARMv7+
|
|
// Linux targets support unaligned accesses. The same goes for NaCl.
|
|
//
|
|
// The above behavior is consistent with GCC.
|
|
int VersionNum = getARMSubArchVersionNumber(Triple);
|
|
if (Triple.isOSDarwin() || Triple.isOSNetBSD()) {
|
|
if (VersionNum < 6 ||
|
|
Triple.getSubArch() == llvm::Triple::SubArchType::ARMSubArch_v6m)
|
|
Features.push_back("+strict-align");
|
|
} else if (Triple.isOSLinux() || Triple.isOSNaCl()) {
|
|
if (VersionNum < 7)
|
|
Features.push_back("+strict-align");
|
|
} else
|
|
Features.push_back("+strict-align");
|
|
}
|
|
|
|
// llvm does not support reserving registers in general. There is support
|
|
// for reserving r9 on ARM though (defined as a platform-specific register
|
|
// in ARM EABI).
|
|
if (Args.hasArg(options::OPT_ffixed_r9))
|
|
Features.push_back("+reserve-r9");
|
|
|
|
// The kext linker doesn't know how to deal with movw/movt.
|
|
if (KernelOrKext || Args.hasArg(options::OPT_mno_movt))
|
|
Features.push_back("+no-movt");
|
|
}
|
|
|
|
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 (useAAPCSForMachO(Triple)) {
|
|
ABIName = "aapcs";
|
|
} else if (Triple.isWatchOS()) {
|
|
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:
|
|
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
|
|
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");
|
|
}
|
|
// ARM tools end.
|
|
|
|
/// getAArch64TargetCPU - Get the (LLVM) name of the AArch64 cpu we are
|
|
/// targeting.
|
|
static std::string getAArch64TargetCPU(const ArgList &Args) {
|
|
Arg *A;
|
|
std::string CPU;
|
|
// If we have -mtune or -mcpu, use that.
|
|
if ((A = Args.getLastArg(options::OPT_mtune_EQ))) {
|
|
CPU = StringRef(A->getValue()).lower();
|
|
} else if ((A = Args.getLastArg(options::OPT_mcpu_EQ))) {
|
|
StringRef Mcpu = A->getValue();
|
|
CPU = Mcpu.split("+").first.lower();
|
|
}
|
|
|
|
// Handle CPU name is 'native'.
|
|
if (CPU == "native")
|
|
return llvm::sys::getHostCPUName();
|
|
else if (CPU.size())
|
|
return CPU;
|
|
|
|
// Make sure we pick "cyclone" if -arch is used.
|
|
// FIXME: Should this be picked by checking the target triple instead?
|
|
if (Args.getLastArg(options::OPT_arch))
|
|
return "cyclone";
|
|
|
|
return "generic";
|
|
}
|
|
|
|
void Clang::AddAArch64TargetArgs(const ArgList &Args,
|
|
ArgStringList &CmdArgs) const {
|
|
std::string TripleStr = getToolChain().ComputeEffectiveClangTriple(Args);
|
|
llvm::Triple Triple(TripleStr);
|
|
|
|
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-global-merge=false");
|
|
else
|
|
CmdArgs.push_back("-aarch64-global-merge=true");
|
|
}
|
|
}
|
|
|
|
// 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,
|
|
StringRef &CPUName, StringRef &ABIName) {
|
|
const char *DefMips32CPU = "mips32r2";
|
|
const char *DefMips64CPU = "mips64r2";
|
|
|
|
// MIPS32r6 is the default for mips(el)?-img-linux-gnu and MIPS64r6 is the
|
|
// default for mips64(el)?-img-linux-gnu.
|
|
if (Triple.getVendor() == llvm::Triple::ImaginationTechnologies &&
|
|
Triple.getEnvironment() == llvm::Triple::GNU) {
|
|
DefMips32CPU = "mips32r6";
|
|
DefMips64CPU = "mips64r6";
|
|
}
|
|
|
|
// MIPS64r6 is the default for Android MIPS64 (mips64el-linux-android).
|
|
if (Triple.isAndroid())
|
|
DefMips64CPU = "mips64r6";
|
|
|
|
// MIPS3 is the default for mips64*-unknown-openbsd.
|
|
if (Triple.getOS() == llvm::Triple::OpenBSD)
|
|
DefMips64CPU = "mips3";
|
|
|
|
if (Arg *A = Args.getLastArg(options::OPT_march_EQ, options::OPT_mcpu_EQ))
|
|
CPUName = A->getValue();
|
|
|
|
if (Arg *A = Args.getLastArg(options::OPT_mabi_EQ)) {
|
|
ABIName = A->getValue();
|
|
// Convert a GNU style Mips ABI name to the name
|
|
// accepted by LLVM Mips backend.
|
|
ABIName = llvm::StringSwitch<llvm::StringRef>(ABIName)
|
|
.Case("32", "o32")
|
|
.Case("64", "n64")
|
|
.Default(ABIName);
|
|
}
|
|
|
|
// Setup default CPU and ABI names.
|
|
if (CPUName.empty() && ABIName.empty()) {
|
|
switch (Triple.getArch()) {
|
|
default:
|
|
llvm_unreachable("Unexpected triple arch name");
|
|
case llvm::Triple::mips:
|
|
case llvm::Triple::mipsel:
|
|
CPUName = DefMips32CPU;
|
|
break;
|
|
case llvm::Triple::mips64:
|
|
case llvm::Triple::mips64el:
|
|
CPUName = DefMips64CPU;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (ABIName.empty()) {
|
|
// Deduce ABI name from the target triple.
|
|
if (Triple.getArch() == llvm::Triple::mips ||
|
|
Triple.getArch() == llvm::Triple::mipsel)
|
|
ABIName = "o32";
|
|
else
|
|
ABIName = "n64";
|
|
}
|
|
|
|
if (CPUName.empty()) {
|
|
// Deduce CPU name from ABI name.
|
|
CPUName = llvm::StringSwitch<const char *>(ABIName)
|
|
.Cases("o32", "eabi", DefMips32CPU)
|
|
.Cases("n32", "n64", DefMips64CPU)
|
|
.Default("");
|
|
}
|
|
|
|
// FIXME: Warn on inconsistent use of -march and -mabi.
|
|
}
|
|
|
|
std::string mips::getMipsABILibSuffix(const ArgList &Args,
|
|
const llvm::Triple &Triple) {
|
|
StringRef CPUName, ABIName;
|
|
tools::mips::getMipsCPUAndABI(Args, Triple, CPUName, ABIName);
|
|
return llvm::StringSwitch<std::string>(ABIName)
|
|
.Case("o32", "")
|
|
.Case("n32", "32")
|
|
.Case("n64", "64");
|
|
}
|
|
|
|
// Convert ABI name to the GNU tools acceptable variant.
|
|
static StringRef getGnuCompatibleMipsABIName(StringRef ABI) {
|
|
return llvm::StringSwitch<llvm::StringRef>(ABI)
|
|
.Case("o32", "32")
|
|
.Case("n64", "64")
|
|
.Default(ABI);
|
|
}
|
|
|
|
// Select the MIPS float ABI as determined by -msoft-float, -mhard-float,
|
|
// and -mfloat-abi=.
|
|
static mips::FloatABI getMipsFloatABI(const Driver &D, const ArgList &Args) {
|
|
mips::FloatABI ABI = mips::FloatABI::Invalid;
|
|
if (Arg *A =
|
|
Args.getLastArg(options::OPT_msoft_float, options::OPT_mhard_float,
|
|
options::OPT_mfloat_abi_EQ)) {
|
|
if (A->getOption().matches(options::OPT_msoft_float))
|
|
ABI = mips::FloatABI::Soft;
|
|
else if (A->getOption().matches(options::OPT_mhard_float))
|
|
ABI = mips::FloatABI::Hard;
|
|
else {
|
|
ABI = llvm::StringSwitch<mips::FloatABI>(A->getValue())
|
|
.Case("soft", mips::FloatABI::Soft)
|
|
.Case("hard", mips::FloatABI::Hard)
|
|
.Default(mips::FloatABI::Invalid);
|
|
if (ABI == mips::FloatABI::Invalid && !StringRef(A->getValue()).empty()) {
|
|
D.Diag(diag::err_drv_invalid_mfloat_abi) << A->getAsString(Args);
|
|
ABI = mips::FloatABI::Hard;
|
|
}
|
|
}
|
|
}
|
|
|
|
// If unspecified, choose the default based on the platform.
|
|
if (ABI == mips::FloatABI::Invalid) {
|
|
// Assume "hard", because it's a default value used by gcc.
|
|
// When we start to recognize specific target MIPS processors,
|
|
// we will be able to select the default more correctly.
|
|
ABI = mips::FloatABI::Hard;
|
|
}
|
|
|
|
assert(ABI != mips::FloatABI::Invalid && "must select an ABI");
|
|
return ABI;
|
|
}
|
|
|
|
static void AddTargetFeature(const ArgList &Args,
|
|
std::vector<const char *> &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));
|
|
}
|
|
}
|
|
|
|
static void getMIPSTargetFeatures(const Driver &D, const llvm::Triple &Triple,
|
|
const ArgList &Args,
|
|
std::vector<const char *> &Features) {
|
|
StringRef CPUName;
|
|
StringRef ABIName;
|
|
mips::getMipsCPUAndABI(Args, Triple, CPUName, ABIName);
|
|
ABIName = getGnuCompatibleMipsABIName(ABIName);
|
|
|
|
AddTargetFeature(Args, Features, options::OPT_mno_abicalls,
|
|
options::OPT_mabicalls, "noabicalls");
|
|
|
|
mips::FloatABI FloatABI = getMipsFloatABI(D, Args);
|
|
if (FloatABI == mips::FloatABI::Soft) {
|
|
// FIXME: Note, this is a hack. We need to pass the selected float
|
|
// mode to the MipsTargetInfoBase to define appropriate macros there.
|
|
// Now it is the only method.
|
|
Features.push_back("+soft-float");
|
|
}
|
|
|
|
if (Arg *A = Args.getLastArg(options::OPT_mnan_EQ)) {
|
|
StringRef Val = StringRef(A->getValue());
|
|
if (Val == "2008") {
|
|
if (mips::getSupportedNanEncoding(CPUName) & mips::Nan2008)
|
|
Features.push_back("+nan2008");
|
|
else {
|
|
Features.push_back("-nan2008");
|
|
D.Diag(diag::warn_target_unsupported_nan2008) << CPUName;
|
|
}
|
|
} else if (Val == "legacy") {
|
|
if (mips::getSupportedNanEncoding(CPUName) & mips::NanLegacy)
|
|
Features.push_back("-nan2008");
|
|
else {
|
|
Features.push_back("+nan2008");
|
|
D.Diag(diag::warn_target_unsupported_nanlegacy) << CPUName;
|
|
}
|
|
} else
|
|
D.Diag(diag::err_drv_unsupported_option_argument)
|
|
<< A->getOption().getName() << Val;
|
|
}
|
|
|
|
AddTargetFeature(Args, Features, options::OPT_msingle_float,
|
|
options::OPT_mdouble_float, "single-float");
|
|
AddTargetFeature(Args, Features, options::OPT_mips16, options::OPT_mno_mips16,
|
|
"mips16");
|
|
AddTargetFeature(Args, Features, options::OPT_mmicromips,
|
|
options::OPT_mno_micromips, "micromips");
|
|
AddTargetFeature(Args, Features, options::OPT_mdsp, options::OPT_mno_dsp,
|
|
"dsp");
|
|
AddTargetFeature(Args, Features, options::OPT_mdspr2, options::OPT_mno_dspr2,
|
|
"dspr2");
|
|
AddTargetFeature(Args, Features, options::OPT_mmsa, options::OPT_mno_msa,
|
|
"msa");
|
|
|
|
// Add the last -mfp32/-mfpxx/-mfp64 or if none are given and the ABI is O32
|
|
// pass -mfpxx
|
|
if (Arg *A = Args.getLastArg(options::OPT_mfp32, options::OPT_mfpxx,
|
|
options::OPT_mfp64)) {
|
|
if (A->getOption().matches(options::OPT_mfp32))
|
|
Features.push_back(Args.MakeArgString("-fp64"));
|
|
else if (A->getOption().matches(options::OPT_mfpxx)) {
|
|
Features.push_back(Args.MakeArgString("+fpxx"));
|
|
Features.push_back(Args.MakeArgString("+nooddspreg"));
|
|
} else
|
|
Features.push_back(Args.MakeArgString("+fp64"));
|
|
} else if (mips::shouldUseFPXX(Args, Triple, CPUName, ABIName, FloatABI)) {
|
|
Features.push_back(Args.MakeArgString("+fpxx"));
|
|
Features.push_back(Args.MakeArgString("+nooddspreg"));
|
|
}
|
|
|
|
AddTargetFeature(Args, Features, options::OPT_mno_odd_spreg,
|
|
options::OPT_modd_spreg, "nooddspreg");
|
|
}
|
|
|
|
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 = 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();
|
|
}
|
|
}
|
|
|
|
/// getPPCTargetCPU - Get the (LLVM) name of the PowerPC cpu we are targeting.
|
|
static std::string getPPCTargetCPU(const ArgList &Args) {
|
|
if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) {
|
|
StringRef CPUName = A->getValue();
|
|
|
|
if (CPUName == "native") {
|
|
std::string CPU = llvm::sys::getHostCPUName();
|
|
if (!CPU.empty() && CPU != "generic")
|
|
return CPU;
|
|
else
|
|
return "";
|
|
}
|
|
|
|
return llvm::StringSwitch<const char *>(CPUName)
|
|
.Case("common", "generic")
|
|
.Case("440", "440")
|
|
.Case("440fp", "440")
|
|
.Case("450", "450")
|
|
.Case("601", "601")
|
|
.Case("602", "602")
|
|
.Case("603", "603")
|
|
.Case("603e", "603e")
|
|
.Case("603ev", "603ev")
|
|
.Case("604", "604")
|
|
.Case("604e", "604e")
|
|
.Case("620", "620")
|
|
.Case("630", "pwr3")
|
|
.Case("G3", "g3")
|
|
.Case("7400", "7400")
|
|
.Case("G4", "g4")
|
|
.Case("7450", "7450")
|
|
.Case("G4+", "g4+")
|
|
.Case("750", "750")
|
|
.Case("970", "970")
|
|
.Case("G5", "g5")
|
|
.Case("a2", "a2")
|
|
.Case("a2q", "a2q")
|
|
.Case("e500mc", "e500mc")
|
|
.Case("e5500", "e5500")
|
|
.Case("power3", "pwr3")
|
|
.Case("power4", "pwr4")
|
|
.Case("power5", "pwr5")
|
|
.Case("power5x", "pwr5x")
|
|
.Case("power6", "pwr6")
|
|
.Case("power6x", "pwr6x")
|
|
.Case("power7", "pwr7")
|
|
.Case("power8", "pwr8")
|
|
.Case("pwr3", "pwr3")
|
|
.Case("pwr4", "pwr4")
|
|
.Case("pwr5", "pwr5")
|
|
.Case("pwr5x", "pwr5x")
|
|
.Case("pwr6", "pwr6")
|
|
.Case("pwr6x", "pwr6x")
|
|
.Case("pwr7", "pwr7")
|
|
.Case("pwr8", "pwr8")
|
|
.Case("powerpc", "ppc")
|
|
.Case("powerpc64", "ppc64")
|
|
.Case("powerpc64le", "ppc64le")
|
|
.Default("");
|
|
}
|
|
|
|
return "";
|
|
}
|
|
|
|
static void getPPCTargetFeatures(const Driver &D, const llvm::Triple &Triple,
|
|
const ArgList &Args,
|
|
std::vector<const char *> &Features) {
|
|
handleTargetFeaturesGroup(Args, Features, options::OPT_m_ppc_Features_Group);
|
|
|
|
ppc::FloatABI FloatABI = ppc::getPPCFloatABI(D, Args);
|
|
if (FloatABI == ppc::FloatABI::Soft &&
|
|
!(Triple.getArch() == llvm::Triple::ppc64 ||
|
|
Triple.getArch() == llvm::Triple::ppc64le))
|
|
Features.push_back("+soft-float");
|
|
else if (FloatABI == ppc::FloatABI::Soft &&
|
|
(Triple.getArch() == llvm::Triple::ppc64 ||
|
|
Triple.getArch() == llvm::Triple::ppc64le))
|
|
D.Diag(diag::err_drv_invalid_mfloat_abi)
|
|
<< "soft float is not supported for ppc64";
|
|
|
|
// Altivec is a bit weird, allow overriding of the Altivec feature here.
|
|
AddTargetFeature(Args, Features, options::OPT_faltivec,
|
|
options::OPT_fno_altivec, "altivec");
|
|
}
|
|
|
|
ppc::FloatABI ppc::getPPCFloatABI(const Driver &D, const ArgList &Args) {
|
|
ppc::FloatABI ABI = ppc::FloatABI::Invalid;
|
|
if (Arg *A =
|
|
Args.getLastArg(options::OPT_msoft_float, options::OPT_mhard_float,
|
|
options::OPT_mfloat_abi_EQ)) {
|
|
if (A->getOption().matches(options::OPT_msoft_float))
|
|
ABI = ppc::FloatABI::Soft;
|
|
else if (A->getOption().matches(options::OPT_mhard_float))
|
|
ABI = ppc::FloatABI::Hard;
|
|
else {
|
|
ABI = llvm::StringSwitch<ppc::FloatABI>(A->getValue())
|
|
.Case("soft", ppc::FloatABI::Soft)
|
|
.Case("hard", ppc::FloatABI::Hard)
|
|
.Default(ppc::FloatABI::Invalid);
|
|
if (ABI == ppc::FloatABI::Invalid && !StringRef(A->getValue()).empty()) {
|
|
D.Diag(diag::err_drv_invalid_mfloat_abi) << A->getAsString(Args);
|
|
ABI = ppc::FloatABI::Hard;
|
|
}
|
|
}
|
|
}
|
|
|
|
// If unspecified, choose the default based on the platform.
|
|
if (ABI == ppc::FloatABI::Invalid) {
|
|
ABI = ppc::FloatABI::Hard;
|
|
}
|
|
|
|
return ABI;
|
|
}
|
|
|
|
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);
|
|
}
|
|
}
|
|
|
|
bool ppc::hasPPCAbiArg(const ArgList &Args, const char *Value) {
|
|
Arg *A = Args.getLastArg(options::OPT_mabi_EQ);
|
|
return A && (A->getValue() == StringRef(Value));
|
|
}
|
|
|
|
/// 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 "";
|
|
}
|
|
|
|
void Clang::AddSparcTargetArgs(const ArgList &Args,
|
|
ArgStringList &CmdArgs) const {
|
|
const Driver &D = getToolChain().getDriver();
|
|
std::string Triple = getToolChain().ComputeEffectiveClangTriple(Args);
|
|
|
|
bool SoftFloatABI = false;
|
|
if (Arg *A =
|
|
Args.getLastArg(options::OPT_msoft_float, options::OPT_mhard_float)) {
|
|
if (A->getOption().matches(options::OPT_msoft_float))
|
|
SoftFloatABI = true;
|
|
}
|
|
|
|
// Only the hard-float ABI on Sparc is standardized, and it is the
|
|
// default. GCC also supports a nonstandard soft-float ABI mode, and
|
|
// perhaps LLVM should implement that, too. However, since llvm
|
|
// currently does not support Sparc soft-float, at all, display an
|
|
// error if it's requested.
|
|
if (SoftFloatABI) {
|
|
D.Diag(diag::err_drv_unsupported_opt_for_target) << "-msoft-float"
|
|
<< Triple;
|
|
}
|
|
}
|
|
|
|
static const char *getSystemZTargetCPU(const ArgList &Args) {
|
|
if (const Arg *A = Args.getLastArg(options::OPT_march_EQ))
|
|
return A->getValue();
|
|
return "z10";
|
|
}
|
|
|
|
static void getSystemZTargetFeatures(const ArgList &Args,
|
|
std::vector<const char *> &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))
|
|
Features.push_back("+transactional-execution");
|
|
else
|
|
Features.push_back("-transactional-execution");
|
|
}
|
|
// -m(no-)vx overrides use of the vector facility.
|
|
if (Arg *A = Args.getLastArg(options::OPT_mvx, options::OPT_mno_vx)) {
|
|
if (A->getOption().matches(options::OPT_mvx))
|
|
Features.push_back("+vector");
|
|
else
|
|
Features.push_back("-vector");
|
|
}
|
|
}
|
|
|
|
static const char *getX86TargetCPU(const ArgList &Args,
|
|
const llvm::Triple &Triple) {
|
|
if (const Arg *A = Args.getLastArg(options::OPT_march_EQ)) {
|
|
if (StringRef(A->getValue()) != "native") {
|
|
if (Triple.isOSDarwin() && Triple.getArchName() == "x86_64h")
|
|
return "core-avx2";
|
|
|
|
return A->getValue();
|
|
}
|
|
|
|
// FIXME: Reject attempts to use -march=native unless the target matches
|
|
// the host.
|
|
//
|
|
// FIXME: We should also incorporate the detected target features for use
|
|
// with -native.
|
|
std::string CPU = llvm::sys::getHostCPUName();
|
|
if (!CPU.empty() && CPU != "generic")
|
|
return Args.MakeArgString(CPU);
|
|
}
|
|
|
|
if (const Arg *A = Args.getLastArg(options::OPT__SLASH_arch)) {
|
|
// Mapping built by referring to X86TargetInfo::getDefaultFeatures().
|
|
StringRef Arch = A->getValue();
|
|
const char *CPU;
|
|
if (Triple.getArch() == llvm::Triple::x86) {
|
|
CPU = llvm::StringSwitch<const char *>(Arch)
|
|
.Case("IA32", "i386")
|
|
.Case("SSE", "pentium3")
|
|
.Case("SSE2", "pentium4")
|
|
.Case("AVX", "sandybridge")
|
|
.Case("AVX2", "haswell")
|
|
.Default(nullptr);
|
|
} else {
|
|
CPU = llvm::StringSwitch<const char *>(Arch)
|
|
.Case("AVX", "sandybridge")
|
|
.Case("AVX2", "haswell")
|
|
.Default(nullptr);
|
|
}
|
|
if (CPU)
|
|
return CPU;
|
|
}
|
|
|
|
// Select the default CPU if none was given (or detection failed).
|
|
|
|
if (Triple.getArch() != llvm::Triple::x86_64 &&
|
|
Triple.getArch() != llvm::Triple::x86)
|
|
return nullptr; // This routine is only handling x86 targets.
|
|
|
|
bool Is64Bit = Triple.getArch() == llvm::Triple::x86_64;
|
|
|
|
// FIXME: Need target hooks.
|
|
if (Triple.isOSDarwin()) {
|
|
if (Triple.getArchName() == "x86_64h")
|
|
return "core-avx2";
|
|
return Is64Bit ? "core2" : "yonah";
|
|
}
|
|
|
|
// Set up default CPU name for PS4 compilers.
|
|
if (Triple.isPS4CPU())
|
|
return "btver2";
|
|
|
|
// On Android use targets compatible with gcc
|
|
if (Triple.isAndroid())
|
|
return Is64Bit ? "x86-64" : "i686";
|
|
|
|
// Everything else goes to x86-64 in 64-bit mode.
|
|
if (Is64Bit)
|
|
return "x86-64";
|
|
|
|
switch (Triple.getOS()) {
|
|
case llvm::Triple::FreeBSD:
|
|
case llvm::Triple::NetBSD:
|
|
case llvm::Triple::OpenBSD:
|
|
return "i486";
|
|
case llvm::Triple::Haiku:
|
|
return "i586";
|
|
case llvm::Triple::Bitrig:
|
|
return "i686";
|
|
default:
|
|
// Fallback to p4.
|
|
return "pentium4";
|
|
}
|
|
}
|
|
|
|
/// 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";
|
|
}
|
|
|
|
static std::string getCPUName(const ArgList &Args, const llvm::Triple &T,
|
|
bool FromAs = false) {
|
|
switch (T.getArch()) {
|
|
default:
|
|
return "";
|
|
|
|
case llvm::Triple::aarch64:
|
|
case llvm::Triple::aarch64_be:
|
|
return getAArch64TargetCPU(Args);
|
|
|
|
case llvm::Triple::arm:
|
|
case llvm::Triple::armeb:
|
|
case llvm::Triple::thumb:
|
|
case llvm::Triple::thumbeb: {
|
|
StringRef MArch, MCPU;
|
|
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 = 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 getX86TargetCPU(Args, T);
|
|
|
|
case llvm::Triple::hexagon:
|
|
return "hexagon" +
|
|
toolchains::HexagonToolChain::GetTargetCPUVersion(Args).str();
|
|
|
|
case llvm::Triple::systemz:
|
|
return 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 void AddGoldPlugin(const ToolChain &ToolChain, const ArgList &Args,
|
|
ArgStringList &CmdArgs, bool IsThinLTO) {
|
|
// 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 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");
|
|
}
|
|
}
|
|
|
|
/// 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 getX86TargetFeatures(const Driver &D, const llvm::Triple &Triple,
|
|
const ArgList &Args,
|
|
std::vector<const char *> &Features) {
|
|
// If -march=native, autodetect the feature list.
|
|
if (const Arg *A = Args.getLastArg(options::OPT_march_EQ)) {
|
|
if (StringRef(A->getValue()) == "native") {
|
|
llvm::StringMap<bool> HostFeatures;
|
|
if (llvm::sys::getHostCPUFeatures(HostFeatures))
|
|
for (auto &F : HostFeatures)
|
|
Features.push_back(
|
|
Args.MakeArgString((F.second ? "+" : "-") + F.first()));
|
|
}
|
|
}
|
|
|
|
if (Triple.getArchName() == "x86_64h") {
|
|
// x86_64h implies quite a few of the more modern subtarget features
|
|
// for Haswell class CPUs, but not all of them. Opt-out of a few.
|
|
Features.push_back("-rdrnd");
|
|
Features.push_back("-aes");
|
|
Features.push_back("-pclmul");
|
|
Features.push_back("-rtm");
|
|
Features.push_back("-hle");
|
|
Features.push_back("-fsgsbase");
|
|
}
|
|
|
|
const llvm::Triple::ArchType ArchType = Triple.getArch();
|
|
// Add features to be compatible with gcc for Android.
|
|
if (Triple.isAndroid()) {
|
|
if (ArchType == llvm::Triple::x86_64) {
|
|
Features.push_back("+sse4.2");
|
|
Features.push_back("+popcnt");
|
|
} else
|
|
Features.push_back("+ssse3");
|
|
}
|
|
|
|
// Set features according to the -arch flag on MSVC.
|
|
if (Arg *A = Args.getLastArg(options::OPT__SLASH_arch)) {
|
|
StringRef Arch = A->getValue();
|
|
bool ArchUsed = false;
|
|
// First, look for flags that are shared in x86 and x86-64.
|
|
if (ArchType == llvm::Triple::x86_64 || ArchType == llvm::Triple::x86) {
|
|
if (Arch == "AVX" || Arch == "AVX2") {
|
|
ArchUsed = true;
|
|
Features.push_back(Args.MakeArgString("+" + Arch.lower()));
|
|
}
|
|
}
|
|
// Then, look for x86-specific flags.
|
|
if (ArchType == llvm::Triple::x86) {
|
|
if (Arch == "IA32") {
|
|
ArchUsed = true;
|
|
} else if (Arch == "SSE" || Arch == "SSE2") {
|
|
ArchUsed = true;
|
|
Features.push_back(Args.MakeArgString("+" + Arch.lower()));
|
|
}
|
|
}
|
|
if (!ArchUsed)
|
|
D.Diag(clang::diag::warn_drv_unused_argument) << A->getAsString(Args);
|
|
}
|
|
|
|
// Now add any that the user explicitly requested on the command line,
|
|
// which may override the defaults.
|
|
handleTargetFeaturesGroup(Args, Features, options::OPT_m_x86_Features_Group);
|
|
}
|
|
|
|
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;
|
|
}
|
|
}
|
|
}
|
|
|
|
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::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");
|
|
}
|
|
}
|
|
|
|
// Decode AArch64 features from string like +[no]featureA+[no]featureB+...
|
|
static bool DecodeAArch64Features(const Driver &D, StringRef text,
|
|
std::vector<const char *> &Features) {
|
|
SmallVector<StringRef, 8> Split;
|
|
text.split(Split, StringRef("+"), -1, false);
|
|
|
|
for (StringRef Feature : Split) {
|
|
const char *result = llvm::StringSwitch<const char *>(Feature)
|
|
.Case("fp", "+fp-armv8")
|
|
.Case("simd", "+neon")
|
|
.Case("crc", "+crc")
|
|
.Case("crypto", "+crypto")
|
|
.Case("fp16", "+fullfp16")
|
|
.Case("profile", "+spe")
|
|
.Case("nofp", "-fp-armv8")
|
|
.Case("nosimd", "-neon")
|
|
.Case("nocrc", "-crc")
|
|
.Case("nocrypto", "-crypto")
|
|
.Case("nofp16", "-fullfp16")
|
|
.Case("noprofile", "-spe")
|
|
.Default(nullptr);
|
|
if (result)
|
|
Features.push_back(result);
|
|
else if (Feature == "neon" || Feature == "noneon")
|
|
D.Diag(diag::err_drv_no_neon_modifier);
|
|
else
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
// Check if the CPU name and feature modifiers in -mcpu are legal. If yes,
|
|
// decode CPU and feature.
|
|
static bool DecodeAArch64Mcpu(const Driver &D, StringRef Mcpu, StringRef &CPU,
|
|
std::vector<const char *> &Features) {
|
|
std::pair<StringRef, StringRef> Split = Mcpu.split("+");
|
|
CPU = Split.first;
|
|
if (CPU == "cyclone" || CPU == "cortex-a53" || CPU == "cortex-a57" ||
|
|
CPU == "cortex-a72" || CPU == "cortex-a35" || CPU == "exynos-m1") {
|
|
Features.push_back("+neon");
|
|
Features.push_back("+crc");
|
|
Features.push_back("+crypto");
|
|
} else if (CPU == "generic") {
|
|
Features.push_back("+neon");
|
|
} else {
|
|
return false;
|
|
}
|
|
|
|
if (Split.second.size() && !DecodeAArch64Features(D, Split.second, Features))
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
static bool
|
|
getAArch64ArchFeaturesFromMarch(const Driver &D, StringRef March,
|
|
const ArgList &Args,
|
|
std::vector<const char *> &Features) {
|
|
std::string MarchLowerCase = March.lower();
|
|
std::pair<StringRef, StringRef> Split = StringRef(MarchLowerCase).split("+");
|
|
|
|
if (Split.first == "armv8-a" || Split.first == "armv8a") {
|
|
// ok, no additional features.
|
|
} else if (Split.first == "armv8.1-a" || Split.first == "armv8.1a") {
|
|
Features.push_back("+v8.1a");
|
|
} else if (Split.first == "armv8.2-a" || Split.first == "armv8.2a" ) {
|
|
Features.push_back("+v8.2a");
|
|
} else {
|
|
return false;
|
|
}
|
|
|
|
if (Split.second.size() && !DecodeAArch64Features(D, Split.second, Features))
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
static bool
|
|
getAArch64ArchFeaturesFromMcpu(const Driver &D, StringRef Mcpu,
|
|
const ArgList &Args,
|
|
std::vector<const char *> &Features) {
|
|
StringRef CPU;
|
|
std::string McpuLowerCase = Mcpu.lower();
|
|
if (!DecodeAArch64Mcpu(D, McpuLowerCase, CPU, Features))
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
static bool
|
|
getAArch64MicroArchFeaturesFromMtune(const Driver &D, StringRef Mtune,
|
|
const ArgList &Args,
|
|
std::vector<const char *> &Features) {
|
|
std::string MtuneLowerCase = Mtune.lower();
|
|
// Handle CPU name is 'native'.
|
|
if (MtuneLowerCase == "native")
|
|
MtuneLowerCase = llvm::sys::getHostCPUName();
|
|
if (MtuneLowerCase == "cyclone") {
|
|
Features.push_back("+zcm");
|
|
Features.push_back("+zcz");
|
|
}
|
|
return true;
|
|
}
|
|
|
|
static bool
|
|
getAArch64MicroArchFeaturesFromMcpu(const Driver &D, StringRef Mcpu,
|
|
const ArgList &Args,
|
|
std::vector<const char *> &Features) {
|
|
StringRef CPU;
|
|
std::vector<const char *> DecodedFeature;
|
|
std::string McpuLowerCase = Mcpu.lower();
|
|
if (!DecodeAArch64Mcpu(D, McpuLowerCase, CPU, DecodedFeature))
|
|
return false;
|
|
|
|
return getAArch64MicroArchFeaturesFromMtune(D, CPU, Args, Features);
|
|
}
|
|
|
|
static void getAArch64TargetFeatures(const Driver &D, const ArgList &Args,
|
|
std::vector<const char *> &Features) {
|
|
Arg *A;
|
|
bool success = true;
|
|
// Enable NEON by default.
|
|
Features.push_back("+neon");
|
|
if ((A = Args.getLastArg(options::OPT_march_EQ)))
|
|
success = getAArch64ArchFeaturesFromMarch(D, A->getValue(), Args, Features);
|
|
else if ((A = Args.getLastArg(options::OPT_mcpu_EQ)))
|
|
success = getAArch64ArchFeaturesFromMcpu(D, A->getValue(), Args, Features);
|
|
else if (Args.hasArg(options::OPT_arch))
|
|
success = getAArch64ArchFeaturesFromMcpu(D, getAArch64TargetCPU(Args), Args,
|
|
Features);
|
|
|
|
if (success && (A = Args.getLastArg(options::OPT_mtune_EQ)))
|
|
success =
|
|
getAArch64MicroArchFeaturesFromMtune(D, A->getValue(), Args, Features);
|
|
else if (success && (A = Args.getLastArg(options::OPT_mcpu_EQ)))
|
|
success =
|
|
getAArch64MicroArchFeaturesFromMcpu(D, A->getValue(), Args, Features);
|
|
else if (Args.hasArg(options::OPT_arch))
|
|
success = getAArch64MicroArchFeaturesFromMcpu(D, getAArch64TargetCPU(Args),
|
|
Args, Features);
|
|
|
|
if (!success)
|
|
D.Diag(diag::err_drv_clang_unsupported) << A->getAsString(Args);
|
|
|
|
if (Args.getLastArg(options::OPT_mgeneral_regs_only)) {
|
|
Features.push_back("-fp-armv8");
|
|
Features.push_back("-crypto");
|
|
Features.push_back("-neon");
|
|
}
|
|
|
|
// En/disable crc
|
|
if (Arg *A = Args.getLastArg(options::OPT_mcrc, options::OPT_mnocrc)) {
|
|
if (A->getOption().matches(options::OPT_mcrc))
|
|
Features.push_back("+crc");
|
|
else
|
|
Features.push_back("-crc");
|
|
}
|
|
|
|
if (Arg *A = Args.getLastArg(options::OPT_mno_unaligned_access,
|
|
options::OPT_munaligned_access))
|
|
if (A->getOption().matches(options::OPT_mno_unaligned_access))
|
|
Features.push_back("+strict-align");
|
|
|
|
if (Args.hasArg(options::OPT_ffixed_x18))
|
|
Features.push_back("+reserve-x18");
|
|
}
|
|
|
|
static void getHexagonTargetFeatures(const ArgList &Args,
|
|
std::vector<const char *> &Features) {
|
|
bool HasHVX = false, HasHVXD = false;
|
|
|
|
// FIXME: This should be able to use handleTargetFeaturesGroup except it is
|
|
// doing dependent option handling here rather than in initFeatureMap or a
|
|
// similar handler.
|
|
for (auto &A : Args) {
|
|
auto &Opt = A->getOption();
|
|
if (Opt.matches(options::OPT_mhexagon_hvx))
|
|
HasHVX = true;
|
|
else if (Opt.matches(options::OPT_mno_hexagon_hvx))
|
|
HasHVXD = HasHVX = false;
|
|
else if (Opt.matches(options::OPT_mhexagon_hvx_double))
|
|
HasHVXD = HasHVX = true;
|
|
else if (Opt.matches(options::OPT_mno_hexagon_hvx_double))
|
|
HasHVXD = false;
|
|
else
|
|
continue;
|
|
A->claim();
|
|
}
|
|
|
|
Features.push_back(HasHVX ? "+hvx" : "-hvx");
|
|
Features.push_back(HasHVXD ? "+hvx-double" : "-hvx-double");
|
|
}
|
|
|
|
static void getWebAssemblyTargetFeatures(const ArgList &Args,
|
|
std::vector<const char *> &Features) {
|
|
handleTargetFeaturesGroup(Args, Features, options::OPT_m_wasm_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<const char *> Features;
|
|
switch (Triple.getArch()) {
|
|
default:
|
|
break;
|
|
case llvm::Triple::mips:
|
|
case llvm::Triple::mipsel:
|
|
case llvm::Triple::mips64:
|
|
case llvm::Triple::mips64el:
|
|
getMIPSTargetFeatures(D, Triple, Args, Features);
|
|
break;
|
|
|
|
case llvm::Triple::arm:
|
|
case llvm::Triple::armeb:
|
|
case llvm::Triple::thumb:
|
|
case llvm::Triple::thumbeb:
|
|
getARMTargetFeatures(TC, Triple, Args, Features, ForAS);
|
|
break;
|
|
|
|
case llvm::Triple::ppc:
|
|
case llvm::Triple::ppc64:
|
|
case llvm::Triple::ppc64le:
|
|
getPPCTargetFeatures(D, Triple, Args, Features);
|
|
break;
|
|
case llvm::Triple::systemz:
|
|
getSystemZTargetFeatures(Args, Features);
|
|
break;
|
|
case llvm::Triple::aarch64:
|
|
case llvm::Triple::aarch64_be:
|
|
getAArch64TargetFeatures(D, Args, Features);
|
|
break;
|
|
case llvm::Triple::x86:
|
|
case llvm::Triple::x86_64:
|
|
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;
|
|
}
|
|
|
|
// Find the last of each feature.
|
|
llvm::StringMap<unsigned> LastOpt;
|
|
for (unsigned I = 0, N = Features.size(); I < N; ++I) {
|
|
const char *Name = Features[I];
|
|
assert(Name[0] == '-' || Name[0] == '+');
|
|
LastOpt[Name + 1] = I;
|
|
}
|
|
|
|
for (unsigned I = 0, N = Features.size(); I < N; ++I) {
|
|
// If this feature was overridden, ignore it.
|
|
const char *Name = Features[I];
|
|
llvm::StringMap<unsigned>::iterator LastI = LastOpt.find(Name + 1);
|
|
assert(LastI != LastOpt.end());
|
|
unsigned Last = LastI->second;
|
|
if (Last != I)
|
|
continue;
|
|
|
|
CmdArgs.push_back("-target-feature");
|
|
CmdArgs.push_back(Name);
|
|
}
|
|
}
|
|
|
|
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, PS4, and MSVC.
|
|
// FIXME: Remove MSVC from this list once things work.
|
|
bool CXXExceptionsEnabled = Triple.getArch() != llvm::Triple::xcore &&
|
|
!Triple.isPS4CPU() &&
|
|
!Triple.isWindowsMSVCEnvironment();
|
|
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 &Act : *A)
|
|
if (ContainsCompileAction(Act))
|
|
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");
|
|
|
|
// 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;
|
|
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;
|
|
}
|
|
|
|
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.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 {
|
|
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 (MipsTargetFeature != nullptr) {
|
|
CmdArgs.push_back("-target-feature");
|
|
CmdArgs.push_back(MipsTargetFeature);
|
|
}
|
|
}
|
|
|
|
// This adds the static libclang_rt.builtins-arch.a directly to the command line
|
|
// FIXME: Make sure we can also emit shared objects if they're requested
|
|
// and available, check for possible errors, etc.
|
|
static void addClangRT(const ToolChain &TC, const ArgList &Args,
|
|
ArgStringList &CmdArgs) {
|
|
CmdArgs.push_back(TC.getCompilerRTArgString(Args, "builtins"));
|
|
}
|
|
|
|
namespace {
|
|
enum OpenMPRuntimeKind {
|
|
/// An unknown OpenMP runtime. We can't generate effective OpenMP code
|
|
/// without knowing what runtime to target.
|
|
OMPRT_Unknown,
|
|
|
|
/// The LLVM OpenMP runtime. When completed and integrated, this will become
|
|
/// the default for Clang.
|
|
OMPRT_OMP,
|
|
|
|
/// The GNU OpenMP runtime. Clang doesn't support generating OpenMP code for
|
|
/// this runtime but can swallow the pragmas, and find and link against the
|
|
/// runtime library itself.
|
|
OMPRT_GOMP,
|
|
|
|
/// The legacy name for the LLVM OpenMP runtime from when it was the Intel
|
|
/// OpenMP runtime. We support this mode for users with existing dependencies
|
|
/// on this runtime library name.
|
|
OMPRT_IOMP5
|
|
};
|
|
}
|
|
|
|
/// Compute the desired OpenMP runtime from the flag provided.
|
|
static OpenMPRuntimeKind getOpenMPRuntime(const ToolChain &TC,
|
|
const ArgList &Args) {
|
|
StringRef RuntimeName(CLANG_DEFAULT_OPENMP_RUNTIME);
|
|
|
|
const Arg *A = Args.getLastArg(options::OPT_fopenmp_EQ);
|
|
if (A)
|
|
RuntimeName = A->getValue();
|
|
|
|
auto RT = llvm::StringSwitch<OpenMPRuntimeKind>(RuntimeName)
|
|
.Case("libomp", OMPRT_OMP)
|
|
.Case("libgomp", OMPRT_GOMP)
|
|
.Case("libiomp5", OMPRT_IOMP5)
|
|
.Default(OMPRT_Unknown);
|
|
|
|
if (RT == OMPRT_Unknown) {
|
|
if (A)
|
|
TC.getDriver().Diag(diag::err_drv_unsupported_option_argument)
|
|
<< A->getOption().getName() << A->getValue();
|
|
else
|
|
// FIXME: We could use a nicer diagnostic here.
|
|
TC.getDriver().Diag(diag::err_drv_unsupported_opt) << "-fopenmp";
|
|
}
|
|
|
|
return RT;
|
|
}
|
|
|
|
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 (getOpenMPRuntime(TC, Args)) {
|
|
case OMPRT_OMP:
|
|
CmdArgs.push_back("-lomp");
|
|
break;
|
|
case OMPRT_GOMP:
|
|
CmdArgs.push_back("-lgomp");
|
|
break;
|
|
case OMPRT_IOMP5:
|
|
CmdArgs.push_back("-liomp5");
|
|
break;
|
|
case OMPRT_Unknown:
|
|
// Already diagnosed.
|
|
break;
|
|
}
|
|
}
|
|
|
|
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");
|
|
}
|
|
|
|
// 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");
|
|
CmdArgs.push_back("-lpthread");
|
|
CmdArgs.push_back("-lrt");
|
|
CmdArgs.push_back("-lm");
|
|
// There's no libdl on FreeBSD.
|
|
if (TC.getTriple().getOS() != llvm::Triple::FreeBSD)
|
|
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())
|
|
StaticRuntimes.push_back("safestack");
|
|
if (SanArgs.needsCfiRt())
|
|
StaticRuntimes.push_back("cfi");
|
|
if (SanArgs.needsCfiDiagRt())
|
|
StaticRuntimes.push_back("cfi_diag");
|
|
if (SanArgs.needsStatsRt()) {
|
|
NonWholeStaticRuntimes.push_back("stats");
|
|
RequiredSymbols.push_back("__sanitizer_stats_register");
|
|
}
|
|
}
|
|
|
|
// 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");
|
|
return !StaticRuntimes.empty();
|
|
}
|
|
|
|
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 shouldUseFramePointerForTarget(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()) {
|
|
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::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::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);
|
|
if (Args.hasArg(options::OPT_pg))
|
|
return true;
|
|
|
|
return shouldUseFramePointerForTarget(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 shouldUseFramePointerForTarget(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()));
|
|
}
|
|
|
|
static VersionTuple getMSCompatibilityVersion(unsigned Version) {
|
|
if (Version < 100)
|
|
return VersionTuple(Version);
|
|
|
|
if (Version < 10000)
|
|
return VersionTuple(Version / 100, Version % 100);
|
|
|
|
unsigned Build = 0, Factor = 1;
|
|
for (; Version > 10000; Version = Version / 10, Factor = Factor * 10)
|
|
Build = Build + (Version % 10) * Factor;
|
|
return VersionTuple(Version / 100, Version % 100, Build);
|
|
}
|
|
|
|
// 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());
|
|
}
|
|
|
|
VersionTuple visualstudio::getMSVCVersion(const Driver *D,
|
|
const llvm::Triple &Triple,
|
|
const llvm::opt::ArgList &Args,
|
|
bool IsWindowsMSVC) {
|
|
if (Args.hasFlag(options::OPT_fms_extensions, options::OPT_fno_ms_extensions,
|
|
IsWindowsMSVC) ||
|
|
Args.hasArg(options::OPT_fmsc_version) ||
|
|
Args.hasArg(options::OPT_fms_compatibility_version)) {
|
|
const Arg *MSCVersion = Args.getLastArg(options::OPT_fmsc_version);
|
|
const Arg *MSCompatibilityVersion =
|
|
Args.getLastArg(options::OPT_fms_compatibility_version);
|
|
|
|
if (MSCVersion && MSCompatibilityVersion) {
|
|
if (D)
|
|
D->Diag(diag::err_drv_argument_not_allowed_with)
|
|
<< MSCVersion->getAsString(Args)
|
|
<< MSCompatibilityVersion->getAsString(Args);
|
|
return VersionTuple();
|
|
}
|
|
|
|
if (MSCompatibilityVersion) {
|
|
VersionTuple MSVT;
|
|
if (MSVT.tryParse(MSCompatibilityVersion->getValue()) && D)
|
|
D->Diag(diag::err_drv_invalid_value)
|
|
<< MSCompatibilityVersion->getAsString(Args)
|
|
<< MSCompatibilityVersion->getValue();
|
|
return MSVT;
|
|
}
|
|
|
|
if (MSCVersion) {
|
|
unsigned Version = 0;
|
|
if (StringRef(MSCVersion->getValue()).getAsInteger(10, Version) && D)
|
|
D->Diag(diag::err_drv_invalid_value) << MSCVersion->getAsString(Args)
|
|
<< MSCVersion->getValue();
|
|
return getMSCompatibilityVersion(Version);
|
|
}
|
|
|
|
unsigned Major, Minor, Micro;
|
|
Triple.getEnvironmentVersion(Major, Minor, Micro);
|
|
if (Major || Minor || Micro)
|
|
return VersionTuple(Major, Minor, Micro);
|
|
|
|
return VersionTuple(18);
|
|
}
|
|
return VersionTuple();
|
|
}
|
|
|
|
static void addPGOAndCoverageFlags(Compilation &C, const Driver &D,
|
|
const InputInfo &Output, const ArgList &Args,
|
|
ArgStringList &CmdArgs) {
|
|
auto *ProfileGenerateArg = Args.getLastArg(
|
|
options::OPT_fprofile_instr_generate,
|
|
options::OPT_fprofile_instr_generate_EQ, options::OPT_fprofile_generate,
|
|
options::OPT_fprofile_generate_EQ,
|
|
options::OPT_fno_profile_instr_generate);
|
|
if (ProfileGenerateArg &&
|
|
ProfileGenerateArg->getOption().matches(
|
|
options::OPT_fno_profile_instr_generate))
|
|
ProfileGenerateArg = nullptr;
|
|
|
|
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;
|
|
|
|
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))
|
|
ProfileGenerateArg->render(Args, CmdArgs);
|
|
else if (ProfileGenerateArg->getOption().matches(
|
|
options::OPT_fprofile_generate_EQ)) {
|
|
SmallString<128> Path(ProfileGenerateArg->getValue());
|
|
llvm::sys::path::append(Path, "default.profraw");
|
|
CmdArgs.push_back(
|
|
Args.MakeArgString(Twine("-fprofile-instr-generate=") + Path));
|
|
} else
|
|
Args.AddAllArgs(CmdArgs, options::OPT_fprofile_instr_generate);
|
|
}
|
|
|
|
if (ProfileUseArg) {
|
|
if (ProfileUseArg->getOption().matches(options::OPT_fprofile_instr_use_EQ))
|
|
ProfileUseArg->render(Args, CmdArgs);
|
|
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-instr-use=") + 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-file");
|
|
SmallString<128> CoverageFilename;
|
|
if (Arg *FinalOutput = C.getArgs().getLastArg(options::OPT_o)) {
|
|
CoverageFilename = FinalOutput->getValue();
|
|
} else {
|
|
CoverageFilename = llvm::sys::path::filename(Output.getBaseInput());
|
|
}
|
|
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);
|
|
}
|
|
}
|
|
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 llvm::Triple &Triple,
|
|
const ArgList &Args) {
|
|
// FIXME: why does this code...and so much everywhere else, use both
|
|
// ToolChain.getTriple() and Triple?
|
|
bool PIE = ToolChain.isPIEDefault();
|
|
bool PIC = PIE || ToolChain.isPICDefault();
|
|
// The Darwin/MachO default to use PIC does not apply when using -static.
|
|
if (ToolChain.getTriple().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 (ToolChain.getTriple().isAndroid()) {
|
|
switch (ToolChain.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 (ToolChain.getTriple().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);
|
|
// 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 (Triple.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 && (ToolChain.getTriple().isOSDarwin() || Triple.isPS4CPU()))
|
|
IsPICLevelTwo |= ToolChain.isPICDefault();
|
|
|
|
// This kernel flags are a trump-card: they will disable PIC/PIE
|
|
// generation, independent of the argument order.
|
|
if (KernelOrKext && ((!Triple.isiOS() || Triple.isOSVersionLT(6)) &&
|
|
!Triple.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 (!ToolChain.getTriple().isOSDarwin())
|
|
ToolChain.getDriver().Diag(diag::err_drv_unsupported_opt_for_target)
|
|
<< A->getSpelling() << ToolChain.getTriple().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 ? 2 : 0, false);
|
|
}
|
|
|
|
if (PIC)
|
|
return std::make_tuple(llvm::Reloc::PIC_, IsPICLevelTwo ? 2 : 1, PIE);
|
|
|
|
return std::make_tuple(llvm::Reloc::Static, 0, false);
|
|
}
|
|
|
|
static const char *RelocationModelName(llvm::Reloc::Model Model) {
|
|
switch (Model) {
|
|
case llvm::Reloc::Default:
|
|
return nullptr;
|
|
case llvm::Reloc::Static:
|
|
return "static";
|
|
case llvm::Reloc::PIC_:
|
|
return "pic";
|
|
case llvm::Reloc::DynamicNoPIC:
|
|
return "dynamic-no-pic";
|
|
}
|
|
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, ToolChain.getTriple(), Args);
|
|
|
|
if (RelocationModel != llvm::Reloc::Static)
|
|
CmdArgs.push_back("-KPIC");
|
|
}
|
|
|
|
void Clang::ConstructJob(Compilation &C, const JobAction &JA,
|
|
const InputInfo &Output, const InputInfoList &Inputs,
|
|
const ArgList &Args, const char *LinkingOutput) const {
|
|
std::string TripleStr = getToolChain().ComputeEffectiveClangTriple(Args);
|
|
const llvm::Triple Triple(TripleStr);
|
|
|
|
bool KernelOrKext =
|
|
Args.hasArg(options::OPT_mkernel, options::OPT_fapple_kext);
|
|
const Driver &D = getToolChain().getDriver();
|
|
ArgStringList CmdArgs;
|
|
|
|
bool IsWindowsGNU = getToolChain().getTriple().isWindowsGNUEnvironment();
|
|
bool IsWindowsCygnus =
|
|
getToolChain().getTriple().isWindowsCygwinEnvironment();
|
|
bool IsWindowsMSVC = getToolChain().getTriple().isWindowsMSVCEnvironment();
|
|
bool IsPS4CPU = getToolChain().getTriple().isPS4CPU();
|
|
|
|
// 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). All other jobs are expected to have exactly one
|
|
// input.
|
|
bool IsCuda = types::isCuda(Input.getType());
|
|
assert((IsCuda || Inputs.size() == 1) && "Unable to handle multiple inputs.");
|
|
|
|
// 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));
|
|
|
|
const ToolChain *AuxToolChain = nullptr;
|
|
if (IsCuda) {
|
|
// FIXME: We need a (better) way to pass information about
|
|
// particular compilation pass we're constructing here. For now we
|
|
// can check which toolchain we're using and pick the other one to
|
|
// extract the triple.
|
|
if (&getToolChain() == C.getCudaDeviceToolChain())
|
|
AuxToolChain = C.getCudaHostToolChain();
|
|
else if (&getToolChain() == C.getCudaHostToolChain())
|
|
AuxToolChain = C.getCudaDeviceToolChain();
|
|
else
|
|
llvm_unreachable("Can't figure out CUDA compilation mode.");
|
|
assert(AuxToolChain != nullptr && "No aux toolchain.");
|
|
CmdArgs.push_back("-aux-triple");
|
|
CmdArgs.push_back(Args.MakeArgString(AuxToolChain->getTriple().str()));
|
|
CmdArgs.push_back("-fcuda-target-overloads");
|
|
CmdArgs.push_back("-fcuda-disable-target-call-checks");
|
|
}
|
|
|
|
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 (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);
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
// 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");
|
|
#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");
|
|
|
|
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(), Triple, Args);
|
|
|
|
const char *RMName = RelocationModelName(RelocationModel);
|
|
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("-pie-level");
|
|
CmdArgs.push_back(PICLevel == 1 ? "1" : "2");
|
|
}
|
|
}
|
|
|
|
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)) {
|
|
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 (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("-mrtd");
|
|
|
|
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_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");
|
|
|
|
// 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>.
|
|
if (!getToolChain().getTriple().isOSDarwin())
|
|
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");
|
|
}
|
|
|
|
// 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::x86:
|
|
case llvm::Triple::x86_64:
|
|
AddX86TargetArgs(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.
|
|
enum CodeGenOptions::DebugInfoKind DebugInfoKind =
|
|
CodeGenOptions::NoDebugInfo;
|
|
bool EmitCodeView = false;
|
|
|
|
// Add clang-cl arguments.
|
|
if (getToolChain().getDriver().IsCLMode())
|
|
AddClangCLArgs(Args, 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.
|
|
types::ID InputType = Input.getType();
|
|
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
|
|
: "-");
|
|
}
|
|
|
|
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.)
|
|
if (SplitDwarfArg && DebugInfoKind < CodeGenOptions::LimitedDebugInfo &&
|
|
A->getIndex() > SplitDwarfArg->getIndex())
|
|
SplitDwarfArg = nullptr;
|
|
} 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);
|
|
|
|
// PS4 defaults to no column info
|
|
if (Args.hasFlag(options::OPT_gcolumn_info, options::OPT_gno_column_info,
|
|
/*Default=*/ !IsPS4CPU))
|
|
CmdArgs.push_back("-dwarf-column-info");
|
|
|
|
// FIXME: Move backend command line options to the module.
|
|
if (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) {
|
|
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);
|
|
|
|
// -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");
|
|
}
|
|
|
|
// CloudABI and WebAssembly use -ffunction-sections and -fdata-sections by
|
|
// default.
|
|
bool UseSeparateSections = Triple.getOS() == llvm::Triple::CloudABI ||
|
|
Triple.getArch() == llvm::Triple::wasm32 ||
|
|
Triple.getArch() == llvm::Triple::wasm64;
|
|
|
|
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);
|
|
|
|
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,
|
|
AuxToolChain);
|
|
|
|
// 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.
|
|
if (Args.hasFlag(options::OPT_ffreestanding, options::OPT_fhosted, false) ||
|
|
KernelOrKext)
|
|
CmdArgs.push_back("-ffreestanding");
|
|
|
|
// 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
|
|
if (Args.hasFlag(options::OPT_fopenmp, options::OPT_fopenmp_EQ,
|
|
options::OPT_fno_openmp, false))
|
|
switch (getOpenMPRuntime(getToolChain(), Args)) {
|
|
case OMPRT_OMP:
|
|
case 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");
|
|
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);
|
|
|
|
// -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;
|
|
if (getToolChain().getSanitizerArgs().needsSafeStackRt()) {
|
|
Args.ClaimAllArgs(options::OPT_fno_stack_protector);
|
|
Args.ClaimAllArgs(options::OPT_fstack_protector_all);
|
|
Args.ClaimAllArgs(options::OPT_fstack_protector_strong);
|
|
Args.ClaimAllArgs(options::OPT_fstack_protector);
|
|
} else 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);
|
|
}
|
|
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 -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);
|
|
}
|
|
|
|
// -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");
|
|
}
|
|
|
|
// -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 HaveModules = 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");
|
|
HaveModules = true;
|
|
}
|
|
}
|
|
|
|
// -fmodule-maps enables implicit reading of module map files. By default,
|
|
// this is enabled if we are using precompiled modules.
|
|
if (Args.hasFlag(options::OPT_fimplicit_module_maps,
|
|
options::OPT_fno_implicit_module_maps, HaveModules)) {
|
|
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)) {
|
|
CmdArgs.push_back("-fno-implicit-modules");
|
|
}
|
|
|
|
// -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);
|
|
|
|
// -fmodule-map-file can be used to specify files containing module
|
|
// definitions.
|
|
Args.AddAllArgs(CmdArgs, options::OPT_fmodule_map_file);
|
|
|
|
// -fmodule-file can be used to specify files containing precompiled modules.
|
|
if (HaveModules)
|
|
Args.AddAllArgs(CmdArgs, options::OPT_fmodule_file);
|
|
else
|
|
Args.ClaimAllArgs(options::OPT_fmodule_file);
|
|
|
|
// -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 (HaveModules) {
|
|
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));
|
|
}
|
|
|
|
// When building modules and generating crashdumps, we need to dump a module
|
|
// dependency VFS alongside the output.
|
|
if (HaveModules && 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 (HaveModules)
|
|
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().toEpochTime())));
|
|
}
|
|
|
|
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);
|
|
|
|
// -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");
|
|
|
|
// -fms-compatibility-version=18.00 is default.
|
|
VersionTuple MSVT = visualstudio::getMSVCVersion(
|
|
&D, getToolChain().getTriple(), Args, IsWindowsMSVC);
|
|
if (!MSVT.empty())
|
|
CmdArgs.push_back(
|
|
Args.MakeArgString("-fms-compatibility-version=" + MSVT.getAsString()));
|
|
|
|
bool IsMSVC2015Compatible = MSVT.getMajor() >= 19;
|
|
if (ImplyVCPPCXXVer) {
|
|
if (IsMSVC2015Compatible)
|
|
CmdArgs.push_back("-std=c++14");
|
|
else
|
|
CmdArgs.push_back("-std=c++11");
|
|
}
|
|
|
|
// -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 (Args.hasArg(options::OPT_fno_inline_functions))
|
|
CmdArgs.push_back("-fno-inline-functions");
|
|
|
|
ObjCRuntime objcRuntime = AddObjCRuntimeArgs(Args, CmdArgs, rewriteKind);
|
|
|
|
// -fobjc-dispatch-method is only relevant with the nonfragile-abi, and
|
|
// legacy is the default. Except for deployment taget 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");
|
|
|
|
}
|
|
|
|
// -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");
|
|
|
|
// Handle -fobjc-gc and -fobjc-gc-only. They are exclusive, and -fobjc-gc-only
|
|
// takes precedence.
|
|
const Arg *GCArg = Args.getLastArg(options::OPT_fobjc_gc_only);
|
|
if (!GCArg)
|
|
GCArg = Args.getLastArg(options::OPT_fobjc_gc);
|
|
if (GCArg) {
|
|
if (ARC) {
|
|
D.Diag(diag::err_drv_objc_gc_arr) << GCArg->getAsString(Args);
|
|
} else if (getToolChain().SupportsObjCGC()) {
|
|
GCArg->render(Args, CmdArgs);
|
|
} else {
|
|
// FIXME: We should move this to a hard error.
|
|
D.Diag(diag::warn_drv_objc_gc_unsupported) << GCArg->getAsString(Args);
|
|
}
|
|
}
|
|
|
|
// 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 (GCArg) {
|
|
if (WeakArg->getOption().matches(options::OPT_fobjc_weak))
|
|
D.Diag(diag::err_objc_weak_with_gc);
|
|
} 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 (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");
|
|
|
|
// -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");
|
|
|
|
// -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 != "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 != "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 (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 the default, unless the terminal doesn't support
|
|
// them.
|
|
// Support both clang's -f[no-]color-diagnostics and gcc's
|
|
// -f[no-]diagnostics-colors[=never|always|auto].
|
|
enum { Colors_On, Colors_Off, Colors_Auto } ShowColors = Colors_Auto;
|
|
for (const auto &Arg : Args) {
|
|
const Option &O = Arg->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;
|
|
|
|
Arg->claim();
|
|
if (O.matches(options::OPT_fcolor_diagnostics) ||
|
|
O.matches(options::OPT_fdiagnostics_color)) {
|
|
ShowColors = Colors_On;
|
|
} else if (O.matches(options::OPT_fno_color_diagnostics) ||
|
|
O.matches(options::OPT_fno_diagnostics_color)) {
|
|
ShowColors = Colors_Off;
|
|
} else {
|
|
assert(O.matches(options::OPT_fdiagnostics_color_EQ));
|
|
StringRef value(Arg->getValue());
|
|
if (value == "always")
|
|
ShowColors = Colors_On;
|
|
else if (value == "never")
|
|
ShowColors = Colors_Off;
|
|
else if (value == "auto")
|
|
ShowColors = Colors_Auto;
|
|
else
|
|
getToolChain().getDriver().Diag(diag::err_drv_clang_unsupported)
|
|
<< ("-fdiagnostics-color=" + value).str();
|
|
}
|
|
}
|
|
if (ShowColors == Colors_On ||
|
|
(ShowColors == Colors_Auto && llvm::sys::Process::StandardErrHasColors()))
|
|
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.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);
|
|
|
|
// -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");
|
|
}
|
|
|
|
// Default to -fno-builtin-str{cat,cpy} on Darwin for ARM.
|
|
//
|
|
// FIXME: This is disabled until clang -cc1 supports -fno-builtin-foo. PR4941.
|
|
#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() && !HaveModules))
|
|
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();
|
|
}
|
|
|
|
// 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.
|
|
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.
|
|
if (C.getDriver().isSaveTempsEnabled() && 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());
|
|
}
|
|
|
|
// 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 {
|
|
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 && !isa<CompileJobAction>(JA) && !isa<BackendJobAction>(JA))
|
|
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 {
|
|
EHFlags() : Synch(false), Asynch(false), NoExceptC(false) {}
|
|
bool Synch;
|
|
bool Asynch;
|
|
bool NoExceptC;
|
|
};
|
|
} // 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 noexcept. This
|
|
/// modifier is an optimization, so we ignore it for now.
|
|
/// 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);
|
|
continue;
|
|
case 'c':
|
|
EH.NoExceptC = maybeConsumeDash(EHVal, I);
|
|
continue;
|
|
case 's':
|
|
EH.Synch = maybeConsumeDash(EHVal, I);
|
|
continue;
|
|
default:
|
|
break;
|
|
}
|
|
D.Diag(clang::diag::err_drv_invalid_value) << "/EH" << EHVal;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return EH;
|
|
}
|
|
|
|
void Clang::AddClangCLArgs(const ArgList &Args, ArgStringList &CmdArgs,
|
|
enum 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");
|
|
FlagForCRT = "--dependent-lib=libcmt";
|
|
break;
|
|
case options::OPT__SLASH_MTd:
|
|
CmdArgs.push_back("-D_DEBUG");
|
|
CmdArgs.push_back("-D_MT");
|
|
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");
|
|
|
|
// Emit CodeView if -Z7 is present.
|
|
*EmitCodeView = Args.hasArg(options::OPT__SLASH_Z7);
|
|
bool EmitDwarf = Args.hasArg(options::OPT_gdwarf);
|
|
// If we are emitting CV but not DWARF, don't build information that LLVM
|
|
// can't yet process.
|
|
if (*EmitCodeView && !EmitDwarf)
|
|
*DebugInfoKind = CodeGenOptions::DebugLineTablesOnly;
|
|
if (*EmitCodeView)
|
|
CmdArgs.push_back("-gcodeview");
|
|
|
|
const Driver &D = getToolChain().getDriver();
|
|
EHFlags EH = parseClangCLEHFlags(D, Args);
|
|
// FIXME: Do something with NoExceptC.
|
|
if (EH.Synch || EH.Asynch) {
|
|
CmdArgs.push_back("-fcxx-exceptions");
|
|
CmdArgs.push_back("-fexceptions");
|
|
}
|
|
|
|
// /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 (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::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];
|
|
|
|
std::string TripleStr =
|
|
getToolChain().ComputeEffectiveClangTriple(Args, Input.getType());
|
|
const llvm::Triple Triple(TripleStr);
|
|
|
|
// 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.
|
|
if (SourceAction->getType() == types::TY_Asm ||
|
|
SourceAction->getType() == types::TY_PP_Asm) {
|
|
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();
|
|
RenderDebugEnablingArgs(Args, CmdArgs,
|
|
(WantDebug ? CodeGenOptions::LimitedDebugInfo
|
|
: CodeGenOptions::NoDebugInfo),
|
|
DwarfVersion, llvm::DebuggerKind::Default);
|
|
|
|
// 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);
|
|
}
|
|
|
|
// 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(), Triple, 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;
|
|
}
|
|
|
|
// 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 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);
|
|
|
|
//----------------------------------------------------------------------------
|
|
// 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);
|
|
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 char *Linker = Args.MakeArgString(getToolChain().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");
|
|
|
|
AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs);
|
|
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 (getARMSubArchVersionNumber(Triple) >= 7 || isARMMProfile(Triple))
|
|
CmdArgs.push_back("--be8");
|
|
}
|
|
|
|
mips::NanEncoding mips::getSupportedNanEncoding(StringRef &CPU) {
|
|
// Strictly speaking, mips32r2 and mips64r2 are NanLegacy-only since Nan2008
|
|
// was first introduced in Release 3. However, other compilers have
|
|
// traditionally allowed it for Release 2 so we should do the same.
|
|
return (NanEncoding)llvm::StringSwitch<int>(CPU)
|
|
.Case("mips1", NanLegacy)
|
|
.Case("mips2", NanLegacy)
|
|
.Case("mips3", NanLegacy)
|
|
.Case("mips4", NanLegacy)
|
|
.Case("mips5", NanLegacy)
|
|
.Case("mips32", NanLegacy)
|
|
.Case("mips32r2", NanLegacy | Nan2008)
|
|
.Case("mips32r3", NanLegacy | Nan2008)
|
|
.Case("mips32r5", NanLegacy | Nan2008)
|
|
.Case("mips32r6", Nan2008)
|
|
.Case("mips64", NanLegacy)
|
|
.Case("mips64r2", NanLegacy | Nan2008)
|
|
.Case("mips64r3", NanLegacy | Nan2008)
|
|
.Case("mips64r5", NanLegacy | Nan2008)
|
|
.Case("mips64r6", Nan2008)
|
|
.Default(NanLegacy);
|
|
}
|
|
|
|
bool mips::hasMipsAbiArg(const ArgList &Args, const char *Value) {
|
|
Arg *A = Args.getLastArg(options::OPT_mabi_EQ);
|
|
return A && (A->getValue() == StringRef(Value));
|
|
}
|
|
|
|
bool mips::isUCLibc(const ArgList &Args) {
|
|
Arg *A = Args.getLastArg(options::OPT_m_libc_Group);
|
|
return A && A->getOption().matches(options::OPT_muclibc);
|
|
}
|
|
|
|
bool mips::isNaN2008(const ArgList &Args, const llvm::Triple &Triple) {
|
|
if (Arg *NaNArg = Args.getLastArg(options::OPT_mnan_EQ))
|
|
return llvm::StringSwitch<bool>(NaNArg->getValue())
|
|
.Case("2008", true)
|
|
.Case("legacy", false)
|
|
.Default(false);
|
|
|
|
// NaN2008 is the default for MIPS32r6/MIPS64r6.
|
|
return llvm::StringSwitch<bool>(getCPUName(Args, Triple))
|
|
.Cases("mips32r6", "mips64r6", true)
|
|
.Default(false);
|
|
|
|
return false;
|
|
}
|
|
|
|
bool mips::isFPXXDefault(const llvm::Triple &Triple, StringRef CPUName,
|
|
StringRef ABIName, mips::FloatABI FloatABI) {
|
|
if (Triple.getVendor() != llvm::Triple::ImaginationTechnologies &&
|
|
Triple.getVendor() != llvm::Triple::MipsTechnologies)
|
|
return false;
|
|
|
|
if (ABIName != "32")
|
|
return false;
|
|
|
|
// FPXX shouldn't be used if either -msoft-float or -mfloat-abi=soft is
|
|
// present.
|
|
if (FloatABI == mips::FloatABI::Soft)
|
|
return false;
|
|
|
|
return llvm::StringSwitch<bool>(CPUName)
|
|
.Cases("mips2", "mips3", "mips4", "mips5", true)
|
|
.Cases("mips32", "mips32r2", "mips32r3", "mips32r5", true)
|
|
.Cases("mips64", "mips64r2", "mips64r3", "mips64r5", true)
|
|
.Default(false);
|
|
}
|
|
|
|
bool mips::shouldUseFPXX(const ArgList &Args, const llvm::Triple &Triple,
|
|
StringRef CPUName, StringRef ABIName,
|
|
mips::FloatABI FloatABI) {
|
|
bool UseFPXX = isFPXXDefault(Triple, CPUName, ABIName, FloatABI);
|
|
|
|
// FPXX shouldn't be used if -msingle-float is present.
|
|
if (Arg *A = Args.getLastArg(options::OPT_msingle_float,
|
|
options::OPT_mdouble_float))
|
|
if (A->getOption().matches(options::OPT_msingle_float))
|
|
UseFPXX = false;
|
|
|
|
return UseFPXX;
|
|
}
|
|
|
|
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);
|
|
T.setArch(Arch);
|
|
|
|
if (Str == "x86_64h")
|
|
T.setArchName(Str);
|
|
else if (Str == "armv6m" || Str == "armv7m" || Str == "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("--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);
|
|
|
|
AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs);
|
|
|
|
if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nodefaultlibs)) {
|
|
if (D.CCCIsCXX())
|
|
ToolChain.AddCXXStdlibLibArgs(Args, CmdArgs);
|
|
CmdArgs.push_back("-lc");
|
|
CmdArgs.push_back("-lcompiler_rt");
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
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[3] = {0, 0, 0};
|
|
if (Arg *A = Args.getLastArg(options::OPT_mlinker_version_EQ)) {
|
|
bool HadExtra;
|
|
if (!Driver::GetReleaseVersion(A->getValue(), Version[0], Version[1],
|
|
Version[2], HadExtra) ||
|
|
HadExtra)
|
|
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. If not found, the option is not used
|
|
// and 'ld' will use its default mechanism to search for libLTO.dylib.
|
|
if (Version[0] >= 133) {
|
|
// Search for libLTO in <InstalledDir>/../lib/libLTO.dylib
|
|
StringRef P = llvm::sys::path::parent_path(D.getInstalledDir());
|
|
SmallString<128> LibLTOPath(P);
|
|
llvm::sys::path::append(LibLTOPath, "lib");
|
|
llvm::sys::path::append(LibLTOPath, "libLTO.dylib");
|
|
if (llvm::sys::fs::exists(LibLTOPath)) {
|
|
CmdArgs.push_back("-lto_library");
|
|
CmdArgs.push_back(C.getArgs().MakeArgString(LibLTOPath));
|
|
} else {
|
|
D.Diag(diag::warn_drv_lto_libpath);
|
|
}
|
|
}
|
|
}
|
|
|
|
// 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");
|
|
}
|
|
|
|
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);
|
|
|
|
// 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);
|
|
// 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 (!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);
|
|
}
|
|
|
|
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);
|
|
|
|
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(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(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(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");
|
|
}
|
|
|
|
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 (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
|
|
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);
|
|
|
|
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);
|
|
|
|
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(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(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");
|
|
|
|
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");
|
|
}
|
|
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);
|
|
|
|
bool NeedsSanitizerDeps = addSanitizerRuntimes(ToolChain, Args, CmdArgs);
|
|
AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs);
|
|
|
|
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;
|
|
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(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(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(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 {
|
|
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,
|
|
llvm::Triple(getToolChain().ComputeEffectiveClangTriple(Args)));
|
|
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")));
|
|
CmdArgs.push_back(
|
|
Args.MakeArgString(getToolChain().GetFilePath("crtbegin.o")));
|
|
} else {
|
|
CmdArgs.push_back(
|
|
Args.MakeArgString(getToolChain().GetFilePath("crti.o")));
|
|
CmdArgs.push_back(
|
|
Args.MakeArgString(getToolChain().GetFilePath("crtbeginS.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);
|
|
|
|
unsigned Major, Minor, Micro;
|
|
getToolChain().getTriple().getOSVersion(Major, Minor, Micro);
|
|
bool useLibgcc = true;
|
|
if (Major >= 7 || (Major == 6 && Minor == 99 && Micro >= 49) || Major == 0) {
|
|
switch (getToolChain().getArch()) {
|
|
case llvm::Triple::aarch64:
|
|
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::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))
|
|
CmdArgs.push_back(
|
|
Args.MakeArgString(getToolChain().GetFilePath("crtend.o")));
|
|
else
|
|
CmdArgs.push_back(
|
|
Args.MakeArgString(getToolChain().GetFilePath("crtendS.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);
|
|
|
|
std::string TripleStr = getToolChain().ComputeEffectiveClangTriple(Args);
|
|
llvm::Triple Triple = llvm::Triple(TripleStr);
|
|
|
|
ArgStringList CmdArgs;
|
|
|
|
llvm::Reloc::Model RelocationModel;
|
|
unsigned PICLevel;
|
|
bool IsPIE;
|
|
std::tie(RelocationModel, PICLevel, IsPIE) =
|
|
ParsePICArgs(getToolChain(), Triple, 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(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(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 -march=armv7-a 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()).lower() == "krait")
|
|
CmdArgs.push_back("-march=armv7-a");
|
|
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 = 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.
|
|
CmdArgs.push_back(ABIName == "64" ? "-KPIC" : "-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,
|
|
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 = 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 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)
|
|
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 std::string getLinuxDynamicLinker(const ArgList &Args,
|
|
const toolchains::Linux &ToolChain) {
|
|
const llvm::Triple::ArchType Arch = ToolChain.getArch();
|
|
|
|
if (ToolChain.getTriple().isAndroid()) {
|
|
if (ToolChain.getTriple().isArch64Bit())
|
|
return "/system/bin/linker64";
|
|
else
|
|
return "/system/bin/linker";
|
|
} else if (Arch == llvm::Triple::x86 || Arch == llvm::Triple::sparc ||
|
|
Arch == llvm::Triple::sparcel)
|
|
return "/lib/ld-linux.so.2";
|
|
else if (Arch == llvm::Triple::aarch64)
|
|
return "/lib/ld-linux-aarch64.so.1";
|
|
else if (Arch == llvm::Triple::aarch64_be)
|
|
return "/lib/ld-linux-aarch64_be.so.1";
|
|
else if (Arch == llvm::Triple::arm || Arch == llvm::Triple::thumb) {
|
|
if (ToolChain.getTriple().getEnvironment() == llvm::Triple::GNUEABIHF ||
|
|
arm::getARMFloatABI(ToolChain, Args) == arm::FloatABI::Hard)
|
|
return "/lib/ld-linux-armhf.so.3";
|
|
else
|
|
return "/lib/ld-linux.so.3";
|
|
} else if (Arch == llvm::Triple::armeb || Arch == llvm::Triple::thumbeb) {
|
|
// TODO: check which dynamic linker name.
|
|
if (ToolChain.getTriple().getEnvironment() == llvm::Triple::GNUEABIHF ||
|
|
arm::getARMFloatABI(ToolChain, Args) == arm::FloatABI::Hard)
|
|
return "/lib/ld-linux-armhf.so.3";
|
|
else
|
|
return "/lib/ld-linux.so.3";
|
|
} else if (Arch == llvm::Triple::mips || Arch == llvm::Triple::mipsel ||
|
|
Arch == llvm::Triple::mips64 || Arch == llvm::Triple::mips64el) {
|
|
std::string LibDir =
|
|
"/lib" + mips::getMipsABILibSuffix(Args, ToolChain.getTriple());
|
|
StringRef LibName;
|
|
bool IsNaN2008 = mips::isNaN2008(Args, ToolChain.getTriple());
|
|
if (mips::isUCLibc(Args))
|
|
LibName = IsNaN2008 ? "ld-uClibc-mipsn8.so.0" : "ld-uClibc.so.0";
|
|
else if (!ToolChain.getTriple().hasEnvironment()) {
|
|
bool LE = (ToolChain.getTriple().getArch() == llvm::Triple::mipsel) ||
|
|
(ToolChain.getTriple().getArch() == llvm::Triple::mips64el);
|
|
LibName = LE ? "ld-musl-mipsel.so.1" : "ld-musl-mips.so.1";
|
|
} else
|
|
LibName = IsNaN2008 ? "ld-linux-mipsn8.so.1" : "ld.so.1";
|
|
|
|
return (LibDir + "/" + LibName).str();
|
|
} else if (Arch == llvm::Triple::ppc)
|
|
return "/lib/ld.so.1";
|
|
else if (Arch == llvm::Triple::ppc64) {
|
|
if (ppc::hasPPCAbiArg(Args, "elfv2"))
|
|
return "/lib64/ld64.so.2";
|
|
return "/lib64/ld64.so.1";
|
|
} else if (Arch == llvm::Triple::ppc64le) {
|
|
if (ppc::hasPPCAbiArg(Args, "elfv1"))
|
|
return "/lib64/ld64.so.1";
|
|
return "/lib64/ld64.so.2";
|
|
} else if (Arch == llvm::Triple::systemz)
|
|
return "/lib/ld64.so.1";
|
|
else if (Arch == llvm::Triple::sparcv9)
|
|
return "/lib64/ld-linux.so.2";
|
|
else if (Arch == llvm::Triple::x86_64 &&
|
|
ToolChain.getTriple().getEnvironment() == llvm::Triple::GNUX32)
|
|
return "/libx32/ld-linux-x32.so.2";
|
|
else
|
|
return "/lib64/ld-linux-x86-64.so.2";
|
|
}
|
|
|
|
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:
|
|
addClangRT(TC, Args, CmdArgs);
|
|
break;
|
|
}
|
|
break;
|
|
case ToolChain::RLT_Libgcc:
|
|
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:
|
|
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 "armebelf_linux_eabi"; /* TODO: check which NAME. */
|
|
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:
|
|
llvm_unreachable("Unexpected arch");
|
|
}
|
|
}
|
|
|
|
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();
|
|
|
|
std::string TripleStr = getToolChain().ComputeEffectiveClangTriple(Args);
|
|
llvm::Triple Triple = llvm::Triple(TripleStr);
|
|
|
|
const llvm::Triple::ArchType Arch = ToolChain.getArch();
|
|
const bool isAndroid = ToolChain.getTriple().isAndroid();
|
|
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::filename(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);
|
|
|
|
for (const auto &Opt : ToolChain.ExtraOpts)
|
|
CmdArgs.push_back(Opt.c_str());
|
|
|
|
if (!Args.hasArg(options::OPT_static)) {
|
|
CmdArgs.push_back("--eh-frame-hdr");
|
|
}
|
|
|
|
CmdArgs.push_back("-m");
|
|
CmdArgs.push_back(getLDMOption(ToolChain.getTriple(), Args));
|
|
|
|
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 (Arch == llvm::Triple::arm || Arch == llvm::Triple::armeb ||
|
|
Arch == llvm::Triple::thumb || Arch == llvm::Triple::thumbeb ||
|
|
(!Args.hasArg(options::OPT_static) &&
|
|
!Args.hasArg(options::OPT_shared))) {
|
|
CmdArgs.push_back("-dynamic-linker");
|
|
CmdArgs.push_back(Args.MakeArgString(
|
|
D.DyldPrefix + getLinuxDynamicLinker(Args, ToolChain)));
|
|
}
|
|
|
|
CmdArgs.push_back("-o");
|
|
CmdArgs.push_back(Output.getFilename());
|
|
|
|
if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) {
|
|
if (!isAndroid) {
|
|
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;
|
|
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);
|
|
|
|
if (Args.hasArg(options::OPT_Z_Xlinker__no_demangle))
|
|
CmdArgs.push_back("--no-demangle");
|
|
|
|
bool NeedsSanitizerDeps = addSanitizerRuntimes(ToolChain, Args, CmdArgs);
|
|
AddLinkerInputs(ToolChain, Inputs, Args, CmdArgs);
|
|
// 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);
|
|
|
|
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 (getOpenMPRuntime(ToolChain, Args)) {
|
|
case OMPRT_OMP:
|
|
CmdArgs.push_back("-lomp");
|
|
break;
|
|
case 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 OMPRT_IOMP5:
|
|
CmdArgs.push_back("-liomp5");
|
|
break;
|
|
case OMPRT_Unknown:
|
|
// Already diagnosed.
|
|
break;
|
|
}
|
|
}
|
|
|
|
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");
|
|
|
|
if (Args.hasArg(options::OPT_static))
|
|
CmdArgs.push_back("--end-group");
|
|
else
|
|
AddRunTimeLibs(ToolChain, D, CmdArgs, Args);
|
|
}
|
|
|
|
if (!Args.hasArg(options::OPT_nostartfiles)) {
|
|
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")));
|
|
}
|
|
}
|
|
|
|
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);
|
|
|
|
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 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);
|
|
|
|
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);
|
|
|
|
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.c_str()));
|
|
}
|
|
}
|
|
|
|
std::string WindowsSdkLibPath;
|
|
if (MSVC.getWindowsSDKLibraryPath(WindowsSdkLibPath))
|
|
CmdArgs.push_back(Args.MakeArgString(std::string("-libpath:") +
|
|
WindowsSdkLibPath.c_str()));
|
|
}
|
|
|
|
CmdArgs.push_back("-nologo");
|
|
|
|
if (Args.hasArg(options::OPT_g_Group, options::OPT__SLASH_Z7))
|
|
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 (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("-include:___asan_seh_interceptor"));
|
|
} 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));
|
|
}
|
|
}
|
|
|
|
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 (getOpenMPRuntime(getToolChain(), Args)) {
|
|
case OMPRT_OMP:
|
|
CmdArgs.push_back("-defaultlib:libomp.lib");
|
|
break;
|
|
case OMPRT_IOMP5:
|
|
CmdArgs.push_back("-defaultlib:libiomp5md.lib");
|
|
break;
|
|
case OMPRT_GOMP:
|
|
break;
|
|
case OMPRT_Unknown:
|
|
// Already diagnosed.
|
|
break;
|
|
}
|
|
}
|
|
|
|
// 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 (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_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);
|
|
|
|
// 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);
|
|
|
|
// 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);
|
|
|
|
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);
|
|
|
|
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("-mcpu=myriad2");
|
|
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.AddAllArgs(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});
|
|
|
|
// 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");
|
|
CmdArgs.push_back("-cv:myriad2"); // Chip Version
|
|
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);
|
|
|
|
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);
|
|
|
|
AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs);
|
|
|
|
if (UseDefaultLibs) {
|
|
if (C.getDriver().CCCIsCXX())
|
|
CmdArgs.push_back("-lstdc++");
|
|
if (T.getOS() == llvm::Triple::RTEMS) {
|
|
CmdArgs.push_back("--start-group");
|
|
CmdArgs.push_back("-lc");
|
|
// 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("ps4-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);
|
|
|
|
if (Args.hasArg(options::OPT_pthread)) {
|
|
CmdArgs.push_back("-lpthread");
|
|
}
|
|
|
|
const char *Exec = Args.MakeArgString(ToolChain.GetProgramPath("ps4-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);
|
|
|
|
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("ps4-ld.gold"));
|
|
#else
|
|
Args.MakeArgString(ToolChain.GetProgramPath("ps4-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");
|
|
|
|
std::vector<std::string> gpu_archs =
|
|
Args.getAllArgValues(options::OPT_march_EQ);
|
|
assert(gpu_archs.size() == 1 && "Exactly one GPU Arch required for ptxas.");
|
|
const std::string& gpu_arch = gpu_archs[0];
|
|
|
|
|
|
ArgStringList CmdArgs;
|
|
CmdArgs.push_back(TC.getTriple().isArch64Bit() ? "-m64" : "-m32");
|
|
|
|
// 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.
|
|
if (Arg *A = Args.getLastArg(options::OPT_O_Group)) {
|
|
// -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");
|
|
}
|
|
|
|
// Don't bother passing -g to ptxas: It's enabled by default at -O0, and
|
|
// not supported at other optimization levels.
|
|
|
|
CmdArgs.push_back("--gpu-name");
|
|
CmdArgs.push_back(Args.MakeArgString(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 = 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 = cast<const CudaDeviceAction>(II.getAction());
|
|
// 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)
|
|
? A->getComputeArchName()
|
|
: A->getGpuArchName();
|
|
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));
|
|
}
|