Skip to content

Commit 47c559d

Browse files
committed
[SCEV] Fold umin_seq to umin using implied poison reasoning
Similar to how we convert logical and/or to bitwise and/or, we should also convert umin_seq to umin based on implied poison reasoning. In %x umin_seq %y, if %y being poison implies %x being poison, then we don't need the sequential evaluation: Having %y contribute towards the result will never make the result more poisonous. An important corollary of this is that if %y is never poison, we also don't need the sequential evaluation. This avoids some of the regressions in D124910. Differential Revision: https://reviews.llvm.org/D124921
1 parent f416e57 commit 47c559d

File tree

2 files changed

+98
-32
lines changed

2 files changed

+98
-32
lines changed

llvm/lib/Analysis/ScalarEvolution.cpp

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4015,6 +4015,59 @@ class SCEVSequentialMinMaxDeduplicatingVisitor final
40154015

40164016
} // namespace
40174017

4018+
/// Return true if V is poison given that AssumedPoison is already poison.
4019+
static bool impliesPoison(const SCEV *AssumedPoison, const SCEV *S) {
4020+
// The only way poison may be introduced in a SCEV expression is from a
4021+
// poison SCEVUnknown (ConstantExprs are also represented as SCEVUnknown,
4022+
// not SCEVConstant). Notably, nowrap flags in SCEV nodes can *not*
4023+
// introduce poison -- they encode guaranteed, non-speculated knowledge.
4024+
//
4025+
// Additionally, all SCEV nodes propagate poison from inputs to outputs,
4026+
// with the notable exception of umin_seq, where only poison from the first
4027+
// operand is (unconditionally) propagated.
4028+
struct SCEVPoisonCollector {
4029+
bool LookThroughSeq;
4030+
SmallPtrSet<const SCEV *, 4> MaybePoison;
4031+
SCEVPoisonCollector(bool LookThroughSeq) : LookThroughSeq(LookThroughSeq) {}
4032+
4033+
bool follow(const SCEV *S) {
4034+
// TODO: We can always follow the first operand, but the SCEVTraversal
4035+
// API doesn't support this.
4036+
if (!LookThroughSeq && isa<SCEVSequentialMinMaxExpr>(S))
4037+
return false;
4038+
4039+
if (auto *SU = dyn_cast<SCEVUnknown>(S)) {
4040+
if (!isGuaranteedNotToBePoison(SU->getValue()))
4041+
MaybePoison.insert(S);
4042+
}
4043+
return true;
4044+
}
4045+
bool isDone() const { return false; }
4046+
};
4047+
4048+
// First collect all SCEVs that might result in AssumedPoison to be poison.
4049+
// We need to look through umin_seq here, because we want to find all SCEVs
4050+
// that *might* result in poison, not only those that are *required* to.
4051+
SCEVPoisonCollector PC1(/* LookThroughSeq */ true);
4052+
visitAll(AssumedPoison, PC1);
4053+
4054+
// AssumedPoison is never poison. As the assumption is false, the implication
4055+
// is true. Don't bother walking the other SCEV in this case.
4056+
if (PC1.MaybePoison.empty())
4057+
return true;
4058+
4059+
// Collect all SCEVs in S that, if poison, *will* result in S being poison
4060+
// as well. We cannot look through umin_seq here, as its argument only *may*
4061+
// make the result poison.
4062+
SCEVPoisonCollector PC2(/* LookThroughSeq */ false);
4063+
visitAll(S, PC2);
4064+
4065+
// Make sure that no matter which SCEV in PC1.MaybePoison is actually poison,
4066+
// it will also make S poison by being part of PC2.MaybePoison.
4067+
return all_of(PC1.MaybePoison,
4068+
[&](const SCEV *S) { return PC2.MaybePoison.contains(S); });
4069+
}
4070+
40184071
const SCEV *
40194072
ScalarEvolution::getSequentialMinMaxExpr(SCEVTypes Kind,
40204073
SmallVectorImpl<const SCEV *> &Ops) {
@@ -4076,6 +4129,19 @@ ScalarEvolution::getSequentialMinMaxExpr(SCEVTypes Kind,
40764129
return getSequentialMinMaxExpr(Kind, Ops);
40774130
}
40784131

4132+
// In %x umin_seq %y, if %y being poison implies %x is also poison, we can
4133+
// use a non-sequential umin instead.
4134+
for (unsigned i = 1, e = Ops.size(); i != e; ++i) {
4135+
if (::impliesPoison(Ops[i], Ops[i - 1])) {
4136+
SmallVector<const SCEV *> SeqOps = {Ops[i - 1], Ops[i]};
4137+
Ops[i - 1] = getMinMaxExpr(
4138+
SCEVSequentialMinMaxExpr::getEquivalentNonSequentialSCEVType(Kind),
4139+
SeqOps);
4140+
Ops.erase(Ops.begin() + i);
4141+
return getSequentialMinMaxExpr(Kind, Ops);
4142+
}
4143+
}
4144+
40794145
// Okay, it looks like we really DO need an expr. Check to see if we
40804146
// already have one, otherwise create a new one.
40814147
FoldingSetNodeID ID;

llvm/test/Analysis/ScalarEvolution/exit-count-select-safe.ll

Lines changed: 32 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -553,15 +553,15 @@ define i32 @logical_and_implies_poison1(i32 %n) {
553553
; CHECK-NEXT: %add = add i32 %n, 1
554554
; CHECK-NEXT: --> (1 + %n) U: full-set S: full-set
555555
; CHECK-NEXT: %i = phi i32 [ 0, %entry ], [ %i.next, %loop ]
556-
; CHECK-NEXT: --> {0,+,1}<%loop> U: full-set S: full-set Exits: (%n umin_seq (1 + %n)) LoopDispositions: { %loop: Computable }
556+
; CHECK-NEXT: --> {0,+,1}<%loop> U: full-set S: full-set Exits: ((1 + %n) umin %n) LoopDispositions: { %loop: Computable }
557557
; CHECK-NEXT: %i.next = add i32 %i, 1
558-
; CHECK-NEXT: --> {1,+,1}<%loop> U: full-set S: full-set Exits: (1 + (%n umin_seq (1 + %n))) LoopDispositions: { %loop: Computable }
558+
; CHECK-NEXT: --> {1,+,1}<%loop> U: full-set S: full-set Exits: (1 + ((1 + %n) umin %n)) LoopDispositions: { %loop: Computable }
559559
; CHECK-NEXT: %cond = select i1 %cond_p0, i1 %cond_p1, i1 false
560560
; CHECK-NEXT: --> (%cond_p0 umin_seq %cond_p1) U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop: Variant }
561561
; CHECK-NEXT: Determining loop execution counts for: @logical_and_implies_poison1
562-
; CHECK-NEXT: Loop %loop: backedge-taken count is (%n umin_seq (1 + %n))
562+
; CHECK-NEXT: Loop %loop: backedge-taken count is ((1 + %n) umin %n)
563563
; CHECK-NEXT: Loop %loop: max backedge-taken count is -1
564-
; CHECK-NEXT: Loop %loop: Predicated backedge-taken count is (%n umin_seq (1 + %n))
564+
; CHECK-NEXT: Loop %loop: Predicated backedge-taken count is ((1 + %n) umin %n)
565565
; CHECK-NEXT: Predicates:
566566
; CHECK: Loop %loop: Trip multiple is 1
567567
;
@@ -585,15 +585,15 @@ define i32 @logical_and_implies_poison2(i32 %n) {
585585
; CHECK-NEXT: %add = add i32 %n, 1
586586
; CHECK-NEXT: --> (1 + %n) U: full-set S: full-set
587587
; CHECK-NEXT: %i = phi i32 [ 0, %entry ], [ %i.next, %loop ]
588-
; CHECK-NEXT: --> {0,+,1}<%loop> U: full-set S: full-set Exits: ((1 + %n) umin_seq %n) LoopDispositions: { %loop: Computable }
588+
; CHECK-NEXT: --> {0,+,1}<%loop> U: full-set S: full-set Exits: ((1 + %n) umin %n) LoopDispositions: { %loop: Computable }
589589
; CHECK-NEXT: %i.next = add i32 %i, 1
590-
; CHECK-NEXT: --> {1,+,1}<%loop> U: full-set S: full-set Exits: (1 + ((1 + %n) umin_seq %n)) LoopDispositions: { %loop: Computable }
590+
; CHECK-NEXT: --> {1,+,1}<%loop> U: full-set S: full-set Exits: (1 + ((1 + %n) umin %n)) LoopDispositions: { %loop: Computable }
591591
; CHECK-NEXT: %cond = select i1 %cond_p0, i1 %cond_p1, i1 false
592592
; CHECK-NEXT: --> (%cond_p0 umin_seq %cond_p1) U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop: Variant }
593593
; CHECK-NEXT: Determining loop execution counts for: @logical_and_implies_poison2
594-
; CHECK-NEXT: Loop %loop: backedge-taken count is ((1 + %n) umin_seq %n)
594+
; CHECK-NEXT: Loop %loop: backedge-taken count is ((1 + %n) umin %n)
595595
; CHECK-NEXT: Loop %loop: max backedge-taken count is -1
596-
; CHECK-NEXT: Loop %loop: Predicated backedge-taken count is ((1 + %n) umin_seq %n)
596+
; CHECK-NEXT: Loop %loop: Predicated backedge-taken count is ((1 + %n) umin %n)
597597
; CHECK-NEXT: Predicates:
598598
; CHECK: Loop %loop: Trip multiple is 1
599599
;
@@ -617,15 +617,15 @@ define i32 @logical_and_implies_poison3(i32 %n, i32 %m) {
617617
; CHECK-NEXT: %add = add i32 %n, %m
618618
; CHECK-NEXT: --> (%n + %m) U: full-set S: full-set
619619
; CHECK-NEXT: %i = phi i32 [ 0, %entry ], [ %i.next, %loop ]
620-
; CHECK-NEXT: --> {0,+,1}<%loop> U: full-set S: full-set Exits: ((%n + %m) umin_seq %n) LoopDispositions: { %loop: Computable }
620+
; CHECK-NEXT: --> {0,+,1}<%loop> U: full-set S: full-set Exits: ((%n + %m) umin %n) LoopDispositions: { %loop: Computable }
621621
; CHECK-NEXT: %i.next = add i32 %i, 1
622-
; CHECK-NEXT: --> {1,+,1}<%loop> U: full-set S: full-set Exits: (1 + ((%n + %m) umin_seq %n)) LoopDispositions: { %loop: Computable }
622+
; CHECK-NEXT: --> {1,+,1}<%loop> U: full-set S: full-set Exits: (1 + ((%n + %m) umin %n)) LoopDispositions: { %loop: Computable }
623623
; CHECK-NEXT: %cond = select i1 %cond_p0, i1 %cond_p1, i1 false
624624
; CHECK-NEXT: --> (%cond_p0 umin_seq %cond_p1) U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop: Variant }
625625
; CHECK-NEXT: Determining loop execution counts for: @logical_and_implies_poison3
626-
; CHECK-NEXT: Loop %loop: backedge-taken count is ((%n + %m) umin_seq %n)
626+
; CHECK-NEXT: Loop %loop: backedge-taken count is ((%n + %m) umin %n)
627627
; CHECK-NEXT: Loop %loop: max backedge-taken count is -1
628-
; CHECK-NEXT: Loop %loop: Predicated backedge-taken count is ((%n + %m) umin_seq %n)
628+
; CHECK-NEXT: Loop %loop: Predicated backedge-taken count is ((%n + %m) umin %n)
629629
; CHECK-NEXT: Predicates:
630630
; CHECK: Loop %loop: Trip multiple is 1
631631
;
@@ -679,15 +679,15 @@ define i32 @logical_and_implies_poison_noundef(i32 %n, i32 noundef %m) {
679679
; CHECK-LABEL: 'logical_and_implies_poison_noundef'
680680
; CHECK-NEXT: Classifying expressions for: @logical_and_implies_poison_noundef
681681
; CHECK-NEXT: %i = phi i32 [ 0, %entry ], [ %i.next, %loop ]
682-
; CHECK-NEXT: --> {0,+,1}<%loop> U: full-set S: full-set Exits: (%n umin_seq %m) LoopDispositions: { %loop: Computable }
682+
; CHECK-NEXT: --> {0,+,1}<%loop> U: full-set S: full-set Exits: (%n umin %m) LoopDispositions: { %loop: Computable }
683683
; CHECK-NEXT: %i.next = add i32 %i, 1
684-
; CHECK-NEXT: --> {1,+,1}<%loop> U: full-set S: full-set Exits: (1 + (%n umin_seq %m)) LoopDispositions: { %loop: Computable }
684+
; CHECK-NEXT: --> {1,+,1}<%loop> U: full-set S: full-set Exits: (1 + (%n umin %m)) LoopDispositions: { %loop: Computable }
685685
; CHECK-NEXT: %cond = select i1 %cond_p0, i1 %cond_p1, i1 false
686686
; CHECK-NEXT: --> (%cond_p0 umin_seq %cond_p1) U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop: Variant }
687687
; CHECK-NEXT: Determining loop execution counts for: @logical_and_implies_poison_noundef
688-
; CHECK-NEXT: Loop %loop: backedge-taken count is (%n umin_seq %m)
688+
; CHECK-NEXT: Loop %loop: backedge-taken count is (%n umin %m)
689689
; CHECK-NEXT: Loop %loop: max backedge-taken count is -1
690-
; CHECK-NEXT: Loop %loop: Predicated backedge-taken count is (%n umin_seq %m)
690+
; CHECK-NEXT: Loop %loop: Predicated backedge-taken count is (%n umin %m)
691691
; CHECK-NEXT: Predicates:
692692
; CHECK: Loop %loop: Trip multiple is 1
693693
;
@@ -741,15 +741,15 @@ define i32 @logical_and_implies_poison_complex1(i32 %n, i32 %m) {
741741
; CHECK-NEXT: %add1 = add i32 %add, 1
742742
; CHECK-NEXT: --> (1 + %n + %m) U: full-set S: full-set
743743
; CHECK-NEXT: %i = phi i32 [ 0, %entry ], [ %i.next, %loop ]
744-
; CHECK-NEXT: --> {0,+,1}<%loop> U: full-set S: full-set Exits: ((1 + %n + %m) umin_seq (%n + %m)) LoopDispositions: { %loop: Computable }
744+
; CHECK-NEXT: --> {0,+,1}<%loop> U: full-set S: full-set Exits: ((%n + %m) umin (1 + %n + %m)) LoopDispositions: { %loop: Computable }
745745
; CHECK-NEXT: %i.next = add i32 %i, 1
746-
; CHECK-NEXT: --> {1,+,1}<%loop> U: full-set S: full-set Exits: (1 + ((1 + %n + %m) umin_seq (%n + %m))) LoopDispositions: { %loop: Computable }
746+
; CHECK-NEXT: --> {1,+,1}<%loop> U: full-set S: full-set Exits: (1 + ((%n + %m) umin (1 + %n + %m))) LoopDispositions: { %loop: Computable }
747747
; CHECK-NEXT: %cond = select i1 %cond_p0, i1 %cond_p1, i1 false
748748
; CHECK-NEXT: --> (%cond_p0 umin_seq %cond_p1) U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop: Variant }
749749
; CHECK-NEXT: Determining loop execution counts for: @logical_and_implies_poison_complex1
750-
; CHECK-NEXT: Loop %loop: backedge-taken count is ((1 + %n + %m) umin_seq (%n + %m))
750+
; CHECK-NEXT: Loop %loop: backedge-taken count is ((%n + %m) umin (1 + %n + %m))
751751
; CHECK-NEXT: Loop %loop: max backedge-taken count is -1
752-
; CHECK-NEXT: Loop %loop: Predicated backedge-taken count is ((1 + %n + %m) umin_seq (%n + %m))
752+
; CHECK-NEXT: Loop %loop: Predicated backedge-taken count is ((%n + %m) umin (1 + %n + %m))
753753
; CHECK-NEXT: Predicates:
754754
; CHECK: Loop %loop: Trip multiple is 1
755755
;
@@ -776,15 +776,15 @@ define i32 @logical_and_implies_poison_complex2(i32 %n, i32 %m, i32 %l) {
776776
; CHECK-NEXT: %add1 = add i32 %add, %l
777777
; CHECK-NEXT: --> (%n + %m + %l) U: full-set S: full-set
778778
; CHECK-NEXT: %i = phi i32 [ 0, %entry ], [ %i.next, %loop ]
779-
; CHECK-NEXT: --> {0,+,1}<%loop> U: full-set S: full-set Exits: ((%n + %m + %l) umin_seq (%n + %m)) LoopDispositions: { %loop: Computable }
779+
; CHECK-NEXT: --> {0,+,1}<%loop> U: full-set S: full-set Exits: ((%n + %m) umin (%n + %m + %l)) LoopDispositions: { %loop: Computable }
780780
; CHECK-NEXT: %i.next = add i32 %i, 1
781-
; CHECK-NEXT: --> {1,+,1}<%loop> U: full-set S: full-set Exits: (1 + ((%n + %m + %l) umin_seq (%n + %m))) LoopDispositions: { %loop: Computable }
781+
; CHECK-NEXT: --> {1,+,1}<%loop> U: full-set S: full-set Exits: (1 + ((%n + %m) umin (%n + %m + %l))) LoopDispositions: { %loop: Computable }
782782
; CHECK-NEXT: %cond = select i1 %cond_p0, i1 %cond_p1, i1 false
783783
; CHECK-NEXT: --> (%cond_p0 umin_seq %cond_p1) U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop: Variant }
784784
; CHECK-NEXT: Determining loop execution counts for: @logical_and_implies_poison_complex2
785-
; CHECK-NEXT: Loop %loop: backedge-taken count is ((%n + %m + %l) umin_seq (%n + %m))
785+
; CHECK-NEXT: Loop %loop: backedge-taken count is ((%n + %m) umin (%n + %m + %l))
786786
; CHECK-NEXT: Loop %loop: max backedge-taken count is -1
787-
; CHECK-NEXT: Loop %loop: Predicated backedge-taken count is ((%n + %m + %l) umin_seq (%n + %m))
787+
; CHECK-NEXT: Loop %loop: Predicated backedge-taken count is ((%n + %m) umin (%n + %m + %l))
788788
; CHECK-NEXT: Predicates:
789789
; CHECK: Loop %loop: Trip multiple is 1
790790
;
@@ -844,17 +844,17 @@ define i32 @logical_and_implies_multiple_ops(i32 %n, i32 %m) {
844844
; CHECK-NEXT: %add = add i32 %n, 1
845845
; CHECK-NEXT: --> (1 + %n) U: full-set S: full-set
846846
; CHECK-NEXT: %i = phi i32 [ 0, %entry ], [ %i.next, %loop ]
847-
; CHECK-NEXT: --> {0,+,1}<%loop> U: full-set S: full-set Exits: (%n umin_seq (1 + %n) umin_seq %m) LoopDispositions: { %loop: Computable }
847+
; CHECK-NEXT: --> {0,+,1}<%loop> U: full-set S: full-set Exits: (((1 + %n) umin %n) umin_seq %m) LoopDispositions: { %loop: Computable }
848848
; CHECK-NEXT: %i.next = add i32 %i, 1
849-
; CHECK-NEXT: --> {1,+,1}<%loop> U: full-set S: full-set Exits: (1 + (%n umin_seq (1 + %n) umin_seq %m)) LoopDispositions: { %loop: Computable }
849+
; CHECK-NEXT: --> {1,+,1}<%loop> U: full-set S: full-set Exits: (1 + (((1 + %n) umin %n) umin_seq %m)) LoopDispositions: { %loop: Computable }
850850
; CHECK-NEXT: %cond = select i1 %cond_p0, i1 %cond_p1, i1 false
851851
; CHECK-NEXT: --> (%cond_p0 umin_seq %cond_p1) U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop: Variant }
852852
; CHECK-NEXT: %cond2 = select i1 %cond, i1 %cond_p2, i1 false
853853
; CHECK-NEXT: --> (%cond_p0 umin_seq %cond_p1 umin_seq %cond_p2) U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop: Variant }
854854
; CHECK-NEXT: Determining loop execution counts for: @logical_and_implies_multiple_ops
855-
; CHECK-NEXT: Loop %loop: backedge-taken count is (%n umin_seq (1 + %n) umin_seq %m)
855+
; CHECK-NEXT: Loop %loop: backedge-taken count is (((1 + %n) umin %n) umin_seq %m)
856856
; CHECK-NEXT: Loop %loop: max backedge-taken count is -1
857-
; CHECK-NEXT: Loop %loop: Predicated backedge-taken count is (%n umin_seq (1 + %n) umin_seq %m)
857+
; CHECK-NEXT: Loop %loop: Predicated backedge-taken count is (((1 + %n) umin %n) umin_seq %m)
858858
; CHECK-NEXT: Predicates:
859859
; CHECK: Loop %loop: Trip multiple is 1
860860
;
@@ -916,17 +916,17 @@ define i32 @logical_and_implies_multiple_ops3(i32 %n, i32 %m) {
916916
; CHECK-NEXT: %add = add i32 %n, 1
917917
; CHECK-NEXT: --> (1 + %n) U: full-set S: full-set
918918
; CHECK-NEXT: %i = phi i32 [ 0, %entry ], [ %i.next, %loop ]
919-
; CHECK-NEXT: --> {0,+,1}<%loop> U: full-set S: full-set Exits: (%m umin_seq %n umin_seq (1 + %n)) LoopDispositions: { %loop: Computable }
919+
; CHECK-NEXT: --> {0,+,1}<%loop> U: full-set S: full-set Exits: (%m umin_seq ((1 + %n) umin %n)) LoopDispositions: { %loop: Computable }
920920
; CHECK-NEXT: %i.next = add i32 %i, 1
921-
; CHECK-NEXT: --> {1,+,1}<%loop> U: full-set S: full-set Exits: (1 + (%m umin_seq %n umin_seq (1 + %n))) LoopDispositions: { %loop: Computable }
921+
; CHECK-NEXT: --> {1,+,1}<%loop> U: full-set S: full-set Exits: (1 + (%m umin_seq ((1 + %n) umin %n))) LoopDispositions: { %loop: Computable }
922922
; CHECK-NEXT: %cond = select i1 %cond_p0, i1 %cond_p1, i1 false
923923
; CHECK-NEXT: --> (%cond_p0 umin_seq %cond_p1) U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop: Variant }
924924
; CHECK-NEXT: %cond2 = select i1 %cond, i1 %cond_p2, i1 false
925925
; CHECK-NEXT: --> (%cond_p0 umin_seq %cond_p1 umin_seq %cond_p2) U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop: Variant }
926926
; CHECK-NEXT: Determining loop execution counts for: @logical_and_implies_multiple_ops3
927-
; CHECK-NEXT: Loop %loop: backedge-taken count is (%m umin_seq %n umin_seq (1 + %n))
927+
; CHECK-NEXT: Loop %loop: backedge-taken count is (%m umin_seq ((1 + %n) umin %n))
928928
; CHECK-NEXT: Loop %loop: max backedge-taken count is -1
929-
; CHECK-NEXT: Loop %loop: Predicated backedge-taken count is (%m umin_seq %n umin_seq (1 + %n))
929+
; CHECK-NEXT: Loop %loop: Predicated backedge-taken count is (%m umin_seq ((1 + %n) umin %n))
930930
; CHECK-NEXT: Predicates:
931931
; CHECK: Loop %loop: Trip multiple is 1
932932
;

0 commit comments

Comments
 (0)