[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