Skip to content

Commit

Permalink
[InstCombine] Fold (X==Z) ? (Y==Z) : (!(Y==Z) && X==Y) --> X==Y
Browse files Browse the repository at this point in the history
This corresponds to the canonicalized form of some logic that was
seen in Swift-generated code for comparing optional pointers:
`(X==Z || Y==Z) ? (X==Z && Y==Z) : X==Y --> X==Y`
where `Z` was the constant `0`.

https://alive2.llvm.org/ce/z/J_3aa9
  • Loading branch information
citymarina committed Sep 20, 2024
1 parent ee4187e commit f8cd042
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 56 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
41 changes: 41 additions & 0 deletions llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1406,6 +1406,44 @@ Instruction *InstCombinerImpl::foldSelectValueEquivalence(SelectInst &Sel,
return nullptr;
}

/// Fold the following code sequence:
/// \code
/// %XeqZ = icmp eq i64 %X, %Z
/// %YeqZ = icmp eq i64 %Y, %Z
/// %XeqY = icmp eq i64 %X, %Y
/// %not.YeqZ = xor i1 %YeqZ, true
/// %and = select i1 %not.YeqZ, i1 %XeqY, i1 false
/// %equal = select i1 %XeqZ, i1 %YeqZ, i1 %and
/// \code
///
/// into:
/// %equal = icmp eq i64 %X, %Y
Instruction *InstCombinerImpl::foldSelectEqualityTest(SelectInst &Sel) {
Value *X, *Y, *Z;
Value *XeqY, *XeqZ = Sel.getCondition(), *YeqZ = Sel.getTrueValue();

if (!match(XeqZ, m_SpecificICmp(ICmpInst::ICMP_EQ, m_Value(X), m_Value(Z))))
return nullptr;

if (!match(YeqZ,
m_c_SpecificICmp(ICmpInst::ICMP_EQ, m_Value(Y), m_Specific(Z))))
std::swap(X, Z);

if (!match(YeqZ,
m_c_SpecificICmp(ICmpInst::ICMP_EQ, m_Value(Y), m_Specific(Z))))
return nullptr;

if (!match(Sel.getFalseValue(),
m_c_LogicalAnd(m_Not(m_Specific(YeqZ)), m_Value(XeqY))))
return nullptr;

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

return replaceInstUsesWith(Sel, XeqY);
}

// 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 @@ -4084,6 +4122,9 @@ Instruction *InstCombinerImpl::visitSelectInst(SelectInst &SI) {
if (Instruction *I = foldSelectToCmp(SI))
return I;

if (Instruction *I = foldSelectEqualityTest(SI))
return I;

