Skip to content

Commit

Permalink
[ValueTracking] Recognize that and(x, add (x, -1)) clears the low bit
Browse files Browse the repository at this point in the history
This is a cleaned up version of a patch by John Regehr with permission. Originally found via the souper tool.

If we add an odd number to x, then bitwise-and the result with x, we know that the low bit of the result must be zero. Either it was zero in x originally, or the add cleared it in the temporary value. As a result, one of the two values anded together must have the bit cleared.

Differential Revision: http://reviews.llvm.org/D14315

llvm-svn: 252629
  • Loading branch information
preames committed Nov 10, 2015
1 parent cad135a commit 2d85874
Show file tree
Hide file tree
Showing 2 changed files with 81 additions and 0 deletions.
16 changes: 16 additions & 0 deletions llvm/lib/Analysis/ValueTracking.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1077,6 +1077,22 @@ static void computeKnownBitsFromOperator(Operator *I, APInt &KnownZero,
KnownOne &= KnownOne2;
// Output known-0 are known to be clear if zero in either the LHS | RHS.
KnownZero |= KnownZero2;

// and(x, add (x, -1)) is a common idiom that always clears the low bit;
// here we handle the more general case of adding any odd number by
// matching the form add(x, add(x, y)) where y is odd.
// TODO: This could be generalized to clearing any bit set in y where the
// following bit is known to be unset in y.
Value *Y = nullptr;
if (match(I->getOperand(0), m_Add(m_Specific(I->getOperand(1)),
m_Value(Y))) ||
match(I->getOperand(1), m_Add(m_Specific(I->getOperand(0)),
m_Value(Y)))) {
APInt KnownZero3(BitWidth, 0), KnownOne3(BitWidth, 0);
computeKnownBits(Y, KnownZero3, KnownOne3, DL, Depth + 1, Q);
if (KnownOne3.countTrailingOnes() > 0)
KnownZero |= APInt::getLowBitsSet(BitWidth, 1);
}
break;
}
case Instruction::Or: {
Expand Down
65 changes: 65 additions & 0 deletions llvm/test/Transforms/InstSimplify/add-mask.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
; RUN: opt -S -instsimplify < %s | FileCheck %s

define i1 @test(i32 %a) {
; CHECK-LABEL: @test
; CHECK: ret i1 false
%rhs = add i32 %a, -1
%and = and i32 %a, %rhs
%res = icmp eq i32 %and, 1
ret i1 %res
}

define i1 @test2(i32 %a) {
; CHECK-LABEL: @test2
; CHECK: ret i1 false
%rhs = add i32 %a, 1
%and = and i32 %a, %rhs
%res = icmp eq i32 %and, 1
ret i1 %res
}

define i1 @test3(i32 %a) {
; CHECK-LABEL: @test3
; CHECK: ret i1 false
%rhs = add i32 %a, 7
%and = and i32 %a, %rhs
%res = icmp eq i32 %and, 1
ret i1 %res
}

@B = external global i32
declare void @llvm.assume(i1)

; Known bits without a constant
define i1 @test4(i32 %a) {
; CHECK-LABEL: @test4
; CHECK: ret i1 false
%b = load i32, i32* @B
%b.and = and i32 %b, 1
%b.cnd = icmp eq i32 %b.and, 1
call void @llvm.assume(i1 %b.cnd)

%rhs = add i32 %a, %b
%and = and i32 %a, %rhs
%res = icmp eq i32 %and, 1
ret i1 %res
}

; Negative test - even number
define i1 @test5(i32 %a) {
; CHECK-LABEL: @test5
; CHECK: ret i1 %res
%rhs = add i32 %a, 2
%and = and i32 %a, %rhs
%res = icmp eq i32 %and, 1
ret i1 %res
}

define i1 @test6(i32 %a) {
; CHECK-LABEL: @test6
; CHECK: ret i1 false
%lhs = add i32 %a, -1
%and = and i32 %lhs, %a
%res = icmp eq i32 %and, 1
ret i1 %res
}

0 comments on commit 2d85874

Please sign in to comment.