[PATCH] D74141: [InstCombine] Simplify a umul overflow check to a != 0 && b != 0.

Florian Hahn via Phabricator via llvm-commits llvm-commits at lists.llvm.org
Thu Feb 6 09:55:40 PST 2020


fhahn created this revision.
fhahn added reviewers: nikic, RKSimon, lebedev.ri, spatel.
Herald added a subscriber: hiraditya.
Herald added a project: LLVM.

This patch adds a simplification if an OR weakens the overflow condition
for umul.with.overflow by treating any non-zero result as overflow. In that
case, we overflow if both umul.with.overflow operands are != 0, as in that
case the result can only be 0, iff the multiplication overflows.

Code like this is generated by code using __builtin_mul_overflow with
negative integer constants, e.g.

  bool test(unsigned long long v, unsigned long long *res) {
    return __builtin_mul_overflow(v, -4775807LL, res);
  }

This simplification is very specific and I am not sure if visitOr is the
best place for it. Any other suggestions?


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D74141

Files:
  llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
  llvm/test/Transforms/InstCombine/umul-signed.ll


Index: llvm/test/Transforms/InstCombine/umul-signed.ll
===================================================================
--- llvm/test/Transforms/InstCombine/umul-signed.ll
+++ llvm/test/Transforms/InstCombine/umul-signed.ll
@@ -14,13 +14,10 @@
 
 define i1 @test1(i64 %a, i64* %ptr) {
 ; CHECK-LABEL: @test1(
-; CHECK-NEXT:    [[RES:%.*]] = tail call { i64, i1 } @llvm.umul.with.overflow.i64(i64 [[A:%.*]], i64 -4775807)
-; CHECK-NEXT:    [[OVERFLOW:%.*]] = extractvalue { i64, i1 } [[RES]], 1
-; CHECK-NEXT:    [[MUL:%.*]] = extractvalue { i64, i1 } [[RES]], 0
-; CHECK-NEXT:    [[CMP:%.*]] = icmp ne i64 [[MUL]], 0
-; CHECK-NEXT:    [[OVERFLOW_1:%.*]] = or i1 [[OVERFLOW]], [[CMP]]
+; CHECK-NEXT:    [[MUL:%.*]] = mul i64 [[A:%.*]], -4775807
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp ne i64 [[A]], 0
 ; CHECK-NEXT:    store i64 [[MUL]], i64* [[PTR:%.*]], align 8
-; CHECK-NEXT:    ret i1 [[OVERFLOW_1]]
+; CHECK-NEXT:    ret i1 [[TMP1]]
 ;
   %res = tail call { i64, i1 } @llvm.umul.with.overflow.i64(i64 %a, i64 -4775807)
   %overflow = extractvalue { i64, i1 } %res, 1
@@ -33,13 +30,10 @@
 
 define i1 @test1_or_ops_swapped(i64 %a, i64* %ptr) {
 ; CHECK-LABEL: @test1_or_ops_swapped(
-; CHECK-NEXT:    [[RES:%.*]] = tail call { i64, i1 } @llvm.umul.with.overflow.i64(i64 [[A:%.*]], i64 -4775807)
-; CHECK-NEXT:    [[OVERFLOW:%.*]] = extractvalue { i64, i1 } [[RES]], 1
-; CHECK-NEXT:    [[MUL:%.*]] = extractvalue { i64, i1 } [[RES]], 0
-; CHECK-NEXT:    [[CMP:%.*]] = icmp ne i64 [[MUL]], 0
-; CHECK-NEXT:    [[OVERFLOW_1:%.*]] = or i1 [[CMP]], [[OVERFLOW]]
+; CHECK-NEXT:    [[MUL:%.*]] = mul i64 [[A:%.*]], -4775807
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp ne i64 [[A]], 0
 ; CHECK-NEXT:    store i64 [[MUL]], i64* [[PTR:%.*]], align 8
-; CHECK-NEXT:    ret i1 [[OVERFLOW_1]]
+; CHECK-NEXT:    ret i1 [[TMP1]]
 ;
   %res = tail call { i64, i1 } @llvm.umul.with.overflow.i64(i64 %a, i64 -4775807)
   %overflow = extractvalue { i64, i1 } %res, 1
@@ -53,14 +47,10 @@
 
 define i1 @test2(i64 %a, i64* %ptr) {
 ; CHECK-LABEL: @test2(
-; CHECK-NEXT:    [[RES:%.*]] = tail call { i64, i1 } @llvm.umul.with.overflow.i64(i64 [[A:%.*]], i64 10000)
-; CHECK-NEXT:    [[OVERFLOW:%.*]] = extractvalue { i64, i1 } [[RES]], 1
-; CHECK-NEXT:    [[MUL:%.*]] = extractvalue { i64, i1 } [[RES]], 0
-; CHECK-NEXT:    [[CMP:%.*]] = icmp ne i64 [[MUL]], 0
-; CHECK-NEXT:    [[OVERFLOW_1:%.*]] = or i1 [[OVERFLOW]], [[CMP]]
-; CHECK-NEXT:    [[NEG:%.*]] = sub i64 0, [[MUL]]
-; CHECK-NEXT:    store i64 [[NEG]], i64* [[PTR:%.*]], align 8
-; CHECK-NEXT:    ret i1 [[OVERFLOW_1]]
+; CHECK-NEXT:    [[TMP1:%.*]] = icmp ne i64 [[A:%.*]], 0
+; CHECK-NEXT:    [[MUL_NEG:%.*]] = mul i64 [[A]], -10000
+; CHECK-NEXT:    store i64 [[MUL_NEG]], i64* [[PTR:%.*]], align 8
+; CHECK-NEXT:    ret i1 [[TMP1]]
 ;
   %res = tail call { i64, i1 } @llvm.umul.with.overflow.i64(i64 %a, i64 10000)
   %overflow = extractvalue { i64, i1 } %res, 1
Index: llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
===================================================================
--- llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
+++ llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
@@ -2723,6 +2723,25 @@
           canonicalizeCondSignextOfHighBitExtractToSignextHighBitExtract(I))
     return V;
 
+  CmpInst::Predicate Pred;
+  Value *UMul1, *UMul2;
+  // Check if the OR weakens the overflow condition for umul.with.overflow by
+  // treating any non-zero result as overflow. In that case, we overflow if both
+  // umul.with.overflow operands are != 0, as in that case the result can only
+  // be 0, iff the multiplication overflows.
+  auto P = m_ICmp(Pred, m_ExtractValue<0>(m_Value(UMul2)), m_SpecificInt(0));
+  if (match(&I, m_Or(m_OneUse(m_ExtractValue<1>(m_Value(UMul1))), P)) ||
+      match(&I, m_Or(P, m_OneUse(m_ExtractValue<1>(m_Value(UMul1)))))) {
+    Value *A, *B;
+    if (Pred == CmpInst::ICMP_NE && UMul1 == UMul2 &&
+        match(UMul1, m_Intrinsic<Intrinsic::umul_with_overflow>(m_Value(A),
+                                                                m_Value(B))))
+
+      return BinaryOperator::CreateAnd(
+          Builder.CreateICmpNE(A, ConstantInt::get(A->getType(), 0)),
+          Builder.CreateICmpNE(A, ConstantInt::get(B->getType(), 0)));
+  }
+
   return nullptr;
 }
 


-------------- next part --------------
A non-text attachment was scrubbed...
Name: D74141.242932.patch
Type: text/x-patch
Size: 4289 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/llvm-commits/attachments/20200206/63cbc953/attachment.bin>


More information about the llvm-commits mailing list