blob: 6c5f86290da01199d45fe280c79bbe8f05cac6c9 [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':
Nate Begeman4b425a82010-06-10 00:16:56 +0000140 case 'a':
Nate Begeman22237772010-06-02 00:34:55 +0000141 scal = true;
142 break;
143 case 'k':
144 quad = true;
145 break;
146 case 'c':
147 cnst = true;
148 case 'p':
Nate Begemanb0a4e452010-06-07 16:00:37 +0000149 usgn = false;
150 poly = false;
Nate Begeman22237772010-06-02 00:34:55 +0000151 pntr = true;
152 scal = true;
153 break;
Nate Begeman3861e742010-06-03 21:35:22 +0000154 case 'h':
155 type = Narrow(type);
Nate Begeman900f4672010-06-08 00:14:42 +0000156 if (type == 'h')
157 quad = false;
Nate Begeman3861e742010-06-03 21:35:22 +0000158 break;
159 case 'e':
160 type = Narrow(type);
161 usgn = true;
162 break;
Nate Begeman22237772010-06-02 00:34:55 +0000163 default:
164 break;
165 }
Nate Begemanb0a4e452010-06-07 16:00:37 +0000166 return type;
167}
168
169static std::string TypeString(const char mod, StringRef typestr,
170 bool ret = false) {
171 bool quad = false;
172 bool poly = false;
173 bool usgn = false;
174 bool scal = false;
175 bool cnst = false;
176 bool pntr = false;
177
178 if (mod == 'v')
179 return "void";
180 if (mod == 'i')
181 return "int";
182
183 // base type to get the type string for.
184 char type = ClassifyType(typestr, quad, poly, usgn);
185
186 // Based on the modifying character, change the type and width if necessary.
187 type = ModType(mod, type, quad, poly, usgn, scal, cnst, pntr);
Nate Begeman22237772010-06-02 00:34:55 +0000188
189 SmallString<128> s;
190
Nate Begeman9e584b32010-06-04 22:53:30 +0000191 if (ret)
192 s += "__neon_";
193
Nate Begeman22237772010-06-02 00:34:55 +0000194 if (usgn)
195 s.push_back('u');
196
197 switch (type) {
198 case 'c':
199 s += poly ? "poly8" : "int8";
200 if (scal)
201 break;
202 s += quad ? "x16" : "x8";
203 break;
204 case 's':
205 s += poly ? "poly16" : "int16";
206 if (scal)
207 break;
208 s += quad ? "x8" : "x4";
209 break;
210 case 'i':
211 s += "int32";
212 if (scal)
213 break;
214 s += quad ? "x4" : "x2";
215 break;
216 case 'l':
217 s += "int64";
218 if (scal)
219 break;
220 s += quad ? "x2" : "x1";
221 break;
222 case 'h':
223 s += "float16";
224 if (scal)
225 break;
226 s += quad ? "x8" : "x4";
227 break;
228 case 'f':
229 s += "float32";
230 if (scal)
231 break;
232 s += quad ? "x4" : "x2";
233 break;
Nate Begeman22237772010-06-02 00:34:55 +0000234 default:
235 throw "unhandled type!";
236 break;
237 }
238
239 if (mod == '2')
240 s += "x2";
241 if (mod == '3')
242 s += "x3";
243 if (mod == '4')
244 s += "x4";
245
246 // Append _t, finishing the type string typedef type.
247 s += "_t";
248
249 if (cnst)
250 s += " const";
251
252 if (pntr)
253 s += " *";
254
255 return s.str();
256}
257
Nate Begeman7c21f742010-06-04 21:36:00 +0000258static std::string BuiltinTypeString(const char mod, StringRef typestr,
259 ClassKind ck, bool ret) {
Nate Begeman92f98af2010-06-04 07:11:25 +0000260 bool quad = false;
261 bool poly = false;
262 bool usgn = false;
263 bool scal = false;
264 bool cnst = false;
265 bool pntr = false;
266
267 if (mod == 'v')
268 return "v";
269 if (mod == 'i')
270 return "i";
271
272 // base type to get the type string for.
273 char type = ClassifyType(typestr, quad, poly, usgn);
274
275 // Based on the modifying character, change the type and width if necessary.
Nate Begemanb0a4e452010-06-07 16:00:37 +0000276 type = ModType(mod, type, quad, poly, usgn, scal, cnst, pntr);
277
278 if (pntr)
279 type = 'v';
280
Nate Begeman92f98af2010-06-04 07:11:25 +0000281 if (type == 'h') {
282 type = 's';
283 usgn = true;
284 }
Nate Begeman7c21f742010-06-04 21:36:00 +0000285 usgn = usgn | poly | ((ck == ClassI || ck == ClassW) && scal && type != 'f');
Nate Begeman92f98af2010-06-04 07:11:25 +0000286
287 if (scal) {
288 SmallString<128> s;
289
290 if (usgn)
291 s.push_back('U');
Nate Begeman7c21f742010-06-04 21:36:00 +0000292
293 if (type == 'l')
294 s += "LLi";
295 else
296 s.push_back(type);
297
Nate Begeman92f98af2010-06-04 07:11:25 +0000298 if (cnst)
299 s.push_back('C');
300 if (pntr)
301 s.push_back('*');
302 return s.str();
303 }
Nate Begeman7c21f742010-06-04 21:36:00 +0000304
305 // Since the return value must be one type, return a vector type of the
306 // appropriate width which we will bitcast.
307 if (ret) {
308 if (mod == '2')
309 return quad ? "V32c" : "V16c";
310 if (mod == '3')
311 return quad ? "V48c" : "V24c";
312 if (mod == '4')
313 return quad ? "V64c" : "V32c";
Nate Begemanf50551e2010-06-09 18:02:26 +0000314 if (mod == 'f' || (ck != ClassB && type == 'f'))
Nate Begeman56387832010-06-08 06:01:16 +0000315 return quad ? "V4f" : "V2f";
Nate Begemanf50551e2010-06-09 18:02:26 +0000316 if (ck != ClassB && type == 's')
Nate Begeman007afe42010-06-09 05:11:55 +0000317 return quad ? "V8s" : "V4s";
Nate Begemanf50551e2010-06-09 18:02:26 +0000318 if (ck != ClassB && type == 'i')
Nate Begeman56387832010-06-08 06:01:16 +0000319 return quad ? "V4i" : "V2i";
Nate Begemanf50551e2010-06-09 18:02:26 +0000320 if (ck != ClassB && type == 'l')
Nate Begeman007afe42010-06-09 05:11:55 +0000321 return quad ? "V2LLi" : "V1LLi";
Nate Begeman900f4672010-06-08 00:14:42 +0000322
Nate Begeman7c21f742010-06-04 21:36:00 +0000323 return quad ? "V16c" : "V8c";
324 }
325
326 // Non-return array types are passed as individual vectors.
Nate Begeman92f98af2010-06-04 07:11:25 +0000327 if (mod == '2')
328 return quad ? "V16cV16c" : "V8cV8c";
329 if (mod == '3')
330 return quad ? "V16cV16cV16c" : "V8cV8cV8c";
331 if (mod == '4')
332 return quad ? "V16cV16cV16cV16c" : "V8cV8cV8cV8c";
333
Nate Begemanf50551e2010-06-09 18:02:26 +0000334 if (mod == 'f' || (ck != ClassB && type == 'f'))
Nate Begeman007afe42010-06-09 05:11:55 +0000335 return quad ? "V4f" : "V2f";
Nate Begemanf50551e2010-06-09 18:02:26 +0000336 if (ck != ClassB && type == 's')
Nate Begeman007afe42010-06-09 05:11:55 +0000337 return quad ? "V8s" : "V4s";
Nate Begemanf50551e2010-06-09 18:02:26 +0000338 if (ck != ClassB && type == 'i')
Nate Begeman007afe42010-06-09 05:11:55 +0000339 return quad ? "V4i" : "V2i";
Nate Begemanf50551e2010-06-09 18:02:26 +0000340 if (ck != ClassB && type == 'l')
Nate Begeman007afe42010-06-09 05:11:55 +0000341 return quad ? "V2LLi" : "V1LLi";
342
Nate Begeman92f98af2010-06-04 07:11:25 +0000343 return quad ? "V16c" : "V8c";
344}
345
Nate Begeman22237772010-06-02 00:34:55 +0000346// Turn "vst2_lane" into "vst2q_lane_f32", etc.
Nate Begemana8979a02010-06-04 00:21:41 +0000347static std::string MangleName(const std::string &name, StringRef typestr,
348 ClassKind ck) {
Nate Begeman900f4672010-06-08 00:14:42 +0000349 if (name == "vcvt_f32_f16")
350 return name;
351
Nate Begemanaf905ef2010-06-02 06:17:19 +0000352 bool quad = false;
353 bool poly = false;
354 bool usgn = false;
355 char type = ClassifyType(typestr, quad, poly, usgn);
356
357 std::string s = name;
358
359 switch (type) {
Nate Begemana8979a02010-06-04 00:21:41 +0000360 case 'c':
361 switch (ck) {
362 case ClassS: s += poly ? "_p8" : usgn ? "_u8" : "_s8"; break;
363 case ClassI: s += "_i8"; break;
364 case ClassW: s += "_8"; break;
365 default: break;
366 }
367 break;
368 case 's':
369 switch (ck) {
370 case ClassS: s += poly ? "_p16" : usgn ? "_u16" : "_s16"; break;
371 case ClassI: s += "_i16"; break;
372 case ClassW: s += "_16"; break;
373 default: break;
374 }
375 break;
376 case 'i':
377 switch (ck) {
378 case ClassS: s += usgn ? "_u32" : "_s32"; break;
379 case ClassI: s += "_i32"; break;
380 case ClassW: s += "_32"; break;
381 default: break;
382 }
383 break;
384 case 'l':
385 switch (ck) {
386 case ClassS: s += usgn ? "_u64" : "_s64"; break;
387 case ClassI: s += "_i64"; break;
388 case ClassW: s += "_64"; break;
389 default: break;
390 }
391 break;
392 case 'h':
393 switch (ck) {
394 case ClassS:
395 case ClassI: s += "_f16"; break;
396 case ClassW: s += "_16"; break;
397 default: break;
398 }
399 break;
400 case 'f':
401 switch (ck) {
402 case ClassS:
403 case ClassI: s += "_f32"; break;
404 case ClassW: s += "_32"; break;
405 default: break;
406 }
407 break;
408 default:
409 throw "unhandled type!";
410 break;
Nate Begemanaf905ef2010-06-02 06:17:19 +0000411 }
Nate Begemana8979a02010-06-04 00:21:41 +0000412 if (ck == ClassB)
Nate Begeman92f98af2010-06-04 07:11:25 +0000413 s += "_v";
Nate Begemana8979a02010-06-04 00:21:41 +0000414
Nate Begemanaf905ef2010-06-02 06:17:19 +0000415 // Insert a 'q' before the first '_' character so that it ends up before
416 // _lane or _n on vector-scalar operations.
417 if (quad) {
418 size_t pos = s.find('_');
419 s = s.insert(pos, "q");
420 }
421 return s;
Nate Begeman22237772010-06-02 00:34:55 +0000422}
423
Nate Begemanaf905ef2010-06-02 06:17:19 +0000424// Generate the string "(argtype a, argtype b, ...)"
Nate Begeman22237772010-06-02 00:34:55 +0000425static std::string GenArgs(const std::string &proto, StringRef typestr) {
Nate Begeman6c060db2010-06-09 01:09:00 +0000426 bool define = proto.find('i') != std::string::npos;
Nate Begemanaf905ef2010-06-02 06:17:19 +0000427 char arg = 'a';
428
429 std::string s;
430 s += "(";
431
432 for (unsigned i = 1, e = proto.size(); i != e; ++i, ++arg) {
Nate Begeman6c060db2010-06-09 01:09:00 +0000433 if (!define) {
434 s += TypeString(proto[i], typestr);
435 s.push_back(' ');
436 }
Nate Begemanaf905ef2010-06-02 06:17:19 +0000437 s.push_back(arg);
438 if ((i + 1) < e)
439 s += ", ";
440 }
441
442 s += ")";
443 return s;
Nate Begeman22237772010-06-02 00:34:55 +0000444}
445
Nate Begemancc3c41a2010-06-12 03:09:49 +0000446static std::string Duplicate(unsigned nElts, StringRef typestr,
447 const std::string &a) {
Nate Begeman4b425a82010-06-10 00:16:56 +0000448 std::string s;
449
450 s = "(__neon_" + TypeString('d', typestr) + "){ ";
451 for (unsigned i = 0; i != nElts; ++i) {
452 s += a;
453 if ((i + 1) < nElts)
454 s += ", ";
455 }
456 s += " }";
457
458 return s;
459}
460
461// Generate the definition for this intrinsic, e.g. "a + b" for OpAdd.
462// If structTypes is true, the NEON types are structs of vector types rather
463// than vector types, and the call becomes "a.val + b.val"
464static std::string GenOpString(OpKind op, const std::string &proto,
465 StringRef typestr, bool structTypes = true) {
Nate Begemancc3c41a2010-06-12 03:09:49 +0000466 bool dummy, quad = false;
467 char type = ClassifyType(typestr, quad, dummy, dummy);
468 unsigned nElts = 0;
469 switch (type) {
470 case 'c': nElts = 8; break;
471 case 's': nElts = 4; break;
472 case 'i': nElts = 2; break;
473 case 'l': nElts = 1; break;
474 case 'h': nElts = 4; break;
475 case 'f': nElts = 2; break;
476 }
477
Nate Begeman4b425a82010-06-10 00:16:56 +0000478 std::string ts = TypeString(proto[0], typestr);
479 std::string s = ts + " r; r";
Nate Begeman162d3ba2010-06-03 04:04:09 +0000480
Nate Begeman900f4672010-06-08 00:14:42 +0000481 if (structTypes)
482 s += ".val";
483
484 s += " = ";
485
Nate Begeman3861e742010-06-03 21:35:22 +0000486 std::string a, b, c;
487 if (proto.size() > 1)
Nate Begeman900f4672010-06-08 00:14:42 +0000488 a = (structTypes && proto[1] != 'l' && proto[1] != 's') ? "a.val" : "a";
Nate Begeman3861e742010-06-03 21:35:22 +0000489 b = structTypes ? "b.val" : "b";
490 c = structTypes ? "c.val" : "c";
Nate Begeman162d3ba2010-06-03 04:04:09 +0000491
492 switch(op) {
493 case OpAdd:
494 s += a + " + " + b;
495 break;
496 case OpSub:
497 s += a + " - " + b;
498 break;
Nate Begeman4b425a82010-06-10 00:16:56 +0000499 case OpMulN:
Nate Begemancc3c41a2010-06-12 03:09:49 +0000500 b = Duplicate(nElts << quad, typestr, "b");
Nate Begeman162d3ba2010-06-03 04:04:09 +0000501 case OpMul:
502 s += a + " * " + b;
503 break;
Nate Begeman4b425a82010-06-10 00:16:56 +0000504 case OpMlaN:
Nate Begemancc3c41a2010-06-12 03:09:49 +0000505 c = Duplicate(nElts << quad, typestr, "c");
Nate Begeman162d3ba2010-06-03 04:04:09 +0000506 case OpMla:
507 s += a + " + ( " + b + " * " + c + " )";
508 break;
Nate Begeman4b425a82010-06-10 00:16:56 +0000509 case OpMlsN:
Nate Begemancc3c41a2010-06-12 03:09:49 +0000510 c = Duplicate(nElts << quad, typestr, "c");
Nate Begeman162d3ba2010-06-03 04:04:09 +0000511 case OpMls:
512 s += a + " - ( " + b + " * " + c + " )";
513 break;
514 case OpEq:
515 s += "(__neon_" + ts + ")(" + a + " == " + b + ")";
516 break;
517 case OpGe:
518 s += "(__neon_" + ts + ")(" + a + " >= " + b + ")";
519 break;
520 case OpLe:
521 s += "(__neon_" + ts + ")(" + a + " <= " + b + ")";
522 break;
523 case OpGt:
524 s += "(__neon_" + ts + ")(" + a + " > " + b + ")";
525 break;
526 case OpLt:
527 s += "(__neon_" + ts + ")(" + a + " < " + b + ")";
528 break;
529 case OpNeg:
530 s += " -" + a;
531 break;
532 case OpNot:
533 s += " ~" + a;
534 break;
535 case OpAnd:
536 s += a + " & " + b;
537 break;
538 case OpOr:
539 s += a + " | " + b;
540 break;
541 case OpXor:
542 s += a + " ^ " + b;
543 break;
544 case OpAndNot:
545 s += a + " & ~" + b;
546 break;
547 case OpOrNot:
548 s += a + " | ~" + b;
549 break;
Nate Begeman3861e742010-06-03 21:35:22 +0000550 case OpCast:
551 s += "(__neon_" + ts + ")" + a;
552 break;
Nate Begeman900f4672010-06-08 00:14:42 +0000553 case OpConcat:
554 s += "__builtin_shufflevector((__neon_int64x1_t)" + a;
555 s += ", (__neon_int64x1_t)" + b + ", 0, 1)";
556 break;
Nate Begeman6c060db2010-06-09 01:09:00 +0000557 case OpHi:
558 s += "(__neon_int64x1_t)(((__neon_int64x2_t)" + a + ")[1])";
559 break;
560 case OpLo:
561 s += "(__neon_int64x1_t)(((__neon_int64x2_t)" + a + ")[0])";
562 break;
Nate Begeman900f4672010-06-08 00:14:42 +0000563 case OpDup:
Nate Begemancc3c41a2010-06-12 03:09:49 +0000564 s += Duplicate(nElts << quad, typestr, a);
565 break;
566 case OpSelect:
567 // ((0 & 1) | (~0 & 2))
568 ts = TypeString(proto[1], typestr);
569 s += "( " + a + " & (__neon_" + ts + ")" + b + ") | ";
570 s += "(~" + a + " & (__neon_" + ts + ")" + c + ")";
571 break;
572 case OpRev16:
573 s += "__builtin_shufflevector(" + a + ", " + a;
574 for (unsigned i = 2; i <= nElts << quad; i += 2)
575 for (unsigned j = 0; j != 2; ++j)
576 s += ", " + utostr(i - j - 1);
577 s += ")";
578 break;
579 case OpRev32:
580 nElts >>= 1;
581 s += "__builtin_shufflevector(" + a + ", " + a;
582 for (unsigned i = nElts; i <= nElts << (1 + quad); i += nElts)
583 for (unsigned j = 0; j != nElts; ++j)
584 s += ", " + utostr(i - j - 1);
585 s += ")";
586 break;
587 case OpRev64:
588 s += "__builtin_shufflevector(" + a + ", " + a;
589 for (unsigned i = nElts; i <= nElts << quad; i += nElts)
590 for (unsigned j = 0; j != nElts; ++j)
591 s += ", " + utostr(i - j - 1);
592 s += ")";
Nate Begeman900f4672010-06-08 00:14:42 +0000593 break;
Nate Begeman162d3ba2010-06-03 04:04:09 +0000594 default:
595 throw "unknown OpKind!";
596 break;
597 }
Nate Begeman900f4672010-06-08 00:14:42 +0000598 s += "; return r;";
Nate Begeman162d3ba2010-06-03 04:04:09 +0000599 return s;
Nate Begemane66aab52010-06-02 07:14:28 +0000600}
601
Nate Begemanb0a4e452010-06-07 16:00:37 +0000602static unsigned GetNeonEnum(const std::string &proto, StringRef typestr) {
603 unsigned mod = proto[0];
604 unsigned ret = 0;
605
Nate Begeman900f4672010-06-08 00:14:42 +0000606 if (mod == 'v' || mod == 'f')
Nate Begemanb0a4e452010-06-07 16:00:37 +0000607 mod = proto[1];
608
609 bool quad = false;
610 bool poly = false;
611 bool usgn = false;
612 bool scal = false;
613 bool cnst = false;
614 bool pntr = false;
615
616 // base type to get the type string for.
617 char type = ClassifyType(typestr, quad, poly, usgn);
618
619 // Based on the modifying character, change the type and width if necessary.
620 type = ModType(mod, type, quad, poly, usgn, scal, cnst, pntr);
621
622 if (usgn)
623 ret |= 0x08;
624 if (quad)
625 ret |= 0x10;
Nate Begemand6645dd2010-06-10 18:06:07 +0000626 if (poly)
627 ret |= 0x20;
Nate Begemanb0a4e452010-06-07 16:00:37 +0000628
629 switch (type) {
630 case 'c':
631 ret |= poly ? 5 : 0;
632 break;
633 case 's':
634 ret |= poly ? 6 : 1;
635 break;
636 case 'i':
637 ret |= 2;
638 break;
639 case 'l':
640 ret |= 3;
641 break;
642 case 'h':
643 ret |= 7;
644 break;
645 case 'f':
646 ret |= 4;
647 break;
648 default:
649 throw "unhandled type!";
650 break;
651 }
652 return ret;
653}
654
Nate Begeman7c8c8832010-06-02 21:53:00 +0000655// Generate the definition for this intrinsic, e.g. __builtin_neon_cls(a)
656// If structTypes is true, the NEON types are structs of vector types rather
657// than vector types, and the call becomes __builtin_neon_cls(a.val)
658static std::string GenBuiltin(const std::string &name, const std::string &proto,
Nate Begemana8979a02010-06-04 00:21:41 +0000659 StringRef typestr, ClassKind ck,
660 bool structTypes = true) {
Nate Begemancc3c41a2010-06-12 03:09:49 +0000661 bool dummy, quad = false;
662 char type = ClassifyType(typestr, quad, dummy, dummy);
663 unsigned nElts = 0;
664 switch (type) {
665 case 'c': nElts = 8; break;
666 case 's': nElts = 4; break;
667 case 'i': nElts = 2; break;
668 case 'l': nElts = 1; break;
669 case 'h': nElts = 4; break;
670 case 'f': nElts = 2; break;
671 }
Chris Lattner5ca96982010-06-12 15:46:56 +0000672 if (quad) nElts <<= 1;
Nate Begemancc3c41a2010-06-12 03:09:49 +0000673
Nate Begeman7c8c8832010-06-02 21:53:00 +0000674 char arg = 'a';
Nate Begeman162d3ba2010-06-03 04:04:09 +0000675 std::string s;
Nate Begeman9e584b32010-06-04 22:53:30 +0000676
677 bool unioning = (proto[0] == '2' || proto[0] == '3' || proto[0] == '4');
Nate Begeman6c060db2010-06-09 01:09:00 +0000678 bool define = proto.find('i') != std::string::npos;
Nate Begeman9e584b32010-06-04 22:53:30 +0000679
680 // If all types are the same size, bitcasting the args will take care
681 // of arg checking. The actual signedness etc. will be taken care of with
682 // special enums.
683 if (proto.find('s') == std::string::npos)
684 ck = ClassB;
Nate Begeman7c21f742010-06-04 21:36:00 +0000685
Nate Begeman162d3ba2010-06-03 04:04:09 +0000686 if (proto[0] != 'v') {
Nate Begeman6c060db2010-06-09 01:09:00 +0000687 std::string ts = TypeString(proto[0], typestr);
688
689 if (define) {
690 if (proto[0] != 's')
691 s += "(" + ts + "){(__neon_" + ts + ")";
Nate Begeman9e584b32010-06-04 22:53:30 +0000692 } else {
Nate Begeman6c060db2010-06-09 01:09:00 +0000693 if (unioning) {
694 s += "union { ";
695 s += TypeString(proto[0], typestr, true) + " val; ";
696 s += TypeString(proto[0], typestr, false) + " s; ";
697 s += "} r;";
698 } else {
699 s += ts;
700 }
701
702 s += " r; r";
703 if (structTypes && proto[0] != 's' && proto[0] != 'i' && proto[0] != 'l')
704 s += ".val";
705
706 s += " = ";
Nate Begeman162d3ba2010-06-03 04:04:09 +0000707 }
Nate Begeman4b425a82010-06-10 00:16:56 +0000708 }
709
710 bool splat = proto.find('a') != std::string::npos;
Nate Begeman7c8c8832010-06-02 21:53:00 +0000711
712 s += "__builtin_neon_";
Nate Begeman4b425a82010-06-10 00:16:56 +0000713 if (splat) {
714 std::string vname(name, 0, name.size()-2);
715 s += MangleName(vname, typestr, ck);
716 } else {
717 s += MangleName(name, typestr, ck);
718 }
Nate Begeman7c8c8832010-06-02 21:53:00 +0000719 s += "(";
720
721 for (unsigned i = 1, e = proto.size(); i != e; ++i, ++arg) {
Nate Begemancc3c41a2010-06-12 03:09:49 +0000722 std::string args = std::string(&arg, 1);
723 if (define)
724 args = "(" + args + ")";
725
Nate Begeman9e584b32010-06-04 22:53:30 +0000726 // Handle multiple-vector values specially, emitting each subvector as an
727 // argument to the __builtin.
728 if (structTypes && (proto[i] == '2' || proto[i] == '3' || proto[i] == '4')){
729 for (unsigned vi = 0, ve = proto[i] - '0'; vi != ve; ++vi) {
Nate Begemancc3c41a2010-06-12 03:09:49 +0000730 s += args + ".val[" + utostr(vi) + "]";
Nate Begeman9e584b32010-06-04 22:53:30 +0000731 if ((vi + 1) < ve)
732 s += ", ";
733 }
734 if ((i + 1) < e)
735 s += ", ";
736
737 continue;
738 }
739
Nate Begeman4b425a82010-06-10 00:16:56 +0000740 if (splat && (i + 1) == e)
Nate Begemancc3c41a2010-06-12 03:09:49 +0000741 s += Duplicate(nElts, typestr, args);
Nate Begeman4b425a82010-06-10 00:16:56 +0000742 else
Nate Begemancc3c41a2010-06-12 03:09:49 +0000743 s += args;
Nate Begeman9e584b32010-06-04 22:53:30 +0000744
Nate Begeman162d3ba2010-06-03 04:04:09 +0000745 if (structTypes && proto[i] != 's' && proto[i] != 'i' && proto[i] != 'l' &&
Nate Begeman4b425a82010-06-10 00:16:56 +0000746 proto[i] != 'p' && proto[i] != 'c' && proto[i] != 'a') {
Nate Begeman7c8c8832010-06-02 21:53:00 +0000747 s += ".val";
Nate Begeman162d3ba2010-06-03 04:04:09 +0000748 }
Nate Begeman7c8c8832010-06-02 21:53:00 +0000749 if ((i + 1) < e)
750 s += ", ";
751 }
752
Nate Begeman9e584b32010-06-04 22:53:30 +0000753 // Extra constant integer to hold type class enum for this function, e.g. s8
Nate Begeman9e584b32010-06-04 22:53:30 +0000754 if (ck == ClassB)
Nate Begemanb0a4e452010-06-07 16:00:37 +0000755 s += ", " + utostr(GetNeonEnum(proto, typestr));
Nate Begeman9e584b32010-06-04 22:53:30 +0000756
Nate Begeman6c060db2010-06-09 01:09:00 +0000757 if (define)
758 s += ")";
759 else
760 s += ");";
Nate Begeman9e584b32010-06-04 22:53:30 +0000761
762 if (proto[0] != 'v') {
Nate Begeman6c060db2010-06-09 01:09:00 +0000763 if (define) {
764 if (proto[0] != 's')
765 s += "}";
766 } else {
767 if (unioning)
768 s += " return r.s;";
769 else
770 s += " return r;";
771 }
Nate Begeman9e584b32010-06-04 22:53:30 +0000772 }
Nate Begeman7c8c8832010-06-02 21:53:00 +0000773 return s;
Nate Begemane66aab52010-06-02 07:14:28 +0000774}
775
Nate Begeman73cef3e2010-06-04 01:26:15 +0000776static std::string GenBuiltinDef(const std::string &name,
777 const std::string &proto,
778 StringRef typestr, ClassKind ck) {
779 std::string s("BUILTIN(__builtin_neon_");
Nate Begeman92f98af2010-06-04 07:11:25 +0000780
781 // If all types are the same size, bitcasting the args will take care
782 // of arg checking. The actual signedness etc. will be taken care of with
783 // special enums.
784 if (proto.find('s') == std::string::npos)
785 ck = ClassB;
786
Nate Begeman73cef3e2010-06-04 01:26:15 +0000787 s += MangleName(name, typestr, ck);
788 s += ", \"";
789
Nate Begeman92f98af2010-06-04 07:11:25 +0000790 for (unsigned i = 0, e = proto.size(); i != e; ++i)
Nate Begeman7c21f742010-06-04 21:36:00 +0000791 s += BuiltinTypeString(proto[i], typestr, ck, i == 0);
792
793 // Extra constant integer to hold type class enum for this function, e.g. s8
794 if (ck == ClassB)
795 s += "i";
Nate Begeman73cef3e2010-06-04 01:26:15 +0000796
797 s += "\", \"n\")";
798 return s;
799}
800
Nate Begeman5ddb0872010-05-28 01:08:32 +0000801void NeonEmitter::run(raw_ostream &OS) {
802 EmitSourceFileHeader("ARM NEON Header", OS);
803
804 // FIXME: emit license into file?
805
806 OS << "#ifndef __ARM_NEON_H\n";
807 OS << "#define __ARM_NEON_H\n\n";
808
809 OS << "#ifndef __ARM_NEON__\n";
810 OS << "#error \"NEON support not enabled\"\n";
811 OS << "#endif\n\n";
812
813 OS << "#include <stdint.h>\n\n";
Nate Begeman7c8c8832010-06-02 21:53:00 +0000814
815 // Emit NEON-specific scalar typedefs.
816 // FIXME: probably need to do something better for polynomial types.
817 OS << "typedef float float32_t;\n";
818 OS << "typedef uint8_t poly8_t;\n";
819 OS << "typedef uint16_t poly16_t;\n";
Nate Begeman162d3ba2010-06-03 04:04:09 +0000820 OS << "typedef uint16_t float16_t;\n";
Nate Begeman9e584b32010-06-04 22:53:30 +0000821
Nate Begeman7c8c8832010-06-02 21:53:00 +0000822 // Emit Neon vector typedefs.
823 std::string TypedefTypes("cQcsQsiQilQlUcQUcUsQUsUiQUiUlQUlhQhfQfPcQPcPsQPs");
824 SmallVector<StringRef, 24> TDTypeVec;
825 ParseTypes(0, TypedefTypes, TDTypeVec);
826
827 // Emit vector typedefs.
Nate Begeman9e584b32010-06-04 22:53:30 +0000828 for (unsigned v = 1; v != 5; ++v) {
829 for (unsigned i = 0, e = TDTypeVec.size(); i != e; ++i) {
830 bool dummy, quad = false;
831 (void) ClassifyType(TDTypeVec[i], quad, dummy, dummy);
832 OS << "typedef __attribute__(( __vector_size__(";
833
834 OS << utostr(8*v*(quad ? 2 : 1)) << ") )) ";
835 if (!quad)
836 OS << " ";
837
838 OS << TypeString('s', TDTypeVec[i]);
839 OS << " __neon_";
840
841 char t = (v == 1) ? 'd' : '0' + v;
842 OS << TypeString(t, TDTypeVec[i]) << ";\n";
843 }
Nate Begeman7c8c8832010-06-02 21:53:00 +0000844 }
845 OS << "\n";
846
847 // Emit struct typedefs.
848 for (unsigned vi = 1; vi != 5; ++vi) {
849 for (unsigned i = 0, e = TDTypeVec.size(); i != e; ++i) {
850 std::string ts = TypeString('d', TDTypeVec[i]);
851 std::string vs = (vi > 1) ? TypeString('0' + vi, TDTypeVec[i]) : ts;
852 OS << "typedef struct __" << vs << " {\n";
853 OS << " __neon_" << ts << " val";
854 if (vi > 1)
855 OS << "[" << utostr(vi) << "]";
856 OS << ";\n} " << vs << ";\n\n";
857 }
858 }
Nate Begeman5ddb0872010-05-28 01:08:32 +0000859
Nate Begeman7c8c8832010-06-02 21:53:00 +0000860 OS << "#define __ai static __attribute__((__always_inline__))\n\n";
861
Nate Begeman5ddb0872010-05-28 01:08:32 +0000862 std::vector<Record*> RV = Records.getAllDerivedDefinitions("Inst");
863
Nate Begeman22237772010-06-02 00:34:55 +0000864 // Unique the return+pattern types, and assign them.
Nate Begeman5ddb0872010-05-28 01:08:32 +0000865 for (unsigned i = 0, e = RV.size(); i != e; ++i) {
866 Record *R = RV[i];
Nate Begeman22237772010-06-02 00:34:55 +0000867 std::string name = LowercaseString(R->getName());
868 std::string Proto = R->getValueAsString("Prototype");
Nate Begeman5ddb0872010-05-28 01:08:32 +0000869 std::string Types = R->getValueAsString("Types");
Nate Begeman22237772010-06-02 00:34:55 +0000870
871 SmallVector<StringRef, 16> TypeVec;
872 ParseTypes(R, Types, TypeVec);
873
Nate Begeman162d3ba2010-06-03 04:04:09 +0000874 OpKind k = OpMap[R->getValueAsDef("Operand")->getName()];
Nate Begemane66aab52010-06-02 07:14:28 +0000875
Nate Begeman6c060db2010-06-09 01:09:00 +0000876 bool define = Proto.find('i') != std::string::npos;
877
Nate Begeman22237772010-06-02 00:34:55 +0000878 for (unsigned ti = 0, te = TypeVec.size(); ti != te; ++ti) {
879 assert(!Proto.empty() && "");
880
Nate Begeman7c8c8832010-06-02 21:53:00 +0000881 // static always inline + return type
Nate Begeman6c060db2010-06-09 01:09:00 +0000882 if (define)
883 OS << "#define";
884 else
885 OS << "__ai " << TypeString(Proto[0], TypeVec[ti]);
Nate Begeman22237772010-06-02 00:34:55 +0000886
Nate Begemane66aab52010-06-02 07:14:28 +0000887 // Function name with type suffix
Nate Begemana8979a02010-06-04 00:21:41 +0000888 OS << " " << MangleName(name, TypeVec[ti], ClassS);
Nate Begeman22237772010-06-02 00:34:55 +0000889
Nate Begemane66aab52010-06-02 07:14:28 +0000890 // Function arguments
891 OS << GenArgs(Proto, TypeVec[ti]);
Nate Begeman22237772010-06-02 00:34:55 +0000892
Nate Begemane66aab52010-06-02 07:14:28 +0000893 // Definition.
Nate Begeman6c060db2010-06-09 01:09:00 +0000894 if (define)
895 OS << " ";
896 else
897 OS << " { ";
Nate Begeman22237772010-06-02 00:34:55 +0000898
Nate Begemana8979a02010-06-04 00:21:41 +0000899 if (k != OpNone) {
Nate Begeman162d3ba2010-06-03 04:04:09 +0000900 OS << GenOpString(k, Proto, TypeVec[ti]);
Nate Begemana8979a02010-06-04 00:21:41 +0000901 } else {
902 if (R->getSuperClasses().size() < 2)
903 throw TGError(R->getLoc(), "Builtin has no class kind");
904
905 ClassKind ck = ClassMap[R->getSuperClasses()[1]];
906
907 if (ck == ClassNone)
908 throw TGError(R->getLoc(), "Builtin has no class kind");
909 OS << GenBuiltin(name, Proto, TypeVec[ti], ck);
910 }
Nate Begeman6c060db2010-06-09 01:09:00 +0000911 if (!define)
912 OS << " }";
913 OS << "\n";
Nate Begeman22237772010-06-02 00:34:55 +0000914 }
915 OS << "\n";
Nate Begeman5ddb0872010-05-28 01:08:32 +0000916 }
Nate Begeman73cef3e2010-06-04 01:26:15 +0000917 OS << "#undef __ai\n\n";
Nate Begeman7c8c8832010-06-02 21:53:00 +0000918 OS << "#endif /* __ARM_NEON_H */\n";
Nate Begeman5ddb0872010-05-28 01:08:32 +0000919}
Nate Begemana8979a02010-06-04 00:21:41 +0000920
921void NeonEmitter::runHeader(raw_ostream &OS) {
Nate Begeman73cef3e2010-06-04 01:26:15 +0000922 std::vector<Record*> RV = Records.getAllDerivedDefinitions("Inst");
923
924 StringMap<OpKind> EmittedMap;
925
926 for (unsigned i = 0, e = RV.size(); i != e; ++i) {
927 Record *R = RV[i];
928
929 OpKind k = OpMap[R->getValueAsDef("Operand")->getName()];
930 if (k != OpNone)
931 continue;
932
933 std::string name = LowercaseString(R->getName());
934 std::string Proto = R->getValueAsString("Prototype");
935 std::string Types = R->getValueAsString("Types");
936
Nate Begeman4b425a82010-06-10 00:16:56 +0000937 if (Proto.find('a') != std::string::npos)
938 continue;
939
Nate Begeman73cef3e2010-06-04 01:26:15 +0000940 SmallVector<StringRef, 16> TypeVec;
941 ParseTypes(R, Types, TypeVec);
942
943 if (R->getSuperClasses().size() < 2)
944 throw TGError(R->getLoc(), "Builtin has no class kind");
945
946 ClassKind ck = ClassMap[R->getSuperClasses()[1]];
947
948 for (unsigned ti = 0, te = TypeVec.size(); ti != te; ++ti) {
949 std::string bd = GenBuiltinDef(name, Proto, TypeVec[ti], ck);
950 if (EmittedMap.count(bd))
951 continue;
952
953 EmittedMap[bd] = OpNone;
954 OS << bd << "\n";
955 }
956 }
Nate Begemana8979a02010-06-04 00:21:41 +0000957}