Skip to content

Commit

Permalink
Teach isKnownNonEqual how to recurse through invertible multiplies
Browse files Browse the repository at this point in the history
Build on the work started in 8f07629, and add the multiply case. In the process, more clearly describe the requirement for the operation we're looking through.

Differential Revision: https://reviews.llvm.org/D92726
  • Loading branch information
preames committed Dec 7, 2020
1 parent 6dad7ec commit 2656885
Show file tree
Hide file tree
Showing 2 changed files with 93 additions and 1 deletion.
22 changes: 21 additions & 1 deletion llvm/lib/Analysis/ValueTracking.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2502,6 +2502,7 @@ static bool isAddOfNonZero(const Value *V1, const Value *V2, unsigned Depth,
return isKnownNonZero(Op, Depth + 1, Q);
}


/// Return true if it is known that V1 != V2.
static bool isKnownNonEqual(const Value *V1, const Value *V2, unsigned Depth,
const Query &Q) {
Expand All @@ -2514,7 +2515,9 @@ static bool isKnownNonEqual(const Value *V1, const Value *V2, unsigned Depth,
if (Depth >= MaxAnalysisRecursionDepth)
return false;

// See if we can recurse through (exactly one of) our operands.
// See if we can recurse through (exactly one of) our operands. This
// requires our operation be 1-to-1 and map every input value to exactly
// one output value. Such an operation is invertible.
auto *O1 = dyn_cast<Operator>(V1);
auto *O2 = dyn_cast<Operator>(V2);
if (O1 && O2 && O1->getOpcode() == O2->getOpcode()) {
Expand All @@ -2530,6 +2533,23 @@ static bool isKnownNonEqual(const Value *V1, const Value *V2, unsigned Depth,
return isKnownNonEqual(O1->getOperand(0), O2->getOperand(0),
Depth + 1, Q);
break;
case Instruction::Mul:
// invertible if A * B == (A * B) mod 2^N where A, and B are integers
// and N is the bitwdith. The nsw case is non-obvious, but proven by
// alive2: https://alive2.llvm.org/ce/z/Z6D5qK
if ((!cast<BinaryOperator>(O1)->hasNoUnsignedWrap() ||
!cast<BinaryOperator>(O2)->hasNoUnsignedWrap()) &&
(!cast<BinaryOperator>(O1)->hasNoSignedWrap() ||
!cast<BinaryOperator>(O2)->hasNoSignedWrap()))
break;

// Assume operand order has been canonicalized
if (O1->getOperand(1) == O2->getOperand(1) &&
isa<ConstantInt>(O1->getOperand(1)) &&
!cast<ConstantInt>(O1->getOperand(1))->isZero())
return isKnownNonEqual(O1->getOperand(0), O2->getOperand(0),
Depth + 1, Q);
break;
case Instruction::SExt:
case Instruction::ZExt:
if (O1->getOperand(0)->getType() == O2->getOperand(0)->getType())
Expand Down
72 changes: 72 additions & 0 deletions llvm/test/Analysis/ValueTracking/known-non-equal.ll
Original file line number Diff line number Diff line change
Expand Up @@ -130,4 +130,76 @@ define i1 @sub2(i8 %B, i8 %C) {
ret i1 %cmp
}

; op could wrap mapping two values to the same output value.
define i1 @mul1(i8 %B) {
; CHECK-LABEL: @mul1(
; CHECK-NEXT: [[A:%.*]] = add i8 [[B:%.*]], 1
; CHECK-NEXT: [[A_OP:%.*]] = mul i8 [[A]], 27
; CHECK-NEXT: [[B_OP:%.*]] = mul i8 [[B]], 27
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[A_OP]], [[B_OP]]
; CHECK-NEXT: ret i1 [[CMP]]
;
%A = add i8 %B, 1
%A.op = mul i8 %A, 27
%B.op = mul i8 %B, 27

%cmp = icmp eq i8 %A.op, %B.op
ret i1 %cmp
}

define i1 @mul2(i8 %B) {
; CHECK-LABEL: @mul2(
; CHECK-NEXT: ret i1 false
;
%A = add i8 %B, 1
%A.op = mul nuw i8 %A, 27
%B.op = mul nuw i8 %B, 27

%cmp = icmp eq i8 %A.op, %B.op
ret i1 %cmp
}

define i1 @mul3(i8 %B) {
; CHECK-LABEL: @mul3(
; CHECK-NEXT: ret i1 false
;
%A = add i8 %B, 1
%A.op = mul nsw i8 %A, 27
%B.op = mul nsw i8 %B, 27

%cmp = icmp eq i8 %A.op, %B.op
ret i1 %cmp
}

; Multiply by zero collapses all values to one
define i1 @mul4(i8 %B) {
; CHECK-LABEL: @mul4(
; CHECK-NEXT: ret i1 true
;
%A = add i8 %B, 1
%A.op = mul nuw i8 %A, 0
%B.op = mul nuw i8 %B, 0

%cmp = icmp eq i8 %A.op, %B.op
ret i1 %cmp
}

; C might be zero, we can't tell
define i1 @mul5(i8 %B, i8 %C) {
; CHECK-LABEL: @mul5(
; CHECK-NEXT: [[A:%.*]] = add i8 [[B:%.*]], 1
; CHECK-NEXT: [[A_OP:%.*]] = mul nuw nsw i8 [[A]], [[C:%.*]]
; CHECK-NEXT: [[B_OP:%.*]] = mul nuw nsw i8 [[B]], [[C]]
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[A_OP]], [[B_OP]]
; CHECK-NEXT: ret i1 [[CMP]]
;
%A = add i8 %B, 1
%A.op = mul nsw nuw i8 %A, %C
%B.op = mul nsw nuw i8 %B, %C

%cmp = icmp eq i8 %A.op, %B.op
ret i1 %cmp
}


!0 = !{ i8 1, i8 5 }

0 comments on commit 2656885

Please sign in to comment.