1e5dd7070Spatrick //===--- X86.cpp - X86 Helpers for Tools ------------------------*- C++ -*-===// 2e5dd7070Spatrick // 3e5dd7070Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4e5dd7070Spatrick // See https://llvm.org/LICENSE.txt for license information. 5e5dd7070Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6e5dd7070Spatrick // 7e5dd7070Spatrick //===----------------------------------------------------------------------===// 8e5dd7070Spatrick 9e5dd7070Spatrick #include "X86.h" 10e5dd7070Spatrick #include "ToolChains/CommonArgs.h" 11e5dd7070Spatrick #include "clang/Driver/Driver.h" 12e5dd7070Spatrick #include "clang/Driver/DriverDiagnostic.h" 13e5dd7070Spatrick #include "clang/Driver/Options.h" 14e5dd7070Spatrick #include "llvm/ADT/StringSwitch.h" 15e5dd7070Spatrick #include "llvm/Option/ArgList.h" 16e5dd7070Spatrick #include "llvm/Support/Host.h" 17e5dd7070Spatrick 18e5dd7070Spatrick using namespace clang::driver; 19e5dd7070Spatrick using namespace clang::driver::tools; 20e5dd7070Spatrick using namespace clang; 21e5dd7070Spatrick using namespace llvm::opt; 22e5dd7070Spatrick 23e5dd7070Spatrick const char *x86::getX86TargetCPU(const ArgList &Args, 24e5dd7070Spatrick const llvm::Triple &Triple) { 25e5dd7070Spatrick if (const Arg *A = Args.getLastArg(clang::driver::options::OPT_march_EQ)) { 26e5dd7070Spatrick if (StringRef(A->getValue()) != "native") 27e5dd7070Spatrick return A->getValue(); 28e5dd7070Spatrick 29e5dd7070Spatrick // FIXME: Reject attempts to use -march=native unless the target matches 30e5dd7070Spatrick // the host. 31e5dd7070Spatrick // 32e5dd7070Spatrick // FIXME: We should also incorporate the detected target features for use 33e5dd7070Spatrick // with -native. 34e5dd7070Spatrick std::string CPU = llvm::sys::getHostCPUName(); 35e5dd7070Spatrick if (!CPU.empty() && CPU != "generic") 36e5dd7070Spatrick return Args.MakeArgString(CPU); 37e5dd7070Spatrick } 38e5dd7070Spatrick 39e5dd7070Spatrick if (const Arg *A = Args.getLastArgNoClaim(options::OPT__SLASH_arch)) { 40e5dd7070Spatrick // Mapping built by looking at lib/Basic's X86TargetInfo::initFeatureMap(). 41e5dd7070Spatrick StringRef Arch = A->getValue(); 42e5dd7070Spatrick const char *CPU = nullptr; 43e5dd7070Spatrick if (Triple.getArch() == llvm::Triple::x86) { // 32-bit-only /arch: flags. 44e5dd7070Spatrick CPU = llvm::StringSwitch<const char *>(Arch) 45e5dd7070Spatrick .Case("IA32", "i386") 46e5dd7070Spatrick .Case("SSE", "pentium3") 47e5dd7070Spatrick .Case("SSE2", "pentium4") 48e5dd7070Spatrick .Default(nullptr); 49e5dd7070Spatrick } 50e5dd7070Spatrick if (CPU == nullptr) { // 32-bit and 64-bit /arch: flags. 51e5dd7070Spatrick CPU = llvm::StringSwitch<const char *>(Arch) 52e5dd7070Spatrick .Case("AVX", "sandybridge") 53e5dd7070Spatrick .Case("AVX2", "haswell") 54e5dd7070Spatrick .Case("AVX512F", "knl") 55e5dd7070Spatrick .Case("AVX512", "skylake-avx512") 56e5dd7070Spatrick .Default(nullptr); 57e5dd7070Spatrick } 58e5dd7070Spatrick if (CPU) { 59e5dd7070Spatrick A->claim(); 60e5dd7070Spatrick return CPU; 61e5dd7070Spatrick } 62e5dd7070Spatrick } 63e5dd7070Spatrick 64e5dd7070Spatrick // Select the default CPU if none was given (or detection failed). 65e5dd7070Spatrick 66e5dd7070Spatrick if (!Triple.isX86()) 67e5dd7070Spatrick return nullptr; // This routine is only handling x86 targets. 68e5dd7070Spatrick 69e5dd7070Spatrick bool Is64Bit = Triple.getArch() == llvm::Triple::x86_64; 70e5dd7070Spatrick 71e5dd7070Spatrick // FIXME: Need target hooks. 72e5dd7070Spatrick if (Triple.isOSDarwin()) { 73e5dd7070Spatrick if (Triple.getArchName() == "x86_64h") 74e5dd7070Spatrick return "core-avx2"; 75e5dd7070Spatrick // macosx10.12 drops support for all pre-Penryn Macs. 76e5dd7070Spatrick // Simulators can still run on 10.11 though, like Xcode. 77e5dd7070Spatrick if (Triple.isMacOSX() && !Triple.isOSVersionLT(10, 12)) 78e5dd7070Spatrick return "penryn"; 79e5dd7070Spatrick // The oldest x86_64 Macs have core2/Merom; the oldest x86 Macs have Yonah. 80e5dd7070Spatrick return Is64Bit ? "core2" : "yonah"; 81e5dd7070Spatrick } 82e5dd7070Spatrick 83e5dd7070Spatrick // Set up default CPU name for PS4 compilers. 84e5dd7070Spatrick if (Triple.isPS4CPU()) 85e5dd7070Spatrick return "btver2"; 86e5dd7070Spatrick 87e5dd7070Spatrick // On Android use targets compatible with gcc 88e5dd7070Spatrick if (Triple.isAndroid()) 89e5dd7070Spatrick return Is64Bit ? "x86-64" : "i686"; 90e5dd7070Spatrick 91e5dd7070Spatrick // Everything else goes to x86-64 in 64-bit mode. 92e5dd7070Spatrick if (Is64Bit) 93e5dd7070Spatrick return "x86-64"; 94e5dd7070Spatrick 95e5dd7070Spatrick switch (Triple.getOS()) { 96e5dd7070Spatrick case llvm::Triple::FreeBSD: 97e5dd7070Spatrick case llvm::Triple::NetBSD: 98e5dd7070Spatrick return "i486"; 99e5dd7070Spatrick case llvm::Triple::Haiku: 100197cfd86Sjsg case llvm::Triple::OpenBSD: 101e5dd7070Spatrick return "i586"; 102e5dd7070Spatrick default: 103e5dd7070Spatrick // Fallback to p4. 104e5dd7070Spatrick return "pentium4"; 105e5dd7070Spatrick } 106e5dd7070Spatrick } 107e5dd7070Spatrick 108e5dd7070Spatrick void x86::getX86TargetFeatures(const Driver &D, const llvm::Triple &Triple, 109e5dd7070Spatrick const ArgList &Args, 110e5dd7070Spatrick std::vector<StringRef> &Features) { 111e5dd7070Spatrick // If -march=native, autodetect the feature list. 112e5dd7070Spatrick if (const Arg *A = Args.getLastArg(clang::driver::options::OPT_march_EQ)) { 113e5dd7070Spatrick if (StringRef(A->getValue()) == "native") { 114e5dd7070Spatrick llvm::StringMap<bool> HostFeatures; 115e5dd7070Spatrick if (llvm::sys::getHostCPUFeatures(HostFeatures)) 116e5dd7070Spatrick for (auto &F : HostFeatures) 117e5dd7070Spatrick Features.push_back( 118e5dd7070Spatrick Args.MakeArgString((F.second ? "+" : "-") + F.first())); 119e5dd7070Spatrick } 120e5dd7070Spatrick } 121e5dd7070Spatrick 122e5dd7070Spatrick if (Triple.getArchName() == "x86_64h") { 123e5dd7070Spatrick // x86_64h implies quite a few of the more modern subtarget features 124e5dd7070Spatrick // for Haswell class CPUs, but not all of them. Opt-out of a few. 125e5dd7070Spatrick Features.push_back("-rdrnd"); 126e5dd7070Spatrick Features.push_back("-aes"); 127e5dd7070Spatrick Features.push_back("-pclmul"); 128e5dd7070Spatrick Features.push_back("-rtm"); 129e5dd7070Spatrick Features.push_back("-fsgsbase"); 130e5dd7070Spatrick } 131e5dd7070Spatrick 132e5dd7070Spatrick const llvm::Triple::ArchType ArchType = Triple.getArch(); 133e5dd7070Spatrick // Add features to be compatible with gcc for Android. 134e5dd7070Spatrick if (Triple.isAndroid()) { 135e5dd7070Spatrick if (ArchType == llvm::Triple::x86_64) { 136e5dd7070Spatrick Features.push_back("+sse4.2"); 137e5dd7070Spatrick Features.push_back("+popcnt"); 138e5dd7070Spatrick Features.push_back("+cx16"); 139e5dd7070Spatrick } else 140e5dd7070Spatrick Features.push_back("+ssse3"); 141e5dd7070Spatrick } 142e5dd7070Spatrick 143e5dd7070Spatrick // Translate the high level `-mretpoline` flag to the specific target feature 144e5dd7070Spatrick // flags. We also detect if the user asked for retpoline external thunks but 145e5dd7070Spatrick // failed to ask for retpolines themselves (through any of the different 146e5dd7070Spatrick // flags). This is a bit hacky but keeps existing usages working. We should 147e5dd7070Spatrick // consider deprecating this and instead warn if the user requests external 148e5dd7070Spatrick // retpoline thunks and *doesn't* request some form of retpolines. 149*30215e59Spatrick auto SpectreOpt = clang::driver::options::ID::OPT_INVALID; 150e5dd7070Spatrick if (Triple.isOSOpenBSD() && Triple.getArch() == llvm::Triple::x86_64 && 151e5dd7070Spatrick Args.hasFlag(options::OPT_mretpoline, options::OPT_mno_retpoline, true)) { 152e5dd7070Spatrick Features.push_back("+retpoline-indirect-calls"); 153e5dd7070Spatrick Features.push_back("+retpoline-indirect-branches"); 154*30215e59Spatrick SpectreOpt = options::OPT_mretpoline; 155e5dd7070Spatrick } else 156e5dd7070Spatrick if (Args.hasArgNoClaim(options::OPT_mretpoline, options::OPT_mno_retpoline, 157e5dd7070Spatrick options::OPT_mspeculative_load_hardening, 158e5dd7070Spatrick options::OPT_mno_speculative_load_hardening)) { 159e5dd7070Spatrick if (Args.hasFlag(options::OPT_mretpoline, options::OPT_mno_retpoline, 160e5dd7070Spatrick false)) { 161e5dd7070Spatrick Features.push_back("+retpoline-indirect-calls"); 162e5dd7070Spatrick Features.push_back("+retpoline-indirect-branches"); 163*30215e59Spatrick SpectreOpt = options::OPT_mretpoline; 164e5dd7070Spatrick } else if (Args.hasFlag(options::OPT_mspeculative_load_hardening, 165e5dd7070Spatrick options::OPT_mno_speculative_load_hardening, 166e5dd7070Spatrick false)) { 167e5dd7070Spatrick // On x86, speculative load hardening relies on at least using retpolines 168e5dd7070Spatrick // for indirect calls. 169e5dd7070Spatrick Features.push_back("+retpoline-indirect-calls"); 170*30215e59Spatrick SpectreOpt = options::OPT_mspeculative_load_hardening; 171e5dd7070Spatrick } 172e5dd7070Spatrick } else if (Args.hasFlag(options::OPT_mretpoline_external_thunk, 173e5dd7070Spatrick options::OPT_mno_retpoline_external_thunk, false)) { 174e5dd7070Spatrick // FIXME: Add a warning about failing to specify `-mretpoline` and 175e5dd7070Spatrick // eventually switch to an error here. 176e5dd7070Spatrick Features.push_back("+retpoline-indirect-calls"); 177e5dd7070Spatrick Features.push_back("+retpoline-indirect-branches"); 178*30215e59Spatrick SpectreOpt = options::OPT_mretpoline_external_thunk; 179*30215e59Spatrick } 180*30215e59Spatrick 181*30215e59Spatrick auto LVIOpt = clang::driver::options::ID::OPT_INVALID; 182*30215e59Spatrick if (Args.hasFlag(options::OPT_mlvi_hardening, options::OPT_mno_lvi_hardening, 183*30215e59Spatrick false)) { 184*30215e59Spatrick Features.push_back("+lvi-load-hardening"); 185*30215e59Spatrick Features.push_back("+lvi-cfi"); // load hardening implies CFI protection 186*30215e59Spatrick LVIOpt = options::OPT_mlvi_hardening; 187*30215e59Spatrick } else if (Args.hasFlag(options::OPT_mlvi_cfi, options::OPT_mno_lvi_cfi, 188*30215e59Spatrick false)) { 189*30215e59Spatrick Features.push_back("+lvi-cfi"); 190*30215e59Spatrick LVIOpt = options::OPT_mlvi_cfi; 191*30215e59Spatrick } 192*30215e59Spatrick 193*30215e59Spatrick if (SpectreOpt != clang::driver::options::ID::OPT_INVALID && 194*30215e59Spatrick LVIOpt != clang::driver::options::ID::OPT_INVALID) { 195*30215e59Spatrick D.Diag(diag::err_drv_argument_not_allowed_with) 196*30215e59Spatrick << D.getOpts().getOptionName(SpectreOpt) 197*30215e59Spatrick << D.getOpts().getOptionName(LVIOpt); 198e5dd7070Spatrick } 199e5dd7070Spatrick 200e5dd7070Spatrick // Now add any that the user explicitly requested on the command line, 201e5dd7070Spatrick // which may override the defaults. 202e5dd7070Spatrick handleTargetFeaturesGroup(Args, Features, options::OPT_m_x86_Features_Group); 203e5dd7070Spatrick } 204