Skip to content

Commit 0ef7cbc

Browse files
committed
[InstCombine] reduce compare of signbits of 2 values, signed variant
(X s>> BitWidth - 1) == sext (Y s> -1) --> (X ^ Y) < 0 (X s>> BitWidth - 1) != sext (Y s> -1) --> (X ^ Y) > -1 This is the same logic as: 7cbfc39 ...extended to deal with "signed" cast+shift instructions. https://alive2.llvm.org/ce/z/LLidya
1 parent 2d7bb60 commit 0ef7cbc

File tree

2 files changed

+38
-25
lines changed

2 files changed

+38
-25
lines changed

llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4661,20 +4661,34 @@ Instruction *InstCombinerImpl::foldICmpEquality(ICmpInst &I) {
46614661
if (match(Op0, m_And(m_Value(B), m_LowBitMask(MaskC))) &&
46624662
MaskC->countTrailingOnes() == A->getType()->getScalarSizeInBits())
46634663
return new ICmpInst(Pred, A, Builder.CreateTrunc(B, A->getType()));
4664+
}
46644665

4665-
// Test if 2 values have different or same signbits:
4666-
// (X u>> BitWidth - 1) == zext (Y s> -1) --> (X ^ Y) < 0
4667-
// (X u>> BitWidth - 1) != zext (Y s> -1) --> (X ^ Y) > -1
4666+
// Test if 2 values have different or same signbits:
4667+
// (X u>> BitWidth - 1) == zext (Y s> -1) --> (X ^ Y) < 0
4668+
// (X u>> BitWidth - 1) != zext (Y s> -1) --> (X ^ Y) > -1
4669+
// (X s>> BitWidth - 1) == sext (Y s> -1) --> (X ^ Y) < 0
4670+
// (X s>> BitWidth - 1) != sext (Y s> -1) --> (X ^ Y) > -1
4671+
Instruction *ExtI;
4672+
if (match(Op1, m_CombineAnd(m_Instruction(ExtI), m_ZExtOrSExt(m_Value(A)))) &&
4673+
(Op0->hasOneUse() || Op1->hasOneUse())) {
46684674
unsigned OpWidth = Op0->getType()->getScalarSizeInBits();
4675+
Instruction *ShiftI;
46694676
Value *X, *Y;
46704677
ICmpInst::Predicate Pred2;
4671-
if (match(Op0, m_LShr(m_Value(X), m_SpecificIntAllowUndef(OpWidth - 1))) &&
4678+
if (match(Op0, m_CombineAnd(m_Instruction(ShiftI),
4679+
m_Shr(m_Value(X),
4680+
m_SpecificIntAllowUndef(OpWidth - 1)))) &&
46724681
match(A, m_ICmp(Pred2, m_Value(Y), m_AllOnes())) &&
46734682
Pred2 == ICmpInst::ICMP_SGT && X->getType() == Y->getType()) {
4674-
Value *Xor = Builder.CreateXor(X, Y, "xor.signbits");
4675-
Value *R = (Pred == ICmpInst::ICMP_EQ) ? Builder.CreateIsNeg(Xor) :
4676-
Builder.CreateIsNotNeg(Xor);
4677-
return replaceInstUsesWith(I, R);
4683+
unsigned ExtOpc = ExtI->getOpcode();
4684+
unsigned ShiftOpc = ShiftI->getOpcode();
4685+
if ((ExtOpc == Instruction::ZExt && ShiftOpc == Instruction::LShr) ||
4686+
(ExtOpc == Instruction::SExt && ShiftOpc == Instruction::AShr)) {
4687+
Value *Xor = Builder.CreateXor(X, Y, "xor.signbits");
4688+
Value *R = (Pred == ICmpInst::ICMP_EQ) ? Builder.CreateIsNeg(Xor)
4689+
: Builder.CreateIsNotNeg(Xor);
4690+
return replaceInstUsesWith(I, R);
4691+
}
46784692
}
46794693
}
46804694

llvm/test/Transforms/InstCombine/icmp-shr.ll

Lines changed: 16 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1465,10 +1465,8 @@ define i1 @exactly_one_set_signbit_wrong_pred(i8 %x, i8 %y) {
14651465

14661466
define i1 @exactly_one_set_signbit_signed(i8 %x, i8 %y) {
14671467
; CHECK-LABEL: @exactly_one_set_signbit_signed(
1468-
; CHECK-NEXT: [[XSIGN:%.*]] = ashr i8 [[X:%.*]], 7
1469-
; CHECK-NEXT: [[YPOS:%.*]] = icmp sgt i8 [[Y:%.*]], -1
1470-
; CHECK-NEXT: [[YPOSZ:%.*]] = sext i1 [[YPOS]] to i8
1471-
; CHECK-NEXT: [[R:%.*]] = icmp eq i8 [[XSIGN]], [[YPOSZ]]
1468+
; CHECK-NEXT: [[XOR_SIGNBITS:%.*]] = xor i8 [[X:%.*]], [[Y:%.*]]
1469+
; CHECK-NEXT: [[R:%.*]] = icmp slt i8 [[XOR_SIGNBITS]], 0
14721470
; CHECK-NEXT: ret i1 [[R]]
14731471
;
14741472
%xsign = ashr i8 %x, 7
@@ -1482,9 +1480,8 @@ define i1 @exactly_one_set_signbit_use1_signed(i8 %x, i8 %y) {
14821480
; CHECK-LABEL: @exactly_one_set_signbit_use1_signed(
14831481
; CHECK-NEXT: [[XSIGN:%.*]] = ashr i8 [[X:%.*]], 7
14841482
; CHECK-NEXT: call void @use(i8 [[XSIGN]])
1485-
; CHECK-NEXT: [[YPOS:%.*]] = icmp sgt i8 [[Y:%.*]], -1
1486-
; CHECK-NEXT: [[YPOSZ:%.*]] = sext i1 [[YPOS]] to i8
1487-
; CHECK-NEXT: [[R:%.*]] = icmp eq i8 [[XSIGN]], [[YPOSZ]]
1483+
; CHECK-NEXT: [[XOR_SIGNBITS:%.*]] = xor i8 [[X]], [[Y:%.*]]
1484+
; CHECK-NEXT: [[R:%.*]] = icmp slt i8 [[XOR_SIGNBITS]], 0
14881485
; CHECK-NEXT: ret i1 [[R]]
14891486
;
14901487
%xsign = ashr i8 %x, 7
@@ -1497,10 +1494,8 @@ define i1 @exactly_one_set_signbit_use1_signed(i8 %x, i8 %y) {
14971494

14981495
define <2 x i1> @same_signbit_signed(<2 x i8> %x, <2 x i8> %y) {
14991496
; CHECK-LABEL: @same_signbit_signed(
1500-
; CHECK-NEXT: [[XSIGN:%.*]] = ashr <2 x i8> [[X:%.*]], <i8 7, i8 7>
1501-
; CHECK-NEXT: [[YPOS:%.*]] = icmp sgt <2 x i8> [[Y:%.*]], <i8 -1, i8 -1>
1502-
; CHECK-NEXT: [[YPOSZ:%.*]] = sext <2 x i1> [[YPOS]] to <2 x i8>
1503-
; CHECK-NEXT: [[R:%.*]] = icmp ne <2 x i8> [[XSIGN]], [[YPOSZ]]
1497+
; CHECK-NEXT: [[XOR_SIGNBITS:%.*]] = xor <2 x i8> [[X:%.*]], [[Y:%.*]]
1498+
; CHECK-NEXT: [[R:%.*]] = icmp sgt <2 x i8> [[XOR_SIGNBITS]], <i8 -1, i8 -1>
15041499
; CHECK-NEXT: ret <2 x i1> [[R]]
15051500
;
15061501
%xsign = ashr <2 x i8> %x, <i8 7, i8 7>
@@ -1512,11 +1507,11 @@ define <2 x i1> @same_signbit_signed(<2 x i8> %x, <2 x i8> %y) {
15121507

15131508
define i1 @same_signbit_use2_signed(i8 %x, i8 %y) {
15141509
; CHECK-LABEL: @same_signbit_use2_signed(
1515-
; CHECK-NEXT: [[XSIGN:%.*]] = ashr i8 [[X:%.*]], 7
15161510
; CHECK-NEXT: [[YPOS:%.*]] = icmp sgt i8 [[Y:%.*]], -1
15171511
; CHECK-NEXT: [[YPOSZ:%.*]] = sext i1 [[YPOS]] to i8
15181512
; CHECK-NEXT: call void @use(i8 [[YPOSZ]])
1519-
; CHECK-NEXT: [[R:%.*]] = icmp ne i8 [[XSIGN]], [[YPOSZ]]
1513+
; CHECK-NEXT: [[XOR_SIGNBITS:%.*]] = xor i8 [[X:%.*]], [[Y]]
1514+
; CHECK-NEXT: [[R:%.*]] = icmp sgt i8 [[XOR_SIGNBITS]], -1
15201515
; CHECK-NEXT: ret i1 [[R]]
15211516
;
15221517
%xsign = ashr i8 %x, 7
@@ -1527,6 +1522,8 @@ define i1 @same_signbit_use2_signed(i8 %x, i8 %y) {
15271522
ret i1 %r
15281523
}
15291524

1525+
; negative test
1526+
15301527
define i1 @same_signbit_use3_signed(i8 %x, i8 %y) {
15311528
; CHECK-LABEL: @same_signbit_use3_signed(
15321529
; CHECK-NEXT: [[XSIGN:%.*]] = ashr i8 [[X:%.*]], 7
@@ -1548,10 +1545,8 @@ define i1 @same_signbit_use3_signed(i8 %x, i8 %y) {
15481545

15491546
define <2 x i1> @same_signbit_poison_elts_signed(<2 x i8> %x, <2 x i8> %y) {
15501547
; CHECK-LABEL: @same_signbit_poison_elts_signed(
1551-
; CHECK-NEXT: [[XSIGN:%.*]] = ashr <2 x i8> [[X:%.*]], <i8 7, i8 poison>
1552-
; CHECK-NEXT: [[YPOS:%.*]] = icmp sgt <2 x i8> [[Y:%.*]], <i8 -1, i8 poison>
1553-
; CHECK-NEXT: [[YPOSZ:%.*]] = sext <2 x i1> [[YPOS]] to <2 x i8>
1554-
; CHECK-NEXT: [[R:%.*]] = icmp ne <2 x i8> [[XSIGN]], [[YPOSZ]]
1548+
; CHECK-NEXT: [[XOR_SIGNBITS:%.*]] = xor <2 x i8> [[X:%.*]], [[Y:%.*]]
1549+
; CHECK-NEXT: [[R:%.*]] = icmp sgt <2 x i8> [[XOR_SIGNBITS]], <i8 -1, i8 -1>
15551550
; CHECK-NEXT: ret <2 x i1> [[R]]
15561551
;
15571552
%xsign = ashr <2 x i8> %x, <i8 7, i8 poison>
@@ -1561,6 +1556,8 @@ define <2 x i1> @same_signbit_poison_elts_signed(<2 x i8> %x, <2 x i8> %y) {
15611556
ret <2 x i1> %r
15621557
}
15631558

1559+
; negative test
1560+
15641561
define i1 @same_signbit_wrong_type_signed(i8 %x, i32 %y) {
15651562
; CHECK-LABEL: @same_signbit_wrong_type_signed(
15661563
; CHECK-NEXT: [[XSIGN:%.*]] = ashr i8 [[X:%.*]], 7
@@ -1576,6 +1573,8 @@ define i1 @same_signbit_wrong_type_signed(i8 %x, i32 %y) {
15761573
ret i1 %r
15771574
}
15781575

1576+
; negative test
1577+
15791578
define i1 @exactly_one_set_signbit_wrong_shamt_signed(i8 %x, i8 %y) {
15801579
; CHECK-LABEL: @exactly_one_set_signbit_wrong_shamt_signed(
15811580
; CHECK-NEXT: [[XSIGN:%.*]] = ashr i8 [[X:%.*]], 6

0 commit comments

Comments
 (0)