xref: /freebsd-src/contrib/llvm-project/llvm/lib/TargetParser/RISCVTargetParser.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
1bdd1243dSDimitry Andric //===-- RISCVTargetParser.cpp - Parser for target features ------*- C++ -*-===//
2bdd1243dSDimitry Andric //
3bdd1243dSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4bdd1243dSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5bdd1243dSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6bdd1243dSDimitry Andric //
7bdd1243dSDimitry Andric //===----------------------------------------------------------------------===//
8bdd1243dSDimitry Andric //
9bdd1243dSDimitry Andric // This file implements a target parser to recognise hardware features
1006c3fb27SDimitry Andric // for RISC-V CPUs.
11bdd1243dSDimitry Andric //
12bdd1243dSDimitry Andric //===----------------------------------------------------------------------===//
13bdd1243dSDimitry Andric 
14bdd1243dSDimitry Andric #include "llvm/TargetParser/RISCVTargetParser.h"
15bdd1243dSDimitry Andric #include "llvm/ADT/SmallVector.h"
16bdd1243dSDimitry Andric #include "llvm/ADT/StringSwitch.h"
17*0fca6ea1SDimitry Andric #include "llvm/TargetParser/RISCVISAInfo.h"
181ac55f4cSDimitry Andric #include "llvm/TargetParser/Triple.h"
19bdd1243dSDimitry Andric 
20bdd1243dSDimitry Andric namespace llvm {
21bdd1243dSDimitry Andric namespace RISCV {
22bdd1243dSDimitry Andric 
2306c3fb27SDimitry Andric enum CPUKind : unsigned {
24*0fca6ea1SDimitry Andric #define PROC(ENUM, NAME, DEFAULT_MARCH, FAST_SCALAR_UNALIGN,                   \
25*0fca6ea1SDimitry Andric              FAST_VECTOR_UNALIGN)                                              \
26*0fca6ea1SDimitry Andric   CK_##ENUM,
2706c3fb27SDimitry Andric #define TUNE_PROC(ENUM, NAME) CK_##ENUM,
2806c3fb27SDimitry Andric #include "llvm/TargetParser/RISCVTargetParserDef.inc"
2906c3fb27SDimitry Andric };
3006c3fb27SDimitry Andric 
31bdd1243dSDimitry Andric struct CPUInfo {
32bdd1243dSDimitry Andric   StringLiteral Name;
33bdd1243dSDimitry Andric   StringLiteral DefaultMarch;
34*0fca6ea1SDimitry Andric   bool FastScalarUnalignedAccess;
35*0fca6ea1SDimitry Andric   bool FastVectorUnalignedAccess;
36bdd1243dSDimitry Andric   bool is64Bit() const { return DefaultMarch.starts_with("rv64"); }
37bdd1243dSDimitry Andric };
38bdd1243dSDimitry Andric 
39bdd1243dSDimitry Andric constexpr CPUInfo RISCVCPUInfo[] = {
40*0fca6ea1SDimitry Andric #define PROC(ENUM, NAME, DEFAULT_MARCH, FAST_SCALAR_UNALIGN,                   \
41*0fca6ea1SDimitry Andric              FAST_VECTOR_UNALIGN)                                              \
42*0fca6ea1SDimitry Andric   {NAME, DEFAULT_MARCH, FAST_SCALAR_UNALIGN, FAST_VECTOR_UNALIGN},
43bdd1243dSDimitry Andric #include "llvm/TargetParser/RISCVTargetParserDef.inc"
44bdd1243dSDimitry Andric };
45bdd1243dSDimitry Andric 
4606c3fb27SDimitry Andric static const CPUInfo *getCPUInfoByName(StringRef CPU) {
4706c3fb27SDimitry Andric   for (auto &C : RISCVCPUInfo)
4806c3fb27SDimitry Andric     if (C.Name == CPU)
4906c3fb27SDimitry Andric       return &C;
5006c3fb27SDimitry Andric   return nullptr;
5106c3fb27SDimitry Andric }
5206c3fb27SDimitry Andric 
53*0fca6ea1SDimitry Andric bool hasFastScalarUnalignedAccess(StringRef CPU) {
545f757f3fSDimitry Andric   const CPUInfo *Info = getCPUInfoByName(CPU);
55*0fca6ea1SDimitry Andric   return Info && Info->FastScalarUnalignedAccess;
56*0fca6ea1SDimitry Andric }
57*0fca6ea1SDimitry Andric 
58*0fca6ea1SDimitry Andric bool hasFastVectorUnalignedAccess(StringRef CPU) {
59*0fca6ea1SDimitry Andric   const CPUInfo *Info = getCPUInfoByName(CPU);
60*0fca6ea1SDimitry Andric   return Info && Info->FastVectorUnalignedAccess;
615f757f3fSDimitry Andric }
625f757f3fSDimitry Andric 
6306c3fb27SDimitry Andric bool parseCPU(StringRef CPU, bool IsRV64) {
6406c3fb27SDimitry Andric   const CPUInfo *Info = getCPUInfoByName(CPU);
6506c3fb27SDimitry Andric 
6606c3fb27SDimitry Andric   if (!Info)
67bdd1243dSDimitry Andric     return false;
6806c3fb27SDimitry Andric   return Info->is64Bit() == IsRV64;
69bdd1243dSDimitry Andric }
70bdd1243dSDimitry Andric 
7106c3fb27SDimitry Andric bool parseTuneCPU(StringRef TuneCPU, bool IsRV64) {
7206c3fb27SDimitry Andric   std::optional<CPUKind> Kind =
7306c3fb27SDimitry Andric       llvm::StringSwitch<std::optional<CPUKind>>(TuneCPU)
74bdd1243dSDimitry Andric #define TUNE_PROC(ENUM, NAME) .Case(NAME, CK_##ENUM)
75bdd1243dSDimitry Andric   #include "llvm/TargetParser/RISCVTargetParserDef.inc"
7606c3fb27SDimitry Andric       .Default(std::nullopt);
7706c3fb27SDimitry Andric 
7806c3fb27SDimitry Andric   if (Kind.has_value())
7906c3fb27SDimitry Andric     return true;
8006c3fb27SDimitry Andric 
8106c3fb27SDimitry Andric   // Fallback to parsing as a CPU.
8206c3fb27SDimitry Andric   return parseCPU(TuneCPU, IsRV64);
83bdd1243dSDimitry Andric }
84bdd1243dSDimitry Andric 
85bdd1243dSDimitry Andric StringRef getMArchFromMcpu(StringRef CPU) {
8606c3fb27SDimitry Andric   const CPUInfo *Info = getCPUInfoByName(CPU);
8706c3fb27SDimitry Andric   if (!Info)
8806c3fb27SDimitry Andric     return "";
8906c3fb27SDimitry Andric   return Info->DefaultMarch;
90bdd1243dSDimitry Andric }
91bdd1243dSDimitry Andric 
92bdd1243dSDimitry Andric void fillValidCPUArchList(SmallVectorImpl<StringRef> &Values, bool IsRV64) {
93bdd1243dSDimitry Andric   for (const auto &C : RISCVCPUInfo) {
9406c3fb27SDimitry Andric     if (IsRV64 == C.is64Bit())
95bdd1243dSDimitry Andric       Values.emplace_back(C.Name);
96bdd1243dSDimitry Andric   }
97bdd1243dSDimitry Andric }
98bdd1243dSDimitry Andric 
99bdd1243dSDimitry Andric void fillValidTuneCPUArchList(SmallVectorImpl<StringRef> &Values, bool IsRV64) {
100bdd1243dSDimitry Andric   for (const auto &C : RISCVCPUInfo) {
10106c3fb27SDimitry Andric     if (IsRV64 == C.is64Bit())
102bdd1243dSDimitry Andric       Values.emplace_back(C.Name);
103bdd1243dSDimitry Andric   }
104bdd1243dSDimitry Andric #define TUNE_PROC(ENUM, NAME) Values.emplace_back(StringRef(NAME));
105bdd1243dSDimitry Andric #include "llvm/TargetParser/RISCVTargetParserDef.inc"
106bdd1243dSDimitry Andric }
107bdd1243dSDimitry Andric 
108*0fca6ea1SDimitry Andric // This function is currently used by IREE, so it's not dead code.
109*0fca6ea1SDimitry Andric void getFeaturesForCPU(StringRef CPU,
110*0fca6ea1SDimitry Andric                        SmallVectorImpl<std::string> &EnabledFeatures,
111*0fca6ea1SDimitry Andric                        bool NeedPlus) {
112*0fca6ea1SDimitry Andric   StringRef MarchFromCPU = llvm::RISCV::getMArchFromMcpu(CPU);
113*0fca6ea1SDimitry Andric   if (MarchFromCPU == "")
114*0fca6ea1SDimitry Andric     return;
115*0fca6ea1SDimitry Andric 
116*0fca6ea1SDimitry Andric   EnabledFeatures.clear();
117*0fca6ea1SDimitry Andric   auto RII = RISCVISAInfo::parseArchString(
118*0fca6ea1SDimitry Andric       MarchFromCPU, /* EnableExperimentalExtension */ true);
119*0fca6ea1SDimitry Andric 
120*0fca6ea1SDimitry Andric   if (llvm::errorToBool(RII.takeError()))
121*0fca6ea1SDimitry Andric     return;
122*0fca6ea1SDimitry Andric 
123*0fca6ea1SDimitry Andric   std::vector<std::string> FeatStrings =
124*0fca6ea1SDimitry Andric       (*RII)->toFeatures(/* AddAllExtensions */ false);
125*0fca6ea1SDimitry Andric   for (const auto &F : FeatStrings)
126*0fca6ea1SDimitry Andric     if (NeedPlus)
127*0fca6ea1SDimitry Andric       EnabledFeatures.push_back(F);
128*0fca6ea1SDimitry Andric     else
129*0fca6ea1SDimitry Andric       EnabledFeatures.push_back(F.substr(1));
130*0fca6ea1SDimitry Andric }
131*0fca6ea1SDimitry Andric 
132*0fca6ea1SDimitry Andric namespace RISCVExtensionBitmaskTable {
133*0fca6ea1SDimitry Andric #define GET_RISCVExtensionBitmaskTable_IMPL
134*0fca6ea1SDimitry Andric #include "llvm/TargetParser/RISCVTargetParserDef.inc"
135*0fca6ea1SDimitry Andric 
136*0fca6ea1SDimitry Andric } // namespace RISCVExtensionBitmaskTable
137*0fca6ea1SDimitry Andric 
138*0fca6ea1SDimitry Andric namespace {
139*0fca6ea1SDimitry Andric struct LessExtName {
140*0fca6ea1SDimitry Andric   bool operator()(const RISCVExtensionBitmaskTable::RISCVExtensionBitmask &LHS,
141*0fca6ea1SDimitry Andric                   StringRef RHS) {
142*0fca6ea1SDimitry Andric     return StringRef(LHS.Name) < RHS;
143*0fca6ea1SDimitry Andric   }
144*0fca6ea1SDimitry Andric };
145*0fca6ea1SDimitry Andric } // namespace
146*0fca6ea1SDimitry Andric 
147bdd1243dSDimitry Andric } // namespace RISCV
148*0fca6ea1SDimitry Andric 
149*0fca6ea1SDimitry Andric namespace RISCVVType {
150*0fca6ea1SDimitry Andric // Encode VTYPE into the binary format used by the the VSETVLI instruction which
151*0fca6ea1SDimitry Andric // is used by our MC layer representation.
152*0fca6ea1SDimitry Andric //
153*0fca6ea1SDimitry Andric // Bits | Name       | Description
154*0fca6ea1SDimitry Andric // -----+------------+------------------------------------------------
155*0fca6ea1SDimitry Andric // 7    | vma        | Vector mask agnostic
156*0fca6ea1SDimitry Andric // 6    | vta        | Vector tail agnostic
157*0fca6ea1SDimitry Andric // 5:3  | vsew[2:0]  | Standard element width (SEW) setting
158*0fca6ea1SDimitry Andric // 2:0  | vlmul[2:0] | Vector register group multiplier (LMUL) setting
159*0fca6ea1SDimitry Andric unsigned encodeVTYPE(RISCVII::VLMUL VLMUL, unsigned SEW, bool TailAgnostic,
160*0fca6ea1SDimitry Andric                      bool MaskAgnostic) {
161*0fca6ea1SDimitry Andric   assert(isValidSEW(SEW) && "Invalid SEW");
162*0fca6ea1SDimitry Andric   unsigned VLMULBits = static_cast<unsigned>(VLMUL);
163*0fca6ea1SDimitry Andric   unsigned VSEWBits = encodeSEW(SEW);
164*0fca6ea1SDimitry Andric   unsigned VTypeI = (VSEWBits << 3) | (VLMULBits & 0x7);
165*0fca6ea1SDimitry Andric   if (TailAgnostic)
166*0fca6ea1SDimitry Andric     VTypeI |= 0x40;
167*0fca6ea1SDimitry Andric   if (MaskAgnostic)
168*0fca6ea1SDimitry Andric     VTypeI |= 0x80;
169*0fca6ea1SDimitry Andric 
170*0fca6ea1SDimitry Andric   return VTypeI;
171*0fca6ea1SDimitry Andric }
172*0fca6ea1SDimitry Andric 
173*0fca6ea1SDimitry Andric std::pair<unsigned, bool> decodeVLMUL(RISCVII::VLMUL VLMUL) {
174*0fca6ea1SDimitry Andric   switch (VLMUL) {
175*0fca6ea1SDimitry Andric   default:
176*0fca6ea1SDimitry Andric     llvm_unreachable("Unexpected LMUL value!");
177*0fca6ea1SDimitry Andric   case RISCVII::VLMUL::LMUL_1:
178*0fca6ea1SDimitry Andric   case RISCVII::VLMUL::LMUL_2:
179*0fca6ea1SDimitry Andric   case RISCVII::VLMUL::LMUL_4:
180*0fca6ea1SDimitry Andric   case RISCVII::VLMUL::LMUL_8:
181*0fca6ea1SDimitry Andric     return std::make_pair(1 << static_cast<unsigned>(VLMUL), false);
182*0fca6ea1SDimitry Andric   case RISCVII::VLMUL::LMUL_F2:
183*0fca6ea1SDimitry Andric   case RISCVII::VLMUL::LMUL_F4:
184*0fca6ea1SDimitry Andric   case RISCVII::VLMUL::LMUL_F8:
185*0fca6ea1SDimitry Andric     return std::make_pair(1 << (8 - static_cast<unsigned>(VLMUL)), true);
186*0fca6ea1SDimitry Andric   }
187*0fca6ea1SDimitry Andric }
188*0fca6ea1SDimitry Andric 
189*0fca6ea1SDimitry Andric void printVType(unsigned VType, raw_ostream &OS) {
190*0fca6ea1SDimitry Andric   unsigned Sew = getSEW(VType);
191*0fca6ea1SDimitry Andric   OS << "e" << Sew;
192*0fca6ea1SDimitry Andric 
193*0fca6ea1SDimitry Andric   unsigned LMul;
194*0fca6ea1SDimitry Andric   bool Fractional;
195*0fca6ea1SDimitry Andric   std::tie(LMul, Fractional) = decodeVLMUL(getVLMUL(VType));
196*0fca6ea1SDimitry Andric 
197*0fca6ea1SDimitry Andric   if (Fractional)
198*0fca6ea1SDimitry Andric     OS << ", mf";
199*0fca6ea1SDimitry Andric   else
200*0fca6ea1SDimitry Andric     OS << ", m";
201*0fca6ea1SDimitry Andric   OS << LMul;
202*0fca6ea1SDimitry Andric 
203*0fca6ea1SDimitry Andric   if (isTailAgnostic(VType))
204*0fca6ea1SDimitry Andric     OS << ", ta";
205*0fca6ea1SDimitry Andric   else
206*0fca6ea1SDimitry Andric     OS << ", tu";
207*0fca6ea1SDimitry Andric 
208*0fca6ea1SDimitry Andric   if (isMaskAgnostic(VType))
209*0fca6ea1SDimitry Andric     OS << ", ma";
210*0fca6ea1SDimitry Andric   else
211*0fca6ea1SDimitry Andric     OS << ", mu";
212*0fca6ea1SDimitry Andric }
213*0fca6ea1SDimitry Andric 
214*0fca6ea1SDimitry Andric unsigned getSEWLMULRatio(unsigned SEW, RISCVII::VLMUL VLMul) {
215*0fca6ea1SDimitry Andric   unsigned LMul;
216*0fca6ea1SDimitry Andric   bool Fractional;
217*0fca6ea1SDimitry Andric   std::tie(LMul, Fractional) = decodeVLMUL(VLMul);
218*0fca6ea1SDimitry Andric 
219*0fca6ea1SDimitry Andric   // Convert LMul to a fixed point value with 3 fractional bits.
220*0fca6ea1SDimitry Andric   LMul = Fractional ? (8 / LMul) : (LMul * 8);
221*0fca6ea1SDimitry Andric 
222*0fca6ea1SDimitry Andric   assert(SEW >= 8 && "Unexpected SEW value");
223*0fca6ea1SDimitry Andric   return (SEW * 8) / LMul;
224*0fca6ea1SDimitry Andric }
225*0fca6ea1SDimitry Andric 
226*0fca6ea1SDimitry Andric std::optional<RISCVII::VLMUL>
227*0fca6ea1SDimitry Andric getSameRatioLMUL(unsigned SEW, RISCVII::VLMUL VLMUL, unsigned EEW) {
228*0fca6ea1SDimitry Andric   unsigned Ratio = RISCVVType::getSEWLMULRatio(SEW, VLMUL);
229*0fca6ea1SDimitry Andric   unsigned EMULFixedPoint = (EEW * 8) / Ratio;
230*0fca6ea1SDimitry Andric   bool Fractional = EMULFixedPoint < 8;
231*0fca6ea1SDimitry Andric   unsigned EMUL = Fractional ? 8 / EMULFixedPoint : EMULFixedPoint / 8;
232*0fca6ea1SDimitry Andric   if (!isValidLMUL(EMUL, Fractional))
233*0fca6ea1SDimitry Andric     return std::nullopt;
234*0fca6ea1SDimitry Andric   return RISCVVType::encodeLMUL(EMUL, Fractional);
235*0fca6ea1SDimitry Andric }
236*0fca6ea1SDimitry Andric 
237*0fca6ea1SDimitry Andric } // namespace RISCVVType
238*0fca6ea1SDimitry Andric 
239bdd1243dSDimitry Andric } // namespace llvm
240