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