Skip to content

Commit d4182f1

Browse files
authored
[InstCombine] move foldAndOrOfICmpsOfAndWithPow2 into foldLogOpOfMaskedICmps (#121970)
1 parent 1a830aa commit d4182f1

File tree

3 files changed

+101
-136
lines changed

3 files changed

+101
-136
lines changed

llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp

Lines changed: 98 additions & 129 deletions
Original file line numberDiff line numberDiff line change
@@ -514,7 +514,8 @@ static Value *foldLogOpOfMaskedICmpsAsymmetric(
514514
/// into a single (icmp(A & X) ==/!= Y).
515515
static Value *foldLogOpOfMaskedICmps(ICmpInst *LHS, ICmpInst *RHS, bool IsAnd,
516516
bool IsLogical,
517-
InstCombiner::BuilderTy &Builder) {
517+
InstCombiner::BuilderTy &Builder,
518+
const SimplifyQuery &Q) {
518519
Value *A = nullptr, *B = nullptr, *C = nullptr, *D = nullptr, *E = nullptr;
519520
ICmpInst::Predicate PredL = LHS->getPredicate(), PredR = RHS->getPredicate();
520521
std::optional<std::pair<unsigned, unsigned>> MaskPair =
@@ -587,93 +588,107 @@ static Value *foldLogOpOfMaskedICmps(ICmpInst *LHS, ICmpInst *RHS, bool IsAnd,
587588
return Builder.CreateICmp(NewCC, NewAnd2, A);
588589
}
589590

590-
// Remaining cases assume at least that B and D are constant, and depend on
591-
// their actual values. This isn't strictly necessary, just a "handle the
592-
// easy cases for now" decision.
593591
const APInt *ConstB, *ConstD;
594-
if (!match(B, m_APInt(ConstB)) || !match(D, m_APInt(ConstD)))
595-
return nullptr;
596-
597-
if (Mask & (Mask_NotAllZeros | BMask_NotAllOnes)) {
598-
// (icmp ne (A & B), 0) & (icmp ne (A & D), 0) and
599-
// (icmp ne (A & B), B) & (icmp ne (A & D), D)
600-
// -> (icmp ne (A & B), 0) or (icmp ne (A & D), 0)
601-
// Only valid if one of the masks is a superset of the other (check "B&D" is
602-
// the same as either B or D).
603-
APInt NewMask = *ConstB & *ConstD;
604-
if (NewMask == *ConstB)
605-
return LHS;
606-
else if (NewMask == *ConstD)
607-
return RHS;
608-
}
609-
610-
if (Mask & AMask_NotAllOnes) {
611-
// (icmp ne (A & B), B) & (icmp ne (A & D), D)
612-
// -> (icmp ne (A & B), A) or (icmp ne (A & D), A)
613-
// Only valid if one of the masks is a superset of the other (check "B|D" is
614-
// the same as either B or D).
615-
APInt NewMask = *ConstB | *ConstD;
616-
if (NewMask == *ConstB)
617-
return LHS;
618-
else if (NewMask == *ConstD)
619-
return RHS;
620-
}
621-
622-
if (Mask & (BMask_Mixed | BMask_NotMixed)) {
623-
// Mixed:
624-
// (icmp eq (A & B), C) & (icmp eq (A & D), E)
625-
// We already know that B & C == C && D & E == E.
626-
// If we can prove that (B & D) & (C ^ E) == 0, that is, the bits of
627-
// C and E, which are shared by both the mask B and the mask D, don't
628-
// contradict, then we can transform to
629-
// -> (icmp eq (A & (B|D)), (C|E))
630-
// Currently, we only handle the case of B, C, D, and E being constant.
631-
// We can't simply use C and E because we might actually handle
632-
// (icmp ne (A & B), B) & (icmp eq (A & D), D)
633-
// with B and D, having a single bit set.
634-
635-
// NotMixed:
636-
// (icmp ne (A & B), C) & (icmp ne (A & D), E)
637-
// -> (icmp ne (A & (B & D)), (C & E))
638-
// Check the intersection (B & D) for inequality.
639-
// Assume that (B & D) == B || (B & D) == D, i.e B/D is a subset of D/B
640-
// and (B & D) & (C ^ E) == 0, bits of C and E, which are shared by both the
641-
// B and the D, don't contradict.
642-
// Note that we can assume (~B & C) == 0 && (~D & E) == 0, previous
643-
// operation should delete these icmps if it hadn't been met.
644-
645-
const APInt *OldConstC, *OldConstE;
646-
if (!match(C, m_APInt(OldConstC)) || !match(E, m_APInt(OldConstE)))
647-
return nullptr;
648-
649-
auto FoldBMixed = [&](ICmpInst::Predicate CC, bool IsNot) -> Value * {
650-
CC = IsNot ? CmpInst::getInversePredicate(CC) : CC;
651-
const APInt ConstC = PredL != CC ? *ConstB ^ *OldConstC : *OldConstC;
652-
const APInt ConstE = PredR != CC ? *ConstD ^ *OldConstE : *OldConstE;
592+
if (match(B, m_APInt(ConstB)) && match(D, m_APInt(ConstD))) {
593+
if (Mask & (Mask_NotAllZeros | BMask_NotAllOnes)) {
594+
// (icmp ne (A & B), 0) & (icmp ne (A & D), 0) and
595+
// (icmp ne (A & B), B) & (icmp ne (A & D), D)
596+
// -> (icmp ne (A & B), 0) or (icmp ne (A & D), 0)
597+
// Only valid if one of the masks is a superset of the other (check "B&D"
598+
// is the same as either B or D).
599+
APInt NewMask = *ConstB & *ConstD;
600+
if (NewMask == *ConstB)
601+
return LHS;
602+
if (NewMask == *ConstD)
603+
return RHS;
604+
}
653605

654-
if (((*ConstB & *ConstD) & (ConstC ^ ConstE)).getBoolValue())
655-
return IsNot ? nullptr : ConstantInt::get(LHS->getType(), !IsAnd);
606+
if (Mask & AMask_NotAllOnes) {
607+
// (icmp ne (A & B), B) & (icmp ne (A & D), D)
608+
// -> (icmp ne (A & B), A) or (icmp ne (A & D), A)
609+
// Only valid if one of the masks is a superset of the other (check "B|D"
610+
// is the same as either B or D).
611+
APInt NewMask = *ConstB | *ConstD;
612+
if (NewMask == *ConstB)
613+
return LHS;
614+
if (NewMask == *ConstD)
615+
return RHS;
616+
}
656617

657-
if (IsNot && !ConstB->isSubsetOf(*ConstD) && !ConstD->isSubsetOf(*ConstB))
618+
if (Mask & (BMask_Mixed | BMask_NotMixed)) {
619+
// Mixed:
620+
// (icmp eq (A & B), C) & (icmp eq (A & D), E)
621+
// We already know that B & C == C && D & E == E.
622+
// If we can prove that (B & D) & (C ^ E) == 0, that is, the bits of
623+
// C and E, which are shared by both the mask B and the mask D, don't
624+
// contradict, then we can transform to
625+
// -> (icmp eq (A & (B|D)), (C|E))
626+
// Currently, we only handle the case of B, C, D, and E being constant.
627+
// We can't simply use C and E because we might actually handle
628+
// (icmp ne (A & B), B) & (icmp eq (A & D), D)
629+
// with B and D, having a single bit set.
630+
631+
// NotMixed:
632+
// (icmp ne (A & B), C) & (icmp ne (A & D), E)
633+
// -> (icmp ne (A & (B & D)), (C & E))
634+
// Check the intersection (B & D) for inequality.
635+
// Assume that (B & D) == B || (B & D) == D, i.e B/D is a subset of D/B
636+
// and (B & D) & (C ^ E) == 0, bits of C and E, which are shared by both
637+
// the B and the D, don't contradict. Note that we can assume (~B & C) ==
638+
// 0 && (~D & E) == 0, previous operation should delete these icmps if it
639+
// hadn't been met.
640+
641+
const APInt *OldConstC, *OldConstE;
642+
if (!match(C, m_APInt(OldConstC)) || !match(E, m_APInt(OldConstE)))
658643
return nullptr;
659644

660-
APInt BD, CE;
661-
if (IsNot) {
662-
BD = *ConstB & *ConstD;
663-
CE = ConstC & ConstE;
664-
} else {
665-
BD = *ConstB | *ConstD;
666-
CE = ConstC | ConstE;
667-
}
668-
Value *NewAnd = Builder.CreateAnd(A, BD);
669-
Value *CEVal = ConstantInt::get(A->getType(), CE);
670-
return Builder.CreateICmp(CC, CEVal, NewAnd);
671-
};
645+
auto FoldBMixed = [&](ICmpInst::Predicate CC, bool IsNot) -> Value * {
646+
CC = IsNot ? CmpInst::getInversePredicate(CC) : CC;
647+
const APInt ConstC = PredL != CC ? *ConstB ^ *OldConstC : *OldConstC;
648+
const APInt ConstE = PredR != CC ? *ConstD ^ *OldConstE : *OldConstE;
649+
650+
if (((*ConstB & *ConstD) & (ConstC ^ ConstE)).getBoolValue())
651+
return IsNot ? nullptr : ConstantInt::get(LHS->getType(), !IsAnd);
652+
653+
if (IsNot && !ConstB->isSubsetOf(*ConstD) &&
654+
!ConstD->isSubsetOf(*ConstB))
655+
return nullptr;
656+
657+
APInt BD, CE;
658+
if (IsNot) {
659+
BD = *ConstB & *ConstD;
660+
CE = ConstC & ConstE;
661+
} else {
662+
BD = *ConstB | *ConstD;
663+
CE = ConstC | ConstE;
664+
}
665+
Value *NewAnd = Builder.CreateAnd(A, BD);
666+
Value *CEVal = ConstantInt::get(A->getType(), CE);
667+
return Builder.CreateICmp(CC, CEVal, NewAnd);
668+
};
669+
670+
if (Mask & BMask_Mixed)
671+
return FoldBMixed(NewCC, false);
672+
if (Mask & BMask_NotMixed) // can be else also
673+
return FoldBMixed(NewCC, true);
674+
}
675+
}
672676

673-
if (Mask & BMask_Mixed)
674-
return FoldBMixed(NewCC, false);
675-
if (Mask & BMask_NotMixed) // can be else also
676-
return FoldBMixed(NewCC, true);
677+
// (icmp eq (A & B), 0) | (icmp eq (A & D), 0)
678+
// -> (icmp ne (A & (B|D)), (B|D))
679+
// (icmp ne (A & B), 0) & (icmp ne (A & D), 0)
680+
// -> (icmp eq (A & (B|D)), (B|D))
681+
// iff B and D is known to be a power of two
682+
if (Mask & Mask_NotAllZeros &&
683+
isKnownToBeAPowerOfTwo(B, /*OrZero=*/false, /*Depth=*/0, Q) &&
684+
isKnownToBeAPowerOfTwo(D, /*OrZero=*/false, /*Depth=*/0, Q)) {
685+
// If this is a logical and/or, then we must prevent propagation of a
686+
// poison value from the RHS by inserting freeze.
687+
if (IsLogical)
688+
D = Builder.CreateFreeze(D);
689+
Value *Mask = Builder.CreateOr(B, D);
690+
Value *Masked = Builder.CreateAnd(A, Mask);
691+
return Builder.CreateICmp(NewCC, Masked, Mask);
677692
}
678693
return nullptr;
679694
}
@@ -776,46 +791,6 @@ foldAndOrOfICmpsWithPow2AndWithZero(InstCombiner::BuilderTy &Builder,
776791
return Builder.CreateICmp(Pred, And, Op);
777792
}
778793

779-
// Fold (iszero(A & K1) | iszero(A & K2)) -> (A & (K1 | K2)) != (K1 | K2)
780-
// Fold (!iszero(A & K1) & !iszero(A & K2)) -> (A & (K1 | K2)) == (K1 | K2)
781-
Value *InstCombinerImpl::foldAndOrOfICmpsOfAndWithPow2(ICmpInst *LHS,
782-
ICmpInst *RHS,
783-
Instruction *CxtI,
784-
bool IsAnd,
785-
bool IsLogical) {
786-
CmpInst::Predicate Pred = IsAnd ? CmpInst::ICMP_NE : CmpInst::ICMP_EQ;
787-
if (LHS->getPredicate() != Pred || RHS->getPredicate() != Pred)
788-
return nullptr;
789-
790-
if (!match(LHS->getOperand(1), m_Zero()) ||
791-
!match(RHS->getOperand(1), m_Zero()))
792-
return nullptr;
793-
794-
Value *L1, *L2, *R1, *R2;
795-
if (match(LHS->getOperand(0), m_And(m_Value(L1), m_Value(L2))) &&
796-
match(RHS->getOperand(0), m_And(m_Value(R1), m_Value(R2)))) {
797-
if (L1 == R2 || L2 == R2)
798-
std::swap(R1, R2);
799-
if (L2 == R1)
800-
std::swap(L1, L2);
801-
802-
if (L1 == R1 &&
803-
isKnownToBeAPowerOfTwo(L2, false, 0, CxtI) &&
804-
isKnownToBeAPowerOfTwo(R2, false, 0, CxtI)) {
805-
// If this is a logical and/or, then we must prevent propagation of a
806-
// poison value from the RHS by inserting freeze.
807-
if (IsLogical)
808-
R2 = Builder.CreateFreeze(R2);
809-
Value *Mask = Builder.CreateOr(L2, R2);
810-
Value *Masked = Builder.CreateAnd(L1, Mask);
811-
auto NewPred = IsAnd ? CmpInst::ICMP_EQ : CmpInst::ICMP_NE;
812-
return Builder.CreateICmp(NewPred, Masked, Mask);
813-
}
814-
}
815-
816-
return nullptr;
817-
}
818-
819794
/// General pattern:
820795
/// X & Y
821796
///
@@ -3327,12 +3302,6 @@ Value *InstCombinerImpl::foldAndOrOfICmps(ICmpInst *LHS, ICmpInst *RHS,
33273302
bool IsLogical) {
33283303
const SimplifyQuery Q = SQ.getWithInstruction(&I);
33293304

3330-
// Fold (iszero(A & K1) | iszero(A & K2)) -> (A & (K1 | K2)) != (K1 | K2)
3331-
// Fold (!iszero(A & K1) & !iszero(A & K2)) -> (A & (K1 | K2)) == (K1 | K2)
3332-
// if K1 and K2 are a one-bit mask.
3333-
if (Value *V = foldAndOrOfICmpsOfAndWithPow2(LHS, RHS, &I, IsAnd, IsLogical))
3334-
return V;
3335-
33363305
ICmpInst::Predicate PredL = LHS->getPredicate(), PredR = RHS->getPredicate();
33373306
Value *LHS0 = LHS->getOperand(0), *RHS0 = RHS->getOperand(0);
33383307
Value *LHS1 = LHS->getOperand(1), *RHS1 = RHS->getOperand(1);
@@ -3359,7 +3328,7 @@ Value *InstCombinerImpl::foldAndOrOfICmps(ICmpInst *LHS, ICmpInst *RHS,
33593328
// handle (roughly):
33603329
// (icmp ne (A & B), C) | (icmp ne (A & D), E)
33613330
// (icmp eq (A & B), C) & (icmp eq (A & D), E)
3362-
if (Value *V = foldLogOpOfMaskedICmps(LHS, RHS, IsAnd, IsLogical, Builder))
3331+
if (Value *V = foldLogOpOfMaskedICmps(LHS, RHS, IsAnd, IsLogical, Builder, Q))
33633332
return V;
33643333

33653334
if (Value *V =

llvm/lib/Transforms/InstCombine/InstCombineInternal.h

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -435,9 +435,6 @@ class LLVM_LIBRARY_VISIBILITY InstCombinerImpl final
435435
Instruction *
436436
canonicalizeConditionalNegationViaMathToSelect(BinaryOperator &i);
437437

438-
Value *foldAndOrOfICmpsOfAndWithPow2(ICmpInst *LHS, ICmpInst *RHS,
439-
Instruction *CxtI, bool IsAnd,
440-
bool IsLogical = false);
441438
Value *matchSelectFromAndOr(Value *A, Value *B, Value *C, Value *D,
442439
bool InvertFalseVal = false);
443440
Value *getSelectCondition(Value *A, Value *B, bool ABIsTheSame);

llvm/test/Transforms/InstCombine/onehot_merge.ll

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1147,10 +1147,9 @@ define i1 @foo1_and_signbit_lshr_without_shifting_signbit_not_pwr2_logical(i32 %
11471147
define i1 @two_types_of_bittest(i8 %x, i8 %c) {
11481148
; CHECK-LABEL: @two_types_of_bittest(
11491149
; CHECK-NEXT: [[T0:%.*]] = shl nuw i8 1, [[C:%.*]]
1150-
; CHECK-NEXT: [[ICMP1:%.*]] = icmp slt i8 [[X:%.*]], 0
1151-
; CHECK-NEXT: [[AND:%.*]] = and i8 [[X]], [[T0]]
1152-
; CHECK-NEXT: [[ICMP2:%.*]] = icmp ne i8 [[AND]], 0
1153-
; CHECK-NEXT: [[RET:%.*]] = and i1 [[ICMP1]], [[ICMP2]]
1150+
; CHECK-NEXT: [[TMP1:%.*]] = or i8 [[T0]], -128
1151+
; CHECK-NEXT: [[TMP2:%.*]] = and i8 [[X:%.*]], [[TMP1]]
1152+
; CHECK-NEXT: [[RET:%.*]] = icmp eq i8 [[TMP2]], [[TMP1]]
11541153
; CHECK-NEXT: ret i1 [[RET]]
11551154
;
11561155
%t0 = shl i8 1, %c

0 commit comments

Comments
 (0)