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/AddressSpaces.h"
22#include "clang/Basic/SourceLocation.h"
23#include "clang/Lex/Preprocessor.h"
24#include "clang/Sema/Lookup.h"
25#include "clang/Sema/Sema.h"
26#include "clang/Sema/SemaHLSL.h"
27#include "llvm/ADT/STLExtras.h"
28#include "llvm/ADT/SmallVector.h"
29
30using namespace clang;
31using namespace llvm::hlsl;
32
33using clang::hlsl::BuiltinTypeDeclBuilder;
34
35void HLSLExternalSemaSource::InitializeSema(Sema &S) {
36 SemaPtr = &S;
37 ASTContext &AST = SemaPtr->getASTContext();
38 // If the translation unit has external storage force external decls to load.
39 if (AST.getTranslationUnitDecl()->hasExternalLexicalStorage())
40 (void)AST.getTranslationUnitDecl()->decls_begin();
41
42 IdentifierInfo &HLSL = AST.Idents.get(Name: "hlsl", TokenCode: tok::TokenKind::identifier);
43 LookupResult Result(S, &HLSL, SourceLocation(), Sema::LookupNamespaceName);
44 NamespaceDecl *PrevDecl = nullptr;
45 if (S.LookupQualifiedName(R&: Result, LookupCtx: AST.getTranslationUnitDecl()))
46 PrevDecl = Result.getAsSingle<NamespaceDecl>();
47 HLSLNamespace = NamespaceDecl::Create(
48 C&: AST, DC: AST.getTranslationUnitDecl(), /*Inline=*/false, StartLoc: SourceLocation(),
49 IdLoc: SourceLocation(), Id: &HLSL, PrevDecl, /*Nested=*/false);
50 HLSLNamespace->setImplicit(true);
51 HLSLNamespace->setHasExternalLexicalStorage();
52 AST.getTranslationUnitDecl()->addDecl(D: HLSLNamespace);
53
54 // Force external decls in the HLSL namespace to load from the PCH.
55 (void)HLSLNamespace->getCanonicalDecl()->decls_begin();
56 defineTrivialHLSLTypes();
57 defineHLSLTypesWithForwardDeclarations();
58 defineHLSLAtomicIntrinsics();
59
60 // This adds a `using namespace hlsl` directive. In DXC, we don't put HLSL's
61 // built in types inside a namespace, but we are planning to change that in
62 // the near future. In order to be source compatible older versions of HLSL
63 // will need to implicitly use the hlsl namespace. For now in clang everything
64 // will get added to the namespace, and we can remove the using directive for
65 // future language versions to match HLSL's evolution.
66 auto *UsingDecl = UsingDirectiveDecl::Create(
67 C&: AST, DC: AST.getTranslationUnitDecl(), UsingLoc: SourceLocation(), NamespaceLoc: SourceLocation(),
68 QualifierLoc: NestedNameSpecifierLoc(), IdentLoc: SourceLocation(), Nominated: HLSLNamespace,
69 CommonAncestor: AST.getTranslationUnitDecl());
70
71 AST.getTranslationUnitDecl()->addDecl(D: UsingDecl);
72}
73
74void HLSLExternalSemaSource::defineHLSLVectorAlias() {
75 ASTContext &AST = SemaPtr->getASTContext();
76
77 llvm::SmallVector<NamedDecl *> TemplateParams;
78
79 auto *TypeParam = TemplateTypeParmDecl::Create(
80 C: AST, DC: HLSLNamespace, KeyLoc: SourceLocation(), NameLoc: SourceLocation(), D: 0, P: 0,
81 Id: &AST.Idents.get(Name: "element", TokenCode: tok::TokenKind::identifier), Typename: false, ParameterPack: false);
82 TypeParam->setDefaultArgument(
83 C: AST, DefArg: SemaPtr->getTrivialTemplateArgumentLoc(
84 Arg: TemplateArgument(AST.FloatTy), NTTPType: QualType(), Loc: SourceLocation()));
85
86 TemplateParams.emplace_back(Args&: TypeParam);
87
88 auto *SizeParam = NonTypeTemplateParmDecl::Create(
89 C: AST, DC: HLSLNamespace, StartLoc: SourceLocation(), IdLoc: SourceLocation(), D: 0, P: 1,
90 Id: &AST.Idents.get(Name: "element_count", TokenCode: tok::TokenKind::identifier), T: AST.IntTy,
91 ParameterPack: false, TInfo: AST.getTrivialTypeSourceInfo(T: AST.IntTy));
92 llvm::APInt Val(AST.getIntWidth(T: AST.IntTy), 4);
93 TemplateArgument Default(AST, llvm::APSInt(std::move(Val)), AST.IntTy,
94 /*IsDefaulted=*/true);
95 SizeParam->setDefaultArgument(C: AST, DefArg: SemaPtr->getTrivialTemplateArgumentLoc(
96 Arg: Default, NTTPType: AST.IntTy, Loc: SourceLocation()));
97 TemplateParams.emplace_back(Args&: SizeParam);
98
99 auto *ParamList =
100 TemplateParameterList::Create(C: AST, TemplateLoc: SourceLocation(), LAngleLoc: SourceLocation(),
101 Params: TemplateParams, RAngleLoc: SourceLocation(), RequiresClause: nullptr);
102
103 IdentifierInfo &II = AST.Idents.get(Name: "vector", TokenCode: tok::TokenKind::identifier);
104
105 QualType AliasType = AST.getDependentSizedExtVectorType(
106 VectorType: AST.getTemplateTypeParmType(Depth: 0, Index: 0, ParameterPack: false, ParmDecl: TypeParam),
107 SizeExpr: DeclRefExpr::Create(
108 Context: AST, QualifierLoc: NestedNameSpecifierLoc(), TemplateKWLoc: SourceLocation(), D: SizeParam, RefersToEnclosingVariableOrCapture: false,
109 NameInfo: DeclarationNameInfo(SizeParam->getDeclName(), SourceLocation()),
110 T: AST.IntTy, VK: VK_LValue),
111 AttrLoc: SourceLocation());
112
113 auto *Record = TypeAliasDecl::Create(C&: AST, DC: HLSLNamespace, StartLoc: SourceLocation(),
114 IdLoc: SourceLocation(), Id: &II,
115 TInfo: AST.getTrivialTypeSourceInfo(T: AliasType));
116 Record->setImplicit(true);
117
118 auto *Template =
119 TypeAliasTemplateDecl::Create(C&: AST, DC: HLSLNamespace, L: SourceLocation(),
120 Name: Record->getIdentifier(), Params: ParamList, Decl: Record);
121
122 Record->setDescribedAliasTemplate(Template);
123 Template->setImplicit(true);
124 Template->setLexicalDeclContext(Record->getDeclContext());
125 HLSLNamespace->addDecl(D: Template);
126}
127
128void HLSLExternalSemaSource::defineHLSLMatrixAlias() {
129 ASTContext &AST = SemaPtr->getASTContext();
130 llvm::SmallVector<NamedDecl *> TemplateParams;
131
132 auto *TypeParam = TemplateTypeParmDecl::Create(
133 C: AST, DC: HLSLNamespace, KeyLoc: SourceLocation(), NameLoc: SourceLocation(), D: 0, P: 0,
134 Id: &AST.Idents.get(Name: "element", TokenCode: tok::TokenKind::identifier), Typename: false, ParameterPack: false);
135 TypeParam->setDefaultArgument(
136 C: AST, DefArg: SemaPtr->getTrivialTemplateArgumentLoc(
137 Arg: TemplateArgument(AST.FloatTy), NTTPType: QualType(), Loc: SourceLocation()));
138
139 TemplateParams.emplace_back(Args&: TypeParam);
140
141 // these should be 64 bit to be consistent with other clang matrices.
142 auto *RowsParam = NonTypeTemplateParmDecl::Create(
143 C: AST, DC: HLSLNamespace, StartLoc: SourceLocation(), IdLoc: SourceLocation(), D: 0, P: 1,
144 Id: &AST.Idents.get(Name: "rows_count", TokenCode: tok::TokenKind::identifier), T: AST.IntTy,
145 ParameterPack: false, TInfo: AST.getTrivialTypeSourceInfo(T: AST.IntTy));
146 llvm::APInt RVal(AST.getIntWidth(T: AST.IntTy), 4);
147 TemplateArgument RDefault(AST, llvm::APSInt(std::move(RVal)), AST.IntTy,
148 /*IsDefaulted=*/true);
149 RowsParam->setDefaultArgument(
150 C: AST, DefArg: SemaPtr->getTrivialTemplateArgumentLoc(Arg: RDefault, NTTPType: AST.IntTy,
151 Loc: SourceLocation()));
152 TemplateParams.emplace_back(Args&: RowsParam);
153
154 auto *ColsParam = NonTypeTemplateParmDecl::Create(
155 C: AST, DC: HLSLNamespace, StartLoc: SourceLocation(), IdLoc: SourceLocation(), D: 0, P: 2,
156 Id: &AST.Idents.get(Name: "cols_count", TokenCode: tok::TokenKind::identifier), T: AST.IntTy,
157 ParameterPack: false, TInfo: AST.getTrivialTypeSourceInfo(T: AST.IntTy));
158 llvm::APInt CVal(AST.getIntWidth(T: AST.IntTy), 4);
159 TemplateArgument CDefault(AST, llvm::APSInt(std::move(CVal)), AST.IntTy,
160 /*IsDefaulted=*/true);
161 ColsParam->setDefaultArgument(
162 C: AST, DefArg: SemaPtr->getTrivialTemplateArgumentLoc(Arg: CDefault, NTTPType: AST.IntTy,
163 Loc: SourceLocation()));
164 TemplateParams.emplace_back(Args&: ColsParam);
165
166 const unsigned MaxMatDim = SemaPtr->getLangOpts().MaxMatrixDimension;
167
168 auto *MaxRow = IntegerLiteral::Create(
169 C: AST, V: llvm::APInt(AST.getIntWidth(T: AST.IntTy), MaxMatDim), type: AST.IntTy,
170 l: SourceLocation());
171 auto *MaxCol = IntegerLiteral::Create(
172 C: AST, V: llvm::APInt(AST.getIntWidth(T: AST.IntTy), MaxMatDim), type: AST.IntTy,
173 l: SourceLocation());
174
175 auto *RowsRef = DeclRefExpr::Create(
176 Context: AST, QualifierLoc: NestedNameSpecifierLoc(), TemplateKWLoc: SourceLocation(), D: RowsParam,
177 /*RefersToEnclosingVariableOrCapture*/ false,
178 NameInfo: DeclarationNameInfo(RowsParam->getDeclName(), SourceLocation()),
179 T: AST.IntTy, VK: VK_LValue);
180 auto *ColsRef = DeclRefExpr::Create(
181 Context: AST, QualifierLoc: NestedNameSpecifierLoc(), TemplateKWLoc: SourceLocation(), D: ColsParam,
182 /*RefersToEnclosingVariableOrCapture*/ false,
183 NameInfo: DeclarationNameInfo(ColsParam->getDeclName(), SourceLocation()),
184 T: AST.IntTy, VK: VK_LValue);
185
186 auto *RowsLE = BinaryOperator::Create(C: AST, lhs: RowsRef, rhs: MaxRow, opc: BO_LE, ResTy: AST.BoolTy,
187 VK: VK_PRValue, OK: OK_Ordinary,
188 opLoc: SourceLocation(), FPFeatures: FPOptionsOverride());
189 auto *ColsLE = BinaryOperator::Create(C: AST, lhs: ColsRef, rhs: MaxCol, opc: BO_LE, ResTy: AST.BoolTy,
190 VK: VK_PRValue, OK: OK_Ordinary,
191 opLoc: SourceLocation(), FPFeatures: FPOptionsOverride());
192
193 auto *RequiresExpr = BinaryOperator::Create(
194 C: AST, lhs: RowsLE, rhs: ColsLE, opc: BO_LAnd, ResTy: AST.BoolTy, VK: VK_PRValue, OK: OK_Ordinary,
195 opLoc: SourceLocation(), FPFeatures: FPOptionsOverride());
196
197 auto *ParamList = TemplateParameterList::Create(
198 C: AST, TemplateLoc: SourceLocation(), LAngleLoc: SourceLocation(), Params: TemplateParams, RAngleLoc: SourceLocation(),
199 RequiresClause: RequiresExpr);
200
201 IdentifierInfo &II = AST.Idents.get(Name: "matrix", TokenCode: tok::TokenKind::identifier);
202
203 QualType AliasType = AST.getDependentSizedMatrixType(
204 ElementType: AST.getTemplateTypeParmType(Depth: 0, Index: 0, ParameterPack: false, ParmDecl: TypeParam),
205 RowExpr: DeclRefExpr::Create(
206 Context: AST, QualifierLoc: NestedNameSpecifierLoc(), TemplateKWLoc: SourceLocation(), D: RowsParam, RefersToEnclosingVariableOrCapture: false,
207 NameInfo: DeclarationNameInfo(RowsParam->getDeclName(), SourceLocation()),
208 T: AST.IntTy, VK: VK_LValue),
209 ColumnExpr: DeclRefExpr::Create(
210 Context: AST, QualifierLoc: NestedNameSpecifierLoc(), TemplateKWLoc: SourceLocation(), D: ColsParam, RefersToEnclosingVariableOrCapture: false,
211 NameInfo: DeclarationNameInfo(ColsParam->getDeclName(), SourceLocation()),
212 T: AST.IntTy, VK: VK_LValue),
213 AttrLoc: SourceLocation());
214
215 auto *Record = TypeAliasDecl::Create(C&: AST, DC: HLSLNamespace, StartLoc: SourceLocation(),
216 IdLoc: SourceLocation(), Id: &II,
217 TInfo: AST.getTrivialTypeSourceInfo(T: AliasType));
218 Record->setImplicit(true);
219
220 auto *Template =
221 TypeAliasTemplateDecl::Create(C&: AST, DC: HLSLNamespace, L: SourceLocation(),
222 Name: Record->getIdentifier(), Params: ParamList, Decl: Record);
223
224 Record->setDescribedAliasTemplate(Template);
225 Template->setImplicit(true);
226 Template->setLexicalDeclContext(Record->getDeclContext());
227 HLSLNamespace->addDecl(D: Template);
228}
229
230void HLSLExternalSemaSource::defineTrivialHLSLTypes() {
231 defineHLSLVectorAlias();
232 defineHLSLMatrixAlias();
233}
234
235/// Set up common members and attributes for buffer types
236static BuiltinTypeDeclBuilder setupBufferType(CXXRecordDecl *Decl, Sema &S,
237 ResourceClass RC, bool IsROV,
238 bool RawBuffer, bool HasCounter) {
239 return BuiltinTypeDeclBuilder(S, Decl)
240 .addBufferHandles(RC, IsROV, RawBuffer, HasCounter)
241 .addDefaultHandleConstructor()
242 .addCopyConstructor()
243 .addCopyAssignmentOperator()
244 .addStaticInitializationFunctions(HasCounter);
245}
246
247/// Set up common members and attributes for sampler types
248static BuiltinTypeDeclBuilder setupSamplerType(CXXRecordDecl *Decl, Sema &S) {
249 return BuiltinTypeDeclBuilder(S, Decl)
250 .addSamplerHandle()
251 .addDefaultHandleConstructor()
252 .addCopyConstructor()
253 .addCopyAssignmentOperator()
254 .addStaticInitializationFunctions(HasCounter: false);
255}
256
257/// Set up common members and attributes for texture types
258static BuiltinTypeDeclBuilder setupTextureType(CXXRecordDecl *Decl, Sema &S,
259 ResourceClass RC, bool IsROV,
260 bool IsArray,
261 ResourceDimension Dim) {
262 return BuiltinTypeDeclBuilder(S, Decl)
263 .addTextureHandle(RC, IsROV, IsArray, RD: Dim)
264 .addTextureLoadMethods(Dim, IsArray)
265 .addArraySubscriptOperators(Dim, IsArray)
266 .addMipsMember(Dim)
267 .addDefaultHandleConstructor()
268 .addCopyConstructor()
269 .addCopyAssignmentOperator()
270 .addStaticInitializationFunctions(HasCounter: false)
271 .addSampleMethods(Dim, IsArray)
272 .addSampleBiasMethods(Dim, IsArray)
273 .addSampleGradMethods(Dim, IsArray)
274 .addSampleLevelMethods(Dim, IsArray)
275 .addSampleCmpMethods(Dim, IsArray)
276 .addSampleCmpLevelZeroMethods(Dim, IsArray)
277 .addCalculateLodMethods(Dim)
278 .addGetDimensionsMethods(Dim)
279 .addGatherMethods(Dim, IsArray)
280 .addGatherCmpMethods(Dim, IsArray);
281}
282
283/// Set up RWTexture type: UAV texture with only operator[] (uint2, read/write),
284/// Load and GetDimensions (no sample/gather/mips/LOD).
285static BuiltinTypeDeclBuilder setupRWTextureType(CXXRecordDecl *Decl, Sema &S,
286 bool IsArray,
287 ResourceDimension Dim) {
288 return BuiltinTypeDeclBuilder(S, Decl)
289 .addTextureHandle(RC: ResourceClass::UAV, /*IsROV=*/false, IsArray, RD: Dim)
290 .addTextureLoadMethods(Dim, IsArray)
291 .addArraySubscriptOperators(Dim, IsArray)
292 .addGetDimensionsMethods(Dim)
293 .addDefaultHandleConstructor()
294 .addCopyConstructor()
295 .addCopyAssignmentOperator()
296 .addStaticInitializationFunctions(HasCounter: false);
297}
298
299/// Set up Texture2DMS (multisampled) type: SRV texture with only operator[]
300/// and sample-indexed Load. It does not support sampling, gather, LOD, or mips.
301static BuiltinTypeDeclBuilder setupMSTextureType(CXXRecordDecl *Decl, Sema &S,
302 bool IsArray,
303 ResourceDimension Dim) {
304 ClassTemplateDecl *CTD = Decl->getDescribedClassTemplate();
305 assert(CTD && "multisampled texture must be a class template");
306
307 // Parameter 1 is the N in Texture2DMS<T, N>.
308 auto *NTTP =
309 cast<NonTypeTemplateParmDecl>(Val: CTD->getTemplateParameters()->getParam(Idx: 1));
310 Expr *SampleCountExpr =
311 S.BuildDeclRefExpr(D: NTTP, Ty: NTTP->getType(), VK: VK_PRValue, Loc: SourceLocation());
312
313 return BuiltinTypeDeclBuilder(S, Decl)
314 .addTextureHandle(RC: ResourceClass::SRV, /*IsROV=*/false, IsArray, RD: Dim,
315 SampleCountExpr)
316 .addTextureLoadMSMethods(Dim, IsArray)
317 .addArraySubscriptOperators(Dim, IsArray)
318 // TODO: Add MS-specific GetDimensions (with a NumberOfSamples output);
319 // the generic addGetDimensionsMethods is mip-based and unsuitable here.
320 // https://github.com/llvm/wg-hlsl/issues/347
321 .addDefaultHandleConstructor()
322 .addCopyConstructor()
323 .addCopyAssignmentOperator()
324 .addStaticInitializationFunctions(HasCounter: false);
325}
326
327// Add a partial specialization for a template. The `TextureTemplate` is
328// `Texture<element_type>`, and it will be specialized for vectors:
329// `Texture<vector<element_type, element_count>>`.
330static ClassTemplatePartialSpecializationDecl *
331addVectorTexturePartialSpecialization(Sema &S, NamespaceDecl *HLSLNamespace,
332 ClassTemplateDecl *TextureTemplate) {
333 ASTContext &AST = S.getASTContext();
334
335 // Create the template parameters: element_type and element_count.
336 auto *ElementType = TemplateTypeParmDecl::Create(
337 C: AST, DC: HLSLNamespace, KeyLoc: SourceLocation(), NameLoc: SourceLocation(), D: 0, P: 0,
338 Id: &AST.Idents.get(Name: "element_type"), Typename: false, ParameterPack: false);
339 auto *ElementCount = NonTypeTemplateParmDecl::Create(
340 C: AST, DC: HLSLNamespace, StartLoc: SourceLocation(), IdLoc: SourceLocation(), D: 0, P: 1,
341 Id: &AST.Idents.get(Name: "element_count"), T: AST.IntTy, ParameterPack: false,
342 TInfo: AST.getTrivialTypeSourceInfo(T: AST.IntTy));
343
344 auto *TemplateParams = TemplateParameterList::Create(
345 C: AST, TemplateLoc: SourceLocation(), LAngleLoc: SourceLocation(), Params: {ElementType, ElementCount},
346 RAngleLoc: SourceLocation(), RequiresClause: nullptr);
347
348 // Create the dependent vector type: vector<element_type, element_count>.
349 QualType VectorType = AST.getDependentSizedExtVectorType(
350 VectorType: AST.getTemplateTypeParmType(Depth: 0, Index: 0, ParameterPack: false, ParmDecl: ElementType),
351 SizeExpr: DeclRefExpr::Create(
352 Context: AST, QualifierLoc: NestedNameSpecifierLoc(), TemplateKWLoc: SourceLocation(), D: ElementCount, RefersToEnclosingVariableOrCapture: false,
353 NameInfo: DeclarationNameInfo(ElementCount->getDeclName(), SourceLocation()),
354 T: AST.IntTy, VK: VK_LValue),
355 AttrLoc: SourceLocation());
356
357 // Create the partial specialization declaration.
358 QualType CanonInjectedTST =
359 AST.getCanonicalType(T: AST.getTemplateSpecializationType(
360 Keyword: ElaboratedTypeKeyword::Class, T: TemplateName(TextureTemplate),
361 SpecifiedArgs: {TemplateArgument(VectorType)}, CanonicalArgs: {}));
362
363 auto *PartialSpec = ClassTemplatePartialSpecializationDecl::Create(
364 Context&: AST, TK: TagDecl::TagKind::Class, DC: HLSLNamespace, StartLoc: SourceLocation(),
365 IdLoc: SourceLocation(), Params: TemplateParams, SpecializedTemplate: TextureTemplate,
366 Args: {TemplateArgument(VectorType)},
367 CanonInjectedTST: CanQualType::CreateUnsafe(Other: CanonInjectedTST), PrevDecl: nullptr);
368
369 // Set the template arguments as written.
370 TemplateArgument Arg(VectorType);
371 TemplateArgumentLoc ArgLoc =
372 S.getTrivialTemplateArgumentLoc(Arg, NTTPType: QualType(), Loc: SourceLocation());
373 TemplateArgumentListInfo ArgsInfo =
374 TemplateArgumentListInfo(SourceLocation(), SourceLocation());
375 ArgsInfo.addArgument(Loc: ArgLoc);
376 PartialSpec->setTemplateArgsAsWritten(
377 ASTTemplateArgumentListInfo::Create(C: AST, List: ArgsInfo));
378
379 PartialSpec->setImplicit(true);
380 PartialSpec->setLexicalDeclContext(HLSLNamespace);
381 PartialSpec->setHasExternalLexicalStorage();
382
383 // Add the partial specialization to the namespace and the class template.
384 HLSLNamespace->addDecl(D: PartialSpec);
385 TextureTemplate->AddPartialSpecialization(D: PartialSpec, InsertPos: nullptr);
386
387 return PartialSpec;
388}
389
390// This function is responsible for constructing the constraint expression for
391// this concept:
392// template<typename T> concept is_typed_resource_element_compatible =
393// __is_typed_resource_element_compatible<T>;
394static Expr *constructTypedBufferConstraintExpr(Sema &S, SourceLocation NameLoc,
395 TemplateTypeParmDecl *T) {
396 ASTContext &Context = S.getASTContext();
397
398 // Obtain the QualType for 'bool'
399 QualType BoolTy = Context.BoolTy;
400
401 // Create a QualType that points to this TemplateTypeParmDecl
402 QualType TType = Context.getTypeDeclType(Decl: T);
403
404 // Create a TypeSourceInfo for the template type parameter 'T'
405 TypeSourceInfo *TTypeSourceInfo =
406 Context.getTrivialTypeSourceInfo(T: TType, Loc: NameLoc);
407
408 TypeTraitExpr *TypedResExpr = TypeTraitExpr::Create(
409 C: Context, T: BoolTy, Loc: NameLoc, Kind: UTT_IsTypedResourceElementCompatible,
410 Args: {TTypeSourceInfo}, RParenLoc: NameLoc, Value: true);
411
412 return TypedResExpr;
413}
414
415// This function is responsible for constructing the constraint expression for
416// this concept:
417// template<typename T> concept is_constant_buffer_element_compatible =
418// std::is_class_v<T> && !__is_intangible(T);
419static Expr *constructConstantBufferConstraintExpr(Sema &S,
420 SourceLocation NameLoc,
421 TemplateTypeParmDecl *T) {
422 ASTContext &Context = S.getASTContext();
423
424 // Obtain the QualType for 'bool'
425 QualType BoolTy = Context.BoolTy;
426
427 // Create a QualType that points to this TemplateTypeParmDecl
428 QualType TType = Context.getTypeDeclType(Decl: T);
429
430 // Create a TypeSourceInfo for the template type parameter 'T'
431 TypeSourceInfo *TTypeSourceInfo =
432 Context.getTrivialTypeSourceInfo(T: TType, Loc: NameLoc);
433
434 TypeTraitExpr *ResExpr = TypeTraitExpr::Create(
435 C: Context, T: BoolTy, Loc: NameLoc, Kind: UTT_IsConstantBufferElementCompatible,
436 Args: {TTypeSourceInfo}, RParenLoc: NameLoc, Value: true);
437
438 return ResExpr;
439}
440
441// This function is responsible for constructing the constraint expression for
442// this concept:
443// template<typename T> concept is_structured_resource_element_compatible =
444// !__is_intangible<T> && sizeof(T) >= 1;
445static Expr *constructStructuredBufferConstraintExpr(Sema &S,
446 SourceLocation NameLoc,
447 TemplateTypeParmDecl *T) {
448 ASTContext &Context = S.getASTContext();
449
450 // Obtain the QualType for 'bool'
451 QualType BoolTy = Context.BoolTy;
452
453 // Create a QualType that points to this TemplateTypeParmDecl
454 QualType TType = Context.getTypeDeclType(Decl: T);
455
456 // Create a TypeSourceInfo for the template type parameter 'T'
457 TypeSourceInfo *TTypeSourceInfo =
458 Context.getTrivialTypeSourceInfo(T: TType, Loc: NameLoc);
459
460 TypeTraitExpr *IsIntangibleExpr =
461 TypeTraitExpr::Create(C: Context, T: BoolTy, Loc: NameLoc, Kind: UTT_IsIntangibleType,
462 Args: {TTypeSourceInfo}, RParenLoc: NameLoc, Value: true);
463
464 // negate IsIntangibleExpr
465 UnaryOperator *NotIntangibleExpr = UnaryOperator::Create(
466 C: Context, input: IsIntangibleExpr, opc: UO_LNot, type: BoolTy, VK: VK_LValue, OK: OK_Ordinary,
467 l: NameLoc, CanOverflow: false, FPFeatures: FPOptionsOverride());
468
469 // element types also may not be of 0 size
470 UnaryExprOrTypeTraitExpr *SizeOfExpr = new (Context) UnaryExprOrTypeTraitExpr(
471 UETT_SizeOf, TTypeSourceInfo, BoolTy, NameLoc, NameLoc);
472
473 // Create a BinaryOperator that checks if the size of the type is not equal to
474 // 1 Empty structs have a size of 1 in HLSL, so we need to check for that
475 IntegerLiteral *rhs = IntegerLiteral::Create(
476 C: Context, V: llvm::APInt(Context.getTypeSize(T: Context.getSizeType()), 1, true),
477 type: Context.getSizeType(), l: NameLoc);
478
479 BinaryOperator *SizeGEQOneExpr =
480 BinaryOperator::Create(C: Context, lhs: SizeOfExpr, rhs, opc: BO_GE, ResTy: BoolTy, VK: VK_LValue,
481 OK: OK_Ordinary, opLoc: NameLoc, FPFeatures: FPOptionsOverride());
482
483 // Combine the two constraints
484 BinaryOperator *CombinedExpr = BinaryOperator::Create(
485 C: Context, lhs: NotIntangibleExpr, rhs: SizeGEQOneExpr, opc: BO_LAnd, ResTy: BoolTy, VK: VK_LValue,
486 OK: OK_Ordinary, opLoc: NameLoc, FPFeatures: FPOptionsOverride());
487
488 return CombinedExpr;
489}
490
491enum class HLSLBufferType { Typed, Structured, Constant };
492
493static ConceptDecl *constructBufferConceptDecl(Sema &S, NamespaceDecl *NSD,
494 HLSLBufferType BT) {
495 ASTContext &Context = S.getASTContext();
496 DeclContext *DC = NSD->getDeclContext();
497 SourceLocation DeclLoc = SourceLocation();
498
499 IdentifierInfo &ElementTypeII = Context.Idents.get(Name: "element_type");
500 TemplateTypeParmDecl *T = TemplateTypeParmDecl::Create(
501 C: Context, DC: NSD->getDeclContext(), KeyLoc: DeclLoc, NameLoc: DeclLoc,
502 /*D=*/0,
503 /*P=*/0,
504 /*Id=*/&ElementTypeII,
505 /*Typename=*/true,
506 /*ParameterPack=*/false);
507
508 T->setDeclContext(DC);
509 T->setReferenced();
510
511 // Create and Attach Template Parameter List to ConceptDecl
512 TemplateParameterList *ConceptParams = TemplateParameterList::Create(
513 C: Context, TemplateLoc: DeclLoc, LAngleLoc: DeclLoc, Params: {T}, RAngleLoc: DeclLoc, RequiresClause: nullptr);
514
515 DeclarationName DeclName;
516 Expr *ConstraintExpr = nullptr;
517
518 switch (BT) {
519 case HLSLBufferType::Typed:
520 DeclName = DeclarationName(
521 &Context.Idents.get(Name: "__is_typed_resource_element_compatible"));
522 ConstraintExpr = constructTypedBufferConstraintExpr(S, NameLoc: DeclLoc, T);
523 break;
524 case HLSLBufferType::Structured:
525 DeclName = DeclarationName(
526 &Context.Idents.get(Name: "__is_structured_resource_element_compatible"));
527 ConstraintExpr = constructStructuredBufferConstraintExpr(S, NameLoc: DeclLoc, T);
528 break;
529 case HLSLBufferType::Constant:
530 DeclName = DeclarationName(
531 &Context.Idents.get(Name: "__is_constant_buffer_element_compatible"));
532 ConstraintExpr = constructConstantBufferConstraintExpr(S, NameLoc: DeclLoc, T);
533 break;
534 }
535
536 // Create a ConceptDecl
537 ConceptDecl *CD =
538 ConceptDecl::Create(C&: Context, DC: NSD->getDeclContext(), L: DeclLoc, Name: DeclName,
539 Params: ConceptParams, ConstraintExpr);
540
541 // Attach the template parameter list to the ConceptDecl
542 CD->setTemplateParameters(ConceptParams);
543
544 // Add the concept declaration to the Translation Unit Decl
545 NSD->getDeclContext()->addDecl(D: CD);
546
547 return CD;
548}
549
550void HLSLExternalSemaSource::defineHLSLTypesWithForwardDeclarations() {
551 ASTContext &AST = SemaPtr->getASTContext();
552 CXXRecordDecl *Decl;
553 ConceptDecl *TypedBufferConcept = constructBufferConceptDecl(
554 S&: *SemaPtr, NSD: HLSLNamespace, BT: HLSLBufferType::Typed);
555 ConceptDecl *StructuredBufferConcept = constructBufferConceptDecl(
556 S&: *SemaPtr, NSD: HLSLNamespace, BT: HLSLBufferType::Structured);
557 ConceptDecl *ConstantBufferConcept = constructBufferConceptDecl(
558 S&: *SemaPtr, NSD: HLSLNamespace, BT: HLSLBufferType::Constant);
559
560 Decl = BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "ConstantBuffer")
561 .addSimpleTemplateParams(Names: {"element_type"}, CD: ConstantBufferConcept)
562 .finalizeForwardDeclaration();
563
564 onCompletion(Record: Decl, Fn: [this](CXXRecordDecl *Decl) {
565 setupBufferType(Decl, S&: *SemaPtr, RC: ResourceClass::CBuffer, /*IsROV=*/false,
566 /*RawBuffer=*/false, /*HasCounter=*/false)
567 .addConstantBufferConversionToType()
568 .completeDefinition();
569 });
570
571 Decl = BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "Buffer")
572 .addSimpleTemplateParams(Names: {"element_type"}, CD: TypedBufferConcept)
573 .finalizeForwardDeclaration();
574
575 onCompletion(Record: Decl, Fn: [this](CXXRecordDecl *Decl) {
576 setupBufferType(Decl, S&: *SemaPtr, RC: ResourceClass::SRV, /*IsROV=*/false,
577 /*RawBuffer=*/false, /*HasCounter=*/false)
578 .addArraySubscriptOperators()
579 .addLoadMethods()
580 .addGetDimensionsMethodForBuffer()
581 .completeDefinition();
582 });
583
584 Decl = BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "RWBuffer")
585 .addSimpleTemplateParams(Names: {"element_type"}, CD: TypedBufferConcept)
586 .finalizeForwardDeclaration();
587
588 onCompletion(Record: Decl, Fn: [this](CXXRecordDecl *Decl) {
589 setupBufferType(Decl, S&: *SemaPtr, RC: ResourceClass::UAV, /*IsROV=*/false,
590 /*RawBuffer=*/false, /*HasCounter=*/false)
591 .addArraySubscriptOperators()
592 .addLoadMethods()
593 .addGetDimensionsMethodForBuffer()
594 .completeDefinition();
595 });
596
597 Decl =
598 BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "RasterizerOrderedBuffer")
599 .addSimpleTemplateParams(Names: {"element_type"}, CD: StructuredBufferConcept)
600 .finalizeForwardDeclaration();
601 onCompletion(Record: Decl, Fn: [this](CXXRecordDecl *Decl) {
602 setupBufferType(Decl, S&: *SemaPtr, RC: ResourceClass::UAV, /*IsROV=*/true,
603 /*RawBuffer=*/false, /*HasCounter=*/false)
604 .addArraySubscriptOperators()
605 .addLoadMethods()
606 .addGetDimensionsMethodForBuffer()
607 .completeDefinition();
608 });
609
610 Decl = BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "StructuredBuffer")
611 .addSimpleTemplateParams(Names: {"element_type"}, CD: StructuredBufferConcept)
612 .finalizeForwardDeclaration();
613 onCompletion(Record: Decl, Fn: [this](CXXRecordDecl *Decl) {
614 setupBufferType(Decl, S&: *SemaPtr, RC: ResourceClass::SRV, /*IsROV=*/false,
615 /*RawBuffer=*/true, /*HasCounter=*/false)
616 .addArraySubscriptOperators()
617 .addLoadMethods()
618 .addGetDimensionsMethodForBuffer()
619 .completeDefinition();
620 });
621
622 Decl = BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "RWStructuredBuffer")
623 .addSimpleTemplateParams(Names: {"element_type"}, CD: StructuredBufferConcept)
624 .finalizeForwardDeclaration();
625 onCompletion(Record: Decl, Fn: [this](CXXRecordDecl *Decl) {
626 setupBufferType(Decl, S&: *SemaPtr, RC: ResourceClass::UAV, /*IsROV=*/false,
627 /*RawBuffer=*/true, /*HasCounter=*/true)
628 .addArraySubscriptOperators()
629 .addLoadMethods()
630 .addIncrementCounterMethod()
631 .addDecrementCounterMethod()
632 .addGetDimensionsMethodForBuffer()
633 .completeDefinition();
634 });
635
636 Decl =
637 BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "AppendStructuredBuffer")
638 .addSimpleTemplateParams(Names: {"element_type"}, CD: StructuredBufferConcept)
639 .finalizeForwardDeclaration();
640 onCompletion(Record: Decl, Fn: [this](CXXRecordDecl *Decl) {
641 setupBufferType(Decl, S&: *SemaPtr, RC: ResourceClass::UAV, /*IsROV=*/false,
642 /*RawBuffer=*/true, /*HasCounter=*/true)
643 .addAppendMethod()
644 .addGetDimensionsMethodForBuffer()
645 .completeDefinition();
646 });
647
648 Decl =
649 BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "ConsumeStructuredBuffer")
650 .addSimpleTemplateParams(Names: {"element_type"}, CD: StructuredBufferConcept)
651 .finalizeForwardDeclaration();
652 onCompletion(Record: Decl, Fn: [this](CXXRecordDecl *Decl) {
653 setupBufferType(Decl, S&: *SemaPtr, RC: ResourceClass::UAV, /*IsROV=*/false,
654 /*RawBuffer=*/true, /*HasCounter=*/true)
655 .addConsumeMethod()
656 .addGetDimensionsMethodForBuffer()
657 .completeDefinition();
658 });
659
660 Decl = BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace,
661 "RasterizerOrderedStructuredBuffer")
662 .addSimpleTemplateParams(Names: {"element_type"}, CD: StructuredBufferConcept)
663 .finalizeForwardDeclaration();
664 onCompletion(Record: Decl, Fn: [this](CXXRecordDecl *Decl) {
665 setupBufferType(Decl, S&: *SemaPtr, RC: ResourceClass::UAV, /*IsROV=*/true,
666 /*RawBuffer=*/true, /*HasCounter=*/true)
667 .addArraySubscriptOperators()
668 .addLoadMethods()
669 .addIncrementCounterMethod()
670 .addDecrementCounterMethod()
671 .addGetDimensionsMethodForBuffer()
672 .completeDefinition();
673 });
674
675 Decl = BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "ByteAddressBuffer")
676 .finalizeForwardDeclaration();
677 onCompletion(Record: Decl, Fn: [this](CXXRecordDecl *Decl) {
678 setupBufferType(Decl, S&: *SemaPtr, RC: ResourceClass::SRV, /*IsROV=*/false,
679 /*RawBuffer=*/true, /*HasCounter=*/false)
680 .addByteAddressBufferLoadMethods()
681 .addGetDimensionsMethodForBuffer()
682 .completeDefinition();
683 });
684 Decl = BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "RWByteAddressBuffer")
685 .finalizeForwardDeclaration();
686 onCompletion(Record: Decl, Fn: [this](CXXRecordDecl *Decl) {
687 setupBufferType(Decl, S&: *SemaPtr, RC: ResourceClass::UAV, /*IsROV=*/false,
688 /*RawBuffer=*/true, /*HasCounter=*/false)
689 .addByteAddressBufferLoadMethods()
690 .addByteAddressBufferStoreMethods()
691 .addByteAddressBufferInterlockedMethods()
692 .addGetDimensionsMethodForBuffer()
693 .completeDefinition();
694 });
695 Decl = BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace,
696 "RasterizerOrderedByteAddressBuffer")
697 .finalizeForwardDeclaration();
698 onCompletion(Record: Decl, Fn: [this](CXXRecordDecl *Decl) {
699 setupBufferType(Decl, S&: *SemaPtr, RC: ResourceClass::UAV, /*IsROV=*/true,
700 /*RawBuffer=*/true, /*HasCounter=*/false)
701 .addByteAddressBufferInterlockedMethods()
702 .addGetDimensionsMethodForBuffer()
703 .completeDefinition();
704 });
705
706 Decl = BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "SamplerState")
707 .finalizeForwardDeclaration();
708 onCompletion(Record: Decl, Fn: [this](CXXRecordDecl *Decl) {
709 setupSamplerType(Decl, S&: *SemaPtr).completeDefinition();
710 });
711
712 Decl =
713 BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "SamplerComparisonState")
714 .finalizeForwardDeclaration();
715 onCompletion(Record: Decl, Fn: [this](CXXRecordDecl *Decl) {
716 setupSamplerType(Decl, S&: *SemaPtr).completeDefinition();
717 });
718
719 QualType Float4Ty = AST.getExtVectorType(VectorType: AST.FloatTy, NumElts: 4);
720 Decl = BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "Texture2D")
721 .addSimpleTemplateParams(Names: {"element_type"}, DefaultTypes: {Float4Ty},
722 CD: TypedBufferConcept)
723 .finalizeForwardDeclaration();
724
725 onCompletion(Record: Decl, Fn: [this](CXXRecordDecl *Decl) {
726 setupTextureType(Decl, S&: *SemaPtr, RC: ResourceClass::SRV, /*IsROV=*/false,
727 /*IsArray=*/false, Dim: ResourceDimension::Dim2D)
728 .completeDefinition();
729 });
730
731 auto *PartialSpec = addVectorTexturePartialSpecialization(
732 S&: *SemaPtr, HLSLNamespace, TextureTemplate: Decl->getDescribedClassTemplate());
733 onCompletion(Record: PartialSpec, Fn: [this](CXXRecordDecl *Decl) {
734 setupTextureType(Decl, S&: *SemaPtr, RC: ResourceClass::SRV, /*IsROV=*/false,
735 /*IsArray=*/false, Dim: ResourceDimension::Dim2D)
736 .completeDefinition();
737 });
738
739 Decl = BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "RWTexture2D")
740 .addSimpleTemplateParams(Names: {"element_type"}, DefaultTypes: {Float4Ty},
741 CD: TypedBufferConcept)
742 .finalizeForwardDeclaration();
743
744 onCompletion(Record: Decl, Fn: [this](CXXRecordDecl *Decl) {
745 setupRWTextureType(Decl, S&: *SemaPtr, /*IsArray=*/false,
746 Dim: ResourceDimension::Dim2D)
747 .completeDefinition();
748 });
749
750 auto *PartialSpecRW = addVectorTexturePartialSpecialization(
751 S&: *SemaPtr, HLSLNamespace, TextureTemplate: Decl->getDescribedClassTemplate());
752 onCompletion(Record: PartialSpecRW, Fn: [this](CXXRecordDecl *Decl) {
753 setupRWTextureType(Decl, S&: *SemaPtr, /*IsArray=*/false,
754 Dim: ResourceDimension::Dim2D)
755 .completeDefinition();
756 });
757
758 // Texture2DArray — same as Texture2D but IsArray=true
759 Decl = BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "Texture2DArray")
760 .addSimpleTemplateParams(Names: {"element_type"}, DefaultTypes: {Float4Ty},
761 CD: TypedBufferConcept)
762 .finalizeForwardDeclaration();
763
764 onCompletion(Record: Decl, Fn: [this](CXXRecordDecl *Decl) {
765 setupTextureType(Decl, S&: *SemaPtr, RC: ResourceClass::SRV, /*IsROV=*/false,
766 /*IsArray=*/true, Dim: ResourceDimension::Dim2D)
767 .completeDefinition();
768 });
769
770 auto *PartialSpec2DA = addVectorTexturePartialSpecialization(
771 S&: *SemaPtr, HLSLNamespace, TextureTemplate: Decl->getDescribedClassTemplate());
772 onCompletion(Record: PartialSpec2DA, Fn: [this](CXXRecordDecl *Decl) {
773 setupTextureType(Decl, S&: *SemaPtr, RC: ResourceClass::SRV, /*IsROV=*/false,
774 /*IsArray=*/true, Dim: ResourceDimension::Dim2D)
775 .completeDefinition();
776 });
777
778 // RWTexture2DArray — same as RWTexture2D but IsArray=true
779 Decl = BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "RWTexture2DArray")
780 .addSimpleTemplateParams(Names: {"element_type"}, DefaultTypes: {Float4Ty},
781 CD: TypedBufferConcept)
782 .finalizeForwardDeclaration();
783
784 onCompletion(Record: Decl, Fn: [this](CXXRecordDecl *Decl) {
785 setupRWTextureType(Decl, S&: *SemaPtr, /*IsArray=*/true,
786 Dim: ResourceDimension::Dim2D)
787 .completeDefinition();
788 });
789
790 auto *PartialSpecRW2DA = addVectorTexturePartialSpecialization(
791 S&: *SemaPtr, HLSLNamespace, TextureTemplate: Decl->getDescribedClassTemplate());
792 onCompletion(Record: PartialSpecRW2DA, Fn: [this](CXXRecordDecl *Decl) {
793 setupRWTextureType(Decl, S&: *SemaPtr, /*IsArray=*/true,
794 Dim: ResourceDimension::Dim2D)
795 .completeDefinition();
796 });
797
798 // Texture2DMS — like Texture2D but multisampled, and the element type has no
799 // default argument.
800 Decl = BuiltinTypeDeclBuilder(*SemaPtr, HLSLNamespace, "Texture2DMS")
801 .addMSTextureTemplateParams(ElementName: "element_type", SampleCountName: "sample_count",
802 CD: TypedBufferConcept)
803 .finalizeForwardDeclaration();
804
805 onCompletion(Record: Decl, Fn: [this](CXXRecordDecl *Decl) {
806 setupMSTextureType(Decl, S&: *SemaPtr, /*IsArray=*/false,
807 Dim: ResourceDimension::Dim2D)
808 .completeDefinition();
809 });
810}
811
812// Build a single overload of an HLSL atomic intrinsic in the hlsl namespace.
813// `dest` is an address-space-qualified reference; `original_value` (when
814// present) is a plain reference. The synthesized FunctionDecl aliases the
815// underlying clang builtin via BuiltinAliasAttr.
816static void buildAtomicOverload(Sema &S, NamespaceDecl *NS, StringRef FuncName,
817 StringRef BuiltinName, QualType ElemTy,
818 LangAS DestAS, bool ThreeArg) {
819 ASTContext &AST = S.getASTContext();
820
821 QualType DestTy =
822 AST.getLValueReferenceType(T: AST.getAddrSpaceQualType(T: ElemTy, AddressSpace: DestAS));
823 QualType OrigRefTy = AST.getLValueReferenceType(T: ElemTy);
824
825 SmallVector<QualType, 3> ParamTypes;
826 ParamTypes.push_back(Elt: DestTy);
827 ParamTypes.push_back(Elt: ElemTy);
828 if (ThreeArg)
829 ParamTypes.push_back(Elt: OrigRefTy);
830
831 FunctionProtoType::ExtProtoInfo EPI;
832 QualType FuncTy = AST.getFunctionType(ResultTy: AST.VoidTy, Args: ParamTypes, EPI);
833 auto *TSInfo = AST.getTrivialTypeSourceInfo(T: FuncTy, Loc: SourceLocation());
834
835 IdentifierInfo &FuncII = AST.Idents.get(Name: FuncName, TokenCode: tok::TokenKind::identifier);
836 DeclarationName FuncDeclName(&FuncII);
837
838 FunctionDecl *FD = FunctionDecl::Create(
839 C&: AST, DC: NS, StartLoc: SourceLocation(), NLoc: SourceLocation(), N: FuncDeclName, T: FuncTy, TInfo: TSInfo,
840 SC: SC_Extern, /*UsesFPIntrin=*/false, /*isInlineSpecified=*/false,
841 /*hasWrittenPrototype=*/true);
842
843 constexpr const char *ParamNames[] = {"dest", "value", "original_value"};
844 SmallVector<ParmVarDecl *, 3> ParmDecls;
845 unsigned I = 0;
846 for (auto [ParamType, ParamName] : llvm::zip(t&: ParamTypes, u: ParamNames)) {
847 IdentifierInfo &PII = AST.Idents.get(Name: ParamName, TokenCode: tok::TokenKind::identifier);
848 ParmVarDecl *Parm = ParmVarDecl::Create(
849 C&: AST, DC: FD, StartLoc: SourceLocation(), IdLoc: SourceLocation(), Id: &PII, T: ParamType,
850 TInfo: AST.getTrivialTypeSourceInfo(T: ParamType, Loc: SourceLocation()), S: SC_None,
851 DefArg: nullptr);
852 Parm->setScopeInfo(scopeDepth: 0, parameterIndex: I++);
853 ParmDecls.push_back(Elt: Parm);
854 }
855 FD->setParams(ParmDecls);
856
857 IdentifierInfo &BuiltinII =
858 S.getPreprocessor().getIdentifierTable().get(Name: BuiltinName);
859 FD->addAttr(A: BuiltinAliasAttr::CreateImplicit(Ctx&: AST, BuiltinName: &BuiltinII));
860 FD->setImplicit();
861 NS->addDecl(D: FD);
862}
863
864// Synthesize the InterlockedFunc overload set: {int, uint, int64_t, uint64_t}
865// x {groupshared, device} x {2-arg, 3-arg}.
866static void defineHLSLInterlockedFunc(Sema &S, NamespaceDecl *NS,
867 StringRef FuncName,
868 StringRef BuiltinName) {
869 ASTContext &AST = S.getASTContext();
870 // HLSL: int64_t == long, uint64_t == unsigned long (see hlsl_basic_types.h).
871 QualType Elems[] = {AST.IntTy, AST.UnsignedIntTy, AST.LongTy,
872 AST.UnsignedLongTy};
873 LangAS AddrSpaces[] = {LangAS::hlsl_groupshared, LangAS::hlsl_device};
874
875 for (QualType ElemTy : Elems)
876 for (LangAS AS : AddrSpaces)
877 for (bool ThreeArg : {false, true})
878 buildAtomicOverload(S, NS, FuncName, BuiltinName, ElemTy, DestAS: AS, ThreeArg);
879}
880
881void HLSLExternalSemaSource::defineHLSLAtomicIntrinsics() {
882 defineHLSLInterlockedFunc(S&: *SemaPtr, NS: HLSLNamespace, FuncName: "InterlockedAdd",
883 BuiltinName: "__builtin_hlsl_interlocked_add");
884 defineHLSLInterlockedFunc(S&: *SemaPtr, NS: HLSLNamespace, FuncName: "InterlockedMin",
885 BuiltinName: "__builtin_hlsl_interlocked_min");
886 defineHLSLInterlockedFunc(S&: *SemaPtr, NS: HLSLNamespace, FuncName: "InterlockedOr",
887 BuiltinName: "__builtin_hlsl_interlocked_or");
888 defineHLSLInterlockedFunc(S&: *SemaPtr, NS: HLSLNamespace, FuncName: "InterlockedXor",
889 BuiltinName: "__builtin_hlsl_interlocked_xor");
890}
891
892void HLSLExternalSemaSource::onCompletion(CXXRecordDecl *Record,
893 CompletionFunction Fn) {
894 if (!Record->isCompleteDefinition())
895 Completions.insert(KV: std::make_pair(x: Record->getCanonicalDecl(), y&: Fn));
896}
897
898void HLSLExternalSemaSource::CompleteType(TagDecl *Tag) {
899 if (!isa<CXXRecordDecl>(Val: Tag))
900 return;
901 auto *Record = cast<CXXRecordDecl>(Val: Tag);
902 Record = Record->getCanonicalDecl();
903 auto It = Completions.find(Val: Record);
904 if (It == Completions.end())
905 return;
906 // Move out the callback and erase before invoking it: the callback can
907 // re-enter CompleteType and mutate Completions, which invalidates It under
908 // backward-shift deletion.
909 CompletionFunction Fn = std::move(It->second);
910 Completions.erase(I: It);
911 Fn(Record);
912}
913