https://github.com/inbelic updated 
https://github.com/llvm/llvm-project/pull/205433

>From af6351c4ab34c7f7399a1843916b1ea94cf6a683 Mon Sep 17 00:00:00 2001
From: Finn Plummer <[email protected]>
Date: Tue, 23 Jun 2026 20:44:24 +0000
Subject: [PATCH 1/5] Revert "[DirectX] Denote `dx.resource.getpointer` with
 `IntrInaccessibleMemOnly` and `IntrReadMem` (#193593)"

This reverts commit 63e36755decfc92ee5e457c292aeeb0a69cfa484.
---
 llvm/include/llvm/IR/IntrinsicsDirectX.td     |  2 +-
 .../DirectX/getpointer-sink-behavior.ll       | 31 -------------------
 .../Transforms/GVN/no-sink-dxgetpointer.ll    |  5 ++-
 .../DirectX/no-sink-dxgetpointer.ll           |  6 ++--
 4 files changed, 6 insertions(+), 38 deletions(-)
 delete mode 100644 llvm/test/Transforms/DirectX/getpointer-sink-behavior.ll

diff --git a/llvm/include/llvm/IR/IntrinsicsDirectX.td 
b/llvm/include/llvm/IR/IntrinsicsDirectX.td
index af360dfc78965..fed15deb46b77 100644
--- a/llvm/include/llvm/IR/IntrinsicsDirectX.td
+++ b/llvm/include/llvm/IR/IntrinsicsDirectX.td
@@ -38,7 +38,7 @@ def int_dx_resource_handlefromimplicitbinding
 
 def int_dx_resource_getpointer
     : DefaultAttrsIntrinsic<[llvm_anyptr_ty], [llvm_any_ty, llvm_any_ty],
-                            [IntrReadMem, IntrInaccessibleMemOnly]>;
+                            [IntrConvergent, IntrNoMem]>;
 
 def int_dx_resource_getbasepointer
     : DefaultAttrsIntrinsic<[llvm_anyptr_ty], [llvm_any_ty],
diff --git a/llvm/test/Transforms/DirectX/getpointer-sink-behavior.ll 
b/llvm/test/Transforms/DirectX/getpointer-sink-behavior.ll
deleted file mode 100644
index de509fd0ca9fa..0000000000000
--- a/llvm/test/Transforms/DirectX/getpointer-sink-behavior.ll
+++ /dev/null
@@ -1,31 +0,0 @@
-; NOTE: Assertions have been autogenerated by utils/update_test_checks.py 
UTC_ARGS: --version 6
-; RUN: opt -passes=sink -S %s | FileCheck %s
-
-; Verify that dx.resource.getpointer can be sunk into a branch where it is
-; only used.
-
-define void @can_sink_into_branch(i1 %cond) {
-; CHECK-LABEL: define void @can_sink_into_branch(
-; CHECK-SAME: i1 [[COND:%.*]]) {
-; CHECK-NEXT:  [[ENTRY:.*:]]
-; CHECK-NEXT:    br i1 [[COND]], label %[[IF_THEN:.*]], label %[[IF_END:.*]]
-; CHECK:       [[IF_THEN]]:
-; CHECK-NEXT:    [[BUF:%.*]] = call target("dx.RawBuffer", i32, 1, 0) 
@llvm.dx.resource.handlefrombinding.tdx.RawBuffer_i32_1_0t(i32 0, i32 0, i32 1, 
i32 0, ptr null)
-; CHECK-NEXT:    [[PTR:%.*]] = call noundef nonnull align 4 dereferenceable(4) 
ptr 
@llvm.dx.resource.getpointer.p0.tdx.RawBuffer_i32_1_0t.i32(target("dx.RawBuffer",
 i32, 1, 0) [[BUF]], i32 0)
-; CHECK-NEXT:    store i32 42, ptr [[PTR]], align 4
-; CHECK-NEXT:    br label %[[IF_END]]
-; CHECK:       [[IF_END]]:
-; CHECK-NEXT:    ret void
-;
-entry:
-  %buf = call target("dx.RawBuffer", i32, 1, 0) 
@llvm.dx.resource.handlefrombinding.tdx.RawBuffer_i32_1_0t(i32 0, i32 0, i32 1, 
i32 0, ptr null)
-  %ptr = call noundef nonnull align 4 dereferenceable(4) ptr 
@llvm.dx.resource.getpointer.p0.tdx.RawBuffer_i32_1_0t.i32(target("dx.RawBuffer",
 i32, 1, 0) %buf, i32 0)
-  br i1 %cond, label %if.then, label %if.end
-
-if.then:
-  store i32 42, ptr %ptr, align 4
-  br label %if.end
-
-if.end:
-  ret void
-}
diff --git a/llvm/test/Transforms/GVN/no-sink-dxgetpointer.ll 
b/llvm/test/Transforms/GVN/no-sink-dxgetpointer.ll
index eeaead53f893a..2d5a07562f4a4 100644
--- a/llvm/test/Transforms/GVN/no-sink-dxgetpointer.ll
+++ b/llvm/test/Transforms/GVN/no-sink-dxgetpointer.ll
@@ -1,9 +1,8 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py 
UTC_ARGS: --version 6
 ; RUN: opt -passes=gvn -passes=instnamer -S %s | FileCheck %s
 
-; This test ensures that given dx.resource.getpointer reads inaccessible 
memory,
-; the GVN pass is prevented from sinking these intrinsics out of branches which
-; would create phi nodes on the returned ptr.
+; This test ensures that given dx.resource.getpointer is marked convergent, the
+; GVN pass is prevented from sinking these intrinsics.
 ;
 ; NOTE: The following ir represents case F and G from:
 ; https://godbolt.org/z/cK4xh1P49.
diff --git a/llvm/test/Transforms/SimplifyCFG/DirectX/no-sink-dxgetpointer.ll 
b/llvm/test/Transforms/SimplifyCFG/DirectX/no-sink-dxgetpointer.ll
index 576acce2b8dd2..038b25d765d6f 100644
--- a/llvm/test/Transforms/SimplifyCFG/DirectX/no-sink-dxgetpointer.ll
+++ b/llvm/test/Transforms/SimplifyCFG/DirectX/no-sink-dxgetpointer.ll
@@ -1,9 +1,9 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py 
UTC_ARGS: --version 6
 ; RUN: opt -passes=simplifycfg -passes=instnamer -S %s | FileCheck %s
 
-; This test ensures that given dx.resource.getpointer reads inaccessible 
memory,
-; the SimplifyCFG pass will be prevented from sinking these intrinsics out of
-; branches which would create phi nodes on the returned ptr.
+; This test ensures that given dx.resource.getpointer is marked convergent, the
+; SimplifyCFG pass will be prevented from moving these intrinsics into the
+; branches required for sinking handle retrieve before resource access.
 ;
 ; NOTE: The following test ir is generated from:
 ; https://godbolt.org/z/1EdGTbscE.

>From a0cadee9c7cb7b32646602bdc26478f380d51704 Mon Sep 17 00:00:00 2001
From: Finn Plummer <[email protected]>
Date: Tue, 23 Jun 2026 20:50:56 +0000
Subject: [PATCH 2/5] [SPIR-V] Cosolidate resource get pointer and counter
 handle with directx

---
 clang/lib/CodeGen/CGHLSLBuiltins.cpp          |   3 +-
 llvm/include/llvm/IR/IntrinsicsSPIRV.td       |   8 +-
 .../Transforms/GVN/no-sink-spvgetpointer.ll   |  98 ++++++++++++++
 .../DirectX/no-phi-dxgetpointer.ll            |  88 ++++++++++++
 .../SPIRV/no-sink-spvgetpointer.ll            | 128 ++++++++++++++++++
 5 files changed, 320 insertions(+), 5 deletions(-)
 create mode 100644 llvm/test/Transforms/GVN/no-sink-spvgetpointer.ll
 create mode 100644 
llvm/test/Transforms/SimplifyCFG/DirectX/no-phi-dxgetpointer.ll
 create mode 100644 
llvm/test/Transforms/SimplifyCFG/SPIRV/no-sink-spvgetpointer.ll

diff --git a/clang/lib/CodeGen/CGHLSLBuiltins.cpp 
b/clang/lib/CodeGen/CGHLSLBuiltins.cpp
index 20a2119e28ce1..ebf2c0cd5ed16 100644
--- a/clang/lib/CodeGen/CGHLSLBuiltins.cpp
+++ b/clang/lib/CodeGen/CGHLSLBuiltins.cpp
@@ -950,7 +950,8 @@ Value *CodeGenFunction::EmitHLSLBuiltinExpr(unsigned 
BuiltinID,
     llvm::Intrinsic::ID IntrinsicID =
         llvm::Intrinsic::spv_resource_counterhandlefromimplicitbinding;
     SmallVector<Value *> Args{MainHandle, OrderID, SpaceOp};
-    return Builder.CreateIntrinsic(HandleTy, IntrinsicID, Args);
+    return EmitIntrinsicCall(IntrinsicID, {HandleTy, MainHandle->getType()},
+                             Args);
   }
   case Builtin::BI__builtin_hlsl_resource_nonuniformindex: {
     Value *IndexOp = EmitScalarExpr(E->getArg(0));
diff --git a/llvm/include/llvm/IR/IntrinsicsSPIRV.td 
b/llvm/include/llvm/IR/IntrinsicsSPIRV.td
index 6e4cf8f7e72dc..5fb1e16197b57 100644
--- a/llvm/include/llvm/IR/IntrinsicsSPIRV.td
+++ b/llvm/include/llvm/IR/IntrinsicsSPIRV.td
@@ -207,11 +207,11 @@ def int_spv_rsqrt : 
DefaultAttrsIntrinsic<[LLVMMatchType<0>], [llvm_anyfloat_ty]
   def int_spv_resource_counterhandlefromimplicitbinding
       : DefaultAttrsIntrinsic<[llvm_any_ty],
                               [llvm_any_ty, llvm_i32_ty, llvm_i32_ty],
-                              [IntrNoMem]>;
+                              [IntrNoMem, IntrConvergent]>;
   def int_spv_resource_counterhandlefrombinding
       : DefaultAttrsIntrinsic<[llvm_any_ty],
                               [llvm_any_ty, llvm_i32_ty, llvm_i32_ty],
-                              [IntrNoMem]>;
+                              [IntrNoMem, IntrConvergent]>;
 
   def int_spv_firstbituhigh : 
DefaultAttrsIntrinsic<[LLVMScalarOrSameVectorWidth<0, llvm_i32_ty>], 
[llvm_anyint_ty], [IntrNoMem]>;
   def int_spv_firstbitshigh : 
DefaultAttrsIntrinsic<[LLVMScalarOrSameVectorWidth<0, llvm_i32_ty>], 
[llvm_anyint_ty], [IntrNoMem]>;
@@ -328,11 +328,11 @@ def int_spv_rsqrt : 
DefaultAttrsIntrinsic<[LLVMMatchType<0>], [llvm_anyfloat_ty]
 
   def int_spv_resource_getpointer
       : DefaultAttrsIntrinsic<[llvm_anyptr_ty], [llvm_any_ty, llvm_any_ty],
-                              [IntrNoMem]>;
+                              [IntrNoMem, IntrConvergent]>;
 
   def int_spv_resource_getbasepointer
       : DefaultAttrsIntrinsic<[llvm_anyptr_ty], [llvm_any_ty],
-                              [IntrNoMem]>;
+                              [IntrNoMem, IntrConvergent]>;
 
   def int_spv_pushconstant_getpointer
       : DefaultAttrsIntrinsic<[llvm_anyptr_ty], [llvm_any_ty], [IntrNoMem]>;
diff --git a/llvm/test/Transforms/GVN/no-sink-spvgetpointer.ll 
b/llvm/test/Transforms/GVN/no-sink-spvgetpointer.ll
new file mode 100644
index 0000000000000..f21dda66986fd
--- /dev/null
+++ b/llvm/test/Transforms/GVN/no-sink-spvgetpointer.ll
@@ -0,0 +1,98 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py 
UTC_ARGS: --version 6
+; RUN: opt -passes=gvn -passes=instnamer -S %s | FileCheck %s
+
+; This test ensures that given spv.resource.getpointer is marked convergent,
+; the GVN pass is prevented from sinking these intrinsics out of branches which
+; would create phi nodes on the returned ptr.
+
+%"class.hlsl::RWBuffer" = type { target("spirv.Image", i32, 5, 2, 0, 0, 2, 1) }
+%"class.hlsl::RWStructuredBuffer" = type { target("spirv.VulkanBuffer", [0 x 
i32], 12, 1), target("spirv.VulkanBuffer", [0 x i32], 12, 1) }
+%__cblayout_c = type <{ i32 }>
+
+@In = internal global %"class.hlsl::RWBuffer" poison, align 4
[email protected] = private unnamed_addr constant [3 x i8] c"In\00", align 1
+@Out0 = internal global %"class.hlsl::RWStructuredBuffer" poison, align 4
[email protected] = private unnamed_addr constant [5 x i8] c"Out0\00", align 1
+@Out1 = internal global %"class.hlsl::RWStructuredBuffer" poison, align 4
[email protected] = private unnamed_addr constant [5 x i8] c"Out1\00", align 1
[email protected] = local_unnamed_addr global target("spirv.VulkanBuffer", %__cblayout_c, 
2, 0) poison
+@cond = external hidden local_unnamed_addr addrspace(2) global i32, align 4
[email protected] = private unnamed_addr constant [2 x i8] c"c\00", align 1
+
+define void @main() local_unnamed_addr {
+; CHECK-LABEL: define void @main() local_unnamed_addr {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[I:%.*]] = tail call target("spirv.Image", i32, 5, 2, 0, 0, 
2, 1) @llvm.spv.resource.handlefrombinding.tspirv.Image_i32_5_2_0_0_2_1t(i32 0, 
i32 0, i32 1, i32 0, ptr nonnull @.str)
+; CHECK-NEXT:    store target("spirv.Image", i32, 5, 2, 0, 0, 2, 1) [[I]], ptr 
@In, align 4
+; CHECK-NEXT:    [[I1:%.*]] = tail call target("spirv.VulkanBuffer", [0 x 
i32], 12, 1) 
@llvm.spv.resource.handlefrombinding.tspirv.VulkanBuffer_a0i32_12_1t(i32 0, i32 
1, i32 1, i32 0, ptr nonnull @.str.2)
+; CHECK-NEXT:    store target("spirv.VulkanBuffer", [0 x i32], 12, 1) [[I1]], 
ptr @Out0, align 4
+; CHECK-NEXT:    store target("spirv.VulkanBuffer", [0 x i32], 12, 1) [[I1]], 
ptr getelementptr inbounds nuw (i8, ptr @Out0, i32 8), align 4
+; CHECK-NEXT:    [[I2:%.*]] = tail call target("spirv.VulkanBuffer", [0 x 
i32], 12, 1) 
@llvm.spv.resource.handlefrombinding.tspirv.VulkanBuffer_a0i32_12_1t(i32 0, i32 
2, i32 1, i32 0, ptr nonnull @.str.4)
+; CHECK-NEXT:    store target("spirv.VulkanBuffer", [0 x i32], 12, 1) [[I2]], 
ptr @Out1, align 4
+; CHECK-NEXT:    store target("spirv.VulkanBuffer", [0 x i32], 12, 1) [[I2]], 
ptr getelementptr inbounds nuw (i8, ptr @Out1, i32 8), align 4
+; CHECK-NEXT:    [[C_CB_H_I_I:%.*]] = tail call target("spirv.VulkanBuffer", 
[[__CBLAYOUT_C:%.*]], 2, 0) 
@llvm.spv.resource.handlefromimplicitbinding.tspirv.VulkanBuffer_s___cblayout_cs_2_0t(i32
 4, i32 0, i32 1, i32 0, ptr nonnull @c.str)
+; CHECK-NEXT:    store target("spirv.VulkanBuffer", [[__CBLAYOUT_C]], 2, 0) 
[[C_CB_H_I_I]], ptr @c.cb, align 8
+; CHECK-NEXT:    [[I3:%.*]] = tail call i32 
@llvm.spv.flattened.thread.id.in.group()
+; CHECK-NEXT:    [[I4:%.*]] = load i32, ptr addrspace(2) @cond, align 4
+; CHECK-NEXT:    [[LOADEDV_I:%.*]] = trunc nuw i32 [[I4]] to i1
+; CHECK-NEXT:    br i1 [[LOADEDV_I]], label %[[IF_THEN_I:.*]], label 
%[[IF_ELSE_I:.*]]
+; CHECK:       [[IF_THEN_I]]:
+; CHECK-NEXT:    [[I5:%.*]] = tail call noundef nonnull align 4 
dereferenceable(4) ptr 
@llvm.spv.resource.getpointer.p0.tspirv.Image_i32_5_2_0_0_2_1t.i32(target("spirv.Image",
 i32, 5, 2, 0, 0, 2, 1) [[I]], i32 [[I3]])
+; CHECK-NEXT:    [[I6:%.*]] = load i32, ptr [[I5]], align 4
+; CHECK-NEXT:    [[HLSL_WAVE_ACTIVE_SUM_I:%.*]] = tail call i32 
@llvm.spv.wave.reduce.sum.i32(i32 [[I6]])
+; CHECK-NEXT:    [[I7:%.*]] = tail call noundef nonnull align 4 
dereferenceable(4) ptr addrspace(11) 
@llvm.spv.resource.getpointer.p11.tspirv.VulkanBuffer_a0i32_12_1t.i32(target("spirv.VulkanBuffer",
 [0 x i32], 12, 1) [[I1]], i32 [[I3]])
+; CHECK-NEXT:    store i32 [[HLSL_WAVE_ACTIVE_SUM_I]], ptr addrspace(11) 
[[I7]], align 4
+; CHECK-NEXT:    br label %[[MAIN_EXIT:.*]]
+; CHECK:       [[IF_ELSE_I]]:
+; CHECK-NEXT:    [[I8:%.*]] = tail call noundef nonnull align 4 
dereferenceable(4) ptr 
@llvm.spv.resource.getpointer.p0.tspirv.Image_i32_5_2_0_0_2_1t.i32(target("spirv.Image",
 i32, 5, 2, 0, 0, 2, 1) [[I]], i32 [[I3]])
+; CHECK-NEXT:    [[I9:%.*]] = load i32, ptr [[I8]], align 4
+; CHECK-NEXT:    [[I10:%.*]] = tail call noundef nonnull align 4 
dereferenceable(4) ptr addrspace(11) 
@llvm.spv.resource.getpointer.p11.tspirv.VulkanBuffer_a0i32_12_1t.i32(target("spirv.VulkanBuffer",
 [0 x i32], 12, 1) [[I1]], i32 0)
+; CHECK-NEXT:    store i32 [[I9]], ptr addrspace(11) [[I10]], align 4
+; CHECK-NEXT:    br label %[[MAIN_EXIT]]
+; CHECK:       [[MAIN_EXIT]]:
+; CHECK-NEXT:    [[I11:%.*]] = tail call noundef nonnull align 4 
dereferenceable(4) ptr 
@llvm.spv.resource.getpointer.p0.tspirv.Image_i32_5_2_0_0_2_1t.i32(target("spirv.Image",
 i32, 5, 2, 0, 0, 2, 1) [[I]], i32 [[I3]])
+; CHECK-NEXT:    [[I12:%.*]] = load i32, ptr [[I11]], align 4
+; CHECK-NEXT:    [[HLSL_WAVE_ACTIVE_SUM5_I:%.*]] = tail call i32 
@llvm.spv.wave.reduce.sum.i32(i32 [[I12]])
+; CHECK-NEXT:    [[I13:%.*]] = tail call noundef nonnull align 4 
dereferenceable(4) ptr addrspace(11) 
@llvm.spv.resource.getpointer.p11.tspirv.VulkanBuffer_a0i32_12_1t.i32(target("spirv.VulkanBuffer",
 [0 x i32], 12, 1) [[I1]], i32 [[I3]])
+; CHECK-NEXT:    store i32 [[HLSL_WAVE_ACTIVE_SUM5_I]], ptr addrspace(11) 
[[I13]], align 4
+; CHECK-NEXT:    ret void
+;
+entry:
+  %0 = tail call target("spirv.Image", i32, 5, 2, 0, 0, 2, 1) 
@llvm.spv.resource.handlefrombinding.tspirv.Image_i32_5_2_0_0_2_1t(i32 0, i32 
0, i32 1, i32 0, ptr nonnull @.str)
+  store target("spirv.Image", i32, 5, 2, 0, 0, 2, 1) %0, ptr @In, align 4
+  %1 = tail call target("spirv.VulkanBuffer", [0 x i32], 12, 1) 
@llvm.spv.resource.handlefrombinding.tspirv.VulkanBuffer_a0i32_12_1t(i32 0, i32 
1, i32 1, i32 0, ptr nonnull @.str.2)
+  store target("spirv.VulkanBuffer", [0 x i32], 12, 1) %1, ptr @Out0, align 4
+  store target("spirv.VulkanBuffer", [0 x i32], 12, 1) %1, ptr getelementptr 
inbounds nuw (i8, ptr @Out0, i32 8), align 4
+  %2 = tail call target("spirv.VulkanBuffer", [0 x i32], 12, 1) 
@llvm.spv.resource.handlefrombinding.tspirv.VulkanBuffer_a0i32_12_1t(i32 0, i32 
2, i32 1, i32 0, ptr nonnull @.str.4)
+  store target("spirv.VulkanBuffer", [0 x i32], 12, 1) %2, ptr @Out1, align 4
+  store target("spirv.VulkanBuffer", [0 x i32], 12, 1) %2, ptr getelementptr 
inbounds nuw (i8, ptr @Out1, i32 8), align 4
+  %c.cb_h.i.i = tail call target("spirv.VulkanBuffer", %__cblayout_c, 2, 0) 
@llvm.spv.resource.handlefromimplicitbinding.tspirv.VulkanBuffer_s___cblayout_cs_2_0t(i32
 4, i32 0, i32 1, i32 0, ptr nonnull @c.str)
+  store target("spirv.VulkanBuffer", %__cblayout_c, 2, 0) %c.cb_h.i.i, ptr 
@c.cb, align 8
+  %3 = tail call i32 @llvm.spv.flattened.thread.id.in.group()
+  %4 = load i32, ptr addrspace(2) @cond, align 4
+  %loadedv.i = trunc nuw i32 %4 to i1
+  br i1 %loadedv.i, label %if.then.i, label %if.else.i
+
+if.then.i:                                        ; preds = %entry
+  %5 = tail call noundef nonnull align 4 dereferenceable(4) ptr 
@llvm.spv.resource.getpointer.p0.tspirv.Image_i32_5_2_0_0_2_1t.i32(target("spirv.Image",
 i32, 5, 2, 0, 0, 2, 1) %0, i32 %3)
+  %6 = load i32, ptr %5, align 4
+  %hlsl.wave.active.sum.i = tail call i32 @llvm.spv.wave.reduce.sum.i32(i32 %6)
+  %7 = tail call noundef nonnull align 4 dereferenceable(4) ptr addrspace(11) 
@llvm.spv.resource.getpointer.p11.tspirv.VulkanBuffer_a0i32_12_1t.i32(target("spirv.VulkanBuffer",
 [0 x i32], 12, 1) %1, i32 %3)
+  store i32 %hlsl.wave.active.sum.i, ptr addrspace(11) %7, align 4
+  br label %main.exit
+
+if.else.i:                                        ; preds = %entry
+  %8 = tail call noundef nonnull align 4 dereferenceable(4) ptr 
@llvm.spv.resource.getpointer.p0.tspirv.Image_i32_5_2_0_0_2_1t.i32(target("spirv.Image",
 i32, 5, 2, 0, 0, 2, 1) %0, i32 %3)
+  %9 = load i32, ptr %8, align 4
+  %10 = tail call noundef nonnull align 4 dereferenceable(4) ptr addrspace(11) 
@llvm.spv.resource.getpointer.p11.tspirv.VulkanBuffer_a0i32_12_1t.i32(target("spirv.VulkanBuffer",
 [0 x i32], 12, 1) %1, i32 0)
+  store i32 %9, ptr addrspace(11) %10, align 4
+  br label %main.exit
+
+main.exit:                                    ; preds = %if.then.i, %if.else.i
+  %11 = tail call noundef nonnull align 4 dereferenceable(4) ptr 
@llvm.spv.resource.getpointer.p0.tspirv.Image_i32_5_2_0_0_2_1t.i32(target("spirv.Image",
 i32, 5, 2, 0, 0, 2, 1) %0, i32 %3)
+  %12 = load i32, ptr %11, align 4
+  %hlsl.wave.active.sum5.i = tail call i32 @llvm.spv.wave.reduce.sum.i32(i32 
%12)
+  %13 = tail call noundef nonnull align 4 dereferenceable(4) ptr addrspace(11) 
@llvm.spv.resource.getpointer.p11.tspirv.VulkanBuffer_a0i32_12_1t.i32(target("spirv.VulkanBuffer",
 [0 x i32], 12, 1) %1, i32 %3)
+  store i32 %hlsl.wave.active.sum5.i, ptr addrspace(11) %13, align 4
+  ret void
+}
diff --git a/llvm/test/Transforms/SimplifyCFG/DirectX/no-phi-dxgetpointer.ll 
b/llvm/test/Transforms/SimplifyCFG/DirectX/no-phi-dxgetpointer.ll
new file mode 100644
index 0000000000000..24dcf473513ce
--- /dev/null
+++ b/llvm/test/Transforms/SimplifyCFG/DirectX/no-phi-dxgetpointer.ll
@@ -0,0 +1,88 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py 
UTC_ARGS: --version 6
+; RUN: opt -passes='simplifycfg<sink-common-insts>' -passes=instnamer -S %s | 
FileCheck %s
+
+; This test ensures that given dx.resource.getpointer is marked convergent, the
+; SimplifyCFG pass is prevented from sinking the resource accesses out of their
+; branches, which would otherwise create an (illegal) phi node selecting 
between
+; two resource pointers.
+;
+; Without the convergent marking, SimplifyCFG's common-code sinking would sink
+; the load/store from both branches into the common successor and introduce:
+;   %ptr = phi ptr [ %bufA.ptr, %if.then ], [ %bufB.ptr, %if.else ]
+; which is an illegal phi node on a resource pointer.
+;
+; NOTE: The following IR corresponds to the (post-inlining) lowering of:
+;
+;   RWStructuredBuffer<float> bufA : register(u0);
+;   RWStructuredBuffer<float> bufB : register(u1);
+;   RWStructuredBuffer<float> output : register(u2);
+;
+;   cbuffer Constants : register(b0) {
+;       uint condition;
+;   };
+;
+;   [numthreads(64, 1, 1)]
+;   void main(uint tid : SV_DispatchThreadID) {
+;       if (condition == 0) {
+;           output[tid] = bufA[tid];
+;       } else {
+;           output[tid] = bufB[tid];
+;       }
+;   }
+
+@condition = external hidden addrspace(2) global i32, align 4
[email protected] = private unnamed_addr constant [5 x i8] c"bufA\00", align 1
[email protected] = private unnamed_addr constant [5 x i8] c"bufB\00", align 1
[email protected] = private unnamed_addr constant [7 x i8] c"output\00", align 1
+
+define void @main() local_unnamed_addr {
+; CHECK-LABEL: define void @main() local_unnamed_addr {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[BUFA:%.*]] = tail call target("dx.RawBuffer", float, 1, 0) 
@llvm.dx.resource.handlefrombinding.tdx.RawBuffer_f32_1_0t(i32 0, i32 0, i32 1, 
i32 0, ptr nonnull @.str)
+; CHECK-NEXT:    [[BUFB:%.*]] = tail call target("dx.RawBuffer", float, 1, 0) 
@llvm.dx.resource.handlefrombinding.tdx.RawBuffer_f32_1_0t(i32 0, i32 1, i32 1, 
i32 0, ptr nonnull @.str.2)
+; CHECK-NEXT:    [[OUTPUT:%.*]] = tail call target("dx.RawBuffer", float, 1, 
0) @llvm.dx.resource.handlefrombinding.tdx.RawBuffer_f32_1_0t(i32 0, i32 2, i32 
1, i32 0, ptr nonnull @.str.4)
+; CHECK-NEXT:    [[TID:%.*]] = tail call i32 @llvm.dx.thread.id(i32 0)
+; CHECK-NEXT:    [[COND:%.*]] = load i32, ptr addrspace(2) @condition, align 4
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[COND]], 0
+; CHECK-NEXT:    br i1 [[CMP]], label %[[IF_THEN:.*]], label %[[IF_ELSE:.*]]
+; CHECK:       [[IF_THEN]]:
+; CHECK-NEXT:    [[PA:%.*]] = tail call noundef nonnull align 4 
dereferenceable(4) ptr 
@llvm.dx.resource.getpointer.p0.tdx.RawBuffer_f32_1_0t.i32(target("dx.RawBuffer",
 float, 1, 0) [[BUFA]], i32 [[TID]])
+; CHECK-NEXT:    [[VA:%.*]] = load float, ptr [[PA]], align 4
+; CHECK-NEXT:    [[PO1:%.*]] = tail call noundef nonnull align 4 
dereferenceable(4) ptr 
@llvm.dx.resource.getpointer.p0.tdx.RawBuffer_f32_1_0t.i32(target("dx.RawBuffer",
 float, 1, 0) [[OUTPUT]], i32 [[TID]])
+; CHECK-NEXT:    store float [[VA]], ptr [[PO1]], align 4
+; CHECK-NEXT:    br label %[[IF_END:.*]]
+; CHECK:       [[IF_ELSE]]:
+; CHECK-NEXT:    [[PB:%.*]] = tail call noundef nonnull align 4 
dereferenceable(4) ptr 
@llvm.dx.resource.getpointer.p0.tdx.RawBuffer_f32_1_0t.i32(target("dx.RawBuffer",
 float, 1, 0) [[BUFB]], i32 [[TID]])
+; CHECK-NEXT:    [[VB:%.*]] = load float, ptr [[PB]], align 4
+; CHECK-NEXT:    [[PO2:%.*]] = tail call noundef nonnull align 4 
dereferenceable(4) ptr 
@llvm.dx.resource.getpointer.p0.tdx.RawBuffer_f32_1_0t.i32(target("dx.RawBuffer",
 float, 1, 0) [[OUTPUT]], i32 [[TID]])
+; CHECK-NEXT:    store float [[VB]], ptr [[PO2]], align 4
+; CHECK-NEXT:    br label %[[IF_END]]
+; CHECK:       [[IF_END]]:
+; CHECK-NEXT:    ret void
+;
+entry:
+  %bufA = tail call target("dx.RawBuffer", float, 1, 0) 
@llvm.dx.resource.handlefrombinding.tdx.RawBuffer_f32_1_0t(i32 0, i32 0, i32 1, 
i32 0, ptr nonnull @.str)
+  %bufB = tail call target("dx.RawBuffer", float, 1, 0) 
@llvm.dx.resource.handlefrombinding.tdx.RawBuffer_f32_1_0t(i32 0, i32 1, i32 1, 
i32 0, ptr nonnull @.str.2)
+  %output = tail call target("dx.RawBuffer", float, 1, 0) 
@llvm.dx.resource.handlefrombinding.tdx.RawBuffer_f32_1_0t(i32 0, i32 2, i32 1, 
i32 0, ptr nonnull @.str.4)
+  %tid = tail call i32 @llvm.dx.thread.id(i32 0)
+  %cond = load i32, ptr addrspace(2) @condition, align 4
+  %cmp = icmp eq i32 %cond, 0
+  br i1 %cmp, label %if.then, label %if.else
+
+if.then:                                          ; preds = %entry
+  %pA = tail call noundef nonnull align 4 dereferenceable(4) ptr 
@llvm.dx.resource.getpointer.p0.tdx.RawBuffer_f32_1_0t.i32(target("dx.RawBuffer",
 float, 1, 0) %bufA, i32 %tid)
+  %vA = load float, ptr %pA, align 4
+  %pO1 = tail call noundef nonnull align 4 dereferenceable(4) ptr 
@llvm.dx.resource.getpointer.p0.tdx.RawBuffer_f32_1_0t.i32(target("dx.RawBuffer",
 float, 1, 0) %output, i32 %tid)
+  store float %vA, ptr %pO1, align 4
+  br label %if.end
+
+if.else:                                          ; preds = %entry
+  %pB = tail call noundef nonnull align 4 dereferenceable(4) ptr 
@llvm.dx.resource.getpointer.p0.tdx.RawBuffer_f32_1_0t.i32(target("dx.RawBuffer",
 float, 1, 0) %bufB, i32 %tid)
+  %vB = load float, ptr %pB, align 4
+  %pO2 = tail call noundef nonnull align 4 dereferenceable(4) ptr 
@llvm.dx.resource.getpointer.p0.tdx.RawBuffer_f32_1_0t.i32(target("dx.RawBuffer",
 float, 1, 0) %output, i32 %tid)
+  store float %vB, ptr %pO2, align 4
+  br label %if.end
+
+if.end:                                           ; preds = %if.else, %if.then
+  ret void
+}
diff --git a/llvm/test/Transforms/SimplifyCFG/SPIRV/no-sink-spvgetpointer.ll 
b/llvm/test/Transforms/SimplifyCFG/SPIRV/no-sink-spvgetpointer.ll
new file mode 100644
index 0000000000000..4071cf518eb7a
--- /dev/null
+++ b/llvm/test/Transforms/SimplifyCFG/SPIRV/no-sink-spvgetpointer.ll
@@ -0,0 +1,128 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py 
UTC_ARGS: --version 6
+; RUN: opt -passes=simplifycfg -passes=instnamer -S %s | FileCheck %s
+
+; This test ensures that given spv.resource.getpointer is marked convergent,
+; the SimplifyCFG pass will be prevented from sinking these intrinsics out of
+; branches which would create phi nodes on the returned ptr.
+
+%"class.hlsl::RWStructuredBuffer" = type { target("spirv.VulkanBuffer", [0 x 
i32], 12, 1), target("spirv.VulkanBuffer", [0 x i32], 12, 1) }
+%__cblayout_d = type <{ i32, i32, i32, i32 }>
+
+@a = internal global %"class.hlsl::RWStructuredBuffer" poison, align 4
[email protected] = private unnamed_addr constant [2 x i8] c"a\00", align 1
+@b = internal global %"class.hlsl::RWStructuredBuffer" poison, align 4
[email protected] = private unnamed_addr constant [2 x i8] c"b\00", align 1
+@c = internal global %"class.hlsl::RWStructuredBuffer" poison, align 4
[email protected] = private unnamed_addr constant [2 x i8] c"c\00", align 1
[email protected] = local_unnamed_addr global target("spirv.VulkanBuffer", %__cblayout_d, 
2, 0) poison
+@e = external hidden local_unnamed_addr addrspace(2) global i32, align 4
+@f = external hidden local_unnamed_addr addrspace(2) global i32, align 4
+@g = external hidden local_unnamed_addr addrspace(2) global i32, align 4
+@h = external hidden local_unnamed_addr addrspace(2) global i32, align 4
[email protected] = private unnamed_addr constant [2 x i8] c"d\00", align 1
+
+define void @main() local_unnamed_addr {
+; CHECK-LABEL: define void @main() local_unnamed_addr {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[I:%.*]] = tail call target("spirv.VulkanBuffer", [0 x i32], 
12, 1) 
@llvm.spv.resource.handlefromimplicitbinding.tspirv.VulkanBuffer_a0i32_12_1t(i32
 0, i32 0, i32 1, i32 0, ptr nonnull @.str)
+; CHECK-NEXT:    store target("spirv.VulkanBuffer", [0 x i32], 12, 1) [[I]], 
ptr @a, align 4
+; CHECK-NEXT:    store target("spirv.VulkanBuffer", [0 x i32], 12, 1) [[I]], 
ptr getelementptr inbounds nuw (i8, ptr @a, i32 8), align 4
+; CHECK-NEXT:    [[I1:%.*]] = tail call target("spirv.VulkanBuffer", [0 x 
i32], 12, 1) 
@llvm.spv.resource.handlefromimplicitbinding.tspirv.VulkanBuffer_a0i32_12_1t(i32
 2, i32 0, i32 1, i32 0, ptr nonnull @.str.2)
+; CHECK-NEXT:    store target("spirv.VulkanBuffer", [0 x i32], 12, 1) [[I1]], 
ptr @b, align 4
+; CHECK-NEXT:    store target("spirv.VulkanBuffer", [0 x i32], 12, 1) [[I1]], 
ptr getelementptr inbounds nuw (i8, ptr @b, i32 8), align 4
+; CHECK-NEXT:    [[I2:%.*]] = tail call target("spirv.VulkanBuffer", [0 x 
i32], 12, 1) 
@llvm.spv.resource.handlefromimplicitbinding.tspirv.VulkanBuffer_a0i32_12_1t(i32
 4, i32 0, i32 1, i32 0, ptr nonnull @.str.4)
+; CHECK-NEXT:    store target("spirv.VulkanBuffer", [0 x i32], 12, 1) [[I2]], 
ptr @c, align 4
+; CHECK-NEXT:    store target("spirv.VulkanBuffer", [0 x i32], 12, 1) [[I2]], 
ptr getelementptr inbounds nuw (i8, ptr @c, i32 8), align 4
+; CHECK-NEXT:    [[D_CB_H_I_I:%.*]] = tail call target("spirv.VulkanBuffer", 
[[__CBLAYOUT_D:%.*]], 2, 0) 
@llvm.spv.resource.handlefromimplicitbinding.tspirv.VulkanBuffer_s___cblayout_ds_2_0t(i32
 6, i32 0, i32 1, i32 0, ptr nonnull @d.str)
+; CHECK-NEXT:    store target("spirv.VulkanBuffer", [[__CBLAYOUT_D]], 2, 0) 
[[D_CB_H_I_I]], ptr @d.cb, align 8
+; CHECK-NEXT:    [[I3:%.*]] = load i32, ptr addrspace(2) @h, align 4
+; CHECK-NEXT:    [[TOBOOL_NOT_I:%.*]] = icmp eq i32 [[I3]], 0
+; CHECK-NEXT:    br i1 [[TOBOOL_NOT_I]], label %[[IF_ELSE_I:.*]], label 
%[[IF_THEN_I:.*]]
+; CHECK:       [[IF_THEN_I]]:
+; CHECK-NEXT:    [[I4:%.*]] = load i32, ptr addrspace(2) @f, align 4
+; CHECK-NEXT:    [[I5:%.*]] = tail call noundef nonnull align 4 
dereferenceable(4) ptr addrspace(11) 
@llvm.spv.resource.getpointer.p11.tspirv.VulkanBuffer_a0i32_12_1t.i32(target("spirv.VulkanBuffer",
 [0 x i32], 12, 1) [[I1]], i32 [[I4]])
+; CHECK-NEXT:    [[I6:%.*]] = load i32, ptr addrspace(11) [[I5]], align 4
+; CHECK-NEXT:    [[I7:%.*]] = load i32, ptr addrspace(2) @g, align 4
+; CHECK-NEXT:    [[I8:%.*]] = tail call noundef nonnull align 4 
dereferenceable(4) ptr addrspace(11) 
@llvm.spv.resource.getpointer.p11.tspirv.VulkanBuffer_a0i32_12_1t.i32(target("spirv.VulkanBuffer",
 [0 x i32], 12, 1) [[I2]], i32 [[I7]])
+; CHECK-NEXT:    store i32 [[I6]], ptr addrspace(11) [[I8]], align 4
+; CHECK-NEXT:    br label %[[MAIN_EXIT:.*]]
+; CHECK:       [[IF_ELSE_I]]:
+; CHECK-NEXT:    [[I9:%.*]] = load i32, ptr addrspace(2) @g, align 4
+; CHECK-NEXT:    [[CMP_I:%.*]] = icmp eq i32 [[I9]], 0
+; CHECK-NEXT:    br i1 [[CMP_I]], label %[[IF_THEN2_I:.*]], label 
%[[IF_ELSE6_I:.*]]
+; CHECK:       [[IF_THEN2_I]]:
+; CHECK-NEXT:    [[I10:%.*]] = tail call noundef nonnull align 4 
dereferenceable(4) ptr addrspace(11) 
@llvm.spv.resource.getpointer.p11.tspirv.VulkanBuffer_a0i32_12_1t.i32(target("spirv.VulkanBuffer",
 [0 x i32], 12, 1) [[I1]], i32 0)
+; CHECK-NEXT:    [[I11:%.*]] = load i32, ptr addrspace(11) [[I10]], align 4
+; CHECK-NEXT:    [[I12:%.*]] = tail call noundef nonnull align 4 
dereferenceable(4) ptr addrspace(11) 
@llvm.spv.resource.getpointer.p11.tspirv.VulkanBuffer_a0i32_12_1t.i32(target("spirv.VulkanBuffer",
 [0 x i32], 12, 1) [[I2]], i32 0)
+; CHECK-NEXT:    store i32 [[I11]], ptr addrspace(11) [[I12]], align 4
+; CHECK-NEXT:    br label %[[MAIN_EXIT]]
+; CHECK:       [[IF_ELSE6_I]]:
+; CHECK-NEXT:    [[I13:%.*]] = load i32, ptr addrspace(2) @e, align 4
+; CHECK-NEXT:    [[I14:%.*]] = tail call noundef nonnull align 4 
dereferenceable(4) ptr addrspace(11) 
@llvm.spv.resource.getpointer.p11.tspirv.VulkanBuffer_a0i32_12_1t.i32(target("spirv.VulkanBuffer",
 [0 x i32], 12, 1) [[I]], i32 [[I13]])
+; CHECK-NEXT:    [[I15:%.*]] = load i32, ptr addrspace(11) [[I14]], align 4
+; CHECK-NEXT:    [[I16:%.*]] = tail call noundef nonnull align 4 
dereferenceable(4) ptr addrspace(11) 
@llvm.spv.resource.getpointer.p11.tspirv.VulkanBuffer_a0i32_12_1t.i32(target("spirv.VulkanBuffer",
 [0 x i32], 12, 1) [[I2]], i32 [[I9]])
+; CHECK-NEXT:    store i32 [[I15]], ptr addrspace(11) [[I16]], align 4
+; CHECK-NEXT:    br label %[[MAIN_EXIT]]
+; CHECK:       [[MAIN_EXIT]]:
+; CHECK-NEXT:    [[I17:%.*]] = load i32, ptr addrspace(2) @f, align 4
+; CHECK-NEXT:    [[I18:%.*]] = load i32, ptr addrspace(2) @g, align 4
+; CHECK-NEXT:    [[I19:%.*]] = tail call noundef nonnull align 4 
dereferenceable(4) ptr addrspace(11) 
@llvm.spv.resource.getpointer.p11.tspirv.VulkanBuffer_a0i32_12_1t.i32(target("spirv.VulkanBuffer",
 [0 x i32], 12, 1) [[I2]], i32 [[I18]])
+; CHECK-NEXT:    [[I20:%.*]] = load i32, ptr addrspace(11) [[I19]], align 4
+; CHECK-NEXT:    [[ADD_I:%.*]] = add i32 [[I20]], [[I17]]
+; CHECK-NEXT:    store i32 [[ADD_I]], ptr addrspace(11) [[I19]], align 4
+; CHECK-NEXT:    ret void
+;
+entry:
+  %0 = tail call target("spirv.VulkanBuffer", [0 x i32], 12, 1) 
@llvm.spv.resource.handlefromimplicitbinding.tspirv.VulkanBuffer_a0i32_12_1t(i32
 0, i32 0, i32 1, i32 0, ptr nonnull @.str)
+  store target("spirv.VulkanBuffer", [0 x i32], 12, 1) %0, ptr @a, align 4
+  store target("spirv.VulkanBuffer", [0 x i32], 12, 1) %0, ptr getelementptr 
inbounds nuw (i8, ptr @a, i32 8), align 4
+  %1 = tail call target("spirv.VulkanBuffer", [0 x i32], 12, 1) 
@llvm.spv.resource.handlefromimplicitbinding.tspirv.VulkanBuffer_a0i32_12_1t(i32
 2, i32 0, i32 1, i32 0, ptr nonnull @.str.2)
+  store target("spirv.VulkanBuffer", [0 x i32], 12, 1) %1, ptr @b, align 4
+  store target("spirv.VulkanBuffer", [0 x i32], 12, 1) %1, ptr getelementptr 
inbounds nuw (i8, ptr @b, i32 8), align 4
+  %2 = tail call target("spirv.VulkanBuffer", [0 x i32], 12, 1) 
@llvm.spv.resource.handlefromimplicitbinding.tspirv.VulkanBuffer_a0i32_12_1t(i32
 4, i32 0, i32 1, i32 0, ptr nonnull @.str.4)
+  store target("spirv.VulkanBuffer", [0 x i32], 12, 1) %2, ptr @c, align 4
+  store target("spirv.VulkanBuffer", [0 x i32], 12, 1) %2, ptr getelementptr 
inbounds nuw (i8, ptr @c, i32 8), align 4
+  %d.cb_h.i.i = tail call target("spirv.VulkanBuffer", %__cblayout_d, 2, 0) 
@llvm.spv.resource.handlefromimplicitbinding.tspirv.VulkanBuffer_s___cblayout_ds_2_0t(i32
 6, i32 0, i32 1, i32 0, ptr nonnull @d.str)
+  store target("spirv.VulkanBuffer", %__cblayout_d, 2, 0) %d.cb_h.i.i, ptr 
@d.cb, align 8
+  %3 = load i32, ptr addrspace(2) @h, align 4
+  %tobool.not.i = icmp eq i32 %3, 0
+  br i1 %tobool.not.i, label %if.else.i, label %if.then.i
+
+if.then.i:                                        ; preds = %entry
+  %4 = load i32, ptr addrspace(2) @f, align 4
+  %5 = tail call noundef nonnull align 4 dereferenceable(4) ptr addrspace(11) 
@llvm.spv.resource.getpointer.p11.tspirv.VulkanBuffer_a0i32_12_1t.i32(target("spirv.VulkanBuffer",
 [0 x i32], 12, 1) %1, i32 %4)
+  %6 = load i32, ptr addrspace(11) %5, align 4
+  %7 = load i32, ptr addrspace(2) @g, align 4
+  %8 = tail call noundef nonnull align 4 dereferenceable(4) ptr addrspace(11) 
@llvm.spv.resource.getpointer.p11.tspirv.VulkanBuffer_a0i32_12_1t.i32(target("spirv.VulkanBuffer",
 [0 x i32], 12, 1) %2, i32 %7)
+  store i32 %6, ptr addrspace(11) %8, align 4
+  br label %main.exit
+
+if.else.i:                                        ; preds = %entry
+  %9 = load i32, ptr addrspace(2) @g, align 4
+  %cmp.i = icmp eq i32 %9, 0
+  br i1 %cmp.i, label %if.then2.i, label %if.else6.i
+
+if.then2.i:                                       ; preds = %if.else.i
+  %10 = tail call noundef nonnull align 4 dereferenceable(4) ptr addrspace(11) 
@llvm.spv.resource.getpointer.p11.tspirv.VulkanBuffer_a0i32_12_1t.i32(target("spirv.VulkanBuffer",
 [0 x i32], 12, 1) %1, i32 0)
+  %11 = load i32, ptr addrspace(11) %10, align 4
+  %12 = tail call noundef nonnull align 4 dereferenceable(4) ptr addrspace(11) 
@llvm.spv.resource.getpointer.p11.tspirv.VulkanBuffer_a0i32_12_1t.i32(target("spirv.VulkanBuffer",
 [0 x i32], 12, 1) %2, i32 0)
+  store i32 %11, ptr addrspace(11) %12, align 4
+  br label %main.exit
+
+if.else6.i:                                       ; preds = %if.else.i
+  %13 = load i32, ptr addrspace(2) @e, align 4
+  %14 = tail call noundef nonnull align 4 dereferenceable(4) ptr addrspace(11) 
@llvm.spv.resource.getpointer.p11.tspirv.VulkanBuffer_a0i32_12_1t.i32(target("spirv.VulkanBuffer",
 [0 x i32], 12, 1) %0, i32 %13)
+  %15 = load i32, ptr addrspace(11) %14, align 4
+  %16 = tail call noundef nonnull align 4 dereferenceable(4) ptr addrspace(11) 
@llvm.spv.resource.getpointer.p11.tspirv.VulkanBuffer_a0i32_12_1t.i32(target("spirv.VulkanBuffer",
 [0 x i32], 12, 1) %2, i32 %9)
+  store i32 %15, ptr addrspace(11) %16, align 4
+  br label %main.exit
+
+main.exit:                                    ; preds = %if.then.i, 
%if.then2.i, %if.else6.i
+  %17 = load i32, ptr addrspace(2) @f, align 4
+  %18 = load i32, ptr addrspace(2) @g, align 4
+  %19 = tail call noundef nonnull align 4 dereferenceable(4) ptr addrspace(11) 
@llvm.spv.resource.getpointer.p11.tspirv.VulkanBuffer_a0i32_12_1t.i32(target("spirv.VulkanBuffer",
 [0 x i32], 12, 1) %2, i32 %18)
+  %20 = load i32, ptr addrspace(11) %19, align 4
+  %add.i = add i32 %20, %17
+  store i32 %add.i, ptr addrspace(11) %19, align 4
+  ret void
+}

>From 07d557a65b8a8ae64c91df2b9000b11febb0a09b Mon Sep 17 00:00:00 2001
From: Finn Plummer <[email protected]>
Date: Tue, 23 Jun 2026 21:17:41 +0000
Subject: [PATCH 3/5] [SPIR-V] Add test case for counter

---
 .../GVN/no-sink-spvcounterhandle.ll           | 70 +++++++++++++++++++
 1 file changed, 70 insertions(+)
 create mode 100644 llvm/test/Transforms/GVN/no-sink-spvcounterhandle.ll

diff --git a/llvm/test/Transforms/GVN/no-sink-spvcounterhandle.ll 
b/llvm/test/Transforms/GVN/no-sink-spvcounterhandle.ll
new file mode 100644
index 0000000000000..137f63f08f0a8
--- /dev/null
+++ b/llvm/test/Transforms/GVN/no-sink-spvcounterhandle.ll
@@ -0,0 +1,70 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py 
UTC_ARGS: --version 6
+; RUN: opt -passes=gvn -passes=instnamer -S %s | FileCheck %s
+
+; This test ensures that given spv.resource.counterhandlefrombinding is marked
+; convergent, the GVN pass is prevented from sinking these intrinsics out of
+; branches which would create phi nodes on the returned counter handle.
+;
+; It models the following HLSL:
+;
+;   RWStructuredBuffer<int> Out[4] : register(u0);
+;
+;   [numthreads(4,1,1)]
+;   void main(uint GI : SV_GroupIndex) {
+;     for (int i = 0; i < GI; i++)
+;       Out[NonUniformResourceIndex(GI)].IncrementCounter();
+;
+;     Out[NonUniformResourceIndex(GI)][0] = 
Out[NonUniformResourceIndex(GI)].IncrementCounter();
+;   }
+
+target datalayout = "e-ve-i64:64-n8:16:32:64-G10"
+target triple = "spirv1.6-unknown-vulkan1.3-compute"
+
[email protected] = private unnamed_addr constant [4 x i8] c"Out\00", align 1
+@cond = external hidden local_unnamed_addr addrspace(2) global i32, align 4
+
+define void @main() local_unnamed_addr {
+; CHECK-LABEL: define void @main() local_unnamed_addr {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[I:%.*]] = tail call target("spirv.VulkanBuffer", [0 x i32], 
12, 1) @llvm.spv.resource.handlefrombinding.tspirv.VulkanBuffer_a0i32_12_1t(i32 
0, i32 0, i32 4, i32 0, ptr nonnull @Out.str)
+; CHECK-NEXT:    [[I1:%.*]] = load i32, ptr addrspace(2) @cond, align 4
+; CHECK-NEXT:    [[LOADEDV:%.*]] = trunc nuw i32 [[I1]] to i1
+; CHECK-NEXT:    br i1 [[LOADEDV]], label %[[IF_THEN:.*]], label 
%[[IF_ELSE:.*]]
+; CHECK:       [[IF_THEN]]:
+; CHECK-NEXT:    [[I2:%.*]] = tail call target("spirv.VulkanBuffer", i32, 12, 
1) 
@llvm.spv.resource.counterhandlefrombinding.tspirv.VulkanBuffer_i32_12_1t.tspirv.VulkanBuffer_a0i32_12_1t(target("spirv.VulkanBuffer",
 [0 x i32], 12, 1) [[I]], i32 0, i32 0)
+; CHECK-NEXT:    [[I3:%.*]] = tail call i32 
@llvm.spv.resource.updatecounter.tspirv.VulkanBuffer_i32_12_1t(target("spirv.VulkanBuffer",
 i32, 12, 1) [[I2]], i8 1)
+; CHECK-NEXT:    br label %[[EXIT:.*]]
+; CHECK:       [[IF_ELSE]]:
+; CHECK-NEXT:    [[I4:%.*]] = tail call target("spirv.VulkanBuffer", i32, 12, 
1) 
@llvm.spv.resource.counterhandlefrombinding.tspirv.VulkanBuffer_i32_12_1t.tspirv.VulkanBuffer_a0i32_12_1t(target("spirv.VulkanBuffer",
 [0 x i32], 12, 1) [[I]], i32 0, i32 0)
+; CHECK-NEXT:    [[I5:%.*]] = tail call i32 
@llvm.spv.resource.updatecounter.tspirv.VulkanBuffer_i32_12_1t(target("spirv.VulkanBuffer",
 i32, 12, 1) [[I4]], i8 1)
+; CHECK-NEXT:    br label %[[EXIT]]
+; CHECK:       [[EXIT]]:
+; CHECK-NEXT:    [[I6:%.*]] = tail call target("spirv.VulkanBuffer", i32, 12, 
1) 
@llvm.spv.resource.counterhandlefrombinding.tspirv.VulkanBuffer_i32_12_1t.tspirv.VulkanBuffer_a0i32_12_1t(target("spirv.VulkanBuffer",
 [0 x i32], 12, 1) [[I]], i32 0, i32 0)
+; CHECK-NEXT:    [[I7:%.*]] = tail call i32 
@llvm.spv.resource.updatecounter.tspirv.VulkanBuffer_i32_12_1t(target("spirv.VulkanBuffer",
 i32, 12, 1) [[I6]], i8 1)
+; CHECK-NEXT:    [[I8:%.*]] = tail call noundef nonnull align 4 
dereferenceable(4) ptr addrspace(11) 
@llvm.spv.resource.getpointer.p11.tspirv.VulkanBuffer_a0i32_12_1t.i32(target("spirv.VulkanBuffer",
 [0 x i32], 12, 1) [[I]], i32 0)
+; CHECK-NEXT:    store i32 [[I7]], ptr addrspace(11) [[I8]], align 4
+; CHECK-NEXT:    ret void
+;
+entry:
+  %0 = tail call target("spirv.VulkanBuffer", [0 x i32], 12, 1) 
@llvm.spv.resource.handlefrombinding.tspirv.VulkanBuffer_a0i32_12_1t(i32 0, i32 
0, i32 4, i32 0, ptr nonnull @Out.str)
+  %1 = load i32, ptr addrspace(2) @cond, align 4
+  %loadedv = trunc nuw i32 %1 to i1
+  br i1 %loadedv, label %if.then, label %if.else
+
+if.then:                                          ; preds = %entry
+  %2 = tail call target("spirv.VulkanBuffer", i32, 12, 1) 
@llvm.spv.resource.counterhandlefrombinding.tspirv.VulkanBuffer_i32_12_1t.tspirv.VulkanBuffer_a0i32_12_1t(target("spirv.VulkanBuffer",
 [0 x i32], 12, 1) %0, i32 0, i32 0)
+  %3 = tail call i32 
@llvm.spv.resource.updatecounter.tspirv.VulkanBuffer_i32_12_1t(target("spirv.VulkanBuffer",
 i32, 12, 1) %2, i8 1)
+  br label %exit
+
+if.else:                                          ; preds = %entry
+  %4 = tail call target("spirv.VulkanBuffer", i32, 12, 1) 
@llvm.spv.resource.counterhandlefrombinding.tspirv.VulkanBuffer_i32_12_1t.tspirv.VulkanBuffer_a0i32_12_1t(target("spirv.VulkanBuffer",
 [0 x i32], 12, 1) %0, i32 0, i32 0)
+  %5 = tail call i32 
@llvm.spv.resource.updatecounter.tspirv.VulkanBuffer_i32_12_1t(target("spirv.VulkanBuffer",
 i32, 12, 1) %4, i8 1)
+  br label %exit
+
+exit:                                             ; preds = %if.else, %if.then
+  %6 = tail call target("spirv.VulkanBuffer", i32, 12, 1) 
@llvm.spv.resource.counterhandlefrombinding.tspirv.VulkanBuffer_i32_12_1t.tspirv.VulkanBuffer_a0i32_12_1t(target("spirv.VulkanBuffer",
 [0 x i32], 12, 1) %0, i32 0, i32 0)
+  %7 = tail call i32 
@llvm.spv.resource.updatecounter.tspirv.VulkanBuffer_i32_12_1t(target("spirv.VulkanBuffer",
 i32, 12, 1) %6, i8 1)
+  %8 = tail call noundef nonnull align 4 dereferenceable(4) ptr addrspace(11) 
@llvm.spv.resource.getpointer.p11.tspirv.VulkanBuffer_a0i32_12_1t.i32(target("spirv.VulkanBuffer",
 [0 x i32], 12, 1) %0, i32 0)
+  store i32 %7, ptr addrspace(11) %8, align 4
+  ret void
+}

>From 7423d1300e32ce305f0ead0bd69d83f5923cff45 Mon Sep 17 00:00:00 2001
From: Finn Plummer <[email protected]>
Date: Thu, 25 Jun 2026 16:31:43 +0000
Subject: [PATCH 4/5] review: add tests of convergent tokens being emitted

---
 .../resources/StructuredBuffers-constructors.hlsl      |  2 ++
 .../resources/StructuredBuffers-subscripts.hlsl        | 10 ++++++----
 2 files changed, 8 insertions(+), 4 deletions(-)

diff --git 
a/clang/test/CodeGenHLSL/resources/StructuredBuffers-constructors.hlsl 
b/clang/test/CodeGenHLSL/resources/StructuredBuffers-constructors.hlsl
index 96c2d950b50d7..cd0d2ec0c4c2a 100644
--- a/clang/test/CodeGenHLSL/resources/StructuredBuffers-constructors.hlsl
+++ b/clang/test/CodeGenHLSL/resources/StructuredBuffers-constructors.hlsl
@@ -57,6 +57,7 @@ export void foo() {
 // CHECK: define linkonce_odr hidden void 
@hlsl::RWStructuredBuffer<float>::__createFromImplicitBindingWithImplicitCounter(unsigned
 int, unsigned int, int, unsigned int, char const*, unsigned int)
 // CHECK-SAME: (ptr {{.*}} sret(%"class.hlsl::RWStructuredBuffer") align 
{{(4|8)}} %[[RetValue2:.*]], i32 noundef %orderId, 
 // CHECK-SAME: i32 noundef %spaceNo, i32 noundef %range, i32 noundef %index, 
ptr noundef %name, i32 noundef %counterOrderId)
+// CHECK-SPV: %[[ConvTok:.*]] = call token 
@llvm.experimental.convergence.entry()
 // CHECK: %[[Tmp2:.*]] = alloca %"class.hlsl::RWStructuredBuffer"
 // CHECK-DXIL: %[[Handle2:.*]] = call target("dx.RawBuffer", float, 1, 0)
 // CHECK-DXIL-SAME: 
@llvm.dx.resource.handlefromimplicitbinding.tdx.RawBuffer_f32_1_0t(
@@ -73,6 +74,7 @@ export void foo() {
 // CHECK-SPV: %[[HandlePtr:.*]] = getelementptr inbounds nuw 
%"class.hlsl::RWStructuredBuffer", ptr %[[Tmp2]], i32 0, i32 0
 // CHECK-SPV: %[[LoadedHandle:.*]] = load target("spirv.VulkanBuffer", [0 x 
float], 12, 1), ptr %[[HandlePtr]], align 8
 // CHECK-SPV: %[[CounterHandle:.*]] = call target("spirv.VulkanBuffer", i32, 
12, 1) @llvm.spv.resource.counterhandlefromimplicitbinding
+// CHECK-SPV-SAME: [ "convergencectrl"(token %[[ConvTok]]) ]
 // CHECK-SPV: %[[CounterHandlePtr:.*]] = getelementptr inbounds nuw 
%"class.hlsl::RWStructuredBuffer", ptr %[[Tmp2]], i32 0, i32 1
 // CHECK-SPV-NEXT: store target("spirv.VulkanBuffer", i32, 12, 1) 
%[[CounterHandle]], ptr %[[CounterHandlePtr]], align 8
 // CHECK: call void 
@hlsl::RWStructuredBuffer<float>::RWStructuredBuffer(hlsl::RWStructuredBuffer<float>
 const&)(ptr {{.*}} %[[RetValue2]], ptr {{.*}} %[[Tmp2]])
diff --git a/clang/test/CodeGenHLSL/resources/StructuredBuffers-subscripts.hlsl 
b/clang/test/CodeGenHLSL/resources/StructuredBuffers-subscripts.hlsl
index 4e1c1b7b55984..83a3aac79e18e 100644
--- a/clang/test/CodeGenHLSL/resources/StructuredBuffers-subscripts.hlsl
+++ b/clang/test/CodeGenHLSL/resources/StructuredBuffers-subscripts.hlsl
@@ -20,11 +20,13 @@ void main(unsigned GI : SV_GroupIndex) {
 
   // CHECK: %[[TMP:.*]] = alloca %struct.S, align 1
 
-  // DXIL: %[[INPTR:.*]] = call noundef nonnull align 4 dereferenceable(4) ptr 
@llvm.dx.resource.getpointer.p0.tdx.RawBuffer_i32_0_0t.i32(target("dx.RawBuffer",
 i32, 0, 0) %{{.*}}, i32 %{{.*}})
-  // SPV: %[[INPTR:.*]] = call noundef align 4 dereferenceable(4) ptr 
addrspace(11) 
@llvm.spv.resource.getpointer.p11.tspirv.VulkanBuffer_a0i32_12_0t.i32(target("spirv.VulkanBuffer",
 [0 x i32], 12, 0) %{{.*}}, i32 %{{.*}})
+  // CHECK: %[[CONVTOK:.*]] = call token @llvm.experimental.convergence.entry()
+
+  // DXIL: %[[INPTR:.*]] = call noundef nonnull align 4 dereferenceable(4) ptr 
@llvm.dx.resource.getpointer.p0.tdx.RawBuffer_i32_0_0t.i32(target("dx.RawBuffer",
 i32, 0, 0) %{{.*}}, i32 %{{.*}}) [ "convergencectrl"(token %[[CONVTOK]]) ]
+  // SPV: %[[INPTR:.*]] = call noundef align 4 dereferenceable(4) ptr 
addrspace(11) 
@llvm.spv.resource.getpointer.p11.tspirv.VulkanBuffer_a0i32_12_0t.i32(target("spirv.VulkanBuffer",
 [0 x i32], 12, 0) %{{.*}}, i32 %{{.*}}) [ "convergencectrl"(token 
%[[CONVTOK]]) ]
   // CHECK: %[[LOAD:.*]] = load i32, ptr {{.*}}%[[INPTR]]
-  // DXIL: %[[OUT1PTR:.*]] = call noundef nonnull align 4 dereferenceable(4) 
ptr 
@llvm.dx.resource.getpointer.p0.tdx.RawBuffer_i32_1_0t.i32(target("dx.RawBuffer",
 i32, 1, 0) %{{.*}}, i32 %{{.*}})
-  // SPV: %[[OUT1PTR:.*]] =  call noundef align 4 dereferenceable(4) ptr 
addrspace(11) 
@llvm.spv.resource.getpointer.p11.tspirv.VulkanBuffer_a0i32_12_1t.i32(target("spirv.VulkanBuffer",
 [0 x i32], 12, 1) %{{.*}}, i32 %{{.*}})
+  // DXIL: %[[OUT1PTR:.*]] = call noundef nonnull align 4 dereferenceable(4) 
ptr 
@llvm.dx.resource.getpointer.p0.tdx.RawBuffer_i32_1_0t.i32(target("dx.RawBuffer",
 i32, 1, 0) %{{.*}}, i32 %{{.*}}) [ "convergencectrl"(token %[[CONVTOK]]) ]
+  // SPV: %[[OUT1PTR:.*]] =  call noundef align 4 dereferenceable(4) ptr 
addrspace(11) 
@llvm.spv.resource.getpointer.p11.tspirv.VulkanBuffer_a0i32_12_1t.i32(target("spirv.VulkanBuffer",
 [0 x i32], 12, 1) %{{.*}}, i32 %{{.*}}) [ "convergencectrl"(token 
%[[CONVTOK]]) ]
   // CHECK: store i32 %[[LOAD]], ptr {{.*}}%[[OUT1PTR]]
   Out1[GI] = In[GI];
 

>From 02d763b19502a04e74fdc7b7903189ac43c2b584 Mon Sep 17 00:00:00 2001
From: Finn Plummer <[email protected]>
Date: Thu, 25 Jun 2026 16:36:22 +0000
Subject: [PATCH 5/5] review: update test descriptions

---
 llvm/test/Transforms/GVN/no-sink-spvcounterhandle.ll           | 3 +++
 llvm/test/Transforms/GVN/no-sink-spvgetpointer.ll              | 3 +++
 .../test/Transforms/SimplifyCFG/DirectX/no-phi-dxgetpointer.ll | 3 +++
 .../test/Transforms/SimplifyCFG/SPIRV/no-sink-spvgetpointer.ll | 3 +++
 4 files changed, 12 insertions(+)

diff --git a/llvm/test/Transforms/GVN/no-sink-spvcounterhandle.ll 
b/llvm/test/Transforms/GVN/no-sink-spvcounterhandle.ll
index 137f63f08f0a8..9065fbbed0da7 100644
--- a/llvm/test/Transforms/GVN/no-sink-spvcounterhandle.ll
+++ b/llvm/test/Transforms/GVN/no-sink-spvcounterhandle.ll
@@ -5,6 +5,9 @@
 ; convergent, the GVN pass is prevented from sinking these intrinsics out of
 ; branches which would create phi nodes on the returned counter handle.
 ;
+; The CHECK lines below match the input IR exactly, so this test verifies that
+; the pass makes no changes to the IR.
+;
 ; It models the following HLSL:
 ;
 ;   RWStructuredBuffer<int> Out[4] : register(u0);
diff --git a/llvm/test/Transforms/GVN/no-sink-spvgetpointer.ll 
b/llvm/test/Transforms/GVN/no-sink-spvgetpointer.ll
index f21dda66986fd..5e6c2a83118bd 100644
--- a/llvm/test/Transforms/GVN/no-sink-spvgetpointer.ll
+++ b/llvm/test/Transforms/GVN/no-sink-spvgetpointer.ll
@@ -4,6 +4,9 @@
 ; This test ensures that given spv.resource.getpointer is marked convergent,
 ; the GVN pass is prevented from sinking these intrinsics out of branches which
 ; would create phi nodes on the returned ptr.
+;
+; The CHECK lines below match the input IR exactly, so this test verifies that
+; the pass makes no changes to the IR.
 
 %"class.hlsl::RWBuffer" = type { target("spirv.Image", i32, 5, 2, 0, 0, 2, 1) }
 %"class.hlsl::RWStructuredBuffer" = type { target("spirv.VulkanBuffer", [0 x 
i32], 12, 1), target("spirv.VulkanBuffer", [0 x i32], 12, 1) }
diff --git a/llvm/test/Transforms/SimplifyCFG/DirectX/no-phi-dxgetpointer.ll 
b/llvm/test/Transforms/SimplifyCFG/DirectX/no-phi-dxgetpointer.ll
index 24dcf473513ce..395fa7e073f3f 100644
--- a/llvm/test/Transforms/SimplifyCFG/DirectX/no-phi-dxgetpointer.ll
+++ b/llvm/test/Transforms/SimplifyCFG/DirectX/no-phi-dxgetpointer.ll
@@ -11,6 +11,9 @@
 ;   %ptr = phi ptr [ %bufA.ptr, %if.then ], [ %bufB.ptr, %if.else ]
 ; which is an illegal phi node on a resource pointer.
 ;
+; The CHECK lines below match the input IR exactly, so this test verifies that
+; the pass makes no changes to the IR.
+;
 ; NOTE: The following IR corresponds to the (post-inlining) lowering of:
 ;
 ;   RWStructuredBuffer<float> bufA : register(u0);
diff --git a/llvm/test/Transforms/SimplifyCFG/SPIRV/no-sink-spvgetpointer.ll 
b/llvm/test/Transforms/SimplifyCFG/SPIRV/no-sink-spvgetpointer.ll
index 4071cf518eb7a..ebd1c0cc84131 100644
--- a/llvm/test/Transforms/SimplifyCFG/SPIRV/no-sink-spvgetpointer.ll
+++ b/llvm/test/Transforms/SimplifyCFG/SPIRV/no-sink-spvgetpointer.ll
@@ -4,6 +4,9 @@
 ; This test ensures that given spv.resource.getpointer is marked convergent,
 ; the SimplifyCFG pass will be prevented from sinking these intrinsics out of
 ; branches which would create phi nodes on the returned ptr.
+;
+; The CHECK lines below match the input IR exactly, so this test verifies that
+; the pass makes no changes to the IR.
 
 %"class.hlsl::RWStructuredBuffer" = type { target("spirv.VulkanBuffer", [0 x 
i32], 12, 1), target("spirv.VulkanBuffer", [0 x i32], 12, 1) }
 %__cblayout_d = type <{ i32, i32, i32, i32 }>

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

Reply via email to