Coverage Report

Created: 2020-10-24 06:27

/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 (isVoidPointer())
366
0
    S += "v";
367
0
  else if (!isFloatingPoint())
368
0
    switch (ElementBitwidth) {
369
0
    case 1: S += "b"; break;
370
0
    case 8: S += "c"; break;
371
0
    case 16: S += "s"; break;
372
0
    case 32: S += "i"; break;
373
0
    case 64: S += "Wi"; break;
374
0
    case 128: S += "LLLi"; break;
375
0
    default: llvm_unreachable("Unhandled case!");
376
0
    }
377
0
  else if (isFloat())
378
0
    switch (ElementBitwidth) {
379
0
    case 16: S += "h"; break;
380
0
    case 32: S += "f"; break;
381
0
    case 64: S += "d"; break;
382
0
    default: llvm_unreachable("Unhandled case!");
383
0
    }
384
0
  else if (isBFloat()) {
385
0
    assert(ElementBitwidth == 16 && "Not a valid BFloat.");
386
0
    S += "y";
387
0
  }
388
389
0
  if (!isFloatingPoint()) {
390
0
    if ((isChar() || isPointer()) && !isVoidPointer()) {
391
      // Make chars and typed pointers explicitly signed.
392
0
      if (Signed)
393
0
        S = "S" + S;
394
0
      else if (!Signed)
395
0
        S = "U" + S;
396
0
    } else if (!isVoidPointer() && !Signed) {
397
0
      S = "U" + S;
398
0
    }
399
0
  }
400
401
  // Constant indices are "int", but have the "constant expression" modifier.
402
0
  if (isImmediate()) {
403
0
    assert(!isFloat() && "fp immediates are not supported");
404
0
    S = "I" + S;
405
0
  }
406
407
0
  if (isScalar()) {
408
0
    if (Constant) S += "C";
409
0
    if (Pointer) S += "*";
410
0
    return S;
411
0
  }
412
413
0
  assert(isScalableVector() && "Unsupported type");
414
0
  return "q" + utostr(getNumElements() * NumVectors) + S;
