https://github.com/bob80905 updated 
https://github.com/llvm/llvm-project/pull/219317

>From aaab76de2b84dbdbce9eb2e242d5fc1ea69c8356 Mon Sep 17 00:00:00 2001
From: Joshua Batista <[email protected]>
Date: Thu, 27 Aug 2026 15:24:52 -0700
Subject: [PATCH 1/2] first attempt

---
 clang/include/clang/Basic/Builtins.td         |   6 ++
 clang/lib/CodeGen/CGHLSLBuiltins.cpp          |   3 +
 clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp |   5 +
 clang/lib/Sema/HLSLExternalSemaSource.cpp     |   2 +
 clang/lib/Sema/SemaHLSL.cpp                   |   1 +
 .../CodeGenHLSL/builtins/InterlockedAnd.hlsl  |  59 +++++++++++
 .../builtins/RWBuffer-Interlocked.hlsl        |   5 +
 .../RWByteAddressBuffer-InterlockedAnd.hlsl   |  62 +++++++++++
 ...deredByteAddressBuffer-InterlockedAnd.hlsl |  45 ++++++++
 .../BuiltIns/InterlockedAnd-errors.hlsl       | 100 ++++++++++++++++++
 10 files changed, 288 insertions(+)
 create mode 100644 clang/test/CodeGenHLSL/builtins/InterlockedAnd.hlsl
 create mode 100644 
clang/test/CodeGenHLSL/builtins/RWByteAddressBuffer-InterlockedAnd.hlsl
 create mode 100644 
clang/test/CodeGenHLSL/builtins/RasterizerOrderedByteAddressBuffer-InterlockedAnd.hlsl
 create mode 100644 clang/test/SemaHLSL/BuiltIns/InterlockedAnd-errors.hlsl

diff --git a/clang/include/clang/Basic/Builtins.td 
b/clang/include/clang/Basic/Builtins.td
index 0aec57f201301..c919f762ee34a 100644
--- a/clang/include/clang/Basic/Builtins.td
+++ b/clang/include/clang/Basic/Builtins.td
@@ -5551,6 +5551,12 @@ def HLSLInterlockedAdd : LangBuiltin<"HLSL_LANG"> {
   let Prototype = "void (...)";
 }
 
