1//===--- HLSLBuiltinTypeDeclBuilder.cpp - HLSL Builtin Type Decl Builder --===//
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// Helper classes for creating HLSL builtin class types. Used by external HLSL
10// sema source.
11//
12//===----------------------------------------------------------------------===//
13
14#include "HLSLBuiltinTypeDeclBuilder.h"
15#include "clang/AST/ASTContext.h"
16#include "clang/AST/Attr.h"
17#include "clang/AST/Decl.h"
18#include "clang/AST/DeclCXX.h"
19#include "clang/AST/DeclTemplate.h"
20#include "clang/AST/Expr.h"
21#include "clang/AST/HLSLResource.h"
22#include "clang/AST/Stmt.h"
23#include "clang/AST/Type.h"
24#include "clang/Basic/SourceLocation.h"
25#include "clang/Basic/Specifiers.h"
26#include "clang/Sema/Lookup.h"
27#include "clang/Sema/Sema.h"
28#include "clang/Sema/SemaHLSL.h"
29#include "llvm/ADT/SmallVector.h"
30
31using namespace llvm::hlsl;
32
33namespace clang {
34
35namespace hlsl {
36
37namespace {
38
39static FunctionDecl *lookupBuiltinFunction(Sema &S, StringRef Name) {
40 IdentifierInfo &II =
41 S.getASTContext().Idents.get(Name, TokenCode: tok::TokenKind::identifier);
42 DeclarationNameInfo NameInfo =
43 DeclarationNameInfo(DeclarationName(&II), SourceLocation());
44 LookupResult R(S, NameInfo, Sema::LookupOrdinaryName);
45 // AllowBuiltinCreation is false but LookupDirect will create
46 // the builtin when searching the global scope anyways...
47 S.LookupName(R, S: S.getCurScope());
48 // FIXME: If the builtin function was user-declared in global scope,
49 // this assert *will* fail. Should this call LookupBuiltin instead?
50 assert(R.isSingleResult() &&
51 "Since this is a builtin it should always resolve!");
52 return cast<FunctionDecl>(Val: R.getFoundDecl());
53}
54
55static QualType lookupBuiltinType(Sema &S, StringRef Name, DeclContext *DC) {
56 IdentifierInfo &II =
57 S.getASTContext().Idents.get(Name, TokenCode: tok::TokenKind::identifier);
58 LookupResult Result(S, &II, SourceLocation(), Sema::LookupTagName);
59 S.LookupQualifiedName(R&: Result, LookupCtx: DC);
60 assert(!Result.empty() && "Builtin type not found");
61 QualType Ty =
62 S.getASTContext().getTypeDeclType(Decl: Result.getAsSingle<TypeDecl>());
63 S.RequireCompleteType(Loc: SourceLocation(), T: Ty,
64 DiagID: diag::err_tentative_def_incomplete_type);
65 return Ty;
66}
67
68CXXConstructorDecl *lookupCopyConstructor(QualType ResTy) {
69 assert(ResTy->isRecordType() && "not a CXXRecord type");
70 for (auto *CD : ResTy->getAsCXXRecordDecl()->ctors())
71 if (CD->isCopyConstructor())
72 return CD;
73 return nullptr;
74}
75
76ParameterABI
77convertParamModifierToParamABI(HLSLParamModifierAttr::Spelling Modifier) {
78 assert(Modifier != HLSLParamModifierAttr::Spelling::Keyword_in &&
79 "HLSL 'in' parameters modifier cannot be converted to ParameterABI");
80 switch (Modifier) {
81 case HLSLParamModifierAttr::Spelling::Keyword_out:
82 return ParameterABI::HLSLOut;
83 case HLSLParamModifierAttr::Spelling::Keyword_inout:
84 return ParameterABI::HLSLInOut;
85 default:
86 llvm_unreachable("Invalid HLSL parameter modifier");
87 }
88}
89
90QualType getInoutParameterType(ASTContext &AST, QualType Ty) {
91 assert(!Ty->isReferenceType() &&
92 "Pointer and reference types cannot be inout or out parameters");
93 Ty = AST.getLValueReferenceType(T: Ty);
94 Ty.addRestrict();
95 return Ty;
96}
97
98} // namespace
99
100// Builder for template arguments of builtin types. Used internally
101// by BuiltinTypeDeclBuilder.
102struct TemplateParameterListBuilder {
103 BuiltinTypeDeclBuilder &Builder;
104 llvm::SmallVector<NamedDecl *> Params;
105
106 TemplateParameterListBuilder(BuiltinTypeDeclBuilder &RB) : Builder(RB) {}
107 ~TemplateParameterListBuilder();
108
109 TemplateParameterListBuilder &
110 addTypeParameter(StringRef Name, QualType DefaultValue = QualType());
111
112 ConceptSpecializationExpr *
113 constructConceptSpecializationExpr(Sema &S, ConceptDecl *CD);
114
115 BuiltinTypeDeclBuilder &finalizeTemplateArgs(ConceptDecl *CD = nullptr);
116};
117
118// Builder for methods or constructors of builtin types. Allows creating methods
119// or constructors of builtin types using the builder pattern like this:
120//
121// BuiltinTypeMethodBuilder(RecordBuilder, "MethodName", ReturnType)
122// .addParam("param_name", Type, InOutModifier)
123// .callBuiltin("builtin_name", BuiltinParams...)
124// .finalize();
125//
126// The builder needs to have all of the parameters before it can create
127// a CXXMethodDecl or CXXConstructorDecl. It collects them in addParam calls and
128// when a first method that builds the body is called or when access to 'this`
129// is needed it creates the CXXMethodDecl/CXXConstructorDecl and ParmVarDecls
130// instances. These can then be referenced from the body building methods.
131// Destructor or an explicit call to finalize() will complete the method
132// definition.
133//
134// The callBuiltin helper method accepts constants via `Expr *` or placeholder
135// value arguments to indicate which function arguments to forward to the
136// builtin.
137//
138// If the method that is being built has a non-void return type the
139// finalize() will create a return statement with the value of the last
140// statement (unless the last statement is already a ReturnStmt or the return
141// value is void).
142struct BuiltinTypeMethodBuilder {
143private:
144 struct Param {
145 const IdentifierInfo &NameII;
146 QualType Ty;
147 HLSLParamModifierAttr::Spelling Modifier;
148 Param(const IdentifierInfo &NameII, QualType Ty,
149 HLSLParamModifierAttr::Spelling Modifier)
150 : NameII(NameII), Ty(Ty), Modifier(Modifier) {}
151 };
152
153 struct LocalVar {
154 StringRef Name;
155 QualType Ty;
156 VarDecl *Decl;
157 LocalVar(StringRef Name, QualType Ty) : Name(Name), Ty(Ty), Decl(nullptr) {}
158 };
159
160 BuiltinTypeDeclBuilder &DeclBuilder;
161 DeclarationName Name;
162 QualType ReturnTy;
163 // method or constructor declaration
164 // (CXXConstructorDecl derives from CXXMethodDecl)
165 CXXMethodDecl *Method;
166 bool IsConst;
167 bool IsCtor;
168 StorageClass SC;
169 llvm::SmallVector<Param> Params;
170 llvm::SmallVector<Stmt *> StmtsList;
171 TemplateParameterList *TemplateParams = nullptr;
172 llvm::SmallVector<NamedDecl *> TemplateParamDecls;
173
174 // Argument placeholders, inspired by std::placeholder. These are the indices
175 // of arguments to forward to `callBuiltin` and other method builder methods.
176 // Additional special values are:
177 // Handle - refers to the resource handle.
178 // LastStmt - refers to the last statement in the method body; referencing
179 // LastStmt will remove the statement from the method body since
180 // it will be linked from the new expression being constructed.
181 enum class PlaceHolder {
182 _0,
183 _1,
184 _2,
185 _3,
186 _4,
187 _5,
188 Handle = 128,
189 CounterHandle,
190 LastStmt
191 };
192
193 Expr *convertPlaceholder(PlaceHolder PH);
194 Expr *convertPlaceholder(LocalVar &Var);
195 Expr *convertPlaceholder(Expr *E) { return E; }
196 // Converts a QualType to an Expr that carries type information to builtins.
197 Expr *convertPlaceholder(QualType Ty);
198
199public:
200 friend BuiltinTypeDeclBuilder;
201
202 BuiltinTypeMethodBuilder(BuiltinTypeDeclBuilder &DB, DeclarationName &Name,
203 QualType ReturnTy, bool IsConst = false,
204 bool IsCtor = false, StorageClass SC = SC_None)
205 : DeclBuilder(DB), Name(Name), ReturnTy(ReturnTy), Method(nullptr),
206 IsConst(IsConst), IsCtor(IsCtor), SC(SC) {}
207
208 BuiltinTypeMethodBuilder(BuiltinTypeDeclBuilder &DB, StringRef NameStr,
209 QualType ReturnTy, bool IsConst = false,
210 bool IsCtor = false, StorageClass SC = SC_None);
211 BuiltinTypeMethodBuilder(const BuiltinTypeMethodBuilder &Other) = delete;
212
213 ~BuiltinTypeMethodBuilder() { finalize(); }
214
215 BuiltinTypeMethodBuilder &
216 operator=(const BuiltinTypeMethodBuilder &Other) = delete;
217
218 BuiltinTypeMethodBuilder &addParam(StringRef Name, QualType Ty,
219 HLSLParamModifierAttr::Spelling Modifier =
220 HLSLParamModifierAttr::Keyword_in);
221 QualType addTemplateTypeParam(StringRef Name);
222 BuiltinTypeMethodBuilder &declareLocalVar(LocalVar &Var);
223 template <typename... Ts>
224 BuiltinTypeMethodBuilder &callBuiltin(StringRef BuiltinName,
225 QualType ReturnType, Ts &&...ArgSpecs);
226 template <typename TLHS, typename TRHS>
227 BuiltinTypeMethodBuilder &assign(TLHS LHS, TRHS RHS);
228 template <typename T> BuiltinTypeMethodBuilder &dereference(T Ptr);
229
230 template <typename T>
231 BuiltinTypeMethodBuilder &accessHandleFieldOnResource(T ResourceRecord);
232 template <typename ResourceT, typename ValueT>
233 BuiltinTypeMethodBuilder &setHandleFieldOnResource(ResourceT ResourceRecord,
234 ValueT HandleValue);
235 template <typename T>
236 BuiltinTypeMethodBuilder &
237 accessCounterHandleFieldOnResource(T ResourceRecord);
238 template <typename ResourceT, typename ValueT>
239 BuiltinTypeMethodBuilder &
240 setCounterHandleFieldOnResource(ResourceT ResourceRecord, ValueT HandleValue);
241 template <typename T> BuiltinTypeMethodBuilder &returnValue(T ReturnValue);
242 BuiltinTypeMethodBuilder &returnThis();
243 BuiltinTypeDeclBuilder &finalize();
244 Expr *getResourceHandleExpr();
245 Expr *getResourceCounterHandleExpr();
246
247private:
248 void createDecl();
249
250 // Makes sure the declaration is created; should be called before any
251 // statement added to the body or when access to 'this' is needed.
252 void ensureCompleteDecl() {
253 if (!Method)
254 createDecl();
255 }
256
257 template <typename ResourceT, typename ValueT>
258 BuiltinTypeMethodBuilder &setFieldOnResource(ResourceT ResourceRecord,
259 ValueT HandleValue,
260 FieldDecl *HandleField);
261};
262
263TemplateParameterListBuilder::~TemplateParameterListBuilder() {
264 finalizeTemplateArgs();
265}
266
267TemplateParameterListBuilder &
268TemplateParameterListBuilder::addTypeParameter(StringRef Name,
269 QualType DefaultValue) {
270 assert(!Builder.Record->isCompleteDefinition() &&
271 "record is already complete");
272 ASTContext &AST = Builder.SemaRef.getASTContext();
273 unsigned Position = static_cast<unsigned>(Params.size());
274 auto *Decl = TemplateTypeParmDecl::Create(
275 C: AST, DC: Builder.Record->getDeclContext(), KeyLoc: SourceLocation(), NameLoc: SourceLocation(),
276 /* TemplateDepth */ D: 0, P: Position,
277 Id: &AST.Idents.get(Name, TokenCode: tok::TokenKind::identifier),
278 /* Typename */ true,
279 /* ParameterPack */ false,
280 /* HasTypeConstraint*/ false);
281 if (!DefaultValue.isNull())
282 Decl->setDefaultArgument(C: AST,
283 DefArg: Builder.SemaRef.getTrivialTemplateArgumentLoc(
284 Arg: DefaultValue, NTTPType: QualType(), Loc: SourceLocation()));
285
286 Params.emplace_back(Args&: Decl);
287 return *this;
288}
289
290// The concept specialization expression (CSE) constructed in
291// constructConceptSpecializationExpr is constructed so that it
292// matches the CSE that is constructed when parsing the below C++ code:
293//
294// template<typename T>
295// concept is_typed_resource_element_compatible =
296// __builtin_hlsl_typed_resource_element_compatible<T>
297//
298// template<typename element_type> requires
299// is_typed_resource_element_compatible<element_type>
300// struct RWBuffer {
301// element_type Val;
302// };
303//
304// int fn() {
305// RWBuffer<int> Buf;
306// }
307//
308// When dumping the AST and filtering for "RWBuffer", the resulting AST
309// structure is what we're trying to construct below, specifically the
310// CSE portion.
311ConceptSpecializationExpr *
312TemplateParameterListBuilder::constructConceptSpecializationExpr(
313 Sema &S, ConceptDecl *CD) {
314 ASTContext &Context = S.getASTContext();
315 SourceLocation Loc = Builder.Record->getBeginLoc();
316 DeclarationNameInfo DNI(CD->getDeclName(), Loc);
317 NestedNameSpecifierLoc NNSLoc;
318 DeclContext *DC = Builder.Record->getDeclContext();
319 TemplateArgumentListInfo TALI(Loc, Loc);
320
321 // Assume that the concept decl has just one template parameter
322 // This parameter should have been added when CD was constructed
323 // in getTypedBufferConceptDecl
324 assert(CD->getTemplateParameters()->size() == 1 &&
325 "unexpected concept decl parameter count");
326 TemplateTypeParmDecl *ConceptTTPD =
327 dyn_cast<TemplateTypeParmDecl>(Val: CD->getTemplateParameters()->getParam(Idx: 0));
328
329 // this TemplateTypeParmDecl is the template for the resource, and is
330 // used to construct a template argumentthat will be used
331 // to construct the ImplicitConceptSpecializationDecl
332 TemplateTypeParmDecl *T = TemplateTypeParmDecl::Create(
333 C: Context, // AST context
334 DC: Builder.Record->getDeclContext(), // DeclContext
335 KeyLoc: SourceLocation(), NameLoc: SourceLocation(),
336 /*D=*/0, // Depth in the template parameter list
337 /*P=*/0, // Position in the template parameter list
338 /*Id=*/nullptr, // Identifier for 'T'
339 /*Typename=*/true, // Indicates this is a 'typename' or 'class'
340 /*ParameterPack=*/false, // Not a parameter pack
341 /*HasTypeConstraint=*/false // Has no type constraint
342 );
343
344 T->setDeclContext(DC);
345
346 QualType ConceptTType = Context.getTypeDeclType(Decl: ConceptTTPD);
347
348 // this is the 2nd template argument node, on which
349 // the concept constraint is actually being applied: 'element_type'
350 TemplateArgument ConceptTA = TemplateArgument(ConceptTType);
351
352 QualType CSETType = Context.getTypeDeclType(Decl: T);
353
354 // this is the 1st template argument node, which represents
355 // the abstract type that a concept would refer to: 'T'
356 TemplateArgument CSETA = TemplateArgument(CSETType);
357
358 ImplicitConceptSpecializationDecl *ImplicitCSEDecl =
359 ImplicitConceptSpecializationDecl::Create(
360 C: Context, DC: Builder.Record->getDeclContext(), SL: Loc, ConvertedArgs: {CSETA});
361
362 // Constraint satisfaction is used to construct the
363 // ConceptSpecailizationExpr, and represents the 2nd Template Argument,
364 // located at the bottom of the sample AST above.
365 const ConstraintSatisfaction CS(CD, {ConceptTA});
366 TemplateArgumentLoc TAL =
367 S.getTrivialTemplateArgumentLoc(Arg: ConceptTA, NTTPType: QualType(), Loc: SourceLocation());
368
369 TALI.addArgument(Loc: TAL);
370 const ASTTemplateArgumentListInfo *ATALI =
371 ASTTemplateArgumentListInfo::Create(C: Context, List: TALI);
372
373 // In the concept reference, ATALI is what adds the extra
374 // TemplateArgument node underneath CSE
375 ConceptReference *CR =
376 ConceptReference::Create(C: Context, NNS: NNSLoc, TemplateKWLoc: Loc, ConceptNameInfo: DNI, FoundDecl: CD, NamedConcept: CD, ArgsAsWritten: ATALI);
377
378 ConceptSpecializationExpr *CSE =
379 ConceptSpecializationExpr::Create(C: Context, ConceptRef: CR, SpecDecl: ImplicitCSEDecl, Satisfaction: &CS);
380
381 return CSE;
382}
383
384BuiltinTypeDeclBuilder &
385TemplateParameterListBuilder::finalizeTemplateArgs(ConceptDecl *CD) {
386 if (Params.empty())
387 return Builder;
388
389 ASTContext &AST = Builder.SemaRef.Context;
390 ConceptSpecializationExpr *CSE =
391 CD ? constructConceptSpecializationExpr(S&: Builder.SemaRef, CD) : nullptr;
392 auto *ParamList = TemplateParameterList::Create(
393 C: AST, TemplateLoc: SourceLocation(), LAngleLoc: SourceLocation(), Params, RAngleLoc: SourceLocation(), RequiresClause: CSE);
394 Builder.Template = ClassTemplateDecl::Create(
395 C&: AST, DC: Builder.Record->getDeclContext(), L: SourceLocation(),
396 Name: DeclarationName(Builder.Record->getIdentifier()), Params: ParamList,
397 Decl: Builder.Record);
398
399 Builder.Record->setDescribedClassTemplate(Builder.Template);
400 Builder.Template->setImplicit(true);
401 Builder.Template->setLexicalDeclContext(Builder.Record->getDeclContext());
402
403 // NOTE: setPreviousDecl before addDecl so new decl replace old decl when
404 // make visible.
405 Builder.Template->setPreviousDecl(Builder.PrevTemplate);
406 Builder.Record->getDeclContext()->addDecl(D: Builder.Template);
407 Params.clear();
408
409 return Builder;
410}
411
412Expr *BuiltinTypeMethodBuilder::convertPlaceholder(PlaceHolder PH) {
413 if (PH == PlaceHolder::Handle)
414 return getResourceHandleExpr();
415 if (PH == PlaceHolder::CounterHandle)
416 return getResourceCounterHandleExpr();
417
418 if (PH == PlaceHolder::LastStmt) {
419 assert(!StmtsList.empty() && "no statements in the list");
420 Stmt *LastStmt = StmtsList.pop_back_val();
421 assert(isa<ValueStmt>(LastStmt) && "last statement does not have a value");
422 return cast<ValueStmt>(Val: LastStmt)->getExprStmt();
423 }
424
425 // All other placeholders are parameters (_N), and can be loaded as an
426 // LValue. It needs to be an LValue if the result expression will be used as
427 // the actual parameter for an out parameter. The dimension builtins are an
428 // example where this happens.
429 ASTContext &AST = DeclBuilder.SemaRef.getASTContext();
430 ParmVarDecl *ParamDecl = Method->getParamDecl(i: static_cast<unsigned>(PH));
431 return DeclRefExpr::Create(
432 Context: AST, QualifierLoc: NestedNameSpecifierLoc(), TemplateKWLoc: SourceLocation(), D: ParamDecl, RefersToEnclosingVariableOrCapture: false,
433 NameInfo: DeclarationNameInfo(ParamDecl->getDeclName(), SourceLocation()),
434 T: ParamDecl->getType().getNonReferenceType(), VK: VK_LValue);
435}
436
437Expr *BuiltinTypeMethodBuilder::convertPlaceholder(LocalVar &Var) {
438 VarDecl *VD = Var.Decl;
439 assert(VD && "local variable is not declared");
440 return DeclRefExpr::Create(
441 Context: VD->getASTContext(), QualifierLoc: NestedNameSpecifierLoc(), TemplateKWLoc: SourceLocation(), D: VD,
442 RefersToEnclosingVariableOrCapture: false, NameInfo: DeclarationNameInfo(VD->getDeclName(), SourceLocation()),
443 T: VD->getType(), VK: VK_LValue);
444}
445
446Expr *BuiltinTypeMethodBuilder::convertPlaceholder(QualType Ty) {
447 ASTContext &AST = DeclBuilder.SemaRef.getASTContext();
448 QualType PtrTy = AST.getPointerType(T: Ty);
449 // Creates a value-initialized null pointer of type Ty*.
450 return new (AST) CXXScalarValueInitExpr(
451 PtrTy, AST.getTrivialTypeSourceInfo(T: PtrTy, Loc: SourceLocation()),
452 SourceLocation());
453}
454
455BuiltinTypeMethodBuilder::BuiltinTypeMethodBuilder(BuiltinTypeDeclBuilder &DB,
456 StringRef NameStr,
457 QualType ReturnTy,
458 bool IsConst, bool IsCtor,
459 StorageClass SC)
460 : DeclBuilder(DB), ReturnTy(ReturnTy), Method(nullptr), IsConst(IsConst),
461 IsCtor(IsCtor), SC(SC) {
462
463 assert((!NameStr.empty() || IsCtor) && "method needs a name");
464 assert(((IsCtor && !IsConst) || !IsCtor) && "constructor cannot be const");
465
466 ASTContext &AST = DB.SemaRef.getASTContext();
467 if (IsCtor) {
468 Name = AST.DeclarationNames.getCXXConstructorName(
469 Ty: AST.getCanonicalTagType(TD: DB.Record));
470 } else {
471 const IdentifierInfo &II =
472 AST.Idents.get(Name: NameStr, TokenCode: tok::TokenKind::identifier);
473 Name = DeclarationName(&II);
474 }
475}
476
477BuiltinTypeMethodBuilder &
478BuiltinTypeMethodBuilder::addParam(StringRef Name, QualType Ty,
479 HLSLParamModifierAttr::Spelling Modifier) {
480 assert(Method == nullptr && "Cannot add param, method already created");
481 const IdentifierInfo &II = DeclBuilder.SemaRef.getASTContext().Idents.get(
482 Name, TokenCode: tok::TokenKind::identifier);
483 Params.emplace_back(Args: II, Args&: Ty, Args&: Modifier);
484 return *this;
485}
486QualType BuiltinTypeMethodBuilder::addTemplateTypeParam(StringRef Name) {
487 assert(Method == nullptr &&
488 "Cannot add template param, method already created");
489 ASTContext &AST = DeclBuilder.SemaRef.getASTContext();
490 unsigned Position = static_cast<unsigned>(TemplateParamDecls.size());
491 auto *Decl = TemplateTypeParmDecl::Create(
492 C: AST, DC: DeclBuilder.Record, KeyLoc: SourceLocation(), NameLoc: SourceLocation(),
493 /* TemplateDepth */ D: 0, P: Position,
494 Id: &AST.Idents.get(Name, TokenCode: tok::TokenKind::identifier),
495 /* Typename */ true,
496 /* ParameterPack */ false,
497 /* HasTypeConstraint*/ false);
498 TemplateParamDecls.push_back(Elt: Decl);
499
500 return QualType(Decl->getTypeForDecl(), 0);
501}
502
503void BuiltinTypeMethodBuilder::createDecl() {
504 assert(Method == nullptr && "Method or constructor is already created");
505
506 // create function prototype
507 ASTContext &AST = DeclBuilder.SemaRef.getASTContext();
508 SmallVector<QualType> ParamTypes;
509 SmallVector<FunctionType::ExtParameterInfo> ParamExtInfos(Params.size());
510 uint32_t ArgIndex = 0;
511
512 // Create function prototype.
513 bool UseParamExtInfo = false;
514 for (Param &MP : Params) {
515 if (MP.Modifier != HLSLParamModifierAttr::Keyword_in) {
516 UseParamExtInfo = true;
517 FunctionType::ExtParameterInfo &PI = ParamExtInfos[ArgIndex];
518 ParamExtInfos[ArgIndex] =
519 PI.withABI(kind: convertParamModifierToParamABI(Modifier: MP.Modifier));
520 if (!MP.Ty->isDependentType())
521 MP.Ty = getInoutParameterType(AST, Ty: MP.Ty);
522 }
523 ParamTypes.emplace_back(Args&: MP.Ty);
524 ++ArgIndex;
525 }
526
527 FunctionProtoType::ExtProtoInfo ExtInfo;
528 if (UseParamExtInfo)
529 ExtInfo.ExtParameterInfos = ParamExtInfos.data();
530 if (IsConst)
531 ExtInfo.TypeQuals.addConst();
532
533 QualType FuncTy = AST.getFunctionType(ResultTy: ReturnTy, Args: ParamTypes, EPI: ExtInfo);
534
535 // Create method or constructor declaration.
536 auto *TSInfo = AST.getTrivialTypeSourceInfo(T: FuncTy, Loc: SourceLocation());
537 DeclarationNameInfo NameInfo = DeclarationNameInfo(Name, SourceLocation());
538 if (IsCtor)
539 Method = CXXConstructorDecl::Create(
540 C&: AST, RD: DeclBuilder.Record, StartLoc: SourceLocation(), NameInfo, T: FuncTy, TInfo: TSInfo,
541 ES: ExplicitSpecifier(), UsesFPIntrin: false, /*IsInline=*/isInline: true, isImplicitlyDeclared: false,
542 ConstexprKind: ConstexprSpecKind::Unspecified);
543 else
544 Method = CXXMethodDecl::Create(
545 C&: AST, RD: DeclBuilder.Record, StartLoc: SourceLocation(), NameInfo, T: FuncTy, TInfo: TSInfo, SC,
546 UsesFPIntrin: false, isInline: true, ConstexprKind: ConstexprSpecKind::Unspecified, EndLocation: SourceLocation());
547
548 // Create params & set them to the method/constructor and function prototype.
549 SmallVector<ParmVarDecl *> ParmDecls;
550 unsigned CurScopeDepth = DeclBuilder.SemaRef.getCurScope()->getDepth();
551 auto FnProtoLoc =
552 Method->getTypeSourceInfo()->getTypeLoc().getAs<FunctionProtoTypeLoc>();
553 for (int I = 0, E = Params.size(); I != E; I++) {
554 Param &MP = Params[I];
555 ParmVarDecl *Parm = ParmVarDecl::Create(
556 C&: AST, DC: Method, StartLoc: SourceLocation(), IdLoc: SourceLocation(), Id: &MP.NameII, T: MP.Ty,
557 TInfo: AST.getTrivialTypeSourceInfo(T: MP.Ty, Loc: SourceLocation()), S: SC_None,
558 DefArg: nullptr);
559 if (MP.Modifier != HLSLParamModifierAttr::Keyword_in) {
560 auto *Mod =
561 HLSLParamModifierAttr::Create(Ctx&: AST, Range: SourceRange(), S: MP.Modifier);
562 Parm->addAttr(A: Mod);
563 }
564 Parm->setScopeInfo(scopeDepth: CurScopeDepth, parameterIndex: I);
565 ParmDecls.push_back(Elt: Parm);
566 FnProtoLoc.setParam(i: I, VD: Parm);
567 }
568 Method->setParams({ParmDecls});
569}
570
571Expr *BuiltinTypeMethodBuilder::getResourceHandleExpr() {
572 ensureCompleteDecl();
573
574 ASTContext &AST = DeclBuilder.SemaRef.getASTContext();
575 CXXThisExpr *This = CXXThisExpr::Create(
576 Ctx: AST, L: SourceLocation(), Ty: Method->getFunctionObjectParameterType(), IsImplicit: true);
577 FieldDecl *HandleField = DeclBuilder.getResourceHandleField();
578 return MemberExpr::CreateImplicit(C: AST, Base: This, IsArrow: false, MemberDecl: HandleField,
579 T: HandleField->getType(), VK: VK_LValue,
580 OK: OK_Ordinary);
581}
582
583Expr *BuiltinTypeMethodBuilder::getResourceCounterHandleExpr() {
584 ensureCompleteDecl();
585
586 ASTContext &AST = DeclBuilder.SemaRef.getASTContext();
587 CXXThisExpr *This = CXXThisExpr::Create(
588 Ctx: AST, L: SourceLocation(), Ty: Method->getFunctionObjectParameterType(), IsImplicit: true);
589 FieldDecl *HandleField = DeclBuilder.getResourceCounterHandleField();
590 return MemberExpr::CreateImplicit(C: AST, Base: This, IsArrow: false, MemberDecl: HandleField,
591 T: HandleField->getType(), VK: VK_LValue,
592 OK: OK_Ordinary);
593}
594
595BuiltinTypeMethodBuilder &
596BuiltinTypeMethodBuilder::declareLocalVar(LocalVar &Var) {
597 ensureCompleteDecl();
598
599 assert(Var.Decl == nullptr && "local variable is already declared");
600
601 ASTContext &AST = DeclBuilder.SemaRef.getASTContext();
602 Var.Decl = VarDecl::Create(
603 C&: AST, DC: Method, StartLoc: SourceLocation(), IdLoc: SourceLocation(),
604 Id: &AST.Idents.get(Name: Var.Name, TokenCode: tok::TokenKind::identifier), T: Var.Ty,
605 TInfo: AST.getTrivialTypeSourceInfo(T: Var.Ty, Loc: SourceLocation()), S: SC_None);
606 DeclStmt *DS = new (AST) clang::DeclStmt(DeclGroupRef(Var.Decl),
607 SourceLocation(), SourceLocation());
608 StmtsList.push_back(Elt: DS);
609 return *this;
610}
611
612BuiltinTypeMethodBuilder &BuiltinTypeMethodBuilder::returnThis() {
613 ASTContext &AST = DeclBuilder.SemaRef.getASTContext();
614 CXXThisExpr *ThisExpr = CXXThisExpr::Create(
615 Ctx: AST, L: SourceLocation(), Ty: Method->getFunctionObjectParameterType(),
616 /*IsImplicit=*/true);
617 StmtsList.push_back(Elt: ThisExpr);
618 return *this;
619}
620
621template <typename... Ts>
622BuiltinTypeMethodBuilder &
623BuiltinTypeMethodBuilder::callBuiltin(StringRef BuiltinName,
624 QualType ReturnType, Ts &&...ArgSpecs) {
625 ensureCompleteDecl();
626
627 std::array<Expr *, sizeof...(ArgSpecs)> Args{
628 convertPlaceholder(std::forward<Ts>(ArgSpecs))...};
629
630 ASTContext &AST = DeclBuilder.SemaRef.getASTContext();
631 FunctionDecl *FD = lookupBuiltinFunction(S&: DeclBuilder.SemaRef, Name: BuiltinName);
632 DeclRefExpr *DRE = DeclRefExpr::Create(
633 Context: AST, QualifierLoc: NestedNameSpecifierLoc(), TemplateKWLoc: SourceLocation(), D: FD, RefersToEnclosingVariableOrCapture: false,
634 NameInfo: FD->getNameInfo(), T: AST.BuiltinFnTy, VK: VK_PRValue);
635
636 ExprResult Call = DeclBuilder.SemaRef.BuildCallExpr(
637 /*Scope=*/S: nullptr, Fn: DRE, LParenLoc: SourceLocation(),
638 ArgExprs: MultiExprArg(Args.data(), Args.size()), RParenLoc: SourceLocation());
639 assert(!Call.isInvalid() && "Call to builtin cannot fail!");
640 Expr *E = Call.get();
641
642 if (!ReturnType.isNull() &&
643 !AST.hasSameUnqualifiedType(T1: ReturnType, T2: E->getType())) {
644 ExprResult CastResult = DeclBuilder.SemaRef.BuildCStyleCastExpr(
645 LParenLoc: SourceLocation(), Ty: AST.getTrivialTypeSourceInfo(T: ReturnType),
646 RParenLoc: SourceLocation(), Op: E);
647 assert(!CastResult.isInvalid() && "Cast cannot fail!");
648 E = CastResult.get();
649 }
650
651 StmtsList.push_back(Elt: E);
652 return *this;
653}
654
655template <typename TLHS, typename TRHS>
656BuiltinTypeMethodBuilder &BuiltinTypeMethodBuilder::assign(TLHS LHS, TRHS RHS) {
657 Expr *LHSExpr = convertPlaceholder(LHS);
658 Expr *RHSExpr = convertPlaceholder(RHS);
659 Stmt *AssignStmt = BinaryOperator::Create(
660 C: DeclBuilder.SemaRef.getASTContext(), lhs: LHSExpr, rhs: RHSExpr, opc: BO_Assign,
661 ResTy: LHSExpr->getType(), VK: ExprValueKind::VK_PRValue,
662 OK: ExprObjectKind::OK_Ordinary, opLoc: SourceLocation(), FPFeatures: FPOptionsOverride());
663 StmtsList.push_back(Elt: AssignStmt);
664 return *this;
665}
666
667template <typename T>
668BuiltinTypeMethodBuilder &BuiltinTypeMethodBuilder::dereference(T Ptr) {
669 Expr *PtrExpr = convertPlaceholder(Ptr);
670 Expr *Deref =
671 UnaryOperator::Create(C: DeclBuilder.SemaRef.getASTContext(), input: PtrExpr,
672 opc: UO_Deref, type: PtrExpr->getType()->getPointeeType(),
673 VK: VK_LValue, OK: OK_Ordinary, l: SourceLocation(),
674 /*CanOverflow=*/false, FPFeatures: FPOptionsOverride());
675 StmtsList.push_back(Elt: Deref);
676 return *this;
677}
678
679template <typename T>
680BuiltinTypeMethodBuilder &
681BuiltinTypeMethodBuilder::accessHandleFieldOnResource(T ResourceRecord) {
682 ensureCompleteDecl();
683
684 Expr *ResourceExpr = convertPlaceholder(ResourceRecord);
685 auto *ResourceTypeDecl = ResourceExpr->getType()->getAsCXXRecordDecl();
686
687 ASTContext &AST = DeclBuilder.SemaRef.getASTContext();
688 FieldDecl *HandleField = nullptr;
689
690 if (ResourceTypeDecl == DeclBuilder.Record)
691 HandleField = DeclBuilder.getResourceHandleField();
692 else {
693 IdentifierInfo &II = AST.Idents.get(Name: "__handle");
694 for (auto *Decl : ResourceTypeDecl->lookup(Name: &II)) {
695 if ((HandleField = dyn_cast<FieldDecl>(Val: Decl)))
696 break;
697 }
698 assert(HandleField && "Resource handle field not found");
699 }
700
701 MemberExpr *HandleExpr = MemberExpr::CreateImplicit(
702 C: AST, Base: ResourceExpr, IsArrow: false, MemberDecl: HandleField, T: HandleField->getType(), VK: VK_LValue,
703 OK: OK_Ordinary);
704 StmtsList.push_back(Elt: HandleExpr);
705 return *this;
706}
707
708template <typename ResourceT, typename ValueT>
709BuiltinTypeMethodBuilder &
710BuiltinTypeMethodBuilder::setHandleFieldOnResource(ResourceT ResourceRecord,
711 ValueT HandleValue) {
712 return setFieldOnResource(ResourceRecord, HandleValue,
713 DeclBuilder.getResourceHandleField());
714}
715
716template <typename ResourceT, typename ValueT>
717BuiltinTypeMethodBuilder &
718BuiltinTypeMethodBuilder::setCounterHandleFieldOnResource(
719 ResourceT ResourceRecord, ValueT HandleValue) {
720 return setFieldOnResource(ResourceRecord, HandleValue,
721 DeclBuilder.getResourceCounterHandleField());
722}
723
724template <typename ResourceT, typename ValueT>
725BuiltinTypeMethodBuilder &BuiltinTypeMethodBuilder::setFieldOnResource(
726 ResourceT ResourceRecord, ValueT HandleValue, FieldDecl *HandleField) {
727 ensureCompleteDecl();
728
729 Expr *ResourceExpr = convertPlaceholder(ResourceRecord);
730 assert(ResourceExpr->getType()->getAsCXXRecordDecl() ==
731 HandleField->getParent() &&
732 "Getting the field from the wrong resource type.");
733
734 Expr *HandleValueExpr = convertPlaceholder(HandleValue);
735
736 ASTContext &AST = DeclBuilder.SemaRef.getASTContext();
737 MemberExpr *HandleMemberExpr = MemberExpr::CreateImplicit(
738 C: AST, Base: ResourceExpr, IsArrow: false, MemberDecl: HandleField, T: HandleField->getType(), VK: VK_LValue,
739 OK: OK_Ordinary);
740 Stmt *AssignStmt = BinaryOperator::Create(
741 C: DeclBuilder.SemaRef.getASTContext(), lhs: HandleMemberExpr, rhs: HandleValueExpr,
742 opc: BO_Assign, ResTy: HandleMemberExpr->getType(), VK: ExprValueKind::VK_PRValue,
743 OK: ExprObjectKind::OK_Ordinary, opLoc: SourceLocation(), FPFeatures: FPOptionsOverride());
744 StmtsList.push_back(Elt: AssignStmt);
745 return *this;
746}
747
748template <typename T>
749BuiltinTypeMethodBuilder &
750BuiltinTypeMethodBuilder::accessCounterHandleFieldOnResource(T ResourceRecord) {
751 ensureCompleteDecl();
752
753 Expr *ResourceExpr = convertPlaceholder(ResourceRecord);
754 assert(ResourceExpr->getType()->getAsCXXRecordDecl() == DeclBuilder.Record &&
755 "Getting the field from the wrong resource type.");
756
757 ASTContext &AST = DeclBuilder.SemaRef.getASTContext();
758 FieldDecl *HandleField = DeclBuilder.getResourceCounterHandleField();
759 MemberExpr *HandleExpr = MemberExpr::CreateImplicit(
760 C: AST, Base: ResourceExpr, IsArrow: false, MemberDecl: HandleField, T: HandleField->getType(), VK: VK_LValue,
761 OK: OK_Ordinary);
762 StmtsList.push_back(Elt: HandleExpr);
763 return *this;
764}
765
766template <typename T>
767BuiltinTypeMethodBuilder &BuiltinTypeMethodBuilder::returnValue(T ReturnValue) {
768 ensureCompleteDecl();
769
770 Expr *ReturnValueExpr = convertPlaceholder(ReturnValue);
771 ASTContext &AST = DeclBuilder.SemaRef.getASTContext();
772
773 QualType Ty = ReturnValueExpr->getType();
774 if (Ty->isRecordType()) {
775 // For record types, create a call to copy constructor to ensure proper copy
776 // semantics.
777 auto *ICE =
778 ImplicitCastExpr::Create(Context: AST, T: Ty.withConst(), Kind: CK_NoOp, Operand: ReturnValueExpr,
779 BasePath: nullptr, Cat: VK_XValue, FPO: FPOptionsOverride());
780 CXXConstructorDecl *CD = lookupCopyConstructor(ResTy: Ty);
781 assert(CD && "no copy constructor found");
782 ReturnValueExpr = CXXConstructExpr::Create(
783 Ctx: AST, Ty, Loc: SourceLocation(), Ctor: CD, /*Elidable=*/false, Args: {ICE},
784 /*HadMultipleCandidates=*/false, /*ListInitialization=*/false,
785 /*StdInitListInitialization=*/false,
786 /*ZeroInitListInitialization=*/ZeroInitialization: false, ConstructKind: CXXConstructionKind::Complete,
787 ParenOrBraceRange: SourceRange());
788 }
789 StmtsList.push_back(
790 Elt: ReturnStmt::Create(Ctx: AST, RL: SourceLocation(), E: ReturnValueExpr, NRVOCandidate: nullptr));
791 return *this;
792}
793
794BuiltinTypeDeclBuilder &BuiltinTypeMethodBuilder::finalize() {
795 assert(!DeclBuilder.Record->isCompleteDefinition() &&
796 "record is already complete");
797
798 ensureCompleteDecl();
799
800 if (!Method->hasBody()) {
801 ASTContext &AST = DeclBuilder.SemaRef.getASTContext();
802 assert((ReturnTy == AST.VoidTy || !StmtsList.empty()) &&
803 "nothing to return from non-void method");
804 if (ReturnTy != AST.VoidTy) {
805 if (Expr *LastExpr = dyn_cast<Expr>(Val: StmtsList.back())) {
806 assert(AST.hasSameUnqualifiedType(LastExpr->getType(),
807 ReturnTy.getNonReferenceType()) &&
808 "Return type of the last statement must match the return type "
809 "of the method");
810 if (!isa<ReturnStmt>(Val: LastExpr)) {
811 StmtsList.pop_back();
812 StmtsList.push_back(
813 Elt: ReturnStmt::Create(Ctx: AST, RL: SourceLocation(), E: LastExpr, NRVOCandidate: nullptr));
814 }
815 }
816 }
817
818 Method->setBody(CompoundStmt::Create(C: AST, Stmts: StmtsList, FPFeatures: FPOptionsOverride(),
819 LB: SourceLocation(), RB: SourceLocation()));
820 Method->setLexicalDeclContext(DeclBuilder.Record);
821 Method->setAccess(AS_public);
822 Method->addAttr(A: AlwaysInlineAttr::CreateImplicit(
823 Ctx&: AST, Range: SourceRange(), S: AlwaysInlineAttr::CXX11_clang_always_inline));
824 if (!TemplateParamDecls.empty()) {
825 TemplateParams = TemplateParameterList::Create(
826 C: AST, TemplateLoc: SourceLocation(), LAngleLoc: SourceLocation(), Params: TemplateParamDecls,
827 RAngleLoc: SourceLocation(), RequiresClause: nullptr);
828
829 auto *FuncTemplate = FunctionTemplateDecl::Create(C&: AST, DC: DeclBuilder.Record,
830 L: SourceLocation(), Name,
831 Params: TemplateParams, Decl: Method);
832 FuncTemplate->setAccess(AS_public);
833 FuncTemplate->setLexicalDeclContext(DeclBuilder.Record);
834 FuncTemplate->setImplicit(true);
835 Method->setDescribedFunctionTemplate(FuncTemplate);
836 DeclBuilder.Record->addDecl(D: FuncTemplate);
837 } else {
838 DeclBuilder.Record->addDecl(D: Method);
839 }
840 }
841 return DeclBuilder;
842}
843
844BuiltinTypeDeclBuilder::BuiltinTypeDeclBuilder(Sema &SemaRef, CXXRecordDecl *R)
845 : SemaRef(SemaRef), Record(R) {
846 Record->startDefinition();
847 Template = Record->getDescribedClassTemplate();
848}
849
850BuiltinTypeDeclBuilder::BuiltinTypeDeclBuilder(Sema &SemaRef,
851 NamespaceDecl *Namespace,
852 StringRef Name)
853 : SemaRef(SemaRef), HLSLNamespace(Namespace) {
854 ASTContext &AST = SemaRef.getASTContext();
855 IdentifierInfo &II = AST.Idents.get(Name, TokenCode: tok::TokenKind::identifier);
856
857 LookupResult Result(SemaRef, &II, SourceLocation(), Sema::LookupTagName);
858 CXXRecordDecl *PrevDecl = nullptr;
859 if (SemaRef.LookupQualifiedName(R&: Result, LookupCtx: HLSLNamespace)) {
860 // Declaration already exists (from precompiled headers)
861 NamedDecl *Found = Result.getFoundDecl();
862 if (auto *TD = dyn_cast<ClassTemplateDecl>(Val: Found)) {
863 PrevDecl = TD->getTemplatedDecl();
864 PrevTemplate = TD;
865 } else
866 PrevDecl = dyn_cast<CXXRecordDecl>(Val: Found);
867 assert(PrevDecl && "Unexpected lookup result type.");
868 }
869
870 if (PrevDecl && PrevDecl->isCompleteDefinition()) {
871 Record = PrevDecl;
872 Template = PrevTemplate;
873 return;
874 }
875
876 Record =
877 CXXRecordDecl::Create(C: AST, TK: TagDecl::TagKind::Class, DC: HLSLNamespace,
878 StartLoc: SourceLocation(), IdLoc: SourceLocation(), Id: &II, PrevDecl);
879 Record->setImplicit(true);
880 Record->setLexicalDeclContext(HLSLNamespace);
881 Record->setHasExternalLexicalStorage();
882
883 // Don't let anyone derive from built-in types.
884 Record->addAttr(
885 A: FinalAttr::CreateImplicit(Ctx&: AST, Range: SourceRange(), S: FinalAttr::Keyword_final));
886}
887
888BuiltinTypeDeclBuilder::~BuiltinTypeDeclBuilder() {
889 if (HLSLNamespace && !Template && Record->getDeclContext() == HLSLNamespace)
890 HLSLNamespace->addDecl(D: Record);
891}
892
893BuiltinTypeDeclBuilder &
894BuiltinTypeDeclBuilder::addMemberVariable(StringRef Name, QualType Type,
895 llvm::ArrayRef<Attr *> Attrs,
896 AccessSpecifier Access) {
897 assert(!Record->isCompleteDefinition() && "record is already complete");
898 assert(Record->isBeingDefined() &&
899 "Definition must be started before adding members!");
900 ASTContext &AST = Record->getASTContext();
901
902 IdentifierInfo &II = AST.Idents.get(Name, TokenCode: tok::TokenKind::identifier);
903 TypeSourceInfo *MemTySource =
904 AST.getTrivialTypeSourceInfo(T: Type, Loc: SourceLocation());
905 auto *Field = FieldDecl::Create(
906 C: AST, DC: Record, StartLoc: SourceLocation(), IdLoc: SourceLocation(), Id: &II, T: Type, TInfo: MemTySource,
907 BW: nullptr, Mutable: false, InitStyle: InClassInitStyle::ICIS_NoInit);
908 Field->setAccess(Access);
909 Field->setImplicit(true);
910 for (Attr *A : Attrs) {
911 if (A)
912 Field->addAttr(A);
913 }
914
915 Record->addDecl(D: Field);
916 Fields[Name] = Field;
917 return *this;
918}
919
920BuiltinTypeDeclBuilder &
921BuiltinTypeDeclBuilder::addBufferHandles(ResourceClass RC, bool IsROV,
922 bool RawBuffer, bool HasCounter,
923 AccessSpecifier Access) {
924 addHandleMember(RC, RD: ResourceDimension::Unknown, IsROV, RawBuffer, Access);
925 if (HasCounter)
926 addCounterHandleMember(RC, IsROV, RawBuffer, Access);
927 return *this;
928}
929
930BuiltinTypeDeclBuilder &
931BuiltinTypeDeclBuilder::addTextureHandle(ResourceClass RC, bool IsROV,
932 ResourceDimension RD,
933 AccessSpecifier Access) {
934 addHandleMember(RC, RD, IsROV, /*RawBuffer=*/false, Access);
935 return *this;
936}
937
938BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addSamplerHandle() {
939 addHandleMember(RC: ResourceClass::Sampler, RD: ResourceDimension::Unknown,
940 /*IsROV=*/false, /*RawBuffer=*/false);
941 return *this;
942}
943
944BuiltinTypeDeclBuilder &
945BuiltinTypeDeclBuilder::addHandleMember(ResourceClass RC, ResourceDimension RD,
946 bool IsROV, bool RawBuffer,
947 AccessSpecifier Access) {
948 return addResourceMember(MemberName: "__handle", RC, RD, IsROV, RawBuffer,
949 /*IsCounter=*/false, Access);
950}
951
952BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addCounterHandleMember(
953 ResourceClass RC, bool IsROV, bool RawBuffer, AccessSpecifier Access) {
954 return addResourceMember(MemberName: "__counter_handle", RC, RD: ResourceDimension::Unknown,
955 IsROV, RawBuffer,
956 /*IsCounter=*/true, Access);
957}
958
959BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addResourceMember(
960 StringRef MemberName, ResourceClass RC, ResourceDimension RD, bool IsROV,
961 bool RawBuffer, bool IsCounter, AccessSpecifier Access) {
962 assert(!Record->isCompleteDefinition() && "record is already complete");
963
964 ASTContext &Ctx = SemaRef.getASTContext();
965 TypeSourceInfo *ElementTypeInfo =
966 Ctx.getTrivialTypeSourceInfo(T: getHandleElementType(), Loc: SourceLocation());
967
968 // add handle member with resource type attributes
969 QualType AttributedResTy = QualType();
970 SmallVector<const Attr *> Attrs = {
971 HLSLResourceClassAttr::CreateImplicit(Ctx, ResourceClass: RC),
972 IsROV ? HLSLROVAttr::CreateImplicit(Ctx) : nullptr,
973 RawBuffer ? HLSLRawBufferAttr::CreateImplicit(Ctx) : nullptr,
974 RD != ResourceDimension::Unknown
975 ? HLSLResourceDimensionAttr::CreateImplicit(Ctx, Dimension: RD)
976 : nullptr,
977 ElementTypeInfo && RC != ResourceClass::Sampler
978 ? HLSLContainedTypeAttr::CreateImplicit(Ctx, Type: ElementTypeInfo)
979 : nullptr};
980 if (IsCounter)
981 Attrs.push_back(Elt: HLSLIsCounterAttr::CreateImplicit(Ctx));
982
983 if (CreateHLSLAttributedResourceType(S&: SemaRef, Wrapped: Ctx.HLSLResourceTy, AttrList: Attrs,
984 ResType&: AttributedResTy))
985 addMemberVariable(Name: MemberName, Type: AttributedResTy, Attrs: {}, Access);
986 return *this;
987}
988
989// Adds default constructor to the resource class:
990// Resource::Resource()
991BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addDefaultHandleConstructor() {
992 assert(!Record->isCompleteDefinition() && "record is already complete");
993
994 using PH = BuiltinTypeMethodBuilder::PlaceHolder;
995 QualType HandleType = getResourceHandleField()->getType();
996 return BuiltinTypeMethodBuilder(*this, "", SemaRef.getASTContext().VoidTy,
997 false, true)
998 .callBuiltin(BuiltinName: "__builtin_hlsl_resource_uninitializedhandle", ReturnType: HandleType,
999 ArgSpecs: PH::Handle)
1000 .assign(LHS: PH::Handle, RHS: PH::LastStmt)
1001 .finalize();
1002}
1003
1004BuiltinTypeDeclBuilder &
1005BuiltinTypeDeclBuilder::addStaticInitializationFunctions(bool HasCounter) {
1006 if (HasCounter) {
1007 addCreateFromBindingWithImplicitCounter();
1008 addCreateFromImplicitBindingWithImplicitCounter();
1009 } else {
1010 addCreateFromBinding();
1011 addCreateFromImplicitBinding();
1012 }
1013 return *this;
1014}
1015
1016// Adds static method that initializes resource from binding:
1017//
1018// static Resource<T> __createFromBinding(unsigned registerNo,
1019// unsigned spaceNo, int range,
1020// unsigned index, const char *name) {
1021// Resource<T> tmp;
1022// tmp.__handle = __builtin_hlsl_resource_handlefrombinding(
1023// tmp.__handle, registerNo, spaceNo,
1024// range, index, name);
1025// return tmp;
1026// }
1027BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addCreateFromBinding() {
1028 assert(!Record->isCompleteDefinition() && "record is already complete");
1029
1030 using PH = BuiltinTypeMethodBuilder::PlaceHolder;
1031 ASTContext &AST = SemaRef.getASTContext();
1032 QualType HandleType = getResourceHandleField()->getType();
1033 QualType RecordType = AST.getTypeDeclType(Decl: cast<TypeDecl>(Val: Record));
1034 BuiltinTypeMethodBuilder::LocalVar TmpVar("tmp", RecordType);
1035
1036 return BuiltinTypeMethodBuilder(*this, "__createFromBinding", RecordType,
1037 false, false, SC_Static)
1038 .addParam(Name: "registerNo", Ty: AST.UnsignedIntTy)
1039 .addParam(Name: "spaceNo", Ty: AST.UnsignedIntTy)
1040 .addParam(Name: "range", Ty: AST.IntTy)
1041 .addParam(Name: "index", Ty: AST.UnsignedIntTy)
1042 .addParam(Name: "name", Ty: AST.getPointerType(T: AST.CharTy.withConst()))
1043 .declareLocalVar(Var&: TmpVar)
1044 .accessHandleFieldOnResource(ResourceRecord: TmpVar)
1045 .callBuiltin(BuiltinName: "__builtin_hlsl_resource_handlefrombinding", ReturnType: HandleType,
1046 ArgSpecs: PH::LastStmt, ArgSpecs: PH::_0, ArgSpecs: PH::_1, ArgSpecs: PH::_2, ArgSpecs: PH::_3, ArgSpecs: PH::_4)
1047 .setHandleFieldOnResource(ResourceRecord: TmpVar, HandleValue: PH::LastStmt)
1048 .returnValue(ReturnValue: TmpVar)
1049 .finalize();
1050}
1051
1052// Adds static method that initializes resource from binding:
1053//
1054// static Resource<T> __createFromImplicitBinding(unsigned orderId,
1055// unsigned spaceNo, int range,
1056// unsigned index,
1057// const char *name) {
1058// Resource<T> tmp;
1059// tmp.__handle = __builtin_hlsl_resource_handlefromimplicitbinding(
1060// tmp.__handle, spaceNo,
1061// range, index, orderId, name);
1062// return tmp;
1063// }
1064BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addCreateFromImplicitBinding() {
1065 assert(!Record->isCompleteDefinition() && "record is already complete");
1066
1067 using PH = BuiltinTypeMethodBuilder::PlaceHolder;
1068 ASTContext &AST = SemaRef.getASTContext();
1069 QualType HandleType = getResourceHandleField()->getType();
1070 QualType RecordType = AST.getTypeDeclType(Decl: cast<TypeDecl>(Val: Record));
1071 BuiltinTypeMethodBuilder::LocalVar TmpVar("tmp", RecordType);
1072
1073 return BuiltinTypeMethodBuilder(*this, "__createFromImplicitBinding",
1074 RecordType, false, false, SC_Static)
1075 .addParam(Name: "orderId", Ty: AST.UnsignedIntTy)
1076 .addParam(Name: "spaceNo", Ty: AST.UnsignedIntTy)
1077 .addParam(Name: "range", Ty: AST.IntTy)
1078 .addParam(Name: "index", Ty: AST.UnsignedIntTy)
1079 .addParam(Name: "name", Ty: AST.getPointerType(T: AST.CharTy.withConst()))
1080 .declareLocalVar(Var&: TmpVar)
1081 .accessHandleFieldOnResource(ResourceRecord: TmpVar)
1082 .callBuiltin(BuiltinName: "__builtin_hlsl_resource_handlefromimplicitbinding",
1083 ReturnType: HandleType, ArgSpecs: PH::LastStmt, ArgSpecs: PH::_0, ArgSpecs: PH::_1, ArgSpecs: PH::_2, ArgSpecs: PH::_3,
1084 ArgSpecs: PH::_4)
1085 .setHandleFieldOnResource(ResourceRecord: TmpVar, HandleValue: PH::LastStmt)
1086 .returnValue(ReturnValue: TmpVar)
1087 .finalize();
1088}
1089
1090// Adds static method that initializes resource from binding:
1091//
1092// static Resource<T>
1093// __createFromBindingWithImplicitCounter(unsigned registerNo,
1094// unsigned spaceNo, int range,
1095// unsigned index, const char *name,
1096// unsigned counterOrderId) {
1097// Resource<T> tmp;
1098// tmp.__handle = __builtin_hlsl_resource_handlefrombinding(
1099// tmp.__handle, registerNo, spaceNo, range, index, name);
1100// tmp.__counter_handle =
1101// __builtin_hlsl_resource_counterhandlefromimplicitbinding(
1102// tmp.__handle, counterOrderId, spaceNo);
1103// return tmp;
1104// }
1105BuiltinTypeDeclBuilder &
1106BuiltinTypeDeclBuilder::addCreateFromBindingWithImplicitCounter() {
1107 assert(!Record->isCompleteDefinition() && "record is already complete");
1108
1109 using PH = BuiltinTypeMethodBuilder::PlaceHolder;
1110 ASTContext &AST = SemaRef.getASTContext();
1111 QualType HandleType = getResourceHandleField()->getType();
1112 QualType CounterHandleType = getResourceCounterHandleField()->getType();
1113 QualType RecordType = AST.getTypeDeclType(Decl: cast<TypeDecl>(Val: Record));
1114 BuiltinTypeMethodBuilder::LocalVar TmpVar("tmp", RecordType);
1115
1116 return BuiltinTypeMethodBuilder(*this,
1117 "__createFromBindingWithImplicitCounter",
1118 RecordType, false, false, SC_Static)
1119 .addParam(Name: "registerNo", Ty: AST.UnsignedIntTy)
1120 .addParam(Name: "spaceNo", Ty: AST.UnsignedIntTy)
1121 .addParam(Name: "range", Ty: AST.IntTy)
1122 .addParam(Name: "index", Ty: AST.UnsignedIntTy)
1123 .addParam(Name: "name", Ty: AST.getPointerType(T: AST.CharTy.withConst()))
1124 .addParam(Name: "counterOrderId", Ty: AST.UnsignedIntTy)
1125 .declareLocalVar(Var&: TmpVar)
1126 .accessHandleFieldOnResource(ResourceRecord: TmpVar)
1127 .callBuiltin(BuiltinName: "__builtin_hlsl_resource_handlefrombinding", ReturnType: HandleType,
1128 ArgSpecs: PH::LastStmt, ArgSpecs: PH::_0, ArgSpecs: PH::_1, ArgSpecs: PH::_2, ArgSpecs: PH::_3, ArgSpecs: PH::_4)
1129 .setHandleFieldOnResource(ResourceRecord: TmpVar, HandleValue: PH::LastStmt)
1130 .accessHandleFieldOnResource(ResourceRecord: TmpVar)
1131 .callBuiltin(BuiltinName: "__builtin_hlsl_resource_counterhandlefromimplicitbinding",
1132 ReturnType: CounterHandleType, ArgSpecs: PH::LastStmt, ArgSpecs: PH::_5, ArgSpecs: PH::_1)
1133 .setCounterHandleFieldOnResource(ResourceRecord: TmpVar, HandleValue: PH::LastStmt)
1134 .returnValue(ReturnValue: TmpVar)
1135 .finalize();
1136}
1137
1138// Adds static method that initializes resource from binding:
1139//
1140// static Resource<T>
1141// __createFromImplicitBindingWithImplicitCounter(unsigned orderId,
1142// unsigned spaceNo, int range,
1143// unsigned index,
1144// const char *name,
1145// unsigned counterOrderId) {
1146// Resource<T> tmp;
1147// tmp.__handle = __builtin_hlsl_resource_handlefromimplicitbinding(
1148// tmp.__handle, orderId, spaceNo, range, index, name);
1149// tmp.__counter_handle =
1150// __builtin_hlsl_resource_counterhandlefromimplicitbinding(
1151// tmp.__handle, counterOrderId, spaceNo);
1152// return tmp;
1153// }
1154BuiltinTypeDeclBuilder &
1155BuiltinTypeDeclBuilder::addCreateFromImplicitBindingWithImplicitCounter() {
1156 assert(!Record->isCompleteDefinition() && "record is already complete");
1157
1158 using PH = BuiltinTypeMethodBuilder::PlaceHolder;
1159 ASTContext &AST = SemaRef.getASTContext();
1160 QualType HandleType = getResourceHandleField()->getType();
1161 QualType CounterHandleType = getResourceCounterHandleField()->getType();
1162 QualType RecordType = AST.getTypeDeclType(Decl: cast<TypeDecl>(Val: Record));
1163 BuiltinTypeMethodBuilder::LocalVar TmpVar("tmp", RecordType);
1164
1165 return BuiltinTypeMethodBuilder(
1166 *this, "__createFromImplicitBindingWithImplicitCounter",
1167 RecordType, false, false, SC_Static)
1168 .addParam(Name: "orderId", Ty: AST.UnsignedIntTy)
1169 .addParam(Name: "spaceNo", Ty: AST.UnsignedIntTy)
1170 .addParam(Name: "range", Ty: AST.IntTy)
1171 .addParam(Name: "index", Ty: AST.UnsignedIntTy)
1172 .addParam(Name: "name", Ty: AST.getPointerType(T: AST.CharTy.withConst()))
1173 .addParam(Name: "counterOrderId", Ty: AST.UnsignedIntTy)
1174 .declareLocalVar(Var&: TmpVar)
1175 .accessHandleFieldOnResource(ResourceRecord: TmpVar)
1176 .callBuiltin(BuiltinName: "__builtin_hlsl_resource_handlefromimplicitbinding",
1177 ReturnType: HandleType, ArgSpecs: PH::LastStmt, ArgSpecs: PH::_0, ArgSpecs: PH::_1, ArgSpecs: PH::_2, ArgSpecs: PH::_3,
1178 ArgSpecs: PH::_4)
1179 .setHandleFieldOnResource(ResourceRecord: TmpVar, HandleValue: PH::LastStmt)
1180 .accessHandleFieldOnResource(ResourceRecord: TmpVar)
1181 .callBuiltin(BuiltinName: "__builtin_hlsl_resource_counterhandlefromimplicitbinding",
1182 ReturnType: CounterHandleType, ArgSpecs: PH::LastStmt, ArgSpecs: PH::_5, ArgSpecs: PH::_1)
1183 .setCounterHandleFieldOnResource(ResourceRecord: TmpVar, HandleValue: PH::LastStmt)
1184 .returnValue(ReturnValue: TmpVar)
1185 .finalize();
1186}
1187
1188BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addCopyConstructor() {
1189 assert(!Record->isCompleteDefinition() && "record is already complete");
1190
1191 ASTContext &AST = SemaRef.getASTContext();
1192 QualType RecordType = AST.getCanonicalTagType(TD: Record);
1193 QualType ConstRecordType = RecordType.withConst();
1194 QualType ConstRecordRefType = AST.getLValueReferenceType(T: ConstRecordType);
1195
1196 using PH = BuiltinTypeMethodBuilder::PlaceHolder;
1197
1198 BuiltinTypeMethodBuilder MMB(*this, /*Name=*/"", AST.VoidTy,
1199 /*IsConst=*/false, /*IsCtor=*/true);
1200 MMB.addParam(Name: "other", Ty: ConstRecordRefType)
1201 .accessHandleFieldOnResource(ResourceRecord: PH::_0)
1202 .assign(LHS: PH::Handle, RHS: PH::LastStmt);
1203
1204 if (getResourceCounterHandleField())
1205 MMB.accessCounterHandleFieldOnResource(ResourceRecord: PH::_0).assign(LHS: PH::CounterHandle,
1206 RHS: PH::LastStmt);
1207
1208 return MMB.finalize();
1209}
1210
1211BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addCopyAssignmentOperator() {
1212 assert(!Record->isCompleteDefinition() && "record is already complete");
1213
1214 ASTContext &AST = SemaRef.getASTContext();
1215 QualType RecordType = AST.getCanonicalTagType(TD: Record);
1216 QualType ConstRecordType = RecordType.withConst();
1217 QualType ConstRecordRefType = AST.getLValueReferenceType(T: ConstRecordType);
1218 QualType RecordRefType = AST.getLValueReferenceType(T: RecordType);
1219
1220 using PH = BuiltinTypeMethodBuilder::PlaceHolder;
1221 DeclarationName Name = AST.DeclarationNames.getCXXOperatorName(Op: OO_Equal);
1222 BuiltinTypeMethodBuilder MMB(*this, Name, RecordRefType);
1223 MMB.addParam(Name: "other", Ty: ConstRecordRefType)
1224 .accessHandleFieldOnResource(ResourceRecord: PH::_0)
1225 .assign(LHS: PH::Handle, RHS: PH::LastStmt);
1226
1227 if (getResourceCounterHandleField())
1228 MMB.accessCounterHandleFieldOnResource(ResourceRecord: PH::_0).assign(LHS: PH::CounterHandle,
1229 RHS: PH::LastStmt);
1230
1231 return MMB.returnThis().finalize();
1232}
1233
1234BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addArraySubscriptOperators() {
1235 ASTContext &AST = Record->getASTContext();
1236 DeclarationName Subscript =
1237 AST.DeclarationNames.getCXXOperatorName(Op: OO_Subscript);
1238
1239 addHandleAccessFunction(Name&: Subscript, /*IsConst=*/true, /*IsRef=*/true);
1240 if (getResourceAttrs().ResourceClass == llvm::dxil::ResourceClass::UAV)
1241 addHandleAccessFunction(Name&: Subscript, /*IsConst=*/false, /*IsRef=*/true);
1242
1243 return *this;
1244}
1245
1246BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addLoadMethods() {
1247 assert(!Record->isCompleteDefinition() && "record is already complete");
1248
1249 ASTContext &AST = Record->getASTContext();
1250 IdentifierInfo &II = AST.Idents.get(Name: "Load", TokenCode: tok::TokenKind::identifier);
1251 DeclarationName Load(&II);
1252 // TODO: We also need versions with status for CheckAccessFullyMapped.
1253 addHandleAccessFunction(Name&: Load, /*IsConst=*/false, /*IsRef=*/false);
1254 addLoadWithStatusFunction(Name&: Load, /*IsConst=*/false);
1255
1256 return *this;
1257}
1258
1259BuiltinTypeDeclBuilder &
1260BuiltinTypeDeclBuilder::addTextureLoadMethods(ResourceDimension Dim) {
1261 assert(!Record->isCompleteDefinition() && "record is already complete");
1262 ASTContext &AST = Record->getASTContext();
1263 uint32_t VecSize = getResourceDimensions(Dim);
1264 QualType IntTy = AST.IntTy;
1265 QualType OffsetTy = AST.getExtVectorType(VectorType: IntTy, NumElts: VecSize);
1266 QualType LocationTy = AST.getExtVectorType(VectorType: IntTy, NumElts: VecSize + 1);
1267 QualType ReturnType = getHandleElementType();
1268
1269 using PH = BuiltinTypeMethodBuilder::PlaceHolder;
1270
1271 // T Load(int3 location)
1272 BuiltinTypeMethodBuilder(*this, "Load", ReturnType)
1273 .addParam(Name: "Location", Ty: LocationTy)
1274 .callBuiltin(BuiltinName: "__builtin_hlsl_resource_load_level", ReturnType, ArgSpecs: PH::Handle,
1275 ArgSpecs: PH::_0)
1276 .finalize();
1277
1278 // T Load(int3 location, int2 offset)
1279 return BuiltinTypeMethodBuilder(*this, "Load", ReturnType)
1280 .addParam(Name: "Location", Ty: LocationTy)
1281 .addParam(Name: "Offset", Ty: OffsetTy)
1282 .callBuiltin(BuiltinName: "__builtin_hlsl_resource_load_level", ReturnType, ArgSpecs: PH::Handle,
1283 ArgSpecs: PH::_0, ArgSpecs: PH::_1)
1284 .finalize();
1285}
1286
1287BuiltinTypeDeclBuilder &
1288BuiltinTypeDeclBuilder::addByteAddressBufferLoadMethods() {
1289 assert(!Record->isCompleteDefinition() && "record is already complete");
1290
1291 ASTContext &AST = SemaRef.getASTContext();
1292
1293 auto AddLoads = [&](StringRef MethodName, QualType ReturnType) {
1294 IdentifierInfo &II = AST.Idents.get(Name: MethodName, TokenCode: tok::TokenKind::identifier);
1295 DeclarationName Load(&II);
1296
1297 addHandleAccessFunction(Name&: Load, /*IsConst=*/false, /*IsRef=*/false,
1298 ElemTy: ReturnType);
1299 addLoadWithStatusFunction(Name&: Load, /*IsConst=*/false, ReturnTy: ReturnType);
1300 };
1301
1302 AddLoads("Load", AST.UnsignedIntTy);
1303 AddLoads("Load2", AST.getExtVectorType(VectorType: AST.UnsignedIntTy, NumElts: 2));
1304 AddLoads("Load3", AST.getExtVectorType(VectorType: AST.UnsignedIntTy, NumElts: 3));
1305 AddLoads("Load4", AST.getExtVectorType(VectorType: AST.UnsignedIntTy, NumElts: 4));
1306 AddLoads("Load", AST.DependentTy); // Templated version
1307 return *this;
1308}
1309
1310BuiltinTypeDeclBuilder &
1311BuiltinTypeDeclBuilder::addByteAddressBufferStoreMethods() {
1312 assert(!Record->isCompleteDefinition() && "record is already complete");
1313
1314 ASTContext &AST = SemaRef.getASTContext();
1315
1316 auto AddStore = [&](StringRef MethodName, QualType ValueType) {
1317 IdentifierInfo &II = AST.Idents.get(Name: MethodName, TokenCode: tok::TokenKind::identifier);
1318 DeclarationName Store(&II);
1319
1320 addStoreFunction(Name&: Store, /*IsConst=*/false, ValueType);
1321 };
1322
1323 AddStore("Store", AST.UnsignedIntTy);
1324 AddStore("Store2", AST.getExtVectorType(VectorType: AST.UnsignedIntTy, NumElts: 2));
1325 AddStore("Store3", AST.getExtVectorType(VectorType: AST.UnsignedIntTy, NumElts: 3));
1326 AddStore("Store4", AST.getExtVectorType(VectorType: AST.UnsignedIntTy, NumElts: 4));
1327 AddStore("Store", AST.DependentTy); // Templated version
1328
1329 return *this;
1330}
1331
1332BuiltinTypeDeclBuilder &
1333BuiltinTypeDeclBuilder::addSampleMethods(ResourceDimension Dim) {
1334 assert(!Record->isCompleteDefinition() && "record is already complete");
1335 ASTContext &AST = Record->getASTContext();
1336 QualType ReturnType = getHandleElementType();
1337 QualType SamplerStateType =
1338 lookupBuiltinType(S&: SemaRef, Name: "SamplerState", DC: Record->getDeclContext());
1339 uint32_t VecSize = getResourceDimensions(Dim);
1340 QualType FloatTy = AST.FloatTy;
1341 QualType Float2Ty = AST.getExtVectorType(VectorType: FloatTy, NumElts: VecSize);
1342 QualType IntTy = AST.IntTy;
1343 QualType Int2Ty = AST.getExtVectorType(VectorType: IntTy, NumElts: VecSize);
1344 using PH = BuiltinTypeMethodBuilder::PlaceHolder;
1345
1346 // T Sample(SamplerState s, float2 location)
1347 BuiltinTypeMethodBuilder(*this, "Sample", ReturnType)
1348 .addParam(Name: "Sampler", Ty: SamplerStateType)
1349 .addParam(Name: "Location", Ty: Float2Ty)
1350 .accessHandleFieldOnResource(ResourceRecord: PH::_0)
1351 .callBuiltin(BuiltinName: "__builtin_hlsl_resource_sample", ReturnType, ArgSpecs: PH::Handle,
1352 ArgSpecs: PH::LastStmt, ArgSpecs: PH::_1)
1353 .returnValue(ReturnValue: PH::LastStmt)
1354 .finalize();
1355
1356 // T Sample(SamplerState s, float2 location, int2 offset)
1357 BuiltinTypeMethodBuilder(*this, "Sample", ReturnType)
1358 .addParam(Name: "Sampler", Ty: SamplerStateType)
1359 .addParam(Name: "Location", Ty: Float2Ty)
1360 .addParam(Name: "Offset", Ty: Int2Ty)
1361 .accessHandleFieldOnResource(ResourceRecord: PH::_0)
1362 .callBuiltin(BuiltinName: "__builtin_hlsl_resource_sample", ReturnType, ArgSpecs: PH::Handle,
1363 ArgSpecs: PH::LastStmt, ArgSpecs: PH::_1, ArgSpecs: PH::_2)
1364 .returnValue(ReturnValue: PH::LastStmt)
1365 .finalize();
1366
1367 // T Sample(SamplerState s, float2 location, int2 offset, float clamp)
1368 return BuiltinTypeMethodBuilder(*this, "Sample", ReturnType)
1369 .addParam(Name: "Sampler", Ty: SamplerStateType)
1370 .addParam(Name: "Location", Ty: Float2Ty)
1371 .addParam(Name: "Offset", Ty: Int2Ty)
1372 .addParam(Name: "Clamp", Ty: FloatTy)
1373 .accessHandleFieldOnResource(ResourceRecord: PH::_0)
1374 .callBuiltin(BuiltinName: "__builtin_hlsl_resource_sample", ReturnType, ArgSpecs: PH::Handle,
1375 ArgSpecs: PH::LastStmt, ArgSpecs: PH::_1, ArgSpecs: PH::_2, ArgSpecs: PH::_3)
1376 .returnValue(ReturnValue: PH::LastStmt)
1377 .finalize();
1378}
1379
1380BuiltinTypeDeclBuilder &
1381BuiltinTypeDeclBuilder::addSampleBiasMethods(ResourceDimension Dim) {
1382 assert(!Record->isCompleteDefinition() && "record is already complete");
1383 ASTContext &AST = Record->getASTContext();
1384 QualType ReturnType = getHandleElementType();
1385 QualType SamplerStateType =
1386 lookupBuiltinType(S&: SemaRef, Name: "SamplerState", DC: Record->getDeclContext());
1387 uint32_t VecSize = getResourceDimensions(Dim);
1388 QualType FloatTy = AST.FloatTy;
1389 QualType Float2Ty = AST.getExtVectorType(VectorType: FloatTy, NumElts: VecSize);
1390 QualType IntTy = AST.IntTy;
1391 QualType Int2Ty = AST.getExtVectorType(VectorType: IntTy, NumElts: VecSize);
1392 using PH = BuiltinTypeMethodBuilder::PlaceHolder;
1393
1394 // T SampleBias(SamplerState s, float2 location, float bias)
1395 BuiltinTypeMethodBuilder(*this, "SampleBias", ReturnType)
1396 .addParam(Name: "Sampler", Ty: SamplerStateType)
1397 .addParam(Name: "Location", Ty: Float2Ty)
1398 .addParam(Name: "Bias", Ty: FloatTy)
1399 .accessHandleFieldOnResource(ResourceRecord: PH::_0)
1400 .callBuiltin(BuiltinName: "__builtin_hlsl_resource_sample_bias", ReturnType,
1401 ArgSpecs: PH::Handle, ArgSpecs: PH::LastStmt, ArgSpecs: PH::_1, ArgSpecs: PH::_2)
1402 .returnValue(ReturnValue: PH::LastStmt)
1403 .finalize();
1404
1405 // T SampleBias(SamplerState s, float2 location, float bias, int2 offset)
1406 BuiltinTypeMethodBuilder(*this, "SampleBias", ReturnType)
1407 .addParam(Name: "Sampler", Ty: SamplerStateType)
1408 .addParam(Name: "Location", Ty: Float2Ty)
1409 .addParam(Name: "Bias", Ty: FloatTy)
1410 .addParam(Name: "Offset", Ty: Int2Ty)
1411 .accessHandleFieldOnResource(ResourceRecord: PH::_0)
1412 .callBuiltin(BuiltinName: "__builtin_hlsl_resource_sample_bias", ReturnType,
1413 ArgSpecs: PH::Handle, ArgSpecs: PH::LastStmt, ArgSpecs: PH::_1, ArgSpecs: PH::_2, ArgSpecs: PH::_3)
1414 .returnValue(ReturnValue: PH::LastStmt)
1415 .finalize();
1416
1417 // T SampleBias(SamplerState s, float2 location, float bias, int2 offset,
1418 // float clamp)
1419 return BuiltinTypeMethodBuilder(*this, "SampleBias", ReturnType)
1420 .addParam(Name: "Sampler", Ty: SamplerStateType)
1421 .addParam(Name: "Location", Ty: Float2Ty)
1422 .addParam(Name: "Bias", Ty: FloatTy)
1423 .addParam(Name: "Offset", Ty: Int2Ty)
1424 .addParam(Name: "Clamp", Ty: FloatTy)
1425 .accessHandleFieldOnResource(ResourceRecord: PH::_0)
1426 .callBuiltin(BuiltinName: "__builtin_hlsl_resource_sample_bias", ReturnType,
1427 ArgSpecs: PH::Handle, ArgSpecs: PH::LastStmt, ArgSpecs: PH::_1, ArgSpecs: PH::_2, ArgSpecs: PH::_3, ArgSpecs: PH::_4)
1428 .returnValue(ReturnValue: PH::LastStmt)
1429 .finalize();
1430}
1431
1432BuiltinTypeDeclBuilder &
1433BuiltinTypeDeclBuilder::addSampleGradMethods(ResourceDimension Dim) {
1434 assert(!Record->isCompleteDefinition() && "record is already complete");
1435 ASTContext &AST = Record->getASTContext();
1436 QualType ReturnType = getHandleElementType();
1437 QualType SamplerStateType =
1438 lookupBuiltinType(S&: SemaRef, Name: "SamplerState", DC: Record->getDeclContext());
1439 uint32_t VecSize = getResourceDimensions(Dim);
1440 QualType FloatTy = AST.FloatTy;
1441 QualType Float2Ty = AST.getExtVectorType(VectorType: FloatTy, NumElts: VecSize);
1442 QualType IntTy = AST.IntTy;
1443 QualType Int2Ty = AST.getExtVectorType(VectorType: IntTy, NumElts: VecSize);
1444 using PH = BuiltinTypeMethodBuilder::PlaceHolder;
1445
1446 // T SampleGrad(SamplerState s, float2 location, float2 ddx, float2 ddy)
1447 BuiltinTypeMethodBuilder(*this, "SampleGrad", ReturnType)
1448 .addParam(Name: "Sampler", Ty: SamplerStateType)
1449 .addParam(Name: "Location", Ty: Float2Ty)
1450 .addParam(Name: "DDX", Ty: Float2Ty)
1451 .addParam(Name: "DDY", Ty: Float2Ty)
1452 .accessHandleFieldOnResource(ResourceRecord: PH::_0)
1453 .callBuiltin(BuiltinName: "__builtin_hlsl_resource_sample_grad", ReturnType,
1454 ArgSpecs: PH::Handle, ArgSpecs: PH::LastStmt, ArgSpecs: PH::_1, ArgSpecs: PH::_2, ArgSpecs: PH::_3)
1455 .returnValue(ReturnValue: PH::LastStmt)
1456 .finalize();
1457
1458 // T SampleGrad(SamplerState s, float2 location, float2 ddx, float2 ddy,
1459 // int2 offset)
1460 BuiltinTypeMethodBuilder(*this, "SampleGrad", ReturnType)
1461 .addParam(Name: "Sampler", Ty: SamplerStateType)
1462 .addParam(Name: "Location", Ty: Float2Ty)
1463 .addParam(Name: "DDX", Ty: Float2Ty)
1464 .addParam(Name: "DDY", Ty: Float2Ty)
1465 .addParam(Name: "Offset", Ty: Int2Ty)
1466 .accessHandleFieldOnResource(ResourceRecord: PH::_0)
1467 .callBuiltin(BuiltinName: "__builtin_hlsl_resource_sample_grad", ReturnType,
1468 ArgSpecs: PH::Handle, ArgSpecs: PH::LastStmt, ArgSpecs: PH::_1, ArgSpecs: PH::_2, ArgSpecs: PH::_3, ArgSpecs: PH::_4)
1469 .returnValue(ReturnValue: PH::LastStmt)
1470 .finalize();
1471
1472 // T SampleGrad(SamplerState s, float2 location, float2 ddx, float2 ddy,
1473 // int2 offset, float clamp)
1474 return BuiltinTypeMethodBuilder(*this, "SampleGrad", ReturnType)
1475 .addParam(Name: "Sampler", Ty: SamplerStateType)
1476 .addParam(Name: "Location", Ty: Float2Ty)
1477 .addParam(Name: "DDX", Ty: Float2Ty)
1478 .addParam(Name: "DDY", Ty: Float2Ty)
1479 .addParam(Name: "Offset", Ty: Int2Ty)
1480 .addParam(Name: "Clamp", Ty: FloatTy)
1481 .accessHandleFieldOnResource(ResourceRecord: PH::_0)
1482 .callBuiltin(BuiltinName: "__builtin_hlsl_resource_sample_grad", ReturnType,
1483 ArgSpecs: PH::Handle, ArgSpecs: PH::LastStmt, ArgSpecs: PH::_1, ArgSpecs: PH::_2, ArgSpecs: PH::_3, ArgSpecs: PH::_4,
1484 ArgSpecs: PH::_5)
1485 .returnValue(ReturnValue: PH::LastStmt)
1486 .finalize();
1487}
1488
1489BuiltinTypeDeclBuilder &
1490BuiltinTypeDeclBuilder::addSampleLevelMethods(ResourceDimension Dim) {
1491 assert(!Record->isCompleteDefinition() && "record is already complete");
1492 ASTContext &AST = Record->getASTContext();
1493 QualType ReturnType = getHandleElementType();
1494 QualType SamplerStateType =
1495 lookupBuiltinType(S&: SemaRef, Name: "SamplerState", DC: Record->getDeclContext());
1496 uint32_t VecSize = getResourceDimensions(Dim);
1497 QualType FloatTy = AST.FloatTy;
1498 QualType Float2Ty = AST.getExtVectorType(VectorType: FloatTy, NumElts: VecSize);
1499 QualType IntTy = AST.IntTy;
1500 QualType Int2Ty = AST.getExtVectorType(VectorType: IntTy, NumElts: VecSize);
1501 using PH = BuiltinTypeMethodBuilder::PlaceHolder;
1502
1503 // T SampleLevel(SamplerState s, float2 location, float lod)
1504 BuiltinTypeMethodBuilder(*this, "SampleLevel", ReturnType)
1505 .addParam(Name: "Sampler", Ty: SamplerStateType)
1506 .addParam(Name: "Location", Ty: Float2Ty)
1507 .addParam(Name: "LOD", Ty: FloatTy)
1508 .accessHandleFieldOnResource(ResourceRecord: PH::_0)
1509 .callBuiltin(BuiltinName: "__builtin_hlsl_resource_sample_level", ReturnType,
1510 ArgSpecs: PH::Handle, ArgSpecs: PH::LastStmt, ArgSpecs: PH::_1, ArgSpecs: PH::_2)
1511 .returnValue(ReturnValue: PH::LastStmt)
1512 .finalize();
1513
1514 // T SampleLevel(SamplerState s, float2 location, float lod, int2 offset)
1515 return BuiltinTypeMethodBuilder(*this, "SampleLevel", ReturnType)
1516 .addParam(Name: "Sampler", Ty: SamplerStateType)
1517 .addParam(Name: "Location", Ty: Float2Ty)
1518 .addParam(Name: "LOD", Ty: FloatTy)
1519 .addParam(Name: "Offset", Ty: Int2Ty)
1520 .accessHandleFieldOnResource(ResourceRecord: PH::_0)
1521 .callBuiltin(BuiltinName: "__builtin_hlsl_resource_sample_level", ReturnType,
1522 ArgSpecs: PH::Handle, ArgSpecs: PH::LastStmt, ArgSpecs: PH::_1, ArgSpecs: PH::_2, ArgSpecs: PH::_3)
1523 .returnValue(ReturnValue: PH::LastStmt)
1524 .finalize();
1525}
1526
1527BuiltinTypeDeclBuilder &
1528BuiltinTypeDeclBuilder::addSampleCmpMethods(ResourceDimension Dim) {
1529 assert(!Record->isCompleteDefinition() && "record is already complete");
1530 ASTContext &AST = Record->getASTContext();
1531 QualType ReturnType = AST.FloatTy;
1532 QualType SamplerComparisonStateType = lookupBuiltinType(
1533 S&: SemaRef, Name: "SamplerComparisonState", DC: Record->getDeclContext());
1534 uint32_t VecSize = getResourceDimensions(Dim);
1535 QualType FloatTy = AST.FloatTy;
1536 QualType Float2Ty = AST.getExtVectorType(VectorType: FloatTy, NumElts: VecSize);
1537 QualType IntTy = AST.IntTy;
1538 QualType Int2Ty = AST.getExtVectorType(VectorType: IntTy, NumElts: VecSize);
1539 using PH = BuiltinTypeMethodBuilder::PlaceHolder;
1540
1541 // T SampleCmp(SamplerComparisonState s, float2 location, float compare_value)
1542 BuiltinTypeMethodBuilder(*this, "SampleCmp", ReturnType)
1543 .addParam(Name: "Sampler", Ty: SamplerComparisonStateType)
1544 .addParam(Name: "Location", Ty: Float2Ty)
1545 .addParam(Name: "CompareValue", Ty: FloatTy)
1546 .accessHandleFieldOnResource(ResourceRecord: PH::_0)
1547 .callBuiltin(BuiltinName: "__builtin_hlsl_resource_sample_cmp", ReturnType, ArgSpecs: PH::Handle,
1548 ArgSpecs: PH::LastStmt, ArgSpecs: PH::_1, ArgSpecs: PH::_2)
1549 .returnValue(ReturnValue: PH::LastStmt)
1550 .finalize();
1551
1552 // T SampleCmp(SamplerComparisonState s, float2 location, float compare_value,
1553 // int2 offset)
1554 BuiltinTypeMethodBuilder(*this, "SampleCmp", ReturnType)
1555 .addParam(Name: "Sampler", Ty: SamplerComparisonStateType)
1556 .addParam(Name: "Location", Ty: Float2Ty)
1557 .addParam(Name: "CompareValue", Ty: FloatTy)
1558 .addParam(Name: "Offset", Ty: Int2Ty)
1559 .accessHandleFieldOnResource(ResourceRecord: PH::_0)
1560 .callBuiltin(BuiltinName: "__builtin_hlsl_resource_sample_cmp", ReturnType, ArgSpecs: PH::Handle,
1561 ArgSpecs: PH::LastStmt, ArgSpecs: PH::_1, ArgSpecs: PH::_2, ArgSpecs: PH::_3)
1562 .returnValue(ReturnValue: PH::LastStmt)
1563 .finalize();
1564
1565 // T SampleCmp(SamplerComparisonState s, float2 location, float compare_value,
1566 // int2 offset, float clamp)
1567 return BuiltinTypeMethodBuilder(*this, "SampleCmp", ReturnType)
1568 .addParam(Name: "Sampler", Ty: SamplerComparisonStateType)
1569 .addParam(Name: "Location", Ty: Float2Ty)
1570 .addParam(Name: "CompareValue", Ty: FloatTy)
1571 .addParam(Name: "Offset", Ty: Int2Ty)
1572 .addParam(Name: "Clamp", Ty: FloatTy)
1573 .accessHandleFieldOnResource(ResourceRecord: PH::_0)
1574 .callBuiltin(BuiltinName: "__builtin_hlsl_resource_sample_cmp", ReturnType, ArgSpecs: PH::Handle,
1575 ArgSpecs: PH::LastStmt, ArgSpecs: PH::_1, ArgSpecs: PH::_2, ArgSpecs: PH::_3, ArgSpecs: PH::_4)
1576 .returnValue(ReturnValue: PH::LastStmt)
1577 .finalize();
1578}
1579
1580BuiltinTypeDeclBuilder &
1581BuiltinTypeDeclBuilder::addSampleCmpLevelZeroMethods(ResourceDimension Dim) {
1582 assert(!Record->isCompleteDefinition() && "record is already complete");
1583 ASTContext &AST = Record->getASTContext();
1584 QualType ReturnType = AST.FloatTy;
1585 QualType SamplerComparisonStateType = lookupBuiltinType(
1586 S&: SemaRef, Name: "SamplerComparisonState", DC: Record->getDeclContext());
1587 uint32_t VecSize = getResourceDimensions(Dim);
1588 QualType FloatTy = AST.FloatTy;
1589 QualType Float2Ty = AST.getExtVectorType(VectorType: FloatTy, NumElts: VecSize);
1590 QualType IntTy = AST.IntTy;
1591 QualType Int2Ty = AST.getExtVectorType(VectorType: IntTy, NumElts: VecSize);
1592 using PH = BuiltinTypeMethodBuilder::PlaceHolder;
1593
1594 // T SampleCmpLevelZero(SamplerComparisonState s, float2 location, float
1595 // compare_value)
1596 BuiltinTypeMethodBuilder(*this, "SampleCmpLevelZero", ReturnType)
1597 .addParam(Name: "Sampler", Ty: SamplerComparisonStateType)
1598 .addParam(Name: "Location", Ty: Float2Ty)
1599 .addParam(Name: "CompareValue", Ty: FloatTy)
1600 .accessHandleFieldOnResource(ResourceRecord: PH::_0)
1601 .callBuiltin(BuiltinName: "__builtin_hlsl_resource_sample_cmp_level_zero", ReturnType,
1602 ArgSpecs: PH::Handle, ArgSpecs: PH::LastStmt, ArgSpecs: PH::_1, ArgSpecs: PH::_2)
1603 .returnValue(ReturnValue: PH::LastStmt)
1604 .finalize();
1605
1606 // T SampleCmpLevelZero(SamplerComparisonState s, float2 location, float
1607 // compare_value, int2 offset)
1608 return BuiltinTypeMethodBuilder(*this, "SampleCmpLevelZero", ReturnType)
1609 .addParam(Name: "Sampler", Ty: SamplerComparisonStateType)
1610 .addParam(Name: "Location", Ty: Float2Ty)
1611 .addParam(Name: "CompareValue", Ty: FloatTy)
1612 .addParam(Name: "Offset", Ty: Int2Ty)
1613 .accessHandleFieldOnResource(ResourceRecord: PH::_0)
1614 .callBuiltin(BuiltinName: "__builtin_hlsl_resource_sample_cmp_level_zero", ReturnType,
1615 ArgSpecs: PH::Handle, ArgSpecs: PH::LastStmt, ArgSpecs: PH::_1, ArgSpecs: PH::_2, ArgSpecs: PH::_3)
1616 .returnValue(ReturnValue: PH::LastStmt)
1617 .finalize();
1618}
1619
1620QualType BuiltinTypeDeclBuilder::getGatherReturnType() {
1621 ASTContext &AST = SemaRef.getASTContext();
1622 QualType T = getHandleElementType();
1623 if (T.isNull())
1624 return QualType();
1625
1626 if (const auto *VT = T->getAs<VectorType>())
1627 T = VT->getElementType();
1628 else if (const auto *DT = T->getAs<DependentSizedExtVectorType>())
1629 T = DT->getElementType();
1630
1631 return AST.getExtVectorType(VectorType: T, NumElts: 4);
1632}
1633
1634BuiltinTypeDeclBuilder &
1635BuiltinTypeDeclBuilder::addGatherMethods(ResourceDimension Dim) {
1636 assert(!Record->isCompleteDefinition() && "record is already complete");
1637 ASTContext &AST = Record->getASTContext();
1638 QualType ReturnType = getGatherReturnType();
1639
1640 QualType SamplerStateType =
1641 lookupBuiltinType(S&: SemaRef, Name: "SamplerState", DC: Record->getDeclContext());
1642 uint32_t VecSize = getResourceDimensions(Dim);
1643 QualType LocationTy = AST.FloatTy;
1644 QualType Float2Ty = AST.getExtVectorType(VectorType: LocationTy, NumElts: VecSize);
1645 QualType IntTy = AST.IntTy;
1646 QualType OffsetTy = AST.getExtVectorType(VectorType: IntTy, NumElts: VecSize);
1647 using PH = BuiltinTypeMethodBuilder::PlaceHolder;
1648
1649 // Overloads for Gather, GatherRed, GatherGreen, GatherBlue, GatherAlpha
1650 struct GatherVariant {
1651 const char *Name;
1652 int Component;
1653 };
1654 GatherVariant Variants[] = {{.Name: "Gather", .Component: 0},
1655 {.Name: "GatherRed", .Component: 0},
1656 {.Name: "GatherGreen", .Component: 1},
1657 {.Name: "GatherBlue", .Component: 2},
1658 {.Name: "GatherAlpha", .Component: 3}};
1659
1660 for (const auto &V : Variants) {
1661 // ret GatherVariant(SamplerState s, float2 location)
1662 BuiltinTypeMethodBuilder(*this, V.Name, ReturnType)
1663 .addParam(Name: "Sampler", Ty: SamplerStateType)
1664 .addParam(Name: "Location", Ty: Float2Ty)
1665 .accessHandleFieldOnResource(ResourceRecord: PH::_0)
1666 .callBuiltin(BuiltinName: "__builtin_hlsl_resource_gather", ReturnType, ArgSpecs: PH::Handle,
1667 ArgSpecs: PH::LastStmt, ArgSpecs: PH::_1,
1668 ArgSpecs: getConstantUnsignedIntExpr(value: V.Component))
1669 .finalize();
1670
1671 // ret GatherVariant(SamplerState s, float2 location, int2 offset)
1672 BuiltinTypeMethodBuilder(*this, V.Name, ReturnType)
1673 .addParam(Name: "Sampler", Ty: SamplerStateType)
1674 .addParam(Name: "Location", Ty: Float2Ty)
1675 .addParam(Name: "Offset", Ty: OffsetTy)
1676 .accessHandleFieldOnResource(ResourceRecord: PH::_0)
1677 .callBuiltin(BuiltinName: "__builtin_hlsl_resource_gather", ReturnType, ArgSpecs: PH::Handle,
1678 ArgSpecs: PH::LastStmt, ArgSpecs: PH::_1,
1679 ArgSpecs: getConstantUnsignedIntExpr(value: V.Component), ArgSpecs: PH::_2)
1680 .finalize();
1681 }
1682
1683 return *this;
1684}
1685
1686BuiltinTypeDeclBuilder &
1687BuiltinTypeDeclBuilder::addGatherCmpMethods(ResourceDimension Dim) {
1688 assert(!Record->isCompleteDefinition() && "record is already complete");
1689 ASTContext &AST = Record->getASTContext();
1690 QualType ReturnType = AST.getExtVectorType(VectorType: AST.FloatTy, NumElts: 4);
1691
1692 QualType SamplerComparisonStateType = lookupBuiltinType(
1693 S&: SemaRef, Name: "SamplerComparisonState", DC: Record->getDeclContext());
1694 uint32_t VecSize = getResourceDimensions(Dim);
1695 QualType FloatTy = AST.FloatTy;
1696 QualType Float2Ty = AST.getExtVectorType(VectorType: FloatTy, NumElts: VecSize);
1697 QualType IntTy = AST.IntTy;
1698 QualType Int2Ty = AST.getExtVectorType(VectorType: IntTy, NumElts: VecSize);
1699 using PH = BuiltinTypeMethodBuilder::PlaceHolder;
1700
1701 // Overloads for GatherCmp, GatherCmpRed, GatherCmpGreen, GatherCmpBlue,
1702 // GatherCmpAlpha
1703 struct GatherVariant {
1704 const char *Name;
1705 int Component;
1706 };
1707 GatherVariant Variants[] = {{.Name: "GatherCmp", .Component: 0},
1708 {.Name: "GatherCmpRed", .Component: 0},
1709 {.Name: "GatherCmpGreen", .Component: 1},
1710 {.Name: "GatherCmpBlue", .Component: 2},
1711 {.Name: "GatherCmpAlpha", .Component: 3}};
1712
1713 for (const auto &V : Variants) {
1714 // ret GatherCmpVariant(SamplerComparisonState s, float2 location, float
1715 // compare_value)
1716 BuiltinTypeMethodBuilder(*this, V.Name, ReturnType)
1717 .addParam(Name: "Sampler", Ty: SamplerComparisonStateType)
1718 .addParam(Name: "Location", Ty: Float2Ty)
1719 .addParam(Name: "CompareValue", Ty: FloatTy)
1720 .accessHandleFieldOnResource(ResourceRecord: PH::_0)
1721 .callBuiltin(BuiltinName: "__builtin_hlsl_resource_gather_cmp", ReturnType,
1722 ArgSpecs: PH::Handle, ArgSpecs: PH::LastStmt, ArgSpecs: PH::_1, ArgSpecs: PH::_2,
1723 ArgSpecs: getConstantUnsignedIntExpr(value: V.Component))
1724 .finalize();
1725
1726 // ret GatherCmpVariant(SamplerComparisonState s, float2 location, float
1727 // compare_value, int2 offset)
1728 BuiltinTypeMethodBuilder(*this, V.Name, ReturnType)
1729 .addParam(Name: "Sampler", Ty: SamplerComparisonStateType)
1730 .addParam(Name: "Location", Ty: Float2Ty)
1731 .addParam(Name: "CompareValue", Ty: FloatTy)
1732 .addParam(Name: "Offset", Ty: Int2Ty)
1733 .accessHandleFieldOnResource(ResourceRecord: PH::_0)
1734 .callBuiltin(BuiltinName: "__builtin_hlsl_resource_gather_cmp", ReturnType,
1735 ArgSpecs: PH::Handle, ArgSpecs: PH::LastStmt, ArgSpecs: PH::_1, ArgSpecs: PH::_2,
1736 ArgSpecs: getConstantUnsignedIntExpr(value: V.Component), ArgSpecs: PH::_3)
1737 .finalize();
1738 }
1739
1740 return *this;
1741}
1742
1743FieldDecl *BuiltinTypeDeclBuilder::getResourceHandleField() const {
1744 auto I = Fields.find(Key: "__handle");
1745 assert(I != Fields.end() &&
1746 I->second->getType()->isHLSLAttributedResourceType() &&
1747 "record does not have resource handle field");
1748 return I->second;
1749}
1750
1751FieldDecl *BuiltinTypeDeclBuilder::getResourceCounterHandleField() const {
1752 auto I = Fields.find(Key: "__counter_handle");
1753 if (I == Fields.end() ||
1754 !I->second->getType()->isHLSLAttributedResourceType())
1755 return nullptr;
1756 return I->second;
1757}
1758
1759QualType BuiltinTypeDeclBuilder::getFirstTemplateTypeParam() {
1760 assert(Template && "record it not a template");
1761 if (const auto *TTD = dyn_cast<TemplateTypeParmDecl>(
1762 Val: Template->getTemplateParameters()->getParam(Idx: 0))) {
1763 return QualType(TTD->getTypeForDecl(), 0);
1764 }
1765 return QualType();
1766}
1767
1768QualType BuiltinTypeDeclBuilder::getHandleElementType() {
1769 if (Template)
1770 return getFirstTemplateTypeParam();
1771
1772 if (auto *Spec = dyn_cast<ClassTemplateSpecializationDecl>(Val: Record)) {
1773 const auto &Args = Spec->getTemplateArgs();
1774 if (Args.size() > 0 && Args[0].getKind() == TemplateArgument::Type)
1775 return Args[0].getAsType();
1776 }
1777
1778 // TODO: Should we default to VoidTy? Using `i8` is arguably ambiguous.
1779 return SemaRef.getASTContext().Char8Ty;
1780}
1781
1782HLSLAttributedResourceType::Attributes
1783BuiltinTypeDeclBuilder::getResourceAttrs() const {
1784 QualType HandleType = getResourceHandleField()->getType();
1785 return cast<HLSLAttributedResourceType>(Val&: HandleType)->getAttrs();
1786}
1787
1788BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::completeDefinition() {
1789 assert(!Record->isCompleteDefinition() && "record is already complete");
1790 assert(Record->isBeingDefined() &&
1791 "Definition must be started before completing it.");
1792
1793 Record->completeDefinition();
1794 return *this;
1795}
1796
1797Expr *BuiltinTypeDeclBuilder::getConstantIntExpr(int value) {
1798 ASTContext &AST = SemaRef.getASTContext();
1799 return IntegerLiteral::Create(
1800 C: AST, V: llvm::APInt(AST.getTypeSize(T: AST.IntTy), value, true), type: AST.IntTy,
1801 l: SourceLocation());
1802}
1803
1804Expr *BuiltinTypeDeclBuilder::getConstantUnsignedIntExpr(unsigned value) {
1805 ASTContext &AST = SemaRef.getASTContext();
1806 return IntegerLiteral::Create(
1807 C: AST, V: llvm::APInt(AST.getTypeSize(T: AST.UnsignedIntTy), value),
1808 type: AST.UnsignedIntTy, l: SourceLocation());
1809}
1810
1811BuiltinTypeDeclBuilder &
1812BuiltinTypeDeclBuilder::addSimpleTemplateParams(ArrayRef<StringRef> Names,
1813 ConceptDecl *CD = nullptr) {
1814 return addSimpleTemplateParams(Names, DefaultTypes: {}, CD);
1815}
1816
1817BuiltinTypeDeclBuilder &
1818BuiltinTypeDeclBuilder::addSimpleTemplateParams(ArrayRef<StringRef> Names,
1819 ArrayRef<QualType> DefaultTypes,
1820 ConceptDecl *CD) {
1821 if (Record->isCompleteDefinition()) {
1822 assert(Template && "existing record it not a template");
1823 assert(Template->getTemplateParameters()->size() == Names.size() &&
1824 "template param count mismatch");
1825 return *this;
1826 }
1827
1828 assert((DefaultTypes.empty() || DefaultTypes.size() == Names.size()) &&
1829 "template default argument count mismatch");
1830
1831 TemplateParameterListBuilder Builder = TemplateParameterListBuilder(*this);
1832 for (unsigned i = 0; i < Names.size(); ++i) {
1833 QualType DefaultTy = DefaultTypes.empty() ? QualType() : DefaultTypes[i];
1834 Builder.addTypeParameter(Name: Names[i], DefaultValue: DefaultTy);
1835 }
1836 return Builder.finalizeTemplateArgs(CD);
1837}
1838
1839BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addIncrementCounterMethod() {
1840 using PH = BuiltinTypeMethodBuilder::PlaceHolder;
1841 QualType UnsignedIntTy = SemaRef.getASTContext().UnsignedIntTy;
1842 return BuiltinTypeMethodBuilder(*this, "IncrementCounter", UnsignedIntTy)
1843 .callBuiltin(BuiltinName: "__builtin_hlsl_buffer_update_counter", ReturnType: UnsignedIntTy,
1844 ArgSpecs: PH::CounterHandle, ArgSpecs: getConstantIntExpr(value: 1))
1845 .finalize();
1846}
1847
1848BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addDecrementCounterMethod() {
1849 using PH = BuiltinTypeMethodBuilder::PlaceHolder;
1850 QualType UnsignedIntTy = SemaRef.getASTContext().UnsignedIntTy;
1851 return BuiltinTypeMethodBuilder(*this, "DecrementCounter", UnsignedIntTy)
1852 .callBuiltin(BuiltinName: "__builtin_hlsl_buffer_update_counter", ReturnType: UnsignedIntTy,
1853 ArgSpecs: PH::CounterHandle, ArgSpecs: getConstantIntExpr(value: -1))
1854 .finalize();
1855}
1856
1857BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addLoadWithStatusFunction(
1858 DeclarationName &Name, bool IsConst, QualType ReturnTy) {
1859 assert(!Record->isCompleteDefinition() && "record is already complete");
1860 ASTContext &AST = SemaRef.getASTContext();
1861 using PH = BuiltinTypeMethodBuilder::PlaceHolder;
1862 bool NeedsTypedBuiltin = !ReturnTy.isNull();
1863
1864 // The empty QualType is a placeholder. The actual return type is set below.
1865 BuiltinTypeMethodBuilder MMB(*this, Name, QualType(), IsConst);
1866
1867 if (!NeedsTypedBuiltin)
1868 ReturnTy = getHandleElementType();
1869 if (ReturnTy == AST.DependentTy)
1870 ReturnTy = MMB.addTemplateTypeParam(Name: "element_type");
1871 MMB.ReturnTy = ReturnTy;
1872
1873 MMB.addParam(Name: "Index", Ty: AST.UnsignedIntTy)
1874 .addParam(Name: "Status", Ty: AST.UnsignedIntTy,
1875 Modifier: HLSLParamModifierAttr::Keyword_out);
1876
1877 if (NeedsTypedBuiltin)
1878 MMB.callBuiltin(BuiltinName: "__builtin_hlsl_resource_load_with_status_typed", ReturnType: ReturnTy,
1879 ArgSpecs: PH::Handle, ArgSpecs: PH::_0, ArgSpecs: PH::_1, ArgSpecs&: ReturnTy);
1880 else
1881 MMB.callBuiltin(BuiltinName: "__builtin_hlsl_resource_load_with_status", ReturnType: ReturnTy,
1882 ArgSpecs: PH::Handle, ArgSpecs: PH::_0, ArgSpecs: PH::_1);
1883
1884 return MMB.finalize();
1885}
1886
1887BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addHandleAccessFunction(
1888 DeclarationName &Name, bool IsConst, bool IsRef, QualType ElemTy) {
1889 assert(!Record->isCompleteDefinition() && "record is already complete");
1890 ASTContext &AST = SemaRef.getASTContext();
1891 using PH = BuiltinTypeMethodBuilder::PlaceHolder;
1892 bool NeedsTypedBuiltin = !ElemTy.isNull();
1893
1894 // The empty QualType is a placeholder. The actual return type is set below.
1895 BuiltinTypeMethodBuilder MMB(*this, Name, QualType(), IsConst);
1896
1897 if (!NeedsTypedBuiltin)
1898 ElemTy = getHandleElementType();
1899 if (ElemTy == AST.DependentTy)
1900 ElemTy = MMB.addTemplateTypeParam(Name: "element_type");
1901 QualType AddrSpaceElemTy =
1902 AST.getAddrSpaceQualType(T: ElemTy, AddressSpace: LangAS::hlsl_device);
1903 QualType ElemPtrTy = AST.getPointerType(T: AddrSpaceElemTy);
1904 QualType ReturnTy;
1905
1906 if (IsRef) {
1907 ReturnTy = AddrSpaceElemTy;
1908 if (IsConst)
1909 ReturnTy.addConst();
1910 ReturnTy = AST.getLValueReferenceType(T: ReturnTy);
1911 } else {
1912 ReturnTy = ElemTy;
1913 if (IsConst)
1914 ReturnTy.addConst();
1915 }
1916 MMB.ReturnTy = ReturnTy;
1917
1918 MMB.addParam(Name: "Index", Ty: AST.UnsignedIntTy);
1919
1920 if (NeedsTypedBuiltin)
1921 MMB.callBuiltin(BuiltinName: "__builtin_hlsl_resource_getpointer_typed", ReturnType: ElemPtrTy,
1922 ArgSpecs: PH::Handle, ArgSpecs: PH::_0, ArgSpecs&: ElemTy);
1923 else
1924 MMB.callBuiltin(BuiltinName: "__builtin_hlsl_resource_getpointer", ReturnType: ElemPtrTy, ArgSpecs: PH::Handle,
1925 ArgSpecs: PH::_0);
1926
1927 return MMB.dereference(Ptr: PH::LastStmt).finalize();
1928}
1929
1930BuiltinTypeDeclBuilder &
1931BuiltinTypeDeclBuilder::addStoreFunction(DeclarationName &Name, bool IsConst,
1932 QualType ValueTy) {
1933 assert(!Record->isCompleteDefinition() && "record is already complete");
1934 ASTContext &AST = SemaRef.getASTContext();
1935 using PH = BuiltinTypeMethodBuilder::PlaceHolder;
1936
1937 BuiltinTypeMethodBuilder MMB(*this, Name, AST.VoidTy, IsConst);
1938
1939 if (ValueTy == AST.DependentTy)
1940 ValueTy = MMB.addTemplateTypeParam(Name: "element_type");
1941 QualType AddrSpaceElemTy =
1942 AST.getAddrSpaceQualType(T: ValueTy, AddressSpace: LangAS::hlsl_device);
1943 QualType ElemPtrTy = AST.getPointerType(T: AddrSpaceElemTy);
1944
1945 return MMB.addParam(Name: "Index", Ty: AST.UnsignedIntTy)
1946 .addParam(Name: "Value", Ty: ValueTy)
1947 .callBuiltin(BuiltinName: "__builtin_hlsl_resource_getpointer_typed", ReturnType: ElemPtrTy,
1948 ArgSpecs: PH::Handle, ArgSpecs: PH::_0, ArgSpecs&: ValueTy)
1949 .dereference(Ptr: PH::LastStmt)
1950 .assign(LHS: PH::LastStmt, RHS: PH::_1)
1951 .finalize();
1952}
1953
1954BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addAppendMethod() {
1955 using PH = BuiltinTypeMethodBuilder::PlaceHolder;
1956 ASTContext &AST = SemaRef.getASTContext();
1957 QualType ElemTy = getHandleElementType();
1958 QualType AddrSpaceElemTy =
1959 AST.getAddrSpaceQualType(T: ElemTy, AddressSpace: LangAS::hlsl_device);
1960 return BuiltinTypeMethodBuilder(*this, "Append", AST.VoidTy)
1961 .addParam(Name: "value", Ty: ElemTy)
1962 .callBuiltin(BuiltinName: "__builtin_hlsl_buffer_update_counter", ReturnType: AST.UnsignedIntTy,
1963 ArgSpecs: PH::CounterHandle, ArgSpecs: getConstantIntExpr(value: 1))
1964 .callBuiltin(BuiltinName: "__builtin_hlsl_resource_getpointer",
1965 ReturnType: AST.getPointerType(T: AddrSpaceElemTy), ArgSpecs: PH::Handle,
1966 ArgSpecs: PH::LastStmt)
1967 .dereference(Ptr: PH::LastStmt)
1968 .assign(LHS: PH::LastStmt, RHS: PH::_0)
1969 .finalize();
1970}
1971
1972BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addConsumeMethod() {
1973 using PH = BuiltinTypeMethodBuilder::PlaceHolder;
1974 ASTContext &AST = SemaRef.getASTContext();
1975 QualType ElemTy = getHandleElementType();
1976 QualType AddrSpaceElemTy =
1977 AST.getAddrSpaceQualType(T: ElemTy, AddressSpace: LangAS::hlsl_device);
1978 return BuiltinTypeMethodBuilder(*this, "Consume", ElemTy)
1979 .callBuiltin(BuiltinName: "__builtin_hlsl_buffer_update_counter", ReturnType: AST.UnsignedIntTy,
1980 ArgSpecs: PH::CounterHandle, ArgSpecs: getConstantIntExpr(value: -1))
1981 .callBuiltin(BuiltinName: "__builtin_hlsl_resource_getpointer",
1982 ReturnType: AST.getPointerType(T: AddrSpaceElemTy), ArgSpecs: PH::Handle,
1983 ArgSpecs: PH::LastStmt)
1984 .dereference(Ptr: PH::LastStmt)
1985 .finalize();
1986}
1987
1988BuiltinTypeDeclBuilder &
1989BuiltinTypeDeclBuilder::addGetDimensionsMethodForBuffer() {
1990 using PH = BuiltinTypeMethodBuilder::PlaceHolder;
1991 ASTContext &AST = SemaRef.getASTContext();
1992 QualType UIntTy = AST.UnsignedIntTy;
1993
1994 QualType HandleTy = getResourceHandleField()->getType();
1995 auto *AttrResTy = cast<HLSLAttributedResourceType>(Val: HandleTy.getTypePtr());
1996
1997 // Structured buffers except {RW}ByteAddressBuffer have overload
1998 // GetDimensions(out uint numStructs, out uint stride).
1999 if (AttrResTy->getAttrs().RawBuffer &&
2000 AttrResTy->getContainedType() != AST.Char8Ty) {
2001 return BuiltinTypeMethodBuilder(*this, "GetDimensions", AST.VoidTy)
2002 .addParam(Name: "numStructs", Ty: UIntTy, Modifier: HLSLParamModifierAttr::Keyword_out)
2003 .addParam(Name: "stride", Ty: UIntTy, Modifier: HLSLParamModifierAttr::Keyword_out)
2004 .callBuiltin(BuiltinName: "__builtin_hlsl_resource_getdimensions_x", ReturnType: QualType(),
2005 ArgSpecs: PH::Handle, ArgSpecs: PH::_0)
2006 .callBuiltin(BuiltinName: "__builtin_hlsl_resource_getstride", ReturnType: QualType(),
2007 ArgSpecs: PH::Handle, ArgSpecs: PH::_1)
2008 .finalize();
2009 }
2010
2011 // Typed buffers and {RW}ByteAddressBuffer have overload
2012 // GetDimensions(out uint dim).
2013 return BuiltinTypeMethodBuilder(*this, "GetDimensions", AST.VoidTy)
2014 .addParam(Name: "dim", Ty: UIntTy, Modifier: HLSLParamModifierAttr::Keyword_out)
2015 .callBuiltin(BuiltinName: "__builtin_hlsl_resource_getdimensions_x", ReturnType: QualType(),
2016 ArgSpecs: PH::Handle, ArgSpecs: PH::_0)
2017 .finalize();
2018}
2019
2020} // namespace hlsl
2021} // namespace clang
2022