xref: /llvm-project/llvm/lib/TargetParser/RISCVTargetParser.cpp (revision 875b10f7d0888ca7e53f527f4c30531bd6b50bfb)
1 //===-- RISCVTargetParser.cpp - Parser for target features ------*- 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-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file implements a target parser to recognise hardware features
10 // for RISC-V CPUs.
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #include "llvm/TargetParser/RISCVTargetParser.h"
15 #include "llvm/ADT/SmallVector.h"
16 #include "llvm/ADT/StringSwitch.h"
17 #include "llvm/TargetParser/RISCVISAInfo.h"
18 
19 namespace llvm {
20 namespace RISCV {
21 
22 enum CPUKind : unsigned {
23 #define PROC(ENUM, NAME, DEFAULT_MARCH, FAST_SCALAR_UNALIGN,                   \
24              FAST_VECTOR_UNALIGN, MVENDORID, MARCHID, MIMPID)                  \
25   CK_##ENUM,
26 #define TUNE_PROC(ENUM, NAME) CK_##ENUM,
27 #include "llvm/TargetParser/RISCVTargetParserDef.inc"
28 };
29 
30 constexpr CPUInfo RISCVCPUInfo[] = {
31 #define PROC(ENUM, NAME, DEFAULT_MARCH, FAST_SCALAR_UNALIGN,                   \
32              FAST_VECTOR_UNALIGN, MVENDORID, MARCHID, MIMPID)                  \
33   {                                                                            \
34       NAME,                                                                    \
35       DEFAULT_MARCH,                                                           \
36       FAST_SCALAR_UNALIGN,                                                     \
37       FAST_VECTOR_UNALIGN,                                                     \
38       {MVENDORID, MARCHID, MIMPID},                                            \
39   },
40 #include "llvm/TargetParser/RISCVTargetParserDef.inc"
41 };
42 
43 static const CPUInfo *getCPUInfoByName(StringRef CPU) {
44   for (auto &C : RISCVCPUInfo)
45     if (C.Name == CPU)
46       return &C;
47   return nullptr;
48 }
49 
50 bool hasFastScalarUnalignedAccess(StringRef CPU) {
51   const CPUInfo *Info = getCPUInfoByName(CPU);
52   return Info && Info->FastScalarUnalignedAccess;
53 }
54 
55 bool hasFastVectorUnalignedAccess(StringRef CPU) {
56   const CPUInfo *Info = getCPUInfoByName(CPU);
57   return Info && Info->FastVectorUnalignedAccess;
58 }
59 
60 bool hasValidCPUModel(StringRef CPU) {
61   const CPUModel Model = getCPUModel(CPU);
62   return Model.MVendorID != 0 && Model.MArchID != 0 && Model.MImpID != 0;
63 }
64 
65 CPUModel getCPUModel(StringRef CPU) {
66   const CPUInfo *Info = getCPUInfoByName(CPU);
67   if (!Info)
68     return {0, 0, 0};
69   return Info->Model;
70 }
71 
72 bool parseCPU(StringRef CPU, bool IsRV64) {
73   const CPUInfo *Info = getCPUInfoByName(CPU);
74 
75   if (!Info)
76     return false;
77   return Info->is64Bit() == IsRV64;
78 }
79 
80 bool parseTuneCPU(StringRef TuneCPU, bool IsRV64) {
81   std::optional<CPUKind> Kind =
82       llvm::StringSwitch<std::optional<CPUKind>>(TuneCPU)
83 #define TUNE_PROC(ENUM, NAME) .Case(NAME, CK_##ENUM)
84   #include "llvm/TargetParser/RISCVTargetParserDef.inc"
85       .Default(std::nullopt);
86 
87   if (Kind.has_value())
88     return true;
89 
90   // Fallback to parsing as a CPU.
91   return parseCPU(TuneCPU, IsRV64);
92 }
93 
94 StringRef getMArchFromMcpu(StringRef CPU) {
95   const CPUInfo *Info = getCPUInfoByName(CPU);
96   if (!Info)
97     return "";
98   return Info->DefaultMarch;
99 }
100 
101 void fillValidCPUArchList(SmallVectorImpl<StringRef> &Values, bool IsRV64) {
102   for (const auto &C : RISCVCPUInfo) {
103     if (IsRV64 == C.is64Bit())
104       Values.emplace_back(C.Name);
105   }
106 }
107 
108 void fillValidTuneCPUArchList(SmallVectorImpl<StringRef> &Values, bool IsRV64) {
109   for (const auto &C : RISCVCPUInfo) {
110     if (IsRV64 == C.is64Bit())
111       Values.emplace_back(C.Name);
112   }
113 #define TUNE_PROC(ENUM, NAME) Values.emplace_back(StringRef(NAME));
114 #include "llvm/TargetParser/RISCVTargetParserDef.inc"
115 }
116 
117 // This function is currently used by IREE, so it's not dead code.
118 void getFeaturesForCPU(StringRef CPU,
119                        SmallVectorImpl<std::string> &EnabledFeatures,
120                        bool NeedPlus) {
121   StringRef MarchFromCPU = llvm::RISCV::getMArchFromMcpu(CPU);
122   if (MarchFromCPU == "")
123     return;
124 
125   EnabledFeatures.clear();
126   auto RII = RISCVISAInfo::parseArchString(
127       MarchFromCPU, /* EnableExperimentalExtension */ true);
128 
129   if (llvm::errorToBool(RII.takeError()))
130     return;
131 
132   std::vector<std::string> FeatStrings =
133       (*RII)->toFeatures(/* AddAllExtensions */ false);
134   for (const auto &F : FeatStrings)
135     if (NeedPlus)
136       EnabledFeatures.push_back(F);
137     else
138       EnabledFeatures.push_back(F.substr(1));
139 }
140 
141 namespace RISCVExtensionBitmaskTable {
142 #define GET_RISCVExtensionBitmaskTable_IMPL
143 #include "llvm/TargetParser/RISCVTargetParserDef.inc"
144 
145 } // namespace RISCVExtensionBitmaskTable
146 
147 namespace {
148 struct LessExtName {
149   bool operator()(const RISCVExtensionBitmaskTable::RISCVExtensionBitmask &LHS,
150                   StringRef RHS) {
151     return StringRef(LHS.Name) < RHS;
152   }
153 };
154 } // namespace
155 
156 } // namespace RISCV
157 
158 namespace RISCVVType {
159 // Encode VTYPE into the binary format used by the the VSETVLI instruction which
160 // is used by our MC layer representation.
161 //
162 // Bits | Name       | Description
163 // -----+------------+------------------------------------------------
164 // 7    | vma        | Vector mask agnostic
165 // 6    | vta        | Vector tail agnostic
166 // 5:3  | vsew[2:0]  | Standard element width (SEW) setting
167 // 2:0  | vlmul[2:0] | Vector register group multiplier (LMUL) setting
168 unsigned encodeVTYPE(RISCVII::VLMUL VLMUL, unsigned SEW, bool TailAgnostic,
169                      bool MaskAgnostic) {
170   assert(isValidSEW(SEW) && "Invalid SEW");
171   unsigned VLMULBits = static_cast<unsigned>(VLMUL);
172   unsigned VSEWBits = encodeSEW(SEW);
173   unsigned VTypeI = (VSEWBits << 3) | (VLMULBits & 0x7);
174   if (TailAgnostic)
175     VTypeI |= 0x40;
176   if (MaskAgnostic)
177     VTypeI |= 0x80;
178 
179   return VTypeI;
180 }
181 
182 std::pair<unsigned, bool> decodeVLMUL(RISCVII::VLMUL VLMUL) {
183   switch (VLMUL) {
184   default:
185     llvm_unreachable("Unexpected LMUL value!");
186   case RISCVII::VLMUL::LMUL_1:
187   case RISCVII::VLMUL::LMUL_2:
188   case RISCVII::VLMUL::LMUL_4:
189   case RISCVII::VLMUL::LMUL_8:
190     return std::make_pair(1 << static_cast<unsigned>(VLMUL), false);
191   case RISCVII::VLMUL::LMUL_F2:
192   case RISCVII::VLMUL::LMUL_F4:
193   case RISCVII::VLMUL::LMUL_F8:
194     return std::make_pair(1 << (8 - static_cast<unsigned>(VLMUL)), true);
195   }
196 }
197 
198 void printVType(unsigned VType, raw_ostream &OS) {
199   unsigned Sew = getSEW(VType);
200   OS << "e" << Sew;
201 
202   unsigned LMul;
203   bool Fractional;
204   std::tie(LMul, Fractional) = decodeVLMUL(getVLMUL(VType));
205 
206   if (Fractional)
207     OS << ", mf";
208   else
209     OS << ", m";
210   OS << LMul;
211 
212   if (isTailAgnostic(VType))
213     OS << ", ta";
214   else
215     OS << ", tu";
216 
217   if (isMaskAgnostic(VType))
218     OS << ", ma";
219   else
220     OS << ", mu";
221 }
222 
223 unsigned getSEWLMULRatio(unsigned SEW, RISCVII::VLMUL VLMul) {
224   unsigned LMul;
225   bool Fractional;
226   std::tie(LMul, Fractional) = decodeVLMUL(VLMul);
227 
228   // Convert LMul to a fixed point value with 3 fractional bits.
229   LMul = Fractional ? (8 / LMul) : (LMul * 8);
230 
231   assert(SEW >= 8 && "Unexpected SEW value");
232   return (SEW * 8) / LMul;
233 }
234 
235 std::optional<RISCVII::VLMUL>
236 getSameRatioLMUL(unsigned SEW, RISCVII::VLMUL VLMUL, unsigned EEW) {
237   unsigned Ratio = RISCVVType::getSEWLMULRatio(SEW, VLMUL);
238   unsigned EMULFixedPoint = (EEW * 8) / Ratio;
239   bool Fractional = EMULFixedPoint < 8;
240   unsigned EMUL = Fractional ? 8 / EMULFixedPoint : EMULFixedPoint / 8;
241   if (!isValidLMUL(EMUL, Fractional))
242     return std::nullopt;
243   return RISCVVType::encodeLMUL(EMUL, Fractional);
244 }
245 
246 } // namespace RISCVVType
247 
248 } // namespace llvm
249