Coverage Report

Created: 2021-08-24 07:12

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