forked from OSchip/llvm-project
[SCEV] Improve handling of not expressions in isImpliedCond()
SCEV currently tries to prove implications of x pred y by also trying to imply ~y pred ~x. This is expensive in terms of compile-time (in fact, the majority of isImpliedCond compile-time is spent here) and generally not fruitful. The issue is that this also swaps the operands and thus breaks canonical ordering. If originally we were trying to prove an implication like X > C1 -> Y > C2, then we'll now try to prove X > C1 -> C3 > ~Y, which will not work. The only real case where we can get some use out of this transform is if the original conditions were in the form X > C1 -> Y < C2, were then swapped to X > C1 -> C2 > Y and are then swapped again here to X > C1 -> ~Y > C3. As such, handle this at a higher level, where we are doing the swapping in the first place. There's four different ways that we can line up a predicate and a swapped predicate, so we use some heuristics to pick some profitable way. Because we now try this transform at a higher level (isImpliedCondOperands rather than isImpliedCondOperandsHelper), we can also prove additional facts. Of the added tests, one was proven previously while the other wasn't. Differential Revision: https://reviews.llvm.org/D90926
This commit is contained in:
parent
6427c53940
commit
a7efed5a20
|
@ -10341,11 +10341,26 @@ bool ScalarEvolution::isImpliedCondBalancedTypes(
|
||||||
// Check whether swapping the found predicate makes it the same as the
|
// Check whether swapping the found predicate makes it the same as the
|
||||||
// desired predicate.
|
// desired predicate.
|
||||||
if (ICmpInst::getSwappedPredicate(FoundPred) == Pred) {
|
if (ICmpInst::getSwappedPredicate(FoundPred) == Pred) {
|
||||||
if (isa<SCEVConstant>(RHS))
|
// We can write the implication
|
||||||
|
// 0. LHS Pred RHS <- FoundLHS SwapPred FoundRHS
|
||||||
|
// using one of the following ways:
|
||||||
|
// 1. LHS Pred RHS <- FoundRHS Pred FoundLHS
|
||||||
|
// 2. RHS SwapPred LHS <- FoundLHS SwapPred FoundRHS
|
||||||
|
// 3. LHS Pred RHS <- ~FoundLHS Pred ~FoundRHS
|
||||||
|
// 4. ~LHS SwapPred ~RHS <- FoundLHS SwapPred FoundRHS
|
||||||
|
// Forms 1. and 2. require swapping the operands of one condition. Don't
|
||||||
|
// do this if it would break canonical constant/addrec ordering.
|
||||||
|
if (!isa<SCEVConstant>(RHS) && !isa<SCEVAddRecExpr>(LHS))
|
||||||
|
return isImpliedCondOperands(FoundPred, RHS, LHS, FoundLHS, FoundRHS,
|
||||||
|
Context);
|
||||||
|
if (!isa<SCEVConstant>(FoundRHS) && !isa<SCEVAddRecExpr>(FoundLHS))
|
||||||
return isImpliedCondOperands(Pred, LHS, RHS, FoundRHS, FoundLHS, Context);
|
return isImpliedCondOperands(Pred, LHS, RHS, FoundRHS, FoundLHS, Context);
|
||||||
else
|
|
||||||
return isImpliedCondOperands(ICmpInst::getSwappedPredicate(Pred), RHS,
|
// There's no clear preference between forms 3. and 4., try both.
|
||||||
LHS, FoundLHS, FoundRHS, Context);
|
return isImpliedCondOperands(FoundPred, getNotSCEV(LHS), getNotSCEV(RHS),
|
||||||
|
FoundLHS, FoundRHS, Context) ||
|
||||||
|
isImpliedCondOperands(Pred, LHS, RHS, getNotSCEV(FoundLHS),
|
||||||
|
getNotSCEV(FoundRHS), Context);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unsigned comparison is the same as signed comparison when both the operands
|
// Unsigned comparison is the same as signed comparison when both the operands
|
||||||
|
@ -10768,11 +10783,7 @@ bool ScalarEvolution::isImpliedCondOperands(ICmpInst::Predicate Pred,
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
return isImpliedCondOperandsHelper(Pred, LHS, RHS,
|
return isImpliedCondOperandsHelper(Pred, LHS, RHS,
|
||||||
FoundLHS, FoundRHS) ||
|
FoundLHS, FoundRHS);
|
||||||
// ~x < ~y --> x > y
|
|
||||||
isImpliedCondOperandsHelper(Pred, LHS, RHS,
|
|
||||||
getNotSCEV(FoundRHS),
|
|
||||||
getNotSCEV(FoundLHS));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Is MaybeMinMaxExpr an (U|S)(Min|Max) of Candidate and some other values?
|
/// Is MaybeMinMaxExpr an (U|S)(Min|Max) of Candidate and some other values?
|
||||||
|
|
|
@ -15,7 +15,7 @@ bb.i: ; preds = %bb1.i, %bb.nph
|
||||||
|
|
||||||
; This cast shouldn't be folded into the addrec.
|
; This cast shouldn't be folded into the addrec.
|
||||||
; CHECK: %tmp = zext i8 %l_95.0.i1 to i16
|
; CHECK: %tmp = zext i8 %l_95.0.i1 to i16
|
||||||
; CHECK: --> (zext i8 {0,+,-1}<nw><%bb.i> to i16){{ U: [^ ]+ S: [^ ]+}}{{ *}}Exits: 2
|
; CHECK: --> (zext i8 {0,+,-1}<%bb.i> to i16){{ U: [^ ]+ S: [^ ]+}}{{ *}}Exits: 2
|
||||||
|
|
||||||
%tmp = zext i8 %l_95.0.i1 to i16
|
%tmp = zext i8 %l_95.0.i1 to i16
|
||||||
|
|
||||||
|
|
|
@ -68,6 +68,13 @@ protected:
|
||||||
const SCEV *&RHS) {
|
const SCEV *&RHS) {
|
||||||
return SE.matchURem(Expr, LHS, RHS);
|
return SE.matchURem(Expr, LHS, RHS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool isImpliedCond(
|
||||||
|
ScalarEvolution &SE, ICmpInst::Predicate Pred, const SCEV *LHS,
|
||||||
|
const SCEV *RHS, ICmpInst::Predicate FoundPred, const SCEV *FoundLHS,
|
||||||
|
const SCEV *FoundRHS) {
|
||||||
|
return SE.isImpliedCond(Pred, LHS, RHS, FoundPred, FoundLHS, FoundRHS);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
TEST_F(ScalarEvolutionsTest, SCEVUnknownRAUW) {
|
TEST_F(ScalarEvolutionsTest, SCEVUnknownRAUW) {
|
||||||
|
@ -1368,6 +1375,45 @@ TEST_F(ScalarEvolutionsTest, ProveImplicationViaNarrowing) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(ScalarEvolutionsTest, ImpliedCond) {
|
||||||
|
LLVMContext C;
|
||||||
|
SMDiagnostic Err;
|
||||||
|
std::unique_ptr<Module> M = parseAssemblyString(
|
||||||
|
"define void @foo(i32 %len) { "
|
||||||
|
"entry: "
|
||||||
|
" br label %loop "
|
||||||
|
"loop: "
|
||||||
|
" %iv = phi i32 [ 0, %entry], [%iv.next, %loop] "
|
||||||
|
" %iv.next = add nsw i32 %iv, 1 "
|
||||||
|
" %cmp = icmp slt i32 %iv, %len "
|
||||||
|
" br i1 %cmp, label %loop, label %exit "
|
||||||
|
"exit:"
|
||||||
|
" ret void "
|
||||||
|
"}",
|
||||||
|
Err, C);
|
||||||
|
|
||||||
|
ASSERT_TRUE(M && "Could not parse module?");
|
||||||
|
ASSERT_TRUE(!verifyModule(*M) && "Must have been well formed!");
|
||||||
|
|
||||||
|
runWithSE(*M, "foo", [](Function &F, LoopInfo &LI, ScalarEvolution &SE) {
|
||||||
|
Instruction *IV = getInstructionByName(F, "iv");
|
||||||
|
Type *Ty = IV->getType();
|
||||||
|
const SCEV *Zero = SE.getZero(Ty);
|
||||||
|
const SCEV *MinusOne = SE.getMinusOne(Ty);
|
||||||
|
// {0,+,1}<nuw><nsw>
|
||||||
|
const SCEV *AddRec_0_1 = SE.getSCEV(IV);
|
||||||
|
// {0,+,-1}<nw>
|
||||||
|
const SCEV *AddRec_0_N1 = SE.getNegativeSCEV(AddRec_0_1);
|
||||||
|
|
||||||
|
// {0,+,1}<nuw><nsw> > 0 -> {0,+,-1}<nw> < 0
|
||||||
|
EXPECT_TRUE(isImpliedCond(SE, ICmpInst::ICMP_SLT, AddRec_0_N1, Zero,
|
||||||
|
ICmpInst::ICMP_SGT, AddRec_0_1, Zero));
|
||||||
|
// {0,+,-1}<nw> < -1 -> {0,+,1}<nuw><nsw> > 0
|
||||||
|
EXPECT_TRUE(isImpliedCond(SE, ICmpInst::ICMP_SGT, AddRec_0_1, Zero,
|
||||||
|
ICmpInst::ICMP_SLT, AddRec_0_N1, MinusOne));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
TEST_F(ScalarEvolutionsTest, MatchURem) {
|
TEST_F(ScalarEvolutionsTest, MatchURem) {
|
||||||
LLVMContext C;
|
LLVMContext C;
|
||||||
SMDiagnostic Err;
|
SMDiagnostic Err;
|
||||||
|
|
Loading…
Reference in New Issue