blob: dc009e5ca44369c0111311d81cd66ea3b4ab87d5 [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
Sander de Smalenc5b81462020-03-18 11:07:20 +000068 bool isPointer() const { return Pointer; }
69 bool isVoidPointer() const { return Pointer && Void; }
70 bool isSigned() const { return Signed; }
71 bool isImmediate() const { return Immediate; }
72 bool isScalar() const { return NumVectors == 0; }
73 bool isVector() const { return NumVectors > 0; }
74 bool isScalableVector() const { return isVector() && IsScalable; }
75 bool isChar() const { return ElementBitwidth == 8; }
76 bool isVoid() const { return Void & !Pointer; }
77 bool isDefault() const { return DefaultType; }
78 bool isFloat() const { return Float; }
79 bool isInteger() const { return !Float && !Predicate; }
80 bool isScalarPredicate() const { return !Float && ElementBitwidth == 1; }
81 bool isPredicateVector() const { return Predicate; }
82 bool isPredicatePattern() const { return PredicatePattern; }
83 bool isPrefetchOp() const { return PrefetchOp; }
84 bool isConstant() const { return Constant; }
85 unsigned getElementSizeInBits() const { return ElementBitwidth; }
86 unsigned getNumVectors() const { return NumVectors; }
87
88 unsigned getNumElements() const {
89 assert(ElementBitwidth != ~0U);
90 return Bitwidth / ElementBitwidth;
91 }
92 unsigned getSizeInBits() const {
93 return Bitwidth;
94 }
95
96 /// Return the string representation of a type, which is an encoded
97 /// string for passing to the BUILTIN() macro in Builtins.def.
98 std::string builtin_str() const;
99
Sander de Smalen981f0802020-03-18 15:05:08 +0000100 /// Return the C/C++ string representation of a type for use in the
101 /// arm_sve.h header file.
102 std::string str() const;
103
Sander de Smalenc5b81462020-03-18 11:07:20 +0000104private:
105 /// Creates the type based on the typespec string in TS.
106 void applyTypespec();
107
108 /// Applies a prototype modifier to the type.
109 void applyModifier(char Mod);
110};
111
112
113class SVEEmitter;
114
115/// The main grunt class. This represents an instantiation of an intrinsic with
116/// a particular typespec and prototype.
117class Intrinsic {
118 /// The unmangled name.
119 std::string Name;
120
121 /// The name of the corresponding LLVM IR intrinsic.
122 std::string LLVMName;
123
124 /// Intrinsic prototype.
125 std::string Proto;
126
127 /// The base type spec for this intrinsic.
128 TypeSpec BaseTypeSpec;
129
130 /// The base class kind. Most intrinsics use ClassS, which has full type
131 /// info for integers (_s32/_u32), or ClassG which is used for overloaded
132 /// intrinsics.
133 ClassKind Class;
134
135 /// The architectural #ifdef guard.
136 std::string Guard;
137
Sander de Smalenf6ea0262020-04-14 15:31:20 +0100138 // The merge suffix such as _m, _x or _z.
139 std::string MergeSuffix;
140
Sander de Smalenc5b81462020-03-18 11:07:20 +0000141 /// 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
Sander de Smalenf6ea0262020-04-14 15:31:20 +0100147 uint64_t Flags;
Sander de Smalenc5b81462020-03-18 11:07:20 +0000148
149public:
Sander de Smalenf6ea0262020-04-14 15:31:20 +0100150 Intrinsic(StringRef Name, StringRef Proto, uint64_t MergeTy,
151 StringRef MergeSuffix, uint64_t MemoryElementTy, StringRef LLVMName,
152 uint64_t Flags, TypeSpec BT, ClassKind Class, SVEEmitter &Emitter,
153 StringRef Guard);
Sander de Smalenc5b81462020-03-18 11:07:20 +0000154
155 ~Intrinsic()=default;
156
157 std::string getName() const { return Name; }
158 std::string getLLVMName() const { return LLVMName; }
159 std::string getProto() const { return Proto; }
160 TypeSpec getBaseTypeSpec() const { return BaseTypeSpec; }
161 SVEType getBaseType() const { return BaseType; }
162
163 StringRef getGuard() const { return Guard; }
164 ClassKind getClassKind() const { return Class; }
Sander de Smalenc5b81462020-03-18 11:07:20 +0000165
166 SVEType getReturnType() const { return Types[0]; }
167 ArrayRef<SVEType> getTypes() const { return Types; }
168 SVEType getParamType(unsigned I) const { return Types[I + 1]; }
169 unsigned getNumParams() const { return Proto.size() - 1; }
170
Sander de Smalenf6ea0262020-04-14 15:31:20 +0100171 uint64_t getFlags() const { return Flags; }
Sander de Smalenc5b81462020-03-18 11:07:20 +0000172 bool isFlagSet(uint64_t Flag) const { return Flags & Flag;}
173
174 /// Return the type string for a BUILTIN() macro in Builtins.def.
175 std::string getBuiltinTypeStr();
176
177 /// Return the name, mangled with type information. The name is mangled for
178 /// ClassS, so will add type suffixes such as _u32/_s32.
179 std::string getMangledName() const { return mangleName(ClassS); }
180
181 /// Returns true if the intrinsic is overloaded, in that it should also generate
182 /// a short form without the type-specifiers, e.g. 'svld1(..)' instead of
183 /// 'svld1_u32(..)'.
184 static bool isOverloadedIntrinsic(StringRef Name) {
185 auto BrOpen = Name.find("[");
186 auto BrClose = Name.find(']');
187 return BrOpen != std::string::npos && BrClose != std::string::npos;
188 }
189
190 /// Emits the intrinsic declaration to the ostream.
191 void emitIntrinsic(raw_ostream &OS) const;
192
193private:
Sander de Smalenf6ea0262020-04-14 15:31:20 +0100194 std::string getMergeSuffix() const { return MergeSuffix; }
Sander de Smalenc5b81462020-03-18 11:07:20 +0000195 std::string mangleName(ClassKind LocalCK) const;
196 std::string replaceTemplatedArgs(std::string Name, TypeSpec TS,
197 std::string Proto) const;
198};
199
200class SVEEmitter {
201private:
202 RecordKeeper &Records;
203 llvm::StringMap<uint64_t> EltTypes;
204 llvm::StringMap<uint64_t> MemEltTypes;
205 llvm::StringMap<uint64_t> FlagTypes;
Sander de Smalenf6ea0262020-04-14 15:31:20 +0100206 llvm::StringMap<uint64_t> MergeTypes;
Sander de Smalenc5b81462020-03-18 11:07:20 +0000207
Sander de Smalenc5b81462020-03-18 11:07:20 +0000208public:
209 SVEEmitter(RecordKeeper &R) : Records(R) {
210 for (auto *RV : Records.getAllDerivedDefinitions("EltType"))
211 EltTypes[RV->getNameInitAsString()] = RV->getValueAsInt("Value");
212 for (auto *RV : Records.getAllDerivedDefinitions("MemEltType"))
213 MemEltTypes[RV->getNameInitAsString()] = RV->getValueAsInt("Value");
214 for (auto *RV : Records.getAllDerivedDefinitions("FlagType"))
215 FlagTypes[RV->getNameInitAsString()] = RV->getValueAsInt("Value");
Sander de Smalenf6ea0262020-04-14 15:31:20 +0100216 for (auto *RV : Records.getAllDerivedDefinitions("MergeType"))
217 MergeTypes[RV->getNameInitAsString()] = RV->getValueAsInt("Value");
Sander de Smalenc5b81462020-03-18 11:07:20 +0000218 }
219
Sander de Smalenf6ea0262020-04-14 15:31:20 +0100220 // Returns the SVETypeFlags for a given value and mask.
221 uint64_t encodeFlag(uint64_t V, StringRef MaskName) const {
222 auto It = FlagTypes.find(MaskName);
223 if (It != FlagTypes.end()) {
224 uint64_t Mask = It->getValue();
225 unsigned Shift = llvm::countTrailingZeros(Mask);
226 return (V << Shift) & Mask;
227 }
228 llvm_unreachable("Unsupported flag");
229 }
230
231 // Returns the SVETypeFlags for the given element type.
232 uint64_t encodeEltType(StringRef EltName) {
233 auto It = EltTypes.find(EltName);
234 if (It != EltTypes.end())
235 return encodeFlag(It->getValue(), "EltTypeMask");
236 llvm_unreachable("Unsupported EltType");
237 }
238
239 // Returns the SVETypeFlags for the given memory element type.
240 uint64_t encodeMemoryElementType(uint64_t MT) {
241 return encodeFlag(MT, "MemEltTypeMask");
242 }
243
244 // Returns the SVETypeFlags for the given merge type.
245 uint64_t encodeMergeType(uint64_t MT) {
246 return encodeFlag(MT, "MergeTypeMask");
247 }
248
249 // Returns the SVETypeFlags value for the given SVEType.
250 uint64_t encodeTypeFlags(const SVEType &T);
251
Sander de Smalenc5b81462020-03-18 11:07:20 +0000252 /// Emit arm_sve.h.
253 void createHeader(raw_ostream &o);
254
255 /// Emit all the __builtin prototypes and code needed by Sema.
256 void createBuiltins(raw_ostream &o);
257
258 /// Emit all the information needed to map builtin -> LLVM IR intrinsic.
259 void createCodeGenMap(raw_ostream &o);
260
261 /// Create the SVETypeFlags used in CGBuiltins
262 void createTypeFlags(raw_ostream &o);
263
264 /// Create intrinsic and add it to \p Out
265 void createIntrinsic(Record *R, SmallVectorImpl<std::unique_ptr<Intrinsic>> &Out);
Sander de Smalen5087ace2020-03-15 14:29:45 +0000266};
267
268} // end anonymous namespace
269
270
271//===----------------------------------------------------------------------===//
Sander de Smalenc5b81462020-03-18 11:07:20 +0000272// Type implementation
Sander de Smalen8b409ea2020-03-16 10:14:05 +0000273//===----------------------------------------------------------------------===//
Sander de Smalen8b409ea2020-03-16 10:14:05 +0000274
Sander de Smalenc5b81462020-03-18 11:07:20 +0000275std::string SVEType::builtin_str() const {
276 std::string S;
277 if (isVoid())
278 return "v";
279
280 if (isVoidPointer())
281 S += "v";
282 else if (!Float)
283 switch (ElementBitwidth) {
284 case 1: S += "b"; break;
285 case 8: S += "c"; break;
286 case 16: S += "s"; break;
287 case 32: S += "i"; break;
288 case 64: S += "Wi"; break;
289 case 128: S += "LLLi"; break;
290 default: llvm_unreachable("Unhandled case!");
291 }
292 else
293 switch (ElementBitwidth) {
294 case 16: S += "h"; break;
295 case 32: S += "f"; break;
296 case 64: S += "d"; break;
297 default: llvm_unreachable("Unhandled case!");
298 }
299
300 if (!isFloat()) {
301 if ((isChar() || isPointer()) && !isVoidPointer()) {
302 // Make chars and typed pointers explicitly signed.
303 if (Signed)
304 S = "S" + S;
305 else if (!Signed)
306 S = "U" + S;
307 } else if (!isVoidPointer() && !Signed) {
308 S = "U" + S;
309 }
310 }
311
312 // Constant indices are "int", but have the "constant expression" modifier.
313 if (isImmediate()) {
314 assert(!isFloat() && "fp immediates are not supported");
315 S = "I" + S;
316 }
317
318 if (isScalar()) {
319 if (Constant) S += "C";
320 if (Pointer) S += "*";
321 return S;
322 }
323
324 assert(isScalableVector() && "Unsupported type");
325 return "q" + utostr(getNumElements() * NumVectors) + S;
326}
327
Sander de Smalen981f0802020-03-18 15:05:08 +0000328std::string SVEType::str() const {
329 if (isPredicatePattern())
330 return "sv_pattern";
331
332 if (isPrefetchOp())
333 return "sv_prfop";
334
335 std::string S;
336 if (Void)
337 S += "void";
338 else {
339 if (isScalableVector())
340 S += "sv";
341 if (!Signed && !Float)
342 S += "u";
343
344 if (Float)
345 S += "float";
346 else if (isScalarPredicate())
347 S += "bool";
348 else
349 S += "int";
350
351 if (!isScalarPredicate())
352 S += utostr(ElementBitwidth);
353 if (!isScalableVector() && isVector())
354 S += "x" + utostr(getNumElements());
355 if (NumVectors > 1)
356 S += "x" + utostr(NumVectors);
357 S += "_t";
358 }
359
360 if (Constant)
361 S += " const";
362 if (Pointer)
363 S += " *";
364
365 return S;
366}
Sander de Smalenc5b81462020-03-18 11:07:20 +0000367void SVEType::applyTypespec() {
368 for (char I : TS) {
369 switch (I) {
370 case 'P':
371 Predicate = true;
372 ElementBitwidth = 1;
373 break;
374 case 'U':
375 Signed = false;
376 break;
377 case 'c':
378 ElementBitwidth = 8;
379 break;
380 case 's':
381 ElementBitwidth = 16;
382 break;
383 case 'i':
384 ElementBitwidth = 32;
385 break;
386 case 'l':
387 ElementBitwidth = 64;
388 break;
389 case 'h':
390 Float = true;
391 ElementBitwidth = 16;
392 break;
393 case 'f':
394 Float = true;
395 ElementBitwidth = 32;
396 break;
397 case 'd':
398 Float = true;
399 ElementBitwidth = 64;
400 break;
401 default:
402 llvm_unreachable("Unhandled type code!");
403 }
404 }
405 assert(ElementBitwidth != ~0U && "Bad element bitwidth!");
406}
407
408void SVEType::applyModifier(char Mod) {
409 switch (Mod) {
410 case 'v':
411 Void = true;
412 break;
413 case 'd':
414 DefaultType = true;
415 break;
416 case 'c':
417 Constant = true;
418 LLVM_FALLTHROUGH;
419 case 'p':
420 Pointer = true;
421 Bitwidth = ElementBitwidth;
422 NumVectors = 0;
423 break;
424 case 'P':
425 Signed = true;
426 Float = false;
427 Predicate = true;
428 Bitwidth = 16;
429 ElementBitwidth = 1;
430 break;
Sander de Smalen17a68c62020-04-14 13:17:52 +0100431 case 'l':
432 Predicate = false;
433 Signed = true;
434 Float = false;
435 ElementBitwidth = Bitwidth = 64;
436 NumVectors = 0;
437 break;
438 case 'S':
439 Constant = true;
440 Pointer = true;
441 ElementBitwidth = Bitwidth = 8;
442 NumVectors = 0;
443 Signed = true;
444 break;
445 case 'W':
446 Constant = true;
447 Pointer = true;
448 ElementBitwidth = Bitwidth = 8;
449 NumVectors = 0;
450 Signed = false;
451 break;
452 case 'T':
453 Constant = true;
454 Pointer = true;
455 ElementBitwidth = Bitwidth = 16;
456 NumVectors = 0;
457 Signed = true;
458 break;
459 case 'X':
460 Constant = true;
461 Pointer = true;
462 ElementBitwidth = Bitwidth = 16;
463 NumVectors = 0;
464 Signed = false;
465 break;
466 case 'Y':
467 Constant = true;
468 Pointer = true;
469 ElementBitwidth = Bitwidth = 32;
470 NumVectors = 0;
471 Signed = false;
472 break;
473 case 'U':
474 Constant = true;
475 Pointer = true;
476 ElementBitwidth = Bitwidth = 32;
477 NumVectors = 0;
478 Signed = true;
479 break;
480 case 'A':
481 Pointer = true;
482 ElementBitwidth = Bitwidth = 8;
483 NumVectors = 0;
484 Signed = true;
485 break;
486 case 'B':
487 Pointer = true;
488 ElementBitwidth = Bitwidth = 16;
489 NumVectors = 0;
490 Signed = true;
491 break;
492 case 'C':
493 Pointer = true;
494 ElementBitwidth = Bitwidth = 32;
495 NumVectors = 0;
496 Signed = true;
497 break;
498 case 'D':
499 Pointer = true;
500 ElementBitwidth = Bitwidth = 64;
501 NumVectors = 0;
502 Signed = true;
503 break;
504 case 'E':
505 Pointer = true;
506 ElementBitwidth = Bitwidth = 8;
507 NumVectors = 0;
508 Signed = false;
509 break;
510 case 'F':
511 Pointer = true;
512 ElementBitwidth = Bitwidth = 16;
513 NumVectors = 0;
514 Signed = false;
515 break;
516 case 'G':
517 Pointer = true;
518 ElementBitwidth = Bitwidth = 32;
519 NumVectors = 0;
520 Signed = false;
521 break;
Sander de Smalenc5b81462020-03-18 11:07:20 +0000522 default:
523 llvm_unreachable("Unhandled character!");
524 }
525}
526
527
528//===----------------------------------------------------------------------===//
529// Intrinsic implementation
530//===----------------------------------------------------------------------===//
531
Sander de Smalenf6ea0262020-04-14 15:31:20 +0100532Intrinsic::Intrinsic(StringRef Name, StringRef Proto, uint64_t MergeTy,
533 StringRef MergeSuffix, uint64_t MemoryElementTy,
534 StringRef LLVMName, uint64_t Flags, TypeSpec BT,
535 ClassKind Class, SVEEmitter &Emitter, StringRef Guard)
536 : Name(Name.str()), LLVMName(LLVMName), Proto(Proto.str()),
537 BaseTypeSpec(BT), Class(Class), Guard(Guard.str()),
538 MergeSuffix(MergeSuffix.str()), BaseType(BT, 'd'), Flags(Flags) {
539
540 // Types[0] is the return value.
541 for (unsigned I = 0; I < Proto.size(); ++I) {
542 SVEType T(BaseTypeSpec, Proto[I]);
543 Types.push_back(T);
544 }
545
546 // Set flags based on properties
547 this->Flags |= Emitter.encodeTypeFlags(BaseType);
548 this->Flags |= Emitter.encodeMemoryElementType(MemoryElementTy);
549 this->Flags |= Emitter.encodeMergeType(MergeTy);
550}
551
Sander de Smalenc5b81462020-03-18 11:07:20 +0000552std::string Intrinsic::getBuiltinTypeStr() {
553 std::string S;
554
555 SVEType RetT = getReturnType();
556 // Since the return value must be one type, return a vector type of the
557 // appropriate width which we will bitcast. An exception is made for
558 // returning structs of 2, 3, or 4 vectors which are returned in a sret-like
559 // fashion, storing them to a pointer arg.
560 if (RetT.getNumVectors() > 1) {
561 S += "vv*"; // void result with void* first argument
562 } else
563 S += RetT.builtin_str();
564
565 for (unsigned I = 0; I < getNumParams(); ++I)
566 S += getParamType(I).builtin_str();
567
568 return S;
569}
570
571std::string Intrinsic::replaceTemplatedArgs(std::string Name, TypeSpec TS,
572 std::string Proto) const {
573 std::string Ret = Name;
574 while (Ret.find('{') != std::string::npos) {
575 size_t Pos = Ret.find('{');
576 size_t End = Ret.find('}');
577 unsigned NumChars = End - Pos + 1;
578 assert(NumChars == 3 && "Unexpected template argument");
579
580 SVEType T;
581 char C = Ret[Pos+1];
582 switch(C) {
583 default:
584 llvm_unreachable("Unknown predication specifier");
585 case 'd':
586 T = SVEType(TS, 'd');
587 break;
588 case '0':
589 case '1':
590 case '2':
591 case '3':
592 T = SVEType(TS, Proto[C - '0']);
593 break;
594 }
595
596 // Replace templated arg with the right suffix (e.g. u32)
597 std::string TypeCode;
598 if (T.isInteger())
599 TypeCode = T.isSigned() ? 's' : 'u';
600 else if (T.isPredicateVector())
601 TypeCode = 'b';
602 else
603 TypeCode = 'f';
604 Ret.replace(Pos, NumChars, TypeCode + utostr(T.getElementSizeInBits()));
605 }
606
607 return Ret;
608}
609
Sander de Smalenc5b81462020-03-18 11:07:20 +0000610std::string Intrinsic::mangleName(ClassKind LocalCK) const {
611 std::string S = getName();
612
613 if (LocalCK == ClassG) {
614 // Remove the square brackets and everything in between.
615 while (S.find("[") != std::string::npos) {
616 auto Start = S.find("[");
617 auto End = S.find(']');
618 S.erase(Start, (End-Start)+1);
619 }
620 } else {
621 // Remove the square brackets.
622 while (S.find("[") != std::string::npos) {
623 auto BrPos = S.find('[');
624 if (BrPos != std::string::npos)
625 S.erase(BrPos, 1);
626 BrPos = S.find(']');
627 if (BrPos != std::string::npos)
628 S.erase(BrPos, 1);
629 }
630 }
631
632 // Replace all {d} like expressions with e.g. 'u32'
633 return replaceTemplatedArgs(S, getBaseTypeSpec(), getProto()) +
634 getMergeSuffix();
635}
636
637void Intrinsic::emitIntrinsic(raw_ostream &OS) const {
638 // Use the preprocessor to
639 if (getClassKind() != ClassG || getProto().size() <= 1) {
640 OS << "#define " << mangleName(getClassKind())
641 << "(...) __builtin_sve_" << mangleName(ClassS)
642 << "(__VA_ARGS__)\n";
643 } else {
Sander de Smalen981f0802020-03-18 15:05:08 +0000644 std::string FullName = mangleName(ClassS);
645 std::string ProtoName = mangleName(ClassG);
646
647 OS << "__aio __attribute__((__clang_arm_builtin_alias("
648 << "__builtin_sve_" << FullName << ")))\n";
649
650 OS << getTypes()[0].str() << " " << ProtoName << "(";
651 for (unsigned I = 0; I < getTypes().size() - 1; ++I) {
652 if (I != 0)
653 OS << ", ";
654 OS << getTypes()[I + 1].str();
655 }
656 OS << ");\n";
Sander de Smalenc5b81462020-03-18 11:07:20 +0000657 }
658}
659
660//===----------------------------------------------------------------------===//
661// SVEEmitter implementation
662//===----------------------------------------------------------------------===//
Sander de Smalenf6ea0262020-04-14 15:31:20 +0100663uint64_t SVEEmitter::encodeTypeFlags(const SVEType &T) {
664 if (T.isFloat()) {
665 switch (T.getElementSizeInBits()) {
666 case 16:
667 return encodeEltType("EltTyFloat16");
668 case 32:
669 return encodeEltType("EltTyFloat32");
670 case 64:
671 return encodeEltType("EltTyFloat64");
672 default:
673 llvm_unreachable("Unhandled float element bitwidth!");
674 }
675 }
676
677 if (T.isPredicateVector()) {
678 switch (T.getElementSizeInBits()) {
679 case 8:
680 return encodeEltType("EltTyBool8");
681 case 16:
682 return encodeEltType("EltTyBool16");
683 case 32:
684 return encodeEltType("EltTyBool32");
685 case 64:
686 return encodeEltType("EltTyBool64");
687 default:
688 llvm_unreachable("Unhandled predicate element bitwidth!");
689 }
690 }
691
692 switch (T.getElementSizeInBits()) {
693 case 8:
694 return encodeEltType("EltTyInt8");
695 case 16:
696 return encodeEltType("EltTyInt16");
697 case 32:
698 return encodeEltType("EltTyInt32");
699 case 64:
700 return encodeEltType("EltTyInt64");
701 default:
702 llvm_unreachable("Unhandled integer element bitwidth!");
703 }
704}
705
Sander de Smalenc5b81462020-03-18 11:07:20 +0000706void SVEEmitter::createIntrinsic(
707 Record *R, SmallVectorImpl<std::unique_ptr<Intrinsic>> &Out) {
708 StringRef Name = R->getValueAsString("Name");
709 StringRef Proto = R->getValueAsString("Prototype");
710 StringRef Types = R->getValueAsString("Types");
711 StringRef Guard = R->getValueAsString("ArchGuard");
712 StringRef LLVMName = R->getValueAsString("LLVMIntrinsic");
Sander de Smalenf6ea0262020-04-14 15:31:20 +0100713 uint64_t Merge = R->getValueAsInt("Merge");
714 StringRef MergeSuffix = R->getValueAsString("MergeSuffix");
715 uint64_t MemEltType = R->getValueAsInt("MemEltType");
Sander de Smalenc5b81462020-03-18 11:07:20 +0000716 std::vector<Record*> FlagsList = R->getValueAsListOfDefs("Flags");
717
718 int64_t Flags = 0;
719 for (auto FlagRec : FlagsList)
720 Flags |= FlagRec->getValueAsInt("Value");
Sander de Smalenc5b81462020-03-18 11:07:20 +0000721
722 // Extract type specs from string
723 SmallVector<TypeSpec, 8> TypeSpecs;
724 TypeSpec Acc;
725 for (char I : Types) {
726 Acc.push_back(I);
727 if (islower(I)) {
728 TypeSpecs.push_back(TypeSpec(Acc));
729 Acc.clear();
730 }
731 }
732
733 // Remove duplicate type specs.
Benjamin Kramer4065e922020-03-28 19:19:55 +0100734 llvm::sort(TypeSpecs);
Sander de Smalenc5b81462020-03-18 11:07:20 +0000735 TypeSpecs.erase(std::unique(TypeSpecs.begin(), TypeSpecs.end()),
736 TypeSpecs.end());
737
738 // Create an Intrinsic for each type spec.
739 for (auto TS : TypeSpecs) {
Sander de Smalenf6ea0262020-04-14 15:31:20 +0100740 Out.push_back(std::make_unique<Intrinsic>(Name, Proto, Merge, MergeSuffix,
741 MemEltType, LLVMName, Flags, TS,
742 ClassS, *this, Guard));
Sander de Smalen981f0802020-03-18 15:05:08 +0000743
744 // Also generate the short-form (e.g. svadd_m) for the given type-spec.
745 if (Intrinsic::isOverloadedIntrinsic(Name))
Sander de Smalenf6ea0262020-04-14 15:31:20 +0100746 Out.push_back(std::make_unique<Intrinsic>(Name, Proto, Merge, MergeSuffix,
747 MemEltType, LLVMName, Flags, TS,
748 ClassG, *this, Guard));
Sander de Smalenc5b81462020-03-18 11:07:20 +0000749 }
750}
751
752void SVEEmitter::createHeader(raw_ostream &OS) {
Sander de Smalen5087ace2020-03-15 14:29:45 +0000753 OS << "/*===---- arm_sve.h - ARM SVE intrinsics "
754 "-----------------------------------===\n"
755 " *\n"
756 " *\n"
757 " * Part of the LLVM Project, under the Apache License v2.0 with LLVM "
758 "Exceptions.\n"
759 " * See https://llvm.org/LICENSE.txt for license information.\n"
760 " * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception\n"
761 " *\n"
762 " *===-----------------------------------------------------------------"
763 "------===\n"
764 " */\n\n";
765
766 OS << "#ifndef __ARM_SVE_H\n";
767 OS << "#define __ARM_SVE_H\n\n";
768
769 OS << "#if !defined(__ARM_FEATURE_SVE)\n";
770 OS << "#error \"SVE support not enabled\"\n";
771 OS << "#else\n\n";
772
773 OS << "#include <stdint.h>\n\n";
Sander de Smalenc5b81462020-03-18 11:07:20 +0000774 OS << "#ifdef __cplusplus\n";
775 OS << "extern \"C\" {\n";
776 OS << "#else\n";
Sander de Smalen5087ace2020-03-15 14:29:45 +0000777 OS << "#include <stdbool.h>\n";
778 OS << "#endif\n\n";
779
780 OS << "typedef __fp16 float16_t;\n";
781 OS << "typedef float float32_t;\n";
782 OS << "typedef double float64_t;\n";
783 OS << "typedef bool bool_t;\n\n";
784
785 OS << "typedef __SVInt8_t svint8_t;\n";
786 OS << "typedef __SVInt16_t svint16_t;\n";
787 OS << "typedef __SVInt32_t svint32_t;\n";
788 OS << "typedef __SVInt64_t svint64_t;\n";
789 OS << "typedef __SVUint8_t svuint8_t;\n";
790 OS << "typedef __SVUint16_t svuint16_t;\n";
791 OS << "typedef __SVUint32_t svuint32_t;\n";
792 OS << "typedef __SVUint64_t svuint64_t;\n";
793 OS << "typedef __SVFloat16_t svfloat16_t;\n";
794 OS << "typedef __SVFloat32_t svfloat32_t;\n";
795 OS << "typedef __SVFloat64_t svfloat64_t;\n";
796 OS << "typedef __SVBool_t svbool_t;\n\n";
797
Sander de Smalen981f0802020-03-18 15:05:08 +0000798 OS << "/* Function attributes */\n";
799 OS << "#define __aio static inline __attribute__((__always_inline__, "
800 "__nodebug__, __overloadable__))\n\n";
801
Sander de Smalenc5b81462020-03-18 11:07:20 +0000802 SmallVector<std::unique_ptr<Intrinsic>, 128> Defs;
803 std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst");
804 for (auto *R : RV)
805 createIntrinsic(R, Defs);
Sander de Smalen5087ace2020-03-15 14:29:45 +0000806
Sander de Smalenc5b81462020-03-18 11:07:20 +0000807 // Sort intrinsics in header file by following order/priority:
808 // - Architectural guard (i.e. does it require SVE2 or SVE2_AES)
809 // - Class (is intrinsic overloaded or not)
810 // - Intrinsic name
811 std::stable_sort(
812 Defs.begin(), Defs.end(), [](const std::unique_ptr<Intrinsic> &A,
813 const std::unique_ptr<Intrinsic> &B) {
814 return A->getGuard() < B->getGuard() ||
815 (unsigned)A->getClassKind() < (unsigned)B->getClassKind() ||
816 A->getName() < B->getName();
817 });
818
819 StringRef InGuard = "";
820 for (auto &I : Defs) {
821 // Emit #endif/#if pair if needed.
822 if (I->getGuard() != InGuard) {
823 if (!InGuard.empty())
824 OS << "#endif //" << InGuard << "\n";
825 InGuard = I->getGuard();
826 if (!InGuard.empty())
827 OS << "\n#if " << InGuard << "\n";
828 }
829
830 // Actually emit the intrinsic declaration.
831 I->emitIntrinsic(OS);
832 }
833
834 if (!InGuard.empty())
835 OS << "#endif //" << InGuard << "\n";
836
837 OS << "#ifdef __cplusplus\n";
838 OS << "} // extern \"C\"\n";
839 OS << "#endif\n\n";
840 OS << "#endif /*__ARM_FEATURE_SVE */\n\n";
Sander de Smalen5087ace2020-03-15 14:29:45 +0000841 OS << "#endif /* __ARM_SVE_H */\n";
842}
843
Sander de Smalenc5b81462020-03-18 11:07:20 +0000844void SVEEmitter::createBuiltins(raw_ostream &OS) {
845 std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst");
846 SmallVector<std::unique_ptr<Intrinsic>, 128> Defs;
847 for (auto *R : RV)
848 createIntrinsic(R, Defs);
849
850 // The mappings must be sorted based on BuiltinID.
851 llvm::sort(Defs, [](const std::unique_ptr<Intrinsic> &A,
852 const std::unique_ptr<Intrinsic> &B) {
853 return A->getMangledName() < B->getMangledName();
854 });
855
856 OS << "#ifdef GET_SVE_BUILTINS\n";
857 for (auto &Def : Defs) {
858 // Only create BUILTINs for non-overloaded intrinsics, as overloaded
859 // declarations only live in the header file.
860 if (Def->getClassKind() != ClassG)
861 OS << "BUILTIN(__builtin_sve_" << Def->getMangledName() << ", \""
862 << Def->getBuiltinTypeStr() << "\", \"n\")\n";
863 }
864 OS << "#endif\n\n";
865}
866
867void SVEEmitter::createCodeGenMap(raw_ostream &OS) {
868 std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst");
869 SmallVector<std::unique_ptr<Intrinsic>, 128> Defs;
870 for (auto *R : RV)
871 createIntrinsic(R, Defs);
872
873 // The mappings must be sorted based on BuiltinID.
874 llvm::sort(Defs, [](const std::unique_ptr<Intrinsic> &A,
875 const std::unique_ptr<Intrinsic> &B) {
876 return A->getMangledName() < B->getMangledName();
877 });
878
879 OS << "#ifdef GET_SVE_LLVM_INTRINSIC_MAP\n";
880 for (auto &Def : Defs) {
881 // Builtins only exist for non-overloaded intrinsics, overloaded
882 // declarations only live in the header file.
883 if (Def->getClassKind() == ClassG)
884 continue;
885
Sander de Smalenf6ea0262020-04-14 15:31:20 +0100886 uint64_t Flags = Def->getFlags();
Sander de Smalenc5b81462020-03-18 11:07:20 +0000887 auto FlagString = std::to_string(Flags);
888
889 std::string LLVMName = Def->getLLVMName();
890 std::string Builtin = Def->getMangledName();
891 if (!LLVMName.empty())
892 OS << "SVEMAP1(" << Builtin << ", " << LLVMName << ", " << FlagString
893 << "),\n";
894 else
895 OS << "SVEMAP2(" << Builtin << ", " << FlagString << "),\n";
896 }
897 OS << "#endif\n\n";
898}
899
900/// Create the SVETypeFlags used in CGBuiltins
901void SVEEmitter::createTypeFlags(raw_ostream &OS) {
902 OS << "#ifdef LLVM_GET_SVE_TYPEFLAGS\n";
903 for (auto &KV : FlagTypes)
904 OS << "const uint64_t " << KV.getKey() << " = " << KV.getValue() << ";\n";
905 OS << "#endif\n\n";
906
907 OS << "#ifdef LLVM_GET_SVE_ELTTYPES\n";
908 for (auto &KV : EltTypes)
909 OS << " " << KV.getKey() << " = " << KV.getValue() << ",\n";
910 OS << "#endif\n\n";
911
912 OS << "#ifdef LLVM_GET_SVE_MEMELTTYPES\n";
913 for (auto &KV : MemEltTypes)
914 OS << " " << KV.getKey() << " = " << KV.getValue() << ",\n";
915 OS << "#endif\n\n";
Sander de Smalenf6ea0262020-04-14 15:31:20 +0100916
917 OS << "#ifdef LLVM_GET_SVE_MERGETYPES\n";
918 for (auto &KV : MergeTypes)
919 OS << " " << KV.getKey() << " = " << KV.getValue() << ",\n";
920 OS << "#endif\n\n";
Sander de Smalenc5b81462020-03-18 11:07:20 +0000921}
922
Sander de Smalen5087ace2020-03-15 14:29:45 +0000923namespace clang {
924void EmitSveHeader(RecordKeeper &Records, raw_ostream &OS) {
Sander de Smalenc5b81462020-03-18 11:07:20 +0000925 SVEEmitter(Records).createHeader(OS);
926}
927
928void EmitSveBuiltins(RecordKeeper &Records, raw_ostream &OS) {
929 SVEEmitter(Records).createBuiltins(OS);
930}
931
932void EmitSveBuiltinCG(RecordKeeper &Records, raw_ostream &OS) {
933 SVEEmitter(Records).createCodeGenMap(OS);
934}
935void EmitSveTypeFlags(RecordKeeper &Records, raw_ostream &OS) {
936 SVEEmitter(Records).createTypeFlags(OS);
Sander de Smalen5087ace2020-03-15 14:29:45 +0000937}
938
939} // End namespace clang