Path: blob/main/contrib/llvm-project/clang/lib/Support/RISCVVIntrinsicUtils.cpp
35233 views
//===- RISCVVIntrinsicUtils.cpp - RISC-V Vector Intrinsic Utils -*- C++ -*-===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include "clang/Support/RISCVVIntrinsicUtils.h"9#include "llvm/ADT/ArrayRef.h"10#include "llvm/ADT/SmallSet.h"11#include "llvm/ADT/StringExtras.h"12#include "llvm/ADT/StringSet.h"13#include "llvm/ADT/Twine.h"14#include "llvm/Support/ErrorHandling.h"15#include "llvm/Support/raw_ostream.h"16#include <numeric>17#include <optional>1819using namespace llvm;2021namespace clang {22namespace RISCV {2324const PrototypeDescriptor PrototypeDescriptor::Mask = PrototypeDescriptor(25BaseTypeModifier::Vector, VectorTypeModifier::MaskVector);26const PrototypeDescriptor PrototypeDescriptor::VL =27PrototypeDescriptor(BaseTypeModifier::SizeT);28const PrototypeDescriptor PrototypeDescriptor::Vector =29PrototypeDescriptor(BaseTypeModifier::Vector);3031//===----------------------------------------------------------------------===//32// Type implementation33//===----------------------------------------------------------------------===//3435LMULType::LMULType(int NewLog2LMUL) {36// Check Log2LMUL is -3, -2, -1, 0, 1, 2, 337assert(NewLog2LMUL <= 3 && NewLog2LMUL >= -3 && "Bad LMUL number!");38Log2LMUL = NewLog2LMUL;39}4041std::string LMULType::str() const {42if (Log2LMUL < 0)43return "mf" + utostr(1ULL << (-Log2LMUL));44return "m" + utostr(1ULL << Log2LMUL);45}4647VScaleVal LMULType::getScale(unsigned ElementBitwidth) const {48int Log2ScaleResult = 0;49switch (ElementBitwidth) {50default:51break;52case 8:53Log2ScaleResult = Log2LMUL + 3;54break;55case 16:56Log2ScaleResult = Log2LMUL + 2;57break;58case 32:59Log2ScaleResult = Log2LMUL + 1;60break;61case 64:62Log2ScaleResult = Log2LMUL;63break;64}65// Illegal vscale result would be less than 166if (Log2ScaleResult < 0)67return std::nullopt;68return 1 << Log2ScaleResult;69}7071void LMULType::MulLog2LMUL(int log2LMUL) { Log2LMUL += log2LMUL; }7273RVVType::RVVType(BasicType BT, int Log2LMUL,74const PrototypeDescriptor &prototype)75: BT(BT), LMUL(LMULType(Log2LMUL)) {76applyBasicType();77applyModifier(prototype);78Valid = verifyType();79if (Valid) {80initBuiltinStr();81initTypeStr();82if (isVector()) {83initClangBuiltinStr();84}85}86}8788// clang-format off89// boolean type are encoded the ratio of n (SEW/LMUL)90// SEW/LMUL | 1 | 2 | 4 | 8 | 16 | 32 | 6491// c type | vbool64_t | vbool32_t | vbool16_t | vbool8_t | vbool4_t | vbool2_t | vbool1_t92// IR type | nxv1i1 | nxv2i1 | nxv4i1 | nxv8i1 | nxv16i1 | nxv32i1 | nxv64i19394// type\lmul | 1/8 | 1/4 | 1/2 | 1 | 2 | 4 | 895// -------- |------ | -------- | ------- | ------- | -------- | -------- | --------96// i64 | N/A | N/A | N/A | nxv1i64 | nxv2i64 | nxv4i64 | nxv8i6497// i32 | N/A | N/A | nxv1i32 | nxv2i32 | nxv4i32 | nxv8i32 | nxv16i3298// i16 | N/A | nxv1i16 | nxv2i16 | nxv4i16 | nxv8i16 | nxv16i16 | nxv32i1699// i8 | nxv1i8 | nxv2i8 | nxv4i8 | nxv8i8 | nxv16i8 | nxv32i8 | nxv64i8100// double | N/A | N/A | N/A | nxv1f64 | nxv2f64 | nxv4f64 | nxv8f64101// float | N/A | N/A | nxv1f32 | nxv2f32 | nxv4f32 | nxv8f32 | nxv16f32102// half | N/A | nxv1f16 | nxv2f16 | nxv4f16 | nxv8f16 | nxv16f16 | nxv32f16103// bfloat16 | N/A | nxv1bf16 | nxv2bf16| nxv4bf16| nxv8bf16 | nxv16bf16| nxv32bf16104// clang-format on105106bool RVVType::verifyType() const {107if (ScalarType == Invalid)108return false;109if (isScalar())110return true;111if (!Scale)112return false;113if (isFloat() && ElementBitwidth == 8)114return false;115if (isBFloat() && ElementBitwidth != 16)116return false;117if (IsTuple && (NF == 1 || NF > 8))118return false;119if (IsTuple && (1 << std::max(0, LMUL.Log2LMUL)) * NF > 8)120return false;121unsigned V = *Scale;122switch (ElementBitwidth) {123case 1:124case 8:125// Check Scale is 1,2,4,8,16,32,64126return (V <= 64 && isPowerOf2_32(V));127case 16:128// Check Scale is 1,2,4,8,16,32129return (V <= 32 && isPowerOf2_32(V));130case 32:131// Check Scale is 1,2,4,8,16132return (V <= 16 && isPowerOf2_32(V));133case 64:134// Check Scale is 1,2,4,8135return (V <= 8 && isPowerOf2_32(V));136}137return false;138}139140void RVVType::initBuiltinStr() {141assert(isValid() && "RVVType is invalid");142switch (ScalarType) {143case ScalarTypeKind::Void:144BuiltinStr = "v";145return;146case ScalarTypeKind::Size_t:147BuiltinStr = "z";148if (IsImmediate)149BuiltinStr = "I" + BuiltinStr;150if (IsPointer)151BuiltinStr += "*";152return;153case ScalarTypeKind::Ptrdiff_t:154BuiltinStr = "Y";155return;156case ScalarTypeKind::UnsignedLong:157BuiltinStr = "ULi";158return;159case ScalarTypeKind::SignedLong:160BuiltinStr = "Li";161return;162case ScalarTypeKind::Boolean:163assert(ElementBitwidth == 1);164BuiltinStr += "b";165break;166case ScalarTypeKind::SignedInteger:167case ScalarTypeKind::UnsignedInteger:168switch (ElementBitwidth) {169case 8:170BuiltinStr += "c";171break;172case 16:173BuiltinStr += "s";174break;175case 32:176BuiltinStr += "i";177break;178case 64:179BuiltinStr += "Wi";180break;181default:182llvm_unreachable("Unhandled ElementBitwidth!");183}184if (isSignedInteger())185BuiltinStr = "S" + BuiltinStr;186else187BuiltinStr = "U" + BuiltinStr;188break;189case ScalarTypeKind::Float:190switch (ElementBitwidth) {191case 16:192BuiltinStr += "x";193break;194case 32:195BuiltinStr += "f";196break;197case 64:198BuiltinStr += "d";199break;200default:201llvm_unreachable("Unhandled ElementBitwidth!");202}203break;204case ScalarTypeKind::BFloat:205BuiltinStr += "y";206break;207default:208llvm_unreachable("ScalarType is invalid!");209}210if (IsImmediate)211BuiltinStr = "I" + BuiltinStr;212if (isScalar()) {213if (IsConstant)214BuiltinStr += "C";215if (IsPointer)216BuiltinStr += "*";217return;218}219BuiltinStr = "q" + utostr(*Scale) + BuiltinStr;220// Pointer to vector types. Defined for segment load intrinsics.221// segment load intrinsics have pointer type arguments to store the loaded222// vector values.223if (IsPointer)224BuiltinStr += "*";225226if (IsTuple)227BuiltinStr = "T" + utostr(NF) + BuiltinStr;228}229230void RVVType::initClangBuiltinStr() {231assert(isValid() && "RVVType is invalid");232assert(isVector() && "Handle Vector type only");233234ClangBuiltinStr = "__rvv_";235switch (ScalarType) {236case ScalarTypeKind::Boolean:237ClangBuiltinStr += "bool" + utostr(64 / *Scale) + "_t";238return;239case ScalarTypeKind::Float:240ClangBuiltinStr += "float";241break;242case ScalarTypeKind::BFloat:243ClangBuiltinStr += "bfloat";244break;245case ScalarTypeKind::SignedInteger:246ClangBuiltinStr += "int";247break;248case ScalarTypeKind::UnsignedInteger:249ClangBuiltinStr += "uint";250break;251default:252llvm_unreachable("ScalarTypeKind is invalid");253}254ClangBuiltinStr += utostr(ElementBitwidth) + LMUL.str() +255(IsTuple ? "x" + utostr(NF) : "") + "_t";256}257258void RVVType::initTypeStr() {259assert(isValid() && "RVVType is invalid");260261if (IsConstant)262Str += "const ";263264auto getTypeString = [&](StringRef TypeStr) {265if (isScalar())266return Twine(TypeStr + Twine(ElementBitwidth) + "_t").str();267return Twine("v" + TypeStr + Twine(ElementBitwidth) + LMUL.str() +268(IsTuple ? "x" + utostr(NF) : "") + "_t")269.str();270};271272switch (ScalarType) {273case ScalarTypeKind::Void:274Str = "void";275return;276case ScalarTypeKind::Size_t:277Str = "size_t";278if (IsPointer)279Str += " *";280return;281case ScalarTypeKind::Ptrdiff_t:282Str = "ptrdiff_t";283return;284case ScalarTypeKind::UnsignedLong:285Str = "unsigned long";286return;287case ScalarTypeKind::SignedLong:288Str = "long";289return;290case ScalarTypeKind::Boolean:291if (isScalar())292Str += "bool";293else294// Vector bool is special case, the formulate is295// `vbool<N>_t = MVT::nxv<64/N>i1` ex. vbool16_t = MVT::4i1296Str += "vbool" + utostr(64 / *Scale) + "_t";297break;298case ScalarTypeKind::Float:299if (isScalar()) {300if (ElementBitwidth == 64)301Str += "double";302else if (ElementBitwidth == 32)303Str += "float";304else if (ElementBitwidth == 16)305Str += "_Float16";306else307llvm_unreachable("Unhandled floating type.");308} else309Str += getTypeString("float");310break;311case ScalarTypeKind::BFloat:312if (isScalar()) {313if (ElementBitwidth == 16)314Str += "__bf16";315else316llvm_unreachable("Unhandled floating type.");317} else318Str += getTypeString("bfloat");319break;320case ScalarTypeKind::SignedInteger:321Str += getTypeString("int");322break;323case ScalarTypeKind::UnsignedInteger:324Str += getTypeString("uint");325break;326default:327llvm_unreachable("ScalarType is invalid!");328}329if (IsPointer)330Str += " *";331}332333void RVVType::initShortStr() {334switch (ScalarType) {335case ScalarTypeKind::Boolean:336assert(isVector());337ShortStr = "b" + utostr(64 / *Scale);338return;339case ScalarTypeKind::Float:340ShortStr = "f" + utostr(ElementBitwidth);341break;342case ScalarTypeKind::BFloat:343ShortStr = "bf" + utostr(ElementBitwidth);344break;345case ScalarTypeKind::SignedInteger:346ShortStr = "i" + utostr(ElementBitwidth);347break;348case ScalarTypeKind::UnsignedInteger:349ShortStr = "u" + utostr(ElementBitwidth);350break;351default:352llvm_unreachable("Unhandled case!");353}354if (isVector())355ShortStr += LMUL.str();356if (isTuple())357ShortStr += "x" + utostr(NF);358}359360static VectorTypeModifier getTupleVTM(unsigned NF) {361assert(2 <= NF && NF <= 8 && "2 <= NF <= 8");362return static_cast<VectorTypeModifier>(363static_cast<uint8_t>(VectorTypeModifier::Tuple2) + (NF - 2));364}365366void RVVType::applyBasicType() {367switch (BT) {368case BasicType::Int8:369ElementBitwidth = 8;370ScalarType = ScalarTypeKind::SignedInteger;371break;372case BasicType::Int16:373ElementBitwidth = 16;374ScalarType = ScalarTypeKind::SignedInteger;375break;376case BasicType::Int32:377ElementBitwidth = 32;378ScalarType = ScalarTypeKind::SignedInteger;379break;380case BasicType::Int64:381ElementBitwidth = 64;382ScalarType = ScalarTypeKind::SignedInteger;383break;384case BasicType::Float16:385ElementBitwidth = 16;386ScalarType = ScalarTypeKind::Float;387break;388case BasicType::Float32:389ElementBitwidth = 32;390ScalarType = ScalarTypeKind::Float;391break;392case BasicType::Float64:393ElementBitwidth = 64;394ScalarType = ScalarTypeKind::Float;395break;396case BasicType::BFloat16:397ElementBitwidth = 16;398ScalarType = ScalarTypeKind::BFloat;399break;400default:401llvm_unreachable("Unhandled type code!");402}403assert(ElementBitwidth != 0 && "Bad element bitwidth!");404}405406std::optional<PrototypeDescriptor>407PrototypeDescriptor::parsePrototypeDescriptor(408llvm::StringRef PrototypeDescriptorStr) {409PrototypeDescriptor PD;410BaseTypeModifier PT = BaseTypeModifier::Invalid;411VectorTypeModifier VTM = VectorTypeModifier::NoModifier;412413if (PrototypeDescriptorStr.empty())414return PD;415416// Handle base type modifier417auto PType = PrototypeDescriptorStr.back();418switch (PType) {419case 'e':420PT = BaseTypeModifier::Scalar;421break;422case 'v':423PT = BaseTypeModifier::Vector;424break;425case 'w':426PT = BaseTypeModifier::Vector;427VTM = VectorTypeModifier::Widening2XVector;428break;429case 'q':430PT = BaseTypeModifier::Vector;431VTM = VectorTypeModifier::Widening4XVector;432break;433case 'o':434PT = BaseTypeModifier::Vector;435VTM = VectorTypeModifier::Widening8XVector;436break;437case 'm':438PT = BaseTypeModifier::Vector;439VTM = VectorTypeModifier::MaskVector;440break;441case '0':442PT = BaseTypeModifier::Void;443break;444case 'z':445PT = BaseTypeModifier::SizeT;446break;447case 't':448PT = BaseTypeModifier::Ptrdiff;449break;450case 'u':451PT = BaseTypeModifier::UnsignedLong;452break;453case 'l':454PT = BaseTypeModifier::SignedLong;455break;456case 'f':457PT = BaseTypeModifier::Float32;458break;459default:460llvm_unreachable("Illegal primitive type transformers!");461}462PD.PT = static_cast<uint8_t>(PT);463PrototypeDescriptorStr = PrototypeDescriptorStr.drop_back();464465// Compute the vector type transformers, it can only appear one time.466if (PrototypeDescriptorStr.starts_with("(")) {467assert(VTM == VectorTypeModifier::NoModifier &&468"VectorTypeModifier should only have one modifier");469size_t Idx = PrototypeDescriptorStr.find(')');470assert(Idx != StringRef::npos);471StringRef ComplexType = PrototypeDescriptorStr.slice(1, Idx);472PrototypeDescriptorStr = PrototypeDescriptorStr.drop_front(Idx + 1);473assert(!PrototypeDescriptorStr.contains('(') &&474"Only allow one vector type modifier");475476auto ComplexTT = ComplexType.split(":");477if (ComplexTT.first == "Log2EEW") {478uint32_t Log2EEW;479if (ComplexTT.second.getAsInteger(10, Log2EEW)) {480llvm_unreachable("Invalid Log2EEW value!");481return std::nullopt;482}483switch (Log2EEW) {484case 3:485VTM = VectorTypeModifier::Log2EEW3;486break;487case 4:488VTM = VectorTypeModifier::Log2EEW4;489break;490case 5:491VTM = VectorTypeModifier::Log2EEW5;492break;493case 6:494VTM = VectorTypeModifier::Log2EEW6;495break;496default:497llvm_unreachable("Invalid Log2EEW value, should be [3-6]");498return std::nullopt;499}500} else if (ComplexTT.first == "FixedSEW") {501uint32_t NewSEW;502if (ComplexTT.second.getAsInteger(10, NewSEW)) {503llvm_unreachable("Invalid FixedSEW value!");504return std::nullopt;505}506switch (NewSEW) {507case 8:508VTM = VectorTypeModifier::FixedSEW8;509break;510case 16:511VTM = VectorTypeModifier::FixedSEW16;512break;513case 32:514VTM = VectorTypeModifier::FixedSEW32;515break;516case 64:517VTM = VectorTypeModifier::FixedSEW64;518break;519default:520llvm_unreachable("Invalid FixedSEW value, should be 8, 16, 32 or 64");521return std::nullopt;522}523} else if (ComplexTT.first == "LFixedLog2LMUL") {524int32_t Log2LMUL;525if (ComplexTT.second.getAsInteger(10, Log2LMUL)) {526llvm_unreachable("Invalid LFixedLog2LMUL value!");527return std::nullopt;528}529switch (Log2LMUL) {530case -3:531VTM = VectorTypeModifier::LFixedLog2LMULN3;532break;533case -2:534VTM = VectorTypeModifier::LFixedLog2LMULN2;535break;536case -1:537VTM = VectorTypeModifier::LFixedLog2LMULN1;538break;539case 0:540VTM = VectorTypeModifier::LFixedLog2LMUL0;541break;542case 1:543VTM = VectorTypeModifier::LFixedLog2LMUL1;544break;545case 2:546VTM = VectorTypeModifier::LFixedLog2LMUL2;547break;548case 3:549VTM = VectorTypeModifier::LFixedLog2LMUL3;550break;551default:552llvm_unreachable("Invalid LFixedLog2LMUL value, should be [-3, 3]");553return std::nullopt;554}555} else if (ComplexTT.first == "SFixedLog2LMUL") {556int32_t Log2LMUL;557if (ComplexTT.second.getAsInteger(10, Log2LMUL)) {558llvm_unreachable("Invalid SFixedLog2LMUL value!");559return std::nullopt;560}561switch (Log2LMUL) {562case -3:563VTM = VectorTypeModifier::SFixedLog2LMULN3;564break;565case -2:566VTM = VectorTypeModifier::SFixedLog2LMULN2;567break;568case -1:569VTM = VectorTypeModifier::SFixedLog2LMULN1;570break;571case 0:572VTM = VectorTypeModifier::SFixedLog2LMUL0;573break;574case 1:575VTM = VectorTypeModifier::SFixedLog2LMUL1;576break;577case 2:578VTM = VectorTypeModifier::SFixedLog2LMUL2;579break;580case 3:581VTM = VectorTypeModifier::SFixedLog2LMUL3;582break;583default:584llvm_unreachable("Invalid LFixedLog2LMUL value, should be [-3, 3]");585return std::nullopt;586}587588} else if (ComplexTT.first == "SEFixedLog2LMUL") {589int32_t Log2LMUL;590if (ComplexTT.second.getAsInteger(10, Log2LMUL)) {591llvm_unreachable("Invalid SEFixedLog2LMUL value!");592return std::nullopt;593}594switch (Log2LMUL) {595case -3:596VTM = VectorTypeModifier::SEFixedLog2LMULN3;597break;598case -2:599VTM = VectorTypeModifier::SEFixedLog2LMULN2;600break;601case -1:602VTM = VectorTypeModifier::SEFixedLog2LMULN1;603break;604case 0:605VTM = VectorTypeModifier::SEFixedLog2LMUL0;606break;607case 1:608VTM = VectorTypeModifier::SEFixedLog2LMUL1;609break;610case 2:611VTM = VectorTypeModifier::SEFixedLog2LMUL2;612break;613case 3:614VTM = VectorTypeModifier::SEFixedLog2LMUL3;615break;616default:617llvm_unreachable("Invalid LFixedLog2LMUL value, should be [-3, 3]");618return std::nullopt;619}620} else if (ComplexTT.first == "Tuple") {621unsigned NF = 0;622if (ComplexTT.second.getAsInteger(10, NF)) {623llvm_unreachable("Invalid NF value!");624return std::nullopt;625}626VTM = getTupleVTM(NF);627} else {628llvm_unreachable("Illegal complex type transformers!");629}630}631PD.VTM = static_cast<uint8_t>(VTM);632633// Compute the remain type transformers634TypeModifier TM = TypeModifier::NoModifier;635for (char I : PrototypeDescriptorStr) {636switch (I) {637case 'P':638if ((TM & TypeModifier::Const) == TypeModifier::Const)639llvm_unreachable("'P' transformer cannot be used after 'C'");640if ((TM & TypeModifier::Pointer) == TypeModifier::Pointer)641llvm_unreachable("'P' transformer cannot be used twice");642TM |= TypeModifier::Pointer;643break;644case 'C':645TM |= TypeModifier::Const;646break;647case 'K':648TM |= TypeModifier::Immediate;649break;650case 'U':651TM |= TypeModifier::UnsignedInteger;652break;653case 'I':654TM |= TypeModifier::SignedInteger;655break;656case 'F':657TM |= TypeModifier::Float;658break;659case 'S':660TM |= TypeModifier::LMUL1;661break;662default:663llvm_unreachable("Illegal non-primitive type transformer!");664}665}666PD.TM = static_cast<uint8_t>(TM);667668return PD;669}670671void RVVType::applyModifier(const PrototypeDescriptor &Transformer) {672// Handle primitive type transformer673switch (static_cast<BaseTypeModifier>(Transformer.PT)) {674case BaseTypeModifier::Scalar:675Scale = 0;676break;677case BaseTypeModifier::Vector:678Scale = LMUL.getScale(ElementBitwidth);679break;680case BaseTypeModifier::Void:681ScalarType = ScalarTypeKind::Void;682break;683case BaseTypeModifier::SizeT:684ScalarType = ScalarTypeKind::Size_t;685break;686case BaseTypeModifier::Ptrdiff:687ScalarType = ScalarTypeKind::Ptrdiff_t;688break;689case BaseTypeModifier::UnsignedLong:690ScalarType = ScalarTypeKind::UnsignedLong;691break;692case BaseTypeModifier::SignedLong:693ScalarType = ScalarTypeKind::SignedLong;694break;695case BaseTypeModifier::Float32:696ElementBitwidth = 32;697ScalarType = ScalarTypeKind::Float;698break;699case BaseTypeModifier::Invalid:700ScalarType = ScalarTypeKind::Invalid;701return;702}703704switch (static_cast<VectorTypeModifier>(Transformer.VTM)) {705case VectorTypeModifier::Widening2XVector:706ElementBitwidth *= 2;707LMUL.MulLog2LMUL(1);708Scale = LMUL.getScale(ElementBitwidth);709break;710case VectorTypeModifier::Widening4XVector:711ElementBitwidth *= 4;712LMUL.MulLog2LMUL(2);713Scale = LMUL.getScale(ElementBitwidth);714break;715case VectorTypeModifier::Widening8XVector:716ElementBitwidth *= 8;717LMUL.MulLog2LMUL(3);718Scale = LMUL.getScale(ElementBitwidth);719break;720case VectorTypeModifier::MaskVector:721ScalarType = ScalarTypeKind::Boolean;722Scale = LMUL.getScale(ElementBitwidth);723ElementBitwidth = 1;724break;725case VectorTypeModifier::Log2EEW3:726applyLog2EEW(3);727break;728case VectorTypeModifier::Log2EEW4:729applyLog2EEW(4);730break;731case VectorTypeModifier::Log2EEW5:732applyLog2EEW(5);733break;734case VectorTypeModifier::Log2EEW6:735applyLog2EEW(6);736break;737case VectorTypeModifier::FixedSEW8:738applyFixedSEW(8);739break;740case VectorTypeModifier::FixedSEW16:741applyFixedSEW(16);742break;743case VectorTypeModifier::FixedSEW32:744applyFixedSEW(32);745break;746case VectorTypeModifier::FixedSEW64:747applyFixedSEW(64);748break;749case VectorTypeModifier::LFixedLog2LMULN3:750applyFixedLog2LMUL(-3, FixedLMULType::LargerThan);751break;752case VectorTypeModifier::LFixedLog2LMULN2:753applyFixedLog2LMUL(-2, FixedLMULType::LargerThan);754break;755case VectorTypeModifier::LFixedLog2LMULN1:756applyFixedLog2LMUL(-1, FixedLMULType::LargerThan);757break;758case VectorTypeModifier::LFixedLog2LMUL0:759applyFixedLog2LMUL(0, FixedLMULType::LargerThan);760break;761case VectorTypeModifier::LFixedLog2LMUL1:762applyFixedLog2LMUL(1, FixedLMULType::LargerThan);763break;764case VectorTypeModifier::LFixedLog2LMUL2:765applyFixedLog2LMUL(2, FixedLMULType::LargerThan);766break;767case VectorTypeModifier::LFixedLog2LMUL3:768applyFixedLog2LMUL(3, FixedLMULType::LargerThan);769break;770case VectorTypeModifier::SFixedLog2LMULN3:771applyFixedLog2LMUL(-3, FixedLMULType::SmallerThan);772break;773case VectorTypeModifier::SFixedLog2LMULN2:774applyFixedLog2LMUL(-2, FixedLMULType::SmallerThan);775break;776case VectorTypeModifier::SFixedLog2LMULN1:777applyFixedLog2LMUL(-1, FixedLMULType::SmallerThan);778break;779case VectorTypeModifier::SFixedLog2LMUL0:780applyFixedLog2LMUL(0, FixedLMULType::SmallerThan);781break;782case VectorTypeModifier::SFixedLog2LMUL1:783applyFixedLog2LMUL(1, FixedLMULType::SmallerThan);784break;785case VectorTypeModifier::SFixedLog2LMUL2:786applyFixedLog2LMUL(2, FixedLMULType::SmallerThan);787break;788case VectorTypeModifier::SFixedLog2LMUL3:789applyFixedLog2LMUL(3, FixedLMULType::SmallerThan);790break;791case VectorTypeModifier::SEFixedLog2LMULN3:792applyFixedLog2LMUL(-3, FixedLMULType::SmallerOrEqual);793break;794case VectorTypeModifier::SEFixedLog2LMULN2:795applyFixedLog2LMUL(-2, FixedLMULType::SmallerOrEqual);796break;797case VectorTypeModifier::SEFixedLog2LMULN1:798applyFixedLog2LMUL(-1, FixedLMULType::SmallerOrEqual);799break;800case VectorTypeModifier::SEFixedLog2LMUL0:801applyFixedLog2LMUL(0, FixedLMULType::SmallerOrEqual);802break;803case VectorTypeModifier::SEFixedLog2LMUL1:804applyFixedLog2LMUL(1, FixedLMULType::SmallerOrEqual);805break;806case VectorTypeModifier::SEFixedLog2LMUL2:807applyFixedLog2LMUL(2, FixedLMULType::SmallerOrEqual);808break;809case VectorTypeModifier::SEFixedLog2LMUL3:810applyFixedLog2LMUL(3, FixedLMULType::SmallerOrEqual);811break;812case VectorTypeModifier::Tuple2:813case VectorTypeModifier::Tuple3:814case VectorTypeModifier::Tuple4:815case VectorTypeModifier::Tuple5:816case VectorTypeModifier::Tuple6:817case VectorTypeModifier::Tuple7:818case VectorTypeModifier::Tuple8: {819IsTuple = true;820NF = 2 + static_cast<uint8_t>(Transformer.VTM) -821static_cast<uint8_t>(VectorTypeModifier::Tuple2);822break;823}824case VectorTypeModifier::NoModifier:825break;826}827828// Early return if the current type modifier is already invalid.829if (ScalarType == Invalid)830return;831832for (unsigned TypeModifierMaskShift = 0;833TypeModifierMaskShift <= static_cast<unsigned>(TypeModifier::MaxOffset);834++TypeModifierMaskShift) {835unsigned TypeModifierMask = 1 << TypeModifierMaskShift;836if ((static_cast<unsigned>(Transformer.TM) & TypeModifierMask) !=837TypeModifierMask)838continue;839switch (static_cast<TypeModifier>(TypeModifierMask)) {840case TypeModifier::Pointer:841IsPointer = true;842break;843case TypeModifier::Const:844IsConstant = true;845break;846case TypeModifier::Immediate:847IsImmediate = true;848IsConstant = true;849break;850case TypeModifier::UnsignedInteger:851ScalarType = ScalarTypeKind::UnsignedInteger;852break;853case TypeModifier::SignedInteger:854ScalarType = ScalarTypeKind::SignedInteger;855break;856case TypeModifier::Float:857ScalarType = ScalarTypeKind::Float;858break;859case TypeModifier::BFloat:860ScalarType = ScalarTypeKind::BFloat;861break;862case TypeModifier::LMUL1:863LMUL = LMULType(0);864// Update ElementBitwidth need to update Scale too.865Scale = LMUL.getScale(ElementBitwidth);866break;867default:868llvm_unreachable("Unknown type modifier mask!");869}870}871}872873void RVVType::applyLog2EEW(unsigned Log2EEW) {874// update new elmul = (eew/sew) * lmul875LMUL.MulLog2LMUL(Log2EEW - Log2_32(ElementBitwidth));876// update new eew877ElementBitwidth = 1 << Log2EEW;878ScalarType = ScalarTypeKind::SignedInteger;879Scale = LMUL.getScale(ElementBitwidth);880}881882void RVVType::applyFixedSEW(unsigned NewSEW) {883// Set invalid type if src and dst SEW are same.884if (ElementBitwidth == NewSEW) {885ScalarType = ScalarTypeKind::Invalid;886return;887}888// Update new SEW889ElementBitwidth = NewSEW;890Scale = LMUL.getScale(ElementBitwidth);891}892893void RVVType::applyFixedLog2LMUL(int Log2LMUL, enum FixedLMULType Type) {894switch (Type) {895case FixedLMULType::LargerThan:896if (Log2LMUL <= LMUL.Log2LMUL) {897ScalarType = ScalarTypeKind::Invalid;898return;899}900break;901case FixedLMULType::SmallerThan:902if (Log2LMUL >= LMUL.Log2LMUL) {903ScalarType = ScalarTypeKind::Invalid;904return;905}906break;907case FixedLMULType::SmallerOrEqual:908if (Log2LMUL > LMUL.Log2LMUL) {909ScalarType = ScalarTypeKind::Invalid;910return;911}912break;913}914915// Update new LMUL916LMUL = LMULType(Log2LMUL);917Scale = LMUL.getScale(ElementBitwidth);918}919920std::optional<RVVTypes>921RVVTypeCache::computeTypes(BasicType BT, int Log2LMUL, unsigned NF,922ArrayRef<PrototypeDescriptor> Prototype) {923RVVTypes Types;924for (const PrototypeDescriptor &Proto : Prototype) {925auto T = computeType(BT, Log2LMUL, Proto);926if (!T)927return std::nullopt;928// Record legal type index929Types.push_back(*T);930}931return Types;932}933934// Compute the hash value of RVVType, used for cache the result of computeType.935static uint64_t computeRVVTypeHashValue(BasicType BT, int Log2LMUL,936PrototypeDescriptor Proto) {937// Layout of hash value:938// 0 8 16 24 32 40939// | Log2LMUL + 3 | BT | Proto.PT | Proto.TM | Proto.VTM |940assert(Log2LMUL >= -3 && Log2LMUL <= 3);941return (Log2LMUL + 3) | (static_cast<uint64_t>(BT) & 0xff) << 8 |942((uint64_t)(Proto.PT & 0xff) << 16) |943((uint64_t)(Proto.TM & 0xff) << 24) |944((uint64_t)(Proto.VTM & 0xff) << 32);945}946947std::optional<RVVTypePtr> RVVTypeCache::computeType(BasicType BT, int Log2LMUL,948PrototypeDescriptor Proto) {949uint64_t Idx = computeRVVTypeHashValue(BT, Log2LMUL, Proto);950// Search first951auto It = LegalTypes.find(Idx);952if (It != LegalTypes.end())953return &(It->second);954955if (IllegalTypes.count(Idx))956return std::nullopt;957958// Compute type and record the result.959RVVType T(BT, Log2LMUL, Proto);960if (T.isValid()) {961// Record legal type index and value.962std::pair<std::unordered_map<uint64_t, RVVType>::iterator, bool>963InsertResult = LegalTypes.insert({Idx, T});964return &(InsertResult.first->second);965}966// Record illegal type index.967IllegalTypes.insert(Idx);968return std::nullopt;969}970971//===----------------------------------------------------------------------===//972// RVVIntrinsic implementation973//===----------------------------------------------------------------------===//974RVVIntrinsic::RVVIntrinsic(975StringRef NewName, StringRef Suffix, StringRef NewOverloadedName,976StringRef OverloadedSuffix, StringRef IRName, bool IsMasked,977bool HasMaskedOffOperand, bool HasVL, PolicyScheme Scheme,978bool SupportOverloading, bool HasBuiltinAlias, StringRef ManualCodegen,979const RVVTypes &OutInTypes, const std::vector<int64_t> &NewIntrinsicTypes,980unsigned NF, Policy NewPolicyAttrs, bool HasFRMRoundModeOp)981: IRName(IRName), IsMasked(IsMasked),982HasMaskedOffOperand(HasMaskedOffOperand), HasVL(HasVL), Scheme(Scheme),983SupportOverloading(SupportOverloading), HasBuiltinAlias(HasBuiltinAlias),984ManualCodegen(ManualCodegen.str()), NF(NF), PolicyAttrs(NewPolicyAttrs) {985986// Init BuiltinName, Name and OverloadedName987BuiltinName = NewName.str();988Name = BuiltinName;989if (NewOverloadedName.empty())990OverloadedName = NewName.split("_").first.str();991else992OverloadedName = NewOverloadedName.str();993if (!Suffix.empty())994Name += "_" + Suffix.str();995if (!OverloadedSuffix.empty())996OverloadedName += "_" + OverloadedSuffix.str();997998updateNamesAndPolicy(IsMasked, hasPolicy(), Name, BuiltinName, OverloadedName,999PolicyAttrs, HasFRMRoundModeOp);10001001// Init OutputType and InputTypes1002OutputType = OutInTypes[0];1003InputTypes.assign(OutInTypes.begin() + 1, OutInTypes.end());10041005// IntrinsicTypes is unmasked TA version index. Need to update it1006// if there is merge operand (It is always in first operand).1007IntrinsicTypes = NewIntrinsicTypes;1008if ((IsMasked && hasMaskedOffOperand()) ||1009(!IsMasked && hasPassthruOperand())) {1010for (auto &I : IntrinsicTypes) {1011if (I >= 0)1012I += NF;1013}1014}1015}10161017std::string RVVIntrinsic::getBuiltinTypeStr() const {1018std::string S;1019S += OutputType->getBuiltinStr();1020for (const auto &T : InputTypes) {1021S += T->getBuiltinStr();1022}1023return S;1024}10251026std::string RVVIntrinsic::getSuffixStr(1027RVVTypeCache &TypeCache, BasicType Type, int Log2LMUL,1028llvm::ArrayRef<PrototypeDescriptor> PrototypeDescriptors) {1029SmallVector<std::string> SuffixStrs;1030for (auto PD : PrototypeDescriptors) {1031auto T = TypeCache.computeType(Type, Log2LMUL, PD);1032SuffixStrs.push_back((*T)->getShortStr());1033}1034return join(SuffixStrs, "_");1035}10361037llvm::SmallVector<PrototypeDescriptor> RVVIntrinsic::computeBuiltinTypes(1038llvm::ArrayRef<PrototypeDescriptor> Prototype, bool IsMasked,1039bool HasMaskedOffOperand, bool HasVL, unsigned NF,1040PolicyScheme DefaultScheme, Policy PolicyAttrs, bool IsTuple) {1041SmallVector<PrototypeDescriptor> NewPrototype(Prototype.begin(),1042Prototype.end());1043bool HasPassthruOp = DefaultScheme == PolicyScheme::HasPassthruOperand;1044if (IsMasked) {1045// If HasMaskedOffOperand, insert result type as first input operand if1046// need.1047if (HasMaskedOffOperand && !PolicyAttrs.isTAMAPolicy()) {1048if (NF == 1) {1049NewPrototype.insert(NewPrototype.begin() + 1, NewPrototype[0]);1050} else if (NF > 1) {1051if (IsTuple) {1052PrototypeDescriptor BasePtrOperand = Prototype[1];1053PrototypeDescriptor MaskoffType = PrototypeDescriptor(1054static_cast<uint8_t>(BaseTypeModifier::Vector),1055static_cast<uint8_t>(getTupleVTM(NF)),1056BasePtrOperand.TM & ~static_cast<uint8_t>(TypeModifier::Pointer));1057NewPrototype.insert(NewPrototype.begin() + 1, MaskoffType);1058} else {1059// Convert1060// (void, op0 address, op1 address, ...)1061// to1062// (void, op0 address, op1 address, ..., maskedoff0, maskedoff1, ...)1063PrototypeDescriptor MaskoffType = NewPrototype[1];1064MaskoffType.TM &= ~static_cast<uint8_t>(TypeModifier::Pointer);1065NewPrototype.insert(NewPrototype.begin() + NF + 1, NF, MaskoffType);1066}1067}1068}1069if (HasMaskedOffOperand && NF > 1) {1070// Convert1071// (void, op0 address, op1 address, ..., maskedoff0, maskedoff1, ...)1072// to1073// (void, op0 address, op1 address, ..., mask, maskedoff0, maskedoff1,1074// ...)1075if (IsTuple)1076NewPrototype.insert(NewPrototype.begin() + 1,1077PrototypeDescriptor::Mask);1078else1079NewPrototype.insert(NewPrototype.begin() + NF + 1,1080PrototypeDescriptor::Mask);1081} else {1082// If IsMasked, insert PrototypeDescriptor:Mask as first input operand.1083NewPrototype.insert(NewPrototype.begin() + 1, PrototypeDescriptor::Mask);1084}1085} else {1086if (NF == 1) {1087if (PolicyAttrs.isTUPolicy() && HasPassthruOp)1088NewPrototype.insert(NewPrototype.begin(), NewPrototype[0]);1089} else if (PolicyAttrs.isTUPolicy() && HasPassthruOp) {1090if (IsTuple) {1091PrototypeDescriptor BasePtrOperand = Prototype[0];1092PrototypeDescriptor MaskoffType = PrototypeDescriptor(1093static_cast<uint8_t>(BaseTypeModifier::Vector),1094static_cast<uint8_t>(getTupleVTM(NF)),1095BasePtrOperand.TM & ~static_cast<uint8_t>(TypeModifier::Pointer));1096NewPrototype.insert(NewPrototype.begin(), MaskoffType);1097} else {1098// NF > 1 cases for segment load operations.1099// Convert1100// (void, op0 address, op1 address, ...)1101// to1102// (void, op0 address, op1 address, maskedoff0, maskedoff1, ...)1103PrototypeDescriptor MaskoffType = Prototype[1];1104MaskoffType.TM &= ~static_cast<uint8_t>(TypeModifier::Pointer);1105NewPrototype.insert(NewPrototype.begin() + NF + 1, NF, MaskoffType);1106}1107}1108}11091110// If HasVL, append PrototypeDescriptor:VL to last operand1111if (HasVL)1112NewPrototype.push_back(PrototypeDescriptor::VL);11131114return NewPrototype;1115}11161117llvm::SmallVector<Policy> RVVIntrinsic::getSupportedUnMaskedPolicies() {1118return {Policy(Policy::PolicyType::Undisturbed)}; // TU1119}11201121llvm::SmallVector<Policy>1122RVVIntrinsic::getSupportedMaskedPolicies(bool HasTailPolicy,1123bool HasMaskPolicy) {1124if (HasTailPolicy && HasMaskPolicy)1125return {Policy(Policy::PolicyType::Undisturbed,1126Policy::PolicyType::Agnostic), // TUM1127Policy(Policy::PolicyType::Undisturbed,1128Policy::PolicyType::Undisturbed), // TUMU1129Policy(Policy::PolicyType::Agnostic,1130Policy::PolicyType::Undisturbed)}; // MU1131if (HasTailPolicy && !HasMaskPolicy)1132return {Policy(Policy::PolicyType::Undisturbed,1133Policy::PolicyType::Agnostic)}; // TU1134if (!HasTailPolicy && HasMaskPolicy)1135return {Policy(Policy::PolicyType::Agnostic,1136Policy::PolicyType::Undisturbed)}; // MU1137llvm_unreachable("An RVV instruction should not be without both tail policy "1138"and mask policy");1139}11401141void RVVIntrinsic::updateNamesAndPolicy(1142bool IsMasked, bool HasPolicy, std::string &Name, std::string &BuiltinName,1143std::string &OverloadedName, Policy &PolicyAttrs, bool HasFRMRoundModeOp) {11441145auto appendPolicySuffix = [&](const std::string &suffix) {1146Name += suffix;1147BuiltinName += suffix;1148OverloadedName += suffix;1149};11501151if (HasFRMRoundModeOp) {1152Name += "_rm";1153BuiltinName += "_rm";1154}11551156if (IsMasked) {1157if (PolicyAttrs.isTUMUPolicy())1158appendPolicySuffix("_tumu");1159else if (PolicyAttrs.isTUMAPolicy())1160appendPolicySuffix("_tum");1161else if (PolicyAttrs.isTAMUPolicy())1162appendPolicySuffix("_mu");1163else if (PolicyAttrs.isTAMAPolicy()) {1164Name += "_m";1165BuiltinName += "_m";1166} else1167llvm_unreachable("Unhandled policy condition");1168} else {1169if (PolicyAttrs.isTUPolicy())1170appendPolicySuffix("_tu");1171else if (PolicyAttrs.isTAPolicy()) // no suffix needed1172return;1173else1174llvm_unreachable("Unhandled policy condition");1175}1176}11771178SmallVector<PrototypeDescriptor> parsePrototypes(StringRef Prototypes) {1179SmallVector<PrototypeDescriptor> PrototypeDescriptors;1180const StringRef Primaries("evwqom0ztulf");1181while (!Prototypes.empty()) {1182size_t Idx = 0;1183// Skip over complex prototype because it could contain primitive type1184// character.1185if (Prototypes[0] == '(')1186Idx = Prototypes.find_first_of(')');1187Idx = Prototypes.find_first_of(Primaries, Idx);1188assert(Idx != StringRef::npos);1189auto PD = PrototypeDescriptor::parsePrototypeDescriptor(1190Prototypes.slice(0, Idx + 1));1191if (!PD)1192llvm_unreachable("Error during parsing prototype.");1193PrototypeDescriptors.push_back(*PD);1194Prototypes = Prototypes.drop_front(Idx + 1);1195}1196return PrototypeDescriptors;1197}11981199raw_ostream &operator<<(raw_ostream &OS, const RVVIntrinsicRecord &Record) {1200OS << "{";1201OS << "\"" << Record.Name << "\",";1202if (Record.OverloadedName == nullptr ||1203StringRef(Record.OverloadedName).empty())1204OS << "nullptr,";1205else1206OS << "\"" << Record.OverloadedName << "\",";1207OS << Record.PrototypeIndex << ",";1208OS << Record.SuffixIndex << ",";1209OS << Record.OverloadedSuffixIndex << ",";1210OS << (int)Record.PrototypeLength << ",";1211OS << (int)Record.SuffixLength << ",";1212OS << (int)Record.OverloadedSuffixSize << ",";1213OS << Record.RequiredExtensions << ",";1214OS << (int)Record.TypeRangeMask << ",";1215OS << (int)Record.Log2LMULMask << ",";1216OS << (int)Record.NF << ",";1217OS << (int)Record.HasMasked << ",";1218OS << (int)Record.HasVL << ",";1219OS << (int)Record.HasMaskedOffOperand << ",";1220OS << (int)Record.HasTailPolicy << ",";1221OS << (int)Record.HasMaskPolicy << ",";1222OS << (int)Record.HasFRMRoundModeOp << ",";1223OS << (int)Record.IsTuple << ",";1224OS << (int)Record.UnMaskedPolicyScheme << ",";1225OS << (int)Record.MaskedPolicyScheme << ",";1226OS << "},\n";1227return OS;1228}12291230} // end namespace RISCV1231} // end namespace clang123212331234