diff --git a/llvm/lib/Analysis/ScalarEvolution.cpp b/llvm/lib/Analysis/ScalarEvolution.cpp --- a/llvm/lib/Analysis/ScalarEvolution.cpp +++ b/llvm/lib/Analysis/ScalarEvolution.cpp @@ -2397,6 +2397,17 @@ Ops[0]->isZero() && IsKnownNonNegative(Ops[1])) Flags = ScalarEvolution::setFlags(Flags, SCEV::FlagNUW); + // both (udiv X, Y) * Y and Y * (udiv X, Y) are always NUW + if (Type == scMulExpr && !ScalarEvolution::hasFlags(Flags, SCEV::FlagNUW) && + Ops.size() == 2) { + if (auto *UDiv = dyn_cast(Ops[0])) + if (UDiv->getOperand(1) == Ops[1]) + Flags = ScalarEvolution::setFlags(Flags, SCEV::FlagNUW); + if (auto *UDiv = dyn_cast(Ops[1])) + if (UDiv->getOperand(1) == Ops[0]) + Flags = ScalarEvolution::setFlags(Flags, SCEV::FlagNUW); + } + return Flags; } diff --git a/llvm/test/Analysis/ScalarEvolution/extract-highbits-variablemask.ll b/llvm/test/Analysis/ScalarEvolution/extract-highbits-variablemask.ll --- a/llvm/test/Analysis/ScalarEvolution/extract-highbits-variablemask.ll +++ b/llvm/test/Analysis/ScalarEvolution/extract-highbits-variablemask.ll @@ -10,7 +10,7 @@ ; CHECK-NEXT: %tmp1 = udiv i32 %val, %num ; CHECK-NEXT: --> (%val /u %num) U: full-set S: full-set ; CHECK-NEXT: %tmp2 = mul i32 %tmp1, %num -; CHECK-NEXT: --> ((%val /u %num) * %num) U: full-set S: full-set +; CHECK-NEXT: --> ((%val /u %num) * %num) U: full-set S: full-set ; CHECK-NEXT: Determining loop execution counts for: @div ; %tmp1 = udiv i32 %val, %num diff --git a/llvm/test/Analysis/ScalarEvolution/max-be-count-not-constant.ll b/llvm/test/Analysis/ScalarEvolution/max-be-count-not-constant.ll --- a/llvm/test/Analysis/ScalarEvolution/max-be-count-not-constant.ll +++ b/llvm/test/Analysis/ScalarEvolution/max-be-count-not-constant.ll @@ -16,9 +16,9 @@ ; CHECK-NEXT: %tmp1 = add nsw i32 %tmp, 2 ; CHECK-NEXT: --> (2 + %tmp) U: [1,3) S: [1,3) ; CHECK-NEXT: %tmp3 = phi i32 [ 0, %bb ], [ %tmp4, %bb2 ] -; CHECK-NEXT: --> {0,+,(2 + %tmp)}<%bb2> U: [0,3) S: [0,3) Exits: ((2 + %tmp) * (1 /u (2 + %tmp))) LoopDispositions: { %bb2: Computable } +; CHECK-NEXT: --> {0,+,(2 + %tmp)}<%bb2> U: [0,3) S: [0,3) Exits: ((2 + %tmp) * (1 /u (2 + %tmp))) LoopDispositions: { %bb2: Computable } ; CHECK-NEXT: %tmp4 = add nuw nsw i32 %tmp1, %tmp3 -; CHECK-NEXT: --> {(2 + %tmp),+,(2 + %tmp)}<%bb2> U: [1,5) S: [1,5) Exits: (2 + ((2 + %tmp) * (1 /u (2 + %tmp))) + %tmp) LoopDispositions: { %bb2: Computable } +; CHECK-NEXT: --> {(2 + %tmp),+,(2 + %tmp)}<%bb2> U: [1,5) S: [1,5) Exits: (2 + ((2 + %tmp) * (1 /u (2 + %tmp))) + %tmp) LoopDispositions: { %bb2: Computable } ; CHECK-NEXT: Determining loop execution counts for: @pluto ; CHECK-NEXT: Loop %bb2: backedge-taken count is (1 /u (2 + %tmp)) ; CHECK-NEXT: Loop %bb2: max backedge-taken count is 1 diff --git a/llvm/test/Analysis/ScalarEvolution/mul.ll b/llvm/test/Analysis/ScalarEvolution/mul.ll --- a/llvm/test/Analysis/ScalarEvolution/mul.ll +++ b/llvm/test/Analysis/ScalarEvolution/mul.ll @@ -7,7 +7,7 @@ ; CHECK-NEXT: %udiv = udiv i8 %x, %y ; CHECK-NEXT: --> (%x /u %y) U: full-set S: full-set ; CHECK-NEXT: %res = mul i8 %udiv, %y -; CHECK-NEXT: --> ((%x /u %y) * %y) U: full-set S: full-set +; CHECK-NEXT: --> ((%x /u %y) * %y) U: full-set S: full-set ; CHECK-NEXT: Determining loop execution counts for: @test ; %udiv = udiv i8 %x, %y @@ -65,7 +65,7 @@ ; CHECK-NEXT: %udiv = udiv i8 %x, %y ; CHECK-NEXT: --> (%x /u (trunc i32 %y32 to i8)) U: full-set S: full-set ; CHECK-NEXT: %res = mul i8 %udiv, %y -; CHECK-NEXT: --> ((trunc i32 %y32 to i8) * (%x /u (trunc i32 %y32 to i8))) U: full-set S: full-set +; CHECK-NEXT: --> ((trunc i32 %y32 to i8) * (%x /u (trunc i32 %y32 to i8))) U: full-set S: full-set ; CHECK-NEXT: Determining loop execution counts for: @test5 ; %y = trunc i32 %y32 to i8