Coverage Report

Created: 2023-05-31 04:38

/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/lib/Sema/SemaRISCVVectorLookup.cpp
Line
Count
Source (jump to first uncovered line)
1
//==- SemaRISCVVectorLookup.cpp - Name Lookup for RISC-V Vector Intrinsic -==//
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 file implements name lookup for RISC-V vector intrinsic.
10
//
11
//===----------------------------------------------------------------------===//
12
13
#include "clang/AST/ASTContext.h"
14
#include "clang/AST/Decl.h"
15
#include "clang/Basic/Builtins.h"
16
#include "clang/Basic/TargetInfo.h"
17
#include "clang/Lex/Preprocessor.h"
18
#include "clang/Sema/Lookup.h"
19
#include "clang/Sema/RISCVIntrinsicManager.h"
20
#include "clang/Sema/Sema.h"
21
#include "clang/Support/RISCVVIntrinsicUtils.h"
22
#include "llvm/ADT/SmallVector.h"
23
#include <optional>
24
#include <string>
25
#include <vector>
26
27
using namespace llvm;
28
using namespace clang;
29
using namespace clang::RISCV;
30
31
using IntrinsicKind = sema::RISCVIntrinsicManager::IntrinsicKind;
32
33
namespace {
34
35
// Function definition of a RVV intrinsic.
36
struct RVVIntrinsicDef {
37
  /// Full function name with suffix, e.g. vadd_vv_i32m1.
38
  std::string Name;
39
40
  /// Overloaded function name, e.g. vadd.
41
  std::string OverloadName;
42
43
  /// Mapping to which clang built-in function, e.g. __builtin_rvv_vadd.
44
  std::string BuiltinName;
45
46
  /// Function signature, first element is return type.
47
  RVVTypes Signature;
48
};
49
50
struct RVVOverloadIntrinsicDef {
51
  // Indexes of RISCVIntrinsicManagerImpl::IntrinsicList.
52
  SmallVector<size_t, 8> Indexes;
53
};
54
55
} // namespace
56
57
static const PrototypeDescriptor RVVSignatureTable[] = {
58
#define DECL_SIGNATURE_TABLE
59
#include "clang/Basic/riscv_vector_builtin_sema.inc"
60
#undef DECL_SIGNATURE_TABLE
61
};
62
63
static const PrototypeDescriptor RVSiFiveVectorSignatureTable[] = {
64
#define DECL_SIGNATURE_TABLE
65
#include "clang/Basic/riscv_sifive_vector_builtin_sema.inc"
66
#undef DECL_SIGNATURE_TABLE
67
};
68
69
static const RVVIntrinsicRecord RVVIntrinsicRecords[] = {
70
#define DECL_INTRINSIC_RECORDS
71
#include "clang/Basic/riscv_vector_builtin_sema.inc"
72
#undef DECL_INTRINSIC_RECORDS
73
};
74
75
static const RVVIntrinsicRecord RVSiFiveVectorIntrinsicRecords[] = {
76
#define DECL_INTRINSIC_RECORDS
77
#include "clang/Basic/riscv_sifive_vector_builtin_sema.inc"
78
#undef DECL_INTRINSIC_RECORDS
79
};
80
81
// Get subsequence of signature table.
82
static ArrayRef<PrototypeDescriptor>
83
6.87k
ProtoSeq2ArrayRef(IntrinsicKind K, uint16_t Index, uint8_t Length) {
84
6.87k
  switch (K) {
85
6.87k
  case IntrinsicKind::RVV:
86
6.87k
    return ArrayRef(&RVVSignatureTable[Index], Length);
87
0
  case IntrinsicKind::SIFIVE_VECTOR:
88
0
    return ArrayRef(&RVSiFiveVectorSignatureTable[Index], Length);
89
6.87k
  }
90
0
  llvm_unreachable("Unhandled IntrinsicKind");
91
0
}
92
93
23
static QualType RVVType2Qual(ASTContext &Context, const RVVType *Type) {
94
23
  QualType QT;
95
23
  switch (Type->getScalarType()) {
96
0
  case ScalarTypeKind::Void:
97
0
    QT = Context.VoidTy;
98
0
    break;
99
6
  case ScalarTypeKind::Size_t:
100
6
    QT = Context.getSizeType();
101
6
    break;
102
0
  case ScalarTypeKind::Ptrdiff_t:
103
0
    QT = Context.getPointerDiffType();
104
0
    break;
105
0
  case ScalarTypeKind::UnsignedLong:
106
0
    QT = Context.UnsignedLongTy;
107
0
    break;
108
0
  case ScalarTypeKind::SignedLong:
109
0
    QT = Context.LongTy;
110
0
    break;
111
0
  case ScalarTypeKind::Boolean:
112
0
    QT = Context.BoolTy;
113
0
    break;
114
17
  case ScalarTypeKind::SignedInteger:
115
17
    QT = Context.getIntTypeForBitwidth(Type->getElementBitwidth(), true);
116
17
    break;
117
0
  case ScalarTypeKind::UnsignedInteger:
118
0
    QT = Context.getIntTypeForBitwidth(Type->getElementBitwidth(), false);
119
0
    break;
120
0
  case ScalarTypeKind::Float:
121
0
    switch (Type->getElementBitwidth()) {
122
0
    case 64:
123
0
      QT = Context.DoubleTy;
124
0
      break;
125
0
    case 32:
126
0
      QT = Context.FloatTy;
127
0
      break;
128
0
    case 16:
129
0
      QT = Context.Float16Ty;
130
0
      break;
131
0
    default:
132
0
      llvm_unreachable("Unsupported floating point width.");
133
0
    }
134
0
    break;
135
0
  case Invalid:
136
0
    llvm_unreachable("Unhandled type.");
137
23
  }
138
23
  if (Type->isVector()) {
139
16
    if (Type->isTuple())
140
0
      QT = Context.getScalableVectorType(QT, *Type->getScale(), Type->getNF());
141
16
    else
142
16
      QT = Context.getScalableVectorType(QT, *Type->getScale());
143
16
  }
144
145
23
  if (Type->isConstant())
146
1
    QT = Context.getConstType(QT);
147
148
  // Transform the type to a pointer as the last step, if necessary.
149
23
  if (Type->isPointer())
150
1
    QT = Context.getPointerType(QT);
151
152
23
  return QT;
153
23
}
154
155
namespace {
156
class RISCVIntrinsicManagerImpl : public sema::RISCVIntrinsicManager {
157
private:
158
  Sema &S;
159
  ASTContext &Context;
160
  RVVTypeCache TypeCache;
161
162
  // List of all RVV intrinsic.
163
  std::vector<RVVIntrinsicDef> IntrinsicList;
164
  // Mapping function name to index of IntrinsicList.
165
  StringMap<size_t> Intrinsics;
166
  // Mapping function name to RVVOverloadIntrinsicDef.
167
  StringMap<RVVOverloadIntrinsicDef> OverloadIntrinsics;
168
169
  // Create IntrinsicList
170
  void InitIntrinsicList();
171
172
  // Create RVVIntrinsicDef.
173
  void InitRVVIntrinsic(const RVVIntrinsicRecord &Record, StringRef SuffixStr,
174
                        StringRef OverloadedSuffixStr, bool IsMask,
175
                        RVVTypes &Types, bool HasPolicy, Policy PolicyAttrs);
176
177
  // Create FunctionDecl for a vector intrinsic.
178
  void CreateRVVIntrinsicDecl(LookupResult &LR, IdentifierInfo *II,
179
                              Preprocessor &PP, unsigned Index,
180
                              bool IsOverload);
181
182
public:
183
1
  RISCVIntrinsicManagerImpl(clang::Sema &S) : S(S), Context(S.Context) {
184
1
    InitIntrinsicList();
185
1
  }
186
187
  // Create RISC-V vector intrinsic and insert into symbol table if found, and
188
  // return true, otherwise return false.
189
  bool CreateIntrinsicIfFound(LookupResult &LR, IdentifierInfo *II,
190
                              Preprocessor &PP) override;
191
};
192
} // namespace
193
194
1
void RISCVIntrinsicManagerImpl::InitIntrinsicList() {
195
1
  const TargetInfo &TI = Context.getTargetInfo();
196
1
  bool HasRV64 = TI.hasFeature("64bit");
197
1
  bool HasFullMultiply = TI.hasFeature("v");
198
199
1
  auto ConstructRVVIntrinsics = [&](ArrayRef<RVVIntrinsicRecord> Recs,
200
1
                                    IntrinsicKind K) {
201
    // Construction of RVVIntrinsicRecords need to sync with createRVVIntrinsics
202
    // in RISCVVEmitter.cpp.
203
2.29k
    for (auto &Record : Recs) {
204
      // Create Intrinsics for each type and LMUL.
205
2.29k
      BasicType BaseType = BasicType::Unknown;
206
2.29k
      ArrayRef<PrototypeDescriptor> BasicProtoSeq =
207
2.29k
          ProtoSeq2ArrayRef(K, Record.PrototypeIndex, Record.PrototypeLength);
208
2.29k
      ArrayRef<PrototypeDescriptor> SuffixProto =
209
2.29k
          ProtoSeq2ArrayRef(K, Record.SuffixIndex, Record.SuffixLength);
210
2.29k
      ArrayRef<PrototypeDescriptor> OverloadedSuffixProto = ProtoSeq2ArrayRef(
211
2.29k
          K, Record.OverloadedSuffixIndex, Record.OverloadedSuffixSize);
212
213
2.29k
      PolicyScheme UnMaskedPolicyScheme =
214
2.29k
          static_cast<PolicyScheme>(Record.UnMaskedPolicyScheme);
215
2.29k
      PolicyScheme MaskedPolicyScheme =
216
2.29k
          static_cast<PolicyScheme>(Record.MaskedPolicyScheme);
217
218
2.29k
      const Policy DefaultPolicy;
219
220
2.29k
      llvm::SmallVector<PrototypeDescriptor> ProtoSeq =
221
2.29k
          RVVIntrinsic::computeBuiltinTypes(
222
2.29k
              BasicProtoSeq, /*IsMasked=*/false,
223
2.29k
              /*HasMaskedOffOperand=*/false, Record.HasVL, Record.NF,
224
2.29k
              UnMaskedPolicyScheme, DefaultPolicy, Record.IsTuple);
225
226
2.29k
      llvm::SmallVector<PrototypeDescriptor> ProtoMaskSeq =
227
2.29k
          RVVIntrinsic::computeBuiltinTypes(
228
2.29k
              BasicProtoSeq, /*IsMasked=*/true, Record.HasMaskedOffOperand,
229
2.29k
              Record.HasVL, Record.NF, MaskedPolicyScheme, DefaultPolicy,
230
2.29k
              Record.IsTuple);
231
232
2.29k
      bool UnMaskedHasPolicy = UnMaskedPolicyScheme != PolicyScheme::SchemeNone;
233
2.29k
      bool MaskedHasPolicy = MaskedPolicyScheme != PolicyScheme::SchemeNone;
234
2.29k
      SmallVector<Policy> SupportedUnMaskedPolicies =
235
2.29k
          RVVIntrinsic::getSupportedUnMaskedPolicies();
236
2.29k
      SmallVector<Policy> SupportedMaskedPolicies =
237
2.29k
          RVVIntrinsic::getSupportedMaskedPolicies(Record.HasTailPolicy,
238
2.29k
                                                   Record.HasMaskPolicy);
239
240
2.29k
      for (unsigned int TypeRangeMaskShift = 0;
241
18.3k
           TypeRangeMaskShift <= static_cast<unsigned int>(BasicType::MaxOffset);
242
16.0k
           ++TypeRangeMaskShift) {
243
16.0k
        unsigned int BaseTypeI = 1 << TypeRangeMaskShift;
244
16.0k
        BaseType = static_cast<BasicType>(BaseTypeI);
245
246
16.0k
        if ((BaseTypeI & Record.TypeRangeMask) != BaseTypeI)
247
12.6k
          continue;
248
249
        // Check requirement.
250
3.37k
        if (((Record.RequiredExtensions & RVV_REQ_RV64) == RVV_REQ_RV64) &&
251
3.37k
            
!HasRV6444
)
252
0
          continue;
253
254
3.37k
        if ((BaseType == BasicType::Int64) &&
255
3.37k
            ((Record.RequiredExtensions & RVV_REQ_FullMultiply) ==
256
586
             RVV_REQ_FullMultiply) &&
257
3.37k
            
!HasFullMultiply8
)
258
0
          continue;
259
260
        // Expanded with different LMUL.
261
26.9k
        
for (int Log2LMUL = -3; 3.37k
Log2LMUL <= 3;
Log2LMUL++23.6k
) {
262
23.6k
          if (!(Record.Log2LMULMask & (1 << (Log2LMUL + 3))))
263
351
            continue;
264
265
23.2k
          std::optional<RVVTypes> Types =
266
23.2k
              TypeCache.computeTypes(BaseType, Log2LMUL, Record.NF, ProtoSeq);
267
268
          // Ignored to create new intrinsic if there are any illegal types.
269
23.2k
          if (!Types.has_value())
270
9.76k
            continue;
271
272
13.4k
          std::string SuffixStr = RVVIntrinsic::getSuffixStr(
273
13.4k
              TypeCache, BaseType, Log2LMUL, SuffixProto);
274
13.4k
          std::string OverloadedSuffixStr = RVVIntrinsic::getSuffixStr(
275
13.4k
              TypeCache, BaseType, Log2LMUL, OverloadedSuffixProto);
276
277
          // Create non-masked intrinsic.
278
13.4k
          InitRVVIntrinsic(Record, SuffixStr, OverloadedSuffixStr, false, *Types,
279
13.4k
                           UnMaskedHasPolicy, DefaultPolicy);
280
281
          // Create non-masked policy intrinsic.
282
13.4k
          if (Record.UnMaskedPolicyScheme != PolicyScheme::SchemeNone) {
283
8.32k
            for (auto P : SupportedUnMaskedPolicies) {
284
8.32k
              llvm::SmallVector<PrototypeDescriptor> PolicyPrototype =
285
8.32k
                  RVVIntrinsic::computeBuiltinTypes(
286
8.32k
                      BasicProtoSeq, /*IsMasked=*/false,
287
8.32k
                      /*HasMaskedOffOperand=*/false, Record.HasVL, Record.NF,
288
8.32k
                      UnMaskedPolicyScheme, P, Record.IsTuple);
289
8.32k
              std::optional<RVVTypes> PolicyTypes = TypeCache.computeTypes(
290
8.32k
                  BaseType, Log2LMUL, Record.NF, PolicyPrototype);
291
8.32k
              InitRVVIntrinsic(Record, SuffixStr, OverloadedSuffixStr,
292
8.32k
                               /*IsMask=*/false, *PolicyTypes, UnMaskedHasPolicy,
293
8.32k
                               P);
294
8.32k
            }
295
8.32k
          }
296
13.4k
          if (!Record.HasMasked)
297
2.15k
            continue;
298
          // Create masked intrinsic.
299
11.3k
          std::optional<RVVTypes> MaskTypes =
300
11.3k
              TypeCache.computeTypes(BaseType, Log2LMUL, Record.NF, ProtoMaskSeq);
301
11.3k
          InitRVVIntrinsic(Record, SuffixStr, OverloadedSuffixStr, true,
302
11.3k
                           *MaskTypes, MaskedHasPolicy, DefaultPolicy);
303
11.3k
          if (Record.MaskedPolicyScheme == PolicyScheme::SchemeNone)
304
2.82k
            continue;
305
          // Create masked policy intrinsic.
306
23.2k
          
for (auto P : SupportedMaskedPolicies)8.50k
{
307
23.2k
            llvm::SmallVector<PrototypeDescriptor> PolicyPrototype =
308
23.2k
                RVVIntrinsic::computeBuiltinTypes(
309
23.2k
                    BasicProtoSeq, /*IsMasked=*/true,
310
23.2k
                    Record.HasMaskedOffOperand, Record.HasVL, Record.NF,
311
23.2k
                    MaskedPolicyScheme, P, Record.IsTuple);
312
23.2k
            std::optional<RVVTypes> PolicyTypes = TypeCache.computeTypes(
313
23.2k
                BaseType, Log2LMUL, Record.NF, PolicyPrototype);
314
23.2k
            InitRVVIntrinsic(Record, SuffixStr, OverloadedSuffixStr,
315
23.2k
                             /*IsMask=*/true, *PolicyTypes, MaskedHasPolicy, P);
316
23.2k
          }
317
8.50k
        } // End for different LMUL
318
3.37k
      } // End for different TypeRange
319
2.29k
    }
320
1
  };
321
1
  if (S.DeclareRISCVVBuiltins)
322
1
    ConstructRVVIntrinsics(RVVIntrinsicRecords,
323
1
                           IntrinsicKind::RVV);
324
1
  if (S.DeclareRISCVVectorBuiltins)
325
0
    ConstructRVVIntrinsics(RVSiFiveVectorIntrinsicRecords,
326
0
                           IntrinsicKind::SIFIVE_VECTOR);
327
1
}
328
329
// Compute name and signatures for intrinsic with practical types.
330
void RISCVIntrinsicManagerImpl::InitRVVIntrinsic(
331
    const RVVIntrinsicRecord &Record, StringRef SuffixStr,
332
    StringRef OverloadedSuffixStr, bool IsMasked, RVVTypes &Signature,
333
56.4k
    bool HasPolicy, Policy PolicyAttrs) {
334
  // Function name, e.g. vadd_vv_i32m1.
335
56.4k
  std::string Name = Record.Name;
336
56.4k
  if (!SuffixStr.empty())
337
56.4k
    Name += "_" + SuffixStr.str();
338
339
  // Overloaded function name, e.g. vadd.
340
56.4k
  std::string OverloadedName;
341
56.4k
  if (!Record.OverloadedName)
342
51.3k
    OverloadedName = StringRef(Record.Name).split("_").first.str();
343
5.11k
  else
344
5.11k
    OverloadedName = Record.OverloadedName;
345
56.4k
  if (!OverloadedSuffixStr.empty())
346
949
    OverloadedName += "_" + OverloadedSuffixStr.str();
347
348
  // clang built-in function name, e.g. __builtin_rvv_vadd.
349
56.4k
  std::string BuiltinName = "__builtin_rvv_" + std::string(Record.Name);
350
351
56.4k
  RVVIntrinsic::updateNamesAndPolicy(IsMasked, HasPolicy, Name, BuiltinName,
352
56.4k
                                     OverloadedName, PolicyAttrs);
353
354
  // Put into IntrinsicList.
355
56.4k
  size_t Index = IntrinsicList.size();
356
56.4k
  IntrinsicList.push_back({Name, OverloadedName, BuiltinName, Signature});
357
358
  // Creating mapping to Intrinsics.
359
56.4k
  Intrinsics.insert({Name, Index});
360
361
  // Get the RVVOverloadIntrinsicDef.
362
56.4k
  RVVOverloadIntrinsicDef &OverloadIntrinsicDef =
363
56.4k
      OverloadIntrinsics[OverloadedName];
364
365
  // And added the index.
366
56.4k
  OverloadIntrinsicDef.Indexes.push_back(Index);
367
56.4k
}
368
369
void RISCVIntrinsicManagerImpl::CreateRVVIntrinsicDecl(LookupResult &LR,
370
                                                       IdentifierInfo *II,
371
                                                       Preprocessor &PP,
372
                                                       unsigned Index,
373
6
                                                       bool IsOverload) {
374
6
  ASTContext &Context = S.Context;
375
6
  RVVIntrinsicDef &IDef = IntrinsicList[Index];
376
6
  RVVTypes Sigs = IDef.Signature;
377
6
  size_t SigLength = Sigs.size();
378
6
  RVVType *ReturnType = Sigs[0];
379
6
  QualType RetType = RVVType2Qual(Context, ReturnType);
380
6
  SmallVector<QualType, 8> ArgTypes;
381
6
  QualType BuiltinFuncType;
382
383
  // Skip return type, and convert RVVType to QualType for arguments.
384
23
  for (size_t i = 1; i < SigLength; 
++i17
)
385
17
    ArgTypes.push_back(RVVType2Qual(Context, Sigs[i]));
386
387
6
  FunctionProtoType::ExtProtoInfo PI(
388
6
      Context.getDefaultCallingConvention(false, false, true));
389
390
6
  PI.Variadic = false;
391
392
6
  SourceLocation Loc = LR.getNameLoc();
393
6
  BuiltinFuncType = Context.getFunctionType(RetType, ArgTypes, PI);
394
6
  DeclContext *Parent = Context.getTranslationUnitDecl();
395
396
6
  FunctionDecl *RVVIntrinsicDecl = FunctionDecl::Create(
397
6
      Context, Parent, Loc, Loc, II, BuiltinFuncType, /*TInfo=*/nullptr,
398
6
      SC_Extern, S.getCurFPFeatures().isFPConstrained(),
399
6
      /*isInlineSpecified*/ false,
400
6
      /*hasWrittenPrototype*/ true);
401
402
  // Create Decl objects for each parameter, adding them to the
403
  // FunctionDecl.
404
6
  const auto *FP = cast<FunctionProtoType>(BuiltinFuncType);
405
6
  SmallVector<ParmVarDecl *, 8> ParmList;
406
23
  for (unsigned IParm = 0, E = FP->getNumParams(); IParm != E; 
++IParm17
) {
407
17
    ParmVarDecl *Parm =
408
17
        ParmVarDecl::Create(Context, RVVIntrinsicDecl, Loc, Loc, nullptr,
409
17
                            FP->getParamType(IParm), nullptr, SC_None, nullptr);
410
17
    Parm->setScopeInfo(0, IParm);
411
17
    ParmList.push_back(Parm);
412
17
  }
413
6
  RVVIntrinsicDecl->setParams(ParmList);
414
415
  // Add function attributes.
416
6
  if (IsOverload)
417
0
    RVVIntrinsicDecl->addAttr(OverloadableAttr::CreateImplicit(Context));
418
419
  // Setup alias to __builtin_rvv_*
420
6
  IdentifierInfo &IntrinsicII = PP.getIdentifierTable().get(IDef.BuiltinName);
421
6
  RVVIntrinsicDecl->addAttr(
422
6
      BuiltinAliasAttr::CreateImplicit(S.Context, &IntrinsicII));
423
424
  // Add to symbol table.
425
6
  LR.addDecl(RVVIntrinsicDecl);
426
6
}
427
428
bool RISCVIntrinsicManagerImpl::CreateIntrinsicIfFound(LookupResult &LR,
429
                                                       IdentifierInfo *II,
430
7
                                                       Preprocessor &PP) {
431
7
  StringRef Name = II->getName();
432
433
  // Lookup the function name from the overload intrinsics first.
434
7
  auto OvIItr = OverloadIntrinsics.find(Name);
435
7
  if (OvIItr != OverloadIntrinsics.end()) {
436
0
    const RVVOverloadIntrinsicDef &OvIntrinsicDef = OvIItr->second;
437
0
    for (auto Index : OvIntrinsicDef.Indexes)
438
0
      CreateRVVIntrinsicDecl(LR, II, PP, Index,
439
0
                             /*IsOverload*/ true);
440
441
    // If we added overloads, need to resolve the lookup result.
442
0
    LR.resolveKind();
443
0
    return true;
444
0
  }
445
446
  // Lookup the function name from the intrinsics.
447
7
  auto Itr = Intrinsics.find(Name);
448
7
  if (Itr != Intrinsics.end()) {
449
6
    CreateRVVIntrinsicDecl(LR, II, PP, Itr->second,
450
6
                           /*IsOverload*/ false);
451
6
    return true;
452
6
  }
453
454
  // It's not an RVV intrinsics.
455
1
  return false;
456
7
}
457
458
namespace clang {
459
std::unique_ptr<clang::sema::RISCVIntrinsicManager>
460
1
CreateRISCVIntrinsicManager(Sema &S) {
461
1
  return std::make_unique<RISCVIntrinsicManagerImpl>(S);
462
1
}
463
} // namespace clang