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