Skip to content

Commit f9e2fb9

Browse files
committed
[InstCombine] combine intersection for inequality icmps
``` define i1 @src(i32 %A) { %mask1 = and i32 %A, 15 ; 0x0f %tst1 = icmp eq i32 %mask1, 3 ; 0x03 %mask2 = and i32 %A, 255 ; 0xff %tst2 = icmp eq i32 %mask2, 243; 0xf3 %res = or i1 %tst1, %tst2 ret i1 %res } ``` -> ``` define i1 @tgt(i32 %A) { %1 = and i32 %A, 15 %res = icmp eq i32 %1, 3 ret i1 %res } ``` Proof: https://alive2.llvm.org/ce/z/4AyvcE Assume that `(B & D) & (C ^ E) == 0`, and `(B & D) == D || (B & D) == B`, transforms: ``` (icmp ne (A & B), C) & (icmp ne (A & D), E) -> (icmp ne (A & (B&D)), (C&E)) ``` Fixes: llvm#59680 Reviewed By: spatel, bcl5980 Differential Revision: https://reviews.llvm.org/D140666
1 parent 942c4cd commit f9e2fb9

File tree

2 files changed

+45
-26
lines changed

2 files changed

+45
-26
lines changed

llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp

Lines changed: 39 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -625,7 +625,8 @@ static Value *foldLogOpOfMaskedICmps(ICmpInst *LHS, ICmpInst *RHS, bool IsAnd,
625625
return RHS;
626626
}
627627

628-
if (Mask & BMask_Mixed) {
628+
if (Mask & (BMask_Mixed | BMask_NotMixed)) {
629+
// Mixed:
629630
// (icmp eq (A & B), C) & (icmp eq (A & D), E)
630631
// We already know that B & C == C && D & E == E.
631632
// If we can prove that (B & D) & (C ^ E) == 0, that is, the bits of
@@ -636,24 +637,50 @@ static Value *foldLogOpOfMaskedICmps(ICmpInst *LHS, ICmpInst *RHS, bool IsAnd,
636637
// We can't simply use C and E because we might actually handle
637638
// (icmp ne (A & B), B) & (icmp eq (A & D), D)
638639
// with B and D, having a single bit set.
640+
641+
// NotMixed:
642+
// (icmp ne (A & B), C) & (icmp ne (A & D), E)
643+
// -> (icmp ne (A & (B & D)), (C & E))
644+
// Check the intersection (B & D) for inequality.
645+
// Assume that (B & D) == B || (B & D) == D, i.e B/D is a subset of D/B
646+
// and (B & D) & (C ^ E) == 0, bits of C and E, which are shared by both the
647+
// B and the D, don't contradict.
648+
// Note that we can assume (~B & C) == 0 && (~D & E) == 0, previous
649+
// operation should delete these icmps if it hadn't been met.
650+
639651
const APInt *OldConstC, *OldConstE;
640652
if (!match(C, m_APInt(OldConstC)) || !match(E, m_APInt(OldConstE)))
641653
return nullptr;
642654

643-
const APInt ConstC = PredL != NewCC ? *ConstB ^ *OldConstC : *OldConstC;
644-
const APInt ConstE = PredR != NewCC ? *ConstD ^ *OldConstE : *OldConstE;
655+
auto FoldBMixed = [&](ICmpInst::Predicate CC, bool IsNot) -> Value * {
656+
CC = IsNot ? CmpInst::getInversePredicate(CC) : CC;
657+
const APInt ConstC = PredL != CC ? *ConstB ^ *OldConstC : *OldConstC;
658+
const APInt ConstE = PredR != CC ? *ConstD ^ *OldConstE : *OldConstE;
645659

646-
// If there is a conflict, we should actually return a false for the
647-
// whole construct.
648-
if (((*ConstB & *ConstD) & (ConstC ^ ConstE)).getBoolValue())
649-
return ConstantInt::get(LHS->getType(), !IsAnd);
660+
if (((*ConstB & *ConstD) & (ConstC ^ ConstE)).getBoolValue())
661+
return IsNot ? nullptr : ConstantInt::get(LHS->getType(), !IsAnd);
650662

651-
Value *NewOr1 = Builder.CreateOr(B, D);
652-
Value *NewAnd = Builder.CreateAnd(A, NewOr1);
653-
Constant *NewOr2 = ConstantInt::get(A->getType(), ConstC | ConstE);
654-
return Builder.CreateICmp(NewCC, NewAnd, NewOr2);
655-
}
663+
if (IsNot && !ConstB->isSubsetOf(*ConstD) && !ConstD->isSubsetOf(*ConstB))
664+
return nullptr;
656665

666+
APInt BD, CE;
667+
if (IsNot) {
668+
BD = *ConstB & *ConstD;
669+
CE = ConstC & ConstE;
670+
} else {
671+
BD = *ConstB | *ConstD;
672+
CE = ConstC | ConstE;
673+
}
674+
Value *NewAnd = Builder.CreateAnd(A, BD);
675+
Value *CEVal = ConstantInt::get(A->getType(), CE);
676+
return Builder.CreateICmp(CC, CEVal, NewAnd);
677+
};
678+
679+
if (Mask & BMask_Mixed)
680+
return FoldBMixed(NewCC, false);
681+
if (Mask & BMask_NotMixed) // can be else also
682+
return FoldBMixed(NewCC, true);
683+
}
657684
return nullptr;
658685
}
659686

