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