NeonEmitter.cpp revision 6f9f03ef370ad48ece0c5d10edda28f39ccadb5d
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 33using 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. 39static 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. 69static 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. 86static 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. 103static 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. 130static 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. 206static 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. 294static 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. 389static 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. 468static 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. 487static 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, ...)" 493static 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. 521static 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 if (MacroArgUsedDirectly(proto, i)) 530 continue; 531 generatedLocal = true; 532 533 s += TypeString(proto[i], typestr) + " __"; 534 s.push_back(arg); 535 s += " = ("; 536 s.push_back(arg); 537 s += "); "; 538 } 539 540 if (generatedLocal) 541 s += "\\\n "; 542 return s; 543} 544 545// Use the vmovl builtin to sign-extend or zero-extend a vector. 546static std::string Extend(StringRef typestr, const std::string &a) { 547 std::string s; 548 s = MangleName("vmovl", typestr, ClassS); 549 s += "(" + a + ")"; 550 return s; 551} 552 553static std::string Duplicate(unsigned nElts, StringRef typestr, 554 const std::string &a) { 555 std::string s; 556 557 s = "(" + TypeString('d', typestr) + "){ "; 558 for (unsigned i = 0; i != nElts; ++i) { 559 s += a; 560 if ((i + 1) < nElts) 561 s += ", "; 562 } 563 s += " }"; 564 565 return s; 566} 567 568static std::string SplatLane(unsigned nElts, const std::string &vec, 569 const std::string &lane) { 570 std::string s = "__builtin_shufflevector(" + vec + ", " + vec; 571 for (unsigned i = 0; i < nElts; ++i) 572 s += ", " + lane; 573 s += ")"; 574 return s; 575} 576 577static unsigned GetNumElements(StringRef typestr, bool &quad) { 578 quad = false; 579 bool dummy = false; 580 char type = ClassifyType(typestr, quad, dummy, dummy); 581 unsigned nElts = 0; 582 switch (type) { 583 case 'c': nElts = 8; break; 584 case 's': nElts = 4; break; 585 case 'i': nElts = 2; break; 586 case 'l': nElts = 1; break; 587 case 'h': nElts = 4; break; 588 case 'f': nElts = 2; break; 589 default: 590 throw "unhandled type!"; 591 break; 592 } 593 if (quad) nElts <<= 1; 594 return nElts; 595} 596 597// Generate the definition for this intrinsic, e.g. "a + b" for OpAdd. 598static std::string GenOpString(OpKind op, const std::string &proto, 599 StringRef typestr) { 600 bool quad; 601 unsigned nElts = GetNumElements(typestr, quad); 602 bool define = UseMacro(proto); 603 604 std::string ts = TypeString(proto[0], typestr); 605 std::string s; 606 if (!define) { 607 s = "return "; 608 } 609 610 switch(op) { 611 case OpAdd: 612 s += "__a + __b;"; 613 break; 614 case OpAddl: 615 s += Extend(typestr, "__a") + " + " + Extend(typestr, "__b") + ";"; 616 break; 617 case OpAddw: 618 s += "__a + " + Extend(typestr, "__b") + ";"; 619 break; 620 case OpSub: 621 s += "__a - __b;"; 622 break; 623 case OpSubl: 624 s += Extend(typestr, "__a") + " - " + Extend(typestr, "__b") + ";"; 625 break; 626 case OpSubw: 627 s += "__a - " + Extend(typestr, "__b") + ";"; 628 break; 629 case OpMulN: 630 s += "__a * " + Duplicate(nElts, typestr, "__b") + ";"; 631 break; 632 case OpMulLane: 633 s += "__a * " + SplatLane(nElts, "__b", "__c") + ";"; 634 break; 635 case OpMul: 636 s += "__a * __b;"; 637 break; 638 case OpMullLane: 639 s += MangleName("vmull", typestr, ClassS) + "(__a, " + 640 SplatLane(nElts, "__b", "__c") + ");"; 641 break; 642 case OpMlaN: 643 s += "__a + (__b * " + Duplicate(nElts, typestr, "__c") + ");"; 644 break; 645 case OpMlaLane: 646 s += "__a + (__b * " + SplatLane(nElts, "__c", "__d") + ");"; 647 break; 648 case OpMla: 649 s += "__a + (__b * __c);"; 650 break; 651 case OpMlalN: 652 s += "__a + " + MangleName("vmull", typestr, ClassS) + "(__b, " + 653 Duplicate(nElts, typestr, "__c") + ");"; 654 break; 655 case OpMlalLane: 656 s += "__a + " + MangleName("vmull", typestr, ClassS) + "(__b, " + 657 SplatLane(nElts, "__c", "__d") + ");"; 658 break; 659 case OpMlal: 660 s += "__a + " + MangleName("vmull", typestr, ClassS) + "(__b, __c);"; 661 break; 662 case OpMlsN: 663 s += "__a - (__b * " + Duplicate(nElts, typestr, "__c") + ");"; 664 break; 665 case OpMlsLane: 666 s += "__a - (__b * " + SplatLane(nElts, "__c", "__d") + ");"; 667 break; 668 case OpMls: 669 s += "__a - (__b * __c);"; 670 break; 671 case OpMlslN: 672 s += "__a - " + MangleName("vmull", typestr, ClassS) + "(__b, " + 673 Duplicate(nElts, typestr, "__c") + ");"; 674 break; 675 case OpMlslLane: 676 s += "__a - " + MangleName("vmull", typestr, ClassS) + "(__b, " + 677 SplatLane(nElts, "__c", "__d") + ");"; 678 break; 679 case OpMlsl: 680 s += "__a - " + MangleName("vmull", typestr, ClassS) + "(__b, __c);"; 681 break; 682 case OpQDMullLane: 683 s += MangleName("vqdmull", typestr, ClassS) + "(__a, " + 684 SplatLane(nElts, "__b", "__c") + ");"; 685 break; 686 case OpQDMlalLane: 687 s += MangleName("vqdmlal", typestr, ClassS) + "(__a, __b, " + 688 SplatLane(nElts, "__c", "__d") + ");"; 689 break; 690 case OpQDMlslLane: 691 s += MangleName("vqdmlsl", typestr, ClassS) + "(__a, __b, " + 692 SplatLane(nElts, "__c", "__d") + ");"; 693 break; 694 case OpQDMulhLane: 695 s += MangleName("vqdmulh", typestr, ClassS) + "(__a, " + 696 SplatLane(nElts, "__b", "__c") + ");"; 697 break; 698 case OpQRDMulhLane: 699 s += MangleName("vqrdmulh", typestr, ClassS) + "(__a, " + 700 SplatLane(nElts, "__b", "__c") + ");"; 701 break; 702 case OpEq: 703 s += "(" + ts + ")(__a == __b);"; 704 break; 705 case OpGe: 706 s += "(" + ts + ")(__a >= __b);"; 707 break; 708 case OpLe: 709 s += "(" + ts + ")(__a <= __b);"; 710 break; 711 case OpGt: 712 s += "(" + ts + ")(__a > __b);"; 713 break; 714 case OpLt: 715 s += "(" + ts + ")(__a < __b);"; 716 break; 717 case OpNeg: 718 s += " -__a;"; 719 break; 720 case OpNot: 721 s += " ~__a;"; 722 break; 723 case OpAnd: 724 s += "__a & __b;"; 725 break; 726 case OpOr: 727 s += "__a | __b;"; 728 break; 729 case OpXor: 730 s += "__a ^ __b;"; 731 break; 732 case OpAndNot: 733 s += "__a & ~__b;"; 734 break; 735 case OpOrNot: 736 s += "__a | ~__b;"; 737 break; 738 case OpCast: 739 s += "(" + ts + ")__a;"; 740 break; 741 case OpConcat: 742 s += "(" + ts + ")__builtin_shufflevector((int64x1_t)__a"; 743 s += ", (int64x1_t)__b, 0, 1);"; 744 break; 745 case OpHi: 746 s += "(" + ts + 747 ")__builtin_shufflevector((int64x2_t)__a, (int64x2_t)__a, 1);"; 748 break; 749 case OpLo: 750 s += "(" + ts + 751 ")__builtin_shufflevector((int64x2_t)__a, (int64x2_t)__a, 0);"; 752 break; 753 case OpDup: 754 s += Duplicate(nElts, typestr, "__a") + ";"; 755 break; 756 case OpDupLane: 757 s += SplatLane(nElts, "__a", "__b") + ";"; 758 break; 759 case OpSelect: 760 // ((0 & 1) | (~0 & 2)) 761 s += "(" + ts + ")"; 762 ts = TypeString(proto[1], typestr); 763 s += "((__a & (" + ts + ")__b) | "; 764 s += "(~__a & (" + ts + ")__c));"; 765 break; 766 case OpRev16: 767 s += "__builtin_shufflevector(__a, __a"; 768 for (unsigned i = 2; i <= nElts; i += 2) 769 for (unsigned j = 0; j != 2; ++j) 770 s += ", " + utostr(i - j - 1); 771 s += ");"; 772 break; 773 case OpRev32: { 774 unsigned WordElts = nElts >> (1 + (int)quad); 775 s += "__builtin_shufflevector(__a, __a"; 776 for (unsigned i = WordElts; i <= nElts; i += WordElts) 777 for (unsigned j = 0; j != WordElts; ++j) 778 s += ", " + utostr(i - j - 1); 779 s += ");"; 780 break; 781 } 782 case OpRev64: { 783 unsigned DblWordElts = nElts >> (int)quad; 784 s += "__builtin_shufflevector(__a, __a"; 785 for (unsigned i = DblWordElts; i <= nElts; i += DblWordElts) 786 for (unsigned j = 0; j != DblWordElts; ++j) 787 s += ", " + utostr(i - j - 1); 788 s += ");"; 789 break; 790 } 791 case OpAbdl: { 792 std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)"; 793 if (typestr[0] != 'U') { 794 // vabd results are always unsigned and must be zero-extended. 795 std::string utype = "U" + typestr.str(); 796 s += "(" + TypeString(proto[0], typestr) + ")"; 797 abd = "(" + TypeString('d', utype) + ")" + abd; 798 s += Extend(utype, abd) + ";"; 799 } else { 800 s += Extend(typestr, abd) + ";"; 801 } 802 break; 803 } 804 case OpAba: 805 s += "__a + " + MangleName("vabd", typestr, ClassS) + "(__b, __c);"; 806 break; 807 case OpAbal: { 808 s += "__a + "; 809 std::string abd = MangleName("vabd", typestr, ClassS) + "(__b, __c)"; 810 if (typestr[0] != 'U') { 811 // vabd results are always unsigned and must be zero-extended. 812 std::string utype = "U" + typestr.str(); 813 s += "(" + TypeString(proto[0], typestr) + ")"; 814 abd = "(" + TypeString('d', utype) + ")" + abd; 815 s += Extend(utype, abd) + ";"; 816 } else { 817 s += Extend(typestr, abd) + ";"; 818 } 819 break; 820 } 821 default: 822 throw "unknown OpKind!"; 823 break; 824 } 825 return s; 826} 827 828static unsigned GetNeonEnum(const std::string &proto, StringRef typestr) { 829 unsigned mod = proto[0]; 830 831 if (mod == 'v' || mod == 'f') 832 mod = proto[1]; 833 834 bool quad = false; 835 bool poly = false; 836 bool usgn = false; 837 bool scal = false; 838 bool cnst = false; 839 bool pntr = false; 840 841 // Base type to get the type string for. 842 char type = ClassifyType(typestr, quad, poly, usgn); 843 844 // Based on the modifying character, change the type and width if necessary. 845 type = ModType(mod, type, quad, poly, usgn, scal, cnst, pntr); 846 847 NeonTypeFlags::EltType ET; 848 switch (type) { 849 case 'c': 850 ET = poly ? NeonTypeFlags::Poly8 : NeonTypeFlags::Int8; 851 break; 852 case 's': 853 ET = poly ? NeonTypeFlags::Poly16 : NeonTypeFlags::Int16; 854 break; 855 case 'i': 856 ET = NeonTypeFlags::Int32; 857 break; 858 case 'l': 859 ET = NeonTypeFlags::Int64; 860 break; 861 case 'h': 862 ET = NeonTypeFlags::Float16; 863 break; 864 case 'f': 865 ET = NeonTypeFlags::Float32; 866 break; 867 default: 868 throw "unhandled type!"; 869 break; 870 } 871 NeonTypeFlags Flags(ET, usgn, quad && proto[1] != 'g'); 872 return Flags.getFlags(); 873} 874 875// Generate the definition for this intrinsic, e.g. __builtin_neon_cls(a) 876static std::string GenBuiltin(const std::string &name, const std::string &proto, 877 StringRef typestr, ClassKind ck) { 878 std::string s; 879 880 // If this builtin returns a struct 2, 3, or 4 vectors, pass it as an implicit 881 // sret-like argument. 882 bool sret = (proto[0] >= '2' && proto[0] <= '4'); 883 884 bool define = UseMacro(proto); 885 886 // Check if the prototype has a scalar operand with the type of the vector 887 // elements. If not, bitcasting the args will take care of arg checking. 888 // The actual signedness etc. will be taken care of with special enums. 889 if (proto.find('s') == std::string::npos) 890 ck = ClassB; 891 892 if (proto[0] != 'v') { 893 std::string ts = TypeString(proto[0], typestr); 894 895 if (define) { 896 if (sret) 897 s += ts + " r; "; 898 else 899 s += "(" + ts + ")"; 900 } else if (sret) { 901 s += ts + " r; "; 902 } else { 903 s += "return (" + ts + ")"; 904 } 905 } 906 907 bool splat = proto.find('a') != std::string::npos; 908 909 s += "__builtin_neon_"; 910 if (splat) { 911 // Call the non-splat builtin: chop off the "_n" suffix from the name. 912 std::string vname(name, 0, name.size()-2); 913 s += MangleName(vname, typestr, ck); 914 } else { 915 s += MangleName(name, typestr, ck); 916 } 917 s += "("; 918 919 // Pass the address of the return variable as the first argument to sret-like 920 // builtins. 921 if (sret) 922 s += "&r, "; 923 924 char arg = 'a'; 925 for (unsigned i = 1, e = proto.size(); i != e; ++i, ++arg) { 926 std::string args = std::string(&arg, 1); 927 928 // Use the local temporaries instead of the macro arguments. 929 args = "__" + args; 930 931 bool argQuad = false; 932 bool argPoly = false; 933 bool argUsgn = false; 934 bool argScalar = false; 935 bool dummy = false; 936 char argType = ClassifyType(typestr, argQuad, argPoly, argUsgn); 937 argType = ModType(proto[i], argType, argQuad, argPoly, argUsgn, argScalar, 938 dummy, dummy); 939 940 // Handle multiple-vector values specially, emitting each subvector as an 941 // argument to the __builtin. 942 if (proto[i] >= '2' && proto[i] <= '4') { 943 // Check if an explicit cast is needed. 944 if (argType != 'c' || argPoly || argUsgn) 945 args = (argQuad ? "(int8x16_t)" : "(int8x8_t)") + args; 946 947 for (unsigned vi = 0, ve = proto[i] - '0'; vi != ve; ++vi) { 948 s += args + ".val[" + utostr(vi) + "]"; 949 if ((vi + 1) < ve) 950 s += ", "; 951 } 952 if ((i + 1) < e) 953 s += ", "; 954 955 continue; 956 } 957 958 if (splat && (i + 1) == e) 959 args = Duplicate(GetNumElements(typestr, argQuad), typestr, args); 960 961 // Check if an explicit cast is needed. 962 if ((splat || !argScalar) && 963 ((ck == ClassB && argType != 'c') || argPoly || argUsgn)) { 964 std::string argTypeStr = "c"; 965 if (ck != ClassB) 966 argTypeStr = argType; 967 if (argQuad) 968 argTypeStr = "Q" + argTypeStr; 969 args = "(" + TypeString('d', argTypeStr) + ")" + args; 970 } 971 972 s += args; 973 if ((i + 1) < e) 974 s += ", "; 975 } 976 977 // Extra constant integer to hold type class enum for this function, e.g. s8 978 if (ck == ClassB) 979 s += ", " + utostr(GetNeonEnum(proto, typestr)); 980 981 s += ");"; 982 983 if (proto[0] != 'v' && sret) { 984 if (define) 985 s += " r;"; 986 else 987 s += " return r;"; 988 } 989 return s; 990} 991 992static std::string GenBuiltinDef(const std::string &name, 993 const std::string &proto, 994 StringRef typestr, ClassKind ck) { 995 std::string s("BUILTIN(__builtin_neon_"); 996 997 // If all types are the same size, bitcasting the args will take care 998 // of arg checking. The actual signedness etc. will be taken care of with 999 // special enums. 1000 if (proto.find('s') == std::string::npos) 1001 ck = ClassB; 1002 1003 s += MangleName(name, typestr, ck); 1004 s += ", \""; 1005 1006 for (unsigned i = 0, e = proto.size(); i != e; ++i) 1007 s += BuiltinTypeString(proto[i], typestr, ck, i == 0); 1008 1009 // Extra constant integer to hold type class enum for this function, e.g. s8 1010 if (ck == ClassB) 1011 s += "i"; 1012 1013 s += "\", \"n\")"; 1014 return s; 1015} 1016 1017static std::string GenIntrinsic(const std::string &name, 1018 const std::string &proto, 1019 StringRef outTypeStr, StringRef inTypeStr, 1020 OpKind kind, ClassKind classKind) { 1021 assert(!proto.empty() && ""); 1022 bool define = UseMacro(proto); 1023 std::string s; 1024 1025 // static always inline + return type 1026 if (define) 1027 s += "#define "; 1028 else 1029 s += "__ai " + TypeString(proto[0], outTypeStr) + " "; 1030 1031 // Function name with type suffix 1032 std::string mangledName = MangleName(name, outTypeStr, ClassS); 1033 if (outTypeStr != inTypeStr) { 1034 // If the input type is different (e.g., for vreinterpret), append a suffix 1035 // for the input type. String off a "Q" (quad) prefix so that MangleName 1036 // does not insert another "q" in the name. 1037 unsigned typeStrOff = (inTypeStr[0] == 'Q' ? 1 : 0); 1038 StringRef inTypeNoQuad = inTypeStr.substr(typeStrOff); 1039 mangledName = MangleName(mangledName, inTypeNoQuad, ClassS); 1040 } 1041 s += mangledName; 1042 1043 // Function arguments 1044 s += GenArgs(proto, inTypeStr); 1045 1046 // Definition. 1047 if (define) { 1048 s += " __extension__ ({ \\\n "; 1049 s += GenMacroLocals(proto, inTypeStr); 1050 } else { 1051 s += " { \\\n "; 1052 } 1053 1054 if (kind != OpNone) 1055 s += GenOpString(kind, proto, outTypeStr); 1056 else 1057 s += GenBuiltin(name, proto, outTypeStr, classKind); 1058 if (define) 1059 s += " })"; 1060 else 1061 s += " }"; 1062 s += "\n"; 1063 return s; 1064} 1065 1066/// run - Read the records in arm_neon.td and output arm_neon.h. arm_neon.h 1067/// is comprised of type definitions and function declarations. 1068void NeonEmitter::run(raw_ostream &OS) { 1069 OS << 1070 "/*===---- arm_neon.h - ARM Neon intrinsics ------------------------------" 1071 "---===\n" 1072 " *\n" 1073 " * Permission is hereby granted, free of charge, to any person obtaining " 1074 "a copy\n" 1075 " * of this software and associated documentation files (the \"Software\")," 1076 " to deal\n" 1077 " * in the Software without restriction, including without limitation the " 1078 "rights\n" 1079 " * to use, copy, modify, merge, publish, distribute, sublicense, " 1080 "and/or sell\n" 1081 " * copies of the Software, and to permit persons to whom the Software is\n" 1082 " * furnished to do so, subject to the following conditions:\n" 1083 " *\n" 1084 " * The above copyright notice and this permission notice shall be " 1085 "included in\n" 1086 " * all copies or substantial portions of the Software.\n" 1087 " *\n" 1088 " * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, " 1089 "EXPRESS OR\n" 1090 " * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF " 1091 "MERCHANTABILITY,\n" 1092 " * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT " 1093 "SHALL THE\n" 1094 " * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR " 1095 "OTHER\n" 1096 " * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, " 1097 "ARISING FROM,\n" 1098 " * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER " 1099 "DEALINGS IN\n" 1100 " * THE SOFTWARE.\n" 1101 " *\n" 1102 " *===--------------------------------------------------------------------" 1103 "---===\n" 1104 " */\n\n"; 1105 1106 OS << "#ifndef __ARM_NEON_H\n"; 1107 OS << "#define __ARM_NEON_H\n\n"; 1108 1109 OS << "#ifndef __ARM_NEON__\n"; 1110 OS << "#error \"NEON support not enabled\"\n"; 1111 OS << "#endif\n\n"; 1112 1113 OS << "#include <stdint.h>\n\n"; 1114 1115 // Emit NEON-specific scalar typedefs. 1116 OS << "typedef float float32_t;\n"; 1117 OS << "typedef int8_t poly8_t;\n"; 1118 OS << "typedef int16_t poly16_t;\n"; 1119 OS << "typedef uint16_t float16_t;\n"; 1120 1121 // Emit Neon vector typedefs. 1122 std::string TypedefTypes("cQcsQsiQilQlUcQUcUsQUsUiQUiUlQUlhQhfQfPcQPcPsQPs"); 1123 SmallVector<StringRef, 24> TDTypeVec; 1124 ParseTypes(0, TypedefTypes, TDTypeVec); 1125 1126 // Emit vector typedefs. 1127 for (unsigned i = 0, e = TDTypeVec.size(); i != e; ++i) { 1128 bool dummy, quad = false, poly = false; 1129 (void) ClassifyType(TDTypeVec[i], quad, poly, dummy); 1130 if (poly) 1131 OS << "typedef __attribute__((neon_polyvector_type("; 1132 else 1133 OS << "typedef __attribute__((neon_vector_type("; 1134 1135 unsigned nElts = GetNumElements(TDTypeVec[i], quad); 1136 OS << utostr(nElts) << "))) "; 1137 if (nElts < 10) 1138 OS << " "; 1139 1140 OS << TypeString('s', TDTypeVec[i]); 1141 OS << " " << TypeString('d', TDTypeVec[i]) << ";\n"; 1142 } 1143 OS << "\n"; 1144 1145 // Emit struct typedefs. 1146 for (unsigned vi = 2; vi != 5; ++vi) { 1147 for (unsigned i = 0, e = TDTypeVec.size(); i != e; ++i) { 1148 std::string ts = TypeString('d', TDTypeVec[i]); 1149 std::string vs = TypeString('0' + vi, TDTypeVec[i]); 1150 OS << "typedef struct " << vs << " {\n"; 1151 OS << " " << ts << " val"; 1152 OS << "[" << utostr(vi) << "]"; 1153 OS << ";\n} "; 1154 OS << vs << ";\n\n"; 1155 } 1156 } 1157 1158 OS<<"#define __ai static __attribute__((__always_inline__, __nodebug__))\n\n"; 1159 1160 std::vector<Record*> RV = Records.getAllDerivedDefinitions("Inst"); 1161 1162 // Emit vmovl, vmull and vabd intrinsics first so they can be used by other 1163 // intrinsics. (Some of the saturating multiply instructions are also 1164 // used to implement the corresponding "_lane" variants, but tablegen 1165 // sorts the records into alphabetical order so that the "_lane" variants 1166 // come after the intrinsics they use.) 1167 emitIntrinsic(OS, Records.getDef("VMOVL")); 1168 emitIntrinsic(OS, Records.getDef("VMULL")); 1169 emitIntrinsic(OS, Records.getDef("VABD")); 1170 1171 for (unsigned i = 0, e = RV.size(); i != e; ++i) { 1172 Record *R = RV[i]; 1173 if (R->getName() != "VMOVL" && 1174 R->getName() != "VMULL" && 1175 R->getName() != "VABD") 1176 emitIntrinsic(OS, R); 1177 } 1178 1179 OS << "#undef __ai\n\n"; 1180 OS << "#endif /* __ARM_NEON_H */\n"; 1181} 1182 1183/// emitIntrinsic - Write out the arm_neon.h header file definitions for the 1184/// intrinsics specified by record R. 1185void NeonEmitter::emitIntrinsic(raw_ostream &OS, Record *R) { 1186 std::string name = R->getValueAsString("Name"); 1187 std::string Proto = R->getValueAsString("Prototype"); 1188 std::string Types = R->getValueAsString("Types"); 1189 1190 SmallVector<StringRef, 16> TypeVec; 1191 ParseTypes(R, Types, TypeVec); 1192 1193 OpKind kind = OpMap[R->getValueAsDef("Operand")->getName()]; 1194 1195 ClassKind classKind = ClassNone; 1196 if (R->getSuperClasses().size() >= 2) 1197 classKind = ClassMap[R->getSuperClasses()[1]]; 1198 if (classKind == ClassNone && kind == OpNone) 1199 throw TGError(R->getLoc(), "Builtin has no class kind"); 1200 1201 for (unsigned ti = 0, te = TypeVec.size(); ti != te; ++ti) { 1202 if (kind == OpReinterpret) { 1203 bool outQuad = false; 1204 bool dummy = false; 1205 (void)ClassifyType(TypeVec[ti], outQuad, dummy, dummy); 1206 for (unsigned srcti = 0, srcte = TypeVec.size(); 1207 srcti != srcte; ++srcti) { 1208 bool inQuad = false; 1209 (void)ClassifyType(TypeVec[srcti], inQuad, dummy, dummy); 1210 if (srcti == ti || inQuad != outQuad) 1211 continue; 1212 OS << GenIntrinsic(name, Proto, TypeVec[ti], TypeVec[srcti], 1213 OpCast, ClassS); 1214 } 1215 } else { 1216 OS << GenIntrinsic(name, Proto, TypeVec[ti], TypeVec[ti], 1217 kind, classKind); 1218 } 1219 } 1220 OS << "\n"; 1221} 1222 1223static unsigned RangeFromType(const char mod, StringRef typestr) { 1224 // base type to get the type string for. 1225 bool quad = false, dummy = false; 1226 char type = ClassifyType(typestr, quad, dummy, dummy); 1227 type = ModType(mod, type, quad, dummy, dummy, dummy, dummy, dummy); 1228 1229 switch (type) { 1230 case 'c': 1231 return (8 << (int)quad) - 1; 1232 case 'h': 1233 case 's': 1234 return (4 << (int)quad) - 1; 1235 case 'f': 1236 case 'i': 1237 return (2 << (int)quad) - 1; 1238 case 'l': 1239 return (1 << (int)quad) - 1; 1240 default: 1241 throw "unhandled type!"; 1242 break; 1243 } 1244 assert(0 && "unreachable"); 1245 return 0; 1246} 1247 1248/// runHeader - Emit a file with sections defining: 1249/// 1. the NEON section of BuiltinsARM.def. 1250/// 2. the SemaChecking code for the type overload checking. 1251/// 3. the SemaChecking code for validation of intrinsic immedate arguments. 1252void NeonEmitter::runHeader(raw_ostream &OS) { 1253 std::vector<Record*> RV = Records.getAllDerivedDefinitions("Inst"); 1254 1255 StringMap<OpKind> EmittedMap; 1256 1257 // Generate BuiltinsARM.def for NEON 1258 OS << "#ifdef GET_NEON_BUILTINS\n"; 1259 for (unsigned i = 0, e = RV.size(); i != e; ++i) { 1260 Record *R = RV[i]; 1261 OpKind k = OpMap[R->getValueAsDef("Operand")->getName()]; 1262 if (k != OpNone) 1263 continue; 1264 1265 std::string Proto = R->getValueAsString("Prototype"); 1266 1267 // Functions with 'a' (the splat code) in the type prototype should not get 1268 // their own builtin as they use the non-splat variant. 1269 if (Proto.find('a') != std::string::npos) 1270 continue; 1271 1272 std::string Types = R->getValueAsString("Types"); 1273 SmallVector<StringRef, 16> TypeVec; 1274 ParseTypes(R, Types, TypeVec); 1275 1276 if (R->getSuperClasses().size() < 2) 1277 throw TGError(R->getLoc(), "Builtin has no class kind"); 1278 1279 std::string name = R->getValueAsString("Name"); 1280 ClassKind ck = ClassMap[R->getSuperClasses()[1]]; 1281 1282 for (unsigned ti = 0, te = TypeVec.size(); ti != te; ++ti) { 1283 // Generate the BuiltinsARM.def declaration for this builtin, ensuring 1284 // that each unique BUILTIN() macro appears only once in the output 1285 // stream. 1286 std::string bd = GenBuiltinDef(name, Proto, TypeVec[ti], ck); 1287 if (EmittedMap.count(bd)) 1288 continue; 1289 1290 EmittedMap[bd] = OpNone; 1291 OS << bd << "\n"; 1292 } 1293 } 1294 OS << "#endif\n\n"; 1295 1296 // Generate the overloaded type checking code for SemaChecking.cpp 1297 OS << "#ifdef GET_NEON_OVERLOAD_CHECK\n"; 1298 for (unsigned i = 0, e = RV.size(); i != e; ++i) { 1299 Record *R = RV[i]; 1300 OpKind k = OpMap[R->getValueAsDef("Operand")->getName()]; 1301 if (k != OpNone) 1302 continue; 1303 1304 std::string Proto = R->getValueAsString("Prototype"); 1305 std::string Types = R->getValueAsString("Types"); 1306 std::string name = R->getValueAsString("Name"); 1307 1308 // Functions with 'a' (the splat code) in the type prototype should not get 1309 // their own builtin as they use the non-splat variant. 1310 if (Proto.find('a') != std::string::npos) 1311 continue; 1312 1313 // Functions which have a scalar argument cannot be overloaded, no need to 1314 // check them if we are emitting the type checking code. 1315 if (Proto.find('s') != std::string::npos) 1316 continue; 1317 1318 SmallVector<StringRef, 16> TypeVec; 1319 ParseTypes(R, Types, TypeVec); 1320 1321 if (R->getSuperClasses().size() < 2) 1322 throw TGError(R->getLoc(), "Builtin has no class kind"); 1323 1324 int si = -1, qi = -1; 1325 unsigned mask = 0, qmask = 0; 1326 for (unsigned ti = 0, te = TypeVec.size(); ti != te; ++ti) { 1327 // Generate the switch case(s) for this builtin for the type validation. 1328 bool quad = false, poly = false, usgn = false; 1329 (void) ClassifyType(TypeVec[ti], quad, poly, usgn); 1330 1331 if (quad) { 1332 qi = ti; 1333 qmask |= 1 << GetNeonEnum(Proto, TypeVec[ti]); 1334 } else { 1335 si = ti; 1336 mask |= 1 << GetNeonEnum(Proto, TypeVec[ti]); 1337 } 1338 } 1339 bool HasPtr = (Proto.find('p') != std::string::npos); 1340 bool HasConstPtr = (Proto.find('c') != std::string::npos); 1341 if (mask) { 1342 OS << "case ARM::BI__builtin_neon_" 1343 << MangleName(name, TypeVec[si], ClassB) 1344 << ": mask = " << "0x" << utohexstr(mask); 1345 if (HasPtr) 1346 OS << "; HasPtr = true"; 1347 if (HasConstPtr) 1348 OS << "; HasConstPtr = true"; 1349 OS << "; break;\n"; 1350 } 1351 if (qmask) { 1352 OS << "case ARM::BI__builtin_neon_" 1353 << MangleName(name, TypeVec[qi], ClassB) 1354 << ": mask = " << "0x" << utohexstr(qmask); 1355 if (HasPtr) 1356 OS << "; HasPtr = true"; 1357 if (HasConstPtr) 1358 OS << "; HasConstPtr = true"; 1359 OS << "; break;\n"; 1360 } 1361 } 1362 OS << "#endif\n\n"; 1363 1364 // Generate the intrinsic range checking code for shift/lane immediates. 1365 OS << "#ifdef GET_NEON_IMMEDIATE_CHECK\n"; 1366 for (unsigned i = 0, e = RV.size(); i != e; ++i) { 1367 Record *R = RV[i]; 1368 1369 OpKind k = OpMap[R->getValueAsDef("Operand")->getName()]; 1370 if (k != OpNone) 1371 continue; 1372 1373 std::string name = R->getValueAsString("Name"); 1374 std::string Proto = R->getValueAsString("Prototype"); 1375 std::string Types = R->getValueAsString("Types"); 1376 1377 // Functions with 'a' (the splat code) in the type prototype should not get 1378 // their own builtin as they use the non-splat variant. 1379 if (Proto.find('a') != std::string::npos) 1380 continue; 1381 1382 // Functions which do not have an immediate do not need to have range 1383 // checking code emitted. 1384 size_t immPos = Proto.find('i'); 1385 if (immPos == std::string::npos) 1386 continue; 1387 1388 SmallVector<StringRef, 16> TypeVec; 1389 ParseTypes(R, Types, TypeVec); 1390 1391 if (R->getSuperClasses().size() < 2) 1392 throw TGError(R->getLoc(), "Builtin has no class kind"); 1393 1394 ClassKind ck = ClassMap[R->getSuperClasses()[1]]; 1395 1396 for (unsigned ti = 0, te = TypeVec.size(); ti != te; ++ti) { 1397 std::string namestr, shiftstr, rangestr; 1398 1399 if (R->getValueAsBit("isVCVT_N")) { 1400 // VCVT between floating- and fixed-point values takes an immediate 1401 // in the range 1 to 32. 1402 ck = ClassB; 1403 rangestr = "l = 1; u = 31"; // upper bound = l + u 1404 } else if (Proto.find('s') == std::string::npos) { 1405 // Builtins which are overloaded by type will need to have their upper 1406 // bound computed at Sema time based on the type constant. 1407 ck = ClassB; 1408 if (R->getValueAsBit("isShift")) { 1409 shiftstr = ", true"; 1410 1411 // Right shifts have an 'r' in the name, left shifts do not. 1412 if (name.find('r') != std::string::npos) 1413 rangestr = "l = 1; "; 1414 } 1415 rangestr += "u = RFT(TV" + shiftstr + ")"; 1416 } else { 1417 // The immediate generally refers to a lane in the preceding argument. 1418 assert(immPos > 0 && "unexpected immediate operand"); 1419 rangestr = "u = " + utostr(RangeFromType(Proto[immPos-1], TypeVec[ti])); 1420 } 1421 // Make sure cases appear only once by uniquing them in a string map. 1422 namestr = MangleName(name, TypeVec[ti], ck); 1423 if (EmittedMap.count(namestr)) 1424 continue; 1425 EmittedMap[namestr] = OpNone; 1426 1427 // Calculate the index of the immediate that should be range checked. 1428 unsigned immidx = 0; 1429 1430 // Builtins that return a struct of multiple vectors have an extra 1431 // leading arg for the struct return. 1432 if (Proto[0] >= '2' && Proto[0] <= '4') 1433 ++immidx; 1434 1435 // Add one to the index for each argument until we reach the immediate 1436 // to be checked. Structs of vectors are passed as multiple arguments. 1437 for (unsigned ii = 1, ie = Proto.size(); ii != ie; ++ii) { 1438 switch (Proto[ii]) { 1439 default: immidx += 1; break; 1440 case '2': immidx += 2; break; 1441 case '3': immidx += 3; break; 1442 case '4': immidx += 4; break; 1443 case 'i': ie = ii + 1; break; 1444 } 1445 } 1446 OS << "case ARM::BI__builtin_neon_" << MangleName(name, TypeVec[ti], ck) 1447 << ": i = " << immidx << "; " << rangestr << "; break;\n"; 1448 } 1449 } 1450 OS << "#endif\n\n"; 1451} 1452 1453/// GenTest - Write out a test for the intrinsic specified by the name and 1454/// type strings, including the embedded patterns for FileCheck to match. 1455static std::string GenTest(const std::string &name, 1456 const std::string &proto, 1457 StringRef outTypeStr, StringRef inTypeStr, 1458 bool isShift) { 1459 assert(!proto.empty() && ""); 1460 std::string s; 1461 1462 // Function name with type suffix 1463 std::string mangledName = MangleName(name, outTypeStr, ClassS); 1464 if (outTypeStr != inTypeStr) { 1465 // If the input type is different (e.g., for vreinterpret), append a suffix 1466 // for the input type. String off a "Q" (quad) prefix so that MangleName 1467 // does not insert another "q" in the name. 1468 unsigned typeStrOff = (inTypeStr[0] == 'Q' ? 1 : 0); 1469 StringRef inTypeNoQuad = inTypeStr.substr(typeStrOff); 1470 mangledName = MangleName(mangledName, inTypeNoQuad, ClassS); 1471 } 1472 1473 // Emit the FileCheck patterns. 1474 s += "// CHECK: test_" + mangledName + "\n"; 1475 // s += "// CHECK: \n"; // FIXME: + expected instruction opcode. 1476 1477 // Emit the start of the test function. 1478 s += TypeString(proto[0], outTypeStr) + " test_" + mangledName + "("; 1479 char arg = 'a'; 1480 std::string comma; 1481 for (unsigned i = 1, e = proto.size(); i != e; ++i, ++arg) { 1482 // Do not create arguments for values that must be immediate constants. 1483 if (proto[i] == 'i') 1484 continue; 1485 s += comma + TypeString(proto[i], inTypeStr) + " "; 1486 s.push_back(arg); 1487 comma = ", "; 1488 } 1489 s += ") { \\\n "; 1490 1491 if (proto[0] != 'v') 1492 s += "return "; 1493 s += mangledName + "("; 1494 arg = 'a'; 1495 for (unsigned i = 1, e = proto.size(); i != e; ++i, ++arg) { 1496 if (proto[i] == 'i') { 1497 // For immediate operands, test the maximum value. 1498 if (isShift) 1499 s += "1"; // FIXME 1500 else 1501 // The immediate generally refers to a lane in the preceding argument. 1502 s += utostr(RangeFromType(proto[i-1], inTypeStr)); 1503 } else { 1504 s.push_back(arg); 1505 } 1506 if ((i + 1) < e) 1507 s += ", "; 1508 } 1509 s += ");\n}\n\n"; 1510 return s; 1511} 1512 1513/// runTests - Write out a complete set of tests for all of the Neon 1514/// intrinsics. 1515void NeonEmitter::runTests(raw_ostream &OS) { 1516 OS << 1517 "// RUN: %clang_cc1 -triple thumbv7-apple-darwin \\\n" 1518 "// RUN: -target-cpu cortex-a9 -ffreestanding -S -o - %s | FileCheck %s\n" 1519 "\n" 1520 "#include <arm_neon.h>\n" 1521 "\n"; 1522 1523 std::vector<Record*> RV = Records.getAllDerivedDefinitions("Inst"); 1524 for (unsigned i = 0, e = RV.size(); i != e; ++i) { 1525 Record *R = RV[i]; 1526 std::string name = R->getValueAsString("Name"); 1527 std::string Proto = R->getValueAsString("Prototype"); 1528 std::string Types = R->getValueAsString("Types"); 1529 bool isShift = R->getValueAsBit("isShift"); 1530 1531 SmallVector<StringRef, 16> TypeVec; 1532 ParseTypes(R, Types, TypeVec); 1533 1534 OpKind kind = OpMap[R->getValueAsDef("Operand")->getName()]; 1535 for (unsigned ti = 0, te = TypeVec.size(); ti != te; ++ti) { 1536 if (kind == OpReinterpret) { 1537 bool outQuad = false; 1538 bool dummy = false; 1539 (void)ClassifyType(TypeVec[ti], outQuad, dummy, dummy); 1540 for (unsigned srcti = 0, srcte = TypeVec.size(); 1541 srcti != srcte; ++srcti) { 1542 bool inQuad = false; 1543 (void)ClassifyType(TypeVec[srcti], inQuad, dummy, dummy); 1544 if (srcti == ti || inQuad != outQuad) 1545 continue; 1546 OS << GenTest(name, Proto, TypeVec[ti], TypeVec[srcti], isShift); 1547 } 1548 } else { 1549 OS << GenTest(name, Proto, TypeVec[ti], TypeVec[ti], isShift); 1550 } 1551 } 1552 OS << "\n"; 1553 } 1554} 1555 1556