[ScalarEvolution] Fold %x umin_seq %y if %x cannot be zero

Fold %x umin_seq %y to %x umin %y if %x cannot be zero. They only
differ in semantics for %x==0.

More generally %x *_seq %y folds to %x * %y if %x cannot be the
saturation fold (though currently we only have umin_seq).
This commit is contained in:
Nikita Popov 2022-05-09 15:01:27 +02:00
parent ec6024d081
commit 18eaff1510
2 changed files with 19 additions and 7 deletions

View File

@ -4129,10 +4129,22 @@ ScalarEvolution::getSequentialMinMaxExpr(SCEVTypes Kind,
return getSequentialMinMaxExpr(Kind, Ops); return getSequentialMinMaxExpr(Kind, Ops);
} }
// In %x umin_seq %y, if %y being poison implies %x is also poison, we can const SCEV *SaturationPoint;
// use a non-sequential umin instead. switch (Kind) {
case scSequentialUMinExpr:
SaturationPoint = getZero(Ops[0]->getType());
break;
default:
llvm_unreachable("Not a sequential min/max type.");
}
// We can replace %x umin_seq %y with %x umin %y if either:
// * %y being poison implies %x is also poison.
// * %x cannot be the saturating value (e.g. zero for umin).
for (unsigned i = 1, e = Ops.size(); i != e; ++i) { for (unsigned i = 1, e = Ops.size(); i != e; ++i) {
if (::impliesPoison(Ops[i], Ops[i - 1])) { if (::impliesPoison(Ops[i], Ops[i - 1]) ||
isKnownViaNonRecursiveReasoning(ICmpInst::ICMP_NE, Ops[i - 1],
SaturationPoint)) {
SmallVector<const SCEV *> SeqOps = {Ops[i - 1], Ops[i]}; SmallVector<const SCEV *> SeqOps = {Ops[i - 1], Ops[i]};
Ops[i - 1] = getMinMaxExpr( Ops[i - 1] = getMinMaxExpr(
SCEVSequentialMinMaxExpr::getEquivalentNonSequentialSCEVType(Kind), SCEVSequentialMinMaxExpr::getEquivalentNonSequentialSCEVType(Kind),

View File

@ -954,15 +954,15 @@ define i32 @logical_and_not_zero(i16 %n, i32 %m) {
; CHECK-NEXT: %n1 = add i32 %n.ext, 1 ; CHECK-NEXT: %n1 = add i32 %n.ext, 1
; CHECK-NEXT: --> (1 + (zext i16 %n to i32))<nuw><nsw> U: [1,65537) S: [1,65537) ; CHECK-NEXT: --> (1 + (zext i16 %n to i32))<nuw><nsw> U: [1,65537) S: [1,65537)
; CHECK-NEXT: %i = phi i32 [ 0, %entry ], [ %i.next, %loop ] ; CHECK-NEXT: %i = phi i32 [ 0, %entry ], [ %i.next, %loop ]
; CHECK-NEXT: --> {0,+,1}<%loop> U: [0,65537) S: [0,65537) Exits: ((1 + (zext i16 %n to i32))<nuw><nsw> umin_seq %m) LoopDispositions: { %loop: Computable } ; CHECK-NEXT: --> {0,+,1}<%loop> U: [0,65537) S: [0,65537) Exits: ((1 + (zext i16 %n to i32))<nuw><nsw> umin %m) LoopDispositions: { %loop: Computable }
; CHECK-NEXT: %i.next = add i32 %i, 1 ; CHECK-NEXT: %i.next = add i32 %i, 1
; CHECK-NEXT: --> {1,+,1}<%loop> U: [1,65538) S: [1,65538) Exits: (1 + ((1 + (zext i16 %n to i32))<nuw><nsw> umin_seq %m))<nuw><nsw> LoopDispositions: { %loop: Computable } ; CHECK-NEXT: --> {1,+,1}<%loop> U: [1,65538) S: [1,65538) Exits: (1 + ((1 + (zext i16 %n to i32))<nuw><nsw> umin %m))<nuw><nsw> LoopDispositions: { %loop: Computable }
; CHECK-NEXT: %cond = select i1 %cond_p0, i1 %cond_p1, i1 false ; CHECK-NEXT: %cond = select i1 %cond_p0, i1 %cond_p1, i1 false
; CHECK-NEXT: --> (%cond_p0 umin_seq %cond_p1) U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop: Variant } ; CHECK-NEXT: --> (%cond_p0 umin_seq %cond_p1) U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop: Variant }
; CHECK-NEXT: Determining loop execution counts for: @logical_and_not_zero ; CHECK-NEXT: Determining loop execution counts for: @logical_and_not_zero
; CHECK-NEXT: Loop %loop: backedge-taken count is ((1 + (zext i16 %n to i32))<nuw><nsw> umin_seq %m) ; CHECK-NEXT: Loop %loop: backedge-taken count is ((1 + (zext i16 %n to i32))<nuw><nsw> umin %m)
; CHECK-NEXT: Loop %loop: max backedge-taken count is 65536 ; CHECK-NEXT: Loop %loop: max backedge-taken count is 65536
; CHECK-NEXT: Loop %loop: Predicated backedge-taken count is ((1 + (zext i16 %n to i32))<nuw><nsw> umin_seq %m) ; CHECK-NEXT: Loop %loop: Predicated backedge-taken count is ((1 + (zext i16 %n to i32))<nuw><nsw> umin %m)
; CHECK-NEXT: Predicates: ; CHECK-NEXT: Predicates:
; CHECK: Loop %loop: Trip multiple is 1 ; CHECK: Loop %loop: Trip multiple is 1
; ;