brintos

brintos / llvm-project-archived public Read only

0
0
Text · 52.8 KiB · 868f894 Raw
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