Skip to content

Commit

Permalink
[InstCombine] reduce code for flip of masked bit; NFC
Browse files Browse the repository at this point in the history
There are 1-2 potential follow-up NFC commits to reduce
this further on the way to generalizing this for vectors.

The operand replacing path should be dead code because demanded
bits handles that more generally (D91415).
  • Loading branch information
rotateright committed Nov 15, 2020
1 parent e56103d commit 6ddc237
Show file tree
Hide file tree
Showing 4 changed files with 80 additions and 89 deletions.
75 changes: 33 additions & 42 deletions llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
Expand Up @@ -114,47 +114,39 @@ static Value *SimplifyBSwap(BinaryOperator &I,
return Builder.CreateCall(F, BinOp);
}

/// This handles expressions of the form ((val OP C1) & C2). Where
/// the Op parameter is 'OP', OpRHS is 'C1', and AndRHS is 'C2'.
Instruction *InstCombinerImpl::OptAndOp(BinaryOperator *Op, ConstantInt *OpRHS,
ConstantInt *AndRHS,
/// This handles expressions of the form ((X + OpRHS) & AndRHS).
Instruction *InstCombinerImpl::OptAndOp(BinaryOperator *Op, ConstantInt *AndRHS,
BinaryOperator &TheAnd) {
Value *X = Op->getOperand(0);

switch (Op->getOpcode()) {
default: break;
case Instruction::Add:
if (Op->hasOneUse()) {
// Adding a one to a single bit bit-field should be turned into an XOR
// of the bit. First thing to check is to see if this AND is with a
// single bit constant.
const APInt &AndRHSV = AndRHS->getValue();

// If there is only one bit set.
if (AndRHSV.isPowerOf2()) {
// Ok, at this point, we know that we are masking the result of the
// ADD down to exactly one bit. If the constant we are adding has
// no bits set below this bit, then we can eliminate the ADD.
const APInt& AddRHS = OpRHS->getValue();

// Check to see if any bits below the one bit set in AndRHSV are set.
if ((AddRHS & (AndRHSV - 1)).isNullValue()) {
// If not, the only thing that can effect the output of the AND is
// the bit specified by AndRHSV. If that bit is set, the effect of
// the XOR is to toggle the bit. If it is clear, then the ADD has
// no effect.
if ((AddRHS & AndRHSV).isNullValue()) { // Bit is not set, noop
return replaceOperand(TheAnd, 0, X);
} else {
// Pull the XOR out of the AND.
Value *NewAnd = Builder.CreateAnd(X, AndRHS);
NewAnd->takeName(Op);
return BinaryOperator::CreateXor(NewAnd, AndRHS);
}
}
}
Value *X;
const APInt *C;
if (!match(Op, m_OneUse(m_Add(m_Value(X), m_APInt(C)))))
return nullptr;

// Adding a one to a single bit bit-field should be turned into an XOR
// of the bit. First thing to check is to see if this AND is with a
// single bit constant.
const APInt &AndRHSV = AndRHS->getValue();

// If there is only one bit set.
if (AndRHSV.isPowerOf2()) {
// Ok, at this point, we know that we are masking the result of the
// ADD down to exactly one bit. If the constant we are adding has
// no bits set below this bit, then we can eliminate the ADD.

// Check to see if any bits below the one bit set in AndRHSV are set.
if ((*C & (AndRHSV - 1)).isNullValue()) {
// If not, the only thing that can effect the output of the AND is
// the bit specified by AndRHSV. If that bit is set, the effect of
// the XOR is to toggle the bit. If it is clear, then the ADD has
// no effect.
if ((*C & AndRHSV).isNullValue()) // Bit is not set, noop
return replaceOperand(TheAnd, 0, X);

// Pull the XOR out of the AND.
Value *NewAnd = Builder.CreateAnd(X, AndRHS);
NewAnd->takeName(Op);
return BinaryOperator::CreateXor(NewAnd, AndRHS);
}
break;
}
return nullptr;
}
Expand Down Expand Up @@ -1868,9 +1860,8 @@ Instruction *InstCombinerImpl::visitAnd(BinaryOperator &I) {
}
}

if (ConstantInt *Op0CI = dyn_cast<ConstantInt>(Op0I->getOperand(1)))
if (Instruction *Res = OptAndOp(Op0I, Op0CI, AndRHS, I))
return Res;
if (Instruction *Res = OptAndOp(Op0I, AndRHS, I))
return Res;
}
}

Expand Down
4 changes: 2 additions & 2 deletions llvm/lib/Transforms/InstCombine/InstCombineInternal.h
Expand Up @@ -711,8 +711,8 @@ class LLVM_LIBRARY_VISIBILITY InstCombinerImpl final
Instruction *foldSelectInstWithICmp(SelectInst &SI, ICmpInst *ICI);
Instruction *foldSelectValueEquivalence(SelectInst &SI, ICmpInst &ICI);

Instruction *OptAndOp(BinaryOperator *Op, ConstantInt *OpRHS,
ConstantInt *AndRHS, BinaryOperator &TheAnd);
Instruction *OptAndOp(BinaryOperator *Op, ConstantInt *AndRHS,
BinaryOperator &TheAnd);

Value *insertRangeTest(Value *V, const APInt &Lo, const APInt &Hi,
bool isSigned, bool Inside);
Expand Down
45 changes: 0 additions & 45 deletions llvm/test/Transforms/InstCombine/add.ll
Expand Up @@ -336,51 +336,6 @@ define i8 @test15(i8 %A) {
ret i8 %C
}

