blob: d8f203d3df410ff440c565d1848ab33b98f42f6c [file] [log] [blame]
Peter Collingbourne51d77772011-10-06 13:03:08 +00001//===- 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
Jakob Stoklund Olesen3cc509b2012-06-13 05:12:41 +000026#include "llvm/ADT/DenseMap.h"
Peter Collingbourne51d77772011-10-06 13:03:08 +000027#include "llvm/ADT/SmallString.h"
28#include "llvm/ADT/SmallVector.h"
29#include "llvm/ADT/StringExtras.h"
Jakob Stoklund Olesen3cc509b2012-06-13 05:12:41 +000030#include "llvm/ADT/StringMap.h"
David Blaikie7530c032012-01-17 06:56:22 +000031#include "llvm/Support/ErrorHandling.h"
Jakob Stoklund Olesen3cc509b2012-06-13 05:12:41 +000032#include "llvm/TableGen/Error.h"
33#include "llvm/TableGen/Record.h"
34#include "llvm/TableGen/TableGenBackend.h"
Peter Collingbourne51d77772011-10-06 13:03:08 +000035#include <string>
Peter Collingbourne51d77772011-10-06 13:03:08 +000036using namespace llvm;
37
Jakob Stoklund Olesen3cc509b2012-06-13 05:12:41 +000038enum OpKind {
39 OpNone,
40 OpUnavailable,
41 OpAdd,
42 OpAddl,
43 OpAddw,
44 OpSub,
45 OpSubl,
46 OpSubw,
47 OpMul,
48 OpMla,
49 OpMlal,
50 OpMls,
51 OpMlsl,
52 OpMulN,
53 OpMlaN,
54 OpMlsN,
55 OpMlalN,
56 OpMlslN,
57 OpMulLane,
58 OpMullLane,
59 OpMlaLane,
60 OpMlsLane,
61 OpMlalLane,
62 OpMlslLane,
63 OpQDMullLane,
64 OpQDMlalLane,
65 OpQDMlslLane,
66 OpQDMulhLane,
67 OpQRDMulhLane,
68 OpEq,
69 OpGe,
70 OpLe,
71 OpGt,
72 OpLt,
73 OpNeg,
74 OpNot,
75 OpAnd,
76 OpOr,
77 OpXor,
78 OpAndNot,
79 OpOrNot,
80 OpCast,
81 OpConcat,
82 OpDup,
83 OpDupLane,
84 OpHi,
85 OpLo,
86 OpSelect,
87 OpRev16,
88 OpRev32,
89 OpRev64,
90 OpReinterpret,
91 OpAbdl,
92 OpAba,
Tim Northoverb793f0d2013-08-01 09:23:19 +000093 OpAbal,
Hao Liu912502b2013-09-04 09:29:13 +000094 OpDiv,
95 OpLongHi,
96 OpNarrowHi,
97 OpMovlHi
Jakob Stoklund Olesen3cc509b2012-06-13 05:12:41 +000098};
99
100enum ClassKind {
101 ClassNone,
102 ClassI, // generic integer instruction, e.g., "i8" suffix
103 ClassS, // signed/unsigned/poly, e.g., "s8", "u8" or "p8" suffix
104 ClassW, // width-specific instruction, e.g., "8" suffix
Michael Gottesman21e4e942013-04-16 21:18:42 +0000105 ClassB, // bitcast arguments with enum argument to specify type
106 ClassL, // Logical instructions which are op instructions
107 // but we need to not emit any suffix for in our
108 // tests.
109 ClassNoTest // Instructions which we do not test since they are
110 // not TRUE instructions.
Jakob Stoklund Olesen3cc509b2012-06-13 05:12:41 +0000111};
112
113/// NeonTypeFlags - Flags to identify the types for overloaded Neon
114/// builtins. These must be kept in sync with the flags in
115/// include/clang/Basic/TargetBuiltins.h.
116namespace {
117class NeonTypeFlags {
118 enum {
119 EltTypeMask = 0xf,
120 UnsignedFlag = 0x10,
121 QuadFlag = 0x20
122 };
123 uint32_t Flags;
124
125public:
126 enum EltType {
127 Int8,
128 Int16,
129 Int32,
130 Int64,
131 Poly8,
132 Poly16,
133 Float16,
Tim Northoverb793f0d2013-08-01 09:23:19 +0000134 Float32,
135 Float64
Jakob Stoklund Olesen3cc509b2012-06-13 05:12:41 +0000136 };
137
138 NeonTypeFlags(unsigned F) : Flags(F) {}
139 NeonTypeFlags(EltType ET, bool IsUnsigned, bool IsQuad) : Flags(ET) {
140 if (IsUnsigned)
141 Flags |= UnsignedFlag;
142 if (IsQuad)
143 Flags |= QuadFlag;
144 }
145
146 uint32_t getFlags() const { return Flags; }
147};
148} // end anonymous namespace
149
150namespace {
151class NeonEmitter {
152 RecordKeeper &Records;
153 StringMap<OpKind> OpMap;
154 DenseMap<Record*, ClassKind> ClassMap;
155
156public:
157 NeonEmitter(RecordKeeper &R) : Records(R) {
158 OpMap["OP_NONE"] = OpNone;
159 OpMap["OP_UNAVAILABLE"] = OpUnavailable;
160 OpMap["OP_ADD"] = OpAdd;
161 OpMap["OP_ADDL"] = OpAddl;
162 OpMap["OP_ADDW"] = OpAddw;
163 OpMap["OP_SUB"] = OpSub;
164 OpMap["OP_SUBL"] = OpSubl;
165 OpMap["OP_SUBW"] = OpSubw;
166 OpMap["OP_MUL"] = OpMul;
167 OpMap["OP_MLA"] = OpMla;
168 OpMap["OP_MLAL"] = OpMlal;
169 OpMap["OP_MLS"] = OpMls;
170 OpMap["OP_MLSL"] = OpMlsl;
171 OpMap["OP_MUL_N"] = OpMulN;
172 OpMap["OP_MLA_N"] = OpMlaN;
173 OpMap["OP_MLS_N"] = OpMlsN;
174 OpMap["OP_MLAL_N"] = OpMlalN;
175 OpMap["OP_MLSL_N"] = OpMlslN;
176 OpMap["OP_MUL_LN"]= OpMulLane;
177 OpMap["OP_MULL_LN"] = OpMullLane;
178 OpMap["OP_MLA_LN"]= OpMlaLane;
179 OpMap["OP_MLS_LN"]= OpMlsLane;
180 OpMap["OP_MLAL_LN"] = OpMlalLane;
181 OpMap["OP_MLSL_LN"] = OpMlslLane;
182 OpMap["OP_QDMULL_LN"] = OpQDMullLane;
183 OpMap["OP_QDMLAL_LN"] = OpQDMlalLane;
184 OpMap["OP_QDMLSL_LN"] = OpQDMlslLane;
185 OpMap["OP_QDMULH_LN"] = OpQDMulhLane;
186 OpMap["OP_QRDMULH_LN"] = OpQRDMulhLane;
187 OpMap["OP_EQ"] = OpEq;
188 OpMap["OP_GE"] = OpGe;
189 OpMap["OP_LE"] = OpLe;
190 OpMap["OP_GT"] = OpGt;
191 OpMap["OP_LT"] = OpLt;
192 OpMap["OP_NEG"] = OpNeg;
193 OpMap["OP_NOT"] = OpNot;
194 OpMap["OP_AND"] = OpAnd;
195 OpMap["OP_OR"] = OpOr;
196 OpMap["OP_XOR"] = OpXor;
197 OpMap["OP_ANDN"] = OpAndNot;
198 OpMap["OP_ORN"] = OpOrNot;
199 OpMap["OP_CAST"] = OpCast;
200 OpMap["OP_CONC"] = OpConcat;
201 OpMap["OP_HI"] = OpHi;
202 OpMap["OP_LO"] = OpLo;
203 OpMap["OP_DUP"] = OpDup;
204 OpMap["OP_DUP_LN"] = OpDupLane;
205 OpMap["OP_SEL"] = OpSelect;
206 OpMap["OP_REV16"] = OpRev16;
207 OpMap["OP_REV32"] = OpRev32;
208 OpMap["OP_REV64"] = OpRev64;
209 OpMap["OP_REINT"] = OpReinterpret;
210 OpMap["OP_ABDL"] = OpAbdl;
211 OpMap["OP_ABA"] = OpAba;
212 OpMap["OP_ABAL"] = OpAbal;
Tim Northoverb793f0d2013-08-01 09:23:19 +0000213 OpMap["OP_DIV"] = OpDiv;
Hao Liu912502b2013-09-04 09:29:13 +0000214 OpMap["OP_LONG_HI"] = OpLongHi;
215 OpMap["OP_NARROW_HI"] = OpNarrowHi;
216 OpMap["OP_MOVL_HI"] = OpMovlHi;
Jakob Stoklund Olesen3cc509b2012-06-13 05:12:41 +0000217
218 Record *SI = R.getClass("SInst");
219 Record *II = R.getClass("IInst");
220 Record *WI = R.getClass("WInst");
Michael Gottesman21e4e942013-04-16 21:18:42 +0000221 Record *SOpI = R.getClass("SOpInst");
222 Record *IOpI = R.getClass("IOpInst");
223 Record *WOpI = R.getClass("WOpInst");
224 Record *LOpI = R.getClass("LOpInst");
225 Record *NoTestOpI = R.getClass("NoTestOpInst");
226
Jakob Stoklund Olesen3cc509b2012-06-13 05:12:41 +0000227 ClassMap[SI] = ClassS;
228 ClassMap[II] = ClassI;
229 ClassMap[WI] = ClassW;
Michael Gottesman21e4e942013-04-16 21:18:42 +0000230 ClassMap[SOpI] = ClassS;
231 ClassMap[IOpI] = ClassI;
232 ClassMap[WOpI] = ClassW;
233 ClassMap[LOpI] = ClassL;
234 ClassMap[NoTestOpI] = ClassNoTest;
Jakob Stoklund Olesen3cc509b2012-06-13 05:12:41 +0000235 }
236
237 // run - Emit arm_neon.h.inc
238 void run(raw_ostream &o);
239
240 // runHeader - Emit all the __builtin prototypes used in arm_neon.h
241 void runHeader(raw_ostream &o);
242
243 // runTests - Emit tests for all the Neon intrinsics.
244 void runTests(raw_ostream &o);
245
246private:
Tim Northoverb793f0d2013-08-01 09:23:19 +0000247 void emitIntrinsic(raw_ostream &OS, Record *R,
248 StringMap<ClassKind> &EmittedMap);
249 void genBuiltinsDef(raw_ostream &OS, StringMap<ClassKind> &A64IntrinsicMap,
250 bool isA64GenBuiltinDef);
251 void genOverloadTypeCheckCode(raw_ostream &OS,
252 StringMap<ClassKind> &A64IntrinsicMap,
253 bool isA64TypeCheck);
254 void genIntrinsicRangeCheckCode(raw_ostream &OS,
255 StringMap<ClassKind> &A64IntrinsicMap,
256 bool isA64RangeCheck);
257 void genTargetTest(raw_ostream &OS, StringMap<OpKind> &EmittedMap,
258 bool isA64TestGen);
Jakob Stoklund Olesen3cc509b2012-06-13 05:12:41 +0000259};
260} // end anonymous namespace
261
Peter Collingbourne51d77772011-10-06 13:03:08 +0000262/// ParseTypes - break down a string such as "fQf" into a vector of StringRefs,
263/// which each StringRef representing a single type declared in the string.
264/// for "fQf" we would end up with 2 StringRefs, "f", and "Qf", representing
265/// 2xfloat and 4xfloat respectively.
266static void ParseTypes(Record *r, std::string &s,
267 SmallVectorImpl<StringRef> &TV) {
268 const char *data = s.data();
269 int len = 0;
270
271 for (unsigned i = 0, e = s.size(); i != e; ++i, ++len) {
Hao Liu12cd6a82013-08-15 08:26:30 +0000272 if (data[len] == 'P' || data[len] == 'Q' || data[len] == 'U'
Kevin Qin944f09f2013-08-29 07:55:15 +0000273 || data[len] == 'H' || data[len] == 'S')
Peter Collingbourne51d77772011-10-06 13:03:08 +0000274 continue;
275
276 switch (data[len]) {
277 case 'c':
278 case 's':
279 case 'i':
280 case 'l':
281 case 'h':
282 case 'f':
Tim Northoverb793f0d2013-08-01 09:23:19 +0000283 case 'd':
Peter Collingbourne51d77772011-10-06 13:03:08 +0000284 break;
285 default:
Joerg Sonnenberger38859ee2012-10-25 16:37:08 +0000286 PrintFatalError(r->getLoc(),
Peter Collingbourne51d77772011-10-06 13:03:08 +0000287 "Unexpected letter: " + std::string(data + len, 1));
Peter Collingbourne51d77772011-10-06 13:03:08 +0000288 }
289 TV.push_back(StringRef(data, len + 1));
290 data += len + 1;
291 len = -1;
292 }
293}
294
295/// Widen - Convert a type code into the next wider type. char -> short,
296/// short -> int, etc.
297static char Widen(const char t) {
298 switch (t) {
299 case 'c':
300 return 's';
301 case 's':
302 return 'i';
303 case 'i':
304 return 'l';
305 case 'h':
306 return 'f';
Joerg Sonnenberger38859ee2012-10-25 16:37:08 +0000307 default:
308 PrintFatalError("unhandled type in widen!");
Peter Collingbourne51d77772011-10-06 13:03:08 +0000309 }
Peter Collingbourne51d77772011-10-06 13:03:08 +0000310}
311
312/// Narrow - Convert a type code into the next smaller type. short -> char,
313/// float -> half float, etc.
314static char Narrow(const char t) {
315 switch (t) {
316 case 's':
317 return 'c';
318 case 'i':
319 return 's';
320 case 'l':
321 return 'i';
322 case 'f':
323 return 'h';
Joerg Sonnenberger38859ee2012-10-25 16:37:08 +0000324 default:
325 PrintFatalError("unhandled type in narrow!");
Peter Collingbourne51d77772011-10-06 13:03:08 +0000326 }
Peter Collingbourne51d77772011-10-06 13:03:08 +0000327}
328
329/// For a particular StringRef, return the base type code, and whether it has
330/// the quad-vector, polynomial, or unsigned modifiers set.
331static char ClassifyType(StringRef ty, bool &quad, bool &poly, bool &usgn) {
332 unsigned off = 0;
Kevin Qin944f09f2013-08-29 07:55:15 +0000333 // ignore scalar.
334 if (ty[off] == 'S') {
335 ++off;
336 }
Peter Collingbourne51d77772011-10-06 13:03:08 +0000337 // remember quad.
Hao Liu12cd6a82013-08-15 08:26:30 +0000338 if (ty[off] == 'Q' || ty[off] == 'H') {
Peter Collingbourne51d77772011-10-06 13:03:08 +0000339 quad = true;
340 ++off;
341 }
342
343 // remember poly.
344 if (ty[off] == 'P') {
345 poly = true;
346 ++off;
347 }
348
349 // remember unsigned.
350 if (ty[off] == 'U') {
351 usgn = true;
352 ++off;
353 }
354
355 // base type to get the type string for.
356 return ty[off];
357}
358
359/// ModType - Transform a type code and its modifiers based on a mod code. The
360/// mod code definitions may be found at the top of arm_neon.td.
361static char ModType(const char mod, char type, bool &quad, bool &poly,
362 bool &usgn, bool &scal, bool &cnst, bool &pntr) {
363 switch (mod) {
364 case 't':
365 if (poly) {
366 poly = false;
367 usgn = true;
368 }
369 break;
370 case 'u':
371 usgn = true;
372 poly = false;
373 if (type == 'f')
374 type = 'i';
Tim Northoverb793f0d2013-08-01 09:23:19 +0000375 if (type == 'd')
376 type = 'l';
Peter Collingbourne51d77772011-10-06 13:03:08 +0000377 break;
378 case 'x':
379 usgn = false;
380 poly = false;
381 if (type == 'f')
382 type = 'i';
Hao Liu912502b2013-09-04 09:29:13 +0000383 if (type == 'd')
384 type = 'l';
Peter Collingbourne51d77772011-10-06 13:03:08 +0000385 break;
386 case 'f':
387 if (type == 'h')
388 quad = true;
389 type = 'f';
390 usgn = false;
391 break;
392 case 'g':
393 quad = false;
394 break;
395 case 'w':
396 type = Widen(type);
397 quad = true;
398 break;
399 case 'n':
400 type = Widen(type);
401 break;
402 case 'i':
403 type = 'i';
404 scal = true;
405 break;
406 case 'l':
407 type = 'l';
408 scal = true;
409 usgn = true;
410 break;
411 case 's':
412 case 'a':
413 scal = true;
414 break;
415 case 'k':
416 quad = true;
417 break;
418 case 'c':
419 cnst = true;
420 case 'p':
421 pntr = true;
422 scal = true;
423 break;
424 case 'h':
425 type = Narrow(type);
426 if (type == 'h')
427 quad = false;
428 break;
429 case 'e':
430 type = Narrow(type);
431 usgn = true;
432 break;
Hao Liu912502b2013-09-04 09:29:13 +0000433 case 'm':
434 type = Narrow(type);
435 quad = false;
436 break;
Peter Collingbourne51d77772011-10-06 13:03:08 +0000437 default:
438 break;
439 }
440 return type;
441}
442
443/// TypeString - for a modifier and type, generate the name of the typedef for
444/// that type. QUc -> uint8x8_t.
445static std::string TypeString(const char mod, StringRef typestr) {
446 bool quad = false;
447 bool poly = false;
448 bool usgn = false;
449 bool scal = false;
450 bool cnst = false;
451 bool pntr = false;
452
453 if (mod == 'v')
454 return "void";
455 if (mod == 'i')
456 return "int";
457
458 // base type to get the type string for.
459 char type = ClassifyType(typestr, quad, poly, usgn);
460
461 // Based on the modifying character, change the type and width if necessary.
462 type = ModType(mod, type, quad, poly, usgn, scal, cnst, pntr);
463
464 SmallString<128> s;
465
466 if (usgn)
467 s.push_back('u');
468
469 switch (type) {
470 case 'c':
471 s += poly ? "poly8" : "int8";
472 if (scal)
473 break;
474 s += quad ? "x16" : "x8";
475 break;
476 case 's':
477 s += poly ? "poly16" : "int16";
478 if (scal)
479 break;
480 s += quad ? "x8" : "x4";
481 break;
482 case 'i':
483 s += "int32";
484 if (scal)
485 break;
486 s += quad ? "x4" : "x2";
487 break;
488 case 'l':
489 s += "int64";
490 if (scal)
491 break;
492 s += quad ? "x2" : "x1";
493 break;
494 case 'h':
495 s += "float16";
496 if (scal)
497 break;
498 s += quad ? "x8" : "x4";
499 break;
500 case 'f':
501 s += "float32";
502 if (scal)
503 break;
504 s += quad ? "x4" : "x2";
505 break;
Tim Northoverb793f0d2013-08-01 09:23:19 +0000506 case 'd':
507 s += "float64";
508 if (scal)
509 break;
510 s += quad ? "x2" : "x1";
511 break;
512
Peter Collingbourne51d77772011-10-06 13:03:08 +0000513 default:
Joerg Sonnenberger38859ee2012-10-25 16:37:08 +0000514 PrintFatalError("unhandled type!");
Peter Collingbourne51d77772011-10-06 13:03:08 +0000515 }
516
517 if (mod == '2')
518 s += "x2";
519 if (mod == '3')
520 s += "x3";
521 if (mod == '4')
522 s += "x4";
523
524 // Append _t, finishing the type string typedef type.
525 s += "_t";
526
527 if (cnst)
528 s += " const";
529
530 if (pntr)
531 s += " *";
532
533 return s.str();
534}
535
536/// BuiltinTypeString - for a modifier and type, generate the clang
537/// BuiltinsARM.def prototype code for the function. See the top of clang's
538/// Builtins.def for a description of the type strings.
539static std::string BuiltinTypeString(const char mod, StringRef typestr,
540 ClassKind ck, bool ret) {
541 bool quad = false;
542 bool poly = false;
543 bool usgn = false;
544 bool scal = false;
545 bool cnst = false;
546 bool pntr = false;
547
548 if (mod == 'v')
549 return "v"; // void
550 if (mod == 'i')
551 return "i"; // int
552
553 // base type to get the type string for.
554 char type = ClassifyType(typestr, quad, poly, usgn);
555
556 // Based on the modifying character, change the type and width if necessary.
557 type = ModType(mod, type, quad, poly, usgn, scal, cnst, pntr);
558
559 // All pointers are void* pointers. Change type to 'v' now.
560 if (pntr) {
561 usgn = false;
562 poly = false;
563 type = 'v';
564 }
565 // Treat half-float ('h') types as unsigned short ('s') types.
566 if (type == 'h') {
567 type = 's';
568 usgn = true;
569 }
570 usgn = usgn | poly | ((ck == ClassI || ck == ClassW) && scal && type != 'f');
571
572 if (scal) {
573 SmallString<128> s;
574
575 if (usgn)
576 s.push_back('U');
577 else if (type == 'c')
578 s.push_back('S'); // make chars explicitly signed
579
580 if (type == 'l') // 64-bit long
581 s += "LLi";
582 else
583 s.push_back(type);
584
585 if (cnst)
586 s.push_back('C');
587 if (pntr)
588 s.push_back('*');
589 return s.str();
590 }
591
592 // Since the return value must be one type, return a vector type of the
593 // appropriate width which we will bitcast. An exception is made for
594 // returning structs of 2, 3, or 4 vectors which are returned in a sret-like
595 // fashion, storing them to a pointer arg.
596 if (ret) {
597 if (mod >= '2' && mod <= '4')
598 return "vv*"; // void result with void* first argument
599 if (mod == 'f' || (ck != ClassB && type == 'f'))
600 return quad ? "V4f" : "V2f";
601 if (ck != ClassB && type == 's')
602 return quad ? "V8s" : "V4s";
603 if (ck != ClassB && type == 'i')
604 return quad ? "V4i" : "V2i";
605 if (ck != ClassB && type == 'l')
606 return quad ? "V2LLi" : "V1LLi";
607
608 return quad ? "V16Sc" : "V8Sc";
609 }
610
611 // Non-return array types are passed as individual vectors.
612 if (mod == '2')
613 return quad ? "V16ScV16Sc" : "V8ScV8Sc";
614 if (mod == '3')
615 return quad ? "V16ScV16ScV16Sc" : "V8ScV8ScV8Sc";
616 if (mod == '4')
617 return quad ? "V16ScV16ScV16ScV16Sc" : "V8ScV8ScV8ScV8Sc";
618
619 if (mod == 'f' || (ck != ClassB && type == 'f'))
620 return quad ? "V4f" : "V2f";
621 if (ck != ClassB && type == 's')
622 return quad ? "V8s" : "V4s";
623 if (ck != ClassB && type == 'i')
624 return quad ? "V4i" : "V2i";
625 if (ck != ClassB && type == 'l')
626 return quad ? "V2LLi" : "V1LLi";
627
628 return quad ? "V16Sc" : "V8Sc";
629}
630
Michael Gottesmanfb599a42013-04-16 22:07:30 +0000631/// InstructionTypeCode - Computes the ARM argument character code and
632/// quad status for a specific type string and ClassKind.
633static void InstructionTypeCode(const StringRef &typeStr,
634 const ClassKind ck,
635 bool &quad,
636 std::string &typeCode) {
637 bool poly = false;
638 bool usgn = false;
639 char type = ClassifyType(typeStr, quad, poly, usgn);
640
641 switch (type) {
642 case 'c':
643 switch (ck) {
644 case ClassS: typeCode = poly ? "p8" : usgn ? "u8" : "s8"; break;
645 case ClassI: typeCode = "i8"; break;
646 case ClassW: typeCode = "8"; break;
647 default: break;
648 }
649 break;
650 case 's':
651 switch (ck) {
652 case ClassS: typeCode = poly ? "p16" : usgn ? "u16" : "s16"; break;
653 case ClassI: typeCode = "i16"; break;
654 case ClassW: typeCode = "16"; break;
655 default: break;
656 }
657 break;
658 case 'i':
659 switch (ck) {
660 case ClassS: typeCode = usgn ? "u32" : "s32"; break;
661 case ClassI: typeCode = "i32"; break;
662 case ClassW: typeCode = "32"; break;
663 default: break;
664 }
665 break;
666 case 'l':
667 switch (ck) {
668 case ClassS: typeCode = usgn ? "u64" : "s64"; break;
669 case ClassI: typeCode = "i64"; break;
670 case ClassW: typeCode = "64"; break;
671 default: break;
672 }
673 break;
674 case 'h':
675 switch (ck) {
676 case ClassS:
677 case ClassI: typeCode = "f16"; break;
678 case ClassW: typeCode = "16"; break;
679 default: break;
680 }
681 break;
682 case 'f':
683 switch (ck) {
684 case ClassS:
685 case ClassI: typeCode = "f32"; break;
686 case ClassW: typeCode = "32"; break;
687 default: break;
688 }
689 break;
Tim Northoverb793f0d2013-08-01 09:23:19 +0000690 case 'd':
691 switch (ck) {
692 case ClassS:
693 case ClassI:
694 typeCode += "f64";
695 break;
696 case ClassW:
697 PrintFatalError("unhandled type!");
698 default:
699 break;
700 }
701 break;
Michael Gottesmanfb599a42013-04-16 22:07:30 +0000702 default:
703 PrintFatalError("unhandled type!");
704 }
705}
706
Kevin Qin944f09f2013-08-29 07:55:15 +0000707static char Insert_BHSD_Suffix(StringRef typestr){
708 unsigned off = 0;
709 if(typestr[off++] == 'S'){
710 while(typestr[off] == 'Q' || typestr[off] == 'H'||
711 typestr[off] == 'P' || typestr[off] == 'U')
712 ++off;
713 switch (typestr[off]){
714 default : break;
715 case 'c' : return 'b';
716 case 's' : return 'h';
717 case 'i' :
718 case 'f' : return 's';
719 case 'l' :
720 case 'd' : return 'd';
721 }
722 }
723 return 0;
724}
725
Peter Collingbourne51d77772011-10-06 13:03:08 +0000726/// MangleName - Append a type or width suffix to a base neon function name,
Hao Liu12cd6a82013-08-15 08:26:30 +0000727/// and insert a 'q' in the appropriate location if type string starts with 'Q'.
728/// E.g. turn "vst2_lane" into "vst2q_lane_f32", etc.
Kevin Qin944f09f2013-08-29 07:55:15 +0000729/// Insert proper 'b' 'h' 's' 'd' if prefix 'S' is used.
Peter Collingbourne51d77772011-10-06 13:03:08 +0000730static std::string MangleName(const std::string &name, StringRef typestr,
731 ClassKind ck) {
732 if (name == "vcvt_f32_f16")
733 return name;
734
735 bool quad = false;
Michael Gottesmanfb599a42013-04-16 22:07:30 +0000736 std::string typeCode = "";
737
738 InstructionTypeCode(typestr, ck, quad, typeCode);
Peter Collingbourne51d77772011-10-06 13:03:08 +0000739
740 std::string s = name;
741
Michael Gottesmanfb599a42013-04-16 22:07:30 +0000742 if (typeCode.size() > 0) {
743 s += "_" + typeCode;
Peter Collingbourne51d77772011-10-06 13:03:08 +0000744 }
Michael Gottesmanfb599a42013-04-16 22:07:30 +0000745
Peter Collingbourne51d77772011-10-06 13:03:08 +0000746 if (ck == ClassB)
747 s += "_v";
748
749 // Insert a 'q' before the first '_' character so that it ends up before
750 // _lane or _n on vector-scalar operations.
Kevin Qin944f09f2013-08-29 07:55:15 +0000751 if (typestr.find("Q") != StringRef::npos) {
Hao Liu12cd6a82013-08-15 08:26:30 +0000752 size_t pos = s.find('_');
753 s = s.insert(pos, "q");
Peter Collingbourne51d77772011-10-06 13:03:08 +0000754 }
Kevin Qin944f09f2013-08-29 07:55:15 +0000755 char ins = Insert_BHSD_Suffix(typestr);
756 if(ins){
757 size_t pos = s.find('_');
758 s = s.insert(pos, &ins, 1);
759 }
Michael Gottesmanc327f872013-04-16 23:00:26 +0000760
Peter Collingbourne51d77772011-10-06 13:03:08 +0000761 return s;
762}
763
Michael Gottesmanc327f872013-04-16 23:00:26 +0000764static void PreprocessInstruction(const StringRef &Name,
765 const std::string &InstName,
766 std::string &Prefix,
767 bool &HasNPostfix,
768 bool &HasLanePostfix,
769 bool &HasDupPostfix,
770 bool &IsSpecialVCvt,
771 size_t &TBNumber) {
772 // All of our instruction name fields from arm_neon.td are of the form
773 // <instructionname>_...
774 // Thus we grab our instruction name via computation of said Prefix.
775 const size_t PrefixEnd = Name.find_first_of('_');
776 // If InstName is passed in, we use that instead of our name Prefix.
777 Prefix = InstName.size() == 0? Name.slice(0, PrefixEnd).str() : InstName;
778
779 const StringRef Postfix = Name.slice(PrefixEnd, Name.size());
780
781 HasNPostfix = Postfix.count("_n");
782 HasLanePostfix = Postfix.count("_lane");
783 HasDupPostfix = Postfix.count("_dup");
784 IsSpecialVCvt = Postfix.size() != 0 && Name.count("vcvt");
785
786 if (InstName.compare("vtbl") == 0 ||
787 InstName.compare("vtbx") == 0) {
788 // If we have a vtblN/vtbxN instruction, use the instruction's ASCII
789 // encoding to get its true value.
790 TBNumber = Name[Name.size()-1] - 48;
791 }
792}
793
794/// GenerateRegisterCheckPatternsForLoadStores - Given a bunch of data we have
795/// extracted, generate a FileCheck pattern for a Load Or Store
796static void
797GenerateRegisterCheckPatternForLoadStores(const StringRef &NameRef,
798 const std::string& OutTypeCode,
799 const bool &IsQuad,
800 const bool &HasDupPostfix,
801 const bool &HasLanePostfix,
802 const size_t Count,
803 std::string &RegisterSuffix) {
804 const bool IsLDSTOne = NameRef.count("vld1") || NameRef.count("vst1");
805 // If N == 3 || N == 4 and we are dealing with a quad instruction, Clang
806 // will output a series of v{ld,st}1s, so we have to handle it specially.
807 if ((Count == 3 || Count == 4) && IsQuad) {
808 RegisterSuffix += "{";
809 for (size_t i = 0; i < Count; i++) {
810 RegisterSuffix += "d{{[0-9]+}}";
811 if (HasDupPostfix) {
812 RegisterSuffix += "[]";
813 }
814 if (HasLanePostfix) {
815 RegisterSuffix += "[{{[0-9]+}}]";
816 }
817 if (i < Count-1) {
818 RegisterSuffix += ", ";
819 }
820 }
821 RegisterSuffix += "}";
822 } else {
823
824 // Handle normal loads and stores.
825 RegisterSuffix += "{";
826 for (size_t i = 0; i < Count; i++) {
827 RegisterSuffix += "d{{[0-9]+}}";
828 if (HasDupPostfix) {
829 RegisterSuffix += "[]";
830 }
831 if (HasLanePostfix) {
832 RegisterSuffix += "[{{[0-9]+}}]";
833 }
834 if (IsQuad && !HasLanePostfix) {
835 RegisterSuffix += ", d{{[0-9]+}}";
836 if (HasDupPostfix) {
837 RegisterSuffix += "[]";
838 }
839 }
840 if (i < Count-1) {
841 RegisterSuffix += ", ";
842 }
843 }
844 RegisterSuffix += "}, [r{{[0-9]+}}";
845
846 // We only include the alignment hint if we have a vld1.*64 or
847 // a dup/lane instruction.
848 if (IsLDSTOne) {
849 if ((HasLanePostfix || HasDupPostfix) && OutTypeCode != "8") {
Michael Gottesman410c3f72013-06-24 21:25:37 +0000850 RegisterSuffix += ":" + OutTypeCode;
Michael Gottesmanc327f872013-04-16 23:00:26 +0000851 }
852 }
853
854 RegisterSuffix += "]";
855 }
856}
857
858static bool HasNPostfixAndScalarArgs(const StringRef &NameRef,
859 const bool &HasNPostfix) {
860 return (NameRef.count("vmla") ||
861 NameRef.count("vmlal") ||
862 NameRef.count("vmlsl") ||
863 NameRef.count("vmull") ||
864 NameRef.count("vqdmlal") ||
865 NameRef.count("vqdmlsl") ||
866 NameRef.count("vqdmulh") ||
867 NameRef.count("vqdmull") ||
868 NameRef.count("vqrdmulh")) && HasNPostfix;
869}
870
871static bool IsFiveOperandLaneAccumulator(const StringRef &NameRef,
872 const bool &HasLanePostfix) {
873 return (NameRef.count("vmla") ||
874 NameRef.count("vmls") ||
875 NameRef.count("vmlal") ||
876 NameRef.count("vmlsl") ||
877 (NameRef.count("vmul") && NameRef.size() == 3)||
878 NameRef.count("vqdmlal") ||
879 NameRef.count("vqdmlsl") ||
880 NameRef.count("vqdmulh") ||
881 NameRef.count("vqrdmulh")) && HasLanePostfix;
882}
883
884static bool IsSpecialLaneMultiply(const StringRef &NameRef,
885 const bool &HasLanePostfix,
886 const bool &IsQuad) {
887 const bool IsVMulOrMulh = (NameRef.count("vmul") || NameRef.count("mulh"))
888 && IsQuad;
889 const bool IsVMull = NameRef.count("mull") && !IsQuad;
890 return (IsVMulOrMulh || IsVMull) && HasLanePostfix;
891}
892
893static void NormalizeProtoForRegisterPatternCreation(const std::string &Name,
894 const std::string &Proto,
895 const bool &HasNPostfix,
896 const bool &IsQuad,
897 const bool &HasLanePostfix,
898 const bool &HasDupPostfix,
899 std::string &NormedProto) {
900 // Handle generic case.
901 const StringRef NameRef(Name);
902 for (size_t i = 0, end = Proto.size(); i < end; i++) {
903 switch (Proto[i]) {
904 case 'u':
905 case 'f':
906 case 'd':
907 case 's':
908 case 'x':
909 case 't':
910 case 'n':
911 NormedProto += IsQuad? 'q' : 'd';
912 break;
913 case 'w':
914 case 'k':
915 NormedProto += 'q';
916 break;
917 case 'g':
918 case 'h':
919 case 'e':
920 NormedProto += 'd';
921 break;
922 case 'i':
923 NormedProto += HasLanePostfix? 'a' : 'i';
924 break;
925 case 'a':
926 if (HasLanePostfix) {
927 NormedProto += 'a';
928 } else if (HasNPostfixAndScalarArgs(NameRef, HasNPostfix)) {
929 NormedProto += IsQuad? 'q' : 'd';
930 } else {
931 NormedProto += 'i';
932 }
933 break;
934 }
935 }
936
937 // Handle Special Cases.
938 const bool IsNotVExt = !NameRef.count("vext");
939 const bool IsVPADAL = NameRef.count("vpadal");
940 const bool Is5OpLaneAccum = IsFiveOperandLaneAccumulator(NameRef,
941 HasLanePostfix);
942 const bool IsSpecialLaneMul = IsSpecialLaneMultiply(NameRef, HasLanePostfix,
943 IsQuad);
944
945 if (IsSpecialLaneMul) {
946 // If
947 NormedProto[2] = NormedProto[3];
948 NormedProto.erase(3);
949 } else if (NormedProto.size() == 4 &&
950 NormedProto[0] == NormedProto[1] &&
951 IsNotVExt) {
952 // If NormedProto.size() == 4 and the first two proto characters are the
953 // same, ignore the first.
954 NormedProto = NormedProto.substr(1, 3);
955 } else if (Is5OpLaneAccum) {
956 // If we have a 5 op lane accumulator operation, we take characters 1,2,4
957 std::string tmp = NormedProto.substr(1,2);
958 tmp += NormedProto[4];
959 NormedProto = tmp;
960 } else if (IsVPADAL) {
961 // If we have VPADAL, ignore the first character.
962 NormedProto = NormedProto.substr(0, 2);
963 } else if (NameRef.count("vdup") && NormedProto.size() > 2) {
964 // If our instruction is a dup instruction, keep only the first and
965 // last characters.
966 std::string tmp = "";
967 tmp += NormedProto[0];
968 tmp += NormedProto[NormedProto.size()-1];
969 NormedProto = tmp;
970 }
971}
972
973/// GenerateRegisterCheckPatterns - Given a bunch of data we have
974/// extracted, generate a FileCheck pattern to check that an
975/// instruction's arguments are correct.
976static void GenerateRegisterCheckPattern(const std::string &Name,
977 const std::string &Proto,
978 const std::string &OutTypeCode,
979 const bool &HasNPostfix,
980 const bool &IsQuad,
981 const bool &HasLanePostfix,
982 const bool &HasDupPostfix,
983 const size_t &TBNumber,
984 std::string &RegisterSuffix) {
985
986 RegisterSuffix = "";
987
988 const StringRef NameRef(Name);
989 const StringRef ProtoRef(Proto);
990
991 if ((NameRef.count("vdup") || NameRef.count("vmov")) && HasNPostfix) {
992 return;
993 }
994
995 const bool IsLoadStore = NameRef.count("vld") || NameRef.count("vst");
996 const bool IsTBXOrTBL = NameRef.count("vtbl") || NameRef.count("vtbx");
997
998 if (IsLoadStore) {
999 // Grab N value from v{ld,st}N using its ascii representation.
1000 const size_t Count = NameRef[3] - 48;
1001
1002 GenerateRegisterCheckPatternForLoadStores(NameRef, OutTypeCode, IsQuad,
1003 HasDupPostfix, HasLanePostfix,
1004 Count, RegisterSuffix);
1005 } else if (IsTBXOrTBL) {
1006 RegisterSuffix += "d{{[0-9]+}}, {";
1007 for (size_t i = 0; i < TBNumber-1; i++) {
1008 RegisterSuffix += "d{{[0-9]+}}, ";
1009 }
1010 RegisterSuffix += "d{{[0-9]+}}}, d{{[0-9]+}}";
1011 } else {
1012 // Handle a normal instruction.
1013 if (NameRef.count("vget") || NameRef.count("vset"))
1014 return;
1015
1016 // We first normalize our proto, since we only need to emit 4
1017 // different types of checks, yet have more than 4 proto types
1018 // that map onto those 4 patterns.
1019 std::string NormalizedProto("");
1020 NormalizeProtoForRegisterPatternCreation(Name, Proto, HasNPostfix, IsQuad,
1021 HasLanePostfix, HasDupPostfix,
1022 NormalizedProto);
1023
1024 for (size_t i = 0, end = NormalizedProto.size(); i < end; i++) {
1025 const char &c = NormalizedProto[i];
1026 switch (c) {
1027 case 'q':
1028 RegisterSuffix += "q{{[0-9]+}}, ";
1029 break;
1030
1031 case 'd':
1032 RegisterSuffix += "d{{[0-9]+}}, ";
1033 break;
1034
1035 case 'i':
1036 RegisterSuffix += "#{{[0-9]+}}, ";
1037 break;
1038
1039 case 'a':
1040 RegisterSuffix += "d{{[0-9]+}}[{{[0-9]}}], ";
1041 break;
1042 }
1043 }
1044
1045 // Remove extra ", ".
1046 RegisterSuffix = RegisterSuffix.substr(0, RegisterSuffix.size()-2);
1047 }
1048}
1049
1050/// GenerateChecksForIntrinsic - Given a specific instruction name +
1051/// typestr + class kind, generate the proper set of FileCheck
1052/// Patterns to check for. We could just return a string, but instead
1053/// use a vector since it provides us with the extra flexibility of
1054/// emitting multiple checks, which comes in handy for certain cases
1055/// like mla where we want to check for 2 different instructions.
1056static void GenerateChecksForIntrinsic(const std::string &Name,
1057 const std::string &Proto,
1058 StringRef &OutTypeStr,
1059 StringRef &InTypeStr,
1060 ClassKind Ck,
1061 const std::string &InstName,
1062 bool IsHiddenLOp,
1063 std::vector<std::string>& Result) {
1064
1065 // If Ck is a ClassNoTest instruction, just return so no test is
1066 // emitted.
1067 if(Ck == ClassNoTest)
1068 return;
1069
1070 if (Name == "vcvt_f32_f16") {
1071 Result.push_back("vcvt.f32.f16");
1072 return;
1073 }
1074
1075
1076 // Now we preprocess our instruction given the data we have to get the
1077 // data that we need.
1078 // Create a StringRef for String Manipulation of our Name.
1079 const StringRef NameRef(Name);
1080 // Instruction Prefix.
1081 std::string Prefix;
1082 // The type code for our out type string.
1083 std::string OutTypeCode;
1084 // To handle our different cases, we need to check for different postfixes.
1085 // Is our instruction a quad instruction.
1086 bool IsQuad = false;
1087 // Our instruction is of the form <instructionname>_n.
1088 bool HasNPostfix = false;
1089 // Our instruction is of the form <instructionname>_lane.
1090 bool HasLanePostfix = false;
1091 // Our instruction is of the form <instructionname>_dup.
1092 bool HasDupPostfix = false;
1093 // Our instruction is a vcvt instruction which requires special handling.
1094 bool IsSpecialVCvt = false;
1095 // If we have a vtbxN or vtblN instruction, this is set to N.
1096 size_t TBNumber = -1;
1097 // Register Suffix
1098 std::string RegisterSuffix;
1099
1100 PreprocessInstruction(NameRef, InstName, Prefix,
1101 HasNPostfix, HasLanePostfix, HasDupPostfix,
1102 IsSpecialVCvt, TBNumber);
1103
1104 InstructionTypeCode(OutTypeStr, Ck, IsQuad, OutTypeCode);
1105 GenerateRegisterCheckPattern(Name, Proto, OutTypeCode, HasNPostfix, IsQuad,
1106 HasLanePostfix, HasDupPostfix, TBNumber,
1107 RegisterSuffix);
1108
1109 // In the following section, we handle a bunch of special cases. You can tell
1110 // a special case by the fact we are returning early.
1111
1112 // If our instruction is a logical instruction without postfix or a
1113 // hidden LOp just return the current Prefix.
1114 if (Ck == ClassL || IsHiddenLOp) {
1115 Result.push_back(Prefix + " " + RegisterSuffix);
1116 return;
1117 }
1118
1119 // If we have a vmov, due to the many different cases, some of which
1120 // vary within the different intrinsics generated for a single
1121 // instruction type, just output a vmov. (e.g. given an instruction
1122 // A, A.u32 might be vmov and A.u8 might be vmov.8).
1123 //
1124 // FIXME: Maybe something can be done about this. The two cases that we care
1125 // about are vmov as an LType and vmov as a WType.
1126 if (Prefix == "vmov") {
1127 Result.push_back(Prefix + " " + RegisterSuffix);
1128 return;
1129 }
1130
1131 // In the following section, we handle special cases.
1132
1133 if (OutTypeCode == "64") {
1134 // If we have a 64 bit vdup/vext and are handling an uint64x1_t
1135 // type, the intrinsic will be optimized away, so just return
1136 // nothing. On the other hand if we are handling an uint64x2_t
1137 // (i.e. quad instruction), vdup/vmov instructions should be
1138 // emitted.
1139 if (Prefix == "vdup" || Prefix == "vext") {
1140 if (IsQuad) {
1141 Result.push_back("{{vmov|vdup}}");
1142 }
1143 return;
1144 }
1145
1146 // v{st,ld}{2,3,4}_{u,s}64 emit v{st,ld}1.64 instructions with
1147 // multiple register operands.
1148 bool MultiLoadPrefix = Prefix == "vld2" || Prefix == "vld3"
1149 || Prefix == "vld4";
1150 bool MultiStorePrefix = Prefix == "vst2" || Prefix == "vst3"
1151 || Prefix == "vst4";
1152 if (MultiLoadPrefix || MultiStorePrefix) {
1153 Result.push_back(NameRef.slice(0, 3).str() + "1.64");
1154 return;
1155 }
1156
1157 // v{st,ld}1_{lane,dup}_{u64,s64} use vldr/vstr/vmov/str instead of
1158 // emitting said instructions. So return a check for
1159 // vldr/vstr/vmov/str instead.
1160 if (HasLanePostfix || HasDupPostfix) {
1161 if (Prefix == "vst1") {
1162 Result.push_back("{{str|vstr|vmov}}");
1163 return;
1164 } else if (Prefix == "vld1") {
1165 Result.push_back("{{ldr|vldr|vmov}}");
1166 return;
1167 }
1168 }
1169 }
1170
1171 // vzip.32/vuzp.32 are the same instruction as vtrn.32 and are
1172 // sometimes disassembled as vtrn.32. We use a regex to handle both
1173 // cases.
1174 if ((Prefix == "vzip" || Prefix == "vuzp") && OutTypeCode == "32") {
1175 Result.push_back("{{vtrn|" + Prefix + "}}.32 " + RegisterSuffix);
1176 return;
1177 }
1178
1179 // Currently on most ARM processors, we do not use vmla/vmls for
1180 // quad floating point operations. Instead we output vmul + vadd. So
1181 // check if we have one of those instructions and just output a
1182 // check for vmul.
1183 if (OutTypeCode == "f32") {
1184 if (Prefix == "vmls") {
1185 Result.push_back("vmul." + OutTypeCode + " " + RegisterSuffix);
1186 Result.push_back("vsub." + OutTypeCode);
1187 return;
1188 } else if (Prefix == "vmla") {
1189 Result.push_back("vmul." + OutTypeCode + " " + RegisterSuffix);
1190 Result.push_back("vadd." + OutTypeCode);
1191 return;
1192 }
1193 }
1194
1195 // If we have vcvt, get the input type from the instruction name
1196 // (which should be of the form instname_inputtype) and append it
1197 // before the output type.
1198 if (Prefix == "vcvt") {
1199 const std::string inTypeCode = NameRef.substr(NameRef.find_last_of("_")+1);
1200 Prefix += "." + inTypeCode;
1201 }
1202
1203 // Append output type code to get our final mangled instruction.
1204 Prefix += "." + OutTypeCode;
1205
1206 Result.push_back(Prefix + " " + RegisterSuffix);
1207}
1208
Peter Collingbourne51d77772011-10-06 13:03:08 +00001209/// UseMacro - Examine the prototype string to determine if the intrinsic
1210/// should be defined as a preprocessor macro instead of an inline function.
1211static bool UseMacro(const std::string &proto) {
1212 // If this builtin takes an immediate argument, we need to #define it rather
1213 // than use a standard declaration, so that SemaChecking can range check
1214 // the immediate passed by the user.
1215 if (proto.find('i') != std::string::npos)
1216 return true;
1217
1218 // Pointer arguments need to use macros to avoid hiding aligned attributes
1219 // from the pointer type.
1220 if (proto.find('p') != std::string::npos ||
1221 proto.find('c') != std::string::npos)
1222 return true;
1223
1224 return false;
1225}
1226
1227/// MacroArgUsedDirectly - Return true if argument i for an intrinsic that is
1228/// defined as a macro should be accessed directly instead of being first
1229/// assigned to a local temporary.
1230static bool MacroArgUsedDirectly(const std::string &proto, unsigned i) {
1231 // True for constant ints (i), pointers (p) and const pointers (c).
1232 return (proto[i] == 'i' || proto[i] == 'p' || proto[i] == 'c');
1233}
1234
1235// Generate the string "(argtype a, argtype b, ...)"
1236static std::string GenArgs(const std::string &proto, StringRef typestr) {
1237 bool define = UseMacro(proto);
1238 char arg = 'a';
1239
1240 std::string s;
1241 s += "(";
1242
1243 for (unsigned i = 1, e = proto.size(); i != e; ++i, ++arg) {
1244 if (define) {
1245 // Some macro arguments are used directly instead of being assigned
1246 // to local temporaries; prepend an underscore prefix to make their
1247 // names consistent with the local temporaries.
1248 if (MacroArgUsedDirectly(proto, i))
1249 s += "__";
1250 } else {
1251 s += TypeString(proto[i], typestr) + " __";
1252 }
1253 s.push_back(arg);
1254 if ((i + 1) < e)
1255 s += ", ";
1256 }
1257
1258 s += ")";
1259 return s;
1260}
1261
1262// Macro arguments are not type-checked like inline function arguments, so
1263// assign them to local temporaries to get the right type checking.
1264static std::string GenMacroLocals(const std::string &proto, StringRef typestr) {
1265 char arg = 'a';
1266 std::string s;
1267 bool generatedLocal = false;
1268
1269 for (unsigned i = 1, e = proto.size(); i != e; ++i, ++arg) {
1270 // Do not create a temporary for an immediate argument.
1271 // That would defeat the whole point of using a macro!
Peter Collingbourne51d77772011-10-06 13:03:08 +00001272 if (MacroArgUsedDirectly(proto, i))
1273 continue;
1274 generatedLocal = true;
1275
1276 s += TypeString(proto[i], typestr) + " __";
1277 s.push_back(arg);
1278 s += " = (";
1279 s.push_back(arg);
1280 s += "); ";
1281 }
1282
1283 if (generatedLocal)
1284 s += "\\\n ";
1285 return s;
1286}
1287
1288// Use the vmovl builtin to sign-extend or zero-extend a vector.
1289static std::string Extend(StringRef typestr, const std::string &a) {
1290 std::string s;
1291 s = MangleName("vmovl", typestr, ClassS);
1292 s += "(" + a + ")";
1293 return s;
1294}
1295
1296static std::string Duplicate(unsigned nElts, StringRef typestr,
1297 const std::string &a) {
1298 std::string s;
1299
1300 s = "(" + TypeString('d', typestr) + "){ ";
1301 for (unsigned i = 0; i != nElts; ++i) {
1302 s += a;
1303 if ((i + 1) < nElts)
1304 s += ", ";
1305 }
1306 s += " }";
1307
1308 return s;
1309}
1310
1311static std::string SplatLane(unsigned nElts, const std::string &vec,
1312 const std::string &lane) {
1313 std::string s = "__builtin_shufflevector(" + vec + ", " + vec;
1314 for (unsigned i = 0; i < nElts; ++i)
1315 s += ", " + lane;
1316 s += ")";
1317 return s;
1318}
1319
Hao Liu912502b2013-09-04 09:29:13 +00001320static std::string RemoveHigh(const std::string &name) {
1321 std::string s = name;
1322 std::size_t found = s.find("_high_");
1323 if (found == std::string::npos)
1324 PrintFatalError("name should contain \"_high_\" for high intrinsics");
1325 s.replace(found, 5, "");
1326 return s;
1327}
1328
Peter Collingbourne51d77772011-10-06 13:03:08 +00001329static unsigned GetNumElements(StringRef typestr, bool &quad) {
1330 quad = false;
1331 bool dummy = false;
1332 char type = ClassifyType(typestr, quad, dummy, dummy);
1333 unsigned nElts = 0;
1334 switch (type) {
1335 case 'c': nElts = 8; break;
1336 case 's': nElts = 4; break;
1337 case 'i': nElts = 2; break;
1338 case 'l': nElts = 1; break;
1339 case 'h': nElts = 4; break;
1340 case 'f': nElts = 2; break;
Tim Northoverb793f0d2013-08-01 09:23:19 +00001341 case 'd':
1342 nElts = 1;
1343 break;
Peter Collingbourne51d77772011-10-06 13:03:08 +00001344 default:
Joerg Sonnenberger38859ee2012-10-25 16:37:08 +00001345 PrintFatalError("unhandled type!");
Peter Collingbourne51d77772011-10-06 13:03:08 +00001346 }
1347 if (quad) nElts <<= 1;
1348 return nElts;
1349}
1350
1351// Generate the definition for this intrinsic, e.g. "a + b" for OpAdd.
Hao Liu912502b2013-09-04 09:29:13 +00001352static std::string GenOpString(const std::string &name, OpKind op,
1353 const std::string &proto, StringRef typestr) {
Peter Collingbourne51d77772011-10-06 13:03:08 +00001354 bool quad;
1355 unsigned nElts = GetNumElements(typestr, quad);
1356 bool define = UseMacro(proto);
1357
1358 std::string ts = TypeString(proto[0], typestr);
1359 std::string s;
1360 if (!define) {
1361 s = "return ";
1362 }
1363
1364 switch(op) {
1365 case OpAdd:
1366 s += "__a + __b;";
1367 break;
1368 case OpAddl:
1369 s += Extend(typestr, "__a") + " + " + Extend(typestr, "__b") + ";";
1370 break;
1371 case OpAddw:
1372 s += "__a + " + Extend(typestr, "__b") + ";";
1373 break;
1374 case OpSub:
1375 s += "__a - __b;";
1376 break;
1377 case OpSubl:
1378 s += Extend(typestr, "__a") + " - " + Extend(typestr, "__b") + ";";
1379 break;
1380 case OpSubw:
1381 s += "__a - " + Extend(typestr, "__b") + ";";
1382 break;
1383 case OpMulN:
1384 s += "__a * " + Duplicate(nElts, typestr, "__b") + ";";
1385 break;
1386 case OpMulLane:
1387 s += "__a * " + SplatLane(nElts, "__b", "__c") + ";";
1388 break;
1389 case OpMul:
1390 s += "__a * __b;";
1391 break;
1392 case OpMullLane:
1393 s += MangleName("vmull", typestr, ClassS) + "(__a, " +
1394 SplatLane(nElts, "__b", "__c") + ");";
1395 break;
1396 case OpMlaN:
1397 s += "__a + (__b * " + Duplicate(nElts, typestr, "__c") + ");";
1398 break;
1399 case OpMlaLane:
1400 s += "__a + (__b * " + SplatLane(nElts, "__c", "__d") + ");";
1401 break;
1402 case OpMla:
1403 s += "__a + (__b * __c);";
1404 break;
1405 case OpMlalN:
1406 s += "__a + " + MangleName("vmull", typestr, ClassS) + "(__b, " +
1407 Duplicate(nElts, typestr, "__c") + ");";
1408 break;
1409 case OpMlalLane:
1410 s += "__a + " + MangleName("vmull", typestr, ClassS) + "(__b, " +
1411 SplatLane(nElts, "__c", "__d") + ");";
1412 break;
1413 case OpMlal:
1414 s += "__a + " + MangleName("vmull", typestr, ClassS) + "(__b, __c);";
1415 break;
1416 case OpMlsN:
1417 s += "__a - (__b * " + Duplicate(nElts, typestr, "__c") + ");";
1418 break;
1419 case OpMlsLane:
1420 s += "__a - (__b * " + SplatLane(nElts, "__c", "__d") + ");";
1421 break;
1422 case OpMls:
1423 s += "__a - (__b * __c);";
1424 break;
1425 case OpMlslN:
1426 s += "__a - " + MangleName("vmull", typestr, ClassS) + "(__b, " +
1427 Duplicate(nElts, typestr, "__c") + ");";
1428 break;
1429 case OpMlslLane:
1430 s += "__a - " + MangleName("vmull", typestr, ClassS) + "(__b, " +
1431 SplatLane(nElts, "__c", "__d") + ");";
1432 break;
1433 case OpMlsl:
1434 s += "__a - " + MangleName("vmull", typestr, ClassS) + "(__b, __c);";
1435 break;
1436 case OpQDMullLane:
1437 s += MangleName("vqdmull", typestr, ClassS) + "(__a, " +
1438 SplatLane(nElts, "__b", "__c") + ");";
1439 break;
1440 case OpQDMlalLane:
1441 s += MangleName("vqdmlal", typestr, ClassS) + "(__a, __b, " +
1442 SplatLane(nElts, "__c", "__d") + ");";
1443 break;
1444 case OpQDMlslLane:
1445 s += MangleName("vqdmlsl", typestr, ClassS) + "(__a, __b, " +
1446 SplatLane(nElts, "__c", "__d") + ");";
1447 break;
1448 case OpQDMulhLane:
1449 s += MangleName("vqdmulh", typestr, ClassS) + "(__a, " +
1450 SplatLane(nElts, "__b", "__c") + ");";
1451 break;
1452 case OpQRDMulhLane:
1453 s += MangleName("vqrdmulh", typestr, ClassS) + "(__a, " +
1454 SplatLane(nElts, "__b", "__c") + ");";
1455 break;
1456 case OpEq:
1457 s += "(" + ts + ")(__a == __b);";
1458 break;
1459 case OpGe:
1460 s += "(" + ts + ")(__a >= __b);";
1461 break;
1462 case OpLe:
1463 s += "(" + ts + ")(__a <= __b);";
1464 break;
1465 case OpGt:
1466 s += "(" + ts + ")(__a > __b);";
1467 break;
1468 case OpLt:
1469 s += "(" + ts + ")(__a < __b);";
1470 break;
1471 case OpNeg:
1472 s += " -__a;";
1473 break;
1474 case OpNot:
1475 s += " ~__a;";
1476 break;
1477 case OpAnd:
1478 s += "__a & __b;";
1479 break;
1480 case OpOr:
1481 s += "__a | __b;";
1482 break;
1483 case OpXor:
1484 s += "__a ^ __b;";
1485 break;
1486 case OpAndNot:
1487 s += "__a & ~__b;";
1488 break;
1489 case OpOrNot:
1490 s += "__a | ~__b;";
1491 break;
1492 case OpCast:
1493 s += "(" + ts + ")__a;";
1494 break;
1495 case OpConcat:
1496 s += "(" + ts + ")__builtin_shufflevector((int64x1_t)__a";
1497 s += ", (int64x1_t)__b, 0, 1);";
1498 break;
1499 case OpHi:
Jim Grosbachcd765392013-05-15 02:40:04 +00001500 // nElts is for the result vector, so the source is twice that number.
1501 s += "__builtin_shufflevector(__a, __a";
1502 for (unsigned i = nElts; i < nElts * 2; ++i)
1503 s += ", " + utostr(i);
1504 s+= ");";
Peter Collingbourne51d77772011-10-06 13:03:08 +00001505 break;
1506 case OpLo:
Jim Grosbachcd765392013-05-15 02:40:04 +00001507 s += "__builtin_shufflevector(__a, __a";
1508 for (unsigned i = 0; i < nElts; ++i)
1509 s += ", " + utostr(i);
1510 s+= ");";
Peter Collingbourne51d77772011-10-06 13:03:08 +00001511 break;
1512 case OpDup:
1513 s += Duplicate(nElts, typestr, "__a") + ";";
1514 break;
1515 case OpDupLane:
1516 s += SplatLane(nElts, "__a", "__b") + ";";
1517 break;
1518 case OpSelect:
1519 // ((0 & 1) | (~0 & 2))
1520 s += "(" + ts + ")";
1521 ts = TypeString(proto[1], typestr);
1522 s += "((__a & (" + ts + ")__b) | ";
1523 s += "(~__a & (" + ts + ")__c));";
1524 break;
1525 case OpRev16:
1526 s += "__builtin_shufflevector(__a, __a";
1527 for (unsigned i = 2; i <= nElts; i += 2)
1528 for (unsigned j = 0; j != 2; ++j)
1529 s += ", " + utostr(i - j - 1);
1530 s += ");";
1531 break;
1532 case OpRev32: {
1533 unsigned WordElts = nElts >> (1 + (int)quad);
1534 s += "__builtin_shufflevector(__a, __a";
1535 for (unsigned i = WordElts; i <= nElts; i += WordElts)
1536 for (unsigned j = 0; j != WordElts; ++j)
1537 s += ", " + utostr(i - j - 1);
1538 s += ");";
1539 break;
1540 }
1541 case OpRev64: {
1542 unsigned DblWordElts = nElts >> (int)quad;
1543 s += "__builtin_shufflevector(__a, __a";
1544 for (unsigned i = DblWordElts; i <= nElts; i += DblWordElts)
1545 for (unsigned j = 0; j != DblWordElts; ++j)
1546 s += ", " + utostr(i - j - 1);
1547 s += ");";
1548 break;
1549 }
1550 case OpAbdl: {
1551 std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)";
1552 if (typestr[0] != 'U') {
1553 // vabd results are always unsigned and must be zero-extended.
1554 std::string utype = "U" + typestr.str();
1555 s += "(" + TypeString(proto[0], typestr) + ")";
1556 abd = "(" + TypeString('d', utype) + ")" + abd;
1557 s += Extend(utype, abd) + ";";
1558 } else {
1559 s += Extend(typestr, abd) + ";";
1560 }
1561 break;
1562 }
1563 case OpAba:
1564 s += "__a + " + MangleName("vabd", typestr, ClassS) + "(__b, __c);";
1565 break;
1566 case OpAbal: {
1567 s += "__a + ";
1568 std::string abd = MangleName("vabd", typestr, ClassS) + "(__b, __c)";
1569 if (typestr[0] != 'U') {
1570 // vabd results are always unsigned and must be zero-extended.
1571 std::string utype = "U" + typestr.str();
1572 s += "(" + TypeString(proto[0], typestr) + ")";
1573 abd = "(" + TypeString('d', utype) + ")" + abd;
1574 s += Extend(utype, abd) + ";";
1575 } else {
1576 s += Extend(typestr, abd) + ";";
1577 }
1578 break;
1579 }
Tim Northoverb793f0d2013-08-01 09:23:19 +00001580 case OpDiv:
1581 s += "__a / __b;";
1582 break;
Hao Liu912502b2013-09-04 09:29:13 +00001583 case OpMovlHi: {
1584 s = TypeString(proto[1], typestr.drop_front()) + " __a1 = " +
1585 MangleName("vget_high", typestr, ClassS) + "(__a);\n " + s;
1586 s += "(" + ts + ")" + MangleName("vshll_n", typestr, ClassS);
1587 s += "(__a1, 0);";
1588 break;
1589 }
1590 case OpLongHi: {
1591 // Another local variable __a1 is needed for calling a Macro,
1592 // or using __a will have naming conflict when Macro expanding.
1593 s += TypeString(proto[1], typestr.drop_front()) + " __a1 = " +
1594 MangleName("vget_high", typestr, ClassS) + "(__a); \\\n";
1595 s += " (" + ts + ")" + MangleName(RemoveHigh(name), typestr, ClassS) +
1596 "(__a1, __b);";
1597 break;
1598 }
1599 case OpNarrowHi: {
1600 s += "(" + ts + ")" + MangleName("vcombine", typestr, ClassS) + "(__a, " +
1601 MangleName(RemoveHigh(name), typestr, ClassS) + "(__b, __c));";
1602 break;
1603 }
Peter Collingbourne51d77772011-10-06 13:03:08 +00001604 default:
Joerg Sonnenberger38859ee2012-10-25 16:37:08 +00001605 PrintFatalError("unknown OpKind!");
Peter Collingbourne51d77772011-10-06 13:03:08 +00001606 }
1607 return s;
1608}
1609
1610static unsigned GetNeonEnum(const std::string &proto, StringRef typestr) {
1611 unsigned mod = proto[0];
Peter Collingbourne51d77772011-10-06 13:03:08 +00001612
1613 if (mod == 'v' || mod == 'f')
1614 mod = proto[1];
1615
1616 bool quad = false;
1617 bool poly = false;
1618 bool usgn = false;
1619 bool scal = false;
1620 bool cnst = false;
1621 bool pntr = false;
1622
1623 // Base type to get the type string for.
1624 char type = ClassifyType(typestr, quad, poly, usgn);
1625
1626 // Based on the modifying character, change the type and width if necessary.
1627 type = ModType(mod, type, quad, poly, usgn, scal, cnst, pntr);
1628
Bob Wilsonda95f732011-11-08 01:16:11 +00001629 NeonTypeFlags::EltType ET;
Peter Collingbourne51d77772011-10-06 13:03:08 +00001630 switch (type) {
1631 case 'c':
Bob Wilsonda95f732011-11-08 01:16:11 +00001632 ET = poly ? NeonTypeFlags::Poly8 : NeonTypeFlags::Int8;
Peter Collingbourne51d77772011-10-06 13:03:08 +00001633 break;
1634 case 's':
Bob Wilsonda95f732011-11-08 01:16:11 +00001635 ET = poly ? NeonTypeFlags::Poly16 : NeonTypeFlags::Int16;
Peter Collingbourne51d77772011-10-06 13:03:08 +00001636 break;
1637 case 'i':
Bob Wilsonda95f732011-11-08 01:16:11 +00001638 ET = NeonTypeFlags::Int32;
Peter Collingbourne51d77772011-10-06 13:03:08 +00001639 break;
1640 case 'l':
Bob Wilsonda95f732011-11-08 01:16:11 +00001641 ET = NeonTypeFlags::Int64;
Peter Collingbourne51d77772011-10-06 13:03:08 +00001642 break;
1643 case 'h':
Bob Wilsonda95f732011-11-08 01:16:11 +00001644 ET = NeonTypeFlags::Float16;
Peter Collingbourne51d77772011-10-06 13:03:08 +00001645 break;
1646 case 'f':
Bob Wilsonda95f732011-11-08 01:16:11 +00001647 ET = NeonTypeFlags::Float32;
Peter Collingbourne51d77772011-10-06 13:03:08 +00001648 break;
Tim Northoverb793f0d2013-08-01 09:23:19 +00001649 case 'd':
1650 ET = NeonTypeFlags::Float64;
1651 break;
Peter Collingbourne51d77772011-10-06 13:03:08 +00001652 default:
Joerg Sonnenberger38859ee2012-10-25 16:37:08 +00001653 PrintFatalError("unhandled type!");
Peter Collingbourne51d77772011-10-06 13:03:08 +00001654 }
Bob Wilsonda95f732011-11-08 01:16:11 +00001655 NeonTypeFlags Flags(ET, usgn, quad && proto[1] != 'g');
1656 return Flags.getFlags();
Peter Collingbourne51d77772011-10-06 13:03:08 +00001657}
1658
1659// Generate the definition for this intrinsic, e.g. __builtin_neon_cls(a)
1660static std::string GenBuiltin(const std::string &name, const std::string &proto,
1661 StringRef typestr, ClassKind ck) {
1662 std::string s;
1663
1664 // If this builtin returns a struct 2, 3, or 4 vectors, pass it as an implicit
1665 // sret-like argument.
1666 bool sret = (proto[0] >= '2' && proto[0] <= '4');
1667
1668 bool define = UseMacro(proto);
1669
1670 // Check if the prototype has a scalar operand with the type of the vector
1671 // elements. If not, bitcasting the args will take care of arg checking.
1672 // The actual signedness etc. will be taken care of with special enums.
1673 if (proto.find('s') == std::string::npos)
1674 ck = ClassB;
1675
1676 if (proto[0] != 'v') {
1677 std::string ts = TypeString(proto[0], typestr);
1678
1679 if (define) {
1680 if (sret)
1681 s += ts + " r; ";
1682 else
1683 s += "(" + ts + ")";
1684 } else if (sret) {
1685 s += ts + " r; ";
1686 } else {
1687 s += "return (" + ts + ")";
1688 }
1689 }
1690
1691 bool splat = proto.find('a') != std::string::npos;
1692
1693 s += "__builtin_neon_";
1694 if (splat) {
1695 // Call the non-splat builtin: chop off the "_n" suffix from the name.
1696 std::string vname(name, 0, name.size()-2);
1697 s += MangleName(vname, typestr, ck);
1698 } else {
1699 s += MangleName(name, typestr, ck);
1700 }
1701 s += "(";
1702
1703 // Pass the address of the return variable as the first argument to sret-like
1704 // builtins.
1705 if (sret)
1706 s += "&r, ";
1707
1708 char arg = 'a';
1709 for (unsigned i = 1, e = proto.size(); i != e; ++i, ++arg) {
1710 std::string args = std::string(&arg, 1);
1711
1712 // Use the local temporaries instead of the macro arguments.
1713 args = "__" + args;
1714
1715 bool argQuad = false;
1716 bool argPoly = false;
1717 bool argUsgn = false;
1718 bool argScalar = false;
1719 bool dummy = false;
1720 char argType = ClassifyType(typestr, argQuad, argPoly, argUsgn);
1721 argType = ModType(proto[i], argType, argQuad, argPoly, argUsgn, argScalar,
1722 dummy, dummy);
1723
1724 // Handle multiple-vector values specially, emitting each subvector as an
1725 // argument to the __builtin.
1726 if (proto[i] >= '2' && proto[i] <= '4') {
1727 // Check if an explicit cast is needed.
1728 if (argType != 'c' || argPoly || argUsgn)
1729 args = (argQuad ? "(int8x16_t)" : "(int8x8_t)") + args;
1730
1731 for (unsigned vi = 0, ve = proto[i] - '0'; vi != ve; ++vi) {
1732 s += args + ".val[" + utostr(vi) + "]";
1733 if ((vi + 1) < ve)
1734 s += ", ";
1735 }
1736 if ((i + 1) < e)
1737 s += ", ";
1738
1739 continue;
1740 }
1741
1742 if (splat && (i + 1) == e)
1743 args = Duplicate(GetNumElements(typestr, argQuad), typestr, args);
1744
1745 // Check if an explicit cast is needed.
1746 if ((splat || !argScalar) &&
1747 ((ck == ClassB && argType != 'c') || argPoly || argUsgn)) {
1748 std::string argTypeStr = "c";
1749 if (ck != ClassB)
1750 argTypeStr = argType;
1751 if (argQuad)
1752 argTypeStr = "Q" + argTypeStr;
1753 args = "(" + TypeString('d', argTypeStr) + ")" + args;
1754 }
1755
1756 s += args;
1757 if ((i + 1) < e)
1758 s += ", ";
1759 }
1760
1761 // Extra constant integer to hold type class enum for this function, e.g. s8
1762 if (ck == ClassB)
1763 s += ", " + utostr(GetNeonEnum(proto, typestr));
1764
1765 s += ");";
1766
1767 if (proto[0] != 'v' && sret) {
1768 if (define)
1769 s += " r;";
1770 else
1771 s += " return r;";
1772 }
1773 return s;
1774}
1775
1776static std::string GenBuiltinDef(const std::string &name,
1777 const std::string &proto,
1778 StringRef typestr, ClassKind ck) {
1779 std::string s("BUILTIN(__builtin_neon_");
1780
1781 // If all types are the same size, bitcasting the args will take care
1782 // of arg checking. The actual signedness etc. will be taken care of with
1783 // special enums.
1784 if (proto.find('s') == std::string::npos)
1785 ck = ClassB;
1786
1787 s += MangleName(name, typestr, ck);
1788 s += ", \"";
1789
1790 for (unsigned i = 0, e = proto.size(); i != e; ++i)
1791 s += BuiltinTypeString(proto[i], typestr, ck, i == 0);
1792
1793 // Extra constant integer to hold type class enum for this function, e.g. s8
1794 if (ck == ClassB)
1795 s += "i";
1796
1797 s += "\", \"n\")";
1798 return s;
1799}
1800
1801static std::string GenIntrinsic(const std::string &name,
1802 const std::string &proto,
1803 StringRef outTypeStr, StringRef inTypeStr,
1804 OpKind kind, ClassKind classKind) {
1805 assert(!proto.empty() && "");
Jim Grosbach667381b2012-05-09 18:17:30 +00001806 bool define = UseMacro(proto) && kind != OpUnavailable;
Peter Collingbourne51d77772011-10-06 13:03:08 +00001807 std::string s;
1808
1809 // static always inline + return type
1810 if (define)
1811 s += "#define ";
1812 else
1813 s += "__ai " + TypeString(proto[0], outTypeStr) + " ";
1814
1815 // Function name with type suffix
1816 std::string mangledName = MangleName(name, outTypeStr, ClassS);
1817 if (outTypeStr != inTypeStr) {
1818 // If the input type is different (e.g., for vreinterpret), append a suffix
1819 // for the input type. String off a "Q" (quad) prefix so that MangleName
1820 // does not insert another "q" in the name.
1821 unsigned typeStrOff = (inTypeStr[0] == 'Q' ? 1 : 0);
1822 StringRef inTypeNoQuad = inTypeStr.substr(typeStrOff);
1823 mangledName = MangleName(mangledName, inTypeNoQuad, ClassS);
1824 }
1825 s += mangledName;
1826
1827 // Function arguments
1828 s += GenArgs(proto, inTypeStr);
1829
1830 // Definition.
1831 if (define) {
1832 s += " __extension__ ({ \\\n ";
1833 s += GenMacroLocals(proto, inTypeStr);
Jim Grosbach667381b2012-05-09 18:17:30 +00001834 } else if (kind == OpUnavailable) {
1835 s += " __attribute__((unavailable));\n";
1836 return s;
1837 } else
Jim Grosbach66981c72012-08-03 17:30:46 +00001838 s += " {\n ";
Peter Collingbourne51d77772011-10-06 13:03:08 +00001839
1840 if (kind != OpNone)
Hao Liu912502b2013-09-04 09:29:13 +00001841 s += GenOpString(name, kind, proto, outTypeStr);
Peter Collingbourne51d77772011-10-06 13:03:08 +00001842 else
1843 s += GenBuiltin(name, proto, outTypeStr, classKind);
1844 if (define)
1845 s += " })";
1846 else
1847 s += " }";
1848 s += "\n";
1849 return s;
1850}
1851
1852/// run - Read the records in arm_neon.td and output arm_neon.h. arm_neon.h
1853/// is comprised of type definitions and function declarations.
1854void NeonEmitter::run(raw_ostream &OS) {
1855 OS <<
1856 "/*===---- arm_neon.h - ARM Neon intrinsics ------------------------------"
1857 "---===\n"
1858 " *\n"
1859 " * Permission is hereby granted, free of charge, to any person obtaining "
1860 "a copy\n"
1861 " * of this software and associated documentation files (the \"Software\"),"
1862 " to deal\n"
1863 " * in the Software without restriction, including without limitation the "
1864 "rights\n"
1865 " * to use, copy, modify, merge, publish, distribute, sublicense, "
1866 "and/or sell\n"
1867 " * copies of the Software, and to permit persons to whom the Software is\n"
1868 " * furnished to do so, subject to the following conditions:\n"
1869 " *\n"
1870 " * The above copyright notice and this permission notice shall be "
1871 "included in\n"
1872 " * all copies or substantial portions of the Software.\n"
1873 " *\n"
1874 " * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, "
1875 "EXPRESS OR\n"
1876 " * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF "
1877 "MERCHANTABILITY,\n"
1878 " * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT "
1879 "SHALL THE\n"
1880 " * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR "
1881 "OTHER\n"
1882 " * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, "
1883 "ARISING FROM,\n"
1884 " * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER "
1885 "DEALINGS IN\n"
1886 " * THE SOFTWARE.\n"
1887 " *\n"
1888 " *===--------------------------------------------------------------------"
1889 "---===\n"
1890 " */\n\n";
1891
1892 OS << "#ifndef __ARM_NEON_H\n";
1893 OS << "#define __ARM_NEON_H\n\n";
1894
Tim Northoverb793f0d2013-08-01 09:23:19 +00001895 OS << "#if !defined(__ARM_NEON__) && !defined(__AARCH_FEATURE_ADVSIMD)\n";
Peter Collingbourne51d77772011-10-06 13:03:08 +00001896 OS << "#error \"NEON support not enabled\"\n";
1897 OS << "#endif\n\n";
1898
1899 OS << "#include <stdint.h>\n\n";
1900
1901 // Emit NEON-specific scalar typedefs.
1902 OS << "typedef float float32_t;\n";
Tim Northoverb793f0d2013-08-01 09:23:19 +00001903 OS << "typedef __fp16 float16_t;\n";
1904
1905 OS << "#ifdef __aarch64__\n";
1906 OS << "typedef double float64_t;\n";
1907 OS << "#endif\n\n";
1908
1909 // For now, signedness of polynomial types depends on target
1910 OS << "#ifdef __aarch64__\n";
1911 OS << "typedef uint8_t poly8_t;\n";
1912 OS << "typedef uint16_t poly16_t;\n";
1913 OS << "#else\n";
Peter Collingbourne51d77772011-10-06 13:03:08 +00001914 OS << "typedef int8_t poly8_t;\n";
1915 OS << "typedef int16_t poly16_t;\n";
Tim Northoverb793f0d2013-08-01 09:23:19 +00001916 OS << "#endif\n";
Peter Collingbourne51d77772011-10-06 13:03:08 +00001917
1918 // Emit Neon vector typedefs.
Tim Northoverb793f0d2013-08-01 09:23:19 +00001919 std::string TypedefTypes(
1920 "cQcsQsiQilQlUcQUcUsQUsUiQUiUlQUlhQhfQfQdPcQPcPsQPs");
Peter Collingbourne51d77772011-10-06 13:03:08 +00001921 SmallVector<StringRef, 24> TDTypeVec;
1922 ParseTypes(0, TypedefTypes, TDTypeVec);
1923
1924 // Emit vector typedefs.
1925 for (unsigned i = 0, e = TDTypeVec.size(); i != e; ++i) {
1926 bool dummy, quad = false, poly = false;
Tim Northoverb793f0d2013-08-01 09:23:19 +00001927 char type = ClassifyType(TDTypeVec[i], quad, poly, dummy);
1928 bool isA64 = false;
1929
1930 if (type == 'd' && quad)
1931 isA64 = true;
1932
1933 if (isA64)
1934 OS << "#ifdef __aarch64__\n";
1935
Peter Collingbourne51d77772011-10-06 13:03:08 +00001936 if (poly)
1937 OS << "typedef __attribute__((neon_polyvector_type(";
1938 else
1939 OS << "typedef __attribute__((neon_vector_type(";
1940
1941 unsigned nElts = GetNumElements(TDTypeVec[i], quad);
1942 OS << utostr(nElts) << "))) ";
1943 if (nElts < 10)
1944 OS << " ";
1945
1946 OS << TypeString('s', TDTypeVec[i]);
1947 OS << " " << TypeString('d', TDTypeVec[i]) << ";\n";
Tim Northoverb793f0d2013-08-01 09:23:19 +00001948
1949 if (isA64)
1950 OS << "#endif\n";
Peter Collingbourne51d77772011-10-06 13:03:08 +00001951 }
1952 OS << "\n";
1953
1954 // Emit struct typedefs.
1955 for (unsigned vi = 2; vi != 5; ++vi) {
1956 for (unsigned i = 0, e = TDTypeVec.size(); i != e; ++i) {
Tim Northoverb793f0d2013-08-01 09:23:19 +00001957 bool dummy, quad = false, poly = false;
1958 char type = ClassifyType(TDTypeVec[i], quad, poly, dummy);
1959 bool isA64 = false;
1960
1961 if (type == 'd' && quad)
1962 isA64 = true;
1963
1964 if (isA64)
1965 OS << "#ifdef __aarch64__\n";
1966
Peter Collingbourne51d77772011-10-06 13:03:08 +00001967 std::string ts = TypeString('d', TDTypeVec[i]);
1968 std::string vs = TypeString('0' + vi, TDTypeVec[i]);
1969 OS << "typedef struct " << vs << " {\n";
1970 OS << " " << ts << " val";
1971 OS << "[" << utostr(vi) << "]";
1972 OS << ";\n} ";
Tim Northoverb793f0d2013-08-01 09:23:19 +00001973 OS << vs << ";\n";
1974
1975 if (isA64)
1976 OS << "#endif\n";
1977
1978 OS << "\n";
Peter Collingbourne51d77772011-10-06 13:03:08 +00001979 }
1980 }
1981
Bob Wilson1e8058f2013-04-12 20:17:20 +00001982 OS<<"#define __ai static inline __attribute__((__always_inline__, __nodebug__))\n\n";
Peter Collingbourne51d77772011-10-06 13:03:08 +00001983
1984 std::vector<Record*> RV = Records.getAllDerivedDefinitions("Inst");
1985
Tim Northoverb793f0d2013-08-01 09:23:19 +00001986 StringMap<ClassKind> EmittedMap;
1987
Peter Collingbourne51d77772011-10-06 13:03:08 +00001988 // Emit vmovl, vmull and vabd intrinsics first so they can be used by other
1989 // intrinsics. (Some of the saturating multiply instructions are also
1990 // used to implement the corresponding "_lane" variants, but tablegen
1991 // sorts the records into alphabetical order so that the "_lane" variants
1992 // come after the intrinsics they use.)
Tim Northoverb793f0d2013-08-01 09:23:19 +00001993 emitIntrinsic(OS, Records.getDef("VMOVL"), EmittedMap);
1994 emitIntrinsic(OS, Records.getDef("VMULL"), EmittedMap);
1995 emitIntrinsic(OS, Records.getDef("VABD"), EmittedMap);
1996
1997 // ARM intrinsics must be emitted before AArch64 intrinsics to ensure
1998 // common intrinsics appear only once in the output stream.
1999 // The check for uniquiness is done in emitIntrinsic.
2000 // Emit ARM intrinsics.
2001 for (unsigned i = 0, e = RV.size(); i != e; ++i) {
2002 Record *R = RV[i];
2003
2004 // Skip AArch64 intrinsics; they will be emitted at the end.
2005 bool isA64 = R->getValueAsBit("isA64");
2006 if (isA64)
2007 continue;
2008
2009 if (R->getName() != "VMOVL" && R->getName() != "VMULL" &&
2010 R->getName() != "VABD")
2011 emitIntrinsic(OS, R, EmittedMap);
2012 }
2013
2014 // Emit AArch64-specific intrinsics.
2015 OS << "#ifdef __aarch64__\n";
Peter Collingbourne51d77772011-10-06 13:03:08 +00002016
2017 for (unsigned i = 0, e = RV.size(); i != e; ++i) {
2018 Record *R = RV[i];
Tim Northoverb793f0d2013-08-01 09:23:19 +00002019
2020 // Skip ARM intrinsics already included above.
2021 bool isA64 = R->getValueAsBit("isA64");
2022 if (!isA64)
2023 continue;
2024
2025 emitIntrinsic(OS, R, EmittedMap);
Peter Collingbourne51d77772011-10-06 13:03:08 +00002026 }
2027
Tim Northoverb793f0d2013-08-01 09:23:19 +00002028 OS << "#endif\n\n";
2029
Peter Collingbourne51d77772011-10-06 13:03:08 +00002030 OS << "#undef __ai\n\n";
2031 OS << "#endif /* __ARM_NEON_H */\n";
2032}
2033
2034/// emitIntrinsic - Write out the arm_neon.h header file definitions for the
Tim Northoverb793f0d2013-08-01 09:23:19 +00002035/// intrinsics specified by record R checking for intrinsic uniqueness.
2036void NeonEmitter::emitIntrinsic(raw_ostream &OS, Record *R,
2037 StringMap<ClassKind> &EmittedMap) {
Peter Collingbourne51d77772011-10-06 13:03:08 +00002038 std::string name = R->getValueAsString("Name");
2039 std::string Proto = R->getValueAsString("Prototype");
2040 std::string Types = R->getValueAsString("Types");
2041
2042 SmallVector<StringRef, 16> TypeVec;
2043 ParseTypes(R, Types, TypeVec);
2044
2045 OpKind kind = OpMap[R->getValueAsDef("Operand")->getName()];
2046
2047 ClassKind classKind = ClassNone;
2048 if (R->getSuperClasses().size() >= 2)
2049 classKind = ClassMap[R->getSuperClasses()[1]];
2050 if (classKind == ClassNone && kind == OpNone)
Joerg Sonnenberger38859ee2012-10-25 16:37:08 +00002051 PrintFatalError(R->getLoc(), "Builtin has no class kind");
Peter Collingbourne51d77772011-10-06 13:03:08 +00002052
2053 for (unsigned ti = 0, te = TypeVec.size(); ti != te; ++ti) {
2054 if (kind == OpReinterpret) {
2055 bool outQuad = false;
2056 bool dummy = false;
2057 (void)ClassifyType(TypeVec[ti], outQuad, dummy, dummy);
2058 for (unsigned srcti = 0, srcte = TypeVec.size();
2059 srcti != srcte; ++srcti) {
2060 bool inQuad = false;
2061 (void)ClassifyType(TypeVec[srcti], inQuad, dummy, dummy);
2062 if (srcti == ti || inQuad != outQuad)
2063 continue;
Tim Northoverb793f0d2013-08-01 09:23:19 +00002064 std::string s = GenIntrinsic(name, Proto, TypeVec[ti], TypeVec[srcti],
2065 OpCast, ClassS);
2066 if (EmittedMap.count(s))
2067 continue;
2068 EmittedMap[s] = ClassS;
2069 OS << s;
Peter Collingbourne51d77772011-10-06 13:03:08 +00002070 }
2071 } else {
Tim Northoverb793f0d2013-08-01 09:23:19 +00002072 std::string s =
2073 GenIntrinsic(name, Proto, TypeVec[ti], TypeVec[ti], kind, classKind);
2074 if (EmittedMap.count(s))
2075 continue;
2076 EmittedMap[s] = classKind;
2077 OS << s;
Peter Collingbourne51d77772011-10-06 13:03:08 +00002078 }
2079 }
2080 OS << "\n";
2081}
2082
2083static unsigned RangeFromType(const char mod, StringRef typestr) {
2084 // base type to get the type string for.
2085 bool quad = false, dummy = false;
2086 char type = ClassifyType(typestr, quad, dummy, dummy);
2087 type = ModType(mod, type, quad, dummy, dummy, dummy, dummy, dummy);
2088
2089 switch (type) {
2090 case 'c':
2091 return (8 << (int)quad) - 1;
2092 case 'h':
2093 case 's':
2094 return (4 << (int)quad) - 1;
2095 case 'f':
2096 case 'i':
2097 return (2 << (int)quad) - 1;
2098 case 'l':
2099 return (1 << (int)quad) - 1;
2100 default:
Joerg Sonnenberger38859ee2012-10-25 16:37:08 +00002101 PrintFatalError("unhandled type!");
Peter Collingbourne51d77772011-10-06 13:03:08 +00002102 }
Peter Collingbourne51d77772011-10-06 13:03:08 +00002103}
2104
Tim Northoverb793f0d2013-08-01 09:23:19 +00002105/// Generate the ARM and AArch64 intrinsic range checking code for
2106/// shift/lane immediates, checking for unique declarations.
2107void
2108NeonEmitter::genIntrinsicRangeCheckCode(raw_ostream &OS,
2109 StringMap<ClassKind> &A64IntrinsicMap,
2110 bool isA64RangeCheck) {
2111 std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst");
Peter Collingbourne51d77772011-10-06 13:03:08 +00002112 StringMap<OpKind> EmittedMap;
2113
Tim Northoverb793f0d2013-08-01 09:23:19 +00002114 // Generate the intrinsic range checking code for shift/lane immediates.
2115 if (isA64RangeCheck)
2116 OS << "#ifdef GET_NEON_AARCH64_IMMEDIATE_CHECK\n";
2117 else
2118 OS << "#ifdef GET_NEON_IMMEDIATE_CHECK\n";
2119
Peter Collingbourne51d77772011-10-06 13:03:08 +00002120 for (unsigned i = 0, e = RV.size(); i != e; ++i) {
2121 Record *R = RV[i];
Tim Northoverb793f0d2013-08-01 09:23:19 +00002122
Peter Collingbourne51d77772011-10-06 13:03:08 +00002123 OpKind k = OpMap[R->getValueAsDef("Operand")->getName()];
2124 if (k != OpNone)
2125 continue;
2126
Tim Northoverb793f0d2013-08-01 09:23:19 +00002127 std::string name = R->getValueAsString("Name");
Peter Collingbourne51d77772011-10-06 13:03:08 +00002128 std::string Proto = R->getValueAsString("Prototype");
Tim Northoverb793f0d2013-08-01 09:23:19 +00002129 std::string Types = R->getValueAsString("Types");
Kevin Qin944f09f2013-08-29 07:55:15 +00002130 std::string Rename = name + "@" + Proto;
Peter Collingbourne51d77772011-10-06 13:03:08 +00002131
2132 // Functions with 'a' (the splat code) in the type prototype should not get
2133 // their own builtin as they use the non-splat variant.
2134 if (Proto.find('a') != std::string::npos)
2135 continue;
2136
Tim Northoverb793f0d2013-08-01 09:23:19 +00002137 // Functions which do not have an immediate do not need to have range
2138 // checking code emitted.
2139 size_t immPos = Proto.find('i');
2140 if (immPos == std::string::npos)
2141 continue;
2142
Peter Collingbourne51d77772011-10-06 13:03:08 +00002143 SmallVector<StringRef, 16> TypeVec;
2144 ParseTypes(R, Types, TypeVec);
2145
2146 if (R->getSuperClasses().size() < 2)
Joerg Sonnenberger38859ee2012-10-25 16:37:08 +00002147 PrintFatalError(R->getLoc(), "Builtin has no class kind");
Peter Collingbourne51d77772011-10-06 13:03:08 +00002148
Peter Collingbourne51d77772011-10-06 13:03:08 +00002149 ClassKind ck = ClassMap[R->getSuperClasses()[1]];
2150
Tim Northoverb793f0d2013-08-01 09:23:19 +00002151 // Do not include AArch64 range checks if not generating code for AArch64.
2152 bool isA64 = R->getValueAsBit("isA64");
2153 if (!isA64RangeCheck && isA64)
2154 continue;
Peter Collingbourne51d77772011-10-06 13:03:08 +00002155
Tim Northoverb793f0d2013-08-01 09:23:19 +00002156 // Include ARM range checks in AArch64 but only if ARM intrinsics are not
2157 // redefined by AArch64 to handle new types.
Kevin Qin944f09f2013-08-29 07:55:15 +00002158 if (isA64RangeCheck && !isA64 && A64IntrinsicMap.count(Rename)) {
2159 ClassKind &A64CK = A64IntrinsicMap[Rename];
Tim Northoverb793f0d2013-08-01 09:23:19 +00002160 if (A64CK == ck && ck != ClassNone)
2161 continue;
2162 }
2163
2164 for (unsigned ti = 0, te = TypeVec.size(); ti != te; ++ti) {
2165 std::string namestr, shiftstr, rangestr;
2166
2167 if (R->getValueAsBit("isVCVT_N")) {
2168 // VCVT between floating- and fixed-point values takes an immediate
Hao Liu912502b2013-09-04 09:29:13 +00002169 // in the range [1, 32] for f32, or [1, 64] for f64.
Tim Northoverb793f0d2013-08-01 09:23:19 +00002170 ck = ClassB;
Hao Liu912502b2013-09-04 09:29:13 +00002171 if (name.find("32") != std::string::npos)
2172 rangestr = "l = 1; u = 31"; // upper bound = l + u
2173 else if (name.find("64") != std::string::npos)
2174 rangestr = "l = 1; u = 63";
2175 else
2176 PrintFatalError(R->getLoc(),
2177 "Fixed point convert name should contains \"32\" or \"64\"");
Tim Northoverb793f0d2013-08-01 09:23:19 +00002178 } else if (Proto.find('s') == std::string::npos) {
2179 // Builtins which are overloaded by type will need to have their upper
2180 // bound computed at Sema time based on the type constant.
2181 ck = ClassB;
2182 if (R->getValueAsBit("isShift")) {
2183 shiftstr = ", true";
2184
2185 // Right shifts have an 'r' in the name, left shifts do not.
2186 if (name.find('r') != std::string::npos)
2187 rangestr = "l = 1; ";
2188 }
2189 rangestr += "u = RFT(TV" + shiftstr + ")";
2190 } else {
2191 // The immediate generally refers to a lane in the preceding argument.
2192 assert(immPos > 0 && "unexpected immediate operand");
2193 rangestr =
2194 "u = " + utostr(RangeFromType(Proto[immPos - 1], TypeVec[ti]));
2195 }
2196 // Make sure cases appear only once by uniquing them in a string map.
2197 namestr = MangleName(name, TypeVec[ti], ck);
2198 if (EmittedMap.count(namestr))
2199 continue;
2200 EmittedMap[namestr] = OpNone;
2201
2202 // Calculate the index of the immediate that should be range checked.
2203 unsigned immidx = 0;
2204
2205 // Builtins that return a struct of multiple vectors have an extra
2206 // leading arg for the struct return.
2207 if (Proto[0] >= '2' && Proto[0] <= '4')
2208 ++immidx;
2209
2210 // Add one to the index for each argument until we reach the immediate
2211 // to be checked. Structs of vectors are passed as multiple arguments.
2212 for (unsigned ii = 1, ie = Proto.size(); ii != ie; ++ii) {
2213 switch (Proto[ii]) {
2214 default:
2215 immidx += 1;
2216 break;
2217 case '2':
2218 immidx += 2;
2219 break;
2220 case '3':
2221 immidx += 3;
2222 break;
2223 case '4':
2224 immidx += 4;
2225 break;
2226 case 'i':
2227 ie = ii + 1;
2228 break;
2229 }
2230 }
2231 if (isA64RangeCheck)
2232 OS << "case AArch64::BI__builtin_neon_";
2233 else
2234 OS << "case ARM::BI__builtin_neon_";
2235 OS << MangleName(name, TypeVec[ti], ck) << ": i = " << immidx << "; "
2236 << rangestr << "; break;\n";
Peter Collingbourne51d77772011-10-06 13:03:08 +00002237 }
2238 }
2239 OS << "#endif\n\n";
Tim Northoverb793f0d2013-08-01 09:23:19 +00002240}
2241
2242/// Generate the ARM and AArch64 overloaded type checking code for
2243/// SemaChecking.cpp, checking for unique builtin declarations.
2244void
2245NeonEmitter::genOverloadTypeCheckCode(raw_ostream &OS,
2246 StringMap<ClassKind> &A64IntrinsicMap,
2247 bool isA64TypeCheck) {
2248 std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst");
2249 StringMap<OpKind> EmittedMap;
Peter Collingbourne51d77772011-10-06 13:03:08 +00002250
2251 // Generate the overloaded type checking code for SemaChecking.cpp
Tim Northoverb793f0d2013-08-01 09:23:19 +00002252 if (isA64TypeCheck)
2253 OS << "#ifdef GET_NEON_AARCH64_OVERLOAD_CHECK\n";
2254 else
2255 OS << "#ifdef GET_NEON_OVERLOAD_CHECK\n";
2256
Peter Collingbourne51d77772011-10-06 13:03:08 +00002257 for (unsigned i = 0, e = RV.size(); i != e; ++i) {
2258 Record *R = RV[i];
2259 OpKind k = OpMap[R->getValueAsDef("Operand")->getName()];
2260 if (k != OpNone)
2261 continue;
2262
2263 std::string Proto = R->getValueAsString("Prototype");
2264 std::string Types = R->getValueAsString("Types");
2265 std::string name = R->getValueAsString("Name");
Kevin Qin944f09f2013-08-29 07:55:15 +00002266 std::string Rename = name + "@" + Proto;
2267
Peter Collingbourne51d77772011-10-06 13:03:08 +00002268 // Functions with 'a' (the splat code) in the type prototype should not get
2269 // their own builtin as they use the non-splat variant.
2270 if (Proto.find('a') != std::string::npos)
2271 continue;
2272
2273 // Functions which have a scalar argument cannot be overloaded, no need to
2274 // check them if we are emitting the type checking code.
2275 if (Proto.find('s') != std::string::npos)
2276 continue;
2277
2278 SmallVector<StringRef, 16> TypeVec;
2279 ParseTypes(R, Types, TypeVec);
2280
2281 if (R->getSuperClasses().size() < 2)
Joerg Sonnenberger38859ee2012-10-25 16:37:08 +00002282 PrintFatalError(R->getLoc(), "Builtin has no class kind");
Peter Collingbourne51d77772011-10-06 13:03:08 +00002283
Tim Northoverb793f0d2013-08-01 09:23:19 +00002284 // Do not include AArch64 type checks if not generating code for AArch64.
2285 bool isA64 = R->getValueAsBit("isA64");
2286 if (!isA64TypeCheck && isA64)
2287 continue;
2288
2289 // Include ARM type check in AArch64 but only if ARM intrinsics
2290 // are not redefined in AArch64 to handle new types, e.g. "vabd" is a SIntr
2291 // redefined in AArch64 to handle an additional 2 x f64 type.
2292 ClassKind ck = ClassMap[R->getSuperClasses()[1]];
Kevin Qin944f09f2013-08-29 07:55:15 +00002293 if (isA64TypeCheck && !isA64 && A64IntrinsicMap.count(Rename)) {
2294 ClassKind &A64CK = A64IntrinsicMap[Rename];
Tim Northoverb793f0d2013-08-01 09:23:19 +00002295 if (A64CK == ck && ck != ClassNone)
2296 continue;
2297 }
2298
Peter Collingbourne51d77772011-10-06 13:03:08 +00002299 int si = -1, qi = -1;
Richard Smithf8ee6bc2012-08-14 01:28:02 +00002300 uint64_t mask = 0, qmask = 0;
Peter Collingbourne51d77772011-10-06 13:03:08 +00002301 for (unsigned ti = 0, te = TypeVec.size(); ti != te; ++ti) {
2302 // Generate the switch case(s) for this builtin for the type validation.
2303 bool quad = false, poly = false, usgn = false;
2304 (void) ClassifyType(TypeVec[ti], quad, poly, usgn);
2305
2306 if (quad) {
2307 qi = ti;
Richard Smithf8ee6bc2012-08-14 01:28:02 +00002308 qmask |= 1ULL << GetNeonEnum(Proto, TypeVec[ti]);
Peter Collingbourne51d77772011-10-06 13:03:08 +00002309 } else {
2310 si = ti;
Richard Smithf8ee6bc2012-08-14 01:28:02 +00002311 mask |= 1ULL << GetNeonEnum(Proto, TypeVec[ti]);
Peter Collingbourne51d77772011-10-06 13:03:08 +00002312 }
2313 }
Bob Wilson46482552011-11-16 21:32:23 +00002314
2315 // Check if the builtin function has a pointer or const pointer argument.
2316 int PtrArgNum = -1;
2317 bool HasConstPtr = false;
2318 for (unsigned arg = 1, arge = Proto.size(); arg != arge; ++arg) {
2319 char ArgType = Proto[arg];
2320 if (ArgType == 'c') {
2321 HasConstPtr = true;
2322 PtrArgNum = arg - 1;
2323 break;
2324 }
2325 if (ArgType == 'p') {
2326 PtrArgNum = arg - 1;
2327 break;
2328 }
2329 }
2330 // For sret builtins, adjust the pointer argument index.
2331 if (PtrArgNum >= 0 && (Proto[0] >= '2' && Proto[0] <= '4'))
2332 PtrArgNum += 1;
2333
Bob Wilson9082cdd2011-12-20 06:16:48 +00002334 // Omit type checking for the pointer arguments of vld1_lane, vld1_dup,
2335 // and vst1_lane intrinsics. Using a pointer to the vector element
2336 // type with one of those operations causes codegen to select an aligned
2337 // load/store instruction. If you want an unaligned operation,
2338 // the pointer argument needs to have less alignment than element type,
2339 // so just accept any pointer type.
2340 if (name == "vld1_lane" || name == "vld1_dup" || name == "vst1_lane") {
2341 PtrArgNum = -1;
2342 HasConstPtr = false;
2343 }
2344
Bob Wilson6f9f03e2011-11-08 05:04:11 +00002345 if (mask) {
Tim Northoverb793f0d2013-08-01 09:23:19 +00002346 if (isA64TypeCheck)
2347 OS << "case AArch64::BI__builtin_neon_";
2348 else
2349 OS << "case ARM::BI__builtin_neon_";
2350 OS << MangleName(name, TypeVec[si], ClassB) << ": mask = "
2351 << "0x" << utohexstr(mask) << "ULL";
Bob Wilson46482552011-11-16 21:32:23 +00002352 if (PtrArgNum >= 0)
2353 OS << "; PtrArgNum = " << PtrArgNum;
Bob Wilson6f9f03e2011-11-08 05:04:11 +00002354 if (HasConstPtr)
2355 OS << "; HasConstPtr = true";
2356 OS << "; break;\n";
2357 }
2358 if (qmask) {
Tim Northoverb793f0d2013-08-01 09:23:19 +00002359 if (isA64TypeCheck)
2360 OS << "case AArch64::BI__builtin_neon_";
2361 else
2362 OS << "case ARM::BI__builtin_neon_";
2363 OS << MangleName(name, TypeVec[qi], ClassB) << ": mask = "
2364 << "0x" << utohexstr(qmask) << "ULL";
Bob Wilson46482552011-11-16 21:32:23 +00002365 if (PtrArgNum >= 0)
2366 OS << "; PtrArgNum = " << PtrArgNum;
Bob Wilson6f9f03e2011-11-08 05:04:11 +00002367 if (HasConstPtr)
2368 OS << "; HasConstPtr = true";
2369 OS << "; break;\n";
2370 }
Peter Collingbourne51d77772011-10-06 13:03:08 +00002371 }
2372 OS << "#endif\n\n";
Tim Northoverb793f0d2013-08-01 09:23:19 +00002373}
Peter Collingbourne51d77772011-10-06 13:03:08 +00002374
Tim Northoverb793f0d2013-08-01 09:23:19 +00002375/// genBuiltinsDef: Generate the BuiltinsARM.def and BuiltinsAArch64.def
2376/// declaration of builtins, checking for unique builtin declarations.
2377void NeonEmitter::genBuiltinsDef(raw_ostream &OS,
2378 StringMap<ClassKind> &A64IntrinsicMap,
2379 bool isA64GenBuiltinDef) {
2380 std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst");
2381 StringMap<OpKind> EmittedMap;
2382
2383 // Generate BuiltinsARM.def and BuiltinsAArch64.def
2384 if (isA64GenBuiltinDef)
2385 OS << "#ifdef GET_NEON_AARCH64_BUILTINS\n";
2386 else
2387 OS << "#ifdef GET_NEON_BUILTINS\n";
2388
Peter Collingbourne51d77772011-10-06 13:03:08 +00002389 for (unsigned i = 0, e = RV.size(); i != e; ++i) {
2390 Record *R = RV[i];
Peter Collingbourne51d77772011-10-06 13:03:08 +00002391 OpKind k = OpMap[R->getValueAsDef("Operand")->getName()];
2392 if (k != OpNone)
2393 continue;
2394
Peter Collingbourne51d77772011-10-06 13:03:08 +00002395 std::string Proto = R->getValueAsString("Prototype");
Tim Northoverb793f0d2013-08-01 09:23:19 +00002396 std::string name = R->getValueAsString("Name");
Kevin Qin944f09f2013-08-29 07:55:15 +00002397 std::string Rename = name + "@" + Proto;
Peter Collingbourne51d77772011-10-06 13:03:08 +00002398
2399 // Functions with 'a' (the splat code) in the type prototype should not get
2400 // their own builtin as they use the non-splat variant.
2401 if (Proto.find('a') != std::string::npos)
2402 continue;
2403
Tim Northoverb793f0d2013-08-01 09:23:19 +00002404 std::string Types = R->getValueAsString("Types");
Peter Collingbourne51d77772011-10-06 13:03:08 +00002405 SmallVector<StringRef, 16> TypeVec;
2406 ParseTypes(R, Types, TypeVec);
2407
2408 if (R->getSuperClasses().size() < 2)
Joerg Sonnenberger38859ee2012-10-25 16:37:08 +00002409 PrintFatalError(R->getLoc(), "Builtin has no class kind");
Peter Collingbourne51d77772011-10-06 13:03:08 +00002410
2411 ClassKind ck = ClassMap[R->getSuperClasses()[1]];
2412
Tim Northoverb793f0d2013-08-01 09:23:19 +00002413 // Do not include AArch64 BUILTIN() macros if not generating
2414 // code for AArch64
2415 bool isA64 = R->getValueAsBit("isA64");
2416 if (!isA64GenBuiltinDef && isA64)
2417 continue;
Peter Collingbourne51d77772011-10-06 13:03:08 +00002418
Tim Northoverb793f0d2013-08-01 09:23:19 +00002419 // Include ARM BUILTIN() macros in AArch64 but only if ARM intrinsics
2420 // are not redefined in AArch64 to handle new types, e.g. "vabd" is a SIntr
2421 // redefined in AArch64 to handle an additional 2 x f64 type.
Kevin Qin944f09f2013-08-29 07:55:15 +00002422 if (isA64GenBuiltinDef && !isA64 && A64IntrinsicMap.count(Rename)) {
2423 ClassKind &A64CK = A64IntrinsicMap[Rename];
Tim Northoverb793f0d2013-08-01 09:23:19 +00002424 if (A64CK == ck && ck != ClassNone)
Peter Collingbourne51d77772011-10-06 13:03:08 +00002425 continue;
Tim Northoverb793f0d2013-08-01 09:23:19 +00002426 }
Peter Collingbourne51d77772011-10-06 13:03:08 +00002427
Tim Northoverb793f0d2013-08-01 09:23:19 +00002428 for (unsigned ti = 0, te = TypeVec.size(); ti != te; ++ti) {
2429 // Generate the declaration for this builtin, ensuring
2430 // that each unique BUILTIN() macro appears only once in the output
2431 // stream.
2432 std::string bd = GenBuiltinDef(name, Proto, TypeVec[ti], ck);
2433 if (EmittedMap.count(bd))
2434 continue;
Peter Collingbourne51d77772011-10-06 13:03:08 +00002435
Tim Northoverb793f0d2013-08-01 09:23:19 +00002436 EmittedMap[bd] = OpNone;
2437 OS << bd << "\n";
Peter Collingbourne51d77772011-10-06 13:03:08 +00002438 }
2439 }
2440 OS << "#endif\n\n";
2441}
2442
Tim Northoverb793f0d2013-08-01 09:23:19 +00002443/// runHeader - Emit a file with sections defining:
2444/// 1. the NEON section of BuiltinsARM.def and BuiltinsAArch64.def.
2445/// 2. the SemaChecking code for the type overload checking.
2446/// 3. the SemaChecking code for validation of intrinsic immediate arguments.
2447void NeonEmitter::runHeader(raw_ostream &OS) {
2448 std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst");
2449
2450 // build a map of AArch64 intriniscs to be used in uniqueness checks.
2451 StringMap<ClassKind> A64IntrinsicMap;
2452 for (unsigned i = 0, e = RV.size(); i != e; ++i) {
2453 Record *R = RV[i];
2454
2455 bool isA64 = R->getValueAsBit("isA64");
2456 if (!isA64)
2457 continue;
2458
2459 ClassKind CK = ClassNone;
2460 if (R->getSuperClasses().size() >= 2)
2461 CK = ClassMap[R->getSuperClasses()[1]];
2462
2463 std::string Name = R->getValueAsString("Name");
Kevin Qin944f09f2013-08-29 07:55:15 +00002464 std::string Proto = R->getValueAsString("Prototype");
2465 std::string Rename = Name + "@" + Proto;
2466 if (A64IntrinsicMap.count(Rename))
Tim Northoverb793f0d2013-08-01 09:23:19 +00002467 continue;
Kevin Qin944f09f2013-08-29 07:55:15 +00002468 A64IntrinsicMap[Rename] = CK;
Tim Northoverb793f0d2013-08-01 09:23:19 +00002469 }
2470
2471 // Generate BuiltinsARM.def for ARM
2472 genBuiltinsDef(OS, A64IntrinsicMap, false);
2473
2474 // Generate BuiltinsAArch64.def for AArch64
2475 genBuiltinsDef(OS, A64IntrinsicMap, true);
2476
2477 // Generate ARM overloaded type checking code for SemaChecking.cpp
2478 genOverloadTypeCheckCode(OS, A64IntrinsicMap, false);
2479
2480 // Generate AArch64 overloaded type checking code for SemaChecking.cpp
2481 genOverloadTypeCheckCode(OS, A64IntrinsicMap, true);
2482
2483 // Generate ARM range checking code for shift/lane immediates.
2484 genIntrinsicRangeCheckCode(OS, A64IntrinsicMap, false);
2485
2486 // Generate the AArch64 range checking code for shift/lane immediates.
2487 genIntrinsicRangeCheckCode(OS, A64IntrinsicMap, true);
2488}
2489
Peter Collingbourne51d77772011-10-06 13:03:08 +00002490/// GenTest - Write out a test for the intrinsic specified by the name and
2491/// type strings, including the embedded patterns for FileCheck to match.
2492static std::string GenTest(const std::string &name,
2493 const std::string &proto,
2494 StringRef outTypeStr, StringRef inTypeStr,
Michael Gottesman7200bd62013-04-16 22:48:52 +00002495 bool isShift, bool isHiddenLOp,
Tim Northoverb793f0d2013-08-01 09:23:19 +00002496 ClassKind ck, const std::string &InstName,
2497 bool isA64,
2498 std::string & testFuncProto) {
Peter Collingbourne51d77772011-10-06 13:03:08 +00002499 assert(!proto.empty() && "");
2500 std::string s;
2501
2502 // Function name with type suffix
2503 std::string mangledName = MangleName(name, outTypeStr, ClassS);
2504 if (outTypeStr != inTypeStr) {
2505 // If the input type is different (e.g., for vreinterpret), append a suffix
2506 // for the input type. String off a "Q" (quad) prefix so that MangleName
2507 // does not insert another "q" in the name.
2508 unsigned typeStrOff = (inTypeStr[0] == 'Q' ? 1 : 0);
2509 StringRef inTypeNoQuad = inTypeStr.substr(typeStrOff);
2510 mangledName = MangleName(mangledName, inTypeNoQuad, ClassS);
2511 }
2512
Tim Northoverb793f0d2013-08-01 09:23:19 +00002513 // todo: GenerateChecksForIntrinsic does not generate CHECK
2514 // for aarch64 instructions yet
Michael Gottesmanc327f872013-04-16 23:00:26 +00002515 std::vector<std::string> FileCheckPatterns;
Tim Northoverb793f0d2013-08-01 09:23:19 +00002516 if (!isA64) {
2517 GenerateChecksForIntrinsic(name, proto, outTypeStr, inTypeStr, ck, InstName,
2518 isHiddenLOp, FileCheckPatterns);
2519 s+= "// CHECK_ARM: test_" + mangledName + "\n";
2520 }
2521 s += "// CHECK_AARCH64: test_" + mangledName + "\n";
Michael Gottesmanc327f872013-04-16 23:00:26 +00002522
Peter Collingbourne51d77772011-10-06 13:03:08 +00002523 // Emit the FileCheck patterns.
Michael Gottesmanc327f872013-04-16 23:00:26 +00002524 // If for any reason we do not want to emit a check, mangledInst
2525 // will be the empty string.
2526 if (FileCheckPatterns.size()) {
2527 for (std::vector<std::string>::const_iterator i = FileCheckPatterns.begin(),
2528 e = FileCheckPatterns.end();
2529 i != e;
2530 ++i) {
Tim Northoverb793f0d2013-08-01 09:23:19 +00002531 s += "// CHECK_ARM: " + *i + "\n";
Michael Gottesmanc327f872013-04-16 23:00:26 +00002532 }
2533 }
Peter Collingbourne51d77772011-10-06 13:03:08 +00002534
2535 // Emit the start of the test function.
Tim Northoverb793f0d2013-08-01 09:23:19 +00002536
2537 testFuncProto = TypeString(proto[0], outTypeStr) + " test_" + mangledName + "(";
Peter Collingbourne51d77772011-10-06 13:03:08 +00002538 char arg = 'a';
2539 std::string comma;
2540 for (unsigned i = 1, e = proto.size(); i != e; ++i, ++arg) {
2541 // Do not create arguments for values that must be immediate constants.
2542 if (proto[i] == 'i')
2543 continue;
Tim Northoverb793f0d2013-08-01 09:23:19 +00002544 testFuncProto += comma + TypeString(proto[i], inTypeStr) + " ";
2545 testFuncProto.push_back(arg);
Peter Collingbourne51d77772011-10-06 13:03:08 +00002546 comma = ", ";
2547 }
Tim Northoverb793f0d2013-08-01 09:23:19 +00002548 testFuncProto += ")";
2549
2550 s+= testFuncProto;
2551 s+= " {\n ";
Peter Collingbourne51d77772011-10-06 13:03:08 +00002552
2553 if (proto[0] != 'v')
2554 s += "return ";
2555 s += mangledName + "(";
2556 arg = 'a';
2557 for (unsigned i = 1, e = proto.size(); i != e; ++i, ++arg) {
2558 if (proto[i] == 'i') {
2559 // For immediate operands, test the maximum value.
2560 if (isShift)
2561 s += "1"; // FIXME
2562 else
2563 // The immediate generally refers to a lane in the preceding argument.
2564 s += utostr(RangeFromType(proto[i-1], inTypeStr));
2565 } else {
2566 s.push_back(arg);
2567 }
2568 if ((i + 1) < e)
2569 s += ", ";
2570 }
2571 s += ");\n}\n\n";
2572 return s;
2573}
2574
Tim Northoverb793f0d2013-08-01 09:23:19 +00002575/// Write out all intrinsic tests for the specified target, checking
2576/// for intrinsic test uniqueness.
2577void NeonEmitter::genTargetTest(raw_ostream &OS, StringMap<OpKind> &EmittedMap,
2578 bool isA64GenTest) {
2579 if (isA64GenTest)
2580 OS << "#ifdef __aarch64__\n";
Peter Collingbourne51d77772011-10-06 13:03:08 +00002581
Tim Northoverb793f0d2013-08-01 09:23:19 +00002582 std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst");
Peter Collingbourne51d77772011-10-06 13:03:08 +00002583 for (unsigned i = 0, e = RV.size(); i != e; ++i) {
2584 Record *R = RV[i];
2585 std::string name = R->getValueAsString("Name");
2586 std::string Proto = R->getValueAsString("Prototype");
2587 std::string Types = R->getValueAsString("Types");
2588 bool isShift = R->getValueAsBit("isShift");
Michael Gottesman7200bd62013-04-16 22:48:52 +00002589 std::string InstName = R->getValueAsString("InstName");
2590 bool isHiddenLOp = R->getValueAsBit("isHiddenLInst");
Tim Northoverb793f0d2013-08-01 09:23:19 +00002591 bool isA64 = R->getValueAsBit("isA64");
2592
2593 // do not include AArch64 intrinsic test if not generating
2594 // code for AArch64
2595 if (!isA64GenTest && isA64)
2596 continue;
Peter Collingbourne51d77772011-10-06 13:03:08 +00002597
2598 SmallVector<StringRef, 16> TypeVec;
2599 ParseTypes(R, Types, TypeVec);
2600
Michael Gottesman7200bd62013-04-16 22:48:52 +00002601 ClassKind ck = ClassMap[R->getSuperClasses()[1]];
Peter Collingbourne51d77772011-10-06 13:03:08 +00002602 OpKind kind = OpMap[R->getValueAsDef("Operand")->getName()];
Jim Grosbach667381b2012-05-09 18:17:30 +00002603 if (kind == OpUnavailable)
2604 continue;
Peter Collingbourne51d77772011-10-06 13:03:08 +00002605 for (unsigned ti = 0, te = TypeVec.size(); ti != te; ++ti) {
2606 if (kind == OpReinterpret) {
2607 bool outQuad = false;
2608 bool dummy = false;
2609 (void)ClassifyType(TypeVec[ti], outQuad, dummy, dummy);
2610 for (unsigned srcti = 0, srcte = TypeVec.size();
2611 srcti != srcte; ++srcti) {
2612 bool inQuad = false;
2613 (void)ClassifyType(TypeVec[srcti], inQuad, dummy, dummy);
2614 if (srcti == ti || inQuad != outQuad)
2615 continue;
Tim Northoverb793f0d2013-08-01 09:23:19 +00002616 std::string testFuncProto;
2617 std::string s = GenTest(name, Proto, TypeVec[ti], TypeVec[srcti],
2618 isShift, isHiddenLOp, ck, InstName, isA64,
2619 testFuncProto);
2620 if (EmittedMap.count(testFuncProto))
2621 continue;
2622 EmittedMap[testFuncProto] = kind;
2623 OS << s << "\n";
Peter Collingbourne51d77772011-10-06 13:03:08 +00002624 }
2625 } else {
Tim Northoverb793f0d2013-08-01 09:23:19 +00002626 std::string testFuncProto;
2627 std::string s = GenTest(name, Proto, TypeVec[ti], TypeVec[ti], isShift,
2628 isHiddenLOp, ck, InstName, isA64, testFuncProto);
2629 if (EmittedMap.count(testFuncProto))
2630 continue;
2631 EmittedMap[testFuncProto] = kind;
2632 OS << s << "\n";
Peter Collingbourne51d77772011-10-06 13:03:08 +00002633 }
2634 }
Peter Collingbourne51d77772011-10-06 13:03:08 +00002635 }
Tim Northoverb793f0d2013-08-01 09:23:19 +00002636
2637 if (isA64GenTest)
2638 OS << "#endif\n";
2639}
2640/// runTests - Write out a complete set of tests for all of the Neon
2641/// intrinsics.
2642void NeonEmitter::runTests(raw_ostream &OS) {
2643 OS << "// RUN: %clang_cc1 -triple thumbv7s-apple-darwin -target-abi "
2644 "apcs-gnu\\\n"
2645 "// RUN: -target-cpu swift -ffreestanding -Os -S -o - %s\\\n"
2646 "// RUN: | FileCheck %s -check-prefix=CHECK_ARM\n"
2647 "\n"
2648 "// RUN: %clang_cc1 -triple aarch64-none-linux-gnu \\\n"
2649 "// RUN -target-feature +neon -ffreestanding -S -o - %s \\\n"
2650 "// RUN: | FileCheck %s -check-prefix=CHECK_AARCH64\n"
2651 "\n"
2652 "// REQUIRES: long_tests\n"
2653 "\n"
2654 "#include <arm_neon.h>\n"
2655 "\n";
2656
2657 // ARM tests must be emitted before AArch64 tests to ensure
2658 // tests for intrinsics that are common to ARM and AArch64
2659 // appear only once in the output stream.
2660 // The check for uniqueness is done in genTargetTest.
2661 StringMap<OpKind> EmittedMap;
2662
2663 genTargetTest(OS, EmittedMap, false);
2664
2665 genTargetTest(OS, EmittedMap, true);
Peter Collingbourne51d77772011-10-06 13:03:08 +00002666}
2667
Jakob Stoklund Olesen3cc509b2012-06-13 05:12:41 +00002668namespace clang {
2669void EmitNeon(RecordKeeper &Records, raw_ostream &OS) {
2670 NeonEmitter(Records).run(OS);
2671}
2672void EmitNeonSema(RecordKeeper &Records, raw_ostream &OS) {
2673 NeonEmitter(Records).runHeader(OS);
2674}
2675void EmitNeonTest(RecordKeeper &Records, raw_ostream &OS) {
2676 NeonEmitter(Records).runTests(OS);
2677}
2678} // End namespace clang