1352 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8//9// Helper classes for creating HLSL builtin class types. Used by external HLSL10// 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/Expr.h"20#include "clang/AST/Stmt.h"21#include "clang/AST/Type.h"22#include "clang/Basic/SourceLocation.h"23#include "clang/Basic/Specifiers.h"24#include "clang/Sema/Lookup.h"25#include "clang/Sema/Sema.h"26#include "clang/Sema/SemaHLSL.h"27#include "llvm/ADT/SmallVector.h"28 29using namespace llvm::hlsl;30 31namespace clang {32 33namespace hlsl {34 35namespace {36 37static FunctionDecl *lookupBuiltinFunction(Sema &S, StringRef Name) {38 IdentifierInfo &II =39 S.getASTContext().Idents.get(Name, tok::TokenKind::identifier);40 DeclarationNameInfo NameInfo =41 DeclarationNameInfo(DeclarationName(&II), SourceLocation());42 LookupResult R(S, NameInfo, Sema::LookupOrdinaryName);43 // AllowBuiltinCreation is false but LookupDirect will create44 // the builtin when searching the global scope anyways...45 S.LookupName(R, S.getCurScope());46 // FIXME: If the builtin function was user-declared in global scope,47 // this assert *will* fail. Should this call LookupBuiltin instead?48 assert(R.isSingleResult() &&49 "Since this is a builtin it should always resolve!");50 return cast<FunctionDecl>(R.getFoundDecl());51}52 53CXXConstructorDecl *lookupCopyConstructor(QualType ResTy) {54 assert(ResTy->isRecordType() && "not a CXXRecord type");55 for (auto *CD : ResTy->getAsCXXRecordDecl()->ctors())56 if (CD->isCopyConstructor())57 return CD;58 return nullptr;59}60 61ParameterABI62convertParamModifierToParamABI(HLSLParamModifierAttr::Spelling Modifier) {63 assert(Modifier != HLSLParamModifierAttr::Spelling::Keyword_in &&64 "HLSL 'in' parameters modifier cannot be converted to ParameterABI");65 switch (Modifier) {66 case HLSLParamModifierAttr::Spelling::Keyword_out:67 return ParameterABI::HLSLOut;68 case HLSLParamModifierAttr::Spelling::Keyword_inout:69 return ParameterABI::HLSLInOut;70 default:71 llvm_unreachable("Invalid HLSL parameter modifier");72 }73}74 75QualType getInoutParameterType(ASTContext &AST, QualType Ty) {76 assert(!Ty->isReferenceType() &&77 "Pointer and reference types cannot be inout or out parameters");78 Ty = AST.getLValueReferenceType(Ty);79 Ty.addRestrict();80 return Ty;81}82 83} // namespace84 85// Builder for template arguments of builtin types. Used internally86// by BuiltinTypeDeclBuilder.87struct TemplateParameterListBuilder {88 BuiltinTypeDeclBuilder &Builder;89 llvm::SmallVector<NamedDecl *> Params;90 91 TemplateParameterListBuilder(BuiltinTypeDeclBuilder &RB) : Builder(RB) {}92 ~TemplateParameterListBuilder();93 94 TemplateParameterListBuilder &95 addTypeParameter(StringRef Name, QualType DefaultValue = QualType());96 97 ConceptSpecializationExpr *98 constructConceptSpecializationExpr(Sema &S, ConceptDecl *CD);99 100 BuiltinTypeDeclBuilder &finalizeTemplateArgs(ConceptDecl *CD = nullptr);101};102 103// Builder for methods or constructors of builtin types. Allows creating methods104// or constructors of builtin types using the builder pattern like this:105//106// BuiltinTypeMethodBuilder(RecordBuilder, "MethodName", ReturnType)107// .addParam("param_name", Type, InOutModifier)108// .callBuiltin("builtin_name", BuiltinParams...)109// .finalize();110//111// The builder needs to have all of the parameters before it can create112// a CXXMethodDecl or CXXConstructorDecl. It collects them in addParam calls and113// when a first method that builds the body is called or when access to 'this`114// is needed it creates the CXXMethodDecl/CXXConstructorDecl and ParmVarDecls115// instances. These can then be referenced from the body building methods.116// Destructor or an explicit call to finalize() will complete the method117// definition.118//119// The callBuiltin helper method accepts constants via `Expr *` or placeholder120// value arguments to indicate which function arguments to forward to the121// builtin.122//123// If the method that is being built has a non-void return type the124// finalize() will create a return statement with the value of the last125// statement (unless the last statement is already a ReturnStmt or the return126// value is void).127struct BuiltinTypeMethodBuilder {128private:129 struct Param {130 const IdentifierInfo &NameII;131 QualType Ty;132 HLSLParamModifierAttr::Spelling Modifier;133 Param(const IdentifierInfo &NameII, QualType Ty,134 HLSLParamModifierAttr::Spelling Modifier)135 : NameII(NameII), Ty(Ty), Modifier(Modifier) {}136 };137 138 struct LocalVar {139 StringRef Name;140 QualType Ty;141 VarDecl *Decl;142 LocalVar(StringRef Name, QualType Ty) : Name(Name), Ty(Ty), Decl(nullptr) {}143 };144 145 BuiltinTypeDeclBuilder &DeclBuilder;146 DeclarationName Name;147 QualType ReturnTy;148 // method or constructor declaration149 // (CXXConstructorDecl derives from CXXMethodDecl)150 CXXMethodDecl *Method;151 bool IsConst;152 bool IsCtor;153 StorageClass SC;154 llvm::SmallVector<Param> Params;155 llvm::SmallVector<Stmt *> StmtsList;156 157 // Argument placeholders, inspired by std::placeholder. These are the indices158 // of arguments to forward to `callBuiltin` and other method builder methods.159 // Additional special values are:160 // Handle - refers to the resource handle.161 // LastStmt - refers to the last statement in the method body; referencing162 // LastStmt will remove the statement from the method body since163 // it will be linked from the new expression being constructed.164 enum class PlaceHolder {165 _0,166 _1,167 _2,168 _3,169 _4,170 _5,171 Handle = 128,172 CounterHandle,173 LastStmt174 };175 176 Expr *convertPlaceholder(PlaceHolder PH);177 Expr *convertPlaceholder(LocalVar &Var);178 Expr *convertPlaceholder(Expr *E) { return E; }179 180public:181 friend BuiltinTypeDeclBuilder;182 183 BuiltinTypeMethodBuilder(BuiltinTypeDeclBuilder &DB, DeclarationName &Name,184 QualType ReturnTy, bool IsConst = false,185 bool IsCtor = false, StorageClass SC = SC_None)186 : DeclBuilder(DB), Name(Name), ReturnTy(ReturnTy), Method(nullptr),187 IsConst(IsConst), IsCtor(IsCtor), SC(SC) {}188 189 BuiltinTypeMethodBuilder(BuiltinTypeDeclBuilder &DB, StringRef NameStr,190 QualType ReturnTy, bool IsConst = false,191 bool IsCtor = false, StorageClass SC = SC_None);192 BuiltinTypeMethodBuilder(const BuiltinTypeMethodBuilder &Other) = delete;193 194 ~BuiltinTypeMethodBuilder() { finalize(); }195 196 BuiltinTypeMethodBuilder &197 operator=(const BuiltinTypeMethodBuilder &Other) = delete;198 199 BuiltinTypeMethodBuilder &addParam(StringRef Name, QualType Ty,200 HLSLParamModifierAttr::Spelling Modifier =201 HLSLParamModifierAttr::Keyword_in);202 BuiltinTypeMethodBuilder &declareLocalVar(LocalVar &Var);203 template <typename... Ts>204 BuiltinTypeMethodBuilder &callBuiltin(StringRef BuiltinName,205 QualType ReturnType, Ts &&...ArgSpecs);206 template <typename TLHS, typename TRHS>207 BuiltinTypeMethodBuilder &assign(TLHS LHS, TRHS RHS);208 template <typename T> BuiltinTypeMethodBuilder &dereference(T Ptr);209 template <typename T>210 BuiltinTypeMethodBuilder &accessHandleFieldOnResource(T ResourceRecord);211 template <typename ResourceT, typename ValueT>212 BuiltinTypeMethodBuilder &setHandleFieldOnResource(ResourceT ResourceRecord,213 ValueT HandleValue);214 template <typename T>215 BuiltinTypeMethodBuilder &216 accessCounterHandleFieldOnResource(T ResourceRecord);217 template <typename ResourceT, typename ValueT>218 BuiltinTypeMethodBuilder &219 setCounterHandleFieldOnResource(ResourceT ResourceRecord, ValueT HandleValue);220 template <typename T> BuiltinTypeMethodBuilder &returnValue(T ReturnValue);221 BuiltinTypeMethodBuilder &returnThis();222 BuiltinTypeDeclBuilder &finalize();223 Expr *getResourceHandleExpr();224 Expr *getResourceCounterHandleExpr();225 226private:227 void createDecl();228 229 // Makes sure the declaration is created; should be called before any230 // statement added to the body or when access to 'this' is needed.231 void ensureCompleteDecl() {232 if (!Method)233 createDecl();234 }235 236 template <typename ResourceT, typename ValueT>237 BuiltinTypeMethodBuilder &setFieldOnResource(ResourceT ResourceRecord,238 ValueT HandleValue,239 FieldDecl *HandleField);240};241 242TemplateParameterListBuilder::~TemplateParameterListBuilder() {243 finalizeTemplateArgs();244}245 246TemplateParameterListBuilder &247TemplateParameterListBuilder::addTypeParameter(StringRef Name,248 QualType DefaultValue) {249 assert(!Builder.Record->isCompleteDefinition() &&250 "record is already complete");251 ASTContext &AST = Builder.SemaRef.getASTContext();252 unsigned Position = static_cast<unsigned>(Params.size());253 auto *Decl = TemplateTypeParmDecl::Create(254 AST, Builder.Record->getDeclContext(), SourceLocation(), SourceLocation(),255 /* TemplateDepth */ 0, Position,256 &AST.Idents.get(Name, tok::TokenKind::identifier),257 /* Typename */ true,258 /* ParameterPack */ false,259 /* HasTypeConstraint*/ false);260 if (!DefaultValue.isNull())261 Decl->setDefaultArgument(AST,262 Builder.SemaRef.getTrivialTemplateArgumentLoc(263 DefaultValue, QualType(), SourceLocation()));264 265 Params.emplace_back(Decl);266 return *this;267}268 269// The concept specialization expression (CSE) constructed in270// constructConceptSpecializationExpr is constructed so that it271// matches the CSE that is constructed when parsing the below C++ code:272//273// template<typename T>274// concept is_typed_resource_element_compatible =275// __builtin_hlsl_typed_resource_element_compatible<T>276//277// template<typename element_type> requires278// is_typed_resource_element_compatible<element_type>279// struct RWBuffer {280// element_type Val;281// };282//283// int fn() {284// RWBuffer<int> Buf;285// }286//287// When dumping the AST and filtering for "RWBuffer", the resulting AST288// structure is what we're trying to construct below, specifically the289// CSE portion.290ConceptSpecializationExpr *291TemplateParameterListBuilder::constructConceptSpecializationExpr(292 Sema &S, ConceptDecl *CD) {293 ASTContext &Context = S.getASTContext();294 SourceLocation Loc = Builder.Record->getBeginLoc();295 DeclarationNameInfo DNI(CD->getDeclName(), Loc);296 NestedNameSpecifierLoc NNSLoc;297 DeclContext *DC = Builder.Record->getDeclContext();298 TemplateArgumentListInfo TALI(Loc, Loc);299 300 // Assume that the concept decl has just one template parameter301 // This parameter should have been added when CD was constructed302 // in getTypedBufferConceptDecl303 assert(CD->getTemplateParameters()->size() == 1 &&304 "unexpected concept decl parameter count");305 TemplateTypeParmDecl *ConceptTTPD =306 dyn_cast<TemplateTypeParmDecl>(CD->getTemplateParameters()->getParam(0));307 308 // this TemplateTypeParmDecl is the template for the resource, and is309 // used to construct a template argumentthat will be used310 // to construct the ImplicitConceptSpecializationDecl311 TemplateTypeParmDecl *T = TemplateTypeParmDecl::Create(312 Context, // AST context313 Builder.Record->getDeclContext(), // DeclContext314 SourceLocation(), SourceLocation(),315 /*D=*/0, // Depth in the template parameter list316 /*P=*/0, // Position in the template parameter list317 /*Id=*/nullptr, // Identifier for 'T'318 /*Typename=*/true, // Indicates this is a 'typename' or 'class'319 /*ParameterPack=*/false, // Not a parameter pack320 /*HasTypeConstraint=*/false // Has no type constraint321 );322 323 T->setDeclContext(DC);324 325 QualType ConceptTType = Context.getTypeDeclType(ConceptTTPD);326 327 // this is the 2nd template argument node, on which328 // the concept constraint is actually being applied: 'element_type'329 TemplateArgument ConceptTA = TemplateArgument(ConceptTType);330 331 QualType CSETType = Context.getTypeDeclType(T);332 333 // this is the 1st template argument node, which represents334 // the abstract type that a concept would refer to: 'T'335 TemplateArgument CSETA = TemplateArgument(CSETType);336 337 ImplicitConceptSpecializationDecl *ImplicitCSEDecl =338 ImplicitConceptSpecializationDecl::Create(339 Context, Builder.Record->getDeclContext(), Loc, {CSETA});340 341 // Constraint satisfaction is used to construct the342 // ConceptSpecailizationExpr, and represents the 2nd Template Argument,343 // located at the bottom of the sample AST above.344 const ConstraintSatisfaction CS(CD, {ConceptTA});345 TemplateArgumentLoc TAL =346 S.getTrivialTemplateArgumentLoc(ConceptTA, QualType(), SourceLocation());347 348 TALI.addArgument(TAL);349 const ASTTemplateArgumentListInfo *ATALI =350 ASTTemplateArgumentListInfo::Create(Context, TALI);351 352 // In the concept reference, ATALI is what adds the extra353 // TemplateArgument node underneath CSE354 ConceptReference *CR =355 ConceptReference::Create(Context, NNSLoc, Loc, DNI, CD, CD, ATALI);356 357 ConceptSpecializationExpr *CSE =358 ConceptSpecializationExpr::Create(Context, CR, ImplicitCSEDecl, &CS);359 360 return CSE;361}362 363BuiltinTypeDeclBuilder &364TemplateParameterListBuilder::finalizeTemplateArgs(ConceptDecl *CD) {365 if (Params.empty())366 return Builder;367 368 ASTContext &AST = Builder.SemaRef.Context;369 ConceptSpecializationExpr *CSE =370 CD ? constructConceptSpecializationExpr(Builder.SemaRef, CD) : nullptr;371 auto *ParamList = TemplateParameterList::Create(372 AST, SourceLocation(), SourceLocation(), Params, SourceLocation(), CSE);373 Builder.Template = ClassTemplateDecl::Create(374 AST, Builder.Record->getDeclContext(), SourceLocation(),375 DeclarationName(Builder.Record->getIdentifier()), ParamList,376 Builder.Record);377 378 Builder.Record->setDescribedClassTemplate(Builder.Template);379 Builder.Template->setImplicit(true);380 Builder.Template->setLexicalDeclContext(Builder.Record->getDeclContext());381 382 // NOTE: setPreviousDecl before addDecl so new decl replace old decl when383 // make visible.384 Builder.Template->setPreviousDecl(Builder.PrevTemplate);385 Builder.Record->getDeclContext()->addDecl(Builder.Template);386 Params.clear();387 388 return Builder;389}390 391Expr *BuiltinTypeMethodBuilder::convertPlaceholder(PlaceHolder PH) {392 if (PH == PlaceHolder::Handle)393 return getResourceHandleExpr();394 if (PH == PlaceHolder::CounterHandle)395 return getResourceCounterHandleExpr();396 397 if (PH == PlaceHolder::LastStmt) {398 assert(!StmtsList.empty() && "no statements in the list");399 Stmt *LastStmt = StmtsList.pop_back_val();400 assert(isa<ValueStmt>(LastStmt) && "last statement does not have a value");401 return cast<ValueStmt>(LastStmt)->getExprStmt();402 }403 404 ASTContext &AST = DeclBuilder.SemaRef.getASTContext();405 ParmVarDecl *ParamDecl = Method->getParamDecl(static_cast<unsigned>(PH));406 return DeclRefExpr::Create(407 AST, NestedNameSpecifierLoc(), SourceLocation(), ParamDecl, false,408 DeclarationNameInfo(ParamDecl->getDeclName(), SourceLocation()),409 ParamDecl->getType().getNonReferenceType(), VK_PRValue);410}411 412Expr *BuiltinTypeMethodBuilder::convertPlaceholder(LocalVar &Var) {413 VarDecl *VD = Var.Decl;414 assert(VD && "local variable is not declared");415 return DeclRefExpr::Create(416 VD->getASTContext(), NestedNameSpecifierLoc(), SourceLocation(), VD,417 false, DeclarationNameInfo(VD->getDeclName(), SourceLocation()),418 VD->getType(), VK_LValue);419}420 421BuiltinTypeMethodBuilder::BuiltinTypeMethodBuilder(BuiltinTypeDeclBuilder &DB,422 StringRef NameStr,423 QualType ReturnTy,424 bool IsConst, bool IsCtor,425 StorageClass SC)426 : DeclBuilder(DB), ReturnTy(ReturnTy), Method(nullptr), IsConst(IsConst),427 IsCtor(IsCtor), SC(SC) {428 429 assert((!NameStr.empty() || IsCtor) && "method needs a name");430 assert(((IsCtor && !IsConst) || !IsCtor) && "constructor cannot be const");431 432 ASTContext &AST = DB.SemaRef.getASTContext();433 if (IsCtor) {434 Name = AST.DeclarationNames.getCXXConstructorName(435 AST.getCanonicalTagType(DB.Record));436 } else {437 const IdentifierInfo &II =438 AST.Idents.get(NameStr, tok::TokenKind::identifier);439 Name = DeclarationName(&II);440 }441}442 443BuiltinTypeMethodBuilder &444BuiltinTypeMethodBuilder::addParam(StringRef Name, QualType Ty,445 HLSLParamModifierAttr::Spelling Modifier) {446 assert(Method == nullptr && "Cannot add param, method already created");447 const IdentifierInfo &II = DeclBuilder.SemaRef.getASTContext().Idents.get(448 Name, tok::TokenKind::identifier);449 Params.emplace_back(II, Ty, Modifier);450 return *this;451}452 453void BuiltinTypeMethodBuilder::createDecl() {454 assert(Method == nullptr && "Method or constructor is already created");455 456 // create function prototype457 ASTContext &AST = DeclBuilder.SemaRef.getASTContext();458 SmallVector<QualType> ParamTypes;459 SmallVector<FunctionType::ExtParameterInfo> ParamExtInfos(Params.size());460 uint32_t ArgIndex = 0;461 462 // Create function prototype.463 bool UseParamExtInfo = false;464 for (Param &MP : Params) {465 if (MP.Modifier != HLSLParamModifierAttr::Keyword_in) {466 UseParamExtInfo = true;467 FunctionType::ExtParameterInfo &PI = ParamExtInfos[ArgIndex];468 ParamExtInfos[ArgIndex] =469 PI.withABI(convertParamModifierToParamABI(MP.Modifier));470 if (!MP.Ty->isDependentType())471 MP.Ty = getInoutParameterType(AST, MP.Ty);472 }473 ParamTypes.emplace_back(MP.Ty);474 ++ArgIndex;475 }476 477 FunctionProtoType::ExtProtoInfo ExtInfo;478 if (UseParamExtInfo)479 ExtInfo.ExtParameterInfos = ParamExtInfos.data();480 if (IsConst)481 ExtInfo.TypeQuals.addConst();482 483 QualType FuncTy = AST.getFunctionType(ReturnTy, ParamTypes, ExtInfo);484 485 // Create method or constructor declaration.486 auto *TSInfo = AST.getTrivialTypeSourceInfo(FuncTy, SourceLocation());487 DeclarationNameInfo NameInfo = DeclarationNameInfo(Name, SourceLocation());488 if (IsCtor)489 Method = CXXConstructorDecl::Create(490 AST, DeclBuilder.Record, SourceLocation(), NameInfo, FuncTy, TSInfo,491 ExplicitSpecifier(), false, true, false,492 ConstexprSpecKind::Unspecified);493 else494 Method = CXXMethodDecl::Create(495 AST, DeclBuilder.Record, SourceLocation(), NameInfo, FuncTy, TSInfo, SC,496 false, false, ConstexprSpecKind::Unspecified, SourceLocation());497 498 // Create params & set them to the method/constructor and function prototype.499 SmallVector<ParmVarDecl *> ParmDecls;500 unsigned CurScopeDepth = DeclBuilder.SemaRef.getCurScope()->getDepth();501 auto FnProtoLoc =502 Method->getTypeSourceInfo()->getTypeLoc().getAs<FunctionProtoTypeLoc>();503 for (int I = 0, E = Params.size(); I != E; I++) {504 Param &MP = Params[I];505 ParmVarDecl *Parm = ParmVarDecl::Create(506 AST, Method->getDeclContext(), SourceLocation(), SourceLocation(),507 &MP.NameII, MP.Ty,508 AST.getTrivialTypeSourceInfo(MP.Ty, SourceLocation()), SC_None,509 nullptr);510 if (MP.Modifier != HLSLParamModifierAttr::Keyword_in) {511 auto *Mod =512 HLSLParamModifierAttr::Create(AST, SourceRange(), MP.Modifier);513 Parm->addAttr(Mod);514 }515 Parm->setScopeInfo(CurScopeDepth, I);516 ParmDecls.push_back(Parm);517 FnProtoLoc.setParam(I, Parm);518 }519 Method->setParams({ParmDecls});520}521 522Expr *BuiltinTypeMethodBuilder::getResourceHandleExpr() {523 ensureCompleteDecl();524 525 ASTContext &AST = DeclBuilder.SemaRef.getASTContext();526 CXXThisExpr *This = CXXThisExpr::Create(527 AST, SourceLocation(), Method->getFunctionObjectParameterType(), true);528 FieldDecl *HandleField = DeclBuilder.getResourceHandleField();529 return MemberExpr::CreateImplicit(AST, This, false, HandleField,530 HandleField->getType(), VK_LValue,531 OK_Ordinary);532}533 534Expr *BuiltinTypeMethodBuilder::getResourceCounterHandleExpr() {535 ensureCompleteDecl();536 537 ASTContext &AST = DeclBuilder.SemaRef.getASTContext();538 CXXThisExpr *This = CXXThisExpr::Create(539 AST, SourceLocation(), Method->getFunctionObjectParameterType(), true);540 FieldDecl *HandleField = DeclBuilder.getResourceCounterHandleField();541 return MemberExpr::CreateImplicit(AST, This, false, HandleField,542 HandleField->getType(), VK_LValue,543 OK_Ordinary);544}545 546BuiltinTypeMethodBuilder &547BuiltinTypeMethodBuilder::declareLocalVar(LocalVar &Var) {548 ensureCompleteDecl();549 550 assert(Var.Decl == nullptr && "local variable is already declared");551 552 ASTContext &AST = DeclBuilder.SemaRef.getASTContext();553 Var.Decl = VarDecl::Create(554 AST, Method, SourceLocation(), SourceLocation(),555 &AST.Idents.get(Var.Name, tok::TokenKind::identifier), Var.Ty,556 AST.getTrivialTypeSourceInfo(Var.Ty, SourceLocation()), SC_None);557 DeclStmt *DS = new (AST) clang::DeclStmt(DeclGroupRef(Var.Decl),558 SourceLocation(), SourceLocation());559 StmtsList.push_back(DS);560 return *this;561}562 563BuiltinTypeMethodBuilder &BuiltinTypeMethodBuilder::returnThis() {564 ASTContext &AST = DeclBuilder.SemaRef.getASTContext();565 CXXThisExpr *ThisExpr = CXXThisExpr::Create(566 AST, SourceLocation(), Method->getFunctionObjectParameterType(),567 /*IsImplicit=*/true);568 StmtsList.push_back(ThisExpr);569 return *this;570}571 572template <typename... Ts>573BuiltinTypeMethodBuilder &574BuiltinTypeMethodBuilder::callBuiltin(StringRef BuiltinName,575 QualType ReturnType, Ts &&...ArgSpecs) {576 ensureCompleteDecl();577 578 std::array<Expr *, sizeof...(ArgSpecs)> Args{579 convertPlaceholder(std::forward<Ts>(ArgSpecs))...};580 581 ASTContext &AST = DeclBuilder.SemaRef.getASTContext();582 FunctionDecl *FD = lookupBuiltinFunction(DeclBuilder.SemaRef, BuiltinName);583 DeclRefExpr *DRE = DeclRefExpr::Create(584 AST, NestedNameSpecifierLoc(), SourceLocation(), FD, false,585 FD->getNameInfo(), AST.BuiltinFnTy, VK_PRValue);586 587 auto *ImpCast = ImplicitCastExpr::Create(588 AST, AST.getPointerType(FD->getType()), CK_BuiltinFnToFnPtr, DRE, nullptr,589 VK_PRValue, FPOptionsOverride());590 591 if (ReturnType.isNull())592 ReturnType = FD->getReturnType();593 594 Expr *Call = CallExpr::Create(AST, ImpCast, Args, ReturnType, VK_PRValue,595 SourceLocation(), FPOptionsOverride());596 StmtsList.push_back(Call);597 return *this;598}599 600template <typename TLHS, typename TRHS>601BuiltinTypeMethodBuilder &BuiltinTypeMethodBuilder::assign(TLHS LHS, TRHS RHS) {602 Expr *LHSExpr = convertPlaceholder(LHS);603 Expr *RHSExpr = convertPlaceholder(RHS);604 Stmt *AssignStmt = BinaryOperator::Create(605 DeclBuilder.SemaRef.getASTContext(), LHSExpr, RHSExpr, BO_Assign,606 LHSExpr->getType(), ExprValueKind::VK_PRValue,607 ExprObjectKind::OK_Ordinary, SourceLocation(), FPOptionsOverride());608 StmtsList.push_back(AssignStmt);609 return *this;610}611 612template <typename T>613BuiltinTypeMethodBuilder &BuiltinTypeMethodBuilder::dereference(T Ptr) {614 Expr *PtrExpr = convertPlaceholder(Ptr);615 Expr *Deref =616 UnaryOperator::Create(DeclBuilder.SemaRef.getASTContext(), PtrExpr,617 UO_Deref, PtrExpr->getType()->getPointeeType(),618 VK_PRValue, OK_Ordinary, SourceLocation(),619 /*CanOverflow=*/false, FPOptionsOverride());620 StmtsList.push_back(Deref);621 return *this;622}623 624template <typename T>625BuiltinTypeMethodBuilder &626BuiltinTypeMethodBuilder::accessHandleFieldOnResource(T ResourceRecord) {627 ensureCompleteDecl();628 629 Expr *ResourceExpr = convertPlaceholder(ResourceRecord);630 631 ASTContext &AST = DeclBuilder.SemaRef.getASTContext();632 FieldDecl *HandleField = DeclBuilder.getResourceHandleField();633 MemberExpr *HandleExpr = MemberExpr::CreateImplicit(634 AST, ResourceExpr, false, HandleField, HandleField->getType(), VK_LValue,635 OK_Ordinary);636 StmtsList.push_back(HandleExpr);637 return *this;638}639 640template <typename ResourceT, typename ValueT>641BuiltinTypeMethodBuilder &642BuiltinTypeMethodBuilder::setHandleFieldOnResource(ResourceT ResourceRecord,643 ValueT HandleValue) {644 return setFieldOnResource(ResourceRecord, HandleValue,645 DeclBuilder.getResourceHandleField());646}647 648template <typename ResourceT, typename ValueT>649BuiltinTypeMethodBuilder &650BuiltinTypeMethodBuilder::setCounterHandleFieldOnResource(651 ResourceT ResourceRecord, ValueT HandleValue) {652 return setFieldOnResource(ResourceRecord, HandleValue,653 DeclBuilder.getResourceCounterHandleField());654}655 656template <typename ResourceT, typename ValueT>657BuiltinTypeMethodBuilder &BuiltinTypeMethodBuilder::setFieldOnResource(658 ResourceT ResourceRecord, ValueT HandleValue, FieldDecl *HandleField) {659 ensureCompleteDecl();660 661 Expr *ResourceExpr = convertPlaceholder(ResourceRecord);662 Expr *HandleValueExpr = convertPlaceholder(HandleValue);663 664 ASTContext &AST = DeclBuilder.SemaRef.getASTContext();665 MemberExpr *HandleMemberExpr = MemberExpr::CreateImplicit(666 AST, ResourceExpr, false, HandleField, HandleField->getType(), VK_LValue,667 OK_Ordinary);668 Stmt *AssignStmt = BinaryOperator::Create(669 DeclBuilder.SemaRef.getASTContext(), HandleMemberExpr, HandleValueExpr,670 BO_Assign, HandleMemberExpr->getType(), ExprValueKind::VK_PRValue,671 ExprObjectKind::OK_Ordinary, SourceLocation(), FPOptionsOverride());672 StmtsList.push_back(AssignStmt);673 return *this;674}675 676template <typename T>677BuiltinTypeMethodBuilder &678BuiltinTypeMethodBuilder::accessCounterHandleFieldOnResource(T ResourceRecord) {679 ensureCompleteDecl();680 681 Expr *ResourceExpr = convertPlaceholder(ResourceRecord);682 683 ASTContext &AST = DeclBuilder.SemaRef.getASTContext();684 FieldDecl *HandleField = DeclBuilder.getResourceCounterHandleField();685 MemberExpr *HandleExpr = MemberExpr::CreateImplicit(686 AST, ResourceExpr, false, HandleField, HandleField->getType(), VK_LValue,687 OK_Ordinary);688 StmtsList.push_back(HandleExpr);689 return *this;690}691 692template <typename T>693BuiltinTypeMethodBuilder &BuiltinTypeMethodBuilder::returnValue(T ReturnValue) {694 ensureCompleteDecl();695 696 Expr *ReturnValueExpr = convertPlaceholder(ReturnValue);697 ASTContext &AST = DeclBuilder.SemaRef.getASTContext();698 699 QualType Ty = ReturnValueExpr->getType();700 if (Ty->isRecordType()) {701 // For record types, create a call to copy constructor to ensure proper copy702 // semantics.703 auto *ICE =704 ImplicitCastExpr::Create(AST, Ty.withConst(), CK_NoOp, ReturnValueExpr,705 nullptr, VK_XValue, FPOptionsOverride());706 CXXConstructorDecl *CD = lookupCopyConstructor(Ty);707 assert(CD && "no copy constructor found");708 ReturnValueExpr = CXXConstructExpr::Create(709 AST, Ty, SourceLocation(), CD, /*Elidable=*/false, {ICE},710 /*HadMultipleCandidates=*/false, /*ListInitialization=*/false,711 /*StdInitListInitialization=*/false,712 /*ZeroInitListInitialization=*/false, CXXConstructionKind::Complete,713 SourceRange());714 }715 StmtsList.push_back(716 ReturnStmt::Create(AST, SourceLocation(), ReturnValueExpr, nullptr));717 return *this;718}719 720BuiltinTypeDeclBuilder &BuiltinTypeMethodBuilder::finalize() {721 assert(!DeclBuilder.Record->isCompleteDefinition() &&722 "record is already complete");723 724 ensureCompleteDecl();725 726 if (!Method->hasBody()) {727 ASTContext &AST = DeclBuilder.SemaRef.getASTContext();728 assert((ReturnTy == AST.VoidTy || !StmtsList.empty()) &&729 "nothing to return from non-void method");730 if (ReturnTy != AST.VoidTy) {731 if (Expr *LastExpr = dyn_cast<Expr>(StmtsList.back())) {732 assert(AST.hasSameUnqualifiedType(LastExpr->getType(),733 ReturnTy.getNonReferenceType()) &&734 "Return type of the last statement must match the return type "735 "of the method");736 if (!isa<ReturnStmt>(LastExpr)) {737 StmtsList.pop_back();738 StmtsList.push_back(739 ReturnStmt::Create(AST, SourceLocation(), LastExpr, nullptr));740 }741 }742 }743 744 Method->setBody(CompoundStmt::Create(AST, StmtsList, FPOptionsOverride(),745 SourceLocation(), SourceLocation()));746 Method->setLexicalDeclContext(DeclBuilder.Record);747 Method->setAccess(AS_public);748 Method->addAttr(AlwaysInlineAttr::CreateImplicit(749 AST, SourceRange(), AlwaysInlineAttr::CXX11_clang_always_inline));750 DeclBuilder.Record->addDecl(Method);751 }752 return DeclBuilder;753}754 755BuiltinTypeDeclBuilder::BuiltinTypeDeclBuilder(Sema &SemaRef, CXXRecordDecl *R)756 : SemaRef(SemaRef), Record(R) {757 Record->startDefinition();758 Template = Record->getDescribedClassTemplate();759}760 761BuiltinTypeDeclBuilder::BuiltinTypeDeclBuilder(Sema &SemaRef,762 NamespaceDecl *Namespace,763 StringRef Name)764 : SemaRef(SemaRef), HLSLNamespace(Namespace) {765 ASTContext &AST = SemaRef.getASTContext();766 IdentifierInfo &II = AST.Idents.get(Name, tok::TokenKind::identifier);767 768 LookupResult Result(SemaRef, &II, SourceLocation(), Sema::LookupTagName);769 CXXRecordDecl *PrevDecl = nullptr;770 if (SemaRef.LookupQualifiedName(Result, HLSLNamespace)) {771 // Declaration already exists (from precompiled headers)772 NamedDecl *Found = Result.getFoundDecl();773 if (auto *TD = dyn_cast<ClassTemplateDecl>(Found)) {774 PrevDecl = TD->getTemplatedDecl();775 PrevTemplate = TD;776 } else777 PrevDecl = dyn_cast<CXXRecordDecl>(Found);778 assert(PrevDecl && "Unexpected lookup result type.");779 }780 781 if (PrevDecl && PrevDecl->isCompleteDefinition()) {782 Record = PrevDecl;783 Template = PrevTemplate;784 return;785 }786 787 Record =788 CXXRecordDecl::Create(AST, TagDecl::TagKind::Class, HLSLNamespace,789 SourceLocation(), SourceLocation(), &II, PrevDecl);790 Record->setImplicit(true);791 Record->setLexicalDeclContext(HLSLNamespace);792 Record->setHasExternalLexicalStorage();793 794 // Don't let anyone derive from built-in types.795 Record->addAttr(796 FinalAttr::CreateImplicit(AST, SourceRange(), FinalAttr::Keyword_final));797}798 799BuiltinTypeDeclBuilder::~BuiltinTypeDeclBuilder() {800 if (HLSLNamespace && !Template && Record->getDeclContext() == HLSLNamespace)801 HLSLNamespace->addDecl(Record);802}803 804BuiltinTypeDeclBuilder &805BuiltinTypeDeclBuilder::addMemberVariable(StringRef Name, QualType Type,806 llvm::ArrayRef<Attr *> Attrs,807 AccessSpecifier Access) {808 assert(!Record->isCompleteDefinition() && "record is already complete");809 assert(Record->isBeingDefined() &&810 "Definition must be started before adding members!");811 ASTContext &AST = Record->getASTContext();812 813 IdentifierInfo &II = AST.Idents.get(Name, tok::TokenKind::identifier);814 TypeSourceInfo *MemTySource =815 AST.getTrivialTypeSourceInfo(Type, SourceLocation());816 auto *Field = FieldDecl::Create(817 AST, Record, SourceLocation(), SourceLocation(), &II, Type, MemTySource,818 nullptr, false, InClassInitStyle::ICIS_NoInit);819 Field->setAccess(Access);820 Field->setImplicit(true);821 for (Attr *A : Attrs) {822 if (A)823 Field->addAttr(A);824 }825 826 Record->addDecl(Field);827 Fields[Name] = Field;828 return *this;829}830 831BuiltinTypeDeclBuilder &832BuiltinTypeDeclBuilder::addBufferHandles(ResourceClass RC, bool IsROV,833 bool RawBuffer, bool HasCounter,834 AccessSpecifier Access) {835 addHandleMember(RC, IsROV, RawBuffer, Access);836 if (HasCounter)837 addCounterHandleMember(RC, IsROV, RawBuffer, Access);838 return *this;839}840 841BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addHandleMember(842 ResourceClass RC, bool IsROV, bool RawBuffer, AccessSpecifier Access) {843 return addResourceMember("__handle", RC, IsROV, RawBuffer,844 /*IsCounter=*/false, Access);845}846 847BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addCounterHandleMember(848 ResourceClass RC, bool IsROV, bool RawBuffer, AccessSpecifier Access) {849 return addResourceMember("__counter_handle", RC, IsROV, RawBuffer,850 /*IsCounter=*/true, Access);851}852 853BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addResourceMember(854 StringRef MemberName, ResourceClass RC, bool IsROV, bool RawBuffer,855 bool IsCounter, AccessSpecifier Access) {856 assert(!Record->isCompleteDefinition() && "record is already complete");857 858 ASTContext &Ctx = SemaRef.getASTContext();859 TypeSourceInfo *ElementTypeInfo =860 Ctx.getTrivialTypeSourceInfo(getHandleElementType(), SourceLocation());861 862 // add handle member with resource type attributes863 QualType AttributedResTy = QualType();864 SmallVector<const Attr *> Attrs = {865 HLSLResourceClassAttr::CreateImplicit(Ctx, RC),866 IsROV ? HLSLROVAttr::CreateImplicit(Ctx) : nullptr,867 RawBuffer ? HLSLRawBufferAttr::CreateImplicit(Ctx) : nullptr,868 ElementTypeInfo869 ? HLSLContainedTypeAttr::CreateImplicit(Ctx, ElementTypeInfo)870 : nullptr};871 if (IsCounter)872 Attrs.push_back(HLSLIsCounterAttr::CreateImplicit(Ctx));873 874 if (CreateHLSLAttributedResourceType(SemaRef, Ctx.HLSLResourceTy, Attrs,875 AttributedResTy))876 addMemberVariable(MemberName, AttributedResTy, {}, Access);877 return *this;878}879 880// Adds default constructor to the resource class:881// Resource::Resource()882BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addDefaultHandleConstructor() {883 assert(!Record->isCompleteDefinition() && "record is already complete");884 885 using PH = BuiltinTypeMethodBuilder::PlaceHolder;886 QualType HandleType = getResourceHandleField()->getType();887 return BuiltinTypeMethodBuilder(*this, "", SemaRef.getASTContext().VoidTy,888 false, true)889 .callBuiltin("__builtin_hlsl_resource_uninitializedhandle", HandleType,890 PH::Handle)891 .assign(PH::Handle, PH::LastStmt)892 .finalize();893}894 895BuiltinTypeDeclBuilder &896BuiltinTypeDeclBuilder::addStaticInitializationFunctions(bool HasCounter) {897 if (HasCounter) {898 addCreateFromBindingWithImplicitCounter();899 addCreateFromImplicitBindingWithImplicitCounter();900 } else {901 addCreateFromBinding();902 addCreateFromImplicitBinding();903 }904 return *this;905}906 907// Adds static method that initializes resource from binding:908//909// static Resource<T> __createFromBinding(unsigned registerNo,910// unsigned spaceNo, int range,911// unsigned index, const char *name) {912// Resource<T> tmp;913// tmp.__handle = __builtin_hlsl_resource_handlefrombinding(914// tmp.__handle, registerNo, spaceNo,915// range, index, name);916// return tmp;917// }918BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addCreateFromBinding() {919 assert(!Record->isCompleteDefinition() && "record is already complete");920 921 using PH = BuiltinTypeMethodBuilder::PlaceHolder;922 ASTContext &AST = SemaRef.getASTContext();923 QualType HandleType = getResourceHandleField()->getType();924 QualType RecordType = AST.getTypeDeclType(cast<TypeDecl>(Record));925 BuiltinTypeMethodBuilder::LocalVar TmpVar("tmp", RecordType);926 927 return BuiltinTypeMethodBuilder(*this, "__createFromBinding", RecordType,928 false, false, SC_Static)929 .addParam("registerNo", AST.UnsignedIntTy)930 .addParam("spaceNo", AST.UnsignedIntTy)931 .addParam("range", AST.IntTy)932 .addParam("index", AST.UnsignedIntTy)933 .addParam("name", AST.getPointerType(AST.CharTy.withConst()))934 .declareLocalVar(TmpVar)935 .accessHandleFieldOnResource(TmpVar)936 .callBuiltin("__builtin_hlsl_resource_handlefrombinding", HandleType,937 PH::LastStmt, PH::_0, PH::_1, PH::_2, PH::_3, PH::_4)938 .setHandleFieldOnResource(TmpVar, PH::LastStmt)939 .returnValue(TmpVar)940 .finalize();941}942 943// Adds static method that initializes resource from binding:944//945// static Resource<T> __createFromImplicitBinding(unsigned orderId,946// unsigned spaceNo, int range,947// unsigned index,948// const char *name) {949// Resource<T> tmp;950// tmp.__handle = __builtin_hlsl_resource_handlefromimplicitbinding(951// tmp.__handle, spaceNo,952// range, index, orderId, name);953// return tmp;954// }955BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addCreateFromImplicitBinding() {956 assert(!Record->isCompleteDefinition() && "record is already complete");957 958 using PH = BuiltinTypeMethodBuilder::PlaceHolder;959 ASTContext &AST = SemaRef.getASTContext();960 QualType HandleType = getResourceHandleField()->getType();961 QualType RecordType = AST.getTypeDeclType(cast<TypeDecl>(Record));962 BuiltinTypeMethodBuilder::LocalVar TmpVar("tmp", RecordType);963 964 return BuiltinTypeMethodBuilder(*this, "__createFromImplicitBinding",965 RecordType, false, false, SC_Static)966 .addParam("orderId", AST.UnsignedIntTy)967 .addParam("spaceNo", AST.UnsignedIntTy)968 .addParam("range", AST.IntTy)969 .addParam("index", AST.UnsignedIntTy)970 .addParam("name", AST.getPointerType(AST.CharTy.withConst()))971 .declareLocalVar(TmpVar)972 .accessHandleFieldOnResource(TmpVar)973 .callBuiltin("__builtin_hlsl_resource_handlefromimplicitbinding",974 HandleType, PH::LastStmt, PH::_0, PH::_1, PH::_2, PH::_3,975 PH::_4)976 .setHandleFieldOnResource(TmpVar, PH::LastStmt)977 .returnValue(TmpVar)978 .finalize();979}980 981// Adds static method that initializes resource from binding:982//983// static Resource<T>984// __createFromBindingWithImplicitCounter(unsigned registerNo,985// unsigned spaceNo, int range,986// unsigned index, const char *name,987// unsigned counterOrderId) {988// Resource<T> tmp;989// tmp.__handle = __builtin_hlsl_resource_handlefrombinding(990// tmp.__handle, registerNo, spaceNo, range, index, name);991// tmp.__counter_handle =992// __builtin_hlsl_resource_counterhandlefromimplicitbinding(993// tmp.__handle, counterOrderId, spaceNo);994// return tmp;995// }996BuiltinTypeDeclBuilder &997BuiltinTypeDeclBuilder::addCreateFromBindingWithImplicitCounter() {998 assert(!Record->isCompleteDefinition() && "record is already complete");999 1000 using PH = BuiltinTypeMethodBuilder::PlaceHolder;1001 ASTContext &AST = SemaRef.getASTContext();1002 QualType HandleType = getResourceHandleField()->getType();1003 QualType RecordType = AST.getTypeDeclType(cast<TypeDecl>(Record));1004 BuiltinTypeMethodBuilder::LocalVar TmpVar("tmp", RecordType);1005 1006 return BuiltinTypeMethodBuilder(*this,1007 "__createFromBindingWithImplicitCounter",1008 RecordType, false, false, SC_Static)1009 .addParam("registerNo", AST.UnsignedIntTy)1010 .addParam("spaceNo", AST.UnsignedIntTy)1011 .addParam("range", AST.IntTy)1012 .addParam("index", AST.UnsignedIntTy)1013 .addParam("name", AST.getPointerType(AST.CharTy.withConst()))1014 .addParam("counterOrderId", AST.UnsignedIntTy)1015 .declareLocalVar(TmpVar)1016 .accessHandleFieldOnResource(TmpVar)1017 .callBuiltin("__builtin_hlsl_resource_handlefrombinding", HandleType,1018 PH::LastStmt, PH::_0, PH::_1, PH::_2, PH::_3, PH::_4)1019 .setHandleFieldOnResource(TmpVar, PH::LastStmt)1020 .accessHandleFieldOnResource(TmpVar)1021 .callBuiltin("__builtin_hlsl_resource_counterhandlefromimplicitbinding",1022 HandleType, PH::LastStmt, PH::_5, PH::_1)1023 .setCounterHandleFieldOnResource(TmpVar, PH::LastStmt)1024 .returnValue(TmpVar)1025 .finalize();1026}1027 1028// Adds static method that initializes resource from binding:1029//1030// static Resource<T>1031// __createFromImplicitBindingWithImplicitCounter(unsigned orderId,1032// unsigned spaceNo, int range,1033// unsigned index,1034// const char *name,1035// unsigned counterOrderId) {1036// Resource<T> tmp;1037// tmp.__handle = __builtin_hlsl_resource_handlefromimplicitbinding(1038// tmp.__handle, orderId, spaceNo, range, index, name);1039// tmp.__counter_handle =1040// __builtin_hlsl_resource_counterhandlefromimplicitbinding(1041// tmp.__handle, counterOrderId, spaceNo);1042// return tmp;1043// }1044BuiltinTypeDeclBuilder &1045BuiltinTypeDeclBuilder::addCreateFromImplicitBindingWithImplicitCounter() {1046 assert(!Record->isCompleteDefinition() && "record is already complete");1047 1048 using PH = BuiltinTypeMethodBuilder::PlaceHolder;1049 ASTContext &AST = SemaRef.getASTContext();1050 QualType HandleType = getResourceHandleField()->getType();1051 QualType RecordType = AST.getTypeDeclType(cast<TypeDecl>(Record));1052 BuiltinTypeMethodBuilder::LocalVar TmpVar("tmp", RecordType);1053 1054 return BuiltinTypeMethodBuilder(1055 *this, "__createFromImplicitBindingWithImplicitCounter",1056 RecordType, false, false, SC_Static)1057 .addParam("orderId", AST.UnsignedIntTy)1058 .addParam("spaceNo", AST.UnsignedIntTy)1059 .addParam("range", AST.IntTy)1060 .addParam("index", AST.UnsignedIntTy)1061 .addParam("name", AST.getPointerType(AST.CharTy.withConst()))1062 .addParam("counterOrderId", AST.UnsignedIntTy)1063 .declareLocalVar(TmpVar)1064 .accessHandleFieldOnResource(TmpVar)1065 .callBuiltin("__builtin_hlsl_resource_handlefromimplicitbinding",1066 HandleType, PH::LastStmt, PH::_0, PH::_1, PH::_2, PH::_3,1067 PH::_4)1068 .setHandleFieldOnResource(TmpVar, PH::LastStmt)1069 .accessHandleFieldOnResource(TmpVar)1070 .callBuiltin("__builtin_hlsl_resource_counterhandlefromimplicitbinding",1071 HandleType, PH::LastStmt, PH::_5, PH::_1)1072 .setCounterHandleFieldOnResource(TmpVar, PH::LastStmt)1073 .returnValue(TmpVar)1074 .finalize();1075}1076 1077BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addCopyConstructor() {1078 assert(!Record->isCompleteDefinition() && "record is already complete");1079 1080 ASTContext &AST = SemaRef.getASTContext();1081 QualType RecordType = AST.getCanonicalTagType(Record);1082 QualType ConstRecordType = RecordType.withConst();1083 QualType ConstRecordRefType = AST.getLValueReferenceType(ConstRecordType);1084 1085 using PH = BuiltinTypeMethodBuilder::PlaceHolder;1086 1087 BuiltinTypeMethodBuilder MMB(*this, /*Name=*/"", AST.VoidTy,1088 /*IsConst=*/false, /*IsCtor=*/true);1089 MMB.addParam("other", ConstRecordRefType)1090 .accessHandleFieldOnResource(PH::_0)1091 .assign(PH::Handle, PH::LastStmt);1092 1093 if (getResourceCounterHandleField())1094 MMB.accessCounterHandleFieldOnResource(PH::_0).assign(PH::CounterHandle,1095 PH::LastStmt);1096 1097 return MMB.finalize();1098}1099 1100BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addCopyAssignmentOperator() {1101 assert(!Record->isCompleteDefinition() && "record is already complete");1102 1103 ASTContext &AST = SemaRef.getASTContext();1104 QualType RecordType = AST.getCanonicalTagType(Record);1105 QualType ConstRecordType = RecordType.withConst();1106 QualType ConstRecordRefType = AST.getLValueReferenceType(ConstRecordType);1107 QualType RecordRefType = AST.getLValueReferenceType(RecordType);1108 1109 using PH = BuiltinTypeMethodBuilder::PlaceHolder;1110 DeclarationName Name = AST.DeclarationNames.getCXXOperatorName(OO_Equal);1111 BuiltinTypeMethodBuilder MMB(*this, Name, RecordRefType);1112 MMB.addParam("other", ConstRecordRefType)1113 .accessHandleFieldOnResource(PH::_0)1114 .assign(PH::Handle, PH::LastStmt);1115 1116 if (getResourceCounterHandleField())1117 MMB.accessCounterHandleFieldOnResource(PH::_0).assign(PH::CounterHandle,1118 PH::LastStmt);1119 1120 return MMB.returnThis().finalize();1121}1122 1123BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addArraySubscriptOperators() {1124 ASTContext &AST = Record->getASTContext();1125 DeclarationName Subscript =1126 AST.DeclarationNames.getCXXOperatorName(OO_Subscript);1127 1128 addHandleAccessFunction(Subscript, /*IsConst=*/true, /*IsRef=*/true);1129 if (getResourceAttrs().ResourceClass == llvm::dxil::ResourceClass::UAV)1130 addHandleAccessFunction(Subscript, /*IsConst=*/false, /*IsRef=*/true);1131 1132 return *this;1133}1134 1135BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addLoadMethods() {1136 assert(!Record->isCompleteDefinition() && "record is already complete");1137 1138 ASTContext &AST = Record->getASTContext();1139 IdentifierInfo &II = AST.Idents.get("Load", tok::TokenKind::identifier);1140 DeclarationName Load(&II);1141 // TODO: We also need versions with status for CheckAccessFullyMapped.1142 addHandleAccessFunction(Load, /*IsConst=*/false, /*IsRef=*/false);1143 addLoadWithStatusFunction(Load, /*IsConst=*/false);1144 1145 return *this;1146}1147 1148FieldDecl *BuiltinTypeDeclBuilder::getResourceHandleField() const {1149 auto I = Fields.find("__handle");1150 assert(I != Fields.end() &&1151 I->second->getType()->isHLSLAttributedResourceType() &&1152 "record does not have resource handle field");1153 return I->second;1154}1155 1156FieldDecl *BuiltinTypeDeclBuilder::getResourceCounterHandleField() const {1157 auto I = Fields.find("__counter_handle");1158 if (I == Fields.end() ||1159 !I->second->getType()->isHLSLAttributedResourceType())1160 return nullptr;1161 return I->second;1162}1163 1164QualType BuiltinTypeDeclBuilder::getFirstTemplateTypeParam() {1165 assert(Template && "record it not a template");1166 if (const auto *TTD = dyn_cast<TemplateTypeParmDecl>(1167 Template->getTemplateParameters()->getParam(0))) {1168 return QualType(TTD->getTypeForDecl(), 0);1169 }1170 return QualType();1171}1172 1173QualType BuiltinTypeDeclBuilder::getHandleElementType() {1174 if (Template)1175 return getFirstTemplateTypeParam();1176 // TODO: Should we default to VoidTy? Using `i8` is arguably ambiguous.1177 return SemaRef.getASTContext().Char8Ty;1178}1179 1180HLSLAttributedResourceType::Attributes1181BuiltinTypeDeclBuilder::getResourceAttrs() const {1182 QualType HandleType = getResourceHandleField()->getType();1183 return cast<HLSLAttributedResourceType>(HandleType)->getAttrs();1184}1185 1186BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::completeDefinition() {1187 assert(!Record->isCompleteDefinition() && "record is already complete");1188 assert(Record->isBeingDefined() &&1189 "Definition must be started before completing it.");1190 1191 Record->completeDefinition();1192 return *this;1193}1194 1195Expr *BuiltinTypeDeclBuilder::getConstantIntExpr(int value) {1196 ASTContext &AST = SemaRef.getASTContext();1197 return IntegerLiteral::Create(1198 AST, llvm::APInt(AST.getTypeSize(AST.IntTy), value, true), AST.IntTy,1199 SourceLocation());1200}1201 1202BuiltinTypeDeclBuilder &1203BuiltinTypeDeclBuilder::addSimpleTemplateParams(ArrayRef<StringRef> Names,1204 ConceptDecl *CD = nullptr) {1205 if (Record->isCompleteDefinition()) {1206 assert(Template && "existing record it not a template");1207 assert(Template->getTemplateParameters()->size() == Names.size() &&1208 "template param count mismatch");1209 return *this;1210 }1211 1212 TemplateParameterListBuilder Builder = TemplateParameterListBuilder(*this);1213 for (StringRef Name : Names)1214 Builder.addTypeParameter(Name);1215 return Builder.finalizeTemplateArgs(CD);1216}1217 1218BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addIncrementCounterMethod() {1219 using PH = BuiltinTypeMethodBuilder::PlaceHolder;1220 return BuiltinTypeMethodBuilder(*this, "IncrementCounter",1221 SemaRef.getASTContext().UnsignedIntTy)1222 .callBuiltin("__builtin_hlsl_buffer_update_counter", QualType(),1223 PH::CounterHandle, getConstantIntExpr(1))1224 .finalize();1225}1226 1227BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addDecrementCounterMethod() {1228 using PH = BuiltinTypeMethodBuilder::PlaceHolder;1229 return BuiltinTypeMethodBuilder(*this, "DecrementCounter",1230 SemaRef.getASTContext().UnsignedIntTy)1231 .callBuiltin("__builtin_hlsl_buffer_update_counter", QualType(),1232 PH::CounterHandle, getConstantIntExpr(-1))1233 .finalize();1234}1235 1236BuiltinTypeDeclBuilder &1237BuiltinTypeDeclBuilder::addLoadWithStatusFunction(DeclarationName &Name,1238 bool IsConst) {1239 assert(!Record->isCompleteDefinition() && "record is already complete");1240 ASTContext &AST = SemaRef.getASTContext();1241 using PH = BuiltinTypeMethodBuilder::PlaceHolder;1242 1243 QualType ReturnTy = getHandleElementType();1244 return BuiltinTypeMethodBuilder(*this, Name, ReturnTy, IsConst)1245 .addParam("Index", AST.UnsignedIntTy)1246 .addParam("Status", AST.UnsignedIntTy, HLSLParamModifierAttr::Keyword_out)1247 .callBuiltin("__builtin_hlsl_resource_load_with_status", ReturnTy,1248 PH::Handle, PH::_0, PH::_1)1249 .finalize();1250}1251 1252BuiltinTypeDeclBuilder &1253BuiltinTypeDeclBuilder::addHandleAccessFunction(DeclarationName &Name,1254 bool IsConst, bool IsRef) {1255 assert(!Record->isCompleteDefinition() && "record is already complete");1256 ASTContext &AST = SemaRef.getASTContext();1257 using PH = BuiltinTypeMethodBuilder::PlaceHolder;1258 1259 QualType ElemTy = getHandleElementType();1260 QualType AddrSpaceElemTy =1261 AST.getAddrSpaceQualType(ElemTy, LangAS::hlsl_device);1262 QualType ElemPtrTy = AST.getPointerType(AddrSpaceElemTy);1263 QualType ReturnTy;1264 1265 if (IsRef) {1266 ReturnTy = AddrSpaceElemTy;1267 if (IsConst)1268 ReturnTy.addConst();1269 ReturnTy = AST.getLValueReferenceType(ReturnTy);1270 } else {1271 ReturnTy = ElemTy;1272 if (IsConst)1273 ReturnTy.addConst();1274 }1275 1276 return BuiltinTypeMethodBuilder(*this, Name, ReturnTy, IsConst)1277 .addParam("Index", AST.UnsignedIntTy)1278 .callBuiltin("__builtin_hlsl_resource_getpointer", ElemPtrTy, PH::Handle,1279 PH::_0)1280 .dereference(PH::LastStmt)1281 .finalize();1282}1283 1284BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addAppendMethod() {1285 using PH = BuiltinTypeMethodBuilder::PlaceHolder;1286 ASTContext &AST = SemaRef.getASTContext();1287 QualType ElemTy = getHandleElementType();1288 QualType AddrSpaceElemTy =1289 AST.getAddrSpaceQualType(ElemTy, LangAS::hlsl_device);1290 return BuiltinTypeMethodBuilder(*this, "Append", AST.VoidTy)1291 .addParam("value", ElemTy)1292 .callBuiltin("__builtin_hlsl_buffer_update_counter", AST.UnsignedIntTy,1293 PH::CounterHandle, getConstantIntExpr(1))1294 .callBuiltin("__builtin_hlsl_resource_getpointer",1295 AST.getPointerType(AddrSpaceElemTy), PH::Handle,1296 PH::LastStmt)1297 .dereference(PH::LastStmt)1298 .assign(PH::LastStmt, PH::_0)1299 .finalize();1300}1301 1302BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addConsumeMethod() {1303 using PH = BuiltinTypeMethodBuilder::PlaceHolder;1304 ASTContext &AST = SemaRef.getASTContext();1305 QualType ElemTy = getHandleElementType();1306 QualType AddrSpaceElemTy =1307 AST.getAddrSpaceQualType(ElemTy, LangAS::hlsl_device);1308 return BuiltinTypeMethodBuilder(*this, "Consume", ElemTy)1309 .callBuiltin("__builtin_hlsl_buffer_update_counter", AST.UnsignedIntTy,1310 PH::CounterHandle, getConstantIntExpr(-1))1311 .callBuiltin("__builtin_hlsl_resource_getpointer",1312 AST.getPointerType(AddrSpaceElemTy), PH::Handle,1313 PH::LastStmt)1314 .dereference(PH::LastStmt)1315 .finalize();1316}1317 1318BuiltinTypeDeclBuilder &1319BuiltinTypeDeclBuilder::addGetDimensionsMethodForBuffer() {1320 using PH = BuiltinTypeMethodBuilder::PlaceHolder;1321 ASTContext &AST = SemaRef.getASTContext();1322 QualType UIntTy = AST.UnsignedIntTy;1323 1324 QualType HandleTy = getResourceHandleField()->getType();1325 auto *AttrResTy = cast<HLSLAttributedResourceType>(HandleTy.getTypePtr());1326 1327 // Structured buffers except {RW}ByteAddressBuffer have overload1328 // GetDimensions(out uint numStructs, out uint stride).1329 if (AttrResTy->getAttrs().RawBuffer &&1330 AttrResTy->getContainedType() != AST.Char8Ty) {1331 return BuiltinTypeMethodBuilder(*this, "GetDimensions", AST.VoidTy)1332 .addParam("numStructs", UIntTy, HLSLParamModifierAttr::Keyword_out)1333 .addParam("stride", UIntTy, HLSLParamModifierAttr::Keyword_out)1334 .callBuiltin("__builtin_hlsl_resource_getdimensions_x", QualType(),1335 PH::Handle, PH::_0)1336 .callBuiltin("__builtin_hlsl_resource_getstride", QualType(),1337 PH::Handle, PH::_1)1338 .finalize();1339 }1340 1341 // Typed buffers and {RW}ByteAddressBuffer have overload1342 // GetDimensions(out uint dim).1343 return BuiltinTypeMethodBuilder(*this, "GetDimensions", AST.VoidTy)1344 .addParam("dim", UIntTy, HLSLParamModifierAttr::Keyword_out)1345 .callBuiltin("__builtin_hlsl_resource_getdimensions_x", QualType(),1346 PH::Handle, PH::_0)1347 .finalize();1348}1349 1350} // namespace hlsl1351} // namespace clang1352