diff --git a/llvm/lib/Analysis/InstructionSimplify.cpp b/llvm/lib/Analysis/InstructionSimplify.cpp --- a/llvm/lib/Analysis/InstructionSimplify.cpp +++ b/llvm/lib/Analysis/InstructionSimplify.cpp @@ -1382,6 +1382,27 @@ ICmpInst::Predicate UnsignedPred; + Value *ComparedWith; + if (match(UnsignedICmp, + m_c_ICmp(UnsignedPred, m_Specific(Y), m_Value(ComparedWith))) && + match(Y, m_c_Add(m_Specific(ComparedWith), m_Value()))) { + if (UnsignedICmp->getOperand(0) != Y) + UnsignedPred = ICmpInst::getSwappedPredicate(UnsignedPred); + + // Given Y = (A + B) + // Y >= ComparedWith && Y == 0 --> false + // Y < ComparedWith || Y != 0 --> true + // iff ComparedWith is A or B and is non-zero. + if (UnsignedPred == ICmpInst::ICMP_UGE && EqPred == ICmpInst::ICMP_EQ && + IsAnd && + isKnownNonZero(ComparedWith, Q.DL, /*Depth=*/0, Q.AC, Q.CxtI, Q.DT)) + return ConstantInt::getFalse(UnsignedICmp->getType()); + if (UnsignedPred == ICmpInst::ICMP_ULT && EqPred == ICmpInst::ICMP_NE && + !IsAnd && + isKnownNonZero(ComparedWith, Q.DL, /*Depth=*/0, Q.AC, Q.CxtI, Q.DT)) + return ConstantInt::getTrue(UnsignedICmp->getType()); + } + Value *A, *B; // Y = (A - B); if (match(Y, m_Sub(m_Value(A), m_Value(B)))) { diff --git a/llvm/test/Transforms/InstSimplify/result-of-add-of-negative-is-non-zero-and-no-underflow.ll b/llvm/test/Transforms/InstSimplify/result-of-add-of-negative-is-non-zero-and-no-underflow.ll --- a/llvm/test/Transforms/InstSimplify/result-of-add-of-negative-is-non-zero-and-no-underflow.ll +++ b/llvm/test/Transforms/InstSimplify/result-of-add-of-negative-is-non-zero-and-no-underflow.ll @@ -18,10 +18,7 @@ ; CHECK-NEXT: call void @llvm.assume(i1 [[CMP]]) ; CHECK-NEXT: [[ADJUSTED:%.*]] = add i8 [[BASE]], [[OFFSET:%.*]] ; CHECK-NEXT: call void @use8(i8 [[ADJUSTED]]) -; CHECK-NEXT: [[NOT_NULL:%.*]] = icmp ne i8 [[ADJUSTED]], 0 -; CHECK-NEXT: [[NO_UNDERFLOW:%.*]] = icmp ult i8 [[ADJUSTED]], [[BASE]] -; CHECK-NEXT: [[R:%.*]] = or i1 [[NOT_NULL]], [[NO_UNDERFLOW]] -; CHECK-NEXT: ret i1 [[R]] +; CHECK-NEXT: ret i1 true ; %cmp = icmp slt i8 %base, 0 call void @llvm.assume(i1 %cmp) @@ -39,10 +36,7 @@ ; CHECK-NEXT: call void @llvm.assume(i1 [[CMP]]) ; CHECK-NEXT: [[ADJUSTED:%.*]] = add i8 [[BASE]], [[OFFSET:%.*]] ; CHECK-NEXT: call void @use8(i8 [[ADJUSTED]]) -; CHECK-NEXT: [[NOT_NULL:%.*]] = icmp ne i8 [[ADJUSTED]], 0 -; CHECK-NEXT: [[NO_UNDERFLOW:%.*]] = icmp ugt i8 [[BASE]], [[ADJUSTED]] -; CHECK-NEXT: [[R:%.*]] = or i1 [[NOT_NULL]], [[NO_UNDERFLOW]] -; CHECK-NEXT: ret i1 [[R]] +; CHECK-NEXT: ret i1 true ; %cmp = icmp slt i8 %base, 0 call void @llvm.assume(i1 %cmp) @@ -63,10 +57,7 @@ ; CHECK-NEXT: call void @llvm.assume(i1 [[CMP]]) ; CHECK-NEXT: [[ADJUSTED:%.*]] = add i8 [[BASE]], [[OFFSET:%.*]] ; CHECK-NEXT: call void @use8(i8 [[ADJUSTED]]) -; CHECK-NEXT: [[NOT_NULL:%.*]] = icmp eq i8 [[ADJUSTED]], 0 -; CHECK-NEXT: [[NO_UNDERFLOW:%.*]] = icmp uge i8 [[ADJUSTED]], [[BASE]] -; CHECK-NEXT: [[R:%.*]] = and i1 [[NOT_NULL]], [[NO_UNDERFLOW]] -; CHECK-NEXT: ret i1 [[R]] +; CHECK-NEXT: ret i1 false ; %cmp = icmp slt i8 %base, 0 call void @llvm.assume(i1 %cmp) @@ -84,10 +75,7 @@ ; CHECK-NEXT: call void @llvm.assume(i1 [[CMP]]) ; CHECK-NEXT: [[ADJUSTED:%.*]] = add i8 [[BASE]], [[OFFSET:%.*]] ; CHECK-NEXT: call void @use8(i8 [[ADJUSTED]]) -; CHECK-NEXT: [[NOT_NULL:%.*]] = icmp eq i8 [[ADJUSTED]], 0 -; CHECK-NEXT: [[NO_UNDERFLOW:%.*]] = icmp ule i8 [[BASE]], [[ADJUSTED]] -; CHECK-NEXT: [[R:%.*]] = and i1 [[NOT_NULL]], [[NO_UNDERFLOW]] -; CHECK-NEXT: ret i1 [[R]] +; CHECK-NEXT: ret i1 false ; %cmp = icmp slt i8 %base, 0 call void @llvm.assume(i1 %cmp) @@ -99,3 +87,27 @@ %r = and i1 %not_null, %no_underflow ret i1 %r } + +; We need to know that the value we compare with here (%base) is non-zero, +; so knowledge about %offset won't do. +define i1 @t5_bad(i8 %base, i8 %offset) { +; CHECK-LABEL: @t5_bad( +; CHECK-NEXT: [[CMP:%.*]] = icmp slt i8 [[OFFSET:%.*]], 0 +; CHECK-NEXT: call void @llvm.assume(i1 [[CMP]]) +; CHECK-NEXT: [[ADJUSTED:%.*]] = add i8 [[BASE:%.*]], [[OFFSET]] +; CHECK-NEXT: call void @use8(i8 [[ADJUSTED]]) +; CHECK-NEXT: [[NOT_NULL:%.*]] = icmp ne i8 [[ADJUSTED]], 0 +; CHECK-NEXT: [[NO_UNDERFLOW:%.*]] = icmp ult i8 [[ADJUSTED]], [[BASE]] +; CHECK-NEXT: [[R:%.*]] = or i1 [[NOT_NULL]], [[NO_UNDERFLOW]] +; CHECK-NEXT: ret i1 [[R]] +; + %cmp = icmp slt i8 %offset, 0 + call void @llvm.assume(i1 %cmp) + + %adjusted = add i8 %base, %offset + call void @use8(i8 %adjusted) + %not_null = icmp ne i8 %adjusted, 0 + %no_underflow = icmp ult i8 %adjusted, %base + %r = or i1 %not_null, %no_underflow + ret i1 %r +}