[clang] [HLSL] cbuffer: Create host layout structs (PR #122820)
Tex Riddell via cfe-commits
cfe-commits at lists.llvm.org
Wed Jan 22 11:30:15 PST 2025
================
@@ -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))
----------------
tex3d wrote:
Won't we want to catch more intangible types than just resources here? How do we make sure this is kept up-to-date for all intangible types?
On a related note, how do we ensure this code under `createHostLayoutStruct` always has matching/consistent logic to the code in `requiresImplicitBufferLayoutStructure`? Could there be a way to share the key logic components perhaps? For instance, there could be functions that return whether a leaf type is intangible (maybe this is just `Type::IsHLSLIntangibleType`), or is zero-sized, separate from the logic that recursively traverses a record type looking for these properties on field types. The `IsHLSLIntangibleType` and zero-sized detection functions are then used by both traversal paths to ensure consistent behavior.
https://github.com/llvm/llvm-project/pull/122820
More information about the cfe-commits
mailing list