[InstCombine] Fold and of two ranges differing by mask

This is the de Morgan conjugated variant of the existing fold for
ors. Implement this by switching the range code to always work
on ors and perform invert operands at the start and end. This makes
reasoning easier and makes the extension more obviosuly correct.
This commit is contained in:
Nikita Popov 2022-04-29 11:31:12 +02:00
parent 713752610e
commit 5515263e44
2 changed files with 15 additions and 19 deletions

View File

@ -1187,23 +1187,20 @@ static Value *foldAndOrOfICmpsUsingRanges(
if (V1 != V2)
return nullptr;
ConstantRange CR1 = ConstantRange::makeExactICmpRegion(Pred1, C1);
ConstantRange CR1 = ConstantRange::makeExactICmpRegion(
IsAnd ? ICmpInst::getInversePredicate(Pred1) : Pred1, C1);
if (Offset1)
CR1 = CR1.subtract(*Offset1);
ConstantRange CR2 = ConstantRange::makeExactICmpRegion(Pred2, C2);
ConstantRange CR2 = ConstantRange::makeExactICmpRegion(
IsAnd ? ICmpInst::getInversePredicate(Pred2) : Pred2, C2);
if (Offset2)
CR2 = CR2.subtract(*Offset2);
Type *Ty = V1->getType();
Value *NewV = V1;
Optional<ConstantRange> CR =
IsAnd ? CR1.exactIntersectWith(CR2) : CR1.exactUnionWith(CR2);
Optional<ConstantRange> CR = CR1.exactUnionWith(CR2);
if (!CR) {
// TODO: Support and.
if (IsAnd)
return nullptr;
if (!BothHaveOneUse || CR1.isWrappedSet() || CR2.isWrappedSet())
return nullptr;
@ -1220,6 +1217,9 @@ static Value *foldAndOrOfICmpsUsingRanges(
NewV = Builder.CreateAnd(NewV, ConstantInt::get(Ty, ~LowerDiff));
}
if (IsAnd)
CR = CR->inverse();
CmpInst::Predicate NewPred;
APInt NewC, Offset;
CR->getEquivalentICmp(NewPred, NewC, Offset);

View File

@ -1183,12 +1183,10 @@ define i1 @and_ranges_signed_pred(i64 %x) {
define i1 @and_two_ranges_to_mask_and_range(i8 %c) {
; CHECK-LABEL: @and_two_ranges_to_mask_and_range(
; CHECK-NEXT: [[TMP1:%.*]] = add i8 [[C:%.*]], -123
; CHECK-NEXT: [[CMP1:%.*]] = icmp ult i8 [[TMP1]], -26
; CHECK-NEXT: [[TMP2:%.*]] = add i8 [[C]], -91
; CHECK-NEXT: [[CMP2:%.*]] = icmp ult i8 [[TMP2]], -26
; CHECK-NEXT: [[AND:%.*]] = and i1 [[CMP1]], [[CMP2]]
; CHECK-NEXT: ret i1 [[AND]]
; CHECK-NEXT: [[TMP1:%.*]] = and i8 [[C:%.*]], -33
; CHECK-NEXT: [[TMP2:%.*]] = add i8 [[TMP1]], -91
; CHECK-NEXT: [[TMP3:%.*]] = icmp ult i8 [[TMP2]], -26
; CHECK-NEXT: ret i1 [[TMP3]]
;
%c.off = add i8 %c, -97
%cmp1 = icmp ugt i8 %c.off, 25
@ -1234,11 +1232,9 @@ define i1 @and_two_ranges_to_mask_and_range_different_sizes(i8 %c) {
define i1 @and_two_ranges_to_mask_and_range_no_add_on_one_range(i16 %x) {
; CHECK-LABEL: @and_two_ranges_to_mask_and_range_no_add_on_one_range(
; CHECK-NEXT: [[CMP1:%.*]] = icmp ugt i16 [[X:%.*]], 11
; CHECK-NEXT: [[TMP1:%.*]] = add i16 [[X]], -28
; CHECK-NEXT: [[TMP2:%.*]] = icmp ult i16 [[TMP1]], -12
; CHECK-NEXT: [[AND:%.*]] = and i1 [[CMP1]], [[TMP2]]
; CHECK-NEXT: ret i1 [[AND]]
; CHECK-NEXT: [[TMP1:%.*]] = and i16 [[X:%.*]], -20
; CHECK-NEXT: [[TMP2:%.*]] = icmp ugt i16 [[TMP1]], 11
; CHECK-NEXT: ret i1 [[TMP2]]
;
%cmp1 = icmp uge i16 %x, 12
%cmp2 = icmp ult i16 %x, 16