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: 137480093f4SDimitry Andric Type(TypeKind K) : TKind(K) {} 138480093f4SDimitry Andric 139480093f4SDimitry Andric public: 140480093f4SDimitry 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; 146480093f4SDimitry Andric virtual std::string llvmName() const { 147480093f4SDimitry Andric PrintFatalError("no LLVM type name available for type " + cName()); 148480093f4SDimitry Andric } 149480093f4SDimitry 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 }; 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 } 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: 180480093f4SDimitry Andric VoidType() : Type(TypeKind::Void) {} 181480093f4SDimitry Andric unsigned sizeInBits() const override { return 0; } 182480093f4SDimitry Andric bool requiresFloat() const override { return false; } 1835ffd83dbSDimitry Andric bool requiresMVE() const override { return false; } 184480093f4SDimitry Andric std::string cName() const override { return "void"; } 185480093f4SDimitry Andric 186480093f4SDimitry Andric static bool classof(const Type *T) { return T->typeKind() == TypeKind::Void; } 187480093f4SDimitry 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: 195480093f4SDimitry Andric PointerType(const Type *Pointee, bool Const) 196480093f4SDimitry Andric : Type(TypeKind::Pointer), Pointee(Pointee), Const(Const) {} 197480093f4SDimitry Andric unsigned sizeInBits() const override { return 32; } 198480093f4SDimitry Andric bool requiresFloat() const override { return Pointee->requiresFloat(); } 1995ffd83dbSDimitry Andric bool requiresMVE() const override { return Pointee->requiresMVE(); } 200480093f4SDimitry 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 } 212480093f4SDimitry Andric std::string llvmName() const override { 213480093f4SDimitry Andric return "llvm::PointerType::getUnqual(" + Pointee->llvmName() + ")"; 214480093f4SDimitry Andric } 21581ad6265SDimitry Andric const Type *getPointeeType() const { return Pointee; } 216480093f4SDimitry Andric 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: 235480093f4SDimitry 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: 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 } 252480093f4SDimitry Andric unsigned sizeInBits() const override { return Bits; } 253480093f4SDimitry Andric ScalarTypeKind kind() const { return Kind; } 254480093f4SDimitry Andric std::string suffix() const { return toLetter(Kind) + utostr(Bits); } 255480093f4SDimitry Andric std::string cNameBase() const override { 256480093f4SDimitry Andric return toCPrefix(Kind) + utostr(Bits); 257480093f4SDimitry Andric } 258480093f4SDimitry Andric std::string cName() const override { 259480093f4SDimitry Andric if (NameOverride.empty()) 260480093f4SDimitry Andric return CRegularNamedType::cName(); 261480093f4SDimitry Andric return NameOverride; 262480093f4SDimitry Andric } 263480093f4SDimitry 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 } 275480093f4SDimitry Andric std::string acleSuffix(std::string overrideLetter) const override { 276480093f4SDimitry Andric return "_" + (overrideLetter.size() ? overrideLetter : toLetter(Kind)) 277480093f4SDimitry Andric + utostr(Bits); 278480093f4SDimitry Andric } 279480093f4SDimitry Andric bool isInteger() const { return Kind != ScalarTypeKind::Float; } 280480093f4SDimitry Andric bool requiresFloat() const override { return !isInteger(); } 2815ffd83dbSDimitry Andric bool requiresMVE() const override { return false; } 282480093f4SDimitry Andric bool hasNonstandardName() const { return !NameOverride.empty(); } 283480093f4SDimitry Andric 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: 294480093f4SDimitry Andric VectorType(const ScalarType *Element, unsigned Lanes) 295480093f4SDimitry Andric : CRegularNamedType(TypeKind::Vector), Element(Element), Lanes(Lanes) {} 296480093f4SDimitry Andric unsigned sizeInBits() const override { return Lanes * Element->sizeInBits(); } 297480093f4SDimitry Andric unsigned lanes() const { return Lanes; } 298480093f4SDimitry Andric bool requiresFloat() const override { return Element->requiresFloat(); } 2995ffd83dbSDimitry Andric bool requiresMVE() const override { return true; } 300480093f4SDimitry Andric std::string cNameBase() const override { 301480093f4SDimitry Andric return Element->cNameBase() + "x" + utostr(Lanes); 302480093f4SDimitry Andric } 303480093f4SDimitry Andric std::string llvmName() const override { 3045ffd83dbSDimitry Andric return "llvm::FixedVectorType::get(" + Element->llvmName() + ", " + 305480093f4SDimitry Andric utostr(Lanes) + ")"; 306480093f4SDimitry Andric } 307480093f4SDimitry Andric 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: 318480093f4SDimitry Andric MultiVectorType(unsigned Registers, const VectorType *Element) 319480093f4SDimitry Andric : CRegularNamedType(TypeKind::MultiVector), Element(Element), 320480093f4SDimitry Andric Registers(Registers) {} 321480093f4SDimitry Andric unsigned sizeInBits() const override { 322480093f4SDimitry Andric return Registers * Element->sizeInBits(); 323480093f4SDimitry Andric } 324480093f4SDimitry Andric unsigned registers() const { return Registers; } 325480093f4SDimitry Andric bool requiresFloat() const override { return Element->requiresFloat(); } 3265ffd83dbSDimitry Andric bool requiresMVE() const override { return true; } 327480093f4SDimitry 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 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: 346480093f4SDimitry Andric PredicateType(unsigned Lanes) 347480093f4SDimitry Andric : CRegularNamedType(TypeKind::Predicate), Lanes(Lanes) {} 348480093f4SDimitry Andric unsigned sizeInBits() const override { return 16; } 349480093f4SDimitry Andric std::string cNameBase() const override { return "mve_pred16"; } 350480093f4SDimitry Andric bool requiresFloat() const override { return false; }; 3515ffd83dbSDimitry Andric bool requiresMVE() const override { return true; } 352480093f4SDimitry Andric std::string llvmName() const override { 3530eae32dcSDimitry Andric return "llvm::FixedVectorType::get(Builder.getInt1Ty(), " + utostr(Lanes) + 3540eae32dcSDimitry Andric ")"; 355480093f4SDimitry Andric } 356480093f4SDimitry Andric 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 418480093f4SDimitry 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; 476480093f4SDimitry Andric virtual bool hasIntegerConstantValue() const { return false; } 477480093f4SDimitry Andric virtual uint32_t integerConstantValue() const { return 0; } 478480093f4SDimitry Andric virtual bool hasIntegerValue() const { return false; } 479480093f4SDimitry Andric virtual std::string getIntegerValue(const std::string &) { 480480093f4SDimitry Andric llvm_unreachable("non-working Result::getIntegerValue called"); 481480093f4SDimitry Andric } 482480093f4SDimitry 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 498480093f4SDimitry Andric virtual void morePrerequisites(std::vector<Ptr> &output) const {} 499480093f4SDimitry 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 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. 527480093f4SDimitry Andric std::string varname() { 528480093f4SDimitry Andric VarNameUsed = true; 529480093f4SDimitry Andric return VarName; 530480093f4SDimitry Andric } 5315ffd83dbSDimitry Andric void setVarname(const StringRef s) { VarName = std::string(s); } 532480093f4SDimitry Andric bool varnameUsed() const { return VarNameUsed; } 533480093f4SDimitry Andric 534480093f4SDimitry Andric // Emit code to generate this result as a Value *. 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. 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; 566480093f4SDimitry Andric BuiltinArgResult(unsigned ArgNum, bool AddressType, bool Immediate) 567480093f4SDimitry Andric : ArgNum(ArgNum), AddressType(AddressType), Immediate(Immediate) {} 568480093f4SDimitry Andric void genCode(raw_ostream &OS, CodeGenParamAllocator &) const override { 569480093f4SDimitry Andric OS << (AddressType ? "EmitPointerWithAlignment" : "EmitScalarExpr") 570480093f4SDimitry Andric << "(E->getArg(" << ArgNum << "))"; 571480093f4SDimitry Andric } 572480093f4SDimitry 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 *. 576480093f4SDimitry Andric std::string asValue() override { 577480093f4SDimitry Andric if (AddressType) 578*0fca6ea1SDimitry Andric return "(" + varname() + ".emitRawPointer(*this))"; 579480093f4SDimitry Andric return Result::asValue(); 580480093f4SDimitry Andric } 581480093f4SDimitry Andric bool hasIntegerValue() const override { return Immediate; } 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; 596480093f4SDimitry Andric IntLiteralResult(const ScalarType *IntegerType, uint32_t IntegerValue) 597480093f4SDimitry Andric : IntegerType(IntegerType), IntegerValue(IntegerValue) {} 598480093f4SDimitry 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 } 606480093f4SDimitry Andric bool hasIntegerConstantValue() const override { return true; } 607480093f4SDimitry 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; 617480093f4SDimitry Andric IntCastResult(const ScalarType *IntegerType, Ptr V) 618480093f4SDimitry Andric : IntegerType(IntegerType), V(V) {} 619480093f4SDimitry 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 } 629480093f4SDimitry 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; 639480093f4SDimitry Andric PointerCastResult(const PointerType *PtrType, Ptr V) 640480093f4SDimitry Andric : PtrType(PtrType), V(V) {} 641480093f4SDimitry 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 } 646480093f4SDimitry 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; 661*0fca6ea1SDimitry Andric IRBuilderResult(StringRef CallPrefix, const std::vector<Ptr> &Args, 662*0fca6ea1SDimitry Andric const std::set<unsigned> &AddressArgs, 663*0fca6ea1SDimitry Andric const std::map<unsigned, std::string> &IntegerArgs) 664480093f4SDimitry Andric : CallPrefix(CallPrefix), Args(Args), AddressArgs(AddressArgs), 665480093f4SDimitry Andric IntegerArgs(IntegerArgs) {} 666480093f4SDimitry 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 } 692480093f4SDimitry 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; 70881ad6265SDimitry Andric AddressResult(Ptr Arg, const Type *Ty, unsigned Align) 70981ad6265SDimitry Andric : Arg(Arg), Ty(Ty), Align(Align) {} 710480093f4SDimitry 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 } 715480093f4SDimitry Andric std::string typeName() const override { 716480093f4SDimitry Andric return "Address"; 717480093f4SDimitry Andric } 718480093f4SDimitry 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; 730*0fca6ea1SDimitry Andric IRIntrinsicResult(StringRef IntrinsicID, 731*0fca6ea1SDimitry Andric const std::vector<const Type *> &ParamTypes, 732*0fca6ea1SDimitry Andric const std::vector<Ptr> &Args) 7335ffd83dbSDimitry Andric : IntrinsicID(std::string(IntrinsicID)), ParamTypes(ParamTypes), 7345ffd83dbSDimitry Andric Args(Args) {} 735480093f4SDimitry Andric void genCode(raw_ostream &OS, 736480093f4SDimitry Andric CodeGenParamAllocator &ParamAlloc) const override { 737480093f4SDimitry Andric std::string IntNo = ParamAlloc.allocParam( 738480093f4SDimitry Andric "Intrinsic::ID", "Intrinsic::" + IntrinsicID); 739480093f4SDimitry Andric OS << "Builder.CreateCall(CGM.getIntrinsic(" << IntNo; 740480093f4SDimitry Andric if (!ParamTypes.empty()) { 7415ffd83dbSDimitry Andric OS << ", {"; 742480093f4SDimitry Andric const char *Sep = ""; 743480093f4SDimitry Andric for (auto T : ParamTypes) { 744480093f4SDimitry Andric OS << Sep << ParamAlloc.allocParam("llvm::Type *", T->llvmName()); 745480093f4SDimitry Andric Sep = ", "; 746480093f4SDimitry Andric } 747480093f4SDimitry Andric OS << "}"; 748480093f4SDimitry Andric } 7495ffd83dbSDimitry Andric OS << "), {"; 750480093f4SDimitry Andric const char *Sep = ""; 751480093f4SDimitry Andric for (auto Arg : Args) { 752480093f4SDimitry Andric OS << Sep << Arg->asValue(); 753480093f4SDimitry Andric Sep = ", "; 754480093f4SDimitry Andric } 755480093f4SDimitry Andric OS << "})"; 756480093f4SDimitry Andric } 757480093f4SDimitry Andric void morePrerequisites(std::vector<Ptr> &output) const override { 758480093f4SDimitry Andric output.insert(output.end(), Args.begin(), Args.end()); 759480093f4SDimitry Andric } 760480093f4SDimitry Andric }; 761480093f4SDimitry Andric 762480093f4SDimitry Andric // Result subclass that specifies a type, for use in IRBuilder operations such 763480093f4SDimitry Andric // as CreateBitCast that take a type argument. 764480093f4SDimitry Andric class TypeResult : public Result { 765480093f4SDimitry Andric public: 766480093f4SDimitry Andric const Type *T; 767480093f4SDimitry Andric TypeResult(const Type *T) : T(T) {} 768480093f4SDimitry Andric void genCode(raw_ostream &OS, CodeGenParamAllocator &) const override { 769480093f4SDimitry Andric OS << T->llvmName(); 770480093f4SDimitry Andric } 771480093f4SDimitry Andric std::string typeName() const override { 772480093f4SDimitry Andric return "llvm::Type *"; 773480093f4SDimitry Andric } 774480093f4SDimitry Andric }; 775480093f4SDimitry Andric 776480093f4SDimitry Andric // ----------------------------------------------------------------------------- 777480093f4SDimitry Andric // Class that describes a single ACLE intrinsic. 778480093f4SDimitry Andric // 779480093f4SDimitry Andric // A Tablegen record will typically describe more than one ACLE intrinsic, by 780480093f4SDimitry Andric // means of setting the 'list<Type> Params' field to a list of multiple 781480093f4SDimitry Andric // parameter types, so as to define vaddq_{s8,u8,...,f16,f32} all in one go. 782480093f4SDimitry Andric // We'll end up with one instance of ACLEIntrinsic for *each* parameter type, 783480093f4SDimitry Andric // rather than a single one for all of them. Hence, the constructor takes both 784480093f4SDimitry Andric // a Tablegen record and the current value of the parameter type. 785480093f4SDimitry Andric 786480093f4SDimitry Andric class ACLEIntrinsic { 787480093f4SDimitry Andric // Structure documenting that one of the intrinsic's arguments is required to 788480093f4SDimitry Andric // be a compile-time constant integer, and what constraints there are on its 789480093f4SDimitry Andric // value. Used when generating Sema checking code. 790480093f4SDimitry Andric struct ImmediateArg { 791480093f4SDimitry Andric enum class BoundsType { ExplicitRange, UInt }; 792480093f4SDimitry Andric BoundsType boundsType; 793480093f4SDimitry Andric int64_t i1, i2; 794480093f4SDimitry Andric StringRef ExtraCheckType, ExtraCheckArgs; 795480093f4SDimitry Andric const Type *ArgType; 796480093f4SDimitry Andric }; 797480093f4SDimitry Andric 798480093f4SDimitry Andric // For polymorphic intrinsics, FullName is the explicit name that uniquely 799480093f4SDimitry Andric // identifies this variant of the intrinsic, and ShortName is the name it 800480093f4SDimitry Andric // shares with at least one other intrinsic. 801480093f4SDimitry Andric std::string ShortName, FullName; 802480093f4SDimitry Andric 8035ffd83dbSDimitry Andric // Name of the architecture extension, used in the Clang builtin name 8045ffd83dbSDimitry Andric StringRef BuiltinExtension; 8055ffd83dbSDimitry Andric 806480093f4SDimitry Andric // A very small number of intrinsics _only_ have a polymorphic 807480093f4SDimitry Andric // variant (vuninitializedq taking an unevaluated argument). 808480093f4SDimitry Andric bool PolymorphicOnly; 809480093f4SDimitry Andric 810480093f4SDimitry Andric // Another rarely-used flag indicating that the builtin doesn't 811480093f4SDimitry Andric // evaluate its argument(s) at all. 812480093f4SDimitry Andric bool NonEvaluating; 813480093f4SDimitry Andric 8145ffd83dbSDimitry Andric // True if the intrinsic needs only the C header part (no codegen, semantic 8155ffd83dbSDimitry Andric // checks, etc). Used for redeclaring MVE intrinsics in the arm_cde.h header. 8165ffd83dbSDimitry Andric bool HeaderOnly; 8175ffd83dbSDimitry Andric 818480093f4SDimitry Andric const Type *ReturnType; 819480093f4SDimitry Andric std::vector<const Type *> ArgTypes; 820480093f4SDimitry Andric std::map<unsigned, ImmediateArg> ImmediateArgs; 821480093f4SDimitry Andric Result::Ptr Code; 822480093f4SDimitry Andric 823480093f4SDimitry Andric std::map<std::string, std::string> CustomCodeGenArgs; 824480093f4SDimitry Andric 825480093f4SDimitry Andric // Recursive function that does the internals of code generation. 826480093f4SDimitry Andric void genCodeDfs(Result::Ptr V, std::list<Result::Ptr> &Used, 827480093f4SDimitry Andric unsigned Pass) const { 828480093f4SDimitry Andric if (!V->needsVisiting(Pass)) 829480093f4SDimitry Andric return; 830480093f4SDimitry Andric 831480093f4SDimitry Andric for (Result::Ptr W : V->prerequisites()) 832480093f4SDimitry Andric genCodeDfs(W, Used, Pass); 833480093f4SDimitry Andric 834480093f4SDimitry Andric Used.push_back(V); 835480093f4SDimitry Andric } 836480093f4SDimitry Andric 837480093f4SDimitry Andric public: 838480093f4SDimitry Andric const std::string &shortName() const { return ShortName; } 839480093f4SDimitry Andric const std::string &fullName() const { return FullName; } 8405ffd83dbSDimitry Andric StringRef builtinExtension() const { return BuiltinExtension; } 841480093f4SDimitry Andric const Type *returnType() const { return ReturnType; } 842480093f4SDimitry Andric const std::vector<const Type *> &argTypes() const { return ArgTypes; } 843480093f4SDimitry Andric bool requiresFloat() const { 844480093f4SDimitry Andric if (ReturnType->requiresFloat()) 845480093f4SDimitry Andric return true; 846480093f4SDimitry Andric for (const Type *T : ArgTypes) 847480093f4SDimitry Andric if (T->requiresFloat()) 848480093f4SDimitry Andric return true; 849480093f4SDimitry Andric return false; 850480093f4SDimitry Andric } 8515ffd83dbSDimitry Andric bool requiresMVE() const { 8525ffd83dbSDimitry Andric return ReturnType->requiresMVE() || 8535ffd83dbSDimitry Andric any_of(ArgTypes, [](const Type *T) { return T->requiresMVE(); }); 8545ffd83dbSDimitry Andric } 855480093f4SDimitry Andric bool polymorphic() const { return ShortName != FullName; } 856480093f4SDimitry Andric bool polymorphicOnly() const { return PolymorphicOnly; } 857480093f4SDimitry Andric bool nonEvaluating() const { return NonEvaluating; } 8585ffd83dbSDimitry Andric bool headerOnly() const { return HeaderOnly; } 859480093f4SDimitry Andric 8605ffd83dbSDimitry Andric // External entry point for code generation, called from EmitterBase. 861480093f4SDimitry Andric void genCode(raw_ostream &OS, CodeGenParamAllocator &ParamAlloc, 862480093f4SDimitry Andric unsigned Pass) const { 8635ffd83dbSDimitry Andric assert(!headerOnly() && "Called genCode for header-only intrinsic"); 864480093f4SDimitry Andric if (!hasCode()) { 865480093f4SDimitry Andric for (auto kv : CustomCodeGenArgs) 866480093f4SDimitry Andric OS << " " << kv.first << " = " << kv.second << ";\n"; 867480093f4SDimitry Andric OS << " break; // custom code gen\n"; 868480093f4SDimitry Andric return; 869480093f4SDimitry Andric } 870480093f4SDimitry Andric std::list<Result::Ptr> Used; 871480093f4SDimitry Andric genCodeDfs(Code, Used, Pass); 872480093f4SDimitry Andric 873480093f4SDimitry Andric unsigned varindex = 0; 874480093f4SDimitry Andric for (Result::Ptr V : Used) 875480093f4SDimitry Andric if (V->varnameUsed()) 876480093f4SDimitry Andric V->setVarname("Val" + utostr(varindex++)); 877480093f4SDimitry Andric 878480093f4SDimitry Andric for (Result::Ptr V : Used) { 879480093f4SDimitry Andric OS << " "; 880480093f4SDimitry Andric if (V == Used.back()) { 881480093f4SDimitry Andric assert(!V->varnameUsed()); 882480093f4SDimitry Andric OS << "return "; // FIXME: what if the top-level thing is void? 883480093f4SDimitry Andric } else if (V->varnameUsed()) { 884480093f4SDimitry Andric std::string Type = V->typeName(); 885480093f4SDimitry Andric OS << V->typeName(); 8865f757f3fSDimitry Andric if (!StringRef(Type).ends_with("*")) 887480093f4SDimitry Andric OS << " "; 888480093f4SDimitry Andric OS << V->varname() << " = "; 889480093f4SDimitry Andric } 890480093f4SDimitry Andric V->genCode(OS, ParamAlloc); 891480093f4SDimitry Andric OS << ";\n"; 892480093f4SDimitry Andric } 893480093f4SDimitry Andric } 894480093f4SDimitry Andric bool hasCode() const { return Code != nullptr; } 895480093f4SDimitry Andric 896480093f4SDimitry Andric static std::string signedHexLiteral(const llvm::APInt &iOrig) { 897480093f4SDimitry Andric llvm::APInt i = iOrig.trunc(64); 898480093f4SDimitry Andric SmallString<40> s; 899480093f4SDimitry Andric i.toString(s, 16, true, true); 9007a6dacacSDimitry Andric return std::string(s); 901480093f4SDimitry Andric } 902480093f4SDimitry Andric 903480093f4SDimitry Andric std::string genSema() const { 9045ffd83dbSDimitry Andric assert(!headerOnly() && "Called genSema for header-only intrinsic"); 905480093f4SDimitry Andric std::vector<std::string> SemaChecks; 906480093f4SDimitry Andric 907480093f4SDimitry Andric for (const auto &kv : ImmediateArgs) { 908480093f4SDimitry Andric const ImmediateArg &IA = kv.second; 909480093f4SDimitry Andric 910480093f4SDimitry Andric llvm::APInt lo(128, 0), hi(128, 0); 911480093f4SDimitry Andric switch (IA.boundsType) { 912480093f4SDimitry Andric case ImmediateArg::BoundsType::ExplicitRange: 913480093f4SDimitry Andric lo = IA.i1; 914480093f4SDimitry Andric hi = IA.i2; 915480093f4SDimitry Andric break; 916480093f4SDimitry Andric case ImmediateArg::BoundsType::UInt: 917480093f4SDimitry Andric lo = 0; 9185ffd83dbSDimitry Andric hi = llvm::APInt::getMaxValue(IA.i1).zext(128); 919480093f4SDimitry Andric break; 920480093f4SDimitry Andric } 921480093f4SDimitry Andric 922480093f4SDimitry Andric std::string Index = utostr(kv.first); 923480093f4SDimitry Andric 9245ffd83dbSDimitry Andric // Emit a range check if the legal range of values for the 9255ffd83dbSDimitry Andric // immediate is smaller than the _possible_ range of values for 9265ffd83dbSDimitry Andric // its type. 9275ffd83dbSDimitry Andric unsigned ArgTypeBits = IA.ArgType->sizeInBits(); 9285ffd83dbSDimitry Andric llvm::APInt ArgTypeRange = llvm::APInt::getMaxValue(ArgTypeBits).zext(128); 9295ffd83dbSDimitry Andric llvm::APInt ActualRange = (hi-lo).trunc(64).sext(128); 9305ffd83dbSDimitry Andric if (ActualRange.ult(ArgTypeRange)) 931*0fca6ea1SDimitry Andric SemaChecks.push_back("SemaRef.BuiltinConstantArgRange(TheCall, " + 932*0fca6ea1SDimitry Andric Index + ", " + signedHexLiteral(lo) + ", " + 933480093f4SDimitry Andric signedHexLiteral(hi) + ")"); 934480093f4SDimitry Andric 935480093f4SDimitry Andric if (!IA.ExtraCheckType.empty()) { 936480093f4SDimitry Andric std::string Suffix; 9375ffd83dbSDimitry Andric if (!IA.ExtraCheckArgs.empty()) { 9385ffd83dbSDimitry Andric std::string tmp; 9395ffd83dbSDimitry Andric StringRef Arg = IA.ExtraCheckArgs; 9405ffd83dbSDimitry Andric if (Arg == "!lanesize") { 9415ffd83dbSDimitry Andric tmp = utostr(IA.ArgType->sizeInBits()); 9425ffd83dbSDimitry Andric Arg = tmp; 9435ffd83dbSDimitry Andric } 9445ffd83dbSDimitry Andric Suffix = (Twine(", ") + Arg).str(); 9455ffd83dbSDimitry Andric } 946*0fca6ea1SDimitry Andric SemaChecks.push_back((Twine("SemaRef.BuiltinConstantArg") + 947480093f4SDimitry Andric IA.ExtraCheckType + "(TheCall, " + Index + 948480093f4SDimitry Andric Suffix + ")") 949480093f4SDimitry Andric .str()); 950480093f4SDimitry Andric } 9515ffd83dbSDimitry Andric 9525ffd83dbSDimitry Andric assert(!SemaChecks.empty()); 953480093f4SDimitry Andric } 954480093f4SDimitry Andric if (SemaChecks.empty()) 955480093f4SDimitry Andric return ""; 9565ffd83dbSDimitry Andric return join(std::begin(SemaChecks), std::end(SemaChecks), 957480093f4SDimitry Andric " ||\n ") + 9585ffd83dbSDimitry Andric ";\n"; 959480093f4SDimitry Andric } 960480093f4SDimitry Andric 9615ffd83dbSDimitry Andric ACLEIntrinsic(EmitterBase &ME, Record *R, const Type *Param); 962480093f4SDimitry Andric }; 963480093f4SDimitry Andric 964480093f4SDimitry Andric // ----------------------------------------------------------------------------- 965480093f4SDimitry Andric // The top-level class that holds all the state from analyzing the entire 966480093f4SDimitry Andric // Tablegen input. 967480093f4SDimitry Andric 9685ffd83dbSDimitry Andric class EmitterBase { 9695ffd83dbSDimitry Andric protected: 9705ffd83dbSDimitry Andric // EmitterBase holds a collection of all the types we've instantiated. 971480093f4SDimitry Andric VoidType Void; 972480093f4SDimitry Andric std::map<std::string, std::unique_ptr<ScalarType>> ScalarTypes; 973480093f4SDimitry Andric std::map<std::tuple<ScalarTypeKind, unsigned, unsigned>, 974480093f4SDimitry Andric std::unique_ptr<VectorType>> 975480093f4SDimitry Andric VectorTypes; 976480093f4SDimitry Andric std::map<std::pair<std::string, unsigned>, std::unique_ptr<MultiVectorType>> 977480093f4SDimitry Andric MultiVectorTypes; 978480093f4SDimitry Andric std::map<unsigned, std::unique_ptr<PredicateType>> PredicateTypes; 979480093f4SDimitry Andric std::map<std::string, std::unique_ptr<PointerType>> PointerTypes; 980480093f4SDimitry Andric 981480093f4SDimitry Andric // And all the ACLEIntrinsic instances we've created. 982480093f4SDimitry Andric std::map<std::string, std::unique_ptr<ACLEIntrinsic>> ACLEIntrinsics; 983480093f4SDimitry Andric 984480093f4SDimitry Andric public: 985480093f4SDimitry Andric // Methods to create a Type object, or return the right existing one from the 986480093f4SDimitry Andric // maps stored in this object. 987480093f4SDimitry Andric const VoidType *getVoidType() { return &Void; } 988480093f4SDimitry Andric const ScalarType *getScalarType(StringRef Name) { 9895ffd83dbSDimitry Andric return ScalarTypes[std::string(Name)].get(); 990480093f4SDimitry Andric } 991480093f4SDimitry Andric const ScalarType *getScalarType(Record *R) { 992480093f4SDimitry Andric return getScalarType(R->getName()); 993480093f4SDimitry Andric } 994480093f4SDimitry Andric const VectorType *getVectorType(const ScalarType *ST, unsigned Lanes) { 995480093f4SDimitry Andric std::tuple<ScalarTypeKind, unsigned, unsigned> key(ST->kind(), 996480093f4SDimitry Andric ST->sizeInBits(), Lanes); 997480093f4SDimitry Andric if (VectorTypes.find(key) == VectorTypes.end()) 998480093f4SDimitry Andric VectorTypes[key] = std::make_unique<VectorType>(ST, Lanes); 999480093f4SDimitry Andric return VectorTypes[key].get(); 1000480093f4SDimitry Andric } 1001480093f4SDimitry Andric const VectorType *getVectorType(const ScalarType *ST) { 1002480093f4SDimitry Andric return getVectorType(ST, 128 / ST->sizeInBits()); 1003480093f4SDimitry Andric } 1004480093f4SDimitry Andric const MultiVectorType *getMultiVectorType(unsigned Registers, 1005480093f4SDimitry Andric const VectorType *VT) { 1006480093f4SDimitry Andric std::pair<std::string, unsigned> key(VT->cNameBase(), Registers); 1007480093f4SDimitry Andric if (MultiVectorTypes.find(key) == MultiVectorTypes.end()) 1008480093f4SDimitry Andric MultiVectorTypes[key] = std::make_unique<MultiVectorType>(Registers, VT); 1009480093f4SDimitry Andric return MultiVectorTypes[key].get(); 1010480093f4SDimitry Andric } 1011480093f4SDimitry Andric const PredicateType *getPredicateType(unsigned Lanes) { 1012480093f4SDimitry Andric unsigned key = Lanes; 1013480093f4SDimitry Andric if (PredicateTypes.find(key) == PredicateTypes.end()) 1014480093f4SDimitry Andric PredicateTypes[key] = std::make_unique<PredicateType>(Lanes); 1015480093f4SDimitry Andric return PredicateTypes[key].get(); 1016480093f4SDimitry Andric } 1017480093f4SDimitry Andric const PointerType *getPointerType(const Type *T, bool Const) { 1018480093f4SDimitry Andric PointerType PT(T, Const); 1019480093f4SDimitry Andric std::string key = PT.cName(); 1020480093f4SDimitry Andric if (PointerTypes.find(key) == PointerTypes.end()) 1021480093f4SDimitry Andric PointerTypes[key] = std::make_unique<PointerType>(PT); 1022480093f4SDimitry Andric return PointerTypes[key].get(); 1023480093f4SDimitry Andric } 1024480093f4SDimitry Andric 1025480093f4SDimitry Andric // Methods to construct a type from various pieces of Tablegen. These are 1026480093f4SDimitry Andric // always called in the context of setting up a particular ACLEIntrinsic, so 1027480093f4SDimitry Andric // there's always an ambient parameter type (because we're iterating through 1028480093f4SDimitry Andric // the Params list in the Tablegen record for the intrinsic), which is used 1029480093f4SDimitry Andric // to expand Tablegen classes like 'Vector' which mean something different in 1030480093f4SDimitry Andric // each member of a parametric family. 1031480093f4SDimitry Andric const Type *getType(Record *R, const Type *Param); 1032480093f4SDimitry Andric const Type *getType(DagInit *D, const Type *Param); 1033480093f4SDimitry Andric const Type *getType(Init *I, const Type *Param); 1034480093f4SDimitry Andric 1035480093f4SDimitry Andric // Functions that translate the Tablegen representation of an intrinsic's 1036480093f4SDimitry Andric // code generation into a collection of Value objects (which will then be 1037480093f4SDimitry Andric // reprocessed to read out the actual C++ code included by CGBuiltin.cpp). 1038480093f4SDimitry Andric Result::Ptr getCodeForDag(DagInit *D, const Result::Scope &Scope, 1039480093f4SDimitry Andric const Type *Param); 1040480093f4SDimitry Andric Result::Ptr getCodeForDagArg(DagInit *D, unsigned ArgNum, 1041480093f4SDimitry Andric const Result::Scope &Scope, const Type *Param); 1042480093f4SDimitry Andric Result::Ptr getCodeForArg(unsigned ArgNum, const Type *ArgType, bool Promote, 1043480093f4SDimitry Andric bool Immediate); 1044480093f4SDimitry Andric 10455ffd83dbSDimitry Andric void GroupSemaChecks(std::map<std::string, std::set<std::string>> &Checks); 10465ffd83dbSDimitry Andric 1047480093f4SDimitry Andric // Constructor and top-level functions. 1048480093f4SDimitry Andric 10495ffd83dbSDimitry Andric EmitterBase(RecordKeeper &Records); 10505ffd83dbSDimitry Andric virtual ~EmitterBase() = default; 1051480093f4SDimitry Andric 10525ffd83dbSDimitry Andric virtual void EmitHeader(raw_ostream &OS) = 0; 10535ffd83dbSDimitry Andric virtual void EmitBuiltinDef(raw_ostream &OS) = 0; 10545ffd83dbSDimitry Andric virtual void EmitBuiltinSema(raw_ostream &OS) = 0; 1055480093f4SDimitry Andric void EmitBuiltinCG(raw_ostream &OS); 1056480093f4SDimitry Andric void EmitBuiltinAliases(raw_ostream &OS); 1057480093f4SDimitry Andric }; 1058480093f4SDimitry Andric 10595ffd83dbSDimitry Andric const Type *EmitterBase::getType(Init *I, const Type *Param) { 1060480093f4SDimitry Andric if (auto Dag = dyn_cast<DagInit>(I)) 1061480093f4SDimitry Andric return getType(Dag, Param); 1062480093f4SDimitry Andric if (auto Def = dyn_cast<DefInit>(I)) 1063480093f4SDimitry Andric return getType(Def->getDef(), Param); 1064480093f4SDimitry Andric 1065480093f4SDimitry Andric PrintFatalError("Could not convert this value into a type"); 1066480093f4SDimitry Andric } 1067480093f4SDimitry Andric 10685ffd83dbSDimitry Andric const Type *EmitterBase::getType(Record *R, const Type *Param) { 1069480093f4SDimitry Andric // Pass to a subfield of any wrapper records. We don't expect more than one 1070480093f4SDimitry Andric // of these: immediate operands are used as plain numbers rather than as 1071480093f4SDimitry Andric // llvm::Value, so it's meaningless to promote their type anyway. 1072480093f4SDimitry Andric if (R->isSubClassOf("Immediate")) 1073480093f4SDimitry Andric R = R->getValueAsDef("type"); 1074480093f4SDimitry Andric else if (R->isSubClassOf("unpromoted")) 1075480093f4SDimitry Andric R = R->getValueAsDef("underlying_type"); 1076480093f4SDimitry Andric 1077480093f4SDimitry Andric if (R->getName() == "Void") 1078480093f4SDimitry Andric return getVoidType(); 1079480093f4SDimitry Andric if (R->isSubClassOf("PrimitiveType")) 1080480093f4SDimitry Andric return getScalarType(R); 1081480093f4SDimitry Andric if (R->isSubClassOf("ComplexType")) 1082480093f4SDimitry Andric return getType(R->getValueAsDag("spec"), Param); 1083480093f4SDimitry Andric 1084480093f4SDimitry Andric PrintFatalError(R->getLoc(), "Could not convert this record into a type"); 1085480093f4SDimitry Andric } 1086480093f4SDimitry Andric 10875ffd83dbSDimitry Andric const Type *EmitterBase::getType(DagInit *D, const Type *Param) { 1088480093f4SDimitry Andric // The meat of the getType system: types in the Tablegen are represented by a 1089480093f4SDimitry Andric // dag whose operators select sub-cases of this function. 1090480093f4SDimitry Andric 1091480093f4SDimitry Andric Record *Op = cast<DefInit>(D->getOperator())->getDef(); 1092480093f4SDimitry Andric if (!Op->isSubClassOf("ComplexTypeOp")) 1093480093f4SDimitry Andric PrintFatalError( 1094480093f4SDimitry Andric "Expected ComplexTypeOp as dag operator in type expression"); 1095480093f4SDimitry Andric 1096480093f4SDimitry Andric if (Op->getName() == "CTO_Parameter") { 1097480093f4SDimitry Andric if (isa<VoidType>(Param)) 1098480093f4SDimitry Andric PrintFatalError("Parametric type in unparametrised context"); 1099480093f4SDimitry Andric return Param; 1100480093f4SDimitry Andric } 1101480093f4SDimitry Andric 1102480093f4SDimitry Andric if (Op->getName() == "CTO_Vec") { 1103480093f4SDimitry Andric const Type *Element = getType(D->getArg(0), Param); 1104480093f4SDimitry Andric if (D->getNumArgs() == 1) { 1105480093f4SDimitry Andric return getVectorType(cast<ScalarType>(Element)); 1106480093f4SDimitry Andric } else { 1107480093f4SDimitry Andric const Type *ExistingVector = getType(D->getArg(1), Param); 1108480093f4SDimitry Andric return getVectorType(cast<ScalarType>(Element), 1109480093f4SDimitry Andric cast<VectorType>(ExistingVector)->lanes()); 1110480093f4SDimitry Andric } 1111480093f4SDimitry Andric } 1112480093f4SDimitry Andric 1113480093f4SDimitry Andric if (Op->getName() == "CTO_Pred") { 1114480093f4SDimitry Andric const Type *Element = getType(D->getArg(0), Param); 1115480093f4SDimitry Andric return getPredicateType(128 / Element->sizeInBits()); 1116480093f4SDimitry Andric } 1117480093f4SDimitry Andric 1118480093f4SDimitry Andric if (Op->isSubClassOf("CTO_Tuple")) { 1119480093f4SDimitry Andric unsigned Registers = Op->getValueAsInt("n"); 1120480093f4SDimitry Andric const Type *Element = getType(D->getArg(0), Param); 1121480093f4SDimitry Andric return getMultiVectorType(Registers, cast<VectorType>(Element)); 1122480093f4SDimitry Andric } 1123480093f4SDimitry Andric 1124480093f4SDimitry Andric if (Op->isSubClassOf("CTO_Pointer")) { 1125480093f4SDimitry Andric const Type *Pointee = getType(D->getArg(0), Param); 1126480093f4SDimitry Andric return getPointerType(Pointee, Op->getValueAsBit("const")); 1127480093f4SDimitry Andric } 1128480093f4SDimitry Andric 1129480093f4SDimitry Andric if (Op->getName() == "CTO_CopyKind") { 1130480093f4SDimitry Andric const ScalarType *STSize = cast<ScalarType>(getType(D->getArg(0), Param)); 1131480093f4SDimitry Andric const ScalarType *STKind = cast<ScalarType>(getType(D->getArg(1), Param)); 1132480093f4SDimitry Andric for (const auto &kv : ScalarTypes) { 1133480093f4SDimitry Andric const ScalarType *RT = kv.second.get(); 1134480093f4SDimitry Andric if (RT->kind() == STKind->kind() && RT->sizeInBits() == STSize->sizeInBits()) 1135480093f4SDimitry Andric return RT; 1136480093f4SDimitry Andric } 1137480093f4SDimitry Andric PrintFatalError("Cannot find a type to satisfy CopyKind"); 1138480093f4SDimitry Andric } 1139480093f4SDimitry Andric 1140480093f4SDimitry Andric if (Op->isSubClassOf("CTO_ScaleSize")) { 1141480093f4SDimitry Andric const ScalarType *STKind = cast<ScalarType>(getType(D->getArg(0), Param)); 1142480093f4SDimitry Andric int Num = Op->getValueAsInt("num"), Denom = Op->getValueAsInt("denom"); 1143480093f4SDimitry Andric unsigned DesiredSize = STKind->sizeInBits() * Num / Denom; 1144480093f4SDimitry Andric for (const auto &kv : ScalarTypes) { 1145480093f4SDimitry Andric const ScalarType *RT = kv.second.get(); 1146480093f4SDimitry Andric if (RT->kind() == STKind->kind() && RT->sizeInBits() == DesiredSize) 1147480093f4SDimitry Andric return RT; 1148480093f4SDimitry Andric } 1149480093f4SDimitry Andric PrintFatalError("Cannot find a type to satisfy ScaleSize"); 1150480093f4SDimitry Andric } 1151480093f4SDimitry Andric 1152480093f4SDimitry Andric PrintFatalError("Bad operator in type dag expression"); 1153480093f4SDimitry Andric } 1154480093f4SDimitry Andric 11555ffd83dbSDimitry Andric Result::Ptr EmitterBase::getCodeForDag(DagInit *D, const Result::Scope &Scope, 1156480093f4SDimitry Andric const Type *Param) { 1157480093f4SDimitry Andric Record *Op = cast<DefInit>(D->getOperator())->getDef(); 1158480093f4SDimitry Andric 1159480093f4SDimitry Andric if (Op->getName() == "seq") { 1160480093f4SDimitry Andric Result::Scope SubScope = Scope; 1161480093f4SDimitry Andric Result::Ptr PrevV = nullptr; 1162480093f4SDimitry Andric for (unsigned i = 0, e = D->getNumArgs(); i < e; ++i) { 1163480093f4SDimitry Andric // We don't use getCodeForDagArg here, because the argument name 1164480093f4SDimitry Andric // has different semantics in a seq 1165480093f4SDimitry Andric Result::Ptr V = 1166480093f4SDimitry Andric getCodeForDag(cast<DagInit>(D->getArg(i)), SubScope, Param); 1167480093f4SDimitry Andric StringRef ArgName = D->getArgNameStr(i); 1168480093f4SDimitry Andric if (!ArgName.empty()) 11695ffd83dbSDimitry Andric SubScope[std::string(ArgName)] = V; 1170480093f4SDimitry Andric if (PrevV) 1171480093f4SDimitry Andric V->setPredecessor(PrevV); 1172480093f4SDimitry Andric PrevV = V; 1173480093f4SDimitry Andric } 1174480093f4SDimitry Andric return PrevV; 1175480093f4SDimitry Andric } else if (Op->isSubClassOf("Type")) { 1176480093f4SDimitry Andric if (D->getNumArgs() != 1) 1177480093f4SDimitry Andric PrintFatalError("Type casts should have exactly one argument"); 1178480093f4SDimitry Andric const Type *CastType = getType(Op, Param); 1179480093f4SDimitry Andric Result::Ptr Arg = getCodeForDagArg(D, 0, Scope, Param); 1180480093f4SDimitry Andric if (const auto *ST = dyn_cast<ScalarType>(CastType)) { 1181480093f4SDimitry Andric if (!ST->requiresFloat()) { 1182480093f4SDimitry Andric if (Arg->hasIntegerConstantValue()) 1183480093f4SDimitry Andric return std::make_shared<IntLiteralResult>( 1184480093f4SDimitry Andric ST, Arg->integerConstantValue()); 1185480093f4SDimitry Andric else 1186480093f4SDimitry Andric return std::make_shared<IntCastResult>(ST, Arg); 1187480093f4SDimitry Andric } 1188480093f4SDimitry Andric } else if (const auto *PT = dyn_cast<PointerType>(CastType)) { 1189480093f4SDimitry Andric return std::make_shared<PointerCastResult>(PT, Arg); 1190480093f4SDimitry Andric } 1191480093f4SDimitry Andric PrintFatalError("Unsupported type cast"); 1192480093f4SDimitry Andric } else if (Op->getName() == "address") { 1193480093f4SDimitry Andric if (D->getNumArgs() != 2) 1194480093f4SDimitry Andric PrintFatalError("'address' should have two arguments"); 1195480093f4SDimitry Andric Result::Ptr Arg = getCodeForDagArg(D, 0, Scope, Param); 119681ad6265SDimitry Andric 119781ad6265SDimitry Andric const Type *Ty = nullptr; 119881ad6265SDimitry Andric if (auto *DI = dyn_cast<DagInit>(D->getArg(0))) 119981ad6265SDimitry Andric if (auto *PTy = dyn_cast<PointerType>(getType(DI->getOperator(), Param))) 120081ad6265SDimitry Andric Ty = PTy->getPointeeType(); 120181ad6265SDimitry Andric if (!Ty) 120281ad6265SDimitry Andric PrintFatalError("'address' pointer argument should be a pointer"); 120381ad6265SDimitry Andric 1204480093f4SDimitry Andric unsigned Alignment; 1205480093f4SDimitry Andric if (auto *II = dyn_cast<IntInit>(D->getArg(1))) { 1206480093f4SDimitry Andric Alignment = II->getValue(); 1207480093f4SDimitry Andric } else { 1208480093f4SDimitry Andric PrintFatalError("'address' alignment argument should be an integer"); 1209480093f4SDimitry Andric } 121081ad6265SDimitry Andric return std::make_shared<AddressResult>(Arg, Ty, Alignment); 1211480093f4SDimitry Andric } else if (Op->getName() == "unsignedflag") { 1212480093f4SDimitry Andric if (D->getNumArgs() != 1) 1213480093f4SDimitry Andric PrintFatalError("unsignedflag should have exactly one argument"); 1214480093f4SDimitry Andric Record *TypeRec = cast<DefInit>(D->getArg(0))->getDef(); 1215480093f4SDimitry Andric if (!TypeRec->isSubClassOf("Type")) 1216480093f4SDimitry Andric PrintFatalError("unsignedflag's argument should be a type"); 1217480093f4SDimitry Andric if (const auto *ST = dyn_cast<ScalarType>(getType(TypeRec, Param))) { 1218480093f4SDimitry Andric return std::make_shared<IntLiteralResult>( 1219480093f4SDimitry Andric getScalarType("u32"), ST->kind() == ScalarTypeKind::UnsignedInt); 1220480093f4SDimitry Andric } else { 1221480093f4SDimitry Andric PrintFatalError("unsignedflag's argument should be a scalar type"); 1222480093f4SDimitry Andric } 12235ffd83dbSDimitry Andric } else if (Op->getName() == "bitsize") { 12245ffd83dbSDimitry Andric if (D->getNumArgs() != 1) 12255ffd83dbSDimitry Andric PrintFatalError("bitsize should have exactly one argument"); 12265ffd83dbSDimitry Andric Record *TypeRec = cast<DefInit>(D->getArg(0))->getDef(); 12275ffd83dbSDimitry Andric if (!TypeRec->isSubClassOf("Type")) 12285ffd83dbSDimitry Andric PrintFatalError("bitsize's argument should be a type"); 12295ffd83dbSDimitry Andric if (const auto *ST = dyn_cast<ScalarType>(getType(TypeRec, Param))) { 12305ffd83dbSDimitry Andric return std::make_shared<IntLiteralResult>(getScalarType("u32"), 12315ffd83dbSDimitry Andric ST->sizeInBits()); 12325ffd83dbSDimitry Andric } else { 12335ffd83dbSDimitry Andric PrintFatalError("bitsize's argument should be a scalar type"); 12345ffd83dbSDimitry Andric } 1235480093f4SDimitry Andric } else { 1236480093f4SDimitry Andric std::vector<Result::Ptr> Args; 1237480093f4SDimitry Andric for (unsigned i = 0, e = D->getNumArgs(); i < e; ++i) 1238480093f4SDimitry Andric Args.push_back(getCodeForDagArg(D, i, Scope, Param)); 1239480093f4SDimitry Andric if (Op->isSubClassOf("IRBuilderBase")) { 1240480093f4SDimitry Andric std::set<unsigned> AddressArgs; 1241480093f4SDimitry Andric std::map<unsigned, std::string> IntegerArgs; 1242480093f4SDimitry Andric for (Record *sp : Op->getValueAsListOfDefs("special_params")) { 1243480093f4SDimitry Andric unsigned Index = sp->getValueAsInt("index"); 1244480093f4SDimitry Andric if (sp->isSubClassOf("IRBuilderAddrParam")) { 1245480093f4SDimitry Andric AddressArgs.insert(Index); 1246480093f4SDimitry Andric } else if (sp->isSubClassOf("IRBuilderIntParam")) { 12475ffd83dbSDimitry Andric IntegerArgs[Index] = std::string(sp->getValueAsString("type")); 1248480093f4SDimitry Andric } 1249480093f4SDimitry Andric } 1250480093f4SDimitry Andric return std::make_shared<IRBuilderResult>(Op->getValueAsString("prefix"), 1251480093f4SDimitry Andric Args, AddressArgs, IntegerArgs); 1252480093f4SDimitry Andric } else if (Op->isSubClassOf("IRIntBase")) { 1253480093f4SDimitry Andric std::vector<const Type *> ParamTypes; 1254480093f4SDimitry Andric for (Record *RParam : Op->getValueAsListOfDefs("params")) 1255480093f4SDimitry Andric ParamTypes.push_back(getType(RParam, Param)); 12565ffd83dbSDimitry Andric std::string IntName = std::string(Op->getValueAsString("intname")); 1257480093f4SDimitry Andric if (Op->getValueAsBit("appendKind")) 1258480093f4SDimitry Andric IntName += "_" + toLetter(cast<ScalarType>(Param)->kind()); 1259480093f4SDimitry Andric return std::make_shared<IRIntrinsicResult>(IntName, ParamTypes, Args); 1260480093f4SDimitry Andric } else { 1261480093f4SDimitry Andric PrintFatalError("Unsupported dag node " + Op->getName()); 1262480093f4SDimitry Andric } 1263480093f4SDimitry Andric } 1264480093f4SDimitry Andric } 1265480093f4SDimitry Andric 12665ffd83dbSDimitry Andric Result::Ptr EmitterBase::getCodeForDagArg(DagInit *D, unsigned ArgNum, 1267480093f4SDimitry Andric const Result::Scope &Scope, 1268480093f4SDimitry Andric const Type *Param) { 1269480093f4SDimitry Andric Init *Arg = D->getArg(ArgNum); 1270480093f4SDimitry Andric StringRef Name = D->getArgNameStr(ArgNum); 1271480093f4SDimitry Andric 1272480093f4SDimitry Andric if (!Name.empty()) { 1273480093f4SDimitry Andric if (!isa<UnsetInit>(Arg)) 1274480093f4SDimitry Andric PrintFatalError( 1275480093f4SDimitry Andric "dag operator argument should not have both a value and a name"); 12765ffd83dbSDimitry Andric auto it = Scope.find(std::string(Name)); 1277480093f4SDimitry Andric if (it == Scope.end()) 1278480093f4SDimitry Andric PrintFatalError("unrecognized variable name '" + Name + "'"); 1279480093f4SDimitry Andric return it->second; 1280480093f4SDimitry Andric } 1281480093f4SDimitry Andric 1282fe6060f1SDimitry Andric // Sometimes the Arg is a bit. Prior to multiclass template argument 1283fe6060f1SDimitry Andric // checking, integers would sneak through the bit declaration, 1284fe6060f1SDimitry Andric // but now they really are bits. 1285fe6060f1SDimitry Andric if (auto *BI = dyn_cast<BitInit>(Arg)) 1286fe6060f1SDimitry Andric return std::make_shared<IntLiteralResult>(getScalarType("u32"), 1287fe6060f1SDimitry Andric BI->getValue()); 1288fe6060f1SDimitry Andric 1289480093f4SDimitry Andric if (auto *II = dyn_cast<IntInit>(Arg)) 1290480093f4SDimitry Andric return std::make_shared<IntLiteralResult>(getScalarType("u32"), 1291480093f4SDimitry Andric II->getValue()); 1292480093f4SDimitry Andric 1293480093f4SDimitry Andric if (auto *DI = dyn_cast<DagInit>(Arg)) 1294480093f4SDimitry Andric return getCodeForDag(DI, Scope, Param); 1295480093f4SDimitry Andric 1296480093f4SDimitry Andric if (auto *DI = dyn_cast<DefInit>(Arg)) { 1297480093f4SDimitry Andric Record *Rec = DI->getDef(); 1298480093f4SDimitry Andric if (Rec->isSubClassOf("Type")) { 1299480093f4SDimitry Andric const Type *T = getType(Rec, Param); 1300480093f4SDimitry Andric return std::make_shared<TypeResult>(T); 1301480093f4SDimitry Andric } 1302480093f4SDimitry Andric } 1303480093f4SDimitry Andric 1304fe6060f1SDimitry Andric PrintError("bad DAG argument type for code generation"); 1305fe6060f1SDimitry Andric PrintNote("DAG: " + D->getAsString()); 1306fe6060f1SDimitry Andric if (TypedInit *Typed = dyn_cast<TypedInit>(Arg)) 1307fe6060f1SDimitry Andric PrintNote("argument type: " + Typed->getType()->getAsString()); 1308fe6060f1SDimitry Andric PrintFatalNote("argument number " + Twine(ArgNum) + ": " + Arg->getAsString()); 1309480093f4SDimitry Andric } 1310480093f4SDimitry Andric 13115ffd83dbSDimitry Andric Result::Ptr EmitterBase::getCodeForArg(unsigned ArgNum, const Type *ArgType, 1312480093f4SDimitry Andric bool Promote, bool Immediate) { 1313480093f4SDimitry Andric Result::Ptr V = std::make_shared<BuiltinArgResult>( 1314480093f4SDimitry Andric ArgNum, isa<PointerType>(ArgType), Immediate); 1315480093f4SDimitry Andric 1316480093f4SDimitry Andric if (Promote) { 1317480093f4SDimitry Andric if (const auto *ST = dyn_cast<ScalarType>(ArgType)) { 1318480093f4SDimitry Andric if (ST->isInteger() && ST->sizeInBits() < 32) 1319480093f4SDimitry Andric V = std::make_shared<IntCastResult>(getScalarType("u32"), V); 1320480093f4SDimitry Andric } else if (const auto *PT = dyn_cast<PredicateType>(ArgType)) { 1321480093f4SDimitry Andric V = std::make_shared<IntCastResult>(getScalarType("u32"), V); 1322480093f4SDimitry Andric V = std::make_shared<IRIntrinsicResult>("arm_mve_pred_i2v", 1323480093f4SDimitry Andric std::vector<const Type *>{PT}, 1324480093f4SDimitry Andric std::vector<Result::Ptr>{V}); 1325480093f4SDimitry Andric } 1326480093f4SDimitry Andric } 1327480093f4SDimitry Andric 1328480093f4SDimitry Andric return V; 1329480093f4SDimitry Andric } 1330480093f4SDimitry Andric 13315ffd83dbSDimitry Andric ACLEIntrinsic::ACLEIntrinsic(EmitterBase &ME, Record *R, const Type *Param) 1332480093f4SDimitry Andric : ReturnType(ME.getType(R->getValueAsDef("ret"), Param)) { 1333480093f4SDimitry Andric // Derive the intrinsic's full name, by taking the name of the 1334480093f4SDimitry Andric // Tablegen record (or override) and appending the suffix from its 1335480093f4SDimitry Andric // parameter type. (If the intrinsic is unparametrised, its 1336480093f4SDimitry Andric // parameter type will be given as Void, which returns the empty 1337480093f4SDimitry Andric // string for acleSuffix.) 1338480093f4SDimitry Andric StringRef BaseName = 1339480093f4SDimitry Andric (R->isSubClassOf("NameOverride") ? R->getValueAsString("basename") 1340480093f4SDimitry Andric : R->getName()); 1341480093f4SDimitry Andric StringRef overrideLetter = R->getValueAsString("overrideKindLetter"); 13425ffd83dbSDimitry Andric FullName = 13435ffd83dbSDimitry Andric (Twine(BaseName) + Param->acleSuffix(std::string(overrideLetter))).str(); 1344480093f4SDimitry Andric 1345480093f4SDimitry Andric // Derive the intrinsic's polymorphic name, by removing components from the 1346480093f4SDimitry Andric // full name as specified by its 'pnt' member ('polymorphic name type'), 1347480093f4SDimitry Andric // which indicates how many type suffixes to remove, and any other piece of 1348480093f4SDimitry Andric // the name that should be removed. 1349480093f4SDimitry Andric Record *PolymorphicNameType = R->getValueAsDef("pnt"); 1350480093f4SDimitry Andric SmallVector<StringRef, 8> NameParts; 1351480093f4SDimitry Andric StringRef(FullName).split(NameParts, '_'); 1352480093f4SDimitry Andric for (unsigned i = 0, e = PolymorphicNameType->getValueAsInt( 1353480093f4SDimitry Andric "NumTypeSuffixesToDiscard"); 1354480093f4SDimitry Andric i < e; ++i) 1355480093f4SDimitry Andric NameParts.pop_back(); 1356480093f4SDimitry Andric if (!PolymorphicNameType->isValueUnset("ExtraSuffixToDiscard")) { 1357480093f4SDimitry Andric StringRef ExtraSuffix = 1358480093f4SDimitry Andric PolymorphicNameType->getValueAsString("ExtraSuffixToDiscard"); 1359480093f4SDimitry Andric auto it = NameParts.end(); 1360480093f4SDimitry Andric while (it != NameParts.begin()) { 1361480093f4SDimitry Andric --it; 1362480093f4SDimitry Andric if (*it == ExtraSuffix) { 1363480093f4SDimitry Andric NameParts.erase(it); 1364480093f4SDimitry Andric break; 1365480093f4SDimitry Andric } 1366480093f4SDimitry Andric } 1367480093f4SDimitry Andric } 1368480093f4SDimitry Andric ShortName = join(std::begin(NameParts), std::end(NameParts), "_"); 1369480093f4SDimitry Andric 13705ffd83dbSDimitry Andric BuiltinExtension = R->getValueAsString("builtinExtension"); 13715ffd83dbSDimitry Andric 1372480093f4SDimitry Andric PolymorphicOnly = R->getValueAsBit("polymorphicOnly"); 1373480093f4SDimitry Andric NonEvaluating = R->getValueAsBit("nonEvaluating"); 13745ffd83dbSDimitry Andric HeaderOnly = R->getValueAsBit("headerOnly"); 1375480093f4SDimitry Andric 1376480093f4SDimitry Andric // Process the intrinsic's argument list. 1377480093f4SDimitry Andric DagInit *ArgsDag = R->getValueAsDag("args"); 1378480093f4SDimitry Andric Result::Scope Scope; 1379480093f4SDimitry Andric for (unsigned i = 0, e = ArgsDag->getNumArgs(); i < e; ++i) { 1380480093f4SDimitry Andric Init *TypeInit = ArgsDag->getArg(i); 1381480093f4SDimitry Andric 1382480093f4SDimitry Andric bool Promote = true; 1383480093f4SDimitry Andric if (auto TypeDI = dyn_cast<DefInit>(TypeInit)) 1384480093f4SDimitry Andric if (TypeDI->getDef()->isSubClassOf("unpromoted")) 1385480093f4SDimitry Andric Promote = false; 1386480093f4SDimitry Andric 1387480093f4SDimitry Andric // Work out the type of the argument, for use in the function prototype in 1388480093f4SDimitry Andric // the header file. 1389480093f4SDimitry Andric const Type *ArgType = ME.getType(TypeInit, Param); 1390480093f4SDimitry Andric ArgTypes.push_back(ArgType); 1391480093f4SDimitry Andric 1392480093f4SDimitry Andric // If the argument is a subclass of Immediate, record the details about 1393480093f4SDimitry Andric // what values it can take, for Sema checking. 1394480093f4SDimitry Andric bool Immediate = false; 1395480093f4SDimitry Andric if (auto TypeDI = dyn_cast<DefInit>(TypeInit)) { 1396480093f4SDimitry Andric Record *TypeRec = TypeDI->getDef(); 1397480093f4SDimitry Andric if (TypeRec->isSubClassOf("Immediate")) { 1398480093f4SDimitry Andric Immediate = true; 1399480093f4SDimitry Andric 1400480093f4SDimitry Andric Record *Bounds = TypeRec->getValueAsDef("bounds"); 1401480093f4SDimitry Andric ImmediateArg &IA = ImmediateArgs[i]; 1402480093f4SDimitry Andric if (Bounds->isSubClassOf("IB_ConstRange")) { 1403480093f4SDimitry Andric IA.boundsType = ImmediateArg::BoundsType::ExplicitRange; 1404480093f4SDimitry Andric IA.i1 = Bounds->getValueAsInt("lo"); 1405480093f4SDimitry Andric IA.i2 = Bounds->getValueAsInt("hi"); 1406480093f4SDimitry Andric } else if (Bounds->getName() == "IB_UEltValue") { 1407480093f4SDimitry Andric IA.boundsType = ImmediateArg::BoundsType::UInt; 1408480093f4SDimitry Andric IA.i1 = Param->sizeInBits(); 1409480093f4SDimitry Andric } else if (Bounds->getName() == "IB_LaneIndex") { 1410480093f4SDimitry Andric IA.boundsType = ImmediateArg::BoundsType::ExplicitRange; 1411480093f4SDimitry Andric IA.i1 = 0; 1412480093f4SDimitry Andric IA.i2 = 128 / Param->sizeInBits() - 1; 1413480093f4SDimitry Andric } else if (Bounds->isSubClassOf("IB_EltBit")) { 1414480093f4SDimitry Andric IA.boundsType = ImmediateArg::BoundsType::ExplicitRange; 1415480093f4SDimitry Andric IA.i1 = Bounds->getValueAsInt("base"); 1416480093f4SDimitry Andric const Type *T = ME.getType(Bounds->getValueAsDef("type"), Param); 1417480093f4SDimitry Andric IA.i2 = IA.i1 + T->sizeInBits() - 1; 1418480093f4SDimitry Andric } else { 1419480093f4SDimitry Andric PrintFatalError("unrecognised ImmediateBounds subclass"); 1420480093f4SDimitry Andric } 1421480093f4SDimitry Andric 1422480093f4SDimitry Andric IA.ArgType = ArgType; 1423480093f4SDimitry Andric 1424480093f4SDimitry Andric if (!TypeRec->isValueUnset("extra")) { 1425480093f4SDimitry Andric IA.ExtraCheckType = TypeRec->getValueAsString("extra"); 1426480093f4SDimitry Andric if (!TypeRec->isValueUnset("extraarg")) 1427480093f4SDimitry Andric IA.ExtraCheckArgs = TypeRec->getValueAsString("extraarg"); 1428480093f4SDimitry Andric } 1429480093f4SDimitry Andric } 1430480093f4SDimitry Andric } 1431480093f4SDimitry Andric 1432480093f4SDimitry Andric // The argument will usually have a name in the arguments dag, which goes 1433480093f4SDimitry Andric // into the variable-name scope that the code gen will refer to. 1434480093f4SDimitry Andric StringRef ArgName = ArgsDag->getArgNameStr(i); 1435480093f4SDimitry Andric if (!ArgName.empty()) 14365ffd83dbSDimitry Andric Scope[std::string(ArgName)] = 14375ffd83dbSDimitry Andric ME.getCodeForArg(i, ArgType, Promote, Immediate); 1438480093f4SDimitry Andric } 1439480093f4SDimitry Andric 1440480093f4SDimitry Andric // Finally, go through the codegen dag and translate it into a Result object 1441480093f4SDimitry Andric // (with an arbitrary DAG of depended-on Results hanging off it). 1442480093f4SDimitry Andric DagInit *CodeDag = R->getValueAsDag("codegen"); 1443480093f4SDimitry Andric Record *MainOp = cast<DefInit>(CodeDag->getOperator())->getDef(); 1444480093f4SDimitry Andric if (MainOp->isSubClassOf("CustomCodegen")) { 1445480093f4SDimitry Andric // Or, if it's the special case of CustomCodegen, just accumulate 1446480093f4SDimitry Andric // a list of parameters we're going to assign to variables before 1447480093f4SDimitry Andric // breaking from the loop. 1448480093f4SDimitry Andric CustomCodeGenArgs["CustomCodeGenType"] = 1449480093f4SDimitry Andric (Twine("CustomCodeGen::") + MainOp->getValueAsString("type")).str(); 1450480093f4SDimitry Andric for (unsigned i = 0, e = CodeDag->getNumArgs(); i < e; ++i) { 1451480093f4SDimitry Andric StringRef Name = CodeDag->getArgNameStr(i); 1452480093f4SDimitry Andric if (Name.empty()) { 1453480093f4SDimitry Andric PrintFatalError("Operands to CustomCodegen should have names"); 1454480093f4SDimitry Andric } else if (auto *II = dyn_cast<IntInit>(CodeDag->getArg(i))) { 14555ffd83dbSDimitry Andric CustomCodeGenArgs[std::string(Name)] = itostr(II->getValue()); 1456480093f4SDimitry Andric } else if (auto *SI = dyn_cast<StringInit>(CodeDag->getArg(i))) { 14575ffd83dbSDimitry Andric CustomCodeGenArgs[std::string(Name)] = std::string(SI->getValue()); 1458480093f4SDimitry Andric } else { 1459480093f4SDimitry Andric PrintFatalError("Operands to CustomCodegen should be integers"); 1460480093f4SDimitry Andric } 1461480093f4SDimitry Andric } 1462480093f4SDimitry Andric } else { 1463480093f4SDimitry Andric Code = ME.getCodeForDag(CodeDag, Scope, Param); 1464480093f4SDimitry Andric } 1465480093f4SDimitry Andric } 1466480093f4SDimitry Andric 14675ffd83dbSDimitry Andric EmitterBase::EmitterBase(RecordKeeper &Records) { 14685ffd83dbSDimitry Andric // Construct the whole EmitterBase. 1469480093f4SDimitry Andric 1470480093f4SDimitry Andric // First, look up all the instances of PrimitiveType. This gives us the list 1471480093f4SDimitry Andric // of vector typedefs we have to put in arm_mve.h, and also allows us to 1472480093f4SDimitry Andric // collect all the useful ScalarType instances into a big list so that we can 1473480093f4SDimitry Andric // use it for operations such as 'find the unsigned version of this signed 1474480093f4SDimitry Andric // integer type'. 1475480093f4SDimitry Andric for (Record *R : Records.getAllDerivedDefinitions("PrimitiveType")) 14765ffd83dbSDimitry Andric ScalarTypes[std::string(R->getName())] = std::make_unique<ScalarType>(R); 1477480093f4SDimitry Andric 1478480093f4SDimitry Andric // Now go through the instances of Intrinsic, and for each one, iterate 1479480093f4SDimitry Andric // through its list of type parameters making an ACLEIntrinsic for each one. 1480480093f4SDimitry Andric for (Record *R : Records.getAllDerivedDefinitions("Intrinsic")) { 1481480093f4SDimitry Andric for (Record *RParam : R->getValueAsListOfDefs("params")) { 1482480093f4SDimitry Andric const Type *Param = getType(RParam, getVoidType()); 1483480093f4SDimitry Andric auto Intrinsic = std::make_unique<ACLEIntrinsic>(*this, R, Param); 1484480093f4SDimitry Andric ACLEIntrinsics[Intrinsic->fullName()] = std::move(Intrinsic); 1485480093f4SDimitry Andric } 1486480093f4SDimitry Andric } 1487480093f4SDimitry Andric } 1488480093f4SDimitry Andric 1489480093f4SDimitry Andric /// A wrapper on raw_string_ostream that contains its own buffer rather than 1490480093f4SDimitry Andric /// having to point it at one elsewhere. (In other words, it works just like 1491480093f4SDimitry Andric /// std::ostringstream; also, this makes it convenient to declare a whole array 1492480093f4SDimitry Andric /// of them at once.) 1493480093f4SDimitry Andric /// 1494480093f4SDimitry Andric /// We have to set this up using multiple inheritance, to ensure that the 1495480093f4SDimitry Andric /// string member has been constructed before raw_string_ostream's constructor 1496480093f4SDimitry Andric /// is given a pointer to it. 1497480093f4SDimitry Andric class string_holder { 1498480093f4SDimitry Andric protected: 1499480093f4SDimitry Andric std::string S; 1500480093f4SDimitry Andric }; 1501480093f4SDimitry Andric class raw_self_contained_string_ostream : private string_holder, 1502480093f4SDimitry Andric public raw_string_ostream { 1503480093f4SDimitry Andric public: 150404eeddc0SDimitry Andric raw_self_contained_string_ostream() : raw_string_ostream(S) {} 1505480093f4SDimitry Andric }; 1506480093f4SDimitry Andric 15075ffd83dbSDimitry Andric const char LLVMLicenseHeader[] = 1508480093f4SDimitry Andric " *\n" 1509480093f4SDimitry Andric " *\n" 1510480093f4SDimitry Andric " * Part of the LLVM Project, under the Apache License v2.0 with LLVM" 1511480093f4SDimitry Andric " Exceptions.\n" 1512480093f4SDimitry Andric " * See https://llvm.org/LICENSE.txt for license information.\n" 1513480093f4SDimitry Andric " * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception\n" 1514480093f4SDimitry Andric " *\n" 15155ffd83dbSDimitry Andric " *===-----------------------------------------------------------------" 1516480093f4SDimitry Andric "------===\n" 1517480093f4SDimitry Andric " */\n" 1518480093f4SDimitry Andric "\n"; 1519480093f4SDimitry Andric 1520480093f4SDimitry Andric // Machinery for the grouping of intrinsics by similar codegen. 1521480093f4SDimitry Andric // 1522480093f4SDimitry Andric // The general setup is that 'MergeableGroup' stores the things that a set of 1523480093f4SDimitry Andric // similarly shaped intrinsics have in common: the text of their code 1524480093f4SDimitry Andric // generation, and the number and type of their parameter variables. 1525480093f4SDimitry Andric // MergeableGroup is the key in a std::map whose value is a set of 1526480093f4SDimitry Andric // OutputIntrinsic, which stores the ways in which a particular intrinsic 1527480093f4SDimitry Andric // specializes the MergeableGroup's generic description: the function name and 1528480093f4SDimitry Andric // the _values_ of the parameter variables. 1529480093f4SDimitry Andric 1530480093f4SDimitry Andric struct ComparableStringVector : std::vector<std::string> { 1531480093f4SDimitry Andric // Infrastructure: a derived class of vector<string> which comes with an 1532480093f4SDimitry Andric // ordering, so that it can be used as a key in maps and an element in sets. 1533480093f4SDimitry Andric // There's no requirement on the ordering beyond being deterministic. 1534480093f4SDimitry Andric bool operator<(const ComparableStringVector &rhs) const { 1535480093f4SDimitry Andric if (size() != rhs.size()) 1536480093f4SDimitry Andric return size() < rhs.size(); 1537480093f4SDimitry Andric for (size_t i = 0, e = size(); i < e; ++i) 1538480093f4SDimitry Andric if ((*this)[i] != rhs[i]) 1539480093f4SDimitry Andric return (*this)[i] < rhs[i]; 1540480093f4SDimitry Andric return false; 1541480093f4SDimitry Andric } 1542480093f4SDimitry Andric }; 1543480093f4SDimitry Andric 1544480093f4SDimitry Andric struct OutputIntrinsic { 1545480093f4SDimitry Andric const ACLEIntrinsic *Int; 1546480093f4SDimitry Andric std::string Name; 1547480093f4SDimitry Andric ComparableStringVector ParamValues; 1548480093f4SDimitry Andric bool operator<(const OutputIntrinsic &rhs) const { 1549480093f4SDimitry Andric if (Name != rhs.Name) 1550480093f4SDimitry Andric return Name < rhs.Name; 1551480093f4SDimitry Andric return ParamValues < rhs.ParamValues; 1552480093f4SDimitry Andric } 1553480093f4SDimitry Andric }; 1554480093f4SDimitry Andric struct MergeableGroup { 1555480093f4SDimitry Andric std::string Code; 1556480093f4SDimitry Andric ComparableStringVector ParamTypes; 1557480093f4SDimitry Andric bool operator<(const MergeableGroup &rhs) const { 1558480093f4SDimitry Andric if (Code != rhs.Code) 1559480093f4SDimitry Andric return Code < rhs.Code; 1560480093f4SDimitry Andric return ParamTypes < rhs.ParamTypes; 1561480093f4SDimitry Andric } 1562480093f4SDimitry Andric }; 1563480093f4SDimitry Andric 15645ffd83dbSDimitry Andric void EmitterBase::EmitBuiltinCG(raw_ostream &OS) { 1565480093f4SDimitry Andric // Pass 1: generate code for all the intrinsics as if every type or constant 1566480093f4SDimitry Andric // that can possibly be abstracted out into a parameter variable will be. 1567480093f4SDimitry Andric // This identifies the sets of intrinsics we'll group together into a single 1568480093f4SDimitry Andric // piece of code generation. 1569480093f4SDimitry Andric 1570480093f4SDimitry Andric std::map<MergeableGroup, std::set<OutputIntrinsic>> MergeableGroupsPrelim; 1571480093f4SDimitry Andric 1572480093f4SDimitry Andric for (const auto &kv : ACLEIntrinsics) { 1573480093f4SDimitry Andric const ACLEIntrinsic &Int = *kv.second; 15745ffd83dbSDimitry Andric if (Int.headerOnly()) 15755ffd83dbSDimitry Andric continue; 1576480093f4SDimitry Andric 1577480093f4SDimitry Andric MergeableGroup MG; 1578480093f4SDimitry Andric OutputIntrinsic OI; 1579480093f4SDimitry Andric 1580480093f4SDimitry Andric OI.Int = ∬ 1581480093f4SDimitry Andric OI.Name = Int.fullName(); 1582480093f4SDimitry Andric CodeGenParamAllocator ParamAllocPrelim{&MG.ParamTypes, &OI.ParamValues}; 1583480093f4SDimitry Andric raw_string_ostream OS(MG.Code); 1584480093f4SDimitry Andric Int.genCode(OS, ParamAllocPrelim, 1); 1585480093f4SDimitry Andric OS.flush(); 1586480093f4SDimitry Andric 1587480093f4SDimitry Andric MergeableGroupsPrelim[MG].insert(OI); 1588480093f4SDimitry Andric } 1589480093f4SDimitry Andric 1590480093f4SDimitry Andric // Pass 2: for each of those groups, optimize the parameter variable set by 1591480093f4SDimitry Andric // eliminating 'parameters' that are the same for all intrinsics in the 1592480093f4SDimitry Andric // group, and merging together pairs of parameter variables that take the 1593480093f4SDimitry Andric // same values as each other for all intrinsics in the group. 1594480093f4SDimitry Andric 1595480093f4SDimitry Andric std::map<MergeableGroup, std::set<OutputIntrinsic>> MergeableGroups; 1596480093f4SDimitry Andric 1597480093f4SDimitry Andric for (const auto &kv : MergeableGroupsPrelim) { 1598480093f4SDimitry Andric const MergeableGroup &MG = kv.first; 1599480093f4SDimitry Andric std::vector<int> ParamNumbers; 1600480093f4SDimitry Andric std::map<ComparableStringVector, int> ParamNumberMap; 1601480093f4SDimitry Andric 1602480093f4SDimitry Andric // Loop over the parameters for this group. 1603480093f4SDimitry Andric for (size_t i = 0, e = MG.ParamTypes.size(); i < e; ++i) { 1604480093f4SDimitry Andric // Is this parameter the same for all intrinsics in the group? 1605480093f4SDimitry Andric const OutputIntrinsic &OI_first = *kv.second.begin(); 1606480093f4SDimitry Andric bool Constant = all_of(kv.second, [&](const OutputIntrinsic &OI) { 1607480093f4SDimitry Andric return OI.ParamValues[i] == OI_first.ParamValues[i]; 1608480093f4SDimitry Andric }); 1609480093f4SDimitry Andric 1610480093f4SDimitry Andric // If so, record it as -1, meaning 'no parameter variable needed'. Then 1611480093f4SDimitry Andric // the corresponding call to allocParam in pass 2 will not generate a 1612480093f4SDimitry Andric // variable at all, and just use the value inline. 1613480093f4SDimitry Andric if (Constant) { 1614480093f4SDimitry Andric ParamNumbers.push_back(-1); 1615480093f4SDimitry Andric continue; 1616480093f4SDimitry Andric } 1617480093f4SDimitry Andric 1618480093f4SDimitry Andric // Otherwise, make a list of the values this parameter takes for each 1619480093f4SDimitry Andric // intrinsic, and see if that value vector matches anything we already 1620480093f4SDimitry Andric // have. We also record the parameter type, so that we don't accidentally 1621480093f4SDimitry Andric // match up two parameter variables with different types. (Not that 1622480093f4SDimitry Andric // there's much chance of them having textually equivalent values, but in 1623480093f4SDimitry Andric // _principle_ it could happen.) 1624480093f4SDimitry Andric ComparableStringVector key; 1625480093f4SDimitry Andric key.push_back(MG.ParamTypes[i]); 1626480093f4SDimitry Andric for (const auto &OI : kv.second) 1627480093f4SDimitry Andric key.push_back(OI.ParamValues[i]); 1628480093f4SDimitry Andric 1629480093f4SDimitry Andric auto Found = ParamNumberMap.find(key); 1630480093f4SDimitry Andric if (Found != ParamNumberMap.end()) { 1631480093f4SDimitry Andric // Yes, an existing parameter variable can be reused for this. 1632480093f4SDimitry Andric ParamNumbers.push_back(Found->second); 1633480093f4SDimitry Andric continue; 1634480093f4SDimitry Andric } 1635480093f4SDimitry Andric 1636480093f4SDimitry Andric // No, we need a new parameter variable. 1637480093f4SDimitry Andric int ExistingIndex = ParamNumberMap.size(); 1638480093f4SDimitry Andric ParamNumberMap[key] = ExistingIndex; 1639480093f4SDimitry Andric ParamNumbers.push_back(ExistingIndex); 1640480093f4SDimitry Andric } 1641480093f4SDimitry Andric 1642480093f4SDimitry Andric // Now we're ready to do the pass 2 code generation, which will emit the 1643480093f4SDimitry Andric // reduced set of parameter variables we've just worked out. 1644480093f4SDimitry Andric 1645480093f4SDimitry Andric for (const auto &OI_prelim : kv.second) { 1646480093f4SDimitry Andric const ACLEIntrinsic *Int = OI_prelim.Int; 1647480093f4SDimitry Andric 1648480093f4SDimitry Andric MergeableGroup MG; 1649480093f4SDimitry Andric OutputIntrinsic OI; 1650480093f4SDimitry Andric 1651480093f4SDimitry Andric OI.Int = OI_prelim.Int; 1652480093f4SDimitry Andric OI.Name = OI_prelim.Name; 1653480093f4SDimitry Andric CodeGenParamAllocator ParamAlloc{&MG.ParamTypes, &OI.ParamValues, 1654480093f4SDimitry Andric &ParamNumbers}; 1655480093f4SDimitry Andric raw_string_ostream OS(MG.Code); 1656480093f4SDimitry Andric Int->genCode(OS, ParamAlloc, 2); 1657480093f4SDimitry Andric OS.flush(); 1658480093f4SDimitry Andric 1659480093f4SDimitry Andric MergeableGroups[MG].insert(OI); 1660480093f4SDimitry Andric } 1661480093f4SDimitry Andric } 1662480093f4SDimitry Andric 1663480093f4SDimitry Andric // Output the actual C++ code. 1664480093f4SDimitry Andric 1665480093f4SDimitry Andric for (const auto &kv : MergeableGroups) { 1666480093f4SDimitry Andric const MergeableGroup &MG = kv.first; 1667480093f4SDimitry Andric 1668480093f4SDimitry Andric // List of case statements in the main switch on BuiltinID, and an open 1669480093f4SDimitry Andric // brace. 1670480093f4SDimitry Andric const char *prefix = ""; 1671480093f4SDimitry Andric for (const auto &OI : kv.second) { 16725ffd83dbSDimitry Andric OS << prefix << "case ARM::BI__builtin_arm_" << OI.Int->builtinExtension() 16735ffd83dbSDimitry Andric << "_" << OI.Name << ":"; 16745ffd83dbSDimitry Andric 1675480093f4SDimitry Andric prefix = "\n"; 1676480093f4SDimitry Andric } 1677480093f4SDimitry Andric OS << " {\n"; 1678480093f4SDimitry Andric 1679480093f4SDimitry Andric if (!MG.ParamTypes.empty()) { 1680480093f4SDimitry Andric // If we've got some parameter variables, then emit their declarations... 1681480093f4SDimitry Andric for (size_t i = 0, e = MG.ParamTypes.size(); i < e; ++i) { 1682480093f4SDimitry Andric StringRef Type = MG.ParamTypes[i]; 1683480093f4SDimitry Andric OS << " " << Type; 16845f757f3fSDimitry Andric if (!Type.ends_with("*")) 1685480093f4SDimitry Andric OS << " "; 1686480093f4SDimitry Andric OS << " Param" << utostr(i) << ";\n"; 1687480093f4SDimitry Andric } 1688480093f4SDimitry Andric 1689480093f4SDimitry Andric // ... and an inner switch on BuiltinID that will fill them in with each 1690480093f4SDimitry Andric // individual intrinsic's values. 1691480093f4SDimitry Andric OS << " switch (BuiltinID) {\n"; 1692480093f4SDimitry Andric for (const auto &OI : kv.second) { 16935ffd83dbSDimitry Andric OS << " case ARM::BI__builtin_arm_" << OI.Int->builtinExtension() 16945ffd83dbSDimitry Andric << "_" << OI.Name << ":\n"; 1695480093f4SDimitry Andric for (size_t i = 0, e = MG.ParamTypes.size(); i < e; ++i) 1696480093f4SDimitry Andric OS << " Param" << utostr(i) << " = " << OI.ParamValues[i] << ";\n"; 1697480093f4SDimitry Andric OS << " break;\n"; 1698480093f4SDimitry Andric } 1699480093f4SDimitry Andric OS << " }\n"; 1700480093f4SDimitry Andric } 1701480093f4SDimitry Andric 1702480093f4SDimitry Andric // And finally, output the code, and close the outer pair of braces. (The 1703480093f4SDimitry Andric // code will always end with a 'return' statement, so we need not insert a 1704480093f4SDimitry Andric // 'break' here.) 1705480093f4SDimitry Andric OS << MG.Code << "}\n"; 1706480093f4SDimitry Andric } 1707480093f4SDimitry Andric } 1708480093f4SDimitry Andric 17095ffd83dbSDimitry Andric void EmitterBase::EmitBuiltinAliases(raw_ostream &OS) { 17105ffd83dbSDimitry Andric // Build a sorted table of: 17115ffd83dbSDimitry Andric // - intrinsic id number 17125ffd83dbSDimitry Andric // - full name 17135ffd83dbSDimitry Andric // - polymorphic name or -1 17145ffd83dbSDimitry Andric StringToOffsetTable StringTable; 17155ffd83dbSDimitry Andric OS << "static const IntrinToName MapData[] = {\n"; 1716480093f4SDimitry Andric for (const auto &kv : ACLEIntrinsics) { 1717480093f4SDimitry Andric const ACLEIntrinsic &Int = *kv.second; 17185ffd83dbSDimitry Andric if (Int.headerOnly()) 17195ffd83dbSDimitry Andric continue; 17205ffd83dbSDimitry Andric int32_t ShortNameOffset = 17215ffd83dbSDimitry Andric Int.polymorphic() ? StringTable.GetOrAddStringOffset(Int.shortName()) 17225ffd83dbSDimitry Andric : -1; 17235ffd83dbSDimitry Andric OS << " { ARM::BI__builtin_arm_" << Int.builtinExtension() << "_" 17245ffd83dbSDimitry Andric << Int.fullName() << ", " 17255ffd83dbSDimitry Andric << StringTable.GetOrAddStringOffset(Int.fullName()) << ", " 17265ffd83dbSDimitry Andric << ShortNameOffset << "},\n"; 17275ffd83dbSDimitry Andric } 17285ffd83dbSDimitry Andric OS << "};\n\n"; 17295ffd83dbSDimitry Andric 17305ffd83dbSDimitry Andric OS << "ArrayRef<IntrinToName> Map(MapData);\n\n"; 17315ffd83dbSDimitry Andric 17325ffd83dbSDimitry Andric OS << "static const char IntrinNames[] = {\n"; 17335ffd83dbSDimitry Andric StringTable.EmitString(OS); 17345ffd83dbSDimitry Andric OS << "};\n\n"; 17355ffd83dbSDimitry Andric } 17365ffd83dbSDimitry Andric 17375ffd83dbSDimitry Andric void EmitterBase::GroupSemaChecks( 17385ffd83dbSDimitry Andric std::map<std::string, std::set<std::string>> &Checks) { 17395ffd83dbSDimitry Andric for (const auto &kv : ACLEIntrinsics) { 17405ffd83dbSDimitry Andric const ACLEIntrinsic &Int = *kv.second; 17415ffd83dbSDimitry Andric if (Int.headerOnly()) 17425ffd83dbSDimitry Andric continue; 17435ffd83dbSDimitry Andric std::string Check = Int.genSema(); 17445ffd83dbSDimitry Andric if (!Check.empty()) 17455ffd83dbSDimitry Andric Checks[Check].insert(Int.fullName()); 17465ffd83dbSDimitry Andric } 17475ffd83dbSDimitry Andric } 17485ffd83dbSDimitry Andric 17495ffd83dbSDimitry Andric // ----------------------------------------------------------------------------- 17505ffd83dbSDimitry Andric // The class used for generating arm_mve.h and related Clang bits 17515ffd83dbSDimitry Andric // 17525ffd83dbSDimitry Andric 17535ffd83dbSDimitry Andric class MveEmitter : public EmitterBase { 17545ffd83dbSDimitry Andric public: 17555ffd83dbSDimitry Andric MveEmitter(RecordKeeper &Records) : EmitterBase(Records){}; 17565ffd83dbSDimitry Andric void EmitHeader(raw_ostream &OS) override; 17575ffd83dbSDimitry Andric void EmitBuiltinDef(raw_ostream &OS) override; 17585ffd83dbSDimitry Andric void EmitBuiltinSema(raw_ostream &OS) override; 17595ffd83dbSDimitry Andric }; 17605ffd83dbSDimitry Andric 17615ffd83dbSDimitry Andric void MveEmitter::EmitHeader(raw_ostream &OS) { 17625ffd83dbSDimitry Andric // Accumulate pieces of the header file that will be enabled under various 17635ffd83dbSDimitry Andric // different combinations of #ifdef. The index into parts[] is made up of 17645ffd83dbSDimitry Andric // the following bit flags. 17655ffd83dbSDimitry Andric constexpr unsigned Float = 1; 17665ffd83dbSDimitry Andric constexpr unsigned UseUserNamespace = 2; 17675ffd83dbSDimitry Andric 17685ffd83dbSDimitry Andric constexpr unsigned NumParts = 4; 17695ffd83dbSDimitry Andric raw_self_contained_string_ostream parts[NumParts]; 17705ffd83dbSDimitry Andric 17715ffd83dbSDimitry Andric // Write typedefs for all the required vector types, and a few scalar 17725ffd83dbSDimitry Andric // types that don't already have the name we want them to have. 17735ffd83dbSDimitry Andric 17745ffd83dbSDimitry Andric parts[0] << "typedef uint16_t mve_pred16_t;\n"; 17755ffd83dbSDimitry Andric parts[Float] << "typedef __fp16 float16_t;\n" 17765ffd83dbSDimitry Andric "typedef float float32_t;\n"; 17775ffd83dbSDimitry Andric for (const auto &kv : ScalarTypes) { 17785ffd83dbSDimitry Andric const ScalarType *ST = kv.second.get(); 17795ffd83dbSDimitry Andric if (ST->hasNonstandardName()) 17805ffd83dbSDimitry Andric continue; 17815ffd83dbSDimitry Andric raw_ostream &OS = parts[ST->requiresFloat() ? Float : 0]; 17825ffd83dbSDimitry Andric const VectorType *VT = getVectorType(ST); 17835ffd83dbSDimitry Andric 17845ffd83dbSDimitry Andric OS << "typedef __attribute__((__neon_vector_type__(" << VT->lanes() 17855ffd83dbSDimitry Andric << "), __clang_arm_mve_strict_polymorphism)) " << ST->cName() << " " 17865ffd83dbSDimitry Andric << VT->cName() << ";\n"; 17875ffd83dbSDimitry Andric 17885ffd83dbSDimitry Andric // Every vector type also comes with a pair of multi-vector types for 17895ffd83dbSDimitry Andric // the VLD2 and VLD4 instructions. 17905ffd83dbSDimitry Andric for (unsigned n = 2; n <= 4; n += 2) { 17915ffd83dbSDimitry Andric const MultiVectorType *MT = getMultiVectorType(n, VT); 17925ffd83dbSDimitry Andric OS << "typedef struct { " << VT->cName() << " val[" << n << "]; } " 17935ffd83dbSDimitry Andric << MT->cName() << ";\n"; 17945ffd83dbSDimitry Andric } 17955ffd83dbSDimitry Andric } 17965ffd83dbSDimitry Andric parts[0] << "\n"; 17975ffd83dbSDimitry Andric parts[Float] << "\n"; 17985ffd83dbSDimitry Andric 17995ffd83dbSDimitry Andric // Write declarations for all the intrinsics. 18005ffd83dbSDimitry Andric 18015ffd83dbSDimitry Andric for (const auto &kv : ACLEIntrinsics) { 18025ffd83dbSDimitry Andric const ACLEIntrinsic &Int = *kv.second; 18035ffd83dbSDimitry Andric 18045ffd83dbSDimitry Andric // We generate each intrinsic twice, under its full unambiguous 18055ffd83dbSDimitry Andric // name and its shorter polymorphic name (if the latter exists). 18065ffd83dbSDimitry Andric for (bool Polymorphic : {false, true}) { 18075ffd83dbSDimitry Andric if (Polymorphic && !Int.polymorphic()) 18085ffd83dbSDimitry Andric continue; 18095ffd83dbSDimitry Andric if (!Polymorphic && Int.polymorphicOnly()) 18105ffd83dbSDimitry Andric continue; 18115ffd83dbSDimitry Andric 18125ffd83dbSDimitry Andric // We also generate each intrinsic under a name like __arm_vfooq 18135ffd83dbSDimitry Andric // (which is in C language implementation namespace, so it's 18145ffd83dbSDimitry Andric // safe to define in any conforming user program) and a shorter 18155ffd83dbSDimitry Andric // one like vfooq (which is in user namespace, so a user might 18165ffd83dbSDimitry Andric // reasonably have used it for something already). If so, they 18175ffd83dbSDimitry Andric // can #define __ARM_MVE_PRESERVE_USER_NAMESPACE before 18185ffd83dbSDimitry Andric // including the header, which will suppress the shorter names 18195ffd83dbSDimitry Andric // and leave only the implementation-namespace ones. Then they 18205ffd83dbSDimitry Andric // have to write __arm_vfooq everywhere, of course. 18215ffd83dbSDimitry Andric 18225ffd83dbSDimitry Andric for (bool UserNamespace : {false, true}) { 18235ffd83dbSDimitry Andric raw_ostream &OS = parts[(Int.requiresFloat() ? Float : 0) | 18245ffd83dbSDimitry Andric (UserNamespace ? UseUserNamespace : 0)]; 18255ffd83dbSDimitry Andric 18265ffd83dbSDimitry Andric // Make the name of the function in this declaration. 18275ffd83dbSDimitry Andric 18285ffd83dbSDimitry Andric std::string FunctionName = 18295ffd83dbSDimitry Andric Polymorphic ? Int.shortName() : Int.fullName(); 18305ffd83dbSDimitry Andric if (!UserNamespace) 18315ffd83dbSDimitry Andric FunctionName = "__arm_" + FunctionName; 18325ffd83dbSDimitry Andric 18335ffd83dbSDimitry Andric // Make strings for the types involved in the function's 18345ffd83dbSDimitry Andric // prototype. 18355ffd83dbSDimitry Andric 18365ffd83dbSDimitry Andric std::string RetTypeName = Int.returnType()->cName(); 18375f757f3fSDimitry Andric if (!StringRef(RetTypeName).ends_with("*")) 18385ffd83dbSDimitry Andric RetTypeName += " "; 18395ffd83dbSDimitry Andric 18405ffd83dbSDimitry Andric std::vector<std::string> ArgTypeNames; 18415ffd83dbSDimitry Andric for (const Type *ArgTypePtr : Int.argTypes()) 18425ffd83dbSDimitry Andric ArgTypeNames.push_back(ArgTypePtr->cName()); 18435ffd83dbSDimitry Andric std::string ArgTypesString = 18445ffd83dbSDimitry Andric join(std::begin(ArgTypeNames), std::end(ArgTypeNames), ", "); 18455ffd83dbSDimitry Andric 18465ffd83dbSDimitry Andric // Emit the actual declaration. All these functions are 18475ffd83dbSDimitry Andric // declared 'static inline' without a body, which is fine 18485ffd83dbSDimitry Andric // provided clang recognizes them as builtins, and has the 18495ffd83dbSDimitry Andric // effect that this type signature is used in place of the one 1850*0fca6ea1SDimitry Andric // that Builtins.td didn't provide. That's how we can get 18515ffd83dbSDimitry Andric // structure types that weren't defined until this header was 18525ffd83dbSDimitry Andric // included to be part of the type signature of a builtin that 18535ffd83dbSDimitry Andric // was known to clang already. 18545ffd83dbSDimitry Andric // 18555ffd83dbSDimitry Andric // The declarations use __attribute__(__clang_arm_builtin_alias), 18565ffd83dbSDimitry Andric // so that each function declared will be recognized as the 18575ffd83dbSDimitry Andric // appropriate MVE builtin in spite of its user-facing name. 18585ffd83dbSDimitry Andric // 18595ffd83dbSDimitry Andric // (That's better than making them all wrapper functions, 18605ffd83dbSDimitry Andric // partly because it avoids any compiler error message citing 18615ffd83dbSDimitry Andric // the wrapper function definition instead of the user's code, 18625ffd83dbSDimitry Andric // and mostly because some MVE intrinsics have arguments 18635ffd83dbSDimitry Andric // required to be compile-time constants, and that property 18645ffd83dbSDimitry Andric // can't be propagated through a wrapper function. It can be 18655ffd83dbSDimitry Andric // propagated through a macro, but macros can't be overloaded 18665ffd83dbSDimitry Andric // on argument types very easily - you have to use _Generic, 18675ffd83dbSDimitry Andric // which makes error messages very confusing when the user 18685ffd83dbSDimitry Andric // gets it wrong.) 18695ffd83dbSDimitry Andric // 18705ffd83dbSDimitry Andric // Finally, the polymorphic versions of the intrinsics are 18715ffd83dbSDimitry Andric // also defined with __attribute__(overloadable), so that when 18725ffd83dbSDimitry Andric // the same name is defined with several type signatures, the 18735ffd83dbSDimitry Andric // right thing happens. Each one of the overloaded 18745ffd83dbSDimitry Andric // declarations is given a different builtin id, which 18755ffd83dbSDimitry Andric // has exactly the effect we want: first clang resolves the 18765ffd83dbSDimitry Andric // overload to the right function, then it knows which builtin 18775ffd83dbSDimitry Andric // it's referring to, and then the Sema checking for that 18785ffd83dbSDimitry Andric // builtin can check further things like the constant 18795ffd83dbSDimitry Andric // arguments. 18805ffd83dbSDimitry Andric // 18815ffd83dbSDimitry Andric // One more subtlety is the newline just before the return 18825ffd83dbSDimitry Andric // type name. That's a cosmetic tweak to make the error 18835ffd83dbSDimitry Andric // messages legible if the user gets the types wrong in a call 18845ffd83dbSDimitry Andric // to a polymorphic function: this way, clang will print just 18855ffd83dbSDimitry Andric // the _final_ line of each declaration in the header, to show 18865ffd83dbSDimitry Andric // the type signatures that would have been legal. So all the 18875ffd83dbSDimitry Andric // confusing machinery with __attribute__ is left out of the 18885ffd83dbSDimitry Andric // error message, and the user sees something that's more or 18895ffd83dbSDimitry Andric // less self-documenting: "here's a list of actually readable 18905ffd83dbSDimitry Andric // type signatures for vfooq(), and here's why each one didn't 18915ffd83dbSDimitry Andric // match your call". 18925ffd83dbSDimitry Andric 18935ffd83dbSDimitry Andric OS << "static __inline__ __attribute__((" 18945ffd83dbSDimitry Andric << (Polymorphic ? "__overloadable__, " : "") 18955ffd83dbSDimitry Andric << "__clang_arm_builtin_alias(__builtin_arm_mve_" << Int.fullName() 18965ffd83dbSDimitry Andric << ")))\n" 18975ffd83dbSDimitry Andric << RetTypeName << FunctionName << "(" << ArgTypesString << ");\n"; 18985ffd83dbSDimitry Andric } 18995ffd83dbSDimitry Andric } 19005ffd83dbSDimitry Andric } 19015ffd83dbSDimitry Andric for (auto &part : parts) 19025ffd83dbSDimitry Andric part << "\n"; 19035ffd83dbSDimitry Andric 19045ffd83dbSDimitry Andric // Now we've finished accumulating bits and pieces into the parts[] array. 19055ffd83dbSDimitry Andric // Put it all together to write the final output file. 19065ffd83dbSDimitry Andric 19075ffd83dbSDimitry Andric OS << "/*===---- arm_mve.h - ARM MVE intrinsics " 19085ffd83dbSDimitry Andric "-----------------------------------===\n" 19095ffd83dbSDimitry Andric << LLVMLicenseHeader 19105ffd83dbSDimitry Andric << "#ifndef __ARM_MVE_H\n" 19115ffd83dbSDimitry Andric "#define __ARM_MVE_H\n" 19125ffd83dbSDimitry Andric "\n" 19135ffd83dbSDimitry Andric "#if !__ARM_FEATURE_MVE\n" 19145ffd83dbSDimitry Andric "#error \"MVE support not enabled\"\n" 19155ffd83dbSDimitry Andric "#endif\n" 19165ffd83dbSDimitry Andric "\n" 19175ffd83dbSDimitry Andric "#include <stdint.h>\n" 19185ffd83dbSDimitry Andric "\n" 19195ffd83dbSDimitry Andric "#ifdef __cplusplus\n" 19205ffd83dbSDimitry Andric "extern \"C\" {\n" 19215ffd83dbSDimitry Andric "#endif\n" 19225ffd83dbSDimitry Andric "\n"; 19235ffd83dbSDimitry Andric 19245ffd83dbSDimitry Andric for (size_t i = 0; i < NumParts; ++i) { 19255ffd83dbSDimitry Andric std::vector<std::string> conditions; 19265ffd83dbSDimitry Andric if (i & Float) 19275ffd83dbSDimitry Andric conditions.push_back("(__ARM_FEATURE_MVE & 2)"); 19285ffd83dbSDimitry Andric if (i & UseUserNamespace) 19295ffd83dbSDimitry Andric conditions.push_back("(!defined __ARM_MVE_PRESERVE_USER_NAMESPACE)"); 19305ffd83dbSDimitry Andric 19315ffd83dbSDimitry Andric std::string condition = 19325ffd83dbSDimitry Andric join(std::begin(conditions), std::end(conditions), " && "); 19335ffd83dbSDimitry Andric if (!condition.empty()) 19345ffd83dbSDimitry Andric OS << "#if " << condition << "\n\n"; 19355ffd83dbSDimitry Andric OS << parts[i].str(); 19365ffd83dbSDimitry Andric if (!condition.empty()) 19375ffd83dbSDimitry Andric OS << "#endif /* " << condition << " */\n\n"; 19385ffd83dbSDimitry Andric } 19395ffd83dbSDimitry Andric 19405ffd83dbSDimitry Andric OS << "#ifdef __cplusplus\n" 19415ffd83dbSDimitry Andric "} /* extern \"C\" */\n" 19425ffd83dbSDimitry Andric "#endif\n" 19435ffd83dbSDimitry Andric "\n" 19445ffd83dbSDimitry Andric "#endif /* __ARM_MVE_H */\n"; 19455ffd83dbSDimitry Andric } 19465ffd83dbSDimitry Andric 19475ffd83dbSDimitry Andric void MveEmitter::EmitBuiltinDef(raw_ostream &OS) { 19485ffd83dbSDimitry Andric for (const auto &kv : ACLEIntrinsics) { 19495ffd83dbSDimitry Andric const ACLEIntrinsic &Int = *kv.second; 1950349cc55cSDimitry Andric OS << "BUILTIN(__builtin_arm_mve_" << Int.fullName() 1951349cc55cSDimitry Andric << ", \"\", \"n\")\n"; 19525ffd83dbSDimitry Andric } 19535ffd83dbSDimitry Andric 19545ffd83dbSDimitry Andric std::set<std::string> ShortNamesSeen; 19555ffd83dbSDimitry Andric 19565ffd83dbSDimitry Andric for (const auto &kv : ACLEIntrinsics) { 19575ffd83dbSDimitry Andric const ACLEIntrinsic &Int = *kv.second; 19585ffd83dbSDimitry Andric if (Int.polymorphic()) { 19595ffd83dbSDimitry Andric StringRef Name = Int.shortName(); 19605ffd83dbSDimitry Andric if (ShortNamesSeen.find(std::string(Name)) == ShortNamesSeen.end()) { 19615ffd83dbSDimitry Andric OS << "BUILTIN(__builtin_arm_mve_" << Name << ", \"vi.\", \"nt"; 19625ffd83dbSDimitry Andric if (Int.nonEvaluating()) 19635ffd83dbSDimitry Andric OS << "u"; // indicate that this builtin doesn't evaluate its args 19645ffd83dbSDimitry Andric OS << "\")\n"; 19655ffd83dbSDimitry Andric ShortNamesSeen.insert(std::string(Name)); 19665ffd83dbSDimitry Andric } 19675ffd83dbSDimitry Andric } 19685ffd83dbSDimitry Andric } 19695ffd83dbSDimitry Andric } 19705ffd83dbSDimitry Andric 19715ffd83dbSDimitry Andric void MveEmitter::EmitBuiltinSema(raw_ostream &OS) { 19725ffd83dbSDimitry Andric std::map<std::string, std::set<std::string>> Checks; 19735ffd83dbSDimitry Andric GroupSemaChecks(Checks); 19745ffd83dbSDimitry Andric 19755ffd83dbSDimitry Andric for (const auto &kv : Checks) { 19765ffd83dbSDimitry Andric for (StringRef Name : kv.second) 19775ffd83dbSDimitry Andric OS << "case ARM::BI__builtin_arm_mve_" << Name << ":\n"; 19785ffd83dbSDimitry Andric OS << " return " << kv.first; 19795ffd83dbSDimitry Andric } 19805ffd83dbSDimitry Andric } 19815ffd83dbSDimitry Andric 19825ffd83dbSDimitry Andric // ----------------------------------------------------------------------------- 19835ffd83dbSDimitry Andric // Class that describes an ACLE intrinsic implemented as a macro. 19845ffd83dbSDimitry Andric // 19855ffd83dbSDimitry Andric // This class is used when the intrinsic is polymorphic in 2 or 3 types, but we 19865ffd83dbSDimitry Andric // want to avoid a combinatorial explosion by reinterpreting the arguments to 19875ffd83dbSDimitry Andric // fixed types. 19885ffd83dbSDimitry Andric 19895ffd83dbSDimitry Andric class FunctionMacro { 19905ffd83dbSDimitry Andric std::vector<StringRef> Params; 19915ffd83dbSDimitry Andric StringRef Definition; 19925ffd83dbSDimitry Andric 19935ffd83dbSDimitry Andric public: 19945ffd83dbSDimitry Andric FunctionMacro(const Record &R); 19955ffd83dbSDimitry Andric 19965ffd83dbSDimitry Andric const std::vector<StringRef> &getParams() const { return Params; } 19975ffd83dbSDimitry Andric StringRef getDefinition() const { return Definition; } 19985ffd83dbSDimitry Andric }; 19995ffd83dbSDimitry Andric 20005ffd83dbSDimitry Andric FunctionMacro::FunctionMacro(const Record &R) { 20015ffd83dbSDimitry Andric Params = R.getValueAsListOfStrings("params"); 20025ffd83dbSDimitry Andric Definition = R.getValueAsString("definition"); 20035ffd83dbSDimitry Andric } 20045ffd83dbSDimitry Andric 20055ffd83dbSDimitry Andric // ----------------------------------------------------------------------------- 20065ffd83dbSDimitry Andric // The class used for generating arm_cde.h and related Clang bits 20075ffd83dbSDimitry Andric // 20085ffd83dbSDimitry Andric 20095ffd83dbSDimitry Andric class CdeEmitter : public EmitterBase { 20105ffd83dbSDimitry Andric std::map<StringRef, FunctionMacro> FunctionMacros; 20115ffd83dbSDimitry Andric 20125ffd83dbSDimitry Andric public: 20135ffd83dbSDimitry Andric CdeEmitter(RecordKeeper &Records); 20145ffd83dbSDimitry Andric void EmitHeader(raw_ostream &OS) override; 20155ffd83dbSDimitry Andric void EmitBuiltinDef(raw_ostream &OS) override; 20165ffd83dbSDimitry Andric void EmitBuiltinSema(raw_ostream &OS) override; 20175ffd83dbSDimitry Andric }; 20185ffd83dbSDimitry Andric 20195ffd83dbSDimitry Andric CdeEmitter::CdeEmitter(RecordKeeper &Records) : EmitterBase(Records) { 20205ffd83dbSDimitry Andric for (Record *R : Records.getAllDerivedDefinitions("FunctionMacro")) 20215ffd83dbSDimitry Andric FunctionMacros.emplace(R->getName(), FunctionMacro(*R)); 20225ffd83dbSDimitry Andric } 20235ffd83dbSDimitry Andric 20245ffd83dbSDimitry Andric void CdeEmitter::EmitHeader(raw_ostream &OS) { 20255ffd83dbSDimitry Andric // Accumulate pieces of the header file that will be enabled under various 20265ffd83dbSDimitry Andric // different combinations of #ifdef. The index into parts[] is one of the 20275ffd83dbSDimitry Andric // following: 20285ffd83dbSDimitry Andric constexpr unsigned None = 0; 20295ffd83dbSDimitry Andric constexpr unsigned MVE = 1; 20305ffd83dbSDimitry Andric constexpr unsigned MVEFloat = 2; 20315ffd83dbSDimitry Andric 20325ffd83dbSDimitry Andric constexpr unsigned NumParts = 3; 20335ffd83dbSDimitry Andric raw_self_contained_string_ostream parts[NumParts]; 20345ffd83dbSDimitry Andric 20355ffd83dbSDimitry Andric // Write typedefs for all the required vector types, and a few scalar 20365ffd83dbSDimitry Andric // types that don't already have the name we want them to have. 20375ffd83dbSDimitry Andric 20385ffd83dbSDimitry Andric parts[MVE] << "typedef uint16_t mve_pred16_t;\n"; 20395ffd83dbSDimitry Andric parts[MVEFloat] << "typedef __fp16 float16_t;\n" 20405ffd83dbSDimitry Andric "typedef float float32_t;\n"; 20415ffd83dbSDimitry Andric for (const auto &kv : ScalarTypes) { 20425ffd83dbSDimitry Andric const ScalarType *ST = kv.second.get(); 20435ffd83dbSDimitry Andric if (ST->hasNonstandardName()) 20445ffd83dbSDimitry Andric continue; 20455ffd83dbSDimitry Andric // We don't have float64x2_t 20465ffd83dbSDimitry Andric if (ST->kind() == ScalarTypeKind::Float && ST->sizeInBits() == 64) 20475ffd83dbSDimitry Andric continue; 20485ffd83dbSDimitry Andric raw_ostream &OS = parts[ST->requiresFloat() ? MVEFloat : MVE]; 20495ffd83dbSDimitry Andric const VectorType *VT = getVectorType(ST); 20505ffd83dbSDimitry Andric 20515ffd83dbSDimitry Andric OS << "typedef __attribute__((__neon_vector_type__(" << VT->lanes() 20525ffd83dbSDimitry Andric << "), __clang_arm_mve_strict_polymorphism)) " << ST->cName() << " " 20535ffd83dbSDimitry Andric << VT->cName() << ";\n"; 20545ffd83dbSDimitry Andric } 20555ffd83dbSDimitry Andric parts[MVE] << "\n"; 20565ffd83dbSDimitry Andric parts[MVEFloat] << "\n"; 20575ffd83dbSDimitry Andric 20585ffd83dbSDimitry Andric // Write declarations for all the intrinsics. 20595ffd83dbSDimitry Andric 20605ffd83dbSDimitry Andric for (const auto &kv : ACLEIntrinsics) { 20615ffd83dbSDimitry Andric const ACLEIntrinsic &Int = *kv.second; 20625ffd83dbSDimitry Andric 20635ffd83dbSDimitry Andric // We generate each intrinsic twice, under its full unambiguous 20645ffd83dbSDimitry Andric // name and its shorter polymorphic name (if the latter exists). 20655ffd83dbSDimitry Andric for (bool Polymorphic : {false, true}) { 20665ffd83dbSDimitry Andric if (Polymorphic && !Int.polymorphic()) 20675ffd83dbSDimitry Andric continue; 20685ffd83dbSDimitry Andric if (!Polymorphic && Int.polymorphicOnly()) 20695ffd83dbSDimitry Andric continue; 20705ffd83dbSDimitry Andric 20715ffd83dbSDimitry Andric raw_ostream &OS = 20725ffd83dbSDimitry Andric parts[Int.requiresFloat() ? MVEFloat 20735ffd83dbSDimitry Andric : Int.requiresMVE() ? MVE : None]; 20745ffd83dbSDimitry Andric 20755ffd83dbSDimitry Andric // Make the name of the function in this declaration. 20765ffd83dbSDimitry Andric std::string FunctionName = 20775ffd83dbSDimitry Andric "__arm_" + (Polymorphic ? Int.shortName() : Int.fullName()); 20785ffd83dbSDimitry Andric 20795ffd83dbSDimitry Andric // Make strings for the types involved in the function's 20805ffd83dbSDimitry Andric // prototype. 20815ffd83dbSDimitry Andric std::string RetTypeName = Int.returnType()->cName(); 20825f757f3fSDimitry Andric if (!StringRef(RetTypeName).ends_with("*")) 20835ffd83dbSDimitry Andric RetTypeName += " "; 20845ffd83dbSDimitry Andric 20855ffd83dbSDimitry Andric std::vector<std::string> ArgTypeNames; 20865ffd83dbSDimitry Andric for (const Type *ArgTypePtr : Int.argTypes()) 20875ffd83dbSDimitry Andric ArgTypeNames.push_back(ArgTypePtr->cName()); 20885ffd83dbSDimitry Andric std::string ArgTypesString = 20895ffd83dbSDimitry Andric join(std::begin(ArgTypeNames), std::end(ArgTypeNames), ", "); 20905ffd83dbSDimitry Andric 20915ffd83dbSDimitry Andric // Emit the actual declaration. See MveEmitter::EmitHeader for detailed 20925ffd83dbSDimitry Andric // comments 20935ffd83dbSDimitry Andric OS << "static __inline__ __attribute__((" 20945ffd83dbSDimitry Andric << (Polymorphic ? "__overloadable__, " : "") 20955ffd83dbSDimitry Andric << "__clang_arm_builtin_alias(__builtin_arm_" << Int.builtinExtension() 20965ffd83dbSDimitry Andric << "_" << Int.fullName() << ")))\n" 20975ffd83dbSDimitry Andric << RetTypeName << FunctionName << "(" << ArgTypesString << ");\n"; 20985ffd83dbSDimitry Andric } 20995ffd83dbSDimitry Andric } 21005ffd83dbSDimitry Andric 21015ffd83dbSDimitry Andric for (const auto &kv : FunctionMacros) { 21025ffd83dbSDimitry Andric StringRef Name = kv.first; 21035ffd83dbSDimitry Andric const FunctionMacro &FM = kv.second; 21045ffd83dbSDimitry Andric 21055ffd83dbSDimitry Andric raw_ostream &OS = parts[MVE]; 21065ffd83dbSDimitry Andric OS << "#define " 21075ffd83dbSDimitry Andric << "__arm_" << Name << "(" << join(FM.getParams(), ", ") << ") " 21085ffd83dbSDimitry Andric << FM.getDefinition() << "\n"; 21095ffd83dbSDimitry Andric } 21105ffd83dbSDimitry Andric 21115ffd83dbSDimitry Andric for (auto &part : parts) 21125ffd83dbSDimitry Andric part << "\n"; 21135ffd83dbSDimitry Andric 21145ffd83dbSDimitry Andric // Now we've finished accumulating bits and pieces into the parts[] array. 21155ffd83dbSDimitry Andric // Put it all together to write the final output file. 21165ffd83dbSDimitry Andric 21175ffd83dbSDimitry Andric OS << "/*===---- arm_cde.h - ARM CDE intrinsics " 21185ffd83dbSDimitry Andric "-----------------------------------===\n" 21195ffd83dbSDimitry Andric << LLVMLicenseHeader 21205ffd83dbSDimitry Andric << "#ifndef __ARM_CDE_H\n" 21215ffd83dbSDimitry Andric "#define __ARM_CDE_H\n" 21225ffd83dbSDimitry Andric "\n" 21235ffd83dbSDimitry Andric "#if !__ARM_FEATURE_CDE\n" 21245ffd83dbSDimitry Andric "#error \"CDE support not enabled\"\n" 21255ffd83dbSDimitry Andric "#endif\n" 21265ffd83dbSDimitry Andric "\n" 21275ffd83dbSDimitry Andric "#include <stdint.h>\n" 21285ffd83dbSDimitry Andric "\n" 21295ffd83dbSDimitry Andric "#ifdef __cplusplus\n" 21305ffd83dbSDimitry Andric "extern \"C\" {\n" 21315ffd83dbSDimitry Andric "#endif\n" 21325ffd83dbSDimitry Andric "\n"; 21335ffd83dbSDimitry Andric 21345ffd83dbSDimitry Andric for (size_t i = 0; i < NumParts; ++i) { 21355ffd83dbSDimitry Andric std::string condition; 21365ffd83dbSDimitry Andric if (i == MVEFloat) 21375ffd83dbSDimitry Andric condition = "__ARM_FEATURE_MVE & 2"; 21385ffd83dbSDimitry Andric else if (i == MVE) 21395ffd83dbSDimitry Andric condition = "__ARM_FEATURE_MVE"; 21405ffd83dbSDimitry Andric 21415ffd83dbSDimitry Andric if (!condition.empty()) 21425ffd83dbSDimitry Andric OS << "#if " << condition << "\n\n"; 21435ffd83dbSDimitry Andric OS << parts[i].str(); 21445ffd83dbSDimitry Andric if (!condition.empty()) 21455ffd83dbSDimitry Andric OS << "#endif /* " << condition << " */\n\n"; 21465ffd83dbSDimitry Andric } 21475ffd83dbSDimitry Andric 21485ffd83dbSDimitry Andric OS << "#ifdef __cplusplus\n" 21495ffd83dbSDimitry Andric "} /* extern \"C\" */\n" 21505ffd83dbSDimitry Andric "#endif\n" 21515ffd83dbSDimitry Andric "\n" 21525ffd83dbSDimitry Andric "#endif /* __ARM_CDE_H */\n"; 21535ffd83dbSDimitry Andric } 21545ffd83dbSDimitry Andric 21555ffd83dbSDimitry Andric void CdeEmitter::EmitBuiltinDef(raw_ostream &OS) { 21565ffd83dbSDimitry Andric for (const auto &kv : ACLEIntrinsics) { 21575ffd83dbSDimitry Andric if (kv.second->headerOnly()) 21585ffd83dbSDimitry Andric continue; 21595ffd83dbSDimitry Andric const ACLEIntrinsic &Int = *kv.second; 2160349cc55cSDimitry Andric OS << "BUILTIN(__builtin_arm_cde_" << Int.fullName() 2161349cc55cSDimitry Andric << ", \"\", \"ncU\")\n"; 21625ffd83dbSDimitry Andric } 21635ffd83dbSDimitry Andric } 21645ffd83dbSDimitry Andric 21655ffd83dbSDimitry Andric void CdeEmitter::EmitBuiltinSema(raw_ostream &OS) { 21665ffd83dbSDimitry Andric std::map<std::string, std::set<std::string>> Checks; 21675ffd83dbSDimitry Andric GroupSemaChecks(Checks); 21685ffd83dbSDimitry Andric 21695ffd83dbSDimitry Andric for (const auto &kv : Checks) { 21705ffd83dbSDimitry Andric for (StringRef Name : kv.second) 21715ffd83dbSDimitry Andric OS << "case ARM::BI__builtin_arm_cde_" << Name << ":\n"; 21725ffd83dbSDimitry Andric OS << " Err = " << kv.first << " break;\n"; 2173480093f4SDimitry Andric } 2174480093f4SDimitry Andric } 2175480093f4SDimitry Andric 2176480093f4SDimitry Andric } // namespace 2177480093f4SDimitry Andric 2178480093f4SDimitry Andric namespace clang { 2179480093f4SDimitry Andric 21805ffd83dbSDimitry Andric // MVE 21815ffd83dbSDimitry Andric 2182480093f4SDimitry Andric void EmitMveHeader(RecordKeeper &Records, raw_ostream &OS) { 2183480093f4SDimitry Andric MveEmitter(Records).EmitHeader(OS); 2184480093f4SDimitry Andric } 2185480093f4SDimitry Andric 2186480093f4SDimitry Andric void EmitMveBuiltinDef(RecordKeeper &Records, raw_ostream &OS) { 2187480093f4SDimitry Andric MveEmitter(Records).EmitBuiltinDef(OS); 2188480093f4SDimitry Andric } 2189480093f4SDimitry Andric 2190480093f4SDimitry Andric void EmitMveBuiltinSema(RecordKeeper &Records, raw_ostream &OS) { 2191480093f4SDimitry Andric MveEmitter(Records).EmitBuiltinSema(OS); 2192480093f4SDimitry Andric } 2193480093f4SDimitry Andric 2194480093f4SDimitry Andric void EmitMveBuiltinCG(RecordKeeper &Records, raw_ostream &OS) { 2195480093f4SDimitry Andric MveEmitter(Records).EmitBuiltinCG(OS); 2196480093f4SDimitry Andric } 2197480093f4SDimitry Andric 2198480093f4SDimitry Andric void EmitMveBuiltinAliases(RecordKeeper &Records, raw_ostream &OS) { 2199480093f4SDimitry Andric MveEmitter(Records).EmitBuiltinAliases(OS); 2200480093f4SDimitry Andric } 2201480093f4SDimitry Andric 22025ffd83dbSDimitry Andric // CDE 22035ffd83dbSDimitry Andric 22045ffd83dbSDimitry Andric void EmitCdeHeader(RecordKeeper &Records, raw_ostream &OS) { 22055ffd83dbSDimitry Andric CdeEmitter(Records).EmitHeader(OS); 22065ffd83dbSDimitry Andric } 22075ffd83dbSDimitry Andric 22085ffd83dbSDimitry Andric void EmitCdeBuiltinDef(RecordKeeper &Records, raw_ostream &OS) { 22095ffd83dbSDimitry Andric CdeEmitter(Records).EmitBuiltinDef(OS); 22105ffd83dbSDimitry Andric } 22115ffd83dbSDimitry Andric 22125ffd83dbSDimitry Andric void EmitCdeBuiltinSema(RecordKeeper &Records, raw_ostream &OS) { 22135ffd83dbSDimitry Andric CdeEmitter(Records).EmitBuiltinSema(OS); 22145ffd83dbSDimitry Andric } 22155ffd83dbSDimitry Andric 22165ffd83dbSDimitry Andric void EmitCdeBuiltinCG(RecordKeeper &Records, raw_ostream &OS) { 22175ffd83dbSDimitry Andric CdeEmitter(Records).EmitBuiltinCG(OS); 22185ffd83dbSDimitry Andric } 22195ffd83dbSDimitry Andric 22205ffd83dbSDimitry Andric void EmitCdeBuiltinAliases(RecordKeeper &Records, raw_ostream &OS) { 22215ffd83dbSDimitry Andric CdeEmitter(Records).EmitBuiltinAliases(OS); 22225ffd83dbSDimitry Andric } 22235ffd83dbSDimitry Andric 2224480093f4SDimitry Andric } // end namespace clang 2225