1226586Sdim//===- NeonEmitter.cpp - Generate arm_neon.h for use with clang -*- C++ -*-===//
2226586Sdim//
3226586Sdim//                     The LLVM Compiler Infrastructure
4226586Sdim//
5226586Sdim// This file is distributed under the University of Illinois Open Source
6226586Sdim// License. See LICENSE.TXT for details.
7226586Sdim//
8226586Sdim//===----------------------------------------------------------------------===//
9226586Sdim//
10226586Sdim// This tablegen backend is responsible for emitting arm_neon.h, which includes
11226586Sdim// a declaration and definition of each function specified by the ARM NEON
12226586Sdim// compiler interface.  See ARM document DUI0348B.
13226586Sdim//
14226586Sdim// Each NEON instruction is implemented in terms of 1 or more functions which
15226586Sdim// are suffixed with the element type of the input vectors.  Functions may be
16226586Sdim// implemented in terms of generic vector operations such as +, *, -, etc. or
17226586Sdim// by calling a __builtin_-prefixed function which will be handled by clang's
18226586Sdim// CodeGen library.
19226586Sdim//
20226586Sdim// Additional validation code can be generated by this file when runHeader() is
21226586Sdim// called, rather than the normal run() entry point.  A complete set of tests
22226586Sdim// for Neon intrinsics can be generated by calling the runTests() entry point.
23226586Sdim//
24226586Sdim//===----------------------------------------------------------------------===//
25226586Sdim
26239462Sdim#include "llvm/ADT/DenseMap.h"
27226586Sdim#include "llvm/ADT/SmallString.h"
28226586Sdim#include "llvm/ADT/SmallVector.h"
29226586Sdim#include "llvm/ADT/StringExtras.h"
30239462Sdim#include "llvm/ADT/StringMap.h"
31234353Sdim#include "llvm/Support/ErrorHandling.h"
32239462Sdim#include "llvm/TableGen/Error.h"
33239462Sdim#include "llvm/TableGen/Record.h"
34239462Sdim#include "llvm/TableGen/TableGenBackend.h"
35226586Sdim#include <string>
36226586Sdimusing namespace llvm;
37226586Sdim
38239462Sdimenum OpKind {
39239462Sdim  OpNone,
40239462Sdim  OpUnavailable,
41239462Sdim  OpAdd,
42239462Sdim  OpAddl,
43263508Sdim  OpAddlHi,
44239462Sdim  OpAddw,
45263508Sdim  OpAddwHi,
46239462Sdim  OpSub,
47239462Sdim  OpSubl,
48263508Sdim  OpSublHi,
49239462Sdim  OpSubw,
50263508Sdim  OpSubwHi,
51239462Sdim  OpMul,
52239462Sdim  OpMla,
53239462Sdim  OpMlal,
54263508Sdim  OpMullHi,
55263508Sdim  OpMullHiN,
56263508Sdim  OpMlalHi,
57263508Sdim  OpMlalHiN,
58239462Sdim  OpMls,
59239462Sdim  OpMlsl,
60263508Sdim  OpMlslHi,
61263508Sdim  OpMlslHiN,
62239462Sdim  OpMulN,
63239462Sdim  OpMlaN,
64239462Sdim  OpMlsN,
65263508Sdim  OpFMlaN,
66263508Sdim  OpFMlsN,
67239462Sdim  OpMlalN,
68239462Sdim  OpMlslN,
69239462Sdim  OpMulLane,
70263508Sdim  OpMulXLane,
71239462Sdim  OpMullLane,
72263508Sdim  OpMullHiLane,
73239462Sdim  OpMlaLane,
74239462Sdim  OpMlsLane,
75239462Sdim  OpMlalLane,
76263508Sdim  OpMlalHiLane,
77239462Sdim  OpMlslLane,
78263508Sdim  OpMlslHiLane,
79239462Sdim  OpQDMullLane,
80263508Sdim  OpQDMullHiLane,
81239462Sdim  OpQDMlalLane,
82263508Sdim  OpQDMlalHiLane,
83239462Sdim  OpQDMlslLane,
84263508Sdim  OpQDMlslHiLane,
85239462Sdim  OpQDMulhLane,
86239462Sdim  OpQRDMulhLane,
87263508Sdim  OpFMSLane,
88263508Sdim  OpFMSLaneQ,
89263508Sdim  OpTrn1,
90263508Sdim  OpZip1,
91263508Sdim  OpUzp1,
92263508Sdim  OpTrn2,
93263508Sdim  OpZip2,
94263508Sdim  OpUzp2,
95239462Sdim  OpEq,
96239462Sdim  OpGe,
97239462Sdim  OpLe,
98239462Sdim  OpGt,
99239462Sdim  OpLt,
100239462Sdim  OpNeg,
101239462Sdim  OpNot,
102239462Sdim  OpAnd,
103239462Sdim  OpOr,
104239462Sdim  OpXor,
105239462Sdim  OpAndNot,
106239462Sdim  OpOrNot,
107239462Sdim  OpCast,
108239462Sdim  OpConcat,
109239462Sdim  OpDup,
110239462Sdim  OpDupLane,
111239462Sdim  OpHi,
112239462Sdim  OpLo,
113239462Sdim  OpSelect,
114239462Sdim  OpRev16,
115239462Sdim  OpRev32,
116239462Sdim  OpRev64,
117263508Sdim  OpXtnHi,
118263508Sdim  OpSqxtunHi,
119263508Sdim  OpQxtnHi,
120263508Sdim  OpFcvtnHi,
121263508Sdim  OpFcvtlHi,
122263508Sdim  OpFcvtxnHi,
123239462Sdim  OpReinterpret,
124263508Sdim  OpAddhnHi,
125263508Sdim  OpRAddhnHi,
126263508Sdim  OpSubhnHi,
127263508Sdim  OpRSubhnHi,
128239462Sdim  OpAbdl,
129263508Sdim  OpAbdlHi,
130239462Sdim  OpAba,
131263508Sdim  OpAbal,
132263508Sdim  OpAbalHi,
133263508Sdim  OpQDMullHi,
134263508Sdim  OpQDMullHiN,
135263508Sdim  OpQDMlalHi,
136263508Sdim  OpQDMlalHiN,
137263508Sdim  OpQDMlslHi,
138263508Sdim  OpQDMlslHiN,
139263508Sdim  OpDiv,
140263508Sdim  OpLongHi,
141263508Sdim  OpNarrowHi,
142263508Sdim  OpMovlHi,
143263508Sdim  OpCopyLane,
144263508Sdim  OpCopyQLane,
145263508Sdim  OpCopyLaneQ,
146263508Sdim  OpScalarMulLane,
147263508Sdim  OpScalarMulLaneQ,
148263508Sdim  OpScalarMulXLane,
149263508Sdim  OpScalarMulXLaneQ,
150263508Sdim  OpScalarVMulXLane,
151263508Sdim  OpScalarVMulXLaneQ,
152263508Sdim  OpScalarQDMullLane,
153263508Sdim  OpScalarQDMullLaneQ,
154263508Sdim  OpScalarQDMulHiLane,
155263508Sdim  OpScalarQDMulHiLaneQ,
156263508Sdim  OpScalarQRDMulHiLane,
157263508Sdim  OpScalarQRDMulHiLaneQ,
158263508Sdim  OpScalarGetLane,
159263508Sdim  OpScalarSetLane
160239462Sdim};
161239462Sdim
162239462Sdimenum ClassKind {
163239462Sdim  ClassNone,
164239462Sdim  ClassI,           // generic integer instruction, e.g., "i8" suffix
165239462Sdim  ClassS,           // signed/unsigned/poly, e.g., "s8", "u8" or "p8" suffix
166239462Sdim  ClassW,           // width-specific instruction, e.g., "8" suffix
167251662Sdim  ClassB,           // bitcast arguments with enum argument to specify type
168251662Sdim  ClassL,           // Logical instructions which are op instructions
169251662Sdim                    // but we need to not emit any suffix for in our
170251662Sdim                    // tests.
171251662Sdim  ClassNoTest       // Instructions which we do not test since they are
172251662Sdim                    // not TRUE instructions.
173239462Sdim};
174239462Sdim
175239462Sdim/// NeonTypeFlags - Flags to identify the types for overloaded Neon
176239462Sdim/// builtins.  These must be kept in sync with the flags in
177239462Sdim/// include/clang/Basic/TargetBuiltins.h.
178239462Sdimnamespace {
179239462Sdimclass NeonTypeFlags {
180239462Sdim  enum {
181239462Sdim    EltTypeMask = 0xf,
182239462Sdim    UnsignedFlag = 0x10,
183239462Sdim    QuadFlag = 0x20
184239462Sdim  };
185239462Sdim  uint32_t Flags;
186239462Sdim
187239462Sdimpublic:
188239462Sdim  enum EltType {
189239462Sdim    Int8,
190239462Sdim    Int16,
191239462Sdim    Int32,
192239462Sdim    Int64,
193239462Sdim    Poly8,
194239462Sdim    Poly16,
195263508Sdim    Poly64,
196239462Sdim    Float16,
197263508Sdim    Float32,
198263508Sdim    Float64
199239462Sdim  };
200239462Sdim
201239462Sdim  NeonTypeFlags(unsigned F) : Flags(F) {}
202239462Sdim  NeonTypeFlags(EltType ET, bool IsUnsigned, bool IsQuad) : Flags(ET) {
203239462Sdim    if (IsUnsigned)
204239462Sdim      Flags |= UnsignedFlag;
205239462Sdim    if (IsQuad)
206239462Sdim      Flags |= QuadFlag;
207239462Sdim  }
208239462Sdim
209239462Sdim  uint32_t getFlags() const { return Flags; }
210239462Sdim};
211239462Sdim} // end anonymous namespace
212239462Sdim
213239462Sdimnamespace {
214239462Sdimclass NeonEmitter {
215239462Sdim  RecordKeeper &Records;
216239462Sdim  StringMap<OpKind> OpMap;
217239462Sdim  DenseMap<Record*, ClassKind> ClassMap;
218239462Sdim
219239462Sdimpublic:
220239462Sdim  NeonEmitter(RecordKeeper &R) : Records(R) {
221239462Sdim    OpMap["OP_NONE"]  = OpNone;
222239462Sdim    OpMap["OP_UNAVAILABLE"] = OpUnavailable;
223239462Sdim    OpMap["OP_ADD"]   = OpAdd;
224239462Sdim    OpMap["OP_ADDL"]  = OpAddl;
225263508Sdim    OpMap["OP_ADDLHi"] = OpAddlHi;
226239462Sdim    OpMap["OP_ADDW"]  = OpAddw;
227263508Sdim    OpMap["OP_ADDWHi"] = OpAddwHi;
228239462Sdim    OpMap["OP_SUB"]   = OpSub;
229239462Sdim    OpMap["OP_SUBL"]  = OpSubl;
230263508Sdim    OpMap["OP_SUBLHi"] = OpSublHi;
231239462Sdim    OpMap["OP_SUBW"]  = OpSubw;
232263508Sdim    OpMap["OP_SUBWHi"] = OpSubwHi;
233239462Sdim    OpMap["OP_MUL"]   = OpMul;
234239462Sdim    OpMap["OP_MLA"]   = OpMla;
235239462Sdim    OpMap["OP_MLAL"]  = OpMlal;
236263508Sdim    OpMap["OP_MULLHi"]  = OpMullHi;
237263508Sdim    OpMap["OP_MULLHi_N"]  = OpMullHiN;
238263508Sdim    OpMap["OP_MLALHi"]  = OpMlalHi;
239263508Sdim    OpMap["OP_MLALHi_N"]  = OpMlalHiN;
240239462Sdim    OpMap["OP_MLS"]   = OpMls;
241239462Sdim    OpMap["OP_MLSL"]  = OpMlsl;
242263508Sdim    OpMap["OP_MLSLHi"] = OpMlslHi;
243263508Sdim    OpMap["OP_MLSLHi_N"] = OpMlslHiN;
244239462Sdim    OpMap["OP_MUL_N"] = OpMulN;
245239462Sdim    OpMap["OP_MLA_N"] = OpMlaN;
246239462Sdim    OpMap["OP_MLS_N"] = OpMlsN;
247263508Sdim    OpMap["OP_FMLA_N"] = OpFMlaN;
248263508Sdim    OpMap["OP_FMLS_N"] = OpFMlsN;
249239462Sdim    OpMap["OP_MLAL_N"] = OpMlalN;
250239462Sdim    OpMap["OP_MLSL_N"] = OpMlslN;
251239462Sdim    OpMap["OP_MUL_LN"]= OpMulLane;
252263508Sdim    OpMap["OP_MULX_LN"]= OpMulXLane;
253239462Sdim    OpMap["OP_MULL_LN"] = OpMullLane;
254263508Sdim    OpMap["OP_MULLHi_LN"] = OpMullHiLane;
255239462Sdim    OpMap["OP_MLA_LN"]= OpMlaLane;
256239462Sdim    OpMap["OP_MLS_LN"]= OpMlsLane;
257239462Sdim    OpMap["OP_MLAL_LN"] = OpMlalLane;
258263508Sdim    OpMap["OP_MLALHi_LN"] = OpMlalHiLane;
259239462Sdim    OpMap["OP_MLSL_LN"] = OpMlslLane;
260263508Sdim    OpMap["OP_MLSLHi_LN"] = OpMlslHiLane;
261239462Sdim    OpMap["OP_QDMULL_LN"] = OpQDMullLane;
262263508Sdim    OpMap["OP_QDMULLHi_LN"] = OpQDMullHiLane;
263239462Sdim    OpMap["OP_QDMLAL_LN"] = OpQDMlalLane;
264263508Sdim    OpMap["OP_QDMLALHi_LN"] = OpQDMlalHiLane;
265239462Sdim    OpMap["OP_QDMLSL_LN"] = OpQDMlslLane;
266263508Sdim    OpMap["OP_QDMLSLHi_LN"] = OpQDMlslHiLane;
267239462Sdim    OpMap["OP_QDMULH_LN"] = OpQDMulhLane;
268239462Sdim    OpMap["OP_QRDMULH_LN"] = OpQRDMulhLane;
269263508Sdim    OpMap["OP_FMS_LN"] = OpFMSLane;
270263508Sdim    OpMap["OP_FMS_LNQ"] = OpFMSLaneQ;
271263508Sdim    OpMap["OP_TRN1"]  = OpTrn1;
272263508Sdim    OpMap["OP_ZIP1"]  = OpZip1;
273263508Sdim    OpMap["OP_UZP1"]  = OpUzp1;
274263508Sdim    OpMap["OP_TRN2"]  = OpTrn2;
275263508Sdim    OpMap["OP_ZIP2"]  = OpZip2;
276263508Sdim    OpMap["OP_UZP2"]  = OpUzp2;
277239462Sdim    OpMap["OP_EQ"]    = OpEq;
278239462Sdim    OpMap["OP_GE"]    = OpGe;
279239462Sdim    OpMap["OP_LE"]    = OpLe;
280239462Sdim    OpMap["OP_GT"]    = OpGt;
281239462Sdim    OpMap["OP_LT"]    = OpLt;
282239462Sdim    OpMap["OP_NEG"]   = OpNeg;
283239462Sdim    OpMap["OP_NOT"]   = OpNot;
284239462Sdim    OpMap["OP_AND"]   = OpAnd;
285239462Sdim    OpMap["OP_OR"]    = OpOr;
286239462Sdim    OpMap["OP_XOR"]   = OpXor;
287239462Sdim    OpMap["OP_ANDN"]  = OpAndNot;
288239462Sdim    OpMap["OP_ORN"]   = OpOrNot;
289239462Sdim    OpMap["OP_CAST"]  = OpCast;
290239462Sdim    OpMap["OP_CONC"]  = OpConcat;
291239462Sdim    OpMap["OP_HI"]    = OpHi;
292239462Sdim    OpMap["OP_LO"]    = OpLo;
293239462Sdim    OpMap["OP_DUP"]   = OpDup;
294239462Sdim    OpMap["OP_DUP_LN"] = OpDupLane;
295239462Sdim    OpMap["OP_SEL"]   = OpSelect;
296239462Sdim    OpMap["OP_REV16"] = OpRev16;
297239462Sdim    OpMap["OP_REV32"] = OpRev32;
298239462Sdim    OpMap["OP_REV64"] = OpRev64;
299263508Sdim    OpMap["OP_XTN"] = OpXtnHi;
300263508Sdim    OpMap["OP_SQXTUN"] = OpSqxtunHi;
301263508Sdim    OpMap["OP_QXTN"] = OpQxtnHi;
302263508Sdim    OpMap["OP_VCVT_NA_HI"] = OpFcvtnHi;
303263508Sdim    OpMap["OP_VCVT_EX_HI"] = OpFcvtlHi;
304263508Sdim    OpMap["OP_VCVTX_HI"] = OpFcvtxnHi;
305239462Sdim    OpMap["OP_REINT"] = OpReinterpret;
306263508Sdim    OpMap["OP_ADDHNHi"] = OpAddhnHi;
307263508Sdim    OpMap["OP_RADDHNHi"] = OpRAddhnHi;
308263508Sdim    OpMap["OP_SUBHNHi"] = OpSubhnHi;
309263508Sdim    OpMap["OP_RSUBHNHi"] = OpRSubhnHi;
310239462Sdim    OpMap["OP_ABDL"]  = OpAbdl;
311263508Sdim    OpMap["OP_ABDLHi"] = OpAbdlHi;
312239462Sdim    OpMap["OP_ABA"]   = OpAba;
313239462Sdim    OpMap["OP_ABAL"]  = OpAbal;
314263508Sdim    OpMap["OP_ABALHi"] = OpAbalHi;
315263508Sdim    OpMap["OP_QDMULLHi"] = OpQDMullHi;
316263508Sdim    OpMap["OP_QDMULLHi_N"] = OpQDMullHiN;
317263508Sdim    OpMap["OP_QDMLALHi"] = OpQDMlalHi;
318263508Sdim    OpMap["OP_QDMLALHi_N"] = OpQDMlalHiN;
319263508Sdim    OpMap["OP_QDMLSLHi"] = OpQDMlslHi;
320263508Sdim    OpMap["OP_QDMLSLHi_N"] = OpQDMlslHiN;
321263508Sdim    OpMap["OP_DIV"] = OpDiv;
322263508Sdim    OpMap["OP_LONG_HI"] = OpLongHi;
323263508Sdim    OpMap["OP_NARROW_HI"] = OpNarrowHi;
324263508Sdim    OpMap["OP_MOVL_HI"] = OpMovlHi;
325263508Sdim    OpMap["OP_COPY_LN"] = OpCopyLane;
326263508Sdim    OpMap["OP_COPYQ_LN"] = OpCopyQLane;
327263508Sdim    OpMap["OP_COPY_LNQ"] = OpCopyLaneQ;
328263508Sdim    OpMap["OP_SCALAR_MUL_LN"]= OpScalarMulLane;
329263508Sdim    OpMap["OP_SCALAR_MUL_LNQ"]= OpScalarMulLaneQ;
330263508Sdim    OpMap["OP_SCALAR_MULX_LN"]= OpScalarMulXLane;
331263508Sdim    OpMap["OP_SCALAR_MULX_LNQ"]= OpScalarMulXLaneQ;
332263508Sdim    OpMap["OP_SCALAR_VMULX_LN"]= OpScalarVMulXLane;
333263508Sdim    OpMap["OP_SCALAR_VMULX_LNQ"]= OpScalarVMulXLaneQ;
334263508Sdim    OpMap["OP_SCALAR_QDMULL_LN"] = OpScalarQDMullLane;
335263508Sdim    OpMap["OP_SCALAR_QDMULL_LNQ"] = OpScalarQDMullLaneQ;
336263508Sdim    OpMap["OP_SCALAR_QDMULH_LN"] = OpScalarQDMulHiLane;
337263508Sdim    OpMap["OP_SCALAR_QDMULH_LNQ"] = OpScalarQDMulHiLaneQ;
338263508Sdim    OpMap["OP_SCALAR_QRDMULH_LN"] = OpScalarQRDMulHiLane;
339263508Sdim    OpMap["OP_SCALAR_QRDMULH_LNQ"] = OpScalarQRDMulHiLaneQ;
340263508Sdim    OpMap["OP_SCALAR_GET_LN"] = OpScalarGetLane;
341263508Sdim    OpMap["OP_SCALAR_SET_LN"] = OpScalarSetLane;
342239462Sdim
343239462Sdim    Record *SI = R.getClass("SInst");
344239462Sdim    Record *II = R.getClass("IInst");
345239462Sdim    Record *WI = R.getClass("WInst");
346251662Sdim    Record *SOpI = R.getClass("SOpInst");
347251662Sdim    Record *IOpI = R.getClass("IOpInst");
348251662Sdim    Record *WOpI = R.getClass("WOpInst");
349251662Sdim    Record *LOpI = R.getClass("LOpInst");
350251662Sdim    Record *NoTestOpI = R.getClass("NoTestOpInst");
351251662Sdim
352239462Sdim    ClassMap[SI] = ClassS;
353239462Sdim    ClassMap[II] = ClassI;
354239462Sdim    ClassMap[WI] = ClassW;
355251662Sdim    ClassMap[SOpI] = ClassS;
356251662Sdim    ClassMap[IOpI] = ClassI;
357251662Sdim    ClassMap[WOpI] = ClassW;
358251662Sdim    ClassMap[LOpI] = ClassL;
359251662Sdim    ClassMap[NoTestOpI] = ClassNoTest;
360239462Sdim  }
361239462Sdim
362239462Sdim  // run - Emit arm_neon.h.inc
363239462Sdim  void run(raw_ostream &o);
364239462Sdim
365239462Sdim  // runHeader - Emit all the __builtin prototypes used in arm_neon.h
366239462Sdim  void runHeader(raw_ostream &o);
367239462Sdim
368239462Sdim  // runTests - Emit tests for all the Neon intrinsics.
369239462Sdim  void runTests(raw_ostream &o);
370239462Sdim
371239462Sdimprivate:
372263508Sdim  void emitIntrinsic(raw_ostream &OS, Record *R,
373263508Sdim                     StringMap<ClassKind> &EmittedMap);
374263508Sdim  void genBuiltinsDef(raw_ostream &OS, StringMap<ClassKind> &A64IntrinsicMap,
375263508Sdim                      bool isA64GenBuiltinDef);
376263508Sdim  void genOverloadTypeCheckCode(raw_ostream &OS,
377263508Sdim                                StringMap<ClassKind> &A64IntrinsicMap,
378263508Sdim                                bool isA64TypeCheck);
379263508Sdim  void genIntrinsicRangeCheckCode(raw_ostream &OS,
380263508Sdim                                  StringMap<ClassKind> &A64IntrinsicMap,
381263508Sdim                                  bool isA64RangeCheck);
382263508Sdim  void genTargetTest(raw_ostream &OS, StringMap<OpKind> &EmittedMap,
383263508Sdim                     bool isA64TestGen);
384239462Sdim};
385239462Sdim} // end anonymous namespace
386239462Sdim
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) {
397263508Sdim    if (data[len] == 'P' || data[len] == 'Q' || data[len] == 'U'
398263508Sdim                         || 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':
408263508Sdim      case 'd':
409226586Sdim        break;
410226586Sdim      default:
411243830Sdim        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';
432263508Sdim    case 'f':
433263508Sdim      return 'd';
434243830Sdim    default:
435243830Sdim      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';
451263508Sdim    case 'd':
452263508Sdim      return 'f';
453243830Sdim    default:
454243830Sdim      PrintFatalError("unhandled type in narrow!");
455226586Sdim  }
456226586Sdim}
457226586Sdim
458263508Sdimstatic std::string GetNarrowTypestr(StringRef ty)
459263508Sdim{
460263508Sdim  std::string s;
461263508Sdim  for (size_t i = 0, end = ty.size(); i < end; i++) {
462263508Sdim    switch (ty[i]) {
463263508Sdim      case 's':
464263508Sdim        s += 'c';
465263508Sdim        break;
466263508Sdim      case 'i':
467263508Sdim        s += 's';
468263508Sdim        break;
469263508Sdim      case 'l':
470263508Sdim        s += 'i';
471263508Sdim        break;
472263508Sdim      default:
473263508Sdim        s += ty[i];
474263508Sdim        break;
475263508Sdim    }
476263508Sdim  }
477263508Sdim
478263508Sdim  return s;
479263508Sdim}
480263508Sdim
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;
485263508Sdim  // ignore scalar.
486263508Sdim  if (ty[off] == 'S') {
487263508Sdim    ++off;
488263508Sdim  }
489226586Sdim  // remember quad.
490263508Sdim  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;
522263508Sdim    case 'b':
523263508Sdim      scal = true;
524226586Sdim    case 'u':
525226586Sdim      usgn = true;
526226586Sdim      poly = false;
527226586Sdim      if (type == 'f')
528226586Sdim        type = 'i';
529263508Sdim      if (type == 'd')
530263508Sdim        type = 'l';
531226586Sdim      break;
532263508Sdim    case '$':
533263508Sdim      scal = true;
534226586Sdim    case 'x':
535226586Sdim      usgn = false;
536226586Sdim      poly = false;
537226586Sdim      if (type == 'f')
538226586Sdim        type = 'i';
539263508Sdim      if (type == 'd')
540263508Sdim        type = 'l';
541226586Sdim      break;
542263508Sdim    case 'o':
543263508Sdim      scal = true;
544263508Sdim      type = 'd';
545263508Sdim      usgn = false;
546263508Sdim      break;
547263508Sdim    case 'y':
548263508Sdim      scal = true;
549226586Sdim    case 'f':
550226586Sdim      if (type == 'h')
551226586Sdim        quad = true;
552226586Sdim      type = 'f';
553226586Sdim      usgn = false;
554226586Sdim      break;
555263508Sdim    case 'F':
556263508Sdim      type = 'd';
557263508Sdim      usgn = false;
558263508Sdim      break;
559226586Sdim    case 'g':
560226586Sdim      quad = false;
561226586Sdim      break;
562263508Sdim    case 'B':
563263508Sdim    case 'C':
564263508Sdim    case 'D':
565263508Sdim    case 'j':
566263508Sdim      quad = true;
567263508Sdim      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;
584263508Sdim    case 'z':
585263508Sdim      type = Narrow(type);
586263508Sdim      scal = true;
587263508Sdim      break;
588263508Sdim    case 'r':
589263508Sdim      type = Widen(type);
590263508Sdim      scal = true;
591263508Sdim      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;
610263508Sdim    case 'q':
611263508Sdim      type = Narrow(type);
612263508Sdim      quad = true;
613263508Sdim      break;
614226586Sdim    case 'e':
615226586Sdim      type = Narrow(type);
616226586Sdim      usgn = true;
617226586Sdim      break;
618263508Sdim    case 'm':
619263508Sdim      type = Narrow(type);
620263508Sdim      quad = false;
621263508Sdim      break;
622226586Sdim    default:
623226586Sdim      break;
624226586Sdim  }
625226586Sdim  return type;
626226586Sdim}
627226586Sdim
628263508Sdimstatic bool IsMultiVecProto(const char p) {
629263508Sdim  return ((p >= '2' && p <= '4') || (p >= 'B' && p <= 'D'));
630263508Sdim}
631263508Sdim
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':
678263508Sdim      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;
695263508Sdim    case 'd':
696263508Sdim      s += "float64";
697263508Sdim      if (scal)
698263508Sdim        break;
699263508Sdim      s += quad ? "x2" : "x1";
700263508Sdim      break;
701263508Sdim
702226586Sdim    default:
703243830Sdim      PrintFatalError("unhandled type!");
704226586Sdim  }
705226586Sdim
706263508Sdim  if (mod == '2' || mod == 'B')
707226586Sdim    s += "x2";
708263508Sdim  if (mod == '3' || mod == 'C')
709226586Sdim    s += "x3";
710263508Sdim  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  }
759263508Sdim  usgn = usgn | poly | ((ck == ClassI || ck == ClassW) &&
760263508Sdim                         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) {
787263508Sdim    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";
791263508Sdim    if (mod == 'F' || (ck != ClassB && type == 'd'))
792263508Sdim      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.
804263508Sdim  if (mod == '2' || mod == 'B')
805226586Sdim    return quad ? "V16ScV16Sc" : "V8ScV8Sc";
806263508Sdim  if (mod == '3' || mod == 'C')
807226586Sdim    return quad ? "V16ScV16ScV16Sc" : "V8ScV8ScV8Sc";
808263508Sdim  if (mod == '4' || mod == 'D')
809226586Sdim    return quad ? "V16ScV16ScV16ScV16Sc" : "V8ScV8ScV8ScV8Sc";
810226586Sdim
811226586Sdim  if (mod == 'f' || (ck != ClassB && type == 'f'))
812226586Sdim    return quad ? "V4f" : "V2f";
813263508Sdim  if (mod == 'F' || (ck != ClassB && type == 'd'))
814263508Sdim    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
825251662Sdim/// InstructionTypeCode - Computes the ARM argument character code and
826251662Sdim/// quad status for a specific type string and ClassKind.
827251662Sdimstatic void InstructionTypeCode(const StringRef &typeStr,
828251662Sdim                                const ClassKind ck,
829251662Sdim                                bool &quad,
830251662Sdim                                std::string &typeCode) {
831226586Sdim  bool poly = false;
832226586Sdim  bool usgn = false;
833251662Sdim  char type = ClassifyType(typeStr, quad, poly, usgn);
834226586Sdim
835226586Sdim  switch (type) {
836226586Sdim  case 'c':
837226586Sdim    switch (ck) {
838251662Sdim    case ClassS: typeCode = poly ? "p8" : usgn ? "u8" : "s8"; break;
839251662Sdim    case ClassI: typeCode = "i8"; break;
840251662Sdim    case ClassW: typeCode = "8"; break;
841226586Sdim    default: break;
842226586Sdim    }
843226586Sdim    break;
844226586Sdim  case 's':
845226586Sdim    switch (ck) {
846251662Sdim    case ClassS: typeCode = poly ? "p16" : usgn ? "u16" : "s16"; break;
847251662Sdim    case ClassI: typeCode = "i16"; break;
848251662Sdim    case ClassW: typeCode = "16"; break;
849226586Sdim    default: break;
850226586Sdim    }
851226586Sdim    break;
852226586Sdim  case 'i':
853226586Sdim    switch (ck) {
854251662Sdim    case ClassS: typeCode = usgn ? "u32" : "s32"; break;
855251662Sdim    case ClassI: typeCode = "i32"; break;
856251662Sdim    case ClassW: typeCode = "32"; break;
857226586Sdim    default: break;
858226586Sdim    }
859226586Sdim    break;
860226586Sdim  case 'l':
861226586Sdim    switch (ck) {
862263508Sdim    case ClassS: typeCode = poly ? "p64" : usgn ? "u64" : "s64"; break;
863251662Sdim    case ClassI: typeCode = "i64"; break;
864251662Sdim    case ClassW: typeCode = "64"; break;
865226586Sdim    default: break;
866226586Sdim    }
867226586Sdim    break;
868226586Sdim  case 'h':
869226586Sdim    switch (ck) {
870226586Sdim    case ClassS:
871251662Sdim    case ClassI: typeCode = "f16"; break;
872251662Sdim    case ClassW: typeCode = "16"; break;
873226586Sdim    default: break;
874226586Sdim    }
875226586Sdim    break;
876226586Sdim  case 'f':
877226586Sdim    switch (ck) {
878226586Sdim    case ClassS:
879251662Sdim    case ClassI: typeCode = "f32"; break;
880251662Sdim    case ClassW: typeCode = "32"; break;
881226586Sdim    default: break;
882226586Sdim    }
883226586Sdim    break;
884263508Sdim  case 'd':
885263508Sdim    switch (ck) {
886263508Sdim    case ClassS:
887263508Sdim    case ClassI:
888263508Sdim      typeCode += "f64";
889263508Sdim      break;
890263508Sdim    case ClassW:
891263508Sdim      PrintFatalError("unhandled type!");
892263508Sdim    default:
893263508Sdim      break;
894263508Sdim    }
895263508Sdim    break;
896226586Sdim  default:
897243830Sdim    PrintFatalError("unhandled type!");
898226586Sdim  }
899251662Sdim}
900251662Sdim
901263508Sdimstatic char Insert_BHSD_Suffix(StringRef typestr){
902263508Sdim  unsigned off = 0;
903263508Sdim  if(typestr[off++] == 'S'){
904263508Sdim    while(typestr[off] == 'Q' || typestr[off] == 'H'||
905263508Sdim          typestr[off] == 'P' || typestr[off] == 'U')
906263508Sdim      ++off;
907263508Sdim    switch (typestr[off]){
908263508Sdim    default  : break;
909263508Sdim    case 'c' : return 'b';
910263508Sdim    case 's' : return 'h';
911263508Sdim    case 'i' :
912263508Sdim    case 'f' : return 's';
913263508Sdim    case 'l' :
914263508Sdim    case 'd' : return 'd';
915263508Sdim    }
916263508Sdim  }
917263508Sdim  return 0;
918263508Sdim}
919263508Sdim
920263508Sdimstatic bool endsWith_xN(std::string const &name) {
921263508Sdim  if (name.length() > 3) {
922263508Sdim    if (name.compare(name.length() - 3, 3, "_x2") == 0 ||
923263508Sdim        name.compare(name.length() - 3, 3, "_x3") == 0 ||
924263508Sdim        name.compare(name.length() - 3, 3, "_x4") == 0)
925263508Sdim      return true;
926263508Sdim  }
927263508Sdim  return false;
928263508Sdim}
929263508Sdim
930251662Sdim/// MangleName - Append a type or width suffix to a base neon function name,
931263508Sdim/// and insert a 'q' in the appropriate location if type string starts with 'Q'.
932263508Sdim/// E.g. turn "vst2_lane" into "vst2q_lane_f32", etc.
933263508Sdim/// Insert proper 'b' 'h' 's' 'd' if prefix 'S' is used.
934251662Sdimstatic std::string MangleName(const std::string &name, StringRef typestr,
935251662Sdim                              ClassKind ck) {
936263508Sdim  if (name == "vcvt_f32_f16" || name == "vcvt_f32_f64" ||
937263508Sdim      name == "vcvt_f64_f32")
938251662Sdim    return name;
939251662Sdim
940251662Sdim  bool quad = false;
941251662Sdim  std::string typeCode = "";
942251662Sdim
943251662Sdim  InstructionTypeCode(typestr, ck, quad, typeCode);
944251662Sdim
945251662Sdim  std::string s = name;
946251662Sdim
947251662Sdim  if (typeCode.size() > 0) {
948263508Sdim    // If the name is end with _xN (N = 2,3,4), insert the typeCode before _xN.
949263508Sdim    if (endsWith_xN(s))
950263508Sdim      s.insert(s.length() - 3, "_" + typeCode);
951263508Sdim    else
952263508Sdim      s += "_" + typeCode;
953251662Sdim  }
954251662Sdim
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.
960263508Sdim  if (typestr.find("Q") != StringRef::npos) {
961263508Sdim      size_t pos = s.find('_');
962263508Sdim      s = s.insert(pos, "q");
963263508Sdim  }
964263508Sdim  char ins = Insert_BHSD_Suffix(typestr);
965263508Sdim  if(ins){
966226586Sdim    size_t pos = s.find('_');
967263508Sdim    s = s.insert(pos, &ins, 1);
968226586Sdim  }
969251662Sdim
970226586Sdim  return s;
971226586Sdim}
972226586Sdim
973251662Sdimstatic void PreprocessInstruction(const StringRef &Name,
974251662Sdim                                  const std::string &InstName,
975251662Sdim                                  std::string &Prefix,
976251662Sdim                                  bool &HasNPostfix,
977251662Sdim                                  bool &HasLanePostfix,
978251662Sdim                                  bool &HasDupPostfix,
979251662Sdim                                  bool &IsSpecialVCvt,
980251662Sdim                                  size_t &TBNumber) {
981251662Sdim  // All of our instruction name fields from arm_neon.td are of the form
982251662Sdim  //   <instructionname>_...
983251662Sdim  // Thus we grab our instruction name via computation of said Prefix.
984251662Sdim  const size_t PrefixEnd = Name.find_first_of('_');
985251662Sdim  // If InstName is passed in, we use that instead of our name Prefix.
986251662Sdim  Prefix = InstName.size() == 0? Name.slice(0, PrefixEnd).str() : InstName;
987251662Sdim
988251662Sdim  const StringRef Postfix = Name.slice(PrefixEnd, Name.size());
989251662Sdim
990251662Sdim  HasNPostfix = Postfix.count("_n");
991251662Sdim  HasLanePostfix = Postfix.count("_lane");
992251662Sdim  HasDupPostfix = Postfix.count("_dup");
993251662Sdim  IsSpecialVCvt = Postfix.size() != 0 && Name.count("vcvt");
994251662Sdim
995251662Sdim  if (InstName.compare("vtbl") == 0 ||
996251662Sdim      InstName.compare("vtbx") == 0) {
997251662Sdim    // If we have a vtblN/vtbxN instruction, use the instruction's ASCII
998251662Sdim    // encoding to get its true value.
999251662Sdim    TBNumber = Name[Name.size()-1] - 48;
1000251662Sdim  }
1001251662Sdim}
1002251662Sdim
1003251662Sdim/// GenerateRegisterCheckPatternsForLoadStores - Given a bunch of data we have
1004251662Sdim/// extracted, generate a FileCheck pattern for a Load Or Store
1005251662Sdimstatic void
1006251662SdimGenerateRegisterCheckPatternForLoadStores(const StringRef &NameRef,
1007251662Sdim                                          const std::string& OutTypeCode,
1008251662Sdim                                          const bool &IsQuad,
1009251662Sdim                                          const bool &HasDupPostfix,
1010251662Sdim                                          const bool &HasLanePostfix,
1011251662Sdim                                          const size_t Count,
1012251662Sdim                                          std::string &RegisterSuffix) {
1013251662Sdim  const bool IsLDSTOne = NameRef.count("vld1") || NameRef.count("vst1");
1014251662Sdim  // If N == 3 || N == 4 and we are dealing with a quad instruction, Clang
1015251662Sdim  // will output a series of v{ld,st}1s, so we have to handle it specially.
1016251662Sdim  if ((Count == 3 || Count == 4) && IsQuad) {
1017251662Sdim    RegisterSuffix += "{";
1018251662Sdim    for (size_t i = 0; i < Count; i++) {
1019251662Sdim      RegisterSuffix += "d{{[0-9]+}}";
1020251662Sdim      if (HasDupPostfix) {
1021251662Sdim        RegisterSuffix += "[]";
1022251662Sdim      }
1023251662Sdim      if (HasLanePostfix) {
1024251662Sdim        RegisterSuffix += "[{{[0-9]+}}]";
1025251662Sdim      }
1026251662Sdim      if (i < Count-1) {
1027251662Sdim        RegisterSuffix += ", ";
1028251662Sdim      }
1029251662Sdim    }
1030251662Sdim    RegisterSuffix += "}";
1031251662Sdim  } else {
1032251662Sdim
1033251662Sdim    // Handle normal loads and stores.
1034251662Sdim    RegisterSuffix += "{";
1035251662Sdim    for (size_t i = 0; i < Count; i++) {
1036251662Sdim      RegisterSuffix += "d{{[0-9]+}}";
1037251662Sdim      if (HasDupPostfix) {
1038251662Sdim        RegisterSuffix += "[]";
1039251662Sdim      }
1040251662Sdim      if (HasLanePostfix) {
1041251662Sdim        RegisterSuffix += "[{{[0-9]+}}]";
1042251662Sdim      }
1043251662Sdim      if (IsQuad && !HasLanePostfix) {
1044251662Sdim        RegisterSuffix += ", d{{[0-9]+}}";
1045251662Sdim        if (HasDupPostfix) {
1046251662Sdim          RegisterSuffix += "[]";
1047251662Sdim        }
1048251662Sdim      }
1049251662Sdim      if (i < Count-1) {
1050251662Sdim        RegisterSuffix += ", ";
1051251662Sdim      }
1052251662Sdim    }
1053251662Sdim    RegisterSuffix += "}, [r{{[0-9]+}}";
1054251662Sdim
1055251662Sdim    // We only include the alignment hint if we have a vld1.*64 or
1056251662Sdim    // a dup/lane instruction.
1057251662Sdim    if (IsLDSTOne) {
1058251662Sdim      if ((HasLanePostfix || HasDupPostfix) && OutTypeCode != "8") {
1059263508Sdim        RegisterSuffix += ":" + OutTypeCode;
1060251662Sdim      }
1061251662Sdim    }
1062251662Sdim
1063251662Sdim    RegisterSuffix += "]";
1064251662Sdim  }
1065251662Sdim}
1066251662Sdim
1067251662Sdimstatic bool HasNPostfixAndScalarArgs(const StringRef &NameRef,
1068251662Sdim                                     const bool &HasNPostfix) {
1069251662Sdim  return (NameRef.count("vmla") ||
1070251662Sdim          NameRef.count("vmlal") ||
1071251662Sdim          NameRef.count("vmlsl") ||
1072251662Sdim          NameRef.count("vmull") ||
1073251662Sdim          NameRef.count("vqdmlal") ||
1074251662Sdim          NameRef.count("vqdmlsl") ||
1075251662Sdim          NameRef.count("vqdmulh") ||
1076251662Sdim          NameRef.count("vqdmull") ||
1077251662Sdim          NameRef.count("vqrdmulh")) && HasNPostfix;
1078251662Sdim}
1079251662Sdim
1080251662Sdimstatic bool IsFiveOperandLaneAccumulator(const StringRef &NameRef,
1081251662Sdim                                         const bool &HasLanePostfix) {
1082251662Sdim  return (NameRef.count("vmla") ||
1083251662Sdim          NameRef.count("vmls") ||
1084251662Sdim          NameRef.count("vmlal") ||
1085251662Sdim          NameRef.count("vmlsl") ||
1086251662Sdim          (NameRef.count("vmul") && NameRef.size() == 3)||
1087251662Sdim          NameRef.count("vqdmlal") ||
1088251662Sdim          NameRef.count("vqdmlsl") ||
1089251662Sdim          NameRef.count("vqdmulh") ||
1090251662Sdim          NameRef.count("vqrdmulh")) && HasLanePostfix;
1091251662Sdim}
1092251662Sdim
1093251662Sdimstatic bool IsSpecialLaneMultiply(const StringRef &NameRef,
1094251662Sdim                                  const bool &HasLanePostfix,
1095251662Sdim                                  const bool &IsQuad) {
1096251662Sdim  const bool IsVMulOrMulh = (NameRef.count("vmul") || NameRef.count("mulh"))
1097251662Sdim                               && IsQuad;
1098251662Sdim  const bool IsVMull = NameRef.count("mull") && !IsQuad;
1099251662Sdim  return (IsVMulOrMulh || IsVMull) && HasLanePostfix;
1100251662Sdim}
1101251662Sdim
1102251662Sdimstatic void NormalizeProtoForRegisterPatternCreation(const std::string &Name,
1103251662Sdim                                                     const std::string &Proto,
1104251662Sdim                                                     const bool &HasNPostfix,
1105251662Sdim                                                     const bool &IsQuad,
1106251662Sdim                                                     const bool &HasLanePostfix,
1107251662Sdim                                                     const bool &HasDupPostfix,
1108251662Sdim                                                     std::string &NormedProto) {
1109251662Sdim  // Handle generic case.
1110251662Sdim  const StringRef NameRef(Name);
1111251662Sdim  for (size_t i = 0, end = Proto.size(); i < end; i++) {
1112251662Sdim    switch (Proto[i]) {
1113251662Sdim    case 'u':
1114251662Sdim    case 'f':
1115263508Sdim    case 'F':
1116251662Sdim    case 'd':
1117251662Sdim    case 's':
1118251662Sdim    case 'x':
1119251662Sdim    case 't':
1120251662Sdim    case 'n':
1121251662Sdim      NormedProto += IsQuad? 'q' : 'd';
1122251662Sdim      break;
1123251662Sdim    case 'w':
1124251662Sdim    case 'k':
1125251662Sdim      NormedProto += 'q';
1126251662Sdim      break;
1127251662Sdim    case 'g':
1128263508Sdim    case 'j':
1129251662Sdim    case 'h':
1130251662Sdim    case 'e':
1131251662Sdim      NormedProto += 'd';
1132251662Sdim      break;
1133251662Sdim    case 'i':
1134251662Sdim      NormedProto += HasLanePostfix? 'a' : 'i';
1135251662Sdim      break;
1136251662Sdim    case 'a':
1137251662Sdim      if (HasLanePostfix) {
1138251662Sdim        NormedProto += 'a';
1139251662Sdim      } else if (HasNPostfixAndScalarArgs(NameRef, HasNPostfix)) {
1140251662Sdim        NormedProto += IsQuad? 'q' : 'd';
1141251662Sdim      } else {
1142251662Sdim        NormedProto += 'i';
1143251662Sdim      }
1144251662Sdim      break;
1145251662Sdim    }
1146251662Sdim  }
1147251662Sdim
1148251662Sdim  // Handle Special Cases.
1149251662Sdim  const bool IsNotVExt = !NameRef.count("vext");
1150251662Sdim  const bool IsVPADAL = NameRef.count("vpadal");
1151251662Sdim  const bool Is5OpLaneAccum = IsFiveOperandLaneAccumulator(NameRef,
1152251662Sdim                                                           HasLanePostfix);
1153251662Sdim  const bool IsSpecialLaneMul = IsSpecialLaneMultiply(NameRef, HasLanePostfix,
1154251662Sdim                                                      IsQuad);
1155251662Sdim
1156251662Sdim  if (IsSpecialLaneMul) {
1157251662Sdim    // If
1158251662Sdim    NormedProto[2] = NormedProto[3];
1159251662Sdim    NormedProto.erase(3);
1160251662Sdim  } else if (NormedProto.size() == 4 &&
1161251662Sdim             NormedProto[0] == NormedProto[1] &&
1162251662Sdim             IsNotVExt) {
1163251662Sdim    // If NormedProto.size() == 4 and the first two proto characters are the
1164251662Sdim    // same, ignore the first.
1165251662Sdim    NormedProto = NormedProto.substr(1, 3);
1166251662Sdim  } else if (Is5OpLaneAccum) {
1167251662Sdim    // If we have a 5 op lane accumulator operation, we take characters 1,2,4
1168251662Sdim    std::string tmp = NormedProto.substr(1,2);
1169251662Sdim    tmp += NormedProto[4];
1170251662Sdim    NormedProto = tmp;
1171251662Sdim  } else if (IsVPADAL) {
1172251662Sdim    // If we have VPADAL, ignore the first character.
1173251662Sdim    NormedProto = NormedProto.substr(0, 2);
1174251662Sdim  } else if (NameRef.count("vdup") && NormedProto.size() > 2) {
1175251662Sdim    // If our instruction is a dup instruction, keep only the first and
1176251662Sdim    // last characters.
1177251662Sdim    std::string tmp = "";
1178251662Sdim    tmp += NormedProto[0];
1179251662Sdim    tmp += NormedProto[NormedProto.size()-1];
1180251662Sdim    NormedProto = tmp;
1181251662Sdim  }
1182251662Sdim}
1183251662Sdim
1184251662Sdim/// GenerateRegisterCheckPatterns - Given a bunch of data we have
1185251662Sdim/// extracted, generate a FileCheck pattern to check that an
1186251662Sdim/// instruction's arguments are correct.
1187251662Sdimstatic void GenerateRegisterCheckPattern(const std::string &Name,
1188251662Sdim                                         const std::string &Proto,
1189251662Sdim                                         const std::string &OutTypeCode,
1190251662Sdim                                         const bool &HasNPostfix,
1191251662Sdim                                         const bool &IsQuad,
1192251662Sdim                                         const bool &HasLanePostfix,
1193251662Sdim                                         const bool &HasDupPostfix,
1194251662Sdim                                         const size_t &TBNumber,
1195251662Sdim                                         std::string &RegisterSuffix) {
1196251662Sdim
1197251662Sdim  RegisterSuffix = "";
1198251662Sdim
1199251662Sdim  const StringRef NameRef(Name);
1200251662Sdim  const StringRef ProtoRef(Proto);
1201251662Sdim
1202251662Sdim  if ((NameRef.count("vdup") || NameRef.count("vmov")) && HasNPostfix) {
1203251662Sdim    return;
1204251662Sdim  }
1205251662Sdim
1206251662Sdim  const bool IsLoadStore = NameRef.count("vld") || NameRef.count("vst");
1207251662Sdim  const bool IsTBXOrTBL = NameRef.count("vtbl") || NameRef.count("vtbx");
1208251662Sdim
1209251662Sdim  if (IsLoadStore) {
1210251662Sdim    // Grab N value from  v{ld,st}N using its ascii representation.
1211251662Sdim    const size_t Count = NameRef[3] - 48;
1212251662Sdim
1213251662Sdim    GenerateRegisterCheckPatternForLoadStores(NameRef, OutTypeCode, IsQuad,
1214251662Sdim                                              HasDupPostfix, HasLanePostfix,
1215251662Sdim                                              Count, RegisterSuffix);
1216251662Sdim  } else if (IsTBXOrTBL) {
1217251662Sdim    RegisterSuffix += "d{{[0-9]+}}, {";
1218251662Sdim    for (size_t i = 0; i < TBNumber-1; i++) {
1219251662Sdim      RegisterSuffix += "d{{[0-9]+}}, ";
1220251662Sdim    }
1221251662Sdim    RegisterSuffix += "d{{[0-9]+}}}, d{{[0-9]+}}";
1222251662Sdim  } else {
1223251662Sdim    // Handle a normal instruction.
1224251662Sdim    if (NameRef.count("vget") || NameRef.count("vset"))
1225251662Sdim      return;
1226251662Sdim
1227251662Sdim    // We first normalize our proto, since we only need to emit 4
1228251662Sdim    // different types of checks, yet have more than 4 proto types
1229251662Sdim    // that map onto those 4 patterns.
1230251662Sdim    std::string NormalizedProto("");
1231251662Sdim    NormalizeProtoForRegisterPatternCreation(Name, Proto, HasNPostfix, IsQuad,
1232251662Sdim                                             HasLanePostfix, HasDupPostfix,
1233251662Sdim                                             NormalizedProto);
1234251662Sdim
1235251662Sdim    for (size_t i = 0, end = NormalizedProto.size(); i < end; i++) {
1236251662Sdim      const char &c = NormalizedProto[i];
1237251662Sdim      switch (c) {
1238251662Sdim      case 'q':
1239251662Sdim        RegisterSuffix += "q{{[0-9]+}}, ";
1240251662Sdim        break;
1241251662Sdim
1242251662Sdim      case 'd':
1243251662Sdim        RegisterSuffix += "d{{[0-9]+}}, ";
1244251662Sdim        break;
1245251662Sdim
1246251662Sdim      case 'i':
1247251662Sdim        RegisterSuffix += "#{{[0-9]+}}, ";
1248251662Sdim        break;
1249251662Sdim
1250251662Sdim      case 'a':
1251251662Sdim        RegisterSuffix += "d{{[0-9]+}}[{{[0-9]}}], ";
1252251662Sdim        break;
1253251662Sdim      }
1254251662Sdim    }
1255251662Sdim
1256251662Sdim    // Remove extra ", ".
1257251662Sdim    RegisterSuffix = RegisterSuffix.substr(0, RegisterSuffix.size()-2);
1258251662Sdim  }
1259251662Sdim}
1260251662Sdim
1261251662Sdim/// GenerateChecksForIntrinsic - Given a specific instruction name +
1262251662Sdim/// typestr + class kind, generate the proper set of FileCheck
1263251662Sdim/// Patterns to check for. We could just return a string, but instead
1264251662Sdim/// use a vector since it provides us with the extra flexibility of
1265251662Sdim/// emitting multiple checks, which comes in handy for certain cases
1266251662Sdim/// like mla where we want to check for 2 different instructions.
1267251662Sdimstatic void GenerateChecksForIntrinsic(const std::string &Name,
1268251662Sdim                                       const std::string &Proto,
1269251662Sdim                                       StringRef &OutTypeStr,
1270251662Sdim                                       StringRef &InTypeStr,
1271251662Sdim                                       ClassKind Ck,
1272251662Sdim                                       const std::string &InstName,
1273251662Sdim                                       bool IsHiddenLOp,
1274251662Sdim                                       std::vector<std::string>& Result) {
1275251662Sdim
1276251662Sdim  // If Ck is a ClassNoTest instruction, just return so no test is
1277251662Sdim  // emitted.
1278251662Sdim  if(Ck == ClassNoTest)
1279251662Sdim    return;
1280251662Sdim
1281251662Sdim  if (Name == "vcvt_f32_f16") {
1282251662Sdim    Result.push_back("vcvt.f32.f16");
1283251662Sdim    return;
1284251662Sdim  }
1285251662Sdim
1286251662Sdim
1287251662Sdim  // Now we preprocess our instruction given the data we have to get the
1288251662Sdim  // data that we need.
1289251662Sdim  // Create a StringRef for String Manipulation of our Name.
1290251662Sdim  const StringRef NameRef(Name);
1291251662Sdim  // Instruction Prefix.
1292251662Sdim  std::string Prefix;
1293251662Sdim  // The type code for our out type string.
1294251662Sdim  std::string OutTypeCode;
1295251662Sdim  // To handle our different cases, we need to check for different postfixes.
1296251662Sdim  // Is our instruction a quad instruction.
1297251662Sdim  bool IsQuad = false;
1298251662Sdim  // Our instruction is of the form <instructionname>_n.
1299251662Sdim  bool HasNPostfix = false;
1300251662Sdim  // Our instruction is of the form <instructionname>_lane.
1301251662Sdim  bool HasLanePostfix = false;
1302251662Sdim  // Our instruction is of the form <instructionname>_dup.
1303251662Sdim  bool HasDupPostfix  = false;
1304251662Sdim  // Our instruction is a vcvt instruction which requires special handling.
1305251662Sdim  bool IsSpecialVCvt = false;
1306251662Sdim  // If we have a vtbxN or vtblN instruction, this is set to N.
1307251662Sdim  size_t TBNumber = -1;
1308251662Sdim  // Register Suffix
1309251662Sdim  std::string RegisterSuffix;
1310251662Sdim
1311251662Sdim  PreprocessInstruction(NameRef, InstName, Prefix,
1312251662Sdim                        HasNPostfix, HasLanePostfix, HasDupPostfix,
1313251662Sdim                        IsSpecialVCvt, TBNumber);
1314251662Sdim
1315251662Sdim  InstructionTypeCode(OutTypeStr, Ck, IsQuad, OutTypeCode);
1316251662Sdim  GenerateRegisterCheckPattern(Name, Proto, OutTypeCode, HasNPostfix, IsQuad,
1317251662Sdim                               HasLanePostfix, HasDupPostfix, TBNumber,
1318251662Sdim                               RegisterSuffix);
1319251662Sdim
1320251662Sdim  // In the following section, we handle a bunch of special cases. You can tell
1321251662Sdim  // a special case by the fact we are returning early.
1322251662Sdim
1323251662Sdim  // If our instruction is a logical instruction without postfix or a
1324251662Sdim  // hidden LOp just return the current Prefix.
1325251662Sdim  if (Ck == ClassL || IsHiddenLOp) {
1326251662Sdim    Result.push_back(Prefix + " " + RegisterSuffix);
1327251662Sdim    return;
1328251662Sdim  }
1329251662Sdim
1330251662Sdim  // If we have a vmov, due to the many different cases, some of which
1331251662Sdim  // vary within the different intrinsics generated for a single
1332251662Sdim  // instruction type, just output a vmov. (e.g. given an instruction
1333251662Sdim  // A, A.u32 might be vmov and A.u8 might be vmov.8).
1334251662Sdim  //
1335251662Sdim  // FIXME: Maybe something can be done about this. The two cases that we care
1336251662Sdim  // about are vmov as an LType and vmov as a WType.
1337251662Sdim  if (Prefix == "vmov") {
1338251662Sdim    Result.push_back(Prefix + " " + RegisterSuffix);
1339251662Sdim    return;
1340251662Sdim  }
1341251662Sdim
1342251662Sdim  // In the following section, we handle special cases.
1343251662Sdim
1344251662Sdim  if (OutTypeCode == "64") {
1345251662Sdim    // If we have a 64 bit vdup/vext and are handling an uint64x1_t
1346251662Sdim    // type, the intrinsic will be optimized away, so just return
1347251662Sdim    // nothing.  On the other hand if we are handling an uint64x2_t
1348251662Sdim    // (i.e. quad instruction), vdup/vmov instructions should be
1349251662Sdim    // emitted.
1350251662Sdim    if (Prefix == "vdup" || Prefix == "vext") {
1351251662Sdim      if (IsQuad) {
1352251662Sdim        Result.push_back("{{vmov|vdup}}");
1353251662Sdim      }
1354251662Sdim      return;
1355251662Sdim    }
1356251662Sdim
1357251662Sdim    // v{st,ld}{2,3,4}_{u,s}64 emit v{st,ld}1.64 instructions with
1358251662Sdim    // multiple register operands.
1359251662Sdim    bool MultiLoadPrefix = Prefix == "vld2" || Prefix == "vld3"
1360251662Sdim                            || Prefix == "vld4";
1361251662Sdim    bool MultiStorePrefix = Prefix == "vst2" || Prefix == "vst3"
1362251662Sdim                            || Prefix == "vst4";
1363251662Sdim    if (MultiLoadPrefix || MultiStorePrefix) {
1364251662Sdim      Result.push_back(NameRef.slice(0, 3).str() + "1.64");
1365251662Sdim      return;
1366251662Sdim    }
1367251662Sdim
1368251662Sdim    // v{st,ld}1_{lane,dup}_{u64,s64} use vldr/vstr/vmov/str instead of
1369251662Sdim    // emitting said instructions. So return a check for
1370251662Sdim    // vldr/vstr/vmov/str instead.
1371251662Sdim    if (HasLanePostfix || HasDupPostfix) {
1372251662Sdim      if (Prefix == "vst1") {
1373251662Sdim        Result.push_back("{{str|vstr|vmov}}");
1374251662Sdim        return;
1375251662Sdim      } else if (Prefix == "vld1") {
1376251662Sdim        Result.push_back("{{ldr|vldr|vmov}}");
1377251662Sdim        return;
1378251662Sdim      }
1379251662Sdim    }
1380251662Sdim  }
1381251662Sdim
1382251662Sdim  // vzip.32/vuzp.32 are the same instruction as vtrn.32 and are
1383251662Sdim  // sometimes disassembled as vtrn.32. We use a regex to handle both
1384251662Sdim  // cases.
1385251662Sdim  if ((Prefix == "vzip" || Prefix == "vuzp") && OutTypeCode == "32") {
1386251662Sdim    Result.push_back("{{vtrn|" + Prefix + "}}.32 " + RegisterSuffix);
1387251662Sdim    return;
1388251662Sdim  }
1389251662Sdim
1390251662Sdim  // Currently on most ARM processors, we do not use vmla/vmls for
1391251662Sdim  // quad floating point operations. Instead we output vmul + vadd. So
1392251662Sdim  // check if we have one of those instructions and just output a
1393251662Sdim  // check for vmul.
1394251662Sdim  if (OutTypeCode == "f32") {
1395251662Sdim    if (Prefix == "vmls") {
1396251662Sdim      Result.push_back("vmul." + OutTypeCode + " " + RegisterSuffix);
1397251662Sdim      Result.push_back("vsub." + OutTypeCode);
1398251662Sdim      return;
1399251662Sdim    } else if (Prefix == "vmla") {
1400251662Sdim      Result.push_back("vmul." + OutTypeCode + " " + RegisterSuffix);
1401251662Sdim      Result.push_back("vadd." + OutTypeCode);
1402251662Sdim      return;
1403251662Sdim    }
1404251662Sdim  }
1405251662Sdim
1406251662Sdim  // If we have vcvt, get the input type from the instruction name
1407251662Sdim  // (which should be of the form instname_inputtype) and append it
1408251662Sdim  // before the output type.
1409251662Sdim  if (Prefix == "vcvt") {
1410251662Sdim    const std::string inTypeCode = NameRef.substr(NameRef.find_last_of("_")+1);
1411251662Sdim    Prefix += "." + inTypeCode;
1412251662Sdim  }
1413251662Sdim
1414251662Sdim  // Append output type code to get our final mangled instruction.
1415251662Sdim  Prefix += "." + OutTypeCode;
1416251662Sdim
1417251662Sdim  Result.push_back(Prefix + " " + RegisterSuffix);
1418251662Sdim}
1419251662Sdim
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, ...)"
1447263508Sdimstatic std::string GenArgs(const std::string &proto, StringRef typestr,
1448263508Sdim                           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);
1466263508Sdim    //To avoid argument being multiple defined, add extra number for renaming.
1467263508Sdim    if (name == "vcopy_lane" || name == "vcopy_laneq")
1468263508Sdim      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.
1479263508Sdimstatic std::string GenMacroLocals(const std::string &proto, StringRef typestr,
1480263508Sdim                                  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;
1491263508Sdim    bool extranumber = false;
1492263508Sdim    if (name == "vcopy_lane" || name == "vcopy_laneq")
1493263508Sdim      extranumber = true;
1494226586Sdim
1495226586Sdim    s += TypeString(proto[i], typestr) + " __";
1496226586Sdim    s.push_back(arg);
1497263508Sdim    if(extranumber)
1498263508Sdim      s.push_back('1');
1499226586Sdim    s += " = (";
1500226586Sdim    s.push_back(arg);
1501263508Sdim    if(extranumber)
1502263508Sdim      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.
1512263508Sdimstatic std::string Extend(StringRef typestr, const std::string &a, bool h=0) {
1513263508Sdim  std::string s, high;
1514263508Sdim  high = h ? "_high" : "";
1515263508Sdim  s = MangleName("vmovl" + high, typestr, ClassS);
1516263508Sdim  s += "(" + a + ")";
1517263508Sdim  return s;
1518263508Sdim}
1519263508Sdim
1520263508Sdim// Get the high 64-bit part of a vector
1521263508Sdimstatic std::string GetHigh(const std::string &a, StringRef typestr) {
1522226586Sdim  std::string s;
1523263508Sdim  s = MangleName("vget_high", typestr, ClassS);
1524226586Sdim  s += "(" + a + ")";
1525226586Sdim  return s;
1526226586Sdim}
1527226586Sdim
1528263508Sdim// Gen operation with two operands and get high 64-bit for both of two operands.
1529263508Sdimstatic std::string Gen2OpWith2High(StringRef typestr,
1530263508Sdim                                   const std::string &op,
1531263508Sdim                                   const std::string &a,
1532263508Sdim                                   const std::string &b) {
1533263508Sdim  std::string s;
1534263508Sdim  std::string Op1 = GetHigh(a, typestr);
1535263508Sdim  std::string Op2 = GetHigh(b, typestr);
1536263508Sdim  s = MangleName(op, typestr, ClassS);
1537263508Sdim  s += "(" + Op1 + ", " + Op2 + ");";
1538263508Sdim  return s;
1539263508Sdim}
1540263508Sdim
1541263508Sdim// Gen operation with three operands and get high 64-bit of the latter
1542263508Sdim// two operands.
1543263508Sdimstatic std::string Gen3OpWith2High(StringRef typestr,
1544263508Sdim                                   const std::string &op,
1545263508Sdim                                   const std::string &a,
1546263508Sdim                                   const std::string &b,
1547263508Sdim                                   const std::string &c) {
1548263508Sdim  std::string s;
1549263508Sdim  std::string Op1 = GetHigh(b, typestr);
1550263508Sdim  std::string Op2 = GetHigh(c, typestr);
1551263508Sdim  s = MangleName(op, typestr, ClassS);
1552263508Sdim  s += "(" + a + ", " + Op1 + ", " + Op2 + ");";
1553263508Sdim  return s;
1554263508Sdim}
1555263508Sdim
1556263508Sdim// Gen combine operation by putting a on low 64-bit, and b on high 64-bit.
1557263508Sdimstatic std::string GenCombine(std::string typestr,
1558263508Sdim                              const std::string &a,
1559263508Sdim                              const std::string &b) {
1560263508Sdim  std::string s;
1561263508Sdim  s = MangleName("vcombine", typestr, ClassS);
1562263508Sdim  s += "(" + a + ", " + b + ")";
1563263508Sdim  return s;
1564263508Sdim}
1565263508Sdim
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
1590263508Sdimstatic std::string RemoveHigh(const std::string &name) {
1591263508Sdim  std::string s = name;
1592263508Sdim  std::size_t found = s.find("_high_");
1593263508Sdim  if (found == std::string::npos)
1594263508Sdim    PrintFatalError("name should contain \"_high_\" for high intrinsics");
1595263508Sdim  s.replace(found, 5, "");
1596263508Sdim  return s;
1597263508Sdim}
1598263508Sdim
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;
1611263508Sdim  case 'd':
1612263508Sdim    nElts = 1;
1613263508Sdim    break;
1614226586Sdim  default:
1615243830Sdim    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.
1622263508Sdimstatic std::string GenOpString(const std::string &name, OpKind op,
1623263508Sdim                               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;
1641263508Sdim  case OpAddlHi:
1642263508Sdim    s += Extend(typestr, "__a", 1) + " + " + Extend(typestr, "__b", 1) + ";";
1643263508Sdim    break;
1644226586Sdim  case OpAddw:
1645226586Sdim    s += "__a + " + Extend(typestr, "__b") + ";";
1646226586Sdim    break;
1647263508Sdim  case OpAddwHi:
1648263508Sdim    s += "__a + " + Extend(typestr, "__b", 1) + ";";
1649263508Sdim    break;
1650226586Sdim  case OpSub:
1651226586Sdim    s += "__a - __b;";
1652226586Sdim    break;
1653226586Sdim  case OpSubl:
1654226586Sdim    s += Extend(typestr, "__a") + " - " + Extend(typestr, "__b") + ";";
1655226586Sdim    break;
1656263508Sdim  case OpSublHi:
1657263508Sdim    s += Extend(typestr, "__a", 1) + " - " + Extend(typestr, "__b", 1) + ";";
1658263508Sdim    break;
1659226586Sdim  case OpSubw:
1660226586Sdim    s += "__a - " + Extend(typestr, "__b") + ";";
1661226586Sdim    break;
1662263508Sdim  case OpSubwHi:
1663263508Sdim    s += "__a - " + Extend(typestr, "__b", 1) + ";";
1664263508Sdim    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;
1671263508Sdim  case OpMulXLane:
1672263508Sdim    s += MangleName("vmulx", typestr, ClassS) + "(__a, " +
1673263508Sdim      SplatLane(nElts, "__b", "__c") + ");";
1674263508Sdim    break;
1675226586Sdim  case OpMul:
1676226586Sdim    s += "__a * __b;";
1677226586Sdim    break;
1678263508Sdim  case OpFMlaN:
1679263508Sdim    s += MangleName("vfma", typestr, ClassS);
1680263508Sdim    s += "(__a, __b, " + Duplicate(nElts,typestr, "__c") + ");";
1681263508Sdim    break;
1682263508Sdim  case OpFMlsN:
1683263508Sdim    s += MangleName("vfms", typestr, ClassS);
1684263508Sdim    s += "(__a, __b, " + Duplicate(nElts,typestr, "__c") + ");";
1685263508Sdim    break;
1686226586Sdim  case OpMullLane:
1687226586Sdim    s += MangleName("vmull", typestr, ClassS) + "(__a, " +
1688226586Sdim      SplatLane(nElts, "__b", "__c") + ");";
1689226586Sdim    break;
1690263508Sdim  case OpMullHiLane:
1691263508Sdim    s += MangleName("vmull", typestr, ClassS) + "(" +
1692263508Sdim      GetHigh("__a", typestr) + ", " + SplatLane(nElts, "__b", "__c") + ");";
1693263508Sdim    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;
1711263508Sdim  case OpMlalHiLane:
1712263508Sdim    s += "__a + " + MangleName("vmull", typestr, ClassS) + "(" +
1713263508Sdim      GetHigh("__b", typestr) + ", " + SplatLane(nElts, "__c", "__d") + ");";
1714263508Sdim    break;
1715226586Sdim  case OpMlal:
1716226586Sdim    s += "__a + " + MangleName("vmull", typestr, ClassS) + "(__b, __c);";
1717226586Sdim    break;
1718263508Sdim  case OpMullHi:
1719263508Sdim    s += Gen2OpWith2High(typestr, "vmull", "__a", "__b");
1720263508Sdim    break;
1721263508Sdim  case OpMullHiN:
1722263508Sdim    s += MangleName("vmull_n", typestr, ClassS);
1723263508Sdim    s += "(" + GetHigh("__a", typestr) + ", __b);";
1724263508Sdim    return s;
1725263508Sdim  case OpMlalHi:
1726263508Sdim    s += Gen3OpWith2High(typestr, "vmlal", "__a", "__b", "__c");
1727263508Sdim    break;
1728263508Sdim  case OpMlalHiN:
1729263508Sdim    s += MangleName("vmlal_n", typestr, ClassS);
1730263508Sdim    s += "(__a, " + GetHigh("__b", typestr) + ", __c);";
1731263508Sdim    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;
1738263508Sdim  case OpFMSLane:
1739263508Sdim    s += TypeString(proto[1], typestr) + " __a1 = __a; \\\n  ";
1740263508Sdim    s += TypeString(proto[2], typestr) + " __b1 = __b; \\\n  ";
1741263508Sdim    s += TypeString(proto[3], typestr) + " __c1 = __c; \\\n  ";
1742263508Sdim    s += MangleName("vfma_lane", typestr, ClassS) + "(__a1, __b1, -__c1, __d);";
1743263508Sdim    break;
1744263508Sdim  case OpFMSLaneQ:
1745263508Sdim    s += TypeString(proto[1], typestr) + " __a1 = __a; \\\n  ";
1746263508Sdim    s += TypeString(proto[2], typestr) + " __b1 = __b; \\\n  ";
1747263508Sdim    s += TypeString(proto[3], typestr) + " __c1 = __c; \\\n  ";
1748263508Sdim    s += MangleName("vfma_laneq", typestr, ClassS) + "(__a1, __b1, -__c1, __d);";
1749263508Sdim    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;
1761263508Sdim  case OpMlslHiLane:
1762263508Sdim    s += "__a - " + MangleName("vmull", typestr, ClassS) + "(" +
1763263508Sdim      GetHigh("__b", typestr) + ", " + SplatLane(nElts, "__c", "__d") + ");";
1764263508Sdim    break;
1765226586Sdim  case OpMlsl:
1766226586Sdim    s += "__a - " + MangleName("vmull", typestr, ClassS) + "(__b, __c);";
1767226586Sdim    break;
1768263508Sdim  case OpMlslHi:
1769263508Sdim    s += Gen3OpWith2High(typestr, "vmlsl", "__a", "__b", "__c");
1770263508Sdim    break;
1771263508Sdim  case OpMlslHiN:
1772263508Sdim    s += MangleName("vmlsl_n", typestr, ClassS);
1773263508Sdim    s += "(__a, " + GetHigh("__b", typestr) + ", __c);";
1774263508Sdim    break;
1775226586Sdim  case OpQDMullLane:
1776226586Sdim    s += MangleName("vqdmull", typestr, ClassS) + "(__a, " +
1777226586Sdim      SplatLane(nElts, "__b", "__c") + ");";
1778226586Sdim    break;
1779263508Sdim  case OpQDMullHiLane:
1780263508Sdim    s += MangleName("vqdmull", typestr, ClassS) + "(" +
1781263508Sdim      GetHigh("__a", typestr) + ", " + SplatLane(nElts, "__b", "__c") + ");";
1782263508Sdim    break;
1783226586Sdim  case OpQDMlalLane:
1784226586Sdim    s += MangleName("vqdmlal", typestr, ClassS) + "(__a, __b, " +
1785226586Sdim      SplatLane(nElts, "__c", "__d") + ");";
1786226586Sdim    break;
1787263508Sdim  case OpQDMlalHiLane:
1788263508Sdim    s += MangleName("vqdmlal", typestr, ClassS) + "(__a, " +
1789263508Sdim      GetHigh("__b", typestr) + ", " + SplatLane(nElts, "__c", "__d") + ");";
1790263508Sdim    break;
1791226586Sdim  case OpQDMlslLane:
1792226586Sdim    s += MangleName("vqdmlsl", typestr, ClassS) + "(__a, __b, " +
1793226586Sdim      SplatLane(nElts, "__c", "__d") + ");";
1794226586Sdim    break;
1795263508Sdim  case OpQDMlslHiLane:
1796263508Sdim    s += MangleName("vqdmlsl", typestr, ClassS) + "(__a, " +
1797263508Sdim      GetHigh("__b", typestr) + ", " + SplatLane(nElts, "__c", "__d") + ");";
1798263508Sdim    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:
1851263508Sdim    // nElts is for the result vector, so the source is twice that number.
1852263508Sdim    s += "__builtin_shufflevector(__a, __a";
1853263508Sdim    for (unsigned i = nElts; i < nElts * 2; ++i)
1854263508Sdim      s += ", " + utostr(i);
1855263508Sdim    s+= ");";
1856226586Sdim    break;
1857226586Sdim  case OpLo:
1858263508Sdim    s += "__builtin_shufflevector(__a, __a";
1859263508Sdim    for (unsigned i = 0; i < nElts; ++i)
1860263508Sdim      s += ", " + utostr(i);
1861263508Sdim    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  }
1901263508Sdim  case OpXtnHi: {
1902263508Sdim    s = TypeString(proto[1], typestr) + " __a1 = " +
1903263508Sdim        MangleName("vmovn", typestr, ClassS) + "(__b);\n  " +
1904263508Sdim        "return __builtin_shufflevector(__a, __a1";
1905263508Sdim    for (unsigned i = 0; i < nElts * 4; ++i)
1906263508Sdim      s += ", " + utostr(i);
1907263508Sdim    s += ");";
1908263508Sdim    break;
1909263508Sdim  }
1910263508Sdim  case OpSqxtunHi: {
1911263508Sdim    s = TypeString(proto[1], typestr) + " __a1 = " +
1912263508Sdim        MangleName("vqmovun", typestr, ClassS) + "(__b);\n  " +
1913263508Sdim        "return __builtin_shufflevector(__a, __a1";
1914263508Sdim    for (unsigned i = 0; i < nElts * 4; ++i)
1915263508Sdim      s += ", " + utostr(i);
1916263508Sdim    s += ");";
1917263508Sdim    break;
1918263508Sdim  }
1919263508Sdim  case OpQxtnHi: {
1920263508Sdim    s = TypeString(proto[1], typestr) + " __a1 = " +
1921263508Sdim        MangleName("vqmovn", typestr, ClassS) + "(__b);\n  " +
1922263508Sdim        "return __builtin_shufflevector(__a, __a1";
1923263508Sdim    for (unsigned i = 0; i < nElts * 4; ++i)
1924263508Sdim      s += ", " + utostr(i);
1925263508Sdim    s += ");";
1926263508Sdim    break;
1927263508Sdim  }
1928263508Sdim  case OpFcvtnHi: {
1929263508Sdim    std::string FName = (nElts == 1) ? "vcvt_f32" : "vcvt_f16";
1930263508Sdim    s = TypeString(proto[1], typestr) + " __a1 = " +
1931263508Sdim        MangleName(FName, typestr, ClassS) + "(__b);\n  " +
1932263508Sdim        "return __builtin_shufflevector(__a, __a1";
1933263508Sdim    for (unsigned i = 0; i < nElts * 4; ++i)
1934263508Sdim      s += ", " + utostr(i);
1935263508Sdim    s += ");";
1936263508Sdim    break;
1937263508Sdim  }
1938263508Sdim  case OpFcvtlHi: {
1939263508Sdim    std::string FName = (nElts == 2) ? "vcvt_f64" : "vcvt_f32";
1940263508Sdim    s = TypeString('d', typestr) + " __a1 = " + GetHigh("__a", typestr) +
1941263508Sdim        ";\n  return " + MangleName(FName, typestr, ClassS) + "(__a1);";
1942263508Sdim    break;
1943263508Sdim  }
1944263508Sdim  case OpFcvtxnHi: {
1945263508Sdim    s = TypeString(proto[1], typestr) + " __a1 = " +
1946263508Sdim        MangleName("vcvtx_f32", typestr, ClassS) + "(__b);\n  " +
1947263508Sdim        "return __builtin_shufflevector(__a, __a1";
1948263508Sdim    for (unsigned i = 0; i < nElts * 4; ++i)
1949263508Sdim      s += ", " + utostr(i);
1950263508Sdim    s += ");";
1951263508Sdim    break;
1952263508Sdim  }
1953263508Sdim  case OpUzp1:
1954263508Sdim    s += "__builtin_shufflevector(__a, __b";
1955263508Sdim    for (unsigned i = 0; i < nElts; i++)
1956263508Sdim      s += ", " + utostr(2*i);
1957263508Sdim    s += ");";
1958263508Sdim    break;
1959263508Sdim  case OpUzp2:
1960263508Sdim    s += "__builtin_shufflevector(__a, __b";
1961263508Sdim    for (unsigned i = 0; i < nElts; i++)
1962263508Sdim      s += ", " + utostr(2*i+1);
1963263508Sdim    s += ");";
1964263508Sdim    break;
1965263508Sdim  case OpZip1:
1966263508Sdim    s += "__builtin_shufflevector(__a, __b";
1967263508Sdim    for (unsigned i = 0; i < (nElts/2); i++)
1968263508Sdim       s += ", " + utostr(i) + ", " + utostr(i+nElts);
1969263508Sdim    s += ");";
1970263508Sdim    break;
1971263508Sdim  case OpZip2:
1972263508Sdim    s += "__builtin_shufflevector(__a, __b";
1973263508Sdim    for (unsigned i = nElts/2; i < nElts; i++)
1974263508Sdim       s += ", " + utostr(i) + ", " + utostr(i+nElts);
1975263508Sdim    s += ");";
1976263508Sdim    break;
1977263508Sdim  case OpTrn1:
1978263508Sdim    s += "__builtin_shufflevector(__a, __b";
1979263508Sdim    for (unsigned i = 0; i < (nElts/2); i++)
1980263508Sdim       s += ", " + utostr(2*i) + ", " + utostr(2*i+nElts);
1981263508Sdim    s += ");";
1982263508Sdim    break;
1983263508Sdim  case OpTrn2:
1984263508Sdim    s += "__builtin_shufflevector(__a, __b";
1985263508Sdim    for (unsigned i = 0; i < (nElts/2); i++)
1986263508Sdim       s += ", " + utostr(2*i+1) + ", " + utostr(2*i+1+nElts);
1987263508Sdim    s += ");";
1988263508Sdim    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  }
2002263508Sdim  case OpAbdlHi:
2003263508Sdim    s += Gen2OpWith2High(typestr, "vabdl", "__a", "__b");
2004263508Sdim    break;
2005263508Sdim  case OpAddhnHi: {
2006263508Sdim    std::string addhn = MangleName("vaddhn", typestr, ClassS) + "(__b, __c)";
2007263508Sdim    s += GenCombine(GetNarrowTypestr(typestr), "__a", addhn);
2008263508Sdim    s += ";";
2009263508Sdim    break;
2010263508Sdim  }
2011263508Sdim  case OpRAddhnHi: {
2012263508Sdim    std::string raddhn = MangleName("vraddhn", typestr, ClassS) + "(__b, __c)";
2013263508Sdim    s += GenCombine(GetNarrowTypestr(typestr), "__a", raddhn);
2014263508Sdim    s += ";";
2015263508Sdim    break;
2016263508Sdim  }
2017263508Sdim  case OpSubhnHi: {
2018263508Sdim    std::string subhn = MangleName("vsubhn", typestr, ClassS) + "(__b, __c)";
2019263508Sdim    s += GenCombine(GetNarrowTypestr(typestr), "__a", subhn);
2020263508Sdim    s += ";";
2021263508Sdim    break;
2022263508Sdim  }
2023263508Sdim  case OpRSubhnHi: {
2024263508Sdim    std::string rsubhn = MangleName("vrsubhn", typestr, ClassS) + "(__b, __c)";
2025263508Sdim    s += GenCombine(GetNarrowTypestr(typestr), "__a", rsubhn);
2026263508Sdim    s += ";";
2027263508Sdim    break;
2028263508Sdim  }
2029226586Sdim  case OpAba:
2030226586Sdim    s += "__a + " + MangleName("vabd", typestr, ClassS) + "(__b, __c);";
2031226586Sdim    break;
2032263508Sdim  case OpAbal:
2033263508Sdim    s += "__a + " + MangleName("vabdl", typestr, ClassS) + "(__b, __c);";
2034263508Sdim    break;
2035263508Sdim  case OpAbalHi:
2036263508Sdim    s += Gen3OpWith2High(typestr, "vabal", "__a", "__b", "__c");
2037263508Sdim    break;
2038263508Sdim  case OpQDMullHi:
2039263508Sdim    s += Gen2OpWith2High(typestr, "vqdmull", "__a", "__b");
2040263508Sdim    break;
2041263508Sdim  case OpQDMullHiN:
2042263508Sdim    s += MangleName("vqdmull_n", typestr, ClassS);
2043263508Sdim    s += "(" + GetHigh("__a", typestr) + ", __b);";
2044263508Sdim    return s;
2045263508Sdim  case OpQDMlalHi:
2046263508Sdim    s += Gen3OpWith2High(typestr, "vqdmlal", "__a", "__b", "__c");
2047263508Sdim    break;
2048263508Sdim  case OpQDMlalHiN:
2049263508Sdim    s += MangleName("vqdmlal_n", typestr, ClassS);
2050263508Sdim    s += "(__a, " + GetHigh("__b", typestr) + ", __c);";
2051263508Sdim    return s;
2052263508Sdim  case OpQDMlslHi:
2053263508Sdim    s += Gen3OpWith2High(typestr, "vqdmlsl", "__a", "__b", "__c");
2054263508Sdim    break;
2055263508Sdim  case OpQDMlslHiN:
2056263508Sdim    s += MangleName("vqdmlsl_n", typestr, ClassS);
2057263508Sdim    s += "(__a, " + GetHigh("__b", typestr) + ", __c);";
2058263508Sdim    return s;
2059263508Sdim  case OpDiv:
2060263508Sdim    s += "__a / __b;";
2061263508Sdim    break;
2062263508Sdim  case OpMovlHi: {
2063263508Sdim    s = TypeString(proto[1], typestr.drop_front()) + " __a1 = " +
2064263508Sdim        MangleName("vget_high", typestr, ClassS) + "(__a);\n  " + s;
2065263508Sdim    s += "(" + ts + ")" + MangleName("vshll_n", typestr, ClassS);
2066263508Sdim    s += "(__a1, 0);";
2067263508Sdim    break;
2068263508Sdim  }
2069263508Sdim  case OpLongHi: {
2070263508Sdim    // Another local variable __a1 is needed for calling a Macro,
2071263508Sdim    // or using __a will have naming conflict when Macro expanding.
2072263508Sdim    s += TypeString(proto[1], typestr.drop_front()) + " __a1 = " +
2073263508Sdim         MangleName("vget_high", typestr, ClassS) + "(__a); \\\n";
2074263508Sdim    s += "  (" + ts + ")" + MangleName(RemoveHigh(name), typestr, ClassS) +
2075263508Sdim         "(__a1, __b);";
2076263508Sdim    break;
2077263508Sdim  }
2078263508Sdim  case OpNarrowHi: {
2079263508Sdim    s += "(" + ts + ")" + MangleName("vcombine", typestr, ClassS) + "(__a, " +
2080263508Sdim         MangleName(RemoveHigh(name), typestr, ClassS) + "(__b, __c));";
2081263508Sdim    break;
2082263508Sdim  }
2083263508Sdim  case OpCopyLane: {
2084263508Sdim    s += TypeString('s', typestr) + " __c2 = " +
2085263508Sdim         MangleName("vget_lane", typestr, ClassS) + "(__c1, __d1); \\\n  " +
2086263508Sdim         MangleName("vset_lane", typestr, ClassS) + "(__c2, __a1, __b1);";
2087263508Sdim    break;
2088263508Sdim  }
2089263508Sdim  case OpCopyQLane: {
2090263508Sdim    std::string typeCode = "";
2091263508Sdim    InstructionTypeCode(typestr, ClassS, quad, typeCode);
2092263508Sdim    s += TypeString('s', typestr) + " __c2 = vget_lane_" + typeCode +
2093263508Sdim         "(__c1, __d1); \\\n  vsetq_lane_" + typeCode + "(__c2, __a1, __b1);";
2094263508Sdim    break;
2095263508Sdim  }
2096263508Sdim  case OpCopyLaneQ: {
2097263508Sdim    std::string typeCode = "";
2098263508Sdim    InstructionTypeCode(typestr, ClassS, quad, typeCode);
2099263508Sdim    s += TypeString('s', typestr) + " __c2 = vgetq_lane_" + typeCode +
2100263508Sdim         "(__c1, __d1); \\\n  vset_lane_" + typeCode + "(__c2, __a1, __b1);";
2101263508Sdim    break;
2102263508Sdim  }
2103263508Sdim  case OpScalarMulLane: {
2104263508Sdim    std::string typeCode = "";
2105263508Sdim    InstructionTypeCode(typestr, ClassS, quad, typeCode);
2106263508Sdim    s += TypeString('s', typestr) + " __d1 = vget_lane_" + typeCode +
2107263508Sdim      "(__b, __c);\\\n  __a * __d1;";
2108263508Sdim    break;
2109263508Sdim  }
2110263508Sdim  case OpScalarMulLaneQ: {
2111263508Sdim    std::string typeCode = "";
2112263508Sdim    InstructionTypeCode(typestr, ClassS, quad, typeCode);
2113263508Sdim        s += TypeString('s', typestr) + " __d1 = vgetq_lane_" + typeCode +
2114263508Sdim          "(__b, __c);\\\n  __a * __d1;";
2115263508Sdim    break;
2116263508Sdim  }
2117263508Sdim  case OpScalarMulXLane: {
2118263508Sdim    bool dummy = false;
2119263508Sdim    char type = ClassifyType(typestr, dummy, dummy, dummy);
2120263508Sdim    if (type == 'f') type = 's';
2121263508Sdim    std::string typeCode = "";
2122263508Sdim    InstructionTypeCode(typestr, ClassS, quad, typeCode);
2123263508Sdim    s += TypeString('s', typestr) + " __d1 = vget_lane_" + typeCode +
2124263508Sdim      "(__b, __c);\\\n  vmulx" + type + "_" +
2125263508Sdim      typeCode +  "(__a, __d1);";
2126263508Sdim    break;
2127263508Sdim  }
2128263508Sdim  case OpScalarMulXLaneQ: {
2129263508Sdim    bool dummy = false;
2130263508Sdim    char type = ClassifyType(typestr, dummy, dummy, dummy);
2131263508Sdim    if (type == 'f') type = 's';
2132263508Sdim    std::string typeCode = "";
2133263508Sdim    InstructionTypeCode(typestr, ClassS, quad, typeCode);
2134263508Sdim    s += TypeString('s', typestr) + " __d1 = vgetq_lane_" +
2135263508Sdim      typeCode + "(__b, __c);\\\n  vmulx" + type +
2136263508Sdim      "_" + typeCode +  "(__a, __d1);";
2137263508Sdim    break;
2138263508Sdim  }
2139263508Sdim
2140263508Sdim  case OpScalarVMulXLane: {
2141263508Sdim    bool dummy = false;
2142263508Sdim    char type = ClassifyType(typestr, dummy, dummy, dummy);
2143263508Sdim    if (type == 'f') type = 's';
2144263508Sdim    std::string typeCode = "";
2145263508Sdim    InstructionTypeCode(typestr, ClassS, quad, typeCode);
2146263508Sdim    s += TypeString('s', typestr) + " __d1 = vget_lane_" +
2147263508Sdim      typeCode + "(__a, 0);\\\n" +
2148263508Sdim      "  " + TypeString('s', typestr) + " __e1 = vget_lane_" +
2149263508Sdim      typeCode + "(__b, __c);\\\n" +
2150263508Sdim      "  " + TypeString('s', typestr) + " __f1 = vmulx" + type + "_" +
2151263508Sdim      typeCode + "(__d1, __e1);\\\n" +
2152263508Sdim      "  " + TypeString('d', typestr) + " __g1;\\\n" +
2153263508Sdim      "  vset_lane_" + typeCode + "(__f1, __g1, __c);";
2154263508Sdim    break;
2155263508Sdim  }
2156263508Sdim
2157263508Sdim  case OpScalarVMulXLaneQ: {
2158263508Sdim    bool dummy = false;
2159263508Sdim    char type = ClassifyType(typestr, dummy, dummy, dummy);
2160263508Sdim    if (type == 'f') type = 's';
2161263508Sdim    std::string typeCode = "";
2162263508Sdim    InstructionTypeCode(typestr, ClassS, quad, typeCode);
2163263508Sdim    s += TypeString('s', typestr) + " __d1 = vget_lane_" +
2164263508Sdim      typeCode + "(__a, 0);\\\n" +
2165263508Sdim      "  " + TypeString('s', typestr) + " __e1 = vgetq_lane_" +
2166263508Sdim      typeCode + "(__b, __c);\\\n" +
2167263508Sdim      "  " + TypeString('s', typestr) + " __f1 = vmulx" + type + "_" +
2168263508Sdim      typeCode + "(__d1, __e1);\\\n" +
2169263508Sdim      "  " + TypeString('d', typestr) + " __g1;\\\n" +
2170263508Sdim      "  vset_lane_" + typeCode + "(__f1, __g1, 0);";
2171263508Sdim    break;
2172263508Sdim  }
2173263508Sdim  case OpScalarQDMullLane: {
2174263508Sdim    std::string typeCode = "";
2175263508Sdim    InstructionTypeCode(typestr, ClassS, quad, typeCode);
2176263508Sdim    s += MangleName("vqdmull", typestr, ClassS) + "(__a, " +
2177263508Sdim    "vget_lane_" + typeCode + "(b, __c));";
2178263508Sdim    break;
2179263508Sdim  }
2180263508Sdim  case OpScalarQDMullLaneQ: {
2181263508Sdim    std::string typeCode = "";
2182263508Sdim    InstructionTypeCode(typestr, ClassS, quad, typeCode);
2183263508Sdim    s += MangleName("vqdmull", typestr, ClassS) + "(__a, " +
2184263508Sdim    "vgetq_lane_" + typeCode + "(b, __c));";
2185263508Sdim    break;
2186263508Sdim  }
2187263508Sdim  case OpScalarQDMulHiLane: {
2188263508Sdim    std::string typeCode = "";
2189263508Sdim    InstructionTypeCode(typestr, ClassS, quad, typeCode);
2190263508Sdim    s += MangleName("vqdmulh", typestr, ClassS) + "(__a, " +
2191263508Sdim    "vget_lane_" + typeCode + "(__b, __c));";
2192263508Sdim    break;
2193263508Sdim  }
2194263508Sdim  case OpScalarQDMulHiLaneQ: {
2195263508Sdim    std::string typeCode = "";
2196263508Sdim    InstructionTypeCode(typestr, ClassS, quad, typeCode);
2197263508Sdim    s += MangleName("vqdmulh", typestr, ClassS) + "(__a, " +
2198263508Sdim    "vgetq_lane_" + typeCode + "(__b, __c));";
2199263508Sdim    break;
2200263508Sdim  }
2201263508Sdim  case OpScalarQRDMulHiLane: {
2202263508Sdim    std::string typeCode = "";
2203263508Sdim    InstructionTypeCode(typestr, ClassS, quad, typeCode);
2204263508Sdim    s += MangleName("vqrdmulh", typestr, ClassS) + "(__a, " +
2205263508Sdim    "vget_lane_" + typeCode + "(__b, __c));";
2206263508Sdim    break;
2207263508Sdim  }
2208263508Sdim  case OpScalarQRDMulHiLaneQ: {
2209263508Sdim    std::string typeCode = "";
2210263508Sdim    InstructionTypeCode(typestr, ClassS, quad, typeCode);
2211263508Sdim    s += MangleName("vqrdmulh", typestr, ClassS) + "(__a, " +
2212263508Sdim    "vgetq_lane_" + typeCode + "(__b, __c));";
2213263508Sdim    break;
2214263508Sdim  }
2215263508Sdim  case OpScalarGetLane:{
2216263508Sdim    std::string typeCode = "";
2217263508Sdim    InstructionTypeCode(typestr, ClassS, quad, typeCode);
2218263508Sdim    if (quad) {
2219263508Sdim     s += "int16x8_t __a1 = vreinterpretq_s16_f16(__a);\\\n";
2220263508Sdim     s += "  vgetq_lane_s16(__a1, __b);";
2221226586Sdim    } else {
2222263508Sdim     s += "int16x4_t __a1 = vreinterpret_s16_f16(__a);\\\n";
2223263508Sdim     s += "  vget_lane_s16(__a1, __b);";
2224226586Sdim    }
2225226586Sdim    break;
2226226586Sdim  }
2227263508Sdim  case OpScalarSetLane:{
2228263508Sdim    std::string typeCode = "";
2229263508Sdim    InstructionTypeCode(typestr, ClassS, quad, typeCode);
2230263508Sdim    s += "int16_t __a1 = (int16_t)__a;\\\n";
2231263508Sdim    if (quad) {
2232263508Sdim     s += "  int16x8_t __b1 = vreinterpretq_s16_f16(b);\\\n";
2233263508Sdim     s += "  int16x8_t __b2 = vsetq_lane_s16(__a1, __b1, __c);\\\n";
2234263508Sdim     s += "  vreinterpretq_f16_s16(__b2);";
2235263508Sdim    } else {
2236263508Sdim     s += "  int16x4_t __b1 = vreinterpret_s16_f16(b);\\\n";
2237263508Sdim     s += "  int16x4_t __b2 = vset_lane_s16(__a1, __b1, __c);\\\n";
2238263508Sdim     s += "  vreinterpret_f16_s16(__b2);";
2239263508Sdim    }
2240263508Sdim    break;
2241263508Sdim  }
2242263508Sdim
2243226586Sdim  default:
2244243830Sdim    PrintFatalError("unknown OpKind!");
2245226586Sdim  }
2246226586Sdim  return s;
2247226586Sdim}
2248226586Sdim
2249226586Sdimstatic unsigned GetNeonEnum(const std::string &proto, StringRef typestr) {
2250226586Sdim  unsigned mod = proto[0];
2251226586Sdim
2252263508Sdim  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
2268234353Sdim  NeonTypeFlags::EltType ET;
2269226586Sdim  switch (type) {
2270226586Sdim    case 'c':
2271234353Sdim      ET = poly ? NeonTypeFlags::Poly8 : NeonTypeFlags::Int8;
2272226586Sdim      break;
2273226586Sdim    case 's':
2274234353Sdim      ET = poly ? NeonTypeFlags::Poly16 : NeonTypeFlags::Int16;
2275226586Sdim      break;
2276226586Sdim    case 'i':
2277234353Sdim      ET = NeonTypeFlags::Int32;
2278226586Sdim      break;
2279226586Sdim    case 'l':
2280263508Sdim      ET = poly ? NeonTypeFlags::Poly64 : NeonTypeFlags::Int64;
2281226586Sdim      break;
2282226586Sdim    case 'h':
2283234353Sdim      ET = NeonTypeFlags::Float16;
2284226586Sdim      break;
2285226586Sdim    case 'f':
2286234353Sdim      ET = NeonTypeFlags::Float32;
2287226586Sdim      break;
2288263508Sdim    case 'd':
2289263508Sdim      ET = NeonTypeFlags::Float64;
2290263508Sdim      break;
2291226586Sdim    default:
2292243830Sdim      PrintFatalError("unhandled type!");
2293226586Sdim  }
2294234353Sdim  NeonTypeFlags Flags(ET, usgn, quad && proto[1] != 'g');
2295234353Sdim  return Flags.getFlags();
2296226586Sdim}
2297226586Sdim
2298263508Sdim// We don't check 'a' in this function, because for builtin function the
2299263508Sdim// argument matching to 'a' uses a vector type splatted from a scalar type.
2300263508Sdimstatic bool ProtoHasScalar(const std::string proto)
2301263508Sdim{
2302263508Sdim  return (proto.find('s') != std::string::npos
2303263508Sdim          || proto.find('z') != std::string::npos
2304263508Sdim          || proto.find('r') != std::string::npos
2305263508Sdim          || proto.find('b') != std::string::npos
2306263508Sdim          || proto.find('$') != std::string::npos
2307263508Sdim          || proto.find('y') != std::string::npos
2308263508Sdim          || proto.find('o') != std::string::npos);
2309263508Sdim}
2310263508Sdim
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.
2318263508Sdim  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.
2325263508Sdim  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.
2378263508Sdim    unsigned NumOfVec = 0;
2379226586Sdim    if (proto[i] >= '2' && proto[i] <= '4') {
2380263508Sdim      NumOfVec = proto[i] - '0';
2381263508Sdim    } else if (proto[i] >= 'B' && proto[i] <= 'D') {
2382263508Sdim      NumOfVec = proto[i] - 'A' + 1;
2383263508Sdim    }
2384263508Sdim
2385263508Sdim    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
2390263508Sdim      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.
2443263508Sdim  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() && "");
2465239462Sdim  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
2487263508Sdim  s += GenArgs(proto, inTypeStr, name);
2488226586Sdim
2489226586Sdim  // Definition.
2490226586Sdim  if (define) {
2491226586Sdim    s += " __extension__ ({ \\\n  ";
2492263508Sdim    s += GenMacroLocals(proto, inTypeStr, name);
2493239462Sdim  } else if (kind == OpUnavailable) {
2494239462Sdim    s += " __attribute__((unavailable));\n";
2495239462Sdim    return s;
2496239462Sdim  } else
2497239462Sdim    s += " {\n  ";
2498226586Sdim
2499226586Sdim  if (kind != OpNone)
2500263508Sdim    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
2554263508Sdim  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";
2562263508Sdim  OS << "typedef __fp16 float16_t;\n";
2563263508Sdim
2564263508Sdim  OS << "#ifdef __aarch64__\n";
2565263508Sdim  OS << "typedef double float64_t;\n";
2566263508Sdim  OS << "#endif\n\n";
2567263508Sdim
2568263508Sdim  // For now, signedness of polynomial types depends on target
2569263508Sdim  OS << "#ifdef __aarch64__\n";
2570263508Sdim  OS << "typedef uint8_t poly8_t;\n";
2571263508Sdim  OS << "typedef uint16_t poly16_t;\n";
2572263508Sdim  OS << "typedef uint64_t poly64_t;\n";
2573263508Sdim  OS << "#else\n";
2574226586Sdim  OS << "typedef int8_t poly8_t;\n";
2575226586Sdim  OS << "typedef int16_t poly16_t;\n";
2576263508Sdim  OS << "#endif\n";
2577226586Sdim
2578226586Sdim  // Emit Neon vector typedefs.
2579263508Sdim  std::string TypedefTypes(
2580263508Sdim      "cQcsQsiQilQlUcQUcUsQUsUiQUiUlQUlhQhfQfdQdPcQPcPsQPsPlQPl");
2581226586Sdim  SmallVector<StringRef, 24> TDTypeVec;
2582226586Sdim  ParseTypes(0, TypedefTypes, TDTypeVec);
2583226586Sdim
2584226586Sdim  // Emit vector typedefs.
2585263508Sdim  bool isA64 = false;
2586263508Sdim  bool preinsert;
2587263508Sdim  bool postinsert;
2588226586Sdim  for (unsigned i = 0, e = TDTypeVec.size(); i != e; ++i) {
2589226586Sdim    bool dummy, quad = false, poly = false;
2590263508Sdim    char type = ClassifyType(TDTypeVec[i], quad, poly, dummy);
2591263508Sdim    preinsert = false;
2592263508Sdim    postinsert = false;
2593263508Sdim
2594263508Sdim    if (type == 'd' || (type == 'l' && poly)) {
2595263508Sdim      preinsert = isA64? false: true;
2596263508Sdim      isA64 = true;
2597263508Sdim    } else {
2598263508Sdim      postinsert = isA64? true: false;
2599263508Sdim      isA64 = false;
2600263508Sdim    }
2601263508Sdim    if (postinsert)
2602263508Sdim      OS << "#endif\n";
2603263508Sdim    if (preinsert)
2604263508Sdim      OS << "#ifdef __aarch64__\n";
2605263508Sdim
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";
2618263508Sdim
2619226586Sdim  }
2620263508Sdim  postinsert = isA64? true: false;
2621263508Sdim  if (postinsert)
2622263508Sdim    OS << "#endif\n";
2623226586Sdim  OS << "\n";
2624226586Sdim
2625226586Sdim  // Emit struct typedefs.
2626263508Sdim  isA64 = false;
2627226586Sdim  for (unsigned vi = 2; vi != 5; ++vi) {
2628226586Sdim    for (unsigned i = 0, e = TDTypeVec.size(); i != e; ++i) {
2629263508Sdim      bool dummy, quad = false, poly = false;
2630263508Sdim      char type = ClassifyType(TDTypeVec[i], quad, poly, dummy);
2631263508Sdim      preinsert = false;
2632263508Sdim      postinsert = false;
2633263508Sdim
2634263508Sdim      if (type == 'd' || (type == 'l' && poly)) {
2635263508Sdim        preinsert = isA64? false: true;
2636263508Sdim        isA64 = true;
2637263508Sdim      } else {
2638263508Sdim        postinsert = isA64? true: false;
2639263508Sdim        isA64 = false;
2640263508Sdim      }
2641263508Sdim      if (postinsert)
2642263508Sdim        OS << "#endif\n";
2643263508Sdim      if (preinsert)
2644263508Sdim        OS << "#ifdef __aarch64__\n";
2645263508Sdim
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} ";
2652263508Sdim      OS << vs << ";\n";
2653263508Sdim      OS << "\n";
2654226586Sdim    }
2655226586Sdim  }
2656263508Sdim  postinsert = isA64? true: false;
2657263508Sdim  if (postinsert)
2658263508Sdim    OS << "#endif\n";
2659263508Sdim  OS << "\n";
2660226586Sdim
2661251662Sdim  OS<<"#define __ai static inline __attribute__((__always_inline__, __nodebug__))\n\n";
2662226586Sdim
2663226586Sdim  std::vector<Record*> RV = Records.getAllDerivedDefinitions("Inst");
2664226586Sdim
2665263508Sdim  StringMap<ClassKind> EmittedMap;
2666263508Sdim
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.)
2672263508Sdim  emitIntrinsic(OS, Records.getDef("VMOVL"), EmittedMap);
2673263508Sdim  emitIntrinsic(OS, Records.getDef("VMULL"), EmittedMap);
2674263508Sdim  emitIntrinsic(OS, Records.getDef("VABD"), EmittedMap);
2675263508Sdim  emitIntrinsic(OS, Records.getDef("VABDL"), EmittedMap);
2676226586Sdim
2677263508Sdim  // ARM intrinsics must be emitted before AArch64 intrinsics to ensure
2678263508Sdim  // common intrinsics appear only once in the output stream.
2679263508Sdim  // The check for uniquiness is done in emitIntrinsic.
2680263508Sdim  // Emit ARM intrinsics.
2681226586Sdim  for (unsigned i = 0, e = RV.size(); i != e; ++i) {
2682226586Sdim    Record *R = RV[i];
2683263508Sdim
2684263508Sdim    // Skip AArch64 intrinsics; they will be emitted at the end.
2685263508Sdim    bool isA64 = R->getValueAsBit("isA64");
2686263508Sdim    if (isA64)
2687263508Sdim      continue;
2688263508Sdim
2689263508Sdim    if (R->getName() != "VMOVL" && R->getName() != "VMULL" &&
2690226586Sdim        R->getName() != "VABD")
2691263508Sdim      emitIntrinsic(OS, R, EmittedMap);
2692226586Sdim  }
2693226586Sdim
2694263508Sdim  // Emit AArch64-specific intrinsics.
2695263508Sdim  OS << "#ifdef __aarch64__\n";
2696263508Sdim
2697263508Sdim  emitIntrinsic(OS, Records.getDef("VMOVL_HIGH"), EmittedMap);
2698263508Sdim  emitIntrinsic(OS, Records.getDef("VMULL_HIGH"), EmittedMap);
2699263508Sdim  emitIntrinsic(OS, Records.getDef("VABDL_HIGH"), EmittedMap);
2700263508Sdim
2701263508Sdim  for (unsigned i = 0, e = RV.size(); i != e; ++i) {
2702263508Sdim    Record *R = RV[i];
2703263508Sdim
2704263508Sdim    // Skip ARM intrinsics already included above.
2705263508Sdim    bool isA64 = R->getValueAsBit("isA64");
2706263508Sdim    if (!isA64)
2707263508Sdim      continue;
2708263508Sdim
2709263508Sdim    // Skip crypto temporarily, and will emit them all together at the end.
2710263508Sdim    bool isCrypto = R->getValueAsBit("isCrypto");
2711263508Sdim    if (isCrypto)
2712263508Sdim      continue;
2713263508Sdim
2714263508Sdim    emitIntrinsic(OS, R, EmittedMap);
2715263508Sdim  }
2716263508Sdim
2717263508Sdim  OS << "#ifdef __ARM_FEATURE_CRYPTO\n";
2718263508Sdim
2719263508Sdim  for (unsigned i = 0, e = RV.size(); i != e; ++i) {
2720263508Sdim    Record *R = RV[i];
2721263508Sdim
2722263508Sdim    // Skip crypto temporarily, and will emit them all together at the end.
2723263508Sdim    bool isCrypto = R->getValueAsBit("isCrypto");
2724263508Sdim    if (!isCrypto)
2725263508Sdim      continue;
2726263508Sdim
2727263508Sdim    emitIntrinsic(OS, R, EmittedMap);
2728263508Sdim  }
2729263508Sdim
2730263508Sdim  OS << "#endif\n\n";
2731263508Sdim
2732263508Sdim  OS << "#endif\n\n";
2733263508Sdim
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
2739263508Sdim/// intrinsics specified by record R checking for intrinsic uniqueness.
2740263508Sdimvoid NeonEmitter::emitIntrinsic(raw_ostream &OS, Record *R,
2741263508Sdim                                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)
2755243830Sdim    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;
2768263508Sdim        std::string s = GenIntrinsic(name, Proto, TypeVec[ti], TypeVec[srcti],
2769263508Sdim                                     OpCast, ClassS);
2770263508Sdim        if (EmittedMap.count(s))
2771263508Sdim          continue;
2772263508Sdim        EmittedMap[s] = ClassS;
2773263508Sdim        OS << s;
2774226586Sdim      }
2775226586Sdim    } else {
2776263508Sdim      std::string s =
2777263508Sdim          GenIntrinsic(name, Proto, TypeVec[ti], TypeVec[ti], kind, classKind);
2778263508Sdim      if (EmittedMap.count(s))
2779263508Sdim        continue;
2780263508Sdim      EmittedMap[s] = classKind;
2781263508Sdim      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;
2802263508Sdim    case 'd':
2803226586Sdim    case 'l':
2804226586Sdim      return (1 << (int)quad) - 1;
2805226586Sdim    default:
2806243830Sdim      PrintFatalError("unhandled type!");
2807226586Sdim  }
2808226586Sdim}
2809226586Sdim
2810263508Sdimstatic unsigned RangeScalarShiftImm(const char mod, StringRef typestr) {
2811263508Sdim  // base type to get the type string for.
2812263508Sdim  bool dummy = false;
2813263508Sdim  char type = ClassifyType(typestr, dummy, dummy, dummy);
2814263508Sdim  type = ModType(mod, type, dummy, dummy, dummy, dummy, dummy, dummy);
2815226586Sdim
2816263508Sdim  switch (type) {
2817263508Sdim    case 'c':
2818263508Sdim      return 7;
2819263508Sdim    case 'h':
2820263508Sdim    case 's':
2821263508Sdim      return 15;
2822263508Sdim    case 'f':
2823263508Sdim    case 'i':
2824263508Sdim      return 31;
2825263508Sdim    case 'd':
2826263508Sdim    case 'l':
2827263508Sdim      return 63;
2828263508Sdim    default:
2829263508Sdim      PrintFatalError("unhandled type!");
2830263508Sdim  }
2831263508Sdim}
2832263508Sdim
2833263508Sdim/// Generate the ARM and AArch64 intrinsic range checking code for
2834263508Sdim/// shift/lane immediates, checking for unique declarations.
2835263508Sdimvoid
2836263508SdimNeonEmitter::genIntrinsicRangeCheckCode(raw_ostream &OS,
2837263508Sdim                                        StringMap<ClassKind> &A64IntrinsicMap,
2838263508Sdim                                        bool isA64RangeCheck) {
2839263508Sdim  std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst");
2840226586Sdim  StringMap<OpKind> EmittedMap;
2841226586Sdim
2842263508Sdim  // Generate the intrinsic range checking code for shift/lane immediates.
2843263508Sdim  if (isA64RangeCheck)
2844263508Sdim    OS << "#ifdef GET_NEON_AARCH64_IMMEDIATE_CHECK\n";
2845263508Sdim  else
2846263508Sdim    OS << "#ifdef GET_NEON_IMMEDIATE_CHECK\n";
2847263508Sdim
2848226586Sdim  for (unsigned i = 0, e = RV.size(); i != e; ++i) {
2849226586Sdim    Record *R = RV[i];
2850263508Sdim
2851226586Sdim    OpKind k = OpMap[R->getValueAsDef("Operand")->getName()];
2852226586Sdim    if (k != OpNone)
2853226586Sdim      continue;
2854226586Sdim
2855263508Sdim    std::string name = R->getValueAsString("Name");
2856226586Sdim    std::string Proto = R->getValueAsString("Prototype");
2857263508Sdim    std::string Types = R->getValueAsString("Types");
2858263508Sdim    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
2865263508Sdim    // Functions which do not have an immediate do not need to have range
2866263508Sdim    // checking code emitted.
2867263508Sdim    size_t immPos = Proto.find('i');
2868263508Sdim    if (immPos == std::string::npos)
2869263508Sdim      continue;
2870263508Sdim
2871226586Sdim    SmallVector<StringRef, 16> TypeVec;
2872226586Sdim    ParseTypes(R, Types, TypeVec);
2873226586Sdim
2874226586Sdim    if (R->getSuperClasses().size() < 2)
2875243830Sdim      PrintFatalError(R->getLoc(), "Builtin has no class kind");
2876226586Sdim
2877226586Sdim    ClassKind ck = ClassMap[R->getSuperClasses()[1]];
2878263508Sdim    if (!ProtoHasScalar(Proto))
2879263508Sdim      ck = ClassB;
2880226586Sdim
2881263508Sdim    // Do not include AArch64 range checks if not generating code for AArch64.
2882263508Sdim    bool isA64 = R->getValueAsBit("isA64");
2883263508Sdim    if (!isA64RangeCheck && isA64)
2884263508Sdim      continue;
2885263508Sdim
2886263508Sdim    // Include ARM range checks in AArch64 but only if ARM intrinsics are not
2887263508Sdim    // redefined by AArch64 to handle new types.
2888263508Sdim    if (isA64RangeCheck && !isA64 && A64IntrinsicMap.count(Rename)) {
2889263508Sdim      ClassKind &A64CK = A64IntrinsicMap[Rename];
2890263508Sdim      if (A64CK == ck && ck != ClassNone)
2891263508Sdim        continue;
2892263508Sdim    }
2893263508Sdim
2894226586Sdim    for (unsigned ti = 0, te = TypeVec.size(); ti != te; ++ti) {
2895263508Sdim      std::string namestr, shiftstr, rangestr;
2896263508Sdim
2897263508Sdim      if (R->getValueAsBit("isVCVT_N")) {
2898263508Sdim        // VCVT between floating- and fixed-point values takes an immediate
2899263508Sdim        // in the range [1, 32] for f32, or [1, 64] for f64.
2900263508Sdim        ck = ClassB;
2901263508Sdim        if (name.find("32") != std::string::npos)
2902263508Sdim          rangestr = "l = 1; u = 31"; // upper bound = l + u
2903263508Sdim        else if (name.find("64") != std::string::npos)
2904263508Sdim          rangestr = "l = 1; u = 63";
2905263508Sdim        else
2906263508Sdim          PrintFatalError(R->getLoc(),
2907263508Sdim              "Fixed point convert name should contains \"32\" or \"64\"");
2908263508Sdim
2909263508Sdim      } else if (R->getValueAsBit("isScalarShift")) {
2910263508Sdim        // Right shifts have an 'r' in the name, left shifts do not.  Convert
2911263508Sdim        // instructions have the same bounds and right shifts.
2912263508Sdim        if (name.find('r') != std::string::npos ||
2913263508Sdim            name.find("cvt") != std::string::npos)
2914263508Sdim          rangestr = "l = 1; ";
2915263508Sdim
2916263508Sdim        unsigned upBound = RangeScalarShiftImm(Proto[immPos - 1], TypeVec[ti]);
2917263508Sdim        // Narrow shift has half the upper bound
2918263508Sdim        if (R->getValueAsBit("isScalarNarrowShift"))
2919263508Sdim          upBound /= 2;
2920263508Sdim
2921263508Sdim        rangestr += "u = " + utostr(upBound);
2922263508Sdim      } else if (R->getValueAsBit("isShift")) {
2923263508Sdim        // Builtins which are overloaded by type will need to have their upper
2924263508Sdim        // bound computed at Sema time based on the type constant.
2925263508Sdim        shiftstr = ", true";
2926263508Sdim
2927263508Sdim        // Right shifts have an 'r' in the name, left shifts do not.
2928263508Sdim        if (name.find('r') != std::string::npos)
2929263508Sdim          rangestr = "l = 1; ";
2930263508Sdim
2931263508Sdim        rangestr += "u = RFT(TV" + shiftstr + ")";
2932263508Sdim      } else {
2933263508Sdim        // The immediate generally refers to a lane in the preceding argument.
2934263508Sdim        assert(immPos > 0 && "unexpected immediate operand");
2935263508Sdim        rangestr =
2936263508Sdim            "u = " + utostr(RangeFromType(Proto[immPos - 1], TypeVec[ti]));
2937263508Sdim      }
2938263508Sdim      // Make sure cases appear only once by uniquing them in a string map.
2939263508Sdim      namestr = MangleName(name, TypeVec[ti], ck);
2940263508Sdim      if (EmittedMap.count(namestr))
2941226586Sdim        continue;
2942263508Sdim      EmittedMap[namestr] = OpNone;
2943226586Sdim
2944263508Sdim      // Calculate the index of the immediate that should be range checked.
2945263508Sdim      unsigned immidx = 0;
2946263508Sdim
2947263508Sdim      // Builtins that return a struct of multiple vectors have an extra
2948263508Sdim      // leading arg for the struct return.
2949263508Sdim      if (IsMultiVecProto(Proto[0]))
2950263508Sdim        ++immidx;
2951263508Sdim
2952263508Sdim      // Add one to the index for each argument until we reach the immediate
2953263508Sdim      // to be checked.  Structs of vectors are passed as multiple arguments.
2954263508Sdim      for (unsigned ii = 1, ie = Proto.size(); ii != ie; ++ii) {
2955263508Sdim        switch (Proto[ii]) {
2956263508Sdim        default:
2957263508Sdim          immidx += 1;
2958263508Sdim          break;
2959263508Sdim        case '2':
2960263508Sdim        case 'B':
2961263508Sdim          immidx += 2;
2962263508Sdim          break;
2963263508Sdim        case '3':
2964263508Sdim        case 'C':
2965263508Sdim          immidx += 3;
2966263508Sdim          break;
2967263508Sdim        case '4':
2968263508Sdim        case 'D':
2969263508Sdim          immidx += 4;
2970263508Sdim          break;
2971263508Sdim        case 'i':
2972263508Sdim          ie = ii + 1;
2973263508Sdim          break;
2974263508Sdim        }
2975263508Sdim      }
2976263508Sdim      if (isA64RangeCheck)
2977263508Sdim        OS << "case AArch64::BI__builtin_neon_";
2978263508Sdim      else
2979263508Sdim        OS << "case ARM::BI__builtin_neon_";
2980263508Sdim      OS << MangleName(name, TypeVec[ti], ck) << ": i = " << immidx << "; "
2981263508Sdim         << rangestr << "; break;\n";
2982226586Sdim    }
2983226586Sdim  }
2984226586Sdim  OS << "#endif\n\n";
2985263508Sdim}
2986226586Sdim
2987263508Sdim/// Generate the ARM and AArch64 overloaded type checking code for
2988263508Sdim/// SemaChecking.cpp, checking for unique builtin declarations.
2989263508Sdimvoid
2990263508SdimNeonEmitter::genOverloadTypeCheckCode(raw_ostream &OS,
2991263508Sdim                                      StringMap<ClassKind> &A64IntrinsicMap,
2992263508Sdim                                      bool isA64TypeCheck) {
2993263508Sdim  std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst");
2994263508Sdim  StringMap<OpKind> EmittedMap;
2995263508Sdim
2996226586Sdim  // Generate the overloaded type checking code for SemaChecking.cpp
2997263508Sdim  if (isA64TypeCheck)
2998263508Sdim    OS << "#ifdef GET_NEON_AARCH64_OVERLOAD_CHECK\n";
2999263508Sdim  else
3000263508Sdim    OS << "#ifdef GET_NEON_OVERLOAD_CHECK\n";
3001263508Sdim
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");
3011263508Sdim    std::string Rename = name + "@" + Proto;
3012263508Sdim
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.
3020263508Sdim    if (ProtoHasScalar(Proto))
3021226586Sdim      continue;
3022226586Sdim
3023226586Sdim    SmallVector<StringRef, 16> TypeVec;
3024226586Sdim    ParseTypes(R, Types, TypeVec);
3025226586Sdim
3026226586Sdim    if (R->getSuperClasses().size() < 2)
3027243830Sdim      PrintFatalError(R->getLoc(), "Builtin has no class kind");
3028226586Sdim
3029263508Sdim    // Do not include AArch64 type checks if not generating code for AArch64.
3030263508Sdim    bool isA64 = R->getValueAsBit("isA64");
3031263508Sdim    if (!isA64TypeCheck && isA64)
3032263508Sdim      continue;
3033263508Sdim
3034263508Sdim    // Include ARM  type check in AArch64 but only if ARM intrinsics
3035263508Sdim    // are not redefined in AArch64 to handle new types, e.g. "vabd" is a SIntr
3036263508Sdim    // redefined in AArch64 to handle an additional 2 x f64 type.
3037263508Sdim    ClassKind ck = ClassMap[R->getSuperClasses()[1]];
3038263508Sdim    if (isA64TypeCheck && !isA64 && A64IntrinsicMap.count(Rename)) {
3039263508Sdim      ClassKind &A64CK = A64IntrinsicMap[Rename];
3040263508Sdim      if (A64CK == ck && ck != ClassNone)
3041263508Sdim        continue;
3042263508Sdim    }
3043263508Sdim
3044226586Sdim    int si = -1, qi = -1;
3045239462Sdim    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;
3053239462Sdim        qmask |= 1ULL << GetNeonEnum(Proto, TypeVec[ti]);
3054226586Sdim      } else {
3055226586Sdim        si = ti;
3056239462Sdim        mask |= 1ULL << GetNeonEnum(Proto, TypeVec[ti]);
3057226586Sdim      }
3058226586Sdim    }
3059234353Sdim
3060234353Sdim    // Check if the builtin function has a pointer or const pointer argument.
3061234353Sdim    int PtrArgNum = -1;
3062234353Sdim    bool HasConstPtr = false;
3063234353Sdim    for (unsigned arg = 1, arge = Proto.size(); arg != arge; ++arg) {
3064234353Sdim      char ArgType = Proto[arg];
3065234353Sdim      if (ArgType == 'c') {
3066234353Sdim        HasConstPtr = true;
3067234353Sdim        PtrArgNum = arg - 1;
3068234353Sdim        break;
3069234353Sdim      }
3070234353Sdim      if (ArgType == 'p') {
3071234353Sdim        PtrArgNum = arg - 1;
3072234353Sdim        break;
3073234353Sdim      }
3074234353Sdim    }
3075234353Sdim    // For sret builtins, adjust the pointer argument index.
3076263508Sdim    if (PtrArgNum >= 0 && IsMultiVecProto(Proto[0]))
3077234353Sdim      PtrArgNum += 1;
3078234353Sdim
3079234353Sdim    // Omit type checking for the pointer arguments of vld1_lane, vld1_dup,
3080234353Sdim    // and vst1_lane intrinsics.  Using a pointer to the vector element
3081234353Sdim    // type with one of those operations causes codegen to select an aligned
3082234353Sdim    // load/store instruction.  If you want an unaligned operation,
3083234353Sdim    // the pointer argument needs to have less alignment than element type,
3084234353Sdim    // so just accept any pointer type.
3085234353Sdim    if (name == "vld1_lane" || name == "vld1_dup" || name == "vst1_lane") {
3086234353Sdim      PtrArgNum = -1;
3087234353Sdim      HasConstPtr = false;
3088234353Sdim    }
3089234353Sdim
3090234353Sdim    if (mask) {
3091263508Sdim      if (isA64TypeCheck)
3092263508Sdim        OS << "case AArch64::BI__builtin_neon_";
3093263508Sdim      else
3094263508Sdim        OS << "case ARM::BI__builtin_neon_";
3095263508Sdim      OS << MangleName(name, TypeVec[si], ClassB) << ": mask = "
3096263508Sdim         << "0x" << utohexstr(mask) << "ULL";
3097234353Sdim      if (PtrArgNum >= 0)
3098234353Sdim        OS << "; PtrArgNum = " << PtrArgNum;
3099234353Sdim      if (HasConstPtr)
3100234353Sdim        OS << "; HasConstPtr = true";
3101234353Sdim      OS << "; break;\n";
3102234353Sdim    }
3103234353Sdim    if (qmask) {
3104263508Sdim      if (isA64TypeCheck)
3105263508Sdim        OS << "case AArch64::BI__builtin_neon_";
3106263508Sdim      else
3107263508Sdim        OS << "case ARM::BI__builtin_neon_";
3108263508Sdim      OS << MangleName(name, TypeVec[qi], ClassB) << ": mask = "
3109263508Sdim         << "0x" << utohexstr(qmask) << "ULL";
3110234353Sdim      if (PtrArgNum >= 0)
3111234353Sdim        OS << "; PtrArgNum = " << PtrArgNum;
3112234353Sdim      if (HasConstPtr)
3113234353Sdim        OS << "; HasConstPtr = true";
3114234353Sdim      OS << "; break;\n";
3115234353Sdim    }
3116226586Sdim  }
3117226586Sdim  OS << "#endif\n\n";
3118263508Sdim}
3119226586Sdim
3120263508Sdim/// genBuiltinsDef: Generate the BuiltinsARM.def and  BuiltinsAArch64.def
3121263508Sdim/// declaration of builtins, checking for unique builtin declarations.
3122263508Sdimvoid NeonEmitter::genBuiltinsDef(raw_ostream &OS,
3123263508Sdim                                 StringMap<ClassKind> &A64IntrinsicMap,
3124263508Sdim                                 bool isA64GenBuiltinDef) {
3125263508Sdim  std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst");
3126263508Sdim  StringMap<OpKind> EmittedMap;
3127263508Sdim
3128263508Sdim  // Generate BuiltinsARM.def and BuiltinsAArch64.def
3129263508Sdim  if (isA64GenBuiltinDef)
3130263508Sdim    OS << "#ifdef GET_NEON_AARCH64_BUILTINS\n";
3131263508Sdim  else
3132263508Sdim    OS << "#ifdef GET_NEON_BUILTINS\n";
3133263508Sdim
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
3140263508Sdim    std::string Proto = R->getValueAsString("Prototype");
3141226586Sdim    std::string name = R->getValueAsString("Name");
3142263508Sdim    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
3149263508Sdim    std::string Types = R->getValueAsString("Types");
3150226586Sdim    SmallVector<StringRef, 16> TypeVec;
3151226586Sdim    ParseTypes(R, Types, TypeVec);
3152226586Sdim
3153226586Sdim    if (R->getSuperClasses().size() < 2)
3154243830Sdim      PrintFatalError(R->getLoc(), "Builtin has no class kind");
3155226586Sdim
3156226586Sdim    ClassKind ck = ClassMap[R->getSuperClasses()[1]];
3157226586Sdim
3158263508Sdim    // Do not include AArch64 BUILTIN() macros if not generating
3159263508Sdim    // code for AArch64
3160263508Sdim    bool isA64 = R->getValueAsBit("isA64");
3161263508Sdim    if (!isA64GenBuiltinDef && isA64)
3162263508Sdim      continue;
3163226586Sdim
3164263508Sdim    // Include ARM  BUILTIN() macros  in AArch64 but only if ARM intrinsics
3165263508Sdim    // are not redefined in AArch64 to handle new types, e.g. "vabd" is a SIntr
3166263508Sdim    // redefined in AArch64 to handle an additional 2 x f64 type.
3167263508Sdim    if (isA64GenBuiltinDef && !isA64 && A64IntrinsicMap.count(Rename)) {
3168263508Sdim      ClassKind &A64CK = A64IntrinsicMap[Rename];
3169263508Sdim      if (A64CK == ck && ck != ClassNone)
3170263508Sdim        continue;
3171263508Sdim    }
3172226586Sdim
3173263508Sdim    for (unsigned ti = 0, te = TypeVec.size(); ti != te; ++ti) {
3174263508Sdim      // Generate the declaration for this builtin, ensuring
3175263508Sdim      // that each unique BUILTIN() macro appears only once in the output
3176263508Sdim      // stream.
3177263508Sdim      std::string bd = GenBuiltinDef(name, Proto, TypeVec[ti], ck);
3178263508Sdim      if (EmittedMap.count(bd))
3179226586Sdim        continue;
3180226586Sdim
3181263508Sdim      EmittedMap[bd] = OpNone;
3182263508Sdim      OS << bd << "\n";
3183226586Sdim    }
3184226586Sdim  }
3185226586Sdim  OS << "#endif\n\n";
3186226586Sdim}
3187226586Sdim
3188263508Sdim/// runHeader - Emit a file with sections defining:
3189263508Sdim/// 1. the NEON section of BuiltinsARM.def and BuiltinsAArch64.def.
3190263508Sdim/// 2. the SemaChecking code for the type overload checking.
3191263508Sdim/// 3. the SemaChecking code for validation of intrinsic immediate arguments.
3192263508Sdimvoid NeonEmitter::runHeader(raw_ostream &OS) {
3193263508Sdim  std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst");
3194263508Sdim
3195263508Sdim  // build a map of AArch64 intriniscs to be used in uniqueness checks.
3196263508Sdim  StringMap<ClassKind> A64IntrinsicMap;
3197263508Sdim  for (unsigned i = 0, e = RV.size(); i != e; ++i) {
3198263508Sdim    Record *R = RV[i];
3199263508Sdim
3200263508Sdim    bool isA64 = R->getValueAsBit("isA64");
3201263508Sdim    if (!isA64)
3202263508Sdim      continue;
3203263508Sdim
3204263508Sdim    ClassKind CK = ClassNone;
3205263508Sdim    if (R->getSuperClasses().size() >= 2)
3206263508Sdim      CK = ClassMap[R->getSuperClasses()[1]];
3207263508Sdim
3208263508Sdim    std::string Name = R->getValueAsString("Name");
3209263508Sdim    std::string Proto = R->getValueAsString("Prototype");
3210263508Sdim    std::string Rename = Name + "@" + Proto;
3211263508Sdim    if (A64IntrinsicMap.count(Rename))
3212263508Sdim      continue;
3213263508Sdim    A64IntrinsicMap[Rename] = CK;
3214263508Sdim  }
3215263508Sdim
3216263508Sdim  // Generate BuiltinsARM.def for ARM
3217263508Sdim  genBuiltinsDef(OS, A64IntrinsicMap, false);
3218263508Sdim
3219263508Sdim  // Generate BuiltinsAArch64.def for AArch64
3220263508Sdim  genBuiltinsDef(OS, A64IntrinsicMap, true);
3221263508Sdim
3222263508Sdim  // Generate ARM overloaded type checking code for SemaChecking.cpp
3223263508Sdim  genOverloadTypeCheckCode(OS, A64IntrinsicMap, false);
3224263508Sdim
3225263508Sdim  // Generate AArch64 overloaded type checking code for SemaChecking.cpp
3226263508Sdim  genOverloadTypeCheckCode(OS, A64IntrinsicMap, true);
3227263508Sdim
3228263508Sdim  // Generate ARM range checking code for shift/lane immediates.
3229263508Sdim  genIntrinsicRangeCheckCode(OS, A64IntrinsicMap, false);
3230263508Sdim
3231263508Sdim  // Generate the AArch64 range checking code for shift/lane immediates.
3232263508Sdim  genIntrinsicRangeCheckCode(OS, A64IntrinsicMap, true);
3233263508Sdim}
3234263508Sdim
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,
3240251662Sdim                           bool isShift, bool isHiddenLOp,
3241263508Sdim                           ClassKind ck, const std::string &InstName,
3242263508Sdim                           bool isA64,
3243263508Sdim                           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
3258263508Sdim  // todo: GenerateChecksForIntrinsic does not generate CHECK
3259263508Sdim  // for aarch64 instructions yet
3260251662Sdim  std::vector<std::string> FileCheckPatterns;
3261263508Sdim  if (!isA64) {
3262263508Sdim	GenerateChecksForIntrinsic(name, proto, outTypeStr, inTypeStr, ck, InstName,
3263263508Sdim							   isHiddenLOp, FileCheckPatterns);
3264263508Sdim	s+= "// CHECK_ARM: test_" + mangledName + "\n";
3265263508Sdim  }
3266263508Sdim  s += "// CHECK_AARCH64: test_" + mangledName + "\n";
3267251662Sdim
3268226586Sdim  // Emit the FileCheck patterns.
3269251662Sdim  // If for any reason we do not want to emit a check, mangledInst
3270251662Sdim  // will be the empty string.
3271251662Sdim  if (FileCheckPatterns.size()) {
3272251662Sdim    for (std::vector<std::string>::const_iterator i = FileCheckPatterns.begin(),
3273251662Sdim                                                  e = FileCheckPatterns.end();
3274251662Sdim         i != e;
3275251662Sdim         ++i) {
3276263508Sdim      s += "// CHECK_ARM: " + *i + "\n";
3277251662Sdim    }
3278251662Sdim  }
3279226586Sdim
3280226586Sdim  // Emit the start of the test function.
3281263508Sdim
3282263508Sdim  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;
3289263508Sdim    testFuncProto += comma + TypeString(proto[i], inTypeStr) + " ";
3290263508Sdim    testFuncProto.push_back(arg);
3291226586Sdim    comma = ", ";
3292226586Sdim  }
3293263508Sdim  testFuncProto += ")";
3294226586Sdim
3295263508Sdim  s+= testFuncProto;
3296263508Sdim  s+= " {\n  ";
3297263508Sdim
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
3320263508Sdim/// Write out all intrinsic tests for the specified target, checking
3321263508Sdim/// for intrinsic test uniqueness.
3322263508Sdimvoid NeonEmitter::genTargetTest(raw_ostream &OS, StringMap<OpKind> &EmittedMap,
3323263508Sdim                                bool isA64GenTest) {
3324263508Sdim  if (isA64GenTest)
3325263508Sdim	OS << "#ifdef __aarch64__\n";
3326226586Sdim
3327263508Sdim  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");
3334251662Sdim    std::string InstName = R->getValueAsString("InstName");
3335251662Sdim    bool isHiddenLOp = R->getValueAsBit("isHiddenLInst");
3336263508Sdim    bool isA64 = R->getValueAsBit("isA64");
3337226586Sdim
3338263508Sdim    // do not include AArch64 intrinsic test if not generating
3339263508Sdim    // code for AArch64
3340263508Sdim    if (!isA64GenTest && isA64)
3341263508Sdim      continue;
3342263508Sdim
3343226586Sdim    SmallVector<StringRef, 16> TypeVec;
3344226586Sdim    ParseTypes(R, Types, TypeVec);
3345226586Sdim
3346251662Sdim    ClassKind ck = ClassMap[R->getSuperClasses()[1]];
3347226586Sdim    OpKind kind = OpMap[R->getValueAsDef("Operand")->getName()];
3348239462Sdim    if (kind == OpUnavailable)
3349239462Sdim      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;
3361263508Sdim		  std::string testFuncProto;
3362263508Sdim          std::string s = GenTest(name, Proto, TypeVec[ti], TypeVec[srcti],
3363263508Sdim                                  isShift, isHiddenLOp, ck, InstName, isA64,
3364263508Sdim								  testFuncProto);
3365263508Sdim          if (EmittedMap.count(testFuncProto))
3366263508Sdim            continue;
3367263508Sdim          EmittedMap[testFuncProto] = kind;
3368263508Sdim          OS << s << "\n";
3369226586Sdim        }
3370226586Sdim      } else {
3371263508Sdim		std::string testFuncProto;
3372263508Sdim        std::string s = GenTest(name, Proto, TypeVec[ti], TypeVec[ti], isShift,
3373263508Sdim                                isHiddenLOp, ck, InstName, isA64, testFuncProto);
3374263508Sdim        if (EmittedMap.count(testFuncProto))
3375263508Sdim          continue;
3376263508Sdim        EmittedMap[testFuncProto] = kind;
3377263508Sdim        OS << s << "\n";
3378226586Sdim      }
3379226586Sdim    }
3380226586Sdim  }
3381263508Sdim
3382263508Sdim  if (isA64GenTest)
3383263508Sdim	OS << "#endif\n";
3384226586Sdim}
3385263508Sdim/// runTests - Write out a complete set of tests for all of the Neon
3386263508Sdim/// intrinsics.
3387263508Sdimvoid NeonEmitter::runTests(raw_ostream &OS) {
3388263508Sdim  OS << "// RUN: %clang_cc1 -triple thumbv7s-apple-darwin -target-abi "
3389263508Sdim        "apcs-gnu\\\n"
3390263508Sdim        "// RUN:  -target-cpu swift -ffreestanding -Os -S -o - %s\\\n"
3391263508Sdim        "// RUN:  | FileCheck %s -check-prefix=CHECK_ARM\n"
3392263508Sdim		"\n"
3393263508Sdim	    "// RUN: %clang_cc1 -triple aarch64-none-linux-gnu \\\n"
3394263508Sdim	    "// RUN -target-feature +neon  -ffreestanding -S -o - %s \\\n"
3395263508Sdim	    "// RUN:  | FileCheck %s -check-prefix=CHECK_AARCH64\n"
3396263508Sdim        "\n"
3397263508Sdim        "// REQUIRES: long_tests\n"
3398263508Sdim        "\n"
3399263508Sdim        "#include <arm_neon.h>\n"
3400263508Sdim        "\n";
3401226586Sdim
3402263508Sdim  // ARM tests must be emitted before AArch64 tests to ensure
3403263508Sdim  // tests for intrinsics that are common to ARM and AArch64
3404263508Sdim  // appear only once in the output stream.
3405263508Sdim  // The check for uniqueness is done in genTargetTest.
3406263508Sdim  StringMap<OpKind> EmittedMap;
3407263508Sdim
3408263508Sdim  genTargetTest(OS, EmittedMap, false);
3409263508Sdim
3410263508Sdim  genTargetTest(OS, EmittedMap, true);
3411263508Sdim}
3412263508Sdim
3413239462Sdimnamespace clang {
3414239462Sdimvoid EmitNeon(RecordKeeper &Records, raw_ostream &OS) {
3415239462Sdim  NeonEmitter(Records).run(OS);
3416239462Sdim}
3417239462Sdimvoid EmitNeonSema(RecordKeeper &Records, raw_ostream &OS) {
3418239462Sdim  NeonEmitter(Records).runHeader(OS);
3419239462Sdim}
3420239462Sdimvoid EmitNeonTest(RecordKeeper &Records, raw_ostream &OS) {
3421239462Sdim  NeonEmitter(Records).runTests(OS);
3422239462Sdim}
3423239462Sdim} // End namespace clang
3424