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