[llvm] [InstCombine] fold add (or x, -2), x -> and (add x, -1), -2 (PR #230791)
Andreas Jonson via llvm-commits
llvm-commits at lists.llvm.org
Sat Oct 10 09:55:58 PDT 2026
https://github.com/andjo403 updated https://github.com/llvm/llvm-project/pull/230791
>From 33a464d389544c1c9979832b3b02781801fc63ad Mon Sep 17 00:00:00 2001
From: Andreas Jonson <andjo403 at hotmail.com>
Date: Sat, 10 Oct 2026 17:29:48 +0200
Subject: [PATCH 1/3] [InstCombine] Pre commit test (NFC)
---
llvm/test/Transforms/InstCombine/add.ll | 90 ++++++++++++++++++++++---
1 file changed, 80 insertions(+), 10 deletions(-)
diff --git a/llvm/test/Transforms/InstCombine/add.ll b/llvm/test/Transforms/InstCombine/add.ll
index 992cf69f3cba3..9a9001e466da2 100644
--- a/llvm/test/Transforms/InstCombine/add.ll
+++ b/llvm/test/Transforms/InstCombine/add.ll
@@ -4445,11 +4445,11 @@ define i32 @add_reduce_sqr_sum_not_one_use(i32 %a, i32 %b) {
define i32 @add_reduce_sqr_sum_not_one_use2(i32 %a, i32 %b) {
; CHECK-LABEL: @add_reduce_sqr_sum_not_one_use2(
-; CHECK-NEXT: [[A_SQ:%.*]] = mul nsw i32 [[A:%.*]], [[A:%.*]]
-; CHECK-NEXT: tail call void @fake_func(i32 [[A_SQ:%.*]])
-; CHECK-NEXT: [[AB:%.*]] = add i32 [[A:%.*]], [[B:%.*]]
-; CHECK-NEXT: [[AB_SQ:%.*]] = mul i32 [[AB:%.*]], [[AB:%.*]]
-; CHECK-NEXT: ret i32 [[AB_SQ:%.*]]
+; CHECK-NEXT: [[A_SQ:%.*]] = mul nsw i32 [[A:%.*]], [[A]]
+; CHECK-NEXT: tail call void @fake_func(i32 [[A_SQ]])
+; CHECK-NEXT: [[AB:%.*]] = add i32 [[A]], [[B:%.*]]
+; CHECK-NEXT: [[AB_SQ:%.*]] = mul i32 [[AB]], [[AB]]
+; CHECK-NEXT: ret i32 [[AB_SQ]]
;
%a_sq = mul nsw i32 %a, %a
%two_a = shl i32 %a, 1
@@ -4482,11 +4482,11 @@ define i32 @add_reduce_sqr_sum_order2_not_one_use(i32 %a, i32 %b) {
define i32 @add_reduce_sqr_sum_order2_not_one_use2(i32 %a, i32 %b) {
; CHECK-LABEL: @add_reduce_sqr_sum_order2_not_one_use2(
-; CHECK-NEXT: [[A_SQ:%.*]] = mul nsw i32 [[A:%.*]], [[A:%.*]]
-; CHECK-NEXT: tail call void @fake_func(i32 [[A_SQ:%.*]])
-; CHECK-NEXT: [[AB:%.*]] = add i32 [[A:%.*]], [[B:%.*]]
-; CHECK-NEXT: [[AB_SQ:%.*]] = mul i32 [[AB:%.*]], [[AB:%.*]]
-; CHECK-NEXT: ret i32 [[AB_SQ:%.*]]
+; CHECK-NEXT: [[A_SQ:%.*]] = mul nsw i32 [[A:%.*]], [[A]]
+; CHECK-NEXT: tail call void @fake_func(i32 [[A_SQ]])
+; CHECK-NEXT: [[AB:%.*]] = add i32 [[A]], [[B:%.*]]
+; CHECK-NEXT: [[AB_SQ:%.*]] = mul i32 [[AB]], [[AB]]
+; CHECK-NEXT: ret i32 [[AB_SQ]]
;
%a_sq = mul nsw i32 %a, %a
%twoa = mul i32 %a, 2
@@ -5330,3 +5330,73 @@ define i32 @zext_add_no_fold_symmetric(i8 %x) {
%r = add i32 %z, -4
ret i32 %r
}
+
+define i8 @add_or_add(i8 %x) {
+; CHECK-LABEL: @add_or_add(
+; CHECK-NEXT: [[ADD:%.*]] = add i8 [[X:%.*]], 1
+; CHECK-NEXT: [[OR:%.*]] = or i8 [[ADD]], -2
+; CHECK-NEXT: [[RET:%.*]] = add i8 [[OR]], [[ADD]]
+; CHECK-NEXT: ret i8 [[RET]]
+;
+ %add = add i8 %x, 1
+ %or = or i8 %add, -2
+ %ret = add i8 %or, %add
+ ret i8 %ret
+}
+
+define i8 @add_or(i8 %x) {
+; CHECK-LABEL: @add_or(
+; CHECK-NEXT: [[OR:%.*]] = or i8 [[X:%.*]], -2
+; CHECK-NEXT: [[RET:%.*]] = add i8 [[OR]], [[X]]
+; CHECK-NEXT: ret i8 [[RET]]
+;
+ %or = or i8 %x, -2
+ %ret = add i8 %or, %x
+ ret i8 %ret
+}
+
+define i8 @add_or_commuted(i8 %x) {
+; CHECK-LABEL: @add_or_commuted(
+; CHECK-NEXT: [[OR:%.*]] = or i8 [[X:%.*]], -2
+; CHECK-NEXT: [[RET:%.*]] = add i8 [[X]], [[OR]]
+; CHECK-NEXT: ret i8 [[RET]]
+;
+ %or = or i8 %x, -2
+ %ret = add i8 %x, %or
+ ret i8 %ret
+}
+
+define <2 x i8> @add_or_vec(<2 x i8> %x) {
+; CHECK-LABEL: @add_or_vec(
+; CHECK-NEXT: [[OR:%.*]] = or <2 x i8> [[X:%.*]], splat (i8 -2)
+; CHECK-NEXT: [[RET:%.*]] = add <2 x i8> [[OR]], [[X]]
+; CHECK-NEXT: ret <2 x i8> [[RET]]
+;
+ %or = or <2 x i8> %x, <i8 -2, i8 -2>
+ %ret = add <2 x i8> %or, %x
+ ret <2 x i8> %ret
+}
+
+define i8 @neg_add_or_multi_use(i8 %x) {
+; CHECK-LABEL: @neg_add_or_multi_use(
+; CHECK-NEXT: [[OR:%.*]] = or i8 [[X:%.*]], -2
+; CHECK-NEXT: call void @use(i8 [[OR]])
+; CHECK-NEXT: [[RET:%.*]] = add i8 [[OR]], [[X]]
+; CHECK-NEXT: ret i8 [[RET]]
+;
+ %or = or i8 %x, -2
+ call void @use(i8 %or)
+ %ret = add i8 %or, %x
+ ret i8 %ret
+}
+
+define i8 @neg_add_or(i8 %x) {
+; CHECK-LABEL: @neg_add_or(
+; CHECK-NEXT: [[OR:%.*]] = or i8 [[X:%.*]], -4
+; CHECK-NEXT: [[RET:%.*]] = add i8 [[OR]], [[X]]
+; CHECK-NEXT: ret i8 [[RET]]
+;
+ %or = or i8 %x, -4
+ %ret = add i8 %or, %x
+ ret i8 %ret
+}
>From 95dde2aacb30a534c21bc8d9df7bdc6dea10f8f7 Mon Sep 17 00:00:00 2001
From: Andreas Jonson <andjo403 at hotmail.com>
Date: Sat, 10 Oct 2026 17:36:36 +0200
Subject: [PATCH 2/3] [InstCombine] fold add (or x, -2), x -> and (add x, -1),
-2
---
.../Transforms/InstCombine/InstCombineAddSub.cpp | 9 +++++++++
llvm/test/Transforms/InstCombine/add.ll | 16 +++++++---------
2 files changed, 16 insertions(+), 9 deletions(-)
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp
index 3ebcbe44c4c3d..cd5725db552a9 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp
@@ -2050,6 +2050,15 @@ Instruction *InstCombinerImpl::visitAdd(BinaryOperator &I) {
if (Instruction *Res = foldDivCeil(I))
return Res;
+ APInt NegTwo(Ty->getScalarSizeInBits(), -2, /*isSigned=*/true);
+ if (match(&I, m_c_BinOp(m_OneUse(m_Or(m_Value(A), m_SpecificInt(NegTwo))),
+ m_Deferred(A)))) {
+ Value *Ret = Builder.CreateAdd(
+ A, ConstantInt::get(
+ Ty, APInt(Ty->getScalarSizeInBits(), -1, /*isSigned=*/true)));
+ return BinaryOperator::CreateAnd(Ret, ConstantInt::get(Ty, NegTwo));
+ }
+
// Re-enqueue users of the induction variable of add recurrence if we infer
// new nuw/nsw flags.
if (Changed) {
diff --git a/llvm/test/Transforms/InstCombine/add.ll b/llvm/test/Transforms/InstCombine/add.ll
index 9a9001e466da2..1f7f5ef53f1d4 100644
--- a/llvm/test/Transforms/InstCombine/add.ll
+++ b/llvm/test/Transforms/InstCombine/add.ll
@@ -5333,9 +5333,7 @@ define i32 @zext_add_no_fold_symmetric(i8 %x) {
define i8 @add_or_add(i8 %x) {
; CHECK-LABEL: @add_or_add(
-; CHECK-NEXT: [[ADD:%.*]] = add i8 [[X:%.*]], 1
-; CHECK-NEXT: [[OR:%.*]] = or i8 [[ADD]], -2
-; CHECK-NEXT: [[RET:%.*]] = add i8 [[OR]], [[ADD]]
+; CHECK-NEXT: [[RET:%.*]] = and i8 [[X:%.*]], -2
; CHECK-NEXT: ret i8 [[RET]]
;
%add = add i8 %x, 1
@@ -5346,8 +5344,8 @@ define i8 @add_or_add(i8 %x) {
define i8 @add_or(i8 %x) {
; CHECK-LABEL: @add_or(
-; CHECK-NEXT: [[OR:%.*]] = or i8 [[X:%.*]], -2
-; CHECK-NEXT: [[RET:%.*]] = add i8 [[OR]], [[X]]
+; CHECK-NEXT: [[TMP1:%.*]] = add i8 [[X:%.*]], -1
+; CHECK-NEXT: [[RET:%.*]] = and i8 [[TMP1]], -2
; CHECK-NEXT: ret i8 [[RET]]
;
%or = or i8 %x, -2
@@ -5357,8 +5355,8 @@ define i8 @add_or(i8 %x) {
define i8 @add_or_commuted(i8 %x) {
; CHECK-LABEL: @add_or_commuted(
-; CHECK-NEXT: [[OR:%.*]] = or i8 [[X:%.*]], -2
-; CHECK-NEXT: [[RET:%.*]] = add i8 [[X]], [[OR]]
+; CHECK-NEXT: [[TMP1:%.*]] = add i8 [[X:%.*]], -1
+; CHECK-NEXT: [[RET:%.*]] = and i8 [[TMP1]], -2
; CHECK-NEXT: ret i8 [[RET]]
;
%or = or i8 %x, -2
@@ -5368,8 +5366,8 @@ define i8 @add_or_commuted(i8 %x) {
define <2 x i8> @add_or_vec(<2 x i8> %x) {
; CHECK-LABEL: @add_or_vec(
-; CHECK-NEXT: [[OR:%.*]] = or <2 x i8> [[X:%.*]], splat (i8 -2)
-; CHECK-NEXT: [[RET:%.*]] = add <2 x i8> [[OR]], [[X]]
+; CHECK-NEXT: [[TMP1:%.*]] = add <2 x i8> [[X:%.*]], splat (i8 -1)
+; CHECK-NEXT: [[RET:%.*]] = and <2 x i8> [[TMP1]], splat (i8 -2)
; CHECK-NEXT: ret <2 x i8> [[RET]]
;
%or = or <2 x i8> %x, <i8 -2, i8 -2>
>From ee43d9360282c92f68a716b02ffb1e3189831e18 Mon Sep 17 00:00:00 2001
From: Andreas Jonson <andjo403 at hotmail.com>
Date: Sat, 10 Oct 2026 18:55:44 +0200
Subject: [PATCH 3/3] fixup! [InstCombine] fold add (or x, -2), x -> and (add
x, -1), -2
---
llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp | 1 +
1 file changed, 1 insertion(+)
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp
index cd5725db552a9..010b4084c65d8 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp
@@ -2050,6 +2050,7 @@ Instruction *InstCombinerImpl::visitAdd(BinaryOperator &I) {
if (Instruction *Res = foldDivCeil(I))
return Res;
+ // (A | -2) + A -> (A - 1) & -2
APInt NegTwo(Ty->getScalarSizeInBits(), -2, /*isSigned=*/true);
if (match(&I, m_c_BinOp(m_OneUse(m_Or(m_Value(A), m_SpecificInt(NegTwo))),
m_Deferred(A)))) {
More information about the llvm-commits
mailing list