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