blob: 79258a8fbbf2121161e80a52e68907dfa1d6d56f [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>
36
37using namespace llvm;
38
Sander de Smalenc5b81462020-03-18 11:07:20 +000039enum ClassKind {
40 ClassNone,
41 ClassS, // signed/unsigned, e.g., "_s8", "_u8" suffix
42 ClassG, // Overloaded name without type suffix
43};
44
45using TypeSpec = std::string;
Sander de Smalen5087ace2020-03-15 14:29:45 +000046
47namespace {
48
Sander de Smalenc8a5b302020-04-14 15:56:36 +010049class ImmCheck {
50 unsigned Arg;
51 unsigned Kind;
52 unsigned ElementSizeInBits;
53
54public:
55 ImmCheck(unsigned Arg, unsigned Kind, unsigned ElementSizeInBits = 0)
56 : Arg(Arg), Kind(Kind), ElementSizeInBits(ElementSizeInBits) {}
57 ImmCheck(const ImmCheck &Other) = default;
58 ~ImmCheck() = default;
59
60 unsigned getArg() const { return Arg; }
61 unsigned getKind() const { return Kind; }
62 unsigned getElementSizeInBits() const { return ElementSizeInBits; }
63};
64
Sander de Smalenc5b81462020-03-18 11:07:20 +000065class SVEType {
66 TypeSpec TS;
67 bool Float, Signed, Immediate, Void, Constant, Pointer;
68 bool DefaultType, IsScalable, Predicate, PredicatePattern, PrefetchOp;
69 unsigned Bitwidth, ElementBitwidth, NumVectors;
70
Sander de Smalen8b409ea2020-03-16 10:14:05 +000071public:
Sander de Smalenc5b81462020-03-18 11:07:20 +000072 SVEType() : SVEType(TypeSpec(), 'v') {}
73
74 SVEType(TypeSpec TS, char CharMod)
75 : TS(TS), Float(false), Signed(true), Immediate(false), Void(false),
76 Constant(false), Pointer(false), DefaultType(false), IsScalable(true),
77 Predicate(false), PredicatePattern(false), PrefetchOp(false),
78 Bitwidth(128), ElementBitwidth(~0U), NumVectors(1) {
79 if (!TS.empty())
80 applyTypespec();
81 applyModifier(CharMod);
82 }
83
Sander de Smalenc5b81462020-03-18 11:07:20 +000084 bool isPointer() const { return Pointer; }
85 bool isVoidPointer() const { return Pointer && Void; }
86 bool isSigned() const { return Signed; }
87 bool isImmediate() const { return Immediate; }
88 bool isScalar() const { return NumVectors == 0; }
89 bool isVector() const { return NumVectors > 0; }
90 bool isScalableVector() const { return isVector() && IsScalable; }
91 bool isChar() const { return ElementBitwidth == 8; }
92 bool isVoid() const { return Void & !Pointer; }
93 bool isDefault() const { return DefaultType; }
94 bool isFloat() const { return Float; }
95 bool isInteger() const { return !Float && !Predicate; }
96 bool isScalarPredicate() const { return !Float && ElementBitwidth == 1; }
97 bool isPredicateVector() const { return Predicate; }
98 bool isPredicatePattern() const { return PredicatePattern; }
99 bool isPrefetchOp() const { return PrefetchOp; }
100 bool isConstant() const { return Constant; }
101 unsigned getElementSizeInBits() const { return ElementBitwidth; }
102 unsigned getNumVectors() const { return NumVectors; }
103
104 unsigned getNumElements() const {
105 assert(ElementBitwidth != ~0U);
106 return Bitwidth / ElementBitwidth;
107 }
108 unsigned getSizeInBits() const {
109 return Bitwidth;
110 }
111
112 /// Return the string representation of a type, which is an encoded
113 /// string for passing to the BUILTIN() macro in Builtins.def.
114 std::string builtin_str() const;
115
Sander de Smalen981f0802020-03-18 15:05:08 +0000116 /// Return the C/C++ string representation of a type for use in the
117 /// arm_sve.h header file.
118 std::string str() const;
119
Sander de Smalenc5b81462020-03-18 11:07:20 +0000120private:
121 /// Creates the type based on the typespec string in TS.
122 void applyTypespec();
123
124 /// Applies a prototype modifier to the type.
125 void applyModifier(char Mod);
126};
127
128
129class SVEEmitter;
130
131/// The main grunt class. This represents an instantiation of an intrinsic with
132/// a particular typespec and prototype.
133class Intrinsic {
134 /// The unmangled name.
135 std::string Name;
136
137 /// The name of the corresponding LLVM IR intrinsic.
138 std::string LLVMName;
139
140 /// Intrinsic prototype.
141 std::string Proto;
142
143 /// The base type spec for this intrinsic.
144 TypeSpec BaseTypeSpec;
145
146 /// The base class kind. Most intrinsics use ClassS, which has full type
147 /// info for integers (_s32/_u32), or ClassG which is used for overloaded
148 /// intrinsics.
149 ClassKind Class;
150
151 /// The architectural #ifdef guard.
152 std::string Guard;
153
Sander de Smalenf6ea0262020-04-14 15:31:20 +0100154 // The merge suffix such as _m, _x or _z.
155 std::string MergeSuffix;
156
Sander de Smalenc5b81462020-03-18 11:07:20 +0000157 /// The types of return value [0] and parameters [1..].
158 std::vector<SVEType> Types;
159
160 /// The "base type", which is VarType('d', BaseTypeSpec).
161 SVEType BaseType;
162
Sander de Smalenf6ea0262020-04-14 15:31:20 +0100163 uint64_t Flags;
Sander de Smalenc5b81462020-03-18 11:07:20 +0000164
Sander de Smalenc8a5b302020-04-14 15:56:36 +0100165 SmallVector<ImmCheck, 2> ImmChecks;
166
Sander de Smalenc5b81462020-03-18 11:07:20 +0000167public:
Sander de Smalenf6ea0262020-04-14 15:31:20 +0100168 Intrinsic(StringRef Name, StringRef Proto, uint64_t MergeTy,
169 StringRef MergeSuffix, uint64_t MemoryElementTy, StringRef LLVMName,
Sander de Smalenc8a5b302020-04-14 15:56:36 +0100170 uint64_t Flags, ArrayRef<ImmCheck> ImmChecks, TypeSpec BT,
171 ClassKind Class, SVEEmitter &Emitter, StringRef Guard);
Sander de Smalenc5b81462020-03-18 11:07:20 +0000172
173 ~Intrinsic()=default;
174
175 std::string getName() const { return Name; }
176 std::string getLLVMName() const { return LLVMName; }
177 std::string getProto() const { return Proto; }
178 TypeSpec getBaseTypeSpec() const { return BaseTypeSpec; }
179 SVEType getBaseType() const { return BaseType; }
180
181 StringRef getGuard() const { return Guard; }
182 ClassKind getClassKind() const { return Class; }
Sander de Smalenc5b81462020-03-18 11:07:20 +0000183
184 SVEType getReturnType() const { return Types[0]; }
185 ArrayRef<SVEType> getTypes() const { return Types; }
186 SVEType getParamType(unsigned I) const { return Types[I + 1]; }
187 unsigned getNumParams() const { return Proto.size() - 1; }
188
Sander de Smalenf6ea0262020-04-14 15:31:20 +0100189 uint64_t getFlags() const { return Flags; }
Sander de Smalenc5b81462020-03-18 11:07:20 +0000190 bool isFlagSet(uint64_t Flag) const { return Flags & Flag;}
191
Sander de Smalenc8a5b302020-04-14 15:56:36 +0100192 ArrayRef<ImmCheck> getImmChecks() const { return ImmChecks; }
193
Sander de Smalenc5b81462020-03-18 11:07:20 +0000194 /// Return the type string for a BUILTIN() macro in Builtins.def.
195 std::string getBuiltinTypeStr();
196
197 /// Return the name, mangled with type information. The name is mangled for
198 /// ClassS, so will add type suffixes such as _u32/_s32.
199 std::string getMangledName() const { return mangleName(ClassS); }
200
201 /// Returns true if the intrinsic is overloaded, in that it should also generate
202 /// a short form without the type-specifiers, e.g. 'svld1(..)' instead of
203 /// 'svld1_u32(..)'.
204 static bool isOverloadedIntrinsic(StringRef Name) {
205 auto BrOpen = Name.find("[");
206 auto BrClose = Name.find(']');
207 return BrOpen != std::string::npos && BrClose != std::string::npos;
208 }
209
210 /// Emits the intrinsic declaration to the ostream.
211 void emitIntrinsic(raw_ostream &OS) const;
212
213private:
Sander de Smalenf6ea0262020-04-14 15:31:20 +0100214 std::string getMergeSuffix() const { return MergeSuffix; }
Sander de Smalenc5b81462020-03-18 11:07:20 +0000215 std::string mangleName(ClassKind LocalCK) const;
216 std::string replaceTemplatedArgs(std::string Name, TypeSpec TS,
217 std::string Proto) const;
218};
219
220class SVEEmitter {
221private:
222 RecordKeeper &Records;
223 llvm::StringMap<uint64_t> EltTypes;
224 llvm::StringMap<uint64_t> MemEltTypes;
225 llvm::StringMap<uint64_t> FlagTypes;
Sander de Smalenf6ea0262020-04-14 15:31:20 +0100226 llvm::StringMap<uint64_t> MergeTypes;
Sander de Smalenc8a5b302020-04-14 15:56:36 +0100227 llvm::StringMap<uint64_t> ImmCheckTypes;
Sander de Smalenc5b81462020-03-18 11:07:20 +0000228
Sander de Smalenc5b81462020-03-18 11:07:20 +0000229public:
230 SVEEmitter(RecordKeeper &R) : Records(R) {
231 for (auto *RV : Records.getAllDerivedDefinitions("EltType"))
232 EltTypes[RV->getNameInitAsString()] = RV->getValueAsInt("Value");
233 for (auto *RV : Records.getAllDerivedDefinitions("MemEltType"))
234 MemEltTypes[RV->getNameInitAsString()] = RV->getValueAsInt("Value");
235 for (auto *RV : Records.getAllDerivedDefinitions("FlagType"))
236 FlagTypes[RV->getNameInitAsString()] = RV->getValueAsInt("Value");
Sander de Smalenf6ea0262020-04-14 15:31:20 +0100237 for (auto *RV : Records.getAllDerivedDefinitions("MergeType"))
238 MergeTypes[RV->getNameInitAsString()] = RV->getValueAsInt("Value");
Sander de Smalenc8a5b302020-04-14 15:56:36 +0100239 for (auto *RV : Records.getAllDerivedDefinitions("ImmCheckType"))
240 ImmCheckTypes[RV->getNameInitAsString()] = RV->getValueAsInt("Value");
241 }
242
243 /// Returns the enum value for the immcheck type
244 unsigned getEnumValueForImmCheck(StringRef C) const {
245 auto It = ImmCheckTypes.find(C);
246 if (It != ImmCheckTypes.end())
247 return It->getValue();
248 llvm_unreachable("Unsupported imm check");
Sander de Smalenc5b81462020-03-18 11:07:20 +0000249 }
250
Sander de Smalenf6ea0262020-04-14 15:31:20 +0100251 // Returns the SVETypeFlags for a given value and mask.
252 uint64_t encodeFlag(uint64_t V, StringRef MaskName) const {
253 auto It = FlagTypes.find(MaskName);
254 if (It != FlagTypes.end()) {
255 uint64_t Mask = It->getValue();
256 unsigned Shift = llvm::countTrailingZeros(Mask);
257 return (V << Shift) & Mask;
258 }
259 llvm_unreachable("Unsupported flag");
260 }
261
262 // Returns the SVETypeFlags for the given element type.
263 uint64_t encodeEltType(StringRef EltName) {
264 auto It = EltTypes.find(EltName);
265 if (It != EltTypes.end())
266 return encodeFlag(It->getValue(), "EltTypeMask");
267 llvm_unreachable("Unsupported EltType");
268 }
269
270 // Returns the SVETypeFlags for the given memory element type.
271 uint64_t encodeMemoryElementType(uint64_t MT) {
272 return encodeFlag(MT, "MemEltTypeMask");
273 }
274
275 // Returns the SVETypeFlags for the given merge type.
276 uint64_t encodeMergeType(uint64_t MT) {
277 return encodeFlag(MT, "MergeTypeMask");
278 }
279
280 // Returns the SVETypeFlags value for the given SVEType.
281 uint64_t encodeTypeFlags(const SVEType &T);
282
Sander de Smalenc5b81462020-03-18 11:07:20 +0000283 /// Emit arm_sve.h.
284 void createHeader(raw_ostream &o);
285
286 /// Emit all the __builtin prototypes and code needed by Sema.
287 void createBuiltins(raw_ostream &o);
288
289 /// Emit all the information needed to map builtin -> LLVM IR intrinsic.
290 void createCodeGenMap(raw_ostream &o);
291
Sander de Smalenc8a5b302020-04-14 15:56:36 +0100292 /// Emit all the range checks for the immediates.
293 void createRangeChecks(raw_ostream &o);
294
Sander de Smalenc5b81462020-03-18 11:07:20 +0000295 /// Create the SVETypeFlags used in CGBuiltins
296 void createTypeFlags(raw_ostream &o);
297
298 /// Create intrinsic and add it to \p Out
299 void createIntrinsic(Record *R, SmallVectorImpl<std::unique_ptr<Intrinsic>> &Out);
Sander de Smalen5087ace2020-03-15 14:29:45 +0000300};
301
302} // end anonymous namespace
303
304
305//===----------------------------------------------------------------------===//
Sander de Smalenc5b81462020-03-18 11:07:20 +0000306// Type implementation
Sander de Smalen8b409ea2020-03-16 10:14:05 +0000307//===----------------------------------------------------------------------===//
Sander de Smalen8b409ea2020-03-16 10:14:05 +0000308
Sander de Smalenc5b81462020-03-18 11:07:20 +0000309std::string SVEType::builtin_str() const {
310 std::string S;
311 if (isVoid())
312 return "v";
313
314 if (isVoidPointer())
315 S += "v";
316 else if (!Float)
317 switch (ElementBitwidth) {
318 case 1: S += "b"; break;
319 case 8: S += "c"; break;
320 case 16: S += "s"; break;
321 case 32: S += "i"; break;
322 case 64: S += "Wi"; break;
323 case 128: S += "LLLi"; break;
324 default: llvm_unreachable("Unhandled case!");
325 }
326 else
327 switch (ElementBitwidth) {
328 case 16: S += "h"; break;
329 case 32: S += "f"; break;
330 case 64: S += "d"; break;
331 default: llvm_unreachable("Unhandled case!");
332 }
333
334 if (!isFloat()) {
335 if ((isChar() || isPointer()) && !isVoidPointer()) {
336 // Make chars and typed pointers explicitly signed.
337 if (Signed)
338 S = "S" + S;
339 else if (!Signed)
340 S = "U" + S;
341 } else if (!isVoidPointer() && !Signed) {
342 S = "U" + S;
343 }
344 }
345
346 // Constant indices are "int", but have the "constant expression" modifier.
347 if (isImmediate()) {
348 assert(!isFloat() && "fp immediates are not supported");
349 S = "I" + S;
350 }
351
352 if (isScalar()) {
353 if (Constant) S += "C";
354 if (Pointer) S += "*";
355 return S;
356 }
357
358 assert(isScalableVector() && "Unsupported type");
359 return "q" + utostr(getNumElements() * NumVectors) + S;
360}
361
Sander de Smalen981f0802020-03-18 15:05:08 +0000362std::string SVEType::str() const {
363 if (isPredicatePattern())
364 return "sv_pattern";
365
366 if (isPrefetchOp())
367 return "sv_prfop";
368
369 std::string S;
370 if (Void)
371 S += "void";
372 else {
373 if (isScalableVector())
374 S += "sv";
375 if (!Signed && !Float)
376 S += "u";
377
378 if (Float)
379 S += "float";
380 else if (isScalarPredicate())
381 S += "bool";
382 else
383 S += "int";
384
385 if (!isScalarPredicate())
386 S += utostr(ElementBitwidth);
387 if (!isScalableVector() && isVector())
388 S += "x" + utostr(getNumElements());
389 if (NumVectors > 1)
390 S += "x" + utostr(NumVectors);
391 S += "_t";
392 }
393
394 if (Constant)
395 S += " const";
396 if (Pointer)
397 S += " *";
398
399 return S;
400}
Sander de Smalenc5b81462020-03-18 11:07:20 +0000401void SVEType::applyTypespec() {
402 for (char I : TS) {
403 switch (I) {
404 case 'P':
405 Predicate = true;
406 ElementBitwidth = 1;
407 break;
408 case 'U':
409 Signed = false;
410 break;
411 case 'c':
412 ElementBitwidth = 8;
413 break;
414 case 's':
415 ElementBitwidth = 16;
416 break;
417 case 'i':
418 ElementBitwidth = 32;
419 break;
420 case 'l':
421 ElementBitwidth = 64;
422 break;
423 case 'h':
424 Float = true;
425 ElementBitwidth = 16;
426 break;
427 case 'f':
428 Float = true;
429 ElementBitwidth = 32;
430 break;
431 case 'd':
432 Float = true;
433 ElementBitwidth = 64;
434 break;
435 default:
436 llvm_unreachable("Unhandled type code!");
437 }
438 }
439 assert(ElementBitwidth != ~0U && "Bad element bitwidth!");
440}
441
442void SVEType::applyModifier(char Mod) {
443 switch (Mod) {
444 case 'v':
445 Void = true;
446 break;
447 case 'd':
448 DefaultType = true;
449 break;
450 case 'c':
451 Constant = true;
452 LLVM_FALLTHROUGH;
453 case 'p':
454 Pointer = true;
455 Bitwidth = ElementBitwidth;
456 NumVectors = 0;
457 break;
458 case 'P':
459 Signed = true;
460 Float = false;
461 Predicate = true;
462 Bitwidth = 16;
463 ElementBitwidth = 1;
464 break;
Sander de Smalenc8a5b302020-04-14 15:56:36 +0100465 case 'i':
466 Predicate = false;
467 Float = false;
468 ElementBitwidth = Bitwidth = 64;
469 NumVectors = 0;
470 Signed = false;
471 Immediate = true;
472 break;
473 case 'I':
474 Predicate = false;
475 Float = false;
476 ElementBitwidth = Bitwidth = 32;
477 NumVectors = 0;
478 Signed = true;
479 Immediate = true;
480 PredicatePattern = true;
481 break;
Sander de Smalen17a68c62020-04-14 13:17:52 +0100482 case 'l':
483 Predicate = false;
484 Signed = true;
485 Float = false;
486 ElementBitwidth = Bitwidth = 64;
487 NumVectors = 0;
488 break;
489 case 'S':
490 Constant = true;
491 Pointer = true;
492 ElementBitwidth = Bitwidth = 8;
493 NumVectors = 0;
494 Signed = true;
495 break;
496 case 'W':
497 Constant = true;
498 Pointer = true;
499 ElementBitwidth = Bitwidth = 8;
500 NumVectors = 0;
501 Signed = false;
502 break;
503 case 'T':
504 Constant = true;
505 Pointer = true;
506 ElementBitwidth = Bitwidth = 16;
507 NumVectors = 0;
508 Signed = true;
509 break;
510 case 'X':
511 Constant = true;
512 Pointer = true;
513 ElementBitwidth = Bitwidth = 16;
514 NumVectors = 0;
515 Signed = false;
516 break;
517 case 'Y':
518 Constant = true;
519 Pointer = true;
520 ElementBitwidth = Bitwidth = 32;
521 NumVectors = 0;
522 Signed = false;
523 break;
524 case 'U':
525 Constant = true;
526 Pointer = true;
527 ElementBitwidth = Bitwidth = 32;
528 NumVectors = 0;
529 Signed = true;
530 break;
531 case 'A':
532 Pointer = true;
533 ElementBitwidth = Bitwidth = 8;
534 NumVectors = 0;
535 Signed = true;
536 break;
537 case 'B':
538 Pointer = true;
539 ElementBitwidth = Bitwidth = 16;
540 NumVectors = 0;
541 Signed = true;
542 break;
543 case 'C':
544 Pointer = true;
545 ElementBitwidth = Bitwidth = 32;
546 NumVectors = 0;
547 Signed = true;
548 break;
549 case 'D':
550 Pointer = true;
551 ElementBitwidth = Bitwidth = 64;
552 NumVectors = 0;
553 Signed = true;
554 break;
555 case 'E':
556 Pointer = true;
557 ElementBitwidth = Bitwidth = 8;
558 NumVectors = 0;
559 Signed = false;
560 break;
561 case 'F':
562 Pointer = true;
563 ElementBitwidth = Bitwidth = 16;
564 NumVectors = 0;
565 Signed = false;
566 break;
567 case 'G':
568 Pointer = true;
569 ElementBitwidth = Bitwidth = 32;
570 NumVectors = 0;
571 Signed = false;
572 break;
Sander de Smalenc5b81462020-03-18 11:07:20 +0000573 default:
574 llvm_unreachable("Unhandled character!");
575 }
576}
577
578
579//===----------------------------------------------------------------------===//
580// Intrinsic implementation
581//===----------------------------------------------------------------------===//
582
Sander de Smalenf6ea0262020-04-14 15:31:20 +0100583Intrinsic::Intrinsic(StringRef Name, StringRef Proto, uint64_t MergeTy,
584 StringRef MergeSuffix, uint64_t MemoryElementTy,
Sander de Smalenc8a5b302020-04-14 15:56:36 +0100585 StringRef LLVMName, uint64_t Flags,
586 ArrayRef<ImmCheck> Checks, TypeSpec BT, ClassKind Class,
587 SVEEmitter &Emitter, StringRef Guard)
Sander de Smalenf6ea0262020-04-14 15:31:20 +0100588 : Name(Name.str()), LLVMName(LLVMName), Proto(Proto.str()),
589 BaseTypeSpec(BT), Class(Class), Guard(Guard.str()),
Sander de Smalenc8a5b302020-04-14 15:56:36 +0100590 MergeSuffix(MergeSuffix.str()), BaseType(BT, 'd'), Flags(Flags),
591 ImmChecks(Checks.begin(), Checks.end()) {
Sander de Smalenf6ea0262020-04-14 15:31:20 +0100592
593 // Types[0] is the return value.
594 for (unsigned I = 0; I < Proto.size(); ++I) {
595 SVEType T(BaseTypeSpec, Proto[I]);
596 Types.push_back(T);
Sander de Smalenc8a5b302020-04-14 15:56:36 +0100597
598 // Add range checks for immediates
599 if (I > 0) {
600 if (T.isPredicatePattern())
601 ImmChecks.emplace_back(
602 I - 1, Emitter.getEnumValueForImmCheck("ImmCheck0_31"));
603 }
Sander de Smalenf6ea0262020-04-14 15:31:20 +0100604 }
605
606 // Set flags based on properties
607 this->Flags |= Emitter.encodeTypeFlags(BaseType);
608 this->Flags |= Emitter.encodeMemoryElementType(MemoryElementTy);
609 this->Flags |= Emitter.encodeMergeType(MergeTy);
610}
611
Sander de Smalenc5b81462020-03-18 11:07:20 +0000612std::string Intrinsic::getBuiltinTypeStr() {
613 std::string S;
614
615 SVEType RetT = getReturnType();
616 // Since the return value must be one type, return a vector type of the
617 // appropriate width which we will bitcast. An exception is made for
618 // returning structs of 2, 3, or 4 vectors which are returned in a sret-like
619 // fashion, storing them to a pointer arg.
620 if (RetT.getNumVectors() > 1) {
621 S += "vv*"; // void result with void* first argument
622 } else
623 S += RetT.builtin_str();
624
625 for (unsigned I = 0; I < getNumParams(); ++I)
626 S += getParamType(I).builtin_str();
627
628 return S;
629}
630
631std::string Intrinsic::replaceTemplatedArgs(std::string Name, TypeSpec TS,
632 std::string Proto) const {
633 std::string Ret = Name;
634 while (Ret.find('{') != std::string::npos) {
635 size_t Pos = Ret.find('{');
636 size_t End = Ret.find('}');
637 unsigned NumChars = End - Pos + 1;
638 assert(NumChars == 3 && "Unexpected template argument");
639
640 SVEType T;
641 char C = Ret[Pos+1];
642 switch(C) {
643 default:
644 llvm_unreachable("Unknown predication specifier");
645 case 'd':
646 T = SVEType(TS, 'd');
647 break;
648 case '0':
649 case '1':
650 case '2':
651 case '3':
652 T = SVEType(TS, Proto[C - '0']);
653 break;
654 }
655
656 // Replace templated arg with the right suffix (e.g. u32)
657 std::string TypeCode;
658 if (T.isInteger())
659 TypeCode = T.isSigned() ? 's' : 'u';
660 else if (T.isPredicateVector())
661 TypeCode = 'b';
662 else
663 TypeCode = 'f';
664 Ret.replace(Pos, NumChars, TypeCode + utostr(T.getElementSizeInBits()));
665 }
666
667 return Ret;
668}
669
Sander de Smalenc5b81462020-03-18 11:07:20 +0000670std::string Intrinsic::mangleName(ClassKind LocalCK) const {
671 std::string S = getName();
672
673 if (LocalCK == ClassG) {
674 // Remove the square brackets and everything in between.
675 while (S.find("[") != std::string::npos) {
676 auto Start = S.find("[");
677 auto End = S.find(']');
678 S.erase(Start, (End-Start)+1);
679 }
680 } else {
681 // Remove the square brackets.
682 while (S.find("[") != std::string::npos) {
683 auto BrPos = S.find('[');
684 if (BrPos != std::string::npos)
685 S.erase(BrPos, 1);
686 BrPos = S.find(']');
687 if (BrPos != std::string::npos)
688 S.erase(BrPos, 1);
689 }
690 }
691
692 // Replace all {d} like expressions with e.g. 'u32'
693 return replaceTemplatedArgs(S, getBaseTypeSpec(), getProto()) +
694 getMergeSuffix();
695}
696
697void Intrinsic::emitIntrinsic(raw_ostream &OS) const {
698 // Use the preprocessor to
699 if (getClassKind() != ClassG || getProto().size() <= 1) {
700 OS << "#define " << mangleName(getClassKind())
701 << "(...) __builtin_sve_" << mangleName(ClassS)
702 << "(__VA_ARGS__)\n";
703 } else {
Sander de Smalen981f0802020-03-18 15:05:08 +0000704 std::string FullName = mangleName(ClassS);
705 std::string ProtoName = mangleName(ClassG);
706
707 OS << "__aio __attribute__((__clang_arm_builtin_alias("
708 << "__builtin_sve_" << FullName << ")))\n";
709
710 OS << getTypes()[0].str() << " " << ProtoName << "(";
711 for (unsigned I = 0; I < getTypes().size() - 1; ++I) {
712 if (I != 0)
713 OS << ", ";
714 OS << getTypes()[I + 1].str();
715 }
716 OS << ");\n";
Sander de Smalenc5b81462020-03-18 11:07:20 +0000717 }
718}
719
720//===----------------------------------------------------------------------===//
721// SVEEmitter implementation
722//===----------------------------------------------------------------------===//
Sander de Smalenf6ea0262020-04-14 15:31:20 +0100723uint64_t SVEEmitter::encodeTypeFlags(const SVEType &T) {
724 if (T.isFloat()) {
725 switch (T.getElementSizeInBits()) {
726 case 16:
727 return encodeEltType("EltTyFloat16");
728 case 32:
729 return encodeEltType("EltTyFloat32");
730 case 64:
731 return encodeEltType("EltTyFloat64");
732 default:
733 llvm_unreachable("Unhandled float element bitwidth!");
734 }
735 }
736
737 if (T.isPredicateVector()) {
738 switch (T.getElementSizeInBits()) {
739 case 8:
740 return encodeEltType("EltTyBool8");
741 case 16:
742 return encodeEltType("EltTyBool16");
743 case 32:
744 return encodeEltType("EltTyBool32");
745 case 64:
746 return encodeEltType("EltTyBool64");
747 default:
748 llvm_unreachable("Unhandled predicate element bitwidth!");
749 }
750 }
751
752 switch (T.getElementSizeInBits()) {
753 case 8:
754 return encodeEltType("EltTyInt8");
755 case 16:
756 return encodeEltType("EltTyInt16");
757 case 32:
758 return encodeEltType("EltTyInt32");
759 case 64:
760 return encodeEltType("EltTyInt64");
761 default:
762 llvm_unreachable("Unhandled integer element bitwidth!");
763 }
764}
765
Sander de Smalenc5b81462020-03-18 11:07:20 +0000766void SVEEmitter::createIntrinsic(
767 Record *R, SmallVectorImpl<std::unique_ptr<Intrinsic>> &Out) {
768 StringRef Name = R->getValueAsString("Name");
769 StringRef Proto = R->getValueAsString("Prototype");
770 StringRef Types = R->getValueAsString("Types");
771 StringRef Guard = R->getValueAsString("ArchGuard");
772 StringRef LLVMName = R->getValueAsString("LLVMIntrinsic");
Sander de Smalenf6ea0262020-04-14 15:31:20 +0100773 uint64_t Merge = R->getValueAsInt("Merge");
774 StringRef MergeSuffix = R->getValueAsString("MergeSuffix");
775 uint64_t MemEltType = R->getValueAsInt("MemEltType");
Sander de Smalenc5b81462020-03-18 11:07:20 +0000776 std::vector<Record*> FlagsList = R->getValueAsListOfDefs("Flags");
Sander de Smalenc8a5b302020-04-14 15:56:36 +0100777 std::vector<Record*> ImmCheckList = R->getValueAsListOfDefs("ImmChecks");
Sander de Smalenc5b81462020-03-18 11:07:20 +0000778
779 int64_t Flags = 0;
780 for (auto FlagRec : FlagsList)
781 Flags |= FlagRec->getValueAsInt("Value");
Sander de Smalenc5b81462020-03-18 11:07:20 +0000782
783 // Extract type specs from string
784 SmallVector<TypeSpec, 8> TypeSpecs;
785 TypeSpec Acc;
786 for (char I : Types) {
787 Acc.push_back(I);
788 if (islower(I)) {
789 TypeSpecs.push_back(TypeSpec(Acc));
790 Acc.clear();
791 }
792 }
793
794 // Remove duplicate type specs.
Benjamin Kramer4065e922020-03-28 19:19:55 +0100795 llvm::sort(TypeSpecs);
Sander de Smalenc5b81462020-03-18 11:07:20 +0000796 TypeSpecs.erase(std::unique(TypeSpecs.begin(), TypeSpecs.end()),
797 TypeSpecs.end());
798
799 // Create an Intrinsic for each type spec.
800 for (auto TS : TypeSpecs) {
Sander de Smalenc8a5b302020-04-14 15:56:36 +0100801 // Collate a list of range/option checks for the immediates.
802 SmallVector<ImmCheck, 2> ImmChecks;
803 for (auto *R : ImmCheckList) {
Christopher Tetreault464a0692020-04-15 15:16:17 -0700804 int64_t Arg = R->getValueAsInt("Arg");
805 int64_t EltSizeArg = R->getValueAsInt("EltSizeArg");
806 int64_t Kind = R->getValueAsDef("Kind")->getValueAsInt("Value");
807 assert(Arg >= 0 && Kind >= 0 && "Arg and Kind must be nonnegative");
Sander de Smalenc8a5b302020-04-14 15:56:36 +0100808
809 unsigned ElementSizeInBits = 0;
810 if (EltSizeArg >= 0)
811 ElementSizeInBits =
812 SVEType(TS, Proto[EltSizeArg + /* offset by return arg */ 1])
813 .getElementSizeInBits();
814 ImmChecks.push_back(ImmCheck(Arg, Kind, ElementSizeInBits));
815 }
816
817 Out.push_back(std::make_unique<Intrinsic>(
818 Name, Proto, Merge, MergeSuffix, MemEltType, LLVMName, Flags, ImmChecks,
819 TS, ClassS, *this, Guard));
Sander de Smalen981f0802020-03-18 15:05:08 +0000820
821 // Also generate the short-form (e.g. svadd_m) for the given type-spec.
822 if (Intrinsic::isOverloadedIntrinsic(Name))
Sander de Smalenc8a5b302020-04-14 15:56:36 +0100823 Out.push_back(std::make_unique<Intrinsic>(
824 Name, Proto, Merge, MergeSuffix, MemEltType, LLVMName, Flags,
825 ImmChecks, TS, ClassG, *this, Guard));
Sander de Smalenc5b81462020-03-18 11:07:20 +0000826 }
827}
828
829void SVEEmitter::createHeader(raw_ostream &OS) {
Sander de Smalen5087ace2020-03-15 14:29:45 +0000830 OS << "/*===---- arm_sve.h - ARM SVE intrinsics "
831 "-----------------------------------===\n"
832 " *\n"
833 " *\n"
834 " * Part of the LLVM Project, under the Apache License v2.0 with LLVM "
835 "Exceptions.\n"
836 " * See https://llvm.org/LICENSE.txt for license information.\n"
837 " * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception\n"
838 " *\n"
839 " *===-----------------------------------------------------------------"
840 "------===\n"
841 " */\n\n";
842
843 OS << "#ifndef __ARM_SVE_H\n";
844 OS << "#define __ARM_SVE_H\n\n";
845
846 OS << "#if !defined(__ARM_FEATURE_SVE)\n";
847 OS << "#error \"SVE support not enabled\"\n";
848 OS << "#else\n\n";
849
850 OS << "#include <stdint.h>\n\n";
Sander de Smalenc5b81462020-03-18 11:07:20 +0000851 OS << "#ifdef __cplusplus\n";
852 OS << "extern \"C\" {\n";
853 OS << "#else\n";
Sander de Smalen5087ace2020-03-15 14:29:45 +0000854 OS << "#include <stdbool.h>\n";
855 OS << "#endif\n\n";
856
857 OS << "typedef __fp16 float16_t;\n";
858 OS << "typedef float float32_t;\n";
859 OS << "typedef double float64_t;\n";
860 OS << "typedef bool bool_t;\n\n";
861
862 OS << "typedef __SVInt8_t svint8_t;\n";
863 OS << "typedef __SVInt16_t svint16_t;\n";
864 OS << "typedef __SVInt32_t svint32_t;\n";
865 OS << "typedef __SVInt64_t svint64_t;\n";
866 OS << "typedef __SVUint8_t svuint8_t;\n";
867 OS << "typedef __SVUint16_t svuint16_t;\n";
868 OS << "typedef __SVUint32_t svuint32_t;\n";
869 OS << "typedef __SVUint64_t svuint64_t;\n";
870 OS << "typedef __SVFloat16_t svfloat16_t;\n";
871 OS << "typedef __SVFloat32_t svfloat32_t;\n";
872 OS << "typedef __SVFloat64_t svfloat64_t;\n";
873 OS << "typedef __SVBool_t svbool_t;\n\n";
874
Sander de Smalenc8a5b302020-04-14 15:56:36 +0100875 OS << "typedef enum\n";
876 OS << "{\n";
877 OS << " SV_POW2 = 0,\n";
878 OS << " SV_VL1 = 1,\n";
879 OS << " SV_VL2 = 2,\n";
880 OS << " SV_VL3 = 3,\n";
881 OS << " SV_VL4 = 4,\n";
882 OS << " SV_VL5 = 5,\n";
883 OS << " SV_VL6 = 6,\n";
884 OS << " SV_VL7 = 7,\n";
885 OS << " SV_VL8 = 8,\n";
886 OS << " SV_VL16 = 9,\n";
887 OS << " SV_VL32 = 10,\n";
888 OS << " SV_VL64 = 11,\n";
889 OS << " SV_VL128 = 12,\n";
890 OS << " SV_VL256 = 13,\n";
891 OS << " SV_MUL4 = 29,\n";
892 OS << " SV_MUL3 = 30,\n";
893 OS << " SV_ALL = 31\n";
894 OS << "} sv_pattern;\n\n";
895
Sander de Smalen981f0802020-03-18 15:05:08 +0000896 OS << "/* Function attributes */\n";
897 OS << "#define __aio static inline __attribute__((__always_inline__, "
898 "__nodebug__, __overloadable__))\n\n";
899
Sander de Smalenc5b81462020-03-18 11:07:20 +0000900 SmallVector<std::unique_ptr<Intrinsic>, 128> Defs;
901 std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst");
902 for (auto *R : RV)
903 createIntrinsic(R, Defs);
Sander de Smalen5087ace2020-03-15 14:29:45 +0000904
Sander de Smalenc5b81462020-03-18 11:07:20 +0000905 // Sort intrinsics in header file by following order/priority:
906 // - Architectural guard (i.e. does it require SVE2 or SVE2_AES)
907 // - Class (is intrinsic overloaded or not)
908 // - Intrinsic name
909 std::stable_sort(
910 Defs.begin(), Defs.end(), [](const std::unique_ptr<Intrinsic> &A,
911 const std::unique_ptr<Intrinsic> &B) {
912 return A->getGuard() < B->getGuard() ||
913 (unsigned)A->getClassKind() < (unsigned)B->getClassKind() ||
914 A->getName() < B->getName();
915 });
916
917 StringRef InGuard = "";
918 for (auto &I : Defs) {
919 // Emit #endif/#if pair if needed.
920 if (I->getGuard() != InGuard) {
921 if (!InGuard.empty())
922 OS << "#endif //" << InGuard << "\n";
923 InGuard = I->getGuard();
924 if (!InGuard.empty())
925 OS << "\n#if " << InGuard << "\n";
926 }
927
928 // Actually emit the intrinsic declaration.
929 I->emitIntrinsic(OS);
930 }
931
932 if (!InGuard.empty())
933 OS << "#endif //" << InGuard << "\n";
934
935 OS << "#ifdef __cplusplus\n";
936 OS << "} // extern \"C\"\n";
937 OS << "#endif\n\n";
938 OS << "#endif /*__ARM_FEATURE_SVE */\n\n";
Sander de Smalen5087ace2020-03-15 14:29:45 +0000939 OS << "#endif /* __ARM_SVE_H */\n";
940}
941
Sander de Smalenc5b81462020-03-18 11:07:20 +0000942void SVEEmitter::createBuiltins(raw_ostream &OS) {
943 std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst");
944 SmallVector<std::unique_ptr<Intrinsic>, 128> Defs;
945 for (auto *R : RV)
946 createIntrinsic(R, Defs);
947
948 // The mappings must be sorted based on BuiltinID.
949 llvm::sort(Defs, [](const std::unique_ptr<Intrinsic> &A,
950 const std::unique_ptr<Intrinsic> &B) {
951 return A->getMangledName() < B->getMangledName();
952 });
953
954 OS << "#ifdef GET_SVE_BUILTINS\n";
955 for (auto &Def : Defs) {
956 // Only create BUILTINs for non-overloaded intrinsics, as overloaded
957 // declarations only live in the header file.
958 if (Def->getClassKind() != ClassG)
959 OS << "BUILTIN(__builtin_sve_" << Def->getMangledName() << ", \""
960 << Def->getBuiltinTypeStr() << "\", \"n\")\n";
961 }
962 OS << "#endif\n\n";
963}
964
965void SVEEmitter::createCodeGenMap(raw_ostream &OS) {
966 std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst");
967 SmallVector<std::unique_ptr<Intrinsic>, 128> Defs;
968 for (auto *R : RV)
969 createIntrinsic(R, Defs);
970
971 // The mappings must be sorted based on BuiltinID.
972 llvm::sort(Defs, [](const std::unique_ptr<Intrinsic> &A,
973 const std::unique_ptr<Intrinsic> &B) {
974 return A->getMangledName() < B->getMangledName();
975 });
976
977 OS << "#ifdef GET_SVE_LLVM_INTRINSIC_MAP\n";
978 for (auto &Def : Defs) {
979 // Builtins only exist for non-overloaded intrinsics, overloaded
980 // declarations only live in the header file.
981 if (Def->getClassKind() == ClassG)
982 continue;
983
Sander de Smalenf6ea0262020-04-14 15:31:20 +0100984 uint64_t Flags = Def->getFlags();
Sander de Smalenc5b81462020-03-18 11:07:20 +0000985 auto FlagString = std::to_string(Flags);
986
987 std::string LLVMName = Def->getLLVMName();
988 std::string Builtin = Def->getMangledName();
989 if (!LLVMName.empty())
990 OS << "SVEMAP1(" << Builtin << ", " << LLVMName << ", " << FlagString
991 << "),\n";
992 else
993 OS << "SVEMAP2(" << Builtin << ", " << FlagString << "),\n";
994 }
995 OS << "#endif\n\n";
996}
997
Sander de Smalenc8a5b302020-04-14 15:56:36 +0100998void SVEEmitter::createRangeChecks(raw_ostream &OS) {
999 std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst");
1000 SmallVector<std::unique_ptr<Intrinsic>, 128> Defs;
1001 for (auto *R : RV)
1002 createIntrinsic(R, Defs);
1003
1004 // The mappings must be sorted based on BuiltinID.
1005 llvm::sort(Defs, [](const std::unique_ptr<Intrinsic> &A,
1006 const std::unique_ptr<Intrinsic> &B) {
1007 return A->getMangledName() < B->getMangledName();
1008 });
1009
1010
1011 OS << "#ifdef GET_SVE_IMMEDIATE_CHECK\n";
1012
1013 // Ensure these are only emitted once.
1014 std::set<std::string> Emitted;
1015
1016 for (auto &Def : Defs) {
1017 if (Emitted.find(Def->getMangledName()) != Emitted.end() ||
1018 Def->getImmChecks().empty())
1019 continue;
1020
1021 OS << "case SVE::BI__builtin_sve_" << Def->getMangledName() << ":\n";
1022 for (auto &Check : Def->getImmChecks())
1023 OS << "ImmChecks.push_back(std::make_tuple(" << Check.getArg() << ", "
1024 << Check.getKind() << ", " << Check.getElementSizeInBits() << "));\n";
1025 OS << " break;\n";
1026
1027 Emitted.insert(Def->getMangledName());
1028 }
1029
1030 OS << "#endif\n\n";
1031}
1032
Sander de Smalenc5b81462020-03-18 11:07:20 +00001033/// Create the SVETypeFlags used in CGBuiltins
1034void SVEEmitter::createTypeFlags(raw_ostream &OS) {
1035 OS << "#ifdef LLVM_GET_SVE_TYPEFLAGS\n";
1036 for (auto &KV : FlagTypes)
1037 OS << "const uint64_t " << KV.getKey() << " = " << KV.getValue() << ";\n";
1038 OS << "#endif\n\n";
1039
1040 OS << "#ifdef LLVM_GET_SVE_ELTTYPES\n";
1041 for (auto &KV : EltTypes)
1042 OS << " " << KV.getKey() << " = " << KV.getValue() << ",\n";
1043 OS << "#endif\n\n";
1044
1045 OS << "#ifdef LLVM_GET_SVE_MEMELTTYPES\n";
1046 for (auto &KV : MemEltTypes)
1047 OS << " " << KV.getKey() << " = " << KV.getValue() << ",\n";
1048 OS << "#endif\n\n";
Sander de Smalenf6ea0262020-04-14 15:31:20 +01001049
1050 OS << "#ifdef LLVM_GET_SVE_MERGETYPES\n";
1051 for (auto &KV : MergeTypes)
1052 OS << " " << KV.getKey() << " = " << KV.getValue() << ",\n";
1053 OS << "#endif\n\n";
Sander de Smalenc8a5b302020-04-14 15:56:36 +01001054
1055 OS << "#ifdef LLVM_GET_SVE_IMMCHECKTYPES\n";
1056 for (auto &KV : ImmCheckTypes)
1057 OS << " " << KV.getKey() << " = " << KV.getValue() << ",\n";
1058 OS << "#endif\n\n";
Sander de Smalenc5b81462020-03-18 11:07:20 +00001059}
1060
Sander de Smalen5087ace2020-03-15 14:29:45 +00001061namespace clang {
1062void EmitSveHeader(RecordKeeper &Records, raw_ostream &OS) {
Sander de Smalenc5b81462020-03-18 11:07:20 +00001063 SVEEmitter(Records).createHeader(OS);
1064}
1065
1066void EmitSveBuiltins(RecordKeeper &Records, raw_ostream &OS) {
1067 SVEEmitter(Records).createBuiltins(OS);
1068}
1069
1070void EmitSveBuiltinCG(RecordKeeper &Records, raw_ostream &OS) {
1071 SVEEmitter(Records).createCodeGenMap(OS);
1072}
Sander de Smalenc8a5b302020-04-14 15:56:36 +01001073
1074void EmitSveRangeChecks(RecordKeeper &Records, raw_ostream &OS) {
1075 SVEEmitter(Records).createRangeChecks(OS);
1076}
1077
Sander de Smalenc5b81462020-03-18 11:07:20 +00001078void EmitSveTypeFlags(RecordKeeper &Records, raw_ostream &OS) {
1079 SVEEmitter(Records).createTypeFlags(OS);
Sander de Smalen5087ace2020-03-15 14:29:45 +00001080}
1081
1082} // End namespace clang