/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/utils/TableGen/SveEmitter.cpp
Line | Count | Source (jump to first uncovered line) |
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/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" |
32 | | #include <string> |
33 | | #include <sstream> |
34 | | #include <set> |
35 | | #include <cctype> |
36 | | #include <tuple> |
37 | | |
38 | | using namespace llvm; |
39 | | |
40 | | enum ClassKind { |
41 | | ClassNone, |
42 | | ClassS, // signed/unsigned, e.g., "_s8", "_u8" suffix |
43 | | ClassG, // Overloaded name without type suffix |
44 | | }; |
45 | | |
46 | | using TypeSpec = std::string; |
47 | | |
48 | | namespace { |
49 | | |
50 | | class ImmCheck { |
51 | | unsigned Arg; |
52 | | unsigned Kind; |
53 | | unsigned ElementSizeInBits; |
54 | | |
55 | | public: |
56 | | ImmCheck(unsigned Arg, unsigned Kind, unsigned ElementSizeInBits = 0) |
57 | 0 | : Arg(Arg), Kind(Kind), ElementSizeInBits(ElementSizeInBits) {} |
58 | | ImmCheck(const ImmCheck &Other) = default; |
59 | | ~ImmCheck() = default; |
60 | | |
61 | 0 | unsigned getArg() const { return Arg; } |
62 | 0 | unsigned getKind() const { return Kind; } |
63 | 0 | unsigned getElementSizeInBits() const { return ElementSizeInBits; } |
64 | | }; |
65 | | |
66 | | class SVEType { |
67 | | TypeSpec TS; |
68 | | bool Float, Signed, Immediate, Void, Constant, Pointer, BFloat; |
69 | | bool DefaultType, IsScalable, Predicate, PredicatePattern, PrefetchOp; |
70 | | unsigned Bitwidth, ElementBitwidth, NumVectors; |
71 | | |
72 | | public: |
73 | 0 | SVEType() : SVEType(TypeSpec(), 'v') {} |
74 | | |
75 | | SVEType(TypeSpec TS, char CharMod) |
76 | | : TS(TS), Float(false), Signed(true), Immediate(false), Void(false), |
77 | | Constant(false), Pointer(false), BFloat(false), DefaultType(false), |
78 | | IsScalable(true), Predicate(false), PredicatePattern(false), |
79 | 0 | PrefetchOp(false), Bitwidth(128), ElementBitwidth(~0U), NumVectors(1) { |
80 | 0 | if (!TS.empty()) |
81 | 0 | applyTypespec(); |
82 | 0 | applyModifier(CharMod); |
83 | 0 | } |
84 | | |
85 | 0 | bool isPointer() const { return Pointer; } |
86 | 0 | bool isVoidPointer() const { return Pointer && Void; } |
87 | 0 | bool isSigned() const { return Signed; } |
88 | 0 | bool isImmediate() const { return Immediate; } |
89 | 0 | bool isScalar() const { return NumVectors == 0; } |
90 | 0 | bool isVector() const { return NumVectors > 0; } |
91 | 0 | bool isScalableVector() const { return isVector() && IsScalable; } |
92 | 0 | bool isChar() const { return ElementBitwidth == 8; } |
93 | 0 | bool isVoid() const { return Void & !Pointer; } |
94 | 0 | bool isDefault() const { return DefaultType; } |
95 | 0 | bool isFloat() const { return Float && !BFloat; } |
96 | 0 | bool isBFloat() const { return BFloat && !Float; } |
97 | 0 | bool isFloatingPoint() const { return Float || BFloat; } |
98 | 0 | bool isInteger() const { return !isFloatingPoint() && !Predicate; } |
99 | 0 | bool isScalarPredicate() const { |
100 | 0 | return !isFloatingPoint() && Predicate && NumVectors == 0; |
101 | 0 | } |
102 | 0 | bool isPredicateVector() const { return Predicate; } |
103 | 0 | bool isPredicatePattern() const { return PredicatePattern; } |
104 | 0 | bool isPrefetchOp() const { return PrefetchOp; } |
105 | 0 | bool isConstant() const { return Constant; } |
106 | 0 | unsigned getElementSizeInBits() const { return ElementBitwidth; } |
107 | 0 | unsigned getNumVectors() const { return NumVectors; } |
108 | | |
109 | 0 | unsigned getNumElements() const { |
110 | 0 | assert(ElementBitwidth != ~0U); |
111 | 0 | return Bitwidth / ElementBitwidth; |
112 | 0 | } |
113 | 0 | unsigned getSizeInBits() const { |
114 | 0 | return Bitwidth; |
115 | 0 | } |
116 | | |
117 | | /// Return the string representation of a type, which is an encoded |
118 | | /// string for passing to the BUILTIN() macro in Builtins.def. |
119 | | std::string builtin_str() const; |
120 | | |
121 | | /// Return the C/C++ string representation of a type for use in the |
122 | | /// arm_sve.h header file. |
123 | | std::string str() const; |
124 | | |
125 | | private: |
126 | | /// Creates the type based on the typespec string in TS. |
127 | | void applyTypespec(); |
128 | | |
129 | | /// Applies a prototype modifier to the type. |
130 | | void applyModifier(char Mod); |
131 | | }; |
132 | | |
133 | | |
134 | | class SVEEmitter; |
135 | | |
136 | | /// The main grunt class. This represents an instantiation of an intrinsic with |
137 | | /// a particular typespec and prototype. |
138 | | class Intrinsic { |
139 | | /// The unmangled name. |
140 | | std::string Name; |
141 | | |
142 | | /// The name of the corresponding LLVM IR intrinsic. |
143 | | std::string LLVMName; |
144 | | |
145 | | /// Intrinsic prototype. |
146 | | std::string Proto; |
147 | | |
148 | | /// The base type spec for this intrinsic. |
149 | | TypeSpec BaseTypeSpec; |
150 | | |
151 | | /// The base class kind. Most intrinsics use ClassS, which has full type |
152 | | /// info for integers (_s32/_u32), or ClassG which is used for overloaded |
153 | | /// intrinsics. |
154 | | ClassKind Class; |
155 | | |
156 | | /// The architectural #ifdef guard. |
157 | | std::string Guard; |
158 | | |
159 | | // The merge suffix such as _m, _x or _z. |
160 | | std::string MergeSuffix; |
161 | | |
162 | | /// The types of return value [0] and parameters [1..]. |
163 | | std::vector<SVEType> Types; |
164 | | |
165 | | /// The "base type", which is VarType('d', BaseTypeSpec). |
166 | | SVEType BaseType; |
167 | | |
168 | | uint64_t Flags; |
169 | | |
170 | | SmallVector<ImmCheck, 2> ImmChecks; |
171 | | |
172 | | public: |
173 | | Intrinsic(StringRef Name, StringRef Proto, uint64_t MergeTy, |
174 | | StringRef MergeSuffix, uint64_t MemoryElementTy, StringRef LLVMName, |
175 | | uint64_t Flags, ArrayRef<ImmCheck> ImmChecks, TypeSpec BT, |
176 | | ClassKind Class, SVEEmitter &Emitter, StringRef Guard); |
177 | | |
178 | 0 | ~Intrinsic()=default; |
179 | | |
180 | 0 | std::string getName() const { return Name; } |
181 | 0 | std::string getLLVMName() const { return LLVMName; } |
182 | 0 | std::string getProto() const { return Proto; } |
183 | 0 | TypeSpec getBaseTypeSpec() const { return BaseTypeSpec; } |
184 | 0 | SVEType getBaseType() const { return BaseType; } |
185 | | |
186 | 0 | StringRef getGuard() const { return Guard; } |
187 | 0 | ClassKind getClassKind() const { return Class; } |
188 | | |
189 | 0 | SVEType getReturnType() const { return Types[0]; } |
190 | 0 | ArrayRef<SVEType> getTypes() const { return Types; } |
191 | 0 | SVEType getParamType(unsigned I) const { return Types[I + 1]; } |
192 | 0 | unsigned getNumParams() const { return Proto.size() - 1; } |
193 | | |
194 | 0 | uint64_t getFlags() const { return Flags; } |
195 | 0 | bool isFlagSet(uint64_t Flag) const { return Flags & Flag;} |
196 | | |
197 | 0 | ArrayRef<ImmCheck> getImmChecks() const { return ImmChecks; } |
198 | | |
199 | | /// Return the type string for a BUILTIN() macro in Builtins.def. |
200 | | std::string getBuiltinTypeStr(); |
201 | | |
202 | | /// Return the name, mangled with type information. The name is mangled for |
203 | | /// ClassS, so will add type suffixes such as _u32/_s32. |
204 | 0 | std::string getMangledName() const { return mangleName(ClassS); } |
205 | | |
206 | | /// Returns true if the intrinsic is overloaded, in that it should also generate |
207 | | /// a short form without the type-specifiers, e.g. 'svld1(..)' instead of |
208 | | /// 'svld1_u32(..)'. |
209 | 0 | static bool isOverloadedIntrinsic(StringRef Name) { |
210 | 0 | auto BrOpen = Name.find('['); |
211 | 0 | auto BrClose = Name.find(']'); |
212 | 0 | return BrOpen != std::string::npos && BrClose != std::string::npos; |
213 | 0 | } |
214 | | |
215 | | /// Return true if the intrinsic takes a splat operand. |
216 | 0 | bool hasSplat() const { |
217 | | // These prototype modifiers are described in arm_sve.td. |
218 | 0 | return Proto.find_first_of("ajfrKLR@") != std::string::npos; |
219 | 0 | } |
220 | | |
221 | | /// Return the parameter index of the splat operand. |
222 | 0 | unsigned getSplatIdx() const { |
223 | | // These prototype modifiers are described in arm_sve.td. |
224 | 0 | auto Idx = Proto.find_first_of("ajfrKLR@"); |
225 | 0 | assert(Idx != std::string::npos && Idx > 0 && |
226 | 0 | "Prototype has no splat operand"); |
227 | 0 | return Idx - 1; |
228 | 0 | } |
229 | | |
230 | | /// Emits the intrinsic declaration to the ostream. |
231 | | void emitIntrinsic(raw_ostream &OS) const; |
232 | | |
233 | | private: |
234 | 0 | std::string getMergeSuffix() const { return MergeSuffix; } |
235 | | std::string mangleName(ClassKind LocalCK) const; |
236 | | std::string replaceTemplatedArgs(std::string Name, TypeSpec TS, |
237 | | std::string Proto) const; |
238 | | }; |
239 | | |
240 | | class SVEEmitter { |
241 | | private: |
242 | | // The reinterpret builtins are generated separately because they |
243 | | // need the cross product of all types (121 functions in total), |
244 | | // which is inconvenient to specify in the arm_sve.td file or |
245 | | // generate in CGBuiltin.cpp. |
246 | | struct ReinterpretTypeInfo { |
247 | | const char *Suffix; |
248 | | const char *Type; |
249 | | const char *BuiltinType; |
250 | | }; |
251 | | SmallVector<ReinterpretTypeInfo, 12> Reinterprets = { |
252 | | {"s8", "svint8_t", "q16Sc"}, {"s16", "svint16_t", "q8Ss"}, |
253 | | {"s32", "svint32_t", "q4Si"}, {"s64", "svint64_t", "q2SWi"}, |
254 | | {"u8", "svuint8_t", "q16Uc"}, {"u16", "svuint16_t", "q8Us"}, |
255 | | {"u32", "svuint32_t", "q4Ui"}, {"u64", "svuint64_t", "q2UWi"}, |
256 | | {"f16", "svfloat16_t", "q8h"}, {"bf16", "svbfloat16_t", "q8y"}, |
257 | | {"f32", "svfloat32_t", "q4f"}, {"f64", "svfloat64_t", "q2d"}}; |
258 | | |
259 | | RecordKeeper &Records; |
260 | | llvm::StringMap<uint64_t> EltTypes; |
261 | | llvm::StringMap<uint64_t> MemEltTypes; |
262 | | llvm::StringMap<uint64_t> FlagTypes; |
263 | | llvm::StringMap<uint64_t> MergeTypes; |
264 | | llvm::StringMap<uint64_t> ImmCheckTypes; |
265 | | |
266 | | public: |
267 | 0 | SVEEmitter(RecordKeeper &R) : Records(R) { |
268 | 0 | for (auto *RV : Records.getAllDerivedDefinitions("EltType")) |
269 | 0 | EltTypes[RV->getNameInitAsString()] = RV->getValueAsInt("Value"); |
270 | 0 | for (auto *RV : Records.getAllDerivedDefinitions("MemEltType")) |
271 | 0 | MemEltTypes[RV->getNameInitAsString()] = RV->getValueAsInt("Value"); |
272 | 0 | for (auto *RV : Records.getAllDerivedDefinitions("FlagType")) |
273 | 0 | FlagTypes[RV->getNameInitAsString()] = RV->getValueAsInt("Value"); |
274 | 0 | for (auto *RV : Records.getAllDerivedDefinitions("MergeType")) |
275 | 0 | MergeTypes[RV->getNameInitAsString()] = RV->getValueAsInt("Value"); |
276 | 0 | for (auto *RV : Records.getAllDerivedDefinitions("ImmCheckType")) |
277 | 0 | ImmCheckTypes[RV->getNameInitAsString()] = RV->getValueAsInt("Value"); |
278 | 0 | } |
279 | | |
280 | | /// Returns the enum value for the immcheck type |
281 | 0 | unsigned getEnumValueForImmCheck(StringRef C) const { |
282 | 0 | auto It = ImmCheckTypes.find(C); |
283 | 0 | if (It != ImmCheckTypes.end()) |
284 | 0 | return It->getValue(); |
285 | 0 | llvm_unreachable("Unsupported imm check"); |
286 | 0 | } |
287 | | |
288 | | /// Returns the enum value for the flag type |
289 | 0 | uint64_t getEnumValueForFlag(StringRef C) const { |
290 | 0 | auto Res = FlagTypes.find(C); |
291 | 0 | if (Res != FlagTypes.end()) |
292 | 0 | return Res->getValue(); |
293 | 0 | llvm_unreachable("Unsupported flag"); |
294 | 0 | } |
295 | | |
296 | | // Returns the SVETypeFlags for a given value and mask. |
297 | 0 | uint64_t encodeFlag(uint64_t V, StringRef MaskName) const { |
298 | 0 | auto It = FlagTypes.find(MaskName); |
299 | 0 | if (It != FlagTypes.end()) { |
300 | 0 | uint64_t Mask = It->getValue(); |
301 | 0 | unsigned Shift = llvm::countTrailingZeros(Mask); |
302 | 0 | return (V << Shift) & Mask; |
303 | 0 | } |
304 | 0 | llvm_unreachable("Unsupported flag"); |
305 | 0 | } |
306 | | |
307 | | // Returns the SVETypeFlags for the given element type. |
308 | 0 | uint64_t encodeEltType(StringRef EltName) { |
309 | 0 | auto It = EltTypes.find(EltName); |
310 | 0 | if (It != EltTypes.end()) |
311 | 0 | return encodeFlag(It->getValue(), "EltTypeMask"); |
312 | 0 | llvm_unreachable("Unsupported EltType"); |
313 | 0 | } |
314 | | |
315 | | // Returns the SVETypeFlags for the given memory element type. |
316 | 0 | uint64_t encodeMemoryElementType(uint64_t MT) { |
317 | 0 | return encodeFlag(MT, "MemEltTypeMask"); |
318 | 0 | } |
319 | | |
320 | | // Returns the SVETypeFlags for the given merge type. |
321 | 0 | uint64_t encodeMergeType(uint64_t MT) { |
322 | 0 | return encodeFlag(MT, "MergeTypeMask"); |
323 | 0 | } |
324 | | |
325 | | // Returns the SVETypeFlags for the given splat operand. |
326 | 0 | unsigned encodeSplatOperand(unsigned SplatIdx) { |
327 | 0 | assert(SplatIdx < 7 && "SplatIdx out of encodable range"); |
328 | 0 | return encodeFlag(SplatIdx + 1, "SplatOperandMask"); |
329 | 0 | } |
330 | | |
331 | | // Returns the SVETypeFlags value for the given SVEType. |
332 | | uint64_t encodeTypeFlags(const SVEType &T); |
333 | | |
334 | | /// Emit arm_sve.h. |
335 | | void createHeader(raw_ostream &o); |
336 | | |
337 | | /// Emit all the __builtin prototypes and code needed by Sema. |
338 | | void createBuiltins(raw_ostream &o); |
339 | | |
340 | | /// Emit all the information needed to map builtin -> LLVM IR intrinsic. |
341 | | void createCodeGenMap(raw_ostream &o); |
342 | | |
343 | | /// Emit all the range checks for the immediates. |
344 | | void createRangeChecks(raw_ostream &o); |
345 | | |
346 | | /// Create the SVETypeFlags used in CGBuiltins |
347 | | void createTypeFlags(raw_ostream &o); |
348 | | |
349 | | /// Create intrinsic and add it to \p Out |
350 | | void createIntrinsic(Record *R, SmallVectorImpl<std::unique_ptr<Intrinsic>> &Out); |
351 | | }; |
352 | | |
353 | | } // end anonymous namespace |
354 | | |
355 | | |
356 | | //===----------------------------------------------------------------------===// |
357 | | // Type implementation |
358 | | //===----------------------------------------------------------------------===// |
359 | | |
360 | 0 | std::string SVEType::builtin_str() const { |
361 | 0 | std::string S; |
362 | 0 | if (isVoid()) |
363 | 0 | return "v"; |
364 | | |
365 | 0 | if (isScalarPredicate()) |
366 | 0 | return "b"; |
367 | | |
368 | 0 | if (isVoidPointer()) |
369 | 0 | S += "v"; |
370 | 0 | else if (!isFloatingPoint()) |
371 | 0 | switch (ElementBitwidth) { |
372 | 0 | case 1: S += "b"; break; |
373 | 0 | case 8: S += "c"; break; |
374 | 0 | case 16: S += "s"; break; |
375 | 0 | case 32: S += "i"; break; |
376 | 0 | case 64: S += "Wi"; break; |
377 | 0 | case 128: S += "LLLi"; break; |
378 | 0 | default: llvm_unreachable("Unhandled case!"); |
379 | 0 | } |
380 | 0 | else if (isFloat()) |
381 | 0 | switch (ElementBitwidth) { |
382 | 0 | case 16: S += "h"; break; |
383 | 0 | case 32: S += "f"; break; |
384 | 0 | case 64: S += "d"; break; |
385 | 0 | default: llvm_unreachable("Unhandled case!"); |
386 | 0 | } |
387 | 0 | else if (isBFloat()) { |
388 | 0 | assert(ElementBitwidth == 16 && "Not a valid BFloat."); |
389 | 0 | S += "y"; |
390 | 0 | } |
391 | | |
392 | 0 | if (!isFloatingPoint()) { |
393 | 0 | if ((isChar() || isPointer()) && !isVoidPointer()) { |
394 | | // Make chars and typed pointers explicitly signed. |
395 | 0 | if (Signed) |
396 | 0 | S = "S" + S; |
397 | 0 | else if (!Signed) |
398 | 0 | S = "U" + S; |
399 | 0 | } else if (!isVoidPointer() && !Signed) { |
400 | 0 | S = "U" + S; |
401 | 0 | } |
402 | 0 | } |
403 | | |
404 | | // Constant indices are "int", but have the "constant expression" modifier. |
405 | 0 | if (isImmediate()) { |
406 | 0 | assert(!isFloat() && "fp immediates are not supported"); |
407 | 0 | S = "I" + S; |
408 | 0 | } |
409 | | |
410 | 0 | if (isScalar()) { |
411 | 0 | if (Constant) S += "C"; |
412 | 0 | if (Pointer) S += "*"; |
413 | 0 | return S; |
414 | 0 | } |
415 | | |
416 | 0 | assert(isScalableVector() && "Unsupported type"); |
417 | 0 | return "q" + utostr(getNumElements() * NumVectors) + S; |
418 | 0 | } |
419 | | |
420 | 0 | std::string SVEType::str() const { |
421 | 0 | if (isPredicatePattern()) |
422 | 0 | return "enum svpattern"; |
423 | | |
424 | 0 | if (isPrefetchOp()) |
425 | 0 | return "enum svprfop"; |
426 | | |
427 | 0 | std::string S; |
428 | 0 | if (Void) |
429 | 0 | S += "void"; |
430 | 0 | else { |
431 | 0 | if (isScalableVector()) |
432 | 0 | S += "sv"; |
433 | 0 | if (!Signed && !isFloatingPoint()) |
434 | 0 | S += "u"; |
435 | |
|
436 | 0 | if (Float) |
437 | 0 | S += "float"; |
438 | 0 | else if (isScalarPredicate() || isPredicateVector()) |
439 | 0 | S += "bool"; |
440 | 0 | else if (isBFloat()) |
441 | 0 | S += "bfloat"; |
442 | 0 | else |
443 | 0 | S += "int"; |
444 | |
|
445 | 0 | if (!isScalarPredicate() && !isPredicateVector()) |
446 | 0 | S += utostr(ElementBitwidth); |
447 | 0 | if (!isScalableVector() && isVector()) |
448 | 0 | S += "x" + utostr(getNumElements()); |
449 | 0 | if (NumVectors > 1) |
450 | 0 | S += "x" + utostr(NumVectors); |
451 | 0 | if (!isScalarPredicate()) |
452 | 0 | S += "_t"; |
453 | 0 | } |
454 | |
|
455 | 0 | if (Constant) |
456 | 0 | S += " const"; |
457 | 0 | if (Pointer) |
458 | 0 | S += " *"; |
459 | |
|
460 | 0 | return S; |
461 | 0 | } |
462 | 0 | void SVEType::applyTypespec() { |
463 | 0 | for (char I : TS) { |
464 | 0 | switch (I) { |
465 | 0 | case 'P': |
466 | 0 | Predicate = true; |
467 | 0 | break; |
468 | 0 | case 'U': |
469 | 0 | Signed = false; |
470 | 0 | break; |
471 | 0 | case 'c': |
472 | 0 | ElementBitwidth = 8; |
473 | 0 | break; |
474 | 0 | case 's': |
475 | 0 | ElementBitwidth = 16; |
476 | 0 | break; |
477 | 0 | case 'i': |
478 | 0 | ElementBitwidth = 32; |
479 | 0 | break; |
480 | 0 | case 'l': |
481 | 0 | ElementBitwidth = 64; |
482 | 0 | break; |
483 | 0 | case 'h': |
484 | 0 | Float = true; |
485 | 0 | ElementBitwidth = 16; |
486 | 0 | break; |
487 | 0 | case 'f': |
488 | 0 | Float = true; |
489 | 0 | ElementBitwidth = 32; |
490 | 0 | break; |
491 | 0 | case 'd': |
492 | 0 | Float = true; |
493 | 0 | ElementBitwidth = 64; |
494 | 0 | break; |
495 | 0 | case 'b': |
496 | 0 | BFloat = true; |
497 | 0 | Float = false; |
498 | 0 | ElementBitwidth = 16; |
499 | 0 | break; |
500 | 0 | default: |
501 | 0 | llvm_unreachable("Unhandled type code!"); |
502 | 0 | } |
503 | 0 | } |
504 | 0 | assert(ElementBitwidth != ~0U && "Bad element bitwidth!"); |
505 | 0 | } |
506 | | |
507 | 0 | void SVEType::applyModifier(char Mod) { |
508 | 0 | switch (Mod) { |
509 | 0 | case '2': |
510 | 0 | NumVectors = 2; |
511 | 0 | break; |
512 | 0 | case '3': |
513 | 0 | NumVectors = 3; |
514 | 0 | break; |
515 | 0 | case '4': |
516 | 0 | NumVectors = 4; |
517 | 0 | break; |
518 | 0 | case 'v': |
519 | 0 | Void = true; |
520 | 0 | break; |
521 | 0 | case 'd': |
522 | 0 | DefaultType = true; |
523 | 0 | break; |
524 | 0 | case 'c': |
525 | 0 | Constant = true; |
526 | 0 | LLVM_FALLTHROUGH; |
527 | 0 | case 'p': |
528 | 0 | Pointer = true; |
529 | 0 | Bitwidth = ElementBitwidth; |
530 | 0 | NumVectors = 0; |
531 | 0 | break; |
532 | 0 | case 'e': |
533 | 0 | Signed = false; |
534 | 0 | ElementBitwidth /= 2; |
535 | 0 | break; |
536 | 0 | case 'h': |
537 | 0 | ElementBitwidth /= 2; |
538 | 0 | break; |
539 | 0 | case 'q': |
540 | 0 | ElementBitwidth /= 4; |
541 | 0 | break; |
542 | 0 | case 'b': |
543 | 0 | Signed = false; |
544 | 0 | Float = false; |
545 | 0 | BFloat = false; |
546 | 0 | ElementBitwidth /= 4; |
547 | 0 | break; |
548 | 0 | case 'o': |
549 | 0 | ElementBitwidth *= 4; |
550 | 0 | break; |
551 | 0 | case 'P': |
552 | 0 | Signed = true; |
553 | 0 | Float = false; |
554 | 0 | BFloat = false; |
555 | 0 | Predicate = true; |
556 | 0 | Bitwidth = 16; |
557 | 0 | ElementBitwidth = 1; |
558 | 0 | break; |
559 | 0 | case 's': |
560 | 0 | case 'a': |
561 | 0 | Bitwidth = ElementBitwidth; |
562 | 0 | NumVectors = 0; |
563 | 0 | break; |
564 | 0 | case 'R': |
565 | 0 | ElementBitwidth /= 2; |
566 | 0 | NumVectors = 0; |
567 | 0 | break; |
568 | 0 | case 'r': |
569 | 0 | ElementBitwidth /= 4; |
570 | 0 | NumVectors = 0; |
571 | 0 | break; |
572 | 0 | case '@': |
573 | 0 | Signed = false; |
574 | 0 | Float = false; |
575 | 0 | BFloat = false; |
576 | 0 | ElementBitwidth /= 4; |
577 | 0 | NumVectors = 0; |
578 | 0 | break; |
579 | 0 | case 'K': |
580 | 0 | Signed = true; |
581 | 0 | Float = false; |
582 | 0 | BFloat = false; |
583 | 0 | Bitwidth = ElementBitwidth; |
584 | 0 | NumVectors = 0; |
585 | 0 | break; |
586 | 0 | case 'L': |
587 | 0 | Signed = false; |
588 | 0 | Float = false; |
589 | 0 | BFloat = false; |
590 | 0 | Bitwidth = ElementBitwidth; |
591 | 0 | NumVectors = 0; |
592 | 0 | break; |
593 | 0 | case 'u': |
594 | 0 | Predicate = false; |
595 | 0 | Signed = false; |
596 | 0 | Float = false; |
597 | 0 | BFloat = false; |
598 | 0 | break; |
599 | 0 | case 'x': |
600 | 0 | Predicate = false; |
601 | 0 | Signed = true; |
602 | 0 | Float = false; |
603 | 0 | BFloat = false; |
604 | 0 | break; |
605 | 0 | case 'i': |
606 | 0 | Predicate = false; |
607 | 0 | Float = false; |
608 | 0 | BFloat = false; |
609 | 0 | ElementBitwidth = Bitwidth = 64; |
610 | 0 | NumVectors = 0; |
611 | 0 | Signed = false; |
612 | 0 | Immediate = true; |
613 | 0 | break; |
614 | 0 | case 'I': |
615 | 0 | Predicate = false; |
616 | 0 | Float = false; |
617 | 0 | BFloat = false; |
618 | 0 | ElementBitwidth = Bitwidth = 32; |
619 | 0 | NumVectors = 0; |
620 | 0 | Signed = true; |
621 | 0 | Immediate = true; |
622 | 0 | PredicatePattern = true; |
623 | 0 | break; |
624 | 0 | case 'J': |
625 | 0 | Predicate = false; |
626 | 0 | Float = false; |
627 | 0 | BFloat = false; |
628 | 0 | ElementBitwidth = Bitwidth = 32; |
629 | 0 | NumVectors = 0; |
630 | 0 | Signed = true; |
631 | 0 | Immediate = true; |
632 | 0 | PrefetchOp = true; |
633 | 0 | break; |
634 | 0 | case 'k': |
635 | 0 | Predicate = false; |
636 | 0 | Signed = true; |
637 | 0 | Float = false; |
638 | 0 | BFloat = false; |
639 | 0 | ElementBitwidth = Bitwidth = 32; |
640 | 0 | NumVectors = 0; |
641 | 0 | break; |
642 | 0 | case 'l': |
643 | 0 | Predicate = false; |
644 | 0 | Signed = true; |
645 | 0 | Float = false; |
646 | 0 | BFloat = false; |
647 | 0 | ElementBitwidth = Bitwidth = 64; |
648 | 0 | NumVectors = 0; |
649 | 0 | break; |
650 | 0 | case 'm': |
651 | 0 | Predicate = false; |
652 | 0 | Signed = false; |
653 | 0 | Float = false; |
654 | 0 | BFloat = false; |
655 | 0 | ElementBitwidth = Bitwidth = 32; |
656 | 0 | NumVectors = 0; |
657 | 0 | break; |
658 | 0 | case 'n': |
659 | 0 | Predicate = false; |
660 | 0 | Signed = false; |
661 | 0 | Float = false; |
662 | 0 | BFloat = false; |
663 | 0 | ElementBitwidth = Bitwidth = 64; |
664 | 0 | NumVectors = 0; |
665 | 0 | break; |
666 | 0 | case 'w': |
667 | 0 | ElementBitwidth = 64; |
668 | 0 | break; |
669 | 0 | case 'j': |
670 | 0 | ElementBitwidth = Bitwidth = 64; |
671 | 0 | NumVectors = 0; |
672 | 0 | break; |
673 | 0 | case 'f': |
674 | 0 | Signed = false; |
675 | 0 | ElementBitwidth = Bitwidth = 64; |
676 | 0 | NumVectors = 0; |
677 | 0 | break; |
678 | 0 | case 'g': |
679 | 0 | Signed = false; |
680 | 0 | Float = false; |
681 | 0 | BFloat = false; |
682 | 0 | ElementBitwidth = 64; |
683 | 0 | break; |
684 | 0 | case 't': |
685 | 0 | Signed = true; |
686 | 0 | Float = false; |
687 | 0 | BFloat = false; |
688 | 0 | ElementBitwidth = 32; |
689 | 0 | break; |
690 | 0 | case 'z': |
691 | 0 | Signed = false; |
692 | 0 | Float = false; |
693 | 0 | BFloat = false; |
694 | 0 | ElementBitwidth = 32; |
695 | 0 | break; |
696 | 0 | case 'O': |
697 | 0 | Predicate = false; |
698 | 0 | Float = true; |
699 | 0 | ElementBitwidth = 16; |
700 | 0 | break; |
701 | 0 | case 'M': |
702 | 0 | Predicate = false; |
703 | 0 | Float = true; |
704 | 0 | BFloat = false; |
705 | 0 | ElementBitwidth = 32; |
706 | 0 | break; |
707 | 0 | case 'N': |
708 | 0 | Predicate = false; |
709 | 0 | Float = true; |
710 | 0 | ElementBitwidth = 64; |
711 | 0 | break; |
712 | 0 | case 'Q': |
713 | 0 | Constant = true; |
714 | 0 | Pointer = true; |
715 | 0 | Void = true; |
716 | 0 | NumVectors = 0; |
717 | 0 | break; |
718 | 0 | case 'S': |
719 | 0 | Constant = true; |
720 | 0 | Pointer = true; |
721 | 0 | ElementBitwidth = Bitwidth = 8; |
722 | 0 | NumVectors = 0; |
723 | 0 | Signed = true; |
724 | 0 | break; |
725 | 0 | case 'W': |
726 | 0 | Constant = true; |
727 | 0 | Pointer = true; |
728 | 0 | ElementBitwidth = Bitwidth = 8; |
729 | 0 | NumVectors = 0; |
730 | 0 | Signed = false; |
731 | 0 | break; |
732 | 0 | case 'T': |
733 | 0 | Constant = true; |
734 | 0 | Pointer = true; |
735 | 0 | ElementBitwidth = Bitwidth = 16; |
736 | 0 | NumVectors = 0; |
737 | 0 | Signed = true; |
738 | 0 | break; |
739 | 0 | case 'X': |
740 | 0 | Constant = true; |
741 | 0 | Pointer = true; |
742 | 0 | ElementBitwidth = Bitwidth = 16; |
743 | 0 | NumVectors = 0; |
744 | 0 | Signed = false; |
745 | 0 | break; |
746 | 0 | case 'Y': |
747 | 0 | Constant = true; |
748 | 0 | Pointer = true; |
749 | 0 | ElementBitwidth = Bitwidth = 32; |
750 | 0 | NumVectors = 0; |
751 | 0 | Signed = false; |
752 | 0 | break; |
753 | 0 | case 'U': |
754 | 0 | Constant = true; |
755 | 0 | Pointer = true; |
756 | 0 | ElementBitwidth = Bitwidth = 32; |
757 | 0 | NumVectors = 0; |
758 | 0 | Signed = true; |
759 | 0 | break; |
760 | 0 | case 'A': |
761 | 0 | Pointer = true; |
762 | 0 | ElementBitwidth = Bitwidth = 8; |
763 | 0 | NumVectors = 0; |
764 | 0 | Signed = true; |
765 | 0 | break; |
766 | 0 | case 'B': |
767 | 0 | Pointer = true; |
768 | 0 | ElementBitwidth = Bitwidth = 16; |
769 | 0 | NumVectors = 0; |
770 | 0 | Signed = true; |
771 | 0 | break; |
772 | 0 | case 'C': |
773 | 0 | Pointer = true; |
774 | 0 | ElementBitwidth = Bitwidth = 32; |
775 | 0 | NumVectors = 0; |
776 | 0 | Signed = true; |
777 | 0 | break; |
778 | 0 | case 'D': |
779 | 0 | Pointer = true; |
780 | 0 | ElementBitwidth = Bitwidth = 64; |
781 | 0 | NumVectors = 0; |
782 | 0 | Signed = true; |
783 | 0 | break; |
784 | 0 | case 'E': |
785 | 0 | Pointer = true; |
786 | 0 | ElementBitwidth = Bitwidth = 8; |
787 | 0 | NumVectors = 0; |
788 | 0 | Signed = false; |
789 | 0 | break; |
790 | 0 | case 'F': |
791 | 0 | Pointer = true; |
792 | 0 | ElementBitwidth = Bitwidth = 16; |
793 | 0 | NumVectors = 0; |
794 | 0 | Signed = false; |
795 | 0 | break; |
796 | 0 | case 'G': |
797 | 0 | Pointer = true; |
798 | 0 | ElementBitwidth = Bitwidth = 32; |
799 | 0 | NumVectors = 0; |
800 | 0 | Signed = false; |
801 | 0 | break; |
802 | 0 | default: |
803 | 0 | llvm_unreachable("Unhandled character!"); |
804 | 0 | } |
805 | 0 | } |
806 | | |
807 | | |
808 | | //===----------------------------------------------------------------------===// |
809 | | // Intrinsic implementation |
810 | | //===----------------------------------------------------------------------===// |
811 | | |
812 | | Intrinsic::Intrinsic(StringRef Name, StringRef Proto, uint64_t MergeTy, |
813 | | StringRef MergeSuffix, uint64_t MemoryElementTy, |
814 | | StringRef LLVMName, uint64_t Flags, |
815 | | ArrayRef<ImmCheck> Checks, TypeSpec BT, ClassKind Class, |
816 | | SVEEmitter &Emitter, StringRef Guard) |
817 | | : Name(Name.str()), LLVMName(LLVMName), Proto(Proto.str()), |
818 | | BaseTypeSpec(BT), Class(Class), Guard(Guard.str()), |
819 | | MergeSuffix(MergeSuffix.str()), BaseType(BT, 'd'), Flags(Flags), |
820 | 0 | ImmChecks(Checks.begin(), Checks.end()) { |
821 | | // Types[0] is the return value. |
822 | 0 | for (unsigned I = 0; I < Proto.size(); ++I) { |
823 | 0 | SVEType T(BaseTypeSpec, Proto[I]); |
824 | 0 | Types.push_back(T); |
825 | | |
826 | | // Add range checks for immediates |
827 | 0 | if (I > 0) { |
828 | 0 | if (T.isPredicatePattern()) |
829 | 0 | ImmChecks.emplace_back( |
830 | 0 | I - 1, Emitter.getEnumValueForImmCheck("ImmCheck0_31")); |
831 | 0 | else if (T.isPrefetchOp()) |
832 | 0 | ImmChecks.emplace_back( |
833 | 0 | I - 1, Emitter.getEnumValueForImmCheck("ImmCheck0_13")); |
834 | 0 | } |
835 | 0 | } |
836 | | |
837 | | // Set flags based on properties |
838 | 0 | this->Flags |= Emitter.encodeTypeFlags(BaseType); |
839 | 0 | this->Flags |= Emitter.encodeMemoryElementType(MemoryElementTy); |
840 | 0 | this->Flags |= Emitter.encodeMergeType(MergeTy); |
841 | 0 | if (hasSplat()) |
842 | 0 | this->Flags |= Emitter.encodeSplatOperand(getSplatIdx()); |
843 | 0 | } |
844 | | |
845 | 0 | std::string Intrinsic::getBuiltinTypeStr() { |
846 | 0 | std::string S = getReturnType().builtin_str(); |
847 | 0 | for (unsigned I = 0; I < getNumParams(); ++I) |
848 | 0 | S += getParamType(I).builtin_str(); |
849 | |
|
850 | 0 | return S; |
851 | 0 | } |
852 | | |
853 | | std::string Intrinsic::replaceTemplatedArgs(std::string Name, TypeSpec TS, |
854 | 0 | std::string Proto) const { |
855 | 0 | std::string Ret = Name; |
856 | 0 | while (Ret.find('{') != std::string::npos) { |
857 | 0 | size_t Pos = Ret.find('{'); |
858 | 0 | size_t End = Ret.find('}'); |
859 | 0 | unsigned NumChars = End - Pos + 1; |
860 | 0 | assert(NumChars == 3 && "Unexpected template argument"); |
861 | | |
862 | 0 | SVEType T; |
863 | 0 | char C = Ret[Pos+1]; |
864 | 0 | switch(C) { |
865 | 0 | default: |
866 | 0 | llvm_unreachable("Unknown predication specifier"); |
867 | 0 | case 'd': |
868 | 0 | T = SVEType(TS, 'd'); |
869 | 0 | break; |
870 | 0 | case '0': |
871 | 0 | case '1': |
872 | 0 | case '2': |
873 | 0 | case '3': |
874 | 0 | T = SVEType(TS, Proto[C - '0']); |
875 | 0 | break; |
876 | 0 | } |
877 | | |
878 | | // Replace templated arg with the right suffix (e.g. u32) |
879 | 0 | std::string TypeCode; |
880 | 0 | if (T.isInteger()) |
881 | 0 | TypeCode = T.isSigned() ? 's' : 'u'; |
882 | 0 | else if (T.isPredicateVector()) |
883 | 0 | TypeCode = 'b'; |
884 | 0 | else if (T.isBFloat()) |
885 | 0 | TypeCode = "bf"; |
886 | 0 | else |
887 | 0 | TypeCode = 'f'; |
888 | 0 | Ret.replace(Pos, NumChars, TypeCode + utostr(T.getElementSizeInBits())); |
889 | 0 | } |
890 | | |
891 | 0 | return Ret; |
892 | 0 | } |
893 | | |
894 | 0 | std::string Intrinsic::mangleName(ClassKind LocalCK) const { |
895 | 0 | std::string S = getName(); |
896 | |
|
897 | 0 | if (LocalCK == ClassG) { |
898 | | // Remove the square brackets and everything in between. |
899 | 0 | while (S.find('[') != std::string::npos) { |
900 | 0 | auto Start = S.find('['); |
901 | 0 | auto End = S.find(']'); |
902 | 0 | S.erase(Start, (End-Start)+1); |
903 | 0 | } |
904 | 0 | } else { |
905 | | // Remove the square brackets. |
906 | 0 | while (S.find('[') != std::string::npos) { |
907 | 0 | auto BrPos = S.find('['); |
908 | 0 | if (BrPos != std::string::npos) |
909 | 0 | S.erase(BrPos, 1); |
910 | 0 | BrPos = S.find(']'); |
911 | 0 | if (BrPos != std::string::npos) |
912 | 0 | S.erase(BrPos, 1); |
913 | 0 | } |
914 | 0 | } |
915 | | |
916 | | // Replace all {d} like expressions with e.g. 'u32' |
917 | 0 | return replaceTemplatedArgs(S, getBaseTypeSpec(), getProto()) + |
918 | 0 | getMergeSuffix(); |
919 | 0 | } |
920 | | |
921 | 0 | void Intrinsic::emitIntrinsic(raw_ostream &OS) const { |
922 | 0 | bool IsOverloaded = getClassKind() == ClassG && getProto().size() > 1; |
923 | |
|
924 | 0 | std::string FullName = mangleName(ClassS); |
925 | 0 | std::string ProtoName = mangleName(getClassKind()); |
926 | |
|
927 | 0 | OS << (IsOverloaded ? "__aio " : "__ai ") |
928 | 0 | << "__attribute__((__clang_arm_builtin_alias(" |
929 | 0 | << "__builtin_sve_" << FullName << ")))\n"; |
930 | |
|
931 | 0 | OS << getTypes()[0].str() << " " << ProtoName << "("; |
932 | 0 | for (unsigned I = 0; I < getTypes().size() - 1; ++I) { |
933 | 0 | if (I != 0) |
934 | 0 | OS << ", "; |
935 | 0 | OS << getTypes()[I + 1].str(); |
936 | 0 | } |
937 | 0 | OS << ");\n"; |
938 | 0 | } |
939 | | |
940 | | //===----------------------------------------------------------------------===// |
941 | | // SVEEmitter implementation |
942 | | //===----------------------------------------------------------------------===// |
943 | 0 | uint64_t SVEEmitter::encodeTypeFlags(const SVEType &T) { |
944 | 0 | if (T.isFloat()) { |
945 | 0 | switch (T.getElementSizeInBits()) { |
946 | 0 | case 16: |
947 | 0 | return encodeEltType("EltTyFloat16"); |
948 | 0 | case 32: |
949 | 0 | return encodeEltType("EltTyFloat32"); |
950 | 0 | case 64: |
951 | 0 | return encodeEltType("EltTyFloat64"); |
952 | 0 | default: |
953 | 0 | llvm_unreachable("Unhandled float element bitwidth!"); |
954 | 0 | } |
955 | 0 | } |
956 | | |
957 | 0 | if (T.isBFloat()) { |
958 | 0 | assert(T.getElementSizeInBits() == 16 && "Not a valid BFloat."); |
959 | 0 | return encodeEltType("EltTyBFloat16"); |
960 | 0 | } |
961 | | |
962 | 0 | if (T.isPredicateVector()) { |
963 | 0 | switch (T.getElementSizeInBits()) { |
964 | 0 | case 8: |
965 | 0 | return encodeEltType("EltTyBool8"); |
966 | 0 | case 16: |
967 | 0 | return encodeEltType("EltTyBool16"); |
968 | 0 | case 32: |
969 | 0 | return encodeEltType("EltTyBool32"); |
970 | 0 | case 64: |
971 | 0 | return encodeEltType("EltTyBool64"); |
972 | 0 | default: |
973 | 0 | llvm_unreachable("Unhandled predicate element bitwidth!"); |
974 | 0 | } |
975 | 0 | } |
976 | | |
977 | 0 | switch (T.getElementSizeInBits()) { |
978 | 0 | case 8: |
979 | 0 | return encodeEltType("EltTyInt8"); |
980 | 0 | case 16: |
981 | 0 | return encodeEltType("EltTyInt16"); |
982 | 0 | case 32: |
983 | 0 | return encodeEltType("EltTyInt32"); |
984 | 0 | case 64: |
985 | 0 | return encodeEltType("EltTyInt64"); |
986 | 0 | default: |
987 | 0 | llvm_unreachable("Unhandled integer element bitwidth!"); |
988 | 0 | } |
989 | 0 | } |
990 | | |
991 | | void SVEEmitter::createIntrinsic( |
992 | 0 | Record *R, SmallVectorImpl<std::unique_ptr<Intrinsic>> &Out) { |
993 | 0 | StringRef Name = R->getValueAsString("Name"); |
994 | 0 | StringRef Proto = R->getValueAsString("Prototype"); |
995 | 0 | StringRef Types = R->getValueAsString("Types"); |
996 | 0 | StringRef Guard = R->getValueAsString("ArchGuard"); |
997 | 0 | StringRef LLVMName = R->getValueAsString("LLVMIntrinsic"); |
998 | 0 | uint64_t Merge = R->getValueAsInt("Merge"); |
999 | 0 | StringRef MergeSuffix = R->getValueAsString("MergeSuffix"); |
1000 | 0 | uint64_t MemEltType = R->getValueAsInt("MemEltType"); |
1001 | 0 | std::vector<Record*> FlagsList = R->getValueAsListOfDefs("Flags"); |
1002 | 0 | std::vector<Record*> ImmCheckList = R->getValueAsListOfDefs("ImmChecks"); |
1003 | |
|
1004 | 0 | int64_t Flags = 0; |
1005 | 0 | for (auto FlagRec : FlagsList) |
1006 | 0 | Flags |= FlagRec->getValueAsInt("Value"); |
1007 | | |
1008 | | // Create a dummy TypeSpec for non-overloaded builtins. |
1009 | 0 | if (Types.empty()) { |
1010 | 0 | assert((Flags & getEnumValueForFlag("IsOverloadNone")) && |
1011 | 0 | "Expect TypeSpec for overloaded builtin!"); |
1012 | 0 | Types = "i"; |
1013 | 0 | } |
1014 | | |
1015 | | // Extract type specs from string |
1016 | 0 | SmallVector<TypeSpec, 8> TypeSpecs; |
1017 | 0 | TypeSpec Acc; |
1018 | 0 | for (char I : Types) { |
1019 | 0 | Acc.push_back(I); |
1020 | 0 | if (islower(I)) { |
1021 | 0 | TypeSpecs.push_back(TypeSpec(Acc)); |
1022 | 0 | Acc.clear(); |
1023 | 0 | } |
1024 | 0 | } |
1025 | | |
1026 | | // Remove duplicate type specs. |
1027 | 0 | llvm::sort(TypeSpecs); |
1028 | 0 | TypeSpecs.erase(std::unique(TypeSpecs.begin(), TypeSpecs.end()), |
1029 | 0 | TypeSpecs.end()); |
1030 | | |
1031 | | // Create an Intrinsic for each type spec. |
1032 | 0 | for (auto TS : TypeSpecs) { |
1033 | | // Collate a list of range/option checks for the immediates. |
1034 | 0 | SmallVector<ImmCheck, 2> ImmChecks; |
1035 | 0 | for (auto *R : ImmCheckList) { |
1036 | 0 | int64_t Arg = R->getValueAsInt("Arg"); |
1037 | 0 | int64_t EltSizeArg = R->getValueAsInt("EltSizeArg"); |
1038 | 0 | int64_t Kind = R->getValueAsDef("Kind")->getValueAsInt("Value"); |
1039 | 0 | assert(Arg >= 0 && Kind >= 0 && "Arg and Kind must be nonnegative"); |
1040 | | |
1041 | 0 | unsigned ElementSizeInBits = 0; |
1042 | 0 | if (EltSizeArg >= 0) |
1043 | 0 | ElementSizeInBits = |
1044 | 0 | SVEType(TS, Proto[EltSizeArg + /* offset by return arg */ 1]) |
1045 | 0 | .getElementSizeInBits(); |
1046 | 0 | ImmChecks.push_back(ImmCheck(Arg, Kind, ElementSizeInBits)); |
1047 | 0 | } |
1048 | |
|
1049 | 0 | Out.push_back(std::make_unique<Intrinsic>( |
1050 | 0 | Name, Proto, Merge, MergeSuffix, MemEltType, LLVMName, Flags, ImmChecks, |
1051 | 0 | TS, ClassS, *this, Guard)); |
1052 | | |
1053 | | // Also generate the short-form (e.g. svadd_m) for the given type-spec. |
1054 | 0 | if (Intrinsic::isOverloadedIntrinsic(Name)) |
1055 | 0 | Out.push_back(std::make_unique<Intrinsic>( |
1056 | 0 | Name, Proto, Merge, MergeSuffix, MemEltType, LLVMName, Flags, |
1057 | 0 | ImmChecks, TS, ClassG, *this, Guard)); |
1058 | 0 | } |
1059 | 0 | } |
1060 | | |
1061 | 0 | void SVEEmitter::createHeader(raw_ostream &OS) { |
1062 | 0 | OS << "/*===---- arm_sve.h - ARM SVE intrinsics " |
1063 | 0 | "-----------------------------------===\n" |
1064 | 0 | " *\n" |
1065 | 0 | " *\n" |
1066 | 0 | " * Part of the LLVM Project, under the Apache License v2.0 with LLVM " |
1067 | 0 | "Exceptions.\n" |
1068 | 0 | " * See https://llvm.org/LICENSE.txt for license information.\n" |
1069 | 0 | " * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception\n" |
1070 | 0 | " *\n" |
1071 | 0 | " *===-----------------------------------------------------------------" |
1072 | 0 | "------===\n" |
1073 | 0 | " */\n\n"; |
1074 | |
|
1075 | 0 | OS << "#ifndef __ARM_SVE_H\n"; |
1076 | 0 | OS << "#define __ARM_SVE_H\n\n"; |
1077 | |
|
1078 | 0 | OS << "#if !defined(__ARM_FEATURE_SVE)\n"; |
1079 | 0 | OS << "#error \"SVE support not enabled\"\n"; |
1080 | 0 | OS << "#else\n\n"; |
1081 | |
|
1082 | 0 | OS << "#if !defined(__LITTLE_ENDIAN__)\n"; |
1083 | 0 | OS << "#error \"Big endian is currently not supported for arm_sve.h\"\n"; |
1084 | 0 | OS << "#endif\n"; |
1085 | |
|
1086 | 0 | OS << "#include <stdint.h>\n\n"; |
1087 | 0 | OS << "#ifdef __cplusplus\n"; |
1088 | 0 | OS << "extern \"C\" {\n"; |
1089 | 0 | OS << "#else\n"; |
1090 | 0 | OS << "#include <stdbool.h>\n"; |
1091 | 0 | OS << "#endif\n\n"; |
1092 | |
|
1093 | 0 | OS << "typedef __fp16 float16_t;\n"; |
1094 | 0 | OS << "typedef float float32_t;\n"; |
1095 | 0 | OS << "typedef double float64_t;\n"; |
1096 | |
|
1097 | 0 | OS << "typedef __SVInt8_t svint8_t;\n"; |
1098 | 0 | OS << "typedef __SVInt16_t svint16_t;\n"; |
1099 | 0 | OS << "typedef __SVInt32_t svint32_t;\n"; |
1100 | 0 | OS << "typedef __SVInt64_t svint64_t;\n"; |
1101 | 0 | OS << "typedef __SVUint8_t svuint8_t;\n"; |
1102 | 0 | OS << "typedef __SVUint16_t svuint16_t;\n"; |
1103 | 0 | OS << "typedef __SVUint32_t svuint32_t;\n"; |
1104 | 0 | OS << "typedef __SVUint64_t svuint64_t;\n"; |
1105 | 0 | OS << "typedef __SVFloat16_t svfloat16_t;\n\n"; |
1106 | |
|
1107 | 0 | OS << "#if defined(__ARM_FEATURE_SVE_BF16) && " |
1108 | 0 | "!defined(__ARM_FEATURE_BF16_SCALAR_ARITHMETIC)\n"; |
1109 | 0 | OS << "#error \"__ARM_FEATURE_BF16_SCALAR_ARITHMETIC must be defined when " |
1110 | 0 | "__ARM_FEATURE_SVE_BF16 is defined\"\n"; |
1111 | 0 | OS << "#endif\n\n"; |
1112 | |
|
1113 | 0 | OS << "#if defined(__ARM_FEATURE_SVE_BF16)\n"; |
1114 | 0 | OS << "typedef __SVBFloat16_t svbfloat16_t;\n"; |
1115 | 0 | OS << "#endif\n\n"; |
1116 | |
|
1117 | 0 | OS << "#if defined(__ARM_FEATURE_BF16_SCALAR_ARITHMETIC)\n"; |
1118 | 0 | OS << "#include <arm_bf16.h>\n"; |
1119 | 0 | OS << "typedef __bf16 bfloat16_t;\n"; |
1120 | 0 | OS << "#endif\n\n"; |
1121 | |
|
1122 | 0 | OS << "typedef __SVFloat32_t svfloat32_t;\n"; |
1123 | 0 | OS << "typedef __SVFloat64_t svfloat64_t;\n"; |
1124 | 0 | OS << "typedef __clang_svint8x2_t svint8x2_t;\n"; |
1125 | 0 | OS << "typedef __clang_svint16x2_t svint16x2_t;\n"; |
1126 | 0 | OS << "typedef __clang_svint32x2_t svint32x2_t;\n"; |
1127 | 0 | OS << "typedef __clang_svint64x2_t svint64x2_t;\n"; |
1128 | 0 | OS << "typedef __clang_svuint8x2_t svuint8x2_t;\n"; |
1129 | 0 | OS << "typedef __clang_svuint16x2_t svuint16x2_t;\n"; |
1130 | 0 | OS << "typedef __clang_svuint32x2_t svuint32x2_t;\n"; |
1131 | 0 | OS << "typedef __clang_svuint64x2_t svuint64x2_t;\n"; |
1132 | 0 | OS << "typedef __clang_svfloat16x2_t svfloat16x2_t;\n"; |
1133 | 0 | OS << "typedef __clang_svfloat32x2_t svfloat32x2_t;\n"; |
1134 | 0 | OS << "typedef __clang_svfloat64x2_t svfloat64x2_t;\n"; |
1135 | 0 | OS << "typedef __clang_svint8x3_t svint8x3_t;\n"; |
1136 | 0 | OS << "typedef __clang_svint16x3_t svint16x3_t;\n"; |
1137 | 0 | OS << "typedef __clang_svint32x3_t svint32x3_t;\n"; |
1138 | 0 | OS << "typedef __clang_svint64x3_t svint64x3_t;\n"; |
1139 | 0 | OS << "typedef __clang_svuint8x3_t svuint8x3_t;\n"; |
1140 | 0 | OS << "typedef __clang_svuint16x3_t svuint16x3_t;\n"; |
1141 | 0 | OS << "typedef __clang_svuint32x3_t svuint32x3_t;\n"; |
1142 | 0 | OS << "typedef __clang_svuint64x3_t svuint64x3_t;\n"; |
1143 | 0 | OS << "typedef __clang_svfloat16x3_t svfloat16x3_t;\n"; |
1144 | 0 | OS << "typedef __clang_svfloat32x3_t svfloat32x3_t;\n"; |
1145 | 0 | OS << "typedef __clang_svfloat64x3_t svfloat64x3_t;\n"; |
1146 | 0 | OS << "typedef __clang_svint8x4_t svint8x4_t;\n"; |
1147 | 0 | OS << "typedef __clang_svint16x4_t svint16x4_t;\n"; |
1148 | 0 | OS << "typedef __clang_svint32x4_t svint32x4_t;\n"; |
1149 | 0 | OS << "typedef __clang_svint64x4_t svint64x4_t;\n"; |
1150 | 0 | OS << "typedef __clang_svuint8x4_t svuint8x4_t;\n"; |
1151 | 0 | OS << "typedef __clang_svuint16x4_t svuint16x4_t;\n"; |
1152 | 0 | OS << "typedef __clang_svuint32x4_t svuint32x4_t;\n"; |
1153 | 0 | OS << "typedef __clang_svuint64x4_t svuint64x4_t;\n"; |
1154 | 0 | OS << "typedef __clang_svfloat16x4_t svfloat16x4_t;\n"; |
1155 | 0 | OS << "typedef __clang_svfloat32x4_t svfloat32x4_t;\n"; |
1156 | 0 | OS << "typedef __clang_svfloat64x4_t svfloat64x4_t;\n"; |
1157 | 0 | OS << "typedef __SVBool_t svbool_t;\n\n"; |
1158 | |
|
1159 | 0 | OS << "#ifdef __ARM_FEATURE_SVE_BF16\n"; |
1160 | 0 | OS << "typedef __clang_svbfloat16x2_t svbfloat16x2_t;\n"; |
1161 | 0 | OS << "typedef __clang_svbfloat16x3_t svbfloat16x3_t;\n"; |
1162 | 0 | OS << "typedef __clang_svbfloat16x4_t svbfloat16x4_t;\n"; |
1163 | 0 | OS << "#endif\n"; |
1164 | |
|
1165 | 0 | OS << "enum svpattern\n"; |
1166 | 0 | OS << "{\n"; |
1167 | 0 | OS << " SV_POW2 = 0,\n"; |
1168 | 0 | OS << " SV_VL1 = 1,\n"; |
1169 | 0 | OS << " SV_VL2 = 2,\n"; |
1170 | 0 | OS << " SV_VL3 = 3,\n"; |
1171 | 0 | OS << " SV_VL4 = 4,\n"; |
1172 | 0 | OS << " SV_VL5 = 5,\n"; |
1173 | 0 | OS << " SV_VL6 = 6,\n"; |
1174 | 0 | OS << " SV_VL7 = 7,\n"; |
1175 | 0 | OS << " SV_VL8 = 8,\n"; |
1176 | 0 | OS << " SV_VL16 = 9,\n"; |
1177 | 0 | OS << " SV_VL32 = 10,\n"; |
1178 | 0 | OS << " SV_VL64 = 11,\n"; |
1179 | 0 | OS << " SV_VL128 = 12,\n"; |
1180 | 0 | OS << " SV_VL256 = 13,\n"; |
1181 | 0 | OS << " SV_MUL4 = 29,\n"; |
1182 | 0 | OS << " SV_MUL3 = 30,\n"; |
1183 | 0 | OS << " SV_ALL = 31\n"; |
1184 | 0 | OS << "};\n\n"; |
1185 | |
|
1186 | 0 | OS << "enum svprfop\n"; |
1187 | 0 | OS << "{\n"; |
1188 | 0 | OS << " SV_PLDL1KEEP = 0,\n"; |
1189 | 0 | OS << " SV_PLDL1STRM = 1,\n"; |
1190 | 0 | OS << " SV_PLDL2KEEP = 2,\n"; |
1191 | 0 | OS << " SV_PLDL2STRM = 3,\n"; |
1192 | 0 | OS << " SV_PLDL3KEEP = 4,\n"; |
1193 | 0 | OS << " SV_PLDL3STRM = 5,\n"; |
1194 | 0 | OS << " SV_PSTL1KEEP = 8,\n"; |
1195 | 0 | OS << " SV_PSTL1STRM = 9,\n"; |
1196 | 0 | OS << " SV_PSTL2KEEP = 10,\n"; |
1197 | 0 | OS << " SV_PSTL2STRM = 11,\n"; |
1198 | 0 | OS << " SV_PSTL3KEEP = 12,\n"; |
1199 | 0 | OS << " SV_PSTL3STRM = 13\n"; |
1200 | 0 | OS << "};\n\n"; |
1201 | |
|
1202 | 0 | OS << "/* Function attributes */\n"; |
1203 | 0 | OS << "#define __ai static __inline__ __attribute__((__always_inline__, " |
1204 | 0 | "__nodebug__))\n\n"; |
1205 | 0 | OS << "#define __aio static __inline__ __attribute__((__always_inline__, " |
1206 | 0 | "__nodebug__, __overloadable__))\n\n"; |
1207 | | |
1208 | | // Add reinterpret functions. |
1209 | 0 | for (auto ShortForm : { false, true } ) |
1210 | 0 | for (const ReinterpretTypeInfo &From : Reinterprets) |
1211 | 0 | for (const ReinterpretTypeInfo &To : Reinterprets) { |
1212 | 0 | const bool IsBFloat = StringRef(From.Suffix).equals("bf16") || |
1213 | 0 | StringRef(To.Suffix).equals("bf16"); |
1214 | 0 | if (IsBFloat) |
1215 | 0 | OS << "#if defined(__ARM_FEATURE_SVE_BF16)\n"; |
1216 | 0 | if (ShortForm) { |
1217 | 0 | OS << "__aio " << From.Type << " svreinterpret_" << From.Suffix; |
1218 | 0 | OS << "(" << To.Type << " op) {\n"; |
1219 | 0 | OS << " return __builtin_sve_reinterpret_" << From.Suffix << "_" |
1220 | 0 | << To.Suffix << "(op);\n"; |
1221 | 0 | OS << "}\n\n"; |
1222 | 0 | } else |
1223 | 0 | OS << "#define svreinterpret_" << From.Suffix << "_" << To.Suffix |
1224 | 0 | << "(...) __builtin_sve_reinterpret_" << From.Suffix << "_" |
1225 | 0 | << To.Suffix << "(__VA_ARGS__)\n"; |
1226 | 0 | if (IsBFloat) |
1227 | 0 | OS << "#endif /* #if defined(__ARM_FEATURE_SVE_BF16) */\n"; |
1228 | 0 | } |
1229 | |
|
1230 | 0 | SmallVector<std::unique_ptr<Intrinsic>, 128> Defs; |
1231 | 0 | std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst"); |
1232 | 0 | for (auto *R : RV) |
1233 | 0 | createIntrinsic(R, Defs); |
1234 | | |
1235 | | // Sort intrinsics in header file by following order/priority: |
1236 | | // - Architectural guard (i.e. does it require SVE2 or SVE2_AES) |
1237 | | // - Class (is intrinsic overloaded or not) |
1238 | | // - Intrinsic name |
1239 | 0 | std::stable_sort( |
1240 | 0 | Defs.begin(), Defs.end(), [](const std::unique_ptr<Intrinsic> &A, |
1241 | 0 | const std::unique_ptr<Intrinsic> &B) { |
1242 | 0 | auto ToTuple = [](const std::unique_ptr<Intrinsic> &I) { |
1243 | 0 | return std::make_tuple(I->getGuard(), (unsigned)I->getClassKind(), I->getName()); |
1244 | 0 | }; |
1245 | 0 | return ToTuple(A) < ToTuple(B); |
1246 | 0 | }); |
1247 | |
|
1248 | 0 | StringRef InGuard = ""; |
1249 | 0 | for (auto &I : Defs) { |
1250 | | // Emit #endif/#if pair if needed. |
1251 | 0 | if (I->getGuard() != InGuard) { |
1252 | 0 | if (!InGuard.empty()) |
1253 | 0 | OS << "#endif //" << InGuard << "\n"; |
1254 | 0 | InGuard = I->getGuard(); |
1255 | 0 | if (!InGuard.empty()) |
1256 | 0 | OS << "\n#if " << InGuard << "\n"; |
1257 | 0 | } |
1258 | | |
1259 | | // Actually emit the intrinsic declaration. |
1260 | 0 | I->emitIntrinsic(OS); |
1261 | 0 | } |
1262 | |
|
1263 | 0 | if (!InGuard.empty()) |
1264 | 0 | OS << "#endif //" << InGuard << "\n"; |
1265 | |
|
1266 | 0 | OS << "#if defined(__ARM_FEATURE_SVE_BF16)\n"; |
1267 | 0 | OS << "#define svcvtnt_bf16_x svcvtnt_bf16_m\n"; |
1268 | 0 | OS << "#define svcvtnt_bf16_f32_x svcvtnt_bf16_f32_m\n"; |
1269 | 0 | OS << "#endif /*__ARM_FEATURE_SVE_BF16 */\n\n"; |
1270 | |
|
1271 | 0 | OS << "#if defined(__ARM_FEATURE_SVE2)\n"; |
1272 | 0 | OS << "#define svcvtnt_f16_x svcvtnt_f16_m\n"; |
1273 | 0 | OS << "#define svcvtnt_f16_f32_x svcvtnt_f16_f32_m\n"; |
1274 | 0 | OS << "#define svcvtnt_f32_x svcvtnt_f32_m\n"; |
1275 | 0 | OS << "#define svcvtnt_f32_f64_x svcvtnt_f32_f64_m\n\n"; |
1276 | |
|
1277 | 0 | OS << "#define svcvtxnt_f32_x svcvtxnt_f32_m\n"; |
1278 | 0 | OS << "#define svcvtxnt_f32_f64_x svcvtxnt_f32_f64_m\n\n"; |
1279 | |
|
1280 | 0 | OS << "#endif /*__ARM_FEATURE_SVE2 */\n\n"; |
1281 | |
|
1282 | 0 | OS << "#ifdef __cplusplus\n"; |
1283 | 0 | OS << "} // extern \"C\"\n"; |
1284 | 0 | OS << "#endif\n\n"; |
1285 | 0 | OS << "#endif /*__ARM_FEATURE_SVE */\n\n"; |
1286 | 0 | OS << "#endif /* __ARM_SVE_H */\n"; |
1287 | 0 | } |
1288 | | |
1289 | 0 | void SVEEmitter::createBuiltins(raw_ostream &OS) { |
1290 | 0 | std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst"); |
1291 | 0 | SmallVector<std::unique_ptr<Intrinsic>, 128> Defs; |
1292 | 0 | for (auto *R : RV) |
1293 | 0 | createIntrinsic(R, Defs); |
1294 | | |
1295 | | // The mappings must be sorted based on BuiltinID. |
1296 | 0 | llvm::sort(Defs, [](const std::unique_ptr<Intrinsic> &A, |
1297 | 0 | const std::unique_ptr<Intrinsic> &B) { |
1298 | 0 | return A->getMangledName() < B->getMangledName(); |
1299 | 0 | }); |
1300 | |
|
1301 | 0 | OS << "#ifdef GET_SVE_BUILTINS\n"; |
1302 | 0 | for (auto &Def : Defs) { |
1303 | | // Only create BUILTINs for non-overloaded intrinsics, as overloaded |
1304 | | // declarations only live in the header file. |
1305 | 0 | if (Def->getClassKind() != ClassG) |
1306 | 0 | OS << "BUILTIN(__builtin_sve_" << Def->getMangledName() << ", \"" |
1307 | 0 | << Def->getBuiltinTypeStr() << "\", \"n\")\n"; |
1308 | 0 | } |
1309 | | |
1310 | | // Add reinterpret builtins |
1311 | 0 | for (const ReinterpretTypeInfo &From : Reinterprets) |
1312 | 0 | for (const ReinterpretTypeInfo &To : Reinterprets) |
1313 | 0 | OS << "BUILTIN(__builtin_sve_reinterpret_" << From.Suffix << "_" |
1314 | 0 | << To.Suffix << +", \"" << From.BuiltinType << To.BuiltinType |
1315 | 0 | << "\", \"n\")\n"; |
1316 | |
|
1317 | 0 | OS << "#endif\n\n"; |
1318 | 0 | } |
1319 | | |
1320 | 0 | void SVEEmitter::createCodeGenMap(raw_ostream &OS) { |
1321 | 0 | std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst"); |
1322 | 0 | SmallVector<std::unique_ptr<Intrinsic>, 128> Defs; |
1323 | 0 | for (auto *R : RV) |
1324 | 0 | createIntrinsic(R, Defs); |
1325 | | |
1326 | | // The mappings must be sorted based on BuiltinID. |
1327 | 0 | llvm::sort(Defs, [](const std::unique_ptr<Intrinsic> &A, |
1328 | 0 | const std::unique_ptr<Intrinsic> &B) { |
1329 | 0 | return A->getMangledName() < B->getMangledName(); |
1330 | 0 | }); |
1331 | |
|
1332 | 0 | OS << "#ifdef GET_SVE_LLVM_INTRINSIC_MAP\n"; |
1333 | 0 | for (auto &Def : Defs) { |
1334 | | // Builtins only exist for non-overloaded intrinsics, overloaded |
1335 | | // declarations only live in the header file. |
1336 | 0 | if (Def->getClassKind() == ClassG) |
1337 | 0 | continue; |
1338 | | |
1339 | 0 | uint64_t Flags = Def->getFlags(); |
1340 | 0 | auto FlagString = std::to_string(Flags); |
1341 | |
|
1342 | 0 | std::string LLVMName = Def->getLLVMName(); |
1343 | 0 | std::string Builtin = Def->getMangledName(); |
1344 | 0 | if (!LLVMName.empty()) |
1345 | 0 | OS << "SVEMAP1(" << Builtin << ", " << LLVMName << ", " << FlagString |
1346 | 0 | << "),\n"; |
1347 | 0 | else |
1348 | 0 | OS << "SVEMAP2(" << Builtin << ", " << FlagString << "),\n"; |
1349 | 0 | } |
1350 | 0 | OS << "#endif\n\n"; |
1351 | 0 | } |
1352 | | |
1353 | 0 | void SVEEmitter::createRangeChecks(raw_ostream &OS) { |
1354 | 0 | std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst"); |
1355 | 0 | SmallVector<std::unique_ptr<Intrinsic>, 128> Defs; |
1356 | 0 | for (auto *R : RV) |
1357 | 0 | createIntrinsic(R, Defs); |
1358 | | |
1359 | | // The mappings must be sorted based on BuiltinID. |
1360 | 0 | llvm::sort(Defs, [](const std::unique_ptr<Intrinsic> &A, |
1361 | 0 | const std::unique_ptr<Intrinsic> &B) { |
1362 | 0 | return A->getMangledName() < B->getMangledName(); |
1363 | 0 | }); |
1364 | | |
1365 | |
|
1366 | 0 | OS << "#ifdef GET_SVE_IMMEDIATE_CHECK\n"; |
1367 | | |
1368 | | // Ensure these are only emitted once. |
1369 | 0 | std::set<std::string> Emitted; |
1370 | |
|
1371 | 0 | for (auto &Def : Defs) { |
1372 | 0 | if (Emitted.find(Def->getMangledName()) != Emitted.end() || |
1373 | 0 | Def->getImmChecks().empty()) |
1374 | 0 | continue; |
1375 | | |
1376 | 0 | OS << "case SVE::BI__builtin_sve_" << Def->getMangledName() << ":\n"; |
1377 | 0 | for (auto &Check : Def->getImmChecks()) |
1378 | 0 | OS << "ImmChecks.push_back(std::make_tuple(" << Check.getArg() << ", " |
1379 | 0 | << Check.getKind() << ", " << Check.getElementSizeInBits() << "));\n"; |
1380 | 0 | OS << " break;\n"; |
1381 | |
|
1382 | 0 | Emitted.insert(Def->getMangledName()); |
1383 | 0 | } |
1384 | |
|
1385 | 0 | OS << "#endif\n\n"; |
1386 | 0 | } |
1387 | | |
1388 | | /// Create the SVETypeFlags used in CGBuiltins |
1389 | 0 | void SVEEmitter::createTypeFlags(raw_ostream &OS) { |
1390 | 0 | OS << "#ifdef LLVM_GET_SVE_TYPEFLAGS\n"; |
1391 | 0 | for (auto &KV : FlagTypes) |
1392 | 0 | OS << "const uint64_t " << KV.getKey() << " = " << KV.getValue() << ";\n"; |
1393 | 0 | OS << "#endif\n\n"; |
1394 | |
|
1395 | 0 | OS << "#ifdef LLVM_GET_SVE_ELTTYPES\n"; |
1396 | 0 | for (auto &KV : EltTypes) |
1397 | 0 | OS << " " << KV.getKey() << " = " << KV.getValue() << ",\n"; |
1398 | 0 | OS << "#endif\n\n"; |
1399 | |
|
1400 | 0 | OS << "#ifdef LLVM_GET_SVE_MEMELTTYPES\n"; |
1401 | 0 | for (auto &KV : MemEltTypes) |
1402 | 0 | OS << " " << KV.getKey() << " = " << KV.getValue() << ",\n"; |
1403 | 0 | OS << "#endif\n\n"; |
1404 | |
|
1405 | 0 | OS << "#ifdef LLVM_GET_SVE_MERGETYPES\n"; |
1406 | 0 | for (auto &KV : MergeTypes) |
1407 | 0 | OS << " " << KV.getKey() << " = " << KV.getValue() << ",\n"; |
1408 | 0 | OS << "#endif\n\n"; |
1409 | |
|
1410 | 0 | OS << "#ifdef LLVM_GET_SVE_IMMCHECKTYPES\n"; |
1411 | 0 | for (auto &KV : ImmCheckTypes) |
1412 | 0 | OS << " " << KV.getKey() << " = " << KV.getValue() << ",\n"; |
1413 | 0 | OS << "#endif\n\n"; |
1414 | 0 | } |
1415 | | |
1416 | | namespace clang { |
1417 | 0 | void EmitSveHeader(RecordKeeper &Records, raw_ostream &OS) { |
1418 | 0 | SVEEmitter(Records).createHeader(OS); |
1419 | 0 | } |
1420 | | |
1421 | 0 | void EmitSveBuiltins(RecordKeeper &Records, raw_ostream &OS) { |
1422 | 0 | SVEEmitter(Records).createBuiltins(OS); |
1423 | 0 | } |
1424 | | |
1425 | 0 | void EmitSveBuiltinCG(RecordKeeper &Records, raw_ostream &OS) { |
1426 | 0 | SVEEmitter(Records).createCodeGenMap(OS); |
1427 | 0 | } |
1428 | | |
1429 | 0 | void EmitSveRangeChecks(RecordKeeper &Records, raw_ostream &OS) { |
1430 | 0 | SVEEmitter(Records).createRangeChecks(OS); |
1431 | 0 | } |
1432 | | |
1433 | 0 | void EmitSveTypeFlags(RecordKeeper &Records, raw_ostream &OS) { |
1434 | 0 | SVEEmitter(Records).createTypeFlags(OS); |
1435 | 0 | } |
1436 | | |
1437 | | } // End namespace clang |