xref: /freebsd-src/contrib/llvm-project/clang/utils/TableGen/RISCVVEmitter.cpp (revision 81ad626541db97eb356e2c1d4a20eb2a26a766ab)
1 //===- RISCVVEmitter.cpp - Generate riscv_vector.h for use with clang -----===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This tablegen backend is responsible for emitting riscv_vector.h which
10 // includes a declaration and definition of each intrinsic functions specified
11 // in https://github.com/riscv/rvv-intrinsic-doc.
12 //
13 // See also the documentation in include/clang/Basic/riscv_vector.td.
14 //
15 //===----------------------------------------------------------------------===//
16 
17 #include "clang/Support/RISCVVIntrinsicUtils.h"
18 #include "llvm/ADT/ArrayRef.h"
19 #include "llvm/ADT/SmallSet.h"
20 #include "llvm/ADT/StringExtras.h"
21 #include "llvm/ADT/StringMap.h"
22 #include "llvm/ADT/StringSet.h"
23 #include "llvm/ADT/Twine.h"
24 #include "llvm/TableGen/Error.h"
25 #include "llvm/TableGen/Record.h"
26 #include <numeric>
27 
28 using namespace llvm;
29 using namespace clang::RISCV;
30 
31 namespace {
32 class RVVEmitter {
33 private:
34   RecordKeeper &Records;
35 
36 public:
37   RVVEmitter(RecordKeeper &R) : Records(R) {}
38 
39   /// Emit riscv_vector.h
40   void createHeader(raw_ostream &o);
41 
42   /// Emit all the __builtin prototypes and code needed by Sema.
43   void createBuiltins(raw_ostream &o);
44 
45   /// Emit all the information needed to map builtin -> LLVM IR intrinsic.
46   void createCodeGen(raw_ostream &o);
47 
48 private:
49   /// Create all intrinsics and add them to \p Out
50   void createRVVIntrinsics(std::vector<std::unique_ptr<RVVIntrinsic>> &Out);
51   /// Print HeaderCode in RVVHeader Record to \p Out
52   void printHeaderCode(raw_ostream &OS);
53 
54   /// Emit Acrh predecessor definitions and body, assume the element of Defs are
55   /// sorted by extension.
56   void emitArchMacroAndBody(
57       std::vector<std::unique_ptr<RVVIntrinsic>> &Defs, raw_ostream &o,
58       std::function<void(raw_ostream &, const RVVIntrinsic &)>);
59 
60   // Emit the architecture preprocessor definitions. Return true when emits
61   // non-empty string.
62   bool emitMacroRestrictionStr(RISCVPredefinedMacroT PredefinedMacros,
63                                raw_ostream &o);
64 };
65 
66 } // namespace
67 
68 static BasicType ParseBasicType(char c) {
69   switch (c) {
70   case 'c':
71     return BasicType::Int8;
72     break;
73   case 's':
74     return BasicType::Int16;
75     break;
76   case 'i':
77     return BasicType::Int32;
78     break;
79   case 'l':
80     return BasicType::Int64;
81     break;
82   case 'x':
83     return BasicType::Float16;
84     break;
85   case 'f':
86     return BasicType::Float32;
87     break;
88   case 'd':
89     return BasicType::Float64;
90     break;
91 
92   default:
93     return BasicType::Unknown;
94   }
95 }
96 
97 void emitCodeGenSwitchBody(const RVVIntrinsic *RVVI, raw_ostream &OS) {
98   if (!RVVI->getIRName().empty())
99     OS << "  ID = Intrinsic::riscv_" + RVVI->getIRName() + ";\n";
100   if (RVVI->getNF() >= 2)
101     OS << "  NF = " + utostr(RVVI->getNF()) + ";\n";
102   if (RVVI->hasManualCodegen()) {
103     OS << RVVI->getManualCodegen();
104     OS << "break;\n";
105     return;
106   }
107 
108   if (RVVI->isMasked()) {
109     if (RVVI->hasVL()) {
110       OS << "  std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end() - 1);\n";
111       if (RVVI->hasPolicyOperand())
112         OS << "  Ops.push_back(ConstantInt::get(Ops.back()->getType(),"
113               " TAIL_UNDISTURBED));\n";
114     } else {
115       OS << "  std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end());\n";
116     }
117   } else {
118     if (RVVI->hasPolicyOperand())
119       OS << "  Ops.push_back(ConstantInt::get(Ops.back()->getType(), "
120             "TAIL_UNDISTURBED));\n";
121     else if (RVVI->hasPassthruOperand()) {
122       OS << "  Ops.push_back(llvm::UndefValue::get(ResultType));\n";
123       OS << "  std::rotate(Ops.rbegin(), Ops.rbegin() + 1,  Ops.rend());\n";
124     }
125   }
126 
127   OS << "  IntrinsicTypes = {";
128   ListSeparator LS;
129   for (const auto &Idx : RVVI->getIntrinsicTypes()) {
130     if (Idx == -1)
131       OS << LS << "ResultType";
132     else
133       OS << LS << "Ops[" << Idx << "]->getType()";
134   }
135 
136   // VL could be i64 or i32, need to encode it in IntrinsicTypes. VL is
137   // always last operand.
138   if (RVVI->hasVL())
139     OS << ", Ops.back()->getType()";
140   OS << "};\n";
141   OS << "  break;\n";
142 }
143 
144 void emitIntrinsicFuncDef(const RVVIntrinsic &RVVI, raw_ostream &OS) {
145   OS << "__attribute__((__clang_builtin_alias__(";
146   OS << "__builtin_rvv_" << RVVI.getBuiltinName() << ")))\n";
147   OS << RVVI.getOutputType()->getTypeStr() << " " << RVVI.getName() << "(";
148   // Emit function arguments
149   const RVVTypes &InputTypes = RVVI.getInputTypes();
150   if (!InputTypes.empty()) {
151     ListSeparator LS;
152     for (unsigned i = 0; i < InputTypes.size(); ++i)
153       OS << LS << InputTypes[i]->getTypeStr();
154   }
155   OS << ");\n";
156 }
157 
158 void emitOverloadedFuncDef(const RVVIntrinsic &RVVI, raw_ostream &OS) {
159   OS << "__attribute__((__clang_builtin_alias__(";
160   OS << "__builtin_rvv_" << RVVI.getBuiltinName() << ")))\n";
161   OS << RVVI.getOutputType()->getTypeStr() << " " << RVVI.getOverloadedName()
162      << "(";
163   // Emit function arguments
164   const RVVTypes &InputTypes = RVVI.getInputTypes();
165   if (!InputTypes.empty()) {
166     ListSeparator LS;
167     for (unsigned i = 0; i < InputTypes.size(); ++i)
168       OS << LS << InputTypes[i]->getTypeStr();
169   }
170   OS << ");\n";
171 }
172 
173 //===----------------------------------------------------------------------===//
174 // RVVEmitter implementation
175 //===----------------------------------------------------------------------===//
176 void RVVEmitter::createHeader(raw_ostream &OS) {
177 
178   OS << "/*===---- riscv_vector.h - RISC-V V-extension RVVIntrinsics "
179         "-------------------===\n"
180         " *\n"
181         " *\n"
182         " * Part of the LLVM Project, under the Apache License v2.0 with LLVM "
183         "Exceptions.\n"
184         " * See https://llvm.org/LICENSE.txt for license information.\n"
185         " * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception\n"
186         " *\n"
187         " *===-----------------------------------------------------------------"
188         "------===\n"
189         " */\n\n";
190 
191   OS << "#ifndef __RISCV_VECTOR_H\n";
192   OS << "#define __RISCV_VECTOR_H\n\n";
193 
194   OS << "#include <stdint.h>\n";
195   OS << "#include <stddef.h>\n\n";
196 
197   OS << "#ifndef __riscv_vector\n";
198   OS << "#error \"Vector intrinsics require the vector extension.\"\n";
199   OS << "#endif\n\n";
200 
201   OS << "#ifdef __cplusplus\n";
202   OS << "extern \"C\" {\n";
203   OS << "#endif\n\n";
204 
205   printHeaderCode(OS);
206 
207   std::vector<std::unique_ptr<RVVIntrinsic>> Defs;
208   createRVVIntrinsics(Defs);
209 
210   auto printType = [&](auto T) {
211     OS << "typedef " << T->getClangBuiltinStr() << " " << T->getTypeStr()
212        << ";\n";
213   };
214 
215   constexpr int Log2LMULs[] = {-3, -2, -1, 0, 1, 2, 3};
216   // Print RVV boolean types.
217   for (int Log2LMUL : Log2LMULs) {
218     auto T = RVVType::computeType(BasicType::Int8, Log2LMUL,
219                                   PrototypeDescriptor::Mask);
220     if (T)
221       printType(T.getValue());
222   }
223   // Print RVV int/float types.
224   for (char I : StringRef("csil")) {
225     BasicType BT = ParseBasicType(I);
226     for (int Log2LMUL : Log2LMULs) {
227       auto T = RVVType::computeType(BT, Log2LMUL, PrototypeDescriptor::Vector);
228       if (T) {
229         printType(T.getValue());
230         auto UT = RVVType::computeType(
231             BT, Log2LMUL,
232             PrototypeDescriptor(BaseTypeModifier::Vector,
233                                 VectorTypeModifier::NoModifier,
234                                 TypeModifier::UnsignedInteger));
235         printType(UT.getValue());
236       }
237     }
238   }
239   OS << "#if defined(__riscv_zvfh)\n";
240   for (int Log2LMUL : Log2LMULs) {
241     auto T = RVVType::computeType(BasicType::Float16, Log2LMUL,
242                                   PrototypeDescriptor::Vector);
243     if (T)
244       printType(T.getValue());
245   }
246   OS << "#endif\n";
247 
248   OS << "#if defined(__riscv_f)\n";
249   for (int Log2LMUL : Log2LMULs) {
250     auto T = RVVType::computeType(BasicType::Float32, Log2LMUL,
251                                   PrototypeDescriptor::Vector);
252     if (T)
253       printType(T.getValue());
254   }
255   OS << "#endif\n";
256 
257   OS << "#if defined(__riscv_d)\n";
258   for (int Log2LMUL : Log2LMULs) {
259     auto T = RVVType::computeType(BasicType::Float64, Log2LMUL,
260                                   PrototypeDescriptor::Vector);
261     if (T)
262       printType(T.getValue());
263   }
264   OS << "#endif\n\n";
265 
266   // The same extension include in the same arch guard marco.
267   llvm::stable_sort(Defs, [](const std::unique_ptr<RVVIntrinsic> &A,
268                              const std::unique_ptr<RVVIntrinsic> &B) {
269     return A->getRISCVPredefinedMacros() < B->getRISCVPredefinedMacros();
270   });
271 
272   OS << "#define __rvv_ai static __inline__\n";
273 
274   // Print intrinsic functions with macro
275   emitArchMacroAndBody(Defs, OS, [](raw_ostream &OS, const RVVIntrinsic &Inst) {
276     OS << "__rvv_ai ";
277     emitIntrinsicFuncDef(Inst, OS);
278   });
279 
280   OS << "#undef __rvv_ai\n\n";
281 
282   OS << "#define __riscv_v_intrinsic_overloading 1\n";
283 
284   // Print Overloaded APIs
285   OS << "#define __rvv_aio static __inline__ "
286         "__attribute__((__overloadable__))\n";
287 
288   emitArchMacroAndBody(Defs, OS, [](raw_ostream &OS, const RVVIntrinsic &Inst) {
289     if (!Inst.isMasked() && !Inst.hasUnMaskedOverloaded())
290       return;
291     OS << "__rvv_aio ";
292     emitOverloadedFuncDef(Inst, OS);
293   });
294 
295   OS << "#undef __rvv_aio\n";
296 
297   OS << "\n#ifdef __cplusplus\n";
298   OS << "}\n";
299   OS << "#endif // __cplusplus\n";
300   OS << "#endif // __RISCV_VECTOR_H\n";
301 }
302 
303 void RVVEmitter::createBuiltins(raw_ostream &OS) {
304   std::vector<std::unique_ptr<RVVIntrinsic>> Defs;
305   createRVVIntrinsics(Defs);
306 
307   // Map to keep track of which builtin names have already been emitted.
308   StringMap<RVVIntrinsic *> BuiltinMap;
309 
310   OS << "#if defined(TARGET_BUILTIN) && !defined(RISCVV_BUILTIN)\n";
311   OS << "#define RISCVV_BUILTIN(ID, TYPE, ATTRS) TARGET_BUILTIN(ID, TYPE, "
312         "ATTRS, \"zve32x\")\n";
313   OS << "#endif\n";
314   for (auto &Def : Defs) {
315     auto P =
316         BuiltinMap.insert(std::make_pair(Def->getBuiltinName(), Def.get()));
317     if (!P.second) {
318       // Verf that this would have produced the same builtin definition.
319       if (P.first->second->hasBuiltinAlias() != Def->hasBuiltinAlias())
320         PrintFatalError("Builtin with same name has different hasAutoDef");
321       else if (!Def->hasBuiltinAlias() &&
322                P.first->second->getBuiltinTypeStr() != Def->getBuiltinTypeStr())
323         PrintFatalError("Builtin with same name has different type string");
324       continue;
325     }
326     OS << "RISCVV_BUILTIN(__builtin_rvv_" << Def->getBuiltinName() << ",\"";
327     if (!Def->hasBuiltinAlias())
328       OS << Def->getBuiltinTypeStr();
329     OS << "\", \"n\")\n";
330   }
331   OS << "#undef RISCVV_BUILTIN\n";
332 }
333 
334 void RVVEmitter::createCodeGen(raw_ostream &OS) {
335   std::vector<std::unique_ptr<RVVIntrinsic>> Defs;
336   createRVVIntrinsics(Defs);
337   // IR name could be empty, use the stable sort preserves the relative order.
338   llvm::stable_sort(Defs, [](const std::unique_ptr<RVVIntrinsic> &A,
339                              const std::unique_ptr<RVVIntrinsic> &B) {
340     return A->getIRName() < B->getIRName();
341   });
342 
343   // Map to keep track of which builtin names have already been emitted.
344   StringMap<RVVIntrinsic *> BuiltinMap;
345 
346   // Print switch body when the ir name or ManualCodegen changes from previous
347   // iteration.
348   RVVIntrinsic *PrevDef = Defs.begin()->get();
349   for (auto &Def : Defs) {
350     StringRef CurIRName = Def->getIRName();
351     if (CurIRName != PrevDef->getIRName() ||
352         (Def->getManualCodegen() != PrevDef->getManualCodegen())) {
353       emitCodeGenSwitchBody(PrevDef, OS);
354     }
355     PrevDef = Def.get();
356 
357     auto P =
358         BuiltinMap.insert(std::make_pair(Def->getBuiltinName(), Def.get()));
359     if (P.second) {
360       OS << "case RISCVVector::BI__builtin_rvv_" << Def->getBuiltinName()
361          << ":\n";
362       continue;
363     }
364 
365     if (P.first->second->getIRName() != Def->getIRName())
366       PrintFatalError("Builtin with same name has different IRName");
367     else if (P.first->second->getManualCodegen() != Def->getManualCodegen())
368       PrintFatalError("Builtin with same name has different ManualCodegen");
369     else if (P.first->second->getNF() != Def->getNF())
370       PrintFatalError("Builtin with same name has different NF");
371     else if (P.first->second->isMasked() != Def->isMasked())
372       PrintFatalError("Builtin with same name has different isMasked");
373     else if (P.first->second->hasVL() != Def->hasVL())
374       PrintFatalError("Builtin with same name has different hasVL");
375     else if (P.first->second->getPolicyScheme() != Def->getPolicyScheme())
376       PrintFatalError("Builtin with same name has different getPolicyScheme");
377     else if (P.first->second->getIntrinsicTypes() != Def->getIntrinsicTypes())
378       PrintFatalError("Builtin with same name has different IntrinsicTypes");
379   }
380   emitCodeGenSwitchBody(Defs.back().get(), OS);
381   OS << "\n";
382 }
383 
384 void RVVEmitter::createRVVIntrinsics(
385     std::vector<std::unique_ptr<RVVIntrinsic>> &Out) {
386   std::vector<Record *> RV = Records.getAllDerivedDefinitions("RVVBuiltin");
387   for (auto *R : RV) {
388     StringRef Name = R->getValueAsString("Name");
389     StringRef SuffixProto = R->getValueAsString("Suffix");
390     StringRef OverloadedName = R->getValueAsString("OverloadedName");
391     StringRef OverloadedSuffixProto = R->getValueAsString("OverloadedSuffix");
392     StringRef Prototypes = R->getValueAsString("Prototype");
393     StringRef TypeRange = R->getValueAsString("TypeRange");
394     bool HasMasked = R->getValueAsBit("HasMasked");
395     bool HasMaskedOffOperand = R->getValueAsBit("HasMaskedOffOperand");
396     bool HasVL = R->getValueAsBit("HasVL");
397     Record *MaskedPolicyRecord = R->getValueAsDef("MaskedPolicy");
398     PolicyScheme MaskedPolicy =
399         static_cast<PolicyScheme>(MaskedPolicyRecord->getValueAsInt("Value"));
400     Record *UnMaskedPolicyRecord = R->getValueAsDef("UnMaskedPolicy");
401     PolicyScheme UnMaskedPolicy =
402         static_cast<PolicyScheme>(UnMaskedPolicyRecord->getValueAsInt("Value"));
403     bool HasUnMaskedOverloaded = R->getValueAsBit("HasUnMaskedOverloaded");
404     std::vector<int64_t> Log2LMULList = R->getValueAsListOfInts("Log2LMUL");
405     bool HasBuiltinAlias = R->getValueAsBit("HasBuiltinAlias");
406     StringRef ManualCodegen = R->getValueAsString("ManualCodegen");
407     StringRef MaskedManualCodegen = R->getValueAsString("MaskedManualCodegen");
408     std::vector<int64_t> IntrinsicTypes =
409         R->getValueAsListOfInts("IntrinsicTypes");
410     std::vector<StringRef> RequiredFeatures =
411         R->getValueAsListOfStrings("RequiredFeatures");
412     StringRef IRName = R->getValueAsString("IRName");
413     StringRef MaskedIRName = R->getValueAsString("MaskedIRName");
414     unsigned NF = R->getValueAsInt("NF");
415 
416     // Parse prototype and create a list of primitive type with transformers
417     // (operand) in Prototype. Prototype[0] is output operand.
418     SmallVector<PrototypeDescriptor> Prototype = parsePrototypes(Prototypes);
419 
420     SmallVector<PrototypeDescriptor> SuffixDesc = parsePrototypes(SuffixProto);
421     SmallVector<PrototypeDescriptor> OverloadedSuffixDesc =
422         parsePrototypes(OverloadedSuffixProto);
423 
424     // Compute Builtin types
425     SmallVector<PrototypeDescriptor> MaskedPrototype = Prototype;
426     if (HasMasked) {
427       // If HasMaskedOffOperand, insert result type as first input operand.
428       if (HasMaskedOffOperand) {
429         if (NF == 1) {
430           MaskedPrototype.insert(MaskedPrototype.begin() + 1, Prototype[0]);
431         } else {
432           // Convert
433           // (void, op0 address, op1 address, ...)
434           // to
435           // (void, op0 address, op1 address, ..., maskedoff0, maskedoff1, ...)
436           PrototypeDescriptor MaskoffType = Prototype[1];
437           MaskoffType.TM &= ~static_cast<uint8_t>(TypeModifier::Pointer);
438           for (unsigned I = 0; I < NF; ++I)
439             MaskedPrototype.insert(MaskedPrototype.begin() + NF + 1,
440                                    MaskoffType);
441         }
442       }
443       if (HasMaskedOffOperand && NF > 1) {
444         // Convert
445         // (void, op0 address, op1 address, ..., maskedoff0, maskedoff1, ...)
446         // to
447         // (void, op0 address, op1 address, ..., mask, maskedoff0, maskedoff1,
448         // ...)
449         MaskedPrototype.insert(MaskedPrototype.begin() + NF + 1,
450                                PrototypeDescriptor::Mask);
451       } else {
452         // If HasMasked, insert PrototypeDescriptor:Mask as first input operand.
453         MaskedPrototype.insert(MaskedPrototype.begin() + 1,
454                                PrototypeDescriptor::Mask);
455       }
456     }
457     // If HasVL, append PrototypeDescriptor:VL to last operand
458     if (HasVL) {
459       Prototype.push_back(PrototypeDescriptor::VL);
460       MaskedPrototype.push_back(PrototypeDescriptor::VL);
461     }
462 
463     // Create Intrinsics for each type and LMUL.
464     for (char I : TypeRange) {
465       for (int Log2LMUL : Log2LMULList) {
466         BasicType BT = ParseBasicType(I);
467         Optional<RVVTypes> Types =
468             RVVType::computeTypes(BT, Log2LMUL, NF, Prototype);
469         // Ignored to create new intrinsic if there are any illegal types.
470         if (!Types)
471           continue;
472 
473         auto SuffixStr = RVVIntrinsic::getSuffixStr(BT, Log2LMUL, SuffixDesc);
474         auto OverloadedSuffixStr =
475             RVVIntrinsic::getSuffixStr(BT, Log2LMUL, OverloadedSuffixDesc);
476         // Create a unmasked intrinsic
477         Out.push_back(std::make_unique<RVVIntrinsic>(
478             Name, SuffixStr, OverloadedName, OverloadedSuffixStr, IRName,
479             /*IsMasked=*/false, /*HasMaskedOffOperand=*/false, HasVL,
480             UnMaskedPolicy, HasUnMaskedOverloaded, HasBuiltinAlias,
481             ManualCodegen, *Types, IntrinsicTypes, RequiredFeatures, NF));
482         if (HasMasked) {
483           // Create a masked intrinsic
484           Optional<RVVTypes> MaskTypes =
485               RVVType::computeTypes(BT, Log2LMUL, NF, MaskedPrototype);
486           Out.push_back(std::make_unique<RVVIntrinsic>(
487               Name, SuffixStr, OverloadedName, OverloadedSuffixStr,
488               MaskedIRName,
489               /*IsMasked=*/true, HasMaskedOffOperand, HasVL, MaskedPolicy,
490               HasUnMaskedOverloaded, HasBuiltinAlias, MaskedManualCodegen,
491               *MaskTypes, IntrinsicTypes, RequiredFeatures, NF));
492         }
493       } // end for Log2LMULList
494     }   // end for TypeRange
495   }
496 }
497 
498 void RVVEmitter::printHeaderCode(raw_ostream &OS) {
499   std::vector<Record *> RVVHeaders =
500       Records.getAllDerivedDefinitions("RVVHeader");
501   for (auto *R : RVVHeaders) {
502     StringRef HeaderCodeStr = R->getValueAsString("HeaderCode");
503     OS << HeaderCodeStr.str();
504   }
505 }
506 
507 void RVVEmitter::emitArchMacroAndBody(
508     std::vector<std::unique_ptr<RVVIntrinsic>> &Defs, raw_ostream &OS,
509     std::function<void(raw_ostream &, const RVVIntrinsic &)> PrintBody) {
510   RISCVPredefinedMacroT PrevMacros =
511       (*Defs.begin())->getRISCVPredefinedMacros();
512   bool NeedEndif = emitMacroRestrictionStr(PrevMacros, OS);
513   for (auto &Def : Defs) {
514     RISCVPredefinedMacroT CurMacros = Def->getRISCVPredefinedMacros();
515     if (CurMacros != PrevMacros) {
516       if (NeedEndif)
517         OS << "#endif\n\n";
518       NeedEndif = emitMacroRestrictionStr(CurMacros, OS);
519       PrevMacros = CurMacros;
520     }
521     if (Def->hasBuiltinAlias())
522       PrintBody(OS, *Def);
523   }
524   if (NeedEndif)
525     OS << "#endif\n\n";
526 }
527 
528 bool RVVEmitter::emitMacroRestrictionStr(RISCVPredefinedMacroT PredefinedMacros,
529                                          raw_ostream &OS) {
530   if (PredefinedMacros == RISCVPredefinedMacro::Basic)
531     return false;
532   OS << "#if ";
533   ListSeparator LS(" && ");
534   if (PredefinedMacros & RISCVPredefinedMacro::V)
535     OS << LS << "defined(__riscv_v)";
536   if (PredefinedMacros & RISCVPredefinedMacro::Zvfh)
537     OS << LS << "defined(__riscv_zvfh)";
538   if (PredefinedMacros & RISCVPredefinedMacro::RV64)
539     OS << LS << "(__riscv_xlen == 64)";
540   if (PredefinedMacros & RISCVPredefinedMacro::VectorMaxELen64)
541     OS << LS << "(__riscv_v_elen >= 64)";
542   if (PredefinedMacros & RISCVPredefinedMacro::VectorMaxELenFp32)
543     OS << LS << "(__riscv_v_elen_fp >= 32)";
544   if (PredefinedMacros & RISCVPredefinedMacro::VectorMaxELenFp64)
545     OS << LS << "(__riscv_v_elen_fp >= 64)";
546   OS << "\n";
547   return true;
548 }
549 
550 namespace clang {
551 void EmitRVVHeader(RecordKeeper &Records, raw_ostream &OS) {
552   RVVEmitter(Records).createHeader(OS);
553 }
554 
555 void EmitRVVBuiltins(RecordKeeper &Records, raw_ostream &OS) {
556   RVVEmitter(Records).createBuiltins(OS);
557 }
558 
559 void EmitRVVBuiltinCG(RecordKeeper &Records, raw_ostream &OS) {
560   RVVEmitter(Records).createCodeGen(OS);
561 }
562 
563 } // End namespace clang
564