LLVM 23.0.0git
RISCVTargetParser.cpp
Go to the documentation of this file.
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
16#include "llvm/ADT/SmallSet.h"
22
23namespace llvm {
24namespace RISCV {
25
26char ParserError::ID = 0;
27char ParserWarning::ID = 0;
28
29enum CPUKind : unsigned {
30#define PROC(ENUM, NAME, DEFAULT_MARCH, FAST_SCALAR_UNALIGN, \
31 FAST_VECTOR_UNALIGN, MVENDORID, MARCHID, MIMPID) \
32 CK_##ENUM,
33#define TUNE_PROC(ENUM, NAME) CK_##ENUM,
34#include "llvm/TargetParser/RISCVTargetParserDef.inc"
35};
36
37constexpr CPUInfo RISCVCPUInfo[] = {
38#define PROC(ENUM, NAME, DEFAULT_MARCH, FAST_SCALAR_UNALIGN, \
39 FAST_VECTOR_UNALIGN, MVENDORID, MARCHID, MIMPID) \
40 { \
41 NAME, \
42 DEFAULT_MARCH, \
43 FAST_SCALAR_UNALIGN, \
44 FAST_VECTOR_UNALIGN, \
45 {MVENDORID, MARCHID, MIMPID}, \
46 },
47#include "llvm/TargetParser/RISCVTargetParserDef.inc"
48};
49
51 for (auto &C : RISCVCPUInfo)
52 if (C.Name == CPU)
53 return &C;
54 return nullptr;
55}
56
58 const CPUInfo *Info = getCPUInfoByName(CPU);
59 return Info && Info->FastScalarUnalignedAccess;
60}
61
63 const CPUInfo *Info = getCPUInfoByName(CPU);
64 return Info && Info->FastVectorUnalignedAccess;
65}
66
67bool hasValidCPUModel(StringRef CPU) { return getCPUModel(CPU).isValid(); }
68
70 const CPUInfo *Info = getCPUInfoByName(CPU);
71 if (!Info)
72 return {0, 0, 0};
73 return Info->Model;
74}
75
77 if (!Model.isValid())
78 return "";
79
80 for (auto &C : RISCVCPUInfo)
81 if (C.Model == Model)
82 return C.Name;
83 return "";
84}
85
86bool parseCPU(StringRef CPU, bool IsRV64) {
87 const CPUInfo *Info = getCPUInfoByName(CPU);
88
89 if (!Info)
90 return false;
91 return Info->is64Bit() == IsRV64;
92}
93
94bool parseTuneCPU(StringRef TuneCPU, bool IsRV64) {
95 std::optional<CPUKind> Kind =
97#define TUNE_PROC(ENUM, NAME) .Case(NAME, CK_##ENUM)
98 #include "llvm/TargetParser/RISCVTargetParserDef.inc"
99 .Default(std::nullopt);
100
101 if (Kind.has_value())
102 return true;
103
104 // Fallback to parsing as a CPU.
105 return parseCPU(TuneCPU, IsRV64);
106}
107
109 const CPUInfo *Info = getCPUInfoByName(CPU);
110 if (!Info)
111 return "";
112 return Info->DefaultMarch;
113}
114
116 for (const auto &C : RISCVCPUInfo) {
117 if (IsRV64 == C.is64Bit())
118 Values.emplace_back(C.Name);
119 }
120}
121
123 for (const auto &C : RISCVCPUInfo) {
124 if (IsRV64 == C.is64Bit())
125 Values.emplace_back(C.Name);
126 }
127#define TUNE_PROC(ENUM, NAME) Values.emplace_back(StringRef(NAME));
128#include "llvm/TargetParser/RISCVTargetParserDef.inc"
129}
130
131// This function is currently used by IREE, so it's not dead code.
133 SmallVectorImpl<std::string> &EnabledFeatures,
134 bool NeedPlus) {
135 StringRef MarchFromCPU = llvm::RISCV::getMArchFromMcpu(CPU);
136 if (MarchFromCPU == "")
137 return;
138
139 EnabledFeatures.clear();
141 MarchFromCPU, /* EnableExperimentalExtension */ true);
142
143 if (llvm::errorToBool(RII.takeError()))
144 return;
145
146 std::vector<std::string> FeatStrings =
147 (*RII)->toFeatures(/* AddAllExtensions */ false);
148 for (const auto &F : FeatStrings)
149 if (NeedPlus)
150 EnabledFeatures.push_back(F);
151 else
152 EnabledFeatures.push_back(F.substr(1));
153}
154
155namespace {
156class RISCVTuneFeatureLookupTable {
157 struct RISCVTuneFeature {
158 unsigned PosIdx;
159 unsigned NegIdx;
160 unsigned FeatureIdx;
161 };
162
163 struct RISCVImpliedTuneFeature {
164 unsigned FeatureIdx;
165 unsigned ImpliedFeatureIdx;
166 };
167
168 struct RISCVConfigurableTuneFeatures {
169 StringRef Processor;
170 unsigned DirectiveIdx;
171
172 bool operator<(const RISCVConfigurableTuneFeatures &RHS) const {
173 return Processor < RHS.Processor;
174 }
175 };
176
177#define GET_TUNE_FEATURES
178#define GET_CONFIGURABLE_TUNE_FEATURES
179#include "llvm/TargetParser/RISCVTargetParserDef.inc"
180
181 // Positive directive name -> Feature name
182 StringMap<StringRef> PositiveMap;
183 // Negative directive name -> Feature name
184 StringMap<StringRef> NegativeMap;
185
186 StringMap<SmallVector<StringRef>> ImpliedFeatureMap;
187 StringMap<SmallVector<StringRef>> InvImpliedFeatureMap;
188
189public:
190 using SmallStringSet = SmallSet<StringRef, 4>;
191
192 static void getAllTuneFeatures(SmallVectorImpl<StringRef> &Features) {
193 for (const auto &TuneFeature : TuneFeatures)
194 Features.push_back(TuneFeatureStrings[TuneFeature.FeatureIdx]);
195 }
196
197 static void getConfigurableFeatures(StringRef ProcName,
198 SmallStringSet &Directives) {
199 // Entries for the same processor are always put together.
200 auto [ItFirst, ItEnd] =
201 std::equal_range(std::begin(ConfigurableTuneFeatures),
202 std::end(ConfigurableTuneFeatures),
203 RISCVConfigurableTuneFeatures{ProcName, 0});
204 for (; ItFirst != ItEnd; ++ItFirst)
205 Directives.insert(TuneFeatureStrings[ItFirst->DirectiveIdx]);
206 }
207
208 RISCVTuneFeatureLookupTable() {
209 for (const auto &TuneFeature : TuneFeatures) {
210 StringRef PosDirective = TuneFeatureStrings[TuneFeature.PosIdx];
211 StringRef NegDirective = TuneFeatureStrings[TuneFeature.NegIdx];
212 StringRef FeatureName = TuneFeatureStrings[TuneFeature.FeatureIdx];
213 PositiveMap[PosDirective] = FeatureName;
214 NegativeMap[NegDirective] = FeatureName;
215 }
216
217 for (const auto &Imp : ImpliedTuneFeatures) {
218 StringRef Feature = TuneFeatureStrings[Imp.FeatureIdx];
219 StringRef ImpliedFeature = TuneFeatureStrings[Imp.ImpliedFeatureIdx];
220 ImpliedFeatureMap[Feature].push_back(ImpliedFeature);
221 InvImpliedFeatureMap[ImpliedFeature].push_back(Feature);
222 }
223 }
224
225 /// Returns {Feature name, Is positive or not}, or empty feature name
226 /// if not found.
227 std::pair<StringRef, bool> getFeature(StringRef DirectiveName) const {
228 auto It = PositiveMap.find(DirectiveName);
229 if (It != PositiveMap.end())
230 return {It->getValue(), /*IsPositive=*/true};
231
232 return {NegativeMap.lookup(DirectiveName), /*IsPositive=*/false};
233 }
234
235 /// Returns the implied features, or empty ArrayRef if not found. Note:
236 /// ImpliedFeatureMap / InvImpliedFeatureMap are the owners of these implied
237 /// feature lists, so we can just return the ArrayRef.
238 ArrayRef<StringRef> featureImplies(StringRef FeatureName,
239 bool Inverse = false) const {
240 const auto &Map = Inverse ? InvImpliedFeatureMap : ImpliedFeatureMap;
241 auto It = Map.find(FeatureName);
242 if (It == Map.end())
243 return {};
244 return It->second;
245 }
246};
247} // namespace
248
250 RISCVTuneFeatureLookupTable::getAllTuneFeatures(Features);
251}
252
254 SmallVectorImpl<std::string> &ResFeatures) {
255 RISCVTuneFeatureLookupTable TFLookup;
256 using SmallStringSet = RISCVTuneFeatureLookupTable::SmallStringSet;
257
258 // Do not create ParserWarning right away. Instead, we store the warning
259 // message until the last moment.
260 std::string WarningMsg;
261
262 TFString = TFString.trim();
263 if (TFString.empty())
264 return Error::success();
265
266 // Note: StringSet is not really ergonomic to use in this case here.
267 SmallStringSet PositiveFeatures;
268 SmallStringSet NegativeFeatures;
269 SmallStringSet PerProcDirectives;
270 RISCVTuneFeatureLookupTable::getConfigurableFeatures(ProcName,
271 PerProcDirectives);
272 if (PerProcDirectives.empty() && !ProcName.empty())
273 return make_error<ParserError>("Processor '" + Twine(ProcName) +
274 "' has no "
275 "configurable tuning features");
276
277 // Phase 1: Collect explicit features.
278 StringRef DirectiveStr;
279 do {
280 std::tie(DirectiveStr, TFString) = TFString.split(",");
281 auto [FeatureName, IsPositive] = TFLookup.getFeature(DirectiveStr);
282 if (FeatureName.empty()) {
283 raw_string_ostream SS(WarningMsg);
284 SS << "unrecognized tune feature directive '" << DirectiveStr << "'";
285 continue;
286 }
287
288 auto &Features = IsPositive ? PositiveFeatures : NegativeFeatures;
289 if (!Features.insert(FeatureName).second)
291 "cannot specify more than one instance of '" + Twine(DirectiveStr) +
292 "'");
293
294 if (!PerProcDirectives.count(DirectiveStr) && !ProcName.empty())
295 return make_error<ParserError>("Directive '" + Twine(DirectiveStr) +
296 "' is not "
297 "allowed to be used with processor '" +
298 Twine(ProcName) + "'");
299 } while (!TFString.empty());
300
301 auto Intersection =
302 llvm::set_intersection(PositiveFeatures, NegativeFeatures);
303 if (!Intersection.empty()) {
304 std::string IntersectedStr = join(Intersection, "', '");
305 return make_error<ParserError>("Feature(s) '" + Twine(IntersectedStr) +
306 "' cannot appear in both "
307 "positive and negative directives");
308 }
309
310 // Phase 2: Derive implied features.
311 SmallStringSet DerivedPosFeatures;
312 SmallStringSet DerivedNegFeatures;
313 for (StringRef PF : PositiveFeatures) {
314 if (auto FeatureList = TFLookup.featureImplies(PF); !FeatureList.empty())
315 DerivedPosFeatures.insert_range(FeatureList);
316 }
317 for (StringRef NF : NegativeFeatures) {
318 if (auto FeatureList = TFLookup.featureImplies(NF, /*Inverse=*/true);
319 !FeatureList.empty())
320 DerivedNegFeatures.insert_range(FeatureList);
321 }
322 PositiveFeatures.insert_range(DerivedPosFeatures);
323 NegativeFeatures.insert_range(DerivedNegFeatures);
324
325 Intersection = llvm::set_intersection(PositiveFeatures, NegativeFeatures);
326 if (!Intersection.empty()) {
327 std::string IntersectedStr = join(Intersection, "', '");
328 return make_error<ParserError>("Feature(s) '" + Twine(IntersectedStr) +
329 "' were implied by both "
330 "positive and negative directives");
331 }
332
333 // Export the result.
334 const std::string PosPrefix("+");
335 const std::string NegPrefix("-");
336 for (StringRef PF : PositiveFeatures)
337 ResFeatures.emplace_back(PosPrefix + PF.str());
338 for (StringRef NF : NegativeFeatures)
339 ResFeatures.emplace_back(NegPrefix + NF.str());
340
341 if (WarningMsg.empty())
342 return Error::success();
343
344 return make_error<ParserWarning>(WarningMsg);
345}
346
348 SmallVectorImpl<StringRef> &Directives) {
349 RISCVTuneFeatureLookupTable::SmallStringSet DirectiveSet;
350 RISCVTuneFeatureLookupTable::getConfigurableFeatures(CPU, DirectiveSet);
351 Directives.assign(DirectiveSet.begin(), DirectiveSet.end());
352}
353} // namespace RISCV
354
355namespace RISCVVType {
356// Encode VTYPE into the binary format used by the the VSETVLI instruction which
357// is used by our MC layer representation.
358//
359// Bits | Name | Description
360// -----+------------+------------------------------------------------
361// 8 | altfmt | Alternative format for bf16/ofp8
362// 7 | vma | Vector mask agnostic
363// 6 | vta | Vector tail agnostic
364// 5:3 | vsew[2:0] | Standard element width (SEW) setting
365// 2:0 | vlmul[2:0] | Vector register group multiplier (LMUL) setting
366unsigned encodeVTYPE(VLMUL VLMul, unsigned SEW, bool TailAgnostic,
367 bool MaskAgnostic, bool AltFmt) {
368 assert(isValidSEW(SEW) && "Invalid SEW");
369 unsigned VLMulBits = static_cast<unsigned>(VLMul);
370 unsigned VSEWBits = encodeSEW(SEW);
371 unsigned VTypeI = (VSEWBits << 3) | (VLMulBits & 0x7);
372 if (TailAgnostic)
373 VTypeI |= 0x40;
374 if (MaskAgnostic)
375 VTypeI |= 0x80;
376 if (AltFmt)
377 VTypeI |= 0x100;
378
379 return VTypeI;
380}
381
382unsigned encodeXSfmmVType(unsigned SEW, unsigned Widen, bool AltFmt) {
383 assert(isValidSEW(SEW) && "Invalid SEW");
384 assert((Widen == 1 || Widen == 2 || Widen == 4) && "Invalid Widen");
385 unsigned VSEWBits = encodeSEW(SEW);
386 unsigned TWiden = Log2_32(Widen) + 1;
387 unsigned VTypeI = (VSEWBits << 3) | AltFmt << 8 | TWiden << 9;
388 return VTypeI;
389}
390
391std::pair<unsigned, bool> decodeVLMUL(VLMUL VLMul) {
392 switch (VLMul) {
393 default:
394 llvm_unreachable("Unexpected LMUL value!");
395 case LMUL_1:
396 case LMUL_2:
397 case LMUL_4:
398 case LMUL_8:
399 return std::make_pair(1 << static_cast<unsigned>(VLMul), false);
400 case LMUL_F2:
401 case LMUL_F4:
402 case LMUL_F8:
403 return std::make_pair(1 << (8 - static_cast<unsigned>(VLMul)), true);
404 }
405}
406
407void printVType(unsigned VType, raw_ostream &OS) {
408 unsigned Sew = getSEW(VType);
409 OS << "e" << Sew;
410
411 bool AltFmt = RISCVVType::isAltFmt(VType);
412 if (AltFmt)
413 OS << "alt";
414
415 unsigned LMul;
416 bool Fractional;
417 std::tie(LMul, Fractional) = decodeVLMUL(getVLMUL(VType));
418
419 if (Fractional)
420 OS << ", mf";
421 else
422 OS << ", m";
423 OS << LMul;
424
425 if (isTailAgnostic(VType))
426 OS << ", ta";
427 else
428 OS << ", tu";
429
430 if (isMaskAgnostic(VType))
431 OS << ", ma";
432 else
433 OS << ", mu";
434}
435
436void printXSfmmVType(unsigned VType, raw_ostream &OS) {
437 OS << "e" << getSEW(VType) << ", w" << getXSfmmWiden(VType);
438}
439
440unsigned getSEWLMULRatio(unsigned SEW, VLMUL VLMul) {
441 unsigned LMul;
442 bool Fractional;
443 std::tie(LMul, Fractional) = decodeVLMUL(VLMul);
444
445 // Convert LMul to a fixed point value with 3 fractional bits.
446 LMul = Fractional ? (8 / LMul) : (LMul * 8);
447
448 assert(SEW >= 8 && "Unexpected SEW value");
449 return (SEW * 8) / LMul;
450}
451
452std::optional<VLMUL> getSameRatioLMUL(unsigned Ratio, unsigned EEW) {
453 unsigned EMULFixedPoint = (EEW * 8) / Ratio;
454 bool Fractional = EMULFixedPoint < 8;
455 unsigned EMUL = Fractional ? 8 / EMULFixedPoint : EMULFixedPoint / 8;
456 if (!isValidLMUL(EMUL, Fractional))
457 return std::nullopt;
458 return RISCVVType::encodeLMUL(EMUL, Fractional);
459}
460
461} // namespace RISCVVType
462
463} // namespace llvm
static SDValue Widen(SelectionDAG *CurDAG, SDValue N)
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
#define ENUM(Name,...)
Definition ClauseT.h:60
#define F(x, y, z)
Definition MD5.cpp:54
#define TUNE_PROC(ENUM, NAME)
This file defines generic set operations that may be used on set's of different types,...
This file defines the SmallSet class.
This file defines the SmallVector class.
This file contains some functions that are useful when dealing with strings.
This file implements the StringSwitch template, which mimics a switch() statement whose cases are str...
Value * RHS
Lightweight error class with error context and mandatory checking.
Definition Error.h:159
static ErrorSuccess success()
Create a success value.
Definition Error.h:336
static LLVM_ABI llvm::Expected< std::unique_ptr< RISCVISAInfo > > parseArchString(StringRef Arch, bool EnableExperimentalExtension, bool ExperimentalExtensionVersionCheck=true)
Parse RISC-V ISA info from arch string.
const_iterator begin() const
Definition SmallSet.h:216
const_iterator end() const
Definition SmallSet.h:222
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
void assign(size_type NumElts, ValueParamT Elt)
reference emplace_back(ArgTypes &&... Args)
void push_back(const T &Elt)
StringRef - Represent a constant reference to a string, i.e.
Definition StringRef.h:55
std::pair< StringRef, StringRef > split(char Separator) const
Split into two substrings around the first occurrence of a separator character.
Definition StringRef.h:730
constexpr bool empty() const
empty - Check if the string is empty.
Definition StringRef.h:140
StringRef trim(char Char) const
Return string with consecutive Char characters starting from the left and right removed.
Definition StringRef.h:844
A switch()-like statement whose cases are string literals.
StringSwitch & Case(StringLiteral S, T Value)
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
Definition Twine.h:82
This class implements an extremely fast bulk output stream that can only output to a stream.
Definition raw_ostream.h:53
A raw_ostream that writes to an std::string.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
@ C
The default llvm calling convention, compatible with C.
Definition CallingConv.h:34
static bool isTailAgnostic(unsigned VType)
static VLMUL encodeLMUL(unsigned LMUL, bool Fractional)
LLVM_ABI void printXSfmmVType(unsigned VType, raw_ostream &OS)
LLVM_ABI unsigned encodeXSfmmVType(unsigned SEW, unsigned Widen, bool AltFmt)
static unsigned getXSfmmWiden(unsigned VType)
static bool isValidLMUL(unsigned LMUL, bool Fractional)
LLVM_ABI std::optional< VLMUL > getSameRatioLMUL(unsigned Ratio, unsigned EEW)
static bool isMaskAgnostic(unsigned VType)
LLVM_ABI std::pair< unsigned, bool > decodeVLMUL(VLMUL VLMul)
static unsigned encodeSEW(unsigned SEW)
LLVM_ABI unsigned getSEWLMULRatio(unsigned SEW, VLMUL VLMul)
static bool isValidSEW(unsigned SEW)
LLVM_ABI void printVType(unsigned VType, raw_ostream &OS)
static bool isAltFmt(unsigned VType)
LLVM_ABI unsigned encodeVTYPE(VLMUL VLMUL, unsigned SEW, bool TailAgnostic, bool MaskAgnostic, bool AltFmt=false)
static unsigned getSEW(unsigned VType)
static VLMUL getVLMUL(unsigned VType)
LLVM_ABI bool hasFastVectorUnalignedAccess(StringRef CPU)
LLVM_ABI void getFeaturesForCPU(StringRef CPU, SmallVectorImpl< std::string > &EnabledFeatures, bool NeedPlus=false)
LLVM_ABI void fillValidTuneCPUArchList(SmallVectorImpl< StringRef > &Values, bool IsRV64)
static const CPUInfo * getCPUInfoByName(StringRef CPU)
constexpr CPUInfo RISCVCPUInfo[]
LLVM_ABI CPUModel getCPUModel(StringRef CPU)
LLVM_ABI Error parseTuneFeatureString(StringRef ProcName, StringRef TFString, SmallVectorImpl< std::string > &TuneFeatures)
Parse the tune feature string with the respective processor.
LLVM_ABI void getAllTuneFeatures(SmallVectorImpl< StringRef > &TuneFeatures)
LLVM_ABI StringRef getMArchFromMcpu(StringRef CPU)
LLVM_ABI bool parseCPU(StringRef CPU, bool IsRV64)
LLVM_ABI bool hasFastScalarUnalignedAccess(StringRef CPU)
LLVM_ABI bool hasValidCPUModel(StringRef CPU)
LLVM_ABI StringRef getCPUNameFromCPUModel(const CPUModel &Model)
LLVM_ABI bool parseTuneCPU(StringRef CPU, bool IsRV64)
LLVM_ABI void fillValidCPUArchList(SmallVectorImpl< StringRef > &Values, bool IsRV64)
LLVM_ABI void getCPUConfigurableTuneFeatures(StringRef CPU, SmallVectorImpl< StringRef > &Directives)
This is an optimization pass for GlobalISel generic memory operations.
Definition Types.h:26
bool errorToBool(Error Err)
Helper for converting an Error to a bool.
Definition Error.h:1113
bool operator<(int64_t V1, const APSInt &V2)
Definition APSInt.h:360
unsigned Log2_32(uint32_t Value)
Return the floor log base 2 of the specified value, -1 if the value is zero.
Definition MathExtras.h:331
S1Ty set_intersection(const S1Ty &S1, const S2Ty &S2)
set_intersection(A, B) - Return A ^ B
Error make_error(ArgTs &&... Args)
Make a Error instance representing failure using the given error info type.
Definition Error.h:340
std::string join(IteratorT Begin, IteratorT End, StringRef Separator)
Joins the strings in the range [Begin, End), adding Separator between the elements.
ArrayRef(const T &OneElt) -> ArrayRef< T >