https://github.com/hekota updated https://github.com/llvm/llvm-project/pull/125807
>From 42bb34f66f0030f55e1055c4ee0b362511b7f45b Mon Sep 17 00:00:00 2001 From: Helena Kotas <heko...@microsoft.com> Date: Tue, 4 Feb 2025 22:01:49 -0800 Subject: [PATCH 1/5] [HLSL] Implement default constant buffer `$Globals` All variable declarations in the global scope that are not resources, static or empty are implicitly added to implicit constant buffer `$Globals`. Fixes #123801 --- clang/include/clang/AST/Decl.h | 22 +++++++ clang/include/clang/Sema/SemaHLSL.h | 7 ++- clang/lib/AST/Decl.cpp | 41 ++++++++++++- clang/lib/CodeGen/CGHLSLRuntime.cpp | 7 +-- clang/lib/CodeGen/CodeGenModule.cpp | 5 ++ clang/lib/Sema/Sema.cpp | 3 +- clang/lib/Sema/SemaHLSL.cpp | 47 +++++++++++++-- clang/test/AST/HLSL/default_cbuffer.hlsl | 50 ++++++++++++++++ clang/test/CodeGenHLSL/basic_types.hlsl | 64 ++++++++++----------- clang/test/CodeGenHLSL/default_cbuffer.hlsl | 43 ++++++++++++++ 10 files changed, 242 insertions(+), 47 deletions(-) create mode 100644 clang/test/AST/HLSL/default_cbuffer.hlsl create mode 100644 clang/test/CodeGenHLSL/default_cbuffer.hlsl diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h index 05e56978977f2..f86ddaf89bd9c 100644 --- a/clang/include/clang/AST/Decl.h +++ b/clang/include/clang/AST/Decl.h @@ -5038,6 +5038,11 @@ class HLSLBufferDecl final : public NamedDecl, public DeclContext { // LayoutStruct - Layout struct for the buffer CXXRecordDecl *LayoutStruct; + // For default (implicit) constant buffer, a lisf of references of global + // decls that belong to the buffer. The decls are already parented by the + // translation unit context. + SmallVector<Decl *> DefaultBufferDecls; + HLSLBufferDecl(DeclContext *DC, bool CBuffer, SourceLocation KwLoc, IdentifierInfo *ID, SourceLocation IDLoc, SourceLocation LBrace); @@ -5047,6 +5052,8 @@ class HLSLBufferDecl final : public NamedDecl, public DeclContext { bool CBuffer, SourceLocation KwLoc, IdentifierInfo *ID, SourceLocation IDLoc, SourceLocation LBrace); + static HLSLBufferDecl *CreateDefaultCBuffer(ASTContext &C, + DeclContext *LexicalParent); static HLSLBufferDecl *CreateDeserialized(ASTContext &C, GlobalDeclID ID); SourceRange getSourceRange() const override LLVM_READONLY { @@ -5061,6 +5068,7 @@ class HLSLBufferDecl final : public NamedDecl, public DeclContext { bool hasPackoffset() const { return HasPackoffset; } const CXXRecordDecl *getLayoutStruct() const { return LayoutStruct; } void addLayoutStruct(CXXRecordDecl *LS); + void addDefaultBufferDecl(Decl *D); // Implement isa/cast/dyncast/etc. static bool classof(const Decl *D) { return classofKind(D->getKind()); } @@ -5072,6 +5080,20 @@ class HLSLBufferDecl final : public NamedDecl, public DeclContext { return static_cast<HLSLBufferDecl *>(const_cast<DeclContext *>(DC)); } + // Iterator for the buffer decls. Concatenates the list of decls parented + // by this HLSLBufferDecl with the list of default buffer decls. + using buffer_decl_iterator = + llvm::concat_iterator<Decl *const, SmallVector<Decl *>::const_iterator, + decl_iterator>; + using buffer_decl_range = llvm::iterator_range<buffer_decl_iterator>; + + buffer_decl_range buffer_decls() const { + return buffer_decl_range(buffer_decls_begin(), buffer_decls_end()); + } + buffer_decl_iterator buffer_decls_begin() const; + buffer_decl_iterator buffer_decls_end() const; + bool buffer_decls_empty(); + friend class ASTDeclReader; friend class ASTDeclWriter; }; diff --git a/clang/include/clang/Sema/SemaHLSL.h b/clang/include/clang/Sema/SemaHLSL.h index f4cd11f423a84..b1cc856975532 100644 --- a/clang/include/clang/Sema/SemaHLSL.h +++ b/clang/include/clang/Sema/SemaHLSL.h @@ -103,13 +103,13 @@ class SemaHLSL : public SemaBase { HLSLParamModifierAttr::Spelling Spelling); void ActOnTopLevelFunction(FunctionDecl *FD); void ActOnVariableDeclarator(VarDecl *VD); + void ActOnEndOfTranslationUnit(TranslationUnitDecl *TU); void CheckEntryPoint(FunctionDecl *FD); void CheckSemanticAnnotation(FunctionDecl *EntryPoint, const Decl *Param, const HLSLAnnotationAttr *AnnotationAttr); void DiagnoseAttrStageMismatch( const Attr *A, llvm::Triple::EnvironmentType Stage, std::initializer_list<llvm::Triple::EnvironmentType> AllowedStages); - void DiagnoseAvailabilityViolations(TranslationUnitDecl *TU); QualType handleVectorBinOpConversion(ExprResult &LHS, ExprResult &RHS, QualType LHSType, QualType RHSType, @@ -159,11 +159,16 @@ class SemaHLSL : public SemaBase { // List of all resource bindings ResourceBindings Bindings; + // default constant buffer $Globals + HLSLBufferDecl *DefaultCBuffer; + private: void collectResourcesOnVarDecl(VarDecl *D); void collectResourcesOnUserRecordDecl(const VarDecl *VD, const RecordType *RT); void processExplicitBindingsOnDecl(VarDecl *D); + + void diagnoseAvailabilityViolations(TranslationUnitDecl *TU); }; } // namespace clang diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp index 4c5201d0ba2ee..eede936577f09 100644 --- a/clang/lib/AST/Decl.cpp +++ b/clang/lib/AST/Decl.cpp @@ -57,6 +57,7 @@ #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringSwitch.h" +#include "llvm/ADT/iterator_range.h" #include "llvm/Support/Casting.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/raw_ostream.h" @@ -5741,10 +5742,22 @@ HLSLBufferDecl *HLSLBufferDecl::Create(ASTContext &C, return Result; } +HLSLBufferDecl * +HLSLBufferDecl::CreateDefaultCBuffer(ASTContext &C, + DeclContext *LexicalParent) { + DeclContext *DC = LexicalParent; + IdentifierInfo *II = &C.Idents.get("$Globals", tok::TokenKind::identifier); + HLSLBufferDecl *Result = new (C, DC) HLSLBufferDecl( + DC, true, SourceLocation(), II, SourceLocation(), SourceLocation()); + Result->setImplicit(true); + return Result; +} + HLSLBufferDecl *HLSLBufferDecl::CreateDeserialized(ASTContext &C, GlobalDeclID ID) { - return new (C, ID) HLSLBufferDecl(nullptr, false, SourceLocation(), nullptr, - SourceLocation(), SourceLocation()); + return new (C, ID) + HLSLBufferDecl(nullptr, false, SourceLocation(), nullptr, + SourceLocation(), SourceLocation()); } void HLSLBufferDecl::addLayoutStruct(CXXRecordDecl *LS) { @@ -5753,6 +5766,30 @@ void HLSLBufferDecl::addLayoutStruct(CXXRecordDecl *LS) { addDecl(LS); } +void HLSLBufferDecl::addDefaultBufferDecl(Decl *D) { + assert(isImplicit() && + "default decls can only be added to the implicit/default constant " + "buffer $Globals"); + DefaultBufferDecls.push_back(D); +} + +HLSLBufferDecl::buffer_decl_iterator +HLSLBufferDecl::buffer_decls_begin() const { + return buffer_decl_iterator(llvm::iterator_range(DefaultBufferDecls.begin(), + DefaultBufferDecls.end()), + decl_range(decls_begin(), decls_end())); +} + +HLSLBufferDecl::buffer_decl_iterator HLSLBufferDecl::buffer_decls_end() const { + return buffer_decl_iterator( + llvm::iterator_range(DefaultBufferDecls.end(), DefaultBufferDecls.end()), + decl_range(decls_end(), decls_end())); +} + +bool HLSLBufferDecl::buffer_decls_empty() { + return DefaultBufferDecls.empty() && decls_empty(); +} + //===----------------------------------------------------------------------===// // ImportDecl Implementation //===----------------------------------------------------------------------===// diff --git a/clang/lib/CodeGen/CGHLSLRuntime.cpp b/clang/lib/CodeGen/CGHLSLRuntime.cpp index 52247173b6990..a24f5ac878667 100644 --- a/clang/lib/CodeGen/CGHLSLRuntime.cpp +++ b/clang/lib/CodeGen/CGHLSLRuntime.cpp @@ -244,7 +244,7 @@ void CGHLSLRuntime::emitBufferGlobalsAndMetadata(const HLSLBufferDecl *BufDecl, size_t BufferSize = 0; bool UsePackoffset = BufDecl->hasPackoffset(); const auto *ElemIt = LayoutStruct->element_begin(); - for (Decl *D : BufDecl->decls()) { + for (Decl *D : BufDecl->buffer_decls()) { if (isa<CXXRecordDecl, EmptyDecl>(D)) // Nothing to do for this declaration. continue; @@ -286,10 +286,7 @@ void CGHLSLRuntime::emitBufferGlobalsAndMetadata(const HLSLBufferDecl *BufDecl, .str()))) && "layout type does not match the converted element type"); - // there might be resources inside the used defined structs - if (VDTy->isStructureType() && VDTy->isHLSLIntangibleType()) - // FIXME: handle resources in cbuffer structs - llvm_unreachable("resources in cbuffer are not supported yet"); + // FIXME: handle resources in cbuffer user-defined structs // create global variable for the constant and to metadata list GlobalVariable *ElemGV = diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index eb8d3ceeeba4c..65ec9c06b9ee5 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -5503,6 +5503,11 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D, if (getLangOpts().OpenCL && ASTTy->isSamplerT()) return; + // HLSL default buffer constants will be emitted during HLSLBufferDecl codegen + if (getLangOpts().HLSL && + D->getType().getAddressSpace() == LangAS::hlsl_constant) + return; + // If this is OpenMP device, check if it is legal to emit this global // normally. if (LangOpts.OpenMPIsTargetDevice && OpenMPRuntime && diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp index abb46d3a84e74..d3c350b58da1a 100644 --- a/clang/lib/Sema/Sema.cpp +++ b/clang/lib/Sema/Sema.cpp @@ -1416,8 +1416,7 @@ void Sema::ActOnEndOfTranslationUnit() { } if (LangOpts.HLSL) - HLSL().DiagnoseAvailabilityViolations( - getASTContext().getTranslationUnitDecl()); + HLSL().ActOnEndOfTranslationUnit(getASTContext().getTranslationUnitDecl()); // If there were errors, disable 'unused' warnings since they will mostly be // noise. Don't warn for a use from a module: either we should warn on all diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp index 1537a88731892..977185fcf9997 100644 --- a/clang/lib/Sema/SemaHLSL.cpp +++ b/clang/lib/Sema/SemaHLSL.cpp @@ -9,6 +9,7 @@ //===----------------------------------------------------------------------===// #include "clang/Sema/SemaHLSL.h" +#include "clang/AST/ASTConsumer.h" #include "clang/AST/ASTContext.h" #include "clang/AST/Attr.h" #include "clang/AST/Attrs.inc" @@ -147,7 +148,7 @@ bool ResourceBindings::hasBindingInfoForDecl(const VarDecl *VD) const { return DeclToBindingListIndex.contains(VD); } -SemaHLSL::SemaHLSL(Sema &S) : SemaBase(S) {} +SemaHLSL::SemaHLSL(Sema &S) : SemaBase(S), DefaultCBuffer(nullptr) {} Decl *SemaHLSL::ActOnStartBuffer(Scope *BufferScope, bool CBuffer, SourceLocation KwLoc, IdentifierInfo *Ident, @@ -219,7 +220,7 @@ static void validatePackoffset(Sema &S, HLSLBufferDecl *BufDecl) { // or on none. bool HasPackOffset = false; bool HasNonPackOffset = false; - for (auto *Field : BufDecl->decls()) { + for (auto *Field : BufDecl->buffer_decls()) { VarDecl *Var = dyn_cast<VarDecl>(Field); if (!Var) continue; @@ -486,7 +487,7 @@ void createHostLayoutStructForBuffer(Sema &S, HLSLBufferDecl *BufDecl) { LS->setImplicit(true); LS->startDefinition(); - for (Decl *D : BufDecl->decls()) { + for (Decl *D : BufDecl->buffer_decls()) { VarDecl *VD = dyn_cast<VarDecl>(D); if (!VD || VD->getStorageClass() == SC_Static || VD->getType().getAddressSpace() == LangAS::hlsl_groupshared) @@ -1922,7 +1923,21 @@ void DiagnoseHLSLAvailability::CheckDeclAvailability(NamedDecl *D, } // namespace -void SemaHLSL::DiagnoseAvailabilityViolations(TranslationUnitDecl *TU) { +void SemaHLSL::ActOnEndOfTranslationUnit(TranslationUnitDecl *TU) { + + // process default CBuffer - create buffer layout struct and invoke codegenCGH + if (DefaultCBuffer) { + SemaRef.getCurLexicalContext()->addDecl(DefaultCBuffer); + createHostLayoutStructForBuffer(SemaRef, DefaultCBuffer); + + DeclGroupRef DG(DefaultCBuffer); + SemaRef.Consumer.HandleTopLevelDecl(DG); + } + + diagnoseAvailabilityViolations(TU); +} + +void SemaHLSL::diagnoseAvailabilityViolations(TranslationUnitDecl *TU) { // Skip running the diagnostics scan if the diagnostic mode is // strict (-fhlsl-strict-availability) and the target shader stage is known // because all relevant diagnostics were already emitted in the @@ -2784,6 +2799,14 @@ QualType SemaHLSL::getInoutParameterType(QualType Ty) { return Ty; } +static bool IsDefaultBufferConstantDecl(VarDecl *VD) { + QualType QT = VD->getType(); + return VD->getDeclContext()->isTranslationUnit() && + QT.getAddressSpace() == LangAS::Default && + VD->getStorageClass() != SC_Static && + !isInvalidConstantBufferLeafElementType(QT.getTypePtr()); +} + void SemaHLSL::ActOnVariableDeclarator(VarDecl *VD) { if (VD->hasGlobalStorage()) { // make sure the declaration has a complete type @@ -2795,7 +2818,21 @@ void SemaHLSL::ActOnVariableDeclarator(VarDecl *VD) { return; } - // find all resources on decl + // Global variables outside a cbuffer block that are not a resource, static, + // groupshared, or an empty array or struct belong to the default constant + // buffer $Globals + if (IsDefaultBufferConstantDecl(VD)) { + if (DefaultCBuffer == nullptr) + DefaultCBuffer = HLSLBufferDecl::CreateDefaultCBuffer( + SemaRef.getASTContext(), SemaRef.getCurLexicalContext()); + // update address space to hlsl_constant + QualType NewTy = getASTContext().getAddrSpaceQualType( + VD->getType(), LangAS::hlsl_constant); + VD->setType(NewTy); + DefaultCBuffer->addDefaultBufferDecl(VD); + } + + // find all resources bindings on decl if (VD->getType()->isHLSLIntangibleType()) collectResourcesOnVarDecl(VD); diff --git a/clang/test/AST/HLSL/default_cbuffer.hlsl b/clang/test/AST/HLSL/default_cbuffer.hlsl new file mode 100644 index 0000000000000..9e0fce7cc53cf --- /dev/null +++ b/clang/test/AST/HLSL/default_cbuffer.hlsl @@ -0,0 +1,50 @@ +// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -ast-dump -o - %s | FileCheck %s + +struct EmptyStruct { +}; + +struct S { + RWBuffer<float> buf; + EmptyStruct es; + float ea[0]; + float b; +}; + +// CHECK: VarDecl {{.*}} used a 'hlsl_constant float' +float a; + +// CHECK: VarDecl {{.*}} b 'RWBuffer<float>':'hlsl::RWBuffer<float>' +RWBuffer<float> b; + +// CHECK: VarDecl {{.*}} c 'EmptyStruct' +EmptyStruct c; + +// CHECK: VarDecl {{.*}} d 'float[0]' +float d[0]; + +// CHECK: VarDecl {{.*}} e 'RWBuffer<float>[2]' +RWBuffer<float> e[2]; + +// CHECK: VarDecl {{.*}} f 'groupshared float' +groupshared float f; + +// CHECK: VarDecl {{.*}} g 'hlsl_constant float' +float g; + +// CHECK: VarDecl {{.*}} h 'hlsl_constant S' +S h; + +// CHECK: HLSLBufferDecl {{.*}} implicit cbuffer $Globals +// CHECK: CXXRecordDecl {{.*}} implicit struct __cblayout_$Globals definition +// CHECK: PackedAttr +// CHECK-NEXT: FieldDecl {{.*}} a 'float' +// CHECK-NEXT: FieldDecl {{.*}} g 'float' +// CHECK-NEXT: FieldDecl {{.*}} h '__cblayout_S' + +// CHECK: CXXRecordDecl {{.*}} implicit struct __cblayout_S definition +// CHECK: PackedAttr {{.*}} Implicit +// CHECK-NEXT: FieldDecl {{.*}} b 'float' + +export float foo() { + return a; +} diff --git a/clang/test/CodeGenHLSL/basic_types.hlsl b/clang/test/CodeGenHLSL/basic_types.hlsl index d987af45a649f..362042654ea8c 100644 --- a/clang/test/CodeGenHLSL/basic_types.hlsl +++ b/clang/test/CodeGenHLSL/basic_types.hlsl @@ -6,38 +6,38 @@ // RUN: -emit-llvm -disable-llvm-passes -o - -DNAMESPACED| FileCheck %s -// CHECK: @uint16_t_Val = global i16 0, align 2 -// CHECK: @int16_t_Val = global i16 0, align 2 -// CHECK: @uint_Val = global i32 0, align 4 -// CHECK: @uint64_t_Val = global i64 0, align 8 -// CHECK: @int64_t_Val = global i64 0, align 8 -// CHECK: @int16_t2_Val = global <2 x i16> zeroinitializer, align 4 -// CHECK: @int16_t3_Val = global <3 x i16> zeroinitializer, align 8 -// CHECK: @int16_t4_Val = global <4 x i16> zeroinitializer, align 8 -// CHECK: @uint16_t2_Val = global <2 x i16> zeroinitializer, align 4 -// CHECK: @uint16_t3_Val = global <3 x i16> zeroinitializer, align 8 -// CHECK: @uint16_t4_Val = global <4 x i16> zeroinitializer, align 8 -// CHECK: @int2_Val = global <2 x i32> zeroinitializer, align 8 -// CHECK: @int3_Val = global <3 x i32> zeroinitializer, align 16 -// CHECK: @int4_Val = global <4 x i32> zeroinitializer, align 16 -// CHECK: @uint2_Val = global <2 x i32> zeroinitializer, align 8 -// CHECK: @uint3_Val = global <3 x i32> zeroinitializer, align 16 -// CHECK: @uint4_Val = global <4 x i32> zeroinitializer, align 16 -// CHECK: @int64_t2_Val = global <2 x i64> zeroinitializer, align 16 -// CHECK: @int64_t3_Val = global <3 x i64> zeroinitializer, align 32 -// CHECK: @int64_t4_Val = global <4 x i64> zeroinitializer, align 32 -// CHECK: @uint64_t2_Val = global <2 x i64> zeroinitializer, align 16 -// CHECK: @uint64_t3_Val = global <3 x i64> zeroinitializer, align 32 -// CHECK: @uint64_t4_Val = global <4 x i64> zeroinitializer, align 32 -// CHECK: @half2_Val = global <2 x half> zeroinitializer, align 4 -// CHECK: @half3_Val = global <3 x half> zeroinitializer, align 8 -// CHECK: @half4_Val = global <4 x half> zeroinitializer, align 8 -// CHECK: @float2_Val = global <2 x float> zeroinitializer, align 8 -// CHECK: @float3_Val = global <3 x float> zeroinitializer, align 16 -// CHECK: @float4_Val = global <4 x float> zeroinitializer, align 16 -// CHECK: @double2_Val = global <2 x double> zeroinitializer, align 16 -// CHECK: @double3_Val = global <3 x double> zeroinitializer, align 32 -// CHECK: @double4_Val = global <4 x double> zeroinitializer, align 32 +// CHECK: @uint16_t_Val = external addrspace(2) global i16, align 2 +// CHECK: @int16_t_Val = external addrspace(2) global i16, align 2 +// CHECK: @uint_Val = external addrspace(2) global i32, align 4 +// CHECK: @uint64_t_Val = external addrspace(2) global i64, align 8 +// CHECK: @int64_t_Val = external addrspace(2) global i64, align 8 +// CHECK: @int16_t2_Val = external addrspace(2) global <2 x i16>, align 4 +// CHECK: @int16_t3_Val = external addrspace(2) global <3 x i16>, align 8 +// CHECK: @int16_t4_Val = external addrspace(2) global <4 x i16>, align 8 +// CHECK: @uint16_t2_Val = external addrspace(2) global <2 x i16>, align 4 +// CHECK: @uint16_t3_Val = external addrspace(2) global <3 x i16>, align 8 +// CHECK: @uint16_t4_Val = external addrspace(2) global <4 x i16>, align 8 +// CHECK: @int2_Val = external addrspace(2) global <2 x i32>, align 8 +// CHECK: @int3_Val = external addrspace(2) global <3 x i32>, align 16 +// CHECK: @int4_Val = external addrspace(2) global <4 x i32>, align 16 +// CHECK: @uint2_Val = external addrspace(2) global <2 x i32>, align 8 +// CHECK: @uint3_Val = external addrspace(2) global <3 x i32>, align 16 +// CHECK: @uint4_Val = external addrspace(2) global <4 x i32>, align 16 +// CHECK: @int64_t2_Val = external addrspace(2) global <2 x i64>, align 16 +// CHECK: @int64_t3_Val = external addrspace(2) global <3 x i64>, align 32 +// CHECK: @int64_t4_Val = external addrspace(2) global <4 x i64>, align 32 +// CHECK: @uint64_t2_Val = external addrspace(2) global <2 x i64>, align 16 +// CHECK: @uint64_t3_Val = external addrspace(2) global <3 x i64>, align 32 +// CHECK: @uint64_t4_Val = external addrspace(2) global <4 x i64>, align 32 +// CHECK: @half2_Val = external addrspace(2) global <2 x half>, align 4 +// CHECK: @half3_Val = external addrspace(2) global <3 x half>, align 8 +// CHECK: @half4_Val = external addrspace(2) global <4 x half>, align 8 +// CHECK: @float2_Val = external addrspace(2) global <2 x float>, align 8 +// CHECK: @float3_Val = external addrspace(2) global <3 x float>, align 16 +// CHECK: @float4_Val = external addrspace(2) global <4 x float>, align 16 +// CHECK: @double2_Val = external addrspace(2) global <2 x double>, align 16 +// CHECK: @double3_Val = external addrspace(2) global <3 x double>, align 32 +// CHECK: @double4_Val = external addrspace(2) global <4 x double>, align 32 #ifdef NAMESPACED #define TYPE_DECL(T) hlsl::T T##_Val diff --git a/clang/test/CodeGenHLSL/default_cbuffer.hlsl b/clang/test/CodeGenHLSL/default_cbuffer.hlsl new file mode 100644 index 0000000000000..7368997b51ac9 --- /dev/null +++ b/clang/test/CodeGenHLSL/default_cbuffer.hlsl @@ -0,0 +1,43 @@ +// RUN: %clang_cc1 -finclude-default-header -triple dxil-pc-shadermodel6.3-compute \ +// RUN: -fnative-half-type -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s + +// CHECK: %"struct.__cblayout_$Globals" = type { float, float, %struct.__cblayout_S } +// CHECK: %struct.__cblayout_S = type { float } + +// CHECK-DAG: @"$Globals.cb" = external constant target("dx.CBuffer", %"struct.__cblayout_$Globals") +// CHECK-DAG: @a = external addrspace(2) global float +// CHECK-DAG: @g = external addrspace(2) global float +// CHECK-DAG: @h = external addrspace(2) global %struct.__cblayout_S + +struct EmptyStruct { +}; + +struct S { + RWBuffer<float> buf; + EmptyStruct es; + float ea[0]; + float b; +}; + +float a; +RWBuffer<float> b; +EmptyStruct c; +float d[0]; +RWBuffer<float> e[2]; +groupshared float f; +float g; +S h; + +RWBuffer<float> Buf; + +[numthreads(4,1,1)] +void main() { + Buf[0] = a; +} + +// CHECK: !hlsl.cblayouts = !{![[S_LAYOUT:.*]], ![[CB_LAYOUT:.*]]} +// CHECK: !hlsl.cbs = !{![[CB:.*]]} + +// CHECK: ![[S_LAYOUT]] = !{!"struct.__cblayout_S", i32 4, i32 0} +// CHECK: ![[CB_LAYOUT]] = !{!"struct.__cblayout_$Globals", i32 20, i32 0, i32 4, i32 16} +// CHECK: ![[CB]] = !{ptr @"$Globals.cb", ptr addrspace(2) @a, ptr addrspace(2) @g, ptr addrspace(2) @h} \ No newline at end of file >From 648548220abd23fe716fdc9a6b87257f82234ff5 Mon Sep 17 00:00:00 2001 From: Helena Kotas <heko...@microsoft.com> Date: Tue, 4 Feb 2025 22:21:11 -0800 Subject: [PATCH 2/5] clang-format --- clang/lib/AST/Decl.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp index eede936577f09..4eb648ce95f25 100644 --- a/clang/lib/AST/Decl.cpp +++ b/clang/lib/AST/Decl.cpp @@ -5755,9 +5755,8 @@ HLSLBufferDecl::CreateDefaultCBuffer(ASTContext &C, HLSLBufferDecl *HLSLBufferDecl::CreateDeserialized(ASTContext &C, GlobalDeclID ID) { - return new (C, ID) - HLSLBufferDecl(nullptr, false, SourceLocation(), nullptr, - SourceLocation(), SourceLocation()); + return new (C, ID) HLSLBufferDecl(nullptr, false, SourceLocation(), nullptr, + SourceLocation(), SourceLocation()); } void HLSLBufferDecl::addLayoutStruct(CXXRecordDecl *LS) { >From 991ba1d81364fe21da9678d0db94c551abfe853a Mon Sep 17 00:00:00 2001 From: Helena Kotas <heko...@microsoft.com> Date: Wed, 5 Feb 2025 10:21:04 -0800 Subject: [PATCH 3/5] whitespace change so I can force-push the branch to unblock stuck PR --- clang/lib/Sema/SemaHLSL.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp index 977185fcf9997..72485322fc288 100644 --- a/clang/lib/Sema/SemaHLSL.cpp +++ b/clang/lib/Sema/SemaHLSL.cpp @@ -1924,7 +1924,6 @@ void DiagnoseHLSLAvailability::CheckDeclAvailability(NamedDecl *D, } // namespace void SemaHLSL::ActOnEndOfTranslationUnit(TranslationUnitDecl *TU) { - // process default CBuffer - create buffer layout struct and invoke codegenCGH if (DefaultCBuffer) { SemaRef.getCurLexicalContext()->addDecl(DefaultCBuffer); @@ -1933,7 +1932,6 @@ void SemaHLSL::ActOnEndOfTranslationUnit(TranslationUnitDecl *TU) { DeclGroupRef DG(DefaultCBuffer); SemaRef.Consumer.HandleTopLevelDecl(DG); } - diagnoseAvailabilityViolations(TU); } >From 43aedd4ac16a5cd9782ebc63f7e56bc739f81df8 Mon Sep 17 00:00:00 2001 From: Helena Kotas <heko...@microsoft.com> Date: Fri, 14 Feb 2025 19:12:40 -0800 Subject: [PATCH 4/5] fix test after merge --- clang/test/CodeGenHLSL/default_cbuffer.hlsl | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/clang/test/CodeGenHLSL/default_cbuffer.hlsl b/clang/test/CodeGenHLSL/default_cbuffer.hlsl index 7368997b51ac9..8f89606fdd04f 100644 --- a/clang/test/CodeGenHLSL/default_cbuffer.hlsl +++ b/clang/test/CodeGenHLSL/default_cbuffer.hlsl @@ -1,13 +1,13 @@ // RUN: %clang_cc1 -finclude-default-header -triple dxil-pc-shadermodel6.3-compute \ // RUN: -fnative-half-type -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s -// CHECK: %"struct.__cblayout_$Globals" = type { float, float, %struct.__cblayout_S } -// CHECK: %struct.__cblayout_S = type { float } +// CHECK: %"__cblayout_$Globals" = type <{ float, float, target("dx.Layout", %__cblayout_S, 4, 0) }> +// CHECK: %__cblayout_S = type <{ float }> -// CHECK-DAG: @"$Globals.cb" = external constant target("dx.CBuffer", %"struct.__cblayout_$Globals") +// CHECK-DAG: @"$Globals.cb" = external constant target("dx.CBuffer", target("dx.Layout", %"__cblayout_$Globals", 20, 0, 4, 16)) // CHECK-DAG: @a = external addrspace(2) global float // CHECK-DAG: @g = external addrspace(2) global float -// CHECK-DAG: @h = external addrspace(2) global %struct.__cblayout_S +// CHECK-DAG: @h = external addrspace(2) global target("dx.Layout", %__cblayout_S, 4, 0), align 4 struct EmptyStruct { }; @@ -35,9 +35,5 @@ void main() { Buf[0] = a; } -// CHECK: !hlsl.cblayouts = !{![[S_LAYOUT:.*]], ![[CB_LAYOUT:.*]]} // CHECK: !hlsl.cbs = !{![[CB:.*]]} - -// CHECK: ![[S_LAYOUT]] = !{!"struct.__cblayout_S", i32 4, i32 0} -// CHECK: ![[CB_LAYOUT]] = !{!"struct.__cblayout_$Globals", i32 20, i32 0, i32 4, i32 16} // CHECK: ![[CB]] = !{ptr @"$Globals.cb", ptr addrspace(2) @a, ptr addrspace(2) @g, ptr addrspace(2) @h} \ No newline at end of file >From a90b3a1166eb58395a3dd799d6ee078709bc5c69 Mon Sep 17 00:00:00 2001 From: Helena Kotas <heko...@microsoft.com> Date: Tue, 18 Feb 2025 12:45:48 -0800 Subject: [PATCH 5/5] code review feedback - update comment, add new line --- clang/include/clang/AST/Decl.h | 12 ++++++++++-- clang/lib/CodeGen/CGHLSLRuntime.cpp | 1 + clang/test/CodeGenHLSL/default_cbuffer.hlsl | 2 +- 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h index 0dd4ca8cfd38b..86e6d1417ae79 100644 --- a/clang/include/clang/AST/Decl.h +++ b/clang/include/clang/AST/Decl.h @@ -5087,8 +5087,16 @@ class HLSLBufferDecl final : public NamedDecl, public DeclContext { return static_cast<HLSLBufferDecl *>(const_cast<DeclContext *>(DC)); } - // Iterator for the buffer decls. Concatenates the list of decls parented - // by this HLSLBufferDecl with the list of default buffer decls. + // Iterator for the buffer decls. For constant buffers explicitly declared + // with `cbuffer` keyword this will the list of decls parented by this + // HLSLBufferDecl (equal to `decls()`). + // For implicit $Globals buffer this will be the list of default buffer + // declarations stored in DefaultBufferDecls plus the implicit layout + // struct (the only child of HLSLBufferDecl in this case). + // + // The iterator uses llvm::concat_iterator to concatenate the lists + // `decls()` and `DefaultBufferDecls`. For non-default buffers + // `DefaultBufferDecls` is always empty. using buffer_decl_iterator = llvm::concat_iterator<Decl *const, SmallVector<Decl *>::const_iterator, decl_iterator>; diff --git a/clang/lib/CodeGen/CGHLSLRuntime.cpp b/clang/lib/CodeGen/CGHLSLRuntime.cpp index 80ef24d54f128..32cdcbb705ee6 100644 --- a/clang/lib/CodeGen/CGHLSLRuntime.cpp +++ b/clang/lib/CodeGen/CGHLSLRuntime.cpp @@ -150,6 +150,7 @@ void CGHLSLRuntime::emitBufferGlobalsAndMetadata(const HLSLBufferDecl *BufDecl, llvm::Type *LayoutType = *ElemIt++; // FIXME: handle resources in cbuffer user-defined structs + // Issue llvm/wg-hlsl#175 // create global variable for the constant and to metadata list GlobalVariable *ElemGV = diff --git a/clang/test/CodeGenHLSL/default_cbuffer.hlsl b/clang/test/CodeGenHLSL/default_cbuffer.hlsl index 8f89606fdd04f..c5176aa8466e4 100644 --- a/clang/test/CodeGenHLSL/default_cbuffer.hlsl +++ b/clang/test/CodeGenHLSL/default_cbuffer.hlsl @@ -36,4 +36,4 @@ void main() { } // CHECK: !hlsl.cbs = !{![[CB:.*]]} -// CHECK: ![[CB]] = !{ptr @"$Globals.cb", ptr addrspace(2) @a, ptr addrspace(2) @g, ptr addrspace(2) @h} \ No newline at end of file +// CHECK: ![[CB]] = !{ptr @"$Globals.cb", ptr addrspace(2) @a, ptr addrspace(2) @g, ptr addrspace(2) @h} _______________________________________________ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits