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