Skip to content

Commit f7751bc

Browse files
committed
[InstCombine] Canonicalize Bit Testing by Shifting to Sign Bit
Implement a new transformations that folds the bit-testing expression (icmp slt (shl V (sub (bw-1) B)) 0) to (icmp ne (and V (shl 1 B)) 0). Also fold the negated variant of the LHS. Alive proof: https://alive2.llvm.org/ce/z/5ic_qe Relates to issue #86813.
1 parent 27210f0 commit f7751bc

File tree

2 files changed

+45
-31
lines changed

2 files changed

+45
-31
lines changed

llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2304,19 +2304,33 @@ Instruction *InstCombinerImpl::foldICmpShlConstant(ICmpInst &Cmp,
23042304
if (C.isZero() || (Pred == ICmpInst::ICMP_SGT ? C.isAllOnes() : C.isOne()))
23052305
return new ICmpInst(Pred, Shl->getOperand(0), Cmp.getOperand(1));
23062306

2307+
unsigned TypeBits = C.getBitWidth();
2308+
Value *X = Shl->getOperand(0);
2309+
Type *ShType = Shl->getType();
2310+
2311+
// (icmp slt (shl X, (sub bw-1, Y)), 0) --> (icmp ne (and X, (shl 1, Y)), 0)
2312+
// (icmp sgt (shl X, (sub bw-1, Y)), -1) --> (icmp eq (and X, (shl 1, Y)), 0)
2313+
Value *Y;
2314+
if (Shl->hasOneUse() &&
2315+
((Pred == ICmpInst::ICMP_SLT && C.isZero()) ||
2316+
(Pred == ICmpInst::ICMP_SGT && C.isAllOnes())) &&
2317+
match(Shl->getOperand(1),
2318+
m_OneUse(m_Sub(m_SpecificInt(TypeBits - 1), m_Value(Y)))))
2319+
return new ICmpInst(
2320+
Pred == ICmpInst::ICMP_SLT ? ICmpInst::ICMP_NE : ICmpInst::ICMP_EQ,
2321+
Builder.CreateAnd(X, Builder.CreateShl(ConstantInt::get(ShType, 1), Y,
2322+
"", /*HasNUW=*/true)),
2323+
ConstantInt::get(ShType, 0));
2324+
23072325
const APInt *ShiftAmt;
23082326
if (!match(Shl->getOperand(1), m_APInt(ShiftAmt)))
23092327
return foldICmpShlOne(Cmp, Shl, C);
23102328

23112329
// Check that the shift amount is in range. If not, don't perform undefined
23122330
// shifts. When the shift is visited, it will be simplified.
2313-
unsigned TypeBits = C.getBitWidth();
23142331
if (ShiftAmt->uge(TypeBits))
23152332
return nullptr;
23162333

2317-
Value *X = Shl->getOperand(0);
2318-
Type *ShType = Shl->getType();
2319-
23202334
// NSW guarantees that we are only shifting out sign bits from the high bits,
23212335
// so we can ASHR the compare constant without needing a mask and eliminate
23222336
// the shift.

llvm/test/Transforms/InstCombine/icmp-and-shift.ll

Lines changed: 27 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -609,9 +609,9 @@ define i1 @fold_ne_rhs_fail_shift_not_1s(i8 %x, i8 %yy) {
609609

610610
define i1 @test_shl_sub_bw_minus_1_slt_0(i32 %a, i32 %b) {
611611
; CHECK-LABEL: @test_shl_sub_bw_minus_1_slt_0(
612-
; CHECK-NEXT: [[SUB:%.*]] = sub i32 31, [[B:%.*]]
613-
; CHECK-NEXT: [[SHL:%.*]] = shl i32 [[A:%.*]], [[SUB]]
614-
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[SHL]], 0
612+
; CHECK-NEXT: [[TMP1:%.*]] = shl nuw i32 1, [[B:%.*]]
613+
; CHECK-NEXT: [[TMP2:%.*]] = and i32 [[TMP1]], [[A:%.*]]
614+
; CHECK-NEXT: [[CMP:%.*]] = icmp ne i32 [[TMP2]], 0
615615
; CHECK-NEXT: ret i1 [[CMP]]
616616
;
617617
%sub = sub i32 31, %b
@@ -622,9 +622,9 @@ define i1 @test_shl_sub_bw_minus_1_slt_0(i32 %a, i32 %b) {
622622

623623
define i1 @test_const_shl_sub_bw_minus_1_slt_0(i32 %b) {
624624
; CHECK-LABEL: @test_const_shl_sub_bw_minus_1_slt_0(
625-
; CHECK-NEXT: [[SUB:%.*]] = sub i32 31, [[B:%.*]]
626-
; CHECK-NEXT: [[SHL:%.*]] = shl i32 42, [[SUB]]
627-
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[SHL]], 0
625+
; CHECK-NEXT: [[TMP1:%.*]] = shl nuw i32 1, [[B:%.*]]
626+
; CHECK-NEXT: [[TMP2:%.*]] = and i32 [[TMP1]], 42
627+
; CHECK-NEXT: [[CMP:%.*]] = icmp ne i32 [[TMP2]], 0
628628
; CHECK-NEXT: ret i1 [[CMP]]
629629
;
630630
%sub = sub i32 31, %b
@@ -635,9 +635,9 @@ define i1 @test_const_shl_sub_bw_minus_1_slt_0(i32 %b) {
635635

636636
define i1 @test_not_shl_sub_bw_minus_1_slt_0(i32 %a, i32 %b) {
637637
; CHECK-LABEL: @test_not_shl_sub_bw_minus_1_slt_0(
638-
; CHECK-NEXT: [[SUB:%.*]] = sub i32 31, [[B:%.*]]
639-
; CHECK-NEXT: [[SHL:%.*]] = shl i32 [[A:%.*]], [[SUB]]
640-
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i32 [[SHL]], -1
638+
; CHECK-NEXT: [[TMP1:%.*]] = shl nuw i32 1, [[B:%.*]]
639+
; CHECK-NEXT: [[TMP2:%.*]] = and i32 [[TMP1]], [[A:%.*]]
640+
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[TMP2]], 0
641641
; CHECK-NEXT: ret i1 [[CMP]]
642642
;
643643
%sub = sub i32 31, %b
@@ -648,9 +648,9 @@ define i1 @test_not_shl_sub_bw_minus_1_slt_0(i32 %a, i32 %b) {
648648

649649
define i1 @test_shl_nuw_sub_bw_minus_1_slt_0(i32 %a, i32 %b) {
650650
; CHECK-LABEL: @test_shl_nuw_sub_bw_minus_1_slt_0(
651-
; CHECK-NEXT: [[SUB:%.*]] = sub i32 31, [[B:%.*]]
652-
; CHECK-NEXT: [[SHL:%.*]] = shl nuw i32 [[A:%.*]], [[SUB]]
653-
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[SHL]], 0
651+
; CHECK-NEXT: [[TMP1:%.*]] = shl nuw i32 1, [[B:%.*]]
652+
; CHECK-NEXT: [[TMP2:%.*]] = and i32 [[TMP1]], [[A:%.*]]
653+
; CHECK-NEXT: [[CMP:%.*]] = icmp ne i32 [[TMP2]], 0
654654
; CHECK-NEXT: ret i1 [[CMP]]
655655
;
656656
%sub = sub i32 31, %b
@@ -661,9 +661,9 @@ define i1 @test_shl_nuw_sub_bw_minus_1_slt_0(i32 %a, i32 %b) {
661661

662662
define i1 @test_not_const_shl_sub_bw_minus_1_slt_0(i32 %b) {
663663
; CHECK-LABEL: @test_not_const_shl_sub_bw_minus_1_slt_0(
664-
; CHECK-NEXT: [[SUB:%.*]] = sub i32 31, [[B:%.*]]
665-
; CHECK-NEXT: [[SHL:%.*]] = shl i32 42, [[SUB]]
666-
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i32 [[SHL]], -1
664+
; CHECK-NEXT: [[TMP1:%.*]] = shl nuw i32 1, [[B:%.*]]
665+
; CHECK-NEXT: [[TMP2:%.*]] = and i32 [[TMP1]], 42
666+
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[TMP2]], 0
667667
; CHECK-NEXT: ret i1 [[CMP]]
668668
;
669669
%sub = sub i32 31, %b
@@ -674,9 +674,9 @@ define i1 @test_not_const_shl_sub_bw_minus_1_slt_0(i32 %b) {
674674

675675
define <8 x i1> @test_shl_sub_bw_minus_1_slt_0_v8i8(<8 x i8> %a, <8 x i8> %b) {
676676
; CHECK-LABEL: @test_shl_sub_bw_minus_1_slt_0_v8i8(
677-
; CHECK-NEXT: [[SUB:%.*]] = sub <8 x i8> <i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7>, [[B:%.*]]
678-
; CHECK-NEXT: [[SHL:%.*]] = shl <8 x i8> [[A:%.*]], [[SUB]]
679-
; CHECK-NEXT: [[CMP:%.*]] = icmp slt <8 x i8> [[SHL]], zeroinitializer
677+
; CHECK-NEXT: [[TMP1:%.*]] = shl nuw <8 x i8> <i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1>, [[B:%.*]]
678+
; CHECK-NEXT: [[TMP2:%.*]] = and <8 x i8> [[TMP1]], [[A:%.*]]
679+
; CHECK-NEXT: [[CMP:%.*]] = icmp ne <8 x i8> [[TMP2]], zeroinitializer
680680
; CHECK-NEXT: ret <8 x i1> [[CMP]]
681681
;
682682
%sub = sub <8 x i8> <i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7>, %b
@@ -687,9 +687,9 @@ define <8 x i1> @test_shl_sub_bw_minus_1_slt_0_v8i8(<8 x i8> %a, <8 x i8> %b) {
687687

688688
define <8 x i1> @test_const_shl_sub_bw_minus_1_slt_0_v8i8_splat(<8 x i8> %b) {
689689
; CHECK-LABEL: @test_const_shl_sub_bw_minus_1_slt_0_v8i8_splat(
690-
; CHECK-NEXT: [[SUB:%.*]] = sub <8 x i8> <i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7>, [[B:%.*]]
691-
; CHECK-NEXT: [[SHL:%.*]] = shl <8 x i8> <i8 42, i8 42, i8 42, i8 42, i8 42, i8 42, i8 42, i8 42>, [[SUB]]
692-
; CHECK-NEXT: [[CMP:%.*]] = icmp slt <8 x i8> [[SHL]], zeroinitializer
690+
; CHECK-NEXT: [[TMP1:%.*]] = shl nuw <8 x i8> <i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1>, [[B:%.*]]
691+
; CHECK-NEXT: [[TMP2:%.*]] = and <8 x i8> [[TMP1]], <i8 42, i8 42, i8 42, i8 42, i8 42, i8 42, i8 42, i8 42>
692+
; CHECK-NEXT: [[CMP:%.*]] = icmp ne <8 x i8> [[TMP2]], zeroinitializer
693693
; CHECK-NEXT: ret <8 x i1> [[CMP]]
694694
;
695695
%sub = sub <8 x i8> <i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7>, %b
@@ -713,9 +713,9 @@ define <8 x i1> @test_const_shl_sub_bw_minus_1_slt_0_v8i8_splat_poison_1(<8 x i8
713713

714714
define <8 x i1> @test_const_shl_sub_bw_minus_1_slt_0_v8i8_splat_poison_2(<8 x i8> %b) {
715715
; CHECK-LABEL: @test_const_shl_sub_bw_minus_1_slt_0_v8i8_splat_poison_2(
716-
; CHECK-NEXT: [[SUB:%.*]] = sub <8 x i8> <i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7>, [[B:%.*]]
717-
; CHECK-NEXT: [[SHL:%.*]] = shl <8 x i8> <i8 42, i8 42, i8 42, i8 42, i8 42, i8 42, i8 42, i8 poison>, [[SUB]]
718-
; CHECK-NEXT: [[CMP:%.*]] = icmp slt <8 x i8> [[SHL]], zeroinitializer
716+
; CHECK-NEXT: [[TMP1:%.*]] = shl nuw <8 x i8> <i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1>, [[B:%.*]]
717+
; CHECK-NEXT: [[TMP2:%.*]] = and <8 x i8> [[TMP1]], <i8 42, i8 42, i8 42, i8 42, i8 42, i8 42, i8 42, i8 poison>
718+
; CHECK-NEXT: [[CMP:%.*]] = icmp ne <8 x i8> [[TMP2]], zeroinitializer
719719
; CHECK-NEXT: ret <8 x i1> [[CMP]]
720720
;
721721
%sub = sub <8 x i8> <i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7>, %b
@@ -726,9 +726,9 @@ define <8 x i1> @test_const_shl_sub_bw_minus_1_slt_0_v8i8_splat_poison_2(<8 x i8
726726

727727
define <8 x i1> @test_const_shl_sub_bw_minus_1_slt_0_v8i8_nonsplat(<8 x i8> %b) {
728728
; CHECK-LABEL: @test_const_shl_sub_bw_minus_1_slt_0_v8i8_nonsplat(
729-
; CHECK-NEXT: [[SUB:%.*]] = sub <8 x i8> <i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7>, [[B:%.*]]
730-
; CHECK-NEXT: [[SHL:%.*]] = shl <8 x i8> <i8 42, i8 43, i8 44, i8 45, i8 46, i8 47, i8 48, i8 49>, [[SUB]]
731-
; CHECK-NEXT: [[CMP:%.*]] = icmp slt <8 x i8> [[SHL]], zeroinitializer
729+
; CHECK-NEXT: [[TMP1:%.*]] = shl nuw <8 x i8> <i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1, i8 1>, [[B:%.*]]
730+
; CHECK-NEXT: [[TMP2:%.*]] = and <8 x i8> [[TMP1]], <i8 42, i8 43, i8 44, i8 45, i8 46, i8 47, i8 48, i8 49>
731+
; CHECK-NEXT: [[CMP:%.*]] = icmp ne <8 x i8> [[TMP2]], zeroinitializer
732732
; CHECK-NEXT: ret <8 x i1> [[CMP]]
733733
;
734734
%sub = sub <8 x i8> <i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7>, %b

0 commit comments

Comments
 (0)