llvm/test/Transforms/InstCombine/icmp-logical.ll

Lines changed: 6 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1747,11 +1747,8 @@ define i1 @masked_icmps_mask_notallzeros_bmask_mixed_negated_swapped_7b_logical(
17471747

17481748
define i1 @masked_icmps_bmask_notmixed_or(i32 %A) {
17491749
; CHECK-LABEL: @masked_icmps_bmask_notmixed_or(
1750-
; CHECK-NEXT: [[MASK1:%.*]] = and i32 [[A:%.*]], 15
1751-
; CHECK-NEXT: [[TST1:%.*]] = icmp eq i32 [[MASK1]], 3
1752-
; CHECK-NEXT: [[MASK2:%.*]] = and i32 [[A]], 255
1753-
; CHECK-NEXT: [[TST2:%.*]] = icmp eq i32 [[MASK2]], 243
1754-
; CHECK-NEXT: [[RES:%.*]] = or i1 [[TST1]], [[TST2]]
1750+
; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[A:%.*]], 15
1751+
; CHECK-NEXT: [[RES:%.*]] = icmp eq i32 [[TMP1]], 3
17551752
; CHECK-NEXT: ret i1 [[RES]]
17561753
;
17571754
%mask1 = and i32 %A, 15 ; 0x0f
@@ -1764,10 +1761,8 @@ define i1 @masked_icmps_bmask_notmixed_or(i32 %A) {
17641761

17651762
define <2 x i1> @masked_icmps_bmask_notmixed_or_vec(<2 x i8> %A) {
17661763
; CHECK-LABEL: @masked_icmps_bmask_notmixed_or_vec(
1767-
; CHECK-NEXT: [[MASK1:%.*]] = and <2 x i8> [[A:%.*]], <i8 15, i8 15>
1768-
; CHECK-NEXT: [[TST1:%.*]] = icmp eq <2 x i8> [[MASK1]], <i8 3, i8 3>
1769-
; CHECK-NEXT: [[TST2:%.*]] = icmp eq <2 x i8> [[A]], <i8 -13, i8 -13>
1770-
; CHECK-NEXT: [[RES:%.*]] = or <2 x i1> [[TST1]], [[TST2]]
1764+
; CHECK-NEXT: [[TMP1:%.*]] = and <2 x i8> [[A:%.*]], <i8 15, i8 15>
1765+
; CHECK-NEXT: [[RES:%.*]] = icmp eq <2 x i8> [[TMP1]], <i8 3, i8 3>
17711766
; CHECK-NEXT: ret <2 x i1> [[RES]]
17721767
;
17731768
%mask1 = and <2 x i8> %A, <i8 15, i8 15> ; 0x0f
@@ -1829,11 +1824,8 @@ define i1 @masked_icmps_bmask_notmixed_or_contradict_notoptimized(i32 %A) {
18291824

18301825
define i1 @masked_icmps_bmask_notmixed_and(i32 %A) {
18311826
; CHECK-LABEL: @masked_icmps_bmask_notmixed_and(
1832-
; CHECK-NEXT: [[MASK1:%.*]] = and i32 [[A:%.*]], 15
1833-
; CHECK-NEXT: [[TST1:%.*]] = icmp ne i32 [[MASK1]], 3
1834-
; CHECK-NEXT: [[MASK2:%.*]] = and i32 [[A]], 255
1835-
; CHECK-NEXT: [[TST2:%.*]] = icmp ne i32 [[MASK2]], 243
1836-
; CHECK-NEXT: [[RES:%.*]] = and i1 [[TST1]], [[TST2]]
1827+
; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[A:%.*]], 15
1828+
; CHECK-NEXT: [[RES:%.*]] = icmp ne i32 [[TMP1]], 3
18371829
; CHECK-NEXT: ret i1 [[RES]]
18381830
;
18391831
%mask1 = and i32 %A, 15 ; 0x0f

0 commit comments

Comments
 (0)