@@ -182,3 +182,193 @@ define i8 @signed_add_neg5(i32 %a, i32 %b) {
182182 %r = add i8 %lt8 , %gt8
183183 ret i8 %r
184184}
185+
186+ ; sext(A s<= B) + zext(A s>= B) => scmp(A, B)
187+ define i8 @signed_add_ge_le (i32 %a , i32 %b ) {
188+ ; CHECK-LABEL: define i8 @signed_add_ge_le(
189+ ; CHECK-SAME: i32 [[A:%.*]], i32 [[B:%.*]]) {
190+ ; CHECK-NEXT: [[LE:%.*]] = icmp sle i32 [[A]], [[B]]
191+ ; CHECK-NEXT: [[LE8:%.*]] = sext i1 [[LE]] to i8
192+ ; CHECK-NEXT: [[GE:%.*]] = icmp sge i32 [[A]], [[B]]
193+ ; CHECK-NEXT: [[GE8:%.*]] = zext i1 [[GE]] to i8
194+ ; CHECK-NEXT: [[R:%.*]] = add nsw i8 [[LE8]], [[GE8]]
195+ ; CHECK-NEXT: ret i8 [[R]]
196+ ;
197+ %le = icmp sle i32 %a , %b
198+ %le8 = sext i1 %le to i8
199+ %ge = icmp sge i32 %a , %b
200+ %ge8 = zext i1 %ge to i8
201+ %r = add i8 %le8 , %ge8
202+ ret i8 %r
203+ }
204+
205+ ; Unsigned version of >= and <=
206+ define i8 @unsigned_add_ge_le (i32 %a , i32 %b ) {
207+ ; CHECK-LABEL: define i8 @unsigned_add_ge_le(
208+ ; CHECK-SAME: i32 [[A:%.*]], i32 [[B:%.*]]) {
209+ ; CHECK-NEXT: [[LE:%.*]] = icmp ule i32 [[A]], [[B]]
210+ ; CHECK-NEXT: [[LE8:%.*]] = sext i1 [[LE]] to i8
211+ ; CHECK-NEXT: [[GE:%.*]] = icmp uge i32 [[A]], [[B]]
212+ ; CHECK-NEXT: [[GE8:%.*]] = zext i1 [[GE]] to i8
213+ ; CHECK-NEXT: [[R:%.*]] = add nsw i8 [[LE8]], [[GE8]]
214+ ; CHECK-NEXT: ret i8 [[R]]
215+ ;
216+ %le = icmp ule i32 %a , %b
217+ %le8 = sext i1 %le to i8
218+ %ge = icmp uge i32 %a , %b
219+ %ge8 = zext i1 %ge to i8
220+ %r = add i8 %le8 , %ge8
221+ ret i8 %r
222+ }
223+
224+ ; zext(A s>= B) - zext(A s<= B) => scmp(A, B)
225+ define i8 @signed_sub_ge_le (i32 %a , i32 %b ) {
226+ ; CHECK-LABEL: define i8 @signed_sub_ge_le(
227+ ; CHECK-SAME: i32 [[A:%.*]], i32 [[B:%.*]]) {
228+ ; CHECK-NEXT: [[LE:%.*]] = icmp sle i32 [[A]], [[B]]
229+ ; CHECK-NEXT: [[LE8_NEG:%.*]] = sext i1 [[LE]] to i8
230+ ; CHECK-NEXT: [[GE:%.*]] = icmp sge i32 [[A]], [[B]]
231+ ; CHECK-NEXT: [[GE8:%.*]] = zext i1 [[GE]] to i8
232+ ; CHECK-NEXT: [[R:%.*]] = add nsw i8 [[LE8_NEG]], [[GE8]]
233+ ; CHECK-NEXT: ret i8 [[R]]
234+ ;
235+ %le = icmp sle i32 %a , %b
236+ %le8 = zext i1 %le to i8
237+ %ge = icmp sge i32 %a , %b
238+ %ge8 = zext i1 %ge to i8
239+ %r = sub i8 %ge8 , %le8
240+ ret i8 %r
241+ }
242+
243+ ; Unsigned version of >= and <= subtraction
244+ define i8 @unsigned_sub_ge_le (i32 %a , i32 %b ) {
245+ ; CHECK-LABEL: define i8 @unsigned_sub_ge_le(
246+ ; CHECK-SAME: i32 [[A:%.*]], i32 [[B:%.*]]) {
247+ ; CHECK-NEXT: [[LE:%.*]] = icmp ule i32 [[A]], [[B]]
248+ ; CHECK-NEXT: [[LE8_NEG:%.*]] = sext i1 [[LE]] to i8
249+ ; CHECK-NEXT: [[GE:%.*]] = icmp uge i32 [[A]], [[B]]
250+ ; CHECK-NEXT: [[GE8:%.*]] = zext i1 [[GE]] to i8
251+ ; CHECK-NEXT: [[R:%.*]] = add nsw i8 [[LE8_NEG]], [[GE8]]
252+ ; CHECK-NEXT: ret i8 [[R]]
253+ ;
254+ %le = icmp ule i32 %a , %b
255+ %le8 = zext i1 %le to i8
256+ %ge = icmp uge i32 %a , %b
257+ %ge8 = zext i1 %ge to i8
258+ %r = sub i8 %ge8 , %le8
259+ ret i8 %r
260+ }
261+
262+ ; Constant canonicalization: (a > 4) - (a < 6) => scmp(a, 5)
263+ define i8 @signed_sub_const_canonicalization (i32 %a ) {
264+ ; CHECK-LABEL: define i8 @signed_sub_const_canonicalization(
265+ ; CHECK-SAME: i32 [[A:%.*]]) {
266+ ; CHECK-NEXT: [[LT:%.*]] = icmp slt i32 [[A]], 6
267+ ; CHECK-NEXT: [[LT8_NEG:%.*]] = sext i1 [[LT]] to i8
268+ ; CHECK-NEXT: [[GT:%.*]] = icmp sgt i32 [[A]], 4
269+ ; CHECK-NEXT: [[GT8:%.*]] = zext i1 [[GT]] to i8
270+ ; CHECK-NEXT: [[R:%.*]] = add nsw i8 [[LT8_NEG]], [[GT8]]
271+ ; CHECK-NEXT: ret i8 [[R]]
272+ ;
273+ %lt = icmp slt i32 %a , 6
274+ %lt8 = zext i1 %lt to i8
275+ %gt = icmp sgt i32 %a , 4
276+ %gt8 = zext i1 %gt to i8
277+ %r = sub i8 %gt8 , %lt8
278+ ret i8 %r
279+ }
280+
281+ ; Constant canonicalization: (a >= 5) - (a <= 5) => scmp(a, 5)
282+ define i8 @signed_sub_const_canonicalization2 (i32 %a ) {
283+ ; CHECK-LABEL: define i8 @signed_sub_const_canonicalization2(
284+ ; CHECK-SAME: i32 [[A:%.*]]) {
285+ ; CHECK-NEXT: [[LE:%.*]] = icmp slt i32 [[A]], 6
286+ ; CHECK-NEXT: [[LE8_NEG:%.*]] = sext i1 [[LE]] to i8
287+ ; CHECK-NEXT: [[GE:%.*]] = icmp sgt i32 [[A]], 4
288+ ; CHECK-NEXT: [[GE8:%.*]] = zext i1 [[GE]] to i8
289+ ; CHECK-NEXT: [[R:%.*]] = add nsw i8 [[LE8_NEG]], [[GE8]]
290+ ; CHECK-NEXT: ret i8 [[R]]
291+ ;
292+ %le = icmp sle i32 %a , 5
293+ %le8 = zext i1 %le to i8
294+ %ge = icmp sge i32 %a , 5
295+ %ge8 = zext i1 %ge to i8
296+ %r = sub i8 %ge8 , %le8
297+ ret i8 %r
298+ }
299+
300+ ; Unsigned constant canonicalization: (a > 4) - (a < 6) => ucmp(a, 5)
301+ define i8 @unsigned_sub_const_canonicalization (i32 %a ) {
302+ ; CHECK-LABEL: define i8 @unsigned_sub_const_canonicalization(
303+ ; CHECK-SAME: i32 [[A:%.*]]) {
304+ ; CHECK-NEXT: [[LT:%.*]] = icmp ult i32 [[A]], 6
305+ ; CHECK-NEXT: [[LT8_NEG:%.*]] = sext i1 [[LT]] to i8
306+ ; CHECK-NEXT: [[GT:%.*]] = icmp ugt i32 [[A]], 4
307+ ; CHECK-NEXT: [[GT8:%.*]] = zext i1 [[GT]] to i8
308+ ; CHECK-NEXT: [[R:%.*]] = add nsw i8 [[LT8_NEG]], [[GT8]]
309+ ; CHECK-NEXT: ret i8 [[R]]
310+ ;
311+ %lt = icmp ult i32 %a , 6
312+ %lt8 = zext i1 %lt to i8
313+ %gt = icmp ugt i32 %a , 4
314+ %gt8 = zext i1 %gt to i8
315+ %r = sub i8 %gt8 , %lt8
316+ ret i8 %r
317+ }
318+
319+ ; Constant canonicalization with >= and <=: (a >= 5) - (a <= 5) => scmp(a, 5)
320+ define i8 @signed_sub_const_canonicalization_ge_le (i32 %a ) {
321+ ; CHECK-LABEL: define i8 @signed_sub_const_canonicalization_ge_le(
322+ ; CHECK-SAME: i32 [[A:%.*]]) {
323+ ; CHECK-NEXT: [[LE:%.*]] = icmp slt i32 [[A]], 6
324+ ; CHECK-NEXT: [[LE8_NEG:%.*]] = sext i1 [[LE]] to i8
325+ ; CHECK-NEXT: [[GE:%.*]] = icmp sgt i32 [[A]], 4
326+ ; CHECK-NEXT: [[GE8:%.*]] = zext i1 [[GE]] to i8
327+ ; CHECK-NEXT: [[R:%.*]] = add nsw i8 [[LE8_NEG]], [[GE8]]
328+ ; CHECK-NEXT: ret i8 [[R]]
329+ ;
330+ %le = icmp sle i32 %a , 5
331+ %le8 = zext i1 %le to i8
332+ %ge = icmp sge i32 %a , 5
333+ %ge8 = zext i1 %ge to i8
334+ %r = sub i8 %ge8 , %le8
335+ ret i8 %r
336+ }
337+
338+ ; More constant canonicalization: (a > 2) - (a < 4) => scmp(a, 3)
339+ define i8 @signed_sub_const_canonicalization3 (i32 %a ) {
340+ ; CHECK-LABEL: define i8 @signed_sub_const_canonicalization3(
341+ ; CHECK-SAME: i32 [[A:%.*]]) {
342+ ; CHECK-NEXT: [[LT:%.*]] = icmp slt i32 [[A]], 4
343+ ; CHECK-NEXT: [[LT8_NEG:%.*]] = sext i1 [[LT]] to i8
344+ ; CHECK-NEXT: [[GT:%.*]] = icmp sgt i32 [[A]], 2
345+ ; CHECK-NEXT: [[GT8:%.*]] = zext i1 [[GT]] to i8
346+ ; CHECK-NEXT: [[R:%.*]] = add nsw i8 [[LT8_NEG]], [[GT8]]
347+ ; CHECK-NEXT: ret i8 [[R]]
348+ ;
349+ %lt = icmp slt i32 %a , 4
350+ %lt8 = zext i1 %lt to i8
351+ %gt = icmp sgt i32 %a , 2
352+ %gt8 = zext i1 %gt to i8
353+ %r = sub i8 %gt8 , %lt8
354+ ret i8 %r
355+ }
356+
357+ ; Negative test: constants that are more than one apart - should NOT canonicalize
358+ define i8 @signed_sub_const_no_canonicalization (i32 %a ) {
359+ ; CHECK-LABEL: define i8 @signed_sub_const_no_canonicalization(
360+ ; CHECK-SAME: i32 [[A:%.*]]) {
361+ ; CHECK-NEXT: [[LT:%.*]] = icmp slt i32 [[A]], 10
362+ ; CHECK-NEXT: [[LT8_NEG:%.*]] = sext i1 [[LT]] to i8
363+ ; CHECK-NEXT: [[GT:%.*]] = icmp sgt i32 [[A]], 4
364+ ; CHECK-NEXT: [[GT8:%.*]] = zext i1 [[GT]] to i8
365+ ; CHECK-NEXT: [[R:%.*]] = add nsw i8 [[LT8_NEG]], [[GT8]]
366+ ; CHECK-NEXT: ret i8 [[R]]
367+ ;
368+ %lt = icmp slt i32 %a , 10
369+ %lt8 = zext i1 %lt to i8
370+ %gt = icmp sgt i32 %a , 4
371+ %gt8 = zext i1 %gt to i8
372+ %r = sub i8 %gt8 , %lt8
373+ ret i8 %r
374+ }
0 commit comments