blob: 78075ba8a008ae393079d4e6f70e7112e00a0fa5 [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;
Jiangning Liu03916912013-10-05 08:22:55 +0000487 case 'r':
488 type = Widen(type);
Peter Collingbourne51d77772011-10-06 13:03:08 +0000489 case 's':
490 case 'a':
491 scal = true;
492 break;
493 case 'k':
494 quad = true;
495 break;
496 case 'c':
497 cnst = true;
498 case 'p':
499 pntr = true;
500 scal = true;
501 break;
502 case 'h':
503 type = Narrow(type);
504 if (type == 'h')
505 quad = false;
506 break;
Jiangning Liu097a4b42013-09-09 02:21:08 +0000507 case 'q':
508 type = Narrow(type);
509 quad = true;
510 break;
Peter Collingbourne51d77772011-10-06 13:03:08 +0000511 case 'e':
512 type = Narrow(type);
513 usgn = true;
514 break;
Hao Liu912502b2013-09-04 09:29:13 +0000515 case 'm':
516 type = Narrow(type);
517 quad = false;
518 break;
Peter Collingbourne51d77772011-10-06 13:03:08 +0000519 default:
520 break;
521 }
522 return type;
523}
524
525/// TypeString - for a modifier and type, generate the name of the typedef for
526/// that type. QUc -> uint8x8_t.
527static std::string TypeString(const char mod, StringRef typestr) {
528 bool quad = false;
529 bool poly = false;
530 bool usgn = false;
531 bool scal = false;
532 bool cnst = false;
533 bool pntr = false;
534
535 if (mod == 'v')
536 return "void";
537 if (mod == 'i')
538 return "int";
539
540 // base type to get the type string for.
541 char type = ClassifyType(typestr, quad, poly, usgn);
542
543 // Based on the modifying character, change the type and width if necessary.
544 type = ModType(mod, type, quad, poly, usgn, scal, cnst, pntr);
545
546 SmallString<128> s;
547
548 if (usgn)
549 s.push_back('u');
550
551 switch (type) {
552 case 'c':
553 s += poly ? "poly8" : "int8";
554 if (scal)
555 break;
556 s += quad ? "x16" : "x8";
557 break;
558 case 's':
559 s += poly ? "poly16" : "int16";
560 if (scal)
561 break;
562 s += quad ? "x8" : "x4";
563 break;
564 case 'i':
565 s += "int32";
566 if (scal)
567 break;
568 s += quad ? "x4" : "x2";
569 break;
570 case 'l':
571 s += "int64";
572 if (scal)
573 break;
574 s += quad ? "x2" : "x1";
575 break;
576 case 'h':
577 s += "float16";
578 if (scal)
579 break;
580 s += quad ? "x8" : "x4";
581 break;
582 case 'f':
583 s += "float32";
584 if (scal)
585 break;
586 s += quad ? "x4" : "x2";
587 break;
Tim Northoverb793f0d2013-08-01 09:23:19 +0000588 case 'd':
589 s += "float64";
590 if (scal)
591 break;
592 s += quad ? "x2" : "x1";
593 break;
594
Peter Collingbourne51d77772011-10-06 13:03:08 +0000595 default:
Joerg Sonnenberger38859ee2012-10-25 16:37:08 +0000596 PrintFatalError("unhandled type!");
Peter Collingbourne51d77772011-10-06 13:03:08 +0000597 }
598
599 if (mod == '2')
600 s += "x2";
601 if (mod == '3')
602 s += "x3";
603 if (mod == '4')
604 s += "x4";
605
606 // Append _t, finishing the type string typedef type.
607 s += "_t";
608
609 if (cnst)
610 s += " const";
611
612 if (pntr)
613 s += " *";
614
615 return s.str();
616}
617
618/// BuiltinTypeString - for a modifier and type, generate the clang
619/// BuiltinsARM.def prototype code for the function. See the top of clang's
620/// Builtins.def for a description of the type strings.
621static std::string BuiltinTypeString(const char mod, StringRef typestr,
622 ClassKind ck, bool ret) {
623 bool quad = false;
624 bool poly = false;
625 bool usgn = false;
626 bool scal = false;
627 bool cnst = false;
628 bool pntr = false;
629
630 if (mod == 'v')
631 return "v"; // void
632 if (mod == 'i')
633 return "i"; // int
634
635 // base type to get the type string for.
636 char type = ClassifyType(typestr, quad, poly, usgn);
637
638 // Based on the modifying character, change the type and width if necessary.
639 type = ModType(mod, type, quad, poly, usgn, scal, cnst, pntr);
640
641 // All pointers are void* pointers. Change type to 'v' now.
642 if (pntr) {
643 usgn = false;
644 poly = false;
645 type = 'v';
646 }
647 // Treat half-float ('h') types as unsigned short ('s') types.
648 if (type == 'h') {
649 type = 's';
650 usgn = true;
651 }
Jiangning Liu0aa1a882013-10-04 09:21:17 +0000652 usgn = usgn | poly | ((ck == ClassI || ck == ClassW) &&
653 scal && type != 'f' && type != 'd');
Peter Collingbourne51d77772011-10-06 13:03:08 +0000654
655 if (scal) {
656 SmallString<128> s;
657
658 if (usgn)
659 s.push_back('U');
660 else if (type == 'c')
661 s.push_back('S'); // make chars explicitly signed
662
663 if (type == 'l') // 64-bit long
664 s += "LLi";
665 else
666 s.push_back(type);
667
668 if (cnst)
669 s.push_back('C');
670 if (pntr)
671 s.push_back('*');
672 return s.str();
673 }
674
675 // Since the return value must be one type, return a vector type of the
676 // appropriate width which we will bitcast. An exception is made for
677 // returning structs of 2, 3, or 4 vectors which are returned in a sret-like
678 // fashion, storing them to a pointer arg.
679 if (ret) {
680 if (mod >= '2' && mod <= '4')
681 return "vv*"; // void result with void* first argument
682 if (mod == 'f' || (ck != ClassB && type == 'f'))
683 return quad ? "V4f" : "V2f";
Jiangning Liu0aa1a882013-10-04 09:21:17 +0000684 if (ck != ClassB && type == 'd')
685 return quad ? "V2d" : "V1d";
Peter Collingbourne51d77772011-10-06 13:03:08 +0000686 if (ck != ClassB && type == 's')
687 return quad ? "V8s" : "V4s";
688 if (ck != ClassB && type == 'i')
689 return quad ? "V4i" : "V2i";
690 if (ck != ClassB && type == 'l')
691 return quad ? "V2LLi" : "V1LLi";
692
693 return quad ? "V16Sc" : "V8Sc";
694 }
695
696 // Non-return array types are passed as individual vectors.
697 if (mod == '2')
698 return quad ? "V16ScV16Sc" : "V8ScV8Sc";
699 if (mod == '3')
700 return quad ? "V16ScV16ScV16Sc" : "V8ScV8ScV8Sc";
701 if (mod == '4')
702 return quad ? "V16ScV16ScV16ScV16Sc" : "V8ScV8ScV8ScV8Sc";
703
704 if (mod == 'f' || (ck != ClassB && type == 'f'))
705 return quad ? "V4f" : "V2f";
Jiangning Liu0aa1a882013-10-04 09:21:17 +0000706 if (ck != ClassB && type == 'd')
707 return quad ? "V2d" : "V1d";
Peter Collingbourne51d77772011-10-06 13:03:08 +0000708 if (ck != ClassB && type == 's')
709 return quad ? "V8s" : "V4s";
710 if (ck != ClassB && type == 'i')
711 return quad ? "V4i" : "V2i";
712 if (ck != ClassB && type == 'l')
713 return quad ? "V2LLi" : "V1LLi";
714
715 return quad ? "V16Sc" : "V8Sc";
716}
717
Michael Gottesmanfb599a42013-04-16 22:07:30 +0000718/// InstructionTypeCode - Computes the ARM argument character code and
719/// quad status for a specific type string and ClassKind.
720static void InstructionTypeCode(const StringRef &typeStr,
721 const ClassKind ck,
722 bool &quad,
723 std::string &typeCode) {
724 bool poly = false;
725 bool usgn = false;
726 char type = ClassifyType(typeStr, quad, poly, usgn);
727
728 switch (type) {
729 case 'c':
730 switch (ck) {
731 case ClassS: typeCode = poly ? "p8" : usgn ? "u8" : "s8"; break;
732 case ClassI: typeCode = "i8"; break;
733 case ClassW: typeCode = "8"; break;
734 default: break;
735 }
736 break;
737 case 's':
738 switch (ck) {
739 case ClassS: typeCode = poly ? "p16" : usgn ? "u16" : "s16"; break;
740 case ClassI: typeCode = "i16"; break;
741 case ClassW: typeCode = "16"; break;
742 default: break;
743 }
744 break;
745 case 'i':
746 switch (ck) {
747 case ClassS: typeCode = usgn ? "u32" : "s32"; break;
748 case ClassI: typeCode = "i32"; break;
749 case ClassW: typeCode = "32"; break;
750 default: break;
751 }
752 break;
753 case 'l':
754 switch (ck) {
755 case ClassS: typeCode = usgn ? "u64" : "s64"; break;
756 case ClassI: typeCode = "i64"; break;
757 case ClassW: typeCode = "64"; break;
758 default: break;
759 }
760 break;
761 case 'h':
762 switch (ck) {
763 case ClassS:
764 case ClassI: typeCode = "f16"; break;
765 case ClassW: typeCode = "16"; break;
766 default: break;
767 }
768 break;
769 case 'f':
770 switch (ck) {
771 case ClassS:
772 case ClassI: typeCode = "f32"; break;
773 case ClassW: typeCode = "32"; break;
774 default: break;
775 }
776 break;
Tim Northoverb793f0d2013-08-01 09:23:19 +0000777 case 'd':
778 switch (ck) {
779 case ClassS:
780 case ClassI:
781 typeCode += "f64";
782 break;
783 case ClassW:
784 PrintFatalError("unhandled type!");
785 default:
786 break;
787 }
788 break;
Michael Gottesmanfb599a42013-04-16 22:07:30 +0000789 default:
790 PrintFatalError("unhandled type!");
791 }
792}
793
Kevin Qin944f09f2013-08-29 07:55:15 +0000794static char Insert_BHSD_Suffix(StringRef typestr){
795 unsigned off = 0;
796 if(typestr[off++] == 'S'){
797 while(typestr[off] == 'Q' || typestr[off] == 'H'||
798 typestr[off] == 'P' || typestr[off] == 'U')
799 ++off;
800 switch (typestr[off]){
801 default : break;
802 case 'c' : return 'b';
803 case 's' : return 'h';
804 case 'i' :
805 case 'f' : return 's';
806 case 'l' :
807 case 'd' : return 'd';
808 }
809 }
810 return 0;
811}
812
Peter Collingbourne51d77772011-10-06 13:03:08 +0000813/// MangleName - Append a type or width suffix to a base neon function name,
Hao Liu12cd6a82013-08-15 08:26:30 +0000814/// and insert a 'q' in the appropriate location if type string starts with 'Q'.
815/// E.g. turn "vst2_lane" into "vst2q_lane_f32", etc.
Kevin Qin944f09f2013-08-29 07:55:15 +0000816/// Insert proper 'b' 'h' 's' 'd' if prefix 'S' is used.
Peter Collingbourne51d77772011-10-06 13:03:08 +0000817static std::string MangleName(const std::string &name, StringRef typestr,
818 ClassKind ck) {
819 if (name == "vcvt_f32_f16")
820 return name;
821
822 bool quad = false;
Michael Gottesmanfb599a42013-04-16 22:07:30 +0000823 std::string typeCode = "";
824
825 InstructionTypeCode(typestr, ck, quad, typeCode);
Peter Collingbourne51d77772011-10-06 13:03:08 +0000826
827 std::string s = name;
828
Michael Gottesmanfb599a42013-04-16 22:07:30 +0000829 if (typeCode.size() > 0) {
830 s += "_" + typeCode;
Peter Collingbourne51d77772011-10-06 13:03:08 +0000831 }
Michael Gottesmanfb599a42013-04-16 22:07:30 +0000832
Peter Collingbourne51d77772011-10-06 13:03:08 +0000833 if (ck == ClassB)
834 s += "_v";
835
836 // Insert a 'q' before the first '_' character so that it ends up before
837 // _lane or _n on vector-scalar operations.
Kevin Qin944f09f2013-08-29 07:55:15 +0000838 if (typestr.find("Q") != StringRef::npos) {
Hao Liu12cd6a82013-08-15 08:26:30 +0000839 size_t pos = s.find('_');
840 s = s.insert(pos, "q");
Peter Collingbourne51d77772011-10-06 13:03:08 +0000841 }
Kevin Qin944f09f2013-08-29 07:55:15 +0000842 char ins = Insert_BHSD_Suffix(typestr);
843 if(ins){
844 size_t pos = s.find('_');
845 s = s.insert(pos, &ins, 1);
846 }
Michael Gottesmanc327f872013-04-16 23:00:26 +0000847
Peter Collingbourne51d77772011-10-06 13:03:08 +0000848 return s;
849}
850
Michael Gottesmanc327f872013-04-16 23:00:26 +0000851static void PreprocessInstruction(const StringRef &Name,
852 const std::string &InstName,
853 std::string &Prefix,
854 bool &HasNPostfix,
855 bool &HasLanePostfix,
856 bool &HasDupPostfix,
857 bool &IsSpecialVCvt,
858 size_t &TBNumber) {
859 // All of our instruction name fields from arm_neon.td are of the form
860 // <instructionname>_...
861 // Thus we grab our instruction name via computation of said Prefix.
862 const size_t PrefixEnd = Name.find_first_of('_');
863 // If InstName is passed in, we use that instead of our name Prefix.
864 Prefix = InstName.size() == 0? Name.slice(0, PrefixEnd).str() : InstName;
865
866 const StringRef Postfix = Name.slice(PrefixEnd, Name.size());
867
868 HasNPostfix = Postfix.count("_n");
869 HasLanePostfix = Postfix.count("_lane");
870 HasDupPostfix = Postfix.count("_dup");
871 IsSpecialVCvt = Postfix.size() != 0 && Name.count("vcvt");
872
873 if (InstName.compare("vtbl") == 0 ||
874 InstName.compare("vtbx") == 0) {
875 // If we have a vtblN/vtbxN instruction, use the instruction's ASCII
876 // encoding to get its true value.
877 TBNumber = Name[Name.size()-1] - 48;
878 }
879}
880
881/// GenerateRegisterCheckPatternsForLoadStores - Given a bunch of data we have
882/// extracted, generate a FileCheck pattern for a Load Or Store
883static void
884GenerateRegisterCheckPatternForLoadStores(const StringRef &NameRef,
885 const std::string& OutTypeCode,
886 const bool &IsQuad,
887 const bool &HasDupPostfix,
888 const bool &HasLanePostfix,
889 const size_t Count,
890 std::string &RegisterSuffix) {
891 const bool IsLDSTOne = NameRef.count("vld1") || NameRef.count("vst1");
892 // If N == 3 || N == 4 and we are dealing with a quad instruction, Clang
893 // will output a series of v{ld,st}1s, so we have to handle it specially.
894 if ((Count == 3 || Count == 4) && IsQuad) {
895 RegisterSuffix += "{";
896 for (size_t i = 0; i < Count; i++) {
897 RegisterSuffix += "d{{[0-9]+}}";
898 if (HasDupPostfix) {
899 RegisterSuffix += "[]";
900 }
901 if (HasLanePostfix) {
902 RegisterSuffix += "[{{[0-9]+}}]";
903 }
904 if (i < Count-1) {
905 RegisterSuffix += ", ";
906 }
907 }
908 RegisterSuffix += "}";
909 } else {
910
911 // Handle normal loads and stores.
912 RegisterSuffix += "{";
913 for (size_t i = 0; i < Count; i++) {
914 RegisterSuffix += "d{{[0-9]+}}";
915 if (HasDupPostfix) {
916 RegisterSuffix += "[]";
917 }
918 if (HasLanePostfix) {
919 RegisterSuffix += "[{{[0-9]+}}]";
920 }
921 if (IsQuad && !HasLanePostfix) {
922 RegisterSuffix += ", d{{[0-9]+}}";
923 if (HasDupPostfix) {
924 RegisterSuffix += "[]";
925 }
926 }
927 if (i < Count-1) {
928 RegisterSuffix += ", ";
929 }
930 }
931 RegisterSuffix += "}, [r{{[0-9]+}}";
932
933 // We only include the alignment hint if we have a vld1.*64 or
934 // a dup/lane instruction.
935 if (IsLDSTOne) {
936 if ((HasLanePostfix || HasDupPostfix) && OutTypeCode != "8") {
Michael Gottesman410c3f72013-06-24 21:25:37 +0000937 RegisterSuffix += ":" + OutTypeCode;
Michael Gottesmanc327f872013-04-16 23:00:26 +0000938 }
939 }
940
941 RegisterSuffix += "]";
942 }
943}
944
945static bool HasNPostfixAndScalarArgs(const StringRef &NameRef,
946 const bool &HasNPostfix) {
947 return (NameRef.count("vmla") ||
948 NameRef.count("vmlal") ||
949 NameRef.count("vmlsl") ||
950 NameRef.count("vmull") ||
951 NameRef.count("vqdmlal") ||
952 NameRef.count("vqdmlsl") ||
953 NameRef.count("vqdmulh") ||
954 NameRef.count("vqdmull") ||
955 NameRef.count("vqrdmulh")) && HasNPostfix;
956}
957
958static bool IsFiveOperandLaneAccumulator(const StringRef &NameRef,
959 const bool &HasLanePostfix) {
960 return (NameRef.count("vmla") ||
961 NameRef.count("vmls") ||
962 NameRef.count("vmlal") ||
963 NameRef.count("vmlsl") ||
964 (NameRef.count("vmul") && NameRef.size() == 3)||
965 NameRef.count("vqdmlal") ||
966 NameRef.count("vqdmlsl") ||
967 NameRef.count("vqdmulh") ||
968 NameRef.count("vqrdmulh")) && HasLanePostfix;
969}
970
971static bool IsSpecialLaneMultiply(const StringRef &NameRef,
972 const bool &HasLanePostfix,
973 const bool &IsQuad) {
974 const bool IsVMulOrMulh = (NameRef.count("vmul") || NameRef.count("mulh"))
975 && IsQuad;
976 const bool IsVMull = NameRef.count("mull") && !IsQuad;
977 return (IsVMulOrMulh || IsVMull) && HasLanePostfix;
978}
979
980static void NormalizeProtoForRegisterPatternCreation(const std::string &Name,
981 const std::string &Proto,
982 const bool &HasNPostfix,
983 const bool &IsQuad,
984 const bool &HasLanePostfix,
985 const bool &HasDupPostfix,
986 std::string &NormedProto) {
987 // Handle generic case.
988 const StringRef NameRef(Name);
989 for (size_t i = 0, end = Proto.size(); i < end; i++) {
990 switch (Proto[i]) {
991 case 'u':
992 case 'f':
993 case 'd':
994 case 's':
995 case 'x':
996 case 't':
997 case 'n':
998 NormedProto += IsQuad? 'q' : 'd';
999 break;
1000 case 'w':
1001 case 'k':
1002 NormedProto += 'q';
1003 break;
1004 case 'g':
Jiangning Liu0aa1a882013-10-04 09:21:17 +00001005 case 'j':
Michael Gottesmanc327f872013-04-16 23:00:26 +00001006 case 'h':
1007 case 'e':
1008 NormedProto += 'd';
1009 break;
1010 case 'i':
1011 NormedProto += HasLanePostfix? 'a' : 'i';
1012 break;
1013 case 'a':
1014 if (HasLanePostfix) {
1015 NormedProto += 'a';
1016 } else if (HasNPostfixAndScalarArgs(NameRef, HasNPostfix)) {
1017 NormedProto += IsQuad? 'q' : 'd';
1018 } else {
1019 NormedProto += 'i';
1020 }
1021 break;
1022 }
1023 }
1024
1025 // Handle Special Cases.
1026 const bool IsNotVExt = !NameRef.count("vext");
1027 const bool IsVPADAL = NameRef.count("vpadal");
1028 const bool Is5OpLaneAccum = IsFiveOperandLaneAccumulator(NameRef,
1029 HasLanePostfix);
1030 const bool IsSpecialLaneMul = IsSpecialLaneMultiply(NameRef, HasLanePostfix,
1031 IsQuad);
1032
1033 if (IsSpecialLaneMul) {
1034 // If
1035 NormedProto[2] = NormedProto[3];
1036 NormedProto.erase(3);
1037 } else if (NormedProto.size() == 4 &&
1038 NormedProto[0] == NormedProto[1] &&
1039 IsNotVExt) {
1040 // If NormedProto.size() == 4 and the first two proto characters are the
1041 // same, ignore the first.
1042 NormedProto = NormedProto.substr(1, 3);
1043 } else if (Is5OpLaneAccum) {
1044 // If we have a 5 op lane accumulator operation, we take characters 1,2,4
1045 std::string tmp = NormedProto.substr(1,2);
1046 tmp += NormedProto[4];
1047 NormedProto = tmp;
1048 } else if (IsVPADAL) {
1049 // If we have VPADAL, ignore the first character.
1050 NormedProto = NormedProto.substr(0, 2);
1051 } else if (NameRef.count("vdup") && NormedProto.size() > 2) {
1052 // If our instruction is a dup instruction, keep only the first and
1053 // last characters.
1054 std::string tmp = "";
1055 tmp += NormedProto[0];
1056 tmp += NormedProto[NormedProto.size()-1];
1057 NormedProto = tmp;
1058 }
1059}
1060
1061/// GenerateRegisterCheckPatterns - Given a bunch of data we have
1062/// extracted, generate a FileCheck pattern to check that an
1063/// instruction's arguments are correct.
1064static void GenerateRegisterCheckPattern(const std::string &Name,
1065 const std::string &Proto,
1066 const std::string &OutTypeCode,
1067 const bool &HasNPostfix,
1068 const bool &IsQuad,
1069 const bool &HasLanePostfix,
1070 const bool &HasDupPostfix,
1071 const size_t &TBNumber,
1072 std::string &RegisterSuffix) {
1073
1074 RegisterSuffix = "";
1075
1076 const StringRef NameRef(Name);
1077 const StringRef ProtoRef(Proto);
1078
1079 if ((NameRef.count("vdup") || NameRef.count("vmov")) && HasNPostfix) {
1080 return;
1081 }
1082
1083 const bool IsLoadStore = NameRef.count("vld") || NameRef.count("vst");
1084 const bool IsTBXOrTBL = NameRef.count("vtbl") || NameRef.count("vtbx");
1085
1086 if (IsLoadStore) {
1087 // Grab N value from v{ld,st}N using its ascii representation.
1088 const size_t Count = NameRef[3] - 48;
1089
1090 GenerateRegisterCheckPatternForLoadStores(NameRef, OutTypeCode, IsQuad,
1091 HasDupPostfix, HasLanePostfix,
1092 Count, RegisterSuffix);
1093 } else if (IsTBXOrTBL) {
1094 RegisterSuffix += "d{{[0-9]+}}, {";
1095 for (size_t i = 0; i < TBNumber-1; i++) {
1096 RegisterSuffix += "d{{[0-9]+}}, ";
1097 }
1098 RegisterSuffix += "d{{[0-9]+}}}, d{{[0-9]+}}";
1099 } else {
1100 // Handle a normal instruction.
1101 if (NameRef.count("vget") || NameRef.count("vset"))
1102 return;
1103
1104 // We first normalize our proto, since we only need to emit 4
1105 // different types of checks, yet have more than 4 proto types
1106 // that map onto those 4 patterns.
1107 std::string NormalizedProto("");
1108 NormalizeProtoForRegisterPatternCreation(Name, Proto, HasNPostfix, IsQuad,
1109 HasLanePostfix, HasDupPostfix,
1110 NormalizedProto);
1111
1112 for (size_t i = 0, end = NormalizedProto.size(); i < end; i++) {
1113 const char &c = NormalizedProto[i];
1114 switch (c) {
1115 case 'q':
1116 RegisterSuffix += "q{{[0-9]+}}, ";
1117 break;
1118
1119 case 'd':
1120 RegisterSuffix += "d{{[0-9]+}}, ";
1121 break;
1122
1123 case 'i':
1124 RegisterSuffix += "#{{[0-9]+}}, ";
1125 break;
1126
1127 case 'a':
1128 RegisterSuffix += "d{{[0-9]+}}[{{[0-9]}}], ";
1129 break;
1130 }
1131 }
1132
1133 // Remove extra ", ".
1134 RegisterSuffix = RegisterSuffix.substr(0, RegisterSuffix.size()-2);
1135 }
1136}
1137
1138/// GenerateChecksForIntrinsic - Given a specific instruction name +
1139/// typestr + class kind, generate the proper set of FileCheck
1140/// Patterns to check for. We could just return a string, but instead
1141/// use a vector since it provides us with the extra flexibility of
1142/// emitting multiple checks, which comes in handy for certain cases
1143/// like mla where we want to check for 2 different instructions.
1144static void GenerateChecksForIntrinsic(const std::string &Name,
1145 const std::string &Proto,
1146 StringRef &OutTypeStr,
1147 StringRef &InTypeStr,
1148 ClassKind Ck,
1149 const std::string &InstName,
1150 bool IsHiddenLOp,
1151 std::vector<std::string>& Result) {
1152
1153 // If Ck is a ClassNoTest instruction, just return so no test is
1154 // emitted.
1155 if(Ck == ClassNoTest)
1156 return;
1157
1158 if (Name == "vcvt_f32_f16") {
1159 Result.push_back("vcvt.f32.f16");
1160 return;
1161 }
1162
1163
1164 // Now we preprocess our instruction given the data we have to get the
1165 // data that we need.
1166 // Create a StringRef for String Manipulation of our Name.
1167 const StringRef NameRef(Name);
1168 // Instruction Prefix.
1169 std::string Prefix;
1170 // The type code for our out type string.
1171 std::string OutTypeCode;
1172 // To handle our different cases, we need to check for different postfixes.
1173 // Is our instruction a quad instruction.
1174 bool IsQuad = false;
1175 // Our instruction is of the form <instructionname>_n.
1176 bool HasNPostfix = false;
1177 // Our instruction is of the form <instructionname>_lane.
1178 bool HasLanePostfix = false;
1179 // Our instruction is of the form <instructionname>_dup.
1180 bool HasDupPostfix = false;
1181 // Our instruction is a vcvt instruction which requires special handling.
1182 bool IsSpecialVCvt = false;
1183 // If we have a vtbxN or vtblN instruction, this is set to N.
1184 size_t TBNumber = -1;
1185 // Register Suffix
1186 std::string RegisterSuffix;
1187
1188 PreprocessInstruction(NameRef, InstName, Prefix,
1189 HasNPostfix, HasLanePostfix, HasDupPostfix,
1190 IsSpecialVCvt, TBNumber);
1191
1192 InstructionTypeCode(OutTypeStr, Ck, IsQuad, OutTypeCode);
1193 GenerateRegisterCheckPattern(Name, Proto, OutTypeCode, HasNPostfix, IsQuad,
1194 HasLanePostfix, HasDupPostfix, TBNumber,
1195 RegisterSuffix);
1196
1197 // In the following section, we handle a bunch of special cases. You can tell
1198 // a special case by the fact we are returning early.
1199
1200 // If our instruction is a logical instruction without postfix or a
1201 // hidden LOp just return the current Prefix.
1202 if (Ck == ClassL || IsHiddenLOp) {
1203 Result.push_back(Prefix + " " + RegisterSuffix);
1204 return;
1205 }
1206
1207 // If we have a vmov, due to the many different cases, some of which
1208 // vary within the different intrinsics generated for a single
1209 // instruction type, just output a vmov. (e.g. given an instruction
1210 // A, A.u32 might be vmov and A.u8 might be vmov.8).
1211 //
1212 // FIXME: Maybe something can be done about this. The two cases that we care
1213 // about are vmov as an LType and vmov as a WType.
1214 if (Prefix == "vmov") {
1215 Result.push_back(Prefix + " " + RegisterSuffix);
1216 return;
1217 }
1218
1219 // In the following section, we handle special cases.
1220
1221 if (OutTypeCode == "64") {
1222 // If we have a 64 bit vdup/vext and are handling an uint64x1_t
1223 // type, the intrinsic will be optimized away, so just return
1224 // nothing. On the other hand if we are handling an uint64x2_t
1225 // (i.e. quad instruction), vdup/vmov instructions should be
1226 // emitted.
1227 if (Prefix == "vdup" || Prefix == "vext") {
1228 if (IsQuad) {
1229 Result.push_back("{{vmov|vdup}}");
1230 }
1231 return;
1232 }
1233
1234 // v{st,ld}{2,3,4}_{u,s}64 emit v{st,ld}1.64 instructions with
1235 // multiple register operands.
1236 bool MultiLoadPrefix = Prefix == "vld2" || Prefix == "vld3"
1237 || Prefix == "vld4";
1238 bool MultiStorePrefix = Prefix == "vst2" || Prefix == "vst3"
1239 || Prefix == "vst4";
1240 if (MultiLoadPrefix || MultiStorePrefix) {
1241 Result.push_back(NameRef.slice(0, 3).str() + "1.64");
1242 return;
1243 }
1244
1245 // v{st,ld}1_{lane,dup}_{u64,s64} use vldr/vstr/vmov/str instead of
1246 // emitting said instructions. So return a check for
1247 // vldr/vstr/vmov/str instead.
1248 if (HasLanePostfix || HasDupPostfix) {
1249 if (Prefix == "vst1") {
1250 Result.push_back("{{str|vstr|vmov}}");
1251 return;
1252 } else if (Prefix == "vld1") {
1253 Result.push_back("{{ldr|vldr|vmov}}");
1254 return;
1255 }
1256 }
1257 }
1258
1259 // vzip.32/vuzp.32 are the same instruction as vtrn.32 and are
1260 // sometimes disassembled as vtrn.32. We use a regex to handle both
1261 // cases.
1262 if ((Prefix == "vzip" || Prefix == "vuzp") && OutTypeCode == "32") {
1263 Result.push_back("{{vtrn|" + Prefix + "}}.32 " + RegisterSuffix);
1264 return;
1265 }
1266
1267 // Currently on most ARM processors, we do not use vmla/vmls for
1268 // quad floating point operations. Instead we output vmul + vadd. So
1269 // check if we have one of those instructions and just output a
1270 // check for vmul.
1271 if (OutTypeCode == "f32") {
1272 if (Prefix == "vmls") {
1273 Result.push_back("vmul." + OutTypeCode + " " + RegisterSuffix);
1274 Result.push_back("vsub." + OutTypeCode);
1275 return;
1276 } else if (Prefix == "vmla") {
1277 Result.push_back("vmul." + OutTypeCode + " " + RegisterSuffix);
1278 Result.push_back("vadd." + OutTypeCode);
1279 return;
1280 }
1281 }
1282
1283 // If we have vcvt, get the input type from the instruction name
1284 // (which should be of the form instname_inputtype) and append it
1285 // before the output type.
1286 if (Prefix == "vcvt") {
1287 const std::string inTypeCode = NameRef.substr(NameRef.find_last_of("_")+1);
1288 Prefix += "." + inTypeCode;
1289 }
1290
1291 // Append output type code to get our final mangled instruction.
1292 Prefix += "." + OutTypeCode;
1293
1294 Result.push_back(Prefix + " " + RegisterSuffix);
1295}
1296
Peter Collingbourne51d77772011-10-06 13:03:08 +00001297/// UseMacro - Examine the prototype string to determine if the intrinsic
1298/// should be defined as a preprocessor macro instead of an inline function.
1299static bool UseMacro(const std::string &proto) {
1300 // If this builtin takes an immediate argument, we need to #define it rather
1301 // than use a standard declaration, so that SemaChecking can range check
1302 // the immediate passed by the user.
1303 if (proto.find('i') != std::string::npos)
1304 return true;
1305
1306 // Pointer arguments need to use macros to avoid hiding aligned attributes
1307 // from the pointer type.
1308 if (proto.find('p') != std::string::npos ||
1309 proto.find('c') != std::string::npos)
1310 return true;
1311
1312 return false;
1313}
1314
1315/// MacroArgUsedDirectly - Return true if argument i for an intrinsic that is
1316/// defined as a macro should be accessed directly instead of being first
1317/// assigned to a local temporary.
1318static bool MacroArgUsedDirectly(const std::string &proto, unsigned i) {
1319 // True for constant ints (i), pointers (p) and const pointers (c).
1320 return (proto[i] == 'i' || proto[i] == 'p' || proto[i] == 'c');
1321}
1322
1323// Generate the string "(argtype a, argtype b, ...)"
1324static std::string GenArgs(const std::string &proto, StringRef typestr) {
1325 bool define = UseMacro(proto);
1326 char arg = 'a';
1327
1328 std::string s;
1329 s += "(";
1330
1331 for (unsigned i = 1, e = proto.size(); i != e; ++i, ++arg) {
1332 if (define) {
1333 // Some macro arguments are used directly instead of being assigned
1334 // to local temporaries; prepend an underscore prefix to make their
1335 // names consistent with the local temporaries.
1336 if (MacroArgUsedDirectly(proto, i))
1337 s += "__";
1338 } else {
1339 s += TypeString(proto[i], typestr) + " __";
1340 }
1341 s.push_back(arg);
1342 if ((i + 1) < e)
1343 s += ", ";
1344 }
1345
1346 s += ")";
1347 return s;
1348}
1349
1350// Macro arguments are not type-checked like inline function arguments, so
1351// assign them to local temporaries to get the right type checking.
1352static std::string GenMacroLocals(const std::string &proto, StringRef typestr) {
1353 char arg = 'a';
1354 std::string s;
1355 bool generatedLocal = false;
1356
1357 for (unsigned i = 1, e = proto.size(); i != e; ++i, ++arg) {
1358 // Do not create a temporary for an immediate argument.
1359 // That would defeat the whole point of using a macro!
Peter Collingbourne51d77772011-10-06 13:03:08 +00001360 if (MacroArgUsedDirectly(proto, i))
1361 continue;
1362 generatedLocal = true;
1363
1364 s += TypeString(proto[i], typestr) + " __";
1365 s.push_back(arg);
1366 s += " = (";
1367 s.push_back(arg);
1368 s += "); ";
1369 }
1370
1371 if (generatedLocal)
1372 s += "\\\n ";
1373 return s;
1374}
1375
1376// Use the vmovl builtin to sign-extend or zero-extend a vector.
Jiangning Liu097a4b42013-09-09 02:21:08 +00001377static std::string Extend(StringRef typestr, const std::string &a, bool h=0) {
1378 std::string s, high;
1379 high = h ? "_high" : "";
1380 s = MangleName("vmovl" + high, typestr, ClassS);
Peter Collingbourne51d77772011-10-06 13:03:08 +00001381 s += "(" + a + ")";
1382 return s;
1383}
1384
Jiangning Liu097a4b42013-09-09 02:21:08 +00001385// Get the high 64-bit part of a vector
1386static std::string GetHigh(const std::string &a, StringRef typestr) {
1387 std::string s;
1388 s = MangleName("vget_high", typestr, ClassS);
1389 s += "(" + a + ")";
1390 return s;
1391}
1392
1393// Gen operation with two operands and get high 64-bit for both of two operands.
1394static std::string Gen2OpWith2High(StringRef typestr,
1395 const std::string &op,
1396 const std::string &a,
1397 const std::string &b) {
1398 std::string s;
1399 std::string Op1 = GetHigh(a, typestr);
1400 std::string Op2 = GetHigh(b, typestr);
1401 s = MangleName(op, typestr, ClassS);
1402 s += "(" + Op1 + ", " + Op2 + ");";
1403 return s;
1404}
1405
1406// Gen operation with three operands and get high 64-bit of the latter
1407// two operands.
1408static std::string Gen3OpWith2High(StringRef typestr,
1409 const std::string &op,
1410 const std::string &a,
1411 const std::string &b,
1412 const std::string &c) {
1413 std::string s;
1414 std::string Op1 = GetHigh(b, typestr);
1415 std::string Op2 = GetHigh(c, typestr);
1416 s = MangleName(op, typestr, ClassS);
1417 s += "(" + a + ", " + Op1 + ", " + Op2 + ");";
1418 return s;
1419}
1420
1421// Gen combine operation by putting a on low 64-bit, and b on high 64-bit.
1422static std::string GenCombine(std::string typestr,
1423 const std::string &a,
1424 const std::string &b) {
1425 std::string s;
1426 s = MangleName("vcombine", typestr, ClassS);
1427 s += "(" + a + ", " + b + ")";
1428 return s;
1429}
1430
Peter Collingbourne51d77772011-10-06 13:03:08 +00001431static std::string Duplicate(unsigned nElts, StringRef typestr,
1432 const std::string &a) {
1433 std::string s;
1434
1435 s = "(" + TypeString('d', typestr) + "){ ";
1436 for (unsigned i = 0; i != nElts; ++i) {
1437 s += a;
1438 if ((i + 1) < nElts)
1439 s += ", ";
1440 }
1441 s += " }";
1442
1443 return s;
1444}
1445
1446static std::string SplatLane(unsigned nElts, const std::string &vec,
1447 const std::string &lane) {
1448 std::string s = "__builtin_shufflevector(" + vec + ", " + vec;
1449 for (unsigned i = 0; i < nElts; ++i)
1450 s += ", " + lane;
1451 s += ")";
1452 return s;
1453}
1454
Hao Liu912502b2013-09-04 09:29:13 +00001455static std::string RemoveHigh(const std::string &name) {
1456 std::string s = name;
1457 std::size_t found = s.find("_high_");
1458 if (found == std::string::npos)
1459 PrintFatalError("name should contain \"_high_\" for high intrinsics");
1460 s.replace(found, 5, "");
1461 return s;
1462}
1463
Peter Collingbourne51d77772011-10-06 13:03:08 +00001464static unsigned GetNumElements(StringRef typestr, bool &quad) {
1465 quad = false;
1466 bool dummy = false;
1467 char type = ClassifyType(typestr, quad, dummy, dummy);
1468 unsigned nElts = 0;
1469 switch (type) {
1470 case 'c': nElts = 8; break;
1471 case 's': nElts = 4; break;
1472 case 'i': nElts = 2; break;
1473 case 'l': nElts = 1; break;
1474 case 'h': nElts = 4; break;
1475 case 'f': nElts = 2; break;
Tim Northoverb793f0d2013-08-01 09:23:19 +00001476 case 'd':
1477 nElts = 1;
1478 break;
Peter Collingbourne51d77772011-10-06 13:03:08 +00001479 default:
Joerg Sonnenberger38859ee2012-10-25 16:37:08 +00001480 PrintFatalError("unhandled type!");
Peter Collingbourne51d77772011-10-06 13:03:08 +00001481 }
1482 if (quad) nElts <<= 1;
1483 return nElts;
1484}
1485
1486// Generate the definition for this intrinsic, e.g. "a + b" for OpAdd.
Hao Liu912502b2013-09-04 09:29:13 +00001487static std::string GenOpString(const std::string &name, OpKind op,
1488 const std::string &proto, StringRef typestr) {
Peter Collingbourne51d77772011-10-06 13:03:08 +00001489 bool quad;
1490 unsigned nElts = GetNumElements(typestr, quad);
1491 bool define = UseMacro(proto);
1492
1493 std::string ts = TypeString(proto[0], typestr);
1494 std::string s;
1495 if (!define) {
1496 s = "return ";
1497 }
1498
1499 switch(op) {
1500 case OpAdd:
1501 s += "__a + __b;";
1502 break;
1503 case OpAddl:
1504 s += Extend(typestr, "__a") + " + " + Extend(typestr, "__b") + ";";
1505 break;
Jiangning Liu097a4b42013-09-09 02:21:08 +00001506 case OpAddlHi:
1507 s += Extend(typestr, "__a", 1) + " + " + Extend(typestr, "__b", 1) + ";";
1508 break;
Peter Collingbourne51d77772011-10-06 13:03:08 +00001509 case OpAddw:
1510 s += "__a + " + Extend(typestr, "__b") + ";";
1511 break;
Jiangning Liu097a4b42013-09-09 02:21:08 +00001512 case OpAddwHi:
1513 s += "__a + " + Extend(typestr, "__b", 1) + ";";
1514 break;
Peter Collingbourne51d77772011-10-06 13:03:08 +00001515 case OpSub:
1516 s += "__a - __b;";
1517 break;
1518 case OpSubl:
1519 s += Extend(typestr, "__a") + " - " + Extend(typestr, "__b") + ";";
1520 break;
Jiangning Liu097a4b42013-09-09 02:21:08 +00001521 case OpSublHi:
1522 s += Extend(typestr, "__a", 1) + " - " + Extend(typestr, "__b", 1) + ";";
1523 break;
Peter Collingbourne51d77772011-10-06 13:03:08 +00001524 case OpSubw:
1525 s += "__a - " + Extend(typestr, "__b") + ";";
1526 break;
Jiangning Liu097a4b42013-09-09 02:21:08 +00001527 case OpSubwHi:
1528 s += "__a - " + Extend(typestr, "__b", 1) + ";";
1529 break;
Peter Collingbourne51d77772011-10-06 13:03:08 +00001530 case OpMulN:
1531 s += "__a * " + Duplicate(nElts, typestr, "__b") + ";";
1532 break;
1533 case OpMulLane:
1534 s += "__a * " + SplatLane(nElts, "__b", "__c") + ";";
1535 break;
Jiangning Liu0aa1a882013-10-04 09:21:17 +00001536 case OpMulXLane:
1537 s += MangleName("vmulx", typestr, ClassS) + "(__a, " +
1538 SplatLane(nElts, "__b", "__c") + ");";
1539 break;
Peter Collingbourne51d77772011-10-06 13:03:08 +00001540 case OpMul:
1541 s += "__a * __b;";
1542 break;
1543 case OpMullLane:
1544 s += MangleName("vmull", typestr, ClassS) + "(__a, " +
1545 SplatLane(nElts, "__b", "__c") + ");";
1546 break;
Jiangning Liu0aa1a882013-10-04 09:21:17 +00001547 case OpMullHiLane:
1548 s += MangleName("vmull", typestr, ClassS) + "(" +
1549 GetHigh("__a", typestr) + ", " + SplatLane(nElts, "__b", "__c") + ");";
1550 break;
Peter Collingbourne51d77772011-10-06 13:03:08 +00001551 case OpMlaN:
1552 s += "__a + (__b * " + Duplicate(nElts, typestr, "__c") + ");";
1553 break;
1554 case OpMlaLane:
1555 s += "__a + (__b * " + SplatLane(nElts, "__c", "__d") + ");";
1556 break;
1557 case OpMla:
1558 s += "__a + (__b * __c);";
1559 break;
1560 case OpMlalN:
1561 s += "__a + " + MangleName("vmull", typestr, ClassS) + "(__b, " +
1562 Duplicate(nElts, typestr, "__c") + ");";
1563 break;
1564 case OpMlalLane:
1565 s += "__a + " + MangleName("vmull", typestr, ClassS) + "(__b, " +
1566 SplatLane(nElts, "__c", "__d") + ");";
1567 break;
Jiangning Liu0aa1a882013-10-04 09:21:17 +00001568 case OpMlalHiLane:
1569 s += "__a + " + MangleName("vmull", typestr, ClassS) + "(" +
1570 GetHigh("__b", typestr) + ", " + SplatLane(nElts, "__c", "__d") + ");";
1571 break;
Peter Collingbourne51d77772011-10-06 13:03:08 +00001572 case OpMlal:
1573 s += "__a + " + MangleName("vmull", typestr, ClassS) + "(__b, __c);";
1574 break;
Jiangning Liu097a4b42013-09-09 02:21:08 +00001575 case OpMullHi:
1576 s += Gen2OpWith2High(typestr, "vmull", "__a", "__b");
1577 break;
1578 case OpMlalHi:
1579 s += Gen3OpWith2High(typestr, "vmlal", "__a", "__b", "__c");
1580 break;
Peter Collingbourne51d77772011-10-06 13:03:08 +00001581 case OpMlsN:
1582 s += "__a - (__b * " + Duplicate(nElts, typestr, "__c") + ");";
1583 break;
1584 case OpMlsLane:
1585 s += "__a - (__b * " + SplatLane(nElts, "__c", "__d") + ");";
1586 break;
Jiangning Liu0aa1a882013-10-04 09:21:17 +00001587 case OpFMSLane:
1588 s += TypeString(proto[1], typestr) + " __a1 = __a; \\\n ";
1589 s += TypeString(proto[2], typestr) + " __b1 = __b; \\\n ";
1590 s += TypeString(proto[3], typestr) + " __c1 = __c; \\\n ";
1591 s += MangleName("vfma_lane", typestr, ClassS) + "(__a1, __b1, -__c1, __d);";
1592 break;
1593 case OpFMSLaneQ:
1594 s += TypeString(proto[1], typestr) + " __a1 = __a; \\\n ";
1595 s += TypeString(proto[2], typestr) + " __b1 = __b; \\\n ";
1596 s += TypeString(proto[3], typestr) + " __c1 = __c; \\\n ";
1597 s += MangleName("vfma_laneq", typestr, ClassS) + "(__a1, __b1, -__c1, __d);";
1598 break;
Peter Collingbourne51d77772011-10-06 13:03:08 +00001599 case OpMls:
1600 s += "__a - (__b * __c);";
1601 break;
1602 case OpMlslN:
1603 s += "__a - " + MangleName("vmull", typestr, ClassS) + "(__b, " +
1604 Duplicate(nElts, typestr, "__c") + ");";
1605 break;
1606 case OpMlslLane:
1607 s += "__a - " + MangleName("vmull", typestr, ClassS) + "(__b, " +
1608 SplatLane(nElts, "__c", "__d") + ");";
1609 break;
Jiangning Liu0aa1a882013-10-04 09:21:17 +00001610 case OpMlslHiLane:
1611 s += "__a - " + MangleName("vmull", typestr, ClassS) + "(" +
1612 GetHigh("__b", typestr) + ", " + SplatLane(nElts, "__c", "__d") + ");";
1613 break;
Peter Collingbourne51d77772011-10-06 13:03:08 +00001614 case OpMlsl:
1615 s += "__a - " + MangleName("vmull", typestr, ClassS) + "(__b, __c);";
1616 break;
Jiangning Liu097a4b42013-09-09 02:21:08 +00001617 case OpMlslHi:
1618 s += Gen3OpWith2High(typestr, "vmlsl", "__a", "__b", "__c");
1619 break;
Peter Collingbourne51d77772011-10-06 13:03:08 +00001620 case OpQDMullLane:
1621 s += MangleName("vqdmull", typestr, ClassS) + "(__a, " +
1622 SplatLane(nElts, "__b", "__c") + ");";
1623 break;
Jiangning Liu0aa1a882013-10-04 09:21:17 +00001624 case OpQDMullHiLane:
1625 s += MangleName("vqdmull", typestr, ClassS) + "(" +
1626 GetHigh("__a", typestr) + ", " + SplatLane(nElts, "__b", "__c") + ");";
1627 break;
Peter Collingbourne51d77772011-10-06 13:03:08 +00001628 case OpQDMlalLane:
1629 s += MangleName("vqdmlal", typestr, ClassS) + "(__a, __b, " +
1630 SplatLane(nElts, "__c", "__d") + ");";
1631 break;
Jiangning Liu0aa1a882013-10-04 09:21:17 +00001632 case OpQDMlalHiLane:
1633 s += MangleName("vqdmlal", typestr, ClassS) + "(__a, " +
1634 GetHigh("__b", typestr) + ", " + SplatLane(nElts, "__c", "__d") + ");";
1635 break;
Peter Collingbourne51d77772011-10-06 13:03:08 +00001636 case OpQDMlslLane:
1637 s += MangleName("vqdmlsl", typestr, ClassS) + "(__a, __b, " +
1638 SplatLane(nElts, "__c", "__d") + ");";
1639 break;
Jiangning Liu0aa1a882013-10-04 09:21:17 +00001640 case OpQDMlslHiLane:
1641 s += MangleName("vqdmlsl", typestr, ClassS) + "(__a, " +
1642 GetHigh("__b", typestr) + ", " + SplatLane(nElts, "__c", "__d") + ");";
1643 break;
Peter Collingbourne51d77772011-10-06 13:03:08 +00001644 case OpQDMulhLane:
1645 s += MangleName("vqdmulh", typestr, ClassS) + "(__a, " +
1646 SplatLane(nElts, "__b", "__c") + ");";
1647 break;
1648 case OpQRDMulhLane:
1649 s += MangleName("vqrdmulh", typestr, ClassS) + "(__a, " +
1650 SplatLane(nElts, "__b", "__c") + ");";
1651 break;
1652 case OpEq:
1653 s += "(" + ts + ")(__a == __b);";
1654 break;
1655 case OpGe:
1656 s += "(" + ts + ")(__a >= __b);";
1657 break;
1658 case OpLe:
1659 s += "(" + ts + ")(__a <= __b);";
1660 break;
1661 case OpGt:
1662 s += "(" + ts + ")(__a > __b);";
1663 break;
1664 case OpLt:
1665 s += "(" + ts + ")(__a < __b);";
1666 break;
1667 case OpNeg:
1668 s += " -__a;";
1669 break;
1670 case OpNot:
1671 s += " ~__a;";
1672 break;
1673 case OpAnd:
1674 s += "__a & __b;";
1675 break;
1676 case OpOr:
1677 s += "__a | __b;";
1678 break;
1679 case OpXor:
1680 s += "__a ^ __b;";
1681 break;
1682 case OpAndNot:
1683 s += "__a & ~__b;";
1684 break;
1685 case OpOrNot:
1686 s += "__a | ~__b;";
1687 break;
1688 case OpCast:
1689 s += "(" + ts + ")__a;";
1690 break;
1691 case OpConcat:
1692 s += "(" + ts + ")__builtin_shufflevector((int64x1_t)__a";
1693 s += ", (int64x1_t)__b, 0, 1);";
1694 break;
1695 case OpHi:
Jim Grosbachcd765392013-05-15 02:40:04 +00001696 // nElts is for the result vector, so the source is twice that number.
1697 s += "__builtin_shufflevector(__a, __a";
1698 for (unsigned i = nElts; i < nElts * 2; ++i)
1699 s += ", " + utostr(i);
1700 s+= ");";
Peter Collingbourne51d77772011-10-06 13:03:08 +00001701 break;
1702 case OpLo:
Jim Grosbachcd765392013-05-15 02:40:04 +00001703 s += "__builtin_shufflevector(__a, __a";
1704 for (unsigned i = 0; i < nElts; ++i)
1705 s += ", " + utostr(i);
1706 s+= ");";
Peter Collingbourne51d77772011-10-06 13:03:08 +00001707 break;
1708 case OpDup:
1709 s += Duplicate(nElts, typestr, "__a") + ";";
1710 break;
1711 case OpDupLane:
1712 s += SplatLane(nElts, "__a", "__b") + ";";
1713 break;
1714 case OpSelect:
1715 // ((0 & 1) | (~0 & 2))
1716 s += "(" + ts + ")";
1717 ts = TypeString(proto[1], typestr);
1718 s += "((__a & (" + ts + ")__b) | ";
1719 s += "(~__a & (" + ts + ")__c));";
1720 break;
1721 case OpRev16:
1722 s += "__builtin_shufflevector(__a, __a";
1723 for (unsigned i = 2; i <= nElts; i += 2)
1724 for (unsigned j = 0; j != 2; ++j)
1725 s += ", " + utostr(i - j - 1);
1726 s += ");";
1727 break;
1728 case OpRev32: {
1729 unsigned WordElts = nElts >> (1 + (int)quad);
1730 s += "__builtin_shufflevector(__a, __a";
1731 for (unsigned i = WordElts; i <= nElts; i += WordElts)
1732 for (unsigned j = 0; j != WordElts; ++j)
1733 s += ", " + utostr(i - j - 1);
1734 s += ");";
1735 break;
1736 }
1737 case OpRev64: {
1738 unsigned DblWordElts = nElts >> (int)quad;
1739 s += "__builtin_shufflevector(__a, __a";
1740 for (unsigned i = DblWordElts; i <= nElts; i += DblWordElts)
1741 for (unsigned j = 0; j != DblWordElts; ++j)
1742 s += ", " + utostr(i - j - 1);
1743 s += ");";
1744 break;
1745 }
1746 case OpAbdl: {
1747 std::string abd = MangleName("vabd", typestr, ClassS) + "(__a, __b)";
1748 if (typestr[0] != 'U') {
1749 // vabd results are always unsigned and must be zero-extended.
1750 std::string utype = "U" + typestr.str();
1751 s += "(" + TypeString(proto[0], typestr) + ")";
1752 abd = "(" + TypeString('d', utype) + ")" + abd;
1753 s += Extend(utype, abd) + ";";
1754 } else {
1755 s += Extend(typestr, abd) + ";";
1756 }
1757 break;
1758 }
Jiangning Liu097a4b42013-09-09 02:21:08 +00001759 case OpAbdlHi:
1760 s += Gen2OpWith2High(typestr, "vabdl", "__a", "__b");
1761 break;
1762 case OpAddhnHi: {
1763 std::string addhn = MangleName("vaddhn", typestr, ClassS) + "(__b, __c)";
1764 s += GenCombine(GetNarrowTypestr(typestr), "__a", addhn);
1765 s += ";";
1766 break;
1767 }
1768 case OpRAddhnHi: {
1769 std::string raddhn = MangleName("vraddhn", typestr, ClassS) + "(__b, __c)";
1770 s += GenCombine(GetNarrowTypestr(typestr), "__a", raddhn);
1771 s += ";";
1772 break;
1773 }
1774 case OpSubhnHi: {
1775 std::string subhn = MangleName("vsubhn", typestr, ClassS) + "(__b, __c)";
1776 s += GenCombine(GetNarrowTypestr(typestr), "__a", subhn);
1777 s += ";";
1778 break;
1779 }
1780 case OpRSubhnHi: {
1781 std::string rsubhn = MangleName("vrsubhn", typestr, ClassS) + "(__b, __c)";
1782 s += GenCombine(GetNarrowTypestr(typestr), "__a", rsubhn);
1783 s += ";";
1784 break;
1785 }
Peter Collingbourne51d77772011-10-06 13:03:08 +00001786 case OpAba:
1787 s += "__a + " + MangleName("vabd", typestr, ClassS) + "(__b, __c);";
1788 break;
Jiangning Liu097a4b42013-09-09 02:21:08 +00001789 case OpAbal:
1790 s += "__a + " + MangleName("vabdl", typestr, ClassS) + "(__b, __c);";
Peter Collingbourne51d77772011-10-06 13:03:08 +00001791 break;
Jiangning Liu097a4b42013-09-09 02:21:08 +00001792 case OpAbalHi:
1793 s += Gen3OpWith2High(typestr, "vabal", "__a", "__b", "__c");
1794 break;
1795 case OpQDMullHi:
1796 s += Gen2OpWith2High(typestr, "vqdmull", "__a", "__b");
1797 break;
1798 case OpQDMlalHi:
1799 s += Gen3OpWith2High(typestr, "vqdmlal", "__a", "__b", "__c");
1800 break;
1801 case OpQDMlslHi:
1802 s += Gen3OpWith2High(typestr, "vqdmlsl", "__a", "__b", "__c");
1803 break;
Tim Northoverb793f0d2013-08-01 09:23:19 +00001804 case OpDiv:
1805 s += "__a / __b;";
1806 break;
Hao Liu912502b2013-09-04 09:29:13 +00001807 case OpMovlHi: {
1808 s = TypeString(proto[1], typestr.drop_front()) + " __a1 = " +
1809 MangleName("vget_high", typestr, ClassS) + "(__a);\n " + s;
1810 s += "(" + ts + ")" + MangleName("vshll_n", typestr, ClassS);
1811 s += "(__a1, 0);";
1812 break;
1813 }
1814 case OpLongHi: {
1815 // Another local variable __a1 is needed for calling a Macro,
1816 // or using __a will have naming conflict when Macro expanding.
1817 s += TypeString(proto[1], typestr.drop_front()) + " __a1 = " +
1818 MangleName("vget_high", typestr, ClassS) + "(__a); \\\n";
1819 s += " (" + ts + ")" + MangleName(RemoveHigh(name), typestr, ClassS) +
1820 "(__a1, __b);";
1821 break;
1822 }
1823 case OpNarrowHi: {
1824 s += "(" + ts + ")" + MangleName("vcombine", typestr, ClassS) + "(__a, " +
1825 MangleName(RemoveHigh(name), typestr, ClassS) + "(__b, __c));";
1826 break;
1827 }
Peter Collingbourne51d77772011-10-06 13:03:08 +00001828 default:
Joerg Sonnenberger38859ee2012-10-25 16:37:08 +00001829 PrintFatalError("unknown OpKind!");
Peter Collingbourne51d77772011-10-06 13:03:08 +00001830 }
1831 return s;
1832}
1833
1834static unsigned GetNeonEnum(const std::string &proto, StringRef typestr) {
1835 unsigned mod = proto[0];
Peter Collingbourne51d77772011-10-06 13:03:08 +00001836
1837 if (mod == 'v' || mod == 'f')
1838 mod = proto[1];
1839
1840 bool quad = false;
1841 bool poly = false;
1842 bool usgn = false;
1843 bool scal = false;
1844 bool cnst = false;
1845 bool pntr = false;
1846
1847 // Base type to get the type string for.
1848 char type = ClassifyType(typestr, quad, poly, usgn);
1849
1850 // Based on the modifying character, change the type and width if necessary.
1851 type = ModType(mod, type, quad, poly, usgn, scal, cnst, pntr);
1852
Bob Wilsonda95f732011-11-08 01:16:11 +00001853 NeonTypeFlags::EltType ET;
Peter Collingbourne51d77772011-10-06 13:03:08 +00001854 switch (type) {
1855 case 'c':
Bob Wilsonda95f732011-11-08 01:16:11 +00001856 ET = poly ? NeonTypeFlags::Poly8 : NeonTypeFlags::Int8;
Peter Collingbourne51d77772011-10-06 13:03:08 +00001857 break;
1858 case 's':
Bob Wilsonda95f732011-11-08 01:16:11 +00001859 ET = poly ? NeonTypeFlags::Poly16 : NeonTypeFlags::Int16;
Peter Collingbourne51d77772011-10-06 13:03:08 +00001860 break;
1861 case 'i':
Bob Wilsonda95f732011-11-08 01:16:11 +00001862 ET = NeonTypeFlags::Int32;
Peter Collingbourne51d77772011-10-06 13:03:08 +00001863 break;
1864 case 'l':
Bob Wilsonda95f732011-11-08 01:16:11 +00001865 ET = NeonTypeFlags::Int64;
Peter Collingbourne51d77772011-10-06 13:03:08 +00001866 break;
1867 case 'h':
Bob Wilsonda95f732011-11-08 01:16:11 +00001868 ET = NeonTypeFlags::Float16;
Peter Collingbourne51d77772011-10-06 13:03:08 +00001869 break;
1870 case 'f':
Bob Wilsonda95f732011-11-08 01:16:11 +00001871 ET = NeonTypeFlags::Float32;
Peter Collingbourne51d77772011-10-06 13:03:08 +00001872 break;
Tim Northoverb793f0d2013-08-01 09:23:19 +00001873 case 'd':
1874 ET = NeonTypeFlags::Float64;
1875 break;
Peter Collingbourne51d77772011-10-06 13:03:08 +00001876 default:
Joerg Sonnenberger38859ee2012-10-25 16:37:08 +00001877 PrintFatalError("unhandled type!");
Peter Collingbourne51d77772011-10-06 13:03:08 +00001878 }
Bob Wilsonda95f732011-11-08 01:16:11 +00001879 NeonTypeFlags Flags(ET, usgn, quad && proto[1] != 'g');
1880 return Flags.getFlags();
Peter Collingbourne51d77772011-10-06 13:03:08 +00001881}
1882
Jiangning Liu03916912013-10-05 08:22:55 +00001883static bool ProtoHasScalar(const std::string proto)
1884{
1885 return (proto.find('s') != std::string::npos
1886 || proto.find('r') != std::string::npos);
1887}
1888
Peter Collingbourne51d77772011-10-06 13:03:08 +00001889// Generate the definition for this intrinsic, e.g. __builtin_neon_cls(a)
1890static std::string GenBuiltin(const std::string &name, const std::string &proto,
1891 StringRef typestr, ClassKind ck) {
1892 std::string s;
1893
1894 // If this builtin returns a struct 2, 3, or 4 vectors, pass it as an implicit
1895 // sret-like argument.
1896 bool sret = (proto[0] >= '2' && proto[0] <= '4');
1897
1898 bool define = UseMacro(proto);
1899
1900 // Check if the prototype has a scalar operand with the type of the vector
1901 // elements. If not, bitcasting the args will take care of arg checking.
1902 // The actual signedness etc. will be taken care of with special enums.
Jiangning Liu03916912013-10-05 08:22:55 +00001903 if (!ProtoHasScalar(proto))
Peter Collingbourne51d77772011-10-06 13:03:08 +00001904 ck = ClassB;
1905
1906 if (proto[0] != 'v') {
1907 std::string ts = TypeString(proto[0], typestr);
1908
1909 if (define) {
1910 if (sret)
1911 s += ts + " r; ";
1912 else
1913 s += "(" + ts + ")";
1914 } else if (sret) {
1915 s += ts + " r; ";
1916 } else {
1917 s += "return (" + ts + ")";
1918 }
1919 }
1920
1921 bool splat = proto.find('a') != std::string::npos;
1922
1923 s += "__builtin_neon_";
1924 if (splat) {
1925 // Call the non-splat builtin: chop off the "_n" suffix from the name.
1926 std::string vname(name, 0, name.size()-2);
1927 s += MangleName(vname, typestr, ck);
1928 } else {
1929 s += MangleName(name, typestr, ck);
1930 }
1931 s += "(";
1932
1933 // Pass the address of the return variable as the first argument to sret-like
1934 // builtins.
1935 if (sret)
1936 s += "&r, ";
1937
1938 char arg = 'a';
1939 for (unsigned i = 1, e = proto.size(); i != e; ++i, ++arg) {
1940 std::string args = std::string(&arg, 1);
1941
1942 // Use the local temporaries instead of the macro arguments.
1943 args = "__" + args;
1944
1945 bool argQuad = false;
1946 bool argPoly = false;
1947 bool argUsgn = false;
1948 bool argScalar = false;
1949 bool dummy = false;
1950 char argType = ClassifyType(typestr, argQuad, argPoly, argUsgn);
1951 argType = ModType(proto[i], argType, argQuad, argPoly, argUsgn, argScalar,
1952 dummy, dummy);
1953
1954 // Handle multiple-vector values specially, emitting each subvector as an
1955 // argument to the __builtin.
1956 if (proto[i] >= '2' && proto[i] <= '4') {
1957 // Check if an explicit cast is needed.
1958 if (argType != 'c' || argPoly || argUsgn)
1959 args = (argQuad ? "(int8x16_t)" : "(int8x8_t)") + args;
1960
1961 for (unsigned vi = 0, ve = proto[i] - '0'; vi != ve; ++vi) {
1962 s += args + ".val[" + utostr(vi) + "]";
1963 if ((vi + 1) < ve)
1964 s += ", ";
1965 }
1966 if ((i + 1) < e)
1967 s += ", ";
1968
1969 continue;
1970 }
1971
1972 if (splat && (i + 1) == e)
1973 args = Duplicate(GetNumElements(typestr, argQuad), typestr, args);
1974
1975 // Check if an explicit cast is needed.
1976 if ((splat || !argScalar) &&
1977 ((ck == ClassB && argType != 'c') || argPoly || argUsgn)) {
1978 std::string argTypeStr = "c";
1979 if (ck != ClassB)
1980 argTypeStr = argType;
1981 if (argQuad)
1982 argTypeStr = "Q" + argTypeStr;
1983 args = "(" + TypeString('d', argTypeStr) + ")" + args;
1984 }
1985
1986 s += args;
1987 if ((i + 1) < e)
1988 s += ", ";
1989 }
1990
1991 // Extra constant integer to hold type class enum for this function, e.g. s8
1992 if (ck == ClassB)
1993 s += ", " + utostr(GetNeonEnum(proto, typestr));
1994
1995 s += ");";
1996
1997 if (proto[0] != 'v' && sret) {
1998 if (define)
1999 s += " r;";
2000 else
2001 s += " return r;";
2002 }
2003 return s;
2004}
2005
2006static std::string GenBuiltinDef(const std::string &name,
2007 const std::string &proto,
2008 StringRef typestr, ClassKind ck) {
2009 std::string s("BUILTIN(__builtin_neon_");
2010
2011 // If all types are the same size, bitcasting the args will take care
2012 // of arg checking. The actual signedness etc. will be taken care of with
2013 // special enums.
Jiangning Liu03916912013-10-05 08:22:55 +00002014 if (!ProtoHasScalar(proto))
Peter Collingbourne51d77772011-10-06 13:03:08 +00002015 ck = ClassB;
2016
2017 s += MangleName(name, typestr, ck);
2018 s += ", \"";
2019
2020 for (unsigned i = 0, e = proto.size(); i != e; ++i)
2021 s += BuiltinTypeString(proto[i], typestr, ck, i == 0);
2022
2023 // Extra constant integer to hold type class enum for this function, e.g. s8
2024 if (ck == ClassB)
2025 s += "i";
2026
2027 s += "\", \"n\")";
2028 return s;
2029}
2030
2031static std::string GenIntrinsic(const std::string &name,
2032 const std::string &proto,
2033 StringRef outTypeStr, StringRef inTypeStr,
2034 OpKind kind, ClassKind classKind) {
2035 assert(!proto.empty() && "");
Jim Grosbach667381b2012-05-09 18:17:30 +00002036 bool define = UseMacro(proto) && kind != OpUnavailable;
Peter Collingbourne51d77772011-10-06 13:03:08 +00002037 std::string s;
2038
2039 // static always inline + return type
2040 if (define)
2041 s += "#define ";
2042 else
2043 s += "__ai " + TypeString(proto[0], outTypeStr) + " ";
2044
2045 // Function name with type suffix
2046 std::string mangledName = MangleName(name, outTypeStr, ClassS);
2047 if (outTypeStr != inTypeStr) {
2048 // If the input type is different (e.g., for vreinterpret), append a suffix
2049 // for the input type. String off a "Q" (quad) prefix so that MangleName
2050 // does not insert another "q" in the name.
2051 unsigned typeStrOff = (inTypeStr[0] == 'Q' ? 1 : 0);
2052 StringRef inTypeNoQuad = inTypeStr.substr(typeStrOff);
2053 mangledName = MangleName(mangledName, inTypeNoQuad, ClassS);
2054 }
2055 s += mangledName;
2056
2057 // Function arguments
2058 s += GenArgs(proto, inTypeStr);
2059
2060 // Definition.
2061 if (define) {
2062 s += " __extension__ ({ \\\n ";
2063 s += GenMacroLocals(proto, inTypeStr);
Jim Grosbach667381b2012-05-09 18:17:30 +00002064 } else if (kind == OpUnavailable) {
2065 s += " __attribute__((unavailable));\n";
2066 return s;
2067 } else
Jim Grosbach66981c72012-08-03 17:30:46 +00002068 s += " {\n ";
Peter Collingbourne51d77772011-10-06 13:03:08 +00002069
2070 if (kind != OpNone)
Hao Liu912502b2013-09-04 09:29:13 +00002071 s += GenOpString(name, kind, proto, outTypeStr);
Peter Collingbourne51d77772011-10-06 13:03:08 +00002072 else
2073 s += GenBuiltin(name, proto, outTypeStr, classKind);
2074 if (define)
2075 s += " })";
2076 else
2077 s += " }";
2078 s += "\n";
2079 return s;
2080}
2081
2082/// run - Read the records in arm_neon.td and output arm_neon.h. arm_neon.h
2083/// is comprised of type definitions and function declarations.
2084void NeonEmitter::run(raw_ostream &OS) {
2085 OS <<
2086 "/*===---- arm_neon.h - ARM Neon intrinsics ------------------------------"
2087 "---===\n"
2088 " *\n"
2089 " * Permission is hereby granted, free of charge, to any person obtaining "
2090 "a copy\n"
2091 " * of this software and associated documentation files (the \"Software\"),"
2092 " to deal\n"
2093 " * in the Software without restriction, including without limitation the "
2094 "rights\n"
2095 " * to use, copy, modify, merge, publish, distribute, sublicense, "
2096 "and/or sell\n"
2097 " * copies of the Software, and to permit persons to whom the Software is\n"
2098 " * furnished to do so, subject to the following conditions:\n"
2099 " *\n"
2100 " * The above copyright notice and this permission notice shall be "
2101 "included in\n"
2102 " * all copies or substantial portions of the Software.\n"
2103 " *\n"
2104 " * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, "
2105 "EXPRESS OR\n"
2106 " * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF "
2107 "MERCHANTABILITY,\n"
2108 " * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT "
2109 "SHALL THE\n"
2110 " * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR "
2111 "OTHER\n"
2112 " * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, "
2113 "ARISING FROM,\n"
2114 " * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER "
2115 "DEALINGS IN\n"
2116 " * THE SOFTWARE.\n"
2117 " *\n"
2118 " *===--------------------------------------------------------------------"
2119 "---===\n"
2120 " */\n\n";
2121
2122 OS << "#ifndef __ARM_NEON_H\n";
2123 OS << "#define __ARM_NEON_H\n\n";
2124
Tim Northoverb793f0d2013-08-01 09:23:19 +00002125 OS << "#if !defined(__ARM_NEON__) && !defined(__AARCH_FEATURE_ADVSIMD)\n";
Peter Collingbourne51d77772011-10-06 13:03:08 +00002126 OS << "#error \"NEON support not enabled\"\n";
2127 OS << "#endif\n\n";
2128
2129 OS << "#include <stdint.h>\n\n";
2130
2131 // Emit NEON-specific scalar typedefs.
2132 OS << "typedef float float32_t;\n";
Tim Northoverb793f0d2013-08-01 09:23:19 +00002133 OS << "typedef __fp16 float16_t;\n";
2134
2135 OS << "#ifdef __aarch64__\n";
2136 OS << "typedef double float64_t;\n";
2137 OS << "#endif\n\n";
2138
2139 // For now, signedness of polynomial types depends on target
2140 OS << "#ifdef __aarch64__\n";
2141 OS << "typedef uint8_t poly8_t;\n";
2142 OS << "typedef uint16_t poly16_t;\n";
2143 OS << "#else\n";
Peter Collingbourne51d77772011-10-06 13:03:08 +00002144 OS << "typedef int8_t poly8_t;\n";
2145 OS << "typedef int16_t poly16_t;\n";
Tim Northoverb793f0d2013-08-01 09:23:19 +00002146 OS << "#endif\n";
Peter Collingbourne51d77772011-10-06 13:03:08 +00002147
2148 // Emit Neon vector typedefs.
Tim Northoverb793f0d2013-08-01 09:23:19 +00002149 std::string TypedefTypes(
Jiangning Liu0aa1a882013-10-04 09:21:17 +00002150 "cQcsQsiQilQlUcQUcUsQUsUiQUiUlQUlhQhfQfdQdPcQPcPsQPs");
Peter Collingbourne51d77772011-10-06 13:03:08 +00002151 SmallVector<StringRef, 24> TDTypeVec;
2152 ParseTypes(0, TypedefTypes, TDTypeVec);
2153
2154 // Emit vector typedefs.
Jiangning Liu0aa1a882013-10-04 09:21:17 +00002155 bool isA64 = false;
Peter Collingbourne51d77772011-10-06 13:03:08 +00002156 for (unsigned i = 0, e = TDTypeVec.size(); i != e; ++i) {
2157 bool dummy, quad = false, poly = false;
Tim Northoverb793f0d2013-08-01 09:23:19 +00002158 char type = ClassifyType(TDTypeVec[i], quad, poly, dummy);
Jiangning Liu0aa1a882013-10-04 09:21:17 +00002159 bool preinsert = false;
2160 bool postinsert = false;
Tim Northoverb793f0d2013-08-01 09:23:19 +00002161
Jiangning Liu0aa1a882013-10-04 09:21:17 +00002162 if (type == 'd') {
2163 preinsert = isA64? false: true;
Tim Northoverb793f0d2013-08-01 09:23:19 +00002164 isA64 = true;
Jiangning Liu0aa1a882013-10-04 09:21:17 +00002165 } else {
2166 postinsert = isA64? true: false;
2167 isA64 = false;
2168 }
2169 if (postinsert)
2170 OS << "#endif\n";
2171 if (preinsert)
Tim Northoverb793f0d2013-08-01 09:23:19 +00002172 OS << "#ifdef __aarch64__\n";
2173
Peter Collingbourne51d77772011-10-06 13:03:08 +00002174 if (poly)
2175 OS << "typedef __attribute__((neon_polyvector_type(";
2176 else
2177 OS << "typedef __attribute__((neon_vector_type(";
2178
2179 unsigned nElts = GetNumElements(TDTypeVec[i], quad);
2180 OS << utostr(nElts) << "))) ";
2181 if (nElts < 10)
2182 OS << " ";
2183
2184 OS << TypeString('s', TDTypeVec[i]);
2185 OS << " " << TypeString('d', TDTypeVec[i]) << ";\n";
Tim Northoverb793f0d2013-08-01 09:23:19 +00002186
Peter Collingbourne51d77772011-10-06 13:03:08 +00002187 }
2188 OS << "\n";
2189
2190 // Emit struct typedefs.
Jiangning Liu0aa1a882013-10-04 09:21:17 +00002191 isA64 = false;
Peter Collingbourne51d77772011-10-06 13:03:08 +00002192 for (unsigned vi = 2; vi != 5; ++vi) {
2193 for (unsigned i = 0, e = TDTypeVec.size(); i != e; ++i) {
Tim Northoverb793f0d2013-08-01 09:23:19 +00002194 bool dummy, quad = false, poly = false;
2195 char type = ClassifyType(TDTypeVec[i], quad, poly, dummy);
Jiangning Liu0aa1a882013-10-04 09:21:17 +00002196 bool preinsert = false;
2197 bool postinsert = false;
Tim Northoverb793f0d2013-08-01 09:23:19 +00002198
Jiangning Liu0aa1a882013-10-04 09:21:17 +00002199 if (type == 'd') {
2200 preinsert = isA64? false: true;
Tim Northoverb793f0d2013-08-01 09:23:19 +00002201 isA64 = true;
Jiangning Liu0aa1a882013-10-04 09:21:17 +00002202 } else {
2203 postinsert = isA64? true: false;
2204 isA64 = false;
2205 }
2206 if (postinsert)
2207 OS << "#endif\n";
2208 if (preinsert)
Tim Northoverb793f0d2013-08-01 09:23:19 +00002209 OS << "#ifdef __aarch64__\n";
2210
Peter Collingbourne51d77772011-10-06 13:03:08 +00002211 std::string ts = TypeString('d', TDTypeVec[i]);
2212 std::string vs = TypeString('0' + vi, TDTypeVec[i]);
2213 OS << "typedef struct " << vs << " {\n";
2214 OS << " " << ts << " val";
2215 OS << "[" << utostr(vi) << "]";
2216 OS << ";\n} ";
Tim Northoverb793f0d2013-08-01 09:23:19 +00002217 OS << vs << ";\n";
Tim Northoverb793f0d2013-08-01 09:23:19 +00002218 OS << "\n";
Peter Collingbourne51d77772011-10-06 13:03:08 +00002219 }
2220 }
2221
Bob Wilson1e8058f2013-04-12 20:17:20 +00002222 OS<<"#define __ai static inline __attribute__((__always_inline__, __nodebug__))\n\n";
Peter Collingbourne51d77772011-10-06 13:03:08 +00002223
2224 std::vector<Record*> RV = Records.getAllDerivedDefinitions("Inst");
2225
Tim Northoverb793f0d2013-08-01 09:23:19 +00002226 StringMap<ClassKind> EmittedMap;
2227
Peter Collingbourne51d77772011-10-06 13:03:08 +00002228 // Emit vmovl, vmull and vabd intrinsics first so they can be used by other
2229 // intrinsics. (Some of the saturating multiply instructions are also
2230 // used to implement the corresponding "_lane" variants, but tablegen
2231 // sorts the records into alphabetical order so that the "_lane" variants
2232 // come after the intrinsics they use.)
Tim Northoverb793f0d2013-08-01 09:23:19 +00002233 emitIntrinsic(OS, Records.getDef("VMOVL"), EmittedMap);
2234 emitIntrinsic(OS, Records.getDef("VMULL"), EmittedMap);
2235 emitIntrinsic(OS, Records.getDef("VABD"), EmittedMap);
Jiangning Liu097a4b42013-09-09 02:21:08 +00002236 emitIntrinsic(OS, Records.getDef("VABDL"), EmittedMap);
Tim Northoverb793f0d2013-08-01 09:23:19 +00002237
2238 // ARM intrinsics must be emitted before AArch64 intrinsics to ensure
2239 // common intrinsics appear only once in the output stream.
2240 // The check for uniquiness is done in emitIntrinsic.
2241 // Emit ARM intrinsics.
2242 for (unsigned i = 0, e = RV.size(); i != e; ++i) {
2243 Record *R = RV[i];
2244
2245 // Skip AArch64 intrinsics; they will be emitted at the end.
2246 bool isA64 = R->getValueAsBit("isA64");
2247 if (isA64)
2248 continue;
2249
2250 if (R->getName() != "VMOVL" && R->getName() != "VMULL" &&
2251 R->getName() != "VABD")
2252 emitIntrinsic(OS, R, EmittedMap);
2253 }
2254
2255 // Emit AArch64-specific intrinsics.
2256 OS << "#ifdef __aarch64__\n";
Peter Collingbourne51d77772011-10-06 13:03:08 +00002257
Jiangning Liu097a4b42013-09-09 02:21:08 +00002258 emitIntrinsic(OS, Records.getDef("VMOVL_HIGH"), EmittedMap);
2259 emitIntrinsic(OS, Records.getDef("VMULL_HIGH"), EmittedMap);
2260 emitIntrinsic(OS, Records.getDef("VABDL_HIGH"), EmittedMap);
2261
Peter Collingbourne51d77772011-10-06 13:03:08 +00002262 for (unsigned i = 0, e = RV.size(); i != e; ++i) {
2263 Record *R = RV[i];
Tim Northoverb793f0d2013-08-01 09:23:19 +00002264
2265 // Skip ARM intrinsics already included above.
2266 bool isA64 = R->getValueAsBit("isA64");
2267 if (!isA64)
2268 continue;
2269
2270 emitIntrinsic(OS, R, EmittedMap);
Peter Collingbourne51d77772011-10-06 13:03:08 +00002271 }
2272
Tim Northoverb793f0d2013-08-01 09:23:19 +00002273 OS << "#endif\n\n";
2274
Peter Collingbourne51d77772011-10-06 13:03:08 +00002275 OS << "#undef __ai\n\n";
2276 OS << "#endif /* __ARM_NEON_H */\n";
2277}
2278
2279/// emitIntrinsic - Write out the arm_neon.h header file definitions for the
Tim Northoverb793f0d2013-08-01 09:23:19 +00002280/// intrinsics specified by record R checking for intrinsic uniqueness.
2281void NeonEmitter::emitIntrinsic(raw_ostream &OS, Record *R,
2282 StringMap<ClassKind> &EmittedMap) {
Peter Collingbourne51d77772011-10-06 13:03:08 +00002283 std::string name = R->getValueAsString("Name");
2284 std::string Proto = R->getValueAsString("Prototype");
2285 std::string Types = R->getValueAsString("Types");
2286
2287 SmallVector<StringRef, 16> TypeVec;
2288 ParseTypes(R, Types, TypeVec);
2289
2290 OpKind kind = OpMap[R->getValueAsDef("Operand")->getName()];
2291
2292 ClassKind classKind = ClassNone;
2293 if (R->getSuperClasses().size() >= 2)
2294 classKind = ClassMap[R->getSuperClasses()[1]];
2295 if (classKind == ClassNone && kind == OpNone)
Joerg Sonnenberger38859ee2012-10-25 16:37:08 +00002296 PrintFatalError(R->getLoc(), "Builtin has no class kind");
Peter Collingbourne51d77772011-10-06 13:03:08 +00002297
2298 for (unsigned ti = 0, te = TypeVec.size(); ti != te; ++ti) {
2299 if (kind == OpReinterpret) {
2300 bool outQuad = false;
2301 bool dummy = false;
2302 (void)ClassifyType(TypeVec[ti], outQuad, dummy, dummy);
2303 for (unsigned srcti = 0, srcte = TypeVec.size();
2304 srcti != srcte; ++srcti) {
2305 bool inQuad = false;
2306 (void)ClassifyType(TypeVec[srcti], inQuad, dummy, dummy);
2307 if (srcti == ti || inQuad != outQuad)
2308 continue;
Tim Northoverb793f0d2013-08-01 09:23:19 +00002309 std::string s = GenIntrinsic(name, Proto, TypeVec[ti], TypeVec[srcti],
2310 OpCast, ClassS);
2311 if (EmittedMap.count(s))
2312 continue;
2313 EmittedMap[s] = ClassS;
2314 OS << s;
Peter Collingbourne51d77772011-10-06 13:03:08 +00002315 }
2316 } else {
Tim Northoverb793f0d2013-08-01 09:23:19 +00002317 std::string s =
2318 GenIntrinsic(name, Proto, TypeVec[ti], TypeVec[ti], kind, classKind);
2319 if (EmittedMap.count(s))
2320 continue;
2321 EmittedMap[s] = classKind;
2322 OS << s;
Peter Collingbourne51d77772011-10-06 13:03:08 +00002323 }
2324 }
2325 OS << "\n";
2326}
2327
2328static unsigned RangeFromType(const char mod, StringRef typestr) {
2329 // base type to get the type string for.
2330 bool quad = false, dummy = false;
2331 char type = ClassifyType(typestr, quad, dummy, dummy);
2332 type = ModType(mod, type, quad, dummy, dummy, dummy, dummy, dummy);
2333
2334 switch (type) {
2335 case 'c':
2336 return (8 << (int)quad) - 1;
2337 case 'h':
2338 case 's':
2339 return (4 << (int)quad) - 1;
2340 case 'f':
2341 case 'i':
2342 return (2 << (int)quad) - 1;
Jiangning Liu0aa1a882013-10-04 09:21:17 +00002343 case 'd':
Peter Collingbourne51d77772011-10-06 13:03:08 +00002344 case 'l':
2345 return (1 << (int)quad) - 1;
2346 default:
Joerg Sonnenberger38859ee2012-10-25 16:37:08 +00002347 PrintFatalError("unhandled type!");
Peter Collingbourne51d77772011-10-06 13:03:08 +00002348 }
Peter Collingbourne51d77772011-10-06 13:03:08 +00002349}
2350
Tim Northoverb793f0d2013-08-01 09:23:19 +00002351/// Generate the ARM and AArch64 intrinsic range checking code for
2352/// shift/lane immediates, checking for unique declarations.
2353void
2354NeonEmitter::genIntrinsicRangeCheckCode(raw_ostream &OS,
2355 StringMap<ClassKind> &A64IntrinsicMap,
2356 bool isA64RangeCheck) {
2357 std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst");
Peter Collingbourne51d77772011-10-06 13:03:08 +00002358 StringMap<OpKind> EmittedMap;
2359
Tim Northoverb793f0d2013-08-01 09:23:19 +00002360 // Generate the intrinsic range checking code for shift/lane immediates.
2361 if (isA64RangeCheck)
2362 OS << "#ifdef GET_NEON_AARCH64_IMMEDIATE_CHECK\n";
2363 else
2364 OS << "#ifdef GET_NEON_IMMEDIATE_CHECK\n";
2365
Peter Collingbourne51d77772011-10-06 13:03:08 +00002366 for (unsigned i = 0, e = RV.size(); i != e; ++i) {
2367 Record *R = RV[i];
Tim Northoverb793f0d2013-08-01 09:23:19 +00002368
Peter Collingbourne51d77772011-10-06 13:03:08 +00002369 OpKind k = OpMap[R->getValueAsDef("Operand")->getName()];
2370 if (k != OpNone)
2371 continue;
2372
Tim Northoverb793f0d2013-08-01 09:23:19 +00002373 std::string name = R->getValueAsString("Name");
Peter Collingbourne51d77772011-10-06 13:03:08 +00002374 std::string Proto = R->getValueAsString("Prototype");
Tim Northoverb793f0d2013-08-01 09:23:19 +00002375 std::string Types = R->getValueAsString("Types");
Kevin Qin944f09f2013-08-29 07:55:15 +00002376 std::string Rename = name + "@" + Proto;
Peter Collingbourne51d77772011-10-06 13:03:08 +00002377
2378 // Functions with 'a' (the splat code) in the type prototype should not get
2379 // their own builtin as they use the non-splat variant.
2380 if (Proto.find('a') != std::string::npos)
2381 continue;
2382
Tim Northoverb793f0d2013-08-01 09:23:19 +00002383 // Functions which do not have an immediate do not need to have range
2384 // checking code emitted.
2385 size_t immPos = Proto.find('i');
2386 if (immPos == std::string::npos)
2387 continue;
2388
Peter Collingbourne51d77772011-10-06 13:03:08 +00002389 SmallVector<StringRef, 16> TypeVec;
2390 ParseTypes(R, Types, TypeVec);
2391
2392 if (R->getSuperClasses().size() < 2)
Joerg Sonnenberger38859ee2012-10-25 16:37:08 +00002393 PrintFatalError(R->getLoc(), "Builtin has no class kind");
Peter Collingbourne51d77772011-10-06 13:03:08 +00002394
Peter Collingbourne51d77772011-10-06 13:03:08 +00002395 ClassKind ck = ClassMap[R->getSuperClasses()[1]];
2396
Tim Northoverb793f0d2013-08-01 09:23:19 +00002397 // Do not include AArch64 range checks if not generating code for AArch64.
2398 bool isA64 = R->getValueAsBit("isA64");
2399 if (!isA64RangeCheck && isA64)
2400 continue;
Peter Collingbourne51d77772011-10-06 13:03:08 +00002401
Tim Northoverb793f0d2013-08-01 09:23:19 +00002402 // Include ARM range checks in AArch64 but only if ARM intrinsics are not
2403 // redefined by AArch64 to handle new types.
Kevin Qin944f09f2013-08-29 07:55:15 +00002404 if (isA64RangeCheck && !isA64 && A64IntrinsicMap.count(Rename)) {
2405 ClassKind &A64CK = A64IntrinsicMap[Rename];
Tim Northoverb793f0d2013-08-01 09:23:19 +00002406 if (A64CK == ck && ck != ClassNone)
2407 continue;
2408 }
2409
2410 for (unsigned ti = 0, te = TypeVec.size(); ti != te; ++ti) {
2411 std::string namestr, shiftstr, rangestr;
2412
2413 if (R->getValueAsBit("isVCVT_N")) {
2414 // VCVT between floating- and fixed-point values takes an immediate
Hao Liu912502b2013-09-04 09:29:13 +00002415 // in the range [1, 32] for f32, or [1, 64] for f64.
Tim Northoverb793f0d2013-08-01 09:23:19 +00002416 ck = ClassB;
Hao Liu912502b2013-09-04 09:29:13 +00002417 if (name.find("32") != std::string::npos)
2418 rangestr = "l = 1; u = 31"; // upper bound = l + u
2419 else if (name.find("64") != std::string::npos)
2420 rangestr = "l = 1; u = 63";
2421 else
2422 PrintFatalError(R->getLoc(),
2423 "Fixed point convert name should contains \"32\" or \"64\"");
Jiangning Liu03916912013-10-05 08:22:55 +00002424 } else if (!ProtoHasScalar(Proto)) {
Tim Northoverb793f0d2013-08-01 09:23:19 +00002425 // Builtins which are overloaded by type will need to have their upper
2426 // bound computed at Sema time based on the type constant.
2427 ck = ClassB;
2428 if (R->getValueAsBit("isShift")) {
2429 shiftstr = ", true";
2430
2431 // Right shifts have an 'r' in the name, left shifts do not.
2432 if (name.find('r') != std::string::npos)
2433 rangestr = "l = 1; ";
2434 }
2435 rangestr += "u = RFT(TV" + shiftstr + ")";
2436 } else {
2437 // The immediate generally refers to a lane in the preceding argument.
2438 assert(immPos > 0 && "unexpected immediate operand");
2439 rangestr =
2440 "u = " + utostr(RangeFromType(Proto[immPos - 1], TypeVec[ti]));
2441 }
2442 // Make sure cases appear only once by uniquing them in a string map.
2443 namestr = MangleName(name, TypeVec[ti], ck);
2444 if (EmittedMap.count(namestr))
2445 continue;
2446 EmittedMap[namestr] = OpNone;
2447
2448 // Calculate the index of the immediate that should be range checked.
2449 unsigned immidx = 0;
2450
2451 // Builtins that return a struct of multiple vectors have an extra
2452 // leading arg for the struct return.
2453 if (Proto[0] >= '2' && Proto[0] <= '4')
2454 ++immidx;
2455
2456 // Add one to the index for each argument until we reach the immediate
2457 // to be checked. Structs of vectors are passed as multiple arguments.
2458 for (unsigned ii = 1, ie = Proto.size(); ii != ie; ++ii) {
2459 switch (Proto[ii]) {
2460 default:
2461 immidx += 1;
2462 break;
2463 case '2':
2464 immidx += 2;
2465 break;
2466 case '3':
2467 immidx += 3;
2468 break;
2469 case '4':
2470 immidx += 4;
2471 break;
2472 case 'i':
2473 ie = ii + 1;
2474 break;
2475 }
2476 }
2477 if (isA64RangeCheck)
2478 OS << "case AArch64::BI__builtin_neon_";
2479 else
2480 OS << "case ARM::BI__builtin_neon_";
2481 OS << MangleName(name, TypeVec[ti], ck) << ": i = " << immidx << "; "
2482 << rangestr << "; break;\n";
Peter Collingbourne51d77772011-10-06 13:03:08 +00002483 }
2484 }
2485 OS << "#endif\n\n";
Tim Northoverb793f0d2013-08-01 09:23:19 +00002486}
2487
2488/// Generate the ARM and AArch64 overloaded type checking code for
2489/// SemaChecking.cpp, checking for unique builtin declarations.
2490void
2491NeonEmitter::genOverloadTypeCheckCode(raw_ostream &OS,
2492 StringMap<ClassKind> &A64IntrinsicMap,
2493 bool isA64TypeCheck) {
2494 std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst");
2495 StringMap<OpKind> EmittedMap;
Peter Collingbourne51d77772011-10-06 13:03:08 +00002496
2497 // Generate the overloaded type checking code for SemaChecking.cpp
Tim Northoverb793f0d2013-08-01 09:23:19 +00002498 if (isA64TypeCheck)
2499 OS << "#ifdef GET_NEON_AARCH64_OVERLOAD_CHECK\n";
2500 else
2501 OS << "#ifdef GET_NEON_OVERLOAD_CHECK\n";
2502
Peter Collingbourne51d77772011-10-06 13:03:08 +00002503 for (unsigned i = 0, e = RV.size(); i != e; ++i) {
2504 Record *R = RV[i];
2505 OpKind k = OpMap[R->getValueAsDef("Operand")->getName()];
2506 if (k != OpNone)
2507 continue;
2508
2509 std::string Proto = R->getValueAsString("Prototype");
2510 std::string Types = R->getValueAsString("Types");
2511 std::string name = R->getValueAsString("Name");
Kevin Qin944f09f2013-08-29 07:55:15 +00002512 std::string Rename = name + "@" + Proto;
2513
Peter Collingbourne51d77772011-10-06 13:03:08 +00002514 // Functions with 'a' (the splat code) in the type prototype should not get
2515 // their own builtin as they use the non-splat variant.
2516 if (Proto.find('a') != std::string::npos)
2517 continue;
2518
2519 // Functions which have a scalar argument cannot be overloaded, no need to
2520 // check them if we are emitting the type checking code.
Jiangning Liu03916912013-10-05 08:22:55 +00002521 if (ProtoHasScalar(Proto))
Peter Collingbourne51d77772011-10-06 13:03:08 +00002522 continue;
2523
2524 SmallVector<StringRef, 16> TypeVec;
2525 ParseTypes(R, Types, TypeVec);
2526
2527 if (R->getSuperClasses().size() < 2)
Joerg Sonnenberger38859ee2012-10-25 16:37:08 +00002528 PrintFatalError(R->getLoc(), "Builtin has no class kind");
Peter Collingbourne51d77772011-10-06 13:03:08 +00002529
Tim Northoverb793f0d2013-08-01 09:23:19 +00002530 // Do not include AArch64 type checks if not generating code for AArch64.
2531 bool isA64 = R->getValueAsBit("isA64");
2532 if (!isA64TypeCheck && isA64)
2533 continue;
2534
2535 // Include ARM type check in AArch64 but only if ARM intrinsics
2536 // are not redefined in AArch64 to handle new types, e.g. "vabd" is a SIntr
2537 // redefined in AArch64 to handle an additional 2 x f64 type.
2538 ClassKind ck = ClassMap[R->getSuperClasses()[1]];
Kevin Qin944f09f2013-08-29 07:55:15 +00002539 if (isA64TypeCheck && !isA64 && A64IntrinsicMap.count(Rename)) {
2540 ClassKind &A64CK = A64IntrinsicMap[Rename];
Tim Northoverb793f0d2013-08-01 09:23:19 +00002541 if (A64CK == ck && ck != ClassNone)
2542 continue;
2543 }
2544
Peter Collingbourne51d77772011-10-06 13:03:08 +00002545 int si = -1, qi = -1;
Richard Smithf8ee6bc2012-08-14 01:28:02 +00002546 uint64_t mask = 0, qmask = 0;
Peter Collingbourne51d77772011-10-06 13:03:08 +00002547 for (unsigned ti = 0, te = TypeVec.size(); ti != te; ++ti) {
2548 // Generate the switch case(s) for this builtin for the type validation.
2549 bool quad = false, poly = false, usgn = false;
2550 (void) ClassifyType(TypeVec[ti], quad, poly, usgn);
2551
2552 if (quad) {
2553 qi = ti;
Richard Smithf8ee6bc2012-08-14 01:28:02 +00002554 qmask |= 1ULL << GetNeonEnum(Proto, TypeVec[ti]);
Peter Collingbourne51d77772011-10-06 13:03:08 +00002555 } else {
2556 si = ti;
Richard Smithf8ee6bc2012-08-14 01:28:02 +00002557 mask |= 1ULL << GetNeonEnum(Proto, TypeVec[ti]);
Peter Collingbourne51d77772011-10-06 13:03:08 +00002558 }
2559 }
Bob Wilson46482552011-11-16 21:32:23 +00002560
2561 // Check if the builtin function has a pointer or const pointer argument.
2562 int PtrArgNum = -1;
2563 bool HasConstPtr = false;
2564 for (unsigned arg = 1, arge = Proto.size(); arg != arge; ++arg) {
2565 char ArgType = Proto[arg];
2566 if (ArgType == 'c') {
2567 HasConstPtr = true;
2568 PtrArgNum = arg - 1;
2569 break;
2570 }
2571 if (ArgType == 'p') {
2572 PtrArgNum = arg - 1;
2573 break;
2574 }
2575 }
2576 // For sret builtins, adjust the pointer argument index.
2577 if (PtrArgNum >= 0 && (Proto[0] >= '2' && Proto[0] <= '4'))
2578 PtrArgNum += 1;
2579
Bob Wilson9082cdd2011-12-20 06:16:48 +00002580 // Omit type checking for the pointer arguments of vld1_lane, vld1_dup,
2581 // and vst1_lane intrinsics. Using a pointer to the vector element
2582 // type with one of those operations causes codegen to select an aligned
2583 // load/store instruction. If you want an unaligned operation,
2584 // the pointer argument needs to have less alignment than element type,
2585 // so just accept any pointer type.
2586 if (name == "vld1_lane" || name == "vld1_dup" || name == "vst1_lane") {
2587 PtrArgNum = -1;
2588 HasConstPtr = false;
2589 }
2590
Bob Wilson6f9f03e2011-11-08 05:04:11 +00002591 if (mask) {
Tim Northoverb793f0d2013-08-01 09:23:19 +00002592 if (isA64TypeCheck)
2593 OS << "case AArch64::BI__builtin_neon_";
2594 else
2595 OS << "case ARM::BI__builtin_neon_";
2596 OS << MangleName(name, TypeVec[si], ClassB) << ": mask = "
2597 << "0x" << utohexstr(mask) << "ULL";
Bob Wilson46482552011-11-16 21:32:23 +00002598 if (PtrArgNum >= 0)
2599 OS << "; PtrArgNum = " << PtrArgNum;
Bob Wilson6f9f03e2011-11-08 05:04:11 +00002600 if (HasConstPtr)
2601 OS << "; HasConstPtr = true";
2602 OS << "; break;\n";
2603 }
2604 if (qmask) {
Tim Northoverb793f0d2013-08-01 09:23:19 +00002605 if (isA64TypeCheck)
2606 OS << "case AArch64::BI__builtin_neon_";
2607 else
2608 OS << "case ARM::BI__builtin_neon_";
2609 OS << MangleName(name, TypeVec[qi], ClassB) << ": mask = "
2610 << "0x" << utohexstr(qmask) << "ULL";
Bob Wilson46482552011-11-16 21:32:23 +00002611 if (PtrArgNum >= 0)
2612 OS << "; PtrArgNum = " << PtrArgNum;
Bob Wilson6f9f03e2011-11-08 05:04:11 +00002613 if (HasConstPtr)
2614 OS << "; HasConstPtr = true";
2615 OS << "; break;\n";
2616 }
Peter Collingbourne51d77772011-10-06 13:03:08 +00002617 }
2618 OS << "#endif\n\n";
Tim Northoverb793f0d2013-08-01 09:23:19 +00002619}
Peter Collingbourne51d77772011-10-06 13:03:08 +00002620
Tim Northoverb793f0d2013-08-01 09:23:19 +00002621/// genBuiltinsDef: Generate the BuiltinsARM.def and BuiltinsAArch64.def
2622/// declaration of builtins, checking for unique builtin declarations.
2623void NeonEmitter::genBuiltinsDef(raw_ostream &OS,
2624 StringMap<ClassKind> &A64IntrinsicMap,
2625 bool isA64GenBuiltinDef) {
2626 std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst");
2627 StringMap<OpKind> EmittedMap;
2628
2629 // Generate BuiltinsARM.def and BuiltinsAArch64.def
2630 if (isA64GenBuiltinDef)
2631 OS << "#ifdef GET_NEON_AARCH64_BUILTINS\n";
2632 else
2633 OS << "#ifdef GET_NEON_BUILTINS\n";
2634
Peter Collingbourne51d77772011-10-06 13:03:08 +00002635 for (unsigned i = 0, e = RV.size(); i != e; ++i) {
2636 Record *R = RV[i];
Peter Collingbourne51d77772011-10-06 13:03:08 +00002637 OpKind k = OpMap[R->getValueAsDef("Operand")->getName()];
2638 if (k != OpNone)
2639 continue;
2640
Peter Collingbourne51d77772011-10-06 13:03:08 +00002641 std::string Proto = R->getValueAsString("Prototype");
Tim Northoverb793f0d2013-08-01 09:23:19 +00002642 std::string name = R->getValueAsString("Name");
Kevin Qin944f09f2013-08-29 07:55:15 +00002643 std::string Rename = name + "@" + Proto;
Peter Collingbourne51d77772011-10-06 13:03:08 +00002644
2645 // Functions with 'a' (the splat code) in the type prototype should not get
2646 // their own builtin as they use the non-splat variant.
2647 if (Proto.find('a') != std::string::npos)
2648 continue;
2649
Tim Northoverb793f0d2013-08-01 09:23:19 +00002650 std::string Types = R->getValueAsString("Types");
Peter Collingbourne51d77772011-10-06 13:03:08 +00002651 SmallVector<StringRef, 16> TypeVec;
2652 ParseTypes(R, Types, TypeVec);
2653
2654 if (R->getSuperClasses().size() < 2)
Joerg Sonnenberger38859ee2012-10-25 16:37:08 +00002655 PrintFatalError(R->getLoc(), "Builtin has no class kind");
Peter Collingbourne51d77772011-10-06 13:03:08 +00002656
2657 ClassKind ck = ClassMap[R->getSuperClasses()[1]];
2658
Tim Northoverb793f0d2013-08-01 09:23:19 +00002659 // Do not include AArch64 BUILTIN() macros if not generating
2660 // code for AArch64
2661 bool isA64 = R->getValueAsBit("isA64");
2662 if (!isA64GenBuiltinDef && isA64)
2663 continue;
Peter Collingbourne51d77772011-10-06 13:03:08 +00002664
Tim Northoverb793f0d2013-08-01 09:23:19 +00002665 // Include ARM BUILTIN() macros in AArch64 but only if ARM intrinsics
2666 // are not redefined in AArch64 to handle new types, e.g. "vabd" is a SIntr
2667 // redefined in AArch64 to handle an additional 2 x f64 type.
Kevin Qin944f09f2013-08-29 07:55:15 +00002668 if (isA64GenBuiltinDef && !isA64 && A64IntrinsicMap.count(Rename)) {
2669 ClassKind &A64CK = A64IntrinsicMap[Rename];
Tim Northoverb793f0d2013-08-01 09:23:19 +00002670 if (A64CK == ck && ck != ClassNone)
Peter Collingbourne51d77772011-10-06 13:03:08 +00002671 continue;
Tim Northoverb793f0d2013-08-01 09:23:19 +00002672 }
Peter Collingbourne51d77772011-10-06 13:03:08 +00002673
Tim Northoverb793f0d2013-08-01 09:23:19 +00002674 for (unsigned ti = 0, te = TypeVec.size(); ti != te; ++ti) {
2675 // Generate the declaration for this builtin, ensuring
2676 // that each unique BUILTIN() macro appears only once in the output
2677 // stream.
2678 std::string bd = GenBuiltinDef(name, Proto, TypeVec[ti], ck);
2679 if (EmittedMap.count(bd))
2680 continue;
Peter Collingbourne51d77772011-10-06 13:03:08 +00002681
Tim Northoverb793f0d2013-08-01 09:23:19 +00002682 EmittedMap[bd] = OpNone;
2683 OS << bd << "\n";
Peter Collingbourne51d77772011-10-06 13:03:08 +00002684 }
2685 }
2686 OS << "#endif\n\n";
2687}
2688
Tim Northoverb793f0d2013-08-01 09:23:19 +00002689/// runHeader - Emit a file with sections defining:
2690/// 1. the NEON section of BuiltinsARM.def and BuiltinsAArch64.def.
2691/// 2. the SemaChecking code for the type overload checking.
2692/// 3. the SemaChecking code for validation of intrinsic immediate arguments.
2693void NeonEmitter::runHeader(raw_ostream &OS) {
2694 std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst");
2695
2696 // build a map of AArch64 intriniscs to be used in uniqueness checks.
2697 StringMap<ClassKind> A64IntrinsicMap;
2698 for (unsigned i = 0, e = RV.size(); i != e; ++i) {
2699 Record *R = RV[i];
2700
2701 bool isA64 = R->getValueAsBit("isA64");
2702 if (!isA64)
2703 continue;
2704
2705 ClassKind CK = ClassNone;
2706 if (R->getSuperClasses().size() >= 2)
2707 CK = ClassMap[R->getSuperClasses()[1]];
2708
2709 std::string Name = R->getValueAsString("Name");
Kevin Qin944f09f2013-08-29 07:55:15 +00002710 std::string Proto = R->getValueAsString("Prototype");
2711 std::string Rename = Name + "@" + Proto;
2712 if (A64IntrinsicMap.count(Rename))
Tim Northoverb793f0d2013-08-01 09:23:19 +00002713 continue;
Kevin Qin944f09f2013-08-29 07:55:15 +00002714 A64IntrinsicMap[Rename] = CK;
Tim Northoverb793f0d2013-08-01 09:23:19 +00002715 }
2716
2717 // Generate BuiltinsARM.def for ARM
2718 genBuiltinsDef(OS, A64IntrinsicMap, false);
2719
2720 // Generate BuiltinsAArch64.def for AArch64
2721 genBuiltinsDef(OS, A64IntrinsicMap, true);
2722
2723 // Generate ARM overloaded type checking code for SemaChecking.cpp
2724 genOverloadTypeCheckCode(OS, A64IntrinsicMap, false);
2725
2726 // Generate AArch64 overloaded type checking code for SemaChecking.cpp
2727 genOverloadTypeCheckCode(OS, A64IntrinsicMap, true);
2728
2729 // Generate ARM range checking code for shift/lane immediates.
2730 genIntrinsicRangeCheckCode(OS, A64IntrinsicMap, false);
2731
2732 // Generate the AArch64 range checking code for shift/lane immediates.
2733 genIntrinsicRangeCheckCode(OS, A64IntrinsicMap, true);
2734}
2735
Peter Collingbourne51d77772011-10-06 13:03:08 +00002736/// GenTest - Write out a test for the intrinsic specified by the name and
2737/// type strings, including the embedded patterns for FileCheck to match.
2738static std::string GenTest(const std::string &name,
2739 const std::string &proto,
2740 StringRef outTypeStr, StringRef inTypeStr,
Michael Gottesman7200bd62013-04-16 22:48:52 +00002741 bool isShift, bool isHiddenLOp,
Tim Northoverb793f0d2013-08-01 09:23:19 +00002742 ClassKind ck, const std::string &InstName,
2743 bool isA64,
2744 std::string & testFuncProto) {
Peter Collingbourne51d77772011-10-06 13:03:08 +00002745 assert(!proto.empty() && "");
2746 std::string s;
2747
2748 // Function name with type suffix
2749 std::string mangledName = MangleName(name, outTypeStr, ClassS);
2750 if (outTypeStr != inTypeStr) {
2751 // If the input type is different (e.g., for vreinterpret), append a suffix
2752 // for the input type. String off a "Q" (quad) prefix so that MangleName
2753 // does not insert another "q" in the name.
2754 unsigned typeStrOff = (inTypeStr[0] == 'Q' ? 1 : 0);
2755 StringRef inTypeNoQuad = inTypeStr.substr(typeStrOff);
2756 mangledName = MangleName(mangledName, inTypeNoQuad, ClassS);
2757 }
2758
Tim Northoverb793f0d2013-08-01 09:23:19 +00002759 // todo: GenerateChecksForIntrinsic does not generate CHECK
2760 // for aarch64 instructions yet
Michael Gottesmanc327f872013-04-16 23:00:26 +00002761 std::vector<std::string> FileCheckPatterns;
Tim Northoverb793f0d2013-08-01 09:23:19 +00002762 if (!isA64) {
2763 GenerateChecksForIntrinsic(name, proto, outTypeStr, inTypeStr, ck, InstName,
2764 isHiddenLOp, FileCheckPatterns);
2765 s+= "// CHECK_ARM: test_" + mangledName + "\n";
2766 }
2767 s += "// CHECK_AARCH64: test_" + mangledName + "\n";
Michael Gottesmanc327f872013-04-16 23:00:26 +00002768
Peter Collingbourne51d77772011-10-06 13:03:08 +00002769 // Emit the FileCheck patterns.
Michael Gottesmanc327f872013-04-16 23:00:26 +00002770 // If for any reason we do not want to emit a check, mangledInst
2771 // will be the empty string.
2772 if (FileCheckPatterns.size()) {
2773 for (std::vector<std::string>::const_iterator i = FileCheckPatterns.begin(),
2774 e = FileCheckPatterns.end();
2775 i != e;
2776 ++i) {
Tim Northoverb793f0d2013-08-01 09:23:19 +00002777 s += "// CHECK_ARM: " + *i + "\n";
Michael Gottesmanc327f872013-04-16 23:00:26 +00002778 }
2779 }
Peter Collingbourne51d77772011-10-06 13:03:08 +00002780
2781 // Emit the start of the test function.
Tim Northoverb793f0d2013-08-01 09:23:19 +00002782
2783 testFuncProto = TypeString(proto[0], outTypeStr) + " test_" + mangledName + "(";
Peter Collingbourne51d77772011-10-06 13:03:08 +00002784 char arg = 'a';
2785 std::string comma;
2786 for (unsigned i = 1, e = proto.size(); i != e; ++i, ++arg) {
2787 // Do not create arguments for values that must be immediate constants.
2788 if (proto[i] == 'i')
2789 continue;
Tim Northoverb793f0d2013-08-01 09:23:19 +00002790 testFuncProto += comma + TypeString(proto[i], inTypeStr) + " ";
2791 testFuncProto.push_back(arg);
Peter Collingbourne51d77772011-10-06 13:03:08 +00002792 comma = ", ";
2793 }
Tim Northoverb793f0d2013-08-01 09:23:19 +00002794 testFuncProto += ")";
2795
2796 s+= testFuncProto;
2797 s+= " {\n ";
Peter Collingbourne51d77772011-10-06 13:03:08 +00002798
2799 if (proto[0] != 'v')
2800 s += "return ";
2801 s += mangledName + "(";
2802 arg = 'a';
2803 for (unsigned i = 1, e = proto.size(); i != e; ++i, ++arg) {
2804 if (proto[i] == 'i') {
2805 // For immediate operands, test the maximum value.
2806 if (isShift)
2807 s += "1"; // FIXME
2808 else
2809 // The immediate generally refers to a lane in the preceding argument.
2810 s += utostr(RangeFromType(proto[i-1], inTypeStr));
2811 } else {
2812 s.push_back(arg);
2813 }
2814 if ((i + 1) < e)
2815 s += ", ";
2816 }
2817 s += ");\n}\n\n";
2818 return s;
2819}
2820
Tim Northoverb793f0d2013-08-01 09:23:19 +00002821/// Write out all intrinsic tests for the specified target, checking
2822/// for intrinsic test uniqueness.
2823void NeonEmitter::genTargetTest(raw_ostream &OS, StringMap<OpKind> &EmittedMap,
2824 bool isA64GenTest) {
2825 if (isA64GenTest)
2826 OS << "#ifdef __aarch64__\n";
Peter Collingbourne51d77772011-10-06 13:03:08 +00002827
Tim Northoverb793f0d2013-08-01 09:23:19 +00002828 std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst");
Peter Collingbourne51d77772011-10-06 13:03:08 +00002829 for (unsigned i = 0, e = RV.size(); i != e; ++i) {
2830 Record *R = RV[i];
2831 std::string name = R->getValueAsString("Name");
2832 std::string Proto = R->getValueAsString("Prototype");
2833 std::string Types = R->getValueAsString("Types");
2834 bool isShift = R->getValueAsBit("isShift");
Michael Gottesman7200bd62013-04-16 22:48:52 +00002835 std::string InstName = R->getValueAsString("InstName");
2836 bool isHiddenLOp = R->getValueAsBit("isHiddenLInst");
Tim Northoverb793f0d2013-08-01 09:23:19 +00002837 bool isA64 = R->getValueAsBit("isA64");
2838
2839 // do not include AArch64 intrinsic test if not generating
2840 // code for AArch64
2841 if (!isA64GenTest && isA64)
2842 continue;
Peter Collingbourne51d77772011-10-06 13:03:08 +00002843
2844 SmallVector<StringRef, 16> TypeVec;
2845 ParseTypes(R, Types, TypeVec);
2846
Michael Gottesman7200bd62013-04-16 22:48:52 +00002847 ClassKind ck = ClassMap[R->getSuperClasses()[1]];
Peter Collingbourne51d77772011-10-06 13:03:08 +00002848 OpKind kind = OpMap[R->getValueAsDef("Operand")->getName()];
Jim Grosbach667381b2012-05-09 18:17:30 +00002849 if (kind == OpUnavailable)
2850 continue;
Peter Collingbourne51d77772011-10-06 13:03:08 +00002851 for (unsigned ti = 0, te = TypeVec.size(); ti != te; ++ti) {
2852 if (kind == OpReinterpret) {
2853 bool outQuad = false;
2854 bool dummy = false;
2855 (void)ClassifyType(TypeVec[ti], outQuad, dummy, dummy);
2856 for (unsigned srcti = 0, srcte = TypeVec.size();
2857 srcti != srcte; ++srcti) {
2858 bool inQuad = false;
2859 (void)ClassifyType(TypeVec[srcti], inQuad, dummy, dummy);
2860 if (srcti == ti || inQuad != outQuad)
2861 continue;
Tim Northoverb793f0d2013-08-01 09:23:19 +00002862 std::string testFuncProto;
2863 std::string s = GenTest(name, Proto, TypeVec[ti], TypeVec[srcti],
2864 isShift, isHiddenLOp, ck, InstName, isA64,
2865 testFuncProto);
2866 if (EmittedMap.count(testFuncProto))
2867 continue;
2868 EmittedMap[testFuncProto] = kind;
2869 OS << s << "\n";
Peter Collingbourne51d77772011-10-06 13:03:08 +00002870 }
2871 } else {
Tim Northoverb793f0d2013-08-01 09:23:19 +00002872 std::string testFuncProto;
2873 std::string s = GenTest(name, Proto, TypeVec[ti], TypeVec[ti], isShift,
2874 isHiddenLOp, ck, InstName, isA64, testFuncProto);
2875 if (EmittedMap.count(testFuncProto))
2876 continue;
2877 EmittedMap[testFuncProto] = kind;
2878 OS << s << "\n";
Peter Collingbourne51d77772011-10-06 13:03:08 +00002879 }
2880 }
Peter Collingbourne51d77772011-10-06 13:03:08 +00002881 }
Tim Northoverb793f0d2013-08-01 09:23:19 +00002882
2883 if (isA64GenTest)
2884 OS << "#endif\n";
2885}
2886/// runTests - Write out a complete set of tests for all of the Neon
2887/// intrinsics.
2888void NeonEmitter::runTests(raw_ostream &OS) {
2889 OS << "// RUN: %clang_cc1 -triple thumbv7s-apple-darwin -target-abi "
2890 "apcs-gnu\\\n"
2891 "// RUN: -target-cpu swift -ffreestanding -Os -S -o - %s\\\n"
2892 "// RUN: | FileCheck %s -check-prefix=CHECK_ARM\n"
2893 "\n"
2894 "// RUN: %clang_cc1 -triple aarch64-none-linux-gnu \\\n"
2895 "// RUN -target-feature +neon -ffreestanding -S -o - %s \\\n"
2896 "// RUN: | FileCheck %s -check-prefix=CHECK_AARCH64\n"
2897 "\n"
2898 "// REQUIRES: long_tests\n"
2899 "\n"
2900 "#include <arm_neon.h>\n"
2901 "\n";
2902
2903 // ARM tests must be emitted before AArch64 tests to ensure
2904 // tests for intrinsics that are common to ARM and AArch64
2905 // appear only once in the output stream.
2906 // The check for uniqueness is done in genTargetTest.
2907 StringMap<OpKind> EmittedMap;
2908
2909 genTargetTest(OS, EmittedMap, false);
2910
2911 genTargetTest(OS, EmittedMap, true);
Peter Collingbourne51d77772011-10-06 13:03:08 +00002912}
2913
Jakob Stoklund Olesen3cc509b2012-06-13 05:12:41 +00002914namespace clang {
2915void EmitNeon(RecordKeeper &Records, raw_ostream &OS) {
2916 NeonEmitter(Records).run(OS);
2917}
2918void EmitNeonSema(RecordKeeper &Records, raw_ostream &OS) {
2919 NeonEmitter(Records).runHeader(OS);
2920}
2921void EmitNeonTest(RecordKeeper &Records, raw_ostream &OS) {
2922 NeonEmitter(Records).runTests(OS);
2923}
2924} // End namespace clang