https://github.com/farzonl updated 
https://github.com/llvm/llvm-project/pull/154620

>From b51b68d7b5e7019687f2b8617178f2a8d9932278 Mon Sep 17 00:00:00 2001
From: Farzon Lotfi <farzonlo...@microsoft.com>
Date: Wed, 20 Aug 2025 17:11:37 -0400
Subject: [PATCH 01/14] [DirectX] Make dx.RawBuffer an op that can't be
 replaced

fixes #152348

SimplifyCFG collapses raw buffer store from a if\else load into a select.

This change prevents the TargetExtType dx.Rawbuffer from being replace thus 
preserving the if\else blocks.

A further change was needed to eliminate the phi node before we process 
Intrinsic::dx_resource_getpointer in DXILResourceAccess.cpp
---
 .../lib/Target/DirectX/DXILResourceAccess.cpp | 106 +++++++++++++++++-
 llvm/lib/Transforms/Utils/Local.cpp           |   4 +
 llvm/test/CodeGen/DirectX/issue-152348.ll     |  73 ++++++++++++
 3 files changed, 180 insertions(+), 3 deletions(-)
 create mode 100644 llvm/test/CodeGen/DirectX/issue-152348.ll

diff --git a/llvm/lib/Target/DirectX/DXILResourceAccess.cpp 
b/llvm/lib/Target/DirectX/DXILResourceAccess.cpp
index c33ec0efd73ca..59e49d6f24201 100644
--- a/llvm/lib/Target/DirectX/DXILResourceAccess.cpp
+++ b/llvm/lib/Target/DirectX/DXILResourceAccess.cpp
@@ -9,13 +9,17 @@
 #include "DXILResourceAccess.h"
 #include "DirectX.h"
 #include "llvm/Analysis/DXILResource.h"
+#include "llvm/IR/BasicBlock.h"
 #include "llvm/IR/Dominators.h"
 #include "llvm/IR/IRBuilder.h"
+#include "llvm/IR/Instruction.h"
 #include "llvm/IR/Instructions.h"
 #include "llvm/IR/IntrinsicInst.h"
 #include "llvm/IR/Intrinsics.h"
 #include "llvm/IR/IntrinsicsDirectX.h"
+#include "llvm/IR/User.h"
 #include "llvm/InitializePasses.h"
+#include "llvm/Transforms/Utils/ValueMapper.h"
 
 #define DEBUG_TYPE "dxil-resource-access"
 
@@ -198,6 +202,98 @@ static void createLoadIntrinsic(IntrinsicInst *II, 
LoadInst *LI, Value *Offset,
   llvm_unreachable("Unhandled case in switch");
 }
 
