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 isKnownNonZero(Op, Depth + 1, Q);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Return true if it is known that V1 != V2.
|
/// Return true if it is known that V1 != V2.
|
||||||
static bool isKnownNonEqual(const Value *V1, const Value *V2, unsigned Depth,
|
static bool isKnownNonEqual(const Value *V1, const Value *V2, unsigned Depth,
|
||||||
const Query &Q) {
|
const Query &Q) {
|
||||||
|
@ -2514,7 +2515,9 @@ static bool isKnownNonEqual(const Value *V1, const Value *V2, unsigned Depth,
|
||||||
if (Depth >= MaxAnalysisRecursionDepth)
|
if (Depth >= MaxAnalysisRecursionDepth)
|
||||||
return false;
|
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 *O1 = dyn_cast<Operator>(V1);
|
||||||
auto *O2 = dyn_cast<Operator>(V2);
|
auto *O2 = dyn_cast<Operator>(V2);
|
||||||
if (O1 && O2 && O1->getOpcode() == O2->getOpcode()) {
|
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),
|
return isKnownNonEqual(O1->getOperand(0), O2->getOperand(0),
|
||||||
Depth + 1, Q);
|
Depth + 1, Q);
|
||||||
break;
|
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::SExt:
|
||||||
case Instruction::ZExt:
|
case Instruction::ZExt:
|
||||||
if (O1->getOperand(0)->getType() == O2->getOperand(0)->getType())
|
if (O1->getOperand(0)->getType() == O2->getOperand(0)->getType())
|
||||||
|
|
|
@ -130,4 +130,76 @@ define i1 @sub2(i8 %B, i8 %C) {
|
||||||
ret i1 %cmp
|
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 = !{ i8 1, i8 5 }
|
||||||
|
|
Loading…
Reference in New Issue