[llvm] [SimplifyCFG]divergent undef predecessor removal (PR #204287)
Fujun Han via llvm-commits
llvm-commits at lists.llvm.org
Sun Jun 21 21:56:30 PDT 2026
https://github.com/Peter9606 updated https://github.com/llvm/llvm-project/pull/204287
>From f92029a7760a22253d411f256619ecf49169214b Mon Sep 17 00:00:00 2001
From: Fujun Han <fujun.han at iluvatar.com>
Date: Mon, 22 Jun 2026 09:22:09 +0800
Subject: [PATCH] [SimplifyCFG] Skip predecessor removal at convergent join
points
Poison on one PHI incoming edge must not be treated as proof that the
predecessor is unreachable when the value flows to a noundef argument of a
convergent call. IR represents a single-lane view, but convergent operations
bind SIMT semantics at join points.
Add regression test divergent-poison-phi.ll.
Assisted-by: Cursor (composer-2.5-fast)
Signed-off-by: Fujun Han <fujun.han at iluvatar.com>
---
llvm/lib/Transforms/Utils/SimplifyCFG.cpp | 7 +-
.../SimplifyCFG/divergent-poison-phi.ll | 64 +++++++++++++++++++
2 files changed, 69 insertions(+), 2 deletions(-)
create mode 100644 llvm/test/Transforms/SimplifyCFG/divergent-poison-phi.ll
diff --git a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
index 524947dd2e95d..01db2ca0076aa 100644
--- a/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
+++ b/llvm/lib/Transforms/Utils/SimplifyCFG.cpp
@@ -8891,9 +8891,12 @@ static bool passingValueIsAlwaysUndefined(Value *V, Instruction *I, bool PtrValu
if (isa<ConstantPointerNull>(C) &&
CB->paramHasNonNullAttr(ArgIdx, /*AllowUndefOrPoison=*/false))
return !PtrValueMayBeModified;
- // Passing undef to a noundef argument is undefined.
+ // Passing poison/undef to a noundef argument is undefined in the
+ // single-lane IR model, unless the call is convergent: at a join
+ // point, convergent operations bind SIMT semantics and poison on one
+ // PHI incoming edge does not imply that predecessor is unreachable.
if (isa<UndefValue>(C) && CB->isPassingUndefUB(ArgIdx))
- return true;
+ return !CB->isConvergent();
}
}
// Div/Rem by zero is immediate UB
diff --git a/llvm/test/Transforms/SimplifyCFG/divergent-poison-phi.ll b/llvm/test/Transforms/SimplifyCFG/divergent-poison-phi.ll
new file mode 100644
index 0000000000000..3b0874adfaceb
--- /dev/null
+++ b/llvm/test/Transforms/SimplifyCFG/divergent-poison-phi.ll
@@ -0,0 +1,64 @@
+; REQUIRES: amdgpu-registered-target && x86-registered-target
+; RUN: opt < %s -mtriple=amdgcn -passes=simplifycfg -S | FileCheck %s -check-prefix=DIVERGENT
+; RUN: opt < %s -mtriple=x86_64 -passes=simplifycfg -S | FileCheck %s -check-prefix=UNIFORM
+
+; When poison on a PHI incoming edge flows to a convergent noundef call at a
+; join point, do not treat that edge as unreachable. Scalar folding remains
+; valid for the same pattern with a non-convergent callee.
+
+declare i32 @llvm.amdgcn.workitem.id.x() #0
+
+declare i32 @shuffle(i32 noundef, i32 noundef) convergent
+
+declare i32 @use_val(i32 noundef)
+
+define amdgpu_kernel void @k_convergent(ptr addrspace(1) nocapture %counter, ptr addrspace(1) nocapture %out) #1 {
+; DIVERGENT-LABEL: @k_convergent(
+entry:
+ %tid = tail call i32 @llvm.amdgcn.workitem.id.x()
+ %cmp = icmp eq i32 %tid, 0
+ br i1 %cmp, label %if.then, label %if.end
+
+if.then:
+ %old = atomicrmw add ptr addrspace(1) %counter, i32 1 monotonic, align 4
+ br label %if.end
+
+if.end:
+ %val = phi i32 [ %old, %if.then ], [ poison, %entry ]
+ %shfl = tail call i32 @shuffle(i32 noundef %val, i32 noundef %tid) #2
+ %idx = zext i32 %tid to i64
+ %ptr = getelementptr i32, ptr addrspace(1) %out, i64 %idx
+ store i32 %shfl, ptr addrspace(1) %ptr, align 4
+ ret void
+}
+
+define void @k_scalar(i32 %tid, ptr nocapture %counter, ptr nocapture %out) {
+; UNIFORM-LABEL: @k_scalar(
+entry:
+ %cmp = icmp eq i32 %tid, 0
+ br i1 %cmp, label %if.then, label %if.end
+
+if.then:
+ %old = atomicrmw add ptr %counter, i32 1 monotonic, align 4
+ br label %if.end
+
+if.end:
+ %val = phi i32 [ %old, %if.then ], [ poison, %entry ]
+ %use = call i32 @use_val(i32 noundef %val)
+ %idx = zext i32 %tid to i64
+ %ptr = getelementptr i32, ptr %out, i64 %idx
+ store i32 %use, ptr %ptr, align 4
+ ret void
+}
+
+; DIVERGENT-NOT: call void @llvm.assume
+; DIVERGENT: br i1 {{%.*}}, label %if.then, label %if.end
+; DIVERGENT: atomicrmw add
+; DIVERGENT: phi i32
+
+; UNIFORM: call void @llvm.assume
+; UNIFORM-NOT: br i1 {{%.*}}, label %if.then, label %if.end
+
+attributes #0 = { nounwind readnone }
+attributes #1 = { convergent "amdgpu-flat-work-group-size"="1,256" }
+attributes #2 = { convergent }
More information about the llvm-commits
mailing list