[llvm] [InferAddressSpaces] Infer pointer stored and then loaded from global variable (PR #159755)

Wenju He via llvm-commits llvm-commits at lists.llvm.org
Mon Sep 22 01:47:43 PDT 2025


https://github.com/wenju-he updated https://github.com/llvm/llvm-project/pull/159755

>From 349dbc623cf7c490e969289b716fb94b60f71e79 Mon Sep 17 00:00:00 2001
From: Wenju He <wenju.he at intel.com>
Date: Fri, 19 Sep 2025 12:42:34 +0200
Subject: [PATCH 1/4] [InferAddressSpaces] Infer pointer stored and then loaded
 from global variable

Load of a global variable producing a (generic) pointer is treated as an
address expression if every user of the global are local loads or stores
in the same function, with the store actually writing to the global.

The load's pointer AS is inferred from the stored pointer operands.

The test is reduced from `SYCL-CTS/test_hierarchical hierarchical_implicit_barriers`.
---
 .../Transforms/Scalar/InferAddressSpaces.cpp  | 52 +++++++++++++++++--
 .../AMDGPU/gv-store-load.ll                   | 51 ++++++++++++++++++
 2 files changed, 100 insertions(+), 3 deletions(-)
 create mode 100644 llvm/test/Transforms/InferAddressSpaces/AMDGPU/gv-store-load.ll

diff --git a/llvm/lib/Transforms/Scalar/InferAddressSpaces.cpp b/llvm/lib/Transforms/Scalar/InferAddressSpaces.cpp
index 3ad87545953ff..179820bf3eb3e 100644
--- a/llvm/lib/Transforms/Scalar/InferAddressSpaces.cpp
+++ b/llvm/lib/Transforms/Scalar/InferAddressSpaces.cpp
@@ -304,10 +304,24 @@ static bool isNoopPtrIntCastPair(const Operator *I2P, const DataLayout &DL,
          (P2IOp0AS == I2PAS || TTI->isNoopAddrSpaceCast(P2IOp0AS, I2PAS));
 }
 
+// Returns true if every user of a given GV are "simple" loads or stores in the
+// same function, with the store actually writing to GV.
+static bool isLocallyAccessedBySimpleLoadsStores(const GlobalVariable *GV,
+                                                 const Function *F) {
+  return all_of(GV->users(), [=](const User *U) {
+    if (const auto *SI = dyn_cast<StoreInst>(U))
+      return SI->getPointerOperand() == GV && SI->getFunction() == F;
+    if (const auto *LI = dyn_cast<LoadInst>(U))
+      return LI->getFunction() == F;
+    return false;
+  });
+}
+
 // Returns true if V is an address expression.
 // TODO: Currently, we only consider:
 //   - arguments
 //   - phi, bitcast, addrspacecast, and getelementptr operators
+//   - load
 static bool isAddressExpression(const Value &V, const DataLayout &DL,
                                 const TargetTransformInfo *TTI) {
 
@@ -335,6 +349,16 @@ static bool isAddressExpression(const Value &V, const DataLayout &DL,
   }
   case Instruction::IntToPtr:
     return isNoopPtrIntCastPair(Op, DL, TTI);
+  case Instruction::Load: {
+    const auto *LI = cast<LoadInst>(Op);
+    if (LI->getType()->isPtrOrPtrVectorTy()) {
+      // Heuristic: treat load-of-GV as an address expression only if the GV is
+      // locally accessed by load and store.
+      if (const auto *GV = dyn_cast<GlobalVariable>(LI->getPointerOperand()))
+        return isLocallyAccessedBySimpleLoadsStores(GV, LI->getFunction());
+    }
+    return TTI->getAssumedAddrSpace(&V) != UninitializedAddressSpace;
+  }
   default:
     // That value is an address expression if it has an assumed address space.
     return TTI->getAssumedAddrSpace(&V) != UninitializedAddressSpace;
@@ -342,6 +366,8 @@ static bool isAddressExpression(const Value &V, const DataLayout &DL,
 }
 
 // Returns the pointer operands of V.
+// If V is a load from a global variable G, also collect the pointer values
+// stored into G.
 //
 // Precondition: V is an address expression.
 static SmallVector<Value *, 2>
@@ -373,6 +399,20 @@ getPointerOperands(const Value &V, const DataLayout &DL,
     auto *P2I = cast<Operator>(Op.getOperand(0));
     return {P2I->getOperand(0)};
   }
+  case Instruction::Load: {
+    assert(V.getType()->isPtrOrPtrVectorTy());
+    if (const auto *GV = cast<GlobalVariable>(Op.getOperand(0))) {
+      assert(isLocallyAccessedBySimpleLoadsStores(
+          GV, cast<LoadInst>(&V)->getFunction()));
+      SmallVector<Value *, 2> PtrOps;
+      for (const auto *U : GV->users())
+        if (const auto *SI = dyn_cast<StoreInst>(U);
+            SI && SI->getPointerOperand() == GV)
+          PtrOps.push_back(cast<Operator>(U)->getOperand(0));
+      return PtrOps;
+    }
+    return {};
+  }
   default:
     llvm_unreachable("Unexpected instruction type.");
   }
@@ -561,9 +601,11 @@ InferAddressSpacesImpl::collectFlatAddressExpressions(Function &F) const {
       PushPtrOperand(GEP->getPointerOperand());
     } else if (auto *LI = dyn_cast<LoadInst>(&I))
       PushPtrOperand(LI->getPointerOperand());
-    else if (auto *SI = dyn_cast<StoreInst>(&I))
+    else if (auto *SI = dyn_cast<StoreInst>(&I)) {
+      if (SI->getValueOperand()->getType()->isPtrOrPtrVectorTy())
+        PushPtrOperand(SI->getValueOperand());
       PushPtrOperand(SI->getPointerOperand());
-    else if (auto *RMW = dyn_cast<AtomicRMWInst>(&I))
+    } else if (auto *RMW = dyn_cast<AtomicRMWInst>(&I))
       PushPtrOperand(RMW->getPointerOperand());
     else if (auto *CmpX = dyn_cast<AtomicCmpXchgInst>(&I))
       PushPtrOperand(CmpX->getPointerOperand());
@@ -755,6 +797,10 @@ Value *InferAddressSpacesImpl::cloneInstructionWithNewAddressSpace(
     // back.
     return new AddrSpaceCastInst(Src, NewPtrType);
   }
+  case Instruction::Load:
+    if (I->getType()->isPtrOrPtrVectorTy())
+      return new AddrSpaceCastInst(I, NewPtrType);
+    return nullptr;
   default:
     llvm_unreachable("Unexpected opcode");
   }
