Path: blob/main/contrib/llvm-project/clang/lib/Driver/ToolChains/Arch/RISCV.cpp
35294 views
//===--- RISCV.cpp - RISC-V Helpers for Tools -------------------*- C++ -*-===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include "RISCV.h"9#include "../Clang.h"10#include "ToolChains/CommonArgs.h"11#include "clang/Basic/CharInfo.h"12#include "clang/Driver/Driver.h"13#include "clang/Driver/DriverDiagnostic.h"14#include "clang/Driver/Options.h"15#include "llvm/Option/ArgList.h"16#include "llvm/Support/Error.h"17#include "llvm/Support/raw_ostream.h"18#include "llvm/TargetParser/Host.h"19#include "llvm/TargetParser/RISCVISAInfo.h"20#include "llvm/TargetParser/RISCVTargetParser.h"2122using namespace clang::driver;23using namespace clang::driver::tools;24using namespace clang;25using namespace llvm::opt;2627// Returns false if an error is diagnosed.28static bool getArchFeatures(const Driver &D, StringRef Arch,29std::vector<StringRef> &Features,30const ArgList &Args) {31bool EnableExperimentalExtensions =32Args.hasArg(options::OPT_menable_experimental_extensions);33auto ISAInfo =34llvm::RISCVISAInfo::parseArchString(Arch, EnableExperimentalExtensions);35if (!ISAInfo) {36handleAllErrors(ISAInfo.takeError(), [&](llvm::StringError &ErrMsg) {37D.Diag(diag::err_drv_invalid_riscv_arch_name)38<< Arch << ErrMsg.getMessage();39});4041return false;42}4344for (const std::string &Str : (*ISAInfo)->toFeatures(/*AddAllExtension=*/true,45/*IgnoreUnknown=*/false))46Features.push_back(Args.MakeArgString(Str));4748if (EnableExperimentalExtensions)49Features.push_back(Args.MakeArgString("+experimental"));5051return true;52}5354// Get features except standard extension feature55static void getRISCFeaturesFromMcpu(const Driver &D, const Arg *A,56const llvm::Triple &Triple,57StringRef Mcpu,58std::vector<StringRef> &Features) {59bool Is64Bit = Triple.isRISCV64();60if (!llvm::RISCV::parseCPU(Mcpu, Is64Bit)) {61// Try inverting Is64Bit in case the CPU is valid, but for the wrong target.62if (llvm::RISCV::parseCPU(Mcpu, !Is64Bit))63D.Diag(clang::diag::err_drv_invalid_riscv_cpu_name_for_target)64<< Mcpu << Is64Bit;65else66D.Diag(clang::diag::err_drv_unsupported_option_argument)67<< A->getSpelling() << Mcpu;68}69}7071void riscv::getRISCVTargetFeatures(const Driver &D, const llvm::Triple &Triple,72const ArgList &Args,73std::vector<StringRef> &Features) {74std::string MArch = getRISCVArch(Args, Triple);7576if (!getArchFeatures(D, MArch, Features, Args))77return;7879bool CPUFastScalarUnaligned = false;80bool CPUFastVectorUnaligned = false;8182// If users give march and mcpu, get std extension feature from MArch83// and other features (ex. mirco architecture feature) from mcpu84if (Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) {85StringRef CPU = A->getValue();86if (CPU == "native")87CPU = llvm::sys::getHostCPUName();8889getRISCFeaturesFromMcpu(D, A, Triple, CPU, Features);9091if (llvm::RISCV::hasFastScalarUnalignedAccess(CPU))92CPUFastScalarUnaligned = true;93if (llvm::RISCV::hasFastVectorUnalignedAccess(CPU))94CPUFastVectorUnaligned = true;95}9697// Handle features corresponding to "-ffixed-X" options98if (Args.hasArg(options::OPT_ffixed_x1))99Features.push_back("+reserve-x1");100if (Args.hasArg(options::OPT_ffixed_x2))101Features.push_back("+reserve-x2");102if (Args.hasArg(options::OPT_ffixed_x3))103Features.push_back("+reserve-x3");104if (Args.hasArg(options::OPT_ffixed_x4))105Features.push_back("+reserve-x4");106if (Args.hasArg(options::OPT_ffixed_x5))107Features.push_back("+reserve-x5");108if (Args.hasArg(options::OPT_ffixed_x6))109Features.push_back("+reserve-x6");110if (Args.hasArg(options::OPT_ffixed_x7))111Features.push_back("+reserve-x7");112if (Args.hasArg(options::OPT_ffixed_x8))113Features.push_back("+reserve-x8");114if (Args.hasArg(options::OPT_ffixed_x9))115Features.push_back("+reserve-x9");116if (Args.hasArg(options::OPT_ffixed_x10))117Features.push_back("+reserve-x10");118if (Args.hasArg(options::OPT_ffixed_x11))119Features.push_back("+reserve-x11");120if (Args.hasArg(options::OPT_ffixed_x12))121Features.push_back("+reserve-x12");122if (Args.hasArg(options::OPT_ffixed_x13))123Features.push_back("+reserve-x13");124if (Args.hasArg(options::OPT_ffixed_x14))125Features.push_back("+reserve-x14");126if (Args.hasArg(options::OPT_ffixed_x15))127Features.push_back("+reserve-x15");128if (Args.hasArg(options::OPT_ffixed_x16))129Features.push_back("+reserve-x16");130if (Args.hasArg(options::OPT_ffixed_x17))131Features.push_back("+reserve-x17");132if (Args.hasArg(options::OPT_ffixed_x18))133Features.push_back("+reserve-x18");134if (Args.hasArg(options::OPT_ffixed_x19))135Features.push_back("+reserve-x19");136if (Args.hasArg(options::OPT_ffixed_x20))137Features.push_back("+reserve-x20");138if (Args.hasArg(options::OPT_ffixed_x21))139Features.push_back("+reserve-x21");140if (Args.hasArg(options::OPT_ffixed_x22))141Features.push_back("+reserve-x22");142if (Args.hasArg(options::OPT_ffixed_x23))143Features.push_back("+reserve-x23");144if (Args.hasArg(options::OPT_ffixed_x24))145Features.push_back("+reserve-x24");146if (Args.hasArg(options::OPT_ffixed_x25))147Features.push_back("+reserve-x25");148if (Args.hasArg(options::OPT_ffixed_x26))149Features.push_back("+reserve-x26");150if (Args.hasArg(options::OPT_ffixed_x27))151Features.push_back("+reserve-x27");152if (Args.hasArg(options::OPT_ffixed_x28))153Features.push_back("+reserve-x28");154if (Args.hasArg(options::OPT_ffixed_x29))155Features.push_back("+reserve-x29");156if (Args.hasArg(options::OPT_ffixed_x30))157Features.push_back("+reserve-x30");158if (Args.hasArg(options::OPT_ffixed_x31))159Features.push_back("+reserve-x31");160161// FreeBSD local, because ld.lld doesn't support relaxations162// -mno-relax is default, unless -mrelax is specified.163if (Args.hasFlag(options::OPT_mrelax, options::OPT_mno_relax, false)) {164Features.push_back("+relax");165// -gsplit-dwarf -mrelax requires DW_AT_high_pc/DW_AT_ranges/... indexing166// into .debug_addr, which is currently not implemented.167Arg *A;168if (getDebugFissionKind(D, Args, A) != DwarfFissionKind::None)169D.Diag(clang::diag::err_drv_riscv_unsupported_with_linker_relaxation)170<< A->getAsString(Args);171} else {172Features.push_back("-relax");173}174175// If -mstrict-align, -mno-strict-align, -mscalar-strict-align, or176// -mno-scalar-strict-align is passed, use it. Otherwise, the177// unaligned-scalar-mem is enabled if the CPU supports it or the target is178// Android.179if (const Arg *A = Args.getLastArg(180options::OPT_mno_strict_align, options::OPT_mscalar_strict_align,181options::OPT_mstrict_align, options::OPT_mno_scalar_strict_align)) {182if (A->getOption().matches(options::OPT_mno_strict_align) ||183A->getOption().matches(options::OPT_mno_scalar_strict_align)) {184Features.push_back("+unaligned-scalar-mem");185} else {186Features.push_back("-unaligned-scalar-mem");187}188} else if (CPUFastScalarUnaligned || Triple.isAndroid()) {189Features.push_back("+unaligned-scalar-mem");190}191192// If -mstrict-align, -mno-strict-align, -mvector-strict-align, or193// -mno-vector-strict-align is passed, use it. Otherwise, the194// unaligned-vector-mem is enabled if the CPU supports it or the target is195// Android.196if (const Arg *A = Args.getLastArg(197options::OPT_mno_strict_align, options::OPT_mvector_strict_align,198options::OPT_mstrict_align, options::OPT_mno_vector_strict_align)) {199if (A->getOption().matches(options::OPT_mno_strict_align) ||200A->getOption().matches(options::OPT_mno_vector_strict_align)) {201Features.push_back("+unaligned-vector-mem");202} else {203Features.push_back("-unaligned-vector-mem");204}205} else if (CPUFastVectorUnaligned || Triple.isAndroid()) {206Features.push_back("+unaligned-vector-mem");207}208209// Now add any that the user explicitly requested on the command line,210// which may override the defaults.211handleTargetFeaturesGroup(D, Triple, Args, Features,212options::OPT_m_riscv_Features_Group);213}214215StringRef riscv::getRISCVABI(const ArgList &Args, const llvm::Triple &Triple) {216assert(Triple.isRISCV() && "Unexpected triple");217218// GCC's logic around choosing a default `-mabi=` is complex. If GCC is not219// configured using `--with-abi=`, then the logic for the default choice is220// defined in config.gcc. This function is based on the logic in GCC 9.2.0.221//222// The logic used in GCC 9.2.0 is the following, in order:223// 1. Explicit choices using `--with-abi=`224// 2. A default based on `--with-arch=`, if provided225// 3. A default based on the target triple's arch226//227// The logic in config.gcc is a little circular but it is not inconsistent.228//229// Clang does not have `--with-arch=` or `--with-abi=`, so we use `-march=`230// and `-mabi=` respectively instead.231//232// In order to make chosing logic more clear, Clang uses the following logic,233// in order:234// 1. Explicit choices using `-mabi=`235// 2. A default based on the architecture as determined by getRISCVArch236// 3. Choose a default based on the triple237238// 1. If `-mabi=` is specified, use it.239if (const Arg *A = Args.getLastArg(options::OPT_mabi_EQ))240return A->getValue();241242// 2. Choose a default based on the target architecture.243//244// rv32g | rv32*d -> ilp32d245// rv32e -> ilp32e246// rv32* -> ilp32247// rv64g | rv64*d -> lp64d248// rv64e -> lp64e249// rv64* -> lp64250std::string Arch = getRISCVArch(Args, Triple);251252auto ParseResult = llvm::RISCVISAInfo::parseArchString(253Arch, /* EnableExperimentalExtension */ true);254// Ignore parsing error, just go 3rd step.255if (!llvm::errorToBool(ParseResult.takeError()))256return (*ParseResult)->computeDefaultABI();257258// 3. Choose a default based on the triple259//260// We deviate from GCC's defaults here:261// - On `riscv{XLEN}-unknown-elf` we use the integer calling convention only.262// - On all other OSs we use the double floating point calling convention.263if (Triple.isRISCV32()) {264if (Triple.getOS() == llvm::Triple::UnknownOS)265return "ilp32";266else267return "ilp32d";268} else {269if (Triple.getOS() == llvm::Triple::UnknownOS)270return "lp64";271else272return "lp64d";273}274}275276std::string riscv::getRISCVArch(const llvm::opt::ArgList &Args,277const llvm::Triple &Triple) {278assert(Triple.isRISCV() && "Unexpected triple");279280// GCC's logic around choosing a default `-march=` is complex. If GCC is not281// configured using `--with-arch=`, then the logic for the default choice is282// defined in config.gcc. This function is based on the logic in GCC 9.2.0. We283// deviate from GCC's default on additional `-mcpu` option (GCC does not284// support `-mcpu`) and baremetal targets (UnknownOS) where neither `-march`285// nor `-mabi` is specified.286//287// The logic used in GCC 9.2.0 is the following, in order:288// 1. Explicit choices using `--with-arch=`289// 2. A default based on `--with-abi=`, if provided290// 3. A default based on the target triple's arch291//292// The logic in config.gcc is a little circular but it is not inconsistent.293//294// Clang does not have `--with-arch=` or `--with-abi=`, so we use `-march=`295// and `-mabi=` respectively instead.296//297// Clang uses the following logic, in order:298// 1. Explicit choices using `-march=`299// 2. Based on `-mcpu` if the target CPU has a default ISA string300// 3. A default based on `-mabi`, if provided301// 4. A default based on the target triple's arch302//303// Clang does not yet support MULTILIB_REUSE, so we use `rv{XLEN}imafdc`304// instead of `rv{XLEN}gc` though they are (currently) equivalent.305306// 1. If `-march=` is specified, use it.307if (const Arg *A = Args.getLastArg(options::OPT_march_EQ))308return A->getValue();309310// 2. Get march (isa string) based on `-mcpu=`311if (const Arg *A = Args.getLastArg(options::OPT_mcpu_EQ)) {312StringRef CPU = A->getValue();313if (CPU == "native") {314CPU = llvm::sys::getHostCPUName();315// If the target cpu is unrecognized, use target features.316if (CPU.starts_with("generic")) {317auto FeatureMap = llvm::sys::getHostCPUFeatures();318// hwprobe may be unavailable on older Linux versions.319if (!FeatureMap.empty()) {320std::vector<std::string> Features;321for (auto &F : FeatureMap)322Features.push_back(((F.second ? "+" : "-") + F.first()).str());323auto ParseResult = llvm::RISCVISAInfo::parseFeatures(324Triple.isRISCV32() ? 32 : 64, Features);325if (ParseResult)326return (*ParseResult)->toString();327}328}329}330331StringRef MArch = llvm::RISCV::getMArchFromMcpu(CPU);332// Bypass if target cpu's default march is empty.333if (MArch != "")334return MArch.str();335}336337// 3. Choose a default based on `-mabi=`338//339// ilp32e -> rv32e340// lp64e -> rv64e341// ilp32 | ilp32f | ilp32d -> rv32imafdc342// lp64 | lp64f | lp64d -> rv64imafdc343if (const Arg *A = Args.getLastArg(options::OPT_mabi_EQ)) {344StringRef MABI = A->getValue();345346if (MABI.equals_insensitive("ilp32e"))347return "rv32e";348else if (MABI.equals_insensitive("lp64e"))349return "rv64e";350else if (MABI.starts_with_insensitive("ilp32"))351return "rv32imafdc";352else if (MABI.starts_with_insensitive("lp64")) {353if (Triple.isAndroid())354return "rv64imafdcv_zba_zbb_zbs";355356return "rv64imafdc";357}358}359360// 4. Choose a default based on the triple361//362// We deviate from GCC's defaults here:363// - On `riscv{XLEN}-unknown-elf` we default to `rv{XLEN}imac`364// - On all other OSs we use `rv{XLEN}imafdc` (equivalent to `rv{XLEN}gc`)365if (Triple.isRISCV32()) {366if (Triple.getOS() == llvm::Triple::UnknownOS)367return "rv32imac";368else369return "rv32imafdc";370} else {371if (Triple.getOS() == llvm::Triple::UnknownOS)372return "rv64imac";373else if (Triple.isAndroid())374return "rv64imafdcv_zba_zbb_zbs";375else376return "rv64imafdc";377}378}379380std::string riscv::getRISCVTargetCPU(const llvm::opt::ArgList &Args,381const llvm::Triple &Triple) {382std::string CPU;383// If we have -mcpu, use that.384if (const Arg *A = Args.getLastArg(options::OPT_mcpu_EQ))385CPU = A->getValue();386387// Handle CPU name is 'native'.388if (CPU == "native")389CPU = llvm::sys::getHostCPUName();390391if (!CPU.empty())392return CPU;393394return Triple.isRISCV64() ? "generic-rv64" : "generic-rv32";395}396397398