+def HLSLInterlockedAnd : LangBuiltin<"HLSL_LANG"> {
+  let Spellings = ["__builtin_hlsl_interlocked_and"];
+  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 8d74e7652ff49..14b8fd13104b6 100644
--- a/clang/lib/CodeGen/CGHLSLBuiltins.cpp
+++ b/clang/lib/CodeGen/CGHLSLBuiltins.cpp
@@ -1458,6 +1458,9 @@ Value *CodeGenFunction::EmitHLSLBuiltinExpr(unsigned 
BuiltinID,
     // selectAtomicRMW). No intermediate intrinsic.
     return handleInterlockedOp(*this, E, llvm::AtomicRMWInst::Add);
   }
+  case Builtin::BI__builtin_hlsl_interlocked_and: {
+    return handleInterlockedOp(*this, E, llvm::AtomicRMWInst::And);
+  }
   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 35caa0a740235..2606b7a692d2e 100644
--- a/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp
+++ b/clang/lib/Sema/HLSLBuiltinTypeDeclBuilder.cpp
@@ -1727,6 +1727,8 @@ 
BuiltinTypeDeclBuilder::addByteAddressBufferInterlockedMethods() {
   // original-value parameter for each entry.
   addByteAddressBufferInterlockedMethod("InterlockedAdd", AST.UnsignedIntTy,
                                         "__builtin_hlsl_interlocked_add");
+  addByteAddressBufferInterlockedMethod("InterlockedAnd", AST.UnsignedIntTy,
+                                        "__builtin_hlsl_interlocked_and");
   addByteAddressBufferInterlockedMethod("InterlockedMin", AST.IntTy,
                                         "__builtin_hlsl_interlocked_min");
   addByteAddressBufferInterlockedMethod("InterlockedMin", AST.UnsignedIntTy,
@@ -1746,6 +1748,9 @@ 
BuiltinTypeDeclBuilder::addByteAddressBufferInterlockedMethods() {
     addByteAddressBufferInterlockedMethod("InterlockedAdd64",
                                           AST.UnsignedLongTy,
                                           "__builtin_hlsl_interlocked_add");
+    addByteAddressBufferInterlockedMethod("InterlockedAnd64",
+                                          AST.UnsignedLongTy,
+                                          "__builtin_hlsl_interlocked_and");
     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 f8fe990210fbb..939e4c9222e2d 100644
--- a/clang/lib/Sema/HLSLExternalSemaSource.cpp
+++ b/clang/lib/Sema/HLSLExternalSemaSource.cpp
@@ -881,6 +881,8 @@ static void defineHLSLInterlockedFunc(Sema &S, 
NamespaceDecl *NS,
 void HLSLExternalSemaSource::defineHLSLAtomicIntrinsics() {
   defineHLSLInterlockedFunc(*SemaPtr, HLSLNamespace, "InterlockedAdd",
                             "__builtin_hlsl_interlocked_add");
+  defineHLSLInterlockedFunc(*SemaPtr, HLSLNamespace, "InterlockedAnd",
+                            "__builtin_hlsl_interlocked_and");
   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 99c2191ec3787..1665fb65901f8 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -4711,6 +4711,7 @@ bool SemaHLSL::CheckBuiltinFunctionCall(unsigned 
BuiltinID, CallExpr *TheCall) {
     break;
   }
   case Builtin::BI__builtin_hlsl_interlocked_add:
+  case Builtin::BI__builtin_hlsl_interlocked_and:
   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/InterlockedAnd.hlsl 
b/clang/test/CodeGenHLSL/builtins/InterlockedAnd.hlsl
new file mode 100644
index 0000000000000..ac712a1489c8f
--- /dev/null
+++ b/clang/test/CodeGenHLSL/builtins/InterlockedAnd.hlsl
@@ -0,0 +1,59 @@
+// 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 InterlockedAnd to `atomicrmw and monotonic`.
+
+groupshared int  gs_i32;
+groupshared uint gs_u32;
+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 and ptr addrspace(3) {{.*}}@gs_i32{{.*}}, i32 %{{.*}} 
syncscope("workgroup") monotonic
+// SPVCHECK: atomicrmw and ptr addrspace(3) {{.*}}@gs_i32{{.*}}, i32 %{{.*}} 
syncscope("workgroup") monotonic
+export void test_int_2arg(int v) {
+  InterlockedAnd(gs_i32, v);
+}
+
+// CHECK-LABEL: define {{(dso_local |hidden |internal |protected |spir_func 
)*}}void @{{.*}}test_uint_2arg
+// DXCHECK:  atomicrmw and ptr addrspace(3) {{.*}}@gs_u32{{.*}}, i32 %{{.*}} 
syncscope("workgroup") monotonic
+// SPVCHECK: atomicrmw and ptr addrspace(3) {{.*}}@gs_u32{{.*}}, i32 %{{.*}} 
syncscope("workgroup") monotonic
+export void test_uint_2arg(uint v) {
+  InterlockedAnd(gs_u32, v);
+}
+
+// CHECK-LABEL: define {{(dso_local |hidden |internal |protected |spir_func 
)*}}void @{{.*}}test_int_3arg
+// DXCHECK:  %[[R:.*]] = atomicrmw and ptr addrspace(3) {{.*}}@gs_i32{{.*}}, 
i32 %{{.*}} syncscope("workgroup") monotonic
+// SPVCHECK: %[[R:.*]] = atomicrmw and ptr addrspace(3) {{.*}}@gs_i32{{.*}}, 
i32 %{{.*}} syncscope("workgroup") monotonic
+// CHECK:    store i32 %[[R]], ptr {{.*}}
+export void test_int_3arg(int v, out int orig) {
+  InterlockedAnd(gs_i32, v, orig);
+}
+
+// CHECK-LABEL: define {{(dso_local |hidden |internal |protected |spir_func 
)*}}void @{{.*}}test_uint_3arg
+// DXCHECK:  %[[R:.*]] = atomicrmw and ptr addrspace(3) {{.*}}@gs_u32{{.*}}, 
i32 %{{.*}} syncscope("workgroup") monotonic
+// SPVCHECK: %[[R:.*]] = atomicrmw and ptr addrspace(3) {{.*}}@gs_u32{{.*}}, 
i32 %{{.*}} syncscope("workgroup") monotonic
+// CHECK:    store i32 %[[R]], ptr {{.*}}
+export void test_uint_3arg(uint v, out uint orig) {
+  InterlockedAnd(gs_u32, v, orig);
+}
+
+// CHECK-LABEL: define {{(dso_local |hidden |internal |protected |spir_func 
)*}}void @{{.*}}test_int64_2arg
+// DXCHECK:  atomicrmw and ptr addrspace(3) {{.*}}@gs_i64{{.*}}, i64 %{{.*}} 
syncscope("workgroup") monotonic
+// SPVCHECK: atomicrmw and ptr addrspace(3) {{.*}}@gs_i64{{.*}}, i64 %{{.*}} 
syncscope("workgroup") monotonic
+export void test_int64_2arg(int64_t v) {
+  InterlockedAnd(gs_i64, v);
+}
+
+// CHECK-LABEL: define {{(dso_local |hidden |internal |protected |spir_func 
)*}}void @{{.*}}test_uint64_3arg
+// DXCHECK:  %[[R:.*]] = atomicrmw and ptr addrspace(3) {{.*}}@gs_u64{{.*}}, 
i64 %{{.*}} syncscope("workgroup") monotonic
+// SPVCHECK: %[[R:.*]] = atomicrmw and 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) {
+  InterlockedAnd(gs_u64, v, orig);
+}
diff --git a/clang/test/CodeGenHLSL/builtins/RWBuffer-Interlocked.hlsl 
b/clang/test/CodeGenHLSL/builtins/RWBuffer-Interlocked.hlsl
index 980bee046aefa..d79e69a52f9c4 100644
--- a/clang/test/CodeGenHLSL/builtins/RWBuffer-Interlocked.hlsl
+++ b/clang/test/CodeGenHLSL/builtins/RWBuffer-Interlocked.hlsl
@@ -31,6 +31,8 @@ RWBuffer<uint> UOut : register(u1);
 // DXCHECK:  atomicrmw min ptr %[[PTR4]], i32 1 syncscope("device") monotonic
 // DXCHECK:  %[[PTR5:.*]] = call {{.*}} 
