blob: a8d3f010bd08db29bfc810509e24fcda3f0e3a99 [file] [log] [blame]
//===--- Tools.cpp - Tools Implementations --------------------------------===//
//
// 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/LangOptions.h"
#include "clang/Basic/ObjCRuntime.h"
#include "clang/Basic/Version.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/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/Compression.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Format.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 <sys/stat.h>
using namespace clang::driver;
using namespace clang::driver::tools;
using namespace clang;
using namespace llvm::opt;
static void addAssemblerKPIC(const ArgList &Args, ArgStringList &CmdArgs) {
Arg *LastPICArg = Args.getLastArg(options::OPT_fPIC, options::OPT_fno_PIC,
options::OPT_fpic, options::OPT_fno_pic,
options::OPT_fPIE, options::OPT_fno_PIE,
options::OPT_fpie, options::OPT_fno_pie);
if (!LastPICArg)
return;
if (LastPICArg->getOption().matches(options::OPT_fPIC) ||
LastPICArg->getOption().matches(options::OPT_fpic) ||
LastPICArg->getOption().matches(options::OPT_fPIE) ||
LastPICArg->getOption().matches(options::OPT_fpie)) {
CmdArgs.push_back("-KPIC");
}
}
/// 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) && !D.CCCIsCPP())
D.Diag(diag::err_drv_argument_only_allowed_with)
<< A->getAsString(Args) << "-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";
}
// 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 (InputInfoList::const_iterator
it = Inputs.begin(), ie = Inputs.end(); it != ie; ++it) {
const InputInfo &II = *it;
if (!TC.HasNativeLLVMSupport()) {
// Don't try to pass LLVM inputs unless we have native support.
if (II.getType() == types::TY_LLVM_IR ||
II.getType() == types::TY_LTO_IR ||
II.getType() == types::TY_LLVM_BC ||
II.getType() == types::TY_LTO_BC)
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
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 {
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))
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);
// Convert all -MQ <target> args to -MT <quoted target>
for (arg_iterator it = Args.filtered_begin(options::OPT_MT,
options::OPT_MQ),
ie = Args.filtered_end(); it != ie; ++it) {
const Arg *A = *it;
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 (arg_iterator it = Args.filtered_begin(options::OPT_clang_i_Group),
ie = Args.filtered_end(); it != ie; ++it) {
const Arg *A = it;
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.str()))
FoundPCH = true;
}
if (!FoundPCH) {
llvm::sys::path::replace_extension(P, "pth");
if (llvm::sys::fs::exists(P.str()))
FoundPTH = true;
}
if (!FoundPCH && !FoundPTH) {
llvm::sys::path::replace_extension(P, "gch");
if (llvm::sys::fs::exists(P.str())) {
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.str()));
continue;
} else {
// Ignore the PCH if not first on command line and emit warning.
D.Diag(diag::warn_drv_pch_not_first_include)
<< P.str() << A->getAsString(Args);
}
}
}
// Not translated, render as usual.
A->claim();
A->render(Args, CmdArgs);
}
Args.AddAllArgs(CmdArgs, options::OPT_D, options::OPT_U);
Args.AddAllArgs(CmdArgs, options::OPT_I_Group, options::OPT_F,
options::OPT_index_header_map);
// Add -Wp, and -Xassembler 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");
// Add C++ include arguments, if needed.
if (types::isCXX(Inputs[0].getType()))
getToolChain().AddClangCXXStdlibIncludeArgs(Args, CmdArgs);
// Add system include arguments.
getToolChain().AddClangSystemIncludeArgs(Args, CmdArgs);
}
/// getAArch64TargetCPU - Get the (LLVM) name of the AArch64 cpu we are targeting.
//
// FIXME: tblgen this.
static std::string getAArch64TargetCPU(const ArgList &Args,
const llvm::Triple &Triple) {
// FIXME: Warn on inconsistent use of -mcpu and -march.
// If we have -mcpu=, use that.
if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) {
StringRef MCPU = A->getValue();
// Handle -mcpu=native.
if (MCPU == "native")
return llvm::sys::getHostCPUName();
else
return MCPU;
}
return "generic";
}
// 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::arm64:
case llvm::Triple::arm64_be:
case llvm::Triple::arm:
case llvm::Triple::armeb:
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::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:
return true;
}
}
// Handle -mfpu=.
//
// FIXME: Centralize feature selection, defaulting shouldn't be also in the
// frontend target.
static void getAArch64FPUFeatures(const Driver &D, const Arg *A,
const ArgList &Args,
std::vector<const char *> &Features) {
StringRef FPU = A->getValue();
if (FPU == "fp-armv8") {
Features.push_back("+fp-armv8");
} else if (FPU == "neon-fp-armv8") {
Features.push_back("+fp-armv8");
Features.push_back("+neon");
} else if (FPU == "crypto-neon-fp-armv8") {
Features.push_back("+fp-armv8");
Features.push_back("+neon");
Features.push_back("+crypto");
} else if (FPU == "neon") {
Features.push_back("+neon");
} else
D.Diag(diag::err_drv_clang_unsupported) << A->getAsString(Args);
}
// Handle -mhwdiv=.
static void getARMHWDivFeatures(const Driver &D, const Arg *A,
const ArgList &Args,
std::vector<const char *> &Features) {
StringRef HWDiv = A->getValue();
if (HWDiv == "arm") {
Features.push_back("+hwdiv-arm");
Features.push_back("-hwdiv");
} else if (HWDiv == "thumb") {
Features.push_back("-hwdiv-arm");
Features.push_back("+hwdiv");
} else if (HWDiv == "arm,thumb" || HWDiv == "thumb,arm") {
Features.push_back("+hwdiv-arm");
Features.push_back("+hwdiv");
} else if (HWDiv == "none") {
Features.push_back("-hwdiv-arm");
Features.push_back("-hwdiv");
} else
D.Diag(diag::err_drv_clang_unsupported) << A->getAsString(Args);
}
// Handle -mfpu=.
//
// FIXME: Centralize feature selection, defaulting shouldn't be also in the
// frontend target.
static void getARMFPUFeatures(const Driver &D, const Arg *A,
const ArgList &Args,
std::vector<const char *> &Features) {
StringRef FPU = A->getValue();
// Set the target features based on the FPU.
if (FPU == "fpa" || FPU == "fpe2" || FPU == "fpe3" || FPU == "maverick") {
// Disable any default FPU support.
Features.push_back("-vfp2");
Features.push_back("-vfp3");
Features.push_back("-neon");
} else if (FPU == "vfp") {
Features.push_back("+vfp2");
Features.push_back("-neon");
} else if (FPU == "vfp3-d16" || FPU == "vfpv3-d16") {
Features.push_back("+vfp3");
Features.push_back("+d16");
Features.push_back("-neon");
} else if (FPU == "vfp3" || FPU == "vfpv3") {
Features.push_back("+vfp3");
Features.push_back("-neon");
} else if (FPU == "vfp4-d16" || FPU == "vfpv4-d16") {
Features.push_back("+vfp4");
Features.push_back("+d16");
Features.push_back("-neon");
} else if (FPU == "vfp4" || FPU == "vfpv4") {
Features.push_back("+vfp4");
Features.push_back("-neon");
} else if (FPU == "fp4-sp-d16" || FPU == "fpv4-sp-d16") {
Features.push_back("+vfp4");
Features.push_back("+d16");
Features.push_back("+fp-only-sp");
Features.push_back("-neon");
} else if (FPU == "fp-armv8") {
Features.push_back("+fp-armv8");
Features.push_back("-neon");
Features.push_back("-crypto");
} else if (FPU == "neon-fp-armv8") {
Features.push_back("+fp-armv8");
Features.push_back("+neon");
Features.push_back("-crypto");
} else if (FPU == "crypto-neon-fp-armv8") {
Features.push_back("+fp-armv8");
Features.push_back("+neon");
Features.push_back("+crypto");
} else if (FPU == "neon") {
Features.push_back("+neon");
} else if (FPU == "none") {
Features.push_back("-vfp2");
Features.push_back("-vfp3");
Features.push_back("-vfp4");
Features.push_back("-fp-armv8");
Features.push_back("-crypto");
Features.push_back("-neon");
} else
D.Diag(diag::err_drv_clang_unsupported) << A->getAsString(Args);
}
// Select the float ABI as determined by -msoft-float, -mhard-float, and
// -mfloat-abi=.
StringRef tools::arm::getARMFloatABI(const Driver &D, const ArgList &Args,
const llvm::Triple &Triple) {
StringRef FloatABI;
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))
FloatABI = "soft";
else if (A->getOption().matches(options::OPT_mhard_float))
FloatABI = "hard";
else {
FloatABI = A->getValue();
if (FloatABI != "soft" && FloatABI != "softfp" && FloatABI != "hard") {
D.Diag(diag::err_drv_invalid_mfloat_abi)
<< A->getAsString(Args);
FloatABI = "soft";
}
}
}
// If unspecified, choose the default based on the platform.
if (FloatABI.empty()) {
switch (Triple.getOS()) {
case llvm::Triple::Darwin:
case llvm::Triple::MacOSX:
case llvm::Triple::IOS: {
// Darwin defaults to "softfp" for v6 and v7.
//
// FIXME: Factor out an ARM class so we can cache the arch somewhere.
std::string ArchName =
arm::getLLVMArchSuffixForARM(arm::getARMTargetCPU(Args, Triple));
if (StringRef(ArchName).startswith("v6") ||
StringRef(ArchName).startswith("v7"))
FloatABI = "softfp";
else
FloatABI = "soft";
break;
}
// FIXME: this is invalid for WindowsCE
case llvm::Triple::Win32:
FloatABI = "hard";
break;
case llvm::Triple::FreeBSD:
switch(Triple.getEnvironment()) {
case llvm::Triple::GNUEABIHF:
FloatABI = "hard";
break;
default:
// FreeBSD defaults to soft float
FloatABI = "soft";
break;
}
break;
default:
switch(Triple.getEnvironment()) {
case llvm::Triple::GNUEABIHF:
FloatABI = "hard";
break;
case llvm::Triple::GNUEABI:
FloatABI = "softfp";
break;
case llvm::Triple::EABIHF:
FloatABI = "hard";
break;
case llvm::Triple::EABI:
// EABI is always AAPCS, and if it was not marked 'hard', it's softfp
FloatABI = "softfp";
break;
case llvm::Triple::Android: {
std::string ArchName =
arm::getLLVMArchSuffixForARM(arm::getARMTargetCPU(Args, Triple));
if (StringRef(ArchName).startswith("v7"))
FloatABI = "softfp";
else
FloatABI = "soft";
break;
}
default:
// Assume "soft", but warn the user we are guessing.
FloatABI = "soft";
if (Triple.getOS() != llvm::Triple::UnknownOS ||
!Triple.isOSBinFormatMachO())
D.Diag(diag::warn_drv_assuming_mfloat_abi_is) << "soft";
break;
}
}
}
return FloatABI;
}
static void getARMTargetFeatures(const Driver &D, const llvm::Triple &Triple,
const ArgList &Args,
std::vector<const char *> &Features,
bool ForAS) {
StringRef FloatABI = tools::arm::getARMFloatABI(D, Args, Triple);
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 (FloatABI == "soft")
Features.push_back("+soft-float");
// Use software floating point argument passing?
if (FloatABI != "hard")
Features.push_back("+soft-float-abi");
}
// Honor -mfpu=.
if (const Arg *A = Args.getLastArg(options::OPT_mfpu_EQ))
getARMFPUFeatures(D, A, Args, Features);
if (const Arg *A = Args.getLastArg(options::OPT_mhwdiv_EQ))
getARMHWDivFeatures(D, A, Args, Features);
// Setting -msoft-float effectively disables NEON because of the GCC
// implementation, although the same isn't true of VFP or VFP3.
if (FloatABI == "soft") {
Features.push_back("-neon");
// Also need to explicitly disable features which imply NEON.
Features.push_back("-crypto");
}
// 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");
}
}
void Clang::AddARMTargetArgs(const ArgList &Args,
ArgStringList &CmdArgs,
bool KernelOrKext) const {
const Driver &D = getToolChain().getDriver();
// Get the effective triple, which takes into account the deployment target.
std::string TripleStr = getToolChain().ComputeEffectiveClangTriple(Args);
llvm::Triple Triple(TripleStr);
std::string CPUName = arm::getARMTargetCPU(Args, Triple);
// Select the ABI to use.
//
// FIXME: Support -meabi.
const char *ABIName = 0;
if (Arg *A = Args.getLastArg(options::OPT_mabi_EQ)) {
ABIName = A->getValue();
} else if (Triple.isOSDarwin()) {
// The backend is hardwired to assume AAPCS for M-class processors, ensure
// the frontend matches that.
if (Triple.getEnvironment() == llvm::Triple::EABI ||
(Triple.getOS() == llvm::Triple::UnknownOS &&
Triple.getObjectFormat() == llvm::Triple::MachO) ||
StringRef(CPUName).startswith("cortex-m")) {
ABIName = "aapcs";
} 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:
ABIName = "apcs-gnu";
}
}
CmdArgs.push_back("-target-abi");
CmdArgs.push_back(ABIName);
// Determine floating point ABI from the options & target defaults.
StringRef FloatABI = tools::arm::getARMFloatABI(D, Args, Triple);
if (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 (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(FloatABI == "hard" && "Invalid float abi!");
CmdArgs.push_back("-mfloat-abi");
CmdArgs.push_back("hard");
}
// Kernel code has more strict alignment requirements.
if (KernelOrKext) {
if (!Triple.isiOS() || Triple.isOSVersionLT(6)) {
CmdArgs.push_back("-backend-option");
CmdArgs.push_back("-arm-long-calls");
}
CmdArgs.push_back("-backend-option");
CmdArgs.push_back("-arm-strict-align");
// The kext linker doesn't know how to deal with movw/movt.
CmdArgs.push_back("-backend-option");
CmdArgs.push_back("-arm-use-movt=0");
}
// Setting -mno-global-merge disables the codegen global merge pass. Setting
// -mglobal-merge has no effect as the pass is enabled by default.
if (Arg *A = Args.getLastArg(options::OPT_mglobal_merge,
options::OPT_mno_global_merge)) {
if (A->getOption().matches(options::OPT_mno_global_merge))
CmdArgs.push_back("-mno-global-merge");
}
if (!Args.hasFlag(options::OPT_mimplicit_float,
options::OPT_mno_implicit_float,
true))
CmdArgs.push_back("-no-implicit-float");
// 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)) {
CmdArgs.push_back("-backend-option");
CmdArgs.push_back("-arm-reserve-r9");
}
}
/// getARM64TargetCPU - Get the (LLVM) name of the ARM64 cpu we are targeting.
static std::string getARM64TargetCPU(const ArgList &Args) {
// If we have -mcpu=, use that.
if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) {
StringRef MCPU = A->getValue();
// Handle -mcpu=native.
if (MCPU == "native")
return llvm::sys::getHostCPUName();
else
return MCPU;
}
// At some point, we may need to check -march here, but for now we only
// one arm64 architecture.
// 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::AddARM64TargetArgs(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 = 0;
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);
CmdArgs.push_back("-target-cpu");
CmdArgs.push_back(Args.MakeArgString(getARM64TargetCPU(Args)));
if (Args.hasArg(options::OPT_mstrict_align)) {
CmdArgs.push_back("-backend-option");
CmdArgs.push_back("-arm64-strict-align");
}
}
// Get CPU and ABI names. They are not independent
// so we have to calculate them together.
static void getMipsCPUAndABI(const ArgList &Args,
const llvm::Triple &Triple,
StringRef &CPUName,
StringRef &ABIName) {
const char *DefMips32CPU = "mips32r2";
const char *DefMips64CPU = "mips64r2";
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 CPU name from ABI name.
CPUName = llvm::StringSwitch<const char *>(ABIName)
.Cases("32", "o32", "eabi", DefMips32CPU)
.Cases("n32", "n64", "64", DefMips64CPU)
.Default("");
}
else if (!CPUName.empty()) {
// Deduce ABI name from CPU name.
ABIName = llvm::StringSwitch<const char *>(CPUName)
.Cases("mips32", "mips32r2", "o32")
.Cases("mips64", "mips64r2", "n64")
.Default("");
}
// FIXME: Warn on inconsistent cpu and abi usage.
}
// 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 StringRef getMipsFloatABI(const Driver &D, const ArgList &Args) {
StringRef FloatABI;
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))
FloatABI = "soft";
else if (A->getOption().matches(options::OPT_mhard_float))
FloatABI = "hard";
else {
FloatABI = A->getValue();
if (FloatABI != "soft" && FloatABI != "hard") {
D.Diag(diag::err_drv_invalid_mfloat_abi) << A->getAsString(Args);
FloatABI = "hard";
}
}
}
// If unspecified, choose the default based on the platform.
if (FloatABI.empty()) {
// 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.
FloatABI = "hard";
}
return FloatABI;
}
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 ArgList &Args,
std::vector<const char *> &Features) {
StringRef FloatABI = getMipsFloatABI(D, Args);
if (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)) {
if (StringRef(A->getValue()) == "2008")
Features.push_back("+nan2008");
}
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");
AddTargetFeature(Args, Features, options::OPT_mfp64, options::OPT_mfp32,
"fp64");
}
void Clang::AddMIPSTargetArgs(const ArgList &Args,
ArgStringList &CmdArgs) const {
const Driver &D = getToolChain().getDriver();
StringRef CPUName;
StringRef ABIName;
const llvm::Triple &Triple = getToolChain().getTriple();
getMipsCPUAndABI(Args, Triple, CPUName, ABIName);
CmdArgs.push_back("-target-abi");
CmdArgs.push_back(ABIName.data());
StringRef FloatABI = getMipsFloatABI(D, Args);
if (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 == "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("pwr3", "pwr3")
.Case("pwr4", "pwr4")
.Case("pwr5", "pwr5")
.Case("pwr5x", "pwr5x")
.Case("pwr6", "pwr6")
.Case("pwr6x", "pwr6x")
.Case("pwr7", "pwr7")
.Case("powerpc", "ppc")
.Case("powerpc64", "ppc64")
.Case("powerpc64le", "ppc64le")
.Default("");
}
return "";
}
static void getPPCTargetFeatures(const ArgList &Args,
std::vector<const char *> &Features) {
for (arg_iterator it = Args.filtered_begin(options::OPT_m_ppc_Features_Group),
ie = Args.filtered_end();
it != ie; ++it) {
StringRef Name = (*it)->getOption().getName();
(*it)->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);
// Note that gcc calls this mfcrf and LLVM calls this mfocrf so we
// pass the correct option to the backend while calling the frontend
// option the same.
// TODO: Change the LLVM backend option maybe?
if (Name == "mfcrf")
Name = "mfocrf";
Features.push_back(Args.MakeArgString((IsNegative ? "-" : "+") + Name));
}
// Altivec is a bit weird, allow overriding of the Altivec feature here.
AddTargetFeature(Args, Features, options::OPT_faltivec,
options::OPT_fno_altivec, "altivec");
}
/// Get the (LLVM) name of the R600 gpu we are targeting.
static std::string getR600TargetGPU(const ArgList &Args) {
if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) {
const char *GPUName = A->getValue();
return llvm::StringSwitch<const char *>(GPUName)
.Cases("rv630", "rv635", "r600")
.Cases("rv610", "rv620", "rs780", "rs880")
.Case("rv740", "rv770")
.Case("palm", "cedar")
.Cases("sumo", "sumo2", "sumo")
.Case("hemlock", "cypress")
.Case("aruba", "cayman")
.Default(GPUName);
}
return "";
}
static void getSparcTargetFeatures(const ArgList &Args,
std::vector<const char *> Features) {
bool SoftFloatABI = true;
if (Arg *A =
Args.getLastArg(options::OPT_msoft_float, options::OPT_mhard_float)) {
if (A->getOption().matches(options::OPT_mhard_float))
SoftFloatABI = false;
}
if (SoftFloatABI)
Features.push_back("+soft-float");
}
void Clang::AddSparcTargetArgs(const ArgList &Args,
ArgStringList &CmdArgs) const {
const Driver &D = getToolChain().getDriver();
// Select the float ABI as determined by -msoft-float, -mhard-float, and
StringRef FloatABI;
if (Arg *A = Args.getLastArg(options::OPT_msoft_float,
options::OPT_mhard_float)) {
if (A->getOption().matches(options::OPT_msoft_float))
FloatABI = "soft";
else if (A->getOption().matches(options::OPT_mhard_float))
FloatABI = "hard";
}
// If unspecified, choose the default based on the platform.
if (FloatABI.empty()) {
// Assume "soft", but warn the user we are guessing.
FloatABI = "soft";
D.Diag(diag::warn_drv_assuming_mfloat_abi_is) << "soft";
}
if (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");
} else {
assert(FloatABI == "hard" && "Invalid float abi!");
CmdArgs.push_back("-mhard-float");
}
}
static const char *getSystemZTargetCPU(const ArgList &Args) {
if (const Arg *A = Args.getLastArg(options::OPT_march_EQ))
return A->getValue();
return "z10";
}
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);
}
// Select the default CPU if none was given (or detection failed).
if (Triple.getArch() != llvm::Triple::x86_64 &&
Triple.getArch() != llvm::Triple::x86)
return 0; // 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";
}
// On Android use targets compatible with gcc
if (Triple.getEnvironment() == llvm::Triple::Android)
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";
}
}
static std::string getCPUName(const ArgList &Args, const llvm::Triple &T) {
switch(T.getArch()) {
default:
return "";
case llvm::Triple::aarch64:
case llvm::Triple::aarch64_be:
return getAArch64TargetCPU(Args, T);
case llvm::Triple::arm64:
case llvm::Triple::arm64_be:
return getARM64TargetCPU(Args);
case llvm::Triple::arm:
case llvm::Triple::armeb:
case llvm::Triple::thumb:
case llvm::Triple::thumbeb:
return arm::getARMTargetCPU(Args, T);
case llvm::Triple::mips:
case llvm::Triple::mipsel:
case llvm::Triple::mips64:
case llvm::Triple::mips64el: {
StringRef CPUName;
StringRef ABIName;
getMipsCPUAndABI(Args, T, CPUName, ABIName);
return CPUName;
}
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::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::Hexagon_TC::GetTargetCPU(Args).str();
case llvm::Triple::systemz:
return getSystemZTargetCPU(Args);
case llvm::Triple::r600:
return getR600TargetGPU(Args);
}
}
static void AddGoldPlugin(const ToolChain &ToolChain, const ArgList &Args,
ArgStringList &CmdArgs) {
// 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/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));
}
static void getX86TargetFeatures(const llvm::Triple &Triple,
const ArgList &Args,
std::vector<const char *> &Features) {
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");
}
if (Triple.getEnvironment() == llvm::Triple::Android) {
// Add sse3 feature to comply with gcc on Android
Features.push_back("+sse3");
}
// Now add any that the user explicitly requested on the command line,
// which may override the defaults.
for (arg_iterator it = Args.filtered_begin(options::OPT_m_x86_Features_Group),
ie = Args.filtered_end();
it != ie; ++it) {
StringRef Name = (*it)->getOption().getName();
(*it)->claim();
// Skip over "-m".
assert(Name.startswith("m") && "Invalid feature name.");
Name = Name.substr(1);
bool IsNegative = Name.startswith("no-");
if (IsNegative)
Name = Name.substr(3);
Features.push_back(Args.MakeArgString((IsNegative ? "-" : "+") + Name));
}
}
void 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");
}
static inline bool HasPICArg(const ArgList &Args) {
return Args.hasArg(options::OPT_fPIC)
|| Args.hasArg(options::OPT_fpic);
}
static Arg *GetLastSmallDataThresholdArg(const ArgList &Args) {
return Args.getLastArg(options::OPT_G,
options::OPT_G_EQ,
options::OPT_msmall_data_threshold_EQ);
}
static std::string GetHexagonSmallDataThresholdValue(const ArgList &Args) {
std::string value;
if (HasPICArg(Args))
value = "0";
else if (Arg *A = GetLastSmallDataThresholdArg(Args)) {
value = A->getValue();
A->claim();
}
return value;
}
void Clang::AddHexagonTargetArgs(const ArgList &Args,
ArgStringList &CmdArgs) const {
CmdArgs.push_back("-fno-signed-char");
CmdArgs.push_back("-mqdsp6-compat");
CmdArgs.push_back("-Wreturn-type");
std::string SmallDataThreshold = GetHexagonSmallDataThresholdValue(Args);
if (!SmallDataThreshold.empty()) {
CmdArgs.push_back ("-mllvm");
CmdArgs.push_back(Args.MakeArgString(
"-hexagon-small-data-threshold=" + SmallDataThreshold));
}
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");
}
static void getAArch64TargetFeatures(const Driver &D, const ArgList &Args,
std::vector<const char *> &Features) {
// Honor -mfpu=.
if (const Arg *A = Args.getLastArg(options::OPT_mfpu_EQ))
getAArch64FPUFeatures(D, A, Args, Features);
else
Features.push_back("+neon");
if (Args.getLastArg(options::OPT_mgeneral_regs_only)) {
Features.push_back("-fp-armv8");
Features.push_back("-crypto");
Features.push_back("-neon");
}
}
static void getTargetFeatures(const Driver &D, const llvm::Triple &Triple,
const ArgList &Args, ArgStringList &CmdArgs,
bool ForAS) {
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, Args, Features);
break;
case llvm::Triple::arm:
case llvm::Triple::armeb:
case llvm::Triple::thumb:
case llvm::Triple::thumbeb:
getARMTargetFeatures(D, Triple, Args, Features, ForAS);
break;
case llvm::Triple::ppc:
case llvm::Triple::ppc64:
case llvm::Triple::ppc64le:
getPPCTargetFeatures(Args, Features);
break;
case llvm::Triple::sparc:
getSparcTargetFeatures(Args, Features);
break;
case llvm::Triple::aarch64:
case llvm::Triple::aarch64_be:
case llvm::Triple::arm64:
case llvm::Triple::arm64_be:
getAArch64TargetFeatures(D, Args, Features);
break;
case llvm::Triple::x86:
case llvm::Triple::x86_64:
getX86TargetFeatures(Triple, 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));
}
namespace {
struct ExceptionSettings {
bool ExceptionsEnabled;
bool ShouldUseExceptionTables;
ExceptionSettings() : ExceptionsEnabled(false),
ShouldUseExceptionTables(false) {}
};
} // end anonymous namespace.
// exceptionSettings() exists to share the logic between -cc1 and linker invocations.
static ExceptionSettings exceptionSettings(const ArgList &Args,
const llvm::Triple &Triple) {
ExceptionSettings ES;
// Are exceptions enabled by default?
ES.ExceptionsEnabled = (Triple.getArch() != llvm::Triple::xcore);
// This keeps track of whether exceptions were explicitly turned on or off.
bool DidHaveExplicitExceptionFlag = false;
if (Arg *A = Args.getLastArg(options::OPT_fexceptions,
options::OPT_fno_exceptions)) {
if (A->getOption().matches(options::OPT_fexceptions))
ES.ExceptionsEnabled = true;
else
ES.ExceptionsEnabled = false;
DidHaveExplicitExceptionFlag = true;
}
// Exception tables and cleanups can be enabled with -fexceptions even if the
// language itself doesn't support exceptions.
if (ES.ExceptionsEnabled && DidHaveExplicitExceptionFlag)
ES.ShouldUseExceptionTables = true;
return ES;
}
/// addExceptionArgs - 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 llvm::Triple &Triple,
bool KernelOrKext,
const ObjCRuntime &objcRuntime,
ArgStringList &CmdArgs) {
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;
}
// Gather the exception settings from the command line arguments.
ExceptionSettings ES = exceptionSettings(Args, Triple);
// 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");
ES.ShouldUseExceptionTables |=
shouldUseExceptionTablesForObjCExceptions(objcRuntime, Triple);
}
if (types::isCXX(InputType)) {
bool CXXExceptionsEnabled = ES.ExceptionsEnabled;
if (Arg *A = Args.getLastArg(options::OPT_fcxx_exceptions,
options::OPT_fno_cxx_exceptions,
options::OPT_fexceptions,
options::OPT_fno_exceptions)) {
if (A->getOption().matches(options::OPT_fcxx_exceptions))
CXXExceptionsEnabled = true;
else if (A->getOption().matches(options::OPT_fno_cxx_exceptions))
CXXExceptionsEnabled = false;
}
if (CXXExceptionsEnabled) {
CmdArgs.push_back("-fcxx-exceptions");
ES.ShouldUseExceptionTables = true;
}
}
if (ES.ShouldUseExceptionTables)
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 ShouldDisableCFI(const ArgList &Args,
const ToolChain &TC) {
bool Default = true;
if (TC.getTriple().isOSDarwin()) {
// The native darwin assembler doesn't support cfi directives, so
// we disable them if we think the .s file will be passed to it.
Default = TC.useIntegratedAs();
}
return !Args.hasFlag(options::OPT_fdwarf2_cfi_asm,
options::OPT_fno_dwarf2_cfi_asm,
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))
return true;
for (Action::const_iterator it = A->begin(), ie = A->end(); it != ie; ++it)
if (ContainsCompileAction(*it))
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 (ActionList::const_iterator it = C.getActions().begin(),
ie = C.getActions().end(); it != ie; ++it) {
if (ContainsCompileAction(*it)) {
RelaxDefault = true;
break;
}
}
}
return Args.hasFlag(options::OPT_mrelax_all, options::OPT_mno_relax_all,
RelaxDefault);
}
static void CollectArgsForIntegratedAssembler(Compilation &C,
const ArgList &Args,
ArgStringList &CmdArgs,
const Driver &D) {
if (UseRelaxAll(C, Args))
CmdArgs.push_back("-mrelax-all");
// 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;
for (arg_iterator it = Args.filtered_begin(options::OPT_Wa_COMMA,
options::OPT_Xassembler),
ie = Args.filtered_end(); it != ie; ++it) {
const Arg *A = *it;
A->claim();
for (unsigned i = 0, e = A->getNumValues(); i != e; ++i) {
StringRef Value = A->getValue(i);
if (TakeNextArg) {
CmdArgs.push_back(Value.data());
TakeNextArg = false;
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("-mllvm");
CmdArgs.push_back("-fatal-assembler-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 {
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);
}
}
// Until ARM libraries are build separately, we have them all in one library
static StringRef getArchNameForCompilerRTLib(const ToolChain &TC) {
if (TC.getArch() == llvm::Triple::arm ||
TC.getArch() == llvm::Triple::armeb)
return "arm";
else
return TC.getArchName();
}
static SmallString<128> getCompilerRTLibDir(const ToolChain &TC) {
// The runtimes are located in the OS-specific resource directory.
SmallString<128> Res(TC.getDriver().ResourceDir);
const llvm::Triple &Triple = TC.getTriple();
// TC.getOS() yield "freebsd10.0" whereas "freebsd" is expected.
StringRef OSLibName = (Triple.getOS() == llvm::Triple::FreeBSD) ?
"freebsd" : TC.getOS();
llvm::sys::path::append(Res, "lib", OSLibName);
return Res;
}
// This adds the static libclang_rt.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 addClangRTLinux(
const ToolChain &TC, const ArgList &Args, ArgStringList &CmdArgs) {
SmallString<128> LibClangRT = getCompilerRTLibDir(TC);
llvm::sys::path::append(LibClangRT,
Twine("libclang_rt.") + getArchNameForCompilerRTLib(TC) + ".a");
CmdArgs.push_back(Args.MakeArgString(LibClangRT));
CmdArgs.push_back("-lgcc_s");
if (TC.getDriver().CCCIsCXX())
CmdArgs.push_back("-lgcc_eh");
}
static void addProfileRT(
const ToolChain &TC, const ArgList &Args, ArgStringList &CmdArgs) {
if (!(Args.hasArg(options::OPT_fprofile_arcs) ||
Args.hasArg(options::OPT_fprofile_generate) ||
Args.hasArg(options::OPT_fprofile_instr_generate) ||
Args.hasArg(options::OPT_fcreate_profile) ||
Args.hasArg(options::OPT_coverage)))
return;
SmallString<128> LibProfile = getCompilerRTLibDir(TC);
llvm::sys::path::append(LibProfile,
Twine("libclang_rt.profile-") + getArchNameForCompilerRTLib(TC) + ".a");
CmdArgs.push_back(Args.MakeArgString(LibProfile));
}
static SmallString<128> getSanitizerRTLibName(const ToolChain &TC,
const StringRef Sanitizer,
bool Shared) {
// Sanitizer runtime has name "libclang_rt.<Sanitizer>-<ArchName>.{a,so}"
// (or "libclang_rt.<Sanitizer>-<ArchName>-android.so for Android)
const char *EnvSuffix =
TC.getTriple().getEnvironment() == llvm::Triple::Android ? "-android" : "";
SmallString<128> LibSanitizer = getCompilerRTLibDir(TC);
llvm::sys::path::append(LibSanitizer,
Twine("libclang_rt.") + Sanitizer + "-" +
getArchNameForCompilerRTLib(TC) + EnvSuffix +
(Shared ? ".so" : ".a"));
return LibSanitizer;
}
static void addSanitizerRTLinkFlags(const ToolChain &TC, const ArgList &Args,
ArgStringList &CmdArgs,
const StringRef Sanitizer,
bool BeforeLibStdCXX,
bool ExportSymbols = true,
bool LinkDeps = true) {
SmallString<128> LibSanitizer =
getSanitizerRTLibName(TC, Sanitizer, /*Shared*/ false);
// Sanitizer runtime may need to come before -lstdc++ (or -lc++, libstdc++.a,
// etc.) so that the linker picks custom versions of the global 'operator
// new' and 'operator delete' symbols. We take the extreme (but simple)
// strategy of inserting it at the front of the link command. It also
// needs to be forced to end up in the executable, so wrap it in
// whole-archive.
SmallVector<const char *, 3> LibSanitizerArgs;
LibSanitizerArgs.push_back("-whole-archive");
LibSanitizerArgs.push_back(Args.MakeArgString(LibSanitizer));
LibSanitizerArgs.push_back("-no-whole-archive");
CmdArgs.insert(BeforeLibStdCXX ? CmdArgs.begin() : CmdArgs.end(),
LibSanitizerArgs.begin(), LibSanitizerArgs.end());
if (LinkDeps) {
// Link sanitizer dependencies explicitly
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");
}
// If possible, use a dynamic symbols file to export the symbols from the
// runtime library. If we can't do so, use -export-dynamic instead to export
// all symbols from the binary.
if (ExportSymbols) {
if (llvm::sys::fs::exists(LibSanitizer + ".syms"))
CmdArgs.push_back(
Args.MakeArgString("--dynamic-list=" + LibSanitizer + ".syms"));
else
CmdArgs.push_back("-export-dynamic");
}
}
/// If AddressSanitizer is enabled, add appropriate linker flags (Linux).
/// This needs to be called before we add the C run-time (malloc, etc).
static void addAsanRT(const ToolChain &TC, const ArgList &Args,
ArgStringList &CmdArgs, bool Shared) {
if (Shared) {
// Link dynamic runtime if necessary.
SmallString<128> LibSanitizer =
getSanitizerRTLibName(TC, "asan", Shared);
CmdArgs.insert(CmdArgs.begin(), Args.MakeArgString(LibSanitizer));
}
// Do not link static runtime to DSOs or if compiling for Android.
if (Args.hasArg(options::OPT_shared) ||
(TC.getTriple().getEnvironment() == llvm::Triple::Android))
return;
const char *LibAsanStaticPart = Shared ? "asan-preinit" : "asan";
addSanitizerRTLinkFlags(TC, Args, CmdArgs, LibAsanStaticPart,
/*BeforeLibStdCXX*/ true, /*ExportSymbols*/ !Shared,
/*LinkDeps*/ !Shared);
}
/// If ThreadSanitizer is enabled, add appropriate linker flags (Linux).
/// This needs to be called before we add the C run-time (malloc, etc).
static void addTsanRT(const ToolChain &TC, const ArgList &Args,
ArgStringList &CmdArgs) {
if (!Args.hasArg(options::OPT_shared))
addSanitizerRTLinkFlags(TC, Args, CmdArgs, "tsan", true);
}
/// If MemorySanitizer is enabled, add appropriate linker flags (Linux).
/// This needs to be called before we add the C run-time (malloc, etc).
static void addMsanRT(const ToolChain &TC, const ArgList &Args,
ArgStringList &CmdArgs) {
if (!Args.hasArg(options::OPT_shared))
addSanitizerRTLinkFlags(TC, Args, CmdArgs, "msan", true);
}
/// If LeakSanitizer is enabled, add appropriate linker flags (Linux).
/// This needs to be called before we add the C run-time (malloc, etc).
static void addLsanRT(const ToolChain &TC, const ArgList &Args,
ArgStringList &CmdArgs) {
if (!Args.hasArg(options::OPT_shared))
addSanitizerRTLinkFlags(TC, Args, CmdArgs, "lsan", true);
}
/// If UndefinedBehaviorSanitizer is enabled, add appropriate linker flags
/// (Linux).
static void addUbsanRT(const ToolChain &TC, const ArgList &Args,
ArgStringList &CmdArgs, bool IsCXX,
bool HasOtherSanitizerRt) {
// Need a copy of sanitizer_common. This could come from another sanitizer
// runtime; if we're not including one, include our own copy.
if (!HasOtherSanitizerRt)
addSanitizerRTLinkFlags(TC, Args, CmdArgs, "san", true, false);
addSanitizerRTLinkFlags(TC, Args, CmdArgs, "ubsan", false);
// Only include the bits of the runtime which need a C++ ABI library if
// we're linking in C++ mode.
if (IsCXX)
addSanitizerRTLinkFlags(TC, Args, CmdArgs, "ubsan_cxx", false);
}
static void addDfsanRT(const ToolChain &TC, const ArgList &Args,
ArgStringList &CmdArgs) {
if (!Args.hasArg(options::OPT_shared))
addSanitizerRTLinkFlags(TC, Args, CmdArgs, "dfsan", true);
}
// Should be called before we add C++ ABI library.
static void addSanitizerRuntimes(const ToolChain &TC, const ArgList &Args,
ArgStringList &CmdArgs) {
const SanitizerArgs &Sanitize = TC.getSanitizerArgs();
const Driver &D = TC.getDriver();
if (Sanitize.needsUbsanRt())
addUbsanRT(TC, Args, CmdArgs, D.CCCIsCXX(),
Sanitize.needsAsanRt() || Sanitize.needsTsanRt() ||
Sanitize.needsMsanRt() || Sanitize.needsLsanRt());
if (Sanitize.needsAsanRt())
addAsanRT(TC, Args, CmdArgs, Sanitize.needsSharedAsanRt());
if (Sanitize.needsTsanRt())
addTsanRT(TC, Args, CmdArgs);
if (Sanitize.needsMsanRt())
addMsanRT(TC, Args, CmdArgs);
if (Sanitize.needsLsanRt())
addLsanRT(TC, Args, CmdArgs);
if (Sanitize.needsDfsanRt())
addDfsanRT(TC, Args, CmdArgs);
}
static bool shouldUseFramePointerForTarget(const ArgList &Args,
const llvm::Triple &Triple) {
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:
if (Triple.isOSLinux())
if (Arg *A = Args.getLastArg(options::OPT_O_Group))
if (!A->getOption().matches(options::OPT_O0))
return false;
return true;
case llvm::Triple::xcore:
return false;
default:
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);
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);
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 InputInfoList &Inputs) {
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(Inputs[0].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"));
// First extract the dwo sections.
C.addCommand(new Command(JA, T, Exec, ExtractArgs));
// Then remove them from the original .o file.
C.addCommand(new Command(JA, T, Exec, StripArgs));
}
/// \brief Vectorize at all optimization levels greater than 1 except for -Oz.
static bool shouldEnableVectorizerAtOLevel(const ArgList &Args) {
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.
if (S == "z")
return false;
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()));
}
void Clang::ConstructJob(Compilation &C, const JobAction &JA,
const InputInfo &Output,
const InputInfoList &Inputs,
const ArgList &Args,
const char *LinkingOutput) const {
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();
assert(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");
std::string TripleStr = getToolChain().ComputeEffectiveClangTriple(Args);
CmdArgs.push_back(Args.MakeArgString(TripleStr));
const llvm::Triple TT(TripleStr);
if (TT.isOSWindows() && (TT.getArch() == llvm::Triple::arm ||
TT.getArch() == llvm::Triple::thumb)) {
unsigned Offset = TT.getArch() == llvm::Triple::arm ? 4 : 6;
unsigned Version;
TT.getArchName().substr(Offset).getAsInteger(10, Version);
if (Version < 7)
D.Diag(diag::err_target_unsupported_arch) << TT.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) && "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!");
}
}
// The make clang go fast button.
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, Inputs));
// 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");
if (getToolChain().getTriple().getVendor() == llvm::Triple::Apple)
CmdArgs.push_back("-analyzer-checker=osx");
CmdArgs.push_back("-analyzer-checker=deadcode");
if (types::isCXX(Inputs[0].getType()))
CmdArgs.push_back("-analyzer-checker=cplusplus");
// Enable the following experimental checkers for testing.
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");
}
// 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);
bool PIE = getToolChain().isPIEDefault();
bool PIC = PIE || getToolChain().isPICDefault();
bool IsPICLevelTwo = PIC;
// Android-specific defaults for PIC/PIE
if (getToolChain().getTriple().getEnvironment() == llvm::Triple::Android) {
switch (getToolChain().getTriple().getArch()) {
case llvm::Triple::arm:
case llvm::Triple::armeb:
case llvm::Triple::thumb:
case llvm::Triple::thumbeb:
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;
}
}
// For the PIC and PIE flag options, this logic is different from the
// legacy logic in very old versions of GCC, as that logic was just
// a bug no one had ever fixed. This logic is both more rational and
// consistent with GCC's new logic now that the bugs are fixed. The last