From 93f683f434b69072fb5d7d81bd5d16e3491a73ca Mon Sep 17 00:00:00 2001 From: Chris Bieneman Date: Mon, 22 Jun 2026 18:29:49 -0500 Subject: [PATCH] [HLSL] Preserve coherence qualifiers on resource flat-conversions PerformHLSLConversion forced the ICK_Flat_Conversion cast target to the structural/unqualified type, discarding the 'globallycoherent' (and 'reordercoherent') AttributedType. As a result, the converted expression's type no longer reflected the coherence of its destination, forcing consumers to reconstruct that information from declarations. Re-apply the coherence AttributedType to the flat-conversion result when the target is a resource type, so the converted expression's type carries the coherence of its destination (e.g. a ResourceDescriptorHeap[] access used to initialize a 'globallycoherent' resource). --- tools/clang/lib/Sema/SemaHLSL.cpp | 22 +++++++++++++-- .../attributes/coherent_flat_conversion.hlsl | 28 +++++++++++++++++++ .../coherent_flat_conversion_ast.hlsl | 20 +++++++++++++ 3 files changed, 68 insertions(+), 2 deletions(-) create mode 100644 tools/clang/test/CodeGenDXIL/hlsl/attributes/coherent_flat_conversion.hlsl create mode 100644 tools/clang/test/SemaHLSL/attributes/coherent_flat_conversion_ast.hlsl diff --git a/tools/clang/lib/Sema/SemaHLSL.cpp b/tools/clang/lib/Sema/SemaHLSL.cpp index d1ff0ec7b6..587cd4ffdd 100644 --- a/tools/clang/lib/Sema/SemaHLSL.cpp +++ b/tools/clang/lib/Sema/SemaHLSL.cpp @@ -9589,6 +9589,10 @@ clang::ExprResult HLSLExternalSource::PerformHLSLConversion( clang::Sema::CheckedConversionKind CCK) { QualType sourceType = From->getType(); sourceType = GetStructuralForm(sourceType); + + // Store off the type attributes that could be accidentially dropped. + const bool targetGloballyCoherent = hlsl::HasHLSLGloballyCoherent(targetType); + const bool targetReorderCoherent = hlsl::HasHLSLReorderCoherent(targetType); targetType = GetStructuralForm(targetType); ArTypeInfo SourceInfo, TargetInfo; CollectInfo(sourceType, &SourceInfo); @@ -9605,9 +9609,23 @@ clang::ExprResult HLSLExternalSource::PerformHLSLConversion( // convert that to an array of casts under a special kind of flat // flat conversion node? What do component conversion casts cast // from? We don't have a From expression for individiual components. + QualType flatCastType = targetType.getUnqualifiedType(); + // Preserve coherence qualifiers when converting to a resource type so the + // converted expression's type still reflects the coherence of its + // destination. + if (hlsl::IsHLSLResourceType(flatCastType)) { + if (targetGloballyCoherent) + flatCastType = m_context->getAttributedType( + AttributedType::attr_hlsl_globallycoherent, flatCastType, + flatCastType); + else if (targetReorderCoherent) + flatCastType = m_context->getAttributedType( + AttributedType::attr_hlsl_reordercoherent, flatCastType, + flatCastType); + } From = m_sema - ->ImpCastExprToType(From, targetType.getUnqualifiedType(), - CK_FlatConversion, From->getValueKind(), + ->ImpCastExprToType(From, flatCastType, CK_FlatConversion, + From->getValueKind(), /*BasePath=*/0, CCK) .get(); break; diff --git a/tools/clang/test/CodeGenDXIL/hlsl/attributes/coherent_flat_conversion.hlsl b/tools/clang/test/CodeGenDXIL/hlsl/attributes/coherent_flat_conversion.hlsl new file mode 100644 index 0000000000..2e410e510b --- /dev/null +++ b/tools/clang/test/CodeGenDXIL/hlsl/attributes/coherent_flat_conversion.hlsl @@ -0,0 +1,28 @@ +// RUN: %dxc -T lib_6_9 %s | FileCheck %s +// REQUIRES: dxil-1-9 + +// Initializing a coherent resource from ResourceDescriptorHeap[] goes through a +// flat-conversion. Verify the coherence qualifier of the destination is carried +// through to the annotated handle properties in the generated DXIL. + +RWBuffer OutBuf : register(u0); + +// CHECK: call %dx.types.Handle @dx.op.createHandleFromHeap(i32 218 +// CHECK: call %dx.types.Handle @dx.op.annotateHandle(i32 216, %dx.types.Handle %{{.*}}, %dx.types.ResourceProperties { i32 20491, i32 0 }) +// CHECK-SAME: resource: globallycoherent RWByteAddressBuffer +[shader("raygeneration")] +void glc_entry() +{ + globallycoherent RWByteAddressBuffer buf = ResourceDescriptorHeap[0]; + buf.Store(0, 0); +} + +// CHECK: call %dx.types.Handle @dx.op.createHandleFromHeap(i32 218 +// CHECK: call %dx.types.Handle @dx.op.annotateHandle(i32 216, %dx.types.Handle %{{.*}}, %dx.types.ResourceProperties { i32 69642, i32 265 }) +// CHECK-SAME: resource: reordercoherent RWTypedBuffer +[shader("raygeneration")] +void rc_entry() +{ + reordercoherent RWBuffer buf = ResourceDescriptorHeap[1]; + OutBuf[0] = buf[0]; +} diff --git a/tools/clang/test/SemaHLSL/attributes/coherent_flat_conversion_ast.hlsl b/tools/clang/test/SemaHLSL/attributes/coherent_flat_conversion_ast.hlsl new file mode 100644 index 0000000000..08fa80a1f6 --- /dev/null +++ b/tools/clang/test/SemaHLSL/attributes/coherent_flat_conversion_ast.hlsl @@ -0,0 +1,20 @@ +// RUN: %dxc -T lib_6_9 -ast-dump %s | FileCheck %s +// REQUIRES: dxil-1-9 + +// Initializing a coherent resource from ResourceDescriptorHeap[] produces an +// ICK_Flat_Conversion. Verify the converted expression's type still carries the +// coherence qualifier of its destination instead of dropping it. + +[shader("raygeneration")] +void main() +{ + // CHECK: VarDecl {{.*}} used glcBuf 'globallycoherent RWByteAddressBuffer':'RWByteAddressBuffer' cinit + // CHECK-NEXT: ImplicitCastExpr {{.*}} 'globallycoherent RWByteAddressBuffer':'RWByteAddressBuffer' + globallycoherent RWByteAddressBuffer glcBuf = ResourceDescriptorHeap[0]; + glcBuf.Store(0, 0); + + // CHECK: VarDecl {{.*}} used rcBuf 'reordercoherent RWBuffer':'RWBuffer >' cinit + // CHECK-NEXT: ImplicitCastExpr {{.*}} 'reordercoherent RWBuffer >':'RWBuffer >' + reordercoherent RWBuffer rcBuf = ResourceDescriptorHeap[1]; + rcBuf[0] = 5; +}