[DFAJumpThreading] Remove incoming StartBlock from all phis when unfolding select...
[llvm-project.git] / clang / lib / Sema / HLSLExternalSemaSource.cpp
blob8de144486c91df6297c0ecee79bb9af0a66339e1
1 //===--- HLSLExternalSemaSource.cpp - HLSL Sema Source --------------------===//
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 //
10 //===----------------------------------------------------------------------===//
12 #include "clang/Sema/HLSLExternalSemaSource.h"
13 #include "clang/AST/ASTContext.h"
14 #include "clang/AST/Attr.h"
15 #include "clang/AST/DeclCXX.h"
16 #include "clang/Basic/AttrKinds.h"
17 #include "clang/Basic/HLSLRuntime.h"
18 #include "clang/Sema/Lookup.h"
19 #include "clang/Sema/Sema.h"
20 #include "llvm/Frontend/HLSL/HLSLResource.h"
22 #include <functional>
24 using namespace clang;
25 using namespace llvm::hlsl;
27 namespace {
29 struct TemplateParameterListBuilder;
31 struct BuiltinTypeDeclBuilder {
32 CXXRecordDecl *Record = nullptr;
33 ClassTemplateDecl *Template = nullptr;
34 ClassTemplateDecl *PrevTemplate = nullptr;
35 NamespaceDecl *HLSLNamespace = nullptr;
36 llvm::StringMap<FieldDecl *> Fields;
38 BuiltinTypeDeclBuilder(CXXRecordDecl *R) : Record(R) {
39 Record->startDefinition();
40 Template = Record->getDescribedClassTemplate();
43 BuiltinTypeDeclBuilder(Sema &S, NamespaceDecl *Namespace, StringRef Name)
44 : HLSLNamespace(Namespace) {
45 ASTContext &AST = S.getASTContext();
46 IdentifierInfo &II = AST.Idents.get(Name, tok::TokenKind::identifier);
48 LookupResult Result(S, &II, SourceLocation(), Sema::LookupTagName);
49 CXXRecordDecl *PrevDecl = nullptr;
50 if (S.LookupQualifiedName(Result, HLSLNamespace)) {
51 NamedDecl *Found = Result.getFoundDecl();
52 if (auto *TD = dyn_cast<ClassTemplateDecl>(Found)) {
53 PrevDecl = TD->getTemplatedDecl();
54 PrevTemplate = TD;
55 } else
56 PrevDecl = dyn_cast<CXXRecordDecl>(Found);
57 assert(PrevDecl && "Unexpected lookup result type.");
60 if (PrevDecl && PrevDecl->isCompleteDefinition()) {
61 Record = PrevDecl;
62 return;
65 Record = CXXRecordDecl::Create(AST, TagDecl::TagKind::Class, HLSLNamespace,
66 SourceLocation(), SourceLocation(), &II,
67 PrevDecl, true);
68 Record->setImplicit(true);
69 Record->setLexicalDeclContext(HLSLNamespace);
70 Record->setHasExternalLexicalStorage();
72 // Don't let anyone derive from built-in types.
73 Record->addAttr(FinalAttr::CreateImplicit(AST, SourceRange(),
74 FinalAttr::Keyword_final));
77 ~BuiltinTypeDeclBuilder() {
78 if (HLSLNamespace && !Template && Record->getDeclContext() == HLSLNamespace)
79 HLSLNamespace->addDecl(Record);
82 BuiltinTypeDeclBuilder &
83 addMemberVariable(StringRef Name, QualType Type,
84 AccessSpecifier Access = AccessSpecifier::AS_private) {
85 if (Record->isCompleteDefinition())
86 return *this;
87 assert(Record->isBeingDefined() &&
88 "Definition must be started before adding members!");
89 ASTContext &AST = Record->getASTContext();
91 IdentifierInfo &II = AST.Idents.get(Name, tok::TokenKind::identifier);
92 TypeSourceInfo *MemTySource =
93 AST.getTrivialTypeSourceInfo(Type, SourceLocation());
94 auto *Field = FieldDecl::Create(
95 AST, Record, SourceLocation(), SourceLocation(), &II, Type, MemTySource,
96 nullptr, false, InClassInitStyle::ICIS_NoInit);
97 Field->setAccess(Access);
98 Field->setImplicit(true);
99 Record->addDecl(Field);
100 Fields[Name] = Field;
101 return *this;
104 BuiltinTypeDeclBuilder &
105 addHandleMember(AccessSpecifier Access = AccessSpecifier::AS_private) {
106 if (Record->isCompleteDefinition())
107 return *this;
108 QualType Ty = Record->getASTContext().VoidPtrTy;
109 if (Template) {
110 if (const auto *TTD = dyn_cast<TemplateTypeParmDecl>(
111 Template->getTemplateParameters()->getParam(0)))
112 Ty = Record->getASTContext().getPointerType(
113 QualType(TTD->getTypeForDecl(), 0));
115 return addMemberVariable("h", Ty, Access);
118 BuiltinTypeDeclBuilder &annotateResourceClass(ResourceClass RC,
119 ResourceKind RK) {
120 if (Record->isCompleteDefinition())
121 return *this;
122 Record->addAttr(
123 HLSLResourceAttr::CreateImplicit(Record->getASTContext(), RC, RK));
124 return *this;
127 static DeclRefExpr *lookupBuiltinFunction(ASTContext &AST, Sema &S,
128 StringRef Name) {
129 CXXScopeSpec SS;
130 IdentifierInfo &II = AST.Idents.get(Name, tok::TokenKind::identifier);
131 DeclarationNameInfo NameInfo =
132 DeclarationNameInfo(DeclarationName(&II), SourceLocation());
133 LookupResult R(S, NameInfo, Sema::LookupOrdinaryName);
134 S.LookupParsedName(R, S.getCurScope(), &SS, false);
135 assert(R.isSingleResult() &&
136 "Since this is a builtin it should always resolve!");
137 auto *VD = cast<ValueDecl>(R.getFoundDecl());
138 QualType Ty = VD->getType();
139 return DeclRefExpr::Create(AST, NestedNameSpecifierLoc(), SourceLocation(),
140 VD, false, NameInfo, Ty, VK_PRValue);
143 static Expr *emitResourceClassExpr(ASTContext &AST, ResourceClass RC) {
144 return IntegerLiteral::Create(
145 AST,
146 llvm::APInt(AST.getIntWidth(AST.UnsignedCharTy),
147 static_cast<uint8_t>(RC)),
148 AST.UnsignedCharTy, SourceLocation());
151 BuiltinTypeDeclBuilder &addDefaultHandleConstructor(Sema &S,
152 ResourceClass RC) {
153 if (Record->isCompleteDefinition())
154 return *this;
155 ASTContext &AST = Record->getASTContext();
157 QualType ConstructorType =
158 AST.getFunctionType(AST.VoidTy, {}, FunctionProtoType::ExtProtoInfo());
160 CanQualType CanTy = Record->getTypeForDecl()->getCanonicalTypeUnqualified();
161 DeclarationName Name = AST.DeclarationNames.getCXXConstructorName(CanTy);
162 CXXConstructorDecl *Constructor = CXXConstructorDecl::Create(
163 AST, Record, SourceLocation(),
164 DeclarationNameInfo(Name, SourceLocation()), ConstructorType,
165 AST.getTrivialTypeSourceInfo(ConstructorType, SourceLocation()),
166 ExplicitSpecifier(), false, true, false,
167 ConstexprSpecKind::Unspecified);
169 DeclRefExpr *Fn =
170 lookupBuiltinFunction(AST, S, "__builtin_hlsl_create_handle");
172 Expr *RCExpr = emitResourceClassExpr(AST, RC);
173 Expr *Call = CallExpr::Create(AST, Fn, {RCExpr}, AST.VoidPtrTy, VK_PRValue,
174 SourceLocation(), FPOptionsOverride());
176 CXXThisExpr *This = CXXThisExpr::Create(
177 AST, SourceLocation(), Constructor->getFunctionObjectParameterType(),
178 true);
179 Expr *Handle = MemberExpr::CreateImplicit(AST, This, false, Fields["h"],
180 Fields["h"]->getType(), VK_LValue,
181 OK_Ordinary);
183 // If the handle isn't a void pointer, cast the builtin result to the
184 // correct type.
185 if (Handle->getType().getCanonicalType() != AST.VoidPtrTy) {
186 Call = CXXStaticCastExpr::Create(
187 AST, Handle->getType(), VK_PRValue, CK_Dependent, Call, nullptr,
188 AST.getTrivialTypeSourceInfo(Handle->getType(), SourceLocation()),
189 FPOptionsOverride(), SourceLocation(), SourceLocation(),
190 SourceRange());
193 BinaryOperator *Assign = BinaryOperator::Create(
194 AST, Handle, Call, BO_Assign, Handle->getType(), VK_LValue, OK_Ordinary,
195 SourceLocation(), FPOptionsOverride());
197 Constructor->setBody(
198 CompoundStmt::Create(AST, {Assign}, FPOptionsOverride(),
199 SourceLocation(), SourceLocation()));
200 Constructor->setAccess(AccessSpecifier::AS_public);
201 Record->addDecl(Constructor);
202 return *this;
205 BuiltinTypeDeclBuilder &addArraySubscriptOperators() {
206 if (Record->isCompleteDefinition())
207 return *this;
208 addArraySubscriptOperator(true);
209 addArraySubscriptOperator(false);
210 return *this;
213 BuiltinTypeDeclBuilder &addArraySubscriptOperator(bool IsConst) {
214 if (Record->isCompleteDefinition())
215 return *this;
216 assert(Fields.count("h") > 0 &&
217 "Subscript operator must be added after the handle.");
219 FieldDecl *Handle = Fields["h"];
220 ASTContext &AST = Record->getASTContext();
222 assert(Handle->getType().getCanonicalType() != AST.VoidPtrTy &&
223 "Not yet supported for void pointer handles.");
225 QualType ElemTy =
226 QualType(Handle->getType()->getPointeeOrArrayElementType(), 0);
227 QualType ReturnTy = ElemTy;
229 FunctionProtoType::ExtProtoInfo ExtInfo;
231 // Subscript operators return references to elements, const makes the
232 // reference and method const so that the underlying data is not mutable.
233 ReturnTy = AST.getLValueReferenceType(ReturnTy);
234 if (IsConst) {
235 ExtInfo.TypeQuals.addConst();
236 ReturnTy.addConst();
239 QualType MethodTy =
240 AST.getFunctionType(ReturnTy, {AST.UnsignedIntTy}, ExtInfo);
241 auto *TSInfo = AST.getTrivialTypeSourceInfo(MethodTy, SourceLocation());
242 auto *MethodDecl = CXXMethodDecl::Create(
243 AST, Record, SourceLocation(),
244 DeclarationNameInfo(
245 AST.DeclarationNames.getCXXOperatorName(OO_Subscript),
246 SourceLocation()),
247 MethodTy, TSInfo, SC_None, false, false, ConstexprSpecKind::Unspecified,
248 SourceLocation());
250 IdentifierInfo &II = AST.Idents.get("Idx", tok::TokenKind::identifier);
251 auto *IdxParam = ParmVarDecl::Create(
252 AST, MethodDecl->getDeclContext(), SourceLocation(), SourceLocation(),
253 &II, AST.UnsignedIntTy,
254 AST.getTrivialTypeSourceInfo(AST.UnsignedIntTy, SourceLocation()),
255 SC_None, nullptr);
256 MethodDecl->setParams({IdxParam});
258 // Also add the parameter to the function prototype.
259 auto FnProtoLoc = TSInfo->getTypeLoc().getAs<FunctionProtoTypeLoc>();
260 FnProtoLoc.setParam(0, IdxParam);
262 auto *This =
263 CXXThisExpr::Create(AST, SourceLocation(),
264 MethodDecl->getFunctionObjectParameterType(), true);
265 auto *HandleAccess = MemberExpr::CreateImplicit(
266 AST, This, false, Handle, Handle->getType(), VK_LValue, OK_Ordinary);
268 auto *IndexExpr = DeclRefExpr::Create(
269 AST, NestedNameSpecifierLoc(), SourceLocation(), IdxParam, false,
270 DeclarationNameInfo(IdxParam->getDeclName(), SourceLocation()),
271 AST.UnsignedIntTy, VK_PRValue);
273 auto *Array =
274 new (AST) ArraySubscriptExpr(HandleAccess, IndexExpr, ElemTy, VK_LValue,
275 OK_Ordinary, SourceLocation());
277 auto *Return = ReturnStmt::Create(AST, SourceLocation(), Array, nullptr);
279 MethodDecl->setBody(CompoundStmt::Create(AST, {Return}, FPOptionsOverride(),
280 SourceLocation(),
281 SourceLocation()));
282 MethodDecl->setLexicalDeclContext(Record);
283 MethodDecl->setAccess(AccessSpecifier::AS_public);
284 MethodDecl->addAttr(AlwaysInlineAttr::CreateImplicit(
285 AST, SourceRange(), AlwaysInlineAttr::CXX11_clang_always_inline));
286 Record->addDecl(MethodDecl);
288 return *this;
291 BuiltinTypeDeclBuilder &startDefinition() {
292 if (Record->isCompleteDefinition())
293 return *this;
294 Record->startDefinition();
295 return *this;
298 BuiltinTypeDeclBuilder &completeDefinition() {
299 if (Record->isCompleteDefinition())
300 return *this;
301 assert(Record->isBeingDefined() &&
302 "Definition must be started before completing it.");
304 Record->completeDefinition();
305 return *this;
308 TemplateParameterListBuilder addTemplateArgumentList();
311 struct TemplateParameterListBuilder {
312 BuiltinTypeDeclBuilder &Builder;
313 ASTContext &AST;
314 llvm::SmallVector<NamedDecl *> Params;
316 TemplateParameterListBuilder(BuiltinTypeDeclBuilder &RB)
317 : Builder(RB), AST(RB.Record->getASTContext()) {}
319 ~TemplateParameterListBuilder() { finalizeTemplateArgs(); }
321 TemplateParameterListBuilder &
322 addTypeParameter(StringRef Name, QualType DefaultValue = QualType()) {
323 if (Builder.Record->isCompleteDefinition())
324 return *this;
325 unsigned Position = static_cast<unsigned>(Params.size());
326 auto *Decl = TemplateTypeParmDecl::Create(
327 AST, Builder.Record->getDeclContext(), SourceLocation(),
328 SourceLocation(), /* TemplateDepth */ 0, Position,
329 &AST.Idents.get(Name, tok::TokenKind::identifier), /* Typename */ false,
330 /* ParameterPack */ false);
331 if (!DefaultValue.isNull())
332 Decl->setDefaultArgument(AST.getTrivialTypeSourceInfo(DefaultValue));
334 Params.emplace_back(Decl);
335 return *this;
338 BuiltinTypeDeclBuilder &finalizeTemplateArgs() {
339 if (Params.empty())
340 return Builder;
341 auto *ParamList =
342 TemplateParameterList::Create(AST, SourceLocation(), SourceLocation(),
343 Params, SourceLocation(), nullptr);
344 Builder.Template = ClassTemplateDecl::Create(
345 AST, Builder.Record->getDeclContext(), SourceLocation(),
346 DeclarationName(Builder.Record->getIdentifier()), ParamList,
347 Builder.Record);
348 Builder.Record->setDescribedClassTemplate(Builder.Template);
349 Builder.Template->setImplicit(true);
350 Builder.Template->setLexicalDeclContext(Builder.Record->getDeclContext());
351 // NOTE: setPreviousDecl before addDecl so new decl replace old decl when
352 // make visible.
353 Builder.Template->setPreviousDecl(Builder.PrevTemplate);
354 Builder.Record->getDeclContext()->addDecl(Builder.Template);
355 Params.clear();
357 QualType T = Builder.Template->getInjectedClassNameSpecialization();
358 T = AST.getInjectedClassNameType(Builder.Record, T);
360 return Builder;
364 TemplateParameterListBuilder BuiltinTypeDeclBuilder::addTemplateArgumentList() {
365 return TemplateParameterListBuilder(*this);
367 } // namespace
369 HLSLExternalSemaSource::~HLSLExternalSemaSource() {}
371 void HLSLExternalSemaSource::InitializeSema(Sema &S) {
372 SemaPtr = &S;
373 ASTContext &AST = SemaPtr->getASTContext();
374 // If the translation unit has external storage force external decls to load.
375 if (AST.getTranslationUnitDecl()->hasExternalLexicalStorage())
376 (void)AST.getTranslationUnitDecl()->decls_begin();
378 IdentifierInfo &HLSL = AST.Idents.get("hlsl", tok::TokenKind::identifier);
379 LookupResult Result(S, &HLSL, SourceLocation(), Sema::LookupNamespaceName);
380 NamespaceDecl *PrevDecl = nullptr;
381 if (S.LookupQualifiedName(Result, AST.getTranslationUnitDecl()))
382 PrevDecl = Result.getAsSingle<NamespaceDecl>();
383 HLSLNamespace = NamespaceDecl::Create(
384 AST, AST.getTranslationUnitDecl(), /*Inline=*/false, SourceLocation(),
385 SourceLocation(), &HLSL, PrevDecl, /*Nested=*/false);
386 HLSLNamespace->setImplicit(true);
387 HLSLNamespace->setHasExternalLexicalStorage();
388 AST.getTranslationUnitDecl()->addDecl(HLSLNamespace);
390 // Force external decls in the HLSL namespace to load from the PCH.
391 (void)HLSLNamespace->getCanonicalDecl()->decls_begin();
392 defineTrivialHLSLTypes();
393 forwardDeclareHLSLTypes();
395 // This adds a `using namespace hlsl` directive. In DXC, we don't put HLSL's
396 // built in types inside a namespace, but we are planning to change that in
397 // the near future. In order to be source compatible older versions of HLSL
398 // will need to implicitly use the hlsl namespace. For now in clang everything
399 // will get added to the namespace, and we can remove the using directive for
400 // future language versions to match HLSL's evolution.
401 auto *UsingDecl = UsingDirectiveDecl::Create(
402 AST, AST.getTranslationUnitDecl(), SourceLocation(), SourceLocation(),
403 NestedNameSpecifierLoc(), SourceLocation(), HLSLNamespace,
404 AST.getTranslationUnitDecl());
406 AST.getTranslationUnitDecl()->addDecl(UsingDecl);
409 void HLSLExternalSemaSource::defineHLSLVectorAlias() {
410 ASTContext &AST = SemaPtr->getASTContext();
412 llvm::SmallVector<NamedDecl *> TemplateParams;
414 auto *TypeParam = TemplateTypeParmDecl::Create(
415 AST, HLSLNamespace, SourceLocation(), SourceLocation(), 0, 0,
416 &AST.Idents.get("element", tok::TokenKind::identifier), false, false);
417 TypeParam->setDefaultArgument(AST.getTrivialTypeSourceInfo(AST.FloatTy));
419 TemplateParams.emplace_back(TypeParam);
421 auto *SizeParam = NonTypeTemplateParmDecl::Create(
422 AST, HLSLNamespace, SourceLocation(), SourceLocation(), 0, 1,
423 &AST.Idents.get("element_count", tok::TokenKind::identifier), AST.IntTy,
424 false, AST.getTrivialTypeSourceInfo(AST.IntTy));
425 Expr *LiteralExpr =
426 IntegerLiteral::Create(AST, llvm::APInt(AST.getIntWidth(AST.IntTy), 4),
427 AST.IntTy, SourceLocation());
428 SizeParam->setDefaultArgument(LiteralExpr);
429 TemplateParams.emplace_back(SizeParam);
431 auto *ParamList =
432 TemplateParameterList::Create(AST, SourceLocation(), SourceLocation(),
433 TemplateParams, SourceLocation(), nullptr);
435 IdentifierInfo &II = AST.Idents.get("vector", tok::TokenKind::identifier);
437 QualType AliasType = AST.getDependentSizedExtVectorType(
438 AST.getTemplateTypeParmType(0, 0, false, TypeParam),
439 DeclRefExpr::Create(
440 AST, NestedNameSpecifierLoc(), SourceLocation(), SizeParam, false,
441 DeclarationNameInfo(SizeParam->getDeclName(), SourceLocation()),
442 AST.IntTy, VK_LValue),
443 SourceLocation());
445 auto *Record = TypeAliasDecl::Create(AST, HLSLNamespace, SourceLocation(),
446 SourceLocation(), &II,
447 AST.getTrivialTypeSourceInfo(AliasType));
448 Record->setImplicit(true);
450 auto *Template =
451 TypeAliasTemplateDecl::Create(AST, HLSLNamespace, SourceLocation(),
452 Record->getIdentifier(), ParamList, Record);
454 Record->setDescribedAliasTemplate(Template);
455 Template->setImplicit(true);
456 Template->setLexicalDeclContext(Record->getDeclContext());
457 HLSLNamespace->addDecl(Template);
460 void HLSLExternalSemaSource::defineTrivialHLSLTypes() {
461 defineHLSLVectorAlias();
463 ResourceDecl = BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "Resource")
464 .startDefinition()
465 .addHandleMember(AccessSpecifier::AS_public)
466 .completeDefinition()
467 .Record;
470 void HLSLExternalSemaSource::forwardDeclareHLSLTypes() {
471 CXXRecordDecl *Decl;
472 Decl = BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "RWBuffer")
473 .addTemplateArgumentList()
474 .addTypeParameter("element_type", SemaPtr->getASTContext().FloatTy)
475 .finalizeTemplateArgs()
476 .Record;
477 if (!Decl->isCompleteDefinition())
478 Completions.insert(
479 std::make_pair(Decl->getCanonicalDecl(),
480 std::bind(&HLSLExternalSemaSource::completeBufferType,
481 this, std::placeholders::_1)));
484 void HLSLExternalSemaSource::CompleteType(TagDecl *Tag) {
485 if (!isa<CXXRecordDecl>(Tag))
486 return;
487 auto Record = cast<CXXRecordDecl>(Tag);
489 // If this is a specialization, we need to get the underlying templated
490 // declaration and complete that.
491 if (auto TDecl = dyn_cast<ClassTemplateSpecializationDecl>(Record))
492 Record = TDecl->getSpecializedTemplate()->getTemplatedDecl();
493 Record = Record->getCanonicalDecl();
494 auto It = Completions.find(Record);
495 if (It == Completions.end())
496 return;
497 It->second(Record);
500 void HLSLExternalSemaSource::completeBufferType(CXXRecordDecl *Record) {
501 BuiltinTypeDeclBuilder(Record)
502 .addHandleMember()
503 .addDefaultHandleConstructor(*SemaPtr, ResourceClass::UAV)
504 .addArraySubscriptOperators()
505 .annotateResourceClass(ResourceClass::UAV, ResourceKind::TypedBuffer)
506 .completeDefinition();