arm_neon.h now makes it through clang and generates appropriate code for those functi...
[oota-llvm.git] / utils / TableGen / NeonEmitter.cpp
1 //===- 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"
18 #include "llvm/ADT/SmallString.h"
19 #include "llvm/ADT/SmallVector.h"
20 #include "llvm/ADT/StringExtras.h"
21 #include "llvm/ADT/StringMap.h"
22 #include <string>
23
24 using namespace llvm;
25
26 enum 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
47 static 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
75 static char Widen(const char t) {
76   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
88 static char ClassifyType(StringRef ty, bool &quad, bool &poly, bool &usgn) {
89   unsigned off = 0;
90   
91   // 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
113 static std::string TypeString(const char mod, StringRef typestr) {
114   bool quad = false;
115   bool poly = false;
116   bool usgn = false;
117   bool scal = false;
118   bool cnst = false;
119   bool pntr = false;
120   
121   // base type to get the type string for.
122   char type = ClassifyType(typestr, quad, poly, usgn);
123   
124   // Based on the modifying character, change the type and width if necessary.
125   switch (mod) {
126     case 'v':
127       return "void";
128     case 'i':
129       return "int";
130     case 't':
131       if (poly) {
132         poly = false;
133         usgn = true;
134       }
135       break;
136     case 'x':
137       usgn = true;
138       poly = false;
139       if (type == 'f')
140         type = 'i';
141       break;
142     case 'f':
143       type = 'f';
144       usgn = false;
145       break;
146     case 'w':
147       type = Widen(type);
148       quad = true;
149       break;
150     case 'n':
151       type = Widen(type);
152       break;
153     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;
216     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.
241 static std::string MangleName(const std::string &name, StringRef typestr) {
242   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;
280 }
281
282 // Generate the string "(argtype a, argtype b, ...)"
283 static std::string GenArgs(const std::string &proto, StringRef typestr) {
284   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;
299 }
300
301 // 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"
304 static std::string GenOpString(OpKind op, const std::string &proto,
305                                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;
376 }
377
378 // 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)
381 static std::string GenBuiltin(const std::string &name, const std::string &proto,
382                               StringRef typestr, bool structTypes = true) {
383   char arg = 'a';
384   std::string s;
385   
386   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   }    
395   
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);
402     if (structTypes && proto[i] != 's' && proto[i] != 'i' && proto[i] != 'l' &&
403         proto[i] != 'p' && proto[i] != 'c') {
404       s += ".val";
405     }
406     if ((i + 1) < e)
407       s += ", ";
408   }
409   
410   s += ")";
411   if (proto[0] != 'v' && structTypes)
412     s += "}";
413   s += ";";
414   return s;
415 }
416
417 void 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";
430
431   // Emit NEON-specific scalar typedefs.
432   // FIXME: probably need to do something better for polynomial types.
433   // FIXME: is this the correct thing to do for float16?
434   OS << "typedef float float32_t;\n";
435   OS << "typedef uint8_t poly8_t;\n";
436   OS << "typedef uint16_t poly16_t;\n";
437   OS << "typedef uint16_t float16_t;\n";
438   
439   // 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_";
452     OS << TypeString('d', TDTypeVec[i]) << ";\n";
453   }
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   }
468   
469   OS << "#define __ai static __attribute__((__always_inline__))\n\n";
470
471   std::vector<Record*> RV = Records.getAllDerivedDefinitions("Inst");
472   
473   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   
493   // Unique the return+pattern types, and assign them.
494   for (unsigned i = 0, e = RV.size(); i != e; ++i) {
495     Record *R = RV[i];
496     std::string name = LowercaseString(R->getName());
497     std::string Proto = R->getValueAsString("Prototype");
498     std::string Types = R->getValueAsString("Types");
499     
500     SmallVector<StringRef, 16> TypeVec;
501     ParseTypes(R, Types, TypeVec);
502     
503     OpKind k = OpMap[R->getValueAsDef("Operand")->getName()];
504     
505     for (unsigned ti = 0, te = TypeVec.size(); ti != te; ++ti) {
506       assert(!Proto.empty() && "");
507       
508       // static always inline + return type
509       OS << "__ai " << TypeString(Proto[0], TypeVec[ti]);
510       
511       // Function name with type suffix
512       OS << " " << MangleName(name, TypeVec[ti]);
513       
514       // Function arguments
515       OS << GenArgs(Proto, TypeVec[ti]);
516       
517       // Definition.
518       OS << " { ";
519       
520       if (k != OpNone)
521         OS << GenOpString(k, Proto, TypeVec[ti]);
522       else
523         OS << GenBuiltin(name, Proto, TypeVec[ti]);
524
525       OS << " }\n";
526     }
527     OS << "\n";
528   }
529
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.
534   
535   OS << "#endif /* __ARM_NEON_H */\n";
536 }