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