blob: 1649633d3e03d46596b86516e5200624e906928c [file] [log] [blame]
Peter Collingbournebee583f2011-10-06 13:03:08 +00001//===- NeonEmitter.cpp - Generate arm_neon.h for use with clang -*- C++ -*-===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This tablegen backend is responsible for emitting arm_neon.h, which includes
11// a declaration and definition of each function specified by the ARM NEON
12// compiler interface. See ARM document DUI0348B.
13//
14// Each NEON instruction is implemented in terms of 1 or more functions which
15// are suffixed with the element type of the input vectors. Functions may be
16// implemented in terms of generic vector operations such as +, *, -, etc. or
17// by calling a __builtin_-prefixed function which will be handled by clang's
18// CodeGen library.
19//
20// Additional validation code can be generated by this file when runHeader() is
21// called, rather than the normal run() entry point. A complete set of tests
22// for Neon intrinsics can be generated by calling the runTests() entry point.
23//
24//===----------------------------------------------------------------------===//
25
Jakob Stoklund Olesen995e0e12012-06-13 05:12:41 +000026#include "llvm/ADT/DenseMap.h"
Peter Collingbournebee583f2011-10-06 13:03:08 +000027#include "llvm/ADT/SmallString.h"
28#include "llvm/ADT/SmallVector.h"
29#include "llvm/ADT/StringExtras.h"
Jakob Stoklund Olesen995e0e12012-06-13 05:12:41 +000030#include "llvm/ADT/StringMap.h"
David Blaikie8a40f702012-01-17 06:56:22 +000031#include "llvm/Support/ErrorHandling.h"
Jakob Stoklund Olesen995e0e12012-06-13 05:12:41 +000032#include "llvm/TableGen/Error.h"
33#include "llvm/TableGen/Record.h"
34#include "llvm/TableGen/TableGenBackend.h"
Peter Collingbournebee583f2011-10-06 13:03:08 +000035#include <string>
Peter Collingbournebee583f2011-10-06 13:03:08 +000036using namespace llvm;
37
Jakob Stoklund Olesen995e0e12012-06-13 05:12:41 +000038enum OpKind {
39 OpNone,
40 OpUnavailable,
41 OpAdd,
42 OpAddl,
Jiangning Liu1bda93a2013-09-09 02:21:08 +000043 OpAddlHi,
Jakob Stoklund Olesen995e0e12012-06-13 05:12:41 +000044 OpAddw,
Jiangning Liu1bda93a2013-09-09 02:21:08 +000045 OpAddwHi,
Jakob Stoklund Olesen995e0e12012-06-13 05:12:41 +000046 OpSub,
47 OpSubl,
Jiangning Liu1bda93a2013-09-09 02:21:08 +000048 OpSublHi,
Jakob Stoklund Olesen995e0e12012-06-13 05:12:41 +000049 OpSubw,
Jiangning Liu1bda93a2013-09-09 02:21:08 +000050 OpSubwHi,
Jakob Stoklund Olesen995e0e12012-06-13 05:12:41 +000051 OpMul,
52 OpMla,
53 OpMlal,
Jiangning Liu1bda93a2013-09-09 02:21:08 +000054 OpMullHi,
55 OpMlalHi,
Jakob Stoklund Olesen995e0e12012-06-13 05:12:41 +000056 OpMls,
57 OpMlsl,
Jiangning Liu1bda93a2013-09-09 02:21:08 +000058 OpMlslHi,
Jakob Stoklund Olesen995e0e12012-06-13 05:12:41 +000059 OpMulN,
60 OpMlaN,
61 OpMlsN,
62 OpMlalN,
63 OpMlslN,
64 OpMulLane,
Jiangning Liu4617e9d2013-10-04 09:21:17 +000065 OpMulXLane,
Jakob Stoklund Olesen995e0e12012-06-13 05:12:41 +000066 OpMullLane,
Jiangning Liu4617e9d2013-10-04 09:21:17 +000067 OpMullHiLane,
Jakob Stoklund Olesen995e0e12012-06-13 05:12:41 +000068 OpMlaLane,
69 OpMlsLane,
70 OpMlalLane,
Jiangning Liu4617e9d2013-10-04 09:21:17 +000071 OpMlalHiLane,
Jakob Stoklund Olesen995e0e12012-06-13 05:12:41 +000072 OpMlslLane,
Jiangning Liu4617e9d2013-10-04 09:21:17 +000073 OpMlslHiLane,
Jakob Stoklund Olesen995e0e12012-06-13 05:12:41 +000074 OpQDMullLane,
Jiangning Liu4617e9d2013-10-04 09:21:17 +000075 OpQDMullHiLane,
Jakob Stoklund Olesen995e0e12012-06-13 05:12:41 +000076 OpQDMlalLane,
Jiangning Liu4617e9d2013-10-04 09:21:17 +000077 OpQDMlalHiLane,
Jakob Stoklund Olesen995e0e12012-06-13 05:12:41 +000078 OpQDMlslLane,
Jiangning Liu4617e9d2013-10-04 09:21:17 +000079 OpQDMlslHiLane,
Jakob Stoklund Olesen995e0e12012-06-13 05:12:41 +000080 OpQDMulhLane,
81 OpQRDMulhLane,
Jiangning Liu4617e9d2013-10-04 09:21:17 +000082 OpFMSLane,
83 OpFMSLaneQ,
Jakob Stoklund Olesen995e0e12012-06-13 05:12:41 +000084 OpEq,
85 OpGe,
86 OpLe,
87 OpGt,
88 OpLt,
89 OpNeg,
90 OpNot,
91 OpAnd,
92 OpOr,
93 OpXor,
94 OpAndNot,
95 OpOrNot,
96 OpCast,
97 OpConcat,
98 OpDup,
99 OpDupLane,
100 OpHi,
101 OpLo,
102 OpSelect,
103 OpRev16,
104 OpRev32,
105 OpRev64,
106 OpReinterpret,
Jiangning Liu1bda93a2013-09-09 02:21:08 +0000107 OpAddhnHi,
108 OpRAddhnHi,
109 OpSubhnHi,
110 OpRSubhnHi,
Jakob Stoklund Olesen995e0e12012-06-13 05:12:41 +0000111 OpAbdl,
Jiangning Liu1bda93a2013-09-09 02:21:08 +0000112 OpAbdlHi,
Jakob Stoklund Olesen995e0e12012-06-13 05:12:41 +0000113 OpAba,
Tim Northover2fe823a2013-08-01 09:23:19 +0000114 OpAbal,
Jiangning Liu1bda93a2013-09-09 02:21:08 +0000115 OpAbalHi,
116 OpQDMullHi,
117 OpQDMlalHi,
118 OpQDMlslHi,
Hao Liub1852ee2013-09-04 09:29:13 +0000119 OpDiv,
120 OpLongHi,
121 OpNarrowHi,
Kevin Qinf22bf502013-10-11 02:34:30 +0000122 OpMovlHi,
123 OpCopy
Jakob Stoklund Olesen995e0e12012-06-13 05:12:41 +0000124};
125
126enum ClassKind {
127 ClassNone,
128 ClassI, // generic integer instruction, e.g., "i8" suffix
129 ClassS, // signed/unsigned/poly, e.g., "s8", "u8" or "p8" suffix
130 ClassW, // width-specific instruction, e.g., "8" suffix
Michael Gottesmanfc89cc22013-04-16 21:18:42 +0000131 ClassB, // bitcast arguments with enum argument to specify type
132 ClassL, // Logical instructions which are op instructions
133 // but we need to not emit any suffix for in our
134 // tests.
135 ClassNoTest // Instructions which we do not test since they are
136 // not TRUE instructions.
Jakob Stoklund Olesen995e0e12012-06-13 05:12:41 +0000137};
138
139/// NeonTypeFlags - Flags to identify the types for overloaded Neon
140/// builtins. These must be kept in sync with the flags in
141/// include/clang/Basic/TargetBuiltins.h.
142namespace {
143class NeonTypeFlags {
144 enum {
145 EltTypeMask = 0xf,
146 UnsignedFlag = 0x10,
147 QuadFlag = 0x20
148 };
149 uint32_t Flags;
150
151public:
152 enum EltType {
153 Int8,
154 Int16,
155 Int32,
156 Int64,
157 Poly8,
158 Poly16,
159 Float16,
Tim Northover2fe823a2013-08-01 09:23:19 +0000160 Float32,
161 Float64
Jakob Stoklund Olesen995e0e12012-06-13 05:12:41 +0000162 };
163
164 NeonTypeFlags(unsigned F) : Flags(F) {}
165 NeonTypeFlags(EltType ET, bool IsUnsigned, bool IsQuad) : Flags(ET) {
166 if (IsUnsigned)
167 Flags |= UnsignedFlag;
168 if (IsQuad)
169 Flags |= QuadFlag;
170 }
171
172 uint32_t getFlags() const { return Flags; }
173};
174} // end anonymous namespace
175
176namespace {
177class NeonEmitter {
178 RecordKeeper &Records;
179 StringMap<OpKind> OpMap;
180 DenseMap<Record*, ClassKind> ClassMap;
181
182public:
183 NeonEmitter(RecordKeeper &R) : Records(R) {
184 OpMap["OP_NONE"] = OpNone;
185 OpMap["OP_UNAVAILABLE"] = OpUnavailable;
186 OpMap["OP_ADD"] = OpAdd;
187 OpMap["OP_ADDL"] = OpAddl;
Jiangning Liu1bda93a2013-09-09 02:21:08 +0000188 OpMap["OP_ADDLHi"] = OpAddlHi;
Jakob Stoklund Olesen995e0e12012-06-13 05:12:41 +0000189 OpMap["OP_ADDW"] = OpAddw;
Jiangning Liu1bda93a2013-09-09 02:21:08 +0000190 OpMap["OP_ADDWHi"] = OpAddwHi;
Jakob Stoklund Olesen995e0e12012-06-13 05:12:41 +0000191 OpMap["OP_SUB"] = OpSub;
192 OpMap["OP_SUBL"] = OpSubl;
Jiangning Liu1bda93a2013-09-09 02:21:08 +0000193 OpMap["OP_SUBLHi"] = OpSublHi;
Jakob Stoklund Olesen995e0e12012-06-13 05:12:41 +0000194 OpMap["OP_SUBW"] = OpSubw;
Jiangning Liu1bda93a2013-09-09 02:21:08 +0000195 OpMap["OP_SUBWHi"] = OpSubwHi;
Jakob Stoklund Olesen995e0e12012-06-13 05:12:41 +0000196 OpMap["OP_MUL"] = OpMul;
197 OpMap["OP_MLA"] = OpMla;
198 OpMap["OP_MLAL"] = OpMlal;
Jiangning Liu1bda93a2013-09-09 02:21:08 +0000199 OpMap["OP_MULLHi"] = OpMullHi;
200 OpMap["OP_MLALHi"] = OpMlalHi;
Jakob Stoklund Olesen995e0e12012-06-13 05:12:41 +0000201 OpMap["OP_MLS"] = OpMls;
202 OpMap["OP_MLSL"] = OpMlsl;
Jiangning Liu1bda93a2013-09-09 02:21:08 +0000203 OpMap["OP_MLSLHi"] = OpMlslHi;
Jakob Stoklund Olesen995e0e12012-06-13 05:12:41 +0000204 OpMap["OP_MUL_N"] = OpMulN;
205 OpMap["OP_MLA_N"] = OpMlaN;
206 OpMap["OP_MLS_N"] = OpMlsN;
207 OpMap["OP_MLAL_N"] = OpMlalN;
208 OpMap["OP_MLSL_N"] = OpMlslN;
209 OpMap["OP_MUL_LN"]= OpMulLane;
Jiangning Liu4617e9d2013-10-04 09:21:17 +0000210 OpMap["OP_MULX_LN"]= OpMulXLane;
Jakob Stoklund Olesen995e0e12012-06-13 05:12:41 +0000211 OpMap["OP_MULL_LN"] = OpMullLane;
Jiangning Liu4617e9d2013-10-04 09:21:17 +0000212 OpMap["OP_MULLHi_LN"] = OpMullHiLane;
Jakob Stoklund Olesen995e0e12012-06-13 05:12:41 +0000213 OpMap["OP_MLA_LN"]= OpMlaLane;
214 OpMap["OP_MLS_LN"]= OpMlsLane;
215 OpMap["OP_MLAL_LN"] = OpMlalLane;
Jiangning Liu4617e9d2013-10-04 09:21:17 +0000216 OpMap["OP_MLALHi_LN"] = OpMlalHiLane;
Jakob Stoklund Olesen995e0e12012-06-13 05:12:41 +0000217 OpMap["OP_MLSL_LN"] = OpMlslLane;
Jiangning Liu4617e9d2013-10-04 09:21:17 +0000218 OpMap["OP_MLSLHi_LN"] = OpMlslHiLane;
Jakob Stoklund Olesen995e0e12012-06-13 05:12:41 +0000219 OpMap["OP_QDMULL_LN"] = OpQDMullLane;
Jiangning Liu4617e9d2013-10-04 09:21:17 +0000220 OpMap["OP_QDMULLHi_LN"] = OpQDMullHiLane;
Jakob Stoklund Olesen995e0e12012-06-13 05:12:41 +0000221 OpMap["OP_QDMLAL_LN"] = OpQDMlalLane;
Jiangning Liu4617e9d2013-10-04 09:21:17 +0000222 OpMap["OP_QDMLALHi_LN"] = OpQDMlalHiLane;
Jakob Stoklund Olesen995e0e12012-06-13 05:12:41 +0000223 OpMap["OP_QDMLSL_LN"] = OpQDMlslLane;
Jiangning Liu4617e9d2013-10-04 09:21:17 +0000224 OpMap["OP_QDMLSLHi_LN"] = OpQDMlslHiLane;
Jakob Stoklund Olesen995e0e12012-06-13 05:12:41 +0000225 OpMap["OP_QDMULH_LN"] = OpQDMulhLane;
226 OpMap["OP_QRDMULH_LN"] = OpQRDMulhLane;
Jiangning Liu4617e9d2013-10-04 09:21:17 +0000227 OpMap["OP_FMS_LN"] = OpFMSLane;
228 OpMap["OP_FMS_LNQ"] = OpFMSLaneQ;
Jakob Stoklund Olesen995e0e12012-06-13 05:12:41 +0000229 OpMap["OP_EQ"] = OpEq;
230 OpMap["OP_GE"] = OpGe;
231 OpMap["OP_LE"] = OpLe;
232 OpMap["OP_GT"] = OpGt;
233 OpMap["OP_LT"] = OpLt;
234 OpMap["OP_NEG"] = OpNeg;
235 OpMap["OP_NOT"] = OpNot;
236 OpMap["OP_AND"] = OpAnd;
237 OpMap["OP_OR"] = OpOr;
238 OpMap["OP_XOR"] = OpXor;
239 OpMap["OP_ANDN"] = OpAndNot;
240 OpMap["OP_ORN"] = OpOrNot;
241 OpMap["OP_CAST"] = OpCast;
242 OpMap["OP_CONC"] = OpConcat;
243 OpMap["OP_HI"] = OpHi;
244 OpMap["OP_LO"] = OpLo;
245 OpMap["OP_DUP"] = OpDup;
246 OpMap["OP_DUP_LN"] = OpDupLane;
247 OpMap["OP_SEL"] = OpSelect;
248 OpMap["OP_REV16"] = OpRev16;
249 OpMap["OP_REV32"] = OpRev32;
250 OpMap["OP_REV64"] = OpRev64;
251 OpMap["OP_REINT"] = OpReinterpret;
Jiangning Liu1bda93a2013-09-09 02:21:08 +0000252 OpMap["OP_ADDHNHi"] = OpAddhnHi;
253 OpMap["OP_RADDHNHi"] = OpRAddhnHi;
254 OpMap["OP_SUBHNHi"] = OpSubhnHi;
255 OpMap["OP_RSUBHNHi"] = OpRSubhnHi;
Jakob Stoklund Olesen995e0e12012-06-13 05:12:41 +0000256 OpMap["OP_ABDL"] = OpAbdl;
Jiangning Liu1bda93a2013-09-09 02:21:08 +0000257 OpMap["OP_ABDLHi"] = OpAbdlHi;
Jakob Stoklund Olesen995e0e12012-06-13 05:12:41 +0000258 OpMap["OP_ABA"] = OpAba;
259 OpMap["OP_ABAL"] = OpAbal;
Jiangning Liu1bda93a2013-09-09 02:21:08 +0000260 OpMap["OP_ABALHi"] = OpAbalHi;
261 OpMap["OP_QDMULLHi"] = OpQDMullHi;
262 OpMap["OP_QDMLALHi"] = OpQDMlalHi;
263 OpMap["OP_QDMLSLHi"] = OpQDMlslHi;
Tim Northover2fe823a2013-08-01 09:23:19 +0000264 OpMap["OP_DIV"] = OpDiv;
Hao Liub1852ee2013-09-04 09:29:13 +0000265 OpMap["OP_LONG_HI"] = OpLongHi;
266 OpMap["OP_NARROW_HI"] = OpNarrowHi;
267 OpMap["OP_MOVL_HI"] = OpMovlHi;
Kevin Qinf22bf502013-10-11 02:34:30 +0000268 OpMap["OP_COPY"] = OpCopy;
Jakob Stoklund Olesen995e0e12012-06-13 05:12:41 +0000269
270 Record *SI = R.getClass("SInst");
271 Record *II = R.getClass("IInst");
272 Record *WI = R.getClass("WInst");
Michael Gottesmanfc89cc22013-04-16 21:18:42 +0000273 Record *SOpI = R.getClass("SOpInst");
274 Record *IOpI = R.getClass("IOpInst");
275 Record *WOpI = R.getClass("WOpInst");
276 Record *LOpI = R.getClass("LOpInst");
277 Record *NoTestOpI = R.getClass("NoTestOpInst");
278
Jakob Stoklund Olesen995e0e12012-06-13 05:12:41 +0000279 ClassMap[SI] = ClassS;
280 ClassMap[II] = ClassI;
281 ClassMap[WI] = ClassW;
Michael Gottesmanfc89cc22013-04-16 21:18:42 +0000282 ClassMap[SOpI] = ClassS;
283 ClassMap[IOpI] = ClassI;
284 ClassMap[WOpI] = ClassW;
285 ClassMap[LOpI] = ClassL;
286 ClassMap[NoTestOpI] = ClassNoTest;
Jakob Stoklund Olesen995e0e12012-06-13 05:12:41 +0000287 }
288
289 // run - Emit arm_neon.h.inc
290 void run(raw_ostream &o);
291
292 // runHeader - Emit all the __builtin prototypes used in arm_neon.h
293 void runHeader(raw_ostream &o);
294
295 // runTests - Emit tests for all the Neon intrinsics.
296 void runTests(raw_ostream &o);
297
298private:
Tim Northover2fe823a2013-08-01 09:23:19 +0000299 void emitIntrinsic(raw_ostream &OS, Record *R,
300 StringMap<ClassKind> &EmittedMap);
301 void genBuiltinsDef(raw_ostream &OS, StringMap<ClassKind> &A64IntrinsicMap,
302 bool isA64GenBuiltinDef);
303 void genOverloadTypeCheckCode(raw_ostream &OS,
304 StringMap<ClassKind> &A64IntrinsicMap,
305 bool isA64TypeCheck);
306 void genIntrinsicRangeCheckCode(raw_ostream &OS,
307 StringMap<ClassKind> &A64IntrinsicMap,
308 bool isA64RangeCheck);
309 void genTargetTest(raw_ostream &OS, StringMap<OpKind> &EmittedMap,
310 bool isA64TestGen);
Jakob Stoklund Olesen995e0e12012-06-13 05:12:41 +0000311};
312} // end anonymous namespace
313
Peter Collingbournebee583f2011-10-06 13:03:08 +0000314/// ParseTypes - break down a string such as "fQf" into a vector of StringRefs,
315/// which each StringRef representing a single type declared in the string.
316/// for "fQf" we would end up with 2 StringRefs, "f", and "Qf", representing
317/// 2xfloat and 4xfloat respectively.
318static void ParseTypes(Record *r, std::string &s,
319 SmallVectorImpl<StringRef> &TV) {
320 const char *data = s.data();
321 int len = 0;
322
323 for (unsigned i = 0, e = s.size(); i != e; ++i, ++len) {
Hao Liu4efa1402013-08-15 08:26:30 +0000324 if (data[len] == 'P' || data[len] == 'Q' || data[len] == 'U'
Kevin Qinc076d062013-08-29 07:55:15 +0000325 || data[len] == 'H' || data[len] == 'S')
Peter Collingbournebee583f2011-10-06 13:03:08 +0000326 continue;
327
328 switch (data[len]) {
329 case 'c':
330 case 's':
331 case 'i':
332 case 'l':
333 case 'h':
334 case 'f':
Tim Northover2fe823a2013-08-01 09:23:19 +0000335 case 'd':
Peter Collingbournebee583f2011-10-06 13:03:08 +0000336 break;
337 default:
Joerg Sonnenberger691a16b2012-10-25 16:37:08 +0000338 PrintFatalError(r->getLoc(),
Peter Collingbournebee583f2011-10-06 13:03:08 +0000339 "Unexpected letter: " + std::string(data + len, 1));
Peter Collingbournebee583f2011-10-06 13:03:08 +0000340 }
341 TV.push_back(StringRef(data, len + 1));
342 data += len + 1;
343 len = -1;
344 }
345}
346
347/// Widen - Convert a type code into the next wider type. char -> short,
348/// short -> int, etc.
349static char Widen(const char t) {
350 switch (t) {
351 case 'c':
352 return 's';
353 case 's':
354 return 'i';
355 case 'i':
356 return 'l';
357 case 'h':
358 return 'f';
Joerg Sonnenberger691a16b2012-10-25 16:37:08 +0000359 default:
360 PrintFatalError("unhandled type in widen!");
Peter Collingbournebee583f2011-10-06 13:03:08 +0000361 }
Peter Collingbournebee583f2011-10-06 13:03:08 +0000362}
363
364/// Narrow - Convert a type code into the next smaller type. short -> char,
365/// float -> half float, etc.
366static char Narrow(const char t) {
367 switch (t) {
368 case 's':
369 return 'c';
370 case 'i':
371 return 's';
372 case 'l':
373 return 'i';
374 case 'f':
375 return 'h';
Joerg Sonnenberger691a16b2012-10-25 16:37:08 +0000376 default:
377 PrintFatalError("unhandled type in narrow!");
Peter Collingbournebee583f2011-10-06 13:03:08 +0000378 }
Peter Collingbournebee583f2011-10-06 13:03:08 +0000379}
380
Jiangning Liu1bda93a2013-09-09 02:21:08 +0000381static std::string GetNarrowTypestr(StringRef ty)
382{
383 std::string s;
384 for (size_t i = 0, end = ty.size(); i < end; i++) {
385 switch (ty[i]) {
386 case 's':
387 s += 'c';
388 break;
389 case 'i':
390 s += 's';
391 break;
392 case 'l':
393 s += 'i';
394 break;
395 default:
396 s += ty[i];
397 break;
398 }
399 }
400
401 return s;
402}
403
Peter Collingbournebee583f2011-10-06 13:03:08 +0000404/// For a particular StringRef, return the base type code, and whether it has
405/// the quad-vector, polynomial, or unsigned modifiers set.
406static char ClassifyType(StringRef ty, bool &quad, bool &poly, bool &usgn) {
407 unsigned off = 0;
Kevin Qinc076d062013-08-29 07:55:15 +0000408 // ignore scalar.
409 if (ty[off] == 'S') {
410 ++off;
411 }
Peter Collingbournebee583f2011-10-06 13:03:08 +0000412 // remember quad.
Hao Liu4efa1402013-08-15 08:26:30 +0000413 if (ty[off] == 'Q' || ty[off] == 'H') {
Peter Collingbournebee583f2011-10-06 13:03:08 +0000414 quad = true;
415 ++off;
416 }
417
418 // remember poly.
419 if (ty[off] == 'P') {
420 poly = true;
421 ++off;
422 }
423
424 // remember unsigned.
425 if (ty[off] == 'U') {
426 usgn = true;
427 ++off;
428 }
429
430 // base type to get the type string for.
431 return ty[off];
432}
433
434/// ModType - Transform a type code and its modifiers based on a mod code. The
435/// mod code definitions may be found at the top of arm_neon.td.
436static char ModType(const char mod, char type, bool &quad, bool &poly,
437 bool &usgn, bool &scal, bool &cnst, bool &pntr) {
438 switch (mod) {
439 case 't':
440 if (poly) {
441 poly = false;
442 usgn = true;
443 }
444 break;
Chad Rosier4d55e6e2013-10-30 15:20:07 +0000445 case 'b':
446 scal = true;
Peter Collingbournebee583f2011-10-06 13:03:08 +0000447 case 'u':
448 usgn = true;
449 poly = false;
450 if (type == 'f')
451 type = 'i';
Tim Northover2fe823a2013-08-01 09:23:19 +0000452 if (type == 'd')
453 type = 'l';
Peter Collingbournebee583f2011-10-06 13:03:08 +0000454 break;
455 case 'x':
456 usgn = false;
457 poly = false;
458 if (type == 'f')
459 type = 'i';
Hao Liub1852ee2013-09-04 09:29:13 +0000460 if (type == 'd')
461 type = 'l';
Peter Collingbournebee583f2011-10-06 13:03:08 +0000462 break;
Chad Rosier0babda42013-10-08 20:43:46 +0000463 case 'o':
464 scal = true;
465 type = 'd';
466 usgn = false;
467 break;
468 case 'y':
469 scal = true;
Peter Collingbournebee583f2011-10-06 13:03:08 +0000470 case 'f':
471 if (type == 'h')
472 quad = true;
473 type = 'f';
474 usgn = false;
475 break;
476 case 'g':
477 quad = false;
478 break;
Jiangning Liu4617e9d2013-10-04 09:21:17 +0000479 case 'j':
480 quad = true;
481 break;
Peter Collingbournebee583f2011-10-06 13:03:08 +0000482 case 'w':
483 type = Widen(type);
484 quad = true;
485 break;
486 case 'n':
487 type = Widen(type);
488 break;
489 case 'i':
490 type = 'i';
491 scal = true;
492 break;
493 case 'l':
494 type = 'l';
495 scal = true;
496 usgn = true;
497 break;
Chad Rosier3c03dee2013-10-18 14:03:36 +0000498 case 'z':
499 type = Narrow(type);
500 scal = true;
501 break;
Jiangning Liub96ebac2013-10-05 08:22:55 +0000502 case 'r':
503 type = Widen(type);
Chad Rosier3c03dee2013-10-18 14:03:36 +0000504 scal = true;
505 break;
Peter Collingbournebee583f2011-10-06 13:03:08 +0000506 case 's':
507 case 'a':
508 scal = true;
509 break;
510 case 'k':
511 quad = true;
512 break;
513 case 'c':
514 cnst = true;
515 case 'p':
516 pntr = true;
517 scal = true;
518 break;
519 case 'h':
520 type = Narrow(type);
521 if (type == 'h')
522 quad = false;
523 break;
Jiangning Liu1bda93a2013-09-09 02:21:08 +0000524 case 'q':
525 type = Narrow(type);
526 quad = true;
527 break;
Peter Collingbournebee583f2011-10-06 13:03:08 +0000528 case 'e':
529 type = Narrow(type);
530 usgn = true;
531 break;
Hao Liub1852ee2013-09-04 09:29:13 +0000532 case 'm':
533 type = Narrow(type);
534 quad = false;
535 break;
Peter Collingbournebee583f2011-10-06 13:03:08 +0000536 default:
537 break;
538 }
539 return type;
540}
541
542/// TypeString - for a modifier and type, generate the name of the typedef for
543/// that type. QUc -> uint8x8_t.
544static std::string TypeString(const char mod, StringRef typestr) {
545 bool quad = false;
546 bool poly = false;
547 bool usgn = false;
548 bool scal = false;
549 bool cnst = false;
550 bool pntr = false;
551
552 if (mod == 'v')
553 return "void";
554 if (mod == 'i')
555 return "int";
556
557 // base type to get the type string for.
558 char type = ClassifyType(typestr, quad, poly, usgn);
559
560 // Based on the modifying character, change the type and width if necessary.
561 type = ModType(mod, type, quad, poly, usgn, scal, cnst, pntr);
562
563 SmallString<128> s;
564
565 if (usgn)
566 s.push_back('u');
567
568 switch (type) {
569 case 'c':
570 s += poly ? "poly8" : "int8";
571 if (scal)
572 break;
573 s += quad ? "x16" : "x8";
574 break;
575 case 's':
576 s += poly ? "poly16" : "int16";
577 if (scal)
578 break;
579 s += quad ? "x8" : "x4";
580 break;
581 case 'i':
582 s += "int32";
583 if (scal)
584 break;
585 s += quad ? "x4" : "x2";
586 break;
587 case 'l':
588 s += "int64";
589 if (scal)
590 break;
591 s += quad ? "x2" : "x1";
592 break;
593 case 'h':
594 s += "float16";
595 if (scal)
596 break;
597 s += quad ? "x8" : "x4";
598 break;
599 case 'f':
600 s += "float32";
601 if (scal)
602 break;
603 s += quad ? "x4" : "x2";
604 break;
Tim Northover2fe823a2013-08-01 09:23:19 +0000605 case 'd':
606 s += "float64";
607 if (scal)
608 break;
609 s += quad ? "x2" : "x1";
610 break;
611
Peter Collingbournebee583f2011-10-06 13:03:08 +0000612 default:
Joerg Sonnenberger691a16b2012-10-25 16:37:08 +0000613 PrintFatalError("unhandled type!");
Peter Collingbournebee583f2011-10-06 13:03:08 +0000614 }
615
616 if (mod == '2')
617 s += "x2";
618 if (mod == '3')
619 s += "x3";
620 if (mod == '4')
621 s += "x4";
622
623 // Append _t, finishing the type string typedef type.
624 s += "_t";
625
626 if (cnst)
627 s += " const";
628
629 if (pntr)
630 s += " *";
631
632 return s.str();
633}
634
635/// BuiltinTypeString - for a modifier and type, generate the clang
636/// BuiltinsARM.def prototype code for the function. See the top of clang's
637/// Builtins.def for a description of the type strings.
638static std::string BuiltinTypeString(const char mod, StringRef typestr,
639 ClassKind ck, bool ret) {
640 bool quad = false;
641 bool poly = false;
642 bool usgn = false;
643 bool scal = false;
644 bool cnst = false;
645 bool pntr = false;
646
647 if (mod == 'v')
648 return "v"; // void
649 if (mod == 'i')
650 return "i"; // int
651
652 // base type to get the type string for.
653 char type = ClassifyType(typestr, quad, poly, usgn);
654
655 // Based on the modifying character, change the type and width if necessary.
656 type = ModType(mod, type, quad, poly, usgn, scal, cnst, pntr);
657
658 // All pointers are void* pointers. Change type to 'v' now.
659 if (pntr) {
660 usgn = false;
661 poly = false;
662 type = 'v';
663 }
664 // Treat half-float ('h') types as unsigned short ('s') types.
665 if (type == 'h') {
666 type = 's';
667 usgn = true;
668 }
Jiangning Liu4617e9d2013-10-04 09:21:17 +0000669 usgn = usgn | poly | ((ck == ClassI || ck == ClassW) &&
670 scal && type != 'f' && type != 'd');
Peter Collingbournebee583f2011-10-06 13:03:08 +0000671
672 if (scal) {
673 SmallString<128> s;
674
675 if (usgn)
676 s.push_back('U');
677 else if (type == 'c')
678 s.push_back('S'); // make chars explicitly signed
679
680 if (type == 'l') // 64-bit long
681 s += "LLi";
682 else
683 s.push_back(type);
684
685 if (cnst)
686 s.push_back('C');
687 if (pntr)
688 s.push_back('*');
689 return s.str();
690 }
691
692 // Since the return value must be one type, return a vector type of the
693 // appropriate width which we will bitcast. An exception is made for
694 // returning structs of 2, 3, or 4 vectors which are returned in a sret-like
695 // fashion, storing them to a pointer arg.
696 if (ret) {
697 if (mod >= '2' && mod <= '4')
698 return "vv*"; // void result with void* first argument
699 if (mod == 'f' || (ck != ClassB && type == 'f'))
700 return quad ? "V4f" : "V2f";
Jiangning Liu4617e9d2013-10-04 09:21:17 +0000701 if (ck != ClassB && type == 'd')
702 return quad ? "V2d" : "V1d";
Peter Collingbournebee583f2011-10-06 13:03:08 +0000703 if (ck != ClassB && type == 's')
704 return quad ? "V8s" : "V4s";
705 if (ck != ClassB && type == 'i')
706 return quad ? "V4i" : "V2i";
707 if (ck != ClassB && type == 'l')
708 return quad ? "V2LLi" : "V1LLi";
709
710 return quad ? "V16Sc" : "V8Sc";
711 }
712
713 // Non-return array types are passed as individual vectors.
714 if (mod == '2')
715 return quad ? "V16ScV16Sc" : "V8ScV8Sc";
716 if (mod == '3')
717 return quad ? "V16ScV16ScV16Sc" : "V8ScV8ScV8Sc";
718 if (mod == '4')
719 return quad ? "V16ScV16ScV16ScV16Sc" : "V8ScV8ScV8ScV8Sc";
720
721 if (mod == 'f' || (ck != ClassB && type == 'f'))
722 return quad ? "V4f" : "V2f";
Jiangning Liu4617e9d2013-10-04 09:21:17 +0000723 if (ck != ClassB && type == 'd')
724 return quad ? "V2d" : "V1d";
Peter Collingbournebee583f2011-10-06 13:03:08 +0000725 if (ck != ClassB && type == 's')
726 return quad ? "V8s" : "V4s";
727 if (ck != ClassB && type == 'i')
728 return quad ? "V4i" : "V2i";
729 if (ck != ClassB && type == 'l')
730 return quad ? "V2LLi" : "V1LLi";
731
732 return quad ? "V16Sc" : "V8Sc";
733}
734
Michael Gottesman095c58f2013-04-16 22:07:30 +0000735/// InstructionTypeCode - Computes the ARM argument character code and
736/// quad status for a specific type string and ClassKind.
737static void InstructionTypeCode(const StringRef &typeStr,
738 const ClassKind ck,
739 bool &quad,
740 std::string &typeCode) {
741 bool poly = false;
742 bool usgn = false;
743 char type = ClassifyType(typeStr, quad, poly, usgn);
744
745 switch (type) {
746 case 'c':
747 switch (ck) {
748 case ClassS: typeCode = poly ? "p8" : usgn ? "u8" : "s8"; break;
749 case ClassI: typeCode = "i8"; break;
750 case ClassW: typeCode = "8"; break;
751 default: break;
752 }
753 break;
754 case 's':
755 switch (ck) {
756 case ClassS: typeCode = poly ? "p16" : usgn ? "u16" : "s16"; break;
757 case ClassI: typeCode = "i16"; break;
758 case ClassW: typeCode = "16"; break;
759 default: break;
760 }
761 break;
762 case 'i':
763 switch (ck) {
764 case ClassS: typeCode = usgn ? "u32" : "s32"; break;
765 case ClassI: typeCode = "i32"; break;
766 case ClassW: typeCode = "32"; break;
767 default: break;
768 }
769 break;
770 case 'l':
771 switch (ck) {
772 case ClassS: typeCode = usgn ? "u64" : "s64"; break;
773 case ClassI: typeCode = "i64"; break;
774 case ClassW: typeCode = "64"; break;
775 default: break;
776 }
777 break;
778 case 'h':
779 switch (ck) {
780 case ClassS:
781 case ClassI: typeCode = "f16"; break;
782 case ClassW: typeCode = "16"; break;
783 default: break;
784 }
785 break;
786 case 'f':
787 switch (ck) {
788 case ClassS:
789 case ClassI: typeCode = "f32"; break;
790 case ClassW: typeCode = "32"; break;
791 default: break;
792 }
793 break;
Tim Northover2fe823a2013-08-01 09:23:19 +0000794 case 'd':
795 switch (ck) {
796 case ClassS:
797 case ClassI:
798 typeCode += "f64";
799 break;
800 case ClassW:
801 PrintFatalError("unhandled type!");
802 default:
803 break;
804 }
805 break;
Michael Gottesman095c58f2013-04-16 22:07:30 +0000806 default:
807 PrintFatalError("unhandled type!");
808 }
809}
810
Kevin Qinc076d062013-08-29 07:55:15 +0000811static char Insert_BHSD_Suffix(StringRef typestr){
812 unsigned off = 0;
813 if(typestr[off++] == 'S'){
814 while(typestr[off] == 'Q' || typestr[off] == 'H'||
815 typestr[off] == 'P' || typestr[off] == 'U')
816 ++off;
817 switch (typestr[off]){
818 default : break;
819 case 'c' : return 'b';
820 case 's' : return 'h';
821 case 'i' :
822 case 'f' : return 's';
823 case 'l' :
824 case 'd' : return 'd';
825 }
826 }
827 return 0;
828}
829
Peter Collingbournebee583f2011-10-06 13:03:08 +0000830/// MangleName - Append a type or width suffix to a base neon function name,
Hao Liu4efa1402013-08-15 08:26:30 +0000831/// and insert a 'q' in the appropriate location if type string starts with 'Q'.
832/// E.g. turn "vst2_lane" into "vst2q_lane_f32", etc.
Kevin Qinc076d062013-08-29 07:55:15 +0000833/// Insert proper 'b' 'h' 's' 'd' if prefix 'S' is used.
Peter Collingbournebee583f2011-10-06 13:03:08 +0000834static std::string MangleName(const std::string &name, StringRef typestr,
835 ClassKind ck) {
836 if (name == "vcvt_f32_f16")
837 return name;
838
839 bool quad = false;
Michael Gottesman095c58f2013-04-16 22:07:30 +0000840 std::string typeCode = "";
841
842 InstructionTypeCode(typestr, ck, quad, typeCode);
Peter Collingbournebee583f2011-10-06 13:03:08 +0000843
844 std::string s = name;
845
Michael Gottesman095c58f2013-04-16 22:07:30 +0000846 if (typeCode.size() > 0) {
847 s += "_" + typeCode;
Peter Collingbournebee583f2011-10-06 13:03:08 +0000848 }
Michael Gottesman095c58f2013-04-16 22:07:30 +0000849
Peter Collingbournebee583f2011-10-06 13:03:08 +0000850 if (ck == ClassB)
851 s += "_v";
852
853 // Insert a 'q' before the first '_' character so that it ends up before
854 // _lane or _n on vector-scalar operations.
Kevin Qinc076d062013-08-29 07:55:15 +0000855 if (typestr.find("Q") != StringRef::npos) {
Hao Liu4efa1402013-08-15 08:26:30 +0000856 size_t pos = s.find('_');
857 s = s.insert(pos, "q");
Peter Collingbournebee583f2011-10-06 13:03:08 +0000858 }
Kevin Qinc076d062013-08-29 07:55:15 +0000859 char ins = Insert_BHSD_Suffix(typestr);
860 if(ins){
861 size_t pos = s.find('_');
862 s = s.insert(pos, &ins, 1);
863 }
Michael Gottesman6cd3e562013-04-16 23:00:26 +0000864
Peter Collingbournebee583f2011-10-06 13:03:08 +0000865 return s;
866}
867
Michael Gottesman6cd3e562013-04-16 23:00:26 +0000868static void PreprocessInstruction(const StringRef &Name,
869 const std::string &InstName,
870 std::string &Prefix,
871 bool &HasNPostfix,
872 bool &HasLanePostfix,
873 bool &HasDupPostfix,
874 bool &IsSpecialVCvt,
875 size_t &TBNumber) {
876 // All of our instruction name fields from arm_neon.td are of the form
877 // <instructionname>_...
878 // Thus we grab our instruction name via computation of said Prefix.
879 const size_t PrefixEnd = Name.find_first_of('_');
880 // If InstName is passed in, we use that instead of our name Prefix.
881 Prefix = InstName.size() == 0? Name.slice(0, PrefixEnd).str() : InstName;
882
883 const StringRef Postfix = Name.slice(PrefixEnd, Name.size());
884
885 HasNPostfix = Postfix.count("_n");
886 HasLanePostfix = Postfix.count("_lane");
887 HasDupPostfix = Postfix.count("_dup");
888 IsSpecialVCvt = Postfix.size() != 0 && Name.count("vcvt");
889
890 if (InstName.compare("vtbl") == 0 ||
891 InstName.compare("vtbx") == 0) {
892 // If we have a vtblN/vtbxN instruction, use the instruction's ASCII
893 // encoding to get its true value.
894 TBNumber = Name[Name.size()-1] - 48;
895 }
896}
897
898/// GenerateRegisterCheckPatternsForLoadStores - Given a bunch of data we have
899/// extracted, generate a FileCheck pattern for a Load Or Store
900static void
901GenerateRegisterCheckPatternForLoadStores(const StringRef &NameRef,
902 const std::string& OutTypeCode,
903 const bool &IsQuad,
904 const bool &HasDupPostfix,
905 const bool &HasLanePostfix,
906 const size_t Count,
907 std::string &RegisterSuffix) {
908 const bool IsLDSTOne = NameRef.count("vld1") || NameRef.count("vst1");
909 // If N == 3 || N == 4 and we are dealing with a quad instruction, Clang
910 // will output a series of v{ld,st}1s, so we have to handle it specially.
911 if ((Count == 3 || Count == 4) && IsQuad) {
912 RegisterSuffix += "{";
913 for (size_t i = 0; i < Count; i++) {
914 RegisterSuffix += "d{{[0-9]+}}";
915 if (HasDupPostfix) {
916 RegisterSuffix += "[]";
917 }
918 if (HasLanePostfix) {
919 RegisterSuffix += "[{{[0-9]+}}]";
920 }
921 if (i < Count-1) {
922 RegisterSuffix += ", ";
923 }
924 }
925 RegisterSuffix += "}";
926 } else {
927
928 // Handle normal loads and stores.
929 RegisterSuffix += "{";
930 for (size_t i = 0; i < Count; i++) {
931 RegisterSuffix += "d{{[0-9]+}}";
932 if (HasDupPostfix) {
933 RegisterSuffix += "[]";
934 }
935 if (HasLanePostfix) {
936 RegisterSuffix += "[{{[0-9]+}}]";
937 }
938 if (IsQuad && !HasLanePostfix) {
939 RegisterSuffix += ", d{{[0-9]+}}";
940 if (HasDupPostfix) {
941 RegisterSuffix += "[]";
942 }
943 }
944 if (i < Count-1) {
945 RegisterSuffix += ", ";
946 }
947 }
948 RegisterSuffix += "}, [r{{[0-9]+}}";
949
950 // We only include the alignment hint if we have a vld1.*64 or
951 // a dup/lane instruction.
952 if (IsLDSTOne) {
953 if ((HasLanePostfix || HasDupPostfix) && OutTypeCode != "8") {
Michael Gottesmanc6b5e562013-06-24 21:25:37 +0000954 RegisterSuffix += ":" + OutTypeCode;
Michael Gottesman6cd3e562013-04-16 23:00:26 +0000955 }
956 }
957
958 RegisterSuffix += "]";
959 }
960}
961
962static bool HasNPostfixAndScalarArgs(const StringRef &NameRef,
963 const bool &HasNPostfix) {
964 return (NameRef.count("vmla") ||
965 NameRef.count("vmlal") ||
966 NameRef.count("vmlsl") ||
967 NameRef.count("vmull") ||
968 NameRef.count("vqdmlal") ||
969 NameRef.count("vqdmlsl") ||
970 NameRef.count("vqdmulh") ||
971 NameRef.count("vqdmull") ||
972 NameRef.count("vqrdmulh")) && HasNPostfix;
973}
974
975static bool IsFiveOperandLaneAccumulator(const StringRef &NameRef,
976 const bool &HasLanePostfix) {
977 return (NameRef.count("vmla") ||
978 NameRef.count("vmls") ||
979 NameRef.count("vmlal") ||
980 NameRef.count("vmlsl") ||
981 (NameRef.count("vmul") && NameRef.size() == 3)||
982 NameRef.count("vqdmlal") ||
983 NameRef.count("vqdmlsl") ||
984 NameRef.count("vqdmulh") ||
985 NameRef.count("vqrdmulh")) && HasLanePostfix;
986}
987
988static bool IsSpecialLaneMultiply(const StringRef &NameRef,
989 const bool &HasLanePostfix,
990 const bool &IsQuad) {
991 const bool IsVMulOrMulh = (NameRef.count("vmul") || NameRef.count("mulh"))
992 && IsQuad;
993 const bool IsVMull = NameRef.count("mull") && !IsQuad;
994 return (IsVMulOrMulh || IsVMull) && HasLanePostfix;
995}
996
997static void NormalizeProtoForRegisterPatternCreation(const std::string &Name,
998 const std::string &Proto,
999 const bool &HasNPostfix,
1000 const bool &IsQuad,
1001 const bool &HasLanePostfix,
1002 const bool &HasDupPostfix,
1003 std::string &NormedProto) {
1004 // Handle generic case.
1005 const StringRef NameRef(Name);
1006 for (size_t i = 0, end = Proto.size(); i < end; i++) {
1007 switch (Proto[i]) {
1008 case 'u':
1009 case 'f':
1010 case 'd':
1011 case 's':
1012 case 'x':
1013 case 't':
1014 case 'n':
1015 NormedProto += IsQuad? 'q' : 'd';
1016 break;
1017 case 'w':
1018 case 'k':
1019 NormedProto += 'q';
1020 break;
1021 case 'g':
Jiangning Liu4617e9d2013-10-04 09:21:17 +00001022 case 'j':
Michael Gottesman6cd3e562013-04-16 23:00:26 +00001023 case 'h':
1024 case 'e':
1025 NormedProto += 'd';
1026 break;
1027 case 'i':
1028 NormedProto += HasLanePostfix? 'a' : 'i';
1029 break;
1030 case 'a':
1031 if (HasLanePostfix) {
1032 NormedProto += 'a';
1033 } else if (HasNPostfixAndScalarArgs(NameRef, HasNPostfix)) {
1034 NormedProto += IsQuad? 'q' : 'd';
1035 } else {
1036 NormedProto += 'i';
1037 }
1038 break;
1039 }
1040 }
1041
1042 // Handle Special Cases.
1043 const bool IsNotVExt = !NameRef.count("vext");
1044 const bool IsVPADAL = NameRef.count("vpadal");
1045 const bool Is5OpLaneAccum = IsFiveOperandLaneAccumulator(NameRef,
1046 HasLanePostfix);
1047 const bool IsSpecialLaneMul = IsSpecialLaneMultiply(NameRef, HasLanePostfix,
1048 IsQuad);
1049
1050 if (IsSpecialLaneMul) {
1051 // If
1052 NormedProto[2] = NormedProto[3];
1053 NormedProto.erase(3);
1054 } else if (NormedProto.size() == 4 &&
1055 NormedProto[0] == NormedProto[1] &&
1056 IsNotVExt) {
1057 // If NormedProto.size() == 4 and the first two proto characters are the
1058 // same, ignore the first.
1059 NormedProto = NormedProto.substr(1, 3);
1060 } else if (Is5OpLaneAccum) {
1061 // If we have a 5 op lane accumulator operation, we take characters 1,2,4
1062 std::string tmp = NormedProto.substr(1,2);
1063 tmp += NormedProto[4];
1064 NormedProto = tmp;
1065 } else if (IsVPADAL) {
1066 // If we have VPADAL, ignore the first character.
1067 NormedProto = NormedProto.substr(0, 2);
1068 } else if (NameRef.count("vdup") && NormedProto.size() > 2) {
1069 // If our instruction is a dup instruction, keep only the first and
1070 // last characters.
1071 std::string tmp = "";
1072 tmp += NormedProto[0];
1073 tmp += NormedProto[NormedProto.size()-1];
1074 NormedProto = tmp;
1075 }
1076}
1077
1078/// GenerateRegisterCheckPatterns - Given a bunch of data we have
1079/// extracted, generate a FileCheck pattern to check that an
1080/// instruction's arguments are correct.
1081static void GenerateRegisterCheckPattern(const std::string &Name,
1082 const std::string &Proto,
1083 const std::string &OutTypeCode,
1084 const bool &HasNPostfix,
1085 const bool &IsQuad,
1086 const bool &HasLanePostfix,
1087 const bool &HasDupPostfix,
1088 const size_t &TBNumber,
1089 std::string &RegisterSuffix) {
1090
1091 RegisterSuffix = "";
1092
1093 const StringRef NameRef(Name);
1094 const StringRef ProtoRef(Proto);
1095
1096 if ((NameRef.count("vdup") || NameRef.count("vmov")) && HasNPostfix) {
1097 return;
1098 }
1099
1100 const bool IsLoadStore = NameRef.count("vld") || NameRef.count("vst");
1101 const bool IsTBXOrTBL = NameRef.count("vtbl") || NameRef.count("vtbx");
1102
1103 if (IsLoadStore) {
1104 // Grab N value from v{ld,st}N using its ascii representation.
1105 const size_t Count = NameRef[3] - 48;
1106
1107 GenerateRegisterCheckPatternForLoadStores(NameRef, OutTypeCode, IsQuad,
1108 HasDupPostfix, HasLanePostfix,
1109 Count, RegisterSuffix);
1110 } else if (IsTBXOrTBL) {
1111 RegisterSuffix += "d{{[0-9]+}}, {";
1112 for (size_t i = 0; i < TBNumber-1; i++) {
1113 RegisterSuffix += "d{{[0-9]+}}, ";
1114 }
1115 RegisterSuffix += "d{{[0-9]+}}}, d{{[0-9]+}}";
1116 } else {
1117 // Handle a normal instruction.
1118 if (NameRef.count("vget") || NameRef.count("vset"))
1119 return;
1120
1121 // We first normalize our proto, since we only need to emit 4
1122 // different types of checks, yet have more than 4 proto types
1123 // that map onto those 4 patterns.
1124 std::string NormalizedProto("");
1125 NormalizeProtoForRegisterPatternCreation(Name, Proto, HasNPostfix, IsQuad,
1126 HasLanePostfix, HasDupPostfix,
1127 NormalizedProto);
1128
1129 for (size_t i = 0, end = NormalizedProto.size(); i < end; i++) {
1130 const char &c = NormalizedProto[i];
1131 switch (c) {
1132 case 'q':
1133 RegisterSuffix += "q{{[0-9]+}}, ";
1134 break;
1135
1136 case 'd':
1137 RegisterSuffix += "d{{[0-9]+}}, ";
1138 break;
1139
1140 case 'i':
1141 RegisterSuffix += "#{{[0-9]+}}, ";
1142 break;
1143
1144 case 'a':
1145 RegisterSuffix += "d{{[0-9]+}}[{{[0-9]}}], ";
1146 break;
1147 }
1148 }
1149
1150 // Remove extra ", ".
1151 RegisterSuffix = RegisterSuffix.substr(0, RegisterSuffix.size()-2);
1152 }
1153}
1154
1155/// GenerateChecksForIntrinsic - Given a specific instruction name +
1156/// typestr + class kind, generate the proper set of FileCheck
1157/// Patterns to check for. We could just return a string, but instead
1158/// use a vector since it provides us with the extra flexibility of
1159/// emitting multiple checks, which comes in handy for certain cases
1160/// like mla where we want to check for 2 different instructions.
1161static void GenerateChecksForIntrinsic(const std::string &Name,
1162 const std::string &Proto,
1163 StringRef &OutTypeStr,
1164 StringRef &InTypeStr,
1165 ClassKind Ck,
1166 const std::string &InstName,
1167 bool IsHiddenLOp,
1168 std::vector<std::string>& Result) {
1169
1170 // If Ck is a ClassNoTest instruction, just return so no test is
1171 // emitted.
1172 if(Ck == ClassNoTest)
1173 return;
1174
1175 if (Name == "vcvt_f32_f16") {
1176 Result.push_back("vcvt.f32.f16");
1177 return;
1178 }
1179
1180
1181 // Now we preprocess our instruction given the data we have to get the
1182 // data that we need.
1183 // Create a StringRef for String Manipulation of our Name.
1184 const StringRef NameRef(Name);
1185 // Instruction Prefix.
1186 std::string Prefix;
1187 // The type code for our out type string.
1188 std::string OutTypeCode;
1189 // To handle our different cases, we need to check for different postfixes.
1190 // Is our instruction a quad instruction.
1191 bool IsQuad = false;
1192 // Our instruction is of the form <instructionname>_n.
1193 bool HasNPostfix = false;
1194 // Our instruction is of the form <instructionname>_lane.
1195 bool HasLanePostfix = false;
1196 // Our instruction is of the form <instructionname>_dup.
1197 bool HasDupPostfix = false;
1198 // Our instruction is a vcvt instruction which requires special handling.
1199 bool IsSpecialVCvt = false;
1200 // If we have a vtbxN or vtblN instruction, this is set to N.
1201 size_t TBNumber = -1;
1202 // Register Suffix
1203 std::string RegisterSuffix;
1204
1205 PreprocessInstruction(NameRef, InstName, Prefix,
1206 HasNPostfix, HasLanePostfix, HasDupPostfix,
1207 IsSpecialVCvt, TBNumber);
1208
1209 InstructionTypeCode(OutTypeStr, Ck, IsQuad, OutTypeCode);
1210 GenerateRegisterCheckPattern(Name, Proto, OutTypeCode, HasNPostfix, IsQuad,
1211 HasLanePostfix, HasDupPostfix, TBNumber,
1212 RegisterSuffix);
1213
1214 // In the following section, we handle a bunch of special cases. You can tell
1215 // a special case by the fact we are returning early.
1216
1217 // If our instruction is a logical instruction without postfix or a
1218 // hidden LOp just return the current Prefix.
1219 if (Ck == ClassL || IsHiddenLOp) {
1220 Result.push_back(Prefix + " " + RegisterSuffix);
1221 return;
1222 }
1223
1224 // If we have a vmov, due to the many different cases, some of which
1225 // vary within the different intrinsics generated for a single
1226 // instruction type, just output a vmov. (e.g. given an instruction
1227 // A, A.u32 might be vmov and A.u8 might be vmov.8).
1228 //
1229 // FIXME: Maybe something can be done about this. The two cases that we care
1230 // about are vmov as an LType and vmov as a WType.
1231 if (Prefix == "vmov") {
1232 Result.push_back(Prefix + " " + RegisterSuffix);
1233 return;
1234 }
1235
1236 // In the following section, we handle special cases.
1237
1238 if (OutTypeCode == "64") {
1239 // If we have a 64 bit vdup/vext and are handling an uint64x1_t
1240 // type, the intrinsic will be optimized away, so just return
1241 // nothing. On the other hand if we are handling an uint64x2_t
1242 // (i.e. quad instruction), vdup/vmov instructions should be
1243 // emitted.
1244 if (Prefix == "vdup" || Prefix == "vext") {
1245 if (IsQuad) {
1246 Result.push_back("{{vmov|vdup}}");
1247 }
1248 return;
1249 }
1250
1251 // v{st,ld}{2,3,4}_{u,s}64 emit v{st,ld}1.64 instructions with
1252 // multiple register operands.
1253 bool MultiLoadPrefix = Prefix == "vld2" || Prefix == "vld3"
1254 || Prefix == "vld4";
1255 bool MultiStorePrefix = Prefix == "vst2" || Prefix == "vst3"
1256 || Prefix == "vst4";
1257 if (MultiLoadPrefix || MultiStorePrefix) {
1258 Result.push_back(NameRef.slice(0, 3).str() + "1.64");
1259 return;
1260 }
1261
1262 // v{st,ld}1_{lane,dup}_{u64,s64} use vldr/vstr/vmov/str instead of
1263 // emitting said instructions. So return a check for
1264 // vldr/vstr/vmov/str instead.
1265 if (HasLanePostfix || HasDupPostfix) {
1266 if (Prefix == "vst1") {
1267 Result.push_back("{{str|vstr|vmov}}");
1268 return;
1269 } else if (Prefix == "vld1") {
1270 Result.push_back("{{ldr|vldr|vmov}}");
1271 return;
1272 }
1273 }
1274 }
1275
1276 // vzip.32/vuzp.32 are the same instruction as vtrn.32 and are
1277 // sometimes disassembled as vtrn.32. We use a regex to handle both
1278 // cases.
1279 if ((Prefix == "vzip" || Prefix == "vuzp") && OutTypeCode == "32") {
1280 Result.push_back("{{vtrn|" + Prefix + "}}.32 " + RegisterSuffix);
1281 return;
1282 }
1283
1284 // Currently on most ARM processors, we do not use vmla/vmls for
1285 // quad floating point operations. Instead we output vmul + vadd. So
1286 // check if we have one of those instructions and just output a
1287 // check for vmul.
1288 if (OutTypeCode == "f32") {
1289 if (Prefix == "vmls") {
1290 Result.push_back("vmul." + OutTypeCode + " " + RegisterSuffix);
1291 Result.push_back("vsub." + OutTypeCode);
1292 return;
1293 } else if (Prefix == "vmla") {
1294 Result.push_back("vmul." + OutTypeCode + " " + RegisterSuffix);
1295 Result.push_back("vadd." + OutTypeCode);
1296 return;
1297 }
1298 }
1299
1300 // If we have vcvt, get the input type from the instruction name
1301 // (which should be of the form instname_inputtype) and append it
1302 // before the output type.
1303 if (Prefix == "vcvt") {
1304 const std::string inTypeCode = NameRef.substr(NameRef.find_last_of("_")+1);
1305 Prefix += "." + inTypeCode;
1306 }
1307
1308 // Append output type code to get our final mangled instruction.
1309 Prefix += "." + OutTypeCode;
1310
1311 Result.push_back(Prefix + " " + RegisterSuffix);
1312}
1313
Peter Collingbournebee583f2011-10-06 13:03:08 +00001314/// UseMacro - Examine the prototype string to determine if the intrinsic
1315/// should be defined as a preprocessor macro instead of an inline function.
1316static bool UseMacro(const std::string &proto) {
1317 // If this builtin takes an immediate argument, we need to #define it rather
1318 // than use a standard declaration, so that SemaChecking can range check
1319 // the immediate passed by the user.
1320 if (proto.find('i') != std::string::npos)
1321 return true;
1322
1323 // Pointer arguments need to use macros to avoid hiding aligned attributes
1324 // from the pointer type.
1325 if (proto.find('p') != std::string::npos ||
1326 proto.find('c') != std::string::npos)
1327 return true;
1328
1329 return false;
1330}
1331
1332/// MacroArgUsedDirectly - Return true if argument i for an intrinsic that is
1333/// defined as a macro should be accessed directly instead of being first
1334/// assigned to a local temporary.
1335static bool MacroArgUsedDirectly(const std::string &proto, unsigned i) {
1336 // True for constant ints (i), pointers (p) and const pointers (c).
1337 return (proto[i] == 'i' || proto[i] == 'p' || proto[i] == 'c');
1338}
1339
1340// Generate the string "(argtype a, argtype b, ...)"
Kevin Qinf22bf502013-10-11 02:34:30 +00001341static std::string GenArgs(const std::string &proto, StringRef typestr,
1342 const std::string &name) {
Peter Collingbournebee583f2011-10-06 13:03:08 +00001343 bool define = UseMacro(proto);
1344 char arg = 'a';
1345
1346 std::string s;
1347 s += "(";
1348
1349 for (unsigned i = 1, e = proto.size(); i != e; ++i, ++arg) {
1350 if (define) {
1351 // Some macro arguments are used directly instead of being assigned
1352 // to local temporaries; prepend an underscore prefix to make their
1353 // names consistent with the local temporaries.
1354 if (MacroArgUsedDirectly(proto, i))
1355 s += "__";
1356 } else {
1357 s += TypeString(proto[i], typestr) + " __";
1358 }
1359 s.push_back(arg);
Kevin Qinf22bf502013-10-11 02:34:30 +00001360 //To avoid argument being multiple defined, add extra number for renaming.
1361 if (name == "vcopy_lane")
1362 s.push_back('1');
Peter Collingbournebee583f2011-10-06 13:03:08 +00001363 if ((i + 1) < e)
1364 s += ", ";
1365 }
1366
1367 s += ")";
1368 return s;
1369}
1370
1371// Macro arguments are not type-checked like inline function arguments, so
1372// assign them to local temporaries to get the right type checking.
Kevin Qinf22bf502013-10-11 02:34:30 +00001373static std::string GenMacroLocals(const std::string &proto, StringRef typestr,
1374 const std::string &name ) {
Peter Collingbournebee583f2011-10-06 13:03:08 +00001375 char arg = 'a';
1376 std::string s;
1377 bool generatedLocal = false;
1378
1379 for (unsigned i = 1, e = proto.size(); i != e; ++i, ++arg) {
1380 // Do not create a temporary for an immediate argument.
1381 // That would defeat the whole point of using a macro!
Peter Collingbournebee583f2011-10-06 13:03:08 +00001382 if (MacroArgUsedDirectly(proto, i))
1383 continue;
1384 generatedLocal = true;
Kevin Qinf22bf502013-10-11 02:34:30 +00001385 bool extranumber = false;
1386 if(name == "vcopy_lane")
1387 extranumber = true;
Peter Collingbournebee583f2011-10-06 13:03:08 +00001388
1389 s += TypeString(proto[i], typestr) + " __";
1390 s.push_back(arg);
Kevin Qinf22bf502013-10-11 02:34:30 +00001391 if(extranumber)
1392 s.push_back('1');
Peter Collingbournebee583f2011-10-06 13:03:08 +00001393 s += " = (";
1394 s.push_back(arg);
Kevin Qinf22bf502013-10-11 02:34:30 +00001395 if(extranumber)
1396 s.push_back('1');
Peter Collingbournebee583f2011-10-06 13:03:08 +00001397 s += "); ";
1398 }
1399
1400 if (generatedLocal)
1401 s += "\\\n ";
1402 return s;
1403}
1404
1405// Use the vmovl builtin to sign-extend or zero-extend a vector.
Jiangning Liu1bda93a2013-09-09 02:21:08 +00001406static std::string Extend(StringRef typestr, const std::string &a, bool h=0) {
1407 std::string s, high;
1408 high = h ? "_high" : "";
1409 s = MangleName("vmovl" + high, typestr, ClassS);
Peter Collingbournebee583f2011-10-06 13:03:08 +00001410 s += "(" + a + ")";
1411 return s;
1412}
1413
Jiangning Liu1bda93a2013-09-09 02:21:08 +00001414// Get the high 64-bit part of a vector
1415static std::string GetHigh(const std::string &a, StringRef typestr) {
1416 std::string s;
1417 s = MangleName("vget_high", typestr, ClassS);
1418 s += "(" + a + ")";
1419 return s;
1420}
1421
1422// Gen operation with two operands and get high 64-bit for both of two operands.
1423static std::string Gen2OpWith2High(StringRef typestr,
1424 const std::string &op,
1425 const std::string &a,
1426 const std::string &b) {
1427 std::string s;
1428 std::string Op1 = GetHigh(a, typestr);
1429 std::string Op2 = GetHigh(b, typestr);
1430 s = MangleName(op, typestr, ClassS);
1431 s += "(" + Op1 + ", " + Op2 + ");";
1432 return s;
1433}
1434
1435// Gen operation with three operands and get high 64-bit of the latter
1436// two operands.
1437static std::string Gen3OpWith2High(StringRef typestr,
1438 const std::string &op,
1439 const std::string &a,
1440 const std::string &b,
1441 const std::string &c) {
1442 std::string s;
1443 std::string Op1 = GetHigh(b, typestr);
1444 std::string Op2 = GetHigh(c, typestr);
1445 s = MangleName(op, typestr, ClassS);
1446 s += "(" + a + ", " + Op1 + ", " + Op2 + ");";
1447 return s;
1448}
1449
1450// Gen combine operation by putting a on low 64-bit, and b on high 64-bit.
1451static std::string GenCombine(std::string typestr,
1452 const std::string &a,
1453 const std::string &b) {
1454 std::string s;
1455 s = MangleName("vcombine", typestr, ClassS);
1456 s += "(" + a + ", " + b + ")";
1457 return s;
1458}
1459
Peter Collingbournebee583f2011-10-06 13:03:08 +00001460static std::string Duplicate(unsigned nElts, StringRef typestr,
1461 const std::string &a) {
1462 std::string s;
1463
1464 s = "(" + TypeString('d', typestr) + "){ ";
1465 for (unsigned i = 0; i != nElts; ++i) {
1466 s += a;
1467 if ((i + 1) < nElts)
1468 s += ", ";
1469 }
1470 s += " }";
1471
1472 return s;
1473}
1474
1475static std::string SplatLane(unsigned nElts, const std::string &vec,
1476 const std::string &lane) {
1477 std::string s = "__builtin_shufflevector(" + vec + ", " + vec;
1478 for (unsigned i = 0; i < nElts; ++i)
1479 s += ", " + lane;
1480 s += ")";
1481 return s;
1482}
1483
Hao Liub1852ee2013-09-04 09:29:13 +00001484static std::string RemoveHigh(const std::string &name) {
1485 std::string s = name;
1486 std::size_t found = s.find("_high_");
1487 if (found == std::string::npos)
1488 PrintFatalError("name should contain \"_high_\" for high intrinsics");
1489 s.replace(found, 5, "");
1490 return s;
1491}
1492
Peter Collingbournebee583f2011-10-06 13:03:08 +00001493static unsigned GetNumElements(StringRef typestr, bool &quad) {
1494 quad = false;
1495 bool dummy = false;
1496 char type = ClassifyType(typestr, quad, dummy, dummy);
1497 unsigned nElts = 0;
1498 switch (type) {
1499 case 'c': nElts = 8; break;
1500 case 's': nElts = 4; break;
1501 case 'i': nElts = 2; break;
1502 case 'l': nElts = 1; break;
1503 case 'h': nElts = 4; break;
1504 case 'f': nElts = 2; break;
Tim Northover2fe823a2013-08-01 09:23:19 +00001505 case 'd':
1506 nElts = 1;
1507 break;
Peter Collingbournebee583f2011-10-06 13:03:08 +00001508 default:
Joerg Sonnenberger691a16b2012-10-25 16:37:08 +00001509 PrintFatalError("unhandled type!");
Peter Collingbournebee583f2011-10-06 13:03:08 +00001510 }
1511 if (quad) nElts <<= 1;
1512 return nElts;
1513}
1514
1515// Generate the definition for this intrinsic, e.g. "a + b" for OpAdd.
Hao Liub1852ee2013-09-04 09:29:13 +00001516static std::string GenOpString(const std::string &name, OpKind op,
1517 const std::string &proto, StringRef typestr) {
Peter Collingbournebee583f2011-10-06 13:03:08 +00001518 bool quad;
1519 unsigned nElts = GetNumElements(typestr, quad);
1520 bool define = UseMacro(proto);
1521
1522 std::string ts = TypeString(proto[0], typestr);
1523 std::string s;
1524 if (!define) {
1525 s = "return ";
1526 }
1527
1528 switch(op) {
1529 case OpAdd:
1530 s += "__a + __b;";
1531 break;
1532 case OpAddl:
1533 s += Extend(typestr, "__a") + " + " + Extend(typestr, "__b") + ";";
1534 break;
Jiangning Liu1bda93a2013-09-09 02:21:08 +00001535 case OpAddlHi:
1536 s += Extend(typestr, "__a", 1) + " + " + Extend(typestr, "__b", 1) + ";";
1537 break;
Peter Collingbournebee583f2011-10-06 13:03:08 +00001538 case OpAddw:
1539 s += "__a + " + Extend(typestr, "__b") + ";";
1540 break;
Jiangning Liu1bda93a2013-09-09 02:21:08 +00001541 case OpAddwHi:
1542 s += "__a + " + Extend(typestr, "__b", 1) + ";";
1543 break;
Peter Collingbournebee583f2011-10-06 13:03:08 +00001544 case OpSub:
1545 s += "__a - __b;";
1546 break;
1547 case OpSubl:
1548 s += Extend(typestr, "__a") + " - " + Extend(typestr, "__b") + ";";
1549 break;
Jiangning Liu1bda93a2013-09-09 02:21:08 +00001550 case OpSublHi:
1551 s += Extend(typestr, "__a", 1) + " - " + Extend(typestr, "__b", 1) + ";";
1552 break;
Peter Collingbournebee583f2011-10-06 13:03:08 +00001553 case OpSubw:
1554 s += "__a - " + Extend(typestr, "__b") + ";";
1555 break;
Jiangning Liu1bda93a2013-09-09 02:21:08 +00001556 case OpSubwHi:
1557 s += "__a - " + Extend(typestr, "__b", 1) + ";";
1558 break;
Peter Collingbournebee583f2011-10-06 13:03:08 +00001559 case OpMulN:
1560 s += "__a * " + Duplicate(nElts, typestr, "__b") + ";";
1561 break;
1562 case OpMulLane:
1563 s += "__a * " + SplatLane(nElts, "__b", "__c") + ";";
1564 break;
Jiangning Liu4617e9d2013-10-04 09:21:17 +00001565 case OpMulXLane:
1566 s += MangleName("vmulx", typestr, ClassS) + "(__a, " +
1567 SplatLane(nElts, "__b", "__c") + ");";
1568 break;
Peter Collingbournebee583f2011-10-06 13:03:08 +00001569 case OpMul:
1570 s += "__a * __b;";
1571 break;
1572 case OpMullLane:
1573 s += MangleName("vmull", typestr, ClassS) + "(__a, " +
1574 SplatLane(nElts, "__b", "__c") + ");";
1575 break;
Jiangning Liu4617e9d2013-10-04 09:21:17 +00001576 case OpMullHiLane:
1577 s += MangleName("vmull", typestr, ClassS) + "(" +
1578 GetHigh("__a", typestr) + ", " + SplatLane(nElts, "__b", "__c") + ");";
1579 break;
Peter Collingbournebee583f2011-10-06 13:03:08 +00001580 case OpMlaN:
1581 s += "__a + (__b * " + Duplicate(nElts, typestr, "__c") + ");";
1582 break;
1583 case OpMlaLane:
1584 s += "__a + (__b * " + SplatLane(nElts, "__c", "__d") + ");";
1585 break;
1586 case OpMla:
1587 s += "__a + (__b * __c);";
1588 break;
1589 case OpMlalN:
1590 s += "__a + " + MangleName("vmull", typestr, ClassS) + "(__b, " +
1591 Duplicate(nElts, typestr, "__c") + ");";
1592 break;
1593 case OpMlalLane:
1594 s += "__a + " + MangleName("vmull", typestr, ClassS) + "(__b, " +
1595 SplatLane(nElts, "__c", "__d") + ");";
1596 break;
Jiangning Liu4617e9d2013-10-04 09:21:17 +00001597 case OpMlalHiLane:
1598 s += "__a + " + MangleName("vmull", typestr, ClassS) + "(" +
1599 GetHigh("__b", typestr) + ", " + SplatLane(nElts, "__c", "__d") + ");";
1600 break;
Peter Collingbournebee583f2011-10-06 13:03:08 +00001601 case OpMlal:
1602 s += "__a + " + MangleName("vmull", typestr, ClassS) + "(__b, __c);";
1603 break;
Jiangning Liu1bda93a2013-09-09 02:21:08 +00001604 case OpMullHi:
1605 s += Gen2OpWith2High(typestr, "vmull", "__a", "__b");
1606 break;
1607 case OpMlalHi:
1608 s += Gen3OpWith2High(typestr, "vmlal", "__a", "__b", "__c");
1609 break;
Peter Collingbournebee583f2011-10-06 13:03:08 +00001610 case OpMlsN:
1611 s += "__a - (__b * " + Duplicate(nElts, typestr, "__c") + ");";
1612 break;
1613 case OpMlsLane:
1614 s += "__a - (__b * " + SplatLane(nElts, "__c", "__d") + ");";
1615 break;
Jiangning Liu4617e9d2013-10-04 09:21:17 +00001616 case OpFMSLane:
1617 s += TypeString(proto[1], typestr) + " __a1 = __a; \\\n ";
1618 s += TypeString(proto[2], typestr) + " __b1 = __b; \\\n ";
1619 s += TypeString(proto[3], typestr) + " __c1 = __c; \\\n ";
1620 s += MangleName("vfma_lane", typestr, ClassS) + "(__a1, __b1, -__c1, __d);";
1621 break;
1622 case OpFMSLaneQ:
1623 s += TypeString(proto[1], typestr) + " __a1 = __a; \\\n ";
1624 s += TypeString(proto[2], typestr) + " __b1 = __b; \\\n ";
1625 s += TypeString(proto[3], typestr) + " __c1 = __c; \\\n ";
1626 s += MangleName("vfma_laneq", typestr, ClassS) + "(__a1, __b1, -__c1, __d);";
1627 break;
Peter Collingbournebee583f2011-10-06 13:03:08 +00001628 case OpMls:
1629 s += "__a - (__b * __c);";
1630 break;
1631 case OpMlslN:
1632 s += "__a - " + MangleName("vmull", typestr, ClassS) + "(__b, " +
1633 Duplicate(nElts, typestr, "__c") + ");";
1634 break;
1635 case OpMlslLane:
1636 s += "__a - " + MangleName("vmull", typestr, ClassS) + "(__b, " +
1637 SplatLane(nElts, "__c", "__d") + ");";
1638 break;
Jiangning Liu4617e9d2013-10-04 09:21:17 +00001639 case OpMlslHiLane:
1640 s += "__a - " + MangleName("vmull", typestr, ClassS) + "(" +
1641 GetHigh("__b", typestr) + ", " + SplatLane(nElts, "__c", "__d") + ");";
1642 break;
Peter Collingbournebee583f2011-10-06 13:03:08 +00001643 case OpMlsl:
1644 s += "__a - " + MangleName("vmull", typestr, ClassS) + "(__b, __c);";
1645 break;
Jiangning Liu1bda93a2013-09-09 02:21:08 +00001646 case OpMlslHi:
1647 s += Gen3OpWith2High(typestr, "vmlsl", "__a", "__b", "__c");
1648 break;
Peter Collingbournebee583f2011-10-06 13:03:08 +00001649 case OpQDMullLane:
1650 s += MangleName("vqdmull", typestr, ClassS) + "(__a, " +
1651 SplatLane(nElts, "__b", "__c") + ");";
1652 break;
Jiangning Liu4617e9d2013-10-04 09:21:17 +00001653 case OpQDMullHiLane:
1654 s += MangleName("vqdmull", typestr, ClassS) + "(" +
1655 GetHigh("__a", typestr) + ", " + SplatLane(nElts, "__b", "__c") + ");";
1656 break;
Peter Collingbournebee583f2011-10-06 13:03:08 +00001657 case OpQDMlalLane:
1658 s += MangleName("vqdmlal", typestr, ClassS) + "(__a, __b, " +
1659 SplatLane(nElts, "__c", "__d") + ");";
1660 break;
Jiangning Liu4617e9d2013-10-04 09:21:17 +00001661 case OpQDMlalHiLane:
1662 s += MangleName("vqdmlal", typestr, ClassS) + "(__a, " +
1663 GetHigh("__b", typestr) + ", " + SplatLane(nElts, "__c", "__d") + ");";
1664 break;
Peter Collingbournebee583f2011-10-06 13:03:08 +00001665 case OpQDMlslLane:
1666 s += MangleName("vqdmlsl", typestr, ClassS) + "(__a, __b, " +
1667 SplatLane(nElts, "__c", "__d") + ");";
1668 break;
Jiangning Liu4617e9d2013-10-04 09:21:17 +00001669 case OpQDMlslHiLane:
1670 s += MangleName("vqdmlsl", typestr, ClassS) + "(__a, " +
1671 GetHigh("__b", typestr) + ", " + SplatLane(nElts, "__c", "__d") + ");";
1672 break;
Peter Collingbournebee583f2011-10-06 13:03:08 +00001673 case OpQDMulhLane:
1674 s += MangleName("vqdmulh", typestr, ClassS) + "(__a, " +
1675 SplatLane(nElts, "__b", "__c") + ");";
1676 break;
1677 case OpQRDMulhLane:
1678 s += MangleName("vqrdmulh", typestr, ClassS) + "(__a, " +
1679 SplatLane(nElts, "__b", "__c") + ");";
1680 break;
1681 case OpEq:
1682 s += "(" + ts + ")(__a == __b);";
1683 break;
1684 case OpGe:
1685 s += "(" + ts + ")(__a >= __b);";
1686 break;
1687 case OpLe:
1688 s += "(" + ts + ")(__a <= __b);";
1689 break;
1690 case OpGt:
1691 s += "(" + ts + ")(__a > __b);";
1692 break;
1693 case OpLt:
1694 s += "(" + ts + ")(__a < __b);";
1695 break;
1696 case OpNeg:
1697 s += " -__a;";
1698 break;
1699 case OpNot:
1700 s += " ~__a;";
1701 break;
1702 case OpAnd:
1703 s += "__a & __b;";
1704 break;
1705 case OpOr:
1706 s += "__a | __b;";
1707 break;
1708 case OpXor:
1709 s += "__a ^ __b;";
1710 break;
1711 case OpAndNot:
1712 s += "__a & ~__b;";
1713 break;
1714 case OpOrNot:
1715 s += "__a | ~__b;";
1716 break;
1717 case OpCast:
1718 s += "(" + ts + ")__a;";
1719 break;
1720 case OpConcat:
1721 s += "(" + ts + ")__builtin_shufflevector((int64x1_t)__a";
1722 s += ", (int64x1_t)__b, 0, 1);";
1723 break;
1724 case OpHi:
Jim Grosbachd10f1c02013-05-15 02:40:04 +00001725 // nElts is for the result vector, so the source is twice that number.
1726 s += "__builtin_shufflevector(__a, __a";
1727 for (unsigned i = nElts; i < nElts * 2; ++i)
1728 s += ", " + utostr(i);
1729 s+= ");";
Peter Collingbournebee583f2011-10-06 13:03:08 +00001730 break;
1731 case OpLo:
Jim Grosbachd10f1c02013-05-15 02:40:04 +00001732 s += "__builtin_shufflevector(__a, __a";
1733 for (unsigned i = 0; i < nElts; ++i)
1734 s += ", " + utostr(i);
1735 s+= ");";
Peter Collingbournebee583f2011-10-06 13:03:08 +00001736 break;
1737 case OpDup:
1738 s += Duplicate(nElts, typestr, "__a") + ";";
1739 break;
1740 case OpDupLane:
1741 s += SplatLane(nElts, "__a", "__b") + ";";
1742 break;
1743 case OpSelect:
1744 // ((0 & 1) | (~0 & 2))
1745 s += "(" + ts + ")";
1746 ts = TypeString(proto[1], typestr);
1747 s += "((__a & (" + ts + ")__b) | ";
1748 s += "(~__a & (" + ts + ")__c));";
1749 break;
1750 case OpRev16:
1751 s += "__builtin_shufflevector(__a, __a";
1752 for (unsigned i = 2; i <= nElts; i += 2)
1753 for (unsigned j = 0; j != 2; ++j)
1754 s += ", " + utostr(i - j - 1);
1755 s += ");";
1756 break;
1757 case OpRev32: {
1758 unsigned WordElts = nElts >> (1 + (int)quad);
1759 s += "__builtin_shufflevector(__a, __a";
1760 for (unsigned i = WordElts; i <= nElts; i += WordElts)
1761 for (unsigned j = 0; j != WordElts; ++j)
1762 s += ", " + utostr(i - j - 1);
1763 s += ");";
1764 break;
1765 }
1766 case OpRev64: {
1767 unsigned DblWordElts = nElts >> (int)quad;
1768 s += "__builtin_shufflevector(__a, __a";
1769 for (unsigned i = DblWordElts; i <= nElts; i += DblWordElts)
1770 for (unsigned j = 0; j != DblWordElts; ++j)
1771 s += ", " + utostr(i - j - 1);
1772 s += ");";
1773 break;
1774 }
1775 case OpAbdl: {
1776 std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)";
1777 if (typestr[0] != 'U') {
1778 // vabd results are always unsigned and must be zero-extended.
1779 std::string utype = "U" + typestr.str();
1780 s += "(" + TypeString(proto[0], typestr) + ")";
1781 abd = "(" + TypeString('d', utype) + ")" + abd;
1782 s += Extend(utype, abd) + ";";
1783 } else {
1784 s += Extend(typestr, abd) + ";";
1785 }
1786 break;
1787 }
Jiangning Liu1bda93a2013-09-09 02:21:08 +00001788 case OpAbdlHi:
1789 s += Gen2OpWith2High(typestr, "vabdl", "__a", "__b");
1790 break;
1791 case OpAddhnHi: {
1792 std::string addhn = MangleName("vaddhn", typestr, ClassS) + "(__b, __c)";
1793 s += GenCombine(GetNarrowTypestr(typestr), "__a", addhn);
1794 s += ";";
1795 break;
1796 }
1797 case OpRAddhnHi: {
1798 std::string raddhn = MangleName("vraddhn", typestr, ClassS) + "(__b, __c)";
1799 s += GenCombine(GetNarrowTypestr(typestr), "__a", raddhn);
1800 s += ";";
1801 break;
1802 }
1803 case OpSubhnHi: {
1804 std::string subhn = MangleName("vsubhn", typestr, ClassS) + "(__b, __c)";
1805 s += GenCombine(GetNarrowTypestr(typestr), "__a", subhn);
1806 s += ";";
1807 break;
1808 }
1809 case OpRSubhnHi: {
1810 std::string rsubhn = MangleName("vrsubhn", typestr, ClassS) + "(__b, __c)";
1811 s += GenCombine(GetNarrowTypestr(typestr), "__a", rsubhn);
1812 s += ";";
1813 break;
1814 }
Peter Collingbournebee583f2011-10-06 13:03:08 +00001815 case OpAba:
1816 s += "__a + " + MangleName("vabd", typestr, ClassS) + "(__b, __c);";
1817 break;
Jiangning Liu1bda93a2013-09-09 02:21:08 +00001818 case OpAbal:
1819 s += "__a + " + MangleName("vabdl", typestr, ClassS) + "(__b, __c);";
Peter Collingbournebee583f2011-10-06 13:03:08 +00001820 break;
Jiangning Liu1bda93a2013-09-09 02:21:08 +00001821 case OpAbalHi:
1822 s += Gen3OpWith2High(typestr, "vabal", "__a", "__b", "__c");
1823 break;
1824 case OpQDMullHi:
1825 s += Gen2OpWith2High(typestr, "vqdmull", "__a", "__b");
1826 break;
1827 case OpQDMlalHi:
1828 s += Gen3OpWith2High(typestr, "vqdmlal", "__a", "__b", "__c");
1829 break;
1830 case OpQDMlslHi:
1831 s += Gen3OpWith2High(typestr, "vqdmlsl", "__a", "__b", "__c");
1832 break;
Tim Northover2fe823a2013-08-01 09:23:19 +00001833 case OpDiv:
1834 s += "__a / __b;";
1835 break;
Hao Liub1852ee2013-09-04 09:29:13 +00001836 case OpMovlHi: {
1837 s = TypeString(proto[1], typestr.drop_front()) + " __a1 = " +
1838 MangleName("vget_high", typestr, ClassS) + "(__a);\n " + s;
1839 s += "(" + ts + ")" + MangleName("vshll_n", typestr, ClassS);
1840 s += "(__a1, 0);";
1841 break;
1842 }
1843 case OpLongHi: {
1844 // Another local variable __a1 is needed for calling a Macro,
1845 // or using __a will have naming conflict when Macro expanding.
1846 s += TypeString(proto[1], typestr.drop_front()) + " __a1 = " +
1847 MangleName("vget_high", typestr, ClassS) + "(__a); \\\n";
1848 s += " (" + ts + ")" + MangleName(RemoveHigh(name), typestr, ClassS) +
1849 "(__a1, __b);";
1850 break;
1851 }
1852 case OpNarrowHi: {
1853 s += "(" + ts + ")" + MangleName("vcombine", typestr, ClassS) + "(__a, " +
1854 MangleName(RemoveHigh(name), typestr, ClassS) + "(__b, __c));";
1855 break;
1856 }
Kevin Qinf22bf502013-10-11 02:34:30 +00001857 case OpCopy: {
1858 s += TypeString('s', typestr) + " __c2 = " +
1859 MangleName("vget_lane", typestr, ClassS) + "(__c1, __d1); \\\n " +
1860 MangleName("vset_lane", typestr, ClassS) + "(__c2, __a1, __b1);";
1861 break;
1862 }
Peter Collingbournebee583f2011-10-06 13:03:08 +00001863 default:
Joerg Sonnenberger691a16b2012-10-25 16:37:08 +00001864 PrintFatalError("unknown OpKind!");
Peter Collingbournebee583f2011-10-06 13:03:08 +00001865 }
1866 return s;
1867}
1868
1869static unsigned GetNeonEnum(const std::string &proto, StringRef typestr) {
1870 unsigned mod = proto[0];
Peter Collingbournebee583f2011-10-06 13:03:08 +00001871
1872 if (mod == 'v' || mod == 'f')
1873 mod = proto[1];
1874
1875 bool quad = false;
1876 bool poly = false;
1877 bool usgn = false;
1878 bool scal = false;
1879 bool cnst = false;
1880 bool pntr = false;
1881
1882 // Base type to get the type string for.
1883 char type = ClassifyType(typestr, quad, poly, usgn);
1884
1885 // Based on the modifying character, change the type and width if necessary.
1886 type = ModType(mod, type, quad, poly, usgn, scal, cnst, pntr);
1887
Bob Wilson98bc98c2011-11-08 01:16:11 +00001888 NeonTypeFlags::EltType ET;
Peter Collingbournebee583f2011-10-06 13:03:08 +00001889 switch (type) {
1890 case 'c':
Bob Wilson98bc98c2011-11-08 01:16:11 +00001891 ET = poly ? NeonTypeFlags::Poly8 : NeonTypeFlags::Int8;
Peter Collingbournebee583f2011-10-06 13:03:08 +00001892 break;
1893 case 's':
Bob Wilson98bc98c2011-11-08 01:16:11 +00001894 ET = poly ? NeonTypeFlags::Poly16 : NeonTypeFlags::Int16;
Peter Collingbournebee583f2011-10-06 13:03:08 +00001895 break;
1896 case 'i':
Bob Wilson98bc98c2011-11-08 01:16:11 +00001897 ET = NeonTypeFlags::Int32;
Peter Collingbournebee583f2011-10-06 13:03:08 +00001898 break;
1899 case 'l':
Bob Wilson98bc98c2011-11-08 01:16:11 +00001900 ET = NeonTypeFlags::Int64;
Peter Collingbournebee583f2011-10-06 13:03:08 +00001901 break;
1902 case 'h':
Bob Wilson98bc98c2011-11-08 01:16:11 +00001903 ET = NeonTypeFlags::Float16;
Peter Collingbournebee583f2011-10-06 13:03:08 +00001904 break;
1905 case 'f':
Bob Wilson98bc98c2011-11-08 01:16:11 +00001906 ET = NeonTypeFlags::Float32;
Peter Collingbournebee583f2011-10-06 13:03:08 +00001907 break;
Tim Northover2fe823a2013-08-01 09:23:19 +00001908 case 'd':
1909 ET = NeonTypeFlags::Float64;
1910 break;
Peter Collingbournebee583f2011-10-06 13:03:08 +00001911 default:
Joerg Sonnenberger691a16b2012-10-25 16:37:08 +00001912 PrintFatalError("unhandled type!");
Peter Collingbournebee583f2011-10-06 13:03:08 +00001913 }
Bob Wilson98bc98c2011-11-08 01:16:11 +00001914 NeonTypeFlags Flags(ET, usgn, quad && proto[1] != 'g');
1915 return Flags.getFlags();
Peter Collingbournebee583f2011-10-06 13:03:08 +00001916}
1917
Jiangning Liub96ebac2013-10-05 08:22:55 +00001918static bool ProtoHasScalar(const std::string proto)
1919{
1920 return (proto.find('s') != std::string::npos
1921 || proto.find('r') != std::string::npos);
1922}
1923
Peter Collingbournebee583f2011-10-06 13:03:08 +00001924// Generate the definition for this intrinsic, e.g. __builtin_neon_cls(a)
1925static std::string GenBuiltin(const std::string &name, const std::string &proto,
1926 StringRef typestr, ClassKind ck) {
1927 std::string s;
1928
1929 // If this builtin returns a struct 2, 3, or 4 vectors, pass it as an implicit
1930 // sret-like argument.
1931 bool sret = (proto[0] >= '2' && proto[0] <= '4');
1932
1933 bool define = UseMacro(proto);
1934
1935 // Check if the prototype has a scalar operand with the type of the vector
1936 // elements. If not, bitcasting the args will take care of arg checking.
1937 // The actual signedness etc. will be taken care of with special enums.
Jiangning Liub96ebac2013-10-05 08:22:55 +00001938 if (!ProtoHasScalar(proto))
Peter Collingbournebee583f2011-10-06 13:03:08 +00001939 ck = ClassB;
1940
1941 if (proto[0] != 'v') {
1942 std::string ts = TypeString(proto[0], typestr);
1943
1944 if (define) {
1945 if (sret)
1946 s += ts + " r; ";
1947 else
1948 s += "(" + ts + ")";
1949 } else if (sret) {
1950 s += ts + " r; ";
1951 } else {
1952 s += "return (" + ts + ")";
1953 }
1954 }
1955
1956 bool splat = proto.find('a') != std::string::npos;
1957
1958 s += "__builtin_neon_";
1959 if (splat) {
1960 // Call the non-splat builtin: chop off the "_n" suffix from the name.
1961 std::string vname(name, 0, name.size()-2);
1962 s += MangleName(vname, typestr, ck);
1963 } else {
1964 s += MangleName(name, typestr, ck);
1965 }
1966 s += "(";
1967
1968 // Pass the address of the return variable as the first argument to sret-like
1969 // builtins.
1970 if (sret)
1971 s += "&r, ";
1972
1973 char arg = 'a';
1974 for (unsigned i = 1, e = proto.size(); i != e; ++i, ++arg) {
1975 std::string args = std::string(&arg, 1);
1976
1977 // Use the local temporaries instead of the macro arguments.
1978 args = "__" + args;
1979
1980 bool argQuad = false;
1981 bool argPoly = false;
1982 bool argUsgn = false;
1983 bool argScalar = false;
1984 bool dummy = false;
1985 char argType = ClassifyType(typestr, argQuad, argPoly, argUsgn);
1986 argType = ModType(proto[i], argType, argQuad, argPoly, argUsgn, argScalar,
1987 dummy, dummy);
1988
1989 // Handle multiple-vector values specially, emitting each subvector as an
1990 // argument to the __builtin.
1991 if (proto[i] >= '2' && proto[i] <= '4') {
1992 // Check if an explicit cast is needed.
1993 if (argType != 'c' || argPoly || argUsgn)
1994 args = (argQuad ? "(int8x16_t)" : "(int8x8_t)") + args;
1995
1996 for (unsigned vi = 0, ve = proto[i] - '0'; vi != ve; ++vi) {
1997 s += args + ".val[" + utostr(vi) + "]";
1998 if ((vi + 1) < ve)
1999 s += ", ";
2000 }
2001 if ((i + 1) < e)
2002 s += ", ";
2003
2004 continue;
2005 }
2006
2007 if (splat && (i + 1) == e)
2008 args = Duplicate(GetNumElements(typestr, argQuad), typestr, args);
2009
2010 // Check if an explicit cast is needed.
2011 if ((splat || !argScalar) &&
2012 ((ck == ClassB && argType != 'c') || argPoly || argUsgn)) {
2013 std::string argTypeStr = "c";
2014 if (ck != ClassB)
2015 argTypeStr = argType;
2016 if (argQuad)
2017 argTypeStr = "Q" + argTypeStr;
2018 args = "(" + TypeString('d', argTypeStr) + ")" + args;
2019 }
2020
2021 s += args;
2022 if ((i + 1) < e)
2023 s += ", ";
2024 }
2025
2026 // Extra constant integer to hold type class enum for this function, e.g. s8
2027 if (ck == ClassB)
2028 s += ", " + utostr(GetNeonEnum(proto, typestr));
2029
2030 s += ");";
2031
2032 if (proto[0] != 'v' && sret) {
2033 if (define)
2034 s += " r;";
2035 else
2036 s += " return r;";
2037 }
2038 return s;
2039}
2040
2041static std::string GenBuiltinDef(const std::string &name,
2042 const std::string &proto,
2043 StringRef typestr, ClassKind ck) {
2044 std::string s("BUILTIN(__builtin_neon_");
2045
2046 // If all types are the same size, bitcasting the args will take care
2047 // of arg checking. The actual signedness etc. will be taken care of with
2048 // special enums.
Jiangning Liub96ebac2013-10-05 08:22:55 +00002049 if (!ProtoHasScalar(proto))
Peter Collingbournebee583f2011-10-06 13:03:08 +00002050 ck = ClassB;
2051
2052 s += MangleName(name, typestr, ck);
2053 s += ", \"";
2054
2055 for (unsigned i = 0, e = proto.size(); i != e; ++i)
2056 s += BuiltinTypeString(proto[i], typestr, ck, i == 0);
2057
2058 // Extra constant integer to hold type class enum for this function, e.g. s8
2059 if (ck == ClassB)
2060 s += "i";
2061
2062 s += "\", \"n\")";
2063 return s;
2064}
2065
2066static std::string GenIntrinsic(const std::string &name,
2067 const std::string &proto,
2068 StringRef outTypeStr, StringRef inTypeStr,
2069 OpKind kind, ClassKind classKind) {
2070 assert(!proto.empty() && "");
Jim Grosbach6f855e32012-05-09 18:17:30 +00002071 bool define = UseMacro(proto) && kind != OpUnavailable;
Peter Collingbournebee583f2011-10-06 13:03:08 +00002072 std::string s;
2073
2074 // static always inline + return type
2075 if (define)
2076 s += "#define ";
2077 else
2078 s += "__ai " + TypeString(proto[0], outTypeStr) + " ";
2079
2080 // Function name with type suffix
2081 std::string mangledName = MangleName(name, outTypeStr, ClassS);
2082 if (outTypeStr != inTypeStr) {
2083 // If the input type is different (e.g., for vreinterpret), append a suffix
2084 // for the input type. String off a "Q" (quad) prefix so that MangleName
2085 // does not insert another "q" in the name.
2086 unsigned typeStrOff = (inTypeStr[0] == 'Q' ? 1 : 0);
2087 StringRef inTypeNoQuad = inTypeStr.substr(typeStrOff);
2088 mangledName = MangleName(mangledName, inTypeNoQuad, ClassS);
2089 }
2090 s += mangledName;
2091
2092 // Function arguments
Kevin Qinf22bf502013-10-11 02:34:30 +00002093 s += GenArgs(proto, inTypeStr, name);
Peter Collingbournebee583f2011-10-06 13:03:08 +00002094
2095 // Definition.
2096 if (define) {
2097 s += " __extension__ ({ \\\n ";
Kevin Qinf22bf502013-10-11 02:34:30 +00002098 s += GenMacroLocals(proto, inTypeStr, name);
Jim Grosbach6f855e32012-05-09 18:17:30 +00002099 } else if (kind == OpUnavailable) {
2100 s += " __attribute__((unavailable));\n";
2101 return s;
2102 } else
Jim Grosbachcc6b1812012-08-03 17:30:46 +00002103 s += " {\n ";
Peter Collingbournebee583f2011-10-06 13:03:08 +00002104
2105 if (kind != OpNone)
Hao Liub1852ee2013-09-04 09:29:13 +00002106 s += GenOpString(name, kind, proto, outTypeStr);
Peter Collingbournebee583f2011-10-06 13:03:08 +00002107 else
2108 s += GenBuiltin(name, proto, outTypeStr, classKind);
2109 if (define)
2110 s += " })";
2111 else
2112 s += " }";
2113 s += "\n";
2114 return s;
2115}
2116
2117/// run - Read the records in arm_neon.td and output arm_neon.h. arm_neon.h
2118/// is comprised of type definitions and function declarations.
2119void NeonEmitter::run(raw_ostream &OS) {
2120 OS <<
2121 "/*===---- arm_neon.h - ARM Neon intrinsics ------------------------------"
2122 "---===\n"
2123 " *\n"
2124 " * Permission is hereby granted, free of charge, to any person obtaining "
2125 "a copy\n"
2126 " * of this software and associated documentation files (the \"Software\"),"
2127 " to deal\n"
2128 " * in the Software without restriction, including without limitation the "
2129 "rights\n"
2130 " * to use, copy, modify, merge, publish, distribute, sublicense, "
2131 "and/or sell\n"
2132 " * copies of the Software, and to permit persons to whom the Software is\n"
2133 " * furnished to do so, subject to the following conditions:\n"
2134 " *\n"
2135 " * The above copyright notice and this permission notice shall be "
2136 "included in\n"
2137 " * all copies or substantial portions of the Software.\n"
2138 " *\n"
2139 " * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, "
2140 "EXPRESS OR\n"
2141 " * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF "
2142 "MERCHANTABILITY,\n"
2143 " * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT "
2144 "SHALL THE\n"
2145 " * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR "
2146 "OTHER\n"
2147 " * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, "
2148 "ARISING FROM,\n"
2149 " * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER "
2150 "DEALINGS IN\n"
2151 " * THE SOFTWARE.\n"
2152 " *\n"
2153 " *===--------------------------------------------------------------------"
2154 "---===\n"
2155 " */\n\n";
2156
2157 OS << "#ifndef __ARM_NEON_H\n";
2158 OS << "#define __ARM_NEON_H\n\n";
2159
Tim Northover2fe823a2013-08-01 09:23:19 +00002160 OS << "#if !defined(__ARM_NEON__) && !defined(__AARCH_FEATURE_ADVSIMD)\n";
Peter Collingbournebee583f2011-10-06 13:03:08 +00002161 OS << "#error \"NEON support not enabled\"\n";
2162 OS << "#endif\n\n";
2163
2164 OS << "#include <stdint.h>\n\n";
2165
2166 // Emit NEON-specific scalar typedefs.
2167 OS << "typedef float float32_t;\n";
Tim Northover2fe823a2013-08-01 09:23:19 +00002168 OS << "typedef __fp16 float16_t;\n";
2169
2170 OS << "#ifdef __aarch64__\n";
2171 OS << "typedef double float64_t;\n";
2172 OS << "#endif\n\n";
2173
2174 // For now, signedness of polynomial types depends on target
2175 OS << "#ifdef __aarch64__\n";
2176 OS << "typedef uint8_t poly8_t;\n";
2177 OS << "typedef uint16_t poly16_t;\n";
2178 OS << "#else\n";
Peter Collingbournebee583f2011-10-06 13:03:08 +00002179 OS << "typedef int8_t poly8_t;\n";
2180 OS << "typedef int16_t poly16_t;\n";
Tim Northover2fe823a2013-08-01 09:23:19 +00002181 OS << "#endif\n";
Peter Collingbournebee583f2011-10-06 13:03:08 +00002182
2183 // Emit Neon vector typedefs.
Tim Northover2fe823a2013-08-01 09:23:19 +00002184 std::string TypedefTypes(
Jiangning Liu4617e9d2013-10-04 09:21:17 +00002185 "cQcsQsiQilQlUcQUcUsQUsUiQUiUlQUlhQhfQfdQdPcQPcPsQPs");
Peter Collingbournebee583f2011-10-06 13:03:08 +00002186 SmallVector<StringRef, 24> TDTypeVec;
2187 ParseTypes(0, TypedefTypes, TDTypeVec);
2188
2189 // Emit vector typedefs.
Jiangning Liu4617e9d2013-10-04 09:21:17 +00002190 bool isA64 = false;
Peter Collingbournebee583f2011-10-06 13:03:08 +00002191 for (unsigned i = 0, e = TDTypeVec.size(); i != e; ++i) {
2192 bool dummy, quad = false, poly = false;
Tim Northover2fe823a2013-08-01 09:23:19 +00002193 char type = ClassifyType(TDTypeVec[i], quad, poly, dummy);
Jiangning Liu4617e9d2013-10-04 09:21:17 +00002194 bool preinsert = false;
2195 bool postinsert = false;
Tim Northover2fe823a2013-08-01 09:23:19 +00002196
Jiangning Liu4617e9d2013-10-04 09:21:17 +00002197 if (type == 'd') {
2198 preinsert = isA64? false: true;
Tim Northover2fe823a2013-08-01 09:23:19 +00002199 isA64 = true;
Jiangning Liu4617e9d2013-10-04 09:21:17 +00002200 } else {
2201 postinsert = isA64? true: false;
2202 isA64 = false;
2203 }
2204 if (postinsert)
2205 OS << "#endif\n";
2206 if (preinsert)
Tim Northover2fe823a2013-08-01 09:23:19 +00002207 OS << "#ifdef __aarch64__\n";
2208
Peter Collingbournebee583f2011-10-06 13:03:08 +00002209 if (poly)
2210 OS << "typedef __attribute__((neon_polyvector_type(";
2211 else
2212 OS << "typedef __attribute__((neon_vector_type(";
2213
2214 unsigned nElts = GetNumElements(TDTypeVec[i], quad);
2215 OS << utostr(nElts) << "))) ";
2216 if (nElts < 10)
2217 OS << " ";
2218
2219 OS << TypeString('s', TDTypeVec[i]);
2220 OS << " " << TypeString('d', TDTypeVec[i]) << ";\n";
Tim Northover2fe823a2013-08-01 09:23:19 +00002221
Peter Collingbournebee583f2011-10-06 13:03:08 +00002222 }
2223 OS << "\n";
2224
2225 // Emit struct typedefs.
Jiangning Liu4617e9d2013-10-04 09:21:17 +00002226 isA64 = false;
Peter Collingbournebee583f2011-10-06 13:03:08 +00002227 for (unsigned vi = 2; vi != 5; ++vi) {
2228 for (unsigned i = 0, e = TDTypeVec.size(); i != e; ++i) {
Tim Northover2fe823a2013-08-01 09:23:19 +00002229 bool dummy, quad = false, poly = false;
2230 char type = ClassifyType(TDTypeVec[i], quad, poly, dummy);
Jiangning Liu4617e9d2013-10-04 09:21:17 +00002231 bool preinsert = false;
2232 bool postinsert = false;
Tim Northover2fe823a2013-08-01 09:23:19 +00002233
Jiangning Liu4617e9d2013-10-04 09:21:17 +00002234 if (type == 'd') {
2235 preinsert = isA64? false: true;
Tim Northover2fe823a2013-08-01 09:23:19 +00002236 isA64 = true;
Jiangning Liu4617e9d2013-10-04 09:21:17 +00002237 } else {
2238 postinsert = isA64? true: false;
2239 isA64 = false;
2240 }
2241 if (postinsert)
2242 OS << "#endif\n";
2243 if (preinsert)
Tim Northover2fe823a2013-08-01 09:23:19 +00002244 OS << "#ifdef __aarch64__\n";
2245
Peter Collingbournebee583f2011-10-06 13:03:08 +00002246 std::string ts = TypeString('d', TDTypeVec[i]);
2247 std::string vs = TypeString('0' + vi, TDTypeVec[i]);
2248 OS << "typedef struct " << vs << " {\n";
2249 OS << " " << ts << " val";
2250 OS << "[" << utostr(vi) << "]";
2251 OS << ";\n} ";
Tim Northover2fe823a2013-08-01 09:23:19 +00002252 OS << vs << ";\n";
Tim Northover2fe823a2013-08-01 09:23:19 +00002253 OS << "\n";
Peter Collingbournebee583f2011-10-06 13:03:08 +00002254 }
2255 }
2256
Bob Wilson2b593952013-04-12 20:17:20 +00002257 OS<<"#define __ai static inline __attribute__((__always_inline__, __nodebug__))\n\n";
Peter Collingbournebee583f2011-10-06 13:03:08 +00002258
2259 std::vector<Record*> RV = Records.getAllDerivedDefinitions("Inst");
2260
Tim Northover2fe823a2013-08-01 09:23:19 +00002261 StringMap<ClassKind> EmittedMap;
2262
Peter Collingbournebee583f2011-10-06 13:03:08 +00002263 // Emit vmovl, vmull and vabd intrinsics first so they can be used by other
2264 // intrinsics. (Some of the saturating multiply instructions are also
2265 // used to implement the corresponding "_lane" variants, but tablegen
2266 // sorts the records into alphabetical order so that the "_lane" variants
2267 // come after the intrinsics they use.)
Tim Northover2fe823a2013-08-01 09:23:19 +00002268 emitIntrinsic(OS, Records.getDef("VMOVL"), EmittedMap);
2269 emitIntrinsic(OS, Records.getDef("VMULL"), EmittedMap);
2270 emitIntrinsic(OS, Records.getDef("VABD"), EmittedMap);
Jiangning Liu1bda93a2013-09-09 02:21:08 +00002271 emitIntrinsic(OS, Records.getDef("VABDL"), EmittedMap);
Tim Northover2fe823a2013-08-01 09:23:19 +00002272
2273 // ARM intrinsics must be emitted before AArch64 intrinsics to ensure
2274 // common intrinsics appear only once in the output stream.
2275 // The check for uniquiness is done in emitIntrinsic.
2276 // Emit ARM intrinsics.
2277 for (unsigned i = 0, e = RV.size(); i != e; ++i) {
2278 Record *R = RV[i];
2279
2280 // Skip AArch64 intrinsics; they will be emitted at the end.
2281 bool isA64 = R->getValueAsBit("isA64");
2282 if (isA64)
2283 continue;
2284
2285 if (R->getName() != "VMOVL" && R->getName() != "VMULL" &&
2286 R->getName() != "VABD")
2287 emitIntrinsic(OS, R, EmittedMap);
2288 }
2289
2290 // Emit AArch64-specific intrinsics.
2291 OS << "#ifdef __aarch64__\n";
Peter Collingbournebee583f2011-10-06 13:03:08 +00002292
Jiangning Liu1bda93a2013-09-09 02:21:08 +00002293 emitIntrinsic(OS, Records.getDef("VMOVL_HIGH"), EmittedMap);
2294 emitIntrinsic(OS, Records.getDef("VMULL_HIGH"), EmittedMap);
2295 emitIntrinsic(OS, Records.getDef("VABDL_HIGH"), EmittedMap);
2296
Peter Collingbournebee583f2011-10-06 13:03:08 +00002297 for (unsigned i = 0, e = RV.size(); i != e; ++i) {
2298 Record *R = RV[i];
Tim Northover2fe823a2013-08-01 09:23:19 +00002299
2300 // Skip ARM intrinsics already included above.
2301 bool isA64 = R->getValueAsBit("isA64");
2302 if (!isA64)
2303 continue;
2304
2305 emitIntrinsic(OS, R, EmittedMap);
Peter Collingbournebee583f2011-10-06 13:03:08 +00002306 }
2307
Tim Northover2fe823a2013-08-01 09:23:19 +00002308 OS << "#endif\n\n";
2309
Peter Collingbournebee583f2011-10-06 13:03:08 +00002310 OS << "#undef __ai\n\n";
2311 OS << "#endif /* __ARM_NEON_H */\n";
2312}
2313
2314/// emitIntrinsic - Write out the arm_neon.h header file definitions for the
Tim Northover2fe823a2013-08-01 09:23:19 +00002315/// intrinsics specified by record R checking for intrinsic uniqueness.
2316void NeonEmitter::emitIntrinsic(raw_ostream &OS, Record *R,
2317 StringMap<ClassKind> &EmittedMap) {
Peter Collingbournebee583f2011-10-06 13:03:08 +00002318 std::string name = R->getValueAsString("Name");
2319 std::string Proto = R->getValueAsString("Prototype");
2320 std::string Types = R->getValueAsString("Types");
2321
2322 SmallVector<StringRef, 16> TypeVec;
2323 ParseTypes(R, Types, TypeVec);
2324
2325 OpKind kind = OpMap[R->getValueAsDef("Operand")->getName()];
2326
2327 ClassKind classKind = ClassNone;
2328 if (R->getSuperClasses().size() >= 2)
2329 classKind = ClassMap[R->getSuperClasses()[1]];
2330 if (classKind == ClassNone && kind == OpNone)
Joerg Sonnenberger691a16b2012-10-25 16:37:08 +00002331 PrintFatalError(R->getLoc(), "Builtin has no class kind");
Peter Collingbournebee583f2011-10-06 13:03:08 +00002332
2333 for (unsigned ti = 0, te = TypeVec.size(); ti != te; ++ti) {
2334 if (kind == OpReinterpret) {
2335 bool outQuad = false;
2336 bool dummy = false;
2337 (void)ClassifyType(TypeVec[ti], outQuad, dummy, dummy);
2338 for (unsigned srcti = 0, srcte = TypeVec.size();
2339 srcti != srcte; ++srcti) {
2340 bool inQuad = false;
2341 (void)ClassifyType(TypeVec[srcti], inQuad, dummy, dummy);
2342 if (srcti == ti || inQuad != outQuad)
2343 continue;
Tim Northover2fe823a2013-08-01 09:23:19 +00002344 std::string s = GenIntrinsic(name, Proto, TypeVec[ti], TypeVec[srcti],
2345 OpCast, ClassS);
2346 if (EmittedMap.count(s))
2347 continue;
2348 EmittedMap[s] = ClassS;
2349 OS << s;
Peter Collingbournebee583f2011-10-06 13:03:08 +00002350 }
2351 } else {
Tim Northover2fe823a2013-08-01 09:23:19 +00002352 std::string s =
2353 GenIntrinsic(name, Proto, TypeVec[ti], TypeVec[ti], kind, classKind);
2354 if (EmittedMap.count(s))
2355 continue;
2356 EmittedMap[s] = classKind;
2357 OS << s;
Peter Collingbournebee583f2011-10-06 13:03:08 +00002358 }
2359 }
2360 OS << "\n";
2361}
2362
2363static unsigned RangeFromType(const char mod, StringRef typestr) {
2364 // base type to get the type string for.
2365 bool quad = false, dummy = false;
2366 char type = ClassifyType(typestr, quad, dummy, dummy);
2367 type = ModType(mod, type, quad, dummy, dummy, dummy, dummy, dummy);
2368
2369 switch (type) {
2370 case 'c':
2371 return (8 << (int)quad) - 1;
2372 case 'h':
2373 case 's':
2374 return (4 << (int)quad) - 1;
2375 case 'f':
2376 case 'i':
2377 return (2 << (int)quad) - 1;
Jiangning Liu4617e9d2013-10-04 09:21:17 +00002378 case 'd':
Peter Collingbournebee583f2011-10-06 13:03:08 +00002379 case 'l':
2380 return (1 << (int)quad) - 1;
2381 default:
Joerg Sonnenberger691a16b2012-10-25 16:37:08 +00002382 PrintFatalError("unhandled type!");
Peter Collingbournebee583f2011-10-06 13:03:08 +00002383 }
Peter Collingbournebee583f2011-10-06 13:03:08 +00002384}
2385
Chad Rosierbdca3872013-10-31 19:29:05 +00002386static unsigned RangeScalarShiftImm(const char mod, StringRef typestr) {
2387 // base type to get the type string for.
2388 bool dummy = false;
2389 char type = ClassifyType(typestr, dummy, dummy, dummy);
2390 type = ModType(mod, type, dummy, dummy, dummy, dummy, dummy, dummy);
2391
2392 switch (type) {
2393 case 'c':
2394 return 7;
2395 case 'h':
2396 case 's':
2397 return 15;
2398 case 'f':
2399 case 'i':
2400 return 31;
2401 case 'd':
2402 case 'l':
2403 return 63;
2404 default:
2405 PrintFatalError("unhandled type!");
2406 }
2407}
2408
Tim Northover2fe823a2013-08-01 09:23:19 +00002409/// Generate the ARM and AArch64 intrinsic range checking code for
2410/// shift/lane immediates, checking for unique declarations.
2411void
2412NeonEmitter::genIntrinsicRangeCheckCode(raw_ostream &OS,
2413 StringMap<ClassKind> &A64IntrinsicMap,
2414 bool isA64RangeCheck) {
2415 std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst");
Peter Collingbournebee583f2011-10-06 13:03:08 +00002416 StringMap<OpKind> EmittedMap;
2417
Tim Northover2fe823a2013-08-01 09:23:19 +00002418 // Generate the intrinsic range checking code for shift/lane immediates.
2419 if (isA64RangeCheck)
2420 OS << "#ifdef GET_NEON_AARCH64_IMMEDIATE_CHECK\n";
2421 else
2422 OS << "#ifdef GET_NEON_IMMEDIATE_CHECK\n";
2423
Peter Collingbournebee583f2011-10-06 13:03:08 +00002424 for (unsigned i = 0, e = RV.size(); i != e; ++i) {
2425 Record *R = RV[i];
Tim Northover2fe823a2013-08-01 09:23:19 +00002426
Peter Collingbournebee583f2011-10-06 13:03:08 +00002427 OpKind k = OpMap[R->getValueAsDef("Operand")->getName()];
2428 if (k != OpNone)
2429 continue;
2430
Tim Northover2fe823a2013-08-01 09:23:19 +00002431 std::string name = R->getValueAsString("Name");
Peter Collingbournebee583f2011-10-06 13:03:08 +00002432 std::string Proto = R->getValueAsString("Prototype");
Tim Northover2fe823a2013-08-01 09:23:19 +00002433 std::string Types = R->getValueAsString("Types");
Kevin Qinc076d062013-08-29 07:55:15 +00002434 std::string Rename = name + "@" + Proto;
Peter Collingbournebee583f2011-10-06 13:03:08 +00002435
2436 // Functions with 'a' (the splat code) in the type prototype should not get
2437 // their own builtin as they use the non-splat variant.
2438 if (Proto.find('a') != std::string::npos)
2439 continue;
2440
Tim Northover2fe823a2013-08-01 09:23:19 +00002441 // Functions which do not have an immediate do not need to have range
2442 // checking code emitted.
2443 size_t immPos = Proto.find('i');
2444 if (immPos == std::string::npos)
2445 continue;
2446
Peter Collingbournebee583f2011-10-06 13:03:08 +00002447 SmallVector<StringRef, 16> TypeVec;
2448 ParseTypes(R, Types, TypeVec);
2449
2450 if (R->getSuperClasses().size() < 2)
Joerg Sonnenberger691a16b2012-10-25 16:37:08 +00002451 PrintFatalError(R->getLoc(), "Builtin has no class kind");
Peter Collingbournebee583f2011-10-06 13:03:08 +00002452
Peter Collingbournebee583f2011-10-06 13:03:08 +00002453 ClassKind ck = ClassMap[R->getSuperClasses()[1]];
2454
Tim Northover2fe823a2013-08-01 09:23:19 +00002455 // Do not include AArch64 range checks if not generating code for AArch64.
2456 bool isA64 = R->getValueAsBit("isA64");
2457 if (!isA64RangeCheck && isA64)
2458 continue;
Peter Collingbournebee583f2011-10-06 13:03:08 +00002459
Tim Northover2fe823a2013-08-01 09:23:19 +00002460 // Include ARM range checks in AArch64 but only if ARM intrinsics are not
2461 // redefined by AArch64 to handle new types.
Kevin Qinc076d062013-08-29 07:55:15 +00002462 if (isA64RangeCheck && !isA64 && A64IntrinsicMap.count(Rename)) {
2463 ClassKind &A64CK = A64IntrinsicMap[Rename];
Tim Northover2fe823a2013-08-01 09:23:19 +00002464 if (A64CK == ck && ck != ClassNone)
2465 continue;
2466 }
2467
2468 for (unsigned ti = 0, te = TypeVec.size(); ti != te; ++ti) {
2469 std::string namestr, shiftstr, rangestr;
2470
2471 if (R->getValueAsBit("isVCVT_N")) {
2472 // VCVT between floating- and fixed-point values takes an immediate
Hao Liub1852ee2013-09-04 09:29:13 +00002473 // in the range [1, 32] for f32, or [1, 64] for f64.
Tim Northover2fe823a2013-08-01 09:23:19 +00002474 ck = ClassB;
Hao Liub1852ee2013-09-04 09:29:13 +00002475 if (name.find("32") != std::string::npos)
2476 rangestr = "l = 1; u = 31"; // upper bound = l + u
2477 else if (name.find("64") != std::string::npos)
2478 rangestr = "l = 1; u = 63";
2479 else
2480 PrintFatalError(R->getLoc(),
2481 "Fixed point convert name should contains \"32\" or \"64\"");
Chad Rosierbdca3872013-10-31 19:29:05 +00002482
2483 } else if (R->getValueAsBit("isScalarShift")) {
2484 // Right shifts have an 'r' in the name, left shifts do not.
2485 if (name.find('r') != std::string::npos)
2486 rangestr = "l = 1; ";
2487
2488 rangestr += "u = " +
2489 utostr(RangeScalarShiftImm(Proto[immPos - 1], TypeVec[ti]));
Jiangning Liub96ebac2013-10-05 08:22:55 +00002490 } else if (!ProtoHasScalar(Proto)) {
Tim Northover2fe823a2013-08-01 09:23:19 +00002491 // Builtins which are overloaded by type will need to have their upper
2492 // bound computed at Sema time based on the type constant.
2493 ck = ClassB;
2494 if (R->getValueAsBit("isShift")) {
2495 shiftstr = ", true";
2496
2497 // Right shifts have an 'r' in the name, left shifts do not.
2498 if (name.find('r') != std::string::npos)
2499 rangestr = "l = 1; ";
2500 }
2501 rangestr += "u = RFT(TV" + shiftstr + ")";
2502 } else {
2503 // The immediate generally refers to a lane in the preceding argument.
2504 assert(immPos > 0 && "unexpected immediate operand");
2505 rangestr =
2506 "u = " + utostr(RangeFromType(Proto[immPos - 1], TypeVec[ti]));
2507 }
2508 // Make sure cases appear only once by uniquing them in a string map.
2509 namestr = MangleName(name, TypeVec[ti], ck);
2510 if (EmittedMap.count(namestr))
2511 continue;
2512 EmittedMap[namestr] = OpNone;
2513
2514 // Calculate the index of the immediate that should be range checked.
2515 unsigned immidx = 0;
2516
2517 // Builtins that return a struct of multiple vectors have an extra
2518 // leading arg for the struct return.
2519 if (Proto[0] >= '2' && Proto[0] <= '4')
2520 ++immidx;
2521
2522 // Add one to the index for each argument until we reach the immediate
2523 // to be checked. Structs of vectors are passed as multiple arguments.
2524 for (unsigned ii = 1, ie = Proto.size(); ii != ie; ++ii) {
2525 switch (Proto[ii]) {
2526 default:
2527 immidx += 1;
2528 break;
2529 case '2':
2530 immidx += 2;
2531 break;
2532 case '3':
2533 immidx += 3;
2534 break;
2535 case '4':
2536 immidx += 4;
2537 break;
2538 case 'i':
2539 ie = ii + 1;
2540 break;
2541 }
2542 }
2543 if (isA64RangeCheck)
2544 OS << "case AArch64::BI__builtin_neon_";
2545 else
2546 OS << "case ARM::BI__builtin_neon_";
2547 OS << MangleName(name, TypeVec[ti], ck) << ": i = " << immidx << "; "
2548 << rangestr << "; break;\n";
Peter Collingbournebee583f2011-10-06 13:03:08 +00002549 }
2550 }
2551 OS << "#endif\n\n";
Tim Northover2fe823a2013-08-01 09:23:19 +00002552}
2553
2554/// Generate the ARM and AArch64 overloaded type checking code for
2555/// SemaChecking.cpp, checking for unique builtin declarations.
2556void
2557NeonEmitter::genOverloadTypeCheckCode(raw_ostream &OS,
2558 StringMap<ClassKind> &A64IntrinsicMap,
2559 bool isA64TypeCheck) {
2560 std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst");
2561 StringMap<OpKind> EmittedMap;
Peter Collingbournebee583f2011-10-06 13:03:08 +00002562
2563 // Generate the overloaded type checking code for SemaChecking.cpp
Tim Northover2fe823a2013-08-01 09:23:19 +00002564 if (isA64TypeCheck)
2565 OS << "#ifdef GET_NEON_AARCH64_OVERLOAD_CHECK\n";
2566 else
2567 OS << "#ifdef GET_NEON_OVERLOAD_CHECK\n";
2568
Peter Collingbournebee583f2011-10-06 13:03:08 +00002569 for (unsigned i = 0, e = RV.size(); i != e; ++i) {
2570 Record *R = RV[i];
2571 OpKind k = OpMap[R->getValueAsDef("Operand")->getName()];
2572 if (k != OpNone)
2573 continue;
2574
2575 std::string Proto = R->getValueAsString("Prototype");
2576 std::string Types = R->getValueAsString("Types");
2577 std::string name = R->getValueAsString("Name");
Kevin Qinc076d062013-08-29 07:55:15 +00002578 std::string Rename = name + "@" + Proto;
2579
Peter Collingbournebee583f2011-10-06 13:03:08 +00002580 // Functions with 'a' (the splat code) in the type prototype should not get
2581 // their own builtin as they use the non-splat variant.
2582 if (Proto.find('a') != std::string::npos)
2583 continue;
2584
2585 // Functions which have a scalar argument cannot be overloaded, no need to
2586 // check them if we are emitting the type checking code.
Jiangning Liub96ebac2013-10-05 08:22:55 +00002587 if (ProtoHasScalar(Proto))
Peter Collingbournebee583f2011-10-06 13:03:08 +00002588 continue;
2589
2590 SmallVector<StringRef, 16> TypeVec;
2591 ParseTypes(R, Types, TypeVec);
2592
2593 if (R->getSuperClasses().size() < 2)
Joerg Sonnenberger691a16b2012-10-25 16:37:08 +00002594 PrintFatalError(R->getLoc(), "Builtin has no class kind");
Peter Collingbournebee583f2011-10-06 13:03:08 +00002595
Tim Northover2fe823a2013-08-01 09:23:19 +00002596 // Do not include AArch64 type checks if not generating code for AArch64.
2597 bool isA64 = R->getValueAsBit("isA64");
2598 if (!isA64TypeCheck && isA64)
2599 continue;
2600
2601 // Include ARM type check in AArch64 but only if ARM intrinsics
2602 // are not redefined in AArch64 to handle new types, e.g. "vabd" is a SIntr
2603 // redefined in AArch64 to handle an additional 2 x f64 type.
2604 ClassKind ck = ClassMap[R->getSuperClasses()[1]];
Kevin Qinc076d062013-08-29 07:55:15 +00002605 if (isA64TypeCheck && !isA64 && A64IntrinsicMap.count(Rename)) {
2606 ClassKind &A64CK = A64IntrinsicMap[Rename];
Tim Northover2fe823a2013-08-01 09:23:19 +00002607 if (A64CK == ck && ck != ClassNone)
2608 continue;
2609 }
2610
Peter Collingbournebee583f2011-10-06 13:03:08 +00002611 int si = -1, qi = -1;
Richard Smith7d6d47b2012-08-14 01:28:02 +00002612 uint64_t mask = 0, qmask = 0;
Peter Collingbournebee583f2011-10-06 13:03:08 +00002613 for (unsigned ti = 0, te = TypeVec.size(); ti != te; ++ti) {
2614 // Generate the switch case(s) for this builtin for the type validation.
2615 bool quad = false, poly = false, usgn = false;
2616 (void) ClassifyType(TypeVec[ti], quad, poly, usgn);
2617
2618 if (quad) {
2619 qi = ti;
Richard Smith7d6d47b2012-08-14 01:28:02 +00002620 qmask |= 1ULL << GetNeonEnum(Proto, TypeVec[ti]);
Peter Collingbournebee583f2011-10-06 13:03:08 +00002621 } else {
2622 si = ti;
Richard Smith7d6d47b2012-08-14 01:28:02 +00002623 mask |= 1ULL << GetNeonEnum(Proto, TypeVec[ti]);
Peter Collingbournebee583f2011-10-06 13:03:08 +00002624 }
2625 }
Bob Wilson89d14242011-11-16 21:32:23 +00002626
2627 // Check if the builtin function has a pointer or const pointer argument.
2628 int PtrArgNum = -1;
2629 bool HasConstPtr = false;
2630 for (unsigned arg = 1, arge = Proto.size(); arg != arge; ++arg) {
2631 char ArgType = Proto[arg];
2632 if (ArgType == 'c') {
2633 HasConstPtr = true;
2634 PtrArgNum = arg - 1;
2635 break;
2636 }
2637 if (ArgType == 'p') {
2638 PtrArgNum = arg - 1;
2639 break;
2640 }
2641 }
2642 // For sret builtins, adjust the pointer argument index.
2643 if (PtrArgNum >= 0 && (Proto[0] >= '2' && Proto[0] <= '4'))
2644 PtrArgNum += 1;
2645
Bob Wilsonbd646de2011-12-20 06:16:48 +00002646 // Omit type checking for the pointer arguments of vld1_lane, vld1_dup,
2647 // and vst1_lane intrinsics. Using a pointer to the vector element
2648 // type with one of those operations causes codegen to select an aligned
2649 // load/store instruction. If you want an unaligned operation,
2650 // the pointer argument needs to have less alignment than element type,
2651 // so just accept any pointer type.
2652 if (name == "vld1_lane" || name == "vld1_dup" || name == "vst1_lane") {
2653 PtrArgNum = -1;
2654 HasConstPtr = false;
2655 }
2656
Bob Wilsone4d77232011-11-08 05:04:11 +00002657 if (mask) {
Tim Northover2fe823a2013-08-01 09:23:19 +00002658 if (isA64TypeCheck)
2659 OS << "case AArch64::BI__builtin_neon_";
2660 else
2661 OS << "case ARM::BI__builtin_neon_";
2662 OS << MangleName(name, TypeVec[si], ClassB) << ": mask = "
2663 << "0x" << utohexstr(mask) << "ULL";
Bob Wilson89d14242011-11-16 21:32:23 +00002664 if (PtrArgNum >= 0)
2665 OS << "; PtrArgNum = " << PtrArgNum;
Bob Wilsone4d77232011-11-08 05:04:11 +00002666 if (HasConstPtr)
2667 OS << "; HasConstPtr = true";
2668 OS << "; break;\n";
2669 }
2670 if (qmask) {
Tim Northover2fe823a2013-08-01 09:23:19 +00002671 if (isA64TypeCheck)
2672 OS << "case AArch64::BI__builtin_neon_";
2673 else
2674 OS << "case ARM::BI__builtin_neon_";
2675 OS << MangleName(name, TypeVec[qi], ClassB) << ": mask = "
2676 << "0x" << utohexstr(qmask) << "ULL";
Bob Wilson89d14242011-11-16 21:32:23 +00002677 if (PtrArgNum >= 0)
2678 OS << "; PtrArgNum = " << PtrArgNum;
Bob Wilsone4d77232011-11-08 05:04:11 +00002679 if (HasConstPtr)
2680 OS << "; HasConstPtr = true";
2681 OS << "; break;\n";
2682 }
Peter Collingbournebee583f2011-10-06 13:03:08 +00002683 }
2684 OS << "#endif\n\n";
Tim Northover2fe823a2013-08-01 09:23:19 +00002685}
Peter Collingbournebee583f2011-10-06 13:03:08 +00002686
Tim Northover2fe823a2013-08-01 09:23:19 +00002687/// genBuiltinsDef: Generate the BuiltinsARM.def and BuiltinsAArch64.def
2688/// declaration of builtins, checking for unique builtin declarations.
2689void NeonEmitter::genBuiltinsDef(raw_ostream &OS,
2690 StringMap<ClassKind> &A64IntrinsicMap,
2691 bool isA64GenBuiltinDef) {
2692 std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst");
2693 StringMap<OpKind> EmittedMap;
2694
2695 // Generate BuiltinsARM.def and BuiltinsAArch64.def
2696 if (isA64GenBuiltinDef)
2697 OS << "#ifdef GET_NEON_AARCH64_BUILTINS\n";
2698 else
2699 OS << "#ifdef GET_NEON_BUILTINS\n";
2700
Peter Collingbournebee583f2011-10-06 13:03:08 +00002701 for (unsigned i = 0, e = RV.size(); i != e; ++i) {
2702 Record *R = RV[i];
Peter Collingbournebee583f2011-10-06 13:03:08 +00002703 OpKind k = OpMap[R->getValueAsDef("Operand")->getName()];
2704 if (k != OpNone)
2705 continue;
2706
Peter Collingbournebee583f2011-10-06 13:03:08 +00002707 std::string Proto = R->getValueAsString("Prototype");
Tim Northover2fe823a2013-08-01 09:23:19 +00002708 std::string name = R->getValueAsString("Name");
Kevin Qinc076d062013-08-29 07:55:15 +00002709 std::string Rename = name + "@" + Proto;
Peter Collingbournebee583f2011-10-06 13:03:08 +00002710
2711 // Functions with 'a' (the splat code) in the type prototype should not get
2712 // their own builtin as they use the non-splat variant.
2713 if (Proto.find('a') != std::string::npos)
2714 continue;
2715
Tim Northover2fe823a2013-08-01 09:23:19 +00002716 std::string Types = R->getValueAsString("Types");
Peter Collingbournebee583f2011-10-06 13:03:08 +00002717 SmallVector<StringRef, 16> TypeVec;
2718 ParseTypes(R, Types, TypeVec);
2719
2720 if (R->getSuperClasses().size() < 2)
Joerg Sonnenberger691a16b2012-10-25 16:37:08 +00002721 PrintFatalError(R->getLoc(), "Builtin has no class kind");
Peter Collingbournebee583f2011-10-06 13:03:08 +00002722
2723 ClassKind ck = ClassMap[R->getSuperClasses()[1]];
2724
Tim Northover2fe823a2013-08-01 09:23:19 +00002725 // Do not include AArch64 BUILTIN() macros if not generating
2726 // code for AArch64
2727 bool isA64 = R->getValueAsBit("isA64");
2728 if (!isA64GenBuiltinDef && isA64)
2729 continue;
Peter Collingbournebee583f2011-10-06 13:03:08 +00002730
Tim Northover2fe823a2013-08-01 09:23:19 +00002731 // Include ARM BUILTIN() macros in AArch64 but only if ARM intrinsics
2732 // are not redefined in AArch64 to handle new types, e.g. "vabd" is a SIntr
2733 // redefined in AArch64 to handle an additional 2 x f64 type.
Kevin Qinc076d062013-08-29 07:55:15 +00002734 if (isA64GenBuiltinDef && !isA64 && A64IntrinsicMap.count(Rename)) {
2735 ClassKind &A64CK = A64IntrinsicMap[Rename];
Tim Northover2fe823a2013-08-01 09:23:19 +00002736 if (A64CK == ck && ck != ClassNone)
Peter Collingbournebee583f2011-10-06 13:03:08 +00002737 continue;
Tim Northover2fe823a2013-08-01 09:23:19 +00002738 }
Peter Collingbournebee583f2011-10-06 13:03:08 +00002739
Tim Northover2fe823a2013-08-01 09:23:19 +00002740 for (unsigned ti = 0, te = TypeVec.size(); ti != te; ++ti) {
2741 // Generate the declaration for this builtin, ensuring
2742 // that each unique BUILTIN() macro appears only once in the output
2743 // stream.
2744 std::string bd = GenBuiltinDef(name, Proto, TypeVec[ti], ck);
2745 if (EmittedMap.count(bd))
2746 continue;
Peter Collingbournebee583f2011-10-06 13:03:08 +00002747
Tim Northover2fe823a2013-08-01 09:23:19 +00002748 EmittedMap[bd] = OpNone;
2749 OS << bd << "\n";
Peter Collingbournebee583f2011-10-06 13:03:08 +00002750 }
2751 }
2752 OS << "#endif\n\n";
2753}
2754
Tim Northover2fe823a2013-08-01 09:23:19 +00002755/// runHeader - Emit a file with sections defining:
2756/// 1. the NEON section of BuiltinsARM.def and BuiltinsAArch64.def.
2757/// 2. the SemaChecking code for the type overload checking.
2758/// 3. the SemaChecking code for validation of intrinsic immediate arguments.
2759void NeonEmitter::runHeader(raw_ostream &OS) {
2760 std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst");
2761
2762 // build a map of AArch64 intriniscs to be used in uniqueness checks.
2763 StringMap<ClassKind> A64IntrinsicMap;
2764 for (unsigned i = 0, e = RV.size(); i != e; ++i) {
2765 Record *R = RV[i];
2766
2767 bool isA64 = R->getValueAsBit("isA64");
2768 if (!isA64)
2769 continue;
2770
2771 ClassKind CK = ClassNone;
2772 if (R->getSuperClasses().size() >= 2)
2773 CK = ClassMap[R->getSuperClasses()[1]];
2774
2775 std::string Name = R->getValueAsString("Name");
Kevin Qinc076d062013-08-29 07:55:15 +00002776 std::string Proto = R->getValueAsString("Prototype");
2777 std::string Rename = Name + "@" + Proto;
2778 if (A64IntrinsicMap.count(Rename))
Tim Northover2fe823a2013-08-01 09:23:19 +00002779 continue;
Kevin Qinc076d062013-08-29 07:55:15 +00002780 A64IntrinsicMap[Rename] = CK;
Tim Northover2fe823a2013-08-01 09:23:19 +00002781 }
2782
2783 // Generate BuiltinsARM.def for ARM
2784 genBuiltinsDef(OS, A64IntrinsicMap, false);
2785
2786 // Generate BuiltinsAArch64.def for AArch64
2787 genBuiltinsDef(OS, A64IntrinsicMap, true);
2788
2789 // Generate ARM overloaded type checking code for SemaChecking.cpp
2790 genOverloadTypeCheckCode(OS, A64IntrinsicMap, false);
2791
2792 // Generate AArch64 overloaded type checking code for SemaChecking.cpp
2793 genOverloadTypeCheckCode(OS, A64IntrinsicMap, true);
2794
2795 // Generate ARM range checking code for shift/lane immediates.
2796 genIntrinsicRangeCheckCode(OS, A64IntrinsicMap, false);
2797
2798 // Generate the AArch64 range checking code for shift/lane immediates.
2799 genIntrinsicRangeCheckCode(OS, A64IntrinsicMap, true);
2800}
2801
Peter Collingbournebee583f2011-10-06 13:03:08 +00002802/// GenTest - Write out a test for the intrinsic specified by the name and
2803/// type strings, including the embedded patterns for FileCheck to match.
2804static std::string GenTest(const std::string &name,
2805 const std::string &proto,
2806 StringRef outTypeStr, StringRef inTypeStr,
Michael Gottesmand44c8f72013-04-16 22:48:52 +00002807 bool isShift, bool isHiddenLOp,
Tim Northover2fe823a2013-08-01 09:23:19 +00002808 ClassKind ck, const std::string &InstName,
2809 bool isA64,
2810 std::string & testFuncProto) {
Peter Collingbournebee583f2011-10-06 13:03:08 +00002811 assert(!proto.empty() && "");
2812 std::string s;
2813
2814 // Function name with type suffix
2815 std::string mangledName = MangleName(name, outTypeStr, ClassS);
2816 if (outTypeStr != inTypeStr) {
2817 // If the input type is different (e.g., for vreinterpret), append a suffix
2818 // for the input type. String off a "Q" (quad) prefix so that MangleName
2819 // does not insert another "q" in the name.
2820 unsigned typeStrOff = (inTypeStr[0] == 'Q' ? 1 : 0);
2821 StringRef inTypeNoQuad = inTypeStr.substr(typeStrOff);
2822 mangledName = MangleName(mangledName, inTypeNoQuad, ClassS);
2823 }
2824
Tim Northover2fe823a2013-08-01 09:23:19 +00002825 // todo: GenerateChecksForIntrinsic does not generate CHECK
2826 // for aarch64 instructions yet
Michael Gottesman6cd3e562013-04-16 23:00:26 +00002827 std::vector<std::string> FileCheckPatterns;
Tim Northover2fe823a2013-08-01 09:23:19 +00002828 if (!isA64) {
2829 GenerateChecksForIntrinsic(name, proto, outTypeStr, inTypeStr, ck, InstName,
2830 isHiddenLOp, FileCheckPatterns);
2831 s+= "// CHECK_ARM: test_" + mangledName + "\n";
2832 }
2833 s += "// CHECK_AARCH64: test_" + mangledName + "\n";
Michael Gottesman6cd3e562013-04-16 23:00:26 +00002834
Peter Collingbournebee583f2011-10-06 13:03:08 +00002835 // Emit the FileCheck patterns.
Michael Gottesman6cd3e562013-04-16 23:00:26 +00002836 // If for any reason we do not want to emit a check, mangledInst
2837 // will be the empty string.
2838 if (FileCheckPatterns.size()) {
2839 for (std::vector<std::string>::const_iterator i = FileCheckPatterns.begin(),
2840 e = FileCheckPatterns.end();
2841 i != e;
2842 ++i) {
Tim Northover2fe823a2013-08-01 09:23:19 +00002843 s += "// CHECK_ARM: " + *i + "\n";
Michael Gottesman6cd3e562013-04-16 23:00:26 +00002844 }
2845 }
Peter Collingbournebee583f2011-10-06 13:03:08 +00002846
2847 // Emit the start of the test function.
Tim Northover2fe823a2013-08-01 09:23:19 +00002848
2849 testFuncProto = TypeString(proto[0], outTypeStr) + " test_" + mangledName + "(";
Peter Collingbournebee583f2011-10-06 13:03:08 +00002850 char arg = 'a';
2851 std::string comma;
2852 for (unsigned i = 1, e = proto.size(); i != e; ++i, ++arg) {
2853 // Do not create arguments for values that must be immediate constants.
2854 if (proto[i] == 'i')
2855 continue;
Tim Northover2fe823a2013-08-01 09:23:19 +00002856 testFuncProto += comma + TypeString(proto[i], inTypeStr) + " ";
2857 testFuncProto.push_back(arg);
Peter Collingbournebee583f2011-10-06 13:03:08 +00002858 comma = ", ";
2859 }
Tim Northover2fe823a2013-08-01 09:23:19 +00002860 testFuncProto += ")";
2861
2862 s+= testFuncProto;
2863 s+= " {\n ";
Peter Collingbournebee583f2011-10-06 13:03:08 +00002864
2865 if (proto[0] != 'v')
2866 s += "return ";
2867 s += mangledName + "(";
2868 arg = 'a';
2869 for (unsigned i = 1, e = proto.size(); i != e; ++i, ++arg) {
2870 if (proto[i] == 'i') {
2871 // For immediate operands, test the maximum value.
2872 if (isShift)
2873 s += "1"; // FIXME
2874 else
2875 // The immediate generally refers to a lane in the preceding argument.
2876 s += utostr(RangeFromType(proto[i-1], inTypeStr));
2877 } else {
2878 s.push_back(arg);
2879 }
2880 if ((i + 1) < e)
2881 s += ", ";
2882 }
2883 s += ");\n}\n\n";
2884 return s;
2885}
2886
Tim Northover2fe823a2013-08-01 09:23:19 +00002887/// Write out all intrinsic tests for the specified target, checking
2888/// for intrinsic test uniqueness.
2889void NeonEmitter::genTargetTest(raw_ostream &OS, StringMap<OpKind> &EmittedMap,
2890 bool isA64GenTest) {
2891 if (isA64GenTest)
2892 OS << "#ifdef __aarch64__\n";
Peter Collingbournebee583f2011-10-06 13:03:08 +00002893
Tim Northover2fe823a2013-08-01 09:23:19 +00002894 std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst");
Peter Collingbournebee583f2011-10-06 13:03:08 +00002895 for (unsigned i = 0, e = RV.size(); i != e; ++i) {
2896 Record *R = RV[i];
2897 std::string name = R->getValueAsString("Name");
2898 std::string Proto = R->getValueAsString("Prototype");
2899 std::string Types = R->getValueAsString("Types");
2900 bool isShift = R->getValueAsBit("isShift");
Michael Gottesmand44c8f72013-04-16 22:48:52 +00002901 std::string InstName = R->getValueAsString("InstName");
2902 bool isHiddenLOp = R->getValueAsBit("isHiddenLInst");
Tim Northover2fe823a2013-08-01 09:23:19 +00002903 bool isA64 = R->getValueAsBit("isA64");
2904
2905 // do not include AArch64 intrinsic test if not generating
2906 // code for AArch64
2907 if (!isA64GenTest && isA64)
2908 continue;
Peter Collingbournebee583f2011-10-06 13:03:08 +00002909
2910 SmallVector<StringRef, 16> TypeVec;
2911 ParseTypes(R, Types, TypeVec);
2912
Michael Gottesmand44c8f72013-04-16 22:48:52 +00002913 ClassKind ck = ClassMap[R->getSuperClasses()[1]];
Peter Collingbournebee583f2011-10-06 13:03:08 +00002914 OpKind kind = OpMap[R->getValueAsDef("Operand")->getName()];
Jim Grosbach6f855e32012-05-09 18:17:30 +00002915 if (kind == OpUnavailable)
2916 continue;
Peter Collingbournebee583f2011-10-06 13:03:08 +00002917 for (unsigned ti = 0, te = TypeVec.size(); ti != te; ++ti) {
2918 if (kind == OpReinterpret) {
2919 bool outQuad = false;
2920 bool dummy = false;
2921 (void)ClassifyType(TypeVec[ti], outQuad, dummy, dummy);
2922 for (unsigned srcti = 0, srcte = TypeVec.size();
2923 srcti != srcte; ++srcti) {
2924 bool inQuad = false;
2925 (void)ClassifyType(TypeVec[srcti], inQuad, dummy, dummy);
2926 if (srcti == ti || inQuad != outQuad)
2927 continue;
Tim Northover2fe823a2013-08-01 09:23:19 +00002928 std::string testFuncProto;
2929 std::string s = GenTest(name, Proto, TypeVec[ti], TypeVec[srcti],
2930 isShift, isHiddenLOp, ck, InstName, isA64,
2931 testFuncProto);
2932 if (EmittedMap.count(testFuncProto))
2933 continue;
2934 EmittedMap[testFuncProto] = kind;
2935 OS << s << "\n";
Peter Collingbournebee583f2011-10-06 13:03:08 +00002936 }
2937 } else {
Tim Northover2fe823a2013-08-01 09:23:19 +00002938 std::string testFuncProto;
2939 std::string s = GenTest(name, Proto, TypeVec[ti], TypeVec[ti], isShift,
2940 isHiddenLOp, ck, InstName, isA64, testFuncProto);
2941 if (EmittedMap.count(testFuncProto))
2942 continue;
2943 EmittedMap[testFuncProto] = kind;
2944 OS << s << "\n";
Peter Collingbournebee583f2011-10-06 13:03:08 +00002945 }
2946 }
Peter Collingbournebee583f2011-10-06 13:03:08 +00002947 }
Tim Northover2fe823a2013-08-01 09:23:19 +00002948
2949 if (isA64GenTest)
2950 OS << "#endif\n";
2951}
2952/// runTests - Write out a complete set of tests for all of the Neon
2953/// intrinsics.
2954void NeonEmitter::runTests(raw_ostream &OS) {
2955 OS << "// RUN: %clang_cc1 -triple thumbv7s-apple-darwin -target-abi "
2956 "apcs-gnu\\\n"
2957 "// RUN: -target-cpu swift -ffreestanding -Os -S -o - %s\\\n"
2958 "// RUN: | FileCheck %s -check-prefix=CHECK_ARM\n"
2959 "\n"
2960 "// RUN: %clang_cc1 -triple aarch64-none-linux-gnu \\\n"
2961 "// RUN -target-feature +neon -ffreestanding -S -o - %s \\\n"
2962 "// RUN: | FileCheck %s -check-prefix=CHECK_AARCH64\n"
2963 "\n"
2964 "// REQUIRES: long_tests\n"
2965 "\n"
2966 "#include <arm_neon.h>\n"
2967 "\n";
2968
2969 // ARM tests must be emitted before AArch64 tests to ensure
2970 // tests for intrinsics that are common to ARM and AArch64
2971 // appear only once in the output stream.
2972 // The check for uniqueness is done in genTargetTest.
2973 StringMap<OpKind> EmittedMap;
2974
2975 genTargetTest(OS, EmittedMap, false);
2976
2977 genTargetTest(OS, EmittedMap, true);
Peter Collingbournebee583f2011-10-06 13:03:08 +00002978}
2979
Jakob Stoklund Olesen995e0e12012-06-13 05:12:41 +00002980namespace clang {
2981void EmitNeon(RecordKeeper &Records, raw_ostream &OS) {
2982 NeonEmitter(Records).run(OS);
2983}
2984void EmitNeonSema(RecordKeeper &Records, raw_ostream &OS) {
2985 NeonEmitter(Records).runHeader(OS);
2986}
2987void EmitNeonTest(RecordKeeper &Records, raw_ostream &OS) {
2988 NeonEmitter(Records).runTests(OS);
2989}
2990} // End namespace clang