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