https://github.com/s-perron updated https://github.com/llvm/llvm-project/pull/129100
>From 1e794cd4b79235282795891f943f8f4609738d4f Mon Sep 17 00:00:00 2001 From: Steven Perron <stevenper...@google.com> Date: Tue, 4 Feb 2025 11:47:42 -0500 Subject: [PATCH 1/6] [HLSL] Fix resrouce wrapper declaration The resource wrapper should have internal linkage because it contains a handle to the global resource, and it not the actual global. Makeing this changed exposed that we were zeroinitializing the resouce, which is a problem. The handle cannot be zeroinitialized. This is changed to use poison instead. Fixes https://github.com/llvm/llvm-project/issues/122767. --- clang/include/clang/AST/Type.h | 1 + clang/lib/AST/Type.cpp | 27 ++++++++++ clang/lib/CodeGen/CGHLSLRuntime.cpp | 5 ++ clang/lib/CodeGen/CGHLSLRuntime.h | 2 + clang/lib/CodeGen/CodeGenModule.cpp | 6 ++- clang/lib/Sema/SemaHLSL.cpp | 7 +++ .../ByteAddressBuffers-constructors.hlsl | 24 ++++----- .../builtins/RWBuffer-constructor-opt.hlsl | 14 ++---- .../builtins/RWBuffer-constructor.hlsl | 10 ++-- .../StructuredBuffers-constructors.hlsl | 50 +++++++++---------- clang/test/CodeGenHLSL/resource-bindings.hlsl | 32 ++++++------ 11 files changed, 108 insertions(+), 70 deletions(-) diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h index 79cf237431450..5bfc78da7fa13 100644 --- a/clang/include/clang/AST/Type.h +++ b/clang/include/clang/AST/Type.h @@ -2661,6 +2661,7 @@ class alignas(TypeAlignment) Type : public ExtQualsTypeCommonBase { bool isHLSLSpecificType() const; // Any HLSL specific type bool isHLSLBuiltinIntangibleType() const; // Any HLSL builtin intangible type bool isHLSLAttributedResourceType() const; + bool isHLSLResourceWrapper() const; bool isHLSLIntangibleType() const; // Any HLSL intangible type (builtin, array, class) diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp index 1ddc2d1f492af..992ce8b4b4795 100644 --- a/clang/lib/AST/Type.cpp +++ b/clang/lib/AST/Type.cpp @@ -5114,6 +5114,33 @@ bool Type::hasSizedVLAType() const { return false; } +bool Type::isHLSLResourceWrapper() const { + const Type *Ty = getUnqualifiedDesugaredType(); + + // check if it's a builtin type first + if (Ty->isBuiltinType()) + return Ty->isHLSLBuiltinIntangibleType(); + + // unwrap arrays + while (isa<ConstantArrayType>(Ty)) + Ty = Ty->getArrayElementTypeNoTypeQual(); + + const RecordType *RT = + dyn_cast<RecordType>(Ty->getUnqualifiedDesugaredType()); + if (!RT) + return false; + + CXXRecordDecl *RD = RT->getAsCXXRecordDecl(); + assert(RD != nullptr && + "all HLSL structs and classes should be CXXRecordDecl"); + assert(RD->isCompleteDefinition() && "expecting complete type"); + if (RD->field_empty()) { + return false; + } + const FieldDecl *FirstField = *RD->field_begin(); + return FirstField->getType()->isHLSLAttributedResourceType(); +} + bool Type::isHLSLIntangibleType() const { const Type *Ty = getUnqualifiedDesugaredType(); diff --git a/clang/lib/CodeGen/CGHLSLRuntime.cpp b/clang/lib/CodeGen/CGHLSLRuntime.cpp index ed6d2036cb984..77d42e301f1f8 100644 --- a/clang/lib/CodeGen/CGHLSLRuntime.cpp +++ b/clang/lib/CodeGen/CGHLSLRuntime.cpp @@ -711,3 +711,8 @@ void CGHLSLRuntime::emitInitListOpaqueValues(CodeGenFunction &CGF, } } } + +// Returns true if the type is an HLSL resource class +bool CGHLSLRuntime::isResourceRecordType(const clang::Type *Ty) { + return HLSLAttributedResourceType::findHandleTypeOnResource(Ty) != nullptr; +} diff --git a/clang/lib/CodeGen/CGHLSLRuntime.h b/clang/lib/CodeGen/CGHLSLRuntime.h index a9da42324a038..31811cc390cde 100644 --- a/clang/lib/CodeGen/CGHLSLRuntime.h +++ b/clang/lib/CodeGen/CGHLSLRuntime.h @@ -134,6 +134,8 @@ class CGHLSLRuntime { BufferResBinding(HLSLResourceBindingAttr *Attr); }; + static bool isResourceRecordType(const clang::Type *Ty); + protected: CodeGenModule &CGM; diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index cec8f1233b663..78b62d8ac4b01 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -5595,7 +5595,11 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D, if (D->getType()->isReferenceType()) T = D->getType(); - if (getLangOpts().CPlusPlus) { + if (getLangOpts().HLSL && + getHLSLRuntime().isResourceRecordType(D->getType().getTypePtr())) { + Init = llvm::PoisonValue::get(getTypes().ConvertType(ASTTy)); + NeedsGlobalCtor = true; + } else if (getLangOpts().CPlusPlus) { Init = EmitNullConstant(T); if (!IsDefinitionAvailableExternally) NeedsGlobalCtor = true; diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp index bfe84b16218b7..5fedeb2046b4d 100644 --- a/clang/lib/Sema/SemaHLSL.cpp +++ b/clang/lib/Sema/SemaHLSL.cpp @@ -3065,6 +3065,13 @@ void SemaHLSL::ActOnVariableDeclarator(VarDecl *VD) { if (VD->getType()->isHLSLIntangibleType()) collectResourceBindingsOnVarDecl(VD); + if (VD->getType()->isHLSLResourceWrapper()) { + // Make the variable for resources static. The global externally visible + // storage is accessed through the handle, which is a member. The variable + // itself is not externally visible. + VD->setStorageClass(StorageClass::SC_Static); + } + // process explicit bindings processExplicitBindingsOnDecl(VD); } diff --git a/clang/test/CodeGenHLSL/builtins/ByteAddressBuffers-constructors.hlsl b/clang/test/CodeGenHLSL/builtins/ByteAddressBuffers-constructors.hlsl index 7fc6f4bb05745..926a37c689517 100644 --- a/clang/test/CodeGenHLSL/builtins/ByteAddressBuffers-constructors.hlsl +++ b/clang/test/CodeGenHLSL/builtins/ByteAddressBuffers-constructors.hlsl @@ -11,24 +11,24 @@ RasterizerOrderedByteAddressBuffer Buffer2: register(u3, space4); // CHECK: "class.hlsl::RWByteAddressBuffer" = type { target("dx.RawBuffer", i8, 1, 0) } // CHECK: "class.hlsl::RasterizerOrderedByteAddressBuffer" = type { target("dx.RawBuffer", i8, 1, 1) } -// CHECK: @Buffer0 = global %"class.hlsl::ByteAddressBuffer" zeroinitializer, align 4 -// CHECK: @Buffer1 = global %"class.hlsl::RWByteAddressBuffer" zeroinitializer, align 4 -// CHECK: @Buffer2 = global %"class.hlsl::RasterizerOrderedByteAddressBuffer" zeroinitializer, align 4 +// CHECK: @_ZL7Buffer0 = internal global %"class.hlsl::ByteAddressBuffer" poison, align 4 +// CHECK: @_ZL7Buffer1 = internal global %"class.hlsl::RWByteAddressBuffer" poison, align 4 +// CHECK: @_ZL7Buffer2 = internal global %"class.hlsl::RasterizerOrderedByteAddressBuffer" poison, align 4 // CHECK; define internal void @_init_resource_Buffer0() -// CHECK-DXIL: %Buffer0_h = call target("dx.RawBuffer", i8, 0, 0) @llvm.dx.resource.handlefrombinding.tdx.RawBuffer_i8_0_0t(i32 0, i32 0, i32 1, i32 0, i1 false) -// CHECK-DXIL: store target("dx.RawBuffer", i8, 0, 0) %Buffer0_h, ptr @Buffer0, align 4 +// CHECK-DXIL: [[H:%.*]] = call target("dx.RawBuffer", i8, 0, 0) @llvm.dx.resource.handlefrombinding.tdx.RawBuffer_i8_0_0t(i32 0, i32 0, i32 1, i32 0, i1 false) +// CHECK-DXIL: store target("dx.RawBuffer", i8, 0, 0) [[H]], ptr @_ZL7Buffer0, align 4 // CHECK; define internal void @_init_resource_Buffer1() -// CHECK-DXIL: %Buffer1_h = call target("dx.RawBuffer", i8, 1, 0) @llvm.dx.resource.handlefrombinding.tdx.RawBuffer_i8_1_0t(i32 2, i32 1, i32 1, i32 0, i1 false) -// CHECK-DXIL: store target("dx.RawBuffer", i8, 1, 0) %Buffer1_h, ptr @Buffer1, align 4 +// CHECK-DXIL: [[H:%.*]] = call target("dx.RawBuffer", i8, 1, 0) @llvm.dx.resource.handlefrombinding.tdx.RawBuffer_i8_1_0t(i32 2, i32 1, i32 1, i32 0, i1 false) +// CHECK-DXIL: store target("dx.RawBuffer", i8, 1, 0) [[H]], ptr @_ZL7Buffer1, align 4 // CHECK; define internal void @_init_resource_Buffer2() -// CHECK-DXIL: %Buffer2_h = call target("dx.RawBuffer", i8, 1, 1) @llvm.dx.resource.handlefrombinding.tdx.RawBuffer_i8_1_1t(i32 4, i32 3, i32 1, i32 0, i1 false) -// CHECK-DXIL: store target("dx.RawBuffer", i8, 1, 1) %Buffer2_h, ptr @Buffer2, align 4 +// CHECK-DXIL: [[H:%.*]] = call target("dx.RawBuffer", i8, 1, 1) @llvm.dx.resource.handlefrombinding.tdx.RawBuffer_i8_1_1t(i32 4, i32 3, i32 1, i32 0, i1 false) +// CHECK-DXIL: store target("dx.RawBuffer", i8, 1, 1) [[H]], ptr @_ZL7Buffer2, align 4 // CHECK: define internal void @_GLOBAL__sub_I_ByteAddressBuffers_constructors.hlsl() // CHECK: entry: -// CHECK: call void @_init_resource_Buffer0() -// CHECK: call void @_init_resource_Buffer1() -// CHECK: call void @_init_resource_Buffer2() +// CHECK: call void @_init_resource__ZL7Buffer0() +// CHECK: call void @_init_resource__ZL7Buffer1() +// CHECK: call void @_init_resource__ZL7Buffer2() diff --git a/clang/test/CodeGenHLSL/builtins/RWBuffer-constructor-opt.hlsl b/clang/test/CodeGenHLSL/builtins/RWBuffer-constructor-opt.hlsl index 03f22620a097d..239fb6d556999 100644 --- a/clang/test/CodeGenHLSL/builtins/RWBuffer-constructor-opt.hlsl +++ b/clang/test/CodeGenHLSL/builtins/RWBuffer-constructor-opt.hlsl @@ -1,8 +1,7 @@ -// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -x hlsl -emit-llvm -O3 -o - %s | FileCheck %s --check-prefixes=CHECK,CHECK-DXIL -// RUN: %clang_cc1 -triple spirv-vulkan-compute -x hlsl -emit-llvm -O3 -o - %s | FileCheck %s --check-prefixes=CHECK,CHECK-SPIRV +// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -x hlsl -emit-llvm -O3 -o - %s | FileCheck %s +// RUN: %clang_cc1 -triple spirv-vulkan-compute -x hlsl -emit-llvm -O3 -o - %s | FileCheck %s -// CHECK-SPIRV: %"class.hlsl::RWBuffer" = type { target("spirv.Image", float, 5, 2, 0, 0, 2, 0) } -// CHECK-DXIL: %"class.hlsl::RWBuffer" = type { target("dx.TypedBuffer", float, 1, 0, 0) } +// All referenced to an unused resource should be removed by optimizations. RWBuffer<float> Buf : register(u5, space3); [shader("compute")] @@ -10,12 +9,5 @@ RWBuffer<float> Buf : register(u5, space3); void main() { // CHECK: define void @main() // CHECK-NEXT: entry: - -// CHECK-SPIRV-NEXT: %[[HANDLE:.*]] = tail call target("spirv.Image", float, 5, 2, 0, 0, 2, 0) @llvm.spv.resource.handlefrombinding.tspirv.Image_f32_5_2_0_0_2_0t(i32 3, i32 5, i32 1, i32 0, i1 false) -// CHECK-SPIRV-NEXT: store target("spirv.Image", float, 5, 2, 0, 0, 2, 0) %[[HANDLE:.*]], ptr @Buf, align 8 - -// CHECK-DXIL-NEXT: %[[HANDLE:.*]] = tail call target("dx.TypedBuffer", float, 1, 0, 0) @llvm.dx.resource.handlefrombinding.tdx.TypedBuffer_f32_1_0_0t(i32 3, i32 5, i32 1, i32 0, i1 false) -// CHECK-DXIL-NEXT: store target("dx.TypedBuffer", float, 1, 0, 0) %[[HANDLE]], ptr @Buf, align 4 - // CHECK-NEXT: ret void } diff --git a/clang/test/CodeGenHLSL/builtins/RWBuffer-constructor.hlsl b/clang/test/CodeGenHLSL/builtins/RWBuffer-constructor.hlsl index d7cc3892a404b..5324176a7b9bb 100644 --- a/clang/test/CodeGenHLSL/builtins/RWBuffer-constructor.hlsl +++ b/clang/test/CodeGenHLSL/builtins/RWBuffer-constructor.hlsl @@ -7,14 +7,14 @@ RWBuffer<float> Buf : register(u5, space3); // CHECK: %"class.hlsl::RWBuffer" = type { target("dx.TypedBuffer", float, 1, 0, 0) } -// CHECK: @Buf = global %"class.hlsl::RWBuffer" zeroinitializer, align 4 +// CHECK: @_ZL3Buf = internal global %"class.hlsl::RWBuffer" poison, align 4 -// CHECK: define internal void @_init_resource_Buf() -// CHECK-DXIL: %Buf_h = call target("dx.TypedBuffer", float, 1, 0, 0) @llvm.dx.resource.handlefrombinding.tdx.TypedBuffer_f32_1_0_0t(i32 3, i32 5, i32 1, i32 0, i1 false) -// CHECK-DXIL: store target("dx.TypedBuffer", float, 1, 0, 0) %Buf_h, ptr @Buf, align 4 +// CHECK: define internal void @_init_resource__ZL3Buf() +// CHECK-DXIL: [[H:%.*]] = call target("dx.TypedBuffer", float, 1, 0, 0) @llvm.dx.resource.handlefrombinding.tdx.TypedBuffer_f32_1_0_0t(i32 3, i32 5, i32 1, i32 0, i1 false) +// CHECK-DXIL: store target("dx.TypedBuffer", float, 1, 0, 0) [[H]], ptr @_ZL3Buf, align 4 // CHECK: define linkonce_odr void @_ZN4hlsl8RWBufferIfEC2Ev(ptr noundef nonnull align 4 dereferenceable(4) %this) // CHECK-NEXT: entry: // CHECK: define internal void @_GLOBAL__sub_I_RWBuffer_constructor.hlsl() -// CHECK: call void @_init_resource_Buf() +// CHECK: call void @_init_resource__ZL3Buf() diff --git a/clang/test/CodeGenHLSL/builtins/StructuredBuffers-constructors.hlsl b/clang/test/CodeGenHLSL/builtins/StructuredBuffers-constructors.hlsl index bd931181045ba..04534c5550252 100644 --- a/clang/test/CodeGenHLSL/builtins/StructuredBuffers-constructors.hlsl +++ b/clang/test/CodeGenHLSL/builtins/StructuredBuffers-constructors.hlsl @@ -15,31 +15,31 @@ RasterizerOrderedStructuredBuffer<float> Buf5 : register(u1, space2); // CHECK: %"class.hlsl::ConsumeStructuredBuffer" = type { target("dx.RawBuffer", float, 1, 0) } // CHECK: %"class.hlsl::RasterizerOrderedStructuredBuffer" = type { target("dx.RawBuffer", float, 1, 1) } -// CHECK: @Buf = global %"class.hlsl::StructuredBuffer" zeroinitializer, align 4 -// CHECK: @Buf2 = global %"class.hlsl::RWStructuredBuffer" zeroinitializer, align 4 -// CHECK: @Buf3 = global %"class.hlsl::AppendStructuredBuffer" zeroinitializer, align 4 -// CHECK: @Buf4 = global %"class.hlsl::ConsumeStructuredBuffer" zeroinitializer, align 4 -// CHECK: @Buf5 = global %"class.hlsl::RasterizerOrderedStructuredBuffer" zeroinitializer, align 4 +// CHECK: @_ZL3Buf = internal global %"class.hlsl::StructuredBuffer" poison, align 4 +// CHECK: @_ZL4Buf2 = internal global %"class.hlsl::RWStructuredBuffer" poison, align 4 +// CHECK: @_ZL4Buf3 = internal global %"class.hlsl::AppendStructuredBuffer" poison, align 4 +// CHECK: @_ZL4Buf4 = internal global %"class.hlsl::ConsumeStructuredBuffer" poison, align 4 +// CHECK: @_ZL4Buf5 = internal global %"class.hlsl::RasterizerOrderedStructuredBuffer" poison, align 4 -// CHECK: define internal void @_init_resource_Buf() -// CHECK-DXIL: %Buf_h = call target("dx.RawBuffer", float, 0, 0) @llvm.dx.resource.handlefrombinding.tdx.RawBuffer_f32_0_0t(i32 0, i32 10, i32 1, i32 0, i1 false) -// CHECK-DXIL: store target("dx.RawBuffer", float, 0, 0) %Buf_h, ptr @Buf, align 4 +// CHECK: define internal void @_init_resource__ZL3Buf() +// CHECK-DXIL: [[H:%.*]] = call target("dx.RawBuffer", float, 0, 0) @llvm.dx.resource.handlefrombinding.tdx.RawBuffer_f32_0_0t(i32 0, i32 10, i32 1, i32 0, i1 false) +// CHECK-DXIL: store target("dx.RawBuffer", float, 0, 0) [[H]], ptr @_ZL3Buf, align 4 -// CHECK: define internal void @_init_resource_Buf2() -// CHECK-DXIL: %Buf2_h = call target("dx.RawBuffer", float, 1, 0) @llvm.dx.resource.handlefrombinding.tdx.RawBuffer_f32_1_0t(i32 1, i32 5, i32 1, i32 0, i1 false) -// CHECK-DXIL: store target("dx.RawBuffer", float, 1, 0) %Buf2_h, ptr @Buf2, align 4 +// CHECK: define internal void @_init_resource__ZL4Buf2() +// CHECK-DXIL: [[H:%.*]] = call target("dx.RawBuffer", float, 1, 0) @llvm.dx.resource.handlefrombinding.tdx.RawBuffer_f32_1_0t(i32 1, i32 5, i32 1, i32 0, i1 false) +// CHECK-DXIL: store target("dx.RawBuffer", float, 1, 0) [[H]], ptr @_ZL4Buf2, align 4 -// CHECK: define internal void @_init_resource_Buf3() -// CHECK-DXIL: %Buf3_h = call target("dx.RawBuffer", float, 1, 0) @llvm.dx.resource.handlefrombinding.tdx.RawBuffer_f32_1_0t(i32 0, i32 3, i32 1, i32 0, i1 false) -// CHECK-DXIL: store target("dx.RawBuffer", float, 1, 0) %Buf3_h, ptr @Buf3, align 4 +// CHECK: define internal void @_init_resource__ZL4Buf3() +// CHECK-DXIL: [[H:%.*]] = call target("dx.RawBuffer", float, 1, 0) @llvm.dx.resource.handlefrombinding.tdx.RawBuffer_f32_1_0t(i32 0, i32 3, i32 1, i32 0, i1 false) +// CHECK-DXIL: store target("dx.RawBuffer", float, 1, 0) [[H]], ptr @_ZL4Buf3, align 4 -// CHECK: define internal void @_init_resource_Buf4() -// CHECK-DXIL: %Buf4_h = call target("dx.RawBuffer", float, 1, 0) @llvm.dx.resource.handlefrombinding.tdx.RawBuffer_f32_1_0t(i32 0, i32 4, i32 1, i32 0, i1 false) -// CHECK-DXIL: store target("dx.RawBuffer", float, 1, 0) %Buf4_h, ptr @Buf4, align 4 +// CHECK: define internal void @_init_resource__ZL4Buf4() +// CHECK-DXIL: [[H:%.*]] = call target("dx.RawBuffer", float, 1, 0) @llvm.dx.resource.handlefrombinding.tdx.RawBuffer_f32_1_0t(i32 0, i32 4, i32 1, i32 0, i1 false) +// CHECK-DXIL: store target("dx.RawBuffer", float, 1, 0) [[H]], ptr @_ZL4Buf4, align 4 -// CHECK: define internal void @_init_resource_Buf5() -// CHECK-DXIL: %Buf5_h = call target("dx.RawBuffer", float, 1, 1) @llvm.dx.resource.handlefrombinding.tdx.RawBuffer_f32_1_1t(i32 2, i32 1, i32 1, i32 0, i1 false) -// CHECK-DXIL: store target("dx.RawBuffer", float, 1, 1) %Buf5_h, ptr @Buf5, align 4 +// CHECK: define internal void @_init_resource__ZL4Buf5() +// CHECK-DXIL: [[H:%.*]] = call target("dx.RawBuffer", float, 1, 1) @llvm.dx.resource.handlefrombinding.tdx.RawBuffer_f32_1_1t(i32 2, i32 1, i32 1, i32 0, i1 false) +// CHECK-DXIL: store target("dx.RawBuffer", float, 1, 1) [[H]], ptr @_ZL4Buf5, align 4 // CHECK: define linkonce_odr void @_ZN4hlsl16StructuredBufferIfEC2Ev(ptr noundef nonnull align 4 dereferenceable(4) %this) // CHECK-NEXT: entry: @@ -52,8 +52,8 @@ RasterizerOrderedStructuredBuffer<float> Buf5 : register(u1, space2); // CHECK-NEXT: entry: // CHECK: define internal void @_GLOBAL__sub_I_StructuredBuffers_constructors.hlsl() -// CHECK: call void @_init_resource_Buf() -// CHECK: call void @_init_resource_Buf2() -// CHECK: call void @_init_resource_Buf3() -// CHECK: call void @_init_resource_Buf4() -// CHECK: call void @_init_resource_Buf5() +// CHECK: call void @_init_resource__ZL3Buf() +// CHECK: call void @_init_resource__ZL4Buf2() +// CHECK: call void @_init_resource__ZL4Buf3() +// CHECK: call void @_init_resource__ZL4Buf4() +// CHECK: call void @_init_resource__ZL4Buf5() diff --git a/clang/test/CodeGenHLSL/resource-bindings.hlsl b/clang/test/CodeGenHLSL/resource-bindings.hlsl index 57e8cc29572b1..3342fb55a59a4 100644 --- a/clang/test/CodeGenHLSL/resource-bindings.hlsl +++ b/clang/test/CodeGenHLSL/resource-bindings.hlsl @@ -1,34 +1,34 @@ // RUN: %clang_cc1 -triple dxil--shadermodel6.6-compute -x hlsl -finclude-default-header -emit-llvm -disable-llvm-passes -o - %s | FileCheck %s -// CHECK: define internal void @_init_resource_U0S0() -// CHECK: %U0S0_h = call target("dx.TypedBuffer", <4 x float>, 1, 0, 0) @llvm.dx.resource.handlefrombinding.tdx.TypedBuffer_v4f32_1_0_0t(i32 0, i32 0, i32 1, i32 0, i1 false) -// CHECK: store target("dx.TypedBuffer", <4 x float>, 1, 0, 0) %U0S0_h, ptr @U0S0, align 4 +// CHECK: define internal void @_init_resource__ZL4U0S0() +// CHECK: [[H:%.*]] = call target("dx.TypedBuffer", <4 x float>, 1, 0, 0) @llvm.dx.resource.handlefrombinding.tdx.TypedBuffer_v4f32_1_0_0t(i32 0, i32 0, i32 1, i32 0, i1 false) +// CHECK: store target("dx.TypedBuffer", <4 x float>, 1, 0, 0) [[H]], ptr @_ZL4U0S0, align 4 RWBuffer<float4> U0S0 : register(u0); -// CHECK: define internal void @_init_resource_U5S3() -// CHECK: %U5S3_h = call target("dx.TypedBuffer", float, 1, 0, 0) @llvm.dx.resource.handlefrombinding.tdx.TypedBuffer_f32_1_0_0t(i32 3, i32 5, i32 1, i32 0, i1 false) -// CHECK: store target("dx.TypedBuffer", float, 1, 0, 0) %U5S3_h, ptr @U5S3, align 4 +// CHECK: define internal void @_init_resource__ZL4U5S3() +// CHECK: [[H:%.*]] = call target("dx.TypedBuffer", float, 1, 0, 0) @llvm.dx.resource.handlefrombinding.tdx.TypedBuffer_f32_1_0_0t(i32 3, i32 5, i32 1, i32 0, i1 false) +// CHECK: store target("dx.TypedBuffer", float, 1, 0, 0) [[H]], ptr @_ZL4U5S3, align 4 RWBuffer<float> U5S3 : register(u5, space3); -// CHECK: define internal void @_init_resource_T2S2() -// CHECK: %T2S2_h = call target("dx.RawBuffer", i32, 0, 0) @llvm.dx.resource.handlefrombinding.tdx.RawBuffer_i32_0_0t(i32 2, i32 2, i32 1, i32 0, i1 false) -// CHECK: store target("dx.RawBuffer", i32, 0, 0) %T2S2_h, ptr @T2S2, align 4 +// CHECK: define internal void @_init_resource__ZL4T2S2() +// CHECK: [[H:%.*]] = call target("dx.RawBuffer", i32, 0, 0) @llvm.dx.resource.handlefrombinding.tdx.RawBuffer_i32_0_0t(i32 2, i32 2, i32 1, i32 0, i1 false) +// CHECK: store target("dx.RawBuffer", i32, 0, 0) [[H]], ptr @_ZL4T2S2, align 4 StructuredBuffer<int> T2S2 : register(t2, space2); struct S { float4 f; int i; }; -// CHECK: define internal void @_init_resource_T3S0() -// CHECK: %T3S0_h = call target("dx.RawBuffer", %struct.S, 0, 0) @llvm.dx.resource.handlefrombinding.tdx.RawBuffer_s_struct.Ss_0_0t(i32 0, i32 3, i32 1, i32 0, i1 false) -// CHECK: store target("dx.RawBuffer", %struct.S, 0, 0) %T3S0_h, ptr @T3S0, align 4 +// CHECK: define internal void @_init_resource__ZL4T3S0() +// CHECK: [[H:%.*]] = call target("dx.RawBuffer", %struct.S, 0, 0) @llvm.dx.resource.handlefrombinding.tdx.RawBuffer_s_struct.Ss_0_0t(i32 0, i32 3, i32 1, i32 0, i1 false) +// CHECK: store target("dx.RawBuffer", %struct.S, 0, 0) [[H]], ptr @_ZL4T3S0, align 4 StructuredBuffer<S> T3S0 : register(t3); // CHECK: define void @main() -// CHECK: call void @_init_resource_U0S0() -// CHECK: call void @_init_resource_U5S3() -// CHECK: call void @_init_resource_T2S2() -// CHECK: call void @_init_resource_T3S0() +// CHECK: call void @_init_resource__ZL4U0S0() +// CHECK: call void @_init_resource__ZL4U5S3() +// CHECK: call void @_init_resource__ZL4T2S2() +// CHECK: call void @_init_resource__ZL4T3S0() [numthreads(4,1,1)] void main() {} >From ff8423946aca8198eb3c9f185cc8574305421a8c Mon Sep 17 00:00:00 2001 From: Steven Perron <stevenper...@google.com> Date: Thu, 27 Feb 2025 15:30:35 -0500 Subject: [PATCH 2/6] Fix format, and update ast tests. --- clang/lib/AST/Type.cpp | 2 +- clang/test/AST/HLSL/cbuffer.hlsl | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp index 992ce8b4b4795..6661389a63047 100644 --- a/clang/lib/AST/Type.cpp +++ b/clang/lib/AST/Type.cpp @@ -5132,7 +5132,7 @@ bool Type::isHLSLResourceWrapper() const { CXXRecordDecl *RD = RT->getAsCXXRecordDecl(); assert(RD != nullptr && - "all HLSL structs and classes should be CXXRecordDecl"); + "all HLSL structs and classes should be CXXRecordDecl"); assert(RD->isCompleteDefinition() && "expecting complete type"); if (RD->field_empty()) { return false; diff --git a/clang/test/AST/HLSL/cbuffer.hlsl b/clang/test/AST/HLSL/cbuffer.hlsl index 9946fda2355b2..e924f7e690297 100644 --- a/clang/test/AST/HLSL/cbuffer.hlsl +++ b/clang/test/AST/HLSL/cbuffer.hlsl @@ -159,7 +159,7 @@ cbuffer CB { static float SV; // CHECK: VarDecl {{.*}} s7 'EmptyStruct' callinit EmptyStruct s7; - // CHECK: VarDecl {{.*}} Buf 'RWBuffer<float>':'hlsl::RWBuffer<float>' callinit + // CHECK: VarDecl {{.*}} Buf 'RWBuffer<float>':'hlsl::RWBuffer<float>' static callinit RWBuffer<float> Buf; // CHECK: VarDecl {{.*}} ea 'EmptyArrayTypedef':'float[10][0]' EmptyArrayTypedef ea; >From 8848330355aab931903f63df400172592c59cfa5 Mon Sep 17 00:00:00 2001 From: Steven Perron <stevenper...@google.com> Date: Tue, 4 Mar 2025 10:32:38 -0500 Subject: [PATCH 3/6] Rewrite `isHLSLResrouceWrapper` as suggested --- clang/include/clang/AST/Type.h | 2 +- clang/lib/AST/Type.cpp | 27 ++------------------------- clang/lib/Sema/SemaHLSL.cpp | 6 +++++- 3 files changed, 8 insertions(+), 27 deletions(-) diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h index 5bfc78da7fa13..89e39fe817610 100644 --- a/clang/include/clang/AST/Type.h +++ b/clang/include/clang/AST/Type.h @@ -2661,7 +2661,7 @@ class alignas(TypeAlignment) Type : public ExtQualsTypeCommonBase { bool isHLSLSpecificType() const; // Any HLSL specific type bool isHLSLBuiltinIntangibleType() const; // Any HLSL builtin intangible type bool isHLSLAttributedResourceType() const; - bool isHLSLResourceWrapper() const; + bool isHLSLResourceClass() const; bool isHLSLIntangibleType() const; // Any HLSL intangible type (builtin, array, class) diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp index 6661389a63047..7a007ad81a460 100644 --- a/clang/lib/AST/Type.cpp +++ b/clang/lib/AST/Type.cpp @@ -5114,31 +5114,8 @@ bool Type::hasSizedVLAType() const { return false; } -bool Type::isHLSLResourceWrapper() const { - const Type *Ty = getUnqualifiedDesugaredType(); - - // check if it's a builtin type first - if (Ty->isBuiltinType()) - return Ty->isHLSLBuiltinIntangibleType(); - - // unwrap arrays - while (isa<ConstantArrayType>(Ty)) - Ty = Ty->getArrayElementTypeNoTypeQual(); - - const RecordType *RT = - dyn_cast<RecordType>(Ty->getUnqualifiedDesugaredType()); - if (!RT) - return false; - - CXXRecordDecl *RD = RT->getAsCXXRecordDecl(); - assert(RD != nullptr && - "all HLSL structs and classes should be CXXRecordDecl"); - assert(RD->isCompleteDefinition() && "expecting complete type"); - if (RD->field_empty()) { - return false; - } - const FieldDecl *FirstField = *RD->field_begin(); - return FirstField->getType()->isHLSLAttributedResourceType(); +bool Type::isHLSLResourceClass() const { + return HLSLAttributedResourceType::findHandleTypeOnResource(this) != nullptr; } bool Type::isHLSLIntangibleType() const { diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp index 5fedeb2046b4d..ba51f1636f19d 100644 --- a/clang/lib/Sema/SemaHLSL.cpp +++ b/clang/lib/Sema/SemaHLSL.cpp @@ -3065,7 +3065,11 @@ void SemaHLSL::ActOnVariableDeclarator(VarDecl *VD) { if (VD->getType()->isHLSLIntangibleType()) collectResourceBindingsOnVarDecl(VD); - if (VD->getType()->isHLSLResourceWrapper()) { + const Type *VarType = VD->getType().getTypePtr(); + if (VarType->isArrayType()) { + VarType = VarType->getArrayElementTypeNoTypeQual(); + } + if (VarType->isHLSLResourceClass()) { // Make the variable for resources static. The global externally visible // storage is accessed through the handle, which is a member. The variable // itself is not externally visible. >From 554a940a70f318fe90a80fec605f2b9ab305ca6e Mon Sep 17 00:00:00 2001 From: Steven Perron <stevenper...@google.com> Date: Tue, 4 Mar 2025 10:46:34 -0500 Subject: [PATCH 4/6] Remove redudent isResourceRecordType and update test. --- clang/lib/CodeGen/CGHLSLRuntime.cpp | 7 +------ .../CodeGenHLSL/builtins/RWBuffer-constructor-opt.hlsl | 2 ++ 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/clang/lib/CodeGen/CGHLSLRuntime.cpp b/clang/lib/CodeGen/CGHLSLRuntime.cpp index 77d42e301f1f8..39a1686e2113e 100644 --- a/clang/lib/CodeGen/CGHLSLRuntime.cpp +++ b/clang/lib/CodeGen/CGHLSLRuntime.cpp @@ -85,16 +85,11 @@ llvm::Triple::ArchType CGHLSLRuntime::getArch() { return CGM.getTarget().getTriple().getArch(); } -// Returns true if the type is an HLSL resource class -static bool isResourceRecordType(const clang::Type *Ty) { - return HLSLAttributedResourceType::findHandleTypeOnResource(Ty) != nullptr; -} - // Returns true if the type is an HLSL resource class or an array of them static bool isResourceRecordTypeOrArrayOf(const clang::Type *Ty) { while (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(Ty)) Ty = CAT->getArrayElementTypeNoTypeQual(); - return isResourceRecordType(Ty); + return CGHLSLRuntime::isResourceRecordType(Ty); } // Emits constant global variables for buffer constants declarations diff --git a/clang/test/CodeGenHLSL/builtins/RWBuffer-constructor-opt.hlsl b/clang/test/CodeGenHLSL/builtins/RWBuffer-constructor-opt.hlsl index 239fb6d556999..56c523f6bc8cf 100644 --- a/clang/test/CodeGenHLSL/builtins/RWBuffer-constructor-opt.hlsl +++ b/clang/test/CodeGenHLSL/builtins/RWBuffer-constructor-opt.hlsl @@ -7,7 +7,9 @@ RWBuffer<float> Buf : register(u5, space3); [shader("compute")] [numthreads(1, 1, 1)] void main() { +// CHECK-NOT: resource.handlefrombinding // CHECK: define void @main() // CHECK-NEXT: entry: // CHECK-NEXT: ret void +// CHECK-NOT: resource.handlefrombinding } >From 70912b19a2a4ae60f7661f2f7c0f0053d931b239 Mon Sep 17 00:00:00 2001 From: Steven Perron <stevenper...@google.com> Date: Tue, 4 Mar 2025 19:11:46 -0500 Subject: [PATCH 5/6] Update clang/lib/Sema/SemaHLSL.cpp Co-authored-by: Helena Kotas <heko...@microsoft.com> --- clang/lib/Sema/SemaHLSL.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp index ba51f1636f19d..f7ad95360497b 100644 --- a/clang/lib/Sema/SemaHLSL.cpp +++ b/clang/lib/Sema/SemaHLSL.cpp @@ -3066,9 +3066,8 @@ void SemaHLSL::ActOnVariableDeclarator(VarDecl *VD) { collectResourceBindingsOnVarDecl(VD); const Type *VarType = VD->getType().getTypePtr(); - if (VarType->isArrayType()) { + while (VarType->isArrayType()) VarType = VarType->getArrayElementTypeNoTypeQual(); - } if (VarType->isHLSLResourceClass()) { // Make the variable for resources static. The global externally visible // storage is accessed through the handle, which is a member. The variable >From 2240a33e43fd7adbb7fda76e9fddec915d545666 Mon Sep 17 00:00:00 2001 From: Steven Perron <stevenper...@google.com> Date: Wed, 5 Mar 2025 09:49:56 -0500 Subject: [PATCH 6/6] Rename and merge functions. --- clang/include/clang/AST/Type.h | 2 +- clang/lib/AST/Type.cpp | 2 +- clang/lib/CodeGen/CGHLSLRuntime.cpp | 9 ++------- clang/lib/CodeGen/CGHLSLRuntime.h | 2 -- clang/lib/CodeGen/CodeGenModule.cpp | 2 +- clang/lib/Sema/SemaHLSL.cpp | 2 +- 6 files changed, 6 insertions(+), 13 deletions(-) diff --git a/clang/include/clang/AST/Type.h b/clang/include/clang/AST/Type.h index 89e39fe817610..ef59bd1621fb8 100644 --- a/clang/include/clang/AST/Type.h +++ b/clang/include/clang/AST/Type.h @@ -2661,7 +2661,7 @@ class alignas(TypeAlignment) Type : public ExtQualsTypeCommonBase { bool isHLSLSpecificType() const; // Any HLSL specific type bool isHLSLBuiltinIntangibleType() const; // Any HLSL builtin intangible type bool isHLSLAttributedResourceType() const; - bool isHLSLResourceClass() const; + bool isHLSLResourceRecord() const; bool isHLSLIntangibleType() const; // Any HLSL intangible type (builtin, array, class) diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp index 7a007ad81a460..2fd7f5800594a 100644 --- a/clang/lib/AST/Type.cpp +++ b/clang/lib/AST/Type.cpp @@ -5114,7 +5114,7 @@ bool Type::hasSizedVLAType() const { return false; } -bool Type::isHLSLResourceClass() const { +bool Type::isHLSLResourceRecord() const { return HLSLAttributedResourceType::findHandleTypeOnResource(this) != nullptr; } diff --git a/clang/lib/CodeGen/CGHLSLRuntime.cpp b/clang/lib/CodeGen/CGHLSLRuntime.cpp index 39a1686e2113e..dc34653e8f497 100644 --- a/clang/lib/CodeGen/CGHLSLRuntime.cpp +++ b/clang/lib/CodeGen/CGHLSLRuntime.cpp @@ -89,7 +89,7 @@ llvm::Triple::ArchType CGHLSLRuntime::getArch() { static bool isResourceRecordTypeOrArrayOf(const clang::Type *Ty) { while (const ConstantArrayType *CAT = dyn_cast<ConstantArrayType>(Ty)) Ty = CAT->getArrayElementTypeNoTypeQual(); - return CGHLSLRuntime::isResourceRecordType(Ty); + return Ty->isHLSLResourceRecord(); } // Emits constant global variables for buffer constants declarations @@ -653,7 +653,7 @@ void CGHLSLRuntime::handleGlobalVarDefinition(const VarDecl *VD, // on? return; - if (!isResourceRecordType(VD->getType().getTypePtr())) + if (!VD->getType().getTypePtr()->isHLSLResourceRecord()) // FIXME: Only simple declarations of resources are supported for now. // Arrays of resources or resources in user defined classes are // not implemented yet. @@ -706,8 +706,3 @@ void CGHLSLRuntime::emitInitListOpaqueValues(CodeGenFunction &CGF, } } } - -// Returns true if the type is an HLSL resource class -bool CGHLSLRuntime::isResourceRecordType(const clang::Type *Ty) { - return HLSLAttributedResourceType::findHandleTypeOnResource(Ty) != nullptr; -} diff --git a/clang/lib/CodeGen/CGHLSLRuntime.h b/clang/lib/CodeGen/CGHLSLRuntime.h index 31811cc390cde..a9da42324a038 100644 --- a/clang/lib/CodeGen/CGHLSLRuntime.h +++ b/clang/lib/CodeGen/CGHLSLRuntime.h @@ -134,8 +134,6 @@ class CGHLSLRuntime { BufferResBinding(HLSLResourceBindingAttr *Attr); }; - static bool isResourceRecordType(const clang::Type *Ty); - protected: CodeGenModule &CGM; diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index 78b62d8ac4b01..bca0a932b3495 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -5596,7 +5596,7 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D, T = D->getType(); if (getLangOpts().HLSL && - getHLSLRuntime().isResourceRecordType(D->getType().getTypePtr())) { + D->getType().getTypePtr()->isHLSLResourceRecord()) { Init = llvm::PoisonValue::get(getTypes().ConvertType(ASTTy)); NeedsGlobalCtor = true; } else if (getLangOpts().CPlusPlus) { diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp index f7ad95360497b..a4b0b5e4df63f 100644 --- a/clang/lib/Sema/SemaHLSL.cpp +++ b/clang/lib/Sema/SemaHLSL.cpp @@ -3068,7 +3068,7 @@ void SemaHLSL::ActOnVariableDeclarator(VarDecl *VD) { const Type *VarType = VD->getType().getTypePtr(); while (VarType->isArrayType()) VarType = VarType->getArrayElementTypeNoTypeQual(); - if (VarType->isHLSLResourceClass()) { + if (VarType->isHLSLResourceRecord()) { // Make the variable for resources static. The global externally visible // storage is accessed through the handle, which is a member. The variable // itself is not externally visible. _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits