blob: 310d5142da32329cea1c0a9f0238d79085db3d97 [file] [log] [blame]
Nate Begeman5ddb0872010-05-28 01:08:32 +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//
Nate Begemand72c9002010-06-13 04:47:03 +000014// 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.
22//
Nate Begeman5ddb0872010-05-28 01:08:32 +000023//===----------------------------------------------------------------------===//
24
25#include "NeonEmitter.h"
Nate Begeman22237772010-06-02 00:34:55 +000026#include "llvm/ADT/SmallString.h"
27#include "llvm/ADT/SmallVector.h"
Nate Begeman5ddb0872010-05-28 01:08:32 +000028#include "llvm/ADT/StringExtras.h"
Nate Begeman5ddb0872010-05-28 01:08:32 +000029#include <string>
30
31using namespace llvm;
32
Nate Begemand72c9002010-06-13 04:47:03 +000033/// ParseTypes - break down a string such as "fQf" into a vector of StringRefs,
34/// which each StringRef representing a single type declared in the string.
35/// for "fQf" we would end up with 2 StringRefs, "f", and "Qf", representing
36/// 2xfloat and 4xfloat respectively.
Nate Begeman22237772010-06-02 00:34:55 +000037static void ParseTypes(Record *r, std::string &s,
38 SmallVectorImpl<StringRef> &TV) {
39 const char *data = s.data();
40 int len = 0;
41
42 for (unsigned i = 0, e = s.size(); i != e; ++i, ++len) {
43 if (data[len] == 'P' || data[len] == 'Q' || data[len] == 'U')
44 continue;
45
46 switch (data[len]) {
47 case 'c':
48 case 's':
49 case 'i':
50 case 'l':
51 case 'h':
52 case 'f':
53 break;
54 default:
55 throw TGError(r->getLoc(),
56 "Unexpected letter: " + std::string(data + len, 1));
57 break;
58 }
59 TV.push_back(StringRef(data, len + 1));
60 data += len + 1;
61 len = -1;
62 }
63}
64
Nate Begemand72c9002010-06-13 04:47:03 +000065/// Widen - Convert a type code into the next wider type. char -> short,
66/// short -> int, etc.
Duncan Sands8dbbace2010-06-02 08:37:30 +000067static char Widen(const char t) {
Nate Begeman22237772010-06-02 00:34:55 +000068 switch (t) {
69 case 'c':
70 return 's';
71 case 's':
72 return 'i';
73 case 'i':
74 return 'l';
75 default: throw "unhandled type in widen!";
76 }
77 return '\0';
78}
79
Nate Begemand72c9002010-06-13 04:47:03 +000080/// Narrow - Convert a type code into the next smaller type. short -> char,
81/// float -> half float, etc.
Nate Begeman3861e742010-06-03 21:35:22 +000082static char Narrow(const char t) {
83 switch (t) {
84 case 's':
85 return 'c';
86 case 'i':
87 return 's';
88 case 'l':
89 return 'i';
Nate Begeman900f4672010-06-08 00:14:42 +000090 case 'f':
91 return 'h';
Nate Begemane5cb26f2010-09-22 22:28:42 +000092 default: throw "unhandled type in narrow!";
Nate Begeman3861e742010-06-03 21:35:22 +000093 }
94 return '\0';
95}
96
Nate Begemand72c9002010-06-13 04:47:03 +000097/// For a particular StringRef, return the base type code, and whether it has
98/// the quad-vector, polynomial, or unsigned modifiers set.
Nate Begemanaf905ef2010-06-02 06:17:19 +000099static char ClassifyType(StringRef ty, bool &quad, bool &poly, bool &usgn) {
Nate Begeman22237772010-06-02 00:34:55 +0000100 unsigned off = 0;
101
Nate Begemanaf905ef2010-06-02 06:17:19 +0000102 // remember quad.
103 if (ty[off] == 'Q') {
104 quad = true;
105 ++off;
106 }
107
108 // remember poly.
109 if (ty[off] == 'P') {
110 poly = true;
111 ++off;
112 }
113
114 // remember unsigned.
115 if (ty[off] == 'U') {
116 usgn = true;
117 ++off;
118 }
119
120 // base type to get the type string for.
121 return ty[off];
122}
123
Nate Begemand72c9002010-06-13 04:47:03 +0000124/// ModType - Transform a type code and its modifiers based on a mod code. The
125/// mod code definitions may be found at the top of arm_neon.td.
Nate Begemanb0a4e452010-06-07 16:00:37 +0000126static char ModType(const char mod, char type, bool &quad, bool &poly,
127 bool &usgn, bool &scal, bool &cnst, bool &pntr) {
Nate Begeman22237772010-06-02 00:34:55 +0000128 switch (mod) {
Nate Begeman22237772010-06-02 00:34:55 +0000129 case 't':
130 if (poly) {
131 poly = false;
132 usgn = true;
133 }
134 break;
Nate Begeman900f4672010-06-08 00:14:42 +0000135 case 'u':
Nate Begeman22237772010-06-02 00:34:55 +0000136 usgn = true;
Nate Begeman900f4672010-06-08 00:14:42 +0000137 case 'x':
Nate Begeman162d3ba2010-06-03 04:04:09 +0000138 poly = false;
Nate Begeman22237772010-06-02 00:34:55 +0000139 if (type == 'f')
140 type = 'i';
141 break;
142 case 'f':
Nate Begeman900f4672010-06-08 00:14:42 +0000143 if (type == 'h')
144 quad = true;
Nate Begeman22237772010-06-02 00:34:55 +0000145 type = 'f';
Nate Begeman162d3ba2010-06-03 04:04:09 +0000146 usgn = false;
Nate Begeman22237772010-06-02 00:34:55 +0000147 break;
Nate Begeman59d70cb2010-08-06 01:24:11 +0000148 case 'g':
149 quad = false;
150 break;
Nate Begeman22237772010-06-02 00:34:55 +0000151 case 'w':
152 type = Widen(type);
153 quad = true;
154 break;
155 case 'n':
156 type = Widen(type);
157 break;
Nate Begemane5cb26f2010-09-22 22:28:42 +0000158 case 'i':
159 type = 'i';
160 scal = true;
161 break;
Nate Begeman22237772010-06-02 00:34:55 +0000162 case 'l':
163 type = 'l';
164 scal = true;
165 usgn = true;
166 break;
167 case 's':
Nate Begeman4b425a82010-06-10 00:16:56 +0000168 case 'a':
Nate Begeman22237772010-06-02 00:34:55 +0000169 scal = true;
170 break;
171 case 'k':
172 quad = true;
173 break;
174 case 'c':
175 cnst = true;
176 case 'p':
177 pntr = true;
178 scal = true;
179 break;
Nate Begeman3861e742010-06-03 21:35:22 +0000180 case 'h':
181 type = Narrow(type);
Nate Begeman900f4672010-06-08 00:14:42 +0000182 if (type == 'h')
183 quad = false;
Nate Begeman3861e742010-06-03 21:35:22 +0000184 break;
185 case 'e':
186 type = Narrow(type);
187 usgn = true;
188 break;
Nate Begeman22237772010-06-02 00:34:55 +0000189 default:
190 break;
191 }
Nate Begemanb0a4e452010-06-07 16:00:37 +0000192 return type;
193}
194
Nate Begemand72c9002010-06-13 04:47:03 +0000195/// TypeString - for a modifier and type, generate the name of the typedef for
196/// that type. If generic is true, emit the generic vector type rather than
Bob Wilson1ac27cf2010-06-24 22:04:30 +0000197/// the public NEON type. QUc -> uint8x8_t / __neon_uint8x8_t.
Nate Begemanb0a4e452010-06-07 16:00:37 +0000198static std::string TypeString(const char mod, StringRef typestr,
Nate Begemand72c9002010-06-13 04:47:03 +0000199 bool generic = false) {
Nate Begemanb0a4e452010-06-07 16:00:37 +0000200 bool quad = false;
201 bool poly = false;
202 bool usgn = false;
203 bool scal = false;
204 bool cnst = false;
205 bool pntr = false;
206
207 if (mod == 'v')
208 return "void";
209 if (mod == 'i')
210 return "int";
211
212 // base type to get the type string for.
213 char type = ClassifyType(typestr, quad, poly, usgn);
214
215 // Based on the modifying character, change the type and width if necessary.
216 type = ModType(mod, type, quad, poly, usgn, scal, cnst, pntr);
Nate Begeman22237772010-06-02 00:34:55 +0000217
218 SmallString<128> s;
219
Nate Begemand72c9002010-06-13 04:47:03 +0000220 if (generic)
Nate Begeman9e584b32010-06-04 22:53:30 +0000221 s += "__neon_";
222
Nate Begeman22237772010-06-02 00:34:55 +0000223 if (usgn)
224 s.push_back('u');
225
226 switch (type) {
227 case 'c':
228 s += poly ? "poly8" : "int8";
229 if (scal)
230 break;
231 s += quad ? "x16" : "x8";
232 break;
233 case 's':
234 s += poly ? "poly16" : "int16";
235 if (scal)
236 break;
237 s += quad ? "x8" : "x4";
238 break;
239 case 'i':
240 s += "int32";
241 if (scal)
242 break;
243 s += quad ? "x4" : "x2";
244 break;
245 case 'l':
246 s += "int64";
247 if (scal)
248 break;
249 s += quad ? "x2" : "x1";
250 break;
251 case 'h':
252 s += "float16";
253 if (scal)
254 break;
255 s += quad ? "x8" : "x4";
256 break;
257 case 'f':
258 s += "float32";
259 if (scal)
260 break;
261 s += quad ? "x4" : "x2";
262 break;
Nate Begeman22237772010-06-02 00:34:55 +0000263 default:
264 throw "unhandled type!";
265 break;
266 }
267
268 if (mod == '2')
269 s += "x2";
270 if (mod == '3')
271 s += "x3";
272 if (mod == '4')
273 s += "x4";
274
275 // Append _t, finishing the type string typedef type.
276 s += "_t";
277
278 if (cnst)
279 s += " const";
280
281 if (pntr)
282 s += " *";
283
284 return s.str();
285}
286
Bob Wilson1ac27cf2010-06-24 22:04:30 +0000287/// BuiltinTypeString - for a modifier and type, generate the clang
288/// BuiltinsARM.def prototype code for the function. See the top of clang's
289/// Builtins.def for a description of the type strings.
Nate Begeman7c21f742010-06-04 21:36:00 +0000290static std::string BuiltinTypeString(const char mod, StringRef typestr,
291 ClassKind ck, bool ret) {
Nate Begeman92f98af2010-06-04 07:11:25 +0000292 bool quad = false;
293 bool poly = false;
294 bool usgn = false;
295 bool scal = false;
296 bool cnst = false;
297 bool pntr = false;
298
299 if (mod == 'v')
300 return "v";
301 if (mod == 'i')
302 return "i";
303
304 // base type to get the type string for.
305 char type = ClassifyType(typestr, quad, poly, usgn);
306
307 // Based on the modifying character, change the type and width if necessary.
Nate Begemanb0a4e452010-06-07 16:00:37 +0000308 type = ModType(mod, type, quad, poly, usgn, scal, cnst, pntr);
309
Nate Begemanc4a1b652010-06-20 21:09:52 +0000310 if (pntr) {
311 usgn = false;
312 poly = false;
Nate Begemanb0a4e452010-06-07 16:00:37 +0000313 type = 'v';
Nate Begemanc4a1b652010-06-20 21:09:52 +0000314 }
Nate Begeman92f98af2010-06-04 07:11:25 +0000315 if (type == 'h') {
316 type = 's';
317 usgn = true;
318 }
Nate Begeman7c21f742010-06-04 21:36:00 +0000319 usgn = usgn | poly | ((ck == ClassI || ck == ClassW) && scal && type != 'f');
Nate Begeman92f98af2010-06-04 07:11:25 +0000320
321 if (scal) {
322 SmallString<128> s;
323
324 if (usgn)
325 s.push_back('U');
Nate Begeman7c21f742010-06-04 21:36:00 +0000326
327 if (type == 'l')
328 s += "LLi";
329 else
330 s.push_back(type);
331
Nate Begeman92f98af2010-06-04 07:11:25 +0000332 if (cnst)
333 s.push_back('C');
334 if (pntr)
335 s.push_back('*');
336 return s.str();
337 }
Nate Begeman7c21f742010-06-04 21:36:00 +0000338
339 // Since the return value must be one type, return a vector type of the
Nate Begemanc4a1b652010-06-20 21:09:52 +0000340 // appropriate width which we will bitcast. An exception is made for
341 // returning structs of 2, 3, or 4 vectors which are returned in a sret-like
342 // fashion, storing them to a pointer arg.
Nate Begeman7c21f742010-06-04 21:36:00 +0000343 if (ret) {
Nate Begemanc4a1b652010-06-20 21:09:52 +0000344 if (mod == '2' || mod == '3' || mod == '4')
345 return "vv*";
Nate Begemanf50551e2010-06-09 18:02:26 +0000346 if (mod == 'f' || (ck != ClassB && type == 'f'))
Nate Begeman56387832010-06-08 06:01:16 +0000347 return quad ? "V4f" : "V2f";
Nate Begemanf50551e2010-06-09 18:02:26 +0000348 if (ck != ClassB && type == 's')
Nate Begeman007afe42010-06-09 05:11:55 +0000349 return quad ? "V8s" : "V4s";
Nate Begemanf50551e2010-06-09 18:02:26 +0000350 if (ck != ClassB && type == 'i')
Nate Begeman56387832010-06-08 06:01:16 +0000351 return quad ? "V4i" : "V2i";
Nate Begemanf50551e2010-06-09 18:02:26 +0000352 if (ck != ClassB && type == 'l')
Nate Begeman007afe42010-06-09 05:11:55 +0000353 return quad ? "V2LLi" : "V1LLi";
Nate Begeman900f4672010-06-08 00:14:42 +0000354
Nate Begeman7c21f742010-06-04 21:36:00 +0000355 return quad ? "V16c" : "V8c";
356 }
357
358 // Non-return array types are passed as individual vectors.
Nate Begeman92f98af2010-06-04 07:11:25 +0000359 if (mod == '2')
360 return quad ? "V16cV16c" : "V8cV8c";
361 if (mod == '3')
362 return quad ? "V16cV16cV16c" : "V8cV8cV8c";
363 if (mod == '4')
364 return quad ? "V16cV16cV16cV16c" : "V8cV8cV8cV8c";
365
Nate Begemanf50551e2010-06-09 18:02:26 +0000366 if (mod == 'f' || (ck != ClassB && type == 'f'))
Nate Begeman007afe42010-06-09 05:11:55 +0000367 return quad ? "V4f" : "V2f";
Nate Begemanf50551e2010-06-09 18:02:26 +0000368 if (ck != ClassB && type == 's')
Nate Begeman007afe42010-06-09 05:11:55 +0000369 return quad ? "V8s" : "V4s";
Nate Begemanf50551e2010-06-09 18:02:26 +0000370 if (ck != ClassB && type == 'i')
Nate Begeman007afe42010-06-09 05:11:55 +0000371 return quad ? "V4i" : "V2i";
Nate Begemanf50551e2010-06-09 18:02:26 +0000372 if (ck != ClassB && type == 'l')
Nate Begeman007afe42010-06-09 05:11:55 +0000373 return quad ? "V2LLi" : "V1LLi";
374
Nate Begeman92f98af2010-06-04 07:11:25 +0000375 return quad ? "V16c" : "V8c";
376}
377
Bob Wilson9969bc32010-06-24 22:03:41 +0000378/// StructTag - generate the name of the struct tag for a type.
379/// These names are mandated by ARM's ABI.
380static std::string StructTag(StringRef typestr) {
381 bool quad = false;
382 bool poly = false;
383 bool usgn = false;
384
385 // base type to get the type string for.
386 char type = ClassifyType(typestr, quad, poly, usgn);
387
388 SmallString<128> s;
389 s += "__simd";
390 s += quad ? "128_" : "64_";
391 if (usgn)
392 s.push_back('u');
393
394 switch (type) {
395 case 'c':
396 s += poly ? "poly8" : "int8";
397 break;
398 case 's':
399 s += poly ? "poly16" : "int16";
400 break;
401 case 'i':
402 s += "int32";
403 break;
404 case 'l':
405 s += "int64";
406 break;
407 case 'h':
408 s += "float16";
409 break;
410 case 'f':
411 s += "float32";
412 break;
413 default:
414 throw "unhandled type!";
415 break;
416 }
417
418 // Append _t, finishing the struct tag name.
419 s += "_t";
420
421 return s.str();
422}
423
Nate Begemand72c9002010-06-13 04:47:03 +0000424/// MangleName - Append a type or width suffix to a base neon function name,
425/// and insert a 'q' in the appropriate location if the operation works on
426/// 128b rather than 64b. E.g. turn "vst2_lane" into "vst2q_lane_f32", etc.
Nate Begemana8979a02010-06-04 00:21:41 +0000427static std::string MangleName(const std::string &name, StringRef typestr,
428 ClassKind ck) {
Nate Begeman900f4672010-06-08 00:14:42 +0000429 if (name == "vcvt_f32_f16")
430 return name;
431
Nate Begemanaf905ef2010-06-02 06:17:19 +0000432 bool quad = false;
433 bool poly = false;
434 bool usgn = false;
435 char type = ClassifyType(typestr, quad, poly, usgn);
436
437 std::string s = name;
438
439 switch (type) {
Nate Begemana8979a02010-06-04 00:21:41 +0000440 case 'c':
441 switch (ck) {
442 case ClassS: s += poly ? "_p8" : usgn ? "_u8" : "_s8"; break;
443 case ClassI: s += "_i8"; break;
444 case ClassW: s += "_8"; break;
445 default: break;
446 }
447 break;
448 case 's':
449 switch (ck) {
450 case ClassS: s += poly ? "_p16" : usgn ? "_u16" : "_s16"; break;
451 case ClassI: s += "_i16"; break;
452 case ClassW: s += "_16"; break;
453 default: break;
454 }
455 break;
456 case 'i':
457 switch (ck) {
458 case ClassS: s += usgn ? "_u32" : "_s32"; break;
459 case ClassI: s += "_i32"; break;
460 case ClassW: s += "_32"; break;
461 default: break;
462 }
463 break;
464 case 'l':
465 switch (ck) {
466 case ClassS: s += usgn ? "_u64" : "_s64"; break;
467 case ClassI: s += "_i64"; break;
468 case ClassW: s += "_64"; break;
469 default: break;
470 }
471 break;
472 case 'h':
473 switch (ck) {
474 case ClassS:
475 case ClassI: s += "_f16"; break;
476 case ClassW: s += "_16"; break;
477 default: break;
478 }
479 break;
480 case 'f':
481 switch (ck) {
482 case ClassS:
483 case ClassI: s += "_f32"; break;
484 case ClassW: s += "_32"; break;
485 default: break;
486 }
487 break;
488 default:
489 throw "unhandled type!";
490 break;
Nate Begemanaf905ef2010-06-02 06:17:19 +0000491 }
Nate Begemana8979a02010-06-04 00:21:41 +0000492 if (ck == ClassB)
Nate Begeman92f98af2010-06-04 07:11:25 +0000493 s += "_v";
Nate Begemana8979a02010-06-04 00:21:41 +0000494
Nate Begemanaf905ef2010-06-02 06:17:19 +0000495 // Insert a 'q' before the first '_' character so that it ends up before
496 // _lane or _n on vector-scalar operations.
497 if (quad) {
498 size_t pos = s.find('_');
499 s = s.insert(pos, "q");
500 }
501 return s;
Nate Begeman22237772010-06-02 00:34:55 +0000502}
503
Nate Begemanaf905ef2010-06-02 06:17:19 +0000504// Generate the string "(argtype a, argtype b, ...)"
Nate Begeman22237772010-06-02 00:34:55 +0000505static std::string GenArgs(const std::string &proto, StringRef typestr) {
Nate Begeman6c060db2010-06-09 01:09:00 +0000506 bool define = proto.find('i') != std::string::npos;
Nate Begemanaf905ef2010-06-02 06:17:19 +0000507 char arg = 'a';
508
509 std::string s;
510 s += "(";
511
512 for (unsigned i = 1, e = proto.size(); i != e; ++i, ++arg) {
Nate Begeman6c060db2010-06-09 01:09:00 +0000513 if (!define) {
514 s += TypeString(proto[i], typestr);
515 s.push_back(' ');
516 }
Nate Begemanaf905ef2010-06-02 06:17:19 +0000517 s.push_back(arg);
518 if ((i + 1) < e)
519 s += ", ";
520 }
521
522 s += ")";
523 return s;
Nate Begeman22237772010-06-02 00:34:55 +0000524}
525
Nate Begemancc3c41a2010-06-12 03:09:49 +0000526static std::string Duplicate(unsigned nElts, StringRef typestr,
527 const std::string &a) {
Nate Begeman4b425a82010-06-10 00:16:56 +0000528 std::string s;
529
530 s = "(__neon_" + TypeString('d', typestr) + "){ ";
531 for (unsigned i = 0; i != nElts; ++i) {
532 s += a;
533 if ((i + 1) < nElts)
534 s += ", ";
535 }
536 s += " }";
537
538 return s;
539}
540
541// Generate the definition for this intrinsic, e.g. "a + b" for OpAdd.
542// If structTypes is true, the NEON types are structs of vector types rather
543// than vector types, and the call becomes "a.val + b.val"
544static std::string GenOpString(OpKind op, const std::string &proto,
545 StringRef typestr, bool structTypes = true) {
Nate Begemancc3c41a2010-06-12 03:09:49 +0000546 bool dummy, quad = false;
547 char type = ClassifyType(typestr, quad, dummy, dummy);
548 unsigned nElts = 0;
549 switch (type) {
550 case 'c': nElts = 8; break;
551 case 's': nElts = 4; break;
552 case 'i': nElts = 2; break;
553 case 'l': nElts = 1; break;
554 case 'h': nElts = 4; break;
555 case 'f': nElts = 2; break;
556 }
557
Nate Begeman4b425a82010-06-10 00:16:56 +0000558 std::string ts = TypeString(proto[0], typestr);
Bob Wilsonee9ca072010-09-15 01:52:33 +0000559 std::string s;
560 if (op == OpHi || op == OpLo) {
561 s = "union { " + ts + " r; double d; } u; u.d";
562 } else {
563 s = ts + " r; r";
564 if (structTypes)
565 s += ".val";
566 }
Nate Begeman900f4672010-06-08 00:14:42 +0000567
568 s += " = ";
569
Nate Begeman3861e742010-06-03 21:35:22 +0000570 std::string a, b, c;
571 if (proto.size() > 1)
Nate Begeman900f4672010-06-08 00:14:42 +0000572 a = (structTypes && proto[1] != 'l' && proto[1] != 's') ? "a.val" : "a";
Nate Begeman3861e742010-06-03 21:35:22 +0000573 b = structTypes ? "b.val" : "b";
574 c = structTypes ? "c.val" : "c";
Nate Begeman162d3ba2010-06-03 04:04:09 +0000575
576 switch(op) {
577 case OpAdd:
578 s += a + " + " + b;
579 break;
580 case OpSub:
581 s += a + " - " + b;
582 break;
Nate Begeman4b425a82010-06-10 00:16:56 +0000583 case OpMulN:
Nate Begeman4da883a2010-06-15 22:10:31 +0000584 b = Duplicate(nElts << (int)quad, typestr, "b");
Nate Begeman162d3ba2010-06-03 04:04:09 +0000585 case OpMul:
586 s += a + " * " + b;
587 break;
Nate Begeman4b425a82010-06-10 00:16:56 +0000588 case OpMlaN:
Nate Begeman4da883a2010-06-15 22:10:31 +0000589 c = Duplicate(nElts << (int)quad, typestr, "c");
Nate Begeman162d3ba2010-06-03 04:04:09 +0000590 case OpMla:
591 s += a + " + ( " + b + " * " + c + " )";
592 break;
Nate Begeman4b425a82010-06-10 00:16:56 +0000593 case OpMlsN:
Nate Begeman4da883a2010-06-15 22:10:31 +0000594 c = Duplicate(nElts << (int)quad, typestr, "c");
Nate Begeman162d3ba2010-06-03 04:04:09 +0000595 case OpMls:
596 s += a + " - ( " + b + " * " + c + " )";
597 break;
598 case OpEq:
599 s += "(__neon_" + ts + ")(" + a + " == " + b + ")";
600 break;
601 case OpGe:
602 s += "(__neon_" + ts + ")(" + a + " >= " + b + ")";
603 break;
604 case OpLe:
605 s += "(__neon_" + ts + ")(" + a + " <= " + b + ")";
606 break;
607 case OpGt:
608 s += "(__neon_" + ts + ")(" + a + " > " + b + ")";
609 break;
610 case OpLt:
611 s += "(__neon_" + ts + ")(" + a + " < " + b + ")";
612 break;
613 case OpNeg:
614 s += " -" + a;
615 break;
616 case OpNot:
617 s += " ~" + a;
618 break;
619 case OpAnd:
620 s += a + " & " + b;
621 break;
622 case OpOr:
623 s += a + " | " + b;
624 break;
625 case OpXor:
626 s += a + " ^ " + b;
627 break;
628 case OpAndNot:
629 s += a + " & ~" + b;
630 break;
631 case OpOrNot:
632 s += a + " | ~" + b;
633 break;
Nate Begeman3861e742010-06-03 21:35:22 +0000634 case OpCast:
635 s += "(__neon_" + ts + ")" + a;
636 break;
Nate Begeman900f4672010-06-08 00:14:42 +0000637 case OpConcat:
638 s += "__builtin_shufflevector((__neon_int64x1_t)" + a;
639 s += ", (__neon_int64x1_t)" + b + ", 0, 1)";
640 break;
Nate Begeman6c060db2010-06-09 01:09:00 +0000641 case OpHi:
Bob Wilsonee9ca072010-09-15 01:52:33 +0000642 s += "(((__neon_float64x2_t)" + a + ")[1])";
Nate Begeman6c060db2010-06-09 01:09:00 +0000643 break;
644 case OpLo:
Bob Wilsonee9ca072010-09-15 01:52:33 +0000645 s += "(((__neon_float64x2_t)" + a + ")[0])";
Nate Begeman6c060db2010-06-09 01:09:00 +0000646 break;
Nate Begeman900f4672010-06-08 00:14:42 +0000647 case OpDup:
Nate Begeman4da883a2010-06-15 22:10:31 +0000648 s += Duplicate(nElts << (int)quad, typestr, a);
Nate Begemancc3c41a2010-06-12 03:09:49 +0000649 break;
650 case OpSelect:
651 // ((0 & 1) | (~0 & 2))
652 ts = TypeString(proto[1], typestr);
653 s += "( " + a + " & (__neon_" + ts + ")" + b + ") | ";
654 s += "(~" + a + " & (__neon_" + ts + ")" + c + ")";
655 break;
656 case OpRev16:
657 s += "__builtin_shufflevector(" + a + ", " + a;
Nate Begeman4da883a2010-06-15 22:10:31 +0000658 for (unsigned i = 2; i <= nElts << (int)quad; i += 2)
Nate Begemancc3c41a2010-06-12 03:09:49 +0000659 for (unsigned j = 0; j != 2; ++j)
660 s += ", " + utostr(i - j - 1);
661 s += ")";
662 break;
663 case OpRev32:
664 nElts >>= 1;
665 s += "__builtin_shufflevector(" + a + ", " + a;
Nate Begeman4da883a2010-06-15 22:10:31 +0000666 for (unsigned i = nElts; i <= nElts << (1 + (int)quad); i += nElts)
Nate Begemancc3c41a2010-06-12 03:09:49 +0000667 for (unsigned j = 0; j != nElts; ++j)
668 s += ", " + utostr(i - j - 1);
669 s += ")";
670 break;
671 case OpRev64:
672 s += "__builtin_shufflevector(" + a + ", " + a;
Nate Begeman4da883a2010-06-15 22:10:31 +0000673 for (unsigned i = nElts; i <= nElts << (int)quad; i += nElts)
Nate Begemancc3c41a2010-06-12 03:09:49 +0000674 for (unsigned j = 0; j != nElts; ++j)
675 s += ", " + utostr(i - j - 1);
676 s += ")";
Nate Begeman900f4672010-06-08 00:14:42 +0000677 break;
Nate Begeman162d3ba2010-06-03 04:04:09 +0000678 default:
679 throw "unknown OpKind!";
680 break;
681 }
Bob Wilsonee9ca072010-09-15 01:52:33 +0000682 if (op == OpHi || op == OpLo)
683 s += "; return u.r;";
684 else
685 s += "; return r;";
Nate Begeman162d3ba2010-06-03 04:04:09 +0000686 return s;
Nate Begemane66aab52010-06-02 07:14:28 +0000687}
688
Nate Begemanb0a4e452010-06-07 16:00:37 +0000689static unsigned GetNeonEnum(const std::string &proto, StringRef typestr) {
690 unsigned mod = proto[0];
691 unsigned ret = 0;
692
Nate Begeman900f4672010-06-08 00:14:42 +0000693 if (mod == 'v' || mod == 'f')
Nate Begemanb0a4e452010-06-07 16:00:37 +0000694 mod = proto[1];
695
696 bool quad = false;
697 bool poly = false;
698 bool usgn = false;
699 bool scal = false;
700 bool cnst = false;
701 bool pntr = false;
702
Nate Begeman59d70cb2010-08-06 01:24:11 +0000703 // Base type to get the type string for.
Nate Begemanb0a4e452010-06-07 16:00:37 +0000704 char type = ClassifyType(typestr, quad, poly, usgn);
705
706 // Based on the modifying character, change the type and width if necessary.
707 type = ModType(mod, type, quad, poly, usgn, scal, cnst, pntr);
Nate Begeman59d70cb2010-08-06 01:24:11 +0000708
Nate Begemanb0a4e452010-06-07 16:00:37 +0000709 if (usgn)
710 ret |= 0x08;
Nate Begeman59d70cb2010-08-06 01:24:11 +0000711 if (quad && proto[1] != 'g')
Nate Begemanb0a4e452010-06-07 16:00:37 +0000712 ret |= 0x10;
713
714 switch (type) {
715 case 'c':
716 ret |= poly ? 5 : 0;
717 break;
718 case 's':
719 ret |= poly ? 6 : 1;
720 break;
721 case 'i':
722 ret |= 2;
723 break;
724 case 'l':
725 ret |= 3;
726 break;
727 case 'h':
728 ret |= 7;
729 break;
730 case 'f':
731 ret |= 4;
732 break;
733 default:
734 throw "unhandled type!";
735 break;
736 }
737 return ret;
738}
739
Nate Begeman7c8c8832010-06-02 21:53:00 +0000740// Generate the definition for this intrinsic, e.g. __builtin_neon_cls(a)
741// If structTypes is true, the NEON types are structs of vector types rather
742// than vector types, and the call becomes __builtin_neon_cls(a.val)
743static std::string GenBuiltin(const std::string &name, const std::string &proto,
Nate Begemana8979a02010-06-04 00:21:41 +0000744 StringRef typestr, ClassKind ck,
745 bool structTypes = true) {
Nate Begemancc3c41a2010-06-12 03:09:49 +0000746 bool dummy, quad = false;
747 char type = ClassifyType(typestr, quad, dummy, dummy);
748 unsigned nElts = 0;
749 switch (type) {
750 case 'c': nElts = 8; break;
751 case 's': nElts = 4; break;
752 case 'i': nElts = 2; break;
753 case 'l': nElts = 1; break;
754 case 'h': nElts = 4; break;
755 case 'f': nElts = 2; break;
756 }
Chris Lattner5ca96982010-06-12 15:46:56 +0000757 if (quad) nElts <<= 1;
Nate Begemancc3c41a2010-06-12 03:09:49 +0000758
Nate Begeman7c8c8832010-06-02 21:53:00 +0000759 char arg = 'a';
Nate Begeman162d3ba2010-06-03 04:04:09 +0000760 std::string s;
Nate Begeman9e584b32010-06-04 22:53:30 +0000761
Nate Begemanc4a1b652010-06-20 21:09:52 +0000762 // If this builtin returns a struct 2, 3, or 4 vectors, pass it as an implicit
763 // sret-like argument.
764 bool sret = (proto[0] == '2' || proto[0] == '3' || proto[0] == '4');
765
766 // If this builtin takes an immediate argument, we need to #define it rather
767 // than use a standard declaration, so that SemaChecking can range check
768 // the immediate passed by the user.
Nate Begeman6c060db2010-06-09 01:09:00 +0000769 bool define = proto.find('i') != std::string::npos;
Nate Begeman9e584b32010-06-04 22:53:30 +0000770
771 // If all types are the same size, bitcasting the args will take care
772 // of arg checking. The actual signedness etc. will be taken care of with
773 // special enums.
774 if (proto.find('s') == std::string::npos)
775 ck = ClassB;
Nate Begeman7c21f742010-06-04 21:36:00 +0000776
Nate Begeman162d3ba2010-06-03 04:04:09 +0000777 if (proto[0] != 'v') {
Nate Begeman6c060db2010-06-09 01:09:00 +0000778 std::string ts = TypeString(proto[0], typestr);
779
780 if (define) {
Nate Begemanc4a1b652010-06-20 21:09:52 +0000781 if (sret)
782 s += "({ " + ts + " r; ";
783 else if (proto[0] != 's')
Nate Begeman6c060db2010-06-09 01:09:00 +0000784 s += "(" + ts + "){(__neon_" + ts + ")";
Nate Begemanc4a1b652010-06-20 21:09:52 +0000785 } else if (sret) {
786 s += ts + " r; ";
Nate Begeman9e584b32010-06-04 22:53:30 +0000787 } else {
Nate Begemanc4a1b652010-06-20 21:09:52 +0000788 s += ts + " r; r";
Nate Begeman6c060db2010-06-09 01:09:00 +0000789 if (structTypes && proto[0] != 's' && proto[0] != 'i' && proto[0] != 'l')
790 s += ".val";
791
792 s += " = ";
Nate Begeman162d3ba2010-06-03 04:04:09 +0000793 }
Nate Begeman4b425a82010-06-10 00:16:56 +0000794 }
795
796 bool splat = proto.find('a') != std::string::npos;
Nate Begeman7c8c8832010-06-02 21:53:00 +0000797
798 s += "__builtin_neon_";
Nate Begeman4b425a82010-06-10 00:16:56 +0000799 if (splat) {
800 std::string vname(name, 0, name.size()-2);
801 s += MangleName(vname, typestr, ck);
802 } else {
803 s += MangleName(name, typestr, ck);
804 }
Nate Begeman7c8c8832010-06-02 21:53:00 +0000805 s += "(";
Nate Begemanc4a1b652010-06-20 21:09:52 +0000806
807 // Pass the address of the return variable as the first argument to sret-like
808 // builtins.
809 if (sret)
810 s += "&r, ";
Nate Begeman7c8c8832010-06-02 21:53:00 +0000811
812 for (unsigned i = 1, e = proto.size(); i != e; ++i, ++arg) {
Nate Begemancc3c41a2010-06-12 03:09:49 +0000813 std::string args = std::string(&arg, 1);
Nate Begemane5cb26f2010-09-22 22:28:42 +0000814 bool argquad = quad;
815 bool scal = false;
816
817 (void) ModType(proto[i], type, argquad, dummy, dummy, scal, dummy, dummy);
818 bool explicitcast = define && !scal;
819
Nate Begemancc3c41a2010-06-12 03:09:49 +0000820 if (define)
821 args = "(" + args + ")";
Nate Begemane5cb26f2010-09-22 22:28:42 +0000822 if (explicitcast) {
823 unsigned builtinelts = quad ? 16 : 8;
824 args = "(__neon_int8x" + utostr(builtinelts) + "_t)(" + args;
825 }
Nate Begemancc3c41a2010-06-12 03:09:49 +0000826
Nate Begeman9e584b32010-06-04 22:53:30 +0000827 // Handle multiple-vector values specially, emitting each subvector as an
828 // argument to the __builtin.
Nate Begemane5cb26f2010-09-22 22:28:42 +0000829 if (structTypes && (proto[i] >= '2') && (proto[i] <= '4')) {
Nate Begeman9e584b32010-06-04 22:53:30 +0000830 for (unsigned vi = 0, ve = proto[i] - '0'; vi != ve; ++vi) {
Bob Wilsone9c26152010-06-24 22:21:19 +0000831 s += args + ".val[" + utostr(vi) + "].val";
Nate Begemane5cb26f2010-09-22 22:28:42 +0000832 if (explicitcast)
833 s += ")";
834
Nate Begeman9e584b32010-06-04 22:53:30 +0000835 if ((vi + 1) < ve)
836 s += ", ";
837 }
838 if ((i + 1) < e)
839 s += ", ";
840
841 continue;
842 }
843
Nate Begeman4b425a82010-06-10 00:16:56 +0000844 if (splat && (i + 1) == e)
Nate Begemancc3c41a2010-06-12 03:09:49 +0000845 s += Duplicate(nElts, typestr, args);
Nate Begeman4b425a82010-06-10 00:16:56 +0000846 else
Nate Begemancc3c41a2010-06-12 03:09:49 +0000847 s += args;
Nate Begeman9e584b32010-06-04 22:53:30 +0000848
Nate Begemane5cb26f2010-09-22 22:28:42 +0000849 if (structTypes && !scal)
Nate Begeman7c8c8832010-06-02 21:53:00 +0000850 s += ".val";
Nate Begemane5cb26f2010-09-22 22:28:42 +0000851 if (explicitcast)
852 s += ")";
Nate Begeman7c8c8832010-06-02 21:53:00 +0000853 if ((i + 1) < e)
854 s += ", ";
855 }
856
Nate Begeman9e584b32010-06-04 22:53:30 +0000857 // Extra constant integer to hold type class enum for this function, e.g. s8
Nate Begeman9e584b32010-06-04 22:53:30 +0000858 if (ck == ClassB)
Nate Begemanb0a4e452010-06-07 16:00:37 +0000859 s += ", " + utostr(GetNeonEnum(proto, typestr));
Nate Begeman9e584b32010-06-04 22:53:30 +0000860
Nate Begeman6c060db2010-06-09 01:09:00 +0000861 if (define)
862 s += ")";
863 else
864 s += ");";
Nate Begeman9e584b32010-06-04 22:53:30 +0000865
866 if (proto[0] != 'v') {
Nate Begeman6c060db2010-06-09 01:09:00 +0000867 if (define) {
Nate Begemanc4a1b652010-06-20 21:09:52 +0000868 if (sret)
869 s += "; r; })";
870 else if (proto[0] != 's')
Nate Begeman6c060db2010-06-09 01:09:00 +0000871 s += "}";
872 } else {
Nate Begemanc4a1b652010-06-20 21:09:52 +0000873 s += " return r;";
Nate Begeman6c060db2010-06-09 01:09:00 +0000874 }
Nate Begeman9e584b32010-06-04 22:53:30 +0000875 }
Nate Begeman7c8c8832010-06-02 21:53:00 +0000876 return s;
Nate Begemane66aab52010-06-02 07:14:28 +0000877}
878
Nate Begeman73cef3e2010-06-04 01:26:15 +0000879static std::string GenBuiltinDef(const std::string &name,
880 const std::string &proto,
881 StringRef typestr, ClassKind ck) {
882 std::string s("BUILTIN(__builtin_neon_");
Nate Begeman92f98af2010-06-04 07:11:25 +0000883
884 // If all types are the same size, bitcasting the args will take care
885 // of arg checking. The actual signedness etc. will be taken care of with
886 // special enums.
887 if (proto.find('s') == std::string::npos)
888 ck = ClassB;
889
Nate Begeman73cef3e2010-06-04 01:26:15 +0000890 s += MangleName(name, typestr, ck);
891 s += ", \"";
892
Nate Begeman92f98af2010-06-04 07:11:25 +0000893 for (unsigned i = 0, e = proto.size(); i != e; ++i)
Nate Begeman7c21f742010-06-04 21:36:00 +0000894 s += BuiltinTypeString(proto[i], typestr, ck, i == 0);
895
896 // Extra constant integer to hold type class enum for this function, e.g. s8
897 if (ck == ClassB)
898 s += "i";
Nate Begeman73cef3e2010-06-04 01:26:15 +0000899
900 s += "\", \"n\")";
901 return s;
902}
903
Nate Begemand72c9002010-06-13 04:47:03 +0000904/// run - Read the records in arm_neon.td and output arm_neon.h. arm_neon.h
905/// is comprised of type definitions and function declarations.
Nate Begeman5ddb0872010-05-28 01:08:32 +0000906void NeonEmitter::run(raw_ostream &OS) {
907 EmitSourceFileHeader("ARM NEON Header", OS);
908
909 // FIXME: emit license into file?
910
911 OS << "#ifndef __ARM_NEON_H\n";
912 OS << "#define __ARM_NEON_H\n\n";
913
914 OS << "#ifndef __ARM_NEON__\n";
915 OS << "#error \"NEON support not enabled\"\n";
916 OS << "#endif\n\n";
917
918 OS << "#include <stdint.h>\n\n";
Nate Begeman7c8c8832010-06-02 21:53:00 +0000919
920 // Emit NEON-specific scalar typedefs.
Nate Begeman7c8c8832010-06-02 21:53:00 +0000921 OS << "typedef float float32_t;\n";
922 OS << "typedef uint8_t poly8_t;\n";
923 OS << "typedef uint16_t poly16_t;\n";
Nate Begeman162d3ba2010-06-03 04:04:09 +0000924 OS << "typedef uint16_t float16_t;\n";
Nate Begeman9e584b32010-06-04 22:53:30 +0000925
Nate Begeman7c8c8832010-06-02 21:53:00 +0000926 // Emit Neon vector typedefs.
927 std::string TypedefTypes("cQcsQsiQilQlUcQUcUsQUsUiQUiUlQUlhQhfQfPcQPcPsQPs");
928 SmallVector<StringRef, 24> TDTypeVec;
929 ParseTypes(0, TypedefTypes, TDTypeVec);
930
931 // Emit vector typedefs.
Nate Begeman9e584b32010-06-04 22:53:30 +0000932 for (unsigned v = 1; v != 5; ++v) {
933 for (unsigned i = 0, e = TDTypeVec.size(); i != e; ++i) {
934 bool dummy, quad = false;
935 (void) ClassifyType(TDTypeVec[i], quad, dummy, dummy);
936 OS << "typedef __attribute__(( __vector_size__(";
937
938 OS << utostr(8*v*(quad ? 2 : 1)) << ") )) ";
Bob Wilson72774c92010-09-14 21:52:34 +0000939 if (!quad && v == 1)
Nate Begeman9e584b32010-06-04 22:53:30 +0000940 OS << " ";
941
942 OS << TypeString('s', TDTypeVec[i]);
943 OS << " __neon_";
944
945 char t = (v == 1) ? 'd' : '0' + v;
946 OS << TypeString(t, TDTypeVec[i]) << ";\n";
947 }
Nate Begeman7c8c8832010-06-02 21:53:00 +0000948 }
949 OS << "\n";
Bob Wilsonee9ca072010-09-15 01:52:33 +0000950 OS << "typedef __attribute__(( __vector_size__(8) )) "
951 "double __neon_float64x1_t;\n";
952 OS << "typedef __attribute__(( __vector_size__(16) )) "
953 "double __neon_float64x2_t;\n";
954 OS << "\n";
Nate Begeman7c8c8832010-06-02 21:53:00 +0000955
956 // Emit struct typedefs.
957 for (unsigned vi = 1; vi != 5; ++vi) {
958 for (unsigned i = 0, e = TDTypeVec.size(); i != e; ++i) {
Bob Wilson9969bc32010-06-24 22:03:41 +0000959 std::string ts = TypeString('d', TDTypeVec[i], vi == 1);
960 std::string vs = TypeString((vi > 1) ? '0' + vi : 'd', TDTypeVec[i]);
961 std::string tag = (vi > 1) ? vs : StructTag(TDTypeVec[i]);
962 OS << "typedef struct " << tag << " {\n";
963 OS << " " << ts << " val";
Nate Begeman7c8c8832010-06-02 21:53:00 +0000964 if (vi > 1)
965 OS << "[" << utostr(vi) << "]";
966 OS << ";\n} " << vs << ";\n\n";
967 }
968 }
Nate Begeman5ddb0872010-05-28 01:08:32 +0000969
Nate Begeman7c8c8832010-06-02 21:53:00 +0000970 OS << "#define __ai static __attribute__((__always_inline__))\n\n";
971
Nate Begeman5ddb0872010-05-28 01:08:32 +0000972 std::vector<Record*> RV = Records.getAllDerivedDefinitions("Inst");
973
Nate Begeman22237772010-06-02 00:34:55 +0000974 // Unique the return+pattern types, and assign them.
Nate Begeman5ddb0872010-05-28 01:08:32 +0000975 for (unsigned i = 0, e = RV.size(); i != e; ++i) {
976 Record *R = RV[i];
Nate Begeman22237772010-06-02 00:34:55 +0000977 std::string name = LowercaseString(R->getName());
978 std::string Proto = R->getValueAsString("Prototype");
Nate Begeman5ddb0872010-05-28 01:08:32 +0000979 std::string Types = R->getValueAsString("Types");
Nate Begeman22237772010-06-02 00:34:55 +0000980
981 SmallVector<StringRef, 16> TypeVec;
982 ParseTypes(R, Types, TypeVec);
983
Nate Begeman162d3ba2010-06-03 04:04:09 +0000984 OpKind k = OpMap[R->getValueAsDef("Operand")->getName()];
Nate Begemane66aab52010-06-02 07:14:28 +0000985
Nate Begeman6c060db2010-06-09 01:09:00 +0000986 bool define = Proto.find('i') != std::string::npos;
987
Nate Begeman22237772010-06-02 00:34:55 +0000988 for (unsigned ti = 0, te = TypeVec.size(); ti != te; ++ti) {
989 assert(!Proto.empty() && "");
990
Nate Begeman7c8c8832010-06-02 21:53:00 +0000991 // static always inline + return type
Nate Begeman6c060db2010-06-09 01:09:00 +0000992 if (define)
993 OS << "#define";
994 else
995 OS << "__ai " << TypeString(Proto[0], TypeVec[ti]);
Nate Begeman22237772010-06-02 00:34:55 +0000996
Nate Begemane66aab52010-06-02 07:14:28 +0000997 // Function name with type suffix
Nate Begemana8979a02010-06-04 00:21:41 +0000998 OS << " " << MangleName(name, TypeVec[ti], ClassS);
Nate Begeman22237772010-06-02 00:34:55 +0000999
Nate Begemane66aab52010-06-02 07:14:28 +00001000 // Function arguments
1001 OS << GenArgs(Proto, TypeVec[ti]);
Nate Begeman22237772010-06-02 00:34:55 +00001002
Nate Begemane66aab52010-06-02 07:14:28 +00001003 // Definition.
Nate Begeman6c060db2010-06-09 01:09:00 +00001004 if (define)
1005 OS << " ";
1006 else
1007 OS << " { ";
Nate Begeman22237772010-06-02 00:34:55 +00001008
Nate Begemana8979a02010-06-04 00:21:41 +00001009 if (k != OpNone) {
Nate Begeman162d3ba2010-06-03 04:04:09 +00001010 OS << GenOpString(k, Proto, TypeVec[ti]);
Nate Begemana8979a02010-06-04 00:21:41 +00001011 } else {
1012 if (R->getSuperClasses().size() < 2)
1013 throw TGError(R->getLoc(), "Builtin has no class kind");
1014
1015 ClassKind ck = ClassMap[R->getSuperClasses()[1]];
1016
1017 if (ck == ClassNone)
1018 throw TGError(R->getLoc(), "Builtin has no class kind");
1019 OS << GenBuiltin(name, Proto, TypeVec[ti], ck);
1020 }
Nate Begeman6c060db2010-06-09 01:09:00 +00001021 if (!define)
1022 OS << " }";
1023 OS << "\n";
Nate Begeman22237772010-06-02 00:34:55 +00001024 }
1025 OS << "\n";
Nate Begeman5ddb0872010-05-28 01:08:32 +00001026 }
Nate Begeman73cef3e2010-06-04 01:26:15 +00001027 OS << "#undef __ai\n\n";
Nate Begeman7c8c8832010-06-02 21:53:00 +00001028 OS << "#endif /* __ARM_NEON_H */\n";
Nate Begeman5ddb0872010-05-28 01:08:32 +00001029}
Nate Begemana8979a02010-06-04 00:21:41 +00001030
Nate Begeman918f8e42010-06-14 05:17:23 +00001031static unsigned RangeFromType(StringRef typestr) {
1032 // base type to get the type string for.
1033 bool quad = false, dummy = false;
1034 char type = ClassifyType(typestr, quad, dummy, dummy);
1035
1036 switch (type) {
1037 case 'c':
Nate Begeman4da883a2010-06-15 22:10:31 +00001038 return (8 << (int)quad) - 1;
Nate Begeman918f8e42010-06-14 05:17:23 +00001039 case 'h':
1040 case 's':
Nate Begeman4da883a2010-06-15 22:10:31 +00001041 return (4 << (int)quad) - 1;
Nate Begeman918f8e42010-06-14 05:17:23 +00001042 case 'f':
1043 case 'i':
Nate Begeman4da883a2010-06-15 22:10:31 +00001044 return (2 << (int)quad) - 1;
Nate Begeman918f8e42010-06-14 05:17:23 +00001045 case 'l':
Nate Begeman4da883a2010-06-15 22:10:31 +00001046 return (1 << (int)quad) - 1;
Nate Begeman918f8e42010-06-14 05:17:23 +00001047 default:
1048 throw "unhandled type!";
1049 break;
1050 }
Bob Wilsonfdb530d2010-07-28 18:21:10 +00001051 assert(0 && "unreachable");
1052 return 0;
Nate Begeman918f8e42010-06-14 05:17:23 +00001053}
1054
Nate Begemanf8c4c272010-06-17 04:15:13 +00001055/// runHeader - Emit a file with sections defining:
1056/// 1. the NEON section of BuiltinsARM.def.
1057/// 2. the SemaChecking code for the type overload checking.
1058/// 3. the SemaChecking code for validation of intrinsic immedate arguments.
Nate Begemana8979a02010-06-04 00:21:41 +00001059void NeonEmitter::runHeader(raw_ostream &OS) {
Nate Begeman73cef3e2010-06-04 01:26:15 +00001060 std::vector<Record*> RV = Records.getAllDerivedDefinitions("Inst");
1061
1062 StringMap<OpKind> EmittedMap;
1063
Nate Begemanf8c4c272010-06-17 04:15:13 +00001064 // Generate BuiltinsARM.def for NEON
1065 OS << "#ifdef GET_NEON_BUILTINS\n";
Nate Begeman73cef3e2010-06-04 01:26:15 +00001066 for (unsigned i = 0, e = RV.size(); i != e; ++i) {
1067 Record *R = RV[i];
Nate Begeman73cef3e2010-06-04 01:26:15 +00001068 OpKind k = OpMap[R->getValueAsDef("Operand")->getName()];
1069 if (k != OpNone)
1070 continue;
Nate Begeman73cef3e2010-06-04 01:26:15 +00001071
Nate Begemanf8c4c272010-06-17 04:15:13 +00001072 std::string Proto = R->getValueAsString("Prototype");
1073
Nate Begemand72c9002010-06-13 04:47:03 +00001074 // Functions with 'a' (the splat code) in the type prototype should not get
1075 // their own builtin as they use the non-splat variant.
Nate Begeman4b425a82010-06-10 00:16:56 +00001076 if (Proto.find('a') != std::string::npos)
1077 continue;
Nate Begemand72c9002010-06-13 04:47:03 +00001078
Nate Begemanf8c4c272010-06-17 04:15:13 +00001079 std::string Types = R->getValueAsString("Types");
Nate Begeman73cef3e2010-06-04 01:26:15 +00001080 SmallVector<StringRef, 16> TypeVec;
1081 ParseTypes(R, Types, TypeVec);
Nate Begemand72c9002010-06-13 04:47:03 +00001082
Nate Begeman73cef3e2010-06-04 01:26:15 +00001083 if (R->getSuperClasses().size() < 2)
1084 throw TGError(R->getLoc(), "Builtin has no class kind");
1085
Nate Begemanf8c4c272010-06-17 04:15:13 +00001086 std::string name = LowercaseString(R->getName());
Nate Begeman73cef3e2010-06-04 01:26:15 +00001087 ClassKind ck = ClassMap[R->getSuperClasses()[1]];
1088
1089 for (unsigned ti = 0, te = TypeVec.size(); ti != te; ++ti) {
Nate Begemand72c9002010-06-13 04:47:03 +00001090 // Generate the BuiltinsARM.def declaration for this builtin, ensuring
1091 // that each unique BUILTIN() macro appears only once in the output
1092 // stream.
Nate Begeman73cef3e2010-06-04 01:26:15 +00001093 std::string bd = GenBuiltinDef(name, Proto, TypeVec[ti], ck);
1094 if (EmittedMap.count(bd))
1095 continue;
1096
1097 EmittedMap[bd] = OpNone;
1098 OS << bd << "\n";
1099 }
Nate Begemanf8c4c272010-06-17 04:15:13 +00001100 }
1101 OS << "#endif\n\n";
1102
1103 // Generate the overloaded type checking code for SemaChecking.cpp
1104 OS << "#ifdef GET_NEON_OVERLOAD_CHECK\n";
1105 for (unsigned i = 0, e = RV.size(); i != e; ++i) {
1106 Record *R = RV[i];
1107 OpKind k = OpMap[R->getValueAsDef("Operand")->getName()];
1108 if (k != OpNone)
Nate Begemand72c9002010-06-13 04:47:03 +00001109 continue;
Nate Begemanf8c4c272010-06-17 04:15:13 +00001110
1111 std::string Proto = R->getValueAsString("Prototype");
1112 std::string Types = R->getValueAsString("Types");
1113 std::string name = LowercaseString(R->getName());
1114
1115 // Functions with 'a' (the splat code) in the type prototype should not get
1116 // their own builtin as they use the non-splat variant.
1117 if (Proto.find('a') != std::string::npos)
1118 continue;
1119
1120 // Functions which have a scalar argument cannot be overloaded, no need to
1121 // check them if we are emitting the type checking code.
1122 if (Proto.find('s') != std::string::npos)
1123 continue;
1124
1125 SmallVector<StringRef, 16> TypeVec;
1126 ParseTypes(R, Types, TypeVec);
1127
1128 if (R->getSuperClasses().size() < 2)
1129 throw TGError(R->getLoc(), "Builtin has no class kind");
1130
1131 int si = -1, qi = -1;
1132 unsigned mask = 0, qmask = 0;
1133 for (unsigned ti = 0, te = TypeVec.size(); ti != te; ++ti) {
1134 // Generate the switch case(s) for this builtin for the type validation.
1135 bool quad = false, poly = false, usgn = false;
1136 (void) ClassifyType(TypeVec[ti], quad, poly, usgn);
1137
1138 if (quad) {
1139 qi = ti;
1140 qmask |= 1 << GetNeonEnum(Proto, TypeVec[ti]);
1141 } else {
1142 si = ti;
1143 mask |= 1 << GetNeonEnum(Proto, TypeVec[ti]);
1144 }
1145 }
1146 if (mask)
1147 OS << "case ARM::BI__builtin_neon_"
1148 << MangleName(name, TypeVec[si], ClassB)
1149 << ": mask = " << "0x" << utohexstr(mask) << "; break;\n";
1150 if (qmask)
1151 OS << "case ARM::BI__builtin_neon_"
1152 << MangleName(name, TypeVec[qi], ClassB)
1153 << ": mask = " << "0x" << utohexstr(qmask) << "; break;\n";
1154 }
1155 OS << "#endif\n\n";
1156
1157 // Generate the intrinsic range checking code for shift/lane immediates.
1158 OS << "#ifdef GET_NEON_IMMEDIATE_CHECK\n";
1159 for (unsigned i = 0, e = RV.size(); i != e; ++i) {
1160 Record *R = RV[i];
1161
1162 OpKind k = OpMap[R->getValueAsDef("Operand")->getName()];
1163 if (k != OpNone)
1164 continue;
1165
1166 std::string name = LowercaseString(R->getName());
1167 std::string Proto = R->getValueAsString("Prototype");
1168 std::string Types = R->getValueAsString("Types");
1169
1170 // Functions with 'a' (the splat code) in the type prototype should not get
1171 // their own builtin as they use the non-splat variant.
1172 if (Proto.find('a') != std::string::npos)
1173 continue;
1174
1175 // Functions which do not have an immediate do not need to have range
1176 // checking code emitted.
1177 if (Proto.find('i') == std::string::npos)
1178 continue;
1179
1180 SmallVector<StringRef, 16> TypeVec;
1181 ParseTypes(R, Types, TypeVec);
1182
1183 if (R->getSuperClasses().size() < 2)
1184 throw TGError(R->getLoc(), "Builtin has no class kind");
1185
1186 ClassKind ck = ClassMap[R->getSuperClasses()[1]];
1187
1188 for (unsigned ti = 0, te = TypeVec.size(); ti != te; ++ti) {
1189 std::string namestr, shiftstr, rangestr;
1190
1191 // Builtins which are overloaded by type will need to have their upper
1192 // bound computed at Sema time based on the type constant.
1193 if (Proto.find('s') == std::string::npos) {
1194 ck = ClassB;
1195 if (R->getValueAsBit("isShift")) {
1196 shiftstr = ", true";
1197
1198 // Right shifts have an 'r' in the name, left shifts do not.
1199 if (name.find('r') != std::string::npos)
1200 rangestr = "l = 1; ";
1201 }
1202 rangestr += "u = RFT(TV" + shiftstr + ")";
1203 } else {
1204 rangestr = "u = " + utostr(RangeFromType(TypeVec[ti]));
1205 }
Nate Begemanc4a1b652010-06-20 21:09:52 +00001206 // Make sure cases appear only once by uniquing them in a string map.
Nate Begemanf8c4c272010-06-17 04:15:13 +00001207 namestr = MangleName(name, TypeVec[ti], ck);
1208 if (EmittedMap.count(namestr))
1209 continue;
1210 EmittedMap[namestr] = OpNone;
Nate Begemanc4a1b652010-06-20 21:09:52 +00001211
1212 // Calculate the index of the immediate that should be range checked.
Nate Begemanf8c4c272010-06-17 04:15:13 +00001213 unsigned immidx = 0;
Nate Begemanc4a1b652010-06-20 21:09:52 +00001214
1215 // Builtins that return a struct of multiple vectors have an extra
1216 // leading arg for the struct return.
1217 if (Proto[0] == '2' || Proto[0] == '3' || Proto[0] == '4')
1218 ++immidx;
1219
1220 // Add one to the index for each argument until we reach the immediate
1221 // to be checked. Structs of vectors are passed as multiple arguments.
Nate Begemanf8c4c272010-06-17 04:15:13 +00001222 for (unsigned ii = 1, ie = Proto.size(); ii != ie; ++ii) {
1223 switch (Proto[ii]) {
1224 default: immidx += 1; break;
1225 case '2': immidx += 2; break;
1226 case '3': immidx += 3; break;
1227 case '4': immidx += 4; break;
1228 case 'i': ie = ii + 1; break;
1229 }
1230 }
1231 OS << "case ARM::BI__builtin_neon_" << MangleName(name, TypeVec[ti], ck)
1232 << ": i = " << immidx << "; " << rangestr << "; break;\n";
Nate Begemand72c9002010-06-13 04:47:03 +00001233 }
Nate Begeman73cef3e2010-06-04 01:26:15 +00001234 }
Nate Begemanf8c4c272010-06-17 04:15:13 +00001235 OS << "#endif\n\n";
Nate Begemana8979a02010-06-04 00:21:41 +00001236}