blob: 831dfa804ca094a686e0a9a3386a468b66a9c413 [file] [log] [blame]
Sander de Smalen5087ace2020-03-15 14:29:45 +00001//===- SveEmitter.cpp - Generate arm_sve.h for use with clang -*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This tablegen backend is responsible for emitting arm_sve.h, which includes
10// a declaration and definition of each function specified by the ARM C/C++
11// Language Extensions (ACLE).
12//
13// For details, visit:
14// https://developer.arm.com/architectures/system-architectures/software-standards/acle
15//
16// Each SVE instruction is implemented in terms of 1 or more functions which
17// are suffixed with the element type of the input vectors. Functions may be
18// implemented in terms of generic vector operations such as +, *, -, etc. or
19// by calling a __builtin_-prefixed function which will be handled by clang's
20// CodeGen library.
21//
22// See also the documentation in include/clang/Basic/arm_sve.td.
23//
24//===----------------------------------------------------------------------===//
25
26#include "llvm/ADT/STLExtras.h"
Sander de Smalenc5b81462020-03-18 11:07:20 +000027#include "llvm/ADT/StringMap.h"
Sander de Smalen5087ace2020-03-15 14:29:45 +000028#include "llvm/ADT/ArrayRef.h"
29#include "llvm/ADT/StringExtras.h"
30#include "llvm/TableGen/Record.h"
31#include "llvm/TableGen/Error.h"
32#include <string>
33#include <sstream>
34#include <set>
35#include <cctype>
36
37using namespace llvm;
38
Sander de Smalenc5b81462020-03-18 11:07:20 +000039enum ClassKind {
40 ClassNone,
41 ClassS, // signed/unsigned, e.g., "_s8", "_u8" suffix
42 ClassG, // Overloaded name without type suffix
43};
44
45using TypeSpec = std::string;
Sander de Smalen5087ace2020-03-15 14:29:45 +000046
47namespace {
48
Sander de Smalenc5b81462020-03-18 11:07:20 +000049class SVEType {
50 TypeSpec TS;
51 bool Float, Signed, Immediate, Void, Constant, Pointer;
52 bool DefaultType, IsScalable, Predicate, PredicatePattern, PrefetchOp;
53 unsigned Bitwidth, ElementBitwidth, NumVectors;
54
Sander de Smalen8b409ea2020-03-16 10:14:05 +000055public:
Sander de Smalenc5b81462020-03-18 11:07:20 +000056 SVEType() : SVEType(TypeSpec(), 'v') {}
57
58 SVEType(TypeSpec TS, char CharMod)
59 : TS(TS), Float(false), Signed(true), Immediate(false), Void(false),
60 Constant(false), Pointer(false), DefaultType(false), IsScalable(true),
61 Predicate(false), PredicatePattern(false), PrefetchOp(false),
62 Bitwidth(128), ElementBitwidth(~0U), NumVectors(1) {
63 if (!TS.empty())
64 applyTypespec();
65 applyModifier(CharMod);
66 }
67
68 /// Return the value in SVETypeFlags for this type.
69 unsigned getTypeFlags() const;
70
71 bool isPointer() const { return Pointer; }
72 bool isVoidPointer() const { return Pointer && Void; }
73 bool isSigned() const { return Signed; }
74 bool isImmediate() const { return Immediate; }
75 bool isScalar() const { return NumVectors == 0; }
76 bool isVector() const { return NumVectors > 0; }
77 bool isScalableVector() const { return isVector() && IsScalable; }
78 bool isChar() const { return ElementBitwidth == 8; }
79 bool isVoid() const { return Void & !Pointer; }
80 bool isDefault() const { return DefaultType; }
81 bool isFloat() const { return Float; }
82 bool isInteger() const { return !Float && !Predicate; }
83 bool isScalarPredicate() const { return !Float && ElementBitwidth == 1; }
84 bool isPredicateVector() const { return Predicate; }
85 bool isPredicatePattern() const { return PredicatePattern; }
86 bool isPrefetchOp() const { return PrefetchOp; }
87 bool isConstant() const { return Constant; }
88 unsigned getElementSizeInBits() const { return ElementBitwidth; }
89 unsigned getNumVectors() const { return NumVectors; }
90
91 unsigned getNumElements() const {
92 assert(ElementBitwidth != ~0U);
93 return Bitwidth / ElementBitwidth;
94 }
95 unsigned getSizeInBits() const {
96 return Bitwidth;
97 }
98
99 /// Return the string representation of a type, which is an encoded
100 /// string for passing to the BUILTIN() macro in Builtins.def.
101 std::string builtin_str() const;
102
Sander de Smalen981f0802020-03-18 15:05:08 +0000103 /// Return the C/C++ string representation of a type for use in the
104 /// arm_sve.h header file.
105 std::string str() const;
106
Sander de Smalenc5b81462020-03-18 11:07:20 +0000107private:
108 /// Creates the type based on the typespec string in TS.
109 void applyTypespec();
110
111 /// Applies a prototype modifier to the type.
112 void applyModifier(char Mod);
113};
114
115
116class SVEEmitter;
117
118/// The main grunt class. This represents an instantiation of an intrinsic with
119/// a particular typespec and prototype.
120class Intrinsic {
121 /// The unmangled name.
122 std::string Name;
123
124 /// The name of the corresponding LLVM IR intrinsic.
125 std::string LLVMName;
126
127 /// Intrinsic prototype.
128 std::string Proto;
129
130 /// The base type spec for this intrinsic.
131 TypeSpec BaseTypeSpec;
132
133 /// The base class kind. Most intrinsics use ClassS, which has full type
134 /// info for integers (_s32/_u32), or ClassG which is used for overloaded
135 /// intrinsics.
136 ClassKind Class;
137
138 /// The architectural #ifdef guard.
139 std::string Guard;
140
141 /// The types of return value [0] and parameters [1..].
142 std::vector<SVEType> Types;
143
144 /// The "base type", which is VarType('d', BaseTypeSpec).
145 SVEType BaseType;
146
147 unsigned Flags;
148
149public:
150 /// The type of predication.
151 enum MergeType {
152 MergeNone,
153 MergeAny,
154 MergeOp1,
155 MergeZero,
156 MergeAnyExp,
157 MergeZeroExp,
158 MergeInvalid
159 } Merge;
160
161 Intrinsic(StringRef Name, StringRef Proto, int64_t MT, StringRef LLVMName,
162 unsigned Flags, TypeSpec BT, ClassKind Class, SVEEmitter &Emitter,
163 StringRef Guard)
164 : Name(Name.str()), LLVMName(LLVMName), Proto(Proto.str()),
165 BaseTypeSpec(BT), Class(Class), Guard(Guard.str()), BaseType(BT, 'd'),
166 Flags(Flags), Merge(MergeType(MT)) {
167 // Types[0] is the return value.
168 for (unsigned I = 0; I < Proto.size(); ++I)
169 Types.emplace_back(BaseTypeSpec, Proto[I]);
170 }
171
172 ~Intrinsic()=default;
173
174 std::string getName() const { return Name; }
175 std::string getLLVMName() const { return LLVMName; }
176 std::string getProto() const { return Proto; }
177 TypeSpec getBaseTypeSpec() const { return BaseTypeSpec; }
178 SVEType getBaseType() const { return BaseType; }
179
180 StringRef getGuard() const { return Guard; }
181 ClassKind getClassKind() const { return Class; }
182 MergeType getMergeType() const { return Merge; }
183
184 SVEType getReturnType() const { return Types[0]; }
185 ArrayRef<SVEType> getTypes() const { return Types; }
186 SVEType getParamType(unsigned I) const { return Types[I + 1]; }
187 unsigned getNumParams() const { return Proto.size() - 1; }
188
189 unsigned getFlags() const { return Flags; }
190 bool isFlagSet(uint64_t Flag) const { return Flags & Flag;}
191
192 /// Return the type string for a BUILTIN() macro in Builtins.def.
193 std::string getBuiltinTypeStr();
194
195 /// Return the name, mangled with type information. The name is mangled for
196 /// ClassS, so will add type suffixes such as _u32/_s32.
197 std::string getMangledName() const { return mangleName(ClassS); }
198
199 /// Returns true if the intrinsic is overloaded, in that it should also generate
200 /// a short form without the type-specifiers, e.g. 'svld1(..)' instead of
201 /// 'svld1_u32(..)'.
202 static bool isOverloadedIntrinsic(StringRef Name) {
203 auto BrOpen = Name.find("[");
204 auto BrClose = Name.find(']');
205 return BrOpen != std::string::npos && BrClose != std::string::npos;
206 }
207
208 /// Emits the intrinsic declaration to the ostream.
209 void emitIntrinsic(raw_ostream &OS) const;
210
211private:
212 std::string getMergeSuffix() const;
213 std::string mangleName(ClassKind LocalCK) const;
214 std::string replaceTemplatedArgs(std::string Name, TypeSpec TS,
215 std::string Proto) const;
216};
217
218class SVEEmitter {
219private:
220 RecordKeeper &Records;
221 llvm::StringMap<uint64_t> EltTypes;
222 llvm::StringMap<uint64_t> MemEltTypes;
223 llvm::StringMap<uint64_t> FlagTypes;
224
225 unsigned getTypeFlags(const SVEType &T);
226public:
227 SVEEmitter(RecordKeeper &R) : Records(R) {
228 for (auto *RV : Records.getAllDerivedDefinitions("EltType"))
229 EltTypes[RV->getNameInitAsString()] = RV->getValueAsInt("Value");
230 for (auto *RV : Records.getAllDerivedDefinitions("MemEltType"))
231 MemEltTypes[RV->getNameInitAsString()] = RV->getValueAsInt("Value");
232 for (auto *RV : Records.getAllDerivedDefinitions("FlagType"))
233 FlagTypes[RV->getNameInitAsString()] = RV->getValueAsInt("Value");
234 }
235
236 /// Emit arm_sve.h.
237 void createHeader(raw_ostream &o);
238
239 /// Emit all the __builtin prototypes and code needed by Sema.
240 void createBuiltins(raw_ostream &o);
241
242 /// Emit all the information needed to map builtin -> LLVM IR intrinsic.
243 void createCodeGenMap(raw_ostream &o);
244
245 /// Create the SVETypeFlags used in CGBuiltins
246 void createTypeFlags(raw_ostream &o);
247
248 /// Create intrinsic and add it to \p Out
249 void createIntrinsic(Record *R, SmallVectorImpl<std::unique_ptr<Intrinsic>> &Out);
Sander de Smalen5087ace2020-03-15 14:29:45 +0000250};
251
252} // end anonymous namespace
253
254
255//===----------------------------------------------------------------------===//
Sander de Smalenc5b81462020-03-18 11:07:20 +0000256// Type implementation
Sander de Smalen8b409ea2020-03-16 10:14:05 +0000257//===----------------------------------------------------------------------===//
Sander de Smalen8b409ea2020-03-16 10:14:05 +0000258
Sander de Smalenc5b81462020-03-18 11:07:20 +0000259unsigned SVEEmitter::getTypeFlags(const SVEType &T) {
260 unsigned FirstEltType = EltTypes["FirstEltType"];
261 if (T.isFloat()) {
262 switch (T.getElementSizeInBits()) {
263 case 16: return FirstEltType + EltTypes["EltTyFloat16"];
264 case 32: return FirstEltType + EltTypes["EltTyFloat32"];
265 case 64: return FirstEltType + EltTypes["EltTyFloat64"];
266 default: llvm_unreachable("Unhandled float element bitwidth!");
267 }
268 }
269
270 if (T.isPredicateVector()) {
271 switch (T.getElementSizeInBits()) {
272 case 8: return FirstEltType + EltTypes["EltTyBool8"];
273 case 16: return FirstEltType + EltTypes["EltTyBool16"];
274 case 32: return FirstEltType + EltTypes["EltTyBool32"];
275 case 64: return FirstEltType + EltTypes["EltTyBool64"];
276 default: llvm_unreachable("Unhandled predicate element bitwidth!");
277 }
278 }
279
280 switch (T.getElementSizeInBits()) {
281 case 8: return FirstEltType + EltTypes["EltTyInt8"];
282 case 16: return FirstEltType + EltTypes["EltTyInt16"];
283 case 32: return FirstEltType + EltTypes["EltTyInt32"];
284 case 64: return FirstEltType + EltTypes["EltTyInt64"];
285 default: llvm_unreachable("Unhandled integer element bitwidth!");
286 }
287}
288
289std::string SVEType::builtin_str() const {
290 std::string S;
291 if (isVoid())
292 return "v";
293
294 if (isVoidPointer())
295 S += "v";
296 else if (!Float)
297 switch (ElementBitwidth) {
298 case 1: S += "b"; break;
299 case 8: S += "c"; break;
300 case 16: S += "s"; break;
301 case 32: S += "i"; break;
302 case 64: S += "Wi"; break;
303 case 128: S += "LLLi"; break;
304 default: llvm_unreachable("Unhandled case!");
305 }
306 else
307 switch (ElementBitwidth) {
308 case 16: S += "h"; break;
309 case 32: S += "f"; break;
310 case 64: S += "d"; break;
311 default: llvm_unreachable("Unhandled case!");
312 }
313
314 if (!isFloat()) {
315 if ((isChar() || isPointer()) && !isVoidPointer()) {
316 // Make chars and typed pointers explicitly signed.
317 if (Signed)
318 S = "S" + S;
319 else if (!Signed)
320 S = "U" + S;
321 } else if (!isVoidPointer() && !Signed) {
322 S = "U" + S;
323 }
324 }
325
326 // Constant indices are "int", but have the "constant expression" modifier.
327 if (isImmediate()) {
328 assert(!isFloat() && "fp immediates are not supported");
329 S = "I" + S;
330 }
331
332 if (isScalar()) {
333 if (Constant) S += "C";
334 if (Pointer) S += "*";
335 return S;
336 }
337
338 assert(isScalableVector() && "Unsupported type");
339 return "q" + utostr(getNumElements() * NumVectors) + S;
340}
341
Sander de Smalen981f0802020-03-18 15:05:08 +0000342std::string SVEType::str() const {
343 if (isPredicatePattern())
344 return "sv_pattern";
345
346 if (isPrefetchOp())
347 return "sv_prfop";
348
349 std::string S;
350 if (Void)
351 S += "void";
352 else {
353 if (isScalableVector())
354 S += "sv";
355 if (!Signed && !Float)
356 S += "u";
357
358 if (Float)
359 S += "float";
360 else if (isScalarPredicate())
361 S += "bool";
362 else
363 S += "int";
364
365 if (!isScalarPredicate())
366 S += utostr(ElementBitwidth);
367 if (!isScalableVector() && isVector())
368 S += "x" + utostr(getNumElements());
369 if (NumVectors > 1)
370 S += "x" + utostr(NumVectors);
371 S += "_t";
372 }
373
374 if (Constant)
375 S += " const";
376 if (Pointer)
377 S += " *";
378
379 return S;
380}
Sander de Smalenc5b81462020-03-18 11:07:20 +0000381void SVEType::applyTypespec() {
382 for (char I : TS) {
383 switch (I) {
384 case 'P':
385 Predicate = true;
386 ElementBitwidth = 1;
387 break;
388 case 'U':
389 Signed = false;
390 break;
391 case 'c':
392 ElementBitwidth = 8;
393 break;
394 case 's':
395 ElementBitwidth = 16;
396 break;
397 case 'i':
398 ElementBitwidth = 32;
399 break;
400 case 'l':
401 ElementBitwidth = 64;
402 break;
403 case 'h':
404 Float = true;
405 ElementBitwidth = 16;
406 break;
407 case 'f':
408 Float = true;
409 ElementBitwidth = 32;
410 break;
411 case 'd':
412 Float = true;
413 ElementBitwidth = 64;
414 break;
415 default:
416 llvm_unreachable("Unhandled type code!");
417 }
418 }
419 assert(ElementBitwidth != ~0U && "Bad element bitwidth!");
420}
421
422void SVEType::applyModifier(char Mod) {
423 switch (Mod) {
424 case 'v':
425 Void = true;
426 break;
427 case 'd':
428 DefaultType = true;
429 break;
430 case 'c':
431 Constant = true;
432 LLVM_FALLTHROUGH;
433 case 'p':
434 Pointer = true;
435 Bitwidth = ElementBitwidth;
436 NumVectors = 0;
437 break;
438 case 'P':
439 Signed = true;
440 Float = false;
441 Predicate = true;
442 Bitwidth = 16;
443 ElementBitwidth = 1;
444 break;
Sander de Smalen17a68c62020-04-14 13:17:52 +0100445 case 'l':
446 Predicate = false;
447 Signed = true;
448 Float = false;
449 ElementBitwidth = Bitwidth = 64;
450 NumVectors = 0;
451 break;
452 case 'S':
453 Constant = true;
454 Pointer = true;
455 ElementBitwidth = Bitwidth = 8;
456 NumVectors = 0;
457 Signed = true;
458 break;
459 case 'W':
460 Constant = true;
461 Pointer = true;
462 ElementBitwidth = Bitwidth = 8;
463 NumVectors = 0;
464 Signed = false;
465 break;
466 case 'T':
467 Constant = true;
468 Pointer = true;
469 ElementBitwidth = Bitwidth = 16;
470 NumVectors = 0;
471 Signed = true;
472 break;
473 case 'X':
474 Constant = true;
475 Pointer = true;
476 ElementBitwidth = Bitwidth = 16;
477 NumVectors = 0;
478 Signed = false;
479 break;
480 case 'Y':
481 Constant = true;
482 Pointer = true;
483 ElementBitwidth = Bitwidth = 32;
484 NumVectors = 0;
485 Signed = false;
486 break;
487 case 'U':
488 Constant = true;
489 Pointer = true;
490 ElementBitwidth = Bitwidth = 32;
491 NumVectors = 0;
492 Signed = true;
493 break;
494 case 'A':
495 Pointer = true;
496 ElementBitwidth = Bitwidth = 8;
497 NumVectors = 0;
498 Signed = true;
499 break;
500 case 'B':
501 Pointer = true;
502 ElementBitwidth = Bitwidth = 16;
503 NumVectors = 0;
504 Signed = true;
505 break;
506 case 'C':
507 Pointer = true;
508 ElementBitwidth = Bitwidth = 32;
509 NumVectors = 0;
510 Signed = true;
511 break;
512 case 'D':
513 Pointer = true;
514 ElementBitwidth = Bitwidth = 64;
515 NumVectors = 0;
516 Signed = true;
517 break;
518 case 'E':
519 Pointer = true;
520 ElementBitwidth = Bitwidth = 8;
521 NumVectors = 0;
522 Signed = false;
523 break;
524 case 'F':
525 Pointer = true;
526 ElementBitwidth = Bitwidth = 16;
527 NumVectors = 0;
528 Signed = false;
529 break;
530 case 'G':
531 Pointer = true;
532 ElementBitwidth = Bitwidth = 32;
533 NumVectors = 0;
534 Signed = false;
535 break;
Sander de Smalenc5b81462020-03-18 11:07:20 +0000536 default:
537 llvm_unreachable("Unhandled character!");
538 }
539}
540
541
542//===----------------------------------------------------------------------===//
543// Intrinsic implementation
544//===----------------------------------------------------------------------===//
545
546std::string Intrinsic::getBuiltinTypeStr() {
547 std::string S;
548
549 SVEType RetT = getReturnType();
550 // Since the return value must be one type, return a vector type of the
551 // appropriate width which we will bitcast. An exception is made for
552 // returning structs of 2, 3, or 4 vectors which are returned in a sret-like
553 // fashion, storing them to a pointer arg.
554 if (RetT.getNumVectors() > 1) {
555 S += "vv*"; // void result with void* first argument
556 } else
557 S += RetT.builtin_str();
558
559 for (unsigned I = 0; I < getNumParams(); ++I)
560 S += getParamType(I).builtin_str();
561
562 return S;
563}
564
565std::string Intrinsic::replaceTemplatedArgs(std::string Name, TypeSpec TS,
566 std::string Proto) const {
567 std::string Ret = Name;
568 while (Ret.find('{') != std::string::npos) {
569 size_t Pos = Ret.find('{');
570 size_t End = Ret.find('}');
571 unsigned NumChars = End - Pos + 1;
572 assert(NumChars == 3 && "Unexpected template argument");
573
574 SVEType T;
575 char C = Ret[Pos+1];
576 switch(C) {
577 default:
578 llvm_unreachable("Unknown predication specifier");
579 case 'd':
580 T = SVEType(TS, 'd');
581 break;
582 case '0':
583 case '1':
584 case '2':
585 case '3':
586 T = SVEType(TS, Proto[C - '0']);
587 break;
588 }
589
590 // Replace templated arg with the right suffix (e.g. u32)
591 std::string TypeCode;
592 if (T.isInteger())
593 TypeCode = T.isSigned() ? 's' : 'u';
594 else if (T.isPredicateVector())
595 TypeCode = 'b';
596 else
597 TypeCode = 'f';
598 Ret.replace(Pos, NumChars, TypeCode + utostr(T.getElementSizeInBits()));
599 }
600
601 return Ret;
602}
603
604// ACLE function names have a merge style postfix.
605std::string Intrinsic::getMergeSuffix() const {
606 switch (getMergeType()) {
607 default:
608 llvm_unreachable("Unknown predication specifier");
609 case MergeNone: return "";
610 case MergeAny:
611 case MergeAnyExp: return "_x";
612 case MergeOp1: return "_m";
613 case MergeZero:
614 case MergeZeroExp: return "_z";
615 }
616}
617
618std::string Intrinsic::mangleName(ClassKind LocalCK) const {
619 std::string S = getName();
620
621 if (LocalCK == ClassG) {
622 // Remove the square brackets and everything in between.
623 while (S.find("[") != std::string::npos) {
624 auto Start = S.find("[");
625 auto End = S.find(']');
626 S.erase(Start, (End-Start)+1);
627 }
628 } else {
629 // Remove the square brackets.
630 while (S.find("[") != std::string::npos) {
631 auto BrPos = S.find('[');
632 if (BrPos != std::string::npos)
633 S.erase(BrPos, 1);
634 BrPos = S.find(']');
635 if (BrPos != std::string::npos)
636 S.erase(BrPos, 1);
637 }
638 }
639
640 // Replace all {d} like expressions with e.g. 'u32'
641 return replaceTemplatedArgs(S, getBaseTypeSpec(), getProto()) +
642 getMergeSuffix();
643}
644
645void Intrinsic::emitIntrinsic(raw_ostream &OS) const {
646 // Use the preprocessor to
647 if (getClassKind() != ClassG || getProto().size() <= 1) {
648 OS << "#define " << mangleName(getClassKind())
649 << "(...) __builtin_sve_" << mangleName(ClassS)
650 << "(__VA_ARGS__)\n";
651 } else {
Sander de Smalen981f0802020-03-18 15:05:08 +0000652 std::string FullName = mangleName(ClassS);
653 std::string ProtoName = mangleName(ClassG);
654
655 OS << "__aio __attribute__((__clang_arm_builtin_alias("
656 << "__builtin_sve_" << FullName << ")))\n";
657
658 OS << getTypes()[0].str() << " " << ProtoName << "(";
659 for (unsigned I = 0; I < getTypes().size() - 1; ++I) {
660 if (I != 0)
661 OS << ", ";
662 OS << getTypes()[I + 1].str();
663 }
664 OS << ");\n";
Sander de Smalenc5b81462020-03-18 11:07:20 +0000665 }
666}
667
668//===----------------------------------------------------------------------===//
669// SVEEmitter implementation
670//===----------------------------------------------------------------------===//
671void SVEEmitter::createIntrinsic(
672 Record *R, SmallVectorImpl<std::unique_ptr<Intrinsic>> &Out) {
673 StringRef Name = R->getValueAsString("Name");
674 StringRef Proto = R->getValueAsString("Prototype");
675 StringRef Types = R->getValueAsString("Types");
676 StringRef Guard = R->getValueAsString("ArchGuard");
677 StringRef LLVMName = R->getValueAsString("LLVMIntrinsic");
678 int64_t Merge = R->getValueAsInt("Merge");
679 std::vector<Record*> FlagsList = R->getValueAsListOfDefs("Flags");
680
681 int64_t Flags = 0;
682 for (auto FlagRec : FlagsList)
683 Flags |= FlagRec->getValueAsInt("Value");
684 Flags |= R->getValueAsInt("MemEltType") + MemEltTypes["FirstMemEltType"];
685
686 // Extract type specs from string
687 SmallVector<TypeSpec, 8> TypeSpecs;
688 TypeSpec Acc;
689 for (char I : Types) {
690 Acc.push_back(I);
691 if (islower(I)) {
692 TypeSpecs.push_back(TypeSpec(Acc));
693 Acc.clear();
694 }
695 }
696
697 // Remove duplicate type specs.
Benjamin Kramer4065e922020-03-28 19:19:55 +0100698 llvm::sort(TypeSpecs);
Sander de Smalenc5b81462020-03-18 11:07:20 +0000699 TypeSpecs.erase(std::unique(TypeSpecs.begin(), TypeSpecs.end()),
700 TypeSpecs.end());
701
702 // Create an Intrinsic for each type spec.
703 for (auto TS : TypeSpecs) {
704 Out.push_back(std::make_unique<Intrinsic>(Name, Proto, Merge,
705 LLVMName, Flags, TS, ClassS,
706 *this, Guard));
Sander de Smalen981f0802020-03-18 15:05:08 +0000707
708 // Also generate the short-form (e.g. svadd_m) for the given type-spec.
709 if (Intrinsic::isOverloadedIntrinsic(Name))
710 Out.push_back(std::make_unique<Intrinsic>(
711 Name, Proto, Merge, LLVMName, Flags, TS, ClassG, *this, Guard));
Sander de Smalenc5b81462020-03-18 11:07:20 +0000712 }
713}
714
715void SVEEmitter::createHeader(raw_ostream &OS) {
Sander de Smalen5087ace2020-03-15 14:29:45 +0000716 OS << "/*===---- arm_sve.h - ARM SVE intrinsics "
717 "-----------------------------------===\n"
718 " *\n"
719 " *\n"
720 " * Part of the LLVM Project, under the Apache License v2.0 with LLVM "
721 "Exceptions.\n"
722 " * See https://llvm.org/LICENSE.txt for license information.\n"
723 " * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception\n"
724 " *\n"
725 " *===-----------------------------------------------------------------"
726 "------===\n"
727 " */\n\n";
728
729 OS << "#ifndef __ARM_SVE_H\n";
730 OS << "#define __ARM_SVE_H\n\n";
731
732 OS << "#if !defined(__ARM_FEATURE_SVE)\n";
733 OS << "#error \"SVE support not enabled\"\n";
734 OS << "#else\n\n";
735
736 OS << "#include <stdint.h>\n\n";
Sander de Smalenc5b81462020-03-18 11:07:20 +0000737 OS << "#ifdef __cplusplus\n";
738 OS << "extern \"C\" {\n";
739 OS << "#else\n";
Sander de Smalen5087ace2020-03-15 14:29:45 +0000740 OS << "#include <stdbool.h>\n";
741 OS << "#endif\n\n";
742
743 OS << "typedef __fp16 float16_t;\n";
744 OS << "typedef float float32_t;\n";
745 OS << "typedef double float64_t;\n";
746 OS << "typedef bool bool_t;\n\n";
747
748 OS << "typedef __SVInt8_t svint8_t;\n";
749 OS << "typedef __SVInt16_t svint16_t;\n";
750 OS << "typedef __SVInt32_t svint32_t;\n";
751 OS << "typedef __SVInt64_t svint64_t;\n";
752 OS << "typedef __SVUint8_t svuint8_t;\n";
753 OS << "typedef __SVUint16_t svuint16_t;\n";
754 OS << "typedef __SVUint32_t svuint32_t;\n";
755 OS << "typedef __SVUint64_t svuint64_t;\n";
756 OS << "typedef __SVFloat16_t svfloat16_t;\n";
757 OS << "typedef __SVFloat32_t svfloat32_t;\n";
758 OS << "typedef __SVFloat64_t svfloat64_t;\n";
759 OS << "typedef __SVBool_t svbool_t;\n\n";
760
Sander de Smalen981f0802020-03-18 15:05:08 +0000761 OS << "/* Function attributes */\n";
762 OS << "#define __aio static inline __attribute__((__always_inline__, "
763 "__nodebug__, __overloadable__))\n\n";
764
Sander de Smalenc5b81462020-03-18 11:07:20 +0000765 SmallVector<std::unique_ptr<Intrinsic>, 128> Defs;
766 std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst");
767 for (auto *R : RV)
768 createIntrinsic(R, Defs);
Sander de Smalen5087ace2020-03-15 14:29:45 +0000769
Sander de Smalenc5b81462020-03-18 11:07:20 +0000770 // Sort intrinsics in header file by following order/priority:
771 // - Architectural guard (i.e. does it require SVE2 or SVE2_AES)
772 // - Class (is intrinsic overloaded or not)
773 // - Intrinsic name
774 std::stable_sort(
775 Defs.begin(), Defs.end(), [](const std::unique_ptr<Intrinsic> &A,
776 const std::unique_ptr<Intrinsic> &B) {
777 return A->getGuard() < B->getGuard() ||
778 (unsigned)A->getClassKind() < (unsigned)B->getClassKind() ||
779 A->getName() < B->getName();
780 });
781
782 StringRef InGuard = "";
783 for (auto &I : Defs) {
784 // Emit #endif/#if pair if needed.
785 if (I->getGuard() != InGuard) {
786 if (!InGuard.empty())
787 OS << "#endif //" << InGuard << "\n";
788 InGuard = I->getGuard();
789 if (!InGuard.empty())
790 OS << "\n#if " << InGuard << "\n";
791 }
792
793 // Actually emit the intrinsic declaration.
794 I->emitIntrinsic(OS);
795 }
796
797 if (!InGuard.empty())
798 OS << "#endif //" << InGuard << "\n";
799
800 OS << "#ifdef __cplusplus\n";
801 OS << "} // extern \"C\"\n";
802 OS << "#endif\n\n";
803 OS << "#endif /*__ARM_FEATURE_SVE */\n\n";
Sander de Smalen5087ace2020-03-15 14:29:45 +0000804 OS << "#endif /* __ARM_SVE_H */\n";
805}
806
Sander de Smalenc5b81462020-03-18 11:07:20 +0000807void SVEEmitter::createBuiltins(raw_ostream &OS) {
808 std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst");
809 SmallVector<std::unique_ptr<Intrinsic>, 128> Defs;
810 for (auto *R : RV)
811 createIntrinsic(R, Defs);
812
813 // The mappings must be sorted based on BuiltinID.
814 llvm::sort(Defs, [](const std::unique_ptr<Intrinsic> &A,
815 const std::unique_ptr<Intrinsic> &B) {
816 return A->getMangledName() < B->getMangledName();
817 });
818
819 OS << "#ifdef GET_SVE_BUILTINS\n";
820 for (auto &Def : Defs) {
821 // Only create BUILTINs for non-overloaded intrinsics, as overloaded
822 // declarations only live in the header file.
823 if (Def->getClassKind() != ClassG)
824 OS << "BUILTIN(__builtin_sve_" << Def->getMangledName() << ", \""
825 << Def->getBuiltinTypeStr() << "\", \"n\")\n";
826 }
827 OS << "#endif\n\n";
828}
829
830void SVEEmitter::createCodeGenMap(raw_ostream &OS) {
831 std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst");
832 SmallVector<std::unique_ptr<Intrinsic>, 128> Defs;
833 for (auto *R : RV)
834 createIntrinsic(R, Defs);
835
836 // The mappings must be sorted based on BuiltinID.
837 llvm::sort(Defs, [](const std::unique_ptr<Intrinsic> &A,
838 const std::unique_ptr<Intrinsic> &B) {
839 return A->getMangledName() < B->getMangledName();
840 });
841
842 OS << "#ifdef GET_SVE_LLVM_INTRINSIC_MAP\n";
843 for (auto &Def : Defs) {
844 // Builtins only exist for non-overloaded intrinsics, overloaded
845 // declarations only live in the header file.
846 if (Def->getClassKind() == ClassG)
847 continue;
848
849 uint64_t Flags = Def->getFlags() | getTypeFlags(Def->getBaseType());
850 auto FlagString = std::to_string(Flags);
851
852 std::string LLVMName = Def->getLLVMName();
853 std::string Builtin = Def->getMangledName();
854 if (!LLVMName.empty())
855 OS << "SVEMAP1(" << Builtin << ", " << LLVMName << ", " << FlagString
856 << "),\n";
857 else
858 OS << "SVEMAP2(" << Builtin << ", " << FlagString << "),\n";
859 }
860 OS << "#endif\n\n";
861}
862
863/// Create the SVETypeFlags used in CGBuiltins
864void SVEEmitter::createTypeFlags(raw_ostream &OS) {
865 OS << "#ifdef LLVM_GET_SVE_TYPEFLAGS\n";
866 for (auto &KV : FlagTypes)
867 OS << "const uint64_t " << KV.getKey() << " = " << KV.getValue() << ";\n";
868 OS << "#endif\n\n";
869
870 OS << "#ifdef LLVM_GET_SVE_ELTTYPES\n";
871 for (auto &KV : EltTypes)
872 OS << " " << KV.getKey() << " = " << KV.getValue() << ",\n";
873 OS << "#endif\n\n";
874
875 OS << "#ifdef LLVM_GET_SVE_MEMELTTYPES\n";
876 for (auto &KV : MemEltTypes)
877 OS << " " << KV.getKey() << " = " << KV.getValue() << ",\n";
878 OS << "#endif\n\n";
879}
880
Sander de Smalen5087ace2020-03-15 14:29:45 +0000881namespace clang {
882void EmitSveHeader(RecordKeeper &Records, raw_ostream &OS) {
Sander de Smalenc5b81462020-03-18 11:07:20 +0000883 SVEEmitter(Records).createHeader(OS);
884}
885
886void EmitSveBuiltins(RecordKeeper &Records, raw_ostream &OS) {
887 SVEEmitter(Records).createBuiltins(OS);
888}
889
890void EmitSveBuiltinCG(RecordKeeper &Records, raw_ostream &OS) {
891 SVEEmitter(Records).createCodeGenMap(OS);
892}
893void EmitSveTypeFlags(RecordKeeper &Records, raw_ostream &OS) {
894 SVEEmitter(Records).createTypeFlags(OS);
Sander de Smalen5087ace2020-03-15 14:29:45 +0000895}
896
897} // End namespace clang