Skip to content

Commit

Permalink
[InstCombine] Fold (X==Z || Y==Z) ? (X==Z && Y==Z) : X==Y --> X==Y
Browse files Browse the repository at this point in the history
This logic was seen in code generated by Swift for comparing optional pointers,
with `Z` being the constant `0`.

https://alive2.llvm.org/ce/z/Bpd8Yo
  • Loading branch information
citymarina committed Sep 17, 2024
1 parent 0af77da commit d748c02
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 49 deletions.
1 change: 1 addition & 0 deletions llvm/lib/Transforms/InstCombine/InstCombineInternal.h
Original file line number Diff line number Diff line change
Expand Up @@ -734,6 +734,7 @@ class LLVM_LIBRARY_VISIBILITY InstCombinerImpl final
Instruction *foldSelectOfBools(SelectInst &SI);
Instruction *foldSelectToCmp(SelectInst &SI);
Instruction *foldSelectExtConst(SelectInst &Sel);
Instruction *foldSelectEqualityTest(SelectInst &SI);
Instruction *foldSelectOpOp(SelectInst &SI, Instruction *TI, Instruction *FI);
Instruction *foldSelectIntoOp(SelectInst &SI, Value *, Value *);
Instruction *foldSPFofSPF(Instruction *Inner, SelectPatternFlavor SPF1,
Expand Down
47 changes: 47 additions & 0 deletions llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1406,6 +1406,48 @@ Instruction *InstCombinerImpl::foldSelectValueEquivalence(SelectInst &Sel,
return nullptr;
}

/// Fold the following code sequence:
/// \code
/// %XEq = icmp eq i64 %X, %Z
/// %YEq = icmp eq i64 %Y, %Z
/// %either = select i1 %XEq, i1 true, i1 %YEq
/// %both = select i1 %XEq, i1 %YEq, i1 false
/// %cmp = icmp eq i64 %X, %Y
/// %equal = select i1 %either, i1 %both, i1 %cmp
/// \code
///
/// into:
/// %equal = icmp eq i64 %X, %Y
///
/// Equivalently:
/// (X==Z || Y==Z) ? (X==Z && Y==Z) : X==Y --> X==Y
Instruction *InstCombinerImpl::foldSelectEqualityTest(SelectInst &Sel) {
Value *X, *Y, *Z, *XEq, *YEq;
Value *Either = Sel.getCondition(), *Both = Sel.getTrueValue(),
*Cmp = Sel.getFalseValue();

if (!match(Either, m_LogicalOr(m_Value(XEq), m_Value(YEq))))
return nullptr;

if (!match(XEq, m_SpecificICmp(ICmpInst::ICMP_EQ, m_Value(X), m_Value(Z))))
return nullptr;
if (!match(YEq,
m_c_SpecificICmp(ICmpInst::ICMP_EQ, m_Value(Y), m_Specific(Z))))
std::swap(X, Z);
if (!match(YEq,
m_c_SpecificICmp(ICmpInst::ICMP_EQ, m_Value(Y), m_Specific(Z))))
return nullptr;

if (!match(Both, m_c_LogicalAnd(m_Specific(XEq), m_Specific(YEq))))
return nullptr;

if (!match(Cmp,
m_c_SpecificICmp(ICmpInst::ICMP_EQ, m_Specific(X), m_Specific(Y))))
return nullptr;

return replaceInstUsesWith(Sel, Cmp);
}

// See if this is a pattern like:
// %old_cmp1 = icmp slt i32 %x, C2
// %old_replacement = select i1 %old_cmp1, i32 %target_low, i32 %target_high
Expand Down Expand Up @@ -4068,6 +4110,11 @@ Instruction *InstCombinerImpl::visitSelectInst(SelectInst &SI) {
if (Instruction *I = foldSelectOfSymmetricSelect(SI, Builder))
return I;

// This needs to happen before foldNestedSelects, as that could break the
// patterns that we test for.
if (Instruction *I = foldSelectEqualityTest(SI))
return I;

if (Instruction *I = foldNestedSelects(SI, Builder))
return I;

Expand Down
63 changes: 14 additions & 49 deletions llvm/test/Transforms/InstCombine/icmp-equality-test.ll
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,8 @@
define i1 @icmp_equality_test(i64 %X, i64 %Y, i64 %Z) {
; CHECK-LABEL: @icmp_equality_test(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[XEQ:%.*]] = icmp eq i64 [[X:%.*]], [[Z:%.*]]
; CHECK-NEXT: [[YEQ:%.*]] = icmp eq i64 [[Y:%.*]], [[Z]]
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i64 [[X]], [[Y]]
; CHECK-NEXT: [[NOT_YEQ:%.*]] = xor i1 [[YEQ]], true
; CHECK-NEXT: [[BOTH:%.*]] = select i1 [[NOT_YEQ]], i1 [[CMP]], i1 false
; CHECK-NEXT: [[EQUAL:%.*]] = select i1 [[XEQ]], i1 [[YEQ]], i1 [[BOTH]]
; CHECK-NEXT: ret i1 [[EQUAL]]
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i64 [[X:%.*]], [[Y:%.*]]
; CHECK-NEXT: ret i1 [[CMP]]
;
entry:
%XEq = icmp eq i64 %X, %Z
Expand All @@ -25,13 +20,8 @@ entry:
define i1 @icmp_equality_test_constant(i42 %X, i42 %Y) {
; CHECK-LABEL: @icmp_equality_test_constant(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[XEQ:%.*]] = icmp eq i42 [[X:%.*]], -42
; CHECK-NEXT: [[YEQ:%.*]] = icmp eq i42 [[Y:%.*]], -42
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i42 [[X]], [[Y]]
; CHECK-NEXT: [[NOT_YEQ:%.*]] = xor i1 [[YEQ]], true
; CHECK-NEXT: [[BOTH:%.*]] = select i1 [[NOT_YEQ]], i1 [[CMP]], i1 false
; CHECK-NEXT: [[EQUAL:%.*]] = select i1 [[XEQ]], i1 [[YEQ]], i1 [[BOTH]]
; CHECK-NEXT: ret i1 [[EQUAL]]
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i42 [[X:%.*]], [[Y:%.*]]
; CHECK-NEXT: ret i1 [[CMP]]
;
entry:
%XEq = icmp eq i42 %X, -42
Expand All @@ -46,13 +36,8 @@ entry:
define <2 x i1> @icmp_equality_test_vector(<2 x i64> %X, <2 x i64> %Y) {
; CHECK-LABEL: @icmp_equality_test_vector(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[XEQ:%.*]] = icmp eq <2 x i64> [[X:%.*]], <i64 123, i64 456>
; CHECK-NEXT: [[YEQ:%.*]] = icmp eq <2 x i64> [[Y:%.*]], <i64 123, i64 456>
; CHECK-NEXT: [[CMP:%.*]] = icmp eq <2 x i64> [[X]], [[Y]]
; CHECK-NEXT: [[NOT_YEQ:%.*]] = xor <2 x i1> [[YEQ]], <i1 true, i1 true>
; CHECK-NEXT: [[BOTH:%.*]] = select <2 x i1> [[NOT_YEQ]], <2 x i1> [[CMP]], <2 x i1> zeroinitializer
; CHECK-NEXT: [[EQUAL:%.*]] = select <2 x i1> [[XEQ]], <2 x i1> [[YEQ]], <2 x i1> [[BOTH]]
; CHECK-NEXT: ret <2 x i1> [[EQUAL]]
; CHECK-NEXT: [[CMP:%.*]] = icmp eq <2 x i64> [[X:%.*]], [[Y:%.*]]
; CHECK-NEXT: ret <2 x i1> [[CMP]]
;
entry:
%XEq = icmp eq <2 x i64> %X, <i64 123, i64 456>
Expand All @@ -67,13 +52,8 @@ entry:
define i1 @icmp_equality_test_commute_icmp1(i64 %X, i64 %Y, i64 %Z) {
; CHECK-LABEL: @icmp_equality_test_commute_icmp1(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[XEQ:%.*]] = icmp eq i64 [[Z:%.*]], [[X:%.*]]
; CHECK-NEXT: [[YEQ:%.*]] = icmp eq i64 [[Z]], [[Y:%.*]]
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i64 [[Y]], [[X]]
; CHECK-NEXT: [[NOT_YEQ:%.*]] = xor i1 [[YEQ]], true
; CHECK-NEXT: [[BOTH:%.*]] = select i1 [[NOT_YEQ]], i1 [[CMP]], i1 false
; CHECK-NEXT: [[EQUAL:%.*]] = select i1 [[XEQ]], i1 [[YEQ]], i1 [[BOTH]]
; CHECK-NEXT: ret i1 [[EQUAL]]
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i64 [[Y:%.*]], [[X:%.*]]
; CHECK-NEXT: ret i1 [[CMP]]
;
entry:
%XEq = icmp eq i64 %Z, %X
Expand All @@ -88,13 +68,8 @@ entry:
define i1 @icmp_equality_test_commute_icmp2(i64 %X, i64 %Y, i64 %Z) {
; CHECK-LABEL: @icmp_equality_test_commute_icmp2(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[XEQ:%.*]] = icmp eq i64 [[Z:%.*]], [[X:%.*]]
; CHECK-NEXT: [[YEQ:%.*]] = icmp eq i64 [[Y:%.*]], [[Z]]
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i64 [[Y]], [[X]]
; CHECK-NEXT: [[NOT_YEQ:%.*]] = xor i1 [[YEQ]], true
; CHECK-NEXT: [[BOTH:%.*]] = select i1 [[NOT_YEQ]], i1 [[CMP]], i1 false
; CHECK-NEXT: [[EQUAL:%.*]] = select i1 [[XEQ]], i1 [[YEQ]], i1 [[BOTH]]
; CHECK-NEXT: ret i1 [[EQUAL]]
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i64 [[Y:%.*]], [[X:%.*]]
; CHECK-NEXT: ret i1 [[CMP]]
;
entry:
%XEq = icmp eq i64 %Z, %X
Expand All @@ -109,13 +84,8 @@ entry:
define i1 @icmp_equality_test_commute_select1(i64 %X, i64 %Y) {
; CHECK-LABEL: @icmp_equality_test_commute_select1(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[XEQ:%.*]] = icmp eq i64 [[X:%.*]], 0
; CHECK-NEXT: [[YEQ:%.*]] = icmp eq i64 [[Y:%.*]], 0
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i64 [[X]], [[Y]]
; CHECK-NEXT: [[NOT_YEQ:%.*]] = xor i1 [[YEQ]], true
; CHECK-NEXT: [[BOTH:%.*]] = select i1 [[NOT_YEQ]], i1 [[CMP]], i1 false
; CHECK-NEXT: [[EQUAL:%.*]] = select i1 [[XEQ]], i1 [[YEQ]], i1 [[BOTH]]
; CHECK-NEXT: ret i1 [[EQUAL]]
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i64 [[X:%.*]], [[Y:%.*]]
; CHECK-NEXT: ret i1 [[CMP]]
;
entry:
%XEq = icmp eq i64 %X, 0
Expand All @@ -130,13 +100,8 @@ entry:
define i1 @icmp_equality_test_commute_select2(i64 %X, i64 %Y) {
; CHECK-LABEL: @icmp_equality_test_commute_select2(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[XEQ:%.*]] = icmp eq i64 [[X:%.*]], 0
; CHECK-NEXT: [[YEQ:%.*]] = icmp eq i64 [[Y:%.*]], 0
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i64 [[X]], [[Y]]
; CHECK-NEXT: [[NOT_XEQ:%.*]] = xor i1 [[XEQ]], true
; CHECK-NEXT: [[BOTH:%.*]] = select i1 [[NOT_XEQ]], i1 [[CMP]], i1 false
; CHECK-NEXT: [[EQUAL:%.*]] = select i1 [[YEQ]], i1 [[XEQ]], i1 [[BOTH]]
; CHECK-NEXT: ret i1 [[EQUAL]]
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i64 [[X:%.*]], [[Y:%.*]]
; CHECK-NEXT: ret i1 [[CMP]]
;
entry:
%XEq = icmp eq i64 %X, 0
Expand Down

0 comments on commit d748c02

Please sign in to comment.