https://github.com/bob80905 updated https://github.com/llvm/llvm-project/pull/222160
>From fad774c2c4337955cfc7e384eae2d4bf3b9ebb94 Mon Sep 17 00:00:00 2001 From: Joshua Batista <[email protected]> Date: Thu, 3 Sep 2026 16:31:37 -0700 Subject: [PATCH] First attempt implementing interlockedmax --- clang/include/clang/Basic/Builtins.td | 6 ++ clang/lib/CodeGen/CGHLSLBuiltins.cpp | 7 ++ clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp | 9 ++ clang/lib/Sema/HLSLExternalSemaSource.cpp | 2 + clang/lib/Sema/SemaHLSL.cpp | 1 + .../CodeGenHLSL/builtins/InterlockedMax.hlsl | 74 +++++++++++++++ .../builtins/RWBuffer-Interlocked.hlsl | 20 +++- .../RWByteAddressBuffer-InterlockedMax.hlsl | 92 +++++++++++++++++++ ...deredByteAddressBuffer-InterlockedMax.hlsl | 37 ++++++++ ...teAddressBuffer-InterlockedMax-errors.hlsl | 34 +++++++ ...ressBuffer-InterlockedMax-sm65-errors.hlsl | 26 ++++++ .../BuiltIns/InterlockedMax-errors.hlsl | 89 ++++++++++++++++++ 12 files changed, 392 insertions(+), 5 deletions(-) create mode 100644 clang/test/CodeGenHLSL/builtins/InterlockedMax.hlsl create mode 100644 clang/test/CodeGenHLSL/builtins/RWByteAddressBuffer-InterlockedMax.hlsl create mode 100644 clang/test/CodeGenHLSL/builtins/RasterizerOrderedByteAddressBuffer-InterlockedMax.hlsl create mode 100644 clang/test/SemaHLSL/BuiltIns/ByteAddressBuffer-InterlockedMax-errors.hlsl create mode 100644 clang/test/SemaHLSL/BuiltIns/ByteAddressBuffer-InterlockedMax-sm65-errors.hlsl create mode 100644 clang/test/SemaHLSL/BuiltIns/InterlockedMax-errors.hlsl diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td index fe6f41fe00345..ecd6008b1bcc8 100644 --- a/clang/include/clang/Basic/Builtins.td +++ b/clang/include/clang/Basic/Builtins.td @@ -5557,6 +5557,12 @@ def HLSLInterlockedAnd : LangBuiltin<"HLSL_LANG"> { let Prototype = "void (...)"; } +def HLSLInterlockedMax : LangBuiltin<"HLSL_LANG"> { + let Spellings = ["__builtin_hlsl_interlocked_max"]; + let Attributes = [NoThrow]; + let Prototype = "void (...)"; +} + def HLSLInterlockedMin : LangBuiltin<"HLSL_LANG"> { let Spellings = ["__builtin_hlsl_interlocked_min"]; let Attributes = [NoThrow]; diff --git a/clang/lib/CodeGen/CGHLSLBuiltins.cpp b/clang/lib/CodeGen/CGHLSLBuiltins.cpp index 52aac50e6baa6..3a6e3f9617b30 100644 --- a/clang/lib/CodeGen/CGHLSLBuiltins.cpp +++ b/clang/lib/CodeGen/CGHLSLBuiltins.cpp @@ -1481,6 +1481,13 @@ Value *CodeGenFunction::EmitHLSLBuiltinExpr(unsigned BuiltinID, case Builtin::BI__builtin_hlsl_interlocked_and: { return handleInterlockedOp(*this, E, llvm::AtomicRMWInst::And); } + case Builtin::BI__builtin_hlsl_interlocked_max: { + llvm::AtomicRMWInst::BinOp Op = + E->getArg(0)->getType()->hasSignedIntegerRepresentation() + ? llvm::AtomicRMWInst::Max + : llvm::AtomicRMWInst::UMax; + return handleInterlockedOp(*this, E, Op); + } case Builtin::BI__builtin_hlsl_interlocked_min: { llvm::AtomicRMWInst::BinOp Op = E->getArg(0)->getType()->hasSignedIntegerRepresentation() diff --git a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp index 5d499b7d6a96b..585eb29743b75 100644 --- a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp +++ b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp @@ -1752,6 +1752,10 @@ BuiltinTypeDeclBuilder::addByteAddressBufferInterlockedMethods() { "__builtin_hlsl_interlocked_add"); addByteAddressBufferInterlockedMethod("InterlockedAnd", AST.UnsignedIntTy, "__builtin_hlsl_interlocked_and"); + addByteAddressBufferInterlockedMethod("InterlockedMax", AST.IntTy, + "__builtin_hlsl_interlocked_max"); + addByteAddressBufferInterlockedMethod("InterlockedMax", AST.UnsignedIntTy, + "__builtin_hlsl_interlocked_max"); addByteAddressBufferInterlockedMethod("InterlockedMin", AST.IntTy, "__builtin_hlsl_interlocked_min"); addByteAddressBufferInterlockedMethod("InterlockedMin", AST.UnsignedIntTy, @@ -1774,6 +1778,11 @@ BuiltinTypeDeclBuilder::addByteAddressBufferInterlockedMethods() { addByteAddressBufferInterlockedMethod("InterlockedAnd64", AST.UnsignedLongTy, "__builtin_hlsl_interlocked_and"); + addByteAddressBufferInterlockedMethod("InterlockedMax64", AST.LongTy, + "__builtin_hlsl_interlocked_max"); + addByteAddressBufferInterlockedMethod("InterlockedMax64", + AST.UnsignedLongTy, + "__builtin_hlsl_interlocked_max"); addByteAddressBufferInterlockedMethod("InterlockedMin64", AST.LongTy, "__builtin_hlsl_interlocked_min"); addByteAddressBufferInterlockedMethod("InterlockedMin64", diff --git a/clang/lib/Sema/HLSLExternalSemaSource.cpp b/clang/lib/Sema/HLSLExternalSemaSource.cpp index 3f42316d2f1fb..2e40c190074c4 100644 --- a/clang/lib/Sema/HLSLExternalSemaSource.cpp +++ b/clang/lib/Sema/HLSLExternalSemaSource.cpp @@ -886,6 +886,8 @@ void HLSLExternalSemaSource::defineHLSLAtomicIntrinsics() { "__builtin_hlsl_interlocked_add"); defineHLSLInterlockedFunc(*SemaPtr, HLSLNamespace, "InterlockedAnd", "__builtin_hlsl_interlocked_and"); + defineHLSLInterlockedFunc(*SemaPtr, HLSLNamespace, "InterlockedMax", + "__builtin_hlsl_interlocked_max"); defineHLSLInterlockedFunc(*SemaPtr, HLSLNamespace, "InterlockedMin", "__builtin_hlsl_interlocked_min"); defineHLSLInterlockedFunc(*SemaPtr, HLSLNamespace, "InterlockedOr", diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp index f025e71f40e2c..87c039c45ad27 100644 --- a/clang/lib/Sema/SemaHLSL.cpp +++ b/clang/lib/Sema/SemaHLSL.cpp @@ -4712,6 +4712,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_max: case Builtin::BI__builtin_hlsl_interlocked_min: case Builtin::BI__builtin_hlsl_interlocked_or: case Builtin::BI__builtin_hlsl_interlocked_xor: { diff --git a/clang/test/CodeGenHLSL/builtins/InterlockedMax.hlsl b/clang/test/CodeGenHLSL/builtins/InterlockedMax.hlsl new file mode 100644 index 0000000000000..3e7ebfd2a5c88 --- /dev/null +++ b/clang/test/CodeGenHLSL/builtins/InterlockedMax.hlsl @@ -0,0 +1,74 @@ +// 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 signed and unsigned lowering of HLSL InterlockedMax. + +groupshared int gs_i32; +groupshared uint gs_u32; +groupshared int64_t gs_i64; +groupshared uint64_t gs_u64; + +// CHECK-LABEL: define {{.*}}void @{{.*}}test_int_2arg +// DXCHECK: atomicrmw max ptr addrspace(3) {{.*}}@gs_i32{{.*}}, i32 %{{.*}} syncscope("workgroup") monotonic +// SPVCHECK: atomicrmw max ptr addrspace(3) {{.*}}@gs_i32{{.*}}, i32 %{{.*}} syncscope("workgroup") monotonic +export void test_int_2arg(int v) { + InterlockedMax(gs_i32, v); +} + +// CHECK-LABEL: define {{.*}}void @{{.*}}test_uint_2arg +// DXCHECK: atomicrmw umax ptr addrspace(3) {{.*}}@gs_u32{{.*}}, i32 %{{.*}} syncscope("workgroup") monotonic +// SPVCHECK: atomicrmw umax ptr addrspace(3) {{.*}}@gs_u32{{.*}}, i32 %{{.*}} syncscope("workgroup") monotonic +export void test_uint_2arg(uint v) { + InterlockedMax(gs_u32, v); +} + +// CHECK-LABEL: define {{.*}}void @{{.*}}test_int_3arg +// DXCHECK: %[[R:.*]] = atomicrmw max ptr addrspace(3) {{.*}}@gs_i32{{.*}}, i32 %{{.*}} syncscope("workgroup") monotonic +// SPVCHECK: %[[R:.*]] = atomicrmw max ptr addrspace(3) {{.*}}@gs_i32{{.*}}, i32 %{{.*}} syncscope("workgroup") monotonic +// CHECK: store i32 %[[R]], ptr {{.*}} +export void test_int_3arg(int v, out int orig) { + InterlockedMax(gs_i32, v, orig); +} + +// CHECK-LABEL: define {{.*}}void @{{.*}}test_uint_3arg +// DXCHECK: %[[R:.*]] = atomicrmw umax ptr addrspace(3) {{.*}}@gs_u32{{.*}}, i32 %{{.*}} syncscope("workgroup") monotonic +// SPVCHECK: %[[R:.*]] = atomicrmw umax ptr addrspace(3) {{.*}}@gs_u32{{.*}}, i32 %{{.*}} syncscope("workgroup") monotonic +// CHECK: store i32 %[[R]], ptr {{.*}} +export void test_uint_3arg(uint v, out uint orig) { + InterlockedMax(gs_u32, v, orig); +} + +// CHECK-LABEL: define {{.*}}void @{{.*}}test_int64_2arg +// DXCHECK: atomicrmw max ptr addrspace(3) {{.*}}@gs_i64{{.*}}, i64 %{{.*}} syncscope("workgroup") monotonic +// SPVCHECK: atomicrmw max ptr addrspace(3) {{.*}}@gs_i64{{.*}}, i64 %{{.*}} syncscope("workgroup") monotonic +export void test_int64_2arg(int64_t v) { + InterlockedMax(gs_i64, v); +} + +// CHECK-LABEL: define {{.*}}void @{{.*}}test_uint64_2arg +// DXCHECK: atomicrmw umax ptr addrspace(3) {{.*}}@gs_u64{{.*}}, i64 %{{.*}} syncscope("workgroup") monotonic +// SPVCHECK: atomicrmw umax ptr addrspace(3) {{.*}}@gs_u64{{.*}}, i64 %{{.*}} syncscope("workgroup") monotonic +export void test_uint64_2arg(uint64_t v) { + InterlockedMax(gs_u64, v); +} + +// CHECK-LABEL: define {{.*}}void @{{.*}}test_int64_3arg +// DXCHECK: %[[R:.*]] = atomicrmw max ptr addrspace(3) {{.*}}@gs_i64{{.*}}, i64 %{{.*}} syncscope("workgroup") monotonic +// SPVCHECK: %[[R:.*]] = atomicrmw max ptr addrspace(3) {{.*}}@gs_i64{{.*}}, i64 %{{.*}} syncscope("workgroup") monotonic +// CHECK: store i64 %[[R]], ptr {{.*}} +export void test_int64_3arg(int64_t v, out int64_t orig) { + InterlockedMax(gs_i64, v, orig); +} + +// CHECK-LABEL: define {{.*}}void @{{.*}}test_uint64_3arg +// DXCHECK: %[[R:.*]] = atomicrmw umax ptr addrspace(3) {{.*}}@gs_u64{{.*}}, i64 %{{.*}} syncscope("workgroup") monotonic +// SPVCHECK: %[[R:.*]] = atomicrmw umax 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) { + InterlockedMax(gs_u64, v, orig); +} diff --git a/clang/test/CodeGenHLSL/builtins/RWBuffer-Interlocked.hlsl b/clang/test/CodeGenHLSL/builtins/RWBuffer-Interlocked.hlsl index d79e69a52f9c4..81c53ee4a5baa 100644 --- a/clang/test/CodeGenHLSL/builtins/RWBuffer-Interlocked.hlsl +++ b/clang/test/CodeGenHLSL/builtins/RWBuffer-Interlocked.hlsl @@ -11,11 +11,11 @@ // LangAS::hlsl_device branch of the dest-argument address-space check in // SemaHLSL and ensures the atomicrmw is emitted on the pointer returned by // resource.getpointer for a TypedBuffer (as opposed to the RawBuffer path -// covered by the ByteAddressBuffer tests). InterlockedMin is called once on -// a signed buffer and once on an unsigned buffer so that the signed/unsigned -// atomicrmw selection is pinned to an exactly-named resource handle type -// (spirv.SignedImage vs spirv.Image). Add new intrinsics here as more -// InterlockedX operations gain resource support. +// covered by the ByteAddressBuffer tests). InterlockedMin and InterlockedMax +// are each called once on a signed buffer and once on an unsigned buffer so +// that the signed/unsigned atomicrmw selection is pinned to an exactly-named +// resource handle type (spirv.SignedImage vs spirv.Image). Add new intrinsics +// here as more InterlockedX operations gain resource support. RWBuffer<int> Out : register(u0); RWBuffer<uint> UOut : register(u1); @@ -33,6 +33,10 @@ RWBuffer<uint> UOut : register(u1); // DXCHECK: atomicrmw umin ptr %[[PTR5]], i32 1 syncscope("device") monotonic // DXCHECK: %[[PTR6:.*]] = call {{.*}} @llvm.dx.resource.getpointer.p0.tdx.TypedBuffer_i32_1_0_1t.i32(target("dx.TypedBuffer", i32, 1, 0, 1) %{{.*}}, i32 %{{.*}}) // DXCHECK: atomicrmw and ptr %[[PTR6]], i32 1 syncscope("device") monotonic +// DXCHECK: %[[PTR7:.*]] = call {{.*}} @llvm.dx.resource.getpointer.p0.tdx.TypedBuffer_i32_1_0_1t.i32(target("dx.TypedBuffer", i32, 1, 0, 1) %{{.*}}, i32 %{{.*}}) +// DXCHECK: atomicrmw max ptr %[[PTR7]], i32 1 syncscope("device") monotonic +// DXCHECK: %[[PTR8:.*]] = call {{.*}} @llvm.dx.resource.getpointer.p0.tdx.TypedBuffer_i32_1_0_0t.i32(target("dx.TypedBuffer", i32, 1, 0, 0) %{{.*}}, i32 %{{.*}}) +// DXCHECK: atomicrmw umax ptr %[[PTR8]], i32 1 syncscope("device") monotonic // 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 %{{.*}}) @@ -45,6 +49,10 @@ RWBuffer<uint> UOut : register(u1); // SPVCHECK: atomicrmw umin ptr addrspace(11) %[[PTR5]], i32 1 syncscope("device") monotonic // SPVCHECK: %[[PTR6:.*]] = call {{.*}} @llvm.spv.resource.getpointer.{{.*}}(target("spirv.SignedImage", i32, {{.*}}) %{{.*}}, i32 %{{.*}}) // SPVCHECK: atomicrmw and ptr addrspace(11) %[[PTR6]], i32 1 syncscope("device") monotonic +// SPVCHECK: %[[PTR7:.*]] = call {{.*}} @llvm.spv.resource.getpointer.{{.*}}(target("spirv.SignedImage", i32, {{.*}}) %{{.*}}, i32 %{{.*}}) +// SPVCHECK: atomicrmw max ptr addrspace(11) %[[PTR7]], i32 1 syncscope("device") monotonic +// SPVCHECK: %[[PTR8:.*]] = call {{.*}} @llvm.spv.resource.getpointer.{{.*}}(target("spirv.Image", i32, {{.*}}) %{{.*}}, i32 %{{.*}}) +// SPVCHECK: atomicrmw umax ptr addrspace(11) %[[PTR8]], i32 1 syncscope("device") monotonic [shader("compute")] [numthreads(1,1,1)] void main(uint3 id : SV_DispatchThreadID) { @@ -54,4 +62,6 @@ void main(uint3 id : SV_DispatchThreadID) { InterlockedMin(Out[id.x], 1); InterlockedMin(UOut[id.x], 1u); InterlockedAnd(Out[id.x], 1); + InterlockedMax(Out[id.x], 1); + InterlockedMax(UOut[id.x], 1u); } diff --git a/clang/test/CodeGenHLSL/builtins/RWByteAddressBuffer-InterlockedMax.hlsl b/clang/test/CodeGenHLSL/builtins/RWByteAddressBuffer-InterlockedMax.hlsl new file mode 100644 index 0000000000000..80d38171313b3 --- /dev/null +++ b/clang/test/CodeGenHLSL/builtins/RWByteAddressBuffer-InterlockedMax.hlsl @@ -0,0 +1,92 @@ +// 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 signed and unsigned RWByteAddressBuffer::InterlockedMax and +// InterlockedMax64 methods lower through a resource pointer. + +RWByteAddressBuffer BAB : register(u0); + +// CHECK-LABEL: define {{.*}}void @{{.*}}test_bab_int +// DXCHECK: %[[PTR:.*]] = call ptr @llvm.dx.resource.getpointer.p0.tdx.RawBuffer_i8_1_0t.i32({{.*}}) +// DXCHECK: atomicrmw max ptr %[[PTR]], i32 %{{.*}} syncscope("device") monotonic +// SPVCHECK: %[[PTR:.*]] = call ptr addrspace(11) @llvm.spv.resource.getpointer.p11.tspirv.VulkanBuffer_a0i8_12_1t.i32({{.*}}) +// SPVCHECK: atomicrmw max ptr addrspace(11) %[[PTR]], i32 %{{.*}} syncscope("device") monotonic +export void test_bab_int(uint off, int v) { + BAB.InterlockedMax(off, v); +} + +// CHECK-LABEL: define {{.*}}void @{{.*}}test_bab_uint +// DXCHECK: %[[PTR:.*]] = call ptr @llvm.dx.resource.getpointer.p0.tdx.RawBuffer_i8_1_0t.i32({{.*}}) +// DXCHECK: atomicrmw umax ptr %[[PTR]], i32 %{{.*}} syncscope("device") monotonic +// SPVCHECK: %[[PTR:.*]] = call ptr addrspace(11) @llvm.spv.resource.getpointer.p11.tspirv.VulkanBuffer_a0i8_12_1t.i32({{.*}}) +// SPVCHECK: atomicrmw umax ptr addrspace(11) %[[PTR]], i32 %{{.*}} syncscope("device") monotonic +export void test_bab_uint(uint off, uint v) { + BAB.InterlockedMax(off, v); +} + +// CHECK-LABEL: define {{.*}}void @{{.*}}test_bab_int_orig +// DXCHECK: %[[PTR:.*]] = call ptr @llvm.dx.resource.getpointer.p0.tdx.RawBuffer_i8_1_0t.i32({{.*}}) +// DXCHECK: %[[R:.*]] = atomicrmw max ptr %[[PTR]], i32 %{{.*}} syncscope("device") monotonic +// DXCHECK: store i32 %[[R]], ptr {{.*}} +// SPVCHECK: %[[PTR:.*]] = call ptr addrspace(11) @llvm.spv.resource.getpointer.p11.tspirv.VulkanBuffer_a0i8_12_1t.i32({{.*}}) +// SPVCHECK: %[[R:.*]] = atomicrmw max ptr addrspace(11) %[[PTR]], i32 %{{.*}} syncscope("device") monotonic +// SPVCHECK: store i32 %[[R]], ptr {{.*}} +export void test_bab_int_orig(uint off, int v, out int orig) { + BAB.InterlockedMax(off, v, orig); +} + +// CHECK-LABEL: define {{.*}}void @{{.*}}test_bab_uint_orig +// DXCHECK: %[[PTR:.*]] = call ptr @llvm.dx.resource.getpointer.p0.tdx.RawBuffer_i8_1_0t.i32({{.*}}) +// DXCHECK: %[[R:.*]] = atomicrmw umax ptr %[[PTR]], i32 %{{.*}} syncscope("device") monotonic +// DXCHECK: store i32 %[[R]], ptr {{.*}} +// SPVCHECK: %[[PTR:.*]] = call ptr addrspace(11) @llvm.spv.resource.getpointer.p11.tspirv.VulkanBuffer_a0i8_12_1t.i32({{.*}}) +// SPVCHECK: %[[R:.*]] = atomicrmw umax ptr addrspace(11) %[[PTR]], i32 %{{.*}} syncscope("device") monotonic +// SPVCHECK: store i32 %[[R]], ptr {{.*}} +export void test_bab_uint_orig(uint off, uint v, out uint orig) { + BAB.InterlockedMax(off, v, orig); +} + +// CHECK-LABEL: define {{.*}}void @{{.*}}test_bab_int64 +// DXCHECK: %[[PTR:.*]] = call ptr @llvm.dx.resource.getpointer.p0.tdx.RawBuffer_i8_1_0t.i32({{.*}}) +// DXCHECK: atomicrmw max ptr %[[PTR]], i64 %{{.*}} syncscope("device") monotonic +// SPVCHECK: %[[PTR:.*]] = call ptr addrspace(11) @llvm.spv.resource.getpointer.p11.tspirv.VulkanBuffer_a0i8_12_1t.i32({{.*}}) +// SPVCHECK: atomicrmw max ptr addrspace(11) %[[PTR]], i64 %{{.*}} syncscope("device") monotonic +export void test_bab_int64(uint off, int64_t v) { + BAB.InterlockedMax64(off, v); +} + +// CHECK-LABEL: define {{.*}}void @{{.*}}test_bab_uint64 +// DXCHECK: %[[PTR:.*]] = call ptr @llvm.dx.resource.getpointer.p0.tdx.RawBuffer_i8_1_0t.i32({{.*}}) +// DXCHECK: atomicrmw umax ptr %[[PTR]], i64 %{{.*}} syncscope("device") monotonic +// SPVCHECK: %[[PTR:.*]] = call ptr addrspace(11) @llvm.spv.resource.getpointer.p11.tspirv.VulkanBuffer_a0i8_12_1t.i32({{.*}}) +// SPVCHECK: atomicrmw umax ptr addrspace(11) %[[PTR]], i64 %{{.*}} syncscope("device") monotonic +export void test_bab_uint64(uint off, uint64_t v) { + BAB.InterlockedMax64(off, v); +} + +// CHECK-LABEL: define {{.*}}void @{{.*}}test_bab_int64_orig +// DXCHECK: %[[PTR:.*]] = call ptr @llvm.dx.resource.getpointer.p0.tdx.RawBuffer_i8_1_0t.i32({{.*}}) +// DXCHECK: %[[R:.*]] = atomicrmw max ptr %[[PTR]], i64 %{{.*}} syncscope("device") monotonic +// DXCHECK: store i64 %[[R]], ptr {{.*}} +// SPVCHECK: %[[PTR:.*]] = call ptr addrspace(11) @llvm.spv.resource.getpointer.p11.tspirv.VulkanBuffer_a0i8_12_1t.i32({{.*}}) +// SPVCHECK: %[[R:.*]] = atomicrmw max ptr addrspace(11) %[[PTR]], i64 %{{.*}} syncscope("device") monotonic +// SPVCHECK: store i64 %[[R]], ptr {{.*}} +export void test_bab_int64_orig(uint off, int64_t v, out int64_t orig) { + BAB.InterlockedMax64(off, v, orig); +} + +// CHECK-LABEL: define {{.*}}void @{{.*}}test_bab_uint64_orig +// DXCHECK: %[[PTR:.*]] = call ptr @llvm.dx.resource.getpointer.p0.tdx.RawBuffer_i8_1_0t.i32({{.*}}) +// DXCHECK: %[[R:.*]] = atomicrmw umax ptr %[[PTR]], i64 %{{.*}} syncscope("device") monotonic +// DXCHECK: store i64 %[[R]], ptr {{.*}} +// SPVCHECK: %[[PTR:.*]] = call ptr addrspace(11) @llvm.spv.resource.getpointer.p11.tspirv.VulkanBuffer_a0i8_12_1t.i32({{.*}}) +// SPVCHECK: %[[R:.*]] = atomicrmw umax ptr addrspace(11) %[[PTR]], i64 %{{.*}} syncscope("device") monotonic +// SPVCHECK: store i64 %[[R]], ptr {{.*}} +export void test_bab_uint64_orig(uint off, uint64_t v, out uint64_t orig) { + BAB.InterlockedMax64(off, v, orig); +} diff --git a/clang/test/CodeGenHLSL/builtins/RasterizerOrderedByteAddressBuffer-InterlockedMax.hlsl b/clang/test/CodeGenHLSL/builtins/RasterizerOrderedByteAddressBuffer-InterlockedMax.hlsl new file mode 100644 index 0000000000000..d663444425106 --- /dev/null +++ b/clang/test/CodeGenHLSL/builtins/RasterizerOrderedByteAddressBuffer-InterlockedMax.hlsl @@ -0,0 +1,37 @@ +// 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. + +RasterizerOrderedByteAddressBuffer ROVB : register(u1); + +// CHECK-LABEL: define void @{{.*}}test_rovb_int +// DXCHECK: %[[PTR:.*]] = call ptr @llvm.dx.resource.getpointer.p0.tdx.RawBuffer_i8_1_1t.i32({{.*}}) +// DXCHECK: atomicrmw max ptr %[[PTR]], i32 %{{.*}} syncscope("device") monotonic +export void test_rovb_int(uint off, int v) { + ROVB.InterlockedMax(off, v); +} + +// CHECK-LABEL: define void @{{.*}}test_rovb_uint_orig +// DXCHECK: %[[PTR:.*]] = call ptr @llvm.dx.resource.getpointer.p0.tdx.RawBuffer_i8_1_1t.i32({{.*}}) +// DXCHECK: %[[R:.*]] = atomicrmw umax ptr %[[PTR]], i32 %{{.*}} syncscope("device") monotonic +// DXCHECK: store i32 %[[R]], ptr {{.*}} +export void test_rovb_uint_orig(uint off, uint v, out uint orig) { + ROVB.InterlockedMax(off, v, orig); +} + +// CHECK-LABEL: define void @{{.*}}test_rovb_int64 +// DXCHECK: %[[PTR:.*]] = call ptr @llvm.dx.resource.getpointer.p0.tdx.RawBuffer_i8_1_1t.i32({{.*}}) +// DXCHECK: atomicrmw max ptr %[[PTR]], i64 %{{.*}} syncscope("device") monotonic +export void test_rovb_int64(uint off, int64_t v) { + ROVB.InterlockedMax64(off, v); +} + +// CHECK-LABEL: define void @{{.*}}test_rovb_uint64_orig +// DXCHECK: %[[PTR:.*]] = call ptr @llvm.dx.resource.getpointer.p0.tdx.RawBuffer_i8_1_1t.i32({{.*}}) +// DXCHECK: %[[R:.*]] = atomicrmw umax ptr %[[PTR]], i64 %{{.*}} syncscope("device") monotonic +// DXCHECK: store i64 %[[R]], ptr {{.*}} +export void test_rovb_uint64_orig(uint off, uint64_t v, out uint64_t orig) { + ROVB.InterlockedMax64(off, v, orig); +} diff --git a/clang/test/SemaHLSL/BuiltIns/ByteAddressBuffer-InterlockedMax-errors.hlsl b/clang/test/SemaHLSL/BuiltIns/ByteAddressBuffer-InterlockedMax-errors.hlsl new file mode 100644 index 0000000000000..2ec7cc6e69ba4 --- /dev/null +++ b/clang/test/SemaHLSL/BuiltIns/ByteAddressBuffer-InterlockedMax-errors.hlsl @@ -0,0 +1,34 @@ +// RUN: %clang_cc1 -std=hlsl202x -finclude-default-header \ +// RUN: -triple dxil-pc-shadermodel6.6-library %s -fsyntax-only -verify \ +// RUN: -verify-ignore-unexpected=note,warning + +RWByteAddressBuffer BAB : register(u0); +RasterizerOrderedByteAddressBuffer ROVB : register(u1); + +struct S { int x; }; + +void too_few(uint off) { + BAB.InterlockedMax(off); + // expected-error@-1 {{no matching member function for call to 'InterlockedMax'}} +} + +void too_many(uint off, int v, int extra) { + int orig; + BAB.InterlockedMax(off, v, orig, extra); + // expected-error@-1 {{no matching member function for call to 'InterlockedMax'}} +} + +void struct_value(uint off, S v) { + BAB.InterlockedMax(off, v); + // expected-error@-1 {{no matching member function for call to 'InterlockedMax'}} +} + +void rovb_too_few(uint off) { + ROVB.InterlockedMax(off); + // expected-error@-1 {{no matching member function for call to 'InterlockedMax'}} +} + +void rovb_struct_value(uint off, S v) { + ROVB.InterlockedMax(off, v); + // expected-error@-1 {{no matching member function for call to 'InterlockedMax'}} +} diff --git a/clang/test/SemaHLSL/BuiltIns/ByteAddressBuffer-InterlockedMax-sm65-errors.hlsl b/clang/test/SemaHLSL/BuiltIns/ByteAddressBuffer-InterlockedMax-sm65-errors.hlsl new file mode 100644 index 0000000000000..4694d81e5b24b --- /dev/null +++ b/clang/test/SemaHLSL/BuiltIns/ByteAddressBuffer-InterlockedMax-sm65-errors.hlsl @@ -0,0 +1,26 @@ +// RUN: %clang_cc1 -std=hlsl202x -finclude-default-header \ +// RUN: -triple dxil-pc-shadermodel6.5-library %s -fsyntax-only -verify \ +// RUN: -verify-ignore-unexpected=warning + +RWByteAddressBuffer BAB : register(u0); +RasterizerOrderedByteAddressBuffer ROVB : register(u1); + +void sm65_no_bab_max64(uint off, int64_t v) { + BAB.InterlockedMax64(off, v); + // expected-error@-1 {{no member named 'InterlockedMax64' in 'hlsl::RWByteAddressBuffer'}} +} + +void sm65_no_rovb_max64(uint off, int64_t v) { + ROVB.InterlockedMax64(off, v); + // expected-error@-1 {{no member named 'InterlockedMax64' in 'hlsl::RasterizerOrderedByteAddressBuffer'}} +} + +void sm65_bab_max32_ok(uint off, int v) { + BAB.InterlockedMax(off, v); +} + +groupshared int64_t gs_i64; +void sm65_direct_builtin(int64_t v) { + __builtin_hlsl_interlocked_max(gs_i64, v); + // expected-error@-1 {{'__builtin_hlsl_interlocked_max' requires shader model 6.6 or newer}} +} diff --git a/clang/test/SemaHLSL/BuiltIns/InterlockedMax-errors.hlsl b/clang/test/SemaHLSL/BuiltIns/InterlockedMax-errors.hlsl new file mode 100644 index 0000000000000..9f563d5e2ac38 --- /dev/null +++ b/clang/test/SemaHLSL/BuiltIns/InterlockedMax-errors.hlsl @@ -0,0 +1,89 @@ +// RUN: %clang_cc1 -std=hlsl202x -finclude-default-header \ +// RUN: -triple dxil-pc-shadermodel6.6-library %s -emit-llvm-only \ +// RUN: -disable-llvm-passes -verify + +// InterlockedMax is provided as a set of address-space-qualified overloads +// (groupshared/device, {int,uint,int64_t,uint64_t}, 2-arg/3-arg). + +groupshared int gs_i32; +groupshared float gs_f32; +struct S { int x; }; +groupshared S gs_s; + +void too_few() { + InterlockedMax(gs_i32); // expected-error{{no matching function for call to 'InterlockedMax'}} + // expected-note@*:* 16 {{candidate function}} +} + +void too_many(int v, int extra) { + int orig; + InterlockedMax(gs_i32, v, orig, extra); // expected-error{{no matching function for call to 'InterlockedMax'}} + // expected-note@*:* 16 {{candidate function}} +} + +void local_dest(int v) { + int dest; + InterlockedMax(dest, v); // expected-error{{no matching function for call to 'InterlockedMax'}} + // expected-note@*:* 16 {{candidate function}} +} + +void float_dest(float v) { + InterlockedMax(gs_f32, v); // expected-error{{no matching function for call to 'InterlockedMax'}} + // expected-note@*:* 16 {{candidate function}} +} + +void struct_dest(int v) { + InterlockedMax(gs_s, v); // expected-error{{no matching function for call to 'InterlockedMax'}} + // expected-note@*:* 16 {{candidate function}} +} + +void mismatched_orig_type(int v) { + uint orig; + InterlockedMax(gs_i32, v, orig); // expected-error{{no matching function for call to 'InterlockedMax'}} + // expected-note@*:* 16 {{candidate function}} +} + +void direct_too_few() { + __builtin_hlsl_interlocked_max(gs_i32); + // expected-error@-1 {{too few arguments to function call, expected at least 2, have 1}} +} + +void direct_too_many(int v, int extra) { + int orig; + __builtin_hlsl_interlocked_max(gs_i32, v, orig, extra); + // expected-error@-1 {{too many arguments to function call, expected at most 3, have 4}} +} + +void direct_non_integer_dest() { + S local_s; + __builtin_hlsl_interlocked_max(local_s, 1); + // expected-error@-1 {{1st argument must be a scalar integer type (was 'S')}} +} + +void direct_nonlvalue_dest(int v) { + __builtin_hlsl_interlocked_max(1, v); + // expected-error@-1 {{cannot bind non-lvalue argument '1' to out parameter}} +} + +void direct_mismatched_value() { + uint value = 1; + __builtin_hlsl_interlocked_max(gs_i32, value); + // expected-error@-1 {{passing 'uint' (aka 'unsigned int') to parameter of incompatible type 'int'}} +} + +void direct_mismatched_orig(int v) { + uint orig; + __builtin_hlsl_interlocked_max(gs_i32, v, orig); + // expected-error@-1 {{passing 'uint' (aka 'unsigned int') to parameter of incompatible type 'int'}} +} + +void direct_nonlvalue_orig(int v) { + __builtin_hlsl_interlocked_max(gs_i32, v, 1); + // expected-error@-1 {{cannot bind non-lvalue argument '1' to out parameter}} +} + +void direct_default_as_dest(int v) { + int local; + __builtin_hlsl_interlocked_max(local, v); + // expected-error@-1 {{1st argument to atomic builtin must reference groupshared or device memory (was 'int')}} +} _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
