blob: d787e6e56b34e9fd6067830413528799cfa0c698 [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; }
Sander de Smalenaed6bd62020-05-05 09:16:57 +010097 bool isScalarPredicate() const {
98 return !Float && Predicate && NumVectors == 0;
99 }
Sander de Smalenc5b81462020-03-18 11:07:20 +0000100 bool isPredicateVector() const { return Predicate; }
101 bool isPredicatePattern() const { return PredicatePattern; }
102 bool isPrefetchOp() const { return PrefetchOp; }
103 bool isConstant() const { return Constant; }
104 unsigned getElementSizeInBits() const { return ElementBitwidth; }
105 unsigned getNumVectors() const { return NumVectors; }
106
107 unsigned getNumElements() const {
108 assert(ElementBitwidth != ~0U);
109 return Bitwidth / ElementBitwidth;
110 }
111 unsigned getSizeInBits() const {
112 return Bitwidth;
113 }
114
115 /// Return the string representation of a type, which is an encoded
116 /// string for passing to the BUILTIN() macro in Builtins.def.
117 std::string builtin_str() const;
118
Sander de Smalen981f0802020-03-18 15:05:08 +0000119 /// Return the C/C++ string representation of a type for use in the
120 /// arm_sve.h header file.
121 std::string str() const;
122
Sander de Smalenc5b81462020-03-18 11:07:20 +0000123private:
124 /// Creates the type based on the typespec string in TS.
125 void applyTypespec();
126
127 /// Applies a prototype modifier to the type.
128 void applyModifier(char Mod);
129};
130
131
132class SVEEmitter;
133
134/// The main grunt class. This represents an instantiation of an intrinsic with
135/// a particular typespec and prototype.
136class Intrinsic {
137 /// The unmangled name.
138 std::string Name;
139
140 /// The name of the corresponding LLVM IR intrinsic.
141 std::string LLVMName;
142
143 /// Intrinsic prototype.
144 std::string Proto;
145
146 /// The base type spec for this intrinsic.
147 TypeSpec BaseTypeSpec;
148
149 /// The base class kind. Most intrinsics use ClassS, which has full type
150 /// info for integers (_s32/_u32), or ClassG which is used for overloaded
151 /// intrinsics.
152 ClassKind Class;
153
154 /// The architectural #ifdef guard.
155 std::string Guard;
156
Sander de Smalenf6ea0262020-04-14 15:31:20 +0100157 // The merge suffix such as _m, _x or _z.
158 std::string MergeSuffix;
159
Sander de Smalenc5b81462020-03-18 11:07:20 +0000160 /// The types of return value [0] and parameters [1..].
161 std::vector<SVEType> Types;
162
163 /// The "base type", which is VarType('d', BaseTypeSpec).
164 SVEType BaseType;
165
Sander de Smalenf6ea0262020-04-14 15:31:20 +0100166 uint64_t Flags;
Sander de Smalenc5b81462020-03-18 11:07:20 +0000167
Sander de Smalenc8a5b302020-04-14 15:56:36 +0100168 SmallVector<ImmCheck, 2> ImmChecks;
169
Sander de Smalenc5b81462020-03-18 11:07:20 +0000170public:
Sander de Smalenf6ea0262020-04-14 15:31:20 +0100171 Intrinsic(StringRef Name, StringRef Proto, uint64_t MergeTy,
172 StringRef MergeSuffix, uint64_t MemoryElementTy, StringRef LLVMName,
Sander de Smalenc8a5b302020-04-14 15:56:36 +0100173 uint64_t Flags, ArrayRef<ImmCheck> ImmChecks, TypeSpec BT,
174 ClassKind Class, SVEEmitter &Emitter, StringRef Guard);
Sander de Smalenc5b81462020-03-18 11:07:20 +0000175
176 ~Intrinsic()=default;
177
178 std::string getName() const { return Name; }
179 std::string getLLVMName() const { return LLVMName; }
180 std::string getProto() const { return Proto; }
181 TypeSpec getBaseTypeSpec() const { return BaseTypeSpec; }
182 SVEType getBaseType() const { return BaseType; }
183
184 StringRef getGuard() const { return Guard; }
185 ClassKind getClassKind() const { return Class; }
Sander de Smalenc5b81462020-03-18 11:07:20 +0000186
187 SVEType getReturnType() const { return Types[0]; }
188 ArrayRef<SVEType> getTypes() const { return Types; }
189 SVEType getParamType(unsigned I) const { return Types[I + 1]; }
190 unsigned getNumParams() const { return Proto.size() - 1; }
191
Sander de Smalenf6ea0262020-04-14 15:31:20 +0100192 uint64_t getFlags() const { return Flags; }
Sander de Smalenc5b81462020-03-18 11:07:20 +0000193 bool isFlagSet(uint64_t Flag) const { return Flags & Flag;}
194
Sander de Smalenc8a5b302020-04-14 15:56:36 +0100195 ArrayRef<ImmCheck> getImmChecks() const { return ImmChecks; }
196
Sander de Smalenc5b81462020-03-18 11:07:20 +0000197 /// Return the type string for a BUILTIN() macro in Builtins.def.
198 std::string getBuiltinTypeStr();
199
200 /// Return the name, mangled with type information. The name is mangled for
201 /// ClassS, so will add type suffixes such as _u32/_s32.
202 std::string getMangledName() const { return mangleName(ClassS); }
203
204 /// Returns true if the intrinsic is overloaded, in that it should also generate
205 /// a short form without the type-specifiers, e.g. 'svld1(..)' instead of
206 /// 'svld1_u32(..)'.
207 static bool isOverloadedIntrinsic(StringRef Name) {
208 auto BrOpen = Name.find("[");
209 auto BrClose = Name.find(']');
210 return BrOpen != std::string::npos && BrClose != std::string::npos;
211 }
212
Sander de Smalen41d52662020-04-22 13:58:35 +0100213 /// Return true if the intrinsic takes a splat operand.
214 bool hasSplat() const {
215 // These prototype modifiers are described in arm_sve.td.
216 return Proto.find_first_of("ajfrKLR") != std::string::npos;
217 }
218
219 /// Return the parameter index of the splat operand.
220 unsigned getSplatIdx() const {
221 // These prototype modifiers are described in arm_sve.td.
222 auto Idx = Proto.find_first_of("ajfrKLR");
223 assert(Idx != std::string::npos && Idx > 0 &&
224 "Prototype has no splat operand");
225 return Idx - 1;
226 }
227
Sander de Smalenc5b81462020-03-18 11:07:20 +0000228 /// Emits the intrinsic declaration to the ostream.
229 void emitIntrinsic(raw_ostream &OS) const;
230
231private:
Sander de Smalenf6ea0262020-04-14 15:31:20 +0100232 std::string getMergeSuffix() const { return MergeSuffix; }
Sander de Smalenc5b81462020-03-18 11:07:20 +0000233 std::string mangleName(ClassKind LocalCK) const;
234 std::string replaceTemplatedArgs(std::string Name, TypeSpec TS,
235 std::string Proto) const;
236};
237
238class SVEEmitter {
239private:
Sander de Smalen5ba32902020-05-05 13:04:14 +0100240 // The reinterpret builtins are generated separately because they
241 // need the cross product of all types (121 functions in total),
242 // which is inconvenient to specify in the arm_sve.td file or
243 // generate in CGBuiltin.cpp.
244 struct ReinterpretTypeInfo {
245 const char *Suffix;
246 const char *Type;
247 const char *BuiltinType;
248 };
249 SmallVector<ReinterpretTypeInfo, 11> Reinterprets = {
250 {"s8", "svint8_t", "q16Sc"}, {"s16", "svint16_t", "q8Ss"},
251 {"s32", "svint32_t", "q4Si"}, {"s64", "svint64_t", "q2SWi"},
252 {"u8", "svuint8_t", "q16Uc"}, {"u16", "svuint16_t", "q8Us"},
253 {"u32", "svuint32_t", "q4Ui"}, {"u64", "svuint64_t", "q2UWi"},
254 {"f16", "svfloat16_t", "q8h"}, {"f32", "svfloat32_t", "q4f"},
255 {"f64", "svfloat64_t", "q2d"}};
256
Sander de Smalenc5b81462020-03-18 11:07:20 +0000257 RecordKeeper &Records;
258 llvm::StringMap<uint64_t> EltTypes;
259 llvm::StringMap<uint64_t> MemEltTypes;
260 llvm::StringMap<uint64_t> FlagTypes;
Sander de Smalenf6ea0262020-04-14 15:31:20 +0100261 llvm::StringMap<uint64_t> MergeTypes;
Sander de Smalenc8a5b302020-04-14 15:56:36 +0100262 llvm::StringMap<uint64_t> ImmCheckTypes;
Sander de Smalenc5b81462020-03-18 11:07:20 +0000263
Sander de Smalenc5b81462020-03-18 11:07:20 +0000264public:
265 SVEEmitter(RecordKeeper &R) : Records(R) {
266 for (auto *RV : Records.getAllDerivedDefinitions("EltType"))
267 EltTypes[RV->getNameInitAsString()] = RV->getValueAsInt("Value");
268 for (auto *RV : Records.getAllDerivedDefinitions("MemEltType"))
269 MemEltTypes[RV->getNameInitAsString()] = RV->getValueAsInt("Value");
270 for (auto *RV : Records.getAllDerivedDefinitions("FlagType"))
271 FlagTypes[RV->getNameInitAsString()] = RV->getValueAsInt("Value");
Sander de Smalenf6ea0262020-04-14 15:31:20 +0100272 for (auto *RV : Records.getAllDerivedDefinitions("MergeType"))
273 MergeTypes[RV->getNameInitAsString()] = RV->getValueAsInt("Value");
Sander de Smalenc8a5b302020-04-14 15:56:36 +0100274 for (auto *RV : Records.getAllDerivedDefinitions("ImmCheckType"))
275 ImmCheckTypes[RV->getNameInitAsString()] = RV->getValueAsInt("Value");
276 }
277
278 /// Returns the enum value for the immcheck type
279 unsigned getEnumValueForImmCheck(StringRef C) const {
280 auto It = ImmCheckTypes.find(C);
281 if (It != ImmCheckTypes.end())
282 return It->getValue();
283 llvm_unreachable("Unsupported imm check");
Sander de Smalenc5b81462020-03-18 11:07:20 +0000284 }
285
Sander de Smalen662cbaf2020-04-22 15:00:01 +0100286 /// Returns the enum value for the flag type
287 uint64_t getEnumValueForFlag(StringRef C) const {
288 auto Res = FlagTypes.find(C);
289 if (Res != FlagTypes.end())
290 return Res->getValue();
291 llvm_unreachable("Unsupported flag");
292 }
293
Sander de Smalenf6ea0262020-04-14 15:31:20 +0100294 // Returns the SVETypeFlags for a given value and mask.
295 uint64_t encodeFlag(uint64_t V, StringRef MaskName) const {
296 auto It = FlagTypes.find(MaskName);
297 if (It != FlagTypes.end()) {
298 uint64_t Mask = It->getValue();
299 unsigned Shift = llvm::countTrailingZeros(Mask);
300 return (V << Shift) & Mask;
301 }
302 llvm_unreachable("Unsupported flag");
303 }
304
305 // Returns the SVETypeFlags for the given element type.
306 uint64_t encodeEltType(StringRef EltName) {
307 auto It = EltTypes.find(EltName);
308 if (It != EltTypes.end())
309 return encodeFlag(It->getValue(), "EltTypeMask");
310 llvm_unreachable("Unsupported EltType");
311 }
312
313 // Returns the SVETypeFlags for the given memory element type.
314 uint64_t encodeMemoryElementType(uint64_t MT) {
315 return encodeFlag(MT, "MemEltTypeMask");
316 }
317
318 // Returns the SVETypeFlags for the given merge type.
319 uint64_t encodeMergeType(uint64_t MT) {
320 return encodeFlag(MT, "MergeTypeMask");
321 }
322
Sander de Smalen41d52662020-04-22 13:58:35 +0100323 // Returns the SVETypeFlags for the given splat operand.
324 unsigned encodeSplatOperand(unsigned SplatIdx) {
325 assert(SplatIdx < 7 && "SplatIdx out of encodable range");
326 return encodeFlag(SplatIdx + 1, "SplatOperandMask");
327 }
328
Sander de Smalenf6ea0262020-04-14 15:31:20 +0100329 // Returns the SVETypeFlags value for the given SVEType.
330 uint64_t encodeTypeFlags(const SVEType &T);
331
Sander de Smalenc5b81462020-03-18 11:07:20 +0000332 /// Emit arm_sve.h.
333 void createHeader(raw_ostream &o);
334
335 /// Emit all the __builtin prototypes and code needed by Sema.
336 void createBuiltins(raw_ostream &o);
337
338 /// Emit all the information needed to map builtin -> LLVM IR intrinsic.
339 void createCodeGenMap(raw_ostream &o);
340
Sander de Smalenc8a5b302020-04-14 15:56:36 +0100341 /// Emit all the range checks for the immediates.
342 void createRangeChecks(raw_ostream &o);
343
Sander de Smalenc5b81462020-03-18 11:07:20 +0000344 /// Create the SVETypeFlags used in CGBuiltins
345 void createTypeFlags(raw_ostream &o);
346
347 /// Create intrinsic and add it to \p Out
348 void createIntrinsic(Record *R, SmallVectorImpl<std::unique_ptr<Intrinsic>> &Out);
Sander de Smalen5087ace2020-03-15 14:29:45 +0000349};
350
351} // end anonymous namespace
352
353
354//===----------------------------------------------------------------------===//
Sander de Smalenc5b81462020-03-18 11:07:20 +0000355// Type implementation
Sander de Smalen8b409ea2020-03-16 10:14:05 +0000356//===----------------------------------------------------------------------===//
Sander de Smalen8b409ea2020-03-16 10:14:05 +0000357
Sander de Smalenc5b81462020-03-18 11:07:20 +0000358std::string SVEType::builtin_str() const {
359 std::string S;
360 if (isVoid())
361 return "v";
362
363 if (isVoidPointer())
364 S += "v";
365 else if (!Float)
366 switch (ElementBitwidth) {
367 case 1: S += "b"; break;
368 case 8: S += "c"; break;
369 case 16: S += "s"; break;
370 case 32: S += "i"; break;
371 case 64: S += "Wi"; break;
372 case 128: S += "LLLi"; break;
373 default: llvm_unreachable("Unhandled case!");
374 }
375 else
376 switch (ElementBitwidth) {
377 case 16: S += "h"; break;
378 case 32: S += "f"; break;
379 case 64: S += "d"; break;
380 default: llvm_unreachable("Unhandled case!");
381 }
382
383 if (!isFloat()) {
384 if ((isChar() || isPointer()) && !isVoidPointer()) {
385 // Make chars and typed pointers explicitly signed.
386 if (Signed)
387 S = "S" + S;
388 else if (!Signed)
389 S = "U" + S;
390 } else if (!isVoidPointer() && !Signed) {
391 S = "U" + S;
392 }
393 }
394
395 // Constant indices are "int", but have the "constant expression" modifier.
396 if (isImmediate()) {
397 assert(!isFloat() && "fp immediates are not supported");
398 S = "I" + S;
399 }
400
401 if (isScalar()) {
402 if (Constant) S += "C";
403 if (Pointer) S += "*";
404 return S;
405 }
406
407 assert(isScalableVector() && "Unsupported type");
408 return "q" + utostr(getNumElements() * NumVectors) + S;
409}
410
Sander de Smalen981f0802020-03-18 15:05:08 +0000411std::string SVEType::str() const {
412 if (isPredicatePattern())
413 return "sv_pattern";
414
415 if (isPrefetchOp())
416 return "sv_prfop";
417
418 std::string S;
419 if (Void)
420 S += "void";
421 else {
422 if (isScalableVector())
423 S += "sv";
424 if (!Signed && !Float)
425 S += "u";
426
427 if (Float)
428 S += "float";
Sander de Smalenaed6bd62020-05-05 09:16:57 +0100429 else if (isScalarPredicate() || isPredicateVector())
Sander de Smalen981f0802020-03-18 15:05:08 +0000430 S += "bool";
431 else
432 S += "int";
433
Sander de Smalenaed6bd62020-05-05 09:16:57 +0100434 if (!isScalarPredicate() && !isPredicateVector())
Sander de Smalen981f0802020-03-18 15:05:08 +0000435 S += utostr(ElementBitwidth);
436 if (!isScalableVector() && isVector())
437 S += "x" + utostr(getNumElements());
438 if (NumVectors > 1)
439 S += "x" + utostr(NumVectors);
440 S += "_t";
441 }
442
443 if (Constant)
444 S += " const";
445 if (Pointer)
446 S += " *";
447
448 return S;
449}
Sander de Smalenc5b81462020-03-18 11:07:20 +0000450void SVEType::applyTypespec() {
451 for (char I : TS) {
452 switch (I) {
453 case 'P':
454 Predicate = true;
Sander de Smalenc5b81462020-03-18 11:07:20 +0000455 break;
456 case 'U':
457 Signed = false;
458 break;
459 case 'c':
460 ElementBitwidth = 8;
461 break;
462 case 's':
463 ElementBitwidth = 16;
464 break;
465 case 'i':
466 ElementBitwidth = 32;
467 break;
468 case 'l':
469 ElementBitwidth = 64;
470 break;
471 case 'h':
472 Float = true;
473 ElementBitwidth = 16;
474 break;
475 case 'f':
476 Float = true;
477 ElementBitwidth = 32;
478 break;
479 case 'd':
480 Float = true;
481 ElementBitwidth = 64;
482 break;
483 default:
484 llvm_unreachable("Unhandled type code!");
485 }
486 }
487 assert(ElementBitwidth != ~0U && "Bad element bitwidth!");
488}
489
490void SVEType::applyModifier(char Mod) {
491 switch (Mod) {
492 case 'v':
493 Void = true;
494 break;
495 case 'd':
496 DefaultType = true;
497 break;
498 case 'c':
499 Constant = true;
500 LLVM_FALLTHROUGH;
501 case 'p':
502 Pointer = true;
503 Bitwidth = ElementBitwidth;
504 NumVectors = 0;
505 break;
Sander de Smalenfc645392020-04-20 14:57:13 +0100506 case 'e':
507 Signed = false;
508 ElementBitwidth /= 2;
509 break;
Sander de Smalen515020c2020-04-20 14:41:58 +0100510 case 'h':
511 ElementBitwidth /= 2;
512 break;
Sander de Smalenfc645392020-04-20 14:57:13 +0100513 case 'q':
514 ElementBitwidth /= 4;
515 break;
516 case 'o':
517 ElementBitwidth *= 4;
518 break;
Sander de Smalenc5b81462020-03-18 11:07:20 +0000519 case 'P':
520 Signed = true;
521 Float = false;
522 Predicate = true;
523 Bitwidth = 16;
524 ElementBitwidth = 1;
525 break;
Sander de Smalen03f419f2020-04-26 12:47:17 +0100526 case 's':
Sander de Smalen41d52662020-04-22 13:58:35 +0100527 case 'a':
528 Bitwidth = ElementBitwidth;
529 NumVectors = 0;
530 break;
Sander de Smalen3cb8b4c2020-05-07 11:22:39 +0100531 case 'R':
532 ElementBitwidth /= 2;
533 NumVectors = 0;
534 break;
Sander de Smalen91cb13f2020-05-05 13:41:05 +0100535 case 'r':
536 ElementBitwidth /= 4;
537 NumVectors = 0;
538 break;
Sander de Smalen1a720d42020-05-01 17:34:42 +0100539 case 'K':
540 Signed = true;
541 Float = false;
542 Bitwidth = ElementBitwidth;
543 NumVectors = 0;
544 break;
Sander de Smalen334931f2020-05-01 21:39:16 +0100545 case 'L':
546 Signed = false;
547 Float = false;
548 Bitwidth = ElementBitwidth;
549 NumVectors = 0;
550 break;
Sander de Smalen515020c2020-04-20 14:41:58 +0100551 case 'u':
552 Predicate = false;
553 Signed = false;
554 Float = false;
555 break;
Andrzej Warzynski72f56582020-04-07 11:09:01 +0100556 case 'x':
557 Predicate = false;
558 Signed = true;
559 Float = false;
560 break;
Sander de Smalenc8a5b302020-04-14 15:56:36 +0100561 case 'i':
562 Predicate = false;
563 Float = false;
564 ElementBitwidth = Bitwidth = 64;
565 NumVectors = 0;
566 Signed = false;
567 Immediate = true;
568 break;
569 case 'I':
570 Predicate = false;
571 Float = false;
572 ElementBitwidth = Bitwidth = 32;
573 NumVectors = 0;
574 Signed = true;
575 Immediate = true;
576 PredicatePattern = true;
577 break;
Sander de Smalen823e2a62020-04-24 11:31:34 +0100578 case 'J':
579 Predicate = false;
580 Float = false;
581 ElementBitwidth = Bitwidth = 32;
582 NumVectors = 0;
583 Signed = true;
584 Immediate = true;
585 PrefetchOp = true;
586 break;
Sander de Smalen662cbaf2020-04-22 15:00:01 +0100587 case 'k':
588 Predicate = false;
589 Signed = true;
590 Float = false;
591 ElementBitwidth = Bitwidth = 32;
592 NumVectors = 0;
593 break;
Sander de Smalen17a68c62020-04-14 13:17:52 +0100594 case 'l':
595 Predicate = false;
596 Signed = true;
597 Float = false;
598 ElementBitwidth = Bitwidth = 64;
599 NumVectors = 0;
600 break;
Sander de Smalen662cbaf2020-04-22 15:00:01 +0100601 case 'm':
602 Predicate = false;
603 Signed = false;
604 Float = false;
605 ElementBitwidth = Bitwidth = 32;
606 NumVectors = 0;
607 break;
608 case 'n':
609 Predicate = false;
610 Signed = false;
611 Float = false;
612 ElementBitwidth = Bitwidth = 64;
613 NumVectors = 0;
614 break;
Sander de Smalen0ddb2032020-04-24 11:31:34 +0100615 case 'w':
616 ElementBitwidth = 64;
617 break;
618 case 'j':
619 ElementBitwidth = Bitwidth = 64;
620 NumVectors = 0;
621 break;
Sander de Smalen334931f2020-05-01 21:39:16 +0100622 case 'f':
623 Signed = false;
624 ElementBitwidth = Bitwidth = 64;
625 NumVectors = 0;
626 break;
627 case 'g':
628 Signed = false;
629 Float = false;
630 ElementBitwidth = 64;
631 break;
Sander de Smalena5e03892020-04-23 10:53:23 +0100632 case 't':
633 Signed = true;
634 Float = false;
635 ElementBitwidth = 32;
636 break;
637 case 'z':
638 Signed = false;
639 Float = false;
640 ElementBitwidth = 32;
641 break;
Sander de Smalen00216442020-04-23 10:45:13 +0100642 case 'O':
643 Predicate = false;
644 Float = true;
645 ElementBitwidth = 16;
646 break;
647 case 'M':
648 Predicate = false;
649 Float = true;
650 ElementBitwidth = 32;
651 break;
652 case 'N':
653 Predicate = false;
654 Float = true;
655 ElementBitwidth = 64;
656 break;
Sander de Smalen42a56bf2020-04-29 11:36:41 +0100657 case 'Q':
658 Constant = true;
659 Pointer = true;
660 Void = true;
661 NumVectors = 0;
662 break;
Sander de Smalen17a68c62020-04-14 13:17:52 +0100663 case 'S':
664 Constant = true;
665 Pointer = true;
666 ElementBitwidth = Bitwidth = 8;
667 NumVectors = 0;
668 Signed = true;
669 break;
670 case 'W':
671 Constant = true;
672 Pointer = true;
673 ElementBitwidth = Bitwidth = 8;
674 NumVectors = 0;
675 Signed = false;
676 break;
677 case 'T':
678 Constant = true;
679 Pointer = true;
680 ElementBitwidth = Bitwidth = 16;
681 NumVectors = 0;
682 Signed = true;
683 break;
684 case 'X':
685 Constant = true;
686 Pointer = true;
687 ElementBitwidth = Bitwidth = 16;
688 NumVectors = 0;
689 Signed = false;
690 break;
691 case 'Y':
692 Constant = true;
693 Pointer = true;
694 ElementBitwidth = Bitwidth = 32;
695 NumVectors = 0;
696 Signed = false;
697 break;
698 case 'U':
699 Constant = true;
700 Pointer = true;
701 ElementBitwidth = Bitwidth = 32;
702 NumVectors = 0;
703 Signed = true;
704 break;
705 case 'A':
706 Pointer = true;
707 ElementBitwidth = Bitwidth = 8;
708 NumVectors = 0;
709 Signed = true;
710 break;
711 case 'B':
712 Pointer = true;
713 ElementBitwidth = Bitwidth = 16;
714 NumVectors = 0;
715 Signed = true;
716 break;
717 case 'C':
718 Pointer = true;
719 ElementBitwidth = Bitwidth = 32;
720 NumVectors = 0;
721 Signed = true;
722 break;
723 case 'D':
724 Pointer = true;
725 ElementBitwidth = Bitwidth = 64;
726 NumVectors = 0;
727 Signed = true;
728 break;
729 case 'E':
730 Pointer = true;
731 ElementBitwidth = Bitwidth = 8;
732 NumVectors = 0;
733 Signed = false;
734 break;
735 case 'F':
736 Pointer = true;
737 ElementBitwidth = Bitwidth = 16;
738 NumVectors = 0;
739 Signed = false;
740 break;
741 case 'G':
742 Pointer = true;
743 ElementBitwidth = Bitwidth = 32;
744 NumVectors = 0;
745 Signed = false;
746 break;
Sander de Smalenc5b81462020-03-18 11:07:20 +0000747 default:
748 llvm_unreachable("Unhandled character!");
749 }
750}
751
752
753//===----------------------------------------------------------------------===//
754// Intrinsic implementation
755//===----------------------------------------------------------------------===//
756
Sander de Smalenf6ea0262020-04-14 15:31:20 +0100757Intrinsic::Intrinsic(StringRef Name, StringRef Proto, uint64_t MergeTy,
758 StringRef MergeSuffix, uint64_t MemoryElementTy,
Sander de Smalenc8a5b302020-04-14 15:56:36 +0100759 StringRef LLVMName, uint64_t Flags,
760 ArrayRef<ImmCheck> Checks, TypeSpec BT, ClassKind Class,
761 SVEEmitter &Emitter, StringRef Guard)
Sander de Smalenf6ea0262020-04-14 15:31:20 +0100762 : Name(Name.str()), LLVMName(LLVMName), Proto(Proto.str()),
763 BaseTypeSpec(BT), Class(Class), Guard(Guard.str()),
Sander de Smalenc8a5b302020-04-14 15:56:36 +0100764 MergeSuffix(MergeSuffix.str()), BaseType(BT, 'd'), Flags(Flags),
765 ImmChecks(Checks.begin(), Checks.end()) {
Sander de Smalenf6ea0262020-04-14 15:31:20 +0100766
767 // Types[0] is the return value.
768 for (unsigned I = 0; I < Proto.size(); ++I) {
769 SVEType T(BaseTypeSpec, Proto[I]);
770 Types.push_back(T);
Sander de Smalenc8a5b302020-04-14 15:56:36 +0100771
772 // Add range checks for immediates
773 if (I > 0) {
774 if (T.isPredicatePattern())
775 ImmChecks.emplace_back(
776 I - 1, Emitter.getEnumValueForImmCheck("ImmCheck0_31"));
Sander de Smalen823e2a62020-04-24 11:31:34 +0100777 else if (T.isPrefetchOp())
778 ImmChecks.emplace_back(
779 I - 1, Emitter.getEnumValueForImmCheck("ImmCheck0_13"));
Sander de Smalenc8a5b302020-04-14 15:56:36 +0100780 }
Sander de Smalenf6ea0262020-04-14 15:31:20 +0100781 }
782
783 // Set flags based on properties
784 this->Flags |= Emitter.encodeTypeFlags(BaseType);
785 this->Flags |= Emitter.encodeMemoryElementType(MemoryElementTy);
786 this->Flags |= Emitter.encodeMergeType(MergeTy);
Sander de Smalen41d52662020-04-22 13:58:35 +0100787 if (hasSplat())
788 this->Flags |= Emitter.encodeSplatOperand(getSplatIdx());
Sander de Smalenf6ea0262020-04-14 15:31:20 +0100789}
790
Sander de Smalenc5b81462020-03-18 11:07:20 +0000791std::string Intrinsic::getBuiltinTypeStr() {
792 std::string S;
793
794 SVEType RetT = getReturnType();
795 // Since the return value must be one type, return a vector type of the
796 // appropriate width which we will bitcast. An exception is made for
797 // returning structs of 2, 3, or 4 vectors which are returned in a sret-like
798 // fashion, storing them to a pointer arg.
799 if (RetT.getNumVectors() > 1) {
800 S += "vv*"; // void result with void* first argument
801 } else
802 S += RetT.builtin_str();
803
804 for (unsigned I = 0; I < getNumParams(); ++I)
805 S += getParamType(I).builtin_str();
806
807 return S;
808}
809
810std::string Intrinsic::replaceTemplatedArgs(std::string Name, TypeSpec TS,
811 std::string Proto) const {
812 std::string Ret = Name;
813 while (Ret.find('{') != std::string::npos) {
814 size_t Pos = Ret.find('{');
815 size_t End = Ret.find('}');
816 unsigned NumChars = End - Pos + 1;
817 assert(NumChars == 3 && "Unexpected template argument");
818
819 SVEType T;
820 char C = Ret[Pos+1];
821 switch(C) {
822 default:
823 llvm_unreachable("Unknown predication specifier");
824 case 'd':
825 T = SVEType(TS, 'd');
826 break;
827 case '0':
828 case '1':
829 case '2':
830 case '3':
831 T = SVEType(TS, Proto[C - '0']);
832 break;
833 }
834
835 // Replace templated arg with the right suffix (e.g. u32)
836 std::string TypeCode;
837 if (T.isInteger())
838 TypeCode = T.isSigned() ? 's' : 'u';
839 else if (T.isPredicateVector())
840 TypeCode = 'b';
841 else
842 TypeCode = 'f';
843 Ret.replace(Pos, NumChars, TypeCode + utostr(T.getElementSizeInBits()));
844 }
845
846 return Ret;
847}
848
Sander de Smalenc5b81462020-03-18 11:07:20 +0000849std::string Intrinsic::mangleName(ClassKind LocalCK) const {
850 std::string S = getName();
851
852 if (LocalCK == ClassG) {
853 // Remove the square brackets and everything in between.
854 while (S.find("[") != std::string::npos) {
855 auto Start = S.find("[");
856 auto End = S.find(']');
857 S.erase(Start, (End-Start)+1);
858 }
859 } else {
860 // Remove the square brackets.
861 while (S.find("[") != std::string::npos) {
862 auto BrPos = S.find('[');
863 if (BrPos != std::string::npos)
864 S.erase(BrPos, 1);
865 BrPos = S.find(']');
866 if (BrPos != std::string::npos)
867 S.erase(BrPos, 1);
868 }
869 }
870
871 // Replace all {d} like expressions with e.g. 'u32'
872 return replaceTemplatedArgs(S, getBaseTypeSpec(), getProto()) +
873 getMergeSuffix();
874}
875
876void Intrinsic::emitIntrinsic(raw_ostream &OS) const {
877 // Use the preprocessor to
878 if (getClassKind() != ClassG || getProto().size() <= 1) {
879 OS << "#define " << mangleName(getClassKind())
880 << "(...) __builtin_sve_" << mangleName(ClassS)
881 << "(__VA_ARGS__)\n";
882 } else {
Sander de Smalen981f0802020-03-18 15:05:08 +0000883 std::string FullName = mangleName(ClassS);
884 std::string ProtoName = mangleName(ClassG);
885
886 OS << "__aio __attribute__((__clang_arm_builtin_alias("
887 << "__builtin_sve_" << FullName << ")))\n";
888
889 OS << getTypes()[0].str() << " " << ProtoName << "(";
890 for (unsigned I = 0; I < getTypes().size() - 1; ++I) {
891 if (I != 0)
892 OS << ", ";
893 OS << getTypes()[I + 1].str();
894 }
895 OS << ");\n";
Sander de Smalenc5b81462020-03-18 11:07:20 +0000896 }
897}
898
899//===----------------------------------------------------------------------===//
900// SVEEmitter implementation
901//===----------------------------------------------------------------------===//
Sander de Smalenf6ea0262020-04-14 15:31:20 +0100902uint64_t SVEEmitter::encodeTypeFlags(const SVEType &T) {
903 if (T.isFloat()) {
904 switch (T.getElementSizeInBits()) {
905 case 16:
906 return encodeEltType("EltTyFloat16");
907 case 32:
908 return encodeEltType("EltTyFloat32");
909 case 64:
910 return encodeEltType("EltTyFloat64");
911 default:
912 llvm_unreachable("Unhandled float element bitwidth!");
913 }
914 }
915
916 if (T.isPredicateVector()) {
917 switch (T.getElementSizeInBits()) {
918 case 8:
919 return encodeEltType("EltTyBool8");
920 case 16:
921 return encodeEltType("EltTyBool16");
922 case 32:
923 return encodeEltType("EltTyBool32");
924 case 64:
925 return encodeEltType("EltTyBool64");
926 default:
927 llvm_unreachable("Unhandled predicate element bitwidth!");
928 }
929 }
930
931 switch (T.getElementSizeInBits()) {
932 case 8:
933 return encodeEltType("EltTyInt8");
934 case 16:
935 return encodeEltType("EltTyInt16");
936 case 32:
937 return encodeEltType("EltTyInt32");
938 case 64:
939 return encodeEltType("EltTyInt64");
940 default:
941 llvm_unreachable("Unhandled integer element bitwidth!");
942 }
943}
944
Sander de Smalenc5b81462020-03-18 11:07:20 +0000945void SVEEmitter::createIntrinsic(
946 Record *R, SmallVectorImpl<std::unique_ptr<Intrinsic>> &Out) {
947 StringRef Name = R->getValueAsString("Name");
948 StringRef Proto = R->getValueAsString("Prototype");
949 StringRef Types = R->getValueAsString("Types");
950 StringRef Guard = R->getValueAsString("ArchGuard");
951 StringRef LLVMName = R->getValueAsString("LLVMIntrinsic");
Sander de Smalenf6ea0262020-04-14 15:31:20 +0100952 uint64_t Merge = R->getValueAsInt("Merge");
953 StringRef MergeSuffix = R->getValueAsString("MergeSuffix");
954 uint64_t MemEltType = R->getValueAsInt("MemEltType");
Sander de Smalenc5b81462020-03-18 11:07:20 +0000955 std::vector<Record*> FlagsList = R->getValueAsListOfDefs("Flags");
Sander de Smalenc8a5b302020-04-14 15:56:36 +0100956 std::vector<Record*> ImmCheckList = R->getValueAsListOfDefs("ImmChecks");
Sander de Smalenc5b81462020-03-18 11:07:20 +0000957
958 int64_t Flags = 0;
959 for (auto FlagRec : FlagsList)
960 Flags |= FlagRec->getValueAsInt("Value");
Sander de Smalenc5b81462020-03-18 11:07:20 +0000961
Sander de Smalen662cbaf2020-04-22 15:00:01 +0100962 // Create a dummy TypeSpec for non-overloaded builtins.
963 if (Types.empty()) {
964 assert((Flags & getEnumValueForFlag("IsOverloadNone")) &&
965 "Expect TypeSpec for overloaded builtin!");
966 Types = "i";
967 }
968
Sander de Smalenc5b81462020-03-18 11:07:20 +0000969 // Extract type specs from string
970 SmallVector<TypeSpec, 8> TypeSpecs;
971 TypeSpec Acc;
972 for (char I : Types) {
973 Acc.push_back(I);
974 if (islower(I)) {
975 TypeSpecs.push_back(TypeSpec(Acc));
976 Acc.clear();
977 }
978 }
979
980 // Remove duplicate type specs.
Benjamin Kramer4065e922020-03-28 19:19:55 +0100981 llvm::sort(TypeSpecs);
Sander de Smalenc5b81462020-03-18 11:07:20 +0000982 TypeSpecs.erase(std::unique(TypeSpecs.begin(), TypeSpecs.end()),
983 TypeSpecs.end());
984
985 // Create an Intrinsic for each type spec.
986 for (auto TS : TypeSpecs) {
Sander de Smalenc8a5b302020-04-14 15:56:36 +0100987 // Collate a list of range/option checks for the immediates.
988 SmallVector<ImmCheck, 2> ImmChecks;
989 for (auto *R : ImmCheckList) {
Christopher Tetreault464a0692020-04-15 15:16:17 -0700990 int64_t Arg = R->getValueAsInt("Arg");
991 int64_t EltSizeArg = R->getValueAsInt("EltSizeArg");
992 int64_t Kind = R->getValueAsDef("Kind")->getValueAsInt("Value");
993 assert(Arg >= 0 && Kind >= 0 && "Arg and Kind must be nonnegative");
Sander de Smalenc8a5b302020-04-14 15:56:36 +0100994
995 unsigned ElementSizeInBits = 0;
996 if (EltSizeArg >= 0)
997 ElementSizeInBits =
998 SVEType(TS, Proto[EltSizeArg + /* offset by return arg */ 1])
999 .getElementSizeInBits();
1000 ImmChecks.push_back(ImmCheck(Arg, Kind, ElementSizeInBits));
1001 }
1002
1003 Out.push_back(std::make_unique<Intrinsic>(
1004 Name, Proto, Merge, MergeSuffix, MemEltType, LLVMName, Flags, ImmChecks,
1005 TS, ClassS, *this, Guard));
Sander de Smalen981f0802020-03-18 15:05:08 +00001006
1007 // Also generate the short-form (e.g. svadd_m) for the given type-spec.
1008 if (Intrinsic::isOverloadedIntrinsic(Name))
Sander de Smalenc8a5b302020-04-14 15:56:36 +01001009 Out.push_back(std::make_unique<Intrinsic>(
1010 Name, Proto, Merge, MergeSuffix, MemEltType, LLVMName, Flags,
1011 ImmChecks, TS, ClassG, *this, Guard));
Sander de Smalenc5b81462020-03-18 11:07:20 +00001012 }
1013}
1014
1015void SVEEmitter::createHeader(raw_ostream &OS) {
Sander de Smalen5087ace2020-03-15 14:29:45 +00001016 OS << "/*===---- arm_sve.h - ARM SVE intrinsics "
1017 "-----------------------------------===\n"
1018 " *\n"
1019 " *\n"
1020 " * Part of the LLVM Project, under the Apache License v2.0 with LLVM "
1021 "Exceptions.\n"
1022 " * See https://llvm.org/LICENSE.txt for license information.\n"
1023 " * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception\n"
1024 " *\n"
1025 " *===-----------------------------------------------------------------"
1026 "------===\n"
1027 " */\n\n";
1028
1029 OS << "#ifndef __ARM_SVE_H\n";
1030 OS << "#define __ARM_SVE_H\n\n";
1031
1032 OS << "#if !defined(__ARM_FEATURE_SVE)\n";
1033 OS << "#error \"SVE support not enabled\"\n";
1034 OS << "#else\n\n";
1035
Sander de Smalen5ba32902020-05-05 13:04:14 +01001036 OS << "#if !defined(__LITTLE_ENDIAN__)\n";
1037 OS << "#error \"Big endian is currently not supported for arm_sve.h\"\n";
1038 OS << "#endif\n";
1039
Sander de Smalen5087ace2020-03-15 14:29:45 +00001040 OS << "#include <stdint.h>\n\n";
Sander de Smalenc5b81462020-03-18 11:07:20 +00001041 OS << "#ifdef __cplusplus\n";
1042 OS << "extern \"C\" {\n";
1043 OS << "#else\n";
Sander de Smalen5087ace2020-03-15 14:29:45 +00001044 OS << "#include <stdbool.h>\n";
1045 OS << "#endif\n\n";
1046
1047 OS << "typedef __fp16 float16_t;\n";
1048 OS << "typedef float float32_t;\n";
1049 OS << "typedef double float64_t;\n";
1050 OS << "typedef bool bool_t;\n\n";
1051
1052 OS << "typedef __SVInt8_t svint8_t;\n";
1053 OS << "typedef __SVInt16_t svint16_t;\n";
1054 OS << "typedef __SVInt32_t svint32_t;\n";
1055 OS << "typedef __SVInt64_t svint64_t;\n";
1056 OS << "typedef __SVUint8_t svuint8_t;\n";
1057 OS << "typedef __SVUint16_t svuint16_t;\n";
1058 OS << "typedef __SVUint32_t svuint32_t;\n";
1059 OS << "typedef __SVUint64_t svuint64_t;\n";
1060 OS << "typedef __SVFloat16_t svfloat16_t;\n";
1061 OS << "typedef __SVFloat32_t svfloat32_t;\n";
1062 OS << "typedef __SVFloat64_t svfloat64_t;\n";
1063 OS << "typedef __SVBool_t svbool_t;\n\n";
1064
Sander de Smalenc8a5b302020-04-14 15:56:36 +01001065 OS << "typedef enum\n";
1066 OS << "{\n";
1067 OS << " SV_POW2 = 0,\n";
1068 OS << " SV_VL1 = 1,\n";
1069 OS << " SV_VL2 = 2,\n";
1070 OS << " SV_VL3 = 3,\n";
1071 OS << " SV_VL4 = 4,\n";
1072 OS << " SV_VL5 = 5,\n";
1073 OS << " SV_VL6 = 6,\n";
1074 OS << " SV_VL7 = 7,\n";
1075 OS << " SV_VL8 = 8,\n";
1076 OS << " SV_VL16 = 9,\n";
1077 OS << " SV_VL32 = 10,\n";
1078 OS << " SV_VL64 = 11,\n";
1079 OS << " SV_VL128 = 12,\n";
1080 OS << " SV_VL256 = 13,\n";
1081 OS << " SV_MUL4 = 29,\n";
1082 OS << " SV_MUL3 = 30,\n";
1083 OS << " SV_ALL = 31\n";
1084 OS << "} sv_pattern;\n\n";
1085
Sander de Smalen823e2a62020-04-24 11:31:34 +01001086 OS << "typedef enum\n";
1087 OS << "{\n";
1088 OS << " SV_PLDL1KEEP = 0,\n";
1089 OS << " SV_PLDL1STRM = 1,\n";
1090 OS << " SV_PLDL2KEEP = 2,\n";
1091 OS << " SV_PLDL2STRM = 3,\n";
1092 OS << " SV_PLDL3KEEP = 4,\n";
1093 OS << " SV_PLDL3STRM = 5,\n";
1094 OS << " SV_PSTL1KEEP = 8,\n";
1095 OS << " SV_PSTL1STRM = 9,\n";
1096 OS << " SV_PSTL2KEEP = 10,\n";
1097 OS << " SV_PSTL2STRM = 11,\n";
1098 OS << " SV_PSTL3KEEP = 12,\n";
1099 OS << " SV_PSTL3STRM = 13\n";
1100 OS << "} sv_prfop;\n\n";
1101
Sander de Smalen981f0802020-03-18 15:05:08 +00001102 OS << "/* Function attributes */\n";
1103 OS << "#define __aio static inline __attribute__((__always_inline__, "
1104 "__nodebug__, __overloadable__))\n\n";
1105
Sander de Smalen5ba32902020-05-05 13:04:14 +01001106 // Add reinterpret functions.
1107 for (auto ShortForm : { false, true } )
1108 for (const ReinterpretTypeInfo &From : Reinterprets)
1109 for (const ReinterpretTypeInfo &To : Reinterprets) {
1110 if (ShortForm) {
1111 OS << "__aio " << From.Type << " svreinterpret_" << From.Suffix;
1112 OS << "(" << To.Type << " op) {\n";
1113 OS << " return __builtin_sve_reinterpret_" << From.Suffix << "_"
1114 << To.Suffix << "(op);\n";
1115 OS << "}\n\n";
1116 } else
1117 OS << "#define svreinterpret_" << From.Suffix << "_" << To.Suffix
1118 << "(...) __builtin_sve_reinterpret_" << From.Suffix << "_"
1119 << To.Suffix << "(__VA_ARGS__)\n";
1120 }
1121
Sander de Smalenc5b81462020-03-18 11:07:20 +00001122 SmallVector<std::unique_ptr<Intrinsic>, 128> Defs;
1123 std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst");
1124 for (auto *R : RV)
1125 createIntrinsic(R, Defs);
Sander de Smalen5087ace2020-03-15 14:29:45 +00001126
Sander de Smalenc5b81462020-03-18 11:07:20 +00001127 // Sort intrinsics in header file by following order/priority:
1128 // - Architectural guard (i.e. does it require SVE2 or SVE2_AES)
1129 // - Class (is intrinsic overloaded or not)
1130 // - Intrinsic name
1131 std::stable_sort(
1132 Defs.begin(), Defs.end(), [](const std::unique_ptr<Intrinsic> &A,
1133 const std::unique_ptr<Intrinsic> &B) {
Eric Fiselieraf2968e2020-04-16 18:35:31 -04001134 auto ToTuple = [](const std::unique_ptr<Intrinsic> &I) {
1135 return std::make_tuple(I->getGuard(), (unsigned)I->getClassKind(), I->getName());
1136 };
1137 return ToTuple(A) < ToTuple(B);
Sander de Smalenc5b81462020-03-18 11:07:20 +00001138 });
1139
1140 StringRef InGuard = "";
1141 for (auto &I : Defs) {
1142 // Emit #endif/#if pair if needed.
1143 if (I->getGuard() != InGuard) {
1144 if (!InGuard.empty())
1145 OS << "#endif //" << InGuard << "\n";
1146 InGuard = I->getGuard();
1147 if (!InGuard.empty())
1148 OS << "\n#if " << InGuard << "\n";
1149 }
1150
1151 // Actually emit the intrinsic declaration.
1152 I->emitIntrinsic(OS);
1153 }
1154
1155 if (!InGuard.empty())
1156 OS << "#endif //" << InGuard << "\n";
1157
Sander de Smalen00216442020-04-23 10:45:13 +01001158 OS << "#if defined(__ARM_FEATURE_SVE2)\n";
1159 OS << "#define svcvtnt_f16_x svcvtnt_f16_m\n";
1160 OS << "#define svcvtnt_f16_f32_x svcvtnt_f16_f32_m\n";
1161 OS << "#define svcvtnt_f32_x svcvtnt_f32_m\n";
1162 OS << "#define svcvtnt_f32_f64_x svcvtnt_f32_f64_m\n\n";
1163
1164 OS << "#define svcvtxnt_f32_x svcvtxnt_f32_m\n";
1165 OS << "#define svcvtxnt_f32_f64_x svcvtxnt_f32_f64_m\n\n";
1166
1167 OS << "#endif /*__ARM_FEATURE_SVE2 */\n\n";
1168
Sander de Smalenc5b81462020-03-18 11:07:20 +00001169 OS << "#ifdef __cplusplus\n";
1170 OS << "} // extern \"C\"\n";
1171 OS << "#endif\n\n";
1172 OS << "#endif /*__ARM_FEATURE_SVE */\n\n";
Sander de Smalen5087ace2020-03-15 14:29:45 +00001173 OS << "#endif /* __ARM_SVE_H */\n";
1174}
1175
Sander de Smalenc5b81462020-03-18 11:07:20 +00001176void SVEEmitter::createBuiltins(raw_ostream &OS) {
1177 std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst");
1178 SmallVector<std::unique_ptr<Intrinsic>, 128> Defs;
1179 for (auto *R : RV)
1180 createIntrinsic(R, Defs);
1181
1182 // The mappings must be sorted based on BuiltinID.
1183 llvm::sort(Defs, [](const std::unique_ptr<Intrinsic> &A,
1184 const std::unique_ptr<Intrinsic> &B) {
1185 return A->getMangledName() < B->getMangledName();
1186 });
1187
1188 OS << "#ifdef GET_SVE_BUILTINS\n";
1189 for (auto &Def : Defs) {
1190 // Only create BUILTINs for non-overloaded intrinsics, as overloaded
1191 // declarations only live in the header file.
1192 if (Def->getClassKind() != ClassG)
1193 OS << "BUILTIN(__builtin_sve_" << Def->getMangledName() << ", \""
1194 << Def->getBuiltinTypeStr() << "\", \"n\")\n";
1195 }
Sander de Smalen5ba32902020-05-05 13:04:14 +01001196
1197 // Add reinterpret builtins
1198 for (const ReinterpretTypeInfo &From : Reinterprets)
1199 for (const ReinterpretTypeInfo &To : Reinterprets)
1200 OS << "BUILTIN(__builtin_sve_reinterpret_" << From.Suffix << "_"
1201 << To.Suffix << +", \"" << From.BuiltinType << To.BuiltinType
1202 << "\", \"n\")\n";
1203
Sander de Smalenc5b81462020-03-18 11:07:20 +00001204 OS << "#endif\n\n";
Sander de Smalen5ba32902020-05-05 13:04:14 +01001205 }
Sander de Smalenc5b81462020-03-18 11:07:20 +00001206
1207void SVEEmitter::createCodeGenMap(raw_ostream &OS) {
1208 std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst");
1209 SmallVector<std::unique_ptr<Intrinsic>, 128> Defs;
1210 for (auto *R : RV)
1211 createIntrinsic(R, Defs);
1212
1213 // The mappings must be sorted based on BuiltinID.
1214 llvm::sort(Defs, [](const std::unique_ptr<Intrinsic> &A,
1215 const std::unique_ptr<Intrinsic> &B) {
1216 return A->getMangledName() < B->getMangledName();
1217 });
1218
1219 OS << "#ifdef GET_SVE_LLVM_INTRINSIC_MAP\n";
1220 for (auto &Def : Defs) {
1221 // Builtins only exist for non-overloaded intrinsics, overloaded
1222 // declarations only live in the header file.
1223 if (Def->getClassKind() == ClassG)
1224 continue;
1225
Sander de Smalenf6ea0262020-04-14 15:31:20 +01001226 uint64_t Flags = Def->getFlags();
Sander de Smalenc5b81462020-03-18 11:07:20 +00001227 auto FlagString = std::to_string(Flags);
1228
1229 std::string LLVMName = Def->getLLVMName();
1230 std::string Builtin = Def->getMangledName();
1231 if (!LLVMName.empty())
1232 OS << "SVEMAP1(" << Builtin << ", " << LLVMName << ", " << FlagString
1233 << "),\n";
1234 else
1235 OS << "SVEMAP2(" << Builtin << ", " << FlagString << "),\n";
1236 }
1237 OS << "#endif\n\n";
1238}
1239
Sander de Smalenc8a5b302020-04-14 15:56:36 +01001240void SVEEmitter::createRangeChecks(raw_ostream &OS) {
1241 std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst");
1242 SmallVector<std::unique_ptr<Intrinsic>, 128> Defs;
1243 for (auto *R : RV)
1244 createIntrinsic(R, Defs);
1245
1246 // The mappings must be sorted based on BuiltinID.
1247 llvm::sort(Defs, [](const std::unique_ptr<Intrinsic> &A,
1248 const std::unique_ptr<Intrinsic> &B) {
1249 return A->getMangledName() < B->getMangledName();
1250 });
1251
1252
1253 OS << "#ifdef GET_SVE_IMMEDIATE_CHECK\n";
1254
1255 // Ensure these are only emitted once.
1256 std::set<std::string> Emitted;
1257
1258 for (auto &Def : Defs) {
1259 if (Emitted.find(Def->getMangledName()) != Emitted.end() ||
1260 Def->getImmChecks().empty())
1261 continue;
1262
1263 OS << "case SVE::BI__builtin_sve_" << Def->getMangledName() << ":\n";
1264 for (auto &Check : Def->getImmChecks())
1265 OS << "ImmChecks.push_back(std::make_tuple(" << Check.getArg() << ", "
1266 << Check.getKind() << ", " << Check.getElementSizeInBits() << "));\n";
1267 OS << " break;\n";
1268
1269 Emitted.insert(Def->getMangledName());
1270 }
1271
1272 OS << "#endif\n\n";
1273}
1274
Sander de Smalenc5b81462020-03-18 11:07:20 +00001275/// Create the SVETypeFlags used in CGBuiltins
1276void SVEEmitter::createTypeFlags(raw_ostream &OS) {
1277 OS << "#ifdef LLVM_GET_SVE_TYPEFLAGS\n";
1278 for (auto &KV : FlagTypes)
1279 OS << "const uint64_t " << KV.getKey() << " = " << KV.getValue() << ";\n";
1280 OS << "#endif\n\n";
1281
1282 OS << "#ifdef LLVM_GET_SVE_ELTTYPES\n";
1283 for (auto &KV : EltTypes)
1284 OS << " " << KV.getKey() << " = " << KV.getValue() << ",\n";
1285 OS << "#endif\n\n";
1286
1287 OS << "#ifdef LLVM_GET_SVE_MEMELTTYPES\n";
1288 for (auto &KV : MemEltTypes)
1289 OS << " " << KV.getKey() << " = " << KV.getValue() << ",\n";
1290 OS << "#endif\n\n";
Sander de Smalenf6ea0262020-04-14 15:31:20 +01001291
1292 OS << "#ifdef LLVM_GET_SVE_MERGETYPES\n";
1293 for (auto &KV : MergeTypes)
1294 OS << " " << KV.getKey() << " = " << KV.getValue() << ",\n";
1295 OS << "#endif\n\n";
Sander de Smalenc8a5b302020-04-14 15:56:36 +01001296
1297 OS << "#ifdef LLVM_GET_SVE_IMMCHECKTYPES\n";
1298 for (auto &KV : ImmCheckTypes)
1299 OS << " " << KV.getKey() << " = " << KV.getValue() << ",\n";
1300 OS << "#endif\n\n";
Sander de Smalenc5b81462020-03-18 11:07:20 +00001301}
1302
Sander de Smalen5087ace2020-03-15 14:29:45 +00001303namespace clang {
1304void EmitSveHeader(RecordKeeper &Records, raw_ostream &OS) {
Sander de Smalenc5b81462020-03-18 11:07:20 +00001305 SVEEmitter(Records).createHeader(OS);
1306}
1307
1308void EmitSveBuiltins(RecordKeeper &Records, raw_ostream &OS) {
1309 SVEEmitter(Records).createBuiltins(OS);
1310}
1311
1312void EmitSveBuiltinCG(RecordKeeper &Records, raw_ostream &OS) {
1313 SVEEmitter(Records).createCodeGenMap(OS);
1314}
Sander de Smalenc8a5b302020-04-14 15:56:36 +01001315
1316void EmitSveRangeChecks(RecordKeeper &Records, raw_ostream &OS) {
1317 SVEEmitter(Records).createRangeChecks(OS);
1318}
1319
Sander de Smalenc5b81462020-03-18 11:07:20 +00001320void EmitSveTypeFlags(RecordKeeper &Records, raw_ostream &OS) {
1321 SVEEmitter(Records).createTypeFlags(OS);
Sander de Smalen5087ace2020-03-15 14:29:45 +00001322}
1323
1324} // End namespace clang