Path: blob/main/contrib/llvm-project/clang/lib/Basic/Targets/RISCV.cpp
35266 views
//===--- RISCV.cpp - Implement RISC-V target feature support --------------===//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//===----------------------------------------------------------------------===//7//8// This file implements RISC-V TargetInfo objects.9//10//===----------------------------------------------------------------------===//1112#include "RISCV.h"13#include "clang/Basic/Diagnostic.h"14#include "clang/Basic/MacroBuilder.h"15#include "clang/Basic/TargetBuiltins.h"16#include "llvm/ADT/StringSwitch.h"17#include "llvm/Support/raw_ostream.h"18#include "llvm/TargetParser/RISCVTargetParser.h"19#include <optional>2021using namespace clang;22using namespace clang::targets;2324ArrayRef<const char *> RISCVTargetInfo::getGCCRegNames() const {25// clang-format off26static const char *const GCCRegNames[] = {27// Integer registers28"x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7",29"x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15",30"x16", "x17", "x18", "x19", "x20", "x21", "x22", "x23",31"x24", "x25", "x26", "x27", "x28", "x29", "x30", "x31",3233// Floating point registers34"f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7",35"f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15",36"f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23",37"f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31",3839// Vector registers40"v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7",41"v8", "v9", "v10", "v11", "v12", "v13", "v14", "v15",42"v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23",43"v24", "v25", "v26", "v27", "v28", "v29", "v30", "v31",4445// CSRs46"fflags", "frm", "vtype", "vl", "vxsat", "vxrm"47};48// clang-format on49return llvm::ArrayRef(GCCRegNames);50}5152ArrayRef<TargetInfo::GCCRegAlias> RISCVTargetInfo::getGCCRegAliases() const {53static const TargetInfo::GCCRegAlias GCCRegAliases[] = {54{{"zero"}, "x0"}, {{"ra"}, "x1"}, {{"sp"}, "x2"}, {{"gp"}, "x3"},55{{"tp"}, "x4"}, {{"t0"}, "x5"}, {{"t1"}, "x6"}, {{"t2"}, "x7"},56{{"s0"}, "x8"}, {{"s1"}, "x9"}, {{"a0"}, "x10"}, {{"a1"}, "x11"},57{{"a2"}, "x12"}, {{"a3"}, "x13"}, {{"a4"}, "x14"}, {{"a5"}, "x15"},58{{"a6"}, "x16"}, {{"a7"}, "x17"}, {{"s2"}, "x18"}, {{"s3"}, "x19"},59{{"s4"}, "x20"}, {{"s5"}, "x21"}, {{"s6"}, "x22"}, {{"s7"}, "x23"},60{{"s8"}, "x24"}, {{"s9"}, "x25"}, {{"s10"}, "x26"}, {{"s11"}, "x27"},61{{"t3"}, "x28"}, {{"t4"}, "x29"}, {{"t5"}, "x30"}, {{"t6"}, "x31"},62{{"ft0"}, "f0"}, {{"ft1"}, "f1"}, {{"ft2"}, "f2"}, {{"ft3"}, "f3"},63{{"ft4"}, "f4"}, {{"ft5"}, "f5"}, {{"ft6"}, "f6"}, {{"ft7"}, "f7"},64{{"fs0"}, "f8"}, {{"fs1"}, "f9"}, {{"fa0"}, "f10"}, {{"fa1"}, "f11"},65{{"fa2"}, "f12"}, {{"fa3"}, "f13"}, {{"fa4"}, "f14"}, {{"fa5"}, "f15"},66{{"fa6"}, "f16"}, {{"fa7"}, "f17"}, {{"fs2"}, "f18"}, {{"fs3"}, "f19"},67{{"fs4"}, "f20"}, {{"fs5"}, "f21"}, {{"fs6"}, "f22"}, {{"fs7"}, "f23"},68{{"fs8"}, "f24"}, {{"fs9"}, "f25"}, {{"fs10"}, "f26"}, {{"fs11"}, "f27"},69{{"ft8"}, "f28"}, {{"ft9"}, "f29"}, {{"ft10"}, "f30"}, {{"ft11"}, "f31"}};70return llvm::ArrayRef(GCCRegAliases);71}7273bool RISCVTargetInfo::validateAsmConstraint(74const char *&Name, TargetInfo::ConstraintInfo &Info) const {75switch (*Name) {76default:77return false;78case 'I':79// A 12-bit signed immediate.80Info.setRequiresImmediate(-2048, 2047);81return true;82case 'J':83// Integer zero.84Info.setRequiresImmediate(0);85return true;86case 'K':87// A 5-bit unsigned immediate for CSR access instructions.88Info.setRequiresImmediate(0, 31);89return true;90case 'f':91// A floating-point register.92Info.setAllowsRegister();93return true;94case 'A':95// An address that is held in a general-purpose register.96Info.setAllowsMemory();97return true;98case 's':99case 'S': // A symbol or label reference with a constant offset100Info.setAllowsRegister();101return true;102case 'v':103// A vector register.104if (Name[1] == 'r' || Name[1] == 'm') {105Info.setAllowsRegister();106Name += 1;107return true;108}109return false;110}111}112113std::string RISCVTargetInfo::convertConstraint(const char *&Constraint) const {114std::string R;115switch (*Constraint) {116case 'v':117R = std::string("^") + std::string(Constraint, 2);118Constraint += 1;119break;120default:121R = TargetInfo::convertConstraint(Constraint);122break;123}124return R;125}126127static unsigned getVersionValue(unsigned MajorVersion, unsigned MinorVersion) {128return MajorVersion * 1000000 + MinorVersion * 1000;129}130131void RISCVTargetInfo::getTargetDefines(const LangOptions &Opts,132MacroBuilder &Builder) const {133Builder.defineMacro("__riscv");134bool Is64Bit = getTriple().isRISCV64();135Builder.defineMacro("__riscv_xlen", Is64Bit ? "64" : "32");136StringRef CodeModel = getTargetOpts().CodeModel;137unsigned FLen = ISAInfo->getFLen();138unsigned MinVLen = ISAInfo->getMinVLen();139unsigned MaxELen = ISAInfo->getMaxELen();140unsigned MaxELenFp = ISAInfo->getMaxELenFp();141if (CodeModel == "default")142CodeModel = "small";143144if (CodeModel == "small")145Builder.defineMacro("__riscv_cmodel_medlow");146else if (CodeModel == "medium")147Builder.defineMacro("__riscv_cmodel_medany");148149StringRef ABIName = getABI();150if (ABIName == "ilp32f" || ABIName == "lp64f")151Builder.defineMacro("__riscv_float_abi_single");152else if (ABIName == "ilp32d" || ABIName == "lp64d")153Builder.defineMacro("__riscv_float_abi_double");154else155Builder.defineMacro("__riscv_float_abi_soft");156157if (ABIName == "ilp32e" || ABIName == "lp64e")158Builder.defineMacro("__riscv_abi_rve");159160Builder.defineMacro("__riscv_arch_test");161162for (auto &Extension : ISAInfo->getExtensions()) {163auto ExtName = Extension.first;164auto ExtInfo = Extension.second;165166Builder.defineMacro(Twine("__riscv_", ExtName),167Twine(getVersionValue(ExtInfo.Major, ExtInfo.Minor)));168}169170if (ISAInfo->hasExtension("zmmul"))171Builder.defineMacro("__riscv_mul");172173if (ISAInfo->hasExtension("m")) {174Builder.defineMacro("__riscv_div");175Builder.defineMacro("__riscv_muldiv");176}177178if (ISAInfo->hasExtension("a")) {179Builder.defineMacro("__riscv_atomic");180Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1");181Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2");182Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4");183if (Is64Bit)184Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8");185}186187if (FLen) {188Builder.defineMacro("__riscv_flen", Twine(FLen));189Builder.defineMacro("__riscv_fdiv");190Builder.defineMacro("__riscv_fsqrt");191}192193if (MinVLen) {194Builder.defineMacro("__riscv_v_min_vlen", Twine(MinVLen));195Builder.defineMacro("__riscv_v_elen", Twine(MaxELen));196Builder.defineMacro("__riscv_v_elen_fp", Twine(MaxELenFp));197}198199if (ISAInfo->hasExtension("c"))200Builder.defineMacro("__riscv_compressed");201202if (ISAInfo->hasExtension("zve32x")) {203Builder.defineMacro("__riscv_vector");204// Currently we support the v0.12 RISC-V V intrinsics.205Builder.defineMacro("__riscv_v_intrinsic", Twine(getVersionValue(0, 12)));206}207208auto VScale = getVScaleRange(Opts);209if (VScale && VScale->first && VScale->first == VScale->second)210Builder.defineMacro("__riscv_v_fixed_vlen",211Twine(VScale->first * llvm::RISCV::RVVBitsPerBlock));212213if (FastScalarUnalignedAccess)214Builder.defineMacro("__riscv_misaligned_fast");215else216Builder.defineMacro("__riscv_misaligned_avoid");217218if (ISAInfo->hasExtension("e")) {219if (Is64Bit)220Builder.defineMacro("__riscv_64e");221else222Builder.defineMacro("__riscv_32e");223}224}225226static constexpr Builtin::Info BuiltinInfo[] = {227#define BUILTIN(ID, TYPE, ATTRS) \228{#ID, TYPE, ATTRS, nullptr, HeaderDesc::NO_HEADER, ALL_LANGUAGES},229#define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) \230{#ID, TYPE, ATTRS, FEATURE, HeaderDesc::NO_HEADER, ALL_LANGUAGES},231#include "clang/Basic/BuiltinsRISCVVector.def"232#define BUILTIN(ID, TYPE, ATTRS) \233{#ID, TYPE, ATTRS, nullptr, HeaderDesc::NO_HEADER, ALL_LANGUAGES},234#define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE) \235{#ID, TYPE, ATTRS, FEATURE, HeaderDesc::NO_HEADER, ALL_LANGUAGES},236#include "clang/Basic/BuiltinsRISCV.inc"237};238239ArrayRef<Builtin::Info> RISCVTargetInfo::getTargetBuiltins() const {240return llvm::ArrayRef(BuiltinInfo,241clang::RISCV::LastTSBuiltin - Builtin::FirstTSBuiltin);242}243244bool RISCVTargetInfo::initFeatureMap(245llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags, StringRef CPU,246const std::vector<std::string> &FeaturesVec) const {247248unsigned XLen = 32;249250if (getTriple().isRISCV64()) {251Features["64bit"] = true;252XLen = 64;253} else {254Features["32bit"] = true;255}256257// If a target attribute specified a full arch string, override all the ISA258// extension target features.259const auto I = llvm::find(FeaturesVec, "__RISCV_TargetAttrNeedOverride");260if (I != FeaturesVec.end()) {261std::vector<std::string> OverrideFeatures(std::next(I), FeaturesVec.end());262263// Add back any non ISA extension features, e.g. +relax.264auto IsNonISAExtFeature = [](StringRef Feature) {265assert(Feature.size() > 1 && (Feature[0] == '+' || Feature[0] == '-'));266StringRef Ext = Feature.substr(1); // drop the +/-267return !llvm::RISCVISAInfo::isSupportedExtensionFeature(Ext);268};269llvm::copy_if(llvm::make_range(FeaturesVec.begin(), I),270std::back_inserter(OverrideFeatures), IsNonISAExtFeature);271272return TargetInfo::initFeatureMap(Features, Diags, CPU, OverrideFeatures);273}274275// Otherwise, parse the features and add any implied extensions.276std::vector<std::string> AllFeatures = FeaturesVec;277auto ParseResult = llvm::RISCVISAInfo::parseFeatures(XLen, FeaturesVec);278if (!ParseResult) {279std::string Buffer;280llvm::raw_string_ostream OutputErrMsg(Buffer);281handleAllErrors(ParseResult.takeError(), [&](llvm::StringError &ErrMsg) {282OutputErrMsg << ErrMsg.getMessage();283});284Diags.Report(diag::err_invalid_feature_combination) << OutputErrMsg.str();285return false;286}287288// Append all features, not just new ones, so we override any negatives.289llvm::append_range(AllFeatures, (*ParseResult)->toFeatures());290return TargetInfo::initFeatureMap(Features, Diags, CPU, AllFeatures);291}292293std::optional<std::pair<unsigned, unsigned>>294RISCVTargetInfo::getVScaleRange(const LangOptions &LangOpts) const {295// RISCV::RVVBitsPerBlock is 64.296unsigned VScaleMin = ISAInfo->getMinVLen() / llvm::RISCV::RVVBitsPerBlock;297298if (LangOpts.VScaleMin || LangOpts.VScaleMax) {299// Treat Zvl*b as a lower bound on vscale.300VScaleMin = std::max(VScaleMin, LangOpts.VScaleMin);301unsigned VScaleMax = LangOpts.VScaleMax;302if (VScaleMax != 0 && VScaleMax < VScaleMin)303VScaleMax = VScaleMin;304return std::pair<unsigned, unsigned>(VScaleMin ? VScaleMin : 1, VScaleMax);305}306307if (VScaleMin > 0) {308unsigned VScaleMax = ISAInfo->getMaxVLen() / llvm::RISCV::RVVBitsPerBlock;309return std::make_pair(VScaleMin, VScaleMax);310}311312return std::nullopt;313}314315/// Return true if has this feature, need to sync with handleTargetFeatures.316bool RISCVTargetInfo::hasFeature(StringRef Feature) const {317bool Is64Bit = getTriple().isRISCV64();318auto Result = llvm::StringSwitch<std::optional<bool>>(Feature)319.Case("riscv", true)320.Case("riscv32", !Is64Bit)321.Case("riscv64", Is64Bit)322.Case("32bit", !Is64Bit)323.Case("64bit", Is64Bit)324.Case("experimental", HasExperimental)325.Default(std::nullopt);326if (Result)327return *Result;328329return ISAInfo->hasExtension(Feature);330}331332/// Perform initialization based on the user configured set of features.333bool RISCVTargetInfo::handleTargetFeatures(std::vector<std::string> &Features,334DiagnosticsEngine &Diags) {335unsigned XLen = getTriple().isArch64Bit() ? 64 : 32;336auto ParseResult = llvm::RISCVISAInfo::parseFeatures(XLen, Features);337if (!ParseResult) {338std::string Buffer;339llvm::raw_string_ostream OutputErrMsg(Buffer);340handleAllErrors(ParseResult.takeError(), [&](llvm::StringError &ErrMsg) {341OutputErrMsg << ErrMsg.getMessage();342});343Diags.Report(diag::err_invalid_feature_combination) << OutputErrMsg.str();344return false;345} else {346ISAInfo = std::move(*ParseResult);347}348349if (ABI.empty())350ABI = ISAInfo->computeDefaultABI().str();351352if (ISAInfo->hasExtension("zfh") || ISAInfo->hasExtension("zhinx"))353HasLegalHalfType = true;354355FastScalarUnalignedAccess =356llvm::is_contained(Features, "+unaligned-scalar-mem");357358if (llvm::is_contained(Features, "+experimental"))359HasExperimental = true;360361if (ABI == "ilp32e" && ISAInfo->hasExtension("d")) {362Diags.Report(diag::err_invalid_feature_combination)363<< "ILP32E cannot be used with the D ISA extension";364return false;365}366return true;367}368369bool RISCVTargetInfo::isValidCPUName(StringRef Name) const {370bool Is64Bit = getTriple().isArch64Bit();371return llvm::RISCV::parseCPU(Name, Is64Bit);372}373374void RISCVTargetInfo::fillValidCPUList(375SmallVectorImpl<StringRef> &Values) const {376bool Is64Bit = getTriple().isArch64Bit();377llvm::RISCV::fillValidCPUArchList(Values, Is64Bit);378}379380bool RISCVTargetInfo::isValidTuneCPUName(StringRef Name) const {381bool Is64Bit = getTriple().isArch64Bit();382return llvm::RISCV::parseTuneCPU(Name, Is64Bit);383}384385void RISCVTargetInfo::fillValidTuneCPUList(386SmallVectorImpl<StringRef> &Values) const {387bool Is64Bit = getTriple().isArch64Bit();388llvm::RISCV::fillValidTuneCPUArchList(Values, Is64Bit);389}390391static void handleFullArchString(StringRef FullArchStr,392std::vector<std::string> &Features) {393Features.push_back("__RISCV_TargetAttrNeedOverride");394auto RII = llvm::RISCVISAInfo::parseArchString(395FullArchStr, /* EnableExperimentalExtension */ true);396if (llvm::errorToBool(RII.takeError())) {397// Forward the invalid FullArchStr.398Features.push_back("+" + FullArchStr.str());399} else {400// Append a full list of features, including any negative extensions so that401// we override the CPU's features.402std::vector<std::string> FeatStrings =403(*RII)->toFeatures(/* AddAllExtensions */ true);404Features.insert(Features.end(), FeatStrings.begin(), FeatStrings.end());405}406}407408ParsedTargetAttr RISCVTargetInfo::parseTargetAttr(StringRef Features) const {409ParsedTargetAttr Ret;410if (Features == "default")411return Ret;412SmallVector<StringRef, 1> AttrFeatures;413Features.split(AttrFeatures, ";");414bool FoundArch = false;415416for (auto &Feature : AttrFeatures) {417Feature = Feature.trim();418StringRef AttrString = Feature.split("=").second.trim();419420if (Feature.starts_with("arch=")) {421// Override last features422Ret.Features.clear();423if (FoundArch)424Ret.Duplicate = "arch=";425FoundArch = true;426427if (AttrString.starts_with("+")) {428// EXTENSION like arch=+v,+zbb429SmallVector<StringRef, 1> Exts;430AttrString.split(Exts, ",");431for (auto Ext : Exts) {432if (Ext.empty())433continue;434435StringRef ExtName = Ext.substr(1);436std::string TargetFeature =437llvm::RISCVISAInfo::getTargetFeatureForExtension(ExtName);438if (!TargetFeature.empty())439Ret.Features.push_back(Ext.front() + TargetFeature);440else441Ret.Features.push_back(Ext.str());442}443} else {444// full-arch-string like arch=rv64gcv445handleFullArchString(AttrString, Ret.Features);446}447} else if (Feature.starts_with("cpu=")) {448if (!Ret.CPU.empty())449Ret.Duplicate = "cpu=";450451Ret.CPU = AttrString;452453if (!FoundArch) {454// Update Features with CPU's features455StringRef MarchFromCPU = llvm::RISCV::getMArchFromMcpu(Ret.CPU);456if (MarchFromCPU != "") {457Ret.Features.clear();458handleFullArchString(MarchFromCPU, Ret.Features);459}460}461} else if (Feature.starts_with("tune=")) {462if (!Ret.Tune.empty())463Ret.Duplicate = "tune=";464465Ret.Tune = AttrString;466}467}468return Ret;469}470471TargetInfo::CallingConvCheckResult472RISCVTargetInfo::checkCallingConvention(CallingConv CC) const {473switch (CC) {474default:475return CCCR_Warning;476case CC_C:477case CC_RISCVVectorCall:478return CCCR_OK;479}480}481482483