[llvm] r312885 - [InstSimplify] refactor udiv/urem code and add tests; NFCI

Sanjay Patel via llvm-commits llvm-commits at lists.llvm.org
Sun Sep 10 10:55:08 PDT 2017


Author: spatel
Date: Sun Sep 10 10:55:08 2017
New Revision: 312885

URL: http://llvm.org/viewvc/llvm-project?rev=312885&view=rev
Log:
[InstSimplify] refactor udiv/urem code and add tests; NFCI

This removes some duplicated code and makes it easier to support signed div/rem
in a similar way if we want to do that. Note that the existing comments were not
accurate - we don't need a constant divisor to simplify; icmp simplification does
more than that. But as the added tests show, it could go even further.

Modified:
    llvm/trunk/lib/Analysis/InstructionSimplify.cpp
    llvm/trunk/test/Transforms/InstSimplify/div.ll
    llvm/trunk/test/Transforms/InstSimplify/rem.ll

Modified: llvm/trunk/lib/Analysis/InstructionSimplify.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Analysis/InstructionSimplify.cpp?rev=312885&r1=312884&r2=312885&view=diff
==============================================================================
--- llvm/trunk/lib/Analysis/InstructionSimplify.cpp (original)
+++ llvm/trunk/lib/Analysis/InstructionSimplify.cpp Sun Sep 10 10:55:08 2017
@@ -1075,6 +1075,33 @@ Value *llvm::SimplifySDivInst(Value *Op0
   return ::SimplifySDivInst(Op0, Op1, Q, RecursionLimit);
 }
 
