Skip to content

Commit a7c079a

Browse files
committed
[InstCombine] Support logical and in masked icmp fold
Most of the folds implemented in this function work fine with logical operations. We only need to be careful for the cases that work on non-constant masks, where the RHS operand shouldn't be poison. This is a conservative implementation that bails out of illegal transforms, but we could also change these to insert freeze instead.
1 parent 4aa32e1 commit a7c079a

File tree

2 files changed

+35
-43
lines changed

2 files changed

+35
-43
lines changed

llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -365,6 +365,7 @@ getMaskedTypeForICmpPair(Value *&A, Value *&B, Value *&C,
365365
/// (icmp(A & X) ==/!= Y), where the left-hand side is of type Mask_NotAllZeros
366366
/// and the right hand side is of type BMask_Mixed. For example,
367367
/// (icmp (A & 12) != 0) & (icmp (A & 15) == 8) -> (icmp (A & 15) == 8).
368+
/// Also used for logical and/or, must be poison safe.
368369
static Value *foldLogOpOfMaskedICmps_NotAllZeros_BMask_Mixed(
369370
ICmpInst *LHS, ICmpInst *RHS, bool IsAnd, Value *A, Value *B, Value *C,
370371
Value *D, Value *E, ICmpInst::Predicate PredL, ICmpInst::Predicate PredR,
@@ -486,6 +487,7 @@ static Value *foldLogOpOfMaskedICmps_NotAllZeros_BMask_Mixed(
486487
/// Try to fold (icmp(A & B) ==/!= 0) &/| (icmp(A & D) ==/!= E) into a single
487488
/// (icmp(A & X) ==/!= Y), where the left-hand side and the right hand side
488489
/// aren't of the common mask pattern type.
490+
/// Also used for logical and/or, must be poison safe.
489491
static Value *foldLogOpOfMaskedICmpsAsymmetric(
490492
ICmpInst *LHS, ICmpInst *RHS, bool IsAnd, Value *A, Value *B, Value *C,
491493
Value *D, Value *E, ICmpInst::Predicate PredL, ICmpInst::Predicate PredR,
@@ -520,6 +522,7 @@ static Value *foldLogOpOfMaskedICmpsAsymmetric(
520522
/// Try to fold (icmp(A & B) ==/!= C) &/| (icmp(A & D) ==/!= E)
521523
/// into a single (icmp(A & X) ==/!= Y).
522524
static Value *foldLogOpOfMaskedICmps(ICmpInst *LHS, ICmpInst *RHS, bool IsAnd,
525+
bool IsLogical,
523526
InstCombiner::BuilderTy &Builder) {
524527
Value *A = nullptr, *B = nullptr, *C = nullptr, *D = nullptr, *E = nullptr;
525528
ICmpInst::Predicate PredL = LHS->getPredicate(), PredR = RHS->getPredicate();
@@ -564,6 +567,8 @@ static Value *foldLogOpOfMaskedICmps(ICmpInst *LHS, ICmpInst *RHS, bool IsAnd,
564567
if (Mask & Mask_AllZeros) {
565568
// (icmp eq (A & B), 0) & (icmp eq (A & D), 0)
566569
// -> (icmp eq (A & (B|D)), 0)
570+
if (IsLogical && !isGuaranteedNotToBeUndefOrPoison(D))
571+
return nullptr; // TODO: Use freeze?
567572
Value *NewOr = Builder.CreateOr(B, D);
568573
Value *NewAnd = Builder.CreateAnd(A, NewOr);
569574
// We can't use C as zero because we might actually handle
@@ -575,13 +580,17 @@ static Value *foldLogOpOfMaskedICmps(ICmpInst *LHS, ICmpInst *RHS, bool IsAnd,
575580
if (Mask & BMask_AllOnes) {
576581
// (icmp eq (A & B), B) & (icmp eq (A & D), D)
577582
// -> (icmp eq (A & (B|D)), (B|D))
583+
if (IsLogical && !isGuaranteedNotToBeUndefOrPoison(D))
584+
return nullptr; // TODO: Use freeze?
578585
Value *NewOr = Builder.CreateOr(B, D);
579586
Value *NewAnd = Builder.CreateAnd(A, NewOr);
580587
return Builder.CreateICmp(NewCC, NewAnd, NewOr);
581588
}
582589
if (Mask & AMask_AllOnes) {
583590
// (icmp eq (A & B), A) & (icmp eq (A & D), A)
584591
// -> (icmp eq (A & (B&D)), A)
592+
if (IsLogical && !isGuaranteedNotToBeUndefOrPoison(D))
593+
return nullptr; // TODO: Use freeze?
585594
Value *NewAnd1 = Builder.CreateAnd(B, D);
586595
Value *NewAnd2 = Builder.CreateAnd(A, NewAnd1);
587596
return Builder.CreateICmp(NewCC, NewAnd2, A);
@@ -2442,15 +2451,11 @@ Value *InstCombinerImpl::foldAndOrOfICmps(ICmpInst *LHS, ICmpInst *RHS,
24422451
}
24432452
}
24442453

2445-
// TODO: Some (but not all) of the patterns handled by this function are
2446-
// safe with logical and/or.
2447-
if (!IsLogical) {
2448-
// handle (roughly):
2449-
// (icmp ne (A & B), C) | (icmp ne (A & D), E)
2450-
// (icmp eq (A & B), C) & (icmp eq (A & D), E)
2451-
if (Value *V = foldLogOpOfMaskedICmps(LHS, RHS, IsAnd, Builder))
2452-
return V;
2453-
}
2454+
// handle (roughly):
2455+
// (icmp ne (A & B), C) | (icmp ne (A & D), E)
2456+
// (icmp eq (A & B), C) & (icmp eq (A & D), E)
2457+
if (Value *V = foldLogOpOfMaskedICmps(LHS, RHS, IsAnd, IsLogical, Builder))
2458+
return V;
24542459

24552460
// TODO: One of these directions is fine with logical and/or, the other could
24562461
// be supported by inserting freeze.

llvm/test/Transforms/InstCombine/and-or-icmps.ll

Lines changed: 21 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1981,13 +1981,10 @@ define i1 @logical_or_logical_or_icmps_comm3(i8 %x, i8 %y, i8 %z) {
19811981

19821982
define i1 @bitwise_and_logical_and_masked_icmp_asymmetric(i1 %c, i32 %x) {
19831983
; CHECK-LABEL: @bitwise_and_logical_and_masked_icmp_asymmetric(
1984-
; CHECK-NEXT: [[X_M1:%.*]] = and i32 [[X:%.*]], 255
1985-
; CHECK-NEXT: [[C1:%.*]] = icmp ne i32 [[X_M1]], 0
1986-
; CHECK-NEXT: [[AND1:%.*]] = select i1 [[C1]], i1 [[C:%.*]], i1 false
1987-
; CHECK-NEXT: [[X_M2:%.*]] = and i32 [[X]], 11
1984+
; CHECK-NEXT: [[X_M2:%.*]] = and i32 [[X:%.*]], 11
19881985
; CHECK-NEXT: [[C2:%.*]] = icmp eq i32 [[X_M2]], 11
1989-
; CHECK-NEXT: [[AND2:%.*]] = and i1 [[AND1]], [[C2]]
1990-
; CHECK-NEXT: ret i1 [[AND2]]
1986+
; CHECK-NEXT: [[TMP1:%.*]] = select i1 [[C2]], i1 [[C:%.*]], i1 false
1987+
; CHECK-NEXT: ret i1 [[TMP1]]
19911988
;
19921989
%x.m1 = and i32 %x, 255
19931990
%c1 = icmp ne i32 %x.m1, 0
@@ -2000,13 +1997,10 @@ define i1 @bitwise_and_logical_and_masked_icmp_asymmetric(i1 %c, i32 %x) {
20001997

20011998
define i1 @bitwise_and_logical_and_masked_icmp_allzeros(i1 %c, i32 %x) {
20021999
; CHECK-LABEL: @bitwise_and_logical_and_masked_icmp_allzeros(
2003-
; CHECK-NEXT: [[X_M1:%.*]] = and i32 [[X:%.*]], 8
2004-
; CHECK-NEXT: [[C1:%.*]] = icmp eq i32 [[X_M1]], 0
2005-
; CHECK-NEXT: [[AND1:%.*]] = select i1 [[C1]], i1 [[C:%.*]], i1 false
2006-
; CHECK-NEXT: [[X_M2:%.*]] = and i32 [[X]], 7
2007-
; CHECK-NEXT: [[C2:%.*]] = icmp eq i32 [[X_M2]], 0
2008-
; CHECK-NEXT: [[AND2:%.*]] = and i1 [[AND1]], [[C2]]
2009-
; CHECK-NEXT: ret i1 [[AND2]]
2000+
; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[X:%.*]], 15
2001+
; CHECK-NEXT: [[TMP2:%.*]] = icmp eq i32 [[TMP1]], 0
2002+
; CHECK-NEXT: [[TMP3:%.*]] = select i1 [[TMP2]], i1 [[C:%.*]], i1 false
2003+
; CHECK-NEXT: ret i1 [[TMP3]]
20102004
;
20112005
%x.m1 = and i32 %x, 8
20122006
%c1 = icmp eq i32 %x.m1, 0
@@ -2019,13 +2013,11 @@ define i1 @bitwise_and_logical_and_masked_icmp_allzeros(i1 %c, i32 %x) {
20192013

20202014
define i1 @bitwise_and_logical_and_masked_icmp_allzeros_poison1(i1 %c, i32 %x, i32 %y) {
20212015
; CHECK-LABEL: @bitwise_and_logical_and_masked_icmp_allzeros_poison1(
2022-
; CHECK-NEXT: [[X_M1:%.*]] = and i32 [[X:%.*]], [[Y:%.*]]
2023-
; CHECK-NEXT: [[C1:%.*]] = icmp eq i32 [[X_M1]], 0
2024-
; CHECK-NEXT: [[AND1:%.*]] = select i1 [[C1]], i1 [[C:%.*]], i1 false
2025-
; CHECK-NEXT: [[X_M2:%.*]] = and i32 [[X]], 7
2026-
; CHECK-NEXT: [[C2:%.*]] = icmp eq i32 [[X_M2]], 0
2027-
; CHECK-NEXT: [[AND2:%.*]] = and i1 [[AND1]], [[C2]]
2028-
; CHECK-NEXT: ret i1 [[AND2]]
2016+
; CHECK-NEXT: [[TMP1:%.*]] = or i32 [[Y:%.*]], 7
2017+
; CHECK-NEXT: [[TMP2:%.*]] = and i32 [[TMP1]], [[X:%.*]]
2018+
; CHECK-NEXT: [[TMP3:%.*]] = icmp eq i32 [[TMP2]], 0
2019+
; CHECK-NEXT: [[TMP4:%.*]] = select i1 [[TMP3]], i1 [[C:%.*]], i1 false
2020+
; CHECK-NEXT: ret i1 [[TMP4]]
20292021
;
20302022
%x.m1 = and i32 %x, %y
20312023
%c1 = icmp eq i32 %x.m1, 0
@@ -2057,13 +2049,10 @@ define i1 @bitwise_and_logical_and_masked_icmp_allzeros_poison2(i1 %c, i32 %x, i
20572049

20582050
define i1 @bitwise_and_logical_and_masked_icmp_allones(i1 %c, i32 %x) {
20592051
; CHECK-LABEL: @bitwise_and_logical_and_masked_icmp_allones(
2060-
; CHECK-NEXT: [[X_M1:%.*]] = and i32 [[X:%.*]], 8
2061-
; CHECK-NEXT: [[C1:%.*]] = icmp ne i32 [[X_M1]], 0
2062-
; CHECK-NEXT: [[AND1:%.*]] = select i1 [[C1]], i1 [[C:%.*]], i1 false
2063-
; CHECK-NEXT: [[X_M2:%.*]] = and i32 [[X]], 7
2064-
; CHECK-NEXT: [[C2:%.*]] = icmp eq i32 [[X_M2]], 7
2065-
; CHECK-NEXT: [[AND2:%.*]] = and i1 [[AND1]], [[C2]]
2066-
; CHECK-NEXT: ret i1 [[AND2]]
2052+
; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[X:%.*]], 15
2053+
; CHECK-NEXT: [[TMP2:%.*]] = icmp eq i32 [[TMP1]], 15
2054+
; CHECK-NEXT: [[TMP3:%.*]] = select i1 [[TMP2]], i1 [[C:%.*]], i1 false
2055+
; CHECK-NEXT: ret i1 [[TMP3]]
20672056
;
20682057
%x.m1 = and i32 %x, 8
20692058
%c1 = icmp eq i32 %x.m1, 8
@@ -2076,13 +2065,11 @@ define i1 @bitwise_and_logical_and_masked_icmp_allones(i1 %c, i32 %x) {
20762065

20772066
define i1 @bitwise_and_logical_and_masked_icmp_allones_poison1(i1 %c, i32 %x, i32 %y) {
20782067
; CHECK-LABEL: @bitwise_and_logical_and_masked_icmp_allones_poison1(
2079-
; CHECK-NEXT: [[X_M1:%.*]] = and i32 [[X:%.*]], [[Y:%.*]]
2080-
; CHECK-NEXT: [[C1:%.*]] = icmp eq i32 [[X_M1]], [[Y]]
2081-
; CHECK-NEXT: [[AND1:%.*]] = select i1 [[C1]], i1 [[C:%.*]], i1 false
2082-
; CHECK-NEXT: [[X_M2:%.*]] = and i32 [[X]], 7
2083-
; CHECK-NEXT: [[C2:%.*]] = icmp eq i32 [[X_M2]], 7
2084-
; CHECK-NEXT: [[AND2:%.*]] = and i1 [[AND1]], [[C2]]
2085-
; CHECK-NEXT: ret i1 [[AND2]]
2068+
; CHECK-NEXT: [[TMP1:%.*]] = or i32 [[Y:%.*]], 7
2069+
; CHECK-NEXT: [[TMP2:%.*]] = and i32 [[TMP1]], [[X:%.*]]
2070+
; CHECK-NEXT: [[TMP3:%.*]] = icmp eq i32 [[TMP2]], [[TMP1]]
2071+
; CHECK-NEXT: [[TMP4:%.*]] = select i1 [[TMP3]], i1 [[C:%.*]], i1 false
2072+
; CHECK-NEXT: ret i1 [[TMP4]]
20862073
;
20872074
%x.m1 = and i32 %x, %y
20882075
%c1 = icmp eq i32 %x.m1, %y

0 commit comments

Comments
 (0)