[llvm] 0008a69 - [InferAddressSpaces] Lower stuck uninitialized values to flat before rewriting (#215525)

via llvm-commits llvm-commits at lists.llvm.org
Sat Aug 22 11:39:59 PDT 2026


Author: Pankaj Dwivedi
Date: 2026-08-23T00:09:54+05:30
New Revision: 0008a699614a5dbce598d115ad450e1bf38796fe

URL: https://github.com/llvm/llvm-project/commit/0008a699614a5dbce598d115ad450e1bf38796fe
DIFF: https://github.com/llvm/llvm-project/commit/0008a699614a5dbce598d115ad450e1bf38796fe.diff

LOG: [InferAddressSpaces] Lower stuck uninitialized values to flat before rewriting (#215525)

Added: 
    llvm/test/Transforms/InferAddressSpaces/AMDGPU/phi-cycle-uninitialized-addrspace.ll

Modified: 
    llvm/lib/Transforms/Scalar/InferAddressSpaces.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Transforms/Scalar/InferAddressSpaces.cpp b/llvm/lib/Transforms/Scalar/InferAddressSpaces.cpp
index d11fa0e5c9ce0..3820f3e1e45ad 100644
--- a/llvm/lib/Transforms/Scalar/InferAddressSpaces.cpp
+++ b/llvm/lib/Transforms/Scalar/InferAddressSpaces.cpp
@@ -229,6 +229,15 @@ class InferAddressSpacesImpl {
                           ValueToAddrSpaceMapTy &InferredAddrSpace,
                           PredicatedAddrSpaceMapTy &PredicatedAS) const;
 
+  // Adds the users of V whose address space may still change to Worklist.
+  void enqueueUsers(Value &V, const ValueToAddrSpaceMapTy &InferredAddrSpace,
+                    SetVector<Value *> &Worklist) const;
+
+  // Propagates address spaces out of Worklist until nothing changes.
+  void runToFixPoint(SetVector<Value *> &Worklist,
+                     ValueToAddrSpaceMapTy &InferredAddrSpace,
+                     PredicatedAddrSpaceMapTy &PredicatedAS) const;
+
   // Tries to infer the specific address space of each address expression in
   // Postorder.
   void inferAddressSpaces(ArrayRef<WeakTrackingVH> Postorder,
@@ -1133,17 +1142,33 @@ bool InferAddressSpacesImpl::run(Function &CurFn) {
                                      PredicatedAS);
 }
 
-// Constants need to be tracked through RAUW to handle cases with nested
-// constant expressions, so wrap values in WeakTrackingVH.
-void InferAddressSpacesImpl::inferAddressSpaces(
-    ArrayRef<WeakTrackingVH> Postorder,
-    ValueToAddrSpaceMapTy &InferredAddrSpace,
-    PredicatedAddrSpaceMapTy &PredicatedAS) const {
-  SetVector<Value *> Worklist(llvm::from_range, Postorder);
-  // Initially, all expressions are in the uninitialized address space.
-  for (Value *V : Postorder)
-    InferredAddrSpace[V] = UninitializedAddressSpace;
+void InferAddressSpacesImpl::enqueueUsers(
+    Value &V, const ValueToAddrSpaceMapTy &InferredAddrSpace,
+    SetVector<Value *> &Worklist) const {
+  for (Value *User : V.users()) {
+    // Skip if User is already in the worklist.
+    if (Worklist.count(User))
+      continue;
+
+    ValueToAddrSpaceMapTy::const_iterator Pos = InferredAddrSpace.find(User);
+    // Our algorithm only updates the address spaces of flat address
+    // expressions, which are those in InferredAddrSpace.
+    if (Pos == InferredAddrSpace.end())
+      continue;
+
+    // Function updateAddressSpace moves the address space down a lattice path.
+    // Therefore, nothing to do if User is already inferred as flat (the bottom
+    // element in the lattice).
+    if (Pos->second == FlatAddrSpace)
+      continue;
+
+    Worklist.insert(User);
+  }
+}
 
+void InferAddressSpacesImpl::runToFixPoint(
+    SetVector<Value *> &Worklist, ValueToAddrSpaceMapTy &InferredAddrSpace,
+    PredicatedAddrSpaceMapTy &PredicatedAS) const {
   while (!Worklist.empty()) {
     Value *V = Worklist.pop_back_val();
 
@@ -1152,26 +1177,40 @@ void InferAddressSpacesImpl::inferAddressSpaces(
     if (!updateAddressSpace(*V, InferredAddrSpace, PredicatedAS))
       continue;
 
-    for (Value *User : V->users()) {
-      // Skip if User is already in the worklist.
-      if (Worklist.count(User))
-        continue;
+    enqueueUsers(*V, InferredAddrSpace, Worklist);
+  }
+}
 
-      auto Pos = InferredAddrSpace.find(User);
-      // Our algorithm only updates the address spaces of flat address
-      // expressions, which are those in InferredAddrSpace.
-      if (Pos == InferredAddrSpace.end())
-        continue;
+// Constants need to be tracked through RAUW to handle cases with nested
+// constant expressions, so wrap values in WeakTrackingVH.
+void InferAddressSpacesImpl::inferAddressSpaces(
+    ArrayRef<WeakTrackingVH> Postorder,
+    ValueToAddrSpaceMapTy &InferredAddrSpace,
+    PredicatedAddrSpaceMapTy &PredicatedAS) const {
+  SetVector<Value *> Worklist(llvm::from_range, Postorder);
+  // Initially, all expressions are in the uninitialized address space.
+  for (Value *V : Postorder)
+    InferredAddrSpace[V] = UninitializedAddressSpace;
 
-      // Function updateAddressSpace moves the address space down a lattice
-      // path. Therefore, nothing to do if User is already inferred as flat (the
-      // bottom element in the lattice).
-      if (Pos->second == FlatAddrSpace)
-        continue;
+  runToFixPoint(Worklist, InferredAddrSpace, PredicatedAS);
 
-      Worklist.insert(User);
+  // A value still uninitialized here is stuck in a cycle of uninitialized
+  // values and carries no address space information. Lower it to flat so its
+  // users join to flat, instead of being rewritten to reference an operand
+  // that rewriteWithNewAddressSpaces() never converts.
+  SmallVector<Value *, 4> Lowered;
+  for (Value *V : Postorder) {
+    ValueToAddrSpaceMapTy::iterator I = InferredAddrSpace.find(V);
+    if (I->second == UninitializedAddressSpace) {
+      I->second = FlatAddrSpace;
+      Lowered.push_back(V);
     }
   }
+
+  for (Value *V : Lowered)
+    enqueueUsers(*V, InferredAddrSpace, Worklist);
+
+  runToFixPoint(Worklist, InferredAddrSpace, PredicatedAS);
 }
 
 unsigned

diff  --git a/llvm/test/Transforms/InferAddressSpaces/AMDGPU/phi-cycle-uninitialized-addrspace.ll b/llvm/test/Transforms/InferAddressSpaces/AMDGPU/phi-cycle-uninitialized-addrspace.ll
new file mode 100644
index 0000000000000..6929c17930e57
--- /dev/null
+++ b/llvm/test/Transforms/InferAddressSpaces/AMDGPU/phi-cycle-uninitialized-addrspace.ll
@@ -0,0 +1,272 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
+; RUN: opt -mtriple=amdgpu9.42-amd-amdhsa -S -passes=infer-address-spaces %s | FileCheck %s
+
+ at g = external global i8, align 1
+
+; %q is a loop phi whose only non-cyclic incoming value is a constant that is
+; not an address expression, so it stays uninitialized and %p must stay flat.
+define void @phi_cycle_poison_init(i1 %c, ptr addrspace(5) %s) {
+; CHECK-LABEL: define void @phi_cycle_poison_init(
+; CHECK-SAME: i1 [[C:%.*]], ptr addrspace(5) [[S:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*]]:
+; CHECK-NEXT:    [[CAST:%.*]] = addrspacecast ptr addrspace(5) [[S]] to ptr
+; CHECK-NEXT:    br i1 [[C]], label %[[LOOP:.*]], label %[[EXIT:.*]]
+; CHECK:       [[LOOP]]:
+; CHECK-NEXT:    [[Q:%.*]] = phi ptr [ poison, %[[ENTRY]] ], [ [[Q]], %[[LOOP]] ]
+; CHECK-NEXT:    br i1 [[C]], label %[[LOOP]], label %[[EXIT]]
+; CHECK:       [[EXIT]]:
+; CHECK-NEXT:    [[P:%.*]] = phi ptr [ [[CAST]], %[[ENTRY]] ], [ [[Q]], %[[LOOP]] ]
+; CHECK-NEXT:    store i32 0, ptr [[P]], align 4
+; CHECK-NEXT:    ret void
+;
+entry:
+  %cast = addrspacecast ptr addrspace(5) %s to ptr
+  br i1 %c, label %loop, label %exit
+
+loop:
+  %q = phi ptr [ poison, %entry ], [ %q, %loop ]
+  br i1 %c, label %loop, label %exit
+
+exit:
+  %p = phi ptr [ %cast, %entry ], [ %q, %loop ]
+  store i32 0, ptr %p, align 4
+  ret void
+}
+
+; Same, but %q can hold a real flat address, so rewriting the store to
+; addrspace(5) would be a miscompile rather than only a missing replacement.
+define void @phi_cycle_real_flat_addr(i1 %c, ptr addrspace(5) %s) {
+; CHECK-LABEL: define void @phi_cycle_real_flat_addr(
+; CHECK-SAME: i1 [[C:%.*]], ptr addrspace(5) [[S:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*]]:
+; CHECK-NEXT:    [[CAST:%.*]] = addrspacecast ptr addrspace(5) [[S]] to ptr
+; CHECK-NEXT:    br i1 [[C]], label %[[LOOP:.*]], label %[[EXIT:.*]]
+; CHECK:       [[LOOP]]:
+; CHECK-NEXT:    [[Q:%.*]] = phi ptr [ inttoptr (i64 1234 to ptr), %[[ENTRY]] ], [ [[Q]], %[[LOOP]] ]
+; CHECK-NEXT:    br i1 [[C]], label %[[LOOP]], label %[[EXIT]]
+; CHECK:       [[EXIT]]:
+; CHECK-NEXT:    [[P:%.*]] = phi ptr [ [[CAST]], %[[ENTRY]] ], [ [[Q]], %[[LOOP]] ]
+; CHECK-NEXT:    store i32 0, ptr [[P]], align 4
+; CHECK-NEXT:    ret void
+;
+entry:
+  %cast = addrspacecast ptr addrspace(5) %s to ptr
+  br i1 %c, label %loop, label %exit
+
+loop:
+  %q = phi ptr [ inttoptr (i64 1234 to ptr), %entry ], [ %q, %loop ]
+  br i1 %c, label %loop, label %exit
+
+exit:
+  %p = phi ptr [ %cast, %entry ], [ %q, %loop ]
+  store i32 0, ptr %p, align 4
+  ret void
+}
+
+; Same, but the cycle spans two values so it is not trivially foldable.
+define void @phi_gep_cycle(i1 %c, ptr addrspace(5) %s) {
+; CHECK-LABEL: define void @phi_gep_cycle(
+; CHECK-SAME: i1 [[C:%.*]], ptr addrspace(5) [[S:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*]]:
+; CHECK-NEXT:    [[CAST:%.*]] = addrspacecast ptr addrspace(5) [[S]] to ptr
+; CHECK-NEXT:    br i1 [[C]], label %[[LOOP:.*]], label %[[EXIT:.*]]
+; CHECK:       [[LOOP]]:
+; CHECK-NEXT:    [[Q:%.*]] = phi ptr [ poison, %[[ENTRY]] ], [ [[Q_NEXT:%.*]], %[[LOOP]] ]
+; CHECK-NEXT:    [[Q_NEXT]] = getelementptr i8, ptr [[Q]], i64 1
+; CHECK-NEXT:    br i1 [[C]], label %[[LOOP]], label %[[EXIT]]
+; CHECK:       [[EXIT]]:
+; CHECK-NEXT:    [[P:%.*]] = phi ptr [ [[CAST]], %[[ENTRY]] ], [ [[Q_NEXT]], %[[LOOP]] ]
+; CHECK-NEXT:    store i32 0, ptr [[P]], align 4
+; CHECK-NEXT:    ret void
+;
+entry:
+  %cast = addrspacecast ptr addrspace(5) %s to ptr
+  br i1 %c, label %loop, label %exit
+
+loop:
+  %q = phi ptr [ poison, %entry ], [ %q.next, %loop ]
+  %q.next = getelementptr i8, ptr %q, i64 1
+  br i1 %c, label %loop, label %exit
+
+exit:
+  %p = phi ptr [ %cast, %entry ], [ %q.next, %loop ]
+  store i32 0, ptr %p, align 4
+  ret void
+}
+
+; The uninitialized value can also come from unreachable code.
+define void @unreachable_phi_cycle(i1 %c, ptr addrspace(5) %s) {
+; CHECK-LABEL: define void @unreachable_phi_cycle(
+; CHECK-SAME: i1 [[C:%.*]], ptr addrspace(5) [[S:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*]]:
+; CHECK-NEXT:    [[CAST:%.*]] = addrspacecast ptr addrspace(5) [[S]] to ptr
+; CHECK-NEXT:    br label %[[EXIT:.*]]
+; CHECK:       [[DEAD:.*]]:
+; CHECK-NEXT:    [[Q:%.*]] = phi ptr [ [[Q]], %[[DEAD]] ]
+; CHECK-NEXT:    br i1 [[C]], label %[[DEAD]], label %[[EXIT]]
+; CHECK:       [[EXIT]]:
+; CHECK-NEXT:    [[P:%.*]] = phi ptr [ [[CAST]], %[[ENTRY]] ], [ [[Q]], %[[DEAD]] ]
+; CHECK-NEXT:    store i32 0, ptr [[P]], align 4
+; CHECK-NEXT:    ret void
+;
+entry:
+  %cast = addrspacecast ptr addrspace(5) %s to ptr
+  br label %exit
+
+dead:
+  %q = phi ptr [ %q, %dead ]
+  br i1 %c, label %dead, label %exit
+
+exit:
+  %p = phi ptr [ %cast, %entry ], [ %q, %dead ]
+  store i32 0, ptr %p, align 4
+  ret void
+}
+
+; A cycle that does have an inferrable incoming value is still rewritten.
+define void @phi_cycle_inferrable(i1 %c, ptr addrspace(5) %s) {
+; CHECK-LABEL: define void @phi_cycle_inferrable(
+; CHECK-SAME: i1 [[C:%.*]], ptr addrspace(5) [[S:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*]]:
+; CHECK-NEXT:    br label %[[LOOP:.*]]
+; CHECK:       [[LOOP]]:
+; CHECK-NEXT:    [[Q:%.*]] = phi ptr addrspace(5) [ [[S]], %[[ENTRY]] ], [ [[Q_NEXT:%.*]], %[[LOOP]] ]
+; CHECK-NEXT:    [[Q_NEXT]] = getelementptr i8, ptr addrspace(5) [[Q]], i64 1
+; CHECK-NEXT:    store i32 0, ptr addrspace(5) [[Q]], align 4
+; CHECK-NEXT:    br i1 [[C]], label %[[LOOP]], label %[[EXIT:.*]]
+; CHECK:       [[EXIT]]:
+; CHECK-NEXT:    ret void
+;
+entry:
+  %cast = addrspacecast ptr addrspace(5) %s to ptr
+  br label %loop
+
+loop:
+  %q = phi ptr [ %cast, %entry ], [ %q.next, %loop ]
+  %q.next = getelementptr i8, ptr %q, i64 1
+  store i32 0, ptr %q, align 4
+  br i1 %c, label %loop, label %exit
+
+exit:
+  ret void
+}
+
+define void @phi_incoming_instruction(ptr addrspace(1) %arg, i1 %c) {
+; CHECK-LABEL: define void @phi_incoming_instruction(
+; CHECK-SAME: ptr addrspace(1) [[ARG:%.*]], i1 [[C:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*]]:
+; CHECK-NEXT:    [[ARG_CAST:%.*]] = addrspacecast ptr addrspace(1) [[ARG]] to ptr
+; CHECK-NEXT:    br i1 [[C]], label %[[MERGE:.*]], label %[[LOOP:.*]]
+; CHECK:       [[LOOP]]:
+; CHECK-NEXT:    [[X:%.*]] = phi ptr [ poison, %[[ENTRY]] ], [ [[XN:%.*]], %[[LOOP]] ]
+; CHECK-NEXT:    [[XN]] = getelementptr i8, ptr [[X]], i64 1
+; CHECK-NEXT:    br i1 [[C]], label %[[LOOP]], label %[[MERGE]]
+; CHECK:       [[MERGE]]:
+; CHECK-NEXT:    [[P:%.*]] = phi ptr [ [[ARG_CAST]], %[[ENTRY]] ], [ [[XN]], %[[LOOP]] ]
+; CHECK-NEXT:    [[V:%.*]] = load i32, ptr [[P]], align 4
+; CHECK-NEXT:    ret void
+;
+entry:
+  %arg.cast = addrspacecast ptr addrspace(1) %arg to ptr
+  br i1 %c, label %merge, label %loop
+
+loop:
+  %x = phi ptr [ poison, %entry ], [ %xn, %loop ]
+  %xn = getelementptr i8, ptr %x, i64 1
+  br i1 %c, label %loop, label %merge
+
+merge:
+  %p = phi ptr [ %arg.cast, %entry ], [ %xn, %loop ]
+  %v = load i32, ptr %p
+  ret void
+}
+
+define void @phi_incoming_null(ptr addrspace(1) %arg, i1 %c) {
+; CHECK-LABEL: define void @phi_incoming_null(
+; CHECK-SAME: ptr addrspace(1) [[ARG:%.*]], i1 [[C:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*]]:
+; CHECK-NEXT:    [[ARG_CAST:%.*]] = addrspacecast ptr addrspace(1) [[ARG]] to ptr
+; CHECK-NEXT:    br i1 [[C]], label %[[MERGE:.*]], label %[[LOOP:.*]]
+; CHECK:       [[LOOP]]:
+; CHECK-NEXT:    [[X:%.*]] = phi ptr [ null, %[[ENTRY]] ], [ [[XN:%.*]], %[[LOOP]] ]
+; CHECK-NEXT:    [[XN]] = getelementptr i8, ptr [[X]], i64 1
+; CHECK-NEXT:    br i1 [[C]], label %[[LOOP]], label %[[MERGE]]
+; CHECK:       [[MERGE]]:
+; CHECK-NEXT:    [[P:%.*]] = phi ptr [ [[ARG_CAST]], %[[ENTRY]] ], [ [[XN]], %[[LOOP]] ]
+; CHECK-NEXT:    [[V:%.*]] = load i32, ptr [[P]], align 4
+; CHECK-NEXT:    ret void
+;
+entry:
+  %arg.cast = addrspacecast ptr addrspace(1) %arg to ptr
+  br i1 %c, label %merge, label %loop
+
+loop:
+  %x = phi ptr [ null, %entry ], [ %xn, %loop ]
+  %xn = getelementptr i8, ptr %x, i64 1
+  br i1 %c, label %loop, label %merge
+
+merge:
+  %p = phi ptr [ %arg.cast, %entry ], [ %xn, %loop ]
+  %v = load i32, ptr %p
+  ret void
+}
+
+define void @phi_incoming_global(ptr addrspace(1) %arg, i1 %c) {
+; CHECK-LABEL: define void @phi_incoming_global(
+; CHECK-SAME: ptr addrspace(1) [[ARG:%.*]], i1 [[C:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*]]:
+; CHECK-NEXT:    [[ARG_CAST:%.*]] = addrspacecast ptr addrspace(1) [[ARG]] to ptr
+; CHECK-NEXT:    br i1 [[C]], label %[[MERGE:.*]], label %[[LOOP:.*]]
+; CHECK:       [[LOOP]]:
+; CHECK-NEXT:    [[X:%.*]] = phi ptr [ @g, %[[ENTRY]] ], [ [[XN:%.*]], %[[LOOP]] ]
+; CHECK-NEXT:    [[XN]] = getelementptr i8, ptr [[X]], i64 1
+; CHECK-NEXT:    br i1 [[C]], label %[[LOOP]], label %[[MERGE]]
+; CHECK:       [[MERGE]]:
+; CHECK-NEXT:    [[P:%.*]] = phi ptr [ [[ARG_CAST]], %[[ENTRY]] ], [ [[XN]], %[[LOOP]] ]
+; CHECK-NEXT:    [[V:%.*]] = load i8, ptr [[P]], align 1
+; CHECK-NEXT:    ret void
+;
+entry:
+  %arg.cast = addrspacecast ptr addrspace(1) %arg to ptr
+  br i1 %c, label %merge, label %loop
+
+loop:
+  %x = phi ptr [ @g, %entry ], [ %xn, %loop ]
+  %xn = getelementptr i8, ptr %x, i64 1
+  br i1 %c, label %loop, label %merge
+
+merge:
+  %p = phi ptr [ %arg.cast, %entry ], [ %xn, %loop ]
+  %v = load i8, ptr %p
+  ret void
+}
+
+define void @phi_incoming_constant_expr(ptr addrspace(1) %arg, i1 %c) {
+; CHECK-LABEL: define void @phi_incoming_constant_expr(
+; CHECK-SAME: ptr addrspace(1) [[ARG:%.*]], i1 [[C:%.*]]) {
+; CHECK-NEXT:  [[ENTRY:.*]]:
+; CHECK-NEXT:    [[ARG_CAST:%.*]] = addrspacecast ptr addrspace(1) [[ARG]] to ptr
+; CHECK-NEXT:    br i1 [[C]], label %[[MERGE:.*]], label %[[LOOP:.*]]
+; CHECK:       [[LOOP]]:
+; CHECK-NEXT:    [[X:%.*]] = phi ptr [ inttoptr (i64 4096 to ptr), %[[ENTRY]] ], [ [[XN:%.*]], %[[LOOP]] ]
+; CHECK-NEXT:    [[XN]] = getelementptr i8, ptr [[X]], i64 1
+; CHECK-NEXT:    br i1 [[C]], label %[[LOOP]], label %[[MERGE]]
+; CHECK:       [[MERGE]]:
+; CHECK-NEXT:    [[P:%.*]] = phi ptr [ [[ARG_CAST]], %[[ENTRY]] ], [ [[XN]], %[[LOOP]] ]
+; CHECK-NEXT:    [[V:%.*]] = load i32, ptr [[P]], align 4
+; CHECK-NEXT:    ret void
+;
+entry:
+  %arg.cast = addrspacecast ptr addrspace(1) %arg to ptr
+  br i1 %c, label %merge, label %loop
+
+loop:
+  %x = phi ptr [ inttoptr (i64 4096 to ptr), %entry ], [ %xn, %loop ]
+  %xn = getelementptr i8, ptr %x, i64 1
+  br i1 %c, label %loop, label %merge
+
+merge:
+  %p = phi ptr [ %arg.cast, %entry ], [ %xn, %loop ]
+  %v = load i32, ptr %p
+  ret void
+}


        


More information about the llvm-commits mailing list