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" 63*5ffd83dbSDimitry 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" 68*5ffd83dbSDimitry 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 83*5ffd83dbSDimitry 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; 143*5ffd83dbSDimitry 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; } 183*5ffd83dbSDimitry 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(); } 199*5ffd83dbSDimitry 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 } 215480093f4SDimitry Andric 216480093f4SDimitry Andric static bool classof(const Type *T) { 217480093f4SDimitry Andric return T->typeKind() == TypeKind::Pointer; 218480093f4SDimitry Andric } 219480093f4SDimitry Andric }; 220480093f4SDimitry Andric 221480093f4SDimitry Andric // Base class for all the types that have a name of the form 222480093f4SDimitry Andric // [prefix][numbers]_t, like int32_t, uint16x8_t, float32x4x2_t. 223480093f4SDimitry Andric // 224480093f4SDimitry Andric // For this sub-hierarchy we invent a cNameBase() method which returns the 225480093f4SDimitry Andric // whole name except for the trailing "_t", so that Vector and MultiVector can 226480093f4SDimitry Andric // append an extra "x2" or whatever to their element type's cNameBase(). Then 227480093f4SDimitry Andric // the main cName() query method puts "_t" on the end for the final type name. 228480093f4SDimitry Andric 229480093f4SDimitry Andric class CRegularNamedType : public Type { 230480093f4SDimitry Andric using Type::Type; 231480093f4SDimitry Andric virtual std::string cNameBase() const = 0; 232480093f4SDimitry Andric 233480093f4SDimitry Andric public: 234480093f4SDimitry Andric std::string cName() const override { return cNameBase() + "_t"; } 235480093f4SDimitry Andric }; 236480093f4SDimitry Andric 237480093f4SDimitry Andric class ScalarType : public CRegularNamedType { 238480093f4SDimitry Andric ScalarTypeKind Kind; 239480093f4SDimitry Andric unsigned Bits; 240480093f4SDimitry Andric std::string NameOverride; 241480093f4SDimitry Andric 242480093f4SDimitry Andric public: 243480093f4SDimitry Andric ScalarType(const Record *Record) : CRegularNamedType(TypeKind::Scalar) { 244480093f4SDimitry Andric Kind = StringSwitch<ScalarTypeKind>(Record->getValueAsString("kind")) 245480093f4SDimitry Andric .Case("s", ScalarTypeKind::SignedInt) 246480093f4SDimitry Andric .Case("u", ScalarTypeKind::UnsignedInt) 247480093f4SDimitry Andric .Case("f", ScalarTypeKind::Float); 248480093f4SDimitry Andric Bits = Record->getValueAsInt("size"); 249*5ffd83dbSDimitry Andric NameOverride = std::string(Record->getValueAsString("nameOverride")); 250480093f4SDimitry Andric } 251480093f4SDimitry Andric unsigned sizeInBits() const override { return Bits; } 252480093f4SDimitry Andric ScalarTypeKind kind() const { return Kind; } 253480093f4SDimitry Andric std::string suffix() const { return toLetter(Kind) + utostr(Bits); } 254480093f4SDimitry Andric std::string cNameBase() const override { 255480093f4SDimitry Andric return toCPrefix(Kind) + utostr(Bits); 256480093f4SDimitry Andric } 257480093f4SDimitry Andric std::string cName() const override { 258480093f4SDimitry Andric if (NameOverride.empty()) 259480093f4SDimitry Andric return CRegularNamedType::cName(); 260480093f4SDimitry Andric return NameOverride; 261480093f4SDimitry Andric } 262480093f4SDimitry Andric std::string llvmName() const override { 263480093f4SDimitry Andric if (Kind == ScalarTypeKind::Float) { 264480093f4SDimitry Andric if (Bits == 16) 265480093f4SDimitry Andric return "HalfTy"; 266480093f4SDimitry Andric if (Bits == 32) 267480093f4SDimitry Andric return "FloatTy"; 268480093f4SDimitry Andric if (Bits == 64) 269480093f4SDimitry Andric return "DoubleTy"; 270480093f4SDimitry Andric PrintFatalError("bad size for floating type"); 271480093f4SDimitry Andric } 272480093f4SDimitry Andric return "Int" + utostr(Bits) + "Ty"; 273480093f4SDimitry Andric } 274480093f4SDimitry Andric std::string acleSuffix(std::string overrideLetter) const override { 275480093f4SDimitry Andric return "_" + (overrideLetter.size() ? overrideLetter : toLetter(Kind)) 276480093f4SDimitry Andric + utostr(Bits); 277480093f4SDimitry Andric } 278480093f4SDimitry Andric bool isInteger() const { return Kind != ScalarTypeKind::Float; } 279480093f4SDimitry Andric bool requiresFloat() const override { return !isInteger(); } 280*5ffd83dbSDimitry Andric bool requiresMVE() const override { return false; } 281480093f4SDimitry Andric bool hasNonstandardName() const { return !NameOverride.empty(); } 282480093f4SDimitry Andric 283480093f4SDimitry Andric static bool classof(const Type *T) { 284480093f4SDimitry Andric return T->typeKind() == TypeKind::Scalar; 285480093f4SDimitry Andric } 286480093f4SDimitry Andric }; 287480093f4SDimitry Andric 288480093f4SDimitry Andric class VectorType : public CRegularNamedType { 289480093f4SDimitry Andric const ScalarType *Element; 290480093f4SDimitry Andric unsigned Lanes; 291480093f4SDimitry Andric 292480093f4SDimitry Andric public: 293480093f4SDimitry Andric VectorType(const ScalarType *Element, unsigned Lanes) 294480093f4SDimitry Andric : CRegularNamedType(TypeKind::Vector), Element(Element), Lanes(Lanes) {} 295480093f4SDimitry Andric unsigned sizeInBits() const override { return Lanes * Element->sizeInBits(); } 296480093f4SDimitry Andric unsigned lanes() const { return Lanes; } 297480093f4SDimitry Andric bool requiresFloat() const override { return Element->requiresFloat(); } 298*5ffd83dbSDimitry Andric bool requiresMVE() const override { return true; } 299480093f4SDimitry Andric std::string cNameBase() const override { 300480093f4SDimitry Andric return Element->cNameBase() + "x" + utostr(Lanes); 301480093f4SDimitry Andric } 302480093f4SDimitry Andric std::string llvmName() const override { 303*5ffd83dbSDimitry Andric return "llvm::FixedVectorType::get(" + Element->llvmName() + ", " + 304480093f4SDimitry Andric utostr(Lanes) + ")"; 305480093f4SDimitry Andric } 306480093f4SDimitry Andric 307480093f4SDimitry Andric static bool classof(const Type *T) { 308480093f4SDimitry Andric return T->typeKind() == TypeKind::Vector; 309480093f4SDimitry Andric } 310480093f4SDimitry Andric }; 311480093f4SDimitry Andric 312480093f4SDimitry Andric class MultiVectorType : public CRegularNamedType { 313480093f4SDimitry Andric const VectorType *Element; 314480093f4SDimitry Andric unsigned Registers; 315480093f4SDimitry Andric 316480093f4SDimitry Andric public: 317480093f4SDimitry Andric MultiVectorType(unsigned Registers, const VectorType *Element) 318480093f4SDimitry Andric : CRegularNamedType(TypeKind::MultiVector), Element(Element), 319480093f4SDimitry Andric Registers(Registers) {} 320480093f4SDimitry Andric unsigned sizeInBits() const override { 321480093f4SDimitry Andric return Registers * Element->sizeInBits(); 322480093f4SDimitry Andric } 323480093f4SDimitry Andric unsigned registers() const { return Registers; } 324480093f4SDimitry Andric bool requiresFloat() const override { return Element->requiresFloat(); } 325*5ffd83dbSDimitry Andric bool requiresMVE() const override { return true; } 326480093f4SDimitry Andric std::string cNameBase() const override { 327480093f4SDimitry Andric return Element->cNameBase() + "x" + utostr(Registers); 328480093f4SDimitry Andric } 329480093f4SDimitry Andric 330480093f4SDimitry Andric // MultiVectorType doesn't override llvmName, because we don't expect to do 331480093f4SDimitry Andric // automatic code generation for the MVE intrinsics that use it: the {vld2, 332480093f4SDimitry Andric // vld4, vst2, vst4} family are the only ones that use these types, so it was 333480093f4SDimitry Andric // easier to hand-write the codegen for dealing with these structs than to 334480093f4SDimitry Andric // build in lots of extra automatic machinery that would only be used once. 335480093f4SDimitry Andric 336480093f4SDimitry Andric static bool classof(const Type *T) { 337480093f4SDimitry Andric return T->typeKind() == TypeKind::MultiVector; 338480093f4SDimitry Andric } 339480093f4SDimitry Andric }; 340480093f4SDimitry Andric 341480093f4SDimitry Andric class PredicateType : public CRegularNamedType { 342480093f4SDimitry Andric unsigned Lanes; 343480093f4SDimitry Andric 344480093f4SDimitry Andric public: 345480093f4SDimitry Andric PredicateType(unsigned Lanes) 346480093f4SDimitry Andric : CRegularNamedType(TypeKind::Predicate), Lanes(Lanes) {} 347480093f4SDimitry Andric unsigned sizeInBits() const override { return 16; } 348480093f4SDimitry Andric std::string cNameBase() const override { return "mve_pred16"; } 349480093f4SDimitry Andric bool requiresFloat() const override { return false; }; 350*5ffd83dbSDimitry Andric bool requiresMVE() const override { return true; } 351480093f4SDimitry Andric std::string llvmName() const override { 352480093f4SDimitry Andric // Use <4 x i1> instead of <2 x i1> for two-lane vector types. See 353480093f4SDimitry Andric // the comment in llvm/lib/Target/ARM/ARMInstrMVE.td for further 354480093f4SDimitry Andric // explanation. 355480093f4SDimitry Andric unsigned ModifiedLanes = (Lanes == 2 ? 4 : Lanes); 356480093f4SDimitry Andric 357*5ffd83dbSDimitry Andric return "llvm::FixedVectorType::get(Builder.getInt1Ty(), " + 358480093f4SDimitry Andric utostr(ModifiedLanes) + ")"; 359480093f4SDimitry Andric } 360480093f4SDimitry Andric 361480093f4SDimitry Andric static bool classof(const Type *T) { 362480093f4SDimitry Andric return T->typeKind() == TypeKind::Predicate; 363480093f4SDimitry Andric } 364480093f4SDimitry Andric }; 365480093f4SDimitry Andric 366480093f4SDimitry Andric // ----------------------------------------------------------------------------- 367480093f4SDimitry Andric // Class to facilitate merging together the code generation for many intrinsics 368480093f4SDimitry Andric // by means of varying a few constant or type parameters. 369480093f4SDimitry Andric // 370480093f4SDimitry Andric // Most obviously, the intrinsics in a single parametrised family will have 371480093f4SDimitry Andric // code generation sequences that only differ in a type or two, e.g. vaddq_s8 372480093f4SDimitry Andric // and vaddq_u16 will look the same apart from putting a different vector type 373480093f4SDimitry Andric // in the call to CGM.getIntrinsic(). But also, completely different intrinsics 374480093f4SDimitry Andric // will often code-generate in the same way, with only a different choice of 375480093f4SDimitry Andric // _which_ IR intrinsic they lower to (e.g. vaddq_m_s8 and vmulq_m_s8), but 376480093f4SDimitry Andric // marshalling the arguments and return values of the IR intrinsic in exactly 377480093f4SDimitry Andric // the same way. And others might differ only in some other kind of constant, 378480093f4SDimitry Andric // such as a lane index. 379480093f4SDimitry Andric // 380480093f4SDimitry Andric // So, when we generate the IR-building code for all these intrinsics, we keep 381480093f4SDimitry Andric // track of every value that could possibly be pulled out of the code and 382480093f4SDimitry Andric // stored ahead of time in a local variable. Then we group together intrinsics 383480093f4SDimitry Andric // by textual equivalence of the code that would result if _all_ those 384480093f4SDimitry Andric // parameters were stored in local variables. That gives us maximal sets that 385480093f4SDimitry Andric // can be implemented by a single piece of IR-building code by changing 386480093f4SDimitry Andric // parameter values ahead of time. 387480093f4SDimitry Andric // 388480093f4SDimitry Andric // After we've done that, we do a second pass in which we only allocate _some_ 389480093f4SDimitry Andric // of the parameters into local variables, by tracking which ones have the same 390480093f4SDimitry Andric // values as each other (so that a single variable can be reused) and which 391480093f4SDimitry Andric // ones are the same across the whole set (so that no variable is needed at 392480093f4SDimitry Andric // all). 393480093f4SDimitry Andric // 394480093f4SDimitry Andric // Hence the class below. Its allocParam method is invoked during code 395480093f4SDimitry Andric // generation by every method of a Result subclass (see below) that wants to 396480093f4SDimitry Andric // give it the opportunity to pull something out into a switchable parameter. 397480093f4SDimitry Andric // It returns a variable name for the parameter, or (if it's being used in the 398480093f4SDimitry Andric // second pass once we've decided that some parameters don't need to be stored 399480093f4SDimitry Andric // in variables after all) it might just return the input expression unchanged. 400480093f4SDimitry Andric 401480093f4SDimitry Andric struct CodeGenParamAllocator { 402480093f4SDimitry Andric // Accumulated during code generation 403480093f4SDimitry Andric std::vector<std::string> *ParamTypes = nullptr; 404480093f4SDimitry Andric std::vector<std::string> *ParamValues = nullptr; 405480093f4SDimitry Andric 406480093f4SDimitry Andric // Provided ahead of time in pass 2, to indicate which parameters are being 407480093f4SDimitry Andric // assigned to what. This vector contains an entry for each call to 408480093f4SDimitry Andric // allocParam expected during code gen (which we counted up in pass 1), and 409480093f4SDimitry Andric // indicates the number of the parameter variable that should be returned, or 410480093f4SDimitry Andric // -1 if this call shouldn't allocate a parameter variable at all. 411480093f4SDimitry Andric // 412480093f4SDimitry Andric // We rely on the recursive code generation working identically in passes 1 413480093f4SDimitry Andric // and 2, so that the same list of calls to allocParam happen in the same 414480093f4SDimitry Andric // order. That guarantees that the parameter numbers recorded in pass 1 will 415*5ffd83dbSDimitry Andric // match the entries in this vector that store what EmitterBase::EmitBuiltinCG 416480093f4SDimitry Andric // decided to do about each one in pass 2. 417480093f4SDimitry Andric std::vector<int> *ParamNumberMap = nullptr; 418480093f4SDimitry Andric 419480093f4SDimitry Andric // Internally track how many things we've allocated 420480093f4SDimitry Andric unsigned nparams = 0; 421480093f4SDimitry Andric 422480093f4SDimitry Andric std::string allocParam(StringRef Type, StringRef Value) { 423480093f4SDimitry Andric unsigned ParamNumber; 424480093f4SDimitry Andric 425480093f4SDimitry Andric if (!ParamNumberMap) { 426480093f4SDimitry Andric // In pass 1, unconditionally assign a new parameter variable to every 427480093f4SDimitry Andric // value we're asked to process. 428480093f4SDimitry Andric ParamNumber = nparams++; 429480093f4SDimitry Andric } else { 430480093f4SDimitry Andric // In pass 2, consult the map provided by the caller to find out which 431480093f4SDimitry Andric // variable we should be keeping things in. 432480093f4SDimitry Andric int MapValue = (*ParamNumberMap)[nparams++]; 433480093f4SDimitry Andric if (MapValue < 0) 434*5ffd83dbSDimitry Andric return std::string(Value); 435480093f4SDimitry Andric ParamNumber = MapValue; 436480093f4SDimitry Andric } 437480093f4SDimitry Andric 438480093f4SDimitry Andric // If we've allocated a new parameter variable for the first time, store 439480093f4SDimitry Andric // its type and value to be retrieved after codegen. 440480093f4SDimitry Andric if (ParamTypes && ParamTypes->size() == ParamNumber) 441*5ffd83dbSDimitry Andric ParamTypes->push_back(std::string(Type)); 442480093f4SDimitry Andric if (ParamValues && ParamValues->size() == ParamNumber) 443*5ffd83dbSDimitry Andric ParamValues->push_back(std::string(Value)); 444480093f4SDimitry Andric 445480093f4SDimitry Andric // Unimaginative naming scheme for parameter variables. 446480093f4SDimitry Andric return "Param" + utostr(ParamNumber); 447480093f4SDimitry Andric } 448480093f4SDimitry Andric }; 449480093f4SDimitry Andric 450480093f4SDimitry Andric // ----------------------------------------------------------------------------- 451480093f4SDimitry Andric // System of classes that represent all the intermediate values used during 452480093f4SDimitry Andric // code-generation for an intrinsic. 453480093f4SDimitry Andric // 454480093f4SDimitry Andric // The base class 'Result' can represent a value of the LLVM type 'Value', or 455480093f4SDimitry Andric // sometimes 'Address' (for loads/stores, including an alignment requirement). 456480093f4SDimitry Andric // 457480093f4SDimitry Andric // In the case where the Tablegen provides a value in the codegen dag as a 458480093f4SDimitry Andric // plain integer literal, the Result object we construct here will be one that 459480093f4SDimitry Andric // returns true from hasIntegerConstantValue(). This allows the generated C++ 460480093f4SDimitry Andric // code to use the constant directly in contexts which can take a literal 461480093f4SDimitry Andric // integer, such as Builder.CreateExtractValue(thing, 1), without going to the 462480093f4SDimitry Andric // effort of calling llvm::ConstantInt::get() and then pulling the constant 463480093f4SDimitry Andric // back out of the resulting llvm:Value later. 464480093f4SDimitry Andric 465480093f4SDimitry Andric class Result { 466480093f4SDimitry Andric public: 467480093f4SDimitry Andric // Convenient shorthand for the pointer type we'll be using everywhere. 468480093f4SDimitry Andric using Ptr = std::shared_ptr<Result>; 469480093f4SDimitry Andric 470480093f4SDimitry Andric private: 471480093f4SDimitry Andric Ptr Predecessor; 472480093f4SDimitry Andric std::string VarName; 473480093f4SDimitry Andric bool VarNameUsed = false; 474480093f4SDimitry Andric unsigned Visited = 0; 475480093f4SDimitry Andric 476480093f4SDimitry Andric public: 477480093f4SDimitry Andric virtual ~Result() = default; 478480093f4SDimitry Andric using Scope = std::map<std::string, Ptr>; 479480093f4SDimitry Andric virtual void genCode(raw_ostream &OS, CodeGenParamAllocator &) const = 0; 480480093f4SDimitry Andric virtual bool hasIntegerConstantValue() const { return false; } 481480093f4SDimitry Andric virtual uint32_t integerConstantValue() const { return 0; } 482480093f4SDimitry Andric virtual bool hasIntegerValue() const { return false; } 483480093f4SDimitry Andric virtual std::string getIntegerValue(const std::string &) { 484480093f4SDimitry Andric llvm_unreachable("non-working Result::getIntegerValue called"); 485480093f4SDimitry Andric } 486480093f4SDimitry Andric virtual std::string typeName() const { return "Value *"; } 487480093f4SDimitry Andric 488480093f4SDimitry Andric // Mostly, when a code-generation operation has a dependency on prior 489480093f4SDimitry Andric // operations, it's because it uses the output values of those operations as 490480093f4SDimitry Andric // inputs. But there's one exception, which is the use of 'seq' in Tablegen 491480093f4SDimitry Andric // to indicate that operations have to be performed in sequence regardless of 492480093f4SDimitry Andric // whether they use each others' output values. 493480093f4SDimitry Andric // 494480093f4SDimitry Andric // So, the actual generation of code is done by depth-first search, using the 495480093f4SDimitry Andric // prerequisites() method to get a list of all the other Results that have to 496480093f4SDimitry Andric // be computed before this one. That method divides into the 'predecessor', 497480093f4SDimitry Andric // set by setPredecessor() while processing a 'seq' dag node, and the list 498480093f4SDimitry Andric // returned by 'morePrerequisites', which each subclass implements to return 499480093f4SDimitry Andric // a list of the Results it uses as input to whatever its own computation is 500480093f4SDimitry Andric // doing. 501480093f4SDimitry Andric 502480093f4SDimitry Andric virtual void morePrerequisites(std::vector<Ptr> &output) const {} 503480093f4SDimitry Andric std::vector<Ptr> prerequisites() const { 504480093f4SDimitry Andric std::vector<Ptr> ToRet; 505480093f4SDimitry Andric if (Predecessor) 506480093f4SDimitry Andric ToRet.push_back(Predecessor); 507480093f4SDimitry Andric morePrerequisites(ToRet); 508480093f4SDimitry Andric return ToRet; 509480093f4SDimitry Andric } 510480093f4SDimitry Andric 511480093f4SDimitry Andric void setPredecessor(Ptr p) { 512*5ffd83dbSDimitry Andric // If the user has nested one 'seq' node inside another, and this 513*5ffd83dbSDimitry Andric // method is called on the return value of the inner 'seq' (i.e. 514*5ffd83dbSDimitry Andric // the final item inside it), then we can't link _this_ node to p, 515*5ffd83dbSDimitry Andric // because it already has a predecessor. Instead, walk the chain 516*5ffd83dbSDimitry Andric // until we find the first item in the inner seq, and link that to 517*5ffd83dbSDimitry Andric // p, so that nesting seqs has the obvious effect of linking 518*5ffd83dbSDimitry Andric // everything together into one long sequential chain. 519*5ffd83dbSDimitry Andric Result *r = this; 520*5ffd83dbSDimitry Andric while (r->Predecessor) 521*5ffd83dbSDimitry Andric r = r->Predecessor.get(); 522*5ffd83dbSDimitry Andric r->Predecessor = p; 523480093f4SDimitry Andric } 524480093f4SDimitry Andric 525480093f4SDimitry Andric // Each Result will be assigned a variable name in the output code, but not 526480093f4SDimitry Andric // all those variable names will actually be used (e.g. the return value of 527480093f4SDimitry Andric // Builder.CreateStore has void type, so nobody will want to refer to it). To 528480093f4SDimitry Andric // prevent annoying compiler warnings, we track whether each Result's 529480093f4SDimitry Andric // variable name was ever actually mentioned in subsequent statements, so 530480093f4SDimitry Andric // that it can be left out of the final generated code. 531480093f4SDimitry Andric std::string varname() { 532480093f4SDimitry Andric VarNameUsed = true; 533480093f4SDimitry Andric return VarName; 534480093f4SDimitry Andric } 535*5ffd83dbSDimitry Andric void setVarname(const StringRef s) { VarName = std::string(s); } 536480093f4SDimitry Andric bool varnameUsed() const { return VarNameUsed; } 537480093f4SDimitry Andric 538480093f4SDimitry Andric // Emit code to generate this result as a Value *. 539480093f4SDimitry Andric virtual std::string asValue() { 540480093f4SDimitry Andric return varname(); 541480093f4SDimitry Andric } 542480093f4SDimitry Andric 543480093f4SDimitry Andric // Code generation happens in multiple passes. This method tracks whether a 544480093f4SDimitry Andric // Result has yet been visited in a given pass, without the need for a 545480093f4SDimitry Andric // tedious loop in between passes that goes through and resets a 'visited' 546480093f4SDimitry Andric // flag back to false: you just set Pass=1 the first time round, and Pass=2 547480093f4SDimitry Andric // the second time. 548480093f4SDimitry Andric bool needsVisiting(unsigned Pass) { 549480093f4SDimitry Andric bool ToRet = Visited < Pass; 550480093f4SDimitry Andric Visited = Pass; 551480093f4SDimitry Andric return ToRet; 552480093f4SDimitry Andric } 553480093f4SDimitry Andric }; 554480093f4SDimitry Andric 555480093f4SDimitry Andric // Result subclass that retrieves one of the arguments to the clang builtin 556480093f4SDimitry Andric // function. In cases where the argument has pointer type, we call 557480093f4SDimitry Andric // EmitPointerWithAlignment and store the result in a variable of type Address, 558480093f4SDimitry Andric // so that load and store IR nodes can know the right alignment. Otherwise, we 559480093f4SDimitry Andric // call EmitScalarExpr. 560480093f4SDimitry Andric // 561480093f4SDimitry Andric // There are aggregate parameters in the MVE intrinsics API, but we don't deal 562480093f4SDimitry Andric // with them in this Tablegen back end: they only arise in the vld2q/vld4q and 563480093f4SDimitry Andric // vst2q/vst4q family, which is few enough that we just write the code by hand 564480093f4SDimitry Andric // for those in CGBuiltin.cpp. 565480093f4SDimitry Andric class BuiltinArgResult : public Result { 566480093f4SDimitry Andric public: 567480093f4SDimitry Andric unsigned ArgNum; 568480093f4SDimitry Andric bool AddressType; 569480093f4SDimitry Andric bool Immediate; 570480093f4SDimitry Andric BuiltinArgResult(unsigned ArgNum, bool AddressType, bool Immediate) 571480093f4SDimitry Andric : ArgNum(ArgNum), AddressType(AddressType), Immediate(Immediate) {} 572480093f4SDimitry Andric void genCode(raw_ostream &OS, CodeGenParamAllocator &) const override { 573480093f4SDimitry Andric OS << (AddressType ? "EmitPointerWithAlignment" : "EmitScalarExpr") 574480093f4SDimitry Andric << "(E->getArg(" << ArgNum << "))"; 575480093f4SDimitry Andric } 576480093f4SDimitry Andric std::string typeName() const override { 577480093f4SDimitry Andric return AddressType ? "Address" : Result::typeName(); 578480093f4SDimitry Andric } 579480093f4SDimitry Andric // Emit code to generate this result as a Value *. 580480093f4SDimitry Andric std::string asValue() override { 581480093f4SDimitry Andric if (AddressType) 582480093f4SDimitry Andric return "(" + varname() + ".getPointer())"; 583480093f4SDimitry Andric return Result::asValue(); 584480093f4SDimitry Andric } 585480093f4SDimitry Andric bool hasIntegerValue() const override { return Immediate; } 586480093f4SDimitry Andric std::string getIntegerValue(const std::string &IntType) override { 587480093f4SDimitry Andric return "GetIntegerConstantValue<" + IntType + ">(E->getArg(" + 588480093f4SDimitry Andric utostr(ArgNum) + "), getContext())"; 589480093f4SDimitry Andric } 590480093f4SDimitry Andric }; 591480093f4SDimitry Andric 592480093f4SDimitry Andric // Result subclass for an integer literal appearing in Tablegen. This may need 593480093f4SDimitry Andric // to be turned into an llvm::Result by means of llvm::ConstantInt::get(), or 594480093f4SDimitry Andric // it may be used directly as an integer, depending on which IRBuilder method 595480093f4SDimitry Andric // it's being passed to. 596480093f4SDimitry Andric class IntLiteralResult : public Result { 597480093f4SDimitry Andric public: 598480093f4SDimitry Andric const ScalarType *IntegerType; 599480093f4SDimitry Andric uint32_t IntegerValue; 600480093f4SDimitry Andric IntLiteralResult(const ScalarType *IntegerType, uint32_t IntegerValue) 601480093f4SDimitry Andric : IntegerType(IntegerType), IntegerValue(IntegerValue) {} 602480093f4SDimitry Andric void genCode(raw_ostream &OS, 603480093f4SDimitry Andric CodeGenParamAllocator &ParamAlloc) const override { 604480093f4SDimitry Andric OS << "llvm::ConstantInt::get(" 605480093f4SDimitry Andric << ParamAlloc.allocParam("llvm::Type *", IntegerType->llvmName()) 606480093f4SDimitry Andric << ", "; 607480093f4SDimitry Andric OS << ParamAlloc.allocParam(IntegerType->cName(), utostr(IntegerValue)) 608480093f4SDimitry Andric << ")"; 609480093f4SDimitry Andric } 610480093f4SDimitry Andric bool hasIntegerConstantValue() const override { return true; } 611480093f4SDimitry Andric uint32_t integerConstantValue() const override { return IntegerValue; } 612480093f4SDimitry Andric }; 613480093f4SDimitry Andric 614480093f4SDimitry Andric // Result subclass representing a cast between different integer types. We use 615480093f4SDimitry Andric // our own ScalarType abstraction as the representation of the target type, 616480093f4SDimitry Andric // which gives both size and signedness. 617480093f4SDimitry Andric class IntCastResult : public Result { 618480093f4SDimitry Andric public: 619480093f4SDimitry Andric const ScalarType *IntegerType; 620480093f4SDimitry Andric Ptr V; 621480093f4SDimitry Andric IntCastResult(const ScalarType *IntegerType, Ptr V) 622480093f4SDimitry Andric : IntegerType(IntegerType), V(V) {} 623480093f4SDimitry Andric void genCode(raw_ostream &OS, 624480093f4SDimitry Andric CodeGenParamAllocator &ParamAlloc) const override { 625480093f4SDimitry Andric OS << "Builder.CreateIntCast(" << V->varname() << ", " 626480093f4SDimitry Andric << ParamAlloc.allocParam("llvm::Type *", IntegerType->llvmName()) << ", " 627480093f4SDimitry Andric << ParamAlloc.allocParam("bool", 628480093f4SDimitry Andric IntegerType->kind() == ScalarTypeKind::SignedInt 629480093f4SDimitry Andric ? "true" 630480093f4SDimitry Andric : "false") 631480093f4SDimitry Andric << ")"; 632480093f4SDimitry Andric } 633480093f4SDimitry Andric void morePrerequisites(std::vector<Ptr> &output) const override { 634480093f4SDimitry Andric output.push_back(V); 635480093f4SDimitry Andric } 636480093f4SDimitry Andric }; 637480093f4SDimitry Andric 638480093f4SDimitry Andric // Result subclass representing a cast between different pointer types. 639480093f4SDimitry Andric class PointerCastResult : public Result { 640480093f4SDimitry Andric public: 641480093f4SDimitry Andric const PointerType *PtrType; 642480093f4SDimitry Andric Ptr V; 643480093f4SDimitry Andric PointerCastResult(const PointerType *PtrType, Ptr V) 644480093f4SDimitry Andric : PtrType(PtrType), V(V) {} 645480093f4SDimitry Andric void genCode(raw_ostream &OS, 646480093f4SDimitry Andric CodeGenParamAllocator &ParamAlloc) const override { 647480093f4SDimitry Andric OS << "Builder.CreatePointerCast(" << V->asValue() << ", " 648480093f4SDimitry Andric << ParamAlloc.allocParam("llvm::Type *", PtrType->llvmName()) << ")"; 649480093f4SDimitry Andric } 650480093f4SDimitry Andric void morePrerequisites(std::vector<Ptr> &output) const override { 651480093f4SDimitry Andric output.push_back(V); 652480093f4SDimitry Andric } 653480093f4SDimitry Andric }; 654480093f4SDimitry Andric 655480093f4SDimitry Andric // Result subclass representing a call to an IRBuilder method. Each IRBuilder 656480093f4SDimitry Andric // method we want to use will have a Tablegen record giving the method name and 657480093f4SDimitry Andric // describing any important details of how to call it, such as whether a 658480093f4SDimitry Andric // particular argument should be an integer constant instead of an llvm::Value. 659480093f4SDimitry Andric class IRBuilderResult : public Result { 660480093f4SDimitry Andric public: 661480093f4SDimitry Andric StringRef CallPrefix; 662480093f4SDimitry Andric std::vector<Ptr> Args; 663480093f4SDimitry Andric std::set<unsigned> AddressArgs; 664480093f4SDimitry Andric std::map<unsigned, std::string> IntegerArgs; 665480093f4SDimitry Andric IRBuilderResult(StringRef CallPrefix, std::vector<Ptr> Args, 666480093f4SDimitry Andric std::set<unsigned> AddressArgs, 667480093f4SDimitry Andric std::map<unsigned, std::string> IntegerArgs) 668480093f4SDimitry Andric : CallPrefix(CallPrefix), Args(Args), AddressArgs(AddressArgs), 669480093f4SDimitry Andric IntegerArgs(IntegerArgs) {} 670480093f4SDimitry Andric void genCode(raw_ostream &OS, 671480093f4SDimitry Andric CodeGenParamAllocator &ParamAlloc) const override { 672480093f4SDimitry Andric OS << CallPrefix; 673480093f4SDimitry Andric const char *Sep = ""; 674480093f4SDimitry Andric for (unsigned i = 0, e = Args.size(); i < e; ++i) { 675480093f4SDimitry Andric Ptr Arg = Args[i]; 676480093f4SDimitry Andric auto it = IntegerArgs.find(i); 677480093f4SDimitry Andric 678480093f4SDimitry Andric OS << Sep; 679480093f4SDimitry Andric Sep = ", "; 680480093f4SDimitry Andric 681480093f4SDimitry Andric if (it != IntegerArgs.end()) { 682480093f4SDimitry Andric if (Arg->hasIntegerConstantValue()) 683480093f4SDimitry Andric OS << "static_cast<" << it->second << ">(" 684480093f4SDimitry Andric << ParamAlloc.allocParam(it->second, 685480093f4SDimitry Andric utostr(Arg->integerConstantValue())) 686480093f4SDimitry Andric << ")"; 687480093f4SDimitry Andric else if (Arg->hasIntegerValue()) 688480093f4SDimitry Andric OS << ParamAlloc.allocParam(it->second, 689480093f4SDimitry Andric Arg->getIntegerValue(it->second)); 690480093f4SDimitry Andric } else { 691480093f4SDimitry Andric OS << Arg->varname(); 692480093f4SDimitry Andric } 693480093f4SDimitry Andric } 694480093f4SDimitry Andric OS << ")"; 695480093f4SDimitry Andric } 696480093f4SDimitry Andric void morePrerequisites(std::vector<Ptr> &output) const override { 697480093f4SDimitry Andric for (unsigned i = 0, e = Args.size(); i < e; ++i) { 698480093f4SDimitry Andric Ptr Arg = Args[i]; 699480093f4SDimitry Andric if (IntegerArgs.find(i) != IntegerArgs.end()) 700480093f4SDimitry Andric continue; 701480093f4SDimitry Andric output.push_back(Arg); 702480093f4SDimitry Andric } 703480093f4SDimitry Andric } 704480093f4SDimitry Andric }; 705480093f4SDimitry Andric 706480093f4SDimitry Andric // Result subclass representing making an Address out of a Value. 707480093f4SDimitry Andric class AddressResult : public Result { 708480093f4SDimitry Andric public: 709480093f4SDimitry Andric Ptr Arg; 710480093f4SDimitry Andric unsigned Align; 711480093f4SDimitry Andric AddressResult(Ptr Arg, unsigned Align) : Arg(Arg), Align(Align) {} 712480093f4SDimitry Andric void genCode(raw_ostream &OS, 713480093f4SDimitry Andric CodeGenParamAllocator &ParamAlloc) const override { 714480093f4SDimitry Andric OS << "Address(" << Arg->varname() << ", CharUnits::fromQuantity(" 715480093f4SDimitry Andric << Align << "))"; 716480093f4SDimitry Andric } 717480093f4SDimitry Andric std::string typeName() const override { 718480093f4SDimitry Andric return "Address"; 719480093f4SDimitry Andric } 720480093f4SDimitry Andric void morePrerequisites(std::vector<Ptr> &output) const override { 721480093f4SDimitry Andric output.push_back(Arg); 722480093f4SDimitry Andric } 723480093f4SDimitry Andric }; 724480093f4SDimitry Andric 725480093f4SDimitry Andric // Result subclass representing a call to an IR intrinsic, which we first have 726480093f4SDimitry Andric // to look up using an Intrinsic::ID constant and an array of types. 727480093f4SDimitry Andric class IRIntrinsicResult : public Result { 728480093f4SDimitry Andric public: 729480093f4SDimitry Andric std::string IntrinsicID; 730480093f4SDimitry Andric std::vector<const Type *> ParamTypes; 731480093f4SDimitry Andric std::vector<Ptr> Args; 732480093f4SDimitry Andric IRIntrinsicResult(StringRef IntrinsicID, std::vector<const Type *> ParamTypes, 733480093f4SDimitry Andric std::vector<Ptr> Args) 734*5ffd83dbSDimitry Andric : IntrinsicID(std::string(IntrinsicID)), ParamTypes(ParamTypes), 735*5ffd83dbSDimitry Andric Args(Args) {} 736480093f4SDimitry Andric void genCode(raw_ostream &OS, 737480093f4SDimitry Andric CodeGenParamAllocator &ParamAlloc) const override { 738480093f4SDimitry Andric std::string IntNo = ParamAlloc.allocParam( 739480093f4SDimitry Andric "Intrinsic::ID", "Intrinsic::" + IntrinsicID); 740480093f4SDimitry Andric OS << "Builder.CreateCall(CGM.getIntrinsic(" << IntNo; 741480093f4SDimitry Andric if (!ParamTypes.empty()) { 742*5ffd83dbSDimitry Andric OS << ", {"; 743480093f4SDimitry Andric const char *Sep = ""; 744480093f4SDimitry Andric for (auto T : ParamTypes) { 745480093f4SDimitry Andric OS << Sep << ParamAlloc.allocParam("llvm::Type *", T->llvmName()); 746480093f4SDimitry Andric Sep = ", "; 747480093f4SDimitry Andric } 748480093f4SDimitry Andric OS << "}"; 749480093f4SDimitry Andric } 750*5ffd83dbSDimitry Andric OS << "), {"; 751480093f4SDimitry Andric const char *Sep = ""; 752480093f4SDimitry Andric for (auto Arg : Args) { 753480093f4SDimitry Andric OS << Sep << Arg->asValue(); 754480093f4SDimitry Andric Sep = ", "; 755480093f4SDimitry Andric } 756480093f4SDimitry Andric OS << "})"; 757480093f4SDimitry Andric } 758480093f4SDimitry Andric void morePrerequisites(std::vector<Ptr> &output) const override { 759480093f4SDimitry Andric output.insert(output.end(), Args.begin(), Args.end()); 760480093f4SDimitry Andric } 761480093f4SDimitry Andric }; 762480093f4SDimitry Andric 763480093f4SDimitry Andric // Result subclass that specifies a type, for use in IRBuilder operations such 764480093f4SDimitry Andric // as CreateBitCast that take a type argument. 765480093f4SDimitry Andric class TypeResult : public Result { 766480093f4SDimitry Andric public: 767480093f4SDimitry Andric const Type *T; 768480093f4SDimitry Andric TypeResult(const Type *T) : T(T) {} 769480093f4SDimitry Andric void genCode(raw_ostream &OS, CodeGenParamAllocator &) const override { 770480093f4SDimitry Andric OS << T->llvmName(); 771480093f4SDimitry Andric } 772480093f4SDimitry Andric std::string typeName() const override { 773480093f4SDimitry Andric return "llvm::Type *"; 774480093f4SDimitry Andric } 775480093f4SDimitry Andric }; 776480093f4SDimitry Andric 777480093f4SDimitry Andric // ----------------------------------------------------------------------------- 778480093f4SDimitry Andric // Class that describes a single ACLE intrinsic. 779480093f4SDimitry Andric // 780480093f4SDimitry Andric // A Tablegen record will typically describe more than one ACLE intrinsic, by 781480093f4SDimitry Andric // means of setting the 'list<Type> Params' field to a list of multiple 782480093f4SDimitry Andric // parameter types, so as to define vaddq_{s8,u8,...,f16,f32} all in one go. 783480093f4SDimitry Andric // We'll end up with one instance of ACLEIntrinsic for *each* parameter type, 784480093f4SDimitry Andric // rather than a single one for all of them. Hence, the constructor takes both 785480093f4SDimitry Andric // a Tablegen record and the current value of the parameter type. 786480093f4SDimitry Andric 787480093f4SDimitry Andric class ACLEIntrinsic { 788480093f4SDimitry Andric // Structure documenting that one of the intrinsic's arguments is required to 789480093f4SDimitry Andric // be a compile-time constant integer, and what constraints there are on its 790480093f4SDimitry Andric // value. Used when generating Sema checking code. 791480093f4SDimitry Andric struct ImmediateArg { 792480093f4SDimitry Andric enum class BoundsType { ExplicitRange, UInt }; 793480093f4SDimitry Andric BoundsType boundsType; 794480093f4SDimitry Andric int64_t i1, i2; 795480093f4SDimitry Andric StringRef ExtraCheckType, ExtraCheckArgs; 796480093f4SDimitry Andric const Type *ArgType; 797480093f4SDimitry Andric }; 798480093f4SDimitry Andric 799480093f4SDimitry Andric // For polymorphic intrinsics, FullName is the explicit name that uniquely 800480093f4SDimitry Andric // identifies this variant of the intrinsic, and ShortName is the name it 801480093f4SDimitry Andric // shares with at least one other intrinsic. 802480093f4SDimitry Andric std::string ShortName, FullName; 803480093f4SDimitry Andric 804*5ffd83dbSDimitry Andric // Name of the architecture extension, used in the Clang builtin name 805*5ffd83dbSDimitry Andric StringRef BuiltinExtension; 806*5ffd83dbSDimitry Andric 807480093f4SDimitry Andric // A very small number of intrinsics _only_ have a polymorphic 808480093f4SDimitry Andric // variant (vuninitializedq taking an unevaluated argument). 809480093f4SDimitry Andric bool PolymorphicOnly; 810480093f4SDimitry Andric 811480093f4SDimitry Andric // Another rarely-used flag indicating that the builtin doesn't 812480093f4SDimitry Andric // evaluate its argument(s) at all. 813480093f4SDimitry Andric bool NonEvaluating; 814480093f4SDimitry Andric 815*5ffd83dbSDimitry Andric // True if the intrinsic needs only the C header part (no codegen, semantic 816*5ffd83dbSDimitry Andric // checks, etc). Used for redeclaring MVE intrinsics in the arm_cde.h header. 817*5ffd83dbSDimitry Andric bool HeaderOnly; 818*5ffd83dbSDimitry Andric 819480093f4SDimitry Andric const Type *ReturnType; 820480093f4SDimitry Andric std::vector<const Type *> ArgTypes; 821480093f4SDimitry Andric std::map<unsigned, ImmediateArg> ImmediateArgs; 822480093f4SDimitry Andric Result::Ptr Code; 823480093f4SDimitry Andric 824480093f4SDimitry Andric std::map<std::string, std::string> CustomCodeGenArgs; 825480093f4SDimitry Andric 826480093f4SDimitry Andric // Recursive function that does the internals of code generation. 827480093f4SDimitry Andric void genCodeDfs(Result::Ptr V, std::list<Result::Ptr> &Used, 828480093f4SDimitry Andric unsigned Pass) const { 829480093f4SDimitry Andric if (!V->needsVisiting(Pass)) 830480093f4SDimitry Andric return; 831480093f4SDimitry Andric 832480093f4SDimitry Andric for (Result::Ptr W : V->prerequisites()) 833480093f4SDimitry Andric genCodeDfs(W, Used, Pass); 834480093f4SDimitry Andric 835480093f4SDimitry Andric Used.push_back(V); 836480093f4SDimitry Andric } 837480093f4SDimitry Andric 838480093f4SDimitry Andric public: 839480093f4SDimitry Andric const std::string &shortName() const { return ShortName; } 840480093f4SDimitry Andric const std::string &fullName() const { return FullName; } 841*5ffd83dbSDimitry Andric StringRef builtinExtension() const { return BuiltinExtension; } 842480093f4SDimitry Andric const Type *returnType() const { return ReturnType; } 843480093f4SDimitry Andric const std::vector<const Type *> &argTypes() const { return ArgTypes; } 844480093f4SDimitry Andric bool requiresFloat() const { 845480093f4SDimitry Andric if (ReturnType->requiresFloat()) 846480093f4SDimitry Andric return true; 847480093f4SDimitry Andric for (const Type *T : ArgTypes) 848480093f4SDimitry Andric if (T->requiresFloat()) 849480093f4SDimitry Andric return true; 850480093f4SDimitry Andric return false; 851480093f4SDimitry Andric } 852*5ffd83dbSDimitry Andric bool requiresMVE() const { 853*5ffd83dbSDimitry Andric return ReturnType->requiresMVE() || 854*5ffd83dbSDimitry Andric any_of(ArgTypes, [](const Type *T) { return T->requiresMVE(); }); 855*5ffd83dbSDimitry Andric } 856480093f4SDimitry Andric bool polymorphic() const { return ShortName != FullName; } 857480093f4SDimitry Andric bool polymorphicOnly() const { return PolymorphicOnly; } 858480093f4SDimitry Andric bool nonEvaluating() const { return NonEvaluating; } 859*5ffd83dbSDimitry Andric bool headerOnly() const { return HeaderOnly; } 860480093f4SDimitry Andric 861*5ffd83dbSDimitry Andric // External entry point for code generation, called from EmitterBase. 862480093f4SDimitry Andric void genCode(raw_ostream &OS, CodeGenParamAllocator &ParamAlloc, 863480093f4SDimitry Andric unsigned Pass) const { 864*5ffd83dbSDimitry Andric assert(!headerOnly() && "Called genCode for header-only intrinsic"); 865480093f4SDimitry Andric if (!hasCode()) { 866480093f4SDimitry Andric for (auto kv : CustomCodeGenArgs) 867480093f4SDimitry Andric OS << " " << kv.first << " = " << kv.second << ";\n"; 868480093f4SDimitry Andric OS << " break; // custom code gen\n"; 869480093f4SDimitry Andric return; 870480093f4SDimitry Andric } 871480093f4SDimitry Andric std::list<Result::Ptr> Used; 872480093f4SDimitry Andric genCodeDfs(Code, Used, Pass); 873480093f4SDimitry Andric 874480093f4SDimitry Andric unsigned varindex = 0; 875480093f4SDimitry Andric for (Result::Ptr V : Used) 876480093f4SDimitry Andric if (V->varnameUsed()) 877480093f4SDimitry Andric V->setVarname("Val" + utostr(varindex++)); 878480093f4SDimitry Andric 879480093f4SDimitry Andric for (Result::Ptr V : Used) { 880480093f4SDimitry Andric OS << " "; 881480093f4SDimitry Andric if (V == Used.back()) { 882480093f4SDimitry Andric assert(!V->varnameUsed()); 883480093f4SDimitry Andric OS << "return "; // FIXME: what if the top-level thing is void? 884480093f4SDimitry Andric } else if (V->varnameUsed()) { 885480093f4SDimitry Andric std::string Type = V->typeName(); 886480093f4SDimitry Andric OS << V->typeName(); 887480093f4SDimitry Andric if (!StringRef(Type).endswith("*")) 888480093f4SDimitry Andric OS << " "; 889480093f4SDimitry Andric OS << V->varname() << " = "; 890480093f4SDimitry Andric } 891480093f4SDimitry Andric V->genCode(OS, ParamAlloc); 892480093f4SDimitry Andric OS << ";\n"; 893480093f4SDimitry Andric } 894480093f4SDimitry Andric } 895480093f4SDimitry Andric bool hasCode() const { return Code != nullptr; } 896480093f4SDimitry Andric 897480093f4SDimitry Andric static std::string signedHexLiteral(const llvm::APInt &iOrig) { 898480093f4SDimitry Andric llvm::APInt i = iOrig.trunc(64); 899480093f4SDimitry Andric SmallString<40> s; 900480093f4SDimitry Andric i.toString(s, 16, true, true); 901*5ffd83dbSDimitry Andric return std::string(s.str()); 902480093f4SDimitry Andric } 903480093f4SDimitry Andric 904480093f4SDimitry Andric std::string genSema() const { 905*5ffd83dbSDimitry Andric assert(!headerOnly() && "Called genSema for header-only intrinsic"); 906480093f4SDimitry Andric std::vector<std::string> SemaChecks; 907480093f4SDimitry Andric 908480093f4SDimitry Andric for (const auto &kv : ImmediateArgs) { 909480093f4SDimitry Andric const ImmediateArg &IA = kv.second; 910480093f4SDimitry Andric 911480093f4SDimitry Andric llvm::APInt lo(128, 0), hi(128, 0); 912480093f4SDimitry Andric switch (IA.boundsType) { 913480093f4SDimitry Andric case ImmediateArg::BoundsType::ExplicitRange: 914480093f4SDimitry Andric lo = IA.i1; 915480093f4SDimitry Andric hi = IA.i2; 916480093f4SDimitry Andric break; 917480093f4SDimitry Andric case ImmediateArg::BoundsType::UInt: 918480093f4SDimitry Andric lo = 0; 919*5ffd83dbSDimitry Andric hi = llvm::APInt::getMaxValue(IA.i1).zext(128); 920480093f4SDimitry Andric break; 921480093f4SDimitry Andric } 922480093f4SDimitry Andric 923480093f4SDimitry Andric std::string Index = utostr(kv.first); 924480093f4SDimitry Andric 925*5ffd83dbSDimitry Andric // Emit a range check if the legal range of values for the 926*5ffd83dbSDimitry Andric // immediate is smaller than the _possible_ range of values for 927*5ffd83dbSDimitry Andric // its type. 928*5ffd83dbSDimitry Andric unsigned ArgTypeBits = IA.ArgType->sizeInBits(); 929*5ffd83dbSDimitry Andric llvm::APInt ArgTypeRange = llvm::APInt::getMaxValue(ArgTypeBits).zext(128); 930*5ffd83dbSDimitry Andric llvm::APInt ActualRange = (hi-lo).trunc(64).sext(128); 931*5ffd83dbSDimitry Andric if (ActualRange.ult(ArgTypeRange)) 932480093f4SDimitry Andric SemaChecks.push_back("SemaBuiltinConstantArgRange(TheCall, " + Index + 933480093f4SDimitry Andric ", " + signedHexLiteral(lo) + ", " + 934480093f4SDimitry Andric signedHexLiteral(hi) + ")"); 935480093f4SDimitry Andric 936480093f4SDimitry Andric if (!IA.ExtraCheckType.empty()) { 937480093f4SDimitry Andric std::string Suffix; 938*5ffd83dbSDimitry Andric if (!IA.ExtraCheckArgs.empty()) { 939*5ffd83dbSDimitry Andric std::string tmp; 940*5ffd83dbSDimitry Andric StringRef Arg = IA.ExtraCheckArgs; 941*5ffd83dbSDimitry Andric if (Arg == "!lanesize") { 942*5ffd83dbSDimitry Andric tmp = utostr(IA.ArgType->sizeInBits()); 943*5ffd83dbSDimitry Andric Arg = tmp; 944*5ffd83dbSDimitry Andric } 945*5ffd83dbSDimitry Andric Suffix = (Twine(", ") + Arg).str(); 946*5ffd83dbSDimitry Andric } 947480093f4SDimitry Andric SemaChecks.push_back((Twine("SemaBuiltinConstantArg") + 948480093f4SDimitry Andric IA.ExtraCheckType + "(TheCall, " + Index + 949480093f4SDimitry Andric Suffix + ")") 950480093f4SDimitry Andric .str()); 951480093f4SDimitry Andric } 952*5ffd83dbSDimitry Andric 953*5ffd83dbSDimitry Andric assert(!SemaChecks.empty()); 954480093f4SDimitry Andric } 955480093f4SDimitry Andric if (SemaChecks.empty()) 956480093f4SDimitry Andric return ""; 957*5ffd83dbSDimitry Andric return join(std::begin(SemaChecks), std::end(SemaChecks), 958480093f4SDimitry Andric " ||\n ") + 959*5ffd83dbSDimitry Andric ";\n"; 960480093f4SDimitry Andric } 961480093f4SDimitry Andric 962*5ffd83dbSDimitry Andric ACLEIntrinsic(EmitterBase &ME, Record *R, const Type *Param); 963480093f4SDimitry Andric }; 964480093f4SDimitry Andric 965480093f4SDimitry Andric // ----------------------------------------------------------------------------- 966480093f4SDimitry Andric // The top-level class that holds all the state from analyzing the entire 967480093f4SDimitry Andric // Tablegen input. 968480093f4SDimitry Andric 969*5ffd83dbSDimitry Andric class EmitterBase { 970*5ffd83dbSDimitry Andric protected: 971*5ffd83dbSDimitry Andric // EmitterBase holds a collection of all the types we've instantiated. 972480093f4SDimitry Andric VoidType Void; 973480093f4SDimitry Andric std::map<std::string, std::unique_ptr<ScalarType>> ScalarTypes; 974480093f4SDimitry Andric std::map<std::tuple<ScalarTypeKind, unsigned, unsigned>, 975480093f4SDimitry Andric std::unique_ptr<VectorType>> 976480093f4SDimitry Andric VectorTypes; 977480093f4SDimitry Andric std::map<std::pair<std::string, unsigned>, std::unique_ptr<MultiVectorType>> 978480093f4SDimitry Andric MultiVectorTypes; 979480093f4SDimitry Andric std::map<unsigned, std::unique_ptr<PredicateType>> PredicateTypes; 980480093f4SDimitry Andric std::map<std::string, std::unique_ptr<PointerType>> PointerTypes; 981480093f4SDimitry Andric 982480093f4SDimitry Andric // And all the ACLEIntrinsic instances we've created. 983480093f4SDimitry Andric std::map<std::string, std::unique_ptr<ACLEIntrinsic>> ACLEIntrinsics; 984480093f4SDimitry Andric 985480093f4SDimitry Andric public: 986480093f4SDimitry Andric // Methods to create a Type object, or return the right existing one from the 987480093f4SDimitry Andric // maps stored in this object. 988480093f4SDimitry Andric const VoidType *getVoidType() { return &Void; } 989480093f4SDimitry Andric const ScalarType *getScalarType(StringRef Name) { 990*5ffd83dbSDimitry Andric return ScalarTypes[std::string(Name)].get(); 991480093f4SDimitry Andric } 992480093f4SDimitry Andric const ScalarType *getScalarType(Record *R) { 993480093f4SDimitry Andric return getScalarType(R->getName()); 994480093f4SDimitry Andric } 995480093f4SDimitry Andric const VectorType *getVectorType(const ScalarType *ST, unsigned Lanes) { 996480093f4SDimitry Andric std::tuple<ScalarTypeKind, unsigned, unsigned> key(ST->kind(), 997480093f4SDimitry Andric ST->sizeInBits(), Lanes); 998480093f4SDimitry Andric if (VectorTypes.find(key) == VectorTypes.end()) 999480093f4SDimitry Andric VectorTypes[key] = std::make_unique<VectorType>(ST, Lanes); 1000480093f4SDimitry Andric return VectorTypes[key].get(); 1001480093f4SDimitry Andric } 1002480093f4SDimitry Andric const VectorType *getVectorType(const ScalarType *ST) { 1003480093f4SDimitry Andric return getVectorType(ST, 128 / ST->sizeInBits()); 1004480093f4SDimitry Andric } 1005480093f4SDimitry Andric const MultiVectorType *getMultiVectorType(unsigned Registers, 1006480093f4SDimitry Andric const VectorType *VT) { 1007480093f4SDimitry Andric std::pair<std::string, unsigned> key(VT->cNameBase(), Registers); 1008480093f4SDimitry Andric if (MultiVectorTypes.find(key) == MultiVectorTypes.end()) 1009480093f4SDimitry Andric MultiVectorTypes[key] = std::make_unique<MultiVectorType>(Registers, VT); 1010480093f4SDimitry Andric return MultiVectorTypes[key].get(); 1011480093f4SDimitry Andric } 1012480093f4SDimitry Andric const PredicateType *getPredicateType(unsigned Lanes) { 1013480093f4SDimitry Andric unsigned key = Lanes; 1014480093f4SDimitry Andric if (PredicateTypes.find(key) == PredicateTypes.end()) 1015480093f4SDimitry Andric PredicateTypes[key] = std::make_unique<PredicateType>(Lanes); 1016480093f4SDimitry Andric return PredicateTypes[key].get(); 1017480093f4SDimitry Andric } 1018480093f4SDimitry Andric const PointerType *getPointerType(const Type *T, bool Const) { 1019480093f4SDimitry Andric PointerType PT(T, Const); 1020480093f4SDimitry Andric std::string key = PT.cName(); 1021480093f4SDimitry Andric if (PointerTypes.find(key) == PointerTypes.end()) 1022480093f4SDimitry Andric PointerTypes[key] = std::make_unique<PointerType>(PT); 1023480093f4SDimitry Andric return PointerTypes[key].get(); 1024480093f4SDimitry Andric } 1025480093f4SDimitry Andric 1026480093f4SDimitry Andric // Methods to construct a type from various pieces of Tablegen. These are 1027480093f4SDimitry Andric // always called in the context of setting up a particular ACLEIntrinsic, so 1028480093f4SDimitry Andric // there's always an ambient parameter type (because we're iterating through 1029480093f4SDimitry Andric // the Params list in the Tablegen record for the intrinsic), which is used 1030480093f4SDimitry Andric // to expand Tablegen classes like 'Vector' which mean something different in 1031480093f4SDimitry Andric // each member of a parametric family. 1032480093f4SDimitry Andric const Type *getType(Record *R, const Type *Param); 1033480093f4SDimitry Andric const Type *getType(DagInit *D, const Type *Param); 1034480093f4SDimitry Andric const Type *getType(Init *I, const Type *Param); 1035480093f4SDimitry Andric 1036480093f4SDimitry Andric // Functions that translate the Tablegen representation of an intrinsic's 1037480093f4SDimitry Andric // code generation into a collection of Value objects (which will then be 1038480093f4SDimitry Andric // reprocessed to read out the actual C++ code included by CGBuiltin.cpp). 1039480093f4SDimitry Andric Result::Ptr getCodeForDag(DagInit *D, const Result::Scope &Scope, 1040480093f4SDimitry Andric const Type *Param); 1041480093f4SDimitry Andric Result::Ptr getCodeForDagArg(DagInit *D, unsigned ArgNum, 1042480093f4SDimitry Andric const Result::Scope &Scope, const Type *Param); 1043480093f4SDimitry Andric Result::Ptr getCodeForArg(unsigned ArgNum, const Type *ArgType, bool Promote, 1044480093f4SDimitry Andric bool Immediate); 1045480093f4SDimitry Andric 1046*5ffd83dbSDimitry Andric void GroupSemaChecks(std::map<std::string, std::set<std::string>> &Checks); 1047*5ffd83dbSDimitry Andric 1048480093f4SDimitry Andric // Constructor and top-level functions. 1049480093f4SDimitry Andric 1050*5ffd83dbSDimitry Andric EmitterBase(RecordKeeper &Records); 1051*5ffd83dbSDimitry Andric virtual ~EmitterBase() = default; 1052480093f4SDimitry Andric 1053*5ffd83dbSDimitry Andric virtual void EmitHeader(raw_ostream &OS) = 0; 1054*5ffd83dbSDimitry Andric virtual void EmitBuiltinDef(raw_ostream &OS) = 0; 1055*5ffd83dbSDimitry Andric virtual void EmitBuiltinSema(raw_ostream &OS) = 0; 1056480093f4SDimitry Andric void EmitBuiltinCG(raw_ostream &OS); 1057480093f4SDimitry Andric void EmitBuiltinAliases(raw_ostream &OS); 1058480093f4SDimitry Andric }; 1059480093f4SDimitry Andric 1060*5ffd83dbSDimitry Andric const Type *EmitterBase::getType(Init *I, const Type *Param) { 1061480093f4SDimitry Andric if (auto Dag = dyn_cast<DagInit>(I)) 1062480093f4SDimitry Andric return getType(Dag, Param); 1063480093f4SDimitry Andric if (auto Def = dyn_cast<DefInit>(I)) 1064480093f4SDimitry Andric return getType(Def->getDef(), Param); 1065480093f4SDimitry Andric 1066480093f4SDimitry Andric PrintFatalError("Could not convert this value into a type"); 1067480093f4SDimitry Andric } 1068480093f4SDimitry Andric 1069*5ffd83dbSDimitry Andric const Type *EmitterBase::getType(Record *R, const Type *Param) { 1070480093f4SDimitry Andric // Pass to a subfield of any wrapper records. We don't expect more than one 1071480093f4SDimitry Andric // of these: immediate operands are used as plain numbers rather than as 1072480093f4SDimitry Andric // llvm::Value, so it's meaningless to promote their type anyway. 1073480093f4SDimitry Andric if (R->isSubClassOf("Immediate")) 1074480093f4SDimitry Andric R = R->getValueAsDef("type"); 1075480093f4SDimitry Andric else if (R->isSubClassOf("unpromoted")) 1076480093f4SDimitry Andric R = R->getValueAsDef("underlying_type"); 1077480093f4SDimitry Andric 1078480093f4SDimitry Andric if (R->getName() == "Void") 1079480093f4SDimitry Andric return getVoidType(); 1080480093f4SDimitry Andric if (R->isSubClassOf("PrimitiveType")) 1081480093f4SDimitry Andric return getScalarType(R); 1082480093f4SDimitry Andric if (R->isSubClassOf("ComplexType")) 1083480093f4SDimitry Andric return getType(R->getValueAsDag("spec"), Param); 1084480093f4SDimitry Andric 1085480093f4SDimitry Andric PrintFatalError(R->getLoc(), "Could not convert this record into a type"); 1086480093f4SDimitry Andric } 1087480093f4SDimitry Andric 1088*5ffd83dbSDimitry Andric const Type *EmitterBase::getType(DagInit *D, const Type *Param) { 1089480093f4SDimitry Andric // The meat of the getType system: types in the Tablegen are represented by a 1090480093f4SDimitry Andric // dag whose operators select sub-cases of this function. 1091480093f4SDimitry Andric 1092480093f4SDimitry Andric Record *Op = cast<DefInit>(D->getOperator())->getDef(); 1093480093f4SDimitry Andric if (!Op->isSubClassOf("ComplexTypeOp")) 1094480093f4SDimitry Andric PrintFatalError( 1095480093f4SDimitry Andric "Expected ComplexTypeOp as dag operator in type expression"); 1096480093f4SDimitry Andric 1097480093f4SDimitry Andric if (Op->getName() == "CTO_Parameter") { 1098480093f4SDimitry Andric if (isa<VoidType>(Param)) 1099480093f4SDimitry Andric PrintFatalError("Parametric type in unparametrised context"); 1100480093f4SDimitry Andric return Param; 1101480093f4SDimitry Andric } 1102480093f4SDimitry Andric 1103480093f4SDimitry Andric if (Op->getName() == "CTO_Vec") { 1104480093f4SDimitry Andric const Type *Element = getType(D->getArg(0), Param); 1105480093f4SDimitry Andric if (D->getNumArgs() == 1) { 1106480093f4SDimitry Andric return getVectorType(cast<ScalarType>(Element)); 1107480093f4SDimitry Andric } else { 1108480093f4SDimitry Andric const Type *ExistingVector = getType(D->getArg(1), Param); 1109480093f4SDimitry Andric return getVectorType(cast<ScalarType>(Element), 1110480093f4SDimitry Andric cast<VectorType>(ExistingVector)->lanes()); 1111480093f4SDimitry Andric } 1112480093f4SDimitry Andric } 1113480093f4SDimitry Andric 1114480093f4SDimitry Andric if (Op->getName() == "CTO_Pred") { 1115480093f4SDimitry Andric const Type *Element = getType(D->getArg(0), Param); 1116480093f4SDimitry Andric return getPredicateType(128 / Element->sizeInBits()); 1117480093f4SDimitry Andric } 1118480093f4SDimitry Andric 1119480093f4SDimitry Andric if (Op->isSubClassOf("CTO_Tuple")) { 1120480093f4SDimitry Andric unsigned Registers = Op->getValueAsInt("n"); 1121480093f4SDimitry Andric const Type *Element = getType(D->getArg(0), Param); 1122480093f4SDimitry Andric return getMultiVectorType(Registers, cast<VectorType>(Element)); 1123480093f4SDimitry Andric } 1124480093f4SDimitry Andric 1125480093f4SDimitry Andric if (Op->isSubClassOf("CTO_Pointer")) { 1126480093f4SDimitry Andric const Type *Pointee = getType(D->getArg(0), Param); 1127480093f4SDimitry Andric return getPointerType(Pointee, Op->getValueAsBit("const")); 1128480093f4SDimitry Andric } 1129480093f4SDimitry Andric 1130480093f4SDimitry Andric if (Op->getName() == "CTO_CopyKind") { 1131480093f4SDimitry Andric const ScalarType *STSize = cast<ScalarType>(getType(D->getArg(0), Param)); 1132480093f4SDimitry Andric const ScalarType *STKind = cast<ScalarType>(getType(D->getArg(1), Param)); 1133480093f4SDimitry Andric for (const auto &kv : ScalarTypes) { 1134480093f4SDimitry Andric const ScalarType *RT = kv.second.get(); 1135480093f4SDimitry Andric if (RT->kind() == STKind->kind() && RT->sizeInBits() == STSize->sizeInBits()) 1136480093f4SDimitry Andric return RT; 1137480093f4SDimitry Andric } 1138480093f4SDimitry Andric PrintFatalError("Cannot find a type to satisfy CopyKind"); 1139480093f4SDimitry Andric } 1140480093f4SDimitry Andric 1141480093f4SDimitry Andric if (Op->isSubClassOf("CTO_ScaleSize")) { 1142480093f4SDimitry Andric const ScalarType *STKind = cast<ScalarType>(getType(D->getArg(0), Param)); 1143480093f4SDimitry Andric int Num = Op->getValueAsInt("num"), Denom = Op->getValueAsInt("denom"); 1144480093f4SDimitry Andric unsigned DesiredSize = STKind->sizeInBits() * Num / Denom; 1145480093f4SDimitry Andric for (const auto &kv : ScalarTypes) { 1146480093f4SDimitry Andric const ScalarType *RT = kv.second.get(); 1147480093f4SDimitry Andric if (RT->kind() == STKind->kind() && RT->sizeInBits() == DesiredSize) 1148480093f4SDimitry Andric return RT; 1149480093f4SDimitry Andric } 1150480093f4SDimitry Andric PrintFatalError("Cannot find a type to satisfy ScaleSize"); 1151480093f4SDimitry Andric } 1152480093f4SDimitry Andric 1153480093f4SDimitry Andric PrintFatalError("Bad operator in type dag expression"); 1154480093f4SDimitry Andric } 1155480093f4SDimitry Andric 1156*5ffd83dbSDimitry Andric Result::Ptr EmitterBase::getCodeForDag(DagInit *D, const Result::Scope &Scope, 1157480093f4SDimitry Andric const Type *Param) { 1158480093f4SDimitry Andric Record *Op = cast<DefInit>(D->getOperator())->getDef(); 1159480093f4SDimitry Andric 1160480093f4SDimitry Andric if (Op->getName() == "seq") { 1161480093f4SDimitry Andric Result::Scope SubScope = Scope; 1162480093f4SDimitry Andric Result::Ptr PrevV = nullptr; 1163480093f4SDimitry Andric for (unsigned i = 0, e = D->getNumArgs(); i < e; ++i) { 1164480093f4SDimitry Andric // We don't use getCodeForDagArg here, because the argument name 1165480093f4SDimitry Andric // has different semantics in a seq 1166480093f4SDimitry Andric Result::Ptr V = 1167480093f4SDimitry Andric getCodeForDag(cast<DagInit>(D->getArg(i)), SubScope, Param); 1168480093f4SDimitry Andric StringRef ArgName = D->getArgNameStr(i); 1169480093f4SDimitry Andric if (!ArgName.empty()) 1170*5ffd83dbSDimitry Andric SubScope[std::string(ArgName)] = V; 1171480093f4SDimitry Andric if (PrevV) 1172480093f4SDimitry Andric V->setPredecessor(PrevV); 1173480093f4SDimitry Andric PrevV = V; 1174480093f4SDimitry Andric } 1175480093f4SDimitry Andric return PrevV; 1176480093f4SDimitry Andric } else if (Op->isSubClassOf("Type")) { 1177480093f4SDimitry Andric if (D->getNumArgs() != 1) 1178480093f4SDimitry Andric PrintFatalError("Type casts should have exactly one argument"); 1179480093f4SDimitry Andric const Type *CastType = getType(Op, Param); 1180480093f4SDimitry Andric Result::Ptr Arg = getCodeForDagArg(D, 0, Scope, Param); 1181480093f4SDimitry Andric if (const auto *ST = dyn_cast<ScalarType>(CastType)) { 1182480093f4SDimitry Andric if (!ST->requiresFloat()) { 1183480093f4SDimitry Andric if (Arg->hasIntegerConstantValue()) 1184480093f4SDimitry Andric return std::make_shared<IntLiteralResult>( 1185480093f4SDimitry Andric ST, Arg->integerConstantValue()); 1186480093f4SDimitry Andric else 1187480093f4SDimitry Andric return std::make_shared<IntCastResult>(ST, Arg); 1188480093f4SDimitry Andric } 1189480093f4SDimitry Andric } else if (const auto *PT = dyn_cast<PointerType>(CastType)) { 1190480093f4SDimitry Andric return std::make_shared<PointerCastResult>(PT, Arg); 1191480093f4SDimitry Andric } 1192480093f4SDimitry Andric PrintFatalError("Unsupported type cast"); 1193480093f4SDimitry Andric } else if (Op->getName() == "address") { 1194480093f4SDimitry Andric if (D->getNumArgs() != 2) 1195480093f4SDimitry Andric PrintFatalError("'address' should have two arguments"); 1196480093f4SDimitry Andric Result::Ptr Arg = getCodeForDagArg(D, 0, Scope, Param); 1197480093f4SDimitry Andric unsigned Alignment; 1198480093f4SDimitry Andric if (auto *II = dyn_cast<IntInit>(D->getArg(1))) { 1199480093f4SDimitry Andric Alignment = II->getValue(); 1200480093f4SDimitry Andric } else { 1201480093f4SDimitry Andric PrintFatalError("'address' alignment argument should be an integer"); 1202480093f4SDimitry Andric } 1203480093f4SDimitry Andric return std::make_shared<AddressResult>(Arg, Alignment); 1204480093f4SDimitry Andric } else if (Op->getName() == "unsignedflag") { 1205480093f4SDimitry Andric if (D->getNumArgs() != 1) 1206480093f4SDimitry Andric PrintFatalError("unsignedflag should have exactly one argument"); 1207480093f4SDimitry Andric Record *TypeRec = cast<DefInit>(D->getArg(0))->getDef(); 1208480093f4SDimitry Andric if (!TypeRec->isSubClassOf("Type")) 1209480093f4SDimitry Andric PrintFatalError("unsignedflag's argument should be a type"); 1210480093f4SDimitry Andric if (const auto *ST = dyn_cast<ScalarType>(getType(TypeRec, Param))) { 1211480093f4SDimitry Andric return std::make_shared<IntLiteralResult>( 1212480093f4SDimitry Andric getScalarType("u32"), ST->kind() == ScalarTypeKind::UnsignedInt); 1213480093f4SDimitry Andric } else { 1214480093f4SDimitry Andric PrintFatalError("unsignedflag's argument should be a scalar type"); 1215480093f4SDimitry Andric } 1216*5ffd83dbSDimitry Andric } else if (Op->getName() == "bitsize") { 1217*5ffd83dbSDimitry Andric if (D->getNumArgs() != 1) 1218*5ffd83dbSDimitry Andric PrintFatalError("bitsize should have exactly one argument"); 1219*5ffd83dbSDimitry Andric Record *TypeRec = cast<DefInit>(D->getArg(0))->getDef(); 1220*5ffd83dbSDimitry Andric if (!TypeRec->isSubClassOf("Type")) 1221*5ffd83dbSDimitry Andric PrintFatalError("bitsize's argument should be a type"); 1222*5ffd83dbSDimitry Andric if (const auto *ST = dyn_cast<ScalarType>(getType(TypeRec, Param))) { 1223*5ffd83dbSDimitry Andric return std::make_shared<IntLiteralResult>(getScalarType("u32"), 1224*5ffd83dbSDimitry Andric ST->sizeInBits()); 1225*5ffd83dbSDimitry Andric } else { 1226*5ffd83dbSDimitry Andric PrintFatalError("bitsize's argument should be a scalar type"); 1227*5ffd83dbSDimitry Andric } 1228480093f4SDimitry Andric } else { 1229480093f4SDimitry Andric std::vector<Result::Ptr> Args; 1230480093f4SDimitry Andric for (unsigned i = 0, e = D->getNumArgs(); i < e; ++i) 1231480093f4SDimitry Andric Args.push_back(getCodeForDagArg(D, i, Scope, Param)); 1232480093f4SDimitry Andric if (Op->isSubClassOf("IRBuilderBase")) { 1233480093f4SDimitry Andric std::set<unsigned> AddressArgs; 1234480093f4SDimitry Andric std::map<unsigned, std::string> IntegerArgs; 1235480093f4SDimitry Andric for (Record *sp : Op->getValueAsListOfDefs("special_params")) { 1236480093f4SDimitry Andric unsigned Index = sp->getValueAsInt("index"); 1237480093f4SDimitry Andric if (sp->isSubClassOf("IRBuilderAddrParam")) { 1238480093f4SDimitry Andric AddressArgs.insert(Index); 1239480093f4SDimitry Andric } else if (sp->isSubClassOf("IRBuilderIntParam")) { 1240*5ffd83dbSDimitry Andric IntegerArgs[Index] = std::string(sp->getValueAsString("type")); 1241480093f4SDimitry Andric } 1242480093f4SDimitry Andric } 1243480093f4SDimitry Andric return std::make_shared<IRBuilderResult>(Op->getValueAsString("prefix"), 1244480093f4SDimitry Andric Args, AddressArgs, IntegerArgs); 1245480093f4SDimitry Andric } else if (Op->isSubClassOf("IRIntBase")) { 1246480093f4SDimitry Andric std::vector<const Type *> ParamTypes; 1247480093f4SDimitry Andric for (Record *RParam : Op->getValueAsListOfDefs("params")) 1248480093f4SDimitry Andric ParamTypes.push_back(getType(RParam, Param)); 1249*5ffd83dbSDimitry Andric std::string IntName = std::string(Op->getValueAsString("intname")); 1250480093f4SDimitry Andric if (Op->getValueAsBit("appendKind")) 1251480093f4SDimitry Andric IntName += "_" + toLetter(cast<ScalarType>(Param)->kind()); 1252480093f4SDimitry Andric return std::make_shared<IRIntrinsicResult>(IntName, ParamTypes, Args); 1253480093f4SDimitry Andric } else { 1254480093f4SDimitry Andric PrintFatalError("Unsupported dag node " + Op->getName()); 1255480093f4SDimitry Andric } 1256480093f4SDimitry Andric } 1257480093f4SDimitry Andric } 1258480093f4SDimitry Andric 1259*5ffd83dbSDimitry Andric Result::Ptr EmitterBase::getCodeForDagArg(DagInit *D, unsigned ArgNum, 1260480093f4SDimitry Andric const Result::Scope &Scope, 1261480093f4SDimitry Andric const Type *Param) { 1262480093f4SDimitry Andric Init *Arg = D->getArg(ArgNum); 1263480093f4SDimitry Andric StringRef Name = D->getArgNameStr(ArgNum); 1264480093f4SDimitry Andric 1265480093f4SDimitry Andric if (!Name.empty()) { 1266480093f4SDimitry Andric if (!isa<UnsetInit>(Arg)) 1267480093f4SDimitry Andric PrintFatalError( 1268480093f4SDimitry Andric "dag operator argument should not have both a value and a name"); 1269*5ffd83dbSDimitry Andric auto it = Scope.find(std::string(Name)); 1270480093f4SDimitry Andric if (it == Scope.end()) 1271480093f4SDimitry Andric PrintFatalError("unrecognized variable name '" + Name + "'"); 1272480093f4SDimitry Andric return it->second; 1273480093f4SDimitry Andric } 1274480093f4SDimitry Andric 1275480093f4SDimitry Andric if (auto *II = dyn_cast<IntInit>(Arg)) 1276480093f4SDimitry Andric return std::make_shared<IntLiteralResult>(getScalarType("u32"), 1277480093f4SDimitry Andric II->getValue()); 1278480093f4SDimitry Andric 1279480093f4SDimitry Andric if (auto *DI = dyn_cast<DagInit>(Arg)) 1280480093f4SDimitry Andric return getCodeForDag(DI, Scope, Param); 1281480093f4SDimitry Andric 1282480093f4SDimitry Andric if (auto *DI = dyn_cast<DefInit>(Arg)) { 1283480093f4SDimitry Andric Record *Rec = DI->getDef(); 1284480093f4SDimitry Andric if (Rec->isSubClassOf("Type")) { 1285480093f4SDimitry Andric const Type *T = getType(Rec, Param); 1286480093f4SDimitry Andric return std::make_shared<TypeResult>(T); 1287480093f4SDimitry Andric } 1288480093f4SDimitry Andric } 1289480093f4SDimitry Andric 1290480093f4SDimitry Andric PrintFatalError("bad dag argument type for code generation"); 1291480093f4SDimitry Andric } 1292480093f4SDimitry Andric 1293*5ffd83dbSDimitry Andric Result::Ptr EmitterBase::getCodeForArg(unsigned ArgNum, const Type *ArgType, 1294480093f4SDimitry Andric bool Promote, bool Immediate) { 1295480093f4SDimitry Andric Result::Ptr V = std::make_shared<BuiltinArgResult>( 1296480093f4SDimitry Andric ArgNum, isa<PointerType>(ArgType), Immediate); 1297480093f4SDimitry Andric 1298480093f4SDimitry Andric if (Promote) { 1299480093f4SDimitry Andric if (const auto *ST = dyn_cast<ScalarType>(ArgType)) { 1300480093f4SDimitry Andric if (ST->isInteger() && ST->sizeInBits() < 32) 1301480093f4SDimitry Andric V = std::make_shared<IntCastResult>(getScalarType("u32"), V); 1302480093f4SDimitry Andric } else if (const auto *PT = dyn_cast<PredicateType>(ArgType)) { 1303480093f4SDimitry Andric V = std::make_shared<IntCastResult>(getScalarType("u32"), V); 1304480093f4SDimitry Andric V = std::make_shared<IRIntrinsicResult>("arm_mve_pred_i2v", 1305480093f4SDimitry Andric std::vector<const Type *>{PT}, 1306480093f4SDimitry Andric std::vector<Result::Ptr>{V}); 1307480093f4SDimitry Andric } 1308480093f4SDimitry Andric } 1309480093f4SDimitry Andric 1310480093f4SDimitry Andric return V; 1311480093f4SDimitry Andric } 1312480093f4SDimitry Andric 1313*5ffd83dbSDimitry Andric ACLEIntrinsic::ACLEIntrinsic(EmitterBase &ME, Record *R, const Type *Param) 1314480093f4SDimitry Andric : ReturnType(ME.getType(R->getValueAsDef("ret"), Param)) { 1315480093f4SDimitry Andric // Derive the intrinsic's full name, by taking the name of the 1316480093f4SDimitry Andric // Tablegen record (or override) and appending the suffix from its 1317480093f4SDimitry Andric // parameter type. (If the intrinsic is unparametrised, its 1318480093f4SDimitry Andric // parameter type will be given as Void, which returns the empty 1319480093f4SDimitry Andric // string for acleSuffix.) 1320480093f4SDimitry Andric StringRef BaseName = 1321480093f4SDimitry Andric (R->isSubClassOf("NameOverride") ? R->getValueAsString("basename") 1322480093f4SDimitry Andric : R->getName()); 1323480093f4SDimitry Andric StringRef overrideLetter = R->getValueAsString("overrideKindLetter"); 1324*5ffd83dbSDimitry Andric FullName = 1325*5ffd83dbSDimitry Andric (Twine(BaseName) + Param->acleSuffix(std::string(overrideLetter))).str(); 1326480093f4SDimitry Andric 1327480093f4SDimitry Andric // Derive the intrinsic's polymorphic name, by removing components from the 1328480093f4SDimitry Andric // full name as specified by its 'pnt' member ('polymorphic name type'), 1329480093f4SDimitry Andric // which indicates how many type suffixes to remove, and any other piece of 1330480093f4SDimitry Andric // the name that should be removed. 1331480093f4SDimitry Andric Record *PolymorphicNameType = R->getValueAsDef("pnt"); 1332480093f4SDimitry Andric SmallVector<StringRef, 8> NameParts; 1333480093f4SDimitry Andric StringRef(FullName).split(NameParts, '_'); 1334480093f4SDimitry Andric for (unsigned i = 0, e = PolymorphicNameType->getValueAsInt( 1335480093f4SDimitry Andric "NumTypeSuffixesToDiscard"); 1336480093f4SDimitry Andric i < e; ++i) 1337480093f4SDimitry Andric NameParts.pop_back(); 1338480093f4SDimitry Andric if (!PolymorphicNameType->isValueUnset("ExtraSuffixToDiscard")) { 1339480093f4SDimitry Andric StringRef ExtraSuffix = 1340480093f4SDimitry Andric PolymorphicNameType->getValueAsString("ExtraSuffixToDiscard"); 1341480093f4SDimitry Andric auto it = NameParts.end(); 1342480093f4SDimitry Andric while (it != NameParts.begin()) { 1343480093f4SDimitry Andric --it; 1344480093f4SDimitry Andric if (*it == ExtraSuffix) { 1345480093f4SDimitry Andric NameParts.erase(it); 1346480093f4SDimitry Andric break; 1347480093f4SDimitry Andric } 1348480093f4SDimitry Andric } 1349480093f4SDimitry Andric } 1350480093f4SDimitry Andric ShortName = join(std::begin(NameParts), std::end(NameParts), "_"); 1351480093f4SDimitry Andric 1352*5ffd83dbSDimitry Andric BuiltinExtension = R->getValueAsString("builtinExtension"); 1353*5ffd83dbSDimitry Andric 1354480093f4SDimitry Andric PolymorphicOnly = R->getValueAsBit("polymorphicOnly"); 1355480093f4SDimitry Andric NonEvaluating = R->getValueAsBit("nonEvaluating"); 1356*5ffd83dbSDimitry Andric HeaderOnly = R->getValueAsBit("headerOnly"); 1357480093f4SDimitry Andric 1358480093f4SDimitry Andric // Process the intrinsic's argument list. 1359480093f4SDimitry Andric DagInit *ArgsDag = R->getValueAsDag("args"); 1360480093f4SDimitry Andric Result::Scope Scope; 1361480093f4SDimitry Andric for (unsigned i = 0, e = ArgsDag->getNumArgs(); i < e; ++i) { 1362480093f4SDimitry Andric Init *TypeInit = ArgsDag->getArg(i); 1363480093f4SDimitry Andric 1364480093f4SDimitry Andric bool Promote = true; 1365480093f4SDimitry Andric if (auto TypeDI = dyn_cast<DefInit>(TypeInit)) 1366480093f4SDimitry Andric if (TypeDI->getDef()->isSubClassOf("unpromoted")) 1367480093f4SDimitry Andric Promote = false; 1368480093f4SDimitry Andric 1369480093f4SDimitry Andric // Work out the type of the argument, for use in the function prototype in 1370480093f4SDimitry Andric // the header file. 1371480093f4SDimitry Andric const Type *ArgType = ME.getType(TypeInit, Param); 1372480093f4SDimitry Andric ArgTypes.push_back(ArgType); 1373480093f4SDimitry Andric 1374480093f4SDimitry Andric // If the argument is a subclass of Immediate, record the details about 1375480093f4SDimitry Andric // what values it can take, for Sema checking. 1376480093f4SDimitry Andric bool Immediate = false; 1377480093f4SDimitry Andric if (auto TypeDI = dyn_cast<DefInit>(TypeInit)) { 1378480093f4SDimitry Andric Record *TypeRec = TypeDI->getDef(); 1379480093f4SDimitry Andric if (TypeRec->isSubClassOf("Immediate")) { 1380480093f4SDimitry Andric Immediate = true; 1381480093f4SDimitry Andric 1382480093f4SDimitry Andric Record *Bounds = TypeRec->getValueAsDef("bounds"); 1383480093f4SDimitry Andric ImmediateArg &IA = ImmediateArgs[i]; 1384480093f4SDimitry Andric if (Bounds->isSubClassOf("IB_ConstRange")) { 1385480093f4SDimitry Andric IA.boundsType = ImmediateArg::BoundsType::ExplicitRange; 1386480093f4SDimitry Andric IA.i1 = Bounds->getValueAsInt("lo"); 1387480093f4SDimitry Andric IA.i2 = Bounds->getValueAsInt("hi"); 1388480093f4SDimitry Andric } else if (Bounds->getName() == "IB_UEltValue") { 1389480093f4SDimitry Andric IA.boundsType = ImmediateArg::BoundsType::UInt; 1390480093f4SDimitry Andric IA.i1 = Param->sizeInBits(); 1391480093f4SDimitry Andric } else if (Bounds->getName() == "IB_LaneIndex") { 1392480093f4SDimitry Andric IA.boundsType = ImmediateArg::BoundsType::ExplicitRange; 1393480093f4SDimitry Andric IA.i1 = 0; 1394480093f4SDimitry Andric IA.i2 = 128 / Param->sizeInBits() - 1; 1395480093f4SDimitry Andric } else if (Bounds->isSubClassOf("IB_EltBit")) { 1396480093f4SDimitry Andric IA.boundsType = ImmediateArg::BoundsType::ExplicitRange; 1397480093f4SDimitry Andric IA.i1 = Bounds->getValueAsInt("base"); 1398480093f4SDimitry Andric const Type *T = ME.getType(Bounds->getValueAsDef("type"), Param); 1399480093f4SDimitry Andric IA.i2 = IA.i1 + T->sizeInBits() - 1; 1400480093f4SDimitry Andric } else { 1401480093f4SDimitry Andric PrintFatalError("unrecognised ImmediateBounds subclass"); 1402480093f4SDimitry Andric } 1403480093f4SDimitry Andric 1404480093f4SDimitry Andric IA.ArgType = ArgType; 1405480093f4SDimitry Andric 1406480093f4SDimitry Andric if (!TypeRec->isValueUnset("extra")) { 1407480093f4SDimitry Andric IA.ExtraCheckType = TypeRec->getValueAsString("extra"); 1408480093f4SDimitry Andric if (!TypeRec->isValueUnset("extraarg")) 1409480093f4SDimitry Andric IA.ExtraCheckArgs = TypeRec->getValueAsString("extraarg"); 1410480093f4SDimitry Andric } 1411480093f4SDimitry Andric } 1412480093f4SDimitry Andric } 1413480093f4SDimitry Andric 1414480093f4SDimitry Andric // The argument will usually have a name in the arguments dag, which goes 1415480093f4SDimitry Andric // into the variable-name scope that the code gen will refer to. 1416480093f4SDimitry Andric StringRef ArgName = ArgsDag->getArgNameStr(i); 1417480093f4SDimitry Andric if (!ArgName.empty()) 1418*5ffd83dbSDimitry Andric Scope[std::string(ArgName)] = 1419*5ffd83dbSDimitry Andric ME.getCodeForArg(i, ArgType, Promote, Immediate); 1420480093f4SDimitry Andric } 1421480093f4SDimitry Andric 1422480093f4SDimitry Andric // Finally, go through the codegen dag and translate it into a Result object 1423480093f4SDimitry Andric // (with an arbitrary DAG of depended-on Results hanging off it). 1424480093f4SDimitry Andric DagInit *CodeDag = R->getValueAsDag("codegen"); 1425480093f4SDimitry Andric Record *MainOp = cast<DefInit>(CodeDag->getOperator())->getDef(); 1426480093f4SDimitry Andric if (MainOp->isSubClassOf("CustomCodegen")) { 1427480093f4SDimitry Andric // Or, if it's the special case of CustomCodegen, just accumulate 1428480093f4SDimitry Andric // a list of parameters we're going to assign to variables before 1429480093f4SDimitry Andric // breaking from the loop. 1430480093f4SDimitry Andric CustomCodeGenArgs["CustomCodeGenType"] = 1431480093f4SDimitry Andric (Twine("CustomCodeGen::") + MainOp->getValueAsString("type")).str(); 1432480093f4SDimitry Andric for (unsigned i = 0, e = CodeDag->getNumArgs(); i < e; ++i) { 1433480093f4SDimitry Andric StringRef Name = CodeDag->getArgNameStr(i); 1434480093f4SDimitry Andric if (Name.empty()) { 1435480093f4SDimitry Andric PrintFatalError("Operands to CustomCodegen should have names"); 1436480093f4SDimitry Andric } else if (auto *II = dyn_cast<IntInit>(CodeDag->getArg(i))) { 1437*5ffd83dbSDimitry Andric CustomCodeGenArgs[std::string(Name)] = itostr(II->getValue()); 1438480093f4SDimitry Andric } else if (auto *SI = dyn_cast<StringInit>(CodeDag->getArg(i))) { 1439*5ffd83dbSDimitry Andric CustomCodeGenArgs[std::string(Name)] = std::string(SI->getValue()); 1440480093f4SDimitry Andric } else { 1441480093f4SDimitry Andric PrintFatalError("Operands to CustomCodegen should be integers"); 1442480093f4SDimitry Andric } 1443480093f4SDimitry Andric } 1444480093f4SDimitry Andric } else { 1445480093f4SDimitry Andric Code = ME.getCodeForDag(CodeDag, Scope, Param); 1446480093f4SDimitry Andric } 1447480093f4SDimitry Andric } 1448480093f4SDimitry Andric 1449*5ffd83dbSDimitry Andric EmitterBase::EmitterBase(RecordKeeper &Records) { 1450*5ffd83dbSDimitry Andric // Construct the whole EmitterBase. 1451480093f4SDimitry Andric 1452480093f4SDimitry Andric // First, look up all the instances of PrimitiveType. This gives us the list 1453480093f4SDimitry Andric // of vector typedefs we have to put in arm_mve.h, and also allows us to 1454480093f4SDimitry Andric // collect all the useful ScalarType instances into a big list so that we can 1455480093f4SDimitry Andric // use it for operations such as 'find the unsigned version of this signed 1456480093f4SDimitry Andric // integer type'. 1457480093f4SDimitry Andric for (Record *R : Records.getAllDerivedDefinitions("PrimitiveType")) 1458*5ffd83dbSDimitry Andric ScalarTypes[std::string(R->getName())] = std::make_unique<ScalarType>(R); 1459480093f4SDimitry Andric 1460480093f4SDimitry Andric // Now go through the instances of Intrinsic, and for each one, iterate 1461480093f4SDimitry Andric // through its list of type parameters making an ACLEIntrinsic for each one. 1462480093f4SDimitry Andric for (Record *R : Records.getAllDerivedDefinitions("Intrinsic")) { 1463480093f4SDimitry Andric for (Record *RParam : R->getValueAsListOfDefs("params")) { 1464480093f4SDimitry Andric const Type *Param = getType(RParam, getVoidType()); 1465480093f4SDimitry Andric auto Intrinsic = std::make_unique<ACLEIntrinsic>(*this, R, Param); 1466480093f4SDimitry Andric ACLEIntrinsics[Intrinsic->fullName()] = std::move(Intrinsic); 1467480093f4SDimitry Andric } 1468480093f4SDimitry Andric } 1469480093f4SDimitry Andric } 1470480093f4SDimitry Andric 1471480093f4SDimitry Andric /// A wrapper on raw_string_ostream that contains its own buffer rather than 1472480093f4SDimitry Andric /// having to point it at one elsewhere. (In other words, it works just like 1473480093f4SDimitry Andric /// std::ostringstream; also, this makes it convenient to declare a whole array 1474480093f4SDimitry Andric /// of them at once.) 1475480093f4SDimitry Andric /// 1476480093f4SDimitry Andric /// We have to set this up using multiple inheritance, to ensure that the 1477480093f4SDimitry Andric /// string member has been constructed before raw_string_ostream's constructor 1478480093f4SDimitry Andric /// is given a pointer to it. 1479480093f4SDimitry Andric class string_holder { 1480480093f4SDimitry Andric protected: 1481480093f4SDimitry Andric std::string S; 1482480093f4SDimitry Andric }; 1483480093f4SDimitry Andric class raw_self_contained_string_ostream : private string_holder, 1484480093f4SDimitry Andric public raw_string_ostream { 1485480093f4SDimitry Andric public: 1486480093f4SDimitry Andric raw_self_contained_string_ostream() 1487480093f4SDimitry Andric : string_holder(), raw_string_ostream(S) {} 1488480093f4SDimitry Andric }; 1489480093f4SDimitry Andric 1490*5ffd83dbSDimitry Andric const char LLVMLicenseHeader[] = 1491480093f4SDimitry Andric " *\n" 1492480093f4SDimitry Andric " *\n" 1493480093f4SDimitry Andric " * Part of the LLVM Project, under the Apache License v2.0 with LLVM" 1494480093f4SDimitry Andric " Exceptions.\n" 1495480093f4SDimitry Andric " * See https://llvm.org/LICENSE.txt for license information.\n" 1496480093f4SDimitry Andric " * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception\n" 1497480093f4SDimitry Andric " *\n" 1498*5ffd83dbSDimitry Andric " *===-----------------------------------------------------------------" 1499480093f4SDimitry Andric "------===\n" 1500480093f4SDimitry Andric " */\n" 1501480093f4SDimitry Andric "\n"; 1502480093f4SDimitry Andric 1503480093f4SDimitry Andric // Machinery for the grouping of intrinsics by similar codegen. 1504480093f4SDimitry Andric // 1505480093f4SDimitry Andric // The general setup is that 'MergeableGroup' stores the things that a set of 1506480093f4SDimitry Andric // similarly shaped intrinsics have in common: the text of their code 1507480093f4SDimitry Andric // generation, and the number and type of their parameter variables. 1508480093f4SDimitry Andric // MergeableGroup is the key in a std::map whose value is a set of 1509480093f4SDimitry Andric // OutputIntrinsic, which stores the ways in which a particular intrinsic 1510480093f4SDimitry Andric // specializes the MergeableGroup's generic description: the function name and 1511480093f4SDimitry Andric // the _values_ of the parameter variables. 1512480093f4SDimitry Andric 1513480093f4SDimitry Andric struct ComparableStringVector : std::vector<std::string> { 1514480093f4SDimitry Andric // Infrastructure: a derived class of vector<string> which comes with an 1515480093f4SDimitry Andric // ordering, so that it can be used as a key in maps and an element in sets. 1516480093f4SDimitry Andric // There's no requirement on the ordering beyond being deterministic. 1517480093f4SDimitry Andric bool operator<(const ComparableStringVector &rhs) const { 1518480093f4SDimitry Andric if (size() != rhs.size()) 1519480093f4SDimitry Andric return size() < rhs.size(); 1520480093f4SDimitry Andric for (size_t i = 0, e = size(); i < e; ++i) 1521480093f4SDimitry Andric if ((*this)[i] != rhs[i]) 1522480093f4SDimitry Andric return (*this)[i] < rhs[i]; 1523480093f4SDimitry Andric return false; 1524480093f4SDimitry Andric } 1525480093f4SDimitry Andric }; 1526480093f4SDimitry Andric 1527480093f4SDimitry Andric struct OutputIntrinsic { 1528480093f4SDimitry Andric const ACLEIntrinsic *Int; 1529480093f4SDimitry Andric std::string Name; 1530480093f4SDimitry Andric ComparableStringVector ParamValues; 1531480093f4SDimitry Andric bool operator<(const OutputIntrinsic &rhs) const { 1532480093f4SDimitry Andric if (Name != rhs.Name) 1533480093f4SDimitry Andric return Name < rhs.Name; 1534480093f4SDimitry Andric return ParamValues < rhs.ParamValues; 1535480093f4SDimitry Andric } 1536480093f4SDimitry Andric }; 1537480093f4SDimitry Andric struct MergeableGroup { 1538480093f4SDimitry Andric std::string Code; 1539480093f4SDimitry Andric ComparableStringVector ParamTypes; 1540480093f4SDimitry Andric bool operator<(const MergeableGroup &rhs) const { 1541480093f4SDimitry Andric if (Code != rhs.Code) 1542480093f4SDimitry Andric return Code < rhs.Code; 1543480093f4SDimitry Andric return ParamTypes < rhs.ParamTypes; 1544480093f4SDimitry Andric } 1545480093f4SDimitry Andric }; 1546480093f4SDimitry Andric 1547*5ffd83dbSDimitry Andric void EmitterBase::EmitBuiltinCG(raw_ostream &OS) { 1548480093f4SDimitry Andric // Pass 1: generate code for all the intrinsics as if every type or constant 1549480093f4SDimitry Andric // that can possibly be abstracted out into a parameter variable will be. 1550480093f4SDimitry Andric // This identifies the sets of intrinsics we'll group together into a single 1551480093f4SDimitry Andric // piece of code generation. 1552480093f4SDimitry Andric 1553480093f4SDimitry Andric std::map<MergeableGroup, std::set<OutputIntrinsic>> MergeableGroupsPrelim; 1554480093f4SDimitry Andric 1555480093f4SDimitry Andric for (const auto &kv : ACLEIntrinsics) { 1556480093f4SDimitry Andric const ACLEIntrinsic &Int = *kv.second; 1557*5ffd83dbSDimitry Andric if (Int.headerOnly()) 1558*5ffd83dbSDimitry Andric continue; 1559480093f4SDimitry Andric 1560480093f4SDimitry Andric MergeableGroup MG; 1561480093f4SDimitry Andric OutputIntrinsic OI; 1562480093f4SDimitry Andric 1563480093f4SDimitry Andric OI.Int = ∬ 1564480093f4SDimitry Andric OI.Name = Int.fullName(); 1565480093f4SDimitry Andric CodeGenParamAllocator ParamAllocPrelim{&MG.ParamTypes, &OI.ParamValues}; 1566480093f4SDimitry Andric raw_string_ostream OS(MG.Code); 1567480093f4SDimitry Andric Int.genCode(OS, ParamAllocPrelim, 1); 1568480093f4SDimitry Andric OS.flush(); 1569480093f4SDimitry Andric 1570480093f4SDimitry Andric MergeableGroupsPrelim[MG].insert(OI); 1571480093f4SDimitry Andric } 1572480093f4SDimitry Andric 1573480093f4SDimitry Andric // Pass 2: for each of those groups, optimize the parameter variable set by 1574480093f4SDimitry Andric // eliminating 'parameters' that are the same for all intrinsics in the 1575480093f4SDimitry Andric // group, and merging together pairs of parameter variables that take the 1576480093f4SDimitry Andric // same values as each other for all intrinsics in the group. 1577480093f4SDimitry Andric 1578480093f4SDimitry Andric std::map<MergeableGroup, std::set<OutputIntrinsic>> MergeableGroups; 1579480093f4SDimitry Andric 1580480093f4SDimitry Andric for (const auto &kv : MergeableGroupsPrelim) { 1581480093f4SDimitry Andric const MergeableGroup &MG = kv.first; 1582480093f4SDimitry Andric std::vector<int> ParamNumbers; 1583480093f4SDimitry Andric std::map<ComparableStringVector, int> ParamNumberMap; 1584480093f4SDimitry Andric 1585480093f4SDimitry Andric // Loop over the parameters for this group. 1586480093f4SDimitry Andric for (size_t i = 0, e = MG.ParamTypes.size(); i < e; ++i) { 1587480093f4SDimitry Andric // Is this parameter the same for all intrinsics in the group? 1588480093f4SDimitry Andric const OutputIntrinsic &OI_first = *kv.second.begin(); 1589480093f4SDimitry Andric bool Constant = all_of(kv.second, [&](const OutputIntrinsic &OI) { 1590480093f4SDimitry Andric return OI.ParamValues[i] == OI_first.ParamValues[i]; 1591480093f4SDimitry Andric }); 1592480093f4SDimitry Andric 1593480093f4SDimitry Andric // If so, record it as -1, meaning 'no parameter variable needed'. Then 1594480093f4SDimitry Andric // the corresponding call to allocParam in pass 2 will not generate a 1595480093f4SDimitry Andric // variable at all, and just use the value inline. 1596480093f4SDimitry Andric if (Constant) { 1597480093f4SDimitry Andric ParamNumbers.push_back(-1); 1598480093f4SDimitry Andric continue; 1599480093f4SDimitry Andric } 1600480093f4SDimitry Andric 1601480093f4SDimitry Andric // Otherwise, make a list of the values this parameter takes for each 1602480093f4SDimitry Andric // intrinsic, and see if that value vector matches anything we already 1603480093f4SDimitry Andric // have. We also record the parameter type, so that we don't accidentally 1604480093f4SDimitry Andric // match up two parameter variables with different types. (Not that 1605480093f4SDimitry Andric // there's much chance of them having textually equivalent values, but in 1606480093f4SDimitry Andric // _principle_ it could happen.) 1607480093f4SDimitry Andric ComparableStringVector key; 1608480093f4SDimitry Andric key.push_back(MG.ParamTypes[i]); 1609480093f4SDimitry Andric for (const auto &OI : kv.second) 1610480093f4SDimitry Andric key.push_back(OI.ParamValues[i]); 1611480093f4SDimitry Andric 1612480093f4SDimitry Andric auto Found = ParamNumberMap.find(key); 1613480093f4SDimitry Andric if (Found != ParamNumberMap.end()) { 1614480093f4SDimitry Andric // Yes, an existing parameter variable can be reused for this. 1615480093f4SDimitry Andric ParamNumbers.push_back(Found->second); 1616480093f4SDimitry Andric continue; 1617480093f4SDimitry Andric } 1618480093f4SDimitry Andric 1619480093f4SDimitry Andric // No, we need a new parameter variable. 1620480093f4SDimitry Andric int ExistingIndex = ParamNumberMap.size(); 1621480093f4SDimitry Andric ParamNumberMap[key] = ExistingIndex; 1622480093f4SDimitry Andric ParamNumbers.push_back(ExistingIndex); 1623480093f4SDimitry Andric } 1624480093f4SDimitry Andric 1625480093f4SDimitry Andric // Now we're ready to do the pass 2 code generation, which will emit the 1626480093f4SDimitry Andric // reduced set of parameter variables we've just worked out. 1627480093f4SDimitry Andric 1628480093f4SDimitry Andric for (const auto &OI_prelim : kv.second) { 1629480093f4SDimitry Andric const ACLEIntrinsic *Int = OI_prelim.Int; 1630480093f4SDimitry Andric 1631480093f4SDimitry Andric MergeableGroup MG; 1632480093f4SDimitry Andric OutputIntrinsic OI; 1633480093f4SDimitry Andric 1634480093f4SDimitry Andric OI.Int = OI_prelim.Int; 1635480093f4SDimitry Andric OI.Name = OI_prelim.Name; 1636480093f4SDimitry Andric CodeGenParamAllocator ParamAlloc{&MG.ParamTypes, &OI.ParamValues, 1637480093f4SDimitry Andric &ParamNumbers}; 1638480093f4SDimitry Andric raw_string_ostream OS(MG.Code); 1639480093f4SDimitry Andric Int->genCode(OS, ParamAlloc, 2); 1640480093f4SDimitry Andric OS.flush(); 1641480093f4SDimitry Andric 1642480093f4SDimitry Andric MergeableGroups[MG].insert(OI); 1643480093f4SDimitry Andric } 1644480093f4SDimitry Andric } 1645480093f4SDimitry Andric 1646480093f4SDimitry Andric // Output the actual C++ code. 1647480093f4SDimitry Andric 1648480093f4SDimitry Andric for (const auto &kv : MergeableGroups) { 1649480093f4SDimitry Andric const MergeableGroup &MG = kv.first; 1650480093f4SDimitry Andric 1651480093f4SDimitry Andric // List of case statements in the main switch on BuiltinID, and an open 1652480093f4SDimitry Andric // brace. 1653480093f4SDimitry Andric const char *prefix = ""; 1654480093f4SDimitry Andric for (const auto &OI : kv.second) { 1655*5ffd83dbSDimitry Andric OS << prefix << "case ARM::BI__builtin_arm_" << OI.Int->builtinExtension() 1656*5ffd83dbSDimitry Andric << "_" << OI.Name << ":"; 1657*5ffd83dbSDimitry Andric 1658480093f4SDimitry Andric prefix = "\n"; 1659480093f4SDimitry Andric } 1660480093f4SDimitry Andric OS << " {\n"; 1661480093f4SDimitry Andric 1662480093f4SDimitry Andric if (!MG.ParamTypes.empty()) { 1663480093f4SDimitry Andric // If we've got some parameter variables, then emit their declarations... 1664480093f4SDimitry Andric for (size_t i = 0, e = MG.ParamTypes.size(); i < e; ++i) { 1665480093f4SDimitry Andric StringRef Type = MG.ParamTypes[i]; 1666480093f4SDimitry Andric OS << " " << Type; 1667480093f4SDimitry Andric if (!Type.endswith("*")) 1668480093f4SDimitry Andric OS << " "; 1669480093f4SDimitry Andric OS << " Param" << utostr(i) << ";\n"; 1670480093f4SDimitry Andric } 1671480093f4SDimitry Andric 1672480093f4SDimitry Andric // ... and an inner switch on BuiltinID that will fill them in with each 1673480093f4SDimitry Andric // individual intrinsic's values. 1674480093f4SDimitry Andric OS << " switch (BuiltinID) {\n"; 1675480093f4SDimitry Andric for (const auto &OI : kv.second) { 1676*5ffd83dbSDimitry Andric OS << " case ARM::BI__builtin_arm_" << OI.Int->builtinExtension() 1677*5ffd83dbSDimitry Andric << "_" << OI.Name << ":\n"; 1678480093f4SDimitry Andric for (size_t i = 0, e = MG.ParamTypes.size(); i < e; ++i) 1679480093f4SDimitry Andric OS << " Param" << utostr(i) << " = " << OI.ParamValues[i] << ";\n"; 1680480093f4SDimitry Andric OS << " break;\n"; 1681480093f4SDimitry Andric } 1682480093f4SDimitry Andric OS << " }\n"; 1683480093f4SDimitry Andric } 1684480093f4SDimitry Andric 1685480093f4SDimitry Andric // And finally, output the code, and close the outer pair of braces. (The 1686480093f4SDimitry Andric // code will always end with a 'return' statement, so we need not insert a 1687480093f4SDimitry Andric // 'break' here.) 1688480093f4SDimitry Andric OS << MG.Code << "}\n"; 1689480093f4SDimitry Andric } 1690480093f4SDimitry Andric } 1691480093f4SDimitry Andric 1692*5ffd83dbSDimitry Andric void EmitterBase::EmitBuiltinAliases(raw_ostream &OS) { 1693*5ffd83dbSDimitry Andric // Build a sorted table of: 1694*5ffd83dbSDimitry Andric // - intrinsic id number 1695*5ffd83dbSDimitry Andric // - full name 1696*5ffd83dbSDimitry Andric // - polymorphic name or -1 1697*5ffd83dbSDimitry Andric StringToOffsetTable StringTable; 1698*5ffd83dbSDimitry Andric OS << "static const IntrinToName MapData[] = {\n"; 1699480093f4SDimitry Andric for (const auto &kv : ACLEIntrinsics) { 1700480093f4SDimitry Andric const ACLEIntrinsic &Int = *kv.second; 1701*5ffd83dbSDimitry Andric if (Int.headerOnly()) 1702*5ffd83dbSDimitry Andric continue; 1703*5ffd83dbSDimitry Andric int32_t ShortNameOffset = 1704*5ffd83dbSDimitry Andric Int.polymorphic() ? StringTable.GetOrAddStringOffset(Int.shortName()) 1705*5ffd83dbSDimitry Andric : -1; 1706*5ffd83dbSDimitry Andric OS << " { ARM::BI__builtin_arm_" << Int.builtinExtension() << "_" 1707*5ffd83dbSDimitry Andric << Int.fullName() << ", " 1708*5ffd83dbSDimitry Andric << StringTable.GetOrAddStringOffset(Int.fullName()) << ", " 1709*5ffd83dbSDimitry Andric << ShortNameOffset << "},\n"; 1710*5ffd83dbSDimitry Andric } 1711*5ffd83dbSDimitry Andric OS << "};\n\n"; 1712*5ffd83dbSDimitry Andric 1713*5ffd83dbSDimitry Andric OS << "ArrayRef<IntrinToName> Map(MapData);\n\n"; 1714*5ffd83dbSDimitry Andric 1715*5ffd83dbSDimitry Andric OS << "static const char IntrinNames[] = {\n"; 1716*5ffd83dbSDimitry Andric StringTable.EmitString(OS); 1717*5ffd83dbSDimitry Andric OS << "};\n\n"; 1718*5ffd83dbSDimitry Andric } 1719*5ffd83dbSDimitry Andric 1720*5ffd83dbSDimitry Andric void EmitterBase::GroupSemaChecks( 1721*5ffd83dbSDimitry Andric std::map<std::string, std::set<std::string>> &Checks) { 1722*5ffd83dbSDimitry Andric for (const auto &kv : ACLEIntrinsics) { 1723*5ffd83dbSDimitry Andric const ACLEIntrinsic &Int = *kv.second; 1724*5ffd83dbSDimitry Andric if (Int.headerOnly()) 1725*5ffd83dbSDimitry Andric continue; 1726*5ffd83dbSDimitry Andric std::string Check = Int.genSema(); 1727*5ffd83dbSDimitry Andric if (!Check.empty()) 1728*5ffd83dbSDimitry Andric Checks[Check].insert(Int.fullName()); 1729*5ffd83dbSDimitry Andric } 1730*5ffd83dbSDimitry Andric } 1731*5ffd83dbSDimitry Andric 1732*5ffd83dbSDimitry Andric // ----------------------------------------------------------------------------- 1733*5ffd83dbSDimitry Andric // The class used for generating arm_mve.h and related Clang bits 1734*5ffd83dbSDimitry Andric // 1735*5ffd83dbSDimitry Andric 1736*5ffd83dbSDimitry Andric class MveEmitter : public EmitterBase { 1737*5ffd83dbSDimitry Andric public: 1738*5ffd83dbSDimitry Andric MveEmitter(RecordKeeper &Records) : EmitterBase(Records){}; 1739*5ffd83dbSDimitry Andric void EmitHeader(raw_ostream &OS) override; 1740*5ffd83dbSDimitry Andric void EmitBuiltinDef(raw_ostream &OS) override; 1741*5ffd83dbSDimitry Andric void EmitBuiltinSema(raw_ostream &OS) override; 1742*5ffd83dbSDimitry Andric }; 1743*5ffd83dbSDimitry Andric 1744*5ffd83dbSDimitry Andric void MveEmitter::EmitHeader(raw_ostream &OS) { 1745*5ffd83dbSDimitry Andric // Accumulate pieces of the header file that will be enabled under various 1746*5ffd83dbSDimitry Andric // different combinations of #ifdef. The index into parts[] is made up of 1747*5ffd83dbSDimitry Andric // the following bit flags. 1748*5ffd83dbSDimitry Andric constexpr unsigned Float = 1; 1749*5ffd83dbSDimitry Andric constexpr unsigned UseUserNamespace = 2; 1750*5ffd83dbSDimitry Andric 1751*5ffd83dbSDimitry Andric constexpr unsigned NumParts = 4; 1752*5ffd83dbSDimitry Andric raw_self_contained_string_ostream parts[NumParts]; 1753*5ffd83dbSDimitry Andric 1754*5ffd83dbSDimitry Andric // Write typedefs for all the required vector types, and a few scalar 1755*5ffd83dbSDimitry Andric // types that don't already have the name we want them to have. 1756*5ffd83dbSDimitry Andric 1757*5ffd83dbSDimitry Andric parts[0] << "typedef uint16_t mve_pred16_t;\n"; 1758*5ffd83dbSDimitry Andric parts[Float] << "typedef __fp16 float16_t;\n" 1759*5ffd83dbSDimitry Andric "typedef float float32_t;\n"; 1760*5ffd83dbSDimitry Andric for (const auto &kv : ScalarTypes) { 1761*5ffd83dbSDimitry Andric const ScalarType *ST = kv.second.get(); 1762*5ffd83dbSDimitry Andric if (ST->hasNonstandardName()) 1763*5ffd83dbSDimitry Andric continue; 1764*5ffd83dbSDimitry Andric raw_ostream &OS = parts[ST->requiresFloat() ? Float : 0]; 1765*5ffd83dbSDimitry Andric const VectorType *VT = getVectorType(ST); 1766*5ffd83dbSDimitry Andric 1767*5ffd83dbSDimitry Andric OS << "typedef __attribute__((__neon_vector_type__(" << VT->lanes() 1768*5ffd83dbSDimitry Andric << "), __clang_arm_mve_strict_polymorphism)) " << ST->cName() << " " 1769*5ffd83dbSDimitry Andric << VT->cName() << ";\n"; 1770*5ffd83dbSDimitry Andric 1771*5ffd83dbSDimitry Andric // Every vector type also comes with a pair of multi-vector types for 1772*5ffd83dbSDimitry Andric // the VLD2 and VLD4 instructions. 1773*5ffd83dbSDimitry Andric for (unsigned n = 2; n <= 4; n += 2) { 1774*5ffd83dbSDimitry Andric const MultiVectorType *MT = getMultiVectorType(n, VT); 1775*5ffd83dbSDimitry Andric OS << "typedef struct { " << VT->cName() << " val[" << n << "]; } " 1776*5ffd83dbSDimitry Andric << MT->cName() << ";\n"; 1777*5ffd83dbSDimitry Andric } 1778*5ffd83dbSDimitry Andric } 1779*5ffd83dbSDimitry Andric parts[0] << "\n"; 1780*5ffd83dbSDimitry Andric parts[Float] << "\n"; 1781*5ffd83dbSDimitry Andric 1782*5ffd83dbSDimitry Andric // Write declarations for all the intrinsics. 1783*5ffd83dbSDimitry Andric 1784*5ffd83dbSDimitry Andric for (const auto &kv : ACLEIntrinsics) { 1785*5ffd83dbSDimitry Andric const ACLEIntrinsic &Int = *kv.second; 1786*5ffd83dbSDimitry Andric 1787*5ffd83dbSDimitry Andric // We generate each intrinsic twice, under its full unambiguous 1788*5ffd83dbSDimitry Andric // name and its shorter polymorphic name (if the latter exists). 1789*5ffd83dbSDimitry Andric for (bool Polymorphic : {false, true}) { 1790*5ffd83dbSDimitry Andric if (Polymorphic && !Int.polymorphic()) 1791*5ffd83dbSDimitry Andric continue; 1792*5ffd83dbSDimitry Andric if (!Polymorphic && Int.polymorphicOnly()) 1793*5ffd83dbSDimitry Andric continue; 1794*5ffd83dbSDimitry Andric 1795*5ffd83dbSDimitry Andric // We also generate each intrinsic under a name like __arm_vfooq 1796*5ffd83dbSDimitry Andric // (which is in C language implementation namespace, so it's 1797*5ffd83dbSDimitry Andric // safe to define in any conforming user program) and a shorter 1798*5ffd83dbSDimitry Andric // one like vfooq (which is in user namespace, so a user might 1799*5ffd83dbSDimitry Andric // reasonably have used it for something already). If so, they 1800*5ffd83dbSDimitry Andric // can #define __ARM_MVE_PRESERVE_USER_NAMESPACE before 1801*5ffd83dbSDimitry Andric // including the header, which will suppress the shorter names 1802*5ffd83dbSDimitry Andric // and leave only the implementation-namespace ones. Then they 1803*5ffd83dbSDimitry Andric // have to write __arm_vfooq everywhere, of course. 1804*5ffd83dbSDimitry Andric 1805*5ffd83dbSDimitry Andric for (bool UserNamespace : {false, true}) { 1806*5ffd83dbSDimitry Andric raw_ostream &OS = parts[(Int.requiresFloat() ? Float : 0) | 1807*5ffd83dbSDimitry Andric (UserNamespace ? UseUserNamespace : 0)]; 1808*5ffd83dbSDimitry Andric 1809*5ffd83dbSDimitry Andric // Make the name of the function in this declaration. 1810*5ffd83dbSDimitry Andric 1811*5ffd83dbSDimitry Andric std::string FunctionName = 1812*5ffd83dbSDimitry Andric Polymorphic ? Int.shortName() : Int.fullName(); 1813*5ffd83dbSDimitry Andric if (!UserNamespace) 1814*5ffd83dbSDimitry Andric FunctionName = "__arm_" + FunctionName; 1815*5ffd83dbSDimitry Andric 1816*5ffd83dbSDimitry Andric // Make strings for the types involved in the function's 1817*5ffd83dbSDimitry Andric // prototype. 1818*5ffd83dbSDimitry Andric 1819*5ffd83dbSDimitry Andric std::string RetTypeName = Int.returnType()->cName(); 1820*5ffd83dbSDimitry Andric if (!StringRef(RetTypeName).endswith("*")) 1821*5ffd83dbSDimitry Andric RetTypeName += " "; 1822*5ffd83dbSDimitry Andric 1823*5ffd83dbSDimitry Andric std::vector<std::string> ArgTypeNames; 1824*5ffd83dbSDimitry Andric for (const Type *ArgTypePtr : Int.argTypes()) 1825*5ffd83dbSDimitry Andric ArgTypeNames.push_back(ArgTypePtr->cName()); 1826*5ffd83dbSDimitry Andric std::string ArgTypesString = 1827*5ffd83dbSDimitry Andric join(std::begin(ArgTypeNames), std::end(ArgTypeNames), ", "); 1828*5ffd83dbSDimitry Andric 1829*5ffd83dbSDimitry Andric // Emit the actual declaration. All these functions are 1830*5ffd83dbSDimitry Andric // declared 'static inline' without a body, which is fine 1831*5ffd83dbSDimitry Andric // provided clang recognizes them as builtins, and has the 1832*5ffd83dbSDimitry Andric // effect that this type signature is used in place of the one 1833*5ffd83dbSDimitry Andric // that Builtins.def didn't provide. That's how we can get 1834*5ffd83dbSDimitry Andric // structure types that weren't defined until this header was 1835*5ffd83dbSDimitry Andric // included to be part of the type signature of a builtin that 1836*5ffd83dbSDimitry Andric // was known to clang already. 1837*5ffd83dbSDimitry Andric // 1838*5ffd83dbSDimitry Andric // The declarations use __attribute__(__clang_arm_builtin_alias), 1839*5ffd83dbSDimitry Andric // so that each function declared will be recognized as the 1840*5ffd83dbSDimitry Andric // appropriate MVE builtin in spite of its user-facing name. 1841*5ffd83dbSDimitry Andric // 1842*5ffd83dbSDimitry Andric // (That's better than making them all wrapper functions, 1843*5ffd83dbSDimitry Andric // partly because it avoids any compiler error message citing 1844*5ffd83dbSDimitry Andric // the wrapper function definition instead of the user's code, 1845*5ffd83dbSDimitry Andric // and mostly because some MVE intrinsics have arguments 1846*5ffd83dbSDimitry Andric // required to be compile-time constants, and that property 1847*5ffd83dbSDimitry Andric // can't be propagated through a wrapper function. It can be 1848*5ffd83dbSDimitry Andric // propagated through a macro, but macros can't be overloaded 1849*5ffd83dbSDimitry Andric // on argument types very easily - you have to use _Generic, 1850*5ffd83dbSDimitry Andric // which makes error messages very confusing when the user 1851*5ffd83dbSDimitry Andric // gets it wrong.) 1852*5ffd83dbSDimitry Andric // 1853*5ffd83dbSDimitry Andric // Finally, the polymorphic versions of the intrinsics are 1854*5ffd83dbSDimitry Andric // also defined with __attribute__(overloadable), so that when 1855*5ffd83dbSDimitry Andric // the same name is defined with several type signatures, the 1856*5ffd83dbSDimitry Andric // right thing happens. Each one of the overloaded 1857*5ffd83dbSDimitry Andric // declarations is given a different builtin id, which 1858*5ffd83dbSDimitry Andric // has exactly the effect we want: first clang resolves the 1859*5ffd83dbSDimitry Andric // overload to the right function, then it knows which builtin 1860*5ffd83dbSDimitry Andric // it's referring to, and then the Sema checking for that 1861*5ffd83dbSDimitry Andric // builtin can check further things like the constant 1862*5ffd83dbSDimitry Andric // arguments. 1863*5ffd83dbSDimitry Andric // 1864*5ffd83dbSDimitry Andric // One more subtlety is the newline just before the return 1865*5ffd83dbSDimitry Andric // type name. That's a cosmetic tweak to make the error 1866*5ffd83dbSDimitry Andric // messages legible if the user gets the types wrong in a call 1867*5ffd83dbSDimitry Andric // to a polymorphic function: this way, clang will print just 1868*5ffd83dbSDimitry Andric // the _final_ line of each declaration in the header, to show 1869*5ffd83dbSDimitry Andric // the type signatures that would have been legal. So all the 1870*5ffd83dbSDimitry Andric // confusing machinery with __attribute__ is left out of the 1871*5ffd83dbSDimitry Andric // error message, and the user sees something that's more or 1872*5ffd83dbSDimitry Andric // less self-documenting: "here's a list of actually readable 1873*5ffd83dbSDimitry Andric // type signatures for vfooq(), and here's why each one didn't 1874*5ffd83dbSDimitry Andric // match your call". 1875*5ffd83dbSDimitry Andric 1876*5ffd83dbSDimitry Andric OS << "static __inline__ __attribute__((" 1877*5ffd83dbSDimitry Andric << (Polymorphic ? "__overloadable__, " : "") 1878*5ffd83dbSDimitry Andric << "__clang_arm_builtin_alias(__builtin_arm_mve_" << Int.fullName() 1879*5ffd83dbSDimitry Andric << ")))\n" 1880*5ffd83dbSDimitry Andric << RetTypeName << FunctionName << "(" << ArgTypesString << ");\n"; 1881*5ffd83dbSDimitry Andric } 1882*5ffd83dbSDimitry Andric } 1883*5ffd83dbSDimitry Andric } 1884*5ffd83dbSDimitry Andric for (auto &part : parts) 1885*5ffd83dbSDimitry Andric part << "\n"; 1886*5ffd83dbSDimitry Andric 1887*5ffd83dbSDimitry Andric // Now we've finished accumulating bits and pieces into the parts[] array. 1888*5ffd83dbSDimitry Andric // Put it all together to write the final output file. 1889*5ffd83dbSDimitry Andric 1890*5ffd83dbSDimitry Andric OS << "/*===---- arm_mve.h - ARM MVE intrinsics " 1891*5ffd83dbSDimitry Andric "-----------------------------------===\n" 1892*5ffd83dbSDimitry Andric << LLVMLicenseHeader 1893*5ffd83dbSDimitry Andric << "#ifndef __ARM_MVE_H\n" 1894*5ffd83dbSDimitry Andric "#define __ARM_MVE_H\n" 1895*5ffd83dbSDimitry Andric "\n" 1896*5ffd83dbSDimitry Andric "#if !__ARM_FEATURE_MVE\n" 1897*5ffd83dbSDimitry Andric "#error \"MVE support not enabled\"\n" 1898*5ffd83dbSDimitry Andric "#endif\n" 1899*5ffd83dbSDimitry Andric "\n" 1900*5ffd83dbSDimitry Andric "#include <stdint.h>\n" 1901*5ffd83dbSDimitry Andric "\n" 1902*5ffd83dbSDimitry Andric "#ifdef __cplusplus\n" 1903*5ffd83dbSDimitry Andric "extern \"C\" {\n" 1904*5ffd83dbSDimitry Andric "#endif\n" 1905*5ffd83dbSDimitry Andric "\n"; 1906*5ffd83dbSDimitry Andric 1907*5ffd83dbSDimitry Andric for (size_t i = 0; i < NumParts; ++i) { 1908*5ffd83dbSDimitry Andric std::vector<std::string> conditions; 1909*5ffd83dbSDimitry Andric if (i & Float) 1910*5ffd83dbSDimitry Andric conditions.push_back("(__ARM_FEATURE_MVE & 2)"); 1911*5ffd83dbSDimitry Andric if (i & UseUserNamespace) 1912*5ffd83dbSDimitry Andric conditions.push_back("(!defined __ARM_MVE_PRESERVE_USER_NAMESPACE)"); 1913*5ffd83dbSDimitry Andric 1914*5ffd83dbSDimitry Andric std::string condition = 1915*5ffd83dbSDimitry Andric join(std::begin(conditions), std::end(conditions), " && "); 1916*5ffd83dbSDimitry Andric if (!condition.empty()) 1917*5ffd83dbSDimitry Andric OS << "#if " << condition << "\n\n"; 1918*5ffd83dbSDimitry Andric OS << parts[i].str(); 1919*5ffd83dbSDimitry Andric if (!condition.empty()) 1920*5ffd83dbSDimitry Andric OS << "#endif /* " << condition << " */\n\n"; 1921*5ffd83dbSDimitry Andric } 1922*5ffd83dbSDimitry Andric 1923*5ffd83dbSDimitry Andric OS << "#ifdef __cplusplus\n" 1924*5ffd83dbSDimitry Andric "} /* extern \"C\" */\n" 1925*5ffd83dbSDimitry Andric "#endif\n" 1926*5ffd83dbSDimitry Andric "\n" 1927*5ffd83dbSDimitry Andric "#endif /* __ARM_MVE_H */\n"; 1928*5ffd83dbSDimitry Andric } 1929*5ffd83dbSDimitry Andric 1930*5ffd83dbSDimitry Andric void MveEmitter::EmitBuiltinDef(raw_ostream &OS) { 1931*5ffd83dbSDimitry Andric for (const auto &kv : ACLEIntrinsics) { 1932*5ffd83dbSDimitry Andric const ACLEIntrinsic &Int = *kv.second; 1933*5ffd83dbSDimitry Andric OS << "TARGET_HEADER_BUILTIN(__builtin_arm_mve_" << Int.fullName() 1934*5ffd83dbSDimitry Andric << ", \"\", \"n\", \"arm_mve.h\", ALL_LANGUAGES, \"\")\n"; 1935*5ffd83dbSDimitry Andric } 1936*5ffd83dbSDimitry Andric 1937*5ffd83dbSDimitry Andric std::set<std::string> ShortNamesSeen; 1938*5ffd83dbSDimitry Andric 1939*5ffd83dbSDimitry Andric for (const auto &kv : ACLEIntrinsics) { 1940*5ffd83dbSDimitry Andric const ACLEIntrinsic &Int = *kv.second; 1941*5ffd83dbSDimitry Andric if (Int.polymorphic()) { 1942*5ffd83dbSDimitry Andric StringRef Name = Int.shortName(); 1943*5ffd83dbSDimitry Andric if (ShortNamesSeen.find(std::string(Name)) == ShortNamesSeen.end()) { 1944*5ffd83dbSDimitry Andric OS << "BUILTIN(__builtin_arm_mve_" << Name << ", \"vi.\", \"nt"; 1945*5ffd83dbSDimitry Andric if (Int.nonEvaluating()) 1946*5ffd83dbSDimitry Andric OS << "u"; // indicate that this builtin doesn't evaluate its args 1947*5ffd83dbSDimitry Andric OS << "\")\n"; 1948*5ffd83dbSDimitry Andric ShortNamesSeen.insert(std::string(Name)); 1949*5ffd83dbSDimitry Andric } 1950*5ffd83dbSDimitry Andric } 1951*5ffd83dbSDimitry Andric } 1952*5ffd83dbSDimitry Andric } 1953*5ffd83dbSDimitry Andric 1954*5ffd83dbSDimitry Andric void MveEmitter::EmitBuiltinSema(raw_ostream &OS) { 1955*5ffd83dbSDimitry Andric std::map<std::string, std::set<std::string>> Checks; 1956*5ffd83dbSDimitry Andric GroupSemaChecks(Checks); 1957*5ffd83dbSDimitry Andric 1958*5ffd83dbSDimitry Andric for (const auto &kv : Checks) { 1959*5ffd83dbSDimitry Andric for (StringRef Name : kv.second) 1960*5ffd83dbSDimitry Andric OS << "case ARM::BI__builtin_arm_mve_" << Name << ":\n"; 1961*5ffd83dbSDimitry Andric OS << " return " << kv.first; 1962*5ffd83dbSDimitry Andric } 1963*5ffd83dbSDimitry Andric } 1964*5ffd83dbSDimitry Andric 1965*5ffd83dbSDimitry Andric // ----------------------------------------------------------------------------- 1966*5ffd83dbSDimitry Andric // Class that describes an ACLE intrinsic implemented as a macro. 1967*5ffd83dbSDimitry Andric // 1968*5ffd83dbSDimitry Andric // This class is used when the intrinsic is polymorphic in 2 or 3 types, but we 1969*5ffd83dbSDimitry Andric // want to avoid a combinatorial explosion by reinterpreting the arguments to 1970*5ffd83dbSDimitry Andric // fixed types. 1971*5ffd83dbSDimitry Andric 1972*5ffd83dbSDimitry Andric class FunctionMacro { 1973*5ffd83dbSDimitry Andric std::vector<StringRef> Params; 1974*5ffd83dbSDimitry Andric StringRef Definition; 1975*5ffd83dbSDimitry Andric 1976*5ffd83dbSDimitry Andric public: 1977*5ffd83dbSDimitry Andric FunctionMacro(const Record &R); 1978*5ffd83dbSDimitry Andric 1979*5ffd83dbSDimitry Andric const std::vector<StringRef> &getParams() const { return Params; } 1980*5ffd83dbSDimitry Andric StringRef getDefinition() const { return Definition; } 1981*5ffd83dbSDimitry Andric }; 1982*5ffd83dbSDimitry Andric 1983*5ffd83dbSDimitry Andric FunctionMacro::FunctionMacro(const Record &R) { 1984*5ffd83dbSDimitry Andric Params = R.getValueAsListOfStrings("params"); 1985*5ffd83dbSDimitry Andric Definition = R.getValueAsString("definition"); 1986*5ffd83dbSDimitry Andric } 1987*5ffd83dbSDimitry Andric 1988*5ffd83dbSDimitry Andric // ----------------------------------------------------------------------------- 1989*5ffd83dbSDimitry Andric // The class used for generating arm_cde.h and related Clang bits 1990*5ffd83dbSDimitry Andric // 1991*5ffd83dbSDimitry Andric 1992*5ffd83dbSDimitry Andric class CdeEmitter : public EmitterBase { 1993*5ffd83dbSDimitry Andric std::map<StringRef, FunctionMacro> FunctionMacros; 1994*5ffd83dbSDimitry Andric 1995*5ffd83dbSDimitry Andric public: 1996*5ffd83dbSDimitry Andric CdeEmitter(RecordKeeper &Records); 1997*5ffd83dbSDimitry Andric void EmitHeader(raw_ostream &OS) override; 1998*5ffd83dbSDimitry Andric void EmitBuiltinDef(raw_ostream &OS) override; 1999*5ffd83dbSDimitry Andric void EmitBuiltinSema(raw_ostream &OS) override; 2000*5ffd83dbSDimitry Andric }; 2001*5ffd83dbSDimitry Andric 2002*5ffd83dbSDimitry Andric CdeEmitter::CdeEmitter(RecordKeeper &Records) : EmitterBase(Records) { 2003*5ffd83dbSDimitry Andric for (Record *R : Records.getAllDerivedDefinitions("FunctionMacro")) 2004*5ffd83dbSDimitry Andric FunctionMacros.emplace(R->getName(), FunctionMacro(*R)); 2005*5ffd83dbSDimitry Andric } 2006*5ffd83dbSDimitry Andric 2007*5ffd83dbSDimitry Andric void CdeEmitter::EmitHeader(raw_ostream &OS) { 2008*5ffd83dbSDimitry Andric // Accumulate pieces of the header file that will be enabled under various 2009*5ffd83dbSDimitry Andric // different combinations of #ifdef. The index into parts[] is one of the 2010*5ffd83dbSDimitry Andric // following: 2011*5ffd83dbSDimitry Andric constexpr unsigned None = 0; 2012*5ffd83dbSDimitry Andric constexpr unsigned MVE = 1; 2013*5ffd83dbSDimitry Andric constexpr unsigned MVEFloat = 2; 2014*5ffd83dbSDimitry Andric 2015*5ffd83dbSDimitry Andric constexpr unsigned NumParts = 3; 2016*5ffd83dbSDimitry Andric raw_self_contained_string_ostream parts[NumParts]; 2017*5ffd83dbSDimitry Andric 2018*5ffd83dbSDimitry Andric // Write typedefs for all the required vector types, and a few scalar 2019*5ffd83dbSDimitry Andric // types that don't already have the name we want them to have. 2020*5ffd83dbSDimitry Andric 2021*5ffd83dbSDimitry Andric parts[MVE] << "typedef uint16_t mve_pred16_t;\n"; 2022*5ffd83dbSDimitry Andric parts[MVEFloat] << "typedef __fp16 float16_t;\n" 2023*5ffd83dbSDimitry Andric "typedef float float32_t;\n"; 2024*5ffd83dbSDimitry Andric for (const auto &kv : ScalarTypes) { 2025*5ffd83dbSDimitry Andric const ScalarType *ST = kv.second.get(); 2026*5ffd83dbSDimitry Andric if (ST->hasNonstandardName()) 2027*5ffd83dbSDimitry Andric continue; 2028*5ffd83dbSDimitry Andric // We don't have float64x2_t 2029*5ffd83dbSDimitry Andric if (ST->kind() == ScalarTypeKind::Float && ST->sizeInBits() == 64) 2030*5ffd83dbSDimitry Andric continue; 2031*5ffd83dbSDimitry Andric raw_ostream &OS = parts[ST->requiresFloat() ? MVEFloat : MVE]; 2032*5ffd83dbSDimitry Andric const VectorType *VT = getVectorType(ST); 2033*5ffd83dbSDimitry Andric 2034*5ffd83dbSDimitry Andric OS << "typedef __attribute__((__neon_vector_type__(" << VT->lanes() 2035*5ffd83dbSDimitry Andric << "), __clang_arm_mve_strict_polymorphism)) " << ST->cName() << " " 2036*5ffd83dbSDimitry Andric << VT->cName() << ";\n"; 2037*5ffd83dbSDimitry Andric } 2038*5ffd83dbSDimitry Andric parts[MVE] << "\n"; 2039*5ffd83dbSDimitry Andric parts[MVEFloat] << "\n"; 2040*5ffd83dbSDimitry Andric 2041*5ffd83dbSDimitry Andric // Write declarations for all the intrinsics. 2042*5ffd83dbSDimitry Andric 2043*5ffd83dbSDimitry Andric for (const auto &kv : ACLEIntrinsics) { 2044*5ffd83dbSDimitry Andric const ACLEIntrinsic &Int = *kv.second; 2045*5ffd83dbSDimitry Andric 2046*5ffd83dbSDimitry Andric // We generate each intrinsic twice, under its full unambiguous 2047*5ffd83dbSDimitry Andric // name and its shorter polymorphic name (if the latter exists). 2048*5ffd83dbSDimitry Andric for (bool Polymorphic : {false, true}) { 2049*5ffd83dbSDimitry Andric if (Polymorphic && !Int.polymorphic()) 2050*5ffd83dbSDimitry Andric continue; 2051*5ffd83dbSDimitry Andric if (!Polymorphic && Int.polymorphicOnly()) 2052*5ffd83dbSDimitry Andric continue; 2053*5ffd83dbSDimitry Andric 2054*5ffd83dbSDimitry Andric raw_ostream &OS = 2055*5ffd83dbSDimitry Andric parts[Int.requiresFloat() ? MVEFloat 2056*5ffd83dbSDimitry Andric : Int.requiresMVE() ? MVE : None]; 2057*5ffd83dbSDimitry Andric 2058*5ffd83dbSDimitry Andric // Make the name of the function in this declaration. 2059*5ffd83dbSDimitry Andric std::string FunctionName = 2060*5ffd83dbSDimitry Andric "__arm_" + (Polymorphic ? Int.shortName() : Int.fullName()); 2061*5ffd83dbSDimitry Andric 2062*5ffd83dbSDimitry Andric // Make strings for the types involved in the function's 2063*5ffd83dbSDimitry Andric // prototype. 2064*5ffd83dbSDimitry Andric std::string RetTypeName = Int.returnType()->cName(); 2065*5ffd83dbSDimitry Andric if (!StringRef(RetTypeName).endswith("*")) 2066*5ffd83dbSDimitry Andric RetTypeName += " "; 2067*5ffd83dbSDimitry Andric 2068*5ffd83dbSDimitry Andric std::vector<std::string> ArgTypeNames; 2069*5ffd83dbSDimitry Andric for (const Type *ArgTypePtr : Int.argTypes()) 2070*5ffd83dbSDimitry Andric ArgTypeNames.push_back(ArgTypePtr->cName()); 2071*5ffd83dbSDimitry Andric std::string ArgTypesString = 2072*5ffd83dbSDimitry Andric join(std::begin(ArgTypeNames), std::end(ArgTypeNames), ", "); 2073*5ffd83dbSDimitry Andric 2074*5ffd83dbSDimitry Andric // Emit the actual declaration. See MveEmitter::EmitHeader for detailed 2075*5ffd83dbSDimitry Andric // comments 2076*5ffd83dbSDimitry Andric OS << "static __inline__ __attribute__((" 2077*5ffd83dbSDimitry Andric << (Polymorphic ? "__overloadable__, " : "") 2078*5ffd83dbSDimitry Andric << "__clang_arm_builtin_alias(__builtin_arm_" << Int.builtinExtension() 2079*5ffd83dbSDimitry Andric << "_" << Int.fullName() << ")))\n" 2080*5ffd83dbSDimitry Andric << RetTypeName << FunctionName << "(" << ArgTypesString << ");\n"; 2081*5ffd83dbSDimitry Andric } 2082*5ffd83dbSDimitry Andric } 2083*5ffd83dbSDimitry Andric 2084*5ffd83dbSDimitry Andric for (const auto &kv : FunctionMacros) { 2085*5ffd83dbSDimitry Andric StringRef Name = kv.first; 2086*5ffd83dbSDimitry Andric const FunctionMacro &FM = kv.second; 2087*5ffd83dbSDimitry Andric 2088*5ffd83dbSDimitry Andric raw_ostream &OS = parts[MVE]; 2089*5ffd83dbSDimitry Andric OS << "#define " 2090*5ffd83dbSDimitry Andric << "__arm_" << Name << "(" << join(FM.getParams(), ", ") << ") " 2091*5ffd83dbSDimitry Andric << FM.getDefinition() << "\n"; 2092*5ffd83dbSDimitry Andric } 2093*5ffd83dbSDimitry Andric 2094*5ffd83dbSDimitry Andric for (auto &part : parts) 2095*5ffd83dbSDimitry Andric part << "\n"; 2096*5ffd83dbSDimitry Andric 2097*5ffd83dbSDimitry Andric // Now we've finished accumulating bits and pieces into the parts[] array. 2098*5ffd83dbSDimitry Andric // Put it all together to write the final output file. 2099*5ffd83dbSDimitry Andric 2100*5ffd83dbSDimitry Andric OS << "/*===---- arm_cde.h - ARM CDE intrinsics " 2101*5ffd83dbSDimitry Andric "-----------------------------------===\n" 2102*5ffd83dbSDimitry Andric << LLVMLicenseHeader 2103*5ffd83dbSDimitry Andric << "#ifndef __ARM_CDE_H\n" 2104*5ffd83dbSDimitry Andric "#define __ARM_CDE_H\n" 2105*5ffd83dbSDimitry Andric "\n" 2106*5ffd83dbSDimitry Andric "#if !__ARM_FEATURE_CDE\n" 2107*5ffd83dbSDimitry Andric "#error \"CDE support not enabled\"\n" 2108*5ffd83dbSDimitry Andric "#endif\n" 2109*5ffd83dbSDimitry Andric "\n" 2110*5ffd83dbSDimitry Andric "#include <stdint.h>\n" 2111*5ffd83dbSDimitry Andric "\n" 2112*5ffd83dbSDimitry Andric "#ifdef __cplusplus\n" 2113*5ffd83dbSDimitry Andric "extern \"C\" {\n" 2114*5ffd83dbSDimitry Andric "#endif\n" 2115*5ffd83dbSDimitry Andric "\n"; 2116*5ffd83dbSDimitry Andric 2117*5ffd83dbSDimitry Andric for (size_t i = 0; i < NumParts; ++i) { 2118*5ffd83dbSDimitry Andric std::string condition; 2119*5ffd83dbSDimitry Andric if (i == MVEFloat) 2120*5ffd83dbSDimitry Andric condition = "__ARM_FEATURE_MVE & 2"; 2121*5ffd83dbSDimitry Andric else if (i == MVE) 2122*5ffd83dbSDimitry Andric condition = "__ARM_FEATURE_MVE"; 2123*5ffd83dbSDimitry Andric 2124*5ffd83dbSDimitry Andric if (!condition.empty()) 2125*5ffd83dbSDimitry Andric OS << "#if " << condition << "\n\n"; 2126*5ffd83dbSDimitry Andric OS << parts[i].str(); 2127*5ffd83dbSDimitry Andric if (!condition.empty()) 2128*5ffd83dbSDimitry Andric OS << "#endif /* " << condition << " */\n\n"; 2129*5ffd83dbSDimitry Andric } 2130*5ffd83dbSDimitry Andric 2131*5ffd83dbSDimitry Andric OS << "#ifdef __cplusplus\n" 2132*5ffd83dbSDimitry Andric "} /* extern \"C\" */\n" 2133*5ffd83dbSDimitry Andric "#endif\n" 2134*5ffd83dbSDimitry Andric "\n" 2135*5ffd83dbSDimitry Andric "#endif /* __ARM_CDE_H */\n"; 2136*5ffd83dbSDimitry Andric } 2137*5ffd83dbSDimitry Andric 2138*5ffd83dbSDimitry Andric void CdeEmitter::EmitBuiltinDef(raw_ostream &OS) { 2139*5ffd83dbSDimitry Andric for (const auto &kv : ACLEIntrinsics) { 2140*5ffd83dbSDimitry Andric if (kv.second->headerOnly()) 2141*5ffd83dbSDimitry Andric continue; 2142*5ffd83dbSDimitry Andric const ACLEIntrinsic &Int = *kv.second; 2143*5ffd83dbSDimitry Andric OS << "TARGET_HEADER_BUILTIN(__builtin_arm_cde_" << Int.fullName() 2144*5ffd83dbSDimitry Andric << ", \"\", \"ncU\", \"arm_cde.h\", ALL_LANGUAGES, \"\")\n"; 2145*5ffd83dbSDimitry Andric } 2146*5ffd83dbSDimitry Andric } 2147*5ffd83dbSDimitry Andric 2148*5ffd83dbSDimitry Andric void CdeEmitter::EmitBuiltinSema(raw_ostream &OS) { 2149*5ffd83dbSDimitry Andric std::map<std::string, std::set<std::string>> Checks; 2150*5ffd83dbSDimitry Andric GroupSemaChecks(Checks); 2151*5ffd83dbSDimitry Andric 2152*5ffd83dbSDimitry Andric for (const auto &kv : Checks) { 2153*5ffd83dbSDimitry Andric for (StringRef Name : kv.second) 2154*5ffd83dbSDimitry Andric OS << "case ARM::BI__builtin_arm_cde_" << Name << ":\n"; 2155*5ffd83dbSDimitry Andric OS << " Err = " << kv.first << " break;\n"; 2156480093f4SDimitry Andric } 2157480093f4SDimitry Andric } 2158480093f4SDimitry Andric 2159480093f4SDimitry Andric } // namespace 2160480093f4SDimitry Andric 2161480093f4SDimitry Andric namespace clang { 2162480093f4SDimitry Andric 2163*5ffd83dbSDimitry Andric // MVE 2164*5ffd83dbSDimitry Andric 2165480093f4SDimitry Andric void EmitMveHeader(RecordKeeper &Records, raw_ostream &OS) { 2166480093f4SDimitry Andric MveEmitter(Records).EmitHeader(OS); 2167480093f4SDimitry Andric } 2168480093f4SDimitry Andric 2169480093f4SDimitry Andric void EmitMveBuiltinDef(RecordKeeper &Records, raw_ostream &OS) { 2170480093f4SDimitry Andric MveEmitter(Records).EmitBuiltinDef(OS); 2171480093f4SDimitry Andric } 2172480093f4SDimitry Andric 2173480093f4SDimitry Andric void EmitMveBuiltinSema(RecordKeeper &Records, raw_ostream &OS) { 2174480093f4SDimitry Andric MveEmitter(Records).EmitBuiltinSema(OS); 2175480093f4SDimitry Andric } 2176480093f4SDimitry Andric 2177480093f4SDimitry Andric void EmitMveBuiltinCG(RecordKeeper &Records, raw_ostream &OS) { 2178480093f4SDimitry Andric MveEmitter(Records).EmitBuiltinCG(OS); 2179480093f4SDimitry Andric } 2180480093f4SDimitry Andric 2181480093f4SDimitry Andric void EmitMveBuiltinAliases(RecordKeeper &Records, raw_ostream &OS) { 2182480093f4SDimitry Andric MveEmitter(Records).EmitBuiltinAliases(OS); 2183480093f4SDimitry Andric } 2184480093f4SDimitry Andric 2185*5ffd83dbSDimitry Andric // CDE 2186*5ffd83dbSDimitry Andric 2187*5ffd83dbSDimitry Andric void EmitCdeHeader(RecordKeeper &Records, raw_ostream &OS) { 2188*5ffd83dbSDimitry Andric CdeEmitter(Records).EmitHeader(OS); 2189*5ffd83dbSDimitry Andric } 2190*5ffd83dbSDimitry Andric 2191*5ffd83dbSDimitry Andric void EmitCdeBuiltinDef(RecordKeeper &Records, raw_ostream &OS) { 2192*5ffd83dbSDimitry Andric CdeEmitter(Records).EmitBuiltinDef(OS); 2193*5ffd83dbSDimitry Andric } 2194*5ffd83dbSDimitry Andric 2195*5ffd83dbSDimitry Andric void EmitCdeBuiltinSema(RecordKeeper &Records, raw_ostream &OS) { 2196*5ffd83dbSDimitry Andric CdeEmitter(Records).EmitBuiltinSema(OS); 2197*5ffd83dbSDimitry Andric } 2198*5ffd83dbSDimitry Andric 2199*5ffd83dbSDimitry Andric void EmitCdeBuiltinCG(RecordKeeper &Records, raw_ostream &OS) { 2200*5ffd83dbSDimitry Andric CdeEmitter(Records).EmitBuiltinCG(OS); 2201*5ffd83dbSDimitry Andric } 2202*5ffd83dbSDimitry Andric 2203*5ffd83dbSDimitry Andric void EmitCdeBuiltinAliases(RecordKeeper &Records, raw_ostream &OS) { 2204*5ffd83dbSDimitry Andric CdeEmitter(Records).EmitBuiltinAliases(OS); 2205*5ffd83dbSDimitry Andric } 2206*5ffd83dbSDimitry Andric 2207480093f4SDimitry Andric } // end namespace clang 2208