[llvm] Fujun.han/instcombine or to xor (PR #75129)
Fujun Han via llvm-commits
llvm-commits at lists.llvm.org
Mon Dec 11 18:29:23 PST 2023
https://github.com/Peter9606 created https://github.com/llvm/llvm-project/pull/75129
Simplify a complex OR to XOR
Following pattern:
(or (and 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
can be simplified into:
(xor x, half_c)
Proof: https://alive2.llvm.org/ce/z/Lfax3w
>From 9e24bc338a94db28bc8f023babf403e2111757e2 Mon Sep 17 00:00:00 2001
From: Peter Han <fujun.han at iluvatar.com>
Date: Tue, 12 Dec 2023 08:21:07 +0800
Subject: [PATCH 1/2] [InstCombine][NFC]Pre-commit test for an OR pattern can
be simplified to XOR.
Signed-off-by: Peter Han <fujun.han at iluvatar.com>
---
...-and-add-constant-constant-and-constant.ll | 39 +++++++++++++++++++
1 file changed, 39 insertions(+)
create mode 100644 llvm/test/Transforms/InstCombine/or-and-add-constant-constant-and-constant.ll
diff --git a/llvm/test/Transforms/InstCombine/or-and-add-constant-constant-and-constant.ll b/llvm/test/Transforms/InstCombine/or-and-add-constant-constant-and-constant.ll
new file mode 100644
index 00000000000000..4de3ce9106ec37
--- /dev/null
+++ b/llvm/test/Transforms/InstCombine/or-and-add-constant-constant-and-constant.ll
@@ -0,0 +1,39 @@
+; 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)
+; Proof: https://alive2.llvm.org/ce/z/Lfax3w
+
+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 a5420c88891d511b7f3b6235ca220dfdc286c62a Mon Sep 17 00:00:00 2001
From: Peter Han <fujun.han at iluvatar.com>
Date: Tue, 12 Dec 2023 08:36:34 +0800
Subject: [PATCH 2/2] [InstCombine]Simplify a complex OR to XOR
Following pattern:
(or (and 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
can be simplified into:
(xor x, half_c)
Proof: https://alive2.llvm.org/ce/z/Lfax3w
Signed-off-by: Peter Han <fujun.han at iluvatar.com>
---
.../InstCombine/InstCombineAndOrXor.cpp | 22 ++++++++++++++++++-
...-and-add-constant-constant-and-constant.ll | 5 +----
2 files changed, 22 insertions(+), 5 deletions(-)
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
index 6002f599ca71ab..67ec4a1608169a 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
@@ -3343,6 +3343,27 @@ Instruction *InstCombinerImpl::visitOr(BinaryOperator &I) {
if (Instruction *X = foldComplexAndOrPatterns(I, Builder))
return X;
+ // Change (or (and (add x, half_c1), c3), (and x, c2)) to (xor x, half_c1),
+ // iff c1, c2, c3 is constant, and half_c1 = (lshr c1, 1), and c1 is pow2,
+ // and c2 < c1, and c3 == (c1 - 1) ^ c2, and (c1 >> 1) & c3 == (c1 >> 1) and x
+ // is known to be less than c1.
+ Type *Ty = I.getType();
+ if (Ty->isIntegerTy()) {
+ Value *X = nullptr;
+ const APInt *HalfC1 = nullptr, *C2 = nullptr, *C3 = nullptr;
+ if (match(&I,
+ m_c_Or(m_c_And(m_c_Add(m_Value(X), m_APInt(HalfC1)), m_APInt(C3)),
+ m_c_And(m_Value(X), m_APInt(C2))))) {
+ const APInt C1 = HalfC1->shl(1);
+ KnownBits KnownX = computeKnownBits(X, 0, nullptr);
+ if (C1.isPowerOf2() && C2->ult(C1) && (*C3 == (*C2 ^ (C1 - 1))) &&
+ ((*HalfC1 & *C3) == *HalfC1) && KnownX.getMaxValue().ult(C1)) {
+ Value *Xor = Builder.CreateXor(X, ConstantInt::get(Ty, *HalfC1));
+ return replaceInstUsesWith(I, Xor);
+ }
+ }
+ }
+
// (A&B)|(A&C) -> A&(B|C) etc
if (Value *V = foldUsingDistributiveLaws(I))
return replaceInstUsesWith(I, V);
@@ -3351,7 +3372,6 @@ Instruction *InstCombinerImpl::visitOr(BinaryOperator &I) {
return replaceInstUsesWith(I, V);
Value *Op0 = I.getOperand(0), *Op1 = I.getOperand(1);
- Type *Ty = I.getType();
if (Ty->isIntOrIntVectorTy(1)) {
if (auto *SI0 = dyn_cast<SelectInst>(Op0)) {
if (auto *R =
diff --git a/llvm/test/Transforms/InstCombine/or-and-add-constant-constant-and-constant.ll b/llvm/test/Transforms/InstCombine/or-and-add-constant-constant-and-constant.ll
index 4de3ce9106ec37..3e48f3c3f331b9 100644
--- a/llvm/test/Transforms/InstCombine/or-and-add-constant-constant-and-constant.ll
+++ b/llvm/test/Transforms/InstCombine/or-and-add-constant-constant-and-constant.ll
@@ -19,10 +19,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