[llvm] [InstCombine] Fold `(X & C1) | C2` into `X & (C1 | C2)` iff `(X & C2) == C2` (PR #76470)
Yingwei Zheng via llvm-commits
llvm-commits at lists.llvm.org
Wed Dec 27 13:05:20 PST 2023
https://github.com/dtcxzyw created https://github.com/llvm/llvm-project/pull/76470
Alive2: https://alive2.llvm.org/ce/z/VKJYaS
>From 1a2a4983603367c32c22a2d1b546a856b49b3cd1 Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Thu, 28 Dec 2023 05:00:10 +0800
Subject: [PATCH 1/2] [InstCombine] Add pre-commit tests. NFC.
---
llvm/test/Transforms/InstCombine/or.ll | 97 ++++++++++++++++++++++++++
1 file changed, 97 insertions(+)
diff --git a/llvm/test/Transforms/InstCombine/or.ll b/llvm/test/Transforms/InstCombine/or.ll
index 805546099398b4..65eee503a0eb00 100644
--- a/llvm/test/Transforms/InstCombine/or.ll
+++ b/llvm/test/Transforms/InstCombine/or.ll
@@ -1636,3 +1636,100 @@ define i32 @assoc_cast_assoc_disjoint(i16 %x) {
%c = or disjoint i32 %b, 65536
ret i32 %c
}
+
+; (X & C1) | C2 -> X & (C1 | C2) iff (X & C2) == C2
+define i32 @test_or_and_disjoint(i32 %a) {
+; CHECK-LABEL: @test_or_and_disjoint(
+; CHECK-NEXT: [[A0:%.*]] = and i32 [[A:%.*]], 24
+; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[A0]], 8
+; CHECK-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
+; CHECK: if.then:
+; CHECK-NEXT: [[A1:%.*]] = and i32 [[A]], 7
+; CHECK-NEXT: [[A2:%.*]] = or disjoint i32 [[A1]], 8
+; CHECK-NEXT: ret i32 [[A2]]
+; CHECK: if.else:
+; CHECK-NEXT: ret i32 0
+;
+ %a0 = and i32 %a, 24
+ %cmp = icmp eq i32 %a0, 8
+ br i1 %cmp, label %if.then, label %if.else
+if.then:
+ %a1 = and i32 %a, 7
+ %a2 = or i32 %a1, 8
+ ret i32 %a2
+if.else:
+ ret i32 0
+}
+
+define i32 @test_or_and_mixed(i32 %a) {
+; CHECK-LABEL: @test_or_and_mixed(
+; CHECK-NEXT: [[A0:%.*]] = and i32 [[A:%.*]], 27
+; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[A0]], 11
+; CHECK-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
+; CHECK: if.then:
+; CHECK-NEXT: [[A1:%.*]] = and i32 [[A]], 4
+; CHECK-NEXT: [[A2:%.*]] = or disjoint i32 [[A1]], 11
+; CHECK-NEXT: ret i32 [[A2]]
+; CHECK: if.else:
+; CHECK-NEXT: ret i32 0
+;
+ %a0 = and i32 %a, 27
+ %cmp = icmp eq i32 %a0, 11
+ br i1 %cmp, label %if.then, label %if.else
+if.then:
+ %a1 = and i32 %a, 7
+ %a2 = or i32 %a1, 11
+ ret i32 %a2
+if.else:
+ ret i32 0
+}
+
+; Negative tests
+
+define i32 @test_or_and_disjoint_fail(i32 %a) {
+; CHECK-LABEL: @test_or_and_disjoint_fail(
+; CHECK-NEXT: [[A0:%.*]] = and i32 [[A:%.*]], 24
+; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[A0]], 16
+; CHECK-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
+; CHECK: if.then:
+; CHECK-NEXT: [[A1:%.*]] = and i32 [[A]], 7
+; CHECK-NEXT: [[A2:%.*]] = or disjoint i32 [[A1]], 8
+; CHECK-NEXT: ret i32 [[A2]]
+; CHECK: if.else:
+; CHECK-NEXT: ret i32 0
+;
+ %a0 = and i32 %a, 24
+ %cmp = icmp eq i32 %a0, 16
+ br i1 %cmp, label %if.then, label %if.else
+if.then:
+ %a1 = and i32 %a, 7
+ %a2 = or i32 %a1, 8
+ ret i32 %a2
+if.else:
+ ret i32 0
+}
+
+define i32 @test_or_and_disjoint_multiuse(i32 %a) {
+; CHECK-LABEL: @test_or_and_disjoint_multiuse(
+; CHECK-NEXT: [[A0:%.*]] = and i32 [[A:%.*]], 24
+; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[A0]], 8
+; CHECK-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
+; CHECK: if.then:
+; CHECK-NEXT: [[A1:%.*]] = and i32 [[A]], 7
+; CHECK-NEXT: call void @use(i32 [[A1]])
+; CHECK-NEXT: [[A2:%.*]] = or disjoint i32 [[A1]], 8
+; CHECK-NEXT: ret i32 [[A2]]
+; CHECK: if.else:
+; CHECK-NEXT: ret i32 0
+;
+ %a0 = and i32 %a, 24
+ %cmp = icmp eq i32 %a0, 8
+ br i1 %cmp, label %if.then, label %if.else
+if.then:
+ %a1 = and i32 %a, 7
+ call void @use(i32 %a1)
+ %a2 = or i32 %a1, 8
+ ret i32 %a2
+if.else:
+ ret i32 0
+}
>From b96af27a97818b41a127113f4d4313aa704b2469 Mon Sep 17 00:00:00 2001
From: Yingwei Zheng <dtcxzyw2333 at gmail.com>
Date: Thu, 28 Dec 2023 05:02:16 +0800
Subject: [PATCH 2/2] [InstCombine] Fold `(X & C1) | C2` into `X & (C1 | C2)`
iff `(X & C2) == C2`
---
llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp | 8 ++++++++
llvm/test/Transforms/InstCombine/or.ll | 6 ++----
2 files changed, 10 insertions(+), 4 deletions(-)
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
index 63b1e0f64a8824..6958418ba7f3fa 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
@@ -3872,6 +3872,14 @@ Instruction *InstCombinerImpl::visitOr(BinaryOperator &I) {
}
}
+ // (X & C1) | C2 -> X & (C1 | C2) iff (X & C2) == C2
+ if (match(Op0, m_OneUse(m_And(m_Value(X), m_APInt(C1)))) &&
+ match(Op1, m_APInt(C2))) {
+ KnownBits KnownX = computeKnownBits(X, /*Depth*/ 0, &I);
+ if ((KnownX.One & *C2) == *C2)
+ return BinaryOperator::CreateAnd(X, ConstantInt::get(Ty, *C1 | *C2));
+ }
+
return nullptr;
}
diff --git a/llvm/test/Transforms/InstCombine/or.ll b/llvm/test/Transforms/InstCombine/or.ll
index 65eee503a0eb00..010ef239744188 100644
--- a/llvm/test/Transforms/InstCombine/or.ll
+++ b/llvm/test/Transforms/InstCombine/or.ll
@@ -1644,8 +1644,7 @@ define i32 @test_or_and_disjoint(i32 %a) {
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[A0]], 8
; CHECK-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
; CHECK: if.then:
-; CHECK-NEXT: [[A1:%.*]] = and i32 [[A]], 7
-; CHECK-NEXT: [[A2:%.*]] = or disjoint i32 [[A1]], 8
+; CHECK-NEXT: [[A2:%.*]] = and i32 [[A]], 15
; CHECK-NEXT: ret i32 [[A2]]
; CHECK: if.else:
; CHECK-NEXT: ret i32 0
@@ -1667,8 +1666,7 @@ define i32 @test_or_and_mixed(i32 %a) {
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[A0]], 11
; CHECK-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
; CHECK: if.then:
-; CHECK-NEXT: [[A1:%.*]] = and i32 [[A]], 4
-; CHECK-NEXT: [[A2:%.*]] = or disjoint i32 [[A1]], 11
+; CHECK-NEXT: [[A2:%.*]] = and i32 [[A]], 15
; CHECK-NEXT: ret i32 [[A2]]
; CHECK: if.else:
; CHECK-NEXT: ret i32 0
More information about the llvm-commits
mailing list