llvm.org GIT mirror llvm / 14ebdf2
[ValueTracking] recognize more variants of smin/smax Try harder to detect obfuscated min/max patterns: the initial pattern was added with D9352 / rL236202. There was a bug fix for PR27137 at rL264996, but I think we can do better by folding the corresponding smax pattern and commuted variants. The codegen tests demonstrate the effect of ValueTracking on the backend via SelectionDAGBuilder. We can't expose these differences minimally in IR because we don't have smin/smax intrinsics for IR. Differential Revision: https://reviews.llvm.org/D26091 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@285499 91177308-0d34-0410-b5e6-96231b3b80d8 Sanjay Patel 3 years ago
4 changed file(s) with 33 addition(s) and 49 deletion(s). Raw diff Collapse all Expand all
39683968 }
39693969 }
39703970
3971 // Y >s C ? ~Y : ~C == ~Y , ~C)
3971 // (X >s C) ? ~X : ~C ==> (~X SMIN(~X, ~C)
3972 // (X (~X >s ~C) ? ~X : ~C ==> SMAX(~X, ~C)
39723973 const APInt *C2;
3973 if (match(FalseVal, m_APInt(C2))) {
3974 if (Pred == ICmpInst::ICMP_SGT &&
3975 CmpRHS->getType() == FalseVal->getType() && ~(*C1) == *C2 &&
3976 (match(TrueVal, m_Not(m_Specific(CmpLHS))) ||
3977 match(CmpLHS, m_Not(m_Specific(TrueVal))))) {
3978 LHS = TrueVal;
3979 RHS = FalseVal;
3980 return {SPF_SMIN, SPNB_NA, false};
3981 }
3974 if (match(TrueVal, m_Not(m_Specific(CmpLHS))) &&
3975 match(FalseVal, m_APInt(C2)) && ~(*C1) == *C2 &&
3976 (Pred == CmpInst::ICMP_SGT || Pred == CmpInst::ICMP_SLT)) {
3977 LHS = TrueVal;
3978 RHS = FalseVal;
3979 return {Pred == CmpInst::ICMP_SGT ? SPF_SMIN : SPF_SMAX, SPNB_NA, false};
3980 }
3981
3982 // (X >s C) ? ~C : ~X ==> (~X SMAX(~C, ~X)
3983 // (X (~X >s ~C) ? ~C : ~X ==> SMIN(~C, ~X)
3984 if (match(FalseVal, m_Not(m_Specific(CmpLHS))) &&
3985 match(TrueVal, m_APInt(C2)) && ~(*C1) == *C2 &&
3986 (Pred == CmpInst::ICMP_SGT || Pred == CmpInst::ICMP_SLT)) {
3987 LHS = TrueVal;
3988 RHS = FalseVal;
3989 return {Pred == CmpInst::ICMP_SGT ? SPF_SMAX : SPF_SMIN, SPNB_NA, false};
39823990 }
39833991 }
39843992
1717 ret <4 x i32> %sel
1818 }
1919
20 ; FIXME: These are signed min/max ops.
21
2220 define <4 x i32> @smin_vec2(<4 x i32> %x) {
2321 ; CHECK-LABEL: smin_vec2:
2422 ; CHECK: # BB#0:
2523 ; CHECK-NEXT: vpcmpeqd %xmm1, %xmm1, %xmm1
26 ; CHECK-NEXT: vpxor %xmm1, %xmm0, %xmm1
27 ; CHECK-NEXT: vpxor %xmm2, %xmm2, %xmm2
28 ; CHECK-NEXT: vpcmpgtd %xmm0, %xmm2, %xmm0
29 ; CHECK-NEXT: vpor %xmm1, %xmm0, %xmm0
24 ; CHECK-NEXT: vpxor %xmm1, %xmm0, %xmm0
25 ; CHECK-NEXT: vpminsd %xmm1, %xmm0, %xmm0
3026 ; CHECK-NEXT: retq
3127 ;
3228 %not_x = xor <4 x i32> %x,
3935 ; CHECK-LABEL: smax_vec1:
4036 ; CHECK: # BB#0:
4137 ; CHECK-NEXT: vpcmpeqd %xmm1, %xmm1, %xmm1
42 ; CHECK-NEXT: vpxor %xmm1, %xmm0, %xmm2
43 ; CHECK-NEXT: vpxor %xmm3, %xmm3, %xmm3
44 ; CHECK-NEXT: vpcmpgtd %xmm0, %xmm3, %xmm0
4538 ; CHECK-NEXT: vpxor %xmm1, %xmm0, %xmm0
46 ; CHECK-NEXT: vpor %xmm2, %xmm0, %xmm0
39 ; CHECK-NEXT: vpmaxsd %xmm1, %xmm0, %xmm0
4740 ; CHECK-NEXT: retq
4841 ;
4942 %not_x = xor <4 x i32> %x,
5649 ; CHECK-LABEL: smax_vec2:
5750 ; CHECK: # BB#0:
5851 ; CHECK-NEXT: vpcmpeqd %xmm1, %xmm1, %xmm1
59 ; CHECK-NEXT: vpxor %xmm1, %xmm0, %xmm1
60 ; CHECK-NEXT: vpxor %xmm2, %xmm2, %xmm2
61 ; CHECK-NEXT: vpcmpgtd %xmm2, %xmm0, %xmm0
62 ; CHECK-NEXT: vpor %xmm1, %xmm0, %xmm0
52 ; CHECK-NEXT: vpxor %xmm1, %xmm0, %xmm0
53 ; CHECK-NEXT: vpmaxsd %xmm1, %xmm0, %xmm0
6354 ; CHECK-NEXT: retq
6455 ;
6556 %not_x = xor <4 x i32> %x,
139139 ; max(min(%a, -1), -1) == -1 (swap predicate and select ops)
140140 define i32 @max_of_min_swap(i32 %a) {
141141 ; CHECK-LABEL: @max_of_min_swap(
142 ; CHECK-NEXT: [[NOT_A:%.*]] = xor i32 %a, -1
143 ; CHECK-NEXT: [[C0:%.*]] = icmp slt i32 %a, 0
144 ; CHECK-NEXT: [[S0:%.*]] = select i1 [[C0]], i32 -1, i32 [[NOT_A]]
145 ; CHECK-NEXT: [[C1:%.*]] = icmp sgt i32 [[S0]], -1
146 ; CHECK-NEXT: [[S1:%.*]] = select i1 [[C1]], i32 [[S0]], i32 -1
147 ; CHECK-NEXT: ret i32 [[S1]]
142 ; CHECK-NEXT: ret i32 -1
148143 ;
149144 %not_a = xor i32 %a, -1
150145 %c0 = icmp slt i32 %a, 0
157152 ; min(max(%a, -1), -1) == -1
158153 define i32 @min_of_max(i32 %a) {
159154 ; CHECK-LABEL: @min_of_max(
160 ; CHECK-NEXT: [[NOT_A:%.*]] = xor i32 %a, -1
161 ; CHECK-NEXT: [[C0:%.*]] = icmp slt i32 %a, 0
162 ; CHECK-NEXT: [[S0:%.*]] = select i1 [[C0]], i32 [[NOT_A]], i32 -1
163 ; CHECK-NEXT: [[C1:%.*]] = icmp slt i32 [[S0]], -1
164 ; CHECK-NEXT: [[S1:%.*]] = select i1 [[C1]], i32 [[S0]], i32 -1
165 ; CHECK-NEXT: ret i32 [[S1]]
155 ; CHECK-NEXT: ret i32 -1
166156 ;
167157 %not_a = xor i32 %a, -1
168158 %c0 = icmp slt i32 %a, 0
175165 ; min(max(%a, -1), -1) == -1 (swap predicate and select ops)
176166 define i32 @min_of_max_swap(i32 %a) {
177167 ; CHECK-LABEL: @min_of_max_swap(
178 ; CHECK-NEXT: [[NOT_A:%.*]] = xor i32 %a, -1
179 ; CHECK-NEXT: [[C0:%.*]] = icmp sgt i32 %a, 0
180 ; CHECK-NEXT: [[S0:%.*]] = select i1 [[C0]], i32 -1, i32 [[NOT_A]]
181 ; CHECK-NEXT: [[C1:%.*]] = icmp slt i32 [[S0]], -1
182 ; CHECK-NEXT: [[S1:%.*]] = select i1 [[C1]], i32 [[S0]], i32 -1
183 ; CHECK-NEXT: ret i32 [[S1]]
168 ; CHECK-NEXT: ret i32 -1
184169 ;
185170 %not_a = xor i32 %a, -1
186171 %c0 = icmp sgt i32 %a, 0
None ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
1 ; RUN: opt < %s -instcombine -S | FileCheck %s
21
32 ; PR1822
17641763 ret i32 %sel
17651764 }
17661765
1766 ; max(max(~a, -1), -1) --> max(~a, -1)
1767
17671768 define i32 @PR27137(i32 %a) {
17681769 ; CHECK-LABEL: @PR27137(
1769 ; CHECK-NEXT: %not_a = xor i32 %a, -1
1770 ; CHECK-NEXT: %c0 = icmp slt i32 %a, 0
1771 ; CHECK-NEXT: %s0 = select i1 %c0, i32 %not_a, i32 -1
1772 ; CHECK-NEXT: %c1 = icmp sgt i32 %s0, -1
1773 ; CHECK-NEXT: %s1 = select i1 %c1, i32 %s0, i32 -1
1774 ; CHECK-NEXT: ret i32 %s1
1770 ; CHECK-NEXT: [[NOT_A:%.*]] = xor i32 %a, -1
1771 ; CHECK-NEXT: [[C0:%.*]] = icmp slt i32 %a, 0
1772 ; CHECK-NEXT: [[S0:%.*]] = select i1 [[C0]], i32 [[NOT_A]], i32 -1
1773 ; CHECK-NEXT: ret i32 [[S0]]
1774 ;
17751775
17761776 %not_a = xor i32 %a, -1
17771777 %c0 = icmp slt i32 %a, 0