/// accordingly.
void addToLoopUseLists(const SCEV *S);
+ /// Try to match the pattern generated by getURemExpr(A, B). If successful,
+ /// Assign A and B to LHS and RHS, respectively.
+ bool matchURem(const SCEV *Expr, const SCEV *&LHS, const SCEV *&RHS);
+
FoldingSet<SCEV> UniqueSCEVs;
FoldingSet<SCEVPredicate> UniquePreds;
BumpPtrAllocator SCEVAllocator;
}
}
+ // zext(A % B) --> zext(A) % zext(B)
+ {
+ const SCEV *LHS;
+ const SCEV *RHS;
+ if (matchURem(Op, LHS, RHS))
+ return getURemExpr(getZeroExtendExpr(LHS, Ty, Depth + 1),
+ getZeroExtendExpr(RHS, Ty, Depth + 1));
+ }
+
+ // zext(A / B) --> zext(A) / zext(B).
+ if (auto *Div = dyn_cast<SCEVUDivExpr>(Op))
+ return getUDivExpr(getZeroExtendExpr(Div->getLHS(), Ty, Depth + 1),
+ getZeroExtendExpr(Div->getRHS(), Ty, Depth + 1));
+
if (auto *SA = dyn_cast<SCEVAddExpr>(Op)) {
// zext((A + B + ...)<nuw>) --> (zext(A) + zext(B) + ...)<nuw>
if (SA->hasNoUnsignedWrap()) {
OS.indent(Depth + 2) << "--> " << *II->second.second << "\n";
}
}
+
+// Match the mathematical pattern A - (A / B) * B, where A and B can be
+// arbitrary expressions.
+// It's not always easy, as A and B can be folded (imagine A is X / 2, and B is
+// 4, A / B becomes X / 8).
+bool ScalarEvolution::matchURem(const SCEV *Expr, const SCEV *&LHS,
+ const SCEV *&RHS) {
+ const auto *Add = dyn_cast<SCEVAddExpr>(Expr);
+ if (Add == nullptr || Add->getNumOperands() != 2)
+ return false;
+
+ const SCEV *A = Add->getOperand(1);
+ const auto *Mul = dyn_cast<SCEVMulExpr>(Add->getOperand(0));
+
+ if (Mul == nullptr)
+ return false;
+
+ const auto MatchURemWithDivisor = [&](const SCEV *B) {
+ // (SomeExpr + (-(SomeExpr / B) * B)).
+ if (Expr == getURemExpr(A, B)) {
+ LHS = A;
+ RHS = B;
+ return true;
+ }
+ return false;
+ };
+
+ // (SomeExpr + (-1 * (SomeExpr / B) * B)).
+ if (Mul->getNumOperands() == 3 && isa<SCEVConstant>(Mul->getOperand(0)))
+ return MatchURemWithDivisor(Mul->getOperand(1)) ||
+ MatchURemWithDivisor(Mul->getOperand(2));
+
+ // (SomeExpr + ((-SomeExpr / B) * B)) or (SomeExpr + ((SomeExpr / B) * -B)).
+ if (Mul->getNumOperands() == 2)
+ return MatchURemWithDivisor(Mul->getOperand(1)) ||
+ MatchURemWithDivisor(Mul->getOperand(0)) ||
+ MatchURemWithDivisor(getNegativeSCEV(Mul->getOperand(1))) ||
+ MatchURemWithDivisor(getNegativeSCEV(Mul->getOperand(0)));
+ return false;
+};
--- /dev/null
+; RUN: opt -analyze -scalar-evolution -S < %s | FileCheck %s
+
+define i64 @test1(i32 %a, i32 %b) {
+; CHECK-LABEL: @test1
+ %div = udiv i32 %a, %b
+ %zext = zext i32 %div to i64
+; CHECK: %zext
+; CHECK-NEXT: --> ((zext i32 %a to i64) /u (zext i32 %b to i64))
+ ret i64 %zext
+}
+
+define i64 @test2(i32 %a, i32 %b) {
+; CHECK-LABEL: @test2
+ %rem = urem i32 %a, %b
+ %zext = zext i32 %rem to i64
+; CHECK: %zext
+; CHECK-NEXT: --> ((zext i32 %a to i64) + (-1 * (zext i32 %b to i64) * ((zext i32 %a to i64) /u (zext i32 %b to i64))))
+ ret i64 %zext
+}
+
+define i64 @test3(i32 %a, i32 %b) {
+; CHECK-LABEL: @test3
+ %div = udiv i32 %a, %b
+ %mul = mul i32 %div, %b
+ %sub = sub i32 %a, %mul
+ %zext = zext i32 %sub to i64
+; CHECK: %zext
+; CHECK-NEXT: --> ((zext i32 %a to i64) + (-1 * (zext i32 %b to i64) * ((zext i32 %a to i64) /u (zext i32 %b to i64))))
+ ret i64 %zext
+}
+
+define i64 @test4(i32 %t) {
+; CHECK-LABEL: @test4
+ %a = udiv i32 %t, 2
+ %div = udiv i32 %t, 112
+ %mul = mul i32 %div, 56
+ %sub = sub i32 %a, %mul
+ %zext = zext i32 %sub to i64
+; CHECK: %zext
+; CHECK-NEXT: --> ((-56 * ((zext i32 %t to i64) /u 112)) + ((zext i32 %t to i64) /u 2))
+ ret i64 %zext
+}