Coverage Report

Created: 2023-11-11 10:31

/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/include/clang/Support/RISCVVIntrinsicUtils.h
Line
Count
Source (jump to first uncovered line)
1
//===--- RISCVVIntrinsicUtils.h - RISC-V Vector Intrinsic Utils -*- 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
#ifndef CLANG_SUPPORT_RISCVVINTRINSICUTILS_H
10
#define CLANG_SUPPORT_RISCVVINTRINSICUTILS_H
11
12
#include "llvm/ADT/ArrayRef.h"
13
#include "llvm/ADT/BitmaskEnum.h"
14
#include "llvm/ADT/SmallVector.h"
15
#include "llvm/ADT/StringRef.h"
16
#include <cstdint>
17
#include <optional>
18
#include <set>
19
#include <string>
20
#include <unordered_map>
21
#include <vector>
22
23
namespace llvm {
24
class raw_ostream;
25
} // end namespace llvm
26
27
namespace clang {
28
namespace RISCV {
29
30
using VScaleVal = std::optional<unsigned>;
31
32
// Modifier for vector type.
33
enum class VectorTypeModifier : uint8_t {
34
  NoModifier,
35
  Widening2XVector,
36
  Widening4XVector,
37
  Widening8XVector,
38
  MaskVector,
39
  Log2EEW3,
40
  Log2EEW4,
41
  Log2EEW5,
42
  Log2EEW6,
43
  FixedSEW8,
44
  FixedSEW16,
45
  FixedSEW32,
46
  FixedSEW64,
47
  LFixedLog2LMULN3,
48
  LFixedLog2LMULN2,
49
  LFixedLog2LMULN1,
50
  LFixedLog2LMUL0,
51
  LFixedLog2LMUL1,
52
  LFixedLog2LMUL2,
53
  LFixedLog2LMUL3,
54
  SFixedLog2LMULN3,
55
  SFixedLog2LMULN2,
56
  SFixedLog2LMULN1,
57
  SFixedLog2LMUL0,
58
  SFixedLog2LMUL1,
59
  SFixedLog2LMUL2,
60
  SFixedLog2LMUL3,
61
  SEFixedLog2LMULN3,
62
  SEFixedLog2LMULN2,
63
  SEFixedLog2LMULN1,
64
  SEFixedLog2LMUL0,
65
  SEFixedLog2LMUL1,
66
  SEFixedLog2LMUL2,
67
  SEFixedLog2LMUL3,
68
  Tuple2,
69
  Tuple3,
70
  Tuple4,
71
  Tuple5,
72
  Tuple6,
73
  Tuple7,
74
  Tuple8,
75
};
76
77
// Similar to basic type but used to describe what's kind of type related to
78
// basic vector type, used to compute type info of arguments.
79
enum class BaseTypeModifier : uint8_t {
80
  Invalid,
81
  Scalar,
82
  Vector,
83
  Void,
84
  SizeT,
85
  Ptrdiff,
86
  UnsignedLong,
87
  SignedLong,
88
  Float32
89
};
90
91
// Modifier for type, used for both scalar and vector types.
92
enum class TypeModifier : uint8_t {
93
  NoModifier = 0,
94
  Pointer = 1 << 0,
95
  Const = 1 << 1,
96
  Immediate = 1 << 2,
97
  UnsignedInteger = 1 << 3,
98
  SignedInteger = 1 << 4,
99
  Float = 1 << 5,
100
  // LMUL1 should be kind of VectorTypeModifier, but that might come with
101
  // Widening2XVector for widening reduction.
102
  // However that might require VectorTypeModifier become bitmask rather than
103
  // simple enum, so we decide keek LMUL1 in TypeModifier for code size
104
  // optimization of clang binary size.
105
  LMUL1 = 1 << 6,
106
  MaxOffset = 6,
107
  LLVM_MARK_AS_BITMASK_ENUM(LMUL1),
108
};
109
110
class Policy {
111
public:
112
  enum PolicyType {
113
    Undisturbed,
114
    Agnostic,
115
  };
116
117
private:
118
  // The default assumption for an RVV instruction is TAMA, as an undisturbed
119
  // policy generally will affect the performance of an out-of-order core.
120
  const PolicyType TailPolicy = Agnostic;
121
  const PolicyType MaskPolicy = Agnostic;
122
123
public:
124
2.41k
  Policy() = default;
125
2.41k
  Policy(PolicyType TailPolicy) : TailPolicy(TailPolicy) {}
126
  Policy(PolicyType TailPolicy, PolicyType MaskPolicy)
127
7.12k
      : TailPolicy(TailPolicy), MaskPolicy(MaskPolicy) {}
128
129
31.4k
  bool isTAMAPolicy() const {
130
31.4k
    return TailPolicy == Agnostic && 
MaskPolicy == Agnostic18.6k
;
131
31.4k
  }
132
133
18.2k
  bool isTAMUPolicy() const {
134
18.2k
    return TailPolicy == Agnostic && MaskPolicy == Undisturbed;
135
18.2k
  }
136
137
25.7k
  bool isTUMAPolicy() const {
138
25.7k
    return TailPolicy == Undisturbed && 
MaskPolicy == Agnostic7.42k
;
139
25.7k
  }
140
141
32.7k
  bool isTUMUPolicy() const {
142
32.7k
    return TailPolicy == Undisturbed && 
MaskPolicy == Undisturbed14.4k
;
143
32.7k
  }
144
145
13.3k
  bool isTAPolicy() const { return TailPolicy == Agnostic; }
146
147
31.6k
  bool isTUPolicy() const { return TailPolicy == Undisturbed; }
148
149
0
  bool isMAPolicy() const { return MaskPolicy == Agnostic; }
150
151
0
  bool isMUPolicy() const { return MaskPolicy == Undisturbed; }
152
153
0
  bool operator==(const Policy &Other) const {
154
0
    return TailPolicy == Other.TailPolicy && MaskPolicy == Other.MaskPolicy;
155
0
  }
156
157
0
  bool operator!=(const Policy &Other) const { return !(*this == Other); }
158
159
0
  bool operator<(const Policy &Other) const {
160
0
    // Just for maintain the old order for quick test.
161
0
    if (MaskPolicy != Other.MaskPolicy)
162
0
      return Other.MaskPolicy < MaskPolicy;
163
0
    return TailPolicy < Other.TailPolicy;
164
0
  }
165
};
166
167
// PrototypeDescriptor is used to compute type info of arguments or return
168
// value.
169
struct PrototypeDescriptor {
170
0
  constexpr PrototypeDescriptor() = default;
171
  constexpr PrototypeDescriptor(
172
      BaseTypeModifier PT,
173
      VectorTypeModifier VTM = VectorTypeModifier::NoModifier,
174
      TypeModifier TM = TypeModifier::NoModifier)
175
      : PT(static_cast<uint8_t>(PT)), VTM(static_cast<uint8_t>(VTM)),
176
0
        TM(static_cast<uint8_t>(TM)) {}
177
  constexpr PrototypeDescriptor(uint8_t PT, uint8_t VTM, uint8_t TM)
178
8.74k
      : PT(PT), VTM(VTM), TM(TM) {}
179
180
  uint8_t PT = static_cast<uint8_t>(BaseTypeModifier::Invalid);
181
  uint8_t VTM = static_cast<uint8_t>(VectorTypeModifier::NoModifier);
182
  uint8_t TM = static_cast<uint8_t>(TypeModifier::NoModifier);
183
184
0
  bool operator!=(const PrototypeDescriptor &PD) const {
185
0
    return !(*this == PD);
186
0
  }
187
0
  bool operator==(const PrototypeDescriptor &PD) const {
188
0
    return PD.PT == PT && PD.VTM == VTM && PD.TM == TM;
189
0
  }
190
0
  bool operator<(const PrototypeDescriptor &PD) const {
191
0
    return std::tie(PT, VTM, TM) < std::tie(PD.PT, PD.VTM, PD.TM);
192
0
  }
193
  static const PrototypeDescriptor Mask;
194
  static const PrototypeDescriptor Vector;
195
  static const PrototypeDescriptor VL;
196
  static std::optional<PrototypeDescriptor>
197
  parsePrototypeDescriptor(llvm::StringRef PrototypeStr);
198
};
199
200
llvm::SmallVector<PrototypeDescriptor>
201
parsePrototypes(llvm::StringRef Prototypes);
202
203
// Basic type of vector type.
204
enum class BasicType : uint8_t {
205
  Unknown = 0,
206
  Int8 = 1 << 0,
207
  Int16 = 1 << 1,
208
  Int32 = 1 << 2,
209
  Int64 = 1 << 3,
210
  BFloat16 = 1 << 4,
211
  Float16 = 1 << 5,
212
  Float32 = 1 << 6,
213
  Float64 = 1 << 7,
214
  MaxOffset = 7,
215
  LLVM_MARK_AS_BITMASK_ENUM(Float64),
216
};
217
218
// Type of vector type.
219
enum ScalarTypeKind : uint8_t {
220
  Void,
221
  Size_t,
222
  Ptrdiff_t,
223
  UnsignedLong,
224
  SignedLong,
225
  Boolean,
226
  SignedInteger,
227
  UnsignedInteger,
228
  Float,
229
  BFloat,
230
  Invalid,
231
  Undefined,
232
};
233
234
// Exponential LMUL
235
struct LMULType {
236
  int Log2LMUL;
237
  LMULType(int Log2LMUL);
238
  // Return the C/C++ string representation of LMUL
239
  std::string str() const;
240
  std::optional<unsigned> getScale(unsigned ElementBitwidth) const;
241
  void MulLog2LMUL(int Log2LMUL);
242
};
243
244
class RVVType;
245
using RVVTypePtr = RVVType *;
246
using RVVTypes = std::vector<RVVTypePtr>;
247
class RVVTypeCache;
248
249
// This class is compact representation of a valid and invalid RVVType.
250
class RVVType {
251
  friend class RVVTypeCache;
252
253
  BasicType BT;
254
  ScalarTypeKind ScalarType = Undefined;
255
  LMULType LMUL;
256
  bool IsPointer = false;
257
  // IsConstant indices are "int", but have the constant expression.
258
  bool IsImmediate = false;
259
  // Const qualifier for pointer to const object or object of const type.
260
  bool IsConstant = false;
261
  unsigned ElementBitwidth = 0;
262
  VScaleVal Scale = 0;
263
  bool Valid;
264
  bool IsTuple = false;
265
  unsigned NF = 0;
266
267
  std::string BuiltinStr;
268
  std::string ClangBuiltinStr;
269
  std::string Str;
270
  std::string ShortStr;
271
272
  enum class FixedLMULType { LargerThan, SmallerThan, SmallerOrEqual };
273
274
  RVVType(BasicType BT, int Log2LMUL, const PrototypeDescriptor &Profile);
275
276
public:
277
  // Return the string representation of a type, which is an encoded string for
278
  // passing to the BUILTIN() macro in Builtins.def.
279
0
  const std::string &getBuiltinStr() const { return BuiltinStr; }
280
281
  // Return the clang builtin type for RVV vector type which are used in the
282
  // riscv_vector.h header file.
283
0
  const std::string &getClangBuiltinStr() const { return ClangBuiltinStr; }
284
285
  // Return the C/C++ string representation of a type for use in the
286
  // riscv_vector.h header file.
287
0
  const std::string &getTypeStr() const { return Str; }
288
289
  // Return the short name of a type for C/C++ name suffix.
290
17.1k
  const std::string &getShortStr() {
291
    // Not all types are used in short name, so compute the short name by
292
    // demanded.
293
17.1k
    if (ShortStr.empty())
294
1.02k
      initShortStr();
295
17.1k
    return ShortStr;
296
17.1k
  }
297
298
7.65k
  bool isValid() const { return Valid; }
299
5.58k
  bool isScalar() const { return Scale && 
*Scale == 05.22k
; }
300
4.14k
  bool isVector() const { return Scale && *Scale != 0; }
301
0
  bool isVector(unsigned Width) const {
302
0
    return isVector() && ElementBitwidth == Width;
303
0
  }
304
1.54k
  bool isFloat() const { return ScalarType == ScalarTypeKind::Float; }
305
1.53k
  bool isBFloat() const { return ScalarType == ScalarTypeKind::BFloat; }
306
1.29k
  bool isSignedInteger() const {
307
1.29k
    return ScalarType == ScalarTypeKind::SignedInteger;
308
1.29k
  }
309
0
  bool isFloatVector(unsigned Width) const {
310
0
    return isVector() && isFloat() && ElementBitwidth == Width;
311
0
  }
312
0
  bool isFloat(unsigned Width) const {
313
0
    return isFloat() && ElementBitwidth == Width;
314
0
  }
315
23
  bool isConstant() const { return IsConstant; }
316
23
  bool isPointer() const { return IsPointer; }
317
1.01k
  bool isTuple() const { return IsTuple; }
318
17
  unsigned getElementBitwidth() const { return ElementBitwidth; }
319
320
23
  ScalarTypeKind getScalarType() const { return ScalarType; }
321
16
  VScaleVal getScale() const { return Scale; }
322
0
  unsigned getNF() const {
323
0
    assert(NF > 1 && NF <= 8 && "Only legal NF should be fetched");
324
0
    return NF;
325
0
  }
326
327
private:
328
  // Verify RVV vector type and set Valid.
329
  bool verifyType() const;
330
331
  // Creates a type based on basic types of TypeRange
332
  void applyBasicType();
333
334
  // Applies a prototype modifier to the current type. The result maybe an
335
  // invalid type.
336
  void applyModifier(const PrototypeDescriptor &prototype);
337
338
  void applyLog2EEW(unsigned Log2EEW);
339
  void applyFixedSEW(unsigned NewSEW);
340
  void applyFixedLog2LMUL(int Log2LMUL, enum FixedLMULType Type);
341
342
  // Compute and record a string for legal type.
343
  void initBuiltinStr();
344
  // Compute and record a builtin RVV vector type string.
345
  void initClangBuiltinStr();
346
  // Compute and record a type string for used in the header.
347
  void initTypeStr();
348
  // Compute and record a short name of a type for C/C++ name suffix.
349
  void initShortStr();
350
};
351
352
// This class is used to manage RVVType, RVVType should only created by this
353
// class, also provided thread-safe cache capability.
354
class RVVTypeCache {
355
private:
356
  std::unordered_map<uint64_t, RVVType> LegalTypes;
357
  std::set<uint64_t> IllegalTypes;
358
359
public:
360
  /// Compute output and input types by applying different config (basic type
361
  /// and LMUL with type transformers). It also record result of type in legal
362
  /// or illegal set to avoid compute the same config again. The result maybe
363
  /// have illegal RVVType.
364
  std::optional<RVVTypes>
365
  computeTypes(BasicType BT, int Log2LMUL, unsigned NF,
366
               llvm::ArrayRef<PrototypeDescriptor> Prototype);
367
  std::optional<RVVTypePtr> computeType(BasicType BT, int Log2LMUL,
368
                                        PrototypeDescriptor Proto);
369
};
370
371
enum PolicyScheme : uint8_t {
372
  SchemeNone,
373
  // Passthru operand is at first parameter in C builtin.
374
  HasPassthruOperand,
375
  HasPolicyOperand,
376
};
377
378
// TODO refactor RVVIntrinsic class design after support all intrinsic
379
// combination. This represents an instantiation of an intrinsic with a
380
// particular type and prototype
381
class RVVIntrinsic {
382
383
private:
384
  std::string BuiltinName; // Builtin name
385
  std::string Name;        // C intrinsic name.
386
  std::string OverloadedName;
387
  std::string IRName;
388
  bool IsMasked;
389
  bool HasMaskedOffOperand;
390
  bool HasVL;
391
  PolicyScheme Scheme;
392
  bool SupportOverloading;
393
  bool HasBuiltinAlias;
394
  std::string ManualCodegen;
395
  RVVTypePtr OutputType; // Builtin output type
396
  RVVTypes InputTypes;   // Builtin input types
397
  // The types we use to obtain the specific LLVM intrinsic. They are index of
398
  // InputTypes. -1 means the return type.
399
  std::vector<int64_t> IntrinsicTypes;
400
  unsigned NF = 1;
401
  Policy PolicyAttrs;
402
403
public:
404
  RVVIntrinsic(llvm::StringRef Name, llvm::StringRef Suffix,
405
               llvm::StringRef OverloadedName, llvm::StringRef OverloadedSuffix,
406
               llvm::StringRef IRName, bool IsMasked, bool HasMaskedOffOperand,
407
               bool HasVL, PolicyScheme Scheme, bool SupportOverloading,
408
               bool HasBuiltinAlias, llvm::StringRef ManualCodegen,
409
               const RVVTypes &Types,
410
               const std::vector<int64_t> &IntrinsicTypes,
411
               const std::vector<llvm::StringRef> &RequiredFeatures,
412
               unsigned NF, Policy PolicyAttrs, bool HasFRMRoundModeOp);
413
0
  ~RVVIntrinsic() = default;
414
415
0
  RVVTypePtr getOutputType() const { return OutputType; }
416
0
  const RVVTypes &getInputTypes() const { return InputTypes; }
417
0
  llvm::StringRef getBuiltinName() const { return BuiltinName; }
418
0
  llvm::StringRef getName() const { return Name; }
419
0
  llvm::StringRef getOverloadedName() const { return OverloadedName; }
420
0
  bool hasMaskedOffOperand() const { return HasMaskedOffOperand; }
421
0
  bool hasVL() const { return HasVL; }
422
0
  bool hasPolicy() const { return Scheme != PolicyScheme::SchemeNone; }
423
0
  bool hasPassthruOperand() const {
424
0
    return Scheme == PolicyScheme::HasPassthruOperand;
425
0
  }
426
0
  bool hasPolicyOperand() const {
427
0
    return Scheme == PolicyScheme::HasPolicyOperand;
428
0
  }
429
0
  bool supportOverloading() const { return SupportOverloading; }
430
0
  bool hasBuiltinAlias() const { return HasBuiltinAlias; }
431
0
  bool hasManualCodegen() const { return !ManualCodegen.empty(); }
432
0
  bool isMasked() const { return IsMasked; }
433
0
  llvm::StringRef getIRName() const { return IRName; }
434
0
  llvm::StringRef getManualCodegen() const { return ManualCodegen; }
435
0
  PolicyScheme getPolicyScheme() const { return Scheme; }
436
0
  unsigned getNF() const { return NF; }
437
0
  const std::vector<int64_t> &getIntrinsicTypes() const {
438
0
    return IntrinsicTypes;
439
0
  }
440
0
  Policy getPolicyAttrs() const {
441
0
    return PolicyAttrs;
442
0
  }
443
0
  unsigned getPolicyAttrsBits() const {
444
    // CGBuiltin.cpp
445
    // The 0th bit simulates the `vta` of RVV
446
    // The 1st bit simulates the `vma` of RVV
447
    // int PolicyAttrs = 0;
448
449
0
    if (PolicyAttrs.isTUMAPolicy())
450
0
      return 2;
451
0
    if (PolicyAttrs.isTAMAPolicy())
452
0
      return 3;
453
0
    if (PolicyAttrs.isTUMUPolicy())
454
0
      return 0;
455
0
    if (PolicyAttrs.isTAMUPolicy())
456
0
      return 1;
457
458
0
    llvm_unreachable("unsupport policy");
459
0
    return 0;
460
0
  }
Unexecuted instantiation: clang::RISCV::RVVIntrinsic::getPolicyAttrsBits() const
Unexecuted instantiation: clang::RISCV::RVVIntrinsic::getPolicyAttrsBits() const
461
462
  // Return the type string for a BUILTIN() macro in Builtins.def.
463
  std::string getBuiltinTypeStr() const;
464
465
  static std::string
466
  getSuffixStr(RVVTypeCache &TypeCache, BasicType Type, int Log2LMUL,
467
               llvm::ArrayRef<PrototypeDescriptor> PrototypeDescriptors);
468
469
  static llvm::SmallVector<PrototypeDescriptor>
470
  computeBuiltinTypes(llvm::ArrayRef<PrototypeDescriptor> Prototype,
471
                      bool IsMasked, bool HasMaskedOffOperand, bool HasVL,
472
                      unsigned NF, PolicyScheme DefaultScheme,
473
                      Policy PolicyAttrs, bool IsTuple);
474
475
  static llvm::SmallVector<Policy> getSupportedUnMaskedPolicies();
476
  static llvm::SmallVector<Policy>
477
      getSupportedMaskedPolicies(bool HasTailPolicy, bool HasMaskPolicy);
478
479
  static void updateNamesAndPolicy(bool IsMasked, bool HasPolicy,
480
                                   std::string &Name, std::string &BuiltinName,
481
                                   std::string &OverloadedName,
482
                                   Policy &PolicyAttrs, bool HasFRMRoundModeOp);
483
};
484
485
// RVVRequire should be sync'ed with target features, but only
486
// required features used in riscv_vector.td.
487
enum RVVRequire : uint16_t {
488
  RVV_REQ_None = 0,
489
  RVV_REQ_RV64 = 1 << 0,
490
  RVV_REQ_ZvfhminOrZvfh = 1 << 1,
491
  RVV_REQ_Xsfvcp = 1 << 2,
492
  RVV_REQ_Xsfvfnrclipxfqf = 1 << 3,
493
  RVV_REQ_Xsfvfwmaccqqq = 1 << 4,
494
  RVV_REQ_Xsfvqmaccdod = 1 << 5,
495
  RVV_REQ_Xsfvqmaccqoq = 1 << 6,
496
  RVV_REQ_Zvbb = 1 << 7,
497
  RVV_REQ_Zvbc = 1 << 8,
498
  RVV_REQ_Zvkb = 1 << 9,
499
  RVV_REQ_Zvkg = 1 << 10,
500
  RVV_REQ_Zvkned = 1 << 11,
501
  RVV_REQ_Zvknha = 1 << 12,
502
  RVV_REQ_Zvknhb = 1 << 13,
503
  RVV_REQ_Zvksed = 1 << 14,
504
  RVV_REQ_Zvksh = 1 << 15,
505
506
  LLVM_MARK_AS_BITMASK_ENUM(RVV_REQ_Zvksh)
507
};
508
509
// Raw RVV intrinsic info, used to expand later.
510
// This struct is highly compact for minimized code size.
511
struct RVVIntrinsicRecord {
512
  // Intrinsic name, e.g. vadd_vv
513
  const char *Name;
514
515
  // Overloaded intrinsic name, could be empty if it can be computed from Name.
516
  // e.g. vadd
517
  const char *OverloadedName;
518
519
  // Prototype for this intrinsic, index of RVVSignatureTable.
520
  uint16_t PrototypeIndex;
521
522
  // Suffix of intrinsic name, index of RVVSignatureTable.
523
  uint16_t SuffixIndex;
524
525
  // Suffix of overloaded intrinsic name, index of RVVSignatureTable.
526
  uint16_t OverloadedSuffixIndex;
527
528
  // Length of the prototype.
529
  uint8_t PrototypeLength;
530
531
  // Length of intrinsic name suffix.
532
  uint8_t SuffixLength;
533
534
  // Length of overloaded intrinsic suffix.
535
  uint8_t OverloadedSuffixSize;
536
537
  // Required target features for this intrinsic.
538
  uint16_t RequiredExtensions;
539
540
  // Supported type, mask of BasicType.
541
  uint8_t TypeRangeMask;
542
543
  // Supported LMUL.
544
  uint8_t Log2LMULMask;
545
546
  // Number of fields, greater than 1 if it's segment load/store.
547
  uint8_t NF;
548
549
  bool HasMasked : 1;
550
  bool HasVL : 1;
551
  bool HasMaskedOffOperand : 1;
552
  bool HasTailPolicy : 1;
553
  bool HasMaskPolicy : 1;
554
  bool HasFRMRoundModeOp : 1;
555
  bool IsTuple : 1;
556
  uint8_t UnMaskedPolicyScheme : 2;
557
  uint8_t MaskedPolicyScheme : 2;
558
};
559
560
llvm::raw_ostream &operator<<(llvm::raw_ostream &OS,
561
                              const RVVIntrinsicRecord &RVVInstrRecord);
562
563
LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE();
564
} // end namespace RISCV
565
566
} // end namespace clang
567
568
#endif // CLANG_SUPPORT_RISCVVINTRINSICUTILS_H