Index: llvm/include/llvm/IR/ConstantRange.h =================================================================== --- llvm/include/llvm/IR/ConstantRange.h +++ llvm/include/llvm/IR/ConstantRange.h @@ -418,6 +418,14 @@ /// treating both this and \p Other as unsigned ranges. ConstantRange multiply(const ConstantRange &Other) const; + /// Return a new range representing the possible values resulting + /// from a multiplication with wrap type \p NoWrapKind of a value in this + /// range and a value in \p Other. + /// If the result range is disjoint, the preferred range is determined by the + /// \p PreferredRangeType. + ConstantRange mulWithNoWrap(const ConstantRange &Other, unsigned NoWrapKind, + PreferredRangeType RangeType = Smallest) const; + /// Return range of possible values for a signed multiplication of this and /// \p Other. However, if overflow is possible always return a full range /// rather than trying to determine a more precise result. @@ -483,6 +491,15 @@ /// TODO: This isn't fully implemented yet. ConstantRange shl(const ConstantRange &Other) const; + /// Return a new range representing the possible values resulting + /// from a left shift with wrap type \p NoWrapKind of a value in this + /// range and a value in \p Other. + /// If the result range is disjoint, the preferred range is determined by the + /// \p PreferredRangeType. + ConstantRange shlWithNoWrap(const ConstantRange &Other, unsigned NoWrapKind, + PreferredRangeType RangeType = Smallest) const; + + /// Return a new range representing the possible values resulting from a /// logical right shift of a value in this range and a value in \p Other. ConstantRange lshr(const ConstantRange &Other) const; Index: llvm/lib/IR/ConstantRange.cpp =================================================================== --- llvm/lib/IR/ConstantRange.cpp +++ llvm/lib/IR/ConstantRange.cpp @@ -930,6 +930,10 @@ return addWithNoWrap(Other, NoWrapKind); case Instruction::Sub: return subWithNoWrap(Other, NoWrapKind); + case Instruction::Mul: + return mulWithNoWrap(Other, NoWrapKind); + case Instruction::Shl: + return shlWithNoWrap(Other, NoWrapKind); default: // Don't know about this Overflowing Binary Operation. // Conservatively fallback to plain binop handling. @@ -1136,6 +1140,28 @@ return UR.isSizeStrictlySmallerThan(SR) ? UR : SR; } +ConstantRange ConstantRange::mulWithNoWrap(const ConstantRange &Other, + unsigned NoWrapKind, + PreferredRangeType RangeType) const { + // Calculate the range for "X * Y" which is guaranteed not to wrap(overflow). + // (X is from this, and Y is from Other) + if (isEmptySet() || Other.isEmptySet()) + return getEmpty(); + if (isFullSet() && Other.isFullSet()) + return getFull(); + + using OBO = OverflowingBinaryOperator; + ConstantRange Result = multiply(Other); + + if (NoWrapKind & OBO::NoSignedWrap) + Result = Result.intersectWith(smul_sat(Other), RangeType); + + if (NoWrapKind & OBO::NoUnsignedWrap) + Result = Result.intersectWith(umul_sat(Other), RangeType); + + return Result; +} + ConstantRange ConstantRange::smul_fast(const ConstantRange &Other) const { if (isEmptySet() || Other.isEmptySet()) return getEmpty(); @@ -1473,6 +1499,28 @@ return ConstantRange::getNonEmpty(std::move(Min), std::move(Max) + 1); } +ConstantRange ConstantRange::shlWithNoWrap(const ConstantRange &Other, + unsigned NoWrapKind, + PreferredRangeType RangeType) const { + // Calculate the range for "shl X Y" which is guaranteed not to wrap(overflow). + // (X is from this, and Y is from Other) + if (isEmptySet() || Other.isEmptySet()) + return getEmpty(); + if (isFullSet() && Other.isFullSet()) + return getFull(); + + using OBO = OverflowingBinaryOperator; + ConstantRange Result = shl(Other); + + if (NoWrapKind & OBO::NoSignedWrap) + Result = Result.intersectWith(sshl_sat(Other), RangeType); + + if (NoWrapKind & OBO::NoUnsignedWrap) + Result = Result.intersectWith(ushl_sat(Other), RangeType); + + return Result; +} + ConstantRange ConstantRange::lshr(const ConstantRange &Other) const { if (isEmptySet() || Other.isEmptySet()) Index: llvm/test/Transforms/CorrelatedValuePropagation/mul.ll =================================================================== --- llvm/test/Transforms/CorrelatedValuePropagation/mul.ll +++ llvm/test/Transforms/CorrelatedValuePropagation/mul.ll @@ -179,8 +179,7 @@ ; CHECK-NEXT: entry: ; CHECK-NEXT: [[C:%.*]] = add nuw nsw i8 [[B:%.*]], 1 ; CHECK-NEXT: [[MUL:%.*]] = mul nuw i8 [[C]], 4 -; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[MUL]], 0 -; CHECK-NEXT: ret i1 [[CMP]] +; CHECK-NEXT: ret i1 false ; entry: %c = add nuw nsw i8 %b, 1 @@ -194,8 +193,7 @@ ; CHECK-NEXT: entry: ; CHECK-NEXT: [[C:%.*]] = add nuw nsw i8 [[B:%.*]], 3 ; CHECK-NEXT: [[MUL:%.*]] = mul nuw i8 [[C]], 4 -; CHECK-NEXT: [[CMP:%.*]] = icmp ult i8 [[MUL]], 2 -; CHECK-NEXT: ret i1 [[CMP]] +; CHECK-NEXT: ret i1 false ; entry: %c = add nuw nsw i8 %b, 3 Index: llvm/test/Transforms/CorrelatedValuePropagation/shl.ll =================================================================== --- llvm/test/Transforms/CorrelatedValuePropagation/shl.ll +++ llvm/test/Transforms/CorrelatedValuePropagation/shl.ll @@ -86,7 +86,7 @@ ; CHECK-NEXT: br i1 [[CMP]], label [[BB:%.*]], label [[EXIT:%.*]] ; CHECK: bb: ; CHECK-NEXT: [[SHL:%.*]] = shl nuw nsw i8 [[A:%.*]], [[B]] -; CHECK-NEXT: ret i8 [[SHL]] +; CHECK-NEXT: ret i8 -1 ; CHECK: exit: ; CHECK-NEXT: ret i8 0 ; @@ -382,8 +382,7 @@ ; CHECK-NEXT: entry: ; CHECK-NEXT: [[C:%.*]] = add nuw nsw i8 [[B:%.*]], 1 ; CHECK-NEXT: [[SHL:%.*]] = shl nuw i8 [[C]], 2 -; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[SHL]], 0 -; CHECK-NEXT: ret i1 [[CMP]] +; CHECK-NEXT: ret i1 false ; entry: %c = add nuw nsw i8 %b, 1 @@ -397,8 +396,7 @@ ; CHECK-NEXT: entry: ; CHECK-NEXT: [[C:%.*]] = add nuw nsw i8 [[B:%.*]], 3 ; CHECK-NEXT: [[SHL:%.*]] = shl nuw i8 [[C]], 2 -; CHECK-NEXT: [[CMP:%.*]] = icmp ult i8 [[SHL]], 2 -; CHECK-NEXT: ret i1 [[CMP]] +; CHECK-NEXT: ret i1 false ; entry: %c = add nuw nsw i8 %b, 3