Subversion Repositories QNX 8.QNX8 LLVM/Clang compiler suite

Rev

Details | Last modification | View Log | RSS feed

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