[llvm] 77f75b4 - [InstCombine] Extend `(icmp eq/ne (and Z, X), (and Z, Y))` folds
Noah Goldstein via llvm-commits
llvm-commits at lists.llvm.org
Mon Jun 10 11:00:41 PDT 2024
Author: Noah Goldstein
Date: 2024-06-10T13:00:28-05:00
New Revision: 77f75b45fd8a4bbc061e85a4432c23b64ca7d4f2
URL: https://github.com/llvm/llvm-project/commit/77f75b45fd8a4bbc061e85a4432c23b64ca7d4f2
DIFF: https://github.com/llvm/llvm-project/commit/77f75b45fd8a4bbc061e85a4432c23b64ca7d4f2.diff
LOG: [InstCombine] Extend `(icmp eq/ne (and Z, X), (and Z, Y))` folds
Two ways to relaxed:
1) Only require one of the `and` ops to be single-use if both `X`
and `Y` are constant.
2) Special case, if `X ^ Y` is a negative power of 2, then
`Z ^ NegP2 ==/!= 0` will fold to `Z u</u>= -NegP2` which
creates no additional instructions so fold irrelivant of
use counts.
Closes #94867
Added:
Modified:
llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
llvm/test/Transforms/InstCombine/and-compare.ll
Removed:
################################################################################
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
index 3fce4a3c20b33..34b0f8b860497 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
@@ -5549,8 +5549,8 @@ Instruction *InstCombinerImpl::foldICmpEquality(ICmpInst &I) {
}
// (X&Z) == (Y&Z) -> (X^Y) & Z == 0
- if (match(Op0, m_OneUse(m_And(m_Value(A), m_Value(B)))) &&
- match(Op1, m_OneUse(m_And(m_Value(C), m_Value(D))))) {
+ if (match(Op0, m_And(m_Value(A), m_Value(B))) &&
+ match(Op1, m_And(m_Value(C), m_Value(D)))) {
Value *X = nullptr, *Y = nullptr, *Z = nullptr;
if (A == C) {
@@ -5571,10 +5571,26 @@ Instruction *InstCombinerImpl::foldICmpEquality(ICmpInst &I) {
Z = B;
}
- if (X) { // Build (X^Y) & Z
- Op1 = Builder.CreateXor(X, Y);
- Op1 = Builder.CreateAnd(Op1, Z);
- return new ICmpInst(Pred, Op1, Constant::getNullValue(Op1->getType()));
+ if (X) {
+ // If X^Y is a negative power of two, then `icmp eq/ne (Z & NegP2), 0`
+ // will fold to `icmp ult/uge Z, -NegP2` incurringb no additional
+ // instructions.
+ const APInt *C0, *C1;
+ bool XorIsNegP2 = match(X, m_APInt(C0)) && match(Y, m_APInt(C1)) &&
+ (*C0 ^ *C1).isNegatedPowerOf2();
+
+ // If either Op0/Op1 are both one use or X^Y will constant fold and one of
+ // Op0/Op1 are one use, proceed. In those cases we are instruction neutral
+ // but `icmp eq/ne A, 0` is easier to analyze than `icmp eq/ne A, B`.
+ int UseCnt =
+ int(Op0->hasOneUse()) + int(Op1->hasOneUse()) +
+ (int(match(X, m_ImmConstant()) && match(Y, m_ImmConstant())));
+ if (XorIsNegP2 || UseCnt >= 2) {
+ // Build (X^Y) & Z
+ Op1 = Builder.CreateXor(X, Y);
+ Op1 = Builder.CreateAnd(Op1, Z);
+ return new ICmpInst(Pred, Op1, Constant::getNullValue(Op1->getType()));
+ }
}
}
diff --git a/llvm/test/Transforms/InstCombine/and-compare.ll b/llvm/test/Transforms/InstCombine/and-compare.ll
index 3f714b3640492..5a9767a64a2ce 100644
--- a/llvm/test/Transforms/InstCombine/and-compare.ll
+++ b/llvm/test/Transforms/InstCombine/and-compare.ll
@@ -83,7 +83,7 @@ define i1 @test_ne_cp2(i8 %x, i8 %yy) {
; CHECK-NEXT: [[AND_X_Y:%.*]] = and i8 [[X]], 16
; CHECK-NEXT: call void @use.i8(i8 [[AND_X_NEG_Y]])
; CHECK-NEXT: call void @use.i8(i8 [[AND_X_Y]])
-; CHECK-NEXT: [[R:%.*]] = icmp ne i8 [[AND_X_NEG_Y]], [[AND_X_Y]]
+; CHECK-NEXT: [[R:%.*]] = icmp ugt i8 [[X]], 31
; CHECK-NEXT: ret i1 [[R]]
;
%and_x_neg_y = and i8 %x, -16
@@ -100,7 +100,7 @@ define i1 @test_ne_cp2_2(i8 %x, i8 %yy) {
; CHECK-NEXT: [[AND_X_Y:%.*]] = and i8 [[X]], 4
; CHECK-NEXT: call void @use.i8(i8 [[AND_X_NEG_Y]])
; CHECK-NEXT: call void @use.i8(i8 [[AND_X_Y]])
-; CHECK-NEXT: [[R:%.*]] = icmp eq i8 [[AND_X_Y]], [[AND_X_NEG_Y]]
+; CHECK-NEXT: [[R:%.*]] = icmp ult i8 [[X]], 8
; CHECK-NEXT: ret i1 [[R]]
;
%and_x_neg_y = and i8 %x, -4
@@ -117,7 +117,7 @@ define i1 @test_ne_cp2_other_okay_all_ones(i8 %x, i8 %yy) {
; CHECK-NEXT: [[AND_X_Y:%.*]] = and i8 [[X]], 16
; CHECK-NEXT: call void @use.i8(i8 [[AND_X_NEG_Y]])
; CHECK-NEXT: call void @use.i8(i8 [[AND_X_Y]])
-; CHECK-NEXT: [[R:%.*]] = icmp ne i8 [[AND_X_NEG_Y]], [[AND_X_Y]]
+; CHECK-NEXT: [[R:%.*]] = icmp ne i8 [[X]], 0
; CHECK-NEXT: ret i1 [[R]]
;
%and_x_neg_y = and i8 %x, -17
@@ -147,10 +147,9 @@ define i1 @test_ne_cp2_other_fail2(i8 %x, i8 %yy) {
define i1 @test_ne_cp2_other_okay(i8 %x, i8 %yy) {
; CHECK-LABEL: @test_ne_cp2_other_okay(
-; CHECK-NEXT: [[AND_X_NEG_Y:%.*]] = and i8 [[X:%.*]], -17
-; CHECK-NEXT: [[AND_X_Y:%.*]] = and i8 [[X]], 16
+; CHECK-NEXT: [[AND_X_Y:%.*]] = and i8 [[X:%.*]], 16
; CHECK-NEXT: call void @use.i8(i8 [[AND_X_Y]])
-; CHECK-NEXT: [[R:%.*]] = icmp ne i8 [[AND_X_NEG_Y]], [[AND_X_Y]]
+; CHECK-NEXT: [[R:%.*]] = icmp ne i8 [[X]], 0
; CHECK-NEXT: ret i1 [[R]]
;
%and_x_neg_y = and i8 %x, -17
@@ -162,10 +161,9 @@ define i1 @test_ne_cp2_other_okay(i8 %x, i8 %yy) {
define i1 @test_ne_cp2_other_okay2(i8 %x, i8 %yy) {
; CHECK-LABEL: @test_ne_cp2_other_okay2(
-; CHECK-NEXT: [[AND_X_NEG_Y:%.*]] = and i8 [[X:%.*]], -17
-; CHECK-NEXT: [[AND_X_Y:%.*]] = and i8 [[X]], 16
+; CHECK-NEXT: [[AND_X_Y:%.*]] = and i8 [[X:%.*]], 16
; CHECK-NEXT: call void @use.i8(i8 [[AND_X_Y]])
-; CHECK-NEXT: [[R:%.*]] = icmp ne i8 [[AND_X_Y]], [[AND_X_NEG_Y]]
+; CHECK-NEXT: [[R:%.*]] = icmp ne i8 [[X]], 0
; CHECK-NEXT: ret i1 [[R]]
;
%and_x_neg_y = and i8 %x, -17
More information about the llvm-commits
mailing list