blob: 9dc2d56f6c97414dca054a7b0d14d89a51549072 [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,
122 OpMovlHi
Jakob Stoklund Olesen3cc509b2012-06-13 05:12:41 +0000123};
124
125enum ClassKind {
126 ClassNone,
127 ClassI, // generic integer instruction, e.g., "i8" suffix
128 ClassS, // signed/unsigned/poly, e.g., "s8", "u8" or "p8" suffix
129 ClassW, // width-specific instruction, e.g., "8" suffix
Michael Gottesman21e4e942013-04-16 21:18:42 +0000130 ClassB, // bitcast arguments with enum argument to specify type
131 ClassL, // Logical instructions which are op instructions
132 // but we need to not emit any suffix for in our
133 // tests.
134 ClassNoTest // Instructions which we do not test since they are
135 // not TRUE instructions.
Jakob Stoklund Olesen3cc509b2012-06-13 05:12:41 +0000136};
137
138/// NeonTypeFlags - Flags to identify the types for overloaded Neon
139/// builtins. These must be kept in sync with the flags in
140/// include/clang/Basic/TargetBuiltins.h.
141namespace {
142class NeonTypeFlags {
143 enum {
144 EltTypeMask = 0xf,
145 UnsignedFlag = 0x10,
146 QuadFlag = 0x20
147 };
148 uint32_t Flags;
149
150public:
151 enum EltType {
152 Int8,
153 Int16,
154 Int32,
155 Int64,
156 Poly8,
157 Poly16,
158 Float16,
Tim Northoverb793f0d2013-08-01 09:23:19 +0000159 Float32,
160 Float64
Jakob Stoklund Olesen3cc509b2012-06-13 05:12:41 +0000161 };
162
163 NeonTypeFlags(unsigned F) : Flags(F) {}
164 NeonTypeFlags(EltType ET, bool IsUnsigned, bool IsQuad) : Flags(ET) {
165 if (IsUnsigned)
166 Flags |= UnsignedFlag;
167 if (IsQuad)
168 Flags |= QuadFlag;
169 }
170
171 uint32_t getFlags() const { return Flags; }
172};
173} // end anonymous namespace
174
175namespace {
176class NeonEmitter {
177 RecordKeeper &Records;
178 StringMap<OpKind> OpMap;
179 DenseMap<Record*, ClassKind> ClassMap;
180
181public:
182 NeonEmitter(RecordKeeper &R) : Records(R) {
183 OpMap["OP_NONE"] = OpNone;
184 OpMap["OP_UNAVAILABLE"] = OpUnavailable;
185 OpMap["OP_ADD"] = OpAdd;
186 OpMap["OP_ADDL"] = OpAddl;
Jiangning Liu097a4b42013-09-09 02:21:08 +0000187 OpMap["OP_ADDLHi"] = OpAddlHi;
Jakob Stoklund Olesen3cc509b2012-06-13 05:12:41 +0000188 OpMap["OP_ADDW"] = OpAddw;
Jiangning Liu097a4b42013-09-09 02:21:08 +0000189 OpMap["OP_ADDWHi"] = OpAddwHi;
Jakob Stoklund Olesen3cc509b2012-06-13 05:12:41 +0000190 OpMap["OP_SUB"] = OpSub;
191 OpMap["OP_SUBL"] = OpSubl;
Jiangning Liu097a4b42013-09-09 02:21:08 +0000192 OpMap["OP_SUBLHi"] = OpSublHi;
Jakob Stoklund Olesen3cc509b2012-06-13 05:12:41 +0000193 OpMap["OP_SUBW"] = OpSubw;
Jiangning Liu097a4b42013-09-09 02:21:08 +0000194 OpMap["OP_SUBWHi"] = OpSubwHi;
Jakob Stoklund Olesen3cc509b2012-06-13 05:12:41 +0000195 OpMap["OP_MUL"] = OpMul;
196 OpMap["OP_MLA"] = OpMla;
197 OpMap["OP_MLAL"] = OpMlal;
Jiangning Liu097a4b42013-09-09 02:21:08 +0000198 OpMap["OP_MULLHi"] = OpMullHi;
199 OpMap["OP_MLALHi"] = OpMlalHi;
Jakob Stoklund Olesen3cc509b2012-06-13 05:12:41 +0000200 OpMap["OP_MLS"] = OpMls;
201 OpMap["OP_MLSL"] = OpMlsl;
Jiangning Liu097a4b42013-09-09 02:21:08 +0000202 OpMap["OP_MLSLHi"] = OpMlslHi;
Jakob Stoklund Olesen3cc509b2012-06-13 05:12:41 +0000203 OpMap["OP_MUL_N"] = OpMulN;
204 OpMap["OP_MLA_N"] = OpMlaN;
205 OpMap["OP_MLS_N"] = OpMlsN;
206 OpMap["OP_MLAL_N"] = OpMlalN;
207 OpMap["OP_MLSL_N"] = OpMlslN;
208 OpMap["OP_MUL_LN"]= OpMulLane;
Jiangning Liu0aa1a882013-10-04 09:21:17 +0000209 OpMap["OP_MULX_LN"]= OpMulXLane;
Jakob Stoklund Olesen3cc509b2012-06-13 05:12:41 +0000210 OpMap["OP_MULL_LN"] = OpMullLane;
Jiangning Liu0aa1a882013-10-04 09:21:17 +0000211 OpMap["OP_MULLHi_LN"] = OpMullHiLane;
Jakob Stoklund Olesen3cc509b2012-06-13 05:12:41 +0000212 OpMap["OP_MLA_LN"]= OpMlaLane;
213 OpMap["OP_MLS_LN"]= OpMlsLane;
214 OpMap["OP_MLAL_LN"] = OpMlalLane;
Jiangning Liu0aa1a882013-10-04 09:21:17 +0000215 OpMap["OP_MLALHi_LN"] = OpMlalHiLane;
Jakob Stoklund Olesen3cc509b2012-06-13 05:12:41 +0000216 OpMap["OP_MLSL_LN"] = OpMlslLane;
Jiangning Liu0aa1a882013-10-04 09:21:17 +0000217 OpMap["OP_MLSLHi_LN"] = OpMlslHiLane;
Jakob Stoklund Olesen3cc509b2012-06-13 05:12:41 +0000218 OpMap["OP_QDMULL_LN"] = OpQDMullLane;
Jiangning Liu0aa1a882013-10-04 09:21:17 +0000219 OpMap["OP_QDMULLHi_LN"] = OpQDMullHiLane;
Jakob Stoklund Olesen3cc509b2012-06-13 05:12:41 +0000220 OpMap["OP_QDMLAL_LN"] = OpQDMlalLane;
Jiangning Liu0aa1a882013-10-04 09:21:17 +0000221 OpMap["OP_QDMLALHi_LN"] = OpQDMlalHiLane;
Jakob Stoklund Olesen3cc509b2012-06-13 05:12:41 +0000222 OpMap["OP_QDMLSL_LN"] = OpQDMlslLane;
Jiangning Liu0aa1a882013-10-04 09:21:17 +0000223 OpMap["OP_QDMLSLHi_LN"] = OpQDMlslHiLane;
Jakob Stoklund Olesen3cc509b2012-06-13 05:12:41 +0000224 OpMap["OP_QDMULH_LN"] = OpQDMulhLane;
225 OpMap["OP_QRDMULH_LN"] = OpQRDMulhLane;
Jiangning Liu0aa1a882013-10-04 09:21:17 +0000226 OpMap["OP_FMS_LN"] = OpFMSLane;
227 OpMap["OP_FMS_LNQ"] = OpFMSLaneQ;
Jakob Stoklund Olesen3cc509b2012-06-13 05:12:41 +0000228 OpMap["OP_EQ"] = OpEq;
229 OpMap["OP_GE"] = OpGe;
230 OpMap["OP_LE"] = OpLe;
231 OpMap["OP_GT"] = OpGt;
232 OpMap["OP_LT"] = OpLt;
233 OpMap["OP_NEG"] = OpNeg;
234 OpMap["OP_NOT"] = OpNot;
235 OpMap["OP_AND"] = OpAnd;
236 OpMap["OP_OR"] = OpOr;
237 OpMap["OP_XOR"] = OpXor;
238 OpMap["OP_ANDN"] = OpAndNot;
239 OpMap["OP_ORN"] = OpOrNot;
240 OpMap["OP_CAST"] = OpCast;
241 OpMap["OP_CONC"] = OpConcat;
242 OpMap["OP_HI"] = OpHi;
243 OpMap["OP_LO"] = OpLo;
244 OpMap["OP_DUP"] = OpDup;
245 OpMap["OP_DUP_LN"] = OpDupLane;
246 OpMap["OP_SEL"] = OpSelect;
247 OpMap["OP_REV16"] = OpRev16;
248 OpMap["OP_REV32"] = OpRev32;
249 OpMap["OP_REV64"] = OpRev64;
250 OpMap["OP_REINT"] = OpReinterpret;
Jiangning Liu097a4b42013-09-09 02:21:08 +0000251 OpMap["OP_ADDHNHi"] = OpAddhnHi;
252 OpMap["OP_RADDHNHi"] = OpRAddhnHi;
253 OpMap["OP_SUBHNHi"] = OpSubhnHi;
254 OpMap["OP_RSUBHNHi"] = OpRSubhnHi;
Jakob Stoklund Olesen3cc509b2012-06-13 05:12:41 +0000255 OpMap["OP_ABDL"] = OpAbdl;
Jiangning Liu097a4b42013-09-09 02:21:08 +0000256 OpMap["OP_ABDLHi"] = OpAbdlHi;
Jakob Stoklund Olesen3cc509b2012-06-13 05:12:41 +0000257 OpMap["OP_ABA"] = OpAba;
258 OpMap["OP_ABAL"] = OpAbal;
Jiangning Liu097a4b42013-09-09 02:21:08 +0000259 OpMap["OP_ABALHi"] = OpAbalHi;
260 OpMap["OP_QDMULLHi"] = OpQDMullHi;
261 OpMap["OP_QDMLALHi"] = OpQDMlalHi;
262 OpMap["OP_QDMLSLHi"] = OpQDMlslHi;
Tim Northoverb793f0d2013-08-01 09:23:19 +0000263 OpMap["OP_DIV"] = OpDiv;
Hao Liu912502b2013-09-04 09:29:13 +0000264 OpMap["OP_LONG_HI"] = OpLongHi;
265 OpMap["OP_NARROW_HI"] = OpNarrowHi;
266 OpMap["OP_MOVL_HI"] = OpMovlHi;
Jakob Stoklund Olesen3cc509b2012-06-13 05:12:41 +0000267
268 Record *SI = R.getClass("SInst");
269 Record *II = R.getClass("IInst");
270 Record *WI = R.getClass("WInst");
Michael Gottesman21e4e942013-04-16 21:18:42 +0000271 Record *SOpI = R.getClass("SOpInst");
272 Record *IOpI = R.getClass("IOpInst");
273 Record *WOpI = R.getClass("WOpInst");
274 Record *LOpI = R.getClass("LOpInst");
275 Record *NoTestOpI = R.getClass("NoTestOpInst");
276
Jakob Stoklund Olesen3cc509b2012-06-13 05:12:41 +0000277 ClassMap[SI] = ClassS;
278 ClassMap[II] = ClassI;
279 ClassMap[WI] = ClassW;
Michael Gottesman21e4e942013-04-16 21:18:42 +0000280 ClassMap[SOpI] = ClassS;
281 ClassMap[IOpI] = ClassI;
282 ClassMap[WOpI] = ClassW;
283 ClassMap[LOpI] = ClassL;
284 ClassMap[NoTestOpI] = ClassNoTest;
Jakob Stoklund Olesen3cc509b2012-06-13 05:12:41 +0000285 }
286
287 // run - Emit arm_neon.h.inc
288 void run(raw_ostream &o);
289
290 // runHeader - Emit all the __builtin prototypes used in arm_neon.h
291 void runHeader(raw_ostream &o);
292
293 // runTests - Emit tests for all the Neon intrinsics.
294 void runTests(raw_ostream &o);
295
296private:
Tim Northoverb793f0d2013-08-01 09:23:19 +0000297 void emitIntrinsic(raw_ostream &OS, Record *R,
298 StringMap<ClassKind> &EmittedMap);
299 void genBuiltinsDef(raw_ostream &OS, StringMap<ClassKind> &A64IntrinsicMap,
300 bool isA64GenBuiltinDef);
301 void genOverloadTypeCheckCode(raw_ostream &OS,
302 StringMap<ClassKind> &A64IntrinsicMap,
303 bool isA64TypeCheck);
304 void genIntrinsicRangeCheckCode(raw_ostream &OS,
305 StringMap<ClassKind> &A64IntrinsicMap,
306 bool isA64RangeCheck);
307 void genTargetTest(raw_ostream &OS, StringMap<OpKind> &EmittedMap,
308 bool isA64TestGen);
Jakob Stoklund Olesen3cc509b2012-06-13 05:12:41 +0000309};
310} // end anonymous namespace
311
Peter Collingbourne51d77772011-10-06 13:03:08 +0000312/// ParseTypes - break down a string such as "fQf" into a vector of StringRefs,
313/// which each StringRef representing a single type declared in the string.
314/// for "fQf" we would end up with 2 StringRefs, "f", and "Qf", representing
315/// 2xfloat and 4xfloat respectively.
316static void ParseTypes(Record *r, std::string &s,
317 SmallVectorImpl<StringRef> &TV) {
318 const char *data = s.data();
319 int len = 0;
320
321 for (unsigned i = 0, e = s.size(); i != e; ++i, ++len) {
Hao Liu12cd6a82013-08-15 08:26:30 +0000322 if (data[len] == 'P' || data[len] == 'Q' || data[len] == 'U'
Kevin Qin944f09f2013-08-29 07:55:15 +0000323 || data[len] == 'H' || data[len] == 'S')
Peter Collingbourne51d77772011-10-06 13:03:08 +0000324 continue;
325
326 switch (data[len]) {
327 case 'c':
328 case 's':
329 case 'i':
330 case 'l':
331 case 'h':
332 case 'f':
Tim Northoverb793f0d2013-08-01 09:23:19 +0000333 case 'd':
Peter Collingbourne51d77772011-10-06 13:03:08 +0000334 break;
335 default:
Joerg Sonnenberger38859ee2012-10-25 16:37:08 +0000336 PrintFatalError(r->getLoc(),
Peter Collingbourne51d77772011-10-06 13:03:08 +0000337 "Unexpected letter: " + std::string(data + len, 1));
Peter Collingbourne51d77772011-10-06 13:03:08 +0000338 }
339 TV.push_back(StringRef(data, len + 1));
340 data += len + 1;
341 len = -1;
342 }
343}
344
345/// Widen - Convert a type code into the next wider type. char -> short,
346/// short -> int, etc.
347static char Widen(const char t) {
348 switch (t) {
349 case 'c':
350 return 's';
351 case 's':
352 return 'i';
353 case 'i':
354 return 'l';
355 case 'h':
356 return 'f';
Joerg Sonnenberger38859ee2012-10-25 16:37:08 +0000357 default:
358 PrintFatalError("unhandled type in widen!");
Peter Collingbourne51d77772011-10-06 13:03:08 +0000359 }
Peter Collingbourne51d77772011-10-06 13:03:08 +0000360}
361
362/// Narrow - Convert a type code into the next smaller type. short -> char,
363/// float -> half float, etc.
364static char Narrow(const char t) {
365 switch (t) {
366 case 's':
367 return 'c';
368 case 'i':
369 return 's';
370 case 'l':
371 return 'i';
372 case 'f':
373 return 'h';
Joerg Sonnenberger38859ee2012-10-25 16:37:08 +0000374 default:
375 PrintFatalError("unhandled type in narrow!");
Peter Collingbourne51d77772011-10-06 13:03:08 +0000376 }
Peter Collingbourne51d77772011-10-06 13:03:08 +0000377}
378
Jiangning Liu097a4b42013-09-09 02:21:08 +0000379static std::string GetNarrowTypestr(StringRef ty)
380{
381 std::string s;
382 for (size_t i = 0, end = ty.size(); i < end; i++) {
383 switch (ty[i]) {
384 case 's':
385 s += 'c';
386 break;
387 case 'i':
388 s += 's';
389 break;
390 case 'l':
391 s += 'i';
392 break;
393 default:
394 s += ty[i];
395 break;
396 }
397 }
398
399 return s;
400}
401
Peter Collingbourne51d77772011-10-06 13:03:08 +0000402/// For a particular StringRef, return the base type code, and whether it has
403/// the quad-vector, polynomial, or unsigned modifiers set.
404static char ClassifyType(StringRef ty, bool &quad, bool &poly, bool &usgn) {
405 unsigned off = 0;
Kevin Qin944f09f2013-08-29 07:55:15 +0000406 // ignore scalar.
407 if (ty[off] == 'S') {
408 ++off;
409 }
Peter Collingbourne51d77772011-10-06 13:03:08 +0000410 // remember quad.
Hao Liu12cd6a82013-08-15 08:26:30 +0000411 if (ty[off] == 'Q' || ty[off] == 'H') {
Peter Collingbourne51d77772011-10-06 13:03:08 +0000412 quad = true;
413 ++off;
414 }
415
416 // remember poly.
417 if (ty[off] == 'P') {
418 poly = true;
419 ++off;
420 }
421
422 // remember unsigned.
423 if (ty[off] == 'U') {
424 usgn = true;
425 ++off;
426 }
427
428 // base type to get the type string for.
429 return ty[off];
430}
431
432/// ModType - Transform a type code and its modifiers based on a mod code. The
433/// mod code definitions may be found at the top of arm_neon.td.
434static char ModType(const char mod, char type, bool &quad, bool &poly,
435 bool &usgn, bool &scal, bool &cnst, bool &pntr) {
436 switch (mod) {
437 case 't':
438 if (poly) {
439 poly = false;
440 usgn = true;
441 }
442 break;
443 case 'u':
444 usgn = true;
445 poly = false;
446 if (type == 'f')
447 type = 'i';
Tim Northoverb793f0d2013-08-01 09:23:19 +0000448 if (type == 'd')
449 type = 'l';
Peter Collingbourne51d77772011-10-06 13:03:08 +0000450 break;
451 case 'x':
452 usgn = false;
453 poly = false;
454 if (type == 'f')
455 type = 'i';
Hao Liu912502b2013-09-04 09:29:13 +0000456 if (type == 'd')
457 type = 'l';
Peter Collingbourne51d77772011-10-06 13:03:08 +0000458 break;
459 case 'f':
460 if (type == 'h')
461 quad = true;
462 type = 'f';
463 usgn = false;
464 break;
465 case 'g':
466 quad = false;
467 break;
Jiangning Liu0aa1a882013-10-04 09:21:17 +0000468 case 'j':
469 quad = true;
470 break;
Peter Collingbourne51d77772011-10-06 13:03:08 +0000471 case 'w':
472 type = Widen(type);
473 quad = true;
474 break;
475 case 'n':
476 type = Widen(type);
477 break;
478 case 'i':
479 type = 'i';
480 scal = true;
481 break;
482 case 'l':
483 type = 'l';
484 scal = true;
485 usgn = true;
486 break;
487 case 's':
488 case 'a':
489 scal = true;
490 break;
491 case 'k':
492 quad = true;
493 break;
494 case 'c':
495 cnst = true;
496 case 'p':
497 pntr = true;
498 scal = true;
499 break;
500 case 'h':
501 type = Narrow(type);
502 if (type == 'h')
503 quad = false;
504 break;
Jiangning Liu097a4b42013-09-09 02:21:08 +0000505 case 'q':
506 type = Narrow(type);
507 quad = true;
508 break;
Peter Collingbourne51d77772011-10-06 13:03:08 +0000509 case 'e':
510 type = Narrow(type);
511 usgn = true;
512 break;
Hao Liu912502b2013-09-04 09:29:13 +0000513 case 'm':
514 type = Narrow(type);
515 quad = false;
516 break;
Peter Collingbourne51d77772011-10-06 13:03:08 +0000517 default:
518 break;
519 }
520 return type;
521}
522
523/// TypeString - for a modifier and type, generate the name of the typedef for
524/// that type. QUc -> uint8x8_t.
525static std::string TypeString(const char mod, StringRef typestr) {
526 bool quad = false;
527 bool poly = false;
528 bool usgn = false;
529 bool scal = false;
530 bool cnst = false;
531 bool pntr = false;
532
533 if (mod == 'v')
534 return "void";
535 if (mod == 'i')
536 return "int";
537
538 // base type to get the type string for.
539 char type = ClassifyType(typestr, quad, poly, usgn);
540
541 // Based on the modifying character, change the type and width if necessary.
542 type = ModType(mod, type, quad, poly, usgn, scal, cnst, pntr);
543
544 SmallString<128> s;
545
546 if (usgn)
547 s.push_back('u');
548
549 switch (type) {
550 case 'c':
551 s += poly ? "poly8" : "int8";
552 if (scal)
553 break;
554 s += quad ? "x16" : "x8";
555 break;
556 case 's':
557 s += poly ? "poly16" : "int16";
558 if (scal)
559 break;
560 s += quad ? "x8" : "x4";
561 break;
562 case 'i':
563 s += "int32";
564 if (scal)
565 break;
566 s += quad ? "x4" : "x2";
567 break;
568 case 'l':
569 s += "int64";
570 if (scal)
571 break;
572 s += quad ? "x2" : "x1";
573 break;
574 case 'h':
575 s += "float16";
576 if (scal)
577 break;
578 s += quad ? "x8" : "x4";
579 break;
580 case 'f':
581 s += "float32";
582 if (scal)
583 break;
584 s += quad ? "x4" : "x2";
585 break;
Tim Northoverb793f0d2013-08-01 09:23:19 +0000586 case 'd':
587 s += "float64";
588 if (scal)
589 break;
590 s += quad ? "x2" : "x1";
591 break;
592
Peter Collingbourne51d77772011-10-06 13:03:08 +0000593 default:
Joerg Sonnenberger38859ee2012-10-25 16:37:08 +0000594 PrintFatalError("unhandled type!");
Peter Collingbourne51d77772011-10-06 13:03:08 +0000595 }
596
597 if (mod == '2')
598 s += "x2";
599 if (mod == '3')
600 s += "x3";
601 if (mod == '4')
602 s += "x4";
603
604 // Append _t, finishing the type string typedef type.
605 s += "_t";
606
607 if (cnst)
608 s += " const";
609
610 if (pntr)
611 s += " *";
612
613 return s.str();
614}
615
616/// BuiltinTypeString - for a modifier and type, generate the clang
617/// BuiltinsARM.def prototype code for the function. See the top of clang's
618/// Builtins.def for a description of the type strings.
619static std::string BuiltinTypeString(const char mod, StringRef typestr,
620 ClassKind ck, bool ret) {
621 bool quad = false;
622 bool poly = false;
623 bool usgn = false;
624 bool scal = false;
625 bool cnst = false;
626 bool pntr = false;
627
628 if (mod == 'v')
629 return "v"; // void
630 if (mod == 'i')
631 return "i"; // int
632
633 // base type to get the type string for.
634 char type = ClassifyType(typestr, quad, poly, usgn);
635
636 // Based on the modifying character, change the type and width if necessary.
637 type = ModType(mod, type, quad, poly, usgn, scal, cnst, pntr);
638
639 // All pointers are void* pointers. Change type to 'v' now.
640 if (pntr) {
641 usgn = false;
642 poly = false;
643 type = 'v';
644 }
645 // Treat half-float ('h') types as unsigned short ('s') types.
646 if (type == 'h') {
647 type = 's';
648 usgn = true;
649 }
Jiangning Liu0aa1a882013-10-04 09:21:17 +0000650 usgn = usgn | poly | ((ck == ClassI || ck == ClassW) &&
651 scal && type != 'f' && type != 'd');
Peter Collingbourne51d77772011-10-06 13:03:08 +0000652
653 if (scal) {
654 SmallString<128> s;
655
656 if (usgn)
657 s.push_back('U');
658 else if (type == 'c')
659 s.push_back('S'); // make chars explicitly signed
660
661 if (type == 'l') // 64-bit long
662 s += "LLi";
663 else
664 s.push_back(type);
665
666 if (cnst)
667 s.push_back('C');
668 if (pntr)
669 s.push_back('*');
670 return s.str();
671 }
672
673 // Since the return value must be one type, return a vector type of the
674 // appropriate width which we will bitcast. An exception is made for
675 // returning structs of 2, 3, or 4 vectors which are returned in a sret-like
676 // fashion, storing them to a pointer arg.
677 if (ret) {
678 if (mod >= '2' && mod <= '4')
679 return "vv*"; // void result with void* first argument
680 if (mod == 'f' || (ck != ClassB && type == 'f'))
681 return quad ? "V4f" : "V2f";
Jiangning Liu0aa1a882013-10-04 09:21:17 +0000682 if (ck != ClassB && type == 'd')
683 return quad ? "V2d" : "V1d";
Peter Collingbourne51d77772011-10-06 13:03:08 +0000684 if (ck != ClassB && type == 's')
685 return quad ? "V8s" : "V4s";
686 if (ck != ClassB && type == 'i')
687 return quad ? "V4i" : "V2i";
688 if (ck != ClassB && type == 'l')
689 return quad ? "V2LLi" : "V1LLi";
690
691 return quad ? "V16Sc" : "V8Sc";
692 }
693
694 // Non-return array types are passed as individual vectors.
695 if (mod == '2')
696 return quad ? "V16ScV16Sc" : "V8ScV8Sc";
697 if (mod == '3')
698 return quad ? "V16ScV16ScV16Sc" : "V8ScV8ScV8Sc";
699 if (mod == '4')
700 return quad ? "V16ScV16ScV16ScV16Sc" : "V8ScV8ScV8ScV8Sc";
701
702 if (mod == 'f' || (ck != ClassB && type == 'f'))
703 return quad ? "V4f" : "V2f";
Jiangning Liu0aa1a882013-10-04 09:21:17 +0000704 if (ck != ClassB && type == 'd')
705 return quad ? "V2d" : "V1d";
Peter Collingbourne51d77772011-10-06 13:03:08 +0000706 if (ck != ClassB && type == 's')
707 return quad ? "V8s" : "V4s";
708 if (ck != ClassB && type == 'i')
709 return quad ? "V4i" : "V2i";
710 if (ck != ClassB && type == 'l')
711 return quad ? "V2LLi" : "V1LLi";
712
713 return quad ? "V16Sc" : "V8Sc";
714}
715
Michael Gottesmanfb599a42013-04-16 22:07:30 +0000716/// InstructionTypeCode - Computes the ARM argument character code and
717/// quad status for a specific type string and ClassKind.
718static void InstructionTypeCode(const StringRef &typeStr,
719 const ClassKind ck,
720 bool &quad,
721 std::string &typeCode) {
722 bool poly = false;
723 bool usgn = false;
724 char type = ClassifyType(typeStr, quad, poly, usgn);
725
726 switch (type) {
727 case 'c':
728 switch (ck) {
729 case ClassS: typeCode = poly ? "p8" : usgn ? "u8" : "s8"; break;
730 case ClassI: typeCode = "i8"; break;
731 case ClassW: typeCode = "8"; break;
732 default: break;
733 }
734 break;
735 case 's':
736 switch (ck) {
737 case ClassS: typeCode = poly ? "p16" : usgn ? "u16" : "s16"; break;
738 case ClassI: typeCode = "i16"; break;
739 case ClassW: typeCode = "16"; break;
740 default: break;
741 }
742 break;
743 case 'i':
744 switch (ck) {
745 case ClassS: typeCode = usgn ? "u32" : "s32"; break;
746 case ClassI: typeCode = "i32"; break;
747 case ClassW: typeCode = "32"; break;
748 default: break;
749 }
750 break;
751 case 'l':
752 switch (ck) {
753 case ClassS: typeCode = usgn ? "u64" : "s64"; break;
754 case ClassI: typeCode = "i64"; break;
755 case ClassW: typeCode = "64"; break;
756 default: break;
757 }
758 break;
759 case 'h':
760 switch (ck) {
761 case ClassS:
762 case ClassI: typeCode = "f16"; break;
763 case ClassW: typeCode = "16"; break;
764 default: break;
765 }
766 break;
767 case 'f':
768 switch (ck) {
769 case ClassS:
770 case ClassI: typeCode = "f32"; break;
771 case ClassW: typeCode = "32"; break;
772 default: break;
773 }
774 break;
Tim Northoverb793f0d2013-08-01 09:23:19 +0000775 case 'd':
776 switch (ck) {
777 case ClassS:
778 case ClassI:
779 typeCode += "f64";
780 break;
781 case ClassW:
782 PrintFatalError("unhandled type!");
783 default:
784 break;
785 }
786 break;
Michael Gottesmanfb599a42013-04-16 22:07:30 +0000787 default:
788 PrintFatalError("unhandled type!");
789 }
790}
791
Kevin Qin944f09f2013-08-29 07:55:15 +0000792static char Insert_BHSD_Suffix(StringRef typestr){
793 unsigned off = 0;
794 if(typestr[off++] == 'S'){
795 while(typestr[off] == 'Q' || typestr[off] == 'H'||
796 typestr[off] == 'P' || typestr[off] == 'U')
797 ++off;
798 switch (typestr[off]){
799 default : break;
800 case 'c' : return 'b';
801 case 's' : return 'h';
802 case 'i' :
803 case 'f' : return 's';
804 case 'l' :
805 case 'd' : return 'd';
806 }
807 }
808 return 0;
809}
810
Peter Collingbourne51d77772011-10-06 13:03:08 +0000811/// MangleName - Append a type or width suffix to a base neon function name,
Hao Liu12cd6a82013-08-15 08:26:30 +0000812/// and insert a 'q' in the appropriate location if type string starts with 'Q'.
813/// E.g. turn "vst2_lane" into "vst2q_lane_f32", etc.
Kevin Qin944f09f2013-08-29 07:55:15 +0000814/// Insert proper 'b' 'h' 's' 'd' if prefix 'S' is used.
Peter Collingbourne51d77772011-10-06 13:03:08 +0000815static std::string MangleName(const std::string &name, StringRef typestr,
816 ClassKind ck) {
817 if (name == "vcvt_f32_f16")
818 return name;
819
820 bool quad = false;
Michael Gottesmanfb599a42013-04-16 22:07:30 +0000821 std::string typeCode = "";
822
823 InstructionTypeCode(typestr, ck, quad, typeCode);
Peter Collingbourne51d77772011-10-06 13:03:08 +0000824
825 std::string s = name;
826
Michael Gottesmanfb599a42013-04-16 22:07:30 +0000827 if (typeCode.size() > 0) {
828 s += "_" + typeCode;
Peter Collingbourne51d77772011-10-06 13:03:08 +0000829 }
Michael Gottesmanfb599a42013-04-16 22:07:30 +0000830
Peter Collingbourne51d77772011-10-06 13:03:08 +0000831 if (ck == ClassB)
832 s += "_v";
833
834 // Insert a 'q' before the first '_' character so that it ends up before
835 // _lane or _n on vector-scalar operations.
Kevin Qin944f09f2013-08-29 07:55:15 +0000836 if (typestr.find("Q") != StringRef::npos) {
Hao Liu12cd6a82013-08-15 08:26:30 +0000837 size_t pos = s.find('_');
838 s = s.insert(pos, "q");
Peter Collingbourne51d77772011-10-06 13:03:08 +0000839 }
Kevin Qin944f09f2013-08-29 07:55:15 +0000840 char ins = Insert_BHSD_Suffix(typestr);
841 if(ins){
842 size_t pos = s.find('_');
843 s = s.insert(pos, &ins, 1);
844 }
Michael Gottesmanc327f872013-04-16 23:00:26 +0000845
Peter Collingbourne51d77772011-10-06 13:03:08 +0000846 return s;
847}
848
Michael Gottesmanc327f872013-04-16 23:00:26 +0000849static void PreprocessInstruction(const StringRef &Name,
850 const std::string &InstName,
851 std::string &Prefix,
852 bool &HasNPostfix,
853 bool &HasLanePostfix,
854 bool &HasDupPostfix,
855 bool &IsSpecialVCvt,
856 size_t &TBNumber) {
857 // All of our instruction name fields from arm_neon.td are of the form
858 // <instructionname>_...
859 // Thus we grab our instruction name via computation of said Prefix.
860 const size_t PrefixEnd = Name.find_first_of('_');
861 // If InstName is passed in, we use that instead of our name Prefix.
862 Prefix = InstName.size() == 0? Name.slice(0, PrefixEnd).str() : InstName;
863
864 const StringRef Postfix = Name.slice(PrefixEnd, Name.size());
865
866 HasNPostfix = Postfix.count("_n");
867 HasLanePostfix = Postfix.count("_lane");
868 HasDupPostfix = Postfix.count("_dup");
869 IsSpecialVCvt = Postfix.size() != 0 && Name.count("vcvt");
870
871 if (InstName.compare("vtbl") == 0 ||
872 InstName.compare("vtbx") == 0) {
873 // If we have a vtblN/vtbxN instruction, use the instruction's ASCII
874 // encoding to get its true value.
875 TBNumber = Name[Name.size()-1] - 48;
876 }
877}
878
879/// GenerateRegisterCheckPatternsForLoadStores - Given a bunch of data we have
880/// extracted, generate a FileCheck pattern for a Load Or Store
881static void
882GenerateRegisterCheckPatternForLoadStores(const StringRef &NameRef,
883 const std::string& OutTypeCode,
884 const bool &IsQuad,
885 const bool &HasDupPostfix,
886 const bool &HasLanePostfix,
887 const size_t Count,
888 std::string &RegisterSuffix) {
889 const bool IsLDSTOne = NameRef.count("vld1") || NameRef.count("vst1");
890 // If N == 3 || N == 4 and we are dealing with a quad instruction, Clang
891 // will output a series of v{ld,st}1s, so we have to handle it specially.
892 if ((Count == 3 || Count == 4) && IsQuad) {
893 RegisterSuffix += "{";
894 for (size_t i = 0; i < Count; i++) {
895 RegisterSuffix += "d{{[0-9]+}}";
896 if (HasDupPostfix) {
897 RegisterSuffix += "[]";
898 }
899 if (HasLanePostfix) {
900 RegisterSuffix += "[{{[0-9]+}}]";
901 }
902 if (i < Count-1) {
903 RegisterSuffix += ", ";
904 }
905 }
906 RegisterSuffix += "}";
907 } else {
908
909 // Handle normal loads and stores.
910 RegisterSuffix += "{";
911 for (size_t i = 0; i < Count; i++) {
912 RegisterSuffix += "d{{[0-9]+}}";
913 if (HasDupPostfix) {
914 RegisterSuffix += "[]";
915 }
916 if (HasLanePostfix) {
917 RegisterSuffix += "[{{[0-9]+}}]";
918 }
919 if (IsQuad && !HasLanePostfix) {
920 RegisterSuffix += ", d{{[0-9]+}}";
921 if (HasDupPostfix) {
922 RegisterSuffix += "[]";
923 }
924 }
925 if (i < Count-1) {
926 RegisterSuffix += ", ";
927 }
928 }
929 RegisterSuffix += "}, [r{{[0-9]+}}";
930
931 // We only include the alignment hint if we have a vld1.*64 or
932 // a dup/lane instruction.
933 if (IsLDSTOne) {
934 if ((HasLanePostfix || HasDupPostfix) && OutTypeCode != "8") {
Michael Gottesman410c3f72013-06-24 21:25:37 +0000935 RegisterSuffix += ":" + OutTypeCode;
Michael Gottesmanc327f872013-04-16 23:00:26 +0000936 }
937 }
938
939 RegisterSuffix += "]";
940 }
941}
942
943static bool HasNPostfixAndScalarArgs(const StringRef &NameRef,
944 const bool &HasNPostfix) {
945 return (NameRef.count("vmla") ||
946 NameRef.count("vmlal") ||
947 NameRef.count("vmlsl") ||
948 NameRef.count("vmull") ||
949 NameRef.count("vqdmlal") ||
950 NameRef.count("vqdmlsl") ||
951 NameRef.count("vqdmulh") ||
952 NameRef.count("vqdmull") ||
953 NameRef.count("vqrdmulh")) && HasNPostfix;
954}
955
956static bool IsFiveOperandLaneAccumulator(const StringRef &NameRef,
957 const bool &HasLanePostfix) {
958 return (NameRef.count("vmla") ||
959 NameRef.count("vmls") ||
960 NameRef.count("vmlal") ||
961 NameRef.count("vmlsl") ||
962 (NameRef.count("vmul") && NameRef.size() == 3)||
963 NameRef.count("vqdmlal") ||
964 NameRef.count("vqdmlsl") ||
965 NameRef.count("vqdmulh") ||
966 NameRef.count("vqrdmulh")) && HasLanePostfix;
967}
968
969static bool IsSpecialLaneMultiply(const StringRef &NameRef,
970 const bool &HasLanePostfix,
971 const bool &IsQuad) {
972 const bool IsVMulOrMulh = (NameRef.count("vmul") || NameRef.count("mulh"))
973 && IsQuad;
974 const bool IsVMull = NameRef.count("mull") && !IsQuad;
975 return (IsVMulOrMulh || IsVMull) && HasLanePostfix;
976}
977
978static void NormalizeProtoForRegisterPatternCreation(const std::string &Name,
979 const std::string &Proto,
980 const bool &HasNPostfix,
981 const bool &IsQuad,
982 const bool &HasLanePostfix,
983 const bool &HasDupPostfix,
984 std::string &NormedProto) {
985 // Handle generic case.
986 const StringRef NameRef(Name);
987 for (size_t i = 0, end = Proto.size(); i < end; i++) {
988 switch (Proto[i]) {
989 case 'u':
990 case 'f':
991 case 'd':
992 case 's':
993 case 'x':
994 case 't':
995 case 'n':
996 NormedProto += IsQuad? 'q' : 'd';
997 break;
998 case 'w':
999 case 'k':
1000 NormedProto += 'q';
1001 break;
1002 case 'g':
Jiangning Liu0aa1a882013-10-04 09:21:17 +00001003 case 'j':
Michael Gottesmanc327f872013-04-16 23:00:26 +00001004 case 'h':
1005 case 'e':
1006 NormedProto += 'd';
1007 break;
1008 case 'i':
1009 NormedProto += HasLanePostfix? 'a' : 'i';
1010 break;
1011 case 'a':
1012 if (HasLanePostfix) {
1013 NormedProto += 'a';
1014 } else if (HasNPostfixAndScalarArgs(NameRef, HasNPostfix)) {
1015 NormedProto += IsQuad? 'q' : 'd';
1016 } else {
1017 NormedProto += 'i';
1018 }
1019 break;
1020 }
1021 }
1022
1023 // Handle Special Cases.
1024 const bool IsNotVExt = !NameRef.count("vext");
1025 const bool IsVPADAL = NameRef.count("vpadal");
1026 const bool Is5OpLaneAccum = IsFiveOperandLaneAccumulator(NameRef,
1027 HasLanePostfix);
1028 const bool IsSpecialLaneMul = IsSpecialLaneMultiply(NameRef, HasLanePostfix,
1029 IsQuad);
1030
1031 if (IsSpecialLaneMul) {
1032 // If
1033 NormedProto[2] = NormedProto[3];
1034 NormedProto.erase(3);
1035 } else if (NormedProto.size() == 4 &&
1036 NormedProto[0] == NormedProto[1] &&
1037 IsNotVExt) {
1038 // If NormedProto.size() == 4 and the first two proto characters are the
1039 // same, ignore the first.
1040 NormedProto = NormedProto.substr(1, 3);
1041 } else if (Is5OpLaneAccum) {
1042 // If we have a 5 op lane accumulator operation, we take characters 1,2,4
1043 std::string tmp = NormedProto.substr(1,2);
1044 tmp += NormedProto[4];
1045 NormedProto = tmp;
1046 } else if (IsVPADAL) {
1047 // If we have VPADAL, ignore the first character.
1048 NormedProto = NormedProto.substr(0, 2);
1049 } else if (NameRef.count("vdup") && NormedProto.size() > 2) {
1050 // If our instruction is a dup instruction, keep only the first and
1051 // last characters.
1052 std::string tmp = "";
1053 tmp += NormedProto[0];
1054 tmp += NormedProto[NormedProto.size()-1];
1055 NormedProto = tmp;
1056 }
1057}
1058
1059/// GenerateRegisterCheckPatterns - Given a bunch of data we have
1060/// extracted, generate a FileCheck pattern to check that an
1061/// instruction's arguments are correct.
1062static void GenerateRegisterCheckPattern(const std::string &Name,
1063 const std::string &Proto,
1064 const std::string &OutTypeCode,
1065 const bool &HasNPostfix,
1066 const bool &IsQuad,
1067 const bool &HasLanePostfix,
1068 const bool &HasDupPostfix,
1069 const size_t &TBNumber,
1070 std::string &RegisterSuffix) {
1071
1072 RegisterSuffix = "";
1073
1074 const StringRef NameRef(Name);
1075 const StringRef ProtoRef(Proto);
1076
1077 if ((NameRef.count("vdup") || NameRef.count("vmov")) && HasNPostfix) {
1078 return;
1079 }
1080
1081 const bool IsLoadStore = NameRef.count("vld") || NameRef.count("vst");
1082 const bool IsTBXOrTBL = NameRef.count("vtbl") || NameRef.count("vtbx");
1083
1084 if (IsLoadStore) {
1085 // Grab N value from v{ld,st}N using its ascii representation.
1086 const size_t Count = NameRef[3] - 48;
1087
1088 GenerateRegisterCheckPatternForLoadStores(NameRef, OutTypeCode, IsQuad,
1089 HasDupPostfix, HasLanePostfix,
1090 Count, RegisterSuffix);
1091 } else if (IsTBXOrTBL) {
1092 RegisterSuffix += "d{{[0-9]+}}, {";
1093 for (size_t i = 0; i < TBNumber-1; i++) {
1094 RegisterSuffix += "d{{[0-9]+}}, ";
1095 }
1096 RegisterSuffix += "d{{[0-9]+}}}, d{{[0-9]+}}";
1097 } else {
1098 // Handle a normal instruction.
1099 if (NameRef.count("vget") || NameRef.count("vset"))
1100 return;
1101
1102 // We first normalize our proto, since we only need to emit 4
1103 // different types of checks, yet have more than 4 proto types
1104 // that map onto those 4 patterns.
1105 std::string NormalizedProto("");
1106 NormalizeProtoForRegisterPatternCreation(Name, Proto, HasNPostfix, IsQuad,
1107 HasLanePostfix, HasDupPostfix,
1108 NormalizedProto);
1109
1110 for (size_t i = 0, end = NormalizedProto.size(); i < end; i++) {
1111 const char &c = NormalizedProto[i];
1112 switch (c) {
1113 case 'q':
1114 RegisterSuffix += "q{{[0-9]+}}, ";
1115 break;
1116
1117 case 'd':
1118 RegisterSuffix += "d{{[0-9]+}}, ";
1119 break;
1120
1121 case 'i':
1122 RegisterSuffix += "#{{[0-9]+}}, ";
1123 break;
1124
1125 case 'a':
1126 RegisterSuffix += "d{{[0-9]+}}[{{[0-9]}}], ";
1127 break;
1128 }
1129 }
1130
1131 // Remove extra ", ".
1132 RegisterSuffix = RegisterSuffix.substr(0, RegisterSuffix.size()-2);
1133 }
1134}
1135
1136/// GenerateChecksForIntrinsic - Given a specific instruction name +
1137/// typestr + class kind, generate the proper set of FileCheck
1138/// Patterns to check for. We could just return a string, but instead
1139/// use a vector since it provides us with the extra flexibility of
1140/// emitting multiple checks, which comes in handy for certain cases
1141/// like mla where we want to check for 2 different instructions.
1142static void GenerateChecksForIntrinsic(const std::string &Name,
1143 const std::string &Proto,
1144 StringRef &OutTypeStr,
1145 StringRef &InTypeStr,
1146 ClassKind Ck,
1147 const std::string &InstName,
1148 bool IsHiddenLOp,
1149 std::vector<std::string>& Result) {
1150
1151 // If Ck is a ClassNoTest instruction, just return so no test is
1152 // emitted.
1153 if(Ck == ClassNoTest)
1154 return;
1155
1156 if (Name == "vcvt_f32_f16") {
1157 Result.push_back("vcvt.f32.f16");
1158 return;
1159 }
1160
1161
1162 // Now we preprocess our instruction given the data we have to get the
1163 // data that we need.
1164 // Create a StringRef for String Manipulation of our Name.
1165 const StringRef NameRef(Name);
1166 // Instruction Prefix.
1167 std::string Prefix;
1168 // The type code for our out type string.
1169 std::string OutTypeCode;
1170 // To handle our different cases, we need to check for different postfixes.
1171 // Is our instruction a quad instruction.
1172 bool IsQuad = false;
1173 // Our instruction is of the form <instructionname>_n.
1174 bool HasNPostfix = false;
1175 // Our instruction is of the form <instructionname>_lane.
1176 bool HasLanePostfix = false;
1177 // Our instruction is of the form <instructionname>_dup.
1178 bool HasDupPostfix = false;
1179 // Our instruction is a vcvt instruction which requires special handling.
1180 bool IsSpecialVCvt = false;
1181 // If we have a vtbxN or vtblN instruction, this is set to N.
1182 size_t TBNumber = -1;
1183 // Register Suffix
1184 std::string RegisterSuffix;
1185
1186 PreprocessInstruction(NameRef, InstName, Prefix,
1187 HasNPostfix, HasLanePostfix, HasDupPostfix,
1188 IsSpecialVCvt, TBNumber);
1189
1190 InstructionTypeCode(OutTypeStr, Ck, IsQuad, OutTypeCode);
1191 GenerateRegisterCheckPattern(Name, Proto, OutTypeCode, HasNPostfix, IsQuad,
1192 HasLanePostfix, HasDupPostfix, TBNumber,
1193 RegisterSuffix);
1194
1195 // In the following section, we handle a bunch of special cases. You can tell
1196 // a special case by the fact we are returning early.
1197
1198 // If our instruction is a logical instruction without postfix or a
1199 // hidden LOp just return the current Prefix.
1200 if (Ck == ClassL || IsHiddenLOp) {
1201 Result.push_back(Prefix + " " + RegisterSuffix);
1202 return;
1203 }
1204
1205 // If we have a vmov, due to the many different cases, some of which
1206 // vary within the different intrinsics generated for a single
1207 // instruction type, just output a vmov. (e.g. given an instruction
1208 // A, A.u32 might be vmov and A.u8 might be vmov.8).
1209 //
1210 // FIXME: Maybe something can be done about this. The two cases that we care
1211 // about are vmov as an LType and vmov as a WType.
1212 if (Prefix == "vmov") {
1213 Result.push_back(Prefix + " " + RegisterSuffix);
1214 return;
1215 }
1216
1217 // In the following section, we handle special cases.
1218
1219 if (OutTypeCode == "64") {
1220 // If we have a 64 bit vdup/vext and are handling an uint64x1_t
1221 // type, the intrinsic will be optimized away, so just return
1222 // nothing. On the other hand if we are handling an uint64x2_t
1223 // (i.e. quad instruction), vdup/vmov instructions should be
1224 // emitted.
1225 if (Prefix == "vdup" || Prefix == "vext") {
1226 if (IsQuad) {
1227 Result.push_back("{{vmov|vdup}}");
1228 }
1229 return;
1230 }
1231
1232 // v{st,ld}{2,3,4}_{u,s}64 emit v{st,ld}1.64 instructions with
1233 // multiple register operands.
1234 bool MultiLoadPrefix = Prefix == "vld2" || Prefix == "vld3"
1235 || Prefix == "vld4";
1236 bool MultiStorePrefix = Prefix == "vst2" || Prefix == "vst3"
1237 || Prefix == "vst4";
1238 if (MultiLoadPrefix || MultiStorePrefix) {
1239 Result.push_back(NameRef.slice(0, 3).str() + "1.64");
1240 return;
1241 }
1242
1243 // v{st,ld}1_{lane,dup}_{u64,s64} use vldr/vstr/vmov/str instead of
1244 // emitting said instructions. So return a check for
1245 // vldr/vstr/vmov/str instead.
1246 if (HasLanePostfix || HasDupPostfix) {
1247 if (Prefix == "vst1") {
1248 Result.push_back("{{str|vstr|vmov}}");
1249 return;
1250 } else if (Prefix == "vld1") {
1251 Result.push_back("{{ldr|vldr|vmov}}");
1252 return;
1253 }
1254 }
1255 }
1256
1257 // vzip.32/vuzp.32 are the same instruction as vtrn.32 and are
1258 // sometimes disassembled as vtrn.32. We use a regex to handle both
1259 // cases.
1260 if ((Prefix == "vzip" || Prefix == "vuzp") && OutTypeCode == "32") {
1261 Result.push_back("{{vtrn|" + Prefix + "}}.32 " + RegisterSuffix);
1262 return;
1263 }
1264
1265 // Currently on most ARM processors, we do not use vmla/vmls for
1266 // quad floating point operations. Instead we output vmul + vadd. So
1267 // check if we have one of those instructions and just output a
1268 // check for vmul.
1269 if (OutTypeCode == "f32") {
1270 if (Prefix == "vmls") {
1271 Result.push_back("vmul." + OutTypeCode + " " + RegisterSuffix);
1272 Result.push_back("vsub." + OutTypeCode);
1273 return;
1274 } else if (Prefix == "vmla") {
1275 Result.push_back("vmul." + OutTypeCode + " " + RegisterSuffix);
1276 Result.push_back("vadd." + OutTypeCode);
1277 return;
1278 }
1279 }
1280
1281 // If we have vcvt, get the input type from the instruction name
1282 // (which should be of the form instname_inputtype) and append it
1283 // before the output type.
1284 if (Prefix == "vcvt") {
1285 const std::string inTypeCode = NameRef.substr(NameRef.find_last_of("_")+1);
1286 Prefix += "." + inTypeCode;
1287 }
1288
1289 // Append output type code to get our final mangled instruction.
1290 Prefix += "." + OutTypeCode;
1291
1292 Result.push_back(Prefix + " " + RegisterSuffix);
1293}
1294
Peter Collingbourne51d77772011-10-06 13:03:08 +00001295/// UseMacro - Examine the prototype string to determine if the intrinsic
1296/// should be defined as a preprocessor macro instead of an inline function.
1297static bool UseMacro(const std::string &proto) {
1298 // If this builtin takes an immediate argument, we need to #define it rather
1299 // than use a standard declaration, so that SemaChecking can range check
1300 // the immediate passed by the user.
1301 if (proto.find('i') != std::string::npos)
1302 return true;
1303
1304 // Pointer arguments need to use macros to avoid hiding aligned attributes
1305 // from the pointer type.
1306 if (proto.find('p') != std::string::npos ||
1307 proto.find('c') != std::string::npos)
1308 return true;
1309
1310 return false;
1311}
1312
1313/// MacroArgUsedDirectly - Return true if argument i for an intrinsic that is
1314/// defined as a macro should be accessed directly instead of being first
1315/// assigned to a local temporary.
1316static bool MacroArgUsedDirectly(const std::string &proto, unsigned i) {
1317 // True for constant ints (i), pointers (p) and const pointers (c).
1318 return (proto[i] == 'i' || proto[i] == 'p' || proto[i] == 'c');
1319}
1320
1321// Generate the string "(argtype a, argtype b, ...)"
1322static std::string GenArgs(const std::string &proto, StringRef typestr) {
1323 bool define = UseMacro(proto);
1324 char arg = 'a';
1325
1326 std::string s;
1327 s += "(";
1328
1329 for (unsigned i = 1, e = proto.size(); i != e; ++i, ++arg) {
1330 if (define) {
1331 // Some macro arguments are used directly instead of being assigned
1332 // to local temporaries; prepend an underscore prefix to make their
1333 // names consistent with the local temporaries.
1334 if (MacroArgUsedDirectly(proto, i))
1335 s += "__";
1336 } else {
1337 s += TypeString(proto[i], typestr) + " __";
1338 }
1339 s.push_back(arg);
1340 if ((i + 1) < e)
1341 s += ", ";
1342 }
1343
1344 s += ")";
1345 return s;
1346}
1347
1348// Macro arguments are not type-checked like inline function arguments, so
1349// assign them to local temporaries to get the right type checking.
1350static std::string GenMacroLocals(const std::string &proto, StringRef typestr) {
1351 char arg = 'a';
1352 std::string s;
1353 bool generatedLocal = false;
1354
1355 for (unsigned i = 1, e = proto.size(); i != e; ++i, ++arg) {
1356 // Do not create a temporary for an immediate argument.
1357 // That would defeat the whole point of using a macro!
Peter Collingbourne51d77772011-10-06 13:03:08 +00001358 if (MacroArgUsedDirectly(proto, i))
1359 continue;
1360 generatedLocal = true;
1361
1362 s += TypeString(proto[i], typestr) + " __";
1363 s.push_back(arg);
1364 s += " = (";
1365 s.push_back(arg);
1366 s += "); ";
1367 }
1368
1369 if (generatedLocal)
1370 s += "\\\n ";
1371 return s;
1372}
1373
1374// Use the vmovl builtin to sign-extend or zero-extend a vector.
Jiangning Liu097a4b42013-09-09 02:21:08 +00001375static std::string Extend(StringRef typestr, const std::string &a, bool h=0) {
1376 std::string s, high;
1377 high = h ? "_high" : "";
1378 s = MangleName("vmovl" + high, typestr, ClassS);
Peter Collingbourne51d77772011-10-06 13:03:08 +00001379 s += "(" + a + ")";
1380 return s;
1381}
1382
Jiangning Liu097a4b42013-09-09 02:21:08 +00001383// Get the high 64-bit part of a vector
1384static std::string GetHigh(const std::string &a, StringRef typestr) {
1385 std::string s;
1386 s = MangleName("vget_high", typestr, ClassS);
1387 s += "(" + a + ")";
1388 return s;
1389}
1390
1391// Gen operation with two operands and get high 64-bit for both of two operands.
1392static std::string Gen2OpWith2High(StringRef typestr,
1393 const std::string &op,
1394 const std::string &a,
1395 const std::string &b) {
1396 std::string s;
1397 std::string Op1 = GetHigh(a, typestr);
1398 std::string Op2 = GetHigh(b, typestr);
1399 s = MangleName(op, typestr, ClassS);
1400 s += "(" + Op1 + ", " + Op2 + ");";
1401 return s;
1402}
1403
1404// Gen operation with three operands and get high 64-bit of the latter
1405// two operands.
1406static std::string Gen3OpWith2High(StringRef typestr,
1407 const std::string &op,
1408 const std::string &a,
1409 const std::string &b,
1410 const std::string &c) {
1411 std::string s;
1412 std::string Op1 = GetHigh(b, typestr);
1413 std::string Op2 = GetHigh(c, typestr);
1414 s = MangleName(op, typestr, ClassS);
1415 s += "(" + a + ", " + Op1 + ", " + Op2 + ");";
1416 return s;
1417}
1418
1419// Gen combine operation by putting a on low 64-bit, and b on high 64-bit.
1420static std::string GenCombine(std::string typestr,
1421 const std::string &a,
1422 const std::string &b) {
1423 std::string s;
1424 s = MangleName("vcombine", typestr, ClassS);
1425 s += "(" + a + ", " + b + ")";
1426 return s;
1427}
1428
Peter Collingbourne51d77772011-10-06 13:03:08 +00001429static std::string Duplicate(unsigned nElts, StringRef typestr,
1430 const std::string &a) {
1431 std::string s;
1432
1433 s = "(" + TypeString('d', typestr) + "){ ";
1434 for (unsigned i = 0; i != nElts; ++i) {
1435 s += a;
1436 if ((i + 1) < nElts)
1437 s += ", ";
1438 }
1439 s += " }";
1440
1441 return s;
1442}
1443
1444static std::string SplatLane(unsigned nElts, const std::string &vec,
1445 const std::string &lane) {
1446 std::string s = "__builtin_shufflevector(" + vec + ", " + vec;
1447 for (unsigned i = 0; i < nElts; ++i)
1448 s += ", " + lane;
1449 s += ")";
1450 return s;
1451}
1452
Hao Liu912502b2013-09-04 09:29:13 +00001453static std::string RemoveHigh(const std::string &name) {
1454 std::string s = name;
1455 std::size_t found = s.find("_high_");
1456 if (found == std::string::npos)
1457 PrintFatalError("name should contain \"_high_\" for high intrinsics");
1458 s.replace(found, 5, "");
1459 return s;
1460}
1461
Peter Collingbourne51d77772011-10-06 13:03:08 +00001462static unsigned GetNumElements(StringRef typestr, bool &quad) {
1463 quad = false;
1464 bool dummy = false;
1465 char type = ClassifyType(typestr, quad, dummy, dummy);
1466 unsigned nElts = 0;
1467 switch (type) {
1468 case 'c': nElts = 8; break;
1469 case 's': nElts = 4; break;
1470 case 'i': nElts = 2; break;
1471 case 'l': nElts = 1; break;
1472 case 'h': nElts = 4; break;
1473 case 'f': nElts = 2; break;
Tim Northoverb793f0d2013-08-01 09:23:19 +00001474 case 'd':
1475 nElts = 1;
1476 break;
Peter Collingbourne51d77772011-10-06 13:03:08 +00001477 default:
Joerg Sonnenberger38859ee2012-10-25 16:37:08 +00001478 PrintFatalError("unhandled type!");
Peter Collingbourne51d77772011-10-06 13:03:08 +00001479 }
1480 if (quad) nElts <<= 1;
1481 return nElts;
1482}
1483
1484// Generate the definition for this intrinsic, e.g. "a + b" for OpAdd.
Hao Liu912502b2013-09-04 09:29:13 +00001485static std::string GenOpString(const std::string &name, OpKind op,
1486 const std::string &proto, StringRef typestr) {
Peter Collingbourne51d77772011-10-06 13:03:08 +00001487 bool quad;
1488 unsigned nElts = GetNumElements(typestr, quad);
1489 bool define = UseMacro(proto);
1490
1491 std::string ts = TypeString(proto[0], typestr);
1492 std::string s;
1493 if (!define) {
1494 s = "return ";
1495 }
1496
1497 switch(op) {
1498 case OpAdd:
1499 s += "__a + __b;";
1500 break;
1501 case OpAddl:
1502 s += Extend(typestr, "__a") + " + " + Extend(typestr, "__b") + ";";
1503 break;
Jiangning Liu097a4b42013-09-09 02:21:08 +00001504 case OpAddlHi:
1505 s += Extend(typestr, "__a", 1) + " + " + Extend(typestr, "__b", 1) + ";";
1506 break;
Peter Collingbourne51d77772011-10-06 13:03:08 +00001507 case OpAddw:
1508 s += "__a + " + Extend(typestr, "__b") + ";";
1509 break;
Jiangning Liu097a4b42013-09-09 02:21:08 +00001510 case OpAddwHi:
1511 s += "__a + " + Extend(typestr, "__b", 1) + ";";
1512 break;
Peter Collingbourne51d77772011-10-06 13:03:08 +00001513 case OpSub:
1514 s += "__a - __b;";
1515 break;
1516 case OpSubl:
1517 s += Extend(typestr, "__a") + " - " + Extend(typestr, "__b") + ";";
1518 break;
Jiangning Liu097a4b42013-09-09 02:21:08 +00001519 case OpSublHi:
1520 s += Extend(typestr, "__a", 1) + " - " + Extend(typestr, "__b", 1) + ";";
1521 break;
Peter Collingbourne51d77772011-10-06 13:03:08 +00001522 case OpSubw:
1523 s += "__a - " + Extend(typestr, "__b") + ";";
1524 break;
Jiangning Liu097a4b42013-09-09 02:21:08 +00001525 case OpSubwHi:
1526 s += "__a - " + Extend(typestr, "__b", 1) + ";";
1527 break;
Peter Collingbourne51d77772011-10-06 13:03:08 +00001528 case OpMulN:
1529 s += "__a * " + Duplicate(nElts, typestr, "__b") + ";";
1530 break;
1531 case OpMulLane:
1532 s += "__a * " + SplatLane(nElts, "__b", "__c") + ";";
1533 break;
Jiangning Liu0aa1a882013-10-04 09:21:17 +00001534 case OpMulXLane:
1535 s += MangleName("vmulx", typestr, ClassS) + "(__a, " +
1536 SplatLane(nElts, "__b", "__c") + ");";
1537 break;
Peter Collingbourne51d77772011-10-06 13:03:08 +00001538 case OpMul:
1539 s += "__a * __b;";
1540 break;
1541 case OpMullLane:
1542 s += MangleName("vmull", typestr, ClassS) + "(__a, " +
1543 SplatLane(nElts, "__b", "__c") + ");";
1544 break;
Jiangning Liu0aa1a882013-10-04 09:21:17 +00001545 case OpMullHiLane:
1546 s += MangleName("vmull", typestr, ClassS) + "(" +
1547 GetHigh("__a", typestr) + ", " + SplatLane(nElts, "__b", "__c") + ");";
1548 break;
Peter Collingbourne51d77772011-10-06 13:03:08 +00001549 case OpMlaN:
1550 s += "__a + (__b * " + Duplicate(nElts, typestr, "__c") + ");";
1551 break;
1552 case OpMlaLane:
1553 s += "__a + (__b * " + SplatLane(nElts, "__c", "__d") + ");";
1554 break;
1555 case OpMla:
1556 s += "__a + (__b * __c);";
1557 break;
1558 case OpMlalN:
1559 s += "__a + " + MangleName("vmull", typestr, ClassS) + "(__b, " +
1560 Duplicate(nElts, typestr, "__c") + ");";
1561 break;
1562 case OpMlalLane:
1563 s += "__a + " + MangleName("vmull", typestr, ClassS) + "(__b, " +
1564 SplatLane(nElts, "__c", "__d") + ");";
1565 break;
Jiangning Liu0aa1a882013-10-04 09:21:17 +00001566 case OpMlalHiLane:
1567 s += "__a + " + MangleName("vmull", typestr, ClassS) + "(" +
1568 GetHigh("__b", typestr) + ", " + SplatLane(nElts, "__c", "__d") + ");";
1569 break;
Peter Collingbourne51d77772011-10-06 13:03:08 +00001570 case OpMlal:
1571 s += "__a + " + MangleName("vmull", typestr, ClassS) + "(__b, __c);";
1572 break;
Jiangning Liu097a4b42013-09-09 02:21:08 +00001573 case OpMullHi:
1574 s += Gen2OpWith2High(typestr, "vmull", "__a", "__b");
1575 break;
1576 case OpMlalHi:
1577 s += Gen3OpWith2High(typestr, "vmlal", "__a", "__b", "__c");
1578 break;
Peter Collingbourne51d77772011-10-06 13:03:08 +00001579 case OpMlsN:
1580 s += "__a - (__b * " + Duplicate(nElts, typestr, "__c") + ");";
1581 break;
1582 case OpMlsLane:
1583 s += "__a - (__b * " + SplatLane(nElts, "__c", "__d") + ");";
1584 break;
Jiangning Liu0aa1a882013-10-04 09:21:17 +00001585 case OpFMSLane:
1586 s += TypeString(proto[1], typestr) + " __a1 = __a; \\\n ";
1587 s += TypeString(proto[2], typestr) + " __b1 = __b; \\\n ";
1588 s += TypeString(proto[3], typestr) + " __c1 = __c; \\\n ";
1589 s += MangleName("vfma_lane", typestr, ClassS) + "(__a1, __b1, -__c1, __d);";
1590 break;
1591 case OpFMSLaneQ:
1592 s += TypeString(proto[1], typestr) + " __a1 = __a; \\\n ";
1593 s += TypeString(proto[2], typestr) + " __b1 = __b; \\\n ";
1594 s += TypeString(proto[3], typestr) + " __c1 = __c; \\\n ";
1595 s += MangleName("vfma_laneq", typestr, ClassS) + "(__a1, __b1, -__c1, __d);";
1596 break;
Peter Collingbourne51d77772011-10-06 13:03:08 +00001597 case OpMls:
1598 s += "__a - (__b * __c);";
1599 break;
1600 case OpMlslN:
1601 s += "__a - " + MangleName("vmull", typestr, ClassS) + "(__b, " +
1602 Duplicate(nElts, typestr, "__c") + ");";
1603 break;
1604 case OpMlslLane:
1605 s += "__a - " + MangleName("vmull", typestr, ClassS) + "(__b, " +
1606 SplatLane(nElts, "__c", "__d") + ");";
1607 break;
Jiangning Liu0aa1a882013-10-04 09:21:17 +00001608 case OpMlslHiLane:
1609 s += "__a - " + MangleName("vmull", typestr, ClassS) + "(" +
1610 GetHigh("__b", typestr) + ", " + SplatLane(nElts, "__c", "__d") + ");";
1611 break;
Peter Collingbourne51d77772011-10-06 13:03:08 +00001612 case OpMlsl:
1613 s += "__a - " + MangleName("vmull", typestr, ClassS) + "(__b, __c);";
1614 break;
Jiangning Liu097a4b42013-09-09 02:21:08 +00001615 case OpMlslHi:
1616 s += Gen3OpWith2High(typestr, "vmlsl", "__a", "__b", "__c");
1617 break;
Peter Collingbourne51d77772011-10-06 13:03:08 +00001618 case OpQDMullLane:
1619 s += MangleName("vqdmull", typestr, ClassS) + "(__a, " +
1620 SplatLane(nElts, "__b", "__c") + ");";
1621 break;
Jiangning Liu0aa1a882013-10-04 09:21:17 +00001622 case OpQDMullHiLane:
1623 s += MangleName("vqdmull", typestr, ClassS) + "(" +
1624 GetHigh("__a", typestr) + ", " + SplatLane(nElts, "__b", "__c") + ");";
1625 break;
Peter Collingbourne51d77772011-10-06 13:03:08 +00001626 case OpQDMlalLane:
1627 s += MangleName("vqdmlal", typestr, ClassS) + "(__a, __b, " +
1628 SplatLane(nElts, "__c", "__d") + ");";
1629 break;
Jiangning Liu0aa1a882013-10-04 09:21:17 +00001630 case OpQDMlalHiLane:
1631 s += MangleName("vqdmlal", typestr, ClassS) + "(__a, " +
1632 GetHigh("__b", typestr) + ", " + SplatLane(nElts, "__c", "__d") + ");";
1633 break;
Peter Collingbourne51d77772011-10-06 13:03:08 +00001634 case OpQDMlslLane:
1635 s += MangleName("vqdmlsl", typestr, ClassS) + "(__a, __b, " +
1636 SplatLane(nElts, "__c", "__d") + ");";
1637 break;
Jiangning Liu0aa1a882013-10-04 09:21:17 +00001638 case OpQDMlslHiLane:
1639 s += MangleName("vqdmlsl", typestr, ClassS) + "(__a, " +
1640 GetHigh("__b", typestr) + ", " + SplatLane(nElts, "__c", "__d") + ");";
1641 break;
Peter Collingbourne51d77772011-10-06 13:03:08 +00001642 case OpQDMulhLane:
1643 s += MangleName("vqdmulh", typestr, ClassS) + "(__a, " +
1644 SplatLane(nElts, "__b", "__c") + ");";
1645 break;
1646 case OpQRDMulhLane:
1647 s += MangleName("vqrdmulh", typestr, ClassS) + "(__a, " +
1648 SplatLane(nElts, "__b", "__c") + ");";
1649 break;
1650 case OpEq:
1651 s += "(" + ts + ")(__a == __b);";
1652 break;
1653 case OpGe:
1654 s += "(" + ts + ")(__a >= __b);";
1655 break;
1656 case OpLe:
1657 s += "(" + ts + ")(__a <= __b);";
1658 break;
1659 case OpGt:
1660 s += "(" + ts + ")(__a > __b);";
1661 break;
1662 case OpLt:
1663 s += "(" + ts + ")(__a < __b);";
1664 break;
1665 case OpNeg:
1666 s += " -__a;";
1667 break;
1668 case OpNot:
1669 s += " ~__a;";
1670 break;
1671 case OpAnd:
1672 s += "__a & __b;";
1673 break;
1674 case OpOr:
1675 s += "__a | __b;";
1676 break;
1677 case OpXor:
1678 s += "__a ^ __b;";
1679 break;
1680 case OpAndNot:
1681 s += "__a & ~__b;";
1682 break;
1683 case OpOrNot:
1684 s += "__a | ~__b;";
1685 break;
1686 case OpCast:
1687 s += "(" + ts + ")__a;";
1688 break;
1689 case OpConcat:
1690 s += "(" + ts + ")__builtin_shufflevector((int64x1_t)__a";
1691 s += ", (int64x1_t)__b, 0, 1);";
1692 break;
1693 case OpHi:
Jim Grosbachcd765392013-05-15 02:40:04 +00001694 // nElts is for the result vector, so the source is twice that number.
1695 s += "__builtin_shufflevector(__a, __a";
1696 for (unsigned i = nElts; i < nElts * 2; ++i)
1697 s += ", " + utostr(i);
1698 s+= ");";
Peter Collingbourne51d77772011-10-06 13:03:08 +00001699 break;
1700 case OpLo:
Jim Grosbachcd765392013-05-15 02:40:04 +00001701 s += "__builtin_shufflevector(__a, __a";
1702 for (unsigned i = 0; i < nElts; ++i)
1703 s += ", " + utostr(i);
1704 s+= ");";
Peter Collingbourne51d77772011-10-06 13:03:08 +00001705 break;
1706 case OpDup:
1707 s += Duplicate(nElts, typestr, "__a") + ";";
1708 break;
1709 case OpDupLane:
1710 s += SplatLane(nElts, "__a", "__b") + ";";
1711 break;
1712 case OpSelect:
1713 // ((0 & 1) | (~0 & 2))
1714 s += "(" + ts + ")";
1715 ts = TypeString(proto[1], typestr);
1716 s += "((__a & (" + ts + ")__b) | ";
1717 s += "(~__a & (" + ts + ")__c));";
1718 break;
1719 case OpRev16:
1720 s += "__builtin_shufflevector(__a, __a";
1721 for (unsigned i = 2; i <= nElts; i += 2)
1722 for (unsigned j = 0; j != 2; ++j)
1723 s += ", " + utostr(i - j - 1);
1724 s += ");";
1725 break;
1726 case OpRev32: {
1727 unsigned WordElts = nElts >> (1 + (int)quad);
1728 s += "__builtin_shufflevector(__a, __a";
1729 for (unsigned i = WordElts; i <= nElts; i += WordElts)
1730 for (unsigned j = 0; j != WordElts; ++j)
1731 s += ", " + utostr(i - j - 1);
1732 s += ");";
1733 break;
1734 }
1735 case OpRev64: {
1736 unsigned DblWordElts = nElts >> (int)quad;
1737 s += "__builtin_shufflevector(__a, __a";
1738 for (unsigned i = DblWordElts; i <= nElts; i += DblWordElts)
1739 for (unsigned j = 0; j != DblWordElts; ++j)
1740 s += ", " + utostr(i - j - 1);
1741 s += ");";
1742 break;
1743 }
1744 case OpAbdl: {
1745 std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)";
1746 if (typestr[0] != 'U') {
1747 // vabd results are always unsigned and must be zero-extended.
1748 std::string utype = "U" + typestr.str();
1749 s += "(" + TypeString(proto[0], typestr) + ")";
1750 abd = "(" + TypeString('d', utype) + ")" + abd;
1751 s += Extend(utype, abd) + ";";
1752 } else {
1753 s += Extend(typestr, abd) + ";";
1754 }
1755 break;
1756 }
Jiangning Liu097a4b42013-09-09 02:21:08 +00001757 case OpAbdlHi:
1758 s += Gen2OpWith2High(typestr, "vabdl", "__a", "__b");
1759 break;
1760 case OpAddhnHi: {
1761 std::string addhn = MangleName("vaddhn", typestr, ClassS) + "(__b, __c)";
1762 s += GenCombine(GetNarrowTypestr(typestr), "__a", addhn);
1763 s += ";";
1764 break;
1765 }
1766 case OpRAddhnHi: {
1767 std::string raddhn = MangleName("vraddhn", typestr, ClassS) + "(__b, __c)";
1768 s += GenCombine(GetNarrowTypestr(typestr), "__a", raddhn);
1769 s += ";";
1770 break;
1771 }
1772 case OpSubhnHi: {
1773 std::string subhn = MangleName("vsubhn", typestr, ClassS) + "(__b, __c)";
1774 s += GenCombine(GetNarrowTypestr(typestr), "__a", subhn);
1775 s += ";";
1776 break;
1777 }
1778 case OpRSubhnHi: {
1779 std::string rsubhn = MangleName("vrsubhn", typestr, ClassS) + "(__b, __c)";
1780 s += GenCombine(GetNarrowTypestr(typestr), "__a", rsubhn);
1781 s += ";";
1782 break;
1783 }
Peter Collingbourne51d77772011-10-06 13:03:08 +00001784 case OpAba:
1785 s += "__a + " + MangleName("vabd", typestr, ClassS) + "(__b, __c);";
1786 break;
Jiangning Liu097a4b42013-09-09 02:21:08 +00001787 case OpAbal:
1788 s += "__a + " + MangleName("vabdl", typestr, ClassS) + "(__b, __c);";
Peter Collingbourne51d77772011-10-06 13:03:08 +00001789 break;
Jiangning Liu097a4b42013-09-09 02:21:08 +00001790 case OpAbalHi:
1791 s += Gen3OpWith2High(typestr, "vabal", "__a", "__b", "__c");
1792 break;
1793 case OpQDMullHi:
1794 s += Gen2OpWith2High(typestr, "vqdmull", "__a", "__b");
1795 break;
1796 case OpQDMlalHi:
1797 s += Gen3OpWith2High(typestr, "vqdmlal", "__a", "__b", "__c");
1798 break;
1799 case OpQDMlslHi:
1800 s += Gen3OpWith2High(typestr, "vqdmlsl", "__a", "__b", "__c");
1801 break;
Tim Northoverb793f0d2013-08-01 09:23:19 +00001802 case OpDiv:
1803 s += "__a / __b;";
1804 break;
Hao Liu912502b2013-09-04 09:29:13 +00001805 case OpMovlHi: {
1806 s = TypeString(proto[1], typestr.drop_front()) + " __a1 = " +
1807 MangleName("vget_high", typestr, ClassS) + "(__a);\n " + s;
1808 s += "(" + ts + ")" + MangleName("vshll_n", typestr, ClassS);
1809 s += "(__a1, 0);";
1810 break;
1811 }
1812 case OpLongHi: {
1813 // Another local variable __a1 is needed for calling a Macro,
1814 // or using __a will have naming conflict when Macro expanding.
1815 s += TypeString(proto[1], typestr.drop_front()) + " __a1 = " +
1816 MangleName("vget_high", typestr, ClassS) + "(__a); \\\n";
1817 s += " (" + ts + ")" + MangleName(RemoveHigh(name), typestr, ClassS) +
1818 "(__a1, __b);";
1819 break;
1820 }
1821 case OpNarrowHi: {
1822 s += "(" + ts + ")" + MangleName("vcombine", typestr, ClassS) + "(__a, " +
1823 MangleName(RemoveHigh(name), typestr, ClassS) + "(__b, __c));";
1824 break;
1825 }
Peter Collingbourne51d77772011-10-06 13:03:08 +00001826 default:
Joerg Sonnenberger38859ee2012-10-25 16:37:08 +00001827 PrintFatalError("unknown OpKind!");
Peter Collingbourne51d77772011-10-06 13:03:08 +00001828 }
1829 return s;
1830}
1831
1832static unsigned GetNeonEnum(const std::string &proto, StringRef typestr) {
1833 unsigned mod = proto[0];
Peter Collingbourne51d77772011-10-06 13:03:08 +00001834
1835 if (mod == 'v' || mod == 'f')
1836 mod = proto[1];
1837
1838 bool quad = false;
1839 bool poly = false;
1840 bool usgn = false;
1841 bool scal = false;
1842 bool cnst = false;
1843 bool pntr = false;
1844
1845 // Base type to get the type string for.
1846 char type = ClassifyType(typestr, quad, poly, usgn);
1847
1848 // Based on the modifying character, change the type and width if necessary.
1849 type = ModType(mod, type, quad, poly, usgn, scal, cnst, pntr);
1850
Bob Wilsonda95f732011-11-08 01:16:11 +00001851 NeonTypeFlags::EltType ET;
Peter Collingbourne51d77772011-10-06 13:03:08 +00001852 switch (type) {
1853 case 'c':
Bob Wilsonda95f732011-11-08 01:16:11 +00001854 ET = poly ? NeonTypeFlags::Poly8 : NeonTypeFlags::Int8;
Peter Collingbourne51d77772011-10-06 13:03:08 +00001855 break;
1856 case 's':
Bob Wilsonda95f732011-11-08 01:16:11 +00001857 ET = poly ? NeonTypeFlags::Poly16 : NeonTypeFlags::Int16;
Peter Collingbourne51d77772011-10-06 13:03:08 +00001858 break;
1859 case 'i':
Bob Wilsonda95f732011-11-08 01:16:11 +00001860 ET = NeonTypeFlags::Int32;
Peter Collingbourne51d77772011-10-06 13:03:08 +00001861 break;
1862 case 'l':
Bob Wilsonda95f732011-11-08 01:16:11 +00001863 ET = NeonTypeFlags::Int64;
Peter Collingbourne51d77772011-10-06 13:03:08 +00001864 break;
1865 case 'h':
Bob Wilsonda95f732011-11-08 01:16:11 +00001866 ET = NeonTypeFlags::Float16;
Peter Collingbourne51d77772011-10-06 13:03:08 +00001867 break;
1868 case 'f':
Bob Wilsonda95f732011-11-08 01:16:11 +00001869 ET = NeonTypeFlags::Float32;
Peter Collingbourne51d77772011-10-06 13:03:08 +00001870 break;
Tim Northoverb793f0d2013-08-01 09:23:19 +00001871 case 'd':
1872 ET = NeonTypeFlags::Float64;
1873 break;
Peter Collingbourne51d77772011-10-06 13:03:08 +00001874 default:
Joerg Sonnenberger38859ee2012-10-25 16:37:08 +00001875 PrintFatalError("unhandled type!");
Peter Collingbourne51d77772011-10-06 13:03:08 +00001876 }
Bob Wilsonda95f732011-11-08 01:16:11 +00001877 NeonTypeFlags Flags(ET, usgn, quad && proto[1] != 'g');
1878 return Flags.getFlags();
Peter Collingbourne51d77772011-10-06 13:03:08 +00001879}
1880
1881// Generate the definition for this intrinsic, e.g. __builtin_neon_cls(a)
1882static std::string GenBuiltin(const std::string &name, const std::string &proto,
1883 StringRef typestr, ClassKind ck) {
1884 std::string s;
1885
1886 // If this builtin returns a struct 2, 3, or 4 vectors, pass it as an implicit
1887 // sret-like argument.
1888 bool sret = (proto[0] >= '2' && proto[0] <= '4');
1889
1890 bool define = UseMacro(proto);
1891
1892 // Check if the prototype has a scalar operand with the type of the vector
1893 // elements. If not, bitcasting the args will take care of arg checking.
1894 // The actual signedness etc. will be taken care of with special enums.
1895 if (proto.find('s') == std::string::npos)
1896 ck = ClassB;
1897
1898 if (proto[0] != 'v') {
1899 std::string ts = TypeString(proto[0], typestr);
1900
1901 if (define) {
1902 if (sret)
1903 s += ts + " r; ";
1904 else
1905 s += "(" + ts + ")";
1906 } else if (sret) {
1907 s += ts + " r; ";
1908 } else {
1909 s += "return (" + ts + ")";
1910 }
1911 }
1912
1913 bool splat = proto.find('a') != std::string::npos;
1914
1915 s += "__builtin_neon_";
1916 if (splat) {
1917 // Call the non-splat builtin: chop off the "_n" suffix from the name.
1918 std::string vname(name, 0, name.size()-2);
1919 s += MangleName(vname, typestr, ck);
1920 } else {
1921 s += MangleName(name, typestr, ck);
1922 }
1923 s += "(";
1924
1925 // Pass the address of the return variable as the first argument to sret-like
1926 // builtins.
1927 if (sret)
1928 s += "&r, ";
1929
1930 char arg = 'a';
1931 for (unsigned i = 1, e = proto.size(); i != e; ++i, ++arg) {
1932 std::string args = std::string(&arg, 1);
1933
1934 // Use the local temporaries instead of the macro arguments.
1935 args = "__" + args;
1936
1937 bool argQuad = false;
1938 bool argPoly = false;
1939 bool argUsgn = false;
1940 bool argScalar = false;
1941 bool dummy = false;
1942 char argType = ClassifyType(typestr, argQuad, argPoly, argUsgn);
1943 argType = ModType(proto[i], argType, argQuad, argPoly, argUsgn, argScalar,
1944 dummy, dummy);
1945
1946 // Handle multiple-vector values specially, emitting each subvector as an
1947 // argument to the __builtin.
1948 if (proto[i] >= '2' && proto[i] <= '4') {
1949 // Check if an explicit cast is needed.
1950 if (argType != 'c' || argPoly || argUsgn)
1951 args = (argQuad ? "(int8x16_t)" : "(int8x8_t)") + args;
1952
1953 for (unsigned vi = 0, ve = proto[i] - '0'; vi != ve; ++vi) {
1954 s += args + ".val[" + utostr(vi) + "]";
1955 if ((vi + 1) < ve)
1956 s += ", ";
1957 }
1958 if ((i + 1) < e)
1959 s += ", ";
1960
1961 continue;
1962 }
1963
1964 if (splat && (i + 1) == e)
1965 args = Duplicate(GetNumElements(typestr, argQuad), typestr, args);
1966
1967 // Check if an explicit cast is needed.
1968 if ((splat || !argScalar) &&
1969 ((ck == ClassB && argType != 'c') || argPoly || argUsgn)) {
1970 std::string argTypeStr = "c";
1971 if (ck != ClassB)
1972 argTypeStr = argType;
1973 if (argQuad)
1974 argTypeStr = "Q" + argTypeStr;
1975 args = "(" + TypeString('d', argTypeStr) + ")" + args;
1976 }
1977
1978 s += args;
1979 if ((i + 1) < e)
1980 s += ", ";
1981 }
1982
1983 // Extra constant integer to hold type class enum for this function, e.g. s8
1984 if (ck == ClassB)
1985 s += ", " + utostr(GetNeonEnum(proto, typestr));
1986
1987 s += ");";
1988
1989 if (proto[0] != 'v' && sret) {
1990 if (define)
1991 s += " r;";
1992 else
1993 s += " return r;";
1994 }
1995 return s;
1996}
1997
1998static std::string GenBuiltinDef(const std::string &name,
1999 const std::string &proto,
2000 StringRef typestr, ClassKind ck) {
2001 std::string s("BUILTIN(__builtin_neon_");
2002
2003 // If all types are the same size, bitcasting the args will take care
2004 // of arg checking. The actual signedness etc. will be taken care of with
2005 // special enums.
2006 if (proto.find('s') == std::string::npos)
2007 ck = ClassB;
2008
2009 s += MangleName(name, typestr, ck);
2010 s += ", \"";
2011
2012 for (unsigned i = 0, e = proto.size(); i != e; ++i)
2013 s += BuiltinTypeString(proto[i], typestr, ck, i == 0);
2014
2015 // Extra constant integer to hold type class enum for this function, e.g. s8
2016 if (ck == ClassB)
2017 s += "i";
2018
2019 s += "\", \"n\")";
2020 return s;
2021}
2022
2023static std::string GenIntrinsic(const std::string &name,
2024 const std::string &proto,
2025 StringRef outTypeStr, StringRef inTypeStr,
2026 OpKind kind, ClassKind classKind) {
2027 assert(!proto.empty() && "");
Jim Grosbach667381b2012-05-09 18:17:30 +00002028 bool define = UseMacro(proto) && kind != OpUnavailable;
Peter Collingbourne51d77772011-10-06 13:03:08 +00002029 std::string s;
2030
2031 // static always inline + return type
2032 if (define)
2033 s += "#define ";
2034 else
2035 s += "__ai " + TypeString(proto[0], outTypeStr) + " ";
2036
2037 // Function name with type suffix
2038 std::string mangledName = MangleName(name, outTypeStr, ClassS);
2039 if (outTypeStr != inTypeStr) {
2040 // If the input type is different (e.g., for vreinterpret), append a suffix
2041 // for the input type. String off a "Q" (quad) prefix so that MangleName
2042 // does not insert another "q" in the name.
2043 unsigned typeStrOff = (inTypeStr[0] == 'Q' ? 1 : 0);
2044 StringRef inTypeNoQuad = inTypeStr.substr(typeStrOff);
2045 mangledName = MangleName(mangledName, inTypeNoQuad, ClassS);
2046 }
2047 s += mangledName;
2048
2049 // Function arguments
2050 s += GenArgs(proto, inTypeStr);
2051
2052 // Definition.
2053 if (define) {
2054 s += " __extension__ ({ \\\n ";
2055 s += GenMacroLocals(proto, inTypeStr);
Jim Grosbach667381b2012-05-09 18:17:30 +00002056 } else if (kind == OpUnavailable) {
2057 s += " __attribute__((unavailable));\n";
2058 return s;
2059 } else
Jim Grosbach66981c72012-08-03 17:30:46 +00002060 s += " {\n ";
Peter Collingbourne51d77772011-10-06 13:03:08 +00002061
2062 if (kind != OpNone)
Hao Liu912502b2013-09-04 09:29:13 +00002063 s += GenOpString(name, kind, proto, outTypeStr);
Peter Collingbourne51d77772011-10-06 13:03:08 +00002064 else
2065 s += GenBuiltin(name, proto, outTypeStr, classKind);
2066 if (define)
2067 s += " })";
2068 else
2069 s += " }";
2070 s += "\n";
2071 return s;
2072}
2073
2074/// run - Read the records in arm_neon.td and output arm_neon.h. arm_neon.h
2075/// is comprised of type definitions and function declarations.
2076void NeonEmitter::run(raw_ostream &OS) {
2077 OS <<
2078 "/*===---- arm_neon.h - ARM Neon intrinsics ------------------------------"
2079 "---===\n"
2080 " *\n"
2081 " * Permission is hereby granted, free of charge, to any person obtaining "
2082 "a copy\n"
2083 " * of this software and associated documentation files (the \"Software\"),"
2084 " to deal\n"
2085 " * in the Software without restriction, including without limitation the "
2086 "rights\n"
2087 " * to use, copy, modify, merge, publish, distribute, sublicense, "
2088 "and/or sell\n"
2089 " * copies of the Software, and to permit persons to whom the Software is\n"
2090 " * furnished to do so, subject to the following conditions:\n"
2091 " *\n"
2092 " * The above copyright notice and this permission notice shall be "
2093 "included in\n"
2094 " * all copies or substantial portions of the Software.\n"
2095 " *\n"
2096 " * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, "
2097 "EXPRESS OR\n"
2098 " * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF "
2099 "MERCHANTABILITY,\n"
2100 " * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT "
2101 "SHALL THE\n"
2102 " * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR "
2103 "OTHER\n"
2104 " * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, "
2105 "ARISING FROM,\n"
2106 " * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER "
2107 "DEALINGS IN\n"
2108 " * THE SOFTWARE.\n"
2109 " *\n"
2110 " *===--------------------------------------------------------------------"
2111 "---===\n"
2112 " */\n\n";
2113
2114 OS << "#ifndef __ARM_NEON_H\n";
2115 OS << "#define __ARM_NEON_H\n\n";
2116
Tim Northoverb793f0d2013-08-01 09:23:19 +00002117 OS << "#if !defined(__ARM_NEON__) && !defined(__AARCH_FEATURE_ADVSIMD)\n";
Peter Collingbourne51d77772011-10-06 13:03:08 +00002118 OS << "#error \"NEON support not enabled\"\n";
2119 OS << "#endif\n\n";
2120
2121 OS << "#include <stdint.h>\n\n";
2122
2123 // Emit NEON-specific scalar typedefs.
2124 OS << "typedef float float32_t;\n";
Tim Northoverb793f0d2013-08-01 09:23:19 +00002125 OS << "typedef __fp16 float16_t;\n";
2126
2127 OS << "#ifdef __aarch64__\n";
2128 OS << "typedef double float64_t;\n";
2129 OS << "#endif\n\n";
2130
2131 // For now, signedness of polynomial types depends on target
2132 OS << "#ifdef __aarch64__\n";
2133 OS << "typedef uint8_t poly8_t;\n";
2134 OS << "typedef uint16_t poly16_t;\n";
2135 OS << "#else\n";
Peter Collingbourne51d77772011-10-06 13:03:08 +00002136 OS << "typedef int8_t poly8_t;\n";
2137 OS << "typedef int16_t poly16_t;\n";
Tim Northoverb793f0d2013-08-01 09:23:19 +00002138 OS << "#endif\n";
Peter Collingbourne51d77772011-10-06 13:03:08 +00002139
2140 // Emit Neon vector typedefs.
Tim Northoverb793f0d2013-08-01 09:23:19 +00002141 std::string TypedefTypes(
Jiangning Liu0aa1a882013-10-04 09:21:17 +00002142 "cQcsQsiQilQlUcQUcUsQUsUiQUiUlQUlhQhfQfdQdPcQPcPsQPs");
Peter Collingbourne51d77772011-10-06 13:03:08 +00002143 SmallVector<StringRef, 24> TDTypeVec;
2144 ParseTypes(0, TypedefTypes, TDTypeVec);
2145
2146 // Emit vector typedefs.
Jiangning Liu0aa1a882013-10-04 09:21:17 +00002147 bool isA64 = false;
Peter Collingbourne51d77772011-10-06 13:03:08 +00002148 for (unsigned i = 0, e = TDTypeVec.size(); i != e; ++i) {
2149 bool dummy, quad = false, poly = false;
Tim Northoverb793f0d2013-08-01 09:23:19 +00002150 char type = ClassifyType(TDTypeVec[i], quad, poly, dummy);
Jiangning Liu0aa1a882013-10-04 09:21:17 +00002151 bool preinsert = false;
2152 bool postinsert = false;
Tim Northoverb793f0d2013-08-01 09:23:19 +00002153
Jiangning Liu0aa1a882013-10-04 09:21:17 +00002154 if (type == 'd') {
2155 preinsert = isA64? false: true;
Tim Northoverb793f0d2013-08-01 09:23:19 +00002156 isA64 = true;
Jiangning Liu0aa1a882013-10-04 09:21:17 +00002157 } else {
2158 postinsert = isA64? true: false;
2159 isA64 = false;
2160 }
2161 if (postinsert)
2162 OS << "#endif\n";
2163 if (preinsert)
Tim Northoverb793f0d2013-08-01 09:23:19 +00002164 OS << "#ifdef __aarch64__\n";
2165
Peter Collingbourne51d77772011-10-06 13:03:08 +00002166 if (poly)
2167 OS << "typedef __attribute__((neon_polyvector_type(";
2168 else
2169 OS << "typedef __attribute__((neon_vector_type(";
2170
2171 unsigned nElts = GetNumElements(TDTypeVec[i], quad);
2172 OS << utostr(nElts) << "))) ";
2173 if (nElts < 10)
2174 OS << " ";
2175
2176 OS << TypeString('s', TDTypeVec[i]);
2177 OS << " " << TypeString('d', TDTypeVec[i]) << ";\n";
Tim Northoverb793f0d2013-08-01 09:23:19 +00002178
Peter Collingbourne51d77772011-10-06 13:03:08 +00002179 }
2180 OS << "\n";
2181
2182 // Emit struct typedefs.
Jiangning Liu0aa1a882013-10-04 09:21:17 +00002183 isA64 = false;
Peter Collingbourne51d77772011-10-06 13:03:08 +00002184 for (unsigned vi = 2; vi != 5; ++vi) {
2185 for (unsigned i = 0, e = TDTypeVec.size(); i != e; ++i) {
Tim Northoverb793f0d2013-08-01 09:23:19 +00002186 bool dummy, quad = false, poly = false;
2187 char type = ClassifyType(TDTypeVec[i], quad, poly, dummy);
Jiangning Liu0aa1a882013-10-04 09:21:17 +00002188 bool preinsert = false;
2189 bool postinsert = false;
Tim Northoverb793f0d2013-08-01 09:23:19 +00002190
Jiangning Liu0aa1a882013-10-04 09:21:17 +00002191 if (type == 'd') {
2192 preinsert = isA64? false: true;
Tim Northoverb793f0d2013-08-01 09:23:19 +00002193 isA64 = true;
Jiangning Liu0aa1a882013-10-04 09:21:17 +00002194 } else {
2195 postinsert = isA64? true: false;
2196 isA64 = false;
2197 }
2198 if (postinsert)
2199 OS << "#endif\n";
2200 if (preinsert)
Tim Northoverb793f0d2013-08-01 09:23:19 +00002201 OS << "#ifdef __aarch64__\n";
2202
Peter Collingbourne51d77772011-10-06 13:03:08 +00002203 std::string ts = TypeString('d', TDTypeVec[i]);
2204 std::string vs = TypeString('0' + vi, TDTypeVec[i]);
2205 OS << "typedef struct " << vs << " {\n";
2206 OS << " " << ts << " val";
2207 OS << "[" << utostr(vi) << "]";
2208 OS << ";\n} ";
Tim Northoverb793f0d2013-08-01 09:23:19 +00002209 OS << vs << ";\n";
Tim Northoverb793f0d2013-08-01 09:23:19 +00002210 OS << "\n";
Peter Collingbourne51d77772011-10-06 13:03:08 +00002211 }
2212 }
2213
Bob Wilson1e8058f2013-04-12 20:17:20 +00002214 OS<<"#define __ai static inline __attribute__((__always_inline__, __nodebug__))\n\n";
Peter Collingbourne51d77772011-10-06 13:03:08 +00002215
2216 std::vector<Record*> RV = Records.getAllDerivedDefinitions("Inst");
2217
Tim Northoverb793f0d2013-08-01 09:23:19 +00002218 StringMap<ClassKind> EmittedMap;
2219
Peter Collingbourne51d77772011-10-06 13:03:08 +00002220 // Emit vmovl, vmull and vabd intrinsics first so they can be used by other
2221 // intrinsics. (Some of the saturating multiply instructions are also
2222 // used to implement the corresponding "_lane" variants, but tablegen
2223 // sorts the records into alphabetical order so that the "_lane" variants
2224 // come after the intrinsics they use.)
Tim Northoverb793f0d2013-08-01 09:23:19 +00002225 emitIntrinsic(OS, Records.getDef("VMOVL"), EmittedMap);
2226 emitIntrinsic(OS, Records.getDef("VMULL"), EmittedMap);
2227 emitIntrinsic(OS, Records.getDef("VABD"), EmittedMap);
Jiangning Liu097a4b42013-09-09 02:21:08 +00002228 emitIntrinsic(OS, Records.getDef("VABDL"), EmittedMap);
Tim Northoverb793f0d2013-08-01 09:23:19 +00002229
2230 // ARM intrinsics must be emitted before AArch64 intrinsics to ensure
2231 // common intrinsics appear only once in the output stream.
2232 // The check for uniquiness is done in emitIntrinsic.
2233 // Emit ARM intrinsics.
2234 for (unsigned i = 0, e = RV.size(); i != e; ++i) {
2235 Record *R = RV[i];
2236
2237 // Skip AArch64 intrinsics; they will be emitted at the end.
2238 bool isA64 = R->getValueAsBit("isA64");
2239 if (isA64)
2240 continue;
2241
2242 if (R->getName() != "VMOVL" && R->getName() != "VMULL" &&
2243 R->getName() != "VABD")
2244 emitIntrinsic(OS, R, EmittedMap);
2245 }
2246
2247 // Emit AArch64-specific intrinsics.
2248 OS << "#ifdef __aarch64__\n";
Peter Collingbourne51d77772011-10-06 13:03:08 +00002249
Jiangning Liu097a4b42013-09-09 02:21:08 +00002250 emitIntrinsic(OS, Records.getDef("VMOVL_HIGH"), EmittedMap);
2251 emitIntrinsic(OS, Records.getDef("VMULL_HIGH"), EmittedMap);
2252 emitIntrinsic(OS, Records.getDef("VABDL_HIGH"), EmittedMap);
2253
Peter Collingbourne51d77772011-10-06 13:03:08 +00002254 for (unsigned i = 0, e = RV.size(); i != e; ++i) {
2255 Record *R = RV[i];
Tim Northoverb793f0d2013-08-01 09:23:19 +00002256
2257 // Skip ARM intrinsics already included above.
2258 bool isA64 = R->getValueAsBit("isA64");
2259 if (!isA64)
2260 continue;
2261
2262 emitIntrinsic(OS, R, EmittedMap);
Peter Collingbourne51d77772011-10-06 13:03:08 +00002263 }
2264
Tim Northoverb793f0d2013-08-01 09:23:19 +00002265 OS << "#endif\n\n";
2266
Peter Collingbourne51d77772011-10-06 13:03:08 +00002267 OS << "#undef __ai\n\n";
2268 OS << "#endif /* __ARM_NEON_H */\n";
2269}
2270
2271/// emitIntrinsic - Write out the arm_neon.h header file definitions for the
Tim Northoverb793f0d2013-08-01 09:23:19 +00002272/// intrinsics specified by record R checking for intrinsic uniqueness.
2273void NeonEmitter::emitIntrinsic(raw_ostream &OS, Record *R,
2274 StringMap<ClassKind> &EmittedMap) {
Peter Collingbourne51d77772011-10-06 13:03:08 +00002275 std::string name = R->getValueAsString("Name");
2276 std::string Proto = R->getValueAsString("Prototype");
2277 std::string Types = R->getValueAsString("Types");
2278
2279 SmallVector<StringRef, 16> TypeVec;
2280 ParseTypes(R, Types, TypeVec);
2281
2282 OpKind kind = OpMap[R->getValueAsDef("Operand")->getName()];
2283
2284 ClassKind classKind = ClassNone;
2285 if (R->getSuperClasses().size() >= 2)
2286 classKind = ClassMap[R->getSuperClasses()[1]];
2287 if (classKind == ClassNone && kind == OpNone)
Joerg Sonnenberger38859ee2012-10-25 16:37:08 +00002288 PrintFatalError(R->getLoc(), "Builtin has no class kind");
Peter Collingbourne51d77772011-10-06 13:03:08 +00002289
2290 for (unsigned ti = 0, te = TypeVec.size(); ti != te; ++ti) {
2291 if (kind == OpReinterpret) {
2292 bool outQuad = false;
2293 bool dummy = false;
2294 (void)ClassifyType(TypeVec[ti], outQuad, dummy, dummy);
2295 for (unsigned srcti = 0, srcte = TypeVec.size();
2296 srcti != srcte; ++srcti) {
2297 bool inQuad = false;
2298 (void)ClassifyType(TypeVec[srcti], inQuad, dummy, dummy);
2299 if (srcti == ti || inQuad != outQuad)
2300 continue;
Tim Northoverb793f0d2013-08-01 09:23:19 +00002301 std::string s = GenIntrinsic(name, Proto, TypeVec[ti], TypeVec[srcti],
2302 OpCast, ClassS);
2303 if (EmittedMap.count(s))
2304 continue;
2305 EmittedMap[s] = ClassS;
2306 OS << s;
Peter Collingbourne51d77772011-10-06 13:03:08 +00002307 }
2308 } else {
Tim Northoverb793f0d2013-08-01 09:23:19 +00002309 std::string s =
2310 GenIntrinsic(name, Proto, TypeVec[ti], TypeVec[ti], kind, classKind);
2311 if (EmittedMap.count(s))
2312 continue;
2313 EmittedMap[s] = classKind;
2314 OS << s;
Peter Collingbourne51d77772011-10-06 13:03:08 +00002315 }
2316 }
2317 OS << "\n";
2318}
2319
2320static unsigned RangeFromType(const char mod, StringRef typestr) {
2321 // base type to get the type string for.
2322 bool quad = false, dummy = false;
2323 char type = ClassifyType(typestr, quad, dummy, dummy);
2324 type = ModType(mod, type, quad, dummy, dummy, dummy, dummy, dummy);
2325
2326 switch (type) {
2327 case 'c':
2328 return (8 << (int)quad) - 1;
2329 case 'h':
2330 case 's':
2331 return (4 << (int)quad) - 1;
2332 case 'f':
2333 case 'i':
2334 return (2 << (int)quad) - 1;
Jiangning Liu0aa1a882013-10-04 09:21:17 +00002335 case 'd':
Peter Collingbourne51d77772011-10-06 13:03:08 +00002336 case 'l':
2337 return (1 << (int)quad) - 1;
2338 default:
Joerg Sonnenberger38859ee2012-10-25 16:37:08 +00002339 PrintFatalError("unhandled type!");
Peter Collingbourne51d77772011-10-06 13:03:08 +00002340 }
Peter Collingbourne51d77772011-10-06 13:03:08 +00002341}
2342
Tim Northoverb793f0d2013-08-01 09:23:19 +00002343/// Generate the ARM and AArch64 intrinsic range checking code for
2344/// shift/lane immediates, checking for unique declarations.
2345void
2346NeonEmitter::genIntrinsicRangeCheckCode(raw_ostream &OS,
2347 StringMap<ClassKind> &A64IntrinsicMap,
2348 bool isA64RangeCheck) {
2349 std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst");
Peter Collingbourne51d77772011-10-06 13:03:08 +00002350 StringMap<OpKind> EmittedMap;
2351
Tim Northoverb793f0d2013-08-01 09:23:19 +00002352 // Generate the intrinsic range checking code for shift/lane immediates.
2353 if (isA64RangeCheck)
2354 OS << "#ifdef GET_NEON_AARCH64_IMMEDIATE_CHECK\n";
2355 else
2356 OS << "#ifdef GET_NEON_IMMEDIATE_CHECK\n";
2357
Peter Collingbourne51d77772011-10-06 13:03:08 +00002358 for (unsigned i = 0, e = RV.size(); i != e; ++i) {
2359 Record *R = RV[i];
Tim Northoverb793f0d2013-08-01 09:23:19 +00002360
Peter Collingbourne51d77772011-10-06 13:03:08 +00002361 OpKind k = OpMap[R->getValueAsDef("Operand")->getName()];
2362 if (k != OpNone)
2363 continue;
2364
Tim Northoverb793f0d2013-08-01 09:23:19 +00002365 std::string name = R->getValueAsString("Name");
Peter Collingbourne51d77772011-10-06 13:03:08 +00002366 std::string Proto = R->getValueAsString("Prototype");
Tim Northoverb793f0d2013-08-01 09:23:19 +00002367 std::string Types = R->getValueAsString("Types");
Kevin Qin944f09f2013-08-29 07:55:15 +00002368 std::string Rename = name + "@" + Proto;
Peter Collingbourne51d77772011-10-06 13:03:08 +00002369
2370 // Functions with 'a' (the splat code) in the type prototype should not get
2371 // their own builtin as they use the non-splat variant.
2372 if (Proto.find('a') != std::string::npos)
2373 continue;
2374
Tim Northoverb793f0d2013-08-01 09:23:19 +00002375 // Functions which do not have an immediate do not need to have range
2376 // checking code emitted.
2377 size_t immPos = Proto.find('i');
2378 if (immPos == std::string::npos)
2379 continue;
2380
Peter Collingbourne51d77772011-10-06 13:03:08 +00002381 SmallVector<StringRef, 16> TypeVec;
2382 ParseTypes(R, Types, TypeVec);
2383
2384 if (R->getSuperClasses().size() < 2)
Joerg Sonnenberger38859ee2012-10-25 16:37:08 +00002385 PrintFatalError(R->getLoc(), "Builtin has no class kind");
Peter Collingbourne51d77772011-10-06 13:03:08 +00002386
Peter Collingbourne51d77772011-10-06 13:03:08 +00002387 ClassKind ck = ClassMap[R->getSuperClasses()[1]];
2388
Tim Northoverb793f0d2013-08-01 09:23:19 +00002389 // Do not include AArch64 range checks if not generating code for AArch64.
2390 bool isA64 = R->getValueAsBit("isA64");
2391 if (!isA64RangeCheck && isA64)
2392 continue;
Peter Collingbourne51d77772011-10-06 13:03:08 +00002393
Tim Northoverb793f0d2013-08-01 09:23:19 +00002394 // Include ARM range checks in AArch64 but only if ARM intrinsics are not
2395 // redefined by AArch64 to handle new types.
Kevin Qin944f09f2013-08-29 07:55:15 +00002396 if (isA64RangeCheck && !isA64 && A64IntrinsicMap.count(Rename)) {
2397 ClassKind &A64CK = A64IntrinsicMap[Rename];
Tim Northoverb793f0d2013-08-01 09:23:19 +00002398 if (A64CK == ck && ck != ClassNone)
2399 continue;
2400 }
2401
2402 for (unsigned ti = 0, te = TypeVec.size(); ti != te; ++ti) {
2403 std::string namestr, shiftstr, rangestr;
2404
2405 if (R->getValueAsBit("isVCVT_N")) {
2406 // VCVT between floating- and fixed-point values takes an immediate
Hao Liu912502b2013-09-04 09:29:13 +00002407 // in the range [1, 32] for f32, or [1, 64] for f64.
Tim Northoverb793f0d2013-08-01 09:23:19 +00002408 ck = ClassB;
Hao Liu912502b2013-09-04 09:29:13 +00002409 if (name.find("32") != std::string::npos)
2410 rangestr = "l = 1; u = 31"; // upper bound = l + u
2411 else if (name.find("64") != std::string::npos)
2412 rangestr = "l = 1; u = 63";
2413 else
2414 PrintFatalError(R->getLoc(),
2415 "Fixed point convert name should contains \"32\" or \"64\"");
Tim Northoverb793f0d2013-08-01 09:23:19 +00002416 } else if (Proto.find('s') == std::string::npos) {
2417 // Builtins which are overloaded by type will need to have their upper
2418 // bound computed at Sema time based on the type constant.
2419 ck = ClassB;
2420 if (R->getValueAsBit("isShift")) {
2421 shiftstr = ", true";
2422
2423 // Right shifts have an 'r' in the name, left shifts do not.
2424 if (name.find('r') != std::string::npos)
2425 rangestr = "l = 1; ";
2426 }
2427 rangestr += "u = RFT(TV" + shiftstr + ")";
2428 } else {
2429 // The immediate generally refers to a lane in the preceding argument.
2430 assert(immPos > 0 && "unexpected immediate operand");
2431 rangestr =
2432 "u = " + utostr(RangeFromType(Proto[immPos - 1], TypeVec[ti]));
2433 }
2434 // Make sure cases appear only once by uniquing them in a string map.
2435 namestr = MangleName(name, TypeVec[ti], ck);
2436 if (EmittedMap.count(namestr))
2437 continue;
2438 EmittedMap[namestr] = OpNone;
2439
2440 // Calculate the index of the immediate that should be range checked.
2441 unsigned immidx = 0;
2442
2443 // Builtins that return a struct of multiple vectors have an extra
2444 // leading arg for the struct return.
2445 if (Proto[0] >= '2' && Proto[0] <= '4')
2446 ++immidx;
2447
2448 // Add one to the index for each argument until we reach the immediate
2449 // to be checked. Structs of vectors are passed as multiple arguments.
2450 for (unsigned ii = 1, ie = Proto.size(); ii != ie; ++ii) {
2451 switch (Proto[ii]) {
2452 default:
2453 immidx += 1;
2454 break;
2455 case '2':
2456 immidx += 2;
2457 break;
2458 case '3':
2459 immidx += 3;
2460 break;
2461 case '4':
2462 immidx += 4;
2463 break;
2464 case 'i':
2465 ie = ii + 1;
2466 break;
2467 }
2468 }
2469 if (isA64RangeCheck)
2470 OS << "case AArch64::BI__builtin_neon_";
2471 else
2472 OS << "case ARM::BI__builtin_neon_";
2473 OS << MangleName(name, TypeVec[ti], ck) << ": i = " << immidx << "; "
2474 << rangestr << "; break;\n";
Peter Collingbourne51d77772011-10-06 13:03:08 +00002475 }
2476 }
2477 OS << "#endif\n\n";
Tim Northoverb793f0d2013-08-01 09:23:19 +00002478}
2479
2480/// Generate the ARM and AArch64 overloaded type checking code for
2481/// SemaChecking.cpp, checking for unique builtin declarations.
2482void
2483NeonEmitter::genOverloadTypeCheckCode(raw_ostream &OS,
2484 StringMap<ClassKind> &A64IntrinsicMap,
2485 bool isA64TypeCheck) {
2486 std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst");
2487 StringMap<OpKind> EmittedMap;
Peter Collingbourne51d77772011-10-06 13:03:08 +00002488
2489 // Generate the overloaded type checking code for SemaChecking.cpp
Tim Northoverb793f0d2013-08-01 09:23:19 +00002490 if (isA64TypeCheck)
2491 OS << "#ifdef GET_NEON_AARCH64_OVERLOAD_CHECK\n";
2492 else
2493 OS << "#ifdef GET_NEON_OVERLOAD_CHECK\n";
2494
Peter Collingbourne51d77772011-10-06 13:03:08 +00002495 for (unsigned i = 0, e = RV.size(); i != e; ++i) {
2496 Record *R = RV[i];
2497 OpKind k = OpMap[R->getValueAsDef("Operand")->getName()];
2498 if (k != OpNone)
2499 continue;
2500
2501 std::string Proto = R->getValueAsString("Prototype");
2502 std::string Types = R->getValueAsString("Types");
2503 std::string name = R->getValueAsString("Name");
Kevin Qin944f09f2013-08-29 07:55:15 +00002504 std::string Rename = name + "@" + Proto;
2505
Peter Collingbourne51d77772011-10-06 13:03:08 +00002506 // Functions with 'a' (the splat code) in the type prototype should not get
2507 // their own builtin as they use the non-splat variant.
2508 if (Proto.find('a') != std::string::npos)
2509 continue;
2510
2511 // Functions which have a scalar argument cannot be overloaded, no need to
2512 // check them if we are emitting the type checking code.
2513 if (Proto.find('s') != std::string::npos)
2514 continue;
2515
2516 SmallVector<StringRef, 16> TypeVec;
2517 ParseTypes(R, Types, TypeVec);
2518
2519 if (R->getSuperClasses().size() < 2)
Joerg Sonnenberger38859ee2012-10-25 16:37:08 +00002520 PrintFatalError(R->getLoc(), "Builtin has no class kind");
Peter Collingbourne51d77772011-10-06 13:03:08 +00002521
Tim Northoverb793f0d2013-08-01 09:23:19 +00002522 // Do not include AArch64 type checks if not generating code for AArch64.
2523 bool isA64 = R->getValueAsBit("isA64");
2524 if (!isA64TypeCheck && isA64)
2525 continue;
2526
2527 // Include ARM type check in AArch64 but only if ARM intrinsics
2528 // are not redefined in AArch64 to handle new types, e.g. "vabd" is a SIntr
2529 // redefined in AArch64 to handle an additional 2 x f64 type.
2530 ClassKind ck = ClassMap[R->getSuperClasses()[1]];
Kevin Qin944f09f2013-08-29 07:55:15 +00002531 if (isA64TypeCheck && !isA64 && A64IntrinsicMap.count(Rename)) {
2532 ClassKind &A64CK = A64IntrinsicMap[Rename];
Tim Northoverb793f0d2013-08-01 09:23:19 +00002533 if (A64CK == ck && ck != ClassNone)
2534 continue;
2535 }
2536
Peter Collingbourne51d77772011-10-06 13:03:08 +00002537 int si = -1, qi = -1;
Richard Smithf8ee6bc2012-08-14 01:28:02 +00002538 uint64_t mask = 0, qmask = 0;
Peter Collingbourne51d77772011-10-06 13:03:08 +00002539 for (unsigned ti = 0, te = TypeVec.size(); ti != te; ++ti) {
2540 // Generate the switch case(s) for this builtin for the type validation.
2541 bool quad = false, poly = false, usgn = false;
2542 (void) ClassifyType(TypeVec[ti], quad, poly, usgn);
2543
2544 if (quad) {
2545 qi = ti;
Richard Smithf8ee6bc2012-08-14 01:28:02 +00002546 qmask |= 1ULL << GetNeonEnum(Proto, TypeVec[ti]);
Peter Collingbourne51d77772011-10-06 13:03:08 +00002547 } else {
2548 si = ti;
Richard Smithf8ee6bc2012-08-14 01:28:02 +00002549 mask |= 1ULL << GetNeonEnum(Proto, TypeVec[ti]);
Peter Collingbourne51d77772011-10-06 13:03:08 +00002550 }
2551 }
Bob Wilson46482552011-11-16 21:32:23 +00002552
2553 // Check if the builtin function has a pointer or const pointer argument.
2554 int PtrArgNum = -1;
2555 bool HasConstPtr = false;
2556 for (unsigned arg = 1, arge = Proto.size(); arg != arge; ++arg) {
2557 char ArgType = Proto[arg];
2558 if (ArgType == 'c') {
2559 HasConstPtr = true;
2560 PtrArgNum = arg - 1;
2561 break;
2562 }
2563 if (ArgType == 'p') {
2564 PtrArgNum = arg - 1;
2565 break;
2566 }
2567 }
2568 // For sret builtins, adjust the pointer argument index.
2569 if (PtrArgNum >= 0 && (Proto[0] >= '2' && Proto[0] <= '4'))
2570 PtrArgNum += 1;
2571
Bob Wilson9082cdd2011-12-20 06:16:48 +00002572 // Omit type checking for the pointer arguments of vld1_lane, vld1_dup,
2573 // and vst1_lane intrinsics. Using a pointer to the vector element
2574 // type with one of those operations causes codegen to select an aligned
2575 // load/store instruction. If you want an unaligned operation,
2576 // the pointer argument needs to have less alignment than element type,
2577 // so just accept any pointer type.
2578 if (name == "vld1_lane" || name == "vld1_dup" || name == "vst1_lane") {
2579 PtrArgNum = -1;
2580 HasConstPtr = false;
2581 }
2582
Bob Wilson6f9f03e2011-11-08 05:04:11 +00002583 if (mask) {
Tim Northoverb793f0d2013-08-01 09:23:19 +00002584 if (isA64TypeCheck)
2585 OS << "case AArch64::BI__builtin_neon_";
2586 else
2587 OS << "case ARM::BI__builtin_neon_";
2588 OS << MangleName(name, TypeVec[si], ClassB) << ": mask = "
2589 << "0x" << utohexstr(mask) << "ULL";
Bob Wilson46482552011-11-16 21:32:23 +00002590 if (PtrArgNum >= 0)
2591 OS << "; PtrArgNum = " << PtrArgNum;
Bob Wilson6f9f03e2011-11-08 05:04:11 +00002592 if (HasConstPtr)
2593 OS << "; HasConstPtr = true";
2594 OS << "; break;\n";
2595 }
2596 if (qmask) {
Tim Northoverb793f0d2013-08-01 09:23:19 +00002597 if (isA64TypeCheck)
2598 OS << "case AArch64::BI__builtin_neon_";
2599 else
2600 OS << "case ARM::BI__builtin_neon_";
2601 OS << MangleName(name, TypeVec[qi], ClassB) << ": mask = "
2602 << "0x" << utohexstr(qmask) << "ULL";
Bob Wilson46482552011-11-16 21:32:23 +00002603 if (PtrArgNum >= 0)
2604 OS << "; PtrArgNum = " << PtrArgNum;
Bob Wilson6f9f03e2011-11-08 05:04:11 +00002605 if (HasConstPtr)
2606 OS << "; HasConstPtr = true";
2607 OS << "; break;\n";
2608 }
Peter Collingbourne51d77772011-10-06 13:03:08 +00002609 }
2610 OS << "#endif\n\n";
Tim Northoverb793f0d2013-08-01 09:23:19 +00002611}
Peter Collingbourne51d77772011-10-06 13:03:08 +00002612
Tim Northoverb793f0d2013-08-01 09:23:19 +00002613/// genBuiltinsDef: Generate the BuiltinsARM.def and BuiltinsAArch64.def
2614/// declaration of builtins, checking for unique builtin declarations.
2615void NeonEmitter::genBuiltinsDef(raw_ostream &OS,
2616 StringMap<ClassKind> &A64IntrinsicMap,
2617 bool isA64GenBuiltinDef) {
2618 std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst");
2619 StringMap<OpKind> EmittedMap;
2620
2621 // Generate BuiltinsARM.def and BuiltinsAArch64.def
2622 if (isA64GenBuiltinDef)
2623 OS << "#ifdef GET_NEON_AARCH64_BUILTINS\n";
2624 else
2625 OS << "#ifdef GET_NEON_BUILTINS\n";
2626
Peter Collingbourne51d77772011-10-06 13:03:08 +00002627 for (unsigned i = 0, e = RV.size(); i != e; ++i) {
2628 Record *R = RV[i];
Peter Collingbourne51d77772011-10-06 13:03:08 +00002629 OpKind k = OpMap[R->getValueAsDef("Operand")->getName()];
2630 if (k != OpNone)
2631 continue;
2632
Peter Collingbourne51d77772011-10-06 13:03:08 +00002633 std::string Proto = R->getValueAsString("Prototype");
Tim Northoverb793f0d2013-08-01 09:23:19 +00002634 std::string name = R->getValueAsString("Name");
Kevin Qin944f09f2013-08-29 07:55:15 +00002635 std::string Rename = name + "@" + Proto;
Peter Collingbourne51d77772011-10-06 13:03:08 +00002636
2637 // Functions with 'a' (the splat code) in the type prototype should not get
2638 // their own builtin as they use the non-splat variant.
2639 if (Proto.find('a') != std::string::npos)
2640 continue;
2641
Tim Northoverb793f0d2013-08-01 09:23:19 +00002642 std::string Types = R->getValueAsString("Types");
Peter Collingbourne51d77772011-10-06 13:03:08 +00002643 SmallVector<StringRef, 16> TypeVec;
2644 ParseTypes(R, Types, TypeVec);
2645
2646 if (R->getSuperClasses().size() < 2)
Joerg Sonnenberger38859ee2012-10-25 16:37:08 +00002647 PrintFatalError(R->getLoc(), "Builtin has no class kind");
Peter Collingbourne51d77772011-10-06 13:03:08 +00002648
2649 ClassKind ck = ClassMap[R->getSuperClasses()[1]];
2650
Tim Northoverb793f0d2013-08-01 09:23:19 +00002651 // Do not include AArch64 BUILTIN() macros if not generating
2652 // code for AArch64
2653 bool isA64 = R->getValueAsBit("isA64");
2654 if (!isA64GenBuiltinDef && isA64)
2655 continue;
Peter Collingbourne51d77772011-10-06 13:03:08 +00002656
Tim Northoverb793f0d2013-08-01 09:23:19 +00002657 // Include ARM BUILTIN() macros in AArch64 but only if ARM intrinsics
2658 // are not redefined in AArch64 to handle new types, e.g. "vabd" is a SIntr
2659 // redefined in AArch64 to handle an additional 2 x f64 type.
Kevin Qin944f09f2013-08-29 07:55:15 +00002660 if (isA64GenBuiltinDef && !isA64 && A64IntrinsicMap.count(Rename)) {
2661 ClassKind &A64CK = A64IntrinsicMap[Rename];
Tim Northoverb793f0d2013-08-01 09:23:19 +00002662 if (A64CK == ck && ck != ClassNone)
Peter Collingbourne51d77772011-10-06 13:03:08 +00002663 continue;
Tim Northoverb793f0d2013-08-01 09:23:19 +00002664 }
Peter Collingbourne51d77772011-10-06 13:03:08 +00002665
Tim Northoverb793f0d2013-08-01 09:23:19 +00002666 for (unsigned ti = 0, te = TypeVec.size(); ti != te; ++ti) {
2667 // Generate the declaration for this builtin, ensuring
2668 // that each unique BUILTIN() macro appears only once in the output
2669 // stream.
2670 std::string bd = GenBuiltinDef(name, Proto, TypeVec[ti], ck);
2671 if (EmittedMap.count(bd))
2672 continue;
Peter Collingbourne51d77772011-10-06 13:03:08 +00002673
Tim Northoverb793f0d2013-08-01 09:23:19 +00002674 EmittedMap[bd] = OpNone;
2675 OS << bd << "\n";
Peter Collingbourne51d77772011-10-06 13:03:08 +00002676 }
2677 }
2678 OS << "#endif\n\n";
2679}
2680
Tim Northoverb793f0d2013-08-01 09:23:19 +00002681/// runHeader - Emit a file with sections defining:
2682/// 1. the NEON section of BuiltinsARM.def and BuiltinsAArch64.def.
2683/// 2. the SemaChecking code for the type overload checking.
2684/// 3. the SemaChecking code for validation of intrinsic immediate arguments.
2685void NeonEmitter::runHeader(raw_ostream &OS) {
2686 std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst");
2687
2688 // build a map of AArch64 intriniscs to be used in uniqueness checks.
2689 StringMap<ClassKind> A64IntrinsicMap;
2690 for (unsigned i = 0, e = RV.size(); i != e; ++i) {
2691 Record *R = RV[i];
2692
2693 bool isA64 = R->getValueAsBit("isA64");
2694 if (!isA64)
2695 continue;
2696
2697 ClassKind CK = ClassNone;
2698 if (R->getSuperClasses().size() >= 2)
2699 CK = ClassMap[R->getSuperClasses()[1]];
2700
2701 std::string Name = R->getValueAsString("Name");
Kevin Qin944f09f2013-08-29 07:55:15 +00002702 std::string Proto = R->getValueAsString("Prototype");
2703 std::string Rename = Name + "@" + Proto;
2704 if (A64IntrinsicMap.count(Rename))
Tim Northoverb793f0d2013-08-01 09:23:19 +00002705 continue;
Kevin Qin944f09f2013-08-29 07:55:15 +00002706 A64IntrinsicMap[Rename] = CK;
Tim Northoverb793f0d2013-08-01 09:23:19 +00002707 }
2708
2709 // Generate BuiltinsARM.def for ARM
2710 genBuiltinsDef(OS, A64IntrinsicMap, false);
2711
2712 // Generate BuiltinsAArch64.def for AArch64
2713 genBuiltinsDef(OS, A64IntrinsicMap, true);
2714
2715 // Generate ARM overloaded type checking code for SemaChecking.cpp
2716 genOverloadTypeCheckCode(OS, A64IntrinsicMap, false);
2717
2718 // Generate AArch64 overloaded type checking code for SemaChecking.cpp
2719 genOverloadTypeCheckCode(OS, A64IntrinsicMap, true);
2720
2721 // Generate ARM range checking code for shift/lane immediates.
2722 genIntrinsicRangeCheckCode(OS, A64IntrinsicMap, false);
2723
2724 // Generate the AArch64 range checking code for shift/lane immediates.
2725 genIntrinsicRangeCheckCode(OS, A64IntrinsicMap, true);
2726}
2727
Peter Collingbourne51d77772011-10-06 13:03:08 +00002728/// GenTest - Write out a test for the intrinsic specified by the name and
2729/// type strings, including the embedded patterns for FileCheck to match.
2730static std::string GenTest(const std::string &name,
2731 const std::string &proto,
2732 StringRef outTypeStr, StringRef inTypeStr,
Michael Gottesman7200bd62013-04-16 22:48:52 +00002733 bool isShift, bool isHiddenLOp,
Tim Northoverb793f0d2013-08-01 09:23:19 +00002734 ClassKind ck, const std::string &InstName,
2735 bool isA64,
2736 std::string & testFuncProto) {
Peter Collingbourne51d77772011-10-06 13:03:08 +00002737 assert(!proto.empty() && "");
2738 std::string s;
2739
2740 // Function name with type suffix
2741 std::string mangledName = MangleName(name, outTypeStr, ClassS);
2742 if (outTypeStr != inTypeStr) {
2743 // If the input type is different (e.g., for vreinterpret), append a suffix
2744 // for the input type. String off a "Q" (quad) prefix so that MangleName
2745 // does not insert another "q" in the name.
2746 unsigned typeStrOff = (inTypeStr[0] == 'Q' ? 1 : 0);
2747 StringRef inTypeNoQuad = inTypeStr.substr(typeStrOff);
2748 mangledName = MangleName(mangledName, inTypeNoQuad, ClassS);
2749 }
2750
Tim Northoverb793f0d2013-08-01 09:23:19 +00002751 // todo: GenerateChecksForIntrinsic does not generate CHECK
2752 // for aarch64 instructions yet
Michael Gottesmanc327f872013-04-16 23:00:26 +00002753 std::vector<std::string> FileCheckPatterns;
Tim Northoverb793f0d2013-08-01 09:23:19 +00002754 if (!isA64) {
2755 GenerateChecksForIntrinsic(name, proto, outTypeStr, inTypeStr, ck, InstName,
2756 isHiddenLOp, FileCheckPatterns);
2757 s+= "// CHECK_ARM: test_" + mangledName + "\n";
2758 }
2759 s += "// CHECK_AARCH64: test_" + mangledName + "\n";
Michael Gottesmanc327f872013-04-16 23:00:26 +00002760
Peter Collingbourne51d77772011-10-06 13:03:08 +00002761 // Emit the FileCheck patterns.
Michael Gottesmanc327f872013-04-16 23:00:26 +00002762 // If for any reason we do not want to emit a check, mangledInst
2763 // will be the empty string.
2764 if (FileCheckPatterns.size()) {
2765 for (std::vector<std::string>::const_iterator i = FileCheckPatterns.begin(),
2766 e = FileCheckPatterns.end();
2767 i != e;
2768 ++i) {
Tim Northoverb793f0d2013-08-01 09:23:19 +00002769 s += "// CHECK_ARM: " + *i + "\n";
Michael Gottesmanc327f872013-04-16 23:00:26 +00002770 }
2771 }
Peter Collingbourne51d77772011-10-06 13:03:08 +00002772
2773 // Emit the start of the test function.
Tim Northoverb793f0d2013-08-01 09:23:19 +00002774
2775 testFuncProto = TypeString(proto[0], outTypeStr) + " test_" + mangledName + "(";
Peter Collingbourne51d77772011-10-06 13:03:08 +00002776 char arg = 'a';
2777 std::string comma;
2778 for (unsigned i = 1, e = proto.size(); i != e; ++i, ++arg) {
2779 // Do not create arguments for values that must be immediate constants.
2780 if (proto[i] == 'i')
2781 continue;
Tim Northoverb793f0d2013-08-01 09:23:19 +00002782 testFuncProto += comma + TypeString(proto[i], inTypeStr) + " ";
2783 testFuncProto.push_back(arg);
Peter Collingbourne51d77772011-10-06 13:03:08 +00002784 comma = ", ";
2785 }
Tim Northoverb793f0d2013-08-01 09:23:19 +00002786 testFuncProto += ")";
2787
2788 s+= testFuncProto;
2789 s+= " {\n ";
Peter Collingbourne51d77772011-10-06 13:03:08 +00002790
2791 if (proto[0] != 'v')
2792 s += "return ";
2793 s += mangledName + "(";
2794 arg = 'a';
2795 for (unsigned i = 1, e = proto.size(); i != e; ++i, ++arg) {
2796 if (proto[i] == 'i') {
2797 // For immediate operands, test the maximum value.
2798 if (isShift)
2799 s += "1"; // FIXME
2800 else
2801 // The immediate generally refers to a lane in the preceding argument.
2802 s += utostr(RangeFromType(proto[i-1], inTypeStr));
2803 } else {
2804 s.push_back(arg);
2805 }
2806 if ((i + 1) < e)
2807 s += ", ";
2808 }
2809 s += ");\n}\n\n";
2810 return s;
2811}
2812
Tim Northoverb793f0d2013-08-01 09:23:19 +00002813/// Write out all intrinsic tests for the specified target, checking
2814/// for intrinsic test uniqueness.
2815void NeonEmitter::genTargetTest(raw_ostream &OS, StringMap<OpKind> &EmittedMap,
2816 bool isA64GenTest) {
2817 if (isA64GenTest)
2818 OS << "#ifdef __aarch64__\n";
Peter Collingbourne51d77772011-10-06 13:03:08 +00002819
Tim Northoverb793f0d2013-08-01 09:23:19 +00002820 std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst");
Peter Collingbourne51d77772011-10-06 13:03:08 +00002821 for (unsigned i = 0, e = RV.size(); i != e; ++i) {
2822 Record *R = RV[i];
2823 std::string name = R->getValueAsString("Name");
2824 std::string Proto = R->getValueAsString("Prototype");
2825 std::string Types = R->getValueAsString("Types");
2826 bool isShift = R->getValueAsBit("isShift");
Michael Gottesman7200bd62013-04-16 22:48:52 +00002827 std::string InstName = R->getValueAsString("InstName");
2828 bool isHiddenLOp = R->getValueAsBit("isHiddenLInst");
Tim Northoverb793f0d2013-08-01 09:23:19 +00002829 bool isA64 = R->getValueAsBit("isA64");
2830
2831 // do not include AArch64 intrinsic test if not generating
2832 // code for AArch64
2833 if (!isA64GenTest && isA64)
2834 continue;
Peter Collingbourne51d77772011-10-06 13:03:08 +00002835
2836 SmallVector<StringRef, 16> TypeVec;
2837 ParseTypes(R, Types, TypeVec);
2838
Michael Gottesman7200bd62013-04-16 22:48:52 +00002839 ClassKind ck = ClassMap[R->getSuperClasses()[1]];
Peter Collingbourne51d77772011-10-06 13:03:08 +00002840 OpKind kind = OpMap[R->getValueAsDef("Operand")->getName()];
Jim Grosbach667381b2012-05-09 18:17:30 +00002841 if (kind == OpUnavailable)
2842 continue;
Peter Collingbourne51d77772011-10-06 13:03:08 +00002843 for (unsigned ti = 0, te = TypeVec.size(); ti != te; ++ti) {
2844 if (kind == OpReinterpret) {
2845 bool outQuad = false;
2846 bool dummy = false;
2847 (void)ClassifyType(TypeVec[ti], outQuad, dummy, dummy);
2848 for (unsigned srcti = 0, srcte = TypeVec.size();
2849 srcti != srcte; ++srcti) {
2850 bool inQuad = false;
2851 (void)ClassifyType(TypeVec[srcti], inQuad, dummy, dummy);
2852 if (srcti == ti || inQuad != outQuad)
2853 continue;
Tim Northoverb793f0d2013-08-01 09:23:19 +00002854 std::string testFuncProto;
2855 std::string s = GenTest(name, Proto, TypeVec[ti], TypeVec[srcti],
2856 isShift, isHiddenLOp, ck, InstName, isA64,
2857 testFuncProto);
2858 if (EmittedMap.count(testFuncProto))
2859 continue;
2860 EmittedMap[testFuncProto] = kind;
2861 OS << s << "\n";
Peter Collingbourne51d77772011-10-06 13:03:08 +00002862 }
2863 } else {
Tim Northoverb793f0d2013-08-01 09:23:19 +00002864 std::string testFuncProto;
2865 std::string s = GenTest(name, Proto, TypeVec[ti], TypeVec[ti], isShift,
2866 isHiddenLOp, ck, InstName, isA64, testFuncProto);
2867 if (EmittedMap.count(testFuncProto))
2868 continue;
2869 EmittedMap[testFuncProto] = kind;
2870 OS << s << "\n";
Peter Collingbourne51d77772011-10-06 13:03:08 +00002871 }
2872 }
Peter Collingbourne51d77772011-10-06 13:03:08 +00002873 }
Tim Northoverb793f0d2013-08-01 09:23:19 +00002874
2875 if (isA64GenTest)
2876 OS << "#endif\n";
2877}
2878/// runTests - Write out a complete set of tests for all of the Neon
2879/// intrinsics.
2880void NeonEmitter::runTests(raw_ostream &OS) {
2881 OS << "// RUN: %clang_cc1 -triple thumbv7s-apple-darwin -target-abi "
2882 "apcs-gnu\\\n"
2883 "// RUN: -target-cpu swift -ffreestanding -Os -S -o - %s\\\n"
2884 "// RUN: | FileCheck %s -check-prefix=CHECK_ARM\n"
2885 "\n"
2886 "// RUN: %clang_cc1 -triple aarch64-none-linux-gnu \\\n"
2887 "// RUN -target-feature +neon -ffreestanding -S -o - %s \\\n"
2888 "// RUN: | FileCheck %s -check-prefix=CHECK_AARCH64\n"
2889 "\n"
2890 "// REQUIRES: long_tests\n"
2891 "\n"
2892 "#include <arm_neon.h>\n"
2893 "\n";
2894
2895 // ARM tests must be emitted before AArch64 tests to ensure
2896 // tests for intrinsics that are common to ARM and AArch64
2897 // appear only once in the output stream.
2898 // The check for uniqueness is done in genTargetTest.
2899 StringMap<OpKind> EmittedMap;
2900
2901 genTargetTest(OS, EmittedMap, false);
2902
2903 genTargetTest(OS, EmittedMap, true);
Peter Collingbourne51d77772011-10-06 13:03:08 +00002904}
2905
Jakob Stoklund Olesen3cc509b2012-06-13 05:12:41 +00002906namespace clang {
2907void EmitNeon(RecordKeeper &Records, raw_ostream &OS) {
2908 NeonEmitter(Records).run(OS);
2909}
2910void EmitNeonSema(RecordKeeper &Records, raw_ostream &OS) {
2911 NeonEmitter(Records).runHeader(OS);
2912}
2913void EmitNeonTest(RecordKeeper &Records, raw_ostream &OS) {
2914 NeonEmitter(Records).runTests(OS);
2915}
2916} // End namespace clang