[llvm] e5748c6 - [InstCombine] reduce sub-with-overflow ==/!= 0

Sanjay Patel via llvm-commits llvm-commits at lists.llvm.org
Mon Aug 15 10:04:01 PDT 2022


Author: Sanjay Patel
Date: 2022-08-15T13:03:51-04:00
New Revision: e5748c6e73e7a3173046002b1f9a556965552c37

URL: https://github.com/llvm/llvm-project/commit/e5748c6e73e7a3173046002b1f9a556965552c37
DIFF: https://github.com/llvm/llvm-project/commit/e5748c6e73e7a3173046002b1f9a556965552c37.diff

LOG: [InstCombine] reduce sub-with-overflow ==/!= 0

The basic patterns look like this:
https://alive2.llvm.org/ce/z/MDj9EC

The tests have a use of the overflow value too.
Otherwise, existing folds should reduce already.

This was noted as a missing IR fold in:
926e7312b2f20f2f7b

Hopefully, this makes it easier to implement a backend
fix because we should get the same IR regardless of
whether the source used builtins or inline code.

Added: 
    

Modified: 
    llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
    llvm/test/Transforms/InstCombine/ssubo.ll
    llvm/test/Transforms/InstCombine/usubo.ll

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
index 39f526c95fb6..46e4f6b7edd3 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
@@ -3185,6 +3185,20 @@ Instruction *InstCombinerImpl::foldICmpInstWithConstant(ICmpInst &Cmp) {
     if (auto *II = dyn_cast<IntrinsicInst>(Cmp.getOperand(0)))
       if (Instruction *I = foldICmpIntrinsicWithConstant(Cmp, II, *C))
         return I;
+
+    // (extractval ([s/u]subo X, Y), 0) == 0 --> X == Y
+    // (extractval ([s/u]subo X, Y), 0) != 0 --> X != Y
+    // TODO: This checks one-use, but that is not strictly necessary.
+    Value *Cmp0 = Cmp.getOperand(0);
+    Value *X, *Y;
+    if (C->isZero() && Cmp.isEquality() && Cmp0->hasOneUse() &&
+        (match(Cmp0,
+               m_ExtractValue<0>(m_Intrinsic<Intrinsic::ssub_with_overflow>(
+                   m_Value(X), m_Value(Y)))) ||
+         match(Cmp0,
+               m_ExtractValue<0>(m_Intrinsic<Intrinsic::usub_with_overflow>(
+                   m_Value(X), m_Value(Y))))))
+      return new ICmpInst(Cmp.getPredicate(), X, Y);
   }
 
   if (match(Cmp.getOperand(1), m_APIntAllowUndef(C)))

