https://github.com/dtcxzyw updated https://github.com/llvm/llvm-project/pull/67915
>From c4ce28c942c172e5646b5922f0b02b4169197840 Mon Sep 17 00:00:00 2001 From: Yingwei Zheng <dtcxzyw2...@gmail.com> Date: Sun, 1 Oct 2023 21:52:47 +0800 Subject: [PATCH 1/2] [InstCombine] Canonicalize `(X +/- Y) & Y` into `~X & Y` when Y is a power of 2 --- .../InstCombine/InstCombineAndOrXor.cpp | 8 ++++ llvm/test/Transforms/InstCombine/and.ll | 44 +++++++++++++++++-- 2 files changed, 48 insertions(+), 4 deletions(-) diff --git a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp index cbdab3e9c5fb91d..4322cc96f5a2b6c 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp @@ -2250,6 +2250,14 @@ Instruction *InstCombinerImpl::visitAnd(BinaryOperator &I) { return SelectInst::Create(Cmp, ConstantInt::getNullValue(Ty), Y); } + // Canonicalize: + // (X +/- Y) & Y --> ~X & Y when Y is a power of 2. + if (match(&I, m_c_And(m_Value(Y), m_OneUse(m_CombineOr( + m_c_Add(m_Value(X), m_Deferred(Y)), + m_Sub(m_Value(X), m_Deferred(Y)))))) && + isKnownToBeAPowerOfTwo(Y, /*OrZero*/ true, /*Depth*/ 0, &I)) + return BinaryOperator::CreateAnd(Builder.CreateNot(X), Y); + const APInt *C; if (match(Op1, m_APInt(C))) { const APInt *XorC; diff --git a/llvm/test/Transforms/InstCombine/and.ll b/llvm/test/Transforms/InstCombine/and.ll index 90f027010e2aea6..eb39ff9014ff3a4 100644 --- a/llvm/test/Transforms/InstCombine/and.ll +++ b/llvm/test/Transforms/InstCombine/and.ll @@ -1595,8 +1595,8 @@ define <2 x i8> @flip_masked_bit_uniform(<2 x i8> %A) { define <2 x i8> @flip_masked_bit_undef(<2 x i8> %A) { ; CHECK-LABEL: @flip_masked_bit_undef( -; CHECK-NEXT: [[B:%.*]] = add <2 x i8> [[A:%.*]], <i8 16, i8 undef> -; CHECK-NEXT: [[C:%.*]] = and <2 x i8> [[B]], <i8 16, i8 undef> +; CHECK-NEXT: [[TMP1:%.*]] = xor <2 x i8> [[A:%.*]], <i8 -1, i8 -1> +; CHECK-NEXT: [[C:%.*]] = and <2 x i8> [[TMP1]], <i8 16, i8 undef> ; CHECK-NEXT: ret <2 x i8> [[C]] ; %B = add <2 x i8> %A, <i8 16, i8 undef> @@ -1606,8 +1606,8 @@ define <2 x i8> @flip_masked_bit_undef(<2 x i8> %A) { define <2 x i8> @flip_masked_bit_nonuniform(<2 x i8> %A) { ; CHECK-LABEL: @flip_masked_bit_nonuniform( -; CHECK-NEXT: [[B:%.*]] = add <2 x i8> [[A:%.*]], <i8 16, i8 4> -; CHECK-NEXT: [[C:%.*]] = and <2 x i8> [[B]], <i8 16, i8 4> +; CHECK-NEXT: [[TMP1:%.*]] = xor <2 x i8> [[A:%.*]], <i8 -1, i8 -1> +; CHECK-NEXT: [[C:%.*]] = and <2 x i8> [[TMP1]], <i8 16, i8 4> ; CHECK-NEXT: ret <2 x i8> [[C]] ; %B = add <2 x i8> %A, <i8 16, i8 4> @@ -2546,3 +2546,39 @@ define i32 @and_zext_eq_zero(i32 %A, i32 %C) { %5 = and i32 %2, %4 ret i32 %5 } + +define i32 @canonicalize_and_add_power2_or_zero(i32 %x, i32 %y) { +; CHECK-LABEL: @canonicalize_and_add_power2_or_zero( +; CHECK-NEXT: [[NY:%.*]] = sub i32 0, [[Y:%.*]] +; CHECK-NEXT: [[P2:%.*]] = and i32 [[NY]], [[Y]] +; CHECK-NEXT: call void @use32(i32 [[P2]]) +; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[X:%.*]], -1 +; CHECK-NEXT: [[AND:%.*]] = and i32 [[P2]], [[TMP1]] +; CHECK-NEXT: ret i32 [[AND]] +; + %ny = sub i32 0, %y + %p2 = and i32 %y, %ny + call void @use32(i32 %p2) ; keep p2 + + %val = add i32 %x, %p2 + %and = and i32 %val, %p2 + ret i32 %and +} + +define i32 @canonicalize_and_sub_power2_or_zero(i32 %x, i32 %y) { +; CHECK-LABEL: @canonicalize_and_sub_power2_or_zero( +; CHECK-NEXT: [[NY:%.*]] = sub i32 0, [[Y:%.*]] +; CHECK-NEXT: [[P2:%.*]] = and i32 [[NY]], [[Y]] +; CHECK-NEXT: call void @use32(i32 [[P2]]) +; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[X:%.*]], -1 +; CHECK-NEXT: [[AND:%.*]] = and i32 [[P2]], [[TMP1]] +; CHECK-NEXT: ret i32 [[AND]] +; + %ny = sub i32 0, %y + %p2 = and i32 %y, %ny + call void @use32(i32 %p2) ; keep p2 + + %val = sub i32 %x, %p2 + %and = and i32 %val, %p2 + ret i32 %and +} >From b64ca5b5f743e6a935f4ea09154c3a08c6e65c47 Mon Sep 17 00:00:00 2001 From: Yingwei Zheng <dtcxzyw2...@gmail.com> Date: Fri, 6 Oct 2023 17:32:46 +0800 Subject: [PATCH 2/2] fixup! [InstCombine] Canonicalize `(X +/- Y) & Y` into `~X & Y` when Y is a power of 2 Add additional tests. --- llvm/test/Transforms/InstCombine/and.ll | 123 ++++++++++++++++++++++++ 1 file changed, 123 insertions(+) diff --git a/llvm/test/Transforms/InstCombine/and.ll b/llvm/test/Transforms/InstCombine/and.ll index eb39ff9014ff3a4..989640ed41f2d2e 100644 --- a/llvm/test/Transforms/InstCombine/and.ll +++ b/llvm/test/Transforms/InstCombine/and.ll @@ -2582,3 +2582,126 @@ define i32 @canonicalize_and_sub_power2_or_zero(i32 %x, i32 %y) { %and = and i32 %val, %p2 ret i32 %and } + +define i32 @canonicalize_and_add_power2_or_zero_commuted1(i32 %x, i32 %y) { +; CHECK-LABEL: @canonicalize_and_add_power2_or_zero_commuted1( +; CHECK-NEXT: [[NY:%.*]] = sub i32 0, [[Y:%.*]] +; CHECK-NEXT: [[P2:%.*]] = and i32 [[NY]], [[Y]] +; CHECK-NEXT: call void @use32(i32 [[P2]]) +; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[X:%.*]], -1 +; CHECK-NEXT: [[AND:%.*]] = and i32 [[P2]], [[TMP1]] +; CHECK-NEXT: ret i32 [[AND]] +; + %ny = sub i32 0, %y + %p2 = and i32 %y, %ny + call void @use32(i32 %p2) ; keep p2 + + %val = add i32 %p2, %x + %and = and i32 %val, %p2 + ret i32 %and +} + +define i32 @canonicalize_and_add_power2_or_zero_commuted2(i32 %x, i32 %y) { +; CHECK-LABEL: @canonicalize_and_add_power2_or_zero_commuted2( +; CHECK-NEXT: [[NY:%.*]] = sub i32 0, [[Y:%.*]] +; CHECK-NEXT: [[P2:%.*]] = and i32 [[NY]], [[Y]] +; CHECK-NEXT: call void @use32(i32 [[P2]]) +; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[X:%.*]], -1 +; CHECK-NEXT: [[AND:%.*]] = and i32 [[P2]], [[TMP1]] +; CHECK-NEXT: ret i32 [[AND]] +; + %ny = sub i32 0, %y + %p2 = and i32 %y, %ny + call void @use32(i32 %p2) ; keep p2 + + %val = add i32 %x, %p2 + %and = and i32 %p2, %val + ret i32 %and +} + +define i32 @canonicalize_and_add_power2_or_zero_commuted3(i32 %x, i32 %y) { +; CHECK-LABEL: @canonicalize_and_add_power2_or_zero_commuted3( +; CHECK-NEXT: [[NY:%.*]] = sub i32 0, [[Y:%.*]] +; CHECK-NEXT: [[P2:%.*]] = and i32 [[NY]], [[Y]] +; CHECK-NEXT: call void @use32(i32 [[P2]]) +; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[X:%.*]], -1 +; CHECK-NEXT: [[AND:%.*]] = and i32 [[P2]], [[TMP1]] +; CHECK-NEXT: ret i32 [[AND]] +; + %ny = sub i32 0, %y + %p2 = and i32 %y, %ny + call void @use32(i32 %p2) ; keep p2 + + %val = add i32 %p2, %x + %and = and i32 %p2, %val + ret i32 %and +} + +define i32 @canonicalize_and_sub_power2_or_zero_commuted_nofold(i32 %x, i32 %y) { +; CHECK-LABEL: @canonicalize_and_sub_power2_or_zero_commuted_nofold( +; CHECK-NEXT: [[NY:%.*]] = sub i32 0, [[Y:%.*]] +; CHECK-NEXT: [[P2:%.*]] = and i32 [[NY]], [[Y]] +; CHECK-NEXT: call void @use32(i32 [[P2]]) +; CHECK-NEXT: [[VAL:%.*]] = sub i32 [[P2]], [[X:%.*]] +; CHECK-NEXT: [[AND:%.*]] = and i32 [[VAL]], [[P2]] +; CHECK-NEXT: ret i32 [[AND]] +; + %ny = sub i32 0, %y + %p2 = and i32 %y, %ny + call void @use32(i32 %p2) ; keep p2 + + %val = sub i32 %p2, %x + %and = and i32 %val, %p2 + ret i32 %and +} + +define i32 @canonicalize_and_add_non_power2_or_zero_nofold(i32 %x, i32 %y) { +; CHECK-LABEL: @canonicalize_and_add_non_power2_or_zero_nofold( +; CHECK-NEXT: [[VAL:%.*]] = add i32 [[X:%.*]], [[Y:%.*]] +; CHECK-NEXT: [[AND:%.*]] = and i32 [[VAL]], [[Y]] +; CHECK-NEXT: ret i32 [[AND]] +; + %val = add i32 %x, %y + %and = and i32 %val, %y + ret i32 %and +} + +define i32 @canonicalize_and_add_power2_or_zero_multiuse_nofold(i32 %x, i32 %y) { +; CHECK-LABEL: @canonicalize_and_add_power2_or_zero_multiuse_nofold( +; CHECK-NEXT: [[NY:%.*]] = sub i32 0, [[Y:%.*]] +; CHECK-NEXT: [[P2:%.*]] = and i32 [[NY]], [[Y]] +; CHECK-NEXT: call void @use32(i32 [[P2]]) +; CHECK-NEXT: [[VAL:%.*]] = add i32 [[P2]], [[X:%.*]] +; CHECK-NEXT: call void @use32(i32 [[VAL]]) +; CHECK-NEXT: [[AND:%.*]] = and i32 [[VAL]], [[P2]] +; CHECK-NEXT: ret i32 [[AND]] +; + %ny = sub i32 0, %y + %p2 = and i32 %y, %ny + call void @use32(i32 %p2) ; keep p2 + + %val = add i32 %x, %p2 + call void @use32(i32 %val) + %and = and i32 %val, %p2 + ret i32 %and +} + +define i32 @canonicalize_and_sub_power2_or_zero_multiuse_nofold(i32 %x, i32 %y) { +; CHECK-LABEL: @canonicalize_and_sub_power2_or_zero_multiuse_nofold( +; CHECK-NEXT: [[NY:%.*]] = sub i32 0, [[Y:%.*]] +; CHECK-NEXT: [[P2:%.*]] = and i32 [[NY]], [[Y]] +; CHECK-NEXT: call void @use32(i32 [[P2]]) +; CHECK-NEXT: [[VAL:%.*]] = sub i32 [[X:%.*]], [[P2]] +; CHECK-NEXT: call void @use32(i32 [[VAL]]) +; CHECK-NEXT: [[AND:%.*]] = and i32 [[VAL]], [[P2]] +; CHECK-NEXT: ret i32 [[AND]] +; + %ny = sub i32 0, %y + %p2 = and i32 %y, %ny + call void @use32(i32 %p2) ; keep p2 + + %val = sub i32 %x, %p2 + call void @use32(i32 %val) + %and = and i32 %val, %p2 + ret i32 %and +} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits