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

source code of llvm/lib/TargetParser/RISCVTargetParser.cpp