diff  --git a/llvm/test/Transforms/InstCombine/ssubo.ll b/llvm/test/Transforms/InstCombine/ssubo.ll
index d8f965d396e2..30749afdfc57 100644
--- a/llvm/test/Transforms/InstCombine/ssubo.ll
+++ b/llvm/test/Transforms/InstCombine/ssubo.ll
@@ -102,8 +102,7 @@ define i1 @sub_eq0(i8 %x, i8 %y, i1 %b) {
 ; CHECK-NEXT:    [[SS:%.*]] = call { i8, i1 } @llvm.ssub.with.overflow.i8(i8 [[X:%.*]], i8 [[Y:%.*]])
 ; CHECK-NEXT:    [[OV:%.*]] = extractvalue { i8, i1 } [[SS]], 1
 ; CHECK-NEXT:    call void @use(i1 [[OV]])
-; CHECK-NEXT:    [[SUB:%.*]] = extractvalue { i8, i1 } [[SS]], 0
-; CHECK-NEXT:    [[EQ0:%.*]] = icmp eq i8 [[SUB]], 0
+; CHECK-NEXT:    [[EQ0:%.*]] = icmp eq i8 [[X]], [[Y]]
 ; CHECK-NEXT:    ret i1 [[EQ0]]
 ;
   %ss = call { i8, i1 } @llvm.ssub.with.overflow.i8(i8 %x, i8 %y)
@@ -119,8 +118,7 @@ define i1 @sub_ne0(i8 %x, i8 %y, i1 %b) {
 ; CHECK-NEXT:    [[SS:%.*]] = call { i8, i1 } @llvm.ssub.with.overflow.i8(i8 [[X:%.*]], i8 [[Y:%.*]])
 ; CHECK-NEXT:    [[OV:%.*]] = extractvalue { i8, i1 } [[SS]], 1
 ; CHECK-NEXT:    call void @use(i1 [[OV]])
-; CHECK-NEXT:    [[SUB:%.*]] = extractvalue { i8, i1 } [[SS]], 0
-; CHECK-NEXT:    [[NE0:%.*]] = icmp ne i8 [[SUB]], 0
+; CHECK-NEXT:    [[NE0:%.*]] = icmp ne i8 [[X]], [[Y]]
 ; CHECK-NEXT:    ret i1 [[NE0]]
 ;
   %ss = call { i8, i1 } @llvm.ssub.with.overflow.i8(i8 %x, i8 %y)
@@ -130,3 +128,41 @@ define i1 @sub_ne0(i8 %x, i8 %y, i1 %b) {
   %ne0 = icmp ne i8 %sub, 0
   ret i1 %ne0
 }
+
+; negative test - need zero
+
+define i1 @sub_eq1(i8 %x, i8 %y, i1 %b) {
+; CHECK-LABEL: @sub_eq1(
+; CHECK-NEXT:    [[SS:%.*]] = call { i8, i1 } @llvm.ssub.with.overflow.i8(i8 [[X:%.*]], i8 [[Y:%.*]])
+; CHECK-NEXT:    [[OV:%.*]] = extractvalue { i8, i1 } [[SS]], 1
+; CHECK-NEXT:    call void @use(i1 [[OV]])
+; CHECK-NEXT:    [[SUB:%.*]] = extractvalue { i8, i1 } [[SS]], 0
+; CHECK-NEXT:    [[EQ1:%.*]] = icmp eq i8 [[SUB]], 1
+; CHECK-NEXT:    ret i1 [[EQ1]]
+;
+  %ss = call { i8, i1 } @llvm.ssub.with.overflow.i8(i8 %x, i8 %y)
+  %ov = extractvalue { i8, i1 } %ss, 1
+  call void @use(i1 %ov)
+  %sub = extractvalue { i8, i1 } %ss, 0
+  %eq1 = icmp eq i8 %sub, 1
+  ret i1 %eq1
+}
+
+; negative test - need equality pred
+
+define i1 @sub_sgt0(i8 %x, i8 %y, i1 %b) {
+; CHECK-LABEL: @sub_sgt0(
+; CHECK-NEXT:    [[SS:%.*]] = call { i8, i1 } @llvm.ssub.with.overflow.i8(i8 [[X:%.*]], i8 [[Y:%.*]])
+; CHECK-NEXT:    [[OV:%.*]] = extractvalue { i8, i1 } [[SS]], 1
+; CHECK-NEXT:    call void @use(i1 [[OV]])
+; CHECK-NEXT:    [[SUB:%.*]] = extractvalue { i8, i1 } [[SS]], 0
+; CHECK-NEXT:    [[SGT0:%.*]] = icmp sgt i8 [[SUB]], 0
+; CHECK-NEXT:    ret i1 [[SGT0]]
+;
+  %ss = call { i8, i1 } @llvm.ssub.with.overflow.i8(i8 %x, i8 %y)
+  %ov = extractvalue { i8, i1 } %ss, 1
+  call void @use(i1 %ov)
+  %sub = extractvalue { i8, i1 } %ss, 0
+  %sgt0 = icmp sgt i8 %sub, 0
+  ret i1 %sgt0
+}

diff  --git a/llvm/test/Transforms/InstCombine/usubo.ll b/llvm/test/Transforms/InstCombine/usubo.ll
index 7ecbef2f329e..2074190a2cd4 100644
--- a/llvm/test/Transforms/InstCombine/usubo.ll
+++ b/llvm/test/Transforms/InstCombine/usubo.ll
@@ -98,11 +98,9 @@ define i1 @test_constant255(i8 %a) {
 
 define i1 @sub_eq0(i8 %x, i8 %y, i1 %b) {
 ; CHECK-LABEL: @sub_eq0(
-; CHECK-NEXT:    [[US:%.*]] = call { i8, i1 } @llvm.usub.with.overflow.i8(i8 [[X:%.*]], i8 [[Y:%.*]])
-; CHECK-NEXT:    [[OV:%.*]] = extractvalue { i8, i1 } [[US]], 1
+; CHECK-NEXT:    [[OV:%.*]] = icmp ult i8 [[X:%.*]], [[Y:%.*]]
 ; CHECK-NEXT:    call void @use(i1 [[OV]])
-; CHECK-NEXT:    [[SUB:%.*]] = extractvalue { i8, i1 } [[US]], 0
-; CHECK-NEXT:    [[EQ0:%.*]] = icmp eq i8 [[SUB]], 0
+; CHECK-NEXT:    [[EQ0:%.*]] = icmp eq i8 [[X]], [[Y]]
 ; CHECK-NEXT:    ret i1 [[EQ0]]
 ;
   %us = call { i8, i1 } @llvm.usub.with.overflow.i8(i8 %x, i8 %y)
@@ -115,11 +113,9 @@ define i1 @sub_eq0(i8 %x, i8 %y, i1 %b) {
 
 define i1 @sub_ne0(i8 %x, i8 %y, i1 %b) {
 ; CHECK-LABEL: @sub_ne0(
-; CHECK-NEXT:    [[US:%.*]] = call { i8, i1 } @llvm.usub.with.overflow.i8(i8 [[X:%.*]], i8 [[Y:%.*]])
-; CHECK-NEXT:    [[OV:%.*]] = extractvalue { i8, i1 } [[US]], 1
+; CHECK-NEXT:    [[OV:%.*]] = icmp ult i8 [[X:%.*]], [[Y:%.*]]
 ; CHECK-NEXT:    call void @use(i1 [[OV]])
-; CHECK-NEXT:    [[SUB:%.*]] = extractvalue { i8, i1 } [[US]], 0
-; CHECK-NEXT:    [[NE0:%.*]] = icmp ne i8 [[SUB]], 0
+; CHECK-NEXT:    [[NE0:%.*]] = icmp ne i8 [[X]], [[Y]]
 ; CHECK-NEXT:    ret i1 [[NE0]]
 ;
   %us = call { i8, i1 } @llvm.usub.with.overflow.i8(i8 %x, i8 %y)
@@ -129,3 +125,41 @@ define i1 @sub_ne0(i8 %x, i8 %y, i1 %b) {
   %ne0 = icmp ne i8 %sub, 0
   ret i1 %ne0
 }
+
+; negative test - need zero
+
+define i1 @sub_eq1(i8 %x, i8 %y, i1 %b) {
+; CHECK-LABEL: @sub_eq1(
+; CHECK-NEXT:    [[SS:%.*]] = call { i8, i1 } @llvm.usub.with.overflow.i8(i8 [[X:%.*]], i8 [[Y:%.*]])
+; CHECK-NEXT:    [[OV:%.*]] = extractvalue { i8, i1 } [[SS]], 1
+; CHECK-NEXT:    call void @use(i1 [[OV]])
+; CHECK-NEXT:    [[SUB:%.*]] = extractvalue { i8, i1 } [[SS]], 0
+; CHECK-NEXT:    [[EQ1:%.*]] = icmp eq i8 [[SUB]], 1
+; CHECK-NEXT:    ret i1 [[EQ1]]
+;
+  %ss = call { i8, i1 } @llvm.usub.with.overflow.i8(i8 %x, i8 %y)
+  %ov = extractvalue { i8, i1 } %ss, 1
+  call void @use(i1 %ov)
+  %sub = extractvalue { i8, i1 } %ss, 0
+  %eq1 = icmp eq i8 %sub, 1
+  ret i1 %eq1
+}
+
+; negative test - need equality pred
+
+define i1 @sub_sgt0(i8 %x, i8 %y, i1 %b) {
+; CHECK-LABEL: @sub_sgt0(
+; CHECK-NEXT:    [[SS:%.*]] = call { i8, i1 } @llvm.usub.with.overflow.i8(i8 [[X:%.*]], i8 [[Y:%.*]])
+; CHECK-NEXT:    [[OV:%.*]] = extractvalue { i8, i1 } [[SS]], 1
+; CHECK-NEXT:    call void @use(i1 [[OV]])
+; CHECK-NEXT:    [[SUB:%.*]] = extractvalue { i8, i1 } [[SS]], 0
+; CHECK-NEXT:    [[SGT0:%.*]] = icmp sgt i8 [[SUB]], 0
+; CHECK-NEXT:    ret i1 [[SGT0]]
+;
+  %ss = call { i8, i1 } @llvm.usub.with.overflow.i8(i8 %x, i8 %y)
+  %ov = extractvalue { i8, i1 } %ss, 1
+  call void @use(i1 %ov)
+  %sub = extractvalue { i8, i1 } %ss, 0
+  %sgt0 = icmp sgt i8 %sub, 0
+  ret i1 %sgt0
+}


        


More information about the llvm-commits mailing list