[llvm] [DFAJumpThreading] Unfold select to the incoming block of phi user (PR #160987)
via llvm-commits
llvm-commits at lists.llvm.org
Sat Sep 27 00:25:32 PDT 2025
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-llvm-transforms
Author: Hongyu Chen (XChy)
<details>
<summary>Changes</summary>
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.
---
Full diff: https://github.com/llvm/llvm-project/pull/160987.diff
3 Files Affected:
- (modified) llvm/lib/Transforms/Scalar/DFAJumpThreading.cpp (+6-4)
- (modified) llvm/test/Transforms/DFAJumpThreading/dfa-jump-threading-transform.ll (+22-18)
- (modified) llvm/test/Transforms/DFAJumpThreading/dfa-unfold-select.ll (+70)
``````````diff
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
+}
``````````
</details>
https://github.com/llvm/llvm-project/pull/160987
More information about the llvm-commits
mailing list