1 //===- 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/ArrayRef.h"
27 #include "llvm/ADT/STLExtras.h"
28 #include "llvm/ADT/StringExtras.h"
29 #include "llvm/ADT/StringMap.h"
30 #include "llvm/TableGen/Error.h"
31 #include "llvm/TableGen/Record.h"
32 #include <array>
33 #include <cctype>
34 #include <set>
35 #include <sstream>
36 #include <string>
37 #include <tuple>
38
39 using namespace llvm;
40
41 enum ClassKind {
42 ClassNone,
43 ClassS, // signed/unsigned, e.g., "_s8", "_u8" suffix
44 ClassG, // Overloaded name without type suffix
45 };
46
47 enum class ACLEKind { SVE, SME };
48
49 using TypeSpec = std::string;
50
51 namespace {
52
53 class ImmCheck {
54 unsigned Arg;
55 unsigned Kind;
56 unsigned ElementSizeInBits;
57
58 public:
ImmCheck(unsigned Arg,unsigned Kind,unsigned ElementSizeInBits=0)59 ImmCheck(unsigned Arg, unsigned Kind, unsigned ElementSizeInBits = 0)
60 : Arg(Arg), Kind(Kind), ElementSizeInBits(ElementSizeInBits) {}
61 ImmCheck(const ImmCheck &Other) = default;
62 ~ImmCheck() = default;
63
getArg() const64 unsigned getArg() const { return Arg; }
getKind() const65 unsigned getKind() const { return Kind; }
getElementSizeInBits() const66 unsigned getElementSizeInBits() const { return ElementSizeInBits; }
67 };
68
69 class SVEType {
70 bool Float, Signed, Immediate, Void, Constant, Pointer, BFloat;
71 bool DefaultType, IsScalable, Predicate, PredicatePattern, PrefetchOp,
72 Svcount;
73 unsigned Bitwidth, ElementBitwidth, NumVectors;
74
75 public:
SVEType()76 SVEType() : SVEType("", 'v') {}
77
SVEType(StringRef TS,char CharMod,unsigned NumVectors=1)78 SVEType(StringRef TS, char CharMod, unsigned NumVectors = 1)
79 : Float(false), Signed(true), Immediate(false), Void(false),
80 Constant(false), Pointer(false), BFloat(false), DefaultType(false),
81 IsScalable(true), Predicate(false), PredicatePattern(false),
82 PrefetchOp(false), Svcount(false), Bitwidth(128), ElementBitwidth(~0U),
83 NumVectors(NumVectors) {
84 if (!TS.empty())
85 applyTypespec(TS);
86 applyModifier(CharMod);
87 }
88
SVEType(const SVEType & Base,unsigned NumV)89 SVEType(const SVEType &Base, unsigned NumV) : SVEType(Base) {
90 NumVectors = NumV;
91 }
92
isPointer() const93 bool isPointer() const { return Pointer; }
isVoidPointer() const94 bool isVoidPointer() const { return Pointer && Void; }
isSigned() const95 bool isSigned() const { return Signed; }
isImmediate() const96 bool isImmediate() const { return Immediate; }
isScalar() const97 bool isScalar() const { return NumVectors == 0; }
isVector() const98 bool isVector() const { return NumVectors > 0; }
isScalableVector() const99 bool isScalableVector() const { return isVector() && IsScalable; }
isFixedLengthVector() const100 bool isFixedLengthVector() const { return isVector() && !IsScalable; }
isChar() const101 bool isChar() const { return ElementBitwidth == 8; }
isVoid() const102 bool isVoid() const { return Void && !Pointer; }
isDefault() const103 bool isDefault() const { return DefaultType; }
isFloat() const104 bool isFloat() const { return Float && !BFloat; }
isBFloat() const105 bool isBFloat() const { return BFloat && !Float; }
isFloatingPoint() const106 bool isFloatingPoint() const { return Float || BFloat; }
isInteger() const107 bool isInteger() const {
108 return !isFloatingPoint() && !Predicate && !Svcount;
109 }
isScalarPredicate() const110 bool isScalarPredicate() const {
111 return !isFloatingPoint() && Predicate && NumVectors == 0;
112 }
isPredicateVector() const113 bool isPredicateVector() const { return Predicate; }
isPredicatePattern() const114 bool isPredicatePattern() const { return PredicatePattern; }
isPrefetchOp() const115 bool isPrefetchOp() const { return PrefetchOp; }
isSvcount() const116 bool isSvcount() const { return Svcount; }
isConstant() const117 bool isConstant() const { return Constant; }
getElementSizeInBits() const118 unsigned getElementSizeInBits() const { return ElementBitwidth; }
getNumVectors() const119 unsigned getNumVectors() const { return NumVectors; }
120
getNumElements() const121 unsigned getNumElements() const {
122 assert(ElementBitwidth != ~0U);
123 return Bitwidth / ElementBitwidth;
124 }
getSizeInBits() const125 unsigned getSizeInBits() const {
126 return Bitwidth;
127 }
128
129 /// Return the string representation of a type, which is an encoded
130 /// string for passing to the BUILTIN() macro in Builtins.def.
131 std::string builtin_str() const;
132
133 /// Return the C/C++ string representation of a type for use in the
134 /// arm_sve.h header file.
135 std::string str() const;
136
137 private:
138 /// Creates the type based on the typespec string in TS.
139 void applyTypespec(StringRef TS);
140
141 /// Applies a prototype modifier to the type.
142 void applyModifier(char Mod);
143 };
144
145 class SVEEmitter;
146
147 /// The main grunt class. This represents an instantiation of an intrinsic with
148 /// a particular typespec and prototype.
149 class Intrinsic {
150 /// The unmangled name.
151 std::string Name;
152
153 /// The name of the corresponding LLVM IR intrinsic.
154 std::string LLVMName;
155
156 /// Intrinsic prototype.
157 std::string Proto;
158
159 /// The base type spec for this intrinsic.
160 TypeSpec BaseTypeSpec;
161
162 /// The base class kind. Most intrinsics use ClassS, which has full type
163 /// info for integers (_s32/_u32), or ClassG which is used for overloaded
164 /// intrinsics.
165 ClassKind Class;
166
167 /// The architectural #ifdef guard.
168 std::string SVEGuard, SMEGuard;
169
170 // The merge suffix such as _m, _x or _z.
171 std::string MergeSuffix;
172
173 /// The types of return value [0] and parameters [1..].
174 std::vector<SVEType> Types;
175
176 /// The "base type", which is VarType('d', BaseTypeSpec).
177 SVEType BaseType;
178
179 uint64_t Flags;
180
181 SmallVector<ImmCheck, 2> ImmChecks;
182
183 public:
184 Intrinsic(StringRef Name, StringRef Proto, uint64_t MergeTy,
185 StringRef MergeSuffix, uint64_t MemoryElementTy, StringRef LLVMName,
186 uint64_t Flags, ArrayRef<ImmCheck> ImmChecks, TypeSpec BT,
187 ClassKind Class, SVEEmitter &Emitter, StringRef SVEGuard,
188 StringRef SMEGuard);
189
190 ~Intrinsic()=default;
191
getName() const192 std::string getName() const { return Name; }
getLLVMName() const193 std::string getLLVMName() const { return LLVMName; }
getProto() const194 std::string getProto() const { return Proto; }
getBaseTypeSpec() const195 TypeSpec getBaseTypeSpec() const { return BaseTypeSpec; }
getBaseType() const196 SVEType getBaseType() const { return BaseType; }
197
getSVEGuard() const198 StringRef getSVEGuard() const { return SVEGuard; }
getSMEGuard() const199 StringRef getSMEGuard() const { return SMEGuard; }
printGuard(raw_ostream & OS) const200 void printGuard(raw_ostream &OS) const {
201 if (!SVEGuard.empty() && SMEGuard.empty())
202 OS << SVEGuard;
203 else if (SVEGuard.empty() && !SMEGuard.empty())
204 OS << SMEGuard;
205 else {
206 if (SVEGuard.find(",") != std::string::npos ||
207 SVEGuard.find("|") != std::string::npos)
208 OS << "(" << SVEGuard << ")";
209 else
210 OS << SVEGuard;
211 OS << "|";
212 if (SMEGuard.find(",") != std::string::npos ||
213 SMEGuard.find("|") != std::string::npos)
214 OS << "(" << SMEGuard << ")";
215 else
216 OS << SMEGuard;
217 }
218 }
getClassKind() const219 ClassKind getClassKind() const { return Class; }
220
getReturnType() const221 SVEType getReturnType() const { return Types[0]; }
getTypes() const222 ArrayRef<SVEType> getTypes() const { return Types; }
getParamType(unsigned I) const223 SVEType getParamType(unsigned I) const { return Types[I + 1]; }
getNumParams() const224 unsigned getNumParams() const {
225 return Proto.size() - (2 * llvm::count(Proto, '.')) - 1;
226 }
227
getFlags() const228 uint64_t getFlags() const { return Flags; }
isFlagSet(uint64_t Flag) const229 bool isFlagSet(uint64_t Flag) const { return Flags & Flag;}
230
getImmChecks() const231 ArrayRef<ImmCheck> getImmChecks() const { return ImmChecks; }
232
233 /// Return the type string for a BUILTIN() macro in Builtins.def.
234 std::string getBuiltinTypeStr();
235
236 /// Return the name, mangled with type information. The name is mangled for
237 /// ClassS, so will add type suffixes such as _u32/_s32.
getMangledName() const238 std::string getMangledName() const { return mangleName(ClassS); }
239
240 /// As above, but mangles the LLVM name instead.
getMangledLLVMName() const241 std::string getMangledLLVMName() const { return mangleLLVMName(); }
242
243 /// Returns true if the intrinsic is overloaded, in that it should also generate
244 /// a short form without the type-specifiers, e.g. 'svld1(..)' instead of
245 /// 'svld1_u32(..)'.
isOverloadedIntrinsic(StringRef Name)246 static bool isOverloadedIntrinsic(StringRef Name) {
247 auto BrOpen = Name.find('[');
248 auto BrClose = Name.find(']');
249 return BrOpen != std::string::npos && BrClose != std::string::npos;
250 }
251
252 /// Return true if the intrinsic takes a splat operand.
hasSplat() const253 bool hasSplat() const {
254 // These prototype modifiers are described in arm_sve.td.
255 return Proto.find_first_of("ajfrKLR@") != std::string::npos;
256 }
257
258 /// Return the parameter index of the splat operand.
getSplatIdx() const259 unsigned getSplatIdx() const {
260 unsigned I = 1, Param = 0;
261 for (; I < Proto.size(); ++I, ++Param) {
262 if (Proto[I] == 'a' || Proto[I] == 'j' || Proto[I] == 'f' ||
263 Proto[I] == 'r' || Proto[I] == 'K' || Proto[I] == 'L' ||
264 Proto[I] == 'R' || Proto[I] == '@')
265 break;
266
267 // Multivector modifier can be skipped
268 if (Proto[I] == '.')
269 I += 2;
270 }
271 assert(I != Proto.size() && "Prototype has no splat operand");
272 return Param;
273 }
274
275 /// Emits the intrinsic declaration to the ostream.
276 void emitIntrinsic(raw_ostream &OS, SVEEmitter &Emitter, ACLEKind Kind) const;
277
278 private:
getMergeSuffix() const279 std::string getMergeSuffix() const { return MergeSuffix; }
280 std::string mangleName(ClassKind LocalCK) const;
281 std::string mangleLLVMName() const;
282 std::string replaceTemplatedArgs(std::string Name, TypeSpec TS,
283 std::string Proto) const;
284 };
285
286 class SVEEmitter {
287 private:
288 // The reinterpret builtins are generated separately because they
289 // need the cross product of all types (121 functions in total),
290 // which is inconvenient to specify in the arm_sve.td file or
291 // generate in CGBuiltin.cpp.
292 struct ReinterpretTypeInfo {
293 SVEType BaseType;
294 const char *Suffix;
295 };
296
297 static const std::array<ReinterpretTypeInfo, 12> Reinterprets;
298
299 RecordKeeper &Records;
300 llvm::StringMap<uint64_t> EltTypes;
301 llvm::StringMap<uint64_t> MemEltTypes;
302 llvm::StringMap<uint64_t> FlagTypes;
303 llvm::StringMap<uint64_t> MergeTypes;
304 llvm::StringMap<uint64_t> ImmCheckTypes;
305
306 public:
SVEEmitter(RecordKeeper & R)307 SVEEmitter(RecordKeeper &R) : Records(R) {
308 for (auto *RV : Records.getAllDerivedDefinitions("EltType"))
309 EltTypes[RV->getNameInitAsString()] = RV->getValueAsInt("Value");
310 for (auto *RV : Records.getAllDerivedDefinitions("MemEltType"))
311 MemEltTypes[RV->getNameInitAsString()] = RV->getValueAsInt("Value");
312 for (auto *RV : Records.getAllDerivedDefinitions("FlagType"))
313 FlagTypes[RV->getNameInitAsString()] = RV->getValueAsInt("Value");
314 for (auto *RV : Records.getAllDerivedDefinitions("MergeType"))
315 MergeTypes[RV->getNameInitAsString()] = RV->getValueAsInt("Value");
316 for (auto *RV : Records.getAllDerivedDefinitions("ImmCheckType"))
317 ImmCheckTypes[RV->getNameInitAsString()] = RV->getValueAsInt("Value");
318 }
319
320 /// Returns the enum value for the immcheck type
getEnumValueForImmCheck(StringRef C) const321 unsigned getEnumValueForImmCheck(StringRef C) const {
322 auto It = ImmCheckTypes.find(C);
323 if (It != ImmCheckTypes.end())
324 return It->getValue();
325 llvm_unreachable("Unsupported imm check");
326 }
327
328 /// Returns the enum value for the flag type
getEnumValueForFlag(StringRef C) const329 uint64_t getEnumValueForFlag(StringRef C) const {
330 auto Res = FlagTypes.find(C);
331 if (Res != FlagTypes.end())
332 return Res->getValue();
333 llvm_unreachable("Unsupported flag");
334 }
335
336 // Returns the SVETypeFlags for a given value and mask.
encodeFlag(uint64_t V,StringRef MaskName) const337 uint64_t encodeFlag(uint64_t V, StringRef MaskName) const {
338 auto It = FlagTypes.find(MaskName);
339 if (It != FlagTypes.end()) {
340 uint64_t Mask = It->getValue();
341 unsigned Shift = llvm::countr_zero(Mask);
342 assert(Shift < 64 && "Mask value produced an invalid shift value");
343 return (V << Shift) & Mask;
344 }
345 llvm_unreachable("Unsupported flag");
346 }
347
348 // Returns the SVETypeFlags for the given element type.
encodeEltType(StringRef EltName)349 uint64_t encodeEltType(StringRef EltName) {
350 auto It = EltTypes.find(EltName);
351 if (It != EltTypes.end())
352 return encodeFlag(It->getValue(), "EltTypeMask");
353 llvm_unreachable("Unsupported EltType");
354 }
355
356 // Returns the SVETypeFlags for the given memory element type.
encodeMemoryElementType(uint64_t MT)357 uint64_t encodeMemoryElementType(uint64_t MT) {
358 return encodeFlag(MT, "MemEltTypeMask");
359 }
360
361 // Returns the SVETypeFlags for the given merge type.
encodeMergeType(uint64_t MT)362 uint64_t encodeMergeType(uint64_t MT) {
363 return encodeFlag(MT, "MergeTypeMask");
364 }
365
366 // Returns the SVETypeFlags for the given splat operand.
encodeSplatOperand(unsigned SplatIdx)367 unsigned encodeSplatOperand(unsigned SplatIdx) {
368 assert(SplatIdx < 7 && "SplatIdx out of encodable range");
369 return encodeFlag(SplatIdx + 1, "SplatOperandMask");
370 }
371
372 // Returns the SVETypeFlags value for the given SVEType.
373 uint64_t encodeTypeFlags(const SVEType &T);
374
375 /// Emit arm_sve.h.
376 void createHeader(raw_ostream &o);
377
378 // Emits core intrinsics in both arm_sme.h and arm_sve.h
379 void createCoreHeaderIntrinsics(raw_ostream &o, SVEEmitter &Emitter,
380 ACLEKind Kind);
381
382 /// Emit all the __builtin prototypes and code needed by Sema.
383 void createBuiltins(raw_ostream &o);
384
385 /// Emit all the information needed to map builtin -> LLVM IR intrinsic.
386 void createCodeGenMap(raw_ostream &o);
387
388 /// Emit all the range checks for the immediates.
389 void createRangeChecks(raw_ostream &o);
390
391 /// Create the SVETypeFlags used in CGBuiltins
392 void createTypeFlags(raw_ostream &o);
393
394 /// Emit arm_sme.h.
395 void createSMEHeader(raw_ostream &o);
396
397 /// Emit all the SME __builtin prototypes and code needed by Sema.
398 void createSMEBuiltins(raw_ostream &o);
399
400 /// Emit all the information needed to map builtin -> LLVM IR intrinsic.
401 void createSMECodeGenMap(raw_ostream &o);
402
403 /// Create a table for a builtin's requirement for PSTATE.SM.
404 void createStreamingAttrs(raw_ostream &o, ACLEKind Kind);
405
406 /// Emit all the range checks for the immediates.
407 void createSMERangeChecks(raw_ostream &o);
408
409 /// Create a table for a builtin's requirement for PSTATE.ZA.
410 void createBuiltinZAState(raw_ostream &OS);
411
412 /// Create intrinsic and add it to \p Out
413 void createIntrinsic(Record *R,
414 SmallVectorImpl<std::unique_ptr<Intrinsic>> &Out);
415 };
416
417 const std::array<SVEEmitter::ReinterpretTypeInfo, 12> SVEEmitter::Reinterprets =
418 {{{SVEType("c", 'd'), "s8"},
419 {SVEType("Uc", 'd'), "u8"},
420 {SVEType("s", 'd'), "s16"},
421 {SVEType("Us", 'd'), "u16"},
422 {SVEType("i", 'd'), "s32"},
423 {SVEType("Ui", 'd'), "u32"},
424 {SVEType("l", 'd'), "s64"},
425 {SVEType("Ul", 'd'), "u64"},
426 {SVEType("h", 'd'), "f16"},
427 {SVEType("b", 'd'), "bf16"},
428 {SVEType("f", 'd'), "f32"},
429 {SVEType("d", 'd'), "f64"}}};
430
431 } // end anonymous namespace
432
433
434 //===----------------------------------------------------------------------===//
435 // Type implementation
436 //===----------------------------------------------------------------------===//
437
builtin_str() const438 std::string SVEType::builtin_str() const {
439 std::string S;
440 if (isVoid())
441 return "v";
442
443 if (isScalarPredicate())
444 return "b";
445
446 if (isSvcount())
447 return "Qa";
448
449 if (isVoidPointer())
450 S += "v";
451 else if (!isFloatingPoint())
452 switch (ElementBitwidth) {
453 case 1: S += "b"; break;
454 case 8: S += "c"; break;
455 case 16: S += "s"; break;
456 case 32: S += "i"; break;
457 case 64: S += "Wi"; break;
458 case 128: S += "LLLi"; break;
459 default: llvm_unreachable("Unhandled case!");
460 }
461 else if (isFloat())
462 switch (ElementBitwidth) {
463 case 16: S += "h"; break;
464 case 32: S += "f"; break;
465 case 64: S += "d"; break;
466 default: llvm_unreachable("Unhandled case!");
467 }
468 else if (isBFloat()) {
469 assert(ElementBitwidth == 16 && "Not a valid BFloat.");
470 S += "y";
471 }
472
473 if (!isFloatingPoint()) {
474 if ((isChar() || isPointer()) && !isVoidPointer()) {
475 // Make chars and typed pointers explicitly signed.
476 if (Signed)
477 S = "S" + S;
478 else if (!Signed)
479 S = "U" + S;
480 } else if (!isVoidPointer() && !Signed) {
481 S = "U" + S;
482 }
483 }
484
485 // Constant indices are "int", but have the "constant expression" modifier.
486 if (isImmediate()) {
487 assert(!isFloat() && "fp immediates are not supported");
488 S = "I" + S;
489 }
490
491 if (isScalar()) {
492 if (Constant) S += "C";
493 if (Pointer) S += "*";
494 return S;
495 }
496
497 if (isFixedLengthVector())
498 return "V" + utostr(getNumElements() * NumVectors) + S;
499 return "q" + utostr(getNumElements() * NumVectors) + S;
500 }
501
str() const502 std::string SVEType::str() const {
503 if (isPredicatePattern())
504 return "enum svpattern";
505
506 if (isPrefetchOp())
507 return "enum svprfop";
508
509 std::string S;
510 if (Void)
511 S += "void";
512 else {
513 if (isScalableVector() || isSvcount())
514 S += "sv";
515 if (!Signed && !isFloatingPoint())
516 S += "u";
517
518 if (Float)
519 S += "float";
520 else if (isSvcount())
521 S += "count";
522 else if (isScalarPredicate() || isPredicateVector())
523 S += "bool";
524 else if (isBFloat())
525 S += "bfloat";
526 else
527 S += "int";
528
529 if (!isScalarPredicate() && !isPredicateVector() && !isSvcount())
530 S += utostr(ElementBitwidth);
531 if (isFixedLengthVector())
532 S += "x" + utostr(getNumElements());
533 if (NumVectors > 1)
534 S += "x" + utostr(NumVectors);
535 if (!isScalarPredicate())
536 S += "_t";
537 }
538
539 if (Constant)
540 S += " const";
541 if (Pointer)
542 S += " *";
543
544 return S;
545 }
546
applyTypespec(StringRef TS)547 void SVEType::applyTypespec(StringRef TS) {
548 for (char I : TS) {
549 switch (I) {
550 case 'Q':
551 Svcount = true;
552 break;
553 case 'P':
554 Predicate = true;
555 break;
556 case 'U':
557 Signed = false;
558 break;
559 case 'c':
560 ElementBitwidth = 8;
561 break;
562 case 's':
563 ElementBitwidth = 16;
564 break;
565 case 'i':
566 ElementBitwidth = 32;
567 break;
568 case 'l':
569 ElementBitwidth = 64;
570 break;
571 case 'q':
572 ElementBitwidth = 128;
573 break;
574 case 'h':
575 Float = true;
576 ElementBitwidth = 16;
577 break;
578 case 'f':
579 Float = true;
580 ElementBitwidth = 32;
581 break;
582 case 'd':
583 Float = true;
584 ElementBitwidth = 64;
585 break;
586 case 'b':
587 BFloat = true;
588 Float = false;
589 ElementBitwidth = 16;
590 break;
591 default:
592 llvm_unreachable("Unhandled type code!");
593 }
594 }
595 assert(ElementBitwidth != ~0U && "Bad element bitwidth!");
596 }
597
applyModifier(char Mod)598 void SVEType::applyModifier(char Mod) {
599 switch (Mod) {
600 case 'v':
601 Void = true;
602 break;
603 case 'd':
604 DefaultType = true;
605 break;
606 case 'c':
607 Constant = true;
608 [[fallthrough]];
609 case 'p':
610 Pointer = true;
611 Bitwidth = ElementBitwidth;
612 NumVectors = 0;
613 break;
614 case 'e':
615 Signed = false;
616 ElementBitwidth /= 2;
617 break;
618 case 'h':
619 ElementBitwidth /= 2;
620 break;
621 case 'q':
622 ElementBitwidth /= 4;
623 break;
624 case 'b':
625 Signed = false;
626 Float = false;
627 BFloat = false;
628 ElementBitwidth /= 4;
629 break;
630 case 'o':
631 ElementBitwidth *= 4;
632 break;
633 case 'P':
634 Signed = true;
635 Float = false;
636 BFloat = false;
637 Predicate = true;
638 Svcount = false;
639 Bitwidth = 16;
640 ElementBitwidth = 1;
641 break;
642 case '{':
643 IsScalable = false;
644 Bitwidth = 128;
645 NumVectors = 1;
646 break;
647 case 's':
648 case 'a':
649 Bitwidth = ElementBitwidth;
650 NumVectors = 0;
651 break;
652 case 'R':
653 ElementBitwidth /= 2;
654 NumVectors = 0;
655 break;
656 case 'r':
657 ElementBitwidth /= 4;
658 NumVectors = 0;
659 break;
660 case '@':
661 Signed = false;
662 Float = false;
663 BFloat = false;
664 ElementBitwidth /= 4;
665 NumVectors = 0;
666 break;
667 case 'K':
668 Signed = true;
669 Float = false;
670 BFloat = false;
671 Bitwidth = ElementBitwidth;
672 NumVectors = 0;
673 break;
674 case 'L':
675 Signed = false;
676 Float = false;
677 BFloat = false;
678 Bitwidth = ElementBitwidth;
679 NumVectors = 0;
680 break;
681 case 'u':
682 Predicate = false;
683 Svcount = false;
684 Signed = false;
685 Float = false;
686 BFloat = false;
687 break;
688 case 'x':
689 Predicate = false;
690 Svcount = false;
691 Signed = true;
692 Float = false;
693 BFloat = false;
694 break;
695 case 'i':
696 Predicate = false;
697 Svcount = false;
698 Float = false;
699 BFloat = false;
700 ElementBitwidth = Bitwidth = 64;
701 NumVectors = 0;
702 Signed = false;
703 Immediate = true;
704 break;
705 case 'I':
706 Predicate = false;
707 Svcount = false;
708 Float = false;
709 BFloat = false;
710 ElementBitwidth = Bitwidth = 32;
711 NumVectors = 0;
712 Signed = true;
713 Immediate = true;
714 PredicatePattern = true;
715 break;
716 case 'J':
717 Predicate = false;
718 Svcount = false;
719 Float = false;
720 BFloat = false;
721 ElementBitwidth = Bitwidth = 32;
722 NumVectors = 0;
723 Signed = true;
724 Immediate = true;
725 PrefetchOp = true;
726 break;
727 case 'k':
728 Predicate = false;
729 Svcount = false;
730 Signed = true;
731 Float = false;
732 BFloat = false;
733 ElementBitwidth = Bitwidth = 32;
734 NumVectors = 0;
735 break;
736 case 'l':
737 Predicate = false;
738 Svcount = false;
739 Signed = true;
740 Float = false;
741 BFloat = false;
742 ElementBitwidth = Bitwidth = 64;
743 NumVectors = 0;
744 break;
745 case 'm':
746 Predicate = false;
747 Svcount = false;
748 Signed = false;
749 Float = false;
750 BFloat = false;
751 ElementBitwidth = Bitwidth = 32;
752 NumVectors = 0;
753 break;
754 case 'n':
755 Predicate = false;
756 Svcount = false;
757 Signed = false;
758 Float = false;
759 BFloat = false;
760 ElementBitwidth = Bitwidth = 64;
761 NumVectors = 0;
762 break;
763 case 'w':
764 ElementBitwidth = 64;
765 break;
766 case 'j':
767 ElementBitwidth = Bitwidth = 64;
768 NumVectors = 0;
769 break;
770 case 'f':
771 Signed = false;
772 ElementBitwidth = Bitwidth = 64;
773 NumVectors = 0;
774 break;
775 case 'g':
776 Signed = false;
777 Float = false;
778 BFloat = false;
779 ElementBitwidth = 64;
780 break;
781 case '[':
782 Signed = false;
783 Float = false;
784 BFloat = false;
785 ElementBitwidth = 8;
786 break;
787 case 't':
788 Signed = true;
789 Float = false;
790 BFloat = false;
791 ElementBitwidth = 32;
792 break;
793 case 'z':
794 Signed = false;
795 Float = false;
796 BFloat = false;
797 ElementBitwidth = 32;
798 break;
799 case 'O':
800 Predicate = false;
801 Svcount = false;
802 Float = true;
803 ElementBitwidth = 16;
804 break;
805 case 'M':
806 Predicate = false;
807 Svcount = false;
808 Float = true;
809 BFloat = false;
810 ElementBitwidth = 32;
811 break;
812 case 'N':
813 Predicate = false;
814 Svcount = false;
815 Float = true;
816 ElementBitwidth = 64;
817 break;
818 case 'Q':
819 Constant = true;
820 Pointer = true;
821 Void = true;
822 NumVectors = 0;
823 break;
824 case 'S':
825 Constant = true;
826 Pointer = true;
827 ElementBitwidth = Bitwidth = 8;
828 NumVectors = 0;
829 Signed = true;
830 break;
831 case 'W':
832 Constant = true;
833 Pointer = true;
834 ElementBitwidth = Bitwidth = 8;
835 NumVectors = 0;
836 Signed = false;
837 break;
838 case 'T':
839 Constant = true;
840 Pointer = true;
841 ElementBitwidth = Bitwidth = 16;
842 NumVectors = 0;
843 Signed = true;
844 break;
845 case 'X':
846 Constant = true;
847 Pointer = true;
848 ElementBitwidth = Bitwidth = 16;
849 NumVectors = 0;
850 Signed = false;
851 break;
852 case 'Y':
853 Constant = true;
854 Pointer = true;
855 ElementBitwidth = Bitwidth = 32;
856 NumVectors = 0;
857 Signed = false;
858 break;
859 case 'U':
860 Constant = true;
861 Pointer = true;
862 ElementBitwidth = Bitwidth = 32;
863 NumVectors = 0;
864 Signed = true;
865 break;
866 case '%':
867 Pointer = true;
868 Void = true;
869 NumVectors = 0;
870 break;
871 case 'A':
872 Pointer = true;
873 ElementBitwidth = Bitwidth = 8;
874 NumVectors = 0;
875 Signed = true;
876 break;
877 case 'B':
878 Pointer = true;
879 ElementBitwidth = Bitwidth = 16;
880 NumVectors = 0;
881 Signed = true;
882 break;
883 case 'C':
884 Pointer = true;
885 ElementBitwidth = Bitwidth = 32;
886 NumVectors = 0;
887 Signed = true;
888 break;
889 case 'D':
890 Pointer = true;
891 ElementBitwidth = Bitwidth = 64;
892 NumVectors = 0;
893 Signed = true;
894 break;
895 case 'E':
896 Pointer = true;
897 ElementBitwidth = Bitwidth = 8;
898 NumVectors = 0;
899 Signed = false;
900 break;
901 case 'F':
902 Pointer = true;
903 ElementBitwidth = Bitwidth = 16;
904 NumVectors = 0;
905 Signed = false;
906 break;
907 case 'G':
908 Pointer = true;
909 ElementBitwidth = Bitwidth = 32;
910 NumVectors = 0;
911 Signed = false;
912 break;
913 case '$':
914 Predicate = false;
915 Svcount = false;
916 Float = false;
917 BFloat = true;
918 ElementBitwidth = 16;
919 break;
920 case '}':
921 Predicate = false;
922 Signed = true;
923 Svcount = true;
924 NumVectors = 0;
925 Float = false;
926 BFloat = false;
927 break;
928 case '.':
929 llvm_unreachable(". is never a type in itself");
930 break;
931 default:
932 llvm_unreachable("Unhandled character!");
933 }
934 }
935
936 /// Returns the modifier and number of vectors for the given operand \p Op.
getProtoModifier(StringRef Proto,unsigned Op)937 std::pair<char, unsigned> getProtoModifier(StringRef Proto, unsigned Op) {
938 for (unsigned P = 0; !Proto.empty(); ++P) {
939 unsigned NumVectors = 1;
940 unsigned CharsToSkip = 1;
941 char Mod = Proto[0];
942 if (Mod == '2' || Mod == '3' || Mod == '4') {
943 NumVectors = Mod - '0';
944 Mod = 'd';
945 if (Proto.size() > 1 && Proto[1] == '.') {
946 Mod = Proto[2];
947 CharsToSkip = 3;
948 }
949 }
950
951 if (P == Op)
952 return {Mod, NumVectors};
953
954 Proto = Proto.drop_front(CharsToSkip);
955 }
956 llvm_unreachable("Unexpected Op");
957 }
958
959 //===----------------------------------------------------------------------===//
960 // Intrinsic implementation
961 //===----------------------------------------------------------------------===//
962
Intrinsic(StringRef Name,StringRef Proto,uint64_t MergeTy,StringRef MergeSuffix,uint64_t MemoryElementTy,StringRef LLVMName,uint64_t Flags,ArrayRef<ImmCheck> Checks,TypeSpec BT,ClassKind Class,SVEEmitter & Emitter,StringRef SVEGuard,StringRef SMEGuard)963 Intrinsic::Intrinsic(StringRef Name, StringRef Proto, uint64_t MergeTy,
964 StringRef MergeSuffix, uint64_t MemoryElementTy,
965 StringRef LLVMName, uint64_t Flags,
966 ArrayRef<ImmCheck> Checks, TypeSpec BT, ClassKind Class,
967 SVEEmitter &Emitter, StringRef SVEGuard,
968 StringRef SMEGuard)
969 : Name(Name.str()), LLVMName(LLVMName), Proto(Proto.str()),
970 BaseTypeSpec(BT), Class(Class), SVEGuard(SVEGuard.str()),
971 SMEGuard(SMEGuard.str()), MergeSuffix(MergeSuffix.str()),
972 BaseType(BT, 'd'), Flags(Flags), ImmChecks(Checks.begin(), Checks.end()) {
973 // Types[0] is the return value.
974 for (unsigned I = 0; I < (getNumParams() + 1); ++I) {
975 char Mod;
976 unsigned NumVectors;
977 std::tie(Mod, NumVectors) = getProtoModifier(Proto, I);
978 SVEType T(BaseTypeSpec, Mod, NumVectors);
979 Types.push_back(T);
980
981 // Add range checks for immediates
982 if (I > 0) {
983 if (T.isPredicatePattern())
984 ImmChecks.emplace_back(
985 I - 1, Emitter.getEnumValueForImmCheck("ImmCheck0_31"));
986 else if (T.isPrefetchOp())
987 ImmChecks.emplace_back(
988 I - 1, Emitter.getEnumValueForImmCheck("ImmCheck0_13"));
989 }
990 }
991
992 // Set flags based on properties
993 this->Flags |= Emitter.encodeTypeFlags(BaseType);
994 this->Flags |= Emitter.encodeMemoryElementType(MemoryElementTy);
995 this->Flags |= Emitter.encodeMergeType(MergeTy);
996 if (hasSplat())
997 this->Flags |= Emitter.encodeSplatOperand(getSplatIdx());
998 }
999
getBuiltinTypeStr()1000 std::string Intrinsic::getBuiltinTypeStr() {
1001 std::string S = getReturnType().builtin_str();
1002 for (unsigned I = 0; I < getNumParams(); ++I)
1003 S += getParamType(I).builtin_str();
1004
1005 return S;
1006 }
1007
replaceTemplatedArgs(std::string Name,TypeSpec TS,std::string Proto) const1008 std::string Intrinsic::replaceTemplatedArgs(std::string Name, TypeSpec TS,
1009 std::string Proto) const {
1010 std::string Ret = Name;
1011 while (Ret.find('{') != std::string::npos) {
1012 size_t Pos = Ret.find('{');
1013 size_t End = Ret.find('}');
1014 unsigned NumChars = End - Pos + 1;
1015 assert(NumChars == 3 && "Unexpected template argument");
1016
1017 SVEType T;
1018 char C = Ret[Pos+1];
1019 switch(C) {
1020 default:
1021 llvm_unreachable("Unknown predication specifier");
1022 case 'd':
1023 T = SVEType(TS, 'd');
1024 break;
1025 case '0':
1026 case '1':
1027 case '2':
1028 case '3':
1029 T = SVEType(TS, Proto[C - '0']);
1030 break;
1031 }
1032
1033 // Replace templated arg with the right suffix (e.g. u32)
1034 std::string TypeCode;
1035 if (T.isInteger())
1036 TypeCode = T.isSigned() ? 's' : 'u';
1037 else if (T.isSvcount())
1038 TypeCode = 'c';
1039 else if (T.isPredicateVector())
1040 TypeCode = 'b';
1041 else if (T.isBFloat())
1042 TypeCode = "bf";
1043 else
1044 TypeCode = 'f';
1045 Ret.replace(Pos, NumChars, TypeCode + utostr(T.getElementSizeInBits()));
1046 }
1047
1048 return Ret;
1049 }
1050
mangleLLVMName() const1051 std::string Intrinsic::mangleLLVMName() const {
1052 std::string S = getLLVMName();
1053
1054 // Replace all {d} like expressions with e.g. 'u32'
1055 return replaceTemplatedArgs(S, getBaseTypeSpec(), getProto());
1056 }
1057
mangleName(ClassKind LocalCK) const1058 std::string Intrinsic::mangleName(ClassKind LocalCK) const {
1059 std::string S = getName();
1060
1061 if (LocalCK == ClassG) {
1062 // Remove the square brackets and everything in between.
1063 while (S.find('[') != std::string::npos) {
1064 auto Start = S.find('[');
1065 auto End = S.find(']');
1066 S.erase(Start, (End-Start)+1);
1067 }
1068 } else {
1069 // Remove the square brackets.
1070 while (S.find('[') != std::string::npos) {
1071 auto BrPos = S.find('[');
1072 if (BrPos != std::string::npos)
1073 S.erase(BrPos, 1);
1074 BrPos = S.find(']');
1075 if (BrPos != std::string::npos)
1076 S.erase(BrPos, 1);
1077 }
1078 }
1079
1080 // Replace all {d} like expressions with e.g. 'u32'
1081 return replaceTemplatedArgs(S, getBaseTypeSpec(), getProto()) +
1082 getMergeSuffix();
1083 }
1084
emitIntrinsic(raw_ostream & OS,SVEEmitter & Emitter,ACLEKind Kind) const1085 void Intrinsic::emitIntrinsic(raw_ostream &OS, SVEEmitter &Emitter,
1086 ACLEKind Kind) const {
1087 bool IsOverloaded = getClassKind() == ClassG && getProto().size() > 1;
1088
1089 std::string FullName = mangleName(ClassS);
1090 std::string ProtoName = mangleName(getClassKind());
1091 OS << (IsOverloaded ? "__aio " : "__ai ")
1092 << "__attribute__((__clang_arm_builtin_alias(";
1093
1094 switch (Kind) {
1095 case ACLEKind::SME:
1096 OS << "__builtin_sme_" << FullName << ")";
1097 break;
1098 case ACLEKind::SVE:
1099 OS << "__builtin_sve_" << FullName << ")";
1100 break;
1101 }
1102
1103 OS << "))\n";
1104
1105 OS << getTypes()[0].str() << " " << ProtoName << "(";
1106 for (unsigned I = 0; I < getTypes().size() - 1; ++I) {
1107 if (I != 0)
1108 OS << ", ";
1109 OS << getTypes()[I + 1].str();
1110 }
1111 OS << ");\n";
1112 }
1113
1114 //===----------------------------------------------------------------------===//
1115 // SVEEmitter implementation
1116 //===----------------------------------------------------------------------===//
encodeTypeFlags(const SVEType & T)1117 uint64_t SVEEmitter::encodeTypeFlags(const SVEType &T) {
1118 if (T.isFloat()) {
1119 switch (T.getElementSizeInBits()) {
1120 case 16:
1121 return encodeEltType("EltTyFloat16");
1122 case 32:
1123 return encodeEltType("EltTyFloat32");
1124 case 64:
1125 return encodeEltType("EltTyFloat64");
1126 default:
1127 llvm_unreachable("Unhandled float element bitwidth!");
1128 }
1129 }
1130
1131 if (T.isBFloat()) {
1132 assert(T.getElementSizeInBits() == 16 && "Not a valid BFloat.");
1133 return encodeEltType("EltTyBFloat16");
1134 }
1135
1136 if (T.isPredicateVector() || T.isSvcount()) {
1137 switch (T.getElementSizeInBits()) {
1138 case 8:
1139 return encodeEltType("EltTyBool8");
1140 case 16:
1141 return encodeEltType("EltTyBool16");
1142 case 32:
1143 return encodeEltType("EltTyBool32");
1144 case 64:
1145 return encodeEltType("EltTyBool64");
1146 default:
1147 llvm_unreachable("Unhandled predicate element bitwidth!");
1148 }
1149 }
1150
1151 switch (T.getElementSizeInBits()) {
1152 case 8:
1153 return encodeEltType("EltTyInt8");
1154 case 16:
1155 return encodeEltType("EltTyInt16");
1156 case 32:
1157 return encodeEltType("EltTyInt32");
1158 case 64:
1159 return encodeEltType("EltTyInt64");
1160 case 128:
1161 return encodeEltType("EltTyInt128");
1162 default:
1163 llvm_unreachable("Unhandled integer element bitwidth!");
1164 }
1165 }
1166
createIntrinsic(Record * R,SmallVectorImpl<std::unique_ptr<Intrinsic>> & Out)1167 void SVEEmitter::createIntrinsic(
1168 Record *R, SmallVectorImpl<std::unique_ptr<Intrinsic>> &Out) {
1169 StringRef Name = R->getValueAsString("Name");
1170 StringRef Proto = R->getValueAsString("Prototype");
1171 StringRef Types = R->getValueAsString("Types");
1172 StringRef SVEGuard = R->getValueAsString("SVETargetGuard");
1173 StringRef SMEGuard = R->getValueAsString("SMETargetGuard");
1174 StringRef LLVMName = R->getValueAsString("LLVMIntrinsic");
1175 uint64_t Merge = R->getValueAsInt("Merge");
1176 StringRef MergeSuffix = R->getValueAsString("MergeSuffix");
1177 uint64_t MemEltType = R->getValueAsInt("MemEltType");
1178 std::vector<Record*> FlagsList = R->getValueAsListOfDefs("Flags");
1179 std::vector<Record*> ImmCheckList = R->getValueAsListOfDefs("ImmChecks");
1180
1181 int64_t Flags = 0;
1182 for (auto FlagRec : FlagsList)
1183 Flags |= FlagRec->getValueAsInt("Value");
1184
1185 // Create a dummy TypeSpec for non-overloaded builtins.
1186 if (Types.empty()) {
1187 assert((Flags & getEnumValueForFlag("IsOverloadNone")) &&
1188 "Expect TypeSpec for overloaded builtin!");
1189 Types = "i";
1190 }
1191
1192 // Extract type specs from string
1193 SmallVector<TypeSpec, 8> TypeSpecs;
1194 TypeSpec Acc;
1195 for (char I : Types) {
1196 Acc.push_back(I);
1197 if (islower(I)) {
1198 TypeSpecs.push_back(TypeSpec(Acc));
1199 Acc.clear();
1200 }
1201 }
1202
1203 // Remove duplicate type specs.
1204 llvm::sort(TypeSpecs);
1205 TypeSpecs.erase(std::unique(TypeSpecs.begin(), TypeSpecs.end()),
1206 TypeSpecs.end());
1207
1208 // Create an Intrinsic for each type spec.
1209 for (auto TS : TypeSpecs) {
1210 // Collate a list of range/option checks for the immediates.
1211 SmallVector<ImmCheck, 2> ImmChecks;
1212 for (auto *R : ImmCheckList) {
1213 int64_t Arg = R->getValueAsInt("Arg");
1214 int64_t EltSizeArg = R->getValueAsInt("EltSizeArg");
1215 int64_t Kind = R->getValueAsDef("Kind")->getValueAsInt("Value");
1216 assert(Arg >= 0 && Kind >= 0 && "Arg and Kind must be nonnegative");
1217
1218 unsigned ElementSizeInBits = 0;
1219 char Mod;
1220 unsigned NumVectors;
1221 std::tie(Mod, NumVectors) = getProtoModifier(Proto, EltSizeArg + 1);
1222 if (EltSizeArg >= 0)
1223 ElementSizeInBits = SVEType(TS, Mod, NumVectors).getElementSizeInBits();
1224 ImmChecks.push_back(ImmCheck(Arg, Kind, ElementSizeInBits));
1225 }
1226
1227 Out.push_back(std::make_unique<Intrinsic>(
1228 Name, Proto, Merge, MergeSuffix, MemEltType, LLVMName, Flags, ImmChecks,
1229 TS, ClassS, *this, SVEGuard, SMEGuard));
1230
1231 // Also generate the short-form (e.g. svadd_m) for the given type-spec.
1232 if (Intrinsic::isOverloadedIntrinsic(Name))
1233 Out.push_back(std::make_unique<Intrinsic>(
1234 Name, Proto, Merge, MergeSuffix, MemEltType, LLVMName, Flags,
1235 ImmChecks, TS, ClassG, *this, SVEGuard, SMEGuard));
1236 }
1237 }
1238
createCoreHeaderIntrinsics(raw_ostream & OS,SVEEmitter & Emitter,ACLEKind Kind)1239 void SVEEmitter::createCoreHeaderIntrinsics(raw_ostream &OS,
1240 SVEEmitter &Emitter,
1241 ACLEKind Kind) {
1242 SmallVector<std::unique_ptr<Intrinsic>, 128> Defs;
1243 std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst");
1244 for (auto *R : RV)
1245 createIntrinsic(R, Defs);
1246
1247 // Sort intrinsics in header file by following order/priority:
1248 // - Architectural guard (i.e. does it require SVE2 or SVE2_AES)
1249 // - Class (is intrinsic overloaded or not)
1250 // - Intrinsic name
1251 std::stable_sort(Defs.begin(), Defs.end(),
1252 [](const std::unique_ptr<Intrinsic> &A,
1253 const std::unique_ptr<Intrinsic> &B) {
1254 auto ToTuple = [](const std::unique_ptr<Intrinsic> &I) {
1255 return std::make_tuple(
1256 I->getSVEGuard().str() + I->getSMEGuard().str(),
1257 (unsigned)I->getClassKind(), I->getName());
1258 };
1259 return ToTuple(A) < ToTuple(B);
1260 });
1261
1262 // Actually emit the intrinsic declarations.
1263 for (auto &I : Defs)
1264 I->emitIntrinsic(OS, Emitter, Kind);
1265 }
1266
createHeader(raw_ostream & OS)1267 void SVEEmitter::createHeader(raw_ostream &OS) {
1268 OS << "/*===---- arm_sve.h - ARM SVE intrinsics "
1269 "-----------------------------------===\n"
1270 " *\n"
1271 " *\n"
1272 " * Part of the LLVM Project, under the Apache License v2.0 with LLVM "
1273 "Exceptions.\n"
1274 " * See https://llvm.org/LICENSE.txt for license information.\n"
1275 " * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception\n"
1276 " *\n"
1277 " *===-----------------------------------------------------------------"
1278 "------===\n"
1279 " */\n\n";
1280
1281 OS << "#ifndef __ARM_SVE_H\n";
1282 OS << "#define __ARM_SVE_H\n\n";
1283
1284 OS << "#if !defined(__LITTLE_ENDIAN__)\n";
1285 OS << "#error \"Big endian is currently not supported for arm_sve.h\"\n";
1286 OS << "#endif\n";
1287
1288 OS << "#include <stdint.h>\n\n";
1289 OS << "#ifdef __cplusplus\n";
1290 OS << "extern \"C\" {\n";
1291 OS << "#else\n";
1292 OS << "#include <stdbool.h>\n";
1293 OS << "#endif\n\n";
1294
1295 OS << "typedef __fp16 float16_t;\n";
1296 OS << "typedef float float32_t;\n";
1297 OS << "typedef double float64_t;\n";
1298
1299 OS << "typedef __SVInt8_t svint8_t;\n";
1300 OS << "typedef __SVInt16_t svint16_t;\n";
1301 OS << "typedef __SVInt32_t svint32_t;\n";
1302 OS << "typedef __SVInt64_t svint64_t;\n";
1303 OS << "typedef __SVUint8_t svuint8_t;\n";
1304 OS << "typedef __SVUint16_t svuint16_t;\n";
1305 OS << "typedef __SVUint32_t svuint32_t;\n";
1306 OS << "typedef __SVUint64_t svuint64_t;\n";
1307 OS << "typedef __SVFloat16_t svfloat16_t;\n\n";
1308
1309 OS << "typedef __SVBfloat16_t svbfloat16_t;\n";
1310
1311 OS << "#include <arm_bf16.h>\n";
1312 OS << "#include <arm_vector_types.h>\n";
1313
1314 OS << "typedef __SVFloat32_t svfloat32_t;\n";
1315 OS << "typedef __SVFloat64_t svfloat64_t;\n";
1316 OS << "typedef __clang_svint8x2_t svint8x2_t;\n";
1317 OS << "typedef __clang_svint16x2_t svint16x2_t;\n";
1318 OS << "typedef __clang_svint32x2_t svint32x2_t;\n";
1319 OS << "typedef __clang_svint64x2_t svint64x2_t;\n";
1320 OS << "typedef __clang_svuint8x2_t svuint8x2_t;\n";
1321 OS << "typedef __clang_svuint16x2_t svuint16x2_t;\n";
1322 OS << "typedef __clang_svuint32x2_t svuint32x2_t;\n";
1323 OS << "typedef __clang_svuint64x2_t svuint64x2_t;\n";
1324 OS << "typedef __clang_svfloat16x2_t svfloat16x2_t;\n";
1325 OS << "typedef __clang_svfloat32x2_t svfloat32x2_t;\n";
1326 OS << "typedef __clang_svfloat64x2_t svfloat64x2_t;\n";
1327 OS << "typedef __clang_svint8x3_t svint8x3_t;\n";
1328 OS << "typedef __clang_svint16x3_t svint16x3_t;\n";
1329 OS << "typedef __clang_svint32x3_t svint32x3_t;\n";
1330 OS << "typedef __clang_svint64x3_t svint64x3_t;\n";
1331 OS << "typedef __clang_svuint8x3_t svuint8x3_t;\n";
1332 OS << "typedef __clang_svuint16x3_t svuint16x3_t;\n";
1333 OS << "typedef __clang_svuint32x3_t svuint32x3_t;\n";
1334 OS << "typedef __clang_svuint64x3_t svuint64x3_t;\n";
1335 OS << "typedef __clang_svfloat16x3_t svfloat16x3_t;\n";
1336 OS << "typedef __clang_svfloat32x3_t svfloat32x3_t;\n";
1337 OS << "typedef __clang_svfloat64x3_t svfloat64x3_t;\n";
1338 OS << "typedef __clang_svint8x4_t svint8x4_t;\n";
1339 OS << "typedef __clang_svint16x4_t svint16x4_t;\n";
1340 OS << "typedef __clang_svint32x4_t svint32x4_t;\n";
1341 OS << "typedef __clang_svint64x4_t svint64x4_t;\n";
1342 OS << "typedef __clang_svuint8x4_t svuint8x4_t;\n";
1343 OS << "typedef __clang_svuint16x4_t svuint16x4_t;\n";
1344 OS << "typedef __clang_svuint32x4_t svuint32x4_t;\n";
1345 OS << "typedef __clang_svuint64x4_t svuint64x4_t;\n";
1346 OS << "typedef __clang_svfloat16x4_t svfloat16x4_t;\n";
1347 OS << "typedef __clang_svfloat32x4_t svfloat32x4_t;\n";
1348 OS << "typedef __clang_svfloat64x4_t svfloat64x4_t;\n";
1349 OS << "typedef __SVBool_t svbool_t;\n";
1350 OS << "typedef __clang_svboolx2_t svboolx2_t;\n";
1351 OS << "typedef __clang_svboolx4_t svboolx4_t;\n\n";
1352
1353 OS << "typedef __clang_svbfloat16x2_t svbfloat16x2_t;\n";
1354 OS << "typedef __clang_svbfloat16x3_t svbfloat16x3_t;\n";
1355 OS << "typedef __clang_svbfloat16x4_t svbfloat16x4_t;\n";
1356
1357 OS << "typedef __SVCount_t svcount_t;\n\n";
1358
1359 OS << "enum svpattern\n";
1360 OS << "{\n";
1361 OS << " SV_POW2 = 0,\n";
1362 OS << " SV_VL1 = 1,\n";
1363 OS << " SV_VL2 = 2,\n";
1364 OS << " SV_VL3 = 3,\n";
1365 OS << " SV_VL4 = 4,\n";
1366 OS << " SV_VL5 = 5,\n";
1367 OS << " SV_VL6 = 6,\n";
1368 OS << " SV_VL7 = 7,\n";
1369 OS << " SV_VL8 = 8,\n";
1370 OS << " SV_VL16 = 9,\n";
1371 OS << " SV_VL32 = 10,\n";
1372 OS << " SV_VL64 = 11,\n";
1373 OS << " SV_VL128 = 12,\n";
1374 OS << " SV_VL256 = 13,\n";
1375 OS << " SV_MUL4 = 29,\n";
1376 OS << " SV_MUL3 = 30,\n";
1377 OS << " SV_ALL = 31\n";
1378 OS << "};\n\n";
1379
1380 OS << "enum svprfop\n";
1381 OS << "{\n";
1382 OS << " SV_PLDL1KEEP = 0,\n";
1383 OS << " SV_PLDL1STRM = 1,\n";
1384 OS << " SV_PLDL2KEEP = 2,\n";
1385 OS << " SV_PLDL2STRM = 3,\n";
1386 OS << " SV_PLDL3KEEP = 4,\n";
1387 OS << " SV_PLDL3STRM = 5,\n";
1388 OS << " SV_PSTL1KEEP = 8,\n";
1389 OS << " SV_PSTL1STRM = 9,\n";
1390 OS << " SV_PSTL2KEEP = 10,\n";
1391 OS << " SV_PSTL2STRM = 11,\n";
1392 OS << " SV_PSTL3KEEP = 12,\n";
1393 OS << " SV_PSTL3STRM = 13\n";
1394 OS << "};\n\n";
1395
1396 OS << "/* Function attributes */\n";
1397 OS << "#define __ai static __inline__ __attribute__((__always_inline__, "
1398 "__nodebug__))\n\n";
1399 OS << "#define __aio static __inline__ __attribute__((__always_inline__, "
1400 "__nodebug__, __overloadable__))\n\n";
1401
1402 // Add reinterpret functions.
1403 for (auto [N, Suffix] :
1404 std::initializer_list<std::pair<unsigned, const char *>>{
1405 {1, ""}, {2, "_x2"}, {3, "_x3"}, {4, "_x4"}}) {
1406 for (auto ShortForm : {false, true})
1407 for (const ReinterpretTypeInfo &To : Reinterprets) {
1408 SVEType ToV(To.BaseType, N);
1409 for (const ReinterpretTypeInfo &From : Reinterprets) {
1410 SVEType FromV(From.BaseType, N);
1411 OS << "__aio "
1412 "__attribute__((__clang_arm_builtin_alias(__builtin_sve_"
1413 "reinterpret_"
1414 << To.Suffix << "_" << From.Suffix << Suffix << ")))\n"
1415 << ToV.str() << " svreinterpret_" << To.Suffix;
1416 if (!ShortForm)
1417 OS << "_" << From.Suffix << Suffix;
1418 OS << "(" << FromV.str() << " op);\n";
1419 }
1420 }
1421 }
1422
1423 createCoreHeaderIntrinsics(OS, *this, ACLEKind::SVE);
1424
1425 OS << "#define svcvtnt_bf16_x svcvtnt_bf16_m\n";
1426 OS << "#define svcvtnt_bf16_f32_x svcvtnt_bf16_f32_m\n";
1427
1428 OS << "#define svcvtnt_f16_x svcvtnt_f16_m\n";
1429 OS << "#define svcvtnt_f16_f32_x svcvtnt_f16_f32_m\n";
1430 OS << "#define svcvtnt_f32_x svcvtnt_f32_m\n";
1431 OS << "#define svcvtnt_f32_f64_x svcvtnt_f32_f64_m\n\n";
1432
1433 OS << "#define svcvtxnt_f32_x svcvtxnt_f32_m\n";
1434 OS << "#define svcvtxnt_f32_f64_x svcvtxnt_f32_f64_m\n\n";
1435
1436 OS << "#ifdef __cplusplus\n";
1437 OS << "} // extern \"C\"\n";
1438 OS << "#endif\n\n";
1439 OS << "#undef __ai\n\n";
1440 OS << "#undef __aio\n\n";
1441 OS << "#endif /* __ARM_SVE_H */\n";
1442 }
1443
createBuiltins(raw_ostream & OS)1444 void SVEEmitter::createBuiltins(raw_ostream &OS) {
1445 std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst");
1446 SmallVector<std::unique_ptr<Intrinsic>, 128> Defs;
1447 for (auto *R : RV)
1448 createIntrinsic(R, Defs);
1449
1450 // The mappings must be sorted based on BuiltinID.
1451 llvm::sort(Defs, [](const std::unique_ptr<Intrinsic> &A,
1452 const std::unique_ptr<Intrinsic> &B) {
1453 return A->getMangledName() < B->getMangledName();
1454 });
1455
1456 OS << "#ifdef GET_SVE_BUILTINS\n";
1457 for (auto &Def : Defs) {
1458 // Only create BUILTINs for non-overloaded intrinsics, as overloaded
1459 // declarations only live in the header file.
1460 if (Def->getClassKind() != ClassG) {
1461 OS << "TARGET_BUILTIN(__builtin_sve_" << Def->getMangledName() << ", \""
1462 << Def->getBuiltinTypeStr() << "\", \"n\", \"";
1463 Def->printGuard(OS);
1464 OS << "\")\n";
1465 }
1466 }
1467
1468 // Add reinterpret functions.
1469 for (auto [N, Suffix] :
1470 std::initializer_list<std::pair<unsigned, const char *>>{
1471 {1, ""}, {2, "_x2"}, {3, "_x3"}, {4, "_x4"}}) {
1472 for (const ReinterpretTypeInfo &To : Reinterprets) {
1473 SVEType ToV(To.BaseType, N);
1474 for (const ReinterpretTypeInfo &From : Reinterprets) {
1475 SVEType FromV(From.BaseType, N);
1476 OS << "TARGET_BUILTIN(__builtin_sve_reinterpret_" << To.Suffix << "_"
1477 << From.Suffix << Suffix << +", \"" << ToV.builtin_str()
1478 << FromV.builtin_str() << "\", \"n\", \"sme|sve\")\n";
1479 }
1480 }
1481 }
1482
1483 OS << "#endif\n\n";
1484 }
1485
createCodeGenMap(raw_ostream & OS)1486 void SVEEmitter::createCodeGenMap(raw_ostream &OS) {
1487 std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst");
1488 SmallVector<std::unique_ptr<Intrinsic>, 128> Defs;
1489 for (auto *R : RV)
1490 createIntrinsic(R, Defs);
1491
1492 // The mappings must be sorted based on BuiltinID.
1493 llvm::sort(Defs, [](const std::unique_ptr<Intrinsic> &A,
1494 const std::unique_ptr<Intrinsic> &B) {
1495 return A->getMangledName() < B->getMangledName();
1496 });
1497
1498 OS << "#ifdef GET_SVE_LLVM_INTRINSIC_MAP\n";
1499 for (auto &Def : Defs) {
1500 // Builtins only exist for non-overloaded intrinsics, overloaded
1501 // declarations only live in the header file.
1502 if (Def->getClassKind() == ClassG)
1503 continue;
1504
1505 uint64_t Flags = Def->getFlags();
1506 auto FlagString = std::to_string(Flags);
1507
1508 std::string LLVMName = Def->getMangledLLVMName();
1509 std::string Builtin = Def->getMangledName();
1510 if (!LLVMName.empty())
1511 OS << "SVEMAP1(" << Builtin << ", " << LLVMName << ", " << FlagString
1512 << "),\n";
1513 else
1514 OS << "SVEMAP2(" << Builtin << ", " << FlagString << "),\n";
1515 }
1516 OS << "#endif\n\n";
1517 }
1518
createRangeChecks(raw_ostream & OS)1519 void SVEEmitter::createRangeChecks(raw_ostream &OS) {
1520 std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst");
1521 SmallVector<std::unique_ptr<Intrinsic>, 128> Defs;
1522 for (auto *R : RV)
1523 createIntrinsic(R, Defs);
1524
1525 // The mappings must be sorted based on BuiltinID.
1526 llvm::sort(Defs, [](const std::unique_ptr<Intrinsic> &A,
1527 const std::unique_ptr<Intrinsic> &B) {
1528 return A->getMangledName() < B->getMangledName();
1529 });
1530
1531
1532 OS << "#ifdef GET_SVE_IMMEDIATE_CHECK\n";
1533
1534 // Ensure these are only emitted once.
1535 std::set<std::string> Emitted;
1536
1537 for (auto &Def : Defs) {
1538 if (Emitted.find(Def->getMangledName()) != Emitted.end() ||
1539 Def->getImmChecks().empty())
1540 continue;
1541
1542 OS << "case SVE::BI__builtin_sve_" << Def->getMangledName() << ":\n";
1543 for (auto &Check : Def->getImmChecks())
1544 OS << "ImmChecks.push_back(std::make_tuple(" << Check.getArg() << ", "
1545 << Check.getKind() << ", " << Check.getElementSizeInBits() << "));\n";
1546 OS << " break;\n";
1547
1548 Emitted.insert(Def->getMangledName());
1549 }
1550
1551 OS << "#endif\n\n";
1552 }
1553
1554 /// Create the SVETypeFlags used in CGBuiltins
createTypeFlags(raw_ostream & OS)1555 void SVEEmitter::createTypeFlags(raw_ostream &OS) {
1556 OS << "#ifdef LLVM_GET_SVE_TYPEFLAGS\n";
1557 for (auto &KV : FlagTypes)
1558 OS << "const uint64_t " << KV.getKey() << " = " << KV.getValue() << ";\n";
1559 OS << "#endif\n\n";
1560
1561 OS << "#ifdef LLVM_GET_SVE_ELTTYPES\n";
1562 for (auto &KV : EltTypes)
1563 OS << " " << KV.getKey() << " = " << KV.getValue() << ",\n";
1564 OS << "#endif\n\n";
1565
1566 OS << "#ifdef LLVM_GET_SVE_MEMELTTYPES\n";
1567 for (auto &KV : MemEltTypes)
1568 OS << " " << KV.getKey() << " = " << KV.getValue() << ",\n";
1569 OS << "#endif\n\n";
1570
1571 OS << "#ifdef LLVM_GET_SVE_MERGETYPES\n";
1572 for (auto &KV : MergeTypes)
1573 OS << " " << KV.getKey() << " = " << KV.getValue() << ",\n";
1574 OS << "#endif\n\n";
1575
1576 OS << "#ifdef LLVM_GET_SVE_IMMCHECKTYPES\n";
1577 for (auto &KV : ImmCheckTypes)
1578 OS << " " << KV.getKey() << " = " << KV.getValue() << ",\n";
1579 OS << "#endif\n\n";
1580 }
1581
createSMEHeader(raw_ostream & OS)1582 void SVEEmitter::createSMEHeader(raw_ostream &OS) {
1583 OS << "/*===---- arm_sme.h - ARM SME intrinsics "
1584 "------===\n"
1585 " *\n"
1586 " *\n"
1587 " * Part of the LLVM Project, under the Apache License v2.0 with LLVM "
1588 "Exceptions.\n"
1589 " * See https://llvm.org/LICENSE.txt for license information.\n"
1590 " * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception\n"
1591 " *\n"
1592 " *===-----------------------------------------------------------------"
1593 "------===\n"
1594 " */\n\n";
1595
1596 OS << "#ifndef __ARM_SME_H\n";
1597 OS << "#define __ARM_SME_H\n\n";
1598
1599 OS << "#if !defined(__LITTLE_ENDIAN__)\n";
1600 OS << "#error \"Big endian is currently not supported for arm_sme.h\"\n";
1601 OS << "#endif\n";
1602
1603 OS << "#include <arm_sve.h>\n\n";
1604 OS << "#include <stddef.h>\n\n";
1605
1606 OS << "/* Function attributes */\n";
1607 OS << "#define __ai static __inline__ __attribute__((__always_inline__, "
1608 "__nodebug__))\n\n";
1609 OS << "#define __aio static __inline__ __attribute__((__always_inline__, "
1610 "__nodebug__, __overloadable__))\n\n";
1611
1612 OS << "#ifdef __cplusplus\n";
1613 OS << "extern \"C\" {\n";
1614 OS << "#endif\n\n";
1615
1616 OS << "void __arm_za_disable(void) __arm_streaming_compatible;\n\n";
1617
1618 OS << "__ai bool __arm_has_sme(void) __arm_streaming_compatible {\n";
1619 OS << " uint64_t x0, x1;\n";
1620 OS << " __builtin_arm_get_sme_state(&x0, &x1);\n";
1621 OS << " return x0 & (1ULL << 63);\n";
1622 OS << "}\n\n";
1623
1624 OS << "__ai bool __arm_in_streaming_mode(void) __arm_streaming_compatible "
1625 "{\n";
1626 OS << " uint64_t x0, x1;\n";
1627 OS << " __builtin_arm_get_sme_state(&x0, &x1);\n";
1628 OS << " return x0 & 1;\n";
1629 OS << "}\n\n";
1630
1631 OS << "void *__arm_sc_memcpy(void *dest, const void *src, size_t n) __arm_streaming_compatible;\n";
1632 OS << "void *__arm_sc_memmove(void *dest, const void *src, size_t n) __arm_streaming_compatible;\n";
1633 OS << "void *__arm_sc_memset(void *s, int c, size_t n) __arm_streaming_compatible;\n";
1634 OS << "void *__arm_sc_memchr(void *s, int c, size_t n) __arm_streaming_compatible;\n\n";
1635
1636 OS << "__ai __attribute__((target(\"sme\"))) void svundef_za(void) "
1637 "__arm_streaming_compatible __arm_out(\"za\") "
1638 "{ }\n\n";
1639
1640 createCoreHeaderIntrinsics(OS, *this, ACLEKind::SME);
1641
1642 OS << "#ifdef __cplusplus\n";
1643 OS << "} // extern \"C\"\n";
1644 OS << "#endif\n\n";
1645 OS << "#undef __ai\n\n";
1646 OS << "#endif /* __ARM_SME_H */\n";
1647 }
1648
createSMEBuiltins(raw_ostream & OS)1649 void SVEEmitter::createSMEBuiltins(raw_ostream &OS) {
1650 std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst");
1651 SmallVector<std::unique_ptr<Intrinsic>, 128> Defs;
1652 for (auto *R : RV) {
1653 createIntrinsic(R, Defs);
1654 }
1655
1656 // The mappings must be sorted based on BuiltinID.
1657 llvm::sort(Defs, [](const std::unique_ptr<Intrinsic> &A,
1658 const std::unique_ptr<Intrinsic> &B) {
1659 return A->getMangledName() < B->getMangledName();
1660 });
1661
1662 OS << "#ifdef GET_SME_BUILTINS\n";
1663 for (auto &Def : Defs) {
1664 // Only create BUILTINs for non-overloaded intrinsics, as overloaded
1665 // declarations only live in the header file.
1666 if (Def->getClassKind() != ClassG) {
1667 OS << "TARGET_BUILTIN(__builtin_sme_" << Def->getMangledName() << ", \""
1668 << Def->getBuiltinTypeStr() << "\", \"n\", \"";
1669 Def->printGuard(OS);
1670 OS << "\")\n";
1671 }
1672 }
1673
1674 OS << "#endif\n\n";
1675 }
1676
createSMECodeGenMap(raw_ostream & OS)1677 void SVEEmitter::createSMECodeGenMap(raw_ostream &OS) {
1678 std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst");
1679 SmallVector<std::unique_ptr<Intrinsic>, 128> Defs;
1680 for (auto *R : RV) {
1681 createIntrinsic(R, Defs);
1682 }
1683
1684 // The mappings must be sorted based on BuiltinID.
1685 llvm::sort(Defs, [](const std::unique_ptr<Intrinsic> &A,
1686 const std::unique_ptr<Intrinsic> &B) {
1687 return A->getMangledName() < B->getMangledName();
1688 });
1689
1690 OS << "#ifdef GET_SME_LLVM_INTRINSIC_MAP\n";
1691 for (auto &Def : Defs) {
1692 // Builtins only exist for non-overloaded intrinsics, overloaded
1693 // declarations only live in the header file.
1694 if (Def->getClassKind() == ClassG)
1695 continue;
1696
1697 uint64_t Flags = Def->getFlags();
1698 auto FlagString = std::to_string(Flags);
1699
1700 std::string LLVMName = Def->getLLVMName();
1701 std::string Builtin = Def->getMangledName();
1702 if (!LLVMName.empty())
1703 OS << "SMEMAP1(" << Builtin << ", " << LLVMName << ", " << FlagString
1704 << "),\n";
1705 else
1706 OS << "SMEMAP2(" << Builtin << ", " << FlagString << "),\n";
1707 }
1708 OS << "#endif\n\n";
1709 }
1710
createSMERangeChecks(raw_ostream & OS)1711 void SVEEmitter::createSMERangeChecks(raw_ostream &OS) {
1712 std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst");
1713 SmallVector<std::unique_ptr<Intrinsic>, 128> Defs;
1714 for (auto *R : RV) {
1715 createIntrinsic(R, Defs);
1716 }
1717
1718 // The mappings must be sorted based on BuiltinID.
1719 llvm::sort(Defs, [](const std::unique_ptr<Intrinsic> &A,
1720 const std::unique_ptr<Intrinsic> &B) {
1721 return A->getMangledName() < B->getMangledName();
1722 });
1723
1724
1725 OS << "#ifdef GET_SME_IMMEDIATE_CHECK\n";
1726
1727 // Ensure these are only emitted once.
1728 std::set<std::string> Emitted;
1729
1730 for (auto &Def : Defs) {
1731 if (Emitted.find(Def->getMangledName()) != Emitted.end() ||
1732 Def->getImmChecks().empty())
1733 continue;
1734
1735 OS << "case SME::BI__builtin_sme_" << Def->getMangledName() << ":\n";
1736 for (auto &Check : Def->getImmChecks())
1737 OS << "ImmChecks.push_back(std::make_tuple(" << Check.getArg() << ", "
1738 << Check.getKind() << ", " << Check.getElementSizeInBits() << "));\n";
1739 OS << " break;\n";
1740
1741 Emitted.insert(Def->getMangledName());
1742 }
1743
1744 OS << "#endif\n\n";
1745 }
1746
createBuiltinZAState(raw_ostream & OS)1747 void SVEEmitter::createBuiltinZAState(raw_ostream &OS) {
1748 std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst");
1749 SmallVector<std::unique_ptr<Intrinsic>, 128> Defs;
1750 for (auto *R : RV)
1751 createIntrinsic(R, Defs);
1752
1753 std::map<std::string, std::set<std::string>> IntrinsicsPerState;
1754 for (auto &Def : Defs) {
1755 std::string Key;
1756 auto AddToKey = [&Key](const std::string &S) -> void {
1757 Key = Key.empty() ? S : (Key + " | " + S);
1758 };
1759
1760 if (Def->isFlagSet(getEnumValueForFlag("IsInZA")))
1761 AddToKey("ArmInZA");
1762 else if (Def->isFlagSet(getEnumValueForFlag("IsOutZA")))
1763 AddToKey("ArmOutZA");
1764 else if (Def->isFlagSet(getEnumValueForFlag("IsInOutZA")))
1765 AddToKey("ArmInOutZA");
1766
1767 if (Def->isFlagSet(getEnumValueForFlag("IsInZT0")))
1768 AddToKey("ArmInZT0");
1769 else if (Def->isFlagSet(getEnumValueForFlag("IsOutZT0")))
1770 AddToKey("ArmOutZT0");
1771 else if (Def->isFlagSet(getEnumValueForFlag("IsInOutZT0")))
1772 AddToKey("ArmInOutZT0");
1773
1774 if (!Key.empty())
1775 IntrinsicsPerState[Key].insert(Def->getMangledName());
1776 }
1777
1778 OS << "#ifdef GET_SME_BUILTIN_GET_STATE\n";
1779 for (auto &KV : IntrinsicsPerState) {
1780 for (StringRef Name : KV.second)
1781 OS << "case SME::BI__builtin_sme_" << Name << ":\n";
1782 OS << " return " << KV.first << ";\n";
1783 }
1784 OS << "#endif\n\n";
1785 }
1786
createStreamingAttrs(raw_ostream & OS,ACLEKind Kind)1787 void SVEEmitter::createStreamingAttrs(raw_ostream &OS, ACLEKind Kind) {
1788 std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst");
1789 SmallVector<std::unique_ptr<Intrinsic>, 128> Defs;
1790 for (auto *R : RV)
1791 createIntrinsic(R, Defs);
1792
1793 StringRef ExtensionKind;
1794 switch (Kind) {
1795 case ACLEKind::SME:
1796 ExtensionKind = "SME";
1797 break;
1798 case ACLEKind::SVE:
1799 ExtensionKind = "SVE";
1800 break;
1801 }
1802
1803 OS << "#ifdef GET_" << ExtensionKind << "_STREAMING_ATTRS\n";
1804
1805 llvm::StringMap<std::set<std::string>> StreamingMap;
1806
1807 uint64_t IsStreamingFlag = getEnumValueForFlag("IsStreaming");
1808 uint64_t VerifyRuntimeMode = getEnumValueForFlag("VerifyRuntimeMode");
1809 uint64_t IsStreamingCompatibleFlag =
1810 getEnumValueForFlag("IsStreamingCompatible");
1811
1812 for (auto &Def : Defs) {
1813 if (!Def->isFlagSet(VerifyRuntimeMode) && !Def->getSVEGuard().empty() &&
1814 !Def->getSMEGuard().empty())
1815 report_fatal_error("Missing VerifyRuntimeMode flag");
1816
1817 if (Def->isFlagSet(IsStreamingFlag))
1818 StreamingMap["ArmStreaming"].insert(Def->getMangledName());
1819 else if (Def->isFlagSet(VerifyRuntimeMode))
1820 StreamingMap["VerifyRuntimeMode"].insert(Def->getMangledName());
1821 else if (Def->isFlagSet(IsStreamingCompatibleFlag))
1822 StreamingMap["ArmStreamingCompatible"].insert(Def->getMangledName());
1823 else
1824 StreamingMap["ArmNonStreaming"].insert(Def->getMangledName());
1825 }
1826
1827 for (auto BuiltinType : StreamingMap.keys()) {
1828 for (auto Name : StreamingMap[BuiltinType]) {
1829 OS << "case " << ExtensionKind << "::BI__builtin_"
1830 << ExtensionKind.lower() << "_";
1831 OS << Name << ":\n";
1832 }
1833 OS << " BuiltinType = " << BuiltinType << ";\n";
1834 OS << " break;\n";
1835 }
1836
1837 OS << "#endif\n\n";
1838 }
1839
1840 namespace clang {
EmitSveHeader(RecordKeeper & Records,raw_ostream & OS)1841 void EmitSveHeader(RecordKeeper &Records, raw_ostream &OS) {
1842 SVEEmitter(Records).createHeader(OS);
1843 }
1844
EmitSveBuiltins(RecordKeeper & Records,raw_ostream & OS)1845 void EmitSveBuiltins(RecordKeeper &Records, raw_ostream &OS) {
1846 SVEEmitter(Records).createBuiltins(OS);
1847 }
1848
EmitSveBuiltinCG(RecordKeeper & Records,raw_ostream & OS)1849 void EmitSveBuiltinCG(RecordKeeper &Records, raw_ostream &OS) {
1850 SVEEmitter(Records).createCodeGenMap(OS);
1851 }
1852
EmitSveRangeChecks(RecordKeeper & Records,raw_ostream & OS)1853 void EmitSveRangeChecks(RecordKeeper &Records, raw_ostream &OS) {
1854 SVEEmitter(Records).createRangeChecks(OS);
1855 }
1856
EmitSveTypeFlags(RecordKeeper & Records,raw_ostream & OS)1857 void EmitSveTypeFlags(RecordKeeper &Records, raw_ostream &OS) {
1858 SVEEmitter(Records).createTypeFlags(OS);
1859 }
1860
EmitSveStreamingAttrs(RecordKeeper & Records,raw_ostream & OS)1861 void EmitSveStreamingAttrs(RecordKeeper &Records, raw_ostream &OS) {
1862 SVEEmitter(Records).createStreamingAttrs(OS, ACLEKind::SVE);
1863 }
1864
EmitSmeHeader(RecordKeeper & Records,raw_ostream & OS)1865 void EmitSmeHeader(RecordKeeper &Records, raw_ostream &OS) {
1866 SVEEmitter(Records).createSMEHeader(OS);
1867 }
1868
EmitSmeBuiltins(RecordKeeper & Records,raw_ostream & OS)1869 void EmitSmeBuiltins(RecordKeeper &Records, raw_ostream &OS) {
1870 SVEEmitter(Records).createSMEBuiltins(OS);
1871 }
1872
EmitSmeBuiltinCG(RecordKeeper & Records,raw_ostream & OS)1873 void EmitSmeBuiltinCG(RecordKeeper &Records, raw_ostream &OS) {
1874 SVEEmitter(Records).createSMECodeGenMap(OS);
1875 }
1876
EmitSmeRangeChecks(RecordKeeper & Records,raw_ostream & OS)1877 void EmitSmeRangeChecks(RecordKeeper &Records, raw_ostream &OS) {
1878 SVEEmitter(Records).createSMERangeChecks(OS);
1879 }
1880
EmitSmeStreamingAttrs(RecordKeeper & Records,raw_ostream & OS)1881 void EmitSmeStreamingAttrs(RecordKeeper &Records, raw_ostream &OS) {
1882 SVEEmitter(Records).createStreamingAttrs(OS, ACLEKind::SME);
1883 }
1884
EmitSmeBuiltinZAState(RecordKeeper & Records,raw_ostream & OS)1885 void EmitSmeBuiltinZAState(RecordKeeper &Records, raw_ostream &OS) {
1886 SVEEmitter(Records).createBuiltinZAState(OS);
1887 }
1888 } // End namespace clang
1889