1 //===-- RISCVTargetParser.cpp - Parser for target features ------*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
9 // This file implements a target parser to recognise hardware features
12 //===----------------------------------------------------------------------===//
14 #include "llvm/TargetParser/RISCVTargetParser.h"
15 #include "llvm/ADT/SmallVector.h"
16 #include "llvm/ADT/StringSwitch.h"
17 #include "llvm/TargetParser/RISCVISAInfo.h"
22 enum CPUKind
: unsigned {
23 #define PROC(ENUM, NAME, DEFAULT_MARCH, FAST_SCALAR_UNALIGN, \
24 FAST_VECTOR_UNALIGN, MVENDORID, MARCHID, MIMPID) \
26 #define TUNE_PROC(ENUM, NAME) CK_##ENUM,
27 #include "llvm/TargetParser/RISCVTargetParserDef.inc"
30 constexpr CPUInfo RISCVCPUInfo
[] = {
31 #define PROC(ENUM, NAME, DEFAULT_MARCH, FAST_SCALAR_UNALIGN, \
32 FAST_VECTOR_UNALIGN, MVENDORID, MARCHID, MIMPID) \
36 FAST_SCALAR_UNALIGN, \
37 FAST_VECTOR_UNALIGN, \
38 {MVENDORID, MARCHID, MIMPID}, \
40 #include "llvm/TargetParser/RISCVTargetParserDef.inc"
43 static const CPUInfo
*getCPUInfoByName(StringRef CPU
) {
44 for (auto &C
: RISCVCPUInfo
)
50 bool hasFastScalarUnalignedAccess(StringRef CPU
) {
51 const CPUInfo
*Info
= getCPUInfoByName(CPU
);
52 return Info
&& Info
->FastScalarUnalignedAccess
;
55 bool hasFastVectorUnalignedAccess(StringRef CPU
) {
56 const CPUInfo
*Info
= getCPUInfoByName(CPU
);
57 return Info
&& Info
->FastVectorUnalignedAccess
;
60 bool hasValidCPUModel(StringRef CPU
) {
61 const CPUModel Model
= getCPUModel(CPU
);
62 return Model
.MVendorID
!= 0 && Model
.MArchID
!= 0 && Model
.MImpID
!= 0;
65 CPUModel
getCPUModel(StringRef CPU
) {
66 const CPUInfo
*Info
= getCPUInfoByName(CPU
);
72 bool parseCPU(StringRef CPU
, bool IsRV64
) {
73 const CPUInfo
*Info
= getCPUInfoByName(CPU
);
77 return Info
->is64Bit() == IsRV64
;
80 bool parseTuneCPU(StringRef TuneCPU
, bool IsRV64
) {
81 std::optional
<CPUKind
> Kind
=
82 llvm::StringSwitch
<std::optional
<CPUKind
>>(TuneCPU
)
83 #define TUNE_PROC(ENUM, NAME) .Case(NAME, CK_##ENUM)
84 #include "llvm/TargetParser/RISCVTargetParserDef.inc"
85 .Default(std::nullopt
);
90 // Fallback to parsing as a CPU.
91 return parseCPU(TuneCPU
, IsRV64
);
94 StringRef
getMArchFromMcpu(StringRef CPU
) {
95 const CPUInfo
*Info
= getCPUInfoByName(CPU
);
98 return Info
->DefaultMarch
;
101 void fillValidCPUArchList(SmallVectorImpl
<StringRef
> &Values
, bool IsRV64
) {
102 for (const auto &C
: RISCVCPUInfo
) {
103 if (IsRV64
== C
.is64Bit())
104 Values
.emplace_back(C
.Name
);
108 void fillValidTuneCPUArchList(SmallVectorImpl
<StringRef
> &Values
, bool IsRV64
) {
109 for (const auto &C
: RISCVCPUInfo
) {
110 if (IsRV64
== C
.is64Bit())
111 Values
.emplace_back(C
.Name
);
113 #define TUNE_PROC(ENUM, NAME) Values.emplace_back(StringRef(NAME));
114 #include "llvm/TargetParser/RISCVTargetParserDef.inc"
117 // This function is currently used by IREE, so it's not dead code.
118 void getFeaturesForCPU(StringRef CPU
,
119 SmallVectorImpl
<std::string
> &EnabledFeatures
,
121 StringRef MarchFromCPU
= llvm::RISCV::getMArchFromMcpu(CPU
);
122 if (MarchFromCPU
== "")
125 EnabledFeatures
.clear();
126 auto RII
= RISCVISAInfo::parseArchString(
127 MarchFromCPU
, /* EnableExperimentalExtension */ true);
129 if (llvm::errorToBool(RII
.takeError()))
132 std::vector
<std::string
> FeatStrings
=
133 (*RII
)->toFeatures(/* AddAllExtensions */ false);
134 for (const auto &F
: FeatStrings
)
136 EnabledFeatures
.push_back(F
);
138 EnabledFeatures
.push_back(F
.substr(1));
141 namespace RISCVExtensionBitmaskTable
{
142 #define GET_RISCVExtensionBitmaskTable_IMPL
143 #include "llvm/TargetParser/RISCVTargetParserDef.inc"
145 } // namespace RISCVExtensionBitmaskTable
149 bool operator()(const RISCVExtensionBitmaskTable::RISCVExtensionBitmask
&LHS
,
151 return StringRef(LHS
.Name
) < RHS
;
158 namespace RISCVVType
{
159 // Encode VTYPE into the binary format used by the the VSETVLI instruction which
160 // is used by our MC layer representation.
162 // Bits | Name | Description
163 // -----+------------+------------------------------------------------
164 // 7 | vma | Vector mask agnostic
165 // 6 | vta | Vector tail agnostic
166 // 5:3 | vsew[2:0] | Standard element width (SEW) setting
167 // 2:0 | vlmul[2:0] | Vector register group multiplier (LMUL) setting
168 unsigned encodeVTYPE(RISCVII::VLMUL VLMUL
, unsigned SEW
, bool TailAgnostic
,
170 assert(isValidSEW(SEW
) && "Invalid SEW");
171 unsigned VLMULBits
= static_cast<unsigned>(VLMUL
);
172 unsigned VSEWBits
= encodeSEW(SEW
);
173 unsigned VTypeI
= (VSEWBits
<< 3) | (VLMULBits
& 0x7);
182 std::pair
<unsigned, bool> decodeVLMUL(RISCVII::VLMUL VLMUL
) {
185 llvm_unreachable("Unexpected LMUL value!");
186 case RISCVII::VLMUL::LMUL_1
:
187 case RISCVII::VLMUL::LMUL_2
:
188 case RISCVII::VLMUL::LMUL_4
:
189 case RISCVII::VLMUL::LMUL_8
:
190 return std::make_pair(1 << static_cast<unsigned>(VLMUL
), false);
191 case RISCVII::VLMUL::LMUL_F2
:
192 case RISCVII::VLMUL::LMUL_F4
:
193 case RISCVII::VLMUL::LMUL_F8
:
194 return std::make_pair(1 << (8 - static_cast<unsigned>(VLMUL
)), true);
198 void printVType(unsigned VType
, raw_ostream
&OS
) {
199 unsigned Sew
= getSEW(VType
);
204 std::tie(LMul
, Fractional
) = decodeVLMUL(getVLMUL(VType
));
212 if (isTailAgnostic(VType
))
217 if (isMaskAgnostic(VType
))
223 unsigned getSEWLMULRatio(unsigned SEW
, RISCVII::VLMUL VLMul
) {
226 std::tie(LMul
, Fractional
) = decodeVLMUL(VLMul
);
228 // Convert LMul to a fixed point value with 3 fractional bits.
229 LMul
= Fractional
? (8 / LMul
) : (LMul
* 8);
231 assert(SEW
>= 8 && "Unexpected SEW value");
232 return (SEW
* 8) / LMul
;
235 std::optional
<RISCVII::VLMUL
>
236 getSameRatioLMUL(unsigned SEW
, RISCVII::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
))
243 return RISCVVType::encodeLMUL(EMUL
, Fractional
);
246 } // namespace RISCVVType