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