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