415
0
}
416
417
0
std::string SVEType::str() const {
418
0
  if (isPredicatePattern())
419
0
    return "sv_pattern";
420
421
0
  if (isPrefetchOp())
422
0
    return "sv_prfop";
423
424
0
  std::string S;
425
0
  if (Void)
426
0
    S += "void";
427
0
  else {
428
0
    if (isScalableVector())
429
0
      S += "sv";
430
0
    if (!Signed && !isFloatingPoint())
431
0
      S += "u";
432
433
0
    if (Float)
434
0
      S += "float";
435
0
    else if (isScalarPredicate() || isPredicateVector())
436
0
      S += "bool";
437
0
    else if (isBFloat())
438
0
      S += "bfloat";
439
0
    else
440
0
      S += "int";
441
442
0
    if (!isScalarPredicate() && !isPredicateVector())
443
0
      S += utostr(ElementBitwidth);
444
0
    if (!isScalableVector() && isVector())
445
0
      S += "x" + utostr(getNumElements());
446
0
    if (NumVectors > 1)
447
0
      S += "x" + utostr(NumVectors);
448
0
    if (!isScalarPredicate())
449
0
      S += "_t";
450
0
  }
451
452
0
  if (Constant)
453
0
    S += " const";
454
0
  if (Pointer)
455
0
    S += " *";
456
457
0
  return S;
458
0
}
459
0
void SVEType::applyTypespec() {
460
0
  for (char I : TS) {
461
0
    switch (I) {
462
0
    case 'P':
463
0
      Predicate = true;
464
0
      break;
465
0
    case 'U':
466
0
      Signed = false;
467
0
      break;
468
0
    case 'c':
469
0
      ElementBitwidth = 8;
470
0
      break;
471
0
    case 's':
472
0
      ElementBitwidth = 16;
473
0
      break;
474
0
    case 'i':
475
0
      ElementBitwidth = 32;
476
0
      break;
477
0
    case 'l':
478
0
      ElementBitwidth = 64;
479
0
      break;
480
0
    case 'h':
481
0
      Float = true;
482
0
      ElementBitwidth = 16;
483
0
      break;
484
0
    case 'f':
485
0
      Float = true;
486
0
      ElementBitwidth = 32;
487
0
      break;
488
0
    case 'd':
489
0
      Float = true;
490
0
      ElementBitwidth = 64;
491
0
      break;
492
0
    case 'b':
493
0
      BFloat = true;
494
0
      Float = false;
495
0
      ElementBitwidth = 16;
496
0
      break;
497
0
    default:
498
0
      llvm_unreachable("Unhandled type code!");
499
0
    }
500
0
  }
501
0
  assert(ElementBitwidth != ~0U && "Bad element bitwidth!");
502
0
}
503
504
0
void SVEType::applyModifier(char Mod) {
505
0
  switch (Mod) {
506
0
  case '2':
507
0
    NumVectors = 2;
508
0
    break;
509
0
  case '3':
510
0
    NumVectors = 3;
511
0
    break;
512
0
  case '4':
513
0
    NumVectors = 4;
514
0
    break;
515
0
  case 'v':
516
0
    Void = true;
517
0
    break;
518
0
  case 'd':
519
0
    DefaultType = true;
520
0
    break;
521
0
  case 'c':
522
0
    Constant = true;
523
0
    LLVM_FALLTHROUGH;
524
0
  case 'p':
525
0
    Pointer = true;
526
0
    Bitwidth = ElementBitwidth;
527
0
    NumVectors = 0;
528
0
    break;
529
0
  case 'e':
530
0
    Signed = false;
531
0
    ElementBitwidth /= 2;
532
0
    break;
533
0
  case 'h':
534
0
    ElementBitwidth /= 2;
535
0
    break;
536
0
  case 'q':
537
0
    ElementBitwidth /= 4;
538
0
    break;
539
0
  case 'b':
540
0
    Signed = false;
541
0
    Float = false;
542
0
    BFloat = false;
543
0
    ElementBitwidth /= 4;
544
0
    break;
545
0
  case 'o':
546
0
    ElementBitwidth *= 4;
547
0
    break;
548
0
  case 'P':
549
0
    Signed = true;
550
0
    Float = false;
551
0
    BFloat = false;
552
0
    Predicate = true;
553
0
    Bitwidth = 16;
554
0
    ElementBitwidth = 1;
555
0
    break;
556
0
  case 's':
557
0
  case 'a':
558
0
    Bitwidth = ElementBitwidth;
559
0
    NumVectors = 0;
560
0
    break;
561
0
  case 'R':
562
0
    ElementBitwidth /= 2;
563
0
    NumVectors = 0;
564
0
    break;
565
0
  case 'r':
566
0
    ElementBitwidth /= 4;
567
0
    NumVectors = 0;
568
0
    break;
569
0
  case '@':
570
0
    Signed = false;
571
0
    Float = false;
572
0
    BFloat = false;
573
0
    ElementBitwidth /= 4;
574
0
    NumVectors = 0;
575
0
    break;
576
0
  case 'K':
577
0
    Signed = true;
578
0
    Float = false;
579
0
    BFloat = false;
580
0
    Bitwidth = ElementBitwidth;
581
0
    NumVectors = 0;
582
0
    break;
583
0
  case 'L':
584
0
    Signed = false;
585
0
    Float = false;
586
0
    BFloat = false;
587
0
    Bitwidth = ElementBitwidth;
588
0
    NumVectors = 0;
589
0
    break;
590
0
  case 'u':
591
0
    Predicate = false;
592
0
    Signed = false;
593
0
    Float = false;
594
0
    BFloat = false;
595
0
    break;
596
0
  case 'x':
597
0
    Predicate = false;
598
0
    Signed = true;
599
0
    Float = false;
600
0
    BFloat = false;
601
0
    break;
602
0
  case 'i':
603
0
    Predicate = false;
604
0
    Float = false;
605
0
    BFloat = false;
606
0
    ElementBitwidth = Bitwidth = 64;
607
0
    NumVectors = 0;
608
0
    Signed = false;
609
0
    Immediate = true;
610
0
    break;
611
0
  case 'I':
612
0
    Predicate = false;
613
0
    Float = false;
614
0
    BFloat = false;
615
0
    ElementBitwidth = Bitwidth = 32;
616
0
    NumVectors = 0;
617
0
    Signed = true;
618
0
    Immediate = true;
619
0
    PredicatePattern = true;
620
0
    break;
621
0
  case 'J':
622
0
    Predicate = false;
623
0
    Float = false;
624
0
    BFloat = false;
625
0
    ElementBitwidth = Bitwidth = 32;
626
0
    NumVectors = 0;
627
0
    Signed = true;
628
0
    Immediate = true;
629
0
    PrefetchOp = true;
630
0
    break;
631
0
  case 'k':
632
0
    Predicate = false;
633
0
    Signed = true;
634
0
    Float = false;
635
0
    BFloat = false;
636
0
    ElementBitwidth = Bitwidth = 32;
637
0
    NumVectors = 0;
638
0
    break;
639
0
  case 'l':
640
0
    Predicate = false;
641
0
    Signed = true;
642
0
    Float = false;
643
0
    BFloat = false;
644
0
    ElementBitwidth = Bitwidth = 64;
645
0
    NumVectors = 0;
646
0
    break;
647
0
  case 'm':
648
0
    Predicate = false;
649
0
    Signed = false;
650
0
    Float = false;
651
0
    BFloat = false;
652
0
    ElementBitwidth = Bitwidth = 32;
653
0
    NumVectors = 0;
654
0
    break;
655
0
  case 'n':
656
0
    Predicate = false;
657
0
    Signed = false;
658
0
    Float = false;
659
0
    BFloat = false;
660
0
    ElementBitwidth = Bitwidth = 64;
661
0
    NumVectors = 0;
662
0
    break;
663
0
  case 'w':
664
0
    ElementBitwidth = 64;
665
0
    break;
666
0
  case 'j':
667
0
    ElementBitwidth = Bitwidth = 64;
668
0
    NumVectors = 0;
669
0
    break;
670
0
  case 'f':
671
0
    Signed = false;
672
0
    ElementBitwidth = Bitwidth = 64;
673
0
    NumVectors = 0;
674
0
    break;
675
0
  case 'g':
676
0
    Signed = false;
677
0
    Float = false;
678
0
    BFloat = false;
679
0
    ElementBitwidth = 64;
680
0
    break;
681
0
  case 't':
682
0
    Signed = true;
683
0
    Float = false;
684
0
    BFloat = false;
685
0
    ElementBitwidth = 32;
686
0
    break;
687
0
  case 'z':
688
0
    Signed = false;
689
0
    Float = false;
690
0
    BFloat = false;
691
0
    ElementBitwidth = 32;
692
0
    break;
693
0
  case 'O':
694
0
    Predicate = false;
695
0
    Float = true;
696
0
    ElementBitwidth = 16;
697
0
    break;
698
0
  case 'M':
699
0
    Predicate = false;
700
0
    Float = true;
701
0
    BFloat = false;
702
0
    ElementBitwidth = 32;
703
0
    break;
704
0
  case 'N':
705
0
    Predicate = false;
706
0
    Float = true;
707
0
    ElementBitwidth = 64;
708
0
    break;
709
0
  case 'Q':
710
0
    Constant = true;
711
0
    Pointer = true;
712
0
    Void = true;
713
0
    NumVectors = 0;
714
0
    break;
715
0
  case 'S':
716
0
    Constant = true;
717
0
    Pointer = true;
718
0
    ElementBitwidth = Bitwidth = 8;
719
0
    NumVectors = 0;
720
0
    Signed = true;
721
0
    break;
722
0
  case 'W':
723
0
    Constant = true;
724
0
    Pointer = true;
725
0
    ElementBitwidth = Bitwidth = 8;
726
0
    NumVectors = 0;
727
0
    Signed = false;
728
0
    break;
729
0
  case 'T':
730
0
    Constant = true;
731
0
    Pointer = true;
732
0
    ElementBitwidth = Bitwidth = 16;
733
0
    NumVectors = 0;
734
0
    Signed = true;
735
0
    break;
736
0
  case 'X':
737
0
    Constant = true;
738
0
    Pointer = true;
739
0
    ElementBitwidth = Bitwidth = 16;
740
0
    NumVectors = 0;
741
0
    Signed = false;
742
0
    break;
743
0
  case 'Y':
744
0
    Constant = true;
745
0
    Pointer = true;
746
0
    ElementBitwidth = Bitwidth = 32;
747
0
    NumVectors = 0;
748
0
    Signed = false;
749
0
    break;
750
0
  case 'U':
751
0
    Constant = true;
752
0
    Pointer = true;
753
0
    ElementBitwidth = Bitwidth = 32;
754
0
    NumVectors = 0;
755
0
    Signed = true;
756
0
    break;
757
0
  case 'A':
758
0
    Pointer = true;
759
0
    ElementBitwidth = Bitwidth = 8;
760
0
    NumVectors = 0;
761
0
    Signed = true;
762
0
    break;
763
0
  case 'B':
764
0
    Pointer = true;
765
0
    ElementBitwidth = Bitwidth = 16;
766
0
    NumVectors = 0;
767
0
    Signed = true;
768
0
    break;
769
0
  case 'C':
770
0
    Pointer = true;
771
0
    ElementBitwidth = Bitwidth = 32;
772
0
    NumVectors = 0;
773
0
    Signed = true;
774
0
    break;
775
0
  case 'D':
776
0
    Pointer = true;
777
0
    ElementBitwidth = Bitwidth = 64;
778
0
    NumVectors = 0;
779
0
    Signed = true;
780
0
    break;
781
0
  case 'E':
782
0
    Pointer = true;
783
0
    ElementBitwidth = Bitwidth = 8;
784
0
    NumVectors = 0;
785
0
    Signed = false;
786
0
    break;
787
0
  case 'F':
788
0
    Pointer = true;
789
0
    ElementBitwidth = Bitwidth = 16;
790
0
    NumVectors = 0;
791
0
    Signed = false;
792
0
    break;
793
0
  case 'G':
794
0
    Pointer = true;
795
0
    ElementBitwidth = Bitwidth = 32;
796
0
    NumVectors = 0;
797
0
    Signed = false;
798
0
    break;
799
0
  default:
800
0
    llvm_unreachable("Unhandled character!");
801
0
  }
802
0
}
803
804
805
//===----------------------------------------------------------------------===//
806
// Intrinsic implementation
807
//===----------------------------------------------------------------------===//
808
809
Intrinsic::Intrinsic(StringRef Name, StringRef Proto, uint64_t MergeTy,
810
                     StringRef MergeSuffix, uint64_t MemoryElementTy,
811
                     StringRef LLVMName, uint64_t Flags,
812
                     ArrayRef<ImmCheck> Checks, TypeSpec BT, ClassKind Class,
813
                     SVEEmitter &Emitter, StringRef Guard)