+/// Given a predicate and two operands, return true if the comparison is true.
+/// This is a helper for div/rem simplification where we return some other value
+/// when we can prove a relationship between the operands.
+static bool isICmpTrue(ICmpInst::Predicate Pred, Value *LHS, Value *RHS,
+                       const SimplifyQuery &Q, unsigned MaxRecurse) {
+  Value *V = SimplifyICmpInst(Pred, LHS, RHS, Q, MaxRecurse);
+  Constant *C = dyn_cast_or_null<Constant>(V);
+  return (C && C->isAllOnesValue());
+}
+
+static Value *simplifyUnsignedDivRem(Value *Op0, Value *Op1,
+                                     const SimplifyQuery &Q,
+                                     unsigned MaxRecurse, bool IsDiv) {
+  // Recursion is always used, so bail out at once if we already hit the limit.
+  if (!MaxRecurse--)
+    return nullptr;
+
+  // If we can prove that the quotient is unsigned less than the divisor, then
+  // we know the answer:
+  // X / Y --> 0
+  // X % Y --> X
+  if (isICmpTrue(ICmpInst::ICMP_ULT, Op0, Op1, Q, MaxRecurse))
+    return IsDiv ? Constant::getNullValue(Op0->getType()) : Op0;
+
+  return nullptr;
+}
+
 /// Given operands for a UDiv, see if we can fold the result.
 /// If not, this returns null.
 static Value *SimplifyUDivInst(Value *Op0, Value *Op1, const SimplifyQuery &Q,
@@ -1082,15 +1109,8 @@ static Value *SimplifyUDivInst(Value *Op
   if (Value *V = SimplifyDiv(Instruction::UDiv, Op0, Op1, Q, MaxRecurse))
     return V;
 
-  // udiv %V, C -> 0 if %V < C
-  if (MaxRecurse) {
-    if (Constant *C = dyn_cast_or_null<Constant>(SimplifyICmpInst(
-            ICmpInst::ICMP_ULT, Op0, Op1, Q, MaxRecurse - 1))) {
-      if (C->isAllOnesValue()) {
-        return Constant::getNullValue(Op0->getType());
-      }
-    }
-  }
+  if (Value *V = simplifyUnsignedDivRem(Op0, Op1, Q, MaxRecurse, true))
+    return V;
 
   return nullptr;
 }
@@ -1198,15 +1218,8 @@ static Value *SimplifyURemInst(Value *Op
   if (Value *V = SimplifyRem(Instruction::URem, Op0, Op1, Q, MaxRecurse))
     return V;
 
-  // urem %V, C -> %V if %V < C
-  if (MaxRecurse) {
-    if (Constant *C = dyn_cast_or_null<Constant>(SimplifyICmpInst(
-            ICmpInst::ICMP_ULT, Op0, Op1, Q, MaxRecurse - 1))) {
-      if (C->isAllOnesValue()) {
-        return Op0;
-      }
-    }
-  }
+  if (Value *V = simplifyUnsignedDivRem(Op0, Op1, Q, MaxRecurse, false))
+    return V;
 
   return nullptr;
 }

Modified: llvm/trunk/test/Transforms/InstSimplify/div.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstSimplify/div.ll?rev=312885&r1=312884&r2=312885&view=diff
==============================================================================
--- llvm/trunk/test/Transforms/InstSimplify/div.ll (original)
+++ llvm/trunk/test/Transforms/InstSimplify/div.ll Sun Sep 10 10:55:08 2017
@@ -54,6 +54,74 @@ define <2 x i1> @udiv_bool_vec(<2 x i1>
   ret <2 x i1> %div
 }
 
+define i32 @udiv_quotient_known_smaller_than_constant_denom(i32 %x) {
+; CHECK-LABEL: @udiv_quotient_known_smaller_than_constant_denom(
+; CHECK-NEXT:    ret i32 0
+;
+  %and = and i32 %x, 250
+  %div = udiv i32 %and, 251
+  ret i32 %div
+}
+
+define i32 @not_udiv_quotient_known_smaller_than_constant_denom(i32 %x) {
+; CHECK-LABEL: @not_udiv_quotient_known_smaller_than_constant_denom(
+; CHECK-NEXT:    [[AND:%.*]] = and i32 %x, 251
+; CHECK-NEXT:    [[DIV:%.*]] = udiv i32 [[AND]], 251
+; CHECK-NEXT:    ret i32 [[DIV]]
+;
+  %and = and i32 %x, 251
+  %div = udiv i32 %and, 251
+  ret i32 %div
+}
+
+define i32 @udiv_constant_quotient_known_smaller_than_denom(i32 %x) {
+; CHECK-LABEL: @udiv_constant_quotient_known_smaller_than_denom(
+; CHECK-NEXT:    ret i32 0
+;
+  %or = or i32 %x, 251
+  %div = udiv i32 250, %or
+  ret i32 %div
+}
+
+define i32 @not_udiv_constant_quotient_known_smaller_than_denom(i32 %x) {
+; CHECK-LABEL: @not_udiv_constant_quotient_known_smaller_than_denom(
+; CHECK-NEXT:    [[OR:%.*]] = or i32 %x, 251
+; CHECK-NEXT:    [[DIV:%.*]] = udiv i32 251, [[OR]]
+; CHECK-NEXT:    ret i32 [[DIV]]
+;
+  %or = or i32 %x, 251
+  %div = udiv i32 251, %or
+  ret i32 %div
+}
+
+; This would require computing known bits on both x and y. Is it worth doing?
+
+define i32 @udiv_quotient_known_smaller_than_denom(i32 %x, i32 %y) {
+; CHECK-LABEL: @udiv_quotient_known_smaller_than_denom(
+; CHECK-NEXT:    [[AND:%.*]] = and i32 %x, 250
+; CHECK-NEXT:    [[OR:%.*]] = or i32 %y, 251
+; CHECK-NEXT:    [[DIV:%.*]] = udiv i32 [[AND]], [[OR]]
+; CHECK-NEXT:    ret i32 [[DIV]]
+;
+  %and = and i32 %x, 250
+  %or = or i32 %y, 251
+  %div = udiv i32 %and, %or
+  ret i32 %div
+}
+
+define i32 @not_udiv_quotient_known_smaller_than_denom(i32 %x, i32 %y) {
+; CHECK-LABEL: @not_udiv_quotient_known_smaller_than_denom(
+; CHECK-NEXT:    [[AND:%.*]] = and i32 %x, 251
+; CHECK-NEXT:    [[OR:%.*]] = or i32 %y, 251
+; CHECK-NEXT:    [[DIV:%.*]] = udiv i32 [[AND]], [[OR]]
+; CHECK-NEXT:    ret i32 [[DIV]]
+;
+  %and = and i32 %x, 251
+  %or = or i32 %y, 251
+  %div = udiv i32 %and, %or
+  ret i32 %div
+}
+
 declare i32 @external()
 
 define i32 @div1() {

Modified: llvm/trunk/test/Transforms/InstSimplify/rem.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstSimplify/rem.ll?rev=312885&r1=312884&r2=312885&view=diff
==============================================================================
--- llvm/trunk/test/Transforms/InstSimplify/rem.ll (original)
+++ llvm/trunk/test/Transforms/InstSimplify/rem.ll Sun Sep 10 10:55:08 2017
@@ -104,6 +104,75 @@ define i32 @rem3(i32 %x, i32 %n) {
   ret i32 %mod1
 }
 
+define i32 @urem_quotient_known_smaller_than_constant_denom(i32 %x) {
+; CHECK-LABEL: @urem_quotient_known_smaller_than_constant_denom(
+; CHECK-NEXT:    [[AND:%.*]] = and i32 %x, 250
+; CHECK-NEXT:    ret i32 [[AND]]
+;
+  %and = and i32 %x, 250
+  %r = urem i32 %and, 251
+  ret i32 %r
+}
+
+define i32 @not_urem_quotient_known_smaller_than_constant_denom(i32 %x) {
+; CHECK-LABEL: @not_urem_quotient_known_smaller_than_constant_denom(
+; CHECK-NEXT:    [[AND:%.*]] = and i32 %x, 251
+; CHECK-NEXT:    [[R:%.*]] = urem i32 [[AND]], 251
+; CHECK-NEXT:    ret i32 [[R]]
+;
+  %and = and i32 %x, 251
+  %r = urem i32 %and, 251
+  ret i32 %r
+}
+
+define i32 @urem_constant_quotient_known_smaller_than_denom(i32 %x) {
+; CHECK-LABEL: @urem_constant_quotient_known_smaller_than_denom(
+; CHECK-NEXT:    ret i32 250
+;
+  %or = or i32 %x, 251
+  %r = urem i32 250, %or
+  ret i32 %r
+}
+
+define i32 @not_urem_constant_quotient_known_smaller_than_denom(i32 %x) {
+; CHECK-LABEL: @not_urem_constant_quotient_known_smaller_than_denom(
+; CHECK-NEXT:    [[OR:%.*]] = or i32 %x, 251
+; CHECK-NEXT:    [[R:%.*]] = urem i32 251, [[OR]]
+; CHECK-NEXT:    ret i32 [[R]]
+;
+  %or = or i32 %x, 251
+  %r = urem i32 251, %or
+  ret i32 %r
+}
+
+; This would require computing known bits on both x and y. Is it worth doing?
+
+define i32 @urem_quotient_known_smaller_than_denom(i32 %x, i32 %y) {
+; CHECK-LABEL: @urem_quotient_known_smaller_than_denom(
+; CHECK-NEXT:    [[AND:%.*]] = and i32 %x, 250
+; CHECK-NEXT:    [[OR:%.*]] = or i32 %y, 251
+; CHECK-NEXT:    [[R:%.*]] = urem i32 [[AND]], [[OR]]
+; CHECK-NEXT:    ret i32 [[R]]
+;
+  %and = and i32 %x, 250
+  %or = or i32 %y, 251
+  %r = urem i32 %and, %or
+  ret i32 %r
+}
+
+define i32 @not_urem_quotient_known_smaller_than_denom(i32 %x, i32 %y) {
+; CHECK-LABEL: @not_urem_quotient_known_smaller_than_denom(
+; CHECK-NEXT:    [[AND:%.*]] = and i32 %x, 251
+; CHECK-NEXT:    [[OR:%.*]] = or i32 %y, 251
+; CHECK-NEXT:    [[R:%.*]] = urem i32 [[AND]], [[OR]]
+; CHECK-NEXT:    ret i32 [[R]]
+;
+  %and = and i32 %x, 251
+  %or = or i32 %y, 251
+  %r = urem i32 %and, %or
+  ret i32 %r
+}
+
 declare i32 @external()
 
 define i32 @rem4() {




More information about the llvm-commits mailing list