106f32e7eSjoerg //===--- X86.cpp - X86 Helpers for Tools ------------------------*- C++ -*-===//
206f32e7eSjoerg //
306f32e7eSjoerg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
406f32e7eSjoerg // See https://llvm.org/LICENSE.txt for license information.
506f32e7eSjoerg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
606f32e7eSjoerg //
706f32e7eSjoerg //===----------------------------------------------------------------------===//
806f32e7eSjoerg 
906f32e7eSjoerg #include "X86.h"
1006f32e7eSjoerg #include "ToolChains/CommonArgs.h"
1106f32e7eSjoerg #include "clang/Driver/Driver.h"
1206f32e7eSjoerg #include "clang/Driver/DriverDiagnostic.h"
1306f32e7eSjoerg #include "clang/Driver/Options.h"
1406f32e7eSjoerg #include "llvm/ADT/StringSwitch.h"
1506f32e7eSjoerg #include "llvm/Option/ArgList.h"
1606f32e7eSjoerg #include "llvm/Support/Host.h"
1706f32e7eSjoerg 
1806f32e7eSjoerg using namespace clang::driver;
1906f32e7eSjoerg using namespace clang::driver::tools;
2006f32e7eSjoerg using namespace clang;
2106f32e7eSjoerg using namespace llvm::opt;
2206f32e7eSjoerg 
getX86TargetCPU(const ArgList & Args,const llvm::Triple & Triple)23*13fbcb42Sjoerg std::string x86::getX86TargetCPU(const ArgList &Args,
2406f32e7eSjoerg                                  const llvm::Triple &Triple) {
2506f32e7eSjoerg   if (const Arg *A = Args.getLastArg(clang::driver::options::OPT_march_EQ)) {
26*13fbcb42Sjoerg     StringRef CPU = A->getValue();
27*13fbcb42Sjoerg     if (CPU != "native")
28*13fbcb42Sjoerg       return std::string(CPU);
2906f32e7eSjoerg 
3006f32e7eSjoerg     // FIXME: Reject attempts to use -march=native unless the target matches
3106f32e7eSjoerg     // the host.
3206f32e7eSjoerg     //
3306f32e7eSjoerg     // FIXME: We should also incorporate the detected target features for use
3406f32e7eSjoerg     // with -native.
35*13fbcb42Sjoerg     CPU = llvm::sys::getHostCPUName();
3606f32e7eSjoerg     if (!CPU.empty() && CPU != "generic")
37*13fbcb42Sjoerg       return std::string(CPU);
3806f32e7eSjoerg   }
3906f32e7eSjoerg 
4006f32e7eSjoerg   if (const Arg *A = Args.getLastArgNoClaim(options::OPT__SLASH_arch)) {
4106f32e7eSjoerg     // Mapping built by looking at lib/Basic's X86TargetInfo::initFeatureMap().
4206f32e7eSjoerg     StringRef Arch = A->getValue();
43*13fbcb42Sjoerg     StringRef CPU;
4406f32e7eSjoerg     if (Triple.getArch() == llvm::Triple::x86) {  // 32-bit-only /arch: flags.
45*13fbcb42Sjoerg       CPU = llvm::StringSwitch<StringRef>(Arch)
4606f32e7eSjoerg                 .Case("IA32", "i386")
4706f32e7eSjoerg                 .Case("SSE", "pentium3")
4806f32e7eSjoerg                 .Case("SSE2", "pentium4")
49*13fbcb42Sjoerg                 .Default("");
5006f32e7eSjoerg     }
51*13fbcb42Sjoerg     if (CPU.empty()) {  // 32-bit and 64-bit /arch: flags.
52*13fbcb42Sjoerg       CPU = llvm::StringSwitch<StringRef>(Arch)
5306f32e7eSjoerg                 .Case("AVX", "sandybridge")
5406f32e7eSjoerg                 .Case("AVX2", "haswell")
5506f32e7eSjoerg                 .Case("AVX512F", "knl")
5606f32e7eSjoerg                 .Case("AVX512", "skylake-avx512")
57*13fbcb42Sjoerg                 .Default("");
5806f32e7eSjoerg     }
59*13fbcb42Sjoerg     if (!CPU.empty()) {
6006f32e7eSjoerg       A->claim();
61*13fbcb42Sjoerg       return std::string(CPU);
6206f32e7eSjoerg     }
6306f32e7eSjoerg   }
6406f32e7eSjoerg 
6506f32e7eSjoerg   // Select the default CPU if none was given (or detection failed).
6606f32e7eSjoerg 
67*13fbcb42Sjoerg   if (!Triple.isX86())
68*13fbcb42Sjoerg     return ""; // This routine is only handling x86 targets.
6906f32e7eSjoerg 
7006f32e7eSjoerg   bool Is64Bit = Triple.getArch() == llvm::Triple::x86_64;
7106f32e7eSjoerg 
7206f32e7eSjoerg   // FIXME: Need target hooks.
7306f32e7eSjoerg   if (Triple.isOSDarwin()) {
7406f32e7eSjoerg     if (Triple.getArchName() == "x86_64h")
7506f32e7eSjoerg       return "core-avx2";
7606f32e7eSjoerg     // macosx10.12 drops support for all pre-Penryn Macs.
7706f32e7eSjoerg     // Simulators can still run on 10.11 though, like Xcode.
7806f32e7eSjoerg     if (Triple.isMacOSX() && !Triple.isOSVersionLT(10, 12))
7906f32e7eSjoerg       return "penryn";
8006f32e7eSjoerg     // The oldest x86_64 Macs have core2/Merom; the oldest x86 Macs have Yonah.
8106f32e7eSjoerg     return Is64Bit ? "core2" : "yonah";
8206f32e7eSjoerg   }
8306f32e7eSjoerg 
8406f32e7eSjoerg   // Set up default CPU name for PS4 compilers.
8506f32e7eSjoerg   if (Triple.isPS4CPU())
8606f32e7eSjoerg     return "btver2";
8706f32e7eSjoerg 
8806f32e7eSjoerg   // On Android use targets compatible with gcc
8906f32e7eSjoerg   if (Triple.isAndroid())
9006f32e7eSjoerg     return Is64Bit ? "x86-64" : "i686";
9106f32e7eSjoerg 
9206f32e7eSjoerg   // Everything else goes to x86-64 in 64-bit mode.
9306f32e7eSjoerg   if (Is64Bit)
9406f32e7eSjoerg     return "x86-64";
9506f32e7eSjoerg 
9606f32e7eSjoerg   switch (Triple.getOS()) {
9706f32e7eSjoerg   case llvm::Triple::NetBSD:
9806f32e7eSjoerg     return "i486";
9906f32e7eSjoerg   case llvm::Triple::Haiku:
100*13fbcb42Sjoerg   case llvm::Triple::OpenBSD:
10106f32e7eSjoerg     return "i586";
102*13fbcb42Sjoerg   case llvm::Triple::FreeBSD:
103*13fbcb42Sjoerg     return "i686";
10406f32e7eSjoerg   default:
10506f32e7eSjoerg     // Fallback to p4.
10606f32e7eSjoerg     return "pentium4";
10706f32e7eSjoerg   }
10806f32e7eSjoerg }
10906f32e7eSjoerg 
getX86TargetFeatures(const Driver & D,const llvm::Triple & Triple,const ArgList & Args,std::vector<StringRef> & Features)11006f32e7eSjoerg void x86::getX86TargetFeatures(const Driver &D, const llvm::Triple &Triple,
11106f32e7eSjoerg                                const ArgList &Args,
11206f32e7eSjoerg                                std::vector<StringRef> &Features) {
11306f32e7eSjoerg   // If -march=native, autodetect the feature list.
11406f32e7eSjoerg   if (const Arg *A = Args.getLastArg(clang::driver::options::OPT_march_EQ)) {
11506f32e7eSjoerg     if (StringRef(A->getValue()) == "native") {
11606f32e7eSjoerg       llvm::StringMap<bool> HostFeatures;
11706f32e7eSjoerg       if (llvm::sys::getHostCPUFeatures(HostFeatures))
11806f32e7eSjoerg         for (auto &F : HostFeatures)
11906f32e7eSjoerg           Features.push_back(
12006f32e7eSjoerg               Args.MakeArgString((F.second ? "+" : "-") + F.first()));
12106f32e7eSjoerg     }
12206f32e7eSjoerg   }
12306f32e7eSjoerg 
12406f32e7eSjoerg   if (Triple.getArchName() == "x86_64h") {
12506f32e7eSjoerg     // x86_64h implies quite a few of the more modern subtarget features
12606f32e7eSjoerg     // for Haswell class CPUs, but not all of them. Opt-out of a few.
12706f32e7eSjoerg     Features.push_back("-rdrnd");
12806f32e7eSjoerg     Features.push_back("-aes");
12906f32e7eSjoerg     Features.push_back("-pclmul");
13006f32e7eSjoerg     Features.push_back("-rtm");
13106f32e7eSjoerg     Features.push_back("-fsgsbase");
13206f32e7eSjoerg   }
13306f32e7eSjoerg 
13406f32e7eSjoerg   const llvm::Triple::ArchType ArchType = Triple.getArch();
13506f32e7eSjoerg   // Add features to be compatible with gcc for Android.
13606f32e7eSjoerg   if (Triple.isAndroid()) {
13706f32e7eSjoerg     if (ArchType == llvm::Triple::x86_64) {
13806f32e7eSjoerg       Features.push_back("+sse4.2");
13906f32e7eSjoerg       Features.push_back("+popcnt");
14006f32e7eSjoerg       Features.push_back("+cx16");
14106f32e7eSjoerg     } else
14206f32e7eSjoerg       Features.push_back("+ssse3");
14306f32e7eSjoerg   }
14406f32e7eSjoerg 
14506f32e7eSjoerg   // Translate the high level `-mretpoline` flag to the specific target feature
14606f32e7eSjoerg   // flags. We also detect if the user asked for retpoline external thunks but
14706f32e7eSjoerg   // failed to ask for retpolines themselves (through any of the different
14806f32e7eSjoerg   // flags). This is a bit hacky but keeps existing usages working. We should
14906f32e7eSjoerg   // consider deprecating this and instead warn if the user requests external
15006f32e7eSjoerg   // retpoline thunks and *doesn't* request some form of retpolines.
151*13fbcb42Sjoerg   auto SpectreOpt = clang::driver::options::ID::OPT_INVALID;
15206f32e7eSjoerg   if (Args.hasArgNoClaim(options::OPT_mretpoline, options::OPT_mno_retpoline,
15306f32e7eSjoerg                          options::OPT_mspeculative_load_hardening,
15406f32e7eSjoerg                          options::OPT_mno_speculative_load_hardening)) {
15506f32e7eSjoerg     if (Args.hasFlag(options::OPT_mretpoline, options::OPT_mno_retpoline,
15606f32e7eSjoerg                      false)) {
15706f32e7eSjoerg       Features.push_back("+retpoline-indirect-calls");
15806f32e7eSjoerg       Features.push_back("+retpoline-indirect-branches");
159*13fbcb42Sjoerg       SpectreOpt = options::OPT_mretpoline;
16006f32e7eSjoerg     } else if (Args.hasFlag(options::OPT_mspeculative_load_hardening,
16106f32e7eSjoerg                             options::OPT_mno_speculative_load_hardening,
16206f32e7eSjoerg                             false)) {
16306f32e7eSjoerg       // On x86, speculative load hardening relies on at least using retpolines
16406f32e7eSjoerg       // for indirect calls.
16506f32e7eSjoerg       Features.push_back("+retpoline-indirect-calls");
166*13fbcb42Sjoerg       SpectreOpt = options::OPT_mspeculative_load_hardening;
16706f32e7eSjoerg     }
16806f32e7eSjoerg   } else if (Args.hasFlag(options::OPT_mretpoline_external_thunk,
16906f32e7eSjoerg                           options::OPT_mno_retpoline_external_thunk, false)) {
17006f32e7eSjoerg     // FIXME: Add a warning about failing to specify `-mretpoline` and
17106f32e7eSjoerg     // eventually switch to an error here.
17206f32e7eSjoerg     Features.push_back("+retpoline-indirect-calls");
17306f32e7eSjoerg     Features.push_back("+retpoline-indirect-branches");
174*13fbcb42Sjoerg     SpectreOpt = options::OPT_mretpoline_external_thunk;
175*13fbcb42Sjoerg   }
176*13fbcb42Sjoerg 
177*13fbcb42Sjoerg   auto LVIOpt = clang::driver::options::ID::OPT_INVALID;
178*13fbcb42Sjoerg   if (Args.hasFlag(options::OPT_mlvi_hardening, options::OPT_mno_lvi_hardening,
179*13fbcb42Sjoerg                    false)) {
180*13fbcb42Sjoerg     Features.push_back("+lvi-load-hardening");
181*13fbcb42Sjoerg     Features.push_back("+lvi-cfi"); // load hardening implies CFI protection
182*13fbcb42Sjoerg     LVIOpt = options::OPT_mlvi_hardening;
183*13fbcb42Sjoerg   } else if (Args.hasFlag(options::OPT_mlvi_cfi, options::OPT_mno_lvi_cfi,
184*13fbcb42Sjoerg                           false)) {
185*13fbcb42Sjoerg     Features.push_back("+lvi-cfi");
186*13fbcb42Sjoerg     LVIOpt = options::OPT_mlvi_cfi;
187*13fbcb42Sjoerg   }
188*13fbcb42Sjoerg 
189*13fbcb42Sjoerg   if (Args.hasFlag(options::OPT_m_seses, options::OPT_mno_seses, false)) {
190*13fbcb42Sjoerg     if (LVIOpt == options::OPT_mlvi_hardening)
191*13fbcb42Sjoerg       D.Diag(diag::err_drv_argument_not_allowed_with)
192*13fbcb42Sjoerg           << D.getOpts().getOptionName(options::OPT_mlvi_hardening)
193*13fbcb42Sjoerg           << D.getOpts().getOptionName(options::OPT_m_seses);
194*13fbcb42Sjoerg 
195*13fbcb42Sjoerg     if (SpectreOpt != clang::driver::options::ID::OPT_INVALID)
196*13fbcb42Sjoerg       D.Diag(diag::err_drv_argument_not_allowed_with)
197*13fbcb42Sjoerg           << D.getOpts().getOptionName(SpectreOpt)
198*13fbcb42Sjoerg           << D.getOpts().getOptionName(options::OPT_m_seses);
199*13fbcb42Sjoerg 
200*13fbcb42Sjoerg     Features.push_back("+seses");
201*13fbcb42Sjoerg     if (!Args.hasArg(options::OPT_mno_lvi_cfi)) {
202*13fbcb42Sjoerg       Features.push_back("+lvi-cfi");
203*13fbcb42Sjoerg       LVIOpt = options::OPT_mlvi_cfi;
204*13fbcb42Sjoerg     }
205*13fbcb42Sjoerg   }
206*13fbcb42Sjoerg 
207*13fbcb42Sjoerg   if (SpectreOpt != clang::driver::options::ID::OPT_INVALID &&
208*13fbcb42Sjoerg       LVIOpt != clang::driver::options::ID::OPT_INVALID) {
209*13fbcb42Sjoerg     D.Diag(diag::err_drv_argument_not_allowed_with)
210*13fbcb42Sjoerg         << D.getOpts().getOptionName(SpectreOpt)
211*13fbcb42Sjoerg         << D.getOpts().getOptionName(LVIOpt);
21206f32e7eSjoerg   }
21306f32e7eSjoerg 
21406f32e7eSjoerg   // Now add any that the user explicitly requested on the command line,
21506f32e7eSjoerg   // which may override the defaults.
21606f32e7eSjoerg   handleTargetFeaturesGroup(Args, Features, options::OPT_m_x86_Features_Group);
21706f32e7eSjoerg }
218