[llvm] [InstCombine] Change (add x, c) to (xor x, c) (PR #75129)
Fujun Han via llvm-commits
llvm-commits at lists.llvm.org
Thu Dec 14 04:00:48 PST 2023
https://github.com/Peter9606 updated https://github.com/llvm/llvm-project/pull/75129
>From f84e38579deda4d1f2b6c54b98bcb3617ed82bb6 Mon Sep 17 00:00:00 2001
From: Peter Han <fujun.han at iluvatar.com>
Date: Thu, 14 Dec 2023 13:48:58 +0800
Subject: [PATCH 1/2] [InstCombine][NFC]Pre-commit test for add-constant to
xor-constant.
Signed-off-by: Peter Han <fujun.han at iluvatar.com>
---
llvm/test/Transforms/InstCombine/and.ll | 48 ++++++++++++++++++++-
llvm/test/Transforms/InstCombine/pr75129.ll | 41 ++++++++++++++++++
2 files changed, 87 insertions(+), 2 deletions(-)
create mode 100644 llvm/test/Transforms/InstCombine/pr75129.ll
diff --git a/llvm/test/Transforms/InstCombine/and.ll b/llvm/test/Transforms/InstCombine/and.ll
index 79857f3efbc18b..b3ecd3c2b8dcb5 100644
--- a/llvm/test/Transforms/InstCombine/and.ll
+++ b/llvm/test/Transforms/InstCombine/and.ll
@@ -395,8 +395,8 @@ define i8 @test27(i8 %A) {
define i32 @ashr_lowmask(i32 %x) {
; CHECK-LABEL: @ashr_lowmask(
-; CHECK-NEXT: [[TMP1:%.*]] = lshr i32 [[X:%.*]], 24
-; CHECK-NEXT: ret i32 [[TMP1]]
+; CHECK-NEXT: [[A:%.*]] = lshr i32 [[X:%.*]], 24
+; CHECK-NEXT: ret i32 [[A]]
;
%a = ashr i32 %x, 24
%r = and i32 %a, 255
@@ -2711,3 +2711,47 @@ define i32 @canonicalize_and_sub_power2_or_zero_multiuse_nofold(i32 %x, i32 %y)
%and = and i32 %val, %p2
ret i32 %and
}
+
+define i32 @add_constant_equal_with_the_top_bit_of_demandedbits_pass(i32 %x) {
+; CHECK-LABEL: @add_constant_equal_with_the_top_bit_of_demandedbits_pass(
+; CHECK-NEXT: [[ADD:%.*]] = add i32 [[X:%.*]], 16
+; CHECK-NEXT: [[AND:%.*]] = and i32 [[ADD]], 24
+; CHECK-NEXT: ret i32 [[AND]]
+;
+ %add = add i32 %x, 16
+ %and = and i32 %add, 24
+ ret i32 %and
+}
+
+define <2 x i16> @add_constant_equal_with_the_top_bit_of_demandedbits_pass_vector(<2 x i16> %x) {
+; CHECK-LABEL: @add_constant_equal_with_the_top_bit_of_demandedbits_pass_vector(
+; CHECK-NEXT: [[ADD:%.*]] = add <2 x i16> [[X:%.*]], <i16 16, i16 16>
+; CHECK-NEXT: [[AND:%.*]] = and <2 x i16> [[ADD]], <i16 24, i16 24>
+; CHECK-NEXT: ret <2 x i16> [[AND]]
+;
+ %add = add <2 x i16> %x, <i16 16, i16 16>
+ %and = and <2 x i16> %add, <i16 24, i16 24>
+ ret <2 x i16> %and
+}
+
+define i32 @add_constant_equal_with_the_top_bit_of_demandedbits_fail1(i32 %x) {
+; CHECK-LABEL: @add_constant_equal_with_the_top_bit_of_demandedbits_fail1(
+; CHECK-NEXT: [[ADD:%.*]] = add i32 [[X:%.*]], 8
+; CHECK-NEXT: [[AND:%.*]] = and i32 [[ADD]], 24
+; CHECK-NEXT: ret i32 [[AND]]
+;
+ %add = add i32 %x, 8
+ %and = and i32 %add, 24
+ ret i32 %and
+}
+
+define i32 @add_constant_equal_with_the_top_bit_of_demandedbits_fail2(i32 %x) {
+; CHECK-LABEL: @add_constant_equal_with_the_top_bit_of_demandedbits_fail2(
+; CHECK-NEXT: [[ADD:%.*]] = add i32 [[X:%.*]], 24
+; CHECK-NEXT: [[AND:%.*]] = and i32 [[ADD]], 24
+; CHECK-NEXT: ret i32 [[AND]]
+;
+ %add = add i32 %x, 24
+ %and = and i32 %add, 24
+ ret i32 %and
+}
diff --git a/llvm/test/Transforms/InstCombine/pr75129.ll b/llvm/test/Transforms/InstCombine/pr75129.ll
new file mode 100644
index 00000000000000..c9e0fbc0ca0648
--- /dev/null
+++ b/llvm/test/Transforms/InstCombine/pr75129.ll
@@ -0,0 +1,41 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -passes=instcombine -S | FileCheck %s
+
+; Pattern:
+; (or (and (add x, half_c1), c3), (and x, c2))
+; IFF:
+; c1, c2, c3 is constant
+; c1 is pow2
+; c2 < c1
+; c3 == (c1 - 1) ^ c2
+; half_c1 == (lshr c1, 1)
+; (c1 >> 1) & c3 == (c1 >> 1)
+; x is known to be less than c1
+; Could be transformed into:
+; (xor x, half_c1)
+; The reason above transformation could be done is becase
+; in (and (add x, half_c1), c3), half_c1 equals the top bit
+; of the demanded mask indicated by (and ..., c3)
+
+define i16 @or_and_add_and() {
+; CHECK-LABEL: @or_and_add_and(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[X:%.*]] = call i16 @dummy(), !range [[RNG0:![0-9]+]]
+; CHECK-NEXT: [[ADD:%.*]] = add nuw nsw i16 [[X]], 32
+; CHECK-NEXT: [[AND1:%.*]] = and i16 [[ADD]], 48
+; CHECK-NEXT: [[AND2:%.*]] = and i16 [[X]], 15
+; CHECK-NEXT: [[OR:%.*]] = or disjoint i16 [[AND1]], [[AND2]]
+; CHECK-NEXT: ret i16 [[OR]]
+;
+entry:
+ %x = call i16 @dummy(), !range !0
+ %add = add i16 32, %x
+ %and1 = and i16 %add, 48
+ %and2 = and i16 %x, 15
+ %or = or i16 %and1, %and2
+ ret i16 %or
+}
+
+declare i16 @dummy()
+
+!0 = !{i16 0, i16 64}
>From 229586608bf86243327293611dcc49ba9518ba3a Mon Sep 17 00:00:00 2001
From: Peter Han <fujun.han at iluvatar.com>
Date: Thu, 14 Dec 2023 19:59:51 +0800
Subject: [PATCH 2/2] [InstCombine]Change (add x, c) to (xor x, c) iff c is
constant and c equals the top bit of the demanded bits.
Signed-off-by: Peter Han <fujun.han at iluvatar.com>
---
.../InstCombine/InstCombineSimplifyDemanded.cpp | 8 ++++++++
llvm/test/Transforms/InstCombine/and.ll | 8 ++++----
llvm/test/Transforms/InstCombine/pr75129.ll | 5 +----
3 files changed, 13 insertions(+), 8 deletions(-)
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp
index 046ce9d1207e8e..18d4c2dc308e2e 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp
@@ -552,6 +552,14 @@ Value *InstCombinerImpl::SimplifyDemandedUseBits(Value *V, APInt DemandedMask,
if (DemandedFromOps.isSubsetOf(LHSKnown.Zero))
return I->getOperand(1);
+ // (add X, C) --> (xor X, C) IFF C is equal to the top bit of the DemandMask
+ {
+ const APInt *C;
+ if (match(I->getOperand(1), m_APInt(C)) &&
+ C->isOneBitSet(DemandedMask.getActiveBits() - 1))
+ return Builder.CreateXor(I->getOperand(0), ConstantInt::get(VTy, *C));
+ }
+
// Otherwise just compute the known bits of the result.
bool NSW = cast<OverflowingBinaryOperator>(I)->hasNoSignedWrap();
Known = KnownBits::computeForAddSub(true, NSW, LHSKnown, RHSKnown);
diff --git a/llvm/test/Transforms/InstCombine/and.ll b/llvm/test/Transforms/InstCombine/and.ll
index b3ecd3c2b8dcb5..cb611764ec755b 100644
--- a/llvm/test/Transforms/InstCombine/and.ll
+++ b/llvm/test/Transforms/InstCombine/and.ll
@@ -2714,8 +2714,8 @@ define i32 @canonicalize_and_sub_power2_or_zero_multiuse_nofold(i32 %x, i32 %y)
define i32 @add_constant_equal_with_the_top_bit_of_demandedbits_pass(i32 %x) {
; CHECK-LABEL: @add_constant_equal_with_the_top_bit_of_demandedbits_pass(
-; CHECK-NEXT: [[ADD:%.*]] = add i32 [[X:%.*]], 16
-; CHECK-NEXT: [[AND:%.*]] = and i32 [[ADD]], 24
+; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[X:%.*]], 24
+; CHECK-NEXT: [[AND:%.*]] = xor i32 [[TMP1]], 16
; CHECK-NEXT: ret i32 [[AND]]
;
%add = add i32 %x, 16
@@ -2725,8 +2725,8 @@ define i32 @add_constant_equal_with_the_top_bit_of_demandedbits_pass(i32 %x) {
define <2 x i16> @add_constant_equal_with_the_top_bit_of_demandedbits_pass_vector(<2 x i16> %x) {
; CHECK-LABEL: @add_constant_equal_with_the_top_bit_of_demandedbits_pass_vector(
-; CHECK-NEXT: [[ADD:%.*]] = add <2 x i16> [[X:%.*]], <i16 16, i16 16>
-; CHECK-NEXT: [[AND:%.*]] = and <2 x i16> [[ADD]], <i16 24, i16 24>
+; CHECK-NEXT: [[TMP1:%.*]] = and <2 x i16> [[X:%.*]], <i16 24, i16 24>
+; CHECK-NEXT: [[AND:%.*]] = xor <2 x i16> [[TMP1]], <i16 16, i16 16>
; CHECK-NEXT: ret <2 x i16> [[AND]]
;
%add = add <2 x i16> %x, <i16 16, i16 16>
diff --git a/llvm/test/Transforms/InstCombine/pr75129.ll b/llvm/test/Transforms/InstCombine/pr75129.ll
index c9e0fbc0ca0648..c1912514b91bd1 100644
--- a/llvm/test/Transforms/InstCombine/pr75129.ll
+++ b/llvm/test/Transforms/InstCombine/pr75129.ll
@@ -21,10 +21,7 @@ define i16 @or_and_add_and() {
; CHECK-LABEL: @or_and_add_and(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[X:%.*]] = call i16 @dummy(), !range [[RNG0:![0-9]+]]
-; CHECK-NEXT: [[ADD:%.*]] = add nuw nsw i16 [[X]], 32
-; CHECK-NEXT: [[AND1:%.*]] = and i16 [[ADD]], 48
-; CHECK-NEXT: [[AND2:%.*]] = and i16 [[X]], 15
-; CHECK-NEXT: [[OR:%.*]] = or disjoint i16 [[AND1]], [[AND2]]
+; CHECK-NEXT: [[OR:%.*]] = xor i16 [[X]], 32
; CHECK-NEXT: ret i16 [[OR]]
;
entry:
More information about the llvm-commits
mailing list