Skip to content

Commit b785b55

Browse files
[InstSimplify] Fold X * C >= X to true
Proof: https://alive2.llvm.org/ce/z/T_ocLy This patch folds `X * C >= X` to `true` when `C` is known to be non-zero and `mul` is `nuw`. Folds for other math operators exist already: https://llvm-ir.godbolt.org/z/GKcYEf5Kb
1 parent 066e78c commit b785b55

File tree

2 files changed

+28
-25
lines changed

2 files changed

+28
-25
lines changed

llvm/lib/Analysis/InstructionSimplify.cpp

Lines changed: 24 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3031,7 +3031,9 @@ enum class MonotonicType { GreaterEq, LowerEq };
30313031

30323032
/// Get values V_i such that V uge V_i (GreaterEq) or V ule V_i (LowerEq).
30333033
static void getUnsignedMonotonicValues(SmallPtrSetImpl<Value *> &Res, Value *V,
3034-
MonotonicType Type, unsigned Depth = 0) {
3034+
MonotonicType Type,
3035+
const SimplifyQuery &Q,
3036+
unsigned Depth = 0) {
30353037
if (!Res.insert(V).second)
30363038
return;
30373039

@@ -3047,24 +3049,31 @@ static void getUnsignedMonotonicValues(SmallPtrSetImpl<Value *> &Res, Value *V,
30473049
if (Type == MonotonicType::GreaterEq) {
30483050
if (match(I, m_Or(m_Value(X), m_Value(Y))) ||
30493051
match(I, m_Intrinsic<Intrinsic::uadd_sat>(m_Value(X), m_Value(Y)))) {
3050-
getUnsignedMonotonicValues(Res, X, Type, Depth);
3051-
getUnsignedMonotonicValues(Res, Y, Type, Depth);
3052+
getUnsignedMonotonicValues(Res, X, Type, Q, Depth);
3053+
getUnsignedMonotonicValues(Res, Y, Type, Q, Depth);
3054+
}
3055+
// X * Y >= X --> true
3056+
if (match(I, m_NUWMul(m_Value(X), m_Value(Y)))) {
3057+
if (isKnownNonZero(X, Q))
3058+
getUnsignedMonotonicValues(Res, Y, Type, Q, Depth);
3059+
if (isKnownNonZero(Y, Q))
3060+
getUnsignedMonotonicValues(Res, X, Type, Q, Depth);
30523061
}
30533062
} else {
30543063
assert(Type == MonotonicType::LowerEq);
30553064
switch (I->getOpcode()) {
30563065
case Instruction::And:
3057-
getUnsignedMonotonicValues(Res, I->getOperand(0), Type, Depth);
3058-
getUnsignedMonotonicValues(Res, I->getOperand(1), Type, Depth);
3066+
getUnsignedMonotonicValues(Res, I->getOperand(0), Type, Q, Depth);
3067+
getUnsignedMonotonicValues(Res, I->getOperand(1), Type, Q, Depth);
30593068
break;
30603069
case Instruction::URem:
30613070
case Instruction::UDiv:
30623071
case Instruction::LShr:
3063-
getUnsignedMonotonicValues(Res, I->getOperand(0), Type, Depth);
3072+
getUnsignedMonotonicValues(Res, I->getOperand(0), Type, Q, Depth);
30643073
break;
30653074
case Instruction::Call:
30663075
if (match(I, m_Intrinsic<Intrinsic::usub_sat>(m_Value(X))))
3067-
getUnsignedMonotonicValues(Res, X, Type, Depth);
3076+
getUnsignedMonotonicValues(Res, X, Type, Q, Depth);
30683077
break;
30693078
default:
30703079
break;
@@ -3073,16 +3082,16 @@ static void getUnsignedMonotonicValues(SmallPtrSetImpl<Value *> &Res, Value *V,
30733082
}
30743083

30753084
static Value *simplifyICmpUsingMonotonicValues(CmpPredicate Pred, Value *LHS,
3076-
Value *RHS) {
3085+
Value *RHS,
3086+
const SimplifyQuery &Q) {
30773087
if (Pred != ICmpInst::ICMP_UGE && Pred != ICmpInst::ICMP_ULT)
30783088
return nullptr;
3079-
30803089
// We have LHS uge GreaterValues and LowerValues uge RHS. If any of the
30813090
// GreaterValues and LowerValues are the same, it follows that LHS uge RHS.
30823091
SmallPtrSet<Value *, 4> GreaterValues;
30833092
SmallPtrSet<Value *, 4> LowerValues;
3084-
getUnsignedMonotonicValues(GreaterValues, LHS, MonotonicType::GreaterEq);
3085-
getUnsignedMonotonicValues(LowerValues, RHS, MonotonicType::LowerEq);
3093+
getUnsignedMonotonicValues(GreaterValues, LHS, MonotonicType::GreaterEq, Q);
3094+
getUnsignedMonotonicValues(LowerValues, RHS, MonotonicType::LowerEq, Q);
30863095
for (Value *GV : GreaterValues)
30873096
if (LowerValues.contains(GV))
30883097
return ConstantInt::getBool(getCompareTy(LHS),
@@ -3994,14 +4003,16 @@ static Value *simplifyICmpInst(CmpPredicate Pred, Value *LHS, Value *RHS,
39944003

39954004
if (Value *V = simplifyICmpWithIntrinsicOnLHS(Pred, LHS, RHS))
39964005
return V;
4006+
39974007
if (Value *V = simplifyICmpWithIntrinsicOnLHS(
39984008
ICmpInst::getSwappedPredicate(Pred), RHS, LHS))
39994009
return V;
40004010

4001-
if (Value *V = simplifyICmpUsingMonotonicValues(Pred, LHS, RHS))
4011+
if (Value *V = simplifyICmpUsingMonotonicValues(Pred, LHS, RHS, Q))
40024012
return V;
4013+
40034014
if (Value *V = simplifyICmpUsingMonotonicValues(
4004-
ICmpInst::getSwappedPredicate(Pred), RHS, LHS))
4015+
ICmpInst::getSwappedPredicate(Pred), RHS, LHS, Q))
40054016
return V;
40064017

40074018
if (Value *V = simplifyICmpWithDominatingAssume(Pred, LHS, RHS, Q))

llvm/test/Transforms/InstSimplify/icmp-monotonic.ll

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -222,9 +222,7 @@ define i1 @mul_nuw_nonzero_rhs_monotonic(i8 %x, i8 %c) {
222222
; CHECK-SAME: i8 [[X:%.*]], i8 [[C:%.*]]) {
223223
; CHECK-NEXT: [[C_NONZERO:%.*]] = icmp ne i8 [[C]], 0
224224
; CHECK-NEXT: call void @llvm.assume(i1 [[C_NONZERO]])
225-
; CHECK-NEXT: [[PROD:%.*]] = mul nuw i8 [[X]], [[C]]
226-
; CHECK-NEXT: [[CMP:%.*]] = icmp uge i8 [[PROD]], [[X]]
227-
; CHECK-NEXT: ret i1 [[CMP]]
225+
; CHECK-NEXT: ret i1 true
228226
;
229227
%c_nonzero = icmp ne i8 %c, 0
230228
call void @llvm.assume(i1 %c_nonzero)
@@ -239,9 +237,7 @@ define i1 @mul_nuw_nonzero_rhs_monotonic_inverse_predicate(i8 %x, i8 %c) {
239237
; CHECK-SAME: i8 [[X:%.*]], i8 [[C:%.*]]) {
240238
; CHECK-NEXT: [[C_NONZERO:%.*]] = icmp ne i8 [[C]], 0
241239
; CHECK-NEXT: call void @llvm.assume(i1 [[C_NONZERO]])
242-
; CHECK-NEXT: [[PROD:%.*]] = mul nuw i8 [[X]], [[C]]
243-
; CHECK-NEXT: [[CMP:%.*]] = icmp ult i8 [[PROD]], [[X]]
244-
; CHECK-NEXT: ret i1 [[CMP]]
240+
; CHECK-NEXT: ret i1 false
245241
;
246242
%c_nonzero = icmp ne i8 %c, 0
247243
call void @llvm.assume(i1 %c_nonzero)
@@ -256,9 +252,7 @@ define i1 @mul_nuw_nonzero_lhs_monotonic(i8 %x, i8 %c) {
256252
; CHECK-SAME: i8 [[X:%.*]], i8 [[C:%.*]]) {
257253
; CHECK-NEXT: [[C_NONZERO:%.*]] = icmp ne i8 [[X]], 0
258254
; CHECK-NEXT: call void @llvm.assume(i1 [[C_NONZERO]])
259-
; CHECK-NEXT: [[PROD:%.*]] = mul nuw i8 [[X]], [[C]]
260-
; CHECK-NEXT: [[CMP:%.*]] = icmp uge i8 [[PROD]], [[C]]
261-
; CHECK-NEXT: ret i1 [[CMP]]
255+
; CHECK-NEXT: ret i1 true
262256
;
263257
%c_nonzero = icmp ne i8 %x, 0
264258
call void @llvm.assume(i1 %c_nonzero)
@@ -275,9 +269,7 @@ define i1 @mul_nuw_nonzero_lhs_rhs_monotonic(i8 %x, i8 %c) {
275269
; CHECK-NEXT: call void @llvm.assume(i1 [[C_NONZERO]])
276270
; CHECK-NEXT: [[X_NONZERO:%.*]] = icmp ne i8 [[X]], 0
277271
; CHECK-NEXT: call void @llvm.assume(i1 [[X_NONZERO]])
278-
; CHECK-NEXT: [[PROD:%.*]] = mul nuw i8 [[X]], [[C]]
279-
; CHECK-NEXT: [[CMP:%.*]] = icmp uge i8 [[PROD]], [[X]]
280-
; CHECK-NEXT: ret i1 [[CMP]]
272+
; CHECK-NEXT: ret i1 true
281273
;
282274
%c_nonzero = icmp ne i8 %c, 0
283275
call void @llvm.assume(i1 %c_nonzero)

0 commit comments

Comments
 (0)