NeonEmitter.cpp revision 251662
1226586Sdim//===- NeonEmitter.cpp - Generate arm_neon.h for use with clang -*- C++ -*-===//
2226586Sdim//
3226586Sdim//                     The LLVM Compiler Infrastructure
4226586Sdim//
5226586Sdim// This file is distributed under the University of Illinois Open Source
6226586Sdim// License. See LICENSE.TXT for details.
7226586Sdim//
8226586Sdim//===----------------------------------------------------------------------===//
9226586Sdim//
10226586Sdim// This tablegen backend is responsible for emitting arm_neon.h, which includes
11226586Sdim// a declaration and definition of each function specified by the ARM NEON
12226586Sdim// compiler interface.  See ARM document DUI0348B.
13226586Sdim//
14226586Sdim// Each NEON instruction is implemented in terms of 1 or more functions which
15226586Sdim// are suffixed with the element type of the input vectors.  Functions may be
16226586Sdim// implemented in terms of generic vector operations such as +, *, -, etc. or
17226586Sdim// by calling a __builtin_-prefixed function which will be handled by clang's
18226586Sdim// CodeGen library.
19226586Sdim//
20226586Sdim// Additional validation code can be generated by this file when runHeader() is
21226586Sdim// called, rather than the normal run() entry point.  A complete set of tests
22226586Sdim// for Neon intrinsics can be generated by calling the runTests() entry point.
23226586Sdim//
24226586Sdim//===----------------------------------------------------------------------===//
25226586Sdim
26239462Sdim#include "llvm/ADT/DenseMap.h"
27226586Sdim#include "llvm/ADT/SmallString.h"
28226586Sdim#include "llvm/ADT/SmallVector.h"
29226586Sdim#include "llvm/ADT/StringExtras.h"
30239462Sdim#include "llvm/ADT/StringMap.h"
31234353Sdim#include "llvm/Support/ErrorHandling.h"
32239462Sdim#include "llvm/TableGen/Error.h"
33239462Sdim#include "llvm/TableGen/Record.h"
34239462Sdim#include "llvm/TableGen/TableGenBackend.h"
35226586Sdim#include <string>
36226586Sdimusing namespace llvm;
37226586Sdim
38239462Sdimenum OpKind {
39239462Sdim  OpNone,
40239462Sdim  OpUnavailable,
41239462Sdim  OpAdd,
42239462Sdim  OpAddl,
43239462Sdim  OpAddw,
44239462Sdim  OpSub,
45239462Sdim  OpSubl,
46239462Sdim  OpSubw,
47239462Sdim  OpMul,
48239462Sdim  OpMla,
49239462Sdim  OpMlal,
50239462Sdim  OpMls,
51239462Sdim  OpMlsl,
52239462Sdim  OpMulN,
53239462Sdim  OpMlaN,
54239462Sdim  OpMlsN,
55239462Sdim  OpMlalN,
56239462Sdim  OpMlslN,
57239462Sdim  OpMulLane,
58239462Sdim  OpMullLane,
59239462Sdim  OpMlaLane,
60239462Sdim  OpMlsLane,
61239462Sdim  OpMlalLane,
62239462Sdim  OpMlslLane,
63239462Sdim  OpQDMullLane,
64239462Sdim  OpQDMlalLane,
65239462Sdim  OpQDMlslLane,
66239462Sdim  OpQDMulhLane,
67239462Sdim  OpQRDMulhLane,
68239462Sdim  OpEq,
69239462Sdim  OpGe,
70239462Sdim  OpLe,
71239462Sdim  OpGt,
72239462Sdim  OpLt,
73239462Sdim  OpNeg,
74239462Sdim  OpNot,
75239462Sdim  OpAnd,
76239462Sdim  OpOr,
77239462Sdim  OpXor,
78239462Sdim  OpAndNot,
79239462Sdim  OpOrNot,
80239462Sdim  OpCast,
81239462Sdim  OpConcat,
82239462Sdim  OpDup,
83239462Sdim  OpDupLane,
84239462Sdim  OpHi,
85239462Sdim  OpLo,
86239462Sdim  OpSelect,
87239462Sdim  OpRev16,
88239462Sdim  OpRev32,
89239462Sdim  OpRev64,
90239462Sdim  OpReinterpret,
91239462Sdim  OpAbdl,
92239462Sdim  OpAba,
93239462Sdim  OpAbal
94239462Sdim};
95239462Sdim
96239462Sdimenum ClassKind {
97239462Sdim  ClassNone,
98239462Sdim  ClassI,           // generic integer instruction, e.g., "i8" suffix
99239462Sdim  ClassS,           // signed/unsigned/poly, e.g., "s8", "u8" or "p8" suffix
100239462Sdim  ClassW,           // width-specific instruction, e.g., "8" suffix
101251662Sdim  ClassB,           // bitcast arguments with enum argument to specify type
102251662Sdim  ClassL,           // Logical instructions which are op instructions
103251662Sdim                    // but we need to not emit any suffix for in our
104251662Sdim                    // tests.
105251662Sdim  ClassNoTest       // Instructions which we do not test since they are
106251662Sdim                    // not TRUE instructions.
107239462Sdim};
108239462Sdim
109239462Sdim/// NeonTypeFlags - Flags to identify the types for overloaded Neon
110239462Sdim/// builtins.  These must be kept in sync with the flags in
111239462Sdim/// include/clang/Basic/TargetBuiltins.h.
112239462Sdimnamespace {
113239462Sdimclass NeonTypeFlags {
114239462Sdim  enum {
115239462Sdim    EltTypeMask = 0xf,
116239462Sdim    UnsignedFlag = 0x10,
117239462Sdim    QuadFlag = 0x20
118239462Sdim  };
119239462Sdim  uint32_t Flags;
120239462Sdim
121239462Sdimpublic:
122239462Sdim  enum EltType {
123239462Sdim    Int8,
124239462Sdim    Int16,
125239462Sdim    Int32,
126239462Sdim    Int64,
127239462Sdim    Poly8,
128239462Sdim    Poly16,
129239462Sdim    Float16,
130239462Sdim    Float32
131239462Sdim  };
132239462Sdim
133239462Sdim  NeonTypeFlags(unsigned F) : Flags(F) {}
134239462Sdim  NeonTypeFlags(EltType ET, bool IsUnsigned, bool IsQuad) : Flags(ET) {
135239462Sdim    if (IsUnsigned)
136239462Sdim      Flags |= UnsignedFlag;
137239462Sdim    if (IsQuad)
138239462Sdim      Flags |= QuadFlag;
139239462Sdim  }
140239462Sdim
141239462Sdim  uint32_t getFlags() const { return Flags; }
142239462Sdim};
143239462Sdim} // end anonymous namespace
144239462Sdim
145239462Sdimnamespace {
146239462Sdimclass NeonEmitter {
147239462Sdim  RecordKeeper &Records;
148239462Sdim  StringMap<OpKind> OpMap;
149239462Sdim  DenseMap<Record*, ClassKind> ClassMap;
150239462Sdim
151239462Sdimpublic:
152239462Sdim  NeonEmitter(RecordKeeper &R) : Records(R) {
153239462Sdim    OpMap["OP_NONE"]  = OpNone;
154239462Sdim    OpMap["OP_UNAVAILABLE"] = OpUnavailable;
155239462Sdim    OpMap["OP_ADD"]   = OpAdd;
156239462Sdim    OpMap["OP_ADDL"]  = OpAddl;
157239462Sdim    OpMap["OP_ADDW"]  = OpAddw;
158239462Sdim    OpMap["OP_SUB"]   = OpSub;
159239462Sdim    OpMap["OP_SUBL"]  = OpSubl;
160239462Sdim    OpMap["OP_SUBW"]  = OpSubw;
161239462Sdim    OpMap["OP_MUL"]   = OpMul;
162239462Sdim    OpMap["OP_MLA"]   = OpMla;
163239462Sdim    OpMap["OP_MLAL"]  = OpMlal;
164239462Sdim    OpMap["OP_MLS"]   = OpMls;
165239462Sdim    OpMap["OP_MLSL"]  = OpMlsl;
166239462Sdim    OpMap["OP_MUL_N"] = OpMulN;
167239462Sdim    OpMap["OP_MLA_N"] = OpMlaN;
168239462Sdim    OpMap["OP_MLS_N"] = OpMlsN;
169239462Sdim    OpMap["OP_MLAL_N"] = OpMlalN;
170239462Sdim    OpMap["OP_MLSL_N"] = OpMlslN;
171239462Sdim    OpMap["OP_MUL_LN"]= OpMulLane;
172239462Sdim    OpMap["OP_MULL_LN"] = OpMullLane;
173239462Sdim    OpMap["OP_MLA_LN"]= OpMlaLane;
174239462Sdim    OpMap["OP_MLS_LN"]= OpMlsLane;
175239462Sdim    OpMap["OP_MLAL_LN"] = OpMlalLane;
176239462Sdim    OpMap["OP_MLSL_LN"] = OpMlslLane;
177239462Sdim    OpMap["OP_QDMULL_LN"] = OpQDMullLane;
178239462Sdim    OpMap["OP_QDMLAL_LN"] = OpQDMlalLane;
179239462Sdim    OpMap["OP_QDMLSL_LN"] = OpQDMlslLane;
180239462Sdim    OpMap["OP_QDMULH_LN"] = OpQDMulhLane;
181239462Sdim    OpMap["OP_QRDMULH_LN"] = OpQRDMulhLane;
182239462Sdim    OpMap["OP_EQ"]    = OpEq;
183239462Sdim    OpMap["OP_GE"]    = OpGe;
184239462Sdim    OpMap["OP_LE"]    = OpLe;
185239462Sdim    OpMap["OP_GT"]    = OpGt;
186239462Sdim    OpMap["OP_LT"]    = OpLt;
187239462Sdim    OpMap["OP_NEG"]   = OpNeg;
188239462Sdim    OpMap["OP_NOT"]   = OpNot;
189239462Sdim    OpMap["OP_AND"]   = OpAnd;
190239462Sdim    OpMap["OP_OR"]    = OpOr;
191239462Sdim    OpMap["OP_XOR"]   = OpXor;
192239462Sdim    OpMap["OP_ANDN"]  = OpAndNot;
193239462Sdim    OpMap["OP_ORN"]   = OpOrNot;
194239462Sdim    OpMap["OP_CAST"]  = OpCast;
195239462Sdim    OpMap["OP_CONC"]  = OpConcat;
196239462Sdim    OpMap["OP_HI"]    = OpHi;
197239462Sdim    OpMap["OP_LO"]    = OpLo;
198239462Sdim    OpMap["OP_DUP"]   = OpDup;
199239462Sdim    OpMap["OP_DUP_LN"] = OpDupLane;
200239462Sdim    OpMap["OP_SEL"]   = OpSelect;
201239462Sdim    OpMap["OP_REV16"] = OpRev16;
202239462Sdim    OpMap["OP_REV32"] = OpRev32;
203239462Sdim    OpMap["OP_REV64"] = OpRev64;
204239462Sdim    OpMap["OP_REINT"] = OpReinterpret;
205239462Sdim    OpMap["OP_ABDL"]  = OpAbdl;
206239462Sdim    OpMap["OP_ABA"]   = OpAba;
207239462Sdim    OpMap["OP_ABAL"]  = OpAbal;
208239462Sdim
209239462Sdim    Record *SI = R.getClass("SInst");
210239462Sdim    Record *II = R.getClass("IInst");
211239462Sdim    Record *WI = R.getClass("WInst");
212251662Sdim    Record *SOpI = R.getClass("SOpInst");
213251662Sdim    Record *IOpI = R.getClass("IOpInst");
214251662Sdim    Record *WOpI = R.getClass("WOpInst");
215251662Sdim    Record *LOpI = R.getClass("LOpInst");
216251662Sdim    Record *NoTestOpI = R.getClass("NoTestOpInst");
217251662Sdim
218239462Sdim    ClassMap[SI] = ClassS;
219239462Sdim    ClassMap[II] = ClassI;
220239462Sdim    ClassMap[WI] = ClassW;
221251662Sdim    ClassMap[SOpI] = ClassS;
222251662Sdim    ClassMap[IOpI] = ClassI;
223251662Sdim    ClassMap[WOpI] = ClassW;
224251662Sdim    ClassMap[LOpI] = ClassL;
225251662Sdim    ClassMap[NoTestOpI] = ClassNoTest;
226239462Sdim  }
227239462Sdim
228239462Sdim  // run - Emit arm_neon.h.inc
229239462Sdim  void run(raw_ostream &o);
230239462Sdim
231239462Sdim  // runHeader - Emit all the __builtin prototypes used in arm_neon.h
232239462Sdim  void runHeader(raw_ostream &o);
233239462Sdim
234239462Sdim  // runTests - Emit tests for all the Neon intrinsics.
235239462Sdim  void runTests(raw_ostream &o);
236239462Sdim
237239462Sdimprivate:
238239462Sdim  void emitIntrinsic(raw_ostream &OS, Record *R);
239239462Sdim};
240239462Sdim} // end anonymous namespace
241239462Sdim
242226586Sdim/// ParseTypes - break down a string such as "fQf" into a vector of StringRefs,
243226586Sdim/// which each StringRef representing a single type declared in the string.
244226586Sdim/// for "fQf" we would end up with 2 StringRefs, "f", and "Qf", representing
245226586Sdim/// 2xfloat and 4xfloat respectively.
246226586Sdimstatic void ParseTypes(Record *r, std::string &s,
247226586Sdim                       SmallVectorImpl<StringRef> &TV) {
248226586Sdim  const char *data = s.data();
249226586Sdim  int len = 0;
250226586Sdim
251226586Sdim  for (unsigned i = 0, e = s.size(); i != e; ++i, ++len) {
252226586Sdim    if (data[len] == 'P' || data[len] == 'Q' || data[len] == 'U')
253226586Sdim      continue;
254226586Sdim
255226586Sdim    switch (data[len]) {
256226586Sdim      case 'c':
257226586Sdim      case 's':
258226586Sdim      case 'i':
259226586Sdim      case 'l':
260226586Sdim      case 'h':
261226586Sdim      case 'f':
262226586Sdim        break;
263226586Sdim      default:
264243830Sdim        PrintFatalError(r->getLoc(),
265226586Sdim                      "Unexpected letter: " + std::string(data + len, 1));
266226586Sdim    }
267226586Sdim    TV.push_back(StringRef(data, len + 1));
268226586Sdim    data += len + 1;
269226586Sdim    len = -1;
270226586Sdim  }
271226586Sdim}
272226586Sdim
273226586Sdim/// Widen - Convert a type code into the next wider type.  char -> short,
274226586Sdim/// short -> int, etc.
275226586Sdimstatic char Widen(const char t) {
276226586Sdim  switch (t) {
277226586Sdim    case 'c':
278226586Sdim      return 's';
279226586Sdim    case 's':
280226586Sdim      return 'i';
281226586Sdim    case 'i':
282226586Sdim      return 'l';
283226586Sdim    case 'h':
284226586Sdim      return 'f';
285243830Sdim    default:
286243830Sdim      PrintFatalError("unhandled type in widen!");
287226586Sdim  }
288226586Sdim}
289226586Sdim
290226586Sdim/// Narrow - Convert a type code into the next smaller type.  short -> char,
291226586Sdim/// float -> half float, etc.
292226586Sdimstatic char Narrow(const char t) {
293226586Sdim  switch (t) {
294226586Sdim    case 's':
295226586Sdim      return 'c';
296226586Sdim    case 'i':
297226586Sdim      return 's';
298226586Sdim    case 'l':
299226586Sdim      return 'i';
300226586Sdim    case 'f':
301226586Sdim      return 'h';
302243830Sdim    default:
303243830Sdim      PrintFatalError("unhandled type in narrow!");
304226586Sdim  }
305226586Sdim}
306226586Sdim
307226586Sdim/// For a particular StringRef, return the base type code, and whether it has
308226586Sdim/// the quad-vector, polynomial, or unsigned modifiers set.
309226586Sdimstatic char ClassifyType(StringRef ty, bool &quad, bool &poly, bool &usgn) {
310226586Sdim  unsigned off = 0;
311226586Sdim
312226586Sdim  // remember quad.
313226586Sdim  if (ty[off] == 'Q') {
314226586Sdim    quad = true;
315226586Sdim    ++off;
316226586Sdim  }
317226586Sdim
318226586Sdim  // remember poly.
319226586Sdim  if (ty[off] == 'P') {
320226586Sdim    poly = true;
321226586Sdim    ++off;
322226586Sdim  }
323226586Sdim
324226586Sdim  // remember unsigned.
325226586Sdim  if (ty[off] == 'U') {
326226586Sdim    usgn = true;
327226586Sdim    ++off;
328226586Sdim  }
329226586Sdim
330226586Sdim  // base type to get the type string for.
331226586Sdim  return ty[off];
332226586Sdim}
333226586Sdim
334226586Sdim/// ModType - Transform a type code and its modifiers based on a mod code. The
335226586Sdim/// mod code definitions may be found at the top of arm_neon.td.
336226586Sdimstatic char ModType(const char mod, char type, bool &quad, bool &poly,
337226586Sdim                    bool &usgn, bool &scal, bool &cnst, bool &pntr) {
338226586Sdim  switch (mod) {
339226586Sdim    case 't':
340226586Sdim      if (poly) {
341226586Sdim        poly = false;
342226586Sdim        usgn = true;
343226586Sdim      }
344226586Sdim      break;
345226586Sdim    case 'u':
346226586Sdim      usgn = true;
347226586Sdim      poly = false;
348226586Sdim      if (type == 'f')
349226586Sdim        type = 'i';
350226586Sdim      break;
351226586Sdim    case 'x':
352226586Sdim      usgn = false;
353226586Sdim      poly = false;
354226586Sdim      if (type == 'f')
355226586Sdim        type = 'i';
356226586Sdim      break;
357226586Sdim    case 'f':
358226586Sdim      if (type == 'h')
359226586Sdim        quad = true;
360226586Sdim      type = 'f';
361226586Sdim      usgn = false;
362226586Sdim      break;
363226586Sdim    case 'g':
364226586Sdim      quad = false;
365226586Sdim      break;
366226586Sdim    case 'w':
367226586Sdim      type = Widen(type);
368226586Sdim      quad = true;
369226586Sdim      break;
370226586Sdim    case 'n':
371226586Sdim      type = Widen(type);
372226586Sdim      break;
373226586Sdim    case 'i':
374226586Sdim      type = 'i';
375226586Sdim      scal = true;
376226586Sdim      break;
377226586Sdim    case 'l':
378226586Sdim      type = 'l';
379226586Sdim      scal = true;
380226586Sdim      usgn = true;
381226586Sdim      break;
382226586Sdim    case 's':
383226586Sdim    case 'a':
384226586Sdim      scal = true;
385226586Sdim      break;
386226586Sdim    case 'k':
387226586Sdim      quad = true;
388226586Sdim      break;
389226586Sdim    case 'c':
390226586Sdim      cnst = true;
391226586Sdim    case 'p':
392226586Sdim      pntr = true;
393226586Sdim      scal = true;
394226586Sdim      break;
395226586Sdim    case 'h':
396226586Sdim      type = Narrow(type);
397226586Sdim      if (type == 'h')
398226586Sdim        quad = false;
399226586Sdim      break;
400226586Sdim    case 'e':
401226586Sdim      type = Narrow(type);
402226586Sdim      usgn = true;
403226586Sdim      break;
404226586Sdim    default:
405226586Sdim      break;
406226586Sdim  }
407226586Sdim  return type;
408226586Sdim}
409226586Sdim
410226586Sdim/// TypeString - for a modifier and type, generate the name of the typedef for
411226586Sdim/// that type.  QUc -> uint8x8_t.
412226586Sdimstatic std::string TypeString(const char mod, StringRef typestr) {
413226586Sdim  bool quad = false;
414226586Sdim  bool poly = false;
415226586Sdim  bool usgn = false;
416226586Sdim  bool scal = false;
417226586Sdim  bool cnst = false;
418226586Sdim  bool pntr = false;
419226586Sdim
420226586Sdim  if (mod == 'v')
421226586Sdim    return "void";
422226586Sdim  if (mod == 'i')
423226586Sdim    return "int";
424226586Sdim
425226586Sdim  // base type to get the type string for.
426226586Sdim  char type = ClassifyType(typestr, quad, poly, usgn);
427226586Sdim
428226586Sdim  // Based on the modifying character, change the type and width if necessary.
429226586Sdim  type = ModType(mod, type, quad, poly, usgn, scal, cnst, pntr);
430226586Sdim
431226586Sdim  SmallString<128> s;
432226586Sdim
433226586Sdim  if (usgn)
434226586Sdim    s.push_back('u');
435226586Sdim
436226586Sdim  switch (type) {
437226586Sdim    case 'c':
438226586Sdim      s += poly ? "poly8" : "int8";
439226586Sdim      if (scal)
440226586Sdim        break;
441226586Sdim      s += quad ? "x16" : "x8";
442226586Sdim      break;
443226586Sdim    case 's':
444226586Sdim      s += poly ? "poly16" : "int16";
445226586Sdim      if (scal)
446226586Sdim        break;
447226586Sdim      s += quad ? "x8" : "x4";
448226586Sdim      break;
449226586Sdim    case 'i':
450226586Sdim      s += "int32";
451226586Sdim      if (scal)
452226586Sdim        break;
453226586Sdim      s += quad ? "x4" : "x2";
454226586Sdim      break;
455226586Sdim    case 'l':
456226586Sdim      s += "int64";
457226586Sdim      if (scal)
458226586Sdim        break;
459226586Sdim      s += quad ? "x2" : "x1";
460226586Sdim      break;
461226586Sdim    case 'h':
462226586Sdim      s += "float16";
463226586Sdim      if (scal)
464226586Sdim        break;
465226586Sdim      s += quad ? "x8" : "x4";
466226586Sdim      break;
467226586Sdim    case 'f':
468226586Sdim      s += "float32";
469226586Sdim      if (scal)
470226586Sdim        break;
471226586Sdim      s += quad ? "x4" : "x2";
472226586Sdim      break;
473226586Sdim    default:
474243830Sdim      PrintFatalError("unhandled type!");
475226586Sdim  }
476226586Sdim
477226586Sdim  if (mod == '2')
478226586Sdim    s += "x2";
479226586Sdim  if (mod == '3')
480226586Sdim    s += "x3";
481226586Sdim  if (mod == '4')
482226586Sdim    s += "x4";
483226586Sdim
484226586Sdim  // Append _t, finishing the type string typedef type.
485226586Sdim  s += "_t";
486226586Sdim
487226586Sdim  if (cnst)
488226586Sdim    s += " const";
489226586Sdim
490226586Sdim  if (pntr)
491226586Sdim    s += " *";
492226586Sdim
493226586Sdim  return s.str();
494226586Sdim}
495226586Sdim
496226586Sdim/// BuiltinTypeString - for a modifier and type, generate the clang
497226586Sdim/// BuiltinsARM.def prototype code for the function.  See the top of clang's
498226586Sdim/// Builtins.def for a description of the type strings.
499226586Sdimstatic std::string BuiltinTypeString(const char mod, StringRef typestr,
500226586Sdim                                     ClassKind ck, bool ret) {
501226586Sdim  bool quad = false;
502226586Sdim  bool poly = false;
503226586Sdim  bool usgn = false;
504226586Sdim  bool scal = false;
505226586Sdim  bool cnst = false;
506226586Sdim  bool pntr = false;
507226586Sdim
508226586Sdim  if (mod == 'v')
509226586Sdim    return "v"; // void
510226586Sdim  if (mod == 'i')
511226586Sdim    return "i"; // int
512226586Sdim
513226586Sdim  // base type to get the type string for.
514226586Sdim  char type = ClassifyType(typestr, quad, poly, usgn);
515226586Sdim
516226586Sdim  // Based on the modifying character, change the type and width if necessary.
517226586Sdim  type = ModType(mod, type, quad, poly, usgn, scal, cnst, pntr);
518226586Sdim
519226586Sdim  // All pointers are void* pointers.  Change type to 'v' now.
520226586Sdim  if (pntr) {
521226586Sdim    usgn = false;
522226586Sdim    poly = false;
523226586Sdim    type = 'v';
524226586Sdim  }
525226586Sdim  // Treat half-float ('h') types as unsigned short ('s') types.
526226586Sdim  if (type == 'h') {
527226586Sdim    type = 's';
528226586Sdim    usgn = true;
529226586Sdim  }
530226586Sdim  usgn = usgn | poly | ((ck == ClassI || ck == ClassW) && scal && type != 'f');
531226586Sdim
532226586Sdim  if (scal) {
533226586Sdim    SmallString<128> s;
534226586Sdim
535226586Sdim    if (usgn)
536226586Sdim      s.push_back('U');
537226586Sdim    else if (type == 'c')
538226586Sdim      s.push_back('S'); // make chars explicitly signed
539226586Sdim
540226586Sdim    if (type == 'l') // 64-bit long
541226586Sdim      s += "LLi";
542226586Sdim    else
543226586Sdim      s.push_back(type);
544226586Sdim
545226586Sdim    if (cnst)
546226586Sdim      s.push_back('C');
547226586Sdim    if (pntr)
548226586Sdim      s.push_back('*');
549226586Sdim    return s.str();
550226586Sdim  }
551226586Sdim
552226586Sdim  // Since the return value must be one type, return a vector type of the
553226586Sdim  // appropriate width which we will bitcast.  An exception is made for
554226586Sdim  // returning structs of 2, 3, or 4 vectors which are returned in a sret-like
555226586Sdim  // fashion, storing them to a pointer arg.
556226586Sdim  if (ret) {
557226586Sdim    if (mod >= '2' && mod <= '4')
558226586Sdim      return "vv*"; // void result with void* first argument
559226586Sdim    if (mod == 'f' || (ck != ClassB && type == 'f'))
560226586Sdim      return quad ? "V4f" : "V2f";
561226586Sdim    if (ck != ClassB && type == 's')
562226586Sdim      return quad ? "V8s" : "V4s";
563226586Sdim    if (ck != ClassB && type == 'i')
564226586Sdim      return quad ? "V4i" : "V2i";
565226586Sdim    if (ck != ClassB && type == 'l')
566226586Sdim      return quad ? "V2LLi" : "V1LLi";
567226586Sdim
568226586Sdim    return quad ? "V16Sc" : "V8Sc";
569226586Sdim  }
570226586Sdim
571226586Sdim  // Non-return array types are passed as individual vectors.
572226586Sdim  if (mod == '2')
573226586Sdim    return quad ? "V16ScV16Sc" : "V8ScV8Sc";
574226586Sdim  if (mod == '3')
575226586Sdim    return quad ? "V16ScV16ScV16Sc" : "V8ScV8ScV8Sc";
576226586Sdim  if (mod == '4')
577226586Sdim    return quad ? "V16ScV16ScV16ScV16Sc" : "V8ScV8ScV8ScV8Sc";
578226586Sdim
579226586Sdim  if (mod == 'f' || (ck != ClassB && type == 'f'))
580226586Sdim    return quad ? "V4f" : "V2f";
581226586Sdim  if (ck != ClassB && type == 's')
582226586Sdim    return quad ? "V8s" : "V4s";
583226586Sdim  if (ck != ClassB && type == 'i')
584226586Sdim    return quad ? "V4i" : "V2i";
585226586Sdim  if (ck != ClassB && type == 'l')
586226586Sdim    return quad ? "V2LLi" : "V1LLi";
587226586Sdim
588226586Sdim  return quad ? "V16Sc" : "V8Sc";
589226586Sdim}
590226586Sdim
591251662Sdim/// InstructionTypeCode - Computes the ARM argument character code and
592251662Sdim/// quad status for a specific type string and ClassKind.
593251662Sdimstatic void InstructionTypeCode(const StringRef &typeStr,
594251662Sdim                                const ClassKind ck,
595251662Sdim                                bool &quad,
596251662Sdim                                std::string &typeCode) {
597226586Sdim  bool poly = false;
598226586Sdim  bool usgn = false;
599251662Sdim  char type = ClassifyType(typeStr, quad, poly, usgn);
600226586Sdim
601226586Sdim  switch (type) {
602226586Sdim  case 'c':
603226586Sdim    switch (ck) {
604251662Sdim    case ClassS: typeCode = poly ? "p8" : usgn ? "u8" : "s8"; break;
605251662Sdim    case ClassI: typeCode = "i8"; break;
606251662Sdim    case ClassW: typeCode = "8"; break;
607226586Sdim    default: break;
608226586Sdim    }
609226586Sdim    break;
610226586Sdim  case 's':
611226586Sdim    switch (ck) {
612251662Sdim    case ClassS: typeCode = poly ? "p16" : usgn ? "u16" : "s16"; break;
613251662Sdim    case ClassI: typeCode = "i16"; break;
614251662Sdim    case ClassW: typeCode = "16"; break;
615226586Sdim    default: break;
616226586Sdim    }
617226586Sdim    break;
618226586Sdim  case 'i':
619226586Sdim    switch (ck) {
620251662Sdim    case ClassS: typeCode = usgn ? "u32" : "s32"; break;
621251662Sdim    case ClassI: typeCode = "i32"; break;
622251662Sdim    case ClassW: typeCode = "32"; break;
623226586Sdim    default: break;
624226586Sdim    }
625226586Sdim    break;
626226586Sdim  case 'l':
627226586Sdim    switch (ck) {
628251662Sdim    case ClassS: typeCode = usgn ? "u64" : "s64"; break;
629251662Sdim    case ClassI: typeCode = "i64"; break;
630251662Sdim    case ClassW: typeCode = "64"; break;
631226586Sdim    default: break;
632226586Sdim    }
633226586Sdim    break;
634226586Sdim  case 'h':
635226586Sdim    switch (ck) {
636226586Sdim    case ClassS:
637251662Sdim    case ClassI: typeCode = "f16"; break;
638251662Sdim    case ClassW: typeCode = "16"; break;
639226586Sdim    default: break;
640226586Sdim    }
641226586Sdim    break;
642226586Sdim  case 'f':
643226586Sdim    switch (ck) {
644226586Sdim    case ClassS:
645251662Sdim    case ClassI: typeCode = "f32"; break;
646251662Sdim    case ClassW: typeCode = "32"; break;
647226586Sdim    default: break;
648226586Sdim    }
649226586Sdim    break;
650226586Sdim  default:
651243830Sdim    PrintFatalError("unhandled type!");
652226586Sdim  }
653251662Sdim}
654251662Sdim
655251662Sdim/// MangleName - Append a type or width suffix to a base neon function name,
656251662Sdim/// and insert a 'q' in the appropriate location if the operation works on
657251662Sdim/// 128b rather than 64b.   E.g. turn "vst2_lane" into "vst2q_lane_f32", etc.
658251662Sdimstatic std::string MangleName(const std::string &name, StringRef typestr,
659251662Sdim                              ClassKind ck) {
660251662Sdim  if (name == "vcvt_f32_f16")
661251662Sdim    return name;
662251662Sdim
663251662Sdim  bool quad = false;
664251662Sdim  std::string typeCode = "";
665251662Sdim
666251662Sdim  InstructionTypeCode(typestr, ck, quad, typeCode);
667251662Sdim
668251662Sdim  std::string s = name;
669251662Sdim
670251662Sdim  if (typeCode.size() > 0) {
671251662Sdim    s += "_" + typeCode;
672251662Sdim  }
673251662Sdim
674226586Sdim  if (ck == ClassB)
675226586Sdim    s += "_v";
676226586Sdim
677226586Sdim  // Insert a 'q' before the first '_' character so that it ends up before
678226586Sdim  // _lane or _n on vector-scalar operations.
679226586Sdim  if (quad) {
680226586Sdim    size_t pos = s.find('_');
681226586Sdim    s = s.insert(pos, "q");
682226586Sdim  }
683251662Sdim
684226586Sdim  return s;
685226586Sdim}
686226586Sdim
687251662Sdimstatic void PreprocessInstruction(const StringRef &Name,
688251662Sdim                                  const std::string &InstName,
689251662Sdim                                  std::string &Prefix,
690251662Sdim                                  bool &HasNPostfix,
691251662Sdim                                  bool &HasLanePostfix,
692251662Sdim                                  bool &HasDupPostfix,
693251662Sdim                                  bool &IsSpecialVCvt,
694251662Sdim                                  size_t &TBNumber) {
695251662Sdim  // All of our instruction name fields from arm_neon.td are of the form
696251662Sdim  //   <instructionname>_...
697251662Sdim  // Thus we grab our instruction name via computation of said Prefix.
698251662Sdim  const size_t PrefixEnd = Name.find_first_of('_');
699251662Sdim  // If InstName is passed in, we use that instead of our name Prefix.
700251662Sdim  Prefix = InstName.size() == 0? Name.slice(0, PrefixEnd).str() : InstName;
701251662Sdim
702251662Sdim  const StringRef Postfix = Name.slice(PrefixEnd, Name.size());
703251662Sdim
704251662Sdim  HasNPostfix = Postfix.count("_n");
705251662Sdim  HasLanePostfix = Postfix.count("_lane");
706251662Sdim  HasDupPostfix = Postfix.count("_dup");
707251662Sdim  IsSpecialVCvt = Postfix.size() != 0 && Name.count("vcvt");
708251662Sdim
709251662Sdim  if (InstName.compare("vtbl") == 0 ||
710251662Sdim      InstName.compare("vtbx") == 0) {
711251662Sdim    // If we have a vtblN/vtbxN instruction, use the instruction's ASCII
712251662Sdim    // encoding to get its true value.
713251662Sdim    TBNumber = Name[Name.size()-1] - 48;
714251662Sdim  }
715251662Sdim}
716251662Sdim
717251662Sdim/// GenerateRegisterCheckPatternsForLoadStores - Given a bunch of data we have
718251662Sdim/// extracted, generate a FileCheck pattern for a Load Or Store
719251662Sdimstatic void
720251662SdimGenerateRegisterCheckPatternForLoadStores(const StringRef &NameRef,
721251662Sdim                                          const std::string& OutTypeCode,
722251662Sdim                                          const bool &IsQuad,
723251662Sdim                                          const bool &HasDupPostfix,
724251662Sdim                                          const bool &HasLanePostfix,
725251662Sdim                                          const size_t Count,
726251662Sdim                                          std::string &RegisterSuffix) {
727251662Sdim  const bool IsLDSTOne = NameRef.count("vld1") || NameRef.count("vst1");
728251662Sdim  // If N == 3 || N == 4 and we are dealing with a quad instruction, Clang
729251662Sdim  // will output a series of v{ld,st}1s, so we have to handle it specially.
730251662Sdim  if ((Count == 3 || Count == 4) && IsQuad) {
731251662Sdim    RegisterSuffix += "{";
732251662Sdim    for (size_t i = 0; i < Count; i++) {
733251662Sdim      RegisterSuffix += "d{{[0-9]+}}";
734251662Sdim      if (HasDupPostfix) {
735251662Sdim        RegisterSuffix += "[]";
736251662Sdim      }
737251662Sdim      if (HasLanePostfix) {
738251662Sdim        RegisterSuffix += "[{{[0-9]+}}]";
739251662Sdim      }
740251662Sdim      if (i < Count-1) {
741251662Sdim        RegisterSuffix += ", ";
742251662Sdim      }
743251662Sdim    }
744251662Sdim    RegisterSuffix += "}";
745251662Sdim  } else {
746251662Sdim
747251662Sdim    // Handle normal loads and stores.
748251662Sdim    RegisterSuffix += "{";
749251662Sdim    for (size_t i = 0; i < Count; i++) {
750251662Sdim      RegisterSuffix += "d{{[0-9]+}}";
751251662Sdim      if (HasDupPostfix) {
752251662Sdim        RegisterSuffix += "[]";
753251662Sdim      }
754251662Sdim      if (HasLanePostfix) {
755251662Sdim        RegisterSuffix += "[{{[0-9]+}}]";
756251662Sdim      }
757251662Sdim      if (IsQuad && !HasLanePostfix) {
758251662Sdim        RegisterSuffix += ", d{{[0-9]+}}";
759251662Sdim        if (HasDupPostfix) {
760251662Sdim          RegisterSuffix += "[]";
761251662Sdim        }
762251662Sdim      }
763251662Sdim      if (i < Count-1) {
764251662Sdim        RegisterSuffix += ", ";
765251662Sdim      }
766251662Sdim    }
767251662Sdim    RegisterSuffix += "}, [r{{[0-9]+}}";
768251662Sdim
769251662Sdim    // We only include the alignment hint if we have a vld1.*64 or
770251662Sdim    // a dup/lane instruction.
771251662Sdim    if (IsLDSTOne) {
772251662Sdim      if ((HasLanePostfix || HasDupPostfix) && OutTypeCode != "8") {
773251662Sdim        RegisterSuffix += ", :" + OutTypeCode;
774251662Sdim      } else if (OutTypeCode == "64") {
775251662Sdim        RegisterSuffix += ", :64";
776251662Sdim      }
777251662Sdim    }
778251662Sdim
779251662Sdim    RegisterSuffix += "]";
780251662Sdim  }
781251662Sdim}
782251662Sdim
783251662Sdimstatic bool HasNPostfixAndScalarArgs(const StringRef &NameRef,
784251662Sdim                                     const bool &HasNPostfix) {
785251662Sdim  return (NameRef.count("vmla") ||
786251662Sdim          NameRef.count("vmlal") ||
787251662Sdim          NameRef.count("vmlsl") ||
788251662Sdim          NameRef.count("vmull") ||
789251662Sdim          NameRef.count("vqdmlal") ||
790251662Sdim          NameRef.count("vqdmlsl") ||
791251662Sdim          NameRef.count("vqdmulh") ||
792251662Sdim          NameRef.count("vqdmull") ||
793251662Sdim          NameRef.count("vqrdmulh")) && HasNPostfix;
794251662Sdim}
795251662Sdim
796251662Sdimstatic bool IsFiveOperandLaneAccumulator(const StringRef &NameRef,
797251662Sdim                                         const bool &HasLanePostfix) {
798251662Sdim  return (NameRef.count("vmla") ||
799251662Sdim          NameRef.count("vmls") ||
800251662Sdim          NameRef.count("vmlal") ||
801251662Sdim          NameRef.count("vmlsl") ||
802251662Sdim          (NameRef.count("vmul") && NameRef.size() == 3)||
803251662Sdim          NameRef.count("vqdmlal") ||
804251662Sdim          NameRef.count("vqdmlsl") ||
805251662Sdim          NameRef.count("vqdmulh") ||
806251662Sdim          NameRef.count("vqrdmulh")) && HasLanePostfix;
807251662Sdim}
808251662Sdim
809251662Sdimstatic bool IsSpecialLaneMultiply(const StringRef &NameRef,
810251662Sdim                                  const bool &HasLanePostfix,
811251662Sdim                                  const bool &IsQuad) {
812251662Sdim  const bool IsVMulOrMulh = (NameRef.count("vmul") || NameRef.count("mulh"))
813251662Sdim                               && IsQuad;
814251662Sdim  const bool IsVMull = NameRef.count("mull") && !IsQuad;
815251662Sdim  return (IsVMulOrMulh || IsVMull) && HasLanePostfix;
816251662Sdim}
817251662Sdim
818251662Sdimstatic void NormalizeProtoForRegisterPatternCreation(const std::string &Name,
819251662Sdim                                                     const std::string &Proto,
820251662Sdim                                                     const bool &HasNPostfix,
821251662Sdim                                                     const bool &IsQuad,
822251662Sdim                                                     const bool &HasLanePostfix,
823251662Sdim                                                     const bool &HasDupPostfix,
824251662Sdim                                                     std::string &NormedProto) {
825251662Sdim  // Handle generic case.
826251662Sdim  const StringRef NameRef(Name);
827251662Sdim  for (size_t i = 0, end = Proto.size(); i < end; i++) {
828251662Sdim    switch (Proto[i]) {
829251662Sdim    case 'u':
830251662Sdim    case 'f':
831251662Sdim    case 'd':
832251662Sdim    case 's':
833251662Sdim    case 'x':
834251662Sdim    case 't':
835251662Sdim    case 'n':
836251662Sdim      NormedProto += IsQuad? 'q' : 'd';
837251662Sdim      break;
838251662Sdim    case 'w':
839251662Sdim    case 'k':
840251662Sdim      NormedProto += 'q';
841251662Sdim      break;
842251662Sdim    case 'g':
843251662Sdim    case 'h':
844251662Sdim    case 'e':
845251662Sdim      NormedProto += 'd';
846251662Sdim      break;
847251662Sdim    case 'i':
848251662Sdim      NormedProto += HasLanePostfix? 'a' : 'i';
849251662Sdim      break;
850251662Sdim    case 'a':
851251662Sdim      if (HasLanePostfix) {
852251662Sdim        NormedProto += 'a';
853251662Sdim      } else if (HasNPostfixAndScalarArgs(NameRef, HasNPostfix)) {
854251662Sdim        NormedProto += IsQuad? 'q' : 'd';
855251662Sdim      } else {
856251662Sdim        NormedProto += 'i';
857251662Sdim      }
858251662Sdim      break;
859251662Sdim    }
860251662Sdim  }
861251662Sdim
862251662Sdim  // Handle Special Cases.
863251662Sdim  const bool IsNotVExt = !NameRef.count("vext");
864251662Sdim  const bool IsVPADAL = NameRef.count("vpadal");
865251662Sdim  const bool Is5OpLaneAccum = IsFiveOperandLaneAccumulator(NameRef,
866251662Sdim                                                           HasLanePostfix);
867251662Sdim  const bool IsSpecialLaneMul = IsSpecialLaneMultiply(NameRef, HasLanePostfix,
868251662Sdim                                                      IsQuad);
869251662Sdim
870251662Sdim  if (IsSpecialLaneMul) {
871251662Sdim    // If
872251662Sdim    NormedProto[2] = NormedProto[3];
873251662Sdim    NormedProto.erase(3);
874251662Sdim  } else if (NormedProto.size() == 4 &&
875251662Sdim             NormedProto[0] == NormedProto[1] &&
876251662Sdim             IsNotVExt) {
877251662Sdim    // If NormedProto.size() == 4 and the first two proto characters are the
878251662Sdim    // same, ignore the first.
879251662Sdim    NormedProto = NormedProto.substr(1, 3);
880251662Sdim  } else if (Is5OpLaneAccum) {
881251662Sdim    // If we have a 5 op lane accumulator operation, we take characters 1,2,4
882251662Sdim    std::string tmp = NormedProto.substr(1,2);
883251662Sdim    tmp += NormedProto[4];
884251662Sdim    NormedProto = tmp;
885251662Sdim  } else if (IsVPADAL) {
886251662Sdim    // If we have VPADAL, ignore the first character.
887251662Sdim    NormedProto = NormedProto.substr(0, 2);
888251662Sdim  } else if (NameRef.count("vdup") && NormedProto.size() > 2) {
889251662Sdim    // If our instruction is a dup instruction, keep only the first and
890251662Sdim    // last characters.
891251662Sdim    std::string tmp = "";
892251662Sdim    tmp += NormedProto[0];
893251662Sdim    tmp += NormedProto[NormedProto.size()-1];
894251662Sdim    NormedProto = tmp;
895251662Sdim  }
896251662Sdim}
897251662Sdim
898251662Sdim/// GenerateRegisterCheckPatterns - Given a bunch of data we have
899251662Sdim/// extracted, generate a FileCheck pattern to check that an
900251662Sdim/// instruction's arguments are correct.
901251662Sdimstatic void GenerateRegisterCheckPattern(const std::string &Name,
902251662Sdim                                         const std::string &Proto,
903251662Sdim                                         const std::string &OutTypeCode,
904251662Sdim                                         const bool &HasNPostfix,
905251662Sdim                                         const bool &IsQuad,
906251662Sdim                                         const bool &HasLanePostfix,
907251662Sdim                                         const bool &HasDupPostfix,
908251662Sdim                                         const size_t &TBNumber,
909251662Sdim                                         std::string &RegisterSuffix) {
910251662Sdim
911251662Sdim  RegisterSuffix = "";
912251662Sdim
913251662Sdim  const StringRef NameRef(Name);
914251662Sdim  const StringRef ProtoRef(Proto);
915251662Sdim
916251662Sdim  if ((NameRef.count("vdup") || NameRef.count("vmov")) && HasNPostfix) {
917251662Sdim    return;
918251662Sdim  }
919251662Sdim
920251662Sdim  const bool IsLoadStore = NameRef.count("vld") || NameRef.count("vst");
921251662Sdim  const bool IsTBXOrTBL = NameRef.count("vtbl") || NameRef.count("vtbx");
922251662Sdim
923251662Sdim  if (IsLoadStore) {
924251662Sdim    // Grab N value from  v{ld,st}N using its ascii representation.
925251662Sdim    const size_t Count = NameRef[3] - 48;
926251662Sdim
927251662Sdim    GenerateRegisterCheckPatternForLoadStores(NameRef, OutTypeCode, IsQuad,
928251662Sdim                                              HasDupPostfix, HasLanePostfix,
929251662Sdim                                              Count, RegisterSuffix);
930251662Sdim  } else if (IsTBXOrTBL) {
931251662Sdim    RegisterSuffix += "d{{[0-9]+}}, {";
932251662Sdim    for (size_t i = 0; i < TBNumber-1; i++) {
933251662Sdim      RegisterSuffix += "d{{[0-9]+}}, ";
934251662Sdim    }
935251662Sdim    RegisterSuffix += "d{{[0-9]+}}}, d{{[0-9]+}}";
936251662Sdim  } else {
937251662Sdim    // Handle a normal instruction.
938251662Sdim    if (NameRef.count("vget") || NameRef.count("vset"))
939251662Sdim      return;
940251662Sdim
941251662Sdim    // We first normalize our proto, since we only need to emit 4
942251662Sdim    // different types of checks, yet have more than 4 proto types
943251662Sdim    // that map onto those 4 patterns.
944251662Sdim    std::string NormalizedProto("");
945251662Sdim    NormalizeProtoForRegisterPatternCreation(Name, Proto, HasNPostfix, IsQuad,
946251662Sdim                                             HasLanePostfix, HasDupPostfix,
947251662Sdim                                             NormalizedProto);
948251662Sdim
949251662Sdim    for (size_t i = 0, end = NormalizedProto.size(); i < end; i++) {
950251662Sdim      const char &c = NormalizedProto[i];
951251662Sdim      switch (c) {
952251662Sdim      case 'q':
953251662Sdim        RegisterSuffix += "q{{[0-9]+}}, ";
954251662Sdim        break;
955251662Sdim
956251662Sdim      case 'd':
957251662Sdim        RegisterSuffix += "d{{[0-9]+}}, ";
958251662Sdim        break;
959251662Sdim
960251662Sdim      case 'i':
961251662Sdim        RegisterSuffix += "#{{[0-9]+}}, ";
962251662Sdim        break;
963251662Sdim
964251662Sdim      case 'a':
965251662Sdim        RegisterSuffix += "d{{[0-9]+}}[{{[0-9]}}], ";
966251662Sdim        break;
967251662Sdim      }
968251662Sdim    }
969251662Sdim
970251662Sdim    // Remove extra ", ".
971251662Sdim    RegisterSuffix = RegisterSuffix.substr(0, RegisterSuffix.size()-2);
972251662Sdim  }
973251662Sdim}
974251662Sdim
975251662Sdim/// GenerateChecksForIntrinsic - Given a specific instruction name +
976251662Sdim/// typestr + class kind, generate the proper set of FileCheck
977251662Sdim/// Patterns to check for. We could just return a string, but instead
978251662Sdim/// use a vector since it provides us with the extra flexibility of
979251662Sdim/// emitting multiple checks, which comes in handy for certain cases
980251662Sdim/// like mla where we want to check for 2 different instructions.
981251662Sdimstatic void GenerateChecksForIntrinsic(const std::string &Name,
982251662Sdim                                       const std::string &Proto,
983251662Sdim                                       StringRef &OutTypeStr,
984251662Sdim                                       StringRef &InTypeStr,
985251662Sdim                                       ClassKind Ck,
986251662Sdim                                       const std::string &InstName,
987251662Sdim                                       bool IsHiddenLOp,
988251662Sdim                                       std::vector<std::string>& Result) {
989251662Sdim
990251662Sdim  // If Ck is a ClassNoTest instruction, just return so no test is
991251662Sdim  // emitted.
992251662Sdim  if(Ck == ClassNoTest)
993251662Sdim    return;
994251662Sdim
995251662Sdim  if (Name == "vcvt_f32_f16") {
996251662Sdim    Result.push_back("vcvt.f32.f16");
997251662Sdim    return;
998251662Sdim  }
999251662Sdim
1000251662Sdim
1001251662Sdim  // Now we preprocess our instruction given the data we have to get the
1002251662Sdim  // data that we need.
1003251662Sdim  // Create a StringRef for String Manipulation of our Name.
1004251662Sdim  const StringRef NameRef(Name);
1005251662Sdim  // Instruction Prefix.
1006251662Sdim  std::string Prefix;
1007251662Sdim  // The type code for our out type string.
1008251662Sdim  std::string OutTypeCode;
1009251662Sdim  // To handle our different cases, we need to check for different postfixes.
1010251662Sdim  // Is our instruction a quad instruction.
1011251662Sdim  bool IsQuad = false;
1012251662Sdim  // Our instruction is of the form <instructionname>_n.
1013251662Sdim  bool HasNPostfix = false;
1014251662Sdim  // Our instruction is of the form <instructionname>_lane.
1015251662Sdim  bool HasLanePostfix = false;
1016251662Sdim  // Our instruction is of the form <instructionname>_dup.
1017251662Sdim  bool HasDupPostfix  = false;
1018251662Sdim  // Our instruction is a vcvt instruction which requires special handling.
1019251662Sdim  bool IsSpecialVCvt = false;
1020251662Sdim  // If we have a vtbxN or vtblN instruction, this is set to N.
1021251662Sdim  size_t TBNumber = -1;
1022251662Sdim  // Register Suffix
1023251662Sdim  std::string RegisterSuffix;
1024251662Sdim
1025251662Sdim  PreprocessInstruction(NameRef, InstName, Prefix,
1026251662Sdim                        HasNPostfix, HasLanePostfix, HasDupPostfix,
1027251662Sdim                        IsSpecialVCvt, TBNumber);
1028251662Sdim
1029251662Sdim  InstructionTypeCode(OutTypeStr, Ck, IsQuad, OutTypeCode);
1030251662Sdim  GenerateRegisterCheckPattern(Name, Proto, OutTypeCode, HasNPostfix, IsQuad,
1031251662Sdim                               HasLanePostfix, HasDupPostfix, TBNumber,
1032251662Sdim                               RegisterSuffix);
1033251662Sdim
1034251662Sdim  // In the following section, we handle a bunch of special cases. You can tell
1035251662Sdim  // a special case by the fact we are returning early.
1036251662Sdim
1037251662Sdim  // If our instruction is a logical instruction without postfix or a
1038251662Sdim  // hidden LOp just return the current Prefix.
1039251662Sdim  if (Ck == ClassL || IsHiddenLOp) {
1040251662Sdim    Result.push_back(Prefix + " " + RegisterSuffix);
1041251662Sdim    return;
1042251662Sdim  }
1043251662Sdim
1044251662Sdim  // If we have a vmov, due to the many different cases, some of which
1045251662Sdim  // vary within the different intrinsics generated for a single
1046251662Sdim  // instruction type, just output a vmov. (e.g. given an instruction
1047251662Sdim  // A, A.u32 might be vmov and A.u8 might be vmov.8).
1048251662Sdim  //
1049251662Sdim  // FIXME: Maybe something can be done about this. The two cases that we care
1050251662Sdim  // about are vmov as an LType and vmov as a WType.
1051251662Sdim  if (Prefix == "vmov") {
1052251662Sdim    Result.push_back(Prefix + " " + RegisterSuffix);
1053251662Sdim    return;
1054251662Sdim  }
1055251662Sdim
1056251662Sdim  // In the following section, we handle special cases.
1057251662Sdim
1058251662Sdim  if (OutTypeCode == "64") {
1059251662Sdim    // If we have a 64 bit vdup/vext and are handling an uint64x1_t
1060251662Sdim    // type, the intrinsic will be optimized away, so just return
1061251662Sdim    // nothing.  On the other hand if we are handling an uint64x2_t
1062251662Sdim    // (i.e. quad instruction), vdup/vmov instructions should be
1063251662Sdim    // emitted.
1064251662Sdim    if (Prefix == "vdup" || Prefix == "vext") {
1065251662Sdim      if (IsQuad) {
1066251662Sdim        Result.push_back("{{vmov|vdup}}");
1067251662Sdim      }
1068251662Sdim      return;
1069251662Sdim    }
1070251662Sdim
1071251662Sdim    // v{st,ld}{2,3,4}_{u,s}64 emit v{st,ld}1.64 instructions with
1072251662Sdim    // multiple register operands.
1073251662Sdim    bool MultiLoadPrefix = Prefix == "vld2" || Prefix == "vld3"
1074251662Sdim                            || Prefix == "vld4";
1075251662Sdim    bool MultiStorePrefix = Prefix == "vst2" || Prefix == "vst3"
1076251662Sdim                            || Prefix == "vst4";
1077251662Sdim    if (MultiLoadPrefix || MultiStorePrefix) {
1078251662Sdim      Result.push_back(NameRef.slice(0, 3).str() + "1.64");
1079251662Sdim      return;
1080251662Sdim    }
1081251662Sdim
1082251662Sdim    // v{st,ld}1_{lane,dup}_{u64,s64} use vldr/vstr/vmov/str instead of
1083251662Sdim    // emitting said instructions. So return a check for
1084251662Sdim    // vldr/vstr/vmov/str instead.
1085251662Sdim    if (HasLanePostfix || HasDupPostfix) {
1086251662Sdim      if (Prefix == "vst1") {
1087251662Sdim        Result.push_back("{{str|vstr|vmov}}");
1088251662Sdim        return;
1089251662Sdim      } else if (Prefix == "vld1") {
1090251662Sdim        Result.push_back("{{ldr|vldr|vmov}}");
1091251662Sdim        return;
1092251662Sdim      }
1093251662Sdim    }
1094251662Sdim  }
1095251662Sdim
1096251662Sdim  // vzip.32/vuzp.32 are the same instruction as vtrn.32 and are
1097251662Sdim  // sometimes disassembled as vtrn.32. We use a regex to handle both
1098251662Sdim  // cases.
1099251662Sdim  if ((Prefix == "vzip" || Prefix == "vuzp") && OutTypeCode == "32") {
1100251662Sdim    Result.push_back("{{vtrn|" + Prefix + "}}.32 " + RegisterSuffix);
1101251662Sdim    return;
1102251662Sdim  }
1103251662Sdim
1104251662Sdim  // Currently on most ARM processors, we do not use vmla/vmls for
1105251662Sdim  // quad floating point operations. Instead we output vmul + vadd. So
1106251662Sdim  // check if we have one of those instructions and just output a
1107251662Sdim  // check for vmul.
1108251662Sdim  if (OutTypeCode == "f32") {
1109251662Sdim    if (Prefix == "vmls") {
1110251662Sdim      Result.push_back("vmul." + OutTypeCode + " " + RegisterSuffix);
1111251662Sdim      Result.push_back("vsub." + OutTypeCode);
1112251662Sdim      return;
1113251662Sdim    } else if (Prefix == "vmla") {
1114251662Sdim      Result.push_back("vmul." + OutTypeCode + " " + RegisterSuffix);
1115251662Sdim      Result.push_back("vadd." + OutTypeCode);
1116251662Sdim      return;
1117251662Sdim    }
1118251662Sdim  }
1119251662Sdim
1120251662Sdim  // If we have vcvt, get the input type from the instruction name
1121251662Sdim  // (which should be of the form instname_inputtype) and append it
1122251662Sdim  // before the output type.
1123251662Sdim  if (Prefix == "vcvt") {
1124251662Sdim    const std::string inTypeCode = NameRef.substr(NameRef.find_last_of("_")+1);
1125251662Sdim    Prefix += "." + inTypeCode;
1126251662Sdim  }
1127251662Sdim
1128251662Sdim  // Append output type code to get our final mangled instruction.
1129251662Sdim  Prefix += "." + OutTypeCode;
1130251662Sdim
1131251662Sdim  Result.push_back(Prefix + " " + RegisterSuffix);
1132251662Sdim}
1133251662Sdim
1134226586Sdim/// UseMacro - Examine the prototype string to determine if the intrinsic
1135226586Sdim/// should be defined as a preprocessor macro instead of an inline function.
1136226586Sdimstatic bool UseMacro(const std::string &proto) {
1137226586Sdim  // If this builtin takes an immediate argument, we need to #define it rather
1138226586Sdim  // than use a standard declaration, so that SemaChecking can range check
1139226586Sdim  // the immediate passed by the user.
1140226586Sdim  if (proto.find('i') != std::string::npos)
1141226586Sdim    return true;
1142226586Sdim
1143226586Sdim  // Pointer arguments need to use macros to avoid hiding aligned attributes
1144226586Sdim  // from the pointer type.
1145226586Sdim  if (proto.find('p') != std::string::npos ||
1146226586Sdim      proto.find('c') != std::string::npos)
1147226586Sdim    return true;
1148226586Sdim
1149226586Sdim  return false;
1150226586Sdim}
1151226586Sdim
1152226586Sdim/// MacroArgUsedDirectly - Return true if argument i for an intrinsic that is
1153226586Sdim/// defined as a macro should be accessed directly instead of being first
1154226586Sdim/// assigned to a local temporary.
1155226586Sdimstatic bool MacroArgUsedDirectly(const std::string &proto, unsigned i) {
1156226586Sdim  // True for constant ints (i), pointers (p) and const pointers (c).
1157226586Sdim  return (proto[i] == 'i' || proto[i] == 'p' || proto[i] == 'c');
1158226586Sdim}
1159226586Sdim
1160226586Sdim// Generate the string "(argtype a, argtype b, ...)"
1161226586Sdimstatic std::string GenArgs(const std::string &proto, StringRef typestr) {
1162226586Sdim  bool define = UseMacro(proto);
1163226586Sdim  char arg = 'a';
1164226586Sdim
1165226586Sdim  std::string s;
1166226586Sdim  s += "(";
1167226586Sdim
1168226586Sdim  for (unsigned i = 1, e = proto.size(); i != e; ++i, ++arg) {
1169226586Sdim    if (define) {
1170226586Sdim      // Some macro arguments are used directly instead of being assigned
1171226586Sdim      // to local temporaries; prepend an underscore prefix to make their
1172226586Sdim      // names consistent with the local temporaries.
1173226586Sdim      if (MacroArgUsedDirectly(proto, i))
1174226586Sdim        s += "__";
1175226586Sdim    } else {
1176226586Sdim      s += TypeString(proto[i], typestr) + " __";
1177226586Sdim    }
1178226586Sdim    s.push_back(arg);
1179226586Sdim    if ((i + 1) < e)
1180226586Sdim      s += ", ";
1181226586Sdim  }
1182226586Sdim
1183226586Sdim  s += ")";
1184226586Sdim  return s;
1185226586Sdim}
1186226586Sdim
1187226586Sdim// Macro arguments are not type-checked like inline function arguments, so
1188226586Sdim// assign them to local temporaries to get the right type checking.
1189226586Sdimstatic std::string GenMacroLocals(const std::string &proto, StringRef typestr) {
1190226586Sdim  char arg = 'a';
1191226586Sdim  std::string s;
1192226586Sdim  bool generatedLocal = false;
1193226586Sdim
1194226586Sdim  for (unsigned i = 1, e = proto.size(); i != e; ++i, ++arg) {
1195226586Sdim    // Do not create a temporary for an immediate argument.
1196226586Sdim    // That would defeat the whole point of using a macro!
1197226586Sdim    if (MacroArgUsedDirectly(proto, i))
1198226586Sdim      continue;
1199226586Sdim    generatedLocal = true;
1200226586Sdim
1201226586Sdim    s += TypeString(proto[i], typestr) + " __";
1202226586Sdim    s.push_back(arg);
1203226586Sdim    s += " = (";
1204226586Sdim    s.push_back(arg);
1205226586Sdim    s += "); ";
1206226586Sdim  }
1207226586Sdim
1208226586Sdim  if (generatedLocal)
1209226586Sdim    s += "\\\n  ";
1210226586Sdim  return s;
1211226586Sdim}
1212226586Sdim
1213226586Sdim// Use the vmovl builtin to sign-extend or zero-extend a vector.
1214226586Sdimstatic std::string Extend(StringRef typestr, const std::string &a) {
1215226586Sdim  std::string s;
1216226586Sdim  s = MangleName("vmovl", typestr, ClassS);
1217226586Sdim  s += "(" + a + ")";
1218226586Sdim  return s;
1219226586Sdim}
1220226586Sdim
1221226586Sdimstatic std::string Duplicate(unsigned nElts, StringRef typestr,
1222226586Sdim                             const std::string &a) {
1223226586Sdim  std::string s;
1224226586Sdim
1225226586Sdim  s = "(" + TypeString('d', typestr) + "){ ";
1226226586Sdim  for (unsigned i = 0; i != nElts; ++i) {
1227226586Sdim    s += a;
1228226586Sdim    if ((i + 1) < nElts)
1229226586Sdim      s += ", ";
1230226586Sdim  }
1231226586Sdim  s += " }";
1232226586Sdim
1233226586Sdim  return s;
1234226586Sdim}
1235226586Sdim
1236226586Sdimstatic std::string SplatLane(unsigned nElts, const std::string &vec,
1237226586Sdim                             const std::string &lane) {
1238226586Sdim  std::string s = "__builtin_shufflevector(" + vec + ", " + vec;
1239226586Sdim  for (unsigned i = 0; i < nElts; ++i)
1240226586Sdim    s += ", " + lane;
1241226586Sdim  s += ")";
1242226586Sdim  return s;
1243226586Sdim}
1244226586Sdim
1245226586Sdimstatic unsigned GetNumElements(StringRef typestr, bool &quad) {
1246226586Sdim  quad = false;
1247226586Sdim  bool dummy = false;
1248226586Sdim  char type = ClassifyType(typestr, quad, dummy, dummy);
1249226586Sdim  unsigned nElts = 0;
1250226586Sdim  switch (type) {
1251226586Sdim  case 'c': nElts = 8; break;
1252226586Sdim  case 's': nElts = 4; break;
1253226586Sdim  case 'i': nElts = 2; break;
1254226586Sdim  case 'l': nElts = 1; break;
1255226586Sdim  case 'h': nElts = 4; break;
1256226586Sdim  case 'f': nElts = 2; break;
1257226586Sdim  default:
1258243830Sdim    PrintFatalError("unhandled type!");
1259226586Sdim  }
1260226586Sdim  if (quad) nElts <<= 1;
1261226586Sdim  return nElts;
1262226586Sdim}
1263226586Sdim
1264226586Sdim// Generate the definition for this intrinsic, e.g. "a + b" for OpAdd.
1265226586Sdimstatic std::string GenOpString(OpKind op, const std::string &proto,
1266226586Sdim                               StringRef typestr) {
1267226586Sdim  bool quad;
1268226586Sdim  unsigned nElts = GetNumElements(typestr, quad);
1269226586Sdim  bool define = UseMacro(proto);
1270226586Sdim
1271226586Sdim  std::string ts = TypeString(proto[0], typestr);
1272226586Sdim  std::string s;
1273226586Sdim  if (!define) {
1274226586Sdim    s = "return ";
1275226586Sdim  }
1276226586Sdim
1277226586Sdim  switch(op) {
1278226586Sdim  case OpAdd:
1279226586Sdim    s += "__a + __b;";
1280226586Sdim    break;
1281226586Sdim  case OpAddl:
1282226586Sdim    s += Extend(typestr, "__a") + " + " + Extend(typestr, "__b") + ";";
1283226586Sdim    break;
1284226586Sdim  case OpAddw:
1285226586Sdim    s += "__a + " + Extend(typestr, "__b") + ";";
1286226586Sdim    break;
1287226586Sdim  case OpSub:
1288226586Sdim    s += "__a - __b;";
1289226586Sdim    break;
1290226586Sdim  case OpSubl:
1291226586Sdim    s += Extend(typestr, "__a") + " - " + Extend(typestr, "__b") + ";";
1292226586Sdim    break;
1293226586Sdim  case OpSubw:
1294226586Sdim    s += "__a - " + Extend(typestr, "__b") + ";";
1295226586Sdim    break;
1296226586Sdim  case OpMulN:
1297226586Sdim    s += "__a * " + Duplicate(nElts, typestr, "__b") + ";";
1298226586Sdim    break;
1299226586Sdim  case OpMulLane:
1300226586Sdim    s += "__a * " + SplatLane(nElts, "__b", "__c") + ";";
1301226586Sdim    break;
1302226586Sdim  case OpMul:
1303226586Sdim    s += "__a * __b;";
1304226586Sdim    break;
1305226586Sdim  case OpMullLane:
1306226586Sdim    s += MangleName("vmull", typestr, ClassS) + "(__a, " +
1307226586Sdim      SplatLane(nElts, "__b", "__c") + ");";
1308226586Sdim    break;
1309226586Sdim  case OpMlaN:
1310226586Sdim    s += "__a + (__b * " + Duplicate(nElts, typestr, "__c") + ");";
1311226586Sdim    break;
1312226586Sdim  case OpMlaLane:
1313226586Sdim    s += "__a + (__b * " + SplatLane(nElts, "__c", "__d") + ");";
1314226586Sdim    break;
1315226586Sdim  case OpMla:
1316226586Sdim    s += "__a + (__b * __c);";
1317226586Sdim    break;
1318226586Sdim  case OpMlalN:
1319226586Sdim    s += "__a + " + MangleName("vmull", typestr, ClassS) + "(__b, " +
1320226586Sdim      Duplicate(nElts, typestr, "__c") + ");";
1321226586Sdim    break;
1322226586Sdim  case OpMlalLane:
1323226586Sdim    s += "__a + " + MangleName("vmull", typestr, ClassS) + "(__b, " +
1324226586Sdim      SplatLane(nElts, "__c", "__d") + ");";
1325226586Sdim    break;
1326226586Sdim  case OpMlal:
1327226586Sdim    s += "__a + " + MangleName("vmull", typestr, ClassS) + "(__b, __c);";
1328226586Sdim    break;
1329226586Sdim  case OpMlsN:
1330226586Sdim    s += "__a - (__b * " + Duplicate(nElts, typestr, "__c") + ");";
1331226586Sdim    break;
1332226586Sdim  case OpMlsLane:
1333226586Sdim    s += "__a - (__b * " + SplatLane(nElts, "__c", "__d") + ");";
1334226586Sdim    break;
1335226586Sdim  case OpMls:
1336226586Sdim    s += "__a - (__b * __c);";
1337226586Sdim    break;
1338226586Sdim  case OpMlslN:
1339226586Sdim    s += "__a - " + MangleName("vmull", typestr, ClassS) + "(__b, " +
1340226586Sdim      Duplicate(nElts, typestr, "__c") + ");";
1341226586Sdim    break;
1342226586Sdim  case OpMlslLane:
1343226586Sdim    s += "__a - " + MangleName("vmull", typestr, ClassS) + "(__b, " +
1344226586Sdim      SplatLane(nElts, "__c", "__d") + ");";
1345226586Sdim    break;
1346226586Sdim  case OpMlsl:
1347226586Sdim    s += "__a - " + MangleName("vmull", typestr, ClassS) + "(__b, __c);";
1348226586Sdim    break;
1349226586Sdim  case OpQDMullLane:
1350226586Sdim    s += MangleName("vqdmull", typestr, ClassS) + "(__a, " +
1351226586Sdim      SplatLane(nElts, "__b", "__c") + ");";
1352226586Sdim    break;
1353226586Sdim  case OpQDMlalLane:
1354226586Sdim    s += MangleName("vqdmlal", typestr, ClassS) + "(__a, __b, " +
1355226586Sdim      SplatLane(nElts, "__c", "__d") + ");";
1356226586Sdim    break;
1357226586Sdim  case OpQDMlslLane:
1358226586Sdim    s += MangleName("vqdmlsl", typestr, ClassS) + "(__a, __b, " +
1359226586Sdim      SplatLane(nElts, "__c", "__d") + ");";
1360226586Sdim    break;
1361226586Sdim  case OpQDMulhLane:
1362226586Sdim    s += MangleName("vqdmulh", typestr, ClassS) + "(__a, " +
1363226586Sdim      SplatLane(nElts, "__b", "__c") + ");";
1364226586Sdim    break;
1365226586Sdim  case OpQRDMulhLane:
1366226586Sdim    s += MangleName("vqrdmulh", typestr, ClassS) + "(__a, " +
1367226586Sdim      SplatLane(nElts, "__b", "__c") + ");";
1368226586Sdim    break;
1369226586Sdim  case OpEq:
1370226586Sdim    s += "(" + ts + ")(__a == __b);";
1371226586Sdim    break;
1372226586Sdim  case OpGe:
1373226586Sdim    s += "(" + ts + ")(__a >= __b);";
1374226586Sdim    break;
1375226586Sdim  case OpLe:
1376226586Sdim    s += "(" + ts + ")(__a <= __b);";
1377226586Sdim    break;
1378226586Sdim  case OpGt:
1379226586Sdim    s += "(" + ts + ")(__a > __b);";
1380226586Sdim    break;
1381226586Sdim  case OpLt:
1382226586Sdim    s += "(" + ts + ")(__a < __b);";
1383226586Sdim    break;
1384226586Sdim  case OpNeg:
1385226586Sdim    s += " -__a;";
1386226586Sdim    break;
1387226586Sdim  case OpNot:
1388226586Sdim    s += " ~__a;";
1389226586Sdim    break;
1390226586Sdim  case OpAnd:
1391226586Sdim    s += "__a & __b;";
1392226586Sdim    break;
1393226586Sdim  case OpOr:
1394226586Sdim    s += "__a | __b;";
1395226586Sdim    break;
1396226586Sdim  case OpXor:
1397226586Sdim    s += "__a ^ __b;";
1398226586Sdim    break;
1399226586Sdim  case OpAndNot:
1400226586Sdim    s += "__a & ~__b;";
1401226586Sdim    break;
1402226586Sdim  case OpOrNot:
1403226586Sdim    s += "__a | ~__b;";
1404226586Sdim    break;
1405226586Sdim  case OpCast:
1406226586Sdim    s += "(" + ts + ")__a;";
1407226586Sdim    break;
1408226586Sdim  case OpConcat:
1409226586Sdim    s += "(" + ts + ")__builtin_shufflevector((int64x1_t)__a";
1410226586Sdim    s += ", (int64x1_t)__b, 0, 1);";
1411226586Sdim    break;
1412226586Sdim  case OpHi:
1413226586Sdim    s += "(" + ts +
1414226586Sdim      ")__builtin_shufflevector((int64x2_t)__a, (int64x2_t)__a, 1);";
1415226586Sdim    break;
1416226586Sdim  case OpLo:
1417226586Sdim    s += "(" + ts +
1418226586Sdim      ")__builtin_shufflevector((int64x2_t)__a, (int64x2_t)__a, 0);";
1419226586Sdim    break;
1420226586Sdim  case OpDup:
1421226586Sdim    s += Duplicate(nElts, typestr, "__a") + ";";
1422226586Sdim    break;
1423226586Sdim  case OpDupLane:
1424226586Sdim    s += SplatLane(nElts, "__a", "__b") + ";";
1425226586Sdim    break;
1426226586Sdim  case OpSelect:
1427226586Sdim    // ((0 & 1) | (~0 & 2))
1428226586Sdim    s += "(" + ts + ")";
1429226586Sdim    ts = TypeString(proto[1], typestr);
1430226586Sdim    s += "((__a & (" + ts + ")__b) | ";
1431226586Sdim    s += "(~__a & (" + ts + ")__c));";
1432226586Sdim    break;
1433226586Sdim  case OpRev16:
1434226586Sdim    s += "__builtin_shufflevector(__a, __a";
1435226586Sdim    for (unsigned i = 2; i <= nElts; i += 2)
1436226586Sdim      for (unsigned j = 0; j != 2; ++j)
1437226586Sdim        s += ", " + utostr(i - j - 1);
1438226586Sdim    s += ");";
1439226586Sdim    break;
1440226586Sdim  case OpRev32: {
1441226586Sdim    unsigned WordElts = nElts >> (1 + (int)quad);
1442226586Sdim    s += "__builtin_shufflevector(__a, __a";
1443226586Sdim    for (unsigned i = WordElts; i <= nElts; i += WordElts)
1444226586Sdim      for (unsigned j = 0; j != WordElts; ++j)
1445226586Sdim        s += ", " + utostr(i - j - 1);
1446226586Sdim    s += ");";
1447226586Sdim    break;
1448226586Sdim  }
1449226586Sdim  case OpRev64: {
1450226586Sdim    unsigned DblWordElts = nElts >> (int)quad;
1451226586Sdim    s += "__builtin_shufflevector(__a, __a";
1452226586Sdim    for (unsigned i = DblWordElts; i <= nElts; i += DblWordElts)
1453226586Sdim      for (unsigned j = 0; j != DblWordElts; ++j)
1454226586Sdim        s += ", " + utostr(i - j - 1);
1455226586Sdim    s += ");";
1456226586Sdim    break;
1457226586Sdim  }
1458226586Sdim  case OpAbdl: {
1459226586Sdim    std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)";
1460226586Sdim    if (typestr[0] != 'U') {
1461226586Sdim      // vabd results are always unsigned and must be zero-extended.
1462226586Sdim      std::string utype = "U" + typestr.str();
1463226586Sdim      s += "(" + TypeString(proto[0], typestr) + ")";
1464226586Sdim      abd = "(" + TypeString('d', utype) + ")" + abd;
1465226586Sdim      s += Extend(utype, abd) + ";";
1466226586Sdim    } else {
1467226586Sdim      s += Extend(typestr, abd) + ";";
1468226586Sdim    }
1469226586Sdim    break;
1470226586Sdim  }
1471226586Sdim  case OpAba:
1472226586Sdim    s += "__a + " + MangleName("vabd", typestr, ClassS) + "(__b, __c);";
1473226586Sdim    break;
1474226586Sdim  case OpAbal: {
1475226586Sdim    s += "__a + ";
1476226586Sdim    std::string abd = MangleName("vabd", typestr, ClassS) + "(__b, __c)";
1477226586Sdim    if (typestr[0] != 'U') {
1478226586Sdim      // vabd results are always unsigned and must be zero-extended.
1479226586Sdim      std::string utype = "U" + typestr.str();
1480226586Sdim      s += "(" + TypeString(proto[0], typestr) + ")";
1481226586Sdim      abd = "(" + TypeString('d', utype) + ")" + abd;
1482226586Sdim      s += Extend(utype, abd) + ";";
1483226586Sdim    } else {
1484226586Sdim      s += Extend(typestr, abd) + ";";
1485226586Sdim    }
1486226586Sdim    break;
1487226586Sdim  }
1488226586Sdim  default:
1489243830Sdim    PrintFatalError("unknown OpKind!");
1490226586Sdim  }
1491226586Sdim  return s;
1492226586Sdim}
1493226586Sdim
1494226586Sdimstatic unsigned GetNeonEnum(const std::string &proto, StringRef typestr) {
1495226586Sdim  unsigned mod = proto[0];
1496226586Sdim
1497226586Sdim  if (mod == 'v' || mod == 'f')
1498226586Sdim    mod = proto[1];
1499226586Sdim
1500226586Sdim  bool quad = false;
1501226586Sdim  bool poly = false;
1502226586Sdim  bool usgn = false;
1503226586Sdim  bool scal = false;
1504226586Sdim  bool cnst = false;
1505226586Sdim  bool pntr = false;
1506226586Sdim
1507226586Sdim  // Base type to get the type string for.
1508226586Sdim  char type = ClassifyType(typestr, quad, poly, usgn);
1509226586Sdim
1510226586Sdim  // Based on the modifying character, change the type and width if necessary.
1511226586Sdim  type = ModType(mod, type, quad, poly, usgn, scal, cnst, pntr);
1512226586Sdim
1513234353Sdim  NeonTypeFlags::EltType ET;
1514226586Sdim  switch (type) {
1515226586Sdim    case 'c':
1516234353Sdim      ET = poly ? NeonTypeFlags::Poly8 : NeonTypeFlags::Int8;
1517226586Sdim      break;
1518226586Sdim    case 's':
1519234353Sdim      ET = poly ? NeonTypeFlags::Poly16 : NeonTypeFlags::Int16;
1520226586Sdim      break;
1521226586Sdim    case 'i':
1522234353Sdim      ET = NeonTypeFlags::Int32;
1523226586Sdim      break;
1524226586Sdim    case 'l':
1525234353Sdim      ET = NeonTypeFlags::Int64;
1526226586Sdim      break;
1527226586Sdim    case 'h':
1528234353Sdim      ET = NeonTypeFlags::Float16;
1529226586Sdim      break;
1530226586Sdim    case 'f':
1531234353Sdim      ET = NeonTypeFlags::Float32;
1532226586Sdim      break;
1533226586Sdim    default:
1534243830Sdim      PrintFatalError("unhandled type!");
1535226586Sdim  }
1536234353Sdim  NeonTypeFlags Flags(ET, usgn, quad && proto[1] != 'g');
1537234353Sdim  return Flags.getFlags();
1538226586Sdim}
1539226586Sdim
1540226586Sdim// Generate the definition for this intrinsic, e.g. __builtin_neon_cls(a)
1541226586Sdimstatic std::string GenBuiltin(const std::string &name, const std::string &proto,
1542226586Sdim                              StringRef typestr, ClassKind ck) {
1543226586Sdim  std::string s;
1544226586Sdim
1545226586Sdim  // If this builtin returns a struct 2, 3, or 4 vectors, pass it as an implicit
1546226586Sdim  // sret-like argument.
1547226586Sdim  bool sret = (proto[0] >= '2' && proto[0] <= '4');
1548226586Sdim
1549226586Sdim  bool define = UseMacro(proto);
1550226586Sdim
1551226586Sdim  // Check if the prototype has a scalar operand with the type of the vector
1552226586Sdim  // elements.  If not, bitcasting the args will take care of arg checking.
1553226586Sdim  // The actual signedness etc. will be taken care of with special enums.
1554226586Sdim  if (proto.find('s') == std::string::npos)
1555226586Sdim    ck = ClassB;
1556226586Sdim
1557226586Sdim  if (proto[0] != 'v') {
1558226586Sdim    std::string ts = TypeString(proto[0], typestr);
1559226586Sdim
1560226586Sdim    if (define) {
1561226586Sdim      if (sret)
1562226586Sdim        s += ts + " r; ";
1563226586Sdim      else
1564226586Sdim        s += "(" + ts + ")";
1565226586Sdim    } else if (sret) {
1566226586Sdim      s += ts + " r; ";
1567226586Sdim    } else {
1568226586Sdim      s += "return (" + ts + ")";
1569226586Sdim    }
1570226586Sdim  }
1571226586Sdim
1572226586Sdim  bool splat = proto.find('a') != std::string::npos;
1573226586Sdim
1574226586Sdim  s += "__builtin_neon_";
1575226586Sdim  if (splat) {
1576226586Sdim    // Call the non-splat builtin: chop off the "_n" suffix from the name.
1577226586Sdim    std::string vname(name, 0, name.size()-2);
1578226586Sdim    s += MangleName(vname, typestr, ck);
1579226586Sdim  } else {
1580226586Sdim    s += MangleName(name, typestr, ck);
1581226586Sdim  }
1582226586Sdim  s += "(";
1583226586Sdim
1584226586Sdim  // Pass the address of the return variable as the first argument to sret-like
1585226586Sdim  // builtins.
1586226586Sdim  if (sret)
1587226586Sdim    s += "&r, ";
1588226586Sdim
1589226586Sdim  char arg = 'a';
1590226586Sdim  for (unsigned i = 1, e = proto.size(); i != e; ++i, ++arg) {
1591226586Sdim    std::string args = std::string(&arg, 1);
1592226586Sdim
1593226586Sdim    // Use the local temporaries instead of the macro arguments.
1594226586Sdim    args = "__" + args;
1595226586Sdim
1596226586Sdim    bool argQuad = false;
1597226586Sdim    bool argPoly = false;
1598226586Sdim    bool argUsgn = false;
1599226586Sdim    bool argScalar = false;
1600226586Sdim    bool dummy = false;
1601226586Sdim    char argType = ClassifyType(typestr, argQuad, argPoly, argUsgn);
1602226586Sdim    argType = ModType(proto[i], argType, argQuad, argPoly, argUsgn, argScalar,
1603226586Sdim                      dummy, dummy);
1604226586Sdim
1605226586Sdim    // Handle multiple-vector values specially, emitting each subvector as an
1606226586Sdim    // argument to the __builtin.
1607226586Sdim    if (proto[i] >= '2' && proto[i] <= '4') {
1608226586Sdim      // Check if an explicit cast is needed.
1609226586Sdim      if (argType != 'c' || argPoly || argUsgn)
1610226586Sdim        args = (argQuad ? "(int8x16_t)" : "(int8x8_t)") + args;
1611226586Sdim
1612226586Sdim      for (unsigned vi = 0, ve = proto[i] - '0'; vi != ve; ++vi) {
1613226586Sdim        s += args + ".val[" + utostr(vi) + "]";
1614226586Sdim        if ((vi + 1) < ve)
1615226586Sdim          s += ", ";
1616226586Sdim      }
1617226586Sdim      if ((i + 1) < e)
1618226586Sdim        s += ", ";
1619226586Sdim
1620226586Sdim      continue;
1621226586Sdim    }
1622226586Sdim
1623226586Sdim    if (splat && (i + 1) == e)
1624226586Sdim      args = Duplicate(GetNumElements(typestr, argQuad), typestr, args);
1625226586Sdim
1626226586Sdim    // Check if an explicit cast is needed.
1627226586Sdim    if ((splat || !argScalar) &&
1628226586Sdim        ((ck == ClassB && argType != 'c') || argPoly || argUsgn)) {
1629226586Sdim      std::string argTypeStr = "c";
1630226586Sdim      if (ck != ClassB)
1631226586Sdim        argTypeStr = argType;
1632226586Sdim      if (argQuad)
1633226586Sdim        argTypeStr = "Q" + argTypeStr;
1634226586Sdim      args = "(" + TypeString('d', argTypeStr) + ")" + args;
1635226586Sdim    }
1636226586Sdim
1637226586Sdim    s += args;
1638226586Sdim    if ((i + 1) < e)
1639226586Sdim      s += ", ";
1640226586Sdim  }
1641226586Sdim
1642226586Sdim  // Extra constant integer to hold type class enum for this function, e.g. s8
1643226586Sdim  if (ck == ClassB)
1644226586Sdim    s += ", " + utostr(GetNeonEnum(proto, typestr));
1645226586Sdim
1646226586Sdim  s += ");";
1647226586Sdim
1648226586Sdim  if (proto[0] != 'v' && sret) {
1649226586Sdim    if (define)
1650226586Sdim      s += " r;";
1651226586Sdim    else
1652226586Sdim      s += " return r;";
1653226586Sdim  }
1654226586Sdim  return s;
1655226586Sdim}
1656226586Sdim
1657226586Sdimstatic std::string GenBuiltinDef(const std::string &name,
1658226586Sdim                                 const std::string &proto,
1659226586Sdim                                 StringRef typestr, ClassKind ck) {
1660226586Sdim  std::string s("BUILTIN(__builtin_neon_");
1661226586Sdim
1662226586Sdim  // If all types are the same size, bitcasting the args will take care
1663226586Sdim  // of arg checking.  The actual signedness etc. will be taken care of with
1664226586Sdim  // special enums.
1665226586Sdim  if (proto.find('s') == std::string::npos)
1666226586Sdim    ck = ClassB;
1667226586Sdim
1668226586Sdim  s += MangleName(name, typestr, ck);
1669226586Sdim  s += ", \"";
1670226586Sdim
1671226586Sdim  for (unsigned i = 0, e = proto.size(); i != e; ++i)
1672226586Sdim    s += BuiltinTypeString(proto[i], typestr, ck, i == 0);
1673226586Sdim
1674226586Sdim  // Extra constant integer to hold type class enum for this function, e.g. s8
1675226586Sdim  if (ck == ClassB)
1676226586Sdim    s += "i";
1677226586Sdim
1678226586Sdim  s += "\", \"n\")";
1679226586Sdim  return s;
1680226586Sdim}
1681226586Sdim
1682226586Sdimstatic std::string GenIntrinsic(const std::string &name,
1683226586Sdim                                const std::string &proto,
1684226586Sdim                                StringRef outTypeStr, StringRef inTypeStr,
1685226586Sdim                                OpKind kind, ClassKind classKind) {
1686226586Sdim  assert(!proto.empty() && "");
1687239462Sdim  bool define = UseMacro(proto) && kind != OpUnavailable;
1688226586Sdim  std::string s;
1689226586Sdim
1690226586Sdim  // static always inline + return type
1691226586Sdim  if (define)
1692226586Sdim    s += "#define ";
1693226586Sdim  else
1694226586Sdim    s += "__ai " + TypeString(proto[0], outTypeStr) + " ";
1695226586Sdim
1696226586Sdim  // Function name with type suffix
1697226586Sdim  std::string mangledName = MangleName(name, outTypeStr, ClassS);
1698226586Sdim  if (outTypeStr != inTypeStr) {
1699226586Sdim    // If the input type is different (e.g., for vreinterpret), append a suffix
1700226586Sdim    // for the input type.  String off a "Q" (quad) prefix so that MangleName
1701226586Sdim    // does not insert another "q" in the name.
1702226586Sdim    unsigned typeStrOff = (inTypeStr[0] == 'Q' ? 1 : 0);
1703226586Sdim    StringRef inTypeNoQuad = inTypeStr.substr(typeStrOff);
1704226586Sdim    mangledName = MangleName(mangledName, inTypeNoQuad, ClassS);
1705226586Sdim  }
1706226586Sdim  s += mangledName;
1707226586Sdim
1708226586Sdim  // Function arguments
1709226586Sdim  s += GenArgs(proto, inTypeStr);
1710226586Sdim
1711226586Sdim  // Definition.
1712226586Sdim  if (define) {
1713226586Sdim    s += " __extension__ ({ \\\n  ";
1714226586Sdim    s += GenMacroLocals(proto, inTypeStr);
1715239462Sdim  } else if (kind == OpUnavailable) {
1716239462Sdim    s += " __attribute__((unavailable));\n";
1717239462Sdim    return s;
1718239462Sdim  } else
1719239462Sdim    s += " {\n  ";
1720226586Sdim
1721226586Sdim  if (kind != OpNone)
1722226586Sdim    s += GenOpString(kind, proto, outTypeStr);
1723226586Sdim  else
1724226586Sdim    s += GenBuiltin(name, proto, outTypeStr, classKind);
1725226586Sdim  if (define)
1726226586Sdim    s += " })";
1727226586Sdim  else
1728226586Sdim    s += " }";
1729226586Sdim  s += "\n";
1730226586Sdim  return s;
1731226586Sdim}
1732226586Sdim
1733226586Sdim/// run - Read the records in arm_neon.td and output arm_neon.h.  arm_neon.h
1734226586Sdim/// is comprised of type definitions and function declarations.
1735226586Sdimvoid NeonEmitter::run(raw_ostream &OS) {
1736226586Sdim  OS <<
1737226586Sdim    "/*===---- arm_neon.h - ARM Neon intrinsics ------------------------------"
1738226586Sdim    "---===\n"
1739226586Sdim    " *\n"
1740226586Sdim    " * Permission is hereby granted, free of charge, to any person obtaining "
1741226586Sdim    "a copy\n"
1742226586Sdim    " * of this software and associated documentation files (the \"Software\"),"
1743226586Sdim    " to deal\n"
1744226586Sdim    " * in the Software without restriction, including without limitation the "
1745226586Sdim    "rights\n"
1746226586Sdim    " * to use, copy, modify, merge, publish, distribute, sublicense, "
1747226586Sdim    "and/or sell\n"
1748226586Sdim    " * copies of the Software, and to permit persons to whom the Software is\n"
1749226586Sdim    " * furnished to do so, subject to the following conditions:\n"
1750226586Sdim    " *\n"
1751226586Sdim    " * The above copyright notice and this permission notice shall be "
1752226586Sdim    "included in\n"
1753226586Sdim    " * all copies or substantial portions of the Software.\n"
1754226586Sdim    " *\n"
1755226586Sdim    " * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, "
1756226586Sdim    "EXPRESS OR\n"
1757226586Sdim    " * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF "
1758226586Sdim    "MERCHANTABILITY,\n"
1759226586Sdim    " * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT "
1760226586Sdim    "SHALL THE\n"
1761226586Sdim    " * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR "
1762226586Sdim    "OTHER\n"
1763226586Sdim    " * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, "
1764226586Sdim    "ARISING FROM,\n"
1765226586Sdim    " * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER "
1766226586Sdim    "DEALINGS IN\n"
1767226586Sdim    " * THE SOFTWARE.\n"
1768226586Sdim    " *\n"
1769226586Sdim    " *===--------------------------------------------------------------------"
1770226586Sdim    "---===\n"
1771226586Sdim    " */\n\n";
1772226586Sdim
1773226586Sdim  OS << "#ifndef __ARM_NEON_H\n";
1774226586Sdim  OS << "#define __ARM_NEON_H\n\n";
1775226586Sdim
1776226586Sdim  OS << "#ifndef __ARM_NEON__\n";
1777226586Sdim  OS << "#error \"NEON support not enabled\"\n";
1778226586Sdim  OS << "#endif\n\n";
1779226586Sdim
1780226586Sdim  OS << "#include <stdint.h>\n\n";
1781226586Sdim
1782226586Sdim  // Emit NEON-specific scalar typedefs.
1783226586Sdim  OS << "typedef float float32_t;\n";
1784226586Sdim  OS << "typedef int8_t poly8_t;\n";
1785226586Sdim  OS << "typedef int16_t poly16_t;\n";
1786226586Sdim  OS << "typedef uint16_t float16_t;\n";
1787226586Sdim
1788226586Sdim  // Emit Neon vector typedefs.
1789226586Sdim  std::string TypedefTypes("cQcsQsiQilQlUcQUcUsQUsUiQUiUlQUlhQhfQfPcQPcPsQPs");
1790226586Sdim  SmallVector<StringRef, 24> TDTypeVec;
1791226586Sdim  ParseTypes(0, TypedefTypes, TDTypeVec);
1792226586Sdim
1793226586Sdim  // Emit vector typedefs.
1794226586Sdim  for (unsigned i = 0, e = TDTypeVec.size(); i != e; ++i) {
1795226586Sdim    bool dummy, quad = false, poly = false;
1796226586Sdim    (void) ClassifyType(TDTypeVec[i], quad, poly, dummy);
1797226586Sdim    if (poly)
1798226586Sdim      OS << "typedef __attribute__((neon_polyvector_type(";
1799226586Sdim    else
1800226586Sdim      OS << "typedef __attribute__((neon_vector_type(";
1801226586Sdim
1802226586Sdim    unsigned nElts = GetNumElements(TDTypeVec[i], quad);
1803226586Sdim    OS << utostr(nElts) << "))) ";
1804226586Sdim    if (nElts < 10)
1805226586Sdim      OS << " ";
1806226586Sdim
1807226586Sdim    OS << TypeString('s', TDTypeVec[i]);
1808226586Sdim    OS << " " << TypeString('d', TDTypeVec[i]) << ";\n";
1809226586Sdim  }
1810226586Sdim  OS << "\n";
1811226586Sdim
1812226586Sdim  // Emit struct typedefs.
1813226586Sdim  for (unsigned vi = 2; vi != 5; ++vi) {
1814226586Sdim    for (unsigned i = 0, e = TDTypeVec.size(); i != e; ++i) {
1815226586Sdim      std::string ts = TypeString('d', TDTypeVec[i]);
1816226586Sdim      std::string vs = TypeString('0' + vi, TDTypeVec[i]);
1817226586Sdim      OS << "typedef struct " << vs << " {\n";
1818226586Sdim      OS << "  " << ts << " val";
1819226586Sdim      OS << "[" << utostr(vi) << "]";
1820226586Sdim      OS << ";\n} ";
1821226586Sdim      OS << vs << ";\n\n";
1822226586Sdim    }
1823226586Sdim  }
1824226586Sdim
1825251662Sdim  OS<<"#define __ai static inline __attribute__((__always_inline__, __nodebug__))\n\n";
1826226586Sdim
1827226586Sdim  std::vector<Record*> RV = Records.getAllDerivedDefinitions("Inst");
1828226586Sdim
1829226586Sdim  // Emit vmovl, vmull and vabd intrinsics first so they can be used by other
1830226586Sdim  // intrinsics.  (Some of the saturating multiply instructions are also
1831226586Sdim  // used to implement the corresponding "_lane" variants, but tablegen
1832226586Sdim  // sorts the records into alphabetical order so that the "_lane" variants
1833226586Sdim  // come after the intrinsics they use.)
1834226586Sdim  emitIntrinsic(OS, Records.getDef("VMOVL"));
1835226586Sdim  emitIntrinsic(OS, Records.getDef("VMULL"));
1836226586Sdim  emitIntrinsic(OS, Records.getDef("VABD"));
1837226586Sdim
1838226586Sdim  for (unsigned i = 0, e = RV.size(); i != e; ++i) {
1839226586Sdim    Record *R = RV[i];
1840226586Sdim    if (R->getName() != "VMOVL" &&
1841226586Sdim        R->getName() != "VMULL" &&
1842226586Sdim        R->getName() != "VABD")
1843226586Sdim      emitIntrinsic(OS, R);
1844226586Sdim  }
1845226586Sdim
1846226586Sdim  OS << "#undef __ai\n\n";
1847226586Sdim  OS << "#endif /* __ARM_NEON_H */\n";
1848226586Sdim}
1849226586Sdim
1850226586Sdim/// emitIntrinsic - Write out the arm_neon.h header file definitions for the
1851226586Sdim/// intrinsics specified by record R.
1852226586Sdimvoid NeonEmitter::emitIntrinsic(raw_ostream &OS, Record *R) {
1853226586Sdim  std::string name = R->getValueAsString("Name");
1854226586Sdim  std::string Proto = R->getValueAsString("Prototype");
1855226586Sdim  std::string Types = R->getValueAsString("Types");
1856226586Sdim
1857226586Sdim  SmallVector<StringRef, 16> TypeVec;
1858226586Sdim  ParseTypes(R, Types, TypeVec);
1859226586Sdim
1860226586Sdim  OpKind kind = OpMap[R->getValueAsDef("Operand")->getName()];
1861226586Sdim
1862226586Sdim  ClassKind classKind = ClassNone;
1863226586Sdim  if (R->getSuperClasses().size() >= 2)
1864226586Sdim    classKind = ClassMap[R->getSuperClasses()[1]];
1865226586Sdim  if (classKind == ClassNone && kind == OpNone)
1866243830Sdim    PrintFatalError(R->getLoc(), "Builtin has no class kind");
1867226586Sdim
1868226586Sdim  for (unsigned ti = 0, te = TypeVec.size(); ti != te; ++ti) {
1869226586Sdim    if (kind == OpReinterpret) {
1870226586Sdim      bool outQuad = false;
1871226586Sdim      bool dummy = false;
1872226586Sdim      (void)ClassifyType(TypeVec[ti], outQuad, dummy, dummy);
1873226586Sdim      for (unsigned srcti = 0, srcte = TypeVec.size();
1874226586Sdim           srcti != srcte; ++srcti) {
1875226586Sdim        bool inQuad = false;
1876226586Sdim        (void)ClassifyType(TypeVec[srcti], inQuad, dummy, dummy);
1877226586Sdim        if (srcti == ti || inQuad != outQuad)
1878226586Sdim          continue;
1879226586Sdim        OS << GenIntrinsic(name, Proto, TypeVec[ti], TypeVec[srcti],
1880226586Sdim                           OpCast, ClassS);
1881226586Sdim      }
1882226586Sdim    } else {
1883226586Sdim      OS << GenIntrinsic(name, Proto, TypeVec[ti], TypeVec[ti],
1884226586Sdim                         kind, classKind);
1885226586Sdim    }
1886226586Sdim  }
1887226586Sdim  OS << "\n";
1888226586Sdim}
1889226586Sdim
1890226586Sdimstatic unsigned RangeFromType(const char mod, StringRef typestr) {
1891226586Sdim  // base type to get the type string for.
1892226586Sdim  bool quad = false, dummy = false;
1893226586Sdim  char type = ClassifyType(typestr, quad, dummy, dummy);
1894226586Sdim  type = ModType(mod, type, quad, dummy, dummy, dummy, dummy, dummy);
1895226586Sdim
1896226586Sdim  switch (type) {
1897226586Sdim    case 'c':
1898226586Sdim      return (8 << (int)quad) - 1;
1899226586Sdim    case 'h':
1900226586Sdim    case 's':
1901226586Sdim      return (4 << (int)quad) - 1;
1902226586Sdim    case 'f':
1903226586Sdim    case 'i':
1904226586Sdim      return (2 << (int)quad) - 1;
1905226586Sdim    case 'l':
1906226586Sdim      return (1 << (int)quad) - 1;
1907226586Sdim    default:
1908243830Sdim      PrintFatalError("unhandled type!");
1909226586Sdim  }
1910226586Sdim}
1911226586Sdim
1912226586Sdim/// runHeader - Emit a file with sections defining:
1913226586Sdim/// 1. the NEON section of BuiltinsARM.def.
1914226586Sdim/// 2. the SemaChecking code for the type overload checking.
1915239462Sdim/// 3. the SemaChecking code for validation of intrinsic immediate arguments.
1916226586Sdimvoid NeonEmitter::runHeader(raw_ostream &OS) {
1917226586Sdim  std::vector<Record*> RV = Records.getAllDerivedDefinitions("Inst");
1918226586Sdim
1919226586Sdim  StringMap<OpKind> EmittedMap;
1920226586Sdim
1921226586Sdim  // Generate BuiltinsARM.def for NEON
1922226586Sdim  OS << "#ifdef GET_NEON_BUILTINS\n";
1923226586Sdim  for (unsigned i = 0, e = RV.size(); i != e; ++i) {
1924226586Sdim    Record *R = RV[i];
1925226586Sdim    OpKind k = OpMap[R->getValueAsDef("Operand")->getName()];
1926226586Sdim    if (k != OpNone)
1927226586Sdim      continue;
1928226586Sdim
1929226586Sdim    std::string Proto = R->getValueAsString("Prototype");
1930226586Sdim
1931226586Sdim    // Functions with 'a' (the splat code) in the type prototype should not get
1932226586Sdim    // their own builtin as they use the non-splat variant.
1933226586Sdim    if (Proto.find('a') != std::string::npos)
1934226586Sdim      continue;
1935226586Sdim
1936226586Sdim    std::string Types = R->getValueAsString("Types");
1937226586Sdim    SmallVector<StringRef, 16> TypeVec;
1938226586Sdim    ParseTypes(R, Types, TypeVec);
1939226586Sdim
1940226586Sdim    if (R->getSuperClasses().size() < 2)
1941243830Sdim      PrintFatalError(R->getLoc(), "Builtin has no class kind");
1942226586Sdim
1943226586Sdim    std::string name = R->getValueAsString("Name");
1944226586Sdim    ClassKind ck = ClassMap[R->getSuperClasses()[1]];
1945226586Sdim
1946226586Sdim    for (unsigned ti = 0, te = TypeVec.size(); ti != te; ++ti) {
1947226586Sdim      // Generate the BuiltinsARM.def declaration for this builtin, ensuring
1948226586Sdim      // that each unique BUILTIN() macro appears only once in the output
1949226586Sdim      // stream.
1950226586Sdim      std::string bd = GenBuiltinDef(name, Proto, TypeVec[ti], ck);
1951226586Sdim      if (EmittedMap.count(bd))
1952226586Sdim        continue;
1953226586Sdim
1954226586Sdim      EmittedMap[bd] = OpNone;
1955226586Sdim      OS << bd << "\n";
1956226586Sdim    }
1957226586Sdim  }
1958226586Sdim  OS << "#endif\n\n";
1959226586Sdim
1960226586Sdim  // Generate the overloaded type checking code for SemaChecking.cpp
1961226586Sdim  OS << "#ifdef GET_NEON_OVERLOAD_CHECK\n";
1962226586Sdim  for (unsigned i = 0, e = RV.size(); i != e; ++i) {
1963226586Sdim    Record *R = RV[i];
1964226586Sdim    OpKind k = OpMap[R->getValueAsDef("Operand")->getName()];
1965226586Sdim    if (k != OpNone)
1966226586Sdim      continue;
1967226586Sdim
1968226586Sdim    std::string Proto = R->getValueAsString("Prototype");
1969226586Sdim    std::string Types = R->getValueAsString("Types");
1970226586Sdim    std::string name = R->getValueAsString("Name");
1971226586Sdim
1972226586Sdim    // Functions with 'a' (the splat code) in the type prototype should not get
1973226586Sdim    // their own builtin as they use the non-splat variant.
1974226586Sdim    if (Proto.find('a') != std::string::npos)
1975226586Sdim      continue;
1976226586Sdim
1977226586Sdim    // Functions which have a scalar argument cannot be overloaded, no need to
1978226586Sdim    // check them if we are emitting the type checking code.
1979226586Sdim    if (Proto.find('s') != std::string::npos)
1980226586Sdim      continue;
1981226586Sdim
1982226586Sdim    SmallVector<StringRef, 16> TypeVec;
1983226586Sdim    ParseTypes(R, Types, TypeVec);
1984226586Sdim
1985226586Sdim    if (R->getSuperClasses().size() < 2)
1986243830Sdim      PrintFatalError(R->getLoc(), "Builtin has no class kind");
1987226586Sdim
1988226586Sdim    int si = -1, qi = -1;
1989239462Sdim    uint64_t mask = 0, qmask = 0;
1990226586Sdim    for (unsigned ti = 0, te = TypeVec.size(); ti != te; ++ti) {
1991226586Sdim      // Generate the switch case(s) for this builtin for the type validation.
1992226586Sdim      bool quad = false, poly = false, usgn = false;
1993226586Sdim      (void) ClassifyType(TypeVec[ti], quad, poly, usgn);
1994226586Sdim
1995226586Sdim      if (quad) {
1996226586Sdim        qi = ti;
1997239462Sdim        qmask |= 1ULL << GetNeonEnum(Proto, TypeVec[ti]);
1998226586Sdim      } else {
1999226586Sdim        si = ti;
2000239462Sdim        mask |= 1ULL << GetNeonEnum(Proto, TypeVec[ti]);
2001226586Sdim      }
2002226586Sdim    }
2003234353Sdim
2004234353Sdim    // Check if the builtin function has a pointer or const pointer argument.
2005234353Sdim    int PtrArgNum = -1;
2006234353Sdim    bool HasConstPtr = false;
2007234353Sdim    for (unsigned arg = 1, arge = Proto.size(); arg != arge; ++arg) {
2008234353Sdim      char ArgType = Proto[arg];
2009234353Sdim      if (ArgType == 'c') {
2010234353Sdim        HasConstPtr = true;
2011234353Sdim        PtrArgNum = arg - 1;
2012234353Sdim        break;
2013234353Sdim      }
2014234353Sdim      if (ArgType == 'p') {
2015234353Sdim        PtrArgNum = arg - 1;
2016234353Sdim        break;
2017234353Sdim      }
2018234353Sdim    }
2019234353Sdim    // For sret builtins, adjust the pointer argument index.
2020234353Sdim    if (PtrArgNum >= 0 && (Proto[0] >= '2' && Proto[0] <= '4'))
2021234353Sdim      PtrArgNum += 1;
2022234353Sdim
2023234353Sdim    // Omit type checking for the pointer arguments of vld1_lane, vld1_dup,
2024234353Sdim    // and vst1_lane intrinsics.  Using a pointer to the vector element
2025234353Sdim    // type with one of those operations causes codegen to select an aligned
2026234353Sdim    // load/store instruction.  If you want an unaligned operation,
2027234353Sdim    // the pointer argument needs to have less alignment than element type,
2028234353Sdim    // so just accept any pointer type.
2029234353Sdim    if (name == "vld1_lane" || name == "vld1_dup" || name == "vst1_lane") {
2030234353Sdim      PtrArgNum = -1;
2031234353Sdim      HasConstPtr = false;
2032234353Sdim    }
2033234353Sdim
2034234353Sdim    if (mask) {
2035226586Sdim      OS << "case ARM::BI__builtin_neon_"
2036226586Sdim         << MangleName(name, TypeVec[si], ClassB)
2037239462Sdim         << ": mask = " << "0x" << utohexstr(mask) << "ULL";
2038234353Sdim      if (PtrArgNum >= 0)
2039234353Sdim        OS << "; PtrArgNum = " << PtrArgNum;
2040234353Sdim      if (HasConstPtr)
2041234353Sdim        OS << "; HasConstPtr = true";
2042234353Sdim      OS << "; break;\n";
2043234353Sdim    }
2044234353Sdim    if (qmask) {
2045226586Sdim      OS << "case ARM::BI__builtin_neon_"
2046226586Sdim         << MangleName(name, TypeVec[qi], ClassB)
2047239462Sdim         << ": mask = " << "0x" << utohexstr(qmask) << "ULL";
2048234353Sdim      if (PtrArgNum >= 0)
2049234353Sdim        OS << "; PtrArgNum = " << PtrArgNum;
2050234353Sdim      if (HasConstPtr)
2051234353Sdim        OS << "; HasConstPtr = true";
2052234353Sdim      OS << "; break;\n";
2053234353Sdim    }
2054226586Sdim  }
2055226586Sdim  OS << "#endif\n\n";
2056226586Sdim
2057226586Sdim  // Generate the intrinsic range checking code for shift/lane immediates.
2058226586Sdim  OS << "#ifdef GET_NEON_IMMEDIATE_CHECK\n";
2059226586Sdim  for (unsigned i = 0, e = RV.size(); i != e; ++i) {
2060226586Sdim    Record *R = RV[i];
2061226586Sdim
2062226586Sdim    OpKind k = OpMap[R->getValueAsDef("Operand")->getName()];
2063226586Sdim    if (k != OpNone)
2064226586Sdim      continue;
2065226586Sdim
2066226586Sdim    std::string name = R->getValueAsString("Name");
2067226586Sdim    std::string Proto = R->getValueAsString("Prototype");
2068226586Sdim    std::string Types = R->getValueAsString("Types");
2069226586Sdim
2070226586Sdim    // Functions with 'a' (the splat code) in the type prototype should not get
2071226586Sdim    // their own builtin as they use the non-splat variant.
2072226586Sdim    if (Proto.find('a') != std::string::npos)
2073226586Sdim      continue;
2074226586Sdim
2075226586Sdim    // Functions which do not have an immediate do not need to have range
2076226586Sdim    // checking code emitted.
2077226586Sdim    size_t immPos = Proto.find('i');
2078226586Sdim    if (immPos == std::string::npos)
2079226586Sdim      continue;
2080226586Sdim
2081226586Sdim    SmallVector<StringRef, 16> TypeVec;
2082226586Sdim    ParseTypes(R, Types, TypeVec);
2083226586Sdim
2084226586Sdim    if (R->getSuperClasses().size() < 2)
2085243830Sdim      PrintFatalError(R->getLoc(), "Builtin has no class kind");
2086226586Sdim
2087226586Sdim    ClassKind ck = ClassMap[R->getSuperClasses()[1]];
2088226586Sdim
2089226586Sdim    for (unsigned ti = 0, te = TypeVec.size(); ti != te; ++ti) {
2090226586Sdim      std::string namestr, shiftstr, rangestr;
2091226586Sdim
2092226586Sdim      if (R->getValueAsBit("isVCVT_N")) {
2093226586Sdim        // VCVT between floating- and fixed-point values takes an immediate
2094226586Sdim        // in the range 1 to 32.
2095226586Sdim        ck = ClassB;
2096226586Sdim        rangestr = "l = 1; u = 31"; // upper bound = l + u
2097226586Sdim      } else if (Proto.find('s') == std::string::npos) {
2098226586Sdim        // Builtins which are overloaded by type will need to have their upper
2099226586Sdim        // bound computed at Sema time based on the type constant.
2100226586Sdim        ck = ClassB;
2101226586Sdim        if (R->getValueAsBit("isShift")) {
2102226586Sdim          shiftstr = ", true";
2103226586Sdim
2104226586Sdim          // Right shifts have an 'r' in the name, left shifts do not.
2105226586Sdim          if (name.find('r') != std::string::npos)
2106226586Sdim            rangestr = "l = 1; ";
2107226586Sdim        }
2108226586Sdim        rangestr += "u = RFT(TV" + shiftstr + ")";
2109226586Sdim      } else {
2110226586Sdim        // The immediate generally refers to a lane in the preceding argument.
2111226586Sdim        assert(immPos > 0 && "unexpected immediate operand");
2112226586Sdim        rangestr = "u = " + utostr(RangeFromType(Proto[immPos-1], TypeVec[ti]));
2113226586Sdim      }
2114226586Sdim      // Make sure cases appear only once by uniquing them in a string map.
2115226586Sdim      namestr = MangleName(name, TypeVec[ti], ck);
2116226586Sdim      if (EmittedMap.count(namestr))
2117226586Sdim        continue;
2118226586Sdim      EmittedMap[namestr] = OpNone;
2119226586Sdim
2120226586Sdim      // Calculate the index of the immediate that should be range checked.
2121226586Sdim      unsigned immidx = 0;
2122226586Sdim
2123226586Sdim      // Builtins that return a struct of multiple vectors have an extra
2124226586Sdim      // leading arg for the struct return.
2125226586Sdim      if (Proto[0] >= '2' && Proto[0] <= '4')
2126226586Sdim        ++immidx;
2127226586Sdim
2128226586Sdim      // Add one to the index for each argument until we reach the immediate
2129226586Sdim      // to be checked.  Structs of vectors are passed as multiple arguments.
2130226586Sdim      for (unsigned ii = 1, ie = Proto.size(); ii != ie; ++ii) {
2131226586Sdim        switch (Proto[ii]) {
2132226586Sdim          default:  immidx += 1; break;
2133226586Sdim          case '2': immidx += 2; break;
2134226586Sdim          case '3': immidx += 3; break;
2135226586Sdim          case '4': immidx += 4; break;
2136226586Sdim          case 'i': ie = ii + 1; break;
2137226586Sdim        }
2138226586Sdim      }
2139226586Sdim      OS << "case ARM::BI__builtin_neon_" << MangleName(name, TypeVec[ti], ck)
2140226586Sdim         << ": i = " << immidx << "; " << rangestr << "; break;\n";
2141226586Sdim    }
2142226586Sdim  }
2143226586Sdim  OS << "#endif\n\n";
2144226586Sdim}
2145226586Sdim
2146226586Sdim/// GenTest - Write out a test for the intrinsic specified by the name and
2147226586Sdim/// type strings, including the embedded patterns for FileCheck to match.
2148226586Sdimstatic std::string GenTest(const std::string &name,
2149226586Sdim                           const std::string &proto,
2150226586Sdim                           StringRef outTypeStr, StringRef inTypeStr,
2151251662Sdim                           bool isShift, bool isHiddenLOp,
2152251662Sdim                           ClassKind ck, const std::string &InstName) {
2153226586Sdim  assert(!proto.empty() && "");
2154226586Sdim  std::string s;
2155226586Sdim
2156226586Sdim  // Function name with type suffix
2157226586Sdim  std::string mangledName = MangleName(name, outTypeStr, ClassS);
2158226586Sdim  if (outTypeStr != inTypeStr) {
2159226586Sdim    // If the input type is different (e.g., for vreinterpret), append a suffix
2160226586Sdim    // for the input type.  String off a "Q" (quad) prefix so that MangleName
2161226586Sdim    // does not insert another "q" in the name.
2162226586Sdim    unsigned typeStrOff = (inTypeStr[0] == 'Q' ? 1 : 0);
2163226586Sdim    StringRef inTypeNoQuad = inTypeStr.substr(typeStrOff);
2164226586Sdim    mangledName = MangleName(mangledName, inTypeNoQuad, ClassS);
2165226586Sdim  }
2166226586Sdim
2167251662Sdim  std::vector<std::string> FileCheckPatterns;
2168251662Sdim  GenerateChecksForIntrinsic(name, proto, outTypeStr, inTypeStr, ck, InstName,
2169251662Sdim                             isHiddenLOp, FileCheckPatterns);
2170251662Sdim
2171226586Sdim  // Emit the FileCheck patterns.
2172226586Sdim  s += "// CHECK: test_" + mangledName + "\n";
2173251662Sdim  // If for any reason we do not want to emit a check, mangledInst
2174251662Sdim  // will be the empty string.
2175251662Sdim  if (FileCheckPatterns.size()) {
2176251662Sdim    for (std::vector<std::string>::const_iterator i = FileCheckPatterns.begin(),
2177251662Sdim                                                  e = FileCheckPatterns.end();
2178251662Sdim         i != e;
2179251662Sdim         ++i) {
2180251662Sdim      s += "// CHECK: " + *i + "\n";
2181251662Sdim    }
2182251662Sdim  }
2183226586Sdim
2184226586Sdim  // Emit the start of the test function.
2185226586Sdim  s += TypeString(proto[0], outTypeStr) + " test_" + mangledName + "(";
2186226586Sdim  char arg = 'a';
2187226586Sdim  std::string comma;
2188226586Sdim  for (unsigned i = 1, e = proto.size(); i != e; ++i, ++arg) {
2189226586Sdim    // Do not create arguments for values that must be immediate constants.
2190226586Sdim    if (proto[i] == 'i')
2191226586Sdim      continue;
2192226586Sdim    s += comma + TypeString(proto[i], inTypeStr) + " ";
2193226586Sdim    s.push_back(arg);
2194226586Sdim    comma = ", ";
2195226586Sdim  }
2196239462Sdim  s += ") {\n  ";
2197226586Sdim
2198226586Sdim  if (proto[0] != 'v')
2199226586Sdim    s += "return ";
2200226586Sdim  s += mangledName + "(";
2201226586Sdim  arg = 'a';
2202226586Sdim  for (unsigned i = 1, e = proto.size(); i != e; ++i, ++arg) {
2203226586Sdim    if (proto[i] == 'i') {
2204226586Sdim      // For immediate operands, test the maximum value.
2205226586Sdim      if (isShift)
2206226586Sdim        s += "1"; // FIXME
2207226586Sdim      else
2208226586Sdim        // The immediate generally refers to a lane in the preceding argument.
2209226586Sdim        s += utostr(RangeFromType(proto[i-1], inTypeStr));
2210226586Sdim    } else {
2211226586Sdim      s.push_back(arg);
2212226586Sdim    }
2213226586Sdim    if ((i + 1) < e)
2214226586Sdim      s += ", ";
2215226586Sdim  }
2216226586Sdim  s += ");\n}\n\n";
2217226586Sdim  return s;
2218226586Sdim}
2219226586Sdim
2220226586Sdim/// runTests - Write out a complete set of tests for all of the Neon
2221226586Sdim/// intrinsics.
2222226586Sdimvoid NeonEmitter::runTests(raw_ostream &OS) {
2223226586Sdim  OS <<
2224251662Sdim    "// RUN: %clang_cc1 -triple thumbv7s-apple-darwin -target-abi apcs-gnu\\\n"
2225251662Sdim    "// RUN:  -target-cpu swift -ffreestanding -Os -S -o - %s\\\n"
2226251662Sdim    "// RUN:  | FileCheck %s\n"
2227226586Sdim    "\n"
2228226586Sdim    "#include <arm_neon.h>\n"
2229226586Sdim    "\n";
2230226586Sdim
2231226586Sdim  std::vector<Record*> RV = Records.getAllDerivedDefinitions("Inst");
2232226586Sdim  for (unsigned i = 0, e = RV.size(); i != e; ++i) {
2233226586Sdim    Record *R = RV[i];
2234226586Sdim    std::string name = R->getValueAsString("Name");
2235226586Sdim    std::string Proto = R->getValueAsString("Prototype");
2236226586Sdim    std::string Types = R->getValueAsString("Types");
2237226586Sdim    bool isShift = R->getValueAsBit("isShift");
2238251662Sdim    std::string InstName = R->getValueAsString("InstName");
2239251662Sdim    bool isHiddenLOp = R->getValueAsBit("isHiddenLInst");
2240226586Sdim
2241226586Sdim    SmallVector<StringRef, 16> TypeVec;
2242226586Sdim    ParseTypes(R, Types, TypeVec);
2243226586Sdim
2244251662Sdim    ClassKind ck = ClassMap[R->getSuperClasses()[1]];
2245226586Sdim    OpKind kind = OpMap[R->getValueAsDef("Operand")->getName()];
2246239462Sdim    if (kind == OpUnavailable)
2247239462Sdim      continue;
2248226586Sdim    for (unsigned ti = 0, te = TypeVec.size(); ti != te; ++ti) {
2249226586Sdim      if (kind == OpReinterpret) {
2250226586Sdim        bool outQuad = false;
2251226586Sdim        bool dummy = false;
2252226586Sdim        (void)ClassifyType(TypeVec[ti], outQuad, dummy, dummy);
2253226586Sdim        for (unsigned srcti = 0, srcte = TypeVec.size();
2254226586Sdim             srcti != srcte; ++srcti) {
2255226586Sdim          bool inQuad = false;
2256226586Sdim          (void)ClassifyType(TypeVec[srcti], inQuad, dummy, dummy);
2257226586Sdim          if (srcti == ti || inQuad != outQuad)
2258226586Sdim            continue;
2259251662Sdim          OS << GenTest(name, Proto, TypeVec[ti], TypeVec[srcti],
2260251662Sdim                        isShift, isHiddenLOp, ck, InstName);
2261226586Sdim        }
2262226586Sdim      } else {
2263251662Sdim        OS << GenTest(name, Proto, TypeVec[ti], TypeVec[ti],
2264251662Sdim                      isShift, isHiddenLOp, ck, InstName);
2265226586Sdim      }
2266226586Sdim    }
2267226586Sdim    OS << "\n";
2268226586Sdim  }
2269226586Sdim}
2270226586Sdim
2271239462Sdimnamespace clang {
2272239462Sdimvoid EmitNeon(RecordKeeper &Records, raw_ostream &OS) {
2273239462Sdim  NeonEmitter(Records).run(OS);
2274239462Sdim}
2275239462Sdimvoid EmitNeonSema(RecordKeeper &Records, raw_ostream &OS) {
2276239462Sdim  NeonEmitter(Records).runHeader(OS);
2277239462Sdim}
2278239462Sdimvoid EmitNeonTest(RecordKeeper &Records, raw_ostream &OS) {
2279239462Sdim  NeonEmitter(Records).runTests(OS);
2280239462Sdim}
2281239462Sdim} // End namespace clang
2282