1fe6060f1SDimitry Andric //===- RISCVVEmitter.cpp - Generate riscv_vector.h for use with clang -----===// 2fe6060f1SDimitry Andric // 3fe6060f1SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4fe6060f1SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5fe6060f1SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6fe6060f1SDimitry Andric // 7fe6060f1SDimitry Andric //===----------------------------------------------------------------------===// 8fe6060f1SDimitry Andric // 9fe6060f1SDimitry Andric // This tablegen backend is responsible for emitting riscv_vector.h which 10fe6060f1SDimitry Andric // includes a declaration and definition of each intrinsic functions specified 11fe6060f1SDimitry Andric // in https://github.com/riscv/rvv-intrinsic-doc. 12fe6060f1SDimitry Andric // 13fe6060f1SDimitry Andric // See also the documentation in include/clang/Basic/riscv_vector.td. 14fe6060f1SDimitry Andric // 15fe6060f1SDimitry Andric //===----------------------------------------------------------------------===// 16fe6060f1SDimitry Andric 1781ad6265SDimitry Andric #include "clang/Support/RISCVVIntrinsicUtils.h" 18fe6060f1SDimitry Andric #include "llvm/ADT/ArrayRef.h" 19fe6060f1SDimitry Andric #include "llvm/ADT/SmallSet.h" 20fe6060f1SDimitry Andric #include "llvm/ADT/StringExtras.h" 21fe6060f1SDimitry Andric #include "llvm/ADT/StringMap.h" 22fe6060f1SDimitry Andric #include "llvm/ADT/StringSet.h" 23fe6060f1SDimitry Andric #include "llvm/ADT/Twine.h" 24fe6060f1SDimitry Andric #include "llvm/TableGen/Error.h" 25fe6060f1SDimitry Andric #include "llvm/TableGen/Record.h" 26fe6060f1SDimitry Andric #include <numeric> 27fe6060f1SDimitry Andric 28fe6060f1SDimitry Andric using namespace llvm; 2981ad6265SDimitry Andric using namespace clang::RISCV; 30fe6060f1SDimitry Andric 31fe6060f1SDimitry Andric namespace { 32fe6060f1SDimitry Andric class RVVEmitter { 33fe6060f1SDimitry Andric private: 34fe6060f1SDimitry Andric RecordKeeper &Records; 35fe6060f1SDimitry Andric 36fe6060f1SDimitry Andric public: 37fe6060f1SDimitry Andric RVVEmitter(RecordKeeper &R) : Records(R) {} 38fe6060f1SDimitry Andric 39fe6060f1SDimitry Andric /// Emit riscv_vector.h 40fe6060f1SDimitry Andric void createHeader(raw_ostream &o); 41fe6060f1SDimitry Andric 42fe6060f1SDimitry Andric /// Emit all the __builtin prototypes and code needed by Sema. 43fe6060f1SDimitry Andric void createBuiltins(raw_ostream &o); 44fe6060f1SDimitry Andric 45fe6060f1SDimitry Andric /// Emit all the information needed to map builtin -> LLVM IR intrinsic. 46fe6060f1SDimitry Andric void createCodeGen(raw_ostream &o); 47fe6060f1SDimitry Andric 48fe6060f1SDimitry Andric private: 49fe6060f1SDimitry Andric /// Create all intrinsics and add them to \p Out 50fe6060f1SDimitry Andric void createRVVIntrinsics(std::vector<std::unique_ptr<RVVIntrinsic>> &Out); 5181ad6265SDimitry Andric /// Print HeaderCode in RVVHeader Record to \p Out 5281ad6265SDimitry Andric void printHeaderCode(raw_ostream &OS); 53fe6060f1SDimitry Andric 54fe6060f1SDimitry Andric /// Emit Acrh predecessor definitions and body, assume the element of Defs are 55fe6060f1SDimitry Andric /// sorted by extension. 56fe6060f1SDimitry Andric void emitArchMacroAndBody( 57fe6060f1SDimitry Andric std::vector<std::unique_ptr<RVVIntrinsic>> &Defs, raw_ostream &o, 58fe6060f1SDimitry Andric std::function<void(raw_ostream &, const RVVIntrinsic &)>); 59fe6060f1SDimitry Andric 60fe6060f1SDimitry Andric // Emit the architecture preprocessor definitions. Return true when emits 61fe6060f1SDimitry Andric // non-empty string. 6204eeddc0SDimitry Andric bool emitMacroRestrictionStr(RISCVPredefinedMacroT PredefinedMacros, 6304eeddc0SDimitry Andric raw_ostream &o); 64fe6060f1SDimitry Andric }; 65fe6060f1SDimitry Andric 66fe6060f1SDimitry Andric } // namespace 67fe6060f1SDimitry Andric 6881ad6265SDimitry Andric static BasicType ParseBasicType(char c) { 6981ad6265SDimitry Andric switch (c) { 70fe6060f1SDimitry Andric case 'c': 7181ad6265SDimitry Andric return BasicType::Int8; 72fe6060f1SDimitry Andric break; 73fe6060f1SDimitry Andric case 's': 7481ad6265SDimitry Andric return BasicType::Int16; 75fe6060f1SDimitry Andric break; 76fe6060f1SDimitry Andric case 'i': 7781ad6265SDimitry Andric return BasicType::Int32; 78fe6060f1SDimitry Andric break; 79fe6060f1SDimitry Andric case 'l': 8081ad6265SDimitry Andric return BasicType::Int64; 81fe6060f1SDimitry Andric break; 82fe6060f1SDimitry Andric case 'x': 8381ad6265SDimitry Andric return BasicType::Float16; 84fe6060f1SDimitry Andric break; 85fe6060f1SDimitry Andric case 'f': 8681ad6265SDimitry Andric return BasicType::Float32; 87fe6060f1SDimitry Andric break; 88fe6060f1SDimitry Andric case 'd': 8981ad6265SDimitry Andric return BasicType::Float64; 90fe6060f1SDimitry Andric break; 9181ad6265SDimitry Andric 92fe6060f1SDimitry Andric default: 9381ad6265SDimitry Andric return BasicType::Unknown; 94fe6060f1SDimitry Andric } 95fe6060f1SDimitry Andric } 96fe6060f1SDimitry Andric 9781ad6265SDimitry Andric void emitCodeGenSwitchBody(const RVVIntrinsic *RVVI, raw_ostream &OS) { 9881ad6265SDimitry Andric if (!RVVI->getIRName().empty()) 9981ad6265SDimitry Andric OS << " ID = Intrinsic::riscv_" + RVVI->getIRName() + ";\n"; 10081ad6265SDimitry Andric if (RVVI->getNF() >= 2) 10181ad6265SDimitry Andric OS << " NF = " + utostr(RVVI->getNF()) + ";\n"; 10281ad6265SDimitry Andric if (RVVI->hasManualCodegen()) { 10381ad6265SDimitry Andric OS << RVVI->getManualCodegen(); 104fe6060f1SDimitry Andric OS << "break;\n"; 105fe6060f1SDimitry Andric return; 106fe6060f1SDimitry Andric } 107fe6060f1SDimitry Andric 108*753f127fSDimitry Andric // Cast pointer operand of vector load intrinsic. 109*753f127fSDimitry Andric for (const auto &I : enumerate(RVVI->getInputTypes())) { 110*753f127fSDimitry Andric if (I.value()->isPointer()) { 111*753f127fSDimitry Andric assert(RVVI->getIntrinsicTypes().front() == -1 && 112*753f127fSDimitry Andric "RVVI should be vector load intrinsic."); 113*753f127fSDimitry Andric OS << " Ops[" << I.index() << "] = Builder.CreateBitCast(Ops["; 114*753f127fSDimitry Andric OS << I.index() << "], ResultType->getPointerTo());\n"; 115*753f127fSDimitry Andric } 116*753f127fSDimitry Andric } 117*753f127fSDimitry Andric 11881ad6265SDimitry Andric if (RVVI->isMasked()) { 11981ad6265SDimitry Andric if (RVVI->hasVL()) { 120fe6060f1SDimitry Andric OS << " std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end() - 1);\n"; 12181ad6265SDimitry Andric if (RVVI->hasPolicyOperand()) 122349cc55cSDimitry Andric OS << " Ops.push_back(ConstantInt::get(Ops.back()->getType()," 123349cc55cSDimitry Andric " TAIL_UNDISTURBED));\n"; 124fe6060f1SDimitry Andric } else { 125fe6060f1SDimitry Andric OS << " std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end());\n"; 126fe6060f1SDimitry Andric } 12781ad6265SDimitry Andric } else { 12881ad6265SDimitry Andric if (RVVI->hasPolicyOperand()) 12981ad6265SDimitry Andric OS << " Ops.push_back(ConstantInt::get(Ops.back()->getType(), " 13081ad6265SDimitry Andric "TAIL_UNDISTURBED));\n"; 13181ad6265SDimitry Andric else if (RVVI->hasPassthruOperand()) { 13281ad6265SDimitry Andric OS << " Ops.push_back(llvm::UndefValue::get(ResultType));\n"; 13381ad6265SDimitry Andric OS << " std::rotate(Ops.rbegin(), Ops.rbegin() + 1, Ops.rend());\n"; 13481ad6265SDimitry Andric } 135fe6060f1SDimitry Andric } 136fe6060f1SDimitry Andric 137fe6060f1SDimitry Andric OS << " IntrinsicTypes = {"; 138fe6060f1SDimitry Andric ListSeparator LS; 13981ad6265SDimitry Andric for (const auto &Idx : RVVI->getIntrinsicTypes()) { 140fe6060f1SDimitry Andric if (Idx == -1) 141fe6060f1SDimitry Andric OS << LS << "ResultType"; 142fe6060f1SDimitry Andric else 143fe6060f1SDimitry Andric OS << LS << "Ops[" << Idx << "]->getType()"; 144fe6060f1SDimitry Andric } 145fe6060f1SDimitry Andric 146fe6060f1SDimitry Andric // VL could be i64 or i32, need to encode it in IntrinsicTypes. VL is 147fe6060f1SDimitry Andric // always last operand. 14881ad6265SDimitry Andric if (RVVI->hasVL()) 149fe6060f1SDimitry Andric OS << ", Ops.back()->getType()"; 150fe6060f1SDimitry Andric OS << "};\n"; 151fe6060f1SDimitry Andric OS << " break;\n"; 152fe6060f1SDimitry Andric } 153fe6060f1SDimitry Andric 15481ad6265SDimitry Andric void emitIntrinsicFuncDef(const RVVIntrinsic &RVVI, raw_ostream &OS) { 155349cc55cSDimitry Andric OS << "__attribute__((__clang_builtin_alias__("; 15681ad6265SDimitry Andric OS << "__builtin_rvv_" << RVVI.getBuiltinName() << ")))\n"; 15781ad6265SDimitry Andric OS << RVVI.getOutputType()->getTypeStr() << " " << RVVI.getName() << "("; 158349cc55cSDimitry Andric // Emit function arguments 15981ad6265SDimitry Andric const RVVTypes &InputTypes = RVVI.getInputTypes(); 160fe6060f1SDimitry Andric if (!InputTypes.empty()) { 161fe6060f1SDimitry Andric ListSeparator LS; 162349cc55cSDimitry Andric for (unsigned i = 0; i < InputTypes.size(); ++i) 163349cc55cSDimitry Andric OS << LS << InputTypes[i]->getTypeStr(); 164fe6060f1SDimitry Andric } 165349cc55cSDimitry Andric OS << ");\n"; 166fe6060f1SDimitry Andric } 167fe6060f1SDimitry Andric 16881ad6265SDimitry Andric void emitOverloadedFuncDef(const RVVIntrinsic &RVVI, raw_ostream &OS) { 169349cc55cSDimitry Andric OS << "__attribute__((__clang_builtin_alias__("; 17081ad6265SDimitry Andric OS << "__builtin_rvv_" << RVVI.getBuiltinName() << ")))\n"; 17181ad6265SDimitry Andric OS << RVVI.getOutputType()->getTypeStr() << " " << RVVI.getOverloadedName() 17281ad6265SDimitry Andric << "("; 173fe6060f1SDimitry Andric // Emit function arguments 17481ad6265SDimitry Andric const RVVTypes &InputTypes = RVVI.getInputTypes(); 175fe6060f1SDimitry Andric if (!InputTypes.empty()) { 176fe6060f1SDimitry Andric ListSeparator LS; 177fe6060f1SDimitry Andric for (unsigned i = 0; i < InputTypes.size(); ++i) 178349cc55cSDimitry Andric OS << LS << InputTypes[i]->getTypeStr(); 179fe6060f1SDimitry Andric } 180349cc55cSDimitry Andric OS << ");\n"; 181fe6060f1SDimitry Andric } 182fe6060f1SDimitry Andric 183fe6060f1SDimitry Andric //===----------------------------------------------------------------------===// 184fe6060f1SDimitry Andric // RVVEmitter implementation 185fe6060f1SDimitry Andric //===----------------------------------------------------------------------===// 186fe6060f1SDimitry Andric void RVVEmitter::createHeader(raw_ostream &OS) { 187fe6060f1SDimitry Andric 188fe6060f1SDimitry Andric OS << "/*===---- riscv_vector.h - RISC-V V-extension RVVIntrinsics " 189fe6060f1SDimitry Andric "-------------------===\n" 190fe6060f1SDimitry Andric " *\n" 191fe6060f1SDimitry Andric " *\n" 192fe6060f1SDimitry Andric " * Part of the LLVM Project, under the Apache License v2.0 with LLVM " 193fe6060f1SDimitry Andric "Exceptions.\n" 194fe6060f1SDimitry Andric " * See https://llvm.org/LICENSE.txt for license information.\n" 195fe6060f1SDimitry Andric " * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception\n" 196fe6060f1SDimitry Andric " *\n" 197fe6060f1SDimitry Andric " *===-----------------------------------------------------------------" 198fe6060f1SDimitry Andric "------===\n" 199fe6060f1SDimitry Andric " */\n\n"; 200fe6060f1SDimitry Andric 201fe6060f1SDimitry Andric OS << "#ifndef __RISCV_VECTOR_H\n"; 202fe6060f1SDimitry Andric OS << "#define __RISCV_VECTOR_H\n\n"; 203fe6060f1SDimitry Andric 204fe6060f1SDimitry Andric OS << "#include <stdint.h>\n"; 205fe6060f1SDimitry Andric OS << "#include <stddef.h>\n\n"; 206fe6060f1SDimitry Andric 207fe6060f1SDimitry Andric OS << "#ifndef __riscv_vector\n"; 208fe6060f1SDimitry Andric OS << "#error \"Vector intrinsics require the vector extension.\"\n"; 209fe6060f1SDimitry Andric OS << "#endif\n\n"; 210fe6060f1SDimitry Andric 211fe6060f1SDimitry Andric OS << "#ifdef __cplusplus\n"; 212fe6060f1SDimitry Andric OS << "extern \"C\" {\n"; 213fe6060f1SDimitry Andric OS << "#endif\n\n"; 214fe6060f1SDimitry Andric 21581ad6265SDimitry Andric printHeaderCode(OS); 216349cc55cSDimitry Andric 217fe6060f1SDimitry Andric std::vector<std::unique_ptr<RVVIntrinsic>> Defs; 218fe6060f1SDimitry Andric createRVVIntrinsics(Defs); 219fe6060f1SDimitry Andric 220fe6060f1SDimitry Andric auto printType = [&](auto T) { 221fe6060f1SDimitry Andric OS << "typedef " << T->getClangBuiltinStr() << " " << T->getTypeStr() 222fe6060f1SDimitry Andric << ";\n"; 223fe6060f1SDimitry Andric }; 224fe6060f1SDimitry Andric 225fe6060f1SDimitry Andric constexpr int Log2LMULs[] = {-3, -2, -1, 0, 1, 2, 3}; 226fe6060f1SDimitry Andric // Print RVV boolean types. 227fe6060f1SDimitry Andric for (int Log2LMUL : Log2LMULs) { 22881ad6265SDimitry Andric auto T = RVVType::computeType(BasicType::Int8, Log2LMUL, 22981ad6265SDimitry Andric PrototypeDescriptor::Mask); 23081ad6265SDimitry Andric if (T) 231*753f127fSDimitry Andric printType(T.value()); 232fe6060f1SDimitry Andric } 233fe6060f1SDimitry Andric // Print RVV int/float types. 234fe6060f1SDimitry Andric for (char I : StringRef("csil")) { 23581ad6265SDimitry Andric BasicType BT = ParseBasicType(I); 236fe6060f1SDimitry Andric for (int Log2LMUL : Log2LMULs) { 23781ad6265SDimitry Andric auto T = RVVType::computeType(BT, Log2LMUL, PrototypeDescriptor::Vector); 23881ad6265SDimitry Andric if (T) { 239*753f127fSDimitry Andric printType(T.value()); 24081ad6265SDimitry Andric auto UT = RVVType::computeType( 24181ad6265SDimitry Andric BT, Log2LMUL, 24281ad6265SDimitry Andric PrototypeDescriptor(BaseTypeModifier::Vector, 24381ad6265SDimitry Andric VectorTypeModifier::NoModifier, 24481ad6265SDimitry Andric TypeModifier::UnsignedInteger)); 245*753f127fSDimitry Andric printType(UT.value()); 246fe6060f1SDimitry Andric } 247fe6060f1SDimitry Andric } 248fe6060f1SDimitry Andric } 24981ad6265SDimitry Andric OS << "#if defined(__riscv_zvfh)\n"; 250fe6060f1SDimitry Andric for (int Log2LMUL : Log2LMULs) { 25181ad6265SDimitry Andric auto T = RVVType::computeType(BasicType::Float16, Log2LMUL, 25281ad6265SDimitry Andric PrototypeDescriptor::Vector); 25381ad6265SDimitry Andric if (T) 254*753f127fSDimitry Andric printType(T.value()); 255fe6060f1SDimitry Andric } 256fe6060f1SDimitry Andric OS << "#endif\n"; 257fe6060f1SDimitry Andric 258fe6060f1SDimitry Andric OS << "#if defined(__riscv_f)\n"; 259fe6060f1SDimitry Andric for (int Log2LMUL : Log2LMULs) { 26081ad6265SDimitry Andric auto T = RVVType::computeType(BasicType::Float32, Log2LMUL, 26181ad6265SDimitry Andric PrototypeDescriptor::Vector); 26281ad6265SDimitry Andric if (T) 263*753f127fSDimitry Andric printType(T.value()); 264fe6060f1SDimitry Andric } 265fe6060f1SDimitry Andric OS << "#endif\n"; 266fe6060f1SDimitry Andric 267fe6060f1SDimitry Andric OS << "#if defined(__riscv_d)\n"; 268fe6060f1SDimitry Andric for (int Log2LMUL : Log2LMULs) { 26981ad6265SDimitry Andric auto T = RVVType::computeType(BasicType::Float64, Log2LMUL, 27081ad6265SDimitry Andric PrototypeDescriptor::Vector); 27181ad6265SDimitry Andric if (T) 272*753f127fSDimitry Andric printType(T.value()); 273fe6060f1SDimitry Andric } 274fe6060f1SDimitry Andric OS << "#endif\n\n"; 275fe6060f1SDimitry Andric 276fe6060f1SDimitry Andric // The same extension include in the same arch guard marco. 277349cc55cSDimitry Andric llvm::stable_sort(Defs, [](const std::unique_ptr<RVVIntrinsic> &A, 278fe6060f1SDimitry Andric const std::unique_ptr<RVVIntrinsic> &B) { 27904eeddc0SDimitry Andric return A->getRISCVPredefinedMacros() < B->getRISCVPredefinedMacros(); 280fe6060f1SDimitry Andric }); 281fe6060f1SDimitry Andric 282349cc55cSDimitry Andric OS << "#define __rvv_ai static __inline__\n"; 283349cc55cSDimitry Andric 284fe6060f1SDimitry Andric // Print intrinsic functions with macro 285fe6060f1SDimitry Andric emitArchMacroAndBody(Defs, OS, [](raw_ostream &OS, const RVVIntrinsic &Inst) { 286349cc55cSDimitry Andric OS << "__rvv_ai "; 28781ad6265SDimitry Andric emitIntrinsicFuncDef(Inst, OS); 288fe6060f1SDimitry Andric }); 289fe6060f1SDimitry Andric 290349cc55cSDimitry Andric OS << "#undef __rvv_ai\n\n"; 291349cc55cSDimitry Andric 292fe6060f1SDimitry Andric OS << "#define __riscv_v_intrinsic_overloading 1\n"; 293fe6060f1SDimitry Andric 294fe6060f1SDimitry Andric // Print Overloaded APIs 295349cc55cSDimitry Andric OS << "#define __rvv_aio static __inline__ " 296349cc55cSDimitry Andric "__attribute__((__overloadable__))\n"; 297fe6060f1SDimitry Andric 298fe6060f1SDimitry Andric emitArchMacroAndBody(Defs, OS, [](raw_ostream &OS, const RVVIntrinsic &Inst) { 29981ad6265SDimitry Andric if (!Inst.isMasked() && !Inst.hasUnMaskedOverloaded()) 300fe6060f1SDimitry Andric return; 301349cc55cSDimitry Andric OS << "__rvv_aio "; 30281ad6265SDimitry Andric emitOverloadedFuncDef(Inst, OS); 303fe6060f1SDimitry Andric }); 304fe6060f1SDimitry Andric 305349cc55cSDimitry Andric OS << "#undef __rvv_aio\n"; 306349cc55cSDimitry Andric 307fe6060f1SDimitry Andric OS << "\n#ifdef __cplusplus\n"; 308fe6060f1SDimitry Andric OS << "}\n"; 309349cc55cSDimitry Andric OS << "#endif // __cplusplus\n"; 310fe6060f1SDimitry Andric OS << "#endif // __RISCV_VECTOR_H\n"; 311fe6060f1SDimitry Andric } 312fe6060f1SDimitry Andric 313fe6060f1SDimitry Andric void RVVEmitter::createBuiltins(raw_ostream &OS) { 314fe6060f1SDimitry Andric std::vector<std::unique_ptr<RVVIntrinsic>> Defs; 315fe6060f1SDimitry Andric createRVVIntrinsics(Defs); 316fe6060f1SDimitry Andric 317349cc55cSDimitry Andric // Map to keep track of which builtin names have already been emitted. 318349cc55cSDimitry Andric StringMap<RVVIntrinsic *> BuiltinMap; 319349cc55cSDimitry Andric 320fe6060f1SDimitry Andric OS << "#if defined(TARGET_BUILTIN) && !defined(RISCVV_BUILTIN)\n"; 321fe6060f1SDimitry Andric OS << "#define RISCVV_BUILTIN(ID, TYPE, ATTRS) TARGET_BUILTIN(ID, TYPE, " 32281ad6265SDimitry Andric "ATTRS, \"zve32x\")\n"; 323fe6060f1SDimitry Andric OS << "#endif\n"; 324fe6060f1SDimitry Andric for (auto &Def : Defs) { 325349cc55cSDimitry Andric auto P = 326349cc55cSDimitry Andric BuiltinMap.insert(std::make_pair(Def->getBuiltinName(), Def.get())); 327349cc55cSDimitry Andric if (!P.second) { 32881ad6265SDimitry Andric // Verf that this would have produced the same builtin definition. 32981ad6265SDimitry Andric if (P.first->second->hasBuiltinAlias() != Def->hasBuiltinAlias()) 330349cc55cSDimitry Andric PrintFatalError("Builtin with same name has different hasAutoDef"); 33181ad6265SDimitry Andric else if (!Def->hasBuiltinAlias() && 33281ad6265SDimitry Andric P.first->second->getBuiltinTypeStr() != Def->getBuiltinTypeStr()) 333349cc55cSDimitry Andric PrintFatalError("Builtin with same name has different type string"); 334349cc55cSDimitry Andric continue; 335349cc55cSDimitry Andric } 336349cc55cSDimitry Andric OS << "RISCVV_BUILTIN(__builtin_rvv_" << Def->getBuiltinName() << ",\""; 33781ad6265SDimitry Andric if (!Def->hasBuiltinAlias()) 338349cc55cSDimitry Andric OS << Def->getBuiltinTypeStr(); 339349cc55cSDimitry Andric OS << "\", \"n\")\n"; 340fe6060f1SDimitry Andric } 341fe6060f1SDimitry Andric OS << "#undef RISCVV_BUILTIN\n"; 342fe6060f1SDimitry Andric } 343fe6060f1SDimitry Andric 344fe6060f1SDimitry Andric void RVVEmitter::createCodeGen(raw_ostream &OS) { 345fe6060f1SDimitry Andric std::vector<std::unique_ptr<RVVIntrinsic>> Defs; 346fe6060f1SDimitry Andric createRVVIntrinsics(Defs); 347fe6060f1SDimitry Andric // IR name could be empty, use the stable sort preserves the relative order. 348349cc55cSDimitry Andric llvm::stable_sort(Defs, [](const std::unique_ptr<RVVIntrinsic> &A, 349fe6060f1SDimitry Andric const std::unique_ptr<RVVIntrinsic> &B) { 350fe6060f1SDimitry Andric return A->getIRName() < B->getIRName(); 351fe6060f1SDimitry Andric }); 352349cc55cSDimitry Andric 353349cc55cSDimitry Andric // Map to keep track of which builtin names have already been emitted. 354349cc55cSDimitry Andric StringMap<RVVIntrinsic *> BuiltinMap; 355349cc55cSDimitry Andric 356fe6060f1SDimitry Andric // Print switch body when the ir name or ManualCodegen changes from previous 357fe6060f1SDimitry Andric // iteration. 358fe6060f1SDimitry Andric RVVIntrinsic *PrevDef = Defs.begin()->get(); 359fe6060f1SDimitry Andric for (auto &Def : Defs) { 360fe6060f1SDimitry Andric StringRef CurIRName = Def->getIRName(); 361fe6060f1SDimitry Andric if (CurIRName != PrevDef->getIRName() || 362fe6060f1SDimitry Andric (Def->getManualCodegen() != PrevDef->getManualCodegen())) { 36381ad6265SDimitry Andric emitCodeGenSwitchBody(PrevDef, OS); 364fe6060f1SDimitry Andric } 365fe6060f1SDimitry Andric PrevDef = Def.get(); 366349cc55cSDimitry Andric 367349cc55cSDimitry Andric auto P = 368349cc55cSDimitry Andric BuiltinMap.insert(std::make_pair(Def->getBuiltinName(), Def.get())); 369349cc55cSDimitry Andric if (P.second) { 370349cc55cSDimitry Andric OS << "case RISCVVector::BI__builtin_rvv_" << Def->getBuiltinName() 371349cc55cSDimitry Andric << ":\n"; 372349cc55cSDimitry Andric continue; 373349cc55cSDimitry Andric } 374349cc55cSDimitry Andric 375349cc55cSDimitry Andric if (P.first->second->getIRName() != Def->getIRName()) 376349cc55cSDimitry Andric PrintFatalError("Builtin with same name has different IRName"); 377349cc55cSDimitry Andric else if (P.first->second->getManualCodegen() != Def->getManualCodegen()) 378349cc55cSDimitry Andric PrintFatalError("Builtin with same name has different ManualCodegen"); 379349cc55cSDimitry Andric else if (P.first->second->getNF() != Def->getNF()) 380349cc55cSDimitry Andric PrintFatalError("Builtin with same name has different NF"); 38181ad6265SDimitry Andric else if (P.first->second->isMasked() != Def->isMasked()) 38281ad6265SDimitry Andric PrintFatalError("Builtin with same name has different isMasked"); 383349cc55cSDimitry Andric else if (P.first->second->hasVL() != Def->hasVL()) 38481ad6265SDimitry Andric PrintFatalError("Builtin with same name has different hasVL"); 38581ad6265SDimitry Andric else if (P.first->second->getPolicyScheme() != Def->getPolicyScheme()) 38681ad6265SDimitry Andric PrintFatalError("Builtin with same name has different getPolicyScheme"); 387349cc55cSDimitry Andric else if (P.first->second->getIntrinsicTypes() != Def->getIntrinsicTypes()) 388349cc55cSDimitry Andric PrintFatalError("Builtin with same name has different IntrinsicTypes"); 389fe6060f1SDimitry Andric } 39081ad6265SDimitry Andric emitCodeGenSwitchBody(Defs.back().get(), OS); 391fe6060f1SDimitry Andric OS << "\n"; 392fe6060f1SDimitry Andric } 393fe6060f1SDimitry Andric 394fe6060f1SDimitry Andric void RVVEmitter::createRVVIntrinsics( 395fe6060f1SDimitry Andric std::vector<std::unique_ptr<RVVIntrinsic>> &Out) { 396fe6060f1SDimitry Andric std::vector<Record *> RV = Records.getAllDerivedDefinitions("RVVBuiltin"); 397fe6060f1SDimitry Andric for (auto *R : RV) { 398fe6060f1SDimitry Andric StringRef Name = R->getValueAsString("Name"); 399fe6060f1SDimitry Andric StringRef SuffixProto = R->getValueAsString("Suffix"); 40081ad6265SDimitry Andric StringRef OverloadedName = R->getValueAsString("OverloadedName"); 40181ad6265SDimitry Andric StringRef OverloadedSuffixProto = R->getValueAsString("OverloadedSuffix"); 402fe6060f1SDimitry Andric StringRef Prototypes = R->getValueAsString("Prototype"); 403fe6060f1SDimitry Andric StringRef TypeRange = R->getValueAsString("TypeRange"); 40481ad6265SDimitry Andric bool HasMasked = R->getValueAsBit("HasMasked"); 405fe6060f1SDimitry Andric bool HasMaskedOffOperand = R->getValueAsBit("HasMaskedOffOperand"); 406fe6060f1SDimitry Andric bool HasVL = R->getValueAsBit("HasVL"); 40781ad6265SDimitry Andric Record *MaskedPolicyRecord = R->getValueAsDef("MaskedPolicy"); 40881ad6265SDimitry Andric PolicyScheme MaskedPolicy = 40981ad6265SDimitry Andric static_cast<PolicyScheme>(MaskedPolicyRecord->getValueAsInt("Value")); 41081ad6265SDimitry Andric Record *UnMaskedPolicyRecord = R->getValueAsDef("UnMaskedPolicy"); 41181ad6265SDimitry Andric PolicyScheme UnMaskedPolicy = 41281ad6265SDimitry Andric static_cast<PolicyScheme>(UnMaskedPolicyRecord->getValueAsInt("Value")); 41381ad6265SDimitry Andric bool HasUnMaskedOverloaded = R->getValueAsBit("HasUnMaskedOverloaded"); 414fe6060f1SDimitry Andric std::vector<int64_t> Log2LMULList = R->getValueAsListOfInts("Log2LMUL"); 41581ad6265SDimitry Andric bool HasBuiltinAlias = R->getValueAsBit("HasBuiltinAlias"); 416fe6060f1SDimitry Andric StringRef ManualCodegen = R->getValueAsString("ManualCodegen"); 41781ad6265SDimitry Andric StringRef MaskedManualCodegen = R->getValueAsString("MaskedManualCodegen"); 418fe6060f1SDimitry Andric std::vector<int64_t> IntrinsicTypes = 419fe6060f1SDimitry Andric R->getValueAsListOfInts("IntrinsicTypes"); 42004eeddc0SDimitry Andric std::vector<StringRef> RequiredFeatures = 42104eeddc0SDimitry Andric R->getValueAsListOfStrings("RequiredFeatures"); 422fe6060f1SDimitry Andric StringRef IRName = R->getValueAsString("IRName"); 42381ad6265SDimitry Andric StringRef MaskedIRName = R->getValueAsString("MaskedIRName"); 424fe6060f1SDimitry Andric unsigned NF = R->getValueAsInt("NF"); 425fe6060f1SDimitry Andric 426fe6060f1SDimitry Andric // Parse prototype and create a list of primitive type with transformers 42781ad6265SDimitry Andric // (operand) in Prototype. Prototype[0] is output operand. 42881ad6265SDimitry Andric SmallVector<PrototypeDescriptor> Prototype = parsePrototypes(Prototypes); 42981ad6265SDimitry Andric 43081ad6265SDimitry Andric SmallVector<PrototypeDescriptor> SuffixDesc = parsePrototypes(SuffixProto); 43181ad6265SDimitry Andric SmallVector<PrototypeDescriptor> OverloadedSuffixDesc = 43281ad6265SDimitry Andric parsePrototypes(OverloadedSuffixProto); 433fe6060f1SDimitry Andric 434fe6060f1SDimitry Andric // Compute Builtin types 43581ad6265SDimitry Andric SmallVector<PrototypeDescriptor> MaskedPrototype = Prototype; 43681ad6265SDimitry Andric if (HasMasked) { 437fe6060f1SDimitry Andric // If HasMaskedOffOperand, insert result type as first input operand. 438fe6060f1SDimitry Andric if (HasMaskedOffOperand) { 439fe6060f1SDimitry Andric if (NF == 1) { 44081ad6265SDimitry Andric MaskedPrototype.insert(MaskedPrototype.begin() + 1, Prototype[0]); 441fe6060f1SDimitry Andric } else { 442fe6060f1SDimitry Andric // Convert 443fe6060f1SDimitry Andric // (void, op0 address, op1 address, ...) 444fe6060f1SDimitry Andric // to 445fe6060f1SDimitry Andric // (void, op0 address, op1 address, ..., maskedoff0, maskedoff1, ...) 44681ad6265SDimitry Andric PrototypeDescriptor MaskoffType = Prototype[1]; 44781ad6265SDimitry Andric MaskoffType.TM &= ~static_cast<uint8_t>(TypeModifier::Pointer); 448fe6060f1SDimitry Andric for (unsigned I = 0; I < NF; ++I) 44981ad6265SDimitry Andric MaskedPrototype.insert(MaskedPrototype.begin() + NF + 1, 45081ad6265SDimitry Andric MaskoffType); 451fe6060f1SDimitry Andric } 452fe6060f1SDimitry Andric } 453fe6060f1SDimitry Andric if (HasMaskedOffOperand && NF > 1) { 454fe6060f1SDimitry Andric // Convert 455fe6060f1SDimitry Andric // (void, op0 address, op1 address, ..., maskedoff0, maskedoff1, ...) 456fe6060f1SDimitry Andric // to 457fe6060f1SDimitry Andric // (void, op0 address, op1 address, ..., mask, maskedoff0, maskedoff1, 458fe6060f1SDimitry Andric // ...) 45981ad6265SDimitry Andric MaskedPrototype.insert(MaskedPrototype.begin() + NF + 1, 46081ad6265SDimitry Andric PrototypeDescriptor::Mask); 461fe6060f1SDimitry Andric } else { 46281ad6265SDimitry Andric // If HasMasked, insert PrototypeDescriptor:Mask as first input operand. 46381ad6265SDimitry Andric MaskedPrototype.insert(MaskedPrototype.begin() + 1, 46481ad6265SDimitry Andric PrototypeDescriptor::Mask); 465fe6060f1SDimitry Andric } 466fe6060f1SDimitry Andric } 46781ad6265SDimitry Andric // If HasVL, append PrototypeDescriptor:VL to last operand 468fe6060f1SDimitry Andric if (HasVL) { 46981ad6265SDimitry Andric Prototype.push_back(PrototypeDescriptor::VL); 47081ad6265SDimitry Andric MaskedPrototype.push_back(PrototypeDescriptor::VL); 471fe6060f1SDimitry Andric } 472fe6060f1SDimitry Andric 473fe6060f1SDimitry Andric // Create Intrinsics for each type and LMUL. 474fe6060f1SDimitry Andric for (char I : TypeRange) { 475fe6060f1SDimitry Andric for (int Log2LMUL : Log2LMULList) { 47681ad6265SDimitry Andric BasicType BT = ParseBasicType(I); 47781ad6265SDimitry Andric Optional<RVVTypes> Types = 47881ad6265SDimitry Andric RVVType::computeTypes(BT, Log2LMUL, NF, Prototype); 479fe6060f1SDimitry Andric // Ignored to create new intrinsic if there are any illegal types. 48081ad6265SDimitry Andric if (!Types) 481fe6060f1SDimitry Andric continue; 482fe6060f1SDimitry Andric 48381ad6265SDimitry Andric auto SuffixStr = RVVIntrinsic::getSuffixStr(BT, Log2LMUL, SuffixDesc); 48481ad6265SDimitry Andric auto OverloadedSuffixStr = 48581ad6265SDimitry Andric RVVIntrinsic::getSuffixStr(BT, Log2LMUL, OverloadedSuffixDesc); 48681ad6265SDimitry Andric // Create a unmasked intrinsic 487fe6060f1SDimitry Andric Out.push_back(std::make_unique<RVVIntrinsic>( 48881ad6265SDimitry Andric Name, SuffixStr, OverloadedName, OverloadedSuffixStr, IRName, 48981ad6265SDimitry Andric /*IsMasked=*/false, /*HasMaskedOffOperand=*/false, HasVL, 49081ad6265SDimitry Andric UnMaskedPolicy, HasUnMaskedOverloaded, HasBuiltinAlias, 49181ad6265SDimitry Andric ManualCodegen, *Types, IntrinsicTypes, RequiredFeatures, NF)); 49281ad6265SDimitry Andric if (HasMasked) { 49381ad6265SDimitry Andric // Create a masked intrinsic 494fe6060f1SDimitry Andric Optional<RVVTypes> MaskTypes = 49581ad6265SDimitry Andric RVVType::computeTypes(BT, Log2LMUL, NF, MaskedPrototype); 496fe6060f1SDimitry Andric Out.push_back(std::make_unique<RVVIntrinsic>( 49781ad6265SDimitry Andric Name, SuffixStr, OverloadedName, OverloadedSuffixStr, 49881ad6265SDimitry Andric MaskedIRName, 49981ad6265SDimitry Andric /*IsMasked=*/true, HasMaskedOffOperand, HasVL, MaskedPolicy, 50081ad6265SDimitry Andric HasUnMaskedOverloaded, HasBuiltinAlias, MaskedManualCodegen, 50181ad6265SDimitry Andric *MaskTypes, IntrinsicTypes, RequiredFeatures, NF)); 502fe6060f1SDimitry Andric } 503fe6060f1SDimitry Andric } // end for Log2LMULList 504fe6060f1SDimitry Andric } // end for TypeRange 505fe6060f1SDimitry Andric } 506fe6060f1SDimitry Andric } 507fe6060f1SDimitry Andric 50881ad6265SDimitry Andric void RVVEmitter::printHeaderCode(raw_ostream &OS) { 509349cc55cSDimitry Andric std::vector<Record *> RVVHeaders = 510349cc55cSDimitry Andric Records.getAllDerivedDefinitions("RVVHeader"); 511349cc55cSDimitry Andric for (auto *R : RVVHeaders) { 512349cc55cSDimitry Andric StringRef HeaderCodeStr = R->getValueAsString("HeaderCode"); 513349cc55cSDimitry Andric OS << HeaderCodeStr.str(); 514349cc55cSDimitry Andric } 515349cc55cSDimitry Andric } 516349cc55cSDimitry Andric 517fe6060f1SDimitry Andric void RVVEmitter::emitArchMacroAndBody( 518fe6060f1SDimitry Andric std::vector<std::unique_ptr<RVVIntrinsic>> &Defs, raw_ostream &OS, 519fe6060f1SDimitry Andric std::function<void(raw_ostream &, const RVVIntrinsic &)> PrintBody) { 52004eeddc0SDimitry Andric RISCVPredefinedMacroT PrevMacros = 52104eeddc0SDimitry Andric (*Defs.begin())->getRISCVPredefinedMacros(); 52204eeddc0SDimitry Andric bool NeedEndif = emitMacroRestrictionStr(PrevMacros, OS); 523fe6060f1SDimitry Andric for (auto &Def : Defs) { 52404eeddc0SDimitry Andric RISCVPredefinedMacroT CurMacros = Def->getRISCVPredefinedMacros(); 52504eeddc0SDimitry Andric if (CurMacros != PrevMacros) { 526fe6060f1SDimitry Andric if (NeedEndif) 527fe6060f1SDimitry Andric OS << "#endif\n\n"; 52804eeddc0SDimitry Andric NeedEndif = emitMacroRestrictionStr(CurMacros, OS); 52904eeddc0SDimitry Andric PrevMacros = CurMacros; 530fe6060f1SDimitry Andric } 53181ad6265SDimitry Andric if (Def->hasBuiltinAlias()) 532fe6060f1SDimitry Andric PrintBody(OS, *Def); 533fe6060f1SDimitry Andric } 534fe6060f1SDimitry Andric if (NeedEndif) 535fe6060f1SDimitry Andric OS << "#endif\n\n"; 536fe6060f1SDimitry Andric } 537fe6060f1SDimitry Andric 53804eeddc0SDimitry Andric bool RVVEmitter::emitMacroRestrictionStr(RISCVPredefinedMacroT PredefinedMacros, 53904eeddc0SDimitry Andric raw_ostream &OS) { 54004eeddc0SDimitry Andric if (PredefinedMacros == RISCVPredefinedMacro::Basic) 541fe6060f1SDimitry Andric return false; 542fe6060f1SDimitry Andric OS << "#if "; 543fe6060f1SDimitry Andric ListSeparator LS(" && "); 54404eeddc0SDimitry Andric if (PredefinedMacros & RISCVPredefinedMacro::V) 54504eeddc0SDimitry Andric OS << LS << "defined(__riscv_v)"; 54681ad6265SDimitry Andric if (PredefinedMacros & RISCVPredefinedMacro::Zvfh) 54781ad6265SDimitry Andric OS << LS << "defined(__riscv_zvfh)"; 54804eeddc0SDimitry Andric if (PredefinedMacros & RISCVPredefinedMacro::RV64) 54904eeddc0SDimitry Andric OS << LS << "(__riscv_xlen == 64)"; 55004eeddc0SDimitry Andric if (PredefinedMacros & RISCVPredefinedMacro::VectorMaxELen64) 55104eeddc0SDimitry Andric OS << LS << "(__riscv_v_elen >= 64)"; 55204eeddc0SDimitry Andric if (PredefinedMacros & RISCVPredefinedMacro::VectorMaxELenFp32) 55304eeddc0SDimitry Andric OS << LS << "(__riscv_v_elen_fp >= 32)"; 55404eeddc0SDimitry Andric if (PredefinedMacros & RISCVPredefinedMacro::VectorMaxELenFp64) 55504eeddc0SDimitry Andric OS << LS << "(__riscv_v_elen_fp >= 64)"; 556fe6060f1SDimitry Andric OS << "\n"; 557fe6060f1SDimitry Andric return true; 558fe6060f1SDimitry Andric } 559fe6060f1SDimitry Andric 560fe6060f1SDimitry Andric namespace clang { 561fe6060f1SDimitry Andric void EmitRVVHeader(RecordKeeper &Records, raw_ostream &OS) { 562fe6060f1SDimitry Andric RVVEmitter(Records).createHeader(OS); 563fe6060f1SDimitry Andric } 564fe6060f1SDimitry Andric 565fe6060f1SDimitry Andric void EmitRVVBuiltins(RecordKeeper &Records, raw_ostream &OS) { 566fe6060f1SDimitry Andric RVVEmitter(Records).createBuiltins(OS); 567fe6060f1SDimitry Andric } 568fe6060f1SDimitry Andric 569fe6060f1SDimitry Andric void EmitRVVBuiltinCG(RecordKeeper &Records, raw_ostream &OS) { 570fe6060f1SDimitry Andric RVVEmitter(Records).createCodeGen(OS); 571fe6060f1SDimitry Andric } 572fe6060f1SDimitry Andric 573fe6060f1SDimitry Andric } // End namespace clang 574