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
getCPUInfoByName(StringRef CPU)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
hasFastScalarUnalignedAccess(StringRef CPU)50 bool hasFastScalarUnalignedAccess(StringRef CPU) {
51 const CPUInfo *Info = getCPUInfoByName(CPU);
52 return Info && Info->FastScalarUnalignedAccess;
53 }
54
hasFastVectorUnalignedAccess(StringRef CPU)55 bool hasFastVectorUnalignedAccess(StringRef CPU) {
56 const CPUInfo *Info = getCPUInfoByName(CPU);
57 return Info && Info->FastVectorUnalignedAccess;
58 }
59
hasValidCPUModel(StringRef CPU)60 bool hasValidCPUModel(StringRef CPU) { return getCPUModel(CPU).isValid(); }
61
getCPUModel(StringRef CPU)62 CPUModel getCPUModel(StringRef CPU) {
63 const CPUInfo *Info = getCPUInfoByName(CPU);
64 if (!Info)
65 return {0, 0, 0};
66 return Info->Model;
67 }
68
getCPUNameFromCPUModel(const CPUModel & Model)69 StringRef getCPUNameFromCPUModel(const CPUModel &Model) {
70 if (!Model.isValid())
71 return "";
72
73 for (auto &C : RISCVCPUInfo)
74 if (C.Model == Model)
75 return C.Name;
76 return "";
77 }
78
parseCPU(StringRef CPU,bool IsRV64)79 bool parseCPU(StringRef CPU, bool IsRV64) {
80 const CPUInfo *Info = getCPUInfoByName(CPU);
81
82 if (!Info)
83 return false;
84 return Info->is64Bit() == IsRV64;
85 }
86
parseTuneCPU(StringRef TuneCPU,bool IsRV64)87 bool parseTuneCPU(StringRef TuneCPU, bool IsRV64) {
88 std::optional<CPUKind> Kind =
89 llvm::StringSwitch<std::optional<CPUKind>>(TuneCPU)
90 #define TUNE_PROC(ENUM, NAME) .Case(NAME, CK_##ENUM)
91 #include "llvm/TargetParser/RISCVTargetParserDef.inc"
92 .Default(std::nullopt);
93
94 if (Kind.has_value())
95 return true;
96
97 // Fallback to parsing as a CPU.
98 return parseCPU(TuneCPU, IsRV64);
99 }
100
getMArchFromMcpu(StringRef CPU)101 StringRef getMArchFromMcpu(StringRef CPU) {
102 const CPUInfo *Info = getCPUInfoByName(CPU);
103 if (!Info)
104 return "";
105 return Info->DefaultMarch;
106 }
107
fillValidCPUArchList(SmallVectorImpl<StringRef> & Values,bool IsRV64)108 void fillValidCPUArchList(SmallVectorImpl<StringRef> &Values, bool IsRV64) {
109 for (const auto &C : RISCVCPUInfo) {
110 if (IsRV64 == C.is64Bit())
111 Values.emplace_back(C.Name);
112 }
113 }
114
fillValidTuneCPUArchList(SmallVectorImpl<StringRef> & Values,bool IsRV64)115 void fillValidTuneCPUArchList(SmallVectorImpl<StringRef> &Values, bool IsRV64) {
116 for (const auto &C : RISCVCPUInfo) {
117 if (IsRV64 == C.is64Bit())
118 Values.emplace_back(C.Name);
119 }
120 #define TUNE_PROC(ENUM, NAME) Values.emplace_back(StringRef(NAME));
121 #include "llvm/TargetParser/RISCVTargetParserDef.inc"
122 }
123
124 // This function is currently used by IREE, so it's not dead code.
getFeaturesForCPU(StringRef CPU,SmallVectorImpl<std::string> & EnabledFeatures,bool NeedPlus)125 void getFeaturesForCPU(StringRef CPU,
126 SmallVectorImpl<std::string> &EnabledFeatures,
127 bool NeedPlus) {
128 StringRef MarchFromCPU = llvm::RISCV::getMArchFromMcpu(CPU);
129 if (MarchFromCPU == "")
130 return;
131
132 EnabledFeatures.clear();
133 auto RII = RISCVISAInfo::parseArchString(
134 MarchFromCPU, /* EnableExperimentalExtension */ true);
135
136 if (llvm::errorToBool(RII.takeError()))
137 return;
138
139 std::vector<std::string> FeatStrings =
140 (*RII)->toFeatures(/* AddAllExtensions */ false);
141 for (const auto &F : FeatStrings)
142 if (NeedPlus)
143 EnabledFeatures.push_back(F);
144 else
145 EnabledFeatures.push_back(F.substr(1));
146 }
147
148 } // namespace RISCV
149
150 namespace RISCVVType {
151 // Encode VTYPE into the binary format used by the the VSETVLI instruction which
152 // is used by our MC layer representation.
153 //
154 // Bits | Name | Description
155 // -----+------------+------------------------------------------------
156 // 7 | vma | Vector mask agnostic
157 // 6 | vta | Vector tail agnostic
158 // 5:3 | vsew[2:0] | Standard element width (SEW) setting
159 // 2:0 | vlmul[2:0] | Vector register group multiplier (LMUL) setting
encodeVTYPE(VLMUL VLMul,unsigned SEW,bool TailAgnostic,bool MaskAgnostic)160 unsigned encodeVTYPE(VLMUL VLMul, unsigned SEW, bool TailAgnostic,
161 bool MaskAgnostic) {
162 assert(isValidSEW(SEW) && "Invalid SEW");
163 unsigned VLMulBits = static_cast<unsigned>(VLMul);
164 unsigned VSEWBits = encodeSEW(SEW);
165 unsigned VTypeI = (VSEWBits << 3) | (VLMulBits & 0x7);
166 if (TailAgnostic)
167 VTypeI |= 0x40;
168 if (MaskAgnostic)
169 VTypeI |= 0x80;
170
171 return VTypeI;
172 }
173
encodeXSfmmVType(unsigned SEW,unsigned Widen,bool AltFmt)174 unsigned encodeXSfmmVType(unsigned SEW, unsigned Widen, bool AltFmt) {
175 assert(isValidSEW(SEW) && "Invalid SEW");
176 assert((Widen == 1 || Widen == 2 || Widen == 4) && "Invalid Widen");
177 unsigned VSEWBits = encodeSEW(SEW);
178 unsigned TWiden = Log2_32(Widen) + 1;
179 unsigned VTypeI = (VSEWBits << 3) | AltFmt << 8 | TWiden << 9;
180 return VTypeI;
181 }
182
decodeVLMUL(VLMUL VLMul)183 std::pair<unsigned, bool> decodeVLMUL(VLMUL VLMul) {
184 switch (VLMul) {
185 default:
186 llvm_unreachable("Unexpected LMUL value!");
187 case LMUL_1:
188 case LMUL_2:
189 case LMUL_4:
190 case LMUL_8:
191 return std::make_pair(1 << static_cast<unsigned>(VLMul), false);
192 case LMUL_F2:
193 case LMUL_F4:
194 case LMUL_F8:
195 return std::make_pair(1 << (8 - static_cast<unsigned>(VLMul)), true);
196 }
197 }
198
printVType(unsigned VType,raw_ostream & OS)199 void printVType(unsigned VType, raw_ostream &OS) {
200 unsigned Sew = getSEW(VType);
201 OS << "e" << Sew;
202
203 unsigned LMul;
204 bool Fractional;
205 std::tie(LMul, Fractional) = decodeVLMUL(getVLMUL(VType));
206
207 if (Fractional)
208 OS << ", mf";
209 else
210 OS << ", m";
211 OS << LMul;
212
213 if (isTailAgnostic(VType))
214 OS << ", ta";
215 else
216 OS << ", tu";
217
218 if (isMaskAgnostic(VType))
219 OS << ", ma";
220 else
221 OS << ", mu";
222 }
223
getSEWLMULRatio(unsigned SEW,VLMUL VLMul)224 unsigned getSEWLMULRatio(unsigned SEW, VLMUL VLMul) {
225 unsigned LMul;
226 bool Fractional;
227 std::tie(LMul, Fractional) = decodeVLMUL(VLMul);
228
229 // Convert LMul to a fixed point value with 3 fractional bits.
230 LMul = Fractional ? (8 / LMul) : (LMul * 8);
231
232 assert(SEW >= 8 && "Unexpected SEW value");
233 return (SEW * 8) / LMul;
234 }
235
getSameRatioLMUL(unsigned SEW,VLMUL VLMul,unsigned EEW)236 std::optional<VLMUL> getSameRatioLMUL(unsigned SEW, 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