Skip to content

Commit c034c44

Browse files
authored
[InstCombine] Fold select of symmetric selects (#99245)
fixes #98800 Fold patterns like: select c2 (select c1 a b) (select c1 b a) into: select (xor c1 c2) b a Alive2 proofs: https://alive2.llvm.org/ce/z/4QAm4K https://alive2.llvm.org/ce/z/vTVRnC
1 parent 77b2c68 commit c034c44

File tree

2 files changed

+151
-0
lines changed

2 files changed

+151
-0
lines changed

llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3012,6 +3012,32 @@ struct DecomposedSelect {
30123012
};
30133013
} // namespace
30143014

3015+
/// Folds patterns like:
3016+
/// select c2 (select c1 a b) (select c1 b a)
3017+
/// into:
3018+
/// select (xor c1 c2) b a
3019+
static Instruction *
3020+
foldSelectOfSymmetricSelect(SelectInst &OuterSelVal,
3021+
InstCombiner::BuilderTy &Builder) {
3022+
3023+
Value *OuterCond, *InnerCond, *InnerTrueVal, *InnerFalseVal;
3024+
if (!match(
3025+
&OuterSelVal,
3026+
m_Select(m_Value(OuterCond),
3027+
m_OneUse(m_Select(m_Value(InnerCond), m_Value(InnerTrueVal),
3028+
m_Value(InnerFalseVal))),
3029+
m_OneUse(m_Select(m_Deferred(InnerCond),
3030+
m_Deferred(InnerFalseVal),
3031+
m_Deferred(InnerTrueVal))))))
3032+
return nullptr;
3033+
3034+
if (OuterCond->getType() != InnerCond->getType())
3035+
return nullptr;
3036+
3037+
Value *Xor = Builder.CreateXor(InnerCond, OuterCond);
3038+
return SelectInst::Create(Xor, InnerFalseVal, InnerTrueVal);
3039+
}
3040+
30153041
/// Look for patterns like
30163042
/// %outer.cond = select i1 %inner.cond, i1 %alt.cond, i1 false
30173043
/// %inner.sel = select i1 %inner.cond, i8 %inner.sel.t, i8 %inner.sel.f
@@ -3987,6 +4013,9 @@ Instruction *InstCombinerImpl::visitSelectInst(SelectInst &SI) {
39874013
}
39884014
}
39894015

