[InstCombine] propagate "exact" through folds of div
authorSanjay Patel <spatel@rotateright.com>
Wed, 12 Oct 2022 13:05:34 +0000 (09:05 -0400)
committerSanjay Patel <spatel@rotateright.com>
Wed, 12 Oct 2022 13:25:05 +0000 (09:25 -0400)
These folds were added recently with:
6b869be8100d
8da2fa856f1b
...but they didn't account for the "exact" attribute,
and that can be safely propagated:
https://alive2.llvm.org/ce/z/F_WhnR
https://alive2.llvm.org/ce/z/ft9Cgr

llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
llvm/test/Transforms/InstCombine/div-shift.ll

index c7a7be1..b861406 100644 (file)
@@ -827,28 +827,34 @@ static Instruction *foldIDivShl(BinaryOperator &I,
   Type *Ty = I.getType();
 
   // With appropriate no-wrap constraints, remove a common factor in the
-  // dividend and divisor that is disguised as a left-shift.
+  // dividend and divisor that is disguised as a left-shifted value.
   Value *X, *Y, *Z;
-  if (match(Op1, m_Shl(m_Value(X), m_Value(Z))) &&
-      match(Op0, m_c_Mul(m_Specific(X), m_Value(Y)))) {
-    // Both operands must have the matching no-wrap for this kind of division.
-    auto *Mul = cast<OverflowingBinaryOperator>(Op0);
-    auto *Shl = cast<OverflowingBinaryOperator>(Op1);
-    bool HasNUW = Mul->hasNoUnsignedWrap() && Shl->hasNoUnsignedWrap();
-    bool HasNSW = Mul->hasNoSignedWrap() && Shl->hasNoSignedWrap();
-
-    // (X * Y) u/ (X << Z) --> Y u>> Z
-    if (!IsSigned && HasNUW)
-      return BinaryOperator::CreateLShr(Y, Z);
-
-    // (X * Y) s/ (X << Z) --> Y s/ (1 << Z)
-    if (IsSigned && HasNSW && (Op0->hasOneUse() || Op1->hasOneUse())) {
-      Value *Shl = Builder.CreateShl(ConstantInt::get(Ty, 1), Z);
-      return BinaryOperator::CreateSDiv(Y, Shl);
-    }
+  if (!match(Op1, m_Shl(m_Value(X), m_Value(Z))) ||
+      !match(Op0, m_c_Mul(m_Specific(X), m_Value(Y))))
+    return nullptr;
+
+  // Both operands must have the matching no-wrap for this kind of division.
+  Instruction *Ret = nullptr;
+  auto *Mul = cast<OverflowingBinaryOperator>(Op0);
+  auto *Shl = cast<OverflowingBinaryOperator>(Op1);
+  bool HasNUW = Mul->hasNoUnsignedWrap() && Shl->hasNoUnsignedWrap();
+  bool HasNSW = Mul->hasNoSignedWrap() && Shl->hasNoSignedWrap();
+
+  // (X * Y) u/ (X << Z) --> Y u>> Z
+  if (!IsSigned && HasNUW)
+    Ret = BinaryOperator::CreateLShr(Y, Z);
+
+  // (X * Y) s/ (X << Z) --> Y s/ (1 << Z)
+  if (IsSigned && HasNSW && (Op0->hasOneUse() || Op1->hasOneUse())) {
+    Value *Shl = Builder.CreateShl(ConstantInt::get(Ty, 1), Z);
+    Ret = BinaryOperator::CreateSDiv(Y, Shl);
   }
 
-  return nullptr;
+  if (!Ret)
+    return nullptr;
+
+  Ret->setIsExact(I.isExact());
+  return Ret;
 }
 
 /// This function implements the transforms common to both integer division
index d357ec7..bac752a 100644 (file)
@@ -314,7 +314,7 @@ define i5 @sdiv_mul_shl_nsw(i5 %x, i5 %y, i5 %z) {
 define i5 @sdiv_mul_shl_nsw_exact_commute1(i5 %x, i5 %y, i5 %z) {
 ; CHECK-LABEL: @sdiv_mul_shl_nsw_exact_commute1(
 ; CHECK-NEXT:    [[TMP1:%.*]] = shl nuw i5 1, [[Z:%.*]]
-; CHECK-NEXT:    [[D:%.*]] = sdiv i5 [[Y:%.*]], [[TMP1]]
+; CHECK-NEXT:    [[D:%.*]] = sdiv exact i5 [[Y:%.*]], [[TMP1]]
 ; CHECK-NEXT:    ret i5 [[D]]
 ;
   %m1 = mul nsw i5 %y, %x
@@ -453,7 +453,7 @@ define i5 @udiv_mul_shl_nuw(i5 %x, i5 %y, i5 %z) {
 
 define i5 @udiv_mul_shl_nuw_exact_commute1(i5 %x, i5 %y, i5 %z) {
 ; CHECK-LABEL: @udiv_mul_shl_nuw_exact_commute1(
-; CHECK-NEXT:    [[D:%.*]] = lshr i5 [[Y:%.*]], [[Z:%.*]]
+; CHECK-NEXT:    [[D:%.*]] = lshr exact i5 [[Y:%.*]], [[Z:%.*]]
 ; CHECK-NEXT:    ret i5 [[D]]
 ;
   %m1 = mul nuw i5 %y, %x