Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 22 additions & 12 deletions llvm/lib/Analysis/InstructionSimplify.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3031,7 +3031,9 @@ enum class MonotonicType { GreaterEq, LowerEq };

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

Expand All @@ -3047,24 +3049,31 @@ static void getUnsignedMonotonicValues(SmallPtrSetImpl<Value *> &Res, Value *V,
if (Type == MonotonicType::GreaterEq) {
if (match(I, m_Or(m_Value(X), m_Value(Y))) ||
match(I, m_Intrinsic<Intrinsic::uadd_sat>(m_Value(X), m_Value(Y)))) {
getUnsignedMonotonicValues(Res, X, Type, Depth);
getUnsignedMonotonicValues(Res, Y, Type, Depth);
getUnsignedMonotonicValues(Res, X, Type, Q, Depth);
getUnsignedMonotonicValues(Res, Y, Type, Q, Depth);
}
// X * Y >= X --> true
if (match(I, m_NUWMul(m_Value(X), m_Value(Y)))) {
if (isKnownNonZero(X, Q))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need the non-constant support?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is needed by assimp:
https://github.com/assimp/assimp/blob/2bce77f909b9f56c8c67cff33cc73a244505aa46/code/AssetLib/glTF2/glTF2Asset.inl#L897-L903

  %switch.gep = getelementptr inbounds nuw [7 x i64], ptr @switch.table._ZN5glTF28Accessor6Sparse9PatchDataEj, i64 0, i64 %307
  %switch.load = load i64, ptr %switch.gep, align 8
  %308 = mul nuw nsw i64 %switch.load, %202
  store i64 %308, ptr %20, align 8
  %309 = icmp samesign ult i64 %308, %202

getUnsignedMonotonicValues(Res, Y, Type, Q, Depth);
if (isKnownNonZero(Y, Q))
getUnsignedMonotonicValues(Res, X, Type, Q, Depth);
}
} else {
assert(Type == MonotonicType::LowerEq);
switch (I->getOpcode()) {
case Instruction::And:
getUnsignedMonotonicValues(Res, I->getOperand(0), Type, Depth);
getUnsignedMonotonicValues(Res, I->getOperand(1), Type, Depth);
getUnsignedMonotonicValues(Res, I->getOperand(0), Type, Q, Depth);
getUnsignedMonotonicValues(Res, I->getOperand(1), Type, Q, Depth);
break;
case Instruction::URem:
case Instruction::UDiv:
case Instruction::LShr:
getUnsignedMonotonicValues(Res, I->getOperand(0), Type, Depth);
getUnsignedMonotonicValues(Res, I->getOperand(0), Type, Q, Depth);
break;
case Instruction::Call:
if (match(I, m_Intrinsic<Intrinsic::usub_sat>(m_Value(X))))
getUnsignedMonotonicValues(Res, X, Type, Depth);
getUnsignedMonotonicValues(Res, X, Type, Q, Depth);
break;
default:
break;
Expand All @@ -3073,16 +3082,17 @@ static void getUnsignedMonotonicValues(SmallPtrSetImpl<Value *> &Res, Value *V,
}

static Value *simplifyICmpUsingMonotonicValues(CmpPredicate Pred, Value *LHS,
Value *RHS) {
Value *RHS,
const SimplifyQuery &Q) {
if (Pred != ICmpInst::ICMP_UGE && Pred != ICmpInst::ICMP_ULT)
return nullptr;

// We have LHS uge GreaterValues and LowerValues uge RHS. If any of the
// GreaterValues and LowerValues are the same, it follows that LHS uge RHS.
SmallPtrSet<Value *, 4> GreaterValues;
SmallPtrSet<Value *, 4> LowerValues;
getUnsignedMonotonicValues(GreaterValues, LHS, MonotonicType::GreaterEq);
getUnsignedMonotonicValues(LowerValues, RHS, MonotonicType::LowerEq);
getUnsignedMonotonicValues(GreaterValues, LHS, MonotonicType::GreaterEq, Q);
getUnsignedMonotonicValues(LowerValues, RHS, MonotonicType::LowerEq, Q);
for (Value *GV : GreaterValues)
if (LowerValues.contains(GV))
return ConstantInt::getBool(getCompareTy(LHS),
Expand Down Expand Up @@ -3998,10 +4008,10 @@ static Value *simplifyICmpInst(CmpPredicate Pred, Value *LHS, Value *RHS,
ICmpInst::getSwappedPredicate(Pred), RHS, LHS))
return V;

if (Value *V = simplifyICmpUsingMonotonicValues(Pred, LHS, RHS))
if (Value *V = simplifyICmpUsingMonotonicValues(Pred, LHS, RHS, Q))
return V;
if (Value *V = simplifyICmpUsingMonotonicValues(
ICmpInst::getSwappedPredicate(Pred), RHS, LHS))
ICmpInst::getSwappedPredicate(Pred), RHS, LHS, Q))
return V;

if (Value *V = simplifyICmpWithDominatingAssume(Pred, LHS, RHS, Q))
Expand Down
144 changes: 144 additions & 0 deletions llvm/test/Transforms/InstSimplify/icmp-monotonic.ll
Original file line number Diff line number Diff line change
Expand Up @@ -216,3 +216,147 @@ define i1 @lshr_add_ule_non_monotonic(i32 %x, i32 %y, i32 %z) {
%cmp = icmp ule i32 %op1, %op2
ret i1 %cmp
}

define i1 @mul_nuw_nonzero_rhs_monotonic(i8 %x, i8 %c) {
; CHECK-LABEL: define i1 @mul_nuw_nonzero_rhs_monotonic(
; CHECK-SAME: i8 [[X:%.*]], i8 [[C:%.*]]) {
; CHECK-NEXT: [[C_NONZERO:%.*]] = icmp ne i8 [[C]], 0
; CHECK-NEXT: call void @llvm.assume(i1 [[C_NONZERO]])
; CHECK-NEXT: ret i1 true
;
%c_nonzero = icmp ne i8 %c, 0
call void @llvm.assume(i1 %c_nonzero)

%prod = mul nuw i8 %x, %c
%cmp = icmp uge i8 %prod, %x
ret i1 %cmp
}

define i1 @mul_nuw_nonzero_rhs_commuted_monotonic(i8 %x, i8 %c) {
; CHECK-LABEL: define i1 @mul_nuw_nonzero_rhs_commuted_monotonic(
; CHECK-SAME: i8 [[X:%.*]], i8 [[C:%.*]]) {
; CHECK-NEXT: [[C_NONZERO:%.*]] = icmp ne i8 [[C]], 0
; CHECK-NEXT: call void @llvm.assume(i1 [[C_NONZERO]])
; CHECK-NEXT: ret i1 true
;
%c_nonzero = icmp ne i8 %c, 0
call void @llvm.assume(i1 %c_nonzero)

%prod = mul nuw i8 %c, %x
%cmp = icmp uge i8 %prod, %x
ret i1 %cmp
}

define i1 @mul_nuw_nonzero_rhs_monotonic_inverse_predicate(i8 %x, i8 %c) {
; CHECK-LABEL: define i1 @mul_nuw_nonzero_rhs_monotonic_inverse_predicate(
; CHECK-SAME: i8 [[X:%.*]], i8 [[C:%.*]]) {
; CHECK-NEXT: [[C_NONZERO:%.*]] = icmp ne i8 [[C]], 0
; CHECK-NEXT: call void @llvm.assume(i1 [[C_NONZERO]])
; CHECK-NEXT: ret i1 false
;
%c_nonzero = icmp ne i8 %c, 0
call void @llvm.assume(i1 %c_nonzero)

%prod = mul nuw i8 %x, %c
%cmp = icmp ult i8 %prod, %x
ret i1 %cmp
}

define i1 @mul_nuw_nonzero_lhs_monotonic(i8 %x, i8 %c) {
; CHECK-LABEL: define i1 @mul_nuw_nonzero_lhs_monotonic(
; CHECK-SAME: i8 [[X:%.*]], i8 [[C:%.*]]) {
; CHECK-NEXT: [[C_NONZERO:%.*]] = icmp ne i8 [[X]], 0
; CHECK-NEXT: call void @llvm.assume(i1 [[C_NONZERO]])
; CHECK-NEXT: ret i1 true
;
%c_nonzero = icmp ne i8 %x, 0
call void @llvm.assume(i1 %c_nonzero)

%prod = mul nuw i8 %x, %c
%cmp = icmp uge i8 %prod, %c
ret i1 %cmp
}

define i1 @mul_nuw_nonzero_lhs_rhs_monotonic(i8 %x, i8 %c) {
; CHECK-LABEL: define i1 @mul_nuw_nonzero_lhs_rhs_monotonic(
; CHECK-SAME: i8 [[X:%.*]], i8 [[C:%.*]]) {
; CHECK-NEXT: [[C_NONZERO:%.*]] = icmp ne i8 [[C]], 0
; CHECK-NEXT: call void @llvm.assume(i1 [[C_NONZERO]])
; CHECK-NEXT: [[X_NONZERO:%.*]] = icmp ne i8 [[X]], 0
; CHECK-NEXT: call void @llvm.assume(i1 [[X_NONZERO]])
; CHECK-NEXT: ret i1 true
;
%c_nonzero = icmp ne i8 %c, 0
call void @llvm.assume(i1 %c_nonzero)

%x_nonzero = icmp ne i8 %x, 0
call void @llvm.assume(i1 %x_nonzero)

%prod = mul nuw i8 %x, %c
%cmp = icmp uge i8 %prod, %x
ret i1 %cmp
}


define i1 @negative_mul_non_nsw(i8 %x, i8 %c) {
; CHECK-LABEL: define i1 @negative_mul_non_nsw(
; CHECK-SAME: i8 [[X:%.*]], i8 [[C:%.*]]) {
; CHECK-NEXT: [[C_NONZERO:%.*]] = icmp ne i8 [[C]], 0
; CHECK-NEXT: call void @llvm.assume(i1 [[C_NONZERO]])
; CHECK-NEXT: [[X3:%.*]] = mul i8 [[X]], [[C]]
; CHECK-NEXT: [[CMP:%.*]] = icmp uge i8 [[X3]], [[X]]
; CHECK-NEXT: ret i1 [[CMP]]
;
%c_nonzero = icmp ne i8 %c, 0
call void @llvm.assume(i1 %c_nonzero)

%prod = mul i8 %x, %c
%cmp = icmp uge i8 %prod, %x
ret i1 %cmp
}

define i1 @negative_mul_no_nonzero(i8 %x, i8 %c) {
; CHECK-LABEL: define i1 @negative_mul_no_nonzero(
; CHECK-SAME: i8 [[X:%.*]], i8 [[C:%.*]]) {
; CHECK-NEXT: [[X3:%.*]] = mul nsw i8 [[X]], [[C]]
; CHECK-NEXT: [[CMP:%.*]] = icmp uge i8 [[X3]], [[X]]
; CHECK-NEXT: ret i1 [[CMP]]
;
%prod = mul nsw i8 %x, %c
%cmp = icmp uge i8 %prod, %x
ret i1 %cmp
}

define i1 @negative_mul_lhs_maybe_zero(i8 %x, i8 %c) {
; CHECK-LABEL: define i1 @negative_mul_lhs_maybe_zero(
; CHECK-SAME: i8 [[X:%.*]], i8 [[C:%.*]]) {
; CHECK-NEXT: [[C_NONZERO:%.*]] = icmp ne i8 [[C]], 0
; CHECK-NEXT: call void @llvm.assume(i1 [[C_NONZERO]])
; CHECK-NEXT: [[X3:%.*]] = mul nuw i8 [[X]], [[C]]
; CHECK-NEXT: [[CMP:%.*]] = icmp uge i8 [[X3]], [[C]]
; CHECK-NEXT: ret i1 [[CMP]]
;
%c_nonzero = icmp ne i8 %c, 0
call void @llvm.assume(i1 %c_nonzero)

%prod = mul nuw i8 %x, %c
%cmp = icmp uge i8 %prod, %c
ret i1 %cmp
}

define i1 @negative_mul_rhs_maybe_zero(i8 %x, i8 %c) {
; CHECK-LABEL: define i1 @negative_mul_rhs_maybe_zero(
; CHECK-SAME: i8 [[X:%.*]], i8 [[C:%.*]]) {
; CHECK-NEXT: [[C_NONZERO:%.*]] = icmp ne i8 [[X]], 0
; CHECK-NEXT: call void @llvm.assume(i1 [[C_NONZERO]])
; CHECK-NEXT: [[X3:%.*]] = mul nuw i8 [[X]], [[C]]
; CHECK-NEXT: [[CMP:%.*]] = icmp uge i8 [[X3]], [[X]]
; CHECK-NEXT: ret i1 [[CMP]]
;
%c_nonzero = icmp ne i8 %x, 0
call void @llvm.assume(i1 %c_nonzero)

%prod = mul nuw i8 %x, %c
%cmp = icmp uge i8 %prod, %x
ret i1 %cmp
}