brintos

brintos / llvm-project-archived public Read only

0
0
Text · 87.3 KiB · 8fde56a Raw
2300 lines · cpp
1//===-- MveEmitter.cpp - Generate arm_mve.h for use with clang ------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// This set of linked tablegen backends is responsible for emitting the bits10// and pieces that implement <arm_mve.h>, which is defined by the ACLE standard11// and provides a set of types and functions for (more or less) direct access12// to the MVE instruction set, including the scalar shifts as well as the13// vector instructions.14//15// MVE's standard intrinsic functions are unusual in that they have a system of16// polymorphism. For example, the function vaddq() can behave like vaddq_u16(),17// vaddq_f32(), vaddq_s8(), etc., depending on the types of the vector18// arguments you give it.19//20// This constrains the implementation strategies. The usual approach to making21// the user-facing functions polymorphic would be to either use22// __attribute__((overloadable)) to make a set of vaddq() functions that are23// all inline wrappers on the underlying clang builtins, or to define a single24// vaddq() macro which expands to an instance of _Generic.25//26// The inline-wrappers approach would work fine for most intrinsics, except for27// the ones that take an argument required to be a compile-time constant,28// because if you wrap an inline function around a call to a builtin, the29// constant nature of the argument is not passed through.30//31// The _Generic approach can be made to work with enough effort, but it takes a32// lot of machinery, because of the design feature of _Generic that even the33// untaken branches are required to pass all front-end validity checks such as34// type-correctness. You can work around that by nesting further _Generics all35// over the place to coerce things to the right type in untaken branches, but36// what you get out is complicated, hard to guarantee its correctness, and37// worst of all, gives _completely unreadable_ error messages if the user gets38// the types wrong for an intrinsic call.39//40// Therefore, my strategy is to introduce a new __attribute__ that allows a41// function to be mapped to a clang builtin even though it doesn't have the42// same name, and then declare all the user-facing MVE function names with that43// attribute, mapping each one directly to the clang builtin. And the44// polymorphic ones have __attribute__((overloadable)) as well. So once the45// compiler has resolved the overload, it knows the internal builtin ID of the46// selected function, and can check the immediate arguments against that; and47// if the user gets the types wrong in a call to a polymorphic intrinsic, they48// get a completely clear error message showing all the declarations of that49// function in the header file and explaining why each one doesn't fit their50// call.51//52// The downside of this is that if every clang builtin has to correspond53// exactly to a user-facing ACLE intrinsic, then you can't save work in the54// frontend by doing it in the header file: CGBuiltin.cpp has to do the entire55// job of converting an ACLE intrinsic call into LLVM IR. So the Tablegen56// description for an MVE intrinsic has to contain a full description of the57// sequence of IRBuilder calls that clang will need to make.58//59//===----------------------------------------------------------------------===//60 61#include "llvm/ADT/APInt.h"62#include "llvm/ADT/StringRef.h"63#include "llvm/ADT/StringSwitch.h"64#include "llvm/Support/Casting.h"65#include "llvm/Support/raw_ostream.h"66#include "llvm/TableGen/Error.h"67#include "llvm/TableGen/Record.h"68#include "llvm/TableGen/StringToOffsetTable.h"69#include <cassert>70#include <cstddef>71#include <cstdint>72#include <list>73#include <map>74#include <memory>75#include <set>76#include <string>77#include <vector>78 79using namespace llvm;80 81namespace {82 83class EmitterBase;84class Result;85 86// -----------------------------------------------------------------------------87// A system of classes to represent all the types we'll need to deal with in88// the prototypes of intrinsics.89//90// Query methods include finding out the C name of a type; the "LLVM name" in91// the sense of a C++ code snippet that can be used in the codegen function;92// the suffix that represents the type in the ACLE intrinsic naming scheme93// (e.g. 's32' represents int32_t in intrinsics such as vaddq_s32); whether the94// type is floating-point related (hence should be under #ifdef in the MVE95// header so that it isn't included in integer-only MVE mode); and the type's96// size in bits. Not all subtypes support all these queries.97 98class Type {99public:100  enum class TypeKind {101    // Void appears as a return type (for store intrinsics, which are pure102    // side-effect). It's also used as the parameter type in the Tablegen103    // when an intrinsic doesn't need to come in various suffixed forms like104    // vfooq_s8,vfooq_u16,vfooq_f32.105    Void,106 107    // Scalar is used for ordinary int and float types of all sizes.108    Scalar,109 110    // Vector is used for anything that occupies exactly one MVE vector111    // register, i.e. {uint,int,float}NxM_t.112    Vector,113 114    // MultiVector is used for the {uint,int,float}NxMxK_t types used by the115    // interleaving load/store intrinsics v{ld,st}{2,4}q.116    MultiVector,117 118    // Predicate is used by all the predicated intrinsics. Its C119    // representation is mve_pred16_t (which is just an alias for uint16_t).120    // But we give more detail here, by indicating that a given predicate121    // instruction is logically regarded as a vector of i1 containing the122    // same number of lanes as the input vector type. So our Predicate type123    // comes with a lane count, which we use to decide which kind of <n x i1>124    // we'll invoke the pred_i2v IR intrinsic to translate it into.125    Predicate,126 127    // Pointer is used for pointer types (obviously), and comes with a flag128    // indicating whether it's a pointer to a const or mutable instance of129    // the pointee type.130    Pointer,131  };132 133private:134  const TypeKind TKind;135 136protected:137  Type(TypeKind K) : TKind(K) {}138 139public:140  TypeKind typeKind() const { return TKind; }141  virtual ~Type() = default;142  virtual bool requiresFloat() const = 0;143  virtual bool requiresMVE() const = 0;144  virtual unsigned sizeInBits() const = 0;145  virtual std::string cName() const = 0;146  virtual std::string llvmName() const {147    PrintFatalError("no LLVM type name available for type " + cName());148  }149  virtual std::string acleSuffix(std::string) const {150    PrintFatalError("no ACLE suffix available for this type");151  }152};153 154enum class ScalarTypeKind { SignedInt, UnsignedInt, Float };155inline std::string toLetter(ScalarTypeKind kind) {156  switch (kind) {157  case ScalarTypeKind::SignedInt:158    return "s";159  case ScalarTypeKind::UnsignedInt:160    return "u";161  case ScalarTypeKind::Float:162    return "f";163  }164  llvm_unreachable("Unhandled ScalarTypeKind enum");165}166inline std::string toCPrefix(ScalarTypeKind kind) {167  switch (kind) {168  case ScalarTypeKind::SignedInt:169    return "int";170  case ScalarTypeKind::UnsignedInt:171    return "uint";172  case ScalarTypeKind::Float:173    return "float";174  }175  llvm_unreachable("Unhandled ScalarTypeKind enum");176}177 178class VoidType : public Type {179public:180  VoidType() : Type(TypeKind::Void) {}181  unsigned sizeInBits() const override { return 0; }182  bool requiresFloat() const override { return false; }183  bool requiresMVE() const override { return false; }184  std::string cName() const override { return "void"; }185 186  static bool classof(const Type *T) { return T->typeKind() == TypeKind::Void; }187  std::string acleSuffix(std::string) const override { return ""; }188};189 190class PointerType : public Type {191  const Type *Pointee;192  bool Const;193 194public:195  PointerType(const Type *Pointee, bool Const)196      : Type(TypeKind::Pointer), Pointee(Pointee), Const(Const) {}197  unsigned sizeInBits() const override { return 32; }198  bool requiresFloat() const override { return Pointee->requiresFloat(); }199  bool requiresMVE() const override { return Pointee->requiresMVE(); }200  std::string cName() const override {201    std::string Name = Pointee->cName();202 203    // The syntax for a pointer in C is different when the pointee is204    // itself a pointer. The MVE intrinsics don't contain any double205    // pointers, so we don't need to worry about that wrinkle.206    assert(!isa<PointerType>(Pointee) && "Pointer to pointer not supported");207 208    if (Const)209      Name = "const " + Name;210    return Name + " *";211  }212  std::string llvmName() const override { return "Builder.getPtrTy()"; }213  const Type *getPointeeType() const { return Pointee; }214 215  static bool classof(const Type *T) {216    return T->typeKind() == TypeKind::Pointer;217  }218};219 220// Base class for all the types that have a name of the form221// [prefix][numbers]_t, like int32_t, uint16x8_t, float32x4x2_t.222//223// For this sub-hierarchy we invent a cNameBase() method which returns the224// whole name except for the trailing "_t", so that Vector and MultiVector can225// append an extra "x2" or whatever to their element type's cNameBase(). Then226// the main cName() query method puts "_t" on the end for the final type name.227 228class CRegularNamedType : public Type {229  using Type::Type;230  virtual std::string cNameBase() const = 0;231 232public:233  std::string cName() const override { return cNameBase() + "_t"; }234};235 236class ScalarType : public CRegularNamedType {237  ScalarTypeKind Kind;238  unsigned Bits;239  std::string NameOverride;240 241public:242  ScalarType(const Record *Record) : CRegularNamedType(TypeKind::Scalar) {243    Kind = StringSwitch<ScalarTypeKind>(Record->getValueAsString("kind"))244               .Case("s", ScalarTypeKind::SignedInt)245               .Case("u", ScalarTypeKind::UnsignedInt)246               .Case("f", ScalarTypeKind::Float);247    Bits = Record->getValueAsInt("size");248    NameOverride = std::string(Record->getValueAsString("nameOverride"));249  }250  unsigned sizeInBits() const override { return Bits; }251  ScalarTypeKind kind() const { return Kind; }252  std::string suffix() const { return toLetter(Kind) + utostr(Bits); }253  std::string cNameBase() const override {254    return toCPrefix(Kind) + utostr(Bits);255  }256  std::string cName() const override {257    if (NameOverride.empty())258      return CRegularNamedType::cName();259    return NameOverride;260  }261  std::string llvmName() const override {262    if (Kind == ScalarTypeKind::Float) {263      if (Bits == 16)264        return "HalfTy";265      if (Bits == 32)266        return "FloatTy";267      if (Bits == 64)268        return "DoubleTy";269      PrintFatalError("bad size for floating type");270    }271    return "Int" + utostr(Bits) + "Ty";272  }273  std::string acleSuffix(std::string overrideLetter) const override {274    return "_" + (overrideLetter.size() ? overrideLetter : toLetter(Kind))275               + utostr(Bits);276  }277  bool isInteger() const { return Kind != ScalarTypeKind::Float; }278  bool requiresFloat() const override { return !isInteger(); }279  bool requiresMVE() const override { return false; }280  bool hasNonstandardName() const { return !NameOverride.empty(); }281 282  static bool classof(const Type *T) {283    return T->typeKind() == TypeKind::Scalar;284  }285};286 287class VectorType : public CRegularNamedType {288  const ScalarType *Element;289  unsigned Lanes;290 291public:292  VectorType(const ScalarType *Element, unsigned Lanes)293      : CRegularNamedType(TypeKind::Vector), Element(Element), Lanes(Lanes) {}294  unsigned sizeInBits() const override { return Lanes * Element->sizeInBits(); }295  unsigned lanes() const { return Lanes; }296  bool requiresFloat() const override { return Element->requiresFloat(); }297  bool requiresMVE() const override { return true; }298  std::string cNameBase() const override {299    return Element->cNameBase() + "x" + utostr(Lanes);300  }301  std::string llvmName() const override {302    return "llvm::FixedVectorType::get(" + Element->llvmName() + ", " +303           utostr(Lanes) + ")";304  }305 306  static bool classof(const Type *T) {307    return T->typeKind() == TypeKind::Vector;308  }309};310 311class MultiVectorType : public CRegularNamedType {312  const VectorType *Element;313  unsigned Registers;314 315public:316  MultiVectorType(unsigned Registers, const VectorType *Element)317      : CRegularNamedType(TypeKind::MultiVector), Element(Element),318        Registers(Registers) {}319  unsigned sizeInBits() const override {320    return Registers * Element->sizeInBits();321  }322  unsigned registers() const { return Registers; }323  bool requiresFloat() const override { return Element->requiresFloat(); }324  bool requiresMVE() const override { return true; }325  std::string cNameBase() const override {326    return Element->cNameBase() + "x" + utostr(Registers);327  }328 329  // MultiVectorType doesn't override llvmName, because we don't expect to do330  // automatic code generation for the MVE intrinsics that use it: the {vld2,331  // vld4, vst2, vst4} family are the only ones that use these types, so it was332  // easier to hand-write the codegen for dealing with these structs than to333  // build in lots of extra automatic machinery that would only be used once.334 335  static bool classof(const Type *T) {336    return T->typeKind() == TypeKind::MultiVector;337  }338};339 340class PredicateType : public CRegularNamedType {341  unsigned Lanes;342 343public:344  PredicateType(unsigned Lanes)345      : CRegularNamedType(TypeKind::Predicate), Lanes(Lanes) {}346  unsigned sizeInBits() const override { return 16; }347  std::string cNameBase() const override { return "mve_pred16"; }348  bool requiresFloat() const override { return false; };349  bool requiresMVE() const override { return true; }350  std::string llvmName() const override {351    return "llvm::FixedVectorType::get(Builder.getInt1Ty(), " + utostr(Lanes) +352           ")";353  }354 355  static bool classof(const Type *T) {356    return T->typeKind() == TypeKind::Predicate;357  }358};359 360// -----------------------------------------------------------------------------361// Class to facilitate merging together the code generation for many intrinsics362// by means of varying a few constant or type parameters.363//364// Most obviously, the intrinsics in a single parametrised family will have365// code generation sequences that only differ in a type or two, e.g. vaddq_s8366// and vaddq_u16 will look the same apart from putting a different vector type367// in the call to CGM.getIntrinsic(). But also, completely different intrinsics368// will often code-generate in the same way, with only a different choice of369// _which_ IR intrinsic they lower to (e.g. vaddq_m_s8 and vmulq_m_s8), but370// marshalling the arguments and return values of the IR intrinsic in exactly371// the same way. And others might differ only in some other kind of constant,372// such as a lane index.373//374// So, when we generate the IR-building code for all these intrinsics, we keep375// track of every value that could possibly be pulled out of the code and376// stored ahead of time in a local variable. Then we group together intrinsics377// by textual equivalence of the code that would result if _all_ those378// parameters were stored in local variables. That gives us maximal sets that379// can be implemented by a single piece of IR-building code by changing380// parameter values ahead of time.381//382// After we've done that, we do a second pass in which we only allocate _some_383// of the parameters into local variables, by tracking which ones have the same384// values as each other (so that a single variable can be reused) and which385// ones are the same across the whole set (so that no variable is needed at386// all).387//388// Hence the class below. Its allocParam method is invoked during code389// generation by every method of a Result subclass (see below) that wants to390// give it the opportunity to pull something out into a switchable parameter.391// It returns a variable name for the parameter, or (if it's being used in the392// second pass once we've decided that some parameters don't need to be stored393// in variables after all) it might just return the input expression unchanged.394 395struct CodeGenParamAllocator {396  // Accumulated during code generation397  std::vector<std::string> *ParamTypes = nullptr;398  std::vector<std::string> *ParamValues = nullptr;399 400  // Provided ahead of time in pass 2, to indicate which parameters are being401  // assigned to what. This vector contains an entry for each call to402  // allocParam expected during code gen (which we counted up in pass 1), and403  // indicates the number of the parameter variable that should be returned, or404  // -1 if this call shouldn't allocate a parameter variable at all.405  //406  // We rely on the recursive code generation working identically in passes 1407  // and 2, so that the same list of calls to allocParam happen in the same408  // order. That guarantees that the parameter numbers recorded in pass 1 will409  // match the entries in this vector that store what EmitterBase::EmitBuiltinCG410  // decided to do about each one in pass 2.411  std::vector<int> *ParamNumberMap = nullptr;412 413  // Internally track how many things we've allocated414  unsigned nparams = 0;415 416  std::string allocParam(StringRef Type, StringRef Value) {417    unsigned ParamNumber;418 419    if (!ParamNumberMap) {420      // In pass 1, unconditionally assign a new parameter variable to every421      // value we're asked to process.422      ParamNumber = nparams++;423    } else {424      // In pass 2, consult the map provided by the caller to find out which425      // variable we should be keeping things in.426      int MapValue = (*ParamNumberMap)[nparams++];427      if (MapValue < 0)428        return std::string(Value);429      ParamNumber = MapValue;430    }431 432    // If we've allocated a new parameter variable for the first time, store433    // its type and value to be retrieved after codegen.434    if (ParamTypes && ParamTypes->size() == ParamNumber)435      ParamTypes->push_back(std::string(Type));436    if (ParamValues && ParamValues->size() == ParamNumber)437      ParamValues->push_back(std::string(Value));438 439    // Unimaginative naming scheme for parameter variables.440    return "Param" + utostr(ParamNumber);441  }442};443 444// -----------------------------------------------------------------------------445// System of classes that represent all the intermediate values used during446// code-generation for an intrinsic.447//448// The base class 'Result' can represent a value of the LLVM type 'Value', or449// sometimes 'Address' (for loads/stores, including an alignment requirement).450//451// In the case where the Tablegen provides a value in the codegen dag as a452// plain integer literal, the Result object we construct here will be one that453// returns true from hasIntegerConstantValue(). This allows the generated C++454// code to use the constant directly in contexts which can take a literal455// integer, such as Builder.CreateExtractValue(thing, 1), without going to the456// effort of calling llvm::ConstantInt::get() and then pulling the constant457// back out of the resulting llvm:Value later.458 459class Result {460public:461  // Convenient shorthand for the pointer type we'll be using everywhere.462  using Ptr = std::shared_ptr<Result>;463 464private:465  Ptr Predecessor;466  std::string VarName;467  bool VarNameUsed = false;468  unsigned Visited = 0;469 470public:471  virtual ~Result() = default;472  using Scope = std::map<std::string, Ptr, std::less<>>;473  virtual void genCode(raw_ostream &OS, CodeGenParamAllocator &) const = 0;474  virtual bool hasIntegerConstantValue() const { return false; }475  virtual uint32_t integerConstantValue() const { return 0; }476  virtual bool hasIntegerValue() const { return false; }477  virtual std::string getIntegerValue(const std::string &) {478    llvm_unreachable("non-working Result::getIntegerValue called");479  }480  virtual std::string typeName() const { return "Value *"; }481 482  // Mostly, when a code-generation operation has a dependency on prior483  // operations, it's because it uses the output values of those operations as484  // inputs. But there's one exception, which is the use of 'seq' in Tablegen485  // to indicate that operations have to be performed in sequence regardless of486  // whether they use each others' output values.487  //488  // So, the actual generation of code is done by depth-first search, using the489  // prerequisites() method to get a list of all the other Results that have to490  // be computed before this one. That method divides into the 'predecessor',491  // set by setPredecessor() while processing a 'seq' dag node, and the list492  // returned by 'morePrerequisites', which each subclass implements to return493  // a list of the Results it uses as input to whatever its own computation is494  // doing.495 496  virtual void morePrerequisites(std::vector<Ptr> &output) const {}497  std::vector<Ptr> prerequisites() const {498    std::vector<Ptr> ToRet;499    if (Predecessor)500      ToRet.push_back(Predecessor);501    morePrerequisites(ToRet);502    return ToRet;503  }504 505  void setPredecessor(Ptr p) {506    // If the user has nested one 'seq' node inside another, and this507    // method is called on the return value of the inner 'seq' (i.e.508    // the final item inside it), then we can't link _this_ node to p,509    // because it already has a predecessor. Instead, walk the chain510    // until we find the first item in the inner seq, and link that to511    // p, so that nesting seqs has the obvious effect of linking512    // everything together into one long sequential chain.513    Result *r = this;514    while (r->Predecessor)515      r = r->Predecessor.get();516    r->Predecessor = p;517  }518 519  // Each Result will be assigned a variable name in the output code, but not520  // all those variable names will actually be used (e.g. the return value of521  // Builder.CreateStore has void type, so nobody will want to refer to it). To522  // prevent annoying compiler warnings, we track whether each Result's523  // variable name was ever actually mentioned in subsequent statements, so524  // that it can be left out of the final generated code.525  std::string varname() {526    VarNameUsed = true;527    return VarName;528  }529  void setVarname(const StringRef s) { VarName = std::string(s); }530  bool varnameUsed() const { return VarNameUsed; }531 532  // Emit code to generate this result as a Value *.533  virtual std::string asValue() {534    return varname();535  }536 537  // Code generation happens in multiple passes. This method tracks whether a538  // Result has yet been visited in a given pass, without the need for a539  // tedious loop in between passes that goes through and resets a 'visited'540  // flag back to false: you just set Pass=1 the first time round, and Pass=2541  // the second time.542  bool needsVisiting(unsigned Pass) {543    bool ToRet = Visited < Pass;544    Visited = Pass;545    return ToRet;546  }547};548 549// Result subclass that retrieves one of the arguments to the clang builtin550// function. In cases where the argument has pointer type, we call551// EmitPointerWithAlignment and store the result in a variable of type Address,552// so that load and store IR nodes can know the right alignment. Otherwise, we553// call EmitScalarExpr.554//555// There are aggregate parameters in the MVE intrinsics API, but we don't deal556// with them in this Tablegen back end: they only arise in the vld2q/vld4q and557// vst2q/vst4q family, which is few enough that we just write the code by hand558// for those in CGBuiltin.cpp.559class BuiltinArgResult : public Result {560public:561  unsigned ArgNum;562  bool AddressType;563  bool Immediate;564  BuiltinArgResult(unsigned ArgNum, bool AddressType, bool Immediate)565      : ArgNum(ArgNum), AddressType(AddressType), Immediate(Immediate) {}566  void genCode(raw_ostream &OS, CodeGenParamAllocator &) const override {567    OS << (AddressType ? "EmitPointerWithAlignment" : "EmitScalarExpr")568       << "(E->getArg(" << ArgNum << "))";569  }570  std::string typeName() const override {571    return AddressType ? "Address" : Result::typeName();572  }573  // Emit code to generate this result as a Value *.574  std::string asValue() override {575    if (AddressType)576      return "(" + varname() + ".emitRawPointer(*this))";577    return Result::asValue();578  }579  bool hasIntegerValue() const override { return Immediate; }580  std::string getIntegerValue(const std::string &IntType) override {581    return "GetIntegerConstantValue<" + IntType + ">(E->getArg(" +582           utostr(ArgNum) + "), getContext())";583  }584};585 586// Result subclass for an integer literal appearing in Tablegen. This may need587// to be turned into an llvm::Result by means of llvm::ConstantInt::get(), or588// it may be used directly as an integer, depending on which IRBuilder method589// it's being passed to.590class IntLiteralResult : public Result {591public:592  const ScalarType *IntegerType;593  uint32_t IntegerValue;594  IntLiteralResult(const ScalarType *IntegerType, uint32_t IntegerValue)595      : IntegerType(IntegerType), IntegerValue(IntegerValue) {}596  void genCode(raw_ostream &OS,597               CodeGenParamAllocator &ParamAlloc) const override {598    OS << "llvm::ConstantInt::get("599       << ParamAlloc.allocParam("llvm::Type *", IntegerType->llvmName())600       << ", ";601    OS << ParamAlloc.allocParam(IntegerType->cName(), utostr(IntegerValue))602       << ")";603  }604  bool hasIntegerConstantValue() const override { return true; }605  uint32_t integerConstantValue() const override { return IntegerValue; }606};607 608// Result subclass representing a cast between different integer types. We use609// our own ScalarType abstraction as the representation of the target type,610// which gives both size and signedness.611class IntCastResult : public Result {612public:613  const ScalarType *IntegerType;614  Ptr V;615  IntCastResult(const ScalarType *IntegerType, Ptr V)616      : IntegerType(IntegerType), V(V) {}617  void genCode(raw_ostream &OS,618               CodeGenParamAllocator &ParamAlloc) const override {619    OS << "Builder.CreateIntCast(" << V->varname() << ", "620       << ParamAlloc.allocParam("llvm::Type *", IntegerType->llvmName()) << ", "621       << ParamAlloc.allocParam("bool",622                                IntegerType->kind() == ScalarTypeKind::SignedInt623                                    ? "true"624                                    : "false")625       << ")";626  }627  void morePrerequisites(std::vector<Ptr> &output) const override {628    output.push_back(V);629  }630};631 632// Result subclass representing a cast between different pointer types.633class PointerCastResult : public Result {634public:635  const PointerType *PtrType;636  Ptr V;637  PointerCastResult(const PointerType *PtrType, Ptr V)638      : PtrType(PtrType), V(V) {}639  void genCode(raw_ostream &OS,640               CodeGenParamAllocator &ParamAlloc) const override {641    OS << "Builder.CreatePointerCast(" << V->asValue() << ", "642       << ParamAlloc.allocParam("llvm::Type *", PtrType->llvmName()) << ")";643  }644  void morePrerequisites(std::vector<Ptr> &output) const override {645    output.push_back(V);646  }647};648 649// Result subclass representing a call to an IRBuilder method. Each IRBuilder650// method we want to use will have a Tablegen record giving the method name and651// describing any important details of how to call it, such as whether a652// particular argument should be an integer constant instead of an llvm::Value.653class IRBuilderResult : public Result {654public:655  StringRef CallPrefix;656  std::vector<Ptr> Args;657  std::set<unsigned> AddressArgs;658  std::map<unsigned, std::string> IntegerArgs;659  IRBuilderResult(StringRef CallPrefix, const std::vector<Ptr> &Args,660                  const std::set<unsigned> &AddressArgs,661                  const std::map<unsigned, std::string> &IntegerArgs)662      : CallPrefix(CallPrefix), Args(Args), AddressArgs(AddressArgs),663        IntegerArgs(IntegerArgs) {}664  void genCode(raw_ostream &OS,665               CodeGenParamAllocator &ParamAlloc) const override {666    OS << CallPrefix;667    const char *Sep = "";668    for (unsigned i = 0, e = Args.size(); i < e; ++i) {669      Ptr Arg = Args[i];670      auto it = IntegerArgs.find(i);671 672      OS << Sep;673      Sep = ", ";674 675      if (it != IntegerArgs.end()) {676        if (Arg->hasIntegerConstantValue())677          OS << "static_cast<" << it->second << ">("678             << ParamAlloc.allocParam(it->second,679                                      utostr(Arg->integerConstantValue()))680             << ")";681        else if (Arg->hasIntegerValue())682          OS << ParamAlloc.allocParam(it->second,683                                      Arg->getIntegerValue(it->second));684      } else {685        OS << Arg->varname();686      }687    }688    OS << ")";689  }690  void morePrerequisites(std::vector<Ptr> &output) const override {691    for (unsigned i = 0, e = Args.size(); i < e; ++i) {692      Ptr Arg = Args[i];693      if (IntegerArgs.find(i) != IntegerArgs.end())694        continue;695      output.push_back(Arg);696    }697  }698};699 700// Result subclass representing making an Address out of a Value.701class AddressResult : public Result {702public:703  Ptr Arg;704  const Type *Ty;705  unsigned Align;706  AddressResult(Ptr Arg, const Type *Ty, unsigned Align)707      : Arg(Arg), Ty(Ty), Align(Align) {}708  void genCode(raw_ostream &OS,709               CodeGenParamAllocator &ParamAlloc) const override {710    OS << "Address(" << Arg->varname() << ", " << Ty->llvmName()711       << ", CharUnits::fromQuantity(" << Align << "))";712  }713  std::string typeName() const override {714    return "Address";715  }716  void morePrerequisites(std::vector<Ptr> &output) const override {717    output.push_back(Arg);718  }719};720 721// Result subclass representing a call to an IR intrinsic, which we first have722// to look up using an Intrinsic::ID constant and an array of types.723class IRIntrinsicResult : public Result {724public:725  std::string IntrinsicID;726  std::vector<const Type *> ParamTypes;727  std::vector<Ptr> Args;728  IRIntrinsicResult(StringRef IntrinsicID,729                    const std::vector<const Type *> &ParamTypes,730                    const std::vector<Ptr> &Args)731      : IntrinsicID(std::string(IntrinsicID)), ParamTypes(ParamTypes),732        Args(Args) {}733  void genCode(raw_ostream &OS,734               CodeGenParamAllocator &ParamAlloc) const override {735    std::string IntNo = ParamAlloc.allocParam(736        "Intrinsic::ID", "Intrinsic::" + IntrinsicID);737    OS << "Builder.CreateCall(CGM.getIntrinsic(" << IntNo;738    if (!ParamTypes.empty()) {739      OS << ", {";740      const char *Sep = "";741      for (auto T : ParamTypes) {742        OS << Sep << ParamAlloc.allocParam("llvm::Type *", T->llvmName());743        Sep = ", ";744      }745      OS << "}";746    }747    OS << "), {";748    const char *Sep = "";749    for (auto Arg : Args) {750      OS << Sep << Arg->asValue();751      Sep = ", ";752    }753    OS << "})";754  }755  void morePrerequisites(std::vector<Ptr> &output) const override {756    llvm::append_range(output, Args);757  }758};759 760// Result subclass that generates761// Builder.getIsFPConstrained() ? <Standard> : <StrictFp>762class StrictFpAltResult : public Result {763public:764  Ptr Standard;765  Ptr StrictFp;766  StrictFpAltResult(Ptr Standard, Ptr StrictFp)767      : Standard(Standard), StrictFp(StrictFp) {}768  void genCode(raw_ostream &OS,769               CodeGenParamAllocator &ParamAlloc) const override {770    OS << "!Builder.getIsFPConstrained() ? ";771    Standard->genCode(OS, ParamAlloc);772    OS << " : ";773    StrictFp->genCode(OS, ParamAlloc);774  }775  void morePrerequisites(std::vector<Ptr> &output) const override {776    Standard->morePrerequisites(output);777  }778};779 780// Result subclass that specifies a type, for use in IRBuilder operations such781// as CreateBitCast that take a type argument.782class TypeResult : public Result {783public:784  const Type *T;785  TypeResult(const Type *T) : T(T) {}786  void genCode(raw_ostream &OS, CodeGenParamAllocator &) const override {787    OS << T->llvmName();788  }789  std::string typeName() const override {790    return "llvm::Type *";791  }792};793 794// -----------------------------------------------------------------------------795// Class that describes a single ACLE intrinsic.796//797// A Tablegen record will typically describe more than one ACLE intrinsic, by798// means of setting the 'list<Type> Params' field to a list of multiple799// parameter types, so as to define vaddq_{s8,u8,...,f16,f32} all in one go.800// We'll end up with one instance of ACLEIntrinsic for *each* parameter type,801// rather than a single one for all of them. Hence, the constructor takes both802// a Tablegen record and the current value of the parameter type.803 804class ACLEIntrinsic {805  // Structure documenting that one of the intrinsic's arguments is required to806  // be a compile-time constant integer, and what constraints there are on its807  // value. Used when generating Sema checking code.808  struct ImmediateArg {809    enum class BoundsType { ExplicitRange, UInt };810    BoundsType boundsType;811    int64_t i1, i2;812    StringRef ExtraCheckType, ExtraCheckArgs;813    const Type *ArgType;814  };815 816  // For polymorphic intrinsics, FullName is the explicit name that uniquely817  // identifies this variant of the intrinsic, and ShortName is the name it818  // shares with at least one other intrinsic.819  std::string ShortName, FullName;820 821  // Name of the architecture extension, used in the Clang builtin name822  StringRef BuiltinExtension;823 824  // A very small number of intrinsics _only_ have a polymorphic825  // variant (vuninitializedq taking an unevaluated argument).826  bool PolymorphicOnly;827 828  // Another rarely-used flag indicating that the builtin doesn't829  // evaluate its argument(s) at all.830  bool NonEvaluating;831 832  // True if the intrinsic needs only the C header part (no codegen, semantic833  // checks, etc). Used for redeclaring MVE intrinsics in the arm_cde.h header.834  bool HeaderOnly;835 836  const Type *ReturnType;837  std::vector<const Type *> ArgTypes;838  std::map<unsigned, ImmediateArg> ImmediateArgs;839  Result::Ptr Code;840 841  std::map<std::string, std::string> CustomCodeGenArgs;842 843  // Recursive function that does the internals of code generation.844  void genCodeDfs(Result::Ptr V, std::list<Result::Ptr> &Used,845                  unsigned Pass) const {846    if (!V->needsVisiting(Pass))847      return;848 849    for (Result::Ptr W : V->prerequisites())850      genCodeDfs(W, Used, Pass);851 852    Used.push_back(V);853  }854 855public:856  const std::string &shortName() const { return ShortName; }857  const std::string &fullName() const { return FullName; }858  StringRef builtinExtension() const { return BuiltinExtension; }859  const Type *returnType() const { return ReturnType; }860  const std::vector<const Type *> &argTypes() const { return ArgTypes; }861  bool requiresFloat() const {862    if (ReturnType->requiresFloat())863      return true;864    for (const Type *T : ArgTypes)865      if (T->requiresFloat())866        return true;867    return false;868  }869  bool requiresMVE() const {870    return ReturnType->requiresMVE() ||871           any_of(ArgTypes, [](const Type *T) { return T->requiresMVE(); });872  }873  bool polymorphic() const { return ShortName != FullName; }874  bool polymorphicOnly() const { return PolymorphicOnly; }875  bool nonEvaluating() const { return NonEvaluating; }876  bool headerOnly() const { return HeaderOnly; }877 878  // External entry point for code generation, called from EmitterBase.879  void genCode(raw_ostream &OS, CodeGenParamAllocator &ParamAlloc,880               unsigned Pass) const {881    assert(!headerOnly() && "Called genCode for header-only intrinsic");882    if (!hasCode()) {883      for (auto kv : CustomCodeGenArgs)884        OS << "  " << kv.first << " = " << kv.second << ";\n";885      OS << "  break; // custom code gen\n";886      return;887    }888    std::list<Result::Ptr> Used;889    genCodeDfs(Code, Used, Pass);890 891    unsigned varindex = 0;892    for (Result::Ptr V : Used)893      if (V->varnameUsed())894        V->setVarname("Val" + utostr(varindex++));895 896    for (Result::Ptr V : Used) {897      OS << "  ";898      if (V == Used.back()) {899        assert(!V->varnameUsed());900        OS << "return "; // FIXME: what if the top-level thing is void?901      } else if (V->varnameUsed()) {902        std::string Type = V->typeName();903        OS << V->typeName();904        if (!StringRef(Type).ends_with("*"))905          OS << " ";906        OS << V->varname() << " = ";907      }908      V->genCode(OS, ParamAlloc);909      OS << ";\n";910    }911  }912  bool hasCode() const { return Code != nullptr; }913 914  static std::string signedHexLiteral(const APInt &iOrig) {915    APInt i = iOrig.trunc(64);916    SmallString<40> s;917    i.toString(s, 16, true, true);918    return std::string(s);919  }920 921  std::string genSema() const {922    assert(!headerOnly() && "Called genSema for header-only intrinsic");923    std::vector<std::string> SemaChecks;924 925    for (const auto &kv : ImmediateArgs) {926      const ImmediateArg &IA = kv.second;927 928      APInt lo(128, 0), hi(128, 0);929      switch (IA.boundsType) {930      case ImmediateArg::BoundsType::ExplicitRange:931        lo = IA.i1;932        hi = IA.i2;933        break;934      case ImmediateArg::BoundsType::UInt:935        lo = 0;936        hi = APInt::getMaxValue(IA.i1).zext(128);937        break;938      }939 940      std::string Index = utostr(kv.first);941 942      // Emit a range check if the legal range of values for the943      // immediate is smaller than the _possible_ range of values for944      // its type.945      unsigned ArgTypeBits = IA.ArgType->sizeInBits();946      APInt ArgTypeRange = APInt::getMaxValue(ArgTypeBits).zext(128);947      APInt ActualRange = (hi - lo).trunc(64).sext(128);948      if (ActualRange.ult(ArgTypeRange))949        SemaChecks.push_back("SemaRef.BuiltinConstantArgRange(TheCall, " +950                             Index + ", " + signedHexLiteral(lo) + ", " +951                             signedHexLiteral(hi) + ")");952 953      if (!IA.ExtraCheckType.empty()) {954        std::string Suffix;955        if (!IA.ExtraCheckArgs.empty()) {956          std::string tmp;957          StringRef Arg = IA.ExtraCheckArgs;958          if (Arg == "!lanesize") {959            tmp = utostr(IA.ArgType->sizeInBits());960            Arg = tmp;961          }962          Suffix = (Twine(", ") + Arg).str();963        }964        SemaChecks.push_back((Twine("SemaRef.BuiltinConstantArg") +965                              IA.ExtraCheckType + "(TheCall, " + Index +966                              Suffix + ")")967                                 .str());968      }969 970      assert(!SemaChecks.empty());971    }972    if (SemaChecks.empty())973      return "";974    return join(std::begin(SemaChecks), std::end(SemaChecks),975                " ||\n         ") +976           ";\n";977  }978 979  ACLEIntrinsic(EmitterBase &ME, const Record *R, const Type *Param);980};981 982// -----------------------------------------------------------------------------983// The top-level class that holds all the state from analyzing the entire984// Tablegen input.985 986class EmitterBase {987protected:988  // EmitterBase holds a collection of all the types we've instantiated.989  VoidType Void;990  std::map<std::string, std::unique_ptr<ScalarType>> ScalarTypes;991  std::map<std::tuple<ScalarTypeKind, unsigned, unsigned>,992           std::unique_ptr<VectorType>>993      VectorTypes;994  std::map<std::pair<std::string, unsigned>, std::unique_ptr<MultiVectorType>>995      MultiVectorTypes;996  std::map<unsigned, std::unique_ptr<PredicateType>> PredicateTypes;997  std::map<std::string, std::unique_ptr<PointerType>> PointerTypes;998 999  // And all the ACLEIntrinsic instances we've created.1000  std::map<std::string, std::unique_ptr<ACLEIntrinsic>> ACLEIntrinsics;1001 1002public:1003  // Methods to create a Type object, or return the right existing one from the1004  // maps stored in this object.1005  const VoidType *getVoidType() { return &Void; }1006  const ScalarType *getScalarType(StringRef Name) {1007    return ScalarTypes[std::string(Name)].get();1008  }1009  const ScalarType *getScalarType(const Record *R) {1010    return getScalarType(R->getName());1011  }1012  const VectorType *getVectorType(const ScalarType *ST, unsigned Lanes) {1013    std::tuple<ScalarTypeKind, unsigned, unsigned> key(ST->kind(),1014                                                       ST->sizeInBits(), Lanes);1015    auto [It, Inserted] = VectorTypes.try_emplace(key);1016    if (Inserted)1017      It->second = std::make_unique<VectorType>(ST, Lanes);1018    return It->second.get();1019  }1020  const VectorType *getVectorType(const ScalarType *ST) {1021    return getVectorType(ST, 128 / ST->sizeInBits());1022  }1023  const MultiVectorType *getMultiVectorType(unsigned Registers,1024                                            const VectorType *VT) {1025    std::pair<std::string, unsigned> key(VT->cNameBase(), Registers);1026    auto [It, Inserted] = MultiVectorTypes.try_emplace(key);1027    if (Inserted)1028      It->second = std::make_unique<MultiVectorType>(Registers, VT);1029    return It->second.get();1030  }1031  const PredicateType *getPredicateType(unsigned Lanes) {1032    unsigned key = Lanes;1033    auto [It, Inserted] = PredicateTypes.try_emplace(key);1034    if (Inserted)1035      It->second = std::make_unique<PredicateType>(Lanes);1036    return It->second.get();1037  }1038  const PointerType *getPointerType(const Type *T, bool Const) {1039    PointerType PT(T, Const);1040    std::string key = PT.cName();1041    auto [It, Inserted] = PointerTypes.try_emplace(key);1042    if (Inserted)1043      It->second = std::make_unique<PointerType>(PT);1044    return It->second.get();1045  }1046 1047  // Methods to construct a type from various pieces of Tablegen. These are1048  // always called in the context of setting up a particular ACLEIntrinsic, so1049  // there's always an ambient parameter type (because we're iterating through1050  // the Params list in the Tablegen record for the intrinsic), which is used1051  // to expand Tablegen classes like 'Vector' which mean something different in1052  // each member of a parametric family.1053  const Type *getType(const Record *R, const Type *Param);1054  const Type *getType(const DagInit *D, const Type *Param);1055  const Type *getType(const Init *I, const Type *Param);1056 1057  // Functions that translate the Tablegen representation of an intrinsic's1058  // code generation into a collection of Value objects (which will then be1059  // reprocessed to read out the actual C++ code included by CGBuiltin.cpp).1060  Result::Ptr getCodeForDag(const DagInit *D, const Result::Scope &Scope,1061                            const Type *Param);1062  Result::Ptr getCodeForDagArg(const DagInit *D, unsigned ArgNum,1063                               const Result::Scope &Scope, const Type *Param);1064  Result::Ptr getCodeForArg(unsigned ArgNum, const Type *ArgType, bool Promote,1065                            bool Immediate);1066 1067  void GroupSemaChecks(std::map<std::string, std::set<std::string>> &Checks);1068 1069  // Constructor and top-level functions.1070 1071  EmitterBase(const RecordKeeper &Records);1072  virtual ~EmitterBase() = default;1073 1074  virtual void EmitHeader(raw_ostream &OS) = 0;1075  virtual void EmitBuiltinDef(raw_ostream &OS) = 0;1076  virtual void EmitBuiltinSema(raw_ostream &OS) = 0;1077  void EmitBuiltinCG(raw_ostream &OS);1078  void EmitBuiltinAliases(raw_ostream &OS);1079};1080 1081const Type *EmitterBase::getType(const Init *I, const Type *Param) {1082  if (const auto *Dag = dyn_cast<DagInit>(I))1083    return getType(Dag, Param);1084  if (const auto *Def = dyn_cast<DefInit>(I))1085    return getType(Def->getDef(), Param);1086 1087  PrintFatalError("Could not convert this value into a type");1088}1089 1090const Type *EmitterBase::getType(const Record *R, const Type *Param) {1091  // Pass to a subfield of any wrapper records. We don't expect more than one1092  // of these: immediate operands are used as plain numbers rather than as1093  // llvm::Value, so it's meaningless to promote their type anyway.1094  if (R->isSubClassOf("Immediate"))1095    R = R->getValueAsDef("type");1096  else if (R->isSubClassOf("unpromoted"))1097    R = R->getValueAsDef("underlying_type");1098 1099  if (R->getName() == "Void")1100    return getVoidType();1101  if (R->isSubClassOf("PrimitiveType"))1102    return getScalarType(R);1103  if (R->isSubClassOf("ComplexType"))1104    return getType(R->getValueAsDag("spec"), Param);1105 1106  PrintFatalError(R->getLoc(), "Could not convert this record into a type");1107}1108 1109const Type *EmitterBase::getType(const DagInit *D, const Type *Param) {1110  // The meat of the getType system: types in the Tablegen are represented by a1111  // dag whose operators select sub-cases of this function.1112 1113  const Record *Op = cast<DefInit>(D->getOperator())->getDef();1114  if (!Op->isSubClassOf("ComplexTypeOp"))1115    PrintFatalError(1116        "Expected ComplexTypeOp as dag operator in type expression");1117 1118  if (Op->getName() == "CTO_Parameter") {1119    if (isa<VoidType>(Param))1120      PrintFatalError("Parametric type in unparametrised context");1121    return Param;1122  }1123 1124  if (Op->getName() == "CTO_Vec") {1125    const Type *Element = getType(D->getArg(0), Param);1126    if (D->getNumArgs() == 1) {1127      return getVectorType(cast<ScalarType>(Element));1128    } else {1129      const Type *ExistingVector = getType(D->getArg(1), Param);1130      return getVectorType(cast<ScalarType>(Element),1131                           cast<VectorType>(ExistingVector)->lanes());1132    }1133  }1134 1135  if (Op->getName() == "CTO_Pred") {1136    const Type *Element = getType(D->getArg(0), Param);1137    return getPredicateType(128 / Element->sizeInBits());1138  }1139 1140  if (Op->isSubClassOf("CTO_Tuple")) {1141    unsigned Registers = Op->getValueAsInt("n");1142    const Type *Element = getType(D->getArg(0), Param);1143    return getMultiVectorType(Registers, cast<VectorType>(Element));1144  }1145 1146  if (Op->isSubClassOf("CTO_Pointer")) {1147    const Type *Pointee = getType(D->getArg(0), Param);1148    return getPointerType(Pointee, Op->getValueAsBit("const"));1149  }1150 1151  if (Op->getName() == "CTO_CopyKind") {1152    const ScalarType *STSize = cast<ScalarType>(getType(D->getArg(0), Param));1153    const ScalarType *STKind = cast<ScalarType>(getType(D->getArg(1), Param));1154    for (const auto &kv : ScalarTypes) {1155      const ScalarType *RT = kv.second.get();1156      if (RT->kind() == STKind->kind() && RT->sizeInBits() == STSize->sizeInBits())1157        return RT;1158    }1159    PrintFatalError("Cannot find a type to satisfy CopyKind");1160  }1161 1162  if (Op->isSubClassOf("CTO_ScaleSize")) {1163    const ScalarType *STKind = cast<ScalarType>(getType(D->getArg(0), Param));1164    int Num = Op->getValueAsInt("num"), Denom = Op->getValueAsInt("denom");1165    unsigned DesiredSize = STKind->sizeInBits() * Num / Denom;1166    for (const auto &kv : ScalarTypes) {1167      const ScalarType *RT = kv.second.get();1168      if (RT->kind() == STKind->kind() && RT->sizeInBits() == DesiredSize)1169        return RT;1170    }1171    PrintFatalError("Cannot find a type to satisfy ScaleSize");1172  }1173 1174  PrintFatalError("Bad operator in type dag expression");1175}1176 1177Result::Ptr EmitterBase::getCodeForDag(const DagInit *D,1178                                       const Result::Scope &Scope,1179                                       const Type *Param) {1180  const Record *Op = cast<DefInit>(D->getOperator())->getDef();1181 1182  if (Op->getName() == "seq") {1183    Result::Scope SubScope = Scope;1184    Result::Ptr PrevV = nullptr;1185    for (unsigned i = 0, e = D->getNumArgs(); i < e; ++i) {1186      // We don't use getCodeForDagArg here, because the argument name1187      // has different semantics in a seq1188      Result::Ptr V =1189          getCodeForDag(cast<DagInit>(D->getArg(i)), SubScope, Param);1190      StringRef ArgName = D->getArgNameStr(i);1191      if (!ArgName.empty())1192        SubScope[std::string(ArgName)] = V;1193      if (PrevV)1194        V->setPredecessor(PrevV);1195      PrevV = V;1196    }1197    return PrevV;1198  } else if (Op->isSubClassOf("Type")) {1199    if (D->getNumArgs() != 1)1200      PrintFatalError("Type casts should have exactly one argument");1201    const Type *CastType = getType(Op, Param);1202    Result::Ptr Arg = getCodeForDagArg(D, 0, Scope, Param);1203    if (const auto *ST = dyn_cast<ScalarType>(CastType)) {1204      if (!ST->requiresFloat()) {1205        if (Arg->hasIntegerConstantValue())1206          return std::make_shared<IntLiteralResult>(1207              ST, Arg->integerConstantValue());1208        else1209          return std::make_shared<IntCastResult>(ST, Arg);1210      }1211    } else if (const auto *PT = dyn_cast<PointerType>(CastType)) {1212      return std::make_shared<PointerCastResult>(PT, Arg);1213    }1214    PrintFatalError("Unsupported type cast");1215  } else if (Op->getName() == "address") {1216    if (D->getNumArgs() != 2)1217      PrintFatalError("'address' should have two arguments");1218    Result::Ptr Arg = getCodeForDagArg(D, 0, Scope, Param);1219 1220    const Type *Ty = nullptr;1221    if (const auto *DI = dyn_cast<DagInit>(D->getArg(0)))1222      if (auto *PTy = dyn_cast<PointerType>(getType(DI->getOperator(), Param)))1223        Ty = PTy->getPointeeType();1224    if (!Ty)1225      PrintFatalError("'address' pointer argument should be a pointer");1226 1227    unsigned Alignment;1228    if (const auto *II = dyn_cast<IntInit>(D->getArg(1))) {1229      Alignment = II->getValue();1230    } else {1231      PrintFatalError("'address' alignment argument should be an integer");1232    }1233    return std::make_shared<AddressResult>(Arg, Ty, Alignment);1234  } else if (Op->getName() == "unsignedflag") {1235    if (D->getNumArgs() != 1)1236      PrintFatalError("unsignedflag should have exactly one argument");1237    const Record *TypeRec = cast<DefInit>(D->getArg(0))->getDef();1238    if (!TypeRec->isSubClassOf("Type"))1239      PrintFatalError("unsignedflag's argument should be a type");1240    if (const auto *ST = dyn_cast<ScalarType>(getType(TypeRec, Param))) {1241      return std::make_shared<IntLiteralResult>(1242        getScalarType("u32"), ST->kind() == ScalarTypeKind::UnsignedInt);1243    } else {1244      PrintFatalError("unsignedflag's argument should be a scalar type");1245    }1246  } else if (Op->getName() == "bitsize") {1247    if (D->getNumArgs() != 1)1248      PrintFatalError("bitsize should have exactly one argument");1249    const Record *TypeRec = cast<DefInit>(D->getArg(0))->getDef();1250    if (!TypeRec->isSubClassOf("Type"))1251      PrintFatalError("bitsize's argument should be a type");1252    if (const auto *ST = dyn_cast<ScalarType>(getType(TypeRec, Param))) {1253      return std::make_shared<IntLiteralResult>(getScalarType("u32"),1254                                                ST->sizeInBits());1255    } else {1256      PrintFatalError("bitsize's argument should be a scalar type");1257    }1258  } else {1259    std::vector<Result::Ptr> Args;1260    for (unsigned i = 0, e = D->getNumArgs(); i < e; ++i)1261      Args.push_back(getCodeForDagArg(D, i, Scope, Param));1262 1263    auto GenIRBuilderBase = [&](const Record *Op) -> Result::Ptr {1264      assert(Op->isSubClassOf("IRBuilderBase") &&1265             "Expected IRBuilderBase in GenIRBuilderBase\n");1266      std::set<unsigned> AddressArgs;1267      std::map<unsigned, std::string> IntegerArgs;1268      for (const Record *sp : Op->getValueAsListOfDefs("special_params")) {1269        unsigned Index = sp->getValueAsInt("index");1270        if (sp->isSubClassOf("IRBuilderAddrParam")) {1271          AddressArgs.insert(Index);1272        } else if (sp->isSubClassOf("IRBuilderIntParam")) {1273          IntegerArgs[Index] = std::string(sp->getValueAsString("type"));1274        }1275      }1276      return std::make_shared<IRBuilderResult>(Op->getValueAsString("prefix"),1277                                               Args, AddressArgs, IntegerArgs);1278    };1279    auto GenIRIntBase = [&](const Record *Op) -> Result::Ptr {1280      assert(Op->isSubClassOf("IRIntBase") &&1281             "Expected IRIntBase in GenIRIntBase\n");1282      std::vector<const Type *> ParamTypes;1283      for (const Record *RParam : Op->getValueAsListOfDefs("params"))1284        ParamTypes.push_back(getType(RParam, Param));1285      std::string IntName = std::string(Op->getValueAsString("intname"));1286      if (Op->getValueAsBit("appendKind"))1287        IntName += "_" + toLetter(cast<ScalarType>(Param)->kind());1288      return std::make_shared<IRIntrinsicResult>(IntName, ParamTypes, Args);1289    };1290 1291    if (Op->isSubClassOf("IRBuilderBase")) {1292      return GenIRBuilderBase(Op);1293    } else if (Op->isSubClassOf("IRIntBase")) {1294      return GenIRIntBase(Op);1295    } else if (Op->isSubClassOf("strictFPAlt")) {1296      auto StardardBuilder = Op->getValueAsDef("standard");1297      Result::Ptr Standard = StardardBuilder->isSubClassOf("IRBuilder")1298                                 ? GenIRBuilderBase(StardardBuilder)1299                                 : GenIRIntBase(StardardBuilder);1300      Result::Ptr StrictFp = GenIRIntBase(Op->getValueAsDef("strictfp"));1301      return std::make_shared<StrictFpAltResult>(Standard, StrictFp);1302    } else {1303      PrintFatalError("Unsupported dag node " + Op->getName());1304    }1305  }1306}1307 1308Result::Ptr EmitterBase::getCodeForDagArg(const DagInit *D, unsigned ArgNum,1309                                          const Result::Scope &Scope,1310                                          const Type *Param) {1311  const Init *Arg = D->getArg(ArgNum);1312  StringRef Name = D->getArgNameStr(ArgNum);1313 1314  if (!Name.empty()) {1315    if (!isa<UnsetInit>(Arg))1316      PrintFatalError(1317          "dag operator argument should not have both a value and a name");1318    auto it = Scope.find(Name);1319    if (it == Scope.end())1320      PrintFatalError("unrecognized variable name '" + Name + "'");1321    return it->second;1322  }1323 1324  // Sometimes the Arg is a bit. Prior to multiclass template argument1325  // checking, integers would sneak through the bit declaration,1326  // but now they really are bits.1327  if (const auto *BI = dyn_cast<BitInit>(Arg))1328    return std::make_shared<IntLiteralResult>(getScalarType("u32"),1329                                              BI->getValue());1330 1331  if (const auto *II = dyn_cast<IntInit>(Arg))1332    return std::make_shared<IntLiteralResult>(getScalarType("u32"),1333                                              II->getValue());1334 1335  if (const auto *DI = dyn_cast<DagInit>(Arg))1336    return getCodeForDag(DI, Scope, Param);1337 1338  if (const auto *DI = dyn_cast<DefInit>(Arg)) {1339    const Record *Rec = DI->getDef();1340    if (Rec->isSubClassOf("Type")) {1341      const Type *T = getType(Rec, Param);1342      return std::make_shared<TypeResult>(T);1343    }1344  }1345 1346  PrintError("bad DAG argument type for code generation");1347  PrintNote("DAG: " + D->getAsString());1348  if (const auto *Typed = dyn_cast<TypedInit>(Arg))1349    PrintNote("argument type: " + Typed->getType()->getAsString());1350  PrintFatalNote("argument number " + Twine(ArgNum) + ": " + Arg->getAsString());1351}1352 1353Result::Ptr EmitterBase::getCodeForArg(unsigned ArgNum, const Type *ArgType,1354                                       bool Promote, bool Immediate) {1355  Result::Ptr V = std::make_shared<BuiltinArgResult>(1356      ArgNum, isa<PointerType>(ArgType), Immediate);1357 1358  if (Promote) {1359    if (const auto *ST = dyn_cast<ScalarType>(ArgType)) {1360      if (ST->isInteger() && ST->sizeInBits() < 32)1361        V = std::make_shared<IntCastResult>(getScalarType("u32"), V);1362    } else if (const auto *PT = dyn_cast<PredicateType>(ArgType)) {1363      V = std::make_shared<IntCastResult>(getScalarType("u32"), V);1364      V = std::make_shared<IRIntrinsicResult>("arm_mve_pred_i2v",1365                                              std::vector<const Type *>{PT},1366                                              std::vector<Result::Ptr>{V});1367    }1368  }1369 1370  return V;1371}1372 1373ACLEIntrinsic::ACLEIntrinsic(EmitterBase &ME, const Record *R,1374                             const Type *Param)1375    : ReturnType(ME.getType(R->getValueAsDef("ret"), Param)) {1376  // Derive the intrinsic's full name, by taking the name of the1377  // Tablegen record (or override) and appending the suffix from its1378  // parameter type. (If the intrinsic is unparametrised, its1379  // parameter type will be given as Void, which returns the empty1380  // string for acleSuffix.)1381  StringRef BaseName =1382      (R->isSubClassOf("NameOverride") ? R->getValueAsString("basename")1383                                       : R->getName());1384  StringRef overrideLetter = R->getValueAsString("overrideKindLetter");1385  FullName =1386      (Twine(BaseName) + Param->acleSuffix(std::string(overrideLetter))).str();1387 1388  // Derive the intrinsic's polymorphic name, by removing components from the1389  // full name as specified by its 'pnt' member ('polymorphic name type'),1390  // which indicates how many type suffixes to remove, and any other piece of1391  // the name that should be removed.1392  const Record *PolymorphicNameType = R->getValueAsDef("pnt");1393  SmallVector<StringRef, 8> NameParts;1394  StringRef(FullName).split(NameParts, '_');1395  for (unsigned i = 0, e = PolymorphicNameType->getValueAsInt(1396                           "NumTypeSuffixesToDiscard");1397       i < e; ++i)1398    NameParts.pop_back();1399  if (!PolymorphicNameType->isValueUnset("ExtraSuffixToDiscard")) {1400    StringRef ExtraSuffix =1401        PolymorphicNameType->getValueAsString("ExtraSuffixToDiscard");1402    auto it = NameParts.end();1403    while (it != NameParts.begin()) {1404      --it;1405      if (*it == ExtraSuffix) {1406        NameParts.erase(it);1407        break;1408      }1409    }1410  }1411  ShortName = join(std::begin(NameParts), std::end(NameParts), "_");1412 1413  BuiltinExtension = R->getValueAsString("builtinExtension");1414 1415  PolymorphicOnly = R->getValueAsBit("polymorphicOnly");1416  NonEvaluating = R->getValueAsBit("nonEvaluating");1417  HeaderOnly = R->getValueAsBit("headerOnly");1418 1419  // Process the intrinsic's argument list.1420  const DagInit *ArgsDag = R->getValueAsDag("args");1421  Result::Scope Scope;1422  for (unsigned i = 0, e = ArgsDag->getNumArgs(); i < e; ++i) {1423    const Init *TypeInit = ArgsDag->getArg(i);1424 1425    bool Promote = true;1426    if (const auto *TypeDI = dyn_cast<DefInit>(TypeInit))1427      if (TypeDI->getDef()->isSubClassOf("unpromoted"))1428        Promote = false;1429 1430    // Work out the type of the argument, for use in the function prototype in1431    // the header file.1432    const Type *ArgType = ME.getType(TypeInit, Param);1433    ArgTypes.push_back(ArgType);1434 1435    // If the argument is a subclass of Immediate, record the details about1436    // what values it can take, for Sema checking.1437    bool Immediate = false;1438    if (const auto *TypeDI = dyn_cast<DefInit>(TypeInit)) {1439      const Record *TypeRec = TypeDI->getDef();1440      if (TypeRec->isSubClassOf("Immediate")) {1441        Immediate = true;1442 1443        const Record *Bounds = TypeRec->getValueAsDef("bounds");1444        ImmediateArg &IA = ImmediateArgs[i];1445        if (Bounds->isSubClassOf("IB_ConstRange")) {1446          IA.boundsType = ImmediateArg::BoundsType::ExplicitRange;1447          IA.i1 = Bounds->getValueAsInt("lo");1448          IA.i2 = Bounds->getValueAsInt("hi");1449        } else if (Bounds->getName() == "IB_UEltValue") {1450          IA.boundsType = ImmediateArg::BoundsType::UInt;1451          IA.i1 = Param->sizeInBits();1452        } else if (Bounds->getName() == "IB_LaneIndex") {1453          IA.boundsType = ImmediateArg::BoundsType::ExplicitRange;1454          IA.i1 = 0;1455          IA.i2 = 128 / Param->sizeInBits() - 1;1456        } else if (Bounds->isSubClassOf("IB_EltBit")) {1457          IA.boundsType = ImmediateArg::BoundsType::ExplicitRange;1458          IA.i1 = Bounds->getValueAsInt("base");1459          const Type *T = ME.getType(Bounds->getValueAsDef("type"), Param);1460          IA.i2 = IA.i1 + T->sizeInBits() - 1;1461        } else {1462          PrintFatalError("unrecognised ImmediateBounds subclass");1463        }1464 1465        IA.ArgType = ArgType;1466 1467        if (!TypeRec->isValueUnset("extra")) {1468          IA.ExtraCheckType = TypeRec->getValueAsString("extra");1469          if (!TypeRec->isValueUnset("extraarg"))1470            IA.ExtraCheckArgs = TypeRec->getValueAsString("extraarg");1471        }1472      }1473    }1474 1475    // The argument will usually have a name in the arguments dag, which goes1476    // into the variable-name scope that the code gen will refer to.1477    StringRef ArgName = ArgsDag->getArgNameStr(i);1478    if (!ArgName.empty())1479      Scope[std::string(ArgName)] =1480          ME.getCodeForArg(i, ArgType, Promote, Immediate);1481  }1482 1483  // Finally, go through the codegen dag and translate it into a Result object1484  // (with an arbitrary DAG of depended-on Results hanging off it).1485  const DagInit *CodeDag = R->getValueAsDag("codegen");1486  const Record *MainOp = cast<DefInit>(CodeDag->getOperator())->getDef();1487  if (MainOp->isSubClassOf("CustomCodegen")) {1488    // Or, if it's the special case of CustomCodegen, just accumulate1489    // a list of parameters we're going to assign to variables before1490    // breaking from the loop.1491    CustomCodeGenArgs["CustomCodeGenType"] =1492        (Twine("CustomCodeGen::") + MainOp->getValueAsString("type")).str();1493    for (unsigned i = 0, e = CodeDag->getNumArgs(); i < e; ++i) {1494      StringRef Name = CodeDag->getArgNameStr(i);1495      if (Name.empty()) {1496        PrintFatalError("Operands to CustomCodegen should have names");1497      } else if (const auto *II = dyn_cast<IntInit>(CodeDag->getArg(i))) {1498        CustomCodeGenArgs[std::string(Name)] = itostr(II->getValue());1499      } else if (const auto *SI = dyn_cast<StringInit>(CodeDag->getArg(i))) {1500        CustomCodeGenArgs[std::string(Name)] = std::string(SI->getValue());1501      } else {1502        PrintFatalError("Operands to CustomCodegen should be integers");1503      }1504    }1505  } else {1506    Code = ME.getCodeForDag(CodeDag, Scope, Param);1507  }1508}1509 1510EmitterBase::EmitterBase(const RecordKeeper &Records) {1511  // Construct the whole EmitterBase.1512 1513  // First, look up all the instances of PrimitiveType. This gives us the list1514  // of vector typedefs we have to put in arm_mve.h, and also allows us to1515  // collect all the useful ScalarType instances into a big list so that we can1516  // use it for operations such as 'find the unsigned version of this signed1517  // integer type'.1518  for (const Record *R : Records.getAllDerivedDefinitions("PrimitiveType"))1519    ScalarTypes[std::string(R->getName())] = std::make_unique<ScalarType>(R);1520 1521  // Now go through the instances of Intrinsic, and for each one, iterate1522  // through its list of type parameters making an ACLEIntrinsic for each one.1523  for (const Record *R : Records.getAllDerivedDefinitions("Intrinsic")) {1524    for (const Record *RParam : R->getValueAsListOfDefs("params")) {1525      const Type *Param = getType(RParam, getVoidType());1526      auto Intrinsic = std::make_unique<ACLEIntrinsic>(*this, R, Param);1527      ACLEIntrinsics[Intrinsic->fullName()] = std::move(Intrinsic);1528    }1529  }1530}1531 1532/// A wrapper on raw_string_ostream that contains its own buffer rather than1533/// having to point it at one elsewhere. (In other words, it works just like1534/// std::ostringstream; also, this makes it convenient to declare a whole array1535/// of them at once.)1536///1537/// We have to set this up using multiple inheritance, to ensure that the1538/// string member has been constructed before raw_string_ostream's constructor1539/// is given a pointer to it.1540class string_holder {1541protected:1542  std::string S;1543};1544class raw_self_contained_string_ostream : private string_holder,1545                                          public raw_string_ostream {1546public:1547  raw_self_contained_string_ostream() : raw_string_ostream(S) {}1548};1549 1550const char LLVMLicenseHeader[] =1551    " *\n"1552    " *\n"1553    " * Part of the LLVM Project, under the Apache License v2.0 with LLVM"1554    " Exceptions.\n"1555    " * See https://llvm.org/LICENSE.txt for license information.\n"1556    " * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception\n"1557    " *\n"1558    " *===-----------------------------------------------------------------"1559    "------===\n"1560    " */\n"1561    "\n";1562 1563// Machinery for the grouping of intrinsics by similar codegen.1564//1565// The general setup is that 'MergeableGroup' stores the things that a set of1566// similarly shaped intrinsics have in common: the text of their code1567// generation, and the number and type of their parameter variables.1568// MergeableGroup is the key in a std::map whose value is a set of1569// OutputIntrinsic, which stores the ways in which a particular intrinsic1570// specializes the MergeableGroup's generic description: the function name and1571// the _values_ of the parameter variables.1572 1573struct ComparableStringVector : std::vector<std::string> {1574  // Infrastructure: a derived class of vector<string> which comes with an1575  // ordering, so that it can be used as a key in maps and an element in sets.1576  // There's no requirement on the ordering beyond being deterministic.1577  bool operator<(const ComparableStringVector &rhs) const {1578    if (size() != rhs.size())1579      return size() < rhs.size();1580    for (size_t i = 0, e = size(); i < e; ++i)1581      if ((*this)[i] != rhs[i])1582        return (*this)[i] < rhs[i];1583    return false;1584  }1585};1586 1587struct OutputIntrinsic {1588  const ACLEIntrinsic *Int;1589  std::string Name;1590  ComparableStringVector ParamValues;1591  bool operator<(const OutputIntrinsic &rhs) const {1592    return std::tie(Name, ParamValues) < std::tie(rhs.Name, rhs.ParamValues);1593  }1594};1595struct MergeableGroup {1596  std::string Code;1597  ComparableStringVector ParamTypes;1598  bool operator<(const MergeableGroup &rhs) const {1599    return std::tie(Code, ParamTypes) < std::tie(rhs.Code, rhs.ParamTypes);1600  }1601};1602 1603void EmitterBase::EmitBuiltinCG(raw_ostream &OS) {1604  // Pass 1: generate code for all the intrinsics as if every type or constant1605  // that can possibly be abstracted out into a parameter variable will be.1606  // This identifies the sets of intrinsics we'll group together into a single1607  // piece of code generation.1608 1609  std::map<MergeableGroup, std::set<OutputIntrinsic>> MergeableGroupsPrelim;1610 1611  for (const auto &kv : ACLEIntrinsics) {1612    const ACLEIntrinsic &Int = *kv.second;1613    if (Int.headerOnly())1614      continue;1615 1616    MergeableGroup MG;1617    OutputIntrinsic OI;1618 1619    OI.Int = &Int;1620    OI.Name = Int.fullName();1621    CodeGenParamAllocator ParamAllocPrelim{&MG.ParamTypes, &OI.ParamValues};1622    raw_string_ostream OS(MG.Code);1623    Int.genCode(OS, ParamAllocPrelim, 1);1624 1625    MergeableGroupsPrelim[MG].insert(OI);1626  }1627 1628  // Pass 2: for each of those groups, optimize the parameter variable set by1629  // eliminating 'parameters' that are the same for all intrinsics in the1630  // group, and merging together pairs of parameter variables that take the1631  // same values as each other for all intrinsics in the group.1632 1633  std::map<MergeableGroup, std::set<OutputIntrinsic>> MergeableGroups;1634 1635  for (const auto &kv : MergeableGroupsPrelim) {1636    const MergeableGroup &MG = kv.first;1637    std::vector<int> ParamNumbers;1638    std::map<ComparableStringVector, int> ParamNumberMap;1639 1640    // Loop over the parameters for this group.1641    for (size_t i = 0, e = MG.ParamTypes.size(); i < e; ++i) {1642      // Is this parameter the same for all intrinsics in the group?1643      const OutputIntrinsic &OI_first = *kv.second.begin();1644      bool Constant = all_of(kv.second, [&](const OutputIntrinsic &OI) {1645        return OI.ParamValues[i] == OI_first.ParamValues[i];1646      });1647 1648      // If so, record it as -1, meaning 'no parameter variable needed'. Then1649      // the corresponding call to allocParam in pass 2 will not generate a1650      // variable at all, and just use the value inline.1651      if (Constant) {1652        ParamNumbers.push_back(-1);1653        continue;1654      }1655 1656      // Otherwise, make a list of the values this parameter takes for each1657      // intrinsic, and see if that value vector matches anything we already1658      // have. We also record the parameter type, so that we don't accidentally1659      // match up two parameter variables with different types. (Not that1660      // there's much chance of them having textually equivalent values, but in1661      // _principle_ it could happen.)1662      ComparableStringVector key;1663      key.push_back(MG.ParamTypes[i]);1664      for (const auto &OI : kv.second)1665        key.push_back(OI.ParamValues[i]);1666 1667      // Obtain a new parameter variable if we don't have one.1668      int ParamNum =1669          ParamNumberMap.try_emplace(key, ParamNumberMap.size()).first->second;1670      ParamNumbers.push_back(ParamNum);1671    }1672 1673    // Now we're ready to do the pass 2 code generation, which will emit the1674    // reduced set of parameter variables we've just worked out.1675 1676    for (const auto &OI_prelim : kv.second) {1677      const ACLEIntrinsic *Int = OI_prelim.Int;1678 1679      MergeableGroup MG;1680      OutputIntrinsic OI;1681 1682      OI.Int = OI_prelim.Int;1683      OI.Name = OI_prelim.Name;1684      CodeGenParamAllocator ParamAlloc{&MG.ParamTypes, &OI.ParamValues,1685                                       &ParamNumbers};1686      raw_string_ostream OS(MG.Code);1687      Int->genCode(OS, ParamAlloc, 2);1688 1689      MergeableGroups[MG].insert(OI);1690    }1691  }1692 1693  // Output the actual C++ code.1694 1695  for (const auto &kv : MergeableGroups) {1696    const MergeableGroup &MG = kv.first;1697 1698    // List of case statements in the main switch on BuiltinID, and an open1699    // brace.1700    const char *prefix = "";1701    for (const auto &OI : kv.second) {1702      OS << prefix << "case ARM::BI__builtin_arm_" << OI.Int->builtinExtension()1703         << "_" << OI.Name << ":";1704 1705      prefix = "\n";1706    }1707    OS << " {\n";1708 1709    if (!MG.ParamTypes.empty()) {1710      // If we've got some parameter variables, then emit their declarations...1711      for (size_t i = 0, e = MG.ParamTypes.size(); i < e; ++i) {1712        StringRef Type = MG.ParamTypes[i];1713        OS << "  " << Type;1714        if (!Type.ends_with("*"))1715          OS << " ";1716        OS << " Param" << utostr(i) << ";\n";1717      }1718 1719      // ... and an inner switch on BuiltinID that will fill them in with each1720      // individual intrinsic's values.1721      OS << "  switch (BuiltinID) {\n";1722      for (const auto &OI : kv.second) {1723        OS << "  case ARM::BI__builtin_arm_" << OI.Int->builtinExtension()1724           << "_" << OI.Name << ":\n";1725        for (size_t i = 0, e = MG.ParamTypes.size(); i < e; ++i)1726          OS << "    Param" << utostr(i) << " = static_cast<"1727             << MG.ParamTypes[i] << ">(" << OI.ParamValues[i] << ");\n";1728        OS << "    break;\n";1729      }1730      OS << "  }\n";1731    }1732 1733    // And finally, output the code, and close the outer pair of braces. (The1734    // code will always end with a 'return' statement, so we need not insert a1735    // 'break' here.)1736    OS << MG.Code << "}\n";1737  }1738}1739 1740void EmitterBase::EmitBuiltinAliases(raw_ostream &OS) {1741  // Build a sorted table of:1742  // - intrinsic id number1743  // - full name1744  // - polymorphic name or -11745  StringToOffsetTable StringTable;1746  OS << "static const IntrinToName MapData[] = {\n";1747  for (const auto &kv : ACLEIntrinsics) {1748    const ACLEIntrinsic &Int = *kv.second;1749    if (Int.headerOnly())1750      continue;1751    int32_t ShortNameOffset =1752        Int.polymorphic() ? StringTable.GetOrAddStringOffset(Int.shortName())1753                          : -1;1754    OS << "  { ARM::BI__builtin_arm_" << Int.builtinExtension() << "_"1755       << Int.fullName() << ", "1756       << StringTable.GetOrAddStringOffset(Int.fullName()) << ", "1757       << ShortNameOffset << "},\n";1758  }1759  OS << "};\n\n";1760 1761  OS << "ArrayRef<IntrinToName> Map(MapData);\n\n";1762 1763  OS << "static const char IntrinNames[] = {\n";1764  StringTable.EmitString(OS);1765  OS << "};\n\n";1766}1767 1768void EmitterBase::GroupSemaChecks(1769    std::map<std::string, std::set<std::string>> &Checks) {1770  for (const auto &kv : ACLEIntrinsics) {1771    const ACLEIntrinsic &Int = *kv.second;1772    if (Int.headerOnly())1773      continue;1774    std::string Check = Int.genSema();1775    if (!Check.empty())1776      Checks[Check].insert(Int.fullName());1777  }1778}1779 1780// -----------------------------------------------------------------------------1781// The class used for generating arm_mve.h and related Clang bits1782//1783 1784class MveEmitter : public EmitterBase {1785public:1786  MveEmitter(const RecordKeeper &Records) : EmitterBase(Records) {}1787  void EmitHeader(raw_ostream &OS) override;1788  void EmitBuiltinDef(raw_ostream &OS) override;1789  void EmitBuiltinSema(raw_ostream &OS) override;1790};1791 1792void MveEmitter::EmitHeader(raw_ostream &OS) {1793  // Accumulate pieces of the header file that will be enabled under various1794  // different combinations of #ifdef. The index into parts[] is made up of1795  // the following bit flags.1796  constexpr unsigned Float = 1;1797  constexpr unsigned UseUserNamespace = 2;1798 1799  constexpr unsigned NumParts = 4;1800  raw_self_contained_string_ostream parts[NumParts];1801 1802  // Write typedefs for all the required vector types, and a few scalar1803  // types that don't already have the name we want them to have.1804 1805  parts[0] << "typedef uint16_t mve_pred16_t;\n";1806  parts[Float] << "typedef __fp16 float16_t;\n"1807                  "typedef float float32_t;\n";1808  for (const auto &kv : ScalarTypes) {1809    const ScalarType *ST = kv.second.get();1810    if (ST->hasNonstandardName())1811      continue;1812    raw_ostream &OS = parts[ST->requiresFloat() ? Float : 0];1813    const VectorType *VT = getVectorType(ST);1814 1815    OS << "typedef __attribute__((__neon_vector_type__(" << VT->lanes()1816       << "), __clang_arm_mve_strict_polymorphism)) " << ST->cName() << " "1817       << VT->cName() << ";\n";1818 1819    // Every vector type also comes with a pair of multi-vector types for1820    // the VLD2 and VLD4 instructions.1821    for (unsigned n = 2; n <= 4; n += 2) {1822      const MultiVectorType *MT = getMultiVectorType(n, VT);1823      OS << "typedef struct { " << VT->cName() << " val[" << n << "]; } "1824         << MT->cName() << ";\n";1825    }1826  }1827  parts[0] << "\n";1828  parts[Float] << "\n";1829 1830  // Write declarations for all the intrinsics.1831 1832  for (const auto &kv : ACLEIntrinsics) {1833    const ACLEIntrinsic &Int = *kv.second;1834 1835    // We generate each intrinsic twice, under its full unambiguous1836    // name and its shorter polymorphic name (if the latter exists).1837    for (bool Polymorphic : {false, true}) {1838      if (Polymorphic && !Int.polymorphic())1839        continue;1840      if (!Polymorphic && Int.polymorphicOnly())1841        continue;1842 1843      // We also generate each intrinsic under a name like __arm_vfooq1844      // (which is in C language implementation namespace, so it's1845      // safe to define in any conforming user program) and a shorter1846      // one like vfooq (which is in user namespace, so a user might1847      // reasonably have used it for something already). If so, they1848      // can #define __ARM_MVE_PRESERVE_USER_NAMESPACE before1849      // including the header, which will suppress the shorter names1850      // and leave only the implementation-namespace ones. Then they1851      // have to write __arm_vfooq everywhere, of course.1852 1853      for (bool UserNamespace : {false, true}) {1854        raw_ostream &OS = parts[(Int.requiresFloat() ? Float : 0) |1855                                (UserNamespace ? UseUserNamespace : 0)];1856 1857        // Make the name of the function in this declaration.1858 1859        std::string FunctionName =1860            Polymorphic ? Int.shortName() : Int.fullName();1861        if (!UserNamespace)1862          FunctionName = "__arm_" + FunctionName;1863 1864        // Make strings for the types involved in the function's1865        // prototype.1866 1867        std::string RetTypeName = Int.returnType()->cName();1868        if (!StringRef(RetTypeName).ends_with("*"))1869          RetTypeName += " ";1870 1871        std::vector<std::string> ArgTypeNames;1872        for (const Type *ArgTypePtr : Int.argTypes())1873          ArgTypeNames.push_back(ArgTypePtr->cName());1874        std::string ArgTypesString =1875            join(std::begin(ArgTypeNames), std::end(ArgTypeNames), ", ");1876 1877        // Emit the actual declaration. All these functions are1878        // declared 'static inline' without a body, which is fine1879        // provided clang recognizes them as builtins, and has the1880        // effect that this type signature is used in place of the one1881        // that Builtins.td didn't provide. That's how we can get1882        // structure types that weren't defined until this header was1883        // included to be part of the type signature of a builtin that1884        // was known to clang already.1885        //1886        // The declarations use __attribute__(__clang_arm_builtin_alias),1887        // so that each function declared will be recognized as the1888        // appropriate MVE builtin in spite of its user-facing name.1889        //1890        // (That's better than making them all wrapper functions,1891        // partly because it avoids any compiler error message citing1892        // the wrapper function definition instead of the user's code,1893        // and mostly because some MVE intrinsics have arguments1894        // required to be compile-time constants, and that property1895        // can't be propagated through a wrapper function. It can be1896        // propagated through a macro, but macros can't be overloaded1897        // on argument types very easily - you have to use _Generic,1898        // which makes error messages very confusing when the user1899        // gets it wrong.)1900        //1901        // Finally, the polymorphic versions of the intrinsics are1902        // also defined with __attribute__(overloadable), so that when1903        // the same name is defined with several type signatures, the1904        // right thing happens. Each one of the overloaded1905        // declarations is given a different builtin id, which1906        // has exactly the effect we want: first clang resolves the1907        // overload to the right function, then it knows which builtin1908        // it's referring to, and then the Sema checking for that1909        // builtin can check further things like the constant1910        // arguments.1911        //1912        // One more subtlety is the newline just before the return1913        // type name. That's a cosmetic tweak to make the error1914        // messages legible if the user gets the types wrong in a call1915        // to a polymorphic function: this way, clang will print just1916        // the _final_ line of each declaration in the header, to show1917        // the type signatures that would have been legal. So all the1918        // confusing machinery with __attribute__ is left out of the1919        // error message, and the user sees something that's more or1920        // less self-documenting: "here's a list of actually readable1921        // type signatures for vfooq(), and here's why each one didn't1922        // match your call".1923 1924        OS << "static __inline__ __attribute__(("1925           << (Polymorphic ? "__overloadable__, " : "")1926           << "__clang_arm_builtin_alias(__builtin_arm_mve_" << Int.fullName()1927           << ")))\n"1928           << RetTypeName << FunctionName << "(" << ArgTypesString << ");\n";1929      }1930    }1931  }1932  for (auto &part : parts)1933    part << "\n";1934 1935  // Now we've finished accumulating bits and pieces into the parts[] array.1936  // Put it all together to write the final output file.1937 1938  OS << "/*===---- arm_mve.h - ARM MVE intrinsics "1939        "-----------------------------------===\n"1940     << LLVMLicenseHeader1941     << "#ifndef __ARM_MVE_H\n"1942        "#define __ARM_MVE_H\n"1943        "\n"1944        "#if !__ARM_FEATURE_MVE\n"1945        "#error \"MVE support not enabled\"\n"1946        "#endif\n"1947        "\n"1948        "#include <stdint.h>\n"1949        "\n"1950        "#ifdef __cplusplus\n"1951        "extern \"C\" {\n"1952        "#endif\n"1953        "\n";1954 1955  for (size_t i = 0; i < NumParts; ++i) {1956    std::vector<std::string> conditions;1957    if (i & Float)1958      conditions.push_back("(__ARM_FEATURE_MVE & 2)");1959    if (i & UseUserNamespace)1960      conditions.push_back("(!defined __ARM_MVE_PRESERVE_USER_NAMESPACE)");1961 1962    std::string condition =1963        join(std::begin(conditions), std::end(conditions), " && ");1964    if (!condition.empty())1965      OS << "#if " << condition << "\n\n";1966    OS << parts[i].str();1967    if (!condition.empty())1968      OS << "#endif /* " << condition << " */\n\n";1969  }1970 1971  OS << "#ifdef __cplusplus\n"1972        "} /* extern \"C\" */\n"1973        "#endif\n"1974        "\n"1975        "#endif /* __ARM_MVE_H */\n";1976}1977 1978void MveEmitter::EmitBuiltinDef(raw_ostream &OS) {1979  llvm::StringToOffsetTable Table;1980  Table.GetOrAddStringOffset("n");1981  Table.GetOrAddStringOffset("nt");1982  Table.GetOrAddStringOffset("ntu");1983  Table.GetOrAddStringOffset("vi.");1984 1985  for (const auto &[_, Int] : ACLEIntrinsics)1986    Table.GetOrAddStringOffset(Int->fullName());1987 1988  std::map<std::string, ACLEIntrinsic *> ShortNameIntrinsics;1989  for (const auto &[_, Int] : ACLEIntrinsics) {1990    if (!Int->polymorphic())1991      continue;1992 1993    StringRef Name = Int->shortName();1994    if (ShortNameIntrinsics.insert({Name.str(), Int.get()}).second)1995      Table.GetOrAddStringOffset(Name);1996  }1997 1998  OS << "#ifdef GET_MVE_BUILTIN_ENUMERATORS\n";1999  for (const auto &[_, Int] : ACLEIntrinsics) {2000    OS << "  BI__builtin_arm_mve_" << Int->fullName() << ",\n";2001  }2002  for (const auto &[Name, _] : ShortNameIntrinsics) {2003    OS << "  BI__builtin_arm_mve_" << Name << ",\n";2004  }2005  OS << "#endif // GET_MVE_BUILTIN_ENUMERATORS\n\n";2006 2007  OS << "#ifdef GET_MVE_BUILTIN_STR_TABLE\n";2008  Table.EmitStringTableDef(OS, "BuiltinStrings");2009  OS << "#endif // GET_MVE_BUILTIN_STR_TABLE\n\n";2010 2011  OS << "#ifdef GET_MVE_BUILTIN_INFOS\n";2012  for (const auto &[_, Int] : ACLEIntrinsics) {2013    OS << "    Builtin::Info{Builtin::Info::StrOffsets{"2014       << Table.GetStringOffset(Int->fullName()) << " /* " << Int->fullName()2015       << " */, " << Table.GetStringOffset("") << ", "2016       << Table.GetStringOffset("n") << " /* n */}},\n";2017  }2018  for (const auto &[Name, Int] : ShortNameIntrinsics) {2019    StringRef Attrs = Int->nonEvaluating() ? "ntu" : "nt";2020    OS << "    Builtin::Info{Builtin::Info::StrOffsets{"2021       << Table.GetStringOffset(Name) << " /* " << Name << " */, "2022       << Table.GetStringOffset("vi.") << " /* vi. */, "2023       << Table.GetStringOffset(Attrs) << " /* " << Attrs << " */}},\n";2024  }2025  OS << "#endif // GET_MVE_BUILTIN_INFOS\n\n";2026}2027 2028void MveEmitter::EmitBuiltinSema(raw_ostream &OS) {2029  std::map<std::string, std::set<std::string>> Checks;2030  GroupSemaChecks(Checks);2031 2032  for (const auto &kv : Checks) {2033    for (StringRef Name : kv.second)2034      OS << "case ARM::BI__builtin_arm_mve_" << Name << ":\n";2035    OS << "  return " << kv.first;2036  }2037}2038 2039// -----------------------------------------------------------------------------2040// Class that describes an ACLE intrinsic implemented as a macro.2041//2042// This class is used when the intrinsic is polymorphic in 2 or 3 types, but we2043// want to avoid a combinatorial explosion by reinterpreting the arguments to2044// fixed types.2045 2046class FunctionMacro {2047  std::vector<StringRef> Params;2048  StringRef Definition;2049 2050public:2051  FunctionMacro(const Record &R);2052 2053  const std::vector<StringRef> &getParams() const { return Params; }2054  StringRef getDefinition() const { return Definition; }2055};2056 2057FunctionMacro::FunctionMacro(const Record &R) {2058  Params = R.getValueAsListOfStrings("params");2059  Definition = R.getValueAsString("definition");2060}2061 2062// -----------------------------------------------------------------------------2063// The class used for generating arm_cde.h and related Clang bits2064//2065 2066class CdeEmitter : public EmitterBase {2067  std::map<StringRef, FunctionMacro> FunctionMacros;2068 2069public:2070  CdeEmitter(const RecordKeeper &Records);2071  void EmitHeader(raw_ostream &OS) override;2072  void EmitBuiltinDef(raw_ostream &OS) override;2073  void EmitBuiltinSema(raw_ostream &OS) override;2074};2075 2076CdeEmitter::CdeEmitter(const RecordKeeper &Records) : EmitterBase(Records) {2077  for (const Record *R : Records.getAllDerivedDefinitions("FunctionMacro"))2078    FunctionMacros.emplace(R->getName(), FunctionMacro(*R));2079}2080 2081void CdeEmitter::EmitHeader(raw_ostream &OS) {2082  // Accumulate pieces of the header file that will be enabled under various2083  // different combinations of #ifdef. The index into parts[] is one of the2084  // following:2085  constexpr unsigned None = 0;2086  constexpr unsigned MVE = 1;2087  constexpr unsigned MVEFloat = 2;2088 2089  constexpr unsigned NumParts = 3;2090  raw_self_contained_string_ostream parts[NumParts];2091 2092  // Write typedefs for all the required vector types, and a few scalar2093  // types that don't already have the name we want them to have.2094 2095  parts[MVE] << "typedef uint16_t mve_pred16_t;\n";2096  parts[MVEFloat] << "typedef __fp16 float16_t;\n"2097                     "typedef float float32_t;\n";2098  for (const auto &kv : ScalarTypes) {2099    const ScalarType *ST = kv.second.get();2100    if (ST->hasNonstandardName())2101      continue;2102    // We don't have float64x2_t2103    if (ST->kind() == ScalarTypeKind::Float && ST->sizeInBits() == 64)2104      continue;2105    raw_ostream &OS = parts[ST->requiresFloat() ? MVEFloat : MVE];2106    const VectorType *VT = getVectorType(ST);2107 2108    OS << "typedef __attribute__((__neon_vector_type__(" << VT->lanes()2109       << "), __clang_arm_mve_strict_polymorphism)) " << ST->cName() << " "2110       << VT->cName() << ";\n";2111  }2112  parts[MVE] << "\n";2113  parts[MVEFloat] << "\n";2114 2115  // Write declarations for all the intrinsics.2116 2117  for (const auto &kv : ACLEIntrinsics) {2118    const ACLEIntrinsic &Int = *kv.second;2119 2120    // We generate each intrinsic twice, under its full unambiguous2121    // name and its shorter polymorphic name (if the latter exists).2122    for (bool Polymorphic : {false, true}) {2123      if (Polymorphic && !Int.polymorphic())2124        continue;2125      if (!Polymorphic && Int.polymorphicOnly())2126        continue;2127 2128      raw_ostream &OS =2129          parts[Int.requiresFloat() ? MVEFloat2130                                    : Int.requiresMVE() ? MVE : None];2131 2132      // Make the name of the function in this declaration.2133      std::string FunctionName =2134          "__arm_" + (Polymorphic ? Int.shortName() : Int.fullName());2135 2136      // Make strings for the types involved in the function's2137      // prototype.2138      std::string RetTypeName = Int.returnType()->cName();2139      if (!StringRef(RetTypeName).ends_with("*"))2140        RetTypeName += " ";2141 2142      std::vector<std::string> ArgTypeNames;2143      for (const Type *ArgTypePtr : Int.argTypes())2144        ArgTypeNames.push_back(ArgTypePtr->cName());2145      std::string ArgTypesString =2146          join(std::begin(ArgTypeNames), std::end(ArgTypeNames), ", ");2147 2148      // Emit the actual declaration. See MveEmitter::EmitHeader for detailed2149      // comments2150      OS << "static __inline__ __attribute__(("2151         << (Polymorphic ? "__overloadable__, " : "")2152         << "__clang_arm_builtin_alias(__builtin_arm_" << Int.builtinExtension()2153         << "_" << Int.fullName() << ")))\n"2154         << RetTypeName << FunctionName << "(" << ArgTypesString << ");\n";2155    }2156  }2157 2158  for (const auto &kv : FunctionMacros) {2159    StringRef Name = kv.first;2160    const FunctionMacro &FM = kv.second;2161 2162    raw_ostream &OS = parts[MVE];2163    OS << "#define "2164       << "__arm_" << Name << "(" << join(FM.getParams(), ", ") << ") "2165       << FM.getDefinition() << "\n";2166  }2167 2168  for (auto &part : parts)2169    part << "\n";2170 2171  // Now we've finished accumulating bits and pieces into the parts[] array.2172  // Put it all together to write the final output file.2173 2174  OS << "/*===---- arm_cde.h - ARM CDE intrinsics "2175        "-----------------------------------===\n"2176     << LLVMLicenseHeader2177     << "#ifndef __ARM_CDE_H\n"2178        "#define __ARM_CDE_H\n"2179        "\n"2180        "#if !__ARM_FEATURE_CDE\n"2181        "#error \"CDE support not enabled\"\n"2182        "#endif\n"2183        "\n"2184        "#include <stdint.h>\n"2185        "\n"2186        "#ifdef __cplusplus\n"2187        "extern \"C\" {\n"2188        "#endif\n"2189        "\n";2190 2191  for (size_t i = 0; i < NumParts; ++i) {2192    std::string condition;2193    if (i == MVEFloat)2194      condition = "__ARM_FEATURE_MVE & 2";2195    else if (i == MVE)2196      condition = "__ARM_FEATURE_MVE";2197 2198    if (!condition.empty())2199      OS << "#if " << condition << "\n\n";2200    OS << parts[i].str();2201    if (!condition.empty())2202      OS << "#endif /* " << condition << " */\n\n";2203  }2204 2205  OS << "#ifdef __cplusplus\n"2206        "} /* extern \"C\" */\n"2207        "#endif\n"2208        "\n"2209        "#endif /* __ARM_CDE_H */\n";2210}2211 2212void CdeEmitter::EmitBuiltinDef(raw_ostream &OS) {2213  llvm::StringToOffsetTable Table;2214  Table.GetOrAddStringOffset("ncU");2215 2216  for (const auto &[_, Int] : ACLEIntrinsics)2217    if (!Int->headerOnly())2218      Table.GetOrAddStringOffset(Int->fullName());2219 2220  OS << "#ifdef GET_CDE_BUILTIN_ENUMERATORS\n";2221  for (const auto &[_, Int] : ACLEIntrinsics)2222    if (!Int->headerOnly())2223      OS << "  BI__builtin_arm_cde_" << Int->fullName() << ",\n";2224  OS << "#endif // GET_CDE_BUILTIN_ENUMERATORS\n\n";2225 2226  OS << "#ifdef GET_CDE_BUILTIN_STR_TABLE\n";2227  Table.EmitStringTableDef(OS, "BuiltinStrings");2228  OS << "#endif // GET_CDE_BUILTIN_STR_TABLE\n\n";2229 2230  OS << "#ifdef GET_CDE_BUILTIN_INFOS\n";2231  for (const auto &[_, Int] : ACLEIntrinsics)2232    if (!Int->headerOnly())2233      OS << "    Builtin::Info{Builtin::Info::StrOffsets{"2234         << Table.GetStringOffset(Int->fullName()) << " /* " << Int->fullName()2235         << " */, " << Table.GetStringOffset("") << ", "2236         << Table.GetStringOffset("ncU") << " /* ncU */}},\n";2237  OS << "#endif // GET_CDE_BUILTIN_INFOS\n\n";2238}2239 2240void CdeEmitter::EmitBuiltinSema(raw_ostream &OS) {2241  std::map<std::string, std::set<std::string>> Checks;2242  GroupSemaChecks(Checks);2243 2244  for (const auto &kv : Checks) {2245    for (StringRef Name : kv.second)2246      OS << "case ARM::BI__builtin_arm_cde_" << Name << ":\n";2247    OS << "  Err = " << kv.first << "  break;\n";2248  }2249}2250 2251} // namespace2252 2253namespace clang {2254 2255// MVE2256 2257void EmitMveHeader(const RecordKeeper &Records, raw_ostream &OS) {2258  MveEmitter(Records).EmitHeader(OS);2259}2260 2261void EmitMveBuiltinDef(const RecordKeeper &Records, raw_ostream &OS) {2262  MveEmitter(Records).EmitBuiltinDef(OS);2263}2264 2265void EmitMveBuiltinSema(const RecordKeeper &Records, raw_ostream &OS) {2266  MveEmitter(Records).EmitBuiltinSema(OS);2267}2268 2269void EmitMveBuiltinCG(const RecordKeeper &Records, raw_ostream &OS) {2270  MveEmitter(Records).EmitBuiltinCG(OS);2271}2272 2273void EmitMveBuiltinAliases(const RecordKeeper &Records, raw_ostream &OS) {2274  MveEmitter(Records).EmitBuiltinAliases(OS);2275}2276 2277// CDE2278 2279void EmitCdeHeader(const RecordKeeper &Records, raw_ostream &OS) {2280  CdeEmitter(Records).EmitHeader(OS);2281}2282 2283void EmitCdeBuiltinDef(const RecordKeeper &Records, raw_ostream &OS) {2284  CdeEmitter(Records).EmitBuiltinDef(OS);2285}2286 2287void EmitCdeBuiltinSema(const RecordKeeper &Records, raw_ostream &OS) {2288  CdeEmitter(Records).EmitBuiltinSema(OS);2289}2290 2291void EmitCdeBuiltinCG(const RecordKeeper &Records, raw_ostream &OS) {2292  CdeEmitter(Records).EmitBuiltinCG(OS);2293}2294 2295void EmitCdeBuiltinAliases(const RecordKeeper &Records, raw_ostream &OS) {2296  CdeEmitter(Records).EmitBuiltinAliases(OS);2297}2298 2299} // end namespace clang2300