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