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