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