1 //===- MveEmitter.cpp - Generate arm_mve.h for use with clang -*- C++ -*-=====// 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-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // This set of linked tablegen backends is responsible for emitting the bits 10 // and pieces that implement <arm_mve.h>, which is defined by the ACLE standard 11 // and provides a set of types and functions for (more or less) direct access 12 // to the MVE instruction set, including the scalar shifts as well as the 13 // vector instructions. 14 // 15 // MVE's standard intrinsic functions are unusual in that they have a system of 16 // polymorphism. For example, the function vaddq() can behave like vaddq_u16(), 17 // vaddq_f32(), vaddq_s8(), etc., depending on the types of the vector 18 // arguments you give it. 19 // 20 // This constrains the implementation strategies. The usual approach to making 21 // the user-facing functions polymorphic would be to either use 22 // __attribute__((overloadable)) to make a set of vaddq() functions that are 23 // all inline wrappers on the underlying clang builtins, or to define a single 24 // vaddq() macro which expands to an instance of _Generic. 25 // 26 // The inline-wrappers approach would work fine for most intrinsics, except for 27 // 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, the 29 // 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 a 32 // lot of machinery, because of the design feature of _Generic that even the 33 // untaken branches are required to pass all front-end validity checks such as 34 // type-correctness. You can work around that by nesting further _Generics all 35 // over the place to coerce things to the right type in untaken branches, but 36 // what you get out is complicated, hard to guarantee its correctness, and 37 // worst of all, gives _completely unreadable_ error messages if the user gets 38 // the types wrong for an intrinsic call. 39 // 40 // Therefore, my strategy is to introduce a new __attribute__ that allows a 41 // function to be mapped to a clang builtin even though it doesn't have the 42 // same name, and then declare all the user-facing MVE function names with that 43 // attribute, mapping each one directly to the clang builtin. And the 44 // polymorphic ones have __attribute__((overloadable)) as well. So once the 45 // compiler has resolved the overload, it knows the internal builtin ID of the 46 // selected function, and can check the immediate arguments against that; and 47 // if the user gets the types wrong in a call to a polymorphic intrinsic, they 48 // get a completely clear error message showing all the declarations of that 49 // function in the header file and explaining why each one doesn't fit their 50 // call. 51 // 52 // The downside of this is that if every clang builtin has to correspond 53 // exactly to a user-facing ACLE intrinsic, then you can't save work in the 54 // frontend by doing it in the header file: CGBuiltin.cpp has to do the entire 55 // job of converting an ACLE intrinsic call into LLVM IR. So the Tablegen 56 // description for an MVE intrinsic has to contain a full description of the 57 // 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/Support/Casting.h" 64 #include "llvm/Support/raw_ostream.h" 65 #include "llvm/TableGen/Error.h" 66 #include "llvm/TableGen/Record.h" 67 #include "llvm/TableGen/StringToOffsetTable.h" 68 #include <cassert> 69 #include <cstddef> 70 #include <cstdint> 71 #include <list> 72 #include <map> 73 #include <memory> 74 #include <set> 75 #include <string> 76 #include <vector> 77 78 using namespace llvm; 79 80 namespace { 81 82 class MveEmitter; 83 class Result; 84 85 // ----------------------------------------------------------------------------- 86 // A system of classes to represent all the types we'll need to deal with in 87 // the prototypes of intrinsics. 88 // 89 // Query methods include finding out the C name of a type; the "LLVM name" in 90 // the sense of a C++ code snippet that can be used in the codegen function; 91 // the suffix that represents the type in the ACLE intrinsic naming scheme 92 // (e.g. 's32' represents int32_t in intrinsics such as vaddq_s32); whether the 93 // type is floating-point related (hence should be under #ifdef in the MVE 94 // header so that it isn't included in integer-only MVE mode); and the type's 95 // size in bits. Not all subtypes support all these queries. 96 97 class Type { 98 public: 99 enum class TypeKind { 100 // Void appears as a return type (for store intrinsics, which are pure 101 // side-effect). It's also used as the parameter type in the Tablegen 102 // when an intrinsic doesn't need to come in various suffixed forms like 103 // vfooq_s8,vfooq_u16,vfooq_f32. 104 Void, 105 106 // Scalar is used for ordinary int and float types of all sizes. 107 Scalar, 108 109 // Vector is used for anything that occupies exactly one MVE vector 110 // register, i.e. {uint,int,float}NxM_t. 111 Vector, 112 113 // MultiVector is used for the {uint,int,float}NxMxK_t types used by the 114 // interleaving load/store intrinsics v{ld,st}{2,4}q. 115 MultiVector, 116 117 // Predicate is used by all the predicated intrinsics. Its C 118 // representation is mve_pred16_t (which is just an alias for uint16_t). 119 // But we give more detail here, by indicating that a given predicate 120 // instruction is logically regarded as a vector of i1 containing the 121 // same number of lanes as the input vector type. So our Predicate type 122 // comes with a lane count, which we use to decide which kind of <n x i1> 123 // we'll invoke the pred_i2v IR intrinsic to translate it into. 124 Predicate, 125 126 // Pointer is used for pointer types (obviously), and comes with a flag 127 // indicating whether it's a pointer to a const or mutable instance of 128 // the pointee type. 129 Pointer, 130 }; 131 132 private: 133 const TypeKind TKind; 134 135 protected: 136 Type(TypeKind K) : TKind(K) {} 137 138 public: 139 TypeKind typeKind() const { return TKind; } 140 virtual ~Type() = default; 141 virtual bool requiresFloat() const = 0; 142 virtual unsigned sizeInBits() const = 0; 143 virtual std::string cName() const = 0; 144 virtual std::string llvmName() const { 145 PrintFatalError("no LLVM type name available for type " + cName()); 146 } 147 virtual std::string acleSuffix(std::string) const { 148 PrintFatalError("no ACLE suffix available for this type"); 149 } 150 }; 151 152 enum class ScalarTypeKind { SignedInt, UnsignedInt, Float }; 153 inline std::string toLetter(ScalarTypeKind kind) { 154 switch (kind) { 155 case ScalarTypeKind::SignedInt: 156 return "s"; 157 case ScalarTypeKind::UnsignedInt: 158 return "u"; 159 case ScalarTypeKind::Float: 160 return "f"; 161 } 162 llvm_unreachable("Unhandled ScalarTypeKind enum"); 163 } 164 inline std::string toCPrefix(ScalarTypeKind kind) { 165 switch (kind) { 166 case ScalarTypeKind::SignedInt: 167 return "int"; 168 case ScalarTypeKind::UnsignedInt: 169 return "uint"; 170 case ScalarTypeKind::Float: 171 return "float"; 172 } 173 llvm_unreachable("Unhandled ScalarTypeKind enum"); 174 } 175 176 class VoidType : public Type { 177 public: 178 VoidType() : Type(TypeKind::Void) {} 179 unsigned sizeInBits() const override { return 0; } 180 bool requiresFloat() const override { return false; } 181 std::string cName() const override { return "void"; } 182 183 static bool classof(const Type *T) { return T->typeKind() == TypeKind::Void; } 184 std::string acleSuffix(std::string) const override { return ""; } 185 }; 186 187 class PointerType : public Type { 188 const Type *Pointee; 189 bool Const; 190 191 public: 192 PointerType(const Type *Pointee, bool Const) 193 : Type(TypeKind::Pointer), Pointee(Pointee), Const(Const) {} 194 unsigned sizeInBits() const override { return 32; } 195 bool requiresFloat() const override { return Pointee->requiresFloat(); } 196 std::string cName() const override { 197 std::string Name = Pointee->cName(); 198 199 // The syntax for a pointer in C is different when the pointee is 200 // itself a pointer. The MVE intrinsics don't contain any double 201 // pointers, so we don't need to worry about that wrinkle. 202 assert(!isa<PointerType>(Pointee) && "Pointer to pointer not supported"); 203 204 if (Const) 205 Name = "const " + Name; 206 return Name + " *"; 207 } 208 std::string llvmName() const override { 209 return "llvm::PointerType::getUnqual(" + Pointee->llvmName() + ")"; 210 } 211 212 static bool classof(const Type *T) { 213 return T->typeKind() == TypeKind::Pointer; 214 } 215 }; 216 217 // Base class for all the types that have a name of the form 218 // [prefix][numbers]_t, like int32_t, uint16x8_t, float32x4x2_t. 219 // 220 // For this sub-hierarchy we invent a cNameBase() method which returns the 221 // whole name except for the trailing "_t", so that Vector and MultiVector can 222 // append an extra "x2" or whatever to their element type's cNameBase(). Then 223 // the main cName() query method puts "_t" on the end for the final type name. 224 225 class CRegularNamedType : public Type { 226 using Type::Type; 227 virtual std::string cNameBase() const = 0; 228 229 public: 230 std::string cName() const override { return cNameBase() + "_t"; } 231 }; 232 233 class ScalarType : public CRegularNamedType { 234 ScalarTypeKind Kind; 235 unsigned Bits; 236 std::string NameOverride; 237 238 public: 239 ScalarType(const Record *Record) : CRegularNamedType(TypeKind::Scalar) { 240 Kind = StringSwitch<ScalarTypeKind>(Record->getValueAsString("kind")) 241 .Case("s", ScalarTypeKind::SignedInt) 242 .Case("u", ScalarTypeKind::UnsignedInt) 243 .Case("f", ScalarTypeKind::Float); 244 Bits = Record->getValueAsInt("size"); 245 NameOverride = std::string(Record->getValueAsString("nameOverride")); 246 } 247 unsigned sizeInBits() const override { return Bits; } 248 ScalarTypeKind kind() const { return Kind; } 249 std::string suffix() const { return toLetter(Kind) + utostr(Bits); } 250 std::string cNameBase() const override { 251 return toCPrefix(Kind) + utostr(Bits); 252 } 253 std::string cName() const override { 254 if (NameOverride.empty()) 255 return CRegularNamedType::cName(); 256 return NameOverride; 257 } 258 std::string llvmName() const override { 259 if (Kind == ScalarTypeKind::Float) { 260 if (Bits == 16) 261 return "HalfTy"; 262 if (Bits == 32) 263 return "FloatTy"; 264 if (Bits == 64) 265 return "DoubleTy"; 266 PrintFatalError("bad size for floating type"); 267 } 268 return "Int" + utostr(Bits) + "Ty"; 269 } 270 std::string acleSuffix(std::string overrideLetter) const override { 271 return "_" + (overrideLetter.size() ? overrideLetter : toLetter(Kind)) 272 + utostr(Bits); 273 } 274 bool isInteger() const { return Kind != ScalarTypeKind::Float; } 275 bool requiresFloat() const override { return !isInteger(); } 276 bool hasNonstandardName() const { return !NameOverride.empty(); } 277 278 static bool classof(const Type *T) { 279 return T->typeKind() == TypeKind::Scalar; 280 } 281 }; 282 283 class VectorType : public CRegularNamedType { 284 const ScalarType *Element; 285 unsigned Lanes; 286 287 public: 288 VectorType(const ScalarType *Element, unsigned Lanes) 289 : CRegularNamedType(TypeKind::Vector), Element(Element), Lanes(Lanes) {} 290 unsigned sizeInBits() const override { return Lanes * Element->sizeInBits(); } 291 unsigned lanes() const { return Lanes; } 292 bool requiresFloat() const override { return Element->requiresFloat(); } 293 std::string cNameBase() const override { 294 return Element->cNameBase() + "x" + utostr(Lanes); 295 } 296 std::string llvmName() const override { 297 return "llvm::VectorType::get(" + Element->llvmName() + ", " + 298 utostr(Lanes) + ")"; 299 } 300 301 static bool classof(const Type *T) { 302 return T->typeKind() == TypeKind::Vector; 303 } 304 }; 305 306 class MultiVectorType : public CRegularNamedType { 307 const VectorType *Element; 308 unsigned Registers; 309 310 public: 311 MultiVectorType(unsigned Registers, const VectorType *Element) 312 : CRegularNamedType(TypeKind::MultiVector), Element(Element), 313 Registers(Registers) {} 314 unsigned sizeInBits() const override { 315 return Registers * Element->sizeInBits(); 316 } 317 unsigned registers() const { return Registers; } 318 bool requiresFloat() const override { return Element->requiresFloat(); } 319 std::string cNameBase() const override { 320 return Element->cNameBase() + "x" + utostr(Registers); 321 } 322 323 // MultiVectorType doesn't override llvmName, because we don't expect to do 324 // automatic code generation for the MVE intrinsics that use it: the {vld2, 325 // vld4, vst2, vst4} family are the only ones that use these types, so it was 326 // easier to hand-write the codegen for dealing with these structs than to 327 // build in lots of extra automatic machinery that would only be used once. 328 329 static bool classof(const Type *T) { 330 return T->typeKind() == TypeKind::MultiVector; 331 } 332 }; 333 334 class PredicateType : public CRegularNamedType { 335 unsigned Lanes; 336 337 public: 338 PredicateType(unsigned Lanes) 339 : CRegularNamedType(TypeKind::Predicate), Lanes(Lanes) {} 340 unsigned sizeInBits() const override { return 16; } 341 std::string cNameBase() const override { return "mve_pred16"; } 342 bool requiresFloat() const override { return false; }; 343 std::string llvmName() const override { 344 // Use <4 x i1> instead of <2 x i1> for two-lane vector types. See 345 // the comment in llvm/lib/Target/ARM/ARMInstrMVE.td for further 346 // explanation. 347 unsigned ModifiedLanes = (Lanes == 2 ? 4 : Lanes); 348 349 return "llvm::VectorType::get(Builder.getInt1Ty(), " + 350 utostr(ModifiedLanes) + ")"; 351 } 352 353 static bool classof(const Type *T) { 354 return T->typeKind() == TypeKind::Predicate; 355 } 356 }; 357 358 // ----------------------------------------------------------------------------- 359 // Class to facilitate merging together the code generation for many intrinsics 360 // by means of varying a few constant or type parameters. 361 // 362 // Most obviously, the intrinsics in a single parametrised family will have 363 // code generation sequences that only differ in a type or two, e.g. vaddq_s8 364 // and vaddq_u16 will look the same apart from putting a different vector type 365 // in the call to CGM.getIntrinsic(). But also, completely different intrinsics 366 // will often code-generate in the same way, with only a different choice of 367 // _which_ IR intrinsic they lower to (e.g. vaddq_m_s8 and vmulq_m_s8), but 368 // marshalling the arguments and return values of the IR intrinsic in exactly 369 // the same way. And others might differ only in some other kind of constant, 370 // such as a lane index. 371 // 372 // So, when we generate the IR-building code for all these intrinsics, we keep 373 // track of every value that could possibly be pulled out of the code and 374 // stored ahead of time in a local variable. Then we group together intrinsics 375 // by textual equivalence of the code that would result if _all_ those 376 // parameters were stored in local variables. That gives us maximal sets that 377 // can be implemented by a single piece of IR-building code by changing 378 // parameter values ahead of time. 379 // 380 // After we've done that, we do a second pass in which we only allocate _some_ 381 // of the parameters into local variables, by tracking which ones have the same 382 // values as each other (so that a single variable can be reused) and which 383 // ones are the same across the whole set (so that no variable is needed at 384 // all). 385 // 386 // Hence the class below. Its allocParam method is invoked during code 387 // generation by every method of a Result subclass (see below) that wants to 388 // give it the opportunity to pull something out into a switchable parameter. 389 // It returns a variable name for the parameter, or (if it's being used in the 390 // second pass once we've decided that some parameters don't need to be stored 391 // in variables after all) it might just return the input expression unchanged. 392 393 struct CodeGenParamAllocator { 394 // Accumulated during code generation 395 std::vector<std::string> *ParamTypes = nullptr; 396 std::vector<std::string> *ParamValues = nullptr; 397 398 // Provided ahead of time in pass 2, to indicate which parameters are being 399 // assigned to what. This vector contains an entry for each call to 400 // allocParam expected during code gen (which we counted up in pass 1), and 401 // indicates the number of the parameter variable that should be returned, or 402 // -1 if this call shouldn't allocate a parameter variable at all. 403 // 404 // We rely on the recursive code generation working identically in passes 1 405 // and 2, so that the same list of calls to allocParam happen in the same 406 // order. That guarantees that the parameter numbers recorded in pass 1 will 407 // match the entries in this vector that store what MveEmitter::EmitBuiltinCG 408 // decided to do about each one in pass 2. 409 std::vector<int> *ParamNumberMap = nullptr; 410 411 // Internally track how many things we've allocated 412 unsigned nparams = 0; 413 414 std::string allocParam(StringRef Type, StringRef Value) { 415 unsigned ParamNumber; 416 417 if (!ParamNumberMap) { 418 // In pass 1, unconditionally assign a new parameter variable to every 419 // value we're asked to process. 420 ParamNumber = nparams++; 421 } else { 422 // In pass 2, consult the map provided by the caller to find out which 423 // variable we should be keeping things in. 424 int MapValue = (*ParamNumberMap)[nparams++]; 425 if (MapValue < 0) 426 return std::string(Value); 427 ParamNumber = MapValue; 428 } 429 430 // If we've allocated a new parameter variable for the first time, store 431 // its type and value to be retrieved after codegen. 432 if (ParamTypes && ParamTypes->size() == ParamNumber) 433 ParamTypes->push_back(std::string(Type)); 434 if (ParamValues && ParamValues->size() == ParamNumber) 435 ParamValues->push_back(std::string(Value)); 436 437 // Unimaginative naming scheme for parameter variables. 438 return "Param" + utostr(ParamNumber); 439 } 440 }; 441 442 // ----------------------------------------------------------------------------- 443 // System of classes that represent all the intermediate values used during 444 // code-generation for an intrinsic. 445 // 446 // The base class 'Result' can represent a value of the LLVM type 'Value', or 447 // sometimes 'Address' (for loads/stores, including an alignment requirement). 448 // 449 // In the case where the Tablegen provides a value in the codegen dag as a 450 // plain integer literal, the Result object we construct here will be one that 451 // returns true from hasIntegerConstantValue(). This allows the generated C++ 452 // code to use the constant directly in contexts which can take a literal 453 // integer, such as Builder.CreateExtractValue(thing, 1), without going to the 454 // effort of calling llvm::ConstantInt::get() and then pulling the constant 455 // back out of the resulting llvm:Value later. 456 457 class Result { 458 public: 459 // Convenient shorthand for the pointer type we'll be using everywhere. 460 using Ptr = std::shared_ptr<Result>; 461 462 private: 463 Ptr Predecessor; 464 std::string VarName; 465 bool VarNameUsed = false; 466 unsigned Visited = 0; 467 468 public: 469 virtual ~Result() = default; 470 using Scope = std::map<std::string, Ptr>; 471 virtual void genCode(raw_ostream &OS, CodeGenParamAllocator &) const = 0; 472 virtual bool hasIntegerConstantValue() const { return false; } 473 virtual uint32_t integerConstantValue() const { return 0; } 474 virtual bool hasIntegerValue() const { return false; } 475 virtual std::string getIntegerValue(const std::string &) { 476 llvm_unreachable("non-working Result::getIntegerValue called"); 477 } 478 virtual std::string typeName() const { return "Value *"; } 479 480 // Mostly, when a code-generation operation has a dependency on prior 481 // operations, it's because it uses the output values of those operations as 482 // inputs. But there's one exception, which is the use of 'seq' in Tablegen 483 // to indicate that operations have to be performed in sequence regardless of 484 // whether they use each others' output values. 485 // 486 // So, the actual generation of code is done by depth-first search, using the 487 // prerequisites() method to get a list of all the other Results that have to 488 // be computed before this one. That method divides into the 'predecessor', 489 // set by setPredecessor() while processing a 'seq' dag node, and the list 490 // returned by 'morePrerequisites', which each subclass implements to return 491 // a list of the Results it uses as input to whatever its own computation is 492 // doing. 493 494 virtual void morePrerequisites(std::vector<Ptr> &output) const {} 495 std::vector<Ptr> prerequisites() const { 496 std::vector<Ptr> ToRet; 497 if (Predecessor) 498 ToRet.push_back(Predecessor); 499 morePrerequisites(ToRet); 500 return ToRet; 501 } 502 503 void setPredecessor(Ptr p) { 504 // If the user has nested one 'seq' node inside another, and this 505 // method is called on the return value of the inner 'seq' (i.e. 506 // the final item inside it), then we can't link _this_ node to p, 507 // because it already has a predecessor. Instead, walk the chain 508 // until we find the first item in the inner seq, and link that to 509 // p, so that nesting seqs has the obvious effect of linking 510 // everything together into one long sequential chain. 511 Result *r = this; 512 while (r->Predecessor) 513 r = r->Predecessor.get(); 514 r->Predecessor = p; 515 } 516 517 // Each Result will be assigned a variable name in the output code, but not 518 // all those variable names will actually be used (e.g. the return value of 519 // Builder.CreateStore has void type, so nobody will want to refer to it). To 520 // prevent annoying compiler warnings, we track whether each Result's 521 // variable name was ever actually mentioned in subsequent statements, so 522 // that it can be left out of the final generated code. 523 std::string varname() { 524 VarNameUsed = true; 525 return VarName; 526 } 527 void setVarname(const StringRef s) { VarName = std::string(s); } 528 bool varnameUsed() const { return VarNameUsed; } 529 530 // Emit code to generate this result as a Value *. 531 virtual std::string asValue() { 532 return varname(); 533 } 534 535 // Code generation happens in multiple passes. This method tracks whether a 536 // Result has yet been visited in a given pass, without the need for a 537 // tedious loop in between passes that goes through and resets a 'visited' 538 // flag back to false: you just set Pass=1 the first time round, and Pass=2 539 // the second time. 540 bool needsVisiting(unsigned Pass) { 541 bool ToRet = Visited < Pass; 542 Visited = Pass; 543 return ToRet; 544 } 545 }; 546 547 // Result subclass that retrieves one of the arguments to the clang builtin 548 // function. In cases where the argument has pointer type, we call 549 // EmitPointerWithAlignment and store the result in a variable of type Address, 550 // so that load and store IR nodes can know the right alignment. Otherwise, we 551 // call EmitScalarExpr. 552 // 553 // There are aggregate parameters in the MVE intrinsics API, but we don't deal 554 // with them in this Tablegen back end: they only arise in the vld2q/vld4q and 555 // vst2q/vst4q family, which is few enough that we just write the code by hand 556 // for those in CGBuiltin.cpp. 557 class BuiltinArgResult : public Result { 558 public: 559 unsigned ArgNum; 560 bool AddressType; 561 bool Immediate; 562 BuiltinArgResult(unsigned ArgNum, bool AddressType, bool Immediate) 563 : ArgNum(ArgNum), AddressType(AddressType), Immediate(Immediate) {} 564 void genCode(raw_ostream &OS, CodeGenParamAllocator &) const override { 565 OS << (AddressType ? "EmitPointerWithAlignment" : "EmitScalarExpr") 566 << "(E->getArg(" << ArgNum << "))"; 567 } 568 std::string typeName() const override { 569 return AddressType ? "Address" : Result::typeName(); 570 } 571 // Emit code to generate this result as a Value *. 572 std::string asValue() override { 573 if (AddressType) 574 return "(" + varname() + ".getPointer())"; 575 return Result::asValue(); 576 } 577 bool hasIntegerValue() const override { return Immediate; } 578 std::string getIntegerValue(const std::string &IntType) override { 579 return "GetIntegerConstantValue<" + IntType + ">(E->getArg(" + 580 utostr(ArgNum) + "), getContext())"; 581 } 582 }; 583 584 // Result subclass for an integer literal appearing in Tablegen. This may need 585 // to be turned into an llvm::Result by means of llvm::ConstantInt::get(), or 586 // it may be used directly as an integer, depending on which IRBuilder method 587 // it's being passed to. 588 class IntLiteralResult : public Result { 589 public: 590 const ScalarType *IntegerType; 591 uint32_t IntegerValue; 592 IntLiteralResult(const ScalarType *IntegerType, uint32_t IntegerValue) 593 : IntegerType(IntegerType), IntegerValue(IntegerValue) {} 594 void genCode(raw_ostream &OS, 595 CodeGenParamAllocator &ParamAlloc) const override { 596 OS << "llvm::ConstantInt::get(" 597 << ParamAlloc.allocParam("llvm::Type *", IntegerType->llvmName()) 598 << ", "; 599 OS << ParamAlloc.allocParam(IntegerType->cName(), utostr(IntegerValue)) 600 << ")"; 601 } 602 bool hasIntegerConstantValue() const override { return true; } 603 uint32_t integerConstantValue() const override { return IntegerValue; } 604 }; 605 606 // Result subclass representing a cast between different integer types. We use 607 // our own ScalarType abstraction as the representation of the target type, 608 // which gives both size and signedness. 609 class IntCastResult : public Result { 610 public: 611 const ScalarType *IntegerType; 612 Ptr V; 613 IntCastResult(const ScalarType *IntegerType, Ptr V) 614 : IntegerType(IntegerType), V(V) {} 615 void genCode(raw_ostream &OS, 616 CodeGenParamAllocator &ParamAlloc) const override { 617 OS << "Builder.CreateIntCast(" << V->varname() << ", " 618 << ParamAlloc.allocParam("llvm::Type *", IntegerType->llvmName()) << ", " 619 << ParamAlloc.allocParam("bool", 620 IntegerType->kind() == ScalarTypeKind::SignedInt 621 ? "true" 622 : "false") 623 << ")"; 624 } 625 void morePrerequisites(std::vector<Ptr> &output) const override { 626 output.push_back(V); 627 } 628 }; 629 630 // Result subclass representing a cast between different pointer types. 631 class PointerCastResult : public Result { 632 public: 633 const PointerType *PtrType; 634 Ptr V; 635 PointerCastResult(const PointerType *PtrType, Ptr V) 636 : PtrType(PtrType), V(V) {} 637 void genCode(raw_ostream &OS, 638 CodeGenParamAllocator &ParamAlloc) const override { 639 OS << "Builder.CreatePointerCast(" << V->asValue() << ", " 640 << ParamAlloc.allocParam("llvm::Type *", PtrType->llvmName()) << ")"; 641 } 642 void morePrerequisites(std::vector<Ptr> &output) const override { 643 output.push_back(V); 644 } 645 }; 646 647 // Result subclass representing a call to an IRBuilder method. Each IRBuilder 648 // method we want to use will have a Tablegen record giving the method name and 649 // describing any important details of how to call it, such as whether a 650 // particular argument should be an integer constant instead of an llvm::Value. 651 class IRBuilderResult : public Result { 652 public: 653 StringRef CallPrefix; 654 std::vector<Ptr> Args; 655 std::set<unsigned> AddressArgs; 656 std::map<unsigned, std::string> IntegerArgs; 657 IRBuilderResult(StringRef CallPrefix, std::vector<Ptr> Args, 658 std::set<unsigned> AddressArgs, 659 std::map<unsigned, std::string> IntegerArgs) 660 : CallPrefix(CallPrefix), Args(Args), AddressArgs(AddressArgs), 661 IntegerArgs(IntegerArgs) {} 662 void genCode(raw_ostream &OS, 663 CodeGenParamAllocator &ParamAlloc) const override { 664 OS << CallPrefix; 665 const char *Sep = ""; 666 for (unsigned i = 0, e = Args.size(); i < e; ++i) { 667 Ptr Arg = Args[i]; 668 auto it = IntegerArgs.find(i); 669 670 OS << Sep; 671 Sep = ", "; 672 673 if (it != IntegerArgs.end()) { 674 if (Arg->hasIntegerConstantValue()) 675 OS << "static_cast<" << it->second << ">(" 676 << ParamAlloc.allocParam(it->second, 677 utostr(Arg->integerConstantValue())) 678 << ")"; 679 else if (Arg->hasIntegerValue()) 680 OS << ParamAlloc.allocParam(it->second, 681 Arg->getIntegerValue(it->second)); 682 } else { 683 OS << Arg->varname(); 684 } 685 } 686 OS << ")"; 687 } 688 void morePrerequisites(std::vector<Ptr> &output) const override { 689 for (unsigned i = 0, e = Args.size(); i < e; ++i) { 690 Ptr Arg = Args[i]; 691 if (IntegerArgs.find(i) != IntegerArgs.end()) 692 continue; 693 output.push_back(Arg); 694 } 695 } 696 }; 697 698 // Result subclass representing making an Address out of a Value. 699 class AddressResult : public Result { 700 public: 701 Ptr Arg; 702 unsigned Align; 703 AddressResult(Ptr Arg, unsigned Align) : Arg(Arg), Align(Align) {} 704 void genCode(raw_ostream &OS, 705 CodeGenParamAllocator &ParamAlloc) const override { 706 OS << "Address(" << Arg->varname() << ", CharUnits::fromQuantity(" 707 << Align << "))"; 708 } 709 std::string typeName() const override { 710 return "Address"; 711 } 712 void morePrerequisites(std::vector<Ptr> &output) const override { 713 output.push_back(Arg); 714 } 715 }; 716 717 // Result subclass representing a call to an IR intrinsic, which we first have 718 // to look up using an Intrinsic::ID constant and an array of types. 719 class IRIntrinsicResult : public Result { 720 public: 721 std::string IntrinsicID; 722 std::vector<const Type *> ParamTypes; 723 std::vector<Ptr> Args; 724 IRIntrinsicResult(StringRef IntrinsicID, std::vector<const Type *> ParamTypes, 725 std::vector<Ptr> Args) 726 : IntrinsicID(std::string(IntrinsicID)), ParamTypes(ParamTypes), 727 Args(Args) {} 728 void genCode(raw_ostream &OS, 729 CodeGenParamAllocator &ParamAlloc) const override { 730 std::string IntNo = ParamAlloc.allocParam( 731 "Intrinsic::ID", "Intrinsic::" + IntrinsicID); 732 OS << "Builder.CreateCall(CGM.getIntrinsic(" << IntNo; 733 if (!ParamTypes.empty()) { 734 OS << ", llvm::SmallVector<llvm::Type *, " << ParamTypes.size() << "> {"; 735 const char *Sep = ""; 736 for (auto T : ParamTypes) { 737 OS << Sep << ParamAlloc.allocParam("llvm::Type *", T->llvmName()); 738 Sep = ", "; 739 } 740 OS << "}"; 741 } 742 OS << "), llvm::SmallVector<Value *, " << Args.size() << "> {"; 743 const char *Sep = ""; 744 for (auto Arg : Args) { 745 OS << Sep << Arg->asValue(); 746 Sep = ", "; 747 } 748 OS << "})"; 749 } 750 void morePrerequisites(std::vector<Ptr> &output) const override { 751 output.insert(output.end(), Args.begin(), Args.end()); 752 } 753 }; 754 755 // Result subclass that specifies a type, for use in IRBuilder operations such 756 // as CreateBitCast that take a type argument. 757 class TypeResult : public Result { 758 public: 759 const Type *T; 760 TypeResult(const Type *T) : T(T) {} 761 void genCode(raw_ostream &OS, CodeGenParamAllocator &) const override { 762 OS << T->llvmName(); 763 } 764 std::string typeName() const override { 765 return "llvm::Type *"; 766 } 767 }; 768 769 // ----------------------------------------------------------------------------- 770 // Class that describes a single ACLE intrinsic. 771 // 772 // A Tablegen record will typically describe more than one ACLE intrinsic, by 773 // means of setting the 'list<Type> Params' field to a list of multiple 774 // parameter types, so as to define vaddq_{s8,u8,...,f16,f32} all in one go. 775 // We'll end up with one instance of ACLEIntrinsic for *each* parameter type, 776 // rather than a single one for all of them. Hence, the constructor takes both 777 // a Tablegen record and the current value of the parameter type. 778 779 class ACLEIntrinsic { 780 // Structure documenting that one of the intrinsic's arguments is required to 781 // be a compile-time constant integer, and what constraints there are on its 782 // value. Used when generating Sema checking code. 783 struct ImmediateArg { 784 enum class BoundsType { ExplicitRange, UInt }; 785 BoundsType boundsType; 786 int64_t i1, i2; 787 StringRef ExtraCheckType, ExtraCheckArgs; 788 const Type *ArgType; 789 }; 790 791 // For polymorphic intrinsics, FullName is the explicit name that uniquely 792 // identifies this variant of the intrinsic, and ShortName is the name it 793 // shares with at least one other intrinsic. 794 std::string ShortName, FullName; 795 796 // A very small number of intrinsics _only_ have a polymorphic 797 // variant (vuninitializedq taking an unevaluated argument). 798 bool PolymorphicOnly; 799 800 // Another rarely-used flag indicating that the builtin doesn't 801 // evaluate its argument(s) at all. 802 bool NonEvaluating; 803 804 const Type *ReturnType; 805 std::vector<const Type *> ArgTypes; 806 std::map<unsigned, ImmediateArg> ImmediateArgs; 807 Result::Ptr Code; 808 809 std::map<std::string, std::string> CustomCodeGenArgs; 810 811 // Recursive function that does the internals of code generation. 812 void genCodeDfs(Result::Ptr V, std::list<Result::Ptr> &Used, 813 unsigned Pass) const { 814 if (!V->needsVisiting(Pass)) 815 return; 816 817 for (Result::Ptr W : V->prerequisites()) 818 genCodeDfs(W, Used, Pass); 819 820 Used.push_back(V); 821 } 822 823 public: 824 const std::string &shortName() const { return ShortName; } 825 const std::string &fullName() const { return FullName; } 826 const Type *returnType() const { return ReturnType; } 827 const std::vector<const Type *> &argTypes() const { return ArgTypes; } 828 bool requiresFloat() const { 829 if (ReturnType->requiresFloat()) 830 return true; 831 for (const Type *T : ArgTypes) 832 if (T->requiresFloat()) 833 return true; 834 return false; 835 } 836 bool polymorphic() const { return ShortName != FullName; } 837 bool polymorphicOnly() const { return PolymorphicOnly; } 838 bool nonEvaluating() const { return NonEvaluating; } 839 840 // External entry point for code generation, called from MveEmitter. 841 void genCode(raw_ostream &OS, CodeGenParamAllocator &ParamAlloc, 842 unsigned Pass) const { 843 if (!hasCode()) { 844 for (auto kv : CustomCodeGenArgs) 845 OS << " " << kv.first << " = " << kv.second << ";\n"; 846 OS << " break; // custom code gen\n"; 847 return; 848 } 849 std::list<Result::Ptr> Used; 850 genCodeDfs(Code, Used, Pass); 851 852 unsigned varindex = 0; 853 for (Result::Ptr V : Used) 854 if (V->varnameUsed()) 855 V->setVarname("Val" + utostr(varindex++)); 856 857 for (Result::Ptr V : Used) { 858 OS << " "; 859 if (V == Used.back()) { 860 assert(!V->varnameUsed()); 861 OS << "return "; // FIXME: what if the top-level thing is void? 862 } else if (V->varnameUsed()) { 863 std::string Type = V->typeName(); 864 OS << V->typeName(); 865 if (!StringRef(Type).endswith("*")) 866 OS << " "; 867 OS << V->varname() << " = "; 868 } 869 V->genCode(OS, ParamAlloc); 870 OS << ";\n"; 871 } 872 } 873 bool hasCode() const { return Code != nullptr; } 874 875 static std::string signedHexLiteral(const llvm::APInt &iOrig) { 876 llvm::APInt i = iOrig.trunc(64); 877 SmallString<40> s; 878 i.toString(s, 16, true, true); 879 return std::string(s.str()); 880 } 881 882 std::string genSema() const { 883 std::vector<std::string> SemaChecks; 884 885 for (const auto &kv : ImmediateArgs) { 886 const ImmediateArg &IA = kv.second; 887 888 llvm::APInt lo(128, 0), hi(128, 0); 889 switch (IA.boundsType) { 890 case ImmediateArg::BoundsType::ExplicitRange: 891 lo = IA.i1; 892 hi = IA.i2; 893 break; 894 case ImmediateArg::BoundsType::UInt: 895 lo = 0; 896 hi = llvm::APInt::getMaxValue(IA.i1).zext(128); 897 break; 898 } 899 900 std::string Index = utostr(kv.first); 901 902 // Emit a range check if the legal range of values for the 903 // immediate is smaller than the _possible_ range of values for 904 // its type. 905 unsigned ArgTypeBits = IA.ArgType->sizeInBits(); 906 llvm::APInt ArgTypeRange = llvm::APInt::getMaxValue(ArgTypeBits).zext(128); 907 llvm::APInt ActualRange = (hi-lo).trunc(64).sext(128); 908 if (ActualRange.ult(ArgTypeRange)) 909 SemaChecks.push_back("SemaBuiltinConstantArgRange(TheCall, " + Index + 910 ", " + signedHexLiteral(lo) + ", " + 911 signedHexLiteral(hi) + ")"); 912 913 if (!IA.ExtraCheckType.empty()) { 914 std::string Suffix; 915 if (!IA.ExtraCheckArgs.empty()) { 916 std::string tmp; 917 StringRef Arg = IA.ExtraCheckArgs; 918 if (Arg == "!lanesize") { 919 tmp = utostr(IA.ArgType->sizeInBits()); 920 Arg = tmp; 921 } 922 Suffix = (Twine(", ") + Arg).str(); 923 } 924 SemaChecks.push_back((Twine("SemaBuiltinConstantArg") + 925 IA.ExtraCheckType + "(TheCall, " + Index + 926 Suffix + ")") 927 .str()); 928 } 929 930 assert(!SemaChecks.empty()); 931 } 932 if (SemaChecks.empty()) 933 return ""; 934 return (Twine(" return ") + 935 join(std::begin(SemaChecks), std::end(SemaChecks), 936 " ||\n ") + 937 ";\n") 938 .str(); 939 } 940 941 ACLEIntrinsic(MveEmitter &ME, Record *R, const Type *Param); 942 }; 943 944 // ----------------------------------------------------------------------------- 945 // The top-level class that holds all the state from analyzing the entire 946 // Tablegen input. 947 948 class MveEmitter { 949 // MveEmitter holds a collection of all the types we've instantiated. 950 VoidType Void; 951 std::map<std::string, std::unique_ptr<ScalarType>> ScalarTypes; 952 std::map<std::tuple<ScalarTypeKind, unsigned, unsigned>, 953 std::unique_ptr<VectorType>> 954 VectorTypes; 955 std::map<std::pair<std::string, unsigned>, std::unique_ptr<MultiVectorType>> 956 MultiVectorTypes; 957 std::map<unsigned, std::unique_ptr<PredicateType>> PredicateTypes; 958 std::map<std::string, std::unique_ptr<PointerType>> PointerTypes; 959 960 // And all the ACLEIntrinsic instances we've created. 961 std::map<std::string, std::unique_ptr<ACLEIntrinsic>> ACLEIntrinsics; 962 963 public: 964 // Methods to create a Type object, or return the right existing one from the 965 // maps stored in this object. 966 const VoidType *getVoidType() { return &Void; } 967 const ScalarType *getScalarType(StringRef Name) { 968 return ScalarTypes[std::string(Name)].get(); 969 } 970 const ScalarType *getScalarType(Record *R) { 971 return getScalarType(R->getName()); 972 } 973 const VectorType *getVectorType(const ScalarType *ST, unsigned Lanes) { 974 std::tuple<ScalarTypeKind, unsigned, unsigned> key(ST->kind(), 975 ST->sizeInBits(), Lanes); 976 if (VectorTypes.find(key) == VectorTypes.end()) 977 VectorTypes[key] = std::make_unique<VectorType>(ST, Lanes); 978 return VectorTypes[key].get(); 979 } 980 const VectorType *getVectorType(const ScalarType *ST) { 981 return getVectorType(ST, 128 / ST->sizeInBits()); 982 } 983 const MultiVectorType *getMultiVectorType(unsigned Registers, 984 const VectorType *VT) { 985 std::pair<std::string, unsigned> key(VT->cNameBase(), Registers); 986 if (MultiVectorTypes.find(key) == MultiVectorTypes.end()) 987 MultiVectorTypes[key] = std::make_unique<MultiVectorType>(Registers, VT); 988 return MultiVectorTypes[key].get(); 989 } 990 const PredicateType *getPredicateType(unsigned Lanes) { 991 unsigned key = Lanes; 992 if (PredicateTypes.find(key) == PredicateTypes.end()) 993 PredicateTypes[key] = std::make_unique<PredicateType>(Lanes); 994 return PredicateTypes[key].get(); 995 } 996 const PointerType *getPointerType(const Type *T, bool Const) { 997 PointerType PT(T, Const); 998 std::string key = PT.cName(); 999 if (PointerTypes.find(key) == PointerTypes.end()) 1000 PointerTypes[key] = std::make_unique<PointerType>(PT); 1001 return PointerTypes[key].get(); 1002 } 1003 1004 // Methods to construct a type from various pieces of Tablegen. These are 1005 // always called in the context of setting up a particular ACLEIntrinsic, so 1006 // there's always an ambient parameter type (because we're iterating through 1007 // the Params list in the Tablegen record for the intrinsic), which is used 1008 // to expand Tablegen classes like 'Vector' which mean something different in 1009 // each member of a parametric family. 1010 const Type *getType(Record *R, const Type *Param); 1011 const Type *getType(DagInit *D, const Type *Param); 1012 const Type *getType(Init *I, const Type *Param); 1013 1014 // Functions that translate the Tablegen representation of an intrinsic's 1015 // code generation into a collection of Value objects (which will then be 1016 // reprocessed to read out the actual C++ code included by CGBuiltin.cpp). 1017 Result::Ptr getCodeForDag(DagInit *D, const Result::Scope &Scope, 1018 const Type *Param); 1019 Result::Ptr getCodeForDagArg(DagInit *D, unsigned ArgNum, 1020 const Result::Scope &Scope, const Type *Param); 1021 Result::Ptr getCodeForArg(unsigned ArgNum, const Type *ArgType, bool Promote, 1022 bool Immediate); 1023 1024 // Constructor and top-level functions. 1025 1026 MveEmitter(RecordKeeper &Records); 1027 1028 void EmitHeader(raw_ostream &OS); 1029 void EmitBuiltinDef(raw_ostream &OS); 1030 void EmitBuiltinSema(raw_ostream &OS); 1031 void EmitBuiltinCG(raw_ostream &OS); 1032 void EmitBuiltinAliases(raw_ostream &OS); 1033 }; 1034 1035 const Type *MveEmitter::getType(Init *I, const Type *Param) { 1036 if (auto Dag = dyn_cast<DagInit>(I)) 1037 return getType(Dag, Param); 1038 if (auto Def = dyn_cast<DefInit>(I)) 1039 return getType(Def->getDef(), Param); 1040 1041 PrintFatalError("Could not convert this value into a type"); 1042 } 1043 1044 const Type *MveEmitter::getType(Record *R, const Type *Param) { 1045 // Pass to a subfield of any wrapper records. We don't expect more than one 1046 // of these: immediate operands are used as plain numbers rather than as 1047 // llvm::Value, so it's meaningless to promote their type anyway. 1048 if (R->isSubClassOf("Immediate")) 1049 R = R->getValueAsDef("type"); 1050 else if (R->isSubClassOf("unpromoted")) 1051 R = R->getValueAsDef("underlying_type"); 1052 1053 if (R->getName() == "Void") 1054 return getVoidType(); 1055 if (R->isSubClassOf("PrimitiveType")) 1056 return getScalarType(R); 1057 if (R->isSubClassOf("ComplexType")) 1058 return getType(R->getValueAsDag("spec"), Param); 1059 1060 PrintFatalError(R->getLoc(), "Could not convert this record into a type"); 1061 } 1062 1063 const Type *MveEmitter::getType(DagInit *D, const Type *Param) { 1064 // The meat of the getType system: types in the Tablegen are represented by a 1065 // dag whose operators select sub-cases of this function. 1066 1067 Record *Op = cast<DefInit>(D->getOperator())->getDef(); 1068 if (!Op->isSubClassOf("ComplexTypeOp")) 1069 PrintFatalError( 1070 "Expected ComplexTypeOp as dag operator in type expression"); 1071 1072 if (Op->getName() == "CTO_Parameter") { 1073 if (isa<VoidType>(Param)) 1074 PrintFatalError("Parametric type in unparametrised context"); 1075 return Param; 1076 } 1077 1078 if (Op->getName() == "CTO_Vec") { 1079 const Type *Element = getType(D->getArg(0), Param); 1080 if (D->getNumArgs() == 1) { 1081 return getVectorType(cast<ScalarType>(Element)); 1082 } else { 1083 const Type *ExistingVector = getType(D->getArg(1), Param); 1084 return getVectorType(cast<ScalarType>(Element), 1085 cast<VectorType>(ExistingVector)->lanes()); 1086 } 1087 } 1088 1089 if (Op->getName() == "CTO_Pred") { 1090 const Type *Element = getType(D->getArg(0), Param); 1091 return getPredicateType(128 / Element->sizeInBits()); 1092 } 1093 1094 if (Op->isSubClassOf("CTO_Tuple")) { 1095 unsigned Registers = Op->getValueAsInt("n"); 1096 const Type *Element = getType(D->getArg(0), Param); 1097 return getMultiVectorType(Registers, cast<VectorType>(Element)); 1098 } 1099 1100 if (Op->isSubClassOf("CTO_Pointer")) { 1101 const Type *Pointee = getType(D->getArg(0), Param); 1102 return getPointerType(Pointee, Op->getValueAsBit("const")); 1103 } 1104 1105 if (Op->getName() == "CTO_CopyKind") { 1106 const ScalarType *STSize = cast<ScalarType>(getType(D->getArg(0), Param)); 1107 const ScalarType *STKind = cast<ScalarType>(getType(D->getArg(1), Param)); 1108 for (const auto &kv : ScalarTypes) { 1109 const ScalarType *RT = kv.second.get(); 1110 if (RT->kind() == STKind->kind() && RT->sizeInBits() == STSize->sizeInBits()) 1111 return RT; 1112 } 1113 PrintFatalError("Cannot find a type to satisfy CopyKind"); 1114 } 1115 1116 if (Op->isSubClassOf("CTO_ScaleSize")) { 1117 const ScalarType *STKind = cast<ScalarType>(getType(D->getArg(0), Param)); 1118 int Num = Op->getValueAsInt("num"), Denom = Op->getValueAsInt("denom"); 1119 unsigned DesiredSize = STKind->sizeInBits() * Num / Denom; 1120 for (const auto &kv : ScalarTypes) { 1121 const ScalarType *RT = kv.second.get(); 1122 if (RT->kind() == STKind->kind() && RT->sizeInBits() == DesiredSize) 1123 return RT; 1124 } 1125 PrintFatalError("Cannot find a type to satisfy ScaleSize"); 1126 } 1127 1128 PrintFatalError("Bad operator in type dag expression"); 1129 } 1130 1131 Result::Ptr MveEmitter::getCodeForDag(DagInit *D, const Result::Scope &Scope, 1132 const Type *Param) { 1133 Record *Op = cast<DefInit>(D->getOperator())->getDef(); 1134 1135 if (Op->getName() == "seq") { 1136 Result::Scope SubScope = Scope; 1137 Result::Ptr PrevV = nullptr; 1138 for (unsigned i = 0, e = D->getNumArgs(); i < e; ++i) { 1139 // We don't use getCodeForDagArg here, because the argument name 1140 // has different semantics in a seq 1141 Result::Ptr V = 1142 getCodeForDag(cast<DagInit>(D->getArg(i)), SubScope, Param); 1143 StringRef ArgName = D->getArgNameStr(i); 1144 if (!ArgName.empty()) 1145 SubScope[std::string(ArgName)] = V; 1146 if (PrevV) 1147 V->setPredecessor(PrevV); 1148 PrevV = V; 1149 } 1150 return PrevV; 1151 } else if (Op->isSubClassOf("Type")) { 1152 if (D->getNumArgs() != 1) 1153 PrintFatalError("Type casts should have exactly one argument"); 1154 const Type *CastType = getType(Op, Param); 1155 Result::Ptr Arg = getCodeForDagArg(D, 0, Scope, Param); 1156 if (const auto *ST = dyn_cast<ScalarType>(CastType)) { 1157 if (!ST->requiresFloat()) { 1158 if (Arg->hasIntegerConstantValue()) 1159 return std::make_shared<IntLiteralResult>( 1160 ST, Arg->integerConstantValue()); 1161 else 1162 return std::make_shared<IntCastResult>(ST, Arg); 1163 } 1164 } else if (const auto *PT = dyn_cast<PointerType>(CastType)) { 1165 return std::make_shared<PointerCastResult>(PT, Arg); 1166 } 1167 PrintFatalError("Unsupported type cast"); 1168 } else if (Op->getName() == "address") { 1169 if (D->getNumArgs() != 2) 1170 PrintFatalError("'address' should have two arguments"); 1171 Result::Ptr Arg = getCodeForDagArg(D, 0, Scope, Param); 1172 unsigned Alignment; 1173 if (auto *II = dyn_cast<IntInit>(D->getArg(1))) { 1174 Alignment = II->getValue(); 1175 } else { 1176 PrintFatalError("'address' alignment argument should be an integer"); 1177 } 1178 return std::make_shared<AddressResult>(Arg, Alignment); 1179 } else if (Op->getName() == "unsignedflag") { 1180 if (D->getNumArgs() != 1) 1181 PrintFatalError("unsignedflag should have exactly one argument"); 1182 Record *TypeRec = cast<DefInit>(D->getArg(0))->getDef(); 1183 if (!TypeRec->isSubClassOf("Type")) 1184 PrintFatalError("unsignedflag's argument should be a type"); 1185 if (const auto *ST = dyn_cast<ScalarType>(getType(TypeRec, Param))) { 1186 return std::make_shared<IntLiteralResult>( 1187 getScalarType("u32"), ST->kind() == ScalarTypeKind::UnsignedInt); 1188 } else { 1189 PrintFatalError("unsignedflag's argument should be a scalar type"); 1190 } 1191 } else { 1192 std::vector<Result::Ptr> Args; 1193 for (unsigned i = 0, e = D->getNumArgs(); i < e; ++i) 1194 Args.push_back(getCodeForDagArg(D, i, Scope, Param)); 1195 if (Op->isSubClassOf("IRBuilderBase")) { 1196 std::set<unsigned> AddressArgs; 1197 std::map<unsigned, std::string> IntegerArgs; 1198 for (Record *sp : Op->getValueAsListOfDefs("special_params")) { 1199 unsigned Index = sp->getValueAsInt("index"); 1200 if (sp->isSubClassOf("IRBuilderAddrParam")) { 1201 AddressArgs.insert(Index); 1202 } else if (sp->isSubClassOf("IRBuilderIntParam")) { 1203 IntegerArgs[Index] = std::string(sp->getValueAsString("type")); 1204 } 1205 } 1206 return std::make_shared<IRBuilderResult>(Op->getValueAsString("prefix"), 1207 Args, AddressArgs, IntegerArgs); 1208 } else if (Op->isSubClassOf("IRIntBase")) { 1209 std::vector<const Type *> ParamTypes; 1210 for (Record *RParam : Op->getValueAsListOfDefs("params")) 1211 ParamTypes.push_back(getType(RParam, Param)); 1212 std::string IntName = std::string(Op->getValueAsString("intname")); 1213 if (Op->getValueAsBit("appendKind")) 1214 IntName += "_" + toLetter(cast<ScalarType>(Param)->kind()); 1215 return std::make_shared<IRIntrinsicResult>(IntName, ParamTypes, Args); 1216 } else { 1217 PrintFatalError("Unsupported dag node " + Op->getName()); 1218 } 1219 } 1220 } 1221 1222 Result::Ptr MveEmitter::getCodeForDagArg(DagInit *D, unsigned ArgNum, 1223 const Result::Scope &Scope, 1224 const Type *Param) { 1225 Init *Arg = D->getArg(ArgNum); 1226 StringRef Name = D->getArgNameStr(ArgNum); 1227 1228 if (!Name.empty()) { 1229 if (!isa<UnsetInit>(Arg)) 1230 PrintFatalError( 1231 "dag operator argument should not have both a value and a name"); 1232 auto it = Scope.find(std::string(Name)); 1233 if (it == Scope.end()) 1234 PrintFatalError("unrecognized variable name '" + Name + "'"); 1235 return it->second; 1236 } 1237 1238 if (auto *II = dyn_cast<IntInit>(Arg)) 1239 return std::make_shared<IntLiteralResult>(getScalarType("u32"), 1240 II->getValue()); 1241 1242 if (auto *DI = dyn_cast<DagInit>(Arg)) 1243 return getCodeForDag(DI, Scope, Param); 1244 1245 if (auto *DI = dyn_cast<DefInit>(Arg)) { 1246 Record *Rec = DI->getDef(); 1247 if (Rec->isSubClassOf("Type")) { 1248 const Type *T = getType(Rec, Param); 1249 return std::make_shared<TypeResult>(T); 1250 } 1251 } 1252 1253 PrintFatalError("bad dag argument type for code generation"); 1254 } 1255 1256 Result::Ptr MveEmitter::getCodeForArg(unsigned ArgNum, const Type *ArgType, 1257 bool Promote, bool Immediate) { 1258 Result::Ptr V = std::make_shared<BuiltinArgResult>( 1259 ArgNum, isa<PointerType>(ArgType), Immediate); 1260 1261 if (Promote) { 1262 if (const auto *ST = dyn_cast<ScalarType>(ArgType)) { 1263 if (ST->isInteger() && ST->sizeInBits() < 32) 1264 V = std::make_shared<IntCastResult>(getScalarType("u32"), V); 1265 } else if (const auto *PT = dyn_cast<PredicateType>(ArgType)) { 1266 V = std::make_shared<IntCastResult>(getScalarType("u32"), V); 1267 V = std::make_shared<IRIntrinsicResult>("arm_mve_pred_i2v", 1268 std::vector<const Type *>{PT}, 1269 std::vector<Result::Ptr>{V}); 1270 } 1271 } 1272 1273 return V; 1274 } 1275 1276 ACLEIntrinsic::ACLEIntrinsic(MveEmitter &ME, Record *R, const Type *Param) 1277 : ReturnType(ME.getType(R->getValueAsDef("ret"), Param)) { 1278 // Derive the intrinsic's full name, by taking the name of the 1279 // Tablegen record (or override) and appending the suffix from its 1280 // parameter type. (If the intrinsic is unparametrised, its 1281 // parameter type will be given as Void, which returns the empty 1282 // string for acleSuffix.) 1283 StringRef BaseName = 1284 (R->isSubClassOf("NameOverride") ? R->getValueAsString("basename") 1285 : R->getName()); 1286 StringRef overrideLetter = R->getValueAsString("overrideKindLetter"); 1287 FullName = 1288 (Twine(BaseName) + Param->acleSuffix(std::string(overrideLetter))).str(); 1289 1290 // Derive the intrinsic's polymorphic name, by removing components from the 1291 // full name as specified by its 'pnt' member ('polymorphic name type'), 1292 // which indicates how many type suffixes to remove, and any other piece of 1293 // the name that should be removed. 1294 Record *PolymorphicNameType = R->getValueAsDef("pnt"); 1295 SmallVector<StringRef, 8> NameParts; 1296 StringRef(FullName).split(NameParts, '_'); 1297 for (unsigned i = 0, e = PolymorphicNameType->getValueAsInt( 1298 "NumTypeSuffixesToDiscard"); 1299 i < e; ++i) 1300 NameParts.pop_back(); 1301 if (!PolymorphicNameType->isValueUnset("ExtraSuffixToDiscard")) { 1302 StringRef ExtraSuffix = 1303 PolymorphicNameType->getValueAsString("ExtraSuffixToDiscard"); 1304 auto it = NameParts.end(); 1305 while (it != NameParts.begin()) { 1306 --it; 1307 if (*it == ExtraSuffix) { 1308 NameParts.erase(it); 1309 break; 1310 } 1311 } 1312 } 1313 ShortName = join(std::begin(NameParts), std::end(NameParts), "_"); 1314 1315 PolymorphicOnly = R->getValueAsBit("polymorphicOnly"); 1316 NonEvaluating = R->getValueAsBit("nonEvaluating"); 1317 1318 // Process the intrinsic's argument list. 1319 DagInit *ArgsDag = R->getValueAsDag("args"); 1320 Result::Scope Scope; 1321 for (unsigned i = 0, e = ArgsDag->getNumArgs(); i < e; ++i) { 1322 Init *TypeInit = ArgsDag->getArg(i); 1323 1324 bool Promote = true; 1325 if (auto TypeDI = dyn_cast<DefInit>(TypeInit)) 1326 if (TypeDI->getDef()->isSubClassOf("unpromoted")) 1327 Promote = false; 1328 1329 // Work out the type of the argument, for use in the function prototype in 1330 // the header file. 1331 const Type *ArgType = ME.getType(TypeInit, Param); 1332 ArgTypes.push_back(ArgType); 1333 1334 // If the argument is a subclass of Immediate, record the details about 1335 // what values it can take, for Sema checking. 1336 bool Immediate = false; 1337 if (auto TypeDI = dyn_cast<DefInit>(TypeInit)) { 1338 Record *TypeRec = TypeDI->getDef(); 1339 if (TypeRec->isSubClassOf("Immediate")) { 1340 Immediate = true; 1341 1342 Record *Bounds = TypeRec->getValueAsDef("bounds"); 1343 ImmediateArg &IA = ImmediateArgs[i]; 1344 if (Bounds->isSubClassOf("IB_ConstRange")) { 1345 IA.boundsType = ImmediateArg::BoundsType::ExplicitRange; 1346 IA.i1 = Bounds->getValueAsInt("lo"); 1347 IA.i2 = Bounds->getValueAsInt("hi"); 1348 } else if (Bounds->getName() == "IB_UEltValue") { 1349 IA.boundsType = ImmediateArg::BoundsType::UInt; 1350 IA.i1 = Param->sizeInBits(); 1351 } else if (Bounds->getName() == "IB_LaneIndex") { 1352 IA.boundsType = ImmediateArg::BoundsType::ExplicitRange; 1353 IA.i1 = 0; 1354 IA.i2 = 128 / Param->sizeInBits() - 1; 1355 } else if (Bounds->isSubClassOf("IB_EltBit")) { 1356 IA.boundsType = ImmediateArg::BoundsType::ExplicitRange; 1357 IA.i1 = Bounds->getValueAsInt("base"); 1358 const Type *T = ME.getType(Bounds->getValueAsDef("type"), Param); 1359 IA.i2 = IA.i1 + T->sizeInBits() - 1; 1360 } else { 1361 PrintFatalError("unrecognised ImmediateBounds subclass"); 1362 } 1363 1364 IA.ArgType = ArgType; 1365 1366 if (!TypeRec->isValueUnset("extra")) { 1367 IA.ExtraCheckType = TypeRec->getValueAsString("extra"); 1368 if (!TypeRec->isValueUnset("extraarg")) 1369 IA.ExtraCheckArgs = TypeRec->getValueAsString("extraarg"); 1370 } 1371 } 1372 } 1373 1374 // The argument will usually have a name in the arguments dag, which goes 1375 // into the variable-name scope that the code gen will refer to. 1376 StringRef ArgName = ArgsDag->getArgNameStr(i); 1377 if (!ArgName.empty()) 1378 Scope[std::string(ArgName)] = 1379 ME.getCodeForArg(i, ArgType, Promote, Immediate); 1380 } 1381 1382 // Finally, go through the codegen dag and translate it into a Result object 1383 // (with an arbitrary DAG of depended-on Results hanging off it). 1384 DagInit *CodeDag = R->getValueAsDag("codegen"); 1385 Record *MainOp = cast<DefInit>(CodeDag->getOperator())->getDef(); 1386 if (MainOp->isSubClassOf("CustomCodegen")) { 1387 // Or, if it's the special case of CustomCodegen, just accumulate 1388 // a list of parameters we're going to assign to variables before 1389 // breaking from the loop. 1390 CustomCodeGenArgs["CustomCodeGenType"] = 1391 (Twine("CustomCodeGen::") + MainOp->getValueAsString("type")).str(); 1392 for (unsigned i = 0, e = CodeDag->getNumArgs(); i < e; ++i) { 1393 StringRef Name = CodeDag->getArgNameStr(i); 1394 if (Name.empty()) { 1395 PrintFatalError("Operands to CustomCodegen should have names"); 1396 } else if (auto *II = dyn_cast<IntInit>(CodeDag->getArg(i))) { 1397 CustomCodeGenArgs[std::string(Name)] = itostr(II->getValue()); 1398 } else if (auto *SI = dyn_cast<StringInit>(CodeDag->getArg(i))) { 1399 CustomCodeGenArgs[std::string(Name)] = std::string(SI->getValue()); 1400 } else { 1401 PrintFatalError("Operands to CustomCodegen should be integers"); 1402 } 1403 } 1404 } else { 1405 Code = ME.getCodeForDag(CodeDag, Scope, Param); 1406 } 1407 } 1408 1409 MveEmitter::MveEmitter(RecordKeeper &Records) { 1410 // Construct the whole MveEmitter. 1411 1412 // First, look up all the instances of PrimitiveType. This gives us the list 1413 // of vector typedefs we have to put in arm_mve.h, and also allows us to 1414 // collect all the useful ScalarType instances into a big list so that we can 1415 // use it for operations such as 'find the unsigned version of this signed 1416 // integer type'. 1417 for (Record *R : Records.getAllDerivedDefinitions("PrimitiveType")) 1418 ScalarTypes[std::string(R->getName())] = std::make_unique<ScalarType>(R); 1419 1420 // Now go through the instances of Intrinsic, and for each one, iterate 1421 // through its list of type parameters making an ACLEIntrinsic for each one. 1422 for (Record *R : Records.getAllDerivedDefinitions("Intrinsic")) { 1423 for (Record *RParam : R->getValueAsListOfDefs("params")) { 1424 const Type *Param = getType(RParam, getVoidType()); 1425 auto Intrinsic = std::make_unique<ACLEIntrinsic>(*this, R, Param); 1426 ACLEIntrinsics[Intrinsic->fullName()] = std::move(Intrinsic); 1427 } 1428 } 1429 } 1430 1431 /// A wrapper on raw_string_ostream that contains its own buffer rather than 1432 /// having to point it at one elsewhere. (In other words, it works just like 1433 /// std::ostringstream; also, this makes it convenient to declare a whole array 1434 /// of them at once.) 1435 /// 1436 /// We have to set this up using multiple inheritance, to ensure that the 1437 /// string member has been constructed before raw_string_ostream's constructor 1438 /// is given a pointer to it. 1439 class string_holder { 1440 protected: 1441 std::string S; 1442 }; 1443 class raw_self_contained_string_ostream : private string_holder, 1444 public raw_string_ostream { 1445 public: 1446 raw_self_contained_string_ostream() 1447 : string_holder(), raw_string_ostream(S) {} 1448 }; 1449 1450 void MveEmitter::EmitHeader(raw_ostream &OS) { 1451 // Accumulate pieces of the header file that will be enabled under various 1452 // different combinations of #ifdef. The index into parts[] is made up of 1453 // the following bit flags. 1454 constexpr unsigned Float = 1; 1455 constexpr unsigned UseUserNamespace = 2; 1456 1457 constexpr unsigned NumParts = 4; 1458 raw_self_contained_string_ostream parts[NumParts]; 1459 1460 // Write typedefs for all the required vector types, and a few scalar 1461 // types that don't already have the name we want them to have. 1462 1463 parts[0] << "typedef uint16_t mve_pred16_t;\n"; 1464 parts[Float] << "typedef __fp16 float16_t;\n" 1465 "typedef float float32_t;\n"; 1466 for (const auto &kv : ScalarTypes) { 1467 const ScalarType *ST = kv.second.get(); 1468 if (ST->hasNonstandardName()) 1469 continue; 1470 raw_ostream &OS = parts[ST->requiresFloat() ? Float : 0]; 1471 const VectorType *VT = getVectorType(ST); 1472 1473 OS << "typedef __attribute__((__neon_vector_type__(" << VT->lanes() 1474 << "), __clang_arm_mve_strict_polymorphism)) " << ST->cName() << " " 1475 << VT->cName() << ";\n"; 1476 1477 // Every vector type also comes with a pair of multi-vector types for 1478 // the VLD2 and VLD4 instructions. 1479 for (unsigned n = 2; n <= 4; n += 2) { 1480 const MultiVectorType *MT = getMultiVectorType(n, VT); 1481 OS << "typedef struct { " << VT->cName() << " val[" << n << "]; } " 1482 << MT->cName() << ";\n"; 1483 } 1484 } 1485 parts[0] << "\n"; 1486 parts[Float] << "\n"; 1487 1488 // Write declarations for all the intrinsics. 1489 1490 for (const auto &kv : ACLEIntrinsics) { 1491 const ACLEIntrinsic &Int = *kv.second; 1492 1493 // We generate each intrinsic twice, under its full unambiguous 1494 // name and its shorter polymorphic name (if the latter exists). 1495 for (bool Polymorphic : {false, true}) { 1496 if (Polymorphic && !Int.polymorphic()) 1497 continue; 1498 if (!Polymorphic && Int.polymorphicOnly()) 1499 continue; 1500 1501 // We also generate each intrinsic under a name like __arm_vfooq 1502 // (which is in C language implementation namespace, so it's 1503 // safe to define in any conforming user program) and a shorter 1504 // one like vfooq (which is in user namespace, so a user might 1505 // reasonably have used it for something already). If so, they 1506 // can #define __ARM_MVE_PRESERVE_USER_NAMESPACE before 1507 // including the header, which will suppress the shorter names 1508 // and leave only the implementation-namespace ones. Then they 1509 // have to write __arm_vfooq everywhere, of course. 1510 1511 for (bool UserNamespace : {false, true}) { 1512 raw_ostream &OS = parts[(Int.requiresFloat() ? Float : 0) | 1513 (UserNamespace ? UseUserNamespace : 0)]; 1514 1515 // Make the name of the function in this declaration. 1516 1517 std::string FunctionName = 1518 Polymorphic ? Int.shortName() : Int.fullName(); 1519 if (!UserNamespace) 1520 FunctionName = "__arm_" + FunctionName; 1521 1522 // Make strings for the types involved in the function's 1523 // prototype. 1524 1525 std::string RetTypeName = Int.returnType()->cName(); 1526 if (!StringRef(RetTypeName).endswith("*")) 1527 RetTypeName += " "; 1528 1529 std::vector<std::string> ArgTypeNames; 1530 for (const Type *ArgTypePtr : Int.argTypes()) 1531 ArgTypeNames.push_back(ArgTypePtr->cName()); 1532 std::string ArgTypesString = 1533 join(std::begin(ArgTypeNames), std::end(ArgTypeNames), ", "); 1534 1535 // Emit the actual declaration. All these functions are 1536 // declared 'static inline' without a body, which is fine 1537 // provided clang recognizes them as builtins, and has the 1538 // effect that this type signature is used in place of the one 1539 // that Builtins.def didn't provide. That's how we can get 1540 // structure types that weren't defined until this header was 1541 // included to be part of the type signature of a builtin that 1542 // was known to clang already. 1543 // 1544 // The declarations use __attribute__(__clang_arm_mve_alias), 1545 // so that each function declared will be recognized as the 1546 // appropriate MVE builtin in spite of its user-facing name. 1547 // 1548 // (That's better than making them all wrapper functions, 1549 // partly because it avoids any compiler error message citing 1550 // the wrapper function definition instead of the user's code, 1551 // and mostly because some MVE intrinsics have arguments 1552 // required to be compile-time constants, and that property 1553 // can't be propagated through a wrapper function. It can be 1554 // propagated through a macro, but macros can't be overloaded 1555 // on argument types very easily - you have to use _Generic, 1556 // which makes error messages very confusing when the user 1557 // gets it wrong.) 1558 // 1559 // Finally, the polymorphic versions of the intrinsics are 1560 // also defined with __attribute__(overloadable), so that when 1561 // the same name is defined with several type signatures, the 1562 // right thing happens. Each one of the overloaded 1563 // declarations is given a different builtin id, which 1564 // has exactly the effect we want: first clang resolves the 1565 // overload to the right function, then it knows which builtin 1566 // it's referring to, and then the Sema checking for that 1567 // builtin can check further things like the constant 1568 // arguments. 1569 // 1570 // One more subtlety is the newline just before the return 1571 // type name. That's a cosmetic tweak to make the error 1572 // messages legible if the user gets the types wrong in a call 1573 // to a polymorphic function: this way, clang will print just 1574 // the _final_ line of each declaration in the header, to show 1575 // the type signatures that would have been legal. So all the 1576 // confusing machinery with __attribute__ is left out of the 1577 // error message, and the user sees something that's more or 1578 // less self-documenting: "here's a list of actually readable 1579 // type signatures for vfooq(), and here's why each one didn't 1580 // match your call". 1581 1582 OS << "static __inline__ __attribute__((" 1583 << (Polymorphic ? "overloadable, " : "") 1584 << "__clang_arm_mve_alias(__builtin_arm_mve_" << Int.fullName() 1585 << ")))\n" 1586 << RetTypeName << FunctionName << "(" << ArgTypesString << ");\n"; 1587 } 1588 } 1589 } 1590 for (auto &part : parts) 1591 part << "\n"; 1592 1593 // Now we've finished accumulating bits and pieces into the parts[] array. 1594 // Put it all together to write the final output file. 1595 1596 OS << "/*===---- arm_mve.h - ARM MVE intrinsics " 1597 "-----------------------------------===\n" 1598 " *\n" 1599 " *\n" 1600 " * Part of the LLVM Project, under the Apache License v2.0 with LLVM " 1601 "Exceptions.\n" 1602 " * See https://llvm.org/LICENSE.txt for license information.\n" 1603 " * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception\n" 1604 " *\n" 1605 " *===-------------------------------------------------------------" 1606 "----" 1607 "------===\n" 1608 " */\n" 1609 "\n" 1610 "#ifndef __ARM_MVE_H\n" 1611 "#define __ARM_MVE_H\n" 1612 "\n" 1613 "#if !__ARM_FEATURE_MVE\n" 1614 "#error \"MVE support not enabled\"\n" 1615 "#endif\n" 1616 "\n" 1617 "#include <stdint.h>\n" 1618 "\n" 1619 "#ifdef __cplusplus\n" 1620 "extern \"C\" {\n" 1621 "#endif\n" 1622 "\n"; 1623 1624 for (size_t i = 0; i < NumParts; ++i) { 1625 std::vector<std::string> conditions; 1626 if (i & Float) 1627 conditions.push_back("(__ARM_FEATURE_MVE & 2)"); 1628 if (i & UseUserNamespace) 1629 conditions.push_back("(!defined __ARM_MVE_PRESERVE_USER_NAMESPACE)"); 1630 1631 std::string condition = 1632 join(std::begin(conditions), std::end(conditions), " && "); 1633 if (!condition.empty()) 1634 OS << "#if " << condition << "\n\n"; 1635 OS << parts[i].str(); 1636 if (!condition.empty()) 1637 OS << "#endif /* " << condition << " */\n\n"; 1638 } 1639 1640 OS << "#ifdef __cplusplus\n" 1641 "} /* extern \"C\" */\n" 1642 "#endif\n" 1643 "\n" 1644 "#endif /* __ARM_MVE_H */\n"; 1645 } 1646 1647 void MveEmitter::EmitBuiltinDef(raw_ostream &OS) { 1648 for (const auto &kv : ACLEIntrinsics) { 1649 const ACLEIntrinsic &Int = *kv.second; 1650 OS << "TARGET_HEADER_BUILTIN(__builtin_arm_mve_" << Int.fullName() 1651 << ", \"\", \"n\", \"arm_mve.h\", ALL_LANGUAGES, \"\")\n"; 1652 } 1653 1654 std::set<std::string> ShortNamesSeen; 1655 1656 for (const auto &kv : ACLEIntrinsics) { 1657 const ACLEIntrinsic &Int = *kv.second; 1658 if (Int.polymorphic()) { 1659 StringRef Name = Int.shortName(); 1660 if (ShortNamesSeen.find(std::string(Name)) == ShortNamesSeen.end()) { 1661 OS << "BUILTIN(__builtin_arm_mve_" << Name << ", \"vi.\", \"nt"; 1662 if (Int.nonEvaluating()) 1663 OS << "u"; // indicate that this builtin doesn't evaluate its args 1664 OS << "\")\n"; 1665 ShortNamesSeen.insert(std::string(Name)); 1666 } 1667 } 1668 } 1669 } 1670 1671 void MveEmitter::EmitBuiltinSema(raw_ostream &OS) { 1672 std::map<std::string, std::set<std::string>> Checks; 1673 1674 for (const auto &kv : ACLEIntrinsics) { 1675 const ACLEIntrinsic &Int = *kv.second; 1676 std::string Check = Int.genSema(); 1677 if (!Check.empty()) 1678 Checks[Check].insert(Int.fullName()); 1679 } 1680 1681 for (const auto &kv : Checks) { 1682 for (StringRef Name : kv.second) 1683 OS << "case ARM::BI__builtin_arm_mve_" << Name << ":\n"; 1684 OS << kv.first; 1685 } 1686 } 1687 1688 // Machinery for the grouping of intrinsics by similar codegen. 1689 // 1690 // The general setup is that 'MergeableGroup' stores the things that a set of 1691 // similarly shaped intrinsics have in common: the text of their code 1692 // generation, and the number and type of their parameter variables. 1693 // MergeableGroup is the key in a std::map whose value is a set of 1694 // OutputIntrinsic, which stores the ways in which a particular intrinsic 1695 // specializes the MergeableGroup's generic description: the function name and 1696 // the _values_ of the parameter variables. 1697 1698 struct ComparableStringVector : std::vector<std::string> { 1699 // Infrastructure: a derived class of vector<string> which comes with an 1700 // ordering, so that it can be used as a key in maps and an element in sets. 1701 // There's no requirement on the ordering beyond being deterministic. 1702 bool operator<(const ComparableStringVector &rhs) const { 1703 if (size() != rhs.size()) 1704 return size() < rhs.size(); 1705 for (size_t i = 0, e = size(); i < e; ++i) 1706 if ((*this)[i] != rhs[i]) 1707 return (*this)[i] < rhs[i]; 1708 return false; 1709 } 1710 }; 1711 1712 struct OutputIntrinsic { 1713 const ACLEIntrinsic *Int; 1714 std::string Name; 1715 ComparableStringVector ParamValues; 1716 bool operator<(const OutputIntrinsic &rhs) const { 1717 if (Name != rhs.Name) 1718 return Name < rhs.Name; 1719 return ParamValues < rhs.ParamValues; 1720 } 1721 }; 1722 struct MergeableGroup { 1723 std::string Code; 1724 ComparableStringVector ParamTypes; 1725 bool operator<(const MergeableGroup &rhs) const { 1726 if (Code != rhs.Code) 1727 return Code < rhs.Code; 1728 return ParamTypes < rhs.ParamTypes; 1729 } 1730 }; 1731 1732 void MveEmitter::EmitBuiltinCG(raw_ostream &OS) { 1733 // Pass 1: generate code for all the intrinsics as if every type or constant 1734 // that can possibly be abstracted out into a parameter variable will be. 1735 // This identifies the sets of intrinsics we'll group together into a single 1736 // piece of code generation. 1737 1738 std::map<MergeableGroup, std::set<OutputIntrinsic>> MergeableGroupsPrelim; 1739 1740 for (const auto &kv : ACLEIntrinsics) { 1741 const ACLEIntrinsic &Int = *kv.second; 1742 1743 MergeableGroup MG; 1744 OutputIntrinsic OI; 1745 1746 OI.Int = ∬ 1747 OI.Name = Int.fullName(); 1748 CodeGenParamAllocator ParamAllocPrelim{&MG.ParamTypes, &OI.ParamValues}; 1749 raw_string_ostream OS(MG.Code); 1750 Int.genCode(OS, ParamAllocPrelim, 1); 1751 OS.flush(); 1752 1753 MergeableGroupsPrelim[MG].insert(OI); 1754 } 1755 1756 // Pass 2: for each of those groups, optimize the parameter variable set by 1757 // eliminating 'parameters' that are the same for all intrinsics in the 1758 // group, and merging together pairs of parameter variables that take the 1759 // same values as each other for all intrinsics in the group. 1760 1761 std::map<MergeableGroup, std::set<OutputIntrinsic>> MergeableGroups; 1762 1763 for (const auto &kv : MergeableGroupsPrelim) { 1764 const MergeableGroup &MG = kv.first; 1765 std::vector<int> ParamNumbers; 1766 std::map<ComparableStringVector, int> ParamNumberMap; 1767 1768 // Loop over the parameters for this group. 1769 for (size_t i = 0, e = MG.ParamTypes.size(); i < e; ++i) { 1770 // Is this parameter the same for all intrinsics in the group? 1771 const OutputIntrinsic &OI_first = *kv.second.begin(); 1772 bool Constant = all_of(kv.second, [&](const OutputIntrinsic &OI) { 1773 return OI.ParamValues[i] == OI_first.ParamValues[i]; 1774 }); 1775 1776 // If so, record it as -1, meaning 'no parameter variable needed'. Then 1777 // the corresponding call to allocParam in pass 2 will not generate a 1778 // variable at all, and just use the value inline. 1779 if (Constant) { 1780 ParamNumbers.push_back(-1); 1781 continue; 1782 } 1783 1784 // Otherwise, make a list of the values this parameter takes for each 1785 // intrinsic, and see if that value vector matches anything we already 1786 // have. We also record the parameter type, so that we don't accidentally 1787 // match up two parameter variables with different types. (Not that 1788 // there's much chance of them having textually equivalent values, but in 1789 // _principle_ it could happen.) 1790 ComparableStringVector key; 1791 key.push_back(MG.ParamTypes[i]); 1792 for (const auto &OI : kv.second) 1793 key.push_back(OI.ParamValues[i]); 1794 1795 auto Found = ParamNumberMap.find(key); 1796 if (Found != ParamNumberMap.end()) { 1797 // Yes, an existing parameter variable can be reused for this. 1798 ParamNumbers.push_back(Found->second); 1799 continue; 1800 } 1801 1802 // No, we need a new parameter variable. 1803 int ExistingIndex = ParamNumberMap.size(); 1804 ParamNumberMap[key] = ExistingIndex; 1805 ParamNumbers.push_back(ExistingIndex); 1806 } 1807 1808 // Now we're ready to do the pass 2 code generation, which will emit the 1809 // reduced set of parameter variables we've just worked out. 1810 1811 for (const auto &OI_prelim : kv.second) { 1812 const ACLEIntrinsic *Int = OI_prelim.Int; 1813 1814 MergeableGroup MG; 1815 OutputIntrinsic OI; 1816 1817 OI.Int = OI_prelim.Int; 1818 OI.Name = OI_prelim.Name; 1819 CodeGenParamAllocator ParamAlloc{&MG.ParamTypes, &OI.ParamValues, 1820 &ParamNumbers}; 1821 raw_string_ostream OS(MG.Code); 1822 Int->genCode(OS, ParamAlloc, 2); 1823 OS.flush(); 1824 1825 MergeableGroups[MG].insert(OI); 1826 } 1827 } 1828 1829 // Output the actual C++ code. 1830 1831 for (const auto &kv : MergeableGroups) { 1832 const MergeableGroup &MG = kv.first; 1833 1834 // List of case statements in the main switch on BuiltinID, and an open 1835 // brace. 1836 const char *prefix = ""; 1837 for (const auto &OI : kv.second) { 1838 OS << prefix << "case ARM::BI__builtin_arm_mve_" << OI.Name << ":"; 1839 prefix = "\n"; 1840 } 1841 OS << " {\n"; 1842 1843 if (!MG.ParamTypes.empty()) { 1844 // If we've got some parameter variables, then emit their declarations... 1845 for (size_t i = 0, e = MG.ParamTypes.size(); i < e; ++i) { 1846 StringRef Type = MG.ParamTypes[i]; 1847 OS << " " << Type; 1848 if (!Type.endswith("*")) 1849 OS << " "; 1850 OS << " Param" << utostr(i) << ";\n"; 1851 } 1852 1853 // ... and an inner switch on BuiltinID that will fill them in with each 1854 // individual intrinsic's values. 1855 OS << " switch (BuiltinID) {\n"; 1856 for (const auto &OI : kv.second) { 1857 OS << " case ARM::BI__builtin_arm_mve_" << OI.Name << ":\n"; 1858 for (size_t i = 0, e = MG.ParamTypes.size(); i < e; ++i) 1859 OS << " Param" << utostr(i) << " = " << OI.ParamValues[i] << ";\n"; 1860 OS << " break;\n"; 1861 } 1862 OS << " }\n"; 1863 } 1864 1865 // And finally, output the code, and close the outer pair of braces. (The 1866 // code will always end with a 'return' statement, so we need not insert a 1867 // 'break' here.) 1868 OS << MG.Code << "}\n"; 1869 } 1870 } 1871 1872 void MveEmitter::EmitBuiltinAliases(raw_ostream &OS) { 1873 // Build a sorted table of: 1874 // - intrinsic id number 1875 // - full name 1876 // - polymorphic name or -1 1877 StringToOffsetTable StringTable; 1878 OS << "struct IntrinToName {\n" 1879 " uint32_t Id;\n" 1880 " int32_t FullName;\n" 1881 " int32_t ShortName;\n" 1882 "};\n"; 1883 OS << "static const IntrinToName Map[] = {\n"; 1884 for (const auto &kv : ACLEIntrinsics) { 1885 const ACLEIntrinsic &Int = *kv.second; 1886 int32_t ShortNameOffset = 1887 Int.polymorphic() ? StringTable.GetOrAddStringOffset(Int.shortName()) 1888 : -1; 1889 OS << " { ARM::BI__builtin_arm_mve_" << Int.fullName() << ", " 1890 << StringTable.GetOrAddStringOffset(Int.fullName()) << ", " 1891 << ShortNameOffset << "},\n"; 1892 } 1893 OS << "};\n\n"; 1894 1895 OS << "static const char IntrinNames[] = {\n"; 1896 StringTable.EmitString(OS); 1897 OS << "};\n\n"; 1898 1899 OS << "auto It = std::lower_bound(std::begin(Map), " 1900 "std::end(Map), BuiltinID,\n" 1901 " [](const IntrinToName &L, unsigned Id) {\n" 1902 " return L.Id < Id;\n" 1903 " });\n"; 1904 OS << "if (It == std::end(Map) || It->Id != BuiltinID)\n" 1905 " return false;\n"; 1906 OS << "StringRef FullName(&IntrinNames[It->FullName]);\n"; 1907 OS << "if (AliasName == FullName)\n" 1908 " return true;\n"; 1909 OS << "if (It->ShortName == -1)\n" 1910 " return false;\n"; 1911 OS << "StringRef ShortName(&IntrinNames[It->ShortName]);\n"; 1912 OS << "return AliasName == ShortName;\n"; 1913 } 1914 1915 } // namespace 1916 1917 namespace clang { 1918 1919 void EmitMveHeader(RecordKeeper &Records, raw_ostream &OS) { 1920 MveEmitter(Records).EmitHeader(OS); 1921 } 1922 1923 void EmitMveBuiltinDef(RecordKeeper &Records, raw_ostream &OS) { 1924 MveEmitter(Records).EmitBuiltinDef(OS); 1925 } 1926 1927 void EmitMveBuiltinSema(RecordKeeper &Records, raw_ostream &OS) { 1928 MveEmitter(Records).EmitBuiltinSema(OS); 1929 } 1930 1931 void EmitMveBuiltinCG(RecordKeeper &Records, raw_ostream &OS) { 1932 MveEmitter(Records).EmitBuiltinCG(OS); 1933 } 1934 1935 void EmitMveBuiltinAliases(RecordKeeper &Records, raw_ostream &OS) { 1936 MveEmitter(Records).EmitBuiltinAliases(OS); 1937 } 1938 1939 } // end namespace clang 1940