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 = ∬
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