; Only one bit set
define i8 @test16(i8 %A) {
; CHECK-LABEL: @test16(
; CHECK-NEXT: [[B:%.*]] = and i8 [[A:%.*]], 16
; CHECK-NEXT: [[C:%.*]] = xor i8 [[B]], 16
; CHECK-NEXT: ret i8 [[C]]
;
%B = add i8 %A, 16
%C = and i8 %B, 16
ret i8 %C
}

define <2 x i8> @test16_uniform(<2 x i8> %A) {
; CHECK-LABEL: @test16_uniform(
; CHECK-NEXT: [[B:%.*]] = add <2 x i8> [[A:%.*]], <i8 16, i8 16>
; CHECK-NEXT: [[C:%.*]] = and <2 x i8> [[B]], <i8 16, i8 16>
; CHECK-NEXT: ret <2 x i8> [[C]]
;
%B = add <2 x i8> %A, <i8 16, i8 16>
%C = and <2 x i8> %B, <i8 16, i8 16>
ret <2 x i8> %C
}

define <2 x i8> @test16_undef(<2 x i8> %A) {
; CHECK-LABEL: @test16_undef(
; CHECK-NEXT: [[B:%.*]] = add <2 x i8> [[A:%.*]], <i8 16, i8 undef>
; CHECK-NEXT: [[C:%.*]] = and <2 x i8> [[B]], <i8 16, i8 undef>
; CHECK-NEXT: ret <2 x i8> [[C]]
;
%B = add <2 x i8> %A, <i8 16, i8 undef>
%C = and <2 x i8> %B, <i8 16, i8 undef>
ret <2 x i8> %C
}

define <2 x i8> @test16_nonuniform(<2 x i8> %A) {
; CHECK-LABEL: @test16_nonuniform(
; CHECK-NEXT: [[B:%.*]] = add <2 x i8> [[A:%.*]], <i8 16, i8 4>
; CHECK-NEXT: [[C:%.*]] = and <2 x i8> [[B]], <i8 16, i8 4>
; CHECK-NEXT: ret <2 x i8> [[C]]
;
%B = add <2 x i8> %A, <i8 16, i8 4>
%C = and <2 x i8> %B, <i8 16, i8 4>
ret <2 x i8> %C
}

define i32 @test17(i32 %A) {
; CHECK-LABEL: @test17(
; CHECK-NEXT: [[C:%.*]] = sub i32 0, [[A:%.*]]
Expand Down
45 changes: 45 additions & 0 deletions llvm/test/Transforms/InstCombine/and.ll
Expand Up @@ -1134,3 +1134,48 @@ define <2 x i8> @lowmask_add_vec(<2 x i8> %x, <2 x i8>* %p) {
%r = and <2 x i8> %a, <i8 16, i8 32> ; 0x10, 0x20
ret <2 x i8> %r
}

; Only one bit set
define i8 @flip_masked_bit(i8 %A) {
; CHECK-LABEL: @flip_masked_bit(
; CHECK-NEXT: [[B:%.*]] = and i8 [[A:%.*]], 16
; CHECK-NEXT: [[C:%.*]] = xor i8 [[B]], 16
; CHECK-NEXT: ret i8 [[C]]
;
%B = add i8 %A, 16
%C = and i8 %B, 16
ret i8 %C
}

define <2 x i8> @flip_masked_bit_uniform(<2 x i8> %A) {
; CHECK-LABEL: @flip_masked_bit_uniform(
; CHECK-NEXT: [[B:%.*]] = add <2 x i8> [[A:%.*]], <i8 16, i8 16>
; CHECK-NEXT: [[C:%.*]] = and <2 x i8> [[B]], <i8 16, i8 16>
; CHECK-NEXT: ret <2 x i8> [[C]]
;
%B = add <2 x i8> %A, <i8 16, i8 16>
%C = and <2 x i8> %B, <i8 16, i8 16>
ret <2 x i8> %C
}

define <2 x i8> @flip_masked_bit_undef(<2 x i8> %A) {
; CHECK-LABEL: @flip_masked_bit_undef(
; CHECK-NEXT: [[B:%.*]] = add <2 x i8> [[A:%.*]], <i8 16, i8 undef>
; CHECK-NEXT: [[C:%.*]] = and <2 x i8> [[B]], <i8 16, i8 undef>
; CHECK-NEXT: ret <2 x i8> [[C]]
;
%B = add <2 x i8> %A, <i8 16, i8 undef>
%C = and <2 x i8> %B, <i8 16, i8 undef>
ret <2 x i8> %C
}

define <2 x i8> @flip_masked_bit_nonuniform(<2 x i8> %A) {
; CHECK-LABEL: @flip_masked_bit_nonuniform(
; CHECK-NEXT: [[B:%.*]] = add <2 x i8> [[A:%.*]], <i8 16, i8 4>
; CHECK-NEXT: [[C:%.*]] = and <2 x i8> [[B]], <i8 16, i8 4>
; CHECK-NEXT: ret <2 x i8> [[C]]
;
%B = add <2 x i8> %A, <i8 16, i8 4>
%C = and <2 x i8> %B, <i8 16, i8 4>
ret <2 x i8> %C
}

0 comments on commit 6ddc237

Please sign in to comment.