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