1480093f4SDimitry Andric //===- MveEmitter.cpp - Generate arm_mve.h for use with clang -*- C++ -*-=====//
2480093f4SDimitry Andric //
3480093f4SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4480093f4SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5480093f4SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6480093f4SDimitry Andric //
7480093f4SDimitry Andric //===----------------------------------------------------------------------===//
8480093f4SDimitry Andric //
9480093f4SDimitry Andric // This set of linked tablegen backends is responsible for emitting the bits
10480093f4SDimitry Andric // and pieces that implement <arm_mve.h>, which is defined by the ACLE standard
11480093f4SDimitry Andric // and provides a set of types and functions for (more or less) direct access
12480093f4SDimitry Andric // to the MVE instruction set, including the scalar shifts as well as the
13480093f4SDimitry Andric // vector instructions.
14480093f4SDimitry Andric //
15480093f4SDimitry Andric // MVE's standard intrinsic functions are unusual in that they have a system of
16480093f4SDimitry Andric // polymorphism. For example, the function vaddq() can behave like vaddq_u16(),
17480093f4SDimitry Andric // vaddq_f32(), vaddq_s8(), etc., depending on the types of the vector
18480093f4SDimitry Andric // arguments you give it.
19480093f4SDimitry Andric //
20480093f4SDimitry Andric // This constrains the implementation strategies. The usual approach to making
21480093f4SDimitry Andric // the user-facing functions polymorphic would be to either use
22480093f4SDimitry Andric // __attribute__((overloadable)) to make a set of vaddq() functions that are
23480093f4SDimitry Andric // all inline wrappers on the underlying clang builtins, or to define a single
24480093f4SDimitry Andric // vaddq() macro which expands to an instance of _Generic.
25480093f4SDimitry Andric //
26480093f4SDimitry Andric // The inline-wrappers approach would work fine for most intrinsics, except for
27480093f4SDimitry Andric // the ones that take an argument required to be a compile-time constant,
28480093f4SDimitry Andric // because if you wrap an inline function around a call to a builtin, the
29480093f4SDimitry Andric // constant nature of the argument is not passed through.
30480093f4SDimitry Andric //
31480093f4SDimitry Andric // The _Generic approach can be made to work with enough effort, but it takes a
32480093f4SDimitry Andric // lot of machinery, because of the design feature of _Generic that even the
33480093f4SDimitry Andric // untaken branches are required to pass all front-end validity checks such as
34480093f4SDimitry Andric // type-correctness. You can work around that by nesting further _Generics all
35480093f4SDimitry Andric // over the place to coerce things to the right type in untaken branches, but
36480093f4SDimitry Andric // what you get out is complicated, hard to guarantee its correctness, and
37480093f4SDimitry Andric // worst of all, gives _completely unreadable_ error messages if the user gets
38480093f4SDimitry Andric // the types wrong for an intrinsic call.
39480093f4SDimitry Andric //
40480093f4SDimitry Andric // Therefore, my strategy is to introduce a new __attribute__ that allows a
41480093f4SDimitry Andric // function to be mapped to a clang builtin even though it doesn't have the
42480093f4SDimitry Andric // same name, and then declare all the user-facing MVE function names with that
43480093f4SDimitry Andric // attribute, mapping each one directly to the clang builtin. And the
44480093f4SDimitry Andric // polymorphic ones have __attribute__((overloadable)) as well. So once the
45480093f4SDimitry Andric // compiler has resolved the overload, it knows the internal builtin ID of the
46480093f4SDimitry Andric // selected function, and can check the immediate arguments against that; and
47480093f4SDimitry Andric // if the user gets the types wrong in a call to a polymorphic intrinsic, they
48480093f4SDimitry Andric // get a completely clear error message showing all the declarations of that
49480093f4SDimitry Andric // function in the header file and explaining why each one doesn't fit their
50480093f4SDimitry Andric // call.
51480093f4SDimitry Andric //
52480093f4SDimitry Andric // The downside of this is that if every clang builtin has to correspond
53480093f4SDimitry Andric // exactly to a user-facing ACLE intrinsic, then you can't save work in the
54480093f4SDimitry Andric // frontend by doing it in the header file: CGBuiltin.cpp has to do the entire
55480093f4SDimitry Andric // job of converting an ACLE intrinsic call into LLVM IR. So the Tablegen
56480093f4SDimitry Andric // description for an MVE intrinsic has to contain a full description of the
57480093f4SDimitry Andric // sequence of IRBuilder calls that clang will need to make.
58480093f4SDimitry Andric //
59480093f4SDimitry Andric //===----------------------------------------------------------------------===//
60480093f4SDimitry Andric 
61480093f4SDimitry Andric #include "llvm/ADT/APInt.h"
62480093f4SDimitry Andric #include "llvm/ADT/StringRef.h"
635ffd83dbSDimitry Andric #include "llvm/ADT/StringSwitch.h"
64480093f4SDimitry Andric #include "llvm/Support/Casting.h"
65480093f4SDimitry Andric #include "llvm/Support/raw_ostream.h"
66480093f4SDimitry Andric #include "llvm/TableGen/Error.h"
67480093f4SDimitry Andric #include "llvm/TableGen/Record.h"
685ffd83dbSDimitry Andric #include "llvm/TableGen/StringToOffsetTable.h"
69480093f4SDimitry Andric #include <cassert>
70480093f4SDimitry Andric #include <cstddef>
71480093f4SDimitry Andric #include <cstdint>
72480093f4SDimitry Andric #include <list>
73480093f4SDimitry Andric #include <map>
74480093f4SDimitry Andric #include <memory>
75480093f4SDimitry Andric #include <set>
76480093f4SDimitry Andric #include <string>
77480093f4SDimitry Andric #include <vector>
78480093f4SDimitry Andric 
79480093f4SDimitry Andric using namespace llvm;
80480093f4SDimitry Andric 
81480093f4SDimitry Andric namespace {
82480093f4SDimitry Andric 
835ffd83dbSDimitry Andric class EmitterBase;
84480093f4SDimitry Andric class Result;
85480093f4SDimitry Andric 
86480093f4SDimitry Andric // -----------------------------------------------------------------------------
87480093f4SDimitry Andric // A system of classes to represent all the types we'll need to deal with in
88480093f4SDimitry Andric // the prototypes of intrinsics.
89480093f4SDimitry Andric //
90480093f4SDimitry Andric // Query methods include finding out the C name of a type; the "LLVM name" in
91480093f4SDimitry Andric // the sense of a C++ code snippet that can be used in the codegen function;
92480093f4SDimitry Andric // the suffix that represents the type in the ACLE intrinsic naming scheme
93480093f4SDimitry Andric // (e.g. 's32' represents int32_t in intrinsics such as vaddq_s32); whether the
94480093f4SDimitry Andric // type is floating-point related (hence should be under #ifdef in the MVE
95480093f4SDimitry Andric // header so that it isn't included in integer-only MVE mode); and the type's
96480093f4SDimitry Andric // size in bits. Not all subtypes support all these queries.
97480093f4SDimitry Andric 
98480093f4SDimitry Andric class Type {
99480093f4SDimitry Andric public:
100480093f4SDimitry Andric   enum class TypeKind {
101480093f4SDimitry Andric     // Void appears as a return type (for store intrinsics, which are pure
102480093f4SDimitry Andric     // side-effect). It's also used as the parameter type in the Tablegen
103480093f4SDimitry Andric     // when an intrinsic doesn't need to come in various suffixed forms like
104480093f4SDimitry Andric     // vfooq_s8,vfooq_u16,vfooq_f32.
105480093f4SDimitry Andric     Void,
106480093f4SDimitry Andric 
107480093f4SDimitry Andric     // Scalar is used for ordinary int and float types of all sizes.
108480093f4SDimitry Andric     Scalar,
109480093f4SDimitry Andric 
110480093f4SDimitry Andric     // Vector is used for anything that occupies exactly one MVE vector
111480093f4SDimitry Andric     // register, i.e. {uint,int,float}NxM_t.
112480093f4SDimitry Andric     Vector,
113480093f4SDimitry Andric 
114480093f4SDimitry Andric     // MultiVector is used for the {uint,int,float}NxMxK_t types used by the
115480093f4SDimitry Andric     // interleaving load/store intrinsics v{ld,st}{2,4}q.
116480093f4SDimitry Andric     MultiVector,
117480093f4SDimitry Andric 
118480093f4SDimitry Andric     // Predicate is used by all the predicated intrinsics. Its C
119480093f4SDimitry Andric     // representation is mve_pred16_t (which is just an alias for uint16_t).
120480093f4SDimitry Andric     // But we give more detail here, by indicating that a given predicate
121480093f4SDimitry Andric     // instruction is logically regarded as a vector of i1 containing the
122480093f4SDimitry Andric     // same number of lanes as the input vector type. So our Predicate type
123480093f4SDimitry Andric     // comes with a lane count, which we use to decide which kind of <n x i1>
124480093f4SDimitry Andric     // we'll invoke the pred_i2v IR intrinsic to translate it into.
125480093f4SDimitry Andric     Predicate,
126480093f4SDimitry Andric 
127480093f4SDimitry Andric     // Pointer is used for pointer types (obviously), and comes with a flag
128480093f4SDimitry Andric     // indicating whether it's a pointer to a const or mutable instance of
129480093f4SDimitry Andric     // the pointee type.
130480093f4SDimitry Andric     Pointer,
131480093f4SDimitry Andric   };
132480093f4SDimitry Andric 
133480093f4SDimitry Andric private:
134480093f4SDimitry Andric   const TypeKind TKind;
135480093f4SDimitry Andric 
136480093f4SDimitry Andric protected:
Type(TypeKind K)137480093f4SDimitry Andric   Type(TypeKind K) : TKind(K) {}
138480093f4SDimitry Andric 
139480093f4SDimitry Andric public:
typeKind() const140480093f4SDimitry Andric   TypeKind typeKind() const { return TKind; }
141480093f4SDimitry Andric   virtual ~Type() = default;
142480093f4SDimitry Andric   virtual bool requiresFloat() const = 0;
1435ffd83dbSDimitry Andric   virtual bool requiresMVE() const = 0;
144480093f4SDimitry Andric   virtual unsigned sizeInBits() const = 0;
145480093f4SDimitry Andric   virtual std::string cName() const = 0;
llvmName() const146480093f4SDimitry Andric   virtual std::string llvmName() const {
147480093f4SDimitry Andric     PrintFatalError("no LLVM type name available for type " + cName());
148480093f4SDimitry Andric   }
acleSuffix(std::string) const149480093f4SDimitry Andric   virtual std::string acleSuffix(std::string) const {
150480093f4SDimitry Andric     PrintFatalError("no ACLE suffix available for this type");
151480093f4SDimitry Andric   }
152480093f4SDimitry Andric };
153480093f4SDimitry Andric 
154480093f4SDimitry Andric enum class ScalarTypeKind { SignedInt, UnsignedInt, Float };
toLetter(ScalarTypeKind kind)155480093f4SDimitry Andric inline std::string toLetter(ScalarTypeKind kind) {
156480093f4SDimitry Andric   switch (kind) {
157480093f4SDimitry Andric   case ScalarTypeKind::SignedInt:
158480093f4SDimitry Andric     return "s";
159480093f4SDimitry Andric   case ScalarTypeKind::UnsignedInt:
160480093f4SDimitry Andric     return "u";
161480093f4SDimitry Andric   case ScalarTypeKind::Float:
162480093f4SDimitry Andric     return "f";
163480093f4SDimitry Andric   }
164480093f4SDimitry Andric   llvm_unreachable("Unhandled ScalarTypeKind enum");
165480093f4SDimitry Andric }
toCPrefix(ScalarTypeKind kind)166480093f4SDimitry Andric inline std::string toCPrefix(ScalarTypeKind kind) {
167480093f4SDimitry Andric   switch (kind) {
168480093f4SDimitry Andric   case ScalarTypeKind::SignedInt:
169480093f4SDimitry Andric     return "int";
170480093f4SDimitry Andric   case ScalarTypeKind::UnsignedInt:
171480093f4SDimitry Andric     return "uint";
172480093f4SDimitry Andric   case ScalarTypeKind::Float:
173480093f4SDimitry Andric     return "float";
174480093f4SDimitry Andric   }
175480093f4SDimitry Andric   llvm_unreachable("Unhandled ScalarTypeKind enum");
176480093f4SDimitry Andric }
177480093f4SDimitry Andric 
178480093f4SDimitry Andric class VoidType : public Type {
179480093f4SDimitry Andric public:
VoidType()180480093f4SDimitry Andric   VoidType() : Type(TypeKind::Void) {}
sizeInBits() const181480093f4SDimitry Andric   unsigned sizeInBits() const override { return 0; }
requiresFloat() const182480093f4SDimitry Andric   bool requiresFloat() const override { return false; }
requiresMVE() const1835ffd83dbSDimitry Andric   bool requiresMVE() const override { return false; }
cName() const184480093f4SDimitry Andric   std::string cName() const override { return "void"; }
185480093f4SDimitry Andric 
classof(const Type * T)186480093f4SDimitry Andric   static bool classof(const Type *T) { return T->typeKind() == TypeKind::Void; }
acleSuffix(std::string) const187480093f4SDimitry Andric   std::string acleSuffix(std::string) const override { return ""; }
188480093f4SDimitry Andric };
189480093f4SDimitry Andric 
190480093f4SDimitry Andric class PointerType : public Type {
191480093f4SDimitry Andric   const Type *Pointee;
192480093f4SDimitry Andric   bool Const;
193480093f4SDimitry Andric 
194480093f4SDimitry Andric public:
PointerType(const Type * Pointee,bool Const)195480093f4SDimitry Andric   PointerType(const Type *Pointee, bool Const)
196480093f4SDimitry Andric       : Type(TypeKind::Pointer), Pointee(Pointee), Const(Const) {}
sizeInBits() const197480093f4SDimitry Andric   unsigned sizeInBits() const override { return 32; }
requiresFloat() const198480093f4SDimitry Andric   bool requiresFloat() const override { return Pointee->requiresFloat(); }
requiresMVE() const1995ffd83dbSDimitry Andric   bool requiresMVE() const override { return Pointee->requiresMVE(); }
cName() const200480093f4SDimitry Andric   std::string cName() const override {
201480093f4SDimitry Andric     std::string Name = Pointee->cName();
202480093f4SDimitry Andric 
203480093f4SDimitry Andric     // The syntax for a pointer in C is different when the pointee is
204480093f4SDimitry Andric     // itself a pointer. The MVE intrinsics don't contain any double
205480093f4SDimitry Andric     // pointers, so we don't need to worry about that wrinkle.
206480093f4SDimitry Andric     assert(!isa<PointerType>(Pointee) && "Pointer to pointer not supported");
207480093f4SDimitry Andric 
208480093f4SDimitry Andric     if (Const)
209480093f4SDimitry Andric       Name = "const " + Name;
210480093f4SDimitry Andric     return Name + " *";
211480093f4SDimitry Andric   }
llvmName() const212480093f4SDimitry Andric   std::string llvmName() const override {
213480093f4SDimitry Andric     return "llvm::PointerType::getUnqual(" + Pointee->llvmName() + ")";
214480093f4SDimitry Andric   }
getPointeeType() const21581ad6265SDimitry Andric   const Type *getPointeeType() const { return Pointee; }
216480093f4SDimitry Andric 
classof(const Type * T)217480093f4SDimitry Andric   static bool classof(const Type *T) {
218480093f4SDimitry Andric     return T->typeKind() == TypeKind::Pointer;
219480093f4SDimitry Andric   }
220480093f4SDimitry Andric };
221480093f4SDimitry Andric 
222480093f4SDimitry Andric // Base class for all the types that have a name of the form
223480093f4SDimitry Andric // [prefix][numbers]_t, like int32_t, uint16x8_t, float32x4x2_t.
224480093f4SDimitry Andric //
225480093f4SDimitry Andric // For this sub-hierarchy we invent a cNameBase() method which returns the
226480093f4SDimitry Andric // whole name except for the trailing "_t", so that Vector and MultiVector can
227480093f4SDimitry Andric // append an extra "x2" or whatever to their element type's cNameBase(). Then
228480093f4SDimitry Andric // the main cName() query method puts "_t" on the end for the final type name.
229480093f4SDimitry Andric 
230480093f4SDimitry Andric class CRegularNamedType : public Type {
231480093f4SDimitry Andric   using Type::Type;
232480093f4SDimitry Andric   virtual std::string cNameBase() const = 0;
233480093f4SDimitry Andric 
234480093f4SDimitry Andric public:
cName() const235480093f4SDimitry Andric   std::string cName() const override { return cNameBase() + "_t"; }
236480093f4SDimitry Andric };
237480093f4SDimitry Andric 
238480093f4SDimitry Andric class ScalarType : public CRegularNamedType {
239480093f4SDimitry Andric   ScalarTypeKind Kind;
240480093f4SDimitry Andric   unsigned Bits;
241480093f4SDimitry Andric   std::string NameOverride;
242480093f4SDimitry Andric 
243480093f4SDimitry Andric public:
ScalarType(const Record * Record)244480093f4SDimitry Andric   ScalarType(const Record *Record) : CRegularNamedType(TypeKind::Scalar) {
245480093f4SDimitry Andric     Kind = StringSwitch<ScalarTypeKind>(Record->getValueAsString("kind"))
246480093f4SDimitry Andric                .Case("s", ScalarTypeKind::SignedInt)
247480093f4SDimitry Andric                .Case("u", ScalarTypeKind::UnsignedInt)
248480093f4SDimitry Andric                .Case("f", ScalarTypeKind::Float);
249480093f4SDimitry Andric     Bits = Record->getValueAsInt("size");
2505ffd83dbSDimitry Andric     NameOverride = std::string(Record->getValueAsString("nameOverride"));
251480093f4SDimitry Andric   }
sizeInBits() const252480093f4SDimitry Andric   unsigned sizeInBits() const override { return Bits; }
kind() const253480093f4SDimitry Andric   ScalarTypeKind kind() const { return Kind; }
suffix() const254480093f4SDimitry Andric   std::string suffix() const { return toLetter(Kind) + utostr(Bits); }
cNameBase() const255480093f4SDimitry Andric   std::string cNameBase() const override {
256480093f4SDimitry Andric     return toCPrefix(Kind) + utostr(Bits);
257480093f4SDimitry Andric   }
cName() const258480093f4SDimitry Andric   std::string cName() const override {
259480093f4SDimitry Andric     if (NameOverride.empty())
260480093f4SDimitry Andric       return CRegularNamedType::cName();
261480093f4SDimitry Andric     return NameOverride;
262480093f4SDimitry Andric   }
llvmName() const263480093f4SDimitry Andric   std::string llvmName() const override {
264480093f4SDimitry Andric     if (Kind == ScalarTypeKind::Float) {
265480093f4SDimitry Andric       if (Bits == 16)
266480093f4SDimitry Andric         return "HalfTy";
267480093f4SDimitry Andric       if (Bits == 32)
268480093f4SDimitry Andric         return "FloatTy";
269480093f4SDimitry Andric       if (Bits == 64)
270480093f4SDimitry Andric         return "DoubleTy";
271480093f4SDimitry Andric       PrintFatalError("bad size for floating type");
272480093f4SDimitry Andric     }
273480093f4SDimitry Andric     return "Int" + utostr(Bits) + "Ty";
274480093f4SDimitry Andric   }
acleSuffix(std::string overrideLetter) const275480093f4SDimitry Andric   std::string acleSuffix(std::string overrideLetter) const override {
276480093f4SDimitry Andric     return "_" + (overrideLetter.size() ? overrideLetter : toLetter(Kind))
277480093f4SDimitry Andric                + utostr(Bits);
278480093f4SDimitry Andric   }
isInteger() const279480093f4SDimitry Andric   bool isInteger() const { return Kind != ScalarTypeKind::Float; }
requiresFloat() const280480093f4SDimitry Andric   bool requiresFloat() const override { return !isInteger(); }
requiresMVE() const2815ffd83dbSDimitry Andric   bool requiresMVE() const override { return false; }
hasNonstandardName() const282480093f4SDimitry Andric   bool hasNonstandardName() const { return !NameOverride.empty(); }
283480093f4SDimitry Andric 
classof(const Type * T)284480093f4SDimitry Andric   static bool classof(const Type *T) {
285480093f4SDimitry Andric     return T->typeKind() == TypeKind::Scalar;
286480093f4SDimitry Andric   }
287480093f4SDimitry Andric };
288480093f4SDimitry Andric 
289480093f4SDimitry Andric class VectorType : public CRegularNamedType {
290480093f4SDimitry Andric   const ScalarType *Element;
291480093f4SDimitry Andric   unsigned Lanes;
292480093f4SDimitry Andric 
293480093f4SDimitry Andric public:
VectorType(const ScalarType * Element,unsigned Lanes)294480093f4SDimitry Andric   VectorType(const ScalarType *Element, unsigned Lanes)
295480093f4SDimitry Andric       : CRegularNamedType(TypeKind::Vector), Element(Element), Lanes(Lanes) {}
sizeInBits() const296480093f4SDimitry Andric   unsigned sizeInBits() const override { return Lanes * Element->sizeInBits(); }
lanes() const297480093f4SDimitry Andric   unsigned lanes() const { return Lanes; }
requiresFloat() const298480093f4SDimitry Andric   bool requiresFloat() const override { return Element->requiresFloat(); }
requiresMVE() const2995ffd83dbSDimitry Andric   bool requiresMVE() const override { return true; }
cNameBase() const300480093f4SDimitry Andric   std::string cNameBase() const override {
301480093f4SDimitry Andric     return Element->cNameBase() + "x" + utostr(Lanes);
302480093f4SDimitry Andric   }
llvmName() const303480093f4SDimitry Andric   std::string llvmName() const override {
3045ffd83dbSDimitry Andric     return "llvm::FixedVectorType::get(" + Element->llvmName() + ", " +
305480093f4SDimitry Andric            utostr(Lanes) + ")";
306480093f4SDimitry Andric   }
307480093f4SDimitry Andric 
classof(const Type * T)308480093f4SDimitry Andric   static bool classof(const Type *T) {
309480093f4SDimitry Andric     return T->typeKind() == TypeKind::Vector;
310480093f4SDimitry Andric   }
311480093f4SDimitry Andric };
312480093f4SDimitry Andric 
313480093f4SDimitry Andric class MultiVectorType : public CRegularNamedType {
314480093f4SDimitry Andric   const VectorType *Element;
315480093f4SDimitry Andric   unsigned Registers;
316480093f4SDimitry Andric 
317480093f4SDimitry Andric public:
MultiVectorType(unsigned Registers,const VectorType * Element)318480093f4SDimitry Andric   MultiVectorType(unsigned Registers, const VectorType *Element)
319480093f4SDimitry Andric       : CRegularNamedType(TypeKind::MultiVector), Element(Element),
320480093f4SDimitry Andric         Registers(Registers) {}
sizeInBits() const321480093f4SDimitry Andric   unsigned sizeInBits() const override {
322480093f4SDimitry Andric     return Registers * Element->sizeInBits();
323480093f4SDimitry Andric   }
registers() const324480093f4SDimitry Andric   unsigned registers() const { return Registers; }
requiresFloat() const325480093f4SDimitry Andric   bool requiresFloat() const override { return Element->requiresFloat(); }
requiresMVE() const3265ffd83dbSDimitry Andric   bool requiresMVE() const override { return true; }
cNameBase() const327480093f4SDimitry Andric   std::string cNameBase() const override {
328480093f4SDimitry Andric     return Element->cNameBase() + "x" + utostr(Registers);
329480093f4SDimitry Andric   }
330480093f4SDimitry Andric 
331480093f4SDimitry Andric   // MultiVectorType doesn't override llvmName, because we don't expect to do
332480093f4SDimitry Andric   // automatic code generation for the MVE intrinsics that use it: the {vld2,
333480093f4SDimitry Andric   // vld4, vst2, vst4} family are the only ones that use these types, so it was
334480093f4SDimitry Andric   // easier to hand-write the codegen for dealing with these structs than to
335480093f4SDimitry Andric   // build in lots of extra automatic machinery that would only be used once.
336480093f4SDimitry Andric 
classof(const Type * T)337480093f4SDimitry Andric   static bool classof(const Type *T) {
338480093f4SDimitry Andric     return T->typeKind() == TypeKind::MultiVector;
339480093f4SDimitry Andric   }
340480093f4SDimitry Andric };
341480093f4SDimitry Andric 
342480093f4SDimitry Andric class PredicateType : public CRegularNamedType {
343480093f4SDimitry Andric   unsigned Lanes;
344480093f4SDimitry Andric 
345480093f4SDimitry Andric public:
PredicateType(unsigned Lanes)346480093f4SDimitry Andric   PredicateType(unsigned Lanes)
347480093f4SDimitry Andric       : CRegularNamedType(TypeKind::Predicate), Lanes(Lanes) {}
sizeInBits() const348480093f4SDimitry Andric   unsigned sizeInBits() const override { return 16; }
cNameBase() const349480093f4SDimitry Andric   std::string cNameBase() const override { return "mve_pred16"; }
requiresFloat() const350480093f4SDimitry Andric   bool requiresFloat() const override { return false; };
requiresMVE() const3515ffd83dbSDimitry Andric   bool requiresMVE() const override { return true; }
llvmName() const352480093f4SDimitry Andric   std::string llvmName() const override {
3530eae32dcSDimitry Andric     return "llvm::FixedVectorType::get(Builder.getInt1Ty(), " + utostr(Lanes) +
3540eae32dcSDimitry Andric            ")";
355480093f4SDimitry Andric   }
356480093f4SDimitry Andric 
classof(const Type * T)357480093f4SDimitry Andric   static bool classof(const Type *T) {
358480093f4SDimitry Andric     return T->typeKind() == TypeKind::Predicate;
359480093f4SDimitry Andric   }
360480093f4SDimitry Andric };
361480093f4SDimitry Andric 
362480093f4SDimitry Andric // -----------------------------------------------------------------------------
363480093f4SDimitry Andric // Class to facilitate merging together the code generation for many intrinsics
364480093f4SDimitry Andric // by means of varying a few constant or type parameters.
365480093f4SDimitry Andric //
366480093f4SDimitry Andric // Most obviously, the intrinsics in a single parametrised family will have
367480093f4SDimitry Andric // code generation sequences that only differ in a type or two, e.g. vaddq_s8
368480093f4SDimitry Andric // and vaddq_u16 will look the same apart from putting a different vector type
369480093f4SDimitry Andric // in the call to CGM.getIntrinsic(). But also, completely different intrinsics
370480093f4SDimitry Andric // will often code-generate in the same way, with only a different choice of
371480093f4SDimitry Andric // _which_ IR intrinsic they lower to (e.g. vaddq_m_s8 and vmulq_m_s8), but
372480093f4SDimitry Andric // marshalling the arguments and return values of the IR intrinsic in exactly
373480093f4SDimitry Andric // the same way. And others might differ only in some other kind of constant,
374480093f4SDimitry Andric // such as a lane index.
375480093f4SDimitry Andric //
376480093f4SDimitry Andric // So, when we generate the IR-building code for all these intrinsics, we keep
377480093f4SDimitry Andric // track of every value that could possibly be pulled out of the code and
378480093f4SDimitry Andric // stored ahead of time in a local variable. Then we group together intrinsics
379480093f4SDimitry Andric // by textual equivalence of the code that would result if _all_ those
380480093f4SDimitry Andric // parameters were stored in local variables. That gives us maximal sets that
381480093f4SDimitry Andric // can be implemented by a single piece of IR-building code by changing
382480093f4SDimitry Andric // parameter values ahead of time.
383480093f4SDimitry Andric //
384480093f4SDimitry Andric // After we've done that, we do a second pass in which we only allocate _some_
385480093f4SDimitry Andric // of the parameters into local variables, by tracking which ones have the same
386480093f4SDimitry Andric // values as each other (so that a single variable can be reused) and which
387480093f4SDimitry Andric // ones are the same across the whole set (so that no variable is needed at
388480093f4SDimitry Andric // all).
389480093f4SDimitry Andric //
390480093f4SDimitry Andric // Hence the class below. Its allocParam method is invoked during code
391480093f4SDimitry Andric // generation by every method of a Result subclass (see below) that wants to
392480093f4SDimitry Andric // give it the opportunity to pull something out into a switchable parameter.
393480093f4SDimitry Andric // It returns a variable name for the parameter, or (if it's being used in the
394480093f4SDimitry Andric // second pass once we've decided that some parameters don't need to be stored
395480093f4SDimitry Andric // in variables after all) it might just return the input expression unchanged.
396480093f4SDimitry Andric 
397480093f4SDimitry Andric struct CodeGenParamAllocator {
398480093f4SDimitry Andric   // Accumulated during code generation
399480093f4SDimitry Andric   std::vector<std::string> *ParamTypes = nullptr;
400480093f4SDimitry Andric   std::vector<std::string> *ParamValues = nullptr;
401480093f4SDimitry Andric 
402480093f4SDimitry Andric   // Provided ahead of time in pass 2, to indicate which parameters are being
403480093f4SDimitry Andric   // assigned to what. This vector contains an entry for each call to
404480093f4SDimitry Andric   // allocParam expected during code gen (which we counted up in pass 1), and
405480093f4SDimitry Andric   // indicates the number of the parameter variable that should be returned, or
406480093f4SDimitry Andric   // -1 if this call shouldn't allocate a parameter variable at all.
407480093f4SDimitry Andric   //
408480093f4SDimitry Andric   // We rely on the recursive code generation working identically in passes 1
409480093f4SDimitry Andric   // and 2, so that the same list of calls to allocParam happen in the same
410480093f4SDimitry Andric   // order. That guarantees that the parameter numbers recorded in pass 1 will
4115ffd83dbSDimitry Andric   // match the entries in this vector that store what EmitterBase::EmitBuiltinCG
412480093f4SDimitry Andric   // decided to do about each one in pass 2.
413480093f4SDimitry Andric   std::vector<int> *ParamNumberMap = nullptr;
414480093f4SDimitry Andric 
415480093f4SDimitry Andric   // Internally track how many things we've allocated
416480093f4SDimitry Andric   unsigned nparams = 0;
417480093f4SDimitry Andric 
allocParam__anonc95a670f0111::CodeGenParamAllocator418480093f4SDimitry Andric   std::string allocParam(StringRef Type, StringRef Value) {
419480093f4SDimitry Andric     unsigned ParamNumber;
420480093f4SDimitry Andric 
421480093f4SDimitry Andric     if (!ParamNumberMap) {
422480093f4SDimitry Andric       // In pass 1, unconditionally assign a new parameter variable to every
423480093f4SDimitry Andric       // value we're asked to process.
424480093f4SDimitry Andric       ParamNumber = nparams++;
425480093f4SDimitry Andric     } else {
426480093f4SDimitry Andric       // In pass 2, consult the map provided by the caller to find out which
427480093f4SDimitry Andric       // variable we should be keeping things in.
428480093f4SDimitry Andric       int MapValue = (*ParamNumberMap)[nparams++];
429480093f4SDimitry Andric       if (MapValue < 0)
4305ffd83dbSDimitry Andric         return std::string(Value);
431480093f4SDimitry Andric       ParamNumber = MapValue;
432480093f4SDimitry Andric     }
433480093f4SDimitry Andric 
434480093f4SDimitry Andric     // If we've allocated a new parameter variable for the first time, store
435480093f4SDimitry Andric     // its type and value to be retrieved after codegen.
436480093f4SDimitry Andric     if (ParamTypes && ParamTypes->size() == ParamNumber)
4375ffd83dbSDimitry Andric       ParamTypes->push_back(std::string(Type));
438480093f4SDimitry Andric     if (ParamValues && ParamValues->size() == ParamNumber)
4395ffd83dbSDimitry Andric       ParamValues->push_back(std::string(Value));
440480093f4SDimitry Andric 
441480093f4SDimitry Andric     // Unimaginative naming scheme for parameter variables.
442480093f4SDimitry Andric     return "Param" + utostr(ParamNumber);
443480093f4SDimitry Andric   }
444480093f4SDimitry Andric };
445480093f4SDimitry Andric 
446480093f4SDimitry Andric // -----------------------------------------------------------------------------
447480093f4SDimitry Andric // System of classes that represent all the intermediate values used during
448480093f4SDimitry Andric // code-generation for an intrinsic.
449480093f4SDimitry Andric //
450480093f4SDimitry Andric // The base class 'Result' can represent a value of the LLVM type 'Value', or
451480093f4SDimitry Andric // sometimes 'Address' (for loads/stores, including an alignment requirement).
452480093f4SDimitry Andric //
453480093f4SDimitry Andric // In the case where the Tablegen provides a value in the codegen dag as a
454480093f4SDimitry Andric // plain integer literal, the Result object we construct here will be one that
455480093f4SDimitry Andric // returns true from hasIntegerConstantValue(). This allows the generated C++
456480093f4SDimitry Andric // code to use the constant directly in contexts which can take a literal
457480093f4SDimitry Andric // integer, such as Builder.CreateExtractValue(thing, 1), without going to the
458480093f4SDimitry Andric // effort of calling llvm::ConstantInt::get() and then pulling the constant
459480093f4SDimitry Andric // back out of the resulting llvm:Value later.
460480093f4SDimitry Andric 
461480093f4SDimitry Andric class Result {
462480093f4SDimitry Andric public:
463480093f4SDimitry Andric   // Convenient shorthand for the pointer type we'll be using everywhere.
464480093f4SDimitry Andric   using Ptr = std::shared_ptr<Result>;
465480093f4SDimitry Andric 
466480093f4SDimitry Andric private:
467480093f4SDimitry Andric   Ptr Predecessor;
468480093f4SDimitry Andric   std::string VarName;
469480093f4SDimitry Andric   bool VarNameUsed = false;
470480093f4SDimitry Andric   unsigned Visited = 0;
471480093f4SDimitry Andric 
472480093f4SDimitry Andric public:
473480093f4SDimitry Andric   virtual ~Result() = default;
474480093f4SDimitry Andric   using Scope = std::map<std::string, Ptr>;
475480093f4SDimitry Andric   virtual void genCode(raw_ostream &OS, CodeGenParamAllocator &) const = 0;
hasIntegerConstantValue() const476480093f4SDimitry Andric   virtual bool hasIntegerConstantValue() const { return false; }
integerConstantValue() const477480093f4SDimitry Andric   virtual uint32_t integerConstantValue() const { return 0; }
hasIntegerValue() const478480093f4SDimitry Andric   virtual bool hasIntegerValue() const { return false; }
getIntegerValue(const std::string &)479480093f4SDimitry Andric   virtual std::string getIntegerValue(const std::string &) {
480480093f4SDimitry Andric     llvm_unreachable("non-working Result::getIntegerValue called");
481480093f4SDimitry Andric   }
typeName() const482480093f4SDimitry Andric   virtual std::string typeName() const { return "Value *"; }
483480093f4SDimitry Andric 
484480093f4SDimitry Andric   // Mostly, when a code-generation operation has a dependency on prior
485480093f4SDimitry Andric   // operations, it's because it uses the output values of those operations as
486480093f4SDimitry Andric   // inputs. But there's one exception, which is the use of 'seq' in Tablegen
487480093f4SDimitry Andric   // to indicate that operations have to be performed in sequence regardless of
488480093f4SDimitry Andric   // whether they use each others' output values.
489480093f4SDimitry Andric   //
490480093f4SDimitry Andric   // So, the actual generation of code is done by depth-first search, using the
491480093f4SDimitry Andric   // prerequisites() method to get a list of all the other Results that have to
492480093f4SDimitry Andric   // be computed before this one. That method divides into the 'predecessor',
493480093f4SDimitry Andric   // set by setPredecessor() while processing a 'seq' dag node, and the list
494480093f4SDimitry Andric   // returned by 'morePrerequisites', which each subclass implements to return
495480093f4SDimitry Andric   // a list of the Results it uses as input to whatever its own computation is
496480093f4SDimitry Andric   // doing.
497480093f4SDimitry Andric 
morePrerequisites(std::vector<Ptr> & output) const498480093f4SDimitry Andric   virtual void morePrerequisites(std::vector<Ptr> &output) const {}
prerequisites() const499480093f4SDimitry Andric   std::vector<Ptr> prerequisites() const {
500480093f4SDimitry Andric     std::vector<Ptr> ToRet;
501480093f4SDimitry Andric     if (Predecessor)
502480093f4SDimitry Andric       ToRet.push_back(Predecessor);
503480093f4SDimitry Andric     morePrerequisites(ToRet);
504480093f4SDimitry Andric     return ToRet;
505480093f4SDimitry Andric   }
506480093f4SDimitry Andric 
setPredecessor(Ptr p)507480093f4SDimitry Andric   void setPredecessor(Ptr p) {
5085ffd83dbSDimitry Andric     // If the user has nested one 'seq' node inside another, and this
5095ffd83dbSDimitry Andric     // method is called on the return value of the inner 'seq' (i.e.
5105ffd83dbSDimitry Andric     // the final item inside it), then we can't link _this_ node to p,
5115ffd83dbSDimitry Andric     // because it already has a predecessor. Instead, walk the chain
5125ffd83dbSDimitry Andric     // until we find the first item in the inner seq, and link that to
5135ffd83dbSDimitry Andric     // p, so that nesting seqs has the obvious effect of linking
5145ffd83dbSDimitry Andric     // everything together into one long sequential chain.
5155ffd83dbSDimitry Andric     Result *r = this;
5165ffd83dbSDimitry Andric     while (r->Predecessor)
5175ffd83dbSDimitry Andric       r = r->Predecessor.get();
5185ffd83dbSDimitry Andric     r->Predecessor = p;
519480093f4SDimitry Andric   }
520480093f4SDimitry Andric 
521480093f4SDimitry Andric   // Each Result will be assigned a variable name in the output code, but not
522480093f4SDimitry Andric   // all those variable names will actually be used (e.g. the return value of
523480093f4SDimitry Andric   // Builder.CreateStore has void type, so nobody will want to refer to it). To
524480093f4SDimitry Andric   // prevent annoying compiler warnings, we track whether each Result's
525480093f4SDimitry Andric   // variable name was ever actually mentioned in subsequent statements, so
526480093f4SDimitry Andric   // that it can be left out of the final generated code.
varname()527480093f4SDimitry Andric   std::string varname() {
528480093f4SDimitry Andric     VarNameUsed = true;
529480093f4SDimitry Andric     return VarName;
530480093f4SDimitry Andric   }
setVarname(const StringRef s)5315ffd83dbSDimitry Andric   void setVarname(const StringRef s) { VarName = std::string(s); }
varnameUsed() const532480093f4SDimitry Andric   bool varnameUsed() const { return VarNameUsed; }
533480093f4SDimitry Andric 
534480093f4SDimitry Andric   // Emit code to generate this result as a Value *.
asValue()535480093f4SDimitry Andric   virtual std::string asValue() {
536480093f4SDimitry Andric     return varname();
537480093f4SDimitry Andric   }
538480093f4SDimitry Andric 
539480093f4SDimitry Andric   // Code generation happens in multiple passes. This method tracks whether a
540480093f4SDimitry Andric   // Result has yet been visited in a given pass, without the need for a
541480093f4SDimitry Andric   // tedious loop in between passes that goes through and resets a 'visited'
542480093f4SDimitry Andric   // flag back to false: you just set Pass=1 the first time round, and Pass=2
543480093f4SDimitry Andric   // the second time.
needsVisiting(unsigned Pass)544480093f4SDimitry Andric   bool needsVisiting(unsigned Pass) {
545480093f4SDimitry Andric     bool ToRet = Visited < Pass;
546480093f4SDimitry Andric     Visited = Pass;
547480093f4SDimitry Andric     return ToRet;
548480093f4SDimitry Andric   }
549480093f4SDimitry Andric };
550480093f4SDimitry Andric 
551480093f4SDimitry Andric // Result subclass that retrieves one of the arguments to the clang builtin
552480093f4SDimitry Andric // function. In cases where the argument has pointer type, we call
553480093f4SDimitry Andric // EmitPointerWithAlignment and store the result in a variable of type Address,
554480093f4SDimitry Andric // so that load and store IR nodes can know the right alignment. Otherwise, we
555480093f4SDimitry Andric // call EmitScalarExpr.
556480093f4SDimitry Andric //
557480093f4SDimitry Andric // There are aggregate parameters in the MVE intrinsics API, but we don't deal
558480093f4SDimitry Andric // with them in this Tablegen back end: they only arise in the vld2q/vld4q and
559480093f4SDimitry Andric // vst2q/vst4q family, which is few enough that we just write the code by hand
560480093f4SDimitry Andric // for those in CGBuiltin.cpp.
561480093f4SDimitry Andric class BuiltinArgResult : public Result {
562480093f4SDimitry Andric public:
563480093f4SDimitry Andric   unsigned ArgNum;
564480093f4SDimitry Andric   bool AddressType;
565480093f4SDimitry Andric   bool Immediate;
BuiltinArgResult(unsigned ArgNum,bool AddressType,bool Immediate)566480093f4SDimitry Andric   BuiltinArgResult(unsigned ArgNum, bool AddressType, bool Immediate)
567480093f4SDimitry Andric       : ArgNum(ArgNum), AddressType(AddressType), Immediate(Immediate) {}
genCode(raw_ostream & OS,CodeGenParamAllocator &) const568480093f4SDimitry Andric   void genCode(raw_ostream &OS, CodeGenParamAllocator &) const override {
569480093f4SDimitry Andric     OS << (AddressType ? "EmitPointerWithAlignment" : "EmitScalarExpr")
570480093f4SDimitry Andric        << "(E->getArg(" << ArgNum << "))";
571480093f4SDimitry Andric   }
typeName() const572480093f4SDimitry Andric   std::string typeName() const override {
573480093f4SDimitry Andric     return AddressType ? "Address" : Result::typeName();
574480093f4SDimitry Andric   }
575480093f4SDimitry Andric   // Emit code to generate this result as a Value *.
asValue()576480093f4SDimitry Andric   std::string asValue() override {
577480093f4SDimitry Andric     if (AddressType)
578480093f4SDimitry Andric       return "(" + varname() + ".getPointer())";
579480093f4SDimitry Andric     return Result::asValue();
580480093f4SDimitry Andric   }
hasIntegerValue() const581480093f4SDimitry Andric   bool hasIntegerValue() const override { return Immediate; }
getIntegerValue(const std::string & IntType)582480093f4SDimitry Andric   std::string getIntegerValue(const std::string &IntType) override {
583480093f4SDimitry Andric     return "GetIntegerConstantValue<" + IntType + ">(E->getArg(" +
584480093f4SDimitry Andric            utostr(ArgNum) + "), getContext())";
585480093f4SDimitry Andric   }
586480093f4SDimitry Andric };
587480093f4SDimitry Andric 
588480093f4SDimitry Andric // Result subclass for an integer literal appearing in Tablegen. This may need
589480093f4SDimitry Andric // to be turned into an llvm::Result by means of llvm::ConstantInt::get(), or
590480093f4SDimitry Andric // it may be used directly as an integer, depending on which IRBuilder method
591480093f4SDimitry Andric // it's being passed to.
592480093f4SDimitry Andric class IntLiteralResult : public Result {
593480093f4SDimitry Andric public:
594480093f4SDimitry Andric   const ScalarType *IntegerType;
595480093f4SDimitry Andric   uint32_t IntegerValue;
IntLiteralResult(const ScalarType * IntegerType,uint32_t IntegerValue)596480093f4SDimitry Andric   IntLiteralResult(const ScalarType *IntegerType, uint32_t IntegerValue)
597480093f4SDimitry Andric       : IntegerType(IntegerType), IntegerValue(IntegerValue) {}
genCode(raw_ostream & OS,CodeGenParamAllocator & ParamAlloc) const598480093f4SDimitry Andric   void genCode(raw_ostream &OS,
599480093f4SDimitry Andric                CodeGenParamAllocator &ParamAlloc) const override {
600480093f4SDimitry Andric     OS << "llvm::ConstantInt::get("
601480093f4SDimitry Andric        << ParamAlloc.allocParam("llvm::Type *", IntegerType->llvmName())
602480093f4SDimitry Andric        << ", ";
603480093f4SDimitry Andric     OS << ParamAlloc.allocParam(IntegerType->cName(), utostr(IntegerValue))
604480093f4SDimitry Andric        << ")";
605480093f4SDimitry Andric   }
hasIntegerConstantValue() const606480093f4SDimitry Andric   bool hasIntegerConstantValue() const override { return true; }
integerConstantValue() const607480093f4SDimitry Andric   uint32_t integerConstantValue() const override { return IntegerValue; }
608480093f4SDimitry Andric };
609480093f4SDimitry Andric 
610480093f4SDimitry Andric // Result subclass representing a cast between different integer types. We use
611480093f4SDimitry Andric // our own ScalarType abstraction as the representation of the target type,
612480093f4SDimitry Andric // which gives both size and signedness.
613480093f4SDimitry Andric class IntCastResult : public Result {
614480093f4SDimitry Andric public:
615480093f4SDimitry Andric   const ScalarType *IntegerType;
616480093f4SDimitry Andric   Ptr V;
IntCastResult(const ScalarType * IntegerType,Ptr V)617480093f4SDimitry Andric   IntCastResult(const ScalarType *IntegerType, Ptr V)
618480093f4SDimitry Andric       : IntegerType(IntegerType), V(V) {}
genCode(raw_ostream & OS,CodeGenParamAllocator & ParamAlloc) const619480093f4SDimitry Andric   void genCode(raw_ostream &OS,
620480093f4SDimitry Andric                CodeGenParamAllocator &ParamAlloc) const override {
621480093f4SDimitry Andric     OS << "Builder.CreateIntCast(" << V->varname() << ", "
622480093f4SDimitry Andric        << ParamAlloc.allocParam("llvm::Type *", IntegerType->llvmName()) << ", "
623480093f4SDimitry Andric        << ParamAlloc.allocParam("bool",
624480093f4SDimitry Andric                                 IntegerType->kind() == ScalarTypeKind::SignedInt
625480093f4SDimitry Andric                                     ? "true"
626480093f4SDimitry Andric                                     : "false")
627480093f4SDimitry Andric        << ")";
628480093f4SDimitry Andric   }
morePrerequisites(std::vector<Ptr> & output) const629480093f4SDimitry Andric   void morePrerequisites(std::vector<Ptr> &output) const override {
630480093f4SDimitry Andric     output.push_back(V);
631480093f4SDimitry Andric   }
632480093f4SDimitry Andric };
633480093f4SDimitry Andric 
634480093f4SDimitry Andric // Result subclass representing a cast between different pointer types.
635480093f4SDimitry Andric class PointerCastResult : public Result {
636480093f4SDimitry Andric public:
637480093f4SDimitry Andric   const PointerType *PtrType;
638480093f4SDimitry Andric   Ptr V;
PointerCastResult(const PointerType * PtrType,Ptr V)639480093f4SDimitry Andric   PointerCastResult(const PointerType *PtrType, Ptr V)
640480093f4SDimitry Andric       : PtrType(PtrType), V(V) {}
genCode(raw_ostream & OS,CodeGenParamAllocator & ParamAlloc) const641480093f4SDimitry Andric   void genCode(raw_ostream &OS,
642480093f4SDimitry Andric                CodeGenParamAllocator &ParamAlloc) const override {
643480093f4SDimitry Andric     OS << "Builder.CreatePointerCast(" << V->asValue() << ", "
644480093f4SDimitry Andric        << ParamAlloc.allocParam("llvm::Type *", PtrType->llvmName()) << ")";
645480093f4SDimitry Andric   }
morePrerequisites(std::vector<Ptr> & output) const646480093f4SDimitry Andric   void morePrerequisites(std::vector<Ptr> &output) const override {
647480093f4SDimitry Andric     output.push_back(V);
648480093f4SDimitry Andric   }
649480093f4SDimitry Andric };
650480093f4SDimitry Andric 
651480093f4SDimitry Andric // Result subclass representing a call to an IRBuilder method. Each IRBuilder
652480093f4SDimitry Andric // method we want to use will have a Tablegen record giving the method name and
653480093f4SDimitry Andric // describing any important details of how to call it, such as whether a
654480093f4SDimitry Andric // particular argument should be an integer constant instead of an llvm::Value.
655480093f4SDimitry Andric class IRBuilderResult : public Result {
656480093f4SDimitry Andric public:
657480093f4SDimitry Andric   StringRef CallPrefix;
658480093f4SDimitry Andric   std::vector<Ptr> Args;
659480093f4SDimitry Andric   std::set<unsigned> AddressArgs;
660480093f4SDimitry Andric   std::map<unsigned, std::string> IntegerArgs;
IRBuilderResult(StringRef CallPrefix,std::vector<Ptr> Args,std::set<unsigned> AddressArgs,std::map<unsigned,std::string> IntegerArgs)661480093f4SDimitry Andric   IRBuilderResult(StringRef CallPrefix, std::vector<Ptr> Args,
662480093f4SDimitry Andric                   std::set<unsigned> AddressArgs,
663480093f4SDimitry Andric                   std::map<unsigned, std::string> IntegerArgs)
664480093f4SDimitry Andric       : CallPrefix(CallPrefix), Args(Args), AddressArgs(AddressArgs),
665480093f4SDimitry Andric         IntegerArgs(IntegerArgs) {}
genCode(raw_ostream & OS,CodeGenParamAllocator & ParamAlloc) const666480093f4SDimitry Andric   void genCode(raw_ostream &OS,
667480093f4SDimitry Andric                CodeGenParamAllocator &ParamAlloc) const override {
668480093f4SDimitry Andric     OS << CallPrefix;
669480093f4SDimitry Andric     const char *Sep = "";
670480093f4SDimitry Andric     for (unsigned i = 0, e = Args.size(); i < e; ++i) {
671480093f4SDimitry Andric       Ptr Arg = Args[i];
672480093f4SDimitry Andric       auto it = IntegerArgs.find(i);
673480093f4SDimitry Andric 
674480093f4SDimitry Andric       OS << Sep;
675480093f4SDimitry Andric       Sep = ", ";
676480093f4SDimitry Andric 
677480093f4SDimitry Andric       if (it != IntegerArgs.end()) {
678480093f4SDimitry Andric         if (Arg->hasIntegerConstantValue())
679480093f4SDimitry Andric           OS << "static_cast<" << it->second << ">("
680480093f4SDimitry Andric              << ParamAlloc.allocParam(it->second,
681480093f4SDimitry Andric                                       utostr(Arg->integerConstantValue()))
682480093f4SDimitry Andric              << ")";
683480093f4SDimitry Andric         else if (Arg->hasIntegerValue())
684480093f4SDimitry Andric           OS << ParamAlloc.allocParam(it->second,
685480093f4SDimitry Andric                                       Arg->getIntegerValue(it->second));
686480093f4SDimitry Andric       } else {
687480093f4SDimitry Andric         OS << Arg->varname();
688480093f4SDimitry Andric       }
689480093f4SDimitry Andric     }
690480093f4SDimitry Andric     OS << ")";
691480093f4SDimitry Andric   }
morePrerequisites(std::vector<Ptr> & output) const692480093f4SDimitry Andric   void morePrerequisites(std::vector<Ptr> &output) const override {
693480093f4SDimitry Andric     for (unsigned i = 0, e = Args.size(); i < e; ++i) {
694480093f4SDimitry Andric       Ptr Arg = Args[i];
695480093f4SDimitry Andric       if (IntegerArgs.find(i) != IntegerArgs.end())
696480093f4SDimitry Andric         continue;
697480093f4SDimitry Andric       output.push_back(Arg);
698480093f4SDimitry Andric     }
699480093f4SDimitry Andric   }
700480093f4SDimitry Andric };
701480093f4SDimitry Andric 
702480093f4SDimitry Andric // Result subclass representing making an Address out of a Value.
703480093f4SDimitry Andric class AddressResult : public Result {
704480093f4SDimitry Andric public:
705480093f4SDimitry Andric   Ptr Arg;
70681ad6265SDimitry Andric   const Type *Ty;
707480093f4SDimitry Andric   unsigned Align;
AddressResult(Ptr Arg,const Type * Ty,unsigned Align)70881ad6265SDimitry Andric   AddressResult(Ptr Arg, const Type *Ty, unsigned Align)
70981ad6265SDimitry Andric       : Arg(Arg), Ty(Ty), Align(Align) {}
genCode(raw_ostream & OS,CodeGenParamAllocator & ParamAlloc) const710480093f4SDimitry Andric   void genCode(raw_ostream &OS,
711480093f4SDimitry Andric                CodeGenParamAllocator &ParamAlloc) const override {
71281ad6265SDimitry Andric     OS << "Address(" << Arg->varname() << ", " << Ty->llvmName()
71381ad6265SDimitry Andric        << ", CharUnits::fromQuantity(" << Align << "))";
714480093f4SDimitry Andric   }
typeName() const715480093f4SDimitry Andric   std::string typeName() const override {
716480093f4SDimitry Andric     return "Address";
717480093f4SDimitry Andric   }
morePrerequisites(std::vector<Ptr> & output) const718480093f4SDimitry Andric   void morePrerequisites(std::vector<Ptr> &output) const override {
719480093f4SDimitry Andric     output.push_back(Arg);
720480093f4SDimitry Andric   }
721480093f4SDimitry Andric };
722480093f4SDimitry Andric 
723480093f4SDimitry Andric // Result subclass representing a call to an IR intrinsic, which we first have
724480093f4SDimitry Andric // to look up using an Intrinsic::ID constant and an array of types.
725480093f4SDimitry Andric class IRIntrinsicResult : public Result {
726480093f4SDimitry Andric public:
727480093f4SDimitry Andric   std::string IntrinsicID;
728480093f4SDimitry Andric   std::vector<const Type *> ParamTypes;
729480093f4SDimitry Andric   std::vector<Ptr> Args;
IRIntrinsicResult(StringRef IntrinsicID,std::vector<const Type * > ParamTypes,std::vector<Ptr> Args)730480093f4SDimitry Andric   IRIntrinsicResult(StringRef IntrinsicID, std::vector<const Type *> ParamTypes,
731480093f4SDimitry Andric                     std::vector<Ptr> Args)
7325ffd83dbSDimitry Andric       : IntrinsicID(std::string(IntrinsicID)), ParamTypes(ParamTypes),
7335ffd83dbSDimitry Andric         Args(Args) {}
genCode(raw_ostream & OS,CodeGenParamAllocator & ParamAlloc) const734480093f4SDimitry Andric   void genCode(raw_ostream &OS,
735480093f4SDimitry Andric                CodeGenParamAllocator &ParamAlloc) const override {
736480093f4SDimitry Andric     std::string IntNo = ParamAlloc.allocParam(
737480093f4SDimitry Andric         "Intrinsic::ID", "Intrinsic::" + IntrinsicID);
738480093f4SDimitry Andric     OS << "Builder.CreateCall(CGM.getIntrinsic(" << IntNo;
739480093f4SDimitry Andric     if (!ParamTypes.empty()) {
7405ffd83dbSDimitry Andric       OS << ", {";
741480093f4SDimitry Andric       const char *Sep = "";
742480093f4SDimitry Andric       for (auto T : ParamTypes) {
743480093f4SDimitry Andric         OS << Sep << ParamAlloc.allocParam("llvm::Type *", T->llvmName());
744480093f4SDimitry Andric         Sep = ", ";
745480093f4SDimitry Andric       }
746480093f4SDimitry Andric       OS << "}";
747480093f4SDimitry Andric     }
7485ffd83dbSDimitry Andric     OS << "), {";
749480093f4SDimitry Andric     const char *Sep = "";
750480093f4SDimitry Andric     for (auto Arg : Args) {
751480093f4SDimitry Andric       OS << Sep << Arg->asValue();
752480093f4SDimitry Andric       Sep = ", ";
753480093f4SDimitry Andric     }
754480093f4SDimitry Andric     OS << "})";
755480093f4SDimitry Andric   }
morePrerequisites(std::vector<Ptr> & output) const756480093f4SDimitry Andric   void morePrerequisites(std::vector<Ptr> &output) const override {
757480093f4SDimitry Andric     output.insert(output.end(), Args.begin(), Args.end());
758480093f4SDimitry Andric   }
759480093f4SDimitry Andric };
760480093f4SDimitry Andric 
761480093f4SDimitry Andric // Result subclass that specifies a type, for use in IRBuilder operations such
762480093f4SDimitry Andric // as CreateBitCast that take a type argument.
763480093f4SDimitry Andric class TypeResult : public Result {
764480093f4SDimitry Andric public:
765480093f4SDimitry Andric   const Type *T;
TypeResult(const Type * T)766480093f4SDimitry Andric   TypeResult(const Type *T) : T(T) {}
genCode(raw_ostream & OS,CodeGenParamAllocator &) const767480093f4SDimitry Andric   void genCode(raw_ostream &OS, CodeGenParamAllocator &) const override {
768480093f4SDimitry Andric     OS << T->llvmName();
769480093f4SDimitry Andric   }
typeName() const770480093f4SDimitry Andric   std::string typeName() const override {
771480093f4SDimitry Andric     return "llvm::Type *";
772480093f4SDimitry Andric   }
773480093f4SDimitry Andric };
774480093f4SDimitry Andric 
775480093f4SDimitry Andric // -----------------------------------------------------------------------------
776480093f4SDimitry Andric // Class that describes a single ACLE intrinsic.
777480093f4SDimitry Andric //
778480093f4SDimitry Andric // A Tablegen record will typically describe more than one ACLE intrinsic, by
779480093f4SDimitry Andric // means of setting the 'list<Type> Params' field to a list of multiple
780480093f4SDimitry Andric // parameter types, so as to define vaddq_{s8,u8,...,f16,f32} all in one go.
781480093f4SDimitry Andric // We'll end up with one instance of ACLEIntrinsic for *each* parameter type,
782480093f4SDimitry Andric // rather than a single one for all of them. Hence, the constructor takes both
783480093f4SDimitry Andric // a Tablegen record and the current value of the parameter type.
784480093f4SDimitry Andric 
785480093f4SDimitry Andric class ACLEIntrinsic {
786480093f4SDimitry Andric   // Structure documenting that one of the intrinsic's arguments is required to
787480093f4SDimitry Andric   // be a compile-time constant integer, and what constraints there are on its
788480093f4SDimitry Andric   // value. Used when generating Sema checking code.
789480093f4SDimitry Andric   struct ImmediateArg {
790480093f4SDimitry Andric     enum class BoundsType { ExplicitRange, UInt };
791480093f4SDimitry Andric     BoundsType boundsType;
792480093f4SDimitry Andric     int64_t i1, i2;
793480093f4SDimitry Andric     StringRef ExtraCheckType, ExtraCheckArgs;
794480093f4SDimitry Andric     const Type *ArgType;
795480093f4SDimitry Andric   };
796480093f4SDimitry Andric 
797480093f4SDimitry Andric   // For polymorphic intrinsics, FullName is the explicit name that uniquely
798480093f4SDimitry Andric   // identifies this variant of the intrinsic, and ShortName is the name it
799480093f4SDimitry Andric   // shares with at least one other intrinsic.
800480093f4SDimitry Andric   std::string ShortName, FullName;
801480093f4SDimitry Andric 
8025ffd83dbSDimitry Andric   // Name of the architecture extension, used in the Clang builtin name
8035ffd83dbSDimitry Andric   StringRef BuiltinExtension;
8045ffd83dbSDimitry Andric 
805480093f4SDimitry Andric   // A very small number of intrinsics _only_ have a polymorphic
806480093f4SDimitry Andric   // variant (vuninitializedq taking an unevaluated argument).
807480093f4SDimitry Andric   bool PolymorphicOnly;
808480093f4SDimitry Andric 
809480093f4SDimitry Andric   // Another rarely-used flag indicating that the builtin doesn't
810480093f4SDimitry Andric   // evaluate its argument(s) at all.
811480093f4SDimitry Andric   bool NonEvaluating;
812480093f4SDimitry Andric 
8135ffd83dbSDimitry Andric   // True if the intrinsic needs only the C header part (no codegen, semantic
8145ffd83dbSDimitry Andric   // checks, etc). Used for redeclaring MVE intrinsics in the arm_cde.h header.
8155ffd83dbSDimitry Andric   bool HeaderOnly;
8165ffd83dbSDimitry Andric 
817480093f4SDimitry Andric   const Type *ReturnType;
818480093f4SDimitry Andric   std::vector<const Type *> ArgTypes;
819480093f4SDimitry Andric   std::map<unsigned, ImmediateArg> ImmediateArgs;
820480093f4SDimitry Andric   Result::Ptr Code;
821480093f4SDimitry Andric 
822480093f4SDimitry Andric   std::map<std::string, std::string> CustomCodeGenArgs;
823480093f4SDimitry Andric 
824480093f4SDimitry Andric   // Recursive function that does the internals of code generation.
genCodeDfs(Result::Ptr V,std::list<Result::Ptr> & Used,unsigned Pass) const825480093f4SDimitry Andric   void genCodeDfs(Result::Ptr V, std::list<Result::Ptr> &Used,
826480093f4SDimitry Andric                   unsigned Pass) const {
827480093f4SDimitry Andric     if (!V->needsVisiting(Pass))
828480093f4SDimitry Andric       return;
829480093f4SDimitry Andric 
830480093f4SDimitry Andric     for (Result::Ptr W : V->prerequisites())
831480093f4SDimitry Andric       genCodeDfs(W, Used, Pass);
832480093f4SDimitry Andric 
833480093f4SDimitry Andric     Used.push_back(V);
834480093f4SDimitry Andric   }
835480093f4SDimitry Andric 
836480093f4SDimitry Andric public:
shortName() const837480093f4SDimitry Andric   const std::string &shortName() const { return ShortName; }
fullName() const838480093f4SDimitry Andric   const std::string &fullName() const { return FullName; }
builtinExtension() const8395ffd83dbSDimitry Andric   StringRef builtinExtension() const { return BuiltinExtension; }
returnType() const840480093f4SDimitry Andric   const Type *returnType() const { return ReturnType; }
argTypes() const841480093f4SDimitry Andric   const std::vector<const Type *> &argTypes() const { return ArgTypes; }
requiresFloat() const842480093f4SDimitry Andric   bool requiresFloat() const {
843480093f4SDimitry Andric     if (ReturnType->requiresFloat())
844480093f4SDimitry Andric       return true;
845480093f4SDimitry Andric     for (const Type *T : ArgTypes)
846480093f4SDimitry Andric       if (T->requiresFloat())
847480093f4SDimitry Andric         return true;
848480093f4SDimitry Andric     return false;
849480093f4SDimitry Andric   }
requiresMVE() const8505ffd83dbSDimitry Andric   bool requiresMVE() const {
8515ffd83dbSDimitry Andric     return ReturnType->requiresMVE() ||
8525ffd83dbSDimitry Andric            any_of(ArgTypes, [](const Type *T) { return T->requiresMVE(); });
8535ffd83dbSDimitry Andric   }
polymorphic() const854480093f4SDimitry Andric   bool polymorphic() const { return ShortName != FullName; }
polymorphicOnly() const855480093f4SDimitry Andric   bool polymorphicOnly() const { return PolymorphicOnly; }
nonEvaluating() const856480093f4SDimitry Andric   bool nonEvaluating() const { return NonEvaluating; }
headerOnly() const8575ffd83dbSDimitry Andric   bool headerOnly() const { return HeaderOnly; }
858480093f4SDimitry Andric 
8595ffd83dbSDimitry Andric   // External entry point for code generation, called from EmitterBase.
genCode(raw_ostream & OS,CodeGenParamAllocator & ParamAlloc,unsigned Pass) const860480093f4SDimitry Andric   void genCode(raw_ostream &OS, CodeGenParamAllocator &ParamAlloc,
861480093f4SDimitry Andric                unsigned Pass) const {
8625ffd83dbSDimitry Andric     assert(!headerOnly() && "Called genCode for header-only intrinsic");
863480093f4SDimitry Andric     if (!hasCode()) {
864480093f4SDimitry Andric       for (auto kv : CustomCodeGenArgs)
865480093f4SDimitry Andric         OS << "  " << kv.first << " = " << kv.second << ";\n";
866480093f4SDimitry Andric       OS << "  break; // custom code gen\n";
867480093f4SDimitry Andric       return;
868480093f4SDimitry Andric     }
869480093f4SDimitry Andric     std::list<Result::Ptr> Used;
870480093f4SDimitry Andric     genCodeDfs(Code, Used, Pass);
871480093f4SDimitry Andric 
872480093f4SDimitry Andric     unsigned varindex = 0;
873480093f4SDimitry Andric     for (Result::Ptr V : Used)
874480093f4SDimitry Andric       if (V->varnameUsed())
875480093f4SDimitry Andric         V->setVarname("Val" + utostr(varindex++));
876480093f4SDimitry Andric 
877480093f4SDimitry Andric     for (Result::Ptr V : Used) {
878480093f4SDimitry Andric       OS << "  ";
879480093f4SDimitry Andric       if (V == Used.back()) {
880480093f4SDimitry Andric         assert(!V->varnameUsed());
881480093f4SDimitry Andric         OS << "return "; // FIXME: what if the top-level thing is void?
882480093f4SDimitry Andric       } else if (V->varnameUsed()) {
883480093f4SDimitry Andric         std::string Type = V->typeName();
884480093f4SDimitry Andric         OS << V->typeName();
8855f757f3fSDimitry Andric         if (!StringRef(Type).ends_with("*"))
886480093f4SDimitry Andric           OS << " ";
887480093f4SDimitry Andric         OS << V->varname() << " = ";
888480093f4SDimitry Andric       }
889480093f4SDimitry Andric       V->genCode(OS, ParamAlloc);
890480093f4SDimitry Andric       OS << ";\n";
891480093f4SDimitry Andric     }
892480093f4SDimitry Andric   }
hasCode() const893480093f4SDimitry Andric   bool hasCode() const { return Code != nullptr; }
894480093f4SDimitry Andric 
signedHexLiteral(const llvm::APInt & iOrig)895480093f4SDimitry Andric   static std::string signedHexLiteral(const llvm::APInt &iOrig) {
896480093f4SDimitry Andric     llvm::APInt i = iOrig.trunc(64);
897480093f4SDimitry Andric     SmallString<40> s;
898480093f4SDimitry Andric     i.toString(s, 16, true, true);
899*7a6dacacSDimitry Andric     return std::string(s);
900480093f4SDimitry Andric   }
901480093f4SDimitry Andric 
genSema() const902480093f4SDimitry Andric   std::string genSema() const {
9035ffd83dbSDimitry Andric     assert(!headerOnly() && "Called genSema for header-only intrinsic");
904480093f4SDimitry Andric     std::vector<std::string> SemaChecks;
905480093f4SDimitry Andric 
906480093f4SDimitry Andric     for (const auto &kv : ImmediateArgs) {
907480093f4SDimitry Andric       const ImmediateArg &IA = kv.second;
908480093f4SDimitry Andric 
909480093f4SDimitry Andric       llvm::APInt lo(128, 0), hi(128, 0);
910480093f4SDimitry Andric       switch (IA.boundsType) {
911480093f4SDimitry Andric       case ImmediateArg::BoundsType::ExplicitRange:
912480093f4SDimitry Andric         lo = IA.i1;
913480093f4SDimitry Andric         hi = IA.i2;
914480093f4SDimitry Andric         break;
915480093f4SDimitry Andric       case ImmediateArg::BoundsType::UInt:
916480093f4SDimitry Andric         lo = 0;
9175ffd83dbSDimitry Andric         hi = llvm::APInt::getMaxValue(IA.i1).zext(128);
918480093f4SDimitry Andric         break;
919480093f4SDimitry Andric       }
920480093f4SDimitry Andric 
921480093f4SDimitry Andric       std::string Index = utostr(kv.first);
922480093f4SDimitry Andric 
9235ffd83dbSDimitry Andric       // Emit a range check if the legal range of values for the
9245ffd83dbSDimitry Andric       // immediate is smaller than the _possible_ range of values for
9255ffd83dbSDimitry Andric       // its type.
9265ffd83dbSDimitry Andric       unsigned ArgTypeBits = IA.ArgType->sizeInBits();
9275ffd83dbSDimitry Andric       llvm::APInt ArgTypeRange = llvm::APInt::getMaxValue(ArgTypeBits).zext(128);
9285ffd83dbSDimitry Andric       llvm::APInt ActualRange = (hi-lo).trunc(64).sext(128);
9295ffd83dbSDimitry Andric       if (ActualRange.ult(ArgTypeRange))
930480093f4SDimitry Andric         SemaChecks.push_back("SemaBuiltinConstantArgRange(TheCall, " + Index +
931480093f4SDimitry Andric                              ", " + signedHexLiteral(lo) + ", " +
932480093f4SDimitry Andric                              signedHexLiteral(hi) + ")");
933480093f4SDimitry Andric 
934480093f4SDimitry Andric       if (!IA.ExtraCheckType.empty()) {
935480093f4SDimitry Andric         std::string Suffix;
9365ffd83dbSDimitry Andric         if (!IA.ExtraCheckArgs.empty()) {
9375ffd83dbSDimitry Andric           std::string tmp;
9385ffd83dbSDimitry Andric           StringRef Arg = IA.ExtraCheckArgs;
9395ffd83dbSDimitry Andric           if (Arg == "!lanesize") {
9405ffd83dbSDimitry Andric             tmp = utostr(IA.ArgType->sizeInBits());
9415ffd83dbSDimitry Andric             Arg = tmp;
9425ffd83dbSDimitry Andric           }
9435ffd83dbSDimitry Andric           Suffix = (Twine(", ") + Arg).str();
9445ffd83dbSDimitry Andric         }
945480093f4SDimitry Andric         SemaChecks.push_back((Twine("SemaBuiltinConstantArg") +
946480093f4SDimitry Andric                               IA.ExtraCheckType + "(TheCall, " + Index +
947480093f4SDimitry Andric                               Suffix + ")")
948480093f4SDimitry Andric                                  .str());
949480093f4SDimitry Andric       }
9505ffd83dbSDimitry Andric 
9515ffd83dbSDimitry Andric       assert(!SemaChecks.empty());
952480093f4SDimitry Andric     }
953480093f4SDimitry Andric     if (SemaChecks.empty())
954480093f4SDimitry Andric       return "";
9555ffd83dbSDimitry Andric     return join(std::begin(SemaChecks), std::end(SemaChecks),
956480093f4SDimitry Andric                 " ||\n         ") +
9575ffd83dbSDimitry Andric            ";\n";
958480093f4SDimitry Andric   }
959480093f4SDimitry Andric 
9605ffd83dbSDimitry Andric   ACLEIntrinsic(EmitterBase &ME, Record *R, const Type *Param);
961480093f4SDimitry Andric };
962480093f4SDimitry Andric 
963480093f4SDimitry Andric // -----------------------------------------------------------------------------
964480093f4SDimitry Andric // The top-level class that holds all the state from analyzing the entire
965480093f4SDimitry Andric // Tablegen input.
966480093f4SDimitry Andric 
9675ffd83dbSDimitry Andric class EmitterBase {
9685ffd83dbSDimitry Andric protected:
9695ffd83dbSDimitry Andric   // EmitterBase holds a collection of all the types we've instantiated.
970480093f4SDimitry Andric   VoidType Void;
971480093f4SDimitry Andric   std::map<std::string, std::unique_ptr<ScalarType>> ScalarTypes;
972480093f4SDimitry Andric   std::map<std::tuple<ScalarTypeKind, unsigned, unsigned>,
973480093f4SDimitry Andric            std::unique_ptr<VectorType>>
974480093f4SDimitry Andric       VectorTypes;
975480093f4SDimitry Andric   std::map<std::pair<std::string, unsigned>, std::unique_ptr<MultiVectorType>>
976480093f4SDimitry Andric       MultiVectorTypes;
977480093f4SDimitry Andric   std::map<unsigned, std::unique_ptr<PredicateType>> PredicateTypes;
978480093f4SDimitry Andric   std::map<std::string, std::unique_ptr<PointerType>> PointerTypes;
979480093f4SDimitry Andric 
980480093f4SDimitry Andric   // And all the ACLEIntrinsic instances we've created.
981480093f4SDimitry Andric   std::map<std::string, std::unique_ptr<ACLEIntrinsic>> ACLEIntrinsics;
982480093f4SDimitry Andric 
983480093f4SDimitry Andric public:
984480093f4SDimitry Andric   // Methods to create a Type object, or return the right existing one from the
985480093f4SDimitry Andric   // maps stored in this object.
getVoidType()986480093f4SDimitry Andric   const VoidType *getVoidType() { return &Void; }
getScalarType(StringRef Name)987480093f4SDimitry Andric   const ScalarType *getScalarType(StringRef Name) {
9885ffd83dbSDimitry Andric     return ScalarTypes[std::string(Name)].get();
989480093f4SDimitry Andric   }
getScalarType(Record * R)990480093f4SDimitry Andric   const ScalarType *getScalarType(Record *R) {
991480093f4SDimitry Andric     return getScalarType(R->getName());
992480093f4SDimitry Andric   }
getVectorType(const ScalarType * ST,unsigned Lanes)993480093f4SDimitry Andric   const VectorType *getVectorType(const ScalarType *ST, unsigned Lanes) {
994480093f4SDimitry Andric     std::tuple<ScalarTypeKind, unsigned, unsigned> key(ST->kind(),
995480093f4SDimitry Andric                                                        ST->sizeInBits(), Lanes);
996480093f4SDimitry Andric     if (VectorTypes.find(key) == VectorTypes.end())
997480093f4SDimitry Andric       VectorTypes[key] = std::make_unique<VectorType>(ST, Lanes);
998480093f4SDimitry Andric     return VectorTypes[key].get();
999480093f4SDimitry Andric   }
getVectorType(const ScalarType * ST)1000480093f4SDimitry Andric   const VectorType *getVectorType(const ScalarType *ST) {
1001480093f4SDimitry Andric     return getVectorType(ST, 128 / ST->sizeInBits());
1002480093f4SDimitry Andric   }
getMultiVectorType(unsigned Registers,const VectorType * VT)1003480093f4SDimitry Andric   const MultiVectorType *getMultiVectorType(unsigned Registers,
1004480093f4SDimitry Andric                                             const VectorType *VT) {
1005480093f4SDimitry Andric     std::pair<std::string, unsigned> key(VT->cNameBase(), Registers);
1006480093f4SDimitry Andric     if (MultiVectorTypes.find(key) == MultiVectorTypes.end())
1007480093f4SDimitry Andric       MultiVectorTypes[key] = std::make_unique<MultiVectorType>(Registers, VT);
1008480093f4SDimitry Andric     return MultiVectorTypes[key].get();
1009480093f4SDimitry Andric   }
getPredicateType(unsigned Lanes)1010480093f4SDimitry Andric   const PredicateType *getPredicateType(unsigned Lanes) {
1011480093f4SDimitry Andric     unsigned key = Lanes;
1012480093f4SDimitry Andric     if (PredicateTypes.find(key) == PredicateTypes.end())
1013480093f4SDimitry Andric       PredicateTypes[key] = std::make_unique<PredicateType>(Lanes);
1014480093f4SDimitry Andric     return PredicateTypes[key].get();
1015480093f4SDimitry Andric   }
getPointerType(const Type * T,bool Const)1016480093f4SDimitry Andric   const PointerType *getPointerType(const Type *T, bool Const) {
1017480093f4SDimitry Andric     PointerType PT(T, Const);
1018480093f4SDimitry Andric     std::string key = PT.cName();
1019480093f4SDimitry Andric     if (PointerTypes.find(key) == PointerTypes.end())
1020480093f4SDimitry Andric       PointerTypes[key] = std::make_unique<PointerType>(PT);
1021480093f4SDimitry Andric     return PointerTypes[key].get();
1022480093f4SDimitry Andric   }
1023480093f4SDimitry Andric 
1024480093f4SDimitry Andric   // Methods to construct a type from various pieces of Tablegen. These are
1025480093f4SDimitry Andric   // always called in the context of setting up a particular ACLEIntrinsic, so
1026480093f4SDimitry Andric   // there's always an ambient parameter type (because we're iterating through
1027480093f4SDimitry Andric   // the Params list in the Tablegen record for the intrinsic), which is used
1028480093f4SDimitry Andric   // to expand Tablegen classes like 'Vector' which mean something different in
1029480093f4SDimitry Andric   // each member of a parametric family.
1030480093f4SDimitry Andric   const Type *getType(Record *R, const Type *Param);
1031480093f4SDimitry Andric   const Type *getType(DagInit *D, const Type *Param);
1032480093f4SDimitry Andric   const Type *getType(Init *I, const Type *Param);
1033480093f4SDimitry Andric 
1034480093f4SDimitry Andric   // Functions that translate the Tablegen representation of an intrinsic's
1035480093f4SDimitry Andric   // code generation into a collection of Value objects (which will then be
1036480093f4SDimitry Andric   // reprocessed to read out the actual C++ code included by CGBuiltin.cpp).
1037480093f4SDimitry Andric   Result::Ptr getCodeForDag(DagInit *D, const Result::Scope &Scope,
1038480093f4SDimitry Andric                             const Type *Param);
1039480093f4SDimitry Andric   Result::Ptr getCodeForDagArg(DagInit *D, unsigned ArgNum,
1040480093f4SDimitry Andric                                const Result::Scope &Scope, const Type *Param);
1041480093f4SDimitry Andric   Result::Ptr getCodeForArg(unsigned ArgNum, const Type *ArgType, bool Promote,
1042480093f4SDimitry Andric                             bool Immediate);
1043480093f4SDimitry Andric 
10445ffd83dbSDimitry Andric   void GroupSemaChecks(std::map<std::string, std::set<std::string>> &Checks);
10455ffd83dbSDimitry Andric 
1046480093f4SDimitry Andric   // Constructor and top-level functions.
1047480093f4SDimitry Andric 
10485ffd83dbSDimitry Andric   EmitterBase(RecordKeeper &Records);
10495ffd83dbSDimitry Andric   virtual ~EmitterBase() = default;
1050480093f4SDimitry Andric 
10515ffd83dbSDimitry Andric   virtual void EmitHeader(raw_ostream &OS) = 0;
10525ffd83dbSDimitry Andric   virtual void EmitBuiltinDef(raw_ostream &OS) = 0;
10535ffd83dbSDimitry Andric   virtual void EmitBuiltinSema(raw_ostream &OS) = 0;
1054480093f4SDimitry Andric   void EmitBuiltinCG(raw_ostream &OS);
1055480093f4SDimitry Andric   void EmitBuiltinAliases(raw_ostream &OS);
1056480093f4SDimitry Andric };
1057480093f4SDimitry Andric 
getType(Init * I,const Type * Param)10585ffd83dbSDimitry Andric const Type *EmitterBase::getType(Init *I, const Type *Param) {
1059480093f4SDimitry Andric   if (auto Dag = dyn_cast<DagInit>(I))
1060480093f4SDimitry Andric     return getType(Dag, Param);
1061480093f4SDimitry Andric   if (auto Def = dyn_cast<DefInit>(I))
1062480093f4SDimitry Andric     return getType(Def->getDef(), Param);
1063480093f4SDimitry Andric 
1064480093f4SDimitry Andric   PrintFatalError("Could not convert this value into a type");
1065480093f4SDimitry Andric }
1066480093f4SDimitry Andric 
getType(Record * R,const Type * Param)10675ffd83dbSDimitry Andric const Type *EmitterBase::getType(Record *R, const Type *Param) {
1068480093f4SDimitry Andric   // Pass to a subfield of any wrapper records. We don't expect more than one
1069480093f4SDimitry Andric   // of these: immediate operands are used as plain numbers rather than as
1070480093f4SDimitry Andric   // llvm::Value, so it's meaningless to promote their type anyway.
1071480093f4SDimitry Andric   if (R->isSubClassOf("Immediate"))
1072480093f4SDimitry Andric     R = R->getValueAsDef("type");
1073480093f4SDimitry Andric   else if (R->isSubClassOf("unpromoted"))
1074480093f4SDimitry Andric     R = R->getValueAsDef("underlying_type");
1075480093f4SDimitry Andric 
1076480093f4SDimitry Andric   if (R->getName() == "Void")
1077480093f4SDimitry Andric     return getVoidType();
1078480093f4SDimitry Andric   if (R->isSubClassOf("PrimitiveType"))
1079480093f4SDimitry Andric     return getScalarType(R);
1080480093f4SDimitry Andric   if (R->isSubClassOf("ComplexType"))
1081480093f4SDimitry Andric     return getType(R->getValueAsDag("spec"), Param);
1082480093f4SDimitry Andric 
1083480093f4SDimitry Andric   PrintFatalError(R->getLoc(), "Could not convert this record into a type");
1084480093f4SDimitry Andric }
1085480093f4SDimitry Andric 
getType(DagInit * D,const Type * Param)10865ffd83dbSDimitry Andric const Type *EmitterBase::getType(DagInit *D, const Type *Param) {
1087480093f4SDimitry Andric   // The meat of the getType system: types in the Tablegen are represented by a
1088480093f4SDimitry Andric   // dag whose operators select sub-cases of this function.
1089480093f4SDimitry Andric 
1090480093f4SDimitry Andric   Record *Op = cast<DefInit>(D->getOperator())->getDef();
1091480093f4SDimitry Andric   if (!Op->isSubClassOf("ComplexTypeOp"))
1092480093f4SDimitry Andric     PrintFatalError(
1093480093f4SDimitry Andric         "Expected ComplexTypeOp as dag operator in type expression");
1094480093f4SDimitry Andric 
1095480093f4SDimitry Andric   if (Op->getName() == "CTO_Parameter") {
1096480093f4SDimitry Andric     if (isa<VoidType>(Param))
1097480093f4SDimitry Andric       PrintFatalError("Parametric type in unparametrised context");
1098480093f4SDimitry Andric     return Param;
1099480093f4SDimitry Andric   }
1100480093f4SDimitry Andric 
1101480093f4SDimitry Andric   if (Op->getName() == "CTO_Vec") {
1102480093f4SDimitry Andric     const Type *Element = getType(D->getArg(0), Param);
1103480093f4SDimitry Andric     if (D->getNumArgs() == 1) {
1104480093f4SDimitry Andric       return getVectorType(cast<ScalarType>(Element));
1105480093f4SDimitry Andric     } else {
1106480093f4SDimitry Andric       const Type *ExistingVector = getType(D->getArg(1), Param);
1107480093f4SDimitry Andric       return getVectorType(cast<ScalarType>(Element),
1108480093f4SDimitry Andric                            cast<VectorType>(ExistingVector)->lanes());
1109480093f4SDimitry Andric     }
1110480093f4SDimitry Andric   }
1111480093f4SDimitry Andric 
1112480093f4SDimitry Andric   if (Op->getName() == "CTO_Pred") {
1113480093f4SDimitry Andric     const Type *Element = getType(D->getArg(0), Param);
1114480093f4SDimitry Andric     return getPredicateType(128 / Element->sizeInBits());
1115480093f4SDimitry Andric   }
1116480093f4SDimitry Andric 
1117480093f4SDimitry Andric   if (Op->isSubClassOf("CTO_Tuple")) {
1118480093f4SDimitry Andric     unsigned Registers = Op->getValueAsInt("n");
1119480093f4SDimitry Andric     const Type *Element = getType(D->getArg(0), Param);
1120480093f4SDimitry Andric     return getMultiVectorType(Registers, cast<VectorType>(Element));
1121480093f4SDimitry Andric   }
1122480093f4SDimitry Andric 
1123480093f4SDimitry Andric   if (Op->isSubClassOf("CTO_Pointer")) {
1124480093f4SDimitry Andric     const Type *Pointee = getType(D->getArg(0), Param);
1125480093f4SDimitry Andric     return getPointerType(Pointee, Op->getValueAsBit("const"));
1126480093f4SDimitry Andric   }
1127480093f4SDimitry Andric 
1128480093f4SDimitry Andric   if (Op->getName() == "CTO_CopyKind") {
1129480093f4SDimitry Andric     const ScalarType *STSize = cast<ScalarType>(getType(D->getArg(0), Param));
1130480093f4SDimitry Andric     const ScalarType *STKind = cast<ScalarType>(getType(D->getArg(1), Param));
1131480093f4SDimitry Andric     for (const auto &kv : ScalarTypes) {
1132480093f4SDimitry Andric       const ScalarType *RT = kv.second.get();
1133480093f4SDimitry Andric       if (RT->kind() == STKind->kind() && RT->sizeInBits() == STSize->sizeInBits())
1134480093f4SDimitry Andric         return RT;
1135480093f4SDimitry Andric     }
1136480093f4SDimitry Andric     PrintFatalError("Cannot find a type to satisfy CopyKind");
1137480093f4SDimitry Andric   }
1138480093f4SDimitry Andric 
1139480093f4SDimitry Andric   if (Op->isSubClassOf("CTO_ScaleSize")) {
1140480093f4SDimitry Andric     const ScalarType *STKind = cast<ScalarType>(getType(D->getArg(0), Param));
1141480093f4SDimitry Andric     int Num = Op->getValueAsInt("num"), Denom = Op->getValueAsInt("denom");
1142480093f4SDimitry Andric     unsigned DesiredSize = STKind->sizeInBits() * Num / Denom;
1143480093f4SDimitry Andric     for (const auto &kv : ScalarTypes) {
1144480093f4SDimitry Andric       const ScalarType *RT = kv.second.get();
1145480093f4SDimitry Andric       if (RT->kind() == STKind->kind() && RT->sizeInBits() == DesiredSize)
1146480093f4SDimitry Andric         return RT;
1147480093f4SDimitry Andric     }
1148480093f4SDimitry Andric     PrintFatalError("Cannot find a type to satisfy ScaleSize");
1149480093f4SDimitry Andric   }
1150480093f4SDimitry Andric 
1151480093f4SDimitry Andric   PrintFatalError("Bad operator in type dag expression");
1152480093f4SDimitry Andric }
1153480093f4SDimitry Andric 
getCodeForDag(DagInit * D,const Result::Scope & Scope,const Type * Param)11545ffd83dbSDimitry Andric Result::Ptr EmitterBase::getCodeForDag(DagInit *D, const Result::Scope &Scope,
1155480093f4SDimitry Andric                                        const Type *Param) {
1156480093f4SDimitry Andric   Record *Op = cast<DefInit>(D->getOperator())->getDef();
1157480093f4SDimitry Andric 
1158480093f4SDimitry Andric   if (Op->getName() == "seq") {
1159480093f4SDimitry Andric     Result::Scope SubScope = Scope;
1160480093f4SDimitry Andric     Result::Ptr PrevV = nullptr;
1161480093f4SDimitry Andric     for (unsigned i = 0, e = D->getNumArgs(); i < e; ++i) {
1162480093f4SDimitry Andric       // We don't use getCodeForDagArg here, because the argument name
1163480093f4SDimitry Andric       // has different semantics in a seq
1164480093f4SDimitry Andric       Result::Ptr V =
1165480093f4SDimitry Andric           getCodeForDag(cast<DagInit>(D->getArg(i)), SubScope, Param);
1166480093f4SDimitry Andric       StringRef ArgName = D->getArgNameStr(i);
1167480093f4SDimitry Andric       if (!ArgName.empty())
11685ffd83dbSDimitry Andric         SubScope[std::string(ArgName)] = V;
1169480093f4SDimitry Andric       if (PrevV)
1170480093f4SDimitry Andric         V->setPredecessor(PrevV);
1171480093f4SDimitry Andric       PrevV = V;
1172480093f4SDimitry Andric     }
1173480093f4SDimitry Andric     return PrevV;
1174480093f4SDimitry Andric   } else if (Op->isSubClassOf("Type")) {
1175480093f4SDimitry Andric     if (D->getNumArgs() != 1)
1176480093f4SDimitry Andric       PrintFatalError("Type casts should have exactly one argument");
1177480093f4SDimitry Andric     const Type *CastType = getType(Op, Param);
1178480093f4SDimitry Andric     Result::Ptr Arg = getCodeForDagArg(D, 0, Scope, Param);
1179480093f4SDimitry Andric     if (const auto *ST = dyn_cast<ScalarType>(CastType)) {
1180480093f4SDimitry Andric       if (!ST->requiresFloat()) {
1181480093f4SDimitry Andric         if (Arg->hasIntegerConstantValue())
1182480093f4SDimitry Andric           return std::make_shared<IntLiteralResult>(
1183480093f4SDimitry Andric               ST, Arg->integerConstantValue());
1184480093f4SDimitry Andric         else
1185480093f4SDimitry Andric           return std::make_shared<IntCastResult>(ST, Arg);
1186480093f4SDimitry Andric       }
1187480093f4SDimitry Andric     } else if (const auto *PT = dyn_cast<PointerType>(CastType)) {
1188480093f4SDimitry Andric       return std::make_shared<PointerCastResult>(PT, Arg);
1189480093f4SDimitry Andric     }
1190480093f4SDimitry Andric     PrintFatalError("Unsupported type cast");
1191480093f4SDimitry Andric   } else if (Op->getName() == "address") {
1192480093f4SDimitry Andric     if (D->getNumArgs() != 2)
1193480093f4SDimitry Andric       PrintFatalError("'address' should have two arguments");
1194480093f4SDimitry Andric     Result::Ptr Arg = getCodeForDagArg(D, 0, Scope, Param);
119581ad6265SDimitry Andric 
119681ad6265SDimitry Andric     const Type *Ty = nullptr;
119781ad6265SDimitry Andric     if (auto *DI = dyn_cast<DagInit>(D->getArg(0)))
119881ad6265SDimitry Andric       if (auto *PTy = dyn_cast<PointerType>(getType(DI->getOperator(), Param)))
119981ad6265SDimitry Andric         Ty = PTy->getPointeeType();
120081ad6265SDimitry Andric     if (!Ty)
120181ad6265SDimitry Andric       PrintFatalError("'address' pointer argument should be a pointer");
120281ad6265SDimitry Andric 
1203480093f4SDimitry Andric     unsigned Alignment;
1204480093f4SDimitry Andric     if (auto *II = dyn_cast<IntInit>(D->getArg(1))) {
1205480093f4SDimitry Andric       Alignment = II->getValue();
1206480093f4SDimitry Andric     } else {
1207480093f4SDimitry Andric       PrintFatalError("'address' alignment argument should be an integer");
1208480093f4SDimitry Andric     }
120981ad6265SDimitry Andric     return std::make_shared<AddressResult>(Arg, Ty, Alignment);
1210480093f4SDimitry Andric   } else if (Op->getName() == "unsignedflag") {
1211480093f4SDimitry Andric     if (D->getNumArgs() != 1)
1212480093f4SDimitry Andric       PrintFatalError("unsignedflag should have exactly one argument");
1213480093f4SDimitry Andric     Record *TypeRec = cast<DefInit>(D->getArg(0))->getDef();
1214480093f4SDimitry Andric     if (!TypeRec->isSubClassOf("Type"))
1215480093f4SDimitry Andric       PrintFatalError("unsignedflag's argument should be a type");
1216480093f4SDimitry Andric     if (const auto *ST = dyn_cast<ScalarType>(getType(TypeRec, Param))) {
1217480093f4SDimitry Andric       return std::make_shared<IntLiteralResult>(
1218480093f4SDimitry Andric         getScalarType("u32"), ST->kind() == ScalarTypeKind::UnsignedInt);
1219480093f4SDimitry Andric     } else {
1220480093f4SDimitry Andric       PrintFatalError("unsignedflag's argument should be a scalar type");
1221480093f4SDimitry Andric     }
12225ffd83dbSDimitry Andric   } else if (Op->getName() == "bitsize") {
12235ffd83dbSDimitry Andric     if (D->getNumArgs() != 1)
12245ffd83dbSDimitry Andric       PrintFatalError("bitsize should have exactly one argument");
12255ffd83dbSDimitry Andric     Record *TypeRec = cast<DefInit>(D->getArg(0))->getDef();
12265ffd83dbSDimitry Andric     if (!TypeRec->isSubClassOf("Type"))
12275ffd83dbSDimitry Andric       PrintFatalError("bitsize's argument should be a type");
12285ffd83dbSDimitry Andric     if (const auto *ST = dyn_cast<ScalarType>(getType(TypeRec, Param))) {
12295ffd83dbSDimitry Andric       return std::make_shared<IntLiteralResult>(getScalarType("u32"),
12305ffd83dbSDimitry Andric                                                 ST->sizeInBits());
12315ffd83dbSDimitry Andric     } else {
12325ffd83dbSDimitry Andric       PrintFatalError("bitsize's argument should be a scalar type");
12335ffd83dbSDimitry Andric     }
1234480093f4SDimitry Andric   } else {
1235480093f4SDimitry Andric     std::vector<Result::Ptr> Args;
1236480093f4SDimitry Andric     for (unsigned i = 0, e = D->getNumArgs(); i < e; ++i)
1237480093f4SDimitry Andric       Args.push_back(getCodeForDagArg(D, i, Scope, Param));
1238480093f4SDimitry Andric     if (Op->isSubClassOf("IRBuilderBase")) {
1239480093f4SDimitry Andric       std::set<unsigned> AddressArgs;
1240480093f4SDimitry Andric       std::map<unsigned, std::string> IntegerArgs;
1241480093f4SDimitry Andric       for (Record *sp : Op->getValueAsListOfDefs("special_params")) {
1242480093f4SDimitry Andric         unsigned Index = sp->getValueAsInt("index");
1243480093f4SDimitry Andric         if (sp->isSubClassOf("IRBuilderAddrParam")) {
1244480093f4SDimitry Andric           AddressArgs.insert(Index);
1245480093f4SDimitry Andric         } else if (sp->isSubClassOf("IRBuilderIntParam")) {
12465ffd83dbSDimitry Andric           IntegerArgs[Index] = std::string(sp->getValueAsString("type"));
1247480093f4SDimitry Andric         }
1248480093f4SDimitry Andric       }
1249480093f4SDimitry Andric       return std::make_shared<IRBuilderResult>(Op->getValueAsString("prefix"),
1250480093f4SDimitry Andric                                                Args, AddressArgs, IntegerArgs);
1251480093f4SDimitry Andric     } else if (Op->isSubClassOf("IRIntBase")) {
1252480093f4SDimitry Andric       std::vector<const Type *> ParamTypes;
1253480093f4SDimitry Andric       for (Record *RParam : Op->getValueAsListOfDefs("params"))
1254480093f4SDimitry Andric         ParamTypes.push_back(getType(RParam, Param));
12555ffd83dbSDimitry Andric       std::string IntName = std::string(Op->getValueAsString("intname"));
1256480093f4SDimitry Andric       if (Op->getValueAsBit("appendKind"))
1257480093f4SDimitry Andric         IntName += "_" + toLetter(cast<ScalarType>(Param)->kind());
1258480093f4SDimitry Andric       return std::make_shared<IRIntrinsicResult>(IntName, ParamTypes, Args);
1259480093f4SDimitry Andric     } else {
1260480093f4SDimitry Andric       PrintFatalError("Unsupported dag node " + Op->getName());
1261480093f4SDimitry Andric     }
1262480093f4SDimitry Andric   }
1263480093f4SDimitry Andric }
1264480093f4SDimitry Andric 
getCodeForDagArg(DagInit * D,unsigned ArgNum,const Result::Scope & Scope,const Type * Param)12655ffd83dbSDimitry Andric Result::Ptr EmitterBase::getCodeForDagArg(DagInit *D, unsigned ArgNum,
1266480093f4SDimitry Andric                                           const Result::Scope &Scope,
1267480093f4SDimitry Andric                                           const Type *Param) {
1268480093f4SDimitry Andric   Init *Arg = D->getArg(ArgNum);
1269480093f4SDimitry Andric   StringRef Name = D->getArgNameStr(ArgNum);
1270480093f4SDimitry Andric 
1271480093f4SDimitry Andric   if (!Name.empty()) {
1272480093f4SDimitry Andric     if (!isa<UnsetInit>(Arg))
1273480093f4SDimitry Andric       PrintFatalError(
1274480093f4SDimitry Andric           "dag operator argument should not have both a value and a name");
12755ffd83dbSDimitry Andric     auto it = Scope.find(std::string(Name));
1276480093f4SDimitry Andric     if (it == Scope.end())
1277480093f4SDimitry Andric       PrintFatalError("unrecognized variable name '" + Name + "'");
1278480093f4SDimitry Andric     return it->second;
1279480093f4SDimitry Andric   }
1280480093f4SDimitry Andric 
1281fe6060f1SDimitry Andric   // Sometimes the Arg is a bit. Prior to multiclass template argument
1282fe6060f1SDimitry Andric   // checking, integers would sneak through the bit declaration,
1283fe6060f1SDimitry Andric   // but now they really are bits.
1284fe6060f1SDimitry Andric   if (auto *BI = dyn_cast<BitInit>(Arg))
1285fe6060f1SDimitry Andric     return std::make_shared<IntLiteralResult>(getScalarType("u32"),
1286fe6060f1SDimitry Andric                                               BI->getValue());
1287fe6060f1SDimitry Andric 
1288480093f4SDimitry Andric   if (auto *II = dyn_cast<IntInit>(Arg))
1289480093f4SDimitry Andric     return std::make_shared<IntLiteralResult>(getScalarType("u32"),
1290480093f4SDimitry Andric                                               II->getValue());
1291480093f4SDimitry Andric 
1292480093f4SDimitry Andric   if (auto *DI = dyn_cast<DagInit>(Arg))
1293480093f4SDimitry Andric     return getCodeForDag(DI, Scope, Param);
1294480093f4SDimitry Andric 
1295480093f4SDimitry Andric   if (auto *DI = dyn_cast<DefInit>(Arg)) {
1296480093f4SDimitry Andric     Record *Rec = DI->getDef();
1297480093f4SDimitry Andric     if (Rec->isSubClassOf("Type")) {
1298480093f4SDimitry Andric       const Type *T = getType(Rec, Param);
1299480093f4SDimitry Andric       return std::make_shared<TypeResult>(T);
1300480093f4SDimitry Andric     }
1301480093f4SDimitry Andric   }
1302480093f4SDimitry Andric 
1303fe6060f1SDimitry Andric   PrintError("bad DAG argument type for code generation");
1304fe6060f1SDimitry Andric   PrintNote("DAG: " + D->getAsString());
1305fe6060f1SDimitry Andric   if (TypedInit *Typed = dyn_cast<TypedInit>(Arg))
1306fe6060f1SDimitry Andric     PrintNote("argument type: " + Typed->getType()->getAsString());
1307fe6060f1SDimitry Andric   PrintFatalNote("argument number " + Twine(ArgNum) + ": " + Arg->getAsString());
1308480093f4SDimitry Andric }
1309480093f4SDimitry Andric 
getCodeForArg(unsigned ArgNum,const Type * ArgType,bool Promote,bool Immediate)13105ffd83dbSDimitry Andric Result::Ptr EmitterBase::getCodeForArg(unsigned ArgNum, const Type *ArgType,
1311480093f4SDimitry Andric                                        bool Promote, bool Immediate) {
1312480093f4SDimitry Andric   Result::Ptr V = std::make_shared<BuiltinArgResult>(
1313480093f4SDimitry Andric       ArgNum, isa<PointerType>(ArgType), Immediate);
1314480093f4SDimitry Andric 
1315480093f4SDimitry Andric   if (Promote) {
1316480093f4SDimitry Andric     if (const auto *ST = dyn_cast<ScalarType>(ArgType)) {
1317480093f4SDimitry Andric       if (ST->isInteger() && ST->sizeInBits() < 32)
1318480093f4SDimitry Andric         V = std::make_shared<IntCastResult>(getScalarType("u32"), V);
1319480093f4SDimitry Andric     } else if (const auto *PT = dyn_cast<PredicateType>(ArgType)) {
1320480093f4SDimitry Andric       V = std::make_shared<IntCastResult>(getScalarType("u32"), V);
1321480093f4SDimitry Andric       V = std::make_shared<IRIntrinsicResult>("arm_mve_pred_i2v",
1322480093f4SDimitry Andric                                               std::vector<const Type *>{PT},
1323480093f4SDimitry Andric                                               std::vector<Result::Ptr>{V});
1324480093f4SDimitry Andric     }
1325480093f4SDimitry Andric   }
1326480093f4SDimitry Andric 
1327480093f4SDimitry Andric   return V;
1328480093f4SDimitry Andric }
1329480093f4SDimitry Andric 
ACLEIntrinsic(EmitterBase & ME,Record * R,const Type * Param)13305ffd83dbSDimitry Andric ACLEIntrinsic::ACLEIntrinsic(EmitterBase &ME, Record *R, const Type *Param)
1331480093f4SDimitry Andric     : ReturnType(ME.getType(R->getValueAsDef("ret"), Param)) {
1332480093f4SDimitry Andric   // Derive the intrinsic's full name, by taking the name of the
1333480093f4SDimitry Andric   // Tablegen record (or override) and appending the suffix from its
1334480093f4SDimitry Andric   // parameter type. (If the intrinsic is unparametrised, its
1335480093f4SDimitry Andric   // parameter type will be given as Void, which returns the empty
1336480093f4SDimitry Andric   // string for acleSuffix.)
1337480093f4SDimitry Andric   StringRef BaseName =
1338480093f4SDimitry Andric       (R->isSubClassOf("NameOverride") ? R->getValueAsString("basename")
1339480093f4SDimitry Andric                                        : R->getName());
1340480093f4SDimitry Andric   StringRef overrideLetter = R->getValueAsString("overrideKindLetter");
13415ffd83dbSDimitry Andric   FullName =
13425ffd83dbSDimitry Andric       (Twine(BaseName) + Param->acleSuffix(std::string(overrideLetter))).str();
1343480093f4SDimitry Andric 
1344480093f4SDimitry Andric   // Derive the intrinsic's polymorphic name, by removing components from the
1345480093f4SDimitry Andric   // full name as specified by its 'pnt' member ('polymorphic name type'),
1346480093f4SDimitry Andric   // which indicates how many type suffixes to remove, and any other piece of
1347480093f4SDimitry Andric   // the name that should be removed.
1348480093f4SDimitry Andric   Record *PolymorphicNameType = R->getValueAsDef("pnt");
1349480093f4SDimitry Andric   SmallVector<StringRef, 8> NameParts;
1350480093f4SDimitry Andric   StringRef(FullName).split(NameParts, '_');
1351480093f4SDimitry Andric   for (unsigned i = 0, e = PolymorphicNameType->getValueAsInt(
1352480093f4SDimitry Andric                            "NumTypeSuffixesToDiscard");
1353480093f4SDimitry Andric        i < e; ++i)
1354480093f4SDimitry Andric     NameParts.pop_back();
1355480093f4SDimitry Andric   if (!PolymorphicNameType->isValueUnset("ExtraSuffixToDiscard")) {
1356480093f4SDimitry Andric     StringRef ExtraSuffix =
1357480093f4SDimitry Andric         PolymorphicNameType->getValueAsString("ExtraSuffixToDiscard");
1358480093f4SDimitry Andric     auto it = NameParts.end();
1359480093f4SDimitry Andric     while (it != NameParts.begin()) {
1360480093f4SDimitry Andric       --it;
1361480093f4SDimitry Andric       if (*it == ExtraSuffix) {
1362480093f4SDimitry Andric         NameParts.erase(it);
1363480093f4SDimitry Andric         break;
1364480093f4SDimitry Andric       }
1365480093f4SDimitry Andric     }
1366480093f4SDimitry Andric   }
1367480093f4SDimitry Andric   ShortName = join(std::begin(NameParts), std::end(NameParts), "_");
1368480093f4SDimitry Andric 
13695ffd83dbSDimitry Andric   BuiltinExtension = R->getValueAsString("builtinExtension");
13705ffd83dbSDimitry Andric 
1371480093f4SDimitry Andric   PolymorphicOnly = R->getValueAsBit("polymorphicOnly");
1372480093f4SDimitry Andric   NonEvaluating = R->getValueAsBit("nonEvaluating");
13735ffd83dbSDimitry Andric   HeaderOnly = R->getValueAsBit("headerOnly");
1374480093f4SDimitry Andric 
1375480093f4SDimitry Andric   // Process the intrinsic's argument list.
1376480093f4SDimitry Andric   DagInit *ArgsDag = R->getValueAsDag("args");
1377480093f4SDimitry Andric   Result::Scope Scope;
1378480093f4SDimitry Andric   for (unsigned i = 0, e = ArgsDag->getNumArgs(); i < e; ++i) {
1379480093f4SDimitry Andric     Init *TypeInit = ArgsDag->getArg(i);
1380480093f4SDimitry Andric 
1381480093f4SDimitry Andric     bool Promote = true;
1382480093f4SDimitry Andric     if (auto TypeDI = dyn_cast<DefInit>(TypeInit))
1383480093f4SDimitry Andric       if (TypeDI->getDef()->isSubClassOf("unpromoted"))
1384480093f4SDimitry Andric         Promote = false;
1385480093f4SDimitry Andric 
1386480093f4SDimitry Andric     // Work out the type of the argument, for use in the function prototype in
1387480093f4SDimitry Andric     // the header file.
1388480093f4SDimitry Andric     const Type *ArgType = ME.getType(TypeInit, Param);
1389480093f4SDimitry Andric     ArgTypes.push_back(ArgType);
1390480093f4SDimitry Andric 
1391480093f4SDimitry Andric     // If the argument is a subclass of Immediate, record the details about
1392480093f4SDimitry Andric     // what values it can take, for Sema checking.
1393480093f4SDimitry Andric     bool Immediate = false;
1394480093f4SDimitry Andric     if (auto TypeDI = dyn_cast<DefInit>(TypeInit)) {
1395480093f4SDimitry Andric       Record *TypeRec = TypeDI->getDef();
1396480093f4SDimitry Andric       if (TypeRec->isSubClassOf("Immediate")) {
1397480093f4SDimitry Andric         Immediate = true;
1398480093f4SDimitry Andric 
1399480093f4SDimitry Andric         Record *Bounds = TypeRec->getValueAsDef("bounds");
1400480093f4SDimitry Andric         ImmediateArg &IA = ImmediateArgs[i];
1401480093f4SDimitry Andric         if (Bounds->isSubClassOf("IB_ConstRange")) {
1402480093f4SDimitry Andric           IA.boundsType = ImmediateArg::BoundsType::ExplicitRange;
1403480093f4SDimitry Andric           IA.i1 = Bounds->getValueAsInt("lo");
1404480093f4SDimitry Andric           IA.i2 = Bounds->getValueAsInt("hi");
1405480093f4SDimitry Andric         } else if (Bounds->getName() == "IB_UEltValue") {
1406480093f4SDimitry Andric           IA.boundsType = ImmediateArg::BoundsType::UInt;
1407480093f4SDimitry Andric           IA.i1 = Param->sizeInBits();
1408480093f4SDimitry Andric         } else if (Bounds->getName() == "IB_LaneIndex") {
1409480093f4SDimitry Andric           IA.boundsType = ImmediateArg::BoundsType::ExplicitRange;
1410480093f4SDimitry Andric           IA.i1 = 0;
1411480093f4SDimitry Andric           IA.i2 = 128 / Param->sizeInBits() - 1;
1412480093f4SDimitry Andric         } else if (Bounds->isSubClassOf("IB_EltBit")) {
1413480093f4SDimitry Andric           IA.boundsType = ImmediateArg::BoundsType::ExplicitRange;
1414480093f4SDimitry Andric           IA.i1 = Bounds->getValueAsInt("base");
1415480093f4SDimitry Andric           const Type *T = ME.getType(Bounds->getValueAsDef("type"), Param);
1416480093f4SDimitry Andric           IA.i2 = IA.i1 + T->sizeInBits() - 1;
1417480093f4SDimitry Andric         } else {
1418480093f4SDimitry Andric           PrintFatalError("unrecognised ImmediateBounds subclass");
1419480093f4SDimitry Andric         }
1420480093f4SDimitry Andric 
1421480093f4SDimitry Andric         IA.ArgType = ArgType;
1422480093f4SDimitry Andric 
1423480093f4SDimitry Andric         if (!TypeRec->isValueUnset("extra")) {
1424480093f4SDimitry Andric           IA.ExtraCheckType = TypeRec->getValueAsString("extra");
1425480093f4SDimitry Andric           if (!TypeRec->isValueUnset("extraarg"))
1426480093f4SDimitry Andric             IA.ExtraCheckArgs = TypeRec->getValueAsString("extraarg");
1427480093f4SDimitry Andric         }
1428480093f4SDimitry Andric       }
1429480093f4SDimitry Andric     }
1430480093f4SDimitry Andric 
1431480093f4SDimitry Andric     // The argument will usually have a name in the arguments dag, which goes
1432480093f4SDimitry Andric     // into the variable-name scope that the code gen will refer to.
1433480093f4SDimitry Andric     StringRef ArgName = ArgsDag->getArgNameStr(i);
1434480093f4SDimitry Andric     if (!ArgName.empty())
14355ffd83dbSDimitry Andric       Scope[std::string(ArgName)] =
14365ffd83dbSDimitry Andric           ME.getCodeForArg(i, ArgType, Promote, Immediate);
1437480093f4SDimitry Andric   }
1438480093f4SDimitry Andric 
1439480093f4SDimitry Andric   // Finally, go through the codegen dag and translate it into a Result object
1440480093f4SDimitry Andric   // (with an arbitrary DAG of depended-on Results hanging off it).
1441480093f4SDimitry Andric   DagInit *CodeDag = R->getValueAsDag("codegen");
1442480093f4SDimitry Andric   Record *MainOp = cast<DefInit>(CodeDag->getOperator())->getDef();
1443480093f4SDimitry Andric   if (MainOp->isSubClassOf("CustomCodegen")) {
1444480093f4SDimitry Andric     // Or, if it's the special case of CustomCodegen, just accumulate
1445480093f4SDimitry Andric     // a list of parameters we're going to assign to variables before
1446480093f4SDimitry Andric     // breaking from the loop.
1447480093f4SDimitry Andric     CustomCodeGenArgs["CustomCodeGenType"] =
1448480093f4SDimitry Andric         (Twine("CustomCodeGen::") + MainOp->getValueAsString("type")).str();
1449480093f4SDimitry Andric     for (unsigned i = 0, e = CodeDag->getNumArgs(); i < e; ++i) {
1450480093f4SDimitry Andric       StringRef Name = CodeDag->getArgNameStr(i);
1451480093f4SDimitry Andric       if (Name.empty()) {
1452480093f4SDimitry Andric         PrintFatalError("Operands to CustomCodegen should have names");
1453480093f4SDimitry Andric       } else if (auto *II = dyn_cast<IntInit>(CodeDag->getArg(i))) {
14545ffd83dbSDimitry Andric         CustomCodeGenArgs[std::string(Name)] = itostr(II->getValue());
1455480093f4SDimitry Andric       } else if (auto *SI = dyn_cast<StringInit>(CodeDag->getArg(i))) {
14565ffd83dbSDimitry Andric         CustomCodeGenArgs[std::string(Name)] = std::string(SI->getValue());
1457480093f4SDimitry Andric       } else {
1458480093f4SDimitry Andric         PrintFatalError("Operands to CustomCodegen should be integers");
1459480093f4SDimitry Andric       }
1460480093f4SDimitry Andric     }
1461480093f4SDimitry Andric   } else {
1462480093f4SDimitry Andric     Code = ME.getCodeForDag(CodeDag, Scope, Param);
1463480093f4SDimitry Andric   }
1464480093f4SDimitry Andric }
1465480093f4SDimitry Andric 
EmitterBase(RecordKeeper & Records)14665ffd83dbSDimitry Andric EmitterBase::EmitterBase(RecordKeeper &Records) {
14675ffd83dbSDimitry Andric   // Construct the whole EmitterBase.
1468480093f4SDimitry Andric 
1469480093f4SDimitry Andric   // First, look up all the instances of PrimitiveType. This gives us the list
1470480093f4SDimitry Andric   // of vector typedefs we have to put in arm_mve.h, and also allows us to
1471480093f4SDimitry Andric   // collect all the useful ScalarType instances into a big list so that we can
1472480093f4SDimitry Andric   // use it for operations such as 'find the unsigned version of this signed
1473480093f4SDimitry Andric   // integer type'.
1474480093f4SDimitry Andric   for (Record *R : Records.getAllDerivedDefinitions("PrimitiveType"))
14755ffd83dbSDimitry Andric     ScalarTypes[std::string(R->getName())] = std::make_unique<ScalarType>(R);
1476480093f4SDimitry Andric 
1477480093f4SDimitry Andric   // Now go through the instances of Intrinsic, and for each one, iterate
1478480093f4SDimitry Andric   // through its list of type parameters making an ACLEIntrinsic for each one.
1479480093f4SDimitry Andric   for (Record *R : Records.getAllDerivedDefinitions("Intrinsic")) {
1480480093f4SDimitry Andric     for (Record *RParam : R->getValueAsListOfDefs("params")) {
1481480093f4SDimitry Andric       const Type *Param = getType(RParam, getVoidType());
1482480093f4SDimitry Andric       auto Intrinsic = std::make_unique<ACLEIntrinsic>(*this, R, Param);
1483480093f4SDimitry Andric       ACLEIntrinsics[Intrinsic->fullName()] = std::move(Intrinsic);
1484480093f4SDimitry Andric     }
1485480093f4SDimitry Andric   }
1486480093f4SDimitry Andric }
1487480093f4SDimitry Andric 
1488480093f4SDimitry Andric /// A wrapper on raw_string_ostream that contains its own buffer rather than
1489480093f4SDimitry Andric /// having to point it at one elsewhere. (In other words, it works just like
1490480093f4SDimitry Andric /// std::ostringstream; also, this makes it convenient to declare a whole array
1491480093f4SDimitry Andric /// of them at once.)
1492480093f4SDimitry Andric ///
1493480093f4SDimitry Andric /// We have to set this up using multiple inheritance, to ensure that the
1494480093f4SDimitry Andric /// string member has been constructed before raw_string_ostream's constructor
1495480093f4SDimitry Andric /// is given a pointer to it.
1496480093f4SDimitry Andric class string_holder {
1497480093f4SDimitry Andric protected:
1498480093f4SDimitry Andric   std::string S;
1499480093f4SDimitry Andric };
1500480093f4SDimitry Andric class raw_self_contained_string_ostream : private string_holder,
1501480093f4SDimitry Andric                                           public raw_string_ostream {
1502480093f4SDimitry Andric public:
raw_self_contained_string_ostream()150304eeddc0SDimitry Andric   raw_self_contained_string_ostream() : raw_string_ostream(S) {}
1504480093f4SDimitry Andric };
1505480093f4SDimitry Andric 
15065ffd83dbSDimitry Andric const char LLVMLicenseHeader[] =
1507480093f4SDimitry Andric     " *\n"
1508480093f4SDimitry Andric     " *\n"
1509480093f4SDimitry Andric     " * Part of the LLVM Project, under the Apache License v2.0 with LLVM"
1510480093f4SDimitry Andric     " Exceptions.\n"
1511480093f4SDimitry Andric     " * See https://llvm.org/LICENSE.txt for license information.\n"
1512480093f4SDimitry Andric     " * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception\n"
1513480093f4SDimitry Andric     " *\n"
15145ffd83dbSDimitry Andric     " *===-----------------------------------------------------------------"
1515480093f4SDimitry Andric     "------===\n"
1516480093f4SDimitry Andric     " */\n"
1517480093f4SDimitry Andric     "\n";
1518480093f4SDimitry Andric 
1519480093f4SDimitry Andric // Machinery for the grouping of intrinsics by similar codegen.
1520480093f4SDimitry Andric //
1521480093f4SDimitry Andric // The general setup is that 'MergeableGroup' stores the things that a set of
1522480093f4SDimitry Andric // similarly shaped intrinsics have in common: the text of their code
1523480093f4SDimitry Andric // generation, and the number and type of their parameter variables.
1524480093f4SDimitry Andric // MergeableGroup is the key in a std::map whose value is a set of
1525480093f4SDimitry Andric // OutputIntrinsic, which stores the ways in which a particular intrinsic
1526480093f4SDimitry Andric // specializes the MergeableGroup's generic description: the function name and
1527480093f4SDimitry Andric // the _values_ of the parameter variables.
1528480093f4SDimitry Andric 
1529480093f4SDimitry Andric struct ComparableStringVector : std::vector<std::string> {
1530480093f4SDimitry Andric   // Infrastructure: a derived class of vector<string> which comes with an
1531480093f4SDimitry Andric   // ordering, so that it can be used as a key in maps and an element in sets.
1532480093f4SDimitry Andric   // There's no requirement on the ordering beyond being deterministic.
operator <__anonc95a670f0111::ComparableStringVector1533480093f4SDimitry Andric   bool operator<(const ComparableStringVector &rhs) const {
1534480093f4SDimitry Andric     if (size() != rhs.size())
1535480093f4SDimitry Andric       return size() < rhs.size();
1536480093f4SDimitry Andric     for (size_t i = 0, e = size(); i < e; ++i)
1537480093f4SDimitry Andric       if ((*this)[i] != rhs[i])
1538480093f4SDimitry Andric         return (*this)[i] < rhs[i];
1539480093f4SDimitry Andric     return false;
1540480093f4SDimitry Andric   }
1541480093f4SDimitry Andric };
1542480093f4SDimitry Andric 
1543480093f4SDimitry Andric struct OutputIntrinsic {
1544480093f4SDimitry Andric   const ACLEIntrinsic *Int;
1545480093f4SDimitry Andric   std::string Name;
1546480093f4SDimitry Andric   ComparableStringVector ParamValues;
operator <__anonc95a670f0111::OutputIntrinsic1547480093f4SDimitry Andric   bool operator<(const OutputIntrinsic &rhs) const {
1548480093f4SDimitry Andric     if (Name != rhs.Name)
1549480093f4SDimitry Andric       return Name < rhs.Name;
1550480093f4SDimitry Andric     return ParamValues < rhs.ParamValues;
1551480093f4SDimitry Andric   }
1552480093f4SDimitry Andric };
1553480093f4SDimitry Andric struct MergeableGroup {
1554480093f4SDimitry Andric   std::string Code;
1555480093f4SDimitry Andric   ComparableStringVector ParamTypes;
operator <__anonc95a670f0111::MergeableGroup1556480093f4SDimitry Andric   bool operator<(const MergeableGroup &rhs) const {
1557480093f4SDimitry Andric     if (Code != rhs.Code)
1558480093f4SDimitry Andric       return Code < rhs.Code;
1559480093f4SDimitry Andric     return ParamTypes < rhs.ParamTypes;
1560480093f4SDimitry Andric   }
1561480093f4SDimitry Andric };
1562480093f4SDimitry Andric 
EmitBuiltinCG(raw_ostream & OS)15635ffd83dbSDimitry Andric void EmitterBase::EmitBuiltinCG(raw_ostream &OS) {
1564480093f4SDimitry Andric   // Pass 1: generate code for all the intrinsics as if every type or constant
1565480093f4SDimitry Andric   // that can possibly be abstracted out into a parameter variable will be.
1566480093f4SDimitry Andric   // This identifies the sets of intrinsics we'll group together into a single
1567480093f4SDimitry Andric   // piece of code generation.
1568480093f4SDimitry Andric 
1569480093f4SDimitry Andric   std::map<MergeableGroup, std::set<OutputIntrinsic>> MergeableGroupsPrelim;
1570480093f4SDimitry Andric 
1571480093f4SDimitry Andric   for (const auto &kv : ACLEIntrinsics) {
1572480093f4SDimitry Andric     const ACLEIntrinsic &Int = *kv.second;
15735ffd83dbSDimitry Andric     if (Int.headerOnly())
15745ffd83dbSDimitry Andric       continue;
1575480093f4SDimitry Andric 
1576480093f4SDimitry Andric     MergeableGroup MG;
1577480093f4SDimitry Andric     OutputIntrinsic OI;
1578480093f4SDimitry Andric 
1579480093f4SDimitry Andric     OI.Int = &Int;
1580480093f4SDimitry Andric     OI.Name = Int.fullName();
1581480093f4SDimitry Andric     CodeGenParamAllocator ParamAllocPrelim{&MG.ParamTypes, &OI.ParamValues};
1582480093f4SDimitry Andric     raw_string_ostream OS(MG.Code);
1583480093f4SDimitry Andric     Int.genCode(OS, ParamAllocPrelim, 1);
1584480093f4SDimitry Andric     OS.flush();
1585480093f4SDimitry Andric 
1586480093f4SDimitry Andric     MergeableGroupsPrelim[MG].insert(OI);
1587480093f4SDimitry Andric   }
1588480093f4SDimitry Andric 
1589480093f4SDimitry Andric   // Pass 2: for each of those groups, optimize the parameter variable set by
1590480093f4SDimitry Andric   // eliminating 'parameters' that are the same for all intrinsics in the
1591480093f4SDimitry Andric   // group, and merging together pairs of parameter variables that take the
1592480093f4SDimitry Andric   // same values as each other for all intrinsics in the group.
1593480093f4SDimitry Andric 
1594480093f4SDimitry Andric   std::map<MergeableGroup, std::set<OutputIntrinsic>> MergeableGroups;
1595480093f4SDimitry Andric 
1596480093f4SDimitry Andric   for (const auto &kv : MergeableGroupsPrelim) {
1597480093f4SDimitry Andric     const MergeableGroup &MG = kv.first;
1598480093f4SDimitry Andric     std::vector<int> ParamNumbers;
1599480093f4SDimitry Andric     std::map<ComparableStringVector, int> ParamNumberMap;
1600480093f4SDimitry Andric 
1601480093f4SDimitry Andric     // Loop over the parameters for this group.
1602480093f4SDimitry Andric     for (size_t i = 0, e = MG.ParamTypes.size(); i < e; ++i) {
1603480093f4SDimitry Andric       // Is this parameter the same for all intrinsics in the group?
1604480093f4SDimitry Andric       const OutputIntrinsic &OI_first = *kv.second.begin();
1605480093f4SDimitry Andric       bool Constant = all_of(kv.second, [&](const OutputIntrinsic &OI) {
1606480093f4SDimitry Andric         return OI.ParamValues[i] == OI_first.ParamValues[i];
1607480093f4SDimitry Andric       });
1608480093f4SDimitry Andric 
1609480093f4SDimitry Andric       // If so, record it as -1, meaning 'no parameter variable needed'. Then
1610480093f4SDimitry Andric       // the corresponding call to allocParam in pass 2 will not generate a
1611480093f4SDimitry Andric       // variable at all, and just use the value inline.
1612480093f4SDimitry Andric       if (Constant) {
1613480093f4SDimitry Andric         ParamNumbers.push_back(-1);
1614480093f4SDimitry Andric         continue;
1615480093f4SDimitry Andric       }
1616480093f4SDimitry Andric 
1617480093f4SDimitry Andric       // Otherwise, make a list of the values this parameter takes for each
1618480093f4SDimitry Andric       // intrinsic, and see if that value vector matches anything we already
1619480093f4SDimitry Andric       // have. We also record the parameter type, so that we don't accidentally
1620480093f4SDimitry Andric       // match up two parameter variables with different types. (Not that
1621480093f4SDimitry Andric       // there's much chance of them having textually equivalent values, but in
1622480093f4SDimitry Andric       // _principle_ it could happen.)
1623480093f4SDimitry Andric       ComparableStringVector key;
1624480093f4SDimitry Andric       key.push_back(MG.ParamTypes[i]);
1625480093f4SDimitry Andric       for (const auto &OI : kv.second)
1626480093f4SDimitry Andric         key.push_back(OI.ParamValues[i]);
1627480093f4SDimitry Andric 
1628480093f4SDimitry Andric       auto Found = ParamNumberMap.find(key);
1629480093f4SDimitry Andric       if (Found != ParamNumberMap.end()) {
1630480093f4SDimitry Andric         // Yes, an existing parameter variable can be reused for this.
1631480093f4SDimitry Andric         ParamNumbers.push_back(Found->second);
1632480093f4SDimitry Andric         continue;
1633480093f4SDimitry Andric       }
1634480093f4SDimitry Andric 
1635480093f4SDimitry Andric       // No, we need a new parameter variable.
1636480093f4SDimitry Andric       int ExistingIndex = ParamNumberMap.size();
1637480093f4SDimitry Andric       ParamNumberMap[key] = ExistingIndex;
1638480093f4SDimitry Andric       ParamNumbers.push_back(ExistingIndex);
1639480093f4SDimitry Andric     }
1640480093f4SDimitry Andric 
1641480093f4SDimitry Andric     // Now we're ready to do the pass 2 code generation, which will emit the
1642480093f4SDimitry Andric     // reduced set of parameter variables we've just worked out.
1643480093f4SDimitry Andric 
1644480093f4SDimitry Andric     for (const auto &OI_prelim : kv.second) {
1645480093f4SDimitry Andric       const ACLEIntrinsic *Int = OI_prelim.Int;
1646480093f4SDimitry Andric 
1647480093f4SDimitry Andric       MergeableGroup MG;
1648480093f4SDimitry Andric       OutputIntrinsic OI;
1649480093f4SDimitry Andric 
1650480093f4SDimitry Andric       OI.Int = OI_prelim.Int;
1651480093f4SDimitry Andric       OI.Name = OI_prelim.Name;
1652480093f4SDimitry Andric       CodeGenParamAllocator ParamAlloc{&MG.ParamTypes, &OI.ParamValues,
1653480093f4SDimitry Andric                                        &ParamNumbers};
1654480093f4SDimitry Andric       raw_string_ostream OS(MG.Code);
1655480093f4SDimitry Andric       Int->genCode(OS, ParamAlloc, 2);
1656480093f4SDimitry Andric       OS.flush();
1657480093f4SDimitry Andric 
1658480093f4SDimitry Andric       MergeableGroups[MG].insert(OI);
1659480093f4SDimitry Andric     }
1660480093f4SDimitry Andric   }
1661480093f4SDimitry Andric 
1662480093f4SDimitry Andric   // Output the actual C++ code.
1663480093f4SDimitry Andric 
1664480093f4SDimitry Andric   for (const auto &kv : MergeableGroups) {
1665480093f4SDimitry Andric     const MergeableGroup &MG = kv.first;
1666480093f4SDimitry Andric 
1667480093f4SDimitry Andric     // List of case statements in the main switch on BuiltinID, and an open
1668480093f4SDimitry Andric     // brace.
1669480093f4SDimitry Andric     const char *prefix = "";
1670480093f4SDimitry Andric     for (const auto &OI : kv.second) {
16715ffd83dbSDimitry Andric       OS << prefix << "case ARM::BI__builtin_arm_" << OI.Int->builtinExtension()
16725ffd83dbSDimitry Andric          << "_" << OI.Name << ":";
16735ffd83dbSDimitry Andric 
1674480093f4SDimitry Andric       prefix = "\n";
1675480093f4SDimitry Andric     }
1676480093f4SDimitry Andric     OS << " {\n";
1677480093f4SDimitry Andric 
1678480093f4SDimitry Andric     if (!MG.ParamTypes.empty()) {
1679480093f4SDimitry Andric       // If we've got some parameter variables, then emit their declarations...
1680480093f4SDimitry Andric       for (size_t i = 0, e = MG.ParamTypes.size(); i < e; ++i) {
1681480093f4SDimitry Andric         StringRef Type = MG.ParamTypes[i];
1682480093f4SDimitry Andric         OS << "  " << Type;
16835f757f3fSDimitry Andric         if (!Type.ends_with("*"))
1684480093f4SDimitry Andric           OS << " ";
1685480093f4SDimitry Andric         OS << " Param" << utostr(i) << ";\n";
1686480093f4SDimitry Andric       }
1687480093f4SDimitry Andric 
1688480093f4SDimitry Andric       // ... and an inner switch on BuiltinID that will fill them in with each
1689480093f4SDimitry Andric       // individual intrinsic's values.
1690480093f4SDimitry Andric       OS << "  switch (BuiltinID) {\n";
1691480093f4SDimitry Andric       for (const auto &OI : kv.second) {
16925ffd83dbSDimitry Andric         OS << "  case ARM::BI__builtin_arm_" << OI.Int->builtinExtension()
16935ffd83dbSDimitry Andric            << "_" << OI.Name << ":\n";
1694480093f4SDimitry Andric         for (size_t i = 0, e = MG.ParamTypes.size(); i < e; ++i)
1695480093f4SDimitry Andric           OS << "    Param" << utostr(i) << " = " << OI.ParamValues[i] << ";\n";
1696480093f4SDimitry Andric         OS << "    break;\n";
1697480093f4SDimitry Andric       }
1698480093f4SDimitry Andric       OS << "  }\n";
1699480093f4SDimitry Andric     }
1700480093f4SDimitry Andric 
1701480093f4SDimitry Andric     // And finally, output the code, and close the outer pair of braces. (The
1702480093f4SDimitry Andric     // code will always end with a 'return' statement, so we need not insert a
1703480093f4SDimitry Andric     // 'break' here.)
1704480093f4SDimitry Andric     OS << MG.Code << "}\n";
1705480093f4SDimitry Andric   }
1706480093f4SDimitry Andric }
1707480093f4SDimitry Andric 
EmitBuiltinAliases(raw_ostream & OS)17085ffd83dbSDimitry Andric void EmitterBase::EmitBuiltinAliases(raw_ostream &OS) {
17095ffd83dbSDimitry Andric   // Build a sorted table of:
17105ffd83dbSDimitry Andric   // - intrinsic id number
17115ffd83dbSDimitry Andric   // - full name
17125ffd83dbSDimitry Andric   // - polymorphic name or -1
17135ffd83dbSDimitry Andric   StringToOffsetTable StringTable;
17145ffd83dbSDimitry Andric   OS << "static const IntrinToName MapData[] = {\n";
1715480093f4SDimitry Andric   for (const auto &kv : ACLEIntrinsics) {
1716480093f4SDimitry Andric     const ACLEIntrinsic &Int = *kv.second;
17175ffd83dbSDimitry Andric     if (Int.headerOnly())
17185ffd83dbSDimitry Andric       continue;
17195ffd83dbSDimitry Andric     int32_t ShortNameOffset =
17205ffd83dbSDimitry Andric         Int.polymorphic() ? StringTable.GetOrAddStringOffset(Int.shortName())
17215ffd83dbSDimitry Andric                           : -1;
17225ffd83dbSDimitry Andric     OS << "  { ARM::BI__builtin_arm_" << Int.builtinExtension() << "_"
17235ffd83dbSDimitry Andric        << Int.fullName() << ", "
17245ffd83dbSDimitry Andric        << StringTable.GetOrAddStringOffset(Int.fullName()) << ", "
17255ffd83dbSDimitry Andric        << ShortNameOffset << "},\n";
17265ffd83dbSDimitry Andric   }
17275ffd83dbSDimitry Andric   OS << "};\n\n";
17285ffd83dbSDimitry Andric 
17295ffd83dbSDimitry Andric   OS << "ArrayRef<IntrinToName> Map(MapData);\n\n";
17305ffd83dbSDimitry Andric 
17315ffd83dbSDimitry Andric   OS << "static const char IntrinNames[] = {\n";
17325ffd83dbSDimitry Andric   StringTable.EmitString(OS);
17335ffd83dbSDimitry Andric   OS << "};\n\n";
17345ffd83dbSDimitry Andric }
17355ffd83dbSDimitry Andric 
GroupSemaChecks(std::map<std::string,std::set<std::string>> & Checks)17365ffd83dbSDimitry Andric void EmitterBase::GroupSemaChecks(
17375ffd83dbSDimitry Andric     std::map<std::string, std::set<std::string>> &Checks) {
17385ffd83dbSDimitry Andric   for (const auto &kv : ACLEIntrinsics) {
17395ffd83dbSDimitry Andric     const ACLEIntrinsic &Int = *kv.second;
17405ffd83dbSDimitry Andric     if (Int.headerOnly())
17415ffd83dbSDimitry Andric       continue;
17425ffd83dbSDimitry Andric     std::string Check = Int.genSema();
17435ffd83dbSDimitry Andric     if (!Check.empty())
17445ffd83dbSDimitry Andric       Checks[Check].insert(Int.fullName());
17455ffd83dbSDimitry Andric   }
17465ffd83dbSDimitry Andric }
17475ffd83dbSDimitry Andric 
17485ffd83dbSDimitry Andric // -----------------------------------------------------------------------------
17495ffd83dbSDimitry Andric // The class used for generating arm_mve.h and related Clang bits
17505ffd83dbSDimitry Andric //
17515ffd83dbSDimitry Andric 
17525ffd83dbSDimitry Andric class MveEmitter : public EmitterBase {
17535ffd83dbSDimitry Andric public:
MveEmitter(RecordKeeper & Records)17545ffd83dbSDimitry Andric   MveEmitter(RecordKeeper &Records) : EmitterBase(Records){};
17555ffd83dbSDimitry Andric   void EmitHeader(raw_ostream &OS) override;
17565ffd83dbSDimitry Andric   void EmitBuiltinDef(raw_ostream &OS) override;
17575ffd83dbSDimitry Andric   void EmitBuiltinSema(raw_ostream &OS) override;
17585ffd83dbSDimitry Andric };
17595ffd83dbSDimitry Andric 
EmitHeader(raw_ostream & OS)17605ffd83dbSDimitry Andric void MveEmitter::EmitHeader(raw_ostream &OS) {
17615ffd83dbSDimitry Andric   // Accumulate pieces of the header file that will be enabled under various
17625ffd83dbSDimitry Andric   // different combinations of #ifdef. The index into parts[] is made up of
17635ffd83dbSDimitry Andric   // the following bit flags.
17645ffd83dbSDimitry Andric   constexpr unsigned Float = 1;
17655ffd83dbSDimitry Andric   constexpr unsigned UseUserNamespace = 2;
17665ffd83dbSDimitry Andric 
17675ffd83dbSDimitry Andric   constexpr unsigned NumParts = 4;
17685ffd83dbSDimitry Andric   raw_self_contained_string_ostream parts[NumParts];
17695ffd83dbSDimitry Andric 
17705ffd83dbSDimitry Andric   // Write typedefs for all the required vector types, and a few scalar
17715ffd83dbSDimitry Andric   // types that don't already have the name we want them to have.
17725ffd83dbSDimitry Andric 
17735ffd83dbSDimitry Andric   parts[0] << "typedef uint16_t mve_pred16_t;\n";
17745ffd83dbSDimitry Andric   parts[Float] << "typedef __fp16 float16_t;\n"
17755ffd83dbSDimitry Andric                   "typedef float float32_t;\n";
17765ffd83dbSDimitry Andric   for (const auto &kv : ScalarTypes) {
17775ffd83dbSDimitry Andric     const ScalarType *ST = kv.second.get();
17785ffd83dbSDimitry Andric     if (ST->hasNonstandardName())
17795ffd83dbSDimitry Andric       continue;
17805ffd83dbSDimitry Andric     raw_ostream &OS = parts[ST->requiresFloat() ? Float : 0];
17815ffd83dbSDimitry Andric     const VectorType *VT = getVectorType(ST);
17825ffd83dbSDimitry Andric 
17835ffd83dbSDimitry Andric     OS << "typedef __attribute__((__neon_vector_type__(" << VT->lanes()
17845ffd83dbSDimitry Andric        << "), __clang_arm_mve_strict_polymorphism)) " << ST->cName() << " "
17855ffd83dbSDimitry Andric        << VT->cName() << ";\n";
17865ffd83dbSDimitry Andric 
17875ffd83dbSDimitry Andric     // Every vector type also comes with a pair of multi-vector types for
17885ffd83dbSDimitry Andric     // the VLD2 and VLD4 instructions.
17895ffd83dbSDimitry Andric     for (unsigned n = 2; n <= 4; n += 2) {
17905ffd83dbSDimitry Andric       const MultiVectorType *MT = getMultiVectorType(n, VT);
17915ffd83dbSDimitry Andric       OS << "typedef struct { " << VT->cName() << " val[" << n << "]; } "
17925ffd83dbSDimitry Andric          << MT->cName() << ";\n";
17935ffd83dbSDimitry Andric     }
17945ffd83dbSDimitry Andric   }
17955ffd83dbSDimitry Andric   parts[0] << "\n";
17965ffd83dbSDimitry Andric   parts[Float] << "\n";
17975ffd83dbSDimitry Andric 
17985ffd83dbSDimitry Andric   // Write declarations for all the intrinsics.
17995ffd83dbSDimitry Andric 
18005ffd83dbSDimitry Andric   for (const auto &kv : ACLEIntrinsics) {
18015ffd83dbSDimitry Andric     const ACLEIntrinsic &Int = *kv.second;
18025ffd83dbSDimitry Andric 
18035ffd83dbSDimitry Andric     // We generate each intrinsic twice, under its full unambiguous
18045ffd83dbSDimitry Andric     // name and its shorter polymorphic name (if the latter exists).
18055ffd83dbSDimitry Andric     for (bool Polymorphic : {false, true}) {
18065ffd83dbSDimitry Andric       if (Polymorphic && !Int.polymorphic())
18075ffd83dbSDimitry Andric         continue;
18085ffd83dbSDimitry Andric       if (!Polymorphic && Int.polymorphicOnly())
18095ffd83dbSDimitry Andric         continue;
18105ffd83dbSDimitry Andric 
18115ffd83dbSDimitry Andric       // We also generate each intrinsic under a name like __arm_vfooq
18125ffd83dbSDimitry Andric       // (which is in C language implementation namespace, so it's
18135ffd83dbSDimitry Andric       // safe to define in any conforming user program) and a shorter
18145ffd83dbSDimitry Andric       // one like vfooq (which is in user namespace, so a user might
18155ffd83dbSDimitry Andric       // reasonably have used it for something already). If so, they
18165ffd83dbSDimitry Andric       // can #define __ARM_MVE_PRESERVE_USER_NAMESPACE before
18175ffd83dbSDimitry Andric       // including the header, which will suppress the shorter names
18185ffd83dbSDimitry Andric       // and leave only the implementation-namespace ones. Then they
18195ffd83dbSDimitry Andric       // have to write __arm_vfooq everywhere, of course.
18205ffd83dbSDimitry Andric 
18215ffd83dbSDimitry Andric       for (bool UserNamespace : {false, true}) {
18225ffd83dbSDimitry Andric         raw_ostream &OS = parts[(Int.requiresFloat() ? Float : 0) |
18235ffd83dbSDimitry Andric                                 (UserNamespace ? UseUserNamespace : 0)];
18245ffd83dbSDimitry Andric 
18255ffd83dbSDimitry Andric         // Make the name of the function in this declaration.
18265ffd83dbSDimitry Andric 
18275ffd83dbSDimitry Andric         std::string FunctionName =
18285ffd83dbSDimitry Andric             Polymorphic ? Int.shortName() : Int.fullName();
18295ffd83dbSDimitry Andric         if (!UserNamespace)
18305ffd83dbSDimitry Andric           FunctionName = "__arm_" + FunctionName;
18315ffd83dbSDimitry Andric 
18325ffd83dbSDimitry Andric         // Make strings for the types involved in the function's
18335ffd83dbSDimitry Andric         // prototype.
18345ffd83dbSDimitry Andric 
18355ffd83dbSDimitry Andric         std::string RetTypeName = Int.returnType()->cName();
18365f757f3fSDimitry Andric         if (!StringRef(RetTypeName).ends_with("*"))
18375ffd83dbSDimitry Andric           RetTypeName += " ";
18385ffd83dbSDimitry Andric 
18395ffd83dbSDimitry Andric         std::vector<std::string> ArgTypeNames;
18405ffd83dbSDimitry Andric         for (const Type *ArgTypePtr : Int.argTypes())
18415ffd83dbSDimitry Andric           ArgTypeNames.push_back(ArgTypePtr->cName());
18425ffd83dbSDimitry Andric         std::string ArgTypesString =
18435ffd83dbSDimitry Andric             join(std::begin(ArgTypeNames), std::end(ArgTypeNames), ", ");
18445ffd83dbSDimitry Andric 
18455ffd83dbSDimitry Andric         // Emit the actual declaration. All these functions are
18465ffd83dbSDimitry Andric         // declared 'static inline' without a body, which is fine
18475ffd83dbSDimitry Andric         // provided clang recognizes them as builtins, and has the
18485ffd83dbSDimitry Andric         // effect that this type signature is used in place of the one
18495ffd83dbSDimitry Andric         // that Builtins.def didn't provide. That's how we can get
18505ffd83dbSDimitry Andric         // structure types that weren't defined until this header was
18515ffd83dbSDimitry Andric         // included to be part of the type signature of a builtin that
18525ffd83dbSDimitry Andric         // was known to clang already.
18535ffd83dbSDimitry Andric         //
18545ffd83dbSDimitry Andric         // The declarations use __attribute__(__clang_arm_builtin_alias),
18555ffd83dbSDimitry Andric         // so that each function declared will be recognized as the
18565ffd83dbSDimitry Andric         // appropriate MVE builtin in spite of its user-facing name.
18575ffd83dbSDimitry Andric         //
18585ffd83dbSDimitry Andric         // (That's better than making them all wrapper functions,
18595ffd83dbSDimitry Andric         // partly because it avoids any compiler error message citing
18605ffd83dbSDimitry Andric         // the wrapper function definition instead of the user's code,
18615ffd83dbSDimitry Andric         // and mostly because some MVE intrinsics have arguments
18625ffd83dbSDimitry Andric         // required to be compile-time constants, and that property
18635ffd83dbSDimitry Andric         // can't be propagated through a wrapper function. It can be
18645ffd83dbSDimitry Andric         // propagated through a macro, but macros can't be overloaded
18655ffd83dbSDimitry Andric         // on argument types very easily - you have to use _Generic,
18665ffd83dbSDimitry Andric         // which makes error messages very confusing when the user
18675ffd83dbSDimitry Andric         // gets it wrong.)
18685ffd83dbSDimitry Andric         //
18695ffd83dbSDimitry Andric         // Finally, the polymorphic versions of the intrinsics are
18705ffd83dbSDimitry Andric         // also defined with __attribute__(overloadable), so that when
18715ffd83dbSDimitry Andric         // the same name is defined with several type signatures, the
18725ffd83dbSDimitry Andric         // right thing happens. Each one of the overloaded
18735ffd83dbSDimitry Andric         // declarations is given a different builtin id, which
18745ffd83dbSDimitry Andric         // has exactly the effect we want: first clang resolves the
18755ffd83dbSDimitry Andric         // overload to the right function, then it knows which builtin
18765ffd83dbSDimitry Andric         // it's referring to, and then the Sema checking for that
18775ffd83dbSDimitry Andric         // builtin can check further things like the constant
18785ffd83dbSDimitry Andric         // arguments.
18795ffd83dbSDimitry Andric         //
18805ffd83dbSDimitry Andric         // One more subtlety is the newline just before the return
18815ffd83dbSDimitry Andric         // type name. That's a cosmetic tweak to make the error
18825ffd83dbSDimitry Andric         // messages legible if the user gets the types wrong in a call
18835ffd83dbSDimitry Andric         // to a polymorphic function: this way, clang will print just
18845ffd83dbSDimitry Andric         // the _final_ line of each declaration in the header, to show
18855ffd83dbSDimitry Andric         // the type signatures that would have been legal. So all the
18865ffd83dbSDimitry Andric         // confusing machinery with __attribute__ is left out of the
18875ffd83dbSDimitry Andric         // error message, and the user sees something that's more or
18885ffd83dbSDimitry Andric         // less self-documenting: "here's a list of actually readable
18895ffd83dbSDimitry Andric         // type signatures for vfooq(), and here's why each one didn't
18905ffd83dbSDimitry Andric         // match your call".
18915ffd83dbSDimitry Andric 
18925ffd83dbSDimitry Andric         OS << "static __inline__ __attribute__(("
18935ffd83dbSDimitry Andric            << (Polymorphic ? "__overloadable__, " : "")
18945ffd83dbSDimitry Andric            << "__clang_arm_builtin_alias(__builtin_arm_mve_" << Int.fullName()
18955ffd83dbSDimitry Andric            << ")))\n"
18965ffd83dbSDimitry Andric            << RetTypeName << FunctionName << "(" << ArgTypesString << ");\n";
18975ffd83dbSDimitry Andric       }
18985ffd83dbSDimitry Andric     }
18995ffd83dbSDimitry Andric   }
19005ffd83dbSDimitry Andric   for (auto &part : parts)
19015ffd83dbSDimitry Andric     part << "\n";
19025ffd83dbSDimitry Andric 
19035ffd83dbSDimitry Andric   // Now we've finished accumulating bits and pieces into the parts[] array.
19045ffd83dbSDimitry Andric   // Put it all together to write the final output file.
19055ffd83dbSDimitry Andric 
19065ffd83dbSDimitry Andric   OS << "/*===---- arm_mve.h - ARM MVE intrinsics "
19075ffd83dbSDimitry Andric         "-----------------------------------===\n"
19085ffd83dbSDimitry Andric      << LLVMLicenseHeader
19095ffd83dbSDimitry Andric      << "#ifndef __ARM_MVE_H\n"
19105ffd83dbSDimitry Andric         "#define __ARM_MVE_H\n"
19115ffd83dbSDimitry Andric         "\n"
19125ffd83dbSDimitry Andric         "#if !__ARM_FEATURE_MVE\n"
19135ffd83dbSDimitry Andric         "#error \"MVE support not enabled\"\n"
19145ffd83dbSDimitry Andric         "#endif\n"
19155ffd83dbSDimitry Andric         "\n"
19165ffd83dbSDimitry Andric         "#include <stdint.h>\n"
19175ffd83dbSDimitry Andric         "\n"
19185ffd83dbSDimitry Andric         "#ifdef __cplusplus\n"
19195ffd83dbSDimitry Andric         "extern \"C\" {\n"
19205ffd83dbSDimitry Andric         "#endif\n"
19215ffd83dbSDimitry Andric         "\n";
19225ffd83dbSDimitry Andric 
19235ffd83dbSDimitry Andric   for (size_t i = 0; i < NumParts; ++i) {
19245ffd83dbSDimitry Andric     std::vector<std::string> conditions;
19255ffd83dbSDimitry Andric     if (i & Float)
19265ffd83dbSDimitry Andric       conditions.push_back("(__ARM_FEATURE_MVE & 2)");
19275ffd83dbSDimitry Andric     if (i & UseUserNamespace)
19285ffd83dbSDimitry Andric       conditions.push_back("(!defined __ARM_MVE_PRESERVE_USER_NAMESPACE)");
19295ffd83dbSDimitry Andric 
19305ffd83dbSDimitry Andric     std::string condition =
19315ffd83dbSDimitry Andric         join(std::begin(conditions), std::end(conditions), " && ");
19325ffd83dbSDimitry Andric     if (!condition.empty())
19335ffd83dbSDimitry Andric       OS << "#if " << condition << "\n\n";
19345ffd83dbSDimitry Andric     OS << parts[i].str();
19355ffd83dbSDimitry Andric     if (!condition.empty())
19365ffd83dbSDimitry Andric       OS << "#endif /* " << condition << " */\n\n";
19375ffd83dbSDimitry Andric   }
19385ffd83dbSDimitry Andric 
19395ffd83dbSDimitry Andric   OS << "#ifdef __cplusplus\n"
19405ffd83dbSDimitry Andric         "} /* extern \"C\" */\n"
19415ffd83dbSDimitry Andric         "#endif\n"
19425ffd83dbSDimitry Andric         "\n"
19435ffd83dbSDimitry Andric         "#endif /* __ARM_MVE_H */\n";
19445ffd83dbSDimitry Andric }
19455ffd83dbSDimitry Andric 
EmitBuiltinDef(raw_ostream & OS)19465ffd83dbSDimitry Andric void MveEmitter::EmitBuiltinDef(raw_ostream &OS) {
19475ffd83dbSDimitry Andric   for (const auto &kv : ACLEIntrinsics) {
19485ffd83dbSDimitry Andric     const ACLEIntrinsic &Int = *kv.second;
1949349cc55cSDimitry Andric     OS << "BUILTIN(__builtin_arm_mve_" << Int.fullName()
1950349cc55cSDimitry Andric        << ", \"\", \"n\")\n";
19515ffd83dbSDimitry Andric   }
19525ffd83dbSDimitry Andric 
19535ffd83dbSDimitry Andric   std::set<std::string> ShortNamesSeen;
19545ffd83dbSDimitry Andric 
19555ffd83dbSDimitry Andric   for (const auto &kv : ACLEIntrinsics) {
19565ffd83dbSDimitry Andric     const ACLEIntrinsic &Int = *kv.second;
19575ffd83dbSDimitry Andric     if (Int.polymorphic()) {
19585ffd83dbSDimitry Andric       StringRef Name = Int.shortName();
19595ffd83dbSDimitry Andric       if (ShortNamesSeen.find(std::string(Name)) == ShortNamesSeen.end()) {
19605ffd83dbSDimitry Andric         OS << "BUILTIN(__builtin_arm_mve_" << Name << ", \"vi.\", \"nt";
19615ffd83dbSDimitry Andric         if (Int.nonEvaluating())
19625ffd83dbSDimitry Andric           OS << "u"; // indicate that this builtin doesn't evaluate its args
19635ffd83dbSDimitry Andric         OS << "\")\n";
19645ffd83dbSDimitry Andric         ShortNamesSeen.insert(std::string(Name));
19655ffd83dbSDimitry Andric       }
19665ffd83dbSDimitry Andric     }
19675ffd83dbSDimitry Andric   }
19685ffd83dbSDimitry Andric }
19695ffd83dbSDimitry Andric 
EmitBuiltinSema(raw_ostream & OS)19705ffd83dbSDimitry Andric void MveEmitter::EmitBuiltinSema(raw_ostream &OS) {
19715ffd83dbSDimitry Andric   std::map<std::string, std::set<std::string>> Checks;
19725ffd83dbSDimitry Andric   GroupSemaChecks(Checks);
19735ffd83dbSDimitry Andric 
19745ffd83dbSDimitry Andric   for (const auto &kv : Checks) {
19755ffd83dbSDimitry Andric     for (StringRef Name : kv.second)
19765ffd83dbSDimitry Andric       OS << "case ARM::BI__builtin_arm_mve_" << Name << ":\n";
19775ffd83dbSDimitry Andric     OS << "  return " << kv.first;
19785ffd83dbSDimitry Andric   }
19795ffd83dbSDimitry Andric }
19805ffd83dbSDimitry Andric 
19815ffd83dbSDimitry Andric // -----------------------------------------------------------------------------
19825ffd83dbSDimitry Andric // Class that describes an ACLE intrinsic implemented as a macro.
19835ffd83dbSDimitry Andric //
19845ffd83dbSDimitry Andric // This class is used when the intrinsic is polymorphic in 2 or 3 types, but we
19855ffd83dbSDimitry Andric // want to avoid a combinatorial explosion by reinterpreting the arguments to
19865ffd83dbSDimitry Andric // fixed types.
19875ffd83dbSDimitry Andric 
19885ffd83dbSDimitry Andric class FunctionMacro {
19895ffd83dbSDimitry Andric   std::vector<StringRef> Params;
19905ffd83dbSDimitry Andric   StringRef Definition;
19915ffd83dbSDimitry Andric 
19925ffd83dbSDimitry Andric public:
19935ffd83dbSDimitry Andric   FunctionMacro(const Record &R);
19945ffd83dbSDimitry Andric 
getParams() const19955ffd83dbSDimitry Andric   const std::vector<StringRef> &getParams() const { return Params; }
getDefinition() const19965ffd83dbSDimitry Andric   StringRef getDefinition() const { return Definition; }
19975ffd83dbSDimitry Andric };
19985ffd83dbSDimitry Andric 
FunctionMacro(const Record & R)19995ffd83dbSDimitry Andric FunctionMacro::FunctionMacro(const Record &R) {
20005ffd83dbSDimitry Andric   Params = R.getValueAsListOfStrings("params");
20015ffd83dbSDimitry Andric   Definition = R.getValueAsString("definition");
20025ffd83dbSDimitry Andric }
20035ffd83dbSDimitry Andric 
20045ffd83dbSDimitry Andric // -----------------------------------------------------------------------------
20055ffd83dbSDimitry Andric // The class used for generating arm_cde.h and related Clang bits
20065ffd83dbSDimitry Andric //
20075ffd83dbSDimitry Andric 
20085ffd83dbSDimitry Andric class CdeEmitter : public EmitterBase {
20095ffd83dbSDimitry Andric   std::map<StringRef, FunctionMacro> FunctionMacros;
20105ffd83dbSDimitry Andric 
20115ffd83dbSDimitry Andric public:
20125ffd83dbSDimitry Andric   CdeEmitter(RecordKeeper &Records);
20135ffd83dbSDimitry Andric   void EmitHeader(raw_ostream &OS) override;
20145ffd83dbSDimitry Andric   void EmitBuiltinDef(raw_ostream &OS) override;
20155ffd83dbSDimitry Andric   void EmitBuiltinSema(raw_ostream &OS) override;
20165ffd83dbSDimitry Andric };
20175ffd83dbSDimitry Andric 
CdeEmitter(RecordKeeper & Records)20185ffd83dbSDimitry Andric CdeEmitter::CdeEmitter(RecordKeeper &Records) : EmitterBase(Records) {
20195ffd83dbSDimitry Andric   for (Record *R : Records.getAllDerivedDefinitions("FunctionMacro"))
20205ffd83dbSDimitry Andric     FunctionMacros.emplace(R->getName(), FunctionMacro(*R));
20215ffd83dbSDimitry Andric }
20225ffd83dbSDimitry Andric 
EmitHeader(raw_ostream & OS)20235ffd83dbSDimitry Andric void CdeEmitter::EmitHeader(raw_ostream &OS) {
20245ffd83dbSDimitry Andric   // Accumulate pieces of the header file that will be enabled under various
20255ffd83dbSDimitry Andric   // different combinations of #ifdef. The index into parts[] is one of the
20265ffd83dbSDimitry Andric   // following:
20275ffd83dbSDimitry Andric   constexpr unsigned None = 0;
20285ffd83dbSDimitry Andric   constexpr unsigned MVE = 1;
20295ffd83dbSDimitry Andric   constexpr unsigned MVEFloat = 2;
20305ffd83dbSDimitry Andric 
20315ffd83dbSDimitry Andric   constexpr unsigned NumParts = 3;
20325ffd83dbSDimitry Andric   raw_self_contained_string_ostream parts[NumParts];
20335ffd83dbSDimitry Andric 
20345ffd83dbSDimitry Andric   // Write typedefs for all the required vector types, and a few scalar
20355ffd83dbSDimitry Andric   // types that don't already have the name we want them to have.
20365ffd83dbSDimitry Andric 
20375ffd83dbSDimitry Andric   parts[MVE] << "typedef uint16_t mve_pred16_t;\n";
20385ffd83dbSDimitry Andric   parts[MVEFloat] << "typedef __fp16 float16_t;\n"
20395ffd83dbSDimitry Andric                      "typedef float float32_t;\n";
20405ffd83dbSDimitry Andric   for (const auto &kv : ScalarTypes) {
20415ffd83dbSDimitry Andric     const ScalarType *ST = kv.second.get();
20425ffd83dbSDimitry Andric     if (ST->hasNonstandardName())
20435ffd83dbSDimitry Andric       continue;
20445ffd83dbSDimitry Andric     // We don't have float64x2_t
20455ffd83dbSDimitry Andric     if (ST->kind() == ScalarTypeKind::Float && ST->sizeInBits() == 64)
20465ffd83dbSDimitry Andric       continue;
20475ffd83dbSDimitry Andric     raw_ostream &OS = parts[ST->requiresFloat() ? MVEFloat : MVE];
20485ffd83dbSDimitry Andric     const VectorType *VT = getVectorType(ST);
20495ffd83dbSDimitry Andric 
20505ffd83dbSDimitry Andric     OS << "typedef __attribute__((__neon_vector_type__(" << VT->lanes()
20515ffd83dbSDimitry Andric        << "), __clang_arm_mve_strict_polymorphism)) " << ST->cName() << " "
20525ffd83dbSDimitry Andric        << VT->cName() << ";\n";
20535ffd83dbSDimitry Andric   }
20545ffd83dbSDimitry Andric   parts[MVE] << "\n";
20555ffd83dbSDimitry Andric   parts[MVEFloat] << "\n";
20565ffd83dbSDimitry Andric 
20575ffd83dbSDimitry Andric   // Write declarations for all the intrinsics.
20585ffd83dbSDimitry Andric 
20595ffd83dbSDimitry Andric   for (const auto &kv : ACLEIntrinsics) {
20605ffd83dbSDimitry Andric     const ACLEIntrinsic &Int = *kv.second;
20615ffd83dbSDimitry Andric 
20625ffd83dbSDimitry Andric     // We generate each intrinsic twice, under its full unambiguous
20635ffd83dbSDimitry Andric     // name and its shorter polymorphic name (if the latter exists).
20645ffd83dbSDimitry Andric     for (bool Polymorphic : {false, true}) {
20655ffd83dbSDimitry Andric       if (Polymorphic && !Int.polymorphic())
20665ffd83dbSDimitry Andric         continue;
20675ffd83dbSDimitry Andric       if (!Polymorphic && Int.polymorphicOnly())
20685ffd83dbSDimitry Andric         continue;
20695ffd83dbSDimitry Andric 
20705ffd83dbSDimitry Andric       raw_ostream &OS =
20715ffd83dbSDimitry Andric           parts[Int.requiresFloat() ? MVEFloat
20725ffd83dbSDimitry Andric                                     : Int.requiresMVE() ? MVE : None];
20735ffd83dbSDimitry Andric 
20745ffd83dbSDimitry Andric       // Make the name of the function in this declaration.
20755ffd83dbSDimitry Andric       std::string FunctionName =
20765ffd83dbSDimitry Andric           "__arm_" + (Polymorphic ? Int.shortName() : Int.fullName());
20775ffd83dbSDimitry Andric 
20785ffd83dbSDimitry Andric       // Make strings for the types involved in the function's
20795ffd83dbSDimitry Andric       // prototype.
20805ffd83dbSDimitry Andric       std::string RetTypeName = Int.returnType()->cName();
20815f757f3fSDimitry Andric       if (!StringRef(RetTypeName).ends_with("*"))
20825ffd83dbSDimitry Andric         RetTypeName += " ";
20835ffd83dbSDimitry Andric 
20845ffd83dbSDimitry Andric       std::vector<std::string> ArgTypeNames;
20855ffd83dbSDimitry Andric       for (const Type *ArgTypePtr : Int.argTypes())
20865ffd83dbSDimitry Andric         ArgTypeNames.push_back(ArgTypePtr->cName());
20875ffd83dbSDimitry Andric       std::string ArgTypesString =
20885ffd83dbSDimitry Andric           join(std::begin(ArgTypeNames), std::end(ArgTypeNames), ", ");
20895ffd83dbSDimitry Andric 
20905ffd83dbSDimitry Andric       // Emit the actual declaration. See MveEmitter::EmitHeader for detailed
20915ffd83dbSDimitry Andric       // comments
20925ffd83dbSDimitry Andric       OS << "static __inline__ __attribute__(("
20935ffd83dbSDimitry Andric          << (Polymorphic ? "__overloadable__, " : "")
20945ffd83dbSDimitry Andric          << "__clang_arm_builtin_alias(__builtin_arm_" << Int.builtinExtension()
20955ffd83dbSDimitry Andric          << "_" << Int.fullName() << ")))\n"
20965ffd83dbSDimitry Andric          << RetTypeName << FunctionName << "(" << ArgTypesString << ");\n";
20975ffd83dbSDimitry Andric     }
20985ffd83dbSDimitry Andric   }
20995ffd83dbSDimitry Andric 
21005ffd83dbSDimitry Andric   for (const auto &kv : FunctionMacros) {
21015ffd83dbSDimitry Andric     StringRef Name = kv.first;
21025ffd83dbSDimitry Andric     const FunctionMacro &FM = kv.second;
21035ffd83dbSDimitry Andric 
21045ffd83dbSDimitry Andric     raw_ostream &OS = parts[MVE];
21055ffd83dbSDimitry Andric     OS << "#define "
21065ffd83dbSDimitry Andric        << "__arm_" << Name << "(" << join(FM.getParams(), ", ") << ") "
21075ffd83dbSDimitry Andric        << FM.getDefinition() << "\n";
21085ffd83dbSDimitry Andric   }
21095ffd83dbSDimitry Andric 
21105ffd83dbSDimitry Andric   for (auto &part : parts)
21115ffd83dbSDimitry Andric     part << "\n";
21125ffd83dbSDimitry Andric 
21135ffd83dbSDimitry Andric   // Now we've finished accumulating bits and pieces into the parts[] array.
21145ffd83dbSDimitry Andric   // Put it all together to write the final output file.
21155ffd83dbSDimitry Andric 
21165ffd83dbSDimitry Andric   OS << "/*===---- arm_cde.h - ARM CDE intrinsics "
21175ffd83dbSDimitry Andric         "-----------------------------------===\n"
21185ffd83dbSDimitry Andric      << LLVMLicenseHeader
21195ffd83dbSDimitry Andric      << "#ifndef __ARM_CDE_H\n"
21205ffd83dbSDimitry Andric         "#define __ARM_CDE_H\n"
21215ffd83dbSDimitry Andric         "\n"
21225ffd83dbSDimitry Andric         "#if !__ARM_FEATURE_CDE\n"
21235ffd83dbSDimitry Andric         "#error \"CDE support not enabled\"\n"
21245ffd83dbSDimitry Andric         "#endif\n"
21255ffd83dbSDimitry Andric         "\n"
21265ffd83dbSDimitry Andric         "#include <stdint.h>\n"
21275ffd83dbSDimitry Andric         "\n"
21285ffd83dbSDimitry Andric         "#ifdef __cplusplus\n"
21295ffd83dbSDimitry Andric         "extern \"C\" {\n"
21305ffd83dbSDimitry Andric         "#endif\n"
21315ffd83dbSDimitry Andric         "\n";
21325ffd83dbSDimitry Andric 
21335ffd83dbSDimitry Andric   for (size_t i = 0; i < NumParts; ++i) {
21345ffd83dbSDimitry Andric     std::string condition;
21355ffd83dbSDimitry Andric     if (i == MVEFloat)
21365ffd83dbSDimitry Andric       condition = "__ARM_FEATURE_MVE & 2";
21375ffd83dbSDimitry Andric     else if (i == MVE)
21385ffd83dbSDimitry Andric       condition = "__ARM_FEATURE_MVE";
21395ffd83dbSDimitry Andric 
21405ffd83dbSDimitry Andric     if (!condition.empty())
21415ffd83dbSDimitry Andric       OS << "#if " << condition << "\n\n";
21425ffd83dbSDimitry Andric     OS << parts[i].str();
21435ffd83dbSDimitry Andric     if (!condition.empty())
21445ffd83dbSDimitry Andric       OS << "#endif /* " << condition << " */\n\n";
21455ffd83dbSDimitry Andric   }
21465ffd83dbSDimitry Andric 
21475ffd83dbSDimitry Andric   OS << "#ifdef __cplusplus\n"
21485ffd83dbSDimitry Andric         "} /* extern \"C\" */\n"
21495ffd83dbSDimitry Andric         "#endif\n"
21505ffd83dbSDimitry Andric         "\n"
21515ffd83dbSDimitry Andric         "#endif /* __ARM_CDE_H */\n";
21525ffd83dbSDimitry Andric }
21535ffd83dbSDimitry Andric 
EmitBuiltinDef(raw_ostream & OS)21545ffd83dbSDimitry Andric void CdeEmitter::EmitBuiltinDef(raw_ostream &OS) {
21555ffd83dbSDimitry Andric   for (const auto &kv : ACLEIntrinsics) {
21565ffd83dbSDimitry Andric     if (kv.second->headerOnly())
21575ffd83dbSDimitry Andric       continue;
21585ffd83dbSDimitry Andric     const ACLEIntrinsic &Int = *kv.second;
2159349cc55cSDimitry Andric     OS << "BUILTIN(__builtin_arm_cde_" << Int.fullName()
2160349cc55cSDimitry Andric        << ", \"\", \"ncU\")\n";
21615ffd83dbSDimitry Andric   }
21625ffd83dbSDimitry Andric }
21635ffd83dbSDimitry Andric 
EmitBuiltinSema(raw_ostream & OS)21645ffd83dbSDimitry Andric void CdeEmitter::EmitBuiltinSema(raw_ostream &OS) {
21655ffd83dbSDimitry Andric   std::map<std::string, std::set<std::string>> Checks;
21665ffd83dbSDimitry Andric   GroupSemaChecks(Checks);
21675ffd83dbSDimitry Andric 
21685ffd83dbSDimitry Andric   for (const auto &kv : Checks) {
21695ffd83dbSDimitry Andric     for (StringRef Name : kv.second)
21705ffd83dbSDimitry Andric       OS << "case ARM::BI__builtin_arm_cde_" << Name << ":\n";
21715ffd83dbSDimitry Andric     OS << "  Err = " << kv.first << "  break;\n";
2172480093f4SDimitry Andric   }
2173480093f4SDimitry Andric }
2174480093f4SDimitry Andric 
2175480093f4SDimitry Andric } // namespace
2176480093f4SDimitry Andric 
2177480093f4SDimitry Andric namespace clang {
2178480093f4SDimitry Andric 
21795ffd83dbSDimitry Andric // MVE
21805ffd83dbSDimitry Andric 
EmitMveHeader(RecordKeeper & Records,raw_ostream & OS)2181480093f4SDimitry Andric void EmitMveHeader(RecordKeeper &Records, raw_ostream &OS) {
2182480093f4SDimitry Andric   MveEmitter(Records).EmitHeader(OS);
2183480093f4SDimitry Andric }
2184480093f4SDimitry Andric 
EmitMveBuiltinDef(RecordKeeper & Records,raw_ostream & OS)2185480093f4SDimitry Andric void EmitMveBuiltinDef(RecordKeeper &Records, raw_ostream &OS) {
2186480093f4SDimitry Andric   MveEmitter(Records).EmitBuiltinDef(OS);
2187480093f4SDimitry Andric }
2188480093f4SDimitry Andric 
EmitMveBuiltinSema(RecordKeeper & Records,raw_ostream & OS)2189480093f4SDimitry Andric void EmitMveBuiltinSema(RecordKeeper &Records, raw_ostream &OS) {
2190480093f4SDimitry Andric   MveEmitter(Records).EmitBuiltinSema(OS);
2191480093f4SDimitry Andric }
2192480093f4SDimitry Andric 
EmitMveBuiltinCG(RecordKeeper & Records,raw_ostream & OS)2193480093f4SDimitry Andric void EmitMveBuiltinCG(RecordKeeper &Records, raw_ostream &OS) {
2194480093f4SDimitry Andric   MveEmitter(Records).EmitBuiltinCG(OS);
2195480093f4SDimitry Andric }
2196480093f4SDimitry Andric 
EmitMveBuiltinAliases(RecordKeeper & Records,raw_ostream & OS)2197480093f4SDimitry Andric void EmitMveBuiltinAliases(RecordKeeper &Records, raw_ostream &OS) {
2198480093f4SDimitry Andric   MveEmitter(Records).EmitBuiltinAliases(OS);
2199480093f4SDimitry Andric }
2200480093f4SDimitry Andric 
22015ffd83dbSDimitry Andric // CDE
22025ffd83dbSDimitry Andric 
EmitCdeHeader(RecordKeeper & Records,raw_ostream & OS)22035ffd83dbSDimitry Andric void EmitCdeHeader(RecordKeeper &Records, raw_ostream &OS) {
22045ffd83dbSDimitry Andric   CdeEmitter(Records).EmitHeader(OS);
22055ffd83dbSDimitry Andric }
22065ffd83dbSDimitry Andric 
EmitCdeBuiltinDef(RecordKeeper & Records,raw_ostream & OS)22075ffd83dbSDimitry Andric void EmitCdeBuiltinDef(RecordKeeper &Records, raw_ostream &OS) {
22085ffd83dbSDimitry Andric   CdeEmitter(Records).EmitBuiltinDef(OS);
22095ffd83dbSDimitry Andric }
22105ffd83dbSDimitry Andric 
EmitCdeBuiltinSema(RecordKeeper & Records,raw_ostream & OS)22115ffd83dbSDimitry Andric void EmitCdeBuiltinSema(RecordKeeper &Records, raw_ostream &OS) {
22125ffd83dbSDimitry Andric   CdeEmitter(Records).EmitBuiltinSema(OS);
22135ffd83dbSDimitry Andric }
22145ffd83dbSDimitry Andric 
EmitCdeBuiltinCG(RecordKeeper & Records,raw_ostream & OS)22155ffd83dbSDimitry Andric void EmitCdeBuiltinCG(RecordKeeper &Records, raw_ostream &OS) {
22165ffd83dbSDimitry Andric   CdeEmitter(Records).EmitBuiltinCG(OS);
22175ffd83dbSDimitry Andric }
22185ffd83dbSDimitry Andric 
EmitCdeBuiltinAliases(RecordKeeper & Records,raw_ostream & OS)22195ffd83dbSDimitry Andric void EmitCdeBuiltinAliases(RecordKeeper &Records, raw_ostream &OS) {
22205ffd83dbSDimitry Andric   CdeEmitter(Records).EmitBuiltinAliases(OS);
22215ffd83dbSDimitry Andric }
22225ffd83dbSDimitry Andric 
2223480093f4SDimitry Andric } // end namespace clang
2224