This is an archive of the discontinued LLVM Phabricator instance.

[InstCombine] Fold add nuw + uadd.with.overflow
ClosedPublic

Authored by dlrobertson on Mar 17 2019, 9:08 AM.

Details

Diff Detail

Event Timeline

dlrobertson created this revision.Mar 17 2019, 9:08 AM
Herald added a project: Restricted Project. · View Herald TranscriptMar 17 2019, 9:08 AM

Looks reasonable, test coverage nits added.

llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
2078–2081

Are these tested?

dlrobertson marked an inline comment as done.Mar 17 2019, 10:10 AM
dlrobertson added inline comments.
llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
2078–2081

foldIntrinsicWithOverflowCommon is a very thin wrapper around OptimizeOverflowCheck which is tested in with_overflow.ll. I couldn't find any tests in which canonicalizeConstantArg0ToArg1 would be used. I can add a test for it in with_overflow.ll.

dlrobertson marked an inline comment as done.Mar 17 2019, 12:09 PM

Rebased on master

lebedev.ri accepted this revision.Mar 19 2019, 12:22 AM

Looks reasonable, but maybe wait for @nikic / @spatel.

This revision is now accepted and ready to land.Mar 19 2019, 12:22 AM
spatel accepted this revision.Mar 19 2019, 11:08 AM

Logic looks fine, so I won't hold it up, but seems better to not duplicate code for sibling transforms?

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
index 49524d7f42e..9de4e60c1b9 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
@@ -2046,6 +2046,7 @@ Instruction *InstCombiner::visitCallInst(CallInst &CI) {
       return &CI;
     break;
   }
+  case Intrinsic::uadd_with_overflow:
   case Intrinsic::sadd_with_overflow: {
     if (Instruction *I = canonicalizeConstantArg0ToArg1(CI))
       return I;
@@ -2053,25 +2054,28 @@ Instruction *InstCombiner::visitCallInst(CallInst &CI) {
       return I;
 
     // Given 2 constant operands whose sum does not overflow:
+    // uaddo (X +nuw C0), C1 -> uaddo X, C0 + C1
     // saddo (X +nsw C0), C1 -> saddo X, C0 + C1
+    bool IsUnsigned = II->getIntrinsicID() == Intrinsic::uadd_with_overflow;
     Value *X;
     const APInt *C0, *C1;
     Value *Arg0 = II->getArgOperand(0);
     Value *Arg1 = II->getArgOperand(1);
-    if (match(Arg0, m_NSWAdd(m_Value(X), m_APInt(C0))) &&
-        match(Arg1, m_APInt(C1))) {
+    bool HasAdd = IsUnsigned ? match(Arg0, m_NUWAdd(m_Value(X), m_APInt(C0)))
+                             : match(Arg0, m_NSWAdd(m_Value(X), m_APInt(C0)));
+    if (HasAdd && match(Arg1, m_APInt(C1))) {
       bool Overflow;
-      APInt NewC = C1->sadd_ov(*C0, Overflow);
+      APInt NewC = IsUnsigned ? C1->uadd_ov(*C0, Overflow)
+                              : C1->sadd_ov(*C0, Overflow);
       if (!Overflow)
         return replaceInstUsesWith(
             *II, Builder.CreateBinaryIntrinsic(
-                     Intrinsic::sadd_with_overflow, X,
+                     II->getIntrinsicID(), X,
                      ConstantInt::get(Arg1->getType(), NewC)));
     }
 
     break;
   }
-  case Intrinsic::uadd_with_overflow:
   case Intrinsic::umul_with_overflow:
   case Intrinsic::smul_with_overflow:
     if (Instruction *I = canonicalizeConstantArg0ToArg1(CI))

I agree, the duplication doesn't look nice.
It may indeed be better to condense the cases,
and have a standalone switch for more specific opts
that will come up in the future,

Logic looks fine, so I won't hold it up, but seems better to not duplicate code for sibling transforms?

Your change looks much better. I wanted to do something like this initially, but I couldn't figure it out. I was missing getIntrinsicId. I'll update this shortly.

Combine saddo and uaddo branch

This revision was automatically updated to reflect the committed changes.