[InstCombine] fold mul of sext bools to 'and'

Alive2:
  define i32 @src(i1 %x, i1 %y) {
  %0:
  %zx = sext i1 %x to i32
  %zy = sext i1 %y to i32
  %r = mul i32 %zx, %zy
  ret i32 %r
  }
  =>
  define i32 @tgt(i1 %x, i1 %y) {
  %0:
  %a = and i1 %x, %y
  %r = zext i1 %a to i32
  ret i32 %r
  }
  Transformation seems to be correct!

https://alive2.llvm.org/ce/z/gaPQxA
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp b/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
index 39b6c67..2965103 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
@@ -367,8 +367,11 @@
   }
 
   // (zext bool X) * (zext bool Y) --> zext (and X, Y)
-  if (match(Op0, m_ZExt(m_Value(X))) && X->getType()->isIntOrIntVectorTy(1) &&
-      match(Op1, m_ZExt(m_Value(Y))) && Y->getType()->isIntOrIntVectorTy(1) &&
+  // (sext bool X) * (sext bool Y) --> zext (and X, Y)
+  // Note: -1 * -1 == 1 * 1 == 1 (if the extends match, the result is the same)
+  if (((match(Op0, m_ZExt(m_Value(X))) && match(Op1, m_ZExt(m_Value(Y)))) ||
+       (match(Op0, m_SExt(m_Value(X))) && match(Op1, m_SExt(m_Value(Y))))) &&
+      X->getType()->isIntOrIntVectorTy(1) && X->getType() == Y->getType() &&
       (Op0->hasOneUse() || Op1->hasOneUse())) {
     Value *And = Builder.CreateAnd(X, Y, "mulbool");
     return CastInst::Create(Instruction::ZExt, And, I.getType());