@@ -866,7 +912,7 @@ Value *InferAddressSpacesImpl::cloneValueWithNewAddressSpace(
         I, NewAddrSpace, ValueWithNewAddrSpace, PredicatedAS, PoisonUsesToFix);
     if (Instruction *NewI = dyn_cast_or_null<Instruction>(NewV)) {
       if (NewI->getParent() == nullptr) {
-        NewI->insertBefore(I->getIterator());
+        NewI->insertAfter(I->getIterator());
         NewI->takeName(I);
         NewI->setDebugLoc(I->getDebugLoc());
       }
diff --git a/llvm/test/Transforms/InferAddressSpaces/AMDGPU/gv-store-load.ll b/llvm/test/Transforms/InferAddressSpaces/AMDGPU/gv-store-load.ll
new file mode 100644
index 0000000000000..8c3274758b929
--- /dev/null
+++ b/llvm/test/Transforms/InferAddressSpaces/AMDGPU/gv-store-load.ll
@@ -0,0 +1,51 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
+; RUN: opt -S -mtriple=amdgcn-amd-amdhsa -passes=infer-address-spaces %s | FileCheck %s
+
+ at WGCopy = internal unnamed_addr addrspace(3) global ptr poison, align 16
+
+; Function Attrs: nounwind
+define void @gv_store_load() {
+; CHECK-LABEL: define void @gv_store_load() {
+; CHECK-NEXT:  [[ENTRY:.*]]:
+; CHECK-NEXT:    [[AGG_TMP1617:%.*]] = alloca i64, align 8, addrspace(5)
+; CHECK-NEXT:    [[IS:%.*]] = call i1 @is_leader()
+; CHECK-NEXT:    br i1 [[IS]], label %[[LEADER:.*]], label %[[MERGE:.*]]
+; CHECK:       [[LEADER]]:
+; CHECK-NEXT:    br label %[[MERGE]]
+; CHECK:       [[MERGE]]:
+; CHECK-NEXT:    [[AGG_TMP_I_SROA_0_0:%.*]] = phi ptr addrspace(5) [ [[AGG_TMP1617]], %[[LEADER]] ], [ undef, %[[ENTRY]] ]
+; CHECK-NEXT:    [[TMP0:%.*]] = addrspacecast ptr addrspace(5) [[AGG_TMP_I_SROA_0_0]] to ptr
+; CHECK-NEXT:    br i1 [[IS]], label %[[LEADER_I:.*]], label %[[EXIT:.*]]
+; CHECK:       [[LEADER_I]]:
+; CHECK-NEXT:    store ptr [[TMP0]], ptr addrspace(3) @WGCopy, align 16
+; CHECK-NEXT:    br label %[[EXIT]]
+; CHECK:       [[EXIT]]:
+; CHECK-NEXT:    [[TMP1:%.*]] = load ptr, ptr addrspace(3) @WGCopy, align 16
+; CHECK-NEXT:    [[AGG_TMP_I_SROA_0_0_COPYLOAD:%.*]] = addrspacecast ptr [[TMP1]] to ptr addrspace(5)
+; CHECK-NEXT:    [[TMP2:%.*]] = load i64, ptr addrspace(5) [[AGG_TMP_I_SROA_0_0_COPYLOAD]], align 8
+; CHECK-NEXT:    ret void
+;
+entry:
+  %agg.tmp1617 = alloca i64, align 8, addrspace(5)
+  %is = call i1 @is_leader()
+  br i1 %is, label %leader, label %merge
+
+leader:                                      ; preds = %entry
+  %group.ascast.i = addrspacecast ptr addrspace(5) %agg.tmp1617 to ptr
+  br label %merge
+
+merge:                                          ; preds = %leader, %entry
+  %agg.tmp.i.sroa.0.0 = phi ptr [ %group.ascast.i, %leader ], [ undef, %entry ]
+  br i1 %is, label %leader.i, label %exit
+
+leader.i:                                        ; preds = %merge
+  store ptr %agg.tmp.i.sroa.0.0, ptr addrspace(3) @WGCopy, align 16
+  br label %exit
+
+exit: ; preds = %leader.i, %merge
+  %agg.tmp.i.sroa.0.0.copyload = load ptr, ptr addrspace(3) @WGCopy, align 16
+  %15 = load i64, ptr %agg.tmp.i.sroa.0.0.copyload, align 8
+  ret void
+}
+
+declare i1 @is_leader()

>From 4d2ad490a531b5a5714ad3d1d6fa24e579ed2310 Mon Sep 17 00:00:00 2001
From: Wenju He <wenju.he at intel.com>
Date: Fri, 19 Sep 2025 12:56:30 +0200
Subject: [PATCH 2/4] update per copilot review

---
 llvm/lib/Transforms/Scalar/InferAddressSpaces.cpp | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/llvm/lib/Transforms/Scalar/InferAddressSpaces.cpp b/llvm/lib/Transforms/Scalar/InferAddressSpaces.cpp
index 179820bf3eb3e..f2d63fa9ffa82 100644
--- a/llvm/lib/Transforms/Scalar/InferAddressSpaces.cpp
+++ b/llvm/lib/Transforms/Scalar/InferAddressSpaces.cpp
@@ -406,8 +406,7 @@ getPointerOperands(const Value &V, const DataLayout &DL,
           GV, cast<LoadInst>(&V)->getFunction()));
       SmallVector<Value *, 2> PtrOps;
       for (const auto *U : GV->users())
-        if (const auto *SI = dyn_cast<StoreInst>(U);
-            SI && SI->getPointerOperand() == GV)
+        if (isa<StoreInst>(U))
           PtrOps.push_back(cast<Operator>(U)->getOperand(0));
       return PtrOps;
     }

