xref: /freebsd-src/contrib/llvm-project/clang/utils/TableGen/RISCVVEmitter.cpp (revision 04eeddc0aa8e0a417a16eaf9d7d095207f4a8623)
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 
17fe6060f1SDimitry Andric #include "llvm/ADT/ArrayRef.h"
18fe6060f1SDimitry Andric #include "llvm/ADT/SmallSet.h"
19fe6060f1SDimitry Andric #include "llvm/ADT/StringExtras.h"
20fe6060f1SDimitry Andric #include "llvm/ADT/StringMap.h"
21fe6060f1SDimitry Andric #include "llvm/ADT/StringSet.h"
22fe6060f1SDimitry Andric #include "llvm/ADT/Twine.h"
23fe6060f1SDimitry Andric #include "llvm/TableGen/Error.h"
24fe6060f1SDimitry Andric #include "llvm/TableGen/Record.h"
25fe6060f1SDimitry Andric #include <numeric>
26fe6060f1SDimitry Andric 
27fe6060f1SDimitry Andric using namespace llvm;
28fe6060f1SDimitry Andric using BasicType = char;
29fe6060f1SDimitry Andric using VScaleVal = Optional<unsigned>;
30fe6060f1SDimitry Andric 
31fe6060f1SDimitry Andric namespace {
32fe6060f1SDimitry Andric 
33fe6060f1SDimitry Andric // Exponential LMUL
34fe6060f1SDimitry Andric struct LMULType {
35fe6060f1SDimitry Andric   int Log2LMUL;
36fe6060f1SDimitry Andric   LMULType(int Log2LMUL);
37fe6060f1SDimitry Andric   // Return the C/C++ string representation of LMUL
38fe6060f1SDimitry Andric   std::string str() const;
39fe6060f1SDimitry Andric   Optional<unsigned> getScale(unsigned ElementBitwidth) const;
40fe6060f1SDimitry Andric   void MulLog2LMUL(int Log2LMUL);
41fe6060f1SDimitry Andric   LMULType &operator*=(uint32_t RHS);
42fe6060f1SDimitry Andric };
43fe6060f1SDimitry Andric 
44fe6060f1SDimitry Andric // This class is compact representation of a valid and invalid RVVType.
45fe6060f1SDimitry Andric class RVVType {
46fe6060f1SDimitry Andric   enum ScalarTypeKind : uint32_t {
47fe6060f1SDimitry Andric     Void,
48fe6060f1SDimitry Andric     Size_t,
49fe6060f1SDimitry Andric     Ptrdiff_t,
50fe6060f1SDimitry Andric     UnsignedLong,
51fe6060f1SDimitry Andric     SignedLong,
52fe6060f1SDimitry Andric     Boolean,
53fe6060f1SDimitry Andric     SignedInteger,
54fe6060f1SDimitry Andric     UnsignedInteger,
55fe6060f1SDimitry Andric     Float,
56fe6060f1SDimitry Andric     Invalid,
57fe6060f1SDimitry Andric   };
58fe6060f1SDimitry Andric   BasicType BT;
59fe6060f1SDimitry Andric   ScalarTypeKind ScalarType = Invalid;
60fe6060f1SDimitry Andric   LMULType LMUL;
61fe6060f1SDimitry Andric   bool IsPointer = false;
62fe6060f1SDimitry Andric   // IsConstant indices are "int", but have the constant expression.
63fe6060f1SDimitry Andric   bool IsImmediate = false;
64fe6060f1SDimitry Andric   // Const qualifier for pointer to const object or object of const type.
65fe6060f1SDimitry Andric   bool IsConstant = false;
66fe6060f1SDimitry Andric   unsigned ElementBitwidth = 0;
67fe6060f1SDimitry Andric   VScaleVal Scale = 0;
68fe6060f1SDimitry Andric   bool Valid;
69fe6060f1SDimitry Andric 
70fe6060f1SDimitry Andric   std::string BuiltinStr;
71fe6060f1SDimitry Andric   std::string ClangBuiltinStr;
72fe6060f1SDimitry Andric   std::string Str;
73fe6060f1SDimitry Andric   std::string ShortStr;
74fe6060f1SDimitry Andric 
75fe6060f1SDimitry Andric public:
76fe6060f1SDimitry Andric   RVVType() : RVVType(BasicType(), 0, StringRef()) {}
77fe6060f1SDimitry Andric   RVVType(BasicType BT, int Log2LMUL, StringRef prototype);
78fe6060f1SDimitry Andric 
79fe6060f1SDimitry Andric   // Return the string representation of a type, which is an encoded string for
80fe6060f1SDimitry Andric   // passing to the BUILTIN() macro in Builtins.def.
81fe6060f1SDimitry Andric   const std::string &getBuiltinStr() const { return BuiltinStr; }
82fe6060f1SDimitry Andric 
83349cc55cSDimitry Andric   // Return the clang builtin type for RVV vector type which are used in the
84fe6060f1SDimitry Andric   // riscv_vector.h header file.
85fe6060f1SDimitry Andric   const std::string &getClangBuiltinStr() const { return ClangBuiltinStr; }
86fe6060f1SDimitry Andric 
87fe6060f1SDimitry Andric   // Return the C/C++ string representation of a type for use in the
88fe6060f1SDimitry Andric   // riscv_vector.h header file.
89fe6060f1SDimitry Andric   const std::string &getTypeStr() const { return Str; }
90fe6060f1SDimitry Andric 
91fe6060f1SDimitry Andric   // Return the short name of a type for C/C++ name suffix.
92fe6060f1SDimitry Andric   const std::string &getShortStr() {
93fe6060f1SDimitry Andric     // Not all types are used in short name, so compute the short name by
94fe6060f1SDimitry Andric     // demanded.
95fe6060f1SDimitry Andric     if (ShortStr.empty())
96fe6060f1SDimitry Andric       initShortStr();
97fe6060f1SDimitry Andric     return ShortStr;
98fe6060f1SDimitry Andric   }
99fe6060f1SDimitry Andric 
100fe6060f1SDimitry Andric   bool isValid() const { return Valid; }
101fe6060f1SDimitry Andric   bool isScalar() const { return Scale.hasValue() && Scale.getValue() == 0; }
102fe6060f1SDimitry Andric   bool isVector() const { return Scale.hasValue() && Scale.getValue() != 0; }
103*04eeddc0SDimitry Andric   bool isVector(unsigned Width) const {
104*04eeddc0SDimitry Andric     return isVector() && ElementBitwidth == Width;
105*04eeddc0SDimitry Andric   }
106fe6060f1SDimitry Andric   bool isFloat() const { return ScalarType == ScalarTypeKind::Float; }
107fe6060f1SDimitry Andric   bool isSignedInteger() const {
108fe6060f1SDimitry Andric     return ScalarType == ScalarTypeKind::SignedInteger;
109fe6060f1SDimitry Andric   }
110fe6060f1SDimitry Andric   bool isFloatVector(unsigned Width) const {
111fe6060f1SDimitry Andric     return isVector() && isFloat() && ElementBitwidth == Width;
112fe6060f1SDimitry Andric   }
113fe6060f1SDimitry Andric   bool isFloat(unsigned Width) const {
114fe6060f1SDimitry Andric     return isFloat() && ElementBitwidth == Width;
115fe6060f1SDimitry Andric   }
116fe6060f1SDimitry Andric 
117fe6060f1SDimitry Andric private:
118fe6060f1SDimitry Andric   // Verify RVV vector type and set Valid.
119fe6060f1SDimitry Andric   bool verifyType() const;
120fe6060f1SDimitry Andric 
121fe6060f1SDimitry Andric   // Creates a type based on basic types of TypeRange
122fe6060f1SDimitry Andric   void applyBasicType();
123fe6060f1SDimitry Andric 
124fe6060f1SDimitry Andric   // Applies a prototype modifier to the current type. The result maybe an
125fe6060f1SDimitry Andric   // invalid type.
126fe6060f1SDimitry Andric   void applyModifier(StringRef prototype);
127fe6060f1SDimitry Andric 
128fe6060f1SDimitry Andric   // Compute and record a string for legal type.
129fe6060f1SDimitry Andric   void initBuiltinStr();
130fe6060f1SDimitry Andric   // Compute and record a builtin RVV vector type string.
131fe6060f1SDimitry Andric   void initClangBuiltinStr();
132fe6060f1SDimitry Andric   // Compute and record a type string for used in the header.
133fe6060f1SDimitry Andric   void initTypeStr();
134fe6060f1SDimitry Andric   // Compute and record a short name of a type for C/C++ name suffix.
135fe6060f1SDimitry Andric   void initShortStr();
136fe6060f1SDimitry Andric };
137fe6060f1SDimitry Andric 
138fe6060f1SDimitry Andric using RVVTypePtr = RVVType *;
139fe6060f1SDimitry Andric using RVVTypes = std::vector<RVVTypePtr>;
140*04eeddc0SDimitry Andric using RISCVPredefinedMacroT = uint8_t;
141fe6060f1SDimitry Andric 
142*04eeddc0SDimitry Andric enum RISCVPredefinedMacro : RISCVPredefinedMacroT {
143fe6060f1SDimitry Andric   Basic = 0,
144*04eeddc0SDimitry Andric   V = 1 << 1,
145*04eeddc0SDimitry Andric   Zfh = 1 << 2,
146*04eeddc0SDimitry Andric   RV64 = 1 << 3,
147*04eeddc0SDimitry Andric   VectorMaxELen64 = 1 << 4,
148*04eeddc0SDimitry Andric   VectorMaxELenFp32 = 1 << 5,
149*04eeddc0SDimitry Andric   VectorMaxELenFp64 = 1 << 6,
150fe6060f1SDimitry Andric };
151fe6060f1SDimitry Andric 
152fe6060f1SDimitry Andric // TODO refactor RVVIntrinsic class design after support all intrinsic
153fe6060f1SDimitry Andric // combination. This represents an instantiation of an intrinsic with a
154fe6060f1SDimitry Andric // particular type and prototype
155fe6060f1SDimitry Andric class RVVIntrinsic {
156fe6060f1SDimitry Andric 
157fe6060f1SDimitry Andric private:
158349cc55cSDimitry Andric   std::string BuiltinName; // Builtin name
159349cc55cSDimitry Andric   std::string Name;        // C intrinsic name.
160fe6060f1SDimitry Andric   std::string MangledName;
161fe6060f1SDimitry Andric   std::string IRName;
162fe6060f1SDimitry Andric   bool IsMask;
163fe6060f1SDimitry Andric   bool HasVL;
164349cc55cSDimitry Andric   bool HasPolicy;
165fe6060f1SDimitry Andric   bool HasNoMaskedOverloaded;
166fe6060f1SDimitry Andric   bool HasAutoDef; // There is automiatic definition in header
167fe6060f1SDimitry Andric   std::string ManualCodegen;
168fe6060f1SDimitry Andric   RVVTypePtr OutputType; // Builtin output type
169fe6060f1SDimitry Andric   RVVTypes InputTypes;   // Builtin input types
170fe6060f1SDimitry Andric   // The types we use to obtain the specific LLVM intrinsic. They are index of
171fe6060f1SDimitry Andric   // InputTypes. -1 means the return type.
172fe6060f1SDimitry Andric   std::vector<int64_t> IntrinsicTypes;
173*04eeddc0SDimitry Andric   RISCVPredefinedMacroT RISCVPredefinedMacros = 0;
174fe6060f1SDimitry Andric   unsigned NF = 1;
175fe6060f1SDimitry Andric 
176fe6060f1SDimitry Andric public:
177fe6060f1SDimitry Andric   RVVIntrinsic(StringRef Name, StringRef Suffix, StringRef MangledName,
178349cc55cSDimitry Andric                StringRef MangledSuffix, StringRef IRName, bool IsMask,
179349cc55cSDimitry Andric                bool HasMaskedOffOperand, bool HasVL, bool HasPolicy,
180fe6060f1SDimitry Andric                bool HasNoMaskedOverloaded, bool HasAutoDef,
181fe6060f1SDimitry Andric                StringRef ManualCodegen, const RVVTypes &Types,
182fe6060f1SDimitry Andric                const std::vector<int64_t> &IntrinsicTypes,
183*04eeddc0SDimitry Andric                const std::vector<StringRef> &RequiredFeatures, unsigned NF);
184fe6060f1SDimitry Andric   ~RVVIntrinsic() = default;
185fe6060f1SDimitry Andric 
186349cc55cSDimitry Andric   StringRef getBuiltinName() const { return BuiltinName; }
187fe6060f1SDimitry Andric   StringRef getName() const { return Name; }
188fe6060f1SDimitry Andric   StringRef getMangledName() const { return MangledName; }
189fe6060f1SDimitry Andric   bool hasVL() const { return HasVL; }
190349cc55cSDimitry Andric   bool hasPolicy() const { return HasPolicy; }
191fe6060f1SDimitry Andric   bool hasNoMaskedOverloaded() const { return HasNoMaskedOverloaded; }
192fe6060f1SDimitry Andric   bool hasManualCodegen() const { return !ManualCodegen.empty(); }
193fe6060f1SDimitry Andric   bool hasAutoDef() const { return HasAutoDef; }
194fe6060f1SDimitry Andric   bool isMask() const { return IsMask; }
195fe6060f1SDimitry Andric   StringRef getIRName() const { return IRName; }
196fe6060f1SDimitry Andric   StringRef getManualCodegen() const { return ManualCodegen; }
197*04eeddc0SDimitry Andric   RISCVPredefinedMacroT getRISCVPredefinedMacros() const {
198*04eeddc0SDimitry Andric     return RISCVPredefinedMacros;
199*04eeddc0SDimitry Andric   }
200fe6060f1SDimitry Andric   unsigned getNF() const { return NF; }
201349cc55cSDimitry Andric   const std::vector<int64_t> &getIntrinsicTypes() const {
202349cc55cSDimitry Andric     return IntrinsicTypes;
203349cc55cSDimitry Andric   }
204fe6060f1SDimitry Andric 
205fe6060f1SDimitry Andric   // Return the type string for a BUILTIN() macro in Builtins.def.
206fe6060f1SDimitry Andric   std::string getBuiltinTypeStr() const;
207fe6060f1SDimitry Andric 
208fe6060f1SDimitry Andric   // Emit the code block for switch body in EmitRISCVBuiltinExpr, it should
209fe6060f1SDimitry Andric   // init the RVVIntrinsic ID and IntrinsicTypes.
210fe6060f1SDimitry Andric   void emitCodeGenSwitchBody(raw_ostream &o) const;
211fe6060f1SDimitry Andric 
212fe6060f1SDimitry Andric   // Emit the macros for mapping C/C++ intrinsic function to builtin functions.
213349cc55cSDimitry Andric   void emitIntrinsicFuncDef(raw_ostream &o) const;
214fe6060f1SDimitry Andric 
215fe6060f1SDimitry Andric   // Emit the mangled function definition.
216fe6060f1SDimitry Andric   void emitMangledFuncDef(raw_ostream &o) const;
217fe6060f1SDimitry Andric };
218fe6060f1SDimitry Andric 
219fe6060f1SDimitry Andric class RVVEmitter {
220fe6060f1SDimitry Andric private:
221fe6060f1SDimitry Andric   RecordKeeper &Records;
222fe6060f1SDimitry Andric   std::string HeaderCode;
223fe6060f1SDimitry Andric   // Concat BasicType, LMUL and Proto as key
224fe6060f1SDimitry Andric   StringMap<RVVType> LegalTypes;
225fe6060f1SDimitry Andric   StringSet<> IllegalTypes;
226fe6060f1SDimitry Andric 
227fe6060f1SDimitry Andric public:
228fe6060f1SDimitry Andric   RVVEmitter(RecordKeeper &R) : Records(R) {}
229fe6060f1SDimitry Andric 
230fe6060f1SDimitry Andric   /// Emit riscv_vector.h
231fe6060f1SDimitry Andric   void createHeader(raw_ostream &o);
232fe6060f1SDimitry Andric 
233fe6060f1SDimitry Andric   /// Emit all the __builtin prototypes and code needed by Sema.
234fe6060f1SDimitry Andric   void createBuiltins(raw_ostream &o);
235fe6060f1SDimitry Andric 
236fe6060f1SDimitry Andric   /// Emit all the information needed to map builtin -> LLVM IR intrinsic.
237fe6060f1SDimitry Andric   void createCodeGen(raw_ostream &o);
238fe6060f1SDimitry Andric 
239fe6060f1SDimitry Andric   std::string getSuffixStr(char Type, int Log2LMUL, StringRef Prototypes);
240fe6060f1SDimitry Andric 
241fe6060f1SDimitry Andric private:
242fe6060f1SDimitry Andric   /// Create all intrinsics and add them to \p Out
243fe6060f1SDimitry Andric   void createRVVIntrinsics(std::vector<std::unique_ptr<RVVIntrinsic>> &Out);
244349cc55cSDimitry Andric   /// Create Headers and add them to \p Out
245349cc55cSDimitry Andric   void createRVVHeaders(raw_ostream &OS);
246fe6060f1SDimitry Andric   /// Compute output and input types by applying different config (basic type
247fe6060f1SDimitry Andric   /// and LMUL with type transformers). It also record result of type in legal
248fe6060f1SDimitry Andric   /// or illegal set to avoid compute the  same config again. The result maybe
249fe6060f1SDimitry Andric   /// have illegal RVVType.
250fe6060f1SDimitry Andric   Optional<RVVTypes> computeTypes(BasicType BT, int Log2LMUL, unsigned NF,
251fe6060f1SDimitry Andric                                   ArrayRef<std::string> PrototypeSeq);
252fe6060f1SDimitry Andric   Optional<RVVTypePtr> computeType(BasicType BT, int Log2LMUL, StringRef Proto);
253fe6060f1SDimitry Andric 
254fe6060f1SDimitry Andric   /// Emit Acrh predecessor definitions and body, assume the element of Defs are
255fe6060f1SDimitry Andric   /// sorted by extension.
256fe6060f1SDimitry Andric   void emitArchMacroAndBody(
257fe6060f1SDimitry Andric       std::vector<std::unique_ptr<RVVIntrinsic>> &Defs, raw_ostream &o,
258fe6060f1SDimitry Andric       std::function<void(raw_ostream &, const RVVIntrinsic &)>);
259fe6060f1SDimitry Andric 
260fe6060f1SDimitry Andric   // Emit the architecture preprocessor definitions. Return true when emits
261fe6060f1SDimitry Andric   // non-empty string.
262*04eeddc0SDimitry Andric   bool emitMacroRestrictionStr(RISCVPredefinedMacroT PredefinedMacros,
263*04eeddc0SDimitry Andric                                raw_ostream &o);
264fe6060f1SDimitry Andric   // Slice Prototypes string into sub prototype string and process each sub
265fe6060f1SDimitry Andric   // prototype string individually in the Handler.
266fe6060f1SDimitry Andric   void parsePrototypes(StringRef Prototypes,
267fe6060f1SDimitry Andric                        std::function<void(StringRef)> Handler);
268fe6060f1SDimitry Andric };
269fe6060f1SDimitry Andric 
270fe6060f1SDimitry Andric } // namespace
271fe6060f1SDimitry Andric 
272fe6060f1SDimitry Andric //===----------------------------------------------------------------------===//
273fe6060f1SDimitry Andric // Type implementation
274fe6060f1SDimitry Andric //===----------------------------------------------------------------------===//
275fe6060f1SDimitry Andric 
276fe6060f1SDimitry Andric LMULType::LMULType(int NewLog2LMUL) {
277fe6060f1SDimitry Andric   // Check Log2LMUL is -3, -2, -1, 0, 1, 2, 3
278fe6060f1SDimitry Andric   assert(NewLog2LMUL <= 3 && NewLog2LMUL >= -3 && "Bad LMUL number!");
279fe6060f1SDimitry Andric   Log2LMUL = NewLog2LMUL;
280fe6060f1SDimitry Andric }
281fe6060f1SDimitry Andric 
282fe6060f1SDimitry Andric std::string LMULType::str() const {
283fe6060f1SDimitry Andric   if (Log2LMUL < 0)
284fe6060f1SDimitry Andric     return "mf" + utostr(1ULL << (-Log2LMUL));
285fe6060f1SDimitry Andric   return "m" + utostr(1ULL << Log2LMUL);
286fe6060f1SDimitry Andric }
287fe6060f1SDimitry Andric 
288fe6060f1SDimitry Andric VScaleVal LMULType::getScale(unsigned ElementBitwidth) const {
289fe6060f1SDimitry Andric   int Log2ScaleResult = 0;
290fe6060f1SDimitry Andric   switch (ElementBitwidth) {
291fe6060f1SDimitry Andric   default:
292fe6060f1SDimitry Andric     break;
293fe6060f1SDimitry Andric   case 8:
294fe6060f1SDimitry Andric     Log2ScaleResult = Log2LMUL + 3;
295fe6060f1SDimitry Andric     break;
296fe6060f1SDimitry Andric   case 16:
297fe6060f1SDimitry Andric     Log2ScaleResult = Log2LMUL + 2;
298fe6060f1SDimitry Andric     break;
299fe6060f1SDimitry Andric   case 32:
300fe6060f1SDimitry Andric     Log2ScaleResult = Log2LMUL + 1;
301fe6060f1SDimitry Andric     break;
302fe6060f1SDimitry Andric   case 64:
303fe6060f1SDimitry Andric     Log2ScaleResult = Log2LMUL;
304fe6060f1SDimitry Andric     break;
305fe6060f1SDimitry Andric   }
306fe6060f1SDimitry Andric   // Illegal vscale result would be less than 1
307fe6060f1SDimitry Andric   if (Log2ScaleResult < 0)
308fe6060f1SDimitry Andric     return None;
309fe6060f1SDimitry Andric   return 1 << Log2ScaleResult;
310fe6060f1SDimitry Andric }
311fe6060f1SDimitry Andric 
312fe6060f1SDimitry Andric void LMULType::MulLog2LMUL(int log2LMUL) { Log2LMUL += log2LMUL; }
313fe6060f1SDimitry Andric 
314fe6060f1SDimitry Andric LMULType &LMULType::operator*=(uint32_t RHS) {
315fe6060f1SDimitry Andric   assert(isPowerOf2_32(RHS));
316fe6060f1SDimitry Andric   this->Log2LMUL = this->Log2LMUL + Log2_32(RHS);
317fe6060f1SDimitry Andric   return *this;
318fe6060f1SDimitry Andric }
319fe6060f1SDimitry Andric 
320fe6060f1SDimitry Andric RVVType::RVVType(BasicType BT, int Log2LMUL, StringRef prototype)
321fe6060f1SDimitry Andric     : BT(BT), LMUL(LMULType(Log2LMUL)) {
322fe6060f1SDimitry Andric   applyBasicType();
323fe6060f1SDimitry Andric   applyModifier(prototype);
324fe6060f1SDimitry Andric   Valid = verifyType();
325fe6060f1SDimitry Andric   if (Valid) {
326fe6060f1SDimitry Andric     initBuiltinStr();
327fe6060f1SDimitry Andric     initTypeStr();
328fe6060f1SDimitry Andric     if (isVector()) {
329fe6060f1SDimitry Andric       initClangBuiltinStr();
330fe6060f1SDimitry Andric     }
331fe6060f1SDimitry Andric   }
332fe6060f1SDimitry Andric }
333fe6060f1SDimitry Andric 
334fe6060f1SDimitry Andric // clang-format off
335fe6060f1SDimitry Andric // boolean type are encoded the ratio of n (SEW/LMUL)
336fe6060f1SDimitry Andric // SEW/LMUL | 1         | 2         | 4         | 8        | 16        | 32        | 64
337fe6060f1SDimitry Andric // c type   | vbool64_t | vbool32_t | vbool16_t | vbool8_t | vbool4_t  | vbool2_t  | vbool1_t
338fe6060f1SDimitry Andric // IR type  | nxv1i1    | nxv2i1    | nxv4i1    | nxv8i1   | nxv16i1   | nxv32i1   | nxv64i1
339fe6060f1SDimitry Andric 
340fe6060f1SDimitry Andric // type\lmul | 1/8    | 1/4      | 1/2     | 1       | 2        | 4        | 8
341fe6060f1SDimitry Andric // --------  |------  | -------- | ------- | ------- | -------- | -------- | --------
342fe6060f1SDimitry Andric // i64       | N/A    | N/A      | N/A     | nxv1i64 | nxv2i64  | nxv4i64  | nxv8i64
343fe6060f1SDimitry Andric // i32       | N/A    | N/A      | nxv1i32 | nxv2i32 | nxv4i32  | nxv8i32  | nxv16i32
344fe6060f1SDimitry Andric // i16       | N/A    | nxv1i16  | nxv2i16 | nxv4i16 | nxv8i16  | nxv16i16 | nxv32i16
345fe6060f1SDimitry Andric // i8        | nxv1i8 | nxv2i8   | nxv4i8  | nxv8i8  | nxv16i8  | nxv32i8  | nxv64i8
346fe6060f1SDimitry Andric // double    | N/A    | N/A      | N/A     | nxv1f64 | nxv2f64  | nxv4f64  | nxv8f64
347fe6060f1SDimitry Andric // float     | N/A    | N/A      | nxv1f32 | nxv2f32 | nxv4f32  | nxv8f32  | nxv16f32
348fe6060f1SDimitry Andric // half      | N/A    | nxv1f16  | nxv2f16 | nxv4f16 | nxv8f16  | nxv16f16 | nxv32f16
349fe6060f1SDimitry Andric // clang-format on
350fe6060f1SDimitry Andric 
351fe6060f1SDimitry Andric bool RVVType::verifyType() const {
352fe6060f1SDimitry Andric   if (ScalarType == Invalid)
353fe6060f1SDimitry Andric     return false;
354fe6060f1SDimitry Andric   if (isScalar())
355fe6060f1SDimitry Andric     return true;
356fe6060f1SDimitry Andric   if (!Scale.hasValue())
357fe6060f1SDimitry Andric     return false;
358fe6060f1SDimitry Andric   if (isFloat() && ElementBitwidth == 8)
359fe6060f1SDimitry Andric     return false;
360fe6060f1SDimitry Andric   unsigned V = Scale.getValue();
361fe6060f1SDimitry Andric   switch (ElementBitwidth) {
362fe6060f1SDimitry Andric   case 1:
363fe6060f1SDimitry Andric   case 8:
364fe6060f1SDimitry Andric     // Check Scale is 1,2,4,8,16,32,64
365fe6060f1SDimitry Andric     return (V <= 64 && isPowerOf2_32(V));
366fe6060f1SDimitry Andric   case 16:
367fe6060f1SDimitry Andric     // Check Scale is 1,2,4,8,16,32
368fe6060f1SDimitry Andric     return (V <= 32 && isPowerOf2_32(V));
369fe6060f1SDimitry Andric   case 32:
370fe6060f1SDimitry Andric     // Check Scale is 1,2,4,8,16
371fe6060f1SDimitry Andric     return (V <= 16 && isPowerOf2_32(V));
372fe6060f1SDimitry Andric   case 64:
373fe6060f1SDimitry Andric     // Check Scale is 1,2,4,8
374fe6060f1SDimitry Andric     return (V <= 8 && isPowerOf2_32(V));
375fe6060f1SDimitry Andric   }
376fe6060f1SDimitry Andric   return false;
377fe6060f1SDimitry Andric }
378fe6060f1SDimitry Andric 
379fe6060f1SDimitry Andric void RVVType::initBuiltinStr() {
380fe6060f1SDimitry Andric   assert(isValid() && "RVVType is invalid");
381fe6060f1SDimitry Andric   switch (ScalarType) {
382fe6060f1SDimitry Andric   case ScalarTypeKind::Void:
383fe6060f1SDimitry Andric     BuiltinStr = "v";
384fe6060f1SDimitry Andric     return;
385fe6060f1SDimitry Andric   case ScalarTypeKind::Size_t:
386fe6060f1SDimitry Andric     BuiltinStr = "z";
387fe6060f1SDimitry Andric     if (IsImmediate)
388fe6060f1SDimitry Andric       BuiltinStr = "I" + BuiltinStr;
389fe6060f1SDimitry Andric     if (IsPointer)
390fe6060f1SDimitry Andric       BuiltinStr += "*";
391fe6060f1SDimitry Andric     return;
392fe6060f1SDimitry Andric   case ScalarTypeKind::Ptrdiff_t:
393fe6060f1SDimitry Andric     BuiltinStr = "Y";
394fe6060f1SDimitry Andric     return;
395fe6060f1SDimitry Andric   case ScalarTypeKind::UnsignedLong:
396fe6060f1SDimitry Andric     BuiltinStr = "ULi";
397fe6060f1SDimitry Andric     return;
398fe6060f1SDimitry Andric   case ScalarTypeKind::SignedLong:
399fe6060f1SDimitry Andric     BuiltinStr = "Li";
400fe6060f1SDimitry Andric     return;
401fe6060f1SDimitry Andric   case ScalarTypeKind::Boolean:
402fe6060f1SDimitry Andric     assert(ElementBitwidth == 1);
403fe6060f1SDimitry Andric     BuiltinStr += "b";
404fe6060f1SDimitry Andric     break;
405fe6060f1SDimitry Andric   case ScalarTypeKind::SignedInteger:
406fe6060f1SDimitry Andric   case ScalarTypeKind::UnsignedInteger:
407fe6060f1SDimitry Andric     switch (ElementBitwidth) {
408fe6060f1SDimitry Andric     case 8:
409fe6060f1SDimitry Andric       BuiltinStr += "c";
410fe6060f1SDimitry Andric       break;
411fe6060f1SDimitry Andric     case 16:
412fe6060f1SDimitry Andric       BuiltinStr += "s";
413fe6060f1SDimitry Andric       break;
414fe6060f1SDimitry Andric     case 32:
415fe6060f1SDimitry Andric       BuiltinStr += "i";
416fe6060f1SDimitry Andric       break;
417fe6060f1SDimitry Andric     case 64:
418fe6060f1SDimitry Andric       BuiltinStr += "Wi";
419fe6060f1SDimitry Andric       break;
420fe6060f1SDimitry Andric     default:
421fe6060f1SDimitry Andric       llvm_unreachable("Unhandled ElementBitwidth!");
422fe6060f1SDimitry Andric     }
423fe6060f1SDimitry Andric     if (isSignedInteger())
424fe6060f1SDimitry Andric       BuiltinStr = "S" + BuiltinStr;
425fe6060f1SDimitry Andric     else
426fe6060f1SDimitry Andric       BuiltinStr = "U" + BuiltinStr;
427fe6060f1SDimitry Andric     break;
428fe6060f1SDimitry Andric   case ScalarTypeKind::Float:
429fe6060f1SDimitry Andric     switch (ElementBitwidth) {
430fe6060f1SDimitry Andric     case 16:
431fe6060f1SDimitry Andric       BuiltinStr += "x";
432fe6060f1SDimitry Andric       break;
433fe6060f1SDimitry Andric     case 32:
434fe6060f1SDimitry Andric       BuiltinStr += "f";
435fe6060f1SDimitry Andric       break;
436fe6060f1SDimitry Andric     case 64:
437fe6060f1SDimitry Andric       BuiltinStr += "d";
438fe6060f1SDimitry Andric       break;
439fe6060f1SDimitry Andric     default:
440fe6060f1SDimitry Andric       llvm_unreachable("Unhandled ElementBitwidth!");
441fe6060f1SDimitry Andric     }
442fe6060f1SDimitry Andric     break;
443fe6060f1SDimitry Andric   default:
444fe6060f1SDimitry Andric     llvm_unreachable("ScalarType is invalid!");
445fe6060f1SDimitry Andric   }
446fe6060f1SDimitry Andric   if (IsImmediate)
447fe6060f1SDimitry Andric     BuiltinStr = "I" + BuiltinStr;
448fe6060f1SDimitry Andric   if (isScalar()) {
449fe6060f1SDimitry Andric     if (IsConstant)
450fe6060f1SDimitry Andric       BuiltinStr += "C";
451fe6060f1SDimitry Andric     if (IsPointer)
452fe6060f1SDimitry Andric       BuiltinStr += "*";
453fe6060f1SDimitry Andric     return;
454fe6060f1SDimitry Andric   }
455fe6060f1SDimitry Andric   BuiltinStr = "q" + utostr(Scale.getValue()) + BuiltinStr;
456*04eeddc0SDimitry Andric   // Pointer to vector types. Defined for segment load intrinsics.
457*04eeddc0SDimitry Andric   // segment load intrinsics have pointer type arguments to store the loaded
458fe6060f1SDimitry Andric   // vector values.
459fe6060f1SDimitry Andric   if (IsPointer)
460fe6060f1SDimitry Andric     BuiltinStr += "*";
461fe6060f1SDimitry Andric }
462fe6060f1SDimitry Andric 
463fe6060f1SDimitry Andric void RVVType::initClangBuiltinStr() {
464fe6060f1SDimitry Andric   assert(isValid() && "RVVType is invalid");
465fe6060f1SDimitry Andric   assert(isVector() && "Handle Vector type only");
466fe6060f1SDimitry Andric 
467fe6060f1SDimitry Andric   ClangBuiltinStr = "__rvv_";
468fe6060f1SDimitry Andric   switch (ScalarType) {
469fe6060f1SDimitry Andric   case ScalarTypeKind::Boolean:
470fe6060f1SDimitry Andric     ClangBuiltinStr += "bool" + utostr(64 / Scale.getValue()) + "_t";
471fe6060f1SDimitry Andric     return;
472fe6060f1SDimitry Andric   case ScalarTypeKind::Float:
473fe6060f1SDimitry Andric     ClangBuiltinStr += "float";
474fe6060f1SDimitry Andric     break;
475fe6060f1SDimitry Andric   case ScalarTypeKind::SignedInteger:
476fe6060f1SDimitry Andric     ClangBuiltinStr += "int";
477fe6060f1SDimitry Andric     break;
478fe6060f1SDimitry Andric   case ScalarTypeKind::UnsignedInteger:
479fe6060f1SDimitry Andric     ClangBuiltinStr += "uint";
480fe6060f1SDimitry Andric     break;
481fe6060f1SDimitry Andric   default:
482fe6060f1SDimitry Andric     llvm_unreachable("ScalarTypeKind is invalid");
483fe6060f1SDimitry Andric   }
484fe6060f1SDimitry Andric   ClangBuiltinStr += utostr(ElementBitwidth) + LMUL.str() + "_t";
485fe6060f1SDimitry Andric }
486fe6060f1SDimitry Andric 
487fe6060f1SDimitry Andric void RVVType::initTypeStr() {
488fe6060f1SDimitry Andric   assert(isValid() && "RVVType is invalid");
489fe6060f1SDimitry Andric 
490fe6060f1SDimitry Andric   if (IsConstant)
491fe6060f1SDimitry Andric     Str += "const ";
492fe6060f1SDimitry Andric 
493fe6060f1SDimitry Andric   auto getTypeString = [&](StringRef TypeStr) {
494fe6060f1SDimitry Andric     if (isScalar())
495fe6060f1SDimitry Andric       return Twine(TypeStr + Twine(ElementBitwidth) + "_t").str();
496fe6060f1SDimitry Andric     return Twine("v" + TypeStr + Twine(ElementBitwidth) + LMUL.str() + "_t")
497fe6060f1SDimitry Andric         .str();
498fe6060f1SDimitry Andric   };
499fe6060f1SDimitry Andric 
500fe6060f1SDimitry Andric   switch (ScalarType) {
501fe6060f1SDimitry Andric   case ScalarTypeKind::Void:
502fe6060f1SDimitry Andric     Str = "void";
503fe6060f1SDimitry Andric     return;
504fe6060f1SDimitry Andric   case ScalarTypeKind::Size_t:
505fe6060f1SDimitry Andric     Str = "size_t";
506fe6060f1SDimitry Andric     if (IsPointer)
507fe6060f1SDimitry Andric       Str += " *";
508fe6060f1SDimitry Andric     return;
509fe6060f1SDimitry Andric   case ScalarTypeKind::Ptrdiff_t:
510fe6060f1SDimitry Andric     Str = "ptrdiff_t";
511fe6060f1SDimitry Andric     return;
512fe6060f1SDimitry Andric   case ScalarTypeKind::UnsignedLong:
513fe6060f1SDimitry Andric     Str = "unsigned long";
514fe6060f1SDimitry Andric     return;
515fe6060f1SDimitry Andric   case ScalarTypeKind::SignedLong:
516fe6060f1SDimitry Andric     Str = "long";
517fe6060f1SDimitry Andric     return;
518fe6060f1SDimitry Andric   case ScalarTypeKind::Boolean:
519fe6060f1SDimitry Andric     if (isScalar())
520fe6060f1SDimitry Andric       Str += "bool";
521fe6060f1SDimitry Andric     else
522fe6060f1SDimitry Andric       // Vector bool is special case, the formulate is
523fe6060f1SDimitry Andric       // `vbool<N>_t = MVT::nxv<64/N>i1` ex. vbool16_t = MVT::4i1
524fe6060f1SDimitry Andric       Str += "vbool" + utostr(64 / Scale.getValue()) + "_t";
525fe6060f1SDimitry Andric     break;
526fe6060f1SDimitry Andric   case ScalarTypeKind::Float:
527fe6060f1SDimitry Andric     if (isScalar()) {
528fe6060f1SDimitry Andric       if (ElementBitwidth == 64)
529fe6060f1SDimitry Andric         Str += "double";
530fe6060f1SDimitry Andric       else if (ElementBitwidth == 32)
531fe6060f1SDimitry Andric         Str += "float";
532fe6060f1SDimitry Andric       else if (ElementBitwidth == 16)
533fe6060f1SDimitry Andric         Str += "_Float16";
534fe6060f1SDimitry Andric       else
535fe6060f1SDimitry Andric         llvm_unreachable("Unhandled floating type.");
536fe6060f1SDimitry Andric     } else
537fe6060f1SDimitry Andric       Str += getTypeString("float");
538fe6060f1SDimitry Andric     break;
539fe6060f1SDimitry Andric   case ScalarTypeKind::SignedInteger:
540fe6060f1SDimitry Andric     Str += getTypeString("int");
541fe6060f1SDimitry Andric     break;
542fe6060f1SDimitry Andric   case ScalarTypeKind::UnsignedInteger:
543fe6060f1SDimitry Andric     Str += getTypeString("uint");
544fe6060f1SDimitry Andric     break;
545fe6060f1SDimitry Andric   default:
546fe6060f1SDimitry Andric     llvm_unreachable("ScalarType is invalid!");
547fe6060f1SDimitry Andric   }
548fe6060f1SDimitry Andric   if (IsPointer)
549fe6060f1SDimitry Andric     Str += " *";
550fe6060f1SDimitry Andric }
551fe6060f1SDimitry Andric 
552fe6060f1SDimitry Andric void RVVType::initShortStr() {
553fe6060f1SDimitry Andric   switch (ScalarType) {
554fe6060f1SDimitry Andric   case ScalarTypeKind::Boolean:
555fe6060f1SDimitry Andric     assert(isVector());
556fe6060f1SDimitry Andric     ShortStr = "b" + utostr(64 / Scale.getValue());
557fe6060f1SDimitry Andric     return;
558fe6060f1SDimitry Andric   case ScalarTypeKind::Float:
559fe6060f1SDimitry Andric     ShortStr = "f" + utostr(ElementBitwidth);
560fe6060f1SDimitry Andric     break;
561fe6060f1SDimitry Andric   case ScalarTypeKind::SignedInteger:
562fe6060f1SDimitry Andric     ShortStr = "i" + utostr(ElementBitwidth);
563fe6060f1SDimitry Andric     break;
564fe6060f1SDimitry Andric   case ScalarTypeKind::UnsignedInteger:
565fe6060f1SDimitry Andric     ShortStr = "u" + utostr(ElementBitwidth);
566fe6060f1SDimitry Andric     break;
567fe6060f1SDimitry Andric   default:
568fe6060f1SDimitry Andric     PrintFatalError("Unhandled case!");
569fe6060f1SDimitry Andric   }
570fe6060f1SDimitry Andric   if (isVector())
571fe6060f1SDimitry Andric     ShortStr += LMUL.str();
572fe6060f1SDimitry Andric }
573fe6060f1SDimitry Andric 
574fe6060f1SDimitry Andric void RVVType::applyBasicType() {
575fe6060f1SDimitry Andric   switch (BT) {
576fe6060f1SDimitry Andric   case 'c':
577fe6060f1SDimitry Andric     ElementBitwidth = 8;
578fe6060f1SDimitry Andric     ScalarType = ScalarTypeKind::SignedInteger;
579fe6060f1SDimitry Andric     break;
580fe6060f1SDimitry Andric   case 's':
581fe6060f1SDimitry Andric     ElementBitwidth = 16;
582fe6060f1SDimitry Andric     ScalarType = ScalarTypeKind::SignedInteger;
583fe6060f1SDimitry Andric     break;
584fe6060f1SDimitry Andric   case 'i':
585fe6060f1SDimitry Andric     ElementBitwidth = 32;
586fe6060f1SDimitry Andric     ScalarType = ScalarTypeKind::SignedInteger;
587fe6060f1SDimitry Andric     break;
588fe6060f1SDimitry Andric   case 'l':
589fe6060f1SDimitry Andric     ElementBitwidth = 64;
590fe6060f1SDimitry Andric     ScalarType = ScalarTypeKind::SignedInteger;
591fe6060f1SDimitry Andric     break;
592fe6060f1SDimitry Andric   case 'x':
593fe6060f1SDimitry Andric     ElementBitwidth = 16;
594fe6060f1SDimitry Andric     ScalarType = ScalarTypeKind::Float;
595fe6060f1SDimitry Andric     break;
596fe6060f1SDimitry Andric   case 'f':
597fe6060f1SDimitry Andric     ElementBitwidth = 32;
598fe6060f1SDimitry Andric     ScalarType = ScalarTypeKind::Float;
599fe6060f1SDimitry Andric     break;
600fe6060f1SDimitry Andric   case 'd':
601fe6060f1SDimitry Andric     ElementBitwidth = 64;
602fe6060f1SDimitry Andric     ScalarType = ScalarTypeKind::Float;
603fe6060f1SDimitry Andric     break;
604fe6060f1SDimitry Andric   default:
605fe6060f1SDimitry Andric     PrintFatalError("Unhandled type code!");
606fe6060f1SDimitry Andric   }
607fe6060f1SDimitry Andric   assert(ElementBitwidth != 0 && "Bad element bitwidth!");
608fe6060f1SDimitry Andric }
609fe6060f1SDimitry Andric 
610fe6060f1SDimitry Andric void RVVType::applyModifier(StringRef Transformer) {
611fe6060f1SDimitry Andric   if (Transformer.empty())
612fe6060f1SDimitry Andric     return;
613fe6060f1SDimitry Andric   // Handle primitive type transformer
614fe6060f1SDimitry Andric   auto PType = Transformer.back();
615fe6060f1SDimitry Andric   switch (PType) {
616fe6060f1SDimitry Andric   case 'e':
617fe6060f1SDimitry Andric     Scale = 0;
618fe6060f1SDimitry Andric     break;
619fe6060f1SDimitry Andric   case 'v':
620fe6060f1SDimitry Andric     Scale = LMUL.getScale(ElementBitwidth);
621fe6060f1SDimitry Andric     break;
622fe6060f1SDimitry Andric   case 'w':
623fe6060f1SDimitry Andric     ElementBitwidth *= 2;
624fe6060f1SDimitry Andric     LMUL *= 2;
625fe6060f1SDimitry Andric     Scale = LMUL.getScale(ElementBitwidth);
626fe6060f1SDimitry Andric     break;
627fe6060f1SDimitry Andric   case 'q':
628fe6060f1SDimitry Andric     ElementBitwidth *= 4;
629fe6060f1SDimitry Andric     LMUL *= 4;
630fe6060f1SDimitry Andric     Scale = LMUL.getScale(ElementBitwidth);
631fe6060f1SDimitry Andric     break;
632fe6060f1SDimitry Andric   case 'o':
633fe6060f1SDimitry Andric     ElementBitwidth *= 8;
634fe6060f1SDimitry Andric     LMUL *= 8;
635fe6060f1SDimitry Andric     Scale = LMUL.getScale(ElementBitwidth);
636fe6060f1SDimitry Andric     break;
637fe6060f1SDimitry Andric   case 'm':
638fe6060f1SDimitry Andric     ScalarType = ScalarTypeKind::Boolean;
639fe6060f1SDimitry Andric     Scale = LMUL.getScale(ElementBitwidth);
640fe6060f1SDimitry Andric     ElementBitwidth = 1;
641fe6060f1SDimitry Andric     break;
642fe6060f1SDimitry Andric   case '0':
643fe6060f1SDimitry Andric     ScalarType = ScalarTypeKind::Void;
644fe6060f1SDimitry Andric     break;
645fe6060f1SDimitry Andric   case 'z':
646fe6060f1SDimitry Andric     ScalarType = ScalarTypeKind::Size_t;
647fe6060f1SDimitry Andric     break;
648fe6060f1SDimitry Andric   case 't':
649fe6060f1SDimitry Andric     ScalarType = ScalarTypeKind::Ptrdiff_t;
650fe6060f1SDimitry Andric     break;
651fe6060f1SDimitry Andric   case 'u':
652fe6060f1SDimitry Andric     ScalarType = ScalarTypeKind::UnsignedLong;
653fe6060f1SDimitry Andric     break;
654fe6060f1SDimitry Andric   case 'l':
655fe6060f1SDimitry Andric     ScalarType = ScalarTypeKind::SignedLong;
656fe6060f1SDimitry Andric     break;
657fe6060f1SDimitry Andric   default:
658fe6060f1SDimitry Andric     PrintFatalError("Illegal primitive type transformers!");
659fe6060f1SDimitry Andric   }
660fe6060f1SDimitry Andric   Transformer = Transformer.drop_back();
661fe6060f1SDimitry Andric 
662fe6060f1SDimitry Andric   // Extract and compute complex type transformer. It can only appear one time.
663fe6060f1SDimitry Andric   if (Transformer.startswith("(")) {
664fe6060f1SDimitry Andric     size_t Idx = Transformer.find(')');
665fe6060f1SDimitry Andric     assert(Idx != StringRef::npos);
666fe6060f1SDimitry Andric     StringRef ComplexType = Transformer.slice(1, Idx);
667fe6060f1SDimitry Andric     Transformer = Transformer.drop_front(Idx + 1);
668349cc55cSDimitry Andric     assert(!Transformer.contains('(') &&
669fe6060f1SDimitry Andric            "Only allow one complex type transformer");
670fe6060f1SDimitry Andric 
671fe6060f1SDimitry Andric     auto UpdateAndCheckComplexProto = [&]() {
672fe6060f1SDimitry Andric       Scale = LMUL.getScale(ElementBitwidth);
673fe6060f1SDimitry Andric       const StringRef VectorPrototypes("vwqom");
674fe6060f1SDimitry Andric       if (!VectorPrototypes.contains(PType))
675fe6060f1SDimitry Andric         PrintFatalError("Complex type transformer only supports vector type!");
676fe6060f1SDimitry Andric       if (Transformer.find_first_of("PCKWS") != StringRef::npos)
677fe6060f1SDimitry Andric         PrintFatalError(
678fe6060f1SDimitry Andric             "Illegal type transformer for Complex type transformer");
679fe6060f1SDimitry Andric     };
680fe6060f1SDimitry Andric     auto ComputeFixedLog2LMUL =
681fe6060f1SDimitry Andric         [&](StringRef Value,
682fe6060f1SDimitry Andric             std::function<bool(const int32_t &, const int32_t &)> Compare) {
683fe6060f1SDimitry Andric           int32_t Log2LMUL;
684fe6060f1SDimitry Andric           Value.getAsInteger(10, Log2LMUL);
685fe6060f1SDimitry Andric           if (!Compare(Log2LMUL, LMUL.Log2LMUL)) {
686fe6060f1SDimitry Andric             ScalarType = Invalid;
687fe6060f1SDimitry Andric             return false;
688fe6060f1SDimitry Andric           }
689fe6060f1SDimitry Andric           // Update new LMUL
690fe6060f1SDimitry Andric           LMUL = LMULType(Log2LMUL);
691fe6060f1SDimitry Andric           UpdateAndCheckComplexProto();
692fe6060f1SDimitry Andric           return true;
693fe6060f1SDimitry Andric         };
694fe6060f1SDimitry Andric     auto ComplexTT = ComplexType.split(":");
695fe6060f1SDimitry Andric     if (ComplexTT.first == "Log2EEW") {
696fe6060f1SDimitry Andric       uint32_t Log2EEW;
697fe6060f1SDimitry Andric       ComplexTT.second.getAsInteger(10, Log2EEW);
698fe6060f1SDimitry Andric       // update new elmul = (eew/sew) * lmul
699fe6060f1SDimitry Andric       LMUL.MulLog2LMUL(Log2EEW - Log2_32(ElementBitwidth));
700fe6060f1SDimitry Andric       // update new eew
701fe6060f1SDimitry Andric       ElementBitwidth = 1 << Log2EEW;
702fe6060f1SDimitry Andric       ScalarType = ScalarTypeKind::SignedInteger;
703fe6060f1SDimitry Andric       UpdateAndCheckComplexProto();
704fe6060f1SDimitry Andric     } else if (ComplexTT.first == "FixedSEW") {
705fe6060f1SDimitry Andric       uint32_t NewSEW;
706fe6060f1SDimitry Andric       ComplexTT.second.getAsInteger(10, NewSEW);
707fe6060f1SDimitry Andric       // Set invalid type if src and dst SEW are same.
708fe6060f1SDimitry Andric       if (ElementBitwidth == NewSEW) {
709fe6060f1SDimitry Andric         ScalarType = Invalid;
710fe6060f1SDimitry Andric         return;
711fe6060f1SDimitry Andric       }
712fe6060f1SDimitry Andric       // Update new SEW
713fe6060f1SDimitry Andric       ElementBitwidth = NewSEW;
714fe6060f1SDimitry Andric       UpdateAndCheckComplexProto();
715fe6060f1SDimitry Andric     } else if (ComplexTT.first == "LFixedLog2LMUL") {
716fe6060f1SDimitry Andric       // New LMUL should be larger than old
717fe6060f1SDimitry Andric       if (!ComputeFixedLog2LMUL(ComplexTT.second, std::greater<int32_t>()))
718fe6060f1SDimitry Andric         return;
719fe6060f1SDimitry Andric     } else if (ComplexTT.first == "SFixedLog2LMUL") {
720fe6060f1SDimitry Andric       // New LMUL should be smaller than old
721fe6060f1SDimitry Andric       if (!ComputeFixedLog2LMUL(ComplexTT.second, std::less<int32_t>()))
722fe6060f1SDimitry Andric         return;
723fe6060f1SDimitry Andric     } else {
724fe6060f1SDimitry Andric       PrintFatalError("Illegal complex type transformers!");
725fe6060f1SDimitry Andric     }
726fe6060f1SDimitry Andric   }
727fe6060f1SDimitry Andric 
728fe6060f1SDimitry Andric   // Compute the remain type transformers
729fe6060f1SDimitry Andric   for (char I : Transformer) {
730fe6060f1SDimitry Andric     switch (I) {
731fe6060f1SDimitry Andric     case 'P':
732fe6060f1SDimitry Andric       if (IsConstant)
733fe6060f1SDimitry Andric         PrintFatalError("'P' transformer cannot be used after 'C'");
734fe6060f1SDimitry Andric       if (IsPointer)
735fe6060f1SDimitry Andric         PrintFatalError("'P' transformer cannot be used twice");
736fe6060f1SDimitry Andric       IsPointer = true;
737fe6060f1SDimitry Andric       break;
738fe6060f1SDimitry Andric     case 'C':
739fe6060f1SDimitry Andric       if (IsConstant)
740fe6060f1SDimitry Andric         PrintFatalError("'C' transformer cannot be used twice");
741fe6060f1SDimitry Andric       IsConstant = true;
742fe6060f1SDimitry Andric       break;
743fe6060f1SDimitry Andric     case 'K':
744fe6060f1SDimitry Andric       IsImmediate = true;
745fe6060f1SDimitry Andric       break;
746fe6060f1SDimitry Andric     case 'U':
747fe6060f1SDimitry Andric       ScalarType = ScalarTypeKind::UnsignedInteger;
748fe6060f1SDimitry Andric       break;
749fe6060f1SDimitry Andric     case 'I':
750fe6060f1SDimitry Andric       ScalarType = ScalarTypeKind::SignedInteger;
751fe6060f1SDimitry Andric       break;
752fe6060f1SDimitry Andric     case 'F':
753fe6060f1SDimitry Andric       ScalarType = ScalarTypeKind::Float;
754fe6060f1SDimitry Andric       break;
755fe6060f1SDimitry Andric     case 'S':
756fe6060f1SDimitry Andric       LMUL = LMULType(0);
757fe6060f1SDimitry Andric       // Update ElementBitwidth need to update Scale too.
758fe6060f1SDimitry Andric       Scale = LMUL.getScale(ElementBitwidth);
759fe6060f1SDimitry Andric       break;
760fe6060f1SDimitry Andric     default:
761fe6060f1SDimitry Andric       PrintFatalError("Illegal non-primitive type transformer!");
762fe6060f1SDimitry Andric     }
763fe6060f1SDimitry Andric   }
764fe6060f1SDimitry Andric }
765fe6060f1SDimitry Andric 
766fe6060f1SDimitry Andric //===----------------------------------------------------------------------===//
767fe6060f1SDimitry Andric // RVVIntrinsic implementation
768fe6060f1SDimitry Andric //===----------------------------------------------------------------------===//
769fe6060f1SDimitry Andric RVVIntrinsic::RVVIntrinsic(StringRef NewName, StringRef Suffix,
770fe6060f1SDimitry Andric                            StringRef NewMangledName, StringRef MangledSuffix,
771349cc55cSDimitry Andric                            StringRef IRName, bool IsMask,
772349cc55cSDimitry Andric                            bool HasMaskedOffOperand, bool HasVL, bool HasPolicy,
773fe6060f1SDimitry Andric                            bool HasNoMaskedOverloaded, bool HasAutoDef,
774fe6060f1SDimitry Andric                            StringRef ManualCodegen, const RVVTypes &OutInTypes,
775fe6060f1SDimitry Andric                            const std::vector<int64_t> &NewIntrinsicTypes,
776*04eeddc0SDimitry Andric                            const std::vector<StringRef> &RequiredFeatures,
777*04eeddc0SDimitry Andric                            unsigned NF)
778349cc55cSDimitry Andric     : IRName(IRName), IsMask(IsMask), HasVL(HasVL), HasPolicy(HasPolicy),
779fe6060f1SDimitry Andric       HasNoMaskedOverloaded(HasNoMaskedOverloaded), HasAutoDef(HasAutoDef),
780fe6060f1SDimitry Andric       ManualCodegen(ManualCodegen.str()), NF(NF) {
781fe6060f1SDimitry Andric 
782349cc55cSDimitry Andric   // Init BuiltinName, Name and MangledName
783349cc55cSDimitry Andric   BuiltinName = NewName.str();
784349cc55cSDimitry Andric   Name = BuiltinName;
785fe6060f1SDimitry Andric   if (NewMangledName.empty())
786fe6060f1SDimitry Andric     MangledName = NewName.split("_").first.str();
787fe6060f1SDimitry Andric   else
788fe6060f1SDimitry Andric     MangledName = NewMangledName.str();
789fe6060f1SDimitry Andric   if (!Suffix.empty())
790fe6060f1SDimitry Andric     Name += "_" + Suffix.str();
791fe6060f1SDimitry Andric   if (!MangledSuffix.empty())
792fe6060f1SDimitry Andric     MangledName += "_" + MangledSuffix.str();
793fe6060f1SDimitry Andric   if (IsMask) {
794349cc55cSDimitry Andric     BuiltinName += "_m";
795fe6060f1SDimitry Andric     Name += "_m";
796fe6060f1SDimitry Andric   }
797349cc55cSDimitry Andric 
798fe6060f1SDimitry Andric   // Init RISC-V extensions
799fe6060f1SDimitry Andric   for (const auto &T : OutInTypes) {
800fe6060f1SDimitry Andric     if (T->isFloatVector(16) || T->isFloat(16))
801*04eeddc0SDimitry Andric       RISCVPredefinedMacros |= RISCVPredefinedMacro::Zfh;
802*04eeddc0SDimitry Andric     if (T->isFloatVector(32))
803*04eeddc0SDimitry Andric       RISCVPredefinedMacros |= RISCVPredefinedMacro::VectorMaxELenFp32;
804*04eeddc0SDimitry Andric     if (T->isFloatVector(64))
805*04eeddc0SDimitry Andric       RISCVPredefinedMacros |= RISCVPredefinedMacro::VectorMaxELenFp64;
806*04eeddc0SDimitry Andric     if (T->isVector(64))
807*04eeddc0SDimitry Andric       RISCVPredefinedMacros |= RISCVPredefinedMacro::VectorMaxELen64;
808fe6060f1SDimitry Andric   }
809*04eeddc0SDimitry Andric   for (auto Feature : RequiredFeatures) {
810*04eeddc0SDimitry Andric     if (Feature == "RV64")
811*04eeddc0SDimitry Andric       RISCVPredefinedMacros |= RISCVPredefinedMacro::RV64;
812*04eeddc0SDimitry Andric     // Note: Full multiply instruction (mulh, mulhu, mulhsu, smul) for EEW=64
813*04eeddc0SDimitry Andric     // require V.
814*04eeddc0SDimitry Andric     if (Feature == "FullMultiply" &&
815*04eeddc0SDimitry Andric         (RISCVPredefinedMacros & RISCVPredefinedMacro::VectorMaxELen64))
816*04eeddc0SDimitry Andric       RISCVPredefinedMacros |= RISCVPredefinedMacro::V;
817*04eeddc0SDimitry Andric   }
818fe6060f1SDimitry Andric 
819fe6060f1SDimitry Andric   // Init OutputType and InputTypes
820fe6060f1SDimitry Andric   OutputType = OutInTypes[0];
821fe6060f1SDimitry Andric   InputTypes.assign(OutInTypes.begin() + 1, OutInTypes.end());
822fe6060f1SDimitry Andric 
823fe6060f1SDimitry Andric   // IntrinsicTypes is nonmasked version index. Need to update it
824fe6060f1SDimitry Andric   // if there is maskedoff operand (It is always in first operand).
825fe6060f1SDimitry Andric   IntrinsicTypes = NewIntrinsicTypes;
826fe6060f1SDimitry Andric   if (IsMask && HasMaskedOffOperand) {
827fe6060f1SDimitry Andric     for (auto &I : IntrinsicTypes) {
828fe6060f1SDimitry Andric       if (I >= 0)
829fe6060f1SDimitry Andric         I += NF;
830fe6060f1SDimitry Andric     }
831fe6060f1SDimitry Andric   }
832fe6060f1SDimitry Andric }
833fe6060f1SDimitry Andric 
834fe6060f1SDimitry Andric std::string RVVIntrinsic::getBuiltinTypeStr() const {
835fe6060f1SDimitry Andric   std::string S;
836fe6060f1SDimitry Andric   S += OutputType->getBuiltinStr();
837fe6060f1SDimitry Andric   for (const auto &T : InputTypes) {
838fe6060f1SDimitry Andric     S += T->getBuiltinStr();
839fe6060f1SDimitry Andric   }
840fe6060f1SDimitry Andric   return S;
841fe6060f1SDimitry Andric }
842fe6060f1SDimitry Andric 
843fe6060f1SDimitry Andric void RVVIntrinsic::emitCodeGenSwitchBody(raw_ostream &OS) const {
844fe6060f1SDimitry Andric   if (!getIRName().empty())
845fe6060f1SDimitry Andric     OS << "  ID = Intrinsic::riscv_" + getIRName() + ";\n";
846fe6060f1SDimitry Andric   if (NF >= 2)
847fe6060f1SDimitry Andric     OS << "  NF = " + utostr(getNF()) + ";\n";
848fe6060f1SDimitry Andric   if (hasManualCodegen()) {
849fe6060f1SDimitry Andric     OS << ManualCodegen;
850fe6060f1SDimitry Andric     OS << "break;\n";
851fe6060f1SDimitry Andric     return;
852fe6060f1SDimitry Andric   }
853fe6060f1SDimitry Andric 
854fe6060f1SDimitry Andric   if (isMask()) {
855fe6060f1SDimitry Andric     if (hasVL()) {
856fe6060f1SDimitry Andric       OS << "  std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end() - 1);\n";
857349cc55cSDimitry Andric       if (hasPolicy())
858349cc55cSDimitry Andric         OS << "  Ops.push_back(ConstantInt::get(Ops.back()->getType(),"
859349cc55cSDimitry Andric                                " TAIL_UNDISTURBED));\n";
860fe6060f1SDimitry Andric     } else {
861fe6060f1SDimitry Andric       OS << "  std::rotate(Ops.begin(), Ops.begin() + 1, Ops.end());\n";
862fe6060f1SDimitry Andric     }
863fe6060f1SDimitry Andric   }
864fe6060f1SDimitry Andric 
865fe6060f1SDimitry Andric   OS << "  IntrinsicTypes = {";
866fe6060f1SDimitry Andric   ListSeparator LS;
867fe6060f1SDimitry Andric   for (const auto &Idx : IntrinsicTypes) {
868fe6060f1SDimitry Andric     if (Idx == -1)
869fe6060f1SDimitry Andric       OS << LS << "ResultType";
870fe6060f1SDimitry Andric     else
871fe6060f1SDimitry Andric       OS << LS << "Ops[" << Idx << "]->getType()";
872fe6060f1SDimitry Andric   }
873fe6060f1SDimitry Andric 
874fe6060f1SDimitry Andric   // VL could be i64 or i32, need to encode it in IntrinsicTypes. VL is
875fe6060f1SDimitry Andric   // always last operand.
876fe6060f1SDimitry Andric   if (hasVL())
877fe6060f1SDimitry Andric     OS << ", Ops.back()->getType()";
878fe6060f1SDimitry Andric   OS << "};\n";
879fe6060f1SDimitry Andric   OS << "  break;\n";
880fe6060f1SDimitry Andric }
881fe6060f1SDimitry Andric 
882349cc55cSDimitry Andric void RVVIntrinsic::emitIntrinsicFuncDef(raw_ostream &OS) const {
883349cc55cSDimitry Andric   OS << "__attribute__((__clang_builtin_alias__(";
884349cc55cSDimitry Andric   OS << "__builtin_rvv_" << getBuiltinName() << ")))\n";
885349cc55cSDimitry Andric   OS << OutputType->getTypeStr() << " " << getName() << "(";
886349cc55cSDimitry Andric   // Emit function arguments
887fe6060f1SDimitry Andric   if (!InputTypes.empty()) {
888fe6060f1SDimitry Andric     ListSeparator LS;
889349cc55cSDimitry Andric     for (unsigned i = 0; i < InputTypes.size(); ++i)
890349cc55cSDimitry Andric       OS << LS << InputTypes[i]->getTypeStr();
891fe6060f1SDimitry Andric   }
892349cc55cSDimitry Andric   OS << ");\n";
893fe6060f1SDimitry Andric }
894fe6060f1SDimitry Andric 
895fe6060f1SDimitry Andric void RVVIntrinsic::emitMangledFuncDef(raw_ostream &OS) const {
896349cc55cSDimitry Andric   OS << "__attribute__((__clang_builtin_alias__(";
897349cc55cSDimitry Andric   OS << "__builtin_rvv_" << getBuiltinName() << ")))\n";
898fe6060f1SDimitry Andric   OS << OutputType->getTypeStr() << " " << getMangledName() << "(";
899fe6060f1SDimitry Andric   // Emit function arguments
900fe6060f1SDimitry Andric   if (!InputTypes.empty()) {
901fe6060f1SDimitry Andric     ListSeparator LS;
902fe6060f1SDimitry Andric     for (unsigned i = 0; i < InputTypes.size(); ++i)
903349cc55cSDimitry Andric       OS << LS << InputTypes[i]->getTypeStr();
904fe6060f1SDimitry Andric   }
905349cc55cSDimitry Andric   OS << ");\n";
906fe6060f1SDimitry Andric }
907fe6060f1SDimitry Andric 
908fe6060f1SDimitry Andric //===----------------------------------------------------------------------===//
909fe6060f1SDimitry Andric // RVVEmitter implementation
910fe6060f1SDimitry Andric //===----------------------------------------------------------------------===//
911fe6060f1SDimitry Andric void RVVEmitter::createHeader(raw_ostream &OS) {
912fe6060f1SDimitry Andric 
913fe6060f1SDimitry Andric   OS << "/*===---- riscv_vector.h - RISC-V V-extension RVVIntrinsics "
914fe6060f1SDimitry Andric         "-------------------===\n"
915fe6060f1SDimitry Andric         " *\n"
916fe6060f1SDimitry Andric         " *\n"
917fe6060f1SDimitry Andric         " * Part of the LLVM Project, under the Apache License v2.0 with LLVM "
918fe6060f1SDimitry Andric         "Exceptions.\n"
919fe6060f1SDimitry Andric         " * See https://llvm.org/LICENSE.txt for license information.\n"
920fe6060f1SDimitry Andric         " * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception\n"
921fe6060f1SDimitry Andric         " *\n"
922fe6060f1SDimitry Andric         " *===-----------------------------------------------------------------"
923fe6060f1SDimitry Andric         "------===\n"
924fe6060f1SDimitry Andric         " */\n\n";
925fe6060f1SDimitry Andric 
926fe6060f1SDimitry Andric   OS << "#ifndef __RISCV_VECTOR_H\n";
927fe6060f1SDimitry Andric   OS << "#define __RISCV_VECTOR_H\n\n";
928fe6060f1SDimitry Andric 
929fe6060f1SDimitry Andric   OS << "#include <stdint.h>\n";
930fe6060f1SDimitry Andric   OS << "#include <stddef.h>\n\n";
931fe6060f1SDimitry Andric 
932fe6060f1SDimitry Andric   OS << "#ifndef __riscv_vector\n";
933fe6060f1SDimitry Andric   OS << "#error \"Vector intrinsics require the vector extension.\"\n";
934fe6060f1SDimitry Andric   OS << "#endif\n\n";
935fe6060f1SDimitry Andric 
936fe6060f1SDimitry Andric   OS << "#ifdef __cplusplus\n";
937fe6060f1SDimitry Andric   OS << "extern \"C\" {\n";
938fe6060f1SDimitry Andric   OS << "#endif\n\n";
939fe6060f1SDimitry Andric 
940349cc55cSDimitry Andric   createRVVHeaders(OS);
941349cc55cSDimitry Andric 
942fe6060f1SDimitry Andric   std::vector<std::unique_ptr<RVVIntrinsic>> Defs;
943fe6060f1SDimitry Andric   createRVVIntrinsics(Defs);
944fe6060f1SDimitry Andric 
945fe6060f1SDimitry Andric   // Print header code
946fe6060f1SDimitry Andric   if (!HeaderCode.empty()) {
947fe6060f1SDimitry Andric     OS << HeaderCode;
948fe6060f1SDimitry Andric   }
949fe6060f1SDimitry Andric 
950fe6060f1SDimitry Andric   auto printType = [&](auto T) {
951fe6060f1SDimitry Andric     OS << "typedef " << T->getClangBuiltinStr() << " " << T->getTypeStr()
952fe6060f1SDimitry Andric        << ";\n";
953fe6060f1SDimitry Andric   };
954fe6060f1SDimitry Andric 
955fe6060f1SDimitry Andric   constexpr int Log2LMULs[] = {-3, -2, -1, 0, 1, 2, 3};
956fe6060f1SDimitry Andric   // Print RVV boolean types.
957fe6060f1SDimitry Andric   for (int Log2LMUL : Log2LMULs) {
958fe6060f1SDimitry Andric     auto T = computeType('c', Log2LMUL, "m");
959fe6060f1SDimitry Andric     if (T.hasValue())
960fe6060f1SDimitry Andric       printType(T.getValue());
961fe6060f1SDimitry Andric   }
962fe6060f1SDimitry Andric   // Print RVV int/float types.
963fe6060f1SDimitry Andric   for (char I : StringRef("csil")) {
964fe6060f1SDimitry Andric     for (int Log2LMUL : Log2LMULs) {
965fe6060f1SDimitry Andric       auto T = computeType(I, Log2LMUL, "v");
966fe6060f1SDimitry Andric       if (T.hasValue()) {
967fe6060f1SDimitry Andric         printType(T.getValue());
968fe6060f1SDimitry Andric         auto UT = computeType(I, Log2LMUL, "Uv");
969fe6060f1SDimitry Andric         printType(UT.getValue());
970fe6060f1SDimitry Andric       }
971fe6060f1SDimitry Andric     }
972fe6060f1SDimitry Andric   }
973fe6060f1SDimitry Andric   OS << "#if defined(__riscv_zfh)\n";
974fe6060f1SDimitry Andric   for (int Log2LMUL : Log2LMULs) {
975fe6060f1SDimitry Andric     auto T = computeType('x', Log2LMUL, "v");
976fe6060f1SDimitry Andric     if (T.hasValue())
977fe6060f1SDimitry Andric       printType(T.getValue());
978fe6060f1SDimitry Andric   }
979fe6060f1SDimitry Andric   OS << "#endif\n";
980fe6060f1SDimitry Andric 
981fe6060f1SDimitry Andric   OS << "#if defined(__riscv_f)\n";
982fe6060f1SDimitry Andric   for (int Log2LMUL : Log2LMULs) {
983fe6060f1SDimitry Andric     auto T = computeType('f', Log2LMUL, "v");
984fe6060f1SDimitry Andric     if (T.hasValue())
985fe6060f1SDimitry Andric       printType(T.getValue());
986fe6060f1SDimitry Andric   }
987fe6060f1SDimitry Andric   OS << "#endif\n";
988fe6060f1SDimitry Andric 
989fe6060f1SDimitry Andric   OS << "#if defined(__riscv_d)\n";
990fe6060f1SDimitry Andric   for (int Log2LMUL : Log2LMULs) {
991fe6060f1SDimitry Andric     auto T = computeType('d', Log2LMUL, "v");
992fe6060f1SDimitry Andric     if (T.hasValue())
993fe6060f1SDimitry Andric       printType(T.getValue());
994fe6060f1SDimitry Andric   }
995fe6060f1SDimitry Andric   OS << "#endif\n\n";
996fe6060f1SDimitry Andric 
997fe6060f1SDimitry Andric   // The same extension include in the same arch guard marco.
998349cc55cSDimitry Andric   llvm::stable_sort(Defs, [](const std::unique_ptr<RVVIntrinsic> &A,
999fe6060f1SDimitry Andric                              const std::unique_ptr<RVVIntrinsic> &B) {
1000*04eeddc0SDimitry Andric     return A->getRISCVPredefinedMacros() < B->getRISCVPredefinedMacros();
1001fe6060f1SDimitry Andric   });
1002fe6060f1SDimitry Andric 
1003349cc55cSDimitry Andric   OS << "#define __rvv_ai static __inline__\n";
1004349cc55cSDimitry Andric 
1005fe6060f1SDimitry Andric   // Print intrinsic functions with macro
1006fe6060f1SDimitry Andric   emitArchMacroAndBody(Defs, OS, [](raw_ostream &OS, const RVVIntrinsic &Inst) {
1007349cc55cSDimitry Andric     OS << "__rvv_ai ";
1008349cc55cSDimitry Andric     Inst.emitIntrinsicFuncDef(OS);
1009fe6060f1SDimitry Andric   });
1010fe6060f1SDimitry Andric 
1011349cc55cSDimitry Andric   OS << "#undef __rvv_ai\n\n";
1012349cc55cSDimitry Andric 
1013fe6060f1SDimitry Andric   OS << "#define __riscv_v_intrinsic_overloading 1\n";
1014fe6060f1SDimitry Andric 
1015fe6060f1SDimitry Andric   // Print Overloaded APIs
1016349cc55cSDimitry Andric   OS << "#define __rvv_aio static __inline__ "
1017349cc55cSDimitry Andric         "__attribute__((__overloadable__))\n";
1018fe6060f1SDimitry Andric 
1019fe6060f1SDimitry Andric   emitArchMacroAndBody(Defs, OS, [](raw_ostream &OS, const RVVIntrinsic &Inst) {
1020fe6060f1SDimitry Andric     if (!Inst.isMask() && !Inst.hasNoMaskedOverloaded())
1021fe6060f1SDimitry Andric       return;
1022349cc55cSDimitry Andric     OS << "__rvv_aio ";
1023fe6060f1SDimitry Andric     Inst.emitMangledFuncDef(OS);
1024fe6060f1SDimitry Andric   });
1025fe6060f1SDimitry Andric 
1026349cc55cSDimitry Andric   OS << "#undef __rvv_aio\n";
1027349cc55cSDimitry Andric 
1028fe6060f1SDimitry Andric   OS << "\n#ifdef __cplusplus\n";
1029fe6060f1SDimitry Andric   OS << "}\n";
1030349cc55cSDimitry Andric   OS << "#endif // __cplusplus\n";
1031fe6060f1SDimitry Andric   OS << "#endif // __RISCV_VECTOR_H\n";
1032fe6060f1SDimitry Andric }
1033fe6060f1SDimitry Andric 
1034fe6060f1SDimitry Andric void RVVEmitter::createBuiltins(raw_ostream &OS) {
1035fe6060f1SDimitry Andric   std::vector<std::unique_ptr<RVVIntrinsic>> Defs;
1036fe6060f1SDimitry Andric   createRVVIntrinsics(Defs);
1037fe6060f1SDimitry Andric 
1038349cc55cSDimitry Andric   // Map to keep track of which builtin names have already been emitted.
1039349cc55cSDimitry Andric   StringMap<RVVIntrinsic *> BuiltinMap;
1040349cc55cSDimitry Andric 
1041fe6060f1SDimitry Andric   OS << "#if defined(TARGET_BUILTIN) && !defined(RISCVV_BUILTIN)\n";
1042fe6060f1SDimitry Andric   OS << "#define RISCVV_BUILTIN(ID, TYPE, ATTRS) TARGET_BUILTIN(ID, TYPE, "
1043*04eeddc0SDimitry Andric         "ATTRS, \"zve32x|v\")\n";
1044fe6060f1SDimitry Andric   OS << "#endif\n";
1045fe6060f1SDimitry Andric   for (auto &Def : Defs) {
1046349cc55cSDimitry Andric     auto P =
1047349cc55cSDimitry Andric         BuiltinMap.insert(std::make_pair(Def->getBuiltinName(), Def.get()));
1048349cc55cSDimitry Andric     if (!P.second) {
1049349cc55cSDimitry Andric       // Verify that this would have produced the same builtin definition.
1050349cc55cSDimitry Andric       if (P.first->second->hasAutoDef() != Def->hasAutoDef()) {
1051349cc55cSDimitry Andric         PrintFatalError("Builtin with same name has different hasAutoDef");
1052349cc55cSDimitry Andric       } else if (!Def->hasAutoDef() && P.first->second->getBuiltinTypeStr() !=
1053349cc55cSDimitry Andric                                            Def->getBuiltinTypeStr()) {
1054349cc55cSDimitry Andric         PrintFatalError("Builtin with same name has different type string");
1055349cc55cSDimitry Andric       }
1056349cc55cSDimitry Andric       continue;
1057349cc55cSDimitry Andric     }
1058349cc55cSDimitry Andric 
1059349cc55cSDimitry Andric     OS << "RISCVV_BUILTIN(__builtin_rvv_" << Def->getBuiltinName() << ",\"";
1060349cc55cSDimitry Andric     if (!Def->hasAutoDef())
1061349cc55cSDimitry Andric       OS << Def->getBuiltinTypeStr();
1062349cc55cSDimitry Andric     OS << "\", \"n\")\n";
1063fe6060f1SDimitry Andric   }
1064fe6060f1SDimitry Andric   OS << "#undef RISCVV_BUILTIN\n";
1065fe6060f1SDimitry Andric }
1066fe6060f1SDimitry Andric 
1067fe6060f1SDimitry Andric void RVVEmitter::createCodeGen(raw_ostream &OS) {
1068fe6060f1SDimitry Andric   std::vector<std::unique_ptr<RVVIntrinsic>> Defs;
1069fe6060f1SDimitry Andric   createRVVIntrinsics(Defs);
1070fe6060f1SDimitry Andric   // IR name could be empty, use the stable sort preserves the relative order.
1071349cc55cSDimitry Andric   llvm::stable_sort(Defs, [](const std::unique_ptr<RVVIntrinsic> &A,
1072fe6060f1SDimitry Andric                              const std::unique_ptr<RVVIntrinsic> &B) {
1073fe6060f1SDimitry Andric     return A->getIRName() < B->getIRName();
1074fe6060f1SDimitry Andric   });
1075349cc55cSDimitry Andric 
1076349cc55cSDimitry Andric   // Map to keep track of which builtin names have already been emitted.
1077349cc55cSDimitry Andric   StringMap<RVVIntrinsic *> BuiltinMap;
1078349cc55cSDimitry Andric 
1079fe6060f1SDimitry Andric   // Print switch body when the ir name or ManualCodegen changes from previous
1080fe6060f1SDimitry Andric   // iteration.
1081fe6060f1SDimitry Andric   RVVIntrinsic *PrevDef = Defs.begin()->get();
1082fe6060f1SDimitry Andric   for (auto &Def : Defs) {
1083fe6060f1SDimitry Andric     StringRef CurIRName = Def->getIRName();
1084fe6060f1SDimitry Andric     if (CurIRName != PrevDef->getIRName() ||
1085fe6060f1SDimitry Andric         (Def->getManualCodegen() != PrevDef->getManualCodegen())) {
1086fe6060f1SDimitry Andric       PrevDef->emitCodeGenSwitchBody(OS);
1087fe6060f1SDimitry Andric     }
1088fe6060f1SDimitry Andric     PrevDef = Def.get();
1089349cc55cSDimitry Andric 
1090349cc55cSDimitry Andric     auto P =
1091349cc55cSDimitry Andric         BuiltinMap.insert(std::make_pair(Def->getBuiltinName(), Def.get()));
1092349cc55cSDimitry Andric     if (P.second) {
1093349cc55cSDimitry Andric       OS << "case RISCVVector::BI__builtin_rvv_" << Def->getBuiltinName()
1094349cc55cSDimitry Andric          << ":\n";
1095349cc55cSDimitry Andric       continue;
1096349cc55cSDimitry Andric     }
1097349cc55cSDimitry Andric 
1098349cc55cSDimitry Andric     if (P.first->second->getIRName() != Def->getIRName())
1099349cc55cSDimitry Andric       PrintFatalError("Builtin with same name has different IRName");
1100349cc55cSDimitry Andric     else if (P.first->second->getManualCodegen() != Def->getManualCodegen())
1101349cc55cSDimitry Andric       PrintFatalError("Builtin with same name has different ManualCodegen");
1102349cc55cSDimitry Andric     else if (P.first->second->getNF() != Def->getNF())
1103349cc55cSDimitry Andric       PrintFatalError("Builtin with same name has different NF");
1104349cc55cSDimitry Andric     else if (P.first->second->isMask() != Def->isMask())
1105349cc55cSDimitry Andric       PrintFatalError("Builtin with same name has different isMask");
1106349cc55cSDimitry Andric     else if (P.first->second->hasVL() != Def->hasVL())
1107349cc55cSDimitry Andric       PrintFatalError("Builtin with same name has different HasPolicy");
1108349cc55cSDimitry Andric     else if (P.first->second->hasPolicy() != Def->hasPolicy())
1109349cc55cSDimitry Andric       PrintFatalError("Builtin with same name has different HasPolicy");
1110349cc55cSDimitry Andric     else if (P.first->second->getIntrinsicTypes() != Def->getIntrinsicTypes())
1111349cc55cSDimitry Andric       PrintFatalError("Builtin with same name has different IntrinsicTypes");
1112fe6060f1SDimitry Andric   }
1113fe6060f1SDimitry Andric   Defs.back()->emitCodeGenSwitchBody(OS);
1114fe6060f1SDimitry Andric   OS << "\n";
1115fe6060f1SDimitry Andric }
1116fe6060f1SDimitry Andric 
1117fe6060f1SDimitry Andric void RVVEmitter::parsePrototypes(StringRef Prototypes,
1118fe6060f1SDimitry Andric                                  std::function<void(StringRef)> Handler) {
1119fe6060f1SDimitry Andric   const StringRef Primaries("evwqom0ztul");
1120fe6060f1SDimitry Andric   while (!Prototypes.empty()) {
1121fe6060f1SDimitry Andric     size_t Idx = 0;
1122fe6060f1SDimitry Andric     // Skip over complex prototype because it could contain primitive type
1123fe6060f1SDimitry Andric     // character.
1124fe6060f1SDimitry Andric     if (Prototypes[0] == '(')
1125fe6060f1SDimitry Andric       Idx = Prototypes.find_first_of(')');
1126fe6060f1SDimitry Andric     Idx = Prototypes.find_first_of(Primaries, Idx);
1127fe6060f1SDimitry Andric     assert(Idx != StringRef::npos);
1128fe6060f1SDimitry Andric     Handler(Prototypes.slice(0, Idx + 1));
1129fe6060f1SDimitry Andric     Prototypes = Prototypes.drop_front(Idx + 1);
1130fe6060f1SDimitry Andric   }
1131fe6060f1SDimitry Andric }
1132fe6060f1SDimitry Andric 
1133fe6060f1SDimitry Andric std::string RVVEmitter::getSuffixStr(char Type, int Log2LMUL,
1134fe6060f1SDimitry Andric                                      StringRef Prototypes) {
1135fe6060f1SDimitry Andric   SmallVector<std::string> SuffixStrs;
1136fe6060f1SDimitry Andric   parsePrototypes(Prototypes, [&](StringRef Proto) {
1137fe6060f1SDimitry Andric     auto T = computeType(Type, Log2LMUL, Proto);
1138fe6060f1SDimitry Andric     SuffixStrs.push_back(T.getValue()->getShortStr());
1139fe6060f1SDimitry Andric   });
1140fe6060f1SDimitry Andric   return join(SuffixStrs, "_");
1141fe6060f1SDimitry Andric }
1142fe6060f1SDimitry Andric 
1143fe6060f1SDimitry Andric void RVVEmitter::createRVVIntrinsics(
1144fe6060f1SDimitry Andric     std::vector<std::unique_ptr<RVVIntrinsic>> &Out) {
1145fe6060f1SDimitry Andric   std::vector<Record *> RV = Records.getAllDerivedDefinitions("RVVBuiltin");
1146fe6060f1SDimitry Andric   for (auto *R : RV) {
1147fe6060f1SDimitry Andric     StringRef Name = R->getValueAsString("Name");
1148fe6060f1SDimitry Andric     StringRef SuffixProto = R->getValueAsString("Suffix");
1149fe6060f1SDimitry Andric     StringRef MangledName = R->getValueAsString("MangledName");
1150fe6060f1SDimitry Andric     StringRef MangledSuffixProto = R->getValueAsString("MangledSuffix");
1151fe6060f1SDimitry Andric     StringRef Prototypes = R->getValueAsString("Prototype");
1152fe6060f1SDimitry Andric     StringRef TypeRange = R->getValueAsString("TypeRange");
1153fe6060f1SDimitry Andric     bool HasMask = R->getValueAsBit("HasMask");
1154fe6060f1SDimitry Andric     bool HasMaskedOffOperand = R->getValueAsBit("HasMaskedOffOperand");
1155fe6060f1SDimitry Andric     bool HasVL = R->getValueAsBit("HasVL");
1156349cc55cSDimitry Andric     bool HasPolicy = R->getValueAsBit("HasPolicy");
1157fe6060f1SDimitry Andric     bool HasNoMaskedOverloaded = R->getValueAsBit("HasNoMaskedOverloaded");
1158fe6060f1SDimitry Andric     std::vector<int64_t> Log2LMULList = R->getValueAsListOfInts("Log2LMUL");
1159fe6060f1SDimitry Andric     StringRef ManualCodegen = R->getValueAsString("ManualCodegen");
1160fe6060f1SDimitry Andric     StringRef ManualCodegenMask = R->getValueAsString("ManualCodegenMask");
1161fe6060f1SDimitry Andric     std::vector<int64_t> IntrinsicTypes =
1162fe6060f1SDimitry Andric         R->getValueAsListOfInts("IntrinsicTypes");
1163*04eeddc0SDimitry Andric     std::vector<StringRef> RequiredFeatures =
1164*04eeddc0SDimitry Andric         R->getValueAsListOfStrings("RequiredFeatures");
1165fe6060f1SDimitry Andric     StringRef IRName = R->getValueAsString("IRName");
1166fe6060f1SDimitry Andric     StringRef IRNameMask = R->getValueAsString("IRNameMask");
1167fe6060f1SDimitry Andric     unsigned NF = R->getValueAsInt("NF");
1168fe6060f1SDimitry Andric 
1169fe6060f1SDimitry Andric     StringRef HeaderCodeStr = R->getValueAsString("HeaderCode");
1170fe6060f1SDimitry Andric     bool HasAutoDef = HeaderCodeStr.empty();
1171fe6060f1SDimitry Andric     if (!HeaderCodeStr.empty()) {
1172fe6060f1SDimitry Andric       HeaderCode += HeaderCodeStr.str();
1173fe6060f1SDimitry Andric     }
1174fe6060f1SDimitry Andric     // Parse prototype and create a list of primitive type with transformers
1175fe6060f1SDimitry Andric     // (operand) in ProtoSeq. ProtoSeq[0] is output operand.
1176fe6060f1SDimitry Andric     SmallVector<std::string> ProtoSeq;
1177fe6060f1SDimitry Andric     parsePrototypes(Prototypes, [&ProtoSeq](StringRef Proto) {
1178fe6060f1SDimitry Andric       ProtoSeq.push_back(Proto.str());
1179fe6060f1SDimitry Andric     });
1180fe6060f1SDimitry Andric 
1181fe6060f1SDimitry Andric     // Compute Builtin types
1182fe6060f1SDimitry Andric     SmallVector<std::string> ProtoMaskSeq = ProtoSeq;
1183fe6060f1SDimitry Andric     if (HasMask) {
1184fe6060f1SDimitry Andric       // If HasMaskedOffOperand, insert result type as first input operand.
1185fe6060f1SDimitry Andric       if (HasMaskedOffOperand) {
1186fe6060f1SDimitry Andric         if (NF == 1) {
1187fe6060f1SDimitry Andric           ProtoMaskSeq.insert(ProtoMaskSeq.begin() + 1, ProtoSeq[0]);
1188fe6060f1SDimitry Andric         } else {
1189fe6060f1SDimitry Andric           // Convert
1190fe6060f1SDimitry Andric           // (void, op0 address, op1 address, ...)
1191fe6060f1SDimitry Andric           // to
1192fe6060f1SDimitry Andric           // (void, op0 address, op1 address, ..., maskedoff0, maskedoff1, ...)
1193fe6060f1SDimitry Andric           for (unsigned I = 0; I < NF; ++I)
1194fe6060f1SDimitry Andric             ProtoMaskSeq.insert(
1195fe6060f1SDimitry Andric                 ProtoMaskSeq.begin() + NF + 1,
1196fe6060f1SDimitry Andric                 ProtoSeq[1].substr(1)); // Use substr(1) to skip '*'
1197fe6060f1SDimitry Andric         }
1198fe6060f1SDimitry Andric       }
1199fe6060f1SDimitry Andric       if (HasMaskedOffOperand && NF > 1) {
1200fe6060f1SDimitry Andric         // Convert
1201fe6060f1SDimitry Andric         // (void, op0 address, op1 address, ..., maskedoff0, maskedoff1, ...)
1202fe6060f1SDimitry Andric         // to
1203fe6060f1SDimitry Andric         // (void, op0 address, op1 address, ..., mask, maskedoff0, maskedoff1,
1204fe6060f1SDimitry Andric         // ...)
1205fe6060f1SDimitry Andric         ProtoMaskSeq.insert(ProtoMaskSeq.begin() + NF + 1, "m");
1206fe6060f1SDimitry Andric       } else {
1207fe6060f1SDimitry Andric         // If HasMask, insert 'm' as first input operand.
1208fe6060f1SDimitry Andric         ProtoMaskSeq.insert(ProtoMaskSeq.begin() + 1, "m");
1209fe6060f1SDimitry Andric       }
1210fe6060f1SDimitry Andric     }
1211fe6060f1SDimitry Andric     // If HasVL, append 'z' to last operand
1212fe6060f1SDimitry Andric     if (HasVL) {
1213fe6060f1SDimitry Andric       ProtoSeq.push_back("z");
1214fe6060f1SDimitry Andric       ProtoMaskSeq.push_back("z");
1215fe6060f1SDimitry Andric     }
1216fe6060f1SDimitry Andric 
1217fe6060f1SDimitry Andric     // Create Intrinsics for each type and LMUL.
1218fe6060f1SDimitry Andric     for (char I : TypeRange) {
1219fe6060f1SDimitry Andric       for (int Log2LMUL : Log2LMULList) {
1220fe6060f1SDimitry Andric         Optional<RVVTypes> Types = computeTypes(I, Log2LMUL, NF, ProtoSeq);
1221fe6060f1SDimitry Andric         // Ignored to create new intrinsic if there are any illegal types.
1222fe6060f1SDimitry Andric         if (!Types.hasValue())
1223fe6060f1SDimitry Andric           continue;
1224fe6060f1SDimitry Andric 
1225fe6060f1SDimitry Andric         auto SuffixStr = getSuffixStr(I, Log2LMUL, SuffixProto);
1226fe6060f1SDimitry Andric         auto MangledSuffixStr = getSuffixStr(I, Log2LMUL, MangledSuffixProto);
1227fe6060f1SDimitry Andric         // Create a non-mask intrinsic
1228fe6060f1SDimitry Andric         Out.push_back(std::make_unique<RVVIntrinsic>(
1229fe6060f1SDimitry Andric             Name, SuffixStr, MangledName, MangledSuffixStr, IRName,
1230349cc55cSDimitry Andric             /*IsMask=*/false, /*HasMaskedOffOperand=*/false, HasVL, HasPolicy,
1231349cc55cSDimitry Andric             HasNoMaskedOverloaded, HasAutoDef, ManualCodegen, Types.getValue(),
1232*04eeddc0SDimitry Andric             IntrinsicTypes, RequiredFeatures, NF));
1233fe6060f1SDimitry Andric         if (HasMask) {
1234fe6060f1SDimitry Andric           // Create a mask intrinsic
1235fe6060f1SDimitry Andric           Optional<RVVTypes> MaskTypes =
1236fe6060f1SDimitry Andric               computeTypes(I, Log2LMUL, NF, ProtoMaskSeq);
1237fe6060f1SDimitry Andric           Out.push_back(std::make_unique<RVVIntrinsic>(
1238fe6060f1SDimitry Andric               Name, SuffixStr, MangledName, MangledSuffixStr, IRNameMask,
1239349cc55cSDimitry Andric               /*IsMask=*/true, HasMaskedOffOperand, HasVL, HasPolicy,
1240fe6060f1SDimitry Andric               HasNoMaskedOverloaded, HasAutoDef, ManualCodegenMask,
1241*04eeddc0SDimitry Andric               MaskTypes.getValue(), IntrinsicTypes, RequiredFeatures, NF));
1242fe6060f1SDimitry Andric         }
1243fe6060f1SDimitry Andric       } // end for Log2LMULList
1244fe6060f1SDimitry Andric     }   // end for TypeRange
1245fe6060f1SDimitry Andric   }
1246fe6060f1SDimitry Andric }
1247fe6060f1SDimitry Andric 
1248349cc55cSDimitry Andric void RVVEmitter::createRVVHeaders(raw_ostream &OS) {
1249349cc55cSDimitry Andric   std::vector<Record *> RVVHeaders =
1250349cc55cSDimitry Andric       Records.getAllDerivedDefinitions("RVVHeader");
1251349cc55cSDimitry Andric   for (auto *R : RVVHeaders) {
1252349cc55cSDimitry Andric     StringRef HeaderCodeStr = R->getValueAsString("HeaderCode");
1253349cc55cSDimitry Andric     OS << HeaderCodeStr.str();
1254349cc55cSDimitry Andric   }
1255349cc55cSDimitry Andric }
1256349cc55cSDimitry Andric 
1257fe6060f1SDimitry Andric Optional<RVVTypes>
1258fe6060f1SDimitry Andric RVVEmitter::computeTypes(BasicType BT, int Log2LMUL, unsigned NF,
1259fe6060f1SDimitry Andric                          ArrayRef<std::string> PrototypeSeq) {
1260fe6060f1SDimitry Andric   // LMUL x NF must be less than or equal to 8.
1261fe6060f1SDimitry Andric   if ((Log2LMUL >= 1) && (1 << Log2LMUL) * NF > 8)
1262fe6060f1SDimitry Andric     return llvm::None;
1263fe6060f1SDimitry Andric 
1264fe6060f1SDimitry Andric   RVVTypes Types;
1265fe6060f1SDimitry Andric   for (const std::string &Proto : PrototypeSeq) {
1266fe6060f1SDimitry Andric     auto T = computeType(BT, Log2LMUL, Proto);
1267fe6060f1SDimitry Andric     if (!T.hasValue())
1268fe6060f1SDimitry Andric       return llvm::None;
1269fe6060f1SDimitry Andric     // Record legal type index
1270fe6060f1SDimitry Andric     Types.push_back(T.getValue());
1271fe6060f1SDimitry Andric   }
1272fe6060f1SDimitry Andric   return Types;
1273fe6060f1SDimitry Andric }
1274fe6060f1SDimitry Andric 
1275fe6060f1SDimitry Andric Optional<RVVTypePtr> RVVEmitter::computeType(BasicType BT, int Log2LMUL,
1276fe6060f1SDimitry Andric                                              StringRef Proto) {
1277fe6060f1SDimitry Andric   std::string Idx = Twine(Twine(BT) + Twine(Log2LMUL) + Proto).str();
1278fe6060f1SDimitry Andric   // Search first
1279fe6060f1SDimitry Andric   auto It = LegalTypes.find(Idx);
1280fe6060f1SDimitry Andric   if (It != LegalTypes.end())
1281fe6060f1SDimitry Andric     return &(It->second);
1282fe6060f1SDimitry Andric   if (IllegalTypes.count(Idx))
1283fe6060f1SDimitry Andric     return llvm::None;
1284fe6060f1SDimitry Andric   // Compute type and record the result.
1285fe6060f1SDimitry Andric   RVVType T(BT, Log2LMUL, Proto);
1286fe6060f1SDimitry Andric   if (T.isValid()) {
1287fe6060f1SDimitry Andric     // Record legal type index and value.
1288fe6060f1SDimitry Andric     LegalTypes.insert({Idx, T});
1289fe6060f1SDimitry Andric     return &(LegalTypes[Idx]);
1290fe6060f1SDimitry Andric   }
1291fe6060f1SDimitry Andric   // Record illegal type index.
1292fe6060f1SDimitry Andric   IllegalTypes.insert(Idx);
1293fe6060f1SDimitry Andric   return llvm::None;
1294fe6060f1SDimitry Andric }
1295fe6060f1SDimitry Andric 
1296fe6060f1SDimitry Andric void RVVEmitter::emitArchMacroAndBody(
1297fe6060f1SDimitry Andric     std::vector<std::unique_ptr<RVVIntrinsic>> &Defs, raw_ostream &OS,
1298fe6060f1SDimitry Andric     std::function<void(raw_ostream &, const RVVIntrinsic &)> PrintBody) {
1299*04eeddc0SDimitry Andric   RISCVPredefinedMacroT PrevMacros =
1300*04eeddc0SDimitry Andric       (*Defs.begin())->getRISCVPredefinedMacros();
1301*04eeddc0SDimitry Andric   bool NeedEndif = emitMacroRestrictionStr(PrevMacros, OS);
1302fe6060f1SDimitry Andric   for (auto &Def : Defs) {
1303*04eeddc0SDimitry Andric     RISCVPredefinedMacroT CurMacros = Def->getRISCVPredefinedMacros();
1304*04eeddc0SDimitry Andric     if (CurMacros != PrevMacros) {
1305fe6060f1SDimitry Andric       if (NeedEndif)
1306fe6060f1SDimitry Andric         OS << "#endif\n\n";
1307*04eeddc0SDimitry Andric       NeedEndif = emitMacroRestrictionStr(CurMacros, OS);
1308*04eeddc0SDimitry Andric       PrevMacros = CurMacros;
1309fe6060f1SDimitry Andric     }
1310fe6060f1SDimitry Andric     if (Def->hasAutoDef())
1311fe6060f1SDimitry Andric       PrintBody(OS, *Def);
1312fe6060f1SDimitry Andric   }
1313fe6060f1SDimitry Andric   if (NeedEndif)
1314fe6060f1SDimitry Andric     OS << "#endif\n\n";
1315fe6060f1SDimitry Andric }
1316fe6060f1SDimitry Andric 
1317*04eeddc0SDimitry Andric bool RVVEmitter::emitMacroRestrictionStr(RISCVPredefinedMacroT PredefinedMacros,
1318*04eeddc0SDimitry Andric                                          raw_ostream &OS) {
1319*04eeddc0SDimitry Andric   if (PredefinedMacros == RISCVPredefinedMacro::Basic)
1320fe6060f1SDimitry Andric     return false;
1321fe6060f1SDimitry Andric   OS << "#if ";
1322fe6060f1SDimitry Andric   ListSeparator LS(" && ");
1323*04eeddc0SDimitry Andric   if (PredefinedMacros & RISCVPredefinedMacro::V)
1324*04eeddc0SDimitry Andric     OS << LS << "defined(__riscv_v)";
1325*04eeddc0SDimitry Andric   if (PredefinedMacros & RISCVPredefinedMacro::Zfh)
1326fe6060f1SDimitry Andric     OS << LS << "defined(__riscv_zfh)";
1327*04eeddc0SDimitry Andric   if (PredefinedMacros & RISCVPredefinedMacro::RV64)
1328*04eeddc0SDimitry Andric     OS << LS << "(__riscv_xlen == 64)";
1329*04eeddc0SDimitry Andric   if (PredefinedMacros & RISCVPredefinedMacro::VectorMaxELen64)
1330*04eeddc0SDimitry Andric     OS << LS << "(__riscv_v_elen >= 64)";
1331*04eeddc0SDimitry Andric   if (PredefinedMacros & RISCVPredefinedMacro::VectorMaxELenFp32)
1332*04eeddc0SDimitry Andric     OS << LS << "(__riscv_v_elen_fp >= 32)";
1333*04eeddc0SDimitry Andric   if (PredefinedMacros & RISCVPredefinedMacro::VectorMaxELenFp64)
1334*04eeddc0SDimitry Andric     OS << LS << "(__riscv_v_elen_fp >= 64)";
1335fe6060f1SDimitry Andric   OS << "\n";
1336fe6060f1SDimitry Andric   return true;
1337fe6060f1SDimitry Andric }
1338fe6060f1SDimitry Andric 
1339fe6060f1SDimitry Andric namespace clang {
1340fe6060f1SDimitry Andric void EmitRVVHeader(RecordKeeper &Records, raw_ostream &OS) {
1341fe6060f1SDimitry Andric   RVVEmitter(Records).createHeader(OS);
1342fe6060f1SDimitry Andric }
1343fe6060f1SDimitry Andric 
1344fe6060f1SDimitry Andric void EmitRVVBuiltins(RecordKeeper &Records, raw_ostream &OS) {
1345fe6060f1SDimitry Andric   RVVEmitter(Records).createBuiltins(OS);
1346fe6060f1SDimitry Andric }
1347fe6060f1SDimitry Andric 
1348fe6060f1SDimitry Andric void EmitRVVBuiltinCG(RecordKeeper &Records, raw_ostream &OS) {
1349fe6060f1SDimitry Andric   RVVEmitter(Records).createCodeGen(OS);
1350fe6060f1SDimitry Andric }
1351fe6060f1SDimitry Andric 
1352fe6060f1SDimitry Andric } // End namespace clang
1353