Skip to content

Commit 8a7e547

Browse files
authored
[InstCombine] Canonicalize (X +/- Y) & Y into ~X & Y when Y is a power of 2 (#67915)
This patch canonicalizes the pattern `(X +/- Y) & Y` into `~X & Y` when `Y` is a power of 2 or zero. It will reduce the patterns to match in #67836 and exploit more optimization opportunities. Alive2: https://alive2.llvm.org/ce/z/LBpvRF
1 parent 2ceabf6 commit 8a7e547

File tree

2 files changed

+22
-14
lines changed

2 files changed

+22
-14
lines changed

llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2250,6 +2250,14 @@ Instruction *InstCombinerImpl::visitAnd(BinaryOperator &I) {
22502250
return SelectInst::Create(Cmp, ConstantInt::getNullValue(Ty), Y);
22512251
}
22522252

2253+
// Canonicalize:
2254+
// (X +/- Y) & Y --> ~X & Y when Y is a power of 2.
2255+
if (match(&I, m_c_And(m_Value(Y), m_OneUse(m_CombineOr(
2256+
m_c_Add(m_Value(X), m_Deferred(Y)),
2257+
m_Sub(m_Value(X), m_Deferred(Y)))))) &&
2258+
isKnownToBeAPowerOfTwo(Y, /*OrZero*/ true, /*Depth*/ 0, &I))
2259+
return BinaryOperator::CreateAnd(Builder.CreateNot(X), Y);
2260+
22532261
const APInt *C;
22542262
if (match(Op1, m_APInt(C))) {
22552263
const APInt *XorC;

llvm/test/Transforms/InstCombine/and.ll

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1595,8 +1595,8 @@ define <2 x i8> @flip_masked_bit_uniform(<2 x i8> %A) {
15951595

15961596
define <2 x i8> @flip_masked_bit_undef(<2 x i8> %A) {
15971597
; CHECK-LABEL: @flip_masked_bit_undef(
1598-
; CHECK-NEXT: [[B:%.*]] = add <2 x i8> [[A:%.*]], <i8 16, i8 undef>
1599-
; CHECK-NEXT: [[C:%.*]] = and <2 x i8> [[B]], <i8 16, i8 undef>
1598+
; CHECK-NEXT: [[TMP1:%.*]] = xor <2 x i8> [[A:%.*]], <i8 -1, i8 -1>
1599+
; CHECK-NEXT: [[C:%.*]] = and <2 x i8> [[TMP1]], <i8 16, i8 undef>
16001600
; CHECK-NEXT: ret <2 x i8> [[C]]
16011601
;
16021602
%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) {
16061606

16071607
define <2 x i8> @flip_masked_bit_nonuniform(<2 x i8> %A) {
16081608
; CHECK-LABEL: @flip_masked_bit_nonuniform(
1609-
; CHECK-NEXT: [[B:%.*]] = add <2 x i8> [[A:%.*]], <i8 16, i8 4>
1610-
; CHECK-NEXT: [[C:%.*]] = and <2 x i8> [[B]], <i8 16, i8 4>
1609+
; CHECK-NEXT: [[TMP1:%.*]] = xor <2 x i8> [[A:%.*]], <i8 -1, i8 -1>
1610+
; CHECK-NEXT: [[C:%.*]] = and <2 x i8> [[TMP1]], <i8 16, i8 4>
16111611
; CHECK-NEXT: ret <2 x i8> [[C]]
16121612
;
16131613
%B = add <2 x i8> %A, <i8 16, i8 4>
@@ -2553,8 +2553,8 @@ define i32 @canonicalize_and_add_power2_or_zero(i32 %x, i32 %y) {
25532553
; CHECK-NEXT: [[P2:%.*]] = and i32 [[NY]], [[Y]]
25542554
; CHECK-NEXT: call void @use32(i32 [[P2]])
25552555
; CHECK-NEXT: [[X2:%.*]] = mul i32 [[X:%.*]], [[X]]
2556-
; CHECK-NEXT: [[VAL:%.*]] = add i32 [[X2]], [[P2]]
2557-
; CHECK-NEXT: [[AND:%.*]] = and i32 [[VAL]], [[P2]]
2556+
; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[X2]], -1
2557+
; CHECK-NEXT: [[AND:%.*]] = and i32 [[P2]], [[TMP1]]
25582558
; CHECK-NEXT: ret i32 [[AND]]
25592559
;
25602560
%ny = sub i32 0, %y
@@ -2572,8 +2572,8 @@ define i32 @canonicalize_and_sub_power2_or_zero(i32 %x, i32 %y) {
25722572
; CHECK-NEXT: [[NY:%.*]] = sub i32 0, [[Y:%.*]]
25732573
; CHECK-NEXT: [[P2:%.*]] = and i32 [[NY]], [[Y]]
25742574
; CHECK-NEXT: call void @use32(i32 [[P2]])
2575-
; CHECK-NEXT: [[VAL:%.*]] = sub i32 [[X:%.*]], [[P2]]
2576-
; CHECK-NEXT: [[AND:%.*]] = and i32 [[VAL]], [[P2]]
2575+
; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[X:%.*]], -1
2576+
; CHECK-NEXT: [[AND:%.*]] = and i32 [[P2]], [[TMP1]]
25772577
; CHECK-NEXT: ret i32 [[AND]]
25782578
;
25792579
%ny = sub i32 0, %y
@@ -2590,8 +2590,8 @@ define i32 @canonicalize_and_add_power2_or_zero_commuted1(i32 %x, i32 %y) {
25902590
; CHECK-NEXT: [[NY:%.*]] = sub i32 0, [[Y:%.*]]
25912591
; CHECK-NEXT: [[P2:%.*]] = and i32 [[NY]], [[Y]]
25922592
; CHECK-NEXT: call void @use32(i32 [[P2]])
2593-
; CHECK-NEXT: [[VAL:%.*]] = add i32 [[P2]], [[X:%.*]]
2594-
; CHECK-NEXT: [[AND:%.*]] = and i32 [[VAL]], [[P2]]
2593+
; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[X:%.*]], -1
2594+
; CHECK-NEXT: [[AND:%.*]] = and i32 [[P2]], [[TMP1]]
25952595
; CHECK-NEXT: ret i32 [[AND]]
25962596
;
25972597
%ny = sub i32 0, %y
@@ -2609,8 +2609,8 @@ define i32 @canonicalize_and_add_power2_or_zero_commuted2(i32 %x, i32 %y) {
26092609
; CHECK-NEXT: [[P2:%.*]] = and i32 [[NY]], [[Y]]
26102610
; CHECK-NEXT: call void @use32(i32 [[P2]])
26112611
; CHECK-NEXT: [[X2:%.*]] = mul i32 [[X:%.*]], [[X]]
2612-
; CHECK-NEXT: [[VAL:%.*]] = add i32 [[X2]], [[P2]]
2613-
; CHECK-NEXT: [[AND:%.*]] = and i32 [[P2]], [[VAL]]
2612+
; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[X2]], -1
2613+
; CHECK-NEXT: [[AND:%.*]] = and i32 [[P2]], [[TMP1]]
26142614
; CHECK-NEXT: ret i32 [[AND]]
26152615
;
26162616
%ny = sub i32 0, %y
@@ -2628,8 +2628,8 @@ define i32 @canonicalize_and_add_power2_or_zero_commuted3(i32 %x, i32 %y) {
26282628
; CHECK-NEXT: [[NY:%.*]] = sub i32 0, [[Y:%.*]]
26292629
; CHECK-NEXT: [[P2:%.*]] = and i32 [[NY]], [[Y]]
26302630
; CHECK-NEXT: call void @use32(i32 [[P2]])
2631-
; CHECK-NEXT: [[VAL:%.*]] = add i32 [[P2]], [[X:%.*]]
2632-
; CHECK-NEXT: [[AND:%.*]] = and i32 [[P2]], [[VAL]]
2631+
; CHECK-NEXT: [[TMP1:%.*]] = xor i32 [[X:%.*]], -1
2632+
; CHECK-NEXT: [[AND:%.*]] = and i32 [[P2]], [[TMP1]]
26332633
; CHECK-NEXT: ret i32 [[AND]]
26342634
;
26352635
%ny = sub i32 0, %y

0 commit comments

Comments
 (0)