[llvm] [InstCombine] Fold X - Y + Y * C -> X + Y * (C - 1) (PR #117722)
via llvm-commits
llvm-commits at lists.llvm.org
Tue Nov 26 07:18:52 PST 2024
https://github.com/AreaZR updated https://github.com/llvm/llvm-project/pull/117722
>From e7bc7dbdbf9e471cfa4c88c5ea5d1292e07ad8ed Mon Sep 17 00:00:00 2001
From: Rose <gfunni234 at gmail.com>
Date: Tue, 26 Nov 2024 10:11:39 -0500
Subject: [PATCH 1/2] [InstCombine] Pre-commit tests (NFC)
---
.../InstCombine/addsub-constant-folding.ll | 109 ++++++++++++++++++
1 file changed, 109 insertions(+)
diff --git a/llvm/test/Transforms/InstCombine/addsub-constant-folding.ll b/llvm/test/Transforms/InstCombine/addsub-constant-folding.ll
index b38466f6cf0ec2..7c3d61260cf5cf 100644
--- a/llvm/test/Transforms/InstCombine/addsub-constant-folding.ll
+++ b/llvm/test/Transforms/InstCombine/addsub-constant-folding.ll
@@ -750,3 +750,112 @@ define i8 @sub_from_constant_extra_use(i8 %x, i8 %y) {
%r = add i8 %sub, %y
ret i8 %r
}
+
+define i32 @sub_plus_mul(i32 %x, i32 %y) {
+; CHECK-LABEL: @sub_plus_mul(
+; CHECK-NEXT: [[A:%.*]] = sub i32 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT: [[B:%.*]] = mul i32 [[Y]], 10
+; CHECK-NEXT: [[C:%.*]] = add i32 [[A]], [[B]]
+; CHECK-NEXT: ret i32 [[C]]
+;
+ %a = sub i32 %x, %y
+ %b = mul i32 %y, 10
+ %c = add i32 %a, %b
+ ret i32 %c
+}
+
+define i32 @sub_plus_mul_2(i32 %x, i32 %y) {
+; CHECK-LABEL: @sub_plus_mul_2(
+; CHECK-NEXT: [[A:%.*]] = sub i32 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT: [[B:%.*]] = mul i32 [[Y]], -10
+; CHECK-NEXT: [[C:%.*]] = add i32 [[A]], [[B]]
+; CHECK-NEXT: ret i32 [[C]]
+;
+ %a = sub i32 %x, %y
+ %b = mul i32 %y, -10
+ %c = add i32 %a, %b
+ ret i32 %c
+}
+
+define i32 @sub_plus_mul3(i32 %x, i32 %y) {
+; CHECK-LABEL: @sub_plus_mul3(
+; CHECK-NEXT: [[A:%.*]] = mul i32 [[Y:%.*]], 10
+; CHECK-NEXT: [[B:%.*]] = sub i32 [[X:%.*]], [[Y]]
+; CHECK-NEXT: [[C:%.*]] = add i32 [[B]], [[A]]
+; CHECK-NEXT: ret i32 [[C]]
+;
+ %a = mul i32 %y, 10
+ %b = sub i32 %x, %y
+ %c = add i32 %b, %a
+ ret i32 %c
+}
+
+define i32 @sub_plus_mul4(i32 %x, i32 %y) {
+; CHECK-LABEL: @sub_plus_mul4(
+; CHECK-NEXT: [[A:%.*]] = mul i32 [[Y:%.*]], -10
+; CHECK-NEXT: [[B:%.*]] = sub i32 [[X:%.*]], [[Y]]
+; CHECK-NEXT: [[C:%.*]] = add i32 [[B]], [[A]]
+; CHECK-NEXT: ret i32 [[C]]
+;
+ %a = mul i32 %y, -10
+ %b = sub i32 %x, %y
+ %c = add i32 %b, %a
+ ret i32 %c
+}
+
+define <2 x i8> @sub_plus_mul_splat(<2 x i8> %x, <2 x i8> %y) {
+; CHECK-LABEL: @sub_plus_mul_splat(
+; CHECK-NEXT: [[A:%.*]] = sub <2 x i8> [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT: [[B:%.*]] = mul <2 x i8> [[Y]], splat (i8 7)
+; CHECK-NEXT: [[C:%.*]] = add <2 x i8> [[A]], [[B]]
+; CHECK-NEXT: ret <2 x i8> [[C]]
+;
+ %a = sub <2 x i8> %x, %y
+ %b = mul <2 x i8> %y, splat(i8 7)
+ %c = add <2 x i8> %a, %b
+ ret <2 x i8> %c
+}
+
+;; <- Negative Tests ->
+
+;; mul does not work if it is a powerof2, because it results in worse codegen
+define i32 @neg_sub_plus_mul_pow2(i32 %x, i32 %y) {
+; CHECK-LABEL: @neg_sub_plus_mul_pow2(
+; CHECK-NEXT: [[A:%.*]] = sub i32 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT: [[B:%.*]] = shl i32 [[Y]], 3
+; CHECK-NEXT: [[C:%.*]] = add i32 [[A]], [[B]]
+; CHECK-NEXT: ret i32 [[C]]
+;
+ %a = sub i32 %x, %y
+ %b = mul i32 %y, 8
+ %c = add i32 %a, %b
+ ret i32 %c
+}
+
+define <2 x i8> @sub_plus_mul_splat_shl(<2 x i8> %x, <2 x i8> %y) {
+; CHECK-LABEL: @sub_plus_mul_splat_shl(
+; CHECK-NEXT: [[A:%.*]] = sub <2 x i8> [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT: [[B:%.*]] = shl <2 x i8> [[Y]], splat (i8 3)
+; CHECK-NEXT: [[C:%.*]] = add <2 x i8> [[A]], [[B]]
+; CHECK-NEXT: ret <2 x i8> [[C]]
+;
+ %a = sub <2 x i8> %x, %y
+ %b = mul <2 x i8> %y, splat(i8 8)
+ %c = add <2 x i8> %a, %b
+ ret <2 x i8> %c
+}
+
+define i32 @neg_sub_plus_mul_multiuse(i32 %x, i32 %y) {
+; CHECK-LABEL: @neg_sub_plus_mul_multiuse(
+; CHECK-NEXT: [[A:%.*]] = sub i32 [[X:%.*]], [[Y:%.*]]
+; CHECK-NEXT: [[B:%.*]] = mul i32 [[Y]], 7
+; CHECK-NEXT: call void @use(i32 [[B]])
+; CHECK-NEXT: [[C:%.*]] = add i32 [[A]], [[B]]
+; CHECK-NEXT: ret i32 [[C]]
+;
+ %a = sub i32 %x, %y
+ %b = mul i32 %y, 7
+ call void @use(i32 %b)
+ %c = add i32 %a, %b
+ ret i32 %c
+}
>From 8e48b77c7274c012bd85714055d5fdffb50f1e6b Mon Sep 17 00:00:00 2001
From: Rose <gfunni234 at gmail.com>
Date: Tue, 26 Nov 2024 10:15:17 -0500
Subject: [PATCH 2/2] [InstCombine] Fold X - Y + Y * C -> X + Y * (C - 1)
Alive2 Proof:
https://alive2.llvm.org/ce/z/gS9Wb7
This is based on and closes https://github.com/llvm/llvm-project/issues/108451
Note that no nsw or nuw saving works because they all result in poison or undef mismatches.
---
.../InstCombine/InstCombineAddSub.cpp | 12 +++++++
.../InstCombine/addsub-constant-folding.ll | 31 ++++++++-----------
2 files changed, 25 insertions(+), 18 deletions(-)
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp
index 6fe96935818531..b127f88090e289 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp
@@ -1612,6 +1612,18 @@ Instruction *InstCombinerImpl::visitAdd(BinaryOperator &I) {
Value *Sub = Builder.CreateSub(B, A, "reass.sub");
return BinaryOperator::CreateAdd(Sub, C1);
}
+
+ // A - B + B * C -> A + B * (C - 1)
+ const APInt *C;
+ if (((match(LHS, m_Sub(m_Value(A), m_Value(B))) &&
+ match(RHS, m_Mul(m_Specific(B), m_APInt(C)))) ||
+ (match(RHS, m_Sub(m_Value(A), m_Value(B))) &&
+ match(LHS, m_Mul(m_Specific(B), m_APInt(C))))) &&
+ LHS->hasOneUse() && RHS->hasOneUse()) {
+ Value *Mul =
+ Builder.CreateMul(B, ConstantInt::get(RHS->getType(), *C - 1));
+ return BinaryOperator::CreateAdd(A, Mul);
+ }
}
// X % C0 + (( X / C0 ) % C1) * C0 => X % (C0 * C1)
diff --git a/llvm/test/Transforms/InstCombine/addsub-constant-folding.ll b/llvm/test/Transforms/InstCombine/addsub-constant-folding.ll
index 7c3d61260cf5cf..62600b254e9944 100644
--- a/llvm/test/Transforms/InstCombine/addsub-constant-folding.ll
+++ b/llvm/test/Transforms/InstCombine/addsub-constant-folding.ll
@@ -753,9 +753,8 @@ define i8 @sub_from_constant_extra_use(i8 %x, i8 %y) {
define i32 @sub_plus_mul(i32 %x, i32 %y) {
; CHECK-LABEL: @sub_plus_mul(
-; CHECK-NEXT: [[A:%.*]] = sub i32 [[X:%.*]], [[Y:%.*]]
-; CHECK-NEXT: [[B:%.*]] = mul i32 [[Y]], 10
-; CHECK-NEXT: [[C:%.*]] = add i32 [[A]], [[B]]
+; CHECK-NEXT: [[B:%.*]] = mul i32 [[Y:%.*]], 9
+; CHECK-NEXT: [[C:%.*]] = add i32 [[A:%.*]], [[B]]
; CHECK-NEXT: ret i32 [[C]]
;
%a = sub i32 %x, %y
@@ -766,9 +765,8 @@ define i32 @sub_plus_mul(i32 %x, i32 %y) {
define i32 @sub_plus_mul_2(i32 %x, i32 %y) {
; CHECK-LABEL: @sub_plus_mul_2(
-; CHECK-NEXT: [[A:%.*]] = sub i32 [[X:%.*]], [[Y:%.*]]
-; CHECK-NEXT: [[B:%.*]] = mul i32 [[Y]], -10
-; CHECK-NEXT: [[C:%.*]] = add i32 [[A]], [[B]]
+; CHECK-NEXT: [[B:%.*]] = mul i32 [[Y:%.*]], -11
+; CHECK-NEXT: [[C:%.*]] = add i32 [[A:%.*]], [[B]]
; CHECK-NEXT: ret i32 [[C]]
;
%a = sub i32 %x, %y
@@ -779,9 +777,8 @@ define i32 @sub_plus_mul_2(i32 %x, i32 %y) {
define i32 @sub_plus_mul3(i32 %x, i32 %y) {
; CHECK-LABEL: @sub_plus_mul3(
-; CHECK-NEXT: [[A:%.*]] = mul i32 [[Y:%.*]], 10
-; CHECK-NEXT: [[B:%.*]] = sub i32 [[X:%.*]], [[Y]]
-; CHECK-NEXT: [[C:%.*]] = add i32 [[B]], [[A]]
+; CHECK-NEXT: [[A:%.*]] = mul i32 [[Y:%.*]], 9
+; CHECK-NEXT: [[C:%.*]] = add i32 [[B:%.*]], [[A]]
; CHECK-NEXT: ret i32 [[C]]
;
%a = mul i32 %y, 10
@@ -792,9 +789,8 @@ define i32 @sub_plus_mul3(i32 %x, i32 %y) {
define i32 @sub_plus_mul4(i32 %x, i32 %y) {
; CHECK-LABEL: @sub_plus_mul4(
-; CHECK-NEXT: [[A:%.*]] = mul i32 [[Y:%.*]], -10
-; CHECK-NEXT: [[B:%.*]] = sub i32 [[X:%.*]], [[Y]]
-; CHECK-NEXT: [[C:%.*]] = add i32 [[B]], [[A]]
+; CHECK-NEXT: [[A:%.*]] = mul i32 [[Y:%.*]], -11
+; CHECK-NEXT: [[C:%.*]] = add i32 [[B:%.*]], [[A]]
; CHECK-NEXT: ret i32 [[C]]
;
%a = mul i32 %y, -10
@@ -805,9 +801,8 @@ define i32 @sub_plus_mul4(i32 %x, i32 %y) {
define <2 x i8> @sub_plus_mul_splat(<2 x i8> %x, <2 x i8> %y) {
; CHECK-LABEL: @sub_plus_mul_splat(
-; CHECK-NEXT: [[A:%.*]] = sub <2 x i8> [[X:%.*]], [[Y:%.*]]
-; CHECK-NEXT: [[B:%.*]] = mul <2 x i8> [[Y]], splat (i8 7)
-; CHECK-NEXT: [[C:%.*]] = add <2 x i8> [[A]], [[B]]
+; CHECK-NEXT: [[B:%.*]] = mul <2 x i8> [[Y:%.*]], splat (i8 6)
+; CHECK-NEXT: [[C:%.*]] = add <2 x i8> [[A:%.*]], [[B]]
; CHECK-NEXT: ret <2 x i8> [[C]]
;
%a = sub <2 x i8> %x, %y
@@ -818,7 +813,7 @@ define <2 x i8> @sub_plus_mul_splat(<2 x i8> %x, <2 x i8> %y) {
;; <- Negative Tests ->
-;; mul does not work if it is a powerof2, because it results in worse codegen
+;; mul does not work if it is a power of 2, because it results in worse codegen
define i32 @neg_sub_plus_mul_pow2(i32 %x, i32 %y) {
; CHECK-LABEL: @neg_sub_plus_mul_pow2(
; CHECK-NEXT: [[A:%.*]] = sub i32 [[X:%.*]], [[Y:%.*]]
@@ -832,8 +827,8 @@ define i32 @neg_sub_plus_mul_pow2(i32 %x, i32 %y) {
ret i32 %c
}
-define <2 x i8> @sub_plus_mul_splat_shl(<2 x i8> %x, <2 x i8> %y) {
-; CHECK-LABEL: @sub_plus_mul_splat_shl(
+define <2 x i8> @neg_sub_plus_mul_splat_shl(<2 x i8> %x, <2 x i8> %y) {
+; CHECK-LABEL: @neg_sub_plus_mul_splat_shl(
; CHECK-NEXT: [[A:%.*]] = sub <2 x i8> [[X:%.*]], [[Y:%.*]]
; CHECK-NEXT: [[B:%.*]] = shl <2 x i8> [[Y]], splat (i8 3)
; CHECK-NEXT: [[C:%.*]] = add <2 x i8> [[A]], [[B]]
More information about the llvm-commits
mailing list