[llvm] r224849 - InstCombine: Infer nuw for multiplies

David Majnemer david.majnemer at gmail.com
Fri Dec 26 01:50:35 PST 2014


Author: majnemer
Date: Fri Dec 26 03:50:35 2014
New Revision: 224849

URL: http://llvm.org/viewvc/llvm-project?rev=224849&view=rev
Log:
InstCombine: Infer nuw for multiplies

A multiply cannot unsigned wrap if there are bitwidth, or more, leading
zero bits between the two operands.

Modified:
    llvm/trunk/lib/Transforms/InstCombine/InstCombine.h
    llvm/trunk/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
    llvm/trunk/test/Transforms/InstCombine/intrinsics.ll
    llvm/trunk/test/Transforms/InstCombine/mul.ll

Modified: llvm/trunk/lib/Transforms/InstCombine/InstCombine.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/InstCombine/InstCombine.h?rev=224849&r1=224848&r2=224849&view=diff
==============================================================================
--- llvm/trunk/lib/Transforms/InstCombine/InstCombine.h (original)
+++ llvm/trunk/lib/Transforms/InstCombine/InstCombine.h Fri Dec 26 03:50:35 2014
@@ -286,6 +286,7 @@ private:
   bool WillNotOverflowSignedSub(Value *LHS, Value *RHS, Instruction *CxtI);
   bool WillNotOverflowUnsignedSub(Value *LHS, Value *RHS, Instruction *CxtI);
   bool WillNotOverflowSignedMul(Value *LHS, Value *RHS, Instruction *CxtI);
+  bool WillNotOverflowUnsignedMul(Value *LHS, Value *RHS, Instruction *CxtI);
   Value *EmitGEPOffset(User *GEP);
   Instruction *scalarizePHI(ExtractElementInst &EI, PHINode *PN);
   Value *EvaluateInDifferentElementOrder(Value *V, ArrayRef<int> Mask);

Modified: llvm/trunk/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp?rev=224849&r1=224848&r2=224849&view=diff
==============================================================================
--- llvm/trunk/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp (original)
+++ llvm/trunk/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp Fri Dec 26 03:50:35 2014
@@ -165,6 +165,39 @@ bool InstCombiner::WillNotOverflowSigned
   return false;
 }
 
+/// \brief Return true if we can prove that:
+///    (mul LHS, RHS)  === (mul nuw LHS, RHS)
+bool InstCombiner::WillNotOverflowUnsignedMul(Value *LHS, Value *RHS,
+                                              Instruction *CxtI) {
+  // Multiplying n * m significant bits yields a result of n + m significant
+  // bits. If the total number of significant bits does not exceed the
+  // result bit width (minus 1), there is no overflow.
+  // This means if we have enough leading zero bits in the operands
+  // we can guarantee that the result does not overflow.
+  // Ref: "Hacker's Delight" by Henry Warren
+  unsigned BitWidth = LHS->getType()->getScalarSizeInBits();
+  APInt LHSKnownZero(BitWidth, 0);
+  APInt RHSKnownZero(BitWidth, 0);
+  APInt TmpKnownOne(BitWidth, 0);
+  computeKnownBits(LHS, LHSKnownZero, TmpKnownOne, 0, CxtI);
+  computeKnownBits(RHS, RHSKnownZero, TmpKnownOne, 0, CxtI);
+  // Note that underestimating the number of zero bits gives a more
+  // conservative answer.
+  unsigned ZeroBits = LHSKnownZero.countLeadingOnes() +
+                      RHSKnownZero.countLeadingOnes();
+  // First handle the easy case: if we have enough zero bits there's
+  // definitely no overflow.
+  if (ZeroBits >= BitWidth)
+    return true;
+
+  // There is an ambiguous cases where there can be no overflow:
+  //   ZeroBits == BitWidth - 1
+  // However, determining overflow requires calculating the sign bit of
+  // LHS * RHS/2.
+
+  return false;
+}
+
 Instruction *InstCombiner::visitMul(BinaryOperator &I) {
   bool Changed = SimplifyAssociativeOrCommutative(I);
   Value *Op0 = I.getOperand(0), *Op1 = I.getOperand(1);
@@ -380,6 +413,11 @@ Instruction *InstCombiner::visitMul(Bina
     I.setHasNoSignedWrap(true);
   }
 
+  if (!I.hasNoUnsignedWrap() && WillNotOverflowUnsignedMul(Op0, Op1, &I)) {
+    Changed = true;
+    I.setHasNoUnsignedWrap(true);
+  }
+
   return Changed ? &I : nullptr;
 }
 

Modified: llvm/trunk/test/Transforms/InstCombine/intrinsics.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/intrinsics.ll?rev=224849&r1=224848&r2=224849&view=diff
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/intrinsics.ll (original)
+++ llvm/trunk/test/Transforms/InstCombine/intrinsics.ll Fri Dec 26 03:50:35 2014
@@ -148,7 +148,7 @@ define %ov.result.32 @smultest1_nsw(i32
   %x = call %ov.result.32 @llvm.smul.with.overflow.i32(i32 %A, i32 %B)
   ret %ov.result.32 %x
 ; CHECK-LABEL: @smultest1_nsw
-; CHECK: %x = mul nsw i32 %A, %B
+; CHECK: %x = mul nuw nsw i32 %A, %B
 ; CHECK-NEXT: %1 = insertvalue %ov.result.32 { i32 undef, i1 false }, i32 %x, 0
 ; CHECK-NEXT:  ret %ov.result.32 %1
 }

Modified: llvm/trunk/test/Transforms/InstCombine/mul.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/mul.ll?rev=224849&r1=224848&r2=224849&view=diff
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/mul.ll (original)
+++ llvm/trunk/test/Transforms/InstCombine/mul.ll Fri Dec 26 03:50:35 2014
@@ -258,12 +258,24 @@ define i32 @test28(i32 %A) {
 
 define i64 @test29(i31 %A, i31 %B) {
 ; CHECK-LABEL: @test29(
-        %C = zext i31 %A to i64
-        %D = zext i31 %B to i64
+        %C = sext i31 %A to i64
+        %D = sext i31 %B to i64
         %E = mul i64 %C, %D
         ret i64 %E
-; CHECK:      %[[zext1:.*]] = zext i31 %A to i64
-; CHECK-NEXT: %[[zext2:.*]] = zext i31 %B to i64
-; CHECK-NEXT: %[[mul:.*]] = mul nsw i64 %[[zext1]], %[[zext2]]
+; CHECK:      %[[sext1:.*]] = sext i31 %A to i64
+; CHECK-NEXT: %[[sext2:.*]] = sext i31 %B to i64
+; CHECK-NEXT: %[[mul:.*]] = mul nsw i64 %[[sext1]], %[[sext2]]
+; CHECK-NEXT: ret i64 %[[mul]]
+}
+
+define i64 @test30(i32 %A, i32 %B) {
+; CHECK-LABEL: @test30(
+        %C = zext i32 %A to i64
+        %D = zext i32 %B to i64
+        %E = mul i64 %C, %D
+        ret i64 %E
+; CHECK:      %[[zext1:.*]] = zext i32 %A to i64
+; CHECK-NEXT: %[[zext2:.*]] = zext i32 %B to i64
+; CHECK-NEXT: %[[mul:.*]] = mul nuw i64 %[[zext1]], %[[zext2]]
 ; CHECK-NEXT: ret i64 %[[mul]]
 }





More information about the llvm-commits mailing list