Fix a mistake in the computation of leading zeros for udiv.
authorDan Gohman <gohman@apple.com>
Fri, 2 May 2008 21:30:02 +0000 (21:30 +0000)
committerDan Gohman <gohman@apple.com>
Fri, 2 May 2008 21:30:02 +0000 (21:30 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@50591 91177308-0d34-0410-b5e6-96231b3b80d8

lib/CodeGen/SelectionDAG/SelectionDAG.cpp
lib/Transforms/Scalar/InstructionCombining.cpp
test/Transforms/InstCombine/udiv-simplify-bug-0.ll [new file with mode: 0644]
test/Transforms/InstCombine/udiv-simplify-bug-1.ll [new file with mode: 0644]

index 18bb04000801a62f19038c57f97ad4721ac37017..6b2f54393d4b5714c1e285cc7b3bac14f2302df5 100644 (file)
@@ -1257,7 +1257,7 @@ void SelectionDAG::ComputeMaskedBits(SDOperand Op, const APInt &Mask,
   case ISD::UDIV: {
     // For the purposes of computing leading zeros we can conservatively
     // treat a udiv as a logical right shift by the power of 2 known to
-    // be greater than the denominator.
+    // be less than the denominator.
     APInt AllOnes = APInt::getAllOnesValue(BitWidth);
     ComputeMaskedBits(Op.getOperand(0),
                       AllOnes, KnownZero2, KnownOne2, Depth+1);
@@ -1267,8 +1267,10 @@ void SelectionDAG::ComputeMaskedBits(SDOperand Op, const APInt &Mask,
     KnownZero2.clear();
     ComputeMaskedBits(Op.getOperand(1),
                       AllOnes, KnownZero2, KnownOne2, Depth+1);
-    LeadZ = std::min(BitWidth,
-                     LeadZ + BitWidth - KnownOne2.countLeadingZeros());
+    unsigned RHSUnknownLeadingOnes = KnownOne2.countLeadingZeros();
+    if (RHSUnknownLeadingOnes != BitWidth)
+      LeadZ = std::min(BitWidth,
+                       LeadZ + BitWidth - RHSUnknownLeadingOnes - 1);
 
     KnownZero = APInt::getHighBitsSet(BitWidth, LeadZ) & Mask;
     return;
index ce052f724e84b98996219c610f322d8bab60e068..d7a5f7be5c5a5964c53544db8839cd3d1e045d4c 100644 (file)
@@ -780,7 +780,7 @@ void InstCombiner::ComputeMaskedBits(Value *V, const APInt &Mask,
   case Instruction::UDiv: {
     // For the purposes of computing leading zeros we can conservatively
     // treat a udiv as a logical right shift by the power of 2 known to
-    // be greater than the denominator.
+    // be less than the denominator.
     APInt AllOnes = APInt::getAllOnesValue(BitWidth);
     ComputeMaskedBits(I->getOperand(0),
                       AllOnes, KnownZero2, KnownOne2, Depth+1);
@@ -790,8 +790,10 @@ void InstCombiner::ComputeMaskedBits(Value *V, const APInt &Mask,
     KnownZero2.clear();
     ComputeMaskedBits(I->getOperand(1),
                       AllOnes, KnownZero2, KnownOne2, Depth+1);
-    LeadZ = std::min(BitWidth,
-                     LeadZ + BitWidth - KnownOne2.countLeadingZeros());
+    unsigned RHSUnknownLeadingOnes = KnownOne2.countLeadingZeros();
+    if (RHSUnknownLeadingOnes != BitWidth)
+      LeadZ = std::min(BitWidth,
+                       LeadZ + BitWidth - RHSUnknownLeadingOnes - 1);
 
     KnownZero = APInt::getHighBitsSet(BitWidth, LeadZ) & Mask;
     return;
diff --git a/test/Transforms/InstCombine/udiv-simplify-bug-0.ll b/test/Transforms/InstCombine/udiv-simplify-bug-0.ll
new file mode 100644 (file)
index 0000000..5bcaa66
--- /dev/null
@@ -0,0 +1,14 @@
+; RUN: llvm-as < %s | opt -instcombine | llvm-dis | grep {ret i64 0} | count 2
+
+define i64 @foo(i32 %x) nounwind {
+  %y = lshr i32 %x, 1
+  %r = udiv i32 %y, -1
+  %z = sext i32 %r to i64
+  ret i64 %z
+}
+define i64 @bar(i32 %x) nounwind {
+  %y = lshr i32 %x, 31
+  %r = udiv i32 %y, 3
+  %z = sext i32 %r to i64
+  ret i64 %z
+}
diff --git a/test/Transforms/InstCombine/udiv-simplify-bug-1.ll b/test/Transforms/InstCombine/udiv-simplify-bug-1.ll
new file mode 100644 (file)
index 0000000..6e76bcf
--- /dev/null
@@ -0,0 +1,25 @@
+; RUN: llvm-as < %s | opt -instcombine | llvm-dis > %t1.ll
+; RUN: grep udiv %t1.ll | count 3
+; RUN: grep zext %t1.ll | count 3
+; PR2274
+
+; The udiv instructions shouldn't be optimized away, and the
+; sext instructions should be optimized to zext.
+
+define i64 @foo(i32 %x) nounwind {
+  %r = udiv i32 %x, -1
+  %z = sext i32 %r to i64
+  ret i64 %z
+}
+define i64 @bar(i32 %x) nounwind {
+  %y = lshr i32 %x, 30
+  %r = udiv i32 %y, 3
+  %z = sext i32 %r to i64
+  ret i64 %z
+}
+define i64 @qux(i32 %x, i32 %v) nounwind {
+  %y = lshr i32 %x, 31
+  %r = udiv i32 %y, %v
+  %z = sext i32 %r to i64
+  ret i64 %z
+}