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 "NeonEmitter.h" 27 #include "llvm/TableGen/Error.h" 28 #include "llvm/ADT/SmallString.h" 29 #include "llvm/ADT/SmallVector.h" 30 #include "llvm/ADT/StringExtras.h" 31 #include <string> 32 33 using namespace llvm; 34 35 /// ParseTypes - break down a string such as "fQf" into a vector of StringRefs, 36 /// which each StringRef representing a single type declared in the string. 37 /// for "fQf" we would end up with 2 StringRefs, "f", and "Qf", representing 38 /// 2xfloat and 4xfloat respectively. 39 static void ParseTypes(Record *r, std::string &s, 40 SmallVectorImpl<StringRef> &TV) { 41 const char *data = s.data(); 42 int len = 0; 43 44 for (unsigned i = 0, e = s.size(); i != e; ++i, ++len) { 45 if (data[len] == 'P' || data[len] == 'Q' || data[len] == 'U') 46 continue; 47 48 switch (data[len]) { 49 case 'c': 50 case 's': 51 case 'i': 52 case 'l': 53 case 'h': 54 case 'f': 55 break; 56 default: 57 throw TGError(r->getLoc(), 58 "Unexpected letter: " + std::string(data + len, 1)); 59 break; 60 } 61 TV.push_back(StringRef(data, len + 1)); 62 data += len + 1; 63 len = -1; 64 } 65 } 66 67 /// Widen - Convert a type code into the next wider type. char -> short, 68 /// short -> int, etc. 69 static char Widen(const char t) { 70 switch (t) { 71 case 'c': 72 return 's'; 73 case 's': 74 return 'i'; 75 case 'i': 76 return 'l'; 77 case 'h': 78 return 'f'; 79 default: throw "unhandled type in widen!"; 80 } 81 return '\0'; 82 } 83 84 /// Narrow - Convert a type code into the next smaller type. short -> char, 85 /// float -> half float, etc. 86 static char Narrow(const char t) { 87 switch (t) { 88 case 's': 89 return 'c'; 90 case 'i': 91 return 's'; 92 case 'l': 93 return 'i'; 94 case 'f': 95 return 'h'; 96 default: throw "unhandled type in narrow!"; 97 } 98 return '\0'; 99 } 100 101 /// For a particular StringRef, return the base type code, and whether it has 102 /// the quad-vector, polynomial, or unsigned modifiers set. 103 static char ClassifyType(StringRef ty, bool &quad, bool &poly, bool &usgn) { 104 unsigned off = 0; 105 106 // remember quad. 107 if (ty[off] == 'Q') { 108 quad = true; 109 ++off; 110 } 111 112 // remember poly. 113 if (ty[off] == 'P') { 114 poly = true; 115 ++off; 116 } 117 118 // remember unsigned. 119 if (ty[off] == 'U') { 120 usgn = true; 121 ++off; 122 } 123 124 // base type to get the type string for. 125 return ty[off]; 126 } 127 128 /// ModType - Transform a type code and its modifiers based on a mod code. The 129 /// mod code definitions may be found at the top of arm_neon.td. 130 static char ModType(const char mod, char type, bool &quad, bool &poly, 131 bool &usgn, bool &scal, bool &cnst, bool &pntr) { 132 switch (mod) { 133 case 't': 134 if (poly) { 135 poly = false; 136 usgn = true; 137 } 138 break; 139 case 'u': 140 usgn = true; 141 poly = false; 142 if (type == 'f') 143 type = 'i'; 144 break; 145 case 'x': 146 usgn = false; 147 poly = false; 148 if (type == 'f') 149 type = 'i'; 150 break; 151 case 'f': 152 if (type == 'h') 153 quad = true; 154 type = 'f'; 155 usgn = false; 156 break; 157 case 'g': 158 quad = false; 159 break; 160 case 'w': 161 type = Widen(type); 162 quad = true; 163 break; 164 case 'n': 165 type = Widen(type); 166 break; 167 case 'i': 168 type = 'i'; 169 scal = true; 170 break; 171 case 'l': 172 type = 'l'; 173 scal = true; 174 usgn = true; 175 break; 176 case 's': 177 case 'a': 178 scal = true; 179 break; 180 case 'k': 181 quad = true; 182 break; 183 case 'c': 184 cnst = true; 185 case 'p': 186 pntr = true; 187 scal = true; 188 break; 189 case 'h': 190 type = Narrow(type); 191 if (type == 'h') 192 quad = false; 193 break; 194 case 'e': 195 type = Narrow(type); 196 usgn = true; 197 break; 198 default: 199 break; 200 } 201 return type; 202 } 203 204 /// TypeString - for a modifier and type, generate the name of the typedef for 205 /// that type. QUc -> uint8x8_t. 206 static std::string TypeString(const char mod, StringRef typestr) { 207 bool quad = false; 208 bool poly = false; 209 bool usgn = false; 210 bool scal = false; 211 bool cnst = false; 212 bool pntr = false; 213 214 if (mod == 'v') 215 return "void"; 216 if (mod == 'i') 217 return "int"; 218 219 // base type to get the type string for. 220 char type = ClassifyType(typestr, quad, poly, usgn); 221 222 // Based on the modifying character, change the type and width if necessary. 223 type = ModType(mod, type, quad, poly, usgn, scal, cnst, pntr); 224 225 SmallString<128> s; 226 227 if (usgn) 228 s.push_back('u'); 229 230 switch (type) { 231 case 'c': 232 s += poly ? "poly8" : "int8"; 233 if (scal) 234 break; 235 s += quad ? "x16" : "x8"; 236 break; 237 case 's': 238 s += poly ? "poly16" : "int16"; 239 if (scal) 240 break; 241 s += quad ? "x8" : "x4"; 242 break; 243 case 'i': 244 s += "int32"; 245 if (scal) 246 break; 247 s += quad ? "x4" : "x2"; 248 break; 249 case 'l': 250 s += "int64"; 251 if (scal) 252 break; 253 s += quad ? "x2" : "x1"; 254 break; 255 case 'h': 256 s += "float16"; 257 if (scal) 258 break; 259 s += quad ? "x8" : "x4"; 260 break; 261 case 'f': 262 s += "float32"; 263 if (scal) 264 break; 265 s += quad ? "x4" : "x2"; 266 break; 267 default: 268 throw "unhandled type!"; 269 break; 270 } 271 272 if (mod == '2') 273 s += "x2"; 274 if (mod == '3') 275 s += "x3"; 276 if (mod == '4') 277 s += "x4"; 278 279 // Append _t, finishing the type string typedef type. 280 s += "_t"; 281 282 if (cnst) 283 s += " const"; 284 285 if (pntr) 286 s += " *"; 287 288 return s.str(); 289 } 290 291 /// BuiltinTypeString - for a modifier and type, generate the clang 292 /// BuiltinsARM.def prototype code for the function. See the top of clang's 293 /// Builtins.def for a description of the type strings. 294 static std::string BuiltinTypeString(const char mod, StringRef typestr, 295 ClassKind ck, bool ret) { 296 bool quad = false; 297 bool poly = false; 298 bool usgn = false; 299 bool scal = false; 300 bool cnst = false; 301 bool pntr = false; 302 303 if (mod == 'v') 304 return "v"; // void 305 if (mod == 'i') 306 return "i"; // int 307 308 // base type to get the type string for. 309 char type = ClassifyType(typestr, quad, poly, usgn); 310 311 // Based on the modifying character, change the type and width if necessary. 312 type = ModType(mod, type, quad, poly, usgn, scal, cnst, pntr); 313 314 // All pointers are void* pointers. Change type to 'v' now. 315 if (pntr) { 316 usgn = false; 317 poly = false; 318 type = 'v'; 319 } 320 // Treat half-float ('h') types as unsigned short ('s') types. 321 if (type == 'h') { 322 type = 's'; 323 usgn = true; 324 } 325 usgn = usgn | poly | ((ck == ClassI || ck == ClassW) && scal && type != 'f'); 326 327 if (scal) { 328 SmallString<128> s; 329 330 if (usgn) 331 s.push_back('U'); 332 else if (type == 'c') 333 s.push_back('S'); // make chars explicitly signed 334 335 if (type == 'l') // 64-bit long 336 s += "LLi"; 337 else 338 s.push_back(type); 339 340 if (cnst) 341 s.push_back('C'); 342 if (pntr) 343 s.push_back('*'); 344 return s.str(); 345 } 346 347 // Since the return value must be one type, return a vector type of the 348 // appropriate width which we will bitcast. An exception is made for 349 // returning structs of 2, 3, or 4 vectors which are returned in a sret-like 350 // fashion, storing them to a pointer arg. 351 if (ret) { 352 if (mod >= '2' && mod <= '4') 353 return "vv*"; // void result with void* first argument 354 if (mod == 'f' || (ck != ClassB && type == 'f')) 355 return quad ? "V4f" : "V2f"; 356 if (ck != ClassB && type == 's') 357 return quad ? "V8s" : "V4s"; 358 if (ck != ClassB && type == 'i') 359 return quad ? "V4i" : "V2i"; 360 if (ck != ClassB && type == 'l') 361 return quad ? "V2LLi" : "V1LLi"; 362 363 return quad ? "V16Sc" : "V8Sc"; 364 } 365 366 // Non-return array types are passed as individual vectors. 367 if (mod == '2') 368 return quad ? "V16ScV16Sc" : "V8ScV8Sc"; 369 if (mod == '3') 370 return quad ? "V16ScV16ScV16Sc" : "V8ScV8ScV8Sc"; 371 if (mod == '4') 372 return quad ? "V16ScV16ScV16ScV16Sc" : "V8ScV8ScV8ScV8Sc"; 373 374 if (mod == 'f' || (ck != ClassB && type == 'f')) 375 return quad ? "V4f" : "V2f"; 376 if (ck != ClassB && type == 's') 377 return quad ? "V8s" : "V4s"; 378 if (ck != ClassB && type == 'i') 379 return quad ? "V4i" : "V2i"; 380 if (ck != ClassB && type == 'l') 381 return quad ? "V2LLi" : "V1LLi"; 382 383 return quad ? "V16Sc" : "V8Sc"; 384 } 385 386 /// MangleName - Append a type or width suffix to a base neon function name, 387 /// and insert a 'q' in the appropriate location if the operation works on 388 /// 128b rather than 64b. E.g. turn "vst2_lane" into "vst2q_lane_f32", etc. 389 static std::string MangleName(const std::string &name, StringRef typestr, 390 ClassKind ck) { 391 if (name == "vcvt_f32_f16") 392 return name; 393 394 bool quad = false; 395 bool poly = false; 396 bool usgn = false; 397 char type = ClassifyType(typestr, quad, poly, usgn); 398 399 std::string s = name; 400 401 switch (type) { 402 case 'c': 403 switch (ck) { 404 case ClassS: s += poly ? "_p8" : usgn ? "_u8" : "_s8"; break; 405 case ClassI: s += "_i8"; break; 406 case ClassW: s += "_8"; break; 407 default: break; 408 } 409 break; 410 case 's': 411 switch (ck) { 412 case ClassS: s += poly ? "_p16" : usgn ? "_u16" : "_s16"; break; 413 case ClassI: s += "_i16"; break; 414 case ClassW: s += "_16"; break; 415 default: break; 416 } 417 break; 418 case 'i': 419 switch (ck) { 420 case ClassS: s += usgn ? "_u32" : "_s32"; break; 421 case ClassI: s += "_i32"; break; 422 case ClassW: s += "_32"; break; 423 default: break; 424 } 425 break; 426 case 'l': 427 switch (ck) { 428 case ClassS: s += usgn ? "_u64" : "_s64"; break; 429 case ClassI: s += "_i64"; break; 430 case ClassW: s += "_64"; break; 431 default: break; 432 } 433 break; 434 case 'h': 435 switch (ck) { 436 case ClassS: 437 case ClassI: s += "_f16"; break; 438 case ClassW: s += "_16"; break; 439 default: break; 440 } 441 break; 442 case 'f': 443 switch (ck) { 444 case ClassS: 445 case ClassI: s += "_f32"; break; 446 case ClassW: s += "_32"; break; 447 default: break; 448 } 449 break; 450 default: 451 throw "unhandled type!"; 452 break; 453 } 454 if (ck == ClassB) 455 s += "_v"; 456 457 // Insert a 'q' before the first '_' character so that it ends up before 458 // _lane or _n on vector-scalar operations. 459 if (quad) { 460 size_t pos = s.find('_'); 461 s = s.insert(pos, "q"); 462 } 463 return s; 464 } 465 466 /// UseMacro - Examine the prototype string to determine if the intrinsic 467 /// should be defined as a preprocessor macro instead of an inline function. 468 static bool UseMacro(const std::string &proto) { 469 // If this builtin takes an immediate argument, we need to #define it rather 470 // than use a standard declaration, so that SemaChecking can range check 471 // the immediate passed by the user. 472 if (proto.find('i') != std::string::npos) 473 return true; 474 475 // Pointer arguments need to use macros to avoid hiding aligned attributes 476 // from the pointer type. 477 if (proto.find('p') != std::string::npos || 478 proto.find('c') != std::string::npos) 479 return true; 480 481 return false; 482 } 483 484 /// MacroArgUsedDirectly - Return true if argument i for an intrinsic that is 485 /// defined as a macro should be accessed directly instead of being first 486 /// assigned to a local temporary. 487 static bool MacroArgUsedDirectly(const std::string &proto, unsigned i) { 488 // True for constant ints (i), pointers (p) and const pointers (c). 489 return (proto[i] == 'i' || proto[i] == 'p' || proto[i] == 'c'); 490 } 491 492 // Generate the string "(argtype a, argtype b, ...)" 493 static std::string GenArgs(const std::string &proto, StringRef typestr) { 494 bool define = UseMacro(proto); 495 char arg = 'a'; 496 497 std::string s; 498 s += "("; 499 500 for (unsigned i = 1, e = proto.size(); i != e; ++i, ++arg) { 501 if (define) { 502 // Some macro arguments are used directly instead of being assigned 503 // to local temporaries; prepend an underscore prefix to make their 504 // names consistent with the local temporaries. 505 if (MacroArgUsedDirectly(proto, i)) 506 s += "__"; 507 } else { 508 s += TypeString(proto[i], typestr) + " __"; 509 } 510 s.push_back(arg); 511 if ((i + 1) < e) 512 s += ", "; 513 } 514 515 s += ")"; 516 return s; 517 } 518 519 // Macro arguments are not type-checked like inline function arguments, so 520 // assign them to local temporaries to get the right type checking. 521 static std::string GenMacroLocals(const std::string &proto, StringRef typestr) { 522 char arg = 'a'; 523 std::string s; 524 bool generatedLocal = false; 525 526 for (unsigned i = 1, e = proto.size(); i != e; ++i, ++arg) { 527 // Do not create a temporary for an immediate argument. 528 // That would defeat the whole point of using a macro! 529 // FIXME: For other (non-immediate) arguments that are used directly, a 530 // local temporary (or some other method) is still needed to get the 531 // correct type checking, even if that temporary is not used for anything. 532 // This is omitted for now because it turns out the the use of 533 // "__extension__" in the macro disables any warnings from the pointer 534 // assignment. 535 if (MacroArgUsedDirectly(proto, i)) 536 continue; 537 generatedLocal = true; 538 539 s += TypeString(proto[i], typestr) + " __"; 540 s.push_back(arg); 541 s += " = ("; 542 s.push_back(arg); 543 s += "); "; 544 } 545 546 if (generatedLocal) 547 s += "\\\n "; 548 return s; 549 } 550 551 // Use the vmovl builtin to sign-extend or zero-extend a vector. 552 static std::string Extend(StringRef typestr, const std::string &a) { 553 std::string s; 554 s = MangleName("vmovl", typestr, ClassS); 555 s += "(" + a + ")"; 556 return s; 557 } 558 559 static std::string Duplicate(unsigned nElts, StringRef typestr, 560 const std::string &a) { 561 std::string s; 562 563 s = "(" + TypeString('d', typestr) + "){ "; 564 for (unsigned i = 0; i != nElts; ++i) { 565 s += a; 566 if ((i + 1) < nElts) 567 s += ", "; 568 } 569 s += " }"; 570 571 return s; 572 } 573 574 static std::string SplatLane(unsigned nElts, const std::string &vec, 575 const std::string &lane) { 576 std::string s = "__builtin_shufflevector(" + vec + ", " + vec; 577 for (unsigned i = 0; i < nElts; ++i) 578 s += ", " + lane; 579 s += ")"; 580 return s; 581 } 582 583 static unsigned GetNumElements(StringRef typestr, bool &quad) { 584 quad = false; 585 bool dummy = false; 586 char type = ClassifyType(typestr, quad, dummy, dummy); 587 unsigned nElts = 0; 588 switch (type) { 589 case 'c': nElts = 8; break; 590 case 's': nElts = 4; break; 591 case 'i': nElts = 2; break; 592 case 'l': nElts = 1; break; 593 case 'h': nElts = 4; break; 594 case 'f': nElts = 2; break; 595 default: 596 throw "unhandled type!"; 597 break; 598 } 599 if (quad) nElts <<= 1; 600 return nElts; 601 } 602 603 // Generate the definition for this intrinsic, e.g. "a + b" for OpAdd. 604 static std::string GenOpString(OpKind op, const std::string &proto, 605 StringRef typestr) { 606 bool quad; 607 unsigned nElts = GetNumElements(typestr, quad); 608 bool define = UseMacro(proto); 609 610 std::string ts = TypeString(proto[0], typestr); 611 std::string s; 612 if (!define) { 613 s = "return "; 614 } 615 616 switch(op) { 617 case OpAdd: 618 s += "__a + __b;"; 619 break; 620 case OpAddl: 621 s += Extend(typestr, "__a") + " + " + Extend(typestr, "__b") + ";"; 622 break; 623 case OpAddw: 624 s += "__a + " + Extend(typestr, "__b") + ";"; 625 break; 626 case OpSub: 627 s += "__a - __b;"; 628 break; 629 case OpSubl: 630 s += Extend(typestr, "__a") + " - " + Extend(typestr, "__b") + ";"; 631 break; 632 case OpSubw: 633 s += "__a - " + Extend(typestr, "__b") + ";"; 634 break; 635 case OpMulN: 636 s += "__a * " + Duplicate(nElts, typestr, "__b") + ";"; 637 break; 638 case OpMulLane: 639 s += "__a * " + SplatLane(nElts, "__b", "__c") + ";"; 640 break; 641 case OpMul: 642 s += "__a * __b;"; 643 break; 644 case OpMullLane: 645 s += MangleName("vmull", typestr, ClassS) + "(__a, " + 646 SplatLane(nElts, "__b", "__c") + ");"; 647 break; 648 case OpMlaN: 649 s += "__a + (__b * " + Duplicate(nElts, typestr, "__c") + ");"; 650 break; 651 case OpMlaLane: 652 s += "__a + (__b * " + SplatLane(nElts, "__c", "__d") + ");"; 653 break; 654 case OpMla: 655 s += "__a + (__b * __c);"; 656 break; 657 case OpMlalN: 658 s += "__a + " + MangleName("vmull", typestr, ClassS) + "(__b, " + 659 Duplicate(nElts, typestr, "__c") + ");"; 660 break; 661 case OpMlalLane: 662 s += "__a + " + MangleName("vmull", typestr, ClassS) + "(__b, " + 663 SplatLane(nElts, "__c", "__d") + ");"; 664 break; 665 case OpMlal: 666 s += "__a + " + MangleName("vmull", typestr, ClassS) + "(__b, __c);"; 667 break; 668 case OpMlsN: 669 s += "__a - (__b * " + Duplicate(nElts, typestr, "__c") + ");"; 670 break; 671 case OpMlsLane: 672 s += "__a - (__b * " + SplatLane(nElts, "__c", "__d") + ");"; 673 break; 674 case OpMls: 675 s += "__a - (__b * __c);"; 676 break; 677 case OpMlslN: 678 s += "__a - " + MangleName("vmull", typestr, ClassS) + "(__b, " + 679 Duplicate(nElts, typestr, "__c") + ");"; 680 break; 681 case OpMlslLane: 682 s += "__a - " + MangleName("vmull", typestr, ClassS) + "(__b, " + 683 SplatLane(nElts, "__c", "__d") + ");"; 684 break; 685 case OpMlsl: 686 s += "__a - " + MangleName("vmull", typestr, ClassS) + "(__b, __c);"; 687 break; 688 case OpQDMullLane: 689 s += MangleName("vqdmull", typestr, ClassS) + "(__a, " + 690 SplatLane(nElts, "__b", "__c") + ");"; 691 break; 692 case OpQDMlalLane: 693 s += MangleName("vqdmlal", typestr, ClassS) + "(__a, __b, " + 694 SplatLane(nElts, "__c", "__d") + ");"; 695 break; 696 case OpQDMlslLane: 697 s += MangleName("vqdmlsl", typestr, ClassS) + "(__a, __b, " + 698 SplatLane(nElts, "__c", "__d") + ");"; 699 break; 700 case OpQDMulhLane: 701 s += MangleName("vqdmulh", typestr, ClassS) + "(__a, " + 702 SplatLane(nElts, "__b", "__c") + ");"; 703 break; 704 case OpQRDMulhLane: 705 s += MangleName("vqrdmulh", typestr, ClassS) + "(__a, " + 706 SplatLane(nElts, "__b", "__c") + ");"; 707 break; 708 case OpEq: 709 s += "(" + ts + ")(__a == __b);"; 710 break; 711 case OpGe: 712 s += "(" + ts + ")(__a >= __b);"; 713 break; 714 case OpLe: 715 s += "(" + ts + ")(__a <= __b);"; 716 break; 717 case OpGt: 718 s += "(" + ts + ")(__a > __b);"; 719 break; 720 case OpLt: 721 s += "(" + ts + ")(__a < __b);"; 722 break; 723 case OpNeg: 724 s += " -__a;"; 725 break; 726 case OpNot: 727 s += " ~__a;"; 728 break; 729 case OpAnd: 730 s += "__a & __b;"; 731 break; 732 case OpOr: 733 s += "__a | __b;"; 734 break; 735 case OpXor: 736 s += "__a ^ __b;"; 737 break; 738 case OpAndNot: 739 s += "__a & ~__b;"; 740 break; 741 case OpOrNot: 742 s += "__a | ~__b;"; 743 break; 744 case OpCast: 745 s += "(" + ts + ")__a;"; 746 break; 747 case OpConcat: 748 s += "(" + ts + ")__builtin_shufflevector((int64x1_t)__a"; 749 s += ", (int64x1_t)__b, 0, 1);"; 750 break; 751 case OpHi: 752 s += "(" + ts + 753 ")__builtin_shufflevector((int64x2_t)__a, (int64x2_t)__a, 1);"; 754 break; 755 case OpLo: 756 s += "(" + ts + 757 ")__builtin_shufflevector((int64x2_t)__a, (int64x2_t)__a, 0);"; 758 break; 759 case OpDup: 760 s += Duplicate(nElts, typestr, "__a") + ";"; 761 break; 762 case OpDupLane: 763 s += SplatLane(nElts, "__a", "__b") + ";"; 764 break; 765 case OpSelect: 766 // ((0 & 1) | (~0 & 2)) 767 s += "(" + ts + ")"; 768 ts = TypeString(proto[1], typestr); 769 s += "((__a & (" + ts + ")__b) | "; 770 s += "(~__a & (" + ts + ")__c));"; 771 break; 772 case OpRev16: 773 s += "__builtin_shufflevector(__a, __a"; 774 for (unsigned i = 2; i <= nElts; i += 2) 775 for (unsigned j = 0; j != 2; ++j) 776 s += ", " + utostr(i - j - 1); 777 s += ");"; 778 break; 779 case OpRev32: { 780 unsigned WordElts = nElts >> (1 + (int)quad); 781 s += "__builtin_shufflevector(__a, __a"; 782 for (unsigned i = WordElts; i <= nElts; i += WordElts) 783 for (unsigned j = 0; j != WordElts; ++j) 784 s += ", " + utostr(i - j - 1); 785 s += ");"; 786 break; 787 } 788 case OpRev64: { 789 unsigned DblWordElts = nElts >> (int)quad; 790 s += "__builtin_shufflevector(__a, __a"; 791 for (unsigned i = DblWordElts; i <= nElts; i += DblWordElts) 792 for (unsigned j = 0; j != DblWordElts; ++j) 793 s += ", " + utostr(i - j - 1); 794 s += ");"; 795 break; 796 } 797 case OpAbdl: { 798 std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; 799 if (typestr[0] != 'U') { 800 // vabd results are always unsigned and must be zero-extended. 801 std::string utype = "U" + typestr.str(); 802 s += "(" + TypeString(proto[0], typestr) + ")"; 803 abd = "(" + TypeString('d', utype) + ")" + abd; 804 s += Extend(utype, abd) + ";"; 805 } else { 806 s += Extend(typestr, abd) + ";"; 807 } 808 break; 809 } 810 case OpAba: 811 s += "__a + " + MangleName("vabd", typestr, ClassS) + "(__b, __c);"; 812 break; 813 case OpAbal: { 814 s += "__a + "; 815 std::string abd = MangleName("vabd", typestr, ClassS) + "(__b, __c)"; 816 if (typestr[0] != 'U') { 817 // vabd results are always unsigned and must be zero-extended. 818 std::string utype = "U" + typestr.str(); 819 s += "(" + TypeString(proto[0], typestr) + ")"; 820 abd = "(" + TypeString('d', utype) + ")" + abd; 821 s += Extend(utype, abd) + ";"; 822 } else { 823 s += Extend(typestr, abd) + ";"; 824 } 825 break; 826 } 827 default: 828 throw "unknown OpKind!"; 829 break; 830 } 831 return s; 832 } 833 834 static unsigned GetNeonEnum(const std::string &proto, StringRef typestr) { 835 unsigned mod = proto[0]; 836 unsigned ret = 0; 837 838 if (mod == 'v' || mod == 'f') 839 mod = proto[1]; 840 841 bool quad = false; 842 bool poly = false; 843 bool usgn = false; 844 bool scal = false; 845 bool cnst = false; 846 bool pntr = false; 847 848 // Base type to get the type string for. 849 char type = ClassifyType(typestr, quad, poly, usgn); 850 851 // Based on the modifying character, change the type and width if necessary. 852 type = ModType(mod, type, quad, poly, usgn, scal, cnst, pntr); 853 854 if (usgn) 855 ret |= 0x08; 856 if (quad && proto[1] != 'g') 857 ret |= 0x10; 858 859 switch (type) { 860 case 'c': 861 ret |= poly ? 5 : 0; 862 break; 863 case 's': 864 ret |= poly ? 6 : 1; 865 break; 866 case 'i': 867 ret |= 2; 868 break; 869 case 'l': 870 ret |= 3; 871 break; 872 case 'h': 873 ret |= 7; 874 break; 875 case 'f': 876 ret |= 4; 877 break; 878 default: 879 throw "unhandled type!"; 880 break; 881 } 882 return ret; 883 } 884 885 // Generate the definition for this intrinsic, e.g. __builtin_neon_cls(a) 886 static std::string GenBuiltin(const std::string &name, const std::string &proto, 887 StringRef typestr, ClassKind ck) { 888 std::string s; 889 890 // If this builtin returns a struct 2, 3, or 4 vectors, pass it as an implicit 891 // sret-like argument. 892 bool sret = (proto[0] >= '2' && proto[0] <= '4'); 893 894 bool define = UseMacro(proto); 895 896 // Check if the prototype has a scalar operand with the type of the vector 897 // elements. If not, bitcasting the args will take care of arg checking. 898 // The actual signedness etc. will be taken care of with special enums. 899 if (proto.find('s') == std::string::npos) 900 ck = ClassB; 901 902 if (proto[0] != 'v') { 903 std::string ts = TypeString(proto[0], typestr); 904 905 if (define) { 906 if (sret) 907 s += ts + " r; "; 908 else 909 s += "(" + ts + ")"; 910 } else if (sret) { 911 s += ts + " r; "; 912 } else { 913 s += "return (" + ts + ")"; 914 } 915 } 916 917 bool splat = proto.find('a') != std::string::npos; 918 919 s += "__builtin_neon_"; 920 if (splat) { 921 // Call the non-splat builtin: chop off the "_n" suffix from the name. 922 std::string vname(name, 0, name.size()-2); 923 s += MangleName(vname, typestr, ck); 924 } else { 925 s += MangleName(name, typestr, ck); 926 } 927 s += "("; 928 929 // Pass the address of the return variable as the first argument to sret-like 930 // builtins. 931 if (sret) 932 s += "&r, "; 933 934 char arg = 'a'; 935 for (unsigned i = 1, e = proto.size(); i != e; ++i, ++arg) { 936 std::string args = std::string(&arg, 1); 937 938 // Use the local temporaries instead of the macro arguments. 939 args = "__" + args; 940 941 bool argQuad = false; 942 bool argPoly = false; 943 bool argUsgn = false; 944 bool argScalar = false; 945 bool dummy = false; 946 char argType = ClassifyType(typestr, argQuad, argPoly, argUsgn); 947 argType = ModType(proto[i], argType, argQuad, argPoly, argUsgn, argScalar, 948 dummy, dummy); 949 950 // Handle multiple-vector values specially, emitting each subvector as an 951 // argument to the __builtin. 952 if (proto[i] >= '2' && proto[i] <= '4') { 953 // Check if an explicit cast is needed. 954 if (argType != 'c' || argPoly || argUsgn) 955 args = (argQuad ? "(int8x16_t)" : "(int8x8_t)") + args; 956 957 for (unsigned vi = 0, ve = proto[i] - '0'; vi != ve; ++vi) { 958 s += args + ".val[" + utostr(vi) + "]"; 959 if ((vi + 1) < ve) 960 s += ", "; 961 } 962 if ((i + 1) < e) 963 s += ", "; 964 965 continue; 966 } 967 968 if (splat && (i + 1) == e) 969 args = Duplicate(GetNumElements(typestr, argQuad), typestr, args); 970 971 // Check if an explicit cast is needed. 972 if ((splat || !argScalar) && 973 ((ck == ClassB && argType != 'c') || argPoly || argUsgn)) { 974 std::string argTypeStr = "c"; 975 if (ck != ClassB) 976 argTypeStr = argType; 977 if (argQuad) 978 argTypeStr = "Q" + argTypeStr; 979 args = "(" + TypeString('d', argTypeStr) + ")" + args; 980 } 981 982 s += args; 983 if ((i + 1) < e) 984 s += ", "; 985 } 986 987 // Extra constant integer to hold type class enum for this function, e.g. s8 988 if (ck == ClassB) 989 s += ", " + utostr(GetNeonEnum(proto, typestr)); 990 991 s += ");"; 992 993 if (proto[0] != 'v' && sret) { 994 if (define) 995 s += " r;"; 996 else 997 s += " return r;"; 998 } 999 return s; 1000 } 1001 1002 static std::string GenBuiltinDef(const std::string &name, 1003 const std::string &proto, 1004 StringRef typestr, ClassKind ck) { 1005 std::string s("BUILTIN(__builtin_neon_"); 1006 1007 // If all types are the same size, bitcasting the args will take care 1008 // of arg checking. The actual signedness etc. will be taken care of with 1009 // special enums. 1010 if (proto.find('s') == std::string::npos) 1011 ck = ClassB; 1012 1013 s += MangleName(name, typestr, ck); 1014 s += ", \""; 1015 1016 for (unsigned i = 0, e = proto.size(); i != e; ++i) 1017 s += BuiltinTypeString(proto[i], typestr, ck, i == 0); 1018 1019 // Extra constant integer to hold type class enum for this function, e.g. s8 1020 if (ck == ClassB) 1021 s += "i"; 1022 1023 s += "\", \"n\")"; 1024 return s; 1025 } 1026 1027 static std::string GenIntrinsic(const std::string &name, 1028 const std::string &proto, 1029 StringRef outTypeStr, StringRef inTypeStr, 1030 OpKind kind, ClassKind classKind) { 1031 assert(!proto.empty() && ""); 1032 bool define = UseMacro(proto); 1033 std::string s; 1034 1035 // static always inline + return type 1036 if (define) 1037 s += "#define "; 1038 else 1039 s += "__ai " + TypeString(proto[0], outTypeStr) + " "; 1040 1041 // Function name with type suffix 1042 std::string mangledName = MangleName(name, outTypeStr, ClassS); 1043 if (outTypeStr != inTypeStr) { 1044 // If the input type is different (e.g., for vreinterpret), append a suffix 1045 // for the input type. String off a "Q" (quad) prefix so that MangleName 1046 // does not insert another "q" in the name. 1047 unsigned typeStrOff = (inTypeStr[0] == 'Q' ? 1 : 0); 1048 StringRef inTypeNoQuad = inTypeStr.substr(typeStrOff); 1049 mangledName = MangleName(mangledName, inTypeNoQuad, ClassS); 1050 } 1051 s += mangledName; 1052 1053 // Function arguments 1054 s += GenArgs(proto, inTypeStr); 1055 1056 // Definition. 1057 if (define) { 1058 s += " __extension__ ({ \\\n "; 1059 s += GenMacroLocals(proto, inTypeStr); 1060 } else { 1061 s += " { \\\n "; 1062 } 1063 1064 if (kind != OpNone) 1065 s += GenOpString(kind, proto, outTypeStr); 1066 else 1067 s += GenBuiltin(name, proto, outTypeStr, classKind); 1068 if (define) 1069 s += " })"; 1070 else 1071 s += " }"; 1072 s += "\n"; 1073 return s; 1074 } 1075 1076 /// run - Read the records in arm_neon.td and output arm_neon.h. arm_neon.h 1077 /// is comprised of type definitions and function declarations. 1078 void NeonEmitter::run(raw_ostream &OS) { 1079 OS << 1080 "/*===---- arm_neon.h - ARM Neon intrinsics ------------------------------" 1081 "---===\n" 1082 " *\n" 1083 " * Permission is hereby granted, free of charge, to any person obtaining " 1084 "a copy\n" 1085 " * of this software and associated documentation files (the \"Software\")," 1086 " to deal\n" 1087 " * in the Software without restriction, including without limitation the " 1088 "rights\n" 1089 " * to use, copy, modify, merge, publish, distribute, sublicense, " 1090 "and/or sell\n" 1091 " * copies of the Software, and to permit persons to whom the Software is\n" 1092 " * furnished to do so, subject to the following conditions:\n" 1093 " *\n" 1094 " * The above copyright notice and this permission notice shall be " 1095 "included in\n" 1096 " * all copies or substantial portions of the Software.\n" 1097 " *\n" 1098 " * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, " 1099 "EXPRESS OR\n" 1100 " * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF " 1101 "MERCHANTABILITY,\n" 1102 " * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT " 1103 "SHALL THE\n" 1104 " * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR " 1105 "OTHER\n" 1106 " * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, " 1107 "ARISING FROM,\n" 1108 " * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER " 1109 "DEALINGS IN\n" 1110 " * THE SOFTWARE.\n" 1111 " *\n" 1112 " *===--------------------------------------------------------------------" 1113 "---===\n" 1114 " */\n\n"; 1115 1116 OS << "#ifndef __ARM_NEON_H\n"; 1117 OS << "#define __ARM_NEON_H\n\n"; 1118 1119 OS << "#ifndef __ARM_NEON__\n"; 1120 OS << "#error \"NEON support not enabled\"\n"; 1121 OS << "#endif\n\n"; 1122 1123 OS << "#include <stdint.h>\n\n"; 1124 1125 // Emit NEON-specific scalar typedefs. 1126 OS << "typedef float float32_t;\n"; 1127 OS << "typedef int8_t poly8_t;\n"; 1128 OS << "typedef int16_t poly16_t;\n"; 1129 OS << "typedef uint16_t float16_t;\n"; 1130 1131 // Emit Neon vector typedefs. 1132 std::string TypedefTypes("cQcsQsiQilQlUcQUcUsQUsUiQUiUlQUlhQhfQfPcQPcPsQPs"); 1133 SmallVector<StringRef, 24> TDTypeVec; 1134 ParseTypes(0, TypedefTypes, TDTypeVec); 1135 1136 // Emit vector typedefs. 1137 for (unsigned i = 0, e = TDTypeVec.size(); i != e; ++i) { 1138 bool dummy, quad = false, poly = false; 1139 (void) ClassifyType(TDTypeVec[i], quad, poly, dummy); 1140 if (poly) 1141 OS << "typedef __attribute__((neon_polyvector_type("; 1142 else 1143 OS << "typedef __attribute__((neon_vector_type("; 1144 1145 unsigned nElts = GetNumElements(TDTypeVec[i], quad); 1146 OS << utostr(nElts) << "))) "; 1147 if (nElts < 10) 1148 OS << " "; 1149 1150 OS << TypeString('s', TDTypeVec[i]); 1151 OS << " " << TypeString('d', TDTypeVec[i]) << ";\n"; 1152 } 1153 OS << "\n"; 1154 1155 // Emit struct typedefs. 1156 for (unsigned vi = 2; vi != 5; ++vi) { 1157 for (unsigned i = 0, e = TDTypeVec.size(); i != e; ++i) { 1158 std::string ts = TypeString('d', TDTypeVec[i]); 1159 std::string vs = TypeString('0' + vi, TDTypeVec[i]); 1160 OS << "typedef struct " << vs << " {\n"; 1161 OS << " " << ts << " val"; 1162 OS << "[" << utostr(vi) << "]"; 1163 OS << ";\n} "; 1164 OS << vs << ";\n\n"; 1165 } 1166 } 1167 1168 OS<<"#define __ai static __attribute__((__always_inline__, __nodebug__))\n\n"; 1169 1170 std::vector<Record*> RV = Records.getAllDerivedDefinitions("Inst"); 1171 1172 // Emit vmovl, vmull and vabd intrinsics first so they can be used by other 1173 // intrinsics. (Some of the saturating multiply instructions are also 1174 // used to implement the corresponding "_lane" variants, but tablegen 1175 // sorts the records into alphabetical order so that the "_lane" variants 1176 // come after the intrinsics they use.) 1177 emitIntrinsic(OS, Records.getDef("VMOVL")); 1178 emitIntrinsic(OS, Records.getDef("VMULL")); 1179 emitIntrinsic(OS, Records.getDef("VABD")); 1180 1181 for (unsigned i = 0, e = RV.size(); i != e; ++i) { 1182 Record *R = RV[i]; 1183 if (R->getName() != "VMOVL" && 1184 R->getName() != "VMULL" && 1185 R->getName() != "VABD") 1186 emitIntrinsic(OS, R); 1187 } 1188 1189 OS << "#undef __ai\n\n"; 1190 OS << "#endif /* __ARM_NEON_H */\n"; 1191 } 1192 1193 /// emitIntrinsic - Write out the arm_neon.h header file definitions for the 1194 /// intrinsics specified by record R. 1195 void NeonEmitter::emitIntrinsic(raw_ostream &OS, Record *R) { 1196 std::string name = R->getValueAsString("Name"); 1197 std::string Proto = R->getValueAsString("Prototype"); 1198 std::string Types = R->getValueAsString("Types"); 1199 1200 SmallVector<StringRef, 16> TypeVec; 1201 ParseTypes(R, Types, TypeVec); 1202 1203 OpKind kind = OpMap[R->getValueAsDef("Operand")->getName()]; 1204 1205 ClassKind classKind = ClassNone; 1206 if (R->getSuperClasses().size() >= 2) 1207 classKind = ClassMap[R->getSuperClasses()[1]]; 1208 if (classKind == ClassNone && kind == OpNone) 1209 throw TGError(R->getLoc(), "Builtin has no class kind"); 1210 1211 for (unsigned ti = 0, te = TypeVec.size(); ti != te; ++ti) { 1212 if (kind == OpReinterpret) { 1213 bool outQuad = false; 1214 bool dummy = false; 1215 (void)ClassifyType(TypeVec[ti], outQuad, dummy, dummy); 1216 for (unsigned srcti = 0, srcte = TypeVec.size(); 1217 srcti != srcte; ++srcti) { 1218 bool inQuad = false; 1219 (void)ClassifyType(TypeVec[srcti], inQuad, dummy, dummy); 1220 if (srcti == ti || inQuad != outQuad) 1221 continue; 1222 OS << GenIntrinsic(name, Proto, TypeVec[ti], TypeVec[srcti], 1223 OpCast, ClassS); 1224 } 1225 } else { 1226 OS << GenIntrinsic(name, Proto, TypeVec[ti], TypeVec[ti], 1227 kind, classKind); 1228 } 1229 } 1230 OS << "\n"; 1231 } 1232 1233 static unsigned RangeFromType(const char mod, StringRef typestr) { 1234 // base type to get the type string for. 1235 bool quad = false, dummy = false; 1236 char type = ClassifyType(typestr, quad, dummy, dummy); 1237 type = ModType(mod, type, quad, dummy, dummy, dummy, dummy, dummy); 1238 1239 switch (type) { 1240 case 'c': 1241 return (8 << (int)quad) - 1; 1242 case 'h': 1243 case 's': 1244 return (4 << (int)quad) - 1; 1245 case 'f': 1246 case 'i': 1247 return (2 << (int)quad) - 1; 1248 case 'l': 1249 return (1 << (int)quad) - 1; 1250 default: 1251 throw "unhandled type!"; 1252 break; 1253 } 1254 assert(0 && "unreachable"); 1255 return 0; 1256 } 1257 1258 /// runHeader - Emit a file with sections defining: 1259 /// 1. the NEON section of BuiltinsARM.def. 1260 /// 2. the SemaChecking code for the type overload checking. 1261 /// 3. the SemaChecking code for validation of intrinsic immedate arguments. 1262 void NeonEmitter::runHeader(raw_ostream &OS) { 1263 std::vector<Record*> RV = Records.getAllDerivedDefinitions("Inst"); 1264 1265 StringMap<OpKind> EmittedMap; 1266 1267 // Generate BuiltinsARM.def for NEON 1268 OS << "#ifdef GET_NEON_BUILTINS\n"; 1269 for (unsigned i = 0, e = RV.size(); i != e; ++i) { 1270 Record *R = RV[i]; 1271 OpKind k = OpMap[R->getValueAsDef("Operand")->getName()]; 1272 if (k != OpNone) 1273 continue; 1274 1275 std::string Proto = R->getValueAsString("Prototype"); 1276 1277 // Functions with 'a' (the splat code) in the type prototype should not get 1278 // their own builtin as they use the non-splat variant. 1279 if (Proto.find('a') != std::string::npos) 1280 continue; 1281 1282 std::string Types = R->getValueAsString("Types"); 1283 SmallVector<StringRef, 16> TypeVec; 1284 ParseTypes(R, Types, TypeVec); 1285 1286 if (R->getSuperClasses().size() < 2) 1287 throw TGError(R->getLoc(), "Builtin has no class kind"); 1288 1289 std::string name = R->getValueAsString("Name"); 1290 ClassKind ck = ClassMap[R->getSuperClasses()[1]]; 1291 1292 for (unsigned ti = 0, te = TypeVec.size(); ti != te; ++ti) { 1293 // Generate the BuiltinsARM.def declaration for this builtin, ensuring 1294 // that each unique BUILTIN() macro appears only once in the output 1295 // stream. 1296 std::string bd = GenBuiltinDef(name, Proto, TypeVec[ti], ck); 1297 if (EmittedMap.count(bd)) 1298 continue; 1299 1300 EmittedMap[bd] = OpNone; 1301 OS << bd << "\n"; 1302 } 1303 } 1304 OS << "#endif\n\n"; 1305 1306 // Generate the overloaded type checking code for SemaChecking.cpp 1307 OS << "#ifdef GET_NEON_OVERLOAD_CHECK\n"; 1308 for (unsigned i = 0, e = RV.size(); i != e; ++i) { 1309 Record *R = RV[i]; 1310 OpKind k = OpMap[R->getValueAsDef("Operand")->getName()]; 1311 if (k != OpNone) 1312 continue; 1313 1314 std::string Proto = R->getValueAsString("Prototype"); 1315 std::string Types = R->getValueAsString("Types"); 1316 std::string name = R->getValueAsString("Name"); 1317 1318 // Functions with 'a' (the splat code) in the type prototype should not get 1319 // their own builtin as they use the non-splat variant. 1320 if (Proto.find('a') != std::string::npos) 1321 continue; 1322 1323 // Functions which have a scalar argument cannot be overloaded, no need to 1324 // check them if we are emitting the type checking code. 1325 if (Proto.find('s') != std::string::npos) 1326 continue; 1327 1328 SmallVector<StringRef, 16> TypeVec; 1329 ParseTypes(R, Types, TypeVec); 1330 1331 if (R->getSuperClasses().size() < 2) 1332 throw TGError(R->getLoc(), "Builtin has no class kind"); 1333 1334 int si = -1, qi = -1; 1335 unsigned mask = 0, qmask = 0; 1336 for (unsigned ti = 0, te = TypeVec.size(); ti != te; ++ti) { 1337 // Generate the switch case(s) for this builtin for the type validation. 1338 bool quad = false, poly = false, usgn = false; 1339 (void) ClassifyType(TypeVec[ti], quad, poly, usgn); 1340 1341 if (quad) { 1342 qi = ti; 1343 qmask |= 1 << GetNeonEnum(Proto, TypeVec[ti]); 1344 } else { 1345 si = ti; 1346 mask |= 1 << GetNeonEnum(Proto, TypeVec[ti]); 1347 } 1348 } 1349 if (mask) 1350 OS << "case ARM::BI__builtin_neon_" 1351 << MangleName(name, TypeVec[si], ClassB) 1352 << ": mask = " << "0x" << utohexstr(mask) << "; break;\n"; 1353 if (qmask) 1354 OS << "case ARM::BI__builtin_neon_" 1355 << MangleName(name, TypeVec[qi], ClassB) 1356 << ": mask = " << "0x" << utohexstr(qmask) << "; break;\n"; 1357 } 1358 OS << "#endif\n\n"; 1359 1360 // Generate the intrinsic range checking code for shift/lane immediates. 1361 OS << "#ifdef GET_NEON_IMMEDIATE_CHECK\n"; 1362 for (unsigned i = 0, e = RV.size(); i != e; ++i) { 1363 Record *R = RV[i]; 1364 1365 OpKind k = OpMap[R->getValueAsDef("Operand")->getName()]; 1366 if (k != OpNone) 1367 continue; 1368 1369 std::string name = R->getValueAsString("Name"); 1370 std::string Proto = R->getValueAsString("Prototype"); 1371 std::string Types = R->getValueAsString("Types"); 1372 1373 // Functions with 'a' (the splat code) in the type prototype should not get 1374 // their own builtin as they use the non-splat variant. 1375 if (Proto.find('a') != std::string::npos) 1376 continue; 1377 1378 // Functions which do not have an immediate do not need to have range 1379 // checking code emitted. 1380 size_t immPos = Proto.find('i'); 1381 if (immPos == std::string::npos) 1382 continue; 1383 1384 SmallVector<StringRef, 16> TypeVec; 1385 ParseTypes(R, Types, TypeVec); 1386 1387 if (R->getSuperClasses().size() < 2) 1388 throw TGError(R->getLoc(), "Builtin has no class kind"); 1389 1390 ClassKind ck = ClassMap[R->getSuperClasses()[1]]; 1391 1392 for (unsigned ti = 0, te = TypeVec.size(); ti != te; ++ti) { 1393 std::string namestr, shiftstr, rangestr; 1394 1395 if (R->getValueAsBit("isVCVT_N")) { 1396 // VCVT between floating- and fixed-point values takes an immediate 1397 // in the range 1 to 32. 1398 ck = ClassB; 1399 rangestr = "l = 1; u = 31"; // upper bound = l + u 1400 } else if (Proto.find('s') == std::string::npos) { 1401 // Builtins which are overloaded by type will need to have their upper 1402 // bound computed at Sema time based on the type constant. 1403 ck = ClassB; 1404 if (R->getValueAsBit("isShift")) { 1405 shiftstr = ", true"; 1406 1407 // Right shifts have an 'r' in the name, left shifts do not. 1408 if (name.find('r') != std::string::npos) 1409 rangestr = "l = 1; "; 1410 } 1411 rangestr += "u = RFT(TV" + shiftstr + ")"; 1412 } else { 1413 // The immediate generally refers to a lane in the preceding argument. 1414 assert(immPos > 0 && "unexpected immediate operand"); 1415 rangestr = "u = " + utostr(RangeFromType(Proto[immPos-1], TypeVec[ti])); 1416 } 1417 // Make sure cases appear only once by uniquing them in a string map. 1418 namestr = MangleName(name, TypeVec[ti], ck); 1419 if (EmittedMap.count(namestr)) 1420 continue; 1421 EmittedMap[namestr] = OpNone; 1422 1423 // Calculate the index of the immediate that should be range checked. 1424 unsigned immidx = 0; 1425 1426 // Builtins that return a struct of multiple vectors have an extra 1427 // leading arg for the struct return. 1428 if (Proto[0] >= '2' && Proto[0] <= '4') 1429 ++immidx; 1430 1431 // Add one to the index for each argument until we reach the immediate 1432 // to be checked. Structs of vectors are passed as multiple arguments. 1433 for (unsigned ii = 1, ie = Proto.size(); ii != ie; ++ii) { 1434 switch (Proto[ii]) { 1435 default: immidx += 1; break; 1436 case '2': immidx += 2; break; 1437 case '3': immidx += 3; break; 1438 case '4': immidx += 4; break; 1439 case 'i': ie = ii + 1; break; 1440 } 1441 } 1442 OS << "case ARM::BI__builtin_neon_" << MangleName(name, TypeVec[ti], ck) 1443 << ": i = " << immidx << "; " << rangestr << "; break;\n"; 1444 } 1445 } 1446 OS << "#endif\n\n"; 1447 } 1448 1449 /// GenTest - Write out a test for the intrinsic specified by the name and 1450 /// type strings, including the embedded patterns for FileCheck to match. 1451 static std::string GenTest(const std::string &name, 1452 const std::string &proto, 1453 StringRef outTypeStr, StringRef inTypeStr, 1454 bool isShift) { 1455 assert(!proto.empty() && ""); 1456 std::string s; 1457 1458 // Function name with type suffix 1459 std::string mangledName = MangleName(name, outTypeStr, ClassS); 1460 if (outTypeStr != inTypeStr) { 1461 // If the input type is different (e.g., for vreinterpret), append a suffix 1462 // for the input type. String off a "Q" (quad) prefix so that MangleName 1463 // does not insert another "q" in the name. 1464 unsigned typeStrOff = (inTypeStr[0] == 'Q' ? 1 : 0); 1465 StringRef inTypeNoQuad = inTypeStr.substr(typeStrOff); 1466 mangledName = MangleName(mangledName, inTypeNoQuad, ClassS); 1467 } 1468 1469 // Emit the FileCheck patterns. 1470 s += "// CHECK: test_" + mangledName + "\n"; 1471 // s += "// CHECK: \n"; // FIXME: + expected instruction opcode. 1472 1473 // Emit the start of the test function. 1474 s += TypeString(proto[0], outTypeStr) + " test_" + mangledName + "("; 1475 char arg = 'a'; 1476 std::string comma; 1477 for (unsigned i = 1, e = proto.size(); i != e; ++i, ++arg) { 1478 // Do not create arguments for values that must be immediate constants. 1479 if (proto[i] == 'i') 1480 continue; 1481 s += comma + TypeString(proto[i], inTypeStr) + " "; 1482 s.push_back(arg); 1483 comma = ", "; 1484 } 1485 s += ") { \\\n "; 1486 1487 if (proto[0] != 'v') 1488 s += "return "; 1489 s += mangledName + "("; 1490 arg = 'a'; 1491 for (unsigned i = 1, e = proto.size(); i != e; ++i, ++arg) { 1492 if (proto[i] == 'i') { 1493 // For immediate operands, test the maximum value. 1494 if (isShift) 1495 s += "1"; // FIXME 1496 else 1497 // The immediate generally refers to a lane in the preceding argument. 1498 s += utostr(RangeFromType(proto[i-1], inTypeStr)); 1499 } else { 1500 s.push_back(arg); 1501 } 1502 if ((i + 1) < e) 1503 s += ", "; 1504 } 1505 s += ");\n}\n\n"; 1506 return s; 1507 } 1508 1509 /// runTests - Write out a complete set of tests for all of the Neon 1510 /// intrinsics. 1511 void NeonEmitter::runTests(raw_ostream &OS) { 1512 OS << 1513 "// RUN: %clang_cc1 -triple thumbv7-apple-darwin \\\n" 1514 "// RUN: -target-cpu cortex-a9 -ffreestanding -S -o - %s | FileCheck %s\n" 1515 "\n" 1516 "#include <arm_neon.h>\n" 1517 "\n"; 1518 1519 std::vector<Record*> RV = Records.getAllDerivedDefinitions("Inst"); 1520 for (unsigned i = 0, e = RV.size(); i != e; ++i) { 1521 Record *R = RV[i]; 1522 std::string name = R->getValueAsString("Name"); 1523 std::string Proto = R->getValueAsString("Prototype"); 1524 std::string Types = R->getValueAsString("Types"); 1525 bool isShift = R->getValueAsBit("isShift"); 1526 1527 SmallVector<StringRef, 16> TypeVec; 1528 ParseTypes(R, Types, TypeVec); 1529 1530 OpKind kind = OpMap[R->getValueAsDef("Operand")->getName()]; 1531 for (unsigned ti = 0, te = TypeVec.size(); ti != te; ++ti) { 1532 if (kind == OpReinterpret) { 1533 bool outQuad = false; 1534 bool dummy = false; 1535 (void)ClassifyType(TypeVec[ti], outQuad, dummy, dummy); 1536 for (unsigned srcti = 0, srcte = TypeVec.size(); 1537 srcti != srcte; ++srcti) { 1538 bool inQuad = false; 1539 (void)ClassifyType(TypeVec[srcti], inQuad, dummy, dummy); 1540 if (srcti == ti || inQuad != outQuad) 1541 continue; 1542 OS << GenTest(name, Proto, TypeVec[ti], TypeVec[srcti], isShift); 1543 } 1544 } else { 1545 OS << GenTest(name, Proto, TypeVec[ti], TypeVec[ti], isShift); 1546 } 1547 } 1548 OS << "\n"; 1549 } 1550 } 1551 1552