+static void collectBlockUseDef(Instruction *Start,
+                               SmallVectorImpl<Instruction *> &Out) {
+  SmallPtrSet<Instruction *, 32> Visited;
+  SmallVector<Instruction *, 32> Worklist;
+  auto *BB = Start->getParent();
+
+  // Seed with direct users in this block.
+  for (User *U : Start->users()) {
+    if (auto *I = dyn_cast<Instruction>(U)) {
+      if (I->getParent() == BB)
+        Worklist.push_back(I);
+    }
+  }
+
+  // BFS over transitive users, constrained to the same block.
+  while (!Worklist.empty()) {
+    Instruction *I = Worklist.pop_back_val();
+    if (!Visited.insert(I).second)
+      continue;
+    Out.push_back(I);
+
+    for (User *U : I->users()) {
+      if (auto *J = dyn_cast<Instruction>(U)) {
+        if (J->getParent() == BB)
+          Worklist.push_back(J);
+      }
+    }
+    for (Use &V : I->operands()) {
+      if (auto *J = dyn_cast<Instruction>(V)) {
+        if (J->getParent() == BB && V != Start)
+          Worklist.push_back(J);
+      }
+    }
+  }
+
+  // Order results in program order.
+  DenseMap<const Instruction *, unsigned> Ord;
+  unsigned Idx = 0;
+  for (Instruction &I : *BB)
+    Ord[&I] = Idx++;
+
+  llvm::sort(Out, [&](Instruction *A, Instruction *B) {
+    return Ord.lookup(A) < Ord.lookup(B);
+  });
+}
+
+static void phiNodeRemapHelper(PHINode *Phi, BasicBlock *BB,
+                               IRBuilder<> &Builder,
+                               SmallVector<Instruction *> &UsesInBlock) {
+
+  ValueToValueMapTy VMap;
+  Value *Val = Phi->getIncomingValueForBlock(BB);
+  VMap[Phi] = Val;
+  Builder.SetInsertPoint(llvm::dyn_cast<Instruction>(Val)->getNextNode());
+  for (Instruction *I : UsesInBlock) {
+    Instruction *ThenClone = I->clone();
+    RemapInstruction(ThenClone, VMap,
+                     RF_NoModuleLevelChanges | RF_IgnoreMissingLocals);
+    Builder.Insert(ThenClone);
+    VMap[I] = ThenClone;
+  }
+}
+
+static void phiNodeReplacement(IntrinsicInst *II) {
+  SmallVector<Instruction *> DeadInsts;
+  for (User *U : II->users()) {
+    if (auto *Phi = dyn_cast<PHINode>(U)) {
+
+      auto *ThenBB = Phi->getIncomingBlock(0);
+      auto *ElseBB = Phi->getIncomingBlock(1);
+      IRBuilder<> Builder(Phi);
+
+      SmallVector<Instruction *> UsesInBlock;
+      collectBlockUseDef(Phi, UsesInBlock);
+
+      phiNodeRemapHelper(Phi, ThenBB, Builder, UsesInBlock);
+      phiNodeRemapHelper(Phi, ElseBB, Builder, UsesInBlock);
+
+      DeadInsts.push_back(Phi);
+
+      for (Instruction *I : UsesInBlock) {
+        DeadInsts.push_back(I);
+      }
+    }
+  }
+
+  // Traverse the now-dead instructions in RPO and remove them.
+  for (Instruction *Dead : llvm::reverse(DeadInsts))
+    Dead->eraseFromParent();
+  DeadInsts.clear();
+}
+
 static void replaceAccess(IntrinsicInst *II, dxil::ResourceTypeInfo &RTI) {
   // Process users keeping track of indexing accumulated from GEPs.
   struct AccessAndOffset {
@@ -229,7 +325,6 @@ static void replaceAccess(IntrinsicInst *II, 
dxil::ResourceTypeInfo &RTI) {
     } else if (auto *LI = dyn_cast<LoadInst>(Current.Access)) {
       createLoadIntrinsic(II, LI, Current.Offset, RTI);
       DeadInsts.push_back(LI);
-
     } else
       llvm_unreachable("Unhandled instruction - pointer escaped?");
   }
@@ -242,13 +337,19 @@ static void replaceAccess(IntrinsicInst *II, 
dxil::ResourceTypeInfo &RTI) {
 
 static bool transformResourcePointers(Function &F, DXILResourceTypeMap &DRTM) {
   SmallVector<std::pair<IntrinsicInst *, dxil::ResourceTypeInfo>> Resources;
-  for (BasicBlock &BB : F)
+  for (BasicBlock &BB : F) {
+    for (Instruction &I : make_early_inc_range(BB))
+      if (auto *II = dyn_cast<IntrinsicInst>(&I))
+        if (II->getIntrinsicID() == Intrinsic::dx_resource_getpointer)
+          phiNodeReplacement(II);
+
     for (Instruction &I : BB)
       if (auto *II = dyn_cast<IntrinsicInst>(&I))
         if (II->getIntrinsicID() == Intrinsic::dx_resource_getpointer) {
           auto *HandleTy = 
cast<TargetExtType>(II->getArgOperand(0)->getType());
           Resources.emplace_back(II, DRTM[HandleTy]);
         }
+  }
 
   for (auto &[II, RI] : Resources)
     replaceAccess(II, RI);
@@ -279,7 +380,6 @@ class DXILResourceAccessLegacy : public FunctionPass {
   bool runOnFunction(Function &F) override {
     DXILResourceTypeMap &DRTM =
         getAnalysis<DXILResourceTypeWrapperPass>().getResourceTypeMap();
-
     return transformResourcePointers(F, DRTM);
   }
   StringRef getPassName() const override { return "DXIL Resource Access"; }
diff --git a/llvm/lib/Transforms/Utils/Local.cpp 
b/llvm/lib/Transforms/Utils/Local.cpp
index 9d759bc244e3d..1faf6f0ae5993 100644
--- a/llvm/lib/Transforms/Utils/Local.cpp
+++ b/llvm/lib/Transforms/Utils/Local.cpp
@@ -3852,6 +3852,10 @@ bool llvm::canReplaceOperandWithVariable(const 
Instruction *I, unsigned OpIdx) {
   if (I->isLifetimeStartOrEnd())
     return false;
 
+  if (auto *TT = dyn_cast<TargetExtType>(Op->getType());
+      TT && TT->getName() == "dx.RawBuffer")
+    return false;
+
   // Early exit.
   if (!isa<Constant, InlineAsm>(Op))
     return true;
diff --git a/llvm/test/CodeGen/DirectX/issue-152348.ll 
b/llvm/test/CodeGen/DirectX/issue-152348.ll
new file mode 100644
index 0000000000000..508a1681d1258
--- /dev/null
+++ b/llvm/test/CodeGen/DirectX/issue-152348.ll
@@ -0,0 +1,73 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py 
UTC_ARGS: --version 5
+; RUN: opt -S -dxil-resource-type -dxil-resource-access 
-mtriple=dxil-pc-shadermodel6.3-library %s | FileCheck %s
+
+%__cblayout_d = type <{ i32, i32, i32, i32 }>
+
+@.str = internal unnamed_addr constant [2 x i8] c"a\00", align 1
+@d.cb = local_unnamed_addr global target("dx.CBuffer", target("dx.Layout", 
%__cblayout_d, 16, 0, 4, 8, 12)) poison
+@e = external hidden local_unnamed_addr addrspace(2) global i32, align 4
+
+@d.str = internal unnamed_addr constant [2 x i8] c"d\00", align 1
+
+define void @CSMain() local_unnamed_addr {
+; CHECK-LABEL: define void @CSMain() local_unnamed_addr {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[D_CB_H_I_I:%.*]] = tail call target("dx.CBuffer", 
target("dx.Layout", [[__CBLAYOUT_D:%.*]], 16, 0, 4, 8, 12)) 
@llvm.dx.resource.handlefromimplicitbinding.tdx.CBuffer_tdx.Layout_s___cblayout_ds_16_0_4_8_12tt(i32
 3, i32 0, i32 1, i32 0, i1 false, ptr nonnull @d.str)
+; CHECK-NEXT:    store target("dx.CBuffer", target("dx.Layout", 
[[__CBLAYOUT_D]], 16, 0, 4, 8, 12)) [[D_CB_H_I_I]], ptr @d.cb, align 4
+; CHECK-NEXT:    [[TMP0:%.*]] = load i32, ptr addrspace(2) @e, align 4
+; CHECK-NEXT:    [[TOBOOL_NOT_I:%.*]] = icmp eq i32 [[TMP0]], 0
+; CHECK-NEXT:    [[TMP1:%.*]] = load i32, ptr addrspace(2) @e, align 4
+; CHECK-NEXT:    br i1 [[TOBOOL_NOT_I]], label %[[IF_ELSE_I:.*]], label 
%[[IF_THEN_I:.*]]
+; CHECK:       [[IF_THEN_I]]:
+; CHECK-NEXT:    [[TMP2:%.*]] = tail call target("dx.RawBuffer", half, 1, 0) 
@llvm.dx.resource.handlefromimplicitbinding.tdx.RawBuffer_f16_1_0t(i32 1, i32 
0, i32 1, i32 0, i1 false, ptr nonnull @.str)
+; CHECK-NEXT:    [[TMP3:%.*]] = load i32, ptr addrspace(2) @e, align 4
+; CHECK-NEXT:    [[TMP4:%.*]] = tail call target("dx.RawBuffer", half, 1, 0) 
@llvm.dx.resource.handlefromimplicitbinding.tdx.RawBuffer_f16_1_0t(i32 2, i32 
0, i32 1, i32 0, i1 false, ptr nonnull @.str)
+; CHECK-NEXT:    [[TMP5:%.*]] = call { half, i1 } 
@llvm.dx.resource.load.rawbuffer.f16.tdx.RawBuffer_f16_1_0t(target("dx.RawBuffer",
 half, 1, 0) [[TMP2]], i32 [[TMP3]], i32 0)
+; CHECK-NEXT:    [[TMP6:%.*]] = extractvalue { half, i1 } [[TMP5]], 0
+; CHECK-NEXT:    call void 
@llvm.dx.resource.store.rawbuffer.tdx.RawBuffer_f16_1_0t.f16(target("dx.RawBuffer",
 half, 1, 0) [[TMP4]], i32 [[TMP1]], i32 0, half [[TMP6]])
+; CHECK-NEXT:    br label %[[_Z6CSMAINV_EXIT:.*]]
+; CHECK:       [[IF_ELSE_I]]:
+; CHECK-NEXT:    [[TMP7:%.*]] = tail call target("dx.RawBuffer", half, 1, 0) 
@llvm.dx.resource.handlefromimplicitbinding.tdx.RawBuffer_f16_1_0t(i32 0, i32 
0, i32 1, i32 0, i1 false, ptr nonnull @.str)
+; CHECK-NEXT:    [[TMP8:%.*]] = load i32, ptr addrspace(2) @e, align 4
+; CHECK-NEXT:    [[TMP9:%.*]] = tail call target("dx.RawBuffer", half, 1, 0) 
@llvm.dx.resource.handlefromimplicitbinding.tdx.RawBuffer_f16_1_0t(i32 2, i32 
0, i32 1, i32 0, i1 false, ptr nonnull @.str)
+; CHECK-NEXT:    [[TMP10:%.*]] = call { half, i1 } 
@llvm.dx.resource.load.rawbuffer.f16.tdx.RawBuffer_f16_1_0t(target("dx.RawBuffer",
 half, 1, 0) [[TMP7]], i32 [[TMP8]], i32 0)
+; CHECK-NEXT:    [[TMP11:%.*]] = extractvalue { half, i1 } [[TMP10]], 0
+; CHECK-NEXT:    call void 
@llvm.dx.resource.store.rawbuffer.tdx.RawBuffer_f16_1_0t.f16(target("dx.RawBuffer",
 half, 1, 0) [[TMP9]], i32 [[TMP1]], i32 0, half [[TMP11]])
+; CHECK-NEXT:    br label %[[_Z6CSMAINV_EXIT]]
+; CHECK:       [[_Z6CSMAINV_EXIT]]:
+; CHECK-NEXT:    ret void
+;
+entry:
+  %d.cb_h.i.i = tail call target("dx.CBuffer", target("dx.Layout", 
%__cblayout_d, 16, 0, 4, 8, 12)) 
@llvm.dx.resource.handlefromimplicitbinding.tdx.CBuffer_tdx.Layout_s___cblayout_ds_16_0_4_8_12tt(i32
 3, i32 0, i32 1, i32 0, i1 false, ptr nonnull @d.str)
+  store target("dx.CBuffer", target("dx.Layout", %__cblayout_d, 16, 0, 4, 8, 
12)) %d.cb_h.i.i, ptr @d.cb, align 4
+  %0 = load i32, ptr addrspace(2) @e, align 4
+  %tobool.not.i = icmp eq i32 %0, 0
+  %1 = load i32, ptr addrspace(2) @e, align 4
+  br i1 %tobool.not.i, label %if.else.i, label %if.then.i
+
+if.then.i:                                        ; preds = %entry
+  %2 = tail call target("dx.RawBuffer", half, 1, 0) 
@llvm.dx.resource.handlefromimplicitbinding.tdx.RawBuffer_f16_1_0t(i32 1, i32 
0, i32 1, i32 0, i1 false, ptr nonnull @.str)
+  %3 = load i32, ptr addrspace(2) @e, align 4
+  %4 = tail call noundef nonnull align 2 dereferenceable(2) ptr 
@llvm.dx.resource.getpointer.p0.tdx.RawBuffer_f16_1_0t(target("dx.RawBuffer", 
half, 1, 0) %2, i32 %3)
+  br label %_Z6CSMainv.exit
+
+if.else.i:                                        ; preds = %entry
+  %5 = tail call target("dx.RawBuffer", half, 1, 0) 
@llvm.dx.resource.handlefromimplicitbinding.tdx.RawBuffer_f16_1_0t(i32 0, i32 
0, i32 1, i32 0, i1 false, ptr nonnull @.str)
+  %6 = load i32, ptr addrspace(2) @e, align 4
+  %7 = tail call noundef nonnull align 2 dereferenceable(2) ptr 
@llvm.dx.resource.getpointer.p0.tdx.RawBuffer_f16_1_0t(target("dx.RawBuffer", 
half, 1, 0) %5, i32 %6)
+  br label %_Z6CSMainv.exit
+
+_Z6CSMainv.exit:                                  ; preds = %if.then.i, 
%if.else.i
+  %.sink1 = phi ptr [ %4, %if.then.i ], [ %7, %if.else.i ]
+  %8 = tail call target("dx.RawBuffer", half, 1, 0) 
@llvm.dx.resource.handlefromimplicitbinding.tdx.RawBuffer_f16_1_0t(i32 2, i32 
0, i32 1, i32 0, i1 false, ptr nonnull @.str)
+  %9 = tail call noundef nonnull align 2 dereferenceable(2) ptr 
@llvm.dx.resource.getpointer.p0.tdx.RawBuffer_f16_1_0t(target("dx.RawBuffer", 
half, 1, 0) %8, i32 %1)
+  %10 = load half, ptr %.sink1, align 2
+  store half %10, ptr %9, align 2
+  ret void
+
+; uselistorder directives
+  uselistorder label %_Z6CSMainv.exit, { 1, 0 }
+}
+
+; uselistorder directives
+uselistorder ptr 
@llvm.dx.resource.handlefromimplicitbinding.tdx.RawBuffer_f16_1_0t, { 1, 2, 0 }

>From c7d44abef414110dda945298d58f7ff339416d76 Mon Sep 17 00:00:00 2001
From: Farzon Lotfi <farzonlo...@microsoft.com>
Date: Thu, 21 Aug 2025 11:00:13 -0400
Subject: [PATCH 02/14] update to handle multiple phi nodes

---
 .../lib/Target/DirectX/DXILResourceAccess.cpp | 24 +++---
 llvm/test/CodeGen/DirectX/issue-152348.ll     | 82 +++++++++++++++++--
 2 files changed, 90 insertions(+), 16 deletions(-)

diff --git a/llvm/lib/Target/DirectX/DXILResourceAccess.cpp 
b/llvm/lib/Target/DirectX/DXILResourceAccess.cpp
index 59e49d6f24201..e09e71b679031 100644
--- a/llvm/lib/Target/DirectX/DXILResourceAccess.cpp
+++ b/llvm/lib/Target/DirectX/DXILResourceAccess.cpp
@@ -255,13 +255,18 @@ static void phiNodeRemapHelper(PHINode *Phi, BasicBlock 
*BB,
   ValueToValueMapTy VMap;
   Value *Val = Phi->getIncomingValueForBlock(BB);
   VMap[Phi] = Val;
-  Builder.SetInsertPoint(llvm::dyn_cast<Instruction>(Val)->getNextNode());
+  Builder.SetInsertPoint(&BB->back());
   for (Instruction *I : UsesInBlock) {
-    Instruction *ThenClone = I->clone();
-    RemapInstruction(ThenClone, VMap,
+    // don't clone over the Phi just remap them
+    if (auto *PhiNested = dyn_cast<PHINode>(I)) {
+      VMap[PhiNested] = PhiNested->getIncomingValueForBlock(BB);
+      continue;
+    }
+    Instruction *Clone = I->clone();
+    RemapInstruction(Clone, VMap,
                      RF_NoModuleLevelChanges | RF_IgnoreMissingLocals);
-    Builder.Insert(ThenClone);
-    VMap[I] = ThenClone;
+    Builder.Insert(Clone);
+    VMap[I] = Clone;
   }
 }
 
@@ -270,15 +275,14 @@ static void phiNodeReplacement(IntrinsicInst *II) {
   for (User *U : II->users()) {
     if (auto *Phi = dyn_cast<PHINode>(U)) {
 
-      auto *ThenBB = Phi->getIncomingBlock(0);
-      auto *ElseBB = Phi->getIncomingBlock(1);
       IRBuilder<> Builder(Phi);
-
       SmallVector<Instruction *> UsesInBlock;
       collectBlockUseDef(Phi, UsesInBlock);
 
-      phiNodeRemapHelper(Phi, ThenBB, Builder, UsesInBlock);
-      phiNodeRemapHelper(Phi, ElseBB, Builder, UsesInBlock);
+      for (uint I = 0; I < Phi->getNumIncomingValues(); I++) {
+        auto *CurrIncomingBB = Phi->getIncomingBlock(I);
+        phiNodeRemapHelper(Phi, CurrIncomingBB, Builder, UsesInBlock);
+      }
 
       DeadInsts.push_back(Phi);
 
diff --git a/llvm/test/CodeGen/DirectX/issue-152348.ll 
b/llvm/test/CodeGen/DirectX/issue-152348.ll
index 508a1681d1258..693f01457bdc6 100644
--- a/llvm/test/CodeGen/DirectX/issue-152348.ll
+++ b/llvm/test/CodeGen/DirectX/issue-152348.ll
@@ -6,7 +6,6 @@
 @.str = internal unnamed_addr constant [2 x i8] c"a\00", align 1
 @d.cb = local_unnamed_addr global target("dx.CBuffer", target("dx.Layout", 
%__cblayout_d, 16, 0, 4, 8, 12)) poison
 @e = external hidden local_unnamed_addr addrspace(2) global i32, align 4
-
 @d.str = internal unnamed_addr constant [2 x i8] c"d\00", align 1
 
 define void @CSMain() local_unnamed_addr {
@@ -64,10 +63,81 @@ _Z6CSMainv.exit:                                  ; preds = 
%if.then.i, %if.else
   %10 = load half, ptr %.sink1, align 2
   store half %10, ptr %9, align 2
   ret void
-
-; uselistorder directives
-  uselistorder label %_Z6CSMainv.exit, { 1, 0 }
 }
 
-; uselistorder directives
-uselistorder ptr 
@llvm.dx.resource.handlefromimplicitbinding.tdx.RawBuffer_f16_1_0t, { 1, 2, 0 }
+define void @Main() local_unnamed_addr  {
+; CHECK-LABEL: define void @Main() local_unnamed_addr {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[TMP0:%.*]] = tail call target("dx.RawBuffer", half, 1, 0) 
@llvm.dx.resource.handlefromimplicitbinding.tdx.RawBuffer_f16_1_0t(i32 0, i32 
0, i32 1, i32 0, i1 false, ptr nonnull @.str)
+; CHECK-NEXT:    [[TMP1:%.*]] = tail call target("dx.RawBuffer", half, 1, 0) 
@llvm.dx.resource.handlefromimplicitbinding.tdx.RawBuffer_f16_1_0t(i32 1, i32 
0, i32 1, i32 0, i1 false, ptr nonnull @.str)
+; CHECK-NEXT:    [[D_CB_H_I_I:%.*]] = tail call target("dx.CBuffer", 
target("dx.Layout", [[__CBLAYOUT_D:%.*]], 16, 0, 4, 8, 12)) 
@llvm.dx.resource.handlefromimplicitbinding.tdx.CBuffer_tdx.Layout_s___cblayout_ds_16_0_4_8_12tt(i32
 3, i32 0, i32 1, i32 0, i1 false, ptr nonnull @d.str)
+; CHECK-NEXT:    store target("dx.CBuffer", target("dx.Layout", 
[[__CBLAYOUT_D]], 16, 0, 4, 8, 12)) [[D_CB_H_I_I]], ptr @d.cb, align 4
+; CHECK-NEXT:    [[TMP2:%.*]] = load i32, ptr addrspace(2) @e, align 4
+; CHECK-NEXT:    [[TOBOOL_NOT_I:%.*]] = icmp eq i32 [[TMP2]], 0
+; CHECK-NEXT:    br i1 [[TOBOOL_NOT_I]], label %[[IF_ELSE_I:.*]], label 
%[[IF_THEN_I:.*]]
+; CHECK:       [[IF_THEN_I]]:
+; CHECK-NEXT:    [[TMP3:%.*]] = load i32, ptr addrspace(2) @e, align 4
+; CHECK-NEXT:    [[TMP4:%.*]] = load i32, ptr addrspace(2) @e, align 4
+; CHECK-NEXT:    [[TMP5:%.*]] = tail call target("dx.RawBuffer", half, 1, 0) 
@llvm.dx.resource.handlefromimplicitbinding.tdx.RawBuffer_f16_1_0t(i32 2, i32 
0, i32 1, i32 0, i1 false, ptr nonnull @.str)
+; CHECK-NEXT:    [[TMP6:%.*]] = call { half, i1 } 
@llvm.dx.resource.load.rawbuffer.f16.tdx.RawBuffer_f16_1_0t(target("dx.RawBuffer",
 half, 1, 0) [[TMP1]], i32 [[TMP3]], i32 0)
+; CHECK-NEXT:    [[TMP7:%.*]] = extractvalue { half, i1 } [[TMP6]], 0
+; CHECK-NEXT:    call void 
@llvm.dx.resource.store.rawbuffer.tdx.RawBuffer_f16_1_0t.f16(target("dx.RawBuffer",
 half, 1, 0) [[TMP5]], i32 [[TMP4]], i32 0, half [[TMP7]])
+; CHECK-NEXT:    br label %[[_Z6MAINV_EXIT:.*]]
+; CHECK:       [[IF_ELSE_I]]:
+; CHECK-NEXT:    [[TMP8:%.*]] = load i32, ptr addrspace(2) @e, align 4
+; CHECK-NEXT:    [[CMP_I:%.*]] = icmp eq i32 [[TMP8]], 0
+; CHECK-NEXT:    br i1 [[CMP_I]], label %[[IF_THEN2_I:.*]], label 
%[[IF_ELSE6_I:.*]]
+; CHECK:       [[IF_THEN2_I]]:
+; CHECK-NEXT:    [[TMP9:%.*]] = tail call target("dx.RawBuffer", half, 1, 0) 
@llvm.dx.resource.handlefromimplicitbinding.tdx.RawBuffer_f16_1_0t(i32 2, i32 
0, i32 1, i32 0, i1 false, ptr nonnull @.str)
+; CHECK-NEXT:    [[TMP10:%.*]] = call { half, i1 } 
@llvm.dx.resource.load.rawbuffer.f16.tdx.RawBuffer_f16_1_0t(target("dx.RawBuffer",
 half, 1, 0) [[TMP1]], i32 0, i32 0)
+; CHECK-NEXT:    [[TMP11:%.*]] = extractvalue { half, i1 } [[TMP10]], 0
+; CHECK-NEXT:    call void 
@llvm.dx.resource.store.rawbuffer.tdx.RawBuffer_f16_1_0t.f16(target("dx.RawBuffer",
 half, 1, 0) [[TMP9]], i32 0, i32 0, half [[TMP11]])
+; CHECK-NEXT:    br label %[[_Z6MAINV_EXIT]]
+; CHECK:       [[IF_ELSE6_I]]:
+; CHECK-NEXT:    [[TMP12:%.*]] = load i32, ptr addrspace(2) @e, align 4
+; CHECK-NEXT:    [[TMP13:%.*]] = tail call target("dx.RawBuffer", half, 1, 0) 
@llvm.dx.resource.handlefromimplicitbinding.tdx.RawBuffer_f16_1_0t(i32 2, i32 
0, i32 1, i32 0, i1 false, ptr nonnull @.str)
+; CHECK-NEXT:    [[TMP14:%.*]] = call { half, i1 } 
@llvm.dx.resource.load.rawbuffer.f16.tdx.RawBuffer_f16_1_0t(target("dx.RawBuffer",
 half, 1, 0) [[TMP0]], i32 [[TMP12]], i32 0)
+; CHECK-NEXT:    [[TMP15:%.*]] = extractvalue { half, i1 } [[TMP14]], 0
+; CHECK-NEXT:    call void 
@llvm.dx.resource.store.rawbuffer.tdx.RawBuffer_f16_1_0t.f16(target("dx.RawBuffer",
 half, 1, 0) [[TMP13]], i32 [[TMP8]], i32 0, half [[TMP15]])
+; CHECK-NEXT:    br label %[[_Z6MAINV_EXIT]]
+; CHECK:       [[_Z6MAINV_EXIT]]:
+; CHECK-NEXT:    ret void
+;
+entry:
+  %0 = tail call target("dx.RawBuffer", half, 1, 0) 
@llvm.dx.resource.handlefromimplicitbinding.tdx.RawBuffer_f16_1_0t(i32 0, i32 
0, i32 1, i32 0, i1 false, ptr nonnull @.str)
+  %1 = tail call target("dx.RawBuffer", half, 1, 0) 
@llvm.dx.resource.handlefromimplicitbinding.tdx.RawBuffer_f16_1_0t(i32 1, i32 
0, i32 1, i32 0, i1 false, ptr nonnull @.str)
+  %d.cb_h.i.i = tail call target("dx.CBuffer", target("dx.Layout", 
%__cblayout_d, 16, 0, 4, 8, 12)) 
@llvm.dx.resource.handlefromimplicitbinding.tdx.CBuffer_tdx.Layout_s___cblayout_ds_16_0_4_8_12tt(i32
 3, i32 0, i32 1, i32 0, i1 false, ptr nonnull @d.str)
+  store target("dx.CBuffer", target("dx.Layout", %__cblayout_d, 16, 0, 4, 8, 
12)) %d.cb_h.i.i, ptr @d.cb, align 4
+  %2 = load i32, ptr addrspace(2) @e, align 4
+  %tobool.not.i = icmp eq i32 %2, 0
+  br i1 %tobool.not.i, label %if.else.i, label %if.then.i
+
+if.then.i:                                        ; preds = %entry
+  %3 = load i32, ptr addrspace(2) @e, align 4
+  %4 = tail call noundef nonnull align 2 dereferenceable(2) ptr 
@llvm.dx.resource.getpointer.p0.tdx.RawBuffer_f16_1_0t(target("dx.RawBuffer", 
half, 1, 0) %1, i32 %3)
+  %5 = load i32, ptr addrspace(2) @e, align 4
+  br label %_Z6Mainv.exit
+
+if.else.i:                                        ; preds = %entry
+  %6 = load i32, ptr addrspace(2) @e, align 4
+  %cmp.i = icmp eq i32 %6, 0
+  br i1 %cmp.i, label %if.then2.i, label %if.else6.i
+
+if.then2.i:                                       ; preds = %if.else.i
+  %7 = tail call noundef nonnull align 2 dereferenceable(2) ptr 
@llvm.dx.resource.getpointer.p0.tdx.RawBuffer_f16_1_0t(target("dx.RawBuffer", 
half, 1, 0) %1, i32 0)
+  br label %_Z6Mainv.exit
+
+if.else6.i:                                       ; preds = %if.else.i
+  %8 = load i32, ptr addrspace(2) @e, align 4
+  %9 = tail call noundef nonnull align 2 dereferenceable(2) ptr 
@llvm.dx.resource.getpointer.p0.tdx.RawBuffer_f16_1_0t(target("dx.RawBuffer", 
half, 1, 0) %0, i32 %8)
+  br label %_Z6Mainv.exit
+
+_Z6Mainv.exit:                                  ; preds = %if.then.i, 
%if.then2.i, %if.else6.i
+  %.sink2 = phi i32 [ %5, %if.then.i ], [ 0, %if.then2.i ], [ %6, %if.else6.i ]
+  %.sink.in = phi ptr [ %4, %if.then.i ], [ %7, %if.then2.i ], [ %9, 
%if.else6.i ]
+  %10 = tail call target("dx.RawBuffer", half, 1, 0) 
@llvm.dx.resource.handlefromimplicitbinding.tdx.RawBuffer_f16_1_0t(i32 2, i32 
0, i32 1, i32 0, i1 false, ptr nonnull @.str)
+  %.sink = load half, ptr %.sink.in, align 2
+  %11 = tail call noundef nonnull align 2 dereferenceable(2) ptr 
@llvm.dx.resource.getpointer.p0.tdx.RawBuffer_f16_1_0t(target("dx.RawBuffer", 
half, 1, 0) %10, i32 %.sink2)
+  store half %.sink, ptr %11, align 2
+  ret void
+}

>From 4853d0ec2e911190011abd0c54871c00f2173d57 Mon Sep 17 00:00:00 2001
From: Farzon Lotfi <farzonlo...@microsoft.com>
Date: Thu, 21 Aug 2025 12:06:10 -0400
Subject: [PATCH 03/14] create new NoReplacement property

---
 llvm/include/llvm/IR/DerivedTypes.h | 2 ++
 llvm/lib/IR/Type.cpp                | 3 ++-
 llvm/lib/Transforms/Utils/Local.cpp | 2 +-
 3 files changed, 5 insertions(+), 2 deletions(-)

diff --git a/llvm/include/llvm/IR/DerivedTypes.h 
b/llvm/include/llvm/IR/DerivedTypes.h
index fa62bc09b61a3..7810be22d1e99 100644
--- a/llvm/include/llvm/IR/DerivedTypes.h
+++ b/llvm/include/llvm/IR/DerivedTypes.h
@@ -847,6 +847,8 @@ class TargetExtType : public Type {
     CanBeLocal = 1U << 2,
     // This type may be used as an element in a vector.
     CanBeVectorElement = 1U << 3,
+    // This type can not be replaced in an optimization pass.
+    NoReplacement = 1U << 4,
   };
 
   /// Returns true if the target extension type contains the given property.
diff --git a/llvm/lib/IR/Type.cpp b/llvm/lib/IR/Type.cpp
index 9c34662340352..7513debc2ed3a 100644
--- a/llvm/lib/IR/Type.cpp
+++ b/llvm/lib/IR/Type.cpp
@@ -1036,7 +1036,8 @@ static TargetTypeInfo getTargetTypeInfo(const 
TargetExtType *Ty) {
   // DirectX resources
   if (Name.starts_with("dx."))
     return TargetTypeInfo(PointerType::get(C, 0), TargetExtType::CanBeGlobal,
-                          TargetExtType::CanBeLocal);
+                          TargetExtType::CanBeLocal,
+                          TargetExtType::NoReplacement);
 
   // Opaque types in the AMDGPU name space.
   if (Name == "amdgcn.named.barrier") {
diff --git a/llvm/lib/Transforms/Utils/Local.cpp 
b/llvm/lib/Transforms/Utils/Local.cpp
index 1faf6f0ae5993..b5917058c6559 100644
--- a/llvm/lib/Transforms/Utils/Local.cpp
+++ b/llvm/lib/Transforms/Utils/Local.cpp
@@ -3853,7 +3853,7 @@ bool llvm::canReplaceOperandWithVariable(const 
Instruction *I, unsigned OpIdx) {
     return false;
 
   if (auto *TT = dyn_cast<TargetExtType>(Op->getType());
-      TT && TT->getName() == "dx.RawBuffer")
+      TT && TT->hasProperty(TargetExtType::Property::NoReplacement))
     return false;
 
   // Early exit.

>From 90847c2ebb67ef3b28428bf726bdfe01aa3212c8 Mon Sep 17 00:00:00 2001
From: Farzon Lotfi <farzonlo...@microsoft.com>
Date: Tue, 26 Aug 2025 17:07:14 -0400
Subject: [PATCH 04/14] address PR comments

---
 .../lib/Target/DirectX/DXILResourceAccess.cpp | 25 ++++++++++---------
 llvm/test/CodeGen/DirectX/issue-152348.ll     | 23 +++++++++++++++++
 2 files changed, 36 insertions(+), 12 deletions(-)

diff --git a/llvm/lib/Target/DirectX/DXILResourceAccess.cpp 
b/llvm/lib/Target/DirectX/DXILResourceAccess.cpp
index e09e71b679031..cbd2514716c0f 100644
--- a/llvm/lib/Target/DirectX/DXILResourceAccess.cpp
+++ b/llvm/lib/Target/DirectX/DXILResourceAccess.cpp
@@ -273,22 +273,23 @@ static void phiNodeRemapHelper(PHINode *Phi, BasicBlock 
*BB,
 static void phiNodeReplacement(IntrinsicInst *II) {
   SmallVector<Instruction *> DeadInsts;
   for (User *U : II->users()) {
-    if (auto *Phi = dyn_cast<PHINode>(U)) {
+    auto *Phi = dyn_cast<PHINode>(U);
+    if (!Phi)
+      continue;
 
-      IRBuilder<> Builder(Phi);
-      SmallVector<Instruction *> UsesInBlock;
-      collectBlockUseDef(Phi, UsesInBlock);
+    IRBuilder<> Builder(Phi);
+    SmallVector<Instruction *> UsesInBlock;
+    collectBlockUseDef(Phi, UsesInBlock);
 
-      for (uint I = 0; I < Phi->getNumIncomingValues(); I++) {
-        auto *CurrIncomingBB = Phi->getIncomingBlock(I);
-        phiNodeRemapHelper(Phi, CurrIncomingBB, Builder, UsesInBlock);
-      }
+    for (uint I = 0; I < Phi->getNumIncomingValues(); I++) {
+      auto *CurrIncomingBB = Phi->getIncomingBlock(I);
+      phiNodeRemapHelper(Phi, CurrIncomingBB, Builder, UsesInBlock);
+    }
 
-      DeadInsts.push_back(Phi);
+    DeadInsts.push_back(Phi);
 
-      for (Instruction *I : UsesInBlock) {
-        DeadInsts.push_back(I);
-      }
+    for (Instruction *I : UsesInBlock) {
+      DeadInsts.push_back(I);
     }
   }
 
diff --git a/llvm/test/CodeGen/DirectX/issue-152348.ll 
b/llvm/test/CodeGen/DirectX/issue-152348.ll
index 693f01457bdc6..8bbe131563221 100644
--- a/llvm/test/CodeGen/DirectX/issue-152348.ll
+++ b/llvm/test/CodeGen/DirectX/issue-152348.ll
@@ -1,6 +1,29 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py 
UTC_ARGS: --version 5
 ; RUN: opt -S -dxil-resource-type -dxil-resource-access 
-mtriple=dxil-pc-shadermodel6.3-library %s | FileCheck %s
 
+; NOTE: The two LLVM IR functions below are simplified versions of this HLSL
+;      RWStructuredBuffer<float16_t> a;
+;      RWStructuredBuffer<float16_t> b;
+;      RWStructuredBuffer<float16_t> c;
+;      cbuffer d {
+;        uint e;
+;        uint f;
+;        uint g;
+;        uint h;
+;      }
+;      [numthreads(6, 8, 1)] void CSMain() {
+;        if (h) {
+;          float16_t i = b[f];
+;          c[g] = i;
+;        } else if(h == g) {
+;          float16_t i = b[g];
+;           c[h] = i;
+;        } else {
+;          float16_t i = a[e];
+;          c[g] = i;
+;        }
+;      }
+
 %__cblayout_d = type <{ i32, i32, i32, i32 }>
 
 @.str = internal unnamed_addr constant [2 x i8] c"a\00", align 1

>From 2ead86b7765ab43ec081dac6fbb6d3503c16ea3f Mon Sep 17 00:00:00 2001
From: Farzon Lotfi <farzonlo...@microsoft.com>
Date: Wed, 27 Aug 2025 15:31:23 -0400
Subject: [PATCH 05/14] address partial pr comments

---
 .../lib/Target/DirectX/DXILResourceAccess.cpp |   2 +-
 llvm/test/CodeGen/DirectX/issue-152348.ll     | 146 +++++++++---------
 llvm/unittests/Transforms/Utils/LocalTest.cpp |   8 +
 3 files changed, 78 insertions(+), 78 deletions(-)

diff --git a/llvm/lib/Target/DirectX/DXILResourceAccess.cpp 
b/llvm/lib/Target/DirectX/DXILResourceAccess.cpp
index cbd2514716c0f..c569ab8adfcf0 100644
--- a/llvm/lib/Target/DirectX/DXILResourceAccess.cpp
+++ b/llvm/lib/Target/DirectX/DXILResourceAccess.cpp
@@ -281,7 +281,7 @@ static void phiNodeReplacement(IntrinsicInst *II) {
     SmallVector<Instruction *> UsesInBlock;
     collectBlockUseDef(Phi, UsesInBlock);
 
-    for (uint I = 0; I < Phi->getNumIncomingValues(); I++) {
+    for (unsigned I = 0, E = Phi->getNumIncomingValues(); I < E; I++) {
       auto *CurrIncomingBB = Phi->getIncomingBlock(I);
       phiNodeRemapHelper(Phi, CurrIncomingBB, Builder, UsesInBlock);
     }
diff --git a/llvm/test/CodeGen/DirectX/issue-152348.ll 
b/llvm/test/CodeGen/DirectX/issue-152348.ll
index 8bbe131563221..66aeafb7785e3 100644
--- a/llvm/test/CodeGen/DirectX/issue-152348.ll
+++ b/llvm/test/CodeGen/DirectX/issue-152348.ll
@@ -34,133 +34,125 @@
 define void @CSMain() local_unnamed_addr {
 ; CHECK-LABEL: define void @CSMain() local_unnamed_addr {
 ; CHECK-NEXT:  [[ENTRY:.*:]]
-; CHECK-NEXT:    [[D_CB_H_I_I:%.*]] = tail call target("dx.CBuffer", 
target("dx.Layout", [[__CBLAYOUT_D:%.*]], 16, 0, 4, 8, 12)) 
@llvm.dx.resource.handlefromimplicitbinding.tdx.CBuffer_tdx.Layout_s___cblayout_ds_16_0_4_8_12tt(i32
 3, i32 0, i32 1, i32 0, i1 false, ptr nonnull @d.str)
-; CHECK-NEXT:    store target("dx.CBuffer", target("dx.Layout", 
[[__CBLAYOUT_D]], 16, 0, 4, 8, 12)) [[D_CB_H_I_I]], ptr @d.cb, align 4
-; CHECK-NEXT:    [[TMP0:%.*]] = load i32, ptr addrspace(2) @e, align 4
-; CHECK-NEXT:    [[TOBOOL_NOT_I:%.*]] = icmp eq i32 [[TMP0]], 0
-; CHECK-NEXT:    [[TMP1:%.*]] = load i32, ptr addrspace(2) @e, align 4
+; CHECK-NEXT:    [[CALLRAWBUFFERBINDING:%.*]] = tail call target("dx.CBuffer", 
target("dx.Layout", [[__CBLAYOUT_D:%.*]], 16, 0, 4, 8, 12)) 
@llvm.dx.resource.handlefromimplicitbinding.tdx.CBuffer_tdx.Layout_s___cblayout_ds_16_0_4_8_12tt(i32
 3, i32 0, i32 1, i32 0, i1 false, ptr nonnull @d.str)
+; CHECK-NEXT:    store target("dx.CBuffer", target("dx.Layout", 
[[__CBLAYOUT_D]], 16, 0, 4, 8, 12)) [[CALLRAWBUFFERBINDING]], ptr @d.cb, align 4
+; CHECK-NEXT:    [[LOADE:%.*]] = load i32, ptr addrspace(2) @e, align 4
+; CHECK-NEXT:    [[TOBOOL_NOT_I:%.*]] = icmp eq i32 [[LOADE]], 0
 ; CHECK-NEXT:    br i1 [[TOBOOL_NOT_I]], label %[[IF_ELSE_I:.*]], label 
%[[IF_THEN_I:.*]]
 ; CHECK:       [[IF_THEN_I]]:
-; CHECK-NEXT:    [[TMP2:%.*]] = tail call target("dx.RawBuffer", half, 1, 0) 
@llvm.dx.resource.handlefromimplicitbinding.tdx.RawBuffer_f16_1_0t(i32 1, i32 
0, i32 1, i32 0, i1 false, ptr nonnull @.str)
-; CHECK-NEXT:    [[TMP3:%.*]] = load i32, ptr addrspace(2) @e, align 4
-; CHECK-NEXT:    [[TMP4:%.*]] = tail call target("dx.RawBuffer", half, 1, 0) 
@llvm.dx.resource.handlefromimplicitbinding.tdx.RawBuffer_f16_1_0t(i32 2, i32 
0, i32 1, i32 0, i1 false, ptr nonnull @.str)
-; CHECK-NEXT:    [[TMP5:%.*]] = call { half, i1 } 
@llvm.dx.resource.load.rawbuffer.f16.tdx.RawBuffer_f16_1_0t(target("dx.RawBuffer",
 half, 1, 0) [[TMP2]], i32 [[TMP3]], i32 0)
-; CHECK-NEXT:    [[TMP6:%.*]] = extractvalue { half, i1 } [[TMP5]], 0
-; CHECK-NEXT:    call void 
@llvm.dx.resource.store.rawbuffer.tdx.RawBuffer_f16_1_0t.f16(target("dx.RawBuffer",
 half, 1, 0) [[TMP4]], i32 [[TMP1]], i32 0, half [[TMP6]])
+; CHECK-NEXT:    [[IFSTMTCALLRAWBUFFERBINDING:%.*]] = tail call 
target("dx.RawBuffer", half, 1, 0) 
@llvm.dx.resource.handlefromimplicitbinding.tdx.RawBuffer_f16_1_0t(i32 1, i32 
0, i32 1, i32 0, i1 false, ptr nonnull @.str)
+; CHECK-NEXT:    [[TMP0:%.*]] = tail call target("dx.RawBuffer", half, 1, 0) 
@llvm.dx.resource.handlefromimplicitbinding.tdx.RawBuffer_f16_1_0t(i32 2, i32 
0, i32 1, i32 0, i1 false, ptr nonnull @.str)
+; CHECK-NEXT:    [[TMP1:%.*]] = call { half, i1 } 
@llvm.dx.resource.load.rawbuffer.f16.tdx.RawBuffer_f16_1_0t(target("dx.RawBuffer",
 half, 1, 0) [[IFSTMTCALLRAWBUFFERBINDING]], i32 [[LOADE]], i32 0)
+; CHECK-NEXT:    [[TMP2:%.*]] = extractvalue { half, i1 } [[TMP1]], 0
+; CHECK-NEXT:    call void 
@llvm.dx.resource.store.rawbuffer.tdx.RawBuffer_f16_1_0t.f16(target("dx.RawBuffer",
 half, 1, 0) [[TMP0]], i32 [[LOADE]], i32 0, half [[TMP2]])
 ; CHECK-NEXT:    br label %[[_Z6CSMAINV_EXIT:.*]]
 ; CHECK:       [[IF_ELSE_I]]:
-; CHECK-NEXT:    [[TMP7:%.*]] = tail call target("dx.RawBuffer", half, 1, 0) 
@llvm.dx.resource.handlefromimplicitbinding.tdx.RawBuffer_f16_1_0t(i32 0, i32 
0, i32 1, i32 0, i1 false, ptr nonnull @.str)
-; CHECK-NEXT:    [[TMP8:%.*]] = load i32, ptr addrspace(2) @e, align 4
-; CHECK-NEXT:    [[TMP9:%.*]] = tail call target("dx.RawBuffer", half, 1, 0) 
@llvm.dx.resource.handlefromimplicitbinding.tdx.RawBuffer_f16_1_0t(i32 2, i32 
0, i32 1, i32 0, i1 false, ptr nonnull @.str)
-; CHECK-NEXT:    [[TMP10:%.*]] = call { half, i1 } 
@llvm.dx.resource.load.rawbuffer.f16.tdx.RawBuffer_f16_1_0t(target("dx.RawBuffer",
 half, 1, 0) [[TMP7]], i32 [[TMP8]], i32 0)
-; CHECK-NEXT:    [[TMP11:%.*]] = extractvalue { half, i1 } [[TMP10]], 0
-; CHECK-NEXT:    call void 
@llvm.dx.resource.store.rawbuffer.tdx.RawBuffer_f16_1_0t.f16(target("dx.RawBuffer",
 half, 1, 0) [[TMP9]], i32 [[TMP1]], i32 0, half [[TMP11]])
+; CHECK-NEXT:    [[CALL2NDRAWBUFFERBINDING:%.*]] = tail call 
target("dx.RawBuffer", half, 1, 0) 
@llvm.dx.resource.handlefromimplicitbinding.tdx.RawBuffer_f16_1_0t(i32 0, i32 
0, i32 1, i32 0, i1 false, ptr nonnull @.str)
+; CHECK-NEXT:    [[TMP3:%.*]] = tail call target("dx.RawBuffer", half, 1, 0) 
@llvm.dx.resource.handlefromimplicitbinding.tdx.RawBuffer_f16_1_0t(i32 2, i32 
0, i32 1, i32 0, i1 false, ptr nonnull @.str)
+; CHECK-NEXT:    [[TMP4:%.*]] = call { half, i1 } 
@llvm.dx.resource.load.rawbuffer.f16.tdx.RawBuffer_f16_1_0t(target("dx.RawBuffer",
 half, 1, 0) [[CALL2NDRAWBUFFERBINDING]], i32 [[LOADE]], i32 0)
+; CHECK-NEXT:    [[TMP5:%.*]] = extractvalue { half, i1 } [[TMP4]], 0
+; CHECK-NEXT:    call void 
@llvm.dx.resource.store.rawbuffer.tdx.RawBuffer_f16_1_0t.f16(target("dx.RawBuffer",
 half, 1, 0) [[TMP3]], i32 [[LOADE]], i32 0, half [[TMP5]])
 ; CHECK-NEXT:    br label %[[_Z6CSMAINV_EXIT]]
 ; CHECK:       [[_Z6CSMAINV_EXIT]]:
 ; CHECK-NEXT:    ret void
 ;
 entry:
-  %d.cb_h.i.i = tail call target("dx.CBuffer", target("dx.Layout", 
%__cblayout_d, 16, 0, 4, 8, 12)) 
@llvm.dx.resource.handlefromimplicitbinding.tdx.CBuffer_tdx.Layout_s___cblayout_ds_16_0_4_8_12tt(i32
 3, i32 0, i32 1, i32 0, i1 false, ptr nonnull @d.str)
-  store target("dx.CBuffer", target("dx.Layout", %__cblayout_d, 16, 0, 4, 8, 
12)) %d.cb_h.i.i, ptr @d.cb, align 4
-  %0 = load i32, ptr addrspace(2) @e, align 4
-  %tobool.not.i = icmp eq i32 %0, 0
-  %1 = load i32, ptr addrspace(2) @e, align 4
+  %callRawBufferBinding = tail call target("dx.CBuffer", target("dx.Layout", 
%__cblayout_d, 16, 0, 4, 8, 12)) 
@llvm.dx.resource.handlefromimplicitbinding.tdx.CBuffer_tdx.Layout_s___cblayout_ds_16_0_4_8_12tt(i32
 3, i32 0, i32 1, i32 0, i1 false, ptr nonnull @d.str)
+  store target("dx.CBuffer", target("dx.Layout", %__cblayout_d, 16, 0, 4, 8, 
12)) %callRawBufferBinding, ptr @d.cb, align 4
+  %loadE = load i32, ptr addrspace(2) @e, align 4
+  %tobool.not.i = icmp eq i32 %loadE, 0
   br i1 %tobool.not.i, label %if.else.i, label %if.then.i
 
 if.then.i:                                        ; preds = %entry
-  %2 = tail call target("dx.RawBuffer", half, 1, 0) 
@llvm.dx.resource.handlefromimplicitbinding.tdx.RawBuffer_f16_1_0t(i32 1, i32 
0, i32 1, i32 0, i1 false, ptr nonnull @.str)
-  %3 = load i32, ptr addrspace(2) @e, align 4
-  %4 = tail call noundef nonnull align 2 dereferenceable(2) ptr 
@llvm.dx.resource.getpointer.p0.tdx.RawBuffer_f16_1_0t(target("dx.RawBuffer", 
half, 1, 0) %2, i32 %3)
+  %ifStmtcallRawBufferBinding = tail call target("dx.RawBuffer", half, 1, 0) 
@llvm.dx.resource.handlefromimplicitbinding.tdx.RawBuffer_f16_1_0t(i32 1, i32 
0, i32 1, i32 0, i1 false, ptr nonnull @.str)
+  %ifStmtCallResourceGEP = tail call noundef nonnull align 2 
dereferenceable(2) ptr 
@llvm.dx.resource.getpointer.p0.tdx.RawBuffer_f16_1_0t(target("dx.RawBuffer", 
half, 1, 0) %ifStmtcallRawBufferBinding, i32 %loadE)
   br label %_Z6CSMainv.exit
 
 if.else.i:                                        ; preds = %entry
-  %5 = tail call target("dx.RawBuffer", half, 1, 0) 
@llvm.dx.resource.handlefromimplicitbinding.tdx.RawBuffer_f16_1_0t(i32 0, i32 
0, i32 1, i32 0, i1 false, ptr nonnull @.str)
-  %6 = load i32, ptr addrspace(2) @e, align 4
-  %7 = tail call noundef nonnull align 2 dereferenceable(2) ptr 
@llvm.dx.resource.getpointer.p0.tdx.RawBuffer_f16_1_0t(target("dx.RawBuffer", 
half, 1, 0) %5, i32 %6)
+  %call2ndRawBufferBinding = tail call target("dx.RawBuffer", half, 1, 0) 
@llvm.dx.resource.handlefromimplicitbinding.tdx.RawBuffer_f16_1_0t(i32 0, i32 
0, i32 1, i32 0, i1 false, ptr nonnull @.str)
+  %elseStmtCallResourceGEP = tail call noundef nonnull align 2 
dereferenceable(2) ptr 
@llvm.dx.resource.getpointer.p0.tdx.RawBuffer_f16_1_0t(target("dx.RawBuffer", 
half, 1, 0) %call2ndRawBufferBinding, i32 %loadE)
   br label %_Z6CSMainv.exit
 
-_Z6CSMainv.exit:                                  ; preds = %if.then.i, 
%if.else.i
-  %.sink1 = phi ptr [ %4, %if.then.i ], [ %7, %if.else.i ]
-  %8 = tail call target("dx.RawBuffer", half, 1, 0) 
@llvm.dx.resource.handlefromimplicitbinding.tdx.RawBuffer_f16_1_0t(i32 2, i32 
0, i32 1, i32 0, i1 false, ptr nonnull @.str)
-  %9 = tail call noundef nonnull align 2 dereferenceable(2) ptr 
@llvm.dx.resource.getpointer.p0.tdx.RawBuffer_f16_1_0t(target("dx.RawBuffer", 
half, 1, 0) %8, i32 %1)
-  %10 = load half, ptr %.sink1, align 2
-  store half %10, ptr %9, align 2
+_Z6CSMainv.exit:                                  ; preds = %if.else.i, 
%if.then.i
+  %.sink1 = phi ptr [ %ifStmtCallResourceGEP, %if.then.i ], [ 
%elseStmtCallResourceGEP, %if.else.i ]
+  %call3rdRawBufferBinding = tail call target("dx.RawBuffer", half, 1, 0) 
@llvm.dx.resource.handlefromimplicitbinding.tdx.RawBuffer_f16_1_0t(i32 2, i32 
0, i32 1, i32 0, i1 false, ptr nonnull @.str)
+  %sinkCallResourceGEP = tail call noundef nonnull align 2 dereferenceable(2) 
ptr 
@llvm.dx.resource.getpointer.p0.tdx.RawBuffer_f16_1_0t(target("dx.RawBuffer", 
half, 1, 0) %call3rdRawBufferBinding, i32 %loadE)
+  %loadSink = load half, ptr %.sink1, align 2
+  store half %loadSink, ptr %sinkCallResourceGEP, align 2
   ret void
 }
 
 define void @Main() local_unnamed_addr  {
 ; CHECK-LABEL: define void @Main() local_unnamed_addr {
 ; CHECK-NEXT:  [[ENTRY:.*:]]
-; CHECK-NEXT:    [[TMP0:%.*]] = tail call target("dx.RawBuffer", half, 1, 0) 
@llvm.dx.resource.handlefromimplicitbinding.tdx.RawBuffer_f16_1_0t(i32 0, i32 
0, i32 1, i32 0, i1 false, ptr nonnull @.str)
-; CHECK-NEXT:    [[TMP1:%.*]] = tail call target("dx.RawBuffer", half, 1, 0) 
@llvm.dx.resource.handlefromimplicitbinding.tdx.RawBuffer_f16_1_0t(i32 1, i32 
0, i32 1, i32 0, i1 false, ptr nonnull @.str)
-; CHECK-NEXT:    [[D_CB_H_I_I:%.*]] = tail call target("dx.CBuffer", 
target("dx.Layout", [[__CBLAYOUT_D:%.*]], 16, 0, 4, 8, 12)) 
@llvm.dx.resource.handlefromimplicitbinding.tdx.CBuffer_tdx.Layout_s___cblayout_ds_16_0_4_8_12tt(i32
 3, i32 0, i32 1, i32 0, i1 false, ptr nonnull @d.str)
-; CHECK-NEXT:    store target("dx.CBuffer", target("dx.Layout", 
[[__CBLAYOUT_D]], 16, 0, 4, 8, 12)) [[D_CB_H_I_I]], ptr @d.cb, align 4
-; CHECK-NEXT:    [[TMP2:%.*]] = load i32, ptr addrspace(2) @e, align 4
-; CHECK-NEXT:    [[TOBOOL_NOT_I:%.*]] = icmp eq i32 [[TMP2]], 0
+; CHECK-NEXT:    [[CALLRAWBUFFERBINDING1:%.*]] = tail call 
target("dx.RawBuffer", half, 1, 0) 
@llvm.dx.resource.handlefromimplicitbinding.tdx.RawBuffer_f16_1_0t(i32 0, i32 
0, i32 1, i32 0, i1 false, ptr nonnull @.str)
+; CHECK-NEXT:    [[CALLRAWBUFFERBINDING0:%.*]] = tail call 
target("dx.RawBuffer", half, 1, 0) 
@llvm.dx.resource.handlefromimplicitbinding.tdx.RawBuffer_f16_1_0t(i32 1, i32 
0, i32 1, i32 0, i1 false, ptr nonnull @.str)
+; CHECK-NEXT:    [[CALLRAWBUFFERBINDING:%.*]] = tail call target("dx.CBuffer", 
target("dx.Layout", [[__CBLAYOUT_D:%.*]], 16, 0, 4, 8, 12)) 
@llvm.dx.resource.handlefromimplicitbinding.tdx.CBuffer_tdx.Layout_s___cblayout_ds_16_0_4_8_12tt(i32
 3, i32 0, i32 1, i32 0, i1 false, ptr nonnull @d.str)
+; CHECK-NEXT:    store target("dx.CBuffer", target("dx.Layout", 
[[__CBLAYOUT_D]], 16, 0, 4, 8, 12)) [[CALLRAWBUFFERBINDING]], ptr @d.cb, align 4
+; CHECK-NEXT:    [[LOADE:%.*]] = load i32, ptr addrspace(2) @e, align 4
+; CHECK-NEXT:    [[TOBOOL_NOT_I:%.*]] = icmp eq i32 [[LOADE]], 0
 ; CHECK-NEXT:    br i1 [[TOBOOL_NOT_I]], label %[[IF_ELSE_I:.*]], label 
%[[IF_THEN_I:.*]]
 ; CHECK:       [[IF_THEN_I]]:
-; CHECK-NEXT:    [[TMP3:%.*]] = load i32, ptr addrspace(2) @e, align 4
-; CHECK-NEXT:    [[TMP4:%.*]] = load i32, ptr addrspace(2) @e, align 4
-; CHECK-NEXT:    [[TMP5:%.*]] = tail call target("dx.RawBuffer", half, 1, 0) 
@llvm.dx.resource.handlefromimplicitbinding.tdx.RawBuffer_f16_1_0t(i32 2, i32 
0, i32 1, i32 0, i1 false, ptr nonnull @.str)
-; CHECK-NEXT:    [[TMP6:%.*]] = call { half, i1 } 
@llvm.dx.resource.load.rawbuffer.f16.tdx.RawBuffer_f16_1_0t(target("dx.RawBuffer",
 half, 1, 0) [[TMP1]], i32 [[TMP3]], i32 0)
-; CHECK-NEXT:    [[TMP7:%.*]] = extractvalue { half, i1 } [[TMP6]], 0
-; CHECK-NEXT:    call void 
@llvm.dx.resource.store.rawbuffer.tdx.RawBuffer_f16_1_0t.f16(target("dx.RawBuffer",
 half, 1, 0) [[TMP5]], i32 [[TMP4]], i32 0, half [[TMP7]])
+; CHECK-NEXT:    [[IFSTMTLOADE:%.*]] = load i32, ptr addrspace(2) @e, align 4
+; CHECK-NEXT:    [[TMP0:%.*]] = tail call target("dx.RawBuffer", half, 1, 0) 
@llvm.dx.resource.handlefromimplicitbinding.tdx.RawBuffer_f16_1_0t(i32 2, i32 
0, i32 1, i32 0, i1 false, ptr nonnull @.str)
+; CHECK-NEXT:    [[TMP1:%.*]] = call { half, i1 } 
@llvm.dx.resource.load.rawbuffer.f16.tdx.RawBuffer_f16_1_0t(target("dx.RawBuffer",
 half, 1, 0) [[CALLRAWBUFFERBINDING0]], i32 [[LOADE]], i32 0)
+; CHECK-NEXT:    [[TMP2:%.*]] = extractvalue { half, i1 } [[TMP1]], 0
+; CHECK-NEXT:    call void 
@llvm.dx.resource.store.rawbuffer.tdx.RawBuffer_f16_1_0t.f16(target("dx.RawBuffer",
 half, 1, 0) [[TMP0]], i32 [[IFSTMTLOADE]], i32 0, half [[TMP2]])
 ; CHECK-NEXT:    br label %[[_Z6MAINV_EXIT:.*]]
 ; CHECK:       [[IF_ELSE_I]]:
-; CHECK-NEXT:    [[TMP8:%.*]] = load i32, ptr addrspace(2) @e, align 4
-; CHECK-NEXT:    [[CMP_I:%.*]] = icmp eq i32 [[TMP8]], 0
+; CHECK-NEXT:    [[ELSESTMTLOADE:%.*]] = load i32, ptr addrspace(2) @e, align 4
+; CHECK-NEXT:    [[CMP_I:%.*]] = icmp eq i32 [[ELSESTMTLOADE]], 0
 ; CHECK-NEXT:    br i1 [[CMP_I]], label %[[IF_THEN2_I:.*]], label 
%[[IF_ELSE6_I:.*]]
 ; CHECK:       [[IF_THEN2_I]]:
-; CHECK-NEXT:    [[TMP9:%.*]] = tail call target("dx.RawBuffer", half, 1, 0) 
@llvm.dx.resource.handlefromimplicitbinding.tdx.RawBuffer_f16_1_0t(i32 2, i32 
0, i32 1, i32 0, i1 false, ptr nonnull @.str)
-; CHECK-NEXT:    [[TMP10:%.*]] = call { half, i1 } 
@llvm.dx.resource.load.rawbuffer.f16.tdx.RawBuffer_f16_1_0t(target("dx.RawBuffer",
 half, 1, 0) [[TMP1]], i32 0, i32 0)
-; CHECK-NEXT:    [[TMP11:%.*]] = extractvalue { half, i1 } [[TMP10]], 0
-; CHECK-NEXT:    call void 
@llvm.dx.resource.store.rawbuffer.tdx.RawBuffer_f16_1_0t.f16(target("dx.RawBuffer",
 half, 1, 0) [[TMP9]], i32 0, i32 0, half [[TMP11]])
+; CHECK-NEXT:    [[TMP3:%.*]] = tail call target("dx.RawBuffer", half, 1, 0) 
@llvm.dx.resource.handlefromimplicitbinding.tdx.RawBuffer_f16_1_0t(i32 2, i32 
0, i32 1, i32 0, i1 false, ptr nonnull @.str)
+; CHECK-NEXT:    [[TMP4:%.*]] = call { half, i1 } 
@llvm.dx.resource.load.rawbuffer.f16.tdx.RawBuffer_f16_1_0t(target("dx.RawBuffer",
 half, 1, 0) [[CALLRAWBUFFERBINDING0]], i32 0, i32 0)
+; CHECK-NEXT:    [[TMP5:%.*]] = extractvalue { half, i1 } [[TMP4]], 0
+; CHECK-NEXT:    call void 
@llvm.dx.resource.store.rawbuffer.tdx.RawBuffer_f16_1_0t.f16(target("dx.RawBuffer",
 half, 1, 0) [[TMP3]], i32 0, i32 0, half [[TMP5]])
 ; CHECK-NEXT:    br label %[[_Z6MAINV_EXIT]]
 ; CHECK:       [[IF_ELSE6_I]]:
-; CHECK-NEXT:    [[TMP12:%.*]] = load i32, ptr addrspace(2) @e, align 4
-; CHECK-NEXT:    [[TMP13:%.*]] = tail call target("dx.RawBuffer", half, 1, 0) 
@llvm.dx.resource.handlefromimplicitbinding.tdx.RawBuffer_f16_1_0t(i32 2, i32 
0, i32 1, i32 0, i1 false, ptr nonnull @.str)
-; CHECK-NEXT:    [[TMP14:%.*]] = call { half, i1 } 
@llvm.dx.resource.load.rawbuffer.f16.tdx.RawBuffer_f16_1_0t(target("dx.RawBuffer",
 half, 1, 0) [[TMP0]], i32 [[TMP12]], i32 0)
-; CHECK-NEXT:    [[TMP15:%.*]] = extractvalue { half, i1 } [[TMP14]], 0
-; CHECK-NEXT:    call void 
@llvm.dx.resource.store.rawbuffer.tdx.RawBuffer_f16_1_0t.f16(target("dx.RawBuffer",
 half, 1, 0) [[TMP13]], i32 [[TMP8]], i32 0, half [[TMP15]])
+; CHECK-NEXT:    [[ELSESTMTLOADE2:%.*]] = load i32, ptr addrspace(2) @e, align 
4
+; CHECK-NEXT:    [[TMP6:%.*]] = tail call target("dx.RawBuffer", half, 1, 0) 
@llvm.dx.resource.handlefromimplicitbinding.tdx.RawBuffer_f16_1_0t(i32 2, i32 
0, i32 1, i32 0, i1 false, ptr nonnull @.str)
+; CHECK-NEXT:    [[TMP7:%.*]] = call { half, i1 } 
@llvm.dx.resource.load.rawbuffer.f16.tdx.RawBuffer_f16_1_0t(target("dx.RawBuffer",
 half, 1, 0) [[CALLRAWBUFFERBINDING1]], i32 [[ELSESTMTLOADE2]], i32 0)
+; CHECK-NEXT:    [[TMP8:%.*]] = extractvalue { half, i1 } [[TMP7]], 0
+; CHECK-NEXT:    call void 
@llvm.dx.resource.store.rawbuffer.tdx.RawBuffer_f16_1_0t.f16(target("dx.RawBuffer",
 half, 1, 0) [[TMP6]], i32 [[ELSESTMTLOADE]], i32 0, half [[TMP8]])
 ; CHECK-NEXT:    br label %[[_Z6MAINV_EXIT]]
 ; CHECK:       [[_Z6MAINV_EXIT]]:
 ; CHECK-NEXT:    ret void
 ;
 entry:
-  %0 = tail call target("dx.RawBuffer", half, 1, 0) 
@llvm.dx.resource.handlefromimplicitbinding.tdx.RawBuffer_f16_1_0t(i32 0, i32 
0, i32 1, i32 0, i1 false, ptr nonnull @.str)
-  %1 = tail call target("dx.RawBuffer", half, 1, 0) 
@llvm.dx.resource.handlefromimplicitbinding.tdx.RawBuffer_f16_1_0t(i32 1, i32 
0, i32 1, i32 0, i1 false, ptr nonnull @.str)
-  %d.cb_h.i.i = tail call target("dx.CBuffer", target("dx.Layout", 
%__cblayout_d, 16, 0, 4, 8, 12)) 
@llvm.dx.resource.handlefromimplicitbinding.tdx.CBuffer_tdx.Layout_s___cblayout_ds_16_0_4_8_12tt(i32
 3, i32 0, i32 1, i32 0, i1 false, ptr nonnull @d.str)
-  store target("dx.CBuffer", target("dx.Layout", %__cblayout_d, 16, 0, 4, 8, 
12)) %d.cb_h.i.i, ptr @d.cb, align 4
-  %2 = load i32, ptr addrspace(2) @e, align 4
-  %tobool.not.i = icmp eq i32 %2, 0
+  %callRawBufferBinding1 = tail call target("dx.RawBuffer", half, 1, 0) 
@llvm.dx.resource.handlefromimplicitbinding.tdx.RawBuffer_f16_1_0t(i32 0, i32 
0, i32 1, i32 0, i1 false, ptr nonnull @.str)
+  %callRawBufferBinding0 = tail call target("dx.RawBuffer", half, 1, 0) 
@llvm.dx.resource.handlefromimplicitbinding.tdx.RawBuffer_f16_1_0t(i32 1, i32 
0, i32 1, i32 0, i1 false, ptr nonnull @.str)
+  %callRawBufferBinding = tail call target("dx.CBuffer", target("dx.Layout", 
%__cblayout_d, 16, 0, 4, 8, 12)) 
@llvm.dx.resource.handlefromimplicitbinding.tdx.CBuffer_tdx.Layout_s___cblayout_ds_16_0_4_8_12tt(i32
 3, i32 0, i32 1, i32 0, i1 false, ptr nonnull @d.str)
+  store target("dx.CBuffer", target("dx.Layout", %__cblayout_d, 16, 0, 4, 8, 
12)) %callRawBufferBinding, ptr @d.cb, align 4
+  %loadE = load i32, ptr addrspace(2) @e, align 4
+  %tobool.not.i = icmp eq i32 %loadE, 0
   br i1 %tobool.not.i, label %if.else.i, label %if.then.i
 
 if.then.i:                                        ; preds = %entry
-  %3 = load i32, ptr addrspace(2) @e, align 4
-  %4 = tail call noundef nonnull align 2 dereferenceable(2) ptr 
@llvm.dx.resource.getpointer.p0.tdx.RawBuffer_f16_1_0t(target("dx.RawBuffer", 
half, 1, 0) %1, i32 %3)
-  %5 = load i32, ptr addrspace(2) @e, align 4
+  %ifStmtCallResourceGEP = tail call noundef nonnull align 2 
dereferenceable(2) ptr 
@llvm.dx.resource.getpointer.p0.tdx.RawBuffer_f16_1_0t(target("dx.RawBuffer", 
half, 1, 0) %callRawBufferBinding0, i32 %loadE)
+  %ifStmtLoadE = load i32, ptr addrspace(2) @e, align 4
   br label %_Z6Mainv.exit
 
 if.else.i:                                        ; preds = %entry
-  %6 = load i32, ptr addrspace(2) @e, align 4
-  %cmp.i = icmp eq i32 %6, 0
+  %elseStmtLoadE = load i32, ptr addrspace(2) @e, align 4
+  %cmp.i = icmp eq i32 %elseStmtLoadE, 0
   br i1 %cmp.i, label %if.then2.i, label %if.else6.i
 
 if.then2.i:                                       ; preds = %if.else.i
-  %7 = tail call noundef nonnull align 2 dereferenceable(2) ptr 
@llvm.dx.resource.getpointer.p0.tdx.RawBuffer_f16_1_0t(target("dx.RawBuffer", 
half, 1, 0) %1, i32 0)
+  %elseifStmtCallResourceGEP = tail call noundef nonnull align 2 
dereferenceable(2) ptr 
@llvm.dx.resource.getpointer.p0.tdx.RawBuffer_f16_1_0t(target("dx.RawBuffer", 
half, 1, 0) %callRawBufferBinding0, i32 0)
   br label %_Z6Mainv.exit
 
 if.else6.i:                                       ; preds = %if.else.i
-  %8 = load i32, ptr addrspace(2) @e, align 4
-  %9 = tail call noundef nonnull align 2 dereferenceable(2) ptr 
@llvm.dx.resource.getpointer.p0.tdx.RawBuffer_f16_1_0t(target("dx.RawBuffer", 
half, 1, 0) %0, i32 %8)
+  %elseStmtLoadE2 = load i32, ptr addrspace(2) @e, align 4
+  %elseStmtCallResourceGEP = tail call noundef nonnull align 2 
dereferenceable(2) ptr 
@llvm.dx.resource.getpointer.p0.tdx.RawBuffer_f16_1_0t(target("dx.RawBuffer", 
half, 1, 0) %callRawBufferBinding1, i32 %elseStmtLoadE2)
   br label %_Z6Mainv.exit
 
-_Z6Mainv.exit:                                  ; preds = %if.then.i, 
%if.then2.i, %if.else6.i
-  %.sink2 = phi i32 [ %5, %if.then.i ], [ 0, %if.then2.i ], [ %6, %if.else6.i ]
-  %.sink.in = phi ptr [ %4, %if.then.i ], [ %7, %if.then2.i ], [ %9, 
%if.else6.i ]
-  %10 = tail call target("dx.RawBuffer", half, 1, 0) 
@llvm.dx.resource.handlefromimplicitbinding.tdx.RawBuffer_f16_1_0t(i32 2, i32 
0, i32 1, i32 0, i1 false, ptr nonnull @.str)
+_Z6Mainv.exit:                                    ; preds = %if.else6.i, 
%if.then2.i, %if.then.i
+  %.sink2 = phi i32 [ %ifStmtLoadE, %if.then.i ], [ 0, %if.then2.i ], [ 
%elseStmtLoadE, %if.else6.i ]
+  %.sink.in = phi ptr [ %ifStmtCallResourceGEP, %if.then.i ], [ 
%elseifStmtCallResourceGEP, %if.then2.i ], [ %elseStmtCallResourceGEP, 
%if.else6.i ]
+  %callRawBufferBindingSink = tail call target("dx.RawBuffer", half, 1, 0) 
@llvm.dx.resource.handlefromimplicitbinding.tdx.RawBuffer_f16_1_0t(i32 2, i32 
0, i32 1, i32 0, i1 false, ptr nonnull @.str)
   %.sink = load half, ptr %.sink.in, align 2
-  %11 = tail call noundef nonnull align 2 dereferenceable(2) ptr 
@llvm.dx.resource.getpointer.p0.tdx.RawBuffer_f16_1_0t(target("dx.RawBuffer", 
half, 1, 0) %10, i32 %.sink2)
-  store half %.sink, ptr %11, align 2
+  %i11 = tail call noundef nonnull align 2 dereferenceable(2) ptr 
@llvm.dx.resource.getpointer.p0.tdx.RawBuffer_f16_1_0t(target("dx.RawBuffer", 
half, 1, 0) %callRawBufferBindingSink, i32 %.sink2)
+  store half %.sink, ptr %i11, align 2
   ret void
 }
diff --git a/llvm/unittests/Transforms/Utils/LocalTest.cpp 
b/llvm/unittests/Transforms/Utils/LocalTest.cpp
index 0c70feb64e7e4..194684d86558f 100644
--- a/llvm/unittests/Transforms/Utils/LocalTest.cpp
+++ b/llvm/unittests/Transforms/Utils/LocalTest.cpp
@@ -1057,6 +1057,14 @@ TEST(Local, SimplifyCFGWithNullAC) {
                           RequireAndPreserveDomTree ? &DTU : nullptr, 
Options));
 }
 
+TEST(LocalTest, TargetTypeInfoHasNoReplacementProperty) {
+  LLVMContext Ctx;
+  SmallVector<unsigned, 3> Ints = {};
+  auto *TT = llvm::TargetExtType::get(Ctx, "dx.RawBuffer", {}, Ints);
+  
+  EXPECT_TRUE(TT->hasProperty(TargetExtType::Property::NoReplacement));
+}
+
 TEST(Local, CanReplaceOperandWithVariable) {
   LLVMContext Ctx;
   Module M("test_module", Ctx);

>From e6af51390e1929e5ea8f4258442935d4ad705ad6 Mon Sep 17 00:00:00 2001
From: Farzon Lotfi <farzonlo...@microsoft.com>
Date: Wed, 27 Aug 2025 15:55:00 -0400
Subject: [PATCH 06/14] address more pr feedback

---
 llvm/include/llvm/IR/DerivedTypes.h           | 6 +++---
 llvm/lib/IR/Type.cpp                          | 2 +-
 llvm/lib/Transforms/Utils/Local.cpp           | 2 +-
 llvm/unittests/Transforms/Utils/LocalTest.cpp | 4 ++--
 4 files changed, 7 insertions(+), 7 deletions(-)

diff --git a/llvm/include/llvm/IR/DerivedTypes.h 
b/llvm/include/llvm/IR/DerivedTypes.h
index 7810be22d1e99..5db79b82ac61d 100644
--- a/llvm/include/llvm/IR/DerivedTypes.h
+++ b/llvm/include/llvm/IR/DerivedTypes.h
@@ -845,10 +845,10 @@ class TargetExtType : public Type {
     /// This type may be allocated on the stack, either as the allocated type
     /// of an alloca instruction or as a byval function parameter.
     CanBeLocal = 1U << 2,
-    // This type may be used as an element in a vector.
+    /// This type may be used as an element in a vector.
     CanBeVectorElement = 1U << 3,
-    // This type can not be replaced in an optimization pass.
-    NoReplacement = 1U << 4,
+    /// All uses of this type must not attempt to introspect or obscure it.
+    IsTokenLike = 1U << 4,
   };
 
   /// Returns true if the target extension type contains the given property.
diff --git a/llvm/lib/IR/Type.cpp b/llvm/lib/IR/Type.cpp
index 7513debc2ed3a..d3aec2610e068 100644
--- a/llvm/lib/IR/Type.cpp
+++ b/llvm/lib/IR/Type.cpp
@@ -1037,7 +1037,7 @@ static TargetTypeInfo getTargetTypeInfo(const 
TargetExtType *Ty) {
   if (Name.starts_with("dx."))
     return TargetTypeInfo(PointerType::get(C, 0), TargetExtType::CanBeGlobal,
                           TargetExtType::CanBeLocal,
-                          TargetExtType::NoReplacement);
+                          TargetExtType::IsTokenLike);
 
   // Opaque types in the AMDGPU name space.
   if (Name == "amdgcn.named.barrier") {
diff --git a/llvm/lib/Transforms/Utils/Local.cpp 
b/llvm/lib/Transforms/Utils/Local.cpp
index b5917058c6559..81e4551d78806 100644
--- a/llvm/lib/Transforms/Utils/Local.cpp
+++ b/llvm/lib/Transforms/Utils/Local.cpp
@@ -3853,7 +3853,7 @@ bool llvm::canReplaceOperandWithVariable(const 
Instruction *I, unsigned OpIdx) {
     return false;
 
   if (auto *TT = dyn_cast<TargetExtType>(Op->getType());
-      TT && TT->hasProperty(TargetExtType::Property::NoReplacement))
+      TT && TT->hasProperty(TargetExtType::Property::IsTokenLike))
     return false;
 
   // Early exit.
diff --git a/llvm/unittests/Transforms/Utils/LocalTest.cpp 
b/llvm/unittests/Transforms/Utils/LocalTest.cpp
index 194684d86558f..4b53cc3d6e516 100644
--- a/llvm/unittests/Transforms/Utils/LocalTest.cpp
+++ b/llvm/unittests/Transforms/Utils/LocalTest.cpp
@@ -1061,8 +1061,8 @@ TEST(LocalTest, TargetTypeInfoHasNoReplacementProperty) {
   LLVMContext Ctx;
   SmallVector<unsigned, 3> Ints = {};
   auto *TT = llvm::TargetExtType::get(Ctx, "dx.RawBuffer", {}, Ints);
-  
-  EXPECT_TRUE(TT->hasProperty(TargetExtType::Property::NoReplacement));
+
+  EXPECT_TRUE(TT->hasProperty(TargetExtType::Property::IsTokenLike));
 }
 
 TEST(Local, CanReplaceOperandWithVariable) {

>From 533dc4f09ebb0309532f01edcb3e443be4f84a3e Mon Sep 17 00:00:00 2001
From: Farzon Lotfi <farzonlo...@microsoft.com>
Date: Wed, 27 Aug 2025 16:28:21 -0400
Subject: [PATCH 07/14] make an is isTokenLikeTy() helper

---
 llvm/include/llvm/IR/Type.h         | 9 +++++++++
 llvm/lib/Transforms/Utils/Local.cpp | 3 +--
 2 files changed, 10 insertions(+), 2 deletions(-)

diff --git a/llvm/include/llvm/IR/Type.h b/llvm/include/llvm/IR/Type.h
index 74dd490729741..8fc7a8198e80c 100644
--- a/llvm/include/llvm/IR/Type.h
+++ b/llvm/include/llvm/IR/Type.h
@@ -15,6 +15,7 @@
 #define LLVM_IR_TYPE_H
 
 #include "llvm/ADT/ArrayRef.h"
+#include "llvm/IR/DerivedTypes.h"
 #include "llvm/Support/CBindingWrapping.h"
 #include "llvm/Support/Casting.h"
 #include "llvm/Support/Compiler.h"
@@ -233,6 +234,14 @@ class Type {
   /// Return true if this is 'token'.
   bool isTokenTy() const { return getTypeID() == TokenTyID; }
 
+  // Returns true if this is 'token' or 'token-like'.
+  bool isTokenLikeTy() const {
+    if (isTokenTy())
+      return true;
+    if (auto *TT = dyn_cast<TargetExtType>(this))
+      return TT->hasProperty(TargetExtType::Property::IsTokenLike);
+  }
+
   /// True if this is an instance of IntegerType.
   bool isIntegerTy() const { return getTypeID() == IntegerTyID; }
 
diff --git a/llvm/lib/Transforms/Utils/Local.cpp 
b/llvm/lib/Transforms/Utils/Local.cpp
index 81e4551d78806..0eb92470045ea 100644
--- a/llvm/lib/Transforms/Utils/Local.cpp
+++ b/llvm/lib/Transforms/Utils/Local.cpp
@@ -3852,8 +3852,7 @@ bool llvm::canReplaceOperandWithVariable(const 
Instruction *I, unsigned OpIdx) {
   if (I->isLifetimeStartOrEnd())
     return false;
 
-  if (auto *TT = dyn_cast<TargetExtType>(Op->getType());
-      TT && TT->hasProperty(TargetExtType::Property::IsTokenLike))
+  if (Op->getType()->isTokenLikeTy())
     return false;
 
   // Early exit.

>From 74a568f7d03f698b9eb45e72d67bb3b24518a6d0 Mon Sep 17 00:00:00 2001
From: Farzon Lotfi <farzonlo...@microsoft.com>
Date: Thu, 28 Aug 2025 12:23:02 -0400
Subject: [PATCH 08/14] fix isTokenLikeTy implementation

---
 llvm/include/llvm/IR/Type.h | 11 ++---------
 llvm/lib/IR/Type.cpp        |  8 ++++++++
 2 files changed, 10 insertions(+), 9 deletions(-)

diff --git a/llvm/include/llvm/IR/Type.h b/llvm/include/llvm/IR/Type.h
index 8fc7a8198e80c..0c8f960966cd5 100644
--- a/llvm/include/llvm/IR/Type.h
+++ b/llvm/include/llvm/IR/Type.h
@@ -15,7 +15,6 @@
 #define LLVM_IR_TYPE_H
 
 #include "llvm/ADT/ArrayRef.h"
-#include "llvm/IR/DerivedTypes.h"
 #include "llvm/Support/CBindingWrapping.h"
 #include "llvm/Support/Casting.h"
 #include "llvm/Support/Compiler.h"
@@ -26,7 +25,6 @@
 #include <iterator>
 
 namespace llvm {
-
 class IntegerType;
 struct fltSemantics;
 class LLVMContext;
@@ -234,13 +232,8 @@ class Type {
   /// Return true if this is 'token'.
   bool isTokenTy() const { return getTypeID() == TokenTyID; }
 
-  // Returns true if this is 'token' or 'token-like'.
-  bool isTokenLikeTy() const {
-    if (isTokenTy())
-      return true;
-    if (auto *TT = dyn_cast<TargetExtType>(this))
-      return TT->hasProperty(TargetExtType::Property::IsTokenLike);
-  }
+  /// Returns true if this is 'token' or 'token-like'.
+  bool isTokenLikeTy() const;
 
   /// True if this is an instance of IntegerType.
   bool isIntegerTy() const { return getTypeID() == IntegerTyID; }
diff --git a/llvm/lib/IR/Type.cpp b/llvm/lib/IR/Type.cpp
index d3aec2610e068..9db48e8f6a96b 100644
--- a/llvm/lib/IR/Type.cpp
+++ b/llvm/lib/IR/Type.cpp
@@ -1055,6 +1055,14 @@ static TargetTypeInfo getTargetTypeInfo(const 
TargetExtType *Ty) {
   return TargetTypeInfo(Type::getVoidTy(C));
 }
 
+bool Type::isTokenLikeTy() const {
+  if (isTokenTy())
+    return true;
+  if (auto *TT = dyn_cast<TargetExtType>(this))
+    return TT->hasProperty(TargetExtType::Property::IsTokenLike);
+  return false;
+}
+
 Type *TargetExtType::getLayoutType() const {
   return getTargetTypeInfo(this).LayoutType;
 }

>From 65f6d7a3ebfd3e24e0e9cb8c061f5e2cc5115993 Mon Sep 17 00:00:00 2001
From: Farzon Lotfi <farzonlo...@microsoft.com>
Date: Thu, 28 Aug 2025 13:14:28 -0400
Subject: [PATCH 09/14] PR #155332 changed the handlefromimplicitbinding
 intrinsic signature. test needed to be updated

---
 llvm/test/CodeGen/DirectX/issue-152348.ll | 42 +++++++++++------------
 1 file changed, 21 insertions(+), 21 deletions(-)

diff --git a/llvm/test/CodeGen/DirectX/issue-152348.ll 
b/llvm/test/CodeGen/DirectX/issue-152348.ll
index 66aeafb7785e3..aa0179d82b09e 100644
--- a/llvm/test/CodeGen/DirectX/issue-152348.ll
+++ b/llvm/test/CodeGen/DirectX/issue-152348.ll
@@ -34,21 +34,21 @@
 define void @CSMain() local_unnamed_addr {
 ; CHECK-LABEL: define void @CSMain() local_unnamed_addr {
 ; CHECK-NEXT:  [[ENTRY:.*:]]
-; CHECK-NEXT:    [[CALLRAWBUFFERBINDING:%.*]] = tail call target("dx.CBuffer", 
target("dx.Layout", [[__CBLAYOUT_D:%.*]], 16, 0, 4, 8, 12)) 
@llvm.dx.resource.handlefromimplicitbinding.tdx.CBuffer_tdx.Layout_s___cblayout_ds_16_0_4_8_12tt(i32
 3, i32 0, i32 1, i32 0, i1 false, ptr nonnull @d.str)
+; CHECK-NEXT:    [[CALLRAWBUFFERBINDING:%.*]] = tail call target("dx.CBuffer", 
target("dx.Layout", [[__CBLAYOUT_D:%.*]], 16, 0, 4, 8, 12)) 
@llvm.dx.resource.handlefromimplicitbinding.tdx.CBuffer_tdx.Layout_s___cblayout_ds_16_0_4_8_12tt(i32
 3, i32 0, i32 1, i32 0, ptr nonnull @d.str)
 ; CHECK-NEXT:    store target("dx.CBuffer", target("dx.Layout", 
[[__CBLAYOUT_D]], 16, 0, 4, 8, 12)) [[CALLRAWBUFFERBINDING]], ptr @d.cb, align 4
 ; CHECK-NEXT:    [[LOADE:%.*]] = load i32, ptr addrspace(2) @e, align 4
 ; CHECK-NEXT:    [[TOBOOL_NOT_I:%.*]] = icmp eq i32 [[LOADE]], 0
 ; CHECK-NEXT:    br i1 [[TOBOOL_NOT_I]], label %[[IF_ELSE_I:.*]], label 
%[[IF_THEN_I:.*]]
 ; CHECK:       [[IF_THEN_I]]:
-; CHECK-NEXT:    [[IFSTMTCALLRAWBUFFERBINDING:%.*]] = tail call 
target("dx.RawBuffer", half, 1, 0) 
@llvm.dx.resource.handlefromimplicitbinding.tdx.RawBuffer_f16_1_0t(i32 1, i32 
0, i32 1, i32 0, i1 false, ptr nonnull @.str)
-; CHECK-NEXT:    [[TMP0:%.*]] = tail call target("dx.RawBuffer", half, 1, 0) 
@llvm.dx.resource.handlefromimplicitbinding.tdx.RawBuffer_f16_1_0t(i32 2, i32 
0, i32 1, i32 0, i1 false, ptr nonnull @.str)
+; CHECK-NEXT:    [[IFSTMTCALLRAWBUFFERBINDING:%.*]] = tail call 
target("dx.RawBuffer", half, 1, 0) 
@llvm.dx.resource.handlefromimplicitbinding.tdx.RawBuffer_f16_1_0t(i32 1, i32 
0, i32 1, i32 0, ptr nonnull @.str)
+; CHECK-NEXT:    [[TMP0:%.*]] = tail call target("dx.RawBuffer", half, 1, 0) 
@llvm.dx.resource.handlefromimplicitbinding.tdx.RawBuffer_f16_1_0t(i32 2, i32 
0, i32 1, i32 0, ptr nonnull @.str)
 ; CHECK-NEXT:    [[TMP1:%.*]] = call { half, i1 } 
@llvm.dx.resource.load.rawbuffer.f16.tdx.RawBuffer_f16_1_0t(target("dx.RawBuffer",
 half, 1, 0) [[IFSTMTCALLRAWBUFFERBINDING]], i32 [[LOADE]], i32 0)
 ; CHECK-NEXT:    [[TMP2:%.*]] = extractvalue { half, i1 } [[TMP1]], 0
 ; CHECK-NEXT:    call void 
@llvm.dx.resource.store.rawbuffer.tdx.RawBuffer_f16_1_0t.f16(target("dx.RawBuffer",
 half, 1, 0) [[TMP0]], i32 [[LOADE]], i32 0, half [[TMP2]])
 ; CHECK-NEXT:    br label %[[_Z6CSMAINV_EXIT:.*]]
 ; CHECK:       [[IF_ELSE_I]]:
-; CHECK-NEXT:    [[CALL2NDRAWBUFFERBINDING:%.*]] = tail call 
target("dx.RawBuffer", half, 1, 0) 
@llvm.dx.resource.handlefromimplicitbinding.tdx.RawBuffer_f16_1_0t(i32 0, i32 
0, i32 1, i32 0, i1 false, ptr nonnull @.str)
-; CHECK-NEXT:    [[TMP3:%.*]] = tail call target("dx.RawBuffer", half, 1, 0) 
@llvm.dx.resource.handlefromimplicitbinding.tdx.RawBuffer_f16_1_0t(i32 2, i32 
0, i32 1, i32 0, i1 false, ptr nonnull @.str)
+; CHECK-NEXT:    [[CALL2NDRAWBUFFERBINDING:%.*]] = tail call 
target("dx.RawBuffer", half, 1, 0) 
@llvm.dx.resource.handlefromimplicitbinding.tdx.RawBuffer_f16_1_0t(i32 0, i32 
0, i32 1, i32 0, ptr nonnull @.str)
+; CHECK-NEXT:    [[TMP3:%.*]] = tail call target("dx.RawBuffer", half, 1, 0) 
@llvm.dx.resource.handlefromimplicitbinding.tdx.RawBuffer_f16_1_0t(i32 2, i32 
0, i32 1, i32 0, ptr nonnull @.str)
 ; CHECK-NEXT:    [[TMP4:%.*]] = call { half, i1 } 
@llvm.dx.resource.load.rawbuffer.f16.tdx.RawBuffer_f16_1_0t(target("dx.RawBuffer",
 half, 1, 0) [[CALL2NDRAWBUFFERBINDING]], i32 [[LOADE]], i32 0)
 ; CHECK-NEXT:    [[TMP5:%.*]] = extractvalue { half, i1 } [[TMP4]], 0
 ; CHECK-NEXT:    call void 
@llvm.dx.resource.store.rawbuffer.tdx.RawBuffer_f16_1_0t.f16(target("dx.RawBuffer",
 half, 1, 0) [[TMP3]], i32 [[LOADE]], i32 0, half [[TMP5]])
@@ -57,25 +57,25 @@ define void @CSMain() local_unnamed_addr {
 ; CHECK-NEXT:    ret void
 ;
 entry:
-  %callRawBufferBinding = tail call target("dx.CBuffer", target("dx.Layout", 
%__cblayout_d, 16, 0, 4, 8, 12)) 
@llvm.dx.resource.handlefromimplicitbinding.tdx.CBuffer_tdx.Layout_s___cblayout_ds_16_0_4_8_12tt(i32
 3, i32 0, i32 1, i32 0, i1 false, ptr nonnull @d.str)
-  store target("dx.CBuffer", target("dx.Layout", %__cblayout_d, 16, 0, 4, 8, 
12)) %callRawBufferBinding, ptr @d.cb, align 4
+  %callCBufferBinding = tail call target("dx.CBuffer", target("dx.Layout", 
%__cblayout_d, 16, 0, 4, 8, 12)) 
@llvm.dx.resource.handlefromimplicitbinding.tdx.CBuffer_tdx.Layout_s___cblayout_ds_16_0_4_8_12tt(i32
 3, i32 0, i32 1, i32 0, ptr nonnull @d.str)
+  store target("dx.CBuffer", target("dx.Layout", %__cblayout_d, 16, 0, 4, 8, 
12)) %callCBufferBinding, ptr @d.cb, align 4
   %loadE = load i32, ptr addrspace(2) @e, align 4
   %tobool.not.i = icmp eq i32 %loadE, 0
   br i1 %tobool.not.i, label %if.else.i, label %if.then.i
 
 if.then.i:                                        ; preds = %entry
-  %ifStmtcallRawBufferBinding = tail call target("dx.RawBuffer", half, 1, 0) 
@llvm.dx.resource.handlefromimplicitbinding.tdx.RawBuffer_f16_1_0t(i32 1, i32 
0, i32 1, i32 0, i1 false, ptr nonnull @.str)
+  %ifStmtcallRawBufferBinding = tail call target("dx.RawBuffer", half, 1, 0) 
@llvm.dx.resource.handlefromimplicitbinding.tdx.RawBuffer_f16_1_0t(i32 1, i32 
0, i32 1, i32 0, ptr nonnull @.str)
   %ifStmtCallResourceGEP = tail call noundef nonnull align 2 
dereferenceable(2) ptr 
@llvm.dx.resource.getpointer.p0.tdx.RawBuffer_f16_1_0t(target("dx.RawBuffer", 
half, 1, 0) %ifStmtcallRawBufferBinding, i32 %loadE)
   br label %_Z6CSMainv.exit
 
 if.else.i:                                        ; preds = %entry
-  %call2ndRawBufferBinding = tail call target("dx.RawBuffer", half, 1, 0) 
@llvm.dx.resource.handlefromimplicitbinding.tdx.RawBuffer_f16_1_0t(i32 0, i32 
0, i32 1, i32 0, i1 false, ptr nonnull @.str)
+  %call2ndRawBufferBinding = tail call target("dx.RawBuffer", half, 1, 0) 
@llvm.dx.resource.handlefromimplicitbinding.tdx.RawBuffer_f16_1_0t(i32 0, i32 
0, i32 1, i32 0, ptr nonnull @.str)
   %elseStmtCallResourceGEP = tail call noundef nonnull align 2 
dereferenceable(2) ptr 
@llvm.dx.resource.getpointer.p0.tdx.RawBuffer_f16_1_0t(target("dx.RawBuffer", 
half, 1, 0) %call2ndRawBufferBinding, i32 %loadE)
   br label %_Z6CSMainv.exit
 
 _Z6CSMainv.exit:                                  ; preds = %if.else.i, 
%if.then.i
   %.sink1 = phi ptr [ %ifStmtCallResourceGEP, %if.then.i ], [ 
%elseStmtCallResourceGEP, %if.else.i ]
-  %call3rdRawBufferBinding = tail call target("dx.RawBuffer", half, 1, 0) 
@llvm.dx.resource.handlefromimplicitbinding.tdx.RawBuffer_f16_1_0t(i32 2, i32 
0, i32 1, i32 0, i1 false, ptr nonnull @.str)
+  %call3rdRawBufferBinding = tail call target("dx.RawBuffer", half, 1, 0) 
@llvm.dx.resource.handlefromimplicitbinding.tdx.RawBuffer_f16_1_0t(i32 2, i32 
0, i32 1, i32 0, ptr nonnull @.str)
   %sinkCallResourceGEP = tail call noundef nonnull align 2 dereferenceable(2) 
ptr 
@llvm.dx.resource.getpointer.p0.tdx.RawBuffer_f16_1_0t(target("dx.RawBuffer", 
half, 1, 0) %call3rdRawBufferBinding, i32 %loadE)
   %loadSink = load half, ptr %.sink1, align 2
   store half %loadSink, ptr %sinkCallResourceGEP, align 2
@@ -85,16 +85,16 @@ _Z6CSMainv.exit:                                  ; preds = 
%if.else.i, %if.then
 define void @Main() local_unnamed_addr  {
 ; CHECK-LABEL: define void @Main() local_unnamed_addr {
 ; CHECK-NEXT:  [[ENTRY:.*:]]
-; CHECK-NEXT:    [[CALLRAWBUFFERBINDING1:%.*]] = tail call 
target("dx.RawBuffer", half, 1, 0) 
@llvm.dx.resource.handlefromimplicitbinding.tdx.RawBuffer_f16_1_0t(i32 0, i32 
0, i32 1, i32 0, i1 false, ptr nonnull @.str)
-; CHECK-NEXT:    [[CALLRAWBUFFERBINDING0:%.*]] = tail call 
target("dx.RawBuffer", half, 1, 0) 
@llvm.dx.resource.handlefromimplicitbinding.tdx.RawBuffer_f16_1_0t(i32 1, i32 
0, i32 1, i32 0, i1 false, ptr nonnull @.str)
-; CHECK-NEXT:    [[CALLRAWBUFFERBINDING:%.*]] = tail call target("dx.CBuffer", 
target("dx.Layout", [[__CBLAYOUT_D:%.*]], 16, 0, 4, 8, 12)) 
@llvm.dx.resource.handlefromimplicitbinding.tdx.CBuffer_tdx.Layout_s___cblayout_ds_16_0_4_8_12tt(i32
 3, i32 0, i32 1, i32 0, i1 false, ptr nonnull @d.str)
+; CHECK-NEXT:    [[CALLRAWBUFFERBINDING1:%.*]] = tail call 
target("dx.RawBuffer", half, 1, 0) 
@llvm.dx.resource.handlefromimplicitbinding.tdx.RawBuffer_f16_1_0t(i32 0, i32 
0, i32 1, i32 0, ptr nonnull @.str)
+; CHECK-NEXT:    [[CALLRAWBUFFERBINDING0:%.*]] = tail call 
target("dx.RawBuffer", half, 1, 0) 
@llvm.dx.resource.handlefromimplicitbinding.tdx.RawBuffer_f16_1_0t(i32 1, i32 
0, i32 1, i32 0, ptr nonnull @.str)
+; CHECK-NEXT:    [[CALLRAWBUFFERBINDING:%.*]] = tail call target("dx.CBuffer", 
target("dx.Layout", [[__CBLAYOUT_D:%.*]], 16, 0, 4, 8, 12)) 
@llvm.dx.resource.handlefromimplicitbinding.tdx.CBuffer_tdx.Layout_s___cblayout_ds_16_0_4_8_12tt(i32
 3, i32 0, i32 1, i32 0, ptr nonnull @d.str)
 ; CHECK-NEXT:    store target("dx.CBuffer", target("dx.Layout", 
[[__CBLAYOUT_D]], 16, 0, 4, 8, 12)) [[CALLRAWBUFFERBINDING]], ptr @d.cb, align 4
 ; CHECK-NEXT:    [[LOADE:%.*]] = load i32, ptr addrspace(2) @e, align 4
 ; CHECK-NEXT:    [[TOBOOL_NOT_I:%.*]] = icmp eq i32 [[LOADE]], 0
 ; CHECK-NEXT:    br i1 [[TOBOOL_NOT_I]], label %[[IF_ELSE_I:.*]], label 
%[[IF_THEN_I:.*]]
 ; CHECK:       [[IF_THEN_I]]:
 ; CHECK-NEXT:    [[IFSTMTLOADE:%.*]] = load i32, ptr addrspace(2) @e, align 4
-; CHECK-NEXT:    [[TMP0:%.*]] = tail call target("dx.RawBuffer", half, 1, 0) 
@llvm.dx.resource.handlefromimplicitbinding.tdx.RawBuffer_f16_1_0t(i32 2, i32 
0, i32 1, i32 0, i1 false, ptr nonnull @.str)
+; CHECK-NEXT:    [[TMP0:%.*]] = tail call target("dx.RawBuffer", half, 1, 0) 
@llvm.dx.resource.handlefromimplicitbinding.tdx.RawBuffer_f16_1_0t(i32 2, i32 
0, i32 1, i32 0, ptr nonnull @.str)
 ; CHECK-NEXT:    [[TMP1:%.*]] = call { half, i1 } 
@llvm.dx.resource.load.rawbuffer.f16.tdx.RawBuffer_f16_1_0t(target("dx.RawBuffer",
 half, 1, 0) [[CALLRAWBUFFERBINDING0]], i32 [[LOADE]], i32 0)
 ; CHECK-NEXT:    [[TMP2:%.*]] = extractvalue { half, i1 } [[TMP1]], 0
 ; CHECK-NEXT:    call void 
@llvm.dx.resource.store.rawbuffer.tdx.RawBuffer_f16_1_0t.f16(target("dx.RawBuffer",
 half, 1, 0) [[TMP0]], i32 [[IFSTMTLOADE]], i32 0, half [[TMP2]])
@@ -104,14 +104,14 @@ define void @Main() local_unnamed_addr  {
 ; CHECK-NEXT:    [[CMP_I:%.*]] = icmp eq i32 [[ELSESTMTLOADE]], 0
 ; CHECK-NEXT:    br i1 [[CMP_I]], label %[[IF_THEN2_I:.*]], label 
%[[IF_ELSE6_I:.*]]
 ; CHECK:       [[IF_THEN2_I]]:
-; CHECK-NEXT:    [[TMP3:%.*]] = tail call target("dx.RawBuffer", half, 1, 0) 
@llvm.dx.resource.handlefromimplicitbinding.tdx.RawBuffer_f16_1_0t(i32 2, i32 
0, i32 1, i32 0, i1 false, ptr nonnull @.str)
+; CHECK-NEXT:    [[TMP3:%.*]] = tail call target("dx.RawBuffer", half, 1, 0) 
@llvm.dx.resource.handlefromimplicitbinding.tdx.RawBuffer_f16_1_0t(i32 2, i32 
0, i32 1, i32 0, ptr nonnull @.str)
 ; CHECK-NEXT:    [[TMP4:%.*]] = call { half, i1 } 
@llvm.dx.resource.load.rawbuffer.f16.tdx.RawBuffer_f16_1_0t(target("dx.RawBuffer",
 half, 1, 0) [[CALLRAWBUFFERBINDING0]], i32 0, i32 0)
 ; CHECK-NEXT:    [[TMP5:%.*]] = extractvalue { half, i1 } [[TMP4]], 0
 ; CHECK-NEXT:    call void 
@llvm.dx.resource.store.rawbuffer.tdx.RawBuffer_f16_1_0t.f16(target("dx.RawBuffer",
 half, 1, 0) [[TMP3]], i32 0, i32 0, half [[TMP5]])
 ; CHECK-NEXT:    br label %[[_Z6MAINV_EXIT]]
 ; CHECK:       [[IF_ELSE6_I]]:
 ; CHECK-NEXT:    [[ELSESTMTLOADE2:%.*]] = load i32, ptr addrspace(2) @e, align 
4
-; CHECK-NEXT:    [[TMP6:%.*]] = tail call target("dx.RawBuffer", half, 1, 0) 
@llvm.dx.resource.handlefromimplicitbinding.tdx.RawBuffer_f16_1_0t(i32 2, i32 
0, i32 1, i32 0, i1 false, ptr nonnull @.str)
+; CHECK-NEXT:    [[TMP6:%.*]] = tail call target("dx.RawBuffer", half, 1, 0) 
@llvm.dx.resource.handlefromimplicitbinding.tdx.RawBuffer_f16_1_0t(i32 2, i32 
0, i32 1, i32 0, ptr nonnull @.str)
 ; CHECK-NEXT:    [[TMP7:%.*]] = call { half, i1 } 
@llvm.dx.resource.load.rawbuffer.f16.tdx.RawBuffer_f16_1_0t(target("dx.RawBuffer",
 half, 1, 0) [[CALLRAWBUFFERBINDING1]], i32 [[ELSESTMTLOADE2]], i32 0)
 ; CHECK-NEXT:    [[TMP8:%.*]] = extractvalue { half, i1 } [[TMP7]], 0
 ; CHECK-NEXT:    call void 
@llvm.dx.resource.store.rawbuffer.tdx.RawBuffer_f16_1_0t.f16(target("dx.RawBuffer",
 half, 1, 0) [[TMP6]], i32 [[ELSESTMTLOADE]], i32 0, half [[TMP8]])
@@ -120,10 +120,10 @@ define void @Main() local_unnamed_addr  {
 ; CHECK-NEXT:    ret void
 ;
 entry:
-  %callRawBufferBinding1 = tail call target("dx.RawBuffer", half, 1, 0) 
@llvm.dx.resource.handlefromimplicitbinding.tdx.RawBuffer_f16_1_0t(i32 0, i32 
0, i32 1, i32 0, i1 false, ptr nonnull @.str)
-  %callRawBufferBinding0 = tail call target("dx.RawBuffer", half, 1, 0) 
@llvm.dx.resource.handlefromimplicitbinding.tdx.RawBuffer_f16_1_0t(i32 1, i32 
0, i32 1, i32 0, i1 false, ptr nonnull @.str)
-  %callRawBufferBinding = tail call target("dx.CBuffer", target("dx.Layout", 
%__cblayout_d, 16, 0, 4, 8, 12)) 
@llvm.dx.resource.handlefromimplicitbinding.tdx.CBuffer_tdx.Layout_s___cblayout_ds_16_0_4_8_12tt(i32
 3, i32 0, i32 1, i32 0, i1 false, ptr nonnull @d.str)
-  store target("dx.CBuffer", target("dx.Layout", %__cblayout_d, 16, 0, 4, 8, 
12)) %callRawBufferBinding, ptr @d.cb, align 4
+  %callRawBufferBinding1 = tail call target("dx.RawBuffer", half, 1, 0) 
@llvm.dx.resource.handlefromimplicitbinding.tdx.RawBuffer_f16_1_0t(i32 0, i32 
0, i32 1, i32 0, ptr nonnull @.str)
+  %callRawBufferBinding0 = tail call target("dx.RawBuffer", half, 1, 0) 
@llvm.dx.resource.handlefromimplicitbinding.tdx.RawBuffer_f16_1_0t(i32 1, i32 
0, i32 1, i32 0, ptr nonnull @.str)
+  %callCBufferBinding = tail call target("dx.CBuffer", target("dx.Layout", 
%__cblayout_d, 16, 0, 4, 8, 12)) 
@llvm.dx.resource.handlefromimplicitbinding.tdx.CBuffer_tdx.Layout_s___cblayout_ds_16_0_4_8_12tt(i32
 3, i32 0, i32 1, i32 0, ptr nonnull @d.str)
+  store target("dx.CBuffer", target("dx.Layout", %__cblayout_d, 16, 0, 4, 8, 
12)) %callCBufferBinding, ptr @d.cb, align 4
   %loadE = load i32, ptr addrspace(2) @e, align 4
   %tobool.not.i = icmp eq i32 %loadE, 0
   br i1 %tobool.not.i, label %if.else.i, label %if.then.i
@@ -150,7 +150,7 @@ if.else6.i:                                       ; preds = 
%if.else.i
 _Z6Mainv.exit:                                    ; preds = %if.else6.i, 
%if.then2.i, %if.then.i
   %.sink2 = phi i32 [ %ifStmtLoadE, %if.then.i ], [ 0, %if.then2.i ], [ 
%elseStmtLoadE, %if.else6.i ]
   %.sink.in = phi ptr [ %ifStmtCallResourceGEP, %if.then.i ], [ 
%elseifStmtCallResourceGEP, %if.then2.i ], [ %elseStmtCallResourceGEP, 
%if.else6.i ]
-  %callRawBufferBindingSink = tail call target("dx.RawBuffer", half, 1, 0) 
@llvm.dx.resource.handlefromimplicitbinding.tdx.RawBuffer_f16_1_0t(i32 2, i32 
0, i32 1, i32 0, i1 false, ptr nonnull @.str)
+  %callRawBufferBindingSink = tail call target("dx.RawBuffer", half, 1, 0) 
@llvm.dx.resource.handlefromimplicitbinding.tdx.RawBuffer_f16_1_0t(i32 2, i32 
0, i32 1, i32 0, ptr nonnull @.str)
   %.sink = load half, ptr %.sink.in, align 2
   %i11 = tail call noundef nonnull align 2 dereferenceable(2) ptr 
@llvm.dx.resource.getpointer.p0.tdx.RawBuffer_f16_1_0t(target("dx.RawBuffer", 
half, 1, 0) %callRawBufferBindingSink, i32 %.sink2)
   store half %.sink, ptr %i11, align 2

>From 93ff6d262453f01a51ec42d12c3f3f4c2f885ba8 Mon Sep 17 00:00:00 2001
From: Farzon Lotfi <farzonlo...@microsoft.com>
Date: Thu, 28 Aug 2025 14:30:40 -0400
Subject: [PATCH 10/14] fix for hoisting non void returns

---
 llvm/include/llvm/IR/Type.h                   |  1 +
 .../lib/Target/DirectX/DXILResourceAccess.cpp | 35 ++++++++++++----
 .../CodeGen/DirectX/phi-node-replacement.ll   | 42 +++++++++++++++++++
 3 files changed, 69 insertions(+), 9 deletions(-)
 create mode 100644 llvm/test/CodeGen/DirectX/phi-node-replacement.ll

diff --git a/llvm/include/llvm/IR/Type.h b/llvm/include/llvm/IR/Type.h
index 0c8f960966cd5..17d5f5aaf1a1e 100644
--- a/llvm/include/llvm/IR/Type.h
+++ b/llvm/include/llvm/IR/Type.h
@@ -25,6 +25,7 @@
 #include <iterator>
 
 namespace llvm {
+
 class IntegerType;
 struct fltSemantics;
 class LLVMContext;
diff --git a/llvm/lib/Target/DirectX/DXILResourceAccess.cpp 
b/llvm/lib/Target/DirectX/DXILResourceAccess.cpp
index c569ab8adfcf0..7e27850e00f91 100644
--- a/llvm/lib/Target/DirectX/DXILResourceAccess.cpp
+++ b/llvm/lib/Target/DirectX/DXILResourceAccess.cpp
@@ -8,6 +8,7 @@
 
 #include "DXILResourceAccess.h"
 #include "DirectX.h"
+#include "llvm/ADT/SetVector.h"
 #include "llvm/Analysis/DXILResource.h"
 #include "llvm/IR/BasicBlock.h"
 #include "llvm/IR/Dominators.h"
@@ -270,8 +271,10 @@ static void phiNodeRemapHelper(PHINode *Phi, BasicBlock 
*BB,
   }
 }
 
-static void phiNodeReplacement(IntrinsicInst *II) {
-  SmallVector<Instruction *> DeadInsts;
+static void phiNodeReplacement(IntrinsicInst *II,
+                               SmallVector<Instruction *> &PrevBBDeadInsts,
+                               SetVector<BasicBlock *> &DeadBB) {
+  SmallVector<Instruction *> CurrBBDeadInsts;
   for (User *U : II->users()) {
     auto *Phi = dyn_cast<PHINode>(U);
     if (!Phi)
@@ -280,23 +283,29 @@ static void phiNodeReplacement(IntrinsicInst *II) {
     IRBuilder<> Builder(Phi);
     SmallVector<Instruction *> UsesInBlock;
     collectBlockUseDef(Phi, UsesInBlock);
+    bool HasReturnUse = isa<ReturnInst>(UsesInBlock[UsesInBlock.size() - 1]);
 
     for (unsigned I = 0, E = Phi->getNumIncomingValues(); I < E; I++) {
       auto *CurrIncomingBB = Phi->getIncomingBlock(I);
       phiNodeRemapHelper(Phi, CurrIncomingBB, Builder, UsesInBlock);
+      if (HasReturnUse)
+        PrevBBDeadInsts.push_back(&CurrIncomingBB->back());
     }
 
-    DeadInsts.push_back(Phi);
+    CurrBBDeadInsts.push_back(Phi);
 
     for (Instruction *I : UsesInBlock) {
-      DeadInsts.push_back(I);
+      CurrBBDeadInsts.push_back(I);
+    }
+    if (HasReturnUse) {
+      BasicBlock *PhiBB = Phi->getParent();
+      DeadBB.insert(PhiBB);
     }
   }
-
   // Traverse the now-dead instructions in RPO and remove them.
-  for (Instruction *Dead : llvm::reverse(DeadInsts))
+  for (Instruction *Dead : llvm::reverse(CurrBBDeadInsts))
     Dead->eraseFromParent();
-  DeadInsts.clear();
+  CurrBBDeadInsts.clear();
 }
 
 static void replaceAccess(IntrinsicInst *II, dxil::ResourceTypeInfo &RTI) {
@@ -342,11 +351,13 @@ static void replaceAccess(IntrinsicInst *II, 
dxil::ResourceTypeInfo &RTI) {
 
 static bool transformResourcePointers(Function &F, DXILResourceTypeMap &DRTM) {
   SmallVector<std::pair<IntrinsicInst *, dxil::ResourceTypeInfo>> Resources;
-  for (BasicBlock &BB : F) {
+  SetVector<BasicBlock *> DeadBB;
+  SmallVector<Instruction *> PrevBBDeadInsts;
+  for (BasicBlock &BB : make_early_inc_range(F)) {
     for (Instruction &I : make_early_inc_range(BB))
       if (auto *II = dyn_cast<IntrinsicInst>(&I))
         if (II->getIntrinsicID() == Intrinsic::dx_resource_getpointer)
-          phiNodeReplacement(II);
+          phiNodeReplacement(II, PrevBBDeadInsts, DeadBB);
 
     for (Instruction &I : BB)
       if (auto *II = dyn_cast<IntrinsicInst>(&I))
@@ -355,6 +366,12 @@ static bool transformResourcePointers(Function &F, 
DXILResourceTypeMap &DRTM) {
           Resources.emplace_back(II, DRTM[HandleTy]);
         }
   }
+  for (auto *Dead : PrevBBDeadInsts)
+    Dead->eraseFromParent();
+  PrevBBDeadInsts.clear();
+  for (auto *Dead : DeadBB)
+    Dead->eraseFromParent();
+  DeadBB.clear();
 
   for (auto &[II, RI] : Resources)
     replaceAccess(II, RI);
diff --git a/llvm/test/CodeGen/DirectX/phi-node-replacement.ll 
b/llvm/test/CodeGen/DirectX/phi-node-replacement.ll
new file mode 100644
index 0000000000000..6aef126cb5ecd
--- /dev/null
+++ b/llvm/test/CodeGen/DirectX/phi-node-replacement.ll
@@ -0,0 +1,42 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py 
UTC_ARGS: --version 5
+; RUN: opt -S -dxil-resource-type -dxil-resource-access 
-mtriple=dxil-pc-shadermodel6.3-library %s | FileCheck %s
+
+%"$Globals" = type { i32 }
+@CBV = external constant %"$Globals"
+@.str = internal unnamed_addr constant [2 x i8] c"a\00", align 1
+
+define half @CSMain() local_unnamed_addr {
+; CHECK-LABEL: define half @CSMain() local_unnamed_addr {
+; CHECK-NEXT:    [[LOADGLOBAL:%.*]] = load i32, ptr @CBV, align 4
+; CHECK-NEXT:    [[TOBOOL_NOT_I:%.*]] = icmp eq i32 [[LOADGLOBAL]], 0
+; CHECK-NEXT:    br i1 [[TOBOOL_NOT_I]], label %[[IF_ELSE_I:.*]], label 
%[[IF_THEN_I:.*]]
+; CHECK:       [[IF_THEN_I]]:
+; CHECK-NEXT:    [[IFSTMTCALLRAWBUFFERBINDING:%.*]] = tail call 
target("dx.RawBuffer", half, 1, 0) 
@llvm.dx.resource.handlefromimplicitbinding.tdx.RawBuffer_f16_1_0t(i32 1, i32 
0, i32 1, i32 0, ptr nonnull @.str)
+; CHECK-NEXT:    [[TMP1:%.*]] = call { half, i1 } 
@llvm.dx.resource.load.rawbuffer.f16.tdx.RawBuffer_f16_1_0t(target("dx.RawBuffer",
 half, 1, 0) [[IFSTMTCALLRAWBUFFERBINDING]], i32 [[LOADGLOBAL]], i32 0)
+; CHECK-NEXT:    [[TMP2:%.*]] = extractvalue { half, i1 } [[TMP1]], 0
+; CHECK-NEXT:    ret half [[TMP2]]
+; CHECK:       [[IF_ELSE_I]]:
+; CHECK-NEXT:    [[CALL2NDRAWBUFFERBINDING:%.*]] = tail call 
target("dx.RawBuffer", half, 1, 0) 
@llvm.dx.resource.handlefromimplicitbinding.tdx.RawBuffer_f16_1_0t(i32 0, i32 
0, i32 1, i32 0, ptr nonnull @.str)
+; CHECK-NEXT:    [[TMP3:%.*]] = call { half, i1 } 
@llvm.dx.resource.load.rawbuffer.f16.tdx.RawBuffer_f16_1_0t(target("dx.RawBuffer",
 half, 1, 0) [[CALL2NDRAWBUFFERBINDING]], i32 [[LOADGLOBAL]], i32 0)
+; CHECK-NEXT:    [[TMP4:%.*]] = extractvalue { half, i1 } [[TMP3]], 0
+; CHECK-NEXT:    ret half [[TMP4]]
+;
+  %loadGlobal = load i32, ptr @CBV, align 4
+  %tobool.not.i = icmp eq i32 %loadGlobal, 0
+  br i1 %tobool.not.i, label %if.else.i, label %if.then.i
+
+  if.then.i:                                        ; preds = %entry
+  %ifStmtcallRawBufferBinding = tail call target("dx.RawBuffer", half, 1, 0) 
@llvm.dx.resource.handlefromimplicitbinding.tdx.RawBuffer_f16_1_0t(i32 1, i32 
0, i32 1, i32 0, ptr nonnull @.str)
+  %ifStmtCallResourceGEP = tail call noundef nonnull align 2 
dereferenceable(2) ptr 
@llvm.dx.resource.getpointer.p0.tdx.RawBuffer_f16_1_0t(target("dx.RawBuffer", 
half, 1, 0) %ifStmtcallRawBufferBinding, i32 %loadGlobal)
+  br label %_Z6CSMainv.exit
+
+  if.else.i:                                        ; preds = %entry
+  %call2ndRawBufferBinding = tail call target("dx.RawBuffer", half, 1, 0) 
@llvm.dx.resource.handlefromimplicitbinding.tdx.RawBuffer_f16_1_0t(i32 0, i32 
0, i32 1, i32 0, ptr nonnull @.str)
+  %elseStmtCallResourceGEP = tail call noundef nonnull align 2 
dereferenceable(2) ptr 
@llvm.dx.resource.getpointer.p0.tdx.RawBuffer_f16_1_0t(target("dx.RawBuffer", 
half, 1, 0) %call2ndRawBufferBinding, i32 %loadGlobal)
+  br label %_Z6CSMainv.exit
+
+  _Z6CSMainv.exit:                                  ; preds = %if.else.i, 
%if.then.i
+  %.sink1 = phi ptr [ %ifStmtCallResourceGEP, %if.then.i ], [ 
%elseStmtCallResourceGEP, %if.else.i ]
+  %loadSink = load half, ptr %.sink1, align 2
+  ret half %loadSink
+}

>From 5121bc1084507af3c1f26d9436af32dff759283b Mon Sep 17 00:00:00 2001
From: Farzon Lotfi <farzonlo...@microsoft.com>
Date: Thu, 28 Aug 2025 16:00:45 -0400
Subject: [PATCH 11/14] pr comments

---
 llvm/include/llvm/IR/DerivedTypes.h            |  3 ++-
 llvm/include/llvm/IR/Type.h                    |  2 +-
 llvm/lib/Target/DirectX/DXILResourceAccess.cpp | 13 +++++++------
 llvm/lib/Transforms/Utils/Local.cpp            |  5 +----
 4 files changed, 11 insertions(+), 12 deletions(-)

diff --git a/llvm/include/llvm/IR/DerivedTypes.h 
b/llvm/include/llvm/IR/DerivedTypes.h
index 5db79b82ac61d..29b34cfe33964 100644
--- a/llvm/include/llvm/IR/DerivedTypes.h
+++ b/llvm/include/llvm/IR/DerivedTypes.h
@@ -847,7 +847,8 @@ class TargetExtType : public Type {
     CanBeLocal = 1U << 2,
     /// This type may be used as an element in a vector.
     CanBeVectorElement = 1U << 3,
-    /// All uses of this type must not attempt to introspect or obscure it.
+    // This type can only be used in intrinsic arguments and return values.
+    /// In particular, it cannot be used in select and phi instructions.
     IsTokenLike = 1U << 4,
   };
 
diff --git a/llvm/include/llvm/IR/Type.h b/llvm/include/llvm/IR/Type.h
index 17d5f5aaf1a1e..1c042500ba8ec 100644
--- a/llvm/include/llvm/IR/Type.h
+++ b/llvm/include/llvm/IR/Type.h
@@ -233,7 +233,7 @@ class Type {
   /// Return true if this is 'token'.
   bool isTokenTy() const { return getTypeID() == TokenTyID; }
 
-  /// Returns true if this is 'token' or 'token-like'.
+  /// Returns true if this is 'token' or a token-like target type.s
   bool isTokenLikeTy() const;
 
   /// True if this is an instance of IntegerType.
diff --git a/llvm/lib/Target/DirectX/DXILResourceAccess.cpp 
b/llvm/lib/Target/DirectX/DXILResourceAccess.cpp
index 7e27850e00f91..6579d3405cf39 100644
--- a/llvm/lib/Target/DirectX/DXILResourceAccess.cpp
+++ b/llvm/lib/Target/DirectX/DXILResourceAccess.cpp
@@ -203,10 +203,10 @@ static void createLoadIntrinsic(IntrinsicInst *II, 
LoadInst *LI, Value *Offset,
   llvm_unreachable("Unhandled case in switch");
 }
 
-static void collectBlockUseDef(Instruction *Start,
-                               SmallVectorImpl<Instruction *> &Out) {
+static SmallVector<Instruction *> collectBlockUseDef(Instruction *Start) {
   SmallPtrSet<Instruction *, 32> Visited;
   SmallVector<Instruction *, 32> Worklist;
+  SmallVector<Instruction *> Out;
   auto *BB = Start->getParent();
 
   // Seed with direct users in this block.
@@ -247,6 +247,8 @@ static void collectBlockUseDef(Instruction *Start,
   llvm::sort(Out, [&](Instruction *A, Instruction *B) {
     return Ord.lookup(A) < Ord.lookup(B);
   });
+
+  return Out;
 }
 
 static void phiNodeRemapHelper(PHINode *Phi, BasicBlock *BB,
@@ -272,7 +274,7 @@ static void phiNodeRemapHelper(PHINode *Phi, BasicBlock *BB,
 }
 
 static void phiNodeReplacement(IntrinsicInst *II,
-                               SmallVector<Instruction *> &PrevBBDeadInsts,
+                               SmallVectorImpl<Instruction *> &PrevBBDeadInsts,
                                SetVector<BasicBlock *> &DeadBB) {
   SmallVector<Instruction *> CurrBBDeadInsts;
   for (User *U : II->users()) {
@@ -281,9 +283,8 @@ static void phiNodeReplacement(IntrinsicInst *II,
       continue;
 
     IRBuilder<> Builder(Phi);
-    SmallVector<Instruction *> UsesInBlock;
-    collectBlockUseDef(Phi, UsesInBlock);
-    bool HasReturnUse = isa<ReturnInst>(UsesInBlock[UsesInBlock.size() - 1]);
+    SmallVector<Instruction *> UsesInBlock = collectBlockUseDef(Phi);
+    bool HasReturnUse = isa<ReturnInst>(UsesInBlock.back());
 
     for (unsigned I = 0, E = Phi->getNumIncomingValues(); I < E; I++) {
       auto *CurrIncomingBB = Phi->getIncomingBlock(I);
diff --git a/llvm/lib/Transforms/Utils/Local.cpp 
b/llvm/lib/Transforms/Utils/Local.cpp
index 0eb92470045ea..b94ed7db91580 100644
--- a/llvm/lib/Transforms/Utils/Local.cpp
+++ b/llvm/lib/Transforms/Utils/Local.cpp
@@ -3839,7 +3839,7 @@ void llvm::maybeMarkSanitizerLibraryCallNoBuiltin(
 bool llvm::canReplaceOperandWithVariable(const Instruction *I, unsigned OpIdx) 
{
   const auto *Op = I->getOperand(OpIdx);
   // We can't have a PHI with a metadata or token type.
-  if (Op->getType()->isMetadataTy() || Op->getType()->isTokenTy())
+  if (Op->getType()->isMetadataTy() || Op->getType()->isTokenLikeTy())
     return false;
 
   // swifterror pointers can only be used by a load, store, or as a swifterror
@@ -3852,9 +3852,6 @@ bool llvm::canReplaceOperandWithVariable(const 
Instruction *I, unsigned OpIdx) {
   if (I->isLifetimeStartOrEnd())
     return false;
 
-  if (Op->getType()->isTokenLikeTy())
-    return false;
-
   // Early exit.
   if (!isa<Constant, InlineAsm>(Op))
     return true;

>From e4215bb8feaaa6a73cf2db61e922afa772f6dff9 Mon Sep 17 00:00:00 2001
From: Farzon Lotfi <farzonlo...@microsoft.com>
Date: Thu, 28 Aug 2025 17:17:17 -0400
Subject: [PATCH 12/14] add verifer and simplifyCFG tests

---
 llvm/lib/IR/Verifier.cpp                      | 10 ++--
 .../Transforms/SimplifyCFG/token_like_type.ll | 46 +++++++++++++++++++
 llvm/test/Verifier/tokenlike1-with-asserts.ll | 12 +++++
 .../Verifier/tokenlike1-without-asserts.ll    | 12 +++++
 llvm/test/Verifier/tokenlike5.ll              |  7 +++
 llvm/test/Verifier/tokenlike6.ll              |  7 +++
 llvm/test/Verifier/tokenlike7.ll              |  8 ++++
 7 files changed, 97 insertions(+), 5 deletions(-)
 create mode 100644 llvm/test/Transforms/SimplifyCFG/token_like_type.ll
 create mode 100644 llvm/test/Verifier/tokenlike1-with-asserts.ll
 create mode 100644 llvm/test/Verifier/tokenlike1-without-asserts.ll
 create mode 100644 llvm/test/Verifier/tokenlike5.ll
 create mode 100644 llvm/test/Verifier/tokenlike6.ll
 create mode 100644 llvm/test/Verifier/tokenlike7.ll

diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp
index 6e11d6a77cbf7..da05ff166122f 100644
--- a/llvm/lib/IR/Verifier.cpp
+++ b/llvm/lib/IR/Verifier.cpp
@@ -3008,7 +3008,7 @@ void Verifier::visitFunction(const Function &F) {
     if (!IsIntrinsic) {
       Check(!Arg.getType()->isMetadataTy(),
             "Function takes metadata but isn't an intrinsic", &Arg, &F);
-      Check(!Arg.getType()->isTokenTy(),
+      Check(!Arg.getType()->isTokenLikeTy(),
             "Function takes token but isn't an intrinsic", &Arg, &F);
       Check(!Arg.getType()->isX86_AMXTy(),
             "Function takes x86_amx but isn't an intrinsic", &Arg, &F);
@@ -3022,7 +3022,7 @@ void Verifier::visitFunction(const Function &F) {
   }
 
   if (!IsIntrinsic) {
-    Check(!F.getReturnType()->isTokenTy(),
+    Check(!F.getReturnType()->isTokenLikeTy(),
           "Function returns a token but isn't an intrinsic", &F);
     Check(!F.getReturnType()->isX86_AMXTy(),
           "Function returns a x86_amx but isn't an intrinsic", &F);
@@ -3636,7 +3636,7 @@ void Verifier::visitPHINode(PHINode &PN) {
         "PHI nodes not grouped at top of basic block!", &PN, PN.getParent());
 
   // Check that a PHI doesn't yield a Token.
-  Check(!PN.getType()->isTokenTy(), "PHI nodes cannot have token type!");
+  Check(!PN.getType()->isTokenLikeTy(), "PHI nodes cannot have token type!");
 
   // Check that all of the values of the PHI node have the same type as the
   // result.
@@ -3841,14 +3841,14 @@ void Verifier::visitCallBase(CallBase &Call) {
     for (Type *ParamTy : FTy->params()) {
       Check(!ParamTy->isMetadataTy(),
             "Function has metadata parameter but isn't an intrinsic", Call);
-      Check(!ParamTy->isTokenTy(),
+      Check(!ParamTy->isTokenLikeTy(),
             "Function has token parameter but isn't an intrinsic", Call);
     }
   }
 
   // Verify that indirect calls don't return tokens.
   if (!Call.getCalledFunction()) {
-    Check(!FTy->getReturnType()->isTokenTy(),
+    Check(!FTy->getReturnType()->isTokenLikeTy(),
           "Return type cannot be token for indirect call!");
     Check(!FTy->getReturnType()->isX86_AMXTy(),
           "Return type cannot be x86_amx for indirect call!");
diff --git a/llvm/test/Transforms/SimplifyCFG/token_like_type.ll 
b/llvm/test/Transforms/SimplifyCFG/token_like_type.ll
new file mode 100644
index 0000000000000..21a14ccebed86
--- /dev/null
+++ b/llvm/test/Transforms/SimplifyCFG/token_like_type.ll
@@ -0,0 +1,46 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py 
UTC_ARGS: --version 5
+; RUN: opt -S -passes=simplifycfg %s | FileCheck %s
+
+; NOTE: The Check lines should exactly match the IR.
+
+%"$Globals" = type { i32 }
+@CBV = external constant %"$Globals"
+@.str = internal unnamed_addr constant [2 x i8] c"a\00", align 1
+
+define half @CSMain() local_unnamed_addr {
+; CHECK-LABEL: define half @CSMain() local_unnamed_addr {
+; CHECK-NEXT:    [[LOADGLOBAL:%.*]] = load i32, ptr @CBV, align 4
+; CHECK-NEXT:    [[TOBOOL_NOT_I:%.*]] = icmp eq i32 [[LOADGLOBAL]], 0
+; CHECK-NEXT:    br i1 [[TOBOOL_NOT_I]], label %[[IF_ELSE_I:.*]], label 
%[[IF_THEN_I:.*]]
+; CHECK:       [[IF_THEN_I]]:
+; CHECK-NEXT:    [[IFSTMTCALLRAWBUFFERBINDING:%.*]] = tail call 
target("dx.RawBuffer", half, 1, 0) 
@llvm.dx.resource.handlefromimplicitbinding.tdx.RawBuffer_f16_1_0t(i32 1, i32 
0, i32 1, i32 0, ptr nonnull @.str)
+; CHECK-NEXT:    [[IFSTMTCALLRESOURCEGEP:%.*]] = tail call noundef nonnull 
align 2 dereferenceable(2) ptr 
@llvm.dx.resource.getpointer.p0.tdx.RawBuffer_f16_1_0t(target("dx.RawBuffer", 
half, 1, 0) [[IFSTMTCALLRAWBUFFERBINDING]], i32 [[LOADGLOBAL]])
+; CHECK-NEXT:    br label %[[_Z6CSMAINV_EXIT:.*]]
+; CHECK:       [[IF_ELSE_I]]:
+; CHECK-NEXT:    [[CALL2NDRAWBUFFERBINDING:%.*]] = tail call 
target("dx.RawBuffer", half, 1, 0) 
@llvm.dx.resource.handlefromimplicitbinding.tdx.RawBuffer_f16_1_0t(i32 0, i32 
0, i32 1, i32 0, ptr nonnull @.str)
+; CHECK-NEXT:    [[ELSESTMTCALLRESOURCEGEP:%.*]] = tail call noundef nonnull 
align 2 dereferenceable(2) ptr 
@llvm.dx.resource.getpointer.p0.tdx.RawBuffer_f16_1_0t(target("dx.RawBuffer", 
half, 1, 0) [[CALL2NDRAWBUFFERBINDING]], i32 [[LOADGLOBAL]])
+; CHECK-NEXT:    br label %[[_Z6CSMAINV_EXIT]]
+; CHECK:       [[_Z6CSMAINV_EXIT]]:
+; CHECK-NEXT:    [[DOTSINK1:%.*]] = phi ptr [ [[IFSTMTCALLRESOURCEGEP]], 
%[[IF_THEN_I]] ], [ [[ELSESTMTCALLRESOURCEGEP]], %[[IF_ELSE_I]] ]
+; CHECK-NEXT:    [[LOADSINK:%.*]] = load half, ptr [[DOTSINK1]], align 2
+; CHECK-NEXT:    ret half [[LOADSINK]]
+;
+  %loadGlobal = load i32, ptr @CBV, align 4
+  %tobool.not.i = icmp eq i32 %loadGlobal, 0
+  br i1 %tobool.not.i, label %if.else.i, label %if.then.i
+
+  if.then.i:                                        ; preds = %entry
+  %ifStmtcallRawBufferBinding = tail call target("dx.RawBuffer", half, 1, 0) 
@llvm.dx.resource.handlefromimplicitbinding.tdx.RawBuffer_f16_1_0t(i32 1, i32 
0, i32 1, i32 0, ptr nonnull @.str)
+  %ifStmtCallResourceGEP = tail call noundef nonnull align 2 
dereferenceable(2) ptr 
@llvm.dx.resource.getpointer.p0.tdx.RawBuffer_f16_1_0t(target("dx.RawBuffer", 
half, 1, 0) %ifStmtcallRawBufferBinding, i32 %loadGlobal)
+  br label %_Z6CSMainv.exit
+
+  if.else.i:                                        ; preds = %entry
+  %call2ndRawBufferBinding = tail call target("dx.RawBuffer", half, 1, 0) 
@llvm.dx.resource.handlefromimplicitbinding.tdx.RawBuffer_f16_1_0t(i32 0, i32 
0, i32 1, i32 0, ptr nonnull @.str)
+  %elseStmtCallResourceGEP = tail call noundef nonnull align 2 
dereferenceable(2) ptr 
@llvm.dx.resource.getpointer.p0.tdx.RawBuffer_f16_1_0t(target("dx.RawBuffer", 
half, 1, 0) %call2ndRawBufferBinding, i32 %loadGlobal)
+  br label %_Z6CSMainv.exit
+
+  _Z6CSMainv.exit:                                  ; preds = %if.else.i, 
%if.then.i
+  %.sink1 = phi ptr [ %ifStmtCallResourceGEP, %if.then.i ], [ 
%elseStmtCallResourceGEP, %if.else.i ]
+  %loadSink = load half, ptr %.sink1, align 2
+  ret half %loadSink
+}
diff --git a/llvm/test/Verifier/tokenlike1-with-asserts.ll 
b/llvm/test/Verifier/tokenlike1-with-asserts.ll
new file mode 100644
index 0000000000000..19bdd805cfc91
--- /dev/null
+++ b/llvm/test/Verifier/tokenlike1-with-asserts.ll
@@ -0,0 +1,12 @@
+; REQUIRES: asserts
+; RUN: not --crash llvm-as %s -o /dev/null 2>&1 | FileCheck %s
+
+define void @f(target("dx.RawBuffer", half, 1, 0) %A, target("dx.RawBuffer", 
half, 1, 0) %B) {
+entry:
+  br label %bb
+
+bb:
+  %phi = phi target("dx.RawBuffer", half, 1, 0) [ %A, %bb ], [ %B, %entry]
+; CHECK: PHI nodes cannot have token type!
+  br label %bb
+}
diff --git a/llvm/test/Verifier/tokenlike1-without-asserts.ll 
b/llvm/test/Verifier/tokenlike1-without-asserts.ll
new file mode 100644
index 0000000000000..ef7ac00576251
--- /dev/null
+++ b/llvm/test/Verifier/tokenlike1-without-asserts.ll
@@ -0,0 +1,12 @@
+; REQUIRES: !asserts
+; RUN: not llvm-as %s -o /dev/null 2>&1 | FileCheck %s
+
+define void @f(target("dx.RawBuffer", half, 1, 0) %A, target("dx.RawBuffer", 
half, 1, 0) %B) {
+entry:
+  br label %bb
+
+bb:
+  %phi = phi target("dx.RawBuffer", half, 1, 0) [ %A, %bb ], [ %B, %entry]
+; CHECK: PHI nodes cannot have token type!
+  br label %bb
+}
diff --git a/llvm/test/Verifier/tokenlike5.ll b/llvm/test/Verifier/tokenlike5.ll
new file mode 100644
index 0000000000000..ea36f37b547ca
--- /dev/null
+++ b/llvm/test/Verifier/tokenlike5.ll
@@ -0,0 +1,7 @@
+; RUN: not llvm-as %s -o /dev/null 2>&1 | FileCheck %s
+
+define void @f(target("dx.RawBuffer", half, 1, 0) %A) {
+entry:
+  ret void
+}
+; CHECK: Function takes token but isn't an intrinsic
diff --git a/llvm/test/Verifier/tokenlike6.ll b/llvm/test/Verifier/tokenlike6.ll
new file mode 100644
index 0000000000000..3322b52b82c2c
--- /dev/null
+++ b/llvm/test/Verifier/tokenlike6.ll
@@ -0,0 +1,7 @@
+; RUN: not llvm-as %s -o /dev/null 2>&1 | FileCheck %s
+
+define target("dx.RawBuffer", half, 1, 0) @f() {
+entry:
+  ret target("dx.RawBuffer", half, 1, 0) undef
+}
+; CHECK: Function returns a token but isn't an intrinsic
diff --git a/llvm/test/Verifier/tokenlike7.ll b/llvm/test/Verifier/tokenlike7.ll
new file mode 100644
index 0000000000000..03cf68e44a206
--- /dev/null
+++ b/llvm/test/Verifier/tokenlike7.ll
@@ -0,0 +1,8 @@
+; RUN: not llvm-as %s -o /dev/null 2>&1 | FileCheck %s
+
+define void @f() {
+entry:
+  call target("dx.RawBuffer", half, 1, 0) () undef ()
+  ret void
+}
+; CHECK: Return type cannot be token for indirect call!

>From b520011f6654b5297b99b9ce2f9c450c6da04816 Mon Sep 17 00:00:00 2001
From: Farzon Lotfi <farzonlo...@microsoft.com>
Date: Thu, 28 Aug 2025 17:26:49 -0400
Subject: [PATCH 13/14] remove undef

---
 llvm/test/Verifier/tokenlike6.ll | 2 +-
 llvm/test/Verifier/tokenlike7.ll | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/llvm/test/Verifier/tokenlike6.ll b/llvm/test/Verifier/tokenlike6.ll
index 3322b52b82c2c..f24a9427eb8cb 100644
--- a/llvm/test/Verifier/tokenlike6.ll
+++ b/llvm/test/Verifier/tokenlike6.ll
@@ -2,6 +2,6 @@
 
 define target("dx.RawBuffer", half, 1, 0) @f() {
 entry:
-  ret target("dx.RawBuffer", half, 1, 0) undef
+  ret target("dx.RawBuffer", half, 1, 0) poison
 }
 ; CHECK: Function returns a token but isn't an intrinsic
diff --git a/llvm/test/Verifier/tokenlike7.ll b/llvm/test/Verifier/tokenlike7.ll
index 03cf68e44a206..c7454937bb7ef 100644
--- a/llvm/test/Verifier/tokenlike7.ll
+++ b/llvm/test/Verifier/tokenlike7.ll
@@ -2,7 +2,7 @@
 
 define void @f() {
 entry:
-  call target("dx.RawBuffer", half, 1, 0) () undef ()
+  call target("dx.RawBuffer", half, 1, 0) () poison ()
   ret void
 }
 ; CHECK: Return type cannot be token for indirect call!

>From 1546848844c5e5bc4a2dc041a1a85c6001ec9a03 Mon Sep 17 00:00:00 2001
From: Farzon Lotfi <farzonlo...@microsoft.com>
Date: Fri, 29 Aug 2025 09:34:00 -0400
Subject: [PATCH 14/14] fix test to comply with the new token like verifier
 changes

---
 .../CodeGenHLSL/builtins/hlsl_resource_t.hlsl | 21 ++++++++++++-------
 llvm/test/Verifier/tokenlike1-with-asserts.ll | 12 -----------
 2 files changed, 13 insertions(+), 20 deletions(-)
 delete mode 100644 llvm/test/Verifier/tokenlike1-with-asserts.ll

diff --git a/clang/test/CodeGenHLSL/builtins/hlsl_resource_t.hlsl 
b/clang/test/CodeGenHLSL/builtins/hlsl_resource_t.hlsl
index 24114b11c7602..75d9fb8582b3d 100644
--- a/clang/test/CodeGenHLSL/builtins/hlsl_resource_t.hlsl
+++ b/clang/test/CodeGenHLSL/builtins/hlsl_resource_t.hlsl
@@ -2,23 +2,28 @@
 
 using handle_float_t = __hlsl_resource_t [[hlsl::resource_class(UAV)]] 
[[hlsl::contained_type(float)]];
 
+struct CustomResource {
+  handle_float_t h;
+};
+
+// CHECK: %struct.CustomResource = type { target("dx.TypedBuffer", float, 1, 
0, 0) }
 // CHECK: %"class.hlsl::RWBuffer" = type { target("dx.TypedBuffer", <4 x 
float>, 1, 0, 0)
 // CHECK: %"class.hlsl::StructuredBuffer" = type { target("dx.RawBuffer", 
%struct.MyStruct, 0, 0)
 // CHECK: %struct.MyStruct = type <{ <4 x float>, <2 x i32> }>
 
-// CHECK: define hidden void 
@_Z2faU9_Res_u_CTfu17__hlsl_resource_t(target("dx.TypedBuffer", float, 1, 0, 0) 
%a)
-// CHECK: call void 
@_Z4foo1U9_Res_u_CTfu17__hlsl_resource_t(target("dx.TypedBuffer", float, 1, 0, 
0) %0)
-// CHECK: declare hidden void 
@_Z4foo1U9_Res_u_CTfu17__hlsl_resource_t(target("dx.TypedBuffer", float, 1, 0, 
0))
+// CHECK: define hidden void @_Z2fa14CustomResource(ptr noundef 
byval(%struct.CustomResource) align 1 %a)
+// CHECK: call void @_Z4foo114CustomResource(ptr noundef 
byval(%struct.CustomResource) align 1 %agg.tmp)
+// CHECK: declare hidden void @_Z4foo114CustomResource(ptr noundef 
byval(%struct.CustomResource) align 1)
 
-void foo1(handle_float_t res);
+void foo1(CustomResource res);
 
-void fa(handle_float_t a) {
+void fa(CustomResource a) {
     foo1(a);
 }
 
-// CHECK: define hidden void 
@_Z2fbU9_Res_u_CTfu17__hlsl_resource_t(target("dx.TypedBuffer", float, 1, 0, 0) 
%a)
-void fb(handle_float_t a) {
-    handle_float_t b = a;
+// CHECK: define hidden void @_Z2fb14CustomResource(ptr noundef 
byval(%struct.CustomResource) align 1 %a)
+void fb(CustomResource a) {
+    CustomResource b = a;
 }
 
 // CHECK: define hidden void @_Z2fcN4hlsl8RWBufferIDv4_fEE(ptr noundef 
byval(%"class.hlsl::RWBuffer") align 4 %a)
diff --git a/llvm/test/Verifier/tokenlike1-with-asserts.ll 
b/llvm/test/Verifier/tokenlike1-with-asserts.ll
deleted file mode 100644
index 19bdd805cfc91..0000000000000
--- a/llvm/test/Verifier/tokenlike1-with-asserts.ll
+++ /dev/null
@@ -1,12 +0,0 @@
-; REQUIRES: asserts
-; RUN: not --crash llvm-as %s -o /dev/null 2>&1 | FileCheck %s
-
-define void @f(target("dx.RawBuffer", half, 1, 0) %A, target("dx.RawBuffer", 
half, 1, 0) %B) {
-entry:
-  br label %bb
-
-bb:
-  %phi = phi target("dx.RawBuffer", half, 1, 0) [ %A, %bb ], [ %B, %entry]
-; CHECK: PHI nodes cannot have token type!
-  br label %bb
-}

_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to