1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | |
15 | |
16 | |
17 | |
18 | |
19 | |
20 | |
21 | |
22 | |
23 | |
24 | |
25 | |
26 | #include "llvm/ADT/ArrayRef.h" |
27 | #include "llvm/ADT/DenseMap.h" |
28 | #include "llvm/ADT/None.h" |
29 | #include "llvm/ADT/SmallVector.h" |
30 | #include "llvm/ADT/STLExtras.h" |
31 | #include "llvm/ADT/StringExtras.h" |
32 | #include "llvm/ADT/StringRef.h" |
33 | #include "llvm/Support/Casting.h" |
34 | #include "llvm/Support/ErrorHandling.h" |
35 | #include "llvm/Support/raw_ostream.h" |
36 | #include "llvm/TableGen/Error.h" |
37 | #include "llvm/TableGen/Record.h" |
38 | #include "llvm/TableGen/SetTheory.h" |
39 | #include <algorithm> |
40 | #include <cassert> |
41 | #include <cctype> |
42 | #include <cstddef> |
43 | #include <cstdint> |
44 | #include <deque> |
45 | #include <map> |
46 | #include <set> |
47 | #include <sstream> |
48 | #include <string> |
49 | #include <utility> |
50 | #include <vector> |
51 | |
52 | using namespace llvm; |
53 | |
54 | namespace { |
55 | |
56 | |
57 | |
58 | |
59 | static Record *CurrentRecord = nullptr; |
60 | static void assert_with_loc(bool Assertion, const std::string &Str) { |
61 | if (!Assertion) { |
62 | if (CurrentRecord) |
63 | PrintFatalError(CurrentRecord->getLoc(), Str); |
64 | else |
65 | PrintFatalError(Str); |
66 | } |
67 | } |
68 | |
69 | enum ClassKind { |
70 | ClassNone, |
71 | ClassI, |
72 | ClassS, |
73 | ClassW, |
74 | ClassB, |
75 | ClassL, |
76 | |
77 | |
78 | ClassNoTest |
79 | |
80 | }; |
81 | |
82 | |
83 | |
84 | |
85 | namespace NeonTypeFlags { |
86 | |
87 | enum { EltTypeMask = 0xf, UnsignedFlag = 0x10, QuadFlag = 0x20 }; |
88 | |
89 | enum EltType { |
90 | Int8, |
91 | Int16, |
92 | Int32, |
93 | Int64, |
94 | Poly8, |
95 | Poly16, |
96 | Poly64, |
97 | Poly128, |
98 | Float16, |
99 | Float32, |
100 | Float64 |
101 | }; |
102 | |
103 | } |
104 | |
105 | class NeonEmitter; |
106 | |
107 | |
108 | |
109 | |
110 | |
111 | |
112 | |
113 | |
114 | |
115 | class TypeSpec : public std::string { |
116 | public: |
117 | static std::vector<TypeSpec> fromTypeSpecs(StringRef Str) { |
118 | std::vector<TypeSpec> Ret; |
119 | TypeSpec Acc; |
120 | for (char I : Str.str()) { |
121 | if (islower(I)) { |
122 | Acc.push_back(I); |
123 | Ret.push_back(TypeSpec(Acc)); |
124 | Acc.clear(); |
125 | } else { |
126 | Acc.push_back(I); |
127 | } |
128 | } |
129 | return Ret; |
130 | } |
131 | }; |
132 | |
133 | |
134 | |
135 | |
136 | |
137 | |
138 | class Type { |
139 | private: |
140 | TypeSpec TS; |
141 | |
142 | bool Float, Signed, Immediate, Void, Poly, Constant, Pointer; |
143 | |
144 | |
145 | |
146 | bool ScalarForMangling, NoManglingQ; |
147 | unsigned Bitwidth, ElementBitwidth, NumVectors; |
148 | |
149 | public: |
150 | Type() |
151 | : Float(false), Signed(false), Immediate(false), Void(true), Poly(false), |
152 | Constant(false), Pointer(false), ScalarForMangling(false), |
153 | NoManglingQ(false), Bitwidth(0), ElementBitwidth(0), NumVectors(0) {} |
154 | |
155 | Type(TypeSpec TS, char CharMod) |
156 | : TS(std::move(TS)), Float(false), Signed(false), Immediate(false), |
157 | Void(false), Poly(false), Constant(false), Pointer(false), |
158 | ScalarForMangling(false), NoManglingQ(false), Bitwidth(0), |
159 | ElementBitwidth(0), NumVectors(0) { |
160 | applyModifier(CharMod); |
161 | } |
162 | |
163 | |
164 | static Type getVoid() { return Type(); } |
165 | |
166 | bool operator==(const Type &Other) const { return str() == Other.str(); } |
167 | bool operator!=(const Type &Other) const { return !operator==(Other); } |
168 | |
169 | |
170 | |
171 | |
172 | bool isScalarForMangling() const { return ScalarForMangling; } |
173 | bool noManglingQ() const { return NoManglingQ; } |
174 | |
175 | bool isPointer() const { return Pointer; } |
176 | bool isFloating() const { return Float; } |
177 | bool isInteger() const { return !Float && !Poly; } |
178 | bool isSigned() const { return Signed; } |
179 | bool isImmediate() const { return Immediate; } |
180 | bool isScalar() const { return NumVectors == 0; } |
181 | bool isVector() const { return NumVectors > 0; } |
182 | bool isFloat() const { return Float && ElementBitwidth == 32; } |
183 | bool isDouble() const { return Float && ElementBitwidth == 64; } |
184 | bool isHalf() const { return Float && ElementBitwidth == 16; } |
185 | bool isPoly() const { return Poly; } |
186 | bool isChar() const { return ElementBitwidth == 8; } |
187 | bool isShort() const { return !Float && ElementBitwidth == 16; } |
188 | bool isInt() const { return !Float && ElementBitwidth == 32; } |
189 | bool isLong() const { return !Float && ElementBitwidth == 64; } |
190 | bool isVoid() const { return Void; } |
191 | unsigned getNumElements() const { return Bitwidth / ElementBitwidth; } |
192 | unsigned getSizeInBits() const { return Bitwidth; } |
193 | unsigned getElementSizeInBits() const { return ElementBitwidth; } |
194 | unsigned getNumVectors() const { return NumVectors; } |
195 | |
196 | |
197 | |
198 | |
199 | void makeUnsigned() { Signed = false; } |
200 | void makeSigned() { Signed = true; } |
201 | |
202 | void makeInteger(unsigned ElemWidth, bool Sign) { |
203 | Float = false; |
204 | Poly = false; |
205 | Signed = Sign; |
206 | Immediate = false; |
207 | ElementBitwidth = ElemWidth; |
208 | } |
209 | |
210 | void makeImmediate(unsigned ElemWidth) { |
211 | Float = false; |
212 | Poly = false; |
213 | Signed = true; |
214 | Immediate = true; |
215 | ElementBitwidth = ElemWidth; |
216 | } |
217 | |
218 | void makeScalar() { |
219 | Bitwidth = ElementBitwidth; |
220 | NumVectors = 0; |
221 | } |
222 | |
223 | void makeOneVector() { |
224 | assert(isVector()); |
225 | NumVectors = 1; |
226 | } |
227 | |
228 | void doubleLanes() { |
229 | assert_with_loc(Bitwidth != 128, "Can't get bigger than 128!"); |
230 | Bitwidth = 128; |
231 | } |
232 | |
233 | void halveLanes() { |
234 | assert_with_loc(Bitwidth != 64, "Can't get smaller than 64!"); |
235 | Bitwidth = 64; |
236 | } |
237 | |
238 | |
239 | |
240 | std::string str() const; |
241 | |
242 | |
243 | |
244 | std::string builtin_str() const; |
245 | |
246 | |
247 | unsigned getNeonEnum() const; |
248 | |
249 | |
250 | |
251 | static Type fromTypedefName(StringRef Name); |
252 | |
253 | private: |
254 | |
255 | |
256 | |
257 | |
258 | void applyTypespec(bool &Quad); |
259 | |
260 | void applyModifier(char Mod); |
261 | }; |
262 | |
263 | |
264 | |
265 | |
266 | |
267 | |
268 | class Variable { |
269 | Type T; |
270 | std::string N; |
271 | |
272 | public: |
273 | Variable() : T(Type::getVoid()), N("") {} |
274 | Variable(Type T, std::string N) : T(std::move(T)), N(std::move(N)) {} |
275 | |
276 | Type getType() const { return T; } |
277 | std::string getName() const { return "__" + N; } |
278 | }; |
279 | |
280 | |
281 | |
282 | |
283 | |
284 | |
285 | |
286 | class Intrinsic { |
287 | friend class DagEmitter; |
288 | |
289 | |
290 | Record *R; |
291 | |
292 | std::string Name, Proto; |
293 | |
294 | |
295 | TypeSpec OutTS, InTS; |
296 | |
297 | |
298 | |
299 | |
300 | ClassKind CK; |
301 | |
302 | |
303 | ListInit *Body; |
304 | |
305 | std::string Guard; |
306 | |
307 | |
308 | bool IsUnavailable; |
309 | |
310 | |
311 | bool BigEndianSafe; |
312 | |
313 | |
314 | std::vector<Type> Types; |
315 | |
316 | std::map<std::string, Variable> Variables; |
317 | |
318 | bool NeededEarly; |
319 | |
320 | |
321 | bool UseMacro; |
322 | |
323 | std::set<Intrinsic *> Dependencies; |
324 | |
325 | |
326 | Type BaseType, InBaseType; |
327 | |
328 | Variable RetVar; |
329 | |
330 | std::string VariablePostfix; |
331 | |
332 | NeonEmitter &Emitter; |
333 | std::stringstream OS; |
334 | |
335 | public: |
336 | Intrinsic(Record *R, StringRef Name, StringRef Proto, TypeSpec OutTS, |
337 | TypeSpec InTS, ClassKind CK, ListInit *Body, NeonEmitter &Emitter, |
338 | StringRef Guard, bool IsUnavailable, bool BigEndianSafe) |
339 | : R(R), Name(Name.str()), Proto(Proto.str()), OutTS(OutTS), InTS(InTS), |
340 | CK(CK), Body(Body), Guard(Guard.str()), IsUnavailable(IsUnavailable), |
341 | BigEndianSafe(BigEndianSafe), NeededEarly(false), UseMacro(false), |
342 | BaseType(OutTS, 'd'), InBaseType(InTS, 'd'), Emitter(Emitter) { |
343 | |
344 | |
345 | |
346 | if (Proto.find('i') != std::string::npos) |
347 | UseMacro = true; |
348 | |
349 | |
350 | |
351 | if (Proto.find('p') != std::string::npos || |
352 | Proto.find('c') != std::string::npos) |
353 | UseMacro = true; |
354 | |
355 | |
356 | |
357 | if (OutTS.find('h') != std::string::npos && |
358 | Proto.find('s') != std::string::npos) |
359 | UseMacro = true; |
360 | |
361 | |
362 | |
363 | |
364 | Types.emplace_back(OutTS, Proto[0]); |
365 | for (unsigned I = 1; I < Proto.size(); ++I) |
366 | Types.emplace_back(InTS, Proto[I]); |
367 | } |
368 | |
369 | |
370 | Record *getRecord() const { return R; } |
371 | |
372 | |
373 | |
374 | const std::set<Intrinsic *> &getDependencies() const { return Dependencies; } |
375 | |
376 | std::string getGuard() const { return Guard; } |
377 | |
378 | std::string getName() const { return Name; } |
379 | |
380 | |
381 | bool hasImmediate() const { |
382 | return Proto.find('i') != std::string::npos; |
383 | } |
384 | |
385 | |
386 | unsigned getImmediateIdx() const { |
387 | assert(hasImmediate()); |
388 | unsigned Idx = Proto.find('i'); |
389 | (0) . __assert_fail ("Idx > 0 && \"Can't return an immediate!\"", "/home/seafit/code_projects/clang_source/clang/utils/TableGen/NeonEmitter.cpp", 389, __PRETTY_FUNCTION__))" file_link="../../../include/assert.h.html#88" macro="true">assert(Idx > 0 && "Can't return an immediate!"); |
390 | return Idx - 1; |
391 | } |
392 | |
393 | |
394 | bool hasSplat() const { return Proto.find('a') != std::string::npos; } |
395 | |
396 | |
397 | unsigned getSplatIdx() const { |
398 | assert(hasSplat()); |
399 | unsigned Idx = Proto.find('a'); |
400 | (0) . __assert_fail ("Idx > 0 && \"Can't return a splat!\"", "/home/seafit/code_projects/clang_source/clang/utils/TableGen/NeonEmitter.cpp", 400, __PRETTY_FUNCTION__))" file_link="../../../include/assert.h.html#88" macro="true">assert(Idx > 0 && "Can't return a splat!"); |
401 | return Idx - 1; |
402 | } |
403 | |
404 | unsigned getNumParams() const { return Proto.size() - 1; } |
405 | Type getReturnType() const { return Types[0]; } |
406 | Type getParamType(unsigned I) const { return Types[I + 1]; } |
407 | Type getBaseType() const { return BaseType; } |
408 | |
409 | std::string getProto() const { return Proto; } |
410 | |
411 | |
412 | |
413 | bool protoHasScalar() const; |
414 | |
415 | |
416 | |
417 | |
418 | |
419 | unsigned getGeneratedParamIdx(unsigned PIndex) { |
420 | unsigned Idx = 0; |
421 | if (getReturnType().getNumVectors() > 1) |
422 | |
423 | ++Idx; |
424 | |
425 | for (unsigned I = 0; I < PIndex; ++I) |
426 | Idx += std::max(1U, getParamType(I).getNumVectors()); |
427 | |
428 | return Idx; |
429 | } |
430 | |
431 | bool hasBody() const { return Body && !Body->getValues().empty(); } |
432 | |
433 | void setNeededEarly() { NeededEarly = true; } |
434 | |
435 | bool operator<(const Intrinsic &Other) const { |
436 | |
437 | if (Guard != Other.Guard) |
438 | return Guard < Other.Guard; |
439 | return Name < Other.Name; |
440 | } |
441 | |
442 | ClassKind getClassKind(bool UseClassBIfScalar = false) { |
443 | if (UseClassBIfScalar && !protoHasScalar()) |
444 | return ClassB; |
445 | return CK; |
446 | } |
447 | |
448 | |
449 | |
450 | |
451 | std::string getMangledName(bool ForceClassS = false) const; |
452 | |
453 | std::string getInstTypeCode(Type T, ClassKind CK) const; |
454 | |
455 | std::string getBuiltinTypeStr(); |
456 | |
457 | |
458 | std::string generate(); |
459 | |
460 | |
461 | void indexBody(); |
462 | |
463 | private: |
464 | std::string mangleName(std::string Name, ClassKind CK) const; |
465 | |
466 | void initVariables(); |
467 | std::string replaceParamsIn(std::string S); |
468 | |
469 | void emitBodyAsBuiltinCall(); |
470 | |
471 | void generateImpl(bool ReverseArguments, |
472 | StringRef NamePrefix, StringRef CallPrefix); |
473 | void emitReturn(); |
474 | void emitBody(StringRef CallPrefix); |
475 | void emitShadowedArgs(); |
476 | void emitArgumentReversal(); |
477 | void emitReturnReversal(); |
478 | void emitReverseVariable(Variable &Dest, Variable &Src); |
479 | void emitNewLine(); |
480 | void emitClosingBrace(); |
481 | void emitOpeningBrace(); |
482 | void emitPrototype(StringRef NamePrefix); |
483 | |
484 | class DagEmitter { |
485 | Intrinsic &Intr; |
486 | StringRef CallPrefix; |
487 | |
488 | public: |
489 | DagEmitter(Intrinsic &Intr, StringRef CallPrefix) : |
490 | Intr(Intr), CallPrefix(CallPrefix) { |
491 | } |
492 | std::pair<Type, std::string> emitDagArg(Init *Arg, std::string ArgName); |
493 | std::pair<Type, std::string> emitDagSaveTemp(DagInit *DI); |
494 | std::pair<Type, std::string> emitDagSplat(DagInit *DI); |
495 | std::pair<Type, std::string> emitDagDup(DagInit *DI); |
496 | std::pair<Type, std::string> emitDagDupTyped(DagInit *DI); |
497 | std::pair<Type, std::string> emitDagShuffle(DagInit *DI); |
498 | std::pair<Type, std::string> emitDagCast(DagInit *DI, bool IsBitCast); |
499 | std::pair<Type, std::string> emitDagCall(DagInit *DI); |
500 | std::pair<Type, std::string> emitDagNameReplace(DagInit *DI); |
501 | std::pair<Type, std::string> emitDagLiteral(DagInit *DI); |
502 | std::pair<Type, std::string> emitDagOp(DagInit *DI); |
503 | std::pair<Type, std::string> emitDag(DagInit *DI); |
504 | }; |
505 | }; |
506 | |
507 | |
508 | |
509 | |
510 | |
511 | class NeonEmitter { |
512 | RecordKeeper &Records; |
513 | DenseMap<Record *, ClassKind> ClassMap; |
514 | std::map<std::string, std::deque<Intrinsic>> IntrinsicMap; |
515 | unsigned UniqueNumber; |
516 | |
517 | void createIntrinsic(Record *R, SmallVectorImpl<Intrinsic *> &Out); |
518 | void genBuiltinsDef(raw_ostream &OS, SmallVectorImpl<Intrinsic *> &Defs); |
519 | void genOverloadTypeCheckCode(raw_ostream &OS, |
520 | SmallVectorImpl<Intrinsic *> &Defs); |
521 | void genIntrinsicRangeCheckCode(raw_ostream &OS, |
522 | SmallVectorImpl<Intrinsic *> &Defs); |
523 | |
524 | public: |
525 | |
526 | |
527 | Intrinsic &getIntrinsic(StringRef Name, ArrayRef<Type> Types); |
528 | |
529 | |
530 | unsigned getUniqueNumber() { return UniqueNumber++; } |
531 | |
532 | NeonEmitter(RecordKeeper &R) : Records(R), UniqueNumber(0) { |
533 | Record *SI = R.getClass("SInst"); |
534 | Record *II = R.getClass("IInst"); |
535 | Record *WI = R.getClass("WInst"); |
536 | Record *SOpI = R.getClass("SOpInst"); |
537 | Record *IOpI = R.getClass("IOpInst"); |
538 | Record *WOpI = R.getClass("WOpInst"); |
539 | Record *LOpI = R.getClass("LOpInst"); |
540 | Record *NoTestOpI = R.getClass("NoTestOpInst"); |
541 | |
542 | ClassMap[SI] = ClassS; |
543 | ClassMap[II] = ClassI; |
544 | ClassMap[WI] = ClassW; |
545 | ClassMap[SOpI] = ClassS; |
546 | ClassMap[IOpI] = ClassI; |
547 | ClassMap[WOpI] = ClassW; |
548 | ClassMap[LOpI] = ClassL; |
549 | ClassMap[NoTestOpI] = ClassNoTest; |
550 | } |
551 | |
552 | |
553 | void run(raw_ostream &o); |
554 | |
555 | |
556 | void runFP16(raw_ostream &o); |
557 | |
558 | |
559 | |
560 | void (raw_ostream &o); |
561 | |
562 | |
563 | void runTests(raw_ostream &o); |
564 | }; |
565 | |
566 | } |
567 | |
568 | |
569 | |
570 | |
571 | |
572 | std::string Type::str() const { |
573 | if (Void) |
574 | return "void"; |
575 | std::string S; |
576 | |
577 | if (!Signed && isInteger()) |
578 | S += "u"; |
579 | |
580 | if (Poly) |
581 | S += "poly"; |
582 | else if (Float) |
583 | S += "float"; |
584 | else |
585 | S += "int"; |
586 | |
587 | S += utostr(ElementBitwidth); |
588 | if (isVector()) |
589 | S += "x" + utostr(getNumElements()); |
590 | if (NumVectors > 1) |
591 | S += "x" + utostr(NumVectors); |
592 | S += "_t"; |
593 | |
594 | if (Constant) |
595 | S += " const"; |
596 | if (Pointer) |
597 | S += " *"; |
598 | |
599 | return S; |
600 | } |
601 | |
602 | std::string Type::builtin_str() const { |
603 | std::string S; |
604 | if (isVoid()) |
605 | return "v"; |
606 | |
607 | if (Pointer) |
608 | |
609 | S += "v"; |
610 | else if (isInteger()) |
611 | switch (ElementBitwidth) { |
612 | case 8: S += "c"; break; |
613 | case 16: S += "s"; break; |
614 | case 32: S += "i"; break; |
615 | case 64: S += "Wi"; break; |
616 | case 128: S += "LLLi"; break; |
617 | default: llvm_unreachable("Unhandled case!"); |
618 | } |
619 | else |
620 | switch (ElementBitwidth) { |
621 | case 16: S += "h"; break; |
622 | case 32: S += "f"; break; |
623 | case 64: S += "d"; break; |
624 | default: llvm_unreachable("Unhandled case!"); |
625 | } |
626 | |
627 | if (isChar() && !Pointer) |
628 | |
629 | S = "S" + S; |
630 | else if (isInteger() && !Pointer && !Signed) |
631 | S = "U" + S; |
632 | |
633 | |
634 | if (isImmediate()) { |
635 | assert(isInteger() && isSigned()); |
636 | S = "I" + S; |
637 | } |
638 | |
639 | if (isScalar()) { |
640 | if (Constant) S += "C"; |
641 | if (Pointer) S += "*"; |
642 | return S; |
643 | } |
644 | |
645 | std::string Ret; |
646 | for (unsigned I = 0; I < NumVectors; ++I) |
647 | Ret += "V" + utostr(getNumElements()) + S; |
648 | |
649 | return Ret; |
650 | } |
651 | |
652 | unsigned Type::getNeonEnum() const { |
653 | unsigned Addend; |
654 | switch (ElementBitwidth) { |
655 | case 8: Addend = 0; break; |
656 | case 16: Addend = 1; break; |
657 | case 32: Addend = 2; break; |
658 | case 64: Addend = 3; break; |
659 | case 128: Addend = 4; break; |
660 | default: llvm_unreachable("Unhandled element bitwidth!"); |
661 | } |
662 | |
663 | unsigned Base = (unsigned)NeonTypeFlags::Int8 + Addend; |
664 | if (Poly) { |
665 | |
666 | if (Addend >= 2) |
667 | --Addend; |
668 | Base = (unsigned)NeonTypeFlags::Poly8 + Addend; |
669 | } |
670 | if (Float) { |
671 | (0) . __assert_fail ("Addend != 0 && \"Float8 doesn't exist!\"", "/home/seafit/code_projects/clang_source/clang/utils/TableGen/NeonEmitter.cpp", 671, __PRETTY_FUNCTION__))" file_link="../../../include/assert.h.html#88" macro="true">assert(Addend != 0 && "Float8 doesn't exist!"); |
672 | Base = (unsigned)NeonTypeFlags::Float16 + (Addend - 1); |
673 | } |
674 | |
675 | if (Bitwidth == 128) |
676 | Base |= (unsigned)NeonTypeFlags::QuadFlag; |
677 | if (isInteger() && !Signed) |
678 | Base |= (unsigned)NeonTypeFlags::UnsignedFlag; |
679 | |
680 | return Base; |
681 | } |
682 | |
683 | Type Type::fromTypedefName(StringRef Name) { |
684 | Type T; |
685 | T.Void = false; |
686 | T.Float = false; |
687 | T.Poly = false; |
688 | |
689 | if (Name.front() == 'u') { |
690 | T.Signed = false; |
691 | Name = Name.drop_front(); |
692 | } else { |
693 | T.Signed = true; |
694 | } |
695 | |
696 | if (Name.startswith("float")) { |
697 | T.Float = true; |
698 | Name = Name.drop_front(5); |
699 | } else if (Name.startswith("poly")) { |
700 | T.Poly = true; |
701 | Name = Name.drop_front(4); |
702 | } else { |
703 | (0) . __assert_fail ("Name.startswith(\"int\")", "/home/seafit/code_projects/clang_source/clang/utils/TableGen/NeonEmitter.cpp", 703, __PRETTY_FUNCTION__))" file_link="../../../include/assert.h.html#88" macro="true">assert(Name.startswith("int")); |
704 | Name = Name.drop_front(3); |
705 | } |
706 | |
707 | unsigned I = 0; |
708 | for (I = 0; I < Name.size(); ++I) { |
709 | if (!isdigit(Name[I])) |
710 | break; |
711 | } |
712 | Name.substr(0, I).getAsInteger(10, T.ElementBitwidth); |
713 | Name = Name.drop_front(I); |
714 | |
715 | T.Bitwidth = T.ElementBitwidth; |
716 | T.NumVectors = 1; |
717 | |
718 | if (Name.front() == 'x') { |
719 | Name = Name.drop_front(); |
720 | unsigned I = 0; |
721 | for (I = 0; I < Name.size(); ++I) { |
722 | if (!isdigit(Name[I])) |
723 | break; |
724 | } |
725 | unsigned NumLanes; |
726 | Name.substr(0, I).getAsInteger(10, NumLanes); |
727 | Name = Name.drop_front(I); |
728 | T.Bitwidth = T.ElementBitwidth * NumLanes; |
729 | } else { |
730 | |
731 | T.NumVectors = 0; |
732 | } |
733 | if (Name.front() == 'x') { |
734 | Name = Name.drop_front(); |
735 | unsigned I = 0; |
736 | for (I = 0; I < Name.size(); ++I) { |
737 | if (!isdigit(Name[I])) |
738 | break; |
739 | } |
740 | Name.substr(0, I).getAsInteger(10, T.NumVectors); |
741 | Name = Name.drop_front(I); |
742 | } |
743 | |
744 | (0) . __assert_fail ("Name.startswith(\"_t\") && \"Malformed typedef!\"", "/home/seafit/code_projects/clang_source/clang/utils/TableGen/NeonEmitter.cpp", 744, __PRETTY_FUNCTION__))" file_link="../../../include/assert.h.html#88" macro="true">assert(Name.startswith("_t") && "Malformed typedef!"); |
745 | return T; |
746 | } |
747 | |
748 | void Type::applyTypespec(bool &Quad) { |
749 | std::string S = TS; |
750 | ScalarForMangling = false; |
751 | Void = false; |
752 | Poly = Float = false; |
753 | ElementBitwidth = ~0U; |
754 | Signed = true; |
755 | NumVectors = 1; |
756 | |
757 | for (char I : S) { |
758 | switch (I) { |
759 | case 'S': |
760 | ScalarForMangling = true; |
761 | break; |
762 | case 'H': |
763 | NoManglingQ = true; |
764 | Quad = true; |
765 | break; |
766 | case 'Q': |
767 | Quad = true; |
768 | break; |
769 | case 'P': |
770 | Poly = true; |
771 | break; |
772 | case 'U': |
773 | Signed = false; |
774 | break; |
775 | case 'c': |
776 | ElementBitwidth = 8; |
777 | break; |
778 | case 'h': |
779 | Float = true; |
780 | LLVM_FALLTHROUGH; |
781 | case 's': |
782 | ElementBitwidth = 16; |
783 | break; |
784 | case 'f': |
785 | Float = true; |
786 | LLVM_FALLTHROUGH; |
787 | case 'i': |
788 | ElementBitwidth = 32; |
789 | break; |
790 | case 'd': |
791 | Float = true; |
792 | LLVM_FALLTHROUGH; |
793 | case 'l': |
794 | ElementBitwidth = 64; |
795 | break; |
796 | case 'k': |
797 | ElementBitwidth = 128; |
798 | |
799 | if (Poly) |
800 | NumVectors = 0; |
801 | break; |
802 | default: |
803 | llvm_unreachable("Unhandled type code!"); |
804 | } |
805 | } |
806 | (0) . __assert_fail ("ElementBitwidth != ~0U && \"Bad element bitwidth!\"", "/home/seafit/code_projects/clang_source/clang/utils/TableGen/NeonEmitter.cpp", 806, __PRETTY_FUNCTION__))" file_link="../../../include/assert.h.html#88" macro="true">assert(ElementBitwidth != ~0U && "Bad element bitwidth!"); |
807 | |
808 | Bitwidth = Quad ? 128 : 64; |
809 | } |
810 | |
811 | void Type::applyModifier(char Mod) { |
812 | bool AppliedQuad = false; |
813 | applyTypespec(AppliedQuad); |
814 | |
815 | switch (Mod) { |
816 | case 'v': |
817 | Void = true; |
818 | break; |
819 | case 't': |
820 | if (Poly) { |
821 | Poly = false; |
822 | Signed = false; |
823 | } |
824 | break; |
825 | case 'b': |
826 | Signed = false; |
827 | Float = false; |
828 | Poly = false; |
829 | NumVectors = 0; |
830 | Bitwidth = ElementBitwidth; |
831 | break; |
832 | case '$': |
833 | Signed = true; |
834 | Float = false; |
835 | Poly = false; |
836 | NumVectors = 0; |
837 | Bitwidth = ElementBitwidth; |
838 | break; |
839 | case 'u': |
840 | Signed = false; |
841 | Poly = false; |
842 | Float = false; |
843 | break; |
844 | case 'x': |
845 | Signed = true; |
846 | (0) . __assert_fail ("!Poly && \"'u' can't be used with poly types!\"", "/home/seafit/code_projects/clang_source/clang/utils/TableGen/NeonEmitter.cpp", 846, __PRETTY_FUNCTION__))" file_link="../../../include/assert.h.html#88" macro="true">assert(!Poly && "'u' can't be used with poly types!"); |
847 | Float = false; |
848 | break; |
849 | case 'o': |
850 | Bitwidth = ElementBitwidth = 64; |
851 | NumVectors = 0; |
852 | Float = true; |
853 | break; |
854 | case 'y': |
855 | Bitwidth = ElementBitwidth = 32; |
856 | NumVectors = 0; |
857 | Float = true; |
858 | break; |
859 | case 'Y': |
860 | Bitwidth = ElementBitwidth = 16; |
861 | NumVectors = 0; |
862 | Float = true; |
863 | break; |
864 | case 'I': |
865 | Bitwidth = ElementBitwidth = 32; |
866 | NumVectors = 0; |
867 | Float = false; |
868 | Signed = true; |
869 | break; |
870 | case 'L': |
871 | Bitwidth = ElementBitwidth = 64; |
872 | NumVectors = 0; |
873 | Float = false; |
874 | Signed = true; |
875 | break; |
876 | case 'U': |
877 | Bitwidth = ElementBitwidth = 32; |
878 | NumVectors = 0; |
879 | Float = false; |
880 | Signed = false; |
881 | break; |
882 | case 'O': |
883 | Bitwidth = ElementBitwidth = 64; |
884 | NumVectors = 0; |
885 | Float = false; |
886 | Signed = false; |
887 | break; |
888 | case 'f': |
889 | Float = true; |
890 | ElementBitwidth = 32; |
891 | break; |
892 | case 'F': |
893 | Float = true; |
894 | ElementBitwidth = 64; |
895 | break; |
896 | case 'H': |
897 | Float = true; |
898 | ElementBitwidth = 16; |
899 | break; |
900 | case '0': |
901 | Float = true; |
902 | if (AppliedQuad) |
903 | Bitwidth /= 2; |
904 | ElementBitwidth = 16; |
905 | break; |
906 | case '1': |
907 | Float = true; |
908 | if (!AppliedQuad) |
909 | Bitwidth *= 2; |
910 | ElementBitwidth = 16; |
911 | break; |
912 | case 'g': |
913 | if (AppliedQuad) |
914 | Bitwidth /= 2; |
915 | break; |
916 | case 'j': |
917 | if (!AppliedQuad) |
918 | Bitwidth *= 2; |
919 | break; |
920 | case 'w': |
921 | ElementBitwidth *= 2; |
922 | Bitwidth *= 2; |
923 | break; |
924 | case 'n': |
925 | ElementBitwidth *= 2; |
926 | break; |
927 | case 'i': |
928 | Float = false; |
929 | Poly = false; |
930 | ElementBitwidth = Bitwidth = 32; |
931 | NumVectors = 0; |
932 | Signed = true; |
933 | Immediate = true; |
934 | break; |
935 | case 'l': |
936 | Float = false; |
937 | Poly = false; |
938 | ElementBitwidth = Bitwidth = 64; |
939 | NumVectors = 0; |
940 | Signed = false; |
941 | Immediate = true; |
942 | break; |
943 | case 'z': |
944 | ElementBitwidth /= 2; |
945 | Bitwidth = ElementBitwidth; |
946 | NumVectors = 0; |
947 | break; |
948 | case 'r': |
949 | ElementBitwidth *= 2; |
950 | Bitwidth = ElementBitwidth; |
951 | NumVectors = 0; |
952 | break; |
953 | case 's': |
954 | case 'a': |
955 | Bitwidth = ElementBitwidth; |
956 | NumVectors = 0; |
957 | break; |
958 | case 'k': |
959 | Bitwidth *= 2; |
960 | break; |
961 | case 'c': |
962 | Constant = true; |
963 | LLVM_FALLTHROUGH; |
964 | case 'p': |
965 | Pointer = true; |
966 | Bitwidth = ElementBitwidth; |
967 | NumVectors = 0; |
968 | break; |
969 | case 'h': |
970 | ElementBitwidth /= 2; |
971 | break; |
972 | case 'q': |
973 | ElementBitwidth /= 2; |
974 | Bitwidth *= 2; |
975 | break; |
976 | case 'e': |
977 | ElementBitwidth /= 2; |
978 | Signed = false; |
979 | break; |
980 | case 'm': |
981 | ElementBitwidth /= 2; |
982 | Bitwidth /= 2; |
983 | break; |
984 | case 'd': |
985 | break; |
986 | case '2': |
987 | NumVectors = 2; |
988 | break; |
989 | case '3': |
990 | NumVectors = 3; |
991 | break; |
992 | case '4': |
993 | NumVectors = 4; |
994 | break; |
995 | case 'B': |
996 | NumVectors = 2; |
997 | if (!AppliedQuad) |
998 | Bitwidth *= 2; |
999 | break; |
1000 | case 'C': |
1001 | NumVectors = 3; |
1002 | if (!AppliedQuad) |
1003 | Bitwidth *= 2; |
1004 | break; |
1005 | case 'D': |
1006 | NumVectors = 4; |
1007 | if (!AppliedQuad) |
1008 | Bitwidth *= 2; |
1009 | break; |
1010 | case '7': |
1011 | if (AppliedQuad) |
1012 | Bitwidth /= 2; |
1013 | ElementBitwidth = 8; |
1014 | break; |
1015 | case '8': |
1016 | ElementBitwidth = 8; |
1017 | break; |
1018 | case '9': |
1019 | if (!AppliedQuad) |
1020 | Bitwidth *= 2; |
1021 | ElementBitwidth = 8; |
1022 | break; |
1023 | default: |
1024 | llvm_unreachable("Unhandled character!"); |
1025 | } |
1026 | } |
1027 | |
1028 | |
1029 | |
1030 | |
1031 | |
1032 | std::string Intrinsic::getInstTypeCode(Type T, ClassKind CK) const { |
1033 | char typeCode = '\0'; |
1034 | bool printNumber = true; |
1035 | |
1036 | if (CK == ClassB) |
1037 | return ""; |
1038 | |
1039 | if (T.isPoly()) |
1040 | typeCode = 'p'; |
1041 | else if (T.isInteger()) |
1042 | typeCode = T.isSigned() ? 's' : 'u'; |
1043 | else |
1044 | typeCode = 'f'; |
1045 | |
1046 | if (CK == ClassI) { |
1047 | switch (typeCode) { |
1048 | default: |
1049 | break; |
1050 | case 's': |
1051 | case 'u': |
1052 | case 'p': |
1053 | typeCode = 'i'; |
1054 | break; |
1055 | } |
1056 | } |
1057 | if (CK == ClassB) { |
1058 | typeCode = '\0'; |
1059 | } |
1060 | |
1061 | std::string S; |
1062 | if (typeCode != '\0') |
1063 | S.push_back(typeCode); |
1064 | if (printNumber) |
1065 | S += utostr(T.getElementSizeInBits()); |
1066 | |
1067 | return S; |
1068 | } |
1069 | |
1070 | static bool isFloatingPointProtoModifier(char Mod) { |
1071 | return Mod == 'F' || Mod == 'f' || Mod == 'H' || Mod == 'Y' || Mod == 'I'; |
1072 | } |
1073 | |
1074 | std::string Intrinsic::getBuiltinTypeStr() { |
1075 | ClassKind LocalCK = getClassKind(true); |
1076 | std::string S; |
1077 | |
1078 | Type RetT = getReturnType(); |
1079 | if ((LocalCK == ClassI || LocalCK == ClassW) && RetT.isScalar() && |
1080 | !RetT.isFloating()) |
1081 | RetT.makeInteger(RetT.getElementSizeInBits(), false); |
1082 | |
1083 | |
1084 | |
1085 | |
1086 | |
1087 | if (RetT.getNumVectors() > 1) { |
1088 | S += "vv*"; |
1089 | } else { |
1090 | if (RetT.isPoly()) |
1091 | RetT.makeInteger(RetT.getElementSizeInBits(), false); |
1092 | if (!RetT.isScalar() && !RetT.isSigned()) |
1093 | RetT.makeSigned(); |
1094 | |
1095 | bool ForcedVectorFloatingType = isFloatingPointProtoModifier(Proto[0]); |
1096 | if (LocalCK == ClassB && !RetT.isScalar() && !ForcedVectorFloatingType) |
1097 | |
1098 | RetT.makeInteger(8, true); |
1099 | |
1100 | S += RetT.builtin_str(); |
1101 | } |
1102 | |
1103 | for (unsigned I = 0; I < getNumParams(); ++I) { |
1104 | Type T = getParamType(I); |
1105 | if (T.isPoly()) |
1106 | T.makeInteger(T.getElementSizeInBits(), false); |
1107 | |
1108 | bool ForcedFloatingType = isFloatingPointProtoModifier(Proto[I + 1]); |
1109 | if (LocalCK == ClassB && !T.isScalar() && !ForcedFloatingType) |
1110 | T.makeInteger(8, true); |
1111 | |
1112 | if (T.isHalf() && T.isVector() && !T.isScalarForMangling()) |
1113 | T.makeInteger(8, true); |
1114 | |
1115 | if (LocalCK == ClassI) |
1116 | T.makeSigned(); |
1117 | |
1118 | if (hasImmediate() && getImmediateIdx() == I) |
1119 | T.makeImmediate(32); |
1120 | |
1121 | S += T.builtin_str(); |
1122 | } |
1123 | |
1124 | |
1125 | if (LocalCK == ClassB) |
1126 | S += "i"; |
1127 | |
1128 | return S; |
1129 | } |
1130 | |
1131 | std::string Intrinsic::getMangledName(bool ForceClassS) const { |
1132 | |
1133 | |
1134 | |
1135 | ClassKind LocalCK = CK; |
1136 | if (!protoHasScalar()) |
1137 | LocalCK = ClassB; |
1138 | |
1139 | return mangleName(Name, ForceClassS ? ClassS : LocalCK); |
1140 | } |
1141 | |
1142 | std::string Intrinsic::mangleName(std::string Name, ClassKind LocalCK) const { |
1143 | std::string typeCode = getInstTypeCode(BaseType, LocalCK); |
1144 | std::string S = Name; |
1145 | |
1146 | if (Name == "vcvt_f16_f32" || Name == "vcvt_f32_f16" || |
1147 | Name == "vcvt_f32_f64" || Name == "vcvt_f64_f32") |
1148 | return Name; |
1149 | |
1150 | if (!typeCode.empty()) { |
1151 | |
1152 | if (Name.size() >= 3 && isdigit(Name.back()) && |
1153 | Name[Name.length() - 2] == 'x' && Name[Name.length() - 3] == '_') |
1154 | S.insert(S.length() - 3, "_" + typeCode); |
1155 | else |
1156 | S += "_" + typeCode; |
1157 | } |
1158 | |
1159 | if (BaseType != InBaseType) { |
1160 | |
1161 | S += "_" + getInstTypeCode(InBaseType, LocalCK); |
1162 | } |
1163 | |
1164 | if (LocalCK == ClassB) |
1165 | S += "_v"; |
1166 | |
1167 | |
1168 | |
1169 | if (BaseType.getSizeInBits() == 128 && !BaseType.noManglingQ()) { |
1170 | size_t Pos = S.find('_'); |
1171 | S.insert(Pos, "q"); |
1172 | } |
1173 | |
1174 | char Suffix = '\0'; |
1175 | if (BaseType.isScalarForMangling()) { |
1176 | switch (BaseType.getElementSizeInBits()) { |
1177 | case 8: Suffix = 'b'; break; |
1178 | case 16: Suffix = 'h'; break; |
1179 | case 32: Suffix = 's'; break; |
1180 | case 64: Suffix = 'd'; break; |
1181 | default: llvm_unreachable("Bad suffix!"); |
1182 | } |
1183 | } |
1184 | if (Suffix != '\0') { |
1185 | size_t Pos = S.find('_'); |
1186 | S.insert(Pos, &Suffix, 1); |
1187 | } |
1188 | |
1189 | return S; |
1190 | } |
1191 | |
1192 | std::string Intrinsic::replaceParamsIn(std::string S) { |
1193 | while (S.find('$') != std::string::npos) { |
1194 | size_t Pos = S.find('$'); |
1195 | size_t End = Pos + 1; |
1196 | while (isalpha(S[End])) |
1197 | ++End; |
1198 | |
1199 | std::string VarName = S.substr(Pos + 1, End - Pos - 1); |
1200 | assert_with_loc(Variables.find(VarName) != Variables.end(), |
1201 | "Variable not defined!"); |
1202 | S.replace(Pos, End - Pos, Variables.find(VarName)->second.getName()); |
1203 | } |
1204 | |
1205 | return S; |
1206 | } |
1207 | |
1208 | void Intrinsic::initVariables() { |
1209 | Variables.clear(); |
1210 | |
1211 | |
1212 | |
1213 | for (unsigned I = 1; I < Proto.size(); ++I) { |
1214 | char NameC = '0' + (I - 1); |
1215 | std::string Name = "p"; |
1216 | Name.push_back(NameC); |
1217 | |
1218 | Variables[Name] = Variable(Types[I], Name + VariablePostfix); |
1219 | } |
1220 | RetVar = Variable(Types[0], "ret" + VariablePostfix); |
1221 | } |
1222 | |
1223 | void Intrinsic::emitPrototype(StringRef NamePrefix) { |
1224 | if (UseMacro) |
1225 | OS << "#define "; |
1226 | else |
1227 | OS << "__ai " << Types[0].str() << " "; |
1228 | |
1229 | OS << NamePrefix.str() << mangleName(Name, ClassS) << "("; |
1230 | |
1231 | for (unsigned I = 0; I < getNumParams(); ++I) { |
1232 | if (I != 0) |
1233 | OS << ", "; |
1234 | |
1235 | char NameC = '0' + I; |
1236 | std::string Name = "p"; |
1237 | Name.push_back(NameC); |
1238 | assert(Variables.find(Name) != Variables.end()); |
1239 | Variable &V = Variables[Name]; |
1240 | |
1241 | if (!UseMacro) |
1242 | OS << V.getType().str() << " "; |
1243 | OS << V.getName(); |
1244 | } |
1245 | |
1246 | OS << ")"; |
1247 | } |
1248 | |
1249 | void Intrinsic::emitOpeningBrace() { |
1250 | if (UseMacro) |
1251 | OS << " __extension__ ({"; |
1252 | else |
1253 | OS << " {"; |
1254 | emitNewLine(); |
1255 | } |
1256 | |
1257 | void Intrinsic::emitClosingBrace() { |
1258 | if (UseMacro) |
1259 | OS << "})"; |
1260 | else |
1261 | OS << "}"; |
1262 | } |
1263 | |
1264 | void Intrinsic::emitNewLine() { |
1265 | if (UseMacro) |
1266 | OS << " \\\n"; |
1267 | else |
1268 | OS << "\n"; |
1269 | } |
1270 | |
1271 | void Intrinsic::emitReverseVariable(Variable &Dest, Variable &Src) { |
1272 | if (Dest.getType().getNumVectors() > 1) { |
1273 | emitNewLine(); |
1274 | |
1275 | for (unsigned K = 0; K < Dest.getType().getNumVectors(); ++K) { |
1276 | OS << " " << Dest.getName() << ".val[" << K << "] = " |
1277 | << "__builtin_shufflevector(" |
1278 | << Src.getName() << ".val[" << K << "], " |
1279 | << Src.getName() << ".val[" << K << "]"; |
1280 | for (int J = Dest.getType().getNumElements() - 1; J >= 0; --J) |
1281 | OS << ", " << J; |
1282 | OS << ");"; |
1283 | emitNewLine(); |
1284 | } |
1285 | } else { |
1286 | OS << " " << Dest.getName() |
1287 | << " = __builtin_shufflevector(" << Src.getName() << ", " << Src.getName(); |
1288 | for (int J = Dest.getType().getNumElements() - 1; J >= 0; --J) |
1289 | OS << ", " << J; |
1290 | OS << ");"; |
1291 | emitNewLine(); |
1292 | } |
1293 | } |
1294 | |
1295 | void Intrinsic::emitArgumentReversal() { |
1296 | if (BigEndianSafe) |
1297 | return; |
1298 | |
1299 | |
1300 | for (unsigned I = 0; I < getNumParams(); ++I) { |
1301 | std::string Name = "p" + utostr(I); |
1302 | std::string NewName = "rev" + utostr(I); |
1303 | |
1304 | Variable &V = Variables[Name]; |
1305 | Variable NewV(V.getType(), NewName + VariablePostfix); |
1306 | |
1307 | if (!NewV.getType().isVector() || NewV.getType().getNumElements() == 1) |
1308 | continue; |
1309 | |
1310 | OS << " " << NewV.getType().str() << " " << NewV.getName() << ";"; |
1311 | emitReverseVariable(NewV, V); |
1312 | V = NewV; |
1313 | } |
1314 | } |
1315 | |
1316 | void Intrinsic::emitReturnReversal() { |
1317 | if (BigEndianSafe) |
1318 | return; |
1319 | if (!getReturnType().isVector() || getReturnType().isVoid() || |
1320 | getReturnType().getNumElements() == 1) |
1321 | return; |
1322 | emitReverseVariable(RetVar, RetVar); |
1323 | } |
1324 | |
1325 | void Intrinsic::emitShadowedArgs() { |
1326 | |
1327 | |
1328 | if (!UseMacro) |
1329 | return; |
1330 | |
1331 | for (unsigned I = 0; I < getNumParams(); ++I) { |
1332 | |
1333 | |
1334 | if (hasImmediate() && Proto[I+1] == 'i') |
1335 | continue; |
1336 | |
1337 | |
1338 | if (getParamType(I).isPointer()) |
1339 | continue; |
1340 | |
1341 | std::string Name = "p" + utostr(I); |
1342 | |
1343 | assert(Variables.find(Name) != Variables.end()); |
1344 | Variable &V = Variables[Name]; |
1345 | |
1346 | std::string NewName = "s" + utostr(I); |
1347 | Variable V2(V.getType(), NewName + VariablePostfix); |
1348 | |
1349 | OS << " " << V2.getType().str() << " " << V2.getName() << " = " |
1350 | << V.getName() << ";"; |
1351 | emitNewLine(); |
1352 | |
1353 | V = V2; |
1354 | } |
1355 | } |
1356 | |
1357 | |
1358 | |
1359 | bool Intrinsic::protoHasScalar() const { |
1360 | return (Proto.find('s') != std::string::npos || |
1361 | Proto.find('z') != std::string::npos || |
1362 | Proto.find('r') != std::string::npos || |
1363 | Proto.find('b') != std::string::npos || |
1364 | Proto.find('$') != std::string::npos || |
1365 | Proto.find('y') != std::string::npos || |
1366 | Proto.find('o') != std::string::npos); |
1367 | } |
1368 | |
1369 | void Intrinsic::emitBodyAsBuiltinCall() { |
1370 | std::string S; |
1371 | |
1372 | |
1373 | |
1374 | bool SRet = getReturnType().getNumVectors() >= 2; |
1375 | |
1376 | StringRef N = Name; |
1377 | if (hasSplat()) { |
1378 | |
1379 | (0) . __assert_fail ("N.endswith(\"_n\")", "/home/seafit/code_projects/clang_source/clang/utils/TableGen/NeonEmitter.cpp", 1379, __PRETTY_FUNCTION__))" file_link="../../../include/assert.h.html#88" macro="true">assert(N.endswith("_n")); |
1380 | N = N.drop_back(2); |
1381 | } |
1382 | |
1383 | ClassKind LocalCK = CK; |
1384 | if (!protoHasScalar()) |
1385 | LocalCK = ClassB; |
1386 | |
1387 | if (!getReturnType().isVoid() && !SRet) |
1388 | S += "(" + RetVar.getType().str() + ") "; |
1389 | |
1390 | S += "__builtin_neon_" + mangleName(N, LocalCK) + "("; |
1391 | |
1392 | if (SRet) |
1393 | S += "&" + RetVar.getName() + ", "; |
1394 | |
1395 | for (unsigned I = 0; I < getNumParams(); ++I) { |
1396 | Variable &V = Variables["p" + utostr(I)]; |
1397 | Type T = V.getType(); |
1398 | |
1399 | |
1400 | |
1401 | if (T.getNumVectors() > 1) { |
1402 | |
1403 | std::string Cast; |
1404 | if (T.isChar() || T.isPoly() || !T.isSigned()) { |
1405 | Type T2 = T; |
1406 | T2.makeOneVector(); |
1407 | T2.makeInteger(8, ); |
1408 | Cast = "(" + T2.str() + ")"; |
1409 | } |
1410 | |
1411 | for (unsigned J = 0; J < T.getNumVectors(); ++J) |
1412 | S += Cast + V.getName() + ".val[" + utostr(J) + "], "; |
1413 | continue; |
1414 | } |
1415 | |
1416 | std::string Arg; |
1417 | Type CastToType = T; |
1418 | if (hasSplat() && I == getSplatIdx()) { |
1419 | Arg = "(" + BaseType.str() + ") {"; |
1420 | for (unsigned J = 0; J < BaseType.getNumElements(); ++J) { |
1421 | if (J != 0) |
1422 | Arg += ", "; |
1423 | Arg += V.getName(); |
1424 | } |
1425 | Arg += "}"; |
1426 | |
1427 | CastToType = BaseType; |
1428 | } else { |
1429 | Arg = V.getName(); |
1430 | } |
1431 | |
1432 | |
1433 | if (CastToType.isVector()) { |
1434 | CastToType.makeInteger(8, true); |
1435 | Arg = "(" + CastToType.str() + ")" + Arg; |
1436 | } |
1437 | |
1438 | S += Arg + ", "; |
1439 | } |
1440 | |
1441 | |
1442 | if (getClassKind(true) == ClassB) { |
1443 | Type ThisTy = getReturnType(); |
1444 | if (Proto[0] == 'v' || isFloatingPointProtoModifier(Proto[0])) |
1445 | ThisTy = getParamType(0); |
1446 | if (ThisTy.isPointer()) |
1447 | ThisTy = getParamType(1); |
1448 | |
1449 | S += utostr(ThisTy.getNeonEnum()); |
1450 | } else { |
1451 | |
1452 | S.pop_back(); |
1453 | S.pop_back(); |
1454 | } |
1455 | S += ");"; |
1456 | |
1457 | std::string RetExpr; |
1458 | if (!SRet && !RetVar.getType().isVoid()) |
1459 | RetExpr = RetVar.getName() + " = "; |
1460 | |
1461 | OS << " " << RetExpr << S; |
1462 | emitNewLine(); |
1463 | } |
1464 | |
1465 | void Intrinsic::emitBody(StringRef CallPrefix) { |
1466 | std::vector<std::string> Lines; |
1467 | |
1468 | assert(RetVar.getType() == Types[0]); |
1469 | |
1470 | if (!RetVar.getType().isVoid()) { |
1471 | OS << " " << RetVar.getType().str() << " " << RetVar.getName() << ";"; |
1472 | emitNewLine(); |
1473 | } |
1474 | |
1475 | if (!Body || Body->getValues().empty()) { |
1476 | |
1477 | emitBodyAsBuiltinCall(); |
1478 | return; |
1479 | } |
1480 | |
1481 | |
1482 | for (auto *I : Body->getValues()) { |
1483 | if (StringInit *SI = dyn_cast<StringInit>(I)) { |
1484 | Lines.push_back(replaceParamsIn(SI->getAsString())); |
1485 | } else if (DagInit *DI = dyn_cast<DagInit>(I)) { |
1486 | DagEmitter DE(*this, CallPrefix); |
1487 | Lines.push_back(DE.emitDag(DI).second + ";"); |
1488 | } |
1489 | } |
1490 | |
1491 | (0) . __assert_fail ("!Lines.empty() && \"Empty def?\"", "/home/seafit/code_projects/clang_source/clang/utils/TableGen/NeonEmitter.cpp", 1491, __PRETTY_FUNCTION__))" file_link="../../../include/assert.h.html#88" macro="true">assert(!Lines.empty() && "Empty def?"); |
1492 | if (!RetVar.getType().isVoid()) |
1493 | Lines.back().insert(0, RetVar.getName() + " = "); |
1494 | |
1495 | for (auto &L : Lines) { |
1496 | OS << " " << L; |
1497 | emitNewLine(); |
1498 | } |
1499 | } |
1500 | |
1501 | void Intrinsic::emitReturn() { |
1502 | if (RetVar.getType().isVoid()) |
1503 | return; |
1504 | if (UseMacro) |
1505 | OS << " " << RetVar.getName() << ";"; |
1506 | else |
1507 | OS << " return " << RetVar.getName() << ";"; |
1508 | emitNewLine(); |
1509 | } |
1510 | |
1511 | std::pair<Type, std::string> Intrinsic::DagEmitter::emitDag(DagInit *DI) { |
1512 | |
1513 | DefInit *DefI = cast<DefInit>(DI->getOperator()); |
1514 | std::string Op = DefI->getAsString(); |
1515 | |
1516 | if (Op == "cast" || Op == "bitcast") |
1517 | return emitDagCast(DI, Op == "bitcast"); |
1518 | if (Op == "shuffle") |
1519 | return emitDagShuffle(DI); |
1520 | if (Op == "dup") |
1521 | return emitDagDup(DI); |
1522 | if (Op == "dup_typed") |
1523 | return emitDagDupTyped(DI); |
1524 | if (Op == "splat") |
1525 | return emitDagSplat(DI); |
1526 | if (Op == "save_temp") |
1527 | return emitDagSaveTemp(DI); |
1528 | if (Op == "op") |
1529 | return emitDagOp(DI); |
1530 | if (Op == "call") |
1531 | return emitDagCall(DI); |
1532 | if (Op == "name_replace") |
1533 | return emitDagNameReplace(DI); |
1534 | if (Op == "literal") |
1535 | return emitDagLiteral(DI); |
1536 | assert_with_loc(false, "Unknown operation!"); |
1537 | return std::make_pair(Type::getVoid(), ""); |
1538 | } |
1539 | |
1540 | std::pair<Type, std::string> Intrinsic::DagEmitter::emitDagOp(DagInit *DI) { |
1541 | std::string Op = cast<StringInit>(DI->getArg(0))->getAsUnquotedString(); |
1542 | if (DI->getNumArgs() == 2) { |
1543 | |
1544 | std::pair<Type, std::string> R = |
1545 | emitDagArg(DI->getArg(1), DI->getArgNameStr(1)); |
1546 | return std::make_pair(R.first, Op + R.second); |
1547 | } else { |
1548 | (0) . __assert_fail ("DI->getNumArgs() == 3 && \"Can only handle unary and binary ops!\"", "/home/seafit/code_projects/clang_source/clang/utils/TableGen/NeonEmitter.cpp", 1548, __PRETTY_FUNCTION__))" file_link="../../../include/assert.h.html#88" macro="true">assert(DI->getNumArgs() == 3 && "Can only handle unary and binary ops!"); |
1549 | std::pair<Type, std::string> R1 = |
1550 | emitDagArg(DI->getArg(1), DI->getArgNameStr(1)); |
1551 | std::pair<Type, std::string> R2 = |
1552 | emitDagArg(DI->getArg(2), DI->getArgNameStr(2)); |
1553 | assert_with_loc(R1.first == R2.first, "Argument type mismatch!"); |
1554 | return std::make_pair(R1.first, R1.second + " " + Op + " " + R2.second); |
1555 | } |
1556 | } |
1557 | |
1558 | std::pair<Type, std::string> Intrinsic::DagEmitter::emitDagCall(DagInit *DI) { |
1559 | std::vector<Type> Types; |
1560 | std::vector<std::string> Values; |
1561 | for (unsigned I = 0; I < DI->getNumArgs() - 1; ++I) { |
1562 | std::pair<Type, std::string> R = |
1563 | emitDagArg(DI->getArg(I + 1), DI->getArgNameStr(I + 1)); |
1564 | Types.push_back(R.first); |
1565 | Values.push_back(R.second); |
1566 | } |
1567 | |
1568 | |
1569 | std::string N; |
1570 | if (StringInit *SI = dyn_cast<StringInit>(DI->getArg(0))) |
1571 | N = SI->getAsUnquotedString(); |
1572 | else |
1573 | N = emitDagArg(DI->getArg(0), "").second; |
1574 | Intrinsic &Callee = Intr.Emitter.getIntrinsic(N, Types); |
1575 | |
1576 | |
1577 | Callee.setNeededEarly(); |
1578 | Intr.Dependencies.insert(&Callee); |
1579 | |
1580 | |
1581 | std::string S = CallPrefix.str() + Callee.getMangledName(true) + "("; |
1582 | for (unsigned I = 0; I < DI->getNumArgs() - 1; ++I) { |
1583 | if (I != 0) |
1584 | S += ", "; |
1585 | S += Values[I]; |
1586 | } |
1587 | S += ")"; |
1588 | |
1589 | return std::make_pair(Callee.getReturnType(), S); |
1590 | } |
1591 | |
1592 | std::pair<Type, std::string> Intrinsic::DagEmitter::emitDagCast(DagInit *DI, |
1593 | bool IsBitCast){ |
1594 | |
1595 | std::pair<Type, std::string> R = emitDagArg( |
1596 | DI->getArg(DI->getNumArgs() - 1), |
1597 | DI->getArgNameStr(DI->getNumArgs() - 1)); |
1598 | Type castToType = R.first; |
1599 | for (unsigned ArgIdx = 0; ArgIdx < DI->getNumArgs() - 1; ++ArgIdx) { |
1600 | |
1601 | |
1602 | |
1603 | |
1604 | |
1605 | |
1606 | |
1607 | |
1608 | if (!DI->getArgNameStr(ArgIdx).empty()) { |
1609 | assert_with_loc(Intr.Variables.find(DI->getArgNameStr(ArgIdx)) != |
1610 | Intr.Variables.end(), |
1611 | "Variable not found"); |
1612 | castToType = Intr.Variables[DI->getArgNameStr(ArgIdx)].getType(); |
1613 | } else { |
1614 | StringInit *SI = dyn_cast<StringInit>(DI->getArg(ArgIdx)); |
1615 | assert_with_loc(SI, "Expected string type or $Name for cast type"); |
1616 | |
1617 | if (SI->getAsUnquotedString() == "R") { |
1618 | castToType = Intr.getReturnType(); |
1619 | } else if (SI->getAsUnquotedString() == "U") { |
1620 | castToType.makeUnsigned(); |
1621 | } else if (SI->getAsUnquotedString() == "S") { |
1622 | castToType.makeSigned(); |
1623 | } else if (SI->getAsUnquotedString() == "H") { |
1624 | castToType.halveLanes(); |
1625 | } else if (SI->getAsUnquotedString() == "D") { |
1626 | castToType.doubleLanes(); |
1627 | } else if (SI->getAsUnquotedString() == "8") { |
1628 | castToType.makeInteger(8, true); |
1629 | } else { |
1630 | castToType = Type::fromTypedefName(SI->getAsUnquotedString()); |
1631 | assert_with_loc(!castToType.isVoid(), "Unknown typedef"); |
1632 | } |
1633 | } |
1634 | } |
1635 | |
1636 | std::string S; |
1637 | if (IsBitCast) { |
1638 | |
1639 | |
1640 | std::string N = "reint"; |
1641 | unsigned I = 0; |
1642 | while (Intr.Variables.find(N) != Intr.Variables.end()) |
1643 | N = "reint" + utostr(++I); |
1644 | Intr.Variables[N] = Variable(R.first, N + Intr.VariablePostfix); |
1645 | |
1646 | Intr.OS << R.first.str() << " " << Intr.Variables[N].getName() << " = " |
1647 | << R.second << ";"; |
1648 | Intr.emitNewLine(); |
1649 | |
1650 | S = "*(" + castToType.str() + " *) &" + Intr.Variables[N].getName() + ""; |
1651 | } else { |
1652 | |
1653 | S = "(" + castToType.str() + ")(" + R.second + ")"; |
1654 | } |
1655 | |
1656 | return std::make_pair(castToType, S); |
1657 | } |
1658 | |
1659 | std::pair<Type, std::string> Intrinsic::DagEmitter::emitDagShuffle(DagInit *DI){ |
1660 | |
1661 | class LowHalf : public SetTheory::Operator { |
1662 | public: |
1663 | void apply(SetTheory &ST, DagInit *Expr, SetTheory::RecSet &Elts, |
1664 | ArrayRef<SMLoc> Loc) override { |
1665 | SetTheory::RecSet Elts2; |
1666 | ST.evaluate(Expr->arg_begin(), Expr->arg_end(), Elts2, Loc); |
1667 | Elts.insert(Elts2.begin(), Elts2.begin() + (Elts2.size() / 2)); |
1668 | } |
1669 | }; |
1670 | |
1671 | class HighHalf : public SetTheory::Operator { |
1672 | public: |
1673 | void apply(SetTheory &ST, DagInit *Expr, SetTheory::RecSet &Elts, |
1674 | ArrayRef<SMLoc> Loc) override { |
1675 | SetTheory::RecSet Elts2; |
1676 | ST.evaluate(Expr->arg_begin(), Expr->arg_end(), Elts2, Loc); |
1677 | Elts.insert(Elts2.begin() + (Elts2.size() / 2), Elts2.end()); |
1678 | } |
1679 | }; |
1680 | |
1681 | class Rev : public SetTheory::Operator { |
1682 | unsigned ElementSize; |
1683 | |
1684 | public: |
1685 | Rev(unsigned ElementSize) : ElementSize(ElementSize) {} |
1686 | |
1687 | void apply(SetTheory &ST, DagInit *Expr, SetTheory::RecSet &Elts, |
1688 | ArrayRef<SMLoc> Loc) override { |
1689 | SetTheory::RecSet Elts2; |
1690 | ST.evaluate(Expr->arg_begin() + 1, Expr->arg_end(), Elts2, Loc); |
1691 | |
1692 | int64_t VectorSize = cast<IntInit>(Expr->getArg(0))->getValue(); |
1693 | VectorSize /= ElementSize; |
1694 | |
1695 | std::vector<Record *> Revved; |
1696 | for (unsigned VI = 0; VI < Elts2.size(); VI += VectorSize) { |
1697 | for (int LI = VectorSize - 1; LI >= 0; --LI) { |
1698 | Revved.push_back(Elts2[VI + LI]); |
1699 | } |
1700 | } |
1701 | |
1702 | Elts.insert(Revved.begin(), Revved.end()); |
1703 | } |
1704 | }; |
1705 | |
1706 | class MaskExpander : public SetTheory::Expander { |
1707 | unsigned N; |
1708 | |
1709 | public: |
1710 | MaskExpander(unsigned N) : N(N) {} |
1711 | |
1712 | void expand(SetTheory &ST, Record *R, SetTheory::RecSet &Elts) override { |
1713 | unsigned Addend = 0; |
1714 | if (R->getName() == "mask0") |
1715 | Addend = 0; |
1716 | else if (R->getName() == "mask1") |
1717 | Addend = N; |
1718 | else |
1719 | return; |
1720 | for (unsigned I = 0; I < N; ++I) |
1721 | Elts.insert(R->getRecords().getDef("sv" + utostr(I + Addend))); |
1722 | } |
1723 | }; |
1724 | |
1725 | |
1726 | std::pair<Type, std::string> Arg1 = |
1727 | emitDagArg(DI->getArg(0), DI->getArgNameStr(0)); |
1728 | std::pair<Type, std::string> Arg2 = |
1729 | emitDagArg(DI->getArg(1), DI->getArgNameStr(1)); |
1730 | assert_with_loc(Arg1.first == Arg2.first, |
1731 | "Different types in arguments to shuffle!"); |
1732 | |
1733 | SetTheory ST; |
1734 | SetTheory::RecSet Elts; |
1735 | ST.addOperator("lowhalf", llvm::make_unique<LowHalf>()); |
1736 | ST.addOperator("highhalf", llvm::make_unique<HighHalf>()); |
1737 | ST.addOperator("rev", |
1738 | llvm::make_unique<Rev>(Arg1.first.getElementSizeInBits())); |
1739 | ST.addExpander("MaskExpand", |
1740 | llvm::make_unique<MaskExpander>(Arg1.first.getNumElements())); |
1741 | ST.evaluate(DI->getArg(2), Elts, None); |
1742 | |
1743 | std::string S = "__builtin_shufflevector(" + Arg1.second + ", " + Arg2.second; |
1744 | for (auto &E : Elts) { |
1745 | StringRef Name = E->getName(); |
1746 | assert_with_loc(Name.startswith("sv"), |
1747 | "Incorrect element kind in shuffle mask!"); |
1748 | S += ", " + Name.drop_front(2).str(); |
1749 | } |
1750 | S += ")"; |
1751 | |
1752 | |
1753 | Type T(Arg1.first); |
1754 | if (Elts.size() > T.getNumElements()) { |
1755 | assert_with_loc( |
1756 | Elts.size() == T.getNumElements() * 2, |
1757 | "Can only double or half the number of elements in a shuffle!"); |
1758 | T.doubleLanes(); |
1759 | } else if (Elts.size() < T.getNumElements()) { |
1760 | assert_with_loc( |
1761 | Elts.size() == T.getNumElements() / 2, |
1762 | "Can only double or half the number of elements in a shuffle!"); |
1763 | T.halveLanes(); |
1764 | } |
1765 | |
1766 | return std::make_pair(T, S); |
1767 | } |
1768 | |
1769 | std::pair<Type, std::string> Intrinsic::DagEmitter::emitDagDup(DagInit *DI) { |
1770 | assert_with_loc(DI->getNumArgs() == 1, "dup() expects one argument"); |
1771 | std::pair<Type, std::string> A = emitDagArg(DI->getArg(0), |
1772 | DI->getArgNameStr(0)); |
1773 | assert_with_loc(A.first.isScalar(), "dup() expects a scalar argument"); |
1774 | |
1775 | Type T = Intr.getBaseType(); |
1776 | assert_with_loc(T.isVector(), "dup() used but default type is scalar!"); |
1777 | std::string S = "(" + T.str() + ") {"; |
1778 | for (unsigned I = 0; I < T.getNumElements(); ++I) { |
1779 | if (I != 0) |
1780 | S += ", "; |
1781 | S += A.second; |
1782 | } |
1783 | S += "}"; |
1784 | |
1785 | return std::make_pair(T, S); |
1786 | } |
1787 | |
1788 | std::pair<Type, std::string> Intrinsic::DagEmitter::emitDagDupTyped(DagInit *DI) { |
1789 | assert_with_loc(DI->getNumArgs() == 2, "dup_typed() expects two arguments"); |
1790 | std::pair<Type, std::string> A = emitDagArg(DI->getArg(0), |
1791 | DI->getArgNameStr(0)); |
1792 | std::pair<Type, std::string> B = emitDagArg(DI->getArg(1), |
1793 | DI->getArgNameStr(1)); |
1794 | assert_with_loc(B.first.isScalar(), |
1795 | "dup_typed() requires a scalar as the second argument"); |
1796 | |
1797 | Type T = A.first; |
1798 | assert_with_loc(T.isVector(), "dup_typed() used but target type is scalar!"); |
1799 | std::string S = "(" + T.str() + ") {"; |
1800 | for (unsigned I = 0; I < T.getNumElements(); ++I) { |
1801 | if (I != 0) |
1802 | S += ", "; |
1803 | S += B.second; |
1804 | } |
1805 | S += "}"; |
1806 | |
1807 | return std::make_pair(T, S); |
1808 | } |
1809 | |
1810 | std::pair<Type, std::string> Intrinsic::DagEmitter::emitDagSplat(DagInit *DI) { |
1811 | assert_with_loc(DI->getNumArgs() == 2, "splat() expects two arguments"); |
1812 | std::pair<Type, std::string> A = emitDagArg(DI->getArg(0), |
1813 | DI->getArgNameStr(0)); |
1814 | std::pair<Type, std::string> B = emitDagArg(DI->getArg(1), |
1815 | DI->getArgNameStr(1)); |
1816 | |
1817 | assert_with_loc(B.first.isScalar(), |
1818 | "splat() requires a scalar int as the second argument"); |
1819 | |
1820 | std::string S = "__builtin_shufflevector(" + A.second + ", " + A.second; |
1821 | for (unsigned I = 0; I < Intr.getBaseType().getNumElements(); ++I) { |
1822 | S += ", " + B.second; |
1823 | } |
1824 | S += ")"; |
1825 | |
1826 | return std::make_pair(Intr.getBaseType(), S); |
1827 | } |
1828 | |
1829 | std::pair<Type, std::string> Intrinsic::DagEmitter::emitDagSaveTemp(DagInit *DI) { |
1830 | assert_with_loc(DI->getNumArgs() == 2, "save_temp() expects two arguments"); |
1831 | std::pair<Type, std::string> A = emitDagArg(DI->getArg(1), |
1832 | DI->getArgNameStr(1)); |
1833 | |
1834 | assert_with_loc(!A.first.isVoid(), |
1835 | "Argument to save_temp() must have non-void type!"); |
1836 | |
1837 | std::string N = DI->getArgNameStr(0); |
1838 | assert_with_loc(!N.empty(), |
1839 | "save_temp() expects a name as the first argument"); |
1840 | |
1841 | assert_with_loc(Intr.Variables.find(N) == Intr.Variables.end(), |
1842 | "Variable already defined!"); |
1843 | Intr.Variables[N] = Variable(A.first, N + Intr.VariablePostfix); |
1844 | |
1845 | std::string S = |
1846 | A.first.str() + " " + Intr.Variables[N].getName() + " = " + A.second; |
1847 | |
1848 | return std::make_pair(Type::getVoid(), S); |
1849 | } |
1850 | |
1851 | std::pair<Type, std::string> |
1852 | Intrinsic::DagEmitter::emitDagNameReplace(DagInit *DI) { |
1853 | std::string S = Intr.Name; |
1854 | |
1855 | assert_with_loc(DI->getNumArgs() == 2, "name_replace requires 2 arguments!"); |
1856 | std::string ToReplace = cast<StringInit>(DI->getArg(0))->getAsUnquotedString(); |
1857 | std::string ReplaceWith = cast<StringInit>(DI->getArg(1))->getAsUnquotedString(); |
1858 | |
1859 | size_t Idx = S.find(ToReplace); |
1860 | |
1861 | assert_with_loc(Idx != std::string::npos, "name should contain '" + ToReplace + "'!"); |
1862 | S.replace(Idx, ToReplace.size(), ReplaceWith); |
1863 | |
1864 | return std::make_pair(Type::getVoid(), S); |
1865 | } |
1866 | |
1867 | std::pair<Type, std::string> Intrinsic::DagEmitter::emitDagLiteral(DagInit *DI){ |
1868 | std::string Ty = cast<StringInit>(DI->getArg(0))->getAsUnquotedString(); |
1869 | std::string Value = cast<StringInit>(DI->getArg(1))->getAsUnquotedString(); |
1870 | return std::make_pair(Type::fromTypedefName(Ty), Value); |
1871 | } |
1872 | |
1873 | std::pair<Type, std::string> |
1874 | Intrinsic::DagEmitter::emitDagArg(Init *Arg, std::string ArgName) { |
1875 | if (!ArgName.empty()) { |
1876 | assert_with_loc(!Arg->isComplete(), |
1877 | "Arguments must either be DAGs or names, not both!"); |
1878 | assert_with_loc(Intr.Variables.find(ArgName) != Intr.Variables.end(), |
1879 | "Variable not defined!"); |
1880 | Variable &V = Intr.Variables[ArgName]; |
1881 | return std::make_pair(V.getType(), V.getName()); |
1882 | } |
1883 | |
1884 | (0) . __assert_fail ("Arg && \"Neither ArgName nor Arg?!\"", "/home/seafit/code_projects/clang_source/clang/utils/TableGen/NeonEmitter.cpp", 1884, __PRETTY_FUNCTION__))" file_link="../../../include/assert.h.html#88" macro="true">assert(Arg && "Neither ArgName nor Arg?!"); |
1885 | DagInit *DI = dyn_cast<DagInit>(Arg); |
1886 | assert_with_loc(DI, "Arguments must either be DAGs or names!"); |
1887 | |
1888 | return emitDag(DI); |
1889 | } |
1890 | |
1891 | std::string Intrinsic::generate() { |
1892 | |
1893 | |
1894 | OS << "#ifdef __LITTLE_ENDIAN__\n"; |
1895 | |
1896 | generateImpl(false, "", ""); |
1897 | |
1898 | OS << "#else\n"; |
1899 | |
1900 | |
1901 | |
1902 | |
1903 | |
1904 | |
1905 | |
1906 | |
1907 | generateImpl(true, "", "__noswap_"); |
1908 | |
1909 | |
1910 | |
1911 | if (NeededEarly) { |
1912 | generateImpl(false, "__noswap_", "__noswap_"); |
1913 | } |
1914 | OS << "#endif\n\n"; |
1915 | |
1916 | return OS.str(); |
1917 | } |
1918 | |
1919 | void Intrinsic::generateImpl(bool ReverseArguments, |
1920 | StringRef NamePrefix, StringRef CallPrefix) { |
1921 | CurrentRecord = R; |
1922 | |
1923 | |
1924 | |
1925 | |
1926 | |
1927 | |
1928 | for (auto *I : Dependencies) |
1929 | if (I->UseMacro) { |
1930 | VariablePostfix = "_" + utostr(Emitter.getUniqueNumber()); |
1931 | break; |
1932 | } |
1933 | |
1934 | initVariables(); |
1935 | |
1936 | emitPrototype(NamePrefix); |
1937 | |
1938 | if (IsUnavailable) { |
1939 | OS << " __attribute__((unavailable));"; |
1940 | } else { |
1941 | emitOpeningBrace(); |
1942 | emitShadowedArgs(); |
1943 | if (ReverseArguments) |
1944 | emitArgumentReversal(); |
1945 | emitBody(CallPrefix); |
1946 | if (ReverseArguments) |
1947 | emitReturnReversal(); |
1948 | emitReturn(); |
1949 | emitClosingBrace(); |
1950 | } |
1951 | OS << "\n"; |
1952 | |
1953 | CurrentRecord = nullptr; |
1954 | } |
1955 | |
1956 | void Intrinsic::indexBody() { |
1957 | CurrentRecord = R; |
1958 | |
1959 | initVariables(); |
1960 | emitBody(""); |
1961 | OS.str(""); |
1962 | |
1963 | CurrentRecord = nullptr; |
1964 | } |
1965 | |
1966 | |
1967 | |
1968 | |
1969 | |
1970 | Intrinsic &NeonEmitter::getIntrinsic(StringRef Name, ArrayRef<Type> Types) { |
1971 | |
1972 | assert_with_loc(IntrinsicMap.find(Name.str()) != IntrinsicMap.end(), |
1973 | ("Intrinsic '" + Name + "' not found!").str()); |
1974 | auto &V = IntrinsicMap.find(Name.str())->second; |
1975 | std::vector<Intrinsic *> GoodVec; |
1976 | |
1977 | |
1978 | std::string ErrMsg = "looking up intrinsic '" + Name.str() + "("; |
1979 | for (unsigned I = 0; I < Types.size(); ++I) { |
1980 | if (I != 0) |
1981 | ErrMsg += ", "; |
1982 | ErrMsg += Types[I].str(); |
1983 | } |
1984 | ErrMsg += ")'\n"; |
1985 | ErrMsg += "Available overloads:\n"; |
1986 | |
1987 | |
1988 | |
1989 | for (auto &I : V) { |
1990 | ErrMsg += " - " + I.getReturnType().str() + " " + I.getMangledName(); |
1991 | ErrMsg += "("; |
1992 | for (unsigned A = 0; A < I.getNumParams(); ++A) { |
1993 | if (A != 0) |
1994 | ErrMsg += ", "; |
1995 | ErrMsg += I.getParamType(A).str(); |
1996 | } |
1997 | ErrMsg += ")\n"; |
1998 | |
1999 | if (I.getNumParams() != Types.size()) |
2000 | continue; |
2001 | |
2002 | bool Good = true; |
2003 | for (unsigned Arg = 0; Arg < Types.size(); ++Arg) { |
2004 | if (I.getParamType(Arg) != Types[Arg]) { |
2005 | Good = false; |
2006 | break; |
2007 | } |
2008 | } |
2009 | if (Good) |
2010 | GoodVec.push_back(&I); |
2011 | } |
2012 | |
2013 | assert_with_loc(!GoodVec.empty(), |
2014 | "No compatible intrinsic found - " + ErrMsg); |
2015 | assert_with_loc(GoodVec.size() == 1, "Multiple overloads found - " + ErrMsg); |
2016 | |
2017 | return *GoodVec.front(); |
2018 | } |
2019 | |
2020 | void NeonEmitter::createIntrinsic(Record *R, |
2021 | SmallVectorImpl<Intrinsic *> &Out) { |
2022 | std::string Name = R->getValueAsString("Name"); |
2023 | std::string Proto = R->getValueAsString("Prototype"); |
2024 | std::string Types = R->getValueAsString("Types"); |
2025 | Record *OperationRec = R->getValueAsDef("Operation"); |
2026 | bool CartesianProductOfTypes = R->getValueAsBit("CartesianProductOfTypes"); |
2027 | bool BigEndianSafe = R->getValueAsBit("BigEndianSafe"); |
2028 | std::string Guard = R->getValueAsString("ArchGuard"); |
2029 | bool IsUnavailable = OperationRec->getValueAsBit("Unavailable"); |
2030 | |
2031 | |
2032 | |
2033 | CurrentRecord = R; |
2034 | |
2035 | ListInit *Body = OperationRec->getValueAsListInit("Ops"); |
2036 | |
2037 | std::vector<TypeSpec> TypeSpecs = TypeSpec::fromTypeSpecs(Types); |
2038 | |
2039 | ClassKind CK = ClassNone; |
2040 | if (R->getSuperClasses().size() >= 2) |
2041 | CK = ClassMap[R->getSuperClasses()[1].first]; |
2042 | |
2043 | std::vector<std::pair<TypeSpec, TypeSpec>> NewTypeSpecs; |
2044 | for (auto TS : TypeSpecs) { |
2045 | if (CartesianProductOfTypes) { |
2046 | Type DefaultT(TS, 'd'); |
2047 | for (auto SrcTS : TypeSpecs) { |
2048 | Type DefaultSrcT(SrcTS, 'd'); |
2049 | if (TS == SrcTS || |
2050 | DefaultSrcT.getSizeInBits() != DefaultT.getSizeInBits()) |
2051 | continue; |
2052 | NewTypeSpecs.push_back(std::make_pair(TS, SrcTS)); |
2053 | } |
2054 | } else { |
2055 | NewTypeSpecs.push_back(std::make_pair(TS, TS)); |
2056 | } |
2057 | } |
2058 | |
2059 | llvm::sort(NewTypeSpecs); |
2060 | NewTypeSpecs.erase(std::unique(NewTypeSpecs.begin(), NewTypeSpecs.end()), |
2061 | NewTypeSpecs.end()); |
2062 | auto &Entry = IntrinsicMap[Name]; |
2063 | |
2064 | for (auto &I : NewTypeSpecs) { |
2065 | Entry.emplace_back(R, Name, Proto, I.first, I.second, CK, Body, *this, |
2066 | Guard, IsUnavailable, BigEndianSafe); |
2067 | Out.push_back(&Entry.back()); |
2068 | } |
2069 | |
2070 | CurrentRecord = nullptr; |
2071 | } |
2072 | |
2073 | |
2074 | |
2075 | void NeonEmitter::genBuiltinsDef(raw_ostream &OS, |
2076 | SmallVectorImpl<Intrinsic *> &Defs) { |
2077 | OS << "#ifdef GET_NEON_BUILTINS\n"; |
2078 | |
2079 | |
2080 | |
2081 | std::set<std::string> Builtins; |
2082 | |
2083 | for (auto *Def : Defs) { |
2084 | if (Def->hasBody()) |
2085 | continue; |
2086 | |
2087 | |
2088 | if (Def->hasSplat()) |
2089 | continue; |
2090 | |
2091 | std::string S = "BUILTIN(__builtin_neon_" + Def->getMangledName() + ", \""; |
2092 | |
2093 | S += Def->getBuiltinTypeStr(); |
2094 | S += "\", \"n\")"; |
2095 | |
2096 | Builtins.insert(S); |
2097 | } |
2098 | |
2099 | for (auto &S : Builtins) |
2100 | OS << S << "\n"; |
2101 | OS << "#endif\n\n"; |
2102 | } |
2103 | |
2104 | |
2105 | |
2106 | void NeonEmitter::genOverloadTypeCheckCode(raw_ostream &OS, |
2107 | SmallVectorImpl<Intrinsic *> &Defs) { |
2108 | OS << "#ifdef GET_NEON_OVERLOAD_CHECK\n"; |
2109 | |
2110 | |
2111 | |
2112 | |
2113 | struct OverloadInfo { |
2114 | uint64_t Mask; |
2115 | int PtrArgNum; |
2116 | bool HasConstPtr; |
2117 | OverloadInfo() : Mask(0ULL), PtrArgNum(0), HasConstPtr(false) {} |
2118 | }; |
2119 | std::map<std::string, OverloadInfo> OverloadMap; |
2120 | |
2121 | for (auto *Def : Defs) { |
2122 | |
2123 | |
2124 | if (Def->hasBody()) |
2125 | continue; |
2126 | |
2127 | |
2128 | if (Def->hasSplat()) |
2129 | continue; |
2130 | |
2131 | |
2132 | if (Def->protoHasScalar()) |
2133 | continue; |
2134 | |
2135 | uint64_t Mask = 0ULL; |
2136 | Type Ty = Def->getReturnType(); |
2137 | if (Def->getProto()[0] == 'v' || |
2138 | isFloatingPointProtoModifier(Def->getProto()[0])) |
2139 | Ty = Def->getParamType(0); |
2140 | if (Ty.isPointer()) |
2141 | Ty = Def->getParamType(1); |
2142 | |
2143 | Mask |= 1ULL << Ty.getNeonEnum(); |
2144 | |
2145 | |
2146 | std::string Proto = Def->getProto(); |
2147 | int PtrArgNum = -1; |
2148 | bool HasConstPtr = false; |
2149 | for (unsigned I = 0; I < Def->getNumParams(); ++I) { |
2150 | char ArgType = Proto[I + 1]; |
2151 | if (ArgType == 'c') { |
2152 | HasConstPtr = true; |
2153 | PtrArgNum = I; |
2154 | break; |
2155 | } |
2156 | if (ArgType == 'p') { |
2157 | PtrArgNum = I; |
2158 | break; |
2159 | } |
2160 | } |
2161 | |
2162 | if (PtrArgNum >= 0 && Def->getReturnType().getNumVectors() > 1) |
2163 | PtrArgNum += 1; |
2164 | |
2165 | std::string Name = Def->getName(); |
2166 | |
2167 | |
2168 | |
2169 | |
2170 | |
2171 | |
2172 | if (Name == "vld1_lane" || Name == "vld1_dup" || Name == "vst1_lane") { |
2173 | PtrArgNum = -1; |
2174 | HasConstPtr = false; |
2175 | } |
2176 | |
2177 | if (Mask) { |
2178 | std::string Name = Def->getMangledName(); |
2179 | OverloadMap.insert(std::make_pair(Name, OverloadInfo())); |
2180 | OverloadInfo &OI = OverloadMap[Name]; |
2181 | OI.Mask |= Mask; |
2182 | OI.PtrArgNum |= PtrArgNum; |
2183 | OI.HasConstPtr = HasConstPtr; |
2184 | } |
2185 | } |
2186 | |
2187 | for (auto &I : OverloadMap) { |
2188 | OverloadInfo &OI = I.second; |
2189 | |
2190 | OS << "case NEON::BI__builtin_neon_" << I.first << ": "; |
2191 | OS << "mask = 0x" << Twine::utohexstr(OI.Mask) << "ULL"; |
2192 | if (OI.PtrArgNum >= 0) |
2193 | OS << "; PtrArgNum = " << OI.PtrArgNum; |
2194 | if (OI.HasConstPtr) |
2195 | OS << "; HasConstPtr = true"; |
2196 | OS << "; break;\n"; |
2197 | } |
2198 | OS << "#endif\n\n"; |
2199 | } |
2200 | |
2201 | void NeonEmitter::genIntrinsicRangeCheckCode(raw_ostream &OS, |
2202 | SmallVectorImpl<Intrinsic *> &Defs) { |
2203 | OS << "#ifdef GET_NEON_IMMEDIATE_CHECK\n"; |
2204 | |
2205 | std::set<std::string> Emitted; |
2206 | |
2207 | for (auto *Def : Defs) { |
2208 | if (Def->hasBody()) |
2209 | continue; |
2210 | |
2211 | |
2212 | if (Def->hasSplat()) |
2213 | continue; |
2214 | |
2215 | |
2216 | if (!Def->hasImmediate()) |
2217 | continue; |
2218 | if (Emitted.find(Def->getMangledName()) != Emitted.end()) |
2219 | continue; |
2220 | |
2221 | std::string LowerBound, UpperBound; |
2222 | |
2223 | Record *R = Def->getRecord(); |
2224 | if (R->getValueAsBit("isVCVT_N")) { |
2225 | |
2226 | |
2227 | LowerBound = "1"; |
2228 | if (Def->getBaseType().getElementSizeInBits() == 16 || |
2229 | Def->getName().find('h') != std::string::npos) |
2230 | |
2231 | UpperBound = "15"; |
2232 | else if (Def->getBaseType().getElementSizeInBits() == 32) |
2233 | UpperBound = "31"; |
2234 | else |
2235 | UpperBound = "63"; |
2236 | } else if (R->getValueAsBit("isScalarShift")) { |
2237 | |
2238 | |
2239 | if (Def->getName().find('r') != std::string::npos || |
2240 | Def->getName().find("cvt") != std::string::npos) |
2241 | LowerBound = "1"; |
2242 | |
2243 | UpperBound = utostr(Def->getReturnType().getElementSizeInBits() - 1); |
2244 | } else if (R->getValueAsBit("isShift")) { |
2245 | |
2246 | |
2247 | |
2248 | |
2249 | if (Def->getName().find('r') != std::string::npos) |
2250 | LowerBound = "1"; |
2251 | UpperBound = "RFT(TV, true)"; |
2252 | } else if (Def->getClassKind(true) == ClassB) { |
2253 | |
2254 | |
2255 | if (R->getValueAsBit("isLaneQ")) |
2256 | UpperBound = "RFT(TV, false, true)"; |
2257 | else |
2258 | UpperBound = "RFT(TV, false, false)"; |
2259 | } else { |
2260 | |
2261 | getImmediateIdx() > 0", "/home/seafit/code_projects/clang_source/clang/utils/TableGen/NeonEmitter.cpp", 2261, __PRETTY_FUNCTION__))" file_link="../../../include/assert.h.html#88" macro="true">assert(Def->getImmediateIdx() > 0); |
2262 | Type T = Def->getParamType(Def->getImmediateIdx() - 1); |
2263 | UpperBound = utostr(T.getNumElements() - 1); |
2264 | } |
2265 | |
2266 | |
2267 | unsigned Idx = Def->getNumParams(); |
2268 | if (Def->hasImmediate()) |
2269 | Idx = Def->getGeneratedParamIdx(Def->getImmediateIdx()); |
2270 | |
2271 | OS << "case NEON::BI__builtin_neon_" << Def->getMangledName() << ": " |
2272 | << "i = " << Idx << ";"; |
2273 | if (!LowerBound.empty()) |
2274 | OS << " l = " << LowerBound << ";"; |
2275 | if (!UpperBound.empty()) |
2276 | OS << " u = " << UpperBound << ";"; |
2277 | OS << " break;\n"; |
2278 | |
2279 | Emitted.insert(Def->getMangledName()); |
2280 | } |
2281 | |
2282 | OS << "#endif\n\n"; |
2283 | } |
2284 | |
2285 | |
2286 | |
2287 | |
2288 | |
2289 | void NeonEmitter::(raw_ostream &OS) { |
2290 | std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst"); |
2291 | |
2292 | SmallVector<Intrinsic *, 128> Defs; |
2293 | for (auto *R : RV) |
2294 | createIntrinsic(R, Defs); |
2295 | |
2296 | |
2297 | genBuiltinsDef(OS, Defs); |
2298 | |
2299 | |
2300 | genOverloadTypeCheckCode(OS, Defs); |
2301 | |
2302 | |
2303 | genIntrinsicRangeCheckCode(OS, Defs); |
2304 | } |
2305 | |
2306 | |
2307 | |
2308 | void NeonEmitter::run(raw_ostream &OS) { |
2309 | OS << "/*===---- arm_neon.h - ARM Neon intrinsics " |
2310 | "------------------------------" |
2311 | "---===\n" |
2312 | " *\n" |
2313 | " * Permission is hereby granted, free of charge, to any person " |
2314 | "obtaining " |
2315 | "a copy\n" |
2316 | " * of this software and associated documentation files (the " |
2317 | "\"Software\")," |
2318 | " to deal\n" |
2319 | " * in the Software without restriction, including without limitation " |
2320 | "the " |
2321 | "rights\n" |
2322 | " * to use, copy, modify, merge, publish, distribute, sublicense, " |
2323 | "and/or sell\n" |
2324 | " * copies of the Software, and to permit persons to whom the Software " |
2325 | "is\n" |
2326 | " * furnished to do so, subject to the following conditions:\n" |
2327 | " *\n" |
2328 | " * The above copyright notice and this permission notice shall be " |
2329 | "included in\n" |
2330 | " * all copies or substantial portions of the Software.\n" |
2331 | " *\n" |
2332 | " * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, " |
2333 | "EXPRESS OR\n" |
2334 | " * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF " |
2335 | "MERCHANTABILITY,\n" |
2336 | " * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT " |
2337 | "SHALL THE\n" |
2338 | " * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR " |
2339 | "OTHER\n" |
2340 | " * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, " |
2341 | "ARISING FROM,\n" |
2342 | " * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER " |
2343 | "DEALINGS IN\n" |
2344 | " * THE SOFTWARE.\n" |
2345 | " *\n" |
2346 | " *===-----------------------------------------------------------------" |
2347 | "---" |
2348 | "---===\n" |
2349 | " */\n\n"; |
2350 | |
2351 | OS << "#ifndef __ARM_NEON_H\n"; |
2352 | OS << "#define __ARM_NEON_H\n\n"; |
2353 | |
2354 | OS << "#if !defined(__ARM_NEON)\n"; |
2355 | OS << "#error \"NEON support not enabled\"\n"; |
2356 | OS << "#endif\n\n"; |
2357 | |
2358 | OS << "#include <stdint.h>\n\n"; |
2359 | |
2360 | |
2361 | OS << "typedef float float32_t;\n"; |
2362 | OS << "typedef __fp16 float16_t;\n"; |
2363 | |
2364 | OS << "#ifdef __aarch64__\n"; |
2365 | OS << "typedef double float64_t;\n"; |
2366 | OS << "#endif\n\n"; |
2367 | |
2368 | |
2369 | OS << "#ifdef __aarch64__\n"; |
2370 | OS << "typedef uint8_t poly8_t;\n"; |
2371 | OS << "typedef uint16_t poly16_t;\n"; |
2372 | OS << "typedef uint64_t poly64_t;\n"; |
2373 | OS << "typedef __uint128_t poly128_t;\n"; |
2374 | OS << "#else\n"; |
2375 | OS << "typedef int8_t poly8_t;\n"; |
2376 | OS << "typedef int16_t poly16_t;\n"; |
2377 | OS << "#endif\n"; |
2378 | |
2379 | |
2380 | std::string TypedefTypes( |
2381 | "cQcsQsiQilQlUcQUcUsQUsUiQUiUlQUlhQhfQfdQdPcQPcPsQPsPlQPl"); |
2382 | std::vector<TypeSpec> TDTypeVec = TypeSpec::fromTypeSpecs(TypedefTypes); |
2383 | |
2384 | |
2385 | bool InIfdef = false; |
2386 | for (auto &TS : TDTypeVec) { |
2387 | bool IsA64 = false; |
2388 | Type T(TS, 'd'); |
2389 | if (T.isDouble() || (T.isPoly() && T.isLong())) |
2390 | IsA64 = true; |
2391 | |
2392 | if (InIfdef && !IsA64) { |
2393 | OS << "#endif\n"; |
2394 | InIfdef = false; |
2395 | } |
2396 | if (!InIfdef && IsA64) { |
2397 | OS << "#ifdef __aarch64__\n"; |
2398 | InIfdef = true; |
2399 | } |
2400 | |
2401 | if (T.isPoly()) |
2402 | OS << "typedef __attribute__((neon_polyvector_type("; |
2403 | else |
2404 | OS << "typedef __attribute__((neon_vector_type("; |
2405 | |
2406 | Type T2 = T; |
2407 | T2.makeScalar(); |
2408 | OS << T.getNumElements() << "))) "; |
2409 | OS << T2.str(); |
2410 | OS << " " << T.str() << ";\n"; |
2411 | } |
2412 | if (InIfdef) |
2413 | OS << "#endif\n"; |
2414 | OS << "\n"; |
2415 | |
2416 | |
2417 | InIfdef = false; |
2418 | for (unsigned NumMembers = 2; NumMembers <= 4; ++NumMembers) { |
2419 | for (auto &TS : TDTypeVec) { |
2420 | bool IsA64 = false; |
2421 | Type T(TS, 'd'); |
2422 | if (T.isDouble() || (T.isPoly() && T.isLong())) |
2423 | IsA64 = true; |
2424 | |
2425 | if (InIfdef && !IsA64) { |
2426 | OS << "#endif\n"; |
2427 | InIfdef = false; |
2428 | } |
2429 | if (!InIfdef && IsA64) { |
2430 | OS << "#ifdef __aarch64__\n"; |
2431 | InIfdef = true; |
2432 | } |
2433 | |
2434 | char M = '2' + (NumMembers - 2); |
2435 | Type VT(TS, M); |
2436 | OS << "typedef struct " << VT.str() << " {\n"; |
2437 | OS << " " << T.str() << " val"; |
2438 | OS << "[" << NumMembers << "]"; |
2439 | OS << ";\n} "; |
2440 | OS << VT.str() << ";\n"; |
2441 | OS << "\n"; |
2442 | } |
2443 | } |
2444 | if (InIfdef) |
2445 | OS << "#endif\n"; |
2446 | OS << "\n"; |
2447 | |
2448 | OS << "#define __ai static __inline__ __attribute__((__always_inline__, " |
2449 | "__nodebug__))\n\n"; |
2450 | |
2451 | SmallVector<Intrinsic *, 128> Defs; |
2452 | std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst"); |
2453 | for (auto *R : RV) |
2454 | createIntrinsic(R, Defs); |
2455 | |
2456 | for (auto *I : Defs) |
2457 | I->indexBody(); |
2458 | |
2459 | std::stable_sort( |
2460 | Defs.begin(), Defs.end(), |
2461 | [](const Intrinsic *A, const Intrinsic *B) { return *A < *B; }); |
2462 | |
2463 | |
2464 | |
2465 | bool MadeProgress = true; |
2466 | std::string InGuard; |
2467 | while (!Defs.empty() && MadeProgress) { |
2468 | MadeProgress = false; |
2469 | |
2470 | for (SmallVector<Intrinsic *, 128>::iterator I = Defs.begin(); |
2471 | I != Defs.end(); ) { |
2472 | bool DependenciesSatisfied = true; |
2473 | for (auto *II : (*I)->getDependencies()) { |
2474 | if (llvm::is_contained(Defs, II)) |
2475 | DependenciesSatisfied = false; |
2476 | } |
2477 | if (!DependenciesSatisfied) { |
2478 | |
2479 | ++I; |
2480 | continue; |
2481 | } |
2482 | |
2483 | |
2484 | if ((*I)->getGuard() != InGuard) { |
2485 | if (!InGuard.empty()) |
2486 | OS << "#endif\n"; |
2487 | InGuard = (*I)->getGuard(); |
2488 | if (!InGuard.empty()) |
2489 | OS << "#if " << InGuard << "\n"; |
2490 | } |
2491 | |
2492 | |
2493 | OS << (*I)->generate(); |
2494 | |
2495 | MadeProgress = true; |
2496 | I = Defs.erase(I); |
2497 | } |
2498 | } |
2499 | (0) . __assert_fail ("Defs.empty() && \"Some requirements were not satisfied!\"", "/home/seafit/code_projects/clang_source/clang/utils/TableGen/NeonEmitter.cpp", 2499, __PRETTY_FUNCTION__))" file_link="../../../include/assert.h.html#88" macro="true">assert(Defs.empty() && "Some requirements were not satisfied!"); |
2500 | if (!InGuard.empty()) |
2501 | OS << "#endif\n"; |
2502 | |
2503 | OS << "\n"; |
2504 | OS << "#undef __ai\n\n"; |
2505 | OS << "#endif /* __ARM_NEON_H */\n"; |
2506 | } |
2507 | |
2508 | |
2509 | |
2510 | void NeonEmitter::runFP16(raw_ostream &OS) { |
2511 | OS << "/*===---- arm_fp16.h - ARM FP16 intrinsics " |
2512 | "------------------------------" |
2513 | "---===\n" |
2514 | " *\n" |
2515 | " * Permission is hereby granted, free of charge, to any person " |
2516 | "obtaining a copy\n" |
2517 | " * of this software and associated documentation files (the " |
2518 | "\"Software\"), to deal\n" |
2519 | " * in the Software without restriction, including without limitation " |
2520 | "the rights\n" |
2521 | " * to use, copy, modify, merge, publish, distribute, sublicense, " |
2522 | "and/or sell\n" |
2523 | " * copies of the Software, and to permit persons to whom the Software " |
2524 | "is\n" |
2525 | " * furnished to do so, subject to the following conditions:\n" |
2526 | " *\n" |
2527 | " * The above copyright notice and this permission notice shall be " |
2528 | "included in\n" |
2529 | " * all copies or substantial portions of the Software.\n" |
2530 | " *\n" |
2531 | " * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, " |
2532 | "EXPRESS OR\n" |
2533 | " * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF " |
2534 | "MERCHANTABILITY,\n" |
2535 | " * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT " |
2536 | "SHALL THE\n" |
2537 | " * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR " |
2538 | "OTHER\n" |
2539 | " * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, " |
2540 | "ARISING FROM,\n" |
2541 | " * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER " |
2542 | "DEALINGS IN\n" |
2543 | " * THE SOFTWARE.\n" |
2544 | " *\n" |
2545 | " *===-----------------------------------------------------------------" |
2546 | "---" |
2547 | "---===\n" |
2548 | " */\n\n"; |
2549 | |
2550 | OS << "#ifndef __ARM_FP16_H\n"; |
2551 | OS << "#define __ARM_FP16_H\n\n"; |
2552 | |
2553 | OS << "#include <stdint.h>\n\n"; |
2554 | |
2555 | OS << "typedef __fp16 float16_t;\n"; |
2556 | |
2557 | OS << "#define __ai static __inline__ __attribute__((__always_inline__, " |
2558 | "__nodebug__))\n\n"; |
2559 | |
2560 | SmallVector<Intrinsic *, 128> Defs; |
2561 | std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst"); |
2562 | for (auto *R : RV) |
2563 | createIntrinsic(R, Defs); |
2564 | |
2565 | for (auto *I : Defs) |
2566 | I->indexBody(); |
2567 | |
2568 | std::stable_sort( |
2569 | Defs.begin(), Defs.end(), |
2570 | [](const Intrinsic *A, const Intrinsic *B) { return *A < *B; }); |
2571 | |
2572 | |
2573 | |
2574 | bool MadeProgress = true; |
2575 | std::string InGuard; |
2576 | while (!Defs.empty() && MadeProgress) { |
2577 | MadeProgress = false; |
2578 | |
2579 | for (SmallVector<Intrinsic *, 128>::iterator I = Defs.begin(); |
2580 | I != Defs.end(); ) { |
2581 | bool DependenciesSatisfied = true; |
2582 | for (auto *II : (*I)->getDependencies()) { |
2583 | if (llvm::is_contained(Defs, II)) |
2584 | DependenciesSatisfied = false; |
2585 | } |
2586 | if (!DependenciesSatisfied) { |
2587 | |
2588 | ++I; |
2589 | continue; |
2590 | } |
2591 | |
2592 | |
2593 | if ((*I)->getGuard() != InGuard) { |
2594 | if (!InGuard.empty()) |
2595 | OS << "#endif\n"; |
2596 | InGuard = (*I)->getGuard(); |
2597 | if (!InGuard.empty()) |
2598 | OS << "#if " << InGuard << "\n"; |
2599 | } |
2600 | |
2601 | |
2602 | OS << (*I)->generate(); |
2603 | |
2604 | MadeProgress = true; |
2605 | I = Defs.erase(I); |
2606 | } |
2607 | } |
2608 | (0) . __assert_fail ("Defs.empty() && \"Some requirements were not satisfied!\"", "/home/seafit/code_projects/clang_source/clang/utils/TableGen/NeonEmitter.cpp", 2608, __PRETTY_FUNCTION__))" file_link="../../../include/assert.h.html#88" macro="true">assert(Defs.empty() && "Some requirements were not satisfied!"); |
2609 | if (!InGuard.empty()) |
2610 | OS << "#endif\n"; |
2611 | |
2612 | OS << "\n"; |
2613 | OS << "#undef __ai\n\n"; |
2614 | OS << "#endif /* __ARM_FP16_H */\n"; |
2615 | } |
2616 | |
2617 | namespace clang { |
2618 | |
2619 | void EmitNeon(RecordKeeper &Records, raw_ostream &OS) { |
2620 | NeonEmitter(Records).run(OS); |
2621 | } |
2622 | |
2623 | void EmitFP16(RecordKeeper &Records, raw_ostream &OS) { |
2624 | NeonEmitter(Records).runFP16(OS); |
2625 | } |
2626 | |
2627 | void EmitNeonSema(RecordKeeper &Records, raw_ostream &OS) { |
2628 | NeonEmitter(Records).runHeader(OS); |
2629 | } |
2630 | |
2631 | void EmitNeonTest(RecordKeeper &Records, raw_ostream &OS) { |
2632 | llvm_unreachable("Neon test generation no longer implemented!"); |
2633 | } |
2634 | |
2635 | } |
2636 | |