9647666935ce6c7b4082c989b04376a24dbcb460
[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 "llvm/ADT/SmallString.h"
18 #include "llvm/ADT/SmallVector.h"
19 #include "llvm/ADT/StringExtras.h"
20 #include <string>
21
22 using namespace llvm;
23
24 static 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
52 static char Widen(const char t) {
53   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
65 static 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';
73     default: throw "unhandled type in widen!";
74   }
75   return '\0';
76 }
77
78 static char ClassifyType(StringRef ty, bool &quad, bool &poly, bool &usgn) {
79   unsigned off = 0;
80   
81   // remember quad.
82   if (ty[off] == 'Q') {
83     quad = true;
84     ++off;
85   }
86   
87   // remember poly.
88   if (ty[off] == 'P') {
89     poly = true;
90     ++off;
91   }
92   
93   // remember unsigned.
94   if (ty[off] == 'U') {
95     usgn = true;
96     ++off;
97   }
98   
99   // base type to get the type string for.
100   return ty[off];
101 }
102
103 static std::string TypeString(const char mod, StringRef typestr,
104                               bool ret = false) {
105   bool quad = false;
106   bool poly = false;
107   bool usgn = false;
108   bool scal = false;
109   bool cnst = false;
110   bool pntr = false;
111   
112   // base type to get the type string for.
113   char type = ClassifyType(typestr, quad, poly, usgn);
114   
115   // Based on the modifying character, change the type and width if necessary.
116   switch (mod) {
117     case 'v':
118       return "void";
119     case 'i':
120       return "int";
121     case 't':
122       if (poly) {
123         poly = false;
124         usgn = true;
125       }
126       break;
127     case 'x':
128       usgn = true;
129       poly = false;
130       if (type == 'f')
131         type = 'i';
132       break;
133     case 'f':
134       type = 'f';
135       usgn = false;
136       break;
137     case 'w':
138       type = Widen(type);
139       quad = true;
140       break;
141     case 'n':
142       type = Widen(type);
143       break;
144     case 'l':
145       type = 'l';
146       scal = true;
147       usgn = true;
148       break;
149     case 's':
150       scal = true;
151       break;
152     case 'k':
153       quad = true;
154       break;
155     case 'c':
156       cnst = true;
157     case 'p':
158       pntr = true;
159       scal = true;
160       break;
161     case 'h':
162       type = Narrow(type);
163       break;
164     case 'e':
165       type = Narrow(type);
166       usgn = true;
167       break;
168     default:
169       break;
170   }
171   
172   SmallString<128> s;
173   
174   if (ret)
175     s += "__neon_";
176   
177   if (usgn)
178     s.push_back('u');
179   
180   switch (type) {
181     case 'c':
182       s += poly ? "poly8" : "int8";
183       if (scal)
184         break;
185       s += quad ? "x16" : "x8";
186       break;
187     case 's':
188       s += poly ? "poly16" : "int16";
189       if (scal)
190         break;
191       s += quad ? "x8" : "x4";
192       break;
193     case 'i':
194       s += "int32";
195       if (scal)
196         break;
197       s += quad ? "x4" : "x2";
198       break;
199     case 'l':
200       s += "int64";
201       if (scal)
202         break;
203       s += quad ? "x2" : "x1";
204       break;
205     case 'h':
206       s += "float16";
207       if (scal)
208         break;
209       s += quad ? "x8" : "x4";
210       break;
211     case 'f':
212       s += "float32";
213       if (scal)
214         break;
215       s += quad ? "x4" : "x2";
216       break;
217     default:
218       throw "unhandled type!";
219       break;
220   }
221
222   if (mod == '2')
223     s += "x2";
224   if (mod == '3')
225     s += "x3";
226   if (mod == '4')
227     s += "x4";
228   
229   // Append _t, finishing the type string typedef type.
230   s += "_t";
231   
232   if (cnst)
233     s += " const";
234   
235   if (pntr)
236     s += " *";
237   
238   return s.str();
239 }
240
241 static std::string BuiltinTypeString(const char mod, StringRef typestr,
242                                      ClassKind ck, bool ret) {
243   bool quad = false;
244   bool poly = false;
245   bool usgn = false;
246   bool scal = false;
247   bool cnst = false;
248   bool pntr = false;
249   
250   if (mod == 'v')
251     return "v";
252   if (mod == 'i')
253     return "i";
254   
255   // base type to get the type string for.
256   char type = ClassifyType(typestr, quad, poly, usgn);
257   
258   // Based on the modifying character, change the type and width if necessary.
259   switch (mod) {
260     case 't':
261       if (poly) {
262         poly = false;
263         usgn = true;
264       }
265       break;
266     case 'x':
267       usgn = true;
268       poly = false;
269       if (type == 'f')
270         type = 'i';
271       break;
272     case 'f':
273       type = 'f';
274       usgn = false;
275       break;
276     case 'w':
277       type = Widen(type);
278       quad = true;
279       break;
280     case 'n':
281       type = Widen(type);
282       break;
283     case 'l':
284       type = 'l';
285       scal = true;
286       usgn = true;
287       break;
288     case 's':
289       scal = true;
290       break;
291     case 'k':
292       quad = true;
293       break;
294     case 'c':
295       cnst = true;
296     case 'p':
297       type = 'v';
298       usgn = false;
299       poly = false;
300       pntr = true;
301       scal = true;
302       break;
303     case 'h':
304       type = Narrow(type);
305       break;
306     case 'e':
307       type = Narrow(type);
308       usgn = true;
309       break;
310     default:
311       break;
312   }
313   if (type == 'h') {
314     type = 's';
315     usgn = true;
316   }
317   usgn = usgn | poly | ((ck == ClassI || ck == ClassW) && scal && type != 'f');
318
319   if (scal) {
320     SmallString<128> s;
321
322     if (usgn)
323       s.push_back('U');
324     
325     if (type == 'l')
326       s += "LLi";
327     else
328       s.push_back(type);
329  
330     if (cnst)
331       s.push_back('C');
332     if (pntr)
333       s.push_back('*');
334     return s.str();
335   }
336
337   // Since the return value must be one type, return a vector type of the
338   // appropriate width which we will bitcast.
339   if (ret) {
340     if (mod == '2')
341       return quad ? "V32c" : "V16c";
342     if (mod == '3')
343       return quad ? "V48c" : "V24c";
344     if (mod == '4')
345       return quad ? "V64c" : "V32c";
346
347     return quad ? "V16c" : "V8c";
348   }    
349
350   // Non-return array types are passed as individual vectors.
351   if (mod == '2')
352     return quad ? "V16cV16c" : "V8cV8c";
353   if (mod == '3')
354     return quad ? "V16cV16cV16c" : "V8cV8cV8c";
355   if (mod == '4')
356     return quad ? "V16cV16cV16cV16c" : "V8cV8cV8cV8c";
357
358   return quad ? "V16c" : "V8c";
359 }
360
361 // Turn "vst2_lane" into "vst2q_lane_f32", etc.
362 static std::string MangleName(const std::string &name, StringRef typestr,
363                               ClassKind ck) {
364   bool quad = false;
365   bool poly = false;
366   bool usgn = false;
367   char type = ClassifyType(typestr, quad, poly, usgn);
368
369   std::string s = name;
370   
371   switch (type) {
372   case 'c':
373     switch (ck) {
374     case ClassS: s += poly ? "_p8" : usgn ? "_u8" : "_s8"; break;
375     case ClassI: s += "_i8"; break;
376     case ClassW: s += "_8"; break;
377     default: break;
378     }
379     break;
380   case 's':
381     switch (ck) {
382     case ClassS: s += poly ? "_p16" : usgn ? "_u16" : "_s16"; break;
383     case ClassI: s += "_i16"; break;
384     case ClassW: s += "_16"; break;
385     default: break;
386     }
387     break;
388   case 'i':
389     switch (ck) {
390     case ClassS: s += usgn ? "_u32" : "_s32"; break;
391     case ClassI: s += "_i32"; break;
392     case ClassW: s += "_32"; break;
393     default: break;
394     }
395     break;
396   case 'l':
397     switch (ck) {
398     case ClassS: s += usgn ? "_u64" : "_s64"; break;
399     case ClassI: s += "_i64"; break;
400     case ClassW: s += "_64"; break;
401     default: break;
402     }
403     break;
404   case 'h':
405     switch (ck) {
406     case ClassS:
407     case ClassI: s += "_f16"; break;
408     case ClassW: s += "_16"; break;
409     default: break;
410     }
411     break;
412   case 'f':
413     switch (ck) {
414     case ClassS:
415     case ClassI: s += "_f32"; break;
416     case ClassW: s += "_32"; break;
417     default: break;
418     }
419     break;
420   default:
421     throw "unhandled type!";
422     break;
423   }
424   if (ck == ClassB)
425     s += "_v";
426     
427   // Insert a 'q' before the first '_' character so that it ends up before 
428   // _lane or _n on vector-scalar operations.
429   if (quad) {
430     size_t pos = s.find('_');
431     s = s.insert(pos, "q");
432   }
433   return s;
434 }
435
436 // Generate the string "(argtype a, argtype b, ...)"
437 static std::string GenArgs(const std::string &proto, StringRef typestr) {
438   char arg = 'a';
439   
440   std::string s;
441   s += "(";
442   
443   for (unsigned i = 1, e = proto.size(); i != e; ++i, ++arg) {
444     s += TypeString(proto[i], typestr);
445     s.push_back(' ');
446     s.push_back(arg);
447     if ((i + 1) < e)
448       s += ", ";
449   }
450   
451   s += ")";
452   return s;
453 }
454
455 // Generate the definition for this intrinsic, e.g. "a + b" for OpAdd.
456 // If structTypes is true, the NEON types are structs of vector types rather
457 // than vector types, and the call becomes "a.val + b.val"
458 static std::string GenOpString(OpKind op, const std::string &proto,
459                                StringRef typestr, bool structTypes = true) {
460   std::string s("return ");
461   std::string ts = TypeString(proto[0], typestr);
462   if (structTypes)
463     s += "(" + ts + "){";
464   
465   std::string a, b, c;
466   if (proto.size() > 1)
467     a = (structTypes && proto[1] != 'l') ? "a.val" : "a";
468   b = structTypes ? "b.val" : "b";
469   c = structTypes ? "c.val" : "c";
470   
471   switch(op) {
472   case OpAdd:
473     s += a + " + " + b;
474     break;
475   case OpSub:
476     s += a + " - " + b;
477     break;
478   case OpMul:
479     s += a + " * " + b;
480     break;
481   case OpMla:
482     s += a + " + ( " + b + " * " + c + " )";
483     break;
484   case OpMls:
485     s += a + " - ( " + b + " * " + c + " )";
486     break;
487   case OpEq:
488     s += "(__neon_" + ts + ")(" + a + " == " + b + ")";
489     break;
490   case OpGe:
491     s += "(__neon_" + ts + ")(" + a + " >= " + b + ")";
492     break;
493   case OpLe:
494     s += "(__neon_" + ts + ")(" + a + " <= " + b + ")";
495     break;
496   case OpGt:
497     s += "(__neon_" + ts + ")(" + a + " > " + b + ")";
498     break;
499   case OpLt:
500     s += "(__neon_" + ts + ")(" + a + " < " + b + ")";
501     break;
502   case OpNeg:
503     s += " -" + a;
504     break;
505   case OpNot:
506     s += " ~" + a;
507     break;
508   case OpAnd:
509     s += a + " & " + b;
510     break;
511   case OpOr:
512     s += a + " | " + b;
513     break;
514   case OpXor:
515     s += a + " ^ " + b;
516     break;
517   case OpAndNot:
518     s += a + " & ~" + b;
519     break;
520   case OpOrNot:
521     s += a + " | ~" + b;
522     break;
523   case OpCast:
524     s += "(__neon_" + ts + ")" + a;
525     break;
526   default:
527     throw "unknown OpKind!";
528     break;
529   }
530   
531   if (structTypes)
532     s += "}";
533   s += ";";
534   return s;
535 }
536
537 // Generate the definition for this intrinsic, e.g. __builtin_neon_cls(a)
538 // If structTypes is true, the NEON types are structs of vector types rather
539 // than vector types, and the call becomes __builtin_neon_cls(a.val)
540 static std::string GenBuiltin(const std::string &name, const std::string &proto,
541                               StringRef typestr, ClassKind ck,
542                               bool structTypes = true) {
543   char arg = 'a';
544   std::string s;
545
546   bool unioning = (proto[0] == '2' || proto[0] == '3' || proto[0] == '4');
547
548   // If all types are the same size, bitcasting the args will take care 
549   // of arg checking.  The actual signedness etc. will be taken care of with
550   // special enums.
551   if (proto.find('s') == std::string::npos)
552     ck = ClassB;
553
554   if (proto[0] != 'v') {
555     if (unioning) {
556       s += "union { ";
557       s += TypeString(proto[0], typestr, true) + " val; ";
558       s += TypeString(proto[0], typestr, false) + " s; ";
559       s += "} r;";
560     } else {
561       s += TypeString(proto[0], typestr);
562     }
563     
564     s += " r; r";
565     if (structTypes && proto[0] != 's' && proto[0] != 'i' && proto[0] != 'l')
566       s += ".val";
567     
568     s += " = ";
569   }    
570   
571   s += "__builtin_neon_";
572   s += MangleName(name, typestr, ck);
573   s += "(";
574   
575   for (unsigned i = 1, e = proto.size(); i != e; ++i, ++arg) {
576     // Handle multiple-vector values specially, emitting each subvector as an
577     // argument to the __builtin.
578     if (structTypes && (proto[i] == '2' || proto[i] == '3' || proto[i] == '4')){
579       for (unsigned vi = 0, ve = proto[i] - '0'; vi != ve; ++vi) {
580         s.push_back(arg);
581         s += ".val[" + utostr(vi) + "]";
582         if ((vi + 1) < ve)
583           s += ", ";
584       }
585       if ((i + 1) < e)
586         s += ", ";
587
588       continue;
589     }
590     
591     s.push_back(arg);
592     
593     if (structTypes && proto[i] != 's' && proto[i] != 'i' && proto[i] != 'l' &&
594         proto[i] != 'p' && proto[i] != 'c') {
595       s += ".val";
596     }
597     if ((i + 1) < e)
598       s += ", ";
599   }
600   
601   // Extra constant integer to hold type class enum for this function, e.g. s8
602   // FIXME: emit actual type num.
603   if (ck == ClassB)
604     s += ", 0";
605   
606   s += ");";
607
608   if (proto[0] != 'v') {
609     if (unioning)
610       s += " return r.s;";
611     else
612       s += " return r;";
613   }
614   return s;
615 }
616
617 static std::string GenBuiltinDef(const std::string &name, 
618                                  const std::string &proto,
619                                  StringRef typestr, ClassKind ck) {
620   std::string s("BUILTIN(__builtin_neon_");
621
622   // If all types are the same size, bitcasting the args will take care 
623   // of arg checking.  The actual signedness etc. will be taken care of with
624   // special enums.
625   if (proto.find('s') == std::string::npos)
626     ck = ClassB;
627   
628   s += MangleName(name, typestr, ck);
629   s += ", \"";
630   
631   for (unsigned i = 0, e = proto.size(); i != e; ++i)
632     s += BuiltinTypeString(proto[i], typestr, ck, i == 0);
633
634   // Extra constant integer to hold type class enum for this function, e.g. s8
635   if (ck == ClassB)
636     s += "i";
637   
638   s += "\", \"n\")";
639   return s;
640 }
641
642 void NeonEmitter::run(raw_ostream &OS) {
643   EmitSourceFileHeader("ARM NEON Header", OS);
644   
645   // FIXME: emit license into file?
646   
647   OS << "#ifndef __ARM_NEON_H\n";
648   OS << "#define __ARM_NEON_H\n\n";
649   
650   OS << "#ifndef __ARM_NEON__\n";
651   OS << "#error \"NEON support not enabled\"\n";
652   OS << "#endif\n\n";
653
654   OS << "#include <stdint.h>\n\n";
655
656   // Emit NEON-specific scalar typedefs.
657   // FIXME: probably need to do something better for polynomial types.
658   // FIXME: is this the correct thing to do for float16?
659   OS << "typedef float float32_t;\n";
660   OS << "typedef uint8_t poly8_t;\n";
661   OS << "typedef uint16_t poly16_t;\n";
662   OS << "typedef uint16_t float16_t;\n";
663
664   // Emit Neon vector typedefs.
665   std::string TypedefTypes("cQcsQsiQilQlUcQUcUsQUsUiQUiUlQUlhQhfQfPcQPcPsQPs");
666   SmallVector<StringRef, 24> TDTypeVec;
667   ParseTypes(0, TypedefTypes, TDTypeVec);
668
669   // Emit vector typedefs.
670   for (unsigned v = 1; v != 5; ++v) {
671     for (unsigned i = 0, e = TDTypeVec.size(); i != e; ++i) {
672       bool dummy, quad = false;
673       (void) ClassifyType(TDTypeVec[i], quad, dummy, dummy);
674       OS << "typedef __attribute__(( __vector_size__(";
675       
676       OS << utostr(8*v*(quad ? 2 : 1)) << ") )) ";
677       if (!quad)
678         OS << " ";
679       
680       OS << TypeString('s', TDTypeVec[i]);
681       OS << " __neon_";
682       
683       char t = (v == 1) ? 'd' : '0' + v;
684       OS << TypeString(t, TDTypeVec[i]) << ";\n";
685     }
686   }
687   OS << "\n";
688
689   // Emit struct typedefs.
690   for (unsigned vi = 1; vi != 5; ++vi) {
691     for (unsigned i = 0, e = TDTypeVec.size(); i != e; ++i) {
692       std::string ts = TypeString('d', TDTypeVec[i]);
693       std::string vs = (vi > 1) ? TypeString('0' + vi, TDTypeVec[i]) : ts;
694       OS << "typedef struct __" << vs << " {\n";
695       OS << "  __neon_" << ts << " val";
696       if (vi > 1)
697         OS << "[" << utostr(vi) << "]";
698       OS << ";\n} " << vs << ";\n\n";
699     }
700   }
701   
702   OS << "#define __ai static __attribute__((__always_inline__))\n\n";
703
704   std::vector<Record*> RV = Records.getAllDerivedDefinitions("Inst");
705   
706   // Unique the return+pattern types, and assign them.
707   for (unsigned i = 0, e = RV.size(); i != e; ++i) {
708     Record *R = RV[i];
709     std::string name = LowercaseString(R->getName());
710     std::string Proto = R->getValueAsString("Prototype");
711     std::string Types = R->getValueAsString("Types");
712     
713     SmallVector<StringRef, 16> TypeVec;
714     ParseTypes(R, Types, TypeVec);
715     
716     OpKind k = OpMap[R->getValueAsDef("Operand")->getName()];
717     
718     for (unsigned ti = 0, te = TypeVec.size(); ti != te; ++ti) {
719       assert(!Proto.empty() && "");
720       
721       // static always inline + return type
722       OS << "__ai " << TypeString(Proto[0], TypeVec[ti]);
723       
724       // Function name with type suffix
725       OS << " " << MangleName(name, TypeVec[ti], ClassS);
726       
727       // Function arguments
728       OS << GenArgs(Proto, TypeVec[ti]);
729       
730       // Definition.
731       OS << " { ";
732       
733       if (k != OpNone) {
734         OS << GenOpString(k, Proto, TypeVec[ti]);
735       } else {
736         if (R->getSuperClasses().size() < 2)
737           throw TGError(R->getLoc(), "Builtin has no class kind");
738         
739         ClassKind ck = ClassMap[R->getSuperClasses()[1]];
740
741         if (ck == ClassNone)
742           throw TGError(R->getLoc(), "Builtin has no class kind");
743         OS << GenBuiltin(name, Proto, TypeVec[ti], ck);
744       }
745
746       OS << " }\n";
747     }
748     OS << "\n";
749   }
750   OS << "#undef __ai\n\n";
751   OS << "#endif /* __ARM_NEON_H */\n";
752 }
753
754 void NeonEmitter::runHeader(raw_ostream &OS) {
755   std::vector<Record*> RV = Records.getAllDerivedDefinitions("Inst");
756
757   StringMap<OpKind> EmittedMap;
758   
759   for (unsigned i = 0, e = RV.size(); i != e; ++i) {
760     Record *R = RV[i];
761
762     OpKind k = OpMap[R->getValueAsDef("Operand")->getName()];
763     if (k != OpNone)
764       continue;
765     
766     std::string name = LowercaseString(R->getName());
767     std::string Proto = R->getValueAsString("Prototype");
768     std::string Types = R->getValueAsString("Types");
769
770     SmallVector<StringRef, 16> TypeVec;
771     ParseTypes(R, Types, TypeVec);
772
773     if (R->getSuperClasses().size() < 2)
774       throw TGError(R->getLoc(), "Builtin has no class kind");
775     
776     ClassKind ck = ClassMap[R->getSuperClasses()[1]];
777     
778     for (unsigned ti = 0, te = TypeVec.size(); ti != te; ++ti) {
779       std::string bd = GenBuiltinDef(name, Proto, TypeVec[ti], ck);
780       if (EmittedMap.count(bd))
781         continue;
782       
783       EmittedMap[bd] = OpNone;
784       OS << bd << "\n";
785     }
786   }
787 }