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 17*81ad6265SDimitry 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; 29*81ad6265SDimitry 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); 51*81ad6265SDimitry Andric /// Print HeaderCode in RVVHeader Record to \p Out 52*81ad6265SDimitry 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 68*81ad6265SDimitry Andric static BasicType ParseBasicType(char c) { 69*81ad6265SDimitry Andric switch (c) { 70fe6060f1SDimitry Andric case 'c': 71*81ad6265SDimitry Andric return BasicType::Int8; 72fe6060f1SDimitry Andric break; 73fe6060f1SDimitry Andric case 's': 74*81ad6265SDimitry Andric return BasicType::Int16; 75fe6060f1SDimitry Andric break; 76fe6060f1SDimitry Andric case 'i': 77*81ad6265SDimitry Andric return BasicType::Int32; 78fe6060f1SDimitry Andric break; 79fe6060f1SDimitry Andric case 'l': 80*81ad6265SDimitry Andric return BasicType::Int64; 81fe6060f1SDimitry Andric break; 82fe6060f1SDimitry Andric case 'x': 83*81ad6265SDimitry Andric return BasicType::Float16; 84fe6060f1SDimitry Andric break; 85fe6060f1SDimitry Andric case 'f': 86*81ad6265SDimitry Andric return BasicType::Float32; 87fe6060f1SDimitry Andric break; 88fe6060f1SDimitry Andric case 'd': 89*81ad6265SDimitry Andric return BasicType::Float64; 90fe6060f1SDimitry Andric break; 91*81ad6265SDimitry Andric 92fe6060f1SDimitry Andric default: 93*81ad6265SDimitry Andric return BasicType::Unknown; 94fe6060f1SDimitry Andric } 95fe6060f1SDimitry Andric } 96fe6060f1SDimitry Andric 97*81ad6265SDimitry Andric void emitCodeGenSwitchBody(const RVVIntrinsic *RVVI, raw_ostream &OS) { 98*81ad6265SDimitry Andric if (!RVVI->getIRName().empty()) 99*81ad6265SDimitry Andric OS << " ID = Intrinsic::riscv_" + RVVI->getIRName() + ";\n"; 100*81ad6265SDimitry Andric if (RVVI->getNF() >= 2) 101*81ad6265SDimitry Andric OS << " NF = " + utostr(RVVI->getNF()) + ";\n"; 102*81ad6265SDimitry Andric if (RVVI->hasManualCodegen()) { 103*81ad6265SDimitry Andric OS << RVVI->getManualCodegen(); 104fe6060f1SDimitry Andric OS << "break;\n"; 105fe6060f1SDimitry Andric return; 106fe6060f1SDimitry Andric } 107fe6060f1SDimitry Andric 108*81ad6265SDimitry Andric if (RVVI->isMasked()) { 109*81ad6265SDimitry Andric if (RVVI->hasVL()) { 110fe6060f1SDimitry Andric OS << " std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end() - 1);\n"; 111*81ad6265SDimitry Andric if (RVVI->hasPolicyOperand()) 112349cc55cSDimitry Andric OS << " Ops.push_back(ConstantInt::get(Ops.back()->getType()," 113349cc55cSDimitry Andric " TAIL_UNDISTURBED));\n"; 114fe6060f1SDimitry Andric } else { 115fe6060f1SDimitry Andric OS << " std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end());\n"; 116fe6060f1SDimitry Andric } 117*81ad6265SDimitry Andric } else { 118*81ad6265SDimitry Andric if (RVVI->hasPolicyOperand()) 119*81ad6265SDimitry Andric OS << " Ops.push_back(ConstantInt::get(Ops.back()->getType(), " 120*81ad6265SDimitry Andric "TAIL_UNDISTURBED));\n"; 121*81ad6265SDimitry Andric else if (RVVI->hasPassthruOperand()) { 122*81ad6265SDimitry Andric OS << " Ops.push_back(llvm::UndefValue::get(ResultType));\n"; 123*81ad6265SDimitry Andric OS << " std::rotate(Ops.rbegin(), Ops.rbegin() + 1, Ops.rend());\n"; 124*81ad6265SDimitry Andric } 125fe6060f1SDimitry Andric } 126fe6060f1SDimitry Andric 127fe6060f1SDimitry Andric OS << " IntrinsicTypes = {"; 128fe6060f1SDimitry Andric ListSeparator LS; 129*81ad6265SDimitry Andric for (const auto &Idx : RVVI->getIntrinsicTypes()) { 130fe6060f1SDimitry Andric if (Idx == -1) 131fe6060f1SDimitry Andric OS << LS << "ResultType"; 132fe6060f1SDimitry Andric else 133fe6060f1SDimitry Andric OS << LS << "Ops[" << Idx << "]->getType()"; 134fe6060f1SDimitry Andric } 135fe6060f1SDimitry Andric 136fe6060f1SDimitry Andric // VL could be i64 or i32, need to encode it in IntrinsicTypes. VL is 137fe6060f1SDimitry Andric // always last operand. 138*81ad6265SDimitry Andric if (RVVI->hasVL()) 139fe6060f1SDimitry Andric OS << ", Ops.back()->getType()"; 140fe6060f1SDimitry Andric OS << "};\n"; 141fe6060f1SDimitry Andric OS << " break;\n"; 142fe6060f1SDimitry Andric } 143fe6060f1SDimitry Andric 144*81ad6265SDimitry Andric void emitIntrinsicFuncDef(const RVVIntrinsic &RVVI, raw_ostream &OS) { 145349cc55cSDimitry Andric OS << "__attribute__((__clang_builtin_alias__("; 146*81ad6265SDimitry Andric OS << "__builtin_rvv_" << RVVI.getBuiltinName() << ")))\n"; 147*81ad6265SDimitry Andric OS << RVVI.getOutputType()->getTypeStr() << " " << RVVI.getName() << "("; 148349cc55cSDimitry Andric // Emit function arguments 149*81ad6265SDimitry Andric const RVVTypes &InputTypes = RVVI.getInputTypes(); 150fe6060f1SDimitry Andric if (!InputTypes.empty()) { 151fe6060f1SDimitry Andric ListSeparator LS; 152349cc55cSDimitry Andric for (unsigned i = 0; i < InputTypes.size(); ++i) 153349cc55cSDimitry Andric OS << LS << InputTypes[i]->getTypeStr(); 154fe6060f1SDimitry Andric } 155349cc55cSDimitry Andric OS << ");\n"; 156fe6060f1SDimitry Andric } 157fe6060f1SDimitry Andric 158*81ad6265SDimitry Andric void emitOverloadedFuncDef(const RVVIntrinsic &RVVI, raw_ostream &OS) { 159349cc55cSDimitry Andric OS << "__attribute__((__clang_builtin_alias__("; 160*81ad6265SDimitry Andric OS << "__builtin_rvv_" << RVVI.getBuiltinName() << ")))\n"; 161*81ad6265SDimitry Andric OS << RVVI.getOutputType()->getTypeStr() << " " << RVVI.getOverloadedName() 162*81ad6265SDimitry Andric << "("; 163fe6060f1SDimitry Andric // Emit function arguments 164*81ad6265SDimitry Andric const RVVTypes &InputTypes = RVVI.getInputTypes(); 165fe6060f1SDimitry Andric if (!InputTypes.empty()) { 166fe6060f1SDimitry Andric ListSeparator LS; 167fe6060f1SDimitry Andric for (unsigned i = 0; i < InputTypes.size(); ++i) 168349cc55cSDimitry Andric OS << LS << InputTypes[i]->getTypeStr(); 169fe6060f1SDimitry Andric } 170349cc55cSDimitry Andric OS << ");\n"; 171fe6060f1SDimitry Andric } 172fe6060f1SDimitry Andric 173fe6060f1SDimitry Andric //===----------------------------------------------------------------------===// 174fe6060f1SDimitry Andric // RVVEmitter implementation 175fe6060f1SDimitry Andric //===----------------------------------------------------------------------===// 176fe6060f1SDimitry Andric void RVVEmitter::createHeader(raw_ostream &OS) { 177fe6060f1SDimitry Andric 178fe6060f1SDimitry Andric OS << "/*===---- riscv_vector.h - RISC-V V-extension RVVIntrinsics " 179fe6060f1SDimitry Andric "-------------------===\n" 180fe6060f1SDimitry Andric " *\n" 181fe6060f1SDimitry Andric " *\n" 182fe6060f1SDimitry Andric " * Part of the LLVM Project, under the Apache License v2.0 with LLVM " 183fe6060f1SDimitry Andric "Exceptions.\n" 184fe6060f1SDimitry Andric " * See https://llvm.org/LICENSE.txt for license information.\n" 185fe6060f1SDimitry Andric " * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception\n" 186fe6060f1SDimitry Andric " *\n" 187fe6060f1SDimitry Andric " *===-----------------------------------------------------------------" 188fe6060f1SDimitry Andric "------===\n" 189fe6060f1SDimitry Andric " */\n\n"; 190fe6060f1SDimitry Andric 191fe6060f1SDimitry Andric OS << "#ifndef __RISCV_VECTOR_H\n"; 192fe6060f1SDimitry Andric OS << "#define __RISCV_VECTOR_H\n\n"; 193fe6060f1SDimitry Andric 194fe6060f1SDimitry Andric OS << "#include <stdint.h>\n"; 195fe6060f1SDimitry Andric OS << "#include <stddef.h>\n\n"; 196fe6060f1SDimitry Andric 197fe6060f1SDimitry Andric OS << "#ifndef __riscv_vector\n"; 198fe6060f1SDimitry Andric OS << "#error \"Vector intrinsics require the vector extension.\"\n"; 199fe6060f1SDimitry Andric OS << "#endif\n\n"; 200fe6060f1SDimitry Andric 201fe6060f1SDimitry Andric OS << "#ifdef __cplusplus\n"; 202fe6060f1SDimitry Andric OS << "extern \"C\" {\n"; 203fe6060f1SDimitry Andric OS << "#endif\n\n"; 204fe6060f1SDimitry Andric 205*81ad6265SDimitry Andric printHeaderCode(OS); 206349cc55cSDimitry Andric 207fe6060f1SDimitry Andric std::vector<std::unique_ptr<RVVIntrinsic>> Defs; 208fe6060f1SDimitry Andric createRVVIntrinsics(Defs); 209fe6060f1SDimitry Andric 210fe6060f1SDimitry Andric auto printType = [&](auto T) { 211fe6060f1SDimitry Andric OS << "typedef " << T->getClangBuiltinStr() << " " << T->getTypeStr() 212fe6060f1SDimitry Andric << ";\n"; 213fe6060f1SDimitry Andric }; 214fe6060f1SDimitry Andric 215fe6060f1SDimitry Andric constexpr int Log2LMULs[] = {-3, -2, -1, 0, 1, 2, 3}; 216fe6060f1SDimitry Andric // Print RVV boolean types. 217fe6060f1SDimitry Andric for (int Log2LMUL : Log2LMULs) { 218*81ad6265SDimitry Andric auto T = RVVType::computeType(BasicType::Int8, Log2LMUL, 219*81ad6265SDimitry Andric PrototypeDescriptor::Mask); 220*81ad6265SDimitry Andric if (T) 221fe6060f1SDimitry Andric printType(T.getValue()); 222fe6060f1SDimitry Andric } 223fe6060f1SDimitry Andric // Print RVV int/float types. 224fe6060f1SDimitry Andric for (char I : StringRef("csil")) { 225*81ad6265SDimitry Andric BasicType BT = ParseBasicType(I); 226fe6060f1SDimitry Andric for (int Log2LMUL : Log2LMULs) { 227*81ad6265SDimitry Andric auto T = RVVType::computeType(BT, Log2LMUL, PrototypeDescriptor::Vector); 228*81ad6265SDimitry Andric if (T) { 229fe6060f1SDimitry Andric printType(T.getValue()); 230*81ad6265SDimitry Andric auto UT = RVVType::computeType( 231*81ad6265SDimitry Andric BT, Log2LMUL, 232*81ad6265SDimitry Andric PrototypeDescriptor(BaseTypeModifier::Vector, 233*81ad6265SDimitry Andric VectorTypeModifier::NoModifier, 234*81ad6265SDimitry Andric TypeModifier::UnsignedInteger)); 235fe6060f1SDimitry Andric printType(UT.getValue()); 236fe6060f1SDimitry Andric } 237fe6060f1SDimitry Andric } 238fe6060f1SDimitry Andric } 239*81ad6265SDimitry Andric OS << "#if defined(__riscv_zvfh)\n"; 240fe6060f1SDimitry Andric for (int Log2LMUL : Log2LMULs) { 241*81ad6265SDimitry Andric auto T = RVVType::computeType(BasicType::Float16, Log2LMUL, 242*81ad6265SDimitry Andric PrototypeDescriptor::Vector); 243*81ad6265SDimitry Andric if (T) 244fe6060f1SDimitry Andric printType(T.getValue()); 245fe6060f1SDimitry Andric } 246fe6060f1SDimitry Andric OS << "#endif\n"; 247fe6060f1SDimitry Andric 248fe6060f1SDimitry Andric OS << "#if defined(__riscv_f)\n"; 249fe6060f1SDimitry Andric for (int Log2LMUL : Log2LMULs) { 250*81ad6265SDimitry Andric auto T = RVVType::computeType(BasicType::Float32, Log2LMUL, 251*81ad6265SDimitry Andric PrototypeDescriptor::Vector); 252*81ad6265SDimitry Andric if (T) 253fe6060f1SDimitry Andric printType(T.getValue()); 254fe6060f1SDimitry Andric } 255fe6060f1SDimitry Andric OS << "#endif\n"; 256fe6060f1SDimitry Andric 257fe6060f1SDimitry Andric OS << "#if defined(__riscv_d)\n"; 258fe6060f1SDimitry Andric for (int Log2LMUL : Log2LMULs) { 259*81ad6265SDimitry Andric auto T = RVVType::computeType(BasicType::Float64, Log2LMUL, 260*81ad6265SDimitry Andric PrototypeDescriptor::Vector); 261*81ad6265SDimitry Andric if (T) 262fe6060f1SDimitry Andric printType(T.getValue()); 263fe6060f1SDimitry Andric } 264fe6060f1SDimitry Andric OS << "#endif\n\n"; 265fe6060f1SDimitry Andric 266fe6060f1SDimitry Andric // The same extension include in the same arch guard marco. 267349cc55cSDimitry Andric llvm::stable_sort(Defs, [](const std::unique_ptr<RVVIntrinsic> &A, 268fe6060f1SDimitry Andric const std::unique_ptr<RVVIntrinsic> &B) { 26904eeddc0SDimitry Andric return A->getRISCVPredefinedMacros() < B->getRISCVPredefinedMacros(); 270fe6060f1SDimitry Andric }); 271fe6060f1SDimitry Andric 272349cc55cSDimitry Andric OS << "#define __rvv_ai static __inline__\n"; 273349cc55cSDimitry Andric 274fe6060f1SDimitry Andric // Print intrinsic functions with macro 275fe6060f1SDimitry Andric emitArchMacroAndBody(Defs, OS, [](raw_ostream &OS, const RVVIntrinsic &Inst) { 276349cc55cSDimitry Andric OS << "__rvv_ai "; 277*81ad6265SDimitry Andric emitIntrinsicFuncDef(Inst, OS); 278fe6060f1SDimitry Andric }); 279fe6060f1SDimitry Andric 280349cc55cSDimitry Andric OS << "#undef __rvv_ai\n\n"; 281349cc55cSDimitry Andric 282fe6060f1SDimitry Andric OS << "#define __riscv_v_intrinsic_overloading 1\n"; 283fe6060f1SDimitry Andric 284fe6060f1SDimitry Andric // Print Overloaded APIs 285349cc55cSDimitry Andric OS << "#define __rvv_aio static __inline__ " 286349cc55cSDimitry Andric "__attribute__((__overloadable__))\n"; 287fe6060f1SDimitry Andric 288fe6060f1SDimitry Andric emitArchMacroAndBody(Defs, OS, [](raw_ostream &OS, const RVVIntrinsic &Inst) { 289*81ad6265SDimitry Andric if (!Inst.isMasked() && !Inst.hasUnMaskedOverloaded()) 290fe6060f1SDimitry Andric return; 291349cc55cSDimitry Andric OS << "__rvv_aio "; 292*81ad6265SDimitry Andric emitOverloadedFuncDef(Inst, OS); 293fe6060f1SDimitry Andric }); 294fe6060f1SDimitry Andric 295349cc55cSDimitry Andric OS << "#undef __rvv_aio\n"; 296349cc55cSDimitry Andric 297fe6060f1SDimitry Andric OS << "\n#ifdef __cplusplus\n"; 298fe6060f1SDimitry Andric OS << "}\n"; 299349cc55cSDimitry Andric OS << "#endif // __cplusplus\n"; 300fe6060f1SDimitry Andric OS << "#endif // __RISCV_VECTOR_H\n"; 301fe6060f1SDimitry Andric } 302fe6060f1SDimitry Andric 303fe6060f1SDimitry Andric void RVVEmitter::createBuiltins(raw_ostream &OS) { 304fe6060f1SDimitry Andric std::vector<std::unique_ptr<RVVIntrinsic>> Defs; 305fe6060f1SDimitry Andric createRVVIntrinsics(Defs); 306fe6060f1SDimitry Andric 307349cc55cSDimitry Andric // Map to keep track of which builtin names have already been emitted. 308349cc55cSDimitry Andric StringMap<RVVIntrinsic *> BuiltinMap; 309349cc55cSDimitry Andric 310fe6060f1SDimitry Andric OS << "#if defined(TARGET_BUILTIN) && !defined(RISCVV_BUILTIN)\n"; 311fe6060f1SDimitry Andric OS << "#define RISCVV_BUILTIN(ID, TYPE, ATTRS) TARGET_BUILTIN(ID, TYPE, " 312*81ad6265SDimitry Andric "ATTRS, \"zve32x\")\n"; 313fe6060f1SDimitry Andric OS << "#endif\n"; 314fe6060f1SDimitry Andric for (auto &Def : Defs) { 315349cc55cSDimitry Andric auto P = 316349cc55cSDimitry Andric BuiltinMap.insert(std::make_pair(Def->getBuiltinName(), Def.get())); 317349cc55cSDimitry Andric if (!P.second) { 318*81ad6265SDimitry Andric // Verf that this would have produced the same builtin definition. 319*81ad6265SDimitry Andric if (P.first->second->hasBuiltinAlias() != Def->hasBuiltinAlias()) 320349cc55cSDimitry Andric PrintFatalError("Builtin with same name has different hasAutoDef"); 321*81ad6265SDimitry Andric else if (!Def->hasBuiltinAlias() && 322*81ad6265SDimitry Andric P.first->second->getBuiltinTypeStr() != Def->getBuiltinTypeStr()) 323349cc55cSDimitry Andric PrintFatalError("Builtin with same name has different type string"); 324349cc55cSDimitry Andric continue; 325349cc55cSDimitry Andric } 326349cc55cSDimitry Andric OS << "RISCVV_BUILTIN(__builtin_rvv_" << Def->getBuiltinName() << ",\""; 327*81ad6265SDimitry Andric if (!Def->hasBuiltinAlias()) 328349cc55cSDimitry Andric OS << Def->getBuiltinTypeStr(); 329349cc55cSDimitry Andric OS << "\", \"n\")\n"; 330fe6060f1SDimitry Andric } 331fe6060f1SDimitry Andric OS << "#undef RISCVV_BUILTIN\n"; 332fe6060f1SDimitry Andric } 333fe6060f1SDimitry Andric 334fe6060f1SDimitry Andric void RVVEmitter::createCodeGen(raw_ostream &OS) { 335fe6060f1SDimitry Andric std::vector<std::unique_ptr<RVVIntrinsic>> Defs; 336fe6060f1SDimitry Andric createRVVIntrinsics(Defs); 337fe6060f1SDimitry Andric // IR name could be empty, use the stable sort preserves the relative order. 338349cc55cSDimitry Andric llvm::stable_sort(Defs, [](const std::unique_ptr<RVVIntrinsic> &A, 339fe6060f1SDimitry Andric const std::unique_ptr<RVVIntrinsic> &B) { 340fe6060f1SDimitry Andric return A->getIRName() < B->getIRName(); 341fe6060f1SDimitry Andric }); 342349cc55cSDimitry Andric 343349cc55cSDimitry Andric // Map to keep track of which builtin names have already been emitted. 344349cc55cSDimitry Andric StringMap<RVVIntrinsic *> BuiltinMap; 345349cc55cSDimitry Andric 346fe6060f1SDimitry Andric // Print switch body when the ir name or ManualCodegen changes from previous 347fe6060f1SDimitry Andric // iteration. 348fe6060f1SDimitry Andric RVVIntrinsic *PrevDef = Defs.begin()->get(); 349fe6060f1SDimitry Andric for (auto &Def : Defs) { 350fe6060f1SDimitry Andric StringRef CurIRName = Def->getIRName(); 351fe6060f1SDimitry Andric if (CurIRName != PrevDef->getIRName() || 352fe6060f1SDimitry Andric (Def->getManualCodegen() != PrevDef->getManualCodegen())) { 353*81ad6265SDimitry Andric emitCodeGenSwitchBody(PrevDef, OS); 354fe6060f1SDimitry Andric } 355fe6060f1SDimitry Andric PrevDef = Def.get(); 356349cc55cSDimitry Andric 357349cc55cSDimitry Andric auto P = 358349cc55cSDimitry Andric BuiltinMap.insert(std::make_pair(Def->getBuiltinName(), Def.get())); 359349cc55cSDimitry Andric if (P.second) { 360349cc55cSDimitry Andric OS << "case RISCVVector::BI__builtin_rvv_" << Def->getBuiltinName() 361349cc55cSDimitry Andric << ":\n"; 362349cc55cSDimitry Andric continue; 363349cc55cSDimitry Andric } 364349cc55cSDimitry Andric 365349cc55cSDimitry Andric if (P.first->second->getIRName() != Def->getIRName()) 366349cc55cSDimitry Andric PrintFatalError("Builtin with same name has different IRName"); 367349cc55cSDimitry Andric else if (P.first->second->getManualCodegen() != Def->getManualCodegen()) 368349cc55cSDimitry Andric PrintFatalError("Builtin with same name has different ManualCodegen"); 369349cc55cSDimitry Andric else if (P.first->second->getNF() != Def->getNF()) 370349cc55cSDimitry Andric PrintFatalError("Builtin with same name has different NF"); 371*81ad6265SDimitry Andric else if (P.first->second->isMasked() != Def->isMasked()) 372*81ad6265SDimitry Andric PrintFatalError("Builtin with same name has different isMasked"); 373349cc55cSDimitry Andric else if (P.first->second->hasVL() != Def->hasVL()) 374*81ad6265SDimitry Andric PrintFatalError("Builtin with same name has different hasVL"); 375*81ad6265SDimitry Andric else if (P.first->second->getPolicyScheme() != Def->getPolicyScheme()) 376*81ad6265SDimitry Andric PrintFatalError("Builtin with same name has different getPolicyScheme"); 377349cc55cSDimitry Andric else if (P.first->second->getIntrinsicTypes() != Def->getIntrinsicTypes()) 378349cc55cSDimitry Andric PrintFatalError("Builtin with same name has different IntrinsicTypes"); 379fe6060f1SDimitry Andric } 380*81ad6265SDimitry Andric emitCodeGenSwitchBody(Defs.back().get(), OS); 381fe6060f1SDimitry Andric OS << "\n"; 382fe6060f1SDimitry Andric } 383fe6060f1SDimitry Andric 384fe6060f1SDimitry Andric void RVVEmitter::createRVVIntrinsics( 385fe6060f1SDimitry Andric std::vector<std::unique_ptr<RVVIntrinsic>> &Out) { 386fe6060f1SDimitry Andric std::vector<Record *> RV = Records.getAllDerivedDefinitions("RVVBuiltin"); 387fe6060f1SDimitry Andric for (auto *R : RV) { 388fe6060f1SDimitry Andric StringRef Name = R->getValueAsString("Name"); 389fe6060f1SDimitry Andric StringRef SuffixProto = R->getValueAsString("Suffix"); 390*81ad6265SDimitry Andric StringRef OverloadedName = R->getValueAsString("OverloadedName"); 391*81ad6265SDimitry Andric StringRef OverloadedSuffixProto = R->getValueAsString("OverloadedSuffix"); 392fe6060f1SDimitry Andric StringRef Prototypes = R->getValueAsString("Prototype"); 393fe6060f1SDimitry Andric StringRef TypeRange = R->getValueAsString("TypeRange"); 394*81ad6265SDimitry Andric bool HasMasked = R->getValueAsBit("HasMasked"); 395fe6060f1SDimitry Andric bool HasMaskedOffOperand = R->getValueAsBit("HasMaskedOffOperand"); 396fe6060f1SDimitry Andric bool HasVL = R->getValueAsBit("HasVL"); 397*81ad6265SDimitry Andric Record *MaskedPolicyRecord = R->getValueAsDef("MaskedPolicy"); 398*81ad6265SDimitry Andric PolicyScheme MaskedPolicy = 399*81ad6265SDimitry Andric static_cast<PolicyScheme>(MaskedPolicyRecord->getValueAsInt("Value")); 400*81ad6265SDimitry Andric Record *UnMaskedPolicyRecord = R->getValueAsDef("UnMaskedPolicy"); 401*81ad6265SDimitry Andric PolicyScheme UnMaskedPolicy = 402*81ad6265SDimitry Andric static_cast<PolicyScheme>(UnMaskedPolicyRecord->getValueAsInt("Value")); 403*81ad6265SDimitry Andric bool HasUnMaskedOverloaded = R->getValueAsBit("HasUnMaskedOverloaded"); 404fe6060f1SDimitry Andric std::vector<int64_t> Log2LMULList = R->getValueAsListOfInts("Log2LMUL"); 405*81ad6265SDimitry Andric bool HasBuiltinAlias = R->getValueAsBit("HasBuiltinAlias"); 406fe6060f1SDimitry Andric StringRef ManualCodegen = R->getValueAsString("ManualCodegen"); 407*81ad6265SDimitry Andric StringRef MaskedManualCodegen = R->getValueAsString("MaskedManualCodegen"); 408fe6060f1SDimitry Andric std::vector<int64_t> IntrinsicTypes = 409fe6060f1SDimitry Andric R->getValueAsListOfInts("IntrinsicTypes"); 41004eeddc0SDimitry Andric std::vector<StringRef> RequiredFeatures = 41104eeddc0SDimitry Andric R->getValueAsListOfStrings("RequiredFeatures"); 412fe6060f1SDimitry Andric StringRef IRName = R->getValueAsString("IRName"); 413*81ad6265SDimitry Andric StringRef MaskedIRName = R->getValueAsString("MaskedIRName"); 414fe6060f1SDimitry Andric unsigned NF = R->getValueAsInt("NF"); 415fe6060f1SDimitry Andric 416fe6060f1SDimitry Andric // Parse prototype and create a list of primitive type with transformers 417*81ad6265SDimitry Andric // (operand) in Prototype. Prototype[0] is output operand. 418*81ad6265SDimitry Andric SmallVector<PrototypeDescriptor> Prototype = parsePrototypes(Prototypes); 419*81ad6265SDimitry Andric 420*81ad6265SDimitry Andric SmallVector<PrototypeDescriptor> SuffixDesc = parsePrototypes(SuffixProto); 421*81ad6265SDimitry Andric SmallVector<PrototypeDescriptor> OverloadedSuffixDesc = 422*81ad6265SDimitry Andric parsePrototypes(OverloadedSuffixProto); 423fe6060f1SDimitry Andric 424fe6060f1SDimitry Andric // Compute Builtin types 425*81ad6265SDimitry Andric SmallVector<PrototypeDescriptor> MaskedPrototype = Prototype; 426*81ad6265SDimitry Andric if (HasMasked) { 427fe6060f1SDimitry Andric // If HasMaskedOffOperand, insert result type as first input operand. 428fe6060f1SDimitry Andric if (HasMaskedOffOperand) { 429fe6060f1SDimitry Andric if (NF == 1) { 430*81ad6265SDimitry Andric MaskedPrototype.insert(MaskedPrototype.begin() + 1, Prototype[0]); 431fe6060f1SDimitry Andric } else { 432fe6060f1SDimitry Andric // Convert 433fe6060f1SDimitry Andric // (void, op0 address, op1 address, ...) 434fe6060f1SDimitry Andric // to 435fe6060f1SDimitry Andric // (void, op0 address, op1 address, ..., maskedoff0, maskedoff1, ...) 436*81ad6265SDimitry Andric PrototypeDescriptor MaskoffType = Prototype[1]; 437*81ad6265SDimitry Andric MaskoffType.TM &= ~static_cast<uint8_t>(TypeModifier::Pointer); 438fe6060f1SDimitry Andric for (unsigned I = 0; I < NF; ++I) 439*81ad6265SDimitry Andric MaskedPrototype.insert(MaskedPrototype.begin() + NF + 1, 440*81ad6265SDimitry Andric MaskoffType); 441fe6060f1SDimitry Andric } 442fe6060f1SDimitry Andric } 443fe6060f1SDimitry Andric if (HasMaskedOffOperand && NF > 1) { 444fe6060f1SDimitry Andric // Convert 445fe6060f1SDimitry Andric // (void, op0 address, op1 address, ..., maskedoff0, maskedoff1, ...) 446fe6060f1SDimitry Andric // to 447fe6060f1SDimitry Andric // (void, op0 address, op1 address, ..., mask, maskedoff0, maskedoff1, 448fe6060f1SDimitry Andric // ...) 449*81ad6265SDimitry Andric MaskedPrototype.insert(MaskedPrototype.begin() + NF + 1, 450*81ad6265SDimitry Andric PrototypeDescriptor::Mask); 451fe6060f1SDimitry Andric } else { 452*81ad6265SDimitry Andric // If HasMasked, insert PrototypeDescriptor:Mask as first input operand. 453*81ad6265SDimitry Andric MaskedPrototype.insert(MaskedPrototype.begin() + 1, 454*81ad6265SDimitry Andric PrototypeDescriptor::Mask); 455fe6060f1SDimitry Andric } 456fe6060f1SDimitry Andric } 457*81ad6265SDimitry Andric // If HasVL, append PrototypeDescriptor:VL to last operand 458fe6060f1SDimitry Andric if (HasVL) { 459*81ad6265SDimitry Andric Prototype.push_back(PrototypeDescriptor::VL); 460*81ad6265SDimitry Andric MaskedPrototype.push_back(PrototypeDescriptor::VL); 461fe6060f1SDimitry Andric } 462fe6060f1SDimitry Andric 463fe6060f1SDimitry Andric // Create Intrinsics for each type and LMUL. 464fe6060f1SDimitry Andric for (char I : TypeRange) { 465fe6060f1SDimitry Andric for (int Log2LMUL : Log2LMULList) { 466*81ad6265SDimitry Andric BasicType BT = ParseBasicType(I); 467*81ad6265SDimitry Andric Optional<RVVTypes> Types = 468*81ad6265SDimitry Andric RVVType::computeTypes(BT, Log2LMUL, NF, Prototype); 469fe6060f1SDimitry Andric // Ignored to create new intrinsic if there are any illegal types. 470*81ad6265SDimitry Andric if (!Types) 471fe6060f1SDimitry Andric continue; 472fe6060f1SDimitry Andric 473*81ad6265SDimitry Andric auto SuffixStr = RVVIntrinsic::getSuffixStr(BT, Log2LMUL, SuffixDesc); 474*81ad6265SDimitry Andric auto OverloadedSuffixStr = 475*81ad6265SDimitry Andric RVVIntrinsic::getSuffixStr(BT, Log2LMUL, OverloadedSuffixDesc); 476*81ad6265SDimitry Andric // Create a unmasked intrinsic 477fe6060f1SDimitry Andric Out.push_back(std::make_unique<RVVIntrinsic>( 478*81ad6265SDimitry Andric Name, SuffixStr, OverloadedName, OverloadedSuffixStr, IRName, 479*81ad6265SDimitry Andric /*IsMasked=*/false, /*HasMaskedOffOperand=*/false, HasVL, 480*81ad6265SDimitry Andric UnMaskedPolicy, HasUnMaskedOverloaded, HasBuiltinAlias, 481*81ad6265SDimitry Andric ManualCodegen, *Types, IntrinsicTypes, RequiredFeatures, NF)); 482*81ad6265SDimitry Andric if (HasMasked) { 483*81ad6265SDimitry Andric // Create a masked intrinsic 484fe6060f1SDimitry Andric Optional<RVVTypes> MaskTypes = 485*81ad6265SDimitry Andric RVVType::computeTypes(BT, Log2LMUL, NF, MaskedPrototype); 486fe6060f1SDimitry Andric Out.push_back(std::make_unique<RVVIntrinsic>( 487*81ad6265SDimitry Andric Name, SuffixStr, OverloadedName, OverloadedSuffixStr, 488*81ad6265SDimitry Andric MaskedIRName, 489*81ad6265SDimitry Andric /*IsMasked=*/true, HasMaskedOffOperand, HasVL, MaskedPolicy, 490*81ad6265SDimitry Andric HasUnMaskedOverloaded, HasBuiltinAlias, MaskedManualCodegen, 491*81ad6265SDimitry Andric *MaskTypes, IntrinsicTypes, RequiredFeatures, NF)); 492fe6060f1SDimitry Andric } 493fe6060f1SDimitry Andric } // end for Log2LMULList 494fe6060f1SDimitry Andric } // end for TypeRange 495fe6060f1SDimitry Andric } 496fe6060f1SDimitry Andric } 497fe6060f1SDimitry Andric 498*81ad6265SDimitry Andric void RVVEmitter::printHeaderCode(raw_ostream &OS) { 499349cc55cSDimitry Andric std::vector<Record *> RVVHeaders = 500349cc55cSDimitry Andric Records.getAllDerivedDefinitions("RVVHeader"); 501349cc55cSDimitry Andric for (auto *R : RVVHeaders) { 502349cc55cSDimitry Andric StringRef HeaderCodeStr = R->getValueAsString("HeaderCode"); 503349cc55cSDimitry Andric OS << HeaderCodeStr.str(); 504349cc55cSDimitry Andric } 505349cc55cSDimitry Andric } 506349cc55cSDimitry Andric 507fe6060f1SDimitry Andric void RVVEmitter::emitArchMacroAndBody( 508fe6060f1SDimitry Andric std::vector<std::unique_ptr<RVVIntrinsic>> &Defs, raw_ostream &OS, 509fe6060f1SDimitry Andric std::function<void(raw_ostream &, const RVVIntrinsic &)> PrintBody) { 51004eeddc0SDimitry Andric RISCVPredefinedMacroT PrevMacros = 51104eeddc0SDimitry Andric (*Defs.begin())->getRISCVPredefinedMacros(); 51204eeddc0SDimitry Andric bool NeedEndif = emitMacroRestrictionStr(PrevMacros, OS); 513fe6060f1SDimitry Andric for (auto &Def : Defs) { 51404eeddc0SDimitry Andric RISCVPredefinedMacroT CurMacros = Def->getRISCVPredefinedMacros(); 51504eeddc0SDimitry Andric if (CurMacros != PrevMacros) { 516fe6060f1SDimitry Andric if (NeedEndif) 517fe6060f1SDimitry Andric OS << "#endif\n\n"; 51804eeddc0SDimitry Andric NeedEndif = emitMacroRestrictionStr(CurMacros, OS); 51904eeddc0SDimitry Andric PrevMacros = CurMacros; 520fe6060f1SDimitry Andric } 521*81ad6265SDimitry Andric if (Def->hasBuiltinAlias()) 522fe6060f1SDimitry Andric PrintBody(OS, *Def); 523fe6060f1SDimitry Andric } 524fe6060f1SDimitry Andric if (NeedEndif) 525fe6060f1SDimitry Andric OS << "#endif\n\n"; 526fe6060f1SDimitry Andric } 527fe6060f1SDimitry Andric 52804eeddc0SDimitry Andric bool RVVEmitter::emitMacroRestrictionStr(RISCVPredefinedMacroT PredefinedMacros, 52904eeddc0SDimitry Andric raw_ostream &OS) { 53004eeddc0SDimitry Andric if (PredefinedMacros == RISCVPredefinedMacro::Basic) 531fe6060f1SDimitry Andric return false; 532fe6060f1SDimitry Andric OS << "#if "; 533fe6060f1SDimitry Andric ListSeparator LS(" && "); 53404eeddc0SDimitry Andric if (PredefinedMacros & RISCVPredefinedMacro::V) 53504eeddc0SDimitry Andric OS << LS << "defined(__riscv_v)"; 536*81ad6265SDimitry Andric if (PredefinedMacros & RISCVPredefinedMacro::Zvfh) 537*81ad6265SDimitry Andric OS << LS << "defined(__riscv_zvfh)"; 53804eeddc0SDimitry Andric if (PredefinedMacros & RISCVPredefinedMacro::RV64) 53904eeddc0SDimitry Andric OS << LS << "(__riscv_xlen == 64)"; 54004eeddc0SDimitry Andric if (PredefinedMacros & RISCVPredefinedMacro::VectorMaxELen64) 54104eeddc0SDimitry Andric OS << LS << "(__riscv_v_elen >= 64)"; 54204eeddc0SDimitry Andric if (PredefinedMacros & RISCVPredefinedMacro::VectorMaxELenFp32) 54304eeddc0SDimitry Andric OS << LS << "(__riscv_v_elen_fp >= 32)"; 54404eeddc0SDimitry Andric if (PredefinedMacros & RISCVPredefinedMacro::VectorMaxELenFp64) 54504eeddc0SDimitry Andric OS << LS << "(__riscv_v_elen_fp >= 64)"; 546fe6060f1SDimitry Andric OS << "\n"; 547fe6060f1SDimitry Andric return true; 548fe6060f1SDimitry Andric } 549fe6060f1SDimitry Andric 550fe6060f1SDimitry Andric namespace clang { 551fe6060f1SDimitry Andric void EmitRVVHeader(RecordKeeper &Records, raw_ostream &OS) { 552fe6060f1SDimitry Andric RVVEmitter(Records).createHeader(OS); 553fe6060f1SDimitry Andric } 554fe6060f1SDimitry Andric 555fe6060f1SDimitry Andric void EmitRVVBuiltins(RecordKeeper &Records, raw_ostream &OS) { 556fe6060f1SDimitry Andric RVVEmitter(Records).createBuiltins(OS); 557fe6060f1SDimitry Andric } 558fe6060f1SDimitry Andric 559fe6060f1SDimitry Andric void EmitRVVBuiltinCG(RecordKeeper &Records, raw_ostream &OS) { 560fe6060f1SDimitry Andric RVVEmitter(Records).createCodeGen(OS); 561fe6060f1SDimitry Andric } 562fe6060f1SDimitry Andric 563fe6060f1SDimitry Andric } // End namespace clang 564