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