Skip to content

Commit a422148

Browse files
committed
[InstCombine] Improve coverage of foldSelectValueEquivalence for constants
We don't need the `noundef` check if the new simplification is a constant. This cleans up regressions from folding multiuse: `(icmp eq/ne (sub/xor x, y), 0)` -> `(icmp eq/ne x, y)`.
1 parent 689dce0 commit a422148

File tree

3 files changed

+42
-30
lines changed

3 files changed

+42
-30
lines changed

llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp

+38-21
Original file line numberDiff line numberDiff line change
@@ -1288,38 +1288,55 @@ Instruction *InstCombinerImpl::foldSelectValueEquivalence(SelectInst &Sel,
12881288
Swapped = true;
12891289
}
12901290

1291-
// In X == Y ? f(X) : Z, try to evaluate f(Y) and replace the operand.
1292-
// Make sure Y cannot be undef though, as we might pick different values for
1293-
// undef in the icmp and in f(Y). Additionally, take care to avoid replacing
1294-
// X == Y ? X : Z with X == Y ? Y : Z, as that would lead to an infinite
1295-
// replacement cycle.
12961291
Value *CmpLHS = Cmp.getOperand(0), *CmpRHS = Cmp.getOperand(1);
1297-
if (TrueVal != CmpLHS && isGuaranteedNotToBeUndef(CmpRHS, SQ.AC, &Sel, &DT)) {
1298-
if (Value *V = simplifyWithOpReplaced(TrueVal, CmpLHS, CmpRHS, SQ,
1299-
/* AllowRefinement */ true))
1300-
// Require either the replacement or the simplification result to be a
1301-
// constant to avoid infinite loops.
1302-
// FIXME: Make this check more precise.
1303-
if (isa<Constant>(CmpRHS) || isa<Constant>(V))
1292+
auto ReplaceOldOpWithNewOp = [&](Value *OldOp,
1293+
Value *NewOp) -> Instruction * {
1294+
// In X == Y ? f(X) : Z, try to evaluate f(Y) and replace the operand.
1295+
// Take care to avoid replacing X == Y ? X : Z with X == Y ? Y : Z, as that
1296+
// would lead to an infinite replacement cycle.
1297+
// If we will be able to evaluate f(Y) to a constant, we can allow undef,
1298+
// otherwise Y cannot be undef as we might pick different values for undef
1299+
// in the icmp and in f(Y).
1300+
if (TrueVal == OldOp)
1301+
return nullptr;
1302+
1303+
if (Value *V = simplifyWithOpReplaced(TrueVal, OldOp, NewOp, SQ,
1304+
/* AllowRefinement=*/true)) {
1305+
// Need some guarantees about the new simplified op to ensure we don't inf
1306+
// loop.
1307+
// If we simplify to a constant, replace if we aren't creating new undef.
1308+
if (match(V, m_ImmConstant()) &&
1309+
isGuaranteedNotToBeUndef(V, SQ.AC, &Sel, &DT))
13041310
return replaceOperand(Sel, Swapped ? 2 : 1, V);
13051311

1312+
// If NewOp is a constant and OldOp is not replace iff NewOp doesn't
1313+
// contain and undef elements.
1314+
if (match(NewOp, m_ImmConstant())) {
1315+
if (isGuaranteedNotToBeUndef(NewOp, SQ.AC, &Sel, &DT))
1316+
return replaceOperand(Sel, Swapped ? 2 : 1, V);
1317+
return nullptr;
1318+
}
1319+
}
1320+
13061321
// Even if TrueVal does not simplify, we can directly replace a use of
13071322
// CmpLHS with CmpRHS, as long as the instruction is not used anywhere
13081323
// else and is safe to speculatively execute (we may end up executing it
13091324
// with different operands, which should not cause side-effects or trigger
13101325
// undefined behavior). Only do this if CmpRHS is a constant, as
13111326
// profitability is not clear for other cases.
13121327
// FIXME: Support vectors.
1313-
if (match(CmpRHS, m_ImmConstant()) && !match(CmpLHS, m_ImmConstant()) &&
1314-
!Cmp.getType()->isVectorTy())
1315-
if (replaceInInstruction(TrueVal, CmpLHS, CmpRHS))
1328+
if (OldOp == CmpLHS && match(NewOp, m_ImmConstant()) &&
1329+
!match(OldOp, m_ImmConstant()) && !Cmp.getType()->isVectorTy() &&
1330+
isGuaranteedNotToBeUndef(NewOp, SQ.AC, &Sel, &DT))
1331+
if (replaceInInstruction(TrueVal, OldOp, NewOp))
13161332
return &Sel;
1317-
}
1318-
if (TrueVal != CmpRHS && isGuaranteedNotToBeUndef(CmpLHS, SQ.AC, &Sel, &DT))
1319-
if (Value *V = simplifyWithOpReplaced(TrueVal, CmpRHS, CmpLHS, SQ,
1320-
/* AllowRefinement */ true))
1321-
if (isa<Constant>(CmpLHS) || isa<Constant>(V))
1322-
return replaceOperand(Sel, Swapped ? 2 : 1, V);
1333+
return nullptr;
1334+
};
1335+
1336+
if (Instruction *R = ReplaceOldOpWithNewOp(CmpLHS, CmpRHS))
1337+
return R;
1338+
if (Instruction *R = ReplaceOldOpWithNewOp(CmpRHS, CmpLHS))
1339+
return R;
13231340

