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