| //===--- 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/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/TargetParser.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" |
| |
| #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 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) && !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()) { |
| // 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 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 { |
| 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 -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); |
| } |
| |
| // 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: |
| return true; |
| } |
| } |
| |
| // ARM tools start. |
| |
| // Get SubArch (vN). |
| static int getARMSubArchVersionNumber(const llvm::Triple &Triple) { |
| llvm::StringRef Arch = Triple.getArchName(); |
| return llvm::ARMTargetParser::parseArchVersion(Arch); |
| } |
| |
| // True if M-profile. |
| static bool isARMMProfile(const llvm::Triple &Triple) { |
| llvm::StringRef Arch = Triple.getArchName(); |
| unsigned Profile = llvm::ARMTargetParser::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::ARMTargetParser::parseHWDiv(HWDiv); |
| if (!llvm::ARMTargetParser::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::ARMTargetParser::parseFPU(FPU); |
| if (!llvm::ARMTargetParser::getFPUFeatures(FPUID, Features)) |
| D.Diag(diag::err_drv_clang_unsupported) << A->getAsString(Args); |
| } |
| |
| // 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, |
| const llvm::Triple &Triple) { |
| std::string MArch = arm::getARMArch(ArchName, Triple); |
| if (llvm::ARMTargetParser::parseArch(MArch) == llvm::ARM::AK_INVALID) |
| 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, |
| const llvm::Triple &Triple) { |
| std::string CPU = arm::getARMTargetCPU(CPUName, ArchName, Triple); |
| std::string Arch = arm::getARMArch(ArchName, Triple); |
| if (strcmp(arm::getLLVMArchSuffixForARM(CPU, Arch), "") == 0) |
| 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. |
| // |
| if (getARMSubArchVersionNumber(Triple) == 6 || |
| getARMSubArchVersionNumber(Triple) == 7) |
| 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: { |
| if (getARMSubArchVersionNumber(Triple) == 7) |
| 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) { |
| bool KernelOrKext = |
| Args.hasArg(options::OPT_mkernel, options::OPT_fapple_kext); |
| StringRef FloatABI = tools::arm::getARMFloatABI(D, Args, Triple); |
| 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 (FloatABI == "soft") |
| Features.push_back("+soft-float"); |
| |
| // Use software floating point argument passing? |
| if (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, 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, 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, Triple); |
| } else if (CPUArg) { |
| CPUName = CPUArg->getValue(); |
| checkARMCPUName(D, CPUArg, Args, CPUName, ArchName, 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 (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))) { |
| 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) |
| 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) |
| Features.push_back("+no-movt"); |
| } |
| |
| 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); |
| |
| // 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()) { |
| // 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 || isARMMProfile(Triple)) { |
| 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: |
| 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. |
| 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"); |
| } |
| |
| // 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.getEnvironment() == llvm::Triple::Android) { |
| // 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.getEnvironment() == llvm::Triple::Android) |
| 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. |
| } |
| |
| // 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 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"); |
| |
| 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)) { |
| 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()); |
| |
| 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("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 ArgList &Args, |
| std::vector<const char *> &Features) { |
| for (const Arg *A : Args.filtered(options::OPT_m_ppc_Features_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); |
| |
| // 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"); |
| } |
| |
| 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(); |
| |
| 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.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, |
| 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::GetTargetCPU(Args).str(); |
| |
| case llvm::Triple::systemz: |
| return getSystemZTargetCPU(Args); |
| |
| case llvm::Triple::r600: |
| case llvm::Triple::amdgcn: |
| 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" 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)); |
| } |
| |
| /// 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(const 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.getEnvironment() == llvm::Triple::Android) { |
| 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. |
| for (const Arg *A : Args.filtered(options::OPT_m_x86_Features_Group)) { |
| StringRef Name = A->getOption().getName(); |
| A->claim(); |
| |
| // Skip over "-m". |
| assert(Name.startswith("m") && "Invalid feature name."); |
| Name = Name.substr(1); |
| |
| bool IsNegative = Name.startswith("no-"); |
| if (IsNegative) |
| Name = Name.substr(3); |
| |
| Features.push_back(Args.MakeArgString((IsNegative ? "-" : "+") + Name)); |
| } |
| } |
| |
| void 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 (const char *v = |
| toolchains::HexagonToolChain::GetSmallDataThreshold(Args)) { |
| std::string SmallDataThreshold = "-hexagon-small-data-threshold="; |
| SmallDataThreshold += v; |
| CmdArgs.push_back("-mllvm"); |
| CmdArgs.push_back(Args.MakeArgString(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"); |
| } |
| |
| // 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 (const 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("nofp", "-fp-armv8") |
| .Case("nosimd", "-neon") |
| .Case("nocrc", "-crc") |
| .Case("nocrypto", "-crypto") |
| .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") { |
| 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 { |
| 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 llvm::Triple &Triple, |
| 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) || Triple.isOSDarwin()) |
| Features.push_back("+reserve-x18"); |
| } |
| |
| 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, Triple, 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::systemz: |
| getSystemZTargetFeatures(Args, Features); |
| break; |
| case llvm::Triple::aarch64: |
| case llvm::Triple::aarch64_be: |
| getAArch64TargetFeatures(D, Triple, Args, Features); |
| break; |
| case llvm::Triple::x86: |
| case llvm::Triple::x86_64: |
| getX86TargetFeatures(D, 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)); |
| } |
| |
| /// 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); |
| } |
| |
| 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 (const Arg *A : |
| Args.filtered(options::OPT_Wa_COMMA, options::OPT_Xassembler)) { |
| A->claim(); |
| |
| for (const StringRef Value : A->getValues()) { |
| 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("-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-")) { |
| CmdArgs.push_back(Value.data()); |
| } 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); |
| } |
| } |
| |
| // Until ARM libraries are build separately, we have them all in one library |
| static StringRef getArchNameForCompilerRTLib(const ToolChain &TC) { |
| if (TC.getTriple().isWindowsMSVCEnvironment() && |
| TC.getArch() == llvm::Triple::x86) |
| return "i386"; |
| if (TC.getArch() == llvm::Triple::arm || TC.getArch() == llvm::Triple::armeb) |
| return "arm"; |
| 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; |
| } |
| |
| SmallString<128> tools::getCompilerRT(const ToolChain &TC, StringRef Component, |
| bool Shared) { |
| const char *Env = TC.getTriple().getEnvironment() == llvm::Triple::Android |
| ? "-android" |
| : ""; |
| |
| bool IsOSWindows = TC.getTriple().isOSWindows(); |
| bool IsITANMSVCWindows = TC.getTriple().isWindowsMSVCEnvironment() || |
| TC.getTriple().isWindowsItaniumEnvironment(); |
| StringRef Arch = getArchNameForCompilerRTLib(TC); |
| const char *Prefix = IsITANMSVCWindows ? "" : "lib"; |
| const char *Suffix = |
| Shared ? (IsOSWindows ? ".dll" : ".so") : (IsITANMSVCWindows ? ".lib" : ".a"); |
| |
| SmallString<128> Path = getCompilerRTLibDir(TC); |
| llvm::sys::path::append(Path, Prefix + Twine("clang_rt.") + Component + "-" + |
| Arch + Env + Suffix); |
| |
| return Path; |
| } |
| |
| // 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(Args.MakeArgString(getCompilerRT(TC, "builtins"))); |
| } |
| |
| static void addProfileRT(const ToolChain &TC, const ArgList &Args, |
| ArgStringList &CmdArgs) { |
| if (!(Args.hasFlag(options::OPT_fprofile_arcs, options::OPT_fno_profile_arcs, |
| false) || |
| Args.hasArg(options::OPT_fprofile_generate) || |
| Args.hasArg(options::OPT_fprofile_generate_EQ) || |
| Args.hasArg(options::OPT_fprofile_instr_generate) || |
| Args.hasArg(options::OPT_fprofile_instr_generate_EQ) || |
| Args.hasArg(options::OPT_fcreate_profile) || |
| Args.hasArg(options::OPT_coverage))) |
| return; |
| |
| CmdArgs.push_back(Args.MakeArgString(getCompilerRT(TC, "profile"))); |
| } |
| |
| 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 addSanitizerRuntime(const ToolChain &TC, const ArgList &Args, |
| ArgStringList &CmdArgs, StringRef Sanitizer, |
| bool IsShared) { |
| // Static runtimes must be forced into executable, so we wrap them in |
| // whole-archive. |
| if (!IsShared) |
| CmdArgs.push_back("-whole-archive"); |
| CmdArgs.push_back(Args.MakeArgString(getCompilerRT(TC, Sanitizer, IsShared))); |
| if (!IsShared) |
| 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 = getCompilerRT(TC, 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> &HelperStaticRuntimes) { |
| const SanitizerArgs &SanArgs = TC.getSanitizerArgs(); |
| // Collect shared runtimes. |
| if (SanArgs.needsAsanRt() && SanArgs.needsSharedAsanRt()) { |
| SharedRuntimes.push_back("asan"); |
| } |
| |
| // Collect static runtimes. |
| if (Args.hasArg(options::OPT_shared) || |
| (TC.getTriple().getEnvironment() == llvm::Triple::Android)) { |
| // 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"); |
| } |
| |
| // 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, |
| HelperStaticRuntimes; |
| collectSanitizerRuntimes(TC, Args, SharedRuntimes, StaticRuntimes, |
| HelperStaticRuntimes); |
| for (auto RT : SharedRuntimes) |
| addSanitizerRuntime(TC, Args, CmdArgs, RT, true); |
| for (auto RT : HelperStaticRuntimes) |
| addSanitizerRuntime(TC, Args, CmdArgs, RT, false); |
| bool AddExportDynamic = false; |
| for (auto RT : StaticRuntimes) { |
| addSanitizerRuntime(TC, Args, CmdArgs, RT, false); |
| AddExportDynamic |= !addSanitizerDynamicList(TC, Args, CmdArgs, RT); |
| } |
| // 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. |
|