blob: 1f342df74a914a4ff6b3875ef7b31551644a7482 [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"
27#include "llvm/ADT/DenseMap.h"
28#include "llvm/ADT/ArrayRef.h"
29#include "llvm/ADT/StringExtras.h"
30#include "llvm/TableGen/Record.h"
31#include "llvm/TableGen/Error.h"
Sander de Smalen8b409ea2020-03-16 10:14:05 +000032#include "clang/Basic/AArch64SVETypeFlags.h"
Sander de Smalen5087ace2020-03-15 14:29:45 +000033#include <string>
34#include <sstream>
35#include <set>
36#include <cctype>
37
38using namespace llvm;
39
Sander de Smalen8b409ea2020-03-16 10:14:05 +000040enum ClassKind {
41 ClassNone,
42 ClassS, // signed/unsigned, e.g., "_s8", "_u8" suffix
43 ClassG, // Overloaded name without type suffix
44};
45
46using TypeSpec = std::string;
47using SVETypeFlags = clang::SVETypeFlags;
Sander de Smalen5087ace2020-03-15 14:29:45 +000048
49namespace {
50
Sander de Smalen8b409ea2020-03-16 10:14:05 +000051class SVEType {
52 TypeSpec TS;
53 bool Float, Signed, Immediate, Void, Constant, Pointer;
54 bool DefaultType, IsScalable, Predicate, PredicatePattern, PrefetchOp;
55 unsigned Bitwidth, ElementBitwidth, NumVectors;
56
Sander de Smalen5087ace2020-03-15 14:29:45 +000057public:
Sander de Smalen8b409ea2020-03-16 10:14:05 +000058 SVEType() : SVEType(TypeSpec(), 'v') {}
59
60 SVEType(TypeSpec TS, char CharMod)
61 : TS(TS), Float(false), Signed(true), Immediate(false), Void(false),
62 Constant(false), Pointer(false), DefaultType(false), IsScalable(true),
63 Predicate(false), PredicatePattern(false), PrefetchOp(false),
64 Bitwidth(128), ElementBitwidth(~0U), NumVectors(1) {
65 if (!TS.empty())
66 applyTypespec();
67 applyModifier(CharMod);
68 }
69
70 /// Return the value in SVETypeFlags for this type.
71 unsigned getTypeFlags() const;
72
73 bool isPointer() const { return Pointer; }
74 bool isVoidPointer() const { return Pointer && Void; }
75 bool isSigned() const { return Signed; }
76 bool isImmediate() const { return Immediate; }
77 bool isScalar() const { return NumVectors == 0; }
78 bool isVector() const { return NumVectors > 0; }
79 bool isScalableVector() const { return isVector() && IsScalable; }
80 bool isChar() const { return ElementBitwidth == 8; }
81 bool isVoid() const { return Void & !Pointer; }
82 bool isDefault() const { return DefaultType; }
83 bool isFloat() const { return Float; }
84 bool isInteger() const { return !Float && !Predicate; }
85 bool isScalarPredicate() const { return !Float && ElementBitwidth == 1; }
86 bool isPredicateVector() const { return Predicate; }
87 bool isPredicatePattern() const { return PredicatePattern; }
88 bool isPrefetchOp() const { return PrefetchOp; }
89 bool isConstant() const { return Constant; }
90 unsigned getElementSizeInBits() const { return ElementBitwidth; }
91 unsigned getNumVectors() const { return NumVectors; }
92
93 unsigned getNumElements() const {
94 assert(ElementBitwidth != ~0U);
95 return Bitwidth / ElementBitwidth;
96 }
97 unsigned getSizeInBits() const {
98 return Bitwidth;
99 }
100
101 /// Return the string representation of a type, which is an encoded
102 /// string for passing to the BUILTIN() macro in Builtins.def.
103 std::string builtin_str() const;
104
105private:
106 /// Creates the type based on the typespec string in TS.
107 void applyTypespec();
108
109 /// Applies a prototype modifier to the type.
110 void applyModifier(char Mod);
111};
112
113
114class SVEEmitter;
115
116/// The main grunt class. This represents an instantiation of an intrinsic with
117/// a particular typespec and prototype.
118class Intrinsic {
119 /// The unmangled name.
120 std::string Name;
121
122 /// The name of the corresponding LLVM IR intrinsic.
123 std::string LLVMName;
124
125 /// Intrinsic prototype.
126 std::string Proto;
127
128 /// The base type spec for this intrinsic.
129 TypeSpec BaseTypeSpec;
130
131 /// The base class kind. Most intrinsics use ClassS, which has full type
132 /// info for integers (_s32/_u32), or ClassG which is used for overloaded
133 /// intrinsics.
134 ClassKind Class;
135
136 /// The architectural #ifdef guard.
137 std::string Guard;
138
139 /// The types of return value [0] and parameters [1..].
140 std::vector<SVEType> Types;
141
142 /// The "base type", which is VarType('d', BaseTypeSpec).
143 SVEType BaseType;
144
145 /// The type of the memory element
146 enum MemEltType {
147 MemEltTypeDefault,
148 MemEltTypeInt8,
149 MemEltTypeInt16,
150 MemEltTypeInt32,
151 MemEltTypeInt64,
152 MemEltTypeInvalid
153 } MemEltTy;
154
155 SVETypeFlags Flags;
156
157public:
158 /// The type of predication.
159 enum MergeType {
160 MergeNone,
161 MergeAny,
162 MergeOp1,
163 MergeZero,
164 MergeAnyExp,
165 MergeZeroExp,
166 MergeInvalid
167 } Merge;
168
169 Intrinsic(StringRef Name, StringRef Proto, int64_t MT, int64_t MET,
170 StringRef LLVMName, SVETypeFlags Flags, TypeSpec BT, ClassKind Class,
171 SVEEmitter &Emitter, StringRef Guard)
172 : Name(Name.str()), LLVMName(LLVMName), Proto(Proto.str()),
173 BaseTypeSpec(BT), Class(Class), Guard(Guard.str()), BaseType(BT, 'd'),
174 MemEltTy(MemEltType(MET)), Flags(Flags), Merge(MergeType(MT)) {
175 // Types[0] is the return value.
176 for (unsigned I = 0; I < Proto.size(); ++I)
177 Types.emplace_back(BaseTypeSpec, Proto[I]);
178 }
179
180 ~Intrinsic()=default;
181
182 std::string getName() const { return Name; }
183 std::string getLLVMName() const { return LLVMName; }
184 std::string getProto() const { return Proto; }
185 TypeSpec getBaseTypeSpec() const { return BaseTypeSpec; }
186 SVEType getBaseType() const { return BaseType; }
187
188 StringRef getGuard() const { return Guard; }
189 ClassKind getClassKind() const { return Class; }
190 MergeType getMergeType() const { return Merge; }
191
192 SVEType getReturnType() const { return Types[0]; }
193 ArrayRef<SVEType> getTypes() const { return Types; }
194 SVEType getParamType(unsigned I) const { return Types[I + 1]; }
195 unsigned getNumParams() const { return Proto.size() - 1; }
196
197 SVETypeFlags getFlags() const { return Flags; }
198 bool isFlagSet(uint64_t Flag) const { return Flags.isFlagSet(Flag);}
199
200 int64_t getMemEltTypeEnum() const {
201 int64_t METEnum = (MemEltTy << SVETypeFlags::MemEltTypeOffset);
202 assert((METEnum &~ SVETypeFlags::MemEltTypeMask) == 0 && "Bad MemEltTy");
203 return METEnum;
204 }
205
206 /// Return the type string for a BUILTIN() macro in Builtins.def.
207 std::string getBuiltinTypeStr();
208
209 /// Return the name, mangled with type information. The name is mangled for
210 /// ClassS, so will add type suffixes such as _u32/_s32.
211 std::string getMangledName() const { return mangleName(ClassS); }
212
213 /// Returns true if the intrinsic is overloaded, in that it should also generate
214 /// a short form without the type-specifiers, e.g. 'svld1(..)' instead of
215 /// 'svld1_u32(..)'.
216 static bool isOverloadedIntrinsic(StringRef Name) {
217 auto BrOpen = Name.find("[");
218 auto BrClose = Name.find(']');
219 return BrOpen != std::string::npos && BrClose != std::string::npos;
220 }
221
222 /// Emits the intrinsic declaration to the ostream.
223 void emitIntrinsic(raw_ostream &OS) const;
224
225private:
226 std::string getMergeSuffix() const;
227 std::string mangleName(ClassKind LocalCK) const;
228 std::string replaceTemplatedArgs(std::string Name, TypeSpec TS,
229 std::string Proto) const;
230};
231
232class SVEEmitter {
233private:
234 RecordKeeper &Records;
235
236public:
237 SVEEmitter(RecordKeeper &R) : Records(R) {}
238
239 /// Emit arm_sve.h.
240 void createHeader(raw_ostream &o);
241
242 /// Emit all the __builtin prototypes and code needed by Sema.
243 void createBuiltins(raw_ostream &o);
244
245 /// Emit all the information needed to map builtin -> LLVM IR intrinsic.
246 void createCodeGenMap(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 Smalen8b409ea2020-03-16 10:14:05 +0000256// Type implementation
Sander de Smalen5087ace2020-03-15 14:29:45 +0000257//===----------------------------------------------------------------------===//
258
Sander de Smalen8b409ea2020-03-16 10:14:05 +0000259unsigned SVEType::getTypeFlags() const {
260 if (isFloat()) {
261 switch (ElementBitwidth) {
262 case 16: return SVETypeFlags::Float16;
263 case 32: return SVETypeFlags::Float32;
264 case 64: return SVETypeFlags::Float64;
265 default: llvm_unreachable("Unhandled float element bitwidth!");
266 }
267 }
268
269 if (isPredicateVector()) {
270 switch (ElementBitwidth) {
271 case 8: return SVETypeFlags::Bool8;
272 case 16: return SVETypeFlags::Bool16;
273 case 32: return SVETypeFlags::Bool32;
274 case 64: return SVETypeFlags::Bool64;
275 default: llvm_unreachable("Unhandled predicate element bitwidth!");
276 }
277 }
278
279 switch (ElementBitwidth) {
280 case 8: return SVETypeFlags::Int8;
281 case 16: return SVETypeFlags::Int16;
282 case 32: return SVETypeFlags::Int32;
283 case 64: return SVETypeFlags::Int64;
284 default: llvm_unreachable("Unhandled integer element bitwidth!");
285 }
286}
287
288std::string SVEType::builtin_str() const {
289 std::string S;
290 if (isVoid())
291 return "v";
292
293 if (isVoidPointer())
294 S += "v";
295 else if (!Float)
296 switch (ElementBitwidth) {
297 case 1: S += "b"; break;
298 case 8: S += "c"; break;
299 case 16: S += "s"; break;
300 case 32: S += "i"; break;
301 case 64: S += "Wi"; break;
302 case 128: S += "LLLi"; break;
303 default: llvm_unreachable("Unhandled case!");
304 }
305 else
306 switch (ElementBitwidth) {
307 case 16: S += "h"; break;
308 case 32: S += "f"; break;
309 case 64: S += "d"; break;
310 default: llvm_unreachable("Unhandled case!");
311 }
312
313 if (!isFloat()) {
314 if ((isChar() || isPointer()) && !isVoidPointer()) {
315 // Make chars and typed pointers explicitly signed.
316 if (Signed)
317 S = "S" + S;
318 else if (!Signed)
319 S = "U" + S;
320 } else if (!isVoidPointer() && !Signed) {
321 S = "U" + S;
322 }
323 }
324
325 // Constant indices are "int", but have the "constant expression" modifier.
326 if (isImmediate()) {
327 assert(!isFloat() && "fp immediates are not supported");
328 S = "I" + S;
329 }
330
331 if (isScalar()) {
332 if (Constant) S += "C";
333 if (Pointer) S += "*";
334 return S;
335 }
336
337 assert(isScalableVector() && "Unsupported type");
338 return "q" + utostr(getNumElements() * NumVectors) + S;
339}
340
341void SVEType::applyTypespec() {
342 for (char I : TS) {
343 switch (I) {
344 case 'P':
345 Predicate = true;
346 ElementBitwidth = 1;
347 break;
348 case 'U':
349 Signed = false;
350 break;
351 case 'c':
352 ElementBitwidth = 8;
353 break;
354 case 's':
355 ElementBitwidth = 16;
356 break;
357 case 'i':
358 ElementBitwidth = 32;
359 break;
360 case 'l':
361 ElementBitwidth = 64;
362 break;
363 case 'h':
364 Float = true;
365 ElementBitwidth = 16;
366 break;
367 case 'f':
368 Float = true;
369 ElementBitwidth = 32;
370 break;
371 case 'd':
372 Float = true;
373 ElementBitwidth = 64;
374 break;
375 default:
376 llvm_unreachable("Unhandled type code!");
377 }
378 }
379 assert(ElementBitwidth != ~0U && "Bad element bitwidth!");
380}
381
382void SVEType::applyModifier(char Mod) {
383 switch (Mod) {
384 case 'v':
385 Void = true;
386 break;
387 case 'd':
388 DefaultType = true;
389 break;
390 case 'c':
391 Constant = true;
392 LLVM_FALLTHROUGH;
393 case 'p':
394 Pointer = true;
395 Bitwidth = ElementBitwidth;
396 NumVectors = 0;
397 break;
398 case 'P':
399 Signed = true;
400 Float = false;
401 Predicate = true;
402 Bitwidth = 16;
403 ElementBitwidth = 1;
404 break;
405 default:
406 llvm_unreachable("Unhandled character!");
407 }
408}
409
410
411//===----------------------------------------------------------------------===//
412// Intrinsic implementation
413//===----------------------------------------------------------------------===//
414
415std::string Intrinsic::getBuiltinTypeStr() {
416 std::string S;
417
418 SVEType RetT = getReturnType();
419 // Since the return value must be one type, return a vector type of the
420 // appropriate width which we will bitcast. An exception is made for
421 // returning structs of 2, 3, or 4 vectors which are returned in a sret-like
422 // fashion, storing them to a pointer arg.
423 if (RetT.getNumVectors() > 1) {
424 S += "vv*"; // void result with void* first argument
425 } else
426 S += RetT.builtin_str();
427
428 for (unsigned I = 0; I < getNumParams(); ++I)
429 S += getParamType(I).builtin_str();
430
431 return S;
432}
433
434std::string Intrinsic::replaceTemplatedArgs(std::string Name, TypeSpec TS,
435 std::string Proto) const {
436 std::string Ret = Name;
437 while (Ret.find('{') != std::string::npos) {
438 size_t Pos = Ret.find('{');
439 size_t End = Ret.find('}');
440 unsigned NumChars = End - Pos + 1;
441 assert(NumChars == 3 && "Unexpected template argument");
442
443 SVEType T;
444 char C = Ret[Pos+1];
445 switch(C) {
446 default:
447 llvm_unreachable("Unknown predication specifier");
448 case 'd':
449 T = SVEType(TS, 'd');
450 break;
451 case '0':
452 case '1':
453 case '2':
454 case '3':
455 T = SVEType(TS, Proto[C - '0']);
456 break;
457 }
458
459 // Replace templated arg with the right suffix (e.g. u32)
460 std::string TypeCode;
461 if (T.isInteger())
462 TypeCode = T.isSigned() ? 's' : 'u';
463 else if (T.isPredicateVector())
464 TypeCode = 'b';
465 else
466 TypeCode = 'f';
467 Ret.replace(Pos, NumChars, TypeCode + utostr(T.getElementSizeInBits()));
468 }
469
470 return Ret;
471}
472
473// ACLE function names have a merge style postfix.
474std::string Intrinsic::getMergeSuffix() const {
475 switch (getMergeType()) {
476 default:
477 llvm_unreachable("Unknown predication specifier");
478 case MergeNone: return "";
479 case MergeAny:
480 case MergeAnyExp: return "_x";
481 case MergeOp1: return "_m";
482 case MergeZero:
483 case MergeZeroExp: return "_z";
484 }
485}
486
487std::string Intrinsic::mangleName(ClassKind LocalCK) const {
488 std::string S = getName();
489
490 if (LocalCK == ClassG) {
491 // Remove the square brackets and everything in between.
492 while (S.find("[") != std::string::npos) {
493 auto Start = S.find("[");
494 auto End = S.find(']');
495 S.erase(Start, (End-Start)+1);
496 }
497 } else {
498 // Remove the square brackets.
499 while (S.find("[") != std::string::npos) {
500 auto BrPos = S.find('[');
501 if (BrPos != std::string::npos)
502 S.erase(BrPos, 1);
503 BrPos = S.find(']');
504 if (BrPos != std::string::npos)
505 S.erase(BrPos, 1);
506 }
507 }
508
509 // Replace all {d} like expressions with e.g. 'u32'
510 return replaceTemplatedArgs(S, getBaseTypeSpec(), getProto()) +
511 getMergeSuffix();
512}
513
514void Intrinsic::emitIntrinsic(raw_ostream &OS) const {
515 // Use the preprocessor to enable the non-overloaded builtins.
516 if (getClassKind() != ClassG || getProto().size() <= 1) {
517 OS << "#define " << mangleName(getClassKind())
518 << "(...) __builtin_sve_" << mangleName(ClassS)
519 << "(__VA_ARGS__)\n";
520 } else {
521 llvm_unreachable("Not yet implemented. Overloaded intrinsics will follow "
522 "in a future patch");
523 }
524}
525
526//===----------------------------------------------------------------------===//
527// SVEEmitter implementation
528//===----------------------------------------------------------------------===//
529void SVEEmitter::createIntrinsic(
530 Record *R, SmallVectorImpl<std::unique_ptr<Intrinsic>> &Out) {
531 StringRef Name = R->getValueAsString("Name");
532 StringRef Proto = R->getValueAsString("Prototype");
533 StringRef Types = R->getValueAsString("Types");
534 StringRef Guard = R->getValueAsString("ArchGuard");
535 StringRef LLVMName = R->getValueAsString("LLVMIntrinsic");
536 int64_t Merge = R->getValueAsInt("Merge");
537 std::vector<Record*> FlagsList = R->getValueAsListOfDefs("Flags");
538 int64_t MemEltType = R->getValueAsInt("MemEltType");
539
540 int64_t Flags = 0;
541 for (auto FlagRec : FlagsList)
542 Flags |= FlagRec->getValueAsInt("Value");
543
544 // Extract type specs from string
545 SmallVector<TypeSpec, 8> TypeSpecs;
546 TypeSpec Acc;
547 for (char I : Types) {
548 Acc.push_back(I);
549 if (islower(I)) {
550 TypeSpecs.push_back(TypeSpec(Acc));
551 Acc.clear();
552 }
553 }
554
555 // Remove duplicate type specs.
556 std::sort(TypeSpecs.begin(), TypeSpecs.end());
557 TypeSpecs.erase(std::unique(TypeSpecs.begin(), TypeSpecs.end()),
558 TypeSpecs.end());
559
560 // Create an Intrinsic for each type spec.
561 for (auto TS : TypeSpecs) {
562 Out.push_back(std::make_unique<Intrinsic>(Name, Proto, Merge, MemEltType,
563 LLVMName, Flags, TS, ClassS,
564 *this, Guard));
565 }
566}
567
568void SVEEmitter::createHeader(raw_ostream &OS) {
Sander de Smalen5087ace2020-03-15 14:29:45 +0000569 OS << "/*===---- arm_sve.h - ARM SVE intrinsics "
570 "-----------------------------------===\n"
571 " *\n"
572 " *\n"
573 " * Part of the LLVM Project, under the Apache License v2.0 with LLVM "
574 "Exceptions.\n"
575 " * See https://llvm.org/LICENSE.txt for license information.\n"
576 " * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception\n"
577 " *\n"
578 " *===-----------------------------------------------------------------"
579 "------===\n"
580 " */\n\n";
581
582 OS << "#ifndef __ARM_SVE_H\n";
583 OS << "#define __ARM_SVE_H\n\n";
584
585 OS << "#if !defined(__ARM_FEATURE_SVE)\n";
586 OS << "#error \"SVE support not enabled\"\n";
587 OS << "#else\n\n";
588
589 OS << "#include <stdint.h>\n\n";
Sander de Smalen8b409ea2020-03-16 10:14:05 +0000590 OS << "#ifdef __cplusplus\n";
591 OS << "extern \"C\" {\n";
592 OS << "#else\n";
Sander de Smalen5087ace2020-03-15 14:29:45 +0000593 OS << "#include <stdbool.h>\n";
594 OS << "#endif\n\n";
595
596 OS << "typedef __fp16 float16_t;\n";
597 OS << "typedef float float32_t;\n";
598 OS << "typedef double float64_t;\n";
599 OS << "typedef bool bool_t;\n\n";
600
601 OS << "typedef __SVInt8_t svint8_t;\n";
602 OS << "typedef __SVInt16_t svint16_t;\n";
603 OS << "typedef __SVInt32_t svint32_t;\n";
604 OS << "typedef __SVInt64_t svint64_t;\n";
605 OS << "typedef __SVUint8_t svuint8_t;\n";
606 OS << "typedef __SVUint16_t svuint16_t;\n";
607 OS << "typedef __SVUint32_t svuint32_t;\n";
608 OS << "typedef __SVUint64_t svuint64_t;\n";
609 OS << "typedef __SVFloat16_t svfloat16_t;\n";
610 OS << "typedef __SVFloat32_t svfloat32_t;\n";
611 OS << "typedef __SVFloat64_t svfloat64_t;\n";
612 OS << "typedef __SVBool_t svbool_t;\n\n";
613
Sander de Smalen8b409ea2020-03-16 10:14:05 +0000614 SmallVector<std::unique_ptr<Intrinsic>, 128> Defs;
615 std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst");
616 for (auto *R : RV)
617 createIntrinsic(R, Defs);
Sander de Smalen5087ace2020-03-15 14:29:45 +0000618
Sander de Smalen8b409ea2020-03-16 10:14:05 +0000619 // Sort intrinsics in header file by following order/priority:
620 // - Architectural guard (i.e. does it require SVE2 or SVE2_AES)
621 // - Class (is intrinsic overloaded or not)
622 // - Intrinsic name
623 std::stable_sort(
624 Defs.begin(), Defs.end(), [](const std::unique_ptr<Intrinsic> &A,
625 const std::unique_ptr<Intrinsic> &B) {
626 return A->getGuard() < B->getGuard() ||
627 (unsigned)A->getClassKind() < (unsigned)B->getClassKind() ||
628 A->getName() < B->getName();
629 });
630
631 StringRef InGuard = "";
632 for (auto &I : Defs) {
633 // Emit #endif/#if pair if needed.
634 if (I->getGuard() != InGuard) {
635 if (!InGuard.empty())
636 OS << "#endif //" << InGuard << "\n";
637 InGuard = I->getGuard();
638 if (!InGuard.empty())
639 OS << "\n#if " << InGuard << "\n";
640 }
641
642 // Actually emit the intrinsic declaration.
643 I->emitIntrinsic(OS);
644 }
645
646 if (!InGuard.empty())
647 OS << "#endif //" << InGuard << "\n";
648
649 OS << "#ifdef __cplusplus\n";
650 OS << "} // extern \"C\"\n";
651 OS << "#endif\n\n";
652 OS << "#endif /*__ARM_FEATURE_SVE */\n\n";
Sander de Smalen5087ace2020-03-15 14:29:45 +0000653 OS << "#endif /* __ARM_SVE_H */\n";
654}
655
Sander de Smalen8b409ea2020-03-16 10:14:05 +0000656void SVEEmitter::createBuiltins(raw_ostream &OS) {
657 std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst");
658 SmallVector<std::unique_ptr<Intrinsic>, 128> Defs;
659 for (auto *R : RV)
660 createIntrinsic(R, Defs);
661
662 // The mappings must be sorted based on BuiltinID.
663 llvm::sort(Defs, [](const std::unique_ptr<Intrinsic> &A,
664 const std::unique_ptr<Intrinsic> &B) {
665 return A->getMangledName() < B->getMangledName();
666 });
667
668 OS << "#ifdef GET_SVE_BUILTINS\n";
669 for (auto &Def : Defs) {
670 // Only create BUILTINs for non-overloaded intrinsics, as overloaded
671 // declarations only live in the header file.
672 if (Def->getClassKind() != ClassG)
673 OS << "BUILTIN(__builtin_sve_" << Def->getMangledName() << ", \""
674 << Def->getBuiltinTypeStr() << "\", \"n\")\n";
675 }
676 OS << "#endif\n\n";
677}
678
679void SVEEmitter::createCodeGenMap(raw_ostream &OS) {
680 std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst");
681 SmallVector<std::unique_ptr<Intrinsic>, 128> Defs;
682 for (auto *R : RV)
683 createIntrinsic(R, Defs);
684
685 // The mappings must be sorted based on BuiltinID.
686 llvm::sort(Defs, [](const std::unique_ptr<Intrinsic> &A,
687 const std::unique_ptr<Intrinsic> &B) {
688 return A->getMangledName() < B->getMangledName();
689 });
690
691 OS << "#ifdef GET_SVE_LLVM_INTRINSIC_MAP\n";
692 for (auto &Def : Defs) {
693 // Builtins only exist for non-overloaded intrinsics, overloaded
694 // declarations only live in the header file.
695 if (Def->getClassKind() == ClassG)
696 continue;
697
698 assert(!Def->isFlagSet(SVETypeFlags::EltTypeMask) &&
699 !Def->isFlagSet(SVETypeFlags::MemEltTypeMask) &&
700 "Unexpected mask value");
701 uint64_t Flags = Def->getFlags().getBits() |
702 Def->getBaseType().getTypeFlags() |
703 Def->getMemEltTypeEnum();
704 auto FlagString = std::to_string(Flags);
705
706 std::string LLVMName = Def->getLLVMName();
707 std::string Builtin = Def->getMangledName();
708 if (!LLVMName.empty())
709 OS << "SVEMAP1(" << Builtin << ", " << LLVMName << ", " << FlagString
710 << "),\n";
711 else
712 OS << "SVEMAP2(" << Builtin << ", " << FlagString << "),\n";
713 }
714 OS << "#endif\n\n";
715}
716
Sander de Smalen5087ace2020-03-15 14:29:45 +0000717namespace clang {
718void EmitSveHeader(RecordKeeper &Records, raw_ostream &OS) {
Sander de Smalen8b409ea2020-03-16 10:14:05 +0000719 SVEEmitter(Records).createHeader(OS);
720}
721
722void EmitSveBuiltins(RecordKeeper &Records, raw_ostream &OS) {
723 SVEEmitter(Records).createBuiltins(OS);
724}
725
726void EmitSveCodeGenMap(RecordKeeper &Records, raw_ostream &OS) {
727 SVEEmitter(Records).createCodeGenMap(OS);
Sander de Smalen5087ace2020-03-15 14:29:45 +0000728}
729
730} // End namespace clang