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 "InterlockedCompareExchange", AST.UnsignedIntTy,
1848 "__builtin_hlsl_interlocked_compare_exchange",
1849 /*WithOriginalValue=*/true);
1851 "InterlockedCompareExchangeFloatBitwise", AST.FloatTy,
1852 "__builtin_hlsl_interlocked_compare_exchange_float_bitwise",
1853 /*WithOriginalValue=*/true);
1855 "InterlockedCompareStore", AST.UnsignedIntTy,
1856 "__builtin_hlsl_interlocked_compare_store");
1858 "InterlockedCompareStoreFloatBitwise", AST.FloatTy,
1859 "__builtin_hlsl_interlocked_compare_store_float_bitwise");
1861 "InterlockedExchange", AST.UnsignedIntTy,
1862 "__builtin_hlsl_interlocked_exchange", /*RequiresOriginalValue=*/true);
1863 addByteAddressBufferInterlockedMethod("InterlockedExchangeFloat", AST.FloatTy,
1864 "__builtin_hlsl_interlocked_exchange",
1865 /*RequiresOriginalValue=*/true);
1866 addByteAddressBufferInterlockedMethod("InterlockedMax", AST.IntTy,
1867 "__builtin_hlsl_interlocked_max");
1869 "__builtin_hlsl_interlocked_max");
1870 addByteAddressBufferInterlockedMethod("InterlockedMin", AST.IntTy,
1871 "__builtin_hlsl_interlocked_min");
1873 "__builtin_hlsl_interlocked_min");
1875 "__builtin_hlsl_interlocked_or");
1877 "__builtin_hlsl_interlocked_xor");
1878
1879 // Skip synthesizing the 64 bit methods on DXIL targets older than SM 6.6.
1880 const llvm::Triple &TT = AST.getTargetInfo().getTriple();
1881 bool HasInt64AtomicSupport =
1882 TT.getArch() != llvm::Triple::dxil ||
1883 AST.getTargetInfo().getPlatformMinVersion() >= VersionTuple(6, 6);
1884 if (HasInt64AtomicSupport) {
1885 // HLSL's uint64_t is `unsigned long`.
1886 addByteAddressBufferInterlockedMethod("InterlockedAdd64",
1887 AST.UnsignedLongTy,
1888 "__builtin_hlsl_interlocked_add");
1889 addByteAddressBufferInterlockedMethod("InterlockedAnd64",
1890 AST.UnsignedLongTy,
1891 "__builtin_hlsl_interlocked_and");
1893 "InterlockedCompareExchange64", AST.UnsignedLongTy,
1894 "__builtin_hlsl_interlocked_compare_exchange",
1895 /*WithOriginalValue=*/true);
1897 "InterlockedCompareStore64", AST.UnsignedLongTy,
1898 "__builtin_hlsl_interlocked_compare_store");
1900 "InterlockedExchange64", AST.UnsignedLongTy,
1901 "__builtin_hlsl_interlocked_exchange", /*RequiresOriginalValue=*/true);
1902 addByteAddressBufferInterlockedMethod("InterlockedMax64", AST.LongTy,
1903 "__builtin_hlsl_interlocked_max");
1904 addByteAddressBufferInterlockedMethod("InterlockedMax64",
1905 AST.UnsignedLongTy,
1906 "__builtin_hlsl_interlocked_max");
1907 addByteAddressBufferInterlockedMethod("InterlockedMin64", AST.LongTy,
1908 "__builtin_hlsl_interlocked_min");
1909 addByteAddressBufferInterlockedMethod("InterlockedMin64",
1910 AST.UnsignedLongTy,
1911 "__builtin_hlsl_interlocked_min");
1913 "__builtin_hlsl_interlocked_or");
1914 addByteAddressBufferInterlockedMethod("InterlockedXor64",
1915 AST.UnsignedLongTy,
1916 "__builtin_hlsl_interlocked_xor");
1917 }
1918
1919 return *this;
1920}
1921
1923BuiltinTypeDeclBuilder::addDerivativeAvailability(StringRef MethodName) {
1924 ASTContext &AST = Record->getASTContext();
1925 DeclarationName Name(&AST.Idents.get(MethodName, tok::TokenKind::identifier));
1926 for (NamedDecl *D : Record->lookup(Name)) {
1927 if (auto *FTD = dyn_cast<FunctionTemplateDecl>(D))
1928 D = FTD->getTemplatedDecl();
1929 if (auto *MD = dyn_cast<CXXMethodDecl>(D))
1930 addDerivativeAvailabilityAttrs(AST, MD);
1931 }
1932 return *this;
1933}
1934
1936BuiltinTypeDeclBuilder::addSampleMethods(ResourceDimension Dim, bool IsArray) {
1937 assert(!Record->isCompleteDefinition() && "record is already complete");
1938 ASTContext &AST = Record->getASTContext();
1939 QualType ReturnType = getHandleElementType();
1940 QualType SamplerStateType =
1941 lookupBuiltinType(SemaRef, "SamplerState", Record->getDeclContext());
1942 uint32_t OffsetSize = getResourceDimensions(Dim);
1943 uint32_t CoordSize = OffsetSize + (IsArray ? 1 : 0);
1944 QualType FloatTy = AST.FloatTy;
1945 QualType CoordTy = getVectorOrScalarType(AST, FloatTy, CoordSize);
1946 QualType IntTy = AST.IntTy;
1947 QualType OffsetTy = getVectorOrScalarType(AST, IntTy, OffsetSize);
1948 using PH = BuiltinTypeMethodBuilder::PlaceHolder;
1949
1950 // T Sample(SamplerState s, float2 location)
1951 BuiltinTypeMethodBuilder(*this, "Sample", ReturnType)
1952 .addParam("Sampler", SamplerStateType)
1953 .addParam("Location", CoordTy)
1954 .accessHandleFieldOnResource(PH::_0)
1955 .callBuiltin("__builtin_hlsl_resource_sample", ReturnType, PH::Handle,
1956 PH::LastStmt, PH::_1)
1957 .returnValue(PH::LastStmt)
1958 .finalize();
1959
1960 // Resources without offsets have a clamp overload that takes no offset.
1961 if (!hasResourceOffset(Dim)) {
1962 // T Sample(SamplerState s, float3 location, float clamp)
1963 BuiltinTypeMethodBuilder(*this, "Sample", ReturnType)
1964 .addParam("Sampler", SamplerStateType)
1965 .addParam("Location", CoordTy)
1966 .addParam("Clamp", FloatTy)
1967 .accessHandleFieldOnResource(PH::_0)
1968 .callBuiltin("__builtin_hlsl_resource_sample", ReturnType, PH::Handle,
1969 PH::LastStmt, PH::_1, PH::_2)
1970 .returnValue(PH::LastStmt)
1971 .finalize();
1972
1973 // Sample uses implicit derivatives to calculate the mip level.
1974 return addDerivativeAvailability("Sample");
1975 }
1976
1977 // T Sample(SamplerState s, float2 location, int2 offset)
1978 BuiltinTypeMethodBuilder(*this, "Sample", ReturnType)
1979 .addParam("Sampler", SamplerStateType)
1980 .addParam("Location", CoordTy)
1981 .addParam("Offset", OffsetTy)
1982 .accessHandleFieldOnResource(PH::_0)
1983 .callBuiltin("__builtin_hlsl_resource_sample", ReturnType, PH::Handle,
1984 PH::LastStmt, PH::_1, PH::_2)
1985 .returnValue(PH::LastStmt)
1986 .finalize();
1987
1988 // T Sample(SamplerState s, float2 location, int2 offset, float clamp)
1989 BuiltinTypeMethodBuilder(*this, "Sample", ReturnType)
1990 .addParam("Sampler", SamplerStateType)
1991 .addParam("Location", CoordTy)
1992 .addParam("Offset", OffsetTy)
1993 .addParam("Clamp", FloatTy)
1994 .accessHandleFieldOnResource(PH::_0)
1995 .callBuiltin("__builtin_hlsl_resource_sample", ReturnType, PH::Handle,
1996 PH::LastStmt, PH::_1, PH::_2, PH::_3)
1997 .returnValue(PH::LastStmt)
1998 .finalize();
1999
2000 // Sample uses implicit derivatives to calculate the mip level.
2001 return addDerivativeAvailability("Sample");
2002}
2003
2006 bool IsArray) {
2007 assert(!Record->isCompleteDefinition() && "record is already complete");
2008 ASTContext &AST = Record->getASTContext();
2009 QualType ReturnType = getHandleElementType();
2010 QualType SamplerStateType =
2011 lookupBuiltinType(SemaRef, "SamplerState", Record->getDeclContext());
2012 uint32_t OffsetSize = getResourceDimensions(Dim);
2013 uint32_t CoordSize = OffsetSize + (IsArray ? 1 : 0);
2014 QualType FloatTy = AST.FloatTy;
2015 QualType CoordTy = getVectorOrScalarType(AST, FloatTy, CoordSize);
2016 QualType IntTy = AST.IntTy;
2017 QualType OffsetTy = getVectorOrScalarType(AST, IntTy, OffsetSize);
2018 using PH = BuiltinTypeMethodBuilder::PlaceHolder;
2019
2020 // T SampleBias(SamplerState s, float2 location, float bias)
2021 BuiltinTypeMethodBuilder(*this, "SampleBias", ReturnType)
2022 .addParam("Sampler", SamplerStateType)
2023 .addParam("Location", CoordTy)
2024 .addParam("Bias", FloatTy)
2025 .accessHandleFieldOnResource(PH::_0)
2026 .callBuiltin("__builtin_hlsl_resource_sample_bias", ReturnType,
2027 PH::Handle, PH::LastStmt, PH::_1, PH::_2)
2028 .returnValue(PH::LastStmt)
2029 .finalize();
2030
2031 // Resources without offsets have a clamp overload that takes no offset.
2032 if (!hasResourceOffset(Dim)) {
2033 // T SampleBias(SamplerState s, float3 location, float bias, float clamp)
2034 BuiltinTypeMethodBuilder(*this, "SampleBias", ReturnType)
2035 .addParam("Sampler", SamplerStateType)
2036 .addParam("Location", CoordTy)
2037 .addParam("Bias", FloatTy)
2038 .addParam("Clamp", FloatTy)
2039 .accessHandleFieldOnResource(PH::_0)
2040 .callBuiltin("__builtin_hlsl_resource_sample_bias", ReturnType,
2041 PH::Handle, PH::LastStmt, PH::_1, PH::_2, PH::_3)
2042 .returnValue(PH::LastStmt)
2043 .finalize();
2044
2045 // SampleBias uses implicit derivatives to calculate the mip level.
2046 return addDerivativeAvailability("SampleBias");
2047 }
2048
2049 // T SampleBias(SamplerState s, float2 location, float bias, int2 offset)
2050 BuiltinTypeMethodBuilder(*this, "SampleBias", ReturnType)
2051 .addParam("Sampler", SamplerStateType)
2052 .addParam("Location", CoordTy)
2053 .addParam("Bias", FloatTy)
2054 .addParam("Offset", OffsetTy)
2055 .accessHandleFieldOnResource(PH::_0)
2056 .callBuiltin("__builtin_hlsl_resource_sample_bias", ReturnType,
2057 PH::Handle, PH::LastStmt, PH::_1, PH::_2, PH::_3)
2058 .returnValue(PH::LastStmt)
2059 .finalize();
2060
2061 // T SampleBias(SamplerState s, float2 location, float bias, int2 offset,
2062 // float clamp)
2063 BuiltinTypeMethodBuilder(*this, "SampleBias", ReturnType)
2064 .addParam("Sampler", SamplerStateType)
2065 .addParam("Location", CoordTy)
2066 .addParam("Bias", FloatTy)
2067 .addParam("Offset", OffsetTy)
2068 .addParam("Clamp", FloatTy)
2069 .accessHandleFieldOnResource(PH::_0)
2070 .callBuiltin("__builtin_hlsl_resource_sample_bias", ReturnType,
2071 PH::Handle, PH::LastStmt, PH::_1, PH::_2, PH::_3, PH::_4)
2072 .returnValue(PH::LastStmt)
2073 .finalize();
2074
2075 // SampleBias uses implicit derivatives to calculate the mip level.
2076 return addDerivativeAvailability("SampleBias");
2077}
2078
2081 bool IsArray) {
2082 assert(!Record->isCompleteDefinition() && "record is already complete");
2083 ASTContext &AST = Record->getASTContext();
2084 QualType ReturnType = getHandleElementType();
2085 QualType SamplerStateType =
2086 lookupBuiltinType(SemaRef, "SamplerState", Record->getDeclContext());
2087 uint32_t OffsetSize = getResourceDimensions(Dim);
2088 uint32_t CoordSize = OffsetSize + (IsArray ? 1 : 0);
2089 QualType FloatTy = AST.FloatTy;
2090 QualType CoordTy = getVectorOrScalarType(AST, FloatTy, CoordSize);
2091 QualType OffsetFloatTy = getVectorOrScalarType(AST, FloatTy, OffsetSize);
2092 QualType IntTy = AST.IntTy;
2093 QualType OffsetTy = getVectorOrScalarType(AST, IntTy, OffsetSize);
2094 using PH = BuiltinTypeMethodBuilder::PlaceHolder;
2095
2096 // T SampleGrad(SamplerState s, float2 location, float2 ddx, float2 ddy)
2097 BuiltinTypeMethodBuilder(*this, "SampleGrad", ReturnType)
2098 .addParam("Sampler", SamplerStateType)
2099 .addParam("Location", CoordTy)
2100 .addParam("DDX", OffsetFloatTy)
2101 .addParam("DDY", OffsetFloatTy)
2102 .accessHandleFieldOnResource(PH::_0)
2103 .callBuiltin("__builtin_hlsl_resource_sample_grad", ReturnType,
2104 PH::Handle, PH::LastStmt, PH::_1, PH::_2, PH::_3)
2105 .returnValue(PH::LastStmt)
2106 .finalize();
2107
2108 // Resources without offsets have a clamp overload that takes no offset.
2109 if (!hasResourceOffset(Dim)) {
2110 // T SampleGrad(SamplerState s, float3 location, float3 ddx, float3 ddy,
2111 // float clamp)
2112 BuiltinTypeMethodBuilder(*this, "SampleGrad", ReturnType)
2113 .addParam("Sampler", SamplerStateType)
2114 .addParam("Location", CoordTy)
2115 .addParam("DDX", OffsetFloatTy)
2116 .addParam("DDY", OffsetFloatTy)
2117 .addParam("Clamp", FloatTy)
2118 .accessHandleFieldOnResource(PH::_0)
2119 .callBuiltin("__builtin_hlsl_resource_sample_grad", ReturnType,
2120 PH::Handle, PH::LastStmt, PH::_1, PH::_2, PH::_3, PH::_4)
2121 .returnValue(PH::LastStmt)
2122 .finalize();
2123 return *this;
2124 }
2125
2126 // T SampleGrad(SamplerState s, float2 location, float2 ddx, float2 ddy,
2127 // int2 offset)
2128 BuiltinTypeMethodBuilder(*this, "SampleGrad", ReturnType)
2129 .addParam("Sampler", SamplerStateType)
2130 .addParam("Location", CoordTy)
2131 .addParam("DDX", OffsetFloatTy)
2132 .addParam("DDY", OffsetFloatTy)
2133 .addParam("Offset", OffsetTy)
2134 .accessHandleFieldOnResource(PH::_0)
2135 .callBuiltin("__builtin_hlsl_resource_sample_grad", ReturnType,
2136 PH::Handle, PH::LastStmt, PH::_1, PH::_2, PH::_3, PH::_4)
2137 .returnValue(PH::LastStmt)
2138 .finalize();
2139
2140 // T SampleGrad(SamplerState s, float2 location, float2 ddx, float2 ddy,
2141 // int2 offset, float clamp)
2142 BuiltinTypeMethodBuilder(*this, "SampleGrad", ReturnType)
2143 .addParam("Sampler", SamplerStateType)
2144 .addParam("Location", CoordTy)
2145 .addParam("DDX", OffsetFloatTy)
2146 .addParam("DDY", OffsetFloatTy)
2147 .addParam("Offset", OffsetTy)
2148 .addParam("Clamp", FloatTy)
2149 .accessHandleFieldOnResource(PH::_0)
2150 .callBuiltin("__builtin_hlsl_resource_sample_grad", ReturnType,
2151 PH::Handle, PH::LastStmt, PH::_1, PH::_2, PH::_3, PH::_4,
2152 PH::_5)
2153 .returnValue(PH::LastStmt)
2154 .finalize();
2155
2156 return *this;
2157}
2158
2161 bool IsArray) {
2162 assert(!Record->isCompleteDefinition() && "record is already complete");
2163 ASTContext &AST = Record->getASTContext();
2164 QualType ReturnType = getHandleElementType();
2165 QualType SamplerStateType =
2166 lookupBuiltinType(SemaRef, "SamplerState", Record->getDeclContext());
2167 uint32_t OffsetSize = getResourceDimensions(Dim);
2168 uint32_t CoordSize = OffsetSize + (IsArray ? 1 : 0);
2169 QualType FloatTy = AST.FloatTy;
2170 QualType CoordTy = getVectorOrScalarType(AST, FloatTy, CoordSize);
2171 QualType IntTy = AST.IntTy;
2172 QualType OffsetTy = getVectorOrScalarType(AST, IntTy, OffsetSize);
2173 using PH = BuiltinTypeMethodBuilder::PlaceHolder;
2174
2175 // T SampleLevel(SamplerState s, float2 location, float lod)
2176 BuiltinTypeMethodBuilder(*this, "SampleLevel", ReturnType)
2177 .addParam("Sampler", SamplerStateType)
2178 .addParam("Location", CoordTy)
2179 .addParam("LOD", FloatTy)
2180 .accessHandleFieldOnResource(PH::_0)
2181 .callBuiltin("__builtin_hlsl_resource_sample_level", ReturnType,
2182 PH::Handle, PH::LastStmt, PH::_1, PH::_2)
2183 .returnValue(PH::LastStmt)
2184 .finalize();
2185
2186 // Resources without offsets have no offset overloads.
2187 if (!hasResourceOffset(Dim))
2188 return *this;
2189
2190 // T SampleLevel(SamplerState s, float2 location, float lod, int2 offset)
2191 BuiltinTypeMethodBuilder(*this, "SampleLevel", ReturnType)
2192 .addParam("Sampler", SamplerStateType)
2193 .addParam("Location", CoordTy)
2194 .addParam("LOD", FloatTy)
2195 .addParam("Offset", OffsetTy)
2196 .accessHandleFieldOnResource(PH::_0)
2197 .callBuiltin("__builtin_hlsl_resource_sample_level", ReturnType,
2198 PH::Handle, PH::LastStmt, PH::_1, PH::_2, PH::_3)
2199 .returnValue(PH::LastStmt)
2200 .finalize();
2201
2202 return *this;
2203}
2204
2207 bool IsArray) {
2208 assert(!Record->isCompleteDefinition() && "record is already complete");
2209 ASTContext &AST = Record->getASTContext();
2210 QualType ReturnType = AST.FloatTy;
2211 QualType SamplerComparisonStateType = lookupBuiltinType(
2212 SemaRef, "SamplerComparisonState", Record->getDeclContext());
2213 uint32_t OffsetSize = getResourceDimensions(Dim);
2214 uint32_t CoordSize = OffsetSize + (IsArray ? 1 : 0);
2215 QualType FloatTy = AST.FloatTy;
2216 QualType CoordTy = getVectorOrScalarType(AST, FloatTy, CoordSize);
2217 QualType IntTy = AST.IntTy;
2218 QualType OffsetTy = getVectorOrScalarType(AST, IntTy, OffsetSize);
2219 using PH = BuiltinTypeMethodBuilder::PlaceHolder;
2220
2221 // T SampleCmp(SamplerComparisonState s, float2 location, float compare_value)
2222 BuiltinTypeMethodBuilder(*this, "SampleCmp", ReturnType)
2223 .addParam("Sampler", SamplerComparisonStateType)
2224 .addParam("Location", CoordTy)
2225 .addParam("CompareValue", FloatTy)
2226 .accessHandleFieldOnResource(PH::_0)
2227 .callBuiltin("__builtin_hlsl_resource_sample_cmp", ReturnType, PH::Handle,
2228 PH::LastStmt, PH::_1, PH::_2)
2229 .returnValue(PH::LastStmt)
2230 .finalize();
2231
2232 // Resources without offsets have a clamp overload that takes no offset.
2233 if (!hasResourceOffset(Dim)) {
2234 // T SampleCmp(SamplerComparisonState s, float3 location, float
2235 // compare_value, float clamp)
2236 BuiltinTypeMethodBuilder(*this, "SampleCmp", ReturnType)
2237 .addParam("Sampler", SamplerComparisonStateType)
2238 .addParam("Location", CoordTy)
2239 .addParam("CompareValue", FloatTy)
2240 .addParam("Clamp", FloatTy)
2241 .accessHandleFieldOnResource(PH::_0)
2242 .callBuiltin("__builtin_hlsl_resource_sample_cmp", ReturnType,
2243 PH::Handle, PH::LastStmt, PH::_1, PH::_2, PH::_3)
2244 .returnValue(PH::LastStmt)
2245 .finalize();
2246
2247 // SampleCmp uses implicit derivatives to calculate the mip level.
2248 return addDerivativeAvailability("SampleCmp");
2249 }
2250
2251 // T SampleCmp(SamplerComparisonState s, float2 location, float
2252 // compare_value, int2 offset)
2253 BuiltinTypeMethodBuilder(*this, "SampleCmp", ReturnType)
2254 .addParam("Sampler", SamplerComparisonStateType)
2255 .addParam("Location", CoordTy)
2256 .addParam("CompareValue", FloatTy)
2257 .addParam("Offset", OffsetTy)
2258 .accessHandleFieldOnResource(PH::_0)
2259 .callBuiltin("__builtin_hlsl_resource_sample_cmp", ReturnType, PH::Handle,
2260 PH::LastStmt, PH::_1, PH::_2, PH::_3)
2261 .returnValue(PH::LastStmt)
2262 .finalize();
2263
2264 // T SampleCmp(SamplerComparisonState s, float2 location, float
2265 // compare_value, int2 offset, float clamp)
2266 BuiltinTypeMethodBuilder(*this, "SampleCmp", ReturnType)
2267 .addParam("Sampler", SamplerComparisonStateType)
2268 .addParam("Location", CoordTy)
2269 .addParam("CompareValue", FloatTy)
2270 .addParam("Offset", OffsetTy)
2271 .addParam("Clamp", FloatTy)
2272 .accessHandleFieldOnResource(PH::_0)
2273 .callBuiltin("__builtin_hlsl_resource_sample_cmp", ReturnType, PH::Handle,
2274 PH::LastStmt, PH::_1, PH::_2, PH::_3, PH::_4)
2275 .returnValue(PH::LastStmt)
2276 .finalize();
2277
2278 // SampleCmp uses implicit derivatives to calculate the mip level.
2279 return addDerivativeAvailability("SampleCmp");
2280}
2281
2284 bool IsArray) {
2285 assert(!Record->isCompleteDefinition() && "record is already complete");
2286 ASTContext &AST = Record->getASTContext();
2287 QualType ReturnType = AST.FloatTy;
2288 QualType SamplerComparisonStateType = lookupBuiltinType(
2289 SemaRef, "SamplerComparisonState", Record->getDeclContext());
2290 uint32_t OffsetSize = getResourceDimensions(Dim);
2291 uint32_t CoordSize = OffsetSize + (IsArray ? 1 : 0);
2292 QualType FloatTy = AST.FloatTy;
2293 QualType CoordTy = getVectorOrScalarType(AST, FloatTy, CoordSize);
2294 QualType IntTy = AST.IntTy;
2295 QualType OffsetTy = getVectorOrScalarType(AST, IntTy, OffsetSize);
2296 using PH = BuiltinTypeMethodBuilder::PlaceHolder;
2297
2298 // T SampleCmpLevelZero(SamplerComparisonState s, float2 location, float
2299 // compare_value)
2300 BuiltinTypeMethodBuilder(*this, "SampleCmpLevelZero", ReturnType)
2301 .addParam("Sampler", SamplerComparisonStateType)
2302 .addParam("Location", CoordTy)
2303 .addParam("CompareValue", FloatTy)
2304 .accessHandleFieldOnResource(PH::_0)
2305 .callBuiltin("__builtin_hlsl_resource_sample_cmp_level_zero", ReturnType,
2306 PH::Handle, PH::LastStmt, PH::_1, PH::_2)
2307 .returnValue(PH::LastStmt)
2308 .finalize();
2309
2310 // Resources without offsets have no offset overloads.
2311 if (!hasResourceOffset(Dim))
2312 return *this;
2313
2314 // T SampleCmpLevelZero(SamplerComparisonState s, float2 location, float
2315 // compare_value, int2 offset)
2316 BuiltinTypeMethodBuilder(*this, "SampleCmpLevelZero", ReturnType)
2317 .addParam("Sampler", SamplerComparisonStateType)
2318 .addParam("Location", CoordTy)
2319 .addParam("CompareValue", FloatTy)
2320 .addParam("Offset", OffsetTy)
2321 .accessHandleFieldOnResource(PH::_0)
2322 .callBuiltin("__builtin_hlsl_resource_sample_cmp_level_zero", ReturnType,
2323 PH::Handle, PH::LastStmt, PH::_1, PH::_2, PH::_3)
2324 .returnValue(PH::LastStmt)
2325 .finalize();
2326
2327 return *this;
2328}
2329
2332 assert(!Record->isCompleteDefinition() && "record is already complete");
2333 using PH = BuiltinTypeMethodBuilder::PlaceHolder;
2334 ASTContext &AST = SemaRef.getASTContext();
2335 QualType UIntTy = AST.UnsignedIntTy;
2336
2337 assert(Dim != ResourceDimension::Unknown);
2338
2339 QualType FloatTy = AST.FloatTy;
2340 // Add overloads for uint and float.
2341 QualType Params[] = {UIntTy, FloatTy};
2342
2343 for (QualType OutTy : Params) {
2344 if (Dim == ResourceDimension::Dim2D) {
2345 StringRef XYName = "__builtin_hlsl_resource_getdimensions_xy";
2346 StringRef LevelsXYName =
2347 "__builtin_hlsl_resource_getdimensions_levels_xy";
2348
2349 if (OutTy == FloatTy) {
2350 XYName = "__builtin_hlsl_resource_getdimensions_xy_float";
2351 LevelsXYName = "__builtin_hlsl_resource_getdimensions_levels_xy_float";
2352 }
2353
2354 // void GetDimensions(out [uint|float] width, out [uint|float] height)
2355 BuiltinTypeMethodBuilder(*this, "GetDimensions", AST.VoidTy)
2356 .addParam("width", OutTy, HLSLParamModifierAttr::Keyword_out)
2357 .addParam("height", OutTy, HLSLParamModifierAttr::Keyword_out)
2358 .callBuiltin(XYName, QualType(), PH::Handle, PH::_0, PH::_1)
2359 .finalize();
2360
2361 // void GetDimensions(uint mipLevel, out [uint|float] width, out
2362 // [uint|float] height, out [uint|float] numberOfLevels)
2363 BuiltinTypeMethodBuilder(*this, "GetDimensions", AST.VoidTy)
2364 .addParam("mipLevel", UIntTy)
2365 .addParam("width", OutTy, HLSLParamModifierAttr::Keyword_out)
2366 .addParam("height", OutTy, HLSLParamModifierAttr::Keyword_out)
2367 .addParam("numberOfLevels", OutTy, HLSLParamModifierAttr::Keyword_out)
2368 .callBuiltin(LevelsXYName, QualType(), PH::Handle, PH::_0, PH::_1,
2369 PH::_2, PH::_3)
2370 .finalize();
2371 }
2372 }
2373
2374 return *this;
2375}
2376
2379 assert(!Record->isCompleteDefinition() && "record is already complete");
2380 ASTContext &AST = Record->getASTContext();
2381 QualType ReturnType = AST.FloatTy;
2382 QualType SamplerStateType =
2383 lookupBuiltinType(SemaRef, "SamplerState", Record->getDeclContext());
2384 uint32_t VecSize = getResourceDimensions(Dim);
2385 QualType FloatTy = AST.FloatTy;
2386 QualType LocationTy = getVectorOrScalarType(AST, FloatTy, VecSize);
2387 using PH = BuiltinTypeMethodBuilder::PlaceHolder;
2388
2389 // float CalculateLevelOfDetail(SamplerState s, float2 location)
2390 BuiltinTypeMethodBuilder(*this, "CalculateLevelOfDetail", ReturnType)
2391 .addParam("Sampler", SamplerStateType)
2392 .addParam("Location", LocationTy)
2393 .accessHandleFieldOnResource(PH::_0)
2394 .callBuiltin("__builtin_hlsl_resource_calculate_lod", ReturnType,
2395 PH::Handle, PH::LastStmt, PH::_1)
2396 .finalize();
2397
2398 // float CalculateLevelOfDetailUnclamped(SamplerState s, float2 location)
2399 BuiltinTypeMethodBuilder(*this, "CalculateLevelOfDetailUnclamped", ReturnType)
2400 .addParam("Sampler", SamplerStateType)
2401 .addParam("Location", LocationTy)
2402 .accessHandleFieldOnResource(PH::_0)
2403 .callBuiltin("__builtin_hlsl_resource_calculate_lod_unclamped",
2404 ReturnType, PH::Handle, PH::LastStmt, PH::_1)
2405 .finalize();
2406
2407 // Both methods use implicit derivatives to calculate the level of detail.
2408 addDerivativeAvailability("CalculateLevelOfDetail");
2409 return addDerivativeAvailability("CalculateLevelOfDetailUnclamped");
2410}
2411
2412QualType BuiltinTypeDeclBuilder::getGatherReturnType() {
2413 ASTContext &AST = SemaRef.getASTContext();
2414 QualType T = getHandleElementType();
2415 if (T.isNull())
2416 return QualType();
2417
2418 if (const auto *VT = T->getAs<VectorType>())
2419 T = VT->getElementType();
2420 else if (const auto *DT = T->getAs<DependentSizedExtVectorType>())
2421 T = DT->getElementType();
2422
2423 return AST.getExtVectorType(T, 4);
2424}
2425
2427BuiltinTypeDeclBuilder::addGatherMethods(ResourceDimension Dim, bool IsArray) {
2428 assert(!Record->isCompleteDefinition() && "record is already complete");
2429 ASTContext &AST = Record->getASTContext();
2430 QualType ReturnType = getGatherReturnType();
2431
2432 QualType SamplerStateType =
2433 lookupBuiltinType(SemaRef, "SamplerState", Record->getDeclContext());
2434 uint32_t OffsetSize = getResourceDimensions(Dim);
2435 uint32_t CoordSize = OffsetSize + (IsArray ? 1 : 0);
2436 QualType LocationTy = AST.FloatTy;
2437 QualType CoordTy = getVectorOrScalarType(AST, LocationTy, CoordSize);
2438 QualType IntTy = AST.IntTy;
2439 QualType OffsetTy = getVectorOrScalarType(AST, IntTy, OffsetSize);
2440 using PH = BuiltinTypeMethodBuilder::PlaceHolder;
2441
2442 // Overloads for Gather, GatherRed, GatherGreen, GatherBlue, GatherAlpha
2443 struct GatherVariant {
2444 const char *Name;
2445 int Component;
2446 };
2447 GatherVariant Variants[] = {{"Gather", 0},
2448 {"GatherRed", 0},
2449 {"GatherGreen", 1},
2450 {"GatherBlue", 2},
2451 {"GatherAlpha", 3}};
2452
2453 for (const auto &V : Variants) {
2454 // ret GatherVariant(SamplerState s, float2 location)
2455 BuiltinTypeMethodBuilder(*this, V.Name, ReturnType)
2456 .addParam("Sampler", SamplerStateType)
2457 .addParam("Location", CoordTy)
2458 .accessHandleFieldOnResource(PH::_0)
2459 .callBuiltin("__builtin_hlsl_resource_gather", ReturnType, PH::Handle,
2460 PH::LastStmt, PH::_1,
2461 getConstantUnsignedIntExpr(V.Component))
2462 .finalize();
2463
2464 // Resources without offsets have no offset overloads.
2465 if (!hasResourceOffset(Dim))
2466 continue;
2467
2468 // ret GatherVariant(SamplerState s, float2 location, int2 offset)
2469 BuiltinTypeMethodBuilder(*this, V.Name, ReturnType)
2470 .addParam("Sampler", SamplerStateType)
2471 .addParam("Location", CoordTy)
2472 .addParam("Offset", OffsetTy)
2473 .accessHandleFieldOnResource(PH::_0)
2474 .callBuiltin("__builtin_hlsl_resource_gather", ReturnType, PH::Handle,
2475 PH::LastStmt, PH::_1,
2476 getConstantUnsignedIntExpr(V.Component), PH::_2)
2477 .finalize();
2478 }
2479
2480 return *this;
2481}
2482
2485 bool IsArray) {
2486 assert(!Record->isCompleteDefinition() && "record is already complete");
2487 ASTContext &AST = Record->getASTContext();
2488 QualType ReturnType = AST.getExtVectorType(AST.FloatTy, 4);
2489
2490 QualType SamplerComparisonStateType = lookupBuiltinType(
2491 SemaRef, "SamplerComparisonState", Record->getDeclContext());
2492 uint32_t OffsetSize = getResourceDimensions(Dim);
2493 uint32_t CoordSize = OffsetSize + (IsArray ? 1 : 0);
2494 QualType FloatTy = AST.FloatTy;
2495 QualType CoordTy = getVectorOrScalarType(AST, FloatTy, CoordSize);
2496 QualType IntTy = AST.IntTy;
2497 QualType OffsetTy = getVectorOrScalarType(AST, IntTy, OffsetSize);
2498 using PH = BuiltinTypeMethodBuilder::PlaceHolder;
2499
2500 // Overloads for GatherCmp, GatherCmpRed, GatherCmpGreen, GatherCmpBlue,
2501 // GatherCmpAlpha
2502 struct GatherVariant {
2503 const char *Name;
2504 int Component;
2505 };
2506 GatherVariant Variants[] = {{"GatherCmp", 0},
2507 {"GatherCmpRed", 0},
2508 {"GatherCmpGreen", 1},
2509 {"GatherCmpBlue", 2},
2510 {"GatherCmpAlpha", 3}};
2511
2512 for (const auto &V : Variants) {
2513 // ret GatherCmpVariant(SamplerComparisonState s, float2 location, float
2514 // compare_value)
2515 BuiltinTypeMethodBuilder(*this, V.Name, ReturnType)
2516 .addParam("Sampler", SamplerComparisonStateType)
2517 .addParam("Location", CoordTy)
2518 .addParam("CompareValue", FloatTy)
2519 .accessHandleFieldOnResource(PH::_0)
2520 .callBuiltin("__builtin_hlsl_resource_gather_cmp", ReturnType,
2521 PH::Handle, PH::LastStmt, PH::_1, PH::_2,
2522 getConstantUnsignedIntExpr(V.Component))
2523 .finalize();
2524
2525 // Resources without offsets have no offset overloads.
2526 if (!hasResourceOffset(Dim))
2527 continue;
2528
2529 // ret GatherCmpVariant(SamplerComparisonState s, float2 location, float
2530 // compare_value, int2 offset)
2531 BuiltinTypeMethodBuilder(*this, V.Name, ReturnType)
2532 .addParam("Sampler", SamplerComparisonStateType)
2533 .addParam("Location", CoordTy)
2534 .addParam("CompareValue", FloatTy)
2535 .addParam("Offset", OffsetTy)
2536 .accessHandleFieldOnResource(PH::_0)
2537 .callBuiltin("__builtin_hlsl_resource_gather_cmp", ReturnType,
2538 PH::Handle, PH::LastStmt, PH::_1, PH::_2,
2539 getConstantUnsignedIntExpr(V.Component), PH::_3)
2540 .finalize();
2541 }
2542
2543 return *this;
2544}
2545
2546FieldDecl *BuiltinTypeDeclBuilder::getResourceHandleField() const {
2547 auto I = Fields.find("__handle");
2548 assert(I != Fields.end() &&
2549 I->second->getType()->isHLSLAttributedResourceType() &&
2550 "record does not have resource handle field");
2551 return I->second;
2552}
2553
2554FieldDecl *BuiltinTypeDeclBuilder::getResourceCounterHandleField() const {
2555 auto I = Fields.find("__counter_handle");
2556 if (I == Fields.end() ||
2557 !I->second->getType()->isHLSLAttributedResourceType())
2558 return nullptr;
2559 return I->second;
2560}
2561
2562QualType BuiltinTypeDeclBuilder::getFirstTemplateTypeParam() {
2563 assert(Template && "record it not a template");
2564 if (const auto *TTD = dyn_cast<TemplateTypeParmDecl>(
2565 Template->getTemplateParameters()->getParam(0))) {
2566 return QualType(TTD->getTypeForDecl(), 0);
2567 }
2568 return QualType();
2569}
2570
2571QualType BuiltinTypeDeclBuilder::getHandleElementType() {
2572 if (Template)
2573 return getFirstTemplateTypeParam();
2574
2575 if (auto *Spec = dyn_cast<ClassTemplateSpecializationDecl>(Record)) {
2576 const auto &Args = Spec->getTemplateArgs();
2577 if (Args.size() > 0 && Args[0].getKind() == TemplateArgument::Type)
2578 return Args[0].getAsType();
2579 }
2580
2581 // TODO: Should we default to VoidTy? Using `i8` is arguably ambiguous.
2582 return SemaRef.getASTContext().Char8Ty;
2583}
2584
2585HLSLAttributedResourceType::Attributes
2586BuiltinTypeDeclBuilder::getResourceAttrs() const {
2587 QualType HandleType = getResourceHandleField()->getType();
2588 return cast<HLSLAttributedResourceType>(HandleType)->getAttrs();
2589}
2590
2592 assert(!Record->isCompleteDefinition() && "record is already complete");
2593 assert(Record->isBeingDefined() &&
2594 "Definition must be started before completing it.");
2595
2596 Record->completeDefinition();
2597 Record->setIsHLSLBuiltinRecord(true);
2598 return *this;
2599}
2600
2601Expr *BuiltinTypeDeclBuilder::getConstantIntExpr(int value) {
2602 ASTContext &AST = SemaRef.getASTContext();
2604 AST, llvm::APInt(AST.getTypeSize(AST.IntTy), value, true), AST.IntTy,
2605 SourceLocation());
2606}
2607
2608Expr *BuiltinTypeDeclBuilder::getConstantUnsignedIntExpr(unsigned value) {
2609 ASTContext &AST = SemaRef.getASTContext();
2611 AST, llvm::APInt(AST.getTypeSize(AST.UnsignedIntTy), value),
2613}
2614
2620
2623 ArrayRef<QualType> DefaultTypes,
2624 ConceptDecl *CD) {
2625 if (Record->isCompleteDefinition()) {
2626 assert(Template && "existing record it not a template");
2627 assert(Template->getTemplateParameters()->size() == Names.size() &&
2628 "template param count mismatch");
2629 return *this;
2630 }
2631
2632 assert((DefaultTypes.empty() || DefaultTypes.size() == Names.size()) &&
2633 "template default argument count mismatch");
2634
2636 for (unsigned i = 0; i < Names.size(); ++i) {
2637 QualType DefaultTy = DefaultTypes.empty() ? QualType() : DefaultTypes[i];
2638 Builder.addTypeParameter(Names[i], DefaultTy);
2639 }
2640 return Builder.finalizeTemplateArgs(CD);
2641}
2642
2644 StringRef ElementName, StringRef SampleCountName, ConceptDecl *CD) {
2645 if (Record->isCompleteDefinition()) {
2646 assert(Template && "existing record it not a template");
2647 assert(Template->getTemplateParameters()->size() == 2 &&
2648 "template param count mismatch");
2649 return *this;
2650 }
2651
2652 ASTContext &AST = SemaRef.getASTContext();
2654 // No default element type (`Texture2DMS` and `Texture2DMS<>` are errors).
2655 // A sample count of 0 means the count comes from the bound resource rather
2656 // than denoting zero samples.
2657 Builder.addTypeParameter(ElementName);
2658 Builder.addNonTypeParameter(SampleCountName, AST.IntTy,
2659 getConstantIntExpr(0));
2660 return Builder.finalizeTemplateArgs(CD);
2661}
2662
2664 using PH = BuiltinTypeMethodBuilder::PlaceHolder;
2665 QualType UnsignedIntTy = SemaRef.getASTContext().UnsignedIntTy;
2666 return BuiltinTypeMethodBuilder(*this, "IncrementCounter", UnsignedIntTy)
2667 .callBuiltin("__builtin_hlsl_buffer_update_counter", UnsignedIntTy,
2668 PH::CounterHandle, getConstantIntExpr(1))
2669 .finalize();
2670}
2671
2673 using PH = BuiltinTypeMethodBuilder::PlaceHolder;
2674 QualType UnsignedIntTy = SemaRef.getASTContext().UnsignedIntTy;
2675 return BuiltinTypeMethodBuilder(*this, "DecrementCounter", UnsignedIntTy)
2676 .callBuiltin("__builtin_hlsl_buffer_update_counter", UnsignedIntTy,
2677 PH::CounterHandle, getConstantIntExpr(-1))
2678 .finalize();
2679}
2680
2683 QualType ReturnTy) {
2684 assert(!Record->isCompleteDefinition() && "record is already complete");
2685 ASTContext &AST = SemaRef.getASTContext();
2686 using PH = BuiltinTypeMethodBuilder::PlaceHolder;
2687 bool NeedsTypedBuiltin = !ReturnTy.isNull();
2688
2689 // The empty QualType is a placeholder. The actual return type is set below.
2690 // All load methods will be const.
2691 BuiltinTypeMethodBuilder MMB(*this, Name, QualType(), true);
2692
2693 if (!NeedsTypedBuiltin)
2694 ReturnTy = getHandleElementType();
2695 if (ReturnTy == AST.DependentTy)
2696 ReturnTy = MMB.addTemplateTypeParam("element_type");
2697 MMB.ReturnTy = ReturnTy;
2698
2699 MMB.addParam("Index", AST.UnsignedIntTy)
2700 .addParam("Status", AST.UnsignedIntTy,
2701 HLSLParamModifierAttr::Keyword_out);
2702
2703 if (NeedsTypedBuiltin)
2704 MMB.callBuiltin("__builtin_hlsl_resource_load_with_status_typed", ReturnTy,
2705 PH::Handle, PH::_0, PH::_1, ReturnTy);
2706 else
2707 MMB.callBuiltin("__builtin_hlsl_resource_load_with_status", ReturnTy,
2708 PH::Handle, PH::_0, PH::_1);
2709
2710 return MMB.finalize();
2711}
2712
2714 DeclarationName &Name, bool IsConstReturn, bool IsRef, QualType IndexTy,
2715 QualType ElemTy, bool TransposeResult) {
2716 assert(!Record->isCompleteDefinition() && "record is already complete");
2717 ASTContext &AST = SemaRef.getASTContext();
2718 using PH = BuiltinTypeMethodBuilder::PlaceHolder;
2719 bool NeedsTypedBuiltin = !ElemTy.isNull();
2720
2721 // The empty QualType is a placeholder. The actual return type is set below.
2722 // All access methods are const; none of them rebind the resource handle.
2723 BuiltinTypeMethodBuilder MMB(*this, Name, QualType(), true);
2724
2725 if (!NeedsTypedBuiltin)
2726 ElemTy = getHandleElementType();
2727 if (ElemTy == AST.DependentTy)
2728 ElemTy = MMB.addTemplateTypeParam("element_type");
2729 QualType AddrSpaceElemTy =
2731 QualType ElemPtrTy = AST.getPointerType(AddrSpaceElemTy);
2732 QualType ReturnTy;
2733
2734 if (IsRef) {
2735 ReturnTy = AddrSpaceElemTy;
2736 if (IsConstReturn)
2737 ReturnTy.addConst();
2738 ReturnTy = AST.getLValueReferenceType(ReturnTy);
2739 } else {
2740 assert(!IsConstReturn && "There shouldn't be any resource methods with a "
2741 "const ref return value");
2742 ReturnTy = ElemTy;
2743 }
2744 MMB.ReturnTy = ReturnTy;
2745
2746 MMB.addParam("Index", IndexTy);
2747
2748 if (NeedsTypedBuiltin)
2749 MMB.callBuiltin("__builtin_hlsl_resource_getpointer_typed", ElemPtrTy,
2750 PH::Handle, PH::_0, ElemTy);
2751 else
2752 MMB.callBuiltin("__builtin_hlsl_resource_getpointer", ElemPtrTy, PH::Handle,
2753 PH::_0);
2754
2755 MMB.dereference(PH::LastStmt);
2756 if (TransposeResult)
2757 MMB.callBuiltin("__builtin_hlsl_transpose_if_memory_is_row_major", ElemTy,
2758 PH::LastStmt, getConstantIntExpr(1));
2759 return MMB.finalize();
2760}
2761
2764 QualType ValueTy, bool TransposeArg) {
2765 assert(!Record->isCompleteDefinition() && "record is already complete");
2766 ASTContext &AST = SemaRef.getASTContext();
2767 using PH = BuiltinTypeMethodBuilder::PlaceHolder;
2768
2769 BuiltinTypeMethodBuilder MMB(*this, Name, AST.VoidTy, IsConst);
2770
2771 if (ValueTy == AST.DependentTy)
2772 ValueTy = MMB.addTemplateTypeParam("element_type");
2773 QualType AddrSpaceElemTy =
2775 QualType ElemPtrTy = AST.getPointerType(AddrSpaceElemTy);
2776
2777 MMB.addParam("Index", AST.UnsignedIntTy).addParam("Value", ValueTy);
2778 if (TransposeArg)
2779 MMB.callBuiltin("__builtin_hlsl_transpose_if_memory_is_row_major", ValueTy,
2780 PH::_1, getConstantIntExpr(0));
2781 MMB.callBuiltin("__builtin_hlsl_resource_getpointer_typed", ElemPtrTy,
2782 PH::Handle, PH::_0, ValueTy)
2783 .dereference(PH::LastStmt)
2784 .assign(PH::LastStmt, TransposeArg ? PH::LastStmt : PH::_1);
2785 return MMB.finalize();
2786}
2787
2790 StringRef MethodName, QualType ValueTy, StringRef BuiltinName,
2791 bool RequiresOriginalValue) {
2792 assert(!Record->isCompleteDefinition() && "record is already complete");
2793 ASTContext &AST = SemaRef.getASTContext();
2794 using PH = BuiltinTypeMethodBuilder::PlaceHolder;
2795
2796 // Interlocked atomics operate on a typed slot in the buffer. Compose
2797 // `resource_getpointer_typed` with the scalar `__builtin_hlsl_interlocked_*`
2798 // builtin so backend lowering (DXIL and SPIR-V) can pattern-match a
2799 // resource-pointer atomicrmw.
2800 QualType AddrSpaceElemTy =
2802 QualType ElemPtrTy = AST.getPointerType(AddrSpaceElemTy);
2803
2804 auto BuildOverload = [&](bool WithOriginalValue) {
2805 BuiltinTypeMethodBuilder MMB(*this, MethodName, AST.VoidTy);
2806 MMB.addParam("Offset", AST.UnsignedIntTy).addParam("Value", ValueTy);
2807 if (WithOriginalValue)
2808 MMB.addParam("OriginalValue", ValueTy,
2809 HLSLParamModifierAttr::Keyword_out);
2810 MMB.callBuiltin("__builtin_hlsl_resource_getpointer_typed", ElemPtrTy,
2811 PH::Handle, PH::_0, ValueTy)
2812 .dereference(PH::LastStmt);
2813 if (WithOriginalValue)
2814 MMB.callBuiltin(BuiltinName, AST.VoidTy, PH::LastStmt, PH::_1, PH::_2);
2815 else
2816 MMB.callBuiltin(BuiltinName, AST.VoidTy, PH::LastStmt, PH::_1);
2817 MMB.finalize();
2818 };
2819
2820 if (!RequiresOriginalValue)
2821 BuildOverload(/*WithOriginalValue=*/false);
2822 BuildOverload(/*WithOriginalValue=*/true);
2823 return *this;
2824}
2825
2828 StringRef MethodName, QualType ValueTy, StringRef BuiltinName,
2829 bool WithOriginalValue) {
2830 assert(!Record->isCompleteDefinition() && "record is already complete");
2831 ASTContext &AST = SemaRef.getASTContext();
2832 using PH = BuiltinTypeMethodBuilder::PlaceHolder;
2833
2834 QualType AddrSpaceElemTy =
2836 QualType ElemPtrTy = AST.getPointerType(AddrSpaceElemTy);
2837
2838 BuiltinTypeMethodBuilder MMB(*this, MethodName, AST.VoidTy);
2839 MMB.addParam("Offset", AST.UnsignedIntTy)
2840 .addParam("CompareValue", ValueTy)
2841 .addParam("Value", ValueTy);
2842 if (WithOriginalValue)
2843 MMB.addParam("OriginalValue", ValueTy, HLSLParamModifierAttr::Keyword_out);
2844 MMB.callBuiltin("__builtin_hlsl_resource_getpointer_typed", ElemPtrTy,
2845 PH::Handle, PH::_0, ValueTy)
2846 .dereference(PH::LastStmt);
2847 if (WithOriginalValue)
2848 MMB.callBuiltin(BuiltinName, AST.VoidTy, PH::LastStmt, PH::_1, PH::_2,
2849 PH::_3);
2850 else
2851 MMB.callBuiltin(BuiltinName, AST.VoidTy, PH::LastStmt, PH::_1, PH::_2);
2852 MMB.finalize();
2853 return *this;
2854}
2855
2857 using PH = BuiltinTypeMethodBuilder::PlaceHolder;
2858 ASTContext &AST = SemaRef.getASTContext();
2859 QualType ElemTy = getHandleElementType();
2860 QualType AddrSpaceElemTy =
2862 return BuiltinTypeMethodBuilder(*this, "Append", AST.VoidTy)
2863 .addParam("value", ElemTy)
2864 .callBuiltin("__builtin_hlsl_buffer_update_counter", AST.UnsignedIntTy,
2865 PH::CounterHandle, getConstantIntExpr(1))
2866 .callBuiltin("__builtin_hlsl_resource_getpointer",
2867 AST.getPointerType(AddrSpaceElemTy), PH::Handle,
2868 PH::LastStmt)
2869 .dereference(PH::LastStmt)
2870 .assign(PH::LastStmt, PH::_0)
2871 .finalize();
2872}
2873
2875 using PH = BuiltinTypeMethodBuilder::PlaceHolder;
2876 ASTContext &AST = SemaRef.getASTContext();
2877 QualType ElemTy = getHandleElementType();
2878 QualType AddrSpaceElemTy =
2880 return BuiltinTypeMethodBuilder(*this, "Consume", ElemTy)
2881 .callBuiltin("__builtin_hlsl_buffer_update_counter", AST.UnsignedIntTy,
2882 PH::CounterHandle, getConstantIntExpr(-1))
2883 .callBuiltin("__builtin_hlsl_resource_getpointer",
2884 AST.getPointerType(AddrSpaceElemTy), PH::Handle,
2885 PH::LastStmt)
2886 .dereference(PH::LastStmt)
2887 .finalize();
2888}
2889
2892 using PH = BuiltinTypeMethodBuilder::PlaceHolder;
2893 ASTContext &AST = SemaRef.getASTContext();
2894 QualType UIntTy = AST.UnsignedIntTy;
2895
2896 QualType HandleTy = getResourceHandleField()->getType();
2897 auto *AttrResTy = cast<HLSLAttributedResourceType>(HandleTy.getTypePtr());
2898
2899 // Structured buffers except {RW}ByteAddressBuffer have overload
2900 // GetDimensions(out uint numStructs, out uint stride).
2901 if (AttrResTy->getAttrs().RawBuffer &&
2902 AttrResTy->getContainedType() != AST.Char8Ty) {
2903 return BuiltinTypeMethodBuilder(*this, "GetDimensions", AST.VoidTy)
2904 .addParam("numStructs", UIntTy, HLSLParamModifierAttr::Keyword_out)
2905 .addParam("stride", UIntTy, HLSLParamModifierAttr::Keyword_out)
2906 .callBuiltin("__builtin_hlsl_resource_getdimensions_x", QualType(),
2907 PH::Handle, PH::_0)
2908 .callBuiltin("__builtin_hlsl_resource_getstride", QualType(),
2909 PH::Handle, PH::_1)
2910 .finalize();
2911 }
2912
2913 // Typed buffers and {RW}ByteAddressBuffer have overload
2914 // GetDimensions(out uint dim).
2915 return BuiltinTypeMethodBuilder(*this, "GetDimensions", AST.VoidTy)
2916 .addParam("dim", UIntTy, HLSLParamModifierAttr::Keyword_out)
2917 .callBuiltin("__builtin_hlsl_resource_getdimensions_x", QualType(),
2918 PH::Handle, PH::_0)
2919 .finalize();
2920}
2921
2922} // namespace hlsl
2923} // namespace clang
Defines the clang::ASTContext interface.
#define V(N, I)
static const FieldDecl * getResourceHandleField(QualType ResourceTy)
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:245
DeclarationNameTable DeclarationNames
Definition ASTContext.h:860
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:856
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:3299
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition ASTContext.h:245
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:860
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:856
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:975
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:2769
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:5144
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:1212
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:1159
static CXXThisExpr * Create(const ASTContext &Ctx, SourceLocation L, QualType Ty, bool IsImplicit)
Definition ExprCXX.cpp:1616
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:1294
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:498
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:4199
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:3299
const RecordDecl * getParent() const
Returns the parent of this field declaration, which is the struct in which this field is defined.
Definition Decl.h:3535
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:4775
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:4638
ExtParameterInfo withABI(ParameterABI kind) const
Definition TypeBase.h:4652
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:2109
static ImplicitConceptSpecializationDecl * Create(const ASTContext &C, DeclContext *DC, SourceLocation SL, ArrayRef< TemplateArgument > ConvertedArgs)
Describes an C or C++ initializer list.
Definition Expr.h:5356
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:985
Represents the results of name lookup.
Definition Lookup.h:147
MemberExpr - [C99 6.5.2.3] Structure and Union Members.
Definition Expr.h:3412
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:3473
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:2948
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:8446
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:8631
field_iterator field_begin() const
Definition Decl.cpp:5356
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:1165
@ LookupOrdinaryName
Ordinary name lookup, which finds ordinary names (functions, variables, typedefs, etc....
Definition Sema.h:9494
@ LookupNamespaceName
Look up a namespace name within a C++ using directive or namespace alias definition,...
Definition Sema.h:9517
@ LookupTagName
Tag name lookup, which finds the names of enums, classes, structs, and unions.
Definition Sema.h:9497
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:4988
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:3957
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:8417
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:9366
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee.
Definition Type.cpp:885
bool isVectorType() const
Definition TypeBase.h:8822
const T * getAs() const
Member-template getAs<specific type>'.
Definition TypeBase.h:9299
bool isRecordType() const
Definition TypeBase.h:8810
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:5201
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:4273
unsigned getNumElements() const
Definition TypeBase.h:4288
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 & addByteAddressBufferInterlockedCompareMethod(StringRef MethodName, QualType ValueTy, StringRef BuiltinName, bool WithOriginalValue=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:276
@ 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:155
AccessSpecifier
A C++ access specifier (public, private, protected), plus the special value "none" which means differ...
Definition Specifiers.h:127
@ AS_public
Definition Specifiers.h:128
@ AS_protected
Definition Specifiers.h:129
@ AS_private
Definition Specifiers.h:130
nullptr
This class represents a compute construct, representing a 'Kind' of ‘parallel’, 'serial',...
StorageClass
Storage classes.
Definition Specifiers.h:252
@ SC_Static
Definition Specifiers.h:256
@ SC_None
Definition Specifiers.h:254
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:382
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:139
@ VK_XValue
An x-value expression is a reference to an object with independent storage but which can be "moved",...
Definition Specifiers.h:148
@ VK_LValue
An l-value expression is a reference to an object with independent storage.
Definition Specifiers.h:143
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
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)