clang 22.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"
19#include "clang/AST/Expr.h"
20#include "clang/AST/Stmt.h"
21#include "clang/AST/Type.h"
24#include "clang/Sema/Lookup.h"
25#include "clang/Sema/Sema.h"
26#include "clang/Sema/SemaHLSL.h"
27#include "llvm/ADT/SmallVector.h"
28
29using namespace llvm::hlsl;
30
31namespace clang {
32
33namespace hlsl {
34
35namespace {
36
37static FunctionDecl *lookupBuiltinFunction(Sema &S, StringRef Name) {
38 IdentifierInfo &II =
39 S.getASTContext().Idents.get(Name, tok::TokenKind::identifier);
40 DeclarationNameInfo NameInfo =
41 DeclarationNameInfo(DeclarationName(&II), SourceLocation());
42 LookupResult R(S, NameInfo, Sema::LookupOrdinaryName);
43 // AllowBuiltinCreation is false but LookupDirect will create
44 // the builtin when searching the global scope anyways...
45 S.LookupName(R, S.getCurScope());
46 // FIXME: If the builtin function was user-declared in global scope,
47 // this assert *will* fail. Should this call LookupBuiltin instead?
48 assert(R.isSingleResult() &&
49 "Since this is a builtin it should always resolve!");
50 return cast<FunctionDecl>(R.getFoundDecl());
51}
52
53CXXConstructorDecl *lookupCopyConstructor(QualType ResTy) {
54 assert(ResTy->isRecordType() && "not a CXXRecord type");
55 for (auto *CD : ResTy->getAsCXXRecordDecl()->ctors())
56 if (CD->isCopyConstructor())
57 return CD;
58 return nullptr;
59}
60
62convertParamModifierToParamABI(HLSLParamModifierAttr::Spelling Modifier) {
63 assert(Modifier != HLSLParamModifierAttr::Spelling::Keyword_in &&
64 "HLSL 'in' parameters modifier cannot be converted to ParameterABI");
65 switch (Modifier) {
66 case HLSLParamModifierAttr::Spelling::Keyword_out:
68 case HLSLParamModifierAttr::Spelling::Keyword_inout:
70 default:
71 llvm_unreachable("Invalid HLSL parameter modifier");
72 }
73}
74
75QualType getInoutParameterType(ASTContext &AST, QualType Ty) {
76 assert(!Ty->isReferenceType() &&
77 "Pointer and reference types cannot be inout or out parameters");
78 Ty = AST.getLValueReferenceType(Ty);
79 Ty.addRestrict();
80 return Ty;
81}
82
83} // namespace
84
85// Builder for template arguments of builtin types. Used internally
86// by BuiltinTypeDeclBuilder.
102
103// Builder for methods or constructors of builtin types. Allows creating methods
104// or constructors of builtin types using the builder pattern like this:
105//
106// BuiltinTypeMethodBuilder(RecordBuilder, "MethodName", ReturnType)
107// .addParam("param_name", Type, InOutModifier)
108// .callBuiltin("builtin_name", BuiltinParams...)
109// .finalize();
110//
111// The builder needs to have all of the parameters before it can create
112// a CXXMethodDecl or CXXConstructorDecl. It collects them in addParam calls and
113// when a first method that builds the body is called or when access to 'this`
114// is needed it creates the CXXMethodDecl/CXXConstructorDecl and ParmVarDecls
115// instances. These can then be referenced from the body building methods.
116// Destructor or an explicit call to finalize() will complete the method
117// definition.
118//
119// The callBuiltin helper method accepts constants via `Expr *` or placeholder
120// value arguments to indicate which function arguments to forward to the
121// builtin.
122//
123// If the method that is being built has a non-void return type the
124// finalize() will create a return statement with the value of the last
125// statement (unless the last statement is already a ReturnStmt or the return
126// value is void).
128private:
129 struct Param {
130 const IdentifierInfo &NameII;
131 QualType Ty;
132 HLSLParamModifierAttr::Spelling Modifier;
133 Param(const IdentifierInfo &NameII, QualType Ty,
134 HLSLParamModifierAttr::Spelling Modifier)
135 : NameII(NameII), Ty(Ty), Modifier(Modifier) {}
136 };
137
138 struct LocalVar {
139 StringRef Name;
140 QualType Ty;
141 VarDecl *Decl;
142 LocalVar(StringRef Name, QualType Ty) : Name(Name), Ty(Ty), Decl(nullptr) {}
143 };
144
145 BuiltinTypeDeclBuilder &DeclBuilder;
146 DeclarationName Name;
147 QualType ReturnTy;
148 // method or constructor declaration
149 // (CXXConstructorDecl derives from CXXMethodDecl)
150 CXXMethodDecl *Method;
151 bool IsConst;
152 bool IsCtor;
153 StorageClass SC;
156
157 // Argument placeholders, inspired by std::placeholder. These are the indices
158 // of arguments to forward to `callBuiltin` and other method builder methods.
159 // Additional special values are:
160 // Handle - refers to the resource handle.
161 // LastStmt - refers to the last statement in the method body; referencing
162 // LastStmt will remove the statement from the method body since
163 // it will be linked from the new expression being constructed.
164 enum class PlaceHolder {
165 _0,
166 _1,
167 _2,
168 _3,
169 _4,
170 _5,
171 Handle = 128,
172 CounterHandle,
173 LastStmt
174 };
175
176 Expr *convertPlaceholder(PlaceHolder PH);
177 Expr *convertPlaceholder(LocalVar &Var);
178 Expr *convertPlaceholder(Expr *E) { return E; }
179
180public:
182
184 QualType ReturnTy, bool IsConst = false,
185 bool IsCtor = false, StorageClass SC = SC_None)
186 : DeclBuilder(DB), Name(Name), ReturnTy(ReturnTy), Method(nullptr),
187 IsConst(IsConst), IsCtor(IsCtor), SC(SC) {}
188
190 QualType ReturnTy, bool IsConst = false,
191 bool IsCtor = false, StorageClass SC = SC_None);
193
195
198
199 BuiltinTypeMethodBuilder &addParam(StringRef Name, QualType Ty,
200 HLSLParamModifierAttr::Spelling Modifier =
201 HLSLParamModifierAttr::Keyword_in);
203 template <typename... Ts>
204 BuiltinTypeMethodBuilder &callBuiltin(StringRef BuiltinName,
205 QualType ReturnType, Ts... ArgSpecs);
206 template <typename TLHS, typename TRHS>
207 BuiltinTypeMethodBuilder &assign(TLHS LHS, TRHS RHS);
208 template <typename T> BuiltinTypeMethodBuilder &dereference(T Ptr);
209 template <typename T>
211 template <typename ResourceT, typename ValueT>
212 BuiltinTypeMethodBuilder &setHandleFieldOnResource(ResourceT ResourceRecord,
213 ValueT HandleValue);
214 template <typename T>
217 template <typename ResourceT, typename ValueT>
219 setCounterHandleFieldOnResource(ResourceT ResourceRecord, ValueT HandleValue);
220 template <typename T> BuiltinTypeMethodBuilder &returnValue(T ReturnValue);
225
226private:
227 void createDecl();
228
229 // Makes sure the declaration is created; should be called before any
230 // statement added to the body or when access to 'this' is needed.
231 void ensureCompleteDecl() {
232 if (!Method)
233 createDecl();
234 }
235
236 template <typename ResourceT, typename ValueT>
237 BuiltinTypeMethodBuilder &setFieldOnResource(ResourceT ResourceRecord,
238 ValueT HandleValue,
239 FieldDecl *HandleField);
240};
241
245
248 QualType DefaultValue) {
249 assert(!Builder.Record->isCompleteDefinition() &&
250 "record is already complete");
251 ASTContext &AST = Builder.SemaRef.getASTContext();
252 unsigned Position = static_cast<unsigned>(Params.size());
254 AST, Builder.Record->getDeclContext(), SourceLocation(), SourceLocation(),
255 /* TemplateDepth */ 0, Position,
256 &AST.Idents.get(Name, tok::TokenKind::identifier),
257 /* Typename */ true,
258 /* ParameterPack */ false,
259 /* HasTypeConstraint*/ false);
260 if (!DefaultValue.isNull())
261 Decl->setDefaultArgument(AST,
262 Builder.SemaRef.getTrivialTemplateArgumentLoc(
263 DefaultValue, QualType(), SourceLocation()));
264
265 Params.emplace_back(Decl);
266 return *this;
267}
268
269// The concept specialization expression (CSE) constructed in
270// constructConceptSpecializationExpr is constructed so that it
271// matches the CSE that is constructed when parsing the below C++ code:
272//
273// template<typename T>
274// concept is_typed_resource_element_compatible =
275// __builtin_hlsl_typed_resource_element_compatible<T>
276//
277// template<typename element_type> requires
278// is_typed_resource_element_compatible<element_type>
279// struct RWBuffer {
280// element_type Val;
281// };
282//
283// int fn() {
284// RWBuffer<int> Buf;
285// }
286//
287// When dumping the AST and filtering for "RWBuffer", the resulting AST
288// structure is what we're trying to construct below, specifically the
289// CSE portion.
292 Sema &S, ConceptDecl *CD) {
293 ASTContext &Context = S.getASTContext();
294 SourceLocation Loc = Builder.Record->getBeginLoc();
295 DeclarationNameInfo DNI(CD->getDeclName(), Loc);
297 DeclContext *DC = Builder.Record->getDeclContext();
298 TemplateArgumentListInfo TALI(Loc, Loc);
299
300 // Assume that the concept decl has just one template parameter
301 // This parameter should have been added when CD was constructed
302 // in getTypedBufferConceptDecl
303 assert(CD->getTemplateParameters()->size() == 1 &&
304 "unexpected concept decl parameter count");
305 TemplateTypeParmDecl *ConceptTTPD =
306 dyn_cast<TemplateTypeParmDecl>(CD->getTemplateParameters()->getParam(0));
307
308 // this TemplateTypeParmDecl is the template for the resource, and is
309 // used to construct a template argumentthat will be used
310 // to construct the ImplicitConceptSpecializationDecl
312 Context, // AST context
313 Builder.Record->getDeclContext(), // DeclContext
315 /*D=*/0, // Depth in the template parameter list
316 /*P=*/0, // Position in the template parameter list
317 /*Id=*/nullptr, // Identifier for 'T'
318 /*Typename=*/true, // Indicates this is a 'typename' or 'class'
319 /*ParameterPack=*/false, // Not a parameter pack
320 /*HasTypeConstraint=*/false // Has no type constraint
321 );
322
323 T->setDeclContext(DC);
324
325 QualType ConceptTType = Context.getTypeDeclType(ConceptTTPD);
326
327 // this is the 2nd template argument node, on which
328 // the concept constraint is actually being applied: 'element_type'
329 TemplateArgument ConceptTA = TemplateArgument(ConceptTType);
330
331 QualType CSETType = Context.getTypeDeclType(T);
332
333 // this is the 1st template argument node, which represents
334 // the abstract type that a concept would refer to: 'T'
335 TemplateArgument CSETA = TemplateArgument(CSETType);
336
337 ImplicitConceptSpecializationDecl *ImplicitCSEDecl =
339 Context, Builder.Record->getDeclContext(), Loc, {CSETA});
340
341 // Constraint satisfaction is used to construct the
342 // ConceptSpecailizationExpr, and represents the 2nd Template Argument,
343 // located at the bottom of the sample AST above.
344 const ConstraintSatisfaction CS(CD, {ConceptTA});
347
348 TALI.addArgument(TAL);
349 const ASTTemplateArgumentListInfo *ATALI =
351
352 // In the concept reference, ATALI is what adds the extra
353 // TemplateArgument node underneath CSE
354 ConceptReference *CR =
355 ConceptReference::Create(Context, NNSLoc, Loc, DNI, CD, CD, ATALI);
356
358 ConceptSpecializationExpr::Create(Context, CR, ImplicitCSEDecl, &CS);
359
360 return CSE;
361}
362
365 if (Params.empty())
366 return Builder;
367
368 ASTContext &AST = Builder.SemaRef.Context;
370 CD ? constructConceptSpecializationExpr(Builder.SemaRef, CD) : nullptr;
371 auto *ParamList = TemplateParameterList::Create(
374 AST, Builder.Record->getDeclContext(), SourceLocation(),
375 DeclarationName(Builder.Record->getIdentifier()), ParamList,
376 Builder.Record);
377
378 Builder.Record->setDescribedClassTemplate(Builder.Template);
379 Builder.Template->setImplicit(true);
380 Builder.Template->setLexicalDeclContext(Builder.Record->getDeclContext());
381
382 // NOTE: setPreviousDecl before addDecl so new decl replace old decl when
383 // make visible.
384 Builder.Template->setPreviousDecl(Builder.PrevTemplate);
385 Builder.Record->getDeclContext()->addDecl(Builder.Template);
386 Params.clear();
387
388 return Builder;
389}
390
391Expr *BuiltinTypeMethodBuilder::convertPlaceholder(PlaceHolder PH) {
392 if (PH == PlaceHolder::Handle)
393 return getResourceHandleExpr();
394 if (PH == PlaceHolder::CounterHandle)
396
397 if (PH == PlaceHolder::LastStmt) {
398 assert(!StmtsList.empty() && "no statements in the list");
399 Stmt *LastStmt = StmtsList.pop_back_val();
400 assert(isa<ValueStmt>(LastStmt) && "last statement does not have a value");
401 return cast<ValueStmt>(LastStmt)->getExprStmt();
402 }
403
404 ASTContext &AST = DeclBuilder.SemaRef.getASTContext();
405 ParmVarDecl *ParamDecl = Method->getParamDecl(static_cast<unsigned>(PH));
406 return DeclRefExpr::Create(
407 AST, NestedNameSpecifierLoc(), SourceLocation(), ParamDecl, false,
409 ParamDecl->getType().getNonReferenceType(), VK_PRValue);
410}
411
412Expr *BuiltinTypeMethodBuilder::convertPlaceholder(LocalVar &Var) {
413 VarDecl *VD = Var.Decl;
414 assert(VD && "local variable is not declared");
415 return DeclRefExpr::Create(
416 VD->getASTContext(), NestedNameSpecifierLoc(), SourceLocation(), VD,
417 false, DeclarationNameInfo(VD->getDeclName(), SourceLocation()),
418 VD->getType(), VK_LValue);
419}
420
422 StringRef NameStr,
423 QualType ReturnTy,
424 bool IsConst, bool IsCtor,
425 StorageClass SC)
426 : DeclBuilder(DB), ReturnTy(ReturnTy), Method(nullptr), IsConst(IsConst),
427 IsCtor(IsCtor), SC(SC) {
428
429 assert((!NameStr.empty() || IsCtor) && "method needs a name");
430 assert(((IsCtor && !IsConst) || !IsCtor) && "constructor cannot be const");
431
432 ASTContext &AST = DB.SemaRef.getASTContext();
433 if (IsCtor) {
435 AST.getCanonicalTagType(DB.Record));
436 } else {
437 const IdentifierInfo &II =
438 AST.Idents.get(NameStr, tok::TokenKind::identifier);
439 Name = DeclarationName(&II);
440 }
441}
442
445 HLSLParamModifierAttr::Spelling Modifier) {
446 assert(Method == nullptr && "Cannot add param, method already created");
447 const IdentifierInfo &II = DeclBuilder.SemaRef.getASTContext().Idents.get(
448 Name, tok::TokenKind::identifier);
449 Params.emplace_back(II, Ty, Modifier);
450 return *this;
451}
452
453void BuiltinTypeMethodBuilder::createDecl() {
454 assert(Method == nullptr && "Method or constructor is already created");
455
456 // create function prototype
457 ASTContext &AST = DeclBuilder.SemaRef.getASTContext();
458 SmallVector<QualType> ParamTypes;
459 SmallVector<FunctionType::ExtParameterInfo> ParamExtInfos(Params.size());
460 uint32_t ArgIndex = 0;
461
462 // Create function prototype.
463 bool UseParamExtInfo = false;
464 for (Param &MP : Params) {
465 if (MP.Modifier != HLSLParamModifierAttr::Keyword_in) {
466 UseParamExtInfo = true;
467 FunctionType::ExtParameterInfo &PI = ParamExtInfos[ArgIndex];
468 ParamExtInfos[ArgIndex] =
469 PI.withABI(convertParamModifierToParamABI(MP.Modifier));
470 if (!MP.Ty->isDependentType())
471 MP.Ty = getInoutParameterType(AST, MP.Ty);
472 }
473 ParamTypes.emplace_back(MP.Ty);
474 ++ArgIndex;
475 }
476
477 FunctionProtoType::ExtProtoInfo ExtInfo;
478 if (UseParamExtInfo)
479 ExtInfo.ExtParameterInfos = ParamExtInfos.data();
480 if (IsConst)
481 ExtInfo.TypeQuals.addConst();
482
483 QualType FuncTy = AST.getFunctionType(ReturnTy, ParamTypes, ExtInfo);
484
485 // Create method or constructor declaration.
486 auto *TSInfo = AST.getTrivialTypeSourceInfo(FuncTy, SourceLocation());
487 DeclarationNameInfo NameInfo = DeclarationNameInfo(Name, SourceLocation());
488 if (IsCtor)
490 AST, DeclBuilder.Record, SourceLocation(), NameInfo, FuncTy, TSInfo,
491 ExplicitSpecifier(), false, true, false,
493 else
494 Method = CXXMethodDecl::Create(
495 AST, DeclBuilder.Record, SourceLocation(), NameInfo, FuncTy, TSInfo, SC,
496 false, false, ConstexprSpecKind::Unspecified, SourceLocation());
497
498 // Create params & set them to the method/constructor and function prototype.
500 unsigned CurScopeDepth = DeclBuilder.SemaRef.getCurScope()->getDepth();
501 auto FnProtoLoc =
502 Method->getTypeSourceInfo()->getTypeLoc().getAs<FunctionProtoTypeLoc>();
503 for (int I = 0, E = Params.size(); I != E; I++) {
504 Param &MP = Params[I];
505 ParmVarDecl *Parm = ParmVarDecl::Create(
506 AST, Method->getDeclContext(), SourceLocation(), SourceLocation(),
507 &MP.NameII, MP.Ty,
508 AST.getTrivialTypeSourceInfo(MP.Ty, SourceLocation()), SC_None,
509 nullptr);
510 if (MP.Modifier != HLSLParamModifierAttr::Keyword_in) {
511 auto *Mod =
512 HLSLParamModifierAttr::Create(AST, SourceRange(), MP.Modifier);
513 Parm->addAttr(Mod);
514 }
515 Parm->setScopeInfo(CurScopeDepth, I);
516 ParmDecls.push_back(Parm);
517 FnProtoLoc.setParam(I, Parm);
518 }
519 Method->setParams({ParmDecls});
520}
521
523 ensureCompleteDecl();
524
525 ASTContext &AST = DeclBuilder.SemaRef.getASTContext();
527 AST, SourceLocation(), Method->getFunctionObjectParameterType(), true);
528 FieldDecl *HandleField = DeclBuilder.getResourceHandleField();
529 return MemberExpr::CreateImplicit(AST, This, false, HandleField,
530 HandleField->getType(), VK_LValue,
532}
533
535 ensureCompleteDecl();
536
537 ASTContext &AST = DeclBuilder.SemaRef.getASTContext();
539 AST, SourceLocation(), Method->getFunctionObjectParameterType(), true);
540 FieldDecl *HandleField = DeclBuilder.getResourceCounterHandleField();
541 return MemberExpr::CreateImplicit(AST, This, false, HandleField,
542 HandleField->getType(), VK_LValue,
544}
545
548 ensureCompleteDecl();
549
550 assert(Var.Decl == nullptr && "local variable is already declared");
551
552 ASTContext &AST = DeclBuilder.SemaRef.getASTContext();
553 Var.Decl = VarDecl::Create(
554 AST, Method, SourceLocation(), SourceLocation(),
555 &AST.Idents.get(Var.Name, tok::TokenKind::identifier), Var.Ty,
557 DeclStmt *DS = new (AST) clang::DeclStmt(DeclGroupRef(Var.Decl),
559 StmtsList.push_back(DS);
560 return *this;
561}
562
564 ASTContext &AST = DeclBuilder.SemaRef.getASTContext();
566 AST, SourceLocation(), Method->getFunctionObjectParameterType(),
567 /*IsImplicit=*/true);
568 StmtsList.push_back(ThisExpr);
569 return *this;
570}
571
572template <typename... Ts>
575 QualType ReturnType, Ts... ArgSpecs) {
576 ensureCompleteDecl();
577
578 std::array<Expr *, sizeof...(ArgSpecs)> Args{
579 convertPlaceholder(std::forward<Ts>(ArgSpecs))...};
580
581 ASTContext &AST = DeclBuilder.SemaRef.getASTContext();
582 FunctionDecl *FD = lookupBuiltinFunction(DeclBuilder.SemaRef, BuiltinName);
584 AST, NestedNameSpecifierLoc(), SourceLocation(), FD, false,
586
587 auto *ImpCast = ImplicitCastExpr::Create(
588 AST, AST.getPointerType(FD->getType()), CK_BuiltinFnToFnPtr, DRE, nullptr,
590
591 if (ReturnType.isNull())
592 ReturnType = FD->getReturnType();
593
594 Expr *Call = CallExpr::Create(AST, ImpCast, Args, ReturnType, VK_PRValue,
596 StmtsList.push_back(Call);
597 return *this;
598}
599
600template <typename TLHS, typename TRHS>
602 Expr *LHSExpr = convertPlaceholder(LHS);
603 Expr *RHSExpr = convertPlaceholder(RHS);
604 Stmt *AssignStmt = BinaryOperator::Create(
605 DeclBuilder.SemaRef.getASTContext(), LHSExpr, RHSExpr, BO_Assign,
608 StmtsList.push_back(AssignStmt);
609 return *this;
610}
611
612template <typename T>
614 Expr *PtrExpr = convertPlaceholder(Ptr);
615 Expr *Deref =
616 UnaryOperator::Create(DeclBuilder.SemaRef.getASTContext(), PtrExpr,
617 UO_Deref, PtrExpr->getType()->getPointeeType(),
619 /*CanOverflow=*/false, FPOptionsOverride());
620 StmtsList.push_back(Deref);
621 return *this;
622}
623
624template <typename T>
627 ensureCompleteDecl();
628
629 Expr *ResourceExpr = convertPlaceholder(ResourceRecord);
630
631 ASTContext &AST = DeclBuilder.SemaRef.getASTContext();
632 FieldDecl *HandleField = DeclBuilder.getResourceHandleField();
634 AST, ResourceExpr, false, HandleField, HandleField->getType(), VK_LValue,
636 StmtsList.push_back(HandleExpr);
637 return *this;
638}
639
640template <typename ResourceT, typename ValueT>
643 ValueT HandleValue) {
644 return setFieldOnResource(ResourceRecord, HandleValue,
645 DeclBuilder.getResourceHandleField());
646}
647
648template <typename ResourceT, typename ValueT>
651 ResourceT ResourceRecord, ValueT HandleValue) {
652 return setFieldOnResource(ResourceRecord, HandleValue,
653 DeclBuilder.getResourceCounterHandleField());
654}
655
656template <typename ResourceT, typename ValueT>
657BuiltinTypeMethodBuilder &BuiltinTypeMethodBuilder::setFieldOnResource(
658 ResourceT ResourceRecord, ValueT HandleValue, FieldDecl *HandleField) {
659 ensureCompleteDecl();
660
661 Expr *ResourceExpr = convertPlaceholder(ResourceRecord);
662 Expr *HandleValueExpr = convertPlaceholder(HandleValue);
663
664 ASTContext &AST = DeclBuilder.SemaRef.getASTContext();
665 MemberExpr *HandleMemberExpr = MemberExpr::CreateImplicit(
666 AST, ResourceExpr, false, HandleField, HandleField->getType(), VK_LValue,
668 Stmt *AssignStmt = BinaryOperator::Create(
669 DeclBuilder.SemaRef.getASTContext(), HandleMemberExpr, HandleValueExpr,
670 BO_Assign, HandleMemberExpr->getType(), ExprValueKind::VK_PRValue,
672 StmtsList.push_back(AssignStmt);
673 return *this;
674}
675
676template <typename T>
677BuiltinTypeMethodBuilder &
679 ensureCompleteDecl();
680
681 Expr *ResourceExpr = convertPlaceholder(ResourceRecord);
682
683 ASTContext &AST = DeclBuilder.SemaRef.getASTContext();
684 FieldDecl *HandleField = DeclBuilder.getResourceCounterHandleField();
686 AST, ResourceExpr, false, HandleField, HandleField->getType(), VK_LValue,
688 StmtsList.push_back(HandleExpr);
689 return *this;
690}
691
692template <typename T>
694 ensureCompleteDecl();
695
696 Expr *ReturnValueExpr = convertPlaceholder(ReturnValue);
697 ASTContext &AST = DeclBuilder.SemaRef.getASTContext();
698
699 QualType Ty = ReturnValueExpr->getType();
700 if (Ty->isRecordType()) {
701 // For record types, create a call to copy constructor to ensure proper copy
702 // semantics.
703 auto *ICE =
704 ImplicitCastExpr::Create(AST, Ty.withConst(), CK_NoOp, ReturnValueExpr,
705 nullptr, VK_XValue, FPOptionsOverride());
706 CXXConstructorDecl *CD = lookupCopyConstructor(Ty);
707 assert(CD && "no copy constructor found");
708 ReturnValueExpr = CXXConstructExpr::Create(
709 AST, Ty, SourceLocation(), CD, /*Elidable=*/false, {ICE},
710 /*HadMultipleCandidates=*/false, /*ListInitialization=*/false,
711 /*StdInitListInitialization=*/false,
712 /*ZeroInitListInitialization=*/false, CXXConstructionKind::Complete,
713 SourceRange());
714 }
715 StmtsList.push_back(
716 ReturnStmt::Create(AST, SourceLocation(), ReturnValueExpr, nullptr));
717 return *this;
718}
719
721 assert(!DeclBuilder.Record->isCompleteDefinition() &&
722 "record is already complete");
723
724 ensureCompleteDecl();
725
726 if (!Method->hasBody()) {
727 ASTContext &AST = DeclBuilder.SemaRef.getASTContext();
728 assert((ReturnTy == AST.VoidTy || !StmtsList.empty()) &&
729 "nothing to return from non-void method");
730 if (ReturnTy != AST.VoidTy) {
731 if (Expr *LastExpr = dyn_cast<Expr>(StmtsList.back())) {
732 assert(AST.hasSameUnqualifiedType(LastExpr->getType(),
733 ReturnTy.getNonReferenceType()) &&
734 "Return type of the last statement must match the return type "
735 "of the method");
736 if (!isa<ReturnStmt>(LastExpr)) {
737 StmtsList.pop_back();
738 StmtsList.push_back(
739 ReturnStmt::Create(AST, SourceLocation(), LastExpr, nullptr));
740 }
741 }
742 }
743
744 Method->setBody(CompoundStmt::Create(AST, StmtsList, FPOptionsOverride(),
746 Method->setLexicalDeclContext(DeclBuilder.Record);
747 Method->setAccess(AS_public);
748 Method->addAttr(AlwaysInlineAttr::CreateImplicit(
749 AST, SourceRange(), AlwaysInlineAttr::CXX11_clang_always_inline));
750 DeclBuilder.Record->addDecl(Method);
751 }
752 return DeclBuilder;
753}
754
756 : SemaRef(SemaRef), Record(R) {
757 Record->startDefinition();
758 Template = Record->getDescribedClassTemplate();
759}
760
762 NamespaceDecl *Namespace,
763 StringRef Name)
764 : SemaRef(SemaRef), HLSLNamespace(Namespace) {
765 ASTContext &AST = SemaRef.getASTContext();
766 IdentifierInfo &II = AST.Idents.get(Name, tok::TokenKind::identifier);
767
769 CXXRecordDecl *PrevDecl = nullptr;
770 if (SemaRef.LookupQualifiedName(Result, HLSLNamespace)) {
771 // Declaration already exists (from precompiled headers)
772 NamedDecl *Found = Result.getFoundDecl();
773 if (auto *TD = dyn_cast<ClassTemplateDecl>(Found)) {
774 PrevDecl = TD->getTemplatedDecl();
775 PrevTemplate = TD;
776 } else
777 PrevDecl = dyn_cast<CXXRecordDecl>(Found);
778 assert(PrevDecl && "Unexpected lookup result type.");
779 }
780
781 if (PrevDecl && PrevDecl->isCompleteDefinition()) {
782 Record = PrevDecl;
783 Template = PrevTemplate;
784 return;
785 }
786
787 Record =
788 CXXRecordDecl::Create(AST, TagDecl::TagKind::Class, HLSLNamespace,
789 SourceLocation(), SourceLocation(), &II, PrevDecl);
790 Record->setImplicit(true);
791 Record->setLexicalDeclContext(HLSLNamespace);
792 Record->setHasExternalLexicalStorage();
793
794 // Don't let anyone derive from built-in types.
795 Record->addAttr(
796 FinalAttr::CreateImplicit(AST, SourceRange(), FinalAttr::Keyword_final));
797}
798
800 if (HLSLNamespace && !Template && Record->getDeclContext() == HLSLNamespace)
801 HLSLNamespace->addDecl(Record);
802}
803
807 AccessSpecifier Access) {
808 assert(!Record->isCompleteDefinition() && "record is already complete");
809 assert(Record->isBeingDefined() &&
810 "Definition must be started before adding members!");
811 ASTContext &AST = Record->getASTContext();
812
813 IdentifierInfo &II = AST.Idents.get(Name, tok::TokenKind::identifier);
814 TypeSourceInfo *MemTySource =
816 auto *Field = FieldDecl::Create(
817 AST, Record, SourceLocation(), SourceLocation(), &II, Type, MemTySource,
818 nullptr, false, InClassInitStyle::ICIS_NoInit);
819 Field->setAccess(Access);
820 Field->setImplicit(true);
821 for (Attr *A : Attrs) {
822 if (A)
823 Field->addAttr(A);
824 }
825
826 Record->addDecl(Field);
827 Fields[Name] = Field;
828 return *this;
829}
830
832BuiltinTypeDeclBuilder::addBufferHandles(ResourceClass RC, bool IsROV,
833 bool RawBuffer, bool HasCounter,
834 AccessSpecifier Access) {
835 addHandleMember(RC, IsROV, RawBuffer, Access);
836 if (HasCounter)
837 addCounterHandleMember(RC, IsROV, RawBuffer, Access);
838 return *this;
839}
840
841BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addHandleMember(
842 ResourceClass RC, bool IsROV, bool RawBuffer, AccessSpecifier Access) {
843 return addResourceMember("__handle", RC, IsROV, RawBuffer,
844 /*IsCounter=*/false, Access);
845}
846
847BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addCounterHandleMember(
848 ResourceClass RC, bool IsROV, bool RawBuffer, AccessSpecifier Access) {
849 return addResourceMember("__counter_handle", RC, IsROV, RawBuffer,
850 /*IsCounter=*/true, Access);
851}
852
853BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addResourceMember(
854 StringRef MemberName, ResourceClass RC, bool IsROV, bool RawBuffer,
855 bool IsCounter, AccessSpecifier Access) {
856 assert(!Record->isCompleteDefinition() && "record is already complete");
857
858 ASTContext &Ctx = SemaRef.getASTContext();
859 TypeSourceInfo *ElementTypeInfo =
860 Ctx.getTrivialTypeSourceInfo(getHandleElementType(), SourceLocation());
861
862 // add handle member with resource type attributes
863 QualType AttributedResTy = QualType();
865 HLSLResourceClassAttr::CreateImplicit(Ctx, RC),
866 IsROV ? HLSLROVAttr::CreateImplicit(Ctx) : nullptr,
867 RawBuffer ? HLSLRawBufferAttr::CreateImplicit(Ctx) : nullptr,
868 ElementTypeInfo
869 ? HLSLContainedTypeAttr::CreateImplicit(Ctx, ElementTypeInfo)
870 : nullptr};
871 if (IsCounter)
872 Attrs.push_back(HLSLIsCounterAttr::CreateImplicit(Ctx));
873
874 if (CreateHLSLAttributedResourceType(SemaRef, Ctx.HLSLResourceTy, Attrs,
875 AttributedResTy))
876 addMemberVariable(MemberName, AttributedResTy, {}, Access);
877 return *this;
878}
879
880// Adds default constructor to the resource class:
881// Resource::Resource()
883 assert(!Record->isCompleteDefinition() && "record is already complete");
884
885 using PH = BuiltinTypeMethodBuilder::PlaceHolder;
886 QualType HandleType = getResourceHandleField()->getType();
887 return BuiltinTypeMethodBuilder(*this, "", SemaRef.getASTContext().VoidTy,
888 false, true)
889 .callBuiltin("__builtin_hlsl_resource_uninitializedhandle", HandleType,
890 PH::Handle)
891 .assign(PH::Handle, PH::LastStmt)
892 .finalize();
893}
894
897 if (HasCounter) {
898 addCreateFromBindingWithImplicitCounter();
899 addCreateFromImplicitBindingWithImplicitCounter();
900 } else {
901 addCreateFromBinding();
902 addCreateFromImplicitBinding();
903 }
904 return *this;
905}
906
907// Adds static method that initializes resource from binding:
908//
909// static Resource<T> __createFromBinding(unsigned registerNo,
910// unsigned spaceNo, int range,
911// unsigned index, const char *name) {
912// Resource<T> tmp;
913// tmp.__handle = __builtin_hlsl_resource_handlefrombinding(
914// tmp.__handle, registerNo, spaceNo,
915// range, index, name);
916// return tmp;
917// }
918BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addCreateFromBinding() {
919 assert(!Record->isCompleteDefinition() && "record is already complete");
920
921 using PH = BuiltinTypeMethodBuilder::PlaceHolder;
922 ASTContext &AST = SemaRef.getASTContext();
923 QualType HandleType = getResourceHandleField()->getType();
925 BuiltinTypeMethodBuilder::LocalVar TmpVar("tmp", RecordType);
926
927 return BuiltinTypeMethodBuilder(*this, "__createFromBinding", RecordType,
928 false, false, SC_Static)
929 .addParam("registerNo", AST.UnsignedIntTy)
930 .addParam("spaceNo", AST.UnsignedIntTy)
931 .addParam("range", AST.IntTy)
932 .addParam("index", AST.UnsignedIntTy)
933 .addParam("name", AST.getPointerType(AST.CharTy.withConst()))
934 .declareLocalVar(TmpVar)
935 .accessHandleFieldOnResource(TmpVar)
936 .callBuiltin("__builtin_hlsl_resource_handlefrombinding", HandleType,
937 PH::LastStmt, PH::_0, PH::_1, PH::_2, PH::_3, PH::_4)
938 .setHandleFieldOnResource(TmpVar, PH::LastStmt)
939 .returnValue(TmpVar)
940 .finalize();
941}
942
943// Adds static method that initializes resource from binding:
944//
945// static Resource<T> __createFromImplicitBinding(unsigned orderId,
946// unsigned spaceNo, int range,
947// unsigned index,
948// const char *name) {
949// Resource<T> tmp;
950// tmp.__handle = __builtin_hlsl_resource_handlefromimplicitbinding(
951// tmp.__handle, spaceNo,
952// range, index, orderId, name);
953// return tmp;
954// }
955BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addCreateFromImplicitBinding() {
956 assert(!Record->isCompleteDefinition() && "record is already complete");
957
958 using PH = BuiltinTypeMethodBuilder::PlaceHolder;
959 ASTContext &AST = SemaRef.getASTContext();
960 QualType HandleType = getResourceHandleField()->getType();
962 BuiltinTypeMethodBuilder::LocalVar TmpVar("tmp", RecordType);
963
964 return BuiltinTypeMethodBuilder(*this, "__createFromImplicitBinding",
965 RecordType, false, false, SC_Static)
966 .addParam("orderId", AST.UnsignedIntTy)
967 .addParam("spaceNo", AST.UnsignedIntTy)
968 .addParam("range", AST.IntTy)
969 .addParam("index", AST.UnsignedIntTy)
970 .addParam("name", AST.getPointerType(AST.CharTy.withConst()))
971 .declareLocalVar(TmpVar)
972 .accessHandleFieldOnResource(TmpVar)
973 .callBuiltin("__builtin_hlsl_resource_handlefromimplicitbinding",
974 HandleType, PH::LastStmt, PH::_0, PH::_1, PH::_2, PH::_3,
975 PH::_4)
976 .setHandleFieldOnResource(TmpVar, PH::LastStmt)
977 .returnValue(TmpVar)
978 .finalize();
979}
980
981// Adds static method that initializes resource from binding:
982//
983// static Resource<T>
984// __createFromBindingWithImplicitCounter(unsigned registerNo,
985// unsigned spaceNo, int range,
986// unsigned index, const char *name,
987// unsigned counterOrderId) {
988// Resource<T> tmp;
989// tmp.__handle = __builtin_hlsl_resource_handlefrombinding(
990// tmp.__handle, registerNo, spaceNo, range, index, name);
991// tmp.__counter_handle =
992// __builtin_hlsl_resource_counterhandlefromimplicitbinding(
993// tmp.__handle, counterOrderId, spaceNo);
994// return tmp;
995// }
997BuiltinTypeDeclBuilder::addCreateFromBindingWithImplicitCounter() {
998 assert(!Record->isCompleteDefinition() && "record is already complete");
999
1000 using PH = BuiltinTypeMethodBuilder::PlaceHolder;
1001 ASTContext &AST = SemaRef.getASTContext();
1002 QualType HandleType = getResourceHandleField()->getType();
1003 QualType RecordType = AST.getTypeDeclType(cast<TypeDecl>(Record));
1004 BuiltinTypeMethodBuilder::LocalVar TmpVar("tmp", RecordType);
1005
1006 return BuiltinTypeMethodBuilder(*this,
1007 "__createFromBindingWithImplicitCounter",
1008 RecordType, false, false, SC_Static)
1009 .addParam("registerNo", AST.UnsignedIntTy)
1010 .addParam("spaceNo", AST.UnsignedIntTy)
1011 .addParam("range", AST.IntTy)
1012 .addParam("index", AST.UnsignedIntTy)
1013 .addParam("name", AST.getPointerType(AST.CharTy.withConst()))
1014 .addParam("counterOrderId", AST.UnsignedIntTy)
1015 .declareLocalVar(TmpVar)
1016 .accessHandleFieldOnResource(TmpVar)
1017 .callBuiltin("__builtin_hlsl_resource_handlefrombinding", HandleType,
1018 PH::LastStmt, PH::_0, PH::_1, PH::_2, PH::_3, PH::_4)
1019 .setHandleFieldOnResource(TmpVar, PH::LastStmt)
1020 .accessHandleFieldOnResource(TmpVar)
1021 .callBuiltin("__builtin_hlsl_resource_counterhandlefromimplicitbinding",
1022 HandleType, PH::LastStmt, PH::_5, PH::_1)
1023 .setCounterHandleFieldOnResource(TmpVar, PH::LastStmt)
1024 .returnValue(TmpVar)
1025 .finalize();
1026}
1027
1028// Adds static method that initializes resource from binding:
1029//
1030// static Resource<T>
1031// __createFromImplicitBindingWithImplicitCounter(unsigned orderId,
1032// unsigned spaceNo, int range,
1033// unsigned index,
1034// const char *name,
1035// unsigned counterOrderId) {
1036// Resource<T> tmp;
1037// tmp.__handle = __builtin_hlsl_resource_handlefromimplicitbinding(
1038// tmp.__handle, orderId, spaceNo, range, index, name);
1039// tmp.__counter_handle =
1040// __builtin_hlsl_resource_counterhandlefromimplicitbinding(
1041// tmp.__handle, counterOrderId, spaceNo);
1042// return tmp;
1043// }
1045BuiltinTypeDeclBuilder::addCreateFromImplicitBindingWithImplicitCounter() {
1046 assert(!Record->isCompleteDefinition() && "record is already complete");
1047
1048 using PH = BuiltinTypeMethodBuilder::PlaceHolder;
1049 ASTContext &AST = SemaRef.getASTContext();
1050 QualType HandleType = getResourceHandleField()->getType();
1051 QualType RecordType = AST.getTypeDeclType(cast<TypeDecl>(Record));
1052 BuiltinTypeMethodBuilder::LocalVar TmpVar("tmp", RecordType);
1053
1055 *this, "__createFromImplicitBindingWithImplicitCounter",
1056 RecordType, false, false, SC_Static)
1057 .addParam("orderId", AST.UnsignedIntTy)
1058 .addParam("spaceNo", AST.UnsignedIntTy)
1059 .addParam("range", AST.IntTy)
1060 .addParam("index", AST.UnsignedIntTy)
1061 .addParam("name", AST.getPointerType(AST.CharTy.withConst()))
1062 .addParam("counterOrderId", AST.UnsignedIntTy)
1063 .declareLocalVar(TmpVar)
1064 .accessHandleFieldOnResource(TmpVar)
1065 .callBuiltin("__builtin_hlsl_resource_handlefromimplicitbinding",
1066 HandleType, PH::LastStmt, PH::_0, PH::_1, PH::_2, PH::_3,
1067 PH::_4)
1068 .setHandleFieldOnResource(TmpVar, PH::LastStmt)
1069 .accessHandleFieldOnResource(TmpVar)
1070 .callBuiltin("__builtin_hlsl_resource_counterhandlefromimplicitbinding",
1071 HandleType, PH::LastStmt, PH::_5, PH::_1)
1072 .setCounterHandleFieldOnResource(TmpVar, PH::LastStmt)
1073 .returnValue(TmpVar)
1074 .finalize();
1075}
1076
1078 assert(!Record->isCompleteDefinition() && "record is already complete");
1079
1080 ASTContext &AST = SemaRef.getASTContext();
1081 QualType RecordType = AST.getCanonicalTagType(Record);
1082 QualType ConstRecordType = RecordType.withConst();
1083 QualType ConstRecordRefType = AST.getLValueReferenceType(ConstRecordType);
1084
1085 using PH = BuiltinTypeMethodBuilder::PlaceHolder;
1086
1087 BuiltinTypeMethodBuilder MMB(*this, /*Name=*/"", AST.VoidTy,
1088 /*IsConst=*/false, /*IsCtor=*/true);
1089 MMB.addParam("other", ConstRecordRefType)
1091 .assign(PH::Handle, PH::LastStmt);
1092
1093 if (getResourceCounterHandleField())
1094 MMB.accessCounterHandleFieldOnResource(PH::_0).assign(PH::CounterHandle,
1095 PH::LastStmt);
1096
1097 return MMB.finalize();
1098}
1099
1101 assert(!Record->isCompleteDefinition() && "record is already complete");
1102
1103 ASTContext &AST = SemaRef.getASTContext();
1104 QualType RecordType = AST.getCanonicalTagType(Record);
1105 QualType ConstRecordType = RecordType.withConst();
1106 QualType ConstRecordRefType = AST.getLValueReferenceType(ConstRecordType);
1107 QualType RecordRefType = AST.getLValueReferenceType(RecordType);
1108
1109 using PH = BuiltinTypeMethodBuilder::PlaceHolder;
1111 BuiltinTypeMethodBuilder MMB(*this, Name, RecordRefType);
1112 MMB.addParam("other", ConstRecordRefType)
1114 .assign(PH::Handle, PH::LastStmt);
1115
1116 if (getResourceCounterHandleField())
1117 MMB.accessCounterHandleFieldOnResource(PH::_0).assign(PH::CounterHandle,
1118 PH::LastStmt);
1119
1120 return MMB.returnThis().finalize();
1121}
1122
1124 ASTContext &AST = Record->getASTContext();
1125 DeclarationName Subscript =
1126 AST.DeclarationNames.getCXXOperatorName(OO_Subscript);
1127
1128 addHandleAccessFunction(Subscript, /*IsConst=*/true, /*IsRef=*/true);
1129 if (getResourceAttrs().ResourceClass == llvm::dxil::ResourceClass::UAV)
1130 addHandleAccessFunction(Subscript, /*IsConst=*/false, /*IsRef=*/true);
1131
1132 return *this;
1133}
1134
1136 assert(!Record->isCompleteDefinition() && "record is already complete");
1137
1138 ASTContext &AST = Record->getASTContext();
1139 IdentifierInfo &II = AST.Idents.get("Load", tok::TokenKind::identifier);
1140 DeclarationName Load(&II);
1141 // TODO: We also need versions with status for CheckAccessFullyMapped.
1142 addHandleAccessFunction(Load, /*IsConst=*/false, /*IsRef=*/false);
1143
1144 return *this;
1145}
1146
1147FieldDecl *BuiltinTypeDeclBuilder::getResourceHandleField() const {
1148 auto I = Fields.find("__handle");
1149 assert(I != Fields.end() &&
1150 I->second->getType()->isHLSLAttributedResourceType() &&
1151 "record does not have resource handle field");
1152 return I->second;
1153}
1154
1155FieldDecl *BuiltinTypeDeclBuilder::getResourceCounterHandleField() const {
1156 auto I = Fields.find("__counter_handle");
1157 if (I == Fields.end() ||
1158 !I->second->getType()->isHLSLAttributedResourceType())
1159 return nullptr;
1160 return I->second;
1161}
1162
1163QualType BuiltinTypeDeclBuilder::getFirstTemplateTypeParam() {
1164 assert(Template && "record it not a template");
1165 if (const auto *TTD = dyn_cast<TemplateTypeParmDecl>(
1166 Template->getTemplateParameters()->getParam(0))) {
1167 return QualType(TTD->getTypeForDecl(), 0);
1168 }
1169 return QualType();
1170}
1171
1172QualType BuiltinTypeDeclBuilder::getHandleElementType() {
1173 if (Template)
1174 return getFirstTemplateTypeParam();
1175 // TODO: Should we default to VoidTy? Using `i8` is arguably ambiguous.
1176 return SemaRef.getASTContext().Char8Ty;
1177}
1178
1179HLSLAttributedResourceType::Attributes
1180BuiltinTypeDeclBuilder::getResourceAttrs() const {
1181 QualType HandleType = getResourceHandleField()->getType();
1182 return cast<HLSLAttributedResourceType>(HandleType)->getAttrs();
1183}
1184
1186 assert(!Record->isCompleteDefinition() && "record is already complete");
1187 assert(Record->isBeingDefined() &&
1188 "Definition must be started before completing it.");
1189
1190 Record->completeDefinition();
1191 return *this;
1192}
1193
1194Expr *BuiltinTypeDeclBuilder::getConstantIntExpr(int value) {
1195 ASTContext &AST = SemaRef.getASTContext();
1197 AST, llvm::APInt(AST.getTypeSize(AST.IntTy), value, true), AST.IntTy,
1198 SourceLocation());
1199}
1200
1203 ConceptDecl *CD = nullptr) {
1204 if (Record->isCompleteDefinition()) {
1205 assert(Template && "existing record it not a template");
1206 assert(Template->getTemplateParameters()->size() == Names.size() &&
1207 "template param count mismatch");
1208 return *this;
1209 }
1210
1212 for (StringRef Name : Names)
1213 Builder.addTypeParameter(Name);
1214 return Builder.finalizeTemplateArgs(CD);
1215}
1216
1218 using PH = BuiltinTypeMethodBuilder::PlaceHolder;
1219 return BuiltinTypeMethodBuilder(*this, "IncrementCounter",
1220 SemaRef.getASTContext().UnsignedIntTy)
1221 .callBuiltin("__builtin_hlsl_buffer_update_counter", QualType(),
1222 PH::CounterHandle, getConstantIntExpr(1))
1223 .finalize();
1224}
1225
1227 using PH = BuiltinTypeMethodBuilder::PlaceHolder;
1228 return BuiltinTypeMethodBuilder(*this, "DecrementCounter",
1229 SemaRef.getASTContext().UnsignedIntTy)
1230 .callBuiltin("__builtin_hlsl_buffer_update_counter", QualType(),
1231 PH::CounterHandle, getConstantIntExpr(-1))
1232 .finalize();
1233}
1234
1237 bool IsConst, bool IsRef) {
1238 assert(!Record->isCompleteDefinition() && "record is already complete");
1239 ASTContext &AST = SemaRef.getASTContext();
1240 using PH = BuiltinTypeMethodBuilder::PlaceHolder;
1241
1242 QualType ElemTy = getHandleElementType();
1243 QualType AddrSpaceElemTy =
1245 QualType ElemPtrTy = AST.getPointerType(AddrSpaceElemTy);
1246 QualType ReturnTy;
1247
1248 if (IsRef) {
1249 ReturnTy = AddrSpaceElemTy;
1250 if (IsConst)
1251 ReturnTy.addConst();
1252 ReturnTy = AST.getLValueReferenceType(ReturnTy);
1253 } else {
1254 ReturnTy = ElemTy;
1255 if (IsConst)
1256 ReturnTy.addConst();
1257 }
1258
1259 return BuiltinTypeMethodBuilder(*this, Name, ReturnTy, IsConst)
1260 .addParam("Index", AST.UnsignedIntTy)
1261 .callBuiltin("__builtin_hlsl_resource_getpointer", ElemPtrTy, PH::Handle,
1262 PH::_0)
1263 .dereference(PH::LastStmt)
1264 .finalize();
1265}
1266
1268 using PH = BuiltinTypeMethodBuilder::PlaceHolder;
1269 ASTContext &AST = SemaRef.getASTContext();
1270 QualType ElemTy = getHandleElementType();
1271 QualType AddrSpaceElemTy =
1273 return BuiltinTypeMethodBuilder(*this, "Append", AST.VoidTy)
1274 .addParam("value", ElemTy)
1275 .callBuiltin("__builtin_hlsl_buffer_update_counter", AST.UnsignedIntTy,
1276 PH::CounterHandle, getConstantIntExpr(1))
1277 .callBuiltin("__builtin_hlsl_resource_getpointer",
1278 AST.getPointerType(AddrSpaceElemTy), PH::Handle,
1279 PH::LastStmt)
1280 .dereference(PH::LastStmt)
1281 .assign(PH::LastStmt, PH::_0)
1282 .finalize();
1283}
1284
1286 using PH = BuiltinTypeMethodBuilder::PlaceHolder;
1287 ASTContext &AST = SemaRef.getASTContext();
1288 QualType ElemTy = getHandleElementType();
1289 QualType AddrSpaceElemTy =
1291 return BuiltinTypeMethodBuilder(*this, "Consume", ElemTy)
1292 .callBuiltin("__builtin_hlsl_buffer_update_counter", AST.UnsignedIntTy,
1293 PH::CounterHandle, getConstantIntExpr(-1))
1294 .callBuiltin("__builtin_hlsl_resource_getpointer",
1295 AST.getPointerType(AddrSpaceElemTy), PH::Handle,
1296 PH::LastStmt)
1297 .dereference(PH::LastStmt)
1298 .finalize();
1299}
1300
1303 using PH = BuiltinTypeMethodBuilder::PlaceHolder;
1304 ASTContext &AST = SemaRef.getASTContext();
1305 QualType UIntTy = AST.UnsignedIntTy;
1306
1307 QualType HandleTy = getResourceHandleField()->getType();
1308 auto *AttrResTy = cast<HLSLAttributedResourceType>(HandleTy.getTypePtr());
1309
1310 // Structured buffers except {RW}ByteAddressBuffer have overload
1311 // GetDimensions(out uint numStructs, out uint stride).
1312 if (AttrResTy->getAttrs().RawBuffer &&
1313 AttrResTy->getContainedType() != AST.Char8Ty) {
1314 return BuiltinTypeMethodBuilder(*this, "GetDimensions", AST.VoidTy)
1315 .addParam("numStructs", UIntTy, HLSLParamModifierAttr::Keyword_out)
1316 .addParam("stride", UIntTy, HLSLParamModifierAttr::Keyword_out)
1317 .callBuiltin("__builtin_hlsl_resource_getdimensions_x", QualType(),
1318 PH::Handle, PH::_0)
1319 .callBuiltin("__builtin_hlsl_resource_getstride", QualType(),
1320 PH::Handle, PH::_1)
1321 .finalize();
1322 }
1323
1324 // Typed buffers and {RW}ByteAddressBuffer have overload
1325 // GetDimensions(out uint dim).
1326 return BuiltinTypeMethodBuilder(*this, "GetDimensions", AST.VoidTy)
1327 .addParam("dim", UIntTy, HLSLParamModifierAttr::Keyword_out)
1328 .callBuiltin("__builtin_hlsl_resource_getdimensions_x", QualType(),
1329 PH::Handle, PH::_0)
1330 .finalize();
1331}
1332
1333} // namespace hlsl
1334} // namespace clang
Defines the clang::ASTContext interface.
llvm::dxil::ResourceClass ResourceClass
Defines the C++ Decl subclasses, other than those for templates (found in DeclTemplate....
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.
if(__y==0) return __x
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition ASTContext.h:220
QualType getPointerType(QualType T) const
Return the uniqued reference to the type for a pointer to the specified type.
QualType getLValueReferenceType(QualType T, bool SpelledAsLValue=true) const
Return the uniqued reference to the type for an lvalue reference to the specified type.
TypeSourceInfo * getTrivialTypeSourceInfo(QualType T, SourceLocation Loc=SourceLocation()) const
Allocate a TypeSourceInfo where all locations have been initialized to a given location,...
CanQualType CharTy
CanQualType IntTy
QualType getTypeDeclType(ElaboratedTypeKeyword Keyword, NestedNameSpecifier Qualifier, const TypeDecl *Decl) const
CanQualType UnsignedIntTy
a trap message and trap category.
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition ASTContext.h:220
DeclarationNameTable DeclarationNames
Definition ASTContext.h:776
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:772
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 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
Attr - This represents one attribute.
Definition Attr.h:45
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:4977
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:1180
Represents a C++ constructor within a class.
Definition DeclCXX.h:2604
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:2968
Represents a static or instance method of a struct/union/class.
Definition DeclCXX.h:2129
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:2488
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:132
Represents the this expression in C++.
Definition ExprCXX.h:1155
static CXXThisExpr * Create(const ASTContext &Ctx, SourceLocation L, QualType Ty, bool IsImplicit)
Definition ExprCXX.cpp:1585
static CallExpr * Create(const ASTContext &Ctx, Expr *Fn, ArrayRef< Expr * > Args, QualType Ty, ExprValueKind VK, SourceLocation RParenLoc, FPOptionsOverride FPFeatures, unsigned MinNumArgs=0, ADLCallKind UsesADL=NotADL)
Create a call expression.
Definition Expr.cpp:1513
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:394
Declaration of a C++20 concept.
A reference to a concept and its template args, as it appears in the code.
Definition ASTConcept.h:130
static ConceptReference * Create(const ASTContext &C, NestedNameSpecifierLoc NNS, SourceLocation TemplateKWLoc, DeclarationNameInfo ConceptNameInfo, NamedDecl *FoundDecl, TemplateDecl *NamedConcept, const ASTTemplateArgumentListInfo *ArgsAsWritten)
Represents the specialization of a concept - evaluates to a prvalue of type bool.
static ConceptSpecializationExpr * Create(const ASTContext &C, ConceptReference *ConceptRef, ImplicitConceptSpecializationDecl *SpecDecl, const ConstraintSatisfaction *Satisfaction)
The result of a constraint satisfaction check, containing the necessary information to diagnose an un...
Definition ASTConcept.h:47
DeclContext - This is used only as base class of specific decl types that can act as declaration cont...
Definition DeclBase.h:1449
A reference to a declared variable, function, enum, etc.
Definition Expr.h:1270
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:484
DeclStmt - Adaptor class for mixing declarations with statements and expressions.
Definition Stmt.h:1611
Decl - This represents one declaration (or definition), e.g.
Definition DeclBase.h:86
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.
This represents one expression.
Definition Expr.h:112
QualType getType() const
Definition Expr.h:144
Represents difference between two FPOptions values.
Represents a member of a struct/union/class.
Definition Decl.h:3160
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:4689
Represents a function declaration or definition.
Definition Decl.h:2000
QualType getReturnType() const
Definition Decl.h:2845
DeclarationNameInfo getNameInfo() const
Definition Decl.h:2211
Interesting information about a specific parameter that can't simply be reflected in parameter's type...
Definition TypeBase.h:4476
ExtParameterInfo withABI(ParameterABI kind) const
Definition TypeBase.h:4490
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:2068
static ImplicitConceptSpecializationDecl * Create(const ASTContext &C, DeclContext *DC, SourceLocation SL, ArrayRef< TemplateArgument > ConvertedArgs)
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:971
Represents the results of name lookup.
Definition Lookup.h:147
MemberExpr - [C99 6.5.2.3] Structure and Union Members.
Definition Expr.h:3298
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:3359
This represents a decl that may have a name.
Definition Decl.h:274
DeclarationName getDeclName() const
Get the actual, stored name of the declaration, which may be a special name.
Definition Decl.h:340
Represent a C++ namespace.
Definition Decl.h:592
A C++ nested-name-specifier augmented with source location information.
Represents a parameter to a function.
Definition Decl.h:1790
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:2946
A (possibly-)qualified type.
Definition TypeBase.h:937
QualType withConst() const
Definition TypeBase.h:1159
void addConst()
Add the const type qualifier to this QualType.
Definition TypeBase.h:1156
bool isNull() const
Return true if this QualType doesn't point to a type yet.
Definition TypeBase.h:1004
const Type * getTypePtr() const
Retrieves a pointer to the underlying (unqualified) type.
Definition TypeBase.h:8278
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:8463
static ReturnStmt * Create(const ASTContext &Ctx, SourceLocation RL, Expr *E, const VarDecl *NRVOCandidate)
Create a return statement.
Definition Stmt.cpp:1252
unsigned getDepth() const
Returns the depth of this scope. The translation-unit has scope depth 0.
Definition Scope.h:339
Sema - This implements semantic analysis and AST building for C.
Definition Sema.h:854
TemplateArgumentLoc getTrivialTemplateArgumentLoc(const TemplateArgument &Arg, QualType NTTPType, SourceLocation Loc, NamedDecl *TemplateParam=nullptr)
Allocate a TemplateArgumentLoc where all locations have been initialized to the given location.
Scope * getCurScope() const
Retrieve the parser's current scope.
Definition Sema.h:1120
@ LookupOrdinaryName
Ordinary name lookup, which finds ordinary names (functions, variables, typedefs, etc....
Definition Sema.h:9297
@ LookupTagName
Tag name lookup, which finds the names of enums, classes, structs, and unions.
Definition Sema.h:9300
ASTContext & getASTContext() const
Definition Sema.h:925
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:3812
A convenient class for passing around template argument information.
void addArgument(const TemplateArgumentLoc &Loc)
Location wrapper for a TemplateArgument.
Represents a template argument.
TemplateParameterList * getTemplateParameters() const
Get the list of template parameters.
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, unsigned D, unsigned P, IdentifierInfo *Id, bool Typename, bool ParameterPack, bool HasTypeConstraint=false, UnsignedOrNone NumExpanded=std::nullopt)
A container of type source information.
Definition TypeBase.h:8249
The base class of the type hierarchy.
Definition TypeBase.h:1833
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee.
Definition Type.cpp:752
bool isRecordType() const
Definition TypeBase.h:8642
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:5034
QualType getType() const
Definition Decl.h:723
Represents a variable declaration or definition.
Definition Decl.h:926
static VarDecl * Create(ASTContext &C, DeclContext *DC, SourceLocation StartLoc, SourceLocation IdLoc, const IdentifierInfo *Id, QualType T, TypeSourceInfo *TInfo, StorageClass S)
Definition Decl.cpp:2151
BuiltinTypeDeclBuilder(Sema &SemaRef, CXXRecordDecl *R)
BuiltinTypeDeclBuilder & addSimpleTemplateParams(ArrayRef< StringRef > Names, ConceptDecl *CD)
BuiltinTypeDeclBuilder & addMemberVariable(StringRef Name, QualType Type, llvm::ArrayRef< Attr * > Attrs, AccessSpecifier Access=AccessSpecifier::AS_private)
BuiltinTypeDeclBuilder & addHandleAccessFunction(DeclarationName &Name, bool IsConst, bool IsRef)
BuiltinTypeDeclBuilder & addGetDimensionsMethodForBuffer()
BuiltinTypeDeclBuilder & addBufferHandles(ResourceClass RC, bool IsROV, bool RawBuffer, bool HasCounter, AccessSpecifier Access=AccessSpecifier::AS_private)
BuiltinTypeDeclBuilder & addStaticInitializationFunctions(bool HasCounter)
The JSON file list parser is used to communicate input to InstallAPI.
bool isa(CodeGen::Address addr)
Definition Address.h:330
@ ICIS_NoInit
No in-class initializer.
Definition Specifiers.h:272
@ OK_Ordinary
An ordinary object is located at an address in memory.
Definition Specifiers.h:151
AccessSpecifier
A C++ access specifier (public, private, protected), plus the special value "none" which means differ...
Definition Specifiers.h:123
@ AS_public
Definition Specifiers.h:124
nullptr
This class represents a compute construct, representing a 'Kind' of ‘parallel’, 'serial',...
StorageClass
Storage classes.
Definition Specifiers.h:248
@ SC_Static
Definition Specifiers.h:252
@ SC_None
Definition Specifiers.h:250
@ Result
The result type of a method or function.
Definition TypeBase.h:905
ParameterABI
Kinds of parameter ABI.
Definition Specifiers.h:378
const FunctionProtoType * T
@ Template
We are parsing a template declaration.
Definition Parser.h:81
bool CreateHLSLAttributedResourceType(Sema &S, QualType Wrapped, ArrayRef< const Attr * > AttrList, QualType &ResType, HLSLAttributedResourceLocInfo *LocInfo=nullptr)
@ VK_PRValue
A pr-value expression (in the C++11 taxonomy) produces a temporary value.
Definition Specifiers.h:135
@ VK_XValue
An x-value expression is a reference to an object with independent storage but which can be "moved",...
Definition Specifiers.h:144
@ VK_LValue
An l-value expression is a reference to an object with independent storage.
Definition Specifiers.h:139
U cast(CodeGen::Address addr)
Definition Address.h:327
@ Other
Other implicit parameter.
Definition Decl.h:1746
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 & addParam(StringRef Name, QualType Ty, HLSLParamModifierAttr::Spelling Modifier=HLSLParamModifierAttr::Keyword_in)
BuiltinTypeMethodBuilder & accessHandleFieldOnResource(T ResourceRecord)
BuiltinTypeMethodBuilder & operator=(const BuiltinTypeMethodBuilder &Other)=delete
BuiltinTypeMethodBuilder & callBuiltin(StringRef BuiltinName, QualType ReturnType, Ts... ArgSpecs)
BuiltinTypeMethodBuilder & dereference(T Ptr)
BuiltinTypeMethodBuilder & declareLocalVar(LocalVar &Var)
BuiltinTypeMethodBuilder & assign(TLHS LHS, TRHS RHS)
BuiltinTypeMethodBuilder(const BuiltinTypeMethodBuilder &Other)=delete
BuiltinTypeMethodBuilder & accessCounterHandleFieldOnResource(T ResourceRecord)
BuiltinTypeMethodBuilder & setCounterHandleFieldOnResource(ResourceT ResourceRecord, ValueT HandleValue)
BuiltinTypeMethodBuilder & setHandleFieldOnResource(ResourceT ResourceRecord, ValueT HandleValue)
BuiltinTypeMethodBuilder & returnValue(T ReturnValue)
BuiltinTypeMethodBuilder(BuiltinTypeDeclBuilder &DB, DeclarationName &Name, QualType ReturnTy, bool IsConst=false, bool IsCtor=false, StorageClass SC=SC_None)
TemplateParameterListBuilder & addTypeParameter(StringRef Name, QualType DefaultValue=QualType())
BuiltinTypeDeclBuilder & finalizeTemplateArgs(ConceptDecl *CD=nullptr)
ConceptSpecializationExpr * constructConceptSpecializationExpr(Sema &S, ConceptDecl *CD)