Skip to content

Commit 46767d0

Browse files
committed
Add test for clamp like case where the first select is a ([s/z]ext (icmp))
This ([s/z]ext (icmp)) is equivilant to (select icmp, [1/-1], 0), so can be canonicalized too. This is generally not beneficial because after the canonicalization we lose the ability replace one of the selects with ([s/z]ext (icmp)). However, it is beneficial for this particular case: ``` %old_cmp1 = icmp sgt i32 %x, C2 %old_replacement = sext i1 %old_cmp1 to i32 %old_cmp0 = icmp ult i32 %x, C0 %r = select i1 %old_cmp0, i32 %x, i32 %old_replacement it can be rewriten as more canonical pattern: %new_cmp2 = icmp sge i32 %x, C0 %new_clamped_low = smax i32 %target_low, i32 %x %r = select i1 %new_cmp2, i32 -1, i32 %new_clamped_low Iff 0 s<= C2 s<= C0 ``` The select can be lowered to: ``` %sext_cmp2 = sext i1 %new_cmp2 to i32 %r = or i32 %sext_cmp2, i32 %new_clamped_low ```
1 parent 62d0b71 commit 46767d0

File tree

1 file changed

+163
-0
lines changed

1 file changed

+163
-0
lines changed
Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2+
; RUN: opt < %s -passes='instcombine<no-verify-fixpoint>' -S | FileCheck %s
3+
4+
; Given a pattern like:
5+
; %old_cmp1 = icmp sgt i32 %x, C2
6+
; %old_replacement = sext i1 %old_cmp1 to i32
7+
; %old_cmp0 = icmp ult i32 %x, C0
8+
; %r = select i1 %old_cmp0, i32 %x, i32 %old_replacement
9+
; it can be rewriten as more canonical pattern:
10+
; %new_cmp2 = icmp sge i32 %x, C0
11+
; %new_clamped_low = smax i32 %target_low, i32 %x
12+
; %r = select i1 %new_cmp2, i32 -1, i32 %new_clamped_low
13+
; Iff 0 s<= C2 s<= C0
14+
; Also, ULT predicate can also be UGE; or UGT iff C0 != -1 (+invert result)
15+
; Also, SLT predicate can also be SGE; or SGT iff C2 != INT_MAX (+invert res.)
16+
17+
;-------------------------------------------------------------------------------
18+
19+
; clamp-like max case, can be optimized with max
20+
define i32 @clamp_max_sgt(i32 %x) {
21+
; CHECK-LABEL: @clamp_max_sgt(
22+
; CHECK-NEXT: [[OR_COND:%.*]] = icmp ult i32 [[X:%.*]], 256
23+
; CHECK-NEXT: [[CMP2:%.*]] = icmp sgt i32 [[X]], 0
24+
; CHECK-NEXT: [[COND:%.*]] = sext i1 [[CMP2]] to i32
25+
; CHECK-NEXT: [[COND3:%.*]] = select i1 [[OR_COND]], i32 [[X]], i32 [[COND]]
26+
; CHECK-NEXT: ret i32 [[COND3]]
27+
;
28+
%or.cond = icmp ult i32 %x, 256
29+
%cmp2 = icmp sgt i32 %x, 0
30+
%cond = sext i1 %cmp2 to i32
31+
%cond3 = select i1 %or.cond, i32 %x, i32 %cond
32+
ret i32 %cond3
33+
}
34+
35+
; clamp-like max case with vector, can be optimized with max
36+
define <2 x i32> @clamp_max_sgt_vec(<2 x i32> %x) {
37+
; CHECK-LABEL: @clamp_max_sgt_vec(
38+
; CHECK-NEXT: [[OR_COND:%.*]] = icmp ult <2 x i32> [[X:%.*]], <i32 100, i32 256>
39+
; CHECK-NEXT: [[CMP2:%.*]] = icmp sgt <2 x i32> [[X]], <i32 98, i32 254>
40+
; CHECK-NEXT: [[COND:%.*]] = sext <2 x i1> [[CMP2]] to <2 x i32>
41+
; CHECK-NEXT: [[COND3:%.*]] = select <2 x i1> [[OR_COND]], <2 x i32> [[X]], <2 x i32> [[COND]]
42+
; CHECK-NEXT: ret <2 x i32> [[COND3]]
43+
;
44+
%or.cond = icmp ult <2 x i32> %x, <i32 100, i32 256>
45+
%cmp2 = icmp sgt <2 x i32> %x, <i32 98, i32 254>
46+
%cond = sext <2 x i1> %cmp2 to <2 x i32>
47+
%cond3 = select <2 x i1> %or.cond, <2 x i32> %x, <2 x i32> %cond
48+
ret <2 x i32> %cond3
49+
}
50+
51+
; Not clamp-like vector
52+
define <2 x i32> @clamp_max_vec(<2 x i32> %x) {
53+
; CHECK-LABEL: @clamp_max_vec(
54+
; CHECK-NEXT: [[OR_COND:%.*]] = icmp ult <2 x i32> [[X:%.*]], <i32 100, i32 256>
55+
; CHECK-NEXT: [[CMP2:%.*]] = icmp sgt <2 x i32> [[X]], <i32 128, i32 0>
56+
; CHECK-NEXT: [[COND:%.*]] = sext <2 x i1> [[CMP2]] to <2 x i32>
57+
; CHECK-NEXT: [[COND3:%.*]] = select <2 x i1> [[OR_COND]], <2 x i32> [[X]], <2 x i32> [[COND]]
58+
; CHECK-NEXT: ret <2 x i32> [[COND3]]
59+
;
60+
%or.cond = icmp ult <2 x i32> %x, <i32 100, i32 256>
61+
%cmp2 = icmp sgt <2 x i32> %x, <i32 128, i32 0>
62+
%cond = sext <2 x i1> %cmp2 to <2 x i32>
63+
%cond3 = select <2 x i1> %or.cond, <2 x i32> %x, <2 x i32> %cond
64+
ret <2 x i32> %cond3
65+
}
66+
67+
; clamp-like max case, can be optimized with max
68+
define i32 @clamp_max_sgt_neg1(i32 %x) {
69+
; CHECK-LABEL: @clamp_max_sgt_neg1(
70+
; CHECK-NEXT: [[OR_COND:%.*]] = icmp ult i32 [[X:%.*]], 256
71+
; CHECK-NEXT: [[CMP2:%.*]] = icmp sgt i32 [[X]], -1
72+
; CHECK-NEXT: [[COND:%.*]] = sext i1 [[CMP2]] to i32
73+
; CHECK-NEXT: [[COND3:%.*]] = select i1 [[OR_COND]], i32 [[X]], i32 [[COND]]
74+
; CHECK-NEXT: ret i32 [[COND3]]
75+
;
76+
%or.cond = icmp ult i32 %x, 256
77+
%cmp2 = icmp sgt i32 %x, -1
78+
%cond = sext i1 %cmp2 to i32
79+
%cond3 = select i1 %or.cond, i32 %x, i32 %cond
80+
ret i32 %cond3
81+
}
82+
83+
; clamp-like max case, can be optimized with max
84+
define i32 @clamp_max_sge(i32 %x) {
85+
; CHECK-LABEL: @clamp_max_sge(
86+
; CHECK-NEXT: [[OR_COND:%.*]] = icmp ult i32 [[X:%.*]], 256
87+
; CHECK-NEXT: [[CMP2:%.*]] = icmp sgt i32 [[X]], -1
88+
; CHECK-NEXT: [[COND:%.*]] = sext i1 [[CMP2]] to i32
89+
; CHECK-NEXT: [[COND3:%.*]] = select i1 [[OR_COND]], i32 [[X]], i32 [[COND]]
90+
; CHECK-NEXT: ret i32 [[COND3]]
91+
;
92+
%or.cond = icmp ult i32 %x, 256
93+
%cmp2 = icmp sge i32 %x, 0
94+
%cond = sext i1 %cmp2 to i32
95+
%cond3 = select i1 %or.cond, i32 %x, i32 %cond
96+
ret i32 %cond3
97+
}
98+
99+
; Don't support SLT cases, need to select 0 as the low value, -1 as high value
100+
define i32 @clamp_max_slt(i32 %x) {
101+
; CHECK-LABEL: @clamp_max_slt(
102+
; CHECK-NEXT: [[OR_COND:%.*]] = icmp ult i32 [[X:%.*]], 256
103+
; CHECK-NEXT: [[COND:%.*]] = ashr i32 [[X]], 31
104+
; CHECK-NEXT: [[COND3:%.*]] = select i1 [[OR_COND]], i32 [[X]], i32 [[COND]]
105+
; CHECK-NEXT: ret i32 [[COND3]]
106+
;
107+
%or.cond = icmp ult i32 %x, 256
108+
%cmp2 = icmp slt i32 %x, 0
109+
%cond = sext i1 %cmp2 to i32
110+
%cond3 = select i1 %or.cond, i32 %x, i32 %cond
111+
ret i32 %cond3
112+
}
113+
114+
; Don't support SLE cases, need to select 0 as the low value, -1 as high value
115+
define i32 @clamp_max_sle(i32 %x) {
116+
; CHECK-LABEL: @clamp_max_sle(
117+
; CHECK-NEXT: [[OR_COND:%.*]] = icmp ult i32 [[X:%.*]], 256
118+
; CHECK-NEXT: [[CMP2:%.*]] = icmp slt i32 [[X]], 1
119+
; CHECK-NEXT: [[COND:%.*]] = sext i1 [[CMP2]] to i32
120+
; CHECK-NEXT: [[COND3:%.*]] = select i1 [[OR_COND]], i32 [[X]], i32 [[COND]]
121+
; CHECK-NEXT: ret i32 [[COND3]]
122+
;
123+
%or.cond = icmp ult i32 %x, 256
124+
%cmp2 = icmp sle i32 %x, 0
125+
%cond = sext i1 %cmp2 to i32
126+
%cond3 = select i1 %or.cond, i32 %x, i32 %cond
127+
ret i32 %cond3
128+
}
129+
130+
; Not selecting between 0, x, and -1, so can't be optimized with max
131+
; Select between 0, x, and 1
132+
define i32 @clamp_max_bad_values(i32 %x) {
133+
; CHECK-LABEL: @clamp_max_bad_values(
134+
; CHECK-NEXT: [[OR_COND:%.*]] = icmp ult i32 [[X:%.*]], 256
135+
; CHECK-NEXT: [[CMP2:%.*]] = icmp sgt i32 [[X]], 0
136+
; CHECK-NEXT: [[COND:%.*]] = zext i1 [[CMP2]] to i32
137+
; CHECK-NEXT: [[COND3:%.*]] = select i1 [[OR_COND]], i32 [[X]], i32 [[COND]]
138+
; CHECK-NEXT: ret i32 [[COND3]]
139+
;
140+
%or.cond = icmp ult i32 %x, 256
141+
%cmp2 = icmp sgt i32 %x, 0
142+
%cond = zext i1 %cmp2 to i32
143+
%cond3 = select i1 %or.cond, i32 %x, i32 %cond
144+
ret i32 %cond3
145+
}
146+
147+
; Boundaries of range are not 0 and x (x is some positive integer)
148+
define i32 @clamp_max_offset(i32 %x) {
149+
; CHECK-LABEL: @clamp_max_offset(
150+
; CHECK-NEXT: [[TMP1:%.*]] = add i32 [[X:%.*]], -10
151+
; CHECK-NEXT: [[OR_COND:%.*]] = icmp ult i32 [[TMP1]], 246
152+
; CHECK-NEXT: [[CMP2:%.*]] = icmp sgt i32 [[X]], 10
153+
; CHECK-NEXT: [[COND:%.*]] = sext i1 [[CMP2]] to i32
154+
; CHECK-NEXT: [[COND3:%.*]] = select i1 [[OR_COND]], i32 [[X]], i32 [[COND]]
155+
; CHECK-NEXT: ret i32 [[COND3]]
156+
;
157+
%1 = add i32 %x, -10
158+
%or.cond = icmp ult i32 %1, 246
159+
%cmp2 = icmp sgt i32 %x, 10
160+
%cond = sext i1 %cmp2 to i32
161+
%cond3 = select i1 %or.cond, i32 %x, i32 %cond
162+
ret i32 %cond3
163+
}

0 commit comments

Comments
 (0)