Index: llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp =================================================================== --- llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp +++ llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp @@ -305,6 +305,13 @@ if (I.getType()->isIntOrIntVectorTy(1)) return BinaryOperator::CreateAnd(Op0, Op1); + // X * Y --> X & Y, iff X, Y can be only 1. + // Note: We could use known bits to generalize this and related patterns with + // shifts/truncs + if (match(Op0, m_And(m_Value(X), m_One())) && + match(Op1, m_And(m_Value(Y), m_One()))) + return BinaryOperator::CreateAnd(Op0, Op1); + // X*(1 << Y) --> X << Y // (1 << Y)*X --> X << Y { Index: llvm/test/Transforms/InstCombine/mul-masked-bits.ll =================================================================== --- llvm/test/Transforms/InstCombine/mul-masked-bits.ll +++ llvm/test/Transforms/InstCombine/mul-masked-bits.ll @@ -169,9 +169,8 @@ ; Scalar tests define i64 @scalar_mul_bit_x0_y0(i64 %x, i64 %y) { ; CHECK-LABEL: @scalar_mul_bit_x0_y0( -; CHECK-NEXT: [[AND1:%.*]] = and i64 [[X:%.*]], 1 ; CHECK-NEXT: [[AND2:%.*]] = and i64 [[Y:%.*]], 1 -; CHECK-NEXT: [[MUL:%.*]] = mul nuw nsw i64 [[AND1]], [[AND2]] +; CHECK-NEXT: [[MUL:%.*]] = and i64 [[AND2]], [[X:%.*]] ; CHECK-NEXT: ret i64 [[MUL]] ; %and1 = and i64 %x, 1 @@ -210,9 +209,8 @@ ; Vector tests define <2 x i64> @vector_mul_bit_x0_y0(<2 x i64> %x, <2 x i64> %y) { ; CHECK-LABEL: @vector_mul_bit_x0_y0( -; CHECK-NEXT: [[AND1:%.*]] = and <2 x i64> [[X:%.*]], ; CHECK-NEXT: [[AND2:%.*]] = and <2 x i64> [[Y:%.*]], -; CHECK-NEXT: [[MUL:%.*]] = mul nuw nsw <2 x i64> [[AND1]], [[AND2]] +; CHECK-NEXT: [[MUL:%.*]] = and <2 x i64> [[AND2]], [[X:%.*]] ; CHECK-NEXT: ret <2 x i64> [[MUL]] ; %and1 = and <2 x i64> %x,