Skip to content

Commit f8cd042

Browse files
committed
[InstCombine] Fold (X==Z) ? (Y==Z) : (!(Y==Z) && X==Y) --> X==Y
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
1 parent ee4187e commit f8cd042

File tree

3 files changed

+58
-56
lines changed

3 files changed

+58
-56
lines changed

llvm/lib/Transforms/InstCombine/InstCombineInternal.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -734,6 +734,7 @@ class LLVM_LIBRARY_VISIBILITY InstCombinerImpl final
734734
Instruction *foldSelectOfBools(SelectInst &SI);
735735
Instruction *foldSelectToCmp(SelectInst &SI);
736736
Instruction *foldSelectExtConst(SelectInst &Sel);
737+
Instruction *foldSelectEqualityTest(SelectInst &SI);
737738
Instruction *foldSelectOpOp(SelectInst &SI, Instruction *TI, Instruction *FI);
738739
Instruction *foldSelectIntoOp(SelectInst &SI, Value *, Value *);
739740
Instruction *foldSPFofSPF(Instruction *Inner, SelectPatternFlavor SPF1,

llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1406,6 +1406,44 @@ Instruction *InstCombinerImpl::foldSelectValueEquivalence(SelectInst &Sel,
14061406
return nullptr;
14071407
}
14081408

1409+
/// Fold the following code sequence:
1410+
/// \code
1411+
/// %XeqZ = icmp eq i64 %X, %Z
1412+
/// %YeqZ = icmp eq i64 %Y, %Z
1413+
/// %XeqY = icmp eq i64 %X, %Y
1414+
/// %not.YeqZ = xor i1 %YeqZ, true
1415+
/// %and = select i1 %not.YeqZ, i1 %XeqY, i1 false
1416+
/// %equal = select i1 %XeqZ, i1 %YeqZ, i1 %and
1417+
/// \code
1418+
///
1419+
/// into:
1420+
/// %equal = icmp eq i64 %X, %Y
1421+
Instruction *InstCombinerImpl::foldSelectEqualityTest(SelectInst &Sel) {
1422+
Value *X, *Y, *Z;
1423+
Value *XeqY, *XeqZ = Sel.getCondition(), *YeqZ = Sel.getTrueValue();
1424+
1425+
if (!match(XeqZ, m_SpecificICmp(ICmpInst::ICMP_EQ, m_Value(X), m_Value(Z))))
1426+
return nullptr;
1427+
1428+
if (!match(YeqZ,
1429+
m_c_SpecificICmp(ICmpInst::ICMP_EQ, m_Value(Y), m_Specific(Z))))
1430+
std::swap(X, Z);
1431+
1432+
if (!match(YeqZ,
1433+
m_c_SpecificICmp(ICmpInst::ICMP_EQ, m_Value(Y), m_Specific(Z))))
1434+
return nullptr;
1435+
1436+
if (!match(Sel.getFalseValue(),
1437+
m_c_LogicalAnd(m_Not(m_Specific(YeqZ)), m_Value(XeqY))))
1438+
return nullptr;
1439+
1440+
if (!match(XeqY,
1441+
m_c_SpecificICmp(ICmpInst::ICMP_EQ, m_Specific(X), m_Specific(Y))))
1442+
return nullptr;
1443+
1444+
return replaceInstUsesWith(Sel, XeqY);
1445+
}
1446+
14091447
// See if this is a pattern like:
14101448
// %old_cmp1 = icmp slt i32 %x, C2
14111449
// %old_replacement = select i1 %old_cmp1, i32 %target_low, i32 %target_high
@@ -4084,6 +4122,9 @@ Instruction *InstCombinerImpl::visitSelectInst(SelectInst &SI) {
40844122
if (Instruction *I = foldSelectToCmp(SI))
40854123
return I;
40864124

4125+
if (Instruction *I = foldSelectEqualityTest(SI))
4126+
return I;
4127+
40874128
// Fold:
40884129
// (select A && B, T, F) -> (select A, (select B, T, F), F)
40894130
// (select A || B, T, F) -> (select A, T, (select B, T, F))

llvm/test/Transforms/InstCombine/icmp-equality-test.ll

Lines changed: 16 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,8 @@
44
define i1 @icmp_equality_test(i64 %X, i64 %Y, i64 %Z) {
55
; CHECK-LABEL: @icmp_equality_test(
66
; CHECK-NEXT: entry:
7-
; CHECK-NEXT: [[XEQZ:%.*]] = icmp eq i64 [[X:%.*]], [[Z:%.*]]
8-
; CHECK-NEXT: [[YEQZ:%.*]] = icmp eq i64 [[Y:%.*]], [[Z]]
9-
; CHECK-NEXT: [[XEQY:%.*]] = icmp eq i64 [[X]], [[Y]]
10-
; CHECK-NEXT: [[NOT_YEQZ:%.*]] = xor i1 [[YEQZ]], true
11-
; CHECK-NEXT: [[AND:%.*]] = select i1 [[NOT_YEQZ]], i1 [[XEQY]], i1 false
12-
; CHECK-NEXT: [[EQUAL:%.*]] = select i1 [[XEQZ]], i1 [[YEQZ]], i1 [[AND]]
13-
; CHECK-NEXT: ret i1 [[EQUAL]]
7+
; CHECK-NEXT: [[XEQY:%.*]] = icmp eq i64 [[X:%.*]], [[Y:%.*]]
8+
; CHECK-NEXT: ret i1 [[XEQY]]
149
;
1510
entry:
1611
%XeqZ = icmp eq i64 %X, %Z
@@ -25,13 +20,8 @@ entry:
2520
define i1 @icmp_equality_test_constant(i42 %X, i42 %Y) {
2621
; CHECK-LABEL: @icmp_equality_test_constant(
2722
; CHECK-NEXT: entry:
28-
; CHECK-NEXT: [[XEQC:%.*]] = icmp eq i42 [[X:%.*]], -42
29-
; CHECK-NEXT: [[YEQC:%.*]] = icmp eq i42 [[Y:%.*]], -42
30-
; CHECK-NEXT: [[XEQY:%.*]] = icmp eq i42 [[X]], [[Y]]
31-
; CHECK-NEXT: [[NOT_YEQC:%.*]] = xor i1 [[YEQC]], true
32-
; CHECK-NEXT: [[AND:%.*]] = select i1 [[NOT_YEQC]], i1 [[XEQY]], i1 false
33-
; CHECK-NEXT: [[EQUAL:%.*]] = select i1 [[XEQC]], i1 [[YEQC]], i1 [[AND]]
34-
; CHECK-NEXT: ret i1 [[EQUAL]]
23+
; CHECK-NEXT: [[XEQY:%.*]] = icmp eq i42 [[X:%.*]], [[Y:%.*]]
24+
; CHECK-NEXT: ret i1 [[XEQY]]
3525
;
3626
entry:
3727
%XeqC = icmp eq i42 %X, -42
@@ -46,13 +36,8 @@ entry:
4636
define i1 @icmp_equality_test_swift_optional_pointers(i64 %X, i64 %Y) {
4737
; CHECK-LABEL: @icmp_equality_test_swift_optional_pointers(
4838
; CHECK-NEXT: entry:
49-
; CHECK-NEXT: [[XEQC:%.*]] = icmp eq i64 [[X:%.*]], 0
50-
; CHECK-NEXT: [[YEQC:%.*]] = icmp eq i64 [[Y:%.*]], 0
51-
; CHECK-NEXT: [[XEQY:%.*]] = icmp eq i64 [[X]], [[Y]]
52-
; CHECK-NEXT: [[NOT_YEQC:%.*]] = xor i1 [[YEQC]], true
53-
; CHECK-NEXT: [[BOTH:%.*]] = select i1 [[NOT_YEQC]], i1 [[XEQY]], i1 false
54-
; CHECK-NEXT: [[EQUAL:%.*]] = select i1 [[XEQC]], i1 [[YEQC]], i1 [[BOTH]]
55-
; CHECK-NEXT: ret i1 [[EQUAL]]
39+
; CHECK-NEXT: [[XEQY:%.*]] = icmp eq i64 [[X:%.*]], [[Y:%.*]]
40+
; CHECK-NEXT: ret i1 [[XEQY]]
5641
;
5742
entry:
5843
%XeqC = icmp eq i64 %X, 0
@@ -67,13 +52,8 @@ entry:
6752
define <2 x i1> @icmp_equality_test_vector(<2 x i64> %X, <2 x i64> %Y) {
6853
; CHECK-LABEL: @icmp_equality_test_vector(
6954
; CHECK-NEXT: entry:
70-
; CHECK-NEXT: [[XEQC:%.*]] = icmp eq <2 x i64> [[X:%.*]], <i64 123, i64 456>
71-
; CHECK-NEXT: [[YEQC:%.*]] = icmp eq <2 x i64> [[Y:%.*]], <i64 123, i64 456>
72-
; CHECK-NEXT: [[XEQY:%.*]] = icmp eq <2 x i64> [[X]], [[Y]]
73-
; CHECK-NEXT: [[NOT_YEQC:%.*]] = xor <2 x i1> [[YEQC]], <i1 true, i1 true>
74-
; CHECK-NEXT: [[AND:%.*]] = select <2 x i1> [[NOT_YEQC]], <2 x i1> [[XEQY]], <2 x i1> zeroinitializer
75-
; CHECK-NEXT: [[EQUAL:%.*]] = select <2 x i1> [[XEQC]], <2 x i1> [[YEQC]], <2 x i1> [[AND]]
76-
; CHECK-NEXT: ret <2 x i1> [[EQUAL]]
55+
; CHECK-NEXT: [[XEQY:%.*]] = icmp eq <2 x i64> [[X:%.*]], [[Y:%.*]]
56+
; CHECK-NEXT: ret <2 x i1> [[XEQY]]
7757
;
7858
entry:
7959
%XeqC = icmp eq <2 x i64> %X, <i64 123, i64 456>
@@ -88,13 +68,8 @@ entry:
8868
define i1 @icmp_equality_test_commute_icmp1(i64 %X, i64 %Y, i64 %Z) {
8969
; CHECK-LABEL: @icmp_equality_test_commute_icmp1(
9070
; CHECK-NEXT: entry:
91-
; CHECK-NEXT: [[XEQZ:%.*]] = icmp eq i64 [[Z:%.*]], [[X:%.*]]
92-
; CHECK-NEXT: [[YEQZ:%.*]] = icmp eq i64 [[Z]], [[Y:%.*]]
93-
; CHECK-NEXT: [[XEQY:%.*]] = icmp eq i64 [[Y]], [[X]]
94-
; CHECK-NEXT: [[NOT_YEQZ:%.*]] = xor i1 [[YEQZ]], true
95-
; CHECK-NEXT: [[AND:%.*]] = select i1 [[NOT_YEQZ]], i1 [[XEQY]], i1 false
96-
; CHECK-NEXT: [[EQUAL:%.*]] = select i1 [[XEQZ]], i1 [[YEQZ]], i1 [[AND]]
97-
; CHECK-NEXT: ret i1 [[EQUAL]]
71+
; CHECK-NEXT: [[XEQY:%.*]] = icmp eq i64 [[Y:%.*]], [[X:%.*]]
72+
; CHECK-NEXT: ret i1 [[XEQY]]
9873
;
9974
entry:
10075
%XeqZ = icmp eq i64 %Z, %X
@@ -108,13 +83,8 @@ entry:
10883

10984
define i1 @icmp_equality_test_commute_icmp2(i64 %X, i64 %Y, i64 %Z) {
11085
; CHECK-LABEL: @icmp_equality_test_commute_icmp2(
111-
; CHECK-NEXT: [[XEQZ:%.*]] = icmp eq i64 [[Z:%.*]], [[X:%.*]]
112-
; CHECK-NEXT: [[YEQZ:%.*]] = icmp eq i64 [[Y:%.*]], [[Z]]
113-
; CHECK-NEXT: [[XEQY:%.*]] = icmp eq i64 [[Y]], [[X]]
114-
; CHECK-NEXT: [[NOT_YEQZ:%.*]] = xor i1 [[YEQZ]], true
115-
; CHECK-NEXT: [[AND:%.*]] = select i1 [[NOT_YEQZ]], i1 [[XEQY]], i1 false
116-
; CHECK-NEXT: [[EQUAL:%.*]] = select i1 [[XEQZ]], i1 [[YEQZ]], i1 [[AND]]
117-
; CHECK-NEXT: ret i1 [[EQUAL]]
86+
; CHECK-NEXT: [[XEQY:%.*]] = icmp eq i64 [[Y:%.*]], [[X:%.*]]
87+
; CHECK-NEXT: ret i1 [[XEQY]]
11888
;
11989
%XeqZ = icmp eq i64 %Z, %X
12090
%YeqZ = icmp eq i64 %Y, %Z
@@ -128,13 +98,8 @@ define i1 @icmp_equality_test_commute_icmp2(i64 %X, i64 %Y, i64 %Z) {
12898
define i1 @icmp_equality_test_commute_select1(i64 %X, i64 %Y, i64 %Z) {
12999
; CHECK-LABEL: @icmp_equality_test_commute_select1(
130100
; CHECK-NEXT: entry:
131-
; CHECK-NEXT: [[XEQZ:%.*]] = icmp eq i64 [[X:%.*]], [[Z:%.*]]
132-
; CHECK-NEXT: [[YEQZ:%.*]] = icmp eq i64 [[Y:%.*]], [[Z]]
133-
; CHECK-NEXT: [[XEQY:%.*]] = icmp eq i64 [[X]], [[Y]]
134-
; CHECK-NEXT: [[NOT_YEQZ:%.*]] = xor i1 [[YEQZ]], true
135-
; CHECK-NEXT: [[AND:%.*]] = select i1 [[NOT_YEQZ]], i1 [[XEQY]], i1 false
136-
; CHECK-NEXT: [[EQUAL:%.*]] = select i1 [[XEQZ]], i1 [[YEQZ]], i1 [[AND]]
137-
; CHECK-NEXT: ret i1 [[EQUAL]]
101+
; CHECK-NEXT: [[XEQY:%.*]] = icmp eq i64 [[X:%.*]], [[Y:%.*]]
102+
; CHECK-NEXT: ret i1 [[XEQY]]
138103
;
139104
entry:
140105
%XeqZ = icmp eq i64 %X, %Z
@@ -148,13 +113,8 @@ entry:
148113
define i1 @icmp_equality_test_commute_select2(i64 %X, i64 %Y, i64 %Z) {
149114
; CHECK-LABEL: @icmp_equality_test_commute_select2(
150115
; CHECK-NEXT: entry:
151-
; CHECK-NEXT: [[XEQZ_NOT:%.*]] = icmp eq i64 [[X:%.*]], [[Z:%.*]]
152-
; CHECK-NEXT: [[YEQZ:%.*]] = icmp eq i64 [[Y:%.*]], [[Z]]
153-
; CHECK-NEXT: [[XEQY:%.*]] = icmp eq i64 [[X]], [[Y]]
154-
; CHECK-NEXT: [[NOT_YEQZ:%.*]] = xor i1 [[YEQZ]], true
155-
; CHECK-NEXT: [[AND:%.*]] = select i1 [[NOT_YEQZ]], i1 [[XEQY]], i1 false
156-
; CHECK-NEXT: [[EQUAL:%.*]] = select i1 [[XEQZ_NOT]], i1 [[YEQZ]], i1 [[AND]]
157-
; CHECK-NEXT: ret i1 [[EQUAL]]
116+
; CHECK-NEXT: [[XEQY:%.*]] = icmp eq i64 [[X:%.*]], [[Y:%.*]]
117+
; CHECK-NEXT: ret i1 [[XEQY]]
158118
;
159119
entry:
160120
%XeqZ = icmp eq i64 %X, %Z

0 commit comments

Comments
 (0)