[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