[llvm] [DFAJumpThreading] Unfold select to the incoming block of phi user (PR #160987)
Hongyu Chen via llvm-commits
llvm-commits at lists.llvm.org
Sat Sep 27 00:24:57 PDT 2025
https://github.com/XChy created https://github.com/llvm/llvm-project/pull/160987
Fixes #160250
We previously assumed the select to unfold is defined in the incoming block of phi user, as `isValidSelectInst` filters other cases at the initial stage. However, the selects not defined in the incoming block may occur after unfolding the arms of the unfolded select.
This patch sinks the select into the incoming block of the phi user and unfolds it at the incoming block.
>From 82ec2a7ddd7edbef7a97d864bf65a5fddf5bf909 Mon Sep 17 00:00:00 2001
From: XChy <xxs_chy at outlook.com>
Date: Sat, 27 Sep 2025 15:16:10 +0800
Subject: [PATCH] [DFAJumpThreading] Unfold select to the incoming block of phi
user
---
.../Transforms/Scalar/DFAJumpThreading.cpp | 10 +--
.../dfa-jump-threading-transform.ll | 40 ++++++-----
.../DFAJumpThreading/dfa-unfold-select.ll | 70 +++++++++++++++++++
3 files changed, 98 insertions(+), 22 deletions(-)
diff --git a/llvm/lib/Transforms/Scalar/DFAJumpThreading.cpp b/llvm/lib/Transforms/Scalar/DFAJumpThreading.cpp
index 944b253e0f5e7..1da312c5a85ff 100644
--- a/llvm/lib/Transforms/Scalar/DFAJumpThreading.cpp
+++ b/llvm/lib/Transforms/Scalar/DFAJumpThreading.cpp
@@ -190,12 +190,12 @@ void unfold(DomTreeUpdater *DTU, LoopInfo *LI, SelectInstToUnfold SIToUnfold,
std::vector<BasicBlock *> *NewBBs) {
SelectInst *SI = SIToUnfold.getInst();
PHINode *SIUse = SIToUnfold.getUse();
- BasicBlock *StartBlock = SI->getParent();
+ assert(SI->hasOneUse());
+ // The select may come indirectly, instead of from where it is defined.
+ BasicBlock *StartBlock = SIUse->getIncomingBlock(SI->user_begin().getUse());
BranchInst *StartBlockTerm =
dyn_cast<BranchInst>(StartBlock->getTerminator());
-
assert(StartBlockTerm);
- assert(SI->hasOneUse());
if (StartBlockTerm->isUnconditional()) {
BasicBlock *EndBlock = StartBlock->getUniqueSuccessor();
@@ -332,7 +332,7 @@ void unfold(DomTreeUpdater *DTU, LoopInfo *LI, SelectInstToUnfold SIToUnfold,
}
// Preserve loop info
- if (Loop *L = LI->getLoopFor(SI->getParent())) {
+ if (Loop *L = LI->getLoopFor(StartBlock)) {
for (BasicBlock *NewBB : *NewBBs)
L->addBasicBlockToLoop(NewBB, *LI);
}
@@ -533,6 +533,8 @@ struct MainSwitch {
return false;
// Only fold the select coming from directly where it is defined.
+ // TODO: We have dealt with the select coming indirectly now. This
+ // constraint can be relaxed.
PHINode *PHIUser = dyn_cast<PHINode>(SIUse);
if (PHIUser && PHIUser->getIncomingBlock(*SI->use_begin()) != SIBB)
return false;
diff --git a/llvm/test/Transforms/DFAJumpThreading/dfa-jump-threading-transform.ll b/llvm/test/Transforms/DFAJumpThreading/dfa-jump-threading-transform.ll
index cba1ba8dde768..6d9bd1fae11d0 100644
--- a/llvm/test/Transforms/DFAJumpThreading/dfa-jump-threading-transform.ll
+++ b/llvm/test/Transforms/DFAJumpThreading/dfa-jump-threading-transform.ll
@@ -304,25 +304,27 @@ end:
define void @pr106083_invalidBBarg_fold(i1 %cmp1, i1 %cmp2, i1 %not, ptr %d) {
; CHECK-LABEL: @pr106083_invalidBBarg_fold(
; CHECK-NEXT: bb:
-; CHECK-NEXT: br i1 [[CMP1:%.*]], label [[BB1:%.*]], label [[SEL_SI_UNFOLD_FALSE:%.*]]
-; CHECK: sel.si.unfold.false:
-; CHECK-NEXT: [[DOTSI_UNFOLD_PHI1:%.*]] = phi i32 [ 1, [[BB:%.*]] ]
-; CHECK-NEXT: br label [[BB1]]
+; CHECK-NEXT: br label [[BB1:%.*]]
; CHECK: BB1:
-; CHECK-NEXT: [[I:%.*]] = phi i16 [ 0, [[BB1_BACKEDGE:%.*]] ], [ 0, [[BB]] ], [ 1, [[BB7:%.*]] ], [ 0, [[SEL_SI_UNFOLD_FALSE]] ], [ 1, [[BB7_JT0:%.*]] ]
-; CHECK-NEXT: [[SEL_SI_UNFOLD_PHI:%.*]] = phi i32 [ [[SEL_SI_UNFOLD_PHI]], [[BB1_BACKEDGE]] ], [ [[SEL_SI_UNFOLD_PHI]], [[BB7]] ], [ 0, [[BB]] ], [ [[DOTSI_UNFOLD_PHI1]], [[SEL_SI_UNFOLD_FALSE]] ], [ [[SEL_SI_UNFOLD_PHI]], [[BB7_JT0]] ]
+; CHECK-NEXT: [[I:%.*]] = phi i16 [ 0, [[BB1_BACKEDGE:%.*]] ], [ 0, [[BB:%.*]] ], [ 1, [[BB9:%.*]] ], [ 1, [[BB7_JT0:%.*]] ]
; CHECK-NEXT: br i1 [[NOT:%.*]], label [[BB7_JT0]], label [[BB2:%.*]]
; CHECK: BB2:
; CHECK-NEXT: store i16 0, ptr [[D:%.*]], align 2
-; CHECK-NEXT: br i1 [[CMP2:%.*]], label [[BB7]], label [[SPEC_SELECT_SI_UNFOLD_FALSE_JT0:%.*]]
+; CHECK-NEXT: br i1 [[CMP2:%.*]], label [[BB7:%.*]], label [[SPEC_SELECT_SI_UNFOLD_FALSE_JT0:%.*]]
; CHECK: spec.select.si.unfold.false:
-; CHECK-NEXT: br label [[BB7]]
+; CHECK-NEXT: br label [[BB9]]
; CHECK: spec.select.si.unfold.false.jt0:
; CHECK-NEXT: [[DOTSI_UNFOLD_PHI_JT0:%.*]] = phi i32 [ 0, [[BB2]] ]
; CHECK-NEXT: br label [[BB7_JT0]]
+; CHECK: sel.si.unfold.true:
+; CHECK-NEXT: [[DOTSI_UNFOLD_PHI1:%.*]] = phi i32 [ 0, [[BB2]] ]
+; CHECK-NEXT: br i1 [[CMP1:%.*]], label [[BB9]], label [[SEL_SI_UNFOLD_FALSE:%.*]]
+; CHECK: sel.si.unfold.false:
+; CHECK-NEXT: [[DOTSI_UNFOLD_PHI2:%.*]] = phi i32 [ 1, [[BB7]] ]
+; CHECK-NEXT: br label [[BB9]]
; CHECK: BB7:
-; CHECK-NEXT: [[D_PROMOTED4:%.*]] = phi i16 [ 1, [[BB2]] ], [ 1, [[SPEC_SELECT_SI_UNFOLD_FALSE:%.*]] ]
-; CHECK-NEXT: [[_3:%.*]] = phi i32 [ [[SEL_SI_UNFOLD_PHI]], [[BB2]] ], [ poison, [[SPEC_SELECT_SI_UNFOLD_FALSE]] ]
+; CHECK-NEXT: [[D_PROMOTED4:%.*]] = phi i16 [ 1, [[SPEC_SELECT_SI_UNFOLD_FALSE:%.*]] ], [ 1, [[BB7]] ], [ 1, [[SEL_SI_UNFOLD_FALSE]] ]
+; CHECK-NEXT: [[_3:%.*]] = phi i32 [ poison, [[SPEC_SELECT_SI_UNFOLD_FALSE]] ], [ [[DOTSI_UNFOLD_PHI1]], [[BB7]] ], [ [[DOTSI_UNFOLD_PHI2]], [[SEL_SI_UNFOLD_FALSE]] ]
; CHECK-NEXT: switch i32 [[_3]], label [[BB1_BACKEDGE]] [
; CHECK-NEXT: i32 0, label [[BB1]]
; CHECK-NEXT: i32 1, label [[BB8:%.*]]
@@ -367,24 +369,26 @@ BB8: ; preds = %BB7
define void @pr106083_select_dead_uses(i1 %cmp1, i1 %not, ptr %p) {
; CHECK-LABEL: @pr106083_select_dead_uses(
; CHECK-NEXT: bb:
-; CHECK-NEXT: br i1 [[CMP1:%.*]], label [[DOTLOOPEXIT6:%.*]], label [[SPEC_SELECT_SI_UNFOLD_FALSE:%.*]]
-; CHECK: spec.select.si.unfold.false:
-; CHECK-NEXT: [[DOTSI_UNFOLD_PHI1:%.*]] = phi i32 [ 1, [[BB:%.*]] ]
-; CHECK-NEXT: br label [[DOTLOOPEXIT6]]
+; CHECK-NEXT: br label [[DOTLOOPEXIT6:%.*]]
; CHECK: .loopexit6:
-; CHECK-NEXT: [[SPEC_SELECT_SI_UNFOLD_PHI:%.*]] = phi i32 [ [[SPEC_SELECT_SI_UNFOLD_PHI]], [[SELECT_UNFOLD:%.*]] ], [ 0, [[BB]] ], [ [[DOTSI_UNFOLD_PHI1]], [[SPEC_SELECT_SI_UNFOLD_FALSE]] ]
; CHECK-NEXT: br i1 [[NOT:%.*]], label [[SELECT_UNFOLD_JT0:%.*]], label [[BB1:%.*]]
; CHECK: bb1:
; CHECK-NEXT: [[I:%.*]] = load i32, ptr [[P:%.*]], align 4
; CHECK-NEXT: [[NOT2:%.*]] = icmp eq i32 0, 0
-; CHECK-NEXT: br i1 [[NOT2]], label [[SELECT_UNFOLD]], label [[SPEC_SELECT7_SI_UNFOLD_FALSE_JT0:%.*]]
+; CHECK-NEXT: br i1 [[NOT2]], label [[SELECT_UNFOLD:%.*]], label [[SPEC_SELECT7_SI_UNFOLD_FALSE_JT0:%.*]]
; CHECK: spec.select7.si.unfold.false:
-; CHECK-NEXT: br label [[SELECT_UNFOLD]]
+; CHECK-NEXT: br label [[SELECT_UNFOLD1:%.*]]
; CHECK: spec.select7.si.unfold.false.jt0:
; CHECK-NEXT: [[DOTSI_UNFOLD_PHI_JT0:%.*]] = phi i32 [ 0, [[BB1]] ]
; CHECK-NEXT: br label [[SELECT_UNFOLD_JT0]]
+; CHECK: spec.select.si.unfold.true:
+; CHECK-NEXT: [[DOTSI_UNFOLD_PHI1:%.*]] = phi i32 [ 0, [[BB1]] ]
+; CHECK-NEXT: br i1 [[CMP1:%.*]], label [[SELECT_UNFOLD1]], label [[SPEC_SELECT_SI_UNFOLD_FALSE:%.*]]
+; CHECK: spec.select.si.unfold.false:
+; CHECK-NEXT: [[DOTSI_UNFOLD_PHI2:%.*]] = phi i32 [ 1, [[SELECT_UNFOLD]] ]
+; CHECK-NEXT: br label [[SELECT_UNFOLD1]]
; CHECK: select.unfold:
-; CHECK-NEXT: [[_2:%.*]] = phi i32 [ [[SPEC_SELECT_SI_UNFOLD_PHI]], [[BB1]] ], [ poison, [[SPEC_SELECT7_SI_UNFOLD_FALSE:%.*]] ]
+; CHECK-NEXT: [[_2:%.*]] = phi i32 [ poison, [[SPEC_SELECT7_SI_UNFOLD_FALSE:%.*]] ], [ [[DOTSI_UNFOLD_PHI1]], [[SELECT_UNFOLD]] ], [ [[DOTSI_UNFOLD_PHI2]], [[SPEC_SELECT_SI_UNFOLD_FALSE]] ]
; CHECK-NEXT: switch i32 [[_2]], label [[BB2:%.*]] [
; CHECK-NEXT: i32 0, label [[DOTPREHEADER_PREHEADER:%.*]]
; CHECK-NEXT: i32 1, label [[DOTLOOPEXIT6]]
diff --git a/llvm/test/Transforms/DFAJumpThreading/dfa-unfold-select.ll b/llvm/test/Transforms/DFAJumpThreading/dfa-unfold-select.ll
index 93872c3938768..7fc70e838f2fd 100644
--- a/llvm/test/Transforms/DFAJumpThreading/dfa-unfold-select.ll
+++ b/llvm/test/Transforms/DFAJumpThreading/dfa-unfold-select.ll
@@ -463,3 +463,73 @@ unreachable:
sw.bb: ; preds = %if.end
br label %while.cond
}
+
+define i16 @pr160250() {
+; CHECK-LABEL: @pr160250(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: br label [[FOR_COND48:%.*]]
+; CHECK: for.cond48:
+; CHECK-NEXT: br i1 false, label [[CLEANUP87_JT0:%.*]], label [[IF_ELSE:%.*]]
+; CHECK: if.else:
+; CHECK-NEXT: br i1 false, label [[DOT6_SI_UNFOLD_TRUE:%.*]], label [[DOT5_SI_UNFOLD_TRUE:%.*]]
+; CHECK: .5.si.unfold.true:
+; CHECK-NEXT: [[DOTSI_UNFOLD_PHI1:%.*]] = phi i32 [ 0, [[IF_ELSE]] ]
+; CHECK-NEXT: br i1 false, label [[SPEC_SELECT1_SI_UNFOLD_TRUE:%.*]], label [[DOT5_SI_UNFOLD_FALSE:%.*]]
+; CHECK: .5.si.unfold.false:
+; CHECK-NEXT: [[DOTSI_UNFOLD_PHI2:%.*]] = phi i32 [ 0, [[DOT5_SI_UNFOLD_TRUE]] ]
+; CHECK-NEXT: br label [[SPEC_SELECT1_SI_UNFOLD_TRUE]]
+; CHECK: spec.select1.si.unfold.true:
+; CHECK-NEXT: [[DOT5_SI_UNFOLD_PHI:%.*]] = phi i32 [ [[DOTSI_UNFOLD_PHI1]], [[DOT5_SI_UNFOLD_TRUE]] ], [ [[DOTSI_UNFOLD_PHI2]], [[DOT5_SI_UNFOLD_FALSE]] ]
+; CHECK-NEXT: br i1 false, label [[SPEC_SELECT_SI_UNFOLD_FALSE:%.*]], label [[SPEC_SELECT1_SI_UNFOLD_FALSE_JT0:%.*]]
+; CHECK: spec.select1.si.unfold.false:
+; CHECK-NEXT: br label [[SPEC_SELECT_SI_UNFOLD_FALSE]]
+; CHECK: spec.select1.si.unfold.false.jt0:
+; CHECK-NEXT: [[DOTSI_UNFOLD_PHI_JT0:%.*]] = phi i32 [ 0, [[SPEC_SELECT1_SI_UNFOLD_TRUE]] ]
+; CHECK-NEXT: br label [[SPEC_SELECT_SI_UNFOLD_FALSE_JT0:%.*]]
+; CHECK: spec.select.si.unfold.false:
+; CHECK-NEXT: [[SPEC_SELECT1_SI_UNFOLD_PHI:%.*]] = phi i32 [ [[DOT5_SI_UNFOLD_PHI]], [[SPEC_SELECT1_SI_UNFOLD_TRUE]] ], [ poison, [[SPEC_SELECT1_SI_UNFOLD_FALSE:%.*]] ]
+; CHECK-NEXT: br label [[CLEANUP87:%.*]]
+; CHECK: spec.select.si.unfold.false.jt0:
+; CHECK-NEXT: [[SPEC_SELECT1_SI_UNFOLD_PHI_JT0:%.*]] = phi i32 [ [[DOTSI_UNFOLD_PHI_JT0]], [[SPEC_SELECT1_SI_UNFOLD_FALSE_JT0]] ]
+; CHECK-NEXT: br label [[CLEANUP87_JT0]]
+; CHECK: .6.si.unfold.true:
+; CHECK-NEXT: [[DOTSI_UNFOLD_PHI3:%.*]] = phi i32 [ 0, [[IF_ELSE]] ]
+; CHECK-NEXT: br i1 false, label [[CLEANUP87]], label [[DOT6_SI_UNFOLD_FALSE:%.*]]
+; CHECK: .6.si.unfold.false:
+; CHECK-NEXT: [[DOTSI_UNFOLD_PHI4:%.*]] = phi i32 [ 0, [[DOT6_SI_UNFOLD_TRUE]] ]
+; CHECK-NEXT: br label [[CLEANUP87]]
+; CHECK: cleanup87:
+; CHECK-NEXT: [[CLEANUP_DEST_SLOT_3:%.*]] = phi i32 [ [[SPEC_SELECT1_SI_UNFOLD_PHI]], [[SPEC_SELECT_SI_UNFOLD_FALSE]] ], [ [[DOTSI_UNFOLD_PHI3]], [[DOT6_SI_UNFOLD_TRUE]] ], [ [[DOTSI_UNFOLD_PHI4]], [[DOT6_SI_UNFOLD_FALSE]] ]
+; CHECK-NEXT: switch i32 [[CLEANUP_DEST_SLOT_3]], label [[FOR_COND48_BACKEDGE:%.*]] [
+; CHECK-NEXT: i32 0, label [[FOR_COND48_BACKEDGE]]
+; CHECK-NEXT: i32 1, label [[FOR_COND48_BACKEDGE]]
+; CHECK-NEXT: ]
+; CHECK: cleanup87.jt0:
+; CHECK-NEXT: [[CLEANUP_DEST_SLOT_3_JT0:%.*]] = phi i32 [ 0, [[FOR_COND48]] ], [ [[SPEC_SELECT1_SI_UNFOLD_PHI_JT0]], [[SPEC_SELECT_SI_UNFOLD_FALSE_JT0]] ]
+; CHECK-NEXT: br label [[FOR_COND48_BACKEDGE]]
+; CHECK: for.cond48.backedge:
+; CHECK-NEXT: br label [[FOR_COND48]]
+;
+entry:
+ %.5 = select i1 false, i32 0, i32 0
+ %.6 = select i1 false, i32 0, i32 0
+ br label %for.cond48
+
+for.cond48: ; preds = %for.cond48.backedge, %entry
+ br i1 false, label %cleanup87, label %if.else
+
+if.else: ; preds = %for.cond48
+ %spec.select1 = select i1 false, i32 %.5, i32 0
+ %spec.select = select i1 false, i32 %.6, i32 %spec.select1
+ br label %cleanup87
+
+cleanup87: ; preds = %if.else, %for.cond48
+ %cleanup.dest.slot.3 = phi i32 [ 0, %for.cond48 ], [ %spec.select, %if.else ]
+ switch i32 %cleanup.dest.slot.3, label %for.cond48.backedge [
+ i32 0, label %for.cond48.backedge
+ i32 1, label %for.cond48.backedge
+ ]
+
+for.cond48.backedge: ; preds = %cleanup87, %cleanup87, %cleanup87
+ br label %for.cond48
+}
More information about the llvm-commits
mailing list