[llvm] [InstCombine] Fold (add (add A, 1), (sext (icmp ne A, 0))) to call umax(A, 1) (PR #122491)
via llvm-commits
llvm-commits at lists.llvm.org
Sat Jan 11 23:56:27 PST 2025
https://github.com/Ruhung updated https://github.com/llvm/llvm-project/pull/122491
>From 61f0c5eb75995bba1a0efe55f95a769709bc6bf7 Mon Sep 17 00:00:00 2001
From: Ruhung <jhlee at pllab.cs.nthu.edu.tw>
Date: Sat, 11 Jan 2025 00:09:07 +0800
Subject: [PATCH 1/2] [InstCombine] Pre-commit tests
---
.../Transforms/InstCombine/add-sext-icmp.ll | 150 ++++++++++++++++++
1 file changed, 150 insertions(+)
create mode 100644 llvm/test/Transforms/InstCombine/add-sext-icmp.ll
diff --git a/llvm/test/Transforms/InstCombine/add-sext-icmp.ll b/llvm/test/Transforms/InstCombine/add-sext-icmp.ll
new file mode 100644
index 00000000000000..aa353af89f6677
--- /dev/null
+++ b/llvm/test/Transforms/InstCombine/add-sext-icmp.ll
@@ -0,0 +1,150 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
+; RUN: opt -S -passes=instcombine < %s | FileCheck %s
+
+; The pattern:
+; add(add A, 1), (sext(icmp ne A, 0))
+; is transformed into:
+; umax(A, 1)
+
+define i32 @add_sext_icmp(i32 %A) {
+; CHECK-LABEL: define i32 @add_sext_icmp(
+; CHECK-SAME: i32 [[A:%.*]]) {
+; CHECK-NEXT: [[ADD1:%.*]] = add i32 [[A]], 1
+; CHECK-NEXT: [[ICMP:%.*]] = icmp ne i32 [[A]], 0
+; CHECK-NEXT: [[SEXT:%.*]] = sext i1 [[ICMP]] to i32
+; CHECK-NEXT: [[ADD2:%.*]] = add i32 [[ADD1]], [[SEXT]]
+; CHECK-NEXT: ret i32 [[ADD2]]
+;
+ %add1 = add i32 %A, 1
+ %icmp = icmp ne i32 %A, 0
+ %sext = sext i1 %icmp to i32
+ %add2 = add i32 %add1, %sext
+ ret i32 %add2
+}
+
+define i32 @add_sext_icmp_commutative(i32 %A) {
+; CHECK-LABEL: define i32 @add_sext_icmp_commutative(
+; CHECK-SAME: i32 [[A:%.*]]) {
+; CHECK-NEXT: [[ADD1:%.*]] = add i32 [[A]], 1
+; CHECK-NEXT: [[ICMP:%.*]] = icmp ne i32 [[A]], 0
+; CHECK-NEXT: [[SEXT:%.*]] = sext i1 [[ICMP]] to i32
+; CHECK-NEXT: [[ADD2:%.*]] = add i32 [[ADD1]], [[SEXT]]
+; CHECK-NEXT: ret i32 [[ADD2]]
+;
+ %add1 = add i32 %A, 1
+ %icmp = icmp ne i32 %A, 0
+ %sext = sext i1 %icmp to i32
+ %add2 = add i32 %sext, %add1
+ ret i32 %add2
+}
+
+; Negative test
+
+define i32 @add_sext_icmp_negative_constant(i32 %A) {
+; CHECK-LABEL: define i32 @add_sext_icmp_negative_constant(
+; CHECK-SAME: i32 [[A:%.*]]) {
+; CHECK-NEXT: [[ADD1:%.*]] = add i32 [[A]], 2
+; CHECK-NEXT: [[ICMP:%.*]] = icmp ne i32 [[A]], 0
+; CHECK-NEXT: [[SEXT:%.*]] = sext i1 [[ICMP]] to i32
+; CHECK-NEXT: [[ADD2:%.*]] = add i32 [[ADD1]], [[SEXT]]
+; CHECK-NEXT: ret i32 [[ADD2]]
+;
+ %add1 = add i32 %A, 2
+ %icmp = icmp ne i32 %A, 0
+ %sext = sext i1 %icmp to i32
+ %add2 = add i32 %add1, %sext
+ ret i32 %add2
+}
+
+define i32 @add_sext_icmp_negative_pred(i32 %A) {
+; CHECK-LABEL: define i32 @add_sext_icmp_negative_pred(
+; CHECK-SAME: i32 [[A:%.*]]) {
+; CHECK-NEXT: [[ADD1:%.*]] = add i32 [[A]], 1
+; CHECK-NEXT: [[ICMP:%.*]] = icmp eq i32 [[A]], 0
+; CHECK-NEXT: [[SEXT:%.*]] = sext i1 [[ICMP]] to i32
+; CHECK-NEXT: [[ADD2:%.*]] = add i32 [[ADD1]], [[SEXT]]
+; CHECK-NEXT: ret i32 [[ADD2]]
+;
+ %add1 = add i32 %A, 1
+ %icmp = icmp eq i32 %A, 0
+ %sext = sext i1 %icmp to i32
+ %add2 = add i32 %add1, %sext
+ ret i32 %add2
+}
+
+; multi-use test
+
+define i32 @add_sext_icmp_multi_use_add2(i32 %A) {
+; CHECK-LABEL: define i32 @add_sext_icmp_multi_use_add2(
+; CHECK-SAME: i32 [[A:%.*]]) {
+; CHECK-NEXT: [[ADD1:%.*]] = add i32 [[A]], 1
+; CHECK-NEXT: [[ICMP:%.*]] = icmp ne i32 [[A]], 0
+; CHECK-NEXT: [[SEXT:%.*]] = sext i1 [[ICMP]] to i32
+; CHECK-NEXT: [[ADD2:%.*]] = add i32 [[ADD1]], [[SEXT]]
+; CHECK-NEXT: call void @use(i32 [[ADD2]])
+; CHECK-NEXT: ret i32 [[ADD2]]
+;
+ %add1 = add i32 %A, 1
+ %icmp = icmp ne i32 %A, 0
+ %sext = sext i1 %icmp to i32
+ %add2 = add i32 %add1, %sext
+ call void @use(i32 %add2)
+ ret i32 %add2
+}
+
+define i32 @add_sext_icmp_multi_use_sext(i32 %A) {
+; CHECK-LABEL: define i32 @add_sext_icmp_multi_use_sext(
+; CHECK-SAME: i32 [[A:%.*]]) {
+; CHECK-NEXT: [[ADD1:%.*]] = add i32 [[A]], 1
+; CHECK-NEXT: [[ICMP:%.*]] = icmp ne i32 [[A]], 0
+; CHECK-NEXT: [[SEXT:%.*]] = sext i1 [[ICMP]] to i32
+; CHECK-NEXT: call void @use(i32 [[SEXT]])
+; CHECK-NEXT: [[ADD2:%.*]] = add i32 [[ADD1]], [[SEXT]]
+; CHECK-NEXT: ret i32 [[ADD2]]
+;
+ %add1 = add i32 %A, 1
+ %icmp = icmp ne i32 %A, 0
+ %sext = sext i1 %icmp to i32
+ call void @use(i32 %sext)
+ %add2 = add i32 %add1, %sext
+ ret i32 %add2
+}
+
+define i32 @add_sext_icmp_multi_use_icmp(i32 %A) {
+; CHECK-LABEL: define i32 @add_sext_icmp_multi_use_icmp(
+; CHECK-SAME: i32 [[A:%.*]]) {
+; CHECK-NEXT: [[ADD1:%.*]] = add i32 [[A]], 1
+; CHECK-NEXT: [[ICMP:%.*]] = icmp ne i32 [[A]], 0
+; CHECK-NEXT: call void @use(i1 [[ICMP]])
+; CHECK-NEXT: [[SEXT:%.*]] = sext i1 [[ICMP]] to i32
+; CHECK-NEXT: [[ADD2:%.*]] = add i32 [[ADD1]], [[SEXT]]
+; CHECK-NEXT: ret i32 [[ADD2]]
+;
+ %add1 = add i32 %A, 1
+ %icmp = icmp ne i32 %A, 0
+ call void @use(i1 %icmp)
+ %sext = sext i1 %icmp to i32
+ %add2 = add i32 %add1, %sext
+ ret i32 %add2
+}
+
+define i32 @add_sext_icmp_multi_use_add1(i32 %A) {
+; CHECK-LABEL: define i32 @add_sext_icmp_multi_use_add1(
+; CHECK-SAME: i32 [[A:%.*]]) {
+; CHECK-NEXT: [[ADD1:%.*]] = add i32 [[A]], 1
+; CHECK-NEXT: call void @use(i32 [[ADD1]])
+; CHECK-NEXT: [[ICMP:%.*]] = icmp ne i32 [[A]], 0
+; CHECK-NEXT: [[SEXT:%.*]] = sext i1 [[ICMP]] to i32
+; CHECK-NEXT: [[ADD2:%.*]] = add i32 [[ADD1]], [[SEXT]]
+; CHECK-NEXT: ret i32 [[ADD2]]
+;
+ %add1 = add i32 %A, 1
+ call void @use(i32 %add1)
+ %icmp = icmp ne i32 %A, 0
+ %sext = sext i1 %icmp to i32
+ %add2 = add i32 %add1, %sext
+ ret i32 %add2
+}
+
+declare void @use(i32)
+
>From 77bd90e64b82204d3bc0a96006a9124d371eb4ee Mon Sep 17 00:00:00 2001
From: Ruhung <jhlee at pllab.cs.nthu.edu.tw>
Date: Sat, 11 Jan 2025 00:25:43 +0800
Subject: [PATCH 2/2] [InstCombine] Fold (add (add A, 1), (sext (icmp ne A,
0))) to call umax(A, 1)
---
.../Transforms/InstCombine/InstCombineAddSub.cpp | 9 +++++++++
llvm/test/Transforms/InstCombine/add-sext-icmp.ll | 15 +++------------
2 files changed, 12 insertions(+), 12 deletions(-)
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp
index 73876d00e73a7c..45fe2214ec05e2 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp
@@ -1775,6 +1775,15 @@ Instruction *InstCombinerImpl::visitAdd(BinaryOperator &I) {
}
}
+ // (add (add A, 1), (sext (icmp ne A, 0))) => call umax(A, 1)
+ if (match(LHS, m_OneUse(m_Add(m_Value(A), m_One()))) &&
+ match(RHS, m_OneUse(m_SExt(m_OneUse(m_SpecificICmp(
+ ICmpInst::ICMP_NE, m_Specific(A), m_ZeroInt())))))) {
+ Value *OneConst = ConstantInt::get(A->getType(), 1);
+ Value *UMax = Builder.CreateBinaryIntrinsic(Intrinsic::umax, A, OneConst);
+ return replaceInstUsesWith(I, UMax);
+ }
+
if (Instruction *Ashr = foldAddToAshr(I))
return Ashr;
diff --git a/llvm/test/Transforms/InstCombine/add-sext-icmp.ll b/llvm/test/Transforms/InstCombine/add-sext-icmp.ll
index aa353af89f6677..f8bd106964ae44 100644
--- a/llvm/test/Transforms/InstCombine/add-sext-icmp.ll
+++ b/llvm/test/Transforms/InstCombine/add-sext-icmp.ll
@@ -9,10 +9,7 @@
define i32 @add_sext_icmp(i32 %A) {
; CHECK-LABEL: define i32 @add_sext_icmp(
; CHECK-SAME: i32 [[A:%.*]]) {
-; CHECK-NEXT: [[ADD1:%.*]] = add i32 [[A]], 1
-; CHECK-NEXT: [[ICMP:%.*]] = icmp ne i32 [[A]], 0
-; CHECK-NEXT: [[SEXT:%.*]] = sext i1 [[ICMP]] to i32
-; CHECK-NEXT: [[ADD2:%.*]] = add i32 [[ADD1]], [[SEXT]]
+; CHECK-NEXT: [[ADD2:%.*]] = call i32 @llvm.umax.i32(i32 [[A]], i32 1)
; CHECK-NEXT: ret i32 [[ADD2]]
;
%add1 = add i32 %A, 1
@@ -25,10 +22,7 @@ define i32 @add_sext_icmp(i32 %A) {
define i32 @add_sext_icmp_commutative(i32 %A) {
; CHECK-LABEL: define i32 @add_sext_icmp_commutative(
; CHECK-SAME: i32 [[A:%.*]]) {
-; CHECK-NEXT: [[ADD1:%.*]] = add i32 [[A]], 1
-; CHECK-NEXT: [[ICMP:%.*]] = icmp ne i32 [[A]], 0
-; CHECK-NEXT: [[SEXT:%.*]] = sext i1 [[ICMP]] to i32
-; CHECK-NEXT: [[ADD2:%.*]] = add i32 [[ADD1]], [[SEXT]]
+; CHECK-NEXT: [[ADD2:%.*]] = call i32 @llvm.umax.i32(i32 [[A]], i32 1)
; CHECK-NEXT: ret i32 [[ADD2]]
;
%add1 = add i32 %A, 1
@@ -77,10 +71,7 @@ define i32 @add_sext_icmp_negative_pred(i32 %A) {
define i32 @add_sext_icmp_multi_use_add2(i32 %A) {
; CHECK-LABEL: define i32 @add_sext_icmp_multi_use_add2(
; CHECK-SAME: i32 [[A:%.*]]) {
-; CHECK-NEXT: [[ADD1:%.*]] = add i32 [[A]], 1
-; CHECK-NEXT: [[ICMP:%.*]] = icmp ne i32 [[A]], 0
-; CHECK-NEXT: [[SEXT:%.*]] = sext i1 [[ICMP]] to i32
-; CHECK-NEXT: [[ADD2:%.*]] = add i32 [[ADD1]], [[SEXT]]
+; CHECK-NEXT: [[ADD2:%.*]] = call i32 @llvm.umax.i32(i32 [[A]], i32 1)
; CHECK-NEXT: call void @use(i32 [[ADD2]])
; CHECK-NEXT: ret i32 [[ADD2]]
;
More information about the llvm-commits
mailing list