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