[llvm-commits] [llvm] r53534 - in /llvm/trunk: lib/Transforms/Scalar/InstructionCombining.cpp test/Transforms/InstCombine/2008-07-13-DivZero.ll test/Transforms/InstCombine/udiv_select_to_select_shift.ll

Chris Lattner sabre at nondot.org
Sun Jul 13 17:15:53 PDT 2008


Author: lattner
Date: Sun Jul 13 19:15:52 2008
New Revision: 53534

URL: http://llvm.org/viewvc/llvm-project?rev=53534&view=rev
Log:
Fix PR2506 by being a bit more careful about reverse fact propagation when
disproving a condition.  This actually compiles the existing testcase
(udiv_select_to_select_shift) to:

define i64 @test(i64 %X, i1 %Cond) {
entry:
	%divisor1.t = lshr i64 %X, 3		; <i64> [#uses=1]
	%quotient2 = lshr i64 %X, 3		; <i64> [#uses=1]
	%sum = add i64 %divisor1.t, %quotient2		; <i64> [#uses=1]
	ret i64 %sum
}

instead of:

define i64 @test(i64 %X, i1 %Cond) {
entry:
	%quotient1.v = select i1 %Cond, i64 3, i64 4		; <i64> [#uses=1]
	%quotient1 = lshr i64 %X, %quotient1.v		; <i64> [#uses=1]
	%quotient2 = lshr i64 %X, 3		; <i64> [#uses=1]
	%sum = add i64 %quotient1, %quotient2		; <i64> [#uses=1]
	ret i64 %sum
}


Added:
    llvm/trunk/test/Transforms/InstCombine/2008-07-13-DivZero.ll
Modified:
    llvm/trunk/lib/Transforms/Scalar/InstructionCombining.cpp
    llvm/trunk/test/Transforms/InstCombine/udiv_select_to_select_shift.ll

Modified: llvm/trunk/lib/Transforms/Scalar/InstructionCombining.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/Scalar/InstructionCombining.cpp?rev=53534&r1=53533&r2=53534&view=diff

==============================================================================
--- llvm/trunk/lib/Transforms/Scalar/InstructionCombining.cpp (original)
+++ llvm/trunk/lib/Transforms/Scalar/InstructionCombining.cpp Sun Jul 13 19:15:52 2008
@@ -172,6 +172,7 @@
     Instruction *visitURem(BinaryOperator &I);
     Instruction *visitSRem(BinaryOperator &I);
     Instruction *visitFRem(BinaryOperator &I);
+    bool SimplifyDivRemOfSelect(BinaryOperator &I);
     Instruction *commonRemTransforms(BinaryOperator &I);
     Instruction *commonIRemTransforms(BinaryOperator &I);
     Instruction *commonDivTransforms(BinaryOperator &I);
@@ -2566,6 +2567,78 @@
   return Changed ? &I : 0;
 }
 
+/// SimplifyDivRemOfSelect - Try to fold a divide or remainder of a select
+/// instruction.
+bool InstCombiner::SimplifyDivRemOfSelect(BinaryOperator &I) {
+  SelectInst *SI = cast<SelectInst>(I.getOperand(1));
+  
+  // div/rem X, (Cond ? 0 : Y) -> div/rem X, Y
+  int NonNullOperand = -1;
+  if (Constant *ST = dyn_cast<Constant>(SI->getOperand(1)))
+    if (ST->isNullValue())
+      NonNullOperand = 2;
+  // div/rem X, (Cond ? Y : 0) -> div/rem X, Y
+  if (Constant *ST = dyn_cast<Constant>(SI->getOperand(2)))
+    if (ST->isNullValue())
+      NonNullOperand = 1;
+  
+  if (NonNullOperand == -1)
+    return false;
+  
+  Value *SelectCond = SI->getOperand(0);
+  
+  // Change the div/rem to use 'Y' instead of the select.
+  I.setOperand(1, SI->getOperand(NonNullOperand));
+  
+  // Okay, we know we replace the operand of the div/rem with 'Y' with no
+  // problem.  However, the select, or the condition of the select may have
+  // multiple uses.  Based on our knowledge that the operand must be non-zero,
+  // propagate the known value for the select into other uses of it, and
+  // propagate a known value of the condition into its other users.
+  
+  // If the select and condition only have a single use, don't bother with this,
+  // early exit.
+  if (SI->use_empty() && SelectCond->hasOneUse())
+    return true;
+  
+  // Scan the current block backward, looking for other uses of SI.
+  BasicBlock::iterator BBI = &I, BBFront = I.getParent()->begin();
+  
+  while (BBI != BBFront) {
+    --BBI;
+    // If we found a call to a function, we can't assume it will return, so
+    // information from below it cannot be propagated above it.
+    if (isa<CallInst>(BBI) && !isa<IntrinsicInst>(BBI))
+      break;
+    
+    // Replace uses of the select or its condition with the known values.
+    for (Instruction::op_iterator I = BBI->op_begin(), E = BBI->op_end();
+         I != E; ++I) {
+      if (*I == SI) {
+        *I = SI->getOperand(NonNullOperand);
+        AddToWorkList(BBI);
+      } else if (*I == SelectCond) {
+        *I = NonNullOperand == 1 ? ConstantInt::getTrue() :
+                                   ConstantInt::getFalse();
+        AddToWorkList(BBI);
+      }
+    }
+    
+    // If we past the instruction, quit looking for it.
+    if (&*BBI == SI)
+      SI = 0;
+    if (&*BBI == SelectCond)
+      SelectCond = 0;
+    
+    // If we ran out of things to eliminate, break out of the loop.
+    if (SelectCond == 0 && SI == 0)
+      break;
+    
+  }
+  return true;
+}
+
+
 /// This function implements the transforms on div instructions that work
 /// regardless of the kind of div instruction it is (udiv, sdiv, or fdiv). It is
 /// used by the visitors to those instructions.
@@ -2585,40 +2658,6 @@
   if (isa<UndefValue>(Op1))
     return ReplaceInstUsesWith(I, Op1);
 
-  // Handle cases involving: [su]div X, (select Cond, Y, Z)
-  // This does not apply for fdiv.
-  if (SelectInst *SI = dyn_cast<SelectInst>(Op1)) {
-    // [su]div X, (Cond ? 0 : Y) -> div X, Y.  If the div and the select are in
-    // the same basic block, then we replace the select with Y, and the
-    // condition of the select with false (if the cond value is in the same BB).
-    // If the select has uses other than the div, this allows them to be
-    // simplified also. Note that div X, Y is just as good as div X, 0 (undef)
-    if (ConstantInt *ST = dyn_cast<ConstantInt>(SI->getOperand(1)))
-      if (ST->isNullValue()) {
-        Instruction *CondI = dyn_cast<Instruction>(SI->getOperand(0));
-        if (CondI && CondI->getParent() == I.getParent())
-          UpdateValueUsesWith(CondI, ConstantInt::getFalse());
-        else if (I.getParent() != SI->getParent() || SI->hasOneUse())
-          I.setOperand(1, SI->getOperand(2));
-        else
-          UpdateValueUsesWith(SI, SI->getOperand(2));
-        return &I;
-      }
-
-    // Likewise for: [su]div X, (Cond ? Y : 0) -> div X, Y
-    if (ConstantInt *ST = dyn_cast<ConstantInt>(SI->getOperand(2)))
-      if (ST->isNullValue()) {
-        Instruction *CondI = dyn_cast<Instruction>(SI->getOperand(0));
-        if (CondI && CondI->getParent() == I.getParent())
-          UpdateValueUsesWith(CondI, ConstantInt::getTrue());
-        else if (I.getParent() != SI->getParent() || SI->hasOneUse())
-          I.setOperand(1, SI->getOperand(1));
-        else
-          UpdateValueUsesWith(SI, SI->getOperand(1));
-        return &I;
-      }
-  }
-
   return 0;
 }
 
@@ -2643,6 +2682,11 @@
   
   if (Instruction *Common = commonDivTransforms(I))
     return Common;
+  
+  // Handle cases involving: [su]div X, (select Cond, Y, Z)
+  // This does not apply for fdiv.
+  if (isa<SelectInst>(Op1) && SimplifyDivRemOfSelect(I))
+    return &I;
 
   if (ConstantInt *RHS = dyn_cast<ConstantInt>(Op1)) {
     // div X, 1 == X
@@ -2798,36 +2842,8 @@
     return ReplaceInstUsesWith(I, Op1);  // X % undef -> undef
 
   // Handle cases involving: rem X, (select Cond, Y, Z)
-  if (SelectInst *SI = dyn_cast<SelectInst>(Op1)) {
-    // rem X, (Cond ? 0 : Y) -> rem X, Y.  If the rem and the select are in
-    // the same basic block, then we replace the select with Y, and the
-    // condition of the select with false (if the cond value is in the same
-    // BB).  If the select has uses other than the div, this allows them to be
-    // simplified also.
-    if (Constant *ST = dyn_cast<Constant>(SI->getOperand(1)))
-      if (ST->isNullValue()) {
-        Instruction *CondI = dyn_cast<Instruction>(SI->getOperand(0));
-        if (CondI && CondI->getParent() == I.getParent())
-          UpdateValueUsesWith(CondI, ConstantInt::getFalse());
-        else if (I.getParent() != SI->getParent() || SI->hasOneUse())
-          I.setOperand(1, SI->getOperand(2));
-        else
-          UpdateValueUsesWith(SI, SI->getOperand(2));
-        return &I;
-      }
-    // Likewise for: rem X, (Cond ? Y : 0) -> rem X, Y
-    if (Constant *ST = dyn_cast<Constant>(SI->getOperand(2)))
-      if (ST->isNullValue()) {
-        Instruction *CondI = dyn_cast<Instruction>(SI->getOperand(0));
-        if (CondI && CondI->getParent() == I.getParent())
-          UpdateValueUsesWith(CondI, ConstantInt::getTrue());
-        else if (I.getParent() != SI->getParent() || SI->hasOneUse())
-          I.setOperand(1, SI->getOperand(1));
-        else
-          UpdateValueUsesWith(SI, SI->getOperand(1));
-        return &I;
-      }
-  }
+  if (isa<SelectInst>(Op1) && SimplifyDivRemOfSelect(I))
+    return &I;
 
   return 0;
 }

Added: llvm/trunk/test/Transforms/InstCombine/2008-07-13-DivZero.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/2008-07-13-DivZero.ll?rev=53534&view=auto

==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/2008-07-13-DivZero.ll (added)
+++ llvm/trunk/test/Transforms/InstCombine/2008-07-13-DivZero.ll Sun Jul 13 19:15:52 2008
@@ -0,0 +1,16 @@
+; RUN: llvm-as < %s | opt -instcombine | llvm-dis | grep {lshr.*3}
+; RUN: llvm-as < %s | opt -instcombine | llvm-dis | grep {call .*%cond}
+; PR2506
+
+; We can simplify the operand of udiv to '8', but not the operand to the
+; call.  If the callee never returns, we can't assume the div is reachable.
+define i32 @a(i32 %x, i32 %y) {
+entry:
+        %tobool = icmp ne i32 %y, 0             ; <i1> [#uses=1]
+        %cond = select i1 %tobool, i32 8, i32 0         ; <i32> [#uses=2]
+        %call = call i32 @b( i32 %cond )                ; <i32> [#uses=0]
+        %div = udiv i32 %x, %cond               ; <i32> [#uses=1]
+        ret i32 %div
+}
+
+declare i32 @b(i32)

Modified: llvm/trunk/test/Transforms/InstCombine/udiv_select_to_select_shift.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/udiv_select_to_select_shift.ll?rev=53534&r1=53533&r2=53534&view=diff

==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/udiv_select_to_select_shift.ll (original)
+++ llvm/trunk/test/Transforms/InstCombine/udiv_select_to_select_shift.ll Sun Jul 13 19:15:52 2008
@@ -2,13 +2,13 @@
 ; udiv X, (Select Cond, C1, C2) --> Select Cond, (shr X, C1), (shr X, C2)
 ;
 ; RUN: llvm-as < %s | opt -instcombine | llvm-dis -f -o %t
-; RUN:   grep select %t | count 1
+; RUN:   not grep select %t
 ; RUN:   grep lshr %t | count 2
-; RUN:   ignore grep udiv %t | count 0
+; RUN:   not grep udiv %t
 
 define i64 @test(i64 %X, i1 %Cond ) {
 entry:
-        %divisor1 = select i1 %Cond, i64 8, i64 16
+        %divisor1 = select i1 %Cond, i64 16, i64 8
         %quotient1 = udiv i64 %X, %divisor1
         %divisor2 = select i1 %Cond, i64 8, i64 0
         %quotient2 = udiv i64 %X, %divisor2





More information about the llvm-commits mailing list