blob: 8b90bb18c1f5349a09bd04600f6a47df4635ffca [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//
14//===----------------------------------------------------------------------===//
15
16#include "NeonEmitter.h"
Nate Begeman22237772010-06-02 00:34:55 +000017#include "llvm/ADT/SmallString.h"
18#include "llvm/ADT/SmallVector.h"
Nate Begeman5ddb0872010-05-28 01:08:32 +000019#include "llvm/ADT/StringExtras.h"
Nate Begeman5ddb0872010-05-28 01:08:32 +000020#include <string>
21
22using namespace llvm;
23
Nate Begeman22237772010-06-02 00:34:55 +000024static void ParseTypes(Record *r, std::string &s,
25 SmallVectorImpl<StringRef> &TV) {
26 const char *data = s.data();
27 int len = 0;
28
29 for (unsigned i = 0, e = s.size(); i != e; ++i, ++len) {
30 if (data[len] == 'P' || data[len] == 'Q' || data[len] == 'U')
31 continue;
32
33 switch (data[len]) {
34 case 'c':
35 case 's':
36 case 'i':
37 case 'l':
38 case 'h':
39 case 'f':
40 break;
41 default:
42 throw TGError(r->getLoc(),
43 "Unexpected letter: " + std::string(data + len, 1));
44 break;
45 }
46 TV.push_back(StringRef(data, len + 1));
47 data += len + 1;
48 len = -1;
49 }
50}
51
Duncan Sands8dbbace2010-06-02 08:37:30 +000052static char Widen(const char t) {
Nate Begeman22237772010-06-02 00:34:55 +000053 switch (t) {
54 case 'c':
55 return 's';
56 case 's':
57 return 'i';
58 case 'i':
59 return 'l';
60 default: throw "unhandled type in widen!";
61 }
62 return '\0';
63}
64
Nate Begeman3861e742010-06-03 21:35:22 +000065static char Narrow(const char t) {
66 switch (t) {
67 case 's':
68 return 'c';
69 case 'i':
70 return 's';
71 case 'l':
72 return 'i';
Nate Begeman900f4672010-06-08 00:14:42 +000073 case 'f':
74 return 'h';
Nate Begeman3861e742010-06-03 21:35:22 +000075 default: throw "unhandled type in widen!";
76 }
77 return '\0';
78}
79
Nate Begemanaf905ef2010-06-02 06:17:19 +000080static char ClassifyType(StringRef ty, bool &quad, bool &poly, bool &usgn) {
Nate Begeman22237772010-06-02 00:34:55 +000081 unsigned off = 0;
82
Nate Begemanaf905ef2010-06-02 06:17:19 +000083 // remember quad.
84 if (ty[off] == 'Q') {
85 quad = true;
86 ++off;
87 }
88
89 // remember poly.
90 if (ty[off] == 'P') {
91 poly = true;
92 ++off;
93 }
94
95 // remember unsigned.
96 if (ty[off] == 'U') {
97 usgn = true;
98 ++off;
99 }
100
101 // base type to get the type string for.
102 return ty[off];
103}
104
Nate Begemanb0a4e452010-06-07 16:00:37 +0000105static char ModType(const char mod, char type, bool &quad, bool &poly,
106 bool &usgn, bool &scal, bool &cnst, bool &pntr) {
Nate Begeman22237772010-06-02 00:34:55 +0000107 switch (mod) {
Nate Begeman22237772010-06-02 00:34:55 +0000108 case 't':
109 if (poly) {
110 poly = false;
111 usgn = true;
112 }
113 break;
Nate Begeman900f4672010-06-08 00:14:42 +0000114 case 'u':
Nate Begeman22237772010-06-02 00:34:55 +0000115 usgn = true;
Nate Begeman900f4672010-06-08 00:14:42 +0000116 case 'x':
Nate Begeman162d3ba2010-06-03 04:04:09 +0000117 poly = false;
Nate Begeman22237772010-06-02 00:34:55 +0000118 if (type == 'f')
119 type = 'i';
120 break;
121 case 'f':
Nate Begeman900f4672010-06-08 00:14:42 +0000122 if (type == 'h')
123 quad = true;
Nate Begeman22237772010-06-02 00:34:55 +0000124 type = 'f';
Nate Begeman162d3ba2010-06-03 04:04:09 +0000125 usgn = false;
Nate Begeman22237772010-06-02 00:34:55 +0000126 break;
127 case 'w':
128 type = Widen(type);
129 quad = true;
130 break;
131 case 'n':
132 type = Widen(type);
133 break;
Nate Begeman22237772010-06-02 00:34:55 +0000134 case 'l':
135 type = 'l';
136 scal = true;
137 usgn = true;
138 break;
139 case 's':
140 scal = true;
141 break;
142 case 'k':
143 quad = true;
144 break;
145 case 'c':
146 cnst = true;
147 case 'p':
Nate Begemanb0a4e452010-06-07 16:00:37 +0000148 usgn = false;
149 poly = false;
Nate Begeman22237772010-06-02 00:34:55 +0000150 pntr = true;
151 scal = true;
152 break;
Nate Begeman3861e742010-06-03 21:35:22 +0000153 case 'h':
154 type = Narrow(type);
Nate Begeman900f4672010-06-08 00:14:42 +0000155 if (type == 'h')
156 quad = false;
Nate Begeman3861e742010-06-03 21:35:22 +0000157 break;
158 case 'e':
159 type = Narrow(type);
160 usgn = true;
161 break;
Nate Begeman22237772010-06-02 00:34:55 +0000162 default:
163 break;
164 }
Nate Begemanb0a4e452010-06-07 16:00:37 +0000165 return type;
166}
167
168static std::string TypeString(const char mod, StringRef typestr,
169 bool ret = false) {
170 bool quad = false;
171 bool poly = false;
172 bool usgn = false;
173 bool scal = false;
174 bool cnst = false;
175 bool pntr = false;
176
177 if (mod == 'v')
178 return "void";
179 if (mod == 'i')
180 return "int";
181
182 // base type to get the type string for.
183 char type = ClassifyType(typestr, quad, poly, usgn);
184
185 // Based on the modifying character, change the type and width if necessary.
186 type = ModType(mod, type, quad, poly, usgn, scal, cnst, pntr);
Nate Begeman22237772010-06-02 00:34:55 +0000187
188 SmallString<128> s;
189
Nate Begeman9e584b32010-06-04 22:53:30 +0000190 if (ret)
191 s += "__neon_";
192
Nate Begeman22237772010-06-02 00:34:55 +0000193 if (usgn)
194 s.push_back('u');
195
196 switch (type) {
197 case 'c':
198 s += poly ? "poly8" : "int8";
199 if (scal)
200 break;
201 s += quad ? "x16" : "x8";
202 break;
203 case 's':
204 s += poly ? "poly16" : "int16";
205 if (scal)
206 break;
207 s += quad ? "x8" : "x4";
208 break;
209 case 'i':
210 s += "int32";
211 if (scal)
212 break;
213 s += quad ? "x4" : "x2";
214 break;
215 case 'l':
216 s += "int64";
217 if (scal)
218 break;
219 s += quad ? "x2" : "x1";
220 break;
221 case 'h':
222 s += "float16";
223 if (scal)
224 break;
225 s += quad ? "x8" : "x4";
226 break;
227 case 'f':
228 s += "float32";
229 if (scal)
230 break;
231 s += quad ? "x4" : "x2";
232 break;
Nate Begeman22237772010-06-02 00:34:55 +0000233 default:
234 throw "unhandled type!";
235 break;
236 }
237
238 if (mod == '2')
239 s += "x2";
240 if (mod == '3')
241 s += "x3";
242 if (mod == '4')
243 s += "x4";
244
245 // Append _t, finishing the type string typedef type.
246 s += "_t";
247
248 if (cnst)
249 s += " const";
250
251 if (pntr)
252 s += " *";
253
254 return s.str();
255}
256
Nate Begeman7c21f742010-06-04 21:36:00 +0000257static std::string BuiltinTypeString(const char mod, StringRef typestr,
258 ClassKind ck, bool ret) {
Nate Begeman92f98af2010-06-04 07:11:25 +0000259 bool quad = false;
260 bool poly = false;
261 bool usgn = false;
262 bool scal = false;
263 bool cnst = false;
264 bool pntr = false;
265
266 if (mod == 'v')
267 return "v";
268 if (mod == 'i')
269 return "i";
270
271 // base type to get the type string for.
272 char type = ClassifyType(typestr, quad, poly, usgn);
273
274 // Based on the modifying character, change the type and width if necessary.
Nate Begemanb0a4e452010-06-07 16:00:37 +0000275 type = ModType(mod, type, quad, poly, usgn, scal, cnst, pntr);
276
277 if (pntr)
278 type = 'v';
279
Nate Begeman92f98af2010-06-04 07:11:25 +0000280 if (type == 'h') {
281 type = 's';
282 usgn = true;
283 }
Nate Begeman7c21f742010-06-04 21:36:00 +0000284 usgn = usgn | poly | ((ck == ClassI || ck == ClassW) && scal && type != 'f');
Nate Begeman92f98af2010-06-04 07:11:25 +0000285
286 if (scal) {
287 SmallString<128> s;
288
289 if (usgn)
290 s.push_back('U');
Nate Begeman7c21f742010-06-04 21:36:00 +0000291
292 if (type == 'l')
293 s += "LLi";
294 else
295 s.push_back(type);
296
Nate Begeman92f98af2010-06-04 07:11:25 +0000297 if (cnst)
298 s.push_back('C');
299 if (pntr)
300 s.push_back('*');
301 return s.str();
302 }
Nate Begeman7c21f742010-06-04 21:36:00 +0000303
304 // Since the return value must be one type, return a vector type of the
305 // appropriate width which we will bitcast.
306 if (ret) {
307 if (mod == '2')
308 return quad ? "V32c" : "V16c";
309 if (mod == '3')
310 return quad ? "V48c" : "V24c";
311 if (mod == '4')
312 return quad ? "V64c" : "V32c";
Nate Begeman007afe42010-06-09 05:11:55 +0000313 if (mod == 'f' || (ck == ClassI && type == 'f'))
Nate Begeman56387832010-06-08 06:01:16 +0000314 return quad ? "V4f" : "V2f";
Nate Begeman007afe42010-06-09 05:11:55 +0000315 if (ck == ClassI && type == 's')
316 return quad ? "V8s" : "V4s";
317 if (ck == ClassI && type == 'i')
Nate Begeman56387832010-06-08 06:01:16 +0000318 return quad ? "V4i" : "V2i";
Nate Begeman007afe42010-06-09 05:11:55 +0000319 if (ck == ClassI && type == 'l')
320 return quad ? "V2LLi" : "V1LLi";
Nate Begeman900f4672010-06-08 00:14:42 +0000321
Nate Begeman7c21f742010-06-04 21:36:00 +0000322 return quad ? "V16c" : "V8c";
323 }
324
325 // Non-return array types are passed as individual vectors.
Nate Begeman92f98af2010-06-04 07:11:25 +0000326 if (mod == '2')
327 return quad ? "V16cV16c" : "V8cV8c";
328 if (mod == '3')
329 return quad ? "V16cV16cV16c" : "V8cV8cV8c";
330 if (mod == '4')
331 return quad ? "V16cV16cV16cV16c" : "V8cV8cV8cV8c";
332
Nate Begeman007afe42010-06-09 05:11:55 +0000333 if (mod == 'f' || (ck == ClassI && type == 'f'))
334 return quad ? "V4f" : "V2f";
335 if (ck == ClassI && type == 's')
336 return quad ? "V8s" : "V4s";
337 if (ck == ClassI && type == 'i')
338 return quad ? "V4i" : "V2i";
339 if (ck == ClassI && type == 'l')
340 return quad ? "V2LLi" : "V1LLi";
341
Nate Begeman92f98af2010-06-04 07:11:25 +0000342 return quad ? "V16c" : "V8c";
343}
344
Nate Begeman22237772010-06-02 00:34:55 +0000345// Turn "vst2_lane" into "vst2q_lane_f32", etc.
Nate Begemana8979a02010-06-04 00:21:41 +0000346static std::string MangleName(const std::string &name, StringRef typestr,
347 ClassKind ck) {
Nate Begeman900f4672010-06-08 00:14:42 +0000348 if (name == "vcvt_f32_f16")
349 return name;
350
Nate Begemanaf905ef2010-06-02 06:17:19 +0000351 bool quad = false;
352 bool poly = false;
353 bool usgn = false;
354 char type = ClassifyType(typestr, quad, poly, usgn);
355
356 std::string s = name;
357
358 switch (type) {
Nate Begemana8979a02010-06-04 00:21:41 +0000359 case 'c':
360 switch (ck) {
361 case ClassS: s += poly ? "_p8" : usgn ? "_u8" : "_s8"; break;
362 case ClassI: s += "_i8"; break;
363 case ClassW: s += "_8"; break;
364 default: break;
365 }
366 break;
367 case 's':
368 switch (ck) {
369 case ClassS: s += poly ? "_p16" : usgn ? "_u16" : "_s16"; break;
370 case ClassI: s += "_i16"; break;
371 case ClassW: s += "_16"; break;
372 default: break;
373 }
374 break;
375 case 'i':
376 switch (ck) {
377 case ClassS: s += usgn ? "_u32" : "_s32"; break;
378 case ClassI: s += "_i32"; break;
379 case ClassW: s += "_32"; break;
380 default: break;
381 }
382 break;
383 case 'l':
384 switch (ck) {
385 case ClassS: s += usgn ? "_u64" : "_s64"; break;
386 case ClassI: s += "_i64"; break;
387 case ClassW: s += "_64"; break;
388 default: break;
389 }
390 break;
391 case 'h':
392 switch (ck) {
393 case ClassS:
394 case ClassI: s += "_f16"; break;
395 case ClassW: s += "_16"; break;
396 default: break;
397 }
398 break;
399 case 'f':
400 switch (ck) {
401 case ClassS:
402 case ClassI: s += "_f32"; break;
403 case ClassW: s += "_32"; break;
404 default: break;
405 }
406 break;
407 default:
408 throw "unhandled type!";
409 break;
Nate Begemanaf905ef2010-06-02 06:17:19 +0000410 }
Nate Begemana8979a02010-06-04 00:21:41 +0000411 if (ck == ClassB)
Nate Begeman92f98af2010-06-04 07:11:25 +0000412 s += "_v";
Nate Begemana8979a02010-06-04 00:21:41 +0000413
Nate Begemanaf905ef2010-06-02 06:17:19 +0000414 // Insert a 'q' before the first '_' character so that it ends up before
415 // _lane or _n on vector-scalar operations.
416 if (quad) {
417 size_t pos = s.find('_');
418 s = s.insert(pos, "q");
419 }
420 return s;
Nate Begeman22237772010-06-02 00:34:55 +0000421}
422
Nate Begemanaf905ef2010-06-02 06:17:19 +0000423// Generate the string "(argtype a, argtype b, ...)"
Nate Begeman22237772010-06-02 00:34:55 +0000424static std::string GenArgs(const std::string &proto, StringRef typestr) {
Nate Begeman6c060db2010-06-09 01:09:00 +0000425 bool define = proto.find('i') != std::string::npos;
Nate Begemanaf905ef2010-06-02 06:17:19 +0000426 char arg = 'a';
427
428 std::string s;
429 s += "(";
430
431 for (unsigned i = 1, e = proto.size(); i != e; ++i, ++arg) {
Nate Begeman6c060db2010-06-09 01:09:00 +0000432 if (!define) {
433 s += TypeString(proto[i], typestr);
434 s.push_back(' ');
435 }
Nate Begemanaf905ef2010-06-02 06:17:19 +0000436 s.push_back(arg);
437 if ((i + 1) < e)
438 s += ", ";
439 }
440
441 s += ")";
442 return s;
Nate Begeman22237772010-06-02 00:34:55 +0000443}
444
Nate Begeman7c8c8832010-06-02 21:53:00 +0000445// Generate the definition for this intrinsic, e.g. "a + b" for OpAdd.
446// If structTypes is true, the NEON types are structs of vector types rather
447// than vector types, and the call becomes "a.val + b.val"
448static std::string GenOpString(OpKind op, const std::string &proto,
Nate Begeman162d3ba2010-06-03 04:04:09 +0000449 StringRef typestr, bool structTypes = true) {
Nate Begeman9e584b32010-06-04 22:53:30 +0000450 std::string ts = TypeString(proto[0], typestr);
Nate Begeman900f4672010-06-08 00:14:42 +0000451 std::string s = ts + " r; r";
452
Nate Begeman96ec22d2010-06-08 07:11:17 +0000453 bool dummy, quad = false;
Nate Begeman900f4672010-06-08 00:14:42 +0000454 char type = ClassifyType(typestr, quad, dummy, dummy);
455 unsigned nElts = 0;
456 switch (type) {
457 case 'c': nElts = 8; break;
458 case 's': nElts = 4; break;
459 case 'i': nElts = 2; break;
460 case 'l': nElts = 1; break;
461 case 'h': nElts = 4; break;
462 case 'f': nElts = 2; break;
463 }
464 nElts <<= quad;
Nate Begeman162d3ba2010-06-03 04:04:09 +0000465
Nate Begeman900f4672010-06-08 00:14:42 +0000466 if (structTypes)
467 s += ".val";
468
469 s += " = ";
470
Nate Begeman3861e742010-06-03 21:35:22 +0000471 std::string a, b, c;
472 if (proto.size() > 1)
Nate Begeman900f4672010-06-08 00:14:42 +0000473 a = (structTypes && proto[1] != 'l' && proto[1] != 's') ? "a.val" : "a";
Nate Begeman3861e742010-06-03 21:35:22 +0000474 b = structTypes ? "b.val" : "b";
475 c = structTypes ? "c.val" : "c";
Nate Begeman162d3ba2010-06-03 04:04:09 +0000476
477 switch(op) {
478 case OpAdd:
479 s += a + " + " + b;
480 break;
481 case OpSub:
482 s += a + " - " + b;
483 break;
484 case OpMul:
485 s += a + " * " + b;
486 break;
487 case OpMla:
488 s += a + " + ( " + b + " * " + c + " )";
489 break;
490 case OpMls:
491 s += a + " - ( " + b + " * " + c + " )";
492 break;
493 case OpEq:
494 s += "(__neon_" + ts + ")(" + a + " == " + b + ")";
495 break;
496 case OpGe:
497 s += "(__neon_" + ts + ")(" + a + " >= " + b + ")";
498 break;
499 case OpLe:
500 s += "(__neon_" + ts + ")(" + a + " <= " + b + ")";
501 break;
502 case OpGt:
503 s += "(__neon_" + ts + ")(" + a + " > " + b + ")";
504 break;
505 case OpLt:
506 s += "(__neon_" + ts + ")(" + a + " < " + b + ")";
507 break;
508 case OpNeg:
509 s += " -" + a;
510 break;
511 case OpNot:
512 s += " ~" + a;
513 break;
514 case OpAnd:
515 s += a + " & " + b;
516 break;
517 case OpOr:
518 s += a + " | " + b;
519 break;
520 case OpXor:
521 s += a + " ^ " + b;
522 break;
523 case OpAndNot:
524 s += a + " & ~" + b;
525 break;
526 case OpOrNot:
527 s += a + " | ~" + b;
528 break;
Nate Begeman3861e742010-06-03 21:35:22 +0000529 case OpCast:
530 s += "(__neon_" + ts + ")" + a;
531 break;
Nate Begeman900f4672010-06-08 00:14:42 +0000532 case OpConcat:
533 s += "__builtin_shufflevector((__neon_int64x1_t)" + a;
534 s += ", (__neon_int64x1_t)" + b + ", 0, 1)";
535 break;
Nate Begeman6c060db2010-06-09 01:09:00 +0000536 case OpHi:
537 s += "(__neon_int64x1_t)(((__neon_int64x2_t)" + a + ")[1])";
538 break;
539 case OpLo:
540 s += "(__neon_int64x1_t)(((__neon_int64x2_t)" + a + ")[0])";
541 break;
Nate Begeman900f4672010-06-08 00:14:42 +0000542 case OpDup:
543 s += "(__neon_" + ts + "){ ";
544 for (unsigned i = 0; i != nElts; ++i) {
545 s += a;
546 if ((i + 1) < nElts)
547 s += ", ";
548 }
549 s += " }";
550 break;
Nate Begeman162d3ba2010-06-03 04:04:09 +0000551 default:
552 throw "unknown OpKind!";
553 break;
554 }
Nate Begeman900f4672010-06-08 00:14:42 +0000555 s += "; return r;";
Nate Begeman162d3ba2010-06-03 04:04:09 +0000556 return s;
Nate Begemane66aab52010-06-02 07:14:28 +0000557}
558
Nate Begemanb0a4e452010-06-07 16:00:37 +0000559static unsigned GetNeonEnum(const std::string &proto, StringRef typestr) {
560 unsigned mod = proto[0];
561 unsigned ret = 0;
562
Nate Begeman900f4672010-06-08 00:14:42 +0000563 if (mod == 'v' || mod == 'f')
Nate Begemanb0a4e452010-06-07 16:00:37 +0000564 mod = proto[1];
565
566 bool quad = false;
567 bool poly = false;
568 bool usgn = false;
569 bool scal = false;
570 bool cnst = false;
571 bool pntr = false;
572
573 // base type to get the type string for.
574 char type = ClassifyType(typestr, quad, poly, usgn);
575
576 // Based on the modifying character, change the type and width if necessary.
577 type = ModType(mod, type, quad, poly, usgn, scal, cnst, pntr);
578
579 if (usgn)
580 ret |= 0x08;
581 if (quad)
582 ret |= 0x10;
583
584 switch (type) {
585 case 'c':
586 ret |= poly ? 5 : 0;
587 break;
588 case 's':
589 ret |= poly ? 6 : 1;
590 break;
591 case 'i':
592 ret |= 2;
593 break;
594 case 'l':
595 ret |= 3;
596 break;
597 case 'h':
598 ret |= 7;
599 break;
600 case 'f':
601 ret |= 4;
602 break;
603 default:
604 throw "unhandled type!";
605 break;
606 }
607 return ret;
608}
609
Nate Begeman7c8c8832010-06-02 21:53:00 +0000610// Generate the definition for this intrinsic, e.g. __builtin_neon_cls(a)
611// If structTypes is true, the NEON types are structs of vector types rather
612// than vector types, and the call becomes __builtin_neon_cls(a.val)
613static std::string GenBuiltin(const std::string &name, const std::string &proto,
Nate Begemana8979a02010-06-04 00:21:41 +0000614 StringRef typestr, ClassKind ck,
615 bool structTypes = true) {
Nate Begeman7c8c8832010-06-02 21:53:00 +0000616 char arg = 'a';
Nate Begeman162d3ba2010-06-03 04:04:09 +0000617 std::string s;
Nate Begeman9e584b32010-06-04 22:53:30 +0000618
619 bool unioning = (proto[0] == '2' || proto[0] == '3' || proto[0] == '4');
Nate Begeman6c060db2010-06-09 01:09:00 +0000620 bool define = proto.find('i') != std::string::npos;
Nate Begeman9e584b32010-06-04 22:53:30 +0000621
622 // If all types are the same size, bitcasting the args will take care
623 // of arg checking. The actual signedness etc. will be taken care of with
624 // special enums.
625 if (proto.find('s') == std::string::npos)
626 ck = ClassB;
Nate Begeman7c21f742010-06-04 21:36:00 +0000627
Nate Begeman162d3ba2010-06-03 04:04:09 +0000628 if (proto[0] != 'v') {
Nate Begeman6c060db2010-06-09 01:09:00 +0000629 std::string ts = TypeString(proto[0], typestr);
630
631 if (define) {
632 if (proto[0] != 's')
633 s += "(" + ts + "){(__neon_" + ts + ")";
Nate Begeman9e584b32010-06-04 22:53:30 +0000634 } else {
Nate Begeman6c060db2010-06-09 01:09:00 +0000635 if (unioning) {
636 s += "union { ";
637 s += TypeString(proto[0], typestr, true) + " val; ";
638 s += TypeString(proto[0], typestr, false) + " s; ";
639 s += "} r;";
640 } else {
641 s += ts;
642 }
643
644 s += " r; r";
645 if (structTypes && proto[0] != 's' && proto[0] != 'i' && proto[0] != 'l')
646 s += ".val";
647
648 s += " = ";
Nate Begeman162d3ba2010-06-03 04:04:09 +0000649 }
650 }
Nate Begeman7c8c8832010-06-02 21:53:00 +0000651
652 s += "__builtin_neon_";
Nate Begemana8979a02010-06-04 00:21:41 +0000653 s += MangleName(name, typestr, ck);
Nate Begeman7c8c8832010-06-02 21:53:00 +0000654 s += "(";
655
656 for (unsigned i = 1, e = proto.size(); i != e; ++i, ++arg) {
Nate Begeman9e584b32010-06-04 22:53:30 +0000657 // Handle multiple-vector values specially, emitting each subvector as an
658 // argument to the __builtin.
659 if (structTypes && (proto[i] == '2' || proto[i] == '3' || proto[i] == '4')){
660 for (unsigned vi = 0, ve = proto[i] - '0'; vi != ve; ++vi) {
661 s.push_back(arg);
662 s += ".val[" + utostr(vi) + "]";
663 if ((vi + 1) < ve)
664 s += ", ";
665 }
666 if ((i + 1) < e)
667 s += ", ";
668
669 continue;
670 }
671
Nate Begeman007afe42010-06-09 05:11:55 +0000672 // Parenthesize the args from the macro.
673 if (define)
674 s.push_back('(');
Nate Begeman7c8c8832010-06-02 21:53:00 +0000675 s.push_back(arg);
Nate Begeman007afe42010-06-09 05:11:55 +0000676 if (define)
677 s.push_back(')');
Nate Begeman9e584b32010-06-04 22:53:30 +0000678
Nate Begeman162d3ba2010-06-03 04:04:09 +0000679 if (structTypes && proto[i] != 's' && proto[i] != 'i' && proto[i] != 'l' &&
680 proto[i] != 'p' && proto[i] != 'c') {
Nate Begeman7c8c8832010-06-02 21:53:00 +0000681 s += ".val";
Nate Begeman162d3ba2010-06-03 04:04:09 +0000682 }
Nate Begeman7c8c8832010-06-02 21:53:00 +0000683 if ((i + 1) < e)
684 s += ", ";
685 }
686
Nate Begeman9e584b32010-06-04 22:53:30 +0000687 // Extra constant integer to hold type class enum for this function, e.g. s8
Nate Begeman9e584b32010-06-04 22:53:30 +0000688 if (ck == ClassB)
Nate Begemanb0a4e452010-06-07 16:00:37 +0000689 s += ", " + utostr(GetNeonEnum(proto, typestr));
Nate Begeman9e584b32010-06-04 22:53:30 +0000690
Nate Begeman6c060db2010-06-09 01:09:00 +0000691 if (define)
692 s += ")";
693 else
694 s += ");";
Nate Begeman9e584b32010-06-04 22:53:30 +0000695
696 if (proto[0] != 'v') {
Nate Begeman6c060db2010-06-09 01:09:00 +0000697 if (define) {
698 if (proto[0] != 's')
699 s += "}";
700 } else {
701 if (unioning)
702 s += " return r.s;";
703 else
704 s += " return r;";
705 }
Nate Begeman9e584b32010-06-04 22:53:30 +0000706 }
Nate Begeman7c8c8832010-06-02 21:53:00 +0000707 return s;
Nate Begemane66aab52010-06-02 07:14:28 +0000708}
709
Nate Begeman73cef3e2010-06-04 01:26:15 +0000710static std::string GenBuiltinDef(const std::string &name,
711 const std::string &proto,
712 StringRef typestr, ClassKind ck) {
713 std::string s("BUILTIN(__builtin_neon_");
Nate Begeman92f98af2010-06-04 07:11:25 +0000714
715 // If all types are the same size, bitcasting the args will take care
716 // of arg checking. The actual signedness etc. will be taken care of with
717 // special enums.
718 if (proto.find('s') == std::string::npos)
719 ck = ClassB;
720
Nate Begeman73cef3e2010-06-04 01:26:15 +0000721 s += MangleName(name, typestr, ck);
722 s += ", \"";
723
Nate Begeman92f98af2010-06-04 07:11:25 +0000724 for (unsigned i = 0, e = proto.size(); i != e; ++i)
Nate Begeman7c21f742010-06-04 21:36:00 +0000725 s += BuiltinTypeString(proto[i], typestr, ck, i == 0);
726
727 // Extra constant integer to hold type class enum for this function, e.g. s8
728 if (ck == ClassB)
729 s += "i";
Nate Begeman73cef3e2010-06-04 01:26:15 +0000730
731 s += "\", \"n\")";
732 return s;
733}
734
Nate Begeman5ddb0872010-05-28 01:08:32 +0000735void NeonEmitter::run(raw_ostream &OS) {
736 EmitSourceFileHeader("ARM NEON Header", OS);
737
738 // FIXME: emit license into file?
739
740 OS << "#ifndef __ARM_NEON_H\n";
741 OS << "#define __ARM_NEON_H\n\n";
742
743 OS << "#ifndef __ARM_NEON__\n";
744 OS << "#error \"NEON support not enabled\"\n";
745 OS << "#endif\n\n";
746
747 OS << "#include <stdint.h>\n\n";
Nate Begeman7c8c8832010-06-02 21:53:00 +0000748
749 // Emit NEON-specific scalar typedefs.
750 // FIXME: probably need to do something better for polynomial types.
Nate Begeman162d3ba2010-06-03 04:04:09 +0000751 // FIXME: is this the correct thing to do for float16?
Nate Begeman7c8c8832010-06-02 21:53:00 +0000752 OS << "typedef float float32_t;\n";
753 OS << "typedef uint8_t poly8_t;\n";
754 OS << "typedef uint16_t poly16_t;\n";
Nate Begeman162d3ba2010-06-03 04:04:09 +0000755 OS << "typedef uint16_t float16_t;\n";
Nate Begeman9e584b32010-06-04 22:53:30 +0000756
Nate Begeman7c8c8832010-06-02 21:53:00 +0000757 // Emit Neon vector typedefs.
758 std::string TypedefTypes("cQcsQsiQilQlUcQUcUsQUsUiQUiUlQUlhQhfQfPcQPcPsQPs");
759 SmallVector<StringRef, 24> TDTypeVec;
760 ParseTypes(0, TypedefTypes, TDTypeVec);
761
762 // Emit vector typedefs.
Nate Begeman9e584b32010-06-04 22:53:30 +0000763 for (unsigned v = 1; v != 5; ++v) {
764 for (unsigned i = 0, e = TDTypeVec.size(); i != e; ++i) {
765 bool dummy, quad = false;
766 (void) ClassifyType(TDTypeVec[i], quad, dummy, dummy);
767 OS << "typedef __attribute__(( __vector_size__(";
768
769 OS << utostr(8*v*(quad ? 2 : 1)) << ") )) ";
770 if (!quad)
771 OS << " ";
772
773 OS << TypeString('s', TDTypeVec[i]);
774 OS << " __neon_";
775
776 char t = (v == 1) ? 'd' : '0' + v;
777 OS << TypeString(t, TDTypeVec[i]) << ";\n";
778 }
Nate Begeman7c8c8832010-06-02 21:53:00 +0000779 }
780 OS << "\n";
781
782 // Emit struct typedefs.
783 for (unsigned vi = 1; vi != 5; ++vi) {
784 for (unsigned i = 0, e = TDTypeVec.size(); i != e; ++i) {
785 std::string ts = TypeString('d', TDTypeVec[i]);
786 std::string vs = (vi > 1) ? TypeString('0' + vi, TDTypeVec[i]) : ts;
787 OS << "typedef struct __" << vs << " {\n";
788 OS << " __neon_" << ts << " val";
789 if (vi > 1)
790 OS << "[" << utostr(vi) << "]";
791 OS << ";\n} " << vs << ";\n\n";
792 }
793 }
Nate Begeman5ddb0872010-05-28 01:08:32 +0000794
Nate Begeman7c8c8832010-06-02 21:53:00 +0000795 OS << "#define __ai static __attribute__((__always_inline__))\n\n";
796
Nate Begeman5ddb0872010-05-28 01:08:32 +0000797 std::vector<Record*> RV = Records.getAllDerivedDefinitions("Inst");
798
Nate Begeman22237772010-06-02 00:34:55 +0000799 // Unique the return+pattern types, and assign them.
Nate Begeman5ddb0872010-05-28 01:08:32 +0000800 for (unsigned i = 0, e = RV.size(); i != e; ++i) {
801 Record *R = RV[i];
Nate Begeman22237772010-06-02 00:34:55 +0000802 std::string name = LowercaseString(R->getName());
803 std::string Proto = R->getValueAsString("Prototype");
Nate Begeman5ddb0872010-05-28 01:08:32 +0000804 std::string Types = R->getValueAsString("Types");
Nate Begeman22237772010-06-02 00:34:55 +0000805
806 SmallVector<StringRef, 16> TypeVec;
807 ParseTypes(R, Types, TypeVec);
808
Nate Begeman162d3ba2010-06-03 04:04:09 +0000809 OpKind k = OpMap[R->getValueAsDef("Operand")->getName()];
Nate Begemane66aab52010-06-02 07:14:28 +0000810
Nate Begeman6c060db2010-06-09 01:09:00 +0000811 bool define = Proto.find('i') != std::string::npos;
812
Nate Begeman22237772010-06-02 00:34:55 +0000813 for (unsigned ti = 0, te = TypeVec.size(); ti != te; ++ti) {
814 assert(!Proto.empty() && "");
815
Nate Begeman7c8c8832010-06-02 21:53:00 +0000816 // static always inline + return type
Nate Begeman6c060db2010-06-09 01:09:00 +0000817 if (define)
818 OS << "#define";
819 else
820 OS << "__ai " << TypeString(Proto[0], TypeVec[ti]);
Nate Begeman22237772010-06-02 00:34:55 +0000821
Nate Begemane66aab52010-06-02 07:14:28 +0000822 // Function name with type suffix
Nate Begemana8979a02010-06-04 00:21:41 +0000823 OS << " " << MangleName(name, TypeVec[ti], ClassS);
Nate Begeman22237772010-06-02 00:34:55 +0000824
Nate Begemane66aab52010-06-02 07:14:28 +0000825 // Function arguments
826 OS << GenArgs(Proto, TypeVec[ti]);
Nate Begeman22237772010-06-02 00:34:55 +0000827
Nate Begemane66aab52010-06-02 07:14:28 +0000828 // Definition.
Nate Begeman6c060db2010-06-09 01:09:00 +0000829 if (define)
830 OS << " ";
831 else
832 OS << " { ";
Nate Begeman22237772010-06-02 00:34:55 +0000833
Nate Begemana8979a02010-06-04 00:21:41 +0000834 if (k != OpNone) {
Nate Begeman162d3ba2010-06-03 04:04:09 +0000835 OS << GenOpString(k, Proto, TypeVec[ti]);
Nate Begemana8979a02010-06-04 00:21:41 +0000836 } else {
837 if (R->getSuperClasses().size() < 2)
838 throw TGError(R->getLoc(), "Builtin has no class kind");
839
840 ClassKind ck = ClassMap[R->getSuperClasses()[1]];
841
842 if (ck == ClassNone)
843 throw TGError(R->getLoc(), "Builtin has no class kind");
844 OS << GenBuiltin(name, Proto, TypeVec[ti], ck);
845 }
Nate Begeman6c060db2010-06-09 01:09:00 +0000846 if (!define)
847 OS << " }";
848 OS << "\n";
Nate Begeman22237772010-06-02 00:34:55 +0000849 }
850 OS << "\n";
Nate Begeman5ddb0872010-05-28 01:08:32 +0000851 }
Nate Begeman73cef3e2010-06-04 01:26:15 +0000852 OS << "#undef __ai\n\n";
Nate Begeman7c8c8832010-06-02 21:53:00 +0000853 OS << "#endif /* __ARM_NEON_H */\n";
Nate Begeman5ddb0872010-05-28 01:08:32 +0000854}
Nate Begemana8979a02010-06-04 00:21:41 +0000855
856void NeonEmitter::runHeader(raw_ostream &OS) {
Nate Begeman73cef3e2010-06-04 01:26:15 +0000857 std::vector<Record*> RV = Records.getAllDerivedDefinitions("Inst");
858
859 StringMap<OpKind> EmittedMap;
860
861 for (unsigned i = 0, e = RV.size(); i != e; ++i) {
862 Record *R = RV[i];
863
864 OpKind k = OpMap[R->getValueAsDef("Operand")->getName()];
865 if (k != OpNone)
866 continue;
867
868 std::string name = LowercaseString(R->getName());
869 std::string Proto = R->getValueAsString("Prototype");
870 std::string Types = R->getValueAsString("Types");
871
872 SmallVector<StringRef, 16> TypeVec;
873 ParseTypes(R, Types, TypeVec);
874
875 if (R->getSuperClasses().size() < 2)
876 throw TGError(R->getLoc(), "Builtin has no class kind");
877
878 ClassKind ck = ClassMap[R->getSuperClasses()[1]];
879
880 for (unsigned ti = 0, te = TypeVec.size(); ti != te; ++ti) {
881 std::string bd = GenBuiltinDef(name, Proto, TypeVec[ti], ck);
882 if (EmittedMap.count(bd))
883 continue;
884
885 EmittedMap[bd] = OpNone;
886 OS << bd << "\n";
887 }
888 }
Nate Begemana8979a02010-06-04 00:21:41 +0000889}