diff --git a/llvm/lib/Analysis/LazyValueInfo.cpp b/llvm/lib/Analysis/LazyValueInfo.cpp index 50fa169c20815..4d7a009402ecb 100644 --- a/llvm/lib/Analysis/LazyValueInfo.cpp +++ b/llvm/lib/Analysis/LazyValueInfo.cpp @@ -1095,7 +1095,8 @@ static ValueLatticeElement getValueFromICmpCondition(Value *Val, ICmpInst *ICI, if (!Ty->isIntegerTy()) return ValueLatticeElement::getOverdefined(); - APInt Offset(Ty->getScalarSizeInBits(), 0); + unsigned BitWidth = Ty->getScalarSizeInBits(); + APInt Offset(BitWidth, 0); if (matchICmpOperand(Offset, LHS, Val, EdgePred)) return getValueFromSimpleICmpCondition(EdgePred, RHS, Offset); @@ -1118,13 +1119,24 @@ static ValueLatticeElement getValueFromICmpCondition(Value *Val, ICmpInst *ICI, // If (Val & Mask) != 0 then the value must be larger than the lowest set // bit of Mask. if (EdgePred == ICmpInst::ICMP_NE && !Mask->isZero() && C->isZero()) { - unsigned BitWidth = Ty->getIntegerBitWidth(); return ValueLatticeElement::getRange(ConstantRange::getNonEmpty( APInt::getOneBitSet(BitWidth, Mask->countTrailingZeros()), APInt::getZero(BitWidth))); } } + // If (X urem Modulus) >= C, then X >= C. + // TODO: An upper bound could be computed as well. + const APInt *Modulus; + if (match(LHS, m_URem(m_Specific(Val), m_APInt(Modulus))) && + match(RHS, m_APInt(C))) { + // Use the icmp region so we don't have to deal with different predicates. + ConstantRange CR = ConstantRange::makeExactICmpRegion(EdgePred, *C); + if (!CR.isEmptySet()) + return ValueLatticeElement::getRange(ConstantRange::getNonEmpty( + CR.getUnsignedMin(), APInt(BitWidth, 0))); + } + return ValueLatticeElement::getOverdefined(); } diff --git a/llvm/test/Transforms/CorrelatedValuePropagation/urem.ll b/llvm/test/Transforms/CorrelatedValuePropagation/urem.ll index 56f556363e16d..0aa0971cad9d1 100644 --- a/llvm/test/Transforms/CorrelatedValuePropagation/urem.ll +++ b/llvm/test/Transforms/CorrelatedValuePropagation/urem.ll @@ -161,18 +161,18 @@ define void @non_power_of_2(i24 %n) { ret void } +; (x urem 5) uge 2 implies x uge 2 on the true branch. +; We don't know anything about the lower bound on the false branch. define void @urem_implied_cond_uge(i8 %x) { ; CHECK-LABEL: @urem_implied_cond_uge( ; CHECK-NEXT: [[U:%.*]] = urem i8 [[X:%.*]], 5 ; CHECK-NEXT: [[C1:%.*]] = icmp uge i8 [[U]], 2 ; CHECK-NEXT: br i1 [[C1]], label [[IF:%.*]], label [[ELSE:%.*]] ; CHECK: if: -; CHECK-NEXT: [[C2:%.*]] = icmp ult i8 [[X]], 2 -; CHECK-NEXT: call void @use(i1 [[C2]]) +; CHECK-NEXT: call void @use(i1 false) ; CHECK-NEXT: [[C3:%.*]] = icmp ule i8 [[X]], 2 ; CHECK-NEXT: call void @use(i1 [[C3]]) -; CHECK-NEXT: [[C4:%.*]] = icmp uge i8 [[X]], 2 -; CHECK-NEXT: call void @use(i1 [[C4]]) +; CHECK-NEXT: call void @use(i1 true) ; CHECK-NEXT: [[C5:%.*]] = icmp ugt i8 [[X]], 2 ; CHECK-NEXT: call void @use(i1 [[C5]]) ; CHECK-NEXT: ret void @@ -214,6 +214,8 @@ else: ret void } +; (x urem 5) uge 5 is always false. It ends up being folded first, but if it +; weren't, we should handle that gracefully. define void @urem_implied_cond_uge_out_of_range(i8 %x) { ; CHECK-LABEL: @urem_implied_cond_uge_out_of_range( ; CHECK-NEXT: [[U:%.*]] = urem i8 [[X:%.*]], 5 @@ -266,18 +268,17 @@ else: ret void } +; (x urem 5) != 0 is the same as (x urem 5) >= 1 and implies x >= 1. define void @urem_implied_cond_ne_zero(i8 %x) { ; CHECK-LABEL: @urem_implied_cond_ne_zero( ; CHECK-NEXT: [[U:%.*]] = urem i8 [[X:%.*]], 5 ; CHECK-NEXT: [[C1:%.*]] = icmp ne i8 [[U]], 0 ; CHECK-NEXT: br i1 [[C1]], label [[IF:%.*]], label [[ELSE:%.*]] ; CHECK: if: -; CHECK-NEXT: [[C2:%.*]] = icmp ult i8 [[X]], 1 -; CHECK-NEXT: call void @use(i1 [[C2]]) +; CHECK-NEXT: call void @use(i1 false) ; CHECK-NEXT: [[C3:%.*]] = icmp ule i8 [[X]], 1 ; CHECK-NEXT: call void @use(i1 [[C3]]) -; CHECK-NEXT: [[C4:%.*]] = icmp uge i8 [[X]], 1 -; CHECK-NEXT: call void @use(i1 [[C4]]) +; CHECK-NEXT: call void @use(i1 true) ; CHECK-NEXT: [[C5:%.*]] = icmp ugt i8 [[X]], 1 ; CHECK-NEXT: call void @use(i1 [[C5]]) ; CHECK-NEXT: ret void @@ -319,6 +320,8 @@ else: ret void } +; (x urem 5) != 1 doesn't imply anything on the true branch. However, on the +; false branch (x urem 5) == 1 implies x >= 1. define void @urem_implied_cond_ne_non_zero(i8 %x) { ; CHECK-LABEL: @urem_implied_cond_ne_non_zero( ; CHECK-NEXT: [[U:%.*]] = urem i8 [[X:%.*]], 5 @@ -335,12 +338,10 @@ define void @urem_implied_cond_ne_non_zero(i8 %x) { ; CHECK-NEXT: call void @use(i1 [[C5]]) ; CHECK-NEXT: ret void ; CHECK: else: -; CHECK-NEXT: [[C2_2:%.*]] = icmp ult i8 [[X]], 1 -; CHECK-NEXT: call void @use(i1 [[C2_2]]) +; CHECK-NEXT: call void @use(i1 false) ; CHECK-NEXT: [[C3_2:%.*]] = icmp ule i8 [[X]], 1 ; CHECK-NEXT: call void @use(i1 [[C3_2]]) -; CHECK-NEXT: [[C4_2:%.*]] = icmp uge i8 [[X]], 1 -; CHECK-NEXT: call void @use(i1 [[C4_2]]) +; CHECK-NEXT: call void @use(i1 true) ; CHECK-NEXT: [[C5_2:%.*]] = icmp ugt i8 [[X]], 1 ; CHECK-NEXT: call void @use(i1 [[C5_2]]) ; CHECK-NEXT: ret void