[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