================ @@ -253,12 +257,229 @@ static void validatePackoffset(Sema &S, HLSLBufferDecl *BufDecl) { } } +// Returns true if the array has a zero size = if any of the dimensions is 0 +static bool isZeroSizedArray(const ConstantArrayType *CAT) { + while (CAT && !CAT->isZeroSize()) + CAT = dyn_cast<ConstantArrayType>( + CAT->getElementType()->getUnqualifiedDesugaredType()); + return CAT != nullptr; +} + +// Returns true if the struct contains at least one element that prevents it +// from being included inside HLSL Buffer as is, such as an intangible type, +// empty struct, or zero-sized array. If it does, a new implicit layout struct +// needs to be created for HLSL Buffer use that will exclude these unwanted +// declarations (see createHostLayoutStruct function). +static bool requiresImplicitBufferLayoutStructure(const CXXRecordDecl *RD) { + if (RD->getTypeForDecl()->isHLSLIntangibleType() || RD->isEmpty()) + return true; + // check fields + for (const FieldDecl *Field : RD->fields()) { + QualType Ty = Field->getType(); + if (Ty->isRecordType()) { + if (requiresImplicitBufferLayoutStructure(Ty->getAsCXXRecordDecl())) + return true; + } else if (Ty->isConstantArrayType()) { + if (isZeroSizedArray(cast<ConstantArrayType>(Ty))) + return true; + } + } + // check bases + for (const CXXBaseSpecifier &Base : RD->bases()) + if (requiresImplicitBufferLayoutStructure( + Base.getType()->getAsCXXRecordDecl())) + return true; + return false; +} + +static CXXRecordDecl *findRecordDecl(Sema &S, IdentifierInfo *II, + DeclContext *DC) { + DeclarationNameInfo NameInfo = + DeclarationNameInfo(DeclarationName(II), SourceLocation()); + LookupResult R(S, NameInfo, Sema::LookupOrdinaryName); + S.LookupName(R, S.getScopeForContext(DC)); + if (R.isSingleResult()) + return R.getAsSingle<CXXRecordDecl>(); + return nullptr; +} + +// Creates a name for buffer layout struct using the provide name base. +// If the name must be unique (not previously defined), a suffix is added +// until a unique name is found. +static IdentifierInfo *getHostLayoutStructName(Sema &S, + IdentifierInfo *NameBaseII, + bool MustBeUnique, + DeclContext *DC) { + ASTContext &AST = S.getASTContext(); + std::string NameBase; + if (NameBaseII) { + NameBase = NameBaseII->getName().str(); + } else { + // anonymous struct + NameBase = "anon"; + MustBeUnique = true; + } + + std::string Name = "__layout_" + NameBase; + IdentifierInfo *II = &AST.Idents.get(Name, tok::TokenKind::identifier); + if (!MustBeUnique) + return II; + + unsigned suffix = 0; + while (true) { + if (suffix != 0) + II = &AST.Idents.get((llvm::Twine(Name) + "_" + Twine(suffix)).str(), + tok::TokenKind::identifier); + if (!findRecordDecl(S, II, DC)) + return II; + // declaration with that name already exists - increment suffix and try + // again until unique name is found + suffix++; + }; +} + +// Returns true if the record type is an HLSL resource class +static bool isResourceRecordType(const Type *Ty) { + return HLSLAttributedResourceType::findHandleTypeOnResource(Ty) != nullptr; +} + +static CXXRecordDecl *createHostLayoutStruct(Sema &S, CXXRecordDecl *StructDecl, + HLSLBufferDecl *BufDecl); + +// Creates a field declaration of given name and type for HLSL buffer layout +// struct. Returns nullptr if the type cannot be use in HLSL Buffer layout. +static FieldDecl *createFieldForHostLayoutStruct(Sema &S, const Type *Ty, + IdentifierInfo *II, + CXXRecordDecl *LayoutStruct, + HLSLBufferDecl *BufDecl) { + if (Ty->isRecordType()) { + if (isResourceRecordType(Ty)) + return nullptr; + CXXRecordDecl *RD = Ty->getAsCXXRecordDecl(); + if (requiresImplicitBufferLayoutStructure(RD)) { + RD = createHostLayoutStruct(S, RD, BufDecl); + if (!RD) + return nullptr; + Ty = RD->getTypeForDecl(); + } + } else if (Ty->isConstantArrayType()) { + if (isZeroSizedArray(cast<ConstantArrayType>(Ty))) + return nullptr; + } + QualType QT = QualType(Ty, 0); + ASTContext &AST = S.getASTContext(); + TypeSourceInfo *TSI = AST.getTrivialTypeSourceInfo(QT, SourceLocation()); + auto *Field = FieldDecl::Create(AST, LayoutStruct, SourceLocation(), + SourceLocation(), II, QT, TSI, nullptr, false, + InClassInitStyle::ICIS_NoInit); + Field->setAccess(AccessSpecifier::AS_private); + return Field; +} + +// Creates host layout struct for a struct included in HLSL Buffer. +// The layout struct will include only fields that are allowed in HLSL buffer. +// These fields will be filtered out: +// - resource classes +// - empty structs +// - zero-sized arrays +// Returns nullptr if the resulting layout struct would be empty. +static CXXRecordDecl *createHostLayoutStruct(Sema &S, CXXRecordDecl *StructDecl, + HLSLBufferDecl *BufDecl) { + assert(requiresImplicitBufferLayoutStructure(StructDecl) && + "struct is already HLSL buffer compatible"); + + ASTContext &AST = S.getASTContext(); + DeclContext *DC = StructDecl->getDeclContext(); + IdentifierInfo *II = getHostLayoutStructName( + S, StructDecl->getIdentifier(), false, BufDecl->getDeclContext()); + + // reuse existing if the layout struct if it already exists + if (CXXRecordDecl *RD = findRecordDecl(S, II, DC)) + return RD; + + CXXRecordDecl *LS = + CXXRecordDecl::Create(AST, TagDecl::TagKind::Class, BufDecl, + SourceLocation(), SourceLocation(), II); + LS->setImplicit(true); + LS->startDefinition(); + + // copy base struct, create HLSL Buffer compatible version if needed + if (unsigned NumBases = StructDecl->getNumBases()) { + assert(NumBases == 1 && "HLSL supports only one base type"); ---------------- tex3d wrote:
> The interface support in DXC is HLSL 2015-only Not entirely true. We don't support use of interface instances (basically like pointers), but we do support interface definitions, inheritance from such, and overriding method implementations. There is a bug in DXC when calling a method originally defined in an interface that is not inherited first in a multiple-inheritance scenario due to the way the MicrosoftCXXABI generates the code to access `this` for a method which we inherited by defaulting to that ABI in DXC. https://github.com/llvm/llvm-project/pull/122820 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits