[llvm] r217750 - InstSimplify: Simplify trivial and/or of icmps

David Majnemer david.majnemer at gmail.com
Mon Sep 15 01:15:28 PDT 2014


Author: majnemer
Date: Mon Sep 15 03:15:28 2014
New Revision: 217750

URL: http://llvm.org/viewvc/llvm-project?rev=217750&view=rev
Log:
InstSimplify: Simplify trivial and/or of icmps

Some ICmpInsts when anded/ored with another ICmpInst trivially reduces
to true or false depending on whether or not all integers or no integers
satisfy the intersected/unioned range.

This sort of trivial looking code can come about when InstCombine
performs a range reduction-type operation on sdiv and the like.

This fixes PR20916.

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

Modified: llvm/trunk/lib/Analysis/InstructionSimplify.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Analysis/InstructionSimplify.cpp?rev=217750&r1=217749&r2=217750&view=diff
==============================================================================
--- llvm/trunk/lib/Analysis/InstructionSimplify.cpp (original)
+++ llvm/trunk/lib/Analysis/InstructionSimplify.cpp Mon Sep 15 03:15:28 2014
@@ -1414,6 +1414,54 @@ Value *llvm::SimplifyAShrInst(Value *Op0
                             RecursionLimit);
 }
 
+// Simplify (and (icmp ...) (icmp ...)) to true when we can tell that the range
+// of possible values cannot be satisfied.
+static Value *SimplifyAndOfICmps(ICmpInst *Op0, ICmpInst *Op1) {
+  ICmpInst::Predicate Pred0, Pred1;
+  ConstantInt *CI1, *CI2;
+  Value *V;
+  if (!match(Op0, m_ICmp(Pred0, m_Add(m_Value(V), m_ConstantInt(CI1)),
+                         m_ConstantInt(CI2))))
+   return nullptr;
+
+  if (!match(Op1, m_ICmp(Pred1, m_Specific(V), m_Specific(CI1))))
+    return nullptr;
+
+  Type *ITy = Op0->getType();
+
+  auto *AddInst = cast<BinaryOperator>(Op0->getOperand(0));
+  bool isNSW = AddInst->hasNoSignedWrap();
+  bool isNUW = AddInst->hasNoUnsignedWrap();
+
+  const APInt &CI1V = CI1->getValue();
+  const APInt &CI2V = CI2->getValue();
+  const APInt Delta = CI2V - CI1V;
+  if (CI1V.isStrictlyPositive()) {
+    if (Delta == 2) {
+      if (Pred0 == ICmpInst::ICMP_ULT && Pred1 == ICmpInst::ICMP_SGT)
+        return getFalse(ITy);
+      if (Pred0 == ICmpInst::ICMP_SLT && Pred1 == ICmpInst::ICMP_SGT && isNSW)
+        return getFalse(ITy);
+    }
+    if (Delta == 1) {
+      if (Pred0 == ICmpInst::ICMP_ULE && Pred1 == ICmpInst::ICMP_SGT)
+        return getFalse(ITy);
+      if (Pred0 == ICmpInst::ICMP_SLE && Pred1 == ICmpInst::ICMP_SGT && isNSW)
+        return getFalse(ITy);
+    }
+  }
+  if (CI1V.getBoolValue() && isNUW) {
+    if (Delta == 2)
+      if (Pred0 == ICmpInst::ICMP_ULT && Pred1 == ICmpInst::ICMP_UGT)
+        return getFalse(ITy);
+    if (Delta == 1)
+      if (Pred0 == ICmpInst::ICMP_ULE && Pred1 == ICmpInst::ICMP_UGT)
+        return getFalse(ITy);
+  }
+
+  return nullptr;
+}
+
 /// SimplifyAndInst - Given operands for an And, see if we can
 /// fold the result.  If not, this returns null.
 static Value *SimplifyAndInst(Value *Op0, Value *Op1, const Query &Q,
@@ -1470,6 +1518,15 @@ static Value *SimplifyAndInst(Value *Op0
       return Op1;
   }
 
+  if (auto *ICILHS = dyn_cast<ICmpInst>(Op0)) {
+    if (auto *ICIRHS = dyn_cast<ICmpInst>(Op1)) {
+      if (Value *V = SimplifyAndOfICmps(ICILHS, ICIRHS))
+        return V;
+      if (Value *V = SimplifyAndOfICmps(ICIRHS, ICILHS))
+        return V;
+    }
+  }
+
   // Try some generic simplifications for associative operations.
   if (Value *V = SimplifyAssociativeBinOp(Instruction::And, Op0, Op1, Q,
                                           MaxRecurse))
@@ -1510,6 +1567,54 @@ Value *llvm::SimplifyAndInst(Value *Op0,
                            RecursionLimit);
 }
 
+// Simplify (or (icmp ...) (icmp ...)) to true when we can tell that the union
+// contains all possible values.
+static Value *SimplifyOrOfICmps(ICmpInst *Op0, ICmpInst *Op1) {
+  ICmpInst::Predicate Pred0, Pred1;
+  ConstantInt *CI1, *CI2;
+  Value *V;
+  if (!match(Op0, m_ICmp(Pred0, m_Add(m_Value(V), m_ConstantInt(CI1)),
+                         m_ConstantInt(CI2))))
+   return nullptr;
+
+  if (!match(Op1, m_ICmp(Pred1, m_Specific(V), m_Specific(CI1))))
+    return nullptr;
+
+  Type *ITy = Op0->getType();
+
+  auto *AddInst = cast<BinaryOperator>(Op0->getOperand(0));
+  bool isNSW = AddInst->hasNoSignedWrap();
+  bool isNUW = AddInst->hasNoUnsignedWrap();
+
+  const APInt &CI1V = CI1->getValue();
+  const APInt &CI2V = CI2->getValue();
+  const APInt Delta = CI2V - CI1V;
+  if (CI1V.isStrictlyPositive()) {
+    if (Delta == 2) {
+      if (Pred0 == ICmpInst::ICMP_UGE && Pred1 == ICmpInst::ICMP_SLE)
+        return getTrue(ITy);
+      if (Pred0 == ICmpInst::ICMP_SGE && Pred1 == ICmpInst::ICMP_SLE && isNSW)
+        return getTrue(ITy);
+    }
+    if (Delta == 1) {
+      if (Pred0 == ICmpInst::ICMP_UGT && Pred1 == ICmpInst::ICMP_SLE)
+        return getTrue(ITy);
+      if (Pred0 == ICmpInst::ICMP_SGT && Pred1 == ICmpInst::ICMP_SLE && isNSW)
+        return getTrue(ITy);
+    }
+  }
+  if (CI1V.getBoolValue() && isNUW) {
+    if (Delta == 2)
+      if (Pred0 == ICmpInst::ICMP_UGE && Pred1 == ICmpInst::ICMP_ULE)
+        return getTrue(ITy);
+    if (Delta == 1)
+      if (Pred0 == ICmpInst::ICMP_UGT && Pred1 == ICmpInst::ICMP_ULE)
+        return getTrue(ITy);
+  }
+
+  return nullptr;
+}
+
 /// SimplifyOrInst - Given operands for an Or, see if we can
 /// fold the result.  If not, this returns null.
 static Value *SimplifyOrInst(Value *Op0, Value *Op1, const Query &Q,
@@ -1567,6 +1672,15 @@ static Value *SimplifyOrInst(Value *Op0,
       (A == Op0 || B == Op0))
     return Constant::getAllOnesValue(Op0->getType());
 
+  if (auto *ICILHS = dyn_cast<ICmpInst>(Op0)) {
+    if (auto *ICIRHS = dyn_cast<ICmpInst>(Op1)) {
+      if (Value *V = SimplifyOrOfICmps(ICILHS, ICIRHS))
+        return V;
+      if (Value *V = SimplifyOrOfICmps(ICIRHS, ICILHS))
+        return V;
+    }
+  }
+
   // Try some generic simplifications for associative operations.
   if (Value *V = SimplifyAssociativeBinOp(Instruction::Or, Op0, Op1, Q,
                                           MaxRecurse))

Modified: llvm/trunk/test/Transforms/InstSimplify/AndOrXor.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstSimplify/AndOrXor.ll?rev=217750&r1=217749&r2=217750&view=diff
==============================================================================
--- llvm/trunk/test/Transforms/InstSimplify/AndOrXor.ll (original)
+++ llvm/trunk/test/Transforms/InstSimplify/AndOrXor.ll Mon Sep 15 03:15:28 2014
@@ -28,3 +28,123 @@ define i32 @sub_neg_nuw(i32 %x, i32 %y)
   ret i32 %sub
 ; CHECK: ret i32 %x
 }
+
+define i1 @and_of_icmps0(i32 %b) {
+; CHECK-LABEL: @and_of_icmps0(
+  %1 = add i32 %b, 2
+  %2 = icmp ult i32 %1, 4
+  %cmp3 = icmp sgt i32 %b, 2
+  %cmp = and i1 %2, %cmp3
+  ret i1 %cmp
+; CHECK: ret i1 false
+}
+
+define i1 @and_of_icmps1(i32 %b) {
+; CHECK-LABEL: @and_of_icmps1(
+  %1 = add nsw i32 %b, 2
+  %2 = icmp slt i32 %1, 4
+  %cmp3 = icmp sgt i32 %b, 2
+  %cmp = and i1 %2, %cmp3
+  ret i1 %cmp
+; CHECK: ret i1 false
+}
+
+define i1 @and_of_icmps2(i32 %b) {
+; CHECK-LABEL: @and_of_icmps2(
+  %1 = add i32 %b, 2
+  %2 = icmp ule i32 %1, 3
+  %cmp3 = icmp sgt i32 %b, 2
+  %cmp = and i1 %2, %cmp3
+  ret i1 %cmp
+; CHECK: ret i1 false
+}
+
+define i1 @and_of_icmps3(i32 %b) {
+; CHECK-LABEL: @and_of_icmps3(
+  %1 = add nsw i32 %b, 2
+  %2 = icmp sle i32 %1, 3
+  %cmp3 = icmp sgt i32 %b, 2
+  %cmp = and i1 %2, %cmp3
+  ret i1 %cmp
+; CHECK: ret i1 false
+}
+
+define i1 @and_of_icmps4(i32 %b) {
+; CHECK-LABEL: @and_of_icmps4(
+  %1 = add nuw i32 %b, 2
+  %2 = icmp ult i32 %1, 4
+  %cmp3 = icmp ugt i32 %b, 2
+  %cmp = and i1 %2, %cmp3
+  ret i1 %cmp
+; CHECK: ret i1 false
+}
+
+define i1 @and_of_icmps5(i32 %b) {
+; CHECK-LABEL: @and_of_icmps5(
+  %1 = add nuw i32 %b, 2
+  %2 = icmp ule i32 %1, 3
+  %cmp3 = icmp ugt i32 %b, 2
+  %cmp = and i1 %2, %cmp3
+  ret i1 %cmp
+; CHECK: ret i1 false
+}
+
+define i1 @or_of_icmps0(i32 %b) {
+; CHECK-LABEL: @or_of_icmps0(
+  %1 = add i32 %b, 2
+  %2 = icmp uge i32 %1, 4
+  %cmp3 = icmp sle i32 %b, 2
+  %cmp = or i1 %2, %cmp3
+  ret i1 %cmp
+; CHECK: ret i1 true
+}
+
+define i1 @or_of_icmps1(i32 %b) {
+; CHECK-LABEL: @or_of_icmps1(
+  %1 = add nsw i32 %b, 2
+  %2 = icmp sge i32 %1, 4
+  %cmp3 = icmp sle i32 %b, 2
+  %cmp = or i1 %2, %cmp3
+  ret i1 %cmp
+; CHECK: ret i1 true
+}
+
+define i1 @or_of_icmps2(i32 %b) {
+; CHECK-LABEL: @or_of_icmps2(
+  %1 = add i32 %b, 2
+  %2 = icmp ugt i32 %1, 3
+  %cmp3 = icmp sle i32 %b, 2
+  %cmp = or i1 %2, %cmp3
+  ret i1 %cmp
+; CHECK: ret i1 true
+}
+
+define i1 @or_of_icmps3(i32 %b) {
+; CHECK-LABEL: @or_of_icmps3(
+  %1 = add nsw i32 %b, 2
+  %2 = icmp sgt i32 %1, 3
+  %cmp3 = icmp sle i32 %b, 2
+  %cmp = or i1 %2, %cmp3
+  ret i1 %cmp
+; CHECK: ret i1 true
+}
+
+define i1 @or_of_icmps4(i32 %b) {
+; CHECK-LABEL: @or_of_icmps4(
+  %1 = add nuw i32 %b, 2
+  %2 = icmp uge i32 %1, 4
+  %cmp3 = icmp ule i32 %b, 2
+  %cmp = or i1 %2, %cmp3
+  ret i1 %cmp
+; CHECK: ret i1 true
+}
+
+define i1 @or_of_icmps5(i32 %b) {
+; CHECK-LABEL: @or_of_icmps5(
+  %1 = add nuw i32 %b, 2
+  %2 = icmp ugt i32 %1, 3
+  %cmp3 = icmp ule i32 %b, 2
+  %cmp = or i1 %2, %cmp3
+  ret i1 %cmp
+; CHECK: ret i1 true
+}





More information about the llvm-commits mailing list