Mangle __builtin_neon_* names appropriately.
[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/DenseMap.h"
19 #include "llvm/ADT/SmallString.h"
20 #include "llvm/ADT/SmallVector.h"
21 #include "llvm/ADT/StringExtras.h"
22 #include "llvm/ADT/StringMap.h"
23 #include <string>
24
25 using namespace llvm;
26
27 enum 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,
45   OpOrNot,
46   OpCast
47 };
48
49 enum ClassKind {
50   ClassNone,
51   ClassI,
52   ClassS,
53   ClassW,
54   ClassB
55 };
56
57 static 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
85 static char Widen(const char t) {
86   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
98 static 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
111 static char ClassifyType(StringRef ty, bool &quad, bool &poly, bool &usgn) {
112   unsigned off = 0;
113   
114   // 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
136 static std::string TypeString(const char mod, StringRef typestr) {
137   bool quad = false;
138   bool poly = false;
139   bool usgn = false;
140   bool scal = false;
141   bool cnst = false;
142   bool pntr = false;
143   
144   // base type to get the type string for.
145   char type = ClassifyType(typestr, quad, poly, usgn);
146   
147   // Based on the modifying character, change the type and width if necessary.
148   switch (mod) {
149     case 'v':
150       return "void";
151     case 'i':
152       return "int";
153     case 't':
154       if (poly) {
155         poly = false;
156         usgn = true;
157       }
158       break;
159     case 'x':
160       usgn = true;
161       poly = false;
162       if (type == 'f')
163         type = 'i';
164       break;
165     case 'f':
166       type = 'f';
167       usgn = false;
168       break;
169     case 'w':
170       type = Widen(type);
171       quad = true;
172       break;
173     case 'n':
174       type = Widen(type);
175       break;
176     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;
193     case 'h':
194       type = Narrow(type);
195       break;
196     case 'e':
197       type = Narrow(type);
198       usgn = true;
199       break;
200     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;
246     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.
271 static std::string MangleName(const std::string &name, StringRef typestr,
272                               ClassKind ck) {
273   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) {
281   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;
332   }
333   if (ck == ClassB)
334     return s += "_v";
335     
336   // 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;
343 }
344
345 // Generate the string "(argtype a, argtype b, ...)"
346 static std::string GenArgs(const std::string &proto, StringRef typestr) {
347   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;
362 }
363
364 // 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"
367 static std::string GenOpString(OpKind op, const std::string &proto,
368                                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   
374   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";
379   
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;
432   case OpCast:
433     s += "(__neon_" + ts + ")" + a;
434     break;
435   default:
436     throw "unknown OpKind!";
437     break;
438   }
439   
440   if (structTypes)
441     s += "}";
442   s += ";";
443   return s;
444 }
445
446 // 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)
449 static std::string GenBuiltin(const std::string &name, const std::string &proto,
450                               StringRef typestr, ClassKind ck,
451                               bool structTypes = true) {
452   char arg = 'a';
453   std::string s;
454   
455   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   }    
464   
465   s += "__builtin_neon_";
466   s += MangleName(name, typestr, ck);
467   s += "(";
468   
469   for (unsigned i = 1, e = proto.size(); i != e; ++i, ++arg) {
470     s.push_back(arg);
471     if (structTypes && proto[i] != 's' && proto[i] != 'i' && proto[i] != 'l' &&
472         proto[i] != 'p' && proto[i] != 'c') {
473       s += ".val";
474     }
475     if ((i + 1) < e)
476       s += ", ";
477   }
478   
479   s += ")";
480   if (proto[0] != 'v' && structTypes)
481     s += "}";
482   s += ";";
483   return s;
484 }
485
486 void 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";
499
500   // Emit NEON-specific scalar typedefs.
501   // FIXME: probably need to do something better for polynomial types.
502   // FIXME: is this the correct thing to do for float16?
503   OS << "typedef float float32_t;\n";
504   OS << "typedef uint8_t poly8_t;\n";
505   OS << "typedef uint16_t poly16_t;\n";
506   OS << "typedef uint16_t float16_t;\n";
507   
508   // 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_";
521     OS << TypeString('d', TDTypeVec[i]) << ";\n";
522   }
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   }
537   
538   OS << "#define __ai static __attribute__((__always_inline__))\n\n";
539
540   std::vector<Record*> RV = Records.getAllDerivedDefinitions("Inst");
541   
542   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;
561   OpMap["OP_CAST"] = OpCast;
562   
563   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   
573   // Unique the return+pattern types, and assign them.
574   for (unsigned i = 0, e = RV.size(); i != e; ++i) {
575     Record *R = RV[i];
576     std::string name = LowercaseString(R->getName());
577     std::string Proto = R->getValueAsString("Prototype");
578     std::string Types = R->getValueAsString("Types");
579     
580     SmallVector<StringRef, 16> TypeVec;
581     ParseTypes(R, Types, TypeVec);
582     
583     OpKind k = OpMap[R->getValueAsDef("Operand")->getName()];
584     
585     for (unsigned ti = 0, te = TypeVec.size(); ti != te; ++ti) {
586       assert(!Proto.empty() && "");
587       
588       // static always inline + return type
589       OS << "__ai " << TypeString(Proto[0], TypeVec[ti]);
590       
591       // Function name with type suffix
592       OS << " " << MangleName(name, TypeVec[ti], ClassS);
593       
594       // Function arguments
595       OS << GenArgs(Proto, TypeVec[ti]);
596       
597       // Definition.
598       OS << " { ";
599       
600       if (k != OpNone) {
601         OS << GenOpString(k, Proto, TypeVec[ti]);
602       } 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       }
612
613       OS << " }\n";
614     }
615     OS << "\n";
616   }
617
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.
622   
623   OS << "#endif /* __ARM_NEON_H */\n";
624 }
625
626 void NeonEmitter::runHeader(raw_ostream &OS) {
627 }