Index: llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp =================================================================== --- llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp +++ llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp @@ -375,6 +375,14 @@ if (match(Op1, m_LShr(m_Value(X), m_APInt(C))) && *C == C->getBitWidth() - 1) return BinaryOperator::CreateAnd(Builder.CreateAShr(X, *C), Op0); + // X * Y --> X & Y, iff X, Y can be only 1. Don't use known bits API as + // somewhat unclear from a canonicalization perspective, which may increase + // instruction count. (We'd probably want to represent it as trunc(X) ? Y : 0 + // rather than -X & Y, but it's increasing the count either way.) + if (match(Op0, m_And(m_Value(X), m_One())) && + match(Op1, m_And(m_Value(Y), m_One()))) + return BinaryOperator::CreateAnd(Op0, Op1); + // ((ashr X, 31) | 1) * X --> abs(X) // X * ((ashr X, 31) | 1) --> abs(X) if (match(&I, m_c_BinOp(m_Or(m_AShr(m_Value(X), Index: llvm/test/Transforms/InstCombine/mul-bool.ll =================================================================== --- /dev/null +++ llvm/test/Transforms/InstCombine/mul-bool.ll @@ -0,0 +1,57 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt < %s -passes=instcombine -S | FileCheck %s + +; Instcombine should be able to simplify mul operator. + +; Scalar tests +define i64 @scalar_mul_bit_x0_y0(i64 %x, i64 %y) { +; CHECK-LABEL: @scalar_mul_bit_x0_y0( +; CHECK-NEXT: [[AND2:%.*]] = and i64 [[Y:%.*]], 1 +; CHECK-NEXT: [[MUL:%.*]] = and i64 [[AND2]], [[X:%.*]] +; CHECK-NEXT: ret i64 [[MUL]] +; + %and1 = and i64 %x, 1 + %and2 = and i64 %y, 1 + %mul = mul i64 %and1, %and2 + ret i64 %mul +} + +; Negative test +define i64 @scalar_mul_bit_x0_y1(i64 %x, i64 %y) { +; CHECK-LABEL: @scalar_mul_bit_x0_y1( +; CHECK-NEXT: [[AND1:%.*]] = and i64 [[X:%.*]], 1 +; CHECK-NEXT: [[AND2:%.*]] = and i64 [[Y:%.*]], 2 +; CHECK-NEXT: [[MUL:%.*]] = mul nuw nsw i64 [[AND1]], [[AND2]] +; CHECK-NEXT: ret i64 [[MUL]] +; + %and1 = and i64 %x, 1 + %and2 = and i64 %y, 2 + %mul = mul i64 %and1, %and2 + ret i64 %mul +} + +define i64 @scalar_mul_bit_x0_yC(i64 %x, i64 %y, i64 %c) { +; CHECK-LABEL: @scalar_mul_bit_x0_yC( +; CHECK-NEXT: [[AND1:%.*]] = and i64 [[X:%.*]], 1 +; CHECK-NEXT: [[AND2:%.*]] = and i64 [[Y:%.*]], [[C:%.*]] +; CHECK-NEXT: [[MUL:%.*]] = mul nuw i64 [[AND1]], [[AND2]] +; CHECK-NEXT: ret i64 [[MUL]] +; + %and1 = and i64 %x, 1 + %and2 = and i64 %y, %c + %mul = mul i64 %and1, %and2 + ret i64 %mul +} + +; 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: [[AND2:%.*]] = and <2 x i64> [[Y:%.*]], +; CHECK-NEXT: [[MUL:%.*]] = and <2 x i64> [[AND2]], [[X:%.*]] +; CHECK-NEXT: ret <2 x i64> [[MUL]] +; + %and1 = and <2 x i64> %x, + %and2 = and <2 x i64> %y, + %mul = mul <2 x i64> %and1, %and2 + ret <2 x i64> %mul +}