diff --git a/llvm/include/llvm/IR/ConstantRange.h b/llvm/include/llvm/IR/ConstantRange.h --- a/llvm/include/llvm/IR/ConstantRange.h +++ b/llvm/include/llvm/IR/ConstantRange.h @@ -327,6 +327,14 @@ const ConstantRange &Other) const; /// Return a new range representing the possible values resulting + /// from an application of the specified overflowing binary operator to a + /// left hand side of this range and a right hand side of \p Other given + /// the provided knowledge about lack of wrapping \p NoWrapKind. + ConstantRange overflowingBinaryOp(Instruction::BinaryOps BinOp, + const ConstantRange &Other, + unsigned NoWrapKind) const; + + /// Return a new range representing the possible values resulting /// from an addition of a value in this range and a value in \p Other. ConstantRange add(const ConstantRange &Other) const; diff --git a/llvm/lib/Analysis/LazyValueInfo.cpp b/llvm/lib/Analysis/LazyValueInfo.cpp --- a/llvm/lib/Analysis/LazyValueInfo.cpp +++ b/llvm/lib/Analysis/LazyValueInfo.cpp @@ -1090,8 +1090,22 @@ return true; } - return solveBlockValueBinaryOpImpl(BBLV, BO, BB, - [BO](const ConstantRange &CR1, const ConstantRange &CR2) { + if (auto *OBO = dyn_cast(BO)) { + unsigned NoWrapKind = 0; + if (OBO->hasNoUnsignedWrap()) + NoWrapKind |= OverflowingBinaryOperator::NoUnsignedWrap; + if (OBO->hasNoSignedWrap()) + NoWrapKind |= OverflowingBinaryOperator::NoSignedWrap; + + return solveBlockValueBinaryOpImpl( + BBLV, BO, BB, + [BO, NoWrapKind](const ConstantRange &CR1, const ConstantRange &CR2) { + return CR1.overflowingBinaryOp(BO->getOpcode(), CR2, NoWrapKind); + }); + } + + return solveBlockValueBinaryOpImpl( + BBLV, BO, BB, [BO](const ConstantRange &CR1, const ConstantRange &CR2) { return CR1.binaryOp(BO->getOpcode(), CR2); }); } diff --git a/llvm/lib/IR/ConstantRange.cpp b/llvm/lib/IR/ConstantRange.cpp --- a/llvm/lib/IR/ConstantRange.cpp +++ b/llvm/lib/IR/ConstantRange.cpp @@ -816,6 +816,21 @@ } } +ConstantRange ConstantRange::overflowingBinaryOp(Instruction::BinaryOps BinOp, + const ConstantRange &Other, + unsigned NoWrapKind) const { + assert(Instruction::isBinaryOp(BinOp) && "Binary operators only!"); + + switch (BinOp) { + case Instruction::Add: + return addWithNoWrap(Other, NoWrapKind); + default: + // Don't know about this Overflowing Binary Operation. + // Conservatively fallback to plain binop handling. + return binaryOp(BinOp, Other); + } +} + ConstantRange ConstantRange::add(const ConstantRange &Other) const { if (isEmptySet() || Other.isEmptySet()) diff --git a/llvm/test/Transforms/CorrelatedValuePropagation/icmp.ll b/llvm/test/Transforms/CorrelatedValuePropagation/icmp.ll --- a/llvm/test/Transforms/CorrelatedValuePropagation/icmp.ll +++ b/llvm/test/Transforms/CorrelatedValuePropagation/icmp.ll @@ -289,11 +289,9 @@ ; CHECK-NEXT: [[ADD:%.*]] = add nuw nsw i32 [[A]], [[B]] ; CHECK-NEXT: br label [[CONT:%.*]] ; CHECK: cont: -; CHECK-NEXT: [[RES:%.*]] = icmp sge i32 [[ADD]], 0 ; CHECK-NEXT: br label [[EXIT]] ; CHECK: exit: -; CHECK-NEXT: [[IV:%.*]] = phi i1 [ true, [[BEGIN:%.*]] ], [ [[RES]], [[CONT]] ] -; CHECK-NEXT: ret i1 [[IV]] +; CHECK-NEXT: ret i1 true ; begin: %cmp0 = icmp sge i32 %a, 0 @@ -355,11 +353,9 @@ ; CHECK-NEXT: [[ADD:%.*]] = add nuw i32 [[A]], [[B:%.*]] ; CHECK-NEXT: br label [[CONT:%.*]] ; CHECK: cont: -; CHECK-NEXT: [[RES:%.*]] = icmp uge i32 [[ADD]], -256 ; CHECK-NEXT: br label [[EXIT]] ; CHECK: exit: -; CHECK-NEXT: [[IV:%.*]] = phi i1 [ true, [[BEGIN:%.*]] ], [ [[RES]], [[CONT]] ] -; CHECK-NEXT: ret i1 [[IV]] +; CHECK-NEXT: ret i1 true ; begin: %cmp = icmp uge i32 %a, 4294967040