xref: /llvm-project/llvm/lib/TargetParser/RISCVTargetParser.cpp (revision 875b10f7d0888ca7e53f527f4c30531bd6b50bfb)
1ac1ffd3cSFrancesco Petrogalli //===-- RISCVTargetParser.cpp - Parser for target features ------*- C++ -*-===//
2ac1ffd3cSFrancesco Petrogalli //
3ac1ffd3cSFrancesco Petrogalli // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4ac1ffd3cSFrancesco Petrogalli // See https://llvm.org/LICENSE.txt for license information.
5ac1ffd3cSFrancesco Petrogalli // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6ac1ffd3cSFrancesco Petrogalli //
7ac1ffd3cSFrancesco Petrogalli //===----------------------------------------------------------------------===//
8ac1ffd3cSFrancesco Petrogalli //
9ac1ffd3cSFrancesco Petrogalli // This file implements a target parser to recognise hardware features
1029463612SCraig Topper // for RISC-V CPUs.
11ac1ffd3cSFrancesco Petrogalli //
12ac1ffd3cSFrancesco Petrogalli //===----------------------------------------------------------------------===//
13ac1ffd3cSFrancesco Petrogalli 
14ac1ffd3cSFrancesco Petrogalli #include "llvm/TargetParser/RISCVTargetParser.h"
15ac1ffd3cSFrancesco Petrogalli #include "llvm/ADT/SmallVector.h"
16ac1ffd3cSFrancesco Petrogalli #include "llvm/ADT/StringSwitch.h"
17733a8778SCraig Topper #include "llvm/TargetParser/RISCVISAInfo.h"
18ac1ffd3cSFrancesco Petrogalli 
19ac1ffd3cSFrancesco Petrogalli namespace llvm {
20ac1ffd3cSFrancesco Petrogalli namespace RISCV {
21ac1ffd3cSFrancesco Petrogalli 
22fa42e7b6SCraig Topper enum CPUKind : unsigned {
2373acf8d7SCraig Topper #define PROC(ENUM, NAME, DEFAULT_MARCH, FAST_SCALAR_UNALIGN,                   \
244da960b8SPengcheng Wang              FAST_VECTOR_UNALIGN, MVENDORID, MARCHID, MIMPID)                  \
2573acf8d7SCraig Topper   CK_##ENUM,
26fa42e7b6SCraig Topper #define TUNE_PROC(ENUM, NAME) CK_##ENUM,
27fa42e7b6SCraig Topper #include "llvm/TargetParser/RISCVTargetParserDef.inc"
28fa42e7b6SCraig Topper };
29fa42e7b6SCraig Topper 
30ac1ffd3cSFrancesco Petrogalli constexpr CPUInfo RISCVCPUInfo[] = {
3173acf8d7SCraig Topper #define PROC(ENUM, NAME, DEFAULT_MARCH, FAST_SCALAR_UNALIGN,                   \
324da960b8SPengcheng Wang              FAST_VECTOR_UNALIGN, MVENDORID, MARCHID, MIMPID)                  \
334da960b8SPengcheng Wang   {                                                                            \
344da960b8SPengcheng Wang       NAME,                                                                    \
354da960b8SPengcheng Wang       DEFAULT_MARCH,                                                           \
364da960b8SPengcheng Wang       FAST_SCALAR_UNALIGN,                                                     \
374da960b8SPengcheng Wang       FAST_VECTOR_UNALIGN,                                                     \
384da960b8SPengcheng Wang       {MVENDORID, MARCHID, MIMPID},                                            \
394da960b8SPengcheng Wang   },
40ac1ffd3cSFrancesco Petrogalli #include "llvm/TargetParser/RISCVTargetParserDef.inc"
41ac1ffd3cSFrancesco Petrogalli };
42ac1ffd3cSFrancesco Petrogalli 
43ddafabeaSCraig Topper static const CPUInfo *getCPUInfoByName(StringRef CPU) {
44ddafabeaSCraig Topper   for (auto &C : RISCVCPUInfo)
45ddafabeaSCraig Topper     if (C.Name == CPU)
46ddafabeaSCraig Topper       return &C;
47ddafabeaSCraig Topper   return nullptr;
48fa42e7b6SCraig Topper }
49fa42e7b6SCraig Topper 
5073acf8d7SCraig Topper bool hasFastScalarUnalignedAccess(StringRef CPU) {
5175d6795eSYeting Kuo   const CPUInfo *Info = getCPUInfoByName(CPU);
5273acf8d7SCraig Topper   return Info && Info->FastScalarUnalignedAccess;
5373acf8d7SCraig Topper }
5473acf8d7SCraig Topper 
5573acf8d7SCraig Topper bool hasFastVectorUnalignedAccess(StringRef CPU) {
5673acf8d7SCraig Topper   const CPUInfo *Info = getCPUInfoByName(CPU);
5773acf8d7SCraig Topper   return Info && Info->FastVectorUnalignedAccess;
5875d6795eSYeting Kuo }
5975d6795eSYeting Kuo 
60*875b10f7SPengcheng Wang bool hasValidCPUModel(StringRef CPU) {
61*875b10f7SPengcheng Wang   const CPUModel Model = getCPUModel(CPU);
62*875b10f7SPengcheng Wang   return Model.MVendorID != 0 && Model.MArchID != 0 && Model.MImpID != 0;
63*875b10f7SPengcheng Wang }
64*875b10f7SPengcheng Wang 
65*875b10f7SPengcheng Wang CPUModel getCPUModel(StringRef CPU) {
66*875b10f7SPengcheng Wang   const CPUInfo *Info = getCPUInfoByName(CPU);
67*875b10f7SPengcheng Wang   if (!Info)
68*875b10f7SPengcheng Wang     return {0, 0, 0};
69*875b10f7SPengcheng Wang   return Info->Model;
70*875b10f7SPengcheng Wang }
71*875b10f7SPengcheng Wang 
72fa42e7b6SCraig Topper bool parseCPU(StringRef CPU, bool IsRV64) {
73ddafabeaSCraig Topper   const CPUInfo *Info = getCPUInfoByName(CPU);
74fa42e7b6SCraig Topper 
75ddafabeaSCraig Topper   if (!Info)
76ac1ffd3cSFrancesco Petrogalli     return false;
77ddafabeaSCraig Topper   return Info->is64Bit() == IsRV64;
78ac1ffd3cSFrancesco Petrogalli }
79ac1ffd3cSFrancesco Petrogalli 
80fa42e7b6SCraig Topper bool parseTuneCPU(StringRef TuneCPU, bool IsRV64) {
8109f6bddaSCraig Topper   std::optional<CPUKind> Kind =
8209f6bddaSCraig Topper       llvm::StringSwitch<std::optional<CPUKind>>(TuneCPU)
83fa42e7b6SCraig Topper #define TUNE_PROC(ENUM, NAME) .Case(NAME, CK_##ENUM)
84fa42e7b6SCraig Topper   #include "llvm/TargetParser/RISCVTargetParserDef.inc"
8509f6bddaSCraig Topper       .Default(std::nullopt);
86fa42e7b6SCraig Topper 
8709f6bddaSCraig Topper   if (Kind.has_value())
88ac1ffd3cSFrancesco Petrogalli     return true;
89ddafabeaSCraig Topper 
90ddafabeaSCraig Topper   // Fallback to parsing as a CPU.
91ddafabeaSCraig Topper   return parseCPU(TuneCPU, IsRV64);
92ac1ffd3cSFrancesco Petrogalli }
93ac1ffd3cSFrancesco Petrogalli 
94ac1ffd3cSFrancesco Petrogalli StringRef getMArchFromMcpu(StringRef CPU) {
95ddafabeaSCraig Topper   const CPUInfo *Info = getCPUInfoByName(CPU);
96ddafabeaSCraig Topper   if (!Info)
97ddafabeaSCraig Topper     return "";
98ddafabeaSCraig Topper   return Info->DefaultMarch;
99ac1ffd3cSFrancesco Petrogalli }
100ac1ffd3cSFrancesco Petrogalli 
101ac1ffd3cSFrancesco Petrogalli void fillValidCPUArchList(SmallVectorImpl<StringRef> &Values, bool IsRV64) {
102ac1ffd3cSFrancesco Petrogalli   for (const auto &C : RISCVCPUInfo) {
10309f6bddaSCraig Topper     if (IsRV64 == C.is64Bit())
104ac1ffd3cSFrancesco Petrogalli       Values.emplace_back(C.Name);
105ac1ffd3cSFrancesco Petrogalli   }
106ac1ffd3cSFrancesco Petrogalli }
107ac1ffd3cSFrancesco Petrogalli 
108ac1ffd3cSFrancesco Petrogalli void fillValidTuneCPUArchList(SmallVectorImpl<StringRef> &Values, bool IsRV64) {
109ac1ffd3cSFrancesco Petrogalli   for (const auto &C : RISCVCPUInfo) {
11009f6bddaSCraig Topper     if (IsRV64 == C.is64Bit())
111ac1ffd3cSFrancesco Petrogalli       Values.emplace_back(C.Name);
112ac1ffd3cSFrancesco Petrogalli   }
113ac1ffd3cSFrancesco Petrogalli #define TUNE_PROC(ENUM, NAME) Values.emplace_back(StringRef(NAME));
114ac1ffd3cSFrancesco Petrogalli #include "llvm/TargetParser/RISCVTargetParserDef.inc"
115ac1ffd3cSFrancesco Petrogalli }
116ac1ffd3cSFrancesco Petrogalli 
1178fd011ecSBrandon Wu // This function is currently used by IREE, so it's not dead code.
1188fd011ecSBrandon Wu void getFeaturesForCPU(StringRef CPU,
1198fd011ecSBrandon Wu                        SmallVectorImpl<std::string> &EnabledFeatures,
1208fd011ecSBrandon Wu                        bool NeedPlus) {
1218fd011ecSBrandon Wu   StringRef MarchFromCPU = llvm::RISCV::getMArchFromMcpu(CPU);
1228fd011ecSBrandon Wu   if (MarchFromCPU == "")
1238fd011ecSBrandon Wu     return;
1248fd011ecSBrandon Wu 
1258fd011ecSBrandon Wu   EnabledFeatures.clear();
1268fd011ecSBrandon Wu   auto RII = RISCVISAInfo::parseArchString(
1278fd011ecSBrandon Wu       MarchFromCPU, /* EnableExperimentalExtension */ true);
1288fd011ecSBrandon Wu 
1298fd011ecSBrandon Wu   if (llvm::errorToBool(RII.takeError()))
1308fd011ecSBrandon Wu     return;
1318fd011ecSBrandon Wu 
1328fd011ecSBrandon Wu   std::vector<std::string> FeatStrings =
1338fd011ecSBrandon Wu       (*RII)->toFeatures(/* AddAllExtensions */ false);
1348fd011ecSBrandon Wu   for (const auto &F : FeatStrings)
1358fd011ecSBrandon Wu     if (NeedPlus)
1368fd011ecSBrandon Wu       EnabledFeatures.push_back(F);
1378fd011ecSBrandon Wu     else
1388fd011ecSBrandon Wu       EnabledFeatures.push_back(F.substr(1));
1398fd011ecSBrandon Wu }
140f4d4ce1aSPiyou Chen 
141f4d4ce1aSPiyou Chen namespace RISCVExtensionBitmaskTable {
142f4d4ce1aSPiyou Chen #define GET_RISCVExtensionBitmaskTable_IMPL
143f4d4ce1aSPiyou Chen #include "llvm/TargetParser/RISCVTargetParserDef.inc"
144f4d4ce1aSPiyou Chen 
145f4d4ce1aSPiyou Chen } // namespace RISCVExtensionBitmaskTable
146f4d4ce1aSPiyou Chen 
147f4d4ce1aSPiyou Chen namespace {
148f4d4ce1aSPiyou Chen struct LessExtName {
149f4d4ce1aSPiyou Chen   bool operator()(const RISCVExtensionBitmaskTable::RISCVExtensionBitmask &LHS,
150f4d4ce1aSPiyou Chen                   StringRef RHS) {
151f4d4ce1aSPiyou Chen     return StringRef(LHS.Name) < RHS;
152f4d4ce1aSPiyou Chen   }
153f4d4ce1aSPiyou Chen };
154f4d4ce1aSPiyou Chen } // namespace
155f4d4ce1aSPiyou Chen 
156ac1ffd3cSFrancesco Petrogalli } // namespace RISCV
15785388a06SWang Pengcheng 
15885388a06SWang Pengcheng namespace RISCVVType {
15985388a06SWang Pengcheng // Encode VTYPE into the binary format used by the the VSETVLI instruction which
16085388a06SWang Pengcheng // is used by our MC layer representation.
16185388a06SWang Pengcheng //
16285388a06SWang Pengcheng // Bits | Name       | Description
16385388a06SWang Pengcheng // -----+------------+------------------------------------------------
16485388a06SWang Pengcheng // 7    | vma        | Vector mask agnostic
16585388a06SWang Pengcheng // 6    | vta        | Vector tail agnostic
16685388a06SWang Pengcheng // 5:3  | vsew[2:0]  | Standard element width (SEW) setting
16785388a06SWang Pengcheng // 2:0  | vlmul[2:0] | Vector register group multiplier (LMUL) setting
16885388a06SWang Pengcheng unsigned encodeVTYPE(RISCVII::VLMUL VLMUL, unsigned SEW, bool TailAgnostic,
16985388a06SWang Pengcheng                      bool MaskAgnostic) {
17085388a06SWang Pengcheng   assert(isValidSEW(SEW) && "Invalid SEW");
17185388a06SWang Pengcheng   unsigned VLMULBits = static_cast<unsigned>(VLMUL);
17285388a06SWang Pengcheng   unsigned VSEWBits = encodeSEW(SEW);
17385388a06SWang Pengcheng   unsigned VTypeI = (VSEWBits << 3) | (VLMULBits & 0x7);
17485388a06SWang Pengcheng   if (TailAgnostic)
17585388a06SWang Pengcheng     VTypeI |= 0x40;
17685388a06SWang Pengcheng   if (MaskAgnostic)
17785388a06SWang Pengcheng     VTypeI |= 0x80;
17885388a06SWang Pengcheng 
17985388a06SWang Pengcheng   return VTypeI;
18085388a06SWang Pengcheng }
18185388a06SWang Pengcheng 
18285388a06SWang Pengcheng std::pair<unsigned, bool> decodeVLMUL(RISCVII::VLMUL VLMUL) {
18385388a06SWang Pengcheng   switch (VLMUL) {
18485388a06SWang Pengcheng   default:
18585388a06SWang Pengcheng     llvm_unreachable("Unexpected LMUL value!");
18685388a06SWang Pengcheng   case RISCVII::VLMUL::LMUL_1:
18785388a06SWang Pengcheng   case RISCVII::VLMUL::LMUL_2:
18885388a06SWang Pengcheng   case RISCVII::VLMUL::LMUL_4:
18985388a06SWang Pengcheng   case RISCVII::VLMUL::LMUL_8:
19085388a06SWang Pengcheng     return std::make_pair(1 << static_cast<unsigned>(VLMUL), false);
19185388a06SWang Pengcheng   case RISCVII::VLMUL::LMUL_F2:
19285388a06SWang Pengcheng   case RISCVII::VLMUL::LMUL_F4:
19385388a06SWang Pengcheng   case RISCVII::VLMUL::LMUL_F8:
19485388a06SWang Pengcheng     return std::make_pair(1 << (8 - static_cast<unsigned>(VLMUL)), true);
19585388a06SWang Pengcheng   }
19685388a06SWang Pengcheng }
19785388a06SWang Pengcheng 
19885388a06SWang Pengcheng void printVType(unsigned VType, raw_ostream &OS) {
19985388a06SWang Pengcheng   unsigned Sew = getSEW(VType);
20085388a06SWang Pengcheng   OS << "e" << Sew;
20185388a06SWang Pengcheng 
20285388a06SWang Pengcheng   unsigned LMul;
20385388a06SWang Pengcheng   bool Fractional;
20485388a06SWang Pengcheng   std::tie(LMul, Fractional) = decodeVLMUL(getVLMUL(VType));
20585388a06SWang Pengcheng 
20685388a06SWang Pengcheng   if (Fractional)
20785388a06SWang Pengcheng     OS << ", mf";
20885388a06SWang Pengcheng   else
20985388a06SWang Pengcheng     OS << ", m";
21085388a06SWang Pengcheng   OS << LMul;
21185388a06SWang Pengcheng 
21285388a06SWang Pengcheng   if (isTailAgnostic(VType))
21385388a06SWang Pengcheng     OS << ", ta";
21485388a06SWang Pengcheng   else
21585388a06SWang Pengcheng     OS << ", tu";
21685388a06SWang Pengcheng 
21785388a06SWang Pengcheng   if (isMaskAgnostic(VType))
21885388a06SWang Pengcheng     OS << ", ma";
21985388a06SWang Pengcheng   else
22085388a06SWang Pengcheng     OS << ", mu";
22185388a06SWang Pengcheng }
22285388a06SWang Pengcheng 
22385388a06SWang Pengcheng unsigned getSEWLMULRatio(unsigned SEW, RISCVII::VLMUL VLMul) {
22485388a06SWang Pengcheng   unsigned LMul;
22585388a06SWang Pengcheng   bool Fractional;
22685388a06SWang Pengcheng   std::tie(LMul, Fractional) = decodeVLMUL(VLMul);
22785388a06SWang Pengcheng 
22885388a06SWang Pengcheng   // Convert LMul to a fixed point value with 3 fractional bits.
22985388a06SWang Pengcheng   LMul = Fractional ? (8 / LMul) : (LMul * 8);
23085388a06SWang Pengcheng 
23185388a06SWang Pengcheng   assert(SEW >= 8 && "Unexpected SEW value");
23285388a06SWang Pengcheng   return (SEW * 8) / LMul;
23385388a06SWang Pengcheng }
23485388a06SWang Pengcheng 
23585388a06SWang Pengcheng std::optional<RISCVII::VLMUL>
23685388a06SWang Pengcheng getSameRatioLMUL(unsigned SEW, RISCVII::VLMUL VLMUL, unsigned EEW) {
23785388a06SWang Pengcheng   unsigned Ratio = RISCVVType::getSEWLMULRatio(SEW, VLMUL);
23885388a06SWang Pengcheng   unsigned EMULFixedPoint = (EEW * 8) / Ratio;
23985388a06SWang Pengcheng   bool Fractional = EMULFixedPoint < 8;
24085388a06SWang Pengcheng   unsigned EMUL = Fractional ? 8 / EMULFixedPoint : EMULFixedPoint / 8;
24185388a06SWang Pengcheng   if (!isValidLMUL(EMUL, Fractional))
24285388a06SWang Pengcheng     return std::nullopt;
24385388a06SWang Pengcheng   return RISCVVType::encodeLMUL(EMUL, Fractional);
24485388a06SWang Pengcheng }
24585388a06SWang Pengcheng 
24685388a06SWang Pengcheng } // namespace RISCVVType
24785388a06SWang Pengcheng 
248ac1ffd3cSFrancesco Petrogalli } // namespace llvm
249