blob: 7709637445b777f8e71f80ce7d0a31bab304599d [file] [log] [blame]
Nate Begeman5ddb0872010-05-28 01:08:32 +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//===----------------------------------------------------------------------===//
15
16#include "NeonEmitter.h"
17#include "Record.h"
Nate Begeman22237772010-06-02 00:34:55 +000018#include "llvm/ADT/SmallString.h"
19#include "llvm/ADT/SmallVector.h"
Nate Begeman5ddb0872010-05-28 01:08:32 +000020#include "llvm/ADT/StringExtras.h"
21#include "llvm/ADT/StringMap.h"
22#include <string>
23
24using namespace llvm;
25
Nate Begemane66aab52010-06-02 07:14:28 +000026enum OpKind {
27 OpNone,
28 OpAdd,
29 OpSub,
30 OpMul,
31 OpMla,
32 OpMls,
33 OpEq,
34 OpGe,
35 OpLe,
36 OpGt,
37 OpLt,
38 OpNeg,
39 OpNot,
40 OpAnd,
41 OpOr,
42 OpXor,
43 OpAndNot,
44 OpOrNot
45};
46
Nate Begeman22237772010-06-02 00:34:55 +000047static void ParseTypes(Record *r, std::string &s,
48 SmallVectorImpl<StringRef> &TV) {
49 const char *data = s.data();
50 int len = 0;
51
52 for (unsigned i = 0, e = s.size(); i != e; ++i, ++len) {
53 if (data[len] == 'P' || data[len] == 'Q' || data[len] == 'U')
54 continue;
55
56 switch (data[len]) {
57 case 'c':
58 case 's':
59 case 'i':
60 case 'l':
61 case 'h':
62 case 'f':
63 break;
64 default:
65 throw TGError(r->getLoc(),
66 "Unexpected letter: " + std::string(data + len, 1));
67 break;
68 }
69 TV.push_back(StringRef(data, len + 1));
70 data += len + 1;
71 len = -1;
72 }
73}
74
Duncan Sands8dbbace2010-06-02 08:37:30 +000075static char Widen(const char t) {
Nate Begeman22237772010-06-02 00:34:55 +000076 switch (t) {
77 case 'c':
78 return 's';
79 case 's':
80 return 'i';
81 case 'i':
82 return 'l';
83 default: throw "unhandled type in widen!";
84 }
85 return '\0';
86}
87
Nate Begemanaf905ef2010-06-02 06:17:19 +000088static char ClassifyType(StringRef ty, bool &quad, bool &poly, bool &usgn) {
Nate Begeman22237772010-06-02 00:34:55 +000089 unsigned off = 0;
90
Nate Begemanaf905ef2010-06-02 06:17:19 +000091 // remember quad.
92 if (ty[off] == 'Q') {
93 quad = true;
94 ++off;
95 }
96
97 // remember poly.
98 if (ty[off] == 'P') {
99 poly = true;
100 ++off;
101 }
102
103 // remember unsigned.
104 if (ty[off] == 'U') {
105 usgn = true;
106 ++off;
107 }
108
109 // base type to get the type string for.
110 return ty[off];
111}
112
113static std::string TypeString(const char mod, StringRef typestr) {
Nate Begeman22237772010-06-02 00:34:55 +0000114 bool quad = false;
115 bool poly = false;
116 bool usgn = false;
117 bool scal = false;
118 bool cnst = false;
119 bool pntr = false;
120
Nate Begeman22237772010-06-02 00:34:55 +0000121 // base type to get the type string for.
Nate Begemanaf905ef2010-06-02 06:17:19 +0000122 char type = ClassifyType(typestr, quad, poly, usgn);
Nate Begeman22237772010-06-02 00:34:55 +0000123
124 // Based on the modifying character, change the type and width if necessary.
125 switch (mod) {
126 case 'v':
Nate Begemane66aab52010-06-02 07:14:28 +0000127 return "void";
128 case 'i':
129 return "int";
Nate Begeman22237772010-06-02 00:34:55 +0000130 case 't':
131 if (poly) {
132 poly = false;
133 usgn = true;
134 }
135 break;
136 case 'x':
137 usgn = true;
138 if (type == 'f')
139 type = 'i';
140 break;
141 case 'f':
142 type = 'f';
143 break;
144 case 'w':
145 type = Widen(type);
146 quad = true;
147 break;
148 case 'n':
149 type = Widen(type);
150 break;
Nate Begeman22237772010-06-02 00:34:55 +0000151 case 'l':
152 type = 'l';
153 scal = true;
154 usgn = true;
155 break;
156 case 's':
157 scal = true;
158 break;
159 case 'k':
160 quad = true;
161 break;
162 case 'c':
163 cnst = true;
164 case 'p':
165 pntr = true;
166 scal = true;
167 break;
168 default:
169 break;
170 }
171
172 SmallString<128> s;
173
174 if (usgn)
175 s.push_back('u');
176
177 switch (type) {
178 case 'c':
179 s += poly ? "poly8" : "int8";
180 if (scal)
181 break;
182 s += quad ? "x16" : "x8";
183 break;
184 case 's':
185 s += poly ? "poly16" : "int16";
186 if (scal)
187 break;
188 s += quad ? "x8" : "x4";
189 break;
190 case 'i':
191 s += "int32";
192 if (scal)
193 break;
194 s += quad ? "x4" : "x2";
195 break;
196 case 'l':
197 s += "int64";
198 if (scal)
199 break;
200 s += quad ? "x2" : "x1";
201 break;
202 case 'h':
203 s += "float16";
204 if (scal)
205 break;
206 s += quad ? "x8" : "x4";
207 break;
208 case 'f':
209 s += "float32";
210 if (scal)
211 break;
212 s += quad ? "x4" : "x2";
213 break;
Nate Begeman22237772010-06-02 00:34:55 +0000214 default:
215 throw "unhandled type!";
216 break;
217 }
218
219 if (mod == '2')
220 s += "x2";
221 if (mod == '3')
222 s += "x3";
223 if (mod == '4')
224 s += "x4";
225
226 // Append _t, finishing the type string typedef type.
227 s += "_t";
228
229 if (cnst)
230 s += " const";
231
232 if (pntr)
233 s += " *";
234
235 return s.str();
236}
237
238// Turn "vst2_lane" into "vst2q_lane_f32", etc.
239static std::string MangleName(const std::string &name, StringRef typestr) {
Nate Begemanaf905ef2010-06-02 06:17:19 +0000240 bool quad = false;
241 bool poly = false;
242 bool usgn = false;
243 char type = ClassifyType(typestr, quad, poly, usgn);
244
245 std::string s = name;
246
247 switch (type) {
248 case 'c':
249 s += poly ? "_p8" : usgn ? "_u8" : "_s8";
250 break;
251 case 's':
252 s += poly ? "_p16" : usgn ? "_u16" : "_s16";
253 break;
254 case 'i':
255 s += usgn ? "_u32" : "_s32";
256 break;
257 case 'l':
258 s += usgn ? "_u64" : "_s64";
259 break;
260 case 'h':
261 s += "_f16";
262 break;
263 case 'f':
264 s += "_f32";
265 break;
266 default:
267 throw "unhandled type!";
268 break;
269 }
270
271 // Insert a 'q' before the first '_' character so that it ends up before
272 // _lane or _n on vector-scalar operations.
273 if (quad) {
274 size_t pos = s.find('_');
275 s = s.insert(pos, "q");
276 }
277 return s;
Nate Begeman22237772010-06-02 00:34:55 +0000278}
279
Nate Begemanaf905ef2010-06-02 06:17:19 +0000280// Generate the string "(argtype a, argtype b, ...)"
Nate Begeman22237772010-06-02 00:34:55 +0000281static std::string GenArgs(const std::string &proto, StringRef typestr) {
Nate Begemanaf905ef2010-06-02 06:17:19 +0000282 char arg = 'a';
283
284 std::string s;
285 s += "(";
286
287 for (unsigned i = 1, e = proto.size(); i != e; ++i, ++arg) {
288 s += TypeString(proto[i], typestr);
289 s.push_back(' ');
290 s.push_back(arg);
291 if ((i + 1) < e)
292 s += ", ";
293 }
294
295 s += ")";
296 return s;
Nate Begeman22237772010-06-02 00:34:55 +0000297}
298
Nate Begemane66aab52010-06-02 07:14:28 +0000299static OpKind ParseOp(Record *R) {
300 return OpNone;
301}
302
303static std::string GenOpstring(OpKind op) {
304 return "";
305}
306
307static std::string GenBuiltin(std::string &name) {
308 return "";
309}
310
Nate Begeman5ddb0872010-05-28 01:08:32 +0000311void NeonEmitter::run(raw_ostream &OS) {
312 EmitSourceFileHeader("ARM NEON Header", OS);
313
314 // FIXME: emit license into file?
315
316 OS << "#ifndef __ARM_NEON_H\n";
317 OS << "#define __ARM_NEON_H\n\n";
318
319 OS << "#ifndef __ARM_NEON__\n";
320 OS << "#error \"NEON support not enabled\"\n";
321 OS << "#endif\n\n";
322
323 OS << "#include <stdint.h>\n\n";
324
325 // EmitTypedefs(OS);
326
Nate Begeman5ddb0872010-05-28 01:08:32 +0000327 std::vector<Record*> RV = Records.getAllDerivedDefinitions("Inst");
328
Nate Begeman22237772010-06-02 00:34:55 +0000329 // Unique the return+pattern types, and assign them.
Nate Begeman5ddb0872010-05-28 01:08:32 +0000330 for (unsigned i = 0, e = RV.size(); i != e; ++i) {
331 Record *R = RV[i];
Nate Begeman22237772010-06-02 00:34:55 +0000332 std::string name = LowercaseString(R->getName());
333 std::string Proto = R->getValueAsString("Prototype");
Nate Begeman5ddb0872010-05-28 01:08:32 +0000334 std::string Types = R->getValueAsString("Types");
Nate Begeman22237772010-06-02 00:34:55 +0000335
336 SmallVector<StringRef, 16> TypeVec;
337 ParseTypes(R, Types, TypeVec);
338
Nate Begemane66aab52010-06-02 07:14:28 +0000339 OpKind k = ParseOp(R);
340
Nate Begeman22237772010-06-02 00:34:55 +0000341 for (unsigned ti = 0, te = TypeVec.size(); ti != te; ++ti) {
342 assert(!Proto.empty() && "");
343
Nate Begemane66aab52010-06-02 07:14:28 +0000344 // Return type
345 OS << TypeString(Proto[0], TypeVec[ti]);
Nate Begeman22237772010-06-02 00:34:55 +0000346
Nate Begemane66aab52010-06-02 07:14:28 +0000347 // Function name with type suffix
348 OS << " " << MangleName(name, TypeVec[ti]);
Nate Begeman22237772010-06-02 00:34:55 +0000349
Nate Begemane66aab52010-06-02 07:14:28 +0000350 // Function arguments
351 OS << GenArgs(Proto, TypeVec[ti]);
Nate Begeman22237772010-06-02 00:34:55 +0000352
Nate Begemane66aab52010-06-02 07:14:28 +0000353 // Definition.
354 OS << " { ";
Nate Begeman22237772010-06-02 00:34:55 +0000355
Nate Begemane66aab52010-06-02 07:14:28 +0000356 if (k != OpNone)
357 OS << GenOpstring(k);
358 else
359 OS << GenBuiltin(name);
360
361 OS << "}\n";
Nate Begeman22237772010-06-02 00:34:55 +0000362 }
363 OS << "\n";
Nate Begeman5ddb0872010-05-28 01:08:32 +0000364 }
Nate Begeman22237772010-06-02 00:34:55 +0000365
366 // TODO:
367 // Unique the return+pattern types, and assign them to each record
368 // Emit a #define for each unique "type" of intrinsic declaring all variants.
369 // Emit a #define for each intrinsic mapping it to a particular type.
Nate Begeman5ddb0872010-05-28 01:08:32 +0000370
Nate Begeman22237772010-06-02 00:34:55 +0000371 OS << "\n#endif /* __ARM_NEON_H */\n";
Nate Begeman5ddb0872010-05-28 01:08:32 +0000372}