Index: llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp =================================================================== --- llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp +++ llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp @@ -375,6 +375,15 @@ 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 0 or 1 + { + KnownBits XKnown = computeKnownBits(Op0, 0, &I); + KnownBits YKnown = computeKnownBits(Op1, 0, &I); + if ((XKnown.countMaxPopulation() == 1) && + (YKnown.countMaxPopulation() == 1)) + 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/trunc.ll =================================================================== --- llvm/test/Transforms/InstCombine/trunc.ll +++ llvm/test/Transforms/InstCombine/trunc.ll @@ -1021,3 +1021,39 @@ %sub = add nsw i16 %cast, -1 ret i16 %sub } + +define i64 @PR55599_One0(i64 %x, i64 %y) { +; CHECK-LABEL: @PR55599_One0( +; 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 +} + +define i64 @PR55599_One1(i64 %x, i64 %y, i64 %c) { +; CHECK-LABEL: @PR55599_One1( +; 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 +} + +; Aleady supported before +define i64 @PR55599_Zero(i64 %x, i64 %y, i64 %c) { +; CHECK-LABEL: @PR55599_Zero( +; CHECK-NEXT: ret i64 0 +; + %and1 = and i64 %x, %c + %and2 = and i64 %y, 0 + %mul = mul i64 %and1, %and2 + ret i64 %mul +}