814
    : Name(Name.str()), LLVMName(LLVMName), Proto(Proto.str()),
815
      BaseTypeSpec(BT), Class(Class), Guard(Guard.str()),
816
      MergeSuffix(MergeSuffix.str()), BaseType(BT, 'd'), Flags(Flags),
817
0
      ImmChecks(Checks.begin(), Checks.end()) {
818
  // Types[0] is the return value.
819
0
  for (unsigned I = 0; I < Proto.size(); ++I) {
820
0
    SVEType T(BaseTypeSpec, Proto[I]);
821
0
    Types.push_back(T);
822
823
    // Add range checks for immediates
824
0
    if (I > 0) {
825
0
      if (T.isPredicatePattern())
826
0
        ImmChecks.emplace_back(
827
0
            I - 1, Emitter.getEnumValueForImmCheck("ImmCheck0_31"));
828
0
      else if (T.isPrefetchOp())
829
0
        ImmChecks.emplace_back(
830
0
            I - 1, Emitter.getEnumValueForImmCheck("ImmCheck0_13"));
831
0
    }
832
0
  }
833
834
  // Set flags based on properties
835
0
  this->Flags |= Emitter.encodeTypeFlags(BaseType);
836
0
  this->Flags |= Emitter.encodeMemoryElementType(MemoryElementTy);
837
0
  this->Flags |= Emitter.encodeMergeType(MergeTy);
838
0
  if (hasSplat())
839
0
    this->Flags |= Emitter.encodeSplatOperand(getSplatIdx());
840
0
}
841
842
0
std::string Intrinsic::getBuiltinTypeStr() {
843
0
  std::string S = getReturnType().builtin_str();
844
0
  for (unsigned I = 0; I < getNumParams(); ++I)
845
0
    S += getParamType(I).builtin_str();
846
847
0
  return S;
848
0
}
849
850
std::string Intrinsic::replaceTemplatedArgs(std::string Name, TypeSpec TS,
851
0
                                            std::string Proto) const {
852
0
  std::string Ret = Name;
853
0
  while (Ret.find('{') != std::string::npos) {
854
0
    size_t Pos = Ret.find('{');
855
0
    size_t End = Ret.find('}');
856
0
    unsigned NumChars = End - Pos + 1;
857
0
    assert(NumChars == 3 && "Unexpected template argument");
858
859
0
    SVEType T;
860
0
    char C = Ret[Pos+1];
861
0
    switch(C) {
862
0
    default:
863
0
      llvm_unreachable("Unknown predication specifier");
864
0
    case 'd':
865
0
      T = SVEType(TS, 'd');
866
0
      break;
867
0
    case '0':
868
0
    case '1':
869
0
    case '2':
870
0
    case '3':
871
0
      T = SVEType(TS, Proto[C - '0']);
872
0
      break;
873
0
    }
874
875
    // Replace templated arg with the right suffix (e.g. u32)
876
0
    std::string TypeCode;
877
0
    if (T.isInteger())
878
0
      TypeCode = T.isSigned() ? 's' : 'u';
879
0
    else if (T.isPredicateVector())
880
0
      TypeCode = 'b';
881
0
    else if (T.isBFloat())
882
0
      TypeCode = "bf";
883
0
    else
884
0
      TypeCode = 'f';
885
0
    Ret.replace(Pos, NumChars, TypeCode + utostr(T.getElementSizeInBits()));
886
0
  }
887
888
0
  return Ret;
889
0
}
890
891
0
std::string Intrinsic::mangleName(ClassKind LocalCK) const {
892
0
  std::string S = getName();
893
894
0
  if (LocalCK == ClassG) {
895
    // Remove the square brackets and everything in between.
896
0
    while (S.find("[") != std::string::npos) {
897
0
      auto Start = S.find("[");
898
0
      auto End = S.find(']');
899
0
      S.erase(Start, (End-Start)+1);
900
0
    }
901
0
  } else {
902
    // Remove the square brackets.
903
0
    while (S.find("[") != std::string::npos) {
904
0
      auto BrPos = S.find('[');
905
0
      if (BrPos != std::string::npos)
906
0
        S.erase(BrPos, 1);
907
0
      BrPos = S.find(']');
908
0
      if (BrPos != std::string::npos)
909
0
        S.erase(BrPos, 1);
910
0
    }
911
0
  }
912
913
  // Replace all {d} like expressions with e.g. 'u32'
914
0
  return replaceTemplatedArgs(S, getBaseTypeSpec(), getProto()) +
915
0
         getMergeSuffix();
916
0
}
917
918
0
void Intrinsic::emitIntrinsic(raw_ostream &OS) const {
919
  // Use the preprocessor to 
920
0
  if (getClassKind() != ClassG || getProto().size() <= 1) {
921
0
    OS << "#define " << mangleName(getClassKind())
922
0
       << "(...) __builtin_sve_" << mangleName(ClassS)
923
0
       << "(__VA_ARGS__)\n";
924
0
  } else {
925
0
    std::string FullName = mangleName(ClassS);
926
0
    std::string ProtoName = mangleName(ClassG);
927
928
0
    OS << "__aio __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
0
}
940
941
//===----------------------------------------------------------------------===//
942
// SVEEmitter implementation
943
//===----------------------------------------------------------------------===//
944
0
uint64_t SVEEmitter::encodeTypeFlags(const SVEType &T) {
945
0
  if (T.isFloat()) {
946
0
    switch (T.getElementSizeInBits()) {
947
0
    case 16:
948
0
      return encodeEltType("EltTyFloat16");
949
0
    case 32:
950
0
      return encodeEltType("EltTyFloat32");
951
0
    case 64:
952
0
      return encodeEltType("EltTyFloat64");
953
0
    default:
954
0
      llvm_unreachable("Unhandled float element bitwidth!");
955
0
    }
956
0
  }
957
958
0
  if (T.isBFloat()) {
959
0
    assert(T.getElementSizeInBits() == 16 && "Not a valid BFloat.");
960
0
    return encodeEltType("EltTyBFloat16");
961
0
  }
962
963
0
  if (T.isPredicateVector()) {
964
0
    switch (T.getElementSizeInBits()) {
965
0
    case 8:
966
0
      return encodeEltType("EltTyBool8");
967
0
    case 16:
968
0
      return encodeEltType("EltTyBool16");
969
0
    case 32:
970
0
      return encodeEltType("EltTyBool32");
971
0
    case 64:
972
0
      return encodeEltType("EltTyBool64");
973
0
    default:
974
0
      llvm_unreachable("Unhandled predicate element bitwidth!");
975
0
    }
976
0
  }
977
978
0
  switch (T.getElementSizeInBits()) {
979
0
  case 8:
980
0
    return encodeEltType("EltTyInt8");
981
0
  case 16:
982
0
    return encodeEltType("EltTyInt16");
983
0
  case 32:
984
0
    return encodeEltType("EltTyInt32");
985
0
  case 64:
986
0
    return encodeEltType("EltTyInt64");
987
0
  default:
988
0
    llvm_unreachable("Unhandled integer element bitwidth!");
989
0
  }
990
0
}
991
992
void SVEEmitter::createIntrinsic(
993
0
    Record *R, SmallVectorImpl<std::unique_ptr<Intrinsic>> &Out) {
994
0
  StringRef Name = R->getValueAsString("Name");
995
0
  StringRef Proto = R->getValueAsString("Prototype");
996
0
  StringRef Types = R->getValueAsString("Types");
997
0
  StringRef Guard = R->getValueAsString("ArchGuard");
998
0
  StringRef LLVMName = R->getValueAsString("LLVMIntrinsic");
999
0
  uint64_t Merge = R->getValueAsInt("Merge");
1000
0
  StringRef MergeSuffix = R->getValueAsString("MergeSuffix");
1001
0
  uint64_t MemEltType = R->getValueAsInt("MemEltType");
1002
0
  std::vector<Record*> FlagsList = R->getValueAsListOfDefs("Flags");
1003
0
  std::vector<Record*> ImmCheckList = R->getValueAsListOfDefs("ImmChecks");
1004
1005
0
  int64_t Flags = 0;
1006
0
  for (auto FlagRec : FlagsList)
1007
0
    Flags |= FlagRec->getValueAsInt("Value");
1008
1009
  // Create a dummy TypeSpec for non-overloaded builtins.
1010
0
  if (Types.empty()) {
1011
0
    assert((Flags & getEnumValueForFlag("IsOverloadNone")) &&
1012
0
           "Expect TypeSpec for overloaded builtin!");
1013
0
    Types = "i";
1014
0
  }
1015
1016
  // Extract type specs from string
1017
0
  SmallVector<TypeSpec, 8> TypeSpecs;
1018
0
  TypeSpec Acc;
1019
0
  for (char I : Types) {
1020
0
    Acc.push_back(I);
1021
0
    if (islower(I)) {
1022
0
      TypeSpecs.push_back(TypeSpec(Acc));
1023
0
      Acc.clear();
1024
0
    }
1025
0
  }
1026
1027
  // Remove duplicate type specs.
1028
0
  llvm::sort(TypeSpecs);
1029
0
  TypeSpecs.erase(std::unique(TypeSpecs.begin(), TypeSpecs.end()),
1030
0
                  TypeSpecs.end());
1031
1032
  // Create an Intrinsic for each type spec.
1033
0
  for (auto TS : TypeSpecs) {
1034
    // Collate a list of range/option checks for the immediates.
1035
0
    SmallVector<ImmCheck, 2> ImmChecks;
1036
0
    for (auto *R : ImmCheckList) {
1037
0
      int64_t Arg = R->getValueAsInt("Arg");
1038
0
      int64_t EltSizeArg = R->getValueAsInt("EltSizeArg");
1039
0
      int64_t Kind = R->getValueAsDef("Kind")->getValueAsInt("Value");
1040
0
      assert(Arg >= 0 && Kind >= 0 && "Arg and Kind must be nonnegative");
1041
1042
0
      unsigned ElementSizeInBits = 0;
1043
0
      if (EltSizeArg >= 0)
1044
0
        ElementSizeInBits =
1045
0
            SVEType(TS, Proto[EltSizeArg + /* offset by return arg */ 1])
1046
0
                .getElementSizeInBits();
1047
0
      ImmChecks.push_back(ImmCheck(Arg, Kind, ElementSizeInBits));
1048
0
    }
1049
1050
0
    Out.push_back(std::make_unique<Intrinsic>(
1051
0
        Name, Proto, Merge, MergeSuffix, MemEltType, LLVMName, Flags, ImmChecks,
1052
0
        TS, ClassS, *this, Guard));
1053
1054
    // Also generate the short-form (e.g. svadd_m) for the given type-spec.
1055
0
    if (Intrinsic::isOverloadedIntrinsic(Name))
1056
0
      Out.push_back(std::make_unique<Intrinsic>(
1057
0
          Name, Proto, Merge, MergeSuffix, MemEltType, LLVMName, Flags,
1058
0
          ImmChecks, TS, ClassG, *this, Guard));
1059
0
  }
1060
0
}
1061
1062
0
void SVEEmitter::createHeader(raw_ostream &OS) {
1063
0
  OS << "/*===---- arm_sve.h - ARM SVE intrinsics "
1064
0
        "-----------------------------------===\n"
1065
0
        " *\n"
1066
0
        " *\n"
1067
0
        " * Part of the LLVM Project, under the Apache License v2.0 with LLVM "
1068
0
        "Exceptions.\n"
1069
0
        " * See https://llvm.org/LICENSE.txt for license information.\n"
1070
0
        " * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception\n"
1071
0
        " *\n"
1072
0
        " *===-----------------------------------------------------------------"
1073
0
        "------===\n"
1074
0
        " */\n\n";
1075
1076
0
  OS << "#ifndef __ARM_SVE_H\n";
1077
0
  OS << "#define __ARM_SVE_H\n\n";
1078
1079
0
  OS << "#if !defined(__ARM_FEATURE_SVE)\n";
1080
0
  OS << "#error \"SVE support not enabled\"\n";
1081
0
  OS << "#else\n\n";
1082
1083
0
  OS << "#if !defined(__LITTLE_ENDIAN__)\n";
1084
0
  OS << "#error \"Big endian is currently not supported for arm_sve.h\"\n";
1085
0
  OS << "#endif\n";
1086
1087
0
  OS << "#include <stdint.h>\n\n";
1088
0
  OS << "#ifdef  __cplusplus\n";
1089
0
  OS << "extern \"C\" {\n";
1090
0
  OS << "#else\n";
1091
0
  OS << "#include <stdbool.h>\n";
1092
0
  OS << "#endif\n\n";
1093
1094
0
  OS << "typedef __fp16 float16_t;\n";
1095
0
  OS << "typedef float float32_t;\n";
1096
0
  OS << "typedef double float64_t;\n";
1097
1098
0
  OS << "typedef __SVInt8_t svint8_t;\n";
1099
0
  OS << "typedef __SVInt16_t svint16_t;\n";
1100
0
  OS << "typedef __SVInt32_t svint32_t;\n";
1101
0
  OS << "typedef __SVInt64_t svint64_t;\n";
1102
0
  OS << "typedef __SVUint8_t svuint8_t;\n";
1103
0
  OS << "typedef __SVUint16_t svuint16_t;\n";
1104
0
  OS << "typedef __SVUint32_t svuint32_t;\n";
1105
0
  OS << "typedef __SVUint64_t svuint64_t;\n";
1106
0
  OS << "typedef __SVFloat16_t svfloat16_t;\n\n";
1107
1108
0
  OS << "#if defined(__ARM_FEATURE_SVE_BF16) && "
1109
0
        "!defined(__ARM_FEATURE_BF16_SCALAR_ARITHMETIC)\n";
1110
0
  OS << "#error \"__ARM_FEATURE_BF16_SCALAR_ARITHMETIC must be defined when "
1111
0
        "__ARM_FEATURE_SVE_BF16 is defined\"\n";
1112
0
  OS << "#endif\n\n";
1113
1114
0
  OS << "#if defined(__ARM_FEATURE_SVE_BF16)\n";
1115
0
  OS << "typedef __SVBFloat16_t svbfloat16_t;\n";
1116
0
  OS << "#endif\n\n";
1117
1118
0
  OS << "#if defined(__ARM_FEATURE_BF16_SCALAR_ARITHMETIC)\n";
1119
0
  OS << "#include <arm_bf16.h>\n";
1120
0
  OS << "typedef __bf16 bfloat16_t;\n";
1121
0
  OS << "#endif\n\n";
1122
1123
0
  OS << "typedef __SVFloat32_t svfloat32_t;\n";
1124
0
  OS << "typedef __SVFloat64_t svfloat64_t;\n";
1125
0
  OS << "typedef __clang_svint8x2_t svint8x2_t;\n";
1126
0
  OS << "typedef __clang_svint16x2_t svint16x2_t;\n";
1127
0
  OS << "typedef __clang_svint32x2_t svint32x2_t;\n";
1128
0
  OS << "typedef __clang_svint64x2_t svint64x2_t;\n";
1129
0
  OS << "typedef __clang_svuint8x2_t svuint8x2_t;\n";
1130
0
  OS << "typedef __clang_svuint16x2_t svuint16x2_t;\n";
1131
0
  OS << "typedef __clang_svuint32x2_t svuint32x2_t;\n";
1132
0
  OS << "typedef __clang_svuint64x2_t svuint64x2_t;\n";
1133
0
  OS << "typedef __clang_svfloat16x2_t svfloat16x2_t;\n";
1134
0
  OS << "typedef __clang_svfloat32x2_t svfloat32x2_t;\n";
1135
0
  OS << "typedef __clang_svfloat64x2_t svfloat64x2_t;\n";
1136
0
  OS << "typedef __clang_svint8x3_t svint8x3_t;\n";
1137
0
  OS << "typedef __clang_svint16x3_t svint16x3_t;\n";
1138
0
  OS << "typedef __clang_svint32x3_t svint32x3_t;\n";
1139
0
  OS << "typedef __clang_svint64x3_t svint64x3_t;\n";
1140
0
  OS << "typedef __clang_svuint8x3_t svuint8x3_t;\n";
1141
0
  OS << "typedef __clang_svuint16x3_t svuint16x3_t;\n";
1142
0
  OS << "typedef __clang_svuint32x3_t svuint32x3_t;\n";
1143
0
  OS << "typedef __clang_svuint64x3_t svuint64x3_t;\n";
1144
0
  OS << "typedef __clang_svfloat16x3_t svfloat16x3_t;\n";
1145
0
  OS << "typedef __clang_svfloat32x3_t svfloat32x3_t;\n";
1146
0
  OS << "typedef __clang_svfloat64x3_t svfloat64x3_t;\n";
1147
0
  OS << "typedef __clang_svint8x4_t svint8x4_t;\n";
1148
0
  OS << "typedef __clang_svint16x4_t svint16x4_t;\n";
1149
0
  OS << "typedef __clang_svint32x4_t svint32x4_t;\n";
1150
0
  OS << "typedef __clang_svint64x4_t svint64x4_t;\n";
1151
0
  OS << "typedef __clang_svuint8x4_t svuint8x4_t;\n";
1152
0
  OS << "typedef __clang_svuint16x4_t svuint16x4_t;\n";
1153
0
  OS << "typedef __clang_svuint32x4_t svuint32x4_t;\n";
1154
0
  OS << "typedef __clang_svuint64x4_t svuint64x4_t;\n";
1155
0
  OS << "typedef __clang_svfloat16x4_t svfloat16x4_t;\n";
1156
0
  OS << "typedef __clang_svfloat32x4_t svfloat32x4_t;\n";
1157
0
  OS << "typedef __clang_svfloat64x4_t svfloat64x4_t;\n";
1158
0
  OS << "typedef __SVBool_t  svbool_t;\n\n";
1159
1160
0
  OS << "#ifdef __ARM_FEATURE_SVE_BF16\n";
1161
0
  OS << "typedef __clang_svbfloat16x2_t svbfloat16x2_t;\n";
1162
0
  OS << "typedef __clang_svbfloat16x3_t svbfloat16x3_t;\n";
1163
0
  OS << "typedef __clang_svbfloat16x4_t svbfloat16x4_t;\n";
1164
0
  OS << "#endif\n";
1165
1166
0
  OS << "typedef enum\n";
1167
0
  OS << "{\n";
1168
0
  OS << "  SV_POW2 = 0,\n";
1169
0
  OS << "  SV_VL1 = 1,\n";
1170
0
  OS << "  SV_VL2 = 2,\n";
1171
0
  OS << "  SV_VL3 = 3,\n";
1172
0
  OS << "  SV_VL4 = 4,\n";
1173
0
  OS << "  SV_VL5 = 5,\n";
1174
0
  OS << "  SV_VL6 = 6,\n";
1175
0
  OS << "  SV_VL7 = 7,\n";
1176
0
  OS << "  SV_VL8 = 8,\n";
1177
0
  OS << "  SV_VL16 = 9,\n";
1178
0
  OS << "  SV_VL32 = 10,\n";
1179
0
  OS << "  SV_VL64 = 11,\n";
1180
0
  OS << "  SV_VL128 = 12,\n";
1181
0
  OS << "  SV_VL256 = 13,\n";
1182
0
  OS << "  SV_MUL4 = 29,\n";
1183
0
  OS << "  SV_MUL3 = 30,\n";
1184
0
  OS << "  SV_ALL = 31\n";
1185
0
  OS << "} sv_pattern;\n\n";
1186
1187
0
  OS << "typedef enum\n";
1188
0
  OS << "{\n";
1189
0
  OS << "  SV_PLDL1KEEP = 0,\n";
1190
0
  OS << "  SV_PLDL1STRM = 1,\n";
1191
0
  OS << "  SV_PLDL2KEEP = 2,\n";
1192
0
  OS << "  SV_PLDL2STRM = 3,\n";
1193
0
  OS << "  SV_PLDL3KEEP = 4,\n";
1194
0
  OS << "  SV_PLDL3STRM = 5,\n";
1195
0
  OS << "  SV_PSTL1KEEP = 8,\n";
1196
0
  OS << "  SV_PSTL1STRM = 9,\n";
1197
0
  OS << "  SV_PSTL2KEEP = 10,\n";
1198
0
  OS << "  SV_PSTL2STRM = 11,\n";
1199
0
  OS << "  SV_PSTL3KEEP = 12,\n";
1200
0
  OS << "  SV_PSTL3STRM = 13\n";
1201
0
  OS << "} sv_prfop;\n\n";
1202
1203
0
  OS << "/* Function attributes */\n";
1204
0
  OS << "#define __aio static inline __attribute__((__always_inline__, "
1205
0
        "__nodebug__, __overloadable__))\n\n";
1206
1207
  // Add reinterpret functions.
1208
0
  for (auto ShortForm : { false, true } )
1209
0
    for (const ReinterpretTypeInfo &From : Reinterprets)
1210
0
      for (const ReinterpretTypeInfo &To : Reinterprets) {
1211
0
        const bool IsBFloat = StringRef(From.Suffix).equals("bf16") ||
1212
0
                              StringRef(To.Suffix).equals("bf16");
1213
0
        if (IsBFloat)
1214
0
          OS << "#if defined(__ARM_FEATURE_SVE_BF16)\n";
1215
0
        if (ShortForm) {
1216
0
          OS << "__aio " << From.Type << " svreinterpret_" << From.Suffix;
1217
0
          OS << "(" << To.Type << " op) {\n";
1218
0
          OS << "  return __builtin_sve_reinterpret_" << From.Suffix << "_"
1219
0
             << To.Suffix << "(op);\n";
1220
0
          OS << "}\n\n";
1221
0
        } else
1222
0
          OS << "#define svreinterpret_" << From.Suffix << "_" << To.Suffix
1223
0
             << "(...) __builtin_sve_reinterpret_" << From.Suffix << "_"
1224
0
             << To.Suffix << "(__VA_ARGS__)\n";
1225
0
        if (IsBFloat)
1226
0
          OS << "#endif /* #if defined(__ARM_FEATURE_SVE_BF16) */\n";
1227
0
      }
1228
1229
0
  SmallVector<std::unique_ptr<Intrinsic>, 128> Defs;
1230
0
  std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst");
1231
0
  for (auto *R : RV)
1232
0
    createIntrinsic(R, Defs);
1233
1234
  // Sort intrinsics in header file by following order/priority:
1235
  // - Architectural guard (i.e. does it require SVE2 or SVE2_AES)
1236
  // - Class (is intrinsic overloaded or not)
1237
  // - Intrinsic name
1238
0
  std::stable_sort(
1239
0
      Defs.begin(), Defs.end(), [](const std::unique_ptr<Intrinsic> &A,
1240
0
                                   const std::unique_ptr<Intrinsic> &B) {
1241
0
        auto ToTuple = [](const std::unique_ptr<Intrinsic> &I) {
1242
0
          return std::make_tuple(I->getGuard(), (unsigned)I->getClassKind(), I->getName());
1243
0
        };
1244
0
        return ToTuple(A) < ToTuple(B);
1245
0
      });
1246
1247
0
  StringRef InGuard = "";
1248
0
  for (auto &I : Defs) {
1249
    // Emit #endif/#if pair if needed.
1250
0
    if (I->getGuard() != InGuard) {
1251
0
      if (!InGuard.empty())
1252
0
        OS << "#endif  //" << InGuard << "\n";
1253
0
      InGuard = I->getGuard();
1254
0
      if (!InGuard.empty())
1255
0
        OS << "\n#if " << InGuard << "\n";
1256
0
    }
1257
1258
    // Actually emit the intrinsic declaration.
1259
0
    I->emitIntrinsic(OS);
1260
0
  }
1261
1262
0
  if (!InGuard.empty())
1263
0
    OS << "#endif  //" << InGuard << "\n";
1264
1265
0
  OS << "#if defined(__ARM_FEATURE_SVE_BF16)\n";
1266
0
  OS << "#define svcvtnt_bf16_x      svcvtnt_bf16_m\n";
1267
0
  OS << "#define svcvtnt_bf16_f32_x  svcvtnt_bf16_f32_m\n";
1268
0
  OS << "#endif /*__ARM_FEATURE_SVE_BF16 */\n\n";
1269
1270
0
  OS << "#if defined(__ARM_FEATURE_SVE2)\n";
1271
0
  OS << "#define svcvtnt_f16_x      svcvtnt_f16_m\n";
1272
0
  OS << "#define svcvtnt_f16_f32_x  svcvtnt_f16_f32_m\n";
1273
0
  OS << "#define svcvtnt_f32_x      svcvtnt_f32_m\n";
1274
0
  OS << "#define svcvtnt_f32_f64_x  svcvtnt_f32_f64_m\n\n";
1275
1276
0
  OS << "#define svcvtxnt_f32_x     svcvtxnt_f32_m\n";
1277
0
  OS << "#define svcvtxnt_f32_f64_x svcvtxnt_f32_f64_m\n\n";
1278
1279
0
  OS << "#endif /*__ARM_FEATURE_SVE2 */\n\n";
1280
1281
0
  OS << "#ifdef __cplusplus\n";
1282
0
  OS << "} // extern \"C\"\n";
1283
0
  OS << "#endif\n\n";
1284
0
  OS << "#endif /*__ARM_FEATURE_SVE */\n\n";
1285
0
  OS << "#endif /* __ARM_SVE_H */\n";
1286
0
}
1287
1288
0
void SVEEmitter::createBuiltins(raw_ostream &OS) {
1289
0
  std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst");
1290
0
  SmallVector<std::unique_ptr<Intrinsic>, 128> Defs;
1291
0
  for (auto *R : RV)
1292
0
    createIntrinsic(R, Defs);
1293
1294
  // The mappings must be sorted based on BuiltinID.
1295
0
  llvm::sort(Defs, [](const std::unique_ptr<Intrinsic> &A,
1296
0
                      const std::unique_ptr<Intrinsic> &B) {
1297
0
    return A->getMangledName() < B->getMangledName();
1298
0
  });
1299
1300
0
  OS << "#ifdef GET_SVE_BUILTINS\n";
1301
0
  for (auto &Def : Defs) {
1302
    // Only create BUILTINs for non-overloaded intrinsics, as overloaded
1303
    // declarations only live in the header file.
1304
0
    if (Def->getClassKind() != ClassG)
1305
0
      OS << "BUILTIN(__builtin_sve_" << Def->getMangledName() << ", \""
1306
0
         << Def->getBuiltinTypeStr() << "\", \"n\")\n";
1307
0
  }
1308
1309
  // Add reinterpret builtins
1310
0
  for (const ReinterpretTypeInfo &From : Reinterprets)
1311
0
    for (const ReinterpretTypeInfo &To : Reinterprets)
1312
0
      OS << "BUILTIN(__builtin_sve_reinterpret_" << From.Suffix << "_"
1313
0
         << To.Suffix << +", \"" << From.BuiltinType << To.BuiltinType
1314
0
         << "\", \"n\")\n";
1315
1316
0
  OS << "#endif\n\n";
1317
0
  }
1318
1319
0
void SVEEmitter::createCodeGenMap(raw_ostream &OS) {
1320
0
  std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst");
1321
0
  SmallVector<std::unique_ptr<Intrinsic>, 128> Defs;
1322
0
  for (auto *R : RV)
1323
0
    createIntrinsic(R, Defs);
1324
1325
  // The mappings must be sorted based on BuiltinID.
1326
0
  llvm::sort(Defs, [](const std::unique_ptr<Intrinsic> &A,
1327
0
                      const std::unique_ptr<Intrinsic> &B) {
1328
0
    return A->getMangledName() < B->getMangledName();
1329
0
  });
1330
1331
0
  OS << "#ifdef GET_SVE_LLVM_INTRINSIC_MAP\n";
1332
0
  for (auto &Def : Defs) {
1333
    // Builtins only exist for non-overloaded intrinsics, overloaded
1334
    // declarations only live in the header file.
1335
0
    if (Def->getClassKind() == ClassG)
1336
0
      continue;
1337
1338
0
    uint64_t Flags = Def->getFlags();
1339
0
    auto FlagString = std::to_string(Flags);
1340
1341
0
    std::string LLVMName = Def->getLLVMName();
1342
0
    std::string Builtin = Def->getMangledName();
1343
0
    if (!LLVMName.empty())
1344
0
      OS << "SVEMAP1(" << Builtin << ", " << LLVMName << ", " << FlagString
1345
0
         << "),\n";
1346
0
    else
1347
0
      OS << "SVEMAP2(" << Builtin << ", " << FlagString << "),\n";
1348
0
  }
1349
0
  OS << "#endif\n\n";
1350
0
}
1351
1352
0
void SVEEmitter::createRangeChecks(raw_ostream &OS) {
1353
0
  std::vector<Record *> RV = Records.getAllDerivedDefinitions("Inst");
1354
0
  SmallVector<std::unique_ptr<Intrinsic>, 128> Defs;
1355
0
  for (auto *R : RV)
1356
0
    createIntrinsic(R, Defs);
1357
1358
  // The mappings must be sorted based on BuiltinID.
1359
0
  llvm::sort(Defs, [](const std::unique_ptr<Intrinsic> &A,
1360
0
                      const std::unique_ptr<Intrinsic> &B) {
1361
0
    return A->getMangledName() < B->getMangledName();
1362
0
  });
1363
1364
1365
0
  OS << "#ifdef GET_SVE_IMMEDIATE_CHECK\n";
1366
1367
  // Ensure these are only emitted once.
1368
0
  std::set<std::string> Emitted;
1369
1370
0
  for (auto &Def : Defs) {
1371
0
    if (Emitted.find(Def->getMangledName()) != Emitted.end() ||
1372
0
        Def->getImmChecks().empty())
1373
0
      continue;
1374
1375
0
    OS << "case SVE::BI__builtin_sve_" << Def->getMangledName() << ":\n";
1376
0
    for (auto &Check : Def->getImmChecks())
1377
0
      OS << "ImmChecks.push_back(std::make_tuple(" << Check.getArg() << ", "
1378
0
         << Check.getKind() << ", " << Check.getElementSizeInBits() << "));\n";
1379
0
    OS << "  break;\n";
1380
1381
0
    Emitted.insert(Def->getMangledName());
1382
0
  }
1383
1384
0
  OS << "#endif\n\n";
1385
0
}
1386
1387
/// Create the SVETypeFlags used in CGBuiltins
1388
0
void SVEEmitter::createTypeFlags(raw_ostream &OS) {
1389
0
  OS << "#ifdef LLVM_GET_SVE_TYPEFLAGS\n";
1390
0
  for (auto &KV : FlagTypes)
1391
0
    OS << "const uint64_t " << KV.getKey() << " = " << KV.getValue() << ";\n";
1392
0
  OS << "#endif\n\n";
1393
1394
0
  OS << "#ifdef LLVM_GET_SVE_ELTTYPES\n";
1395
0
  for (auto &KV : EltTypes)
1396
0
    OS << "  " << KV.getKey() << " = " << KV.getValue() << ",\n";
1397
0
  OS << "#endif\n\n";
1398
1399
0
  OS << "#ifdef LLVM_GET_SVE_MEMELTTYPES\n";
1400
0
  for (auto &KV : MemEltTypes)
1401
0
    OS << "  " << KV.getKey() << " = " << KV.getValue() << ",\n";
1402
0
  OS << "#endif\n\n";
1403
1404
0
  OS << "#ifdef LLVM_GET_SVE_MERGETYPES\n";
1405
0
  for (auto &KV : MergeTypes)
1406
0
    OS << "  " << KV.getKey() << " = " << KV.getValue() << ",\n";
1407
0
  OS << "#endif\n\n";
1408
1409
0
  OS << "#ifdef LLVM_GET_SVE_IMMCHECKTYPES\n";
1410
0
  for (auto &KV : ImmCheckTypes)
1411
0
    OS << "  " << KV.getKey() << " = " << KV.getValue() << ",\n";
1412
0
  OS << "#endif\n\n";
1413
0
}
1414
1415
namespace clang {
1416
0
void EmitSveHeader(RecordKeeper &Records, raw_ostream &OS) {
1417
0
  SVEEmitter(Records).createHeader(OS);
1418
0
}
1419
1420
0
void EmitSveBuiltins(RecordKeeper &Records, raw_ostream &OS) {
1421
0
  SVEEmitter(Records).createBuiltins(OS);
1422
0
}
1423
1424
0
void EmitSveBuiltinCG(RecordKeeper &Records, raw_ostream &OS) {
1425
0
  SVEEmitter(Records).createCodeGenMap(OS);
1426
0
}
1427
1428
0
void EmitSveRangeChecks(RecordKeeper &Records, raw_ostream &OS) {
1429
0
  SVEEmitter(Records).createRangeChecks(OS);
1430
0
}
1431
1432
0
void EmitSveTypeFlags(RecordKeeper &Records, raw_ostream &OS) {
1433
0
  SVEEmitter(Records).createTypeFlags(OS);
1434
0
}
1435
1436
} // End namespace clang