xref: /freebsd-src/contrib/llvm-project/clang/lib/Basic/Targets/RISCV.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
106c3fb27SDimitry Andric //===--- RISCV.cpp - Implement RISC-V target feature support --------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
906c3fb27SDimitry Andric // This file implements RISC-V TargetInfo objects.
100b57cec5SDimitry Andric //
110b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
120b57cec5SDimitry Andric 
130b57cec5SDimitry Andric #include "RISCV.h"
14349cc55cSDimitry Andric #include "clang/Basic/Diagnostic.h"
150b57cec5SDimitry Andric #include "clang/Basic/MacroBuilder.h"
16fe6060f1SDimitry Andric #include "clang/Basic/TargetBuiltins.h"
170b57cec5SDimitry Andric #include "llvm/ADT/StringSwitch.h"
18349cc55cSDimitry Andric #include "llvm/Support/raw_ostream.h"
19bdd1243dSDimitry Andric #include "llvm/TargetParser/RISCVTargetParser.h"
20bdd1243dSDimitry Andric #include <optional>
210b57cec5SDimitry Andric 
220b57cec5SDimitry Andric using namespace clang;
230b57cec5SDimitry Andric using namespace clang::targets;
240b57cec5SDimitry Andric 
250b57cec5SDimitry Andric ArrayRef<const char *> RISCVTargetInfo::getGCCRegNames() const {
265f757f3fSDimitry Andric   // clang-format off
270b57cec5SDimitry Andric   static const char *const GCCRegNames[] = {
28a7dea167SDimitry Andric       // Integer registers
290b57cec5SDimitry Andric       "x0",  "x1",  "x2",  "x3",  "x4",  "x5",  "x6",  "x7",
300b57cec5SDimitry Andric       "x8",  "x9",  "x10", "x11", "x12", "x13", "x14", "x15",
310b57cec5SDimitry Andric       "x16", "x17", "x18", "x19", "x20", "x21", "x22", "x23",
32a7dea167SDimitry Andric       "x24", "x25", "x26", "x27", "x28", "x29", "x30", "x31",
33a7dea167SDimitry Andric 
34a7dea167SDimitry Andric       // Floating point registers
35a7dea167SDimitry Andric       "f0",  "f1",  "f2",  "f3",  "f4",  "f5",  "f6",  "f7",
36a7dea167SDimitry Andric       "f8",  "f9",  "f10", "f11", "f12", "f13", "f14", "f15",
37a7dea167SDimitry Andric       "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23",
38fe6060f1SDimitry Andric       "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31",
39fe6060f1SDimitry Andric 
40fe6060f1SDimitry Andric       // Vector registers
41fe6060f1SDimitry Andric       "v0",  "v1",  "v2",  "v3",  "v4",  "v5",  "v6",  "v7",
42fe6060f1SDimitry Andric       "v8",  "v9",  "v10", "v11", "v12", "v13", "v14", "v15",
43fe6060f1SDimitry Andric       "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23",
445f757f3fSDimitry Andric       "v24", "v25", "v26", "v27", "v28", "v29", "v30", "v31",
455f757f3fSDimitry Andric 
465f757f3fSDimitry Andric       // CSRs
475f757f3fSDimitry Andric       "fflags", "frm", "vtype", "vl", "vxsat", "vxrm"
485f757f3fSDimitry Andric     };
495f757f3fSDimitry Andric   // clang-format on
50bdd1243dSDimitry Andric   return llvm::ArrayRef(GCCRegNames);
510b57cec5SDimitry Andric }
520b57cec5SDimitry Andric 
530b57cec5SDimitry Andric ArrayRef<TargetInfo::GCCRegAlias> RISCVTargetInfo::getGCCRegAliases() const {
540b57cec5SDimitry Andric   static const TargetInfo::GCCRegAlias GCCRegAliases[] = {
550b57cec5SDimitry Andric       {{"zero"}, "x0"}, {{"ra"}, "x1"},   {{"sp"}, "x2"},    {{"gp"}, "x3"},
560b57cec5SDimitry Andric       {{"tp"}, "x4"},   {{"t0"}, "x5"},   {{"t1"}, "x6"},    {{"t2"}, "x7"},
570b57cec5SDimitry Andric       {{"s0"}, "x8"},   {{"s1"}, "x9"},   {{"a0"}, "x10"},   {{"a1"}, "x11"},
580b57cec5SDimitry Andric       {{"a2"}, "x12"},  {{"a3"}, "x13"},  {{"a4"}, "x14"},   {{"a5"}, "x15"},
590b57cec5SDimitry Andric       {{"a6"}, "x16"},  {{"a7"}, "x17"},  {{"s2"}, "x18"},   {{"s3"}, "x19"},
600b57cec5SDimitry Andric       {{"s4"}, "x20"},  {{"s5"}, "x21"},  {{"s6"}, "x22"},   {{"s7"}, "x23"},
610b57cec5SDimitry Andric       {{"s8"}, "x24"},  {{"s9"}, "x25"},  {{"s10"}, "x26"},  {{"s11"}, "x27"},
62a7dea167SDimitry Andric       {{"t3"}, "x28"},  {{"t4"}, "x29"},  {{"t5"}, "x30"},   {{"t6"}, "x31"},
63a7dea167SDimitry Andric       {{"ft0"}, "f0"},  {{"ft1"}, "f1"},  {{"ft2"}, "f2"},   {{"ft3"}, "f3"},
64a7dea167SDimitry Andric       {{"ft4"}, "f4"},  {{"ft5"}, "f5"},  {{"ft6"}, "f6"},   {{"ft7"}, "f7"},
65a7dea167SDimitry Andric       {{"fs0"}, "f8"},  {{"fs1"}, "f9"},  {{"fa0"}, "f10"},  {{"fa1"}, "f11"},
66a7dea167SDimitry Andric       {{"fa2"}, "f12"}, {{"fa3"}, "f13"}, {{"fa4"}, "f14"},  {{"fa5"}, "f15"},
67a7dea167SDimitry Andric       {{"fa6"}, "f16"}, {{"fa7"}, "f17"}, {{"fs2"}, "f18"},  {{"fs3"}, "f19"},
68a7dea167SDimitry Andric       {{"fs4"}, "f20"}, {{"fs5"}, "f21"}, {{"fs6"}, "f22"},  {{"fs7"}, "f23"},
69a7dea167SDimitry Andric       {{"fs8"}, "f24"}, {{"fs9"}, "f25"}, {{"fs10"}, "f26"}, {{"fs11"}, "f27"},
70a7dea167SDimitry Andric       {{"ft8"}, "f28"}, {{"ft9"}, "f29"}, {{"ft10"}, "f30"}, {{"ft11"}, "f31"}};
71bdd1243dSDimitry Andric   return llvm::ArrayRef(GCCRegAliases);
720b57cec5SDimitry Andric }
730b57cec5SDimitry Andric 
740b57cec5SDimitry Andric bool RISCVTargetInfo::validateAsmConstraint(
750b57cec5SDimitry Andric     const char *&Name, TargetInfo::ConstraintInfo &Info) const {
760b57cec5SDimitry Andric   switch (*Name) {
770b57cec5SDimitry Andric   default:
780b57cec5SDimitry Andric     return false;
790b57cec5SDimitry Andric   case 'I':
800b57cec5SDimitry Andric     // A 12-bit signed immediate.
810b57cec5SDimitry Andric     Info.setRequiresImmediate(-2048, 2047);
820b57cec5SDimitry Andric     return true;
830b57cec5SDimitry Andric   case 'J':
840b57cec5SDimitry Andric     // Integer zero.
850b57cec5SDimitry Andric     Info.setRequiresImmediate(0);
860b57cec5SDimitry Andric     return true;
870b57cec5SDimitry Andric   case 'K':
880b57cec5SDimitry Andric     // A 5-bit unsigned immediate for CSR access instructions.
890b57cec5SDimitry Andric     Info.setRequiresImmediate(0, 31);
900b57cec5SDimitry Andric     return true;
910b57cec5SDimitry Andric   case 'f':
920b57cec5SDimitry Andric     // A floating-point register.
930b57cec5SDimitry Andric     Info.setAllowsRegister();
940b57cec5SDimitry Andric     return true;
950b57cec5SDimitry Andric   case 'A':
960b57cec5SDimitry Andric     // An address that is held in a general-purpose register.
970b57cec5SDimitry Andric     Info.setAllowsMemory();
980b57cec5SDimitry Andric     return true;
99*0fca6ea1SDimitry Andric   case 's':
100*0fca6ea1SDimitry Andric   case 'S': // A symbol or label reference with a constant offset
101fe6060f1SDimitry Andric     Info.setAllowsRegister();
102fe6060f1SDimitry Andric     return true;
103fe6060f1SDimitry Andric   case 'v':
104fe6060f1SDimitry Andric     // A vector register.
105fe6060f1SDimitry Andric     if (Name[1] == 'r' || Name[1] == 'm') {
106fe6060f1SDimitry Andric       Info.setAllowsRegister();
107fe6060f1SDimitry Andric       Name += 1;
108fe6060f1SDimitry Andric       return true;
1090b57cec5SDimitry Andric     }
110fe6060f1SDimitry Andric     return false;
111fe6060f1SDimitry Andric   }
112fe6060f1SDimitry Andric }
113fe6060f1SDimitry Andric 
114fe6060f1SDimitry Andric std::string RISCVTargetInfo::convertConstraint(const char *&Constraint) const {
115fe6060f1SDimitry Andric   std::string R;
116fe6060f1SDimitry Andric   switch (*Constraint) {
117fe6060f1SDimitry Andric   case 'v':
118349cc55cSDimitry Andric     R = std::string("^") + std::string(Constraint, 2);
119fe6060f1SDimitry Andric     Constraint += 1;
120fe6060f1SDimitry Andric     break;
121fe6060f1SDimitry Andric   default:
122fe6060f1SDimitry Andric     R = TargetInfo::convertConstraint(Constraint);
123fe6060f1SDimitry Andric     break;
124fe6060f1SDimitry Andric   }
125fe6060f1SDimitry Andric   return R;
1260b57cec5SDimitry Andric }
1270b57cec5SDimitry Andric 
128bdd1243dSDimitry Andric static unsigned getVersionValue(unsigned MajorVersion, unsigned MinorVersion) {
129bdd1243dSDimitry Andric   return MajorVersion * 1000000 + MinorVersion * 1000;
130bdd1243dSDimitry Andric }
131bdd1243dSDimitry Andric 
1320b57cec5SDimitry Andric void RISCVTargetInfo::getTargetDefines(const LangOptions &Opts,
1330b57cec5SDimitry Andric                                        MacroBuilder &Builder) const {
1340b57cec5SDimitry Andric   Builder.defineMacro("__riscv");
1355f757f3fSDimitry Andric   bool Is64Bit = getTriple().isRISCV64();
1360b57cec5SDimitry Andric   Builder.defineMacro("__riscv_xlen", Is64Bit ? "64" : "32");
137a7dea167SDimitry Andric   StringRef CodeModel = getTargetOpts().CodeModel;
138349cc55cSDimitry Andric   unsigned FLen = ISAInfo->getFLen();
13904eeddc0SDimitry Andric   unsigned MinVLen = ISAInfo->getMinVLen();
14004eeddc0SDimitry Andric   unsigned MaxELen = ISAInfo->getMaxELen();
14104eeddc0SDimitry Andric   unsigned MaxELenFp = ISAInfo->getMaxELenFp();
142a7dea167SDimitry Andric   if (CodeModel == "default")
143a7dea167SDimitry Andric     CodeModel = "small";
144a7dea167SDimitry Andric 
145a7dea167SDimitry Andric   if (CodeModel == "small")
1460b57cec5SDimitry Andric     Builder.defineMacro("__riscv_cmodel_medlow");
147a7dea167SDimitry Andric   else if (CodeModel == "medium")
148a7dea167SDimitry Andric     Builder.defineMacro("__riscv_cmodel_medany");
1490b57cec5SDimitry Andric 
1500b57cec5SDimitry Andric   StringRef ABIName = getABI();
1510b57cec5SDimitry Andric   if (ABIName == "ilp32f" || ABIName == "lp64f")
1520b57cec5SDimitry Andric     Builder.defineMacro("__riscv_float_abi_single");
1530b57cec5SDimitry Andric   else if (ABIName == "ilp32d" || ABIName == "lp64d")
1540b57cec5SDimitry Andric     Builder.defineMacro("__riscv_float_abi_double");
1550b57cec5SDimitry Andric   else
1560b57cec5SDimitry Andric     Builder.defineMacro("__riscv_float_abi_soft");
1570b57cec5SDimitry Andric 
1587a6dacacSDimitry Andric   if (ABIName == "ilp32e" || ABIName == "lp64e")
159a7dea167SDimitry Andric     Builder.defineMacro("__riscv_abi_rve");
160a7dea167SDimitry Andric 
161e8d8bef9SDimitry Andric   Builder.defineMacro("__riscv_arch_test");
162e8d8bef9SDimitry Andric 
163349cc55cSDimitry Andric   for (auto &Extension : ISAInfo->getExtensions()) {
164349cc55cSDimitry Andric     auto ExtName = Extension.first;
165349cc55cSDimitry Andric     auto ExtInfo = Extension.second;
166349cc55cSDimitry Andric 
167297eecfbSDimitry Andric     Builder.defineMacro(Twine("__riscv_", ExtName),
168297eecfbSDimitry Andric                         Twine(getVersionValue(ExtInfo.Major, ExtInfo.Minor)));
169349cc55cSDimitry Andric   }
170349cc55cSDimitry Andric 
171*0fca6ea1SDimitry Andric   if (ISAInfo->hasExtension("zmmul"))
1720b57cec5SDimitry Andric     Builder.defineMacro("__riscv_mul");
173fcaf7f86SDimitry Andric 
174fcaf7f86SDimitry Andric   if (ISAInfo->hasExtension("m")) {
1750b57cec5SDimitry Andric     Builder.defineMacro("__riscv_div");
1760b57cec5SDimitry Andric     Builder.defineMacro("__riscv_muldiv");
1770b57cec5SDimitry Andric   }
1780b57cec5SDimitry Andric 
179349cc55cSDimitry Andric   if (ISAInfo->hasExtension("a")) {
1800b57cec5SDimitry Andric     Builder.defineMacro("__riscv_atomic");
1816813f242SDimitry Andric     Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1");
1826813f242SDimitry Andric     Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2");
1836813f242SDimitry Andric     Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4");
1846813f242SDimitry Andric     if (Is64Bit)
1856813f242SDimitry Andric       Builder.defineMacro("__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8");
1866813f242SDimitry Andric   }
1870b57cec5SDimitry Andric 
188349cc55cSDimitry Andric   if (FLen) {
189349cc55cSDimitry Andric     Builder.defineMacro("__riscv_flen", Twine(FLen));
1900b57cec5SDimitry Andric     Builder.defineMacro("__riscv_fdiv");
1910b57cec5SDimitry Andric     Builder.defineMacro("__riscv_fsqrt");
1920b57cec5SDimitry Andric   }
1930b57cec5SDimitry Andric 
19404eeddc0SDimitry Andric   if (MinVLen) {
19504eeddc0SDimitry Andric     Builder.defineMacro("__riscv_v_min_vlen", Twine(MinVLen));
19604eeddc0SDimitry Andric     Builder.defineMacro("__riscv_v_elen", Twine(MaxELen));
19704eeddc0SDimitry Andric     Builder.defineMacro("__riscv_v_elen_fp", Twine(MaxELenFp));
19804eeddc0SDimitry Andric   }
19904eeddc0SDimitry Andric 
200349cc55cSDimitry Andric   if (ISAInfo->hasExtension("c"))
201e8d8bef9SDimitry Andric     Builder.defineMacro("__riscv_compressed");
202e8d8bef9SDimitry Andric 
203bdd1243dSDimitry Andric   if (ISAInfo->hasExtension("zve32x")) {
204e8d8bef9SDimitry Andric     Builder.defineMacro("__riscv_vector");
2058a4dda33SDimitry Andric     // Currently we support the v0.12 RISC-V V intrinsics.
2068a4dda33SDimitry Andric     Builder.defineMacro("__riscv_v_intrinsic", Twine(getVersionValue(0, 12)));
207bdd1243dSDimitry Andric   }
20806c3fb27SDimitry Andric 
20906c3fb27SDimitry Andric   auto VScale = getVScaleRange(Opts);
21006c3fb27SDimitry Andric   if (VScale && VScale->first && VScale->first == VScale->second)
21106c3fb27SDimitry Andric     Builder.defineMacro("__riscv_v_fixed_vlen",
21206c3fb27SDimitry Andric                         Twine(VScale->first * llvm::RISCV::RVVBitsPerBlock));
2135f757f3fSDimitry Andric 
214*0fca6ea1SDimitry Andric   if (FastScalarUnalignedAccess)
2155f757f3fSDimitry Andric     Builder.defineMacro("__riscv_misaligned_fast");
2165f757f3fSDimitry Andric   else
2175f757f3fSDimitry Andric     Builder.defineMacro("__riscv_misaligned_avoid");
2187a6dacacSDimitry Andric 
2197a6dacacSDimitry Andric   if (ISAInfo->hasExtension("e")) {
2207a6dacacSDimitry Andric     if (Is64Bit)
2217a6dacacSDimitry Andric       Builder.defineMacro("__riscv_64e");
2227a6dacacSDimitry Andric     else
2237a6dacacSDimitry Andric       Builder.defineMacro("__riscv_32e");
2247a6dacacSDimitry Andric   }
225e8d8bef9SDimitry Andric }
226e8d8bef9SDimitry Andric 
227bdd1243dSDimitry Andric static constexpr Builtin::Info BuiltinInfo[] = {
228fe6060f1SDimitry Andric #define BUILTIN(ID, TYPE, ATTRS)                                               \
229bdd1243dSDimitry Andric   {#ID, TYPE, ATTRS, nullptr, HeaderDesc::NO_HEADER, ALL_LANGUAGES},
230fe6060f1SDimitry Andric #define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE)                               \
231bdd1243dSDimitry Andric   {#ID, TYPE, ATTRS, FEATURE, HeaderDesc::NO_HEADER, ALL_LANGUAGES},
232349cc55cSDimitry Andric #include "clang/Basic/BuiltinsRISCVVector.def"
233349cc55cSDimitry Andric #define BUILTIN(ID, TYPE, ATTRS)                                               \
234bdd1243dSDimitry Andric   {#ID, TYPE, ATTRS, nullptr, HeaderDesc::NO_HEADER, ALL_LANGUAGES},
235349cc55cSDimitry Andric #define TARGET_BUILTIN(ID, TYPE, ATTRS, FEATURE)                               \
236bdd1243dSDimitry Andric   {#ID, TYPE, ATTRS, FEATURE, HeaderDesc::NO_HEADER, ALL_LANGUAGES},
237*0fca6ea1SDimitry Andric #include "clang/Basic/BuiltinsRISCV.inc"
238fe6060f1SDimitry Andric };
239fe6060f1SDimitry Andric 
240fe6060f1SDimitry Andric ArrayRef<Builtin::Info> RISCVTargetInfo::getTargetBuiltins() const {
241bdd1243dSDimitry Andric   return llvm::ArrayRef(BuiltinInfo,
242bdd1243dSDimitry Andric                         clang::RISCV::LastTSBuiltin - Builtin::FirstTSBuiltin);
243fe6060f1SDimitry Andric }
244fe6060f1SDimitry Andric 
245fe6060f1SDimitry Andric bool RISCVTargetInfo::initFeatureMap(
246fe6060f1SDimitry Andric     llvm::StringMap<bool> &Features, DiagnosticsEngine &Diags, StringRef CPU,
247fe6060f1SDimitry Andric     const std::vector<std::string> &FeaturesVec) const {
248fe6060f1SDimitry Andric 
24904eeddc0SDimitry Andric   unsigned XLen = 32;
250fe6060f1SDimitry Andric 
2515f757f3fSDimitry Andric   if (getTriple().isRISCV64()) {
25204eeddc0SDimitry Andric     Features["64bit"] = true;
25304eeddc0SDimitry Andric     XLen = 64;
254bdd1243dSDimitry Andric   } else {
255bdd1243dSDimitry Andric     Features["32bit"] = true;
25604eeddc0SDimitry Andric   }
25704eeddc0SDimitry Andric 
2587a6dacacSDimitry Andric   // If a target attribute specified a full arch string, override all the ISA
2597a6dacacSDimitry Andric   // extension target features.
2607a6dacacSDimitry Andric   const auto I = llvm::find(FeaturesVec, "__RISCV_TargetAttrNeedOverride");
2617a6dacacSDimitry Andric   if (I != FeaturesVec.end()) {
2627a6dacacSDimitry Andric     std::vector<std::string> OverrideFeatures(std::next(I), FeaturesVec.end());
2635f757f3fSDimitry Andric 
2647a6dacacSDimitry Andric     // Add back any non ISA extension features, e.g. +relax.
2657a6dacacSDimitry Andric     auto IsNonISAExtFeature = [](StringRef Feature) {
2667a6dacacSDimitry Andric       assert(Feature.size() > 1 && (Feature[0] == '+' || Feature[0] == '-'));
2677a6dacacSDimitry Andric       StringRef Ext = Feature.substr(1); // drop the +/-
2687a6dacacSDimitry Andric       return !llvm::RISCVISAInfo::isSupportedExtensionFeature(Ext);
2697a6dacacSDimitry Andric     };
2707a6dacacSDimitry Andric     llvm::copy_if(llvm::make_range(FeaturesVec.begin(), I),
2717a6dacacSDimitry Andric                   std::back_inserter(OverrideFeatures), IsNonISAExtFeature);
2727a6dacacSDimitry Andric 
2737a6dacacSDimitry Andric     return TargetInfo::initFeatureMap(Features, Diags, CPU, OverrideFeatures);
2747a6dacacSDimitry Andric   }
2757a6dacacSDimitry Andric 
2767a6dacacSDimitry Andric   // Otherwise, parse the features and add any implied extensions.
2777a6dacacSDimitry Andric   std::vector<std::string> AllFeatures = FeaturesVec;
2787a6dacacSDimitry Andric   auto ParseResult = llvm::RISCVISAInfo::parseFeatures(XLen, FeaturesVec);
27904eeddc0SDimitry Andric   if (!ParseResult) {
28004eeddc0SDimitry Andric     std::string Buffer;
28104eeddc0SDimitry Andric     llvm::raw_string_ostream OutputErrMsg(Buffer);
28204eeddc0SDimitry Andric     handleAllErrors(ParseResult.takeError(), [&](llvm::StringError &ErrMsg) {
28304eeddc0SDimitry Andric       OutputErrMsg << ErrMsg.getMessage();
28404eeddc0SDimitry Andric     });
28504eeddc0SDimitry Andric     Diags.Report(diag::err_invalid_feature_combination) << OutputErrMsg.str();
28604eeddc0SDimitry Andric     return false;
28704eeddc0SDimitry Andric   }
28804eeddc0SDimitry Andric 
2897a6dacacSDimitry Andric   // Append all features, not just new ones, so we override any negatives.
2907a6dacacSDimitry Andric   llvm::append_range(AllFeatures, (*ParseResult)->toFeatures());
2917a6dacacSDimitry Andric   return TargetInfo::initFeatureMap(Features, Diags, CPU, AllFeatures);
292fe6060f1SDimitry Andric }
293fe6060f1SDimitry Andric 
294bdd1243dSDimitry Andric std::optional<std::pair<unsigned, unsigned>>
295bdd1243dSDimitry Andric RISCVTargetInfo::getVScaleRange(const LangOptions &LangOpts) const {
296bdd1243dSDimitry Andric   // RISCV::RVVBitsPerBlock is 64.
297bdd1243dSDimitry Andric   unsigned VScaleMin = ISAInfo->getMinVLen() / llvm::RISCV::RVVBitsPerBlock;
298bdd1243dSDimitry Andric 
299bdd1243dSDimitry Andric   if (LangOpts.VScaleMin || LangOpts.VScaleMax) {
300bdd1243dSDimitry Andric     // Treat Zvl*b as a lower bound on vscale.
301bdd1243dSDimitry Andric     VScaleMin = std::max(VScaleMin, LangOpts.VScaleMin);
302bdd1243dSDimitry Andric     unsigned VScaleMax = LangOpts.VScaleMax;
303bdd1243dSDimitry Andric     if (VScaleMax != 0 && VScaleMax < VScaleMin)
304bdd1243dSDimitry Andric       VScaleMax = VScaleMin;
305bdd1243dSDimitry Andric     return std::pair<unsigned, unsigned>(VScaleMin ? VScaleMin : 1, VScaleMax);
306bdd1243dSDimitry Andric   }
307bdd1243dSDimitry Andric 
308bdd1243dSDimitry Andric   if (VScaleMin > 0) {
309bdd1243dSDimitry Andric     unsigned VScaleMax = ISAInfo->getMaxVLen() / llvm::RISCV::RVVBitsPerBlock;
310bdd1243dSDimitry Andric     return std::make_pair(VScaleMin, VScaleMax);
311bdd1243dSDimitry Andric   }
312bdd1243dSDimitry Andric 
313bdd1243dSDimitry Andric   return std::nullopt;
314bdd1243dSDimitry Andric }
315bdd1243dSDimitry Andric 
3160b57cec5SDimitry Andric /// Return true if has this feature, need to sync with handleTargetFeatures.
3170b57cec5SDimitry Andric bool RISCVTargetInfo::hasFeature(StringRef Feature) const {
3185f757f3fSDimitry Andric   bool Is64Bit = getTriple().isRISCV64();
319bdd1243dSDimitry Andric   auto Result = llvm::StringSwitch<std::optional<bool>>(Feature)
3200b57cec5SDimitry Andric                     .Case("riscv", true)
3210b57cec5SDimitry Andric                     .Case("riscv32", !Is64Bit)
3220b57cec5SDimitry Andric                     .Case("riscv64", Is64Bit)
323bdd1243dSDimitry Andric                     .Case("32bit", !Is64Bit)
324fe6060f1SDimitry Andric                     .Case("64bit", Is64Bit)
325cb14a3feSDimitry Andric                     .Case("experimental", HasExperimental)
326bdd1243dSDimitry Andric                     .Default(std::nullopt);
32781ad6265SDimitry Andric   if (Result)
328bdd1243dSDimitry Andric     return *Result;
329349cc55cSDimitry Andric 
330349cc55cSDimitry Andric   return ISAInfo->hasExtension(Feature);
3310b57cec5SDimitry Andric }
3320b57cec5SDimitry Andric 
3330b57cec5SDimitry Andric /// Perform initialization based on the user configured set of features.
3340b57cec5SDimitry Andric bool RISCVTargetInfo::handleTargetFeatures(std::vector<std::string> &Features,
3350b57cec5SDimitry Andric                                            DiagnosticsEngine &Diags) {
336349cc55cSDimitry Andric   unsigned XLen = getTriple().isArch64Bit() ? 64 : 32;
337349cc55cSDimitry Andric   auto ParseResult = llvm::RISCVISAInfo::parseFeatures(XLen, Features);
338349cc55cSDimitry Andric   if (!ParseResult) {
339349cc55cSDimitry Andric     std::string Buffer;
340349cc55cSDimitry Andric     llvm::raw_string_ostream OutputErrMsg(Buffer);
341349cc55cSDimitry Andric     handleAllErrors(ParseResult.takeError(), [&](llvm::StringError &ErrMsg) {
342349cc55cSDimitry Andric       OutputErrMsg << ErrMsg.getMessage();
343349cc55cSDimitry Andric     });
344349cc55cSDimitry Andric     Diags.Report(diag::err_invalid_feature_combination) << OutputErrMsg.str();
345349cc55cSDimitry Andric     return false;
346349cc55cSDimitry Andric   } else {
347349cc55cSDimitry Andric     ISAInfo = std::move(*ParseResult);
3480b57cec5SDimitry Andric   }
3490b57cec5SDimitry Andric 
3500eae32dcSDimitry Andric   if (ABI.empty())
35181ad6265SDimitry Andric     ABI = ISAInfo->computeDefaultABI().str();
3520eae32dcSDimitry Andric 
35306c3fb27SDimitry Andric   if (ISAInfo->hasExtension("zfh") || ISAInfo->hasExtension("zhinx"))
35406c3fb27SDimitry Andric     HasLegalHalfType = true;
35506c3fb27SDimitry Andric 
356*0fca6ea1SDimitry Andric   FastScalarUnalignedAccess =
357*0fca6ea1SDimitry Andric       llvm::is_contained(Features, "+unaligned-scalar-mem");
3585f757f3fSDimitry Andric 
359cb14a3feSDimitry Andric   if (llvm::is_contained(Features, "+experimental"))
360cb14a3feSDimitry Andric     HasExperimental = true;
361cb14a3feSDimitry Andric 
3627a6dacacSDimitry Andric   if (ABI == "ilp32e" && ISAInfo->hasExtension("d")) {
3637a6dacacSDimitry Andric     Diags.Report(diag::err_invalid_feature_combination)
3647a6dacacSDimitry Andric         << "ILP32E cannot be used with the D ISA extension";
3657a6dacacSDimitry Andric     return false;
3667a6dacacSDimitry Andric   }
3670b57cec5SDimitry Andric   return true;
3680b57cec5SDimitry Andric }
369590d96feSDimitry Andric 
370bdd1243dSDimitry Andric bool RISCVTargetInfo::isValidCPUName(StringRef Name) const {
371bdd1243dSDimitry Andric   bool Is64Bit = getTriple().isArch64Bit();
37206c3fb27SDimitry Andric   return llvm::RISCV::parseCPU(Name, Is64Bit);
373590d96feSDimitry Andric }
374590d96feSDimitry Andric 
375bdd1243dSDimitry Andric void RISCVTargetInfo::fillValidCPUList(
376590d96feSDimitry Andric     SmallVectorImpl<StringRef> &Values) const {
377bdd1243dSDimitry Andric   bool Is64Bit = getTriple().isArch64Bit();
378bdd1243dSDimitry Andric   llvm::RISCV::fillValidCPUArchList(Values, Is64Bit);
379590d96feSDimitry Andric }
380590d96feSDimitry Andric 
381bdd1243dSDimitry Andric bool RISCVTargetInfo::isValidTuneCPUName(StringRef Name) const {
382bdd1243dSDimitry Andric   bool Is64Bit = getTriple().isArch64Bit();
38306c3fb27SDimitry Andric   return llvm::RISCV::parseTuneCPU(Name, Is64Bit);
384e8d8bef9SDimitry Andric }
385e8d8bef9SDimitry Andric 
386bdd1243dSDimitry Andric void RISCVTargetInfo::fillValidTuneCPUList(
387e8d8bef9SDimitry Andric     SmallVectorImpl<StringRef> &Values) const {
388bdd1243dSDimitry Andric   bool Is64Bit = getTriple().isArch64Bit();
389bdd1243dSDimitry Andric   llvm::RISCV::fillValidTuneCPUArchList(Values, Is64Bit);
390e8d8bef9SDimitry Andric }
3915f757f3fSDimitry Andric 
3925f757f3fSDimitry Andric static void handleFullArchString(StringRef FullArchStr,
3935f757f3fSDimitry Andric                                  std::vector<std::string> &Features) {
3945f757f3fSDimitry Andric   Features.push_back("__RISCV_TargetAttrNeedOverride");
3955f757f3fSDimitry Andric   auto RII = llvm::RISCVISAInfo::parseArchString(
3965f757f3fSDimitry Andric       FullArchStr, /* EnableExperimentalExtension */ true);
397647cbc5dSDimitry Andric   if (llvm::errorToBool(RII.takeError())) {
3985f757f3fSDimitry Andric     // Forward the invalid FullArchStr.
3995f757f3fSDimitry Andric     Features.push_back("+" + FullArchStr.str());
4005f757f3fSDimitry Andric   } else {
4017a6dacacSDimitry Andric     // Append a full list of features, including any negative extensions so that
4027a6dacacSDimitry Andric     // we override the CPU's features.
4037a6dacacSDimitry Andric     std::vector<std::string> FeatStrings =
4047a6dacacSDimitry Andric         (*RII)->toFeatures(/* AddAllExtensions */ true);
4055f757f3fSDimitry Andric     Features.insert(Features.end(), FeatStrings.begin(), FeatStrings.end());
4065f757f3fSDimitry Andric   }
4075f757f3fSDimitry Andric }
4085f757f3fSDimitry Andric 
4095f757f3fSDimitry Andric ParsedTargetAttr RISCVTargetInfo::parseTargetAttr(StringRef Features) const {
4105f757f3fSDimitry Andric   ParsedTargetAttr Ret;
4115f757f3fSDimitry Andric   if (Features == "default")
4125f757f3fSDimitry Andric     return Ret;
4135f757f3fSDimitry Andric   SmallVector<StringRef, 1> AttrFeatures;
4145f757f3fSDimitry Andric   Features.split(AttrFeatures, ";");
4155f757f3fSDimitry Andric   bool FoundArch = false;
4165f757f3fSDimitry Andric 
4175f757f3fSDimitry Andric   for (auto &Feature : AttrFeatures) {
4185f757f3fSDimitry Andric     Feature = Feature.trim();
4195f757f3fSDimitry Andric     StringRef AttrString = Feature.split("=").second.trim();
4205f757f3fSDimitry Andric 
4215f757f3fSDimitry Andric     if (Feature.starts_with("arch=")) {
4225f757f3fSDimitry Andric       // Override last features
4235f757f3fSDimitry Andric       Ret.Features.clear();
4245f757f3fSDimitry Andric       if (FoundArch)
4255f757f3fSDimitry Andric         Ret.Duplicate = "arch=";
4265f757f3fSDimitry Andric       FoundArch = true;
4275f757f3fSDimitry Andric 
4285f757f3fSDimitry Andric       if (AttrString.starts_with("+")) {
4295f757f3fSDimitry Andric         // EXTENSION like arch=+v,+zbb
4305f757f3fSDimitry Andric         SmallVector<StringRef, 1> Exts;
4315f757f3fSDimitry Andric         AttrString.split(Exts, ",");
4325f757f3fSDimitry Andric         for (auto Ext : Exts) {
4335f757f3fSDimitry Andric           if (Ext.empty())
4345f757f3fSDimitry Andric             continue;
4355f757f3fSDimitry Andric 
4365f757f3fSDimitry Andric           StringRef ExtName = Ext.substr(1);
4375f757f3fSDimitry Andric           std::string TargetFeature =
4385f757f3fSDimitry Andric               llvm::RISCVISAInfo::getTargetFeatureForExtension(ExtName);
4395f757f3fSDimitry Andric           if (!TargetFeature.empty())
4405f757f3fSDimitry Andric             Ret.Features.push_back(Ext.front() + TargetFeature);
4415f757f3fSDimitry Andric           else
4425f757f3fSDimitry Andric             Ret.Features.push_back(Ext.str());
4435f757f3fSDimitry Andric         }
4445f757f3fSDimitry Andric       } else {
4455f757f3fSDimitry Andric         // full-arch-string like arch=rv64gcv
4465f757f3fSDimitry Andric         handleFullArchString(AttrString, Ret.Features);
4475f757f3fSDimitry Andric       }
4485f757f3fSDimitry Andric     } else if (Feature.starts_with("cpu=")) {
4495f757f3fSDimitry Andric       if (!Ret.CPU.empty())
4505f757f3fSDimitry Andric         Ret.Duplicate = "cpu=";
4515f757f3fSDimitry Andric 
4525f757f3fSDimitry Andric       Ret.CPU = AttrString;
4535f757f3fSDimitry Andric 
4545f757f3fSDimitry Andric       if (!FoundArch) {
4555f757f3fSDimitry Andric         // Update Features with CPU's features
4565f757f3fSDimitry Andric         StringRef MarchFromCPU = llvm::RISCV::getMArchFromMcpu(Ret.CPU);
4575f757f3fSDimitry Andric         if (MarchFromCPU != "") {
4585f757f3fSDimitry Andric           Ret.Features.clear();
4595f757f3fSDimitry Andric           handleFullArchString(MarchFromCPU, Ret.Features);
4605f757f3fSDimitry Andric         }
4615f757f3fSDimitry Andric       }
4625f757f3fSDimitry Andric     } else if (Feature.starts_with("tune=")) {
4635f757f3fSDimitry Andric       if (!Ret.Tune.empty())
4645f757f3fSDimitry Andric         Ret.Duplicate = "tune=";
4655f757f3fSDimitry Andric 
4665f757f3fSDimitry Andric       Ret.Tune = AttrString;
4675f757f3fSDimitry Andric     }
4685f757f3fSDimitry Andric   }
4695f757f3fSDimitry Andric   return Ret;
4705f757f3fSDimitry Andric }
471*0fca6ea1SDimitry Andric 
472*0fca6ea1SDimitry Andric TargetInfo::CallingConvCheckResult
473*0fca6ea1SDimitry Andric RISCVTargetInfo::checkCallingConvention(CallingConv CC) const {
474*0fca6ea1SDimitry Andric   switch (CC) {
475*0fca6ea1SDimitry Andric   default:
476*0fca6ea1SDimitry Andric     return CCCR_Warning;
477*0fca6ea1SDimitry Andric   case CC_C:
478*0fca6ea1SDimitry Andric   case CC_RISCVVectorCall:
479*0fca6ea1SDimitry Andric     return CCCR_OK;
480*0fca6ea1SDimitry Andric   }
481*0fca6ea1SDimitry Andric }
482