brintos

brintos / llvm-project-archived public Read only

0
0
Text · 11.6 KiB · d6e6657 Raw
317 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8 9#include "X86.h"10#include "clang/Driver/Driver.h"11#include "clang/Options/Options.h"12#include "llvm/ADT/StringExtras.h"13#include "llvm/ADT/StringMap.h"14#include "llvm/Option/ArgList.h"15#include "llvm/TargetParser/Host.h"16 17using namespace clang::driver;18using namespace clang::driver::tools;19using namespace clang;20using namespace llvm::opt;21 22std::string x86::getX86TargetCPU(const Driver &D, const ArgList &Args,23                                 const llvm::Triple &Triple) {24  if (const Arg *A = Args.getLastArg(options::OPT_march_EQ)) {25    StringRef CPU = A->getValue();26    if (CPU != "native")27      return std::string(CPU);28 29    // FIXME: Reject attempts to use -march=native unless the target matches30    // the host.31    CPU = llvm::sys::getHostCPUName();32    if (!CPU.empty() && CPU != "generic")33      return std::string(CPU);34  }35 36  if (const Arg *A = Args.getLastArg(options::OPT__SLASH_arch)) {37    // Mapping built by looking at lib/Basic's X86TargetInfo::initFeatureMap().38    // The keys are case-sensitive; this matches link.exe.39    // 32-bit and 64-bit /arch: flags.40    llvm::StringMap<StringRef> ArchMap({41        {"AVX", "sandybridge"},42        {"AVX2", "haswell"},43        {"AVX512F", "knl"},44        {"AVX512", "skylake-avx512"},45        {"AVX10.1", "sapphirerapids"},46        {"AVX10.2", "diamondrapids"},47    });48    if (Triple.getArch() == llvm::Triple::x86) {49      // 32-bit-only /arch: flags.50      ArchMap.insert({51          {"IA32", "i386"},52          {"SSE", "pentium3"},53          {"SSE2", "pentium4"},54      });55    }56    StringRef CPU = ArchMap.lookup(A->getValue());57    if (CPU.empty()) {58      std::vector<StringRef> ValidArchs{ArchMap.keys().begin(),59                                        ArchMap.keys().end()};60      sort(ValidArchs);61      D.Diag(diag::warn_drv_invalid_arch_name_with_suggestion)62          << A->getValue() << (Triple.getArch() == llvm::Triple::x86)63          << join(ValidArchs, ", ");64    }65    return std::string(CPU);66  }67 68  // Select the default CPU if none was given (or detection failed).69 70  if (!Triple.isX86())71    return ""; // This routine is only handling x86 targets.72 73  bool Is64Bit = Triple.getArch() == llvm::Triple::x86_64;74 75  // FIXME: Need target hooks.76  if (Triple.isOSDarwin()) {77    if (Triple.getArchName() == "x86_64h")78      return "core-avx2";79    // macosx10.12 drops support for all pre-Penryn Macs.80    // Simulators can still run on 10.11 though, like Xcode.81    if (Triple.isMacOSX() && !Triple.isOSVersionLT(10, 12))82      return "penryn";83 84    if (Triple.isDriverKit())85      return "nehalem";86 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/PS5 compilers.92  if (Triple.isPS4())93    return "btver2";94  if (Triple.isPS5())95    return "znver2";96 97  // On Android use targets compatible with gcc98  if (Triple.isAndroid())99    return Is64Bit ? "x86-64" : "i686";100 101  // Everything else goes to x86-64 in 64-bit mode.102  if (Is64Bit)103    return "x86-64";104 105  switch (Triple.getOS()) {106  case llvm::Triple::NetBSD:107    return "i486";108  case llvm::Triple::Haiku:109  case llvm::Triple::OpenBSD:110    return "i586";111  case llvm::Triple::FreeBSD:112    return "i686";113  default:114    // Fallback to p4.115    return "pentium4";116  }117}118 119void x86::getX86TargetFeatures(const Driver &D, const llvm::Triple &Triple,120                               const ArgList &Args,121                               std::vector<StringRef> &Features) {122  // Claim and report unsupported -mabi=. Note: we don't support "sysv_abi" or123  // "ms_abi" as default function attributes.124  if (const Arg *A = Args.getLastArg(options::OPT_mabi_EQ)) {125    StringRef DefaultAbi =126        (Triple.isOSWindows() || Triple.isUEFI()) ? "ms" : "sysv";127    if (A->getValue() != DefaultAbi)128      D.Diag(diag::err_drv_unsupported_opt_for_target)129          << A->getSpelling() << Triple.getTriple();130  }131 132  // If -march=native, autodetect the feature list.133  if (const Arg *A = Args.getLastArg(options::OPT_march_EQ)) {134    if (StringRef(A->getValue()) == "native") {135      for (auto &F : llvm::sys::getHostCPUFeatures())136        Features.push_back(137            Args.MakeArgString((F.second ? "+" : "-") + F.first()));138    }139  }140 141  if (Triple.getArchName() == "x86_64h") {142    // x86_64h implies quite a few of the more modern subtarget features143    // for Haswell class CPUs, but not all of them. Opt-out of a few.144    Features.push_back("-rdrnd");145    Features.push_back("-aes");146    Features.push_back("-pclmul");147    Features.push_back("-rtm");148    Features.push_back("-fsgsbase");149  }150 151  const llvm::Triple::ArchType ArchType = Triple.getArch();152  // Add features to be compatible with gcc for Android.153  if (Triple.isAndroid()) {154    if (ArchType == llvm::Triple::x86_64) {155      Features.push_back("+sse4.2");156      Features.push_back("+popcnt");157      Features.push_back("+cx16");158    } else159      Features.push_back("+ssse3");160  }161 162  // Translate the high level `-mretpoline` flag to the specific target feature163  // flags. We also detect if the user asked for retpoline external thunks but164  // failed to ask for retpolines themselves (through any of the different165  // flags). This is a bit hacky but keeps existing usages working. We should166  // consider deprecating this and instead warn if the user requests external167  // retpoline thunks and *doesn't* request some form of retpolines.168  auto SpectreOpt = options::ID::OPT_INVALID;169  if (Args.hasArgNoClaim(options::OPT_mretpoline, options::OPT_mno_retpoline,170                         options::OPT_mspeculative_load_hardening,171                         options::OPT_mno_speculative_load_hardening)) {172    if (Args.hasFlag(options::OPT_mretpoline, options::OPT_mno_retpoline,173                     false)) {174      Features.push_back("+retpoline-indirect-calls");175      Features.push_back("+retpoline-indirect-branches");176      SpectreOpt = options::OPT_mretpoline;177    } else if (Args.hasFlag(options::OPT_mspeculative_load_hardening,178                            options::OPT_mno_speculative_load_hardening,179                            false)) {180      // On x86, speculative load hardening relies on at least using retpolines181      // for indirect calls.182      Features.push_back("+retpoline-indirect-calls");183      SpectreOpt = options::OPT_mspeculative_load_hardening;184    }185  } else if (Args.hasFlag(options::OPT_mretpoline_external_thunk,186                          options::OPT_mno_retpoline_external_thunk, false)) {187    // FIXME: Add a warning about failing to specify `-mretpoline` and188    // eventually switch to an error here.189    Features.push_back("+retpoline-indirect-calls");190    Features.push_back("+retpoline-indirect-branches");191    SpectreOpt = options::OPT_mretpoline_external_thunk;192  }193 194  auto LVIOpt = options::ID::OPT_INVALID;195  if (Args.hasFlag(options::OPT_mlvi_hardening, options::OPT_mno_lvi_hardening,196                   false)) {197    Features.push_back("+lvi-load-hardening");198    Features.push_back("+lvi-cfi"); // load hardening implies CFI protection199    LVIOpt = options::OPT_mlvi_hardening;200  } else if (Args.hasFlag(options::OPT_mlvi_cfi, options::OPT_mno_lvi_cfi,201                          false)) {202    Features.push_back("+lvi-cfi");203    LVIOpt = options::OPT_mlvi_cfi;204  }205 206  if (Args.hasFlag(options::OPT_m_seses, options::OPT_mno_seses, false)) {207    if (LVIOpt == options::OPT_mlvi_hardening)208      D.Diag(diag::err_drv_argument_not_allowed_with)209          << D.getOpts().getOptionName(options::OPT_mlvi_hardening)210          << D.getOpts().getOptionName(options::OPT_m_seses);211 212    if (SpectreOpt != options::ID::OPT_INVALID)213      D.Diag(diag::err_drv_argument_not_allowed_with)214          << D.getOpts().getOptionName(SpectreOpt)215          << D.getOpts().getOptionName(options::OPT_m_seses);216 217    Features.push_back("+seses");218    if (!Args.hasArg(options::OPT_mno_lvi_cfi)) {219      Features.push_back("+lvi-cfi");220      LVIOpt = options::OPT_mlvi_cfi;221    }222  }223 224  if (SpectreOpt != options::ID::OPT_INVALID &&225      LVIOpt != options::ID::OPT_INVALID) {226    D.Diag(diag::err_drv_argument_not_allowed_with)227        << D.getOpts().getOptionName(SpectreOpt)228        << D.getOpts().getOptionName(LVIOpt);229  }230 231  // Now add any that the user explicitly requested on the command line,232  // which may override the defaults.233  for (const Arg *A : Args.filtered(options::OPT_m_x86_Features_Group,234                                    options::OPT_mgeneral_regs_only)) {235    StringRef Name = A->getOption().getName();236    A->claim();237 238    // Skip over "-m".239    assert(Name.starts_with("m") && "Invalid feature name.");240    Name = Name.substr(1);241 242    // Replace -mgeneral-regs-only with -x87, -mmx, -sse243    if (A->getOption().getID() == options::OPT_mgeneral_regs_only) {244      Features.insert(Features.end(), {"-x87", "-mmx", "-sse"});245      continue;246    }247 248    bool IsNegative = Name.starts_with("no-");249 250    bool Not64Bit = ArchType != llvm::Triple::x86_64;251    if (Not64Bit && Name == "uintr")252      D.Diag(diag::err_drv_unsupported_opt_for_target)253          << A->getSpelling() << Triple.getTriple();254 255    if (A->getOption().matches(options::OPT_mapx_features_EQ) ||256        A->getOption().matches(options::OPT_mno_apx_features_EQ)) {257 258      if (Not64Bit && !IsNegative)259        D.Diag(diag::err_drv_unsupported_opt_for_target)260            << StringRef(A->getSpelling().str() + "|-mapxf")261            << Triple.getTriple();262 263      for (StringRef Value : A->getValues()) {264        if (Value != "egpr" && Value != "push2pop2" && Value != "ppx" &&265            Value != "ndd" && Value != "ccmp" && Value != "nf" &&266            Value != "cf" && Value != "zu")267          D.Diag(clang::diag::err_drv_unsupported_option_argument)268              << A->getSpelling() << Value;269 270        Features.push_back(271            Args.MakeArgString((IsNegative ? "-" : "+") + Value));272      }273      continue;274    }275    if (IsNegative)276      Name = Name.substr(3);277    Features.push_back(Args.MakeArgString((IsNegative ? "-" : "+") + Name));278  }279 280  // Enable/disable straight line speculation hardening.281  if (Arg *A = Args.getLastArg(options::OPT_mharden_sls_EQ)) {282    StringRef Scope = A->getValue();283    if (Scope == "all") {284      Features.push_back("+harden-sls-ijmp");285      Features.push_back("+harden-sls-ret");286    } else if (Scope == "return") {287      Features.push_back("+harden-sls-ret");288    } else if (Scope == "indirect-jmp") {289      Features.push_back("+harden-sls-ijmp");290    } else if (Scope != "none") {291      D.Diag(diag::err_drv_unsupported_option_argument)292          << A->getSpelling() << Scope;293    }294  }295 296  // -mno-gather, -mno-scatter support297  if (Args.hasArg(options::OPT_mno_gather))298    Features.push_back("+prefer-no-gather");299  if (Args.hasArg(options::OPT_mno_scatter))300    Features.push_back("+prefer-no-scatter");301  if (Args.hasArg(options::OPT_mapx_inline_asm_use_gpr32))302    Features.push_back("+inline-asm-use-gpr32");303 304  // Warn for removed 3dnow support305  if (const Arg *A =306          Args.getLastArg(options::OPT_m3dnowa, options::OPT_mno_3dnowa,307                          options::OPT_mno_3dnow)) {308    if (A->getOption().matches(options::OPT_m3dnowa))309      D.Diag(diag::warn_drv_clang_unsupported) << A->getAsString(Args);310  }311  if (const Arg *A =312          Args.getLastArg(options::OPT_m3dnow, options::OPT_mno_3dnow)) {313    if (A->getOption().matches(options::OPT_m3dnow))314      D.Diag(diag::warn_drv_clang_unsupported) << A->getAsString(Args);315  }316}317