forked from OSchip/llvm-project
Teach isKnownNonEqual how to recurse through invertible multiplies
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
This commit is contained in:
parent
6dad7ec539
commit
2656885390
|
@ -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) {
|
||||
|
@ -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()) {
|
||||
|
@ -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())
|
||||
|
|
|
@ -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 }
|
||||
|
|
Loading…
Reference in New Issue