[llvm] [InstCombine] Fold usub_sat((sub nuw C1, A), C2) to usub_sat(C1 - C2, A) or 0 (PR #82280)
via llvm-commits
llvm-commits at lists.llvm.org
Sat Mar 9 11:29:38 PST 2024
https://github.com/elhewaty updated https://github.com/llvm/llvm-project/pull/82280
>From 6c07b2f4ec1b98dc2dc5c75e3d925c5246599434 Mon Sep 17 00:00:00 2001
From: Mohamed Atef <mohamedatef1698 at gmail.com>
Date: Mon, 19 Feb 2024 22:15:10 +0200
Subject: [PATCH 1/2] [InstCombine] Add test coverage for folding usub_sat((sub
nuw C1, A), C2) to usub_sat(C1 - C2, A) or 0(NFC)
---
.../InstCombine/unsigned_saturated_sub.ll | 95 +++++++++++++++++++
1 file changed, 95 insertions(+)
diff --git a/llvm/test/Transforms/InstCombine/unsigned_saturated_sub.ll b/llvm/test/Transforms/InstCombine/unsigned_saturated_sub.ll
index 5cece931b8d987..37d9754a8c05cc 100644
--- a/llvm/test/Transforms/InstCombine/unsigned_saturated_sub.ll
+++ b/llvm/test/Transforms/InstCombine/unsigned_saturated_sub.ll
@@ -8,6 +8,101 @@ declare void @use(i64)
declare void @usei32(i32)
declare void @usei1(i1)
+; usub_sat((sub nuw C1, A), C2) to usub_sat(C1 - C2, A) or 0
+
+define i32 @usub_sat_C1_C2(i32 %a){
+; CHECK-LABEL: @usub_sat_C1_C2(
+; CHECK-NEXT: [[ADD:%.*]] = sub nuw i32 64, [[A:%.*]]
+; CHECK-NEXT: [[COND:%.*]] = call i32 @llvm.usub.sat.i32(i32 [[ADD]], i32 14)
+; CHECK-NEXT: ret i32 [[COND]]
+;
+ %add = sub nuw i32 64, %a
+ %cond = call i32 @llvm.usub.sat.i32(i32 %add, i32 14)
+ ret i32 %cond
+}
+
+define i32 @usub_sat_C1_C2_produce_0(i32 %a){
+; CHECK-LABEL: @usub_sat_C1_C2_produce_0(
+; CHECK-NEXT: [[ADD:%.*]] = sub nuw i32 14, [[A:%.*]]
+; CHECK-NEXT: [[COND:%.*]] = call i32 @llvm.usub.sat.i32(i32 [[ADD]], i32 14)
+; CHECK-NEXT: ret i32 [[COND]]
+;
+ %add = sub nuw i32 14, %a
+ %cond = call i32 @llvm.usub.sat.i32(i32 %add, i32 14)
+ ret i32 %cond
+}
+
+define i32 @usub_sat_C1_C2_produce_0_too(i32 %a){
+; CHECK-LABEL: @usub_sat_C1_C2_produce_0_too(
+; CHECK-NEXT: [[ADD:%.*]] = sub nuw i32 12, [[A:%.*]]
+; CHECK-NEXT: [[COND:%.*]] = call i32 @llvm.usub.sat.i32(i32 [[ADD]], i32 14)
+; CHECK-NEXT: ret i32 [[COND]]
+;
+ %add = sub nuw i32 12, %a
+ %cond = call i32 @llvm.usub.sat.i32(i32 %add, i32 14)
+ ret i32 %cond
+}
+
+; vector tests
+define <2 x i16> @usub_sat_C1_C2_splat(<2 x i16> %a) {
+; CHECK-LABEL: @usub_sat_C1_C2_splat(
+; CHECK-NEXT: [[ADD:%.*]] = sub nuw <2 x i16> <i16 64, i16 64>, [[A:%.*]]
+; CHECK-NEXT: [[COND:%.*]] = call <2 x i16> @llvm.usub.sat.v2i16(<2 x i16> [[ADD]], <2 x i16> <i16 14, i16 14>)
+; CHECK-NEXT: ret <2 x i16> [[COND]]
+;
+ %add = sub nuw <2 x i16> <i16 64, i16 64>, %a
+ %cond = call <2 x i16> @llvm.usub.sat.v2i16(<2 x i16> %add, <2 x i16> <i16 14, i16 14>)
+ ret <2 x i16> %cond
+}
+
+define <2 x i16> @usub_sat_C1_C2_splat_produce_0(<2 x i16> %a){
+; CHECK-LABEL: @usub_sat_C1_C2_splat_produce_0(
+; CHECK-NEXT: [[ADD:%.*]] = sub nuw <2 x i16> <i16 14, i16 14>, [[A:%.*]]
+; CHECK-NEXT: [[COND:%.*]] = call <2 x i16> @llvm.usub.sat.v2i16(<2 x i16> [[ADD]], <2 x i16> <i16 14, i16 14>)
+; CHECK-NEXT: ret <2 x i16> [[COND]]
+;
+ %add = sub nuw <2 x i16> <i16 14, i16 14>, %a
+ %cond = call <2 x i16> @llvm.usub.sat.v2i16(<2 x i16> %add, <2 x i16> <i16 14, i16 14>)
+ ret <2 x i16> %cond
+}
+
+define <2 x i16> @usub_sat_C1_C2_splat_produce_0_too(<2 x i16> %a){
+; CHECK-LABEL: @usub_sat_C1_C2_splat_produce_0_too(
+; CHECK-NEXT: [[ADD:%.*]] = sub nuw <2 x i16> <i16 12, i16 12>, [[A:%.*]]
+; CHECK-NEXT: [[COND:%.*]] = call <2 x i16> @llvm.usub.sat.v2i16(<2 x i16> [[ADD]], <2 x i16> <i16 14, i16 14>)
+; CHECK-NEXT: ret <2 x i16> [[COND]]
+;
+ %add = sub nuw <2 x i16> <i16 12, i16 12>, %a
+ %cond = call <2 x i16> @llvm.usub.sat.v2i16(<2 x i16> %add, <2 x i16> <i16 14, i16 14>)
+ ret <2 x i16> %cond
+}
+
+; negative tests this souldn't work
+
+define i32 @usub_sat_C1_C2_without_nuw(i32 %a){
+; CHECK-LABEL: @usub_sat_C1_C2_without_nuw(
+; CHECK-NEXT: [[ADD:%.*]] = sub i32 12, [[A:%.*]]
+; CHECK-NEXT: [[COND:%.*]] = call i32 @llvm.usub.sat.i32(i32 [[ADD]], i32 14)
+; CHECK-NEXT: ret i32 [[COND]]
+;
+ %add = sub i32 12, %a
+ %cond = call i32 @llvm.usub.sat.i32(i32 %add, i32 14)
+ ret i32 %cond
+}
+
+define i32 @usub_sat_C1_C2_more_than_one_use_with_add(i32 %a){
+; CHECK-LABEL: @usub_sat_C1_C2_more_than_one_use_with_add(
+; CHECK-NEXT: [[ADD:%.*]] = sub nuw i32 12, [[A:%.*]]
+; CHECK-NEXT: [[COND:%.*]] = call i32 @llvm.usub.sat.i32(i32 [[ADD]], i32 14)
+; CHECK-NEXT: call void @usei32(i32 [[ADD]])
+; CHECK-NEXT: ret i32 [[COND]]
+;
+ %add = sub nuw i32 12, %a
+ %cond = call i32 @llvm.usub.sat.i32(i32 %add, i32 14)
+ call void @usei32(i32 %add)
+ ret i32 %cond
+}
+
; (a > b) ? a - b : 0 -> usub.sat(a, b)
define i64 @max_sub_ugt(i64 %a, i64 %b) {
>From 4e21d4ede9da642d1b06c7969f8e0334a308ab9f Mon Sep 17 00:00:00 2001
From: Mohamed Atef <mohamedatef1698 at gmail.com>
Date: Sat, 9 Mar 2024 21:27:46 +0200
Subject: [PATCH 2/2] [InstCombine] Fold usub_sat((sub nuw C1, A), C2) to
usub_sat(C1 - C2, A) or 0
---
.../InstCombine/InstCombineCalls.cpp | 17 ++++++++++++++
.../InstCombine/unsigned_saturated_sub.ll | 22 +++++--------------
2 files changed, 23 insertions(+), 16 deletions(-)
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
index 5266808c5abab4..c218e0633e8f0d 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
@@ -2139,6 +2139,23 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
}
}
+ // usub_sat((sub nuw C1, A), C2) -> usub_sat(C1 - C2, A) if C2 u< C1
+ // usub_sat((sub nuw C1, A), C2) -> 0 otherwise
+ const APInt *C1, *C2;
+ Value *A;
+ if (IID == Intrinsic::usub_sat &&
+ match(Arg0, m_OneUse(m_NUWSub(m_APInt(C1), m_Value(A)))) &&
+ match(Arg1, m_APInt(C2))) {
+
+ if (C2->ult(*C1)) {
+ auto *New = Builder.CreateBinaryIntrinsic(
+ Intrinsic::usub_sat, ConstantInt::get(Ty, *C1 - *C2), A);
+ return replaceInstUsesWith(*SI, New);
+ } else {
+ return replaceInstUsesWith(*SI, ConstantInt::get(Ty, 0));
+ }
+ }
+
// ssub.sat(X, C) -> sadd.sat(X, -C) if C != MIN
Constant *C;
if (IID == Intrinsic::ssub_sat && match(Arg1, m_Constant(C)) &&
diff --git a/llvm/test/Transforms/InstCombine/unsigned_saturated_sub.ll b/llvm/test/Transforms/InstCombine/unsigned_saturated_sub.ll
index 37d9754a8c05cc..992b1881f13515 100644
--- a/llvm/test/Transforms/InstCombine/unsigned_saturated_sub.ll
+++ b/llvm/test/Transforms/InstCombine/unsigned_saturated_sub.ll
@@ -12,8 +12,7 @@ declare void @usei1(i1)
define i32 @usub_sat_C1_C2(i32 %a){
; CHECK-LABEL: @usub_sat_C1_C2(
-; CHECK-NEXT: [[ADD:%.*]] = sub nuw i32 64, [[A:%.*]]
-; CHECK-NEXT: [[COND:%.*]] = call i32 @llvm.usub.sat.i32(i32 [[ADD]], i32 14)
+; CHECK-NEXT: [[COND:%.*]] = call i32 @llvm.usub.sat.i32(i32 50, i32 [[A:%.*]])
; CHECK-NEXT: ret i32 [[COND]]
;
%add = sub nuw i32 64, %a
@@ -23,9 +22,7 @@ define i32 @usub_sat_C1_C2(i32 %a){
define i32 @usub_sat_C1_C2_produce_0(i32 %a){
; CHECK-LABEL: @usub_sat_C1_C2_produce_0(
-; CHECK-NEXT: [[ADD:%.*]] = sub nuw i32 14, [[A:%.*]]
-; CHECK-NEXT: [[COND:%.*]] = call i32 @llvm.usub.sat.i32(i32 [[ADD]], i32 14)
-; CHECK-NEXT: ret i32 [[COND]]
+; CHECK-NEXT: ret i32 0
;
%add = sub nuw i32 14, %a
%cond = call i32 @llvm.usub.sat.i32(i32 %add, i32 14)
@@ -34,9 +31,7 @@ define i32 @usub_sat_C1_C2_produce_0(i32 %a){
define i32 @usub_sat_C1_C2_produce_0_too(i32 %a){
; CHECK-LABEL: @usub_sat_C1_C2_produce_0_too(
-; CHECK-NEXT: [[ADD:%.*]] = sub nuw i32 12, [[A:%.*]]
-; CHECK-NEXT: [[COND:%.*]] = call i32 @llvm.usub.sat.i32(i32 [[ADD]], i32 14)
-; CHECK-NEXT: ret i32 [[COND]]
+; CHECK-NEXT: ret i32 0
;
%add = sub nuw i32 12, %a
%cond = call i32 @llvm.usub.sat.i32(i32 %add, i32 14)
@@ -46,8 +41,7 @@ define i32 @usub_sat_C1_C2_produce_0_too(i32 %a){
; vector tests
define <2 x i16> @usub_sat_C1_C2_splat(<2 x i16> %a) {
; CHECK-LABEL: @usub_sat_C1_C2_splat(
-; CHECK-NEXT: [[ADD:%.*]] = sub nuw <2 x i16> <i16 64, i16 64>, [[A:%.*]]
-; CHECK-NEXT: [[COND:%.*]] = call <2 x i16> @llvm.usub.sat.v2i16(<2 x i16> [[ADD]], <2 x i16> <i16 14, i16 14>)
+; CHECK-NEXT: [[COND:%.*]] = call <2 x i16> @llvm.usub.sat.v2i16(<2 x i16> <i16 50, i16 50>, <2 x i16> [[A:%.*]])
; CHECK-NEXT: ret <2 x i16> [[COND]]
;
%add = sub nuw <2 x i16> <i16 64, i16 64>, %a
@@ -57,9 +51,7 @@ define <2 x i16> @usub_sat_C1_C2_splat(<2 x i16> %a) {
define <2 x i16> @usub_sat_C1_C2_splat_produce_0(<2 x i16> %a){
; CHECK-LABEL: @usub_sat_C1_C2_splat_produce_0(
-; CHECK-NEXT: [[ADD:%.*]] = sub nuw <2 x i16> <i16 14, i16 14>, [[A:%.*]]
-; CHECK-NEXT: [[COND:%.*]] = call <2 x i16> @llvm.usub.sat.v2i16(<2 x i16> [[ADD]], <2 x i16> <i16 14, i16 14>)
-; CHECK-NEXT: ret <2 x i16> [[COND]]
+; CHECK-NEXT: ret <2 x i16> zeroinitializer
;
%add = sub nuw <2 x i16> <i16 14, i16 14>, %a
%cond = call <2 x i16> @llvm.usub.sat.v2i16(<2 x i16> %add, <2 x i16> <i16 14, i16 14>)
@@ -68,9 +60,7 @@ define <2 x i16> @usub_sat_C1_C2_splat_produce_0(<2 x i16> %a){
define <2 x i16> @usub_sat_C1_C2_splat_produce_0_too(<2 x i16> %a){
; CHECK-LABEL: @usub_sat_C1_C2_splat_produce_0_too(
-; CHECK-NEXT: [[ADD:%.*]] = sub nuw <2 x i16> <i16 12, i16 12>, [[A:%.*]]
-; CHECK-NEXT: [[COND:%.*]] = call <2 x i16> @llvm.usub.sat.v2i16(<2 x i16> [[ADD]], <2 x i16> <i16 14, i16 14>)
-; CHECK-NEXT: ret <2 x i16> [[COND]]
+; CHECK-NEXT: ret <2 x i16> zeroinitializer
;
%add = sub nuw <2 x i16> <i16 12, i16 12>, %a
%cond = call <2 x i16> @llvm.usub.sat.v2i16(<2 x i16> %add, <2 x i16> <i16 14, i16 14>)
More information about the llvm-commits
mailing list