Index: lib/Transforms/InstCombine/InstCombineAndOrXor.cpp =================================================================== --- lib/Transforms/InstCombine/InstCombineAndOrXor.cpp +++ lib/Transforms/InstCombine/InstCombineAndOrXor.cpp @@ -1272,6 +1272,14 @@ if (Value *V = FoldLogicalPlusAnd(Op0LHS, Op0RHS, AndRHS, true, I)) return BinaryOperator::CreateAnd(V, AndRHS); + // -x & 1 -> x & 1 + if (AndRHSMask == 1 && isa(Op0LHS)) { + const APInt &Op0LHSMask = dyn_cast(Op0LHS)->getValue(); + if (Op0LHSMask == 0) { + return BinaryOperator::CreateAnd(Op0RHS, AndRHS); + } + } + // (A - N) & AndRHS -> -N & AndRHS iff A&AndRHS==0 and AndRHS // has 1's for all bits that the subtraction with A might affect. if (Op0I->hasOneUse() && !match(Op0LHS, m_Zero())) { Index: test/Transforms/InstCombine/and-with-one.ll =================================================================== --- /dev/null +++ test/Transforms/InstCombine/and-with-one.ll @@ -0,0 +1,25 @@ +; RUN: opt < %s -instcombine -S | FileCheck %s + +define i64 @test1(i64 %x) { +; CHECK-LABEL: @test1( +; CHECK-NOT: %sub = sub nsw i64 0, %x +; CHECK-NOT: %and = and i64 %sub, 1 +; CHECK-NEXT: %and = and i64 %x, 1 +; CHECK-NEXT: ret i64 %and + %sub = sub nsw i64 0, %x + %and = and i64 %sub, 1 + ret i64 %and +} + +define i64 @test2(i64 %x) { +; CHECK-LABEL: @test2( +; CHECK-NOT: %sub = sub nsw i64 0, %x +; CHECK-NEXT: %and = and i64 %x, 1 +; CHECK-NOT: %add = add i64 %sub, %and +; CHECK-NEXT: %add = sub i64 %and, %x +; CHECK-NEXT: ret i64 %add + %sub = sub nsw i64 0, %x + %and = and i64 %sub, 1 + %add = add i64 %sub, %and + ret i64 %add +}