[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