4016+
if (Instruction *I = foldSelectOfSymmetricSelect(SI, Builder))
4017+
return I;
4018+
39904019
if (Instruction *I = foldNestedSelects(SI, Builder))
39914020
return I;
39924021

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2+
; RUN: opt < %s -passes=instcombine -S | FileCheck %s
3+
4+
define i32 @select_of_symmetric_selects(i32 %a, i32 %b, i1 %c1, i1 %c2) {
5+
; CHECK-LABEL: @select_of_symmetric_selects(
6+
; CHECK-NEXT: [[TMP1:%.*]] = xor i1 [[C1:%.*]], [[C2:%.*]]
7+
; CHECK-NEXT: [[RET:%.*]] = select i1 [[TMP1]], i32 [[B:%.*]], i32 [[A:%.*]]
8+
; CHECK-NEXT: ret i32 [[RET]]
9+
;
10+
%sel1 = select i1 %c1, i32 %a, i32 %b
11+
%sel2 = select i1 %c1, i32 %b, i32 %a
12+
%ret = select i1 %c2, i32 %sel1, i32 %sel2
13+
ret i32 %ret
14+
}
15+
16+
define i32 @select_of_symmetric_selects_negative1(i32 %a, i32 %b, i1 %c1, i1 %c2) {
17+
; CHECK-LABEL: @select_of_symmetric_selects_negative1(
18+
; CHECK-NEXT: [[SEL1:%.*]] = select i1 [[C1:%.*]], i32 [[A:%.*]], i32 [[B:%.*]]
19+
; CHECK-NEXT: [[RET:%.*]] = select i1 [[C2:%.*]], i32 [[SEL1]], i32 [[A]]
20+
; CHECK-NEXT: ret i32 [[RET]]
21+
;
22+
%sel1 = select i1 %c1, i32 %a, i32 %b
23+
%sel2 = select i1 %c2, i32 %b, i32 %a
24+
%ret = select i1 %c2, i32 %sel1, i32 %sel2
25+
ret i32 %ret
26+
}
27+
28+
define i32 @select_of_symmetric_selects_negative2(i32 %a, i32 %b, i32 %c, i1 %c1, i1 %c2) {
29+
; CHECK-LABEL: @select_of_symmetric_selects_negative2(
30+
; CHECK-NEXT: [[SEL1:%.*]] = select i1 [[C1:%.*]], i32 [[A:%.*]], i32 [[B:%.*]]
31+
; CHECK-NEXT: [[SEL2:%.*]] = select i1 [[C1]], i32 [[B]], i32 [[C:%.*]]
32+
; CHECK-NEXT: [[RET:%.*]] = select i1 [[C2:%.*]], i32 [[SEL1]], i32 [[SEL2]]
33+
; CHECK-NEXT: ret i32 [[RET]]
34+
;
35+
%sel1 = select i1 %c1, i32 %a, i32 %b
36+
%sel2 = select i1 %c1, i32 %b, i32 %c
37+
%ret = select i1 %c2, i32 %sel1, i32 %sel2
38+
ret i32 %ret
39+
}
40+
41+
declare void @use(i32)
42+
43+
define i32 @select_of_symmetric_selects_multi_use1(i32 %a, i32 %b, i1 %c1, i1 %c2) {
44+
; CHECK-LABEL: @select_of_symmetric_selects_multi_use1(
45+
; CHECK-NEXT: [[SEL1:%.*]] = select i1 [[C1:%.*]], i32 [[A:%.*]], i32 [[B:%.*]]
46+
; CHECK-NEXT: [[SEL2:%.*]] = select i1 [[C1]], i32 [[B]], i32 [[A]]
47+
; CHECK-NEXT: call void @use(i32 [[SEL2]])
48+
; CHECK-NEXT: [[RET:%.*]] = select i1 [[C2:%.*]], i32 [[SEL1]], i32 [[SEL2]]
49+
; CHECK-NEXT: ret i32 [[RET]]
50+
;
51+
%sel1 = select i1 %c1, i32 %a, i32 %b
52+
%sel2 = select i1 %c1, i32 %b, i32 %a
53+
call void @use(i32 %sel2)
54+
%ret = select i1 %c2, i32 %sel1, i32 %sel2
55+
ret i32 %ret
56+
}
57+
58+
define i32 @select_of_symmetric_selects_multi_use2(i32 %a, i32 %b, i1 %c1, i1 %c2) {
59+
; CHECK-LABEL: @select_of_symmetric_selects_multi_use2(
60+
; CHECK-NEXT: [[SEL1:%.*]] = select i1 [[C1:%.*]], i32 [[A:%.*]], i32 [[B:%.*]]
61+
; CHECK-NEXT: call void @use(i32 [[SEL1]])
62+
; CHECK-NEXT: [[SEL2:%.*]] = select i1 [[C1]], i32 [[B]], i32 [[A]]
63+
; CHECK-NEXT: call void @use(i32 [[SEL2]])
64+
; CHECK-NEXT: [[RET:%.*]] = select i1 [[C2:%.*]], i32 [[SEL1]], i32 [[SEL2]]
65+
; CHECK-NEXT: ret i32 [[RET]]
66+
;
67+
%sel1 = select i1 %c1, i32 %a, i32 %b
68+
call void @use(i32 %sel1)
69+
%sel2 = select i1 %c1, i32 %b, i32 %a
70+
call void @use(i32 %sel2)
71+
%ret = select i1 %c2, i32 %sel1, i32 %sel2
72+
ret i32 %ret
73+
}
74+
75+
define i32 @select_of_symmetric_selects_commuted(i32 %a, i32 %b, i1 %c1, i1 %c2) {
76+
; CHECK-LABEL: @select_of_symmetric_selects_commuted(
77+
; CHECK-NEXT: [[TMP1:%.*]] = xor i1 [[C1:%.*]], [[C2:%.*]]
78+
; CHECK-NEXT: [[RET:%.*]] = select i1 [[TMP1]], i32 [[A:%.*]], i32 [[B:%.*]]
79+
; CHECK-NEXT: ret i32 [[RET]]
80+
;
81+
%sel1 = select i1 %c1, i32 %a, i32 %b
82+
%sel2 = select i1 %c1, i32 %b, i32 %a
83+
%ret = select i1 %c2, i32 %sel2, i32 %sel1
84+
ret i32 %ret
85+
}
86+
87+
define <4 x i32> @select_of_symmetric_selects_vector1(<4 x i32> %a, <4 x i32> %b, i1 %c1, i1 %c2) {
88+
; CHECK-LABEL: @select_of_symmetric_selects_vector1(
89+
; CHECK-NEXT: [[TMP1:%.*]] = xor i1 [[C1:%.*]], [[C2:%.*]]
90+
; CHECK-NEXT: [[RET:%.*]] = select i1 [[TMP1]], <4 x i32> [[A:%.*]], <4 x i32> [[B:%.*]]
91+
; CHECK-NEXT: ret <4 x i32> [[RET]]
92+
;
93+
%sel1 = select i1 %c1, <4 x i32> %a, <4 x i32> %b
94+
%sel2 = select i1 %c1, <4 x i32> %b, <4 x i32> %a
95+
%ret = select i1 %c2, <4 x i32> %sel2, <4 x i32> %sel1
96+
ret <4 x i32> %ret
97+
}
98+
99+
define <4 x i32> @select_of_symmetric_selects_vector2(<4 x i32> %a, <4 x i32> %b, <4 x i1> %c1, <4 x i1> %c2) {
100+
; CHECK-LABEL: @select_of_symmetric_selects_vector2(
101+
; CHECK-NEXT: [[TMP1:%.*]] = xor <4 x i1> [[C1:%.*]], [[C2:%.*]]
102+
; CHECK-NEXT: [[RET:%.*]] = select <4 x i1> [[TMP1]], <4 x i32> [[A:%.*]], <4 x i32> [[B:%.*]]
103+
; CHECK-NEXT: ret <4 x i32> [[RET]]
104+
;
105+
%sel1 = select <4 x i1> %c1, <4 x i32> %a, <4 x i32> %b
106+
%sel2 = select <4 x i1> %c1, <4 x i32> %b, <4 x i32> %a
107+
%ret = select <4 x i1> %c2, <4 x i32> %sel2, <4 x i32> %sel1
108+
ret <4 x i32> %ret
109+
}
110+
111+
define <2 x i32> @select_of_symmetric_selects_vector3(<2 x i32> %a, <2 x i32> %b, <2 x i1> %c1, i1 %c2) {
112+
; CHECK-LABEL: @select_of_symmetric_selects_vector3(
113+
; CHECK-NEXT: [[SEL1:%.*]] = select <2 x i1> [[C1:%.*]], <2 x i32> [[A:%.*]], <2 x i32> [[B:%.*]]
114+
; CHECK-NEXT: [[SEL2:%.*]] = select <2 x i1> [[C1]], <2 x i32> [[B]], <2 x i32> [[A]]
115+
; CHECK-NEXT: [[RET:%.*]] = select i1 [[C2:%.*]], <2 x i32> [[SEL1]], <2 x i32> [[SEL2]]
116+
; CHECK-NEXT: ret <2 x i32> [[RET]]
117+
;
118+
%sel1 = select <2 x i1> %c1, <2 x i32> %a, <2 x i32> %b
119+
%sel2 = select <2 x i1> %c1, <2 x i32> %b, <2 x i32> %a
120+
%ret = select i1 %c2, <2 x i32> %sel1, <2 x i32> %sel2
121+
ret <2 x i32> %ret
122+
}

0 commit comments

Comments
 (0)