Skip to content

Commit 45226d0

Browse files
committed
[InstCombine] Reuse icmp of and/or folds for logical and/or
Similarly to a change recently done for fcmps, add a flag that indicates whether the and/or is logical to foldAndOrOfICmps, and reuse the function when folding logical and/or. We were already calling some parts of it, but this gives us a clearer indication of which parts may need poison-safe variants, and would also allow to fold combinations of bitwise and logical and/or. This change should be close to NFC, because all folds this enables were either already called previously, or can make use of implied poison reasoning.
1 parent 72832ef commit 45226d0

3 files changed

Lines changed: 64 additions & 53 deletions

File tree

‎llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp‎

Lines changed: 58 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -872,6 +872,7 @@ static Value *foldSignedTruncationCheck(ICmpInst *ICmp0, ICmpInst *ICmp1,
872872

873873
/// Fold (icmp eq ctpop(X) 1) | (icmp eq X 0) into (icmp ult ctpop(X) 2) and
874874
/// fold (icmp ne ctpop(X) 1) & (icmp ne X 0) into (icmp ugt ctpop(X) 1).
875+
/// Also used for logical and/or, must be poison safe.
875876
static Value *foldIsPowerOf2OrZero(ICmpInst *Cmp0, ICmpInst *Cmp1, bool IsAnd,
876877
InstCombiner::BuilderTy &Builder) {
877878
CmpInst::Predicate Pred0, Pred1;
@@ -891,6 +892,7 @@ static Value *foldIsPowerOf2OrZero(ICmpInst *Cmp0, ICmpInst *Cmp1, bool IsAnd,
891892
}
892893

893894
/// Reduce a pair of compares that check if a value has exactly 1 bit set.
895+
/// Also used for logical and/or, must be poison safe.
894896
static Value *foldIsPowerOf2(ICmpInst *Cmp0, ICmpInst *Cmp1, bool JoinedByAnd,
895897
InstCombiner::BuilderTy &Builder) {
896898
// Handle 'and' / 'or' commutation: make the equality check the first operand.
@@ -1083,12 +1085,9 @@ Value *InstCombinerImpl::foldEqOfParts(ICmpInst *Cmp0, ICmpInst *Cmp1,
10831085
/// common operand with the constant. Callers are expected to call this with
10841086
/// Cmp0/Cmp1 switched to handle logic op commutativity.
10851087
static Value *foldAndOrOfICmpsWithConstEq(ICmpInst *Cmp0, ICmpInst *Cmp1,
1086-
BinaryOperator &Logic,
1088+
bool IsAnd,
10871089
InstCombiner::BuilderTy &Builder,
10881090
const SimplifyQuery &Q) {
1089-
bool IsAnd = Logic.getOpcode() == Instruction::And;
1090-
assert((IsAnd || Logic.getOpcode() == Instruction::Or) && "Wrong logic op");
1091-
10921091
// Match an equality compare with a non-poison constant as Cmp0.
10931092
// Also, give up if the compare can be constant-folded to avoid looping.
10941093
ICmpInst::Predicate Pred0;
@@ -1122,7 +1121,8 @@ static Value *foldAndOrOfICmpsWithConstEq(ICmpInst *Cmp0, ICmpInst *Cmp1,
11221121
return nullptr;
11231122
SubstituteCmp = Builder.CreateICmp(Pred1, Y, C);
11241123
}
1125-
return Builder.CreateBinOp(Logic.getOpcode(), Cmp0, SubstituteCmp);
1124+
return Builder.CreateBinOp(IsAnd ? Instruction::And : Instruction::Or, Cmp0,
1125+
SubstituteCmp);
11261126
}
11271127

11281128
/// Fold (icmp Pred1 V1, C1) & (icmp Pred2 V2, C2)
@@ -2389,14 +2389,17 @@ Value *foldAndOrOfICmpEqZeroAndICmp(ICmpInst *LHS, ICmpInst *RHS, bool IsAnd,
23892389
}
23902390

23912391
/// Fold (icmp)&(icmp) or (icmp)|(icmp) if possible.
2392+
/// If IsLogical is true, then the and/or is in select form and the transform
2393+
/// must be poison-safe.
23922394
Value *InstCombinerImpl::foldAndOrOfICmps(ICmpInst *LHS, ICmpInst *RHS,
2393-
BinaryOperator &BO, bool IsAnd) {
2394-
const SimplifyQuery Q = SQ.getWithInstruction(&BO);
2395+
Instruction &I, bool IsAnd,
2396+
bool IsLogical) {
2397+
const SimplifyQuery Q = SQ.getWithInstruction(&I);
23952398

23962399
// Fold (iszero(A & K1) | iszero(A & K2)) -> (A & (K1 | K2)) != (K1 | K2)
23972400
// Fold (!iszero(A & K1) & !iszero(A & K2)) -> (A & (K1 | K2)) == (K1 | K2)
23982401
// if K1 and K2 are a one-bit mask.
2399-
if (Value *V = foldAndOrOfICmpsOfAndWithPow2(LHS, RHS, &BO, IsAnd))
2402+
if (Value *V = foldAndOrOfICmpsOfAndWithPow2(LHS, RHS, &I, IsAnd, IsLogical))
24002403
return V;
24012404

24022405
ICmpInst::Predicate PredL = LHS->getPredicate(), PredR = RHS->getPredicate();
@@ -2421,56 +2424,75 @@ Value *InstCombinerImpl::foldAndOrOfICmps(ICmpInst *LHS, ICmpInst *RHS,
24212424
}
24222425
}
24232426

2424-
// handle (roughly):
2425-
// (icmp ne (A & B), C) | (icmp ne (A & D), E)
2426-
// (icmp eq (A & B), C) & (icmp eq (A & D), E)
2427-
if (Value *V = foldLogOpOfMaskedICmps(LHS, RHS, IsAnd, Builder))
2428-
return V;
2427+
// TODO: Some (but not all) of the patterns handled by this function are
2428+
// safe with logical and/or.
2429+
if (!IsLogical) {
2430+
// handle (roughly):
2431+
// (icmp ne (A & B), C) | (icmp ne (A & D), E)
2432+
// (icmp eq (A & B), C) & (icmp eq (A & D), E)
2433+
if (Value *V = foldLogOpOfMaskedICmps(LHS, RHS, IsAnd, Builder))
2434+
return V;
2435+
}
24292436

2430-
if (Value *V = foldAndOrOfICmpEqZeroAndICmp(LHS, RHS, IsAnd, Builder))
2431-
return V;
2432-
if (Value *V = foldAndOrOfICmpEqZeroAndICmp(RHS, LHS, IsAnd, Builder))
2433-
return V;
2437+
// TODO: One of these directions is fine with logical and/or, the other could
2438+
// be supported by inserting freeze.
2439+
if (!IsLogical) {
2440+
if (Value *V = foldAndOrOfICmpEqZeroAndICmp(LHS, RHS, IsAnd, Builder))
2441+
return V;
2442+
if (Value *V = foldAndOrOfICmpEqZeroAndICmp(RHS, LHS, IsAnd, Builder))
2443+
return V;
2444+
}
24342445

2435-
if (Value *V = foldAndOrOfICmpsWithConstEq(LHS, RHS, BO, Builder, Q))
2436-
return V;
2437-
if (Value *V = foldAndOrOfICmpsWithConstEq(RHS, LHS, BO, Builder, Q))
2438-
return V;
2446+
// TODO: Verify whether this is safe for logical and/or.
2447+
if (!IsLogical) {
2448+
if (Value *V = foldAndOrOfICmpsWithConstEq(LHS, RHS, IsAnd, Builder, Q))
2449+
return V;
2450+
if (Value *V = foldAndOrOfICmpsWithConstEq(RHS, LHS, IsAnd, Builder, Q))
2451+
return V;
2452+
}
24392453

24402454
if (Value *V = foldIsPowerOf2OrZero(LHS, RHS, IsAnd, Builder))
24412455
return V;
24422456
if (Value *V = foldIsPowerOf2OrZero(RHS, LHS, IsAnd, Builder))
24432457
return V;
24442458

2445-
// E.g. (icmp slt x, 0) | (icmp sgt x, n) --> icmp ugt x, n
2446-
// E.g. (icmp sge x, 0) & (icmp slt x, n) --> icmp ult x, n
2447-
if (Value *V = simplifyRangeCheck(LHS, RHS, /*Inverted=*/!IsAnd))
2448-
return V;
2459+
// TODO: One of these directions is fine with logical and/or, the other could
2460+
// be supported by inserting freeze.
2461+
if (!IsLogical) {
2462+
// E.g. (icmp slt x, 0) | (icmp sgt x, n) --> icmp ugt x, n
2463+
// E.g. (icmp sge x, 0) & (icmp slt x, n) --> icmp ult x, n
2464+
if (Value *V = simplifyRangeCheck(LHS, RHS, /*Inverted=*/!IsAnd))
2465+
return V;
24492466

2450-
// E.g. (icmp sgt x, n) | (icmp slt x, 0) --> icmp ugt x, n
2451-
// E.g. (icmp slt x, n) & (icmp sge x, 0) --> icmp ult x, n
2452-
if (Value *V = simplifyRangeCheck(RHS, LHS, /*Inverted=*/!IsAnd))
2453-
return V;
2467+
// E.g. (icmp sgt x, n) | (icmp slt x, 0) --> icmp ugt x, n
2468+
// E.g. (icmp slt x, n) & (icmp sge x, 0) --> icmp ult x, n
2469+
if (Value *V = simplifyRangeCheck(RHS, LHS, /*Inverted=*/!IsAnd))
2470+
return V;
2471+
}
24542472

2455-
if (IsAnd)
2456-
if (Value *V = foldSignedTruncationCheck(LHS, RHS, BO, Builder))
2473+
// TODO: Add conjugated or fold, check whether it is safe for logical and/or.
2474+
if (IsAnd && !IsLogical)
2475+
if (Value *V = foldSignedTruncationCheck(LHS, RHS, I, Builder))
24572476
return V;
24582477

24592478
if (Value *V = foldIsPowerOf2(LHS, RHS, IsAnd, Builder))
24602479
return V;
24612480

2462-
if (Value *X = foldUnsignedUnderflowCheck(LHS, RHS, IsAnd, Q, Builder))
2463-
return X;
2464-
if (Value *X = foldUnsignedUnderflowCheck(RHS, LHS, IsAnd, Q, Builder))
2465-
return X;
2481+
// TODO: Verify whether this is safe for logical and/or.
2482+
if (!IsLogical) {
2483+
if (Value *X = foldUnsignedUnderflowCheck(LHS, RHS, IsAnd, Q, Builder))
2484+
return X;
2485+
if (Value *X = foldUnsignedUnderflowCheck(RHS, LHS, IsAnd, Q, Builder))
2486+
return X;
2487+
}
24662488

24672489
if (Value *X = foldEqOfParts(LHS, RHS, IsAnd))
24682490
return X;
24692491

24702492
// (icmp ne A, 0) | (icmp ne B, 0) --> (icmp ne (A|B), 0)
24712493
// (icmp eq A, 0) & (icmp eq B, 0) --> (icmp eq (A|B), 0)
24722494
// TODO: Remove this when foldLogOpOfMaskedICmps can handle undefs.
2473-
if (PredL == (IsAnd ? ICmpInst::ICMP_EQ : ICmpInst::ICMP_NE) &&
2495+
if (!IsLogical && PredL == (IsAnd ? ICmpInst::ICMP_EQ : ICmpInst::ICMP_NE) &&
24742496
PredL == PredR && match(LHS1, m_ZeroInt()) && match(RHS1, m_ZeroInt()) &&
24752497
LHS0->getType() == RHS0->getType()) {
24762498
Value *NewOr = Builder.CreateOr(LHS0, RHS0);

‎llvm/lib/Transforms/InstCombine/InstCombineInternal.h‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -344,8 +344,8 @@ class LLVM_LIBRARY_VISIBILITY InstCombinerImpl final
344344
const CastInst *CI2);
345345
Value *simplifyIntToPtrRoundTripCast(Value *Val);
346346

347-
Value *foldAndOrOfICmps(ICmpInst *LHS, ICmpInst *RHS, BinaryOperator &BO,
348-
bool IsAnd);
347+
Value *foldAndOrOfICmps(ICmpInst *LHS, ICmpInst *RHS, Instruction &I,
348+
bool IsAnd, bool IsLogical = false);
349349
Value *foldXorOfICmps(ICmpInst *LHS, ICmpInst *RHS, BinaryOperator &Xor);
350350

351351
Value *foldEqOfParts(ICmpInst *Cmp0, ICmpInst *Cmp1, bool IsAnd);

‎llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp‎

Lines changed: 4 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2781,22 +2781,11 @@ Instruction *InstCombinerImpl::visitSelectInst(SelectInst &SI) {
27812781
/* IsAnd */ IsAnd))
27822782
return I;
27832783

2784-
if (auto *ICmp0 = dyn_cast<ICmpInst>(CondVal)) {
2785-
if (auto *ICmp1 = dyn_cast<ICmpInst>(Op1)) {
2786-
if (auto *V = foldAndOrOfICmpsOfAndWithPow2(ICmp0, ICmp1, &SI, IsAnd,
2787-
/* IsLogical */ true))
2784+
if (auto *ICmp0 = dyn_cast<ICmpInst>(CondVal))
2785+
if (auto *ICmp1 = dyn_cast<ICmpInst>(Op1))
2786+
if (auto *V = foldAndOrOfICmps(ICmp0, ICmp1, SI, IsAnd,
2787+
/* IsLogical */ true))
27882788
return replaceInstUsesWith(SI, V);
2789-
2790-
if (auto *V = foldEqOfParts(ICmp0, ICmp1, IsAnd))
2791-
return replaceInstUsesWith(SI, V);
2792-
2793-
// This pattern would usually be converted into a bitwise and/or based
2794-
// on "implies poison" reasoning. However, this may fail if adds with
2795-
// nowrap flags are involved.
2796-
if (auto *V = foldAndOrOfICmpsUsingRanges(ICmp0, ICmp1, IsAnd))
2797-
return replaceInstUsesWith(SI, V);
2798-
}
2799-
}
28002789
}
28012790

28022791
// select (select a, true, b), c, false -> select a, c, false

0 commit comments

Comments
 (0)