https://github.com/bob80905 updated https://github.com/llvm/llvm-project/pull/212663
>From 56404306415ddd3dcb9cb5cee44fd114d3fd72bc Mon Sep 17 00:00:00 2001 From: Joshua Batista <[email protected]> Date: Tue, 28 Jul 2026 17:40:01 -0700 Subject: [PATCH 1/2] first attempt --- clang/lib/CodeGen/CGHLSLBuiltins.cpp | 13 +++++++- .../CodeGenHLSL/builtins/InterlockedAdd.hlsl | 24 +++++++------- .../CodeGenHLSL/builtins/InterlockedOr.hlsl | 24 +++++++------- .../CodeGenHLSL/builtins/InterlockedXor.hlsl | 26 ++++++++-------- .../builtins/RWBuffer-Interlocked.hlsl | 12 +++---- .../RWByteAddressBuffer-InterlockedAdd.hlsl | 16 +++++----- .../RWByteAddressBuffer-InterlockedOr.hlsl | 16 +++++----- .../RWByteAddressBuffer-InterlockedXor.hlsl | 16 +++++----- ...deredByteAddressBuffer-InterlockedAdd.hlsl | 8 ++--- ...rderedByteAddressBuffer-InterlockedOr.hlsl | 8 ++--- ...deredByteAddressBuffer-InterlockedXor.hlsl | 8 ++--- llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp | 3 ++ .../Target/SPIRV/SPIRVInstructionSelector.cpp | 14 ++++++++- llvm/lib/Target/SPIRV/SPIRVUtils.cpp | 9 +++++- .../atomicrmw-vulkan-relaxed-workgroup.ll | 26 ++++++++++++++++ .../linkage/groupshared-no-import-linkage.ll | 31 +++++++++++++++++++ 16 files changed, 172 insertions(+), 82 deletions(-) create mode 100644 llvm/test/CodeGen/SPIRV/atomicrmw-vulkan-relaxed-workgroup.ll create mode 100644 llvm/test/CodeGen/SPIRV/linkage/groupshared-no-import-linkage.ll diff --git a/clang/lib/CodeGen/CGHLSLBuiltins.cpp b/clang/lib/CodeGen/CGHLSLBuiltins.cpp index 0796d121a9b43..9818f94fcdaca 100644 --- a/clang/lib/CodeGen/CGHLSLBuiltins.cpp +++ b/clang/lib/CodeGen/CGHLSLBuiltins.cpp @@ -310,6 +310,16 @@ static Value *handleElementwiseF32ToF16(CodeGenFunction &CGF, llvm_unreachable("Intrinsic F32ToF16 not supported by target architecture"); } +// Pick the atomic memory scope for an HLSL Interlocked* op by destination: +// Workgroup for groupshared, Device otherwise (Vulkan forbids CrossDevice). +static llvm::SyncScope::ID GetInterlockedScope(CodeGenFunction &CGF, + const LValue &DestLV) { + StringRef ScopeName = DestLV.getAddressSpace() == LangAS::hlsl_groupshared + ? "workgroup" + : "device"; + return CGF.getLLVMContext().getOrInsertSyncScopeID(ScopeName); +} + static Value *handleInterlockedOp(CodeGenFunction &CGF, const CallExpr *E, llvm::AtomicRMWInst::BinOp Op) { // Emit `atomicrmw <op>` directly — no intermediate intrinsic needed on @@ -321,7 +331,8 @@ static Value *handleInterlockedOp(CodeGenFunction &CGF, const CallExpr *E, "Intrinsic InterlockedOp value operand must be an integer"); llvm::AtomicRMWInst *Call = CGF.Builder.CreateAtomicRMW( - Op, DestAddr, Val, llvm::AtomicOrdering::Monotonic); + Op, DestAddr, Val, llvm::AtomicOrdering::Monotonic, + GetInterlockedScope(CGF, DestLV)); // The 3-arg overload writes the old value (the RMW's return value) into // the `original_value` reference parameter. diff --git a/clang/test/CodeGenHLSL/builtins/InterlockedAdd.hlsl b/clang/test/CodeGenHLSL/builtins/InterlockedAdd.hlsl index 6bb4fd25c4a0c..a878c372dcea6 100644 --- a/clang/test/CodeGenHLSL/builtins/InterlockedAdd.hlsl +++ b/clang/test/CodeGenHLSL/builtins/InterlockedAdd.hlsl @@ -14,45 +14,45 @@ groupshared int64_t gs_i64; groupshared uint64_t gs_u64; // CHECK-LABEL: define {{(dso_local |hidden |internal |protected |spir_func )*}}void @{{.*}}test_int_2arg -// DXCHECK: atomicrmw add ptr addrspace(3) {{.*}}@gs_i32{{.*}}, i32 %{{.*}} monotonic -// SPVCHECK: atomicrmw add ptr addrspace(3) {{.*}}@gs_i32{{.*}}, i32 %{{.*}} monotonic +// DXCHECK: atomicrmw add ptr addrspace(3) {{.*}}@gs_i32{{.*}}, i32 %{{.*}} syncscope("workgroup") monotonic +// SPVCHECK: atomicrmw add ptr addrspace(3) {{.*}}@gs_i32{{.*}}, i32 %{{.*}} syncscope("workgroup") monotonic export void test_int_2arg(int v) { InterlockedAdd(gs_i32, v); } // CHECK-LABEL: define {{(dso_local |hidden |internal |protected |spir_func )*}}void @{{.*}}test_uint_2arg -// DXCHECK: atomicrmw add ptr addrspace(3) {{.*}}@gs_u32{{.*}}, i32 %{{.*}} monotonic -// SPVCHECK: atomicrmw add ptr addrspace(3) {{.*}}@gs_u32{{.*}}, i32 %{{.*}} monotonic +// DXCHECK: atomicrmw add ptr addrspace(3) {{.*}}@gs_u32{{.*}}, i32 %{{.*}} syncscope("workgroup") monotonic +// SPVCHECK: atomicrmw add ptr addrspace(3) {{.*}}@gs_u32{{.*}}, i32 %{{.*}} syncscope("workgroup") monotonic export void test_uint_2arg(uint v) { InterlockedAdd(gs_u32, v); } // CHECK-LABEL: define {{(dso_local |hidden |internal |protected |spir_func )*}}void @{{.*}}test_int_3arg -// DXCHECK: %[[R:.*]] = atomicrmw add ptr addrspace(3) {{.*}}@gs_i32{{.*}}, i32 %{{.*}} monotonic -// SPVCHECK: %[[R:.*]] = atomicrmw add ptr addrspace(3) {{.*}}@gs_i32{{.*}}, i32 %{{.*}} monotonic +// DXCHECK: %[[R:.*]] = atomicrmw add ptr addrspace(3) {{.*}}@gs_i32{{.*}}, i32 %{{.*}} syncscope("workgroup") monotonic +// SPVCHECK: %[[R:.*]] = atomicrmw add ptr addrspace(3) {{.*}}@gs_i32{{.*}}, i32 %{{.*}} syncscope("workgroup") monotonic // CHECK: store i32 %[[R]], ptr {{.*}} export void test_int_3arg(int v, out int orig) { InterlockedAdd(gs_i32, v, orig); } // CHECK-LABEL: define {{(dso_local |hidden |internal |protected |spir_func )*}}void @{{.*}}test_uint_3arg -// DXCHECK: %[[R:.*]] = atomicrmw add ptr addrspace(3) {{.*}}@gs_u32{{.*}}, i32 %{{.*}} monotonic -// SPVCHECK: %[[R:.*]] = atomicrmw add ptr addrspace(3) {{.*}}@gs_u32{{.*}}, i32 %{{.*}} monotonic +// DXCHECK: %[[R:.*]] = atomicrmw add ptr addrspace(3) {{.*}}@gs_u32{{.*}}, i32 %{{.*}} syncscope("workgroup") monotonic +// SPVCHECK: %[[R:.*]] = atomicrmw add ptr addrspace(3) {{.*}}@gs_u32{{.*}}, i32 %{{.*}} syncscope("workgroup") monotonic // CHECK: store i32 %[[R]], ptr {{.*}} export void test_uint_3arg(uint v, out uint orig) { InterlockedAdd(gs_u32, v, orig); } // CHECK-LABEL: define {{(dso_local |hidden |internal |protected |spir_func )*}}void @{{.*}}test_int64_2arg -// DXCHECK: atomicrmw add ptr addrspace(3) {{.*}}@gs_i64{{.*}}, i64 %{{.*}} monotonic -// SPVCHECK: atomicrmw add ptr addrspace(3) {{.*}}@gs_i64{{.*}}, i64 %{{.*}} monotonic +// DXCHECK: atomicrmw add ptr addrspace(3) {{.*}}@gs_i64{{.*}}, i64 %{{.*}} syncscope("workgroup") monotonic +// SPVCHECK: atomicrmw add ptr addrspace(3) {{.*}}@gs_i64{{.*}}, i64 %{{.*}} syncscope("workgroup") monotonic export void test_int64_2arg(int64_t v) { InterlockedAdd(gs_i64, v); } // CHECK-LABEL: define {{(dso_local |hidden |internal |protected |spir_func )*}}void @{{.*}}test_uint64_3arg -// DXCHECK: %[[R:.*]] = atomicrmw add ptr addrspace(3) {{.*}}@gs_u64{{.*}}, i64 %{{.*}} monotonic -// SPVCHECK: %[[R:.*]] = atomicrmw add ptr addrspace(3) {{.*}}@gs_u64{{.*}}, i64 %{{.*}} monotonic +// DXCHECK: %[[R:.*]] = atomicrmw add ptr addrspace(3) {{.*}}@gs_u64{{.*}}, i64 %{{.*}} syncscope("workgroup") monotonic +// SPVCHECK: %[[R:.*]] = atomicrmw add ptr addrspace(3) {{.*}}@gs_u64{{.*}}, i64 %{{.*}} syncscope("workgroup") monotonic // CHECK: store i64 %[[R]], ptr {{.*}} export void test_uint64_3arg(uint64_t v, out uint64_t orig) { InterlockedAdd(gs_u64, v, orig); diff --git a/clang/test/CodeGenHLSL/builtins/InterlockedOr.hlsl b/clang/test/CodeGenHLSL/builtins/InterlockedOr.hlsl index 9c23c5a055a03..c5def7368ecc6 100644 --- a/clang/test/CodeGenHLSL/builtins/InterlockedOr.hlsl +++ b/clang/test/CodeGenHLSL/builtins/InterlockedOr.hlsl @@ -14,45 +14,45 @@ groupshared int64_t gs_i64; groupshared uint64_t gs_u64; // CHECK-LABEL: define {{(dso_local |hidden |internal |protected |spir_func )*}}void @{{.*}}test_int_2arg -// DXCHECK: atomicrmw or ptr addrspace(3) {{.*}}@gs_i32{{.*}}, i32 %{{.*}} monotonic -// SPVCHECK: atomicrmw or ptr addrspace(3) {{.*}}@gs_i32{{.*}}, i32 %{{.*}} monotonic +// DXCHECK: atomicrmw or ptr addrspace(3) {{.*}}@gs_i32{{.*}}, i32 %{{.*}} syncscope("workgroup") monotonic +// SPVCHECK: atomicrmw or ptr addrspace(3) {{.*}}@gs_i32{{.*}}, i32 %{{.*}} syncscope("workgroup") monotonic export void test_int_2arg(int v) { InterlockedOr(gs_i32, v); } // CHECK-LABEL: define {{(dso_local |hidden |internal |protected |spir_func )*}}void @{{.*}}test_uint_2arg -// DXCHECK: atomicrmw or ptr addrspace(3) {{.*}}@gs_u32{{.*}}, i32 %{{.*}} monotonic -// SPVCHECK: atomicrmw or ptr addrspace(3) {{.*}}@gs_u32{{.*}}, i32 %{{.*}} monotonic +// DXCHECK: atomicrmw or ptr addrspace(3) {{.*}}@gs_u32{{.*}}, i32 %{{.*}} syncscope("workgroup") monotonic +// SPVCHECK: atomicrmw or ptr addrspace(3) {{.*}}@gs_u32{{.*}}, i32 %{{.*}} syncscope("workgroup") monotonic export void test_uint_2arg(uint v) { InterlockedOr(gs_u32, v); } // CHECK-LABEL: define {{(dso_local |hidden |internal |protected |spir_func )*}}void @{{.*}}test_int_3arg -// DXCHECK: %[[R:.*]] = atomicrmw or ptr addrspace(3) {{.*}}@gs_i32{{.*}}, i32 %{{.*}} monotonic -// SPVCHECK: %[[R:.*]] = atomicrmw or ptr addrspace(3) {{.*}}@gs_i32{{.*}}, i32 %{{.*}} monotonic +// DXCHECK: %[[R:.*]] = atomicrmw or ptr addrspace(3) {{.*}}@gs_i32{{.*}}, i32 %{{.*}} syncscope("workgroup") monotonic +// SPVCHECK: %[[R:.*]] = atomicrmw or ptr addrspace(3) {{.*}}@gs_i32{{.*}}, i32 %{{.*}} syncscope("workgroup") monotonic // CHECK: store i32 %[[R]], ptr {{.*}} export void test_int_3arg(int v, out int orig) { InterlockedOr(gs_i32, v, orig); } // CHECK-LABEL: define {{(dso_local |hidden |internal |protected |spir_func )*}}void @{{.*}}test_uint_3arg -// DXCHECK: %[[R:.*]] = atomicrmw or ptr addrspace(3) {{.*}}@gs_u32{{.*}}, i32 %{{.*}} monotonic -// SPVCHECK: %[[R:.*]] = atomicrmw or ptr addrspace(3) {{.*}}@gs_u32{{.*}}, i32 %{{.*}} monotonic +// DXCHECK: %[[R:.*]] = atomicrmw or ptr addrspace(3) {{.*}}@gs_u32{{.*}}, i32 %{{.*}} syncscope("workgroup") monotonic +// SPVCHECK: %[[R:.*]] = atomicrmw or ptr addrspace(3) {{.*}}@gs_u32{{.*}}, i32 %{{.*}} syncscope("workgroup") monotonic // CHECK: store i32 %[[R]], ptr {{.*}} export void test_uint_3arg(uint v, out uint orig) { InterlockedOr(gs_u32, v, orig); } // CHECK-LABEL: define {{(dso_local |hidden |internal |protected |spir_func )*}}void @{{.*}}test_int64_2arg -// DXCHECK: atomicrmw or ptr addrspace(3) {{.*}}@gs_i64{{.*}}, i64 %{{.*}} monotonic -// SPVCHECK: atomicrmw or ptr addrspace(3) {{.*}}@gs_i64{{.*}}, i64 %{{.*}} monotonic +// DXCHECK: atomicrmw or ptr addrspace(3) {{.*}}@gs_i64{{.*}}, i64 %{{.*}} syncscope("workgroup") monotonic +// SPVCHECK: atomicrmw or ptr addrspace(3) {{.*}}@gs_i64{{.*}}, i64 %{{.*}} syncscope("workgroup") monotonic export void test_int64_2arg(int64_t v) { InterlockedOr(gs_i64, v); } // CHECK-LABEL: define {{(dso_local |hidden |internal |protected |spir_func )*}}void @{{.*}}test_uint64_3arg -// DXCHECK: %[[R:.*]] = atomicrmw or ptr addrspace(3) {{.*}}@gs_u64{{.*}}, i64 %{{.*}} monotonic -// SPVCHECK: %[[R:.*]] = atomicrmw or ptr addrspace(3) {{.*}}@gs_u64{{.*}}, i64 %{{.*}} monotonic +// DXCHECK: %[[R:.*]] = atomicrmw or ptr addrspace(3) {{.*}}@gs_u64{{.*}}, i64 %{{.*}} syncscope("workgroup") monotonic +// SPVCHECK: %[[R:.*]] = atomicrmw or ptr addrspace(3) {{.*}}@gs_u64{{.*}}, i64 %{{.*}} syncscope("workgroup") monotonic // CHECK: store i64 %[[R]], ptr {{.*}} export void test_uint64_3arg(uint64_t v, out uint64_t orig) { InterlockedOr(gs_u64, v, orig); diff --git a/clang/test/CodeGenHLSL/builtins/InterlockedXor.hlsl b/clang/test/CodeGenHLSL/builtins/InterlockedXor.hlsl index 8cd799c09eb01..e0a60736980ec 100644 --- a/clang/test/CodeGenHLSL/builtins/InterlockedXor.hlsl +++ b/clang/test/CodeGenHLSL/builtins/InterlockedXor.hlsl @@ -6,7 +6,7 @@ // RUN: spirv-pc-vulkan-library %s -emit-llvm -disable-llvm-passes -o - | \ // RUN: FileCheck %s --check-prefixes=CHECK,SPVCHECK -// Test basic lowering of HLSL InterlockedXor to `atomicrmw or monotonic`. +// Test basic lowering of HLSL InterlockedXor to `atomicrmw xor monotonic`. groupshared int gs_i32; groupshared uint gs_u32; @@ -14,45 +14,45 @@ groupshared int64_t gs_i64; groupshared uint64_t gs_u64; // CHECK-LABEL: define {{(dso_local |hidden |internal |protected |spir_func )*}}void @{{.*}}test_int_2arg -// DXCHECK: atomicrmw xor ptr addrspace(3) {{.*}}@gs_i32{{.*}}, i32 %{{.*}} monotonic -// SPVCHECK: atomicrmw xor ptr addrspace(3) {{.*}}@gs_i32{{.*}}, i32 %{{.*}} monotonic +// DXCHECK: atomicrmw xor ptr addrspace(3) {{.*}}@gs_i32{{.*}}, i32 %{{.*}} syncscope("workgroup") monotonic +// SPVCHECK: atomicrmw xor ptr addrspace(3) {{.*}}@gs_i32{{.*}}, i32 %{{.*}} syncscope("workgroup") monotonic export void test_int_2arg(int v) { InterlockedXor(gs_i32, v); } // CHECK-LABEL: define {{(dso_local |hidden |internal |protected |spir_func )*}}void @{{.*}}test_uint_2arg -// DXCHECK: atomicrmw xor ptr addrspace(3) {{.*}}@gs_u32{{.*}}, i32 %{{.*}} monotonic -// SPVCHECK: atomicrmw xor ptr addrspace(3) {{.*}}@gs_u32{{.*}}, i32 %{{.*}} monotonic +// DXCHECK: atomicrmw xor ptr addrspace(3) {{.*}}@gs_u32{{.*}}, i32 %{{.*}} syncscope("workgroup") monotonic +// SPVCHECK: atomicrmw xor ptr addrspace(3) {{.*}}@gs_u32{{.*}}, i32 %{{.*}} syncscope("workgroup") monotonic export void test_uint_2arg(uint v) { InterlockedXor(gs_u32, v); } // CHECK-LABEL: define {{(dso_local |hidden |internal |protected |spir_func )*}}void @{{.*}}test_int_3arg -// DXCHECK: %[[R:.*]] = atomicrmw xor ptr addrspace(3) {{.*}}@gs_i32{{.*}}, i32 %{{.*}} monotonic -// SPVCHECK: %[[R:.*]] = atomicrmw xor ptr addrspace(3) {{.*}}@gs_i32{{.*}}, i32 %{{.*}} monotonic +// DXCHECK: %[[R:.*]] = atomicrmw xor ptr addrspace(3) {{.*}}@gs_i32{{.*}}, i32 %{{.*}} syncscope("workgroup") monotonic +// SPVCHECK: %[[R:.*]] = atomicrmw xor ptr addrspace(3) {{.*}}@gs_i32{{.*}}, i32 %{{.*}} syncscope("workgroup") monotonic // CHECK: store i32 %[[R]], ptr {{.*}} export void test_int_3arg(int v, out int orig) { InterlockedXor(gs_i32, v, orig); } // CHECK-LABEL: define {{(dso_local |hidden |internal |protected |spir_func )*}}void @{{.*}}test_uint_3arg -// DXCHECK: %[[R:.*]] = atomicrmw xor ptr addrspace(3) {{.*}}@gs_u32{{.*}}, i32 %{{.*}} monotonic -// SPVCHECK: %[[R:.*]] = atomicrmw xor ptr addrspace(3) {{.*}}@gs_u32{{.*}}, i32 %{{.*}} monotonic +// DXCHECK: %[[R:.*]] = atomicrmw xor ptr addrspace(3) {{.*}}@gs_u32{{.*}}, i32 %{{.*}} syncscope("workgroup") monotonic +// SPVCHECK: %[[R:.*]] = atomicrmw xor ptr addrspace(3) {{.*}}@gs_u32{{.*}}, i32 %{{.*}} syncscope("workgroup") monotonic // CHECK: store i32 %[[R]], ptr {{.*}} export void test_uint_3arg(uint v, out uint orig) { InterlockedXor(gs_u32, v, orig); } // CHECK-LABEL: define {{(dso_local |hidden |internal |protected |spir_func )*}}void @{{.*}}test_int64_2arg -// DXCHECK: atomicrmw xor ptr addrspace(3) {{.*}}@gs_i64{{.*}}, i64 %{{.*}} monotonic -// SPVCHECK: atomicrmw xor ptr addrspace(3) {{.*}}@gs_i64{{.*}}, i64 %{{.*}} monotonic +// DXCHECK: atomicrmw xor ptr addrspace(3) {{.*}}@gs_i64{{.*}}, i64 %{{.*}} syncscope("workgroup") monotonic +// SPVCHECK: atomicrmw xor ptr addrspace(3) {{.*}}@gs_i64{{.*}}, i64 %{{.*}} syncscope("workgroup") monotonic export void test_int64_2arg(int64_t v) { InterlockedXor(gs_i64, v); } // CHECK-LABEL: define {{(dso_local |hidden |internal |protected |spir_func )*}}void @{{.*}}test_uint64_3arg -// DXCHECK: %[[R:.*]] = atomicrmw xor ptr addrspace(3) {{.*}}@gs_u64{{.*}}, i64 %{{.*}} monotonic -// SPVCHECK: %[[R:.*]] = atomicrmw xor ptr addrspace(3) {{.*}}@gs_u64{{.*}}, i64 %{{.*}} monotonic +// DXCHECK: %[[R:.*]] = atomicrmw xor ptr addrspace(3) {{.*}}@gs_u64{{.*}}, i64 %{{.*}} syncscope("workgroup") monotonic +// SPVCHECK: %[[R:.*]] = atomicrmw xor ptr addrspace(3) {{.*}}@gs_u64{{.*}}, i64 %{{.*}} syncscope("workgroup") monotonic // CHECK: store i64 %[[R]], ptr {{.*}} export void test_uint64_3arg(uint64_t v, out uint64_t orig) { InterlockedXor(gs_u64, v, orig); diff --git a/clang/test/CodeGenHLSL/builtins/RWBuffer-Interlocked.hlsl b/clang/test/CodeGenHLSL/builtins/RWBuffer-Interlocked.hlsl index 4d7050ba3a43c..0ef2b86bc45a5 100644 --- a/clang/test/CodeGenHLSL/builtins/RWBuffer-Interlocked.hlsl +++ b/clang/test/CodeGenHLSL/builtins/RWBuffer-Interlocked.hlsl @@ -18,17 +18,17 @@ RWBuffer<int> Out : register(u0); // CHECK-LABEL: define void @main // DXCHECK: %[[PTR1:.*]] = call {{.*}} @llvm.dx.resource.getpointer.p0.tdx.TypedBuffer_i32_1_0_1t.i32(target("dx.TypedBuffer", i32, 1, 0, 1) %{{.*}}, i32 %{{.*}}) -// DXCHECK: atomicrmw add ptr %[[PTR1]], i32 1 monotonic +// DXCHECK: atomicrmw add ptr %[[PTR1]], i32 1 syncscope("device") monotonic // DXCHECK: %[[PTR2:.*]] = call {{.*}} @llvm.dx.resource.getpointer.p0.tdx.TypedBuffer_i32_1_0_1t.i32(target("dx.TypedBuffer", i32, 1, 0, 1) %{{.*}}, i32 %{{.*}}) -// DXCHECK: atomicrmw or ptr %[[PTR2]], i32 1 monotonic +// DXCHECK: atomicrmw or ptr %[[PTR2]], i32 1 syncscope("device") monotonic // DXCHECK: %[[PTR3:.*]] = call {{.*}} @llvm.dx.resource.getpointer.p0.tdx.TypedBuffer_i32_1_0_1t.i32(target("dx.TypedBuffer", i32, 1, 0, 1) %{{.*}}, i32 %{{.*}}) -// DXCHECK: atomicrmw xor ptr %[[PTR3]], i32 1 monotonic +// DXCHECK: atomicrmw xor ptr %[[PTR3]], i32 1 syncscope("device") monotonic // SPVCHECK: %[[PTR1:.*]] = call {{.*}} @llvm.spv.resource.getpointer.{{.*}}(target("spirv.{{Image|SignedImage}}", i32, {{.*}}) %{{.*}}, i32 %{{.*}}) -// SPVCHECK: atomicrmw add ptr addrspace(11) %[[PTR1]], i32 1 monotonic +// SPVCHECK: atomicrmw add ptr addrspace(11) %[[PTR1]], i32 1 syncscope("device") monotonic // SPVCHECK: %[[PTR2:.*]] = call {{.*}} @llvm.spv.resource.getpointer.{{.*}}(target("spirv.{{Image|SignedImage}}", i32, {{.*}}) %{{.*}}, i32 %{{.*}}) -// SPVCHECK: atomicrmw or ptr addrspace(11) %[[PTR2]], i32 1 monotonic +// SPVCHECK: atomicrmw or ptr addrspace(11) %[[PTR2]], i32 1 syncscope("device") monotonic // SPVCHECK: %[[PTR3:.*]] = call {{.*}} @llvm.spv.resource.getpointer.{{.*}}(target("spirv.{{Image|SignedImage}}", i32, {{.*}}) %{{.*}}, i32 %{{.*}}) -// SPVCHECK: atomicrmw xor ptr addrspace(11) %[[PTR3]], i32 1 monotonic +// SPVCHECK: atomicrmw xor ptr addrspace(11) %[[PTR3]], i32 1 syncscope("device") monotonic [shader("compute")] [numthreads(1,1,1)] void main(uint3 id : SV_DispatchThreadID) { diff --git a/clang/test/CodeGenHLSL/builtins/RWByteAddressBuffer-InterlockedAdd.hlsl b/clang/test/CodeGenHLSL/builtins/RWByteAddressBuffer-InterlockedAdd.hlsl index 576a1f0b70b95..5342c0a7c93f7 100644 --- a/clang/test/CodeGenHLSL/builtins/RWByteAddressBuffer-InterlockedAdd.hlsl +++ b/clang/test/CodeGenHLSL/builtins/RWByteAddressBuffer-InterlockedAdd.hlsl @@ -16,10 +16,10 @@ RWByteAddressBuffer BAB : register(u0); // CHECK-LABEL: define {{(dso_local |hidden |internal |protected |spir_func )*}}void @{{.*}}test_bab_int_2arg // DXCHECK: %[[HANDLE:.*]] = load target("dx.RawBuffer", i8, 1, 0), ptr {{.*}} // DXCHECK: %[[PTR:.*]] = call ptr @llvm.dx.resource.getpointer.p0.tdx.RawBuffer_i8_1_0t.i32(target("dx.RawBuffer", i8, 1, 0) %[[HANDLE]], i32 %{{.*}}) -// DXCHECK: atomicrmw add ptr %[[PTR]], i32 %{{.*}} monotonic +// DXCHECK: atomicrmw add ptr %[[PTR]], i32 %{{.*}} syncscope("device") monotonic // SPVCHECK: %[[HANDLE:.*]] = load target("spirv.VulkanBuffer", [0 x i8], 12, 1), ptr {{.*}} // SPVCHECK: %[[PTR:.*]] = call ptr addrspace(11) @llvm.spv.resource.getpointer.p11.tspirv.VulkanBuffer_a0i8_12_1t.i32(target("spirv.VulkanBuffer", [0 x i8], 12, 1) %[[HANDLE]], i32 %{{.*}}) -// SPVCHECK: atomicrmw add ptr addrspace(11) %[[PTR]], i32 %{{.*}} monotonic +// SPVCHECK: atomicrmw add ptr addrspace(11) %[[PTR]], i32 %{{.*}} syncscope("device") monotonic export void test_bab_int_2arg(uint off, int v) { BAB.InterlockedAdd(off, v); } @@ -27,11 +27,11 @@ export void test_bab_int_2arg(uint off, int v) { // CHECK-LABEL: define {{(dso_local |hidden |internal |protected |spir_func )*}}void @{{.*}}test_bab_uint_3arg // DXCHECK: %[[HANDLE:.*]] = load target("dx.RawBuffer", i8, 1, 0), ptr {{.*}} // DXCHECK: %[[PTR:.*]] = call ptr @llvm.dx.resource.getpointer.p0.tdx.RawBuffer_i8_1_0t.i32(target("dx.RawBuffer", i8, 1, 0) %[[HANDLE]], i32 %{{.*}}) -// DXCHECK: %[[R:.*]] = atomicrmw add ptr %[[PTR]], i32 %{{.*}} monotonic +// DXCHECK: %[[R:.*]] = atomicrmw add ptr %[[PTR]], i32 %{{.*}} syncscope("device") monotonic // DXCHECK: store i32 %[[R]], ptr {{.*}} // SPVCHECK: %[[HANDLE:.*]] = load target("spirv.VulkanBuffer", [0 x i8], 12, 1), ptr {{.*}} // SPVCHECK: %[[PTR:.*]] = call ptr addrspace(11) @llvm.spv.resource.getpointer.p11.tspirv.VulkanBuffer_a0i8_12_1t.i32(target("spirv.VulkanBuffer", [0 x i8], 12, 1) %[[HANDLE]], i32 %{{.*}}) -// SPVCHECK: %[[R:.*]] = atomicrmw add ptr addrspace(11) %[[PTR]], i32 %{{.*}} monotonic +// SPVCHECK: %[[R:.*]] = atomicrmw add ptr addrspace(11) %[[PTR]], i32 %{{.*}} syncscope("device") monotonic // SPVCHECK: store i32 %[[R]], ptr {{.*}} export void test_bab_uint_3arg(uint off, uint v, out uint orig) { BAB.InterlockedAdd(off, v, orig); @@ -40,10 +40,10 @@ export void test_bab_uint_3arg(uint off, uint v, out uint orig) { // CHECK-LABEL: define {{(dso_local |hidden |internal |protected |spir_func )*}}void @{{.*}}test_bab_int64_2arg // DXCHECK: %[[HANDLE:.*]] = load target("dx.RawBuffer", i8, 1, 0), ptr {{.*}} // DXCHECK: %[[PTR:.*]] = call ptr @llvm.dx.resource.getpointer.p0.tdx.RawBuffer_i8_1_0t.i32(target("dx.RawBuffer", i8, 1, 0) %[[HANDLE]], i32 %{{.*}}) -// DXCHECK: atomicrmw add ptr %[[PTR]], i64 %{{.*}} monotonic +// DXCHECK: atomicrmw add ptr %[[PTR]], i64 %{{.*}} syncscope("device") monotonic // SPVCHECK: %[[HANDLE:.*]] = load target("spirv.VulkanBuffer", [0 x i8], 12, 1), ptr {{.*}} // SPVCHECK: %[[PTR:.*]] = call ptr addrspace(11) @llvm.spv.resource.getpointer.p11.tspirv.VulkanBuffer_a0i8_12_1t.i32(target("spirv.VulkanBuffer", [0 x i8], 12, 1) %[[HANDLE]], i32 %{{.*}}) -// SPVCHECK: atomicrmw add ptr addrspace(11) %[[PTR]], i64 %{{.*}} monotonic +// SPVCHECK: atomicrmw add ptr addrspace(11) %[[PTR]], i64 %{{.*}} syncscope("device") monotonic export void test_bab_int64_2arg(uint off, int64_t v) { BAB.InterlockedAdd64(off, v); } @@ -51,11 +51,11 @@ export void test_bab_int64_2arg(uint off, int64_t v) { // CHECK-LABEL: define {{(dso_local |hidden |internal |protected |spir_func )*}}void @{{.*}}test_bab_uint64_3arg // DXCHECK: %[[HANDLE:.*]] = load target("dx.RawBuffer", i8, 1, 0), ptr {{.*}} // DXCHECK: %[[PTR:.*]] = call ptr @llvm.dx.resource.getpointer.p0.tdx.RawBuffer_i8_1_0t.i32(target("dx.RawBuffer", i8, 1, 0) %[[HANDLE]], i32 %{{.*}}) -// DXCHECK: %[[R:.*]] = atomicrmw add ptr %[[PTR]], i64 %{{.*}} monotonic +// DXCHECK: %[[R:.*]] = atomicrmw add ptr %[[PTR]], i64 %{{.*}} syncscope("device") monotonic // DXCHECK: store i64 %[[R]], ptr {{.*}} // SPVCHECK: %[[HANDLE:.*]] = load target("spirv.VulkanBuffer", [0 x i8], 12, 1), ptr {{.*}} // SPVCHECK: %[[PTR:.*]] = call ptr addrspace(11) @llvm.spv.resource.getpointer.p11.tspirv.VulkanBuffer_a0i8_12_1t.i32(target("spirv.VulkanBuffer", [0 x i8], 12, 1) %[[HANDLE]], i32 %{{.*}}) -// SPVCHECK: %[[R:.*]] = atomicrmw add ptr addrspace(11) %[[PTR]], i64 %{{.*}} monotonic +// SPVCHECK: %[[R:.*]] = atomicrmw add ptr addrspace(11) %[[PTR]], i64 %{{.*}} syncscope("device") monotonic // SPVCHECK: store i64 %[[R]], ptr {{.*}} export void test_bab_uint64_3arg(uint off, uint64_t v, out uint64_t orig) { BAB.InterlockedAdd64(off, v, orig); diff --git a/clang/test/CodeGenHLSL/builtins/RWByteAddressBuffer-InterlockedOr.hlsl b/clang/test/CodeGenHLSL/builtins/RWByteAddressBuffer-InterlockedOr.hlsl index 874474d043d5e..b9c6bbb4dcdd5 100644 --- a/clang/test/CodeGenHLSL/builtins/RWByteAddressBuffer-InterlockedOr.hlsl +++ b/clang/test/CodeGenHLSL/builtins/RWByteAddressBuffer-InterlockedOr.hlsl @@ -16,10 +16,10 @@ RWByteAddressBuffer BAB : register(u0); // CHECK-LABEL: define {{(dso_local |hidden |internal |protected |spir_func )*}}void @{{.*}}test_bab_int_2arg // DXCHECK: %[[HANDLE:.*]] = load target("dx.RawBuffer", i8, 1, 0), ptr {{.*}} // DXCHECK: %[[PTR:.*]] = call ptr @llvm.dx.resource.getpointer.p0.tdx.RawBuffer_i8_1_0t.i32(target("dx.RawBuffer", i8, 1, 0) %[[HANDLE]], i32 %{{.*}}) -// DXCHECK: atomicrmw or ptr %[[PTR]], i32 %{{.*}} monotonic +// DXCHECK: atomicrmw or ptr %[[PTR]], i32 %{{.*}} syncscope("device") monotonic // SPVCHECK: %[[HANDLE:.*]] = load target("spirv.VulkanBuffer", [0 x i8], 12, 1), ptr {{.*}} // SPVCHECK: %[[PTR:.*]] = call ptr addrspace(11) @llvm.spv.resource.getpointer.p11.tspirv.VulkanBuffer_a0i8_12_1t.i32(target("spirv.VulkanBuffer", [0 x i8], 12, 1) %[[HANDLE]], i32 %{{.*}}) -// SPVCHECK: atomicrmw or ptr addrspace(11) %[[PTR]], i32 %{{.*}} monotonic +// SPVCHECK: atomicrmw or ptr addrspace(11) %[[PTR]], i32 %{{.*}} syncscope("device") monotonic export void test_bab_int_2arg(uint off, int v) { BAB.InterlockedOr(off, v); } @@ -27,11 +27,11 @@ export void test_bab_int_2arg(uint off, int v) { // CHECK-LABEL: define {{(dso_local |hidden |internal |protected |spir_func )*}}void @{{.*}}test_bab_uint_3arg // DXCHECK: %[[HANDLE:.*]] = load target("dx.RawBuffer", i8, 1, 0), ptr {{.*}} // DXCHECK: %[[PTR:.*]] = call ptr @llvm.dx.resource.getpointer.p0.tdx.RawBuffer_i8_1_0t.i32(target("dx.RawBuffer", i8, 1, 0) %[[HANDLE]], i32 %{{.*}}) -// DXCHECK: %[[R:.*]] = atomicrmw or ptr %[[PTR]], i32 %{{.*}} monotonic +// DXCHECK: %[[R:.*]] = atomicrmw or ptr %[[PTR]], i32 %{{.*}} syncscope("device") monotonic // DXCHECK: store i32 %[[R]], ptr {{.*}} // SPVCHECK: %[[HANDLE:.*]] = load target("spirv.VulkanBuffer", [0 x i8], 12, 1), ptr {{.*}} // SPVCHECK: %[[PTR:.*]] = call ptr addrspace(11) @llvm.spv.resource.getpointer.p11.tspirv.VulkanBuffer_a0i8_12_1t.i32(target("spirv.VulkanBuffer", [0 x i8], 12, 1) %[[HANDLE]], i32 %{{.*}}) -// SPVCHECK: %[[R:.*]] = atomicrmw or ptr addrspace(11) %[[PTR]], i32 %{{.*}} monotonic +// SPVCHECK: %[[R:.*]] = atomicrmw or ptr addrspace(11) %[[PTR]], i32 %{{.*}} syncscope("device") monotonic // SPVCHECK: store i32 %[[R]], ptr {{.*}} export void test_bab_uint_3arg(uint off, uint v, out uint orig) { BAB.InterlockedOr(off, v, orig); @@ -40,10 +40,10 @@ export void test_bab_uint_3arg(uint off, uint v, out uint orig) { // CHECK-LABEL: define {{(dso_local |hidden |internal |protected |spir_func )*}}void @{{.*}}test_bab_int64_2arg // DXCHECK: %[[HANDLE:.*]] = load target("dx.RawBuffer", i8, 1, 0), ptr {{.*}} // DXCHECK: %[[PTR:.*]] = call ptr @llvm.dx.resource.getpointer.p0.tdx.RawBuffer_i8_1_0t.i32(target("dx.RawBuffer", i8, 1, 0) %[[HANDLE]], i32 %{{.*}}) -// DXCHECK: atomicrmw or ptr %[[PTR]], i64 %{{.*}} monotonic +// DXCHECK: atomicrmw or ptr %[[PTR]], i64 %{{.*}} syncscope("device") monotonic // SPVCHECK: %[[HANDLE:.*]] = load target("spirv.VulkanBuffer", [0 x i8], 12, 1), ptr {{.*}} // SPVCHECK: %[[PTR:.*]] = call ptr addrspace(11) @llvm.spv.resource.getpointer.p11.tspirv.VulkanBuffer_a0i8_12_1t.i32(target("spirv.VulkanBuffer", [0 x i8], 12, 1) %[[HANDLE]], i32 %{{.*}}) -// SPVCHECK: atomicrmw or ptr addrspace(11) %[[PTR]], i64 %{{.*}} monotonic +// SPVCHECK: atomicrmw or ptr addrspace(11) %[[PTR]], i64 %{{.*}} syncscope("device") monotonic export void test_bab_int64_2arg(uint off, int64_t v) { BAB.InterlockedOr64(off, v); } @@ -51,11 +51,11 @@ export void test_bab_int64_2arg(uint off, int64_t v) { // CHECK-LABEL: define {{(dso_local |hidden |internal |protected |spir_func )*}}void @{{.*}}test_bab_uint64_3arg // DXCHECK: %[[HANDLE:.*]] = load target("dx.RawBuffer", i8, 1, 0), ptr {{.*}} // DXCHECK: %[[PTR:.*]] = call ptr @llvm.dx.resource.getpointer.p0.tdx.RawBuffer_i8_1_0t.i32(target("dx.RawBuffer", i8, 1, 0) %[[HANDLE]], i32 %{{.*}}) -// DXCHECK: %[[R:.*]] = atomicrmw or ptr %[[PTR]], i64 %{{.*}} monotonic +// DXCHECK: %[[R:.*]] = atomicrmw or ptr %[[PTR]], i64 %{{.*}} syncscope("device") monotonic // DXCHECK: store i64 %[[R]], ptr {{.*}} // SPVCHECK: %[[HANDLE:.*]] = load target("spirv.VulkanBuffer", [0 x i8], 12, 1), ptr {{.*}} // SPVCHECK: %[[PTR:.*]] = call ptr addrspace(11) @llvm.spv.resource.getpointer.p11.tspirv.VulkanBuffer_a0i8_12_1t.i32(target("spirv.VulkanBuffer", [0 x i8], 12, 1) %[[HANDLE]], i32 %{{.*}}) -// SPVCHECK: %[[R:.*]] = atomicrmw or ptr addrspace(11) %[[PTR]], i64 %{{.*}} monotonic +// SPVCHECK: %[[R:.*]] = atomicrmw or ptr addrspace(11) %[[PTR]], i64 %{{.*}} syncscope("device") monotonic // SPVCHECK: store i64 %[[R]], ptr {{.*}} export void test_bab_uint64_3arg(uint off, uint64_t v, out uint64_t orig) { BAB.InterlockedOr64(off, v, orig); diff --git a/clang/test/CodeGenHLSL/builtins/RWByteAddressBuffer-InterlockedXor.hlsl b/clang/test/CodeGenHLSL/builtins/RWByteAddressBuffer-InterlockedXor.hlsl index f4f788b7968a5..41cd077442d8e 100644 --- a/clang/test/CodeGenHLSL/builtins/RWByteAddressBuffer-InterlockedXor.hlsl +++ b/clang/test/CodeGenHLSL/builtins/RWByteAddressBuffer-InterlockedXor.hlsl @@ -16,10 +16,10 @@ RWByteAddressBuffer BAB : register(u0); // CHECK-LABEL: define {{(dso_local |hidden |internal |protected |spir_func )*}}void @{{.*}}test_bab_int_2arg // DXCHECK: %[[HANDLE:.*]] = load target("dx.RawBuffer", i8, 1, 0), ptr {{.*}} // DXCHECK: %[[PTR:.*]] = call ptr @llvm.dx.resource.getpointer.p0.tdx.RawBuffer_i8_1_0t.i32(target("dx.RawBuffer", i8, 1, 0) %[[HANDLE]], i32 %{{.*}}) -// DXCHECK: atomicrmw xor ptr %[[PTR]], i32 %{{.*}} monotonic +// DXCHECK: atomicrmw xor ptr %[[PTR]], i32 %{{.*}} syncscope("device") monotonic // SPVCHECK: %[[HANDLE:.*]] = load target("spirv.VulkanBuffer", [0 x i8], 12, 1), ptr {{.*}} // SPVCHECK: %[[PTR:.*]] = call ptr addrspace(11) @llvm.spv.resource.getpointer.p11.tspirv.VulkanBuffer_a0i8_12_1t.i32(target("spirv.VulkanBuffer", [0 x i8], 12, 1) %[[HANDLE]], i32 %{{.*}}) -// SPVCHECK: atomicrmw xor ptr addrspace(11) %[[PTR]], i32 %{{.*}} monotonic +// SPVCHECK: atomicrmw xor ptr addrspace(11) %[[PTR]], i32 %{{.*}} syncscope("device") monotonic export void test_bab_int_2arg(uint off, int v) { BAB.InterlockedXor(off, v); } @@ -27,11 +27,11 @@ export void test_bab_int_2arg(uint off, int v) { // CHECK-LABEL: define {{(dso_local |hidden |internal |protected |spir_func )*}}void @{{.*}}test_bab_uint_3arg // DXCHECK: %[[HANDLE:.*]] = load target("dx.RawBuffer", i8, 1, 0), ptr {{.*}} // DXCHECK: %[[PTR:.*]] = call ptr @llvm.dx.resource.getpointer.p0.tdx.RawBuffer_i8_1_0t.i32(target("dx.RawBuffer", i8, 1, 0) %[[HANDLE]], i32 %{{.*}}) -// DXCHECK: %[[R:.*]] = atomicrmw xor ptr %[[PTR]], i32 %{{.*}} monotonic +// DXCHECK: %[[R:.*]] = atomicrmw xor ptr %[[PTR]], i32 %{{.*}} syncscope("device") monotonic // DXCHECK: store i32 %[[R]], ptr {{.*}} // SPVCHECK: %[[HANDLE:.*]] = load target("spirv.VulkanBuffer", [0 x i8], 12, 1), ptr {{.*}} // SPVCHECK: %[[PTR:.*]] = call ptr addrspace(11) @llvm.spv.resource.getpointer.p11.tspirv.VulkanBuffer_a0i8_12_1t.i32(target("spirv.VulkanBuffer", [0 x i8], 12, 1) %[[HANDLE]], i32 %{{.*}}) -// SPVCHECK: %[[R:.*]] = atomicrmw xor ptr addrspace(11) %[[PTR]], i32 %{{.*}} monotonic +// SPVCHECK: %[[R:.*]] = atomicrmw xor ptr addrspace(11) %[[PTR]], i32 %{{.*}} syncscope("device") monotonic // SPVCHECK: store i32 %[[R]], ptr {{.*}} export void test_bab_uint_3arg(uint off, uint v, out uint orig) { BAB.InterlockedXor(off, v, orig); @@ -40,10 +40,10 @@ export void test_bab_uint_3arg(uint off, uint v, out uint orig) { // CHECK-LABEL: define {{(dso_local |hidden |internal |protected |spir_func )*}}void @{{.*}}test_bab_int64_2arg // DXCHECK: %[[HANDLE:.*]] = load target("dx.RawBuffer", i8, 1, 0), ptr {{.*}} // DXCHECK: %[[PTR:.*]] = call ptr @llvm.dx.resource.getpointer.p0.tdx.RawBuffer_i8_1_0t.i32(target("dx.RawBuffer", i8, 1, 0) %[[HANDLE]], i32 %{{.*}}) -// DXCHECK: atomicrmw xor ptr %[[PTR]], i64 %{{.*}} monotonic +// DXCHECK: atomicrmw xor ptr %[[PTR]], i64 %{{.*}} syncscope("device") monotonic // SPVCHECK: %[[HANDLE:.*]] = load target("spirv.VulkanBuffer", [0 x i8], 12, 1), ptr {{.*}} // SPVCHECK: %[[PTR:.*]] = call ptr addrspace(11) @llvm.spv.resource.getpointer.p11.tspirv.VulkanBuffer_a0i8_12_1t.i32(target("spirv.VulkanBuffer", [0 x i8], 12, 1) %[[HANDLE]], i32 %{{.*}}) -// SPVCHECK: atomicrmw xor ptr addrspace(11) %[[PTR]], i64 %{{.*}} monotonic +// SPVCHECK: atomicrmw xor ptr addrspace(11) %[[PTR]], i64 %{{.*}} syncscope("device") monotonic export void test_bab_int64_2arg(uint off, int64_t v) { BAB.InterlockedXor64(off, v); } @@ -51,11 +51,11 @@ export void test_bab_int64_2arg(uint off, int64_t v) { // CHECK-LABEL: define {{(dso_local |hidden |internal |protected |spir_func )*}}void @{{.*}}test_bab_uint64_3arg // DXCHECK: %[[HANDLE:.*]] = load target("dx.RawBuffer", i8, 1, 0), ptr {{.*}} // DXCHECK: %[[PTR:.*]] = call ptr @llvm.dx.resource.getpointer.p0.tdx.RawBuffer_i8_1_0t.i32(target("dx.RawBuffer", i8, 1, 0) %[[HANDLE]], i32 %{{.*}}) -// DXCHECK: %[[R:.*]] = atomicrmw xor ptr %[[PTR]], i64 %{{.*}} monotonic +// DXCHECK: %[[R:.*]] = atomicrmw xor ptr %[[PTR]], i64 %{{.*}} syncscope("device") monotonic // DXCHECK: store i64 %[[R]], ptr {{.*}} // SPVCHECK: %[[HANDLE:.*]] = load target("spirv.VulkanBuffer", [0 x i8], 12, 1), ptr {{.*}} // SPVCHECK: %[[PTR:.*]] = call ptr addrspace(11) @llvm.spv.resource.getpointer.p11.tspirv.VulkanBuffer_a0i8_12_1t.i32(target("spirv.VulkanBuffer", [0 x i8], 12, 1) %[[HANDLE]], i32 %{{.*}}) -// SPVCHECK: %[[R:.*]] = atomicrmw xor ptr addrspace(11) %[[PTR]], i64 %{{.*}} monotonic +// SPVCHECK: %[[R:.*]] = atomicrmw xor ptr addrspace(11) %[[PTR]], i64 %{{.*}} syncscope("device") monotonic // SPVCHECK: store i64 %[[R]], ptr {{.*}} export void test_bab_uint64_3arg(uint off, uint64_t v, out uint64_t orig) { BAB.InterlockedXor64(off, v, orig); diff --git a/clang/test/CodeGenHLSL/builtins/RasterizerOrderedByteAddressBuffer-InterlockedAdd.hlsl b/clang/test/CodeGenHLSL/builtins/RasterizerOrderedByteAddressBuffer-InterlockedAdd.hlsl index 377269ac9beda..0b910728232dd 100644 --- a/clang/test/CodeGenHLSL/builtins/RasterizerOrderedByteAddressBuffer-InterlockedAdd.hlsl +++ b/clang/test/CodeGenHLSL/builtins/RasterizerOrderedByteAddressBuffer-InterlockedAdd.hlsl @@ -13,7 +13,7 @@ RasterizerOrderedByteAddressBuffer ROVB : register(u1); // CHECK-LABEL: define void @{{.*}}test_rovb_int_2arg // DXCHECK: %[[HANDLE:.*]] = load target("dx.RawBuffer", i8, 1, 1), ptr {{.*}} // DXCHECK: %[[PTR:.*]] = call ptr @llvm.dx.resource.getpointer.p0.tdx.RawBuffer_i8_1_1t.i32(target("dx.RawBuffer", i8, 1, 1) %[[HANDLE]], i32 %{{.*}}) -// DXCHECK: atomicrmw add ptr %[[PTR]], i32 %{{.*}} monotonic +// DXCHECK: atomicrmw add ptr %[[PTR]], i32 %{{.*}} syncscope("device") monotonic export void test_rovb_int_2arg(uint off, int v) { ROVB.InterlockedAdd(off, v); } @@ -21,7 +21,7 @@ export void test_rovb_int_2arg(uint off, int v) { // CHECK-LABEL: define void @{{.*}}test_rovb_uint_3arg // DXCHECK: %[[HANDLE:.*]] = load target("dx.RawBuffer", i8, 1, 1), ptr {{.*}} // DXCHECK: %[[PTR:.*]] = call ptr @llvm.dx.resource.getpointer.p0.tdx.RawBuffer_i8_1_1t.i32(target("dx.RawBuffer", i8, 1, 1) %[[HANDLE]], i32 %{{.*}}) -// DXCHECK: %[[R:.*]] = atomicrmw add ptr %[[PTR]], i32 %{{.*}} monotonic +// DXCHECK: %[[R:.*]] = atomicrmw add ptr %[[PTR]], i32 %{{.*}} syncscope("device") monotonic // DXCHECK: store i32 %[[R]], ptr {{.*}} export void test_rovb_uint_3arg(uint off, uint v, out uint orig) { ROVB.InterlockedAdd(off, v, orig); @@ -30,7 +30,7 @@ export void test_rovb_uint_3arg(uint off, uint v, out uint orig) { // CHECK-LABEL: define void @{{.*}}test_rovb_int64_2arg // DXCHECK: %[[HANDLE:.*]] = load target("dx.RawBuffer", i8, 1, 1), ptr {{.*}} // DXCHECK: %[[PTR:.*]] = call ptr @llvm.dx.resource.getpointer.p0.tdx.RawBuffer_i8_1_1t.i32(target("dx.RawBuffer", i8, 1, 1) %[[HANDLE]], i32 %{{.*}}) -// DXCHECK: atomicrmw add ptr %[[PTR]], i64 %{{.*}} monotonic +// DXCHECK: atomicrmw add ptr %[[PTR]], i64 %{{.*}} syncscope("device") monotonic export void test_rovb_int64_2arg(uint off, int64_t v) { ROVB.InterlockedAdd64(off, v); } @@ -38,7 +38,7 @@ export void test_rovb_int64_2arg(uint off, int64_t v) { // CHECK-LABEL: define void @{{.*}}test_rovb_uint64_3arg // DXCHECK: %[[HANDLE:.*]] = load target("dx.RawBuffer", i8, 1, 1), ptr {{.*}} // DXCHECK: %[[PTR:.*]] = call ptr @llvm.dx.resource.getpointer.p0.tdx.RawBuffer_i8_1_1t.i32(target("dx.RawBuffer", i8, 1, 1) %[[HANDLE]], i32 %{{.*}}) -// DXCHECK: %[[R:.*]] = atomicrmw add ptr %[[PTR]], i64 %{{.*}} monotonic +// DXCHECK: %[[R:.*]] = atomicrmw add ptr %[[PTR]], i64 %{{.*}} syncscope("device") monotonic // DXCHECK: store i64 %[[R]], ptr {{.*}} export void test_rovb_uint64_3arg(uint off, uint64_t v, out uint64_t orig) { ROVB.InterlockedAdd64(off, v, orig); diff --git a/clang/test/CodeGenHLSL/builtins/RasterizerOrderedByteAddressBuffer-InterlockedOr.hlsl b/clang/test/CodeGenHLSL/builtins/RasterizerOrderedByteAddressBuffer-InterlockedOr.hlsl index 4c8f48880bdf7..81991662a014d 100644 --- a/clang/test/CodeGenHLSL/builtins/RasterizerOrderedByteAddressBuffer-InterlockedOr.hlsl +++ b/clang/test/CodeGenHLSL/builtins/RasterizerOrderedByteAddressBuffer-InterlockedOr.hlsl @@ -13,7 +13,7 @@ RasterizerOrderedByteAddressBuffer ROVB : register(u1); // CHECK-LABEL: define void @{{.*}}test_rovb_int_2arg // DXCHECK: %[[HANDLE:.*]] = load target("dx.RawBuffer", i8, 1, 1), ptr {{.*}} // DXCHECK: %[[PTR:.*]] = call ptr @llvm.dx.resource.getpointer.p0.tdx.RawBuffer_i8_1_1t.i32(target("dx.RawBuffer", i8, 1, 1) %[[HANDLE]], i32 %{{.*}}) -// DXCHECK: atomicrmw or ptr %[[PTR]], i32 %{{.*}} monotonic +// DXCHECK: atomicrmw or ptr %[[PTR]], i32 %{{.*}} syncscope("device") monotonic export void test_rovb_int_2arg(uint off, int v) { ROVB.InterlockedOr(off, v); } @@ -21,7 +21,7 @@ export void test_rovb_int_2arg(uint off, int v) { // CHECK-LABEL: define void @{{.*}}test_rovb_uint_3arg // DXCHECK: %[[HANDLE:.*]] = load target("dx.RawBuffer", i8, 1, 1), ptr {{.*}} // DXCHECK: %[[PTR:.*]] = call ptr @llvm.dx.resource.getpointer.p0.tdx.RawBuffer_i8_1_1t.i32(target("dx.RawBuffer", i8, 1, 1) %[[HANDLE]], i32 %{{.*}}) -// DXCHECK: %[[R:.*]] = atomicrmw or ptr %[[PTR]], i32 %{{.*}} monotonic +// DXCHECK: %[[R:.*]] = atomicrmw or ptr %[[PTR]], i32 %{{.*}} syncscope("device") monotonic // DXCHECK: store i32 %[[R]], ptr {{.*}} export void test_rovb_uint_3arg(uint off, uint v, out uint orig) { ROVB.InterlockedOr(off, v, orig); @@ -30,7 +30,7 @@ export void test_rovb_uint_3arg(uint off, uint v, out uint orig) { // CHECK-LABEL: define void @{{.*}}test_rovb_int64_2arg // DXCHECK: %[[HANDLE:.*]] = load target("dx.RawBuffer", i8, 1, 1), ptr {{.*}} // DXCHECK: %[[PTR:.*]] = call ptr @llvm.dx.resource.getpointer.p0.tdx.RawBuffer_i8_1_1t.i32(target("dx.RawBuffer", i8, 1, 1) %[[HANDLE]], i32 %{{.*}}) -// DXCHECK: atomicrmw or ptr %[[PTR]], i64 %{{.*}} monotonic +// DXCHECK: atomicrmw or ptr %[[PTR]], i64 %{{.*}} syncscope("device") monotonic export void test_rovb_int64_2arg(uint off, int64_t v) { ROVB.InterlockedOr64(off, v); } @@ -38,7 +38,7 @@ export void test_rovb_int64_2arg(uint off, int64_t v) { // CHECK-LABEL: define void @{{.*}}test_rovb_uint64_3arg // DXCHECK: %[[HANDLE:.*]] = load target("dx.RawBuffer", i8, 1, 1), ptr {{.*}} // DXCHECK: %[[PTR:.*]] = call ptr @llvm.dx.resource.getpointer.p0.tdx.RawBuffer_i8_1_1t.i32(target("dx.RawBuffer", i8, 1, 1) %[[HANDLE]], i32 %{{.*}}) -// DXCHECK: %[[R:.*]] = atomicrmw or ptr %[[PTR]], i64 %{{.*}} monotonic +// DXCHECK: %[[R:.*]] = atomicrmw or ptr %[[PTR]], i64 %{{.*}} syncscope("device") monotonic // DXCHECK: store i64 %[[R]], ptr {{.*}} export void test_rovb_uint64_3arg(uint off, uint64_t v, out uint64_t orig) { ROVB.InterlockedOr64(off, v, orig); diff --git a/clang/test/CodeGenHLSL/builtins/RasterizerOrderedByteAddressBuffer-InterlockedXor.hlsl b/clang/test/CodeGenHLSL/builtins/RasterizerOrderedByteAddressBuffer-InterlockedXor.hlsl index b8dfa4f81ee73..4433331ea49ea 100644 --- a/clang/test/CodeGenHLSL/builtins/RasterizerOrderedByteAddressBuffer-InterlockedXor.hlsl +++ b/clang/test/CodeGenHLSL/builtins/RasterizerOrderedByteAddressBuffer-InterlockedXor.hlsl @@ -13,7 +13,7 @@ RasterizerOrderedByteAddressBuffer ROVB : register(u1); // CHECK-LABEL: define void @{{.*}}test_rovb_int_2arg // DXCHECK: %[[HANDLE:.*]] = load target("dx.RawBuffer", i8, 1, 1), ptr {{.*}} // DXCHECK: %[[PTR:.*]] = call ptr @llvm.dx.resource.getpointer.p0.tdx.RawBuffer_i8_1_1t.i32(target("dx.RawBuffer", i8, 1, 1) %[[HANDLE]], i32 %{{.*}}) -// DXCHECK: atomicrmw xor ptr %[[PTR]], i32 %{{.*}} monotonic +// DXCHECK: atomicrmw xor ptr %[[PTR]], i32 %{{.*}} syncscope("device") monotonic export void test_rovb_int_2arg(uint off, int v) { ROVB.InterlockedXor(off, v); } @@ -21,7 +21,7 @@ export void test_rovb_int_2arg(uint off, int v) { // CHECK-LABEL: define void @{{.*}}test_rovb_uint_3arg // DXCHECK: %[[HANDLE:.*]] = load target("dx.RawBuffer", i8, 1, 1), ptr {{.*}} // DXCHECK: %[[PTR:.*]] = call ptr @llvm.dx.resource.getpointer.p0.tdx.RawBuffer_i8_1_1t.i32(target("dx.RawBuffer", i8, 1, 1) %[[HANDLE]], i32 %{{.*}}) -// DXCHECK: %[[R:.*]] = atomicrmw xor ptr %[[PTR]], i32 %{{.*}} monotonic +// DXCHECK: %[[R:.*]] = atomicrmw xor ptr %[[PTR]], i32 %{{.*}} syncscope("device") monotonic // DXCHECK: store i32 %[[R]], ptr {{.*}} export void test_rovb_uint_3arg(uint off, uint v, out uint orig) { ROVB.InterlockedXor(off, v, orig); @@ -30,7 +30,7 @@ export void test_rovb_uint_3arg(uint off, uint v, out uint orig) { // CHECK-LABEL: define void @{{.*}}test_rovb_int64_2arg // DXCHECK: %[[HANDLE:.*]] = load target("dx.RawBuffer", i8, 1, 1), ptr {{.*}} // DXCHECK: %[[PTR:.*]] = call ptr @llvm.dx.resource.getpointer.p0.tdx.RawBuffer_i8_1_1t.i32(target("dx.RawBuffer", i8, 1, 1) %[[HANDLE]], i32 %{{.*}}) -// DXCHECK: atomicrmw xor ptr %[[PTR]], i64 %{{.*}} monotonic +// DXCHECK: atomicrmw xor ptr %[[PTR]], i64 %{{.*}} syncscope("device") monotonic export void test_rovb_int64_2arg(uint off, int64_t v) { ROVB.InterlockedXor64(off, v); } @@ -38,7 +38,7 @@ export void test_rovb_int64_2arg(uint off, int64_t v) { // CHECK-LABEL: define void @{{.*}}test_rovb_uint64_3arg // DXCHECK: %[[HANDLE:.*]] = load target("dx.RawBuffer", i8, 1, 1), ptr {{.*}} // DXCHECK: %[[PTR:.*]] = call ptr @llvm.dx.resource.getpointer.p0.tdx.RawBuffer_i8_1_1t.i32(target("dx.RawBuffer", i8, 1, 1) %[[HANDLE]], i32 %{{.*}}) -// DXCHECK: %[[R:.*]] = atomicrmw xor ptr %[[PTR]], i64 %{{.*}} monotonic +// DXCHECK: %[[R:.*]] = atomicrmw xor ptr %[[PTR]], i64 %{{.*}} syncscope("device") monotonic // DXCHECK: store i64 %[[R]], ptr {{.*}} export void test_rovb_uint64_3arg(uint off, uint64_t v, out uint64_t orig) { ROVB.InterlockedXor64(off, v, orig); diff --git a/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp b/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp index 513b3149dd28f..921d668558068 100644 --- a/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp +++ b/llvm/lib/Target/SPIRV/SPIRVEmitIntrinsics.cpp @@ -2599,6 +2599,9 @@ SPIRVEmitIntrinsicsImpl::visitAtomicCmpXchgInst(AtomicCmpXchgInst &I) { unsigned AS = I.getPointerOperand()->getType()->getPointerAddressSpace(); uint32_t ScSem = static_cast<uint32_t>( getMemSemanticsForStorageClass(addressSpaceToStorageClass(AS, ST))); + // TODO: Like selectAtomicRMW, a relaxed shader atomic must not carry a + // storage-class bit (Vulkan rejects it). Drop ScSem for the success/failure + // semantics when the order is None and ST.isShader() once HLSL emits cmpxchg. Args.push_back(B.getInt32( static_cast<uint32_t>(getMemSemantics(I.getSuccessOrdering())) | ScSem)); Args.push_back(B.getInt32( diff --git a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp index c8f705e0251b6..e9eebc93ec00d 100644 --- a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp +++ b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp @@ -2102,6 +2102,9 @@ bool SPIRVInstructionSelector::selectAtomicLoad(Register ResVReg, uint32_t MemSem = static_cast<uint32_t>(getMemSemantics(AO)); if (MemOp.isVolatile() && STI.getTargetTriple().isVulkanOS()) MemSem |= static_cast<uint32_t>(SPIRV::MemorySemantics::Volatile); + // TODO: Like selectAtomicRMW, a relaxed shader atomic must not carry a + // storage-class bit (Vulkan rejects it). Drop StorageClass here when + // MemSem is None and STI.isShader() once such an atomic load is reachable. Register MemSemReg = buildI32Constant(MemSem | StorageClass, I); MachineIRBuilder MIRBuilder(I); @@ -2251,6 +2254,9 @@ bool SPIRVInstructionSelector::selectAtomicStore(MachineInstr &I) const { uint32_t MemSem = static_cast<uint32_t>(getMemSemantics(AO)); if (MemOp.isVolatile() && STI.getTargetTriple().isVulkanOS()) MemSem |= static_cast<uint32_t>(SPIRV::MemorySemantics::Volatile); + // TODO: Like selectAtomicRMW, a relaxed shader atomic must not carry a + // storage-class bit (Vulkan rejects it). Drop StorageClass here when + // MemSem is None and STI.isShader() once such an atomic store is reachable. Register MemSemReg = buildI32Constant(MemSem | StorageClass, I); MachineIRBuilder MIRBuilder(I); @@ -2524,7 +2530,13 @@ bool SPIRVInstructionSelector::selectAtomicRMW(Register ResVReg, uint32_t ScSem = static_cast<uint32_t>( getMemSemanticsForStorageClass(GR.getPointerStorageClass(Ptr))); AtomicOrdering AO = MemOp->getSuccessOrdering(); - uint32_t MemSem = static_cast<uint32_t>(getMemSemantics(AO)) | ScSem; + uint32_t OrderSem = static_cast<uint32_t>(getMemSemantics(AO)); + // Vulkan forbids a storage-class semantics bit (e.g. WorkgroupMemory) with a + // relaxed order, so a relaxed shader atomic must carry no storage-class bit. + if (STI.isShader() && + OrderSem == static_cast<uint32_t>(SPIRV::MemorySemantics::None)) + ScSem = 0; + uint32_t MemSem = OrderSem | ScSem; Register MemSemReg = buildI32Constant(MemSem, I); Register ValueReg = I.getOperand(2).getReg(); diff --git a/llvm/lib/Target/SPIRV/SPIRVUtils.cpp b/llvm/lib/Target/SPIRV/SPIRVUtils.cpp index 236da61192f1a..825bc147f92f5 100644 --- a/llvm/lib/Target/SPIRV/SPIRVUtils.cpp +++ b/llvm/lib/Target/SPIRV/SPIRVUtils.cpp @@ -1254,13 +1254,20 @@ getSpirvLinkageTypeFor(const SPIRVSubtarget &ST, const GlobalValue &GV) { return std::nullopt; if (GV.isDeclarationForLinker()) { - // Interface variables must not get Import linkage. if (const auto *GVar = dyn_cast<GlobalVariable>(&GV)) { auto SC = addressSpaceToStorageClass(GVar->getAddressSpace(), ST); + // Interface variables (shader-only storage classes) must never get + // Import linkage. if (SC == SPIRV::StorageClass::Input || SC == SPIRV::StorageClass::Output || SC == SPIRV::StorageClass::PushConstant) return std::nullopt; + // Shaders have no linker, so module-internal storage (e.g. HLSL + // groupshared) can't be imported; kernels (e.g. HIP LDS) legitimately + // can. + if (ST.isShader() && (SC == SPIRV::StorageClass::Workgroup || + SC == SPIRV::StorageClass::Private)) + return std::nullopt; } return SPIRV::LinkageType::Import; } diff --git a/llvm/test/CodeGen/SPIRV/atomicrmw-vulkan-relaxed-workgroup.ll b/llvm/test/CodeGen/SPIRV/atomicrmw-vulkan-relaxed-workgroup.ll new file mode 100644 index 0000000000000..b90175ca5b300 --- /dev/null +++ b/llvm/test/CodeGen/SPIRV/atomicrmw-vulkan-relaxed-workgroup.ll @@ -0,0 +1,26 @@ +; In a Vulkan (shader) environment a relaxed (monotonic) atomic must NOT set a +; storage-class memory-semantics bit (e.g. WorkgroupMemory): Vulkan requires +; such bits to be paired with a non-relaxed order (Acquire/Release/AcqRel), so +; pairing WorkgroupMemory with a relaxed order is rejected by spirv-val +; (VUID-StandaloneSpirv-MemorySemantics-10871). This is the shape emitted for +; HLSL Interlocked* on `groupshared` memory, which uses a "workgroup" syncscope +; and a relaxed order. The scope must still be Workgroup and the semantics None. + +; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv-unknown-vulkan1.3-compute %s -o - | FileCheck %s +; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-unknown-vulkan1.3-compute %s -o - -filetype=obj | spirv-val --target-env vulkan1.3 %} + +; CHECK-DAG: %[[#U32:]] = OpTypeInt 32 0 +; Workgroup scope = 2, None (relaxed) memory semantics = 0. +; CHECK-DAG: %[[#WG:]] = OpConstant %[[#U32]] 2 +; CHECK-DAG: %[[#NONE:]] = OpConstantNull %[[#U32]] + +@gs = external hidden addrspace(3) global i32, align 4 + +define void @main() #0 { +entry: + ; CHECK: OpAtomicOr %[[#U32]] %{{[0-9]+}} %[[#WG]] %[[#NONE]] %{{[0-9]+}} + %0 = atomicrmw or ptr addrspace(3) @gs, i32 1 syncscope("workgroup") monotonic + ret void +} + +attributes #0 = { "hlsl.numthreads"="1,1,1" "hlsl.shader"="compute" } diff --git a/llvm/test/CodeGen/SPIRV/linkage/groupshared-no-import-linkage.ll b/llvm/test/CodeGen/SPIRV/linkage/groupshared-no-import-linkage.ll new file mode 100644 index 0000000000000..9131843ff5d0b --- /dev/null +++ b/llvm/test/CodeGen/SPIRV/linkage/groupshared-no-import-linkage.ll @@ -0,0 +1,31 @@ +; HLSL `groupshared` variables are emitted by clang as external, hidden globals +; in the Workgroup storage class (a declaration, since shared memory has no +; initializer). getSpirvLinkageTypeFor must NOT give such module-internal +; storage-class declarations Import linkage: doing so decorates them with +; LinkageAttributes and forces OpCapability Linkage, which is illegal in a +; Vulkan shader. Verify no Linkage capability / decoration is emitted while the +; variable is still materialized as a Workgroup OpVariable. + +; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv-unknown-vulkan1.3-compute %s -o - | FileCheck %s --check-prefixes=CHECK,NOLINK +; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-unknown-vulkan1.3-compute %s -o - -filetype=obj | spirv-val --target-env vulkan1.3 %} + +; The groupshared variable is still emitted, in the Workgroup storage class. +; CHECK-DAG: OpName %[[#gs:]] "gs" +; CHECK-DAG: %[[#PtrWG:]] = OpTypePointer Workgroup %{{[0-9]+}} +; CHECK-DAG: %[[#gs]] = OpVariable %[[#PtrWG]] Workgroup + +; No Linkage capability and no LinkageAttributes decoration may be present. +; A NOT-only prefix scans the whole module (the capability and decoration +; sections precede the OpVariable definition in SPIR-V layout). +; NOLINK-NOT: OpCapability Linkage +; NOLINK-NOT: LinkageAttributes + +@gs = external hidden addrspace(3) global i32, align 4 + +define void @main() #0 { +entry: + store i32 0, ptr addrspace(3) @gs, align 4 + ret void +} + +attributes #0 = { "hlsl.numthreads"="1,1,1" "hlsl.shader"="compute" } >From f02d2111ea632db6cb125c51f32a568eee571fdf Mon Sep 17 00:00:00 2001 From: Joshua Batista <[email protected]> Date: Tue, 28 Jul 2026 18:04:32 -0700 Subject: [PATCH 2/2] self review --- llvm/lib/Target/SPIRV/SPIRVUtils.cpp | 8 +++----- .../SPIRV/linkage/groupshared-no-import-linkage.ll | 6 +++--- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/llvm/lib/Target/SPIRV/SPIRVUtils.cpp b/llvm/lib/Target/SPIRV/SPIRVUtils.cpp index 825bc147f92f5..5e416374dd829 100644 --- a/llvm/lib/Target/SPIRV/SPIRVUtils.cpp +++ b/llvm/lib/Target/SPIRV/SPIRVUtils.cpp @@ -1256,15 +1256,13 @@ getSpirvLinkageTypeFor(const SPIRVSubtarget &ST, const GlobalValue &GV) { if (GV.isDeclarationForLinker()) { if (const auto *GVar = dyn_cast<GlobalVariable>(&GV)) { auto SC = addressSpaceToStorageClass(GVar->getAddressSpace(), ST); - // Interface variables (shader-only storage classes) must never get - // Import linkage. + // Interface variables must not get Import linkage. if (SC == SPIRV::StorageClass::Input || SC == SPIRV::StorageClass::Output || SC == SPIRV::StorageClass::PushConstant) return std::nullopt; - // Shaders have no linker, so module-internal storage (e.g. HLSL - // groupshared) can't be imported; kernels (e.g. HIP LDS) legitimately - // can. + // Shaders have no linker, so module-internal storage + // (e.g. HLSL groupshared) can't be imported if (ST.isShader() && (SC == SPIRV::StorageClass::Workgroup || SC == SPIRV::StorageClass::Private)) return std::nullopt; diff --git a/llvm/test/CodeGen/SPIRV/linkage/groupshared-no-import-linkage.ll b/llvm/test/CodeGen/SPIRV/linkage/groupshared-no-import-linkage.ll index 9131843ff5d0b..8d8c81950bfc1 100644 --- a/llvm/test/CodeGen/SPIRV/linkage/groupshared-no-import-linkage.ll +++ b/llvm/test/CodeGen/SPIRV/linkage/groupshared-no-import-linkage.ll @@ -6,7 +6,7 @@ ; Vulkan shader. Verify no Linkage capability / decoration is emitted while the ; variable is still materialized as a Workgroup OpVariable. -; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv-unknown-vulkan1.3-compute %s -o - | FileCheck %s --check-prefixes=CHECK,NOLINK +; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv-unknown-vulkan1.3-compute %s -o - | FileCheck %s ; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-unknown-vulkan1.3-compute %s -o - -filetype=obj | spirv-val --target-env vulkan1.3 %} ; The groupshared variable is still emitted, in the Workgroup storage class. @@ -17,8 +17,8 @@ ; No Linkage capability and no LinkageAttributes decoration may be present. ; A NOT-only prefix scans the whole module (the capability and decoration ; sections precede the OpVariable definition in SPIR-V layout). -; NOLINK-NOT: OpCapability Linkage -; NOLINK-NOT: LinkageAttributes +; CHECK-NOT: OpCapability Linkage +; CHECK-NOT: LinkageAttributes @gs = external hidden addrspace(3) global i32, align 4 _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
