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//===----------------------------------------------------------------------===//
11
12#include "clang/Sema/HLSLExternalSemaSource.h"
13#include "HLSLBuiltinTypeDeclBuilder.h"
14#include "clang/AST/ASTContext.h"
15#include "clang/AST/Attr.h"
16#include "clang/AST/Decl.h"
17#include "clang/AST/DeclCXX.h"
18#include "clang/AST/DeclTemplate.h"
19#include "clang/AST/Expr.h"
20#include "clang/AST/Type.h"
21#include "clang/Basic/SourceLocation.h"
22#include "clang/Sema/Lookup.h"
23#include "clang/Sema/Sema.h"
24#include "clang/Sema/SemaHLSL.h"
25#include "clang/Sema/TemplateDeduction.h"
26#include "llvm/ADT/SmallVector.h"
27
28using namespace clang;
29using namespace llvm::hlsl;
30
31using clang::hlsl::BuiltinTypeDeclBuilder;
32
33void HLSLExternalSemaSource::InitializeSema(Sema &S) {
34 SemaPtr = &S;
35 ASTContext &AST = SemaPtr->getASTContext();
36 // If the translation unit has external storage force external decls to load.
37 if (AST.getTranslationUnitDecl()->hasExternalLexicalStorage())
38 (void)AST.getTranslationUnitDecl()->decls_begin();
39
40 IdentifierInfo &HLSL = AST.Idents.get(Name: "hlsl", TokenCode: tok::TokenKind::identifier);
41 LookupResult Result(S, &HLSL, SourceLocation(), Sema::LookupNamespaceName);
42 NamespaceDecl *PrevDecl = nullptr;
43 if (S.LookupQualifiedName(R&: Result, LookupCtx: AST.getTranslationUnitDecl()))
44 PrevDecl = Result.getAsSingle<NamespaceDecl>();
45 HLSLNamespace = NamespaceDecl::Create(
46 C&: AST, DC: AST.getTranslationUnitDecl(), /*Inline=*/false, StartLoc: SourceLocation(),
47 IdLoc: SourceLocation(), Id: &HLSL, PrevDecl, /*Nested=*/false);
48 HLSLNamespace->setImplicit(true);
49 HLSLNamespace->setHasExternalLexicalStorage();
50 AST.getTranslationUnitDecl()->addDecl(D: HLSLNamespace);
51
52 // Force external decls in the HLSL namespace to load from the PCH.
53 (void)HLSLNamespace->getCanonicalDecl()->decls_begin();
54 defineTrivialHLSLTypes();
55 defineHLSLTypesWithForwardDeclarations();
56
57 // This adds a `using namespace hlsl` directive. In DXC, we don't put HLSL's
58 // built in types inside a namespace, but we are planning to change that in
59 // the near future. In order to be source compatible older versions of HLSL
60 // will need to implicitly use the hlsl namespace. For now in clang everything
61 // will get added to the namespace, and we can remove the using directive for
62 // future language versions to match HLSL's evolution.
63 auto *UsingDecl = UsingDirectiveDecl::Create(
64 C&: AST, DC: AST.getTranslationUnitDecl(), UsingLoc: SourceLocation(), NamespaceLoc: SourceLocation(),
65 QualifierLoc: NestedNameSpecifierLoc(), IdentLoc: SourceLocation(), Nominated: HLSLNamespace,
66 CommonAncestor: AST.getTranslationUnitDecl());
67
68 AST.getTranslationUnitDecl()->addDecl(D: UsingDecl);
69}
70
71void HLSLExternalSemaSource::defineHLSLVectorAlias() {
72 ASTContext &AST = SemaPtr->getASTContext();
73
74 llvm::SmallVector<NamedDecl *> TemplateParams;
75
76 auto *TypeParam = TemplateTypeParmDecl::Create(
77 C: AST, DC: HLSLNamespace, KeyLoc: SourceLocation(), NameLoc: SourceLocation(), D: 0, P: 0,
78 Id: &AST.Idents.get(Name: "element", TokenCode: tok::TokenKind::identifier), Typename: false, ParameterPack: false);
79 TypeParam->setDefaultArgument(
80 C: AST, DefArg: SemaPtr->getTrivialTemplateArgumentLoc(
81 Arg: TemplateArgument(AST.FloatTy), NTTPType: QualType(), Loc: SourceLocation()));
82
83 TemplateParams.emplace_back(Args&: TypeParam);
84
85 auto *SizeParam = NonTypeTemplateParmDecl::Create(
86 C: AST, DC: HLSLNamespace, StartLoc: SourceLocation(), IdLoc: SourceLocation(), D: 0, P: 1,
87 Id: &AST.Idents.get(Name: "element_count", TokenCode: tok::TokenKind::identifier), T: AST.IntTy,
88 ParameterPack: false, TInfo: AST.getTrivialTypeSourceInfo(T: AST.IntTy));
89 llvm::APInt Val(AST.getIntWidth(T: AST.IntTy), 4);
90 TemplateArgument Default(AST, llvm::APSInt(std::move(Val)), AST.IntTy,
91 /*IsDefaulted=*/true);
92 SizeParam->setDefaultArgument(
93 C: AST, DefArg: SemaPtr->getTrivialTemplateArgumentLoc(Arg: Default, NTTPType: AST.IntTy,
94 Loc: SourceLocation(), TemplateParam: SizeParam));
95 TemplateParams.emplace_back(Args&: SizeParam);
96
97 auto *ParamList =
98 TemplateParameterList::Create(C: AST, TemplateLoc: SourceLocation(), LAngleLoc: SourceLocation(),
99 Params: TemplateParams, RAngleLoc: SourceLocation(), RequiresClause: nullptr);
100
101 IdentifierInfo &II = AST.Idents.get(Name: "vector", TokenCode: tok::TokenKind::identifier);
102
103 QualType AliasType = AST.getDependentSizedExtVectorType(
104 VectorType: AST.getTemplateTypeParmType(Depth: 0, Index: 0, ParameterPack: false, ParmDecl: TypeParam),
105 SizeExpr: DeclRefExpr::Create(
106 Context: AST, QualifierLoc: NestedNameSpecifierLoc(), TemplateKWLoc: SourceLocation(), D: SizeParam, RefersToEnclosingVariableOrCapture: false,
107 NameInfo: DeclarationNameInfo(SizeParam->getDeclName(), SourceLocation()),
108 T: AST.IntTy, VK: VK_LValue),
109 AttrLoc: SourceLocation());
110
111 auto *Record = TypeAliasDecl::Create(C&: AST, DC: HLSLNamespace, StartLoc: SourceLocation(),
112 IdLoc: SourceLocation(), Id: &II,
113 TInfo: AST.getTrivialTypeSourceInfo(T: AliasType));
114 Record->setImplicit(true);
115
116 auto *Template =
117 TypeAliasTemplateDecl::Create(C&: AST, DC: HLSLNamespace, L: SourceLocation(),
118 Name: Record->getIdentifier(), Params: ParamList, Decl: Record);
119
120 Record->setDescribedAliasTemplate(Template);
121 Template->setImplicit(true);
122 Template->setLexicalDeclContext(Record->getDeclContext());
123 HLSLNamespace->addDecl(D: Template);
124}
125
126void HLSLExternalSemaSource::defineHLSLMatrixAlias() {
127 ASTContext &AST = SemaPtr->getASTContext();
128 llvm::SmallVector<NamedDecl *> TemplateParams;
129
130 auto *TypeParam = TemplateTypeParmDecl::Create(
131 C: AST, DC: HLSLNamespace, KeyLoc: SourceLocation(), NameLoc: SourceLocation(), D: 0, P: 0,
132 Id: &AST.Idents.get(Name: "element", TokenCode: tok::TokenKind::identifier), Typename: false, ParameterPack: false);
133 TypeParam->setDefaultArgument(
134 C: AST, DefArg: SemaPtr->getTrivialTemplateArgumentLoc(
135 Arg: TemplateArgument(AST.FloatTy), NTTPType: QualType(), Loc: SourceLocation()));
136
137 TemplateParams.emplace_back(Args&: TypeParam);
138
139 // these should be 64 bit to be consistent with other clang matrices.
140 auto *RowsParam = NonTypeTemplateParmDecl::Create(
141 C: AST, DC: HLSLNamespace, StartLoc: SourceLocation(), IdLoc: SourceLocation(), D: 0, P: 1,
142 Id: &AST.Idents.get(Name: "rows_count", TokenCode: tok::TokenKind::identifier), T: AST.IntTy,
143 ParameterPack: false, TInfo: AST.getTrivialTypeSourceInfo(T: AST.IntTy));
144 llvm::APInt RVal(AST.getIntWidth(T: AST.IntTy), 4);
145 TemplateArgument RDefault(AST, llvm::APSInt(std::move(RVal)), AST.IntTy,
146 /*IsDefaulted=*/true);
147 RowsParam->setDefaultArgument(
148 C: AST, DefArg: SemaPtr->getTrivialTemplateArgumentLoc(Arg: RDefault, NTTPType: AST.IntTy,
149 Loc: SourceLocation(), TemplateParam: RowsParam));
150 TemplateParams.emplace_back(Args&: RowsParam);
151
152 auto *ColsParam = NonTypeTemplateParmDecl::Create(
153 C: AST, DC: HLSLNamespace, StartLoc: SourceLocation(), IdLoc: SourceLocation(), D: 0, P: 2,
154 Id: &AST.Idents.get(Name: "cols_count", TokenCode: tok::TokenKind::identifier), T: AST.IntTy,
155 ParameterPack: false, TInfo: AST.getTrivialTypeSourceInfo(T: AST.IntTy));
156 llvm::APInt CVal(AST.getIntWidth(T: AST.IntTy), 4);
157 TemplateArgument CDefault(AST, llvm::APSInt(std::move(CVal)), AST.IntTy,
158 /*IsDefaulted=*/true);
159 ColsParam->setDefaultArgument(
160 C: AST, DefArg: SemaPtr->getTrivialTemplateArgumentLoc(Arg: CDefault, NTTPType: AST.IntTy,
161 Loc: SourceLocation(), TemplateParam: ColsParam));
162 TemplateParams.emplace_back(Args&: ColsParam);
163
164 const unsigned MaxMatDim = SemaPtr->getLangOpts().MaxMatrixDimension;
165
166 auto *MaxRow = IntegerLiteral::Create(
167 C: AST, V: llvm::APInt(AST.getIntWidth(T: AST.IntTy), MaxMatDim), type: AST.IntTy,
168 l: SourceLocation());
169 auto *MaxCol = IntegerLiteral::Create(
170 C: AST, V: llvm::APInt(AST.getIntWidth(T: AST.IntTy), MaxMatDim), type: AST.IntTy,
171 l: SourceLocation());
172
173 auto *RowsRef = DeclRefExpr::Create(
174 Context: AST, QualifierLoc: NestedNameSpecifierLoc(), TemplateKWLoc: SourceLocation(), D: RowsParam,
175 /*RefersToEnclosingVariableOrCapture*/ false,
176 NameInfo: DeclarationNameInfo(RowsParam->getDeclName(), SourceLocation()),
177 T: AST.IntTy, VK: VK_LValue);
178 auto *ColsRef = DeclRefExpr::Create(
179 Context: AST, QualifierLoc: NestedNameSpecifierLoc(), TemplateKWLoc: SourceLocation(), D: ColsParam,
180 /*RefersToEnclosingVariableOrCapture*/ false,
181 NameInfo: DeclarationNameInfo(ColsParam->getDeclName(), SourceLocation()),
182 T: AST.IntTy, VK: VK_LValue);
183
184 auto *RowsLE = BinaryOperator::Create(C: AST, lhs: RowsRef, rhs: MaxRow, opc: BO_LE, ResTy: AST.BoolTy,
185 VK: VK_PRValue, OK: OK_Ordinary,
186 opLoc: SourceLocation(), FPFeatures: FPOptionsOverride());
187 auto *ColsLE = BinaryOperator::Create(C: AST, lhs: ColsRef, rhs: MaxCol, opc: BO_LE, ResTy: AST.BoolTy,
188 VK: VK_PRValue, OK: OK_Ordinary,
189 opLoc: SourceLocation(), FPFeatures: FPOptionsOverride());
190
191 auto *RequiresExpr = BinaryOperator::Create(
192 C: AST, lhs: RowsLE, rhs: ColsLE, opc: BO_LAnd, ResTy: AST.BoolTy, VK: VK_PRValue, OK: OK_Ordinary,
193 opLoc: SourceLocation(), FPFeatures: FPOptionsOverride());
194
195 auto *ParamList = TemplateParameterList::Create(
196 C: AST, TemplateLoc: SourceLocation(), LAngleLoc: SourceLocation(), Params: TemplateParams, RAngleLoc: SourceLocation(),
197 RequiresClause: RequiresExpr);
198
199 IdentifierInfo &II = AST.Idents.get(Name: "matrix", TokenCode: tok::TokenKind::identifier);
200
201 QualType AliasType = AST.getDependentSizedMatrixType(
202 ElementType: AST.getTemplateTypeParmType(Depth: 0, Index: 0, ParameterPack: false, ParmDecl: TypeParam),
203 RowExpr: DeclRefExpr::Create(
204 Context: AST, QualifierLoc: NestedNameSpecifierLoc(), TemplateKWLoc: SourceLocation(), D: RowsParam, RefersToEnclosingVariableOrCapture: false,
205 NameInfo: DeclarationNameInfo(RowsParam->getDeclName(), SourceLocation()),
206 T: AST.IntTy, VK: VK_LValue),
207 ColumnExpr: DeclRefExpr::Create(
208 Context: AST, QualifierLoc: NestedNameSpecifierLoc(), TemplateKWLoc: SourceLocation(), D: ColsParam, RefersToEnclosingVariableOrCapture: false,
209 NameInfo: DeclarationNameInfo(ColsParam->getDeclName(), SourceLocation()),
210 T: AST.IntTy, VK: VK_LValue),
211 AttrLoc: SourceLocation());
212
213 auto *Record = TypeAliasDecl::Create(C&: AST, DC: HLSLNamespace, StartLoc: SourceLocation(),
214 IdLoc: SourceLocation(), Id: &II,
215 TInfo: AST.getTrivialTypeSourceInfo(T: AliasType));
216 Record->setImplicit(true);
217
218 auto *Template =
219 TypeAliasTemplateDecl::Create(C&: AST, DC: HLSLNamespace, L: SourceLocation(),
220 Name: Record->getIdentifier(), Params: ParamList, Decl: Record);
221
222 Record->setDescribedAliasTemplate(Template);
223 Template->setImplicit(true);
224 Template->setLexicalDeclContext(Record->getDeclContext());
225 HLSLNamespace->addDecl(D: Template);
226}
227
228void HLSLExternalSemaSource::defineTrivialHLSLTypes() {
229 defineHLSLVectorAlias();
230 defineHLSLMatrixAlias();
231}
232
233/// Set up common members and attributes for buffer types
234static BuiltinTypeDeclBuilder setupBufferType(CXXRecordDecl *Decl, Sema &S,
235 ResourceClass RC, bool IsROV,
236 bool RawBuffer, bool HasCounter) {
237 return BuiltinTypeDeclBuilder(S, Decl)
238 .addBufferHandles(RC, IsROV, RawBuffer, HasCounter)
239 .addDefaultHandleConstructor()
240 .addCopyConstructor()
241 .addCopyAssignmentOperator()
242 .addStaticInitializationFunctions(HasCounter);
243}
244
245/// Set up common members and attributes for sampler types
246static BuiltinTypeDeclBuilder setupSamplerType(CXXRecordDecl *Decl, Sema &S) {
247 return BuiltinTypeDeclBuilder(S, Decl)
248 .addSamplerHandle()
249 .addDefaultHandleConstructor()
250 .addCopyConstructor()
251 .addCopyAssignmentOperator()
252 .addStaticInitializationFunctions(HasCounter: false);
253}
254
255/// Set up common members and attributes for texture types
256static BuiltinTypeDeclBuilder setupTextureType(CXXRecordDecl *Decl, Sema &S,
257 ResourceClass RC, bool IsROV,
258 ResourceDimension Dim) {
259 return BuiltinTypeDeclBuilder(S, Decl)
260 .addTextureHandle(RC, IsROV, RD: Dim)
261 .addTextureLoadMethods(Dim)
262 .addDefaultHandleConstructor()
263 .addCopyConstructor()
264 .addCopyAssignmentOperator()
265 .addStaticInitializationFunctions(HasCounter: false)
266 .addSampleMethods(Dim)
267 .addSampleBiasMethods(Dim)
268 .addSampleGradMethods(Dim)
269 .addSampleLevelMethods(Dim)
270 .addSampleCmpMethods(Dim)
271 .addSampleCmpLevelZeroMethods(Dim)
272 .addGatherMethods(Dim)
273 .addGatherCmpMethods(Dim);
274}
275
276// Add a partial specialization for a template. The `TextureTemplate` is
277// `Texture<element_type>`, and it will be specialized for vectors:
278// `Texture<vector<element_type, element_count>>`.
279static ClassTemplatePartialSpecializationDecl *
280addVectorTexturePartialSpecialization(Sema &S, NamespaceDecl *HLSLNamespace,
281 ClassTemplateDecl *TextureTemplate) {
282 ASTContext &AST = S.getASTContext();
283
284 // Create the template parameters: element_type and element_count.
285 auto *ElementType = TemplateTypeParmDecl::Create(
286 C: AST, DC: HLSLNamespace, KeyLoc: SourceLocation(), NameLoc: SourceLocation(), D: 0, P: 0,
287 Id: &AST.Idents.get(Name: "element_type"), Typename: false, ParameterPack: false);
288 auto *ElementCount = NonTypeTemplateParmDecl::Create(
289 C: AST, DC: HLSLNamespace, StartLoc: SourceLocation(), IdLoc: SourceLocation(), D: 0, P: 1,
290 Id: &AST.Idents.get(Name: "element_count"), T: AST.IntTy, ParameterPack: false,
291 TInfo: AST.getTrivialTypeSourceInfo(T: AST.IntTy));
292
293 auto *TemplateParams = TemplateParameterList::Create(
294 C: AST, TemplateLoc: SourceLocation(), LAngleLoc: SourceLocation(), Params: {ElementType, ElementCount},
295 RAngleLoc: SourceLocation(), RequiresClause: nullptr);
296
297 // Create the dependent vector type: vector<element_type, element_count>.
298 QualType VectorType = AST.getDependentSizedExtVectorType(
299 VectorType: AST.getTemplateTypeParmType(Depth: 0, Index: 0, ParameterPack: false, ParmDecl: ElementType),
300 SizeExpr: DeclRefExpr::Create(
301 Context: AST, QualifierLoc: NestedNameSpecifierLoc(), TemplateKWLoc: SourceLocation(), D: ElementCount, RefersToEnclosingVariableOrCapture: false,
302 NameInfo: DeclarationNameInfo(ElementCount->getDeclName(), SourceLocation()),
303 T: AST.IntTy, VK: VK_LValue),
304 AttrLoc: SourceLocation());
305
306 // Create the partial specialization declaration.
307 QualType CanonInjectedTST =
308 AST.getCanonicalType(T: AST.getTemplateSpecializationType(
309 Keyword: ElaboratedTypeKeyword::Class, T: TemplateName(TextureTemplate),
310 SpecifiedArgs: {TemplateArgument(VectorType)}, CanonicalArgs: {}));
311
312 auto *PartialSpec = ClassTemplatePartialSpecializationDecl::Create(
313 Context&: AST, TK: TagDecl::TagKind::Class, DC: HLSLNamespace, StartLoc: SourceLocation(),
314 IdLoc: SourceLocation(), Params: TemplateParams, SpecializedTemplate: TextureTemplate,
315 Args: {TemplateArgument(VectorType)},
316 CanonInjectedTST: CanQualType::CreateUnsafe(Other: CanonInjectedTST), PrevDecl: nullptr);
317
318 // Set the template arguments as written.
319 TemplateArgument Arg(VectorType);
320 TemplateArgumentLoc ArgLoc =
321 S.getTrivialTemplateArgumentLoc(Arg, NTTPType: QualType(), Loc: SourceLocation());
322 TemplateArgumentListInfo ArgsInfo =
323 TemplateArgumentListInfo(SourceLocation(), SourceLocation());
324 ArgsInfo.addArgument(Loc: ArgLoc);
325 PartialSpec->setTemplateArgsAsWritten(
326 ASTTemplateArgumentListInfo::Create(C: AST, List: ArgsInfo));
327
328 PartialSpec->setImplicit(true);
329 PartialSpec->setLexicalDeclContext(HLSLNamespace);
330 PartialSpec->setHasExternalLexicalStorage();
331
332 // Add the partial specialization to the namespace and the class template.
333 HLSLNamespace->addDecl(D: PartialSpec);
334 TextureTemplate->AddPartialSpecialization(D: PartialSpec, InsertPos: nullptr);
335
336 return PartialSpec;
337}
338
339// This function is responsible for constructing the constraint expression for
340// this concept:
341// template<typename T> concept is_typed_resource_element_compatible =
342// __is_typed_resource_element_compatible<T>;
343static Expr *constructTypedBufferConstraintExpr(Sema &S, SourceLocation NameLoc,
344 TemplateTypeParmDecl *T) {
345 ASTContext &Context = S.getASTContext();
346
347 // Obtain the QualType for 'bool'
348 QualType BoolTy = Context.BoolTy;
349
350 // Create a QualType that points to this TemplateTypeParmDecl
351 QualType TType = Context.getTypeDeclType(Decl: T);
352
353 // Create a TypeSourceInfo for the template type parameter 'T'
354 TypeSourceInfo *TTypeSourceInfo =
355 Context.getTrivialTypeSourceInfo(T: TType, Loc: NameLoc);
356
357 TypeTraitExpr *TypedResExpr = TypeTraitExpr::Create(
358 C: Context, T: BoolTy, Loc: NameLoc, Kind: UTT_IsTypedResourceElementCompatible,
359 Args: {TTypeSourceInfo}, RParenLoc: NameLoc, Value: true);
360
361 return TypedResExpr;
362}
363
364// This function is responsible for constructing the constraint expression for
365// this concept:
366// template<typename T> concept is_structured_resource_element_compatible =
367// !__is_intangible<T> && sizeof(T) >= 1;
368static Expr *constructStructuredBufferConstraintExpr(Sema &S,
369 SourceLocation NameLoc,
370 TemplateTypeParmDecl *T) {
371 ASTContext &Context = S.getASTContext();
372
373 // Obtain the QualType for 'bool'
374 QualType BoolTy = Context.BoolTy;
375
376 // Create a QualType that points to this TemplateTypeParmDecl
377 QualType TType = Context.getTypeDeclType(Decl: T);
378
379 // Create a TypeSourceInfo for the template type parameter 'T'
380 TypeSourceInfo *TTypeSourceInfo =
381 Context.getTrivialTypeSourceInfo(T: TType, Loc: NameLoc);
382
383 TypeTraitExpr *IsIntangibleExpr =
384 TypeTraitExpr::Create(C: Context, T: BoolTy, Loc: NameLoc, Kind: UTT_IsIntangibleType,
385 Args: {TTypeSourceInfo}, RParenLoc: NameLoc, Value: true);
386
387 // negate IsIntangibleExpr
388 UnaryOperator *NotIntangibleExpr = UnaryOperator::Create(
389 C: Context, input: IsIntangibleExpr, opc: UO_LNot, type: BoolTy, VK: VK_LValue, OK: OK_Ordinary,
390 l: NameLoc, CanOverflow: false, FPFeatures: FPOptionsOverride());
391
392 // element types also may not be of 0 size
393 UnaryExprOrTypeTraitExpr *SizeOfExpr = new (Context) UnaryExprOrTypeTraitExpr(
394 UETT_SizeOf, TTypeSourceInfo, BoolTy, NameLoc, NameLoc);
395
396 // Create a BinaryOperator that checks if the size of the type is not equal to
397 // 1 Empty structs have a size of 1 in HLSL, so we need to check for that
398 IntegerLiteral *rhs = IntegerLiteral::Create(
399 C: Context, V: llvm::APInt(Context.getTypeSize(T: Context.getSizeType()), 1, true),
400 type: Context.getSizeType(), l: NameLoc);
401
402 BinaryOperator *SizeGEQOneExpr =
403 BinaryOperator::Create(C: Context, lhs: SizeOfExpr, rhs, opc: BO_GE, ResTy: BoolTy, VK: VK_LValue,
404 OK: OK_Ordinary, opLoc: NameLoc, FPFeatures: FPOptionsOverride());
405
406 // Combine the two constraints
407 BinaryOperator *CombinedExpr = BinaryOperator::Create(
408 C: Context, lhs: NotIntangibleExpr, rhs: SizeGEQOneExpr, opc: BO_LAnd, ResTy: BoolTy, VK: VK_LValue,
409 OK: OK_Ordinary, opLoc: NameLoc, FPFeatures: FPOptionsOverride());
410
411 return CombinedExpr;
412}
413
414static ConceptDecl *constructBufferConceptDecl(Sema &S, NamespaceDecl *NSD,
415 bool isTypedBuffer) {
416 ASTContext &Context = S.getASTContext();
417 DeclContext *DC = NSD->getDeclContext();
418 SourceLocation DeclLoc = SourceLocation();
419
420 IdentifierInfo &ElementTypeII = Context.Idents.get(Name: "element_type");
421 TemplateTypeParmDecl *T = TemplateTypeParmDecl::Create(
422 C: Context, DC: NSD->getDeclContext(), KeyLoc: DeclLoc, NameLoc: DeclLoc,
423 /*D=*/0,
424 /*P=*/0,
425 /*Id=*/&ElementTypeII,
426 /*Typename=*/true,
427 /*ParameterPack=*/false);
428
429 T->setDeclContext(DC);
430 T->setReferenced();
431
432 // Create and Attach Template Parameter List to ConceptDecl
433 TemplateParameterList *ConceptParams = TemplateParameterList::Create(
434 C: Context, TemplateLoc: DeclLoc, LAngleLoc: DeclLoc, Params: {T}, RAngleLoc: DeclLoc, RequiresClause: nullptr);
435
436 DeclarationName DeclName;
437 Expr *ConstraintExpr = nullptr;
438
439 if (isTypedBuffer) {
440 DeclName = DeclarationName(
441 &Context.Idents.get(Name: "__is_typed_resource_element_compatible"));
442 ConstraintExpr = constructTypedBufferConstraintExpr(S, NameLoc: DeclLoc, T);
443 } else {
444 DeclName = DeclarationName(
445 &Context.Idents.get(Name: "__is_structured_resource_element_compatible"));
446 ConstraintExpr = constructStructuredBufferConstraintExpr(S, NameLoc: DeclLoc, T);
447 }
448
449 // Create a ConceptDecl
450 ConceptDecl *CD =
451 ConceptDecl::Create(C&: Context, DC: NSD->getDeclContext(), L: DeclLoc, Name: DeclName,
452 Params: ConceptParams, ConstraintExpr);
453
454 // Attach the template parameter list to the ConceptDecl
455 CD->setTemplateParameters(ConceptParams);
456
457 // Add the concept declaration to the Translation Unit Decl
458 NSD->getDeclContext()->addDecl(D: CD);
459
460 return CD;
461}
462
463void HLSLExternalSemaSource::defineHLSLTypesWithForwardDeclarations() {
464 ASTContext &AST = SemaPtr->getASTContext();
465 CXXRecordDecl *Decl;
466 ConceptDecl *TypedBufferConcept = constructBufferConceptDecl(
467 S&: *SemaPtr, NSD: HLSLNamespace, /*isTypedBuffer*/ true);
468 ConceptDecl *StructuredBufferConcept = constructBufferConceptDecl(
469 S&: *SemaPtr, NSD: HLSLNamespace, /*isTypedBuffer*/ false);
470
471 Decl = BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "Buffer")
472 .addSimpleTemplateParams(Names: {"element_type"}, CD: TypedBufferConcept)
473 .finalizeForwardDeclaration();
474
475 onCompletion(Record: Decl, Fn: [this](CXXRecordDecl *Decl) {
476 setupBufferType(Decl, S&: *SemaPtr, RC: ResourceClass::SRV, /*IsROV=*/false,
477 /*RawBuffer=*/false, /*HasCounter=*/false)
478 .addArraySubscriptOperators()
479 .addLoadMethods()
480 .addGetDimensionsMethodForBuffer()
481 .completeDefinition();
482 });
483
484 Decl = BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "RWBuffer")
485 .addSimpleTemplateParams(Names: {"element_type"}, CD: TypedBufferConcept)
486 .finalizeForwardDeclaration();
487
488 onCompletion(Record: Decl, Fn: [this](CXXRecordDecl *Decl) {
489 setupBufferType(Decl, S&: *SemaPtr, RC: ResourceClass::UAV, /*IsROV=*/false,
490 /*RawBuffer=*/false, /*HasCounter=*/false)
491 .addArraySubscriptOperators()
492 .addLoadMethods()
493 .addGetDimensionsMethodForBuffer()
494 .completeDefinition();
495 });
496
497 Decl =
498 BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "RasterizerOrderedBuffer")
499 .addSimpleTemplateParams(Names: {"element_type"}, CD: StructuredBufferConcept)
500 .finalizeForwardDeclaration();
501 onCompletion(Record: Decl, Fn: [this](CXXRecordDecl *Decl) {
502 setupBufferType(Decl, S&: *SemaPtr, RC: ResourceClass::UAV, /*IsROV=*/true,
503 /*RawBuffer=*/false, /*HasCounter=*/false)
504 .addArraySubscriptOperators()
505 .addLoadMethods()
506 .addGetDimensionsMethodForBuffer()
507 .completeDefinition();
508 });
509
510 Decl = BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "StructuredBuffer")
511 .addSimpleTemplateParams(Names: {"element_type"}, CD: StructuredBufferConcept)
512 .finalizeForwardDeclaration();
513 onCompletion(Record: Decl, Fn: [this](CXXRecordDecl *Decl) {
514 setupBufferType(Decl, S&: *SemaPtr, RC: ResourceClass::SRV, /*IsROV=*/false,
515 /*RawBuffer=*/true, /*HasCounter=*/false)
516 .addArraySubscriptOperators()
517 .addLoadMethods()
518 .addGetDimensionsMethodForBuffer()
519 .completeDefinition();
520 });
521
522 Decl = BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "RWStructuredBuffer")
523 .addSimpleTemplateParams(Names: {"element_type"}, CD: StructuredBufferConcept)
524 .finalizeForwardDeclaration();
525 onCompletion(Record: Decl, Fn: [this](CXXRecordDecl *Decl) {
526 setupBufferType(Decl, S&: *SemaPtr, RC: ResourceClass::UAV, /*IsROV=*/false,
527 /*RawBuffer=*/true, /*HasCounter=*/true)
528 .addArraySubscriptOperators()
529 .addLoadMethods()
530 .addIncrementCounterMethod()
531 .addDecrementCounterMethod()
532 .addGetDimensionsMethodForBuffer()
533 .completeDefinition();
534 });
535
536 Decl =
537 BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "AppendStructuredBuffer")
538 .addSimpleTemplateParams(Names: {"element_type"}, CD: StructuredBufferConcept)
539 .finalizeForwardDeclaration();
540 onCompletion(Record: Decl, Fn: [this](CXXRecordDecl *Decl) {
541 setupBufferType(Decl, S&: *SemaPtr, RC: ResourceClass::UAV, /*IsROV=*/false,
542 /*RawBuffer=*/true, /*HasCounter=*/true)
543 .addAppendMethod()
544 .addGetDimensionsMethodForBuffer()
545 .completeDefinition();
546 });
547
548 Decl =
549 BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "ConsumeStructuredBuffer")
550 .addSimpleTemplateParams(Names: {"element_type"}, CD: StructuredBufferConcept)
551 .finalizeForwardDeclaration();
552 onCompletion(Record: Decl, Fn: [this](CXXRecordDecl *Decl) {
553 setupBufferType(Decl, S&: *SemaPtr, RC: ResourceClass::UAV, /*IsROV=*/false,
554 /*RawBuffer=*/true, /*HasCounter=*/true)
555 .addConsumeMethod()
556 .addGetDimensionsMethodForBuffer()
557 .completeDefinition();
558 });
559
560 Decl = BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace,
561 "RasterizerOrderedStructuredBuffer")
562 .addSimpleTemplateParams(Names: {"element_type"}, CD: StructuredBufferConcept)
563 .finalizeForwardDeclaration();
564 onCompletion(Record: Decl, Fn: [this](CXXRecordDecl *Decl) {
565 setupBufferType(Decl, S&: *SemaPtr, RC: ResourceClass::UAV, /*IsROV=*/true,
566 /*RawBuffer=*/true, /*HasCounter=*/true)
567 .addArraySubscriptOperators()
568 .addLoadMethods()
569 .addIncrementCounterMethod()
570 .addDecrementCounterMethod()
571 .addGetDimensionsMethodForBuffer()
572 .completeDefinition();
573 });
574
575 Decl = BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "ByteAddressBuffer")
576 .finalizeForwardDeclaration();
577 onCompletion(Record: Decl, Fn: [this](CXXRecordDecl *Decl) {
578 setupBufferType(Decl, S&: *SemaPtr, RC: ResourceClass::SRV, /*IsROV=*/false,
579 /*RawBuffer=*/true, /*HasCounter=*/false)
580 .addByteAddressBufferLoadMethods()
581 .addGetDimensionsMethodForBuffer()
582 .completeDefinition();
583 });
584 Decl = BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "RWByteAddressBuffer")
585 .finalizeForwardDeclaration();
586 onCompletion(Record: Decl, Fn: [this](CXXRecordDecl *Decl) {
587 setupBufferType(Decl, S&: *SemaPtr, RC: ResourceClass::UAV, /*IsROV=*/false,
588 /*RawBuffer=*/true, /*HasCounter=*/false)
589 .addByteAddressBufferLoadMethods()
590 .addByteAddressBufferStoreMethods()
591 .addGetDimensionsMethodForBuffer()
592 .completeDefinition();
593 });
594 Decl = BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace,
595 "RasterizerOrderedByteAddressBuffer")
596 .finalizeForwardDeclaration();
597 onCompletion(Record: Decl, Fn: [this](CXXRecordDecl *Decl) {
598 setupBufferType(Decl, S&: *SemaPtr, RC: ResourceClass::UAV, /*IsROV=*/true,
599 /*RawBuffer=*/true, /*HasCounter=*/false)
600 .addGetDimensionsMethodForBuffer()
601 .completeDefinition();
602 });
603
604 Decl = BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "SamplerState")
605 .finalizeForwardDeclaration();
606 onCompletion(Record: Decl, Fn: [this](CXXRecordDecl *Decl) {
607 setupSamplerType(Decl, S&: *SemaPtr).completeDefinition();
608 });
609
610 Decl =
611 BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "SamplerComparisonState")
612 .finalizeForwardDeclaration();
613 onCompletion(Record: Decl, Fn: [this](CXXRecordDecl *Decl) {
614 setupSamplerType(Decl, S&: *SemaPtr).completeDefinition();
615 });
616
617 QualType Float4Ty = AST.getExtVectorType(VectorType: AST.FloatTy, NumElts: 4);
618 Decl = BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "Texture2D")
619 .addSimpleTemplateParams(Names: {"element_type"}, DefaultTypes: {Float4Ty},
620 CD: TypedBufferConcept)
621 .finalizeForwardDeclaration();
622
623 onCompletion(Record: Decl, Fn: [this](CXXRecordDecl *Decl) {
624 setupTextureType(Decl, S&: *SemaPtr, RC: ResourceClass::SRV, /*IsROV=*/false,
625 Dim: ResourceDimension::Dim2D)
626 .completeDefinition();
627 });
628
629 auto *PartialSpec = addVectorTexturePartialSpecialization(
630 S&: *SemaPtr, HLSLNamespace, TextureTemplate: Decl->getDescribedClassTemplate());
631 onCompletion(Record: PartialSpec, Fn: [this](CXXRecordDecl *Decl) {
632 setupTextureType(Decl, S&: *SemaPtr, RC: ResourceClass::SRV, /*IsROV=*/false,
633 Dim: ResourceDimension::Dim2D)
634 .completeDefinition();
635 });
636}
637
638void HLSLExternalSemaSource::onCompletion(CXXRecordDecl *Record,
639 CompletionFunction Fn) {
640 if (!Record->isCompleteDefinition())
641 Completions.insert(KV: std::make_pair(x: Record->getCanonicalDecl(), y&: Fn));
642}
643
644void HLSLExternalSemaSource::CompleteType(TagDecl *Tag) {
645 if (!isa<CXXRecordDecl>(Val: Tag))
646 return;
647 auto Record = cast<CXXRecordDecl>(Val: Tag);
648
649 // If this is a specialization, we need to get the underlying templated
650 // declaration and complete that.
651 if (auto TDecl = dyn_cast<ClassTemplateSpecializationDecl>(Val: Record)) {
652 if (!isa<ClassTemplatePartialSpecializationDecl>(Val: TDecl)) {
653 ClassTemplateDecl *Template = TDecl->getSpecializedTemplate();
654 llvm::SmallVector<ClassTemplatePartialSpecializationDecl *, 4> Partials;
655 Template->getPartialSpecializations(PS&: Partials);
656 ClassTemplatePartialSpecializationDecl *MatchedPartial = nullptr;
657 for (auto *Partial : Partials) {
658 sema::TemplateDeductionInfo Info(TDecl->getLocation());
659 if (SemaPtr->DeduceTemplateArguments(Partial, TemplateArgs: TDecl->getTemplateArgs(),
660 Info) ==
661 TemplateDeductionResult::Success) {
662 MatchedPartial = Partial;
663 break;
664 }
665 }
666 if (MatchedPartial)
667 Record = MatchedPartial;
668 else
669 Record = Template->getTemplatedDecl();
670 }
671 }
672 Record = Record->getCanonicalDecl();
673 auto It = Completions.find(Val: Record);
674 if (It == Completions.end())
675 return;
676 It->second(Record);
677 Completions.erase(I: It);
678}
679