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