// Fold:
// (select A && B, T, F) -> (select A, (select B, T, F), F)
// (select A || B, T, F) -> (select A, T, (select B, T, F))
Expand Down
72 changes: 16 additions & 56 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: [[XEQZ:%.*]] = icmp eq i64 [[X:%.*]], [[Z:%.*]]
; CHECK-NEXT: [[YEQZ:%.*]] = icmp eq i64 [[Y:%.*]], [[Z]]
; CHECK-NEXT: [[XEQY:%.*]] = icmp eq i64 [[X]], [[Y]]
; CHECK-NEXT: [[NOT_YEQZ:%.*]] = xor i1 [[YEQZ]], true
; CHECK-NEXT: [[AND:%.*]] = select i1 [[NOT_YEQZ]], i1 [[XEQY]], i1 false
; CHECK-NEXT: [[EQUAL:%.*]] = select i1 [[XEQZ]], i1 [[YEQZ]], i1 [[AND]]
; CHECK-NEXT: ret i1 [[EQUAL]]
; CHECK-NEXT: [[XEQY:%.*]] = icmp eq i64 [[X:%.*]], [[Y:%.*]]
; CHECK-NEXT: ret i1 [[XEQY]]
;
entry:
%XeqZ = 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: [[XEQC:%.*]] = icmp eq i42 [[X:%.*]], -42
; CHECK-NEXT: [[YEQC:%.*]] = icmp eq i42 [[Y:%.*]], -42
; CHECK-NEXT: [[XEQY:%.*]] = icmp eq i42 [[X]], [[Y]]
; CHECK-NEXT: [[NOT_YEQC:%.*]] = xor i1 [[YEQC]], true
; CHECK-NEXT: [[AND:%.*]] = select i1 [[NOT_YEQC]], i1 [[XEQY]], i1 false
; CHECK-NEXT: [[EQUAL:%.*]] = select i1 [[XEQC]], i1 [[YEQC]], i1 [[AND]]
; CHECK-NEXT: ret i1 [[EQUAL]]
; CHECK-NEXT: [[XEQY:%.*]] = icmp eq i42 [[X:%.*]], [[Y:%.*]]
; CHECK-NEXT: ret i1 [[XEQY]]
;
entry:
%XeqC = icmp eq i42 %X, -42
Expand All @@ -46,13 +36,8 @@ entry:
define i1 @icmp_equality_test_swift_optional_pointers(i64 %X, i64 %Y) {
; CHECK-LABEL: @icmp_equality_test_swift_optional_pointers(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[XEQC:%.*]] = icmp eq i64 [[X:%.*]], 0
; CHECK-NEXT: [[YEQC:%.*]] = icmp eq i64 [[Y:%.*]], 0
; CHECK-NEXT: [[XEQY:%.*]] = icmp eq i64 [[X]], [[Y]]
; CHECK-NEXT: [[NOT_YEQC:%.*]] = xor i1 [[YEQC]], true
; CHECK-NEXT: [[BOTH:%.*]] = select i1 [[NOT_YEQC]], i1 [[XEQY]], i1 false
; CHECK-NEXT: [[EQUAL:%.*]] = select i1 [[XEQC]], i1 [[YEQC]], i1 [[BOTH]]
; CHECK-NEXT: ret i1 [[EQUAL]]
; CHECK-NEXT: [[XEQY:%.*]] = icmp eq i64 [[X:%.*]], [[Y:%.*]]
; CHECK-NEXT: ret i1 [[XEQY]]
;
entry:
%XeqC = icmp eq i64 %X, 0
Expand All @@ -67,13 +52,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: [[XEQC:%.*]] = icmp eq <2 x i64> [[X:%.*]], <i64 123, i64 456>
; CHECK-NEXT: [[YEQC:%.*]] = icmp eq <2 x i64> [[Y:%.*]], <i64 123, i64 456>
; CHECK-NEXT: [[XEQY:%.*]] = icmp eq <2 x i64> [[X]], [[Y]]
; CHECK-NEXT: [[NOT_YEQC:%.*]] = xor <2 x i1> [[YEQC]], <i1 true, i1 true>
; CHECK-NEXT: [[AND:%.*]] = select <2 x i1> [[NOT_YEQC]], <2 x i1> [[XEQY]], <2 x i1> zeroinitializer
; CHECK-NEXT: [[EQUAL:%.*]] = select <2 x i1> [[XEQC]], <2 x i1> [[YEQC]], <2 x i1> [[AND]]
; CHECK-NEXT: ret <2 x i1> [[EQUAL]]
; CHECK-NEXT: [[XEQY:%.*]] = icmp eq <2 x i64> [[X:%.*]], [[Y:%.*]]
; CHECK-NEXT: ret <2 x i1> [[XEQY]]
;
entry:
%XeqC = icmp eq <2 x i64> %X, <i64 123, i64 456>
Expand All @@ -88,13 +68,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: [[XEQZ:%.*]] = icmp eq i64 [[Z:%.*]], [[X:%.*]]
; CHECK-NEXT: [[YEQZ:%.*]] = icmp eq i64 [[Z]], [[Y:%.*]]
; CHECK-NEXT: [[XEQY:%.*]] = icmp eq i64 [[Y]], [[X]]
; CHECK-NEXT: [[NOT_YEQZ:%.*]] = xor i1 [[YEQZ]], true
; CHECK-NEXT: [[AND:%.*]] = select i1 [[NOT_YEQZ]], i1 [[XEQY]], i1 false
; CHECK-NEXT: [[EQUAL:%.*]] = select i1 [[XEQZ]], i1 [[YEQZ]], i1 [[AND]]
; CHECK-NEXT: ret i1 [[EQUAL]]
; CHECK-NEXT: [[XEQY:%.*]] = icmp eq i64 [[Y:%.*]], [[X:%.*]]
; CHECK-NEXT: ret i1 [[XEQY]]
;
entry:
%XeqZ = icmp eq i64 %Z, %X
Expand All @@ -108,13 +83,8 @@ entry:

define i1 @icmp_equality_test_commute_icmp2(i64 %X, i64 %Y, i64 %Z) {
; CHECK-LABEL: @icmp_equality_test_commute_icmp2(
; CHECK-NEXT: [[XEQZ:%.*]] = icmp eq i64 [[Z:%.*]], [[X:%.*]]
; CHECK-NEXT: [[YEQZ:%.*]] = icmp eq i64 [[Y:%.*]], [[Z]]
; CHECK-NEXT: [[XEQY:%.*]] = icmp eq i64 [[Y]], [[X]]
; CHECK-NEXT: [[NOT_YEQZ:%.*]] = xor i1 [[YEQZ]], true
; CHECK-NEXT: [[AND:%.*]] = select i1 [[NOT_YEQZ]], i1 [[XEQY]], i1 false
; CHECK-NEXT: [[EQUAL:%.*]] = select i1 [[XEQZ]], i1 [[YEQZ]], i1 [[AND]]
; CHECK-NEXT: ret i1 [[EQUAL]]
; CHECK-NEXT: [[XEQY:%.*]] = icmp eq i64 [[Y:%.*]], [[X:%.*]]
; CHECK-NEXT: ret i1 [[XEQY]]
;
%XeqZ = icmp eq i64 %Z, %X
%YeqZ = icmp eq i64 %Y, %Z
Expand All @@ -128,13 +98,8 @@ define i1 @icmp_equality_test_commute_icmp2(i64 %X, i64 %Y, i64 %Z) {
define i1 @icmp_equality_test_commute_select1(i64 %X, i64 %Y, i64 %Z) {
; CHECK-LABEL: @icmp_equality_test_commute_select1(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[XEQZ:%.*]] = icmp eq i64 [[X:%.*]], [[Z:%.*]]
; CHECK-NEXT: [[YEQZ:%.*]] = icmp eq i64 [[Y:%.*]], [[Z]]
; CHECK-NEXT: [[XEQY:%.*]] = icmp eq i64 [[X]], [[Y]]
; CHECK-NEXT: [[NOT_YEQZ:%.*]] = xor i1 [[YEQZ]], true
; CHECK-NEXT: [[AND:%.*]] = select i1 [[NOT_YEQZ]], i1 [[XEQY]], i1 false
; CHECK-NEXT: [[EQUAL:%.*]] = select i1 [[XEQZ]], i1 [[YEQZ]], i1 [[AND]]
; CHECK-NEXT: ret i1 [[EQUAL]]
; CHECK-NEXT: [[XEQY:%.*]] = icmp eq i64 [[X:%.*]], [[Y:%.*]]
; CHECK-NEXT: ret i1 [[XEQY]]
;
entry:
%XeqZ = icmp eq i64 %X, %Z
Expand All @@ -148,13 +113,8 @@ entry:
define i1 @icmp_equality_test_commute_select2(i64 %X, i64 %Y, i64 %Z) {
; CHECK-LABEL: @icmp_equality_test_commute_select2(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[XEQZ_NOT:%.*]] = icmp eq i64 [[X:%.*]], [[Z:%.*]]
; CHECK-NEXT: [[YEQZ:%.*]] = icmp eq i64 [[Y:%.*]], [[Z]]
; CHECK-NEXT: [[XEQY:%.*]] = icmp eq i64 [[X]], [[Y]]
; CHECK-NEXT: [[NOT_YEQZ:%.*]] = xor i1 [[YEQZ]], true
; CHECK-NEXT: [[AND:%.*]] = select i1 [[NOT_YEQZ]], i1 [[XEQY]], i1 false
; CHECK-NEXT: [[EQUAL:%.*]] = select i1 [[XEQZ_NOT]], i1 [[YEQZ]], i1 [[AND]]
; CHECK-NEXT: ret i1 [[EQUAL]]
; CHECK-NEXT: [[XEQY:%.*]] = icmp eq i64 [[X:%.*]], [[Y:%.*]]
; CHECK-NEXT: ret i1 [[XEQY]]
;
entry:
%XeqZ = icmp eq i64 %X, %Z
Expand Down

0 comments on commit f8cd042

Please sign in to comment.