Coverage Report

Created: 2024-01-17 10:31

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