[clang] [HLSL] Fix resrouce wrapper declaration (PR #129100)
Steven Perron via cfe-commits
cfe-commits at lists.llvm.org
Wed Mar 5 06:51:45 PST 2025
https://github.com/s-perron updated https://github.com/llvm/llvm-project/pull/129100
>From 6961d5683a4bc38c2fee053bc956475d0ccb0b80 Mon Sep 17 00:00:00 2001
From: Steven Perron <stevenperron at 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 c3ff7ebd88516..c5afae48b6a5f 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 8c11ec2e1fe24..e924f49168c52 100644
--- a/clang/lib/AST/Type.cpp
+++ b/clang/lib/AST/Type.cpp
@@ -5098,6 +5098,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 1b7d0ac89690e..e73a5f6b38218 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -5594,7 +5594,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 283a9801fc707..0227640095af1 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -3062,6 +3062,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 d2148122fdc7297996e363a83598e55eb1136160 Mon Sep 17 00:00:00 2001
From: Steven Perron <stevenperron at 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 +-
clang/test/AST/HLSL/resource_binding_attr.hlsl | 6 +++---
3 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp
index e924f49168c52..a44eabc3ff39f 100644
--- a/clang/lib/AST/Type.cpp
+++ b/clang/lib/AST/Type.cpp
@@ -5116,7 +5116,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;
diff --git a/clang/test/AST/HLSL/resource_binding_attr.hlsl b/clang/test/AST/HLSL/resource_binding_attr.hlsl
index 6fac903f75e18..f019957ae62d5 100644
--- a/clang/test/AST/HLSL/resource_binding_attr.hlsl
+++ b/clang/test/AST/HLSL/resource_binding_attr.hlsl
@@ -27,15 +27,15 @@ float foo() {
return a + b;
}
-// CHECK: VarDecl 0x{{[0-9a-f]+}} <{{.*}}> col:17 UAV 'RWBuffer<float>':'hlsl::RWBuffer<float>' callinit
+// CHECK: VarDecl 0x{{[0-9a-f]+}} <{{.*}}> col:17 UAV 'RWBuffer<float>':'hlsl::RWBuffer<float>' static callinit
// CHECK-NEXT:-CXXConstructExpr 0x{{[0-9a-f]+}} <col:17> 'RWBuffer<float>':'hlsl::RWBuffer<float>' 'void ()'
// CHECK-NEXT:-HLSLResourceBindingAttr 0x{{[0-9a-f]+}} <col:23> "u3" "space0"
RWBuffer<float> UAV : register(u3);
-// CHECK: -VarDecl 0x{{[0-9a-f]+}} <{{.*}}> col:17 UAV1 'RWBuffer<float>':'hlsl::RWBuffer<float>' callinit
+// CHECK: -VarDecl 0x{{[0-9a-f]+}} <{{.*}}> col:17 UAV1 'RWBuffer<float>':'hlsl::RWBuffer<float>' static callinit
// CHECK-NEXT:-CXXConstructExpr 0x{{[0-9a-f]+}} <col:17> 'RWBuffer<float>':'hlsl::RWBuffer<float>' 'void ()'
// CHECK-NEXT:-HLSLResourceBindingAttr 0x{{[0-9a-f]+}} <col:24> "u2" "space0"
-// CHECK-NEXT:-VarDecl 0x{{[0-9a-f]+}} <col:1, col:38> col:38 UAV2 'RWBuffer<float>':'hlsl::RWBuffer<float>' callinit
+// CHECK-NEXT:-VarDecl 0x{{[0-9a-f]+}} <col:1, col:38> col:38 UAV2 'RWBuffer<float>':'hlsl::RWBuffer<float>' static callinit
// CHECK-NEXT:-CXXConstructExpr 0x{{[0-9a-f]+}} <col:38> 'RWBuffer<float>':'hlsl::RWBuffer<float>' 'void ()'
// CHECK-NEXT:-HLSLResourceBindingAttr 0x{{[0-9a-f]+}} <col:45> "u4" "space0"
RWBuffer<float> UAV1 : register(u2), UAV2 : register(u4);
>From 80ff71eb9755fc60ffb66066485b4ef8996ad525 Mon Sep 17 00:00:00 2001
From: Steven Perron <stevenperron at 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 c5afae48b6a5f..d7e8d36acdd50 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 a44eabc3ff39f..0b3ba1881d1d4 100644
--- a/clang/lib/AST/Type.cpp
+++ b/clang/lib/AST/Type.cpp
@@ -5098,31 +5098,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 0227640095af1..1b98ab74d177e 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -3062,7 +3062,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 d0f6bc11a7c5fe23522707fac5314feccfd04f8d Mon Sep 17 00:00:00 2001
From: Steven Perron <stevenperron at 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 901556b0be9c4a6c84295ea3e17773cef62c40cc Mon Sep 17 00:00:00 2001
From: Steven Perron <stevenperron at 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 <hekotas at 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 1b98ab74d177e..403c8b15646c3 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -3063,9 +3063,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 4a342118a77359c37cee0f2b621679673c66727a Mon Sep 17 00:00:00 2001
From: Steven Perron <stevenperron at 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 d7e8d36acdd50..9bc25d7ef8ec0 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 0b3ba1881d1d4..04d90bb71b96e 100644
--- a/clang/lib/AST/Type.cpp
+++ b/clang/lib/AST/Type.cpp
@@ -5098,7 +5098,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 e73a5f6b38218..b4b3491aab5f7 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -5595,7 +5595,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 403c8b15646c3..4cacb4e265b04 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -3065,7 +3065,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.
More information about the cfe-commits
mailing list