@@ -123,12 +123,8 @@ struct BuiltinTypeDeclBuilder {
123123 assert (!Record->isCompleteDefinition () && " record is already complete" );
124124
125125 ASTContext &Ctx = SemaRef.getASTContext ();
126- TypeSourceInfo *ElementTypeInfo = nullptr ;
127-
128- QualType ElemTy = Ctx.Char8Ty ;
129- if (Template)
130- ElemTy = getFirstTemplateTypeParam ();
131- ElementTypeInfo = Ctx.getTrivialTypeSourceInfo (ElemTy, SourceLocation ());
126+ TypeSourceInfo *ElementTypeInfo =
127+ Ctx.getTrivialTypeSourceInfo (getHandleElementType (), SourceLocation ());
132128
133129 // add handle member with resource type attributes
134130 QualType AttributedResTy = QualType ();
@@ -171,90 +167,12 @@ struct BuiltinTypeDeclBuilder {
171167 }
172168
173169 BuiltinTypeDeclBuilder &addArraySubscriptOperators () {
174- addArraySubscriptOperator (true );
175- addArraySubscriptOperator (false );
176- return *this ;
177- }
178-
179- BuiltinTypeDeclBuilder &addArraySubscriptOperator (bool IsConst) {
180- assert (!Record->isCompleteDefinition () && " record is already complete" );
181-
182170 ASTContext &AST = Record->getASTContext ();
183- QualType ElemTy = AST.Char8Ty ;
184- if (Template)
185- ElemTy = getFirstTemplateTypeParam ();
186- QualType ReturnTy = ElemTy;
187-
188- FunctionProtoType::ExtProtoInfo ExtInfo;
189-
190- // Subscript operators return references to elements, const makes the
191- // reference and method const so that the underlying data is not mutable.
192- if (IsConst) {
193- ExtInfo.TypeQuals .addConst ();
194- ReturnTy.addConst ();
195- }
196- ReturnTy = AST.getLValueReferenceType (ReturnTy);
197-
198- QualType MethodTy =
199- AST.getFunctionType (ReturnTy, {AST.UnsignedIntTy }, ExtInfo);
200- auto *TSInfo = AST.getTrivialTypeSourceInfo (MethodTy, SourceLocation ());
201- auto *MethodDecl = CXXMethodDecl::Create (
202- AST, Record, SourceLocation (),
203- DeclarationNameInfo (
204- AST.DeclarationNames .getCXXOperatorName (OO_Subscript),
205- SourceLocation ()),
206- MethodTy, TSInfo, SC_None, false , false , ConstexprSpecKind::Unspecified,
207- SourceLocation ());
208-
209- IdentifierInfo &II = AST.Idents .get (" Idx" , tok::TokenKind::identifier);
210- auto *IdxParam = ParmVarDecl::Create (
211- AST, MethodDecl->getDeclContext (), SourceLocation (), SourceLocation (),
212- &II, AST.UnsignedIntTy ,
213- AST.getTrivialTypeSourceInfo (AST.UnsignedIntTy , SourceLocation ()),
214- SC_None, nullptr );
215- MethodDecl->setParams ({IdxParam});
216-
217- // Also add the parameter to the function prototype.
218- auto FnProtoLoc = TSInfo->getTypeLoc ().getAs <FunctionProtoTypeLoc>();
219- FnProtoLoc.setParam (0 , IdxParam);
220-
221- auto *This =
222- CXXThisExpr::Create (AST, SourceLocation (),
223- MethodDecl->getFunctionObjectParameterType (), true );
224- FieldDecl *Handle = Fields[" __handle" ];
225- auto *HandleExpr = MemberExpr::CreateImplicit (
226- AST, This, false , Handle, Handle->getType (), VK_LValue, OK_Ordinary);
227-
228- auto *IndexExpr = DeclRefExpr::Create (
229- AST, NestedNameSpecifierLoc (), SourceLocation (), IdxParam, false ,
230- DeclarationNameInfo (IdxParam->getDeclName (), SourceLocation ()),
231- AST.UnsignedIntTy , VK_PRValue);
232-
233- FunctionDecl *FD =
234- lookupBuiltinFunction (SemaRef, " __builtin_hlsl_resource_getpointer" );
235- DeclRefExpr *Builtin = DeclRefExpr::Create (
236- AST, NestedNameSpecifierLoc (), SourceLocation (), FD, false ,
237- FD->getNameInfo (), AST.BuiltinFnTy , VK_PRValue);
238-
239- // TODO: Map to an hlsl_device address space.
240- QualType ElemPtrTy = AST.getPointerType (ElemTy);
241- Expr *Call =
242- CallExpr::Create (AST, Builtin, {HandleExpr, IndexExpr}, ElemPtrTy,
243- VK_PRValue, SourceLocation (), FPOptionsOverride ());
244- Expr *Deref = UnaryOperator::Create (
245- AST, Call, UO_Deref, ElemTy, VK_PRValue, OK_Ordinary, SourceLocation (),
246- /* CanOverflow=*/ false , FPOptionsOverride ());
247- auto *Return = ReturnStmt::Create (AST, SourceLocation (), Deref, nullptr );
248-
249- MethodDecl->setBody (CompoundStmt::Create (AST, {Return}, FPOptionsOverride (),
250- SourceLocation (),
251- SourceLocation ()));
252- MethodDecl->setLexicalDeclContext (Record);
253- MethodDecl->setAccess (AccessSpecifier::AS_public);
254- MethodDecl->addAttr (AlwaysInlineAttr::CreateImplicit (
255- AST, SourceRange (), AlwaysInlineAttr::CXX11_clang_always_inline));
256- Record->addDecl (MethodDecl);
171+ DeclarationName Subscript =
172+ AST.DeclarationNames .getCXXOperatorName (OO_Subscript);
257173
174+ addHandleAccessFunction (Subscript, /* IsConst=*/ true , /* IsRef=*/ true );
175+ addHandleAccessFunction (Subscript, /* IsConst=*/ false , /* IsRef=*/ true );
258176 return *this ;
259177 }
260178
@@ -275,6 +193,13 @@ struct BuiltinTypeDeclBuilder {
275193 return QualType ();
276194 }
277195
196+ QualType getHandleElementType () {
197+ if (Template)
198+ return getFirstTemplateTypeParam ();
199+ // TODO: Should we default to VoidTy? Using `i8` is arguably ambiguous.
200+ return SemaRef.getASTContext ().Char8Ty ;
201+ }
202+
278203 BuiltinTypeDeclBuilder &startDefinition () {
279204 assert (!Record->isCompleteDefinition () && " record is already complete" );
280205 Record->startDefinition ();
@@ -304,6 +229,8 @@ struct BuiltinTypeDeclBuilder {
304229 // Builtin types methods
305230 BuiltinTypeDeclBuilder &addIncrementCounterMethod ();
306231 BuiltinTypeDeclBuilder &addDecrementCounterMethod ();
232+ BuiltinTypeDeclBuilder &addHandleAccessFunction (DeclarationName &Name,
233+ bool IsConst, bool IsRef);
307234};
308235
309236struct TemplateParameterListBuilder {
@@ -463,7 +390,7 @@ struct TemplateParameterListBuilder {
463390// Builder for methods of builtin types. Allows adding methods to builtin types
464391// using the builder pattern like this:
465392//
466- // BuiltinTypeMethodBuilder(Sema, RecordBuilder, "MethodName", ReturnType)
393+ // BuiltinTypeMethodBuilder(RecordBuilder, "MethodName", ReturnType)
467394// .addParam("param_name", Type, InOutModifier)
468395// .callBuiltin("builtin_name", BuiltinParams...)
469396// .finalizeMethod();
@@ -496,6 +423,7 @@ struct BuiltinTypeMethodBuilder {
496423 DeclarationNameInfo NameInfo;
497424 QualType ReturnTy;
498425 CXXMethodDecl *Method;
426+ bool IsConst;
499427 llvm::SmallVector<MethodParam> Params;
500428 llvm::SmallVector<Stmt *> StmtsList;
501429
@@ -518,11 +446,16 @@ struct BuiltinTypeMethodBuilder {
518446 Expr *convertPlaceholder (Expr *E) { return E; }
519447
520448public:
521- BuiltinTypeMethodBuilder (Sema &S, BuiltinTypeDeclBuilder &DB, StringRef Name,
522- QualType ReturnTy)
523- : DeclBuilder(DB), ReturnTy(ReturnTy), Method(nullptr ) {
449+ BuiltinTypeMethodBuilder (BuiltinTypeDeclBuilder &DB, DeclarationName &Name,
450+ QualType ReturnTy, bool IsConst = false )
451+ : DeclBuilder(DB), NameInfo(DeclarationNameInfo(Name, SourceLocation())),
452+ ReturnTy (ReturnTy), Method(nullptr ), IsConst(IsConst) {}
453+
454+ BuiltinTypeMethodBuilder (BuiltinTypeDeclBuilder &DB, StringRef Name,
455+ QualType ReturnTy, bool IsConst = false )
456+ : DeclBuilder(DB), ReturnTy(ReturnTy), Method(nullptr ), IsConst(IsConst) {
524457 const IdentifierInfo &II =
525- S .getASTContext ().Idents .get (Name, tok::TokenKind::identifier);
458+ DB. SemaRef .getASTContext ().Idents .get (Name, tok::TokenKind::identifier);
526459 NameInfo = DeclarationNameInfo (DeclarationName (&II), SourceLocation ());
527460 }
528461
@@ -545,8 +478,12 @@ struct BuiltinTypeMethodBuilder {
545478 SmallVector<QualType> ParamTypes;
546479 for (MethodParam &MP : Params)
547480 ParamTypes.emplace_back (MP.Ty );
548- QualType MethodTy = AST.getFunctionType (ReturnTy, ParamTypes,
549- FunctionProtoType::ExtProtoInfo ());
481+
482+ FunctionProtoType::ExtProtoInfo ExtInfo;
483+ if (IsConst)
484+ ExtInfo.TypeQuals .addConst ();
485+
486+ QualType MethodTy = AST.getFunctionType (ReturnTy, ParamTypes, ExtInfo);
550487
551488 // create method decl
552489 auto *TSInfo = AST.getTrivialTypeSourceInfo (MethodTy, SourceLocation ());
@@ -596,7 +533,8 @@ struct BuiltinTypeMethodBuilder {
596533 }
597534
598535 template <typename ... Ts>
599- BuiltinTypeMethodBuilder &callBuiltin (StringRef BuiltinName, Ts... ArgSpecs) {
536+ BuiltinTypeMethodBuilder &callBuiltin (StringRef BuiltinName,
537+ QualType ReturnType, Ts... ArgSpecs) {
600538 std::array<Expr *, sizeof ...(ArgSpecs)> Args{
601539 convertPlaceholder (std::forward<Ts>(ArgSpecs))...};
602540
@@ -609,15 +547,32 @@ struct BuiltinTypeMethodBuilder {
609547 FunctionDecl *FD = lookupBuiltinFunction (DeclBuilder.SemaRef , BuiltinName);
610548 DeclRefExpr *DRE = DeclRefExpr::Create (
611549 AST, NestedNameSpecifierLoc (), SourceLocation (), FD, false ,
612- FD->getNameInfo (), FD->getType (), VK_PRValue);
550+ FD->getNameInfo (), AST.BuiltinFnTy , VK_PRValue);
551+
552+ if (ReturnType.isNull ())
553+ ReturnType = FD->getReturnType ();
613554
614- Expr *Call =
615- CallExpr::Create (AST, DRE, Args, FD->getReturnType (), VK_PRValue,
616- SourceLocation (), FPOptionsOverride ());
555+ Expr *Call = CallExpr::Create (AST, DRE, Args, ReturnType, VK_PRValue,
556+ SourceLocation (), FPOptionsOverride ());
617557 StmtsList.push_back (Call);
618558 return *this ;
619559 }
620560
561+ BuiltinTypeMethodBuilder &dereference () {
562+ assert (!StmtsList.empty () && " Nothing to dereference" );
563+ ASTContext &AST = DeclBuilder.SemaRef .getASTContext ();
564+
565+ Expr *LastExpr = dyn_cast<Expr>(StmtsList.back ());
566+ assert (LastExpr && " No expression to dereference" );
567+ Expr *Deref = UnaryOperator::Create (
568+ AST, LastExpr, UO_Deref, LastExpr->getType ()->getPointeeType (),
569+ VK_PRValue, OK_Ordinary, SourceLocation (),
570+ /* CanOverflow=*/ false , FPOptionsOverride ());
571+ StmtsList.pop_back ();
572+ StmtsList.push_back (Deref);
573+ return *this ;
574+ }
575+
621576 BuiltinTypeDeclBuilder &finalizeMethod () {
622577 assert (!DeclBuilder.Record ->isCompleteDefinition () &&
623578 " record is already complete" );
@@ -631,11 +586,8 @@ struct BuiltinTypeMethodBuilder {
631586 " nothing to return from non-void method" );
632587 if (ReturnTy != AST.VoidTy ) {
633588 if (Expr *LastExpr = dyn_cast<Expr>(StmtsList.back ())) {
634- assert (AST.hasSameUnqualifiedType (
635- isa<CallExpr>(LastExpr)
636- ? cast<CallExpr>(LastExpr)->getCallReturnType (AST)
637- : LastExpr->getType (),
638- ReturnTy) &&
589+ assert (AST.hasSameUnqualifiedType (LastExpr->getType (),
590+ ReturnTy.getNonReferenceType ()) &&
639591 " Return type of the last statement must match the return type "
640592 " of the method" );
641593 if (!isa<ReturnStmt>(LastExpr)) {
@@ -682,19 +634,43 @@ BuiltinTypeDeclBuilder::addSimpleTemplateParams(ArrayRef<StringRef> Names,
682634
683635BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addIncrementCounterMethod () {
684636 using PH = BuiltinTypeMethodBuilder::PlaceHolder;
685- return BuiltinTypeMethodBuilder (SemaRef, *this , " IncrementCounter" ,
637+ return BuiltinTypeMethodBuilder (*this , " IncrementCounter" ,
686638 SemaRef.getASTContext ().UnsignedIntTy )
687- .callBuiltin (" __builtin_hlsl_buffer_update_counter" , PH::Handle ,
688- getConstantIntExpr (1 ))
639+ .callBuiltin (" __builtin_hlsl_buffer_update_counter" , QualType () ,
640+ PH::Handle, getConstantIntExpr (1 ))
689641 .finalizeMethod ();
690642}
691643
692644BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addDecrementCounterMethod () {
693645 using PH = BuiltinTypeMethodBuilder::PlaceHolder;
694- return BuiltinTypeMethodBuilder (SemaRef, *this , " DecrementCounter" ,
646+ return BuiltinTypeMethodBuilder (*this , " DecrementCounter" ,
695647 SemaRef.getASTContext ().UnsignedIntTy )
696- .callBuiltin (" __builtin_hlsl_buffer_update_counter" , PH::Handle,
697- getConstantIntExpr (-1 ))
648+ .callBuiltin (" __builtin_hlsl_buffer_update_counter" , QualType (),
649+ PH::Handle, getConstantIntExpr (-1 ))
650+ .finalizeMethod ();
651+ }
652+
653+ BuiltinTypeDeclBuilder &
654+ BuiltinTypeDeclBuilder::addHandleAccessFunction (DeclarationName &Name,
655+ bool IsConst, bool IsRef) {
656+ assert (!Record->isCompleteDefinition () && " record is already complete" );
657+ ASTContext &AST = SemaRef.getASTContext ();
658+ using PH = BuiltinTypeMethodBuilder::PlaceHolder;
659+
660+ QualType ElemTy = getHandleElementType ();
661+ // TODO: Map to an hlsl_device address space.
662+ QualType ElemPtrTy = AST.getPointerType (ElemTy);
663+ QualType ReturnTy = ElemTy;
664+ if (IsConst)
665+ ReturnTy.addConst ();
666+ if (IsRef)
667+ ReturnTy = AST.getLValueReferenceType (ReturnTy);
668+
669+ return BuiltinTypeMethodBuilder (*this , Name, ReturnTy, IsConst)
670+ .addParam (" Index" , AST.UnsignedIntTy )
671+ .callBuiltin (" __builtin_hlsl_resource_getpointer" , ElemPtrTy, PH::Handle,
672+ PH::_0)
673+ .dereference ()
698674 .finalizeMethod ();
699675}
700676
0 commit comments