Skip to content

Commit d748c02

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

File tree

3 files changed

+62
-49
lines changed

3 files changed

+62
-49
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: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1406,6 +1406,48 @@ Instruction *InstCombinerImpl::foldSelectValueEquivalence(SelectInst &Sel,
14061406
return nullptr;
14071407
}
14081408

1409+
/// Fold the following code sequence:
1410+
/// \code
1411+
/// %XEq = icmp eq i64 %X, %Z
1412+
/// %YEq = icmp eq i64 %Y, %Z
1413+
/// %either = select i1 %XEq, i1 true, i1 %YEq
1414+
/// %both = select i1 %XEq, i1 %YEq, i1 false
1415+
/// %cmp = icmp eq i64 %X, %Y
1416+
/// %equal = select i1 %either, i1 %both, i1 %cmp
1417+
/// \code
1418+
///
1419+
/// into:
1420+
/// %equal = icmp eq i64 %X, %Y
1421+
///
1422+
/// Equivalently:
1423+
/// (X==Z || Y==Z) ? (X==Z && Y==Z) : X==Y --> X==Y
1424+
Instruction *InstCombinerImpl::foldSelectEqualityTest(SelectInst &Sel) {
1425+
Value *X, *Y, *Z, *XEq, *YEq;
1426+
Value *Either = Sel.getCondition(), *Both = Sel.getTrueValue(),
1427+
*Cmp = Sel.getFalseValue();
1428+
1429+
if (!match(Either, m_LogicalOr(m_Value(XEq), m_Value(YEq))))
1430+
return nullptr;
1431+
1432+
if (!match(XEq, m_SpecificICmp(ICmpInst::ICMP_EQ, m_Value(X), m_Value(Z))))
1433+
return nullptr;
1434+
if (!match(YEq,
1435+
m_c_SpecificICmp(ICmpInst::ICMP_EQ, m_Value(Y), m_Specific(Z))))
1436+
std::swap(X, Z);
1437+
if (!match(YEq,
1438+
m_c_SpecificICmp(ICmpInst::ICMP_EQ, m_Value(Y), m_Specific(Z))))
1439+
return nullptr;
1440+
1441+
if (!match(Both, m_c_LogicalAnd(m_Specific(XEq), m_Specific(YEq))))
1442+
return nullptr;
1443+
1444+
if (!match(Cmp,
1445+
m_c_SpecificICmp(ICmpInst::ICMP_EQ, m_Specific(X), m_Specific(Y))))
1446+
return nullptr;
1447+
1448+
return replaceInstUsesWith(Sel, Cmp);
1449+
}
1450+
14091451
// See if this is a pattern like:
14101452
// %old_cmp1 = icmp slt i32 %x, C2
14111453
// %old_replacement = select i1 %old_cmp1, i32 %target_low, i32 %target_high
@@ -4068,6 +4110,11 @@ Instruction *InstCombinerImpl::visitSelectInst(SelectInst &SI) {
40684110
if (Instruction *I = foldSelectOfSymmetricSelect(SI, Builder))
40694111
return I;
40704112

4113+
// This needs to happen before foldNestedSelects, as that could break the
4114+
// patterns that we test for.
4115+
if (Instruction *I = foldSelectEqualityTest(SI))
4116+
return I;
4117+
40714118
if (Instruction *I = foldNestedSelects(SI, Builder))
40724119
return I;
40734120

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

Lines changed: 14 additions & 49 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: [[XEQ:%.*]] = icmp eq i64 [[X:%.*]], [[Z:%.*]]
8-
; CHECK-NEXT: [[YEQ:%.*]] = icmp eq i64 [[Y:%.*]], [[Z]]
9-
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i64 [[X]], [[Y]]
10-
; CHECK-NEXT: [[NOT_YEQ:%.*]] = xor i1 [[YEQ]], true
11-
; CHECK-NEXT: [[BOTH:%.*]] = select i1 [[NOT_YEQ]], i1 [[CMP]], i1 false
12-
; CHECK-NEXT: [[EQUAL:%.*]] = select i1 [[XEQ]], i1 [[YEQ]], i1 [[BOTH]]
13-
; CHECK-NEXT: ret i1 [[EQUAL]]
7+
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i64 [[X:%.*]], [[Y:%.*]]
8+
; CHECK-NEXT: ret i1 [[CMP]]
149
;
1510
entry:
1611
%XEq = 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: [[XEQ:%.*]] = icmp eq i42 [[X:%.*]], -42
29-
; CHECK-NEXT: [[YEQ:%.*]] = icmp eq i42 [[Y:%.*]], -42
30-
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i42 [[X]], [[Y]]
31-
; CHECK-NEXT: [[NOT_YEQ:%.*]] = xor i1 [[YEQ]], true
32-
; CHECK-NEXT: [[BOTH:%.*]] = select i1 [[NOT_YEQ]], i1 [[CMP]], i1 false
33-
; CHECK-NEXT: [[EQUAL:%.*]] = select i1 [[XEQ]], i1 [[YEQ]], i1 [[BOTH]]
34-
; CHECK-NEXT: ret i1 [[EQUAL]]
23+
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i42 [[X:%.*]], [[Y:%.*]]
24+
; CHECK-NEXT: ret i1 [[CMP]]
3525
;
3626
entry:
3727
%XEq = icmp eq i42 %X, -42
@@ -46,13 +36,8 @@ entry:
4636
define <2 x i1> @icmp_equality_test_vector(<2 x i64> %X, <2 x i64> %Y) {
4737
; CHECK-LABEL: @icmp_equality_test_vector(
4838
; CHECK-NEXT: entry:
49-
; CHECK-NEXT: [[XEQ:%.*]] = icmp eq <2 x i64> [[X:%.*]], <i64 123, i64 456>
50-
; CHECK-NEXT: [[YEQ:%.*]] = icmp eq <2 x i64> [[Y:%.*]], <i64 123, i64 456>
51-
; CHECK-NEXT: [[CMP:%.*]] = icmp eq <2 x i64> [[X]], [[Y]]
52-
; CHECK-NEXT: [[NOT_YEQ:%.*]] = xor <2 x i1> [[YEQ]], <i1 true, i1 true>
53-
; CHECK-NEXT: [[BOTH:%.*]] = select <2 x i1> [[NOT_YEQ]], <2 x i1> [[CMP]], <2 x i1> zeroinitializer
54-
; CHECK-NEXT: [[EQUAL:%.*]] = select <2 x i1> [[XEQ]], <2 x i1> [[YEQ]], <2 x i1> [[BOTH]]
55-
; CHECK-NEXT: ret <2 x i1> [[EQUAL]]
39+
; CHECK-NEXT: [[CMP:%.*]] = icmp eq <2 x i64> [[X:%.*]], [[Y:%.*]]
40+
; CHECK-NEXT: ret <2 x i1> [[CMP]]
5641
;
5742
entry:
5843
%XEq = icmp eq <2 x i64> %X, <i64 123, i64 456>
@@ -67,13 +52,8 @@ entry:
6752
define i1 @icmp_equality_test_commute_icmp1(i64 %X, i64 %Y, i64 %Z) {
6853
; CHECK-LABEL: @icmp_equality_test_commute_icmp1(
6954
; CHECK-NEXT: entry:
70-
; CHECK-NEXT: [[XEQ:%.*]] = icmp eq i64 [[Z:%.*]], [[X:%.*]]
71-
; CHECK-NEXT: [[YEQ:%.*]] = icmp eq i64 [[Z]], [[Y:%.*]]
72-
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i64 [[Y]], [[X]]
73-
; CHECK-NEXT: [[NOT_YEQ:%.*]] = xor i1 [[YEQ]], true
74-
; CHECK-NEXT: [[BOTH:%.*]] = select i1 [[NOT_YEQ]], i1 [[CMP]], i1 false
75-
; CHECK-NEXT: [[EQUAL:%.*]] = select i1 [[XEQ]], i1 [[YEQ]], i1 [[BOTH]]
76-
; CHECK-NEXT: ret i1 [[EQUAL]]
55+
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i64 [[Y:%.*]], [[X:%.*]]
56+
; CHECK-NEXT: ret i1 [[CMP]]
7757
;
7858
entry:
7959
%XEq = icmp eq i64 %Z, %X
@@ -88,13 +68,8 @@ entry:
8868
define i1 @icmp_equality_test_commute_icmp2(i64 %X, i64 %Y, i64 %Z) {
8969
; CHECK-LABEL: @icmp_equality_test_commute_icmp2(
9070
; CHECK-NEXT: entry:
91-
; CHECK-NEXT: [[XEQ:%.*]] = icmp eq i64 [[Z:%.*]], [[X:%.*]]
92-
; CHECK-NEXT: [[YEQ:%.*]] = icmp eq i64 [[Y:%.*]], [[Z]]
93-
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i64 [[Y]], [[X]]
94-
; CHECK-NEXT: [[NOT_YEQ:%.*]] = xor i1 [[YEQ]], true
95-
; CHECK-NEXT: [[BOTH:%.*]] = select i1 [[NOT_YEQ]], i1 [[CMP]], i1 false
96-
; CHECK-NEXT: [[EQUAL:%.*]] = select i1 [[XEQ]], i1 [[YEQ]], i1 [[BOTH]]
97-
; CHECK-NEXT: ret i1 [[EQUAL]]
71+
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i64 [[Y:%.*]], [[X:%.*]]
72+
; CHECK-NEXT: ret i1 [[CMP]]
9873
;
9974
entry:
10075
%XEq = icmp eq i64 %Z, %X
@@ -109,13 +84,8 @@ entry:
10984
define i1 @icmp_equality_test_commute_select1(i64 %X, i64 %Y) {
11085
; CHECK-LABEL: @icmp_equality_test_commute_select1(
11186
; CHECK-NEXT: entry:
112-
; CHECK-NEXT: [[XEQ:%.*]] = icmp eq i64 [[X:%.*]], 0
113-
; CHECK-NEXT: [[YEQ:%.*]] = icmp eq i64 [[Y:%.*]], 0
114-
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i64 [[X]], [[Y]]
115-
; CHECK-NEXT: [[NOT_YEQ:%.*]] = xor i1 [[YEQ]], true
116-
; CHECK-NEXT: [[BOTH:%.*]] = select i1 [[NOT_YEQ]], i1 [[CMP]], i1 false
117-
; CHECK-NEXT: [[EQUAL:%.*]] = select i1 [[XEQ]], i1 [[YEQ]], i1 [[BOTH]]
118-
; CHECK-NEXT: ret i1 [[EQUAL]]
87+
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i64 [[X:%.*]], [[Y:%.*]]
88+
; CHECK-NEXT: ret i1 [[CMP]]
11989
;
12090
entry:
12191
%XEq = icmp eq i64 %X, 0
@@ -130,13 +100,8 @@ entry:
130100
define i1 @icmp_equality_test_commute_select2(i64 %X, i64 %Y) {
131101
; CHECK-LABEL: @icmp_equality_test_commute_select2(
132102
; CHECK-NEXT: entry:
133-
; CHECK-NEXT: [[XEQ:%.*]] = icmp eq i64 [[X:%.*]], 0
134-
; CHECK-NEXT: [[YEQ:%.*]] = icmp eq i64 [[Y:%.*]], 0
135-
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i64 [[X]], [[Y]]
136-
; CHECK-NEXT: [[NOT_XEQ:%.*]] = xor i1 [[XEQ]], true
137-
; CHECK-NEXT: [[BOTH:%.*]] = select i1 [[NOT_XEQ]], i1 [[CMP]], i1 false
138-
; CHECK-NEXT: [[EQUAL:%.*]] = select i1 [[YEQ]], i1 [[XEQ]], i1 [[BOTH]]
139-
; CHECK-NEXT: ret i1 [[EQUAL]]
103+
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i64 [[X:%.*]], [[Y:%.*]]
104+
; CHECK-NEXT: ret i1 [[CMP]]
140105
;
141106
entry:
142107
%XEq = icmp eq i64 %X, 0

0 commit comments

Comments
 (0)