[llvm] [InstCombine] simplify `(X * C0) / (X * C1)` into `C0 / C1`. (PR #73204)

Nikita Popov via llvm-commits llvm-commits at lists.llvm.org
Fri Dec 8 02:22:50 PST 2023


================
@@ -1207,6 +1207,49 @@ Instruction *InstCombinerImpl::commonIDivTransforms(BinaryOperator &I) {
     }
   }
 
+  // (X * Y) / (X * Z) --> Y / Z (and commuted variants)
+  if (match(Op0, m_Mul(m_Value(X), m_Value(Y)))) {
+    auto OB0HasNSW = cast<OverflowingBinaryOperator>(Op0)->hasNoSignedWrap();
+    auto OB0HasNUW = cast<OverflowingBinaryOperator>(Op0)->hasNoUnsignedWrap();
+
+    auto CreateDivOrNull = [&](Value *A, Value *B) -> Instruction * {
+      auto OB1HasNSW = cast<OverflowingBinaryOperator>(Op1)->hasNoSignedWrap();
+      auto OB1HasNUW =
+          cast<OverflowingBinaryOperator>(Op1)->hasNoUnsignedWrap();
+      const APInt *C1, *C2;
+      if (IsSigned && OB0HasNSW) {
+        if (OB1HasNSW && match(B, m_APInt(C1)) && !C1->isAllOnes())
+          return BinaryOperator::CreateSDiv(A, B);
+        if (match(A, m_APInt(C1)) && match(B, m_APInt(C2)) &&
+            !C2->isSignMask()) {
----------------
nikic wrote:

This `!C2->isSignMask()` check doesn't seem to match what the alive2 proof does, which checks whether the multiplication result is the sign mask, not one of the multiplication operands.

It does not verify if I check `%c1` instead: https://alive2.llvm.org/ce/z/5uSr3w (It's pretty confusing that the meaning of c1/c2 in the proofs and C1/C2 in the code is inverted.)

https://github.com/llvm/llvm-project/pull/73204


More information about the llvm-commits mailing list