1ac1ffd3cSFrancesco Petrogalli //===-- RISCVTargetParser.cpp - Parser for target features ------*- C++ -*-===// 2ac1ffd3cSFrancesco Petrogalli // 3ac1ffd3cSFrancesco Petrogalli // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4ac1ffd3cSFrancesco Petrogalli // See https://llvm.org/LICENSE.txt for license information. 5ac1ffd3cSFrancesco Petrogalli // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6ac1ffd3cSFrancesco Petrogalli // 7ac1ffd3cSFrancesco Petrogalli //===----------------------------------------------------------------------===// 8ac1ffd3cSFrancesco Petrogalli // 9ac1ffd3cSFrancesco Petrogalli // This file implements a target parser to recognise hardware features 1029463612SCraig Topper // for RISC-V CPUs. 11ac1ffd3cSFrancesco Petrogalli // 12ac1ffd3cSFrancesco Petrogalli //===----------------------------------------------------------------------===// 13ac1ffd3cSFrancesco Petrogalli 14ac1ffd3cSFrancesco Petrogalli #include "llvm/TargetParser/RISCVTargetParser.h" 15ac1ffd3cSFrancesco Petrogalli #include "llvm/ADT/SmallVector.h" 16ac1ffd3cSFrancesco Petrogalli #include "llvm/ADT/StringSwitch.h" 17733a8778SCraig Topper #include "llvm/TargetParser/RISCVISAInfo.h" 18ac1ffd3cSFrancesco Petrogalli 19ac1ffd3cSFrancesco Petrogalli namespace llvm { 20ac1ffd3cSFrancesco Petrogalli namespace RISCV { 21ac1ffd3cSFrancesco Petrogalli 22fa42e7b6SCraig Topper enum CPUKind : unsigned { 2373acf8d7SCraig Topper #define PROC(ENUM, NAME, DEFAULT_MARCH, FAST_SCALAR_UNALIGN, \ 244da960b8SPengcheng Wang FAST_VECTOR_UNALIGN, MVENDORID, MARCHID, MIMPID) \ 2573acf8d7SCraig Topper CK_##ENUM, 26fa42e7b6SCraig Topper #define TUNE_PROC(ENUM, NAME) CK_##ENUM, 27fa42e7b6SCraig Topper #include "llvm/TargetParser/RISCVTargetParserDef.inc" 28fa42e7b6SCraig Topper }; 29fa42e7b6SCraig Topper 30ac1ffd3cSFrancesco Petrogalli constexpr CPUInfo RISCVCPUInfo[] = { 3173acf8d7SCraig Topper #define PROC(ENUM, NAME, DEFAULT_MARCH, FAST_SCALAR_UNALIGN, \ 324da960b8SPengcheng Wang FAST_VECTOR_UNALIGN, MVENDORID, MARCHID, MIMPID) \ 334da960b8SPengcheng Wang { \ 344da960b8SPengcheng Wang NAME, \ 354da960b8SPengcheng Wang DEFAULT_MARCH, \ 364da960b8SPengcheng Wang FAST_SCALAR_UNALIGN, \ 374da960b8SPengcheng Wang FAST_VECTOR_UNALIGN, \ 384da960b8SPengcheng Wang {MVENDORID, MARCHID, MIMPID}, \ 394da960b8SPengcheng Wang }, 40ac1ffd3cSFrancesco Petrogalli #include "llvm/TargetParser/RISCVTargetParserDef.inc" 41ac1ffd3cSFrancesco Petrogalli }; 42ac1ffd3cSFrancesco Petrogalli 43ddafabeaSCraig Topper static const CPUInfo *getCPUInfoByName(StringRef CPU) { 44ddafabeaSCraig Topper for (auto &C : RISCVCPUInfo) 45ddafabeaSCraig Topper if (C.Name == CPU) 46ddafabeaSCraig Topper return &C; 47ddafabeaSCraig Topper return nullptr; 48fa42e7b6SCraig Topper } 49fa42e7b6SCraig Topper 5073acf8d7SCraig Topper bool hasFastScalarUnalignedAccess(StringRef CPU) { 5175d6795eSYeting Kuo const CPUInfo *Info = getCPUInfoByName(CPU); 5273acf8d7SCraig Topper return Info && Info->FastScalarUnalignedAccess; 5373acf8d7SCraig Topper } 5473acf8d7SCraig Topper 5573acf8d7SCraig Topper bool hasFastVectorUnalignedAccess(StringRef CPU) { 5673acf8d7SCraig Topper const CPUInfo *Info = getCPUInfoByName(CPU); 5773acf8d7SCraig Topper return Info && Info->FastVectorUnalignedAccess; 5875d6795eSYeting Kuo } 5975d6795eSYeting Kuo 60*875b10f7SPengcheng Wang bool hasValidCPUModel(StringRef CPU) { 61*875b10f7SPengcheng Wang const CPUModel Model = getCPUModel(CPU); 62*875b10f7SPengcheng Wang return Model.MVendorID != 0 && Model.MArchID != 0 && Model.MImpID != 0; 63*875b10f7SPengcheng Wang } 64*875b10f7SPengcheng Wang 65*875b10f7SPengcheng Wang CPUModel getCPUModel(StringRef CPU) { 66*875b10f7SPengcheng Wang const CPUInfo *Info = getCPUInfoByName(CPU); 67*875b10f7SPengcheng Wang if (!Info) 68*875b10f7SPengcheng Wang return {0, 0, 0}; 69*875b10f7SPengcheng Wang return Info->Model; 70*875b10f7SPengcheng Wang } 71*875b10f7SPengcheng Wang 72fa42e7b6SCraig Topper bool parseCPU(StringRef CPU, bool IsRV64) { 73ddafabeaSCraig Topper const CPUInfo *Info = getCPUInfoByName(CPU); 74fa42e7b6SCraig Topper 75ddafabeaSCraig Topper if (!Info) 76ac1ffd3cSFrancesco Petrogalli return false; 77ddafabeaSCraig Topper return Info->is64Bit() == IsRV64; 78ac1ffd3cSFrancesco Petrogalli } 79ac1ffd3cSFrancesco Petrogalli 80fa42e7b6SCraig Topper bool parseTuneCPU(StringRef TuneCPU, bool IsRV64) { 8109f6bddaSCraig Topper std::optional<CPUKind> Kind = 8209f6bddaSCraig Topper llvm::StringSwitch<std::optional<CPUKind>>(TuneCPU) 83fa42e7b6SCraig Topper #define TUNE_PROC(ENUM, NAME) .Case(NAME, CK_##ENUM) 84fa42e7b6SCraig Topper #include "llvm/TargetParser/RISCVTargetParserDef.inc" 8509f6bddaSCraig Topper .Default(std::nullopt); 86fa42e7b6SCraig Topper 8709f6bddaSCraig Topper if (Kind.has_value()) 88ac1ffd3cSFrancesco Petrogalli return true; 89ddafabeaSCraig Topper 90ddafabeaSCraig Topper // Fallback to parsing as a CPU. 91ddafabeaSCraig Topper return parseCPU(TuneCPU, IsRV64); 92ac1ffd3cSFrancesco Petrogalli } 93ac1ffd3cSFrancesco Petrogalli 94ac1ffd3cSFrancesco Petrogalli StringRef getMArchFromMcpu(StringRef CPU) { 95ddafabeaSCraig Topper const CPUInfo *Info = getCPUInfoByName(CPU); 96ddafabeaSCraig Topper if (!Info) 97ddafabeaSCraig Topper return ""; 98ddafabeaSCraig Topper return Info->DefaultMarch; 99ac1ffd3cSFrancesco Petrogalli } 100ac1ffd3cSFrancesco Petrogalli 101ac1ffd3cSFrancesco Petrogalli void fillValidCPUArchList(SmallVectorImpl<StringRef> &Values, bool IsRV64) { 102ac1ffd3cSFrancesco Petrogalli for (const auto &C : RISCVCPUInfo) { 10309f6bddaSCraig Topper if (IsRV64 == C.is64Bit()) 104ac1ffd3cSFrancesco Petrogalli Values.emplace_back(C.Name); 105ac1ffd3cSFrancesco Petrogalli } 106ac1ffd3cSFrancesco Petrogalli } 107ac1ffd3cSFrancesco Petrogalli 108ac1ffd3cSFrancesco Petrogalli void fillValidTuneCPUArchList(SmallVectorImpl<StringRef> &Values, bool IsRV64) { 109ac1ffd3cSFrancesco Petrogalli for (const auto &C : RISCVCPUInfo) { 11009f6bddaSCraig Topper if (IsRV64 == C.is64Bit()) 111ac1ffd3cSFrancesco Petrogalli Values.emplace_back(C.Name); 112ac1ffd3cSFrancesco Petrogalli } 113ac1ffd3cSFrancesco Petrogalli #define TUNE_PROC(ENUM, NAME) Values.emplace_back(StringRef(NAME)); 114ac1ffd3cSFrancesco Petrogalli #include "llvm/TargetParser/RISCVTargetParserDef.inc" 115ac1ffd3cSFrancesco Petrogalli } 116ac1ffd3cSFrancesco Petrogalli 1178fd011ecSBrandon Wu // This function is currently used by IREE, so it's not dead code. 1188fd011ecSBrandon Wu void getFeaturesForCPU(StringRef CPU, 1198fd011ecSBrandon Wu SmallVectorImpl<std::string> &EnabledFeatures, 1208fd011ecSBrandon Wu bool NeedPlus) { 1218fd011ecSBrandon Wu StringRef MarchFromCPU = llvm::RISCV::getMArchFromMcpu(CPU); 1228fd011ecSBrandon Wu if (MarchFromCPU == "") 1238fd011ecSBrandon Wu return; 1248fd011ecSBrandon Wu 1258fd011ecSBrandon Wu EnabledFeatures.clear(); 1268fd011ecSBrandon Wu auto RII = RISCVISAInfo::parseArchString( 1278fd011ecSBrandon Wu MarchFromCPU, /* EnableExperimentalExtension */ true); 1288fd011ecSBrandon Wu 1298fd011ecSBrandon Wu if (llvm::errorToBool(RII.takeError())) 1308fd011ecSBrandon Wu return; 1318fd011ecSBrandon Wu 1328fd011ecSBrandon Wu std::vector<std::string> FeatStrings = 1338fd011ecSBrandon Wu (*RII)->toFeatures(/* AddAllExtensions */ false); 1348fd011ecSBrandon Wu for (const auto &F : FeatStrings) 1358fd011ecSBrandon Wu if (NeedPlus) 1368fd011ecSBrandon Wu EnabledFeatures.push_back(F); 1378fd011ecSBrandon Wu else 1388fd011ecSBrandon Wu EnabledFeatures.push_back(F.substr(1)); 1398fd011ecSBrandon Wu } 140f4d4ce1aSPiyou Chen 141f4d4ce1aSPiyou Chen namespace RISCVExtensionBitmaskTable { 142f4d4ce1aSPiyou Chen #define GET_RISCVExtensionBitmaskTable_IMPL 143f4d4ce1aSPiyou Chen #include "llvm/TargetParser/RISCVTargetParserDef.inc" 144f4d4ce1aSPiyou Chen 145f4d4ce1aSPiyou Chen } // namespace RISCVExtensionBitmaskTable 146f4d4ce1aSPiyou Chen 147f4d4ce1aSPiyou Chen namespace { 148f4d4ce1aSPiyou Chen struct LessExtName { 149f4d4ce1aSPiyou Chen bool operator()(const RISCVExtensionBitmaskTable::RISCVExtensionBitmask &LHS, 150f4d4ce1aSPiyou Chen StringRef RHS) { 151f4d4ce1aSPiyou Chen return StringRef(LHS.Name) < RHS; 152f4d4ce1aSPiyou Chen } 153f4d4ce1aSPiyou Chen }; 154f4d4ce1aSPiyou Chen } // namespace 155f4d4ce1aSPiyou Chen 156ac1ffd3cSFrancesco Petrogalli } // namespace RISCV 15785388a06SWang Pengcheng 15885388a06SWang Pengcheng namespace RISCVVType { 15985388a06SWang Pengcheng // Encode VTYPE into the binary format used by the the VSETVLI instruction which 16085388a06SWang Pengcheng // is used by our MC layer representation. 16185388a06SWang Pengcheng // 16285388a06SWang Pengcheng // Bits | Name | Description 16385388a06SWang Pengcheng // -----+------------+------------------------------------------------ 16485388a06SWang Pengcheng // 7 | vma | Vector mask agnostic 16585388a06SWang Pengcheng // 6 | vta | Vector tail agnostic 16685388a06SWang Pengcheng // 5:3 | vsew[2:0] | Standard element width (SEW) setting 16785388a06SWang Pengcheng // 2:0 | vlmul[2:0] | Vector register group multiplier (LMUL) setting 16885388a06SWang Pengcheng unsigned encodeVTYPE(RISCVII::VLMUL VLMUL, unsigned SEW, bool TailAgnostic, 16985388a06SWang Pengcheng bool MaskAgnostic) { 17085388a06SWang Pengcheng assert(isValidSEW(SEW) && "Invalid SEW"); 17185388a06SWang Pengcheng unsigned VLMULBits = static_cast<unsigned>(VLMUL); 17285388a06SWang Pengcheng unsigned VSEWBits = encodeSEW(SEW); 17385388a06SWang Pengcheng unsigned VTypeI = (VSEWBits << 3) | (VLMULBits & 0x7); 17485388a06SWang Pengcheng if (TailAgnostic) 17585388a06SWang Pengcheng VTypeI |= 0x40; 17685388a06SWang Pengcheng if (MaskAgnostic) 17785388a06SWang Pengcheng VTypeI |= 0x80; 17885388a06SWang Pengcheng 17985388a06SWang Pengcheng return VTypeI; 18085388a06SWang Pengcheng } 18185388a06SWang Pengcheng 18285388a06SWang Pengcheng std::pair<unsigned, bool> decodeVLMUL(RISCVII::VLMUL VLMUL) { 18385388a06SWang Pengcheng switch (VLMUL) { 18485388a06SWang Pengcheng default: 18585388a06SWang Pengcheng llvm_unreachable("Unexpected LMUL value!"); 18685388a06SWang Pengcheng case RISCVII::VLMUL::LMUL_1: 18785388a06SWang Pengcheng case RISCVII::VLMUL::LMUL_2: 18885388a06SWang Pengcheng case RISCVII::VLMUL::LMUL_4: 18985388a06SWang Pengcheng case RISCVII::VLMUL::LMUL_8: 19085388a06SWang Pengcheng return std::make_pair(1 << static_cast<unsigned>(VLMUL), false); 19185388a06SWang Pengcheng case RISCVII::VLMUL::LMUL_F2: 19285388a06SWang Pengcheng case RISCVII::VLMUL::LMUL_F4: 19385388a06SWang Pengcheng case RISCVII::VLMUL::LMUL_F8: 19485388a06SWang Pengcheng return std::make_pair(1 << (8 - static_cast<unsigned>(VLMUL)), true); 19585388a06SWang Pengcheng } 19685388a06SWang Pengcheng } 19785388a06SWang Pengcheng 19885388a06SWang Pengcheng void printVType(unsigned VType, raw_ostream &OS) { 19985388a06SWang Pengcheng unsigned Sew = getSEW(VType); 20085388a06SWang Pengcheng OS << "e" << Sew; 20185388a06SWang Pengcheng 20285388a06SWang Pengcheng unsigned LMul; 20385388a06SWang Pengcheng bool Fractional; 20485388a06SWang Pengcheng std::tie(LMul, Fractional) = decodeVLMUL(getVLMUL(VType)); 20585388a06SWang Pengcheng 20685388a06SWang Pengcheng if (Fractional) 20785388a06SWang Pengcheng OS << ", mf"; 20885388a06SWang Pengcheng else 20985388a06SWang Pengcheng OS << ", m"; 21085388a06SWang Pengcheng OS << LMul; 21185388a06SWang Pengcheng 21285388a06SWang Pengcheng if (isTailAgnostic(VType)) 21385388a06SWang Pengcheng OS << ", ta"; 21485388a06SWang Pengcheng else 21585388a06SWang Pengcheng OS << ", tu"; 21685388a06SWang Pengcheng 21785388a06SWang Pengcheng if (isMaskAgnostic(VType)) 21885388a06SWang Pengcheng OS << ", ma"; 21985388a06SWang Pengcheng else 22085388a06SWang Pengcheng OS << ", mu"; 22185388a06SWang Pengcheng } 22285388a06SWang Pengcheng 22385388a06SWang Pengcheng unsigned getSEWLMULRatio(unsigned SEW, RISCVII::VLMUL VLMul) { 22485388a06SWang Pengcheng unsigned LMul; 22585388a06SWang Pengcheng bool Fractional; 22685388a06SWang Pengcheng std::tie(LMul, Fractional) = decodeVLMUL(VLMul); 22785388a06SWang Pengcheng 22885388a06SWang Pengcheng // Convert LMul to a fixed point value with 3 fractional bits. 22985388a06SWang Pengcheng LMul = Fractional ? (8 / LMul) : (LMul * 8); 23085388a06SWang Pengcheng 23185388a06SWang Pengcheng assert(SEW >= 8 && "Unexpected SEW value"); 23285388a06SWang Pengcheng return (SEW * 8) / LMul; 23385388a06SWang Pengcheng } 23485388a06SWang Pengcheng 23585388a06SWang Pengcheng std::optional<RISCVII::VLMUL> 23685388a06SWang Pengcheng getSameRatioLMUL(unsigned SEW, RISCVII::VLMUL VLMUL, unsigned EEW) { 23785388a06SWang Pengcheng unsigned Ratio = RISCVVType::getSEWLMULRatio(SEW, VLMUL); 23885388a06SWang Pengcheng unsigned EMULFixedPoint = (EEW * 8) / Ratio; 23985388a06SWang Pengcheng bool Fractional = EMULFixedPoint < 8; 24085388a06SWang Pengcheng unsigned EMUL = Fractional ? 8 / EMULFixedPoint : EMULFixedPoint / 8; 24185388a06SWang Pengcheng if (!isValidLMUL(EMUL, Fractional)) 24285388a06SWang Pengcheng return std::nullopt; 24385388a06SWang Pengcheng return RISCVVType::encodeLMUL(EMUL, Fractional); 24485388a06SWang Pengcheng } 24585388a06SWang Pengcheng 24685388a06SWang Pengcheng } // namespace RISCVVType 24785388a06SWang Pengcheng 248ac1ffd3cSFrancesco Petrogalli } // namespace llvm 249