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