>From f689f415a1c451604a2594003cb0b0f46b222f94 Mon Sep 17 00:00:00 2001
From: Wenju He <wenju.he at intel.com>
Date: Mon, 22 Sep 2025 10:43:22 +0200
Subject: [PATCH 3/4] add vector test and negative tests, update
 PtrOps.push_back

---
 .../Transforms/Scalar/InferAddressSpaces.cpp  |   4 +-
 .../AMDGPU/gv-store-load.ll                   | 168 ++++++++++++++++--
 2 files changed, 151 insertions(+), 21 deletions(-)

diff --git a/llvm/lib/Transforms/Scalar/InferAddressSpaces.cpp b/llvm/lib/Transforms/Scalar/InferAddressSpaces.cpp
index f2d63fa9ffa82..25b31684ceaa2 100644
--- a/llvm/lib/Transforms/Scalar/InferAddressSpaces.cpp
+++ b/llvm/lib/Transforms/Scalar/InferAddressSpaces.cpp
@@ -406,8 +406,8 @@ getPointerOperands(const Value &V, const DataLayout &DL,
           GV, cast<LoadInst>(&V)->getFunction()));
       SmallVector<Value *, 2> PtrOps;
       for (const auto *U : GV->users())
-        if (isa<StoreInst>(U))
-          PtrOps.push_back(cast<Operator>(U)->getOperand(0));
+        if (auto *SI = dyn_cast<StoreInst>(U))
+          PtrOps.push_back(const_cast<Value *>(SI->getValueOperand()));
       return PtrOps;
     }
     return {};
