blob: 12730d7283858f525e56ef10dfc97e6a5e6de6f9 [file] [log] [blame]
Sander de Smalen5087ace2020-03-15 14:29:45 +00001//===- SveEmitter.cpp - Generate arm_sve.h for use with clang -*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This tablegen backend is responsible for emitting arm_sve.h, which includes
10// a declaration and definition of each function specified by the ARM C/C++
11// Language Extensions (ACLE).
12//
13// For details, visit:
14// https://developer.arm.com/architectures/system-architectures/software-standards/acle
15//
16// Each SVE instruction is implemented in terms of 1 or more functions which
17// are suffixed with the element type of the input vectors. Functions may be
18// implemented in terms of generic vector operations such as +, *, -, etc. or
19// by calling a __builtin_-prefixed function which will be handled by clang's
20// CodeGen library.
21//
22// See also the documentation in include/clang/Basic/arm_sve.td.
23//
24//===----------------------------------------------------------------------===//
25
26#include "llvm/ADT/STLExtras.h"
Sander de Smalenc5b81462020-03-18 11:07:20 +000027#include "llvm/ADT/StringMap.h"
Sander de Smalen5087ace2020-03-15 14:29:45 +000028#include "llvm/ADT/ArrayRef.h"
29#include "llvm/ADT/StringExtras.h"
30#include "llvm/TableGen/Record.h"
31#include "llvm/TableGen/Error.h"
32#include <string>
33#include <sstream>
34#include <set>
35#include <cctype>
Eric Fiselieraf2968e2020-04-16 18:35:31 -040036#include <tuple>
Sander de Smalen5087ace2020-03-15 14:29:45 +000037
38using namespace llvm;
39
Sander de Smalenc5b81462020-03-18 11:07:20 +000040enum ClassKind {
41 ClassNone,
42 ClassS, // signed/unsigned, e.g., "_s8", "_u8" suffix
43 ClassG, // Overloaded name without type suffix
44};
45
46using TypeSpec = std::string;
Sander de Smalen5087ace2020-03-15 14:29:45 +000047
48namespace {
49
Sander de Smalenc8a5b302020-04-14 15:56:36 +010050class ImmCheck {
51 unsigned Arg;
52 unsigned Kind;
53 unsigned ElementSizeInBits;
54
55public:
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;
60
61 unsigned getArg() const { return Arg; }
62 unsigned getKind() const { return Kind; }
63 unsigned getElementSizeInBits() const { return ElementSizeInBits; }
64};
65
Sander de Smalenc5b81462020-03-18 11:07:20 +000066class SVEType {
67 TypeSpec TS;
68 bool Float, Signed, Immediate, Void, Constant, Pointer;
69 bool DefaultType, IsScalable, Predicate, PredicatePattern, PrefetchOp;
70 unsigned Bitwidth, ElementBitwidth, NumVectors;
71
Sander de Smalen8b409ea2020-03-16 10:14:05 +000072public:
Sander de Smalenc5b81462020-03-18 11:07:20 +000073 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), DefaultType(false), IsScalable(true),
78 Predicate(false), PredicatePattern(false), PrefetchOp(false),
79 Bitwidth(128), ElementBitwidth(~0U), NumVectors(1) {
80 if (!TS.empty())
81 applyTypespec();
82 applyModifier(CharMod);
83 }
84
Sander de Smalenc5b81462020-03-18 11:07:20 +000085 bool isPointer() const { return Pointer; }
86 bool isVoidPointer() const { return Pointer && Void; }
87 bool isSigned() const { return Signed; }
88 bool isImmediate() const { return Immediate; }
89 bool isScalar() const { return NumVectors == 0; }
90 bool isVector() const { return NumVectors > 0; }
91 bool isScalableVector() const { return isVector() && IsScalable; }
92 bool isChar() const { return ElementBitwidth == 8; }
93 bool isVoid() const { return Void & !Pointer; }
94 bool isDefault() const { return DefaultType; }
95 bool isFloat() const { return Float; }
96 bool isInteger() const { return !Float && !Predicate; }
97 bool isScalarPredicate() const { return !Float && ElementBitwidth == 1; }
98 bool isPredicateVector() const { return Predicate; }
99 bool isPredicatePattern() const { return PredicatePattern; }
100 bool isPrefetchOp() const { return PrefetchOp; }
101 bool isConstant() const { return Constant; }
102 unsigned getElementSizeInBits() const { return ElementBitwidth; }
103 unsigned getNumVectors() const { return NumVectors; }
104
105 unsigned getNumElements() const {
106 assert(ElementBitwidth != ~0U);
107 return Bitwidth / ElementBitwidth;
108 }
109 unsigned getSizeInBits() const {
110 return Bitwidth;
111 }
112
113 /// Return the string representation of a type, which is an encoded
114 /// string for passing to the BUILTIN() macro in Builtins.def.
115 std::string builtin_str() const;
116
Sander de Smalen981f0802020-03-18 15:05:08 +0000117 /// Return the C/C++ string representation of a type for use in the
118 /// arm_sve.h header file.
119 std::string str() const;
120
Sander de Smalenc5b81462020-03-18 11:07:20 +0000121private:
122 /// Creates the type based on the typespec string in TS.
123 void applyTypespec();
124
125 /// Applies a prototype modifier to the type.
126 void applyModifier(char Mod);
127};
128
129
130class SVEEmitter;
131
132/// The main grunt class. This represents an instantiation of an intrinsic with
133/// a particular typespec and prototype.
134class Intrinsic {
135 /// The unmangled name.
136 std::string Name;
137
138 /// The name of the corresponding LLVM IR intrinsic.
139 std::string LLVMName;
140
141 /// Intrinsic prototype.
142 std::string Proto;
143
144 /// The base type spec for this intrinsic.
145 TypeSpec BaseTypeSpec;
146
147 /// The base class kind. Most intrinsics use ClassS, which has full type
148 /// info for integers (_s32/_u32), or ClassG which is used for overloaded
149 /// intrinsics.
150 ClassKind Class;
151
152 /// The architectural #ifdef guard.
153 std::string Guard;
154
Sander de Smalenf6ea0262020-04-14 15:31:20 +0100155 // The merge suffix such as _m, _x or _z.
156 std::string MergeSuffix;
157
Sander de Smalenc5b81462020-03-18 11:07:20 +0000158 /// The types of return value [0] and parameters [1..].
159 std::vector<SVEType> Types;
160
161 /// The "base type", which is VarType('d', BaseTypeSpec).
162 SVEType BaseType;
163
Sander de Smalenf6ea0262020-04-14 15:31:20 +0100164 uint64_t Flags;
Sander de Smalenc5b81462020-03-18 11:07:20 +0000165
Sander de Smalenc8a5b302020-04-14 15:56:36 +0100166 SmallVector<ImmCheck, 2> ImmChecks;
167
Sander de Smalenc5b81462020-03-18 11:07:20 +0000168public:
Sander de Smalenf6ea0262020-04-14 15:31:20 +0100169 Intrinsic(StringRef Name, StringRef Proto, uint64_t MergeTy,
170 StringRef MergeSuffix, uint64_t MemoryElementTy, StringRef LLVMName,
Sander de Smalenc8a5b302020-04-14 15:56:36 +0100171 uint64_t Flags, ArrayRef<ImmCheck> ImmChecks, TypeSpec BT,
172 ClassKind Class, SVEEmitter &Emitter, StringRef Guard);
Sander de Smalenc5b81462020-03-18 11:07:20 +0000173
174 ~Intrinsic()=default;
175
176 std::string getName() const { return Name; }
177 std::string getLLVMName() const { return LLVMName; }
178 std::string getProto() const { return Proto; }
179 TypeSpec getBaseTypeSpec() const { return BaseTypeSpec; }
180 SVEType getBaseType() const { return BaseType; }
181
182 StringRef getGuard() const { return Guard; }
183 ClassKind getClassKind() const { return Class; }
Sander de Smalenc5b81462020-03-18 11:07:20 +0000184
185 SVEType getReturnType() const { return Types[0]; }
186 ArrayRef<SVEType> getTypes() const { return Types; }
187 SVEType getParamType(unsigned I) const { return Types[I + 1]; }
188 unsigned getNumParams() const { return Proto.size() - 1; }
189
Sander de Smalenf6ea0262020-04-14 15:31:20 +0100190 uint64_t getFlags() const { return Flags; }
Sander de Smalenc5b81462020-03-18 11:07:20 +0000191 bool isFlagSet(uint64_t Flag) const { return Flags & Flag;}
192
Sander de Smalenc8a5b302020-04-14 15:56:36 +0100193 ArrayRef<ImmCheck> getImmChecks() const { return ImmChecks; }
194
Sander de Smalenc5b81462020-03-18 11:07:20 +0000195 /// Return the type string for a BUILTIN() macro in Builtins.def.
196 std::string getBuiltinTypeStr();
197
198 /// Return the name, mangled with type information. The name is mangled for
199 /// ClassS, so will add type suffixes such as _u32/_s32.
200 std::string getMangledName() const { return mangleName(ClassS); }
201
202 /// Returns true if the intrinsic is overloaded, in that it should also generate
203 /// a short form without the type-specifiers, e.g. 'svld1(..)' instead of
204 /// 'svld1_u32(..)'.
205 static bool isOverloadedIntrinsic(StringRef Name) {
206 auto BrOpen = Name.find("[");
207 auto BrClose = Name.find(']');
208 return BrOpen != std::string::npos && BrClose != std::string::npos;
209 }
210
Sander de Smalen41d52662020-04-22 13:58:35 +0100211 /// Return true if the intrinsic takes a splat operand.
212 bool hasSplat() const {
213 // These prototype modifiers are described in arm_sve.td.
214 return Proto.find_first_of("ajfrKLR") != std::string::npos;
215 }
216
217 /// Return the parameter index of the splat operand.
218 unsigned getSplatIdx() const {
219 // These prototype modifiers are described in arm_sve.td.
220 auto Idx = Proto.find_first_of("ajfrKLR");
221 assert(Idx != std::string::npos && Idx > 0 &&
222 "Prototype has no splat operand");
223 return Idx - 1;
224 }
225
Sander de Smalenc5b81462020-03-18 11:07:20 +0000226 /// Emits the intrinsic declaration to the ostream.
227 void emitIntrinsic(raw_ostream &OS) const;
228
229private:
Sander de Smalenf6ea0262020-04-14 15:31:20 +0100230 std::string getMergeSuffix() const { return MergeSuffix; }
Sander de Smalenc5b81462020-03-18 11:07:20 +0000231 std::string mangleName(ClassKind LocalCK) const;
232 std::string replaceTemplatedArgs(std::string Name, TypeSpec TS,
233 std::string Proto) const;
234};
235
236class SVEEmitter {
237private:
238 RecordKeeper &Records;
239 llvm::StringMap<uint64_t> EltTypes;
240 llvm::StringMap<uint64_t> MemEltTypes;
241 llvm::StringMap<uint64_t> FlagTypes;
Sander de Smalenf6ea0262020-04-14 15:31:20 +0100242 llvm::StringMap<uint64_t> MergeTypes;
Sander de Smalenc8a5b302020-04-14 15:56:36 +0100243 llvm::StringMap<uint64_t> ImmCheckTypes;
Sander de Smalenc5b81462020-03-18 11:07:20 +0000244
Sander de Smalenc5b81462020-03-18 11:07:20 +0000245public:
246 SVEEmitter(RecordKeeper &R) : Records(R) {
247 for (auto *RV : Records.getAllDerivedDefinitions("EltType"))
248 EltTypes[RV->getNameInitAsString()] = RV->getValueAsInt("Value");
249 for (auto *RV : Records.getAllDerivedDefinitions("MemEltType"))
250 MemEltTypes[RV->getNameInitAsString()] = RV->getValueAsInt("Value");
251 for (auto *RV : Records.getAllDerivedDefinitions("FlagType"))
252 FlagTypes[RV->getNameInitAsString()] = RV->getValueAsInt("Value");
Sander de Smalenf6ea0262020-04-14 15:31:20 +0100253 for (auto *RV : Records.getAllDerivedDefinitions("MergeType"))
254 MergeTypes[RV->getNameInitAsString()] = RV->getValueAsInt("Value");
Sander de Smalenc8a5b302020-04-14 15:56:36 +0100255 for (auto *RV : Records.getAllDerivedDefinitions("ImmCheckType"))
256 ImmCheckTypes[RV->getNameInitAsString()] = RV->getValueAsInt("Value");
257 }
258
259 /// Returns the enum value for the immcheck type
260 unsigned getEnumValueForImmCheck(StringRef C) const {
261 auto It = ImmCheckTypes.find(C);
262 if (It != ImmCheckTypes.end())
263 return It->getValue();
264 llvm_unreachable("Unsupported imm check");
Sander de Smalenc5b81462020-03-18 11:07:20 +0000265 }
266
Sander de Smalen662cbaf2020-04-22 15:00:01 +0100267 /// Returns the enum value for the flag type
268 uint64_t getEnumValueForFlag(StringRef C) const {
269 auto Res = FlagTypes.find(C);
270 if (Res != FlagTypes.end())
271 return Res->getValue();
272 llvm_unreachable("Unsupported flag");
273 }
274
Sander de Smalenf6ea0262020-04-14 15:31:20 +0100275 // Returns the SVETypeFlags for a given value and mask.
276 uint64_t encodeFlag(uint64_t V, StringRef MaskName) const {
277 auto It = FlagTypes.find(MaskName);
278 if (It != FlagTypes.end()) {
279 uint64_t Mask = It->getValue();
280 unsigned Shift = llvm::countTrailingZeros(Mask);
281 return (V << Shift) & Mask;
282 }
283 llvm_unreachable("Unsupported flag");
284 }
285
286 // Returns the SVETypeFlags for the given element type.
287 uint64_t encodeEltType(StringRef EltName) {
288 auto It = EltTypes.find(EltName);
289 if (It != EltTypes.end())
290 return encodeFlag(It->getValue(), "EltTypeMask");
291 llvm_unreachable("Unsupported EltType");
292 }
293
294 // Returns the SVETypeFlags for the given memory element type.
295 uint64_t encodeMemoryElementType(uint64_t MT) {
296 return encodeFlag(MT, "MemEltTypeMask");
297 }
298
299 // Returns the SVETypeFlags for the given merge type.
300 uint64_t encodeMergeType(uint64_t MT) {
301 return encodeFlag(MT, "MergeTypeMask");
302 }
303
Sander de Smalen41d52662020-04-22 13:58:35 +0100304 // Returns the SVETypeFlags for the given splat operand.
305 unsigned encodeSplatOperand(unsigned SplatIdx) {
306 assert(SplatIdx < 7 && "SplatIdx out of encodable range");
307 return encodeFlag(SplatIdx + 1, "SplatOperandMask");
308 }
309
Sander de Smalenf6ea0262020-04-14 15:31:20 +0100310 // Returns the SVETypeFlags value for the given SVEType.
311 uint64_t encodeTypeFlags(const SVEType &T);
312
Sander de Smalenc5b81462020-03-18 11:07:20 +0000313 /// Emit arm_sve.h.
314 void createHeader(raw_ostream &o);
315
316 /// Emit all the __builtin prototypes and code needed by Sema.
317 void createBuiltins(raw_ostream &o);
318
319 /// Emit all the information needed to map builtin -> LLVM IR intrinsic.
320 void createCodeGenMap(raw_ostream &o);
321
Sander de Smalenc8a5b302020-04-14 15:56:36 +0100322 /// Emit all the range checks for the immediates.
323 void createRangeChecks(raw_ostream &o);
324
Sander de Smalenc5b81462020-03-18 11:07:20 +0000325 /// Create the SVETypeFlags used in CGBuiltins
326 void createTypeFlags(raw_ostream &o);
327
328 /// Create intrinsic and add it to \p Out
329 void createIntrinsic(Record *R, SmallVectorImpl<std::unique_ptr<Intrinsic>> &Out);
Sander de Smalen5087ace2020-03-15 14:29:45 +0000330};
331
332} // end anonymous namespace
333
334
335//===----------------------------------------------------------------------===//
Sander de Smalenc5b81462020-03-18 11:07:20 +0000336// Type implementation
Sander de Smalen8b409ea2020-03-16 10:14:05 +0000337//===----------------------------------------------------------------------===//
Sander de Smalen8b409ea2020-03-16 10:14:05 +0000338
Sander de Smalenc5b81462020-03-18 11:07:20 +0000339std::string SVEType::builtin_str() const {
340 std::string S;
341 if (isVoid())
342 return "v";
343
344 if (isVoidPointer())
345 S += "v";
346 else if (!Float)
347 switch (ElementBitwidth) {
348 case 1: S += "b"; break;
349 case 8: S += "c"; break;
350 case 16: S += "s"; break;
351 case 32: S += "i"; break;
352 case 64: S += "Wi"; break;
353 case 128: S += "LLLi"; break;
354 default: llvm_unreachable("Unhandled case!");
355 }
356 else
357 switch (ElementBitwidth) {
358 case 16: S += "h"; break;
359 case 32: S += "f"; break;
360 case 64: S += "d"; break;
361 default: llvm_unreachable("Unhandled case!");
362 }
363
364 if (!isFloat()) {
365 if ((isChar() || isPointer()) && !isVoidPointer()) {
366 // Make chars and typed pointers explicitly signed.
367 if (Signed)
368 S = "S" + S;
369 else if (!Signed)
370 S = "U" + S;
371 } else if (!isVoidPointer() && !Signed) {
372 S = "U" + S;
373 }
374 }
375
376 // Constant indices are "int", but have the "constant expression" modifier.
377 if (isImmediate()) {
378 assert(!isFloat() && "fp immediates are not supported");
379 S = "I" + S;
380 }
381
382 if (isScalar()) {
383 if (Constant) S += "C";
384 if (Pointer) S += "*";
385 return S;
386 }
387
388 assert(isScalableVector() && "Unsupported type");
389 return "q" + utostr(getNumElements() * NumVectors) + S;
390}
391
Sander de Smalen981f0802020-03-18 15:05:08 +0000392std::string SVEType::str() const {
393 if (isPredicatePattern())
394 return "sv_pattern";
395
396 if (isPrefetchOp())
397 return "sv_prfop";
398
399 std::string S;
400 if (Void)
401 S += "void";
402 else {
403 if (isScalableVector())
404 S += "sv";
405 if (!Signed && !Float)
406 S += "u";
407
408 if (Float)
409 S += "float";
410 else if (isScalarPredicate())
411 S += "bool";
412 else
413 S += "int";
414
415 if (!isScalarPredicate())
416 S += utostr(ElementBitwidth);
417 if (!isScalableVector() && isVector())
418 S += "x" + utostr(getNumElements());
419 if (NumVectors > 1)
420 S += "x" + utostr(NumVectors);
421 S += "_t";
422 }
423
424 if (Constant)
425 S += " const";
426 if (Pointer)
427 S += " *";
428
429 return S;
430}
Sander de Smalenc5b81462020-03-18 11:07:20 +0000431void SVEType::applyTypespec() {
432 for (char I : TS) {
433 switch (I) {
434 case 'P':
435 Predicate = true;
436 ElementBitwidth = 1;
437 break;
438 case 'U':
439 Signed = false;
440 break;
441 case 'c':
442 ElementBitwidth = 8;
443 break;
444 case 's':
445 ElementBitwidth = 16;
446 break;
447 case 'i':
448 ElementBitwidth = 32;
449 break;
450 case 'l':
451 ElementBitwidth = 64;
452 break;
453 case 'h':
454 Float = true;
455 ElementBitwidth = 16;
456 break;
457 case 'f':
458 Float = true;
459 ElementBitwidth = 32;
460 break;
461 case 'd':
462 Float = true;
463 ElementBitwidth = 64;
464 break;
465 default:
466 llvm_unreachable("Unhandled type code!");
467 }
468 }
469 assert(ElementBitwidth != ~0U && "Bad element bitwidth!");
470}
471
472void SVEType::applyModifier(char Mod) {
473 switch (Mod) {
474 case 'v':
475 Void = true;
476 break;
477 case 'd':
478 DefaultType = true;
479 break;
480 case 'c':
481 Constant = true;
482 LLVM_FALLTHROUGH;
483 case 'p':
484 Pointer = true;
485 Bitwidth = ElementBitwidth;
486 NumVectors = 0;
487 break;
Sander de Smalenfc645392020-04-20 14:57:13 +0100488 case 'e':
489 Signed = false;
490 ElementBitwidth /= 2;
491 break;
Sander de Smalen515020c2020-04-20 14:41:58 +0100492 case 'h':
493 ElementBitwidth /= 2;
494 break;
Sander de Smalenfc645392020-04-20 14:57:13 +0100495 case 'q':
496 ElementBitwidth /= 4;
497 break;
498 case 'o':
499 ElementBitwidth *= 4;
500 break;
Sander de Smalenc5b81462020-03-18 11:07:20 +0000501 case 'P':
502 Signed = true;
503 Float = false;
504 Predicate = true;
505 Bitwidth = 16;
506 ElementBitwidth = 1;
507 break;
Sander de Smalen03f419f2020-04-26 12:47:17 +0100508 case 's':
Sander de Smalen41d52662020-04-22 13:58:35 +0100509 case 'a':
510 Bitwidth = ElementBitwidth;
511 NumVectors = 0;
512 break;
Sander de Smalen1a720d42020-05-01 17:34:42 +0100513 case 'K':
514 Signed = true;
515 Float = false;
516 Bitwidth = ElementBitwidth;
517 NumVectors = 0;
518 break;
Sander de Smalen334931f2020-05-01 21:39:16 +0100519 case 'L':
520 Signed = false;
521 Float = false;
522 Bitwidth = ElementBitwidth;
523 NumVectors = 0;
524 break;
Sander de Smalen515020c2020-04-20 14:41:58 +0100525 case 'u':
526 Predicate = false;
527 Signed = false;
528 Float = false;
529 break;
Andrzej Warzynski72f56582020-04-07 11:09:01 +0100530 case 'x':
531 Predicate = false;
532 Signed = true;
533 Float = false;
534 break;
Sander de Smalenc8a5b302020-04-14 15:56:36 +0100535 case 'i':
536 Predicate = false;
537 Float = false;
538 ElementBitwidth = Bitwidth = 64;
539 NumVectors = 0;
540 Signed = false;
541 Immediate = true;
542 break;
543 case 'I':
544 Predicate = false;
545 Float = false;
546 ElementBitwidth = Bitwidth = 32;
547 NumVectors = 0;
548 Signed = true;
549 Immediate = true;
550 PredicatePattern = true;
551 break;
Sander de Smalen823e2a62020-04-24 11:31:34 +0100552 case 'J':
553 Predicate = false;
554 Float = false;
555 ElementBitwidth = Bitwidth = 32;
556 NumVectors = 0;
557 Signed = true;
558 Immediate = true;
559 PrefetchOp = true;
560 break;
Sander de Smalen662cbaf2020-04-22 15:00:01 +0100561 case 'k':
562 Predicate = false;
563 Signed = true;
564 Float = false;
565 ElementBitwidth = Bitwidth = 32;
566 NumVectors = 0;
567 break;
Sander de Smalen17a68c62020-04-14 13:17:52 +0100568 case 'l':
569 Predicate = false;
570 Signed = true;
571 Float = false;
572 ElementBitwidth = Bitwidth = 64;
573 NumVectors = 0;
574 break;
Sander de Smalen662cbaf2020-04-22 15:00:01 +0100575 case 'm':
576 Predicate = false;
577 Signed = false;
578 Float = false;
579 ElementBitwidth = Bitwidth = 32;
580 NumVectors = 0;
581 break;
582 case 'n':
583 Predicate = false;
584 Signed = false;
585 Float = false;
586 ElementBitwidth = Bitwidth = 64;
587 NumVectors = 0;
588 break;
Sander de Smalen0ddb2032020-04-24 11:31:34 +0100589 case 'w':
590 ElementBitwidth = 64;
591 break;
592 case 'j':
593 ElementBitwidth = Bitwidth = 64;
594 NumVectors = 0;
595 break;
Sander de Smalen334931f2020-05-01 21:39:16 +0100596 case 'f':
597 Signed = false;
598 ElementBitwidth = Bitwidth = 64;
599 NumVectors = 0;
600 break;
601 case 'g':
602 Signed = false;
603 Float = false;
604 ElementBitwidth = 64;
605 break;
Sander de Smalena5e03892020-04-23 10:53:23 +0100606 case 't':
607 Signed = true;
608 Float = false;
609 ElementBitwidth = 32;
610 break;
611 case 'z':
612 Signed = false;
613 Float = false;
614 ElementBitwidth = 32;
615 break;
Sander de Smalen00216442020-04-23 10:45:13 +0100616 case 'O':
617 Predicate = false;
618 Float = true;
619 ElementBitwidth = 16;
620 break;
621 case 'M':
622 Predicate = false;
623 Float = true;
624 ElementBitwidth = 32;
625 break;
626 case 'N':
627 Predicate = false;
628 Float = true;
629 ElementBitwidth = 64;
630 break;
Sander de Smalen42a56bf2020-04-29 11:36:41 +0100631 case 'Q':
632 Constant = true;
633 Pointer = true;
634 Void = true;
635 NumVectors = 0;
636 break;
Sander de Smalen17a68c62020-04-14 13:17:52 +0100637 case 'S':
638 Constant = true;
639 Pointer = true;
640 ElementBitwidth = Bitwidth = 8;
641 NumVectors = 0;
642 Signed = true;
643 break;
644 case 'W':
645 Constant = true;
646 Pointer = true;
647 ElementBitwidth = Bitwidth = 8;
648 NumVectors = 0;
649 Signed = false;
650 break;
651 case 'T':
652 Constant = true;
653 Pointer = true;
654 ElementBitwidth = Bitwidth = 16;
655 NumVectors = 0;
656 Signed = true;
657 break;
658 case 'X':
659 Constant = true;
660 Pointer = true;
661 ElementBitwidth = Bitwidth = 16;
662 NumVectors = 0;
663 Signed = false;
664 break;
665 case 'Y':
666 Constant = true;
667 Pointer = true;
668 ElementBitwidth = Bitwidth = 32;
669 NumVectors = 0;
670 Signed = false;
671 break;
672 case 'U':
673 Constant = true;
674 Pointer = true;
675 ElementBitwidth = Bitwidth = 32;
676 NumVectors = 0;
677 Signed = true;
678 break;
679 case 'A':
680 Pointer = true;
681 ElementBitwidth = Bitwidth = 8;
682 NumVectors = 0;
683 Signed = true;
684 break;
685 case 'B':
686 Pointer = true;
687 ElementBitwidth = Bitwidth = 16;
688 NumVectors = 0;
689 Signed = true;
690 break;
691 case 'C':
692 Pointer = true;
693 ElementBitwidth = Bitwidth = 32;
694 NumVectors = 0;
695 Signed = true;
696 break;
697 case 'D':
698 Pointer = true;
699 ElementBitwidth = Bitwidth = 64;
700 NumVectors = 0;
701 Signed = true;
702 break;
703 case 'E':
704 Pointer = true;
705 ElementBitwidth = Bitwidth = 8;
706 NumVectors = 0;
707 Signed = false;
708 break;
709 case 'F':
710 Pointer = true;
711 ElementBitwidth = Bitwidth = 16;
712 NumVectors = 0;
713 Signed = false;
714 break;
715 case 'G':
716 Pointer = true;
717 ElementBitwidth = Bitwidth = 32;
718 NumVectors = 0;
719 Signed = false;
720 break;
Sander de Smalenc5b81462020-03-18 11:07:20 +0000721 default:
722 llvm_unreachable("Unhandled character!");
723 }
724}
725
726
727//===----------------------------------------------------------------------===//
728// Intrinsic implementation
729//===----------------------------------------------------------------------===//
730
Sander de Smalenf6ea0262020-04-14 15:31:20 +0100731Intrinsic::Intrinsic(StringRef Name, StringRef Proto, uint64_t MergeTy,
732 StringRef MergeSuffix, uint64_t MemoryElementTy,
Sander de Smalenc8a5b302020-04-14 15:56:36 +0100733 StringRef LLVMName, uint64_t Flags,
734 ArrayRef<ImmCheck> Checks, TypeSpec BT, ClassKind Class,
735 SVEEmitter &Emitter, StringRef Guard)
Sander de Smalenf6ea0262020-04-14 15:31:20 +0100736 : Name(Name.str()), LLVMName(LLVMName), Proto(Proto.str()),
737 BaseTypeSpec(BT), Class(Class), Guard(Guard.str()),
Sander de Smalenc8a5b302020-04-14 15:56:36 +0100738 MergeSuffix(MergeSuffix.str()), BaseType(BT, 'd'), Flags(Flags),
739 ImmChecks(Checks.begin(), Checks.end()) {
Sander de Smalenf6ea0262020-04-14 15:31:20 +0100740
741 // Types[0] is the return value.
742 for (unsigned I = 0; I < Proto.size(); ++I) {
743 SVEType T(BaseTypeSpec, Proto[I]);
744 Types.push_back(T);
Sander de Smalenc8a5b302020-04-14 15:56:36 +0100745
746 // Add range checks for immediates
747 if (I > 0) {
748 if (T.isPredicatePattern())
749 ImmChecks.emplace_back(
750 I - 1, Emitter.getEnumValueForImmCheck("ImmCheck0_31"));
Sander de Smalen823e2a62020-04-24 11:31:34 +0100751 else if (T.isPrefetchOp())
752 ImmChecks.emplace_back(
753 I - 1, Emitter.getEnumValueForImmCheck("ImmCheck0_13"));
Sander de Smalenc8a5b302020-04-14 15:56:36 +0100754 }
Sander de Smalenf6ea0262020-04-14 15:31:20 +0100755 }
756
757 // Set flags based on properties
758 this->Flags |= Emitter.encodeTypeFlags(BaseType);
759 this->Flags |= Emitter.encodeMemoryElementType(MemoryElementTy);
760 this->Flags |= Emitter.encodeMergeType(MergeTy);
Sander de Smalen41d52662020-04-22 13:58:35 +0100761 if (hasSplat())
762 this->Flags |= Emitter.encodeSplatOperand(getSplatIdx());
Sander de Smalenf6ea0262020-04-14 15:31:20 +0100763}
764
Sander de Smalenc5b81462020-03-18 11:07:20 +0000765std::string Intrinsic::getBuiltinTypeStr() {
766 std::string S;
767
768 SVEType RetT = getReturnType();
769 // Since the return value must be one type, return a vector type of the
770 // appropriate width which we will bitcast. An exception is made for
771 // returning structs of 2, 3, or 4 vectors which are returned in a sret-like
772 // fashion, storing them to a pointer arg.
773 if (RetT.getNumVectors() > 1) {
774 S += "vv*"; // void result with void* first argument
775 } else
776 S += RetT.builtin_str();
777
778 for (unsigned I = 0; I < getNumParams(); ++I)
779 S += getParamType(I).builtin_str();
780
781 return S;
782}
783
784std::string Intrinsic::replaceTemplatedArgs(std::string Name, TypeSpec TS,
785 std::string Proto) const {
786 std::string Ret = Name;
787 while (Ret.find('{') != std::string::npos) {
788 size_t Pos = Ret.find('{');
789 size_t End = Ret.find('}');
790 unsigned NumChars = End - Pos + 1;
791 assert(NumChars == 3 && "Unexpected template argument");
792
793 SVEType T;
794 char C = Ret[Pos+1];
795 switch(C) {
796 default:
797 llvm_unreachable("Unknown predication specifier");
798 case 'd':
799 T = SVEType(TS, 'd');
800 break;
801 case '0':
802 case '1':
803 case '2':
804 case '3':
805 T = SVEType(TS, Proto[C - '0']);
806 break;
807 }
808
809 // Replace templated arg with the right suffix (e.g. u32)
810 std::string TypeCode;
811 if (T.isInteger())
812 TypeCode = T.isSigned() ? 's' : 'u';
813 else if (T.isPredicateVector())
814 TypeCode = 'b';
815 else
816 TypeCode = 'f';
817 Ret.replace(Pos, NumChars, TypeCode + utostr(T.getElementSizeInBits()));
818 }
819
820 return Ret;
821}
822
Sander de Smalenc5b81462020-03-18 11:07:20 +0000823std::string Intrinsic::mangleName(ClassKind LocalCK) const {
824 std::string S = getName();
825
826 if (LocalCK == ClassG) {
827 // Remove the square brackets and everything in between.
828 while (S.find("[") != std::string::npos) {
829 auto Start = S.find("[");
830 auto End = S.find(']');
831 S.erase(Start, (End-Start)+1);
832 }
833 } else {
834 // Remove the square brackets.
835 while (S.find("[") != std::string::npos) {
836 auto BrPos = S.find('[');
837 if (BrPos != std::string::npos)
838 S.erase(BrPos, 1);
839 BrPos = S.find(']');
840 if (BrPos != std::string::npos)
841 S.erase(BrPos, 1);
842 }
843 }
844
845 // Replace all {d} like expressions with e.g. 'u32'
846 return replaceTemplatedArgs(S, getBaseTypeSpec(), getProto()) +
847 getMergeSuffix();
848}
849
850void Intrinsic::emitIntrinsic(raw_ostream &OS) const {
851 // Use the preprocessor to
852 if (getClassKind() != ClassG || getProto().size() <= 1) {
853 OS << "#define " << mangleName(getClassKind())
854 << "(...) __builtin_sve_" << mangleName(ClassS)
855 << "(__VA_ARGS__)\n";
856 } else {
Sander de Smalen981f0802020-03-18 15:05:08 +0000857 std::string FullName = mangleName(ClassS);
858 std::string ProtoName = mangleName(ClassG);
859
860 OS << "__aio __attribute__((__clang_arm_builtin_alias("
861 << "__builtin_sve_" << FullName << ")))\n";
862
863 OS << getTypes()[0].str() << " " << ProtoName << "(";
864 for (unsigned I = 0; I < getTypes().size() - 1; ++I) {
865 if (I != 0)
866 OS << ", ";
867 OS << getTypes()[I + 1].str();
868 }
869 OS << ");\n";
Sander de Smalenc5b81462020-03-18 11:07:20 +0000870 }
871}
872
873//===----------------------------------------------------------------------===//
874// SVEEmitter implementation
875//===----------------------------------------------------------------------===//
Sander de Smalenf6ea0262020-04-14 15:31:20 +0100876uint64_t SVEEmitter::encodeTypeFlags(const SVEType &T) {
877 if (T.isFloat()) {
878 switch (T.getElementSizeInBits()) {
879 case 16:
880 return encodeEltType("EltTyFloat16");
881 case 32:
882 return encodeEltType("EltTyFloat32");
883 case 64:
884 return encodeEltType("EltTyFloat64");
885 default:
886 llvm_unreachable("Unhandled float element bitwidth!");
887 }
888 }
889
890 if (T.isPredicateVector()) {
891 switch (T.getElementSizeInBits()) {
892 case 8:
893 return encodeEltType("EltTyBool8");
894 case 16:
895 return encodeEltType("EltTyBool16");
896 case 32:
897 return encodeEltType("EltTyBool32");
898 case 64:
899 return encodeEltType("EltTyBool64");
900 default:
901 llvm_unreachable("Unhandled predicate element bitwidth!");
902 }
903 }
904
905 switch (T.getElementSizeInBits()) {
906 case 8:
907 return encodeEltType("EltTyInt8");
908 case 16:
909 return encodeEltType("EltTyInt16");
910 case 32:
911 return encodeEltType("EltTyInt32");
912 case 64:
913 return encodeEltType("EltTyInt64");
914 default:
915 llvm_unreachable("Unhandled integer element bitwidth!");
916 }
917}
918
Sander de Smalenc5b81462020-03-18 11:07:20 +0000919void SVEEmitter::createIntrinsic(
920 Record *R, SmallVectorImpl<std::unique_ptr<Intrinsic>> &Out) {
921 StringRef Name = R->getValueAsString("Name");
922 StringRef Proto = R->getValueAsString("Prototype");
923 StringRef Types = R->getValueAsString("Types");
924 StringRef Guard = R->getValueAsString("ArchGuard");
925 StringRef LLVMName = R->getValueAsString("LLVMIntrinsic");
Sander de Smalenf6ea0262020-04-14 15:31:20 +0100926 uint64_t Merge = R->getValueAsInt("Merge");
927 StringRef MergeSuffix = R->getValueAsString("MergeSuffix");
928 uint64_t MemEltType = R->getValueAsInt("MemEltType");
Sander de Smalenc5b81462020-03-18 11:07:20 +0000929 std::vector<Record*> FlagsList = R->getValueAsListOfDefs("Flags");
Sander de Smalenc8a5b302020-04-14 15:56:36 +0100930 std::vector<Record*> ImmCheckList = R->getValueAsListOfDefs("ImmChecks");
Sander de Smalenc5b81462020-03-18 11:07:20 +0000931
932 int64_t Flags = 0;
933 for (auto FlagRec : FlagsList)
934 Flags |= FlagRec->getValueAsInt("Value");
Sander de Smalenc5b81462020-03-18 11:07:20 +0000935
Sander de Smalen662cbaf2020-04-22 15:00:01 +0100936 // Create a dummy TypeSpec for non-overloaded builtins.
937 if (Types.empty()) {
938 assert((Flags & getEnumValueForFlag("IsOverloadNone")) &&
939 "Expect TypeSpec for overloaded builtin!");
940 Types = "i";
941 }
942
Sander de Smalenc5b81462020-03-18 11:07:20 +0000943 // Extract type specs from string
944 SmallVector<TypeSpec, 8> TypeSpecs;
945 TypeSpec Acc;
946 for (char I : Types) {
947 Acc.push_back(I);
948 if (islower(I)) {
949 TypeSpecs.push_back(TypeSpec(Acc));
950 Acc.clear();
951 }
952 }
953
954 // Remove duplicate type specs.
Benjamin Kramer4065e922020-03-28 19:19:55 +0100955 llvm::sort(TypeSpecs);
Sander de Smalenc5b81462020-03-18 11:07:20 +0000956 TypeSpecs.erase(std::unique(TypeSpecs.begin(), TypeSpecs.end()),
957 TypeSpecs.end());
958
959 // Create an Intrinsic for each type spec.
960 for (auto TS : TypeSpecs) {
Sander de Smalenc8a5b302020-04-14 15:56:36 +0100961 // Collate a list of range/option checks for the immediates.
962 SmallVector<ImmCheck, 2> ImmChecks;
963 for (auto *R : ImmCheckList) {
Christopher Tetreault464a0692020-04-15 15:16:17 -0700964 int64_t Arg = R->getValueAsInt("Arg");
965 int64_t EltSizeArg = R->getValueAsInt("EltSizeArg");
966 int64_t Kind = R->getValueAsDef("Kind")->getValueAsInt("Value");
967 assert(Arg >= 0 && Kind >= 0 && "Arg and Kind must be nonnegative");
Sander de Smalenc8a5b302020-04-14 15:56:36 +0100968
969 unsigned ElementSizeInBits = 0;
970 if (EltSizeArg >= 0)
971 ElementSizeInBits =
972 SVEType(TS, Proto[EltSizeArg + /* offset by return arg */ 1])
973 .getElementSizeInBits();
974 ImmChecks.push_back(ImmCheck(Arg, Kind, ElementSizeInBits));
975 }
976
977 Out.push_back(std::make_unique<Intrinsic>(
978 Name, Proto, Merge, MergeSuffix, MemEltType, LLVMName, Flags, ImmChecks,
979 TS, ClassS, *this, Guard));
Sander de Smalen981f0802020-03-18 15:05:08 +0000980
981 // Also generate the short-form (e.g. svadd_m) for the given type-spec.
982 if (Intrinsic::isOverloadedIntrinsic(Name))
Sander de Smalenc8a5b302020-04-14 15:56:36 +0100983 Out.push_back(std::make_unique<Intrinsic>(
984 Name, Proto, Merge, MergeSuffix, MemEltType, LLVMName, Flags,
985 ImmChecks, TS, ClassG, *this, Guard));
Sander de Smalenc5b81462020-03-18 11:07:20 +0000986 }
987}
988
989void SVEEmitter::createHeader(raw_ostream &OS) {
Sander de Smalen5087ace2020-03-15 14:29:45 +0000990 OS << "/*===---- arm_sve.h - ARM SVE intrinsics "
991 "-----------------------------------===\n"
992 " *\n"
993 " *\n"
994 " * Part of the LLVM Project, under the Apache License v2.0 with LLVM "
995 "Exceptions.\n"
996 " * See https://llvm.org/LICENSE.txt for license information.\n"
997 " * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception\n"
998 " *\n"
999 " *===-----------------------------------------------------------------"
1000 "------===\n"
1001 " */\n\n";
1002
1003 OS << "#ifndef __ARM_SVE_H\n";
1004 OS << "#define __ARM_SVE_H\n\n";
1005
1006 OS << "#if !defined(__ARM_FEATURE_SVE)\n";
1007 OS << "#error \"SVE support not enabled\"\n";
1008 OS << "#else\n\n";
1009
1010 OS << "#include <stdint.h>\n\n";
Sander de Smalenc5b81462020-03-18 11:07:20 +00001011 OS << "#ifdef __cplusplus\n";
1012 OS << "extern \"C\" {\n";
1013 OS << "#else\n";
Sander de Smalen5087ace2020-03-15 14:29:45 +00001014 OS << "#include <stdbool.h>\n";
1015 OS << "#endif\n\n";
1016
1017 OS << "typedef __fp16 float16_t;\n";
1018 OS << "typedef float float32_t;\n";
1019 OS << "typedef double float64_t;\n";
1020 OS << "typedef bool bool_t;\n\n";
1021
1022 OS << "typedef __SVInt8_t svint8_t;\n";
1023 OS << "typedef __SVInt16_t svint16_t;\n";
1024 OS << "typedef __SVInt32_t svint32_t;\n";
1025 OS << "typedef __SVInt64_t svint64_t;\n";
1026 OS << "typedef __SVUint8_t svuint8_t;\n";
1027 OS << "typedef __SVUint16_t svuint16_t;\n";
1028 OS << "typedef __SVUint32_t svuint32_t;\n";
1029 OS << "typedef __SVUint64_t svuint64_t;\n";
1030 OS << "typedef __SVFloat16_t svfloat16_t;\n";
1031 OS << "typedef __SVFloat32_t svfloat32_t;\n";
1032 OS << "typedef __SVFloat64_t svfloat64_t;\n";
1033 OS << "typedef __SVBool_t svbool_t;\n\n";
1034
Sander de Smalenc8a5b302020-04-14 15:56:36 +01001035 OS << "typedef enum\n";
1036 OS << "{\n";
1037 OS << " SV_POW2 = 0,\n";
1038 OS << " SV_VL1 = 1,\n";
1039 OS << " SV_VL2 = 2,\n";
1040 OS << " SV_VL3 = 3,\n";
1041 OS << " SV_VL4 = 4,\n";
1042 OS << " SV_VL5 = 5,\n";
1043 OS << " SV_VL6 = 6,\n";
1044 OS << " SV_VL7 = 7,\n";
1045 OS << " SV_VL8 = 8,\n";
1046 OS << " SV_VL16 = 9,\n";
1047 OS << " SV_VL32 = 10,\n";
1048 OS << " SV_VL64 = 11,\n";
1049 OS << " SV_VL128 = 12,\n";
1050 OS << " SV_VL256 = 13,\n";
1051 OS << " SV_MUL4 = 29,\n";
1052 OS << " SV_MUL3 = 30,\n";
1053 OS << " SV_ALL = 31\n";
1054 OS << "} sv_pattern;\n\n";
1055
Sander de Smalen823e2a62020-04-24 11:31:34 +01001056 OS << "typedef enum\n";
1057 OS << "{\n";
1058 OS << " SV_PLDL1KEEP = 0,\n";
1059 OS << " SV_PLDL1STRM = 1,\n";
1060 OS << " SV_PLDL2KEEP = 2,\n";
1061 OS << " SV_PLDL2STRM = 3,\n";
1062 OS << " SV_PLDL3KEEP = 4,\n";
1063 OS << " SV_PLDL3STRM = 5,\n";
1064 OS << " SV_PSTL1KEEP = 8,\n";
1065 OS << " SV_PSTL1STRM = 9,\n";
1066 OS << " SV_PSTL2KEEP = 10,\n";
1067 OS << " SV_PSTL2STRM = 11,\n";
1068 OS << " SV_PSTL3KEEP = 12,\n";
1069 OS << " SV_PSTL3STRM = 13\n";
1070 OS << "} sv_prfop;\n\n";
1071
Sander de Smalen981f0802020-03-18 15:05:08 +00001072 OS << "/* Function attributes */\n";
1073 OS << "#define __aio static inline __attribute__((__always_inline__, "
1074 "__nodebug__, __overloadable__))\n\n";
1075
Sander de Smalenc5b81462020-03-18 11:07:20 +00001076 SmallVector<std::unique_ptr<Intrinsic>, 128> Defs;
1077 std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst");
1078 for (auto *R : RV)
1079 createIntrinsic(R, Defs);
Sander de Smalen5087ace2020-03-15 14:29:45 +00001080
Sander de Smalenc5b81462020-03-18 11:07:20 +00001081 // Sort intrinsics in header file by following order/priority:
1082 // - Architectural guard (i.e. does it require SVE2 or SVE2_AES)
1083 // - Class (is intrinsic overloaded or not)
1084 // - Intrinsic name
1085 std::stable_sort(
1086 Defs.begin(), Defs.end(), [](const std::unique_ptr<Intrinsic> &A,
1087 const std::unique_ptr<Intrinsic> &B) {
Eric Fiselieraf2968e2020-04-16 18:35:31 -04001088 auto ToTuple = [](const std::unique_ptr<Intrinsic> &I) {
1089 return std::make_tuple(I->getGuard(), (unsigned)I->getClassKind(), I->getName());
1090 };
1091 return ToTuple(A) < ToTuple(B);
Sander de Smalenc5b81462020-03-18 11:07:20 +00001092 });
1093
1094 StringRef InGuard = "";
1095 for (auto &I : Defs) {
1096 // Emit #endif/#if pair if needed.
1097 if (I->getGuard() != InGuard) {
1098 if (!InGuard.empty())
1099 OS << "#endif //" << InGuard << "\n";
1100 InGuard = I->getGuard();
1101 if (!InGuard.empty())
1102 OS << "\n#if " << InGuard << "\n";
1103 }
1104
1105 // Actually emit the intrinsic declaration.
1106 I->emitIntrinsic(OS);
1107 }
1108
1109 if (!InGuard.empty())
1110 OS << "#endif //" << InGuard << "\n";
1111
Sander de Smalen00216442020-04-23 10:45:13 +01001112 OS << "#if defined(__ARM_FEATURE_SVE2)\n";
1113 OS << "#define svcvtnt_f16_x svcvtnt_f16_m\n";
1114 OS << "#define svcvtnt_f16_f32_x svcvtnt_f16_f32_m\n";
1115 OS << "#define svcvtnt_f32_x svcvtnt_f32_m\n";
1116 OS << "#define svcvtnt_f32_f64_x svcvtnt_f32_f64_m\n\n";
1117
1118 OS << "#define svcvtxnt_f32_x svcvtxnt_f32_m\n";
1119 OS << "#define svcvtxnt_f32_f64_x svcvtxnt_f32_f64_m\n\n";
1120
1121 OS << "#endif /*__ARM_FEATURE_SVE2 */\n\n";
1122
Sander de Smalenc5b81462020-03-18 11:07:20 +00001123 OS << "#ifdef __cplusplus\n";
1124 OS << "} // extern \"C\"\n";
1125 OS << "#endif\n\n";
1126 OS << "#endif /*__ARM_FEATURE_SVE */\n\n";
Sander de Smalen5087ace2020-03-15 14:29:45 +00001127 OS << "#endif /* __ARM_SVE_H */\n";
1128}
1129
Sander de Smalenc5b81462020-03-18 11:07:20 +00001130void SVEEmitter::createBuiltins(raw_ostream &OS) {
1131 std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst");
1132 SmallVector<std::unique_ptr<Intrinsic>, 128> Defs;
1133 for (auto *R : RV)
1134 createIntrinsic(R, Defs);
1135
1136 // The mappings must be sorted based on BuiltinID.
1137 llvm::sort(Defs, [](const std::unique_ptr<Intrinsic> &A,
1138 const std::unique_ptr<Intrinsic> &B) {
1139 return A->getMangledName() < B->getMangledName();
1140 });
1141
1142 OS << "#ifdef GET_SVE_BUILTINS\n";
1143 for (auto &Def : Defs) {
1144 // Only create BUILTINs for non-overloaded intrinsics, as overloaded
1145 // declarations only live in the header file.
1146 if (Def->getClassKind() != ClassG)
1147 OS << "BUILTIN(__builtin_sve_" << Def->getMangledName() << ", \""
1148 << Def->getBuiltinTypeStr() << "\", \"n\")\n";
1149 }
1150 OS << "#endif\n\n";
1151}
1152
1153void SVEEmitter::createCodeGenMap(raw_ostream &OS) {
1154 std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst");
1155 SmallVector<std::unique_ptr<Intrinsic>, 128> Defs;
1156 for (auto *R : RV)
1157 createIntrinsic(R, Defs);
1158
1159 // The mappings must be sorted based on BuiltinID.
1160 llvm::sort(Defs, [](const std::unique_ptr<Intrinsic> &A,
1161 const std::unique_ptr<Intrinsic> &B) {
1162 return A->getMangledName() < B->getMangledName();
1163 });
1164
1165 OS << "#ifdef GET_SVE_LLVM_INTRINSIC_MAP\n";
1166 for (auto &Def : Defs) {
1167 // Builtins only exist for non-overloaded intrinsics, overloaded
1168 // declarations only live in the header file.
1169 if (Def->getClassKind() == ClassG)
1170 continue;
1171
Sander de Smalenf6ea0262020-04-14 15:31:20 +01001172 uint64_t Flags = Def->getFlags();
Sander de Smalenc5b81462020-03-18 11:07:20 +00001173 auto FlagString = std::to_string(Flags);
1174
1175 std::string LLVMName = Def->getLLVMName();
1176 std::string Builtin = Def->getMangledName();
1177 if (!LLVMName.empty())
1178 OS << "SVEMAP1(" << Builtin << ", " << LLVMName << ", " << FlagString
1179 << "),\n";
1180 else
1181 OS << "SVEMAP2(" << Builtin << ", " << FlagString << "),\n";
1182 }
1183 OS << "#endif\n\n";
1184}
1185
Sander de Smalenc8a5b302020-04-14 15:56:36 +01001186void SVEEmitter::createRangeChecks(raw_ostream &OS) {
1187 std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst");
1188 SmallVector<std::unique_ptr<Intrinsic>, 128> Defs;
1189 for (auto *R : RV)
1190 createIntrinsic(R, Defs);
1191
1192 // The mappings must be sorted based on BuiltinID.
1193 llvm::sort(Defs, [](const std::unique_ptr<Intrinsic> &A,
1194 const std::unique_ptr<Intrinsic> &B) {
1195 return A->getMangledName() < B->getMangledName();
1196 });
1197
1198
1199 OS << "#ifdef GET_SVE_IMMEDIATE_CHECK\n";
1200
1201 // Ensure these are only emitted once.
1202 std::set<std::string> Emitted;
1203
1204 for (auto &Def : Defs) {
1205 if (Emitted.find(Def->getMangledName()) != Emitted.end() ||
1206 Def->getImmChecks().empty())
1207 continue;
1208
1209 OS << "case SVE::BI__builtin_sve_" << Def->getMangledName() << ":\n";
1210 for (auto &Check : Def->getImmChecks())
1211 OS << "ImmChecks.push_back(std::make_tuple(" << Check.getArg() << ", "
1212 << Check.getKind() << ", " << Check.getElementSizeInBits() << "));\n";
1213 OS << " break;\n";
1214
1215 Emitted.insert(Def->getMangledName());
1216 }
1217
1218 OS << "#endif\n\n";
1219}
1220
Sander de Smalenc5b81462020-03-18 11:07:20 +00001221/// Create the SVETypeFlags used in CGBuiltins
1222void SVEEmitter::createTypeFlags(raw_ostream &OS) {
1223 OS << "#ifdef LLVM_GET_SVE_TYPEFLAGS\n";
1224 for (auto &KV : FlagTypes)
1225 OS << "const uint64_t " << KV.getKey() << " = " << KV.getValue() << ";\n";
1226 OS << "#endif\n\n";
1227
1228 OS << "#ifdef LLVM_GET_SVE_ELTTYPES\n";
1229 for (auto &KV : EltTypes)
1230 OS << " " << KV.getKey() << " = " << KV.getValue() << ",\n";
1231 OS << "#endif\n\n";
1232
1233 OS << "#ifdef LLVM_GET_SVE_MEMELTTYPES\n";
1234 for (auto &KV : MemEltTypes)
1235 OS << " " << KV.getKey() << " = " << KV.getValue() << ",\n";
1236 OS << "#endif\n\n";
Sander de Smalenf6ea0262020-04-14 15:31:20 +01001237
1238 OS << "#ifdef LLVM_GET_SVE_MERGETYPES\n";
1239 for (auto &KV : MergeTypes)
1240 OS << " " << KV.getKey() << " = " << KV.getValue() << ",\n";
1241 OS << "#endif\n\n";
Sander de Smalenc8a5b302020-04-14 15:56:36 +01001242
1243 OS << "#ifdef LLVM_GET_SVE_IMMCHECKTYPES\n";
1244 for (auto &KV : ImmCheckTypes)
1245 OS << " " << KV.getKey() << " = " << KV.getValue() << ",\n";
1246 OS << "#endif\n\n";
Sander de Smalenc5b81462020-03-18 11:07:20 +00001247}
1248
Sander de Smalen5087ace2020-03-15 14:29:45 +00001249namespace clang {
1250void EmitSveHeader(RecordKeeper &Records, raw_ostream &OS) {
Sander de Smalenc5b81462020-03-18 11:07:20 +00001251 SVEEmitter(Records).createHeader(OS);
1252}
1253
1254void EmitSveBuiltins(RecordKeeper &Records, raw_ostream &OS) {
1255 SVEEmitter(Records).createBuiltins(OS);
1256}
1257
1258void EmitSveBuiltinCG(RecordKeeper &Records, raw_ostream &OS) {
1259 SVEEmitter(Records).createCodeGenMap(OS);
1260}
Sander de Smalenc8a5b302020-04-14 15:56:36 +01001261
1262void EmitSveRangeChecks(RecordKeeper &Records, raw_ostream &OS) {
1263 SVEEmitter(Records).createRangeChecks(OS);
1264}
1265
Sander de Smalenc5b81462020-03-18 11:07:20 +00001266void EmitSveTypeFlags(RecordKeeper &Records, raw_ostream &OS) {
1267 SVEEmitter(Records).createTypeFlags(OS);
Sander de Smalen5087ace2020-03-15 14:29:45 +00001268}
1269
1270} // End namespace clang