Skip to content

Commit bee6b50

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 ddd1a4b commit bee6b50

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
@@ -2305,19 +2305,33 @@ Instruction *InstCombinerImpl::foldICmpShlConstant(ICmpInst &Cmp,
23052305
if (C.isZero() || (Pred == ICmpInst::ICMP_SGT ? C.isAllOnes() : C.isOne()))
23062306
return new ICmpInst(Pred, Shl->getOperand(0), Cmp.getOperand(1));
23072307

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

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

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

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

Lines changed: 27 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -741,9 +741,9 @@ define i1 @test_const_shr_and_1_ne_0_multi_use_and_negative(i32 %b) {
741741

742742
define i1 @test_shl_sub_bw_minus_1_slt_0(i32 %a, i32 %b) {
743743
; CHECK-LABEL: @test_shl_sub_bw_minus_1_slt_0(
744-
; CHECK-NEXT: [[SUB:%.*]] = sub i32 31, [[B:%.*]]
745-
; CHECK-NEXT: [[SHL:%.*]] = shl i32 [[A:%.*]], [[SUB]]
746-
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[SHL]], 0
744+
; CHECK-NEXT: [[TMP1:%.*]] = shl nuw i32 1, [[B:%.*]]
745+
; CHECK-NEXT: [[TMP2:%.*]] = and i32 [[TMP1]], [[A:%.*]]
746+
; CHECK-NEXT: [[CMP:%.*]] = icmp ne i32 [[TMP2]], 0
747747
; CHECK-NEXT: ret i1 [[CMP]]
748748
;
749749
%sub = sub i32 31, %b
@@ -754,9 +754,9 @@ define i1 @test_shl_sub_bw_minus_1_slt_0(i32 %a, i32 %b) {
754754

755755
define i1 @test_const_shl_sub_bw_minus_1_slt_0(i32 %b) {
756756
; CHECK-LABEL: @test_const_shl_sub_bw_minus_1_slt_0(
757-
; CHECK-NEXT: [[SUB:%.*]] = sub i32 31, [[B:%.*]]
758-
; CHECK-NEXT: [[SHL:%.*]] = shl i32 42, [[SUB]]
759-
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[SHL]], 0
757+
; CHECK-NEXT: [[TMP1:%.*]] = shl nuw i32 1, [[B:%.*]]
758+
; CHECK-NEXT: [[TMP2:%.*]] = and i32 [[TMP1]], 42
759+
; CHECK-NEXT: [[CMP:%.*]] = icmp ne i32 [[TMP2]], 0
760760
; CHECK-NEXT: ret i1 [[CMP]]
761761
;
762762
%sub = sub i32 31, %b
@@ -767,9 +767,9 @@ define i1 @test_const_shl_sub_bw_minus_1_slt_0(i32 %b) {
767767

768768
define i1 @test_not_shl_sub_bw_minus_1_slt_0(i32 %a, i32 %b) {
769769
; CHECK-LABEL: @test_not_shl_sub_bw_minus_1_slt_0(
770-
; CHECK-NEXT: [[SUB:%.*]] = sub i32 31, [[B:%.*]]
771-
; CHECK-NEXT: [[SHL:%.*]] = shl i32 [[A:%.*]], [[SUB]]
772-
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i32 [[SHL]], -1
770+
; CHECK-NEXT: [[TMP1:%.*]] = shl nuw i32 1, [[B:%.*]]
771+
; CHECK-NEXT: [[TMP2:%.*]] = and i32 [[TMP1]], [[A:%.*]]
772+
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[TMP2]], 0
773773
; CHECK-NEXT: ret i1 [[CMP]]
774774
;
775775
%sub = sub i32 31, %b
@@ -780,9 +780,9 @@ define i1 @test_not_shl_sub_bw_minus_1_slt_0(i32 %a, i32 %b) {
780780

781781
define i1 @test_shl_nuw_sub_bw_minus_1_slt_0(i32 %a, i32 %b) {
782782
; CHECK-LABEL: @test_shl_nuw_sub_bw_minus_1_slt_0(
783-
; CHECK-NEXT: [[SUB:%.*]] = sub i32 31, [[B:%.*]]
784-
; CHECK-NEXT: [[SHL:%.*]] = shl nuw i32 [[A:%.*]], [[SUB]]
785-
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[SHL]], 0
783+
; CHECK-NEXT: [[TMP1:%.*]] = shl nuw i32 1, [[B:%.*]]
784+
; CHECK-NEXT: [[TMP2:%.*]] = and i32 [[TMP1]], [[A:%.*]]
785+
; CHECK-NEXT: [[CMP:%.*]] = icmp ne i32 [[TMP2]], 0
786786
; CHECK-NEXT: ret i1 [[CMP]]
787787
;
788788
%sub = sub i32 31, %b
@@ -793,9 +793,9 @@ define i1 @test_shl_nuw_sub_bw_minus_1_slt_0(i32 %a, i32 %b) {
793793

794794
define i1 @test_not_const_shl_sub_bw_minus_1_slt_0(i32 %b) {
795795
; CHECK-LABEL: @test_not_const_shl_sub_bw_minus_1_slt_0(
796-
; CHECK-NEXT: [[SUB:%.*]] = sub i32 31, [[B:%.*]]
797-
; CHECK-NEXT: [[SHL:%.*]] = shl i32 42, [[SUB]]
798-
; CHECK-NEXT: [[CMP:%.*]] = icmp sgt i32 [[SHL]], -1
796+
; CHECK-NEXT: [[TMP1:%.*]] = shl nuw i32 1, [[B:%.*]]
797+
; CHECK-NEXT: [[TMP2:%.*]] = and i32 [[TMP1]], 42
798+
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[TMP2]], 0
799799
; CHECK-NEXT: ret i1 [[CMP]]
800800
;
801801
%sub = sub i32 31, %b
@@ -806,9 +806,9 @@ define i1 @test_not_const_shl_sub_bw_minus_1_slt_0(i32 %b) {
806806

807807
define <8 x i1> @test_shl_sub_bw_minus_1_slt_0_v8i8(<8 x i8> %a, <8 x i8> %b) {
808808
; CHECK-LABEL: @test_shl_sub_bw_minus_1_slt_0_v8i8(
809-
; CHECK-NEXT: [[SUB:%.*]] = sub <8 x i8> <i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7>, [[B:%.*]]
810-
; CHECK-NEXT: [[SHL:%.*]] = shl <8 x i8> [[A:%.*]], [[SUB]]
811-
; CHECK-NEXT: [[CMP:%.*]] = icmp slt <8 x i8> [[SHL]], zeroinitializer
809+
; 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:%.*]]
810+
; CHECK-NEXT: [[TMP2:%.*]] = and <8 x i8> [[TMP1]], [[A:%.*]]
811+
; CHECK-NEXT: [[CMP:%.*]] = icmp ne <8 x i8> [[TMP2]], zeroinitializer
812812
; CHECK-NEXT: ret <8 x i1> [[CMP]]
813813
;
814814
%sub = sub <8 x i8> <i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7>, %b
@@ -819,9 +819,9 @@ define <8 x i1> @test_shl_sub_bw_minus_1_slt_0_v8i8(<8 x i8> %a, <8 x i8> %b) {
819819

820820
define <8 x i1> @test_const_shl_sub_bw_minus_1_slt_0_v8i8_splat(<8 x i8> %b) {
821821
; CHECK-LABEL: @test_const_shl_sub_bw_minus_1_slt_0_v8i8_splat(
822-
; CHECK-NEXT: [[SUB:%.*]] = sub <8 x i8> <i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7>, [[B:%.*]]
823-
; CHECK-NEXT: [[SHL:%.*]] = shl <8 x i8> <i8 42, i8 42, i8 42, i8 42, i8 42, i8 42, i8 42, i8 42>, [[SUB]]
824-
; CHECK-NEXT: [[CMP:%.*]] = icmp slt <8 x i8> [[SHL]], zeroinitializer
822+
; 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:%.*]]
823+
; CHECK-NEXT: [[TMP2:%.*]] = and <8 x i8> [[TMP1]], <i8 42, i8 42, i8 42, i8 42, i8 42, i8 42, i8 42, i8 42>
824+
; CHECK-NEXT: [[CMP:%.*]] = icmp ne <8 x i8> [[TMP2]], zeroinitializer
825825
; CHECK-NEXT: ret <8 x i1> [[CMP]]
826826
;
827827
%sub = sub <8 x i8> <i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7>, %b
@@ -845,9 +845,9 @@ define <8 x i1> @test_const_shl_sub_bw_minus_1_slt_0_v8i8_splat_poison_1(<8 x i8
845845

846846
define <8 x i1> @test_const_shl_sub_bw_minus_1_slt_0_v8i8_splat_poison_2(<8 x i8> %b) {
847847
; CHECK-LABEL: @test_const_shl_sub_bw_minus_1_slt_0_v8i8_splat_poison_2(
848-
; CHECK-NEXT: [[SUB:%.*]] = sub <8 x i8> <i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7>, [[B:%.*]]
849-
; CHECK-NEXT: [[SHL:%.*]] = shl <8 x i8> <i8 42, i8 42, i8 42, i8 42, i8 42, i8 42, i8 42, i8 poison>, [[SUB]]
850-
; CHECK-NEXT: [[CMP:%.*]] = icmp slt <8 x i8> [[SHL]], zeroinitializer
848+
; 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:%.*]]
849+
; CHECK-NEXT: [[TMP2:%.*]] = and <8 x i8> [[TMP1]], <i8 42, i8 42, i8 42, i8 42, i8 42, i8 42, i8 42, i8 poison>
850+
; CHECK-NEXT: [[CMP:%.*]] = icmp ne <8 x i8> [[TMP2]], zeroinitializer
851851
; CHECK-NEXT: ret <8 x i1> [[CMP]]
852852
;
853853
%sub = sub <8 x i8> <i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7>, %b
@@ -858,9 +858,9 @@ define <8 x i1> @test_const_shl_sub_bw_minus_1_slt_0_v8i8_splat_poison_2(<8 x i8
858858

859859
define <8 x i1> @test_const_shl_sub_bw_minus_1_slt_0_v8i8_nonsplat(<8 x i8> %b) {
860860
; CHECK-LABEL: @test_const_shl_sub_bw_minus_1_slt_0_v8i8_nonsplat(
861-
; CHECK-NEXT: [[SUB:%.*]] = sub <8 x i8> <i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7, i8 7>, [[B:%.*]]
862-
; CHECK-NEXT: [[SHL:%.*]] = shl <8 x i8> <i8 42, i8 43, i8 44, i8 45, i8 46, i8 47, i8 48, i8 49>, [[SUB]]
863-
; CHECK-NEXT: [[CMP:%.*]] = icmp slt <8 x i8> [[SHL]], zeroinitializer
861+
; 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:%.*]]
862+
; CHECK-NEXT: [[TMP2:%.*]] = and <8 x i8> [[TMP1]], <i8 42, i8 43, i8 44, i8 45, i8 46, i8 47, i8 48, i8 49>
863+
; CHECK-NEXT: [[CMP:%.*]] = icmp ne <8 x i8> [[TMP2]], zeroinitializer
864864
; CHECK-NEXT: ret <8 x i1> [[CMP]]
865865
;
866866
%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)