diff --git a/llvm/test/Transforms/InferAddressSpaces/AMDGPU/gv-store-load.ll b/llvm/test/Transforms/InferAddressSpaces/AMDGPU/gv-store-load.ll
index 8c3274758b929..a3bcc2d7c63fb 100644
--- a/llvm/test/Transforms/InferAddressSpaces/AMDGPU/gv-store-load.ll
+++ b/llvm/test/Transforms/InferAddressSpaces/AMDGPU/gv-store-load.ll
@@ -1,51 +1,181 @@
 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
 ; RUN: opt -S -mtriple=amdgcn-amd-amdhsa -passes=infer-address-spaces %s | FileCheck %s
 
- at WGCopy = internal unnamed_addr addrspace(3) global ptr poison, align 16
+ at WGCopy = internal addrspace(3) global ptr poison, align 8
+ at WGCopy1 = internal addrspace(3) global ptr poison, align 8
+ at WGCopy2 = internal addrspace(3) global ptr poison, align 8
+ at WGCopy3 = internal addrspace(3) global ptr poison, align 8
+ at WGCopy4 = internal addrspace(3) global ptr poison, align 8
+ at WGCopyVec = internal addrspace(3) global <2 x ptr> poison, align 16
 
-; Function Attrs: nounwind
+; load ptr AS is inferred.
 define void @gv_store_load() {
 ; CHECK-LABEL: define void @gv_store_load() {
 ; CHECK-NEXT:  [[ENTRY:.*]]:
-; CHECK-NEXT:    [[AGG_TMP1617:%.*]] = alloca i64, align 8, addrspace(5)
+; CHECK-NEXT:    [[AGG:%.*]] = alloca i64, align 8, addrspace(5)
 ; CHECK-NEXT:    [[IS:%.*]] = call i1 @is_leader()
 ; CHECK-NEXT:    br i1 [[IS]], label %[[LEADER:.*]], label %[[MERGE:.*]]
 ; CHECK:       [[LEADER]]:
 ; CHECK-NEXT:    br label %[[MERGE]]
 ; CHECK:       [[MERGE]]:
-; CHECK-NEXT:    [[AGG_TMP_I_SROA_0_0:%.*]] = phi ptr addrspace(5) [ [[AGG_TMP1617]], %[[LEADER]] ], [ undef, %[[ENTRY]] ]
-; CHECK-NEXT:    [[TMP0:%.*]] = addrspacecast ptr addrspace(5) [[AGG_TMP_I_SROA_0_0]] to ptr
+; CHECK-NEXT:    [[AGG_SROA:%.*]] = phi ptr addrspace(5) [ [[AGG]], %[[LEADER]] ], [ poison, %[[ENTRY]] ]
+; CHECK-NEXT:    [[TMP0:%.*]] = addrspacecast ptr addrspace(5) [[AGG_SROA]] to ptr
 ; CHECK-NEXT:    br i1 [[IS]], label %[[LEADER_I:.*]], label %[[EXIT:.*]]
 ; CHECK:       [[LEADER_I]]:
-; CHECK-NEXT:    store ptr [[TMP0]], ptr addrspace(3) @WGCopy, align 16
+; CHECK-NEXT:    store ptr [[TMP0]], ptr addrspace(3) @WGCopy, align 8
 ; CHECK-NEXT:    br label %[[EXIT]]
 ; CHECK:       [[EXIT]]:
-; CHECK-NEXT:    [[TMP1:%.*]] = load ptr, ptr addrspace(3) @WGCopy, align 16
-; CHECK-NEXT:    [[AGG_TMP_I_SROA_0_0_COPYLOAD:%.*]] = addrspacecast ptr [[TMP1]] to ptr addrspace(5)
-; CHECK-NEXT:    [[TMP2:%.*]] = load i64, ptr addrspace(5) [[AGG_TMP_I_SROA_0_0_COPYLOAD]], align 8
+; CHECK-NEXT:    [[TMP1:%.*]] = load ptr, ptr addrspace(3) @WGCopy, align 8
+; CHECK-NEXT:    [[AGG_SROA_COPYLOAD:%.*]] = addrspacecast ptr [[TMP1]] to ptr addrspace(5)
+; CHECK-NEXT:    [[TMP2:%.*]] = load i64, ptr addrspace(5) [[AGG_SROA_COPYLOAD]], align 8
 ; CHECK-NEXT:    ret void
 ;
 entry:
-  %agg.tmp1617 = alloca i64, align 8, addrspace(5)
+  %agg = alloca i64, align 8, addrspace(5)
   %is = call i1 @is_leader()
   br i1 %is, label %leader, label %merge
 
-leader:                                      ; preds = %entry
-  %group.ascast.i = addrspacecast ptr addrspace(5) %agg.tmp1617 to ptr
+leader:                                           ; preds = %entry
+  %group.ascast = addrspacecast ptr addrspace(5) %agg to ptr
   br label %merge
 
-merge:                                          ; preds = %leader, %entry
-  %agg.tmp.i.sroa.0.0 = phi ptr [ %group.ascast.i, %leader ], [ undef, %entry ]
+merge:                                            ; preds = %leader, %entry
+  %agg.sroa = phi ptr [ %group.ascast, %leader ], [ poison, %entry ]
   br i1 %is, label %leader.i, label %exit
 
-leader.i:                                        ; preds = %merge
-  store ptr %agg.tmp.i.sroa.0.0, ptr addrspace(3) @WGCopy, align 16
+leader.i:                                         ; preds = %merge
+  store ptr %agg.sroa, ptr addrspace(3) @WGCopy, align 8
   br label %exit
 
-exit: ; preds = %leader.i, %merge
-  %agg.tmp.i.sroa.0.0.copyload = load ptr, ptr addrspace(3) @WGCopy, align 16
-  %15 = load i64, ptr %agg.tmp.i.sroa.0.0.copyload, align 8
+exit:                                             ; preds = %leader.i, %merge
+  %agg.sroa.copyload = load ptr, ptr addrspace(3) @WGCopy, align 8
+  %val = load i64, ptr %agg.sroa.copyload, align 8
   ret void
 }
 
 declare i1 @is_leader()
+
+; vector load ptr AS is inferred.
+define void @gv_store_load_vec(<2 x ptr addrspace(5)> %private.ptr) {
+; CHECK-LABEL: define void @gv_store_load_vec(
+; CHECK-SAME: <2 x ptr addrspace(5)> [[PRIVATE_PTR:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[GROUP_ASCAST:%.*]] = addrspacecast <2 x ptr addrspace(5)> [[PRIVATE_PTR]] to <2 x ptr>
+; CHECK-NEXT:    store <2 x ptr> [[GROUP_ASCAST]], ptr addrspace(3) @WGCopyVec, align 16
+; CHECK-NEXT:    [[TMP0:%.*]] = load <2 x ptr>, ptr addrspace(3) @WGCopyVec, align 16
+; CHECK-NEXT:    [[AGG_SROA_COPYLOAD:%.*]] = addrspacecast <2 x ptr> [[TMP0]] to <2 x ptr addrspace(5)>
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq <2 x ptr addrspace(5)> [[AGG_SROA_COPYLOAD]], <ptr addrspace(5) addrspacecast (ptr null to ptr addrspace(5)), ptr addrspace(5) addrspacecast (ptr null to ptr addrspace(5))>
+; CHECK-NEXT:    ret void
+;
+entry:
+  %group.ascast = addrspacecast <2 x ptr addrspace(5)> %private.ptr to <2 x ptr>
+  store <2 x ptr> %group.ascast, ptr addrspace(3) @WGCopyVec, align 16
+  %agg.sroa.copyload = load <2 x ptr>, ptr addrspace(3) @WGCopyVec, align 16
+  %cmp = icmp eq <2 x ptr> %agg.sroa.copyload, zeroinitializer
+  ret void
+}
+
+; load ptr AS is not inferred since GV has a user that is not load or store.
+define void @negative_test_gv_user_not_load_store(ptr addrspace(5) %agg) {
+; CHECK-LABEL: define void @negative_test_gv_user_not_load_store(
+; CHECK-SAME: ptr addrspace(5) [[AGG:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[GROUP_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[AGG]] to ptr
+; CHECK-NEXT:    store ptr [[GROUP_ASCAST]], ptr addrspace(3) @WGCopy1, align 8
+; CHECK-NEXT:    [[AGG_COPYLOAD:%.*]] = load ptr, ptr addrspace(3) @WGCopy1, align 8
+; CHECK-NEXT:    [[VAL:%.*]] = load i64, ptr [[AGG_COPYLOAD]], align 8
+; CHECK-NEXT:    [[GV_ASC:%.*]] = addrspacecast ptr addrspace(3) @WGCopy1 to ptr
+; CHECK-NEXT:    ret void
+;
+entry:
+  %group.ascast = addrspacecast ptr addrspace(5) %agg to ptr
+  store ptr %group.ascast, ptr addrspace(3) @WGCopy1, align 8
+  %agg.copyload = load ptr, ptr addrspace(3) @WGCopy1, align 8
+  %val = load i64, ptr %agg.copyload, align 8
+  %gv.asc = addrspacecast ptr addrspace(3) @WGCopy1 to ptr
+  ret void
+}
+
+; load ptr AS is not inferred since GV is not used as pointer operand in store
+; inst.
+define void @negative_test_gv_store_not_pointer_operand(ptr addrspace(5) %agg) {
+; CHECK-LABEL: define void @negative_test_gv_store_not_pointer_operand(
+; CHECK-SAME: ptr addrspace(5) [[AGG:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[B:%.*]] = alloca ptr addrspace(3), align 8, addrspace(5)
+; CHECK-NEXT:    [[GROUP_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[AGG]] to ptr
+; CHECK-NEXT:    store ptr [[GROUP_ASCAST]], ptr addrspace(3) @WGCopy2, align 8
+; CHECK-NEXT:    store ptr addrspace(3) @WGCopy2, ptr addrspace(5) [[B]], align 8
+; CHECK-NEXT:    [[AGG_COPYLOAD:%.*]] = load ptr, ptr addrspace(3) @WGCopy2, align 8
+; CHECK-NEXT:    [[TMP0:%.*]] = load i64, ptr [[AGG_COPYLOAD]], align 8
+; CHECK-NEXT:    ret void
+;
+entry:
+  %b = alloca ptr addrspace(3), align 8, addrspace(5)
+  %group.ascast = addrspacecast ptr addrspace(5) %agg to ptr
+  store ptr %group.ascast, ptr addrspace(3) @WGCopy2, align 8
+  store ptr addrspace(3) @WGCopy2, ptr addrspace(5) %b, align 8
+  %agg.copyload = load ptr, ptr addrspace(3) @WGCopy2, align 8
+  %val = load i64, ptr %agg.copyload, align 8
+  ret void
+}
+
+; load ptr AS is not inferred since there are multiple stores to GV and stored
+; pointers have different AS.
+define void @negative_test_gv_multi_store_different_addrspace(ptr addrspace(1) %arg) {
+; CHECK-LABEL: define void @negative_test_gv_multi_store_different_addrspace(
+; CHECK-SAME: ptr addrspace(1) [[ARG:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[AGG:%.*]] = alloca i64, align 8, addrspace(5)
+; CHECK-NEXT:    [[GROUP_ASCAST:%.*]] = addrspacecast ptr addrspace(1) [[ARG]] to ptr
+; CHECK-NEXT:    store ptr [[GROUP_ASCAST]], ptr addrspace(3) @WGCopy3, align 8
+; CHECK-NEXT:    [[GROUP_ASCAST1:%.*]] = addrspacecast ptr addrspace(5) [[AGG]] to ptr
+; CHECK-NEXT:    store ptr [[GROUP_ASCAST1]], ptr addrspace(3) @WGCopy3, align 8
+; CHECK-NEXT:    [[AGG_COPYLOAD:%.*]] = load ptr, ptr addrspace(3) @WGCopy3, align 8
+; CHECK-NEXT:    [[TMP0:%.*]] = load i64, ptr [[AGG_COPYLOAD]], align 8
+; CHECK-NEXT:    ret void
+;
+entry:
+  %agg = alloca i64, align 8, addrspace(5)
+  %group.ascast = addrspacecast ptr addrspace(1) %arg to ptr
+  store ptr %group.ascast, ptr addrspace(3) @WGCopy3, align 8
+  %group.ascast1 = addrspacecast ptr addrspace(5) %agg to ptr
+  store ptr %group.ascast1, ptr addrspace(3) @WGCopy3, align 8
+  %agg.copyload = load ptr, ptr addrspace(3) @WGCopy3, align 8
+  %val = load i64, ptr %agg.copyload, align 8
+  ret void
+}
+
+; load ptr AS is not inferred since GV is used in two functions
+; negative_test_gv_used_in_two_funcs_foo and negative_test_gv_used_in_two_funcs_bar.
+define void @negative_test_gv_used_in_two_funcs_foo(ptr addrspace(1) %agg) {
+; CHECK-LABEL: define void @negative_test_gv_used_in_two_funcs_foo(
+; CHECK-SAME: ptr addrspace(1) [[AGG:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[GROUP_ASCAST:%.*]] = addrspacecast ptr addrspace(1) [[AGG]] to ptr
+; CHECK-NEXT:    store ptr [[GROUP_ASCAST]], ptr addrspace(3) @WGCopy4, align 8
+; CHECK-NEXT:    [[AGG_SROA_COPYLOAD:%.*]] = load ptr, ptr addrspace(3) @WGCopy4, align 8
+; CHECK-NEXT:    [[TMP0:%.*]] = load i64, ptr [[AGG_SROA_COPYLOAD]], align 8
+; CHECK-NEXT:    ret void
+;
+entry:
+  %group.ascast = addrspacecast ptr addrspace(1) %agg to ptr
+  store ptr %group.ascast, ptr addrspace(3) @WGCopy4, align 8
+  %agg.sroa.copyload = load ptr, ptr addrspace(3) @WGCopy4, align 8
+  %val = load i64, ptr %agg.sroa.copyload, align 8
+  ret void
+}
+
+define void @negative_test_gv_used_in_two_funcs_bar(ptr addrspace(1) %agg) {
+; CHECK-LABEL: define void @negative_test_gv_used_in_two_funcs_bar(
+; CHECK-SAME: ptr addrspace(1) [[AGG:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*:]]
+; CHECK-NEXT:    [[GROUP_ASCAST:%.*]] = addrspacecast ptr addrspace(1) [[AGG]] to ptr
+; CHECK-NEXT:    store ptr [[GROUP_ASCAST]], ptr addrspace(3) @WGCopy4, align 8
+; CHECK-NEXT:    ret void
+;
+entry:
+  %group.ascast = addrspacecast ptr addrspace(1) %agg to ptr
+  store ptr %group.ascast, ptr addrspace(3) @WGCopy4, align 8
+  ret void
+}

>From f3bc5852667311b2f72297c680c2a25dbcb0a617 Mon Sep 17 00:00:00 2001
From: Wenju He <wenju.he at intel.com>
Date: Mon, 22 Sep 2025 16:47:34 +0800
Subject: [PATCH 4/4] Update llvm/lib/Transforms/Scalar/InferAddressSpaces.cpp
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Co-authored-by: Juan Manuel Martinez CaamaƱo <jmartinezcaamao at gmail.com>
---
 llvm/lib/Transforms/Scalar/InferAddressSpaces.cpp | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/llvm/lib/Transforms/Scalar/InferAddressSpaces.cpp b/llvm/lib/Transforms/Scalar/InferAddressSpaces.cpp
index 25b31684ceaa2..771f636407837 100644
--- a/llvm/lib/Transforms/Scalar/InferAddressSpaces.cpp
+++ b/llvm/lib/Transforms/Scalar/InferAddressSpaces.cpp
@@ -601,8 +601,9 @@ InferAddressSpacesImpl::collectFlatAddressExpressions(Function &F) const {
     } else if (auto *LI = dyn_cast<LoadInst>(&I))
       PushPtrOperand(LI->getPointerOperand());
     else if (auto *SI = dyn_cast<StoreInst>(&I)) {
-      if (SI->getValueOperand()->getType()->isPtrOrPtrVectorTy())
-        PushPtrOperand(SI->getValueOperand());
+      Value* V = SI->getValueOperand();
+      if (V->getType()->isPtrOrPtrVectorTy())
+        PushPtrOperand(V);
       PushPtrOperand(SI->getPointerOperand());
     } else if (auto *RMW = dyn_cast<AtomicRMWInst>(&I))
       PushPtrOperand(RMW->getPointerOperand());



More information about the llvm-commits mailing list