123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243 |
- //===--- X86.cpp - X86 Helpers for Tools ------------------------*- C++ -*-===//
- //
- // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
- // See https://llvm.org/LICENSE.txt for license information.
- // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
- //
- //===----------------------------------------------------------------------===//
- #include "X86.h"
- #include "ToolChains/CommonArgs.h"
- #include "clang/Driver/Driver.h"
- #include "clang/Driver/DriverDiagnostic.h"
- #include "clang/Driver/Options.h"
- #include "llvm/ADT/StringExtras.h"
- #include "llvm/ADT/StringMap.h"
- #include "llvm/ADT/StringSwitch.h"
- #include "llvm/Option/ArgList.h"
- #include "llvm/Support/Host.h"
- using namespace clang::driver;
- using namespace clang::driver::tools;
- using namespace clang;
- using namespace llvm::opt;
- std::string x86::getX86TargetCPU(const Driver &D, const ArgList &Args,
- const llvm::Triple &Triple) {
- if (const Arg *A = Args.getLastArg(clang::driver::options::OPT_march_EQ)) {
- StringRef CPU = A->getValue();
- if (CPU != "native")
- return std::string(CPU);
- // 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.
- CPU = llvm::sys::getHostCPUName();
- if (!CPU.empty() && CPU != "generic")
- return std::string(CPU);
- }
- if (const Arg *A = Args.getLastArg(options::OPT__SLASH_arch)) {
- // Mapping built by looking at lib/Basic's X86TargetInfo::initFeatureMap().
- // The keys are case-sensitive; this matches link.exe.
- // 32-bit and 64-bit /arch: flags.
- llvm::StringMap<StringRef> ArchMap({
- {"AVX", "sandybridge"},
- {"AVX2", "haswell"},
- {"AVX512F", "knl"},
- {"AVX512", "skylake-avx512"},
- });
- if (Triple.getArch() == llvm::Triple::x86) {
- // 32-bit-only /arch: flags.
- ArchMap.insert({
- {"IA32", "i386"},
- {"SSE", "pentium3"},
- {"SSE2", "pentium4"},
- });
- }
- StringRef CPU = ArchMap.lookup(A->getValue());
- if (CPU.empty()) {
- std::vector<StringRef> ValidArchs{ArchMap.keys().begin(),
- ArchMap.keys().end()};
- sort(ValidArchs);
- D.Diag(diag::warn_drv_invalid_arch_name_with_suggestion)
- << A->getValue() << (Triple.getArch() == llvm::Triple::x86)
- << join(ValidArchs, ", ");
- }
- return std::string(CPU);
- }
- // Select the default CPU if none was given (or detection failed).
- if (!Triple.isX86())
- return ""; // 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";
- // macosx10.12 drops support for all pre-Penryn Macs.
- // Simulators can still run on 10.11 though, like Xcode.
- if (Triple.isMacOSX() && !Triple.isOSVersionLT(10, 12))
- return "penryn";
- // The oldest x86_64 Macs have core2/Merom; the oldest x86 Macs have Yonah.
- return Is64Bit ? "core2" : "yonah";
- }
- // Set up default CPU name for PS4 compilers.
- if (Triple.isPS4CPU())
- return "btver2";
- // On Android use targets compatible with gcc
- if (Triple.isAndroid())
- return Is64Bit ? "x86-64" : "i686";
- // Everything else goes to x86-64 in 64-bit mode.
- if (Is64Bit)
- return "x86-64";
- switch (Triple.getOS()) {
- case llvm::Triple::NetBSD:
- return "i486";
- case llvm::Triple::Haiku:
- case llvm::Triple::OpenBSD:
- return "i586";
- case llvm::Triple::FreeBSD:
- return "i686";
- default:
- // Fallback to p4.
- return "pentium4";
- }
- }
- void x86::getX86TargetFeatures(const Driver &D, const llvm::Triple &Triple,
- const ArgList &Args,
- std::vector<StringRef> &Features) {
- // If -march=native, autodetect the feature list.
- if (const Arg *A = Args.getLastArg(clang::driver::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("-fsgsbase");
- }
- const llvm::Triple::ArchType ArchType = Triple.getArch();
- // Add features to be compatible with gcc for Android.
- if (Triple.isAndroid()) {
- if (ArchType == llvm::Triple::x86_64) {
- Features.push_back("+sse4.2");
- Features.push_back("+popcnt");
- Features.push_back("+cx16");
- } else
- Features.push_back("+ssse3");
- }
- // Translate the high level `-mretpoline` flag to the specific target feature
- // flags. We also detect if the user asked for retpoline external thunks but
- // failed to ask for retpolines themselves (through any of the different
- // flags). This is a bit hacky but keeps existing usages working. We should
- // consider deprecating this and instead warn if the user requests external
- // retpoline thunks and *doesn't* request some form of retpolines.
- auto SpectreOpt = clang::driver::options::ID::OPT_INVALID;
- if (Args.hasArgNoClaim(options::OPT_mretpoline, options::OPT_mno_retpoline,
- options::OPT_mspeculative_load_hardening,
- options::OPT_mno_speculative_load_hardening)) {
- if (Args.hasFlag(options::OPT_mretpoline, options::OPT_mno_retpoline,
- false)) {
- Features.push_back("+retpoline-indirect-calls");
- Features.push_back("+retpoline-indirect-branches");
- SpectreOpt = options::OPT_mretpoline;
- } else if (Args.hasFlag(options::OPT_mspeculative_load_hardening,
- options::OPT_mno_speculative_load_hardening,
- false)) {
- // On x86, speculative load hardening relies on at least using retpolines
- // for indirect calls.
- Features.push_back("+retpoline-indirect-calls");
- SpectreOpt = options::OPT_mspeculative_load_hardening;
- }
- } else if (Args.hasFlag(options::OPT_mretpoline_external_thunk,
- options::OPT_mno_retpoline_external_thunk, false)) {
- // FIXME: Add a warning about failing to specify `-mretpoline` and
- // eventually switch to an error here.
- Features.push_back("+retpoline-indirect-calls");
- Features.push_back("+retpoline-indirect-branches");
- SpectreOpt = options::OPT_mretpoline_external_thunk;
- }
- auto LVIOpt = clang::driver::options::ID::OPT_INVALID;
- if (Args.hasFlag(options::OPT_mlvi_hardening, options::OPT_mno_lvi_hardening,
- false)) {
- Features.push_back("+lvi-load-hardening");
- Features.push_back("+lvi-cfi"); // load hardening implies CFI protection
- LVIOpt = options::OPT_mlvi_hardening;
- } else if (Args.hasFlag(options::OPT_mlvi_cfi, options::OPT_mno_lvi_cfi,
- false)) {
- Features.push_back("+lvi-cfi");
- LVIOpt = options::OPT_mlvi_cfi;
- }
- if (Args.hasFlag(options::OPT_m_seses, options::OPT_mno_seses, false)) {
- if (LVIOpt == options::OPT_mlvi_hardening)
- D.Diag(diag::err_drv_argument_not_allowed_with)
- << D.getOpts().getOptionName(options::OPT_mlvi_hardening)
- << D.getOpts().getOptionName(options::OPT_m_seses);
- if (SpectreOpt != clang::driver::options::ID::OPT_INVALID)
- D.Diag(diag::err_drv_argument_not_allowed_with)
- << D.getOpts().getOptionName(SpectreOpt)
- << D.getOpts().getOptionName(options::OPT_m_seses);
- Features.push_back("+seses");
- if (!Args.hasArg(options::OPT_mno_lvi_cfi)) {
- Features.push_back("+lvi-cfi");
- LVIOpt = options::OPT_mlvi_cfi;
- }
- }
- if (SpectreOpt != clang::driver::options::ID::OPT_INVALID &&
- LVIOpt != clang::driver::options::ID::OPT_INVALID) {
- D.Diag(diag::err_drv_argument_not_allowed_with)
- << D.getOpts().getOptionName(SpectreOpt)
- << D.getOpts().getOptionName(LVIOpt);
- }
- // 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,
- options::OPT_mgeneral_regs_only)) {
- StringRef Name = A->getOption().getName();
- A->claim();
- // Skip over "-m".
- assert(Name.startswith("m") && "Invalid feature name.");
- Name = Name.substr(1);
- // Replace -mgeneral-regs-only with -x87, -mmx, -sse
- if (A->getOption().getID() == options::OPT_mgeneral_regs_only) {
- Features.insert(Features.end(), {"-x87", "-mmx", "-sse"});
- continue;
- }
- bool IsNegative = Name.startswith("no-");
- if (IsNegative)
- Name = Name.substr(3);
- Features.push_back(Args.MakeArgString((IsNegative ? "-" : "+") + Name));
- }
- }
|