brintos

brintos / llvm-project-archived public Read only

0
0
Text · 12.5 KiB · 7fda8ea Raw
363 lines · cpp
1//===--- RISCV.cpp - RISC-V 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 "RISCV.h"10#include "../Clang.h"11#include "clang/Driver/CommonArgs.h"12#include "clang/Driver/Driver.h"13#include "clang/Options/Options.h"14#include "llvm/Option/ArgList.h"15#include "llvm/Support/Error.h"16#include "llvm/TargetParser/Host.h"17#include "llvm/TargetParser/RISCVISAInfo.h"18#include "llvm/TargetParser/RISCVTargetParser.h"19 20using namespace clang::driver;21using namespace clang::driver::tools;22using namespace clang;23using namespace llvm::opt;24 25// Returns false if an error is diagnosed.26static bool getArchFeatures(const Driver &D, StringRef Arch,27                            std::vector<StringRef> &Features,28                            const ArgList &Args) {29  bool EnableExperimentalExtensions =30      Args.hasArg(options::OPT_menable_experimental_extensions);31  auto ISAInfo =32      llvm::RISCVISAInfo::parseArchString(Arch, EnableExperimentalExtensions);33  if (!ISAInfo) {34    handleAllErrors(ISAInfo.takeError(), [&](llvm::StringError &ErrMsg) {35      D.Diag(diag::err_drv_invalid_riscv_arch_name)36          << Arch << ErrMsg.getMessage();37    });38 39    return false;40  }41 42  for (const std::string &Str : (*ISAInfo)->toFeatures(/*AddAllExtension=*/true,43                                                       /*IgnoreUnknown=*/false))44    Features.push_back(Args.MakeArgString(Str));45 46  if (EnableExperimentalExtensions)47    Features.push_back(Args.MakeArgString("+experimental"));48 49  return true;50}51 52static bool isValidRISCVCPU(const Driver &D, const Arg *A,53                            const llvm::Triple &Triple, StringRef Mcpu) {54  bool Is64Bit = Triple.isRISCV64();55  if (!llvm::RISCV::parseCPU(Mcpu, Is64Bit)) {56    // Try inverting Is64Bit in case the CPU is valid, but for the wrong target.57    if (llvm::RISCV::parseCPU(Mcpu, !Is64Bit))58      D.Diag(clang::diag::err_drv_invalid_riscv_cpu_name_for_target)59          << Mcpu << Is64Bit;60    else61      D.Diag(clang::diag::err_drv_unsupported_option_argument)62          << A->getSpelling() << Mcpu;63    return false;64  }65  return true;66}67 68void riscv::getRISCVTargetFeatures(const Driver &D, const llvm::Triple &Triple,69                                   const ArgList &Args,70                                   std::vector<StringRef> &Features) {71  std::string MArch = getRISCVArch(Args, Triple);72 73  if (!getArchFeatures(D, MArch, Features, Args))74    return;75 76  bool CPUFastScalarUnaligned = false;77  bool CPUFastVectorUnaligned = false;78 79  // If users give march and mcpu, get std extension feature from MArch80  // and other features (ex. mirco architecture feature) from mcpu81  if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) {82    StringRef CPU = A->getValue();83    if (CPU == "native")84      CPU = llvm::sys::getHostCPUName();85 86    if (!isValidRISCVCPU(D, A, Triple, CPU))87      return;88 89    if (llvm::RISCV::hasFastScalarUnalignedAccess(CPU))90      CPUFastScalarUnaligned = true;91    if (llvm::RISCV::hasFastVectorUnalignedAccess(CPU))92      CPUFastVectorUnaligned = true;93  }94 95// Handle features corresponding to "-ffixed-X" options96#define RESERVE_REG(REG)                                                       \97  if (Args.hasArg(options::OPT_ffixed_##REG))                                  \98    Features.push_back("+reserve-" #REG);99  RESERVE_REG(x1)100  RESERVE_REG(x2)101  RESERVE_REG(x3)102  RESERVE_REG(x4)103  RESERVE_REG(x5)104  RESERVE_REG(x6)105  RESERVE_REG(x7)106  RESERVE_REG(x8)107  RESERVE_REG(x9)108  RESERVE_REG(x10)109  RESERVE_REG(x11)110  RESERVE_REG(x12)111  RESERVE_REG(x13)112  RESERVE_REG(x14)113  RESERVE_REG(x15)114  RESERVE_REG(x16)115  RESERVE_REG(x17)116  RESERVE_REG(x18)117  RESERVE_REG(x19)118  RESERVE_REG(x20)119  RESERVE_REG(x21)120  RESERVE_REG(x22)121  RESERVE_REG(x23)122  RESERVE_REG(x24)123  RESERVE_REG(x25)124  RESERVE_REG(x26)125  RESERVE_REG(x27)126  RESERVE_REG(x28)127  RESERVE_REG(x29)128  RESERVE_REG(x30)129  RESERVE_REG(x31)130#undef RESERVE_REG131 132  // -mrelax is default, unless -mno-relax is specified.133  if (Args.hasFlag(options::OPT_mrelax, options::OPT_mno_relax, true))134    Features.push_back("+relax");135  else136    Features.push_back("-relax");137 138  // If -mstrict-align, -mno-strict-align, -mscalar-strict-align, or139  // -mno-scalar-strict-align is passed, use it. Otherwise, the140  // unaligned-scalar-mem is enabled if the CPU supports it or the target is141  // Android.142  if (const Arg *A = Args.getLastArg(143          options::OPT_mno_strict_align, options::OPT_mscalar_strict_align,144          options::OPT_mstrict_align, options::OPT_mno_scalar_strict_align)) {145    if (A->getOption().matches(options::OPT_mno_strict_align) ||146        A->getOption().matches(options::OPT_mno_scalar_strict_align)) {147      Features.push_back("+unaligned-scalar-mem");148    } else {149      Features.push_back("-unaligned-scalar-mem");150    }151  } else if (CPUFastScalarUnaligned || Triple.isAndroid()) {152    Features.push_back("+unaligned-scalar-mem");153  }154 155  // If -mstrict-align, -mno-strict-align, -mvector-strict-align, or156  // -mno-vector-strict-align is passed, use it. Otherwise, the157  // unaligned-vector-mem is enabled if the CPU supports it or the target is158  // Android.159  if (const Arg *A = Args.getLastArg(160          options::OPT_mno_strict_align, options::OPT_mvector_strict_align,161          options::OPT_mstrict_align, options::OPT_mno_vector_strict_align)) {162    if (A->getOption().matches(options::OPT_mno_strict_align) ||163        A->getOption().matches(options::OPT_mno_vector_strict_align)) {164      Features.push_back("+unaligned-vector-mem");165    } else {166      Features.push_back("-unaligned-vector-mem");167    }168  } else if (CPUFastVectorUnaligned || Triple.isAndroid()) {169    Features.push_back("+unaligned-vector-mem");170  }171 172  // Now add any that the user explicitly requested on the command line,173  // which may override the defaults.174  handleTargetFeaturesGroup(D, Triple, Args, Features,175                            options::OPT_m_riscv_Features_Group);176}177 178StringRef riscv::getRISCVABI(const ArgList &Args, const llvm::Triple &Triple) {179  assert(Triple.isRISCV() && "Unexpected triple");180 181  // GCC's logic around choosing a default `-mabi=` is complex. If GCC is not182  // configured using `--with-abi=`, then the logic for the default choice is183  // defined in config.gcc. This function is based on the logic in GCC 9.2.0.184  //185  // The logic used in GCC 9.2.0 is the following, in order:186  // 1. Explicit choices using `--with-abi=`187  // 2. A default based on `--with-arch=`, if provided188  // 3. A default based on the target triple's arch189  //190  // The logic in config.gcc is a little circular but it is not inconsistent.191  //192  // Clang does not have `--with-arch=` or `--with-abi=`, so we use `-march=`193  // and `-mabi=` respectively instead.194  //195  // In order to make chosing logic more clear, Clang uses the following logic,196  // in order:197  // 1. Explicit choices using `-mabi=`198  // 2. A default based on the architecture as determined by getRISCVArch199  // 3. Choose a default based on the triple200 201  // 1. If `-mabi=` is specified, use it.202  if (const Arg *A = Args.getLastArg(options::OPT_mabi_EQ))203    return A->getValue();204 205  // 2. Choose a default based on the target architecture.206  //207  // rv32g | rv32*d -> ilp32d208  // rv32e -> ilp32e209  // rv32* -> ilp32210  // rv64g | rv64*d -> lp64d211  // rv64e -> lp64e212  // rv64* -> lp64213  std::string Arch = getRISCVArch(Args, Triple);214 215  auto ParseResult = llvm::RISCVISAInfo::parseArchString(216      Arch, /* EnableExperimentalExtension */ true);217  // Ignore parsing error, just go 3rd step.218  if (!llvm::errorToBool(ParseResult.takeError()))219    return (*ParseResult)->computeDefaultABI();220 221  // 3. Choose a default based on the triple222  //223  // We deviate from GCC's defaults here:224  // - On `riscv{XLEN}-unknown-elf` we use the integer calling convention only.225  // - On all other OSs we use the double floating point calling convention.226  if (Triple.isRISCV32()) {227    if (Triple.getOS() == llvm::Triple::UnknownOS)228      return "ilp32";229    else230      return "ilp32d";231  } else {232    if (Triple.getOS() == llvm::Triple::UnknownOS)233      return "lp64";234    else235      return "lp64d";236  }237}238 239std::string riscv::getRISCVArch(const llvm::opt::ArgList &Args,240                                const llvm::Triple &Triple) {241  assert(Triple.isRISCV() && "Unexpected triple");242 243  // GCC's logic around choosing a default `-march=` is complex. If GCC is not244  // configured using `--with-arch=`, then the logic for the default choice is245  // defined in config.gcc. This function is based on the logic in GCC 9.2.0. We246  // deviate from GCC's default on additional `-mcpu` option (GCC does not247  // support `-mcpu`) and baremetal targets (UnknownOS) where neither `-march`248  // nor `-mabi` is specified.249  //250  // The logic used in GCC 9.2.0 is the following, in order:251  // 1. Explicit choices using `--with-arch=`252  // 2. A default based on `--with-abi=`, if provided253  // 3. A default based on the target triple's arch254  //255  // The logic in config.gcc is a little circular but it is not inconsistent.256  //257  // Clang does not have `--with-arch=` or `--with-abi=`, so we use `-march=`258  // and `-mabi=` respectively instead.259  //260  // Clang uses the following logic, in order:261  // 1. Explicit choices using `-march=`262  // 2. Based on `-mcpu` if the target CPU has a default ISA string263  // 3. A default based on `-mabi`, if provided264  // 4. A default based on the target triple's arch265  //266  // Clang does not yet support MULTILIB_REUSE, so we use `rv{XLEN}imafdc`267  // instead of `rv{XLEN}gc` though they are (currently) equivalent.268 269  // 1. If `-march=` is specified, use it unless the value is "unset".270  if (const Arg *A = Args.getLastArg(options::OPT_march_EQ)) {271    StringRef MArch = A->getValue();272    if (MArch != "unset")273      return MArch.str();274  }275 276  // 2. Get march (isa string) based on `-mcpu=`277  if (const Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) {278    StringRef CPU = A->getValue();279    if (CPU == "native") {280      CPU = llvm::sys::getHostCPUName();281      // If the target cpu is unrecognized, use target features.282      if (CPU.starts_with("generic")) {283        auto FeatureMap = llvm::sys::getHostCPUFeatures();284        // hwprobe may be unavailable on older Linux versions.285        if (!FeatureMap.empty()) {286          std::vector<std::string> Features;287          for (auto &F : FeatureMap)288            Features.push_back(((F.second ? "+" : "-") + F.first()).str());289          auto ParseResult = llvm::RISCVISAInfo::parseFeatures(290              Triple.isRISCV32() ? 32 : 64, Features);291          if (ParseResult)292            return (*ParseResult)->toString();293        }294      }295    }296 297    StringRef MArch = llvm::RISCV::getMArchFromMcpu(CPU);298    // Bypass if target cpu's default march is empty.299    if (!MArch.empty())300      return MArch.str();301  }302 303  // 3. Choose a default based on `-mabi=`304  //305  // ilp32e -> rv32e306  // lp64e -> rv64e307  // ilp32 | ilp32f | ilp32d -> rv32imafdc308  // lp64 | lp64f | lp64d -> rv64imafdc309  if (const Arg *A = Args.getLastArg(options::OPT_mabi_EQ)) {310    StringRef MABI = A->getValue();311 312    if (MABI.equals_insensitive("ilp32e"))313      return "rv32e";314    if (MABI.equals_insensitive("lp64e"))315      return "rv64e";316    if (MABI.starts_with_insensitive("ilp32"))317      return "rv32imafdc";318    if (MABI.starts_with_insensitive("lp64")) {319      if (Triple.isAndroid())320        return "rv64imafdcv_zba_zbb_zbs";321      if (Triple.isOSFuchsia())322        return "rva22u64_v";323      return "rv64imafdc";324    }325  }326 327  // 4. Choose a default based on the triple328  //329  // We deviate from GCC's defaults here:330  // - On `riscv{XLEN}-unknown-elf` we default to `rv{XLEN}imac`331  // - On all other OSs we use `rv{XLEN}imafdc` (equivalent to `rv{XLEN}gc`)332  if (Triple.isRISCV32()) {333    if (Triple.getOS() == llvm::Triple::UnknownOS)334      return "rv32imac";335    return "rv32imafdc";336  }337 338  if (Triple.getOS() == llvm::Triple::UnknownOS)339    return "rv64imac";340  if (Triple.isAndroid())341    return "rv64imafdcv_zba_zbb_zbs";342  if (Triple.isOSFuchsia())343    return "rva22u64_v";344  return "rv64imafdc";345}346 347std::string riscv::getRISCVTargetCPU(const llvm::opt::ArgList &Args,348                                     const llvm::Triple &Triple) {349  std::string CPU;350  // If we have -mcpu, use that.351  if (const Arg *A = Args.getLastArg(options::OPT_mcpu_EQ))352    CPU = A->getValue();353 354  // Handle CPU name is 'native'.355  if (CPU == "native")356    CPU = llvm::sys::getHostCPUName();357 358  if (!CPU.empty())359    return CPU;360 361  return Triple.isRISCV64() ? "generic-rv64" : "generic-rv32";362}363