1 //===- NeonEmitter.cpp - Generate arm_neon.h for use with clang -*- C++ -*-===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 // 10 // This tablegen backend is responsible for emitting arm_neon.h, which includes 11 // a declaration and definition of each function specified by the ARM NEON 12 // compiler interface. See ARM document DUI0348B. 13 // 14 // Each NEON instruction is implemented in terms of 1 or more functions which 15 // are suffixed with the element type of the input vectors. Functions may be 16 // implemented in terms of generic vector operations such as +, *, -, etc. or 17 // by calling a __builtin_-prefixed function which will be handled by clang's 18 // CodeGen library. 19 // 20 // Additional validation code can be generated by this file when runHeader() is 21 // called, rather than the normal run() entry point. A complete set of tests 22 // for Neon intrinsics can be generated by calling the runTests() entry point. 23 // 24 //===----------------------------------------------------------------------===// 25 26 #include "llvm/ADT/DenseMap.h" 27 #include "llvm/ADT/SmallString.h" 28 #include "llvm/ADT/SmallVector.h" 29 #include "llvm/ADT/StringExtras.h" 30 #include "llvm/ADT/StringMap.h" 31 #include "llvm/Support/ErrorHandling.h" 32 #include "llvm/TableGen/Error.h" 33 #include "llvm/TableGen/Record.h" 34 #include "llvm/TableGen/TableGenBackend.h" 35 #include <string> 36 using namespace llvm; 37 38 enum OpKind { 39 OpNone, 40 OpUnavailable, 41 OpAdd, 42 OpAddl, 43 OpAddlHi, 44 OpAddw, 45 OpAddwHi, 46 OpSub, 47 OpSubl, 48 OpSublHi, 49 OpSubw, 50 OpSubwHi, 51 OpMul, 52 OpMla, 53 OpMlal, 54 OpMullHi, 55 OpMullHiP64, 56 OpMullHiN, 57 OpMlalHi, 58 OpMlalHiN, 59 OpMls, 60 OpMlsl, 61 OpMlslHi, 62 OpMlslHiN, 63 OpMulN, 64 OpMlaN, 65 OpMlsN, 66 OpFMlaN, 67 OpFMlsN, 68 OpMlalN, 69 OpMlslN, 70 OpMulLane, 71 OpMulXLane, 72 OpMullLane, 73 OpMullHiLane, 74 OpMlaLane, 75 OpMlsLane, 76 OpMlalLane, 77 OpMlalHiLane, 78 OpMlslLane, 79 OpMlslHiLane, 80 OpQDMullLane, 81 OpQDMullHiLane, 82 OpQDMlalLane, 83 OpQDMlalHiLane, 84 OpQDMlslLane, 85 OpQDMlslHiLane, 86 OpQDMulhLane, 87 OpQRDMulhLane, 88 OpFMSLane, 89 OpFMSLaneQ, 90 OpTrn1, 91 OpZip1, 92 OpUzp1, 93 OpTrn2, 94 OpZip2, 95 OpUzp2, 96 OpEq, 97 OpGe, 98 OpLe, 99 OpGt, 100 OpLt, 101 OpNeg, 102 OpNot, 103 OpAnd, 104 OpOr, 105 OpXor, 106 OpAndNot, 107 OpOrNot, 108 OpCast, 109 OpConcat, 110 OpDup, 111 OpDupLane, 112 OpHi, 113 OpLo, 114 OpSelect, 115 OpRev16, 116 OpRev32, 117 OpRev64, 118 OpXtnHi, 119 OpSqxtunHi, 120 OpQxtnHi, 121 OpFcvtnHi, 122 OpFcvtlHi, 123 OpFcvtxnHi, 124 OpReinterpret, 125 OpAddhnHi, 126 OpRAddhnHi, 127 OpSubhnHi, 128 OpRSubhnHi, 129 OpAbdl, 130 OpAbdlHi, 131 OpAba, 132 OpAbal, 133 OpAbalHi, 134 OpQDMullHi, 135 OpQDMullHiN, 136 OpQDMlalHi, 137 OpQDMlalHiN, 138 OpQDMlslHi, 139 OpQDMlslHiN, 140 OpDiv, 141 OpLongHi, 142 OpNarrowHi, 143 OpMovlHi, 144 OpCopyLane, 145 OpCopyQLane, 146 OpCopyLaneQ, 147 OpScalarMulLane, 148 OpScalarMulLaneQ, 149 OpScalarMulXLane, 150 OpScalarMulXLaneQ, 151 OpScalarVMulXLane, 152 OpScalarVMulXLaneQ, 153 OpScalarQDMullLane, 154 OpScalarQDMullLaneQ, 155 OpScalarQDMulHiLane, 156 OpScalarQDMulHiLaneQ, 157 OpScalarQRDMulHiLane, 158 OpScalarQRDMulHiLaneQ, 159 OpScalarGetLane, 160 OpScalarSetLane 161 }; 162 163 enum ClassKind { 164 ClassNone, 165 ClassI, // generic integer instruction, e.g., "i8" suffix 166 ClassS, // signed/unsigned/poly, e.g., "s8", "u8" or "p8" suffix 167 ClassW, // width-specific instruction, e.g., "8" suffix 168 ClassB, // bitcast arguments with enum argument to specify type 169 ClassL, // Logical instructions which are op instructions 170 // but we need to not emit any suffix for in our 171 // tests. 172 ClassNoTest // Instructions which we do not test since they are 173 // not TRUE instructions. 174 }; 175 176 /// NeonTypeFlags - Flags to identify the types for overloaded Neon 177 /// builtins. These must be kept in sync with the flags in 178 /// include/clang/Basic/TargetBuiltins.h. 179 namespace { 180 class NeonTypeFlags { 181 enum { 182 EltTypeMask = 0xf, 183 UnsignedFlag = 0x10, 184 QuadFlag = 0x20 185 }; 186 uint32_t Flags; 187 188 public: 189 enum EltType { 190 Int8, 191 Int16, 192 Int32, 193 Int64, 194 Poly8, 195 Poly16, 196 Poly64, 197 Poly128, 198 Float16, 199 Float32, 200 Float64 201 }; 202 203 NeonTypeFlags(unsigned F) : Flags(F) {} 204 NeonTypeFlags(EltType ET, bool IsUnsigned, bool IsQuad) : Flags(ET) { 205 if (IsUnsigned) 206 Flags |= UnsignedFlag; 207 if (IsQuad) 208 Flags |= QuadFlag; 209 } 210 211 uint32_t getFlags() const { return Flags; } 212 }; 213 } // end anonymous namespace 214 215 namespace { 216 class NeonEmitter { 217 RecordKeeper &Records; 218 StringMap<OpKind> OpMap; 219 DenseMap<Record*, ClassKind> ClassMap; 220 221 public: 222 NeonEmitter(RecordKeeper &R) : Records(R) { 223 OpMap["OP_NONE"] = OpNone; 224 OpMap["OP_UNAVAILABLE"] = OpUnavailable; 225 OpMap["OP_ADD"] = OpAdd; 226 OpMap["OP_ADDL"] = OpAddl; 227 OpMap["OP_ADDLHi"] = OpAddlHi; 228 OpMap["OP_ADDW"] = OpAddw; 229 OpMap["OP_ADDWHi"] = OpAddwHi; 230 OpMap["OP_SUB"] = OpSub; 231 OpMap["OP_SUBL"] = OpSubl; 232 OpMap["OP_SUBLHi"] = OpSublHi; 233 OpMap["OP_SUBW"] = OpSubw; 234 OpMap["OP_SUBWHi"] = OpSubwHi; 235 OpMap["OP_MUL"] = OpMul; 236 OpMap["OP_MLA"] = OpMla; 237 OpMap["OP_MLAL"] = OpMlal; 238 OpMap["OP_MULLHi"] = OpMullHi; 239 OpMap["OP_MULLHi_P64"] = OpMullHiP64; 240 OpMap["OP_MULLHi_N"] = OpMullHiN; 241 OpMap["OP_MLALHi"] = OpMlalHi; 242 OpMap["OP_MLALHi_N"] = OpMlalHiN; 243 OpMap["OP_MLS"] = OpMls; 244 OpMap["OP_MLSL"] = OpMlsl; 245 OpMap["OP_MLSLHi"] = OpMlslHi; 246 OpMap["OP_MLSLHi_N"] = OpMlslHiN; 247 OpMap["OP_MUL_N"] = OpMulN; 248 OpMap["OP_MLA_N"] = OpMlaN; 249 OpMap["OP_MLS_N"] = OpMlsN; 250 OpMap["OP_FMLA_N"] = OpFMlaN; 251 OpMap["OP_FMLS_N"] = OpFMlsN; 252 OpMap["OP_MLAL_N"] = OpMlalN; 253 OpMap["OP_MLSL_N"] = OpMlslN; 254 OpMap["OP_MUL_LN"]= OpMulLane; 255 OpMap["OP_MULX_LN"]= OpMulXLane; 256 OpMap["OP_MULL_LN"] = OpMullLane; 257 OpMap["OP_MULLHi_LN"] = OpMullHiLane; 258 OpMap["OP_MLA_LN"]= OpMlaLane; 259 OpMap["OP_MLS_LN"]= OpMlsLane; 260 OpMap["OP_MLAL_LN"] = OpMlalLane; 261 OpMap["OP_MLALHi_LN"] = OpMlalHiLane; 262 OpMap["OP_MLSL_LN"] = OpMlslLane; 263 OpMap["OP_MLSLHi_LN"] = OpMlslHiLane; 264 OpMap["OP_QDMULL_LN"] = OpQDMullLane; 265 OpMap["OP_QDMULLHi_LN"] = OpQDMullHiLane; 266 OpMap["OP_QDMLAL_LN"] = OpQDMlalLane; 267 OpMap["OP_QDMLALHi_LN"] = OpQDMlalHiLane; 268 OpMap["OP_QDMLSL_LN"] = OpQDMlslLane; 269 OpMap["OP_QDMLSLHi_LN"] = OpQDMlslHiLane; 270 OpMap["OP_QDMULH_LN"] = OpQDMulhLane; 271 OpMap["OP_QRDMULH_LN"] = OpQRDMulhLane; 272 OpMap["OP_FMS_LN"] = OpFMSLane; 273 OpMap["OP_FMS_LNQ"] = OpFMSLaneQ; 274 OpMap["OP_TRN1"] = OpTrn1; 275 OpMap["OP_ZIP1"] = OpZip1; 276 OpMap["OP_UZP1"] = OpUzp1; 277 OpMap["OP_TRN2"] = OpTrn2; 278 OpMap["OP_ZIP2"] = OpZip2; 279 OpMap["OP_UZP2"] = OpUzp2; 280 OpMap["OP_EQ"] = OpEq; 281 OpMap["OP_GE"] = OpGe; 282 OpMap["OP_LE"] = OpLe; 283 OpMap["OP_GT"] = OpGt; 284 OpMap["OP_LT"] = OpLt; 285 OpMap["OP_NEG"] = OpNeg; 286 OpMap["OP_NOT"] = OpNot; 287 OpMap["OP_AND"] = OpAnd; 288 OpMap["OP_OR"] = OpOr; 289 OpMap["OP_XOR"] = OpXor; 290 OpMap["OP_ANDN"] = OpAndNot; 291 OpMap["OP_ORN"] = OpOrNot; 292 OpMap["OP_CAST"] = OpCast; 293 OpMap["OP_CONC"] = OpConcat; 294 OpMap["OP_HI"] = OpHi; 295 OpMap["OP_LO"] = OpLo; 296 OpMap["OP_DUP"] = OpDup; 297 OpMap["OP_DUP_LN"] = OpDupLane; 298 OpMap["OP_SEL"] = OpSelect; 299 OpMap["OP_REV16"] = OpRev16; 300 OpMap["OP_REV32"] = OpRev32; 301 OpMap["OP_REV64"] = OpRev64; 302 OpMap["OP_XTN"] = OpXtnHi; 303 OpMap["OP_SQXTUN"] = OpSqxtunHi; 304 OpMap["OP_QXTN"] = OpQxtnHi; 305 OpMap["OP_VCVT_NA_HI"] = OpFcvtnHi; 306 OpMap["OP_VCVT_EX_HI"] = OpFcvtlHi; 307 OpMap["OP_VCVTX_HI"] = OpFcvtxnHi; 308 OpMap["OP_REINT"] = OpReinterpret; 309 OpMap["OP_ADDHNHi"] = OpAddhnHi; 310 OpMap["OP_RADDHNHi"] = OpRAddhnHi; 311 OpMap["OP_SUBHNHi"] = OpSubhnHi; 312 OpMap["OP_RSUBHNHi"] = OpRSubhnHi; 313 OpMap["OP_ABDL"] = OpAbdl; 314 OpMap["OP_ABDLHi"] = OpAbdlHi; 315 OpMap["OP_ABA"] = OpAba; 316 OpMap["OP_ABAL"] = OpAbal; 317 OpMap["OP_ABALHi"] = OpAbalHi; 318 OpMap["OP_QDMULLHi"] = OpQDMullHi; 319 OpMap["OP_QDMULLHi_N"] = OpQDMullHiN; 320 OpMap["OP_QDMLALHi"] = OpQDMlalHi; 321 OpMap["OP_QDMLALHi_N"] = OpQDMlalHiN; 322 OpMap["OP_QDMLSLHi"] = OpQDMlslHi; 323 OpMap["OP_QDMLSLHi_N"] = OpQDMlslHiN; 324 OpMap["OP_DIV"] = OpDiv; 325 OpMap["OP_LONG_HI"] = OpLongHi; 326 OpMap["OP_NARROW_HI"] = OpNarrowHi; 327 OpMap["OP_MOVL_HI"] = OpMovlHi; 328 OpMap["OP_COPY_LN"] = OpCopyLane; 329 OpMap["OP_COPYQ_LN"] = OpCopyQLane; 330 OpMap["OP_COPY_LNQ"] = OpCopyLaneQ; 331 OpMap["OP_SCALAR_MUL_LN"]= OpScalarMulLane; 332 OpMap["OP_SCALAR_MUL_LNQ"]= OpScalarMulLaneQ; 333 OpMap["OP_SCALAR_MULX_LN"]= OpScalarMulXLane; 334 OpMap["OP_SCALAR_MULX_LNQ"]= OpScalarMulXLaneQ; 335 OpMap["OP_SCALAR_VMULX_LN"]= OpScalarVMulXLane; 336 OpMap["OP_SCALAR_VMULX_LNQ"]= OpScalarVMulXLaneQ; 337 OpMap["OP_SCALAR_QDMULL_LN"] = OpScalarQDMullLane; 338 OpMap["OP_SCALAR_QDMULL_LNQ"] = OpScalarQDMullLaneQ; 339 OpMap["OP_SCALAR_QDMULH_LN"] = OpScalarQDMulHiLane; 340 OpMap["OP_SCALAR_QDMULH_LNQ"] = OpScalarQDMulHiLaneQ; 341 OpMap["OP_SCALAR_QRDMULH_LN"] = OpScalarQRDMulHiLane; 342 OpMap["OP_SCALAR_QRDMULH_LNQ"] = OpScalarQRDMulHiLaneQ; 343 OpMap["OP_SCALAR_GET_LN"] = OpScalarGetLane; 344 OpMap["OP_SCALAR_SET_LN"] = OpScalarSetLane; 345 346 Record *SI = R.getClass("SInst"); 347 Record *II = R.getClass("IInst"); 348 Record *WI = R.getClass("WInst"); 349 Record *SOpI = R.getClass("SOpInst"); 350 Record *IOpI = R.getClass("IOpInst"); 351 Record *WOpI = R.getClass("WOpInst"); 352 Record *LOpI = R.getClass("LOpInst"); 353 Record *NoTestOpI = R.getClass("NoTestOpInst"); 354 355 ClassMap[SI] = ClassS; 356 ClassMap[II] = ClassI; 357 ClassMap[WI] = ClassW; 358 ClassMap[SOpI] = ClassS; 359 ClassMap[IOpI] = ClassI; 360 ClassMap[WOpI] = ClassW; 361 ClassMap[LOpI] = ClassL; 362 ClassMap[NoTestOpI] = ClassNoTest; 363 } 364 365 // run - Emit arm_neon.h.inc 366 void run(raw_ostream &o); 367 368 // runHeader - Emit all the __builtin prototypes used in arm_neon.h 369 void runHeader(raw_ostream &o); 370 371 // runTests - Emit tests for all the Neon intrinsics. 372 void runTests(raw_ostream &o); 373 374 private: 375 void emitIntrinsic(raw_ostream &OS, Record *R, 376 StringMap<ClassKind> &EmittedMap); 377 void genBuiltinsDef(raw_ostream &OS); 378 void genOverloadTypeCheckCode(raw_ostream &OS, 379 StringMap<ClassKind> &A64IntrinsicMap, 380 bool isA64TypeCheck); 381 void genIntrinsicRangeCheckCode(raw_ostream &OS, 382 StringMap<ClassKind> &A64IntrinsicMap, 383 bool isA64RangeCheck); 384 void genTargetTest(raw_ostream &OS, StringMap<OpKind> &EmittedMap, 385 bool isA64TestGen); 386 }; 387 } // end anonymous namespace 388 389 /// ParseTypes - break down a string such as "fQf" into a vector of StringRefs, 390 /// which each StringRef representing a single type declared in the string. 391 /// for "fQf" we would end up with 2 StringRefs, "f", and "Qf", representing 392 /// 2xfloat and 4xfloat respectively. 393 static void ParseTypes(Record *r, std::string &s, 394 SmallVectorImpl<StringRef> &TV) { 395 const char *data = s.data(); 396 int len = 0; 397 398 for (unsigned i = 0, e = s.size(); i != e; ++i, ++len) { 399 if (data[len] == 'P' || data[len] == 'Q' || data[len] == 'U' 400 || data[len] == 'H' || data[len] == 'S') 401 continue; 402 403 switch (data[len]) { 404 case 'c': 405 case 's': 406 case 'i': 407 case 'l': 408 case 'k': 409 case 'h': 410 case 'f': 411 case 'd': 412 break; 413 default: 414 PrintFatalError(r->getLoc(), 415 "Unexpected letter: " + std::string(data + len, 1)); 416 } 417 TV.push_back(StringRef(data, len + 1)); 418 data += len + 1; 419 len = -1; 420 } 421 } 422 423 /// Widen - Convert a type code into the next wider type. char -> short, 424 /// short -> int, etc. 425 static char Widen(const char t) { 426 switch (t) { 427 case 'c': 428 return 's'; 429 case 's': 430 return 'i'; 431 case 'i': 432 return 'l'; 433 case 'l': 434 return 'k'; 435 case 'h': 436 return 'f'; 437 case 'f': 438 return 'd'; 439 default: 440 PrintFatalError("unhandled type in widen!"); 441 } 442 } 443 444 /// Narrow - Convert a type code into the next smaller type. short -> char, 445 /// float -> half float, etc. 446 static char Narrow(const char t) { 447 switch (t) { 448 case 's': 449 return 'c'; 450 case 'i': 451 return 's'; 452 case 'l': 453 return 'i'; 454 case 'k': 455 return 'l'; 456 case 'f': 457 return 'h'; 458 case 'd': 459 return 'f'; 460 default: 461 PrintFatalError("unhandled type in narrow!"); 462 } 463 } 464 465 static std::string GetNarrowTypestr(StringRef ty) 466 { 467 std::string s; 468 for (size_t i = 0, end = ty.size(); i < end; i++) { 469 switch (ty[i]) { 470 case 's': 471 s += 'c'; 472 break; 473 case 'i': 474 s += 's'; 475 break; 476 case 'l': 477 s += 'i'; 478 break; 479 case 'k': 480 s += 'l'; 481 break; 482 default: 483 s += ty[i]; 484 break; 485 } 486 } 487 488 return s; 489 } 490 491 /// For a particular StringRef, return the base type code, and whether it has 492 /// the quad-vector, polynomial, or unsigned modifiers set. 493 static char ClassifyType(StringRef ty, bool &quad, bool &poly, bool &usgn) { 494 unsigned off = 0; 495 // ignore scalar. 496 if (ty[off] == 'S') { 497 ++off; 498 } 499 // remember quad. 500 if (ty[off] == 'Q' || ty[off] == 'H') { 501 quad = true; 502 ++off; 503 } 504 505 // remember poly. 506 if (ty[off] == 'P') { 507 poly = true; 508 ++off; 509 } 510 511 // remember unsigned. 512 if (ty[off] == 'U') { 513 usgn = true; 514 ++off; 515 } 516 517 // base type to get the type string for. 518 return ty[off]; 519 } 520 521 /// ModType - Transform a type code and its modifiers based on a mod code. The 522 /// mod code definitions may be found at the top of arm_neon.td. 523 static char ModType(const char mod, char type, bool &quad, bool &poly, 524 bool &usgn, bool &scal, bool &cnst, bool &pntr) { 525 switch (mod) { 526 case 't': 527 if (poly) { 528 poly = false; 529 usgn = true; 530 } 531 break; 532 case 'b': 533 scal = true; 534 case 'u': 535 usgn = true; 536 poly = false; 537 if (type == 'f') 538 type = 'i'; 539 if (type == 'd') 540 type = 'l'; 541 break; 542 case '$': 543 scal = true; 544 case 'x': 545 usgn = false; 546 poly = false; 547 if (type == 'f') 548 type = 'i'; 549 if (type == 'd') 550 type = 'l'; 551 break; 552 case 'o': 553 scal = true; 554 type = 'd'; 555 usgn = false; 556 break; 557 case 'y': 558 scal = true; 559 case 'f': 560 if (type == 'h') 561 quad = true; 562 type = 'f'; 563 usgn = false; 564 break; 565 case 'F': 566 type = 'd'; 567 usgn = false; 568 break; 569 case 'g': 570 quad = false; 571 break; 572 case 'B': 573 case 'C': 574 case 'D': 575 case 'j': 576 quad = true; 577 break; 578 case 'w': 579 type = Widen(type); 580 quad = true; 581 break; 582 case 'n': 583 type = Widen(type); 584 break; 585 case 'i': 586 type = 'i'; 587 scal = true; 588 break; 589 case 'l': 590 type = 'l'; 591 scal = true; 592 usgn = true; 593 break; 594 case 'z': 595 type = Narrow(type); 596 scal = true; 597 break; 598 case 'r': 599 type = Widen(type); 600 scal = true; 601 break; 602 case 's': 603 case 'a': 604 scal = true; 605 break; 606 case 'k': 607 quad = true; 608 break; 609 case 'c': 610 cnst = true; 611 case 'p': 612 pntr = true; 613 scal = true; 614 break; 615 case 'h': 616 type = Narrow(type); 617 if (type == 'h') 618 quad = false; 619 break; 620 case 'q': 621 type = Narrow(type); 622 quad = true; 623 break; 624 case 'e': 625 type = Narrow(type); 626 usgn = true; 627 break; 628 case 'm': 629 type = Narrow(type); 630 quad = false; 631 break; 632 default: 633 break; 634 } 635 return type; 636 } 637 638 static bool IsMultiVecProto(const char p) { 639 return ((p >= '2' && p <= '4') || (p >= 'B' && p <= 'D')); 640 } 641 642 /// TypeString - for a modifier and type, generate the name of the typedef for 643 /// that type. QUc -> uint8x8_t. 644 static std::string TypeString(const char mod, StringRef typestr) { 645 bool quad = false; 646 bool poly = false; 647 bool usgn = false; 648 bool scal = false; 649 bool cnst = false; 650 bool pntr = false; 651 652 if (mod == 'v') 653 return "void"; 654 if (mod == 'i') 655 return "int"; 656 657 // base type to get the type string for. 658 char type = ClassifyType(typestr, quad, poly, usgn); 659 660 // Based on the modifying character, change the type and width if necessary. 661 type = ModType(mod, type, quad, poly, usgn, scal, cnst, pntr); 662 663 SmallString<128> s; 664 665 if (usgn) 666 s.push_back('u'); 667 668 switch (type) { 669 case 'c': 670 s += poly ? "poly8" : "int8"; 671 if (scal) 672 break; 673 s += quad ? "x16" : "x8"; 674 break; 675 case 's': 676 s += poly ? "poly16" : "int16"; 677 if (scal) 678 break; 679 s += quad ? "x8" : "x4"; 680 break; 681 case 'i': 682 s += "int32"; 683 if (scal) 684 break; 685 s += quad ? "x4" : "x2"; 686 break; 687 case 'l': 688 s += (poly && !usgn)? "poly64" : "int64"; 689 if (scal) 690 break; 691 s += quad ? "x2" : "x1"; 692 break; 693 case 'k': 694 s += "poly128"; 695 break; 696 case 'h': 697 s += "float16"; 698 if (scal) 699 break; 700 s += quad ? "x8" : "x4"; 701 break; 702 case 'f': 703 s += "float32"; 704 if (scal) 705 break; 706 s += quad ? "x4" : "x2"; 707 break; 708 case 'd': 709 s += "float64"; 710 if (scal) 711 break; 712 s += quad ? "x2" : "x1"; 713 break; 714 715 default: 716 PrintFatalError("unhandled type!"); 717 } 718 719 if (mod == '2' || mod == 'B') 720 s += "x2"; 721 if (mod == '3' || mod == 'C') 722 s += "x3"; 723 if (mod == '4' || mod == 'D') 724 s += "x4"; 725 726 // Append _t, finishing the type string typedef type. 727 s += "_t"; 728 729 if (cnst) 730 s += " const"; 731 732 if (pntr) 733 s += " *"; 734 735 return s.str(); 736 } 737 738 /// BuiltinTypeString - for a modifier and type, generate the clang 739 /// BuiltinsARM.def prototype code for the function. See the top of clang's 740 /// Builtins.def for a description of the type strings. 741 static std::string BuiltinTypeString(const char mod, StringRef typestr, 742 ClassKind ck, bool ret) { 743 bool quad = false; 744 bool poly = false; 745 bool usgn = false; 746 bool scal = false; 747 bool cnst = false; 748 bool pntr = false; 749 750 if (mod == 'v') 751 return "v"; // void 752 if (mod == 'i') 753 return "i"; // int 754 755 // base type to get the type string for. 756 char type = ClassifyType(typestr, quad, poly, usgn); 757 758 // Based on the modifying character, change the type and width if necessary. 759 type = ModType(mod, type, quad, poly, usgn, scal, cnst, pntr); 760 761 usgn = usgn | poly | ((ck == ClassI || ck == ClassW) && 762 scal && type != 'f' && type != 'd'); 763 764 // All pointers are void* pointers. Change type to 'v' now. 765 if (pntr) { 766 usgn = false; 767 poly = false; 768 type = 'v'; 769 } 770 // Treat half-float ('h') types as unsigned short ('s') types. 771 if (type == 'h') { 772 type = 's'; 773 usgn = true; 774 } 775 776 if (scal) { 777 SmallString<128> s; 778 779 if (usgn) 780 s.push_back('U'); 781 else if (type == 'c') 782 s.push_back('S'); // make chars explicitly signed 783 784 if (type == 'l') // 64-bit long 785 s += "LLi"; 786 else if (type == 'k') // 128-bit long 787 s = "LLLi"; 788 else 789 s.push_back(type); 790 791 if (cnst) 792 s.push_back('C'); 793 if (pntr) 794 s.push_back('*'); 795 return s.str(); 796 } 797 798 // Since the return value must be one type, return a vector type of the 799 // appropriate width which we will bitcast. An exception is made for 800 // returning structs of 2, 3, or 4 vectors which are returned in a sret-like 801 // fashion, storing them to a pointer arg. 802 if (ret) { 803 if (IsMultiVecProto(mod)) 804 return "vv*"; // void result with void* first argument 805 if (mod == 'f' || (ck != ClassB && type == 'f')) 806 return quad ? "V4f" : "V2f"; 807 if (mod == 'F' || (ck != ClassB && type == 'd')) 808 return quad ? "V2d" : "V1d"; 809 if (ck != ClassB && type == 's') 810 return quad ? "V8s" : "V4s"; 811 if (ck != ClassB && type == 'i') 812 return quad ? "V4i" : "V2i"; 813 if (ck != ClassB && type == 'l') 814 return quad ? "V2LLi" : "V1LLi"; 815 816 return quad ? "V16Sc" : "V8Sc"; 817 } 818 819 // Non-return array types are passed as individual vectors. 820 if (mod == '2' || mod == 'B') 821 return quad ? "V16ScV16Sc" : "V8ScV8Sc"; 822 if (mod == '3' || mod == 'C') 823 return quad ? "V16ScV16ScV16Sc" : "V8ScV8ScV8Sc"; 824 if (mod == '4' || mod == 'D') 825 return quad ? "V16ScV16ScV16ScV16Sc" : "V8ScV8ScV8ScV8Sc"; 826 827 if (mod == 'f' || (ck != ClassB && type == 'f')) 828 return quad ? "V4f" : "V2f"; 829 if (mod == 'F' || (ck != ClassB && type == 'd')) 830 return quad ? "V2d" : "V1d"; 831 if (ck != ClassB && type == 's') 832 return quad ? "V8s" : "V4s"; 833 if (ck != ClassB && type == 'i') 834 return quad ? "V4i" : "V2i"; 835 if (ck != ClassB && type == 'l') 836 return quad ? "V2LLi" : "V1LLi"; 837 838 return quad ? "V16Sc" : "V8Sc"; 839 } 840 841 /// InstructionTypeCode - Computes the ARM argument character code and 842 /// quad status for a specific type string and ClassKind. 843 static void InstructionTypeCode(const StringRef &typeStr, 844 const ClassKind ck, 845 bool &quad, 846 std::string &typeCode) { 847 bool poly = false; 848 bool usgn = false; 849 char type = ClassifyType(typeStr, quad, poly, usgn); 850 851 switch (type) { 852 case 'c': 853 switch (ck) { 854 case ClassS: typeCode = poly ? "p8" : usgn ? "u8" : "s8"; break; 855 case ClassI: typeCode = "i8"; break; 856 case ClassW: typeCode = "8"; break; 857 default: break; 858 } 859 break; 860 case 's': 861 switch (ck) { 862 case ClassS: typeCode = poly ? "p16" : usgn ? "u16" : "s16"; break; 863 case ClassI: typeCode = "i16"; break; 864 case ClassW: typeCode = "16"; break; 865 default: break; 866 } 867 break; 868 case 'i': 869 switch (ck) { 870 case ClassS: typeCode = usgn ? "u32" : "s32"; break; 871 case ClassI: typeCode = "i32"; break; 872 case ClassW: typeCode = "32"; break; 873 default: break; 874 } 875 break; 876 case 'l': 877 switch (ck) { 878 case ClassS: typeCode = poly ? "p64" : usgn ? "u64" : "s64"; break; 879 case ClassI: typeCode = "i64"; break; 880 case ClassW: typeCode = "64"; break; 881 default: break; 882 } 883 break; 884 case 'k': 885 assert(poly && "Unrecognized 128 bit integer."); 886 typeCode = "p128"; 887 break; 888 case 'h': 889 switch (ck) { 890 case ClassS: 891 case ClassI: typeCode = "f16"; break; 892 case ClassW: typeCode = "16"; break; 893 default: break; 894 } 895 break; 896 case 'f': 897 switch (ck) { 898 case ClassS: 899 case ClassI: typeCode = "f32"; break; 900 case ClassW: typeCode = "32"; break; 901 default: break; 902 } 903 break; 904 case 'd': 905 switch (ck) { 906 case ClassS: 907 case ClassI: 908 typeCode += "f64"; 909 break; 910 case ClassW: 911 PrintFatalError("unhandled type!"); 912 default: 913 break; 914 } 915 break; 916 default: 917 PrintFatalError("unhandled type!"); 918 } 919 } 920 921 static char Insert_BHSD_Suffix(StringRef typestr){ 922 unsigned off = 0; 923 if(typestr[off++] == 'S'){ 924 while(typestr[off] == 'Q' || typestr[off] == 'H'|| 925 typestr[off] == 'P' || typestr[off] == 'U') 926 ++off; 927 switch (typestr[off]){ 928 default : break; 929 case 'c' : return 'b'; 930 case 's' : return 'h'; 931 case 'i' : 932 case 'f' : return 's'; 933 case 'l' : 934 case 'd' : return 'd'; 935 } 936 } 937 return 0; 938 } 939 940 static bool endsWith_xN(std::string const &name) { 941 if (name.length() > 3) { 942 if (name.compare(name.length() - 3, 3, "_x2") == 0 || 943 name.compare(name.length() - 3, 3, "_x3") == 0 || 944 name.compare(name.length() - 3, 3, "_x4") == 0) 945 return true; 946 } 947 return false; 948 } 949 950 /// MangleName - Append a type or width suffix to a base neon function name, 951 /// and insert a 'q' in the appropriate location if type string starts with 'Q'. 952 /// E.g. turn "vst2_lane" into "vst2q_lane_f32", etc. 953 /// Insert proper 'b' 'h' 's' 'd' if prefix 'S' is used. 954 static std::string MangleName(const std::string &name, StringRef typestr, 955 ClassKind ck) { 956 if (name == "vcvt_f32_f16" || name == "vcvt_f32_f64" || 957 name == "vcvt_f64_f32") 958 return name; 959 960 bool quad = false; 961 std::string typeCode = ""; 962 963 InstructionTypeCode(typestr, ck, quad, typeCode); 964 965 std::string s = name; 966 967 if (typeCode.size() > 0) { 968 // If the name is end with _xN (N = 2,3,4), insert the typeCode before _xN. 969 if (endsWith_xN(s)) 970 s.insert(s.length() - 3, "_" + typeCode); 971 else 972 s += "_" + typeCode; 973 } 974 975 if (ck == ClassB) 976 s += "_v"; 977 978 // Insert a 'q' before the first '_' character so that it ends up before 979 // _lane or _n on vector-scalar operations. 980 if (typestr.find("Q") != StringRef::npos) { 981 size_t pos = s.find('_'); 982 s = s.insert(pos, "q"); 983 } 984 char ins = Insert_BHSD_Suffix(typestr); 985 if(ins){ 986 size_t pos = s.find('_'); 987 s = s.insert(pos, &ins, 1); 988 } 989 990 return s; 991 } 992 993 static void PreprocessInstruction(const StringRef &Name, 994 const std::string &InstName, 995 std::string &Prefix, 996 bool &HasNPostfix, 997 bool &HasLanePostfix, 998 bool &HasDupPostfix, 999 bool &IsSpecialVCvt, 1000 size_t &TBNumber) { 1001 // All of our instruction name fields from arm_neon.td are of the form 1002 // <instructionname>_... 1003 // Thus we grab our instruction name via computation of said Prefix. 1004 const size_t PrefixEnd = Name.find_first_of('_'); 1005 // If InstName is passed in, we use that instead of our name Prefix. 1006 Prefix = InstName.size() == 0? Name.slice(0, PrefixEnd).str() : InstName; 1007 1008 const StringRef Postfix = Name.slice(PrefixEnd, Name.size()); 1009 1010 HasNPostfix = Postfix.count("_n"); 1011 HasLanePostfix = Postfix.count("_lane"); 1012 HasDupPostfix = Postfix.count("_dup"); 1013 IsSpecialVCvt = Postfix.size() != 0 && Name.count("vcvt"); 1014 1015 if (InstName.compare("vtbl") == 0 || 1016 InstName.compare("vtbx") == 0) { 1017 // If we have a vtblN/vtbxN instruction, use the instruction's ASCII 1018 // encoding to get its true value. 1019 TBNumber = Name[Name.size()-1] - 48; 1020 } 1021 } 1022 1023 /// GenerateRegisterCheckPatternsForLoadStores - Given a bunch of data we have 1024 /// extracted, generate a FileCheck pattern for a Load Or Store 1025 static void 1026 GenerateRegisterCheckPatternForLoadStores(const StringRef &NameRef, 1027 const std::string& OutTypeCode, 1028 const bool &IsQuad, 1029 const bool &HasDupPostfix, 1030 const bool &HasLanePostfix, 1031 const size_t Count, 1032 std::string &RegisterSuffix) { 1033 const bool IsLDSTOne = NameRef.count("vld1") || NameRef.count("vst1"); 1034 // If N == 3 || N == 4 and we are dealing with a quad instruction, Clang 1035 // will output a series of v{ld,st}1s, so we have to handle it specially. 1036 if ((Count == 3 || Count == 4) && IsQuad) { 1037 RegisterSuffix += "{"; 1038 for (size_t i = 0; i < Count; i++) { 1039 RegisterSuffix += "d{{[0-9]+}}"; 1040 if (HasDupPostfix) { 1041 RegisterSuffix += "[]"; 1042 } 1043 if (HasLanePostfix) { 1044 RegisterSuffix += "[{{[0-9]+}}]"; 1045 } 1046 if (i < Count-1) { 1047 RegisterSuffix += ", "; 1048 } 1049 } 1050 RegisterSuffix += "}"; 1051 } else { 1052 1053 // Handle normal loads and stores. 1054 RegisterSuffix += "{"; 1055 for (size_t i = 0; i < Count; i++) { 1056 RegisterSuffix += "d{{[0-9]+}}"; 1057 if (HasDupPostfix) { 1058 RegisterSuffix += "[]"; 1059 } 1060 if (HasLanePostfix) { 1061 RegisterSuffix += "[{{[0-9]+}}]"; 1062 } 1063 if (IsQuad && !HasLanePostfix) { 1064 RegisterSuffix += ", d{{[0-9]+}}"; 1065 if (HasDupPostfix) { 1066 RegisterSuffix += "[]"; 1067 } 1068 } 1069 if (i < Count-1) { 1070 RegisterSuffix += ", "; 1071 } 1072 } 1073 RegisterSuffix += "}, [r{{[0-9]+}}"; 1074 1075 // We only include the alignment hint if we have a vld1.*64 or 1076 // a dup/lane instruction. 1077 if (IsLDSTOne) { 1078 if ((HasLanePostfix || HasDupPostfix) && OutTypeCode != "8") { 1079 RegisterSuffix += ":" + OutTypeCode; 1080 } 1081 } 1082 1083 RegisterSuffix += "]"; 1084 } 1085 } 1086 1087 static bool HasNPostfixAndScalarArgs(const StringRef &NameRef, 1088 const bool &HasNPostfix) { 1089 return (NameRef.count("vmla") || 1090 NameRef.count("vmlal") || 1091 NameRef.count("vmlsl") || 1092 NameRef.count("vmull") || 1093 NameRef.count("vqdmlal") || 1094 NameRef.count("vqdmlsl") || 1095 NameRef.count("vqdmulh") || 1096 NameRef.count("vqdmull") || 1097 NameRef.count("vqrdmulh")) && HasNPostfix; 1098 } 1099 1100 static bool IsFiveOperandLaneAccumulator(const StringRef &NameRef, 1101 const bool &HasLanePostfix) { 1102 return (NameRef.count("vmla") || 1103 NameRef.count("vmls") || 1104 NameRef.count("vmlal") || 1105 NameRef.count("vmlsl") || 1106 (NameRef.count("vmul") && NameRef.size() == 3)|| 1107 NameRef.count("vqdmlal") || 1108 NameRef.count("vqdmlsl") || 1109 NameRef.count("vqdmulh") || 1110 NameRef.count("vqrdmulh")) && HasLanePostfix; 1111 } 1112 1113 static bool IsSpecialLaneMultiply(const StringRef &NameRef, 1114 const bool &HasLanePostfix, 1115 const bool &IsQuad) { 1116 const bool IsVMulOrMulh = (NameRef.count("vmul") || NameRef.count("mulh")) 1117 && IsQuad; 1118 const bool IsVMull = NameRef.count("mull") && !IsQuad; 1119 return (IsVMulOrMulh || IsVMull) && HasLanePostfix; 1120 } 1121 1122 static void NormalizeProtoForRegisterPatternCreation(const std::string &Name, 1123 const std::string &Proto, 1124 const bool &HasNPostfix, 1125 const bool &IsQuad, 1126 const bool &HasLanePostfix, 1127 const bool &HasDupPostfix, 1128 std::string &NormedProto) { 1129 // Handle generic case. 1130 const StringRef NameRef(Name); 1131 for (size_t i = 0, end = Proto.size(); i < end; i++) { 1132 switch (Proto[i]) { 1133 case 'u': 1134 case 'f': 1135 case 'F': 1136 case 'd': 1137 case 's': 1138 case 'x': 1139 case 't': 1140 case 'n': 1141 NormedProto += IsQuad? 'q' : 'd'; 1142 break; 1143 case 'w': 1144 case 'k': 1145 NormedProto += 'q'; 1146 break; 1147 case 'g': 1148 case 'j': 1149 case 'h': 1150 case 'e': 1151 NormedProto += 'd'; 1152 break; 1153 case 'i': 1154 NormedProto += HasLanePostfix? 'a' : 'i'; 1155 break; 1156 case 'a': 1157 if (HasLanePostfix) { 1158 NormedProto += 'a'; 1159 } else if (HasNPostfixAndScalarArgs(NameRef, HasNPostfix)) { 1160 NormedProto += IsQuad? 'q' : 'd'; 1161 } else { 1162 NormedProto += 'i'; 1163 } 1164 break; 1165 } 1166 } 1167 1168 // Handle Special Cases. 1169 const bool IsNotVExt = !NameRef.count("vext"); 1170 const bool IsVPADAL = NameRef.count("vpadal"); 1171 const bool Is5OpLaneAccum = IsFiveOperandLaneAccumulator(NameRef, 1172 HasLanePostfix); 1173 const bool IsSpecialLaneMul = IsSpecialLaneMultiply(NameRef, HasLanePostfix, 1174 IsQuad); 1175 1176 if (IsSpecialLaneMul) { 1177 // If 1178 NormedProto[2] = NormedProto[3]; 1179 NormedProto.erase(3); 1180 } else if (NormedProto.size() == 4 && 1181 NormedProto[0] == NormedProto[1] && 1182 IsNotVExt) { 1183 // If NormedProto.size() == 4 and the first two proto characters are the 1184 // same, ignore the first. 1185 NormedProto = NormedProto.substr(1, 3); 1186 } else if (Is5OpLaneAccum) { 1187 // If we have a 5 op lane accumulator operation, we take characters 1,2,4 1188 std::string tmp = NormedProto.substr(1,2); 1189 tmp += NormedProto[4]; 1190 NormedProto = tmp; 1191 } else if (IsVPADAL) { 1192 // If we have VPADAL, ignore the first character. 1193 NormedProto = NormedProto.substr(0, 2); 1194 } else if (NameRef.count("vdup") && NormedProto.size() > 2) { 1195 // If our instruction is a dup instruction, keep only the first and 1196 // last characters. 1197 std::string tmp = ""; 1198 tmp += NormedProto[0]; 1199 tmp += NormedProto[NormedProto.size()-1]; 1200 NormedProto = tmp; 1201 } 1202 } 1203 1204 /// GenerateRegisterCheckPatterns - Given a bunch of data we have 1205 /// extracted, generate a FileCheck pattern to check that an 1206 /// instruction's arguments are correct. 1207 static void GenerateRegisterCheckPattern(const std::string &Name, 1208 const std::string &Proto, 1209 const std::string &OutTypeCode, 1210 const bool &HasNPostfix, 1211 const bool &IsQuad, 1212 const bool &HasLanePostfix, 1213 const bool &HasDupPostfix, 1214 const size_t &TBNumber, 1215 std::string &RegisterSuffix) { 1216 1217 RegisterSuffix = ""; 1218 1219 const StringRef NameRef(Name); 1220 1221 if ((NameRef.count("vdup") || NameRef.count("vmov")) && HasNPostfix) { 1222 return; 1223 } 1224 1225 const bool IsLoadStore = NameRef.count("vld") || NameRef.count("vst"); 1226 const bool IsTBXOrTBL = NameRef.count("vtbl") || NameRef.count("vtbx"); 1227 1228 if (IsLoadStore) { 1229 // Grab N value from v{ld,st}N using its ascii representation. 1230 const size_t Count = NameRef[3] - 48; 1231 1232 GenerateRegisterCheckPatternForLoadStores(NameRef, OutTypeCode, IsQuad, 1233 HasDupPostfix, HasLanePostfix, 1234 Count, RegisterSuffix); 1235 } else if (IsTBXOrTBL) { 1236 RegisterSuffix += "d{{[0-9]+}}, {"; 1237 for (size_t i = 0; i < TBNumber-1; i++) { 1238 RegisterSuffix += "d{{[0-9]+}}, "; 1239 } 1240 RegisterSuffix += "d{{[0-9]+}}}, d{{[0-9]+}}"; 1241 } else { 1242 // Handle a normal instruction. 1243 if (NameRef.count("vget") || NameRef.count("vset")) 1244 return; 1245 1246 // We first normalize our proto, since we only need to emit 4 1247 // different types of checks, yet have more than 4 proto types 1248 // that map onto those 4 patterns. 1249 std::string NormalizedProto(""); 1250 NormalizeProtoForRegisterPatternCreation(Name, Proto, HasNPostfix, IsQuad, 1251 HasLanePostfix, HasDupPostfix, 1252 NormalizedProto); 1253 1254 for (size_t i = 0, end = NormalizedProto.size(); i < end; i++) { 1255 const char &c = NormalizedProto[i]; 1256 switch (c) { 1257 case 'q': 1258 RegisterSuffix += "q{{[0-9]+}}, "; 1259 break; 1260 1261 case 'd': 1262 RegisterSuffix += "d{{[0-9]+}}, "; 1263 break; 1264 1265 case 'i': 1266 RegisterSuffix += "#{{[0-9]+}}, "; 1267 break; 1268 1269 case 'a': 1270 RegisterSuffix += "d{{[0-9]+}}[{{[0-9]}}], "; 1271 break; 1272 } 1273 } 1274 1275 // Remove extra ", ". 1276 RegisterSuffix = RegisterSuffix.substr(0, RegisterSuffix.size()-2); 1277 } 1278 } 1279 1280 /// GenerateChecksForIntrinsic - Given a specific instruction name + 1281 /// typestr + class kind, generate the proper set of FileCheck 1282 /// Patterns to check for. We could just return a string, but instead 1283 /// use a vector since it provides us with the extra flexibility of 1284 /// emitting multiple checks, which comes in handy for certain cases 1285 /// like mla where we want to check for 2 different instructions. 1286 static void GenerateChecksForIntrinsic(const std::string &Name, 1287 const std::string &Proto, 1288 StringRef &OutTypeStr, 1289 StringRef &InTypeStr, 1290 ClassKind Ck, 1291 const std::string &InstName, 1292 bool IsHiddenLOp, 1293 std::vector<std::string>& Result) { 1294 1295 // If Ck is a ClassNoTest instruction, just return so no test is 1296 // emitted. 1297 if(Ck == ClassNoTest) 1298 return; 1299 1300 if (Name == "vcvt_f32_f16") { 1301 Result.push_back("vcvt.f32.f16"); 1302 return; 1303 } 1304 1305 1306 // Now we preprocess our instruction given the data we have to get the 1307 // data that we need. 1308 // Create a StringRef for String Manipulation of our Name. 1309 const StringRef NameRef(Name); 1310 // Instruction Prefix. 1311 std::string Prefix; 1312 // The type code for our out type string. 1313 std::string OutTypeCode; 1314 // To handle our different cases, we need to check for different postfixes. 1315 // Is our instruction a quad instruction. 1316 bool IsQuad = false; 1317 // Our instruction is of the form <instructionname>_n. 1318 bool HasNPostfix = false; 1319 // Our instruction is of the form <instructionname>_lane. 1320 bool HasLanePostfix = false; 1321 // Our instruction is of the form <instructionname>_dup. 1322 bool HasDupPostfix = false; 1323 // Our instruction is a vcvt instruction which requires special handling. 1324 bool IsSpecialVCvt = false; 1325 // If we have a vtbxN or vtblN instruction, this is set to N. 1326 size_t TBNumber = -1; 1327 // Register Suffix 1328 std::string RegisterSuffix; 1329 1330 PreprocessInstruction(NameRef, InstName, Prefix, 1331 HasNPostfix, HasLanePostfix, HasDupPostfix, 1332 IsSpecialVCvt, TBNumber); 1333 1334 InstructionTypeCode(OutTypeStr, Ck, IsQuad, OutTypeCode); 1335 GenerateRegisterCheckPattern(Name, Proto, OutTypeCode, HasNPostfix, IsQuad, 1336 HasLanePostfix, HasDupPostfix, TBNumber, 1337 RegisterSuffix); 1338 1339 // In the following section, we handle a bunch of special cases. You can tell 1340 // a special case by the fact we are returning early. 1341 1342 // If our instruction is a logical instruction without postfix or a 1343 // hidden LOp just return the current Prefix. 1344 if (Ck == ClassL || IsHiddenLOp) { 1345 Result.push_back(Prefix + " " + RegisterSuffix); 1346 return; 1347 } 1348 1349 // If we have a vmov, due to the many different cases, some of which 1350 // vary within the different intrinsics generated for a single 1351 // instruction type, just output a vmov. (e.g. given an instruction 1352 // A, A.u32 might be vmov and A.u8 might be vmov.8). 1353 // 1354 // FIXME: Maybe something can be done about this. The two cases that we care 1355 // about are vmov as an LType and vmov as a WType. 1356 if (Prefix == "vmov") { 1357 Result.push_back(Prefix + " " + RegisterSuffix); 1358 return; 1359 } 1360 1361 // In the following section, we handle special cases. 1362 1363 if (OutTypeCode == "64") { 1364 // If we have a 64 bit vdup/vext and are handling an uint64x1_t 1365 // type, the intrinsic will be optimized away, so just return 1366 // nothing. On the other hand if we are handling an uint64x2_t 1367 // (i.e. quad instruction), vdup/vmov instructions should be 1368 // emitted. 1369 if (Prefix == "vdup" || Prefix == "vext") { 1370 if (IsQuad) { 1371 Result.push_back("{{vmov|vdup}}"); 1372 } 1373 return; 1374 } 1375 1376 // v{st,ld}{2,3,4}_{u,s}64 emit v{st,ld}1.64 instructions with 1377 // multiple register operands. 1378 bool MultiLoadPrefix = Prefix == "vld2" || Prefix == "vld3" 1379 || Prefix == "vld4"; 1380 bool MultiStorePrefix = Prefix == "vst2" || Prefix == "vst3" 1381 || Prefix == "vst4"; 1382 if (MultiLoadPrefix || MultiStorePrefix) { 1383 Result.push_back(NameRef.slice(0, 3).str() + "1.64"); 1384 return; 1385 } 1386 1387 // v{st,ld}1_{lane,dup}_{u64,s64} use vldr/vstr/vmov/str instead of 1388 // emitting said instructions. So return a check for 1389 // vldr/vstr/vmov/str instead. 1390 if (HasLanePostfix || HasDupPostfix) { 1391 if (Prefix == "vst1") { 1392 Result.push_back("{{str|vstr|vmov}}"); 1393 return; 1394 } else if (Prefix == "vld1") { 1395 Result.push_back("{{ldr|vldr|vmov}}"); 1396 return; 1397 } 1398 } 1399 } 1400 1401 // vzip.32/vuzp.32 are the same instruction as vtrn.32 and are 1402 // sometimes disassembled as vtrn.32. We use a regex to handle both 1403 // cases. 1404 if ((Prefix == "vzip" || Prefix == "vuzp") && OutTypeCode == "32") { 1405 Result.push_back("{{vtrn|" + Prefix + "}}.32 " + RegisterSuffix); 1406 return; 1407 } 1408 1409 // Currently on most ARM processors, we do not use vmla/vmls for 1410 // quad floating point operations. Instead we output vmul + vadd. So 1411 // check if we have one of those instructions and just output a 1412 // check for vmul. 1413 if (OutTypeCode == "f32") { 1414 if (Prefix == "vmls") { 1415 Result.push_back("vmul." + OutTypeCode + " " + RegisterSuffix); 1416 Result.push_back("vsub." + OutTypeCode); 1417 return; 1418 } else if (Prefix == "vmla") { 1419 Result.push_back("vmul." + OutTypeCode + " " + RegisterSuffix); 1420 Result.push_back("vadd." + OutTypeCode); 1421 return; 1422 } 1423 } 1424 1425 // If we have vcvt, get the input type from the instruction name 1426 // (which should be of the form instname_inputtype) and append it 1427 // before the output type. 1428 if (Prefix == "vcvt") { 1429 const std::string inTypeCode = NameRef.substr(NameRef.find_last_of("_")+1); 1430 Prefix += "." + inTypeCode; 1431 } 1432 1433 // Append output type code to get our final mangled instruction. 1434 Prefix += "." + OutTypeCode; 1435 1436 Result.push_back(Prefix + " " + RegisterSuffix); 1437 } 1438 1439 /// UseMacro - Examine the prototype string to determine if the intrinsic 1440 /// should be defined as a preprocessor macro instead of an inline function. 1441 static bool UseMacro(const std::string &proto) { 1442 // If this builtin takes an immediate argument, we need to #define it rather 1443 // than use a standard declaration, so that SemaChecking can range check 1444 // the immediate passed by the user. 1445 if (proto.find('i') != std::string::npos) 1446 return true; 1447 1448 // Pointer arguments need to use macros to avoid hiding aligned attributes 1449 // from the pointer type. 1450 if (proto.find('p') != std::string::npos || 1451 proto.find('c') != std::string::npos) 1452 return true; 1453 1454 return false; 1455 } 1456 1457 /// MacroArgUsedDirectly - Return true if argument i for an intrinsic that is 1458 /// defined as a macro should be accessed directly instead of being first 1459 /// assigned to a local temporary. 1460 static bool MacroArgUsedDirectly(const std::string &proto, unsigned i) { 1461 // True for constant ints (i), pointers (p) and const pointers (c). 1462 return (proto[i] == 'i' || proto[i] == 'p' || proto[i] == 'c'); 1463 } 1464 1465 // Generate the string "(argtype a, argtype b, ...)" 1466 static std::string GenArgs(const std::string &proto, StringRef typestr, 1467 const std::string &name) { 1468 bool define = UseMacro(proto); 1469 char arg = 'a'; 1470 1471 std::string s; 1472 s += "("; 1473 1474 for (unsigned i = 1, e = proto.size(); i != e; ++i, ++arg) { 1475 if (define) { 1476 // Some macro arguments are used directly instead of being assigned 1477 // to local temporaries; prepend an underscore prefix to make their 1478 // names consistent with the local temporaries. 1479 if (MacroArgUsedDirectly(proto, i)) 1480 s += "__"; 1481 } else { 1482 s += TypeString(proto[i], typestr) + " __"; 1483 } 1484 s.push_back(arg); 1485 if ((i + 1) < e) 1486 s += ", "; 1487 } 1488 1489 s += ")"; 1490 return s; 1491 } 1492 1493 // Macro arguments are not type-checked like inline function arguments, so 1494 // assign them to local temporaries to get the right type checking. 1495 static std::string GenMacroLocals(const std::string &proto, StringRef typestr, 1496 const std::string &name ) { 1497 char arg = 'a'; 1498 std::string s; 1499 bool generatedLocal = false; 1500 1501 for (unsigned i = 1, e = proto.size(); i != e; ++i, ++arg) { 1502 // Do not create a temporary for an immediate argument. 1503 // That would defeat the whole point of using a macro! 1504 if (MacroArgUsedDirectly(proto, i)) 1505 continue; 1506 generatedLocal = true; 1507 s += TypeString(proto[i], typestr) + " __"; 1508 s.push_back(arg); 1509 s += " = ("; 1510 s.push_back(arg); 1511 s += "); "; 1512 } 1513 1514 if (generatedLocal) 1515 s += "\\\n "; 1516 return s; 1517 } 1518 1519 // Use the vmovl builtin to sign-extend or zero-extend a vector. 1520 static std::string Extend(StringRef typestr, const std::string &a, bool h=0) { 1521 std::string s, high; 1522 high = h ? "_high" : ""; 1523 s = MangleName("vmovl" + high, typestr, ClassS); 1524 s += "(" + a + ")"; 1525 return s; 1526 } 1527 1528 // Get the high 64-bit part of a vector 1529 static std::string GetHigh(const std::string &a, StringRef typestr) { 1530 std::string s; 1531 s = MangleName("vget_high", typestr, ClassS); 1532 s += "(" + a + ")"; 1533 return s; 1534 } 1535 1536 // Gen operation with two operands and get high 64-bit for both of two operands. 1537 static std::string Gen2OpWith2High(StringRef typestr, 1538 const std::string &op, 1539 const std::string &a, 1540 const std::string &b) { 1541 std::string s; 1542 std::string Op1 = GetHigh(a, typestr); 1543 std::string Op2 = GetHigh(b, typestr); 1544 s = MangleName(op, typestr, ClassS); 1545 s += "(" + Op1 + ", " + Op2 + ");"; 1546 return s; 1547 } 1548 1549 // Gen operation with three operands and get high 64-bit of the latter 1550 // two operands. 1551 static std::string Gen3OpWith2High(StringRef typestr, 1552 const std::string &op, 1553 const std::string &a, 1554 const std::string &b, 1555 const std::string &c) { 1556 std::string s; 1557 std::string Op1 = GetHigh(b, typestr); 1558 std::string Op2 = GetHigh(c, typestr); 1559 s = MangleName(op, typestr, ClassS); 1560 s += "(" + a + ", " + Op1 + ", " + Op2 + ");"; 1561 return s; 1562 } 1563 1564 // Gen combine operation by putting a on low 64-bit, and b on high 64-bit. 1565 static std::string GenCombine(std::string typestr, 1566 const std::string &a, 1567 const std::string &b) { 1568 std::string s; 1569 s = MangleName("vcombine", typestr, ClassS); 1570 s += "(" + a + ", " + b + ")"; 1571 return s; 1572 } 1573 1574 static std::string Duplicate(unsigned nElts, StringRef typestr, 1575 const std::string &a) { 1576 std::string s; 1577 1578 s = "(" + TypeString('d', typestr) + "){ "; 1579 for (unsigned i = 0; i != nElts; ++i) { 1580 s += a; 1581 if ((i + 1) < nElts) 1582 s += ", "; 1583 } 1584 s += " }"; 1585 1586 return s; 1587 } 1588 1589 static std::string SplatLane(unsigned nElts, const std::string &vec, 1590 const std::string &lane) { 1591 std::string s = "__builtin_shufflevector(" + vec + ", " + vec; 1592 for (unsigned i = 0; i < nElts; ++i) 1593 s += ", " + lane; 1594 s += ")"; 1595 return s; 1596 } 1597 1598 static std::string RemoveHigh(const std::string &name) { 1599 std::string s = name; 1600 std::size_t found = s.find("_high_"); 1601 if (found == std::string::npos) 1602 PrintFatalError("name should contain \"_high_\" for high intrinsics"); 1603 s.replace(found, 5, ""); 1604 return s; 1605 } 1606 1607 static unsigned GetNumElements(StringRef typestr, bool &quad) { 1608 quad = false; 1609 bool dummy = false; 1610 char type = ClassifyType(typestr, quad, dummy, dummy); 1611 unsigned nElts = 0; 1612 switch (type) { 1613 case 'c': nElts = 8; break; 1614 case 's': nElts = 4; break; 1615 case 'i': nElts = 2; break; 1616 case 'l': nElts = 1; break; 1617 case 'k': nElts = 1; break; 1618 case 'h': nElts = 4; break; 1619 case 'f': nElts = 2; break; 1620 case 'd': 1621 nElts = 1; 1622 break; 1623 default: 1624 PrintFatalError("unhandled type!"); 1625 } 1626 if (quad) nElts <<= 1; 1627 return nElts; 1628 } 1629 1630 // Generate the definition for this intrinsic, e.g. "a + b" for OpAdd. 1631 // 1632 // Note that some intrinsic definitions around 'lane' are being implemented 1633 // with macros, because they all contain constant integer argument, and we 1634 // statically check the range of the lane index to meet the semantic 1635 // requirement of different intrinsics. 1636 // 1637 // For the intrinsics implemented with macro, if they contain another intrinsic 1638 // implemented with maco, we have to avoid using the same argument names for 1639 // the nested instrinsics. For example, macro vfms_lane is being implemented 1640 // with another macor vfma_lane, so we rename all arguments for vfms_lane by 1641 // adding a suffix '1'. 1642 1643 static std::string GenOpString(const std::string &name, OpKind op, 1644 const std::string &proto, StringRef typestr) { 1645 bool quad; 1646 unsigned nElts = GetNumElements(typestr, quad); 1647 bool define = UseMacro(proto); 1648 1649 std::string ts = TypeString(proto[0], typestr); 1650 std::string s; 1651 if (!define) { 1652 s = "return "; 1653 } 1654 1655 switch(op) { 1656 case OpAdd: 1657 s += "__a + __b;"; 1658 break; 1659 case OpAddl: 1660 s += Extend(typestr, "__a") + " + " + Extend(typestr, "__b") + ";"; 1661 break; 1662 case OpAddlHi: 1663 s += Extend(typestr, "__a", 1) + " + " + Extend(typestr, "__b", 1) + ";"; 1664 break; 1665 case OpAddw: 1666 s += "__a + " + Extend(typestr, "__b") + ";"; 1667 break; 1668 case OpAddwHi: 1669 s += "__a + " + Extend(typestr, "__b", 1) + ";"; 1670 break; 1671 case OpSub: 1672 s += "__a - __b;"; 1673 break; 1674 case OpSubl: 1675 s += Extend(typestr, "__a") + " - " + Extend(typestr, "__b") + ";"; 1676 break; 1677 case OpSublHi: 1678 s += Extend(typestr, "__a", 1) + " - " + Extend(typestr, "__b", 1) + ";"; 1679 break; 1680 case OpSubw: 1681 s += "__a - " + Extend(typestr, "__b") + ";"; 1682 break; 1683 case OpSubwHi: 1684 s += "__a - " + Extend(typestr, "__b", 1) + ";"; 1685 break; 1686 case OpMulN: 1687 s += "__a * " + Duplicate(nElts, typestr, "__b") + ";"; 1688 break; 1689 case OpMulLane: 1690 s += "__a * " + SplatLane(nElts, "__b", "__c") + ";"; 1691 break; 1692 case OpMulXLane: 1693 s += MangleName("vmulx", typestr, ClassS) + "(__a, " + 1694 SplatLane(nElts, "__b", "__c") + ");"; 1695 break; 1696 case OpMul: 1697 s += "__a * __b;"; 1698 break; 1699 case OpFMlaN: 1700 s += MangleName("vfma", typestr, ClassS); 1701 s += "(__a, __b, " + Duplicate(nElts,typestr, "__c") + ");"; 1702 break; 1703 case OpFMlsN: 1704 s += MangleName("vfms", typestr, ClassS); 1705 s += "(__a, __b, " + Duplicate(nElts,typestr, "__c") + ");"; 1706 break; 1707 case OpMullLane: 1708 s += MangleName("vmull", typestr, ClassS) + "(__a, " + 1709 SplatLane(nElts, "__b", "__c") + ");"; 1710 break; 1711 case OpMullHiLane: 1712 s += MangleName("vmull", typestr, ClassS) + "(" + 1713 GetHigh("__a", typestr) + ", " + SplatLane(nElts, "__b", "__c") + ");"; 1714 break; 1715 case OpMlaN: 1716 s += "__a + (__b * " + Duplicate(nElts, typestr, "__c") + ");"; 1717 break; 1718 case OpMlaLane: 1719 s += "__a + (__b * " + SplatLane(nElts, "__c", "__d") + ");"; 1720 break; 1721 case OpMla: 1722 s += "__a + (__b * __c);"; 1723 break; 1724 case OpMlalN: 1725 s += "__a + " + MangleName("vmull", typestr, ClassS) + "(__b, " + 1726 Duplicate(nElts, typestr, "__c") + ");"; 1727 break; 1728 case OpMlalLane: 1729 s += "__a + " + MangleName("vmull", typestr, ClassS) + "(__b, " + 1730 SplatLane(nElts, "__c", "__d") + ");"; 1731 break; 1732 case OpMlalHiLane: 1733 s += "__a + " + MangleName("vmull", typestr, ClassS) + "(" + 1734 GetHigh("__b", typestr) + ", " + SplatLane(nElts, "__c", "__d") + ");"; 1735 break; 1736 case OpMlal: 1737 s += "__a + " + MangleName("vmull", typestr, ClassS) + "(__b, __c);"; 1738 break; 1739 case OpMullHi: 1740 s += Gen2OpWith2High(typestr, "vmull", "__a", "__b"); 1741 break; 1742 case OpMullHiP64: { 1743 std::string Op1 = GetHigh("__a", typestr); 1744 std::string Op2 = GetHigh("__b", typestr); 1745 s += MangleName("vmull", typestr, ClassS); 1746 s += "((poly64_t)" + Op1 + ", (poly64_t)" + Op2 + ");"; 1747 break; 1748 } 1749 case OpMullHiN: 1750 s += MangleName("vmull_n", typestr, ClassS); 1751 s += "(" + GetHigh("__a", typestr) + ", __b);"; 1752 return s; 1753 case OpMlalHi: 1754 s += Gen3OpWith2High(typestr, "vmlal", "__a", "__b", "__c"); 1755 break; 1756 case OpMlalHiN: 1757 s += MangleName("vmlal_n", typestr, ClassS); 1758 s += "(__a, " + GetHigh("__b", typestr) + ", __c);"; 1759 return s; 1760 case OpMlsN: 1761 s += "__a - (__b * " + Duplicate(nElts, typestr, "__c") + ");"; 1762 break; 1763 case OpMlsLane: 1764 s += "__a - (__b * " + SplatLane(nElts, "__c", "__d") + ");"; 1765 break; 1766 case OpFMSLane: 1767 s += TypeString(proto[1], typestr) + " __a1 = __a; \\\n "; 1768 s += TypeString(proto[2], typestr) + " __b1 = __b; \\\n "; 1769 s += TypeString(proto[3], typestr) + " __c1 = __c; \\\n "; 1770 s += MangleName("vfma_lane", typestr, ClassS) + "(__a1, __b1, -__c1, __d);"; 1771 break; 1772 case OpFMSLaneQ: 1773 s += TypeString(proto[1], typestr) + " __a1 = __a; \\\n "; 1774 s += TypeString(proto[2], typestr) + " __b1 = __b; \\\n "; 1775 s += TypeString(proto[3], typestr) + " __c1 = __c; \\\n "; 1776 s += MangleName("vfma_laneq", typestr, ClassS) + "(__a1, __b1, -__c1, __d);"; 1777 break; 1778 case OpMls: 1779 s += "__a - (__b * __c);"; 1780 break; 1781 case OpMlslN: 1782 s += "__a - " + MangleName("vmull", typestr, ClassS) + "(__b, " + 1783 Duplicate(nElts, typestr, "__c") + ");"; 1784 break; 1785 case OpMlslLane: 1786 s += "__a - " + MangleName("vmull", typestr, ClassS) + "(__b, " + 1787 SplatLane(nElts, "__c", "__d") + ");"; 1788 break; 1789 case OpMlslHiLane: 1790 s += "__a - " + MangleName("vmull", typestr, ClassS) + "(" + 1791 GetHigh("__b", typestr) + ", " + SplatLane(nElts, "__c", "__d") + ");"; 1792 break; 1793 case OpMlsl: 1794 s += "__a - " + MangleName("vmull", typestr, ClassS) + "(__b, __c);"; 1795 break; 1796 case OpMlslHi: 1797 s += Gen3OpWith2High(typestr, "vmlsl", "__a", "__b", "__c"); 1798 break; 1799 case OpMlslHiN: 1800 s += MangleName("vmlsl_n", typestr, ClassS); 1801 s += "(__a, " + GetHigh("__b", typestr) + ", __c);"; 1802 break; 1803 case OpQDMullLane: 1804 s += MangleName("vqdmull", typestr, ClassS) + "(__a, " + 1805 SplatLane(nElts, "__b", "__c") + ");"; 1806 break; 1807 case OpQDMullHiLane: 1808 s += MangleName("vqdmull", typestr, ClassS) + "(" + 1809 GetHigh("__a", typestr) + ", " + SplatLane(nElts, "__b", "__c") + ");"; 1810 break; 1811 case OpQDMlalLane: 1812 s += MangleName("vqdmlal", typestr, ClassS) + "(__a, __b, " + 1813 SplatLane(nElts, "__c", "__d") + ");"; 1814 break; 1815 case OpQDMlalHiLane: 1816 s += MangleName("vqdmlal", typestr, ClassS) + "(__a, " + 1817 GetHigh("__b", typestr) + ", " + SplatLane(nElts, "__c", "__d") + ");"; 1818 break; 1819 case OpQDMlslLane: 1820 s += MangleName("vqdmlsl", typestr, ClassS) + "(__a, __b, " + 1821 SplatLane(nElts, "__c", "__d") + ");"; 1822 break; 1823 case OpQDMlslHiLane: 1824 s += MangleName("vqdmlsl", typestr, ClassS) + "(__a, " + 1825 GetHigh("__b", typestr) + ", " + SplatLane(nElts, "__c", "__d") + ");"; 1826 break; 1827 case OpQDMulhLane: 1828 s += MangleName("vqdmulh", typestr, ClassS) + "(__a, " + 1829 SplatLane(nElts, "__b", "__c") + ");"; 1830 break; 1831 case OpQRDMulhLane: 1832 s += MangleName("vqrdmulh", typestr, ClassS) + "(__a, " + 1833 SplatLane(nElts, "__b", "__c") + ");"; 1834 break; 1835 case OpEq: 1836 s += "(" + ts + ")(__a == __b);"; 1837 break; 1838 case OpGe: 1839 s += "(" + ts + ")(__a >= __b);"; 1840 break; 1841 case OpLe: 1842 s += "(" + ts + ")(__a <= __b);"; 1843 break; 1844 case OpGt: 1845 s += "(" + ts + ")(__a > __b);"; 1846 break; 1847 case OpLt: 1848 s += "(" + ts + ")(__a < __b);"; 1849 break; 1850 case OpNeg: 1851 s += " -__a;"; 1852 break; 1853 case OpNot: 1854 s += " ~__a;"; 1855 break; 1856 case OpAnd: 1857 s += "__a & __b;"; 1858 break; 1859 case OpOr: 1860 s += "__a | __b;"; 1861 break; 1862 case OpXor: 1863 s += "__a ^ __b;"; 1864 break; 1865 case OpAndNot: 1866 s += "__a & ~__b;"; 1867 break; 1868 case OpOrNot: 1869 s += "__a | ~__b;"; 1870 break; 1871 case OpCast: 1872 s += "(" + ts + ")__a;"; 1873 break; 1874 case OpConcat: 1875 s += "(" + ts + ")__builtin_shufflevector((int64x1_t)__a"; 1876 s += ", (int64x1_t)__b, 0, 1);"; 1877 break; 1878 case OpHi: 1879 // nElts is for the result vector, so the source is twice that number. 1880 s += "__builtin_shufflevector(__a, __a"; 1881 for (unsigned i = nElts; i < nElts * 2; ++i) 1882 s += ", " + utostr(i); 1883 s+= ");"; 1884 break; 1885 case OpLo: 1886 s += "__builtin_shufflevector(__a, __a"; 1887 for (unsigned i = 0; i < nElts; ++i) 1888 s += ", " + utostr(i); 1889 s+= ");"; 1890 break; 1891 case OpDup: 1892 s += Duplicate(nElts, typestr, "__a") + ";"; 1893 break; 1894 case OpDupLane: 1895 s += SplatLane(nElts, "__a", "__b") + ";"; 1896 break; 1897 case OpSelect: 1898 // ((0 & 1) | (~0 & 2)) 1899 s += "(" + ts + ")"; 1900 ts = TypeString(proto[1], typestr); 1901 s += "((__a & (" + ts + ")__b) | "; 1902 s += "(~__a & (" + ts + ")__c));"; 1903 break; 1904 case OpRev16: 1905 s += "__builtin_shufflevector(__a, __a"; 1906 for (unsigned i = 2; i <= nElts; i += 2) 1907 for (unsigned j = 0; j != 2; ++j) 1908 s += ", " + utostr(i - j - 1); 1909 s += ");"; 1910 break; 1911 case OpRev32: { 1912 unsigned WordElts = nElts >> (1 + (int)quad); 1913 s += "__builtin_shufflevector(__a, __a"; 1914 for (unsigned i = WordElts; i <= nElts; i += WordElts) 1915 for (unsigned j = 0; j != WordElts; ++j) 1916 s += ", " + utostr(i - j - 1); 1917 s += ");"; 1918 break; 1919 } 1920 case OpRev64: { 1921 unsigned DblWordElts = nElts >> (int)quad; 1922 s += "__builtin_shufflevector(__a, __a"; 1923 for (unsigned i = DblWordElts; i <= nElts; i += DblWordElts) 1924 for (unsigned j = 0; j != DblWordElts; ++j) 1925 s += ", " + utostr(i - j - 1); 1926 s += ");"; 1927 break; 1928 } 1929 case OpXtnHi: { 1930 s = TypeString(proto[1], typestr) + " __a1 = " + 1931 MangleName("vmovn", typestr, ClassS) + "(__b);\n " + 1932 "return __builtin_shufflevector(__a, __a1"; 1933 for (unsigned i = 0; i < nElts * 4; ++i) 1934 s += ", " + utostr(i); 1935 s += ");"; 1936 break; 1937 } 1938 case OpSqxtunHi: { 1939 s = TypeString(proto[1], typestr) + " __a1 = " + 1940 MangleName("vqmovun", typestr, ClassS) + "(__b);\n " + 1941 "return __builtin_shufflevector(__a, __a1"; 1942 for (unsigned i = 0; i < nElts * 4; ++i) 1943 s += ", " + utostr(i); 1944 s += ");"; 1945 break; 1946 } 1947 case OpQxtnHi: { 1948 s = TypeString(proto[1], typestr) + " __a1 = " + 1949 MangleName("vqmovn", typestr, ClassS) + "(__b);\n " + 1950 "return __builtin_shufflevector(__a, __a1"; 1951 for (unsigned i = 0; i < nElts * 4; ++i) 1952 s += ", " + utostr(i); 1953 s += ");"; 1954 break; 1955 } 1956 case OpFcvtnHi: { 1957 std::string FName = (nElts == 1) ? "vcvt_f32" : "vcvt_f16"; 1958 s = TypeString(proto[1], typestr) + " __a1 = " + 1959 MangleName(FName, typestr, ClassS) + "(__b);\n " + 1960 "return __builtin_shufflevector(__a, __a1"; 1961 for (unsigned i = 0; i < nElts * 4; ++i) 1962 s += ", " + utostr(i); 1963 s += ");"; 1964 break; 1965 } 1966 case OpFcvtlHi: { 1967 std::string FName = (nElts == 2) ? "vcvt_f64" : "vcvt_f32"; 1968 s = TypeString('d', typestr) + " __a1 = " + GetHigh("__a", typestr) + 1969 ";\n return " + MangleName(FName, typestr, ClassS) + "(__a1);"; 1970 break; 1971 } 1972 case OpFcvtxnHi: { 1973 s = TypeString(proto[1], typestr) + " __a1 = " + 1974 MangleName("vcvtx_f32", typestr, ClassS) + "(__b);\n " + 1975 "return __builtin_shufflevector(__a, __a1"; 1976 for (unsigned i = 0; i < nElts * 4; ++i) 1977 s += ", " + utostr(i); 1978 s += ");"; 1979 break; 1980 } 1981 case OpUzp1: 1982 s += "__builtin_shufflevector(__a, __b"; 1983 for (unsigned i = 0; i < nElts; i++) 1984 s += ", " + utostr(2*i); 1985 s += ");"; 1986 break; 1987 case OpUzp2: 1988 s += "__builtin_shufflevector(__a, __b"; 1989 for (unsigned i = 0; i < nElts; i++) 1990 s += ", " + utostr(2*i+1); 1991 s += ");"; 1992 break; 1993 case OpZip1: 1994 s += "__builtin_shufflevector(__a, __b"; 1995 for (unsigned i = 0; i < (nElts/2); i++) 1996 s += ", " + utostr(i) + ", " + utostr(i+nElts); 1997 s += ");"; 1998 break; 1999 case OpZip2: 2000 s += "__builtin_shufflevector(__a, __b"; 2001 for (unsigned i = nElts/2; i < nElts; i++) 2002 s += ", " + utostr(i) + ", " + utostr(i+nElts); 2003 s += ");"; 2004 break; 2005 case OpTrn1: 2006 s += "__builtin_shufflevector(__a, __b"; 2007 for (unsigned i = 0; i < (nElts/2); i++) 2008 s += ", " + utostr(2*i) + ", " + utostr(2*i+nElts); 2009 s += ");"; 2010 break; 2011 case OpTrn2: 2012 s += "__builtin_shufflevector(__a, __b"; 2013 for (unsigned i = 0; i < (nElts/2); i++) 2014 s += ", " + utostr(2*i+1) + ", " + utostr(2*i+1+nElts); 2015 s += ");"; 2016 break; 2017 case OpAbdl: { 2018 std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; 2019 if (typestr[0] != 'U') { 2020 // vabd results are always unsigned and must be zero-extended. 2021 std::string utype = "U" + typestr.str(); 2022 s += "(" + TypeString(proto[0], typestr) + ")"; 2023 abd = "(" + TypeString('d', utype) + ")" + abd; 2024 s += Extend(utype, abd) + ";"; 2025 } else { 2026 s += Extend(typestr, abd) + ";"; 2027 } 2028 break; 2029 } 2030 case OpAbdlHi: 2031 s += Gen2OpWith2High(typestr, "vabdl", "__a", "__b"); 2032 break; 2033 case OpAddhnHi: { 2034 std::string addhn = MangleName("vaddhn", typestr, ClassS) + "(__b, __c)"; 2035 s += GenCombine(GetNarrowTypestr(typestr), "__a", addhn); 2036 s += ";"; 2037 break; 2038 } 2039 case OpRAddhnHi: { 2040 std::string raddhn = MangleName("vraddhn", typestr, ClassS) + "(__b, __c)"; 2041 s += GenCombine(GetNarrowTypestr(typestr), "__a", raddhn); 2042 s += ";"; 2043 break; 2044 } 2045 case OpSubhnHi: { 2046 std::string subhn = MangleName("vsubhn", typestr, ClassS) + "(__b, __c)"; 2047 s += GenCombine(GetNarrowTypestr(typestr), "__a", subhn); 2048 s += ";"; 2049 break; 2050 } 2051 case OpRSubhnHi: { 2052 std::string rsubhn = MangleName("vrsubhn", typestr, ClassS) + "(__b, __c)"; 2053 s += GenCombine(GetNarrowTypestr(typestr), "__a", rsubhn); 2054 s += ";"; 2055 break; 2056 } 2057 case OpAba: 2058 s += "__a + " + MangleName("vabd", typestr, ClassS) + "(__b, __c);"; 2059 break; 2060 case OpAbal: 2061 s += "__a + " + MangleName("vabdl", typestr, ClassS) + "(__b, __c);"; 2062 break; 2063 case OpAbalHi: 2064 s += Gen3OpWith2High(typestr, "vabal", "__a", "__b", "__c"); 2065 break; 2066 case OpQDMullHi: 2067 s += Gen2OpWith2High(typestr, "vqdmull", "__a", "__b"); 2068 break; 2069 case OpQDMullHiN: 2070 s += MangleName("vqdmull_n", typestr, ClassS); 2071 s += "(" + GetHigh("__a", typestr) + ", __b);"; 2072 return s; 2073 case OpQDMlalHi: 2074 s += Gen3OpWith2High(typestr, "vqdmlal", "__a", "__b", "__c"); 2075 break; 2076 case OpQDMlalHiN: 2077 s += MangleName("vqdmlal_n", typestr, ClassS); 2078 s += "(__a, " + GetHigh("__b", typestr) + ", __c);"; 2079 return s; 2080 case OpQDMlslHi: 2081 s += Gen3OpWith2High(typestr, "vqdmlsl", "__a", "__b", "__c"); 2082 break; 2083 case OpQDMlslHiN: 2084 s += MangleName("vqdmlsl_n", typestr, ClassS); 2085 s += "(__a, " + GetHigh("__b", typestr) + ", __c);"; 2086 return s; 2087 case OpDiv: 2088 s += "__a / __b;"; 2089 break; 2090 case OpMovlHi: { 2091 s = TypeString(proto[1], typestr.drop_front()) + " __a1 = " + 2092 MangleName("vget_high", typestr, ClassS) + "(__a);\n " + s; 2093 s += "(" + ts + ")" + MangleName("vshll_n", typestr, ClassS); 2094 s += "(__a1, 0);"; 2095 break; 2096 } 2097 case OpLongHi: { 2098 // Another local variable __a1 is needed for calling a Macro, 2099 // or using __a will have naming conflict when Macro expanding. 2100 s += TypeString(proto[1], typestr.drop_front()) + " __a1 = " + 2101 MangleName("vget_high", typestr, ClassS) + "(__a); \\\n"; 2102 s += " (" + ts + ")" + MangleName(RemoveHigh(name), typestr, ClassS) + 2103 "(__a1, __b);"; 2104 break; 2105 } 2106 case OpNarrowHi: { 2107 s += "(" + ts + ")" + MangleName("vcombine", typestr, ClassS) + "(__a, " + 2108 MangleName(RemoveHigh(name), typestr, ClassS) + "(__b, __c));"; 2109 break; 2110 } 2111 case OpCopyLane: { 2112 s += TypeString(proto[1], typestr) + " __a1 = __a; \\\n "; 2113 s += TypeString(proto[3], typestr) + " __c1 = __c; \\\n "; 2114 s += TypeString('s', typestr) + " __c2 = " + 2115 MangleName("vget_lane", typestr, ClassS) + "(__c1, __d); \\\n " + 2116 MangleName("vset_lane", typestr, ClassS) + "(__c2, __a1, __b);"; 2117 break; 2118 } 2119 case OpCopyQLane: { 2120 std::string typeCode = ""; 2121 InstructionTypeCode(typestr, ClassS, quad, typeCode); 2122 s += TypeString(proto[1], typestr) + " __a1 = __a; \\\n "; 2123 s += TypeString(proto[3], typestr) + " __c1 = __c; \\\n "; 2124 s += TypeString('s', typestr) + " __c2 = vget_lane_" + typeCode + 2125 "(__c1, __d); \\\n vsetq_lane_" + typeCode + "(__c2, __a1, __b);"; 2126 break; 2127 } 2128 case OpCopyLaneQ: { 2129 std::string typeCode = ""; 2130 InstructionTypeCode(typestr, ClassS, quad, typeCode); 2131 s += TypeString(proto[1], typestr) + " __a1 = __a; \\\n "; 2132 s += TypeString(proto[3], typestr) + " __c1 = __c; \\\n "; 2133 s += TypeString('s', typestr) + " __c2 = vgetq_lane_" + typeCode + 2134 "(__c1, __d); \\\n vset_lane_" + typeCode + "(__c2, __a1, __b);"; 2135 break; 2136 } 2137 case OpScalarMulLane: { 2138 std::string typeCode = ""; 2139 InstructionTypeCode(typestr, ClassS, quad, typeCode); 2140 s += TypeString('s', typestr) + " __d1 = vget_lane_" + typeCode + 2141 "(__b, __c);\\\n __a * __d1;"; 2142 break; 2143 } 2144 case OpScalarMulLaneQ: { 2145 std::string typeCode = ""; 2146 InstructionTypeCode(typestr, ClassS, quad, typeCode); 2147 s += TypeString(proto[1], typestr) + " __a1 = __a; \\\n "; 2148 s += TypeString(proto[2], typestr) + " __b1 = __b; \\\n "; 2149 s += TypeString('s', typestr) + " __d1 = vgetq_lane_" + typeCode + 2150 "(__b1, __c);\\\n __a1 * __d1;"; 2151 break; 2152 } 2153 case OpScalarMulXLane: { 2154 bool dummy = false; 2155 char type = ClassifyType(typestr, dummy, dummy, dummy); 2156 if (type == 'f') type = 's'; 2157 std::string typeCode = ""; 2158 InstructionTypeCode(typestr, ClassS, quad, typeCode); 2159 s += TypeString(proto[1], typestr) + " __a1 = __a; \\\n "; 2160 s += TypeString(proto[2], typestr) + " __b1 = __b; \\\n "; 2161 s += TypeString('s', typestr) + " __d1 = vget_lane_" + typeCode + 2162 "(__b1, __c);\\\n vmulx" + type + "_" + 2163 typeCode + "(__a1, __d1);"; 2164 break; 2165 } 2166 case OpScalarMulXLaneQ: { 2167 bool dummy = false; 2168 char type = ClassifyType(typestr, dummy, dummy, dummy); 2169 if (type == 'f') type = 's'; 2170 std::string typeCode = ""; 2171 InstructionTypeCode(typestr, ClassS, quad, typeCode); 2172 s += TypeString(proto[1], typestr) + " __a1 = __a; \\\n "; 2173 s += TypeString(proto[2], typestr) + " __b1 = __b; \\\n "; 2174 s += TypeString('s', typestr) + " __d1 = vgetq_lane_" + 2175 typeCode + "(__b1, __c);\\\n vmulx" + type + 2176 "_" + typeCode + "(__a1, __d1);"; 2177 break; 2178 } 2179 2180 case OpScalarVMulXLane: { 2181 bool dummy = false; 2182 char type = ClassifyType(typestr, dummy, dummy, dummy); 2183 if (type == 'f') type = 's'; 2184 std::string typeCode = ""; 2185 InstructionTypeCode(typestr, ClassS, quad, typeCode); 2186 s += TypeString(proto[1], typestr) + " __a1 = __a; \\\n "; 2187 s += TypeString(proto[2], typestr) + " __b1 = __b; \\\n "; 2188 s += TypeString('s', typestr) + " __d1 = vget_lane_" + 2189 typeCode + "(__a1, 0);\\\n" + 2190 " " + TypeString('s', typestr) + " __e1 = vget_lane_" + 2191 typeCode + "(__b1, __c);\\\n" + 2192 " " + TypeString('s', typestr) + " __f1 = vmulx" + type + "_" + 2193 typeCode + "(__d1, __e1);\\\n" + 2194 " " + TypeString('d', typestr) + " __g1;\\\n" + 2195 " vset_lane_" + typeCode + "(__f1, __g1, __c);"; 2196 break; 2197 } 2198 2199 case OpScalarVMulXLaneQ: { 2200 bool dummy = false; 2201 char type = ClassifyType(typestr, dummy, dummy, dummy); 2202 if (type == 'f') type = 's'; 2203 std::string typeCode = ""; 2204 InstructionTypeCode(typestr, ClassS, quad, typeCode); 2205 s += TypeString(proto[1], typestr) + " __a1 = __a; \\\n "; 2206 s += TypeString(proto[2], typestr) + " __b1 = __b; \\\n "; 2207 s += TypeString('s', typestr) + " __d1 = vget_lane_" + 2208 typeCode + "(__a1, 0);\\\n" + 2209 " " + TypeString('s', typestr) + " __e1 = vgetq_lane_" + 2210 typeCode + "(__b1, __c);\\\n" + 2211 " " + TypeString('s', typestr) + " __f1 = vmulx" + type + "_" + 2212 typeCode + "(__d1, __e1);\\\n" + 2213 " " + TypeString('d', typestr) + " __g1;\\\n" + 2214 " vset_lane_" + typeCode + "(__f1, __g1, 0);"; 2215 break; 2216 } 2217 case OpScalarQDMullLane: { 2218 std::string typeCode = ""; 2219 InstructionTypeCode(typestr, ClassS, quad, typeCode); 2220 s += TypeString(proto[1], typestr) + " __a1 = __a; \\\n "; 2221 s += TypeString(proto[2], typestr) + " __b1 = __b; \\\n "; 2222 s += MangleName("vqdmull", typestr, ClassS) + "(__a1, " + 2223 "vget_lane_" + typeCode + "(__b1, __c));"; 2224 break; 2225 } 2226 case OpScalarQDMullLaneQ: { 2227 std::string typeCode = ""; 2228 InstructionTypeCode(typestr, ClassS, quad, typeCode); 2229 s += TypeString(proto[1], typestr) + " __a1 = __a; \\\n "; 2230 s += TypeString(proto[2], typestr) + " __b1 = __b; \\\n "; 2231 s += MangleName("vqdmull", typestr, ClassS) + "(__a1, " + 2232 "vgetq_lane_" + typeCode + "(__b1, __c));"; 2233 break; 2234 } 2235 case OpScalarQDMulHiLane: { 2236 std::string typeCode = ""; 2237 InstructionTypeCode(typestr, ClassS, quad, typeCode); 2238 s += TypeString(proto[1], typestr) + " __a1 = __a; \\\n "; 2239 s += TypeString(proto[2], typestr) + " __b1 = __b; \\\n "; 2240 s += MangleName("vqdmulh", typestr, ClassS) + "(__a1, " + 2241 "vget_lane_" + typeCode + "(__b1, __c));"; 2242 break; 2243 } 2244 case OpScalarQDMulHiLaneQ: { 2245 std::string typeCode = ""; 2246 InstructionTypeCode(typestr, ClassS, quad, typeCode); 2247 s += TypeString(proto[1], typestr) + " __a1 = __a; \\\n "; 2248 s += TypeString(proto[2], typestr) + " __b1 = __b; \\\n "; 2249 s += MangleName("vqdmulh", typestr, ClassS) + "(__a1, " + 2250 "vgetq_lane_" + typeCode + "(__b1, __c));"; 2251 break; 2252 } 2253 case OpScalarQRDMulHiLane: { 2254 std::string typeCode = ""; 2255 InstructionTypeCode(typestr, ClassS, quad, typeCode); 2256 s += TypeString(proto[1], typestr) + " __a1 = __a; \\\n "; 2257 s += TypeString(proto[2], typestr) + " __b1 = __b; \\\n "; 2258 s += MangleName("vqrdmulh", typestr, ClassS) + "(__a1, " + 2259 "vget_lane_" + typeCode + "(__b1, __c));"; 2260 break; 2261 } 2262 case OpScalarQRDMulHiLaneQ: { 2263 std::string typeCode = ""; 2264 InstructionTypeCode(typestr, ClassS, quad, typeCode); 2265 s += TypeString(proto[1], typestr) + " __a1 = __a; \\\n "; 2266 s += TypeString(proto[2], typestr) + " __b1 = __b; \\\n "; 2267 s += MangleName("vqrdmulh", typestr, ClassS) + "(__a1, " + 2268 "vgetq_lane_" + typeCode + "(__b1, __c));"; 2269 break; 2270 } 2271 case OpScalarGetLane:{ 2272 std::string typeCode = ""; 2273 InstructionTypeCode(typestr, ClassS, quad, typeCode); 2274 s += TypeString(proto[1], typestr) + " __a1 = __a; \\\n "; 2275 2276 std::string intType = quad ? "int16x8_t" : "int16x4_t"; 2277 std::string intName = quad ? "vgetq" : "vget"; 2278 2279 // reinterpret float16 vector as int16 vector 2280 s += intType + " __a2 = *(" + intType + " *)(&__a1);\\\n"; 2281 2282 s += " int16_t __a3 = " + intName + "_lane_s16(__a2, __b);\\\n"; 2283 2284 // reinterpret int16 vector as float16 vector 2285 s += " float16_t __a4 = *(float16_t *)(&__a3);\\\n"; 2286 s += " __a4;"; 2287 break; 2288 } 2289 case OpScalarSetLane:{ 2290 std::string typeCode = ""; 2291 InstructionTypeCode(typestr, ClassS, quad, typeCode); 2292 s += TypeString(proto[1], typestr) + " __a1 = __a;\\\n "; 2293 2294 std::string origType = quad ? "float16x8_t" : "float16x4_t"; 2295 std::string intType = quad ? "int16x8_t" : "int16x4_t"; 2296 std::string intName = quad ? "vsetq" : "vset"; 2297 2298 // reinterpret float16_t as int16_t 2299 s += "int16_t __a2 = *(int16_t *)(&__a1);\\\n"; 2300 // reinterpret float16 vector as int16 vector 2301 s += " " + intType + " __b2 = *(" + intType + " *)(&__b);\\\n"; 2302 2303 s += " " + intType + " __b3 = " + intName + "_lane_s16(__a2, __b2, __c);\\\n"; 2304 2305 // reinterpret int16 vector as float16 vector 2306 s += " " + origType + " __b4 = *(" + origType + " *)(&__b3);\\\n"; 2307 s += "__b4;"; 2308 break; 2309 } 2310 2311 default: 2312 PrintFatalError("unknown OpKind!"); 2313 } 2314 return s; 2315 } 2316 2317 static unsigned GetNeonEnum(const std::string &proto, StringRef typestr) { 2318 unsigned mod = proto[0]; 2319 2320 if (mod == 'v' || mod == 'f' || mod == 'F') 2321 mod = proto[1]; 2322 2323 bool quad = false; 2324 bool poly = false; 2325 bool usgn = false; 2326 bool scal = false; 2327 bool cnst = false; 2328 bool pntr = false; 2329 2330 // Base type to get the type string for. 2331 char type = ClassifyType(typestr, quad, poly, usgn); 2332 2333 // Based on the modifying character, change the type and width if necessary. 2334 type = ModType(mod, type, quad, poly, usgn, scal, cnst, pntr); 2335 2336 NeonTypeFlags::EltType ET; 2337 switch (type) { 2338 case 'c': 2339 ET = poly ? NeonTypeFlags::Poly8 : NeonTypeFlags::Int8; 2340 break; 2341 case 's': 2342 ET = poly ? NeonTypeFlags::Poly16 : NeonTypeFlags::Int16; 2343 break; 2344 case 'i': 2345 ET = NeonTypeFlags::Int32; 2346 break; 2347 case 'l': 2348 ET = poly ? NeonTypeFlags::Poly64 : NeonTypeFlags::Int64; 2349 break; 2350 case 'k': 2351 ET = NeonTypeFlags::Poly128; 2352 break; 2353 case 'h': 2354 ET = NeonTypeFlags::Float16; 2355 break; 2356 case 'f': 2357 ET = NeonTypeFlags::Float32; 2358 break; 2359 case 'd': 2360 ET = NeonTypeFlags::Float64; 2361 break; 2362 default: 2363 PrintFatalError("unhandled type!"); 2364 } 2365 NeonTypeFlags Flags(ET, usgn, quad && proto[1] != 'g'); 2366 return Flags.getFlags(); 2367 } 2368 2369 // We don't check 'a' in this function, because for builtin function the 2370 // argument matching to 'a' uses a vector type splatted from a scalar type. 2371 static bool ProtoHasScalar(const std::string proto) 2372 { 2373 return (proto.find('s') != std::string::npos 2374 || proto.find('z') != std::string::npos 2375 || proto.find('r') != std::string::npos 2376 || proto.find('b') != std::string::npos 2377 || proto.find('$') != std::string::npos 2378 || proto.find('y') != std::string::npos 2379 || proto.find('o') != std::string::npos); 2380 } 2381 2382 // Generate the definition for this intrinsic, e.g. __builtin_neon_cls(a) 2383 static std::string GenBuiltin(const std::string &name, const std::string &proto, 2384 StringRef typestr, ClassKind ck) { 2385 std::string s; 2386 2387 // If this builtin returns a struct 2, 3, or 4 vectors, pass it as an implicit 2388 // sret-like argument. 2389 bool sret = IsMultiVecProto(proto[0]); 2390 2391 bool define = UseMacro(proto); 2392 2393 // Check if the prototype has a scalar operand with the type of the vector 2394 // elements. If not, bitcasting the args will take care of arg checking. 2395 // The actual signedness etc. will be taken care of with special enums. 2396 if (!ProtoHasScalar(proto)) 2397 ck = ClassB; 2398 2399 if (proto[0] != 'v') { 2400 std::string ts = TypeString(proto[0], typestr); 2401 2402 if (define) { 2403 if (sret) 2404 s += ts + " r; "; 2405 else 2406 s += "(" + ts + ")"; 2407 } else if (sret) { 2408 s += ts + " r; "; 2409 } else { 2410 s += "return (" + ts + ")"; 2411 } 2412 } 2413 2414 bool splat = proto.find('a') != std::string::npos; 2415 2416 s += "__builtin_neon_"; 2417 if (splat) { 2418 // Call the non-splat builtin: chop off the "_n" suffix from the name. 2419 std::string vname(name, 0, name.size()-2); 2420 s += MangleName(vname, typestr, ck); 2421 } else { 2422 s += MangleName(name, typestr, ck); 2423 } 2424 s += "("; 2425 2426 // Pass the address of the return variable as the first argument to sret-like 2427 // builtins. 2428 if (sret) 2429 s += "&r, "; 2430 2431 char arg = 'a'; 2432 for (unsigned i = 1, e = proto.size(); i != e; ++i, ++arg) { 2433 std::string args = std::string(&arg, 1); 2434 2435 // Use the local temporaries instead of the macro arguments. 2436 args = "__" + args; 2437 2438 bool argQuad = false; 2439 bool argPoly = false; 2440 bool argUsgn = false; 2441 bool argScalar = false; 2442 bool dummy = false; 2443 char argType = ClassifyType(typestr, argQuad, argPoly, argUsgn); 2444 argType = ModType(proto[i], argType, argQuad, argPoly, argUsgn, argScalar, 2445 dummy, dummy); 2446 2447 // Handle multiple-vector values specially, emitting each subvector as an 2448 // argument to the __builtin. 2449 unsigned NumOfVec = 0; 2450 if (proto[i] >= '2' && proto[i] <= '4') { 2451 NumOfVec = proto[i] - '0'; 2452 } else if (proto[i] >= 'B' && proto[i] <= 'D') { 2453 NumOfVec = proto[i] - 'A' + 1; 2454 } 2455 2456 if (NumOfVec > 0) { 2457 // Check if an explicit cast is needed. 2458 if (argType != 'c' || argPoly || argUsgn) 2459 args = (argQuad ? "(int8x16_t)" : "(int8x8_t)") + args; 2460 2461 for (unsigned vi = 0, ve = NumOfVec; vi != ve; ++vi) { 2462 s += args + ".val[" + utostr(vi) + "]"; 2463 if ((vi + 1) < ve) 2464 s += ", "; 2465 } 2466 if ((i + 1) < e) 2467 s += ", "; 2468 2469 continue; 2470 } 2471 2472 if (splat && (i + 1) == e) 2473 args = Duplicate(GetNumElements(typestr, argQuad), typestr, args); 2474 2475 // Check if an explicit cast is needed. 2476 if ((splat || !argScalar) && 2477 ((ck == ClassB && argType != 'c') || argPoly || argUsgn)) { 2478 std::string argTypeStr = "c"; 2479 if (ck != ClassB) 2480 argTypeStr = argType; 2481 if (argQuad) 2482 argTypeStr = "Q" + argTypeStr; 2483 args = "(" + TypeString('d', argTypeStr) + ")" + args; 2484 } 2485 2486 s += args; 2487 if ((i + 1) < e) 2488 s += ", "; 2489 } 2490 2491 // Extra constant integer to hold type class enum for this function, e.g. s8 2492 if (ck == ClassB) 2493 s += ", " + utostr(GetNeonEnum(proto, typestr)); 2494 2495 s += ");"; 2496 2497 if (proto[0] != 'v' && sret) { 2498 if (define) 2499 s += " r;"; 2500 else 2501 s += " return r;"; 2502 } 2503 return s; 2504 } 2505 2506 static std::string GenBuiltinDef(const std::string &name, 2507 const std::string &proto, 2508 StringRef typestr, ClassKind ck) { 2509 std::string s("BUILTIN(__builtin_neon_"); 2510 2511 // If all types are the same size, bitcasting the args will take care 2512 // of arg checking. The actual signedness etc. will be taken care of with 2513 // special enums. 2514 if (!ProtoHasScalar(proto)) 2515 ck = ClassB; 2516 2517 s += MangleName(name, typestr, ck); 2518 s += ", \""; 2519 2520 for (unsigned i = 0, e = proto.size(); i != e; ++i) 2521 s += BuiltinTypeString(proto[i], typestr, ck, i == 0); 2522 2523 // Extra constant integer to hold type class enum for this function, e.g. s8 2524 if (ck == ClassB) 2525 s += "i"; 2526 2527 s += "\", \"n\")"; 2528 return s; 2529 } 2530 2531 static std::string GenIntrinsic(const std::string &name, 2532 const std::string &proto, 2533 StringRef outTypeStr, StringRef inTypeStr, 2534 OpKind kind, ClassKind classKind) { 2535 assert(!proto.empty() && ""); 2536 bool define = UseMacro(proto) && kind != OpUnavailable; 2537 std::string s; 2538 2539 // static always inline + return type 2540 if (define) 2541 s += "#define "; 2542 else 2543 s += "__ai " + TypeString(proto[0], outTypeStr) + " "; 2544 2545 // Function name with type suffix 2546 std::string mangledName = MangleName(name, outTypeStr, ClassS); 2547 if (outTypeStr != inTypeStr) { 2548 // If the input type is different (e.g., for vreinterpret), append a suffix 2549 // for the input type. String off a "Q" (quad) prefix so that MangleName 2550 // does not insert another "q" in the name. 2551 unsigned typeStrOff = (inTypeStr[0] == 'Q' ? 1 : 0); 2552 StringRef inTypeNoQuad = inTypeStr.substr(typeStrOff); 2553 mangledName = MangleName(mangledName, inTypeNoQuad, ClassS); 2554 } 2555 s += mangledName; 2556 2557 // Function arguments 2558 s += GenArgs(proto, inTypeStr, name); 2559 2560 // Definition. 2561 if (define) { 2562 s += " __extension__ ({ \\\n "; 2563 s += GenMacroLocals(proto, inTypeStr, name); 2564 } else if (kind == OpUnavailable) { 2565 s += " __attribute__((unavailable));\n"; 2566 return s; 2567 } else 2568 s += " {\n "; 2569 2570 if (kind != OpNone) 2571 s += GenOpString(name, kind, proto, outTypeStr); 2572 else 2573 s += GenBuiltin(name, proto, outTypeStr, classKind); 2574 if (define) 2575 s += " })"; 2576 else 2577 s += " }"; 2578 s += "\n"; 2579 return s; 2580 } 2581 2582 /// run - Read the records in arm_neon.td and output arm_neon.h. arm_neon.h 2583 /// is comprised of type definitions and function declarations. 2584 void NeonEmitter::run(raw_ostream &OS) { 2585 OS << 2586 "/*===---- arm_neon.h - ARM Neon intrinsics ------------------------------" 2587 "---===\n" 2588 " *\n" 2589 " * Permission is hereby granted, free of charge, to any person obtaining " 2590 "a copy\n" 2591 " * of this software and associated documentation files (the \"Software\")," 2592 " to deal\n" 2593 " * in the Software without restriction, including without limitation the " 2594 "rights\n" 2595 " * to use, copy, modify, merge, publish, distribute, sublicense, " 2596 "and/or sell\n" 2597 " * copies of the Software, and to permit persons to whom the Software is\n" 2598 " * furnished to do so, subject to the following conditions:\n" 2599 " *\n" 2600 " * The above copyright notice and this permission notice shall be " 2601 "included in\n" 2602 " * all copies or substantial portions of the Software.\n" 2603 " *\n" 2604 " * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, " 2605 "EXPRESS OR\n" 2606 " * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF " 2607 "MERCHANTABILITY,\n" 2608 " * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT " 2609 "SHALL THE\n" 2610 " * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR " 2611 "OTHER\n" 2612 " * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, " 2613 "ARISING FROM,\n" 2614 " * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER " 2615 "DEALINGS IN\n" 2616 " * THE SOFTWARE.\n" 2617 " *\n" 2618 " *===--------------------------------------------------------------------" 2619 "---===\n" 2620 " */\n\n"; 2621 2622 OS << "#ifndef __ARM_NEON_H\n"; 2623 OS << "#define __ARM_NEON_H\n\n"; 2624 2625 OS << "#if !defined(__ARM_NEON)\n"; 2626 OS << "#error \"NEON support not enabled\"\n"; 2627 OS << "#endif\n\n"; 2628 2629 OS << "#include <stdint.h>\n\n"; 2630 2631 // Emit NEON-specific scalar typedefs. 2632 OS << "typedef float float32_t;\n"; 2633 OS << "typedef __fp16 float16_t;\n"; 2634 2635 OS << "#ifdef __aarch64__\n"; 2636 OS << "typedef double float64_t;\n"; 2637 OS << "#endif\n\n"; 2638 2639 // For now, signedness of polynomial types depends on target 2640 OS << "#ifdef __aarch64__\n"; 2641 OS << "typedef uint8_t poly8_t;\n"; 2642 OS << "typedef uint16_t poly16_t;\n"; 2643 OS << "typedef uint64_t poly64_t;\n"; 2644 OS << "typedef __uint128_t poly128_t;\n"; 2645 OS << "#else\n"; 2646 OS << "typedef int8_t poly8_t;\n"; 2647 OS << "typedef int16_t poly16_t;\n"; 2648 OS << "#endif\n"; 2649 2650 // Emit Neon vector typedefs. 2651 std::string TypedefTypes( 2652 "cQcsQsiQilQlUcQUcUsQUsUiQUiUlQUlhQhfQfdQdPcQPcPsQPsPlQPl"); 2653 SmallVector<StringRef, 24> TDTypeVec; 2654 ParseTypes(0, TypedefTypes, TDTypeVec); 2655 2656 // Emit vector typedefs. 2657 bool isA64 = false; 2658 bool preinsert; 2659 bool postinsert; 2660 for (unsigned i = 0, e = TDTypeVec.size(); i != e; ++i) { 2661 bool dummy, quad = false, poly = false; 2662 char type = ClassifyType(TDTypeVec[i], quad, poly, dummy); 2663 preinsert = false; 2664 postinsert = false; 2665 2666 if (type == 'd' || (type == 'l' && poly)) { 2667 preinsert = isA64? false: true; 2668 isA64 = true; 2669 } else { 2670 postinsert = isA64? true: false; 2671 isA64 = false; 2672 } 2673 if (postinsert) 2674 OS << "#endif\n"; 2675 if (preinsert) 2676 OS << "#ifdef __aarch64__\n"; 2677 2678 if (poly) 2679 OS << "typedef __attribute__((neon_polyvector_type("; 2680 else 2681 OS << "typedef __attribute__((neon_vector_type("; 2682 2683 unsigned nElts = GetNumElements(TDTypeVec[i], quad); 2684 OS << utostr(nElts) << "))) "; 2685 if (nElts < 10) 2686 OS << " "; 2687 2688 OS << TypeString('s', TDTypeVec[i]); 2689 OS << " " << TypeString('d', TDTypeVec[i]) << ";\n"; 2690 2691 } 2692 postinsert = isA64? true: false; 2693 if (postinsert) 2694 OS << "#endif\n"; 2695 OS << "\n"; 2696 2697 // Emit struct typedefs. 2698 isA64 = false; 2699 for (unsigned vi = 2; vi != 5; ++vi) { 2700 for (unsigned i = 0, e = TDTypeVec.size(); i != e; ++i) { 2701 bool dummy, quad = false, poly = false; 2702 char type = ClassifyType(TDTypeVec[i], quad, poly, dummy); 2703 preinsert = false; 2704 postinsert = false; 2705 2706 if (type == 'd' || (type == 'l' && poly)) { 2707 preinsert = isA64? false: true; 2708 isA64 = true; 2709 } else { 2710 postinsert = isA64? true: false; 2711 isA64 = false; 2712 } 2713 if (postinsert) 2714 OS << "#endif\n"; 2715 if (preinsert) 2716 OS << "#ifdef __aarch64__\n"; 2717 2718 std::string ts = TypeString('d', TDTypeVec[i]); 2719 std::string vs = TypeString('0' + vi, TDTypeVec[i]); 2720 OS << "typedef struct " << vs << " {\n"; 2721 OS << " " << ts << " val"; 2722 OS << "[" << utostr(vi) << "]"; 2723 OS << ";\n} "; 2724 OS << vs << ";\n"; 2725 OS << "\n"; 2726 } 2727 } 2728 postinsert = isA64? true: false; 2729 if (postinsert) 2730 OS << "#endif\n"; 2731 OS << "\n"; 2732 2733 OS<<"#define __ai static inline __attribute__((__always_inline__, __nodebug__))\n\n"; 2734 2735 std::vector<Record*> RV = Records.getAllDerivedDefinitions("Inst"); 2736 2737 StringMap<ClassKind> EmittedMap; 2738 2739 // Emit vmovl, vmull and vabd intrinsics first so they can be used by other 2740 // intrinsics. (Some of the saturating multiply instructions are also 2741 // used to implement the corresponding "_lane" variants, but tablegen 2742 // sorts the records into alphabetical order so that the "_lane" variants 2743 // come after the intrinsics they use.) 2744 emitIntrinsic(OS, Records.getDef("VMOVL"), EmittedMap); 2745 emitIntrinsic(OS, Records.getDef("VMULL"), EmittedMap); 2746 emitIntrinsic(OS, Records.getDef("VABD"), EmittedMap); 2747 emitIntrinsic(OS, Records.getDef("VABDL"), EmittedMap); 2748 2749 // ARM intrinsics must be emitted before AArch64 intrinsics to ensure 2750 // common intrinsics appear only once in the output stream. 2751 // The check for uniquiness is done in emitIntrinsic. 2752 // Emit ARM intrinsics. 2753 for (unsigned i = 0, e = RV.size(); i != e; ++i) { 2754 Record *R = RV[i]; 2755 2756 // Skip AArch64 intrinsics; they will be emitted at the end. 2757 bool isA64 = R->getValueAsBit("isA64"); 2758 if (isA64) 2759 continue; 2760 2761 if (R->getName() != "VMOVL" && R->getName() != "VMULL" && 2762 R->getName() != "VABD") 2763 emitIntrinsic(OS, R, EmittedMap); 2764 } 2765 2766 // Emit AArch64-specific intrinsics. 2767 OS << "#ifdef __aarch64__\n"; 2768 2769 emitIntrinsic(OS, Records.getDef("VMULL_P64"), EmittedMap); 2770 emitIntrinsic(OS, Records.getDef("VMOVL_HIGH"), EmittedMap); 2771 emitIntrinsic(OS, Records.getDef("VMULL_HIGH"), EmittedMap); 2772 emitIntrinsic(OS, Records.getDef("VABDL_HIGH"), EmittedMap); 2773 2774 for (unsigned i = 0, e = RV.size(); i != e; ++i) { 2775 Record *R = RV[i]; 2776 2777 // Skip ARM intrinsics already included above. 2778 bool isA64 = R->getValueAsBit("isA64"); 2779 if (!isA64) 2780 continue; 2781 2782 // Skip crypto temporarily, and will emit them all together at the end. 2783 bool isCrypto = R->getValueAsBit("isCrypto"); 2784 if (isCrypto) 2785 continue; 2786 2787 emitIntrinsic(OS, R, EmittedMap); 2788 } 2789 2790 OS << "#endif\n\n"; 2791 2792 // Now emit all the crypto intrinsics together 2793 OS << "#ifdef __ARM_FEATURE_CRYPTO\n"; 2794 2795 for (unsigned i = 0, e = RV.size(); i != e; ++i) { 2796 Record *R = RV[i]; 2797 2798 bool isCrypto = R->getValueAsBit("isCrypto"); 2799 if (!isCrypto) 2800 continue; 2801 2802 emitIntrinsic(OS, R, EmittedMap); 2803 } 2804 2805 2806 OS << "#endif\n\n"; 2807 2808 OS << "#undef __ai\n\n"; 2809 OS << "#endif /* __ARM_NEON_H */\n"; 2810 } 2811 2812 /// emitIntrinsic - Write out the arm_neon.h header file definitions for the 2813 /// intrinsics specified by record R checking for intrinsic uniqueness. 2814 void NeonEmitter::emitIntrinsic(raw_ostream &OS, Record *R, 2815 StringMap<ClassKind> &EmittedMap) { 2816 std::string name = R->getValueAsString("Name"); 2817 std::string Proto = R->getValueAsString("Prototype"); 2818 std::string Types = R->getValueAsString("Types"); 2819 2820 SmallVector<StringRef, 16> TypeVec; 2821 ParseTypes(R, Types, TypeVec); 2822 2823 OpKind kind = OpMap[R->getValueAsDef("Operand")->getName()]; 2824 2825 ClassKind classKind = ClassNone; 2826 if (R->getSuperClasses().size() >= 2) 2827 classKind = ClassMap[R->getSuperClasses()[1]]; 2828 if (classKind == ClassNone && kind == OpNone) 2829 PrintFatalError(R->getLoc(), "Builtin has no class kind"); 2830 2831 for (unsigned ti = 0, te = TypeVec.size(); ti != te; ++ti) { 2832 if (kind == OpReinterpret) { 2833 bool outQuad = false; 2834 bool dummy = false; 2835 (void)ClassifyType(TypeVec[ti], outQuad, dummy, dummy); 2836 for (unsigned srcti = 0, srcte = TypeVec.size(); 2837 srcti != srcte; ++srcti) { 2838 bool inQuad = false; 2839 (void)ClassifyType(TypeVec[srcti], inQuad, dummy, dummy); 2840 if (srcti == ti || inQuad != outQuad) 2841 continue; 2842 std::string s = GenIntrinsic(name, Proto, TypeVec[ti], TypeVec[srcti], 2843 OpCast, ClassS); 2844 if (EmittedMap.count(s)) 2845 continue; 2846 EmittedMap[s] = ClassS; 2847 OS << s; 2848 } 2849 } else { 2850 std::string s = 2851 GenIntrinsic(name, Proto, TypeVec[ti], TypeVec[ti], kind, classKind); 2852 if (EmittedMap.count(s)) 2853 continue; 2854 EmittedMap[s] = classKind; 2855 OS << s; 2856 } 2857 } 2858 OS << "\n"; 2859 } 2860 2861 static unsigned RangeFromType(const char mod, StringRef typestr) { 2862 // base type to get the type string for. 2863 bool quad = false, dummy = false; 2864 char type = ClassifyType(typestr, quad, dummy, dummy); 2865 type = ModType(mod, type, quad, dummy, dummy, dummy, dummy, dummy); 2866 2867 switch (type) { 2868 case 'c': 2869 return (8 << (int)quad) - 1; 2870 case 'h': 2871 case 's': 2872 return (4 << (int)quad) - 1; 2873 case 'f': 2874 case 'i': 2875 return (2 << (int)quad) - 1; 2876 case 'd': 2877 case 'l': 2878 return (1 << (int)quad) - 1; 2879 case 'k': 2880 return 0; 2881 default: 2882 PrintFatalError("unhandled type!"); 2883 } 2884 } 2885 2886 static unsigned RangeScalarShiftImm(const char mod, StringRef typestr) { 2887 // base type to get the type string for. 2888 bool dummy = false; 2889 char type = ClassifyType(typestr, dummy, dummy, dummy); 2890 type = ModType(mod, type, dummy, dummy, dummy, dummy, dummy, dummy); 2891 2892 switch (type) { 2893 case 'c': 2894 return 7; 2895 case 'h': 2896 case 's': 2897 return 15; 2898 case 'f': 2899 case 'i': 2900 return 31; 2901 case 'd': 2902 case 'l': 2903 return 63; 2904 case 'k': 2905 return 127; 2906 default: 2907 PrintFatalError("unhandled type!"); 2908 } 2909 } 2910 2911 /// Generate the ARM and AArch64 intrinsic range checking code for 2912 /// shift/lane immediates, checking for unique declarations. 2913 void 2914 NeonEmitter::genIntrinsicRangeCheckCode(raw_ostream &OS, 2915 StringMap<ClassKind> &A64IntrinsicMap, 2916 bool isA64RangeCheck) { 2917 std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst"); 2918 StringMap<OpKind> EmittedMap; 2919 2920 // Generate the intrinsic range checking code for shift/lane immediates. 2921 if (isA64RangeCheck) 2922 OS << "#ifdef GET_NEON_AARCH64_IMMEDIATE_CHECK\n"; 2923 else 2924 OS << "#ifdef GET_NEON_IMMEDIATE_CHECK\n"; 2925 2926 for (unsigned i = 0, e = RV.size(); i != e; ++i) { 2927 Record *R = RV[i]; 2928 2929 OpKind k = OpMap[R->getValueAsDef("Operand")->getName()]; 2930 if (k != OpNone) 2931 continue; 2932 2933 std::string name = R->getValueAsString("Name"); 2934 std::string Proto = R->getValueAsString("Prototype"); 2935 std::string Types = R->getValueAsString("Types"); 2936 std::string Rename = name + "@" + Proto; 2937 2938 // Functions with 'a' (the splat code) in the type prototype should not get 2939 // their own builtin as they use the non-splat variant. 2940 if (Proto.find('a') != std::string::npos) 2941 continue; 2942 2943 // Functions which do not have an immediate do not need to have range 2944 // checking code emitted. 2945 size_t immPos = Proto.find('i'); 2946 if (immPos == std::string::npos) 2947 continue; 2948 2949 SmallVector<StringRef, 16> TypeVec; 2950 ParseTypes(R, Types, TypeVec); 2951 2952 if (R->getSuperClasses().size() < 2) 2953 PrintFatalError(R->getLoc(), "Builtin has no class kind"); 2954 2955 ClassKind ck = ClassMap[R->getSuperClasses()[1]]; 2956 if (!ProtoHasScalar(Proto)) 2957 ck = ClassB; 2958 2959 // Do not include AArch64 range checks if not generating code for AArch64. 2960 bool isA64 = R->getValueAsBit("isA64"); 2961 if (!isA64RangeCheck && isA64) 2962 continue; 2963 2964 // Include ARM range checks in AArch64 but only if ARM intrinsics are not 2965 // redefined by AArch64 to handle new types. 2966 if (isA64RangeCheck && !isA64 && A64IntrinsicMap.count(Rename)) { 2967 ClassKind &A64CK = A64IntrinsicMap[Rename]; 2968 if (A64CK == ck && ck != ClassNone) 2969 continue; 2970 } 2971 2972 for (unsigned ti = 0, te = TypeVec.size(); ti != te; ++ti) { 2973 std::string namestr, shiftstr, rangestr; 2974 2975 if (R->getValueAsBit("isVCVT_N")) { 2976 // VCVT between floating- and fixed-point values takes an immediate 2977 // in the range [1, 32] for f32, or [1, 64] for f64. 2978 ck = ClassB; 2979 if (name.find("32") != std::string::npos) 2980 rangestr = "l = 1; u = 31"; // upper bound = l + u 2981 else if (name.find("64") != std::string::npos) 2982 rangestr = "l = 1; u = 63"; 2983 else 2984 PrintFatalError(R->getLoc(), 2985 "Fixed point convert name should contains \"32\" or \"64\""); 2986 2987 } else if (R->getValueAsBit("isScalarShift")) { 2988 // Right shifts have an 'r' in the name, left shifts do not. Convert 2989 // instructions have the same bounds and right shifts. 2990 if (name.find('r') != std::string::npos || 2991 name.find("cvt") != std::string::npos) 2992 rangestr = "l = 1; "; 2993 2994 unsigned upBound = RangeScalarShiftImm(Proto[immPos - 1], TypeVec[ti]); 2995 // Narrow shift has half the upper bound 2996 if (R->getValueAsBit("isScalarNarrowShift")) 2997 upBound /= 2; 2998 2999 rangestr += "u = " + utostr(upBound); 3000 } else if (R->getValueAsBit("isShift")) { 3001 // Builtins which are overloaded by type will need to have their upper 3002 // bound computed at Sema time based on the type constant. 3003 shiftstr = ", true"; 3004 3005 // Right shifts have an 'r' in the name, left shifts do not. 3006 if (name.find('r') != std::string::npos) 3007 rangestr = "l = 1; "; 3008 3009 rangestr += "u = RFT(TV" + shiftstr + ")"; 3010 } else if (ck == ClassB) { 3011 // ClassB intrinsics have a type (and hence lane number) that is only 3012 // known at runtime. 3013 assert(immPos > 0 && "unexpected immediate operand"); 3014 if (R->getValueAsBit("isLaneQ")) 3015 rangestr = "u = RFT(TV, false, true)"; 3016 else 3017 rangestr = "u = RFT(TV, false, false)"; 3018 } else { 3019 // The immediate generally refers to a lane in the preceding argument. 3020 assert(immPos > 0 && "unexpected immediate operand"); 3021 rangestr = 3022 "u = " + utostr(RangeFromType(Proto[immPos - 1], TypeVec[ti])); 3023 } 3024 // Make sure cases appear only once by uniquing them in a string map. 3025 namestr = MangleName(name, TypeVec[ti], ck); 3026 if (EmittedMap.count(namestr)) 3027 continue; 3028 EmittedMap[namestr] = OpNone; 3029 3030 // Calculate the index of the immediate that should be range checked. 3031 unsigned immidx = 0; 3032 3033 // Builtins that return a struct of multiple vectors have an extra 3034 // leading arg for the struct return. 3035 if (IsMultiVecProto(Proto[0])) 3036 ++immidx; 3037 3038 // Add one to the index for each argument until we reach the immediate 3039 // to be checked. Structs of vectors are passed as multiple arguments. 3040 for (unsigned ii = 1, ie = Proto.size(); ii != ie; ++ii) { 3041 switch (Proto[ii]) { 3042 default: 3043 immidx += 1; 3044 break; 3045 case '2': 3046 case 'B': 3047 immidx += 2; 3048 break; 3049 case '3': 3050 case 'C': 3051 immidx += 3; 3052 break; 3053 case '4': 3054 case 'D': 3055 immidx += 4; 3056 break; 3057 case 'i': 3058 ie = ii + 1; 3059 break; 3060 } 3061 } 3062 OS << "case NEON::BI__builtin_neon_"; 3063 OS << MangleName(name, TypeVec[ti], ck) << ": i = " << immidx << "; " 3064 << rangestr << "; break;\n"; 3065 } 3066 } 3067 OS << "#endif\n\n"; 3068 } 3069 3070 /// Generate the ARM and AArch64 overloaded type checking code for 3071 /// SemaChecking.cpp, checking for unique builtin declarations. 3072 void 3073 NeonEmitter::genOverloadTypeCheckCode(raw_ostream &OS, 3074 StringMap<ClassKind> &A64IntrinsicMap, 3075 bool isA64TypeCheck) { 3076 std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst"); 3077 3078 // Generate the overloaded type checking code for SemaChecking.cpp 3079 if (isA64TypeCheck) 3080 OS << "#ifdef GET_NEON_AARCH64_OVERLOAD_CHECK\n"; 3081 else 3082 OS << "#ifdef GET_NEON_OVERLOAD_CHECK\n"; 3083 3084 for (unsigned i = 0, e = RV.size(); i != e; ++i) { 3085 Record *R = RV[i]; 3086 OpKind k = OpMap[R->getValueAsDef("Operand")->getName()]; 3087 if (k != OpNone) 3088 continue; 3089 3090 std::string Proto = R->getValueAsString("Prototype"); 3091 std::string Types = R->getValueAsString("Types"); 3092 std::string name = R->getValueAsString("Name"); 3093 std::string Rename = name + "@" + Proto; 3094 3095 // Functions with 'a' (the splat code) in the type prototype should not get 3096 // their own builtin as they use the non-splat variant. 3097 if (Proto.find('a') != std::string::npos) 3098 continue; 3099 3100 // Functions which have a scalar argument cannot be overloaded, no need to 3101 // check them if we are emitting the type checking code. 3102 if (ProtoHasScalar(Proto)) 3103 continue; 3104 3105 SmallVector<StringRef, 16> TypeVec; 3106 ParseTypes(R, Types, TypeVec); 3107 3108 if (R->getSuperClasses().size() < 2) 3109 PrintFatalError(R->getLoc(), "Builtin has no class kind"); 3110 3111 // Do not include AArch64 type checks if not generating code for AArch64. 3112 bool isA64 = R->getValueAsBit("isA64"); 3113 if (!isA64TypeCheck && isA64) 3114 continue; 3115 3116 // Include ARM type check in AArch64 but only if ARM intrinsics 3117 // are not redefined in AArch64 to handle new types, e.g. "vabd" is a SIntr 3118 // redefined in AArch64 to handle an additional 2 x f64 type. 3119 ClassKind ck = ClassMap[R->getSuperClasses()[1]]; 3120 if (isA64TypeCheck && !isA64 && A64IntrinsicMap.count(Rename)) { 3121 ClassKind &A64CK = A64IntrinsicMap[Rename]; 3122 if (A64CK == ck && ck != ClassNone) 3123 continue; 3124 } 3125 3126 int si = -1, qi = -1; 3127 uint64_t mask = 0, qmask = 0; 3128 for (unsigned ti = 0, te = TypeVec.size(); ti != te; ++ti) { 3129 // Generate the switch case(s) for this builtin for the type validation. 3130 bool quad = false, poly = false, usgn = false; 3131 (void) ClassifyType(TypeVec[ti], quad, poly, usgn); 3132 3133 if (quad) { 3134 qi = ti; 3135 qmask |= 1ULL << GetNeonEnum(Proto, TypeVec[ti]); 3136 } else { 3137 si = ti; 3138 mask |= 1ULL << GetNeonEnum(Proto, TypeVec[ti]); 3139 } 3140 } 3141 3142 // Check if the builtin function has a pointer or const pointer argument. 3143 int PtrArgNum = -1; 3144 bool HasConstPtr = false; 3145 for (unsigned arg = 1, arge = Proto.size(); arg != arge; ++arg) { 3146 char ArgType = Proto[arg]; 3147 if (ArgType == 'c') { 3148 HasConstPtr = true; 3149 PtrArgNum = arg - 1; 3150 break; 3151 } 3152 if (ArgType == 'p') { 3153 PtrArgNum = arg - 1; 3154 break; 3155 } 3156 } 3157 // For sret builtins, adjust the pointer argument index. 3158 if (PtrArgNum >= 0 && IsMultiVecProto(Proto[0])) 3159 PtrArgNum += 1; 3160 3161 // Omit type checking for the pointer arguments of vld1_lane, vld1_dup, 3162 // and vst1_lane intrinsics. Using a pointer to the vector element 3163 // type with one of those operations causes codegen to select an aligned 3164 // load/store instruction. If you want an unaligned operation, 3165 // the pointer argument needs to have less alignment than element type, 3166 // so just accept any pointer type. 3167 if (name == "vld1_lane" || name == "vld1_dup" || name == "vst1_lane") { 3168 PtrArgNum = -1; 3169 HasConstPtr = false; 3170 } 3171 3172 if (mask) { 3173 OS << "case NEON::BI__builtin_neon_"; 3174 OS << MangleName(name, TypeVec[si], ClassB) << ": mask = " 3175 << "0x" << utohexstr(mask) << "ULL"; 3176 if (PtrArgNum >= 0) 3177 OS << "; PtrArgNum = " << PtrArgNum; 3178 if (HasConstPtr) 3179 OS << "; HasConstPtr = true"; 3180 OS << "; break;\n"; 3181 } 3182 if (qmask) { 3183 OS << "case NEON::BI__builtin_neon_"; 3184 OS << MangleName(name, TypeVec[qi], ClassB) << ": mask = " 3185 << "0x" << utohexstr(qmask) << "ULL"; 3186 if (PtrArgNum >= 0) 3187 OS << "; PtrArgNum = " << PtrArgNum; 3188 if (HasConstPtr) 3189 OS << "; HasConstPtr = true"; 3190 OS << "; break;\n"; 3191 } 3192 } 3193 OS << "#endif\n\n"; 3194 } 3195 3196 /// genBuiltinsDef: Generate the BuiltinsARM.def and BuiltinsAArch64.def 3197 /// declaration of builtins, checking for unique builtin declarations. 3198 void NeonEmitter::genBuiltinsDef(raw_ostream &OS) { 3199 std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst"); 3200 StringMap<OpKind> EmittedMap; 3201 3202 // Generate BuiltinsNEON. 3203 OS << "#ifdef GET_NEON_BUILTINS\n"; 3204 3205 for (unsigned i = 0, e = RV.size(); i != e; ++i) { 3206 Record *R = RV[i]; 3207 OpKind k = OpMap[R->getValueAsDef("Operand")->getName()]; 3208 if (k != OpNone) 3209 continue; 3210 3211 std::string Proto = R->getValueAsString("Prototype"); 3212 std::string name = R->getValueAsString("Name"); 3213 std::string Rename = name + "@" + Proto; 3214 3215 // Functions with 'a' (the splat code) in the type prototype should not get 3216 // their own builtin as they use the non-splat variant. 3217 if (Proto.find('a') != std::string::npos) 3218 continue; 3219 3220 std::string Types = R->getValueAsString("Types"); 3221 SmallVector<StringRef, 16> TypeVec; 3222 ParseTypes(R, Types, TypeVec); 3223 3224 if (R->getSuperClasses().size() < 2) 3225 PrintFatalError(R->getLoc(), "Builtin has no class kind"); 3226 3227 ClassKind ck = ClassMap[R->getSuperClasses()[1]]; 3228 3229 for (unsigned ti = 0, te = TypeVec.size(); ti != te; ++ti) { 3230 // Generate the declaration for this builtin, ensuring 3231 // that each unique BUILTIN() macro appears only once in the output 3232 // stream. 3233 std::string bd = GenBuiltinDef(name, Proto, TypeVec[ti], ck); 3234 if (EmittedMap.count(bd)) 3235 continue; 3236 3237 EmittedMap[bd] = OpNone; 3238 OS << bd << "\n"; 3239 } 3240 } 3241 OS << "#endif\n\n"; 3242 } 3243 3244 /// runHeader - Emit a file with sections defining: 3245 /// 1. the NEON section of BuiltinsARM.def and BuiltinsAArch64.def. 3246 /// 2. the SemaChecking code for the type overload checking. 3247 /// 3. the SemaChecking code for validation of intrinsic immediate arguments. 3248 void NeonEmitter::runHeader(raw_ostream &OS) { 3249 std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst"); 3250 3251 // build a map of AArch64 intriniscs to be used in uniqueness checks. 3252 StringMap<ClassKind> A64IntrinsicMap; 3253 for (unsigned i = 0, e = RV.size(); i != e; ++i) { 3254 Record *R = RV[i]; 3255 3256 bool isA64 = R->getValueAsBit("isA64"); 3257 if (!isA64) 3258 continue; 3259 3260 ClassKind CK = ClassNone; 3261 if (R->getSuperClasses().size() >= 2) 3262 CK = ClassMap[R->getSuperClasses()[1]]; 3263 3264 std::string Name = R->getValueAsString("Name"); 3265 std::string Proto = R->getValueAsString("Prototype"); 3266 std::string Rename = Name + "@" + Proto; 3267 if (A64IntrinsicMap.count(Rename)) 3268 continue; 3269 A64IntrinsicMap[Rename] = CK; 3270 } 3271 3272 // Generate shared BuiltinsXXX.def 3273 genBuiltinsDef(OS); 3274 3275 // Generate ARM overloaded type checking code for SemaChecking.cpp 3276 genOverloadTypeCheckCode(OS, A64IntrinsicMap, false); 3277 3278 // Generate AArch64 overloaded type checking code for SemaChecking.cpp 3279 genOverloadTypeCheckCode(OS, A64IntrinsicMap, true); 3280 3281 // Generate ARM range checking code for shift/lane immediates. 3282 genIntrinsicRangeCheckCode(OS, A64IntrinsicMap, false); 3283 3284 // Generate the AArch64 range checking code for shift/lane immediates. 3285 genIntrinsicRangeCheckCode(OS, A64IntrinsicMap, true); 3286 } 3287 3288 /// GenTest - Write out a test for the intrinsic specified by the name and 3289 /// type strings, including the embedded patterns for FileCheck to match. 3290 static std::string GenTest(const std::string &name, 3291 const std::string &proto, 3292 StringRef outTypeStr, StringRef inTypeStr, 3293 bool isShift, bool isHiddenLOp, 3294 ClassKind ck, const std::string &InstName, 3295 bool isA64, 3296 std::string & testFuncProto) { 3297 assert(!proto.empty() && ""); 3298 std::string s; 3299 3300 // Function name with type suffix 3301 std::string mangledName = MangleName(name, outTypeStr, ClassS); 3302 if (outTypeStr != inTypeStr) { 3303 // If the input type is different (e.g., for vreinterpret), append a suffix 3304 // for the input type. String off a "Q" (quad) prefix so that MangleName 3305 // does not insert another "q" in the name. 3306 unsigned typeStrOff = (inTypeStr[0] == 'Q' ? 1 : 0); 3307 StringRef inTypeNoQuad = inTypeStr.substr(typeStrOff); 3308 mangledName = MangleName(mangledName, inTypeNoQuad, ClassS); 3309 } 3310 3311 // todo: GenerateChecksForIntrinsic does not generate CHECK 3312 // for aarch64 instructions yet 3313 std::vector<std::string> FileCheckPatterns; 3314 if (!isA64) { 3315 GenerateChecksForIntrinsic(name, proto, outTypeStr, inTypeStr, ck, InstName, 3316 isHiddenLOp, FileCheckPatterns); 3317 s+= "// CHECK_ARM: test_" + mangledName + "\n"; 3318 } 3319 s += "// CHECK_AARCH64: test_" + mangledName + "\n"; 3320 3321 // Emit the FileCheck patterns. 3322 // If for any reason we do not want to emit a check, mangledInst 3323 // will be the empty string. 3324 if (FileCheckPatterns.size()) { 3325 for (std::vector<std::string>::const_iterator i = FileCheckPatterns.begin(), 3326 e = FileCheckPatterns.end(); 3327 i != e; 3328 ++i) { 3329 s += "// CHECK_ARM: " + *i + "\n"; 3330 } 3331 } 3332 3333 // Emit the start of the test function. 3334 3335 testFuncProto = TypeString(proto[0], outTypeStr) + " test_" + mangledName + "("; 3336 char arg = 'a'; 3337 std::string comma; 3338 for (unsigned i = 1, e = proto.size(); i != e; ++i, ++arg) { 3339 // Do not create arguments for values that must be immediate constants. 3340 if (proto[i] == 'i') 3341 continue; 3342 testFuncProto += comma + TypeString(proto[i], inTypeStr) + " "; 3343 testFuncProto.push_back(arg); 3344 comma = ", "; 3345 } 3346 testFuncProto += ")"; 3347 3348 s+= testFuncProto; 3349 s+= " {\n "; 3350 3351 if (proto[0] != 'v') 3352 s += "return "; 3353 s += mangledName + "("; 3354 arg = 'a'; 3355 for (unsigned i = 1, e = proto.size(); i != e; ++i, ++arg) { 3356 if (proto[i] == 'i') { 3357 // For immediate operands, test the maximum value. 3358 if (isShift) 3359 s += "1"; // FIXME 3360 else 3361 // The immediate generally refers to a lane in the preceding argument. 3362 s += utostr(RangeFromType(proto[i-1], inTypeStr)); 3363 } else { 3364 s.push_back(arg); 3365 } 3366 if ((i + 1) < e) 3367 s += ", "; 3368 } 3369 s += ");\n}\n\n"; 3370 return s; 3371 } 3372 3373 /// Write out all intrinsic tests for the specified target, checking 3374 /// for intrinsic test uniqueness. 3375 void NeonEmitter::genTargetTest(raw_ostream &OS, StringMap<OpKind> &EmittedMap, 3376 bool isA64GenTest) { 3377 if (isA64GenTest) 3378 OS << "#ifdef __aarch64__\n"; 3379 3380 std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst"); 3381 for (unsigned i = 0, e = RV.size(); i != e; ++i) { 3382 Record *R = RV[i]; 3383 std::string name = R->getValueAsString("Name"); 3384 std::string Proto = R->getValueAsString("Prototype"); 3385 std::string Types = R->getValueAsString("Types"); 3386 bool isShift = R->getValueAsBit("isShift"); 3387 std::string InstName = R->getValueAsString("InstName"); 3388 bool isHiddenLOp = R->getValueAsBit("isHiddenLInst"); 3389 bool isA64 = R->getValueAsBit("isA64"); 3390 3391 // do not include AArch64 intrinsic test if not generating 3392 // code for AArch64 3393 if (!isA64GenTest && isA64) 3394 continue; 3395 3396 SmallVector<StringRef, 16> TypeVec; 3397 ParseTypes(R, Types, TypeVec); 3398 3399 ClassKind ck = ClassMap[R->getSuperClasses()[1]]; 3400 OpKind kind = OpMap[R->getValueAsDef("Operand")->getName()]; 3401 if (kind == OpUnavailable) 3402 continue; 3403 for (unsigned ti = 0, te = TypeVec.size(); ti != te; ++ti) { 3404 if (kind == OpReinterpret) { 3405 bool outQuad = false; 3406 bool dummy = false; 3407 (void)ClassifyType(TypeVec[ti], outQuad, dummy, dummy); 3408 for (unsigned srcti = 0, srcte = TypeVec.size(); 3409 srcti != srcte; ++srcti) { 3410 bool inQuad = false; 3411 (void)ClassifyType(TypeVec[srcti], inQuad, dummy, dummy); 3412 if (srcti == ti || inQuad != outQuad) 3413 continue; 3414 std::string testFuncProto; 3415 std::string s = GenTest(name, Proto, TypeVec[ti], TypeVec[srcti], 3416 isShift, isHiddenLOp, ck, InstName, isA64, 3417 testFuncProto); 3418 if (EmittedMap.count(testFuncProto)) 3419 continue; 3420 EmittedMap[testFuncProto] = kind; 3421 OS << s << "\n"; 3422 } 3423 } else { 3424 std::string testFuncProto; 3425 std::string s = GenTest(name, Proto, TypeVec[ti], TypeVec[ti], isShift, 3426 isHiddenLOp, ck, InstName, isA64, testFuncProto); 3427 if (EmittedMap.count(testFuncProto)) 3428 continue; 3429 EmittedMap[testFuncProto] = kind; 3430 OS << s << "\n"; 3431 } 3432 } 3433 } 3434 3435 if (isA64GenTest) 3436 OS << "#endif\n"; 3437 } 3438 /// runTests - Write out a complete set of tests for all of the Neon 3439 /// intrinsics. 3440 void NeonEmitter::runTests(raw_ostream &OS) { 3441 OS << "// RUN: %clang_cc1 -triple thumbv7s-apple-darwin -target-abi " 3442 "apcs-gnu\\\n" 3443 "// RUN: -target-cpu swift -ffreestanding -Os -S -o - %s\\\n" 3444 "// RUN: | FileCheck %s -check-prefix=CHECK_ARM\n" 3445 "\n" 3446 "// RUN: %clang_cc1 -triple aarch64-none-linux-gnu \\\n" 3447 "// RUN -target-feature +neon -ffreestanding -S -o - %s \\\n" 3448 "// RUN: | FileCheck %s -check-prefix=CHECK_AARCH64\n" 3449 "\n" 3450 "// REQUIRES: long_tests\n" 3451 "\n" 3452 "#include <arm_neon.h>\n" 3453 "\n"; 3454 3455 // ARM tests must be emitted before AArch64 tests to ensure 3456 // tests for intrinsics that are common to ARM and AArch64 3457 // appear only once in the output stream. 3458 // The check for uniqueness is done in genTargetTest. 3459 StringMap<OpKind> EmittedMap; 3460 3461 genTargetTest(OS, EmittedMap, false); 3462 3463 genTargetTest(OS, EmittedMap, true); 3464 } 3465 3466 namespace clang { 3467 void EmitNeon(RecordKeeper &Records, raw_ostream &OS) { 3468 NeonEmitter(Records).run(OS); 3469 } 3470 void EmitNeonSema(RecordKeeper &Records, raw_ostream &OS) { 3471 NeonEmitter(Records).runHeader(OS); 3472 } 3473 void EmitNeonTest(RecordKeeper &Records, raw_ostream &OS) { 3474 NeonEmitter(Records).runTests(OS); 3475 } 3476 } // End namespace clang 3477