@llvm.dx.resource.getpointer.p0.tdx.TypedBuffer_i32_1_0_0t.i32(target("dx.TypedBuffer",
 i32, 1, 0, 0) %{{.*}}, i32 %{{.*}})
 // 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
 // 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 %{{.*}})
@@ -41,6 +43,8 @@ RWBuffer<uint> UOut : register(u1);
 // SPVCHECK: atomicrmw min ptr addrspace(11) %[[PTR4]], i32 1 
syncscope("device") monotonic
 // SPVCHECK: %[[PTR5:.*]] = call {{.*}} 
@llvm.spv.resource.getpointer.{{.*}}(target("spirv.Image", i32, {{.*}}) 
%{{.*}}, i32 %{{.*}})
 // 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
 [shader("compute")]
 [numthreads(1,1,1)]
 void main(uint3 id : SV_DispatchThreadID) {
@@ -49,4 +53,5 @@ void main(uint3 id : SV_DispatchThreadID) {
   InterlockedXor(Out[id.x], 1);
   InterlockedMin(Out[id.x], 1);
   InterlockedMin(UOut[id.x], 1u);
+  InterlockedAnd(Out[id.x], 1);
 }
diff --git 
a/clang/test/CodeGenHLSL/builtins/RWByteAddressBuffer-InterlockedAnd.hlsl 
b/clang/test/CodeGenHLSL/builtins/RWByteAddressBuffer-InterlockedAnd.hlsl
new file mode 100644
index 0000000000000..f6f19f0580523
--- /dev/null
+++ b/clang/test/CodeGenHLSL/builtins/RWByteAddressBuffer-InterlockedAnd.hlsl
@@ -0,0 +1,62 @@
+// 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::InterlockedAnd and InterlockedAnd64
+// member methods lower to `resource_getpointer -> atomicrmw and`, and that
+// the 3-argument overload stores the returned original value through the
+// out parameter, for both DXIL and SPIR-V targets.
+
+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 and 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 and ptr addrspace(11) %[[PTR]], i32 %{{.*}} 
syncscope("device") monotonic
+export void test_bab_int_2arg(uint off, int v) {
+  BAB.InterlockedAnd(off, 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 and 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 and 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.InterlockedAnd(off, v, 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 and 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 and ptr addrspace(11) %[[PTR]], i64 %{{.*}} 
syncscope("device") monotonic
+export void test_bab_int64_2arg(uint off, int64_t v) {
+  BAB.InterlockedAnd64(off, 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 and 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 and 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.InterlockedAnd64(off, v, orig);
+}
diff --git 
a/clang/test/CodeGenHLSL/builtins/RasterizerOrderedByteAddressBuffer-InterlockedAnd.hlsl
 
b/clang/test/CodeGenHLSL/builtins/RasterizerOrderedByteAddressBuffer-InterlockedAnd.hlsl
new file mode 100644
index 0000000000000..8820c2004c5c6
--- /dev/null
+++ 
b/clang/test/CodeGenHLSL/builtins/RasterizerOrderedByteAddressBuffer-InterlockedAnd.hlsl
@@ -0,0 +1,45 @@
+// 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_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 and ptr %[[PTR]], i32 %{{.*}} syncscope("device") 
monotonic
+export void test_rovb_int_2arg(uint off, int v) {
+  ROVB.InterlockedAnd(off, 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 and 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.InterlockedAnd(off, v, 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 and ptr %[[PTR]], i64 %{{.*}} syncscope("device") 
monotonic
+export void test_rovb_int64_2arg(uint off, int64_t v) {
+  ROVB.InterlockedAnd64(off, 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 and 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.InterlockedAnd64(off, v, orig);
+}
diff --git a/clang/test/SemaHLSL/BuiltIns/InterlockedAnd-errors.hlsl 
b/clang/test/SemaHLSL/BuiltIns/InterlockedAnd-errors.hlsl
new file mode 100644
index 0000000000000..6674d7140a44f
--- /dev/null
+++ b/clang/test/SemaHLSL/BuiltIns/InterlockedAnd-errors.hlsl
@@ -0,0 +1,100 @@
+// RUN: %clang_cc1 -std=hlsl202x -finclude-default-header \
+// RUN:   -triple dxil-pc-shadermodel6.6-library %s -emit-llvm-only \
+// RUN:   -disable-llvm-passes -verify
+
+// InterlockedAnd is provided as a set of address-space-qualified overloads
+// (groupshared/device, {int,uint,int64_t,uint64_t}, 2-arg/3-arg). All arg
+// mismatches surface as "no matching function" with 16 candidates. The
+// candidate notes come from synthesized FunctionDecls with no source
+// location, so they are matched with `@*:*`.
+
+groupshared int   gs_i32;
+groupshared float gs_f32;
+struct S { int x; };
+groupshared S     gs_s;
+
+void too_few(int v) {
+  InterlockedAnd(gs_i32); // expected-error{{no matching function for call to 
'InterlockedAnd'}}
+  // expected-note@*:* 16 {{candidate function}}
+}
+
+void too_many(int v, int extra) {
+  int o;
+  InterlockedAnd(gs_i32, v, o, extra); // expected-error{{no matching function 
for call to 'InterlockedAnd'}}
+  // expected-note@*:* 16 {{candidate function}}
+}
+
+// Atomics must operate on actual addresses in groupshared or device memory;
+// passing a plain local (no address space) must not bind to any overload.
+void local_dest(int v) {
+  int dest;
+  InterlockedAnd(dest, v); // expected-error{{no matching function for call to 
'InterlockedAnd'}}
+  // expected-note@*:* 16 {{candidate function}}
+}
+
+void float_dest(float v) {
+  InterlockedAnd(gs_f32, v); // expected-error{{no matching function for call 
to 'InterlockedAnd'}}
+  // expected-note@*:* 16 {{candidate function}}
+}
+
+void struct_dest(int v) {
+  InterlockedAnd(gs_s, v); // expected-error{{no matching function for call to 
'InterlockedAnd'}}
+  // expected-note@*:* 16 {{candidate function}}
+}
+
+void mismatched_orig_type(int v) {
+  uint orig;
+  InterlockedAnd(gs_i32, v, orig); // expected-error{{no matching function for 
call to 'InterlockedAnd'}}
+  // expected-note@*:* 16 {{candidate function}}
+}
+
+// The tests below exercise direct invocations of the underlying clang builtin
+// `__builtin_hlsl_interlocked_and`. These bypass overload resolution against
+// the synthesized `InterlockedAnd` overload set (the builtin's prototype in
+// Builtins.td is `void (...)`), so each error is produced by the explicit
+// checks in SemaHLSL.cpp rather than by candidate-set rejection.
+
+void direct_too_few() {
+  __builtin_hlsl_interlocked_and(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 o;
+  __builtin_hlsl_interlocked_and(gs_i32, v, o, 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_and(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_and(1, v);
+  // expected-error@-1 {{cannot bind non-lvalue argument '1' to out parameter}}
+}
+
+void direct_mismatched_value() {
+  uint uv = 1u;
+  __builtin_hlsl_interlocked_and(gs_i32, uv);
+  // 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_and(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_and(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_and(local, v);
+  // expected-error@-1 {{1st argument to atomic builtin must reference 
groupshared or device memory (was 'int')}}
+}

>From 3bbad477dc6b1c246af1f8ecb786cc7c85e96221 Mon Sep 17 00:00:00 2001
From: Joshua Batista <[email protected]>
Date: Thu, 27 Aug 2026 15:47:56 -0700
Subject: [PATCH 2/2] test quality improvement

---
 .../BuiltIns/InterlockedAnd-errors.hlsl       | 31 ++++++-------------
 1 file changed, 10 insertions(+), 21 deletions(-)

diff --git a/clang/test/SemaHLSL/BuiltIns/InterlockedAnd-errors.hlsl 
b/clang/test/SemaHLSL/BuiltIns/InterlockedAnd-errors.hlsl
index 6674d7140a44f..3ddd14bd15e01 100644
--- a/clang/test/SemaHLSL/BuiltIns/InterlockedAnd-errors.hlsl
+++ b/clang/test/SemaHLSL/BuiltIns/InterlockedAnd-errors.hlsl
@@ -3,29 +3,24 @@
 // RUN:   -disable-llvm-passes -verify
 
 // InterlockedAnd is provided as a set of address-space-qualified overloads
-// (groupshared/device, {int,uint,int64_t,uint64_t}, 2-arg/3-arg). All arg
-// mismatches surface as "no matching function" with 16 candidates. The
-// candidate notes come from synthesized FunctionDecls with no source
-// location, so they are matched with `@*:*`.
+// (groupshared/device, {int,uint,int64_t,uint64_t}, 2-arg/3-arg).
 
-groupshared int   gs_i32;
+groupshared int gs_i32;
 groupshared float gs_f32;
 struct S { int x; };
-groupshared S     gs_s;
+groupshared S gs_s;
 
-void too_few(int v) {
+void too_few() {
   InterlockedAnd(gs_i32); // expected-error{{no matching function for call to 
'InterlockedAnd'}}
   // expected-note@*:* 16 {{candidate function}}
 }
 
 void too_many(int v, int extra) {
-  int o;
-  InterlockedAnd(gs_i32, v, o, extra); // expected-error{{no matching function 
for call to 'InterlockedAnd'}}
+  int orig;
+  InterlockedAnd(gs_i32, v, orig, extra); // expected-error{{no matching 
function for call to 'InterlockedAnd'}}
   // expected-note@*:* 16 {{candidate function}}
 }
 
