blob: cc828a5ccae4ef28fa247a88268e89842677d418 [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"
17#include "Record.h"
Nate Begeman22237772010-06-02 00:34:55 +000018#include "llvm/ADT/SmallString.h"
19#include "llvm/ADT/SmallVector.h"
Nate Begeman5ddb0872010-05-28 01:08:32 +000020#include "llvm/ADT/StringExtras.h"
21#include "llvm/ADT/StringMap.h"
22#include <string>
23
24using namespace llvm;
25
Nate Begemane66aab52010-06-02 07:14:28 +000026enum OpKind {
27 OpNone,
28 OpAdd,
29 OpSub,
30 OpMul,
31 OpMla,
32 OpMls,
33 OpEq,
34 OpGe,
35 OpLe,
36 OpGt,
37 OpLt,
38 OpNeg,
39 OpNot,
40 OpAnd,
41 OpOr,
42 OpXor,
43 OpAndNot,
44 OpOrNot
45};
46
Nate Begeman22237772010-06-02 00:34:55 +000047static void ParseTypes(Record *r, std::string &s,
48 SmallVectorImpl<StringRef> &TV) {
49 const char *data = s.data();
50 int len = 0;
51
52 for (unsigned i = 0, e = s.size(); i != e; ++i, ++len) {
53 if (data[len] == 'P' || data[len] == 'Q' || data[len] == 'U')
54 continue;
55
56 switch (data[len]) {
57 case 'c':
58 case 's':
59 case 'i':
60 case 'l':
61 case 'h':
62 case 'f':
63 break;
64 default:
65 throw TGError(r->getLoc(),
66 "Unexpected letter: " + std::string(data + len, 1));
67 break;
68 }
69 TV.push_back(StringRef(data, len + 1));
70 data += len + 1;
71 len = -1;
72 }
73}
74
Duncan Sands8dbbace2010-06-02 08:37:30 +000075static char Widen(const char t) {
Nate Begeman22237772010-06-02 00:34:55 +000076 switch (t) {
77 case 'c':
78 return 's';
79 case 's':
80 return 'i';
81 case 'i':
82 return 'l';
83 default: throw "unhandled type in widen!";
84 }
85 return '\0';
86}
87
Nate Begemanaf905ef2010-06-02 06:17:19 +000088static char ClassifyType(StringRef ty, bool &quad, bool &poly, bool &usgn) {
Nate Begeman22237772010-06-02 00:34:55 +000089 unsigned off = 0;
90
Nate Begemanaf905ef2010-06-02 06:17:19 +000091 // remember quad.
92 if (ty[off] == 'Q') {
93 quad = true;
94 ++off;
95 }
96
97 // remember poly.
98 if (ty[off] == 'P') {
99 poly = true;
100 ++off;
101 }
102
103 // remember unsigned.
104 if (ty[off] == 'U') {
105 usgn = true;
106 ++off;
107 }
108
109 // base type to get the type string for.
110 return ty[off];
111}
112
113static std::string TypeString(const char mod, StringRef typestr) {
Nate Begeman22237772010-06-02 00:34:55 +0000114 bool quad = false;
115 bool poly = false;
116 bool usgn = false;
117 bool scal = false;
118 bool cnst = false;
119 bool pntr = false;
120
Nate Begeman22237772010-06-02 00:34:55 +0000121 // base type to get the type string for.
Nate Begemanaf905ef2010-06-02 06:17:19 +0000122 char type = ClassifyType(typestr, quad, poly, usgn);
Nate Begeman22237772010-06-02 00:34:55 +0000123
124 // Based on the modifying character, change the type and width if necessary.
125 switch (mod) {
126 case 'v':
Nate Begemane66aab52010-06-02 07:14:28 +0000127 return "void";
128 case 'i':
129 return "int";
Nate Begeman22237772010-06-02 00:34:55 +0000130 case 't':
131 if (poly) {
132 poly = false;
133 usgn = true;
134 }
135 break;
136 case 'x':
137 usgn = true;
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':
143 type = 'f';
Nate Begeman162d3ba2010-06-03 04:04:09 +0000144 usgn = false;
Nate Begeman22237772010-06-02 00:34:55 +0000145 break;
146 case 'w':
147 type = Widen(type);
148 quad = true;
149 break;
150 case 'n':
151 type = Widen(type);
152 break;
Nate Begeman22237772010-06-02 00:34:55 +0000153 case 'l':
154 type = 'l';
155 scal = true;
156 usgn = true;
157 break;
158 case 's':
159 scal = true;
160 break;
161 case 'k':
162 quad = true;
163 break;
164 case 'c':
165 cnst = true;
166 case 'p':
167 pntr = true;
168 scal = true;
169 break;
170 default:
171 break;
172 }
173
174 SmallString<128> s;
175
176 if (usgn)
177 s.push_back('u');
178
179 switch (type) {
180 case 'c':
181 s += poly ? "poly8" : "int8";
182 if (scal)
183 break;
184 s += quad ? "x16" : "x8";
185 break;
186 case 's':
187 s += poly ? "poly16" : "int16";
188 if (scal)
189 break;
190 s += quad ? "x8" : "x4";
191 break;
192 case 'i':
193 s += "int32";
194 if (scal)
195 break;
196 s += quad ? "x4" : "x2";
197 break;
198 case 'l':
199 s += "int64";
200 if (scal)
201 break;
202 s += quad ? "x2" : "x1";
203 break;
204 case 'h':
205 s += "float16";
206 if (scal)
207 break;
208 s += quad ? "x8" : "x4";
209 break;
210 case 'f':
211 s += "float32";
212 if (scal)
213 break;
214 s += quad ? "x4" : "x2";
215 break;
Nate Begeman22237772010-06-02 00:34:55 +0000216 default:
217 throw "unhandled type!";
218 break;
219 }
220
221 if (mod == '2')
222 s += "x2";
223 if (mod == '3')
224 s += "x3";
225 if (mod == '4')
226 s += "x4";
227
228 // Append _t, finishing the type string typedef type.
229 s += "_t";
230
231 if (cnst)
232 s += " const";
233
234 if (pntr)
235 s += " *";
236
237 return s.str();
238}
239
240// Turn "vst2_lane" into "vst2q_lane_f32", etc.
241static std::string MangleName(const std::string &name, StringRef typestr) {
Nate Begemanaf905ef2010-06-02 06:17:19 +0000242 bool quad = false;
243 bool poly = false;
244 bool usgn = false;
245 char type = ClassifyType(typestr, quad, poly, usgn);
246
247 std::string s = name;
248
249 switch (type) {
250 case 'c':
251 s += poly ? "_p8" : usgn ? "_u8" : "_s8";
252 break;
253 case 's':
254 s += poly ? "_p16" : usgn ? "_u16" : "_s16";
255 break;
256 case 'i':
257 s += usgn ? "_u32" : "_s32";
258 break;
259 case 'l':
260 s += usgn ? "_u64" : "_s64";
261 break;
262 case 'h':
263 s += "_f16";
264 break;
265 case 'f':
266 s += "_f32";
267 break;
268 default:
269 throw "unhandled type!";
270 break;
271 }
272
273 // Insert a 'q' before the first '_' character so that it ends up before
274 // _lane or _n on vector-scalar operations.
275 if (quad) {
276 size_t pos = s.find('_');
277 s = s.insert(pos, "q");
278 }
279 return s;
Nate Begeman22237772010-06-02 00:34:55 +0000280}
281
Nate Begemanaf905ef2010-06-02 06:17:19 +0000282// Generate the string "(argtype a, argtype b, ...)"
Nate Begeman22237772010-06-02 00:34:55 +0000283static std::string GenArgs(const std::string &proto, StringRef typestr) {
Nate Begemanaf905ef2010-06-02 06:17:19 +0000284 char arg = 'a';
285
286 std::string s;
287 s += "(";
288
289 for (unsigned i = 1, e = proto.size(); i != e; ++i, ++arg) {
290 s += TypeString(proto[i], typestr);
291 s.push_back(' ');
292 s.push_back(arg);
293 if ((i + 1) < e)
294 s += ", ";
295 }
296
297 s += ")";
298 return s;
Nate Begeman22237772010-06-02 00:34:55 +0000299}
300
Nate Begeman7c8c8832010-06-02 21:53:00 +0000301// Generate the definition for this intrinsic, e.g. "a + b" for OpAdd.
302// If structTypes is true, the NEON types are structs of vector types rather
303// than vector types, and the call becomes "a.val + b.val"
304static std::string GenOpString(OpKind op, const std::string &proto,
Nate Begeman162d3ba2010-06-03 04:04:09 +0000305 StringRef typestr, bool structTypes = true) {
306 std::string s("return ");
307 std::string ts = TypeString(proto[0], typestr);
308 if (structTypes)
309 s += "(" + ts + "){";
310
311 std::string a = structTypes ? "a.val" : "a";
312 std::string b = structTypes ? "b.val" : "b";
313 std::string c = structTypes ? "c.val" : "c";
314
315 switch(op) {
316 case OpAdd:
317 s += a + " + " + b;
318 break;
319 case OpSub:
320 s += a + " - " + b;
321 break;
322 case OpMul:
323 s += a + " * " + b;
324 break;
325 case OpMla:
326 s += a + " + ( " + b + " * " + c + " )";
327 break;
328 case OpMls:
329 s += a + " - ( " + b + " * " + c + " )";
330 break;
331 case OpEq:
332 s += "(__neon_" + ts + ")(" + a + " == " + b + ")";
333 break;
334 case OpGe:
335 s += "(__neon_" + ts + ")(" + a + " >= " + b + ")";
336 break;
337 case OpLe:
338 s += "(__neon_" + ts + ")(" + a + " <= " + b + ")";
339 break;
340 case OpGt:
341 s += "(__neon_" + ts + ")(" + a + " > " + b + ")";
342 break;
343 case OpLt:
344 s += "(__neon_" + ts + ")(" + a + " < " + b + ")";
345 break;
346 case OpNeg:
347 s += " -" + a;
348 break;
349 case OpNot:
350 s += " ~" + a;
351 break;
352 case OpAnd:
353 s += a + " & " + b;
354 break;
355 case OpOr:
356 s += a + " | " + b;
357 break;
358 case OpXor:
359 s += a + " ^ " + b;
360 break;
361 case OpAndNot:
362 s += a + " & ~" + b;
363 break;
364 case OpOrNot:
365 s += a + " | ~" + b;
366 break;
367 default:
368 throw "unknown OpKind!";
369 break;
370 }
371
372 if (structTypes)
373 s += "}";
374 s += ";";
375 return s;
Nate Begemane66aab52010-06-02 07:14:28 +0000376}
377
Nate Begeman7c8c8832010-06-02 21:53:00 +0000378// Generate the definition for this intrinsic, e.g. __builtin_neon_cls(a)
379// If structTypes is true, the NEON types are structs of vector types rather
380// than vector types, and the call becomes __builtin_neon_cls(a.val)
381static std::string GenBuiltin(const std::string &name, const std::string &proto,
382 StringRef typestr, bool structTypes = true) {
383 char arg = 'a';
Nate Begeman162d3ba2010-06-03 04:04:09 +0000384 std::string s;
Nate Begeman7c8c8832010-06-02 21:53:00 +0000385
Nate Begeman162d3ba2010-06-03 04:04:09 +0000386 if (proto[0] != 'v') {
387 // FIXME: if return type is 2/3/4, emit unioning code.
388 s += "return ";
389 if (structTypes) {
390 s += "(";
391 s += TypeString(proto[0], typestr);
392 s += "){";
393 }
394 }
Nate Begeman7c8c8832010-06-02 21:53:00 +0000395
396 s += "__builtin_neon_";
397 s += name;
398 s += "(";
399
400 for (unsigned i = 1, e = proto.size(); i != e; ++i, ++arg) {
401 s.push_back(arg);
Nate Begeman162d3ba2010-06-03 04:04:09 +0000402 if (structTypes && proto[i] != 's' && proto[i] != 'i' && proto[i] != 'l' &&
403 proto[i] != 'p' && proto[i] != 'c') {
Nate Begeman7c8c8832010-06-02 21:53:00 +0000404 s += ".val";
Nate Begeman162d3ba2010-06-03 04:04:09 +0000405 }
Nate Begeman7c8c8832010-06-02 21:53:00 +0000406 if ((i + 1) < e)
407 s += ", ";
408 }
409
410 s += ")";
Nate Begeman162d3ba2010-06-03 04:04:09 +0000411 if (proto[0] != 'v' && structTypes)
Nate Begeman7c8c8832010-06-02 21:53:00 +0000412 s += "}";
413 s += ";";
414 return s;
Nate Begemane66aab52010-06-02 07:14:28 +0000415}
416
Nate Begeman5ddb0872010-05-28 01:08:32 +0000417void NeonEmitter::run(raw_ostream &OS) {
418 EmitSourceFileHeader("ARM NEON Header", OS);
419
420 // FIXME: emit license into file?
421
422 OS << "#ifndef __ARM_NEON_H\n";
423 OS << "#define __ARM_NEON_H\n\n";
424
425 OS << "#ifndef __ARM_NEON__\n";
426 OS << "#error \"NEON support not enabled\"\n";
427 OS << "#endif\n\n";
428
429 OS << "#include <stdint.h>\n\n";
Nate Begeman7c8c8832010-06-02 21:53:00 +0000430
431 // Emit NEON-specific scalar typedefs.
432 // FIXME: probably need to do something better for polynomial types.
Nate Begeman162d3ba2010-06-03 04:04:09 +0000433 // FIXME: is this the correct thing to do for float16?
Nate Begeman7c8c8832010-06-02 21:53:00 +0000434 OS << "typedef float float32_t;\n";
435 OS << "typedef uint8_t poly8_t;\n";
436 OS << "typedef uint16_t poly16_t;\n";
Nate Begeman162d3ba2010-06-03 04:04:09 +0000437 OS << "typedef uint16_t float16_t;\n";
Nate Begeman5ddb0872010-05-28 01:08:32 +0000438
Nate Begeman7c8c8832010-06-02 21:53:00 +0000439 // Emit Neon vector typedefs.
440 std::string TypedefTypes("cQcsQsiQilQlUcQUcUsQUsUiQUiUlQUlhQhfQfPcQPcPsQPs");
441 SmallVector<StringRef, 24> TDTypeVec;
442 ParseTypes(0, TypedefTypes, TDTypeVec);
443
444 // Emit vector typedefs.
445 for (unsigned i = 0, e = TDTypeVec.size(); i != e; ++i) {
446 bool dummy, quad = false;
447 (void) ClassifyType(TDTypeVec[i], quad, dummy, dummy);
448 OS << "typedef __attribute__(( __vector_size__(";
449 OS << (quad ? "16) )) " : "8) )) ");
450 OS << TypeString('s', TDTypeVec[i]);
451 OS << " __neon_";
Nate Begeman162d3ba2010-06-03 04:04:09 +0000452 OS << TypeString('d', TDTypeVec[i]) << ";\n";
Nate Begeman7c8c8832010-06-02 21:53:00 +0000453 }
454 OS << "\n";
455
456 // Emit struct typedefs.
457 for (unsigned vi = 1; vi != 5; ++vi) {
458 for (unsigned i = 0, e = TDTypeVec.size(); i != e; ++i) {
459 std::string ts = TypeString('d', TDTypeVec[i]);
460 std::string vs = (vi > 1) ? TypeString('0' + vi, TDTypeVec[i]) : ts;
461 OS << "typedef struct __" << vs << " {\n";
462 OS << " __neon_" << ts << " val";
463 if (vi > 1)
464 OS << "[" << utostr(vi) << "]";
465 OS << ";\n} " << vs << ";\n\n";
466 }
467 }
Nate Begeman5ddb0872010-05-28 01:08:32 +0000468
Nate Begeman7c8c8832010-06-02 21:53:00 +0000469 OS << "#define __ai static __attribute__((__always_inline__))\n\n";
470
Nate Begeman5ddb0872010-05-28 01:08:32 +0000471 std::vector<Record*> RV = Records.getAllDerivedDefinitions("Inst");
472
Nate Begeman162d3ba2010-06-03 04:04:09 +0000473 StringMap<OpKind> OpMap;
474 OpMap["OP_NONE"] = OpNone;
475 OpMap["OP_ADD"] = OpAdd;
476 OpMap["OP_SUB"] = OpSub;
477 OpMap["OP_MUL"] = OpMul;
478 OpMap["OP_MLA"] = OpMla;
479 OpMap["OP_MLS"] = OpMls;
480 OpMap["OP_EQ"] = OpEq;
481 OpMap["OP_GE"] = OpGe;
482 OpMap["OP_LE"] = OpLe;
483 OpMap["OP_GT"] = OpGt;
484 OpMap["OP_LT"] = OpLt;
485 OpMap["OP_NEG"] = OpNeg;
486 OpMap["OP_NOT"] = OpNot;
487 OpMap["OP_AND"] = OpAnd;
488 OpMap["OP_OR"] = OpOr;
489 OpMap["OP_XOR"] = OpXor;
490 OpMap["OP_ANDN"] = OpAndNot;
491 OpMap["OP_ORN"] = OpOrNot;
492
Nate Begeman22237772010-06-02 00:34:55 +0000493 // Unique the return+pattern types, and assign them.
Nate Begeman5ddb0872010-05-28 01:08:32 +0000494 for (unsigned i = 0, e = RV.size(); i != e; ++i) {
495 Record *R = RV[i];
Nate Begeman22237772010-06-02 00:34:55 +0000496 std::string name = LowercaseString(R->getName());
497 std::string Proto = R->getValueAsString("Prototype");
Nate Begeman5ddb0872010-05-28 01:08:32 +0000498 std::string Types = R->getValueAsString("Types");
Nate Begeman22237772010-06-02 00:34:55 +0000499
500 SmallVector<StringRef, 16> TypeVec;
501 ParseTypes(R, Types, TypeVec);
502
Nate Begeman162d3ba2010-06-03 04:04:09 +0000503 OpKind k = OpMap[R->getValueAsDef("Operand")->getName()];
Nate Begemane66aab52010-06-02 07:14:28 +0000504
Nate Begeman22237772010-06-02 00:34:55 +0000505 for (unsigned ti = 0, te = TypeVec.size(); ti != te; ++ti) {
506 assert(!Proto.empty() && "");
507
Nate Begeman7c8c8832010-06-02 21:53:00 +0000508 // static always inline + return type
509 OS << "__ai " << TypeString(Proto[0], TypeVec[ti]);
Nate Begeman22237772010-06-02 00:34:55 +0000510
Nate Begemane66aab52010-06-02 07:14:28 +0000511 // Function name with type suffix
512 OS << " " << MangleName(name, TypeVec[ti]);
Nate Begeman22237772010-06-02 00:34:55 +0000513
Nate Begemane66aab52010-06-02 07:14:28 +0000514 // Function arguments
515 OS << GenArgs(Proto, TypeVec[ti]);
Nate Begeman22237772010-06-02 00:34:55 +0000516
Nate Begemane66aab52010-06-02 07:14:28 +0000517 // Definition.
518 OS << " { ";
Nate Begeman22237772010-06-02 00:34:55 +0000519
Nate Begemane66aab52010-06-02 07:14:28 +0000520 if (k != OpNone)
Nate Begeman162d3ba2010-06-03 04:04:09 +0000521 OS << GenOpString(k, Proto, TypeVec[ti]);
Nate Begemane66aab52010-06-02 07:14:28 +0000522 else
Nate Begeman7c8c8832010-06-02 21:53:00 +0000523 OS << GenBuiltin(name, Proto, TypeVec[ti]);
Nate Begemane66aab52010-06-02 07:14:28 +0000524
Nate Begeman7c8c8832010-06-02 21:53:00 +0000525 OS << " }\n";
Nate Begeman22237772010-06-02 00:34:55 +0000526 }
527 OS << "\n";
Nate Begeman5ddb0872010-05-28 01:08:32 +0000528 }
Nate Begeman22237772010-06-02 00:34:55 +0000529
530 // TODO:
531 // Unique the return+pattern types, and assign them to each record
532 // Emit a #define for each unique "type" of intrinsic declaring all variants.
533 // Emit a #define for each intrinsic mapping it to a particular type.
Nate Begeman5ddb0872010-05-28 01:08:32 +0000534
Nate Begeman7c8c8832010-06-02 21:53:00 +0000535 OS << "#endif /* __ARM_NEON_H */\n";
Nate Begeman5ddb0872010-05-28 01:08:32 +0000536}