Index: llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp =================================================================== --- llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp +++ llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp @@ -861,6 +861,16 @@ return nullptr; } +// If we get the pattern "(A & ~B) + B", we transfer this pattern to "(A & +// ~B) | B", And InstCombine will finally fold "(A & ~B) | B" to "A or B" +Instruction *InstCombinerImpl::foldAddWithOr(BinaryOperator &Add) { + Value *Op0 = Add.getOperand(0), *Op1 = Add.getOperand(1); + if (match(Op0, m_c_And(m_Not(m_Specific(Op1)), m_Value())) || + match(Op1, m_c_And(m_Not(m_Specific(Op0)), m_Value()))) + return BinaryOperator::CreateOr(Op0, Op1); + return nullptr; +} + Instruction *InstCombinerImpl::foldAddWithConstant(BinaryOperator &Add) { Value *Op0 = Add.getOperand(0), *Op1 = Add.getOperand(1); Constant *Op1C; @@ -1309,6 +1319,9 @@ if (Instruction *X = foldNoWrapAdd(I, Builder)) return X; + if (Instruction *X = foldAddWithOr(I)) + return X; + Value *LHS = I.getOperand(0), *RHS = I.getOperand(1); Type *Ty = I.getType(); if (Ty->isIntOrIntVectorTy(1)) Index: llvm/lib/Transforms/InstCombine/InstCombineInternal.h =================================================================== --- llvm/lib/Transforms/InstCombine/InstCombineInternal.h +++ llvm/lib/Transforms/InstCombine/InstCombineInternal.h @@ -620,6 +620,7 @@ Instruction *foldBinOpIntoSelectOrPhi(BinaryOperator &I); Instruction *foldAddWithConstant(BinaryOperator &Add); + Instruction *foldAddWithOr(BinaryOperator &Add); /// Try to rotate an operation below a PHI node, using PHI nodes for /// its operands. Index: llvm/test/Transforms/InstCombine/and-to-xor.ll =================================================================== --- /dev/null +++ llvm/test/Transforms/InstCombine/and-to-xor.ll @@ -0,0 +1,28 @@ +; Try to fold (A & ~B) + B to A | B +; RUN: opt < %s -instcombine -S | FileCheck %s + +; CHECK: define i32 @and_to_xor1(i32 %0, i32 %1) local_unnamed_addr +; CHECK-NOT: %{{[0-9]+}} = xor i32 %{{[0-9]+}}, -1 +; CHECK-NOT: %{{[0-9]+}} = and i32 %{{[0-9]+}}, %{{[0-9]+}} +; CHECK: %{{[0-9]+}} = or i32 %{{[0-9]+}}, %{{[0-9]+}} +define i32 @and_to_xor1(i32 %0, i32 %1) local_unnamed_addr #0 { + %3 = shl nsw i32 %0, 1 + %4 = mul nsw i32 %1, %0 + %5 = xor i32 %4, -1 + %6 = and i32 %3, %5 + %7 = add nsw i32 %6, %4 + ret i32 %7 +} + +; CHECK: define i32 @and_to_xor2(i32 %0, i32 %1) +; CHECK-NOT: %{{[0-9]+}} = xor i32 %{{[0-9]+}}, -1 +; CHECK-NOT: %{{[0-9]+}} = and i32 %{{[0-9]+}}, %{{[0-9]+}} +; CHECK: %{{[0-9]+}} = or i32 %{{[0-9]+}}, %{{[0-9]+}} +define i32 @and_to_xor2(i32 %0, i32 %1) local_unnamed_addr #0 { + %3 = shl nsw i32 %0, 1 + %4 = mul nsw i32 %1, %0 + %5 = xor i32 %4, -1 + %6 = and i32 %3, %5 + %7 = add nsw i32 %4, %6 + ret i32 %7 +}