Author: Steven Perron Date: 2026-03-30T14:53:09Z New Revision: 58419354a8b3a3f981507d13c3324511eb4833ca
URL: https://github.com/llvm/llvm-project/commit/58419354a8b3a3f981507d13c3324511eb4833ca DIFF: https://github.com/llvm/llvm-project/commit/58419354a8b3a3f981507d13c3324511eb4833ca.diff LOG: [HLSL] Implement Texture2D::mips[][] (#186143) We implement the Textur2D::mips[][] method. We follow the design in DXC. There is a new member called `mips` with type mips_type. The member will contain a copy of the handle for the texture. The type `mips_type` will have a member function `operator[]` that takes a level, and returns a `mips_slice_type`. The slice will contain the handle and the level. It also has an operator[] member function that take a coordinate. It will do a load from the handle with the level and coordinate, and return that value. Assisted-by: Gemini Added: clang/test/CodeGenHLSL/resources/Texture2D-Mips.hlsl clang/test/SemaHLSL/Texture2D-mips-errors.hlsl Modified: clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.h clang/lib/Sema/HLSLExternalSemaSource.cpp clang/test/CodeGenHLSL/resources/Texture2D-Gather.hlsl clang/test/CodeGenHLSL/resources/Texture2D-Sample.hlsl clang/test/CodeGenHLSL/resources/Texture2D-SampleBias.hlsl clang/test/CodeGenHLSL/resources/Texture2D-SampleCmp.hlsl clang/test/CodeGenHLSL/resources/Texture2D-SampleGrad.hlsl clang/test/CodeGenHLSL/resources/Texture2D-SampleLevel.hlsl clang/test/CodeGenHLSL/resources/Texture2D-default-explicit-binding.hlsl clang/test/CodeGenHLSL/resources/Texture2D-default.hlsl clang/test/CodeGenHLSL/resources/Texture2D-shorthand-contexts.hlsl Removed: ################################################################################ diff --git a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp index a99b9446fd65f..3c84cd28732c9 100644 --- a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp +++ b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp @@ -16,6 +16,7 @@ #include "clang/AST/Attr.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclCXX.h" +#include "clang/AST/DeclFriend.h" #include "clang/AST/DeclTemplate.h" #include "clang/AST/Expr.h" #include "clang/AST/HLSLResource.h" @@ -187,6 +188,7 @@ struct BuiltinTypeMethodBuilder { _5, Handle = 128, CounterHandle, + This, LastStmt }; @@ -226,12 +228,22 @@ struct BuiltinTypeMethodBuilder { template <typename TLHS, typename TRHS> BuiltinTypeMethodBuilder &assign(TLHS LHS, TRHS RHS); template <typename T> BuiltinTypeMethodBuilder &dereference(T Ptr); + template <typename V, typename S> + BuiltinTypeMethodBuilder &concat(V Vec, S Scalar, QualType ResultTy); template <typename T> BuiltinTypeMethodBuilder &accessHandleFieldOnResource(T ResourceRecord); - template <typename ResourceT, typename ValueT> - BuiltinTypeMethodBuilder &setHandleFieldOnResource(ResourceT ResourceRecord, + template <typename T> + BuiltinTypeMethodBuilder &accessFieldOnResource(T ResourceRecord, + FieldDecl *Field); + template <typename ValueT> + BuiltinTypeMethodBuilder &setHandleFieldOnResource(LocalVar &ResourceRecord, ValueT HandleValue); + template <typename ResourceT, typename ValueT> + BuiltinTypeMethodBuilder &setFieldOnResource(ResourceT ResourceRecord, + ValueT HandleValue, + FieldDecl *HandleField); + void setMipsHandleField(LocalVar &ResourceRecord); template <typename T> BuiltinTypeMethodBuilder & accessCounterHandleFieldOnResource(T ResourceRecord); @@ -240,7 +252,8 @@ struct BuiltinTypeMethodBuilder { setCounterHandleFieldOnResource(ResourceT ResourceRecord, ValueT HandleValue); template <typename T> BuiltinTypeMethodBuilder &returnValue(T ReturnValue); BuiltinTypeMethodBuilder &returnThis(); - BuiltinTypeDeclBuilder &finalize(); + BuiltinTypeDeclBuilder & + finalize(AccessSpecifier Access = AccessSpecifier::AS_public); Expr *getResourceHandleExpr(); Expr *getResourceCounterHandleExpr(); @@ -253,11 +266,6 @@ struct BuiltinTypeMethodBuilder { if (!Method) createDecl(); } - - template <typename ResourceT, typename ValueT> - BuiltinTypeMethodBuilder &setFieldOnResource(ResourceT ResourceRecord, - ValueT HandleValue, - FieldDecl *HandleField); }; TemplateParameterListBuilder::~TemplateParameterListBuilder() { @@ -414,6 +422,12 @@ Expr *BuiltinTypeMethodBuilder::convertPlaceholder(PlaceHolder PH) { return getResourceHandleExpr(); if (PH == PlaceHolder::CounterHandle) return getResourceCounterHandleExpr(); + if (PH == PlaceHolder::This) { + ASTContext &AST = DeclBuilder.SemaRef.getASTContext(); + return CXXThisExpr::Create(AST, SourceLocation(), + Method->getFunctionObjectParameterType(), + /*IsImplicit=*/true); + } if (PH == PlaceHolder::LastStmt) { assert(!StmtsList.empty() && "no statements in the list"); @@ -609,6 +623,45 @@ BuiltinTypeMethodBuilder::declareLocalVar(LocalVar &Var) { return *this; } +template <typename V, typename S> +BuiltinTypeMethodBuilder &BuiltinTypeMethodBuilder::concat(V Vec, S Scalar, + QualType ResultTy) { + assert(ResultTy->isVectorType() && "The result type must be a vector type."); + ASTContext &AST = DeclBuilder.SemaRef.getASTContext(); + Expr *VecExpr = convertPlaceholder(Vec); + auto *VecTy = VecExpr->getType()->castAs<VectorType>(); + Expr *ScalarExpr = convertPlaceholder(Scalar); + + // Save the vector to a local variable to avoid evaluating the placeholder + // multiple times or sharing the AST node. + LocalVar VecVar("vec_tmp", VecTy->desugar()); + declareLocalVar(VecVar); + assign(VecVar, VecExpr); + + QualType EltTy = VecTy->getElementType(); + unsigned NumElts = VecTy->getNumElements(); + + SmallVector<Expr *, 4> Elts; + for (unsigned I = 0; I < NumElts; ++I) { + Elts.push_back(new (AST) ArraySubscriptExpr( + convertPlaceholder(VecVar), DeclBuilder.getConstantIntExpr(I), EltTy, + VK_PRValue, OK_Ordinary, SourceLocation())); + } + Elts.push_back(ScalarExpr); + + auto *InitList = + new (AST) InitListExpr(AST, SourceLocation(), Elts, SourceLocation()); + InitList->setType(ResultTy); + + ExprResult Cast = DeclBuilder.SemaRef.BuildCStyleCastExpr( + SourceLocation(), AST.getTrivialTypeSourceInfo(ResultTy), + SourceLocation(), InitList); + assert(!Cast.isInvalid() && "Cast cannot fail!"); + StmtsList.push_back(Cast.get()); + + return *this; +} + BuiltinTypeMethodBuilder &BuiltinTypeMethodBuilder::returnThis() { ASTContext &AST = DeclBuilder.SemaRef.getASTContext(); CXXThisExpr *ThisExpr = CXXThisExpr::Create( @@ -705,12 +758,67 @@ BuiltinTypeMethodBuilder::accessHandleFieldOnResource(T ResourceRecord) { return *this; } -template <typename ResourceT, typename ValueT> +template <typename T> +BuiltinTypeMethodBuilder & +BuiltinTypeMethodBuilder::accessFieldOnResource(T ResourceRecord, + FieldDecl *Field) { + ensureCompleteDecl(); + Expr *Base = convertPlaceholder(ResourceRecord); + + ASTContext &AST = DeclBuilder.SemaRef.getASTContext(); + auto *Member = + MemberExpr::CreateImplicit(AST, Base, /*IsArrow=*/false, Field, + Field->getType(), VK_LValue, OK_Ordinary); + StmtsList.push_back(Member); + return *this; +} + +void BuiltinTypeMethodBuilder::setMipsHandleField(LocalVar &ResourceRecord) { + FieldDecl *MipsField = DeclBuilder.Fields.lookup("mips"); + if (!MipsField) + return; + + ASTContext &AST = DeclBuilder.SemaRef.getASTContext(); + QualType MipsTy = MipsField->getType(); + const auto *RT = MipsTy->castAs<RecordType>(); + CXXRecordDecl *MipsRecord = cast<CXXRecordDecl>(RT->getDecl()); + + // The mips record should have a single field that is the handle. + assert(MipsRecord->field_begin() != MipsRecord->field_end() && + "mips_type must have at least one field"); + assert(std::next(MipsRecord->field_begin()) == MipsRecord->field_end() && + "mips_type must have exactly one field"); + FieldDecl *MipsHandleField = *MipsRecord->field_begin(); + + FieldDecl *HandleField = DeclBuilder.getResourceHandleField(); + Expr *ResExpr = convertPlaceholder(ResourceRecord); + MemberExpr *HandleMemberExpr = MemberExpr::CreateImplicit( + AST, ResExpr, false, HandleField, HandleField->getType(), VK_LValue, + OK_Ordinary); + + MemberExpr *MipsMemberExpr = + MemberExpr::CreateImplicit(AST, ResExpr, false, MipsField, + MipsField->getType(), VK_LValue, OK_Ordinary); + MemberExpr *MipsHandleMemberExpr = MemberExpr::CreateImplicit( + AST, MipsMemberExpr, false, MipsHandleField, MipsHandleField->getType(), + VK_LValue, OK_Ordinary); + + Stmt *AssignStmt = BinaryOperator::Create( + AST, MipsHandleMemberExpr, HandleMemberExpr, BO_Assign, + MipsHandleMemberExpr->getType(), ExprValueKind::VK_LValue, + ExprObjectKind::OK_Ordinary, SourceLocation(), FPOptionsOverride()); + + StmtsList.push_back(AssignStmt); +} + +template <typename ValueT> BuiltinTypeMethodBuilder & -BuiltinTypeMethodBuilder::setHandleFieldOnResource(ResourceT ResourceRecord, +BuiltinTypeMethodBuilder::setHandleFieldOnResource(LocalVar &ResourceRecord, ValueT HandleValue) { - return setFieldOnResource(ResourceRecord, HandleValue, - DeclBuilder.getResourceHandleField()); + setFieldOnResource(ResourceRecord, HandleValue, + DeclBuilder.getResourceHandleField()); + setMipsHandleField(ResourceRecord); + return *this; } template <typename ResourceT, typename ValueT> @@ -791,7 +899,8 @@ BuiltinTypeMethodBuilder &BuiltinTypeMethodBuilder::returnValue(T ReturnValue) { return *this; } -BuiltinTypeDeclBuilder &BuiltinTypeMethodBuilder::finalize() { +BuiltinTypeDeclBuilder & +BuiltinTypeMethodBuilder::finalize(AccessSpecifier Access) { assert(!DeclBuilder.Record->isCompleteDefinition() && "record is already complete"); @@ -818,9 +927,11 @@ BuiltinTypeDeclBuilder &BuiltinTypeMethodBuilder::finalize() { Method->setBody(CompoundStmt::Create(AST, StmtsList, FPOptionsOverride(), SourceLocation(), SourceLocation())); Method->setLexicalDeclContext(DeclBuilder.Record); - Method->setAccess(AS_public); + Method->setAccess(Access); + Method->setImplicitlyInline(); Method->addAttr(AlwaysInlineAttr::CreateImplicit( AST, SourceRange(), AlwaysInlineAttr::CXX11_clang_always_inline)); + Method->addAttr(ConvergentAttr::CreateImplicit(AST)); if (!TemplateParamDecls.empty()) { TemplateParams = TemplateParameterList::Create( AST, SourceLocation(), SourceLocation(), TemplateParamDecls, @@ -921,9 +1032,11 @@ BuiltinTypeDeclBuilder & BuiltinTypeDeclBuilder::addBufferHandles(ResourceClass RC, bool IsROV, bool RawBuffer, bool HasCounter, AccessSpecifier Access) { - addHandleMember(RC, ResourceDimension::Unknown, IsROV, RawBuffer, Access); + QualType ElementTy = getHandleElementType(); + addHandleMember(RC, ResourceDimension::Unknown, IsROV, RawBuffer, ElementTy, + Access); if (HasCounter) - addCounterHandleMember(RC, IsROV, RawBuffer, Access); + addCounterHandleMember(RC, IsROV, RawBuffer, ElementTy, Access); return *this; } @@ -931,39 +1044,71 @@ BuiltinTypeDeclBuilder & BuiltinTypeDeclBuilder::addTextureHandle(ResourceClass RC, bool IsROV, ResourceDimension RD, AccessSpecifier Access) { - addHandleMember(RC, RD, IsROV, /*RawBuffer=*/false, Access); + addHandleMember(RC, RD, IsROV, /*RawBuffer=*/false, getHandleElementType(), + Access); return *this; } BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addSamplerHandle() { addHandleMember(ResourceClass::Sampler, ResourceDimension::Unknown, - /*IsROV=*/false, /*RawBuffer=*/false); + /*IsROV=*/false, /*RawBuffer=*/false, getHandleElementType()); return *this; } BuiltinTypeDeclBuilder & -BuiltinTypeDeclBuilder::addHandleMember(ResourceClass RC, ResourceDimension RD, - bool IsROV, bool RawBuffer, - AccessSpecifier Access) { +BuiltinTypeDeclBuilder::addFriend(CXXRecordDecl *Friend) { + assert(!Record->isCompleteDefinition() && "record is already complete"); + ASTContext &AST = SemaRef.getASTContext(); + QualType FriendTy = AST.getCanonicalTagType(Friend); + TypeSourceInfo *TSI = AST.getTrivialTypeSourceInfo(FriendTy); + FriendDecl *FD = + FriendDecl::Create(AST, Record, SourceLocation(), TSI, SourceLocation()); + FD->setAccess(AS_public); + Record->addDecl(FD); + return *this; +} + +CXXRecordDecl *BuiltinTypeDeclBuilder::addPrivateNestedRecord(StringRef Name) { + assert(!Record->isCompleteDefinition() && "record is already complete"); + ASTContext &AST = SemaRef.getASTContext(); + IdentifierInfo &II = AST.Idents.get(Name, tok::TokenKind::identifier); + CXXRecordDecl *NestedRecord = + CXXRecordDecl::Create(AST, TagDecl::TagKind::Struct, Record, + SourceLocation(), SourceLocation(), &II); + NestedRecord->setImplicit(true); + NestedRecord->setAccess(AccessSpecifier::AS_private); + NestedRecord->setLexicalDeclContext(Record); + Record->addDecl(NestedRecord); + return NestedRecord; +} + +BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addHandleMember( + ResourceClass RC, ResourceDimension RD, bool IsROV, bool RawBuffer, + QualType ElementTy, AccessSpecifier Access) { return addResourceMember("__handle", RC, RD, IsROV, RawBuffer, - /*IsCounter=*/false, Access); + /*IsCounter=*/false, ElementTy, Access); } BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addCounterHandleMember( - ResourceClass RC, bool IsROV, bool RawBuffer, AccessSpecifier Access) { + ResourceClass RC, bool IsROV, bool RawBuffer, QualType ElementTy, + AccessSpecifier Access) { return addResourceMember("__counter_handle", RC, ResourceDimension::Unknown, IsROV, RawBuffer, - /*IsCounter=*/true, Access); + /*IsCounter=*/true, ElementTy, Access); } BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addResourceMember( StringRef MemberName, ResourceClass RC, ResourceDimension RD, bool IsROV, - bool RawBuffer, bool IsCounter, AccessSpecifier Access) { + bool RawBuffer, bool IsCounter, QualType ElementTy, + AccessSpecifier Access) { assert(!Record->isCompleteDefinition() && "record is already complete"); ASTContext &Ctx = SemaRef.getASTContext(); + + assert(!ElementTy.isNull() && + "The caller should always pass in the type for the handle."); TypeSourceInfo *ElementTypeInfo = - Ctx.getTrivialTypeSourceInfo(getHandleElementType(), SourceLocation()); + Ctx.getTrivialTypeSourceInfo(ElementTy, SourceLocation()); // add handle member with resource type attributes QualType AttributedResTy = QualType(); @@ -988,7 +1133,8 @@ BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addResourceMember( // Adds default constructor to the resource class: // Resource::Resource() -BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addDefaultHandleConstructor() { +BuiltinTypeDeclBuilder & +BuiltinTypeDeclBuilder::addDefaultHandleConstructor(AccessSpecifier Access) { assert(!Record->isCompleteDefinition() && "record is already complete"); using PH = BuiltinTypeMethodBuilder::PlaceHolder; @@ -998,7 +1144,7 @@ BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addDefaultHandleConstructor() { .callBuiltin("__builtin_hlsl_resource_uninitializedhandle", HandleType, PH::Handle) .assign(PH::Handle, PH::LastStmt) - .finalize(); + .finalize(Access); } BuiltinTypeDeclBuilder & @@ -1185,7 +1331,8 @@ BuiltinTypeDeclBuilder::addCreateFromImplicitBindingWithImplicitCounter() { .finalize(); } -BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addCopyConstructor() { +BuiltinTypeDeclBuilder & +BuiltinTypeDeclBuilder::addCopyConstructor(AccessSpecifier Access) { assert(!Record->isCompleteDefinition() && "record is already complete"); ASTContext &AST = SemaRef.getASTContext(); @@ -1197,18 +1344,18 @@ BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addCopyConstructor() { BuiltinTypeMethodBuilder MMB(*this, /*Name=*/"", AST.VoidTy, /*IsConst=*/false, /*IsCtor=*/true); - MMB.addParam("other", ConstRecordRefType) - .accessHandleFieldOnResource(PH::_0) - .assign(PH::Handle, PH::LastStmt); + MMB.addParam("other", ConstRecordRefType); - if (getResourceCounterHandleField()) - MMB.accessCounterHandleFieldOnResource(PH::_0).assign(PH::CounterHandle, - PH::LastStmt); + for (auto *Field : Record->fields()) { + MMB.accessFieldOnResource(PH::_0, Field) + .setFieldOnResource(PH::This, PH::LastStmt, Field); + } - return MMB.finalize(); + return MMB.finalize(Access); } -BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addCopyAssignmentOperator() { +BuiltinTypeDeclBuilder & +BuiltinTypeDeclBuilder::addCopyAssignmentOperator(AccessSpecifier Access) { assert(!Record->isCompleteDefinition() && "record is already complete"); ASTContext &AST = SemaRef.getASTContext(); @@ -1220,15 +1367,14 @@ BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addCopyAssignmentOperator() { using PH = BuiltinTypeMethodBuilder::PlaceHolder; DeclarationName Name = AST.DeclarationNames.getCXXOperatorName(OO_Equal); BuiltinTypeMethodBuilder MMB(*this, Name, RecordRefType); - MMB.addParam("other", ConstRecordRefType) - .accessHandleFieldOnResource(PH::_0) - .assign(PH::Handle, PH::LastStmt); + MMB.addParam("other", ConstRecordRefType); - if (getResourceCounterHandleField()) - MMB.accessCounterHandleFieldOnResource(PH::_0).assign(PH::CounterHandle, - PH::LastStmt); + for (auto *Field : Record->fields()) { + MMB.accessFieldOnResource(PH::_0, Field) + .setFieldOnResource(PH::This, PH::LastStmt, Field); + } - return MMB.returnThis().finalize(); + return MMB.returnThis().finalize(Access); } BuiltinTypeDeclBuilder & @@ -1269,6 +1415,115 @@ BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addLoadMethods() { return *this; } +CXXRecordDecl *BuiltinTypeDeclBuilder::addMipsSliceType(ResourceDimension Dim, + QualType ReturnType) { + ASTContext &AST = Record->getASTContext(); + uint32_t VecSize = getResourceDimensions(Dim); + QualType IntTy = AST.IntTy; + QualType IndexTy = VecSize > 1 ? AST.getExtVectorType(IntTy, VecSize) : IntTy; + QualType CoordLevelTy = AST.getExtVectorType(IntTy, VecSize + 1); + using PH = BuiltinTypeMethodBuilder::PlaceHolder; + + // Define the mips_slice_type which is returned by mips_type::operator[]. + // It holds the resource handle and the mip level. It has an operator[] + // that takes the coordinate and performs the actual resource load. + CXXRecordDecl *MipsSliceRecord = addPrivateNestedRecord("mips_slice_type"); + BuiltinTypeDeclBuilder MipsSliceBuilder(SemaRef, MipsSliceRecord); + MipsSliceBuilder.addFriend(Record) + .addHandleMember(getResourceAttrs().ResourceClass, Dim, + getResourceAttrs().IsROV, false, ReturnType, + AccessSpecifier::AS_public) + .addMemberVariable("__level", IntTy, {}, AccessSpecifier::AS_public) + .addDefaultHandleConstructor(AccessSpecifier::AS_protected) + .addCopyConstructor(AccessSpecifier::AS_protected) + .addCopyAssignmentOperator(AccessSpecifier::AS_protected); + + FieldDecl *LevelField = MipsSliceBuilder.Fields["__level"]; + assert(LevelField && "Could not find the level field."); + + DeclarationName SubscriptName = + AST.DeclarationNames.getCXXOperatorName(OO_Subscript); + + // operator[](intN coord) on mips_slice_type + BuiltinTypeMethodBuilder(MipsSliceBuilder, SubscriptName, ReturnType, + /*IsConst=*/true) + .addParam("Coord", IndexTy) + .accessFieldOnResource(PH::This, LevelField) + .concat(PH::_0, PH::LastStmt, CoordLevelTy) + .callBuiltin("__builtin_hlsl_resource_load_level", ReturnType, PH::Handle, + PH::LastStmt) + .finalize(); + + MipsSliceBuilder.completeDefinition(); + return MipsSliceRecord; +} + +CXXRecordDecl *BuiltinTypeDeclBuilder::addMipsType(ResourceDimension Dim, + QualType ReturnType) { + ASTContext &AST = Record->getASTContext(); + QualType IntTy = AST.IntTy; + using PH = BuiltinTypeMethodBuilder::PlaceHolder; + + // First, define the mips_slice_type that will be returned by our operator[]. + CXXRecordDecl *MipsSliceRecord = addMipsSliceType(Dim, ReturnType); + + // Define the mips_type, which provides the syntax `Resource.mips[level]`. + // It only holds the handle, and its operator[] returns a mips_slice_type + // initialized with the handle and the requested mip level. + CXXRecordDecl *MipsRecord = addPrivateNestedRecord("mips_type"); + BuiltinTypeDeclBuilder MipsBuilder(SemaRef, MipsRecord); + MipsBuilder.addFriend(Record) + .addHandleMember(getResourceAttrs().ResourceClass, Dim, + getResourceAttrs().IsROV, false, ReturnType, + AccessSpecifier::AS_public) + .addDefaultHandleConstructor(AccessSpecifier::AS_protected) + .addCopyConstructor(AccessSpecifier::AS_protected) + .addCopyAssignmentOperator(AccessSpecifier::AS_protected); + + QualType MipsSliceTy = AST.getCanonicalTagType(MipsSliceRecord); + + DeclarationName SubscriptName = + AST.DeclarationNames.getCXXOperatorName(OO_Subscript); + + // Locate the fields in the slice type so we can initialize them. + auto FieldIt = MipsSliceRecord->field_begin(); + FieldDecl *MipsSliceHandleField = *FieldIt; + FieldDecl *LevelField = *++FieldIt; + assert(MipsSliceHandleField->getName() == "__handle" && + LevelField->getName() == "__level" && + "Could not find fields on mips_slice_type"); + + // operator[](int level) on mips_type + BuiltinTypeMethodBuilder::LocalVar MipsSliceVar("slice", MipsSliceTy); + BuiltinTypeMethodBuilder(MipsBuilder, SubscriptName, MipsSliceTy, + /*IsConst=*/true) + .addParam("Level", IntTy) + .declareLocalVar(MipsSliceVar) + .accessHandleFieldOnResource(PH::This) + .setFieldOnResource(MipsSliceVar, PH::LastStmt, MipsSliceHandleField) + .setFieldOnResource(MipsSliceVar, PH::_0, LevelField) + .returnValue(MipsSliceVar) + .finalize(); + + MipsBuilder.completeDefinition(); + return MipsRecord; +} + +BuiltinTypeDeclBuilder & +BuiltinTypeDeclBuilder::addMipsMember(ResourceDimension Dim) { + assert(!Record->isCompleteDefinition() && "record is already complete"); + ASTContext &AST = Record->getASTContext(); + QualType ReturnType = getHandleElementType(); + + CXXRecordDecl *MipsRecord = addMipsType(Dim, ReturnType); + + // Add the mips field to the texture + QualType MipsTy = AST.getCanonicalTagType(MipsRecord); + addMemberVariable("mips", MipsTy, {}, AccessSpecifier::AS_public); + + return *this; +} + BuiltinTypeDeclBuilder & BuiltinTypeDeclBuilder::addTextureLoadMethods(ResourceDimension Dim) { assert(!Record->isCompleteDefinition() && "record is already complete"); diff --git a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.h b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.h index 4fe6acabfac62..430dc00630676 100644 --- a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.h +++ b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.h @@ -87,9 +87,12 @@ class BuiltinTypeDeclBuilder { ResourceDimension Dim = ResourceDimension::Unknown); // Builtin types constructors - BuiltinTypeDeclBuilder &addDefaultHandleConstructor(); - BuiltinTypeDeclBuilder &addCopyConstructor(); - BuiltinTypeDeclBuilder &addCopyAssignmentOperator(); + BuiltinTypeDeclBuilder &addDefaultHandleConstructor( + AccessSpecifier Access = AccessSpecifier::AS_public); + BuiltinTypeDeclBuilder & + addCopyConstructor(AccessSpecifier Access = AccessSpecifier::AS_public); + BuiltinTypeDeclBuilder &addCopyAssignmentOperator( + AccessSpecifier Access = AccessSpecifier::AS_public); // Static create methods BuiltinTypeDeclBuilder &addStaticInitializationFunctions(bool HasCounter); @@ -122,23 +125,29 @@ class BuiltinTypeDeclBuilder { BuiltinTypeDeclBuilder &addConsumeMethod(); BuiltinTypeDeclBuilder &addGetDimensionsMethodForBuffer(); + BuiltinTypeDeclBuilder &addMipsMember(ResourceDimension Dim); private: BuiltinTypeDeclBuilder &addCreateFromBinding(); BuiltinTypeDeclBuilder &addCreateFromImplicitBinding(); BuiltinTypeDeclBuilder &addCreateFromBindingWithImplicitCounter(); BuiltinTypeDeclBuilder &addCreateFromImplicitBindingWithImplicitCounter(); - BuiltinTypeDeclBuilder &addResourceMember(StringRef MemberName, - ResourceClass RC, - ResourceDimension RD, bool IsROV, - bool RawBuffer, bool IsCounter, - AccessSpecifier Access); + BuiltinTypeDeclBuilder & + addResourceMember(StringRef MemberName, ResourceClass RC, + ResourceDimension RD, bool IsROV, bool RawBuffer, + bool IsCounter, QualType ElementTy, + AccessSpecifier Access = AccessSpecifier::AS_private); + BuiltinTypeDeclBuilder &addFriend(CXXRecordDecl *Friend); + CXXRecordDecl *addPrivateNestedRecord(StringRef Name); + CXXRecordDecl *addMipsSliceType(ResourceDimension Dim, QualType ReturnType); + CXXRecordDecl *addMipsType(ResourceDimension Dim, QualType ReturnType); BuiltinTypeDeclBuilder & addHandleMember(ResourceClass RC, ResourceDimension RD, bool IsROV, - bool RawBuffer, + bool RawBuffer, QualType ElementTy, AccessSpecifier Access = AccessSpecifier::AS_private); BuiltinTypeDeclBuilder & addCounterHandleMember(ResourceClass RC, bool IsROV, bool RawBuffer, + QualType ElementTy, AccessSpecifier Access = AccessSpecifier::AS_private); QualType getGatherReturnType(); FieldDecl *getResourceHandleField() const; diff --git a/clang/lib/Sema/HLSLExternalSemaSource.cpp b/clang/lib/Sema/HLSLExternalSemaSource.cpp index fb40ccc674349..8f99acb4dd442 100644 --- a/clang/lib/Sema/HLSLExternalSemaSource.cpp +++ b/clang/lib/Sema/HLSLExternalSemaSource.cpp @@ -260,6 +260,7 @@ static BuiltinTypeDeclBuilder setupTextureType(CXXRecordDecl *Decl, Sema &S, .addTextureHandle(RC, IsROV, Dim) .addTextureLoadMethods(Dim) .addArraySubscriptOperators(Dim) + .addMipsMember(Dim) .addDefaultHandleConstructor() .addCopyConstructor() .addCopyAssignmentOperator() diff --git a/clang/test/CodeGenHLSL/resources/Texture2D-Gather.hlsl b/clang/test/CodeGenHLSL/resources/Texture2D-Gather.hlsl index 54d428285d88c..2f4cb1d5b98ed 100644 --- a/clang/test/CodeGenHLSL/resources/Texture2D-Gather.hlsl +++ b/clang/test/CodeGenHLSL/resources/Texture2D-Gather.hlsl @@ -1,11 +1,11 @@ // RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-library -x hlsl -emit-llvm -disable-llvm-passes -finclude-default-header -o - %s | llvm-cxxfilt | FileCheck %s --check-prefixes=CHECK,DXIL // RUN: %clang_cc1 -triple spirv-vulkan-library -x hlsl -emit-llvm -disable-llvm-passes -finclude-default-header -o - %s | llvm-cxxfilt | FileCheck %s --check-prefixes=CHECK,SPIRV -// DXIL: %"class.hlsl::Texture2D" = type { target("dx.Texture", <4 x float>, 0, 0, 0, 2) } +// DXIL: %"class.hlsl::Texture2D" = type { target("dx.Texture", <4 x float>, 0, 0, 0, 2), %"struct.hlsl::Texture2D<>::mips_type" } // DXIL: %"class.hlsl::SamplerState" = type { target("dx.Sampler", 0) } // DXIL: %"class.hlsl::SamplerComparisonState" = type { target("dx.Sampler", 0) } -// SPIRV: %"class.hlsl::Texture2D" = type { target("spirv.Image", float, 1, 2, 0, 0, 1, 0) } +// SPIRV: %"class.hlsl::Texture2D" = type { target("spirv.Image", float, 1, 2, 0, 0, 1, 0), %"struct.hlsl::Texture2D<>::mips_type" } // SPIRV: %"class.hlsl::SamplerState" = type { target("spirv.Sampler") } // SPIRV: %"class.hlsl::SamplerComparisonState" = type { target("spirv.Sampler") } diff --git a/clang/test/CodeGenHLSL/resources/Texture2D-Mips.hlsl b/clang/test/CodeGenHLSL/resources/Texture2D-Mips.hlsl new file mode 100644 index 0000000000000..b84df2b184283 --- /dev/null +++ b/clang/test/CodeGenHLSL/resources/Texture2D-Mips.hlsl @@ -0,0 +1,63 @@ +// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-pixel -x hlsl -emit-llvm -disable-llvm-passes -finclude-default-header -o - %s | llvm-cxxfilt | FileCheck %s --check-prefixes=CHECK,DXIL + +Texture2D<float4> t; + +// CHECK: define internal {{.*}} <4 x float> @test_mips(float vector[2])(<2 x float> {{.*}} %loc) #1 { +// CHECK: entry: +// CHECK: %[[LOC_ADDR:.*]] = alloca <2 x float> +// CHECK: %[[REF_TMP:.*]] = alloca %"struct.hlsl::Texture2D<>::mips_slice_type" +// CHECK: store <2 x float> %loc, ptr %[[LOC_ADDR]] +// CHECK: call void @hlsl::Texture2D<float vector[4]>::mips_type::operator[](int) const(ptr {{.*}} %[[REF_TMP]], ptr {{.*}} getelementptr {{.*}} (i8, ptr @t, i32 4), i32 noundef 0) +// CHECK: %[[V0:.*]] = load <2 x float>, ptr %[[LOC_ADDR]] +// CHECK: %[[CONV:.*]] = fptosi <2 x float> %[[V0]] to <2 x i32> +// CHECK: %[[CALL:.*]] = call {{.*}} <4 x float> @hlsl::Texture2D<float vector[4]>::mips_slice_type::operator[](int vector[2]) const(ptr {{.*}} %[[REF_TMP]], <2 x i32> {{.*}} %[[CONV]]) +// CHECK: ret <4 x float> %[[CALL]] + +[shader("pixel")] +float4 test_mips(float2 loc : LOC) : SV_Target { + return t.mips[0][int2(loc)]; +} + +// CHECK: define linkonce_odr hidden void @hlsl::Texture2D<float vector[4]>::mips_type::operator[](int) const(ptr {{.*}} %agg.result, ptr {{.*}} %this, i32 {{.*}} %Level) +// CHECK: entry: +// CHECK: %{{.*}} = alloca ptr +// CHECK: %[[THIS_ADDR:.*]] = alloca ptr +// CHECK: %[[LEVEL_ADDR:.*]] = alloca i32 +// CHECK: %[[SLICE:.*]] = alloca %"struct.hlsl::Texture2D<>::mips_slice_type" +// CHECK: store ptr %agg.result, ptr %{{.*}} +// CHECK: store ptr %this, ptr %[[THIS_ADDR]] +// CHECK: store i32 %Level, ptr %[[LEVEL_ADDR]] +// CHECK: %[[THIS1:.*]] = load ptr, ptr %[[THIS_ADDR]] +// CHECK: call void @hlsl::Texture2D<float vector[4]>::mips_slice_type::mips_slice_type()(ptr {{.*}} %[[SLICE]]) +// CHECK: %[[HANDLE_GEP:.*]] = getelementptr {{.*}} %"struct.hlsl::Texture2D<>::mips_type", ptr %[[THIS1]], i32 0, i32 0 +// CHECK: %[[HANDLE:.*]] = load target("dx.Texture", <4 x float>, 0, 0, 0, 2), ptr %[[HANDLE_GEP]] +// CHECK: %[[HANDLE_GEP2:.*]] = getelementptr {{.*}} %"struct.hlsl::Texture2D<>::mips_slice_type", ptr %[[SLICE]], i32 0, i32 0 +// CHECK: store target("dx.Texture", <4 x float>, 0, 0, 0, 2) %[[HANDLE]], ptr %[[HANDLE_GEP2]] +// CHECK: %[[L_VAL:.*]] = load i32, ptr %[[LEVEL_ADDR]] +// CHECK: %[[LEVEL_GEP:.*]] = getelementptr {{.*}} %"struct.hlsl::Texture2D<>::mips_slice_type", ptr %[[SLICE]], i32 0, i32 1 +// CHECK: store i32 %[[L_VAL]], ptr %[[LEVEL_GEP]] +// CHECK: call void @hlsl::Texture2D<float vector[4]>::mips_slice_type::mips_slice_type(hlsl::Texture2D<float vector[4]>::mips_slice_type const&)(ptr noundef nonnull align 4 dereferenceable(8) %agg.result, ptr noundef nonnull align 4 dereferenceable(8) %[[SLICE]]) + +// CHECK: define linkonce_odr hidden {{.*}} <4 x float> @hlsl::Texture2D<float vector[4]>::mips_slice_type::operator[](int vector[2]) const(ptr {{.*}} %[[THIS:.*]], <2 x i32> noundef %[[COORD:.*]]) +// CHECK: entry: +// CHECK: %[[COORD_ADDR:.*]] = alloca <2 x i32> +// CHECK: %[[VEC_TMP:.*]] = alloca <2 x i32> +// CHECK: store <2 x i32> %[[COORD]], ptr %[[COORD_ADDR]] +// CHECK: %[[THIS1:.*]] = load ptr, ptr %{{.*}} +// CHECK: %[[COORD_PARAM:.*]] = load <2 x i32>, ptr %[[COORD_ADDR]] +// CHECK: store <2 x i32> %[[COORD_PARAM]], ptr %[[VEC_TMP]] +// CHECK: %[[HANDLE_PTR:.*]] = getelementptr {{.*}} %"struct.hlsl::Texture2D<>::mips_slice_type", ptr %[[THIS1]], i32 0, i32 0 +// CHECK: %[[HANDLE:.*]] = load target("dx.Texture", <4 x float>, 0, 0, 0, 2), ptr %[[HANDLE_PTR]] +// CHECK: %[[COORD_VAL:.*]] = load <2 x i32>, ptr %[[VEC_TMP]] +// CHECK: %[[VECEXT:.*]] = extractelement <2 x i32> %[[COORD_VAL]], i32 0 +// CHECK: %[[VECINIT:.*]] = insertelement <3 x i32> poison, i32 %[[VECEXT]], i32 0 +// CHECK: %[[COORD_VAL2:.*]] = load <2 x i32>, ptr %[[VEC_TMP]] +// CHECK: %[[VECEXT2:.*]] = extractelement <2 x i32> %[[COORD_VAL2]], i32 1 +// CHECK: %[[VECINIT3:.*]] = insertelement <3 x i32> %[[VECINIT]], i32 %[[VECEXT2]], i32 1 +// CHECK: %[[LEVEL_PTR:.*]] = getelementptr {{.*}} %"struct.hlsl::Texture2D<>::mips_slice_type", ptr %[[THIS1]], i32 0, i32 1 +// CHECK: %[[LEVEL_VAL:.*]] = load i32, ptr %[[LEVEL_PTR]] +// CHECK: %[[VECINIT4:.*]] = insertelement <3 x i32> %[[VECINIT3]], i32 %[[LEVEL_VAL]], i32 2 +// CHECK: %[[COORD_X:.*]] = shufflevector <3 x i32> %[[VECINIT4]], <3 x i32> poison, <2 x i32> <i32 0, i32 1> +// CHECK: %[[LOD:.*]] = extractelement <3 x i32> %[[VECINIT4]], i64 2 +// DXIL: %[[RES:.*]] = call {{.*}} <4 x float> @llvm.dx.resource.load.level.v4f32.tdx.Texture_v4f32_0_0_0_2t.v2i32.i32.v2i32(target("dx.Texture", <4 x float>, 0, 0, 0, 2) %[[HANDLE]], <2 x i32> %[[COORD_X]], i32 %[[LOD]], <2 x i32> zeroinitializer) +// CHECK: ret <4 x float> %[[RES]] diff --git a/clang/test/CodeGenHLSL/resources/Texture2D-Sample.hlsl b/clang/test/CodeGenHLSL/resources/Texture2D-Sample.hlsl index 93bed2f2b7c27..e37e182be6b44 100644 --- a/clang/test/CodeGenHLSL/resources/Texture2D-Sample.hlsl +++ b/clang/test/CodeGenHLSL/resources/Texture2D-Sample.hlsl @@ -1,10 +1,10 @@ // RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-library -x hlsl -emit-llvm -disable-llvm-passes -finclude-default-header -o - %s | llvm-cxxfilt | FileCheck %s --check-prefixes=CHECK,DXIL // RUN: %clang_cc1 -triple spirv-vulkan-library -x hlsl -emit-llvm -disable-llvm-passes -finclude-default-header -o - %s | llvm-cxxfilt | FileCheck %s --check-prefixes=CHECK,SPIRV -// DXIL: %"class.hlsl::Texture2D" = type { target("dx.Texture", <4 x float>, 0, 0, 0, 2) } +// DXIL: %"class.hlsl::Texture2D" = type { target("dx.Texture", <4 x float>, 0, 0, 0, 2), %"struct.hlsl::Texture2D<>::mips_type" } // DXIL: %"class.hlsl::SamplerState" = type { target("dx.Sampler", 0) } -// SPIRV: %"class.hlsl::Texture2D" = type { target("spirv.Image", float, 1, 2, 0, 0, 1, 0) } +// SPIRV: %"class.hlsl::Texture2D" = type { target("spirv.Image", float, 1, 2, 0, 0, 1, 0), %"struct.hlsl::Texture2D<>::mips_type" } // SPIRV: %"class.hlsl::SamplerState" = type { target("spirv.Sampler") } Texture2D<float4> t; diff --git a/clang/test/CodeGenHLSL/resources/Texture2D-SampleBias.hlsl b/clang/test/CodeGenHLSL/resources/Texture2D-SampleBias.hlsl index c138e7f0a6c8b..481a66c7a59a9 100644 --- a/clang/test/CodeGenHLSL/resources/Texture2D-SampleBias.hlsl +++ b/clang/test/CodeGenHLSL/resources/Texture2D-SampleBias.hlsl @@ -1,10 +1,10 @@ // RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-library -x hlsl -emit-llvm -disable-llvm-passes -finclude-default-header -o - %s | llvm-cxxfilt | FileCheck %s --check-prefixes=CHECK,DXIL // RUN: %clang_cc1 -triple spirv-vulkan-library -x hlsl -emit-llvm -disable-llvm-passes -finclude-default-header -o - %s | llvm-cxxfilt | FileCheck %s --check-prefixes=CHECK,SPIRV -// DXIL: %"class.hlsl::Texture2D" = type { target("dx.Texture", <4 x float>, 0, 0, 0, 2) } +// DXIL: %"class.hlsl::Texture2D" = type { target("dx.Texture", <4 x float>, 0, 0, 0, 2), %"struct.hlsl::Texture2D<>::mips_type" } // DXIL: %"class.hlsl::SamplerState" = type { target("dx.Sampler", 0) } -// SPIRV: %"class.hlsl::Texture2D" = type { target("spirv.Image", float, 1, 2, 0, 0, 1, 0) } +// SPIRV: %"class.hlsl::Texture2D" = type { target("spirv.Image", float, 1, 2, 0, 0, 1, 0), %"struct.hlsl::Texture2D<>::mips_type" } // SPIRV: %"class.hlsl::SamplerState" = type { target("spirv.Sampler") } Texture2D<float4> t; diff --git a/clang/test/CodeGenHLSL/resources/Texture2D-SampleCmp.hlsl b/clang/test/CodeGenHLSL/resources/Texture2D-SampleCmp.hlsl index b76b02177abbc..5262aed2816ef 100644 --- a/clang/test/CodeGenHLSL/resources/Texture2D-SampleCmp.hlsl +++ b/clang/test/CodeGenHLSL/resources/Texture2D-SampleCmp.hlsl @@ -1,10 +1,10 @@ // RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-library -x hlsl -emit-llvm -disable-llvm-passes -finclude-default-header -o - %s | llvm-cxxfilt | FileCheck %s --check-prefixes=CHECK,DXIL // RUN: %clang_cc1 -triple spirv-vulkan-library -x hlsl -emit-llvm -disable-llvm-passes -finclude-default-header -o - %s | llvm-cxxfilt | FileCheck %s --check-prefixes=CHECK,SPIRV -// DXIL: %"class.hlsl::Texture2D" = type { target("dx.Texture", <4 x float>, 0, 0, 0, 2) } +// DXIL: %"class.hlsl::Texture2D" = type { target("dx.Texture", <4 x float>, 0, 0, 0, 2), %"struct.hlsl::Texture2D<>::mips_type" } // DXIL: %"class.hlsl::SamplerComparisonState" = type { target("dx.Sampler", 0) } -// SPIRV: %"class.hlsl::Texture2D" = type { target("spirv.Image", float, 1, 2, 0, 0, 1, 0) } +// SPIRV: %"class.hlsl::Texture2D" = type { target("spirv.Image", float, 1, 2, 0, 0, 1, 0), %"struct.hlsl::Texture2D<>::mips_type" } // SPIRV: %"class.hlsl::SamplerComparisonState" = type { target("spirv.Sampler") } Texture2D<float4> t; diff --git a/clang/test/CodeGenHLSL/resources/Texture2D-SampleGrad.hlsl b/clang/test/CodeGenHLSL/resources/Texture2D-SampleGrad.hlsl index 279521c0bb988..1a2cd93a34168 100644 --- a/clang/test/CodeGenHLSL/resources/Texture2D-SampleGrad.hlsl +++ b/clang/test/CodeGenHLSL/resources/Texture2D-SampleGrad.hlsl @@ -1,10 +1,10 @@ // RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-library -x hlsl -emit-llvm -disable-llvm-passes -finclude-default-header -o - %s | llvm-cxxfilt | FileCheck %s --check-prefixes=CHECK,DXIL // RUN: %clang_cc1 -triple spirv-vulkan-library -x hlsl -emit-llvm -disable-llvm-passes -finclude-default-header -o - %s | llvm-cxxfilt | FileCheck %s --check-prefixes=CHECK,SPIRV -// DXIL: %"class.hlsl::Texture2D" = type { target("dx.Texture", <4 x float>, 0, 0, 0, 2) } +// DXIL: %"class.hlsl::Texture2D" = type { target("dx.Texture", <4 x float>, 0, 0, 0, 2), %"struct.hlsl::Texture2D<>::mips_type" } // DXIL: %"class.hlsl::SamplerState" = type { target("dx.Sampler", 0) } -// SPIRV: %"class.hlsl::Texture2D" = type { target("spirv.Image", float, 1, 2, 0, 0, 1, 0) } +// SPIRV: %"class.hlsl::Texture2D" = type { target("spirv.Image", float, 1, 2, 0, 0, 1, 0), %"struct.hlsl::Texture2D<>::mips_type" } // SPIRV: %"class.hlsl::SamplerState" = type { target("spirv.Sampler") } Texture2D<float4> t; diff --git a/clang/test/CodeGenHLSL/resources/Texture2D-SampleLevel.hlsl b/clang/test/CodeGenHLSL/resources/Texture2D-SampleLevel.hlsl index bcd025c164ac0..85fae6ea278f2 100644 --- a/clang/test/CodeGenHLSL/resources/Texture2D-SampleLevel.hlsl +++ b/clang/test/CodeGenHLSL/resources/Texture2D-SampleLevel.hlsl @@ -1,10 +1,10 @@ // RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-library -x hlsl -emit-llvm -disable-llvm-passes -finclude-default-header -o - %s | llvm-cxxfilt | FileCheck %s --check-prefixes=CHECK,DXIL // RUN: %clang_cc1 -triple spirv-vulkan-library -x hlsl -emit-llvm -disable-llvm-passes -finclude-default-header -o - %s | llvm-cxxfilt | FileCheck %s --check-prefixes=CHECK,SPIRV -// DXIL: %"class.hlsl::Texture2D" = type { target("dx.Texture", <4 x float>, 0, 0, 0, 2) } +// DXIL: %"class.hlsl::Texture2D" = type { target("dx.Texture", <4 x float>, 0, 0, 0, 2), %"struct.hlsl::Texture2D<>::mips_type" } // DXIL: %"class.hlsl::SamplerState" = type { target("dx.Sampler", 0) } -// SPIRV: %"class.hlsl::Texture2D" = type { target("spirv.Image", float, 1, 2, 0, 0, 1, 0) } +// SPIRV: %"class.hlsl::Texture2D" = type { target("spirv.Image", float, 1, 2, 0, 0, 1, 0), %"struct.hlsl::Texture2D<>::mips_type" } // SPIRV: %"class.hlsl::SamplerState" = type { target("spirv.Sampler") } Texture2D<float4> t; diff --git a/clang/test/CodeGenHLSL/resources/Texture2D-default-explicit-binding.hlsl b/clang/test/CodeGenHLSL/resources/Texture2D-default-explicit-binding.hlsl index 06b4cb7ec9900..9a7819364ee83 100644 --- a/clang/test/CodeGenHLSL/resources/Texture2D-default-explicit-binding.hlsl +++ b/clang/test/CodeGenHLSL/resources/Texture2D-default-explicit-binding.hlsl @@ -5,8 +5,8 @@ SamplerState g_s : register(s0); Texture2D<> default_template : register(t1, space2); Texture2D implicit_template : register(t0, space1); -// CHECK: %"class.hlsl::Texture2D" = type { target("dx.Texture", <4 x float>, 0, 0, 0, 2) } -// SPIRV: %"class.hlsl::Texture2D" = type { target("spirv.Image", float, 1, 2, 0, 0, 1, 0) } +// CHECK: %"class.hlsl::Texture2D" = type { target("dx.Texture", <4 x float>, 0, 0, 0, 2), %"struct.hlsl::Texture2D<>::mips_type" } +// SPIRV: %"class.hlsl::Texture2D" = type { target("spirv.Image", float, 1, 2, 0, 0, 1, 0), %"struct.hlsl::Texture2D<>::mips_type" } // CHECK: @{{.*}}default_template = internal global %"class.hlsl::Texture2D" poison, align {{[0-9]+}} // CHECK: @{{.*}}implicit_template = internal global %"class.hlsl::Texture2D" poison, align {{[0-9]+}} diff --git a/clang/test/CodeGenHLSL/resources/Texture2D-default.hlsl b/clang/test/CodeGenHLSL/resources/Texture2D-default.hlsl index 5b5bb737a7958..8ff981e4fa512 100644 --- a/clang/test/CodeGenHLSL/resources/Texture2D-default.hlsl +++ b/clang/test/CodeGenHLSL/resources/Texture2D-default.hlsl @@ -1,7 +1,7 @@ // RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-library -x hlsl -std=hlsl202x -emit-llvm -disable-llvm-passes -finclude-default-header -o - %s | FileCheck %s -// CHECK: %"class.hlsl::Texture2D" = type { target("dx.Texture", <4 x float>, 0, 0, 0, 2) } -// CHECK: %"class.hlsl::Texture2D.0" = type { target("dx.Texture", float, 0, 0, 0, 2) } +// CHECK: %"class.hlsl::Texture2D" = type { target("dx.Texture", <4 x float>, 0, 0, 0, 2), %"struct.hlsl::Texture2D<>::mips_type" } +// CHECK: %"class.hlsl::Texture2D.0" = type { target("dx.Texture", float, 0, 0, 0, 2), %"struct.hlsl::Texture2D<float>::mips_type" } // CHECK: @{{.*}}t1 = internal global %"class.hlsl::Texture2D" poison, align 4 Texture2D<> t1; diff --git a/clang/test/CodeGenHLSL/resources/Texture2D-shorthand-contexts.hlsl b/clang/test/CodeGenHLSL/resources/Texture2D-shorthand-contexts.hlsl index 71ce46232d088..0367e2360242b 100644 --- a/clang/test/CodeGenHLSL/resources/Texture2D-shorthand-contexts.hlsl +++ b/clang/test/CodeGenHLSL/resources/Texture2D-shorthand-contexts.hlsl @@ -1,6 +1,6 @@ // RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-library -x hlsl -finclude-default-header -emit-llvm -disable-llvm-passes -o - %s | llvm-cxxfilt | FileCheck %s -// CHECK: %"class.hlsl::Texture2D" = type { target("dx.Texture", <4 x float>, 0, 0, 0, 2) } +// CHECK: %"class.hlsl::Texture2D" = type { target("dx.Texture", <4 x float>, 0, 0, 0, 2), %"struct.hlsl::Texture2D<>::mips_type" } SamplerState g_s : register(s0); diff --git a/clang/test/SemaHLSL/Texture2D-mips-errors.hlsl b/clang/test/SemaHLSL/Texture2D-mips-errors.hlsl new file mode 100644 index 0000000000000..0c0fc074cae0b --- /dev/null +++ b/clang/test/SemaHLSL/Texture2D-mips-errors.hlsl @@ -0,0 +1,35 @@ +// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-library -x hlsl -emit-llvm -disable-llvm-passes -finclude-default-header -verify %s + +Texture2D<float4> t; + +template<class T> +float4 foo(T t) { + return t[int2(0, 0)]; +} + +[shader("pixel")] +float4 test_mips() : SV_Target { + // expected-error@+4 {{'mips_type' is a private member of 'hlsl::Texture2D<>'}} + // expected-note@*:* {{implicitly declared private here}} + // expected-error@+2 {{calling a protected constructor of class 'hlsl::Texture2D<>::mips_type'}} + // expected-note@*:* {{implicitly declared protected here}} + Texture2D<float4>::mips_type a; + + // expected-error@+4 {{'mips_slice_type' is a private member of 'hlsl::Texture2D<>'}} + // expected-note@*:* {{implicitly declared private here}} + // expected-error@+2 {{calling a protected constructor of class 'hlsl::Texture2D<>::mips_slice_type'}} + // expected-note@*:* {{implicitly declared protected here}} + Texture2D<float4>::mips_slice_type b; + + // expected-warning@+3 {{'auto' type specifier is a HLSL 202y extension}} + // expected-error@+2 {{calling a protected constructor of class 'hlsl::Texture2D<>::mips_type'}} + // expected-note@*:* {{implicitly declared protected here}} + auto c = t.mips; + + // Note: t.mips[0] correctly returns a mips_slice_type prvalue. + // Passing it to a template function like 'foo(t.mips[0])' currently crashes + // the compiler due to an unrelated bug in HLSL template instantiation. + // See: https://github.com/llvm/llvm-project/issues/188556 + // return t.mips[0][int2(0, 0)] + foo(t.mips[0]); + return t.mips[0][int2(0, 0)]; +} _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
