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