[llvm] [DirectX] Cast the pointer for atomics whose value type differs (PR #226563)

Joshua Batista via llvm-commits llvm-commits at lists.llvm.org
Wed Sep 30 16:50:37 PDT 2026


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

>From fca6e981802ba138d820d16709d6acc99142142e Mon Sep 17 00:00:00 2001
From: Joshua Batista <jbatista at microsoft.com>
Date: Fri, 25 Sep 2026 11:27:59 -0700
Subject: [PATCH 1/2] first attempt

---
 llvm/lib/Target/DirectX/DXILPrepare.cpp       | 19 +++++++++++++++++++
 .../DirectXIRPasses/PointerTypeAnalysis.cpp   |  4 ++++
 llvm/test/tools/dxil-dis/atomicrmw.ll         | 19 +++++++++++++++++--
 3 files changed, 40 insertions(+), 2 deletions(-)

diff --git a/llvm/lib/Target/DirectX/DXILPrepare.cpp b/llvm/lib/Target/DirectX/DXILPrepare.cpp
index 23bc42e549dee..c73c4658478ac 100644
--- a/llvm/lib/Target/DirectX/DXILPrepare.cpp
+++ b/llvm/lib/Target/DirectX/DXILPrepare.cpp
@@ -190,6 +190,25 @@ class DXILPrepareModule : public ModulePass {
               GEP->setOperand(0, NoOpBitcast);
             continue;
           }
+          // An atomic on a float allocation exchanges the bit pattern as an
+          // integer, so the pointer element type does not match the value
+          // type. Typed pointers need a cast to keep the two in agreement.
+          if (auto *RMW = dyn_cast<AtomicRMWInst>(&I)) {
+            if (Value *NoOpBitcast = maybeGenerateBitcast(
+                    Builder, PointerTypes, I, RMW->getPointerOperand(),
+                    RMW->getValOperand()->getType()))
+              RMW->setOperand(AtomicRMWInst::getPointerOperandIndex(),
+                              NoOpBitcast);
+            continue;
+          }
+          if (auto *CmpXchg = dyn_cast<AtomicCmpXchgInst>(&I)) {
+            if (Value *NoOpBitcast = maybeGenerateBitcast(
+                    Builder, PointerTypes, I, CmpXchg->getPointerOperand(),
+                    CmpXchg->getNewValOperand()->getType()))
+              CmpXchg->setOperand(AtomicCmpXchgInst::getPointerOperandIndex(),
+                                  NoOpBitcast);
+            continue;
+          }
         }
       }
     }
diff --git a/llvm/lib/Target/DirectX/DirectXIRPasses/PointerTypeAnalysis.cpp b/llvm/lib/Target/DirectX/DirectXIRPasses/PointerTypeAnalysis.cpp
index c58af1560a6b7..5da22aaea3b82 100644
--- a/llvm/lib/Target/DirectX/DirectXIRPasses/PointerTypeAnalysis.cpp
+++ b/llvm/lib/Target/DirectX/DirectXIRPasses/PointerTypeAnalysis.cpp
@@ -63,6 +63,10 @@ Type *classifyPointerType(const Value *V, PointerTypeMap &Map) {
       // When store value is ptr type, cannot get more type info.
       if (NewPointeeTy->isPointerTy())
         continue;
+    } else if (const auto *Inst = dyn_cast<AtomicRMWInst>(User)) {
+      NewPointeeTy = Inst->getValOperand()->getType();
+    } else if (const auto *Inst = dyn_cast<AtomicCmpXchgInst>(User)) {
+      NewPointeeTy = Inst->getNewValOperand()->getType();
     } else if (const auto *GEP = dyn_cast<GEPOperator>(User)) {
       NewPointeeTy = GEP->getSourceElementType();
     }
diff --git a/llvm/test/tools/dxil-dis/atomicrmw.ll b/llvm/test/tools/dxil-dis/atomicrmw.ll
index d8edc4c68aa6c..9c49d9943d617 100644
--- a/llvm/test/tools/dxil-dis/atomicrmw.ll
+++ b/llvm/test/tools/dxil-dis/atomicrmw.ll
@@ -1,17 +1,32 @@
 ; RUN: llc --filetype=obj %s --stop-after=dxil-write-bitcode -o %t.bc
 ; RUN: dxil-dis %t.bc -o - | FileCheck %s
 
-; Verify that the DXIL reader supports the atomicrmw record.
+; Verify that the DXIL reader supports the atomicrmw and the cmpxchg records.
+; A float allocation needs a pointer cast, because the atomic value is an
+; integer and a DXIL pointer carries the element type.
 
 target triple = "dxil-pc-shadermodel6.0-compute"
 
 @gsm = internal addrspace(3) global i32 zeroinitializer, align 4
+ at gsm_float = internal addrspace(3) global float zeroinitializer, align 4
+ at gsm_float_arr = internal addrspace(3) global [4 x float] zeroinitializer, align 4
 
 ; CHECK-LABEL: define void @main()
