https://github.com/bob80905 created https://github.com/llvm/llvm-project/pull/222167
This PR adds the `InterlockedCompareExchangeFloatBitwise` standalone function and resource methods. It completes the interlocked stack. The operation matches `InterlockedCompareStoreFloatBitwise`, except that it reports the previous value. Clang bitcasts both float arguments to `i32` before the `cmpxchg`, then bitcasts the extracted result back to `float` before it stores it through the `original_value` reference parameter. As with the compare-store form, DXC declares this function for 32-bit float alone, so the overload set is float only, and the operation reuses the 32-bit integer DXIL operation, so it works from shader model 6.0 without capability bits. Fixes: https://github.com/llvm/llvm-project/issues/99203 Assisted by: Github Copilot >From cfd9119440d85a6475ce8452a37b2e12f23754a7 Mon Sep 17 00:00:00 2001 From: Joshua Batista <[email protected]> Date: Tue, 8 Sep 2026 14:02:39 -0700 Subject: [PATCH] First attempt implementing InterlockedCompareExchangeFloatBitwise --- clang/include/clang/Basic/Builtins.td | 9 ++ clang/lib/CodeGen/CGHLSLBuiltins.cpp | 7 +- clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp | 8 +- clang/lib/Sema/HLSLExternalSemaSource.cpp | 4 + clang/lib/Sema/SemaHLSL.cpp | 13 +- ...nterlockedCompareExchangeFloatBitwise.hlsl | 43 +++++++ .../builtins/RWBuffer-Interlocked.hlsl | 10 ++ ...nterlockedCompareExchangeFloatBitwise.hlsl | 32 +++++ ...nterlockedCompareExchangeFloatBitwise.hlsl | 25 ++++ ...ockedCompareExchangeFloatBitwise-sm60.hlsl | 42 +++++++ ...kedCompareExchangeFloatBitwise-errors.hlsl | 119 ++++++++++++++++++ 11 files changed, 306 insertions(+), 6 deletions(-) create mode 100644 clang/test/CodeGenHLSL/builtins/InterlockedCompareExchangeFloatBitwise.hlsl create mode 100644 clang/test/CodeGenHLSL/builtins/RWByteAddressBuffer-InterlockedCompareExchangeFloatBitwise.hlsl create mode 100644 clang/test/CodeGenHLSL/builtins/RasterizerOrderedByteAddressBuffer-InterlockedCompareExchangeFloatBitwise.hlsl create mode 100644 clang/test/SemaHLSL/BuiltIns/ByteAddressBuffer-InterlockedCompareExchangeFloatBitwise-sm60.hlsl create mode 100644 clang/test/SemaHLSL/BuiltIns/InterlockedCompareExchangeFloatBitwise-errors.hlsl diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td index 189d17173b055..6ce6bfc6d1404 100644 --- a/clang/include/clang/Basic/Builtins.td +++ b/clang/include/clang/Basic/Builtins.td @@ -5566,6 +5566,15 @@ def HLSLInterlockedCompareExchange : LangBuiltin<"HLSL_LANG"> { let Prototype = "void (...)"; } +def HLSLInterlockedCompareExchangeFloatBitwise : LangBuiltin<"HLSL_LANG"> { + let Spellings = ["__builtin_hlsl_interlocked_compare_exchange_float_bitwise"]; + // SemaHLSL checks these arguments itself. Custom type checking also stops + // the default variadic promotion, which would otherwise widen the float + // arguments to double. + let Attributes = [NoThrow, CustomTypeChecking]; + let Prototype = "void (...)"; +} + def HLSLInterlockedCompareStore : LangBuiltin<"HLSL_LANG"> { let Spellings = ["__builtin_hlsl_interlocked_compare_store"]; // SemaHLSL checks these arguments itself. Custom type checking also stops diff --git a/clang/lib/CodeGen/CGHLSLBuiltins.cpp b/clang/lib/CodeGen/CGHLSLBuiltins.cpp index 65cc094c69d4f..fea6e16ec6db4 100644 --- a/clang/lib/CodeGen/CGHLSLBuiltins.cpp +++ b/clang/lib/CodeGen/CGHLSLBuiltins.cpp @@ -361,9 +361,11 @@ static Value *handleInterlockedCompareOp(CodeGenFunction &CGF, // `cmpxchg` takes an integer or a pointer, so the float-bitwise operations // work on the bit pattern of the float. This is what those operations mean, // and DXIL and SPIR-V both need the integer form. + llvm::Type *FloatTy = nullptr; if (Compare->getType()->isFloatingPointTy()) { + FloatTy = Compare->getType(); llvm::Type *IntTy = - CGF.Builder.getIntNTy(Compare->getType()->getPrimitiveSizeInBits()); + CGF.Builder.getIntNTy(FloatTy->getPrimitiveSizeInBits()); Compare = CGF.Builder.CreateBitCast(Compare, IntTy); Val = CGF.Builder.CreateBitCast(Val, IntTy); DestAddr = DestAddr.withElementType(IntTy); @@ -380,6 +382,8 @@ static Value *handleInterlockedCompareOp(CodeGenFunction &CGF, // `cmpxchg` yields a { previous value, success } pair. HLSL reports only the // previous value, through the `original_value` reference parameter. Value *Original = CGF.Builder.CreateExtractValue(Pair, 0); + if (FloatTy) + Original = CGF.Builder.CreateBitCast(Original, FloatTy); LValue OrigLV = CGF.EmitLValue(E->getArg(3)); CGF.EmitStoreThroughLValue(RValue::get(Original), OrigLV); return Original; @@ -1527,6 +1531,7 @@ Value *CodeGenFunction::EmitHLSLBuiltinExpr(unsigned BuiltinID, return handleInterlockedOp(*this, E, llvm::AtomicRMWInst::And); } case Builtin::BI__builtin_hlsl_interlocked_compare_exchange: + case Builtin::BI__builtin_hlsl_interlocked_compare_exchange_float_bitwise: case Builtin::BI__builtin_hlsl_interlocked_compare_store: case Builtin::BI__builtin_hlsl_interlocked_compare_store_float_bitwise: { return handleInterlockedCompareOp(*this, E); diff --git a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp index 9918a09338482..005796c42ea42 100644 --- a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp +++ b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp @@ -1757,11 +1757,15 @@ BuiltinTypeDeclBuilder::addByteAddressBufferInterlockedMethods() { "InterlockedCompareExchange", AST.UnsignedIntTy, "__builtin_hlsl_interlocked_compare_exchange", /*WithOriginalValue=*/true); + // The float-bitwise compare operations reuse the 32-bit integer DXIL + // operation, so they need no capability bits and work from SM 6.0. + addByteAddressBufferInterlockedCompareMethod( + "InterlockedCompareExchangeFloatBitwise", AST.FloatTy, + "__builtin_hlsl_interlocked_compare_exchange_float_bitwise", + /*WithOriginalValue=*/true); addByteAddressBufferInterlockedCompareMethod( "InterlockedCompareStore", AST.UnsignedIntTy, "__builtin_hlsl_interlocked_compare_store"); - // The float-bitwise compare reuses the 32-bit integer DXIL operation, so it - // needs no capability bits and works from SM 6.0. addByteAddressBufferInterlockedCompareMethod( "InterlockedCompareStoreFloatBitwise", AST.FloatTy, "__builtin_hlsl_interlocked_compare_store_float_bitwise"); diff --git a/clang/lib/Sema/HLSLExternalSemaSource.cpp b/clang/lib/Sema/HLSLExternalSemaSource.cpp index 5c949a184dcd8..72061128c5201 100644 --- a/clang/lib/Sema/HLSLExternalSemaSource.cpp +++ b/clang/lib/Sema/HLSLExternalSemaSource.cpp @@ -954,6 +954,10 @@ void HLSLExternalSemaSource::defineHLSLAtomicIntrinsics() { *SemaPtr, HLSLNamespace, "InterlockedCompareExchange", "__builtin_hlsl_interlocked_compare_exchange", AtomicOverloadShape::CompareExchange); + defineHLSLInterlockedCompareFunc( + *SemaPtr, HLSLNamespace, "InterlockedCompareExchangeFloatBitwise", + "__builtin_hlsl_interlocked_compare_exchange_float_bitwise", + AtomicOverloadShape::CompareExchange, /*FloatOnly=*/true); defineHLSLInterlockedCompareFunc(*SemaPtr, HLSLNamespace, "InterlockedCompareStore", "__builtin_hlsl_interlocked_compare_store", diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp index 4ac2cb458bd41..918be43c2832c 100644 --- a/clang/lib/Sema/SemaHLSL.cpp +++ b/clang/lib/Sema/SemaHLSL.cpp @@ -4713,6 +4713,7 @@ bool SemaHLSL::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { case Builtin::BI__builtin_hlsl_interlocked_add: case Builtin::BI__builtin_hlsl_interlocked_and: case Builtin::BI__builtin_hlsl_interlocked_compare_exchange: + case Builtin::BI__builtin_hlsl_interlocked_compare_exchange_float_bitwise: case Builtin::BI__builtin_hlsl_interlocked_compare_store: case Builtin::BI__builtin_hlsl_interlocked_compare_store_float_bitwise: case Builtin::BI__builtin_hlsl_interlocked_exchange: @@ -4737,9 +4738,15 @@ bool SemaHLSL::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { BuiltinID == Builtin::BI__builtin_hlsl_interlocked_compare_store || IsCompareStoreFloat; // InterlockedCompareExchange adds `compare_value` before `value` and - // always reports the previous value, so it takes four arguments. + // always reports the previous value, so it takes four arguments. The + // float-bitwise form has the same shape and compares the bit patterns + // instead of the values. + const bool IsCompareExchangeFloat = + BuiltinID == + Builtin::BI__builtin_hlsl_interlocked_compare_exchange_float_bitwise; const bool IsCompareExchange = - BuiltinID == Builtin::BI__builtin_hlsl_interlocked_compare_exchange; + BuiltinID == Builtin::BI__builtin_hlsl_interlocked_compare_exchange || + IsCompareExchangeFloat; // InterlockedExchange always reports the previous value, so it requires // `original_value` instead of accepting it as an optional argument. if (IsCompareExchange) { @@ -4766,7 +4773,7 @@ bool SemaHLSL::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { // compare operations operate on float alone. DXIL lowers both as // operations on the value's bit pattern, and DXC accepts 32-bit float // only, so half and double are rejected. - const bool RequiresFloat = IsCompareStoreFloat; + const bool RequiresFloat = IsCompareStoreFloat || IsCompareExchangeFloat; const bool AllowsFloat = RequiresFloat || BuiltinID == Builtin::BI__builtin_hlsl_interlocked_exchange; diff --git a/clang/test/CodeGenHLSL/builtins/InterlockedCompareExchangeFloatBitwise.hlsl b/clang/test/CodeGenHLSL/builtins/InterlockedCompareExchangeFloatBitwise.hlsl new file mode 100644 index 0000000000000..951621dea4740 --- /dev/null +++ b/clang/test/CodeGenHLSL/builtins/InterlockedCompareExchangeFloatBitwise.hlsl @@ -0,0 +1,43 @@ +// RUN: %clang_cc1 -std=hlsl2021 -finclude-default-header -triple \ +// RUN: dxil-pc-shadermodel6.6-library %s -emit-llvm -disable-llvm-passes -o - | \ +// RUN: FileCheck %s --check-prefixes=CHECK,DXCHECK + +// RUN: %clang_cc1 -std=hlsl2021 -finclude-default-header -triple \ +// RUN: spirv-pc-vulkan-library %s -emit-llvm -disable-llvm-passes -o - | \ +// RUN: FileCheck %s --check-prefixes=CHECK,SPVCHECK + +// Test basic lowering of HLSL InterlockedCompareExchangeFloatBitwise to +// `cmpxchg monotonic`. `cmpxchg` takes an integer, so the float arguments +// become their bit patterns first, and the reported value becomes a float +// again before the store. + +groupshared float gs_f32; + +// CHECK-LABEL: define {{(dso_local |hidden |internal |protected |spir_func )*}}void @{{.*}}test_float +// CHECK: [[CMP:%.*]] = bitcast float %{{.*}} to i32 +// CHECK-NEXT: [[VAL:%.*]] = bitcast float %{{.*}} to i32 +// DXCHECK-NEXT: [[PAIR:%.*]] = cmpxchg ptr addrspace(3) {{.*}}@gs_f32{{.*}}, i32 [[CMP]], i32 [[VAL]] syncscope("workgroup") monotonic monotonic +// SPVCHECK-NEXT: [[PAIR:%.*]] = cmpxchg ptr addrspace(3) {{.*}}@gs_f32{{.*}}, i32 [[CMP]], i32 [[VAL]] syncscope("workgroup") monotonic monotonic +// CHECK-NEXT: [[RES:%.*]] = extractvalue { i32, i1 } [[PAIR]], 0 +// CHECK-NEXT: [[ORIG:%.*]] = bitcast i32 [[RES]] to float +// CHECK-NEXT: store float [[ORIG]], ptr %orig +export void test_float(float cmp, float v) { + float orig; + InterlockedCompareExchangeFloatBitwise(gs_f32, cmp, v, orig); +} + +// A device-address-space destination uses the "device" scope instead. +RWBuffer<float> Buf : register(u0); + +// CHECK-LABEL: define {{(dso_local |hidden |internal |protected |spir_func )*}}void @{{.*}}test_device +// CHECK: [[CMP:%.*]] = bitcast float %{{.*}} to i32 +// CHECK-NEXT: [[VAL:%.*]] = bitcast float %{{.*}} to i32 +// DXCHECK-NEXT: [[PAIR:%.*]] = cmpxchg ptr %{{.*}}, i32 [[CMP]], i32 [[VAL]] syncscope("device") monotonic monotonic +// SPVCHECK-NEXT: [[PAIR:%.*]] = cmpxchg ptr addrspace(11) %{{.*}}, i32 [[CMP]], i32 [[VAL]] syncscope("device") monotonic monotonic +// CHECK-NEXT: [[RES:%.*]] = extractvalue { i32, i1 } [[PAIR]], 0 +// CHECK-NEXT: [[ORIG:%.*]] = bitcast i32 [[RES]] to float +// CHECK-NEXT: store float [[ORIG]], ptr %orig +export void test_device(float cmp, float v) { + float orig; + InterlockedCompareExchangeFloatBitwise(Buf[0], cmp, v, orig); +} diff --git a/clang/test/CodeGenHLSL/builtins/RWBuffer-Interlocked.hlsl b/clang/test/CodeGenHLSL/builtins/RWBuffer-Interlocked.hlsl index b85e40a9b1093..603e081df841e 100644 --- a/clang/test/CodeGenHLSL/builtins/RWBuffer-Interlocked.hlsl +++ b/clang/test/CodeGenHLSL/builtins/RWBuffer-Interlocked.hlsl @@ -46,6 +46,10 @@ RWBuffer<float> FOut : register(u2); // DXCHECK: cmpxchg ptr %[[PTR11]], i32 1, i32 2 syncscope("device") monotonic monotonic // DXCHECK: %[[PTR12:.*]] = call {{.*}} @llvm.dx.resource.getpointer.p0.tdx.TypedBuffer_f32_1_0_0t.i32(target("dx.TypedBuffer", float, 1, 0, 0) %{{.*}}, i32 %{{.*}}) // DXCHECK: cmpxchg ptr %[[PTR12]], i32 1065353216, i32 1073741824 syncscope("device") monotonic monotonic +// DXCHECK: %[[PTR13:.*]] = call {{.*}} @llvm.dx.resource.getpointer.p0.tdx.TypedBuffer_f32_1_0_0t.i32(target("dx.TypedBuffer", float, 1, 0, 0) %{{.*}}, i32 %{{.*}}) +// DXCHECK: %[[PAIR13:.*]] = cmpxchg ptr %[[PTR13]], i32 1065353216, i32 1073741824 syncscope("device") monotonic monotonic +// DXCHECK: %[[RES13:.*]] = extractvalue { i32, i1 } %[[PAIR13]], 0 +// DXCHECK: bitcast i32 %[[RES13]] to float // SPVCHECK: %[[PTR1:.*]] = call {{.*}} @llvm.spv.resource.getpointer.{{.*}}(target("spirv.SignedImage", i32, {{.*}}) %{{.*}}, i32 %{{.*}}) // SPVCHECK: atomicrmw add ptr addrspace(11) %[[PTR1]], i32 1 syncscope("device") monotonic // SPVCHECK: %[[PTR2:.*]] = call {{.*}} @llvm.spv.resource.getpointer.{{.*}}(target("spirv.SignedImage", i32, {{.*}}) %{{.*}}, i32 %{{.*}}) @@ -70,6 +74,10 @@ RWBuffer<float> FOut : register(u2); // SPVCHECK: cmpxchg ptr addrspace(11) %[[PTR11]], i32 1, i32 2 syncscope("device") monotonic monotonic // SPVCHECK: %[[PTR12:.*]] = call {{.*}} @llvm.spv.resource.getpointer.{{.*}}(target("spirv.Image", float, {{.*}}) %{{.*}}, i32 %{{.*}}) // SPVCHECK: cmpxchg ptr addrspace(11) %[[PTR12]], i32 1065353216, i32 1073741824 syncscope("device") monotonic monotonic +// SPVCHECK: %[[PTR13:.*]] = call {{.*}} @llvm.spv.resource.getpointer.{{.*}}(target("spirv.Image", float, {{.*}}) %{{.*}}, i32 %{{.*}}) +// SPVCHECK: %[[PAIR13:.*]] = cmpxchg ptr addrspace(11) %[[PTR13]], i32 1065353216, i32 1073741824 syncscope("device") monotonic monotonic +// SPVCHECK: %[[RES13:.*]] = extractvalue { i32, i1 } %[[PAIR13]], 0 +// SPVCHECK: bitcast i32 %[[RES13]] to float [shader("compute")] [numthreads(1,1,1)] void main(uint3 id : SV_DispatchThreadID) { @@ -86,4 +94,6 @@ void main(uint3 id : SV_DispatchThreadID) { InterlockedCompareStore(Out[id.x], 1, 2); InterlockedCompareExchange(Out[id.x], 1, 2, orig); InterlockedCompareStoreFloatBitwise(FOut[id.x], 1.0f, 2.0f); + float forig; + InterlockedCompareExchangeFloatBitwise(FOut[id.x], 1.0f, 2.0f, forig); } diff --git a/clang/test/CodeGenHLSL/builtins/RWByteAddressBuffer-InterlockedCompareExchangeFloatBitwise.hlsl b/clang/test/CodeGenHLSL/builtins/RWByteAddressBuffer-InterlockedCompareExchangeFloatBitwise.hlsl new file mode 100644 index 0000000000000..45389ac89fbd8 --- /dev/null +++ b/clang/test/CodeGenHLSL/builtins/RWByteAddressBuffer-InterlockedCompareExchangeFloatBitwise.hlsl @@ -0,0 +1,32 @@ +// RUN: %clang_cc1 -std=hlsl202x -finclude-default-header -triple \ +// RUN: dxil-pc-shadermodel6.6-library %s -emit-llvm -disable-llvm-passes -o - | \ +// RUN: FileCheck %s --check-prefixes=CHECK,DXCHECK + +// RUN: %clang_cc1 -std=hlsl202x -finclude-default-header -triple \ +// RUN: spirv-pc-vulkan1.3-library %s -emit-llvm -disable-llvm-passes -o - | \ +// RUN: FileCheck %s --check-prefixes=CHECK,SPVCHECK + +// Test that the RWByteAddressBuffer::InterlockedCompareExchangeFloatBitwise +// member method lowers to `resource_getpointer -> cmpxchg`, for both DXIL and +// SPIR-V targets. The float arguments become their bit patterns first, because +// `cmpxchg` takes an integer. The method takes the reported value by +// reference, so the pointer is loaded before the store. + +RWByteAddressBuffer BAB : register(u0); + +// CHECK-LABEL: define {{(dso_local |hidden |internal |protected |spir_func )*}}void @{{.*}}test_bab_float +// 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 %{{.*}}) +// 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 %{{.*}}) +// CHECK: %[[CMP:.*]] = bitcast float %{{.*}} to i32 +// CHECK-NEXT: %[[VAL:.*]] = bitcast float %{{.*}} to i32 +// DXCHECK-NEXT: %[[PAIR:.*]] = cmpxchg ptr %[[PTR]], i32 %[[CMP]], i32 %[[VAL]] syncscope("device") monotonic monotonic +// SPVCHECK-NEXT: %[[PAIR:.*]] = cmpxchg ptr addrspace(11) %[[PTR]], i32 %[[CMP]], i32 %[[VAL]] syncscope("device") monotonic monotonic +// CHECK-NEXT: %[[RES:.*]] = extractvalue { i32, i1 } %[[PAIR]], 0 +// CHECK-NEXT: %[[ORIG:.*]] = bitcast i32 %[[RES]] to float +// CHECK-NEXT: %[[DEST:.*]] = load ptr, ptr %OriginalValue.addr +// CHECK-NEXT: store float %[[ORIG]], ptr %[[DEST]] +export void test_bab_float(uint off, float cmp, float v, out float orig) { + BAB.InterlockedCompareExchangeFloatBitwise(off, cmp, v, orig); +} diff --git a/clang/test/CodeGenHLSL/builtins/RasterizerOrderedByteAddressBuffer-InterlockedCompareExchangeFloatBitwise.hlsl b/clang/test/CodeGenHLSL/builtins/RasterizerOrderedByteAddressBuffer-InterlockedCompareExchangeFloatBitwise.hlsl new file mode 100644 index 0000000000000..67df534c00ae2 --- /dev/null +++ b/clang/test/CodeGenHLSL/builtins/RasterizerOrderedByteAddressBuffer-InterlockedCompareExchangeFloatBitwise.hlsl @@ -0,0 +1,25 @@ +// RUN: %clang_cc1 -std=hlsl202x -finclude-default-header -triple \ +// RUN: dxil-pc-shadermodel6.6-library %s -emit-llvm -disable-llvm-passes -o - | \ +// RUN: FileCheck %s --check-prefixes=CHECK,DXCHECK + +// SPIR-V codegen for RasterizerOrderedByteAddressBuffer is not implemented +// yet (asserts in clang/lib/CodeGen/Targets/SPIR.cpp on +// `!ResAttrs.IsROV && "Rasterizer order views not implemented for SPIR-V yet"`). +// Add a `spirv-pc-vulkan1.3-library` RUN line here when SPIR-V ROV support +// lands. + +RasterizerOrderedByteAddressBuffer ROVB : register(u1); + +// CHECK-LABEL: define void @{{.*}}test_rovb_float +// 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: %[[CMP:.*]] = bitcast float %{{.*}} to i32 +// DXCHECK-NEXT: %[[VAL:.*]] = bitcast float %{{.*}} to i32 +// DXCHECK-NEXT: %[[PAIR:.*]] = cmpxchg ptr %[[PTR]], i32 %[[CMP]], i32 %[[VAL]] syncscope("device") monotonic monotonic +// DXCHECK-NEXT: %[[RES:.*]] = extractvalue { i32, i1 } %[[PAIR]], 0 +// DXCHECK-NEXT: %[[ORIG:.*]] = bitcast i32 %[[RES]] to float +// DXCHECK-NEXT: %[[DEST:.*]] = load ptr, ptr %OriginalValue.addr +// DXCHECK-NEXT: store float %[[ORIG]], ptr %[[DEST]] +export void test_rovb_float(uint off, float cmp, float v, out float orig) { + ROVB.InterlockedCompareExchangeFloatBitwise(off, cmp, v, orig); +} diff --git a/clang/test/SemaHLSL/BuiltIns/ByteAddressBuffer-InterlockedCompareExchangeFloatBitwise-sm60.hlsl b/clang/test/SemaHLSL/BuiltIns/ByteAddressBuffer-InterlockedCompareExchangeFloatBitwise-sm60.hlsl new file mode 100644 index 0000000000000..2adc6d1e1e552 --- /dev/null +++ b/clang/test/SemaHLSL/BuiltIns/ByteAddressBuffer-InterlockedCompareExchangeFloatBitwise-sm60.hlsl @@ -0,0 +1,42 @@ +// RUN: %clang_cc1 -std=hlsl202x -finclude-default-header \ +// RUN: -triple dxil-pc-shadermodel6.0-library %s -fsyntax-only -verify \ +// RUN: -verify-ignore-unexpected=warning + +// The float-bitwise compare reuses the 32-bit integer DXIL operation, so it +// needs no capability bits and works from SM 6.0. The 64-bit compare-exchange +// needs SM 6.6. This file checks both halves, so it proves the two are gated +// differently. + +RWByteAddressBuffer BAB : register(u0); +RasterizerOrderedByteAddressBuffer ROVB : register(u1); +groupshared float gs_f32; +groupshared uint64_t gs_u64; + +void sm60_bab_float_bitwise_ok(uint off, float cmp, float v, out float orig) { + BAB.InterlockedCompareExchangeFloatBitwise(off, cmp, v, orig); +} + +void sm60_rovb_float_bitwise_ok(uint off, float cmp, float v, out float orig) { + ROVB.InterlockedCompareExchangeFloatBitwise(off, cmp, v, orig); +} + +void sm60_free_function_ok(float cmp, float v) { + float orig; + InterlockedCompareExchangeFloatBitwise(gs_f32, cmp, v, orig); +} + +void sm60_direct_builtin_ok(float cmp, float v) { + float orig; + __builtin_hlsl_interlocked_compare_exchange_float_bitwise(gs_f32, cmp, v, orig); +} + +void sm60_no_bab_compare_exchange64(uint off, uint64_t cmp, uint64_t v, + out uint64_t orig) { + BAB.InterlockedCompareExchange64(off, cmp, v, orig); + // expected-error@-1 {{no member named 'InterlockedCompareExchange64' in 'hlsl::RWByteAddressBuffer'}} +} + +void sm60_no_direct_builtin_u64(uint64_t cmp, uint64_t v, out uint64_t orig) { + __builtin_hlsl_interlocked_compare_exchange(gs_u64, cmp, v, orig); + // expected-error@-1 {{'__builtin_hlsl_interlocked_compare_exchange' requires shader model 6.6 or newer}} +} diff --git a/clang/test/SemaHLSL/BuiltIns/InterlockedCompareExchangeFloatBitwise-errors.hlsl b/clang/test/SemaHLSL/BuiltIns/InterlockedCompareExchangeFloatBitwise-errors.hlsl new file mode 100644 index 0000000000000..934654c5f366d --- /dev/null +++ b/clang/test/SemaHLSL/BuiltIns/InterlockedCompareExchangeFloatBitwise-errors.hlsl @@ -0,0 +1,119 @@ +// RUN: %clang_cc1 -std=hlsl202x -finclude-default-header \ +// RUN: -triple dxil-pc-shadermodel6.6-library %s -emit-llvm-only \ +// RUN: -disable-llvm-passes -verify + +// InterlockedCompareExchangeFloatBitwise compares the bit pattern of a 32-bit +// float, so it is provided as a float-only overload set (groupshared/device). +// It reports the previous value, so it has a single 4-argument form. + +groupshared float gs_f32; +groupshared int gs_i32; +groupshared double gs_f64; +groupshared half gs_f16; +struct S { float x; }; +groupshared S gs_s; + +void too_few(float cmp, float v) { + InterlockedCompareExchangeFloatBitwise(gs_f32, cmp, v); // expected-error{{no matching function for call to 'InterlockedCompareExchangeFloatBitwise'}} + // expected-note@*:* 2 {{candidate function}} +} + +void too_many(float cmp, float v, float extra) { + float orig; + InterlockedCompareExchangeFloatBitwise(gs_f32, cmp, v, orig, extra); // expected-error{{no matching function for call to 'InterlockedCompareExchangeFloatBitwise'}} + // expected-note@*:* 2 {{candidate function}} +} + +void local_dest(float cmp, float v) { + float dest; + float orig; + InterlockedCompareExchangeFloatBitwise(dest, cmp, v, orig); // expected-error{{no matching function for call to 'InterlockedCompareExchangeFloatBitwise'}} + // expected-note@*:* 2 {{candidate function}} +} + +// The bitwise compare is defined for 32-bit float alone, so there is no +// integer, half or double overload. +void int_dest(int cmp, int v) { + int orig; + InterlockedCompareExchangeFloatBitwise(gs_i32, cmp, v, orig); // expected-error{{no matching function for call to 'InterlockedCompareExchangeFloatBitwise'}} + // expected-note@*:* 2 {{candidate function}} +} + +void double_dest(double cmp, double v) { + double orig; + InterlockedCompareExchangeFloatBitwise(gs_f64, cmp, v, orig); // expected-error{{no matching function for call to 'InterlockedCompareExchangeFloatBitwise'}} + // expected-note@*:* 2 {{candidate function}} +} + +void half_dest(half cmp, half v) { + half orig; + InterlockedCompareExchangeFloatBitwise(gs_f16, cmp, v, orig); // expected-error{{no matching function for call to 'InterlockedCompareExchangeFloatBitwise'}} + // expected-note@*:* 2 {{candidate function}} +} + +void struct_dest(float cmp, float v) { + float orig; + InterlockedCompareExchangeFloatBitwise(gs_s, cmp, v, orig); // expected-error{{no matching function for call to 'InterlockedCompareExchangeFloatBitwise'}} + // expected-note@*:* 2 {{candidate function}} +} + +void direct_too_few(float cmp, float v) { + __builtin_hlsl_interlocked_compare_exchange_float_bitwise(gs_f32, cmp, v); + // expected-error@-1 {{too few arguments to function call, expected 4, have 3}} +} + +void direct_too_many(float cmp, float v, float extra) { + float orig; + __builtin_hlsl_interlocked_compare_exchange_float_bitwise(gs_f32, cmp, v, orig, extra); + // expected-error@-1 {{too many arguments to function call, expected 4, have 5}} +} + +void direct_integer_dest(int cmp, int v) { + int orig; + __builtin_hlsl_interlocked_compare_exchange_float_bitwise(gs_i32, cmp, v, orig); + // expected-error@-1 {{1st argument must be a scalar 32 bit floating-point type (was 'int')}} +} + +void direct_double_dest(double cmp, double v) { + double orig; + __builtin_hlsl_interlocked_compare_exchange_float_bitwise(gs_f64, cmp, v, orig); + // expected-error@-1 {{1st argument must be a scalar 32 bit floating-point type (was 'double')}} +} + +void direct_half_dest(half cmp, half v) { + half orig; + __builtin_hlsl_interlocked_compare_exchange_float_bitwise(gs_f16, cmp, v, orig); + // expected-error@-1 {{1st argument must be a scalar 32 bit floating-point type (was 'half')}} +} + +void direct_non_scalar_dest() { + S local_s; + float orig; + __builtin_hlsl_interlocked_compare_exchange_float_bitwise(local_s, 1.0f, 2.0f, orig); + // expected-error@-1 {{1st argument must be a scalar 32 bit floating-point type (was 'S')}} +} + +void direct_nonlvalue_dest(float cmp, float v) { + float orig; + __builtin_hlsl_interlocked_compare_exchange_float_bitwise(1.0f, cmp, v, orig); + // expected-error@-1 {{cannot bind non-lvalue argument '1.F' to out parameter}} +} + +// The last argument is an out parameter, so an rvalue is rejected there. +void direct_nonlvalue_original_value(float cmp, float v) { + __builtin_hlsl_interlocked_compare_exchange_float_bitwise(gs_f32, cmp, v, 0.0f); + // expected-error@-1 {{cannot bind non-lvalue argument '0.F' to out parameter}} +} + +void direct_mismatched_original_value(float cmp, float v) { + int orig; + __builtin_hlsl_interlocked_compare_exchange_float_bitwise(gs_f32, cmp, v, orig); + // expected-error@-1 {{passing 'int' to parameter of incompatible type 'float'}} +} + +void direct_default_as_dest(float cmp, float v) { + float local; + float orig; + __builtin_hlsl_interlocked_compare_exchange_float_bitwise(local, cmp, v, orig); + // expected-error@-1 {{1st argument to atomic builtin must reference groupshared or device memory (was 'float')}} +} _______________________________________________ llvm-branch-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