13241341
auto *FalseInst = dyn_cast<Instruction>(FalseVal);
13251342
if (!FalseInst)

llvm/test/Transforms/InstCombine/abs-1.ll

+2-5
Original file line numberDiff line numberDiff line change
@@ -852,11 +852,8 @@ define i8 @abs_diff_signed_sgt_nuw_extra_use3(i8 %a, i8 %b) {
852852

853853
define i32 @abs_diff_signed_slt_swap_wrong_pred1(i32 %a, i32 %b) {
854854
; CHECK-LABEL: @abs_diff_signed_slt_swap_wrong_pred1(
855-
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[A:%.*]], [[B:%.*]]
856-
; CHECK-NEXT: [[SUB_BA:%.*]] = sub nsw i32 [[B]], [[A]]
857-
; CHECK-NEXT: [[SUB_AB:%.*]] = sub nsw i32 [[A]], [[B]]
858-
; CHECK-NEXT: [[COND:%.*]] = select i1 [[CMP]], i32 [[SUB_BA]], i32 [[SUB_AB]]
859-
; CHECK-NEXT: ret i32 [[COND]]
855+
; CHECK-NEXT: [[SUB_AB:%.*]] = sub nsw i32 [[A:%.*]], [[B:%.*]]
856+
; CHECK-NEXT: ret i32 [[SUB_AB]]
860857
;
861858
%cmp = icmp eq i32 %a, %b
862859
%sub_ba = sub nsw i32 %b, %a

llvm/test/Transforms/InstCombine/select.ll

+2-4
Original file line numberDiff line numberDiff line change
@@ -2838,8 +2838,7 @@ define <2 x i8> @select_replacement_add_eq_vec_undef_okay_todo(<2 x i8> %x, <2 x
28382838
define <2 x i8> @select_replacement_xor_eq_vec(<2 x i8> %x, <2 x i8> %y, <2 x i8> %z) {
28392839
; CHECK-LABEL: @select_replacement_xor_eq_vec(
28402840
; CHECK-NEXT: [[CMP:%.*]] = icmp eq <2 x i8> [[X:%.*]], [[Y:%.*]]
2841-
; CHECK-NEXT: [[ADD:%.*]] = xor <2 x i8> [[X]], [[Y]]
2842-
; CHECK-NEXT: [[SEL:%.*]] = select <2 x i1> [[CMP]], <2 x i8> [[ADD]], <2 x i8> [[Z:%.*]]
2841+
; CHECK-NEXT: [[SEL:%.*]] = select <2 x i1> [[CMP]], <2 x i8> zeroinitializer, <2 x i8> [[Z:%.*]]
28432842
; CHECK-NEXT: ret <2 x i8> [[SEL]]
28442843
;
28452844
%cmp = icmp eq <2 x i8> %x, %y
@@ -2905,8 +2904,7 @@ define i8 @select_replacement_sub_noundef_but_may_be_poison(i8 %x, i8 noundef %y
29052904
define i8 @select_replacement_sub(i8 %x, i8 %y, i8 %z) {
29062905
; CHECK-LABEL: @select_replacement_sub(
29072906
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[X:%.*]], [[Y:%.*]]
2908-
; CHECK-NEXT: [[SUB:%.*]] = sub i8 [[X]], [[Y]]
2909-
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP]], i8 [[SUB]], i8 [[Z:%.*]]
2907+
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP]], i8 0, i8 [[Z:%.*]]
29102908
; CHECK-NEXT: ret i8 [[SEL]]
29112909
;
29122910
%cmp = icmp eq i8 %x, %y

0 commit comments

Comments
 (0)