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