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
26245431Sdim#include "llvm/ADT/DenseMap.h"
27226586Sdim#include "llvm/ADT/SmallString.h"
28226586Sdim#include "llvm/ADT/SmallVector.h"
29226586Sdim#include "llvm/ADT/StringExtras.h"
30245431Sdim#include "llvm/ADT/StringMap.h"
31235633Sdim#include "llvm/Support/ErrorHandling.h"
32245431Sdim#include "llvm/TableGen/Error.h"
33245431Sdim#include "llvm/TableGen/Record.h"
34245431Sdim#include "llvm/TableGen/TableGenBackend.h"
35226586Sdim#include <string>
36226586Sdimusing namespace llvm;
37226586Sdim
38245431Sdimenum OpKind {
39245431Sdim  OpNone,
40245431Sdim  OpUnavailable,
41245431Sdim  OpAdd,
42245431Sdim  OpAddl,
43263509Sdim  OpAddlHi,
44245431Sdim  OpAddw,
45263509Sdim  OpAddwHi,
46245431Sdim  OpSub,
47245431Sdim  OpSubl,
48263509Sdim  OpSublHi,
49245431Sdim  OpSubw,
50263509Sdim  OpSubwHi,
51245431Sdim  OpMul,
52245431Sdim  OpMla,
53245431Sdim  OpMlal,
54263509Sdim  OpMullHi,
55263509Sdim  OpMullHiN,
56263509Sdim  OpMlalHi,
57263509Sdim  OpMlalHiN,
58245431Sdim  OpMls,
59245431Sdim  OpMlsl,
60263509Sdim  OpMlslHi,
61263509Sdim  OpMlslHiN,
62245431Sdim  OpMulN,
63245431Sdim  OpMlaN,
64245431Sdim  OpMlsN,
65263509Sdim  OpFMlaN,
66263509Sdim  OpFMlsN,
67245431Sdim  OpMlalN,
68245431Sdim  OpMlslN,
69245431Sdim  OpMulLane,
70263509Sdim  OpMulXLane,
71245431Sdim  OpMullLane,
72263509Sdim  OpMullHiLane,
73245431Sdim  OpMlaLane,
74245431Sdim  OpMlsLane,
75245431Sdim  OpMlalLane,
76263509Sdim  OpMlalHiLane,
77245431Sdim  OpMlslLane,
78263509Sdim  OpMlslHiLane,
79245431Sdim  OpQDMullLane,
80263509Sdim  OpQDMullHiLane,
81245431Sdim  OpQDMlalLane,
82263509Sdim  OpQDMlalHiLane,
83245431Sdim  OpQDMlslLane,
84263509Sdim  OpQDMlslHiLane,
85245431Sdim  OpQDMulhLane,
86245431Sdim  OpQRDMulhLane,
87263509Sdim  OpFMSLane,
88263509Sdim  OpFMSLaneQ,
89263509Sdim  OpTrn1,
90263509Sdim  OpZip1,
91263509Sdim  OpUzp1,
92263509Sdim  OpTrn2,
93263509Sdim  OpZip2,
94263509Sdim  OpUzp2,
95245431Sdim  OpEq,
96245431Sdim  OpGe,
97245431Sdim  OpLe,
98245431Sdim  OpGt,
99245431Sdim  OpLt,
100245431Sdim  OpNeg,
101245431Sdim  OpNot,
102245431Sdim  OpAnd,
103245431Sdim  OpOr,
104245431Sdim  OpXor,
105245431Sdim  OpAndNot,
106245431Sdim  OpOrNot,
107245431Sdim  OpCast,
108245431Sdim  OpConcat,
109245431Sdim  OpDup,
110245431Sdim  OpDupLane,
111245431Sdim  OpHi,
112245431Sdim  OpLo,
113245431Sdim  OpSelect,
114245431Sdim  OpRev16,
115245431Sdim  OpRev32,
116245431Sdim  OpRev64,
117263509Sdim  OpXtnHi,
118263509Sdim  OpSqxtunHi,
119263509Sdim  OpQxtnHi,
120263509Sdim  OpFcvtnHi,
121263509Sdim  OpFcvtlHi,
122263509Sdim  OpFcvtxnHi,
123245431Sdim  OpReinterpret,
124263509Sdim  OpAddhnHi,
125263509Sdim  OpRAddhnHi,
126263509Sdim  OpSubhnHi,
127263509Sdim  OpRSubhnHi,
128245431Sdim  OpAbdl,
129263509Sdim  OpAbdlHi,
130245431Sdim  OpAba,
131263509Sdim  OpAbal,
132263509Sdim  OpAbalHi,
133263509Sdim  OpQDMullHi,
134263509Sdim  OpQDMullHiN,
135263509Sdim  OpQDMlalHi,
136263509Sdim  OpQDMlalHiN,
137263509Sdim  OpQDMlslHi,
138263509Sdim  OpQDMlslHiN,
139263509Sdim  OpDiv,
140263509Sdim  OpLongHi,
141263509Sdim  OpNarrowHi,
142263509Sdim  OpMovlHi,
143263509Sdim  OpCopyLane,
144263509Sdim  OpCopyQLane,
145263509Sdim  OpCopyLaneQ,
146263509Sdim  OpScalarMulLane,
147263509Sdim  OpScalarMulLaneQ,
148263509Sdim  OpScalarMulXLane,
149263509Sdim  OpScalarMulXLaneQ,
150263509Sdim  OpScalarVMulXLane,
151263509Sdim  OpScalarVMulXLaneQ,
152263509Sdim  OpScalarQDMullLane,
153263509Sdim  OpScalarQDMullLaneQ,
154263509Sdim  OpScalarQDMulHiLane,
155263509Sdim  OpScalarQDMulHiLaneQ,
156263509Sdim  OpScalarQRDMulHiLane,
157263509Sdim  OpScalarQRDMulHiLaneQ,
158263509Sdim  OpScalarGetLane,
159263509Sdim  OpScalarSetLane
160245431Sdim};
161245431Sdim
162245431Sdimenum ClassKind {
163245431Sdim  ClassNone,
164245431Sdim  ClassI,           // generic integer instruction, e.g., "i8" suffix
165245431Sdim  ClassS,           // signed/unsigned/poly, e.g., "s8", "u8" or "p8" suffix
166245431Sdim  ClassW,           // width-specific instruction, e.g., "8" suffix
167252723Sdim  ClassB,           // bitcast arguments with enum argument to specify type
168252723Sdim  ClassL,           // Logical instructions which are op instructions
169252723Sdim                    // but we need to not emit any suffix for in our
170252723Sdim                    // tests.
171252723Sdim  ClassNoTest       // Instructions which we do not test since they are
172252723Sdim                    // not TRUE instructions.
173245431Sdim};
174245431Sdim
175245431Sdim/// NeonTypeFlags - Flags to identify the types for overloaded Neon
176245431Sdim/// builtins.  These must be kept in sync with the flags in
177245431Sdim/// include/clang/Basic/TargetBuiltins.h.
178245431Sdimnamespace {
179245431Sdimclass NeonTypeFlags {
180245431Sdim  enum {
181245431Sdim    EltTypeMask = 0xf,
182245431Sdim    UnsignedFlag = 0x10,
183245431Sdim    QuadFlag = 0x20
184245431Sdim  };
185245431Sdim  uint32_t Flags;
186245431Sdim
187245431Sdimpublic:
188245431Sdim  enum EltType {
189245431Sdim    Int8,
190245431Sdim    Int16,
191245431Sdim    Int32,
192245431Sdim    Int64,
193245431Sdim    Poly8,
194245431Sdim    Poly16,
195263509Sdim    Poly64,
196245431Sdim    Float16,
197263509Sdim    Float32,
198263509Sdim    Float64
199245431Sdim  };
200245431Sdim
201245431Sdim  NeonTypeFlags(unsigned F) : Flags(F) {}
202245431Sdim  NeonTypeFlags(EltType ET, bool IsUnsigned, bool IsQuad) : Flags(ET) {
203245431Sdim    if (IsUnsigned)
204245431Sdim      Flags |= UnsignedFlag;
205245431Sdim    if (IsQuad)
206245431Sdim      Flags |= QuadFlag;
207245431Sdim  }
208245431Sdim
209245431Sdim  uint32_t getFlags() const { return Flags; }
210245431Sdim};
211245431Sdim} // end anonymous namespace
212245431Sdim
213245431Sdimnamespace {
214245431Sdimclass NeonEmitter {
215245431Sdim  RecordKeeper &Records;
216245431Sdim  StringMap<OpKind> OpMap;
217245431Sdim  DenseMap<Record*, ClassKind> ClassMap;
218245431Sdim
219245431Sdimpublic:
220245431Sdim  NeonEmitter(RecordKeeper &R) : Records(R) {
221245431Sdim    OpMap["OP_NONE"]  = OpNone;
222245431Sdim    OpMap["OP_UNAVAILABLE"] = OpUnavailable;
223245431Sdim    OpMap["OP_ADD"]   = OpAdd;
224245431Sdim    OpMap["OP_ADDL"]  = OpAddl;
225263509Sdim    OpMap["OP_ADDLHi"] = OpAddlHi;
226245431Sdim    OpMap["OP_ADDW"]  = OpAddw;
227263509Sdim    OpMap["OP_ADDWHi"] = OpAddwHi;
228245431Sdim    OpMap["OP_SUB"]   = OpSub;
229245431Sdim    OpMap["OP_SUBL"]  = OpSubl;
230263509Sdim    OpMap["OP_SUBLHi"] = OpSublHi;
231245431Sdim    OpMap["OP_SUBW"]  = OpSubw;
232263509Sdim    OpMap["OP_SUBWHi"] = OpSubwHi;
233245431Sdim    OpMap["OP_MUL"]   = OpMul;
234245431Sdim    OpMap["OP_MLA"]   = OpMla;
235245431Sdim    OpMap["OP_MLAL"]  = OpMlal;
236263509Sdim    OpMap["OP_MULLHi"]  = OpMullHi;
237263509Sdim    OpMap["OP_MULLHi_N"]  = OpMullHiN;
238263509Sdim    OpMap["OP_MLALHi"]  = OpMlalHi;
239263509Sdim    OpMap["OP_MLALHi_N"]  = OpMlalHiN;
240245431Sdim    OpMap["OP_MLS"]   = OpMls;
241245431Sdim    OpMap["OP_MLSL"]  = OpMlsl;
242263509Sdim    OpMap["OP_MLSLHi"] = OpMlslHi;
243263509Sdim    OpMap["OP_MLSLHi_N"] = OpMlslHiN;
244245431Sdim    OpMap["OP_MUL_N"] = OpMulN;
245245431Sdim    OpMap["OP_MLA_N"] = OpMlaN;
246245431Sdim    OpMap["OP_MLS_N"] = OpMlsN;
247263509Sdim    OpMap["OP_FMLA_N"] = OpFMlaN;
248263509Sdim    OpMap["OP_FMLS_N"] = OpFMlsN;
249245431Sdim    OpMap["OP_MLAL_N"] = OpMlalN;
250245431Sdim    OpMap["OP_MLSL_N"] = OpMlslN;
251245431Sdim    OpMap["OP_MUL_LN"]= OpMulLane;
252263509Sdim    OpMap["OP_MULX_LN"]= OpMulXLane;
253245431Sdim    OpMap["OP_MULL_LN"] = OpMullLane;
254263509Sdim    OpMap["OP_MULLHi_LN"] = OpMullHiLane;
255245431Sdim    OpMap["OP_MLA_LN"]= OpMlaLane;
256245431Sdim    OpMap["OP_MLS_LN"]= OpMlsLane;
257245431Sdim    OpMap["OP_MLAL_LN"] = OpMlalLane;
258263509Sdim    OpMap["OP_MLALHi_LN"] = OpMlalHiLane;
259245431Sdim    OpMap["OP_MLSL_LN"] = OpMlslLane;
260263509Sdim    OpMap["OP_MLSLHi_LN"] = OpMlslHiLane;
261245431Sdim    OpMap["OP_QDMULL_LN"] = OpQDMullLane;
262263509Sdim    OpMap["OP_QDMULLHi_LN"] = OpQDMullHiLane;
263245431Sdim    OpMap["OP_QDMLAL_LN"] = OpQDMlalLane;
264263509Sdim    OpMap["OP_QDMLALHi_LN"] = OpQDMlalHiLane;
265245431Sdim    OpMap["OP_QDMLSL_LN"] = OpQDMlslLane;
266263509Sdim    OpMap["OP_QDMLSLHi_LN"] = OpQDMlslHiLane;
267245431Sdim    OpMap["OP_QDMULH_LN"] = OpQDMulhLane;
268245431Sdim    OpMap["OP_QRDMULH_LN"] = OpQRDMulhLane;
269263509Sdim    OpMap["OP_FMS_LN"] = OpFMSLane;
270263509Sdim    OpMap["OP_FMS_LNQ"] = OpFMSLaneQ;
271263509Sdim    OpMap["OP_TRN1"]  = OpTrn1;
272263509Sdim    OpMap["OP_ZIP1"]  = OpZip1;
273263509Sdim    OpMap["OP_UZP1"]  = OpUzp1;
274263509Sdim    OpMap["OP_TRN2"]  = OpTrn2;
275263509Sdim    OpMap["OP_ZIP2"]  = OpZip2;
276263509Sdim    OpMap["OP_UZP2"]  = OpUzp2;
277245431Sdim    OpMap["OP_EQ"]    = OpEq;
278245431Sdim    OpMap["OP_GE"]    = OpGe;
279245431Sdim    OpMap["OP_LE"]    = OpLe;
280245431Sdim    OpMap["OP_GT"]    = OpGt;
281245431Sdim    OpMap["OP_LT"]    = OpLt;
282245431Sdim    OpMap["OP_NEG"]   = OpNeg;
283245431Sdim    OpMap["OP_NOT"]   = OpNot;
284245431Sdim    OpMap["OP_AND"]   = OpAnd;
285245431Sdim    OpMap["OP_OR"]    = OpOr;
286245431Sdim    OpMap["OP_XOR"]   = OpXor;
287245431Sdim    OpMap["OP_ANDN"]  = OpAndNot;
288245431Sdim    OpMap["OP_ORN"]   = OpOrNot;
289245431Sdim    OpMap["OP_CAST"]  = OpCast;
290245431Sdim    OpMap["OP_CONC"]  = OpConcat;
291245431Sdim    OpMap["OP_HI"]    = OpHi;
292245431Sdim    OpMap["OP_LO"]    = OpLo;
293245431Sdim    OpMap["OP_DUP"]   = OpDup;
294245431Sdim    OpMap["OP_DUP_LN"] = OpDupLane;
295245431Sdim    OpMap["OP_SEL"]   = OpSelect;
296245431Sdim    OpMap["OP_REV16"] = OpRev16;
297245431Sdim    OpMap["OP_REV32"] = OpRev32;
298245431Sdim    OpMap["OP_REV64"] = OpRev64;
299263509Sdim    OpMap["OP_XTN"] = OpXtnHi;
300263509Sdim    OpMap["OP_SQXTUN"] = OpSqxtunHi;
301263509Sdim    OpMap["OP_QXTN"] = OpQxtnHi;
302263509Sdim    OpMap["OP_VCVT_NA_HI"] = OpFcvtnHi;
303263509Sdim    OpMap["OP_VCVT_EX_HI"] = OpFcvtlHi;
304263509Sdim    OpMap["OP_VCVTX_HI"] = OpFcvtxnHi;
305245431Sdim    OpMap["OP_REINT"] = OpReinterpret;
306263509Sdim    OpMap["OP_ADDHNHi"] = OpAddhnHi;
307263509Sdim    OpMap["OP_RADDHNHi"] = OpRAddhnHi;
308263509Sdim    OpMap["OP_SUBHNHi"] = OpSubhnHi;
309263509Sdim    OpMap["OP_RSUBHNHi"] = OpRSubhnHi;
310245431Sdim    OpMap["OP_ABDL"]  = OpAbdl;
311263509Sdim    OpMap["OP_ABDLHi"] = OpAbdlHi;
312245431Sdim    OpMap["OP_ABA"]   = OpAba;
313245431Sdim    OpMap["OP_ABAL"]  = OpAbal;
314263509Sdim    OpMap["OP_ABALHi"] = OpAbalHi;
315263509Sdim    OpMap["OP_QDMULLHi"] = OpQDMullHi;
316263509Sdim    OpMap["OP_QDMULLHi_N"] = OpQDMullHiN;
317263509Sdim    OpMap["OP_QDMLALHi"] = OpQDMlalHi;
318263509Sdim    OpMap["OP_QDMLALHi_N"] = OpQDMlalHiN;
319263509Sdim    OpMap["OP_QDMLSLHi"] = OpQDMlslHi;
320263509Sdim    OpMap["OP_QDMLSLHi_N"] = OpQDMlslHiN;
321263509Sdim    OpMap["OP_DIV"] = OpDiv;
322263509Sdim    OpMap["OP_LONG_HI"] = OpLongHi;
323263509Sdim    OpMap["OP_NARROW_HI"] = OpNarrowHi;
324263509Sdim    OpMap["OP_MOVL_HI"] = OpMovlHi;
325263509Sdim    OpMap["OP_COPY_LN"] = OpCopyLane;
326263509Sdim    OpMap["OP_COPYQ_LN"] = OpCopyQLane;
327263509Sdim    OpMap["OP_COPY_LNQ"] = OpCopyLaneQ;
328263509Sdim    OpMap["OP_SCALAR_MUL_LN"]= OpScalarMulLane;
329263509Sdim    OpMap["OP_SCALAR_MUL_LNQ"]= OpScalarMulLaneQ;
330263509Sdim    OpMap["OP_SCALAR_MULX_LN"]= OpScalarMulXLane;
331263509Sdim    OpMap["OP_SCALAR_MULX_LNQ"]= OpScalarMulXLaneQ;
332263509Sdim    OpMap["OP_SCALAR_VMULX_LN"]= OpScalarVMulXLane;
333263509Sdim    OpMap["OP_SCALAR_VMULX_LNQ"]= OpScalarVMulXLaneQ;
334263509Sdim    OpMap["OP_SCALAR_QDMULL_LN"] = OpScalarQDMullLane;
335263509Sdim    OpMap["OP_SCALAR_QDMULL_LNQ"] = OpScalarQDMullLaneQ;
336263509Sdim    OpMap["OP_SCALAR_QDMULH_LN"] = OpScalarQDMulHiLane;
337263509Sdim    OpMap["OP_SCALAR_QDMULH_LNQ"] = OpScalarQDMulHiLaneQ;
338263509Sdim    OpMap["OP_SCALAR_QRDMULH_LN"] = OpScalarQRDMulHiLane;
339263509Sdim    OpMap["OP_SCALAR_QRDMULH_LNQ"] = OpScalarQRDMulHiLaneQ;
340263509Sdim    OpMap["OP_SCALAR_GET_LN"] = OpScalarGetLane;
341263509Sdim    OpMap["OP_SCALAR_SET_LN"] = OpScalarSetLane;
342245431Sdim
343245431Sdim    Record *SI = R.getClass("SInst");
344245431Sdim    Record *II = R.getClass("IInst");
345245431Sdim    Record *WI = R.getClass("WInst");
346252723Sdim    Record *SOpI = R.getClass("SOpInst");
347252723Sdim    Record *IOpI = R.getClass("IOpInst");
348252723Sdim    Record *WOpI = R.getClass("WOpInst");
349252723Sdim    Record *LOpI = R.getClass("LOpInst");
350252723Sdim    Record *NoTestOpI = R.getClass("NoTestOpInst");
351252723Sdim
352245431Sdim    ClassMap[SI] = ClassS;
353245431Sdim    ClassMap[II] = ClassI;
354245431Sdim    ClassMap[WI] = ClassW;
355252723Sdim    ClassMap[SOpI] = ClassS;
356252723Sdim    ClassMap[IOpI] = ClassI;
357252723Sdim    ClassMap[WOpI] = ClassW;
358252723Sdim    ClassMap[LOpI] = ClassL;
359252723Sdim    ClassMap[NoTestOpI] = ClassNoTest;
360245431Sdim  }
361245431Sdim
362245431Sdim  // run - Emit arm_neon.h.inc
363245431Sdim  void run(raw_ostream &o);
364245431Sdim
365245431Sdim  // runHeader - Emit all the __builtin prototypes used in arm_neon.h
366245431Sdim  void runHeader(raw_ostream &o);
367245431Sdim
368245431Sdim  // runTests - Emit tests for all the Neon intrinsics.
369245431Sdim  void runTests(raw_ostream &o);
370245431Sdim
371245431Sdimprivate:
372263509Sdim  void emitIntrinsic(raw_ostream &OS, Record *R,
373263509Sdim                     StringMap<ClassKind> &EmittedMap);
374263509Sdim  void genBuiltinsDef(raw_ostream &OS, StringMap<ClassKind> &A64IntrinsicMap,
375263509Sdim                      bool isA64GenBuiltinDef);
376263509Sdim  void genOverloadTypeCheckCode(raw_ostream &OS,
377263509Sdim                                StringMap<ClassKind> &A64IntrinsicMap,
378263509Sdim                                bool isA64TypeCheck);
379263509Sdim  void genIntrinsicRangeCheckCode(raw_ostream &OS,
380263509Sdim                                  StringMap<ClassKind> &A64IntrinsicMap,
381263509Sdim                                  bool isA64RangeCheck);
382263509Sdim  void genTargetTest(raw_ostream &OS, StringMap<OpKind> &EmittedMap,
383263509Sdim                     bool isA64TestGen);
384245431Sdim};
385245431Sdim} // end anonymous namespace
386245431Sdim
387226586Sdim/// ParseTypes - break down a string such as "fQf" into a vector of StringRefs,
388226586Sdim/// which each StringRef representing a single type declared in the string.
389226586Sdim/// for "fQf" we would end up with 2 StringRefs, "f", and "Qf", representing
390226586Sdim/// 2xfloat and 4xfloat respectively.
391226586Sdimstatic void ParseTypes(Record *r, std::string &s,
392226586Sdim                       SmallVectorImpl<StringRef> &TV) {
393226586Sdim  const char *data = s.data();
394226586Sdim  int len = 0;
395226586Sdim
396226586Sdim  for (unsigned i = 0, e = s.size(); i != e; ++i, ++len) {
397263509Sdim    if (data[len] == 'P' || data[len] == 'Q' || data[len] == 'U'
398263509Sdim                         || data[len] == 'H' || data[len] == 'S')
399226586Sdim      continue;
400226586Sdim
401226586Sdim    switch (data[len]) {
402226586Sdim      case 'c':
403226586Sdim      case 's':
404226586Sdim      case 'i':
405226586Sdim      case 'l':
406226586Sdim      case 'h':
407226586Sdim      case 'f':
408263509Sdim      case 'd':
409226586Sdim        break;
410226586Sdim      default:
411245431Sdim        PrintFatalError(r->getLoc(),
412226586Sdim                      "Unexpected letter: " + std::string(data + len, 1));
413226586Sdim    }
414226586Sdim    TV.push_back(StringRef(data, len + 1));
415226586Sdim    data += len + 1;
416226586Sdim    len = -1;
417226586Sdim  }
418226586Sdim}
419226586Sdim
420226586Sdim/// Widen - Convert a type code into the next wider type.  char -> short,
421226586Sdim/// short -> int, etc.
422226586Sdimstatic char Widen(const char t) {
423226586Sdim  switch (t) {
424226586Sdim    case 'c':
425226586Sdim      return 's';
426226586Sdim    case 's':
427226586Sdim      return 'i';
428226586Sdim    case 'i':
429226586Sdim      return 'l';
430226586Sdim    case 'h':
431226586Sdim      return 'f';
432263509Sdim    case 'f':
433263509Sdim      return 'd';
434245431Sdim    default:
435245431Sdim      PrintFatalError("unhandled type in widen!");
436226586Sdim  }
437226586Sdim}
438226586Sdim
439226586Sdim/// Narrow - Convert a type code into the next smaller type.  short -> char,
440226586Sdim/// float -> half float, etc.
441226586Sdimstatic char Narrow(const char t) {
442226586Sdim  switch (t) {
443226586Sdim    case 's':
444226586Sdim      return 'c';
445226586Sdim    case 'i':
446226586Sdim      return 's';
447226586Sdim    case 'l':
448226586Sdim      return 'i';
449226586Sdim    case 'f':
450226586Sdim      return 'h';
451263509Sdim    case 'd':
452263509Sdim      return 'f';
453245431Sdim    default:
454245431Sdim      PrintFatalError("unhandled type in narrow!");
455226586Sdim  }
456226586Sdim}
457226586Sdim
458263509Sdimstatic std::string GetNarrowTypestr(StringRef ty)
459263509Sdim{
460263509Sdim  std::string s;
461263509Sdim  for (size_t i = 0, end = ty.size(); i < end; i++) {
462263509Sdim    switch (ty[i]) {
463263509Sdim      case 's':
464263509Sdim        s += 'c';
465263509Sdim        break;
466263509Sdim      case 'i':
467263509Sdim        s += 's';
468263509Sdim        break;
469263509Sdim      case 'l':
470263509Sdim        s += 'i';
471263509Sdim        break;
472263509Sdim      default:
473263509Sdim        s += ty[i];
474263509Sdim        break;
475263509Sdim    }
476263509Sdim  }
477263509Sdim
478263509Sdim  return s;
479263509Sdim}
480263509Sdim
481226586Sdim/// For a particular StringRef, return the base type code, and whether it has
482226586Sdim/// the quad-vector, polynomial, or unsigned modifiers set.
483226586Sdimstatic char ClassifyType(StringRef ty, bool &quad, bool &poly, bool &usgn) {
484226586Sdim  unsigned off = 0;
485263509Sdim  // ignore scalar.
486263509Sdim  if (ty[off] == 'S') {
487263509Sdim    ++off;
488263509Sdim  }
489226586Sdim  // remember quad.
490263509Sdim  if (ty[off] == 'Q' || ty[off] == 'H') {
491226586Sdim    quad = true;
492226586Sdim    ++off;
493226586Sdim  }
494226586Sdim
495226586Sdim  // remember poly.
496226586Sdim  if (ty[off] == 'P') {
497226586Sdim    poly = true;
498226586Sdim    ++off;
499226586Sdim  }
500226586Sdim
501226586Sdim  // remember unsigned.
502226586Sdim  if (ty[off] == 'U') {
503226586Sdim    usgn = true;
504226586Sdim    ++off;
505226586Sdim  }
506226586Sdim
507226586Sdim  // base type to get the type string for.
508226586Sdim  return ty[off];
509226586Sdim}
510226586Sdim
511226586Sdim/// ModType - Transform a type code and its modifiers based on a mod code. The
512226586Sdim/// mod code definitions may be found at the top of arm_neon.td.
513226586Sdimstatic char ModType(const char mod, char type, bool &quad, bool &poly,
514226586Sdim                    bool &usgn, bool &scal, bool &cnst, bool &pntr) {
515226586Sdim  switch (mod) {
516226586Sdim    case 't':
517226586Sdim      if (poly) {
518226586Sdim        poly = false;
519226586Sdim        usgn = true;
520226586Sdim      }
521226586Sdim      break;
522263509Sdim    case 'b':
523263509Sdim      scal = true;
524226586Sdim    case 'u':
525226586Sdim      usgn = true;
526226586Sdim      poly = false;
527226586Sdim      if (type == 'f')
528226586Sdim        type = 'i';
529263509Sdim      if (type == 'd')
530263509Sdim        type = 'l';
531226586Sdim      break;
532263509Sdim    case '$':
533263509Sdim      scal = true;
534226586Sdim    case 'x':
535226586Sdim      usgn = false;
536226586Sdim      poly = false;
537226586Sdim      if (type == 'f')
538226586Sdim        type = 'i';
539263509Sdim      if (type == 'd')
540263509Sdim        type = 'l';
541226586Sdim      break;
542263509Sdim    case 'o':
543263509Sdim      scal = true;
544263509Sdim      type = 'd';
545263509Sdim      usgn = false;
546263509Sdim      break;
547263509Sdim    case 'y':
548263509Sdim      scal = true;
549226586Sdim    case 'f':
550226586Sdim      if (type == 'h')
551226586Sdim        quad = true;
552226586Sdim      type = 'f';
553226586Sdim      usgn = false;
554226586Sdim      break;
555263509Sdim    case 'F':
556263509Sdim      type = 'd';
557263509Sdim      usgn = false;
558263509Sdim      break;
559226586Sdim    case 'g':
560226586Sdim      quad = false;
561226586Sdim      break;
562263509Sdim    case 'B':
563263509Sdim    case 'C':
564263509Sdim    case 'D':
565263509Sdim    case 'j':
566263509Sdim      quad = true;
567263509Sdim      break;
568226586Sdim    case 'w':
569226586Sdim      type = Widen(type);
570226586Sdim      quad = true;
571226586Sdim      break;
572226586Sdim    case 'n':
573226586Sdim      type = Widen(type);
574226586Sdim      break;
575226586Sdim    case 'i':
576226586Sdim      type = 'i';
577226586Sdim      scal = true;
578226586Sdim      break;
579226586Sdim    case 'l':
580226586Sdim      type = 'l';
581226586Sdim      scal = true;
582226586Sdim      usgn = true;
583226586Sdim      break;
584263509Sdim    case 'z':
585263509Sdim      type = Narrow(type);
586263509Sdim      scal = true;
587263509Sdim      break;
588263509Sdim    case 'r':
589263509Sdim      type = Widen(type);
590263509Sdim      scal = true;
591263509Sdim      break;
592226586Sdim    case 's':
593226586Sdim    case 'a':
594226586Sdim      scal = true;
595226586Sdim      break;
596226586Sdim    case 'k':
597226586Sdim      quad = true;
598226586Sdim      break;
599226586Sdim    case 'c':
600226586Sdim      cnst = true;
601226586Sdim    case 'p':
602226586Sdim      pntr = true;
603226586Sdim      scal = true;
604226586Sdim      break;
605226586Sdim    case 'h':
606226586Sdim      type = Narrow(type);
607226586Sdim      if (type == 'h')
608226586Sdim        quad = false;
609226586Sdim      break;
610263509Sdim    case 'q':
611263509Sdim      type = Narrow(type);
612263509Sdim      quad = true;
613263509Sdim      break;
614226586Sdim    case 'e':
615226586Sdim      type = Narrow(type);
616226586Sdim      usgn = true;
617226586Sdim      break;
618263509Sdim    case 'm':
619263509Sdim      type = Narrow(type);
620263509Sdim      quad = false;
621263509Sdim      break;
622226586Sdim    default:
623226586Sdim      break;
624226586Sdim  }
625226586Sdim  return type;
626226586Sdim}
627226586Sdim
628263509Sdimstatic bool IsMultiVecProto(const char p) {
629263509Sdim  return ((p >= '2' && p <= '4') || (p >= 'B' && p <= 'D'));
630263509Sdim}
631263509Sdim
632226586Sdim/// TypeString - for a modifier and type, generate the name of the typedef for
633226586Sdim/// that type.  QUc -> uint8x8_t.
634226586Sdimstatic std::string TypeString(const char mod, StringRef typestr) {
635226586Sdim  bool quad = false;
636226586Sdim  bool poly = false;
637226586Sdim  bool usgn = false;
638226586Sdim  bool scal = false;
639226586Sdim  bool cnst = false;
640226586Sdim  bool pntr = false;
641226586Sdim
642226586Sdim  if (mod == 'v')
643226586Sdim    return "void";
644226586Sdim  if (mod == 'i')
645226586Sdim    return "int";
646226586Sdim
647226586Sdim  // base type to get the type string for.
648226586Sdim  char type = ClassifyType(typestr, quad, poly, usgn);
649226586Sdim
650226586Sdim  // Based on the modifying character, change the type and width if necessary.
651226586Sdim  type = ModType(mod, type, quad, poly, usgn, scal, cnst, pntr);
652226586Sdim
653226586Sdim  SmallString<128> s;
654226586Sdim
655226586Sdim  if (usgn)
656226586Sdim    s.push_back('u');
657226586Sdim
658226586Sdim  switch (type) {
659226586Sdim    case 'c':
660226586Sdim      s += poly ? "poly8" : "int8";
661226586Sdim      if (scal)
662226586Sdim        break;
663226586Sdim      s += quad ? "x16" : "x8";
664226586Sdim      break;
665226586Sdim    case 's':
666226586Sdim      s += poly ? "poly16" : "int16";
667226586Sdim      if (scal)
668226586Sdim        break;
669226586Sdim      s += quad ? "x8" : "x4";
670226586Sdim      break;
671226586Sdim    case 'i':
672226586Sdim      s += "int32";
673226586Sdim      if (scal)
674226586Sdim        break;
675226586Sdim      s += quad ? "x4" : "x2";
676226586Sdim      break;
677226586Sdim    case 'l':
678263509Sdim      s += (poly && !usgn)? "poly64" : "int64";
679226586Sdim      if (scal)
680226586Sdim        break;
681226586Sdim      s += quad ? "x2" : "x1";
682226586Sdim      break;
683226586Sdim    case 'h':
684226586Sdim      s += "float16";
685226586Sdim      if (scal)
686226586Sdim        break;
687226586Sdim      s += quad ? "x8" : "x4";
688226586Sdim      break;
689226586Sdim    case 'f':
690226586Sdim      s += "float32";
691226586Sdim      if (scal)
692226586Sdim        break;
693226586Sdim      s += quad ? "x4" : "x2";
694226586Sdim      break;
695263509Sdim    case 'd':
696263509Sdim      s += "float64";
697263509Sdim      if (scal)
698263509Sdim        break;
699263509Sdim      s += quad ? "x2" : "x1";
700263509Sdim      break;
701263509Sdim
702226586Sdim    default:
703245431Sdim      PrintFatalError("unhandled type!");
704226586Sdim  }
705226586Sdim
706263509Sdim  if (mod == '2' || mod == 'B')
707226586Sdim    s += "x2";
708263509Sdim  if (mod == '3' || mod == 'C')
709226586Sdim    s += "x3";
710263509Sdim  if (mod == '4' || mod == 'D')
711226586Sdim    s += "x4";
712226586Sdim
713226586Sdim  // Append _t, finishing the type string typedef type.
714226586Sdim  s += "_t";
715226586Sdim
716226586Sdim  if (cnst)
717226586Sdim    s += " const";
718226586Sdim
719226586Sdim  if (pntr)
720226586Sdim    s += " *";
721226586Sdim
722226586Sdim  return s.str();
723226586Sdim}
724226586Sdim
725226586Sdim/// BuiltinTypeString - for a modifier and type, generate the clang
726226586Sdim/// BuiltinsARM.def prototype code for the function.  See the top of clang's
727226586Sdim/// Builtins.def for a description of the type strings.
728226586Sdimstatic std::string BuiltinTypeString(const char mod, StringRef typestr,
729226586Sdim                                     ClassKind ck, bool ret) {
730226586Sdim  bool quad = false;
731226586Sdim  bool poly = false;
732226586Sdim  bool usgn = false;
733226586Sdim  bool scal = false;
734226586Sdim  bool cnst = false;
735226586Sdim  bool pntr = false;
736226586Sdim
737226586Sdim  if (mod == 'v')
738226586Sdim    return "v"; // void
739226586Sdim  if (mod == 'i')
740226586Sdim    return "i"; // int
741226586Sdim
742226586Sdim  // base type to get the type string for.
743226586Sdim  char type = ClassifyType(typestr, quad, poly, usgn);
744226586Sdim
745226586Sdim  // Based on the modifying character, change the type and width if necessary.
746226586Sdim  type = ModType(mod, type, quad, poly, usgn, scal, cnst, pntr);
747226586Sdim
748226586Sdim  // All pointers are void* pointers.  Change type to 'v' now.
749226586Sdim  if (pntr) {
750226586Sdim    usgn = false;
751226586Sdim    poly = false;
752226586Sdim    type = 'v';
753226586Sdim  }
754226586Sdim  // Treat half-float ('h') types as unsigned short ('s') types.
755226586Sdim  if (type == 'h') {
756226586Sdim    type = 's';
757226586Sdim    usgn = true;
758226586Sdim  }
759263509Sdim  usgn = usgn | poly | ((ck == ClassI || ck == ClassW) &&
760263509Sdim                         scal && type != 'f' && type != 'd');
761226586Sdim
762226586Sdim  if (scal) {
763226586Sdim    SmallString<128> s;
764226586Sdim
765226586Sdim    if (usgn)
766226586Sdim      s.push_back('U');
767226586Sdim    else if (type == 'c')
768226586Sdim      s.push_back('S'); // make chars explicitly signed
769226586Sdim
770226586Sdim    if (type == 'l') // 64-bit long
771226586Sdim      s += "LLi";
772226586Sdim    else
773226586Sdim      s.push_back(type);
774226586Sdim
775226586Sdim    if (cnst)
776226586Sdim      s.push_back('C');
777226586Sdim    if (pntr)
778226586Sdim      s.push_back('*');
779226586Sdim    return s.str();
780226586Sdim  }
781226586Sdim
782226586Sdim  // Since the return value must be one type, return a vector type of the
783226586Sdim  // appropriate width which we will bitcast.  An exception is made for
784226586Sdim  // returning structs of 2, 3, or 4 vectors which are returned in a sret-like
785226586Sdim  // fashion, storing them to a pointer arg.
786226586Sdim  if (ret) {
787263509Sdim    if (IsMultiVecProto(mod))
788226586Sdim      return "vv*"; // void result with void* first argument
789226586Sdim    if (mod == 'f' || (ck != ClassB && type == 'f'))
790226586Sdim      return quad ? "V4f" : "V2f";
791263509Sdim    if (mod == 'F' || (ck != ClassB && type == 'd'))
792263509Sdim      return quad ? "V2d" : "V1d";
793226586Sdim    if (ck != ClassB && type == 's')
794226586Sdim      return quad ? "V8s" : "V4s";
795226586Sdim    if (ck != ClassB && type == 'i')
796226586Sdim      return quad ? "V4i" : "V2i";
797226586Sdim    if (ck != ClassB && type == 'l')
798226586Sdim      return quad ? "V2LLi" : "V1LLi";
799226586Sdim
800226586Sdim    return quad ? "V16Sc" : "V8Sc";
801226586Sdim  }
802226586Sdim
803226586Sdim  // Non-return array types are passed as individual vectors.
804263509Sdim  if (mod == '2' || mod == 'B')
805226586Sdim    return quad ? "V16ScV16Sc" : "V8ScV8Sc";
806263509Sdim  if (mod == '3' || mod == 'C')
807226586Sdim    return quad ? "V16ScV16ScV16Sc" : "V8ScV8ScV8Sc";
808263509Sdim  if (mod == '4' || mod == 'D')
809226586Sdim    return quad ? "V16ScV16ScV16ScV16Sc" : "V8ScV8ScV8ScV8Sc";
810226586Sdim
811226586Sdim  if (mod == 'f' || (ck != ClassB && type == 'f'))
812226586Sdim    return quad ? "V4f" : "V2f";
813263509Sdim  if (mod == 'F' || (ck != ClassB && type == 'd'))
814263509Sdim    return quad ? "V2d" : "V1d";
815226586Sdim  if (ck != ClassB && type == 's')
816226586Sdim    return quad ? "V8s" : "V4s";
817226586Sdim  if (ck != ClassB && type == 'i')
818226586Sdim    return quad ? "V4i" : "V2i";
819226586Sdim  if (ck != ClassB && type == 'l')
820226586Sdim    return quad ? "V2LLi" : "V1LLi";
821226586Sdim
822226586Sdim  return quad ? "V16Sc" : "V8Sc";
823226586Sdim}
824226586Sdim
825252723Sdim/// InstructionTypeCode - Computes the ARM argument character code and
826252723Sdim/// quad status for a specific type string and ClassKind.
827252723Sdimstatic void InstructionTypeCode(const StringRef &typeStr,
828252723Sdim                                const ClassKind ck,
829252723Sdim                                bool &quad,
830252723Sdim                                std::string &typeCode) {
831226586Sdim  bool poly = false;
832226586Sdim  bool usgn = false;
833252723Sdim  char type = ClassifyType(typeStr, quad, poly, usgn);
834226586Sdim
835226586Sdim  switch (type) {
836226586Sdim  case 'c':
837226586Sdim    switch (ck) {
838252723Sdim    case ClassS: typeCode = poly ? "p8" : usgn ? "u8" : "s8"; break;
839252723Sdim    case ClassI: typeCode = "i8"; break;
840252723Sdim    case ClassW: typeCode = "8"; break;
841226586Sdim    default: break;
842226586Sdim    }
843226586Sdim    break;
844226586Sdim  case 's':
845226586Sdim    switch (ck) {
846252723Sdim    case ClassS: typeCode = poly ? "p16" : usgn ? "u16" : "s16"; break;
847252723Sdim    case ClassI: typeCode = "i16"; break;
848252723Sdim    case ClassW: typeCode = "16"; break;
849226586Sdim    default: break;
850226586Sdim    }
851226586Sdim    break;
852226586Sdim  case 'i':
853226586Sdim    switch (ck) {
854252723Sdim    case ClassS: typeCode = usgn ? "u32" : "s32"; break;
855252723Sdim    case ClassI: typeCode = "i32"; break;
856252723Sdim    case ClassW: typeCode = "32"; break;
857226586Sdim    default: break;
858226586Sdim    }
859226586Sdim    break;
860226586Sdim  case 'l':
861226586Sdim    switch (ck) {
862263509Sdim    case ClassS: typeCode = poly ? "p64" : usgn ? "u64" : "s64"; break;
863252723Sdim    case ClassI: typeCode = "i64"; break;
864252723Sdim    case ClassW: typeCode = "64"; break;
865226586Sdim    default: break;
866226586Sdim    }
867226586Sdim    break;
868226586Sdim  case 'h':
869226586Sdim    switch (ck) {
870226586Sdim    case ClassS:
871252723Sdim    case ClassI: typeCode = "f16"; break;
872252723Sdim    case ClassW: typeCode = "16"; break;
873226586Sdim    default: break;
874226586Sdim    }
875226586Sdim    break;
876226586Sdim  case 'f':
877226586Sdim    switch (ck) {
878226586Sdim    case ClassS:
879252723Sdim    case ClassI: typeCode = "f32"; break;
880252723Sdim    case ClassW: typeCode = "32"; break;
881226586Sdim    default: break;
882226586Sdim    }
883226586Sdim    break;
884263509Sdim  case 'd':
885263509Sdim    switch (ck) {
886263509Sdim    case ClassS:
887263509Sdim    case ClassI:
888263509Sdim      typeCode += "f64";
889263509Sdim      break;
890263509Sdim    case ClassW:
891263509Sdim      PrintFatalError("unhandled type!");
892263509Sdim    default:
893263509Sdim      break;
894263509Sdim    }
895263509Sdim    break;
896226586Sdim  default:
897245431Sdim    PrintFatalError("unhandled type!");
898226586Sdim  }
899252723Sdim}
900252723Sdim
901263509Sdimstatic char Insert_BHSD_Suffix(StringRef typestr){
902263509Sdim  unsigned off = 0;
903263509Sdim  if(typestr[off++] == 'S'){
904263509Sdim    while(typestr[off] == 'Q' || typestr[off] == 'H'||
905263509Sdim          typestr[off] == 'P' || typestr[off] == 'U')
906263509Sdim      ++off;
907263509Sdim    switch (typestr[off]){
908263509Sdim    default  : break;
909263509Sdim    case 'c' : return 'b';
910263509Sdim    case 's' : return 'h';
911263509Sdim    case 'i' :
912263509Sdim    case 'f' : return 's';
913263509Sdim    case 'l' :
914263509Sdim    case 'd' : return 'd';
915263509Sdim    }
916263509Sdim  }
917263509Sdim  return 0;
918263509Sdim}
919263509Sdim
920263509Sdimstatic bool endsWith_xN(std::string const &name) {
921263509Sdim  if (name.length() > 3) {
922263509Sdim    if (name.compare(name.length() - 3, 3, "_x2") == 0 ||
923263509Sdim        name.compare(name.length() - 3, 3, "_x3") == 0 ||
924263509Sdim        name.compare(name.length() - 3, 3, "_x4") == 0)
925263509Sdim      return true;
926263509Sdim  }
927263509Sdim  return false;
928263509Sdim}
929263509Sdim
930252723Sdim/// MangleName - Append a type or width suffix to a base neon function name,
931263509Sdim/// and insert a 'q' in the appropriate location if type string starts with 'Q'.
932263509Sdim/// E.g. turn "vst2_lane" into "vst2q_lane_f32", etc.
933263509Sdim/// Insert proper 'b' 'h' 's' 'd' if prefix 'S' is used.
934252723Sdimstatic std::string MangleName(const std::string &name, StringRef typestr,
935252723Sdim                              ClassKind ck) {
936263509Sdim  if (name == "vcvt_f32_f16" || name == "vcvt_f32_f64" ||
937263509Sdim      name == "vcvt_f64_f32")
938252723Sdim    return name;
939252723Sdim
940252723Sdim  bool quad = false;
941252723Sdim  std::string typeCode = "";
942252723Sdim
943252723Sdim  InstructionTypeCode(typestr, ck, quad, typeCode);
944252723Sdim
945252723Sdim  std::string s = name;
946252723Sdim
947252723Sdim  if (typeCode.size() > 0) {
948263509Sdim    // If the name is end with _xN (N = 2,3,4), insert the typeCode before _xN.
949263509Sdim    if (endsWith_xN(s))
950263509Sdim      s.insert(s.length() - 3, "_" + typeCode);
951263509Sdim    else
952263509Sdim      s += "_" + typeCode;
953252723Sdim  }
954252723Sdim
955226586Sdim  if (ck == ClassB)
956226586Sdim    s += "_v";
957226586Sdim
958226586Sdim  // Insert a 'q' before the first '_' character so that it ends up before
959226586Sdim  // _lane or _n on vector-scalar operations.
960263509Sdim  if (typestr.find("Q") != StringRef::npos) {
961263509Sdim      size_t pos = s.find('_');
962263509Sdim      s = s.insert(pos, "q");
963263509Sdim  }
964263509Sdim  char ins = Insert_BHSD_Suffix(typestr);
965263509Sdim  if(ins){
966226586Sdim    size_t pos = s.find('_');
967263509Sdim    s = s.insert(pos, &ins, 1);
968226586Sdim  }
969252723Sdim
970226586Sdim  return s;
971226586Sdim}
972226586Sdim
973252723Sdimstatic void PreprocessInstruction(const StringRef &Name,
974252723Sdim                                  const std::string &InstName,
975252723Sdim                                  std::string &Prefix,
976252723Sdim                                  bool &HasNPostfix,
977252723Sdim                                  bool &HasLanePostfix,
978252723Sdim                                  bool &HasDupPostfix,
979252723Sdim                                  bool &IsSpecialVCvt,
980252723Sdim                                  size_t &TBNumber) {
981252723Sdim  // All of our instruction name fields from arm_neon.td are of the form
982252723Sdim  //   <instructionname>_...
983252723Sdim  // Thus we grab our instruction name via computation of said Prefix.
984252723Sdim  const size_t PrefixEnd = Name.find_first_of('_');
985252723Sdim  // If InstName is passed in, we use that instead of our name Prefix.
986252723Sdim  Prefix = InstName.size() == 0? Name.slice(0, PrefixEnd).str() : InstName;
987252723Sdim
988252723Sdim  const StringRef Postfix = Name.slice(PrefixEnd, Name.size());
989252723Sdim
990252723Sdim  HasNPostfix = Postfix.count("_n");
991252723Sdim  HasLanePostfix = Postfix.count("_lane");
992252723Sdim  HasDupPostfix = Postfix.count("_dup");
993252723Sdim  IsSpecialVCvt = Postfix.size() != 0 && Name.count("vcvt");
994252723Sdim
995252723Sdim  if (InstName.compare("vtbl") == 0 ||
996252723Sdim      InstName.compare("vtbx") == 0) {
997252723Sdim    // If we have a vtblN/vtbxN instruction, use the instruction's ASCII
998252723Sdim    // encoding to get its true value.
999252723Sdim    TBNumber = Name[Name.size()-1] - 48;
1000252723Sdim  }
1001252723Sdim}
1002252723Sdim
1003252723Sdim/// GenerateRegisterCheckPatternsForLoadStores - Given a bunch of data we have
1004252723Sdim/// extracted, generate a FileCheck pattern for a Load Or Store
1005252723Sdimstatic void
1006252723SdimGenerateRegisterCheckPatternForLoadStores(const StringRef &NameRef,
1007252723Sdim                                          const std::string& OutTypeCode,
1008252723Sdim                                          const bool &IsQuad,
1009252723Sdim                                          const bool &HasDupPostfix,
1010252723Sdim                                          const bool &HasLanePostfix,
1011252723Sdim                                          const size_t Count,
1012252723Sdim                                          std::string &RegisterSuffix) {
1013252723Sdim  const bool IsLDSTOne = NameRef.count("vld1") || NameRef.count("vst1");
1014252723Sdim  // If N == 3 || N == 4 and we are dealing with a quad instruction, Clang
1015252723Sdim  // will output a series of v{ld,st}1s, so we have to handle it specially.
1016252723Sdim  if ((Count == 3 || Count == 4) && IsQuad) {
1017252723Sdim    RegisterSuffix += "{";
1018252723Sdim    for (size_t i = 0; i < Count; i++) {
1019252723Sdim      RegisterSuffix += "d{{[0-9]+}}";
1020252723Sdim      if (HasDupPostfix) {
1021252723Sdim        RegisterSuffix += "[]";
1022252723Sdim      }
1023252723Sdim      if (HasLanePostfix) {
1024252723Sdim        RegisterSuffix += "[{{[0-9]+}}]";
1025252723Sdim      }
1026252723Sdim      if (i < Count-1) {
1027252723Sdim        RegisterSuffix += ", ";
1028252723Sdim      }
1029252723Sdim    }
1030252723Sdim    RegisterSuffix += "}";
1031252723Sdim  } else {
1032252723Sdim
1033252723Sdim    // Handle normal loads and stores.
1034252723Sdim    RegisterSuffix += "{";
1035252723Sdim    for (size_t i = 0; i < Count; i++) {
1036252723Sdim      RegisterSuffix += "d{{[0-9]+}}";
1037252723Sdim      if (HasDupPostfix) {
1038252723Sdim        RegisterSuffix += "[]";
1039252723Sdim      }
1040252723Sdim      if (HasLanePostfix) {
1041252723Sdim        RegisterSuffix += "[{{[0-9]+}}]";
1042252723Sdim      }
1043252723Sdim      if (IsQuad && !HasLanePostfix) {
1044252723Sdim        RegisterSuffix += ", d{{[0-9]+}}";
1045252723Sdim        if (HasDupPostfix) {
1046252723Sdim          RegisterSuffix += "[]";
1047252723Sdim        }
1048252723Sdim      }
1049252723Sdim      if (i < Count-1) {
1050252723Sdim        RegisterSuffix += ", ";
1051252723Sdim      }
1052252723Sdim    }
1053252723Sdim    RegisterSuffix += "}, [r{{[0-9]+}}";
1054252723Sdim
1055252723Sdim    // We only include the alignment hint if we have a vld1.*64 or
1056252723Sdim    // a dup/lane instruction.
1057252723Sdim    if (IsLDSTOne) {
1058252723Sdim      if ((HasLanePostfix || HasDupPostfix) && OutTypeCode != "8") {
1059263509Sdim        RegisterSuffix += ":" + OutTypeCode;
1060252723Sdim      }
1061252723Sdim    }
1062252723Sdim
1063252723Sdim    RegisterSuffix += "]";
1064252723Sdim  }
1065252723Sdim}
1066252723Sdim
1067252723Sdimstatic bool HasNPostfixAndScalarArgs(const StringRef &NameRef,
1068252723Sdim                                     const bool &HasNPostfix) {
1069252723Sdim  return (NameRef.count("vmla") ||
1070252723Sdim          NameRef.count("vmlal") ||
1071252723Sdim          NameRef.count("vmlsl") ||
1072252723Sdim          NameRef.count("vmull") ||
1073252723Sdim          NameRef.count("vqdmlal") ||
1074252723Sdim          NameRef.count("vqdmlsl") ||
1075252723Sdim          NameRef.count("vqdmulh") ||
1076252723Sdim          NameRef.count("vqdmull") ||
1077252723Sdim          NameRef.count("vqrdmulh")) && HasNPostfix;
1078252723Sdim}
1079252723Sdim
1080252723Sdimstatic bool IsFiveOperandLaneAccumulator(const StringRef &NameRef,
1081252723Sdim                                         const bool &HasLanePostfix) {
1082252723Sdim  return (NameRef.count("vmla") ||
1083252723Sdim          NameRef.count("vmls") ||
1084252723Sdim          NameRef.count("vmlal") ||
1085252723Sdim          NameRef.count("vmlsl") ||
1086252723Sdim          (NameRef.count("vmul") && NameRef.size() == 3)||
1087252723Sdim          NameRef.count("vqdmlal") ||
1088252723Sdim          NameRef.count("vqdmlsl") ||
1089252723Sdim          NameRef.count("vqdmulh") ||
1090252723Sdim          NameRef.count("vqrdmulh")) && HasLanePostfix;
1091252723Sdim}
1092252723Sdim
1093252723Sdimstatic bool IsSpecialLaneMultiply(const StringRef &NameRef,
1094252723Sdim                                  const bool &HasLanePostfix,
1095252723Sdim                                  const bool &IsQuad) {
1096252723Sdim  const bool IsVMulOrMulh = (NameRef.count("vmul") || NameRef.count("mulh"))
1097252723Sdim                               && IsQuad;
1098252723Sdim  const bool IsVMull = NameRef.count("mull") && !IsQuad;
1099252723Sdim  return (IsVMulOrMulh || IsVMull) && HasLanePostfix;
1100252723Sdim}
1101252723Sdim
1102252723Sdimstatic void NormalizeProtoForRegisterPatternCreation(const std::string &Name,
1103252723Sdim                                                     const std::string &Proto,
1104252723Sdim                                                     const bool &HasNPostfix,
1105252723Sdim                                                     const bool &IsQuad,
1106252723Sdim                                                     const bool &HasLanePostfix,
1107252723Sdim                                                     const bool &HasDupPostfix,
1108252723Sdim                                                     std::string &NormedProto) {
1109252723Sdim  // Handle generic case.
1110252723Sdim  const StringRef NameRef(Name);
1111252723Sdim  for (size_t i = 0, end = Proto.size(); i < end; i++) {
1112252723Sdim    switch (Proto[i]) {
1113252723Sdim    case 'u':
1114252723Sdim    case 'f':
1115263509Sdim    case 'F':
1116252723Sdim    case 'd':
1117252723Sdim    case 's':
1118252723Sdim    case 'x':
1119252723Sdim    case 't':
1120252723Sdim    case 'n':
1121252723Sdim      NormedProto += IsQuad? 'q' : 'd';
1122252723Sdim      break;
1123252723Sdim    case 'w':
1124252723Sdim    case 'k':
1125252723Sdim      NormedProto += 'q';
1126252723Sdim      break;
1127252723Sdim    case 'g':
1128263509Sdim    case 'j':
1129252723Sdim    case 'h':
1130252723Sdim    case 'e':
1131252723Sdim      NormedProto += 'd';
1132252723Sdim      break;
1133252723Sdim    case 'i':
1134252723Sdim      NormedProto += HasLanePostfix? 'a' : 'i';
1135252723Sdim      break;
1136252723Sdim    case 'a':
1137252723Sdim      if (HasLanePostfix) {
1138252723Sdim        NormedProto += 'a';
1139252723Sdim      } else if (HasNPostfixAndScalarArgs(NameRef, HasNPostfix)) {
1140252723Sdim        NormedProto += IsQuad? 'q' : 'd';
1141252723Sdim      } else {
1142252723Sdim        NormedProto += 'i';
1143252723Sdim      }
1144252723Sdim      break;
1145252723Sdim    }
1146252723Sdim  }
1147252723Sdim
1148252723Sdim  // Handle Special Cases.
1149252723Sdim  const bool IsNotVExt = !NameRef.count("vext");
1150252723Sdim  const bool IsVPADAL = NameRef.count("vpadal");
1151252723Sdim  const bool Is5OpLaneAccum = IsFiveOperandLaneAccumulator(NameRef,
1152252723Sdim                                                           HasLanePostfix);
1153252723Sdim  const bool IsSpecialLaneMul = IsSpecialLaneMultiply(NameRef, HasLanePostfix,
1154252723Sdim                                                      IsQuad);
1155252723Sdim
1156252723Sdim  if (IsSpecialLaneMul) {
1157252723Sdim    // If
1158252723Sdim    NormedProto[2] = NormedProto[3];
1159252723Sdim    NormedProto.erase(3);
1160252723Sdim  } else if (NormedProto.size() == 4 &&
1161252723Sdim             NormedProto[0] == NormedProto[1] &&
1162252723Sdim             IsNotVExt) {
1163252723Sdim    // If NormedProto.size() == 4 and the first two proto characters are the
1164252723Sdim    // same, ignore the first.
1165252723Sdim    NormedProto = NormedProto.substr(1, 3);
1166252723Sdim  } else if (Is5OpLaneAccum) {
1167252723Sdim    // If we have a 5 op lane accumulator operation, we take characters 1,2,4
1168252723Sdim    std::string tmp = NormedProto.substr(1,2);
1169252723Sdim    tmp += NormedProto[4];
1170252723Sdim    NormedProto = tmp;
1171252723Sdim  } else if (IsVPADAL) {
1172252723Sdim    // If we have VPADAL, ignore the first character.
1173252723Sdim    NormedProto = NormedProto.substr(0, 2);
1174252723Sdim  } else if (NameRef.count("vdup") && NormedProto.size() > 2) {
1175252723Sdim    // If our instruction is a dup instruction, keep only the first and
1176252723Sdim    // last characters.
1177252723Sdim    std::string tmp = "";
1178252723Sdim    tmp += NormedProto[0];
1179252723Sdim    tmp += NormedProto[NormedProto.size()-1];
1180252723Sdim    NormedProto = tmp;
1181252723Sdim  }
1182252723Sdim}
1183252723Sdim
1184252723Sdim/// GenerateRegisterCheckPatterns - Given a bunch of data we have
1185252723Sdim/// extracted, generate a FileCheck pattern to check that an
1186252723Sdim/// instruction's arguments are correct.
1187252723Sdimstatic void GenerateRegisterCheckPattern(const std::string &Name,
1188252723Sdim                                         const std::string &Proto,
1189252723Sdim                                         const std::string &OutTypeCode,
1190252723Sdim                                         const bool &HasNPostfix,
1191252723Sdim                                         const bool &IsQuad,
1192252723Sdim                                         const bool &HasLanePostfix,
1193252723Sdim                                         const bool &HasDupPostfix,
1194252723Sdim                                         const size_t &TBNumber,
1195252723Sdim                                         std::string &RegisterSuffix) {
1196252723Sdim
1197252723Sdim  RegisterSuffix = "";
1198252723Sdim
1199252723Sdim  const StringRef NameRef(Name);
1200252723Sdim  const StringRef ProtoRef(Proto);
1201252723Sdim
1202252723Sdim  if ((NameRef.count("vdup") || NameRef.count("vmov")) && HasNPostfix) {
1203252723Sdim    return;
1204252723Sdim  }
1205252723Sdim
1206252723Sdim  const bool IsLoadStore = NameRef.count("vld") || NameRef.count("vst");
1207252723Sdim  const bool IsTBXOrTBL = NameRef.count("vtbl") || NameRef.count("vtbx");
1208252723Sdim
1209252723Sdim  if (IsLoadStore) {
1210252723Sdim    // Grab N value from  v{ld,st}N using its ascii representation.
1211252723Sdim    const size_t Count = NameRef[3] - 48;
1212252723Sdim
1213252723Sdim    GenerateRegisterCheckPatternForLoadStores(NameRef, OutTypeCode, IsQuad,
1214252723Sdim                                              HasDupPostfix, HasLanePostfix,
1215252723Sdim                                              Count, RegisterSuffix);
1216252723Sdim  } else if (IsTBXOrTBL) {
1217252723Sdim    RegisterSuffix += "d{{[0-9]+}}, {";
1218252723Sdim    for (size_t i = 0; i < TBNumber-1; i++) {
1219252723Sdim      RegisterSuffix += "d{{[0-9]+}}, ";
1220252723Sdim    }
1221252723Sdim    RegisterSuffix += "d{{[0-9]+}}}, d{{[0-9]+}}";
1222252723Sdim  } else {
1223252723Sdim    // Handle a normal instruction.
1224252723Sdim    if (NameRef.count("vget") || NameRef.count("vset"))
1225252723Sdim      return;
1226252723Sdim
1227252723Sdim    // We first normalize our proto, since we only need to emit 4
1228252723Sdim    // different types of checks, yet have more than 4 proto types
1229252723Sdim    // that map onto those 4 patterns.
1230252723Sdim    std::string NormalizedProto("");
1231252723Sdim    NormalizeProtoForRegisterPatternCreation(Name, Proto, HasNPostfix, IsQuad,
1232252723Sdim                                             HasLanePostfix, HasDupPostfix,
1233252723Sdim                                             NormalizedProto);
1234252723Sdim
1235252723Sdim    for (size_t i = 0, end = NormalizedProto.size(); i < end; i++) {
1236252723Sdim      const char &c = NormalizedProto[i];
1237252723Sdim      switch (c) {
1238252723Sdim      case 'q':
1239252723Sdim        RegisterSuffix += "q{{[0-9]+}}, ";
1240252723Sdim        break;
1241252723Sdim
1242252723Sdim      case 'd':
1243252723Sdim        RegisterSuffix += "d{{[0-9]+}}, ";
1244252723Sdim        break;
1245252723Sdim
1246252723Sdim      case 'i':
1247252723Sdim        RegisterSuffix += "#{{[0-9]+}}, ";
1248252723Sdim        break;
1249252723Sdim
1250252723Sdim      case 'a':
1251252723Sdim        RegisterSuffix += "d{{[0-9]+}}[{{[0-9]}}], ";
1252252723Sdim        break;
1253252723Sdim      }
1254252723Sdim    }
1255252723Sdim
1256252723Sdim    // Remove extra ", ".
1257252723Sdim    RegisterSuffix = RegisterSuffix.substr(0, RegisterSuffix.size()-2);
1258252723Sdim  }
1259252723Sdim}
1260252723Sdim
1261252723Sdim/// GenerateChecksForIntrinsic - Given a specific instruction name +
1262252723Sdim/// typestr + class kind, generate the proper set of FileCheck
1263252723Sdim/// Patterns to check for. We could just return a string, but instead
1264252723Sdim/// use a vector since it provides us with the extra flexibility of
1265252723Sdim/// emitting multiple checks, which comes in handy for certain cases
1266252723Sdim/// like mla where we want to check for 2 different instructions.
1267252723Sdimstatic void GenerateChecksForIntrinsic(const std::string &Name,
1268252723Sdim                                       const std::string &Proto,
1269252723Sdim                                       StringRef &OutTypeStr,
1270252723Sdim                                       StringRef &InTypeStr,
1271252723Sdim                                       ClassKind Ck,
1272252723Sdim                                       const std::string &InstName,
1273252723Sdim                                       bool IsHiddenLOp,
1274252723Sdim                                       std::vector<std::string>& Result) {
1275252723Sdim
1276252723Sdim  // If Ck is a ClassNoTest instruction, just return so no test is
1277252723Sdim  // emitted.
1278252723Sdim  if(Ck == ClassNoTest)
1279252723Sdim    return;
1280252723Sdim
1281252723Sdim  if (Name == "vcvt_f32_f16") {
1282252723Sdim    Result.push_back("vcvt.f32.f16");
1283252723Sdim    return;
1284252723Sdim  }
1285252723Sdim
1286252723Sdim
1287252723Sdim  // Now we preprocess our instruction given the data we have to get the
1288252723Sdim  // data that we need.
1289252723Sdim  // Create a StringRef for String Manipulation of our Name.
1290252723Sdim  const StringRef NameRef(Name);
1291252723Sdim  // Instruction Prefix.
1292252723Sdim  std::string Prefix;
1293252723Sdim  // The type code for our out type string.
1294252723Sdim  std::string OutTypeCode;
1295252723Sdim  // To handle our different cases, we need to check for different postfixes.
1296252723Sdim  // Is our instruction a quad instruction.
1297252723Sdim  bool IsQuad = false;
1298252723Sdim  // Our instruction is of the form <instructionname>_n.
1299252723Sdim  bool HasNPostfix = false;
1300252723Sdim  // Our instruction is of the form <instructionname>_lane.
1301252723Sdim  bool HasLanePostfix = false;
1302252723Sdim  // Our instruction is of the form <instructionname>_dup.
1303252723Sdim  bool HasDupPostfix  = false;
1304252723Sdim  // Our instruction is a vcvt instruction which requires special handling.
1305252723Sdim  bool IsSpecialVCvt = false;
1306252723Sdim  // If we have a vtbxN or vtblN instruction, this is set to N.
1307252723Sdim  size_t TBNumber = -1;
1308252723Sdim  // Register Suffix
1309252723Sdim  std::string RegisterSuffix;
1310252723Sdim
1311252723Sdim  PreprocessInstruction(NameRef, InstName, Prefix,
1312252723Sdim                        HasNPostfix, HasLanePostfix, HasDupPostfix,
1313252723Sdim                        IsSpecialVCvt, TBNumber);
1314252723Sdim
1315252723Sdim  InstructionTypeCode(OutTypeStr, Ck, IsQuad, OutTypeCode);
1316252723Sdim  GenerateRegisterCheckPattern(Name, Proto, OutTypeCode, HasNPostfix, IsQuad,
1317252723Sdim                               HasLanePostfix, HasDupPostfix, TBNumber,
1318252723Sdim                               RegisterSuffix);
1319252723Sdim
1320252723Sdim  // In the following section, we handle a bunch of special cases. You can tell
1321252723Sdim  // a special case by the fact we are returning early.
1322252723Sdim
1323252723Sdim  // If our instruction is a logical instruction without postfix or a
1324252723Sdim  // hidden LOp just return the current Prefix.
1325252723Sdim  if (Ck == ClassL || IsHiddenLOp) {
1326252723Sdim    Result.push_back(Prefix + " " + RegisterSuffix);
1327252723Sdim    return;
1328252723Sdim  }
1329252723Sdim
1330252723Sdim  // If we have a vmov, due to the many different cases, some of which
1331252723Sdim  // vary within the different intrinsics generated for a single
1332252723Sdim  // instruction type, just output a vmov. (e.g. given an instruction
1333252723Sdim  // A, A.u32 might be vmov and A.u8 might be vmov.8).
1334252723Sdim  //
1335252723Sdim  // FIXME: Maybe something can be done about this. The two cases that we care
1336252723Sdim  // about are vmov as an LType and vmov as a WType.
1337252723Sdim  if (Prefix == "vmov") {
1338252723Sdim    Result.push_back(Prefix + " " + RegisterSuffix);
1339252723Sdim    return;
1340252723Sdim  }
1341252723Sdim
1342252723Sdim  // In the following section, we handle special cases.
1343252723Sdim
1344252723Sdim  if (OutTypeCode == "64") {
1345252723Sdim    // If we have a 64 bit vdup/vext and are handling an uint64x1_t
1346252723Sdim    // type, the intrinsic will be optimized away, so just return
1347252723Sdim    // nothing.  On the other hand if we are handling an uint64x2_t
1348252723Sdim    // (i.e. quad instruction), vdup/vmov instructions should be
1349252723Sdim    // emitted.
1350252723Sdim    if (Prefix == "vdup" || Prefix == "vext") {
1351252723Sdim      if (IsQuad) {
1352252723Sdim        Result.push_back("{{vmov|vdup}}");
1353252723Sdim      }
1354252723Sdim      return;
1355252723Sdim    }
1356252723Sdim
1357252723Sdim    // v{st,ld}{2,3,4}_{u,s}64 emit v{st,ld}1.64 instructions with
1358252723Sdim    // multiple register operands.
1359252723Sdim    bool MultiLoadPrefix = Prefix == "vld2" || Prefix == "vld3"
1360252723Sdim                            || Prefix == "vld4";
1361252723Sdim    bool MultiStorePrefix = Prefix == "vst2" || Prefix == "vst3"
1362252723Sdim                            || Prefix == "vst4";
1363252723Sdim    if (MultiLoadPrefix || MultiStorePrefix) {
1364252723Sdim      Result.push_back(NameRef.slice(0, 3).str() + "1.64");
1365252723Sdim      return;
1366252723Sdim    }
1367252723Sdim
1368252723Sdim    // v{st,ld}1_{lane,dup}_{u64,s64} use vldr/vstr/vmov/str instead of
1369252723Sdim    // emitting said instructions. So return a check for
1370252723Sdim    // vldr/vstr/vmov/str instead.
1371252723Sdim    if (HasLanePostfix || HasDupPostfix) {
1372252723Sdim      if (Prefix == "vst1") {
1373252723Sdim        Result.push_back("{{str|vstr|vmov}}");
1374252723Sdim        return;
1375252723Sdim      } else if (Prefix == "vld1") {
1376252723Sdim        Result.push_back("{{ldr|vldr|vmov}}");
1377252723Sdim        return;
1378252723Sdim      }
1379252723Sdim    }
1380252723Sdim  }
1381252723Sdim
1382252723Sdim  // vzip.32/vuzp.32 are the same instruction as vtrn.32 and are
1383252723Sdim  // sometimes disassembled as vtrn.32. We use a regex to handle both
1384252723Sdim  // cases.
1385252723Sdim  if ((Prefix == "vzip" || Prefix == "vuzp") && OutTypeCode == "32") {
1386252723Sdim    Result.push_back("{{vtrn|" + Prefix + "}}.32 " + RegisterSuffix);
1387252723Sdim    return;
1388252723Sdim  }
1389252723Sdim
1390252723Sdim  // Currently on most ARM processors, we do not use vmla/vmls for
1391252723Sdim  // quad floating point operations. Instead we output vmul + vadd. So
1392252723Sdim  // check if we have one of those instructions and just output a
1393252723Sdim  // check for vmul.
1394252723Sdim  if (OutTypeCode == "f32") {
1395252723Sdim    if (Prefix == "vmls") {
1396252723Sdim      Result.push_back("vmul." + OutTypeCode + " " + RegisterSuffix);
1397252723Sdim      Result.push_back("vsub." + OutTypeCode);
1398252723Sdim      return;
1399252723Sdim    } else if (Prefix == "vmla") {
1400252723Sdim      Result.push_back("vmul." + OutTypeCode + " " + RegisterSuffix);
1401252723Sdim      Result.push_back("vadd." + OutTypeCode);
1402252723Sdim      return;
1403252723Sdim    }
1404252723Sdim  }
1405252723Sdim
1406252723Sdim  // If we have vcvt, get the input type from the instruction name
1407252723Sdim  // (which should be of the form instname_inputtype) and append it
1408252723Sdim  // before the output type.
1409252723Sdim  if (Prefix == "vcvt") {
1410252723Sdim    const std::string inTypeCode = NameRef.substr(NameRef.find_last_of("_")+1);
1411252723Sdim    Prefix += "." + inTypeCode;
1412252723Sdim  }
1413252723Sdim
1414252723Sdim  // Append output type code to get our final mangled instruction.
1415252723Sdim  Prefix += "." + OutTypeCode;
1416252723Sdim
1417252723Sdim  Result.push_back(Prefix + " " + RegisterSuffix);
1418252723Sdim}
1419252723Sdim
1420226586Sdim/// UseMacro - Examine the prototype string to determine if the intrinsic
1421226586Sdim/// should be defined as a preprocessor macro instead of an inline function.
1422226586Sdimstatic bool UseMacro(const std::string &proto) {
1423226586Sdim  // If this builtin takes an immediate argument, we need to #define it rather
1424226586Sdim  // than use a standard declaration, so that SemaChecking can range check
1425226586Sdim  // the immediate passed by the user.
1426226586Sdim  if (proto.find('i') != std::string::npos)
1427226586Sdim    return true;
1428226586Sdim
1429226586Sdim  // Pointer arguments need to use macros to avoid hiding aligned attributes
1430226586Sdim  // from the pointer type.
1431226586Sdim  if (proto.find('p') != std::string::npos ||
1432226586Sdim      proto.find('c') != std::string::npos)
1433226586Sdim    return true;
1434226586Sdim
1435226586Sdim  return false;
1436226586Sdim}
1437226586Sdim
1438226586Sdim/// MacroArgUsedDirectly - Return true if argument i for an intrinsic that is
1439226586Sdim/// defined as a macro should be accessed directly instead of being first
1440226586Sdim/// assigned to a local temporary.
1441226586Sdimstatic bool MacroArgUsedDirectly(const std::string &proto, unsigned i) {
1442226586Sdim  // True for constant ints (i), pointers (p) and const pointers (c).
1443226586Sdim  return (proto[i] == 'i' || proto[i] == 'p' || proto[i] == 'c');
1444226586Sdim}
1445226586Sdim
1446226586Sdim// Generate the string "(argtype a, argtype b, ...)"
1447263509Sdimstatic std::string GenArgs(const std::string &proto, StringRef typestr,
1448263509Sdim                           const std::string &name) {
1449226586Sdim  bool define = UseMacro(proto);
1450226586Sdim  char arg = 'a';
1451226586Sdim
1452226586Sdim  std::string s;
1453226586Sdim  s += "(";
1454226586Sdim
1455226586Sdim  for (unsigned i = 1, e = proto.size(); i != e; ++i, ++arg) {
1456226586Sdim    if (define) {
1457226586Sdim      // Some macro arguments are used directly instead of being assigned
1458226586Sdim      // to local temporaries; prepend an underscore prefix to make their
1459226586Sdim      // names consistent with the local temporaries.
1460226586Sdim      if (MacroArgUsedDirectly(proto, i))
1461226586Sdim        s += "__";
1462226586Sdim    } else {
1463226586Sdim      s += TypeString(proto[i], typestr) + " __";
1464226586Sdim    }
1465226586Sdim    s.push_back(arg);
1466263509Sdim    //To avoid argument being multiple defined, add extra number for renaming.
1467263509Sdim    if (name == "vcopy_lane" || name == "vcopy_laneq")
1468263509Sdim      s.push_back('1');
1469226586Sdim    if ((i + 1) < e)
1470226586Sdim      s += ", ";
1471226586Sdim  }
1472226586Sdim
1473226586Sdim  s += ")";
1474226586Sdim  return s;
1475226586Sdim}
1476226586Sdim
1477226586Sdim// Macro arguments are not type-checked like inline function arguments, so
1478226586Sdim// assign them to local temporaries to get the right type checking.
1479263509Sdimstatic std::string GenMacroLocals(const std::string &proto, StringRef typestr,
1480263509Sdim                                  const std::string &name ) {
1481226586Sdim  char arg = 'a';
1482226586Sdim  std::string s;
1483226586Sdim  bool generatedLocal = false;
1484226586Sdim
1485226586Sdim  for (unsigned i = 1, e = proto.size(); i != e; ++i, ++arg) {
1486226586Sdim    // Do not create a temporary for an immediate argument.
1487226586Sdim    // That would defeat the whole point of using a macro!
1488226586Sdim    if (MacroArgUsedDirectly(proto, i))
1489226586Sdim      continue;
1490226586Sdim    generatedLocal = true;
1491263509Sdim    bool extranumber = false;
1492263509Sdim    if (name == "vcopy_lane" || name == "vcopy_laneq")
1493263509Sdim      extranumber = true;
1494226586Sdim
1495226586Sdim    s += TypeString(proto[i], typestr) + " __";
1496226586Sdim    s.push_back(arg);
1497263509Sdim    if(extranumber)
1498263509Sdim      s.push_back('1');
1499226586Sdim    s += " = (";
1500226586Sdim    s.push_back(arg);
1501263509Sdim    if(extranumber)
1502263509Sdim      s.push_back('1');
1503226586Sdim    s += "); ";
1504226586Sdim  }
1505226586Sdim
1506226586Sdim  if (generatedLocal)
1507226586Sdim    s += "\\\n  ";
1508226586Sdim  return s;
1509226586Sdim}
1510226586Sdim
1511226586Sdim// Use the vmovl builtin to sign-extend or zero-extend a vector.
1512263509Sdimstatic std::string Extend(StringRef typestr, const std::string &a, bool h=0) {
1513263509Sdim  std::string s, high;
1514263509Sdim  high = h ? "_high" : "";
1515263509Sdim  s = MangleName("vmovl" + high, typestr, ClassS);
1516263509Sdim  s += "(" + a + ")";
1517263509Sdim  return s;
1518263509Sdim}
1519263509Sdim
1520263509Sdim// Get the high 64-bit part of a vector
1521263509Sdimstatic std::string GetHigh(const std::string &a, StringRef typestr) {
1522226586Sdim  std::string s;
1523263509Sdim  s = MangleName("vget_high", typestr, ClassS);
1524226586Sdim  s += "(" + a + ")";
1525226586Sdim  return s;
1526226586Sdim}
1527226586Sdim
1528263509Sdim// Gen operation with two operands and get high 64-bit for both of two operands.
1529263509Sdimstatic std::string Gen2OpWith2High(StringRef typestr,
1530263509Sdim                                   const std::string &op,
1531263509Sdim                                   const std::string &a,
1532263509Sdim                                   const std::string &b) {
1533263509Sdim  std::string s;
1534263509Sdim  std::string Op1 = GetHigh(a, typestr);
1535263509Sdim  std::string Op2 = GetHigh(b, typestr);
1536263509Sdim  s = MangleName(op, typestr, ClassS);
1537263509Sdim  s += "(" + Op1 + ", " + Op2 + ");";
1538263509Sdim  return s;
1539263509Sdim}
1540263509Sdim
1541263509Sdim// Gen operation with three operands and get high 64-bit of the latter
1542263509Sdim// two operands.
1543263509Sdimstatic std::string Gen3OpWith2High(StringRef typestr,
1544263509Sdim                                   const std::string &op,
1545263509Sdim                                   const std::string &a,
1546263509Sdim                                   const std::string &b,
1547263509Sdim                                   const std::string &c) {
1548263509Sdim  std::string s;
1549263509Sdim  std::string Op1 = GetHigh(b, typestr);
1550263509Sdim  std::string Op2 = GetHigh(c, typestr);
1551263509Sdim  s = MangleName(op, typestr, ClassS);
1552263509Sdim  s += "(" + a + ", " + Op1 + ", " + Op2 + ");";
1553263509Sdim  return s;
1554263509Sdim}
1555263509Sdim
1556263509Sdim// Gen combine operation by putting a on low 64-bit, and b on high 64-bit.
1557263509Sdimstatic std::string GenCombine(std::string typestr,
1558263509Sdim                              const std::string &a,
1559263509Sdim                              const std::string &b) {
1560263509Sdim  std::string s;
1561263509Sdim  s = MangleName("vcombine", typestr, ClassS);
1562263509Sdim  s += "(" + a + ", " + b + ")";
1563263509Sdim  return s;
1564263509Sdim}
1565263509Sdim
1566226586Sdimstatic std::string Duplicate(unsigned nElts, StringRef typestr,
1567226586Sdim                             const std::string &a) {
1568226586Sdim  std::string s;
1569226586Sdim
1570226586Sdim  s = "(" + TypeString('d', typestr) + "){ ";
1571226586Sdim  for (unsigned i = 0; i != nElts; ++i) {
1572226586Sdim    s += a;
1573226586Sdim    if ((i + 1) < nElts)
1574226586Sdim      s += ", ";
1575226586Sdim  }
1576226586Sdim  s += " }";
1577226586Sdim
1578226586Sdim  return s;
1579226586Sdim}
1580226586Sdim
1581226586Sdimstatic std::string SplatLane(unsigned nElts, const std::string &vec,
1582226586Sdim                             const std::string &lane) {
1583226586Sdim  std::string s = "__builtin_shufflevector(" + vec + ", " + vec;
1584226586Sdim  for (unsigned i = 0; i < nElts; ++i)
1585226586Sdim    s += ", " + lane;
1586226586Sdim  s += ")";
1587226586Sdim  return s;
1588226586Sdim}
1589226586Sdim
1590263509Sdimstatic std::string RemoveHigh(const std::string &name) {
1591263509Sdim  std::string s = name;
1592263509Sdim  std::size_t found = s.find("_high_");
1593263509Sdim  if (found == std::string::npos)
1594263509Sdim    PrintFatalError("name should contain \"_high_\" for high intrinsics");
1595263509Sdim  s.replace(found, 5, "");
1596263509Sdim  return s;
1597263509Sdim}
1598263509Sdim
1599226586Sdimstatic unsigned GetNumElements(StringRef typestr, bool &quad) {
1600226586Sdim  quad = false;
1601226586Sdim  bool dummy = false;
1602226586Sdim  char type = ClassifyType(typestr, quad, dummy, dummy);
1603226586Sdim  unsigned nElts = 0;
1604226586Sdim  switch (type) {
1605226586Sdim  case 'c': nElts = 8; break;
1606226586Sdim  case 's': nElts = 4; break;
1607226586Sdim  case 'i': nElts = 2; break;
1608226586Sdim  case 'l': nElts = 1; break;
1609226586Sdim  case 'h': nElts = 4; break;
1610226586Sdim  case 'f': nElts = 2; break;
1611263509Sdim  case 'd':
1612263509Sdim    nElts = 1;
1613263509Sdim    break;
1614226586Sdim  default:
1615245431Sdim    PrintFatalError("unhandled type!");
1616226586Sdim  }
1617226586Sdim  if (quad) nElts <<= 1;
1618226586Sdim  return nElts;
1619226586Sdim}
1620226586Sdim
1621226586Sdim// Generate the definition for this intrinsic, e.g. "a + b" for OpAdd.
1622263509Sdimstatic std::string GenOpString(const std::string &name, OpKind op,
1623263509Sdim                               const std::string &proto, StringRef typestr) {
1624226586Sdim  bool quad;
1625226586Sdim  unsigned nElts = GetNumElements(typestr, quad);
1626226586Sdim  bool define = UseMacro(proto);
1627226586Sdim
1628226586Sdim  std::string ts = TypeString(proto[0], typestr);
1629226586Sdim  std::string s;
1630226586Sdim  if (!define) {
1631226586Sdim    s = "return ";
1632226586Sdim  }
1633226586Sdim
1634226586Sdim  switch(op) {
1635226586Sdim  case OpAdd:
1636226586Sdim    s += "__a + __b;";
1637226586Sdim    break;
1638226586Sdim  case OpAddl:
1639226586Sdim    s += Extend(typestr, "__a") + " + " + Extend(typestr, "__b") + ";";
1640226586Sdim    break;
1641263509Sdim  case OpAddlHi:
1642263509Sdim    s += Extend(typestr, "__a", 1) + " + " + Extend(typestr, "__b", 1) + ";";
1643263509Sdim    break;
1644226586Sdim  case OpAddw:
1645226586Sdim    s += "__a + " + Extend(typestr, "__b") + ";";
1646226586Sdim    break;
1647263509Sdim  case OpAddwHi:
1648263509Sdim    s += "__a + " + Extend(typestr, "__b", 1) + ";";
1649263509Sdim    break;
1650226586Sdim  case OpSub:
1651226586Sdim    s += "__a - __b;";
1652226586Sdim    break;
1653226586Sdim  case OpSubl:
1654226586Sdim    s += Extend(typestr, "__a") + " - " + Extend(typestr, "__b") + ";";
1655226586Sdim    break;
1656263509Sdim  case OpSublHi:
1657263509Sdim    s += Extend(typestr, "__a", 1) + " - " + Extend(typestr, "__b", 1) + ";";
1658263509Sdim    break;
1659226586Sdim  case OpSubw:
1660226586Sdim    s += "__a - " + Extend(typestr, "__b") + ";";
1661226586Sdim    break;
1662263509Sdim  case OpSubwHi:
1663263509Sdim    s += "__a - " + Extend(typestr, "__b", 1) + ";";
1664263509Sdim    break;
1665226586Sdim  case OpMulN:
1666226586Sdim    s += "__a * " + Duplicate(nElts, typestr, "__b") + ";";
1667226586Sdim    break;
1668226586Sdim  case OpMulLane:
1669226586Sdim    s += "__a * " + SplatLane(nElts, "__b", "__c") + ";";
1670226586Sdim    break;
1671263509Sdim  case OpMulXLane:
1672263509Sdim    s += MangleName("vmulx", typestr, ClassS) + "(__a, " +
1673263509Sdim      SplatLane(nElts, "__b", "__c") + ");";
1674263509Sdim    break;
1675226586Sdim  case OpMul:
1676226586Sdim    s += "__a * __b;";
1677226586Sdim    break;
1678263509Sdim  case OpFMlaN:
1679263509Sdim    s += MangleName("vfma", typestr, ClassS);
1680263509Sdim    s += "(__a, __b, " + Duplicate(nElts,typestr, "__c") + ");";
1681263509Sdim    break;
1682263509Sdim  case OpFMlsN:
1683263509Sdim    s += MangleName("vfms", typestr, ClassS);
1684263509Sdim    s += "(__a, __b, " + Duplicate(nElts,typestr, "__c") + ");";
1685263509Sdim    break;
1686226586Sdim  case OpMullLane:
1687226586Sdim    s += MangleName("vmull", typestr, ClassS) + "(__a, " +
1688226586Sdim      SplatLane(nElts, "__b", "__c") + ");";
1689226586Sdim    break;
1690263509Sdim  case OpMullHiLane:
1691263509Sdim    s += MangleName("vmull", typestr, ClassS) + "(" +
1692263509Sdim      GetHigh("__a", typestr) + ", " + SplatLane(nElts, "__b", "__c") + ");";
1693263509Sdim    break;
1694226586Sdim  case OpMlaN:
1695226586Sdim    s += "__a + (__b * " + Duplicate(nElts, typestr, "__c") + ");";
1696226586Sdim    break;
1697226586Sdim  case OpMlaLane:
1698226586Sdim    s += "__a + (__b * " + SplatLane(nElts, "__c", "__d") + ");";
1699226586Sdim    break;
1700226586Sdim  case OpMla:
1701226586Sdim    s += "__a + (__b * __c);";
1702226586Sdim    break;
1703226586Sdim  case OpMlalN:
1704226586Sdim    s += "__a + " + MangleName("vmull", typestr, ClassS) + "(__b, " +
1705226586Sdim      Duplicate(nElts, typestr, "__c") + ");";
1706226586Sdim    break;
1707226586Sdim  case OpMlalLane:
1708226586Sdim    s += "__a + " + MangleName("vmull", typestr, ClassS) + "(__b, " +
1709226586Sdim      SplatLane(nElts, "__c", "__d") + ");";
1710226586Sdim    break;
1711263509Sdim  case OpMlalHiLane:
1712263509Sdim    s += "__a + " + MangleName("vmull", typestr, ClassS) + "(" +
1713263509Sdim      GetHigh("__b", typestr) + ", " + SplatLane(nElts, "__c", "__d") + ");";
1714263509Sdim    break;
1715226586Sdim  case OpMlal:
1716226586Sdim    s += "__a + " + MangleName("vmull", typestr, ClassS) + "(__b, __c);";
1717226586Sdim    break;
1718263509Sdim  case OpMullHi:
1719263509Sdim    s += Gen2OpWith2High(typestr, "vmull", "__a", "__b");
1720263509Sdim    break;
1721263509Sdim  case OpMullHiN:
1722263509Sdim    s += MangleName("vmull_n", typestr, ClassS);
1723263509Sdim    s += "(" + GetHigh("__a", typestr) + ", __b);";
1724263509Sdim    return s;
1725263509Sdim  case OpMlalHi:
1726263509Sdim    s += Gen3OpWith2High(typestr, "vmlal", "__a", "__b", "__c");
1727263509Sdim    break;
1728263509Sdim  case OpMlalHiN:
1729263509Sdim    s += MangleName("vmlal_n", typestr, ClassS);
1730263509Sdim    s += "(__a, " + GetHigh("__b", typestr) + ", __c);";
1731263509Sdim    return s;
1732226586Sdim  case OpMlsN:
1733226586Sdim    s += "__a - (__b * " + Duplicate(nElts, typestr, "__c") + ");";
1734226586Sdim    break;
1735226586Sdim  case OpMlsLane:
1736226586Sdim    s += "__a - (__b * " + SplatLane(nElts, "__c", "__d") + ");";
1737226586Sdim    break;
1738263509Sdim  case OpFMSLane:
1739263509Sdim    s += TypeString(proto[1], typestr) + " __a1 = __a; \\\n  ";
1740263509Sdim    s += TypeString(proto[2], typestr) + " __b1 = __b; \\\n  ";
1741263509Sdim    s += TypeString(proto[3], typestr) + " __c1 = __c; \\\n  ";
1742263509Sdim    s += MangleName("vfma_lane", typestr, ClassS) + "(__a1, __b1, -__c1, __d);";
1743263509Sdim    break;
1744263509Sdim  case OpFMSLaneQ:
1745263509Sdim    s += TypeString(proto[1], typestr) + " __a1 = __a; \\\n  ";
1746263509Sdim    s += TypeString(proto[2], typestr) + " __b1 = __b; \\\n  ";
1747263509Sdim    s += TypeString(proto[3], typestr) + " __c1 = __c; \\\n  ";
1748263509Sdim    s += MangleName("vfma_laneq", typestr, ClassS) + "(__a1, __b1, -__c1, __d);";
1749263509Sdim    break;
1750226586Sdim  case OpMls:
1751226586Sdim    s += "__a - (__b * __c);";
1752226586Sdim    break;
1753226586Sdim  case OpMlslN:
1754226586Sdim    s += "__a - " + MangleName("vmull", typestr, ClassS) + "(__b, " +
1755226586Sdim      Duplicate(nElts, typestr, "__c") + ");";
1756226586Sdim    break;
1757226586Sdim  case OpMlslLane:
1758226586Sdim    s += "__a - " + MangleName("vmull", typestr, ClassS) + "(__b, " +
1759226586Sdim      SplatLane(nElts, "__c", "__d") + ");";
1760226586Sdim    break;
1761263509Sdim  case OpMlslHiLane:
1762263509Sdim    s += "__a - " + MangleName("vmull", typestr, ClassS) + "(" +
1763263509Sdim      GetHigh("__b", typestr) + ", " + SplatLane(nElts, "__c", "__d") + ");";
1764263509Sdim    break;
1765226586Sdim  case OpMlsl:
1766226586Sdim    s += "__a - " + MangleName("vmull", typestr, ClassS) + "(__b, __c);";
1767226586Sdim    break;
1768263509Sdim  case OpMlslHi:
1769263509Sdim    s += Gen3OpWith2High(typestr, "vmlsl", "__a", "__b", "__c");
1770263509Sdim    break;
1771263509Sdim  case OpMlslHiN:
1772263509Sdim    s += MangleName("vmlsl_n", typestr, ClassS);
1773263509Sdim    s += "(__a, " + GetHigh("__b", typestr) + ", __c);";
1774263509Sdim    break;
1775226586Sdim  case OpQDMullLane:
1776226586Sdim    s += MangleName("vqdmull", typestr, ClassS) + "(__a, " +
1777226586Sdim      SplatLane(nElts, "__b", "__c") + ");";
1778226586Sdim    break;
1779263509Sdim  case OpQDMullHiLane:
1780263509Sdim    s += MangleName("vqdmull", typestr, ClassS) + "(" +
1781263509Sdim      GetHigh("__a", typestr) + ", " + SplatLane(nElts, "__b", "__c") + ");";
1782263509Sdim    break;
1783226586Sdim  case OpQDMlalLane:
1784226586Sdim    s += MangleName("vqdmlal", typestr, ClassS) + "(__a, __b, " +
1785226586Sdim      SplatLane(nElts, "__c", "__d") + ");";
1786226586Sdim    break;
1787263509Sdim  case OpQDMlalHiLane:
1788263509Sdim    s += MangleName("vqdmlal", typestr, ClassS) + "(__a, " +
1789263509Sdim      GetHigh("__b", typestr) + ", " + SplatLane(nElts, "__c", "__d") + ");";
1790263509Sdim    break;
1791226586Sdim  case OpQDMlslLane:
1792226586Sdim    s += MangleName("vqdmlsl", typestr, ClassS) + "(__a, __b, " +
1793226586Sdim      SplatLane(nElts, "__c", "__d") + ");";
1794226586Sdim    break;
1795263509Sdim  case OpQDMlslHiLane:
1796263509Sdim    s += MangleName("vqdmlsl", typestr, ClassS) + "(__a, " +
1797263509Sdim      GetHigh("__b", typestr) + ", " + SplatLane(nElts, "__c", "__d") + ");";
1798263509Sdim    break;
1799226586Sdim  case OpQDMulhLane:
1800226586Sdim    s += MangleName("vqdmulh", typestr, ClassS) + "(__a, " +
1801226586Sdim      SplatLane(nElts, "__b", "__c") + ");";
1802226586Sdim    break;
1803226586Sdim  case OpQRDMulhLane:
1804226586Sdim    s += MangleName("vqrdmulh", typestr, ClassS) + "(__a, " +
1805226586Sdim      SplatLane(nElts, "__b", "__c") + ");";
1806226586Sdim    break;
1807226586Sdim  case OpEq:
1808226586Sdim    s += "(" + ts + ")(__a == __b);";
1809226586Sdim    break;
1810226586Sdim  case OpGe:
1811226586Sdim    s += "(" + ts + ")(__a >= __b);";
1812226586Sdim    break;
1813226586Sdim  case OpLe:
1814226586Sdim    s += "(" + ts + ")(__a <= __b);";
1815226586Sdim    break;
1816226586Sdim  case OpGt:
1817226586Sdim    s += "(" + ts + ")(__a > __b);";
1818226586Sdim    break;
1819226586Sdim  case OpLt:
1820226586Sdim    s += "(" + ts + ")(__a < __b);";
1821226586Sdim    break;
1822226586Sdim  case OpNeg:
1823226586Sdim    s += " -__a;";
1824226586Sdim    break;
1825226586Sdim  case OpNot:
1826226586Sdim    s += " ~__a;";
1827226586Sdim    break;
1828226586Sdim  case OpAnd:
1829226586Sdim    s += "__a & __b;";
1830226586Sdim    break;
1831226586Sdim  case OpOr:
1832226586Sdim    s += "__a | __b;";
1833226586Sdim    break;
1834226586Sdim  case OpXor:
1835226586Sdim    s += "__a ^ __b;";
1836226586Sdim    break;
1837226586Sdim  case OpAndNot:
1838226586Sdim    s += "__a & ~__b;";
1839226586Sdim    break;
1840226586Sdim  case OpOrNot:
1841226586Sdim    s += "__a | ~__b;";
1842226586Sdim    break;
1843226586Sdim  case OpCast:
1844226586Sdim    s += "(" + ts + ")__a;";
1845226586Sdim    break;
1846226586Sdim  case OpConcat:
1847226586Sdim    s += "(" + ts + ")__builtin_shufflevector((int64x1_t)__a";
1848226586Sdim    s += ", (int64x1_t)__b, 0, 1);";
1849226586Sdim    break;
1850226586Sdim  case OpHi:
1851263509Sdim    // nElts is for the result vector, so the source is twice that number.
1852263509Sdim    s += "__builtin_shufflevector(__a, __a";
1853263509Sdim    for (unsigned i = nElts; i < nElts * 2; ++i)
1854263509Sdim      s += ", " + utostr(i);
1855263509Sdim    s+= ");";
1856226586Sdim    break;
1857226586Sdim  case OpLo:
1858263509Sdim    s += "__builtin_shufflevector(__a, __a";
1859263509Sdim    for (unsigned i = 0; i < nElts; ++i)
1860263509Sdim      s += ", " + utostr(i);
1861263509Sdim    s+= ");";
1862226586Sdim    break;
1863226586Sdim  case OpDup:
1864226586Sdim    s += Duplicate(nElts, typestr, "__a") + ";";
1865226586Sdim    break;
1866226586Sdim  case OpDupLane:
1867226586Sdim    s += SplatLane(nElts, "__a", "__b") + ";";
1868226586Sdim    break;
1869226586Sdim  case OpSelect:
1870226586Sdim    // ((0 & 1) | (~0 & 2))
1871226586Sdim    s += "(" + ts + ")";
1872226586Sdim    ts = TypeString(proto[1], typestr);
1873226586Sdim    s += "((__a & (" + ts + ")__b) | ";
1874226586Sdim    s += "(~__a & (" + ts + ")__c));";
1875226586Sdim    break;
1876226586Sdim  case OpRev16:
1877226586Sdim    s += "__builtin_shufflevector(__a, __a";
1878226586Sdim    for (unsigned i = 2; i <= nElts; i += 2)
1879226586Sdim      for (unsigned j = 0; j != 2; ++j)
1880226586Sdim        s += ", " + utostr(i - j - 1);
1881226586Sdim    s += ");";
1882226586Sdim    break;
1883226586Sdim  case OpRev32: {
1884226586Sdim    unsigned WordElts = nElts >> (1 + (int)quad);
1885226586Sdim    s += "__builtin_shufflevector(__a, __a";
1886226586Sdim    for (unsigned i = WordElts; i <= nElts; i += WordElts)
1887226586Sdim      for (unsigned j = 0; j != WordElts; ++j)
1888226586Sdim        s += ", " + utostr(i - j - 1);
1889226586Sdim    s += ");";
1890226586Sdim    break;
1891226586Sdim  }
1892226586Sdim  case OpRev64: {
1893226586Sdim    unsigned DblWordElts = nElts >> (int)quad;
1894226586Sdim    s += "__builtin_shufflevector(__a, __a";
1895226586Sdim    for (unsigned i = DblWordElts; i <= nElts; i += DblWordElts)
1896226586Sdim      for (unsigned j = 0; j != DblWordElts; ++j)
1897226586Sdim        s += ", " + utostr(i - j - 1);
1898226586Sdim    s += ");";
1899226586Sdim    break;
1900226586Sdim  }
1901263509Sdim  case OpXtnHi: {
1902263509Sdim    s = TypeString(proto[1], typestr) + " __a1 = " +
1903263509Sdim        MangleName("vmovn", typestr, ClassS) + "(__b);\n  " +
1904263509Sdim        "return __builtin_shufflevector(__a, __a1";
1905263509Sdim    for (unsigned i = 0; i < nElts * 4; ++i)
1906263509Sdim      s += ", " + utostr(i);
1907263509Sdim    s += ");";
1908263509Sdim    break;
1909263509Sdim  }
1910263509Sdim  case OpSqxtunHi: {
1911263509Sdim    s = TypeString(proto[1], typestr) + " __a1 = " +
1912263509Sdim        MangleName("vqmovun", typestr, ClassS) + "(__b);\n  " +
1913263509Sdim        "return __builtin_shufflevector(__a, __a1";
1914263509Sdim    for (unsigned i = 0; i < nElts * 4; ++i)
1915263509Sdim      s += ", " + utostr(i);
1916263509Sdim    s += ");";
1917263509Sdim    break;
1918263509Sdim  }
1919263509Sdim  case OpQxtnHi: {
1920263509Sdim    s = TypeString(proto[1], typestr) + " __a1 = " +
1921263509Sdim        MangleName("vqmovn", typestr, ClassS) + "(__b);\n  " +
1922263509Sdim        "return __builtin_shufflevector(__a, __a1";
1923263509Sdim    for (unsigned i = 0; i < nElts * 4; ++i)
1924263509Sdim      s += ", " + utostr(i);
1925263509Sdim    s += ");";
1926263509Sdim    break;
1927263509Sdim  }
1928263509Sdim  case OpFcvtnHi: {
1929263509Sdim    std::string FName = (nElts == 1) ? "vcvt_f32" : "vcvt_f16";
1930263509Sdim    s = TypeString(proto[1], typestr) + " __a1 = " +
1931263509Sdim        MangleName(FName, typestr, ClassS) + "(__b);\n  " +
1932263509Sdim        "return __builtin_shufflevector(__a, __a1";
1933263509Sdim    for (unsigned i = 0; i < nElts * 4; ++i)
1934263509Sdim      s += ", " + utostr(i);
1935263509Sdim    s += ");";
1936263509Sdim    break;
1937263509Sdim  }
1938263509Sdim  case OpFcvtlHi: {
1939263509Sdim    std::string FName = (nElts == 2) ? "vcvt_f64" : "vcvt_f32";
1940263509Sdim    s = TypeString('d', typestr) + " __a1 = " + GetHigh("__a", typestr) +
1941263509Sdim        ";\n  return " + MangleName(FName, typestr, ClassS) + "(__a1);";
1942263509Sdim    break;
1943263509Sdim  }
1944263509Sdim  case OpFcvtxnHi: {
1945263509Sdim    s = TypeString(proto[1], typestr) + " __a1 = " +
1946263509Sdim        MangleName("vcvtx_f32", typestr, ClassS) + "(__b);\n  " +
1947263509Sdim        "return __builtin_shufflevector(__a, __a1";
1948263509Sdim    for (unsigned i = 0; i < nElts * 4; ++i)
1949263509Sdim      s += ", " + utostr(i);
1950263509Sdim    s += ");";
1951263509Sdim    break;
1952263509Sdim  }
1953263509Sdim  case OpUzp1:
1954263509Sdim    s += "__builtin_shufflevector(__a, __b";
1955263509Sdim    for (unsigned i = 0; i < nElts; i++)
1956263509Sdim      s += ", " + utostr(2*i);
1957263509Sdim    s += ");";
1958263509Sdim    break;
1959263509Sdim  case OpUzp2:
1960263509Sdim    s += "__builtin_shufflevector(__a, __b";
1961263509Sdim    for (unsigned i = 0; i < nElts; i++)
1962263509Sdim      s += ", " + utostr(2*i+1);
1963263509Sdim    s += ");";
1964263509Sdim    break;
1965263509Sdim  case OpZip1:
1966263509Sdim    s += "__builtin_shufflevector(__a, __b";
1967263509Sdim    for (unsigned i = 0; i < (nElts/2); i++)
1968263509Sdim       s += ", " + utostr(i) + ", " + utostr(i+nElts);
1969263509Sdim    s += ");";
1970263509Sdim    break;
1971263509Sdim  case OpZip2:
1972263509Sdim    s += "__builtin_shufflevector(__a, __b";
1973263509Sdim    for (unsigned i = nElts/2; i < nElts; i++)
1974263509Sdim       s += ", " + utostr(i) + ", " + utostr(i+nElts);
1975263509Sdim    s += ");";
1976263509Sdim    break;
1977263509Sdim  case OpTrn1:
1978263509Sdim    s += "__builtin_shufflevector(__a, __b";
1979263509Sdim    for (unsigned i = 0; i < (nElts/2); i++)
1980263509Sdim       s += ", " + utostr(2*i) + ", " + utostr(2*i+nElts);
1981263509Sdim    s += ");";
1982263509Sdim    break;
1983263509Sdim  case OpTrn2:
1984263509Sdim    s += "__builtin_shufflevector(__a, __b";
1985263509Sdim    for (unsigned i = 0; i < (nElts/2); i++)
1986263509Sdim       s += ", " + utostr(2*i+1) + ", " + utostr(2*i+1+nElts);
1987263509Sdim    s += ");";
1988263509Sdim    break;
1989226586Sdim  case OpAbdl: {
1990226586Sdim    std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)";
1991226586Sdim    if (typestr[0] != 'U') {
1992226586Sdim      // vabd results are always unsigned and must be zero-extended.
1993226586Sdim      std::string utype = "U" + typestr.str();
1994226586Sdim      s += "(" + TypeString(proto[0], typestr) + ")";
1995226586Sdim      abd = "(" + TypeString('d', utype) + ")" + abd;
1996226586Sdim      s += Extend(utype, abd) + ";";
1997226586Sdim    } else {
1998226586Sdim      s += Extend(typestr, abd) + ";";
1999226586Sdim    }
2000226586Sdim    break;
2001226586Sdim  }
2002263509Sdim  case OpAbdlHi:
2003263509Sdim    s += Gen2OpWith2High(typestr, "vabdl", "__a", "__b");
2004263509Sdim    break;
2005263509Sdim  case OpAddhnHi: {
2006263509Sdim    std::string addhn = MangleName("vaddhn", typestr, ClassS) + "(__b, __c)";
2007263509Sdim    s += GenCombine(GetNarrowTypestr(typestr), "__a", addhn);
2008263509Sdim    s += ";";
2009263509Sdim    break;
2010263509Sdim  }
2011263509Sdim  case OpRAddhnHi: {
2012263509Sdim    std::string raddhn = MangleName("vraddhn", typestr, ClassS) + "(__b, __c)";
2013263509Sdim    s += GenCombine(GetNarrowTypestr(typestr), "__a", raddhn);
2014263509Sdim    s += ";";
2015263509Sdim    break;
2016263509Sdim  }
2017263509Sdim  case OpSubhnHi: {
2018263509Sdim    std::string subhn = MangleName("vsubhn", typestr, ClassS) + "(__b, __c)";
2019263509Sdim    s += GenCombine(GetNarrowTypestr(typestr), "__a", subhn);
2020263509Sdim    s += ";";
2021263509Sdim    break;
2022263509Sdim  }
2023263509Sdim  case OpRSubhnHi: {
2024263509Sdim    std::string rsubhn = MangleName("vrsubhn", typestr, ClassS) + "(__b, __c)";
2025263509Sdim    s += GenCombine(GetNarrowTypestr(typestr), "__a", rsubhn);
2026263509Sdim    s += ";";
2027263509Sdim    break;
2028263509Sdim  }
2029226586Sdim  case OpAba:
2030226586Sdim    s += "__a + " + MangleName("vabd", typestr, ClassS) + "(__b, __c);";
2031226586Sdim    break;
2032263509Sdim  case OpAbal:
2033263509Sdim    s += "__a + " + MangleName("vabdl", typestr, ClassS) + "(__b, __c);";
2034263509Sdim    break;
2035263509Sdim  case OpAbalHi:
2036263509Sdim    s += Gen3OpWith2High(typestr, "vabal", "__a", "__b", "__c");
2037263509Sdim    break;
2038263509Sdim  case OpQDMullHi:
2039263509Sdim    s += Gen2OpWith2High(typestr, "vqdmull", "__a", "__b");
2040263509Sdim    break;
2041263509Sdim  case OpQDMullHiN:
2042263509Sdim    s += MangleName("vqdmull_n", typestr, ClassS);
2043263509Sdim    s += "(" + GetHigh("__a", typestr) + ", __b);";
2044263509Sdim    return s;
2045263509Sdim  case OpQDMlalHi:
2046263509Sdim    s += Gen3OpWith2High(typestr, "vqdmlal", "__a", "__b", "__c");
2047263509Sdim    break;
2048263509Sdim  case OpQDMlalHiN:
2049263509Sdim    s += MangleName("vqdmlal_n", typestr, ClassS);
2050263509Sdim    s += "(__a, " + GetHigh("__b", typestr) + ", __c);";
2051263509Sdim    return s;
2052263509Sdim  case OpQDMlslHi:
2053263509Sdim    s += Gen3OpWith2High(typestr, "vqdmlsl", "__a", "__b", "__c");
2054263509Sdim    break;
2055263509Sdim  case OpQDMlslHiN:
2056263509Sdim    s += MangleName("vqdmlsl_n", typestr, ClassS);
2057263509Sdim    s += "(__a, " + GetHigh("__b", typestr) + ", __c);";
2058263509Sdim    return s;
2059263509Sdim  case OpDiv:
2060263509Sdim    s += "__a / __b;";
2061263509Sdim    break;
2062263509Sdim  case OpMovlHi: {
2063263509Sdim    s = TypeString(proto[1], typestr.drop_front()) + " __a1 = " +
2064263509Sdim        MangleName("vget_high", typestr, ClassS) + "(__a);\n  " + s;
2065263509Sdim    s += "(" + ts + ")" + MangleName("vshll_n", typestr, ClassS);
2066263509Sdim    s += "(__a1, 0);";
2067263509Sdim    break;
2068263509Sdim  }
2069263509Sdim  case OpLongHi: {
2070263509Sdim    // Another local variable __a1 is needed for calling a Macro,
2071263509Sdim    // or using __a will have naming conflict when Macro expanding.
2072263509Sdim    s += TypeString(proto[1], typestr.drop_front()) + " __a1 = " +
2073263509Sdim         MangleName("vget_high", typestr, ClassS) + "(__a); \\\n";
2074263509Sdim    s += "  (" + ts + ")" + MangleName(RemoveHigh(name), typestr, ClassS) +
2075263509Sdim         "(__a1, __b);";
2076263509Sdim    break;
2077263509Sdim  }
2078263509Sdim  case OpNarrowHi: {
2079263509Sdim    s += "(" + ts + ")" + MangleName("vcombine", typestr, ClassS) + "(__a, " +
2080263509Sdim         MangleName(RemoveHigh(name), typestr, ClassS) + "(__b, __c));";
2081263509Sdim    break;
2082263509Sdim  }
2083263509Sdim  case OpCopyLane: {
2084263509Sdim    s += TypeString('s', typestr) + " __c2 = " +
2085263509Sdim         MangleName("vget_lane", typestr, ClassS) + "(__c1, __d1); \\\n  " +
2086263509Sdim         MangleName("vset_lane", typestr, ClassS) + "(__c2, __a1, __b1);";
2087263509Sdim    break;
2088263509Sdim  }
2089263509Sdim  case OpCopyQLane: {
2090263509Sdim    std::string typeCode = "";
2091263509Sdim    InstructionTypeCode(typestr, ClassS, quad, typeCode);
2092263509Sdim    s += TypeString('s', typestr) + " __c2 = vget_lane_" + typeCode +
2093263509Sdim         "(__c1, __d1); \\\n  vsetq_lane_" + typeCode + "(__c2, __a1, __b1);";
2094263509Sdim    break;
2095263509Sdim  }
2096263509Sdim  case OpCopyLaneQ: {
2097263509Sdim    std::string typeCode = "";
2098263509Sdim    InstructionTypeCode(typestr, ClassS, quad, typeCode);
2099263509Sdim    s += TypeString('s', typestr) + " __c2 = vgetq_lane_" + typeCode +
2100263509Sdim         "(__c1, __d1); \\\n  vset_lane_" + typeCode + "(__c2, __a1, __b1);";
2101263509Sdim    break;
2102263509Sdim  }
2103263509Sdim  case OpScalarMulLane: {
2104263509Sdim    std::string typeCode = "";
2105263509Sdim    InstructionTypeCode(typestr, ClassS, quad, typeCode);
2106263509Sdim    s += TypeString('s', typestr) + " __d1 = vget_lane_" + typeCode +
2107263509Sdim      "(__b, __c);\\\n  __a * __d1;";
2108263509Sdim    break;
2109263509Sdim  }
2110263509Sdim  case OpScalarMulLaneQ: {
2111263509Sdim    std::string typeCode = "";
2112263509Sdim    InstructionTypeCode(typestr, ClassS, quad, typeCode);
2113263509Sdim        s += TypeString('s', typestr) + " __d1 = vgetq_lane_" + typeCode +
2114263509Sdim          "(__b, __c);\\\n  __a * __d1;";
2115263509Sdim    break;
2116263509Sdim  }
2117263509Sdim  case OpScalarMulXLane: {
2118263509Sdim    bool dummy = false;
2119263509Sdim    char type = ClassifyType(typestr, dummy, dummy, dummy);
2120263509Sdim    if (type == 'f') type = 's';
2121263509Sdim    std::string typeCode = "";
2122263509Sdim    InstructionTypeCode(typestr, ClassS, quad, typeCode);
2123263509Sdim    s += TypeString('s', typestr) + " __d1 = vget_lane_" + typeCode +
2124263509Sdim      "(__b, __c);\\\n  vmulx" + type + "_" +
2125263509Sdim      typeCode +  "(__a, __d1);";
2126263509Sdim    break;
2127263509Sdim  }
2128263509Sdim  case OpScalarMulXLaneQ: {
2129263509Sdim    bool dummy = false;
2130263509Sdim    char type = ClassifyType(typestr, dummy, dummy, dummy);
2131263509Sdim    if (type == 'f') type = 's';
2132263509Sdim    std::string typeCode = "";
2133263509Sdim    InstructionTypeCode(typestr, ClassS, quad, typeCode);
2134263509Sdim    s += TypeString('s', typestr) + " __d1 = vgetq_lane_" +
2135263509Sdim      typeCode + "(__b, __c);\\\n  vmulx" + type +
2136263509Sdim      "_" + typeCode +  "(__a, __d1);";
2137263509Sdim    break;
2138263509Sdim  }
2139263509Sdim
2140263509Sdim  case OpScalarVMulXLane: {
2141263509Sdim    bool dummy = false;
2142263509Sdim    char type = ClassifyType(typestr, dummy, dummy, dummy);
2143263509Sdim    if (type == 'f') type = 's';
2144263509Sdim    std::string typeCode = "";
2145263509Sdim    InstructionTypeCode(typestr, ClassS, quad, typeCode);
2146263509Sdim    s += TypeString('s', typestr) + " __d1 = vget_lane_" +
2147263509Sdim      typeCode + "(__a, 0);\\\n" +
2148263509Sdim      "  " + TypeString('s', typestr) + " __e1 = vget_lane_" +
2149263509Sdim      typeCode + "(__b, __c);\\\n" +
2150263509Sdim      "  " + TypeString('s', typestr) + " __f1 = vmulx" + type + "_" +
2151263509Sdim      typeCode + "(__d1, __e1);\\\n" +
2152263509Sdim      "  " + TypeString('d', typestr) + " __g1;\\\n" +
2153263509Sdim      "  vset_lane_" + typeCode + "(__f1, __g1, __c);";
2154263509Sdim    break;
2155263509Sdim  }
2156263509Sdim
2157263509Sdim  case OpScalarVMulXLaneQ: {
2158263509Sdim    bool dummy = false;
2159263509Sdim    char type = ClassifyType(typestr, dummy, dummy, dummy);
2160263509Sdim    if (type == 'f') type = 's';
2161263509Sdim    std::string typeCode = "";
2162263509Sdim    InstructionTypeCode(typestr, ClassS, quad, typeCode);
2163263509Sdim    s += TypeString('s', typestr) + " __d1 = vget_lane_" +
2164263509Sdim      typeCode + "(__a, 0);\\\n" +
2165263509Sdim      "  " + TypeString('s', typestr) + " __e1 = vgetq_lane_" +
2166263509Sdim      typeCode + "(__b, __c);\\\n" +
2167263509Sdim      "  " + TypeString('s', typestr) + " __f1 = vmulx" + type + "_" +
2168263509Sdim      typeCode + "(__d1, __e1);\\\n" +
2169263509Sdim      "  " + TypeString('d', typestr) + " __g1;\\\n" +
2170263509Sdim      "  vset_lane_" + typeCode + "(__f1, __g1, 0);";
2171263509Sdim    break;
2172263509Sdim  }
2173263509Sdim  case OpScalarQDMullLane: {
2174263509Sdim    std::string typeCode = "";
2175263509Sdim    InstructionTypeCode(typestr, ClassS, quad, typeCode);
2176263509Sdim    s += MangleName("vqdmull", typestr, ClassS) + "(__a, " +
2177263509Sdim    "vget_lane_" + typeCode + "(b, __c));";
2178263509Sdim    break;
2179263509Sdim  }
2180263509Sdim  case OpScalarQDMullLaneQ: {
2181263509Sdim    std::string typeCode = "";
2182263509Sdim    InstructionTypeCode(typestr, ClassS, quad, typeCode);
2183263509Sdim    s += MangleName("vqdmull", typestr, ClassS) + "(__a, " +
2184263509Sdim    "vgetq_lane_" + typeCode + "(b, __c));";
2185263509Sdim    break;
2186263509Sdim  }
2187263509Sdim  case OpScalarQDMulHiLane: {
2188263509Sdim    std::string typeCode = "";
2189263509Sdim    InstructionTypeCode(typestr, ClassS, quad, typeCode);
2190263509Sdim    s += MangleName("vqdmulh", typestr, ClassS) + "(__a, " +
2191263509Sdim    "vget_lane_" + typeCode + "(__b, __c));";
2192263509Sdim    break;
2193263509Sdim  }
2194263509Sdim  case OpScalarQDMulHiLaneQ: {
2195263509Sdim    std::string typeCode = "";
2196263509Sdim    InstructionTypeCode(typestr, ClassS, quad, typeCode);
2197263509Sdim    s += MangleName("vqdmulh", typestr, ClassS) + "(__a, " +
2198263509Sdim    "vgetq_lane_" + typeCode + "(__b, __c));";
2199263509Sdim    break;
2200263509Sdim  }
2201263509Sdim  case OpScalarQRDMulHiLane: {
2202263509Sdim    std::string typeCode = "";
2203263509Sdim    InstructionTypeCode(typestr, ClassS, quad, typeCode);
2204263509Sdim    s += MangleName("vqrdmulh", typestr, ClassS) + "(__a, " +
2205263509Sdim    "vget_lane_" + typeCode + "(__b, __c));";
2206263509Sdim    break;
2207263509Sdim  }
2208263509Sdim  case OpScalarQRDMulHiLaneQ: {
2209263509Sdim    std::string typeCode = "";
2210263509Sdim    InstructionTypeCode(typestr, ClassS, quad, typeCode);
2211263509Sdim    s += MangleName("vqrdmulh", typestr, ClassS) + "(__a, " +
2212263509Sdim    "vgetq_lane_" + typeCode + "(__b, __c));";
2213263509Sdim    break;
2214263509Sdim  }
2215263509Sdim  case OpScalarGetLane:{
2216263509Sdim    std::string typeCode = "";
2217263509Sdim    InstructionTypeCode(typestr, ClassS, quad, typeCode);
2218263509Sdim    if (quad) {
2219263509Sdim     s += "int16x8_t __a1 = vreinterpretq_s16_f16(__a);\\\n";
2220263509Sdim     s += "  vgetq_lane_s16(__a1, __b);";
2221226586Sdim    } else {
2222263509Sdim     s += "int16x4_t __a1 = vreinterpret_s16_f16(__a);\\\n";
2223263509Sdim     s += "  vget_lane_s16(__a1, __b);";
2224226586Sdim    }
2225226586Sdim    break;
2226226586Sdim  }
2227263509Sdim  case OpScalarSetLane:{
2228263509Sdim    std::string typeCode = "";
2229263509Sdim    InstructionTypeCode(typestr, ClassS, quad, typeCode);
2230263509Sdim    s += "int16_t __a1 = (int16_t)__a;\\\n";
2231263509Sdim    if (quad) {
2232263509Sdim     s += "  int16x8_t __b1 = vreinterpretq_s16_f16(b);\\\n";
2233263509Sdim     s += "  int16x8_t __b2 = vsetq_lane_s16(__a1, __b1, __c);\\\n";
2234263509Sdim     s += "  vreinterpretq_f16_s16(__b2);";
2235263509Sdim    } else {
2236263509Sdim     s += "  int16x4_t __b1 = vreinterpret_s16_f16(b);\\\n";
2237263509Sdim     s += "  int16x4_t __b2 = vset_lane_s16(__a1, __b1, __c);\\\n";
2238263509Sdim     s += "  vreinterpret_f16_s16(__b2);";
2239263509Sdim    }
2240263509Sdim    break;
2241263509Sdim  }
2242263509Sdim
2243226586Sdim  default:
2244245431Sdim    PrintFatalError("unknown OpKind!");
2245226586Sdim  }
2246226586Sdim  return s;
2247226586Sdim}
2248226586Sdim
2249226586Sdimstatic unsigned GetNeonEnum(const std::string &proto, StringRef typestr) {
2250226586Sdim  unsigned mod = proto[0];
2251226586Sdim
2252263509Sdim  if (mod == 'v' || mod == 'f' || mod == 'F')
2253226586Sdim    mod = proto[1];
2254226586Sdim
2255226586Sdim  bool quad = false;
2256226586Sdim  bool poly = false;
2257226586Sdim  bool usgn = false;
2258226586Sdim  bool scal = false;
2259226586Sdim  bool cnst = false;
2260226586Sdim  bool pntr = false;
2261226586Sdim
2262226586Sdim  // Base type to get the type string for.
2263226586Sdim  char type = ClassifyType(typestr, quad, poly, usgn);
2264226586Sdim
2265226586Sdim  // Based on the modifying character, change the type and width if necessary.
2266226586Sdim  type = ModType(mod, type, quad, poly, usgn, scal, cnst, pntr);
2267226586Sdim
2268235633Sdim  NeonTypeFlags::EltType ET;
2269226586Sdim  switch (type) {
2270226586Sdim    case 'c':
2271235633Sdim      ET = poly ? NeonTypeFlags::Poly8 : NeonTypeFlags::Int8;
2272226586Sdim      break;
2273226586Sdim    case 's':
2274235633Sdim      ET = poly ? NeonTypeFlags::Poly16 : NeonTypeFlags::Int16;
2275226586Sdim      break;
2276226586Sdim    case 'i':
2277235633Sdim      ET = NeonTypeFlags::Int32;
2278226586Sdim      break;
2279226586Sdim    case 'l':
2280263509Sdim      ET = poly ? NeonTypeFlags::Poly64 : NeonTypeFlags::Int64;
2281226586Sdim      break;
2282226586Sdim    case 'h':
2283235633Sdim      ET = NeonTypeFlags::Float16;
2284226586Sdim      break;
2285226586Sdim    case 'f':
2286235633Sdim      ET = NeonTypeFlags::Float32;
2287226586Sdim      break;
2288263509Sdim    case 'd':
2289263509Sdim      ET = NeonTypeFlags::Float64;
2290263509Sdim      break;
2291226586Sdim    default:
2292245431Sdim      PrintFatalError("unhandled type!");
2293226586Sdim  }
2294235633Sdim  NeonTypeFlags Flags(ET, usgn, quad && proto[1] != 'g');
2295235633Sdim  return Flags.getFlags();
2296226586Sdim}
2297226586Sdim
2298263509Sdim// We don't check 'a' in this function, because for builtin function the
2299263509Sdim// argument matching to 'a' uses a vector type splatted from a scalar type.
2300263509Sdimstatic bool ProtoHasScalar(const std::string proto)
2301263509Sdim{
2302263509Sdim  return (proto.find('s') != std::string::npos
2303263509Sdim          || proto.find('z') != std::string::npos
2304263509Sdim          || proto.find('r') != std::string::npos
2305263509Sdim          || proto.find('b') != std::string::npos
2306263509Sdim          || proto.find('$') != std::string::npos
2307263509Sdim          || proto.find('y') != std::string::npos
2308263509Sdim          || proto.find('o') != std::string::npos);
2309263509Sdim}
2310263509Sdim
2311226586Sdim// Generate the definition for this intrinsic, e.g. __builtin_neon_cls(a)
2312226586Sdimstatic std::string GenBuiltin(const std::string &name, const std::string &proto,
2313226586Sdim                              StringRef typestr, ClassKind ck) {
2314226586Sdim  std::string s;
2315226586Sdim
2316226586Sdim  // If this builtin returns a struct 2, 3, or 4 vectors, pass it as an implicit
2317226586Sdim  // sret-like argument.
2318263509Sdim  bool sret = IsMultiVecProto(proto[0]);
2319226586Sdim
2320226586Sdim  bool define = UseMacro(proto);
2321226586Sdim
2322226586Sdim  // Check if the prototype has a scalar operand with the type of the vector
2323226586Sdim  // elements.  If not, bitcasting the args will take care of arg checking.
2324226586Sdim  // The actual signedness etc. will be taken care of with special enums.
2325263509Sdim  if (!ProtoHasScalar(proto))
2326226586Sdim    ck = ClassB;
2327226586Sdim
2328226586Sdim  if (proto[0] != 'v') {
2329226586Sdim    std::string ts = TypeString(proto[0], typestr);
2330226586Sdim
2331226586Sdim    if (define) {
2332226586Sdim      if (sret)
2333226586Sdim        s += ts + " r; ";
2334226586Sdim      else
2335226586Sdim        s += "(" + ts + ")";
2336226586Sdim    } else if (sret) {
2337226586Sdim      s += ts + " r; ";
2338226586Sdim    } else {
2339226586Sdim      s += "return (" + ts + ")";
2340226586Sdim    }
2341226586Sdim  }
2342226586Sdim
2343226586Sdim  bool splat = proto.find('a') != std::string::npos;
2344226586Sdim
2345226586Sdim  s += "__builtin_neon_";
2346226586Sdim  if (splat) {
2347226586Sdim    // Call the non-splat builtin: chop off the "_n" suffix from the name.
2348226586Sdim    std::string vname(name, 0, name.size()-2);
2349226586Sdim    s += MangleName(vname, typestr, ck);
2350226586Sdim  } else {
2351226586Sdim    s += MangleName(name, typestr, ck);
2352226586Sdim  }
2353226586Sdim  s += "(";
2354226586Sdim
2355226586Sdim  // Pass the address of the return variable as the first argument to sret-like
2356226586Sdim  // builtins.
2357226586Sdim  if (sret)
2358226586Sdim    s += "&r, ";
2359226586Sdim
2360226586Sdim  char arg = 'a';
2361226586Sdim  for (unsigned i = 1, e = proto.size(); i != e; ++i, ++arg) {
2362226586Sdim    std::string args = std::string(&arg, 1);
2363226586Sdim
2364226586Sdim    // Use the local temporaries instead of the macro arguments.
2365226586Sdim    args = "__" + args;
2366226586Sdim
2367226586Sdim    bool argQuad = false;
2368226586Sdim    bool argPoly = false;
2369226586Sdim    bool argUsgn = false;
2370226586Sdim    bool argScalar = false;
2371226586Sdim    bool dummy = false;
2372226586Sdim    char argType = ClassifyType(typestr, argQuad, argPoly, argUsgn);
2373226586Sdim    argType = ModType(proto[i], argType, argQuad, argPoly, argUsgn, argScalar,
2374226586Sdim                      dummy, dummy);
2375226586Sdim
2376226586Sdim    // Handle multiple-vector values specially, emitting each subvector as an
2377226586Sdim    // argument to the __builtin.
2378263509Sdim    unsigned NumOfVec = 0;
2379226586Sdim    if (proto[i] >= '2' && proto[i] <= '4') {
2380263509Sdim      NumOfVec = proto[i] - '0';
2381263509Sdim    } else if (proto[i] >= 'B' && proto[i] <= 'D') {
2382263509Sdim      NumOfVec = proto[i] - 'A' + 1;
2383263509Sdim    }
2384263509Sdim
2385263509Sdim    if (NumOfVec > 0) {
2386226586Sdim      // Check if an explicit cast is needed.
2387226586Sdim      if (argType != 'c' || argPoly || argUsgn)
2388226586Sdim        args = (argQuad ? "(int8x16_t)" : "(int8x8_t)") + args;
2389226586Sdim
2390263509Sdim      for (unsigned vi = 0, ve = NumOfVec; vi != ve; ++vi) {
2391226586Sdim        s += args + ".val[" + utostr(vi) + "]";
2392226586Sdim        if ((vi + 1) < ve)
2393226586Sdim          s += ", ";
2394226586Sdim      }
2395226586Sdim      if ((i + 1) < e)
2396226586Sdim        s += ", ";
2397226586Sdim
2398226586Sdim      continue;
2399226586Sdim    }
2400226586Sdim
2401226586Sdim    if (splat && (i + 1) == e)
2402226586Sdim      args = Duplicate(GetNumElements(typestr, argQuad), typestr, args);
2403226586Sdim
2404226586Sdim    // Check if an explicit cast is needed.
2405226586Sdim    if ((splat || !argScalar) &&
2406226586Sdim        ((ck == ClassB && argType != 'c') || argPoly || argUsgn)) {
2407226586Sdim      std::string argTypeStr = "c";
2408226586Sdim      if (ck != ClassB)
2409226586Sdim        argTypeStr = argType;
2410226586Sdim      if (argQuad)
2411226586Sdim        argTypeStr = "Q" + argTypeStr;
2412226586Sdim      args = "(" + TypeString('d', argTypeStr) + ")" + args;
2413226586Sdim    }
2414226586Sdim
2415226586Sdim    s += args;
2416226586Sdim    if ((i + 1) < e)
2417226586Sdim      s += ", ";
2418226586Sdim  }
2419226586Sdim
2420226586Sdim  // Extra constant integer to hold type class enum for this function, e.g. s8
2421226586Sdim  if (ck == ClassB)
2422226586Sdim    s += ", " + utostr(GetNeonEnum(proto, typestr));
2423226586Sdim
2424226586Sdim  s += ");";
2425226586Sdim
2426226586Sdim  if (proto[0] != 'v' && sret) {
2427226586Sdim    if (define)
2428226586Sdim      s += " r;";
2429226586Sdim    else
2430226586Sdim      s += " return r;";
2431226586Sdim  }
2432226586Sdim  return s;
2433226586Sdim}
2434226586Sdim
2435226586Sdimstatic std::string GenBuiltinDef(const std::string &name,
2436226586Sdim                                 const std::string &proto,
2437226586Sdim                                 StringRef typestr, ClassKind ck) {
2438226586Sdim  std::string s("BUILTIN(__builtin_neon_");
2439226586Sdim
2440226586Sdim  // If all types are the same size, bitcasting the args will take care
2441226586Sdim  // of arg checking.  The actual signedness etc. will be taken care of with
2442226586Sdim  // special enums.
2443263509Sdim  if (!ProtoHasScalar(proto))
2444226586Sdim    ck = ClassB;
2445226586Sdim
2446226586Sdim  s += MangleName(name, typestr, ck);
2447226586Sdim  s += ", \"";
2448226586Sdim
2449226586Sdim  for (unsigned i = 0, e = proto.size(); i != e; ++i)
2450226586Sdim    s += BuiltinTypeString(proto[i], typestr, ck, i == 0);
2451226586Sdim
2452226586Sdim  // Extra constant integer to hold type class enum for this function, e.g. s8
2453226586Sdim  if (ck == ClassB)
2454226586Sdim    s += "i";
2455226586Sdim
2456226586Sdim  s += "\", \"n\")";
2457226586Sdim  return s;
2458226586Sdim}
2459226586Sdim
2460226586Sdimstatic std::string GenIntrinsic(const std::string &name,
2461226586Sdim                                const std::string &proto,
2462226586Sdim                                StringRef outTypeStr, StringRef inTypeStr,
2463226586Sdim                                OpKind kind, ClassKind classKind) {
2464226586Sdim  assert(!proto.empty() && "");
2465245431Sdim  bool define = UseMacro(proto) && kind != OpUnavailable;
2466226586Sdim  std::string s;
2467226586Sdim
2468226586Sdim  // static always inline + return type
2469226586Sdim  if (define)
2470226586Sdim    s += "#define ";
2471226586Sdim  else
2472226586Sdim    s += "__ai " + TypeString(proto[0], outTypeStr) + " ";
2473226586Sdim
2474226586Sdim  // Function name with type suffix
2475226586Sdim  std::string mangledName = MangleName(name, outTypeStr, ClassS);
2476226586Sdim  if (outTypeStr != inTypeStr) {
2477226586Sdim    // If the input type is different (e.g., for vreinterpret), append a suffix
2478226586Sdim    // for the input type.  String off a "Q" (quad) prefix so that MangleName
2479226586Sdim    // does not insert another "q" in the name.
2480226586Sdim    unsigned typeStrOff = (inTypeStr[0] == 'Q' ? 1 : 0);
2481226586Sdim    StringRef inTypeNoQuad = inTypeStr.substr(typeStrOff);
2482226586Sdim    mangledName = MangleName(mangledName, inTypeNoQuad, ClassS);
2483226586Sdim  }
2484226586Sdim  s += mangledName;
2485226586Sdim
2486226586Sdim  // Function arguments
2487263509Sdim  s += GenArgs(proto, inTypeStr, name);
2488226586Sdim
2489226586Sdim  // Definition.
2490226586Sdim  if (define) {
2491226586Sdim    s += " __extension__ ({ \\\n  ";
2492263509Sdim    s += GenMacroLocals(proto, inTypeStr, name);
2493245431Sdim  } else if (kind == OpUnavailable) {
2494245431Sdim    s += " __attribute__((unavailable));\n";
2495245431Sdim    return s;
2496245431Sdim  } else
2497245431Sdim    s += " {\n  ";
2498226586Sdim
2499226586Sdim  if (kind != OpNone)
2500263509Sdim    s += GenOpString(name, kind, proto, outTypeStr);
2501226586Sdim  else
2502226586Sdim    s += GenBuiltin(name, proto, outTypeStr, classKind);
2503226586Sdim  if (define)
2504226586Sdim    s += " })";
2505226586Sdim  else
2506226586Sdim    s += " }";
2507226586Sdim  s += "\n";
2508226586Sdim  return s;
2509226586Sdim}
2510226586Sdim
2511226586Sdim/// run - Read the records in arm_neon.td and output arm_neon.h.  arm_neon.h
2512226586Sdim/// is comprised of type definitions and function declarations.
2513226586Sdimvoid NeonEmitter::run(raw_ostream &OS) {
2514226586Sdim  OS <<
2515226586Sdim    "/*===---- arm_neon.h - ARM Neon intrinsics ------------------------------"
2516226586Sdim    "---===\n"
2517226586Sdim    " *\n"
2518226586Sdim    " * Permission is hereby granted, free of charge, to any person obtaining "
2519226586Sdim    "a copy\n"
2520226586Sdim    " * of this software and associated documentation files (the \"Software\"),"
2521226586Sdim    " to deal\n"
2522226586Sdim    " * in the Software without restriction, including without limitation the "
2523226586Sdim    "rights\n"
2524226586Sdim    " * to use, copy, modify, merge, publish, distribute, sublicense, "
2525226586Sdim    "and/or sell\n"
2526226586Sdim    " * copies of the Software, and to permit persons to whom the Software is\n"
2527226586Sdim    " * furnished to do so, subject to the following conditions:\n"
2528226586Sdim    " *\n"
2529226586Sdim    " * The above copyright notice and this permission notice shall be "
2530226586Sdim    "included in\n"
2531226586Sdim    " * all copies or substantial portions of the Software.\n"
2532226586Sdim    " *\n"
2533226586Sdim    " * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, "
2534226586Sdim    "EXPRESS OR\n"
2535226586Sdim    " * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF "
2536226586Sdim    "MERCHANTABILITY,\n"
2537226586Sdim    " * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT "
2538226586Sdim    "SHALL THE\n"
2539226586Sdim    " * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR "
2540226586Sdim    "OTHER\n"
2541226586Sdim    " * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, "
2542226586Sdim    "ARISING FROM,\n"
2543226586Sdim    " * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER "
2544226586Sdim    "DEALINGS IN\n"
2545226586Sdim    " * THE SOFTWARE.\n"
2546226586Sdim    " *\n"
2547226586Sdim    " *===--------------------------------------------------------------------"
2548226586Sdim    "---===\n"
2549226586Sdim    " */\n\n";
2550226586Sdim
2551226586Sdim  OS << "#ifndef __ARM_NEON_H\n";
2552226586Sdim  OS << "#define __ARM_NEON_H\n\n";
2553226586Sdim
2554263509Sdim  OS << "#if !defined(__ARM_NEON__) && !defined(__ARM_NEON)\n";
2555226586Sdim  OS << "#error \"NEON support not enabled\"\n";
2556226586Sdim  OS << "#endif\n\n";
2557226586Sdim
2558226586Sdim  OS << "#include <stdint.h>\n\n";
2559226586Sdim
2560226586Sdim  // Emit NEON-specific scalar typedefs.
2561226586Sdim  OS << "typedef float float32_t;\n";
2562263509Sdim  OS << "typedef __fp16 float16_t;\n";
2563263509Sdim
2564263509Sdim  OS << "#ifdef __aarch64__\n";
2565263509Sdim  OS << "typedef double float64_t;\n";
2566263509Sdim  OS << "#endif\n\n";
2567263509Sdim
2568263509Sdim  // For now, signedness of polynomial types depends on target
2569263509Sdim  OS << "#ifdef __aarch64__\n";
2570263509Sdim  OS << "typedef uint8_t poly8_t;\n";
2571263509Sdim  OS << "typedef uint16_t poly16_t;\n";
2572263509Sdim  OS << "typedef uint64_t poly64_t;\n";
2573263509Sdim  OS << "#else\n";
2574226586Sdim  OS << "typedef int8_t poly8_t;\n";
2575226586Sdim  OS << "typedef int16_t poly16_t;\n";
2576263509Sdim  OS << "#endif\n";
2577226586Sdim
2578226586Sdim  // Emit Neon vector typedefs.
2579263509Sdim  std::string TypedefTypes(
2580263509Sdim      "cQcsQsiQilQlUcQUcUsQUsUiQUiUlQUlhQhfQfdQdPcQPcPsQPsPlQPl");
2581226586Sdim  SmallVector<StringRef, 24> TDTypeVec;
2582226586Sdim  ParseTypes(0, TypedefTypes, TDTypeVec);
2583226586Sdim
2584226586Sdim  // Emit vector typedefs.
2585263509Sdim  bool isA64 = false;
2586263509Sdim  bool preinsert;
2587263509Sdim  bool postinsert;
2588226586Sdim  for (unsigned i = 0, e = TDTypeVec.size(); i != e; ++i) {
2589226586Sdim    bool dummy, quad = false, poly = false;
2590263509Sdim    char type = ClassifyType(TDTypeVec[i], quad, poly, dummy);
2591263509Sdim    preinsert = false;
2592263509Sdim    postinsert = false;
2593263509Sdim
2594263509Sdim    if (type == 'd' || (type == 'l' && poly)) {
2595263509Sdim      preinsert = isA64? false: true;
2596263509Sdim      isA64 = true;
2597263509Sdim    } else {
2598263509Sdim      postinsert = isA64? true: false;
2599263509Sdim      isA64 = false;
2600263509Sdim    }
2601263509Sdim    if (postinsert)
2602263509Sdim      OS << "#endif\n";
2603263509Sdim    if (preinsert)
2604263509Sdim      OS << "#ifdef __aarch64__\n";
2605263509Sdim
2606226586Sdim    if (poly)
2607226586Sdim      OS << "typedef __attribute__((neon_polyvector_type(";
2608226586Sdim    else
2609226586Sdim      OS << "typedef __attribute__((neon_vector_type(";
2610226586Sdim
2611226586Sdim    unsigned nElts = GetNumElements(TDTypeVec[i], quad);
2612226586Sdim    OS << utostr(nElts) << "))) ";
2613226586Sdim    if (nElts < 10)
2614226586Sdim      OS << " ";
2615226586Sdim
2616226586Sdim    OS << TypeString('s', TDTypeVec[i]);
2617226586Sdim    OS << " " << TypeString('d', TDTypeVec[i]) << ";\n";
2618263509Sdim
2619226586Sdim  }
2620263509Sdim  postinsert = isA64? true: false;
2621263509Sdim  if (postinsert)
2622263509Sdim    OS << "#endif\n";
2623226586Sdim  OS << "\n";
2624226586Sdim
2625226586Sdim  // Emit struct typedefs.
2626263509Sdim  isA64 = false;
2627226586Sdim  for (unsigned vi = 2; vi != 5; ++vi) {
2628226586Sdim    for (unsigned i = 0, e = TDTypeVec.size(); i != e; ++i) {
2629263509Sdim      bool dummy, quad = false, poly = false;
2630263509Sdim      char type = ClassifyType(TDTypeVec[i], quad, poly, dummy);
2631263509Sdim      preinsert = false;
2632263509Sdim      postinsert = false;
2633263509Sdim
2634263509Sdim      if (type == 'd' || (type == 'l' && poly)) {
2635263509Sdim        preinsert = isA64? false: true;
2636263509Sdim        isA64 = true;
2637263509Sdim      } else {
2638263509Sdim        postinsert = isA64? true: false;
2639263509Sdim        isA64 = false;
2640263509Sdim      }
2641263509Sdim      if (postinsert)
2642263509Sdim        OS << "#endif\n";
2643263509Sdim      if (preinsert)
2644263509Sdim        OS << "#ifdef __aarch64__\n";
2645263509Sdim
2646226586Sdim      std::string ts = TypeString('d', TDTypeVec[i]);
2647226586Sdim      std::string vs = TypeString('0' + vi, TDTypeVec[i]);
2648226586Sdim      OS << "typedef struct " << vs << " {\n";
2649226586Sdim      OS << "  " << ts << " val";
2650226586Sdim      OS << "[" << utostr(vi) << "]";
2651226586Sdim      OS << ";\n} ";
2652263509Sdim      OS << vs << ";\n";
2653263509Sdim      OS << "\n";
2654226586Sdim    }
2655226586Sdim  }
2656263509Sdim  postinsert = isA64? true: false;
2657263509Sdim  if (postinsert)
2658263509Sdim    OS << "#endif\n";
2659263509Sdim  OS << "\n";
2660226586Sdim
2661252723Sdim  OS<<"#define __ai static inline __attribute__((__always_inline__, __nodebug__))\n\n";
2662226586Sdim
2663226586Sdim  std::vector<Record*> RV = Records.getAllDerivedDefinitions("Inst");
2664226586Sdim
2665263509Sdim  StringMap<ClassKind> EmittedMap;
2666263509Sdim
2667226586Sdim  // Emit vmovl, vmull and vabd intrinsics first so they can be used by other
2668226586Sdim  // intrinsics.  (Some of the saturating multiply instructions are also
2669226586Sdim  // used to implement the corresponding "_lane" variants, but tablegen
2670226586Sdim  // sorts the records into alphabetical order so that the "_lane" variants
2671226586Sdim  // come after the intrinsics they use.)
2672263509Sdim  emitIntrinsic(OS, Records.getDef("VMOVL"), EmittedMap);
2673263509Sdim  emitIntrinsic(OS, Records.getDef("VMULL"), EmittedMap);
2674263509Sdim  emitIntrinsic(OS, Records.getDef("VABD"), EmittedMap);
2675263509Sdim  emitIntrinsic(OS, Records.getDef("VABDL"), EmittedMap);
2676226586Sdim
2677263509Sdim  // ARM intrinsics must be emitted before AArch64 intrinsics to ensure
2678263509Sdim  // common intrinsics appear only once in the output stream.
2679263509Sdim  // The check for uniquiness is done in emitIntrinsic.
2680263509Sdim  // Emit ARM intrinsics.
2681226586Sdim  for (unsigned i = 0, e = RV.size(); i != e; ++i) {
2682226586Sdim    Record *R = RV[i];
2683263509Sdim
2684263509Sdim    // Skip AArch64 intrinsics; they will be emitted at the end.
2685263509Sdim    bool isA64 = R->getValueAsBit("isA64");
2686263509Sdim    if (isA64)
2687263509Sdim      continue;
2688263509Sdim
2689263509Sdim    if (R->getName() != "VMOVL" && R->getName() != "VMULL" &&
2690226586Sdim        R->getName() != "VABD")
2691263509Sdim      emitIntrinsic(OS, R, EmittedMap);
2692226586Sdim  }
2693226586Sdim
2694263509Sdim  // Emit AArch64-specific intrinsics.
2695263509Sdim  OS << "#ifdef __aarch64__\n";
2696263509Sdim
2697263509Sdim  emitIntrinsic(OS, Records.getDef("VMOVL_HIGH"), EmittedMap);
2698263509Sdim  emitIntrinsic(OS, Records.getDef("VMULL_HIGH"), EmittedMap);
2699263509Sdim  emitIntrinsic(OS, Records.getDef("VABDL_HIGH"), EmittedMap);
2700263509Sdim
2701263509Sdim  for (unsigned i = 0, e = RV.size(); i != e; ++i) {
2702263509Sdim    Record *R = RV[i];
2703263509Sdim
2704263509Sdim    // Skip ARM intrinsics already included above.
2705263509Sdim    bool isA64 = R->getValueAsBit("isA64");
2706263509Sdim    if (!isA64)
2707263509Sdim      continue;
2708263509Sdim
2709263509Sdim    // Skip crypto temporarily, and will emit them all together at the end.
2710263509Sdim    bool isCrypto = R->getValueAsBit("isCrypto");
2711263509Sdim    if (isCrypto)
2712263509Sdim      continue;
2713263509Sdim
2714263509Sdim    emitIntrinsic(OS, R, EmittedMap);
2715263509Sdim  }
2716263509Sdim
2717263509Sdim  OS << "#ifdef __ARM_FEATURE_CRYPTO\n";
2718263509Sdim
2719263509Sdim  for (unsigned i = 0, e = RV.size(); i != e; ++i) {
2720263509Sdim    Record *R = RV[i];
2721263509Sdim
2722263509Sdim    // Skip crypto temporarily, and will emit them all together at the end.
2723263509Sdim    bool isCrypto = R->getValueAsBit("isCrypto");
2724263509Sdim    if (!isCrypto)
2725263509Sdim      continue;
2726263509Sdim
2727263509Sdim    emitIntrinsic(OS, R, EmittedMap);
2728263509Sdim  }
2729263509Sdim
2730263509Sdim  OS << "#endif\n\n";
2731263509Sdim
2732263509Sdim  OS << "#endif\n\n";
2733263509Sdim
2734226586Sdim  OS << "#undef __ai\n\n";
2735226586Sdim  OS << "#endif /* __ARM_NEON_H */\n";
2736226586Sdim}
2737226586Sdim
2738226586Sdim/// emitIntrinsic - Write out the arm_neon.h header file definitions for the
2739263509Sdim/// intrinsics specified by record R checking for intrinsic uniqueness.
2740263509Sdimvoid NeonEmitter::emitIntrinsic(raw_ostream &OS, Record *R,
2741263509Sdim                                StringMap<ClassKind> &EmittedMap) {
2742226586Sdim  std::string name = R->getValueAsString("Name");
2743226586Sdim  std::string Proto = R->getValueAsString("Prototype");
2744226586Sdim  std::string Types = R->getValueAsString("Types");
2745226586Sdim
2746226586Sdim  SmallVector<StringRef, 16> TypeVec;
2747226586Sdim  ParseTypes(R, Types, TypeVec);
2748226586Sdim
2749226586Sdim  OpKind kind = OpMap[R->getValueAsDef("Operand")->getName()];
2750226586Sdim
2751226586Sdim  ClassKind classKind = ClassNone;
2752226586Sdim  if (R->getSuperClasses().size() >= 2)
2753226586Sdim    classKind = ClassMap[R->getSuperClasses()[1]];
2754226586Sdim  if (classKind == ClassNone && kind == OpNone)
2755245431Sdim    PrintFatalError(R->getLoc(), "Builtin has no class kind");
2756226586Sdim
2757226586Sdim  for (unsigned ti = 0, te = TypeVec.size(); ti != te; ++ti) {
2758226586Sdim    if (kind == OpReinterpret) {
2759226586Sdim      bool outQuad = false;
2760226586Sdim      bool dummy = false;
2761226586Sdim      (void)ClassifyType(TypeVec[ti], outQuad, dummy, dummy);
2762226586Sdim      for (unsigned srcti = 0, srcte = TypeVec.size();
2763226586Sdim           srcti != srcte; ++srcti) {
2764226586Sdim        bool inQuad = false;
2765226586Sdim        (void)ClassifyType(TypeVec[srcti], inQuad, dummy, dummy);
2766226586Sdim        if (srcti == ti || inQuad != outQuad)
2767226586Sdim          continue;
2768263509Sdim        std::string s = GenIntrinsic(name, Proto, TypeVec[ti], TypeVec[srcti],
2769263509Sdim                                     OpCast, ClassS);
2770263509Sdim        if (EmittedMap.count(s))
2771263509Sdim          continue;
2772263509Sdim        EmittedMap[s] = ClassS;
2773263509Sdim        OS << s;
2774226586Sdim      }
2775226586Sdim    } else {
2776263509Sdim      std::string s =
2777263509Sdim          GenIntrinsic(name, Proto, TypeVec[ti], TypeVec[ti], kind, classKind);
2778263509Sdim      if (EmittedMap.count(s))
2779263509Sdim        continue;
2780263509Sdim      EmittedMap[s] = classKind;
2781263509Sdim      OS << s;
2782226586Sdim    }
2783226586Sdim  }
2784226586Sdim  OS << "\n";
2785226586Sdim}
2786226586Sdim
2787226586Sdimstatic unsigned RangeFromType(const char mod, StringRef typestr) {
2788226586Sdim  // base type to get the type string for.
2789226586Sdim  bool quad = false, dummy = false;
2790226586Sdim  char type = ClassifyType(typestr, quad, dummy, dummy);
2791226586Sdim  type = ModType(mod, type, quad, dummy, dummy, dummy, dummy, dummy);
2792226586Sdim
2793226586Sdim  switch (type) {
2794226586Sdim    case 'c':
2795226586Sdim      return (8 << (int)quad) - 1;
2796226586Sdim    case 'h':
2797226586Sdim    case 's':
2798226586Sdim      return (4 << (int)quad) - 1;
2799226586Sdim    case 'f':
2800226586Sdim    case 'i':
2801226586Sdim      return (2 << (int)quad) - 1;
2802263509Sdim    case 'd':
2803226586Sdim    case 'l':
2804226586Sdim      return (1 << (int)quad) - 1;
2805226586Sdim    default:
2806245431Sdim      PrintFatalError("unhandled type!");
2807226586Sdim  }
2808226586Sdim}
2809226586Sdim
2810263509Sdimstatic unsigned RangeScalarShiftImm(const char mod, StringRef typestr) {
2811263509Sdim  // base type to get the type string for.
2812263509Sdim  bool dummy = false;
2813263509Sdim  char type = ClassifyType(typestr, dummy, dummy, dummy);
2814263509Sdim  type = ModType(mod, type, dummy, dummy, dummy, dummy, dummy, dummy);
2815226586Sdim
2816263509Sdim  switch (type) {
2817263509Sdim    case 'c':
2818263509Sdim      return 7;
2819263509Sdim    case 'h':
2820263509Sdim    case 's':
2821263509Sdim      return 15;
2822263509Sdim    case 'f':
2823263509Sdim    case 'i':
2824263509Sdim      return 31;
2825263509Sdim    case 'd':
2826263509Sdim    case 'l':
2827263509Sdim      return 63;
2828263509Sdim    default:
2829263509Sdim      PrintFatalError("unhandled type!");
2830263509Sdim  }
2831263509Sdim}
2832263509Sdim
2833263509Sdim/// Generate the ARM and AArch64 intrinsic range checking code for
2834263509Sdim/// shift/lane immediates, checking for unique declarations.
2835263509Sdimvoid
2836263509SdimNeonEmitter::genIntrinsicRangeCheckCode(raw_ostream &OS,
2837263509Sdim                                        StringMap<ClassKind> &A64IntrinsicMap,
2838263509Sdim                                        bool isA64RangeCheck) {
2839263509Sdim  std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst");
2840226586Sdim  StringMap<OpKind> EmittedMap;
2841226586Sdim
2842263509Sdim  // Generate the intrinsic range checking code for shift/lane immediates.
2843263509Sdim  if (isA64RangeCheck)
2844263509Sdim    OS << "#ifdef GET_NEON_AARCH64_IMMEDIATE_CHECK\n";
2845263509Sdim  else
2846263509Sdim    OS << "#ifdef GET_NEON_IMMEDIATE_CHECK\n";
2847263509Sdim
2848226586Sdim  for (unsigned i = 0, e = RV.size(); i != e; ++i) {
2849226586Sdim    Record *R = RV[i];
2850263509Sdim
2851226586Sdim    OpKind k = OpMap[R->getValueAsDef("Operand")->getName()];
2852226586Sdim    if (k != OpNone)
2853226586Sdim      continue;
2854226586Sdim
2855263509Sdim    std::string name = R->getValueAsString("Name");
2856226586Sdim    std::string Proto = R->getValueAsString("Prototype");
2857263509Sdim    std::string Types = R->getValueAsString("Types");
2858263509Sdim    std::string Rename = name + "@" + Proto;
2859226586Sdim
2860226586Sdim    // Functions with 'a' (the splat code) in the type prototype should not get
2861226586Sdim    // their own builtin as they use the non-splat variant.
2862226586Sdim    if (Proto.find('a') != std::string::npos)
2863226586Sdim      continue;
2864226586Sdim
2865263509Sdim    // Functions which do not have an immediate do not need to have range
2866263509Sdim    // checking code emitted.
2867263509Sdim    size_t immPos = Proto.find('i');
2868263509Sdim    if (immPos == std::string::npos)
2869263509Sdim      continue;
2870263509Sdim
2871226586Sdim    SmallVector<StringRef, 16> TypeVec;
2872226586Sdim    ParseTypes(R, Types, TypeVec);
2873226586Sdim
2874226586Sdim    if (R->getSuperClasses().size() < 2)
2875245431Sdim      PrintFatalError(R->getLoc(), "Builtin has no class kind");
2876226586Sdim
2877226586Sdim    ClassKind ck = ClassMap[R->getSuperClasses()[1]];
2878263509Sdim    if (!ProtoHasScalar(Proto))
2879263509Sdim      ck = ClassB;
2880226586Sdim
2881263509Sdim    // Do not include AArch64 range checks if not generating code for AArch64.
2882263509Sdim    bool isA64 = R->getValueAsBit("isA64");
2883263509Sdim    if (!isA64RangeCheck && isA64)
2884263509Sdim      continue;
2885263509Sdim
2886263509Sdim    // Include ARM range checks in AArch64 but only if ARM intrinsics are not
2887263509Sdim    // redefined by AArch64 to handle new types.
2888263509Sdim    if (isA64RangeCheck && !isA64 && A64IntrinsicMap.count(Rename)) {
2889263509Sdim      ClassKind &A64CK = A64IntrinsicMap[Rename];
2890263509Sdim      if (A64CK == ck && ck != ClassNone)
2891263509Sdim        continue;
2892263509Sdim    }
2893263509Sdim
2894226586Sdim    for (unsigned ti = 0, te = TypeVec.size(); ti != te; ++ti) {
2895263509Sdim      std::string namestr, shiftstr, rangestr;
2896263509Sdim
2897263509Sdim      if (R->getValueAsBit("isVCVT_N")) {
2898263509Sdim        // VCVT between floating- and fixed-point values takes an immediate
2899263509Sdim        // in the range [1, 32] for f32, or [1, 64] for f64.
2900263509Sdim        ck = ClassB;
2901263509Sdim        if (name.find("32") != std::string::npos)
2902263509Sdim          rangestr = "l = 1; u = 31"; // upper bound = l + u
2903263509Sdim        else if (name.find("64") != std::string::npos)
2904263509Sdim          rangestr = "l = 1; u = 63";
2905263509Sdim        else
2906263509Sdim          PrintFatalError(R->getLoc(),
2907263509Sdim              "Fixed point convert name should contains \"32\" or \"64\"");
2908263509Sdim
2909263509Sdim      } else if (R->getValueAsBit("isScalarShift")) {
2910263509Sdim        // Right shifts have an 'r' in the name, left shifts do not.  Convert
2911263509Sdim        // instructions have the same bounds and right shifts.
2912263509Sdim        if (name.find('r') != std::string::npos ||
2913263509Sdim            name.find("cvt") != std::string::npos)
2914263509Sdim          rangestr = "l = 1; ";
2915263509Sdim
2916263509Sdim        unsigned upBound = RangeScalarShiftImm(Proto[immPos - 1], TypeVec[ti]);
2917263509Sdim        // Narrow shift has half the upper bound
2918263509Sdim        if (R->getValueAsBit("isScalarNarrowShift"))
2919263509Sdim          upBound /= 2;
2920263509Sdim
2921263509Sdim        rangestr += "u = " + utostr(upBound);
2922263509Sdim      } else if (R->getValueAsBit("isShift")) {
2923263509Sdim        // Builtins which are overloaded by type will need to have their upper
2924263509Sdim        // bound computed at Sema time based on the type constant.
2925263509Sdim        shiftstr = ", true";
2926263509Sdim
2927263509Sdim        // Right shifts have an 'r' in the name, left shifts do not.
2928263509Sdim        if (name.find('r') != std::string::npos)
2929263509Sdim          rangestr = "l = 1; ";
2930263509Sdim
2931263509Sdim        rangestr += "u = RFT(TV" + shiftstr + ")";
2932263509Sdim      } else {
2933263509Sdim        // The immediate generally refers to a lane in the preceding argument.
2934263509Sdim        assert(immPos > 0 && "unexpected immediate operand");
2935263509Sdim        rangestr =
2936263509Sdim            "u = " + utostr(RangeFromType(Proto[immPos - 1], TypeVec[ti]));
2937263509Sdim      }
2938263509Sdim      // Make sure cases appear only once by uniquing them in a string map.
2939263509Sdim      namestr = MangleName(name, TypeVec[ti], ck);
2940263509Sdim      if (EmittedMap.count(namestr))
2941226586Sdim        continue;
2942263509Sdim      EmittedMap[namestr] = OpNone;
2943226586Sdim
2944263509Sdim      // Calculate the index of the immediate that should be range checked.
2945263509Sdim      unsigned immidx = 0;
2946263509Sdim
2947263509Sdim      // Builtins that return a struct of multiple vectors have an extra
2948263509Sdim      // leading arg for the struct return.
2949263509Sdim      if (IsMultiVecProto(Proto[0]))
2950263509Sdim        ++immidx;
2951263509Sdim
2952263509Sdim      // Add one to the index for each argument until we reach the immediate
2953263509Sdim      // to be checked.  Structs of vectors are passed as multiple arguments.
2954263509Sdim      for (unsigned ii = 1, ie = Proto.size(); ii != ie; ++ii) {
2955263509Sdim        switch (Proto[ii]) {
2956263509Sdim        default:
2957263509Sdim          immidx += 1;
2958263509Sdim          break;
2959263509Sdim        case '2':
2960263509Sdim        case 'B':
2961263509Sdim          immidx += 2;
2962263509Sdim          break;
2963263509Sdim        case '3':
2964263509Sdim        case 'C':
2965263509Sdim          immidx += 3;
2966263509Sdim          break;
2967263509Sdim        case '4':
2968263509Sdim        case 'D':
2969263509Sdim          immidx += 4;
2970263509Sdim          break;
2971263509Sdim        case 'i':
2972263509Sdim          ie = ii + 1;
2973263509Sdim          break;
2974263509Sdim        }
2975263509Sdim      }
2976263509Sdim      if (isA64RangeCheck)
2977263509Sdim        OS << "case AArch64::BI__builtin_neon_";
2978263509Sdim      else
2979263509Sdim        OS << "case ARM::BI__builtin_neon_";
2980263509Sdim      OS << MangleName(name, TypeVec[ti], ck) << ": i = " << immidx << "; "
2981263509Sdim         << rangestr << "; break;\n";
2982226586Sdim    }
2983226586Sdim  }
2984226586Sdim  OS << "#endif\n\n";
2985263509Sdim}
2986226586Sdim
2987263509Sdim/// Generate the ARM and AArch64 overloaded type checking code for
2988263509Sdim/// SemaChecking.cpp, checking for unique builtin declarations.
2989263509Sdimvoid
2990263509SdimNeonEmitter::genOverloadTypeCheckCode(raw_ostream &OS,
2991263509Sdim                                      StringMap<ClassKind> &A64IntrinsicMap,
2992263509Sdim                                      bool isA64TypeCheck) {
2993263509Sdim  std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst");
2994263509Sdim  StringMap<OpKind> EmittedMap;
2995263509Sdim
2996226586Sdim  // Generate the overloaded type checking code for SemaChecking.cpp
2997263509Sdim  if (isA64TypeCheck)
2998263509Sdim    OS << "#ifdef GET_NEON_AARCH64_OVERLOAD_CHECK\n";
2999263509Sdim  else
3000263509Sdim    OS << "#ifdef GET_NEON_OVERLOAD_CHECK\n";
3001263509Sdim
3002226586Sdim  for (unsigned i = 0, e = RV.size(); i != e; ++i) {
3003226586Sdim    Record *R = RV[i];
3004226586Sdim    OpKind k = OpMap[R->getValueAsDef("Operand")->getName()];
3005226586Sdim    if (k != OpNone)
3006226586Sdim      continue;
3007226586Sdim
3008226586Sdim    std::string Proto = R->getValueAsString("Prototype");
3009226586Sdim    std::string Types = R->getValueAsString("Types");
3010226586Sdim    std::string name = R->getValueAsString("Name");
3011263509Sdim    std::string Rename = name + "@" + Proto;
3012263509Sdim
3013226586Sdim    // Functions with 'a' (the splat code) in the type prototype should not get
3014226586Sdim    // their own builtin as they use the non-splat variant.
3015226586Sdim    if (Proto.find('a') != std::string::npos)
3016226586Sdim      continue;
3017226586Sdim
3018226586Sdim    // Functions which have a scalar argument cannot be overloaded, no need to
3019226586Sdim    // check them if we are emitting the type checking code.
3020263509Sdim    if (ProtoHasScalar(Proto))
3021226586Sdim      continue;
3022226586Sdim
3023226586Sdim    SmallVector<StringRef, 16> TypeVec;
3024226586Sdim    ParseTypes(R, Types, TypeVec);
3025226586Sdim
3026226586Sdim    if (R->getSuperClasses().size() < 2)
3027245431Sdim      PrintFatalError(R->getLoc(), "Builtin has no class kind");
3028226586Sdim
3029263509Sdim    // Do not include AArch64 type checks if not generating code for AArch64.
3030263509Sdim    bool isA64 = R->getValueAsBit("isA64");
3031263509Sdim    if (!isA64TypeCheck && isA64)
3032263509Sdim      continue;
3033263509Sdim
3034263509Sdim    // Include ARM  type check in AArch64 but only if ARM intrinsics
3035263509Sdim    // are not redefined in AArch64 to handle new types, e.g. "vabd" is a SIntr
3036263509Sdim    // redefined in AArch64 to handle an additional 2 x f64 type.
3037263509Sdim    ClassKind ck = ClassMap[R->getSuperClasses()[1]];
3038263509Sdim    if (isA64TypeCheck && !isA64 && A64IntrinsicMap.count(Rename)) {
3039263509Sdim      ClassKind &A64CK = A64IntrinsicMap[Rename];
3040263509Sdim      if (A64CK == ck && ck != ClassNone)
3041263509Sdim        continue;
3042263509Sdim    }
3043263509Sdim
3044226586Sdim    int si = -1, qi = -1;
3045245431Sdim    uint64_t mask = 0, qmask = 0;
3046226586Sdim    for (unsigned ti = 0, te = TypeVec.size(); ti != te; ++ti) {
3047226586Sdim      // Generate the switch case(s) for this builtin for the type validation.
3048226586Sdim      bool quad = false, poly = false, usgn = false;
3049226586Sdim      (void) ClassifyType(TypeVec[ti], quad, poly, usgn);
3050226586Sdim
3051226586Sdim      if (quad) {
3052226586Sdim        qi = ti;
3053245431Sdim        qmask |= 1ULL << GetNeonEnum(Proto, TypeVec[ti]);
3054226586Sdim      } else {
3055226586Sdim        si = ti;
3056245431Sdim        mask |= 1ULL << GetNeonEnum(Proto, TypeVec[ti]);
3057226586Sdim      }
3058226586Sdim    }
3059235633Sdim
3060235633Sdim    // Check if the builtin function has a pointer or const pointer argument.
3061235633Sdim    int PtrArgNum = -1;
3062235633Sdim    bool HasConstPtr = false;
3063235633Sdim    for (unsigned arg = 1, arge = Proto.size(); arg != arge; ++arg) {
3064235633Sdim      char ArgType = Proto[arg];
3065235633Sdim      if (ArgType == 'c') {
3066235633Sdim        HasConstPtr = true;
3067235633Sdim        PtrArgNum = arg - 1;
3068235633Sdim        break;
3069235633Sdim      }
3070235633Sdim      if (ArgType == 'p') {
3071235633Sdim        PtrArgNum = arg - 1;
3072235633Sdim        break;
3073235633Sdim      }
3074235633Sdim    }
3075235633Sdim    // For sret builtins, adjust the pointer argument index.
3076263509Sdim    if (PtrArgNum >= 0 && IsMultiVecProto(Proto[0]))
3077235633Sdim      PtrArgNum += 1;
3078235633Sdim
3079235633Sdim    // Omit type checking for the pointer arguments of vld1_lane, vld1_dup,
3080235633Sdim    // and vst1_lane intrinsics.  Using a pointer to the vector element
3081235633Sdim    // type with one of those operations causes codegen to select an aligned
3082235633Sdim    // load/store instruction.  If you want an unaligned operation,
3083235633Sdim    // the pointer argument needs to have less alignment than element type,
3084235633Sdim    // so just accept any pointer type.
3085235633Sdim    if (name == "vld1_lane" || name == "vld1_dup" || name == "vst1_lane") {
3086235633Sdim      PtrArgNum = -1;
3087235633Sdim      HasConstPtr = false;
3088235633Sdim    }
3089235633Sdim
3090235633Sdim    if (mask) {
3091263509Sdim      if (isA64TypeCheck)
3092263509Sdim        OS << "case AArch64::BI__builtin_neon_";
3093263509Sdim      else
3094263509Sdim        OS << "case ARM::BI__builtin_neon_";
3095263509Sdim      OS << MangleName(name, TypeVec[si], ClassB) << ": mask = "
3096263509Sdim         << "0x" << utohexstr(mask) << "ULL";
3097235633Sdim      if (PtrArgNum >= 0)
3098235633Sdim        OS << "; PtrArgNum = " << PtrArgNum;
3099235633Sdim      if (HasConstPtr)
3100235633Sdim        OS << "; HasConstPtr = true";
3101235633Sdim      OS << "; break;\n";
3102235633Sdim    }
3103235633Sdim    if (qmask) {
3104263509Sdim      if (isA64TypeCheck)
3105263509Sdim        OS << "case AArch64::BI__builtin_neon_";
3106263509Sdim      else
3107263509Sdim        OS << "case ARM::BI__builtin_neon_";
3108263509Sdim      OS << MangleName(name, TypeVec[qi], ClassB) << ": mask = "
3109263509Sdim         << "0x" << utohexstr(qmask) << "ULL";
3110235633Sdim      if (PtrArgNum >= 0)
3111235633Sdim        OS << "; PtrArgNum = " << PtrArgNum;
3112235633Sdim      if (HasConstPtr)
3113235633Sdim        OS << "; HasConstPtr = true";
3114235633Sdim      OS << "; break;\n";
3115235633Sdim    }
3116226586Sdim  }
3117226586Sdim  OS << "#endif\n\n";
3118263509Sdim}
3119226586Sdim
3120263509Sdim/// genBuiltinsDef: Generate the BuiltinsARM.def and  BuiltinsAArch64.def
3121263509Sdim/// declaration of builtins, checking for unique builtin declarations.
3122263509Sdimvoid NeonEmitter::genBuiltinsDef(raw_ostream &OS,
3123263509Sdim                                 StringMap<ClassKind> &A64IntrinsicMap,
3124263509Sdim                                 bool isA64GenBuiltinDef) {
3125263509Sdim  std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst");
3126263509Sdim  StringMap<OpKind> EmittedMap;
3127263509Sdim
3128263509Sdim  // Generate BuiltinsARM.def and BuiltinsAArch64.def
3129263509Sdim  if (isA64GenBuiltinDef)
3130263509Sdim    OS << "#ifdef GET_NEON_AARCH64_BUILTINS\n";
3131263509Sdim  else
3132263509Sdim    OS << "#ifdef GET_NEON_BUILTINS\n";
3133263509Sdim
3134226586Sdim  for (unsigned i = 0, e = RV.size(); i != e; ++i) {
3135226586Sdim    Record *R = RV[i];
3136226586Sdim    OpKind k = OpMap[R->getValueAsDef("Operand")->getName()];
3137226586Sdim    if (k != OpNone)
3138226586Sdim      continue;
3139226586Sdim
3140263509Sdim    std::string Proto = R->getValueAsString("Prototype");
3141226586Sdim    std::string name = R->getValueAsString("Name");
3142263509Sdim    std::string Rename = name + "@" + Proto;
3143226586Sdim
3144226586Sdim    // Functions with 'a' (the splat code) in the type prototype should not get
3145226586Sdim    // their own builtin as they use the non-splat variant.
3146226586Sdim    if (Proto.find('a') != std::string::npos)
3147226586Sdim      continue;
3148226586Sdim
3149263509Sdim    std::string Types = R->getValueAsString("Types");
3150226586Sdim    SmallVector<StringRef, 16> TypeVec;
3151226586Sdim    ParseTypes(R, Types, TypeVec);
3152226586Sdim
3153226586Sdim    if (R->getSuperClasses().size() < 2)
3154245431Sdim      PrintFatalError(R->getLoc(), "Builtin has no class kind");
3155226586Sdim
3156226586Sdim    ClassKind ck = ClassMap[R->getSuperClasses()[1]];
3157226586Sdim
3158263509Sdim    // Do not include AArch64 BUILTIN() macros if not generating
3159263509Sdim    // code for AArch64
3160263509Sdim    bool isA64 = R->getValueAsBit("isA64");
3161263509Sdim    if (!isA64GenBuiltinDef && isA64)
3162263509Sdim      continue;
3163226586Sdim
3164263509Sdim    // Include ARM  BUILTIN() macros  in AArch64 but only if ARM intrinsics
3165263509Sdim    // are not redefined in AArch64 to handle new types, e.g. "vabd" is a SIntr
3166263509Sdim    // redefined in AArch64 to handle an additional 2 x f64 type.
3167263509Sdim    if (isA64GenBuiltinDef && !isA64 && A64IntrinsicMap.count(Rename)) {
3168263509Sdim      ClassKind &A64CK = A64IntrinsicMap[Rename];
3169263509Sdim      if (A64CK == ck && ck != ClassNone)
3170263509Sdim        continue;
3171263509Sdim    }
3172226586Sdim
3173263509Sdim    for (unsigned ti = 0, te = TypeVec.size(); ti != te; ++ti) {
3174263509Sdim      // Generate the declaration for this builtin, ensuring
3175263509Sdim      // that each unique BUILTIN() macro appears only once in the output
3176263509Sdim      // stream.
3177263509Sdim      std::string bd = GenBuiltinDef(name, Proto, TypeVec[ti], ck);
3178263509Sdim      if (EmittedMap.count(bd))
3179226586Sdim        continue;
3180226586Sdim
3181263509Sdim      EmittedMap[bd] = OpNone;
3182263509Sdim      OS << bd << "\n";
3183226586Sdim    }
3184226586Sdim  }
3185226586Sdim  OS << "#endif\n\n";
3186226586Sdim}
3187226586Sdim
3188263509Sdim/// runHeader - Emit a file with sections defining:
3189263509Sdim/// 1. the NEON section of BuiltinsARM.def and BuiltinsAArch64.def.
3190263509Sdim/// 2. the SemaChecking code for the type overload checking.
3191263509Sdim/// 3. the SemaChecking code for validation of intrinsic immediate arguments.
3192263509Sdimvoid NeonEmitter::runHeader(raw_ostream &OS) {
3193263509Sdim  std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst");
3194263509Sdim
3195263509Sdim  // build a map of AArch64 intriniscs to be used in uniqueness checks.
3196263509Sdim  StringMap<ClassKind> A64IntrinsicMap;
3197263509Sdim  for (unsigned i = 0, e = RV.size(); i != e; ++i) {
3198263509Sdim    Record *R = RV[i];
3199263509Sdim
3200263509Sdim    bool isA64 = R->getValueAsBit("isA64");
3201263509Sdim    if (!isA64)
3202263509Sdim      continue;
3203263509Sdim
3204263509Sdim    ClassKind CK = ClassNone;
3205263509Sdim    if (R->getSuperClasses().size() >= 2)
3206263509Sdim      CK = ClassMap[R->getSuperClasses()[1]];
3207263509Sdim
3208263509Sdim    std::string Name = R->getValueAsString("Name");
3209263509Sdim    std::string Proto = R->getValueAsString("Prototype");
3210263509Sdim    std::string Rename = Name + "@" + Proto;
3211263509Sdim    if (A64IntrinsicMap.count(Rename))
3212263509Sdim      continue;
3213263509Sdim    A64IntrinsicMap[Rename] = CK;
3214263509Sdim  }
3215263509Sdim
3216263509Sdim  // Generate BuiltinsARM.def for ARM
3217263509Sdim  genBuiltinsDef(OS, A64IntrinsicMap, false);
3218263509Sdim
3219263509Sdim  // Generate BuiltinsAArch64.def for AArch64
3220263509Sdim  genBuiltinsDef(OS, A64IntrinsicMap, true);
3221263509Sdim
3222263509Sdim  // Generate ARM overloaded type checking code for SemaChecking.cpp
3223263509Sdim  genOverloadTypeCheckCode(OS, A64IntrinsicMap, false);
3224263509Sdim
3225263509Sdim  // Generate AArch64 overloaded type checking code for SemaChecking.cpp
3226263509Sdim  genOverloadTypeCheckCode(OS, A64IntrinsicMap, true);
3227263509Sdim
3228263509Sdim  // Generate ARM range checking code for shift/lane immediates.
3229263509Sdim  genIntrinsicRangeCheckCode(OS, A64IntrinsicMap, false);
3230263509Sdim
3231263509Sdim  // Generate the AArch64 range checking code for shift/lane immediates.
3232263509Sdim  genIntrinsicRangeCheckCode(OS, A64IntrinsicMap, true);
3233263509Sdim}
3234263509Sdim
3235226586Sdim/// GenTest - Write out a test for the intrinsic specified by the name and
3236226586Sdim/// type strings, including the embedded patterns for FileCheck to match.
3237226586Sdimstatic std::string GenTest(const std::string &name,
3238226586Sdim                           const std::string &proto,
3239226586Sdim                           StringRef outTypeStr, StringRef inTypeStr,
3240252723Sdim                           bool isShift, bool isHiddenLOp,
3241263509Sdim                           ClassKind ck, const std::string &InstName,
3242263509Sdim                           bool isA64,
3243263509Sdim                           std::string & testFuncProto) {
3244226586Sdim  assert(!proto.empty() && "");
3245226586Sdim  std::string s;
3246226586Sdim
3247226586Sdim  // Function name with type suffix
3248226586Sdim  std::string mangledName = MangleName(name, outTypeStr, ClassS);
3249226586Sdim  if (outTypeStr != inTypeStr) {
3250226586Sdim    // If the input type is different (e.g., for vreinterpret), append a suffix
3251226586Sdim    // for the input type.  String off a "Q" (quad) prefix so that MangleName
3252226586Sdim    // does not insert another "q" in the name.
3253226586Sdim    unsigned typeStrOff = (inTypeStr[0] == 'Q' ? 1 : 0);
3254226586Sdim    StringRef inTypeNoQuad = inTypeStr.substr(typeStrOff);
3255226586Sdim    mangledName = MangleName(mangledName, inTypeNoQuad, ClassS);
3256226586Sdim  }
3257226586Sdim
3258263509Sdim  // todo: GenerateChecksForIntrinsic does not generate CHECK
3259263509Sdim  // for aarch64 instructions yet
3260252723Sdim  std::vector<std::string> FileCheckPatterns;
3261263509Sdim  if (!isA64) {
3262263509Sdim	GenerateChecksForIntrinsic(name, proto, outTypeStr, inTypeStr, ck, InstName,
3263263509Sdim							   isHiddenLOp, FileCheckPatterns);
3264263509Sdim	s+= "// CHECK_ARM: test_" + mangledName + "\n";
3265263509Sdim  }
3266263509Sdim  s += "// CHECK_AARCH64: test_" + mangledName + "\n";
3267252723Sdim
3268226586Sdim  // Emit the FileCheck patterns.
3269252723Sdim  // If for any reason we do not want to emit a check, mangledInst
3270252723Sdim  // will be the empty string.
3271252723Sdim  if (FileCheckPatterns.size()) {
3272252723Sdim    for (std::vector<std::string>::const_iterator i = FileCheckPatterns.begin(),
3273252723Sdim                                                  e = FileCheckPatterns.end();
3274252723Sdim         i != e;
3275252723Sdim         ++i) {
3276263509Sdim      s += "// CHECK_ARM: " + *i + "\n";
3277252723Sdim    }
3278252723Sdim  }
3279226586Sdim
3280226586Sdim  // Emit the start of the test function.
3281263509Sdim
3282263509Sdim  testFuncProto = TypeString(proto[0], outTypeStr) + " test_" + mangledName + "(";
3283226586Sdim  char arg = 'a';
3284226586Sdim  std::string comma;
3285226586Sdim  for (unsigned i = 1, e = proto.size(); i != e; ++i, ++arg) {
3286226586Sdim    // Do not create arguments for values that must be immediate constants.
3287226586Sdim    if (proto[i] == 'i')
3288226586Sdim      continue;
3289263509Sdim    testFuncProto += comma + TypeString(proto[i], inTypeStr) + " ";
3290263509Sdim    testFuncProto.push_back(arg);
3291226586Sdim    comma = ", ";
3292226586Sdim  }
3293263509Sdim  testFuncProto += ")";
3294226586Sdim
3295263509Sdim  s+= testFuncProto;
3296263509Sdim  s+= " {\n  ";
3297263509Sdim
3298226586Sdim  if (proto[0] != 'v')
3299226586Sdim    s += "return ";
3300226586Sdim  s += mangledName + "(";
3301226586Sdim  arg = 'a';
3302226586Sdim  for (unsigned i = 1, e = proto.size(); i != e; ++i, ++arg) {
3303226586Sdim    if (proto[i] == 'i') {
3304226586Sdim      // For immediate operands, test the maximum value.
3305226586Sdim      if (isShift)
3306226586Sdim        s += "1"; // FIXME
3307226586Sdim      else
3308226586Sdim        // The immediate generally refers to a lane in the preceding argument.
3309226586Sdim        s += utostr(RangeFromType(proto[i-1], inTypeStr));
3310226586Sdim    } else {
3311226586Sdim      s.push_back(arg);
3312226586Sdim    }
3313226586Sdim    if ((i + 1) < e)
3314226586Sdim      s += ", ";
3315226586Sdim  }
3316226586Sdim  s += ");\n}\n\n";
3317226586Sdim  return s;
3318226586Sdim}
3319226586Sdim
3320263509Sdim/// Write out all intrinsic tests for the specified target, checking
3321263509Sdim/// for intrinsic test uniqueness.
3322263509Sdimvoid NeonEmitter::genTargetTest(raw_ostream &OS, StringMap<OpKind> &EmittedMap,
3323263509Sdim                                bool isA64GenTest) {
3324263509Sdim  if (isA64GenTest)
3325263509Sdim	OS << "#ifdef __aarch64__\n";
3326226586Sdim
3327263509Sdim  std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst");
3328226586Sdim  for (unsigned i = 0, e = RV.size(); i != e; ++i) {
3329226586Sdim    Record *R = RV[i];
3330226586Sdim    std::string name = R->getValueAsString("Name");
3331226586Sdim    std::string Proto = R->getValueAsString("Prototype");
3332226586Sdim    std::string Types = R->getValueAsString("Types");
3333226586Sdim    bool isShift = R->getValueAsBit("isShift");
3334252723Sdim    std::string InstName = R->getValueAsString("InstName");
3335252723Sdim    bool isHiddenLOp = R->getValueAsBit("isHiddenLInst");
3336263509Sdim    bool isA64 = R->getValueAsBit("isA64");
3337226586Sdim
3338263509Sdim    // do not include AArch64 intrinsic test if not generating
3339263509Sdim    // code for AArch64
3340263509Sdim    if (!isA64GenTest && isA64)
3341263509Sdim      continue;
3342263509Sdim
3343226586Sdim    SmallVector<StringRef, 16> TypeVec;
3344226586Sdim    ParseTypes(R, Types, TypeVec);
3345226586Sdim
3346252723Sdim    ClassKind ck = ClassMap[R->getSuperClasses()[1]];
3347226586Sdim    OpKind kind = OpMap[R->getValueAsDef("Operand")->getName()];
3348245431Sdim    if (kind == OpUnavailable)
3349245431Sdim      continue;
3350226586Sdim    for (unsigned ti = 0, te = TypeVec.size(); ti != te; ++ti) {
3351226586Sdim      if (kind == OpReinterpret) {
3352226586Sdim        bool outQuad = false;
3353226586Sdim        bool dummy = false;
3354226586Sdim        (void)ClassifyType(TypeVec[ti], outQuad, dummy, dummy);
3355226586Sdim        for (unsigned srcti = 0, srcte = TypeVec.size();
3356226586Sdim             srcti != srcte; ++srcti) {
3357226586Sdim          bool inQuad = false;
3358226586Sdim          (void)ClassifyType(TypeVec[srcti], inQuad, dummy, dummy);
3359226586Sdim          if (srcti == ti || inQuad != outQuad)
3360226586Sdim            continue;
3361263509Sdim		  std::string testFuncProto;
3362263509Sdim          std::string s = GenTest(name, Proto, TypeVec[ti], TypeVec[srcti],
3363263509Sdim                                  isShift, isHiddenLOp, ck, InstName, isA64,
3364263509Sdim								  testFuncProto);
3365263509Sdim          if (EmittedMap.count(testFuncProto))
3366263509Sdim            continue;
3367263509Sdim          EmittedMap[testFuncProto] = kind;
3368263509Sdim          OS << s << "\n";
3369226586Sdim        }
3370226586Sdim      } else {
3371263509Sdim		std::string testFuncProto;
3372263509Sdim        std::string s = GenTest(name, Proto, TypeVec[ti], TypeVec[ti], isShift,
3373263509Sdim                                isHiddenLOp, ck, InstName, isA64, testFuncProto);
3374263509Sdim        if (EmittedMap.count(testFuncProto))
3375263509Sdim          continue;
3376263509Sdim        EmittedMap[testFuncProto] = kind;
3377263509Sdim        OS << s << "\n";
3378226586Sdim      }
3379226586Sdim    }
3380226586Sdim  }
3381263509Sdim
3382263509Sdim  if (isA64GenTest)
3383263509Sdim	OS << "#endif\n";
3384226586Sdim}
3385263509Sdim/// runTests - Write out a complete set of tests for all of the Neon
3386263509Sdim/// intrinsics.
3387263509Sdimvoid NeonEmitter::runTests(raw_ostream &OS) {
3388263509Sdim  OS << "// RUN: %clang_cc1 -triple thumbv7s-apple-darwin -target-abi "
3389263509Sdim        "apcs-gnu\\\n"
3390263509Sdim        "// RUN:  -target-cpu swift -ffreestanding -Os -S -o - %s\\\n"
3391263509Sdim        "// RUN:  | FileCheck %s -check-prefix=CHECK_ARM\n"
3392263509Sdim		"\n"
3393263509Sdim	    "// RUN: %clang_cc1 -triple aarch64-none-linux-gnu \\\n"
3394263509Sdim	    "// RUN -target-feature +neon  -ffreestanding -S -o - %s \\\n"
3395263509Sdim	    "// RUN:  | FileCheck %s -check-prefix=CHECK_AARCH64\n"
3396263509Sdim        "\n"
3397263509Sdim        "// REQUIRES: long_tests\n"
3398263509Sdim        "\n"
3399263509Sdim        "#include <arm_neon.h>\n"
3400263509Sdim        "\n";
3401226586Sdim
3402263509Sdim  // ARM tests must be emitted before AArch64 tests to ensure
3403263509Sdim  // tests for intrinsics that are common to ARM and AArch64
3404263509Sdim  // appear only once in the output stream.
3405263509Sdim  // The check for uniqueness is done in genTargetTest.
3406263509Sdim  StringMap<OpKind> EmittedMap;
3407263509Sdim
3408263509Sdim  genTargetTest(OS, EmittedMap, false);
3409263509Sdim
3410263509Sdim  genTargetTest(OS, EmittedMap, true);
3411263509Sdim}
3412263509Sdim
3413245431Sdimnamespace clang {
3414245431Sdimvoid EmitNeon(RecordKeeper &Records, raw_ostream &OS) {
3415245431Sdim  NeonEmitter(Records).run(OS);
3416245431Sdim}
3417245431Sdimvoid EmitNeonSema(RecordKeeper &Records, raw_ostream &OS) {
3418245431Sdim  NeonEmitter(Records).runHeader(OS);
3419245431Sdim}
3420245431Sdimvoid EmitNeonTest(RecordKeeper &Records, raw_ostream &OS) {
3421245431Sdim  NeonEmitter(Records).runTests(OS);
3422245431Sdim}
3423245431Sdim} // End namespace clang
3424