blob: 8d4380a1a6ef81fc7f566d7f8818aca9d35ee7a5 [file] [log] [blame]
Peter Collingbourne51d77772011-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 Olesen3cc509b2012-06-13 05:12:41 +000026#include "llvm/ADT/DenseMap.h"
Peter Collingbourne51d77772011-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 Olesen3cc509b2012-06-13 05:12:41 +000030#include "llvm/ADT/StringMap.h"
David Blaikie7530c032012-01-17 06:56:22 +000031#include "llvm/Support/ErrorHandling.h"
Jakob Stoklund Olesen3cc509b2012-06-13 05:12:41 +000032#include "llvm/TableGen/Error.h"
33#include "llvm/TableGen/Record.h"
34#include "llvm/TableGen/TableGenBackend.h"
Peter Collingbourne51d77772011-10-06 13:03:08 +000035#include <string>
Peter Collingbourne51d77772011-10-06 13:03:08 +000036using namespace llvm;
37
Jakob Stoklund Olesen3cc509b2012-06-13 05:12:41 +000038enum OpKind {
39 OpNone,
40 OpUnavailable,
41 OpAdd,
42 OpAddl,
Jiangning Liu097a4b42013-09-09 02:21:08 +000043 OpAddlHi,
Jakob Stoklund Olesen3cc509b2012-06-13 05:12:41 +000044 OpAddw,
Jiangning Liu097a4b42013-09-09 02:21:08 +000045 OpAddwHi,
Jakob Stoklund Olesen3cc509b2012-06-13 05:12:41 +000046 OpSub,
47 OpSubl,
Jiangning Liu097a4b42013-09-09 02:21:08 +000048 OpSublHi,
Jakob Stoklund Olesen3cc509b2012-06-13 05:12:41 +000049 OpSubw,
Jiangning Liu097a4b42013-09-09 02:21:08 +000050 OpSubwHi,
Jakob Stoklund Olesen3cc509b2012-06-13 05:12:41 +000051 OpMul,
52 OpMla,
53 OpMlal,
Jiangning Liu097a4b42013-09-09 02:21:08 +000054 OpMullHi,
55 OpMlalHi,
Jakob Stoklund Olesen3cc509b2012-06-13 05:12:41 +000056 OpMls,
57 OpMlsl,
Jiangning Liu097a4b42013-09-09 02:21:08 +000058 OpMlslHi,
Jakob Stoklund Olesen3cc509b2012-06-13 05:12:41 +000059 OpMulN,
60 OpMlaN,
61 OpMlsN,
62 OpMlalN,
63 OpMlslN,
64 OpMulLane,
Jiangning Liu0aa1a882013-10-04 09:21:17 +000065 OpMulXLane,
Jakob Stoklund Olesen3cc509b2012-06-13 05:12:41 +000066 OpMullLane,
Jiangning Liu0aa1a882013-10-04 09:21:17 +000067 OpMullHiLane,
Jakob Stoklund Olesen3cc509b2012-06-13 05:12:41 +000068 OpMlaLane,
69 OpMlsLane,
70 OpMlalLane,
Jiangning Liu0aa1a882013-10-04 09:21:17 +000071 OpMlalHiLane,
Jakob Stoklund Olesen3cc509b2012-06-13 05:12:41 +000072 OpMlslLane,
Jiangning Liu0aa1a882013-10-04 09:21:17 +000073 OpMlslHiLane,
Jakob Stoklund Olesen3cc509b2012-06-13 05:12:41 +000074 OpQDMullLane,
Jiangning Liu0aa1a882013-10-04 09:21:17 +000075 OpQDMullHiLane,
Jakob Stoklund Olesen3cc509b2012-06-13 05:12:41 +000076 OpQDMlalLane,
Jiangning Liu0aa1a882013-10-04 09:21:17 +000077 OpQDMlalHiLane,
Jakob Stoklund Olesen3cc509b2012-06-13 05:12:41 +000078 OpQDMlslLane,
Jiangning Liu0aa1a882013-10-04 09:21:17 +000079 OpQDMlslHiLane,
Jakob Stoklund Olesen3cc509b2012-06-13 05:12:41 +000080 OpQDMulhLane,
81 OpQRDMulhLane,
Jiangning Liu0aa1a882013-10-04 09:21:17 +000082 OpFMSLane,
83 OpFMSLaneQ,
Jakob Stoklund Olesen3cc509b2012-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 Liu097a4b42013-09-09 02:21:08 +0000107 OpAddhnHi,
108 OpRAddhnHi,
109 OpSubhnHi,
110 OpRSubhnHi,
Jakob Stoklund Olesen3cc509b2012-06-13 05:12:41 +0000111 OpAbdl,
Jiangning Liu097a4b42013-09-09 02:21:08 +0000112 OpAbdlHi,
Jakob Stoklund Olesen3cc509b2012-06-13 05:12:41 +0000113 OpAba,
Tim Northoverb793f0d2013-08-01 09:23:19 +0000114 OpAbal,
Jiangning Liu097a4b42013-09-09 02:21:08 +0000115 OpAbalHi,
116 OpQDMullHi,
117 OpQDMlalHi,
118 OpQDMlslHi,
Hao Liu912502b2013-09-04 09:29:13 +0000119 OpDiv,
120 OpLongHi,
121 OpNarrowHi,
Kevin Qin2102a1d2013-10-11 02:34:30 +0000122 OpMovlHi,
123 OpCopy
Jakob Stoklund Olesen3cc509b2012-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 Gottesman21e4e942013-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 Olesen3cc509b2012-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 Northoverb793f0d2013-08-01 09:23:19 +0000160 Float32,
161 Float64
Jakob Stoklund Olesen3cc509b2012-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 Liu097a4b42013-09-09 02:21:08 +0000188 OpMap["OP_ADDLHi"] = OpAddlHi;
Jakob Stoklund Olesen3cc509b2012-06-13 05:12:41 +0000189 OpMap["OP_ADDW"] = OpAddw;
Jiangning Liu097a4b42013-09-09 02:21:08 +0000190 OpMap["OP_ADDWHi"] = OpAddwHi;
Jakob Stoklund Olesen3cc509b2012-06-13 05:12:41 +0000191 OpMap["OP_SUB"] = OpSub;
192 OpMap["OP_SUBL"] = OpSubl;
Jiangning Liu097a4b42013-09-09 02:21:08 +0000193 OpMap["OP_SUBLHi"] = OpSublHi;
Jakob Stoklund Olesen3cc509b2012-06-13 05:12:41 +0000194 OpMap["OP_SUBW"] = OpSubw;
Jiangning Liu097a4b42013-09-09 02:21:08 +0000195 OpMap["OP_SUBWHi"] = OpSubwHi;
Jakob Stoklund Olesen3cc509b2012-06-13 05:12:41 +0000196 OpMap["OP_MUL"] = OpMul;
197 OpMap["OP_MLA"] = OpMla;
198 OpMap["OP_MLAL"] = OpMlal;
Jiangning Liu097a4b42013-09-09 02:21:08 +0000199 OpMap["OP_MULLHi"] = OpMullHi;
200 OpMap["OP_MLALHi"] = OpMlalHi;
Jakob Stoklund Olesen3cc509b2012-06-13 05:12:41 +0000201 OpMap["OP_MLS"] = OpMls;
202 OpMap["OP_MLSL"] = OpMlsl;
Jiangning Liu097a4b42013-09-09 02:21:08 +0000203 OpMap["OP_MLSLHi"] = OpMlslHi;
Jakob Stoklund Olesen3cc509b2012-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 Liu0aa1a882013-10-04 09:21:17 +0000210 OpMap["OP_MULX_LN"]= OpMulXLane;
Jakob Stoklund Olesen3cc509b2012-06-13 05:12:41 +0000211 OpMap["OP_MULL_LN"] = OpMullLane;
Jiangning Liu0aa1a882013-10-04 09:21:17 +0000212 OpMap["OP_MULLHi_LN"] = OpMullHiLane;
Jakob Stoklund Olesen3cc509b2012-06-13 05:12:41 +0000213 OpMap["OP_MLA_LN"]= OpMlaLane;
214 OpMap["OP_MLS_LN"]= OpMlsLane;
215 OpMap["OP_MLAL_LN"] = OpMlalLane;
Jiangning Liu0aa1a882013-10-04 09:21:17 +0000216 OpMap["OP_MLALHi_LN"] = OpMlalHiLane;
Jakob Stoklund Olesen3cc509b2012-06-13 05:12:41 +0000217 OpMap["OP_MLSL_LN"] = OpMlslLane;
Jiangning Liu0aa1a882013-10-04 09:21:17 +0000218 OpMap["OP_MLSLHi_LN"] = OpMlslHiLane;
Jakob Stoklund Olesen3cc509b2012-06-13 05:12:41 +0000219 OpMap["OP_QDMULL_LN"] = OpQDMullLane;
Jiangning Liu0aa1a882013-10-04 09:21:17 +0000220 OpMap["OP_QDMULLHi_LN"] = OpQDMullHiLane;
Jakob Stoklund Olesen3cc509b2012-06-13 05:12:41 +0000221 OpMap["OP_QDMLAL_LN"] = OpQDMlalLane;
Jiangning Liu0aa1a882013-10-04 09:21:17 +0000222 OpMap["OP_QDMLALHi_LN"] = OpQDMlalHiLane;
Jakob Stoklund Olesen3cc509b2012-06-13 05:12:41 +0000223 OpMap["OP_QDMLSL_LN"] = OpQDMlslLane;
Jiangning Liu0aa1a882013-10-04 09:21:17 +0000224 OpMap["OP_QDMLSLHi_LN"] = OpQDMlslHiLane;
Jakob Stoklund Olesen3cc509b2012-06-13 05:12:41 +0000225 OpMap["OP_QDMULH_LN"] = OpQDMulhLane;
226 OpMap["OP_QRDMULH_LN"] = OpQRDMulhLane;
Jiangning Liu0aa1a882013-10-04 09:21:17 +0000227 OpMap["OP_FMS_LN"] = OpFMSLane;
228 OpMap["OP_FMS_LNQ"] = OpFMSLaneQ;
Jakob Stoklund Olesen3cc509b2012-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 Liu097a4b42013-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 Olesen3cc509b2012-06-13 05:12:41 +0000256 OpMap["OP_ABDL"] = OpAbdl;
Jiangning Liu097a4b42013-09-09 02:21:08 +0000257 OpMap["OP_ABDLHi"] = OpAbdlHi;
Jakob Stoklund Olesen3cc509b2012-06-13 05:12:41 +0000258 OpMap["OP_ABA"] = OpAba;
259 OpMap["OP_ABAL"] = OpAbal;
Jiangning Liu097a4b42013-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 Northoverb793f0d2013-08-01 09:23:19 +0000264 OpMap["OP_DIV"] = OpDiv;
Hao Liu912502b2013-09-04 09:29:13 +0000265 OpMap["OP_LONG_HI"] = OpLongHi;
266 OpMap["OP_NARROW_HI"] = OpNarrowHi;
267 OpMap["OP_MOVL_HI"] = OpMovlHi;
Kevin Qin2102a1d2013-10-11 02:34:30 +0000268 OpMap["OP_COPY"] = OpCopy;
Jakob Stoklund Olesen3cc509b2012-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 Gottesman21e4e942013-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 Olesen3cc509b2012-06-13 05:12:41 +0000279 ClassMap[SI] = ClassS;
280 ClassMap[II] = ClassI;
281 ClassMap[WI] = ClassW;
Michael Gottesman21e4e942013-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 Olesen3cc509b2012-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 Northoverb793f0d2013-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 Olesen3cc509b2012-06-13 05:12:41 +0000311};
312} // end anonymous namespace
313
Peter Collingbourne51d77772011-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 Liu12cd6a82013-08-15 08:26:30 +0000324 if (data[len] == 'P' || data[len] == 'Q' || data[len] == 'U'
Kevin Qin944f09f2013-08-29 07:55:15 +0000325 || data[len] == 'H' || data[len] == 'S')
Peter Collingbourne51d77772011-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 Northoverb793f0d2013-08-01 09:23:19 +0000335 case 'd':
Peter Collingbourne51d77772011-10-06 13:03:08 +0000336 break;
337 default:
Joerg Sonnenberger38859ee2012-10-25 16:37:08 +0000338 PrintFatalError(r->getLoc(),
Peter Collingbourne51d77772011-10-06 13:03:08 +0000339 "Unexpected letter: " + std::string(data + len, 1));
Peter Collingbourne51d77772011-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 Sonnenberger38859ee2012-10-25 16:37:08 +0000359 default:
360 PrintFatalError("unhandled type in widen!");
Peter Collingbourne51d77772011-10-06 13:03:08 +0000361 }
Peter Collingbourne51d77772011-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 Sonnenberger38859ee2012-10-25 16:37:08 +0000376 default:
377 PrintFatalError("unhandled type in narrow!");
Peter Collingbourne51d77772011-10-06 13:03:08 +0000378 }
Peter Collingbourne51d77772011-10-06 13:03:08 +0000379}
380
Jiangning Liu097a4b42013-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 Collingbourne51d77772011-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 Qin944f09f2013-08-29 07:55:15 +0000408 // ignore scalar.
409 if (ty[off] == 'S') {
410 ++off;
411 }
Peter Collingbourne51d77772011-10-06 13:03:08 +0000412 // remember quad.
Hao Liu12cd6a82013-08-15 08:26:30 +0000413 if (ty[off] == 'Q' || ty[off] == 'H') {
Peter Collingbourne51d77772011-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;
445 case 'u':
446 usgn = true;
447 poly = false;
448 if (type == 'f')
449 type = 'i';
Tim Northoverb793f0d2013-08-01 09:23:19 +0000450 if (type == 'd')
451 type = 'l';
Peter Collingbourne51d77772011-10-06 13:03:08 +0000452 break;
453 case 'x':
454 usgn = false;
455 poly = false;
456 if (type == 'f')
457 type = 'i';
Hao Liu912502b2013-09-04 09:29:13 +0000458 if (type == 'd')
459 type = 'l';
Peter Collingbourne51d77772011-10-06 13:03:08 +0000460 break;
Chad Rosier6d048e12013-10-08 20:43:46 +0000461 case 'o':
462 scal = true;
463 type = 'd';
464 usgn = false;
465 break;
466 case 'y':
467 scal = true;
Peter Collingbourne51d77772011-10-06 13:03:08 +0000468 case 'f':
469 if (type == 'h')
470 quad = true;
471 type = 'f';
472 usgn = false;
473 break;
474 case 'g':
475 quad = false;
476 break;
Jiangning Liu0aa1a882013-10-04 09:21:17 +0000477 case 'j':
478 quad = true;
479 break;
Peter Collingbourne51d77772011-10-06 13:03:08 +0000480 case 'w':
481 type = Widen(type);
482 quad = true;
483 break;
484 case 'n':
485 type = Widen(type);
486 break;
487 case 'i':
488 type = 'i';
489 scal = true;
490 break;
491 case 'l':
492 type = 'l';
493 scal = true;
494 usgn = true;
495 break;
Jiangning Liu03916912013-10-05 08:22:55 +0000496 case 'r':
497 type = Widen(type);
Peter Collingbourne51d77772011-10-06 13:03:08 +0000498 case 's':
499 case 'a':
500 scal = true;
501 break;
502 case 'k':
503 quad = true;
504 break;
505 case 'c':
506 cnst = true;
507 case 'p':
508 pntr = true;
509 scal = true;
510 break;
511 case 'h':
512 type = Narrow(type);
513 if (type == 'h')
514 quad = false;
515 break;
Jiangning Liu097a4b42013-09-09 02:21:08 +0000516 case 'q':
517 type = Narrow(type);
518 quad = true;
519 break;
Peter Collingbourne51d77772011-10-06 13:03:08 +0000520 case 'e':
521 type = Narrow(type);
522 usgn = true;
523 break;
Hao Liu912502b2013-09-04 09:29:13 +0000524 case 'm':
525 type = Narrow(type);
526 quad = false;
527 break;
Peter Collingbourne51d77772011-10-06 13:03:08 +0000528 default:
529 break;
530 }
531 return type;
532}
533
534/// TypeString - for a modifier and type, generate the name of the typedef for
535/// that type. QUc -> uint8x8_t.
536static std::string TypeString(const char mod, StringRef typestr) {
537 bool quad = false;
538 bool poly = false;
539 bool usgn = false;
540 bool scal = false;
541 bool cnst = false;
542 bool pntr = false;
543
544 if (mod == 'v')
545 return "void";
546 if (mod == 'i')
547 return "int";
548
549 // base type to get the type string for.
550 char type = ClassifyType(typestr, quad, poly, usgn);
551
552 // Based on the modifying character, change the type and width if necessary.
553 type = ModType(mod, type, quad, poly, usgn, scal, cnst, pntr);
554
555 SmallString<128> s;
556
557 if (usgn)
558 s.push_back('u');
559
560 switch (type) {
561 case 'c':
562 s += poly ? "poly8" : "int8";
563 if (scal)
564 break;
565 s += quad ? "x16" : "x8";
566 break;
567 case 's':
568 s += poly ? "poly16" : "int16";
569 if (scal)
570 break;
571 s += quad ? "x8" : "x4";
572 break;
573 case 'i':
574 s += "int32";
575 if (scal)
576 break;
577 s += quad ? "x4" : "x2";
578 break;
579 case 'l':
580 s += "int64";
581 if (scal)
582 break;
583 s += quad ? "x2" : "x1";
584 break;
585 case 'h':
586 s += "float16";
587 if (scal)
588 break;
589 s += quad ? "x8" : "x4";
590 break;
591 case 'f':
592 s += "float32";
593 if (scal)
594 break;
595 s += quad ? "x4" : "x2";
596 break;
Tim Northoverb793f0d2013-08-01 09:23:19 +0000597 case 'd':
598 s += "float64";
599 if (scal)
600 break;
601 s += quad ? "x2" : "x1";
602 break;
603
Peter Collingbourne51d77772011-10-06 13:03:08 +0000604 default:
Joerg Sonnenberger38859ee2012-10-25 16:37:08 +0000605 PrintFatalError("unhandled type!");
Peter Collingbourne51d77772011-10-06 13:03:08 +0000606 }
607
608 if (mod == '2')
609 s += "x2";
610 if (mod == '3')
611 s += "x3";
612 if (mod == '4')
613 s += "x4";
614
615 // Append _t, finishing the type string typedef type.
616 s += "_t";
617
618 if (cnst)
619 s += " const";
620
621 if (pntr)
622 s += " *";
623
624 return s.str();
625}
626
627/// BuiltinTypeString - for a modifier and type, generate the clang
628/// BuiltinsARM.def prototype code for the function. See the top of clang's
629/// Builtins.def for a description of the type strings.
630static std::string BuiltinTypeString(const char mod, StringRef typestr,
631 ClassKind ck, bool ret) {
632 bool quad = false;
633 bool poly = false;
634 bool usgn = false;
635 bool scal = false;
636 bool cnst = false;
637 bool pntr = false;
638
639 if (mod == 'v')
640 return "v"; // void
641 if (mod == 'i')
642 return "i"; // int
643
644 // base type to get the type string for.
645 char type = ClassifyType(typestr, quad, poly, usgn);
646
647 // Based on the modifying character, change the type and width if necessary.
648 type = ModType(mod, type, quad, poly, usgn, scal, cnst, pntr);
649
650 // All pointers are void* pointers. Change type to 'v' now.
651 if (pntr) {
652 usgn = false;
653 poly = false;
654 type = 'v';
655 }
656 // Treat half-float ('h') types as unsigned short ('s') types.
657 if (type == 'h') {
658 type = 's';
659 usgn = true;
660 }
Jiangning Liu0aa1a882013-10-04 09:21:17 +0000661 usgn = usgn | poly | ((ck == ClassI || ck == ClassW) &&
662 scal && type != 'f' && type != 'd');
Peter Collingbourne51d77772011-10-06 13:03:08 +0000663
664 if (scal) {
665 SmallString<128> s;
666
667 if (usgn)
668 s.push_back('U');
669 else if (type == 'c')
670 s.push_back('S'); // make chars explicitly signed
671
672 if (type == 'l') // 64-bit long
673 s += "LLi";
674 else
675 s.push_back(type);
676
677 if (cnst)
678 s.push_back('C');
679 if (pntr)
680 s.push_back('*');
681 return s.str();
682 }
683
684 // Since the return value must be one type, return a vector type of the
685 // appropriate width which we will bitcast. An exception is made for
686 // returning structs of 2, 3, or 4 vectors which are returned in a sret-like
687 // fashion, storing them to a pointer arg.
688 if (ret) {
689 if (mod >= '2' && mod <= '4')
690 return "vv*"; // void result with void* first argument
691 if (mod == 'f' || (ck != ClassB && type == 'f'))
692 return quad ? "V4f" : "V2f";
Jiangning Liu0aa1a882013-10-04 09:21:17 +0000693 if (ck != ClassB && type == 'd')
694 return quad ? "V2d" : "V1d";
Peter Collingbourne51d77772011-10-06 13:03:08 +0000695 if (ck != ClassB && type == 's')
696 return quad ? "V8s" : "V4s";
697 if (ck != ClassB && type == 'i')
698 return quad ? "V4i" : "V2i";
699 if (ck != ClassB && type == 'l')
700 return quad ? "V2LLi" : "V1LLi";
701
702 return quad ? "V16Sc" : "V8Sc";
703 }
704
705 // Non-return array types are passed as individual vectors.
706 if (mod == '2')
707 return quad ? "V16ScV16Sc" : "V8ScV8Sc";
708 if (mod == '3')
709 return quad ? "V16ScV16ScV16Sc" : "V8ScV8ScV8Sc";
710 if (mod == '4')
711 return quad ? "V16ScV16ScV16ScV16Sc" : "V8ScV8ScV8ScV8Sc";
712
713 if (mod == 'f' || (ck != ClassB && type == 'f'))
714 return quad ? "V4f" : "V2f";
Jiangning Liu0aa1a882013-10-04 09:21:17 +0000715 if (ck != ClassB && type == 'd')
716 return quad ? "V2d" : "V1d";
Peter Collingbourne51d77772011-10-06 13:03:08 +0000717 if (ck != ClassB && type == 's')
718 return quad ? "V8s" : "V4s";
719 if (ck != ClassB && type == 'i')
720 return quad ? "V4i" : "V2i";
721 if (ck != ClassB && type == 'l')
722 return quad ? "V2LLi" : "V1LLi";
723
724 return quad ? "V16Sc" : "V8Sc";
725}
726
Michael Gottesmanfb599a42013-04-16 22:07:30 +0000727/// InstructionTypeCode - Computes the ARM argument character code and
728/// quad status for a specific type string and ClassKind.
729static void InstructionTypeCode(const StringRef &typeStr,
730 const ClassKind ck,
731 bool &quad,
732 std::string &typeCode) {
733 bool poly = false;
734 bool usgn = false;
735 char type = ClassifyType(typeStr, quad, poly, usgn);
736
737 switch (type) {
738 case 'c':
739 switch (ck) {
740 case ClassS: typeCode = poly ? "p8" : usgn ? "u8" : "s8"; break;
741 case ClassI: typeCode = "i8"; break;
742 case ClassW: typeCode = "8"; break;
743 default: break;
744 }
745 break;
746 case 's':
747 switch (ck) {
748 case ClassS: typeCode = poly ? "p16" : usgn ? "u16" : "s16"; break;
749 case ClassI: typeCode = "i16"; break;
750 case ClassW: typeCode = "16"; break;
751 default: break;
752 }
753 break;
754 case 'i':
755 switch (ck) {
756 case ClassS: typeCode = usgn ? "u32" : "s32"; break;
757 case ClassI: typeCode = "i32"; break;
758 case ClassW: typeCode = "32"; break;
759 default: break;
760 }
761 break;
762 case 'l':
763 switch (ck) {
764 case ClassS: typeCode = usgn ? "u64" : "s64"; break;
765 case ClassI: typeCode = "i64"; break;
766 case ClassW: typeCode = "64"; break;
767 default: break;
768 }
769 break;
770 case 'h':
771 switch (ck) {
772 case ClassS:
773 case ClassI: typeCode = "f16"; break;
774 case ClassW: typeCode = "16"; break;
775 default: break;
776 }
777 break;
778 case 'f':
779 switch (ck) {
780 case ClassS:
781 case ClassI: typeCode = "f32"; break;
782 case ClassW: typeCode = "32"; break;
783 default: break;
784 }
785 break;
Tim Northoverb793f0d2013-08-01 09:23:19 +0000786 case 'd':
787 switch (ck) {
788 case ClassS:
789 case ClassI:
790 typeCode += "f64";
791 break;
792 case ClassW:
793 PrintFatalError("unhandled type!");
794 default:
795 break;
796 }
797 break;
Michael Gottesmanfb599a42013-04-16 22:07:30 +0000798 default:
799 PrintFatalError("unhandled type!");
800 }
801}
802
Kevin Qin944f09f2013-08-29 07:55:15 +0000803static char Insert_BHSD_Suffix(StringRef typestr){
804 unsigned off = 0;
805 if(typestr[off++] == 'S'){
806 while(typestr[off] == 'Q' || typestr[off] == 'H'||
807 typestr[off] == 'P' || typestr[off] == 'U')
808 ++off;
809 switch (typestr[off]){
810 default : break;
811 case 'c' : return 'b';
812 case 's' : return 'h';
813 case 'i' :
814 case 'f' : return 's';
815 case 'l' :
816 case 'd' : return 'd';
817 }
818 }
819 return 0;
820}
821
Peter Collingbourne51d77772011-10-06 13:03:08 +0000822/// MangleName - Append a type or width suffix to a base neon function name,
Hao Liu12cd6a82013-08-15 08:26:30 +0000823/// and insert a 'q' in the appropriate location if type string starts with 'Q'.
824/// E.g. turn "vst2_lane" into "vst2q_lane_f32", etc.
Kevin Qin944f09f2013-08-29 07:55:15 +0000825/// Insert proper 'b' 'h' 's' 'd' if prefix 'S' is used.
Peter Collingbourne51d77772011-10-06 13:03:08 +0000826static std::string MangleName(const std::string &name, StringRef typestr,
827 ClassKind ck) {
828 if (name == "vcvt_f32_f16")
829 return name;
830
831 bool quad = false;
Michael Gottesmanfb599a42013-04-16 22:07:30 +0000832 std::string typeCode = "";
833
834 InstructionTypeCode(typestr, ck, quad, typeCode);
Peter Collingbourne51d77772011-10-06 13:03:08 +0000835
836 std::string s = name;
837
Michael Gottesmanfb599a42013-04-16 22:07:30 +0000838 if (typeCode.size() > 0) {
839 s += "_" + typeCode;
Peter Collingbourne51d77772011-10-06 13:03:08 +0000840 }
Michael Gottesmanfb599a42013-04-16 22:07:30 +0000841
Peter Collingbourne51d77772011-10-06 13:03:08 +0000842 if (ck == ClassB)
843 s += "_v";
844
845 // Insert a 'q' before the first '_' character so that it ends up before
846 // _lane or _n on vector-scalar operations.
Kevin Qin944f09f2013-08-29 07:55:15 +0000847 if (typestr.find("Q") != StringRef::npos) {
Hao Liu12cd6a82013-08-15 08:26:30 +0000848 size_t pos = s.find('_');
849 s = s.insert(pos, "q");
Peter Collingbourne51d77772011-10-06 13:03:08 +0000850 }
Kevin Qin944f09f2013-08-29 07:55:15 +0000851 char ins = Insert_BHSD_Suffix(typestr);
852 if(ins){
853 size_t pos = s.find('_');
854 s = s.insert(pos, &ins, 1);
855 }
Michael Gottesmanc327f872013-04-16 23:00:26 +0000856
Peter Collingbourne51d77772011-10-06 13:03:08 +0000857 return s;
858}
859
Michael Gottesmanc327f872013-04-16 23:00:26 +0000860static void PreprocessInstruction(const StringRef &Name,
861 const std::string &InstName,
862 std::string &Prefix,
863 bool &HasNPostfix,
864 bool &HasLanePostfix,
865 bool &HasDupPostfix,
866 bool &IsSpecialVCvt,
867 size_t &TBNumber) {
868 // All of our instruction name fields from arm_neon.td are of the form
869 // <instructionname>_...
870 // Thus we grab our instruction name via computation of said Prefix.
871 const size_t PrefixEnd = Name.find_first_of('_');
872 // If InstName is passed in, we use that instead of our name Prefix.
873 Prefix = InstName.size() == 0? Name.slice(0, PrefixEnd).str() : InstName;
874
875 const StringRef Postfix = Name.slice(PrefixEnd, Name.size());
876
877 HasNPostfix = Postfix.count("_n");
878 HasLanePostfix = Postfix.count("_lane");
879 HasDupPostfix = Postfix.count("_dup");
880 IsSpecialVCvt = Postfix.size() != 0 && Name.count("vcvt");
881
882 if (InstName.compare("vtbl") == 0 ||
883 InstName.compare("vtbx") == 0) {
884 // If we have a vtblN/vtbxN instruction, use the instruction's ASCII
885 // encoding to get its true value.
886 TBNumber = Name[Name.size()-1] - 48;
887 }
888}
889
890/// GenerateRegisterCheckPatternsForLoadStores - Given a bunch of data we have
891/// extracted, generate a FileCheck pattern for a Load Or Store
892static void
893GenerateRegisterCheckPatternForLoadStores(const StringRef &NameRef,
894 const std::string& OutTypeCode,
895 const bool &IsQuad,
896 const bool &HasDupPostfix,
897 const bool &HasLanePostfix,
898 const size_t Count,
899 std::string &RegisterSuffix) {
900 const bool IsLDSTOne = NameRef.count("vld1") || NameRef.count("vst1");
901 // If N == 3 || N == 4 and we are dealing with a quad instruction, Clang
902 // will output a series of v{ld,st}1s, so we have to handle it specially.
903 if ((Count == 3 || Count == 4) && IsQuad) {
904 RegisterSuffix += "{";
905 for (size_t i = 0; i < Count; i++) {
906 RegisterSuffix += "d{{[0-9]+}}";
907 if (HasDupPostfix) {
908 RegisterSuffix += "[]";
909 }
910 if (HasLanePostfix) {
911 RegisterSuffix += "[{{[0-9]+}}]";
912 }
913 if (i < Count-1) {
914 RegisterSuffix += ", ";
915 }
916 }
917 RegisterSuffix += "}";
918 } else {
919
920 // Handle normal loads and stores.
921 RegisterSuffix += "{";
922 for (size_t i = 0; i < Count; i++) {
923 RegisterSuffix += "d{{[0-9]+}}";
924 if (HasDupPostfix) {
925 RegisterSuffix += "[]";
926 }
927 if (HasLanePostfix) {
928 RegisterSuffix += "[{{[0-9]+}}]";
929 }
930 if (IsQuad && !HasLanePostfix) {
931 RegisterSuffix += ", d{{[0-9]+}}";
932 if (HasDupPostfix) {
933 RegisterSuffix += "[]";
934 }
935 }
936 if (i < Count-1) {
937 RegisterSuffix += ", ";
938 }
939 }
940 RegisterSuffix += "}, [r{{[0-9]+}}";
941
942 // We only include the alignment hint if we have a vld1.*64 or
943 // a dup/lane instruction.
944 if (IsLDSTOne) {
945 if ((HasLanePostfix || HasDupPostfix) && OutTypeCode != "8") {
Michael Gottesman410c3f72013-06-24 21:25:37 +0000946 RegisterSuffix += ":" + OutTypeCode;
Michael Gottesmanc327f872013-04-16 23:00:26 +0000947 }
948 }
949
950 RegisterSuffix += "]";
951 }
952}
953
954static bool HasNPostfixAndScalarArgs(const StringRef &NameRef,
955 const bool &HasNPostfix) {
956 return (NameRef.count("vmla") ||
957 NameRef.count("vmlal") ||
958 NameRef.count("vmlsl") ||
959 NameRef.count("vmull") ||
960 NameRef.count("vqdmlal") ||
961 NameRef.count("vqdmlsl") ||
962 NameRef.count("vqdmulh") ||
963 NameRef.count("vqdmull") ||
964 NameRef.count("vqrdmulh")) && HasNPostfix;
965}
966
967static bool IsFiveOperandLaneAccumulator(const StringRef &NameRef,
968 const bool &HasLanePostfix) {
969 return (NameRef.count("vmla") ||
970 NameRef.count("vmls") ||
971 NameRef.count("vmlal") ||
972 NameRef.count("vmlsl") ||
973 (NameRef.count("vmul") && NameRef.size() == 3)||
974 NameRef.count("vqdmlal") ||
975 NameRef.count("vqdmlsl") ||
976 NameRef.count("vqdmulh") ||
977 NameRef.count("vqrdmulh")) && HasLanePostfix;
978}
979
980static bool IsSpecialLaneMultiply(const StringRef &NameRef,
981 const bool &HasLanePostfix,
982 const bool &IsQuad) {
983 const bool IsVMulOrMulh = (NameRef.count("vmul") || NameRef.count("mulh"))
984 && IsQuad;
985 const bool IsVMull = NameRef.count("mull") && !IsQuad;
986 return (IsVMulOrMulh || IsVMull) && HasLanePostfix;
987}
988
989static void NormalizeProtoForRegisterPatternCreation(const std::string &Name,
990 const std::string &Proto,
991 const bool &HasNPostfix,
992 const bool &IsQuad,
993 const bool &HasLanePostfix,
994 const bool &HasDupPostfix,
995 std::string &NormedProto) {
996 // Handle generic case.
997 const StringRef NameRef(Name);
998 for (size_t i = 0, end = Proto.size(); i < end; i++) {
999 switch (Proto[i]) {
1000 case 'u':
1001 case 'f':
1002 case 'd':
1003 case 's':
1004 case 'x':
1005 case 't':
1006 case 'n':
1007 NormedProto += IsQuad? 'q' : 'd';
1008 break;
1009 case 'w':
1010 case 'k':
1011 NormedProto += 'q';
1012 break;
1013 case 'g':
Jiangning Liu0aa1a882013-10-04 09:21:17 +00001014 case 'j':
Michael Gottesmanc327f872013-04-16 23:00:26 +00001015 case 'h':
1016 case 'e':
1017 NormedProto += 'd';
1018 break;
1019 case 'i':
1020 NormedProto += HasLanePostfix? 'a' : 'i';
1021 break;
1022 case 'a':
1023 if (HasLanePostfix) {
1024 NormedProto += 'a';
1025 } else if (HasNPostfixAndScalarArgs(NameRef, HasNPostfix)) {
1026 NormedProto += IsQuad? 'q' : 'd';
1027 } else {
1028 NormedProto += 'i';
1029 }
1030 break;
1031 }
1032 }
1033
1034 // Handle Special Cases.
1035 const bool IsNotVExt = !NameRef.count("vext");
1036 const bool IsVPADAL = NameRef.count("vpadal");
1037 const bool Is5OpLaneAccum = IsFiveOperandLaneAccumulator(NameRef,
1038 HasLanePostfix);
1039 const bool IsSpecialLaneMul = IsSpecialLaneMultiply(NameRef, HasLanePostfix,
1040 IsQuad);
1041
1042 if (IsSpecialLaneMul) {
1043 // If
1044 NormedProto[2] = NormedProto[3];
1045 NormedProto.erase(3);
1046 } else if (NormedProto.size() == 4 &&
1047 NormedProto[0] == NormedProto[1] &&
1048 IsNotVExt) {
1049 // If NormedProto.size() == 4 and the first two proto characters are the
1050 // same, ignore the first.
1051 NormedProto = NormedProto.substr(1, 3);
1052 } else if (Is5OpLaneAccum) {
1053 // If we have a 5 op lane accumulator operation, we take characters 1,2,4
1054 std::string tmp = NormedProto.substr(1,2);
1055 tmp += NormedProto[4];
1056 NormedProto = tmp;
1057 } else if (IsVPADAL) {
1058 // If we have VPADAL, ignore the first character.
1059 NormedProto = NormedProto.substr(0, 2);
1060 } else if (NameRef.count("vdup") && NormedProto.size() > 2) {
1061 // If our instruction is a dup instruction, keep only the first and
1062 // last characters.
1063 std::string tmp = "";
1064 tmp += NormedProto[0];
1065 tmp += NormedProto[NormedProto.size()-1];
1066 NormedProto = tmp;
1067 }
1068}
1069
1070/// GenerateRegisterCheckPatterns - Given a bunch of data we have
1071/// extracted, generate a FileCheck pattern to check that an
1072/// instruction's arguments are correct.
1073static void GenerateRegisterCheckPattern(const std::string &Name,
1074 const std::string &Proto,
1075 const std::string &OutTypeCode,
1076 const bool &HasNPostfix,
1077 const bool &IsQuad,
1078 const bool &HasLanePostfix,
1079 const bool &HasDupPostfix,
1080 const size_t &TBNumber,
1081 std::string &RegisterSuffix) {
1082
1083 RegisterSuffix = "";
1084
1085 const StringRef NameRef(Name);
1086 const StringRef ProtoRef(Proto);
1087
1088 if ((NameRef.count("vdup") || NameRef.count("vmov")) && HasNPostfix) {
1089 return;
1090 }
1091
1092 const bool IsLoadStore = NameRef.count("vld") || NameRef.count("vst");
1093 const bool IsTBXOrTBL = NameRef.count("vtbl") || NameRef.count("vtbx");
1094
1095 if (IsLoadStore) {
1096 // Grab N value from v{ld,st}N using its ascii representation.
1097 const size_t Count = NameRef[3] - 48;
1098
1099 GenerateRegisterCheckPatternForLoadStores(NameRef, OutTypeCode, IsQuad,
1100 HasDupPostfix, HasLanePostfix,
1101 Count, RegisterSuffix);
1102 } else if (IsTBXOrTBL) {
1103 RegisterSuffix += "d{{[0-9]+}}, {";
1104 for (size_t i = 0; i < TBNumber-1; i++) {
1105 RegisterSuffix += "d{{[0-9]+}}, ";
1106 }
1107 RegisterSuffix += "d{{[0-9]+}}}, d{{[0-9]+}}";
1108 } else {
1109 // Handle a normal instruction.
1110 if (NameRef.count("vget") || NameRef.count("vset"))
1111 return;
1112
1113 // We first normalize our proto, since we only need to emit 4
1114 // different types of checks, yet have more than 4 proto types
1115 // that map onto those 4 patterns.
1116 std::string NormalizedProto("");
1117 NormalizeProtoForRegisterPatternCreation(Name, Proto, HasNPostfix, IsQuad,
1118 HasLanePostfix, HasDupPostfix,
1119 NormalizedProto);
1120
1121 for (size_t i = 0, end = NormalizedProto.size(); i < end; i++) {
1122 const char &c = NormalizedProto[i];
1123 switch (c) {
1124 case 'q':
1125 RegisterSuffix += "q{{[0-9]+}}, ";
1126 break;
1127
1128 case 'd':
1129 RegisterSuffix += "d{{[0-9]+}}, ";
1130 break;
1131
1132 case 'i':
1133 RegisterSuffix += "#{{[0-9]+}}, ";
1134 break;
1135
1136 case 'a':
1137 RegisterSuffix += "d{{[0-9]+}}[{{[0-9]}}], ";
1138 break;
1139 }
1140 }
1141
1142 // Remove extra ", ".
1143 RegisterSuffix = RegisterSuffix.substr(0, RegisterSuffix.size()-2);
1144 }
1145}
1146
1147/// GenerateChecksForIntrinsic - Given a specific instruction name +
1148/// typestr + class kind, generate the proper set of FileCheck
1149/// Patterns to check for. We could just return a string, but instead
1150/// use a vector since it provides us with the extra flexibility of
1151/// emitting multiple checks, which comes in handy for certain cases
1152/// like mla where we want to check for 2 different instructions.
1153static void GenerateChecksForIntrinsic(const std::string &Name,
1154 const std::string &Proto,
1155 StringRef &OutTypeStr,
1156 StringRef &InTypeStr,
1157 ClassKind Ck,
1158 const std::string &InstName,
1159 bool IsHiddenLOp,
1160 std::vector<std::string>& Result) {
1161
1162 // If Ck is a ClassNoTest instruction, just return so no test is
1163 // emitted.
1164 if(Ck == ClassNoTest)
1165 return;
1166
1167 if (Name == "vcvt_f32_f16") {
1168 Result.push_back("vcvt.f32.f16");
1169 return;
1170 }
1171
1172
1173 // Now we preprocess our instruction given the data we have to get the
1174 // data that we need.
1175 // Create a StringRef for String Manipulation of our Name.
1176 const StringRef NameRef(Name);
1177 // Instruction Prefix.
1178 std::string Prefix;
1179 // The type code for our out type string.
1180 std::string OutTypeCode;
1181 // To handle our different cases, we need to check for different postfixes.
1182 // Is our instruction a quad instruction.
1183 bool IsQuad = false;
1184 // Our instruction is of the form <instructionname>_n.
1185 bool HasNPostfix = false;
1186 // Our instruction is of the form <instructionname>_lane.
1187 bool HasLanePostfix = false;
1188 // Our instruction is of the form <instructionname>_dup.
1189 bool HasDupPostfix = false;
1190 // Our instruction is a vcvt instruction which requires special handling.
1191 bool IsSpecialVCvt = false;
1192 // If we have a vtbxN or vtblN instruction, this is set to N.
1193 size_t TBNumber = -1;
1194 // Register Suffix
1195 std::string RegisterSuffix;
1196
1197 PreprocessInstruction(NameRef, InstName, Prefix,
1198 HasNPostfix, HasLanePostfix, HasDupPostfix,
1199 IsSpecialVCvt, TBNumber);
1200
1201 InstructionTypeCode(OutTypeStr, Ck, IsQuad, OutTypeCode);
1202 GenerateRegisterCheckPattern(Name, Proto, OutTypeCode, HasNPostfix, IsQuad,
1203 HasLanePostfix, HasDupPostfix, TBNumber,
1204 RegisterSuffix);
1205
1206 // In the following section, we handle a bunch of special cases. You can tell
1207 // a special case by the fact we are returning early.
1208
1209 // If our instruction is a logical instruction without postfix or a
1210 // hidden LOp just return the current Prefix.
1211 if (Ck == ClassL || IsHiddenLOp) {
1212 Result.push_back(Prefix + " " + RegisterSuffix);
1213 return;
1214 }
1215
1216 // If we have a vmov, due to the many different cases, some of which
1217 // vary within the different intrinsics generated for a single
1218 // instruction type, just output a vmov. (e.g. given an instruction
1219 // A, A.u32 might be vmov and A.u8 might be vmov.8).
1220 //
1221 // FIXME: Maybe something can be done about this. The two cases that we care
1222 // about are vmov as an LType and vmov as a WType.
1223 if (Prefix == "vmov") {
1224 Result.push_back(Prefix + " " + RegisterSuffix);
1225 return;
1226 }
1227
1228 // In the following section, we handle special cases.
1229
1230 if (OutTypeCode == "64") {
1231 // If we have a 64 bit vdup/vext and are handling an uint64x1_t
1232 // type, the intrinsic will be optimized away, so just return
1233 // nothing. On the other hand if we are handling an uint64x2_t
1234 // (i.e. quad instruction), vdup/vmov instructions should be
1235 // emitted.
1236 if (Prefix == "vdup" || Prefix == "vext") {
1237 if (IsQuad) {
1238 Result.push_back("{{vmov|vdup}}");
1239 }
1240 return;
1241 }
1242
1243 // v{st,ld}{2,3,4}_{u,s}64 emit v{st,ld}1.64 instructions with
1244 // multiple register operands.
1245 bool MultiLoadPrefix = Prefix == "vld2" || Prefix == "vld3"
1246 || Prefix == "vld4";
1247 bool MultiStorePrefix = Prefix == "vst2" || Prefix == "vst3"
1248 || Prefix == "vst4";
1249 if (MultiLoadPrefix || MultiStorePrefix) {
1250 Result.push_back(NameRef.slice(0, 3).str() + "1.64");
1251 return;
1252 }
1253
1254 // v{st,ld}1_{lane,dup}_{u64,s64} use vldr/vstr/vmov/str instead of
1255 // emitting said instructions. So return a check for
1256 // vldr/vstr/vmov/str instead.
1257 if (HasLanePostfix || HasDupPostfix) {
1258 if (Prefix == "vst1") {
1259 Result.push_back("{{str|vstr|vmov}}");
1260 return;
1261 } else if (Prefix == "vld1") {
1262 Result.push_back("{{ldr|vldr|vmov}}");
1263 return;
1264 }
1265 }
1266 }
1267
1268 // vzip.32/vuzp.32 are the same instruction as vtrn.32 and are
1269 // sometimes disassembled as vtrn.32. We use a regex to handle both
1270 // cases.
1271 if ((Prefix == "vzip" || Prefix == "vuzp") && OutTypeCode == "32") {
1272 Result.push_back("{{vtrn|" + Prefix + "}}.32 " + RegisterSuffix);
1273 return;
1274 }
1275
1276 // Currently on most ARM processors, we do not use vmla/vmls for
1277 // quad floating point operations. Instead we output vmul + vadd. So
1278 // check if we have one of those instructions and just output a
1279 // check for vmul.
1280 if (OutTypeCode == "f32") {
1281 if (Prefix == "vmls") {
1282 Result.push_back("vmul." + OutTypeCode + " " + RegisterSuffix);
1283 Result.push_back("vsub." + OutTypeCode);
1284 return;
1285 } else if (Prefix == "vmla") {
1286 Result.push_back("vmul." + OutTypeCode + " " + RegisterSuffix);
1287 Result.push_back("vadd." + OutTypeCode);
1288 return;
1289 }
1290 }
1291
1292 // If we have vcvt, get the input type from the instruction name
1293 // (which should be of the form instname_inputtype) and append it
1294 // before the output type.
1295 if (Prefix == "vcvt") {
1296 const std::string inTypeCode = NameRef.substr(NameRef.find_last_of("_")+1);
1297 Prefix += "." + inTypeCode;
1298 }
1299
1300 // Append output type code to get our final mangled instruction.
1301 Prefix += "." + OutTypeCode;
1302
1303 Result.push_back(Prefix + " " + RegisterSuffix);
1304}
1305
Peter Collingbourne51d77772011-10-06 13:03:08 +00001306/// UseMacro - Examine the prototype string to determine if the intrinsic
1307/// should be defined as a preprocessor macro instead of an inline function.
1308static bool UseMacro(const std::string &proto) {
1309 // If this builtin takes an immediate argument, we need to #define it rather
1310 // than use a standard declaration, so that SemaChecking can range check
1311 // the immediate passed by the user.
1312 if (proto.find('i') != std::string::npos)
1313 return true;
1314
1315 // Pointer arguments need to use macros to avoid hiding aligned attributes
1316 // from the pointer type.
1317 if (proto.find('p') != std::string::npos ||
1318 proto.find('c') != std::string::npos)
1319 return true;
1320
1321 return false;
1322}
1323
1324/// MacroArgUsedDirectly - Return true if argument i for an intrinsic that is
1325/// defined as a macro should be accessed directly instead of being first
1326/// assigned to a local temporary.
1327static bool MacroArgUsedDirectly(const std::string &proto, unsigned i) {
1328 // True for constant ints (i), pointers (p) and const pointers (c).
1329 return (proto[i] == 'i' || proto[i] == 'p' || proto[i] == 'c');
1330}
1331
1332// Generate the string "(argtype a, argtype b, ...)"
Kevin Qin2102a1d2013-10-11 02:34:30 +00001333static std::string GenArgs(const std::string &proto, StringRef typestr,
1334 const std::string &name) {
Peter Collingbourne51d77772011-10-06 13:03:08 +00001335 bool define = UseMacro(proto);
1336 char arg = 'a';
1337
1338 std::string s;
1339 s += "(";
1340
1341 for (unsigned i = 1, e = proto.size(); i != e; ++i, ++arg) {
1342 if (define) {
1343 // Some macro arguments are used directly instead of being assigned
1344 // to local temporaries; prepend an underscore prefix to make their
1345 // names consistent with the local temporaries.
1346 if (MacroArgUsedDirectly(proto, i))
1347 s += "__";
1348 } else {
1349 s += TypeString(proto[i], typestr) + " __";
1350 }
1351 s.push_back(arg);
Kevin Qin2102a1d2013-10-11 02:34:30 +00001352 //To avoid argument being multiple defined, add extra number for renaming.
1353 if (name == "vcopy_lane")
1354 s.push_back('1');
Peter Collingbourne51d77772011-10-06 13:03:08 +00001355 if ((i + 1) < e)
1356 s += ", ";
1357 }
1358
1359 s += ")";
1360 return s;
1361}
1362
1363// Macro arguments are not type-checked like inline function arguments, so
1364// assign them to local temporaries to get the right type checking.
Kevin Qin2102a1d2013-10-11 02:34:30 +00001365static std::string GenMacroLocals(const std::string &proto, StringRef typestr,
1366 const std::string &name ) {
Peter Collingbourne51d77772011-10-06 13:03:08 +00001367 char arg = 'a';
1368 std::string s;
1369 bool generatedLocal = false;
1370
1371 for (unsigned i = 1, e = proto.size(); i != e; ++i, ++arg) {
1372 // Do not create a temporary for an immediate argument.
1373 // That would defeat the whole point of using a macro!
Peter Collingbourne51d77772011-10-06 13:03:08 +00001374 if (MacroArgUsedDirectly(proto, i))
1375 continue;
1376 generatedLocal = true;
Kevin Qin2102a1d2013-10-11 02:34:30 +00001377 bool extranumber = false;
1378 if(name == "vcopy_lane")
1379 extranumber = true;
Peter Collingbourne51d77772011-10-06 13:03:08 +00001380
1381 s += TypeString(proto[i], typestr) + " __";
1382 s.push_back(arg);
Kevin Qin2102a1d2013-10-11 02:34:30 +00001383 if(extranumber)
1384 s.push_back('1');
Peter Collingbourne51d77772011-10-06 13:03:08 +00001385 s += " = (";
1386 s.push_back(arg);
Kevin Qin2102a1d2013-10-11 02:34:30 +00001387 if(extranumber)
1388 s.push_back('1');
Peter Collingbourne51d77772011-10-06 13:03:08 +00001389 s += "); ";
1390 }
1391
1392 if (generatedLocal)
1393 s += "\\\n ";
1394 return s;
1395}
1396
1397// Use the vmovl builtin to sign-extend or zero-extend a vector.
Jiangning Liu097a4b42013-09-09 02:21:08 +00001398static std::string Extend(StringRef typestr, const std::string &a, bool h=0) {
1399 std::string s, high;
1400 high = h ? "_high" : "";
1401 s = MangleName("vmovl" + high, typestr, ClassS);
Peter Collingbourne51d77772011-10-06 13:03:08 +00001402 s += "(" + a + ")";
1403 return s;
1404}
1405
Jiangning Liu097a4b42013-09-09 02:21:08 +00001406// Get the high 64-bit part of a vector
1407static std::string GetHigh(const std::string &a, StringRef typestr) {
1408 std::string s;
1409 s = MangleName("vget_high", typestr, ClassS);
1410 s += "(" + a + ")";
1411 return s;
1412}
1413
1414// Gen operation with two operands and get high 64-bit for both of two operands.
1415static std::string Gen2OpWith2High(StringRef typestr,
1416 const std::string &op,
1417 const std::string &a,
1418 const std::string &b) {
1419 std::string s;
1420 std::string Op1 = GetHigh(a, typestr);
1421 std::string Op2 = GetHigh(b, typestr);
1422 s = MangleName(op, typestr, ClassS);
1423 s += "(" + Op1 + ", " + Op2 + ");";
1424 return s;
1425}
1426
1427// Gen operation with three operands and get high 64-bit of the latter
1428// two operands.
1429static std::string Gen3OpWith2High(StringRef typestr,
1430 const std::string &op,
1431 const std::string &a,
1432 const std::string &b,
1433 const std::string &c) {
1434 std::string s;
1435 std::string Op1 = GetHigh(b, typestr);
1436 std::string Op2 = GetHigh(c, typestr);
1437 s = MangleName(op, typestr, ClassS);
1438 s += "(" + a + ", " + Op1 + ", " + Op2 + ");";
1439 return s;
1440}
1441
1442// Gen combine operation by putting a on low 64-bit, and b on high 64-bit.
1443static std::string GenCombine(std::string typestr,
1444 const std::string &a,
1445 const std::string &b) {
1446 std::string s;
1447 s = MangleName("vcombine", typestr, ClassS);
1448 s += "(" + a + ", " + b + ")";
1449 return s;
1450}
1451
Peter Collingbourne51d77772011-10-06 13:03:08 +00001452static std::string Duplicate(unsigned nElts, StringRef typestr,
1453 const std::string &a) {
1454 std::string s;
1455
1456 s = "(" + TypeString('d', typestr) + "){ ";
1457 for (unsigned i = 0; i != nElts; ++i) {
1458 s += a;
1459 if ((i + 1) < nElts)
1460 s += ", ";
1461 }
1462 s += " }";
1463
1464 return s;
1465}
1466
1467static std::string SplatLane(unsigned nElts, const std::string &vec,
1468 const std::string &lane) {
1469 std::string s = "__builtin_shufflevector(" + vec + ", " + vec;
1470 for (unsigned i = 0; i < nElts; ++i)
1471 s += ", " + lane;
1472 s += ")";
1473 return s;
1474}
1475
Hao Liu912502b2013-09-04 09:29:13 +00001476static std::string RemoveHigh(const std::string &name) {
1477 std::string s = name;
1478 std::size_t found = s.find("_high_");
1479 if (found == std::string::npos)
1480 PrintFatalError("name should contain \"_high_\" for high intrinsics");
1481 s.replace(found, 5, "");
1482 return s;
1483}
1484
Peter Collingbourne51d77772011-10-06 13:03:08 +00001485static unsigned GetNumElements(StringRef typestr, bool &quad) {
1486 quad = false;
1487 bool dummy = false;
1488 char type = ClassifyType(typestr, quad, dummy, dummy);
1489 unsigned nElts = 0;
1490 switch (type) {
1491 case 'c': nElts = 8; break;
1492 case 's': nElts = 4; break;
1493 case 'i': nElts = 2; break;
1494 case 'l': nElts = 1; break;
1495 case 'h': nElts = 4; break;
1496 case 'f': nElts = 2; break;
Tim Northoverb793f0d2013-08-01 09:23:19 +00001497 case 'd':
1498 nElts = 1;
1499 break;
Peter Collingbourne51d77772011-10-06 13:03:08 +00001500 default:
Joerg Sonnenberger38859ee2012-10-25 16:37:08 +00001501 PrintFatalError("unhandled type!");
Peter Collingbourne51d77772011-10-06 13:03:08 +00001502 }
1503 if (quad) nElts <<= 1;
1504 return nElts;
1505}
1506
1507// Generate the definition for this intrinsic, e.g. "a + b" for OpAdd.
Hao Liu912502b2013-09-04 09:29:13 +00001508static std::string GenOpString(const std::string &name, OpKind op,
1509 const std::string &proto, StringRef typestr) {
Peter Collingbourne51d77772011-10-06 13:03:08 +00001510 bool quad;
1511 unsigned nElts = GetNumElements(typestr, quad);
1512 bool define = UseMacro(proto);
1513
1514 std::string ts = TypeString(proto[0], typestr);
1515 std::string s;
1516 if (!define) {
1517 s = "return ";
1518 }
1519
1520 switch(op) {
1521 case OpAdd:
1522 s += "__a + __b;";
1523 break;
1524 case OpAddl:
1525 s += Extend(typestr, "__a") + " + " + Extend(typestr, "__b") + ";";
1526 break;
Jiangning Liu097a4b42013-09-09 02:21:08 +00001527 case OpAddlHi:
1528 s += Extend(typestr, "__a", 1) + " + " + Extend(typestr, "__b", 1) + ";";
1529 break;
Peter Collingbourne51d77772011-10-06 13:03:08 +00001530 case OpAddw:
1531 s += "__a + " + Extend(typestr, "__b") + ";";
1532 break;
Jiangning Liu097a4b42013-09-09 02:21:08 +00001533 case OpAddwHi:
1534 s += "__a + " + Extend(typestr, "__b", 1) + ";";
1535 break;
Peter Collingbourne51d77772011-10-06 13:03:08 +00001536 case OpSub:
1537 s += "__a - __b;";
1538 break;
1539 case OpSubl:
1540 s += Extend(typestr, "__a") + " - " + Extend(typestr, "__b") + ";";
1541 break;
Jiangning Liu097a4b42013-09-09 02:21:08 +00001542 case OpSublHi:
1543 s += Extend(typestr, "__a", 1) + " - " + Extend(typestr, "__b", 1) + ";";
1544 break;
Peter Collingbourne51d77772011-10-06 13:03:08 +00001545 case OpSubw:
1546 s += "__a - " + Extend(typestr, "__b") + ";";
1547 break;
Jiangning Liu097a4b42013-09-09 02:21:08 +00001548 case OpSubwHi:
1549 s += "__a - " + Extend(typestr, "__b", 1) + ";";
1550 break;
Peter Collingbourne51d77772011-10-06 13:03:08 +00001551 case OpMulN:
1552 s += "__a * " + Duplicate(nElts, typestr, "__b") + ";";
1553 break;
1554 case OpMulLane:
1555 s += "__a * " + SplatLane(nElts, "__b", "__c") + ";";
1556 break;
Jiangning Liu0aa1a882013-10-04 09:21:17 +00001557 case OpMulXLane:
1558 s += MangleName("vmulx", typestr, ClassS) + "(__a, " +
1559 SplatLane(nElts, "__b", "__c") + ");";
1560 break;
Peter Collingbourne51d77772011-10-06 13:03:08 +00001561 case OpMul:
1562 s += "__a * __b;";
1563 break;
1564 case OpMullLane:
1565 s += MangleName("vmull", typestr, ClassS) + "(__a, " +
1566 SplatLane(nElts, "__b", "__c") + ");";
1567 break;
Jiangning Liu0aa1a882013-10-04 09:21:17 +00001568 case OpMullHiLane:
1569 s += MangleName("vmull", typestr, ClassS) + "(" +
1570 GetHigh("__a", typestr) + ", " + SplatLane(nElts, "__b", "__c") + ");";
1571 break;
Peter Collingbourne51d77772011-10-06 13:03:08 +00001572 case OpMlaN:
1573 s += "__a + (__b * " + Duplicate(nElts, typestr, "__c") + ");";
1574 break;
1575 case OpMlaLane:
1576 s += "__a + (__b * " + SplatLane(nElts, "__c", "__d") + ");";
1577 break;
1578 case OpMla:
1579 s += "__a + (__b * __c);";
1580 break;
1581 case OpMlalN:
1582 s += "__a + " + MangleName("vmull", typestr, ClassS) + "(__b, " +
1583 Duplicate(nElts, typestr, "__c") + ");";
1584 break;
1585 case OpMlalLane:
1586 s += "__a + " + MangleName("vmull", typestr, ClassS) + "(__b, " +
1587 SplatLane(nElts, "__c", "__d") + ");";
1588 break;
Jiangning Liu0aa1a882013-10-04 09:21:17 +00001589 case OpMlalHiLane:
1590 s += "__a + " + MangleName("vmull", typestr, ClassS) + "(" +
1591 GetHigh("__b", typestr) + ", " + SplatLane(nElts, "__c", "__d") + ");";
1592 break;
Peter Collingbourne51d77772011-10-06 13:03:08 +00001593 case OpMlal:
1594 s += "__a + " + MangleName("vmull", typestr, ClassS) + "(__b, __c);";
1595 break;
Jiangning Liu097a4b42013-09-09 02:21:08 +00001596 case OpMullHi:
1597 s += Gen2OpWith2High(typestr, "vmull", "__a", "__b");
1598 break;
1599 case OpMlalHi:
1600 s += Gen3OpWith2High(typestr, "vmlal", "__a", "__b", "__c");
1601 break;
Peter Collingbourne51d77772011-10-06 13:03:08 +00001602 case OpMlsN:
1603 s += "__a - (__b * " + Duplicate(nElts, typestr, "__c") + ");";
1604 break;
1605 case OpMlsLane:
1606 s += "__a - (__b * " + SplatLane(nElts, "__c", "__d") + ");";
1607 break;
Jiangning Liu0aa1a882013-10-04 09:21:17 +00001608 case OpFMSLane:
1609 s += TypeString(proto[1], typestr) + " __a1 = __a; \\\n ";
1610 s += TypeString(proto[2], typestr) + " __b1 = __b; \\\n ";
1611 s += TypeString(proto[3], typestr) + " __c1 = __c; \\\n ";
1612 s += MangleName("vfma_lane", typestr, ClassS) + "(__a1, __b1, -__c1, __d);";
1613 break;
1614 case OpFMSLaneQ:
1615 s += TypeString(proto[1], typestr) + " __a1 = __a; \\\n ";
1616 s += TypeString(proto[2], typestr) + " __b1 = __b; \\\n ";
1617 s += TypeString(proto[3], typestr) + " __c1 = __c; \\\n ";
1618 s += MangleName("vfma_laneq", typestr, ClassS) + "(__a1, __b1, -__c1, __d);";
1619 break;
Peter Collingbourne51d77772011-10-06 13:03:08 +00001620 case OpMls:
1621 s += "__a - (__b * __c);";
1622 break;
1623 case OpMlslN:
1624 s += "__a - " + MangleName("vmull", typestr, ClassS) + "(__b, " +
1625 Duplicate(nElts, typestr, "__c") + ");";
1626 break;
1627 case OpMlslLane:
1628 s += "__a - " + MangleName("vmull", typestr, ClassS) + "(__b, " +
1629 SplatLane(nElts, "__c", "__d") + ");";
1630 break;
Jiangning Liu0aa1a882013-10-04 09:21:17 +00001631 case OpMlslHiLane:
1632 s += "__a - " + MangleName("vmull", typestr, ClassS) + "(" +
1633 GetHigh("__b", typestr) + ", " + SplatLane(nElts, "__c", "__d") + ");";
1634 break;
Peter Collingbourne51d77772011-10-06 13:03:08 +00001635 case OpMlsl:
1636 s += "__a - " + MangleName("vmull", typestr, ClassS) + "(__b, __c);";
1637 break;
Jiangning Liu097a4b42013-09-09 02:21:08 +00001638 case OpMlslHi:
1639 s += Gen3OpWith2High(typestr, "vmlsl", "__a", "__b", "__c");
1640 break;
Peter Collingbourne51d77772011-10-06 13:03:08 +00001641 case OpQDMullLane:
1642 s += MangleName("vqdmull", typestr, ClassS) + "(__a, " +
1643 SplatLane(nElts, "__b", "__c") + ");";
1644 break;
Jiangning Liu0aa1a882013-10-04 09:21:17 +00001645 case OpQDMullHiLane:
1646 s += MangleName("vqdmull", typestr, ClassS) + "(" +
1647 GetHigh("__a", typestr) + ", " + SplatLane(nElts, "__b", "__c") + ");";
1648 break;
Peter Collingbourne51d77772011-10-06 13:03:08 +00001649 case OpQDMlalLane:
1650 s += MangleName("vqdmlal", typestr, ClassS) + "(__a, __b, " +
1651 SplatLane(nElts, "__c", "__d") + ");";
1652 break;
Jiangning Liu0aa1a882013-10-04 09:21:17 +00001653 case OpQDMlalHiLane:
1654 s += MangleName("vqdmlal", typestr, ClassS) + "(__a, " +
1655 GetHigh("__b", typestr) + ", " + SplatLane(nElts, "__c", "__d") + ");";
1656 break;
Peter Collingbourne51d77772011-10-06 13:03:08 +00001657 case OpQDMlslLane:
1658 s += MangleName("vqdmlsl", typestr, ClassS) + "(__a, __b, " +
1659 SplatLane(nElts, "__c", "__d") + ");";
1660 break;
Jiangning Liu0aa1a882013-10-04 09:21:17 +00001661 case OpQDMlslHiLane:
1662 s += MangleName("vqdmlsl", typestr, ClassS) + "(__a, " +
1663 GetHigh("__b", typestr) + ", " + SplatLane(nElts, "__c", "__d") + ");";
1664 break;
Peter Collingbourne51d77772011-10-06 13:03:08 +00001665 case OpQDMulhLane:
1666 s += MangleName("vqdmulh", typestr, ClassS) + "(__a, " +
1667 SplatLane(nElts, "__b", "__c") + ");";
1668 break;
1669 case OpQRDMulhLane:
1670 s += MangleName("vqrdmulh", typestr, ClassS) + "(__a, " +
1671 SplatLane(nElts, "__b", "__c") + ");";
1672 break;
1673 case OpEq:
1674 s += "(" + ts + ")(__a == __b);";
1675 break;
1676 case OpGe:
1677 s += "(" + ts + ")(__a >= __b);";
1678 break;
1679 case OpLe:
1680 s += "(" + ts + ")(__a <= __b);";
1681 break;
1682 case OpGt:
1683 s += "(" + ts + ")(__a > __b);";
1684 break;
1685 case OpLt:
1686 s += "(" + ts + ")(__a < __b);";
1687 break;
1688 case OpNeg:
1689 s += " -__a;";
1690 break;
1691 case OpNot:
1692 s += " ~__a;";
1693 break;
1694 case OpAnd:
1695 s += "__a & __b;";
1696 break;
1697 case OpOr:
1698 s += "__a | __b;";
1699 break;
1700 case OpXor:
1701 s += "__a ^ __b;";
1702 break;
1703 case OpAndNot:
1704 s += "__a & ~__b;";
1705 break;
1706 case OpOrNot:
1707 s += "__a | ~__b;";
1708 break;
1709 case OpCast:
1710 s += "(" + ts + ")__a;";
1711 break;
1712 case OpConcat:
1713 s += "(" + ts + ")__builtin_shufflevector((int64x1_t)__a";
1714 s += ", (int64x1_t)__b, 0, 1);";
1715 break;
1716 case OpHi:
Jim Grosbachcd765392013-05-15 02:40:04 +00001717 // nElts is for the result vector, so the source is twice that number.
1718 s += "__builtin_shufflevector(__a, __a";
1719 for (unsigned i = nElts; i < nElts * 2; ++i)
1720 s += ", " + utostr(i);
1721 s+= ");";
Peter Collingbourne51d77772011-10-06 13:03:08 +00001722 break;
1723 case OpLo:
Jim Grosbachcd765392013-05-15 02:40:04 +00001724 s += "__builtin_shufflevector(__a, __a";
1725 for (unsigned i = 0; i < nElts; ++i)
1726 s += ", " + utostr(i);
1727 s+= ");";
Peter Collingbourne51d77772011-10-06 13:03:08 +00001728 break;
1729 case OpDup:
1730 s += Duplicate(nElts, typestr, "__a") + ";";
1731 break;
1732 case OpDupLane:
1733 s += SplatLane(nElts, "__a", "__b") + ";";
1734 break;
1735 case OpSelect:
1736 // ((0 & 1) | (~0 & 2))
1737 s += "(" + ts + ")";
1738 ts = TypeString(proto[1], typestr);
1739 s += "((__a & (" + ts + ")__b) | ";
1740 s += "(~__a & (" + ts + ")__c));";
1741 break;
1742 case OpRev16:
1743 s += "__builtin_shufflevector(__a, __a";
1744 for (unsigned i = 2; i <= nElts; i += 2)
1745 for (unsigned j = 0; j != 2; ++j)
1746 s += ", " + utostr(i - j - 1);
1747 s += ");";
1748 break;
1749 case OpRev32: {
1750 unsigned WordElts = nElts >> (1 + (int)quad);
1751 s += "__builtin_shufflevector(__a, __a";
1752 for (unsigned i = WordElts; i <= nElts; i += WordElts)
1753 for (unsigned j = 0; j != WordElts; ++j)
1754 s += ", " + utostr(i - j - 1);
1755 s += ");";
1756 break;
1757 }
1758 case OpRev64: {
1759 unsigned DblWordElts = nElts >> (int)quad;
1760 s += "__builtin_shufflevector(__a, __a";
1761 for (unsigned i = DblWordElts; i <= nElts; i += DblWordElts)
1762 for (unsigned j = 0; j != DblWordElts; ++j)
1763 s += ", " + utostr(i - j - 1);
1764 s += ");";
1765 break;
1766 }
1767 case OpAbdl: {
1768 std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)";
1769 if (typestr[0] != 'U') {
1770 // vabd results are always unsigned and must be zero-extended.
1771 std::string utype = "U" + typestr.str();
1772 s += "(" + TypeString(proto[0], typestr) + ")";
1773 abd = "(" + TypeString('d', utype) + ")" + abd;
1774 s += Extend(utype, abd) + ";";
1775 } else {
1776 s += Extend(typestr, abd) + ";";
1777 }
1778 break;
1779 }
Jiangning Liu097a4b42013-09-09 02:21:08 +00001780 case OpAbdlHi:
1781 s += Gen2OpWith2High(typestr, "vabdl", "__a", "__b");
1782 break;
1783 case OpAddhnHi: {
1784 std::string addhn = MangleName("vaddhn", typestr, ClassS) + "(__b, __c)";
1785 s += GenCombine(GetNarrowTypestr(typestr), "__a", addhn);
1786 s += ";";
1787 break;
1788 }
1789 case OpRAddhnHi: {
1790 std::string raddhn = MangleName("vraddhn", typestr, ClassS) + "(__b, __c)";
1791 s += GenCombine(GetNarrowTypestr(typestr), "__a", raddhn);
1792 s += ";";
1793 break;
1794 }
1795 case OpSubhnHi: {
1796 std::string subhn = MangleName("vsubhn", typestr, ClassS) + "(__b, __c)";
1797 s += GenCombine(GetNarrowTypestr(typestr), "__a", subhn);
1798 s += ";";
1799 break;
1800 }
1801 case OpRSubhnHi: {
1802 std::string rsubhn = MangleName("vrsubhn", typestr, ClassS) + "(__b, __c)";
1803 s += GenCombine(GetNarrowTypestr(typestr), "__a", rsubhn);
1804 s += ";";
1805 break;
1806 }
Peter Collingbourne51d77772011-10-06 13:03:08 +00001807 case OpAba:
1808 s += "__a + " + MangleName("vabd", typestr, ClassS) + "(__b, __c);";
1809 break;
Jiangning Liu097a4b42013-09-09 02:21:08 +00001810 case OpAbal:
1811 s += "__a + " + MangleName("vabdl", typestr, ClassS) + "(__b, __c);";
Peter Collingbourne51d77772011-10-06 13:03:08 +00001812 break;
Jiangning Liu097a4b42013-09-09 02:21:08 +00001813 case OpAbalHi:
1814 s += Gen3OpWith2High(typestr, "vabal", "__a", "__b", "__c");
1815 break;
1816 case OpQDMullHi:
1817 s += Gen2OpWith2High(typestr, "vqdmull", "__a", "__b");
1818 break;
1819 case OpQDMlalHi:
1820 s += Gen3OpWith2High(typestr, "vqdmlal", "__a", "__b", "__c");
1821 break;
1822 case OpQDMlslHi:
1823 s += Gen3OpWith2High(typestr, "vqdmlsl", "__a", "__b", "__c");
1824 break;
Tim Northoverb793f0d2013-08-01 09:23:19 +00001825 case OpDiv:
1826 s += "__a / __b;";
1827 break;
Hao Liu912502b2013-09-04 09:29:13 +00001828 case OpMovlHi: {
1829 s = TypeString(proto[1], typestr.drop_front()) + " __a1 = " +
1830 MangleName("vget_high", typestr, ClassS) + "(__a);\n " + s;
1831 s += "(" + ts + ")" + MangleName("vshll_n", typestr, ClassS);
1832 s += "(__a1, 0);";
1833 break;
1834 }
1835 case OpLongHi: {
1836 // Another local variable __a1 is needed for calling a Macro,
1837 // or using __a will have naming conflict when Macro expanding.
1838 s += TypeString(proto[1], typestr.drop_front()) + " __a1 = " +
1839 MangleName("vget_high", typestr, ClassS) + "(__a); \\\n";
1840 s += " (" + ts + ")" + MangleName(RemoveHigh(name), typestr, ClassS) +
1841 "(__a1, __b);";
1842 break;
1843 }
1844 case OpNarrowHi: {
1845 s += "(" + ts + ")" + MangleName("vcombine", typestr, ClassS) + "(__a, " +
1846 MangleName(RemoveHigh(name), typestr, ClassS) + "(__b, __c));";
1847 break;
1848 }
Kevin Qin2102a1d2013-10-11 02:34:30 +00001849 case OpCopy: {
1850 s += TypeString('s', typestr) + " __c2 = " +
1851 MangleName("vget_lane", typestr, ClassS) + "(__c1, __d1); \\\n " +
1852 MangleName("vset_lane", typestr, ClassS) + "(__c2, __a1, __b1);";
1853 break;
1854 }
Peter Collingbourne51d77772011-10-06 13:03:08 +00001855 default:
Joerg Sonnenberger38859ee2012-10-25 16:37:08 +00001856 PrintFatalError("unknown OpKind!");
Peter Collingbourne51d77772011-10-06 13:03:08 +00001857 }
1858 return s;
1859}
1860
1861static unsigned GetNeonEnum(const std::string &proto, StringRef typestr) {
1862 unsigned mod = proto[0];
Peter Collingbourne51d77772011-10-06 13:03:08 +00001863
1864 if (mod == 'v' || mod == 'f')
1865 mod = proto[1];
1866
1867 bool quad = false;
1868 bool poly = false;
1869 bool usgn = false;
1870 bool scal = false;
1871 bool cnst = false;
1872 bool pntr = false;
1873
1874 // Base type to get the type string for.
1875 char type = ClassifyType(typestr, quad, poly, usgn);
1876
1877 // Based on the modifying character, change the type and width if necessary.
1878 type = ModType(mod, type, quad, poly, usgn, scal, cnst, pntr);
1879
Bob Wilsonda95f732011-11-08 01:16:11 +00001880 NeonTypeFlags::EltType ET;
Peter Collingbourne51d77772011-10-06 13:03:08 +00001881 switch (type) {
1882 case 'c':
Bob Wilsonda95f732011-11-08 01:16:11 +00001883 ET = poly ? NeonTypeFlags::Poly8 : NeonTypeFlags::Int8;
Peter Collingbourne51d77772011-10-06 13:03:08 +00001884 break;
1885 case 's':
Bob Wilsonda95f732011-11-08 01:16:11 +00001886 ET = poly ? NeonTypeFlags::Poly16 : NeonTypeFlags::Int16;
Peter Collingbourne51d77772011-10-06 13:03:08 +00001887 break;
1888 case 'i':
Bob Wilsonda95f732011-11-08 01:16:11 +00001889 ET = NeonTypeFlags::Int32;
Peter Collingbourne51d77772011-10-06 13:03:08 +00001890 break;
1891 case 'l':
Bob Wilsonda95f732011-11-08 01:16:11 +00001892 ET = NeonTypeFlags::Int64;
Peter Collingbourne51d77772011-10-06 13:03:08 +00001893 break;
1894 case 'h':
Bob Wilsonda95f732011-11-08 01:16:11 +00001895 ET = NeonTypeFlags::Float16;
Peter Collingbourne51d77772011-10-06 13:03:08 +00001896 break;
1897 case 'f':
Bob Wilsonda95f732011-11-08 01:16:11 +00001898 ET = NeonTypeFlags::Float32;
Peter Collingbourne51d77772011-10-06 13:03:08 +00001899 break;
Tim Northoverb793f0d2013-08-01 09:23:19 +00001900 case 'd':
1901 ET = NeonTypeFlags::Float64;
1902 break;
Peter Collingbourne51d77772011-10-06 13:03:08 +00001903 default:
Joerg Sonnenberger38859ee2012-10-25 16:37:08 +00001904 PrintFatalError("unhandled type!");
Peter Collingbourne51d77772011-10-06 13:03:08 +00001905 }
Bob Wilsonda95f732011-11-08 01:16:11 +00001906 NeonTypeFlags Flags(ET, usgn, quad && proto[1] != 'g');
1907 return Flags.getFlags();
Peter Collingbourne51d77772011-10-06 13:03:08 +00001908}
1909
Jiangning Liu03916912013-10-05 08:22:55 +00001910static bool ProtoHasScalar(const std::string proto)
1911{
1912 return (proto.find('s') != std::string::npos
1913 || proto.find('r') != std::string::npos);
1914}
1915
Peter Collingbourne51d77772011-10-06 13:03:08 +00001916// Generate the definition for this intrinsic, e.g. __builtin_neon_cls(a)
1917static std::string GenBuiltin(const std::string &name, const std::string &proto,
1918 StringRef typestr, ClassKind ck) {
1919 std::string s;
1920
1921 // If this builtin returns a struct 2, 3, or 4 vectors, pass it as an implicit
1922 // sret-like argument.
1923 bool sret = (proto[0] >= '2' && proto[0] <= '4');
1924
1925 bool define = UseMacro(proto);
1926
1927 // Check if the prototype has a scalar operand with the type of the vector
1928 // elements. If not, bitcasting the args will take care of arg checking.
1929 // The actual signedness etc. will be taken care of with special enums.
Jiangning Liu03916912013-10-05 08:22:55 +00001930 if (!ProtoHasScalar(proto))
Peter Collingbourne51d77772011-10-06 13:03:08 +00001931 ck = ClassB;
1932
1933 if (proto[0] != 'v') {
1934 std::string ts = TypeString(proto[0], typestr);
1935
1936 if (define) {
1937 if (sret)
1938 s += ts + " r; ";
1939 else
1940 s += "(" + ts + ")";
1941 } else if (sret) {
1942 s += ts + " r; ";
1943 } else {
1944 s += "return (" + ts + ")";
1945 }
1946 }
1947
1948 bool splat = proto.find('a') != std::string::npos;
1949
1950 s += "__builtin_neon_";
1951 if (splat) {
1952 // Call the non-splat builtin: chop off the "_n" suffix from the name.
1953 std::string vname(name, 0, name.size()-2);
1954 s += MangleName(vname, typestr, ck);
1955 } else {
1956 s += MangleName(name, typestr, ck);
1957 }
1958 s += "(";
1959
1960 // Pass the address of the return variable as the first argument to sret-like
1961 // builtins.
1962 if (sret)
1963 s += "&r, ";
1964
1965 char arg = 'a';
1966 for (unsigned i = 1, e = proto.size(); i != e; ++i, ++arg) {
1967 std::string args = std::string(&arg, 1);
1968
1969 // Use the local temporaries instead of the macro arguments.
1970 args = "__" + args;
1971
1972 bool argQuad = false;
1973 bool argPoly = false;
1974 bool argUsgn = false;
1975 bool argScalar = false;
1976 bool dummy = false;
1977 char argType = ClassifyType(typestr, argQuad, argPoly, argUsgn);
1978 argType = ModType(proto[i], argType, argQuad, argPoly, argUsgn, argScalar,
1979 dummy, dummy);
1980
1981 // Handle multiple-vector values specially, emitting each subvector as an
1982 // argument to the __builtin.
1983 if (proto[i] >= '2' && proto[i] <= '4') {
1984 // Check if an explicit cast is needed.
1985 if (argType != 'c' || argPoly || argUsgn)
1986 args = (argQuad ? "(int8x16_t)" : "(int8x8_t)") + args;
1987
1988 for (unsigned vi = 0, ve = proto[i] - '0'; vi != ve; ++vi) {
1989 s += args + ".val[" + utostr(vi) + "]";
1990 if ((vi + 1) < ve)
1991 s += ", ";
1992 }
1993 if ((i + 1) < e)
1994 s += ", ";
1995
1996 continue;
1997 }
1998
1999 if (splat && (i + 1) == e)
2000 args = Duplicate(GetNumElements(typestr, argQuad), typestr, args);
2001
2002 // Check if an explicit cast is needed.
2003 if ((splat || !argScalar) &&
2004 ((ck == ClassB && argType != 'c') || argPoly || argUsgn)) {
2005 std::string argTypeStr = "c";
2006 if (ck != ClassB)
2007 argTypeStr = argType;
2008 if (argQuad)
2009 argTypeStr = "Q" + argTypeStr;
2010 args = "(" + TypeString('d', argTypeStr) + ")" + args;
2011 }
2012
2013 s += args;
2014 if ((i + 1) < e)
2015 s += ", ";
2016 }
2017
2018 // Extra constant integer to hold type class enum for this function, e.g. s8
2019 if (ck == ClassB)
2020 s += ", " + utostr(GetNeonEnum(proto, typestr));
2021
2022 s += ");";
2023
2024 if (proto[0] != 'v' && sret) {
2025 if (define)
2026 s += " r;";
2027 else
2028 s += " return r;";
2029 }
2030 return s;
2031}
2032
2033static std::string GenBuiltinDef(const std::string &name,
2034 const std::string &proto,
2035 StringRef typestr, ClassKind ck) {
2036 std::string s("BUILTIN(__builtin_neon_");
2037
2038 // If all types are the same size, bitcasting the args will take care
2039 // of arg checking. The actual signedness etc. will be taken care of with
2040 // special enums.
Jiangning Liu03916912013-10-05 08:22:55 +00002041 if (!ProtoHasScalar(proto))
Peter Collingbourne51d77772011-10-06 13:03:08 +00002042 ck = ClassB;
2043
2044 s += MangleName(name, typestr, ck);
2045 s += ", \"";
2046
2047 for (unsigned i = 0, e = proto.size(); i != e; ++i)
2048 s += BuiltinTypeString(proto[i], typestr, ck, i == 0);
2049
2050 // Extra constant integer to hold type class enum for this function, e.g. s8
2051 if (ck == ClassB)
2052 s += "i";
2053
2054 s += "\", \"n\")";
2055 return s;
2056}
2057
2058static std::string GenIntrinsic(const std::string &name,
2059 const std::string &proto,
2060 StringRef outTypeStr, StringRef inTypeStr,
2061 OpKind kind, ClassKind classKind) {
2062 assert(!proto.empty() && "");
Jim Grosbach667381b2012-05-09 18:17:30 +00002063 bool define = UseMacro(proto) && kind != OpUnavailable;
Peter Collingbourne51d77772011-10-06 13:03:08 +00002064 std::string s;
2065
2066 // static always inline + return type
2067 if (define)
2068 s += "#define ";
2069 else
2070 s += "__ai " + TypeString(proto[0], outTypeStr) + " ";
2071
2072 // Function name with type suffix
2073 std::string mangledName = MangleName(name, outTypeStr, ClassS);
2074 if (outTypeStr != inTypeStr) {
2075 // If the input type is different (e.g., for vreinterpret), append a suffix
2076 // for the input type. String off a "Q" (quad) prefix so that MangleName
2077 // does not insert another "q" in the name.
2078 unsigned typeStrOff = (inTypeStr[0] == 'Q' ? 1 : 0);
2079 StringRef inTypeNoQuad = inTypeStr.substr(typeStrOff);
2080 mangledName = MangleName(mangledName, inTypeNoQuad, ClassS);
2081 }
2082 s += mangledName;
2083
2084 // Function arguments
Kevin Qin2102a1d2013-10-11 02:34:30 +00002085 s += GenArgs(proto, inTypeStr, name);
Peter Collingbourne51d77772011-10-06 13:03:08 +00002086
2087 // Definition.
2088 if (define) {
2089 s += " __extension__ ({ \\\n ";
Kevin Qin2102a1d2013-10-11 02:34:30 +00002090 s += GenMacroLocals(proto, inTypeStr, name);
Jim Grosbach667381b2012-05-09 18:17:30 +00002091 } else if (kind == OpUnavailable) {
2092 s += " __attribute__((unavailable));\n";
2093 return s;
2094 } else
Jim Grosbach66981c72012-08-03 17:30:46 +00002095 s += " {\n ";
Peter Collingbourne51d77772011-10-06 13:03:08 +00002096
2097 if (kind != OpNone)
Hao Liu912502b2013-09-04 09:29:13 +00002098 s += GenOpString(name, kind, proto, outTypeStr);
Peter Collingbourne51d77772011-10-06 13:03:08 +00002099 else
2100 s += GenBuiltin(name, proto, outTypeStr, classKind);
2101 if (define)
2102 s += " })";
2103 else
2104 s += " }";
2105 s += "\n";
2106 return s;
2107}
2108
2109/// run - Read the records in arm_neon.td and output arm_neon.h. arm_neon.h
2110/// is comprised of type definitions and function declarations.
2111void NeonEmitter::run(raw_ostream &OS) {
2112 OS <<
2113 "/*===---- arm_neon.h - ARM Neon intrinsics ------------------------------"
2114 "---===\n"
2115 " *\n"
2116 " * Permission is hereby granted, free of charge, to any person obtaining "
2117 "a copy\n"
2118 " * of this software and associated documentation files (the \"Software\"),"
2119 " to deal\n"
2120 " * in the Software without restriction, including without limitation the "
2121 "rights\n"
2122 " * to use, copy, modify, merge, publish, distribute, sublicense, "
2123 "and/or sell\n"
2124 " * copies of the Software, and to permit persons to whom the Software is\n"
2125 " * furnished to do so, subject to the following conditions:\n"
2126 " *\n"
2127 " * The above copyright notice and this permission notice shall be "
2128 "included in\n"
2129 " * all copies or substantial portions of the Software.\n"
2130 " *\n"
2131 " * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, "
2132 "EXPRESS OR\n"
2133 " * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF "
2134 "MERCHANTABILITY,\n"
2135 " * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT "
2136 "SHALL THE\n"
2137 " * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR "
2138 "OTHER\n"
2139 " * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, "
2140 "ARISING FROM,\n"
2141 " * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER "
2142 "DEALINGS IN\n"
2143 " * THE SOFTWARE.\n"
2144 " *\n"
2145 " *===--------------------------------------------------------------------"
2146 "---===\n"
2147 " */\n\n";
2148
2149 OS << "#ifndef __ARM_NEON_H\n";
2150 OS << "#define __ARM_NEON_H\n\n";
2151
Tim Northoverb793f0d2013-08-01 09:23:19 +00002152 OS << "#if !defined(__ARM_NEON__) && !defined(__AARCH_FEATURE_ADVSIMD)\n";
Peter Collingbourne51d77772011-10-06 13:03:08 +00002153 OS << "#error \"NEON support not enabled\"\n";
2154 OS << "#endif\n\n";
2155
2156 OS << "#include <stdint.h>\n\n";
2157
2158 // Emit NEON-specific scalar typedefs.
2159 OS << "typedef float float32_t;\n";
Tim Northoverb793f0d2013-08-01 09:23:19 +00002160 OS << "typedef __fp16 float16_t;\n";
2161
2162 OS << "#ifdef __aarch64__\n";
2163 OS << "typedef double float64_t;\n";
2164 OS << "#endif\n\n";
2165
2166 // For now, signedness of polynomial types depends on target
2167 OS << "#ifdef __aarch64__\n";
2168 OS << "typedef uint8_t poly8_t;\n";
2169 OS << "typedef uint16_t poly16_t;\n";
2170 OS << "#else\n";
Peter Collingbourne51d77772011-10-06 13:03:08 +00002171 OS << "typedef int8_t poly8_t;\n";
2172 OS << "typedef int16_t poly16_t;\n";
Tim Northoverb793f0d2013-08-01 09:23:19 +00002173 OS << "#endif\n";
Peter Collingbourne51d77772011-10-06 13:03:08 +00002174
2175 // Emit Neon vector typedefs.
Tim Northoverb793f0d2013-08-01 09:23:19 +00002176 std::string TypedefTypes(
Jiangning Liu0aa1a882013-10-04 09:21:17 +00002177 "cQcsQsiQilQlUcQUcUsQUsUiQUiUlQUlhQhfQfdQdPcQPcPsQPs");
Peter Collingbourne51d77772011-10-06 13:03:08 +00002178 SmallVector<StringRef, 24> TDTypeVec;
2179 ParseTypes(0, TypedefTypes, TDTypeVec);
2180
2181 // Emit vector typedefs.
Jiangning Liu0aa1a882013-10-04 09:21:17 +00002182 bool isA64 = false;
Peter Collingbourne51d77772011-10-06 13:03:08 +00002183 for (unsigned i = 0, e = TDTypeVec.size(); i != e; ++i) {
2184 bool dummy, quad = false, poly = false;
Tim Northoverb793f0d2013-08-01 09:23:19 +00002185 char type = ClassifyType(TDTypeVec[i], quad, poly, dummy);
Jiangning Liu0aa1a882013-10-04 09:21:17 +00002186 bool preinsert = false;
2187 bool postinsert = false;
Tim Northoverb793f0d2013-08-01 09:23:19 +00002188
Jiangning Liu0aa1a882013-10-04 09:21:17 +00002189 if (type == 'd') {
2190 preinsert = isA64? false: true;
Tim Northoverb793f0d2013-08-01 09:23:19 +00002191 isA64 = true;
Jiangning Liu0aa1a882013-10-04 09:21:17 +00002192 } else {
2193 postinsert = isA64? true: false;
2194 isA64 = false;
2195 }
2196 if (postinsert)
2197 OS << "#endif\n";
2198 if (preinsert)
Tim Northoverb793f0d2013-08-01 09:23:19 +00002199 OS << "#ifdef __aarch64__\n";
2200
Peter Collingbourne51d77772011-10-06 13:03:08 +00002201 if (poly)
2202 OS << "typedef __attribute__((neon_polyvector_type(";
2203 else
2204 OS << "typedef __attribute__((neon_vector_type(";
2205
2206 unsigned nElts = GetNumElements(TDTypeVec[i], quad);
2207 OS << utostr(nElts) << "))) ";
2208 if (nElts < 10)
2209 OS << " ";
2210
2211 OS << TypeString('s', TDTypeVec[i]);
2212 OS << " " << TypeString('d', TDTypeVec[i]) << ";\n";
Tim Northoverb793f0d2013-08-01 09:23:19 +00002213
Peter Collingbourne51d77772011-10-06 13:03:08 +00002214 }
2215 OS << "\n";
2216
2217 // Emit struct typedefs.
Jiangning Liu0aa1a882013-10-04 09:21:17 +00002218 isA64 = false;
Peter Collingbourne51d77772011-10-06 13:03:08 +00002219 for (unsigned vi = 2; vi != 5; ++vi) {
2220 for (unsigned i = 0, e = TDTypeVec.size(); i != e; ++i) {
Tim Northoverb793f0d2013-08-01 09:23:19 +00002221 bool dummy, quad = false, poly = false;
2222 char type = ClassifyType(TDTypeVec[i], quad, poly, dummy);
Jiangning Liu0aa1a882013-10-04 09:21:17 +00002223 bool preinsert = false;
2224 bool postinsert = false;
Tim Northoverb793f0d2013-08-01 09:23:19 +00002225
Jiangning Liu0aa1a882013-10-04 09:21:17 +00002226 if (type == 'd') {
2227 preinsert = isA64? false: true;
Tim Northoverb793f0d2013-08-01 09:23:19 +00002228 isA64 = true;
Jiangning Liu0aa1a882013-10-04 09:21:17 +00002229 } else {
2230 postinsert = isA64? true: false;
2231 isA64 = false;
2232 }
2233 if (postinsert)
2234 OS << "#endif\n";
2235 if (preinsert)
Tim Northoverb793f0d2013-08-01 09:23:19 +00002236 OS << "#ifdef __aarch64__\n";
2237
Peter Collingbourne51d77772011-10-06 13:03:08 +00002238 std::string ts = TypeString('d', TDTypeVec[i]);
2239 std::string vs = TypeString('0' + vi, TDTypeVec[i]);
2240 OS << "typedef struct " << vs << " {\n";
2241 OS << " " << ts << " val";
2242 OS << "[" << utostr(vi) << "]";
2243 OS << ";\n} ";
Tim Northoverb793f0d2013-08-01 09:23:19 +00002244 OS << vs << ";\n";
Tim Northoverb793f0d2013-08-01 09:23:19 +00002245 OS << "\n";
Peter Collingbourne51d77772011-10-06 13:03:08 +00002246 }
2247 }
2248
Bob Wilson1e8058f2013-04-12 20:17:20 +00002249 OS<<"#define __ai static inline __attribute__((__always_inline__, __nodebug__))\n\n";
Peter Collingbourne51d77772011-10-06 13:03:08 +00002250
2251 std::vector<Record*> RV = Records.getAllDerivedDefinitions("Inst");
2252
Tim Northoverb793f0d2013-08-01 09:23:19 +00002253 StringMap<ClassKind> EmittedMap;
2254
Peter Collingbourne51d77772011-10-06 13:03:08 +00002255 // Emit vmovl, vmull and vabd intrinsics first so they can be used by other
2256 // intrinsics. (Some of the saturating multiply instructions are also
2257 // used to implement the corresponding "_lane" variants, but tablegen
2258 // sorts the records into alphabetical order so that the "_lane" variants
2259 // come after the intrinsics they use.)
Tim Northoverb793f0d2013-08-01 09:23:19 +00002260 emitIntrinsic(OS, Records.getDef("VMOVL"), EmittedMap);
2261 emitIntrinsic(OS, Records.getDef("VMULL"), EmittedMap);
2262 emitIntrinsic(OS, Records.getDef("VABD"), EmittedMap);
Jiangning Liu097a4b42013-09-09 02:21:08 +00002263 emitIntrinsic(OS, Records.getDef("VABDL"), EmittedMap);
Tim Northoverb793f0d2013-08-01 09:23:19 +00002264
2265 // ARM intrinsics must be emitted before AArch64 intrinsics to ensure
2266 // common intrinsics appear only once in the output stream.
2267 // The check for uniquiness is done in emitIntrinsic.
2268 // Emit ARM intrinsics.
2269 for (unsigned i = 0, e = RV.size(); i != e; ++i) {
2270 Record *R = RV[i];
2271
2272 // Skip AArch64 intrinsics; they will be emitted at the end.
2273 bool isA64 = R->getValueAsBit("isA64");
2274 if (isA64)
2275 continue;
2276
2277 if (R->getName() != "VMOVL" && R->getName() != "VMULL" &&
2278 R->getName() != "VABD")
2279 emitIntrinsic(OS, R, EmittedMap);
2280 }
2281
2282 // Emit AArch64-specific intrinsics.
2283 OS << "#ifdef __aarch64__\n";
Peter Collingbourne51d77772011-10-06 13:03:08 +00002284
Jiangning Liu097a4b42013-09-09 02:21:08 +00002285 emitIntrinsic(OS, Records.getDef("VMOVL_HIGH"), EmittedMap);
2286 emitIntrinsic(OS, Records.getDef("VMULL_HIGH"), EmittedMap);
2287 emitIntrinsic(OS, Records.getDef("VABDL_HIGH"), EmittedMap);
2288
Peter Collingbourne51d77772011-10-06 13:03:08 +00002289 for (unsigned i = 0, e = RV.size(); i != e; ++i) {
2290 Record *R = RV[i];
Tim Northoverb793f0d2013-08-01 09:23:19 +00002291
2292 // Skip ARM intrinsics already included above.
2293 bool isA64 = R->getValueAsBit("isA64");
2294 if (!isA64)
2295 continue;
2296
2297 emitIntrinsic(OS, R, EmittedMap);
Peter Collingbourne51d77772011-10-06 13:03:08 +00002298 }
2299
Tim Northoverb793f0d2013-08-01 09:23:19 +00002300 OS << "#endif\n\n";
2301
Peter Collingbourne51d77772011-10-06 13:03:08 +00002302 OS << "#undef __ai\n\n";
2303 OS << "#endif /* __ARM_NEON_H */\n";
2304}
2305
2306/// emitIntrinsic - Write out the arm_neon.h header file definitions for the
Tim Northoverb793f0d2013-08-01 09:23:19 +00002307/// intrinsics specified by record R checking for intrinsic uniqueness.
2308void NeonEmitter::emitIntrinsic(raw_ostream &OS, Record *R,
2309 StringMap<ClassKind> &EmittedMap) {
Peter Collingbourne51d77772011-10-06 13:03:08 +00002310 std::string name = R->getValueAsString("Name");
2311 std::string Proto = R->getValueAsString("Prototype");
2312 std::string Types = R->getValueAsString("Types");
2313
2314 SmallVector<StringRef, 16> TypeVec;
2315 ParseTypes(R, Types, TypeVec);
2316
2317 OpKind kind = OpMap[R->getValueAsDef("Operand")->getName()];
2318
2319 ClassKind classKind = ClassNone;
2320 if (R->getSuperClasses().size() >= 2)
2321 classKind = ClassMap[R->getSuperClasses()[1]];
2322 if (classKind == ClassNone && kind == OpNone)
Joerg Sonnenberger38859ee2012-10-25 16:37:08 +00002323 PrintFatalError(R->getLoc(), "Builtin has no class kind");
Peter Collingbourne51d77772011-10-06 13:03:08 +00002324
2325 for (unsigned ti = 0, te = TypeVec.size(); ti != te; ++ti) {
2326 if (kind == OpReinterpret) {
2327 bool outQuad = false;
2328 bool dummy = false;
2329 (void)ClassifyType(TypeVec[ti], outQuad, dummy, dummy);
2330 for (unsigned srcti = 0, srcte = TypeVec.size();
2331 srcti != srcte; ++srcti) {
2332 bool inQuad = false;
2333 (void)ClassifyType(TypeVec[srcti], inQuad, dummy, dummy);
2334 if (srcti == ti || inQuad != outQuad)
2335 continue;
Tim Northoverb793f0d2013-08-01 09:23:19 +00002336 std::string s = GenIntrinsic(name, Proto, TypeVec[ti], TypeVec[srcti],
2337 OpCast, ClassS);
2338 if (EmittedMap.count(s))
2339 continue;
2340 EmittedMap[s] = ClassS;
2341 OS << s;
Peter Collingbourne51d77772011-10-06 13:03:08 +00002342 }
2343 } else {
Tim Northoverb793f0d2013-08-01 09:23:19 +00002344 std::string s =
2345 GenIntrinsic(name, Proto, TypeVec[ti], TypeVec[ti], kind, classKind);
2346 if (EmittedMap.count(s))
2347 continue;
2348 EmittedMap[s] = classKind;
2349 OS << s;
Peter Collingbourne51d77772011-10-06 13:03:08 +00002350 }
2351 }
2352 OS << "\n";
2353}
2354
2355static unsigned RangeFromType(const char mod, StringRef typestr) {
2356 // base type to get the type string for.
2357 bool quad = false, dummy = false;
2358 char type = ClassifyType(typestr, quad, dummy, dummy);
2359 type = ModType(mod, type, quad, dummy, dummy, dummy, dummy, dummy);
2360
2361 switch (type) {
2362 case 'c':
2363 return (8 << (int)quad) - 1;
2364 case 'h':
2365 case 's':
2366 return (4 << (int)quad) - 1;
2367 case 'f':
2368 case 'i':
2369 return (2 << (int)quad) - 1;
Jiangning Liu0aa1a882013-10-04 09:21:17 +00002370 case 'd':
Peter Collingbourne51d77772011-10-06 13:03:08 +00002371 case 'l':
2372 return (1 << (int)quad) - 1;
2373 default:
Joerg Sonnenberger38859ee2012-10-25 16:37:08 +00002374 PrintFatalError("unhandled type!");
Peter Collingbourne51d77772011-10-06 13:03:08 +00002375 }
Peter Collingbourne51d77772011-10-06 13:03:08 +00002376}
2377
Tim Northoverb793f0d2013-08-01 09:23:19 +00002378/// Generate the ARM and AArch64 intrinsic range checking code for
2379/// shift/lane immediates, checking for unique declarations.
2380void
2381NeonEmitter::genIntrinsicRangeCheckCode(raw_ostream &OS,
2382 StringMap<ClassKind> &A64IntrinsicMap,
2383 bool isA64RangeCheck) {
2384 std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst");
Peter Collingbourne51d77772011-10-06 13:03:08 +00002385 StringMap<OpKind> EmittedMap;
2386
Tim Northoverb793f0d2013-08-01 09:23:19 +00002387 // Generate the intrinsic range checking code for shift/lane immediates.
2388 if (isA64RangeCheck)
2389 OS << "#ifdef GET_NEON_AARCH64_IMMEDIATE_CHECK\n";
2390 else
2391 OS << "#ifdef GET_NEON_IMMEDIATE_CHECK\n";
2392
Peter Collingbourne51d77772011-10-06 13:03:08 +00002393 for (unsigned i = 0, e = RV.size(); i != e; ++i) {
2394 Record *R = RV[i];
Tim Northoverb793f0d2013-08-01 09:23:19 +00002395
Peter Collingbourne51d77772011-10-06 13:03:08 +00002396 OpKind k = OpMap[R->getValueAsDef("Operand")->getName()];
2397 if (k != OpNone)
2398 continue;
2399
Tim Northoverb793f0d2013-08-01 09:23:19 +00002400 std::string name = R->getValueAsString("Name");
Peter Collingbourne51d77772011-10-06 13:03:08 +00002401 std::string Proto = R->getValueAsString("Prototype");
Tim Northoverb793f0d2013-08-01 09:23:19 +00002402 std::string Types = R->getValueAsString("Types");
Kevin Qin944f09f2013-08-29 07:55:15 +00002403 std::string Rename = name + "@" + Proto;
Peter Collingbourne51d77772011-10-06 13:03:08 +00002404
2405 // Functions with 'a' (the splat code) in the type prototype should not get
2406 // their own builtin as they use the non-splat variant.
2407 if (Proto.find('a') != std::string::npos)
2408 continue;
2409
Tim Northoverb793f0d2013-08-01 09:23:19 +00002410 // Functions which do not have an immediate do not need to have range
2411 // checking code emitted.
2412 size_t immPos = Proto.find('i');
2413 if (immPos == std::string::npos)
2414 continue;
2415
Peter Collingbourne51d77772011-10-06 13:03:08 +00002416 SmallVector<StringRef, 16> TypeVec;
2417 ParseTypes(R, Types, TypeVec);
2418
2419 if (R->getSuperClasses().size() < 2)
Joerg Sonnenberger38859ee2012-10-25 16:37:08 +00002420 PrintFatalError(R->getLoc(), "Builtin has no class kind");
Peter Collingbourne51d77772011-10-06 13:03:08 +00002421
Peter Collingbourne51d77772011-10-06 13:03:08 +00002422 ClassKind ck = ClassMap[R->getSuperClasses()[1]];
2423
Tim Northoverb793f0d2013-08-01 09:23:19 +00002424 // Do not include AArch64 range checks if not generating code for AArch64.
2425 bool isA64 = R->getValueAsBit("isA64");
2426 if (!isA64RangeCheck && isA64)
2427 continue;
Peter Collingbourne51d77772011-10-06 13:03:08 +00002428
Tim Northoverb793f0d2013-08-01 09:23:19 +00002429 // Include ARM range checks in AArch64 but only if ARM intrinsics are not
2430 // redefined by AArch64 to handle new types.
Kevin Qin944f09f2013-08-29 07:55:15 +00002431 if (isA64RangeCheck && !isA64 && A64IntrinsicMap.count(Rename)) {
2432 ClassKind &A64CK = A64IntrinsicMap[Rename];
Tim Northoverb793f0d2013-08-01 09:23:19 +00002433 if (A64CK == ck && ck != ClassNone)
2434 continue;
2435 }
2436
2437 for (unsigned ti = 0, te = TypeVec.size(); ti != te; ++ti) {
2438 std::string namestr, shiftstr, rangestr;
2439
2440 if (R->getValueAsBit("isVCVT_N")) {
2441 // VCVT between floating- and fixed-point values takes an immediate
Hao Liu912502b2013-09-04 09:29:13 +00002442 // in the range [1, 32] for f32, or [1, 64] for f64.
Tim Northoverb793f0d2013-08-01 09:23:19 +00002443 ck = ClassB;
Hao Liu912502b2013-09-04 09:29:13 +00002444 if (name.find("32") != std::string::npos)
2445 rangestr = "l = 1; u = 31"; // upper bound = l + u
2446 else if (name.find("64") != std::string::npos)
2447 rangestr = "l = 1; u = 63";
2448 else
2449 PrintFatalError(R->getLoc(),
2450 "Fixed point convert name should contains \"32\" or \"64\"");
Jiangning Liu03916912013-10-05 08:22:55 +00002451 } else if (!ProtoHasScalar(Proto)) {
Tim Northoverb793f0d2013-08-01 09:23:19 +00002452 // Builtins which are overloaded by type will need to have their upper
2453 // bound computed at Sema time based on the type constant.
2454 ck = ClassB;
2455 if (R->getValueAsBit("isShift")) {
2456 shiftstr = ", true";
2457
2458 // Right shifts have an 'r' in the name, left shifts do not.
2459 if (name.find('r') != std::string::npos)
2460 rangestr = "l = 1; ";
2461 }
2462 rangestr += "u = RFT(TV" + shiftstr + ")";
2463 } else {
2464 // The immediate generally refers to a lane in the preceding argument.
2465 assert(immPos > 0 && "unexpected immediate operand");
2466 rangestr =
2467 "u = " + utostr(RangeFromType(Proto[immPos - 1], TypeVec[ti]));
2468 }
2469 // Make sure cases appear only once by uniquing them in a string map.
2470 namestr = MangleName(name, TypeVec[ti], ck);
2471 if (EmittedMap.count(namestr))
2472 continue;
2473 EmittedMap[namestr] = OpNone;
2474
2475 // Calculate the index of the immediate that should be range checked.
2476 unsigned immidx = 0;
2477
2478 // Builtins that return a struct of multiple vectors have an extra
2479 // leading arg for the struct return.
2480 if (Proto[0] >= '2' && Proto[0] <= '4')
2481 ++immidx;
2482
2483 // Add one to the index for each argument until we reach the immediate
2484 // to be checked. Structs of vectors are passed as multiple arguments.
2485 for (unsigned ii = 1, ie = Proto.size(); ii != ie; ++ii) {
2486 switch (Proto[ii]) {
2487 default:
2488 immidx += 1;
2489 break;
2490 case '2':
2491 immidx += 2;
2492 break;
2493 case '3':
2494 immidx += 3;
2495 break;
2496 case '4':
2497 immidx += 4;
2498 break;
2499 case 'i':
2500 ie = ii + 1;
2501 break;
2502 }
2503 }
2504 if (isA64RangeCheck)
2505 OS << "case AArch64::BI__builtin_neon_";
2506 else
2507 OS << "case ARM::BI__builtin_neon_";
2508 OS << MangleName(name, TypeVec[ti], ck) << ": i = " << immidx << "; "
2509 << rangestr << "; break;\n";
Peter Collingbourne51d77772011-10-06 13:03:08 +00002510 }
2511 }
2512 OS << "#endif\n\n";
Tim Northoverb793f0d2013-08-01 09:23:19 +00002513}
2514
2515/// Generate the ARM and AArch64 overloaded type checking code for
2516/// SemaChecking.cpp, checking for unique builtin declarations.
2517void
2518NeonEmitter::genOverloadTypeCheckCode(raw_ostream &OS,
2519 StringMap<ClassKind> &A64IntrinsicMap,
2520 bool isA64TypeCheck) {
2521 std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst");
2522 StringMap<OpKind> EmittedMap;
Peter Collingbourne51d77772011-10-06 13:03:08 +00002523
2524 // Generate the overloaded type checking code for SemaChecking.cpp
Tim Northoverb793f0d2013-08-01 09:23:19 +00002525 if (isA64TypeCheck)
2526 OS << "#ifdef GET_NEON_AARCH64_OVERLOAD_CHECK\n";
2527 else
2528 OS << "#ifdef GET_NEON_OVERLOAD_CHECK\n";
2529
Peter Collingbourne51d77772011-10-06 13:03:08 +00002530 for (unsigned i = 0, e = RV.size(); i != e; ++i) {
2531 Record *R = RV[i];
2532 OpKind k = OpMap[R->getValueAsDef("Operand")->getName()];
2533 if (k != OpNone)
2534 continue;
2535
2536 std::string Proto = R->getValueAsString("Prototype");
2537 std::string Types = R->getValueAsString("Types");
2538 std::string name = R->getValueAsString("Name");
Kevin Qin944f09f2013-08-29 07:55:15 +00002539 std::string Rename = name + "@" + Proto;
2540
Peter Collingbourne51d77772011-10-06 13:03:08 +00002541 // Functions with 'a' (the splat code) in the type prototype should not get
2542 // their own builtin as they use the non-splat variant.
2543 if (Proto.find('a') != std::string::npos)
2544 continue;
2545
2546 // Functions which have a scalar argument cannot be overloaded, no need to
2547 // check them if we are emitting the type checking code.
Jiangning Liu03916912013-10-05 08:22:55 +00002548 if (ProtoHasScalar(Proto))
Peter Collingbourne51d77772011-10-06 13:03:08 +00002549 continue;
2550
2551 SmallVector<StringRef, 16> TypeVec;
2552 ParseTypes(R, Types, TypeVec);
2553
2554 if (R->getSuperClasses().size() < 2)
Joerg Sonnenberger38859ee2012-10-25 16:37:08 +00002555 PrintFatalError(R->getLoc(), "Builtin has no class kind");
Peter Collingbourne51d77772011-10-06 13:03:08 +00002556
Tim Northoverb793f0d2013-08-01 09:23:19 +00002557 // Do not include AArch64 type checks if not generating code for AArch64.
2558 bool isA64 = R->getValueAsBit("isA64");
2559 if (!isA64TypeCheck && isA64)
2560 continue;
2561
2562 // Include ARM type check in AArch64 but only if ARM intrinsics
2563 // are not redefined in AArch64 to handle new types, e.g. "vabd" is a SIntr
2564 // redefined in AArch64 to handle an additional 2 x f64 type.
2565 ClassKind ck = ClassMap[R->getSuperClasses()[1]];
Kevin Qin944f09f2013-08-29 07:55:15 +00002566 if (isA64TypeCheck && !isA64 && A64IntrinsicMap.count(Rename)) {
2567 ClassKind &A64CK = A64IntrinsicMap[Rename];
Tim Northoverb793f0d2013-08-01 09:23:19 +00002568 if (A64CK == ck && ck != ClassNone)
2569 continue;
2570 }
2571
Peter Collingbourne51d77772011-10-06 13:03:08 +00002572 int si = -1, qi = -1;
Richard Smithf8ee6bc2012-08-14 01:28:02 +00002573 uint64_t mask = 0, qmask = 0;
Peter Collingbourne51d77772011-10-06 13:03:08 +00002574 for (unsigned ti = 0, te = TypeVec.size(); ti != te; ++ti) {
2575 // Generate the switch case(s) for this builtin for the type validation.
2576 bool quad = false, poly = false, usgn = false;
2577 (void) ClassifyType(TypeVec[ti], quad, poly, usgn);
2578
2579 if (quad) {
2580 qi = ti;
Richard Smithf8ee6bc2012-08-14 01:28:02 +00002581 qmask |= 1ULL << GetNeonEnum(Proto, TypeVec[ti]);
Peter Collingbourne51d77772011-10-06 13:03:08 +00002582 } else {
2583 si = ti;
Richard Smithf8ee6bc2012-08-14 01:28:02 +00002584 mask |= 1ULL << GetNeonEnum(Proto, TypeVec[ti]);
Peter Collingbourne51d77772011-10-06 13:03:08 +00002585 }
2586 }
Bob Wilson46482552011-11-16 21:32:23 +00002587
2588 // Check if the builtin function has a pointer or const pointer argument.
2589 int PtrArgNum = -1;
2590 bool HasConstPtr = false;
2591 for (unsigned arg = 1, arge = Proto.size(); arg != arge; ++arg) {
2592 char ArgType = Proto[arg];
2593 if (ArgType == 'c') {
2594 HasConstPtr = true;
2595 PtrArgNum = arg - 1;
2596 break;
2597 }
2598 if (ArgType == 'p') {
2599 PtrArgNum = arg - 1;
2600 break;
2601 }
2602 }
2603 // For sret builtins, adjust the pointer argument index.
2604 if (PtrArgNum >= 0 && (Proto[0] >= '2' && Proto[0] <= '4'))
2605 PtrArgNum += 1;
2606
Bob Wilson9082cdd2011-12-20 06:16:48 +00002607 // Omit type checking for the pointer arguments of vld1_lane, vld1_dup,
2608 // and vst1_lane intrinsics. Using a pointer to the vector element
2609 // type with one of those operations causes codegen to select an aligned
2610 // load/store instruction. If you want an unaligned operation,
2611 // the pointer argument needs to have less alignment than element type,
2612 // so just accept any pointer type.
2613 if (name == "vld1_lane" || name == "vld1_dup" || name == "vst1_lane") {
2614 PtrArgNum = -1;
2615 HasConstPtr = false;
2616 }
2617
Bob Wilson6f9f03e2011-11-08 05:04:11 +00002618 if (mask) {
Tim Northoverb793f0d2013-08-01 09:23:19 +00002619 if (isA64TypeCheck)
2620 OS << "case AArch64::BI__builtin_neon_";
2621 else
2622 OS << "case ARM::BI__builtin_neon_";
2623 OS << MangleName(name, TypeVec[si], ClassB) << ": mask = "
2624 << "0x" << utohexstr(mask) << "ULL";
Bob Wilson46482552011-11-16 21:32:23 +00002625 if (PtrArgNum >= 0)
2626 OS << "; PtrArgNum = " << PtrArgNum;
Bob Wilson6f9f03e2011-11-08 05:04:11 +00002627 if (HasConstPtr)
2628 OS << "; HasConstPtr = true";
2629 OS << "; break;\n";
2630 }
2631 if (qmask) {
Tim Northoverb793f0d2013-08-01 09:23:19 +00002632 if (isA64TypeCheck)
2633 OS << "case AArch64::BI__builtin_neon_";
2634 else
2635 OS << "case ARM::BI__builtin_neon_";
2636 OS << MangleName(name, TypeVec[qi], ClassB) << ": mask = "
2637 << "0x" << utohexstr(qmask) << "ULL";
Bob Wilson46482552011-11-16 21:32:23 +00002638 if (PtrArgNum >= 0)
2639 OS << "; PtrArgNum = " << PtrArgNum;
Bob Wilson6f9f03e2011-11-08 05:04:11 +00002640 if (HasConstPtr)
2641 OS << "; HasConstPtr = true";
2642 OS << "; break;\n";
2643 }
Peter Collingbourne51d77772011-10-06 13:03:08 +00002644 }
2645 OS << "#endif\n\n";
Tim Northoverb793f0d2013-08-01 09:23:19 +00002646}
Peter Collingbourne51d77772011-10-06 13:03:08 +00002647
Tim Northoverb793f0d2013-08-01 09:23:19 +00002648/// genBuiltinsDef: Generate the BuiltinsARM.def and BuiltinsAArch64.def
2649/// declaration of builtins, checking for unique builtin declarations.
2650void NeonEmitter::genBuiltinsDef(raw_ostream &OS,
2651 StringMap<ClassKind> &A64IntrinsicMap,
2652 bool isA64GenBuiltinDef) {
2653 std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst");
2654 StringMap<OpKind> EmittedMap;
2655
2656 // Generate BuiltinsARM.def and BuiltinsAArch64.def
2657 if (isA64GenBuiltinDef)
2658 OS << "#ifdef GET_NEON_AARCH64_BUILTINS\n";
2659 else
2660 OS << "#ifdef GET_NEON_BUILTINS\n";
2661
Peter Collingbourne51d77772011-10-06 13:03:08 +00002662 for (unsigned i = 0, e = RV.size(); i != e; ++i) {
2663 Record *R = RV[i];
Peter Collingbourne51d77772011-10-06 13:03:08 +00002664 OpKind k = OpMap[R->getValueAsDef("Operand")->getName()];
2665 if (k != OpNone)
2666 continue;
2667
Peter Collingbourne51d77772011-10-06 13:03:08 +00002668 std::string Proto = R->getValueAsString("Prototype");
Tim Northoverb793f0d2013-08-01 09:23:19 +00002669 std::string name = R->getValueAsString("Name");
Kevin Qin944f09f2013-08-29 07:55:15 +00002670 std::string Rename = name + "@" + Proto;
Peter Collingbourne51d77772011-10-06 13:03:08 +00002671
2672 // Functions with 'a' (the splat code) in the type prototype should not get
2673 // their own builtin as they use the non-splat variant.
2674 if (Proto.find('a') != std::string::npos)
2675 continue;
2676
Tim Northoverb793f0d2013-08-01 09:23:19 +00002677 std::string Types = R->getValueAsString("Types");
Peter Collingbourne51d77772011-10-06 13:03:08 +00002678 SmallVector<StringRef, 16> TypeVec;
2679 ParseTypes(R, Types, TypeVec);
2680
2681 if (R->getSuperClasses().size() < 2)
Joerg Sonnenberger38859ee2012-10-25 16:37:08 +00002682 PrintFatalError(R->getLoc(), "Builtin has no class kind");
Peter Collingbourne51d77772011-10-06 13:03:08 +00002683
2684 ClassKind ck = ClassMap[R->getSuperClasses()[1]];
2685
Tim Northoverb793f0d2013-08-01 09:23:19 +00002686 // Do not include AArch64 BUILTIN() macros if not generating
2687 // code for AArch64
2688 bool isA64 = R->getValueAsBit("isA64");
2689 if (!isA64GenBuiltinDef && isA64)
2690 continue;
Peter Collingbourne51d77772011-10-06 13:03:08 +00002691
Tim Northoverb793f0d2013-08-01 09:23:19 +00002692 // Include ARM BUILTIN() macros in AArch64 but only if ARM intrinsics
2693 // are not redefined in AArch64 to handle new types, e.g. "vabd" is a SIntr
2694 // redefined in AArch64 to handle an additional 2 x f64 type.
Kevin Qin944f09f2013-08-29 07:55:15 +00002695 if (isA64GenBuiltinDef && !isA64 && A64IntrinsicMap.count(Rename)) {
2696 ClassKind &A64CK = A64IntrinsicMap[Rename];
Tim Northoverb793f0d2013-08-01 09:23:19 +00002697 if (A64CK == ck && ck != ClassNone)
Peter Collingbourne51d77772011-10-06 13:03:08 +00002698 continue;
Tim Northoverb793f0d2013-08-01 09:23:19 +00002699 }
Peter Collingbourne51d77772011-10-06 13:03:08 +00002700
Tim Northoverb793f0d2013-08-01 09:23:19 +00002701 for (unsigned ti = 0, te = TypeVec.size(); ti != te; ++ti) {
2702 // Generate the declaration for this builtin, ensuring
2703 // that each unique BUILTIN() macro appears only once in the output
2704 // stream.
2705 std::string bd = GenBuiltinDef(name, Proto, TypeVec[ti], ck);
2706 if (EmittedMap.count(bd))
2707 continue;
Peter Collingbourne51d77772011-10-06 13:03:08 +00002708
Tim Northoverb793f0d2013-08-01 09:23:19 +00002709 EmittedMap[bd] = OpNone;
2710 OS << bd << "\n";
Peter Collingbourne51d77772011-10-06 13:03:08 +00002711 }
2712 }
2713 OS << "#endif\n\n";
2714}
2715
Tim Northoverb793f0d2013-08-01 09:23:19 +00002716/// runHeader - Emit a file with sections defining:
2717/// 1. the NEON section of BuiltinsARM.def and BuiltinsAArch64.def.
2718/// 2. the SemaChecking code for the type overload checking.
2719/// 3. the SemaChecking code for validation of intrinsic immediate arguments.
2720void NeonEmitter::runHeader(raw_ostream &OS) {
2721 std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst");
2722
2723 // build a map of AArch64 intriniscs to be used in uniqueness checks.
2724 StringMap<ClassKind> A64IntrinsicMap;
2725 for (unsigned i = 0, e = RV.size(); i != e; ++i) {
2726 Record *R = RV[i];
2727
2728 bool isA64 = R->getValueAsBit("isA64");
2729 if (!isA64)
2730 continue;
2731
2732 ClassKind CK = ClassNone;
2733 if (R->getSuperClasses().size() >= 2)
2734 CK = ClassMap[R->getSuperClasses()[1]];
2735
2736 std::string Name = R->getValueAsString("Name");
Kevin Qin944f09f2013-08-29 07:55:15 +00002737 std::string Proto = R->getValueAsString("Prototype");
2738 std::string Rename = Name + "@" + Proto;
2739 if (A64IntrinsicMap.count(Rename))
Tim Northoverb793f0d2013-08-01 09:23:19 +00002740 continue;
Kevin Qin944f09f2013-08-29 07:55:15 +00002741 A64IntrinsicMap[Rename] = CK;
Tim Northoverb793f0d2013-08-01 09:23:19 +00002742 }
2743
2744 // Generate BuiltinsARM.def for ARM
2745 genBuiltinsDef(OS, A64IntrinsicMap, false);
2746
2747 // Generate BuiltinsAArch64.def for AArch64
2748 genBuiltinsDef(OS, A64IntrinsicMap, true);
2749
2750 // Generate ARM overloaded type checking code for SemaChecking.cpp
2751 genOverloadTypeCheckCode(OS, A64IntrinsicMap, false);
2752
2753 // Generate AArch64 overloaded type checking code for SemaChecking.cpp
2754 genOverloadTypeCheckCode(OS, A64IntrinsicMap, true);
2755
2756 // Generate ARM range checking code for shift/lane immediates.
2757 genIntrinsicRangeCheckCode(OS, A64IntrinsicMap, false);
2758
2759 // Generate the AArch64 range checking code for shift/lane immediates.
2760 genIntrinsicRangeCheckCode(OS, A64IntrinsicMap, true);
2761}
2762
Peter Collingbourne51d77772011-10-06 13:03:08 +00002763/// GenTest - Write out a test for the intrinsic specified by the name and
2764/// type strings, including the embedded patterns for FileCheck to match.
2765static std::string GenTest(const std::string &name,
2766 const std::string &proto,
2767 StringRef outTypeStr, StringRef inTypeStr,
Michael Gottesman7200bd62013-04-16 22:48:52 +00002768 bool isShift, bool isHiddenLOp,
Tim Northoverb793f0d2013-08-01 09:23:19 +00002769 ClassKind ck, const std::string &InstName,
2770 bool isA64,
2771 std::string & testFuncProto) {
Peter Collingbourne51d77772011-10-06 13:03:08 +00002772 assert(!proto.empty() && "");
2773 std::string s;
2774
2775 // Function name with type suffix
2776 std::string mangledName = MangleName(name, outTypeStr, ClassS);
2777 if (outTypeStr != inTypeStr) {
2778 // If the input type is different (e.g., for vreinterpret), append a suffix
2779 // for the input type. String off a "Q" (quad) prefix so that MangleName
2780 // does not insert another "q" in the name.
2781 unsigned typeStrOff = (inTypeStr[0] == 'Q' ? 1 : 0);
2782 StringRef inTypeNoQuad = inTypeStr.substr(typeStrOff);
2783 mangledName = MangleName(mangledName, inTypeNoQuad, ClassS);
2784 }
2785
Tim Northoverb793f0d2013-08-01 09:23:19 +00002786 // todo: GenerateChecksForIntrinsic does not generate CHECK
2787 // for aarch64 instructions yet
Michael Gottesmanc327f872013-04-16 23:00:26 +00002788 std::vector<std::string> FileCheckPatterns;
Tim Northoverb793f0d2013-08-01 09:23:19 +00002789 if (!isA64) {
2790 GenerateChecksForIntrinsic(name, proto, outTypeStr, inTypeStr, ck, InstName,
2791 isHiddenLOp, FileCheckPatterns);
2792 s+= "// CHECK_ARM: test_" + mangledName + "\n";
2793 }
2794 s += "// CHECK_AARCH64: test_" + mangledName + "\n";
Michael Gottesmanc327f872013-04-16 23:00:26 +00002795
Peter Collingbourne51d77772011-10-06 13:03:08 +00002796 // Emit the FileCheck patterns.
Michael Gottesmanc327f872013-04-16 23:00:26 +00002797 // If for any reason we do not want to emit a check, mangledInst
2798 // will be the empty string.
2799 if (FileCheckPatterns.size()) {
2800 for (std::vector<std::string>::const_iterator i = FileCheckPatterns.begin(),
2801 e = FileCheckPatterns.end();
2802 i != e;
2803 ++i) {
Tim Northoverb793f0d2013-08-01 09:23:19 +00002804 s += "// CHECK_ARM: " + *i + "\n";
Michael Gottesmanc327f872013-04-16 23:00:26 +00002805 }
2806 }
Peter Collingbourne51d77772011-10-06 13:03:08 +00002807
2808 // Emit the start of the test function.
Tim Northoverb793f0d2013-08-01 09:23:19 +00002809
2810 testFuncProto = TypeString(proto[0], outTypeStr) + " test_" + mangledName + "(";
Peter Collingbourne51d77772011-10-06 13:03:08 +00002811 char arg = 'a';
2812 std::string comma;
2813 for (unsigned i = 1, e = proto.size(); i != e; ++i, ++arg) {
2814 // Do not create arguments for values that must be immediate constants.
2815 if (proto[i] == 'i')
2816 continue;
Tim Northoverb793f0d2013-08-01 09:23:19 +00002817 testFuncProto += comma + TypeString(proto[i], inTypeStr) + " ";
2818 testFuncProto.push_back(arg);
Peter Collingbourne51d77772011-10-06 13:03:08 +00002819 comma = ", ";
2820 }
Tim Northoverb793f0d2013-08-01 09:23:19 +00002821 testFuncProto += ")";
2822
2823 s+= testFuncProto;
2824 s+= " {\n ";
Peter Collingbourne51d77772011-10-06 13:03:08 +00002825
2826 if (proto[0] != 'v')
2827 s += "return ";
2828 s += mangledName + "(";
2829 arg = 'a';
2830 for (unsigned i = 1, e = proto.size(); i != e; ++i, ++arg) {
2831 if (proto[i] == 'i') {
2832 // For immediate operands, test the maximum value.
2833 if (isShift)
2834 s += "1"; // FIXME
2835 else
2836 // The immediate generally refers to a lane in the preceding argument.
2837 s += utostr(RangeFromType(proto[i-1], inTypeStr));
2838 } else {
2839 s.push_back(arg);
2840 }
2841 if ((i + 1) < e)
2842 s += ", ";
2843 }
2844 s += ");\n}\n\n";
2845 return s;
2846}
2847
Tim Northoverb793f0d2013-08-01 09:23:19 +00002848/// Write out all intrinsic tests for the specified target, checking
2849/// for intrinsic test uniqueness.
2850void NeonEmitter::genTargetTest(raw_ostream &OS, StringMap<OpKind> &EmittedMap,
2851 bool isA64GenTest) {
2852 if (isA64GenTest)
2853 OS << "#ifdef __aarch64__\n";
Peter Collingbourne51d77772011-10-06 13:03:08 +00002854
Tim Northoverb793f0d2013-08-01 09:23:19 +00002855 std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst");
Peter Collingbourne51d77772011-10-06 13:03:08 +00002856 for (unsigned i = 0, e = RV.size(); i != e; ++i) {
2857 Record *R = RV[i];
2858 std::string name = R->getValueAsString("Name");
2859 std::string Proto = R->getValueAsString("Prototype");
2860 std::string Types = R->getValueAsString("Types");
2861 bool isShift = R->getValueAsBit("isShift");
Michael Gottesman7200bd62013-04-16 22:48:52 +00002862 std::string InstName = R->getValueAsString("InstName");
2863 bool isHiddenLOp = R->getValueAsBit("isHiddenLInst");
Tim Northoverb793f0d2013-08-01 09:23:19 +00002864 bool isA64 = R->getValueAsBit("isA64");
2865
2866 // do not include AArch64 intrinsic test if not generating
2867 // code for AArch64
2868 if (!isA64GenTest && isA64)
2869 continue;
Peter Collingbourne51d77772011-10-06 13:03:08 +00002870
2871 SmallVector<StringRef, 16> TypeVec;
2872 ParseTypes(R, Types, TypeVec);
2873
Michael Gottesman7200bd62013-04-16 22:48:52 +00002874 ClassKind ck = ClassMap[R->getSuperClasses()[1]];
Peter Collingbourne51d77772011-10-06 13:03:08 +00002875 OpKind kind = OpMap[R->getValueAsDef("Operand")->getName()];
Jim Grosbach667381b2012-05-09 18:17:30 +00002876 if (kind == OpUnavailable)
2877 continue;
Peter Collingbourne51d77772011-10-06 13:03:08 +00002878 for (unsigned ti = 0, te = TypeVec.size(); ti != te; ++ti) {
2879 if (kind == OpReinterpret) {
2880 bool outQuad = false;
2881 bool dummy = false;
2882 (void)ClassifyType(TypeVec[ti], outQuad, dummy, dummy);
2883 for (unsigned srcti = 0, srcte = TypeVec.size();
2884 srcti != srcte; ++srcti) {
2885 bool inQuad = false;
2886 (void)ClassifyType(TypeVec[srcti], inQuad, dummy, dummy);
2887 if (srcti == ti || inQuad != outQuad)
2888 continue;
Tim Northoverb793f0d2013-08-01 09:23:19 +00002889 std::string testFuncProto;
2890 std::string s = GenTest(name, Proto, TypeVec[ti], TypeVec[srcti],
2891 isShift, isHiddenLOp, ck, InstName, isA64,
2892 testFuncProto);
2893 if (EmittedMap.count(testFuncProto))
2894 continue;
2895 EmittedMap[testFuncProto] = kind;
2896 OS << s << "\n";
Peter Collingbourne51d77772011-10-06 13:03:08 +00002897 }
2898 } else {
Tim Northoverb793f0d2013-08-01 09:23:19 +00002899 std::string testFuncProto;
2900 std::string s = GenTest(name, Proto, TypeVec[ti], TypeVec[ti], isShift,
2901 isHiddenLOp, ck, InstName, isA64, testFuncProto);
2902 if (EmittedMap.count(testFuncProto))
2903 continue;
2904 EmittedMap[testFuncProto] = kind;
2905 OS << s << "\n";
Peter Collingbourne51d77772011-10-06 13:03:08 +00002906 }
2907 }
Peter Collingbourne51d77772011-10-06 13:03:08 +00002908 }
Tim Northoverb793f0d2013-08-01 09:23:19 +00002909
2910 if (isA64GenTest)
2911 OS << "#endif\n";
2912}
2913/// runTests - Write out a complete set of tests for all of the Neon
2914/// intrinsics.
2915void NeonEmitter::runTests(raw_ostream &OS) {
2916 OS << "// RUN: %clang_cc1 -triple thumbv7s-apple-darwin -target-abi "
2917 "apcs-gnu\\\n"
2918 "// RUN: -target-cpu swift -ffreestanding -Os -S -o - %s\\\n"
2919 "// RUN: | FileCheck %s -check-prefix=CHECK_ARM\n"
2920 "\n"
2921 "// RUN: %clang_cc1 -triple aarch64-none-linux-gnu \\\n"
2922 "// RUN -target-feature +neon -ffreestanding -S -o - %s \\\n"
2923 "// RUN: | FileCheck %s -check-prefix=CHECK_AARCH64\n"
2924 "\n"
2925 "// REQUIRES: long_tests\n"
2926 "\n"
2927 "#include <arm_neon.h>\n"
2928 "\n";
2929
2930 // ARM tests must be emitted before AArch64 tests to ensure
2931 // tests for intrinsics that are common to ARM and AArch64
2932 // appear only once in the output stream.
2933 // The check for uniqueness is done in genTargetTest.
2934 StringMap<OpKind> EmittedMap;
2935
2936 genTargetTest(OS, EmittedMap, false);
2937
2938 genTargetTest(OS, EmittedMap, true);
Peter Collingbourne51d77772011-10-06 13:03:08 +00002939}
2940
Jakob Stoklund Olesen3cc509b2012-06-13 05:12:41 +00002941namespace clang {
2942void EmitNeon(RecordKeeper &Records, raw_ostream &OS) {
2943 NeonEmitter(Records).run(OS);
2944}
2945void EmitNeonSema(RecordKeeper &Records, raw_ostream &OS) {
2946 NeonEmitter(Records).runHeader(OS);
2947}
2948void EmitNeonTest(RecordKeeper &Records, raw_ostream &OS) {
2949 NeonEmitter(Records).runTests(OS);
2950}
2951} // End namespace clang