Skip to content

Commit da6f423

Browse files
authored
[InstCombine] Fold (x < y) ? -1 : zext(x > y) and (x > y) ? 1 : sext(x < y) to ucmp/scmp(x, y) (#105272)
This patch expands already existing funcionality to include these two additional folds, which are nearly identical to the ones already implemented. Proofs: https://alive2.llvm.org/ce/z/Xy7s4j
1 parent 3b703d4 commit da6f423

File tree

4 files changed

+82
-37
lines changed

4 files changed

+82
-37
lines changed

llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp

+13-4
Original file line numberDiff line numberDiff line change
@@ -3560,7 +3560,9 @@ static Instruction *foldBitCeil(SelectInst &SI, IRBuilderBase &Builder) {
35603560

35613561
// This function tries to fold the following operations:
35623562
// (x < y) ? -1 : zext(x != y)
3563+
// (x < y) ? -1 : zext(x > y)
35633564
// (x > y) ? 1 : sext(x != y)
3565+
// (x > y) ? 1 : sext(x < y)
35643566
// Into ucmp/scmp(x, y), where signedness is determined by the signedness
35653567
// of the comparison in the original sequence.
35663568
Instruction *InstCombinerImpl::foldSelectToCmp(SelectInst &SI) {
@@ -3589,16 +3591,23 @@ Instruction *InstCombinerImpl::foldSelectToCmp(SelectInst &SI) {
35893591
ICmpInst::isSigned(Pred) ? Intrinsic::scmp : Intrinsic::ucmp;
35903592

35913593
bool Replace = false;
3594+
ICmpInst::Predicate ExtendedCmpPredicate;
35923595
// (x < y) ? -1 : zext(x != y)
3596+
// (x < y) ? -1 : zext(x > y)
35933597
if (ICmpInst::isLT(Pred) && match(TV, m_AllOnes()) &&
3594-
match(FV, m_ZExt(m_c_SpecificICmp(ICmpInst::ICMP_NE, m_Specific(LHS),
3595-
m_Specific(RHS)))))
3598+
match(FV, m_ZExt(m_c_ICmp(ExtendedCmpPredicate, m_Specific(LHS),
3599+
m_Specific(RHS)))) &&
3600+
(ExtendedCmpPredicate == ICmpInst::ICMP_NE ||
3601+
ICmpInst::getSwappedPredicate(ExtendedCmpPredicate) == Pred))
35963602
Replace = true;
35973603

35983604
// (x > y) ? 1 : sext(x != y)
3605+
// (x > y) ? 1 : sext(x < y)
35993606
if (ICmpInst::isGT(Pred) && match(TV, m_One()) &&
3600-
match(FV, m_SExt(m_c_SpecificICmp(ICmpInst::ICMP_NE, m_Specific(LHS),
3601-
m_Specific(RHS)))))
3607+
match(FV, m_SExt(m_c_ICmp(ExtendedCmpPredicate, m_Specific(LHS),
3608+
m_Specific(RHS)))) &&
3609+
(ExtendedCmpPredicate == ICmpInst::ICMP_NE ||
3610+
ICmpInst::getSwappedPredicate(ExtendedCmpPredicate) == Pred))
36023611
Replace = true;
36033612

36043613
if (Replace)

llvm/test/Transforms/InstCombine/scmp.ll

+28
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,20 @@ define i8 @scmp_from_select_lt(i32 %x, i32 %y) {
223223
ret i8 %r
224224
}
225225

226+
; Fold (x s< y) ? -1 : zext(x s> y) into scmp(x, y)
227+
define i8 @scmp_from_select_lt_and_gt(i32 %x, i32 %y) {
228+
; CHECK-LABEL: define i8 @scmp_from_select_lt_and_gt(
229+
; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
230+
; CHECK-NEXT: [[R:%.*]] = call i8 @llvm.scmp.i8.i32(i32 [[X]], i32 [[Y]])
231+
; CHECK-NEXT: ret i8 [[R]]
232+
;
233+
%gt_bool = icmp sgt i32 %x, %y
234+
%gt = zext i1 %gt_bool to i8
235+
%lt = icmp slt i32 %x, %y
236+
%r = select i1 %lt, i8 -1, i8 %gt
237+
ret i8 %r
238+
}
239+
226240
; Vector version
227241
define <4 x i8> @scmp_from_select_vec_lt(<4 x i32> %x, <4 x i32> %y) {
228242
; CHECK-LABEL: define <4 x i8> @scmp_from_select_vec_lt(
@@ -315,3 +329,17 @@ define i8 @scmp_of_sub_and_zero_neg3(i32 %x, i32 %y) {
315329
%r = call i8 @llvm.ucmp(i32 %diff, i32 0)
316330
ret i8 %r
317331
}
332+
333+
; Fold (x s> y) ? 1 : sext(x s< y)
334+
define i8 @scmp_from_select_gt_and_lt(i32 %x, i32 %y) {
335+
; CHECK-LABEL: define i8 @scmp_from_select_gt_and_lt(
336+
; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
337+
; CHECK-NEXT: [[R:%.*]] = call i8 @llvm.scmp.i8.i32(i32 [[X]], i32 [[Y]])
338+
; CHECK-NEXT: ret i8 [[R]]
339+
;
340+
%lt_bool = icmp slt i32 %x, %y
341+
%lt = sext i1 %lt_bool to i8
342+
%gt = icmp sgt i32 %x, %y
343+
%r = select i1 %gt, i8 1, i8 %lt
344+
ret i8 %r
345+
}

llvm/test/Transforms/InstCombine/select-select.ll

+11-31
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,9 @@ define float @foo1(float %a) {
1818

1919
define float @foo2(float %a) {
2020
; CHECK-LABEL: @foo2(
21-
; CHECK-NEXT: [[B:%.*]] = fcmp ule float [[C:%.*]], 0.000000e+00
22-
; CHECK-NEXT: [[D:%.*]] = fcmp olt float [[C]], 1.000000e+00
23-
; CHECK-NEXT: [[E:%.*]] = select i1 [[D]], float [[C]], float 1.000000e+00
21+
; CHECK-NEXT: [[B:%.*]] = fcmp ule float [[A:%.*]], 0.000000e+00
22+
; CHECK-NEXT: [[TMP1:%.*]] = fcmp olt float [[A]], 1.000000e+00
23+
; CHECK-NEXT: [[E:%.*]] = select i1 [[TMP1]], float [[A]], float 1.000000e+00
2424
; CHECK-NEXT: [[F:%.*]] = select i1 [[B]], float 0.000000e+00, float [[E]]
2525
; CHECK-NEXT: ret float [[F]]
2626
;
@@ -330,10 +330,7 @@ define i8 @strong_order_cmp_eq_ugt(i32 %a, i32 %b) {
330330

331331
define i8 @strong_order_cmp_slt_sgt(i32 %a, i32 %b) {
332332
; CHECK-LABEL: @strong_order_cmp_slt_sgt(
333-
; CHECK-NEXT: [[CMP_LT:%.*]] = icmp slt i32 [[A:%.*]], [[B:%.*]]
334-
; CHECK-NEXT: [[SEXT:%.*]] = sext i1 [[CMP_LT]] to i8
335-
; CHECK-NEXT: [[CMP_GT:%.*]] = icmp sgt i32 [[A]], [[B]]
336-
; CHECK-NEXT: [[SEL_GT:%.*]] = select i1 [[CMP_GT]], i8 1, i8 [[SEXT]]
333+
; CHECK-NEXT: [[SEL_GT:%.*]] = call i8 @llvm.scmp.i8.i32(i32 [[A:%.*]], i32 [[B:%.*]])
337334
; CHECK-NEXT: ret i8 [[SEL_GT]]
338335
;
339336
%cmp.lt = icmp slt i32 %a, %b
@@ -345,10 +342,7 @@ define i8 @strong_order_cmp_slt_sgt(i32 %a, i32 %b) {
345342

346343
define i8 @strong_order_cmp_ult_ugt(i32 %a, i32 %b) {
347344
; CHECK-LABEL: @strong_order_cmp_ult_ugt(
348-
; CHECK-NEXT: [[CMP_LT:%.*]] = icmp ult i32 [[A:%.*]], [[B:%.*]]
349-
; CHECK-NEXT: [[SEXT:%.*]] = sext i1 [[CMP_LT]] to i8
350-
; CHECK-NEXT: [[CMP_GT:%.*]] = icmp ugt i32 [[A]], [[B]]
351-
; CHECK-NEXT: [[SEL_GT:%.*]] = select i1 [[CMP_GT]], i8 1, i8 [[SEXT]]
345+
; CHECK-NEXT: [[SEL_GT:%.*]] = call i8 @llvm.ucmp.i8.i32(i32 [[A:%.*]], i32 [[B:%.*]])
352346
; CHECK-NEXT: ret i8 [[SEL_GT]]
353347
;
354348
%cmp.lt = icmp ult i32 %a, %b
@@ -360,10 +354,7 @@ define i8 @strong_order_cmp_ult_ugt(i32 %a, i32 %b) {
360354

361355
define i8 @strong_order_cmp_sgt_slt(i32 %a, i32 %b) {
362356
; CHECK-LABEL: @strong_order_cmp_sgt_slt(
363-
; CHECK-NEXT: [[CMP_GT:%.*]] = icmp sgt i32 [[A:%.*]], [[B:%.*]]
364-
; CHECK-NEXT: [[ZEXT:%.*]] = zext i1 [[CMP_GT]] to i8
365-
; CHECK-NEXT: [[CMP_LT:%.*]] = icmp slt i32 [[A]], [[B]]
366-
; CHECK-NEXT: [[SEL_LT:%.*]] = select i1 [[CMP_LT]], i8 -1, i8 [[ZEXT]]
357+
; CHECK-NEXT: [[SEL_LT:%.*]] = call i8 @llvm.scmp.i8.i32(i32 [[A:%.*]], i32 [[B:%.*]])
367358
; CHECK-NEXT: ret i8 [[SEL_LT]]
368359
;
369360
%cmp.gt = icmp sgt i32 %a, %b
@@ -375,10 +366,7 @@ define i8 @strong_order_cmp_sgt_slt(i32 %a, i32 %b) {
375366

376367
define i8 @strong_order_cmp_ugt_ult(i32 %a, i32 %b) {
377368
; CHECK-LABEL: @strong_order_cmp_ugt_ult(
378-
; CHECK-NEXT: [[CMP_GT:%.*]] = icmp ugt i32 [[A:%.*]], [[B:%.*]]
379-
; CHECK-NEXT: [[ZEXT:%.*]] = zext i1 [[CMP_GT]] to i8
380-
; CHECK-NEXT: [[CMP_LT:%.*]] = icmp ult i32 [[A]], [[B]]
381-
; CHECK-NEXT: [[SEL_LT:%.*]] = select i1 [[CMP_LT]], i8 -1, i8 [[ZEXT]]
369+
; CHECK-NEXT: [[SEL_LT:%.*]] = call i8 @llvm.ucmp.i8.i32(i32 [[A:%.*]], i32 [[B:%.*]])
382370
; CHECK-NEXT: ret i8 [[SEL_LT]]
383371
;
384372
%cmp.gt = icmp ugt i32 %a, %b
@@ -460,8 +448,7 @@ define i8 @strong_order_cmp_ugt_ult_zext_not_oneuse(i32 %a, i32 %b) {
460448
; CHECK-NEXT: [[CMP_GT:%.*]] = icmp ugt i32 [[A:%.*]], [[B:%.*]]
461449
; CHECK-NEXT: [[ZEXT:%.*]] = zext i1 [[CMP_GT]] to i8
462450
; CHECK-NEXT: call void @use8(i8 [[ZEXT]])
463-
; CHECK-NEXT: [[CMP_LT:%.*]] = icmp ult i32 [[A]], [[B]]
464-
; CHECK-NEXT: [[SEL_LT:%.*]] = select i1 [[CMP_LT]], i8 -1, i8 [[ZEXT]]
451+
; CHECK-NEXT: [[SEL_LT:%.*]] = call i8 @llvm.ucmp.i8.i32(i32 [[A]], i32 [[B]])
465452
; CHECK-NEXT: ret i8 [[SEL_LT]]
466453
;
467454
%cmp.gt = icmp ugt i32 %a, %b
@@ -477,8 +464,7 @@ define i8 @strong_order_cmp_slt_sgt_sext_not_oneuse(i32 %a, i32 %b) {
477464
; CHECK-NEXT: [[CMP_LT:%.*]] = icmp slt i32 [[A:%.*]], [[B:%.*]]
478465
; CHECK-NEXT: [[SEXT:%.*]] = sext i1 [[CMP_LT]] to i8
479466
; CHECK-NEXT: call void @use8(i8 [[SEXT]])
480-
; CHECK-NEXT: [[CMP_GT:%.*]] = icmp sgt i32 [[A]], [[B]]
481-
; CHECK-NEXT: [[SEL_GT:%.*]] = select i1 [[CMP_GT]], i8 1, i8 [[SEXT]]
467+
; CHECK-NEXT: [[SEL_GT:%.*]] = call i8 @llvm.scmp.i8.i32(i32 [[A]], i32 [[B]])
482468
; CHECK-NEXT: ret i8 [[SEL_GT]]
483469
;
484470
%cmp.lt = icmp slt i32 %a, %b
@@ -491,10 +477,7 @@ define i8 @strong_order_cmp_slt_sgt_sext_not_oneuse(i32 %a, i32 %b) {
491477

492478
define <2 x i8> @strong_order_cmp_ugt_ult_vector(<2 x i32> %a, <2 x i32> %b) {
493479
; CHECK-LABEL: @strong_order_cmp_ugt_ult_vector(
494-
; CHECK-NEXT: [[CMP_GT:%.*]] = icmp ugt <2 x i32> [[A:%.*]], [[B:%.*]]
495-
; CHECK-NEXT: [[ZEXT:%.*]] = zext <2 x i1> [[CMP_GT]] to <2 x i8>
496-
; CHECK-NEXT: [[CMP_LT:%.*]] = icmp ult <2 x i32> [[A]], [[B]]
497-
; CHECK-NEXT: [[SEL_LT:%.*]] = select <2 x i1> [[CMP_LT]], <2 x i8> <i8 -1, i8 -1>, <2 x i8> [[ZEXT]]
480+
; CHECK-NEXT: [[SEL_LT:%.*]] = call <2 x i8> @llvm.ucmp.v2i8.v2i32(<2 x i32> [[A:%.*]], <2 x i32> [[B:%.*]])
498481
; CHECK-NEXT: ret <2 x i8> [[SEL_LT]]
499482
;
500483
%cmp.gt = icmp ugt <2 x i32> %a, %b
@@ -506,10 +489,7 @@ define <2 x i8> @strong_order_cmp_ugt_ult_vector(<2 x i32> %a, <2 x i32> %b) {
506489

507490
define <2 x i8> @strong_order_cmp_ugt_ult_vector_poison(<2 x i32> %a, <2 x i32> %b) {
508491
; CHECK-LABEL: @strong_order_cmp_ugt_ult_vector_poison(
509-
; CHECK-NEXT: [[CMP_GT:%.*]] = icmp ugt <2 x i32> [[A:%.*]], [[B:%.*]]
510-
; CHECK-NEXT: [[ZEXT:%.*]] = zext <2 x i1> [[CMP_GT]] to <2 x i8>
511-
; CHECK-NEXT: [[CMP_LT:%.*]] = icmp ult <2 x i32> [[A]], [[B]]
512-
; CHECK-NEXT: [[SEL_LT:%.*]] = select <2 x i1> [[CMP_LT]], <2 x i8> <i8 poison, i8 -1>, <2 x i8> [[ZEXT]]
492+
; CHECK-NEXT: [[SEL_LT:%.*]] = call <2 x i8> @llvm.ucmp.v2i8.v2i32(<2 x i32> [[A:%.*]], <2 x i32> [[B:%.*]])
513493
; CHECK-NEXT: ret <2 x i8> [[SEL_LT]]
514494
;
515495
%cmp.gt = icmp ugt <2 x i32> %a, %b

llvm/test/Transforms/InstCombine/ucmp.ll

+30-2
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,20 @@ define i8 @ucmp_from_select_lt(i32 %x, i32 %y) {
222222
ret i8 %r
223223
}
224224

225+
; Fold (x u< y) ? -1 : zext(x u> y) into ucmp(x, y)
226+
define i8 @ucmp_from_select_lt_and_gt(i32 %x, i32 %y) {
227+
; CHECK-LABEL: define i8 @ucmp_from_select_lt_and_gt(
228+
; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
229+
; CHECK-NEXT: [[R:%.*]] = call i8 @llvm.ucmp.i8.i32(i32 [[X]], i32 [[Y]])
230+
; CHECK-NEXT: ret i8 [[R]]
231+
;
232+
%gt_bool = icmp ugt i32 %x, %y
233+
%gt = zext i1 %gt_bool to i8
234+
%lt = icmp ult i32 %x, %y
235+
%r = select i1 %lt, i8 -1, i8 %gt
236+
ret i8 %r
237+
}
238+
225239
; Vector version
226240
define <4 x i8> @ucmp_from_select_vec_lt(<4 x i32> %x, <4 x i32> %y) {
227241
; CHECK-LABEL: define <4 x i8> @ucmp_from_select_vec_lt(
@@ -349,13 +363,13 @@ define i8 @ucmp_from_select_le_neg1(i32 %x, i32 %y) {
349363
; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
350364
; CHECK-NEXT: [[NE_BOOL:%.*]] = icmp ult i32 [[X]], [[Y]]
351365
; CHECK-NEXT: [[NE:%.*]] = sext i1 [[NE_BOOL]] to i8
352-
; CHECK-NEXT: [[LE_NOT:%.*]] = icmp ugt i32 [[X]], [[Y]]
366+
; CHECK-NEXT: [[LE_NOT:%.*]] = icmp ult i32 [[X]], [[Y]]
353367
; CHECK-NEXT: [[R:%.*]] = select i1 [[LE_NOT]], i8 1, i8 [[NE]]
354368
; CHECK-NEXT: ret i8 [[R]]
355369
;
356370
%ne_bool = icmp ult i32 %x, %y
357371
%ne = sext i1 %ne_bool to i8
358-
%le = icmp ule i32 %x, %y
372+
%le = icmp uge i32 %x, %y
359373
%r = select i1 %le, i8 %ne, i8 1
360374
ret i8 %r
361375
}
@@ -513,3 +527,17 @@ define i8 @ucmp_from_select_ge_neg4(i32 %x, i32 %y) {
513527
%r = select i1 %ge, i8 %ne, i8 3
514528
ret i8 %r
515529
}
530+
531+
; Fold (x > y) ? 1 : sext(x < y)
532+
define i8 @ucmp_from_select_gt_and_lt(i32 %x, i32 %y) {
533+
; CHECK-LABEL: define i8 @ucmp_from_select_gt_and_lt(
534+
; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
535+
; CHECK-NEXT: [[R:%.*]] = call i8 @llvm.ucmp.i8.i32(i32 [[X]], i32 [[Y]])
536+
; CHECK-NEXT: ret i8 [[R]]
537+
;
538+
%lt_bool = icmp ult i32 %x, %y
539+
%lt = sext i1 %lt_bool to i8
540+
%gt = icmp ugt i32 %x, %y
541+
%r = select i1 %gt, i8 1, i8 %lt
542+
ret i8 %r
543+
}

0 commit comments

Comments
 (0)