blob: 03fe8228dd863906b97765afd4e161c1c8c22a41 [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
211 /// Emits the intrinsic declaration to the ostream.
212 void emitIntrinsic(raw_ostream &OS) const;
213
214private:
Sander de Smalenf6ea0262020-04-14 15:31:20 +0100215 std::string getMergeSuffix() const { return MergeSuffix; }
Sander de Smalenc5b81462020-03-18 11:07:20 +0000216 std::string mangleName(ClassKind LocalCK) const;
217 std::string replaceTemplatedArgs(std::string Name, TypeSpec TS,
218 std::string Proto) const;
219};
220
221class SVEEmitter {
222private:
223 RecordKeeper &Records;
224 llvm::StringMap<uint64_t> EltTypes;
225 llvm::StringMap<uint64_t> MemEltTypes;
226 llvm::StringMap<uint64_t> FlagTypes;
Sander de Smalenf6ea0262020-04-14 15:31:20 +0100227 llvm::StringMap<uint64_t> MergeTypes;
Sander de Smalenc8a5b302020-04-14 15:56:36 +0100228 llvm::StringMap<uint64_t> ImmCheckTypes;
Sander de Smalenc5b81462020-03-18 11:07:20 +0000229
Sander de Smalenc5b81462020-03-18 11:07:20 +0000230public:
231 SVEEmitter(RecordKeeper &R) : Records(R) {
232 for (auto *RV : Records.getAllDerivedDefinitions("EltType"))
233 EltTypes[RV->getNameInitAsString()] = RV->getValueAsInt("Value");
234 for (auto *RV : Records.getAllDerivedDefinitions("MemEltType"))
235 MemEltTypes[RV->getNameInitAsString()] = RV->getValueAsInt("Value");
236 for (auto *RV : Records.getAllDerivedDefinitions("FlagType"))
237 FlagTypes[RV->getNameInitAsString()] = RV->getValueAsInt("Value");
Sander de Smalenf6ea0262020-04-14 15:31:20 +0100238 for (auto *RV : Records.getAllDerivedDefinitions("MergeType"))
239 MergeTypes[RV->getNameInitAsString()] = RV->getValueAsInt("Value");
Sander de Smalenc8a5b302020-04-14 15:56:36 +0100240 for (auto *RV : Records.getAllDerivedDefinitions("ImmCheckType"))
241 ImmCheckTypes[RV->getNameInitAsString()] = RV->getValueAsInt("Value");
242 }
243
244 /// Returns the enum value for the immcheck type
245 unsigned getEnumValueForImmCheck(StringRef C) const {
246 auto It = ImmCheckTypes.find(C);
247 if (It != ImmCheckTypes.end())
248 return It->getValue();
249 llvm_unreachable("Unsupported imm check");
Sander de Smalenc5b81462020-03-18 11:07:20 +0000250 }
251
Sander de Smalenf6ea0262020-04-14 15:31:20 +0100252 // Returns the SVETypeFlags for a given value and mask.
253 uint64_t encodeFlag(uint64_t V, StringRef MaskName) const {
254 auto It = FlagTypes.find(MaskName);
255 if (It != FlagTypes.end()) {
256 uint64_t Mask = It->getValue();
257 unsigned Shift = llvm::countTrailingZeros(Mask);
258 return (V << Shift) & Mask;
259 }
260 llvm_unreachable("Unsupported flag");
261 }
262
263 // Returns the SVETypeFlags for the given element type.
264 uint64_t encodeEltType(StringRef EltName) {
265 auto It = EltTypes.find(EltName);
266 if (It != EltTypes.end())
267 return encodeFlag(It->getValue(), "EltTypeMask");
268 llvm_unreachable("Unsupported EltType");
269 }
270
271 // Returns the SVETypeFlags for the given memory element type.
272 uint64_t encodeMemoryElementType(uint64_t MT) {
273 return encodeFlag(MT, "MemEltTypeMask");
274 }
275
276 // Returns the SVETypeFlags for the given merge type.
277 uint64_t encodeMergeType(uint64_t MT) {
278 return encodeFlag(MT, "MergeTypeMask");
279 }
280
281 // Returns the SVETypeFlags value for the given SVEType.
282 uint64_t encodeTypeFlags(const SVEType &T);
283
Sander de Smalenc5b81462020-03-18 11:07:20 +0000284 /// Emit arm_sve.h.
285 void createHeader(raw_ostream &o);
286
287 /// Emit all the __builtin prototypes and code needed by Sema.
288 void createBuiltins(raw_ostream &o);
289
290 /// Emit all the information needed to map builtin -> LLVM IR intrinsic.
291 void createCodeGenMap(raw_ostream &o);
292
Sander de Smalenc8a5b302020-04-14 15:56:36 +0100293 /// Emit all the range checks for the immediates.
294 void createRangeChecks(raw_ostream &o);
295
Sander de Smalenc5b81462020-03-18 11:07:20 +0000296 /// Create the SVETypeFlags used in CGBuiltins
297 void createTypeFlags(raw_ostream &o);
298
299 /// Create intrinsic and add it to \p Out
300 void createIntrinsic(Record *R, SmallVectorImpl<std::unique_ptr<Intrinsic>> &Out);
Sander de Smalen5087ace2020-03-15 14:29:45 +0000301};
302
303} // end anonymous namespace
304
305
306//===----------------------------------------------------------------------===//
Sander de Smalenc5b81462020-03-18 11:07:20 +0000307// Type implementation
Sander de Smalen8b409ea2020-03-16 10:14:05 +0000308//===----------------------------------------------------------------------===//
Sander de Smalen8b409ea2020-03-16 10:14:05 +0000309
Sander de Smalenc5b81462020-03-18 11:07:20 +0000310std::string SVEType::builtin_str() const {
311 std::string S;
312 if (isVoid())
313 return "v";
314
315 if (isVoidPointer())
316 S += "v";
317 else if (!Float)
318 switch (ElementBitwidth) {
319 case 1: S += "b"; break;
320 case 8: S += "c"; break;
321 case 16: S += "s"; break;
322 case 32: S += "i"; break;
323 case 64: S += "Wi"; break;
324 case 128: S += "LLLi"; break;
325 default: llvm_unreachable("Unhandled case!");
326 }
327 else
328 switch (ElementBitwidth) {
329 case 16: S += "h"; break;
330 case 32: S += "f"; break;
331 case 64: S += "d"; break;
332 default: llvm_unreachable("Unhandled case!");
333 }
334
335 if (!isFloat()) {
336 if ((isChar() || isPointer()) && !isVoidPointer()) {
337 // Make chars and typed pointers explicitly signed.
338 if (Signed)
339 S = "S" + S;
340 else if (!Signed)
341 S = "U" + S;
342 } else if (!isVoidPointer() && !Signed) {
343 S = "U" + S;
344 }
345 }
346
347 // Constant indices are "int", but have the "constant expression" modifier.
348 if (isImmediate()) {
349 assert(!isFloat() && "fp immediates are not supported");
350 S = "I" + S;
351 }
352
353 if (isScalar()) {
354 if (Constant) S += "C";
355 if (Pointer) S += "*";
356 return S;
357 }
358
359 assert(isScalableVector() && "Unsupported type");
360 return "q" + utostr(getNumElements() * NumVectors) + S;
361}
362
Sander de Smalen981f0802020-03-18 15:05:08 +0000363std::string SVEType::str() const {
364 if (isPredicatePattern())
365 return "sv_pattern";
366
367 if (isPrefetchOp())
368 return "sv_prfop";
369
370 std::string S;
371 if (Void)
372 S += "void";
373 else {
374 if (isScalableVector())
375 S += "sv";
376 if (!Signed && !Float)
377 S += "u";
378
379 if (Float)
380 S += "float";
381 else if (isScalarPredicate())
382 S += "bool";
383 else
384 S += "int";
385
386 if (!isScalarPredicate())
387 S += utostr(ElementBitwidth);
388 if (!isScalableVector() && isVector())
389 S += "x" + utostr(getNumElements());
390 if (NumVectors > 1)
391 S += "x" + utostr(NumVectors);
392 S += "_t";
393 }
394
395 if (Constant)
396 S += " const";
397 if (Pointer)
398 S += " *";
399
400 return S;
401}
Sander de Smalenc5b81462020-03-18 11:07:20 +0000402void SVEType::applyTypespec() {
403 for (char I : TS) {
404 switch (I) {
405 case 'P':
406 Predicate = true;
407 ElementBitwidth = 1;
408 break;
409 case 'U':
410 Signed = false;
411 break;
412 case 'c':
413 ElementBitwidth = 8;
414 break;
415 case 's':
416 ElementBitwidth = 16;
417 break;
418 case 'i':
419 ElementBitwidth = 32;
420 break;
421 case 'l':
422 ElementBitwidth = 64;
423 break;
424 case 'h':
425 Float = true;
426 ElementBitwidth = 16;
427 break;
428 case 'f':
429 Float = true;
430 ElementBitwidth = 32;
431 break;
432 case 'd':
433 Float = true;
434 ElementBitwidth = 64;
435 break;
436 default:
437 llvm_unreachable("Unhandled type code!");
438 }
439 }
440 assert(ElementBitwidth != ~0U && "Bad element bitwidth!");
441}
442
443void SVEType::applyModifier(char Mod) {
444 switch (Mod) {
445 case 'v':
446 Void = true;
447 break;
448 case 'd':
449 DefaultType = true;
450 break;
451 case 'c':
452 Constant = true;
453 LLVM_FALLTHROUGH;
454 case 'p':
455 Pointer = true;
456 Bitwidth = ElementBitwidth;
457 NumVectors = 0;
458 break;
Sander de Smalen515020c2020-04-20 14:41:58 +0100459 case 'h':
460 ElementBitwidth /= 2;
461 break;
Sander de Smalenc5b81462020-03-18 11:07:20 +0000462 case 'P':
463 Signed = true;
464 Float = false;
465 Predicate = true;
466 Bitwidth = 16;
467 ElementBitwidth = 1;
468 break;
Sander de Smalen515020c2020-04-20 14:41:58 +0100469 case 'u':
470 Predicate = false;
471 Signed = false;
472 Float = false;
473 break;
Sander de Smalenc8a5b302020-04-14 15:56:36 +0100474 case 'i':
475 Predicate = false;
476 Float = false;
477 ElementBitwidth = Bitwidth = 64;
478 NumVectors = 0;
479 Signed = false;
480 Immediate = true;
481 break;
482 case 'I':
483 Predicate = false;
484 Float = false;
485 ElementBitwidth = Bitwidth = 32;
486 NumVectors = 0;
487 Signed = true;
488 Immediate = true;
489 PredicatePattern = true;
490 break;
Sander de Smalen17a68c62020-04-14 13:17:52 +0100491 case 'l':
492 Predicate = false;
493 Signed = true;
494 Float = false;
495 ElementBitwidth = Bitwidth = 64;
496 NumVectors = 0;
497 break;
498 case 'S':
499 Constant = true;
500 Pointer = true;
501 ElementBitwidth = Bitwidth = 8;
502 NumVectors = 0;
503 Signed = true;
504 break;
505 case 'W':
506 Constant = true;
507 Pointer = true;
508 ElementBitwidth = Bitwidth = 8;
509 NumVectors = 0;
510 Signed = false;
511 break;
512 case 'T':
513 Constant = true;
514 Pointer = true;
515 ElementBitwidth = Bitwidth = 16;
516 NumVectors = 0;
517 Signed = true;
518 break;
519 case 'X':
520 Constant = true;
521 Pointer = true;
522 ElementBitwidth = Bitwidth = 16;
523 NumVectors = 0;
524 Signed = false;
525 break;
526 case 'Y':
527 Constant = true;
528 Pointer = true;
529 ElementBitwidth = Bitwidth = 32;
530 NumVectors = 0;
531 Signed = false;
532 break;
533 case 'U':
534 Constant = true;
535 Pointer = true;
536 ElementBitwidth = Bitwidth = 32;
537 NumVectors = 0;
538 Signed = true;
539 break;
540 case 'A':
541 Pointer = true;
542 ElementBitwidth = Bitwidth = 8;
543 NumVectors = 0;
544 Signed = true;
545 break;
546 case 'B':
547 Pointer = true;
548 ElementBitwidth = Bitwidth = 16;
549 NumVectors = 0;
550 Signed = true;
551 break;
552 case 'C':
553 Pointer = true;
554 ElementBitwidth = Bitwidth = 32;
555 NumVectors = 0;
556 Signed = true;
557 break;
558 case 'D':
559 Pointer = true;
560 ElementBitwidth = Bitwidth = 64;
561 NumVectors = 0;
562 Signed = true;
563 break;
564 case 'E':
565 Pointer = true;
566 ElementBitwidth = Bitwidth = 8;
567 NumVectors = 0;
568 Signed = false;
569 break;
570 case 'F':
571 Pointer = true;
572 ElementBitwidth = Bitwidth = 16;
573 NumVectors = 0;
574 Signed = false;
575 break;
576 case 'G':
577 Pointer = true;
578 ElementBitwidth = Bitwidth = 32;
579 NumVectors = 0;
580 Signed = false;
581 break;
Sander de Smalenc5b81462020-03-18 11:07:20 +0000582 default:
583 llvm_unreachable("Unhandled character!");
584 }
585}
586
587
588//===----------------------------------------------------------------------===//
589// Intrinsic implementation
590//===----------------------------------------------------------------------===//
591
Sander de Smalenf6ea0262020-04-14 15:31:20 +0100592Intrinsic::Intrinsic(StringRef Name, StringRef Proto, uint64_t MergeTy,
593 StringRef MergeSuffix, uint64_t MemoryElementTy,
Sander de Smalenc8a5b302020-04-14 15:56:36 +0100594 StringRef LLVMName, uint64_t Flags,
595 ArrayRef<ImmCheck> Checks, TypeSpec BT, ClassKind Class,
596 SVEEmitter &Emitter, StringRef Guard)
Sander de Smalenf6ea0262020-04-14 15:31:20 +0100597 : Name(Name.str()), LLVMName(LLVMName), Proto(Proto.str()),
598 BaseTypeSpec(BT), Class(Class), Guard(Guard.str()),
Sander de Smalenc8a5b302020-04-14 15:56:36 +0100599 MergeSuffix(MergeSuffix.str()), BaseType(BT, 'd'), Flags(Flags),
600 ImmChecks(Checks.begin(), Checks.end()) {
Sander de Smalenf6ea0262020-04-14 15:31:20 +0100601
602 // Types[0] is the return value.
603 for (unsigned I = 0; I < Proto.size(); ++I) {
604 SVEType T(BaseTypeSpec, Proto[I]);
605 Types.push_back(T);
Sander de Smalenc8a5b302020-04-14 15:56:36 +0100606
607 // Add range checks for immediates
608 if (I > 0) {
609 if (T.isPredicatePattern())
610 ImmChecks.emplace_back(
611 I - 1, Emitter.getEnumValueForImmCheck("ImmCheck0_31"));
612 }
Sander de Smalenf6ea0262020-04-14 15:31:20 +0100613 }
614
615 // Set flags based on properties
616 this->Flags |= Emitter.encodeTypeFlags(BaseType);
617 this->Flags |= Emitter.encodeMemoryElementType(MemoryElementTy);
618 this->Flags |= Emitter.encodeMergeType(MergeTy);
619}
620
Sander de Smalenc5b81462020-03-18 11:07:20 +0000621std::string Intrinsic::getBuiltinTypeStr() {
622 std::string S;
623
624 SVEType RetT = getReturnType();
625 // Since the return value must be one type, return a vector type of the
626 // appropriate width which we will bitcast. An exception is made for
627 // returning structs of 2, 3, or 4 vectors which are returned in a sret-like
628 // fashion, storing them to a pointer arg.
629 if (RetT.getNumVectors() > 1) {
630 S += "vv*"; // void result with void* first argument
631 } else
632 S += RetT.builtin_str();
633
634 for (unsigned I = 0; I < getNumParams(); ++I)
635 S += getParamType(I).builtin_str();
636
637 return S;
638}
639
640std::string Intrinsic::replaceTemplatedArgs(std::string Name, TypeSpec TS,
641 std::string Proto) const {
642 std::string Ret = Name;
643 while (Ret.find('{') != std::string::npos) {
644 size_t Pos = Ret.find('{');
645 size_t End = Ret.find('}');
646 unsigned NumChars = End - Pos + 1;
647 assert(NumChars == 3 && "Unexpected template argument");
648
649 SVEType T;
650 char C = Ret[Pos+1];
651 switch(C) {
652 default:
653 llvm_unreachable("Unknown predication specifier");
654 case 'd':
655 T = SVEType(TS, 'd');
656 break;
657 case '0':
658 case '1':
659 case '2':
660 case '3':
661 T = SVEType(TS, Proto[C - '0']);
662 break;
663 }
664
665 // Replace templated arg with the right suffix (e.g. u32)
666 std::string TypeCode;
667 if (T.isInteger())
668 TypeCode = T.isSigned() ? 's' : 'u';
669 else if (T.isPredicateVector())
670 TypeCode = 'b';
671 else
672 TypeCode = 'f';
673 Ret.replace(Pos, NumChars, TypeCode + utostr(T.getElementSizeInBits()));
674 }
675
676 return Ret;
677}
678
Sander de Smalenc5b81462020-03-18 11:07:20 +0000679std::string Intrinsic::mangleName(ClassKind LocalCK) const {
680 std::string S = getName();
681
682 if (LocalCK == ClassG) {
683 // Remove the square brackets and everything in between.
684 while (S.find("[") != std::string::npos) {
685 auto Start = S.find("[");
686 auto End = S.find(']');
687 S.erase(Start, (End-Start)+1);
688 }
689 } else {
690 // Remove the square brackets.
691 while (S.find("[") != std::string::npos) {
692 auto BrPos = S.find('[');
693 if (BrPos != std::string::npos)
694 S.erase(BrPos, 1);
695 BrPos = S.find(']');
696 if (BrPos != std::string::npos)
697 S.erase(BrPos, 1);
698 }
699 }
700
701 // Replace all {d} like expressions with e.g. 'u32'
702 return replaceTemplatedArgs(S, getBaseTypeSpec(), getProto()) +
703 getMergeSuffix();
704}
705
706void Intrinsic::emitIntrinsic(raw_ostream &OS) const {
707 // Use the preprocessor to
708 if (getClassKind() != ClassG || getProto().size() <= 1) {
709 OS << "#define " << mangleName(getClassKind())
710 << "(...) __builtin_sve_" << mangleName(ClassS)
711 << "(__VA_ARGS__)\n";
712 } else {
Sander de Smalen981f0802020-03-18 15:05:08 +0000713 std::string FullName = mangleName(ClassS);
714 std::string ProtoName = mangleName(ClassG);
715
716 OS << "__aio __attribute__((__clang_arm_builtin_alias("
717 << "__builtin_sve_" << FullName << ")))\n";
718
719 OS << getTypes()[0].str() << " " << ProtoName << "(";
720 for (unsigned I = 0; I < getTypes().size() - 1; ++I) {
721 if (I != 0)
722 OS << ", ";
723 OS << getTypes()[I + 1].str();
724 }
725 OS << ");\n";
Sander de Smalenc5b81462020-03-18 11:07:20 +0000726 }
727}
728
729//===----------------------------------------------------------------------===//
730// SVEEmitter implementation
731//===----------------------------------------------------------------------===//
Sander de Smalenf6ea0262020-04-14 15:31:20 +0100732uint64_t SVEEmitter::encodeTypeFlags(const SVEType &T) {
733 if (T.isFloat()) {
734 switch (T.getElementSizeInBits()) {
735 case 16:
736 return encodeEltType("EltTyFloat16");
737 case 32:
738 return encodeEltType("EltTyFloat32");
739 case 64:
740 return encodeEltType("EltTyFloat64");
741 default:
742 llvm_unreachable("Unhandled float element bitwidth!");
743 }
744 }
745
746 if (T.isPredicateVector()) {
747 switch (T.getElementSizeInBits()) {
748 case 8:
749 return encodeEltType("EltTyBool8");
750 case 16:
751 return encodeEltType("EltTyBool16");
752 case 32:
753 return encodeEltType("EltTyBool32");
754 case 64:
755 return encodeEltType("EltTyBool64");
756 default:
757 llvm_unreachable("Unhandled predicate element bitwidth!");
758 }
759 }
760
761 switch (T.getElementSizeInBits()) {
762 case 8:
763 return encodeEltType("EltTyInt8");
764 case 16:
765 return encodeEltType("EltTyInt16");
766 case 32:
767 return encodeEltType("EltTyInt32");
768 case 64:
769 return encodeEltType("EltTyInt64");
770 default:
771 llvm_unreachable("Unhandled integer element bitwidth!");
772 }
773}
774
Sander de Smalenc5b81462020-03-18 11:07:20 +0000775void SVEEmitter::createIntrinsic(
776 Record *R, SmallVectorImpl<std::unique_ptr<Intrinsic>> &Out) {
777 StringRef Name = R->getValueAsString("Name");
778 StringRef Proto = R->getValueAsString("Prototype");
779 StringRef Types = R->getValueAsString("Types");
780 StringRef Guard = R->getValueAsString("ArchGuard");
781 StringRef LLVMName = R->getValueAsString("LLVMIntrinsic");
Sander de Smalenf6ea0262020-04-14 15:31:20 +0100782 uint64_t Merge = R->getValueAsInt("Merge");
783 StringRef MergeSuffix = R->getValueAsString("MergeSuffix");
784 uint64_t MemEltType = R->getValueAsInt("MemEltType");
Sander de Smalenc5b81462020-03-18 11:07:20 +0000785 std::vector<Record*> FlagsList = R->getValueAsListOfDefs("Flags");
Sander de Smalenc8a5b302020-04-14 15:56:36 +0100786 std::vector<Record*> ImmCheckList = R->getValueAsListOfDefs("ImmChecks");
Sander de Smalenc5b81462020-03-18 11:07:20 +0000787
788 int64_t Flags = 0;
789 for (auto FlagRec : FlagsList)
790 Flags |= FlagRec->getValueAsInt("Value");
Sander de Smalenc5b81462020-03-18 11:07:20 +0000791
792 // Extract type specs from string
793 SmallVector<TypeSpec, 8> TypeSpecs;
794 TypeSpec Acc;
795 for (char I : Types) {
796 Acc.push_back(I);
797 if (islower(I)) {
798 TypeSpecs.push_back(TypeSpec(Acc));
799 Acc.clear();
800 }
801 }
802
803 // Remove duplicate type specs.
Benjamin Kramer4065e922020-03-28 19:19:55 +0100804 llvm::sort(TypeSpecs);
Sander de Smalenc5b81462020-03-18 11:07:20 +0000805 TypeSpecs.erase(std::unique(TypeSpecs.begin(), TypeSpecs.end()),
806 TypeSpecs.end());
807
808 // Create an Intrinsic for each type spec.
809 for (auto TS : TypeSpecs) {
Sander de Smalenc8a5b302020-04-14 15:56:36 +0100810 // Collate a list of range/option checks for the immediates.
811 SmallVector<ImmCheck, 2> ImmChecks;
812 for (auto *R : ImmCheckList) {
Christopher Tetreault464a0692020-04-15 15:16:17 -0700813 int64_t Arg = R->getValueAsInt("Arg");
814 int64_t EltSizeArg = R->getValueAsInt("EltSizeArg");
815 int64_t Kind = R->getValueAsDef("Kind")->getValueAsInt("Value");
816 assert(Arg >= 0 && Kind >= 0 && "Arg and Kind must be nonnegative");
Sander de Smalenc8a5b302020-04-14 15:56:36 +0100817
818 unsigned ElementSizeInBits = 0;
819 if (EltSizeArg >= 0)
820 ElementSizeInBits =
821 SVEType(TS, Proto[EltSizeArg + /* offset by return arg */ 1])
822 .getElementSizeInBits();
823 ImmChecks.push_back(ImmCheck(Arg, Kind, ElementSizeInBits));
824 }
825
826 Out.push_back(std::make_unique<Intrinsic>(
827 Name, Proto, Merge, MergeSuffix, MemEltType, LLVMName, Flags, ImmChecks,
828 TS, ClassS, *this, Guard));
Sander de Smalen981f0802020-03-18 15:05:08 +0000829
830 // Also generate the short-form (e.g. svadd_m) for the given type-spec.
831 if (Intrinsic::isOverloadedIntrinsic(Name))
Sander de Smalenc8a5b302020-04-14 15:56:36 +0100832 Out.push_back(std::make_unique<Intrinsic>(
833 Name, Proto, Merge, MergeSuffix, MemEltType, LLVMName, Flags,
834 ImmChecks, TS, ClassG, *this, Guard));
Sander de Smalenc5b81462020-03-18 11:07:20 +0000835 }
836}
837
838void SVEEmitter::createHeader(raw_ostream &OS) {
Sander de Smalen5087ace2020-03-15 14:29:45 +0000839 OS << "/*===---- arm_sve.h - ARM SVE intrinsics "
840 "-----------------------------------===\n"
841 " *\n"
842 " *\n"
843 " * Part of the LLVM Project, under the Apache License v2.0 with LLVM "
844 "Exceptions.\n"
845 " * See https://llvm.org/LICENSE.txt for license information.\n"
846 " * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception\n"
847 " *\n"
848 " *===-----------------------------------------------------------------"
849 "------===\n"
850 " */\n\n";
851
852 OS << "#ifndef __ARM_SVE_H\n";
853 OS << "#define __ARM_SVE_H\n\n";
854
855 OS << "#if !defined(__ARM_FEATURE_SVE)\n";
856 OS << "#error \"SVE support not enabled\"\n";
857 OS << "#else\n\n";
858
859 OS << "#include <stdint.h>\n\n";
Sander de Smalenc5b81462020-03-18 11:07:20 +0000860 OS << "#ifdef __cplusplus\n";
861 OS << "extern \"C\" {\n";
862 OS << "#else\n";
Sander de Smalen5087ace2020-03-15 14:29:45 +0000863 OS << "#include <stdbool.h>\n";
864 OS << "#endif\n\n";
865
866 OS << "typedef __fp16 float16_t;\n";
867 OS << "typedef float float32_t;\n";
868 OS << "typedef double float64_t;\n";
869 OS << "typedef bool bool_t;\n\n";
870
871 OS << "typedef __SVInt8_t svint8_t;\n";
872 OS << "typedef __SVInt16_t svint16_t;\n";
873 OS << "typedef __SVInt32_t svint32_t;\n";
874 OS << "typedef __SVInt64_t svint64_t;\n";
875 OS << "typedef __SVUint8_t svuint8_t;\n";
876 OS << "typedef __SVUint16_t svuint16_t;\n";
877 OS << "typedef __SVUint32_t svuint32_t;\n";
878 OS << "typedef __SVUint64_t svuint64_t;\n";
879 OS << "typedef __SVFloat16_t svfloat16_t;\n";
880 OS << "typedef __SVFloat32_t svfloat32_t;\n";
881 OS << "typedef __SVFloat64_t svfloat64_t;\n";
882 OS << "typedef __SVBool_t svbool_t;\n\n";
883
Sander de Smalenc8a5b302020-04-14 15:56:36 +0100884 OS << "typedef enum\n";
885 OS << "{\n";
886 OS << " SV_POW2 = 0,\n";
887 OS << " SV_VL1 = 1,\n";
888 OS << " SV_VL2 = 2,\n";
889 OS << " SV_VL3 = 3,\n";
890 OS << " SV_VL4 = 4,\n";
891 OS << " SV_VL5 = 5,\n";
892 OS << " SV_VL6 = 6,\n";
893 OS << " SV_VL7 = 7,\n";
894 OS << " SV_VL8 = 8,\n";
895 OS << " SV_VL16 = 9,\n";
896 OS << " SV_VL32 = 10,\n";
897 OS << " SV_VL64 = 11,\n";
898 OS << " SV_VL128 = 12,\n";
899 OS << " SV_VL256 = 13,\n";
900 OS << " SV_MUL4 = 29,\n";
901 OS << " SV_MUL3 = 30,\n";
902 OS << " SV_ALL = 31\n";
903 OS << "} sv_pattern;\n\n";
904
Sander de Smalen981f0802020-03-18 15:05:08 +0000905 OS << "/* Function attributes */\n";
906 OS << "#define __aio static inline __attribute__((__always_inline__, "
907 "__nodebug__, __overloadable__))\n\n";
908
Sander de Smalenc5b81462020-03-18 11:07:20 +0000909 SmallVector<std::unique_ptr<Intrinsic>, 128> Defs;
910 std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst");
911 for (auto *R : RV)
912 createIntrinsic(R, Defs);
Sander de Smalen5087ace2020-03-15 14:29:45 +0000913
Sander de Smalenc5b81462020-03-18 11:07:20 +0000914 // Sort intrinsics in header file by following order/priority:
915 // - Architectural guard (i.e. does it require SVE2 or SVE2_AES)
916 // - Class (is intrinsic overloaded or not)
917 // - Intrinsic name
918 std::stable_sort(
919 Defs.begin(), Defs.end(), [](const std::unique_ptr<Intrinsic> &A,
920 const std::unique_ptr<Intrinsic> &B) {
Eric Fiselieraf2968e2020-04-16 18:35:31 -0400921 auto ToTuple = [](const std::unique_ptr<Intrinsic> &I) {
922 return std::make_tuple(I->getGuard(), (unsigned)I->getClassKind(), I->getName());
923 };
924 return ToTuple(A) < ToTuple(B);
Sander de Smalenc5b81462020-03-18 11:07:20 +0000925 });
926
927 StringRef InGuard = "";
928 for (auto &I : Defs) {
929 // Emit #endif/#if pair if needed.
930 if (I->getGuard() != InGuard) {
931 if (!InGuard.empty())
932 OS << "#endif //" << InGuard << "\n";
933 InGuard = I->getGuard();
934 if (!InGuard.empty())
935 OS << "\n#if " << InGuard << "\n";
936 }
937
938 // Actually emit the intrinsic declaration.
939 I->emitIntrinsic(OS);
940 }
941
942 if (!InGuard.empty())
943 OS << "#endif //" << InGuard << "\n";
944
945 OS << "#ifdef __cplusplus\n";
946 OS << "} // extern \"C\"\n";
947 OS << "#endif\n\n";
948 OS << "#endif /*__ARM_FEATURE_SVE */\n\n";
Sander de Smalen5087ace2020-03-15 14:29:45 +0000949 OS << "#endif /* __ARM_SVE_H */\n";
950}
951
Sander de Smalenc5b81462020-03-18 11:07:20 +0000952void SVEEmitter::createBuiltins(raw_ostream &OS) {
953 std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst");
954 SmallVector<std::unique_ptr<Intrinsic>, 128> Defs;
955 for (auto *R : RV)
956 createIntrinsic(R, Defs);
957
958 // The mappings must be sorted based on BuiltinID.
959 llvm::sort(Defs, [](const std::unique_ptr<Intrinsic> &A,
960 const std::unique_ptr<Intrinsic> &B) {
961 return A->getMangledName() < B->getMangledName();
962 });
963
964 OS << "#ifdef GET_SVE_BUILTINS\n";
965 for (auto &Def : Defs) {
966 // Only create BUILTINs for non-overloaded intrinsics, as overloaded
967 // declarations only live in the header file.
968 if (Def->getClassKind() != ClassG)
969 OS << "BUILTIN(__builtin_sve_" << Def->getMangledName() << ", \""
970 << Def->getBuiltinTypeStr() << "\", \"n\")\n";
971 }
972 OS << "#endif\n\n";
973}
974
975void SVEEmitter::createCodeGenMap(raw_ostream &OS) {
976 std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst");
977 SmallVector<std::unique_ptr<Intrinsic>, 128> Defs;
978 for (auto *R : RV)
979 createIntrinsic(R, Defs);
980
981 // The mappings must be sorted based on BuiltinID.
982 llvm::sort(Defs, [](const std::unique_ptr<Intrinsic> &A,
983 const std::unique_ptr<Intrinsic> &B) {
984 return A->getMangledName() < B->getMangledName();
985 });
986
987 OS << "#ifdef GET_SVE_LLVM_INTRINSIC_MAP\n";
988 for (auto &Def : Defs) {
989 // Builtins only exist for non-overloaded intrinsics, overloaded
990 // declarations only live in the header file.
991 if (Def->getClassKind() == ClassG)
992 continue;
993
Sander de Smalenf6ea0262020-04-14 15:31:20 +0100994 uint64_t Flags = Def->getFlags();
Sander de Smalenc5b81462020-03-18 11:07:20 +0000995 auto FlagString = std::to_string(Flags);
996
997 std::string LLVMName = Def->getLLVMName();
998 std::string Builtin = Def->getMangledName();
999 if (!LLVMName.empty())
1000 OS << "SVEMAP1(" << Builtin << ", " << LLVMName << ", " << FlagString
1001 << "),\n";
1002 else
1003 OS << "SVEMAP2(" << Builtin << ", " << FlagString << "),\n";
1004 }
1005 OS << "#endif\n\n";
1006}
1007
Sander de Smalenc8a5b302020-04-14 15:56:36 +01001008void SVEEmitter::createRangeChecks(raw_ostream &OS) {
1009 std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst");
1010 SmallVector<std::unique_ptr<Intrinsic>, 128> Defs;
1011 for (auto *R : RV)
1012 createIntrinsic(R, Defs);
1013
1014 // The mappings must be sorted based on BuiltinID.
1015 llvm::sort(Defs, [](const std::unique_ptr<Intrinsic> &A,
1016 const std::unique_ptr<Intrinsic> &B) {
1017 return A->getMangledName() < B->getMangledName();
1018 });
1019
1020
1021 OS << "#ifdef GET_SVE_IMMEDIATE_CHECK\n";
1022
1023 // Ensure these are only emitted once.
1024 std::set<std::string> Emitted;
1025
1026 for (auto &Def : Defs) {
1027 if (Emitted.find(Def->getMangledName()) != Emitted.end() ||
1028 Def->getImmChecks().empty())
1029 continue;
1030
1031 OS << "case SVE::BI__builtin_sve_" << Def->getMangledName() << ":\n";
1032 for (auto &Check : Def->getImmChecks())
1033 OS << "ImmChecks.push_back(std::make_tuple(" << Check.getArg() << ", "
1034 << Check.getKind() << ", " << Check.getElementSizeInBits() << "));\n";
1035 OS << " break;\n";
1036
1037 Emitted.insert(Def->getMangledName());
1038 }
1039
1040 OS << "#endif\n\n";
1041}
1042
Sander de Smalenc5b81462020-03-18 11:07:20 +00001043/// Create the SVETypeFlags used in CGBuiltins
1044void SVEEmitter::createTypeFlags(raw_ostream &OS) {
1045 OS << "#ifdef LLVM_GET_SVE_TYPEFLAGS\n";
1046 for (auto &KV : FlagTypes)
1047 OS << "const uint64_t " << KV.getKey() << " = " << KV.getValue() << ";\n";
1048 OS << "#endif\n\n";
1049
1050 OS << "#ifdef LLVM_GET_SVE_ELTTYPES\n";
1051 for (auto &KV : EltTypes)
1052 OS << " " << KV.getKey() << " = " << KV.getValue() << ",\n";
1053 OS << "#endif\n\n";
1054
1055 OS << "#ifdef LLVM_GET_SVE_MEMELTTYPES\n";
1056 for (auto &KV : MemEltTypes)
1057 OS << " " << KV.getKey() << " = " << KV.getValue() << ",\n";
1058 OS << "#endif\n\n";
Sander de Smalenf6ea0262020-04-14 15:31:20 +01001059
1060 OS << "#ifdef LLVM_GET_SVE_MERGETYPES\n";
1061 for (auto &KV : MergeTypes)
1062 OS << " " << KV.getKey() << " = " << KV.getValue() << ",\n";
1063 OS << "#endif\n\n";
Sander de Smalenc8a5b302020-04-14 15:56:36 +01001064
1065 OS << "#ifdef LLVM_GET_SVE_IMMCHECKTYPES\n";
1066 for (auto &KV : ImmCheckTypes)
1067 OS << " " << KV.getKey() << " = " << KV.getValue() << ",\n";
1068 OS << "#endif\n\n";
Sander de Smalenc5b81462020-03-18 11:07:20 +00001069}
1070
Sander de Smalen5087ace2020-03-15 14:29:45 +00001071namespace clang {
1072void EmitSveHeader(RecordKeeper &Records, raw_ostream &OS) {
Sander de Smalenc5b81462020-03-18 11:07:20 +00001073 SVEEmitter(Records).createHeader(OS);
1074}
1075
1076void EmitSveBuiltins(RecordKeeper &Records, raw_ostream &OS) {
1077 SVEEmitter(Records).createBuiltins(OS);
1078}
1079
1080void EmitSveBuiltinCG(RecordKeeper &Records, raw_ostream &OS) {
1081 SVEEmitter(Records).createCodeGenMap(OS);
1082}
Sander de Smalenc8a5b302020-04-14 15:56:36 +01001083
1084void EmitSveRangeChecks(RecordKeeper &Records, raw_ostream &OS) {
1085 SVEEmitter(Records).createRangeChecks(OS);
1086}
1087
Sander de Smalenc5b81462020-03-18 11:07:20 +00001088void EmitSveTypeFlags(RecordKeeper &Records, raw_ostream &OS) {
1089 SVEEmitter(Records).createTypeFlags(OS);
Sander de Smalen5087ace2020-03-15 14:29:45 +00001090}
1091
1092} // End namespace clang