blob: 43b75914e4a90c3ee2405a3caed6cad1bbaf4d6b [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 Begemana8979a02010-06-04 00:21:41 +000018#include "llvm/ADT/DenseMap.h"
Nate Begeman22237772010-06-02 00:34:55 +000019#include "llvm/ADT/SmallString.h"
20#include "llvm/ADT/SmallVector.h"
Nate Begeman5ddb0872010-05-28 01:08:32 +000021#include "llvm/ADT/StringExtras.h"
22#include "llvm/ADT/StringMap.h"
23#include <string>
24
25using namespace llvm;
26
Nate Begemane66aab52010-06-02 07:14:28 +000027enum OpKind {
28 OpNone,
29 OpAdd,
30 OpSub,
31 OpMul,
32 OpMla,
33 OpMls,
34 OpEq,
35 OpGe,
36 OpLe,
37 OpGt,
38 OpLt,
39 OpNeg,
40 OpNot,
41 OpAnd,
42 OpOr,
43 OpXor,
44 OpAndNot,
Nate Begeman3861e742010-06-03 21:35:22 +000045 OpOrNot,
46 OpCast
Nate Begemane66aab52010-06-02 07:14:28 +000047};
48
Nate Begemana8979a02010-06-04 00:21:41 +000049enum ClassKind {
50 ClassNone,
51 ClassI,
52 ClassS,
53 ClassW,
54 ClassB
55};
56
Nate Begeman22237772010-06-02 00:34:55 +000057static void ParseTypes(Record *r, std::string &s,
58 SmallVectorImpl<StringRef> &TV) {
59 const char *data = s.data();
60 int len = 0;
61
62 for (unsigned i = 0, e = s.size(); i != e; ++i, ++len) {
63 if (data[len] == 'P' || data[len] == 'Q' || data[len] == 'U')
64 continue;
65
66 switch (data[len]) {
67 case 'c':
68 case 's':
69 case 'i':
70 case 'l':
71 case 'h':
72 case 'f':
73 break;
74 default:
75 throw TGError(r->getLoc(),
76 "Unexpected letter: " + std::string(data + len, 1));
77 break;
78 }
79 TV.push_back(StringRef(data, len + 1));
80 data += len + 1;
81 len = -1;
82 }
83}
84
Duncan Sands8dbbace2010-06-02 08:37:30 +000085static char Widen(const char t) {
Nate Begeman22237772010-06-02 00:34:55 +000086 switch (t) {
87 case 'c':
88 return 's';
89 case 's':
90 return 'i';
91 case 'i':
92 return 'l';
93 default: throw "unhandled type in widen!";
94 }
95 return '\0';
96}
97
Nate Begeman3861e742010-06-03 21:35:22 +000098static char Narrow(const char t) {
99 switch (t) {
100 case 's':
101 return 'c';
102 case 'i':
103 return 's';
104 case 'l':
105 return 'i';
106 default: throw "unhandled type in widen!";
107 }
108 return '\0';
109}
110
Nate Begemanaf905ef2010-06-02 06:17:19 +0000111static char ClassifyType(StringRef ty, bool &quad, bool &poly, bool &usgn) {
Nate Begeman22237772010-06-02 00:34:55 +0000112 unsigned off = 0;
113
Nate Begemanaf905ef2010-06-02 06:17:19 +0000114 // remember quad.
115 if (ty[off] == 'Q') {
116 quad = true;
117 ++off;
118 }
119
120 // remember poly.
121 if (ty[off] == 'P') {
122 poly = true;
123 ++off;
124 }
125
126 // remember unsigned.
127 if (ty[off] == 'U') {
128 usgn = true;
129 ++off;
130 }
131
132 // base type to get the type string for.
133 return ty[off];
134}
135
136static std::string TypeString(const char mod, StringRef typestr) {
Nate Begeman22237772010-06-02 00:34:55 +0000137 bool quad = false;
138 bool poly = false;
139 bool usgn = false;
140 bool scal = false;
141 bool cnst = false;
142 bool pntr = false;
143
Nate Begeman22237772010-06-02 00:34:55 +0000144 // base type to get the type string for.
Nate Begemanaf905ef2010-06-02 06:17:19 +0000145 char type = ClassifyType(typestr, quad, poly, usgn);
Nate Begeman22237772010-06-02 00:34:55 +0000146
147 // Based on the modifying character, change the type and width if necessary.
148 switch (mod) {
149 case 'v':
Nate Begemane66aab52010-06-02 07:14:28 +0000150 return "void";
151 case 'i':
152 return "int";
Nate Begeman22237772010-06-02 00:34:55 +0000153 case 't':
154 if (poly) {
155 poly = false;
156 usgn = true;
157 }
158 break;
159 case 'x':
160 usgn = true;
Nate Begeman162d3ba2010-06-03 04:04:09 +0000161 poly = false;
Nate Begeman22237772010-06-02 00:34:55 +0000162 if (type == 'f')
163 type = 'i';
164 break;
165 case 'f':
166 type = 'f';
Nate Begeman162d3ba2010-06-03 04:04:09 +0000167 usgn = false;
Nate Begeman22237772010-06-02 00:34:55 +0000168 break;
169 case 'w':
170 type = Widen(type);
171 quad = true;
172 break;
173 case 'n':
174 type = Widen(type);
175 break;
Nate Begeman22237772010-06-02 00:34:55 +0000176 case 'l':
177 type = 'l';
178 scal = true;
179 usgn = true;
180 break;
181 case 's':
182 scal = true;
183 break;
184 case 'k':
185 quad = true;
186 break;
187 case 'c':
188 cnst = true;
189 case 'p':
190 pntr = true;
191 scal = true;
192 break;
Nate Begeman3861e742010-06-03 21:35:22 +0000193 case 'h':
194 type = Narrow(type);
195 break;
196 case 'e':
197 type = Narrow(type);
198 usgn = true;
199 break;
Nate Begeman22237772010-06-02 00:34:55 +0000200 default:
201 break;
202 }
203
204 SmallString<128> s;
205
206 if (usgn)
207 s.push_back('u');
208
209 switch (type) {
210 case 'c':
211 s += poly ? "poly8" : "int8";
212 if (scal)
213 break;
214 s += quad ? "x16" : "x8";
215 break;
216 case 's':
217 s += poly ? "poly16" : "int16";
218 if (scal)
219 break;
220 s += quad ? "x8" : "x4";
221 break;
222 case 'i':
223 s += "int32";
224 if (scal)
225 break;
226 s += quad ? "x4" : "x2";
227 break;
228 case 'l':
229 s += "int64";
230 if (scal)
231 break;
232 s += quad ? "x2" : "x1";
233 break;
234 case 'h':
235 s += "float16";
236 if (scal)
237 break;
238 s += quad ? "x8" : "x4";
239 break;
240 case 'f':
241 s += "float32";
242 if (scal)
243 break;
244 s += quad ? "x4" : "x2";
245 break;
Nate Begeman22237772010-06-02 00:34:55 +0000246 default:
247 throw "unhandled type!";
248 break;
249 }
250
251 if (mod == '2')
252 s += "x2";
253 if (mod == '3')
254 s += "x3";
255 if (mod == '4')
256 s += "x4";
257
258 // Append _t, finishing the type string typedef type.
259 s += "_t";
260
261 if (cnst)
262 s += " const";
263
264 if (pntr)
265 s += " *";
266
267 return s.str();
268}
269
270// Turn "vst2_lane" into "vst2q_lane_f32", etc.
Nate Begemana8979a02010-06-04 00:21:41 +0000271static std::string MangleName(const std::string &name, StringRef typestr,
272 ClassKind ck) {
Nate Begemanaf905ef2010-06-02 06:17:19 +0000273 bool quad = false;
274 bool poly = false;
275 bool usgn = false;
276 char type = ClassifyType(typestr, quad, poly, usgn);
277
278 std::string s = name;
279
280 switch (type) {
Nate Begemana8979a02010-06-04 00:21:41 +0000281 case 'c':
282 switch (ck) {
283 case ClassS: s += poly ? "_p8" : usgn ? "_u8" : "_s8"; break;
284 case ClassI: s += "_i8"; break;
285 case ClassW: s += "_8"; break;
286 default: break;
287 }
288 break;
289 case 's':
290 switch (ck) {
291 case ClassS: s += poly ? "_p16" : usgn ? "_u16" : "_s16"; break;
292 case ClassI: s += "_i16"; break;
293 case ClassW: s += "_16"; break;
294 default: break;
295 }
296 break;
297 case 'i':
298 switch (ck) {
299 case ClassS: s += usgn ? "_u32" : "_s32"; break;
300 case ClassI: s += "_i32"; break;
301 case ClassW: s += "_32"; break;
302 default: break;
303 }
304 break;
305 case 'l':
306 switch (ck) {
307 case ClassS: s += usgn ? "_u64" : "_s64"; break;
308 case ClassI: s += "_i64"; break;
309 case ClassW: s += "_64"; break;
310 default: break;
311 }
312 break;
313 case 'h':
314 switch (ck) {
315 case ClassS:
316 case ClassI: s += "_f16"; break;
317 case ClassW: s += "_16"; break;
318 default: break;
319 }
320 break;
321 case 'f':
322 switch (ck) {
323 case ClassS:
324 case ClassI: s += "_f32"; break;
325 case ClassW: s += "_32"; break;
326 default: break;
327 }
328 break;
329 default:
330 throw "unhandled type!";
331 break;
Nate Begemanaf905ef2010-06-02 06:17:19 +0000332 }
Nate Begemana8979a02010-06-04 00:21:41 +0000333 if (ck == ClassB)
334 return s += "_v";
335
Nate Begemanaf905ef2010-06-02 06:17:19 +0000336 // Insert a 'q' before the first '_' character so that it ends up before
337 // _lane or _n on vector-scalar operations.
338 if (quad) {
339 size_t pos = s.find('_');
340 s = s.insert(pos, "q");
341 }
342 return s;
Nate Begeman22237772010-06-02 00:34:55 +0000343}
344
Nate Begemanaf905ef2010-06-02 06:17:19 +0000345// Generate the string "(argtype a, argtype b, ...)"
Nate Begeman22237772010-06-02 00:34:55 +0000346static std::string GenArgs(const std::string &proto, StringRef typestr) {
Nate Begemanaf905ef2010-06-02 06:17:19 +0000347 char arg = 'a';
348
349 std::string s;
350 s += "(";
351
352 for (unsigned i = 1, e = proto.size(); i != e; ++i, ++arg) {
353 s += TypeString(proto[i], typestr);
354 s.push_back(' ');
355 s.push_back(arg);
356 if ((i + 1) < e)
357 s += ", ";
358 }
359
360 s += ")";
361 return s;
Nate Begeman22237772010-06-02 00:34:55 +0000362}
363
Nate Begeman7c8c8832010-06-02 21:53:00 +0000364// Generate the definition for this intrinsic, e.g. "a + b" for OpAdd.
365// If structTypes is true, the NEON types are structs of vector types rather
366// than vector types, and the call becomes "a.val + b.val"
367static std::string GenOpString(OpKind op, const std::string &proto,
Nate Begeman162d3ba2010-06-03 04:04:09 +0000368 StringRef typestr, bool structTypes = true) {
369 std::string s("return ");
370 std::string ts = TypeString(proto[0], typestr);
371 if (structTypes)
372 s += "(" + ts + "){";
373
Nate Begeman3861e742010-06-03 21:35:22 +0000374 std::string a, b, c;
375 if (proto.size() > 1)
376 a = (structTypes && proto[1] != 'l') ? "a.val" : "a";
377 b = structTypes ? "b.val" : "b";
378 c = structTypes ? "c.val" : "c";
Nate Begeman162d3ba2010-06-03 04:04:09 +0000379
380 switch(op) {
381 case OpAdd:
382 s += a + " + " + b;
383 break;
384 case OpSub:
385 s += a + " - " + b;
386 break;
387 case OpMul:
388 s += a + " * " + b;
389 break;
390 case OpMla:
391 s += a + " + ( " + b + " * " + c + " )";
392 break;
393 case OpMls:
394 s += a + " - ( " + b + " * " + c + " )";
395 break;
396 case OpEq:
397 s += "(__neon_" + ts + ")(" + a + " == " + b + ")";
398 break;
399 case OpGe:
400 s += "(__neon_" + ts + ")(" + a + " >= " + b + ")";
401 break;
402 case OpLe:
403 s += "(__neon_" + ts + ")(" + a + " <= " + b + ")";
404 break;
405 case OpGt:
406 s += "(__neon_" + ts + ")(" + a + " > " + b + ")";
407 break;
408 case OpLt:
409 s += "(__neon_" + ts + ")(" + a + " < " + b + ")";
410 break;
411 case OpNeg:
412 s += " -" + a;
413 break;
414 case OpNot:
415 s += " ~" + a;
416 break;
417 case OpAnd:
418 s += a + " & " + b;
419 break;
420 case OpOr:
421 s += a + " | " + b;
422 break;
423 case OpXor:
424 s += a + " ^ " + b;
425 break;
426 case OpAndNot:
427 s += a + " & ~" + b;
428 break;
429 case OpOrNot:
430 s += a + " | ~" + b;
431 break;
Nate Begeman3861e742010-06-03 21:35:22 +0000432 case OpCast:
433 s += "(__neon_" + ts + ")" + a;
434 break;
Nate Begeman162d3ba2010-06-03 04:04:09 +0000435 default:
436 throw "unknown OpKind!";
437 break;
438 }
439
440 if (structTypes)
441 s += "}";
442 s += ";";
443 return s;
Nate Begemane66aab52010-06-02 07:14:28 +0000444}
445
Nate Begeman7c8c8832010-06-02 21:53:00 +0000446// Generate the definition for this intrinsic, e.g. __builtin_neon_cls(a)
447// If structTypes is true, the NEON types are structs of vector types rather
448// than vector types, and the call becomes __builtin_neon_cls(a.val)
449static std::string GenBuiltin(const std::string &name, const std::string &proto,
Nate Begemana8979a02010-06-04 00:21:41 +0000450 StringRef typestr, ClassKind ck,
451 bool structTypes = true) {
Nate Begeman7c8c8832010-06-02 21:53:00 +0000452 char arg = 'a';
Nate Begeman162d3ba2010-06-03 04:04:09 +0000453 std::string s;
Nate Begeman7c8c8832010-06-02 21:53:00 +0000454
Nate Begeman162d3ba2010-06-03 04:04:09 +0000455 if (proto[0] != 'v') {
456 // FIXME: if return type is 2/3/4, emit unioning code.
457 s += "return ";
458 if (structTypes) {
459 s += "(";
460 s += TypeString(proto[0], typestr);
461 s += "){";
462 }
463 }
Nate Begeman7c8c8832010-06-02 21:53:00 +0000464
465 s += "__builtin_neon_";
Nate Begemana8979a02010-06-04 00:21:41 +0000466 s += MangleName(name, typestr, ck);
Nate Begeman7c8c8832010-06-02 21:53:00 +0000467 s += "(";
468
469 for (unsigned i = 1, e = proto.size(); i != e; ++i, ++arg) {
470 s.push_back(arg);
Nate Begeman162d3ba2010-06-03 04:04:09 +0000471 if (structTypes && proto[i] != 's' && proto[i] != 'i' && proto[i] != 'l' &&
472 proto[i] != 'p' && proto[i] != 'c') {
Nate Begeman7c8c8832010-06-02 21:53:00 +0000473 s += ".val";
Nate Begeman162d3ba2010-06-03 04:04:09 +0000474 }
Nate Begeman7c8c8832010-06-02 21:53:00 +0000475 if ((i + 1) < e)
476 s += ", ";
477 }
478
479 s += ")";
Nate Begeman162d3ba2010-06-03 04:04:09 +0000480 if (proto[0] != 'v' && structTypes)
Nate Begeman7c8c8832010-06-02 21:53:00 +0000481 s += "}";
482 s += ";";
483 return s;
Nate Begemane66aab52010-06-02 07:14:28 +0000484}
485
Nate Begeman5ddb0872010-05-28 01:08:32 +0000486void NeonEmitter::run(raw_ostream &OS) {
487 EmitSourceFileHeader("ARM NEON Header", OS);
488
489 // FIXME: emit license into file?
490
491 OS << "#ifndef __ARM_NEON_H\n";
492 OS << "#define __ARM_NEON_H\n\n";
493
494 OS << "#ifndef __ARM_NEON__\n";
495 OS << "#error \"NEON support not enabled\"\n";
496 OS << "#endif\n\n";
497
498 OS << "#include <stdint.h>\n\n";
Nate Begeman7c8c8832010-06-02 21:53:00 +0000499
500 // Emit NEON-specific scalar typedefs.
501 // FIXME: probably need to do something better for polynomial types.
Nate Begeman162d3ba2010-06-03 04:04:09 +0000502 // FIXME: is this the correct thing to do for float16?
Nate Begeman7c8c8832010-06-02 21:53:00 +0000503 OS << "typedef float float32_t;\n";
504 OS << "typedef uint8_t poly8_t;\n";
505 OS << "typedef uint16_t poly16_t;\n";
Nate Begeman162d3ba2010-06-03 04:04:09 +0000506 OS << "typedef uint16_t float16_t;\n";
Nate Begeman5ddb0872010-05-28 01:08:32 +0000507
Nate Begeman7c8c8832010-06-02 21:53:00 +0000508 // Emit Neon vector typedefs.
509 std::string TypedefTypes("cQcsQsiQilQlUcQUcUsQUsUiQUiUlQUlhQhfQfPcQPcPsQPs");
510 SmallVector<StringRef, 24> TDTypeVec;
511 ParseTypes(0, TypedefTypes, TDTypeVec);
512
513 // Emit vector typedefs.
514 for (unsigned i = 0, e = TDTypeVec.size(); i != e; ++i) {
515 bool dummy, quad = false;
516 (void) ClassifyType(TDTypeVec[i], quad, dummy, dummy);
517 OS << "typedef __attribute__(( __vector_size__(";
518 OS << (quad ? "16) )) " : "8) )) ");
519 OS << TypeString('s', TDTypeVec[i]);
520 OS << " __neon_";
Nate Begeman162d3ba2010-06-03 04:04:09 +0000521 OS << TypeString('d', TDTypeVec[i]) << ";\n";
Nate Begeman7c8c8832010-06-02 21:53:00 +0000522 }
523 OS << "\n";
524
525 // Emit struct typedefs.
526 for (unsigned vi = 1; vi != 5; ++vi) {
527 for (unsigned i = 0, e = TDTypeVec.size(); i != e; ++i) {
528 std::string ts = TypeString('d', TDTypeVec[i]);
529 std::string vs = (vi > 1) ? TypeString('0' + vi, TDTypeVec[i]) : ts;
530 OS << "typedef struct __" << vs << " {\n";
531 OS << " __neon_" << ts << " val";
532 if (vi > 1)
533 OS << "[" << utostr(vi) << "]";
534 OS << ";\n} " << vs << ";\n\n";
535 }
536 }
Nate Begeman5ddb0872010-05-28 01:08:32 +0000537
Nate Begeman7c8c8832010-06-02 21:53:00 +0000538 OS << "#define __ai static __attribute__((__always_inline__))\n\n";
539
Nate Begeman5ddb0872010-05-28 01:08:32 +0000540 std::vector<Record*> RV = Records.getAllDerivedDefinitions("Inst");
541
Nate Begeman162d3ba2010-06-03 04:04:09 +0000542 StringMap<OpKind> OpMap;
543 OpMap["OP_NONE"] = OpNone;
544 OpMap["OP_ADD"] = OpAdd;
545 OpMap["OP_SUB"] = OpSub;
546 OpMap["OP_MUL"] = OpMul;
547 OpMap["OP_MLA"] = OpMla;
548 OpMap["OP_MLS"] = OpMls;
549 OpMap["OP_EQ"] = OpEq;
550 OpMap["OP_GE"] = OpGe;
551 OpMap["OP_LE"] = OpLe;
552 OpMap["OP_GT"] = OpGt;
553 OpMap["OP_LT"] = OpLt;
554 OpMap["OP_NEG"] = OpNeg;
555 OpMap["OP_NOT"] = OpNot;
556 OpMap["OP_AND"] = OpAnd;
557 OpMap["OP_OR"] = OpOr;
558 OpMap["OP_XOR"] = OpXor;
559 OpMap["OP_ANDN"] = OpAndNot;
560 OpMap["OP_ORN"] = OpOrNot;
Nate Begeman3861e742010-06-03 21:35:22 +0000561 OpMap["OP_CAST"] = OpCast;
Nate Begeman162d3ba2010-06-03 04:04:09 +0000562
Nate Begemana8979a02010-06-04 00:21:41 +0000563 DenseMap<Record*, ClassKind> ClassMap;
564 Record *SI = Records.getClass("SInst");
565 Record *II = Records.getClass("IInst");
566 Record *WI = Records.getClass("WInst");
567 Record *BI = Records.getClass("BInst");
568 ClassMap[SI] = ClassS;
569 ClassMap[II] = ClassI;
570 ClassMap[WI] = ClassW;
571 ClassMap[BI] = ClassB;
572
Nate Begeman22237772010-06-02 00:34:55 +0000573 // Unique the return+pattern types, and assign them.
Nate Begeman5ddb0872010-05-28 01:08:32 +0000574 for (unsigned i = 0, e = RV.size(); i != e; ++i) {
575 Record *R = RV[i];
Nate Begeman22237772010-06-02 00:34:55 +0000576 std::string name = LowercaseString(R->getName());
577 std::string Proto = R->getValueAsString("Prototype");
Nate Begeman5ddb0872010-05-28 01:08:32 +0000578 std::string Types = R->getValueAsString("Types");
Nate Begeman22237772010-06-02 00:34:55 +0000579
580 SmallVector<StringRef, 16> TypeVec;
581 ParseTypes(R, Types, TypeVec);
582
Nate Begeman162d3ba2010-06-03 04:04:09 +0000583 OpKind k = OpMap[R->getValueAsDef("Operand")->getName()];
Nate Begemane66aab52010-06-02 07:14:28 +0000584
Nate Begeman22237772010-06-02 00:34:55 +0000585 for (unsigned ti = 0, te = TypeVec.size(); ti != te; ++ti) {
586 assert(!Proto.empty() && "");
587
Nate Begeman7c8c8832010-06-02 21:53:00 +0000588 // static always inline + return type
589 OS << "__ai " << TypeString(Proto[0], TypeVec[ti]);
Nate Begeman22237772010-06-02 00:34:55 +0000590
Nate Begemane66aab52010-06-02 07:14:28 +0000591 // Function name with type suffix
Nate Begemana8979a02010-06-04 00:21:41 +0000592 OS << " " << MangleName(name, TypeVec[ti], ClassS);
Nate Begeman22237772010-06-02 00:34:55 +0000593
Nate Begemane66aab52010-06-02 07:14:28 +0000594 // Function arguments
595 OS << GenArgs(Proto, TypeVec[ti]);
Nate Begeman22237772010-06-02 00:34:55 +0000596
Nate Begemane66aab52010-06-02 07:14:28 +0000597 // Definition.
598 OS << " { ";
Nate Begeman22237772010-06-02 00:34:55 +0000599
Nate Begemana8979a02010-06-04 00:21:41 +0000600 if (k != OpNone) {
Nate Begeman162d3ba2010-06-03 04:04:09 +0000601 OS << GenOpString(k, Proto, TypeVec[ti]);
Nate Begemana8979a02010-06-04 00:21:41 +0000602 } else {
603 if (R->getSuperClasses().size() < 2)
604 throw TGError(R->getLoc(), "Builtin has no class kind");
605
606 ClassKind ck = ClassMap[R->getSuperClasses()[1]];
607
608 if (ck == ClassNone)
609 throw TGError(R->getLoc(), "Builtin has no class kind");
610 OS << GenBuiltin(name, Proto, TypeVec[ti], ck);
611 }
Nate Begemane66aab52010-06-02 07:14:28 +0000612
Nate Begeman7c8c8832010-06-02 21:53:00 +0000613 OS << " }\n";
Nate Begeman22237772010-06-02 00:34:55 +0000614 }
615 OS << "\n";
Nate Begeman5ddb0872010-05-28 01:08:32 +0000616 }
Nate Begeman22237772010-06-02 00:34:55 +0000617
618 // TODO:
619 // Unique the return+pattern types, and assign them to each record
620 // Emit a #define for each unique "type" of intrinsic declaring all variants.
621 // Emit a #define for each intrinsic mapping it to a particular type.
Nate Begeman5ddb0872010-05-28 01:08:32 +0000622
Nate Begeman7c8c8832010-06-02 21:53:00 +0000623 OS << "#endif /* __ARM_NEON_H */\n";
Nate Begeman5ddb0872010-05-28 01:08:32 +0000624}
Nate Begemana8979a02010-06-04 00:21:41 +0000625
626void NeonEmitter::runHeader(raw_ostream &OS) {
627}