-; CHECK: atomicrmw add i32 addrspace(3)* @gsm, i32 1 monotonic
+; An integer allocation already agrees with the value, so it gets no cast.
+; CHECK-NEXT: atomicrmw add i32 addrspace(3)* @gsm, i32 1 monotonic
+; CHECK-NEXT: [[P0:%.*]] = bitcast float addrspace(3)* @gsm_float to i32 addrspace(3)*
+; CHECK-NEXT: atomicrmw xchg i32 addrspace(3)* [[P0]], i32 2 monotonic
+; CHECK-NEXT: [[P1:%.*]] = bitcast float addrspace(3)* getelementptr {{.*}}@gsm_float_arr{{.*}} to i32 addrspace(3)*
+; CHECK-NEXT: atomicrmw xchg i32 addrspace(3)* [[P1]], i32 3 monotonic
+; CHECK-NEXT: [[P2:%.*]] = bitcast float addrspace(3)* @gsm_float to i32 addrspace(3)*
+; CHECK-NEXT: cmpxchg i32 addrspace(3)* [[P2]], i32 4, i32 5 monotonic monotonic
 
 define void @main() #0 {
   %old = atomicrmw add ptr addrspace(3) @gsm, i32 1 monotonic
+  %f = atomicrmw xchg ptr addrspace(3) @gsm_float, i32 2 monotonic
+  %gep = getelementptr [4 x float], ptr addrspace(3) @gsm_float_arr, i32 0, i32 1
+  %g = atomicrmw xchg ptr addrspace(3) %gep, i32 3 monotonic
+  %c = cmpxchg ptr addrspace(3) @gsm_float, i32 4, i32 5 monotonic monotonic
   ret void
 }
 

>From 223b51b6496b5252301fe74e61947d6f342407b6 Mon Sep 17 00:00:00 2001
From: Joshua Batista <jbatista at microsoft.com>
Date: Wed, 30 Sep 2026 16:50:20 -0700
Subject: [PATCH 2/2] address Finn

---
 llvm/test/tools/dxil-dis/atomicrmw.ll | 10 +++++++---
 1 file changed, 7 insertions(+), 3 deletions(-)

diff --git a/llvm/test/tools/dxil-dis/atomicrmw.ll b/llvm/test/tools/dxil-dis/atomicrmw.ll
index 9c49d9943d617..783356b25299f 100644
--- a/llvm/test/tools/dxil-dis/atomicrmw.ll
+++ b/llvm/test/tools/dxil-dis/atomicrmw.ll
@@ -8,23 +8,27 @@
 target triple = "dxil-pc-shadermodel6.0-compute"
 
 @gsm = internal addrspace(3) global i32 zeroinitializer, align 4
+ at gsm_arr = internal addrspace(3) global [4 x i32] zeroinitializer, align 4
 @gsm_float = internal addrspace(3) global float zeroinitializer, align 4
- at gsm_float_arr = internal addrspace(3) global [4 x float] zeroinitializer, align 4
+ at gsm_farr = internal addrspace(3) global [4 x float] zeroinitializer, align 4
 
 ; CHECK-LABEL: define void @main()
 ; An integer allocation already agrees with the value, so it gets no cast.
 ; CHECK-NEXT: atomicrmw add i32 addrspace(3)* @gsm, i32 1 monotonic
+; CHECK-NEXT: atomicrmw add i32 addrspace(3)* getelementptr {{.*}}@gsm_arr{{.*}}, i32 6 monotonic
 ; CHECK-NEXT: [[P0:%.*]] = bitcast float addrspace(3)* @gsm_float to i32 addrspace(3)*
 ; CHECK-NEXT: atomicrmw xchg i32 addrspace(3)* [[P0]], i32 2 monotonic
-; CHECK-NEXT: [[P1:%.*]] = bitcast float addrspace(3)* getelementptr {{.*}}@gsm_float_arr{{.*}} to i32 addrspace(3)*
+; CHECK-NEXT: [[P1:%.*]] = bitcast float addrspace(3)* getelementptr {{.*}}@gsm_farr{{.*}} to i32 addrspace(3)*
 ; CHECK-NEXT: atomicrmw xchg i32 addrspace(3)* [[P1]], i32 3 monotonic
 ; CHECK-NEXT: [[P2:%.*]] = bitcast float addrspace(3)* @gsm_float to i32 addrspace(3)*
 ; CHECK-NEXT: cmpxchg i32 addrspace(3)* [[P2]], i32 4, i32 5 monotonic monotonic
 
 define void @main() #0 {
   %old = atomicrmw add ptr addrspace(3) @gsm, i32 1 monotonic
+  %int_gep = getelementptr [4 x i32], ptr addrspace(3) @gsm_arr, i32 0, i32 1
+  %arr = atomicrmw add ptr addrspace(3) %int_gep, i32 6 monotonic
   %f = atomicrmw xchg ptr addrspace(3) @gsm_float, i32 2 monotonic
-  %gep = getelementptr [4 x float], ptr addrspace(3) @gsm_float_arr, i32 0, i32 1
+  %gep = getelementptr [4 x float], ptr addrspace(3) @gsm_farr, i32 0, i32 1
   %g = atomicrmw xchg ptr addrspace(3) %gep, i32 3 monotonic
   %c = cmpxchg ptr addrspace(3) @gsm_float, i32 4, i32 5 monotonic monotonic
   ret void



More information about the llvm-commits mailing list