1 //===- SveEmitter.cpp - Generate arm_sve.h for use with clang -*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
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).
13 // For details, visit:
14 // https://developer.arm.com/architectures/system-architectures/software-standards/acle
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
22 // See also the documentation in include/clang/Basic/arm_sve.td.
24 //===----------------------------------------------------------------------===//
26 #include "llvm/ADT/STLExtras.h"
27 #include "llvm/ADT/StringMap.h"
28 #include "llvm/ADT/ArrayRef.h"
29 #include "llvm/ADT/StringExtras.h"
30 #include "llvm/TableGen/Record.h"
31 #include "llvm/TableGen/Error.h"
42 ClassS
, // signed/unsigned, e.g., "_s8", "_u8" suffix
43 ClassG
, // Overloaded name without type suffix
46 using TypeSpec
= std::string
;
53 unsigned ElementSizeInBits
;
56 ImmCheck(unsigned Arg
, unsigned Kind
, unsigned ElementSizeInBits
= 0)
57 : Arg(Arg
), Kind(Kind
), ElementSizeInBits(ElementSizeInBits
) {}
58 ImmCheck(const ImmCheck
&Other
) = default;
59 ~ImmCheck() = default;
61 unsigned getArg() const { return Arg
; }
62 unsigned getKind() const { return Kind
; }
63 unsigned getElementSizeInBits() const { return ElementSizeInBits
; }
68 bool Float
, Signed
, Immediate
, Void
, Constant
, Pointer
, BFloat
;
69 bool DefaultType
, IsScalable
, Predicate
, PredicatePattern
, PrefetchOp
,
71 unsigned Bitwidth
, ElementBitwidth
, NumVectors
;
74 SVEType() : SVEType(TypeSpec(), 'v') {}
76 SVEType(TypeSpec TS
, char CharMod
, unsigned NumVectors
= 1)
77 : TS(TS
), Float(false), Signed(true), Immediate(false), Void(false),
78 Constant(false), Pointer(false), BFloat(false), DefaultType(false),
79 IsScalable(true), Predicate(false), PredicatePattern(false),
80 PrefetchOp(false), Svcount(false), Bitwidth(128), ElementBitwidth(~0U),
81 NumVectors(NumVectors
) {
84 applyModifier(CharMod
);
87 bool isPointer() const { return Pointer
; }
88 bool isVoidPointer() const { return Pointer
&& Void
; }
89 bool isSigned() const { return Signed
; }
90 bool isImmediate() const { return Immediate
; }
91 bool isScalar() const { return NumVectors
== 0; }
92 bool isVector() const { return NumVectors
> 0; }
93 bool isScalableVector() const { return isVector() && IsScalable
; }
94 bool isChar() const { return ElementBitwidth
== 8; }
95 bool isVoid() const { return Void
& !Pointer
; }
96 bool isDefault() const { return DefaultType
; }
97 bool isFloat() const { return Float
&& !BFloat
; }
98 bool isBFloat() const { return BFloat
&& !Float
; }
99 bool isFloatingPoint() const { return Float
|| BFloat
; }
100 bool isInteger() const {
101 return !isFloatingPoint() && !Predicate
&& !Svcount
;
103 bool isScalarPredicate() const {
104 return !isFloatingPoint() && Predicate
&& NumVectors
== 0;
106 bool isPredicateVector() const { return Predicate
; }
107 bool isPredicatePattern() const { return PredicatePattern
; }
108 bool isPrefetchOp() const { return PrefetchOp
; }
109 bool isSvcount() const { return Svcount
; }
110 bool isConstant() const { return Constant
; }
111 unsigned getElementSizeInBits() const { return ElementBitwidth
; }
112 unsigned getNumVectors() const { return NumVectors
; }
114 unsigned getNumElements() const {
115 assert(ElementBitwidth
!= ~0U);
116 return Bitwidth
/ ElementBitwidth
;
118 unsigned getSizeInBits() const {
122 /// Return the string representation of a type, which is an encoded
123 /// string for passing to the BUILTIN() macro in Builtins.def.
124 std::string
builtin_str() const;
126 /// Return the C/C++ string representation of a type for use in the
127 /// arm_sve.h header file.
128 std::string
str() const;
131 /// Creates the type based on the typespec string in TS.
132 void applyTypespec();
134 /// Applies a prototype modifier to the type.
135 void applyModifier(char Mod
);
141 /// The main grunt class. This represents an instantiation of an intrinsic with
142 /// a particular typespec and prototype.
144 /// The unmangled name.
147 /// The name of the corresponding LLVM IR intrinsic.
148 std::string LLVMName
;
150 /// Intrinsic prototype.
153 /// The base type spec for this intrinsic.
154 TypeSpec BaseTypeSpec
;
156 /// The base class kind. Most intrinsics use ClassS, which has full type
157 /// info for integers (_s32/_u32), or ClassG which is used for overloaded
161 /// The architectural #ifdef guard.
164 // The merge suffix such as _m, _x or _z.
165 std::string MergeSuffix
;
167 /// The types of return value [0] and parameters [1..].
168 std::vector
<SVEType
> Types
;
170 /// The "base type", which is VarType('d', BaseTypeSpec).
175 SmallVector
<ImmCheck
, 2> ImmChecks
;
178 Intrinsic(StringRef Name
, StringRef Proto
, uint64_t MergeTy
,
179 StringRef MergeSuffix
, uint64_t MemoryElementTy
, StringRef LLVMName
,
180 uint64_t Flags
, ArrayRef
<ImmCheck
> ImmChecks
, TypeSpec BT
,
181 ClassKind Class
, SVEEmitter
&Emitter
, StringRef Guard
);
183 ~Intrinsic()=default;
185 std::string
getName() const { return Name
; }
186 std::string
getLLVMName() const { return LLVMName
; }
187 std::string
getProto() const { return Proto
; }
188 TypeSpec
getBaseTypeSpec() const { return BaseTypeSpec
; }
189 SVEType
getBaseType() const { return BaseType
; }
191 StringRef
getGuard() const { return Guard
; }
192 ClassKind
getClassKind() const { return Class
; }
194 SVEType
getReturnType() const { return Types
[0]; }
195 ArrayRef
<SVEType
> getTypes() const { return Types
; }
196 SVEType
getParamType(unsigned I
) const { return Types
[I
+ 1]; }
197 unsigned getNumParams() const {
198 return Proto
.size() - (2 * llvm::count(Proto
, '.')) - 1;
201 uint64_t getFlags() const { return Flags
; }
202 bool isFlagSet(uint64_t Flag
) const { return Flags
& Flag
;}
204 ArrayRef
<ImmCheck
> getImmChecks() const { return ImmChecks
; }
206 /// Return the type string for a BUILTIN() macro in Builtins.def.
207 std::string
getBuiltinTypeStr();
209 /// Return the name, mangled with type information. The name is mangled for
210 /// ClassS, so will add type suffixes such as _u32/_s32.
211 std::string
getMangledName() const { return mangleName(ClassS
); }
213 /// As above, but mangles the LLVM name instead.
214 std::string
getMangledLLVMName() const { return mangleLLVMName(); }
216 /// Returns true if the intrinsic is overloaded, in that it should also generate
217 /// a short form without the type-specifiers, e.g. 'svld1(..)' instead of
219 static bool isOverloadedIntrinsic(StringRef Name
) {
220 auto BrOpen
= Name
.find('[');
221 auto BrClose
= Name
.find(']');
222 return BrOpen
!= std::string::npos
&& BrClose
!= std::string::npos
;
225 /// Return true if the intrinsic takes a splat operand.
226 bool hasSplat() const {
227 // These prototype modifiers are described in arm_sve.td.
228 return Proto
.find_first_of("ajfrKLR@") != std::string::npos
;
231 /// Return the parameter index of the splat operand.
232 unsigned getSplatIdx() const {
233 unsigned I
= 1, Param
= 0;
234 for (; I
< Proto
.size(); ++I
, ++Param
) {
235 if (Proto
[I
] == 'a' || Proto
[I
] == 'j' || Proto
[I
] == 'f' ||
236 Proto
[I
] == 'r' || Proto
[I
] == 'K' || Proto
[I
] == 'L' ||
237 Proto
[I
] == 'R' || Proto
[I
] == '@')
240 // Multivector modifier can be skipped
244 assert(I
!= Proto
.size() && "Prototype has no splat operand");
248 /// Emits the intrinsic declaration to the ostream.
249 void emitIntrinsic(raw_ostream
&OS
, SVEEmitter
&Emitter
) const;
252 std::string
getMergeSuffix() const { return MergeSuffix
; }
253 std::string
mangleName(ClassKind LocalCK
) const;
254 std::string
mangleLLVMName() const;
255 std::string
replaceTemplatedArgs(std::string Name
, TypeSpec TS
,
256 std::string Proto
) const;
261 // The reinterpret builtins are generated separately because they
262 // need the cross product of all types (121 functions in total),
263 // which is inconvenient to specify in the arm_sve.td file or
264 // generate in CGBuiltin.cpp.
265 struct ReinterpretTypeInfo
{
268 const char *BuiltinType
;
270 SmallVector
<ReinterpretTypeInfo
, 12> Reinterprets
= {
271 {"s8", "svint8_t", "q16Sc"}, {"s16", "svint16_t", "q8Ss"},
272 {"s32", "svint32_t", "q4Si"}, {"s64", "svint64_t", "q2SWi"},
273 {"u8", "svuint8_t", "q16Uc"}, {"u16", "svuint16_t", "q8Us"},
274 {"u32", "svuint32_t", "q4Ui"}, {"u64", "svuint64_t", "q2UWi"},
275 {"f16", "svfloat16_t", "q8h"}, {"bf16", "svbfloat16_t", "q8y"},
276 {"f32", "svfloat32_t", "q4f"}, {"f64", "svfloat64_t", "q2d"}};
278 RecordKeeper
&Records
;
279 llvm::StringMap
<uint64_t> EltTypes
;
280 llvm::StringMap
<uint64_t> MemEltTypes
;
281 llvm::StringMap
<uint64_t> FlagTypes
;
282 llvm::StringMap
<uint64_t> MergeTypes
;
283 llvm::StringMap
<uint64_t> ImmCheckTypes
;
286 SVEEmitter(RecordKeeper
&R
) : Records(R
) {
287 for (auto *RV
: Records
.getAllDerivedDefinitions("EltType"))
288 EltTypes
[RV
->getNameInitAsString()] = RV
->getValueAsInt("Value");
289 for (auto *RV
: Records
.getAllDerivedDefinitions("MemEltType"))
290 MemEltTypes
[RV
->getNameInitAsString()] = RV
->getValueAsInt("Value");
291 for (auto *RV
: Records
.getAllDerivedDefinitions("FlagType"))
292 FlagTypes
[RV
->getNameInitAsString()] = RV
->getValueAsInt("Value");
293 for (auto *RV
: Records
.getAllDerivedDefinitions("MergeType"))
294 MergeTypes
[RV
->getNameInitAsString()] = RV
->getValueAsInt("Value");
295 for (auto *RV
: Records
.getAllDerivedDefinitions("ImmCheckType"))
296 ImmCheckTypes
[RV
->getNameInitAsString()] = RV
->getValueAsInt("Value");
299 /// Returns the enum value for the immcheck type
300 unsigned getEnumValueForImmCheck(StringRef C
) const {
301 auto It
= ImmCheckTypes
.find(C
);
302 if (It
!= ImmCheckTypes
.end())
303 return It
->getValue();
304 llvm_unreachable("Unsupported imm check");
307 /// Returns the enum value for the flag type
308 uint64_t getEnumValueForFlag(StringRef C
) const {
309 auto Res
= FlagTypes
.find(C
);
310 if (Res
!= FlagTypes
.end())
311 return Res
->getValue();
312 llvm_unreachable("Unsupported flag");
315 // Returns the SVETypeFlags for a given value and mask.
316 uint64_t encodeFlag(uint64_t V
, StringRef MaskName
) const {
317 auto It
= FlagTypes
.find(MaskName
);
318 if (It
!= FlagTypes
.end()) {
319 uint64_t Mask
= It
->getValue();
320 unsigned Shift
= llvm::countr_zero(Mask
);
321 assert(Shift
< 64 && "Mask value produced an invalid shift value");
322 return (V
<< Shift
) & Mask
;
324 llvm_unreachable("Unsupported flag");
327 // Returns the SVETypeFlags for the given element type.
328 uint64_t encodeEltType(StringRef EltName
) {
329 auto It
= EltTypes
.find(EltName
);
330 if (It
!= EltTypes
.end())
331 return encodeFlag(It
->getValue(), "EltTypeMask");
332 llvm_unreachable("Unsupported EltType");
335 // Returns the SVETypeFlags for the given memory element type.
336 uint64_t encodeMemoryElementType(uint64_t MT
) {
337 return encodeFlag(MT
, "MemEltTypeMask");
340 // Returns the SVETypeFlags for the given merge type.
341 uint64_t encodeMergeType(uint64_t MT
) {
342 return encodeFlag(MT
, "MergeTypeMask");
345 // Returns the SVETypeFlags for the given splat operand.
346 unsigned encodeSplatOperand(unsigned SplatIdx
) {
347 assert(SplatIdx
< 7 && "SplatIdx out of encodable range");
348 return encodeFlag(SplatIdx
+ 1, "SplatOperandMask");
351 // Returns the SVETypeFlags value for the given SVEType.
352 uint64_t encodeTypeFlags(const SVEType
&T
);
355 void createHeader(raw_ostream
&o
);
357 /// Emit all the __builtin prototypes and code needed by Sema.
358 void createBuiltins(raw_ostream
&o
);
360 /// Emit all the information needed to map builtin -> LLVM IR intrinsic.
361 void createCodeGenMap(raw_ostream
&o
);
363 /// Emit all the range checks for the immediates.
364 void createRangeChecks(raw_ostream
&o
);
366 /// Create the SVETypeFlags used in CGBuiltins
367 void createTypeFlags(raw_ostream
&o
);
370 void createSMEHeader(raw_ostream
&o
);
372 /// Emit all the SME __builtin prototypes and code needed by Sema.
373 void createSMEBuiltins(raw_ostream
&o
);
375 /// Emit all the information needed to map builtin -> LLVM IR intrinsic.
376 void createSMECodeGenMap(raw_ostream
&o
);
378 /// Emit all the range checks for the immediates.
379 void createSMERangeChecks(raw_ostream
&o
);
381 /// Create intrinsic and add it to \p Out
382 void createIntrinsic(Record
*R
,
383 SmallVectorImpl
<std::unique_ptr
<Intrinsic
>> &Out
);
386 } // end anonymous namespace
389 //===----------------------------------------------------------------------===//
390 // Type implementation
391 //===----------------------------------------------------------------------===//
393 std::string
SVEType::builtin_str() const {
398 if (isScalarPredicate())
406 else if (!isFloatingPoint())
407 switch (ElementBitwidth
) {
408 case 1: S
+= "b"; break;
409 case 8: S
+= "c"; break;
410 case 16: S
+= "s"; break;
411 case 32: S
+= "i"; break;
412 case 64: S
+= "Wi"; break;
413 case 128: S
+= "LLLi"; break;
414 default: llvm_unreachable("Unhandled case!");
417 switch (ElementBitwidth
) {
418 case 16: S
+= "h"; break;
419 case 32: S
+= "f"; break;
420 case 64: S
+= "d"; break;
421 default: llvm_unreachable("Unhandled case!");
423 else if (isBFloat()) {
424 assert(ElementBitwidth
== 16 && "Not a valid BFloat.");
428 if (!isFloatingPoint()) {
429 if ((isChar() || isPointer()) && !isVoidPointer()) {
430 // Make chars and typed pointers explicitly signed.
435 } else if (!isVoidPointer() && !Signed
) {
440 // Constant indices are "int", but have the "constant expression" modifier.
442 assert(!isFloat() && "fp immediates are not supported");
447 if (Constant
) S
+= "C";
448 if (Pointer
) S
+= "*";
452 assert(isScalableVector() && "Unsupported type");
453 return "q" + utostr(getNumElements() * NumVectors
) + S
;
456 std::string
SVEType::str() const {
457 if (isPredicatePattern())
458 return "enum svpattern";
461 return "enum svprfop";
467 if (isScalableVector() || isSvcount())
469 if (!Signed
&& !isFloatingPoint())
474 else if (isSvcount())
476 else if (isScalarPredicate() || isPredicateVector())
483 if (!isScalarPredicate() && !isPredicateVector() && !isSvcount())
484 S
+= utostr(ElementBitwidth
);
485 if (!isScalableVector() && isVector())
486 S
+= "x" + utostr(getNumElements());
488 S
+= "x" + utostr(NumVectors
);
489 if (!isScalarPredicate())
500 void SVEType::applyTypespec() {
516 ElementBitwidth
= 16;
519 ElementBitwidth
= 32;
522 ElementBitwidth
= 64;
525 ElementBitwidth
= 128;
529 ElementBitwidth
= 16;
533 ElementBitwidth
= 32;
537 ElementBitwidth
= 64;
542 ElementBitwidth
= 16;
545 llvm_unreachable("Unhandled type code!");
548 assert(ElementBitwidth
!= ~0U && "Bad element bitwidth!");
551 void SVEType::applyModifier(char Mod
) {
564 Bitwidth
= ElementBitwidth
;
569 ElementBitwidth
/= 2;
572 ElementBitwidth
/= 2;
575 ElementBitwidth
/= 4;
581 ElementBitwidth
/= 4;
584 ElementBitwidth
*= 4;
597 Bitwidth
= ElementBitwidth
;
601 ElementBitwidth
/= 2;
605 ElementBitwidth
/= 4;
612 ElementBitwidth
/= 4;
619 Bitwidth
= ElementBitwidth
;
626 Bitwidth
= ElementBitwidth
;
648 ElementBitwidth
= Bitwidth
= 64;
658 ElementBitwidth
= Bitwidth
= 32;
662 PredicatePattern
= true;
669 ElementBitwidth
= Bitwidth
= 32;
681 ElementBitwidth
= Bitwidth
= 32;
690 ElementBitwidth
= Bitwidth
= 64;
699 ElementBitwidth
= Bitwidth
= 32;
708 ElementBitwidth
= Bitwidth
= 64;
712 ElementBitwidth
= 64;
715 ElementBitwidth
= Bitwidth
= 64;
720 ElementBitwidth
= Bitwidth
= 64;
727 ElementBitwidth
= 64;
733 ElementBitwidth
= 32;
739 ElementBitwidth
= 32;
745 ElementBitwidth
= 16;
752 ElementBitwidth
= 32;
758 ElementBitwidth
= 64;
769 ElementBitwidth
= Bitwidth
= 8;
776 ElementBitwidth
= Bitwidth
= 8;
783 ElementBitwidth
= Bitwidth
= 16;
790 ElementBitwidth
= Bitwidth
= 16;
797 ElementBitwidth
= Bitwidth
= 32;
804 ElementBitwidth
= Bitwidth
= 32;
815 ElementBitwidth
= Bitwidth
= 8;
821 ElementBitwidth
= Bitwidth
= 16;
827 ElementBitwidth
= Bitwidth
= 32;
833 ElementBitwidth
= Bitwidth
= 64;
839 ElementBitwidth
= Bitwidth
= 8;
845 ElementBitwidth
= Bitwidth
= 16;
851 ElementBitwidth
= Bitwidth
= 32;
860 ElementBitwidth
= 16;
871 llvm_unreachable(". is never a type in itself");
874 llvm_unreachable("Unhandled character!");
878 /// Returns the modifier and number of vectors for the given operand \p Op.
879 std::pair
<char, unsigned> getProtoModifier(StringRef Proto
, unsigned Op
) {
880 for (unsigned P
= 0; !Proto
.empty(); ++P
) {
881 unsigned NumVectors
= 1;
882 unsigned CharsToSkip
= 1;
884 if (Mod
== '2' || Mod
== '3' || Mod
== '4') {
885 NumVectors
= Mod
- '0';
887 if (Proto
.size() > 1 && Proto
[1] == '.') {
894 return {Mod
, NumVectors
};
896 Proto
= Proto
.drop_front(CharsToSkip
);
898 llvm_unreachable("Unexpected Op");
901 //===----------------------------------------------------------------------===//
902 // Intrinsic implementation
903 //===----------------------------------------------------------------------===//
905 Intrinsic::Intrinsic(StringRef Name
, StringRef Proto
, uint64_t MergeTy
,
906 StringRef MergeSuffix
, uint64_t MemoryElementTy
,
907 StringRef LLVMName
, uint64_t Flags
,
908 ArrayRef
<ImmCheck
> Checks
, TypeSpec BT
, ClassKind Class
,
909 SVEEmitter
&Emitter
, StringRef Guard
)
910 : Name(Name
.str()), LLVMName(LLVMName
), Proto(Proto
.str()),
911 BaseTypeSpec(BT
), Class(Class
), Guard(Guard
.str()),
912 MergeSuffix(MergeSuffix
.str()), BaseType(BT
, 'd'), Flags(Flags
),
913 ImmChecks(Checks
.begin(), Checks
.end()) {
914 // Types[0] is the return value.
915 for (unsigned I
= 0; I
< (getNumParams() + 1); ++I
) {
918 std::tie(Mod
, NumVectors
) = getProtoModifier(Proto
, I
);
919 SVEType
T(BaseTypeSpec
, Mod
, NumVectors
);
922 // Add range checks for immediates
924 if (T
.isPredicatePattern())
925 ImmChecks
.emplace_back(
926 I
- 1, Emitter
.getEnumValueForImmCheck("ImmCheck0_31"));
927 else if (T
.isPrefetchOp())
928 ImmChecks
.emplace_back(
929 I
- 1, Emitter
.getEnumValueForImmCheck("ImmCheck0_13"));
933 // Set flags based on properties
934 this->Flags
|= Emitter
.encodeTypeFlags(BaseType
);
935 this->Flags
|= Emitter
.encodeMemoryElementType(MemoryElementTy
);
936 this->Flags
|= Emitter
.encodeMergeType(MergeTy
);
938 this->Flags
|= Emitter
.encodeSplatOperand(getSplatIdx());
941 std::string
Intrinsic::getBuiltinTypeStr() {
942 std::string S
= getReturnType().builtin_str();
943 for (unsigned I
= 0; I
< getNumParams(); ++I
)
944 S
+= getParamType(I
).builtin_str();
949 std::string
Intrinsic::replaceTemplatedArgs(std::string Name
, TypeSpec TS
,
950 std::string Proto
) const {
951 std::string Ret
= Name
;
952 while (Ret
.find('{') != std::string::npos
) {
953 size_t Pos
= Ret
.find('{');
954 size_t End
= Ret
.find('}');
955 unsigned NumChars
= End
- Pos
+ 1;
956 assert(NumChars
== 3 && "Unexpected template argument");
962 llvm_unreachable("Unknown predication specifier");
964 T
= SVEType(TS
, 'd');
970 T
= SVEType(TS
, Proto
[C
- '0']);
974 // Replace templated arg with the right suffix (e.g. u32)
975 std::string TypeCode
;
977 TypeCode
= T
.isSigned() ? 's' : 'u';
978 else if (T
.isSvcount())
980 else if (T
.isPredicateVector())
982 else if (T
.isBFloat())
986 Ret
.replace(Pos
, NumChars
, TypeCode
+ utostr(T
.getElementSizeInBits()));
992 std::string
Intrinsic::mangleLLVMName() const {
993 std::string S
= getLLVMName();
995 // Replace all {d} like expressions with e.g. 'u32'
996 return replaceTemplatedArgs(S
, getBaseTypeSpec(), getProto());
999 std::string
Intrinsic::mangleName(ClassKind LocalCK
) const {
1000 std::string S
= getName();
1002 if (LocalCK
== ClassG
) {
1003 // Remove the square brackets and everything in between.
1004 while (S
.find('[') != std::string::npos
) {
1005 auto Start
= S
.find('[');
1006 auto End
= S
.find(']');
1007 S
.erase(Start
, (End
-Start
)+1);
1010 // Remove the square brackets.
1011 while (S
.find('[') != std::string::npos
) {
1012 auto BrPos
= S
.find('[');
1013 if (BrPos
!= std::string::npos
)
1015 BrPos
= S
.find(']');
1016 if (BrPos
!= std::string::npos
)
1021 // Replace all {d} like expressions with e.g. 'u32'
1022 return replaceTemplatedArgs(S
, getBaseTypeSpec(), getProto()) +
1026 void Intrinsic::emitIntrinsic(raw_ostream
&OS
, SVEEmitter
&Emitter
) const {
1027 bool IsOverloaded
= getClassKind() == ClassG
&& getProto().size() > 1;
1029 std::string FullName
= mangleName(ClassS
);
1030 std::string ProtoName
= mangleName(getClassKind());
1031 std::string SMEAttrs
= "";
1033 if (Flags
& Emitter
.getEnumValueForFlag("IsStreaming"))
1034 SMEAttrs
+= ", arm_streaming";
1035 if (Flags
& Emitter
.getEnumValueForFlag("IsStreamingCompatible"))
1036 SMEAttrs
+= ", arm_streaming_compatible";
1037 if (Flags
& Emitter
.getEnumValueForFlag("IsSharedZA"))
1038 SMEAttrs
+= ", arm_shared_za";
1039 if (Flags
& Emitter
.getEnumValueForFlag("IsPreservesZA"))
1040 SMEAttrs
+= ", arm_preserves_za";
1042 OS
<< (IsOverloaded
? "__aio " : "__ai ")
1043 << "__attribute__((__clang_arm_builtin_alias("
1044 << (SMEAttrs
.empty() ? "__builtin_sve_" : "__builtin_sme_")
1046 if (!SMEAttrs
.empty())
1050 OS
<< getTypes()[0].str() << " " << ProtoName
<< "(";
1051 for (unsigned I
= 0; I
< getTypes().size() - 1; ++I
) {
1054 OS
<< getTypes()[I
+ 1].str();
1059 //===----------------------------------------------------------------------===//
1060 // SVEEmitter implementation
1061 //===----------------------------------------------------------------------===//
1062 uint64_t SVEEmitter::encodeTypeFlags(const SVEType
&T
) {
1064 switch (T
.getElementSizeInBits()) {
1066 return encodeEltType("EltTyFloat16");
1068 return encodeEltType("EltTyFloat32");
1070 return encodeEltType("EltTyFloat64");
1072 llvm_unreachable("Unhandled float element bitwidth!");
1077 assert(T
.getElementSizeInBits() == 16 && "Not a valid BFloat.");
1078 return encodeEltType("EltTyBFloat16");
1081 if (T
.isPredicateVector() || T
.isSvcount()) {
1082 switch (T
.getElementSizeInBits()) {
1084 return encodeEltType("EltTyBool8");
1086 return encodeEltType("EltTyBool16");
1088 return encodeEltType("EltTyBool32");
1090 return encodeEltType("EltTyBool64");
1092 llvm_unreachable("Unhandled predicate element bitwidth!");
1096 switch (T
.getElementSizeInBits()) {
1098 return encodeEltType("EltTyInt8");
1100 return encodeEltType("EltTyInt16");
1102 return encodeEltType("EltTyInt32");
1104 return encodeEltType("EltTyInt64");
1106 return encodeEltType("EltTyInt128");
1108 llvm_unreachable("Unhandled integer element bitwidth!");
1112 void SVEEmitter::createIntrinsic(
1113 Record
*R
, SmallVectorImpl
<std::unique_ptr
<Intrinsic
>> &Out
) {
1114 StringRef Name
= R
->getValueAsString("Name");
1115 StringRef Proto
= R
->getValueAsString("Prototype");
1116 StringRef Types
= R
->getValueAsString("Types");
1117 StringRef Guard
= R
->getValueAsString("TargetGuard");
1118 StringRef LLVMName
= R
->getValueAsString("LLVMIntrinsic");
1119 uint64_t Merge
= R
->getValueAsInt("Merge");
1120 StringRef MergeSuffix
= R
->getValueAsString("MergeSuffix");
1121 uint64_t MemEltType
= R
->getValueAsInt("MemEltType");
1122 std::vector
<Record
*> FlagsList
= R
->getValueAsListOfDefs("Flags");
1123 std::vector
<Record
*> ImmCheckList
= R
->getValueAsListOfDefs("ImmChecks");
1126 for (auto FlagRec
: FlagsList
)
1127 Flags
|= FlagRec
->getValueAsInt("Value");
1129 // Create a dummy TypeSpec for non-overloaded builtins.
1130 if (Types
.empty()) {
1131 assert((Flags
& getEnumValueForFlag("IsOverloadNone")) &&
1132 "Expect TypeSpec for overloaded builtin!");
1136 // Extract type specs from string
1137 SmallVector
<TypeSpec
, 8> TypeSpecs
;
1139 for (char I
: Types
) {
1142 TypeSpecs
.push_back(TypeSpec(Acc
));
1147 // Remove duplicate type specs.
1148 llvm::sort(TypeSpecs
);
1149 TypeSpecs
.erase(std::unique(TypeSpecs
.begin(), TypeSpecs
.end()),
1152 // Create an Intrinsic for each type spec.
1153 for (auto TS
: TypeSpecs
) {
1154 // Collate a list of range/option checks for the immediates.
1155 SmallVector
<ImmCheck
, 2> ImmChecks
;
1156 for (auto *R
: ImmCheckList
) {
1157 int64_t Arg
= R
->getValueAsInt("Arg");
1158 int64_t EltSizeArg
= R
->getValueAsInt("EltSizeArg");
1159 int64_t Kind
= R
->getValueAsDef("Kind")->getValueAsInt("Value");
1160 assert(Arg
>= 0 && Kind
>= 0 && "Arg and Kind must be nonnegative");
1162 unsigned ElementSizeInBits
= 0;
1164 unsigned NumVectors
;
1165 std::tie(Mod
, NumVectors
) = getProtoModifier(Proto
, EltSizeArg
+ 1);
1166 if (EltSizeArg
>= 0)
1167 ElementSizeInBits
= SVEType(TS
, Mod
, NumVectors
).getElementSizeInBits();
1168 ImmChecks
.push_back(ImmCheck(Arg
, Kind
, ElementSizeInBits
));
1171 Out
.push_back(std::make_unique
<Intrinsic
>(
1172 Name
, Proto
, Merge
, MergeSuffix
, MemEltType
, LLVMName
, Flags
, ImmChecks
,
1173 TS
, ClassS
, *this, Guard
));
1175 // Also generate the short-form (e.g. svadd_m) for the given type-spec.
1176 if (Intrinsic::isOverloadedIntrinsic(Name
))
1177 Out
.push_back(std::make_unique
<Intrinsic
>(
1178 Name
, Proto
, Merge
, MergeSuffix
, MemEltType
, LLVMName
, Flags
,
1179 ImmChecks
, TS
, ClassG
, *this, Guard
));
1183 void SVEEmitter::createHeader(raw_ostream
&OS
) {
1184 OS
<< "/*===---- arm_sve.h - ARM SVE intrinsics "
1185 "-----------------------------------===\n"
1188 " * Part of the LLVM Project, under the Apache License v2.0 with LLVM "
1190 " * See https://llvm.org/LICENSE.txt for license information.\n"
1191 " * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception\n"
1193 " *===-----------------------------------------------------------------"
1197 OS
<< "#ifndef __ARM_SVE_H\n";
1198 OS
<< "#define __ARM_SVE_H\n\n";
1200 OS
<< "#if !defined(__LITTLE_ENDIAN__)\n";
1201 OS
<< "#error \"Big endian is currently not supported for arm_sve.h\"\n";
1204 OS
<< "#include <stdint.h>\n\n";
1205 OS
<< "#ifdef __cplusplus\n";
1206 OS
<< "extern \"C\" {\n";
1208 OS
<< "#include <stdbool.h>\n";
1211 OS
<< "typedef __fp16 float16_t;\n";
1212 OS
<< "typedef float float32_t;\n";
1213 OS
<< "typedef double float64_t;\n";
1215 OS
<< "typedef __SVInt8_t svint8_t;\n";
1216 OS
<< "typedef __SVInt16_t svint16_t;\n";
1217 OS
<< "typedef __SVInt32_t svint32_t;\n";
1218 OS
<< "typedef __SVInt64_t svint64_t;\n";
1219 OS
<< "typedef __SVUint8_t svuint8_t;\n";
1220 OS
<< "typedef __SVUint16_t svuint16_t;\n";
1221 OS
<< "typedef __SVUint32_t svuint32_t;\n";
1222 OS
<< "typedef __SVUint64_t svuint64_t;\n";
1223 OS
<< "typedef __SVFloat16_t svfloat16_t;\n\n";
1225 OS
<< "typedef __SVBfloat16_t svbfloat16_t;\n";
1227 OS
<< "#include <arm_bf16.h>\n";
1229 OS
<< "typedef __SVFloat32_t svfloat32_t;\n";
1230 OS
<< "typedef __SVFloat64_t svfloat64_t;\n";
1231 OS
<< "typedef __clang_svint8x2_t svint8x2_t;\n";
1232 OS
<< "typedef __clang_svint16x2_t svint16x2_t;\n";
1233 OS
<< "typedef __clang_svint32x2_t svint32x2_t;\n";
1234 OS
<< "typedef __clang_svint64x2_t svint64x2_t;\n";
1235 OS
<< "typedef __clang_svuint8x2_t svuint8x2_t;\n";
1236 OS
<< "typedef __clang_svuint16x2_t svuint16x2_t;\n";
1237 OS
<< "typedef __clang_svuint32x2_t svuint32x2_t;\n";
1238 OS
<< "typedef __clang_svuint64x2_t svuint64x2_t;\n";
1239 OS
<< "typedef __clang_svfloat16x2_t svfloat16x2_t;\n";
1240 OS
<< "typedef __clang_svfloat32x2_t svfloat32x2_t;\n";
1241 OS
<< "typedef __clang_svfloat64x2_t svfloat64x2_t;\n";
1242 OS
<< "typedef __clang_svint8x3_t svint8x3_t;\n";
1243 OS
<< "typedef __clang_svint16x3_t svint16x3_t;\n";
1244 OS
<< "typedef __clang_svint32x3_t svint32x3_t;\n";
1245 OS
<< "typedef __clang_svint64x3_t svint64x3_t;\n";
1246 OS
<< "typedef __clang_svuint8x3_t svuint8x3_t;\n";
1247 OS
<< "typedef __clang_svuint16x3_t svuint16x3_t;\n";
1248 OS
<< "typedef __clang_svuint32x3_t svuint32x3_t;\n";
1249 OS
<< "typedef __clang_svuint64x3_t svuint64x3_t;\n";
1250 OS
<< "typedef __clang_svfloat16x3_t svfloat16x3_t;\n";
1251 OS
<< "typedef __clang_svfloat32x3_t svfloat32x3_t;\n";
1252 OS
<< "typedef __clang_svfloat64x3_t svfloat64x3_t;\n";
1253 OS
<< "typedef __clang_svint8x4_t svint8x4_t;\n";
1254 OS
<< "typedef __clang_svint16x4_t svint16x4_t;\n";
1255 OS
<< "typedef __clang_svint32x4_t svint32x4_t;\n";
1256 OS
<< "typedef __clang_svint64x4_t svint64x4_t;\n";
1257 OS
<< "typedef __clang_svuint8x4_t svuint8x4_t;\n";
1258 OS
<< "typedef __clang_svuint16x4_t svuint16x4_t;\n";
1259 OS
<< "typedef __clang_svuint32x4_t svuint32x4_t;\n";
1260 OS
<< "typedef __clang_svuint64x4_t svuint64x4_t;\n";
1261 OS
<< "typedef __clang_svfloat16x4_t svfloat16x4_t;\n";
1262 OS
<< "typedef __clang_svfloat32x4_t svfloat32x4_t;\n";
1263 OS
<< "typedef __clang_svfloat64x4_t svfloat64x4_t;\n";
1264 OS
<< "typedef __SVBool_t svbool_t;\n";
1265 OS
<< "typedef __clang_svboolx2_t svboolx2_t;\n";
1266 OS
<< "typedef __clang_svboolx4_t svboolx4_t;\n\n";
1268 OS
<< "typedef __clang_svbfloat16x2_t svbfloat16x2_t;\n";
1269 OS
<< "typedef __clang_svbfloat16x3_t svbfloat16x3_t;\n";
1270 OS
<< "typedef __clang_svbfloat16x4_t svbfloat16x4_t;\n";
1272 OS
<< "typedef __SVCount_t svcount_t;\n\n";
1274 OS
<< "enum svpattern\n";
1276 OS
<< " SV_POW2 = 0,\n";
1277 OS
<< " SV_VL1 = 1,\n";
1278 OS
<< " SV_VL2 = 2,\n";
1279 OS
<< " SV_VL3 = 3,\n";
1280 OS
<< " SV_VL4 = 4,\n";
1281 OS
<< " SV_VL5 = 5,\n";
1282 OS
<< " SV_VL6 = 6,\n";
1283 OS
<< " SV_VL7 = 7,\n";
1284 OS
<< " SV_VL8 = 8,\n";
1285 OS
<< " SV_VL16 = 9,\n";
1286 OS
<< " SV_VL32 = 10,\n";
1287 OS
<< " SV_VL64 = 11,\n";
1288 OS
<< " SV_VL128 = 12,\n";
1289 OS
<< " SV_VL256 = 13,\n";
1290 OS
<< " SV_MUL4 = 29,\n";
1291 OS
<< " SV_MUL3 = 30,\n";
1292 OS
<< " SV_ALL = 31\n";
1295 OS
<< "enum svprfop\n";
1297 OS
<< " SV_PLDL1KEEP = 0,\n";
1298 OS
<< " SV_PLDL1STRM = 1,\n";
1299 OS
<< " SV_PLDL2KEEP = 2,\n";
1300 OS
<< " SV_PLDL2STRM = 3,\n";
1301 OS
<< " SV_PLDL3KEEP = 4,\n";
1302 OS
<< " SV_PLDL3STRM = 5,\n";
1303 OS
<< " SV_PSTL1KEEP = 8,\n";
1304 OS
<< " SV_PSTL1STRM = 9,\n";
1305 OS
<< " SV_PSTL2KEEP = 10,\n";
1306 OS
<< " SV_PSTL2STRM = 11,\n";
1307 OS
<< " SV_PSTL3KEEP = 12,\n";
1308 OS
<< " SV_PSTL3STRM = 13\n";
1311 OS
<< "/* Function attributes */\n";
1312 OS
<< "#define __ai static __inline__ __attribute__((__always_inline__, "
1313 "__nodebug__))\n\n";
1314 OS
<< "#define __aio static __inline__ __attribute__((__always_inline__, "
1315 "__nodebug__, __overloadable__))\n\n";
1317 // Add reinterpret functions.
1318 for (auto ShortForm
: { false, true } )
1319 for (const ReinterpretTypeInfo
&From
: Reinterprets
)
1320 for (const ReinterpretTypeInfo
&To
: Reinterprets
) {
1322 OS
<< "__aio __attribute__((target(\"sve\"))) " << From
.Type
1323 << " svreinterpret_" << From
.Suffix
;
1324 OS
<< "(" << To
.Type
<< " op) __arm_streaming_compatible {\n";
1325 OS
<< " return __builtin_sve_reinterpret_" << From
.Suffix
<< "_"
1326 << To
.Suffix
<< "(op);\n";
1329 OS
<< "#define svreinterpret_" << From
.Suffix
<< "_" << To
.Suffix
1330 << "(...) __builtin_sve_reinterpret_" << From
.Suffix
<< "_"
1331 << To
.Suffix
<< "(__VA_ARGS__)\n";
1334 SmallVector
<std::unique_ptr
<Intrinsic
>, 128> Defs
;
1335 std::vector
<Record
*> RV
= Records
.getAllDerivedDefinitions("Inst");
1337 createIntrinsic(R
, Defs
);
1339 // Sort intrinsics in header file by following order/priority:
1340 // - Architectural guard (i.e. does it require SVE2 or SVE2_AES)
1341 // - Class (is intrinsic overloaded or not)
1344 Defs
.begin(), Defs
.end(), [](const std::unique_ptr
<Intrinsic
> &A
,
1345 const std::unique_ptr
<Intrinsic
> &B
) {
1346 auto ToTuple
= [](const std::unique_ptr
<Intrinsic
> &I
) {
1347 return std::make_tuple(I
->getGuard(), (unsigned)I
->getClassKind(), I
->getName());
1349 return ToTuple(A
) < ToTuple(B
);
1352 // Actually emit the intrinsic declarations.
1353 for (auto &I
: Defs
)
1354 I
->emitIntrinsic(OS
, *this);
1356 OS
<< "#define svcvtnt_bf16_x svcvtnt_bf16_m\n";
1357 OS
<< "#define svcvtnt_bf16_f32_x svcvtnt_bf16_f32_m\n";
1359 OS
<< "#define svcvtnt_f16_x svcvtnt_f16_m\n";
1360 OS
<< "#define svcvtnt_f16_f32_x svcvtnt_f16_f32_m\n";
1361 OS
<< "#define svcvtnt_f32_x svcvtnt_f32_m\n";
1362 OS
<< "#define svcvtnt_f32_f64_x svcvtnt_f32_f64_m\n\n";
1364 OS
<< "#define svcvtxnt_f32_x svcvtxnt_f32_m\n";
1365 OS
<< "#define svcvtxnt_f32_f64_x svcvtxnt_f32_f64_m\n\n";
1367 OS
<< "#ifdef __cplusplus\n";
1368 OS
<< "} // extern \"C\"\n";
1370 OS
<< "#undef __ai\n\n";
1371 OS
<< "#undef __aio\n\n";
1372 OS
<< "#endif /* __ARM_SVE_H */\n";
1375 void SVEEmitter::createBuiltins(raw_ostream
&OS
) {
1376 std::vector
<Record
*> RV
= Records
.getAllDerivedDefinitions("Inst");
1377 SmallVector
<std::unique_ptr
<Intrinsic
>, 128> Defs
;
1379 createIntrinsic(R
, Defs
);
1381 // The mappings must be sorted based on BuiltinID.
1382 llvm::sort(Defs
, [](const std::unique_ptr
<Intrinsic
> &A
,
1383 const std::unique_ptr
<Intrinsic
> &B
) {
1384 return A
->getMangledName() < B
->getMangledName();
1387 OS
<< "#ifdef GET_SVE_BUILTINS\n";
1388 for (auto &Def
: Defs
) {
1389 // Only create BUILTINs for non-overloaded intrinsics, as overloaded
1390 // declarations only live in the header file.
1391 if (Def
->getClassKind() != ClassG
)
1392 OS
<< "TARGET_BUILTIN(__builtin_sve_" << Def
->getMangledName() << ", \""
1393 << Def
->getBuiltinTypeStr() << "\", \"n\", \"" << Def
->getGuard()
1397 // Add reinterpret builtins
1398 for (const ReinterpretTypeInfo
&From
: Reinterprets
)
1399 for (const ReinterpretTypeInfo
&To
: Reinterprets
)
1400 OS
<< "TARGET_BUILTIN(__builtin_sve_reinterpret_" << From
.Suffix
<< "_"
1401 << To
.Suffix
<< +", \"" << From
.BuiltinType
<< To
.BuiltinType
1402 << "\", \"n\", \"sve\")\n";
1407 void SVEEmitter::createCodeGenMap(raw_ostream
&OS
) {
1408 std::vector
<Record
*> RV
= Records
.getAllDerivedDefinitions("Inst");
1409 SmallVector
<std::unique_ptr
<Intrinsic
>, 128> Defs
;
1411 createIntrinsic(R
, Defs
);
1413 // The mappings must be sorted based on BuiltinID.
1414 llvm::sort(Defs
, [](const std::unique_ptr
<Intrinsic
> &A
,
1415 const std::unique_ptr
<Intrinsic
> &B
) {
1416 return A
->getMangledName() < B
->getMangledName();
1419 OS
<< "#ifdef GET_SVE_LLVM_INTRINSIC_MAP\n";
1420 for (auto &Def
: Defs
) {
1421 // Builtins only exist for non-overloaded intrinsics, overloaded
1422 // declarations only live in the header file.
1423 if (Def
->getClassKind() == ClassG
)
1426 uint64_t Flags
= Def
->getFlags();
1427 auto FlagString
= std::to_string(Flags
);
1429 std::string LLVMName
= Def
->getMangledLLVMName();
1430 std::string Builtin
= Def
->getMangledName();
1431 if (!LLVMName
.empty())
1432 OS
<< "SVEMAP1(" << Builtin
<< ", " << LLVMName
<< ", " << FlagString
1435 OS
<< "SVEMAP2(" << Builtin
<< ", " << FlagString
<< "),\n";
1440 void SVEEmitter::createRangeChecks(raw_ostream
&OS
) {
1441 std::vector
<Record
*> RV
= Records
.getAllDerivedDefinitions("Inst");
1442 SmallVector
<std::unique_ptr
<Intrinsic
>, 128> Defs
;
1444 createIntrinsic(R
, Defs
);
1446 // The mappings must be sorted based on BuiltinID.
1447 llvm::sort(Defs
, [](const std::unique_ptr
<Intrinsic
> &A
,
1448 const std::unique_ptr
<Intrinsic
> &B
) {
1449 return A
->getMangledName() < B
->getMangledName();
1453 OS
<< "#ifdef GET_SVE_IMMEDIATE_CHECK\n";
1455 // Ensure these are only emitted once.
1456 std::set
<std::string
> Emitted
;
1458 for (auto &Def
: Defs
) {
1459 if (Emitted
.find(Def
->getMangledName()) != Emitted
.end() ||
1460 Def
->getImmChecks().empty())
1463 OS
<< "case SVE::BI__builtin_sve_" << Def
->getMangledName() << ":\n";
1464 for (auto &Check
: Def
->getImmChecks())
1465 OS
<< "ImmChecks.push_back(std::make_tuple(" << Check
.getArg() << ", "
1466 << Check
.getKind() << ", " << Check
.getElementSizeInBits() << "));\n";
1469 Emitted
.insert(Def
->getMangledName());
1475 /// Create the SVETypeFlags used in CGBuiltins
1476 void SVEEmitter::createTypeFlags(raw_ostream
&OS
) {
1477 OS
<< "#ifdef LLVM_GET_SVE_TYPEFLAGS\n";
1478 for (auto &KV
: FlagTypes
)
1479 OS
<< "const uint64_t " << KV
.getKey() << " = " << KV
.getValue() << ";\n";
1482 OS
<< "#ifdef LLVM_GET_SVE_ELTTYPES\n";
1483 for (auto &KV
: EltTypes
)
1484 OS
<< " " << KV
.getKey() << " = " << KV
.getValue() << ",\n";
1487 OS
<< "#ifdef LLVM_GET_SVE_MEMELTTYPES\n";
1488 for (auto &KV
: MemEltTypes
)
1489 OS
<< " " << KV
.getKey() << " = " << KV
.getValue() << ",\n";
1492 OS
<< "#ifdef LLVM_GET_SVE_MERGETYPES\n";
1493 for (auto &KV
: MergeTypes
)
1494 OS
<< " " << KV
.getKey() << " = " << KV
.getValue() << ",\n";
1497 OS
<< "#ifdef LLVM_GET_SVE_IMMCHECKTYPES\n";
1498 for (auto &KV
: ImmCheckTypes
)
1499 OS
<< " " << KV
.getKey() << " = " << KV
.getValue() << ",\n";
1503 void SVEEmitter::createSMEHeader(raw_ostream
&OS
) {
1504 OS
<< "/*===---- arm_sme_draft_spec_subject_to_change.h - ARM SME intrinsics "
1508 " * Part of the LLVM Project, under the Apache License v2.0 with LLVM "
1510 " * See https://llvm.org/LICENSE.txt for license information.\n"
1511 " * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception\n"
1513 " *===-----------------------------------------------------------------"
1517 OS
<< "#ifndef __ARM_SME_H\n";
1518 OS
<< "#define __ARM_SME_H\n\n";
1520 OS
<< "#if !defined(__LITTLE_ENDIAN__)\n";
1521 OS
<< "#error \"Big endian is currently not supported for arm_sme_draft_spec_subject_to_change.h\"\n";
1524 OS
<< "#include <arm_sve.h> \n\n";
1526 OS
<< "/* Function attributes */\n";
1527 OS
<< "#define __ai static __inline__ __attribute__((__always_inline__, "
1528 "__nodebug__))\n\n";
1529 OS
<< "#define __aio static __inline__ __attribute__((__always_inline__, "
1530 "__nodebug__, __overloadable__))\n\n";
1532 OS
<< "#ifdef __cplusplus\n";
1533 OS
<< "extern \"C\" {\n";
1536 SmallVector
<std::unique_ptr
<Intrinsic
>, 128> Defs
;
1537 std::vector
<Record
*> RV
= Records
.getAllDerivedDefinitions("Inst");
1539 createIntrinsic(R
, Defs
);
1541 // Sort intrinsics in header file by following order/priority similar to SVE:
1542 // - Architectural guard
1543 // - Class (is intrinsic overloaded or not)
1545 std::stable_sort(Defs
.begin(), Defs
.end(),
1546 [](const std::unique_ptr
<Intrinsic
> &A
,
1547 const std::unique_ptr
<Intrinsic
> &B
) {
1548 auto ToTuple
= [](const std::unique_ptr
<Intrinsic
> &I
) {
1549 return std::make_tuple(I
->getGuard(),
1550 (unsigned)I
->getClassKind(),
1553 return ToTuple(A
) < ToTuple(B
);
1556 // Actually emit the intrinsic declaration.
1557 for (auto &I
: Defs
) {
1558 I
->emitIntrinsic(OS
, *this);
1561 OS
<< "#ifdef __cplusplus\n";
1562 OS
<< "} // extern \"C\"\n";
1564 OS
<< "#undef __ai\n\n";
1565 OS
<< "#endif /* __ARM_SME_H */\n";
1568 void SVEEmitter::createSMEBuiltins(raw_ostream
&OS
) {
1569 std::vector
<Record
*> RV
= Records
.getAllDerivedDefinitions("Inst");
1570 SmallVector
<std::unique_ptr
<Intrinsic
>, 128> Defs
;
1571 for (auto *R
: RV
) {
1572 createIntrinsic(R
, Defs
);
1575 // The mappings must be sorted based on BuiltinID.
1576 llvm::sort(Defs
, [](const std::unique_ptr
<Intrinsic
> &A
,
1577 const std::unique_ptr
<Intrinsic
> &B
) {
1578 return A
->getMangledName() < B
->getMangledName();
1581 OS
<< "#ifdef GET_SME_BUILTINS\n";
1582 for (auto &Def
: Defs
) {
1583 // Only create BUILTINs for non-overloaded intrinsics, as overloaded
1584 // declarations only live in the header file.
1585 if (Def
->getClassKind() != ClassG
)
1586 OS
<< "TARGET_BUILTIN(__builtin_sme_" << Def
->getMangledName() << ", \""
1587 << Def
->getBuiltinTypeStr() << "\", \"n\", \"" << Def
->getGuard()
1594 void SVEEmitter::createSMECodeGenMap(raw_ostream
&OS
) {
1595 std::vector
<Record
*> RV
= Records
.getAllDerivedDefinitions("Inst");
1596 SmallVector
<std::unique_ptr
<Intrinsic
>, 128> Defs
;
1597 for (auto *R
: RV
) {
1598 createIntrinsic(R
, Defs
);
1601 // The mappings must be sorted based on BuiltinID.
1602 llvm::sort(Defs
, [](const std::unique_ptr
<Intrinsic
> &A
,
1603 const std::unique_ptr
<Intrinsic
> &B
) {
1604 return A
->getMangledName() < B
->getMangledName();
1607 OS
<< "#ifdef GET_SME_LLVM_INTRINSIC_MAP\n";
1608 for (auto &Def
: Defs
) {
1609 // Builtins only exist for non-overloaded intrinsics, overloaded
1610 // declarations only live in the header file.
1611 if (Def
->getClassKind() == ClassG
)
1614 uint64_t Flags
= Def
->getFlags();
1615 auto FlagString
= std::to_string(Flags
);
1617 std::string LLVMName
= Def
->getLLVMName();
1618 std::string Builtin
= Def
->getMangledName();
1619 if (!LLVMName
.empty())
1620 OS
<< "SMEMAP1(" << Builtin
<< ", " << LLVMName
<< ", " << FlagString
1623 OS
<< "SMEMAP2(" << Builtin
<< ", " << FlagString
<< "),\n";
1628 void SVEEmitter::createSMERangeChecks(raw_ostream
&OS
) {
1629 std::vector
<Record
*> RV
= Records
.getAllDerivedDefinitions("Inst");
1630 SmallVector
<std::unique_ptr
<Intrinsic
>, 128> Defs
;
1631 for (auto *R
: RV
) {
1632 createIntrinsic(R
, Defs
);
1635 // The mappings must be sorted based on BuiltinID.
1636 llvm::sort(Defs
, [](const std::unique_ptr
<Intrinsic
> &A
,
1637 const std::unique_ptr
<Intrinsic
> &B
) {
1638 return A
->getMangledName() < B
->getMangledName();
1642 OS
<< "#ifdef GET_SME_IMMEDIATE_CHECK\n";
1644 // Ensure these are only emitted once.
1645 std::set
<std::string
> Emitted
;
1647 for (auto &Def
: Defs
) {
1648 if (Emitted
.find(Def
->getMangledName()) != Emitted
.end() ||
1649 Def
->getImmChecks().empty())
1652 OS
<< "case SME::BI__builtin_sme_" << Def
->getMangledName() << ":\n";
1653 for (auto &Check
: Def
->getImmChecks())
1654 OS
<< "ImmChecks.push_back(std::make_tuple(" << Check
.getArg() << ", "
1655 << Check
.getKind() << ", " << Check
.getElementSizeInBits() << "));\n";
1658 Emitted
.insert(Def
->getMangledName());
1665 void EmitSveHeader(RecordKeeper
&Records
, raw_ostream
&OS
) {
1666 SVEEmitter(Records
).createHeader(OS
);
1669 void EmitSveBuiltins(RecordKeeper
&Records
, raw_ostream
&OS
) {
1670 SVEEmitter(Records
).createBuiltins(OS
);
1673 void EmitSveBuiltinCG(RecordKeeper
&Records
, raw_ostream
&OS
) {
1674 SVEEmitter(Records
).createCodeGenMap(OS
);
1677 void EmitSveRangeChecks(RecordKeeper
&Records
, raw_ostream
&OS
) {
1678 SVEEmitter(Records
).createRangeChecks(OS
);
1681 void EmitSveTypeFlags(RecordKeeper
&Records
, raw_ostream
&OS
) {
1682 SVEEmitter(Records
).createTypeFlags(OS
);
1685 void EmitSmeHeader(RecordKeeper
&Records
, raw_ostream
&OS
) {
1686 SVEEmitter(Records
).createSMEHeader(OS
);
1689 void EmitSmeBuiltins(RecordKeeper
&Records
, raw_ostream
&OS
) {
1690 SVEEmitter(Records
).createSMEBuiltins(OS
);
1693 void EmitSmeBuiltinCG(RecordKeeper
&Records
, raw_ostream
&OS
) {
1694 SVEEmitter(Records
).createSMECodeGenMap(OS
);
1697 void EmitSmeRangeChecks(RecordKeeper
&Records
, raw_ostream
&OS
) {
1698 SVEEmitter(Records
).createSMERangeChecks(OS
);
1700 } // End namespace clang