-// Atomics must operate on actual addresses in groupshared or device memory;
-// passing a plain local (no address space) must not bind to any overload.
 void local_dest(int v) {
   int dest;
   InterlockedAnd(dest, v); // expected-error{{no matching function for call to 
'InterlockedAnd'}}
@@ -48,20 +43,14 @@ void mismatched_orig_type(int v) {
   // expected-note@*:* 16 {{candidate function}}
 }
 
-// The tests below exercise direct invocations of the underlying clang builtin
-// `__builtin_hlsl_interlocked_and`. These bypass overload resolution against
-// the synthesized `InterlockedAnd` overload set (the builtin's prototype in
-// Builtins.td is `void (...)`), so each error is produced by the explicit
-// checks in SemaHLSL.cpp rather than by candidate-set rejection.
-
 void direct_too_few() {
   __builtin_hlsl_interlocked_and(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 o;
-  __builtin_hlsl_interlocked_and(gs_i32, v, o, extra);
+  int orig;
+  __builtin_hlsl_interlocked_and(gs_i32, v, orig, extra);
   // expected-error@-1 {{too many arguments to function call, expected at most 
3, have 4}}
 }
 
@@ -77,8 +66,8 @@ void direct_nonlvalue_dest(int v) {
 }
 
 void direct_mismatched_value() {
-  uint uv = 1u;
-  __builtin_hlsl_interlocked_and(gs_i32, uv);
+  uint value = 1;
+  __builtin_hlsl_interlocked_and(gs_i32, value);
   // expected-error@-1 {{passing 'uint' (aka 'unsigned int') to parameter of 
incompatible type 'int'}}
 }
 

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to