Skip to content

Commit 7cbfc39

Browse files
committed
[InstCombine] reduce compare of signbits of 2 values
Test if 2 values have different or same signbits: (X u>> BitWidth - 1) == zext (Y s> -1) --> (X ^ Y) < 0 (X u>> BitWidth - 1) != zext (Y s> -1) --> (X ^ Y) > -1 https://alive2.llvm.org/ce/z/qMwMhj As noted in #60242, these patterns regressed between the 14.0 and 15.0 releases - probably due to a change in canonicalization of related patterns. The related patterns for testing if 2 values are both pos/neg appear to be handled already.
1 parent d1511ed commit 7cbfc39

File tree

2 files changed

+47
-25
lines changed

2 files changed

+47
-25
lines changed

llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4653,14 +4653,30 @@ Instruction *InstCombinerImpl::foldICmpEquality(ICmpInst &I) {
46534653
}
46544654
}
46554655

4656-
// (B & (Pow2C-1)) == zext A --> A == trunc B
4657-
// (B & (Pow2C-1)) != zext A --> A != trunc B
4658-
const APInt *MaskC;
4659-
if (match(Op0, m_And(m_Value(B), m_LowBitMask(MaskC))) &&
4660-
match(Op1, m_ZExt(m_Value(A))) &&
4661-
MaskC->countTrailingOnes() == A->getType()->getScalarSizeInBits() &&
4662-
(Op0->hasOneUse() || Op1->hasOneUse()))
4663-
return new ICmpInst(Pred, A, Builder.CreateTrunc(B, A->getType()));
4656+
if (match(Op1, m_ZExt(m_Value(A))) &&
4657+
(Op0->hasOneUse() || Op1->hasOneUse())) {
4658+
// (B & (Pow2C-1)) == zext A --> A == trunc B
4659+
// (B & (Pow2C-1)) != zext A --> A != trunc B
4660+
const APInt *MaskC;
4661+
if (match(Op0, m_And(m_Value(B), m_LowBitMask(MaskC))) &&
4662+
MaskC->countTrailingOnes() == A->getType()->getScalarSizeInBits())
4663+
return new ICmpInst(Pred, A, Builder.CreateTrunc(B, A->getType()));
4664+
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
4668+
unsigned OpWidth = Op0->getType()->getScalarSizeInBits();
4669+
Value *X, *Y;
4670+
ICmpInst::Predicate Pred2;
4671+
if (match(Op0, m_LShr(m_Value(X), m_SpecificIntAllowUndef(OpWidth - 1))) &&
4672+
match(A, m_ICmp(Pred2, m_Value(Y), m_AllOnes())) &&
4673+
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);
4678+
}
4679+
}
46644680

46654681
// (A >> C) == (B >> C) --> (A^B) u< (1 << C)
46664682
// For lshr and ashr pairs.

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

Lines changed: 23 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1302,10 +1302,8 @@ define i1 @lshr_neg_sgt_zero(i8 %x) {
13021302

13031303
define i1 @exactly_one_set_signbit(i8 %x, i8 %y) {
13041304
; CHECK-LABEL: @exactly_one_set_signbit(
1305-
; CHECK-NEXT: [[XSIGN:%.*]] = lshr i8 [[X:%.*]], 7
1306-
; CHECK-NEXT: [[YPOS:%.*]] = icmp sgt i8 [[Y:%.*]], -1
1307-
; CHECK-NEXT: [[YPOSZ:%.*]] = zext i1 [[YPOS]] to i8
1308-
; CHECK-NEXT: [[R:%.*]] = icmp eq i8 [[XSIGN]], [[YPOSZ]]
1305+
; CHECK-NEXT: [[XOR_SIGNBITS:%.*]] = xor i8 [[X:%.*]], [[Y:%.*]]
1306+
; CHECK-NEXT: [[R:%.*]] = icmp slt i8 [[XOR_SIGNBITS]], 0
13091307
; CHECK-NEXT: ret i1 [[R]]
13101308
;
13111309
%xsign = lshr i8 %x, 7
@@ -1319,9 +1317,8 @@ define i1 @exactly_one_set_signbit_use1(i8 %x, i8 %y) {
13191317
; CHECK-LABEL: @exactly_one_set_signbit_use1(
13201318
; CHECK-NEXT: [[XSIGN:%.*]] = lshr i8 [[X:%.*]], 7
13211319
; CHECK-NEXT: call void @use(i8 [[XSIGN]])
1322-
; CHECK-NEXT: [[YPOS:%.*]] = icmp sgt i8 [[Y:%.*]], -1
1323-
; CHECK-NEXT: [[YPOSZ:%.*]] = zext i1 [[YPOS]] to i8
1324-
; CHECK-NEXT: [[R:%.*]] = icmp eq i8 [[XSIGN]], [[YPOSZ]]
1320+
; CHECK-NEXT: [[XOR_SIGNBITS:%.*]] = xor i8 [[X]], [[Y:%.*]]
1321+
; CHECK-NEXT: [[R:%.*]] = icmp slt i8 [[XOR_SIGNBITS]], 0
13251322
; CHECK-NEXT: ret i1 [[R]]
13261323
;
13271324
%xsign = lshr i8 %x, 7
@@ -1334,10 +1331,8 @@ define i1 @exactly_one_set_signbit_use1(i8 %x, i8 %y) {
13341331

13351332
define <2 x i1> @same_signbit(<2 x i8> %x, <2 x i8> %y) {
13361333
; CHECK-LABEL: @same_signbit(
1337-
; CHECK-NEXT: [[XSIGN:%.*]] = lshr <2 x i8> [[X:%.*]], <i8 7, i8 7>
1338-
; CHECK-NEXT: [[YPOS:%.*]] = icmp sgt <2 x i8> [[Y:%.*]], <i8 -1, i8 -1>
1339-
; CHECK-NEXT: [[YPOSZ:%.*]] = zext <2 x i1> [[YPOS]] to <2 x i8>
1340-
; CHECK-NEXT: [[R:%.*]] = icmp ne <2 x i8> [[XSIGN]], [[YPOSZ]]
1334+
; CHECK-NEXT: [[XOR_SIGNBITS:%.*]] = xor <2 x i8> [[X:%.*]], [[Y:%.*]]
1335+
; CHECK-NEXT: [[R:%.*]] = icmp sgt <2 x i8> [[XOR_SIGNBITS]], <i8 -1, i8 -1>
13411336
; CHECK-NEXT: ret <2 x i1> [[R]]
13421337
;
13431338
%xsign = lshr <2 x i8> %x, <i8 7, i8 7>
@@ -1349,11 +1344,11 @@ define <2 x i1> @same_signbit(<2 x i8> %x, <2 x i8> %y) {
13491344

13501345
define i1 @same_signbit_use2(i8 %x, i8 %y) {
13511346
; CHECK-LABEL: @same_signbit_use2(
1352-
; CHECK-NEXT: [[XSIGN:%.*]] = lshr i8 [[X:%.*]], 7
13531347
; CHECK-NEXT: [[YPOS:%.*]] = icmp sgt i8 [[Y:%.*]], -1
13541348
; CHECK-NEXT: [[YPOSZ:%.*]] = zext i1 [[YPOS]] to i8
13551349
; CHECK-NEXT: call void @use(i8 [[YPOSZ]])
1356-
; CHECK-NEXT: [[R:%.*]] = icmp ne i8 [[XSIGN]], [[YPOSZ]]
1350+
; CHECK-NEXT: [[XOR_SIGNBITS:%.*]] = xor i8 [[X:%.*]], [[Y]]
1351+
; CHECK-NEXT: [[R:%.*]] = icmp sgt i8 [[XOR_SIGNBITS]], -1
13571352
; CHECK-NEXT: ret i1 [[R]]
13581353
;
13591354
%xsign = lshr i8 %x, 7
@@ -1364,6 +1359,8 @@ define i1 @same_signbit_use2(i8 %x, i8 %y) {
13641359
ret i1 %r
13651360
}
13661361

1362+
; negative test
1363+
13671364
define i1 @same_signbit_use3(i8 %x, i8 %y) {
13681365
; CHECK-LABEL: @same_signbit_use3(
13691366
; CHECK-NEXT: [[XSIGN:%.*]] = lshr i8 [[X:%.*]], 7
@@ -1385,10 +1382,8 @@ define i1 @same_signbit_use3(i8 %x, i8 %y) {
13851382

13861383
define <2 x i1> @same_signbit_poison_elts(<2 x i8> %x, <2 x i8> %y) {
13871384
; CHECK-LABEL: @same_signbit_poison_elts(
1388-
; CHECK-NEXT: [[XSIGN:%.*]] = lshr <2 x i8> [[X:%.*]], <i8 7, i8 poison>
1389-
; CHECK-NEXT: [[YPOS:%.*]] = icmp sgt <2 x i8> [[Y:%.*]], <i8 -1, i8 poison>
1390-
; CHECK-NEXT: [[YPOSZ:%.*]] = zext <2 x i1> [[YPOS]] to <2 x i8>
1391-
; CHECK-NEXT: [[R:%.*]] = icmp ne <2 x i8> [[XSIGN]], [[YPOSZ]]
1385+
; CHECK-NEXT: [[XOR_SIGNBITS:%.*]] = xor <2 x i8> [[X:%.*]], [[Y:%.*]]
1386+
; CHECK-NEXT: [[R:%.*]] = icmp sgt <2 x i8> [[XOR_SIGNBITS]], <i8 -1, i8 -1>
13921387
; CHECK-NEXT: ret <2 x i1> [[R]]
13931388
;
13941389
%xsign = lshr <2 x i8> %x, <i8 7, i8 poison>
@@ -1398,6 +1393,8 @@ define <2 x i1> @same_signbit_poison_elts(<2 x i8> %x, <2 x i8> %y) {
13981393
ret <2 x i1> %r
13991394
}
14001395

1396+
; negative test
1397+
14011398
define i1 @same_signbit_wrong_type(i8 %x, i32 %y) {
14021399
; CHECK-LABEL: @same_signbit_wrong_type(
14031400
; CHECK-NEXT: [[XSIGN:%.*]] = lshr i8 [[X:%.*]], 7
@@ -1412,6 +1409,9 @@ define i1 @same_signbit_wrong_type(i8 %x, i32 %y) {
14121409
%r = icmp ne i8 %xsign, %yposz
14131410
ret i1 %r
14141411
}
1412+
1413+
; negative test
1414+
14151415
define i1 @exactly_one_set_signbit_wrong_shamt(i8 %x, i8 %y) {
14161416
; CHECK-LABEL: @exactly_one_set_signbit_wrong_shamt(
14171417
; CHECK-NEXT: [[XSIGN:%.*]] = lshr i8 [[X:%.*]], 6
@@ -1427,6 +1427,9 @@ define i1 @exactly_one_set_signbit_wrong_shamt(i8 %x, i8 %y) {
14271427
ret i1 %r
14281428
}
14291429

1430+
; negative test
1431+
; TODO: This could reduce.
1432+
14301433
define i1 @exactly_one_set_signbit_wrong_shr(i8 %x, i8 %y) {
14311434
; CHECK-LABEL: @exactly_one_set_signbit_wrong_shr(
14321435
; CHECK-NEXT: [[XSIGN:%.*]] = ashr i8 [[X:%.*]], 7
@@ -1442,6 +1445,9 @@ define i1 @exactly_one_set_signbit_wrong_shr(i8 %x, i8 %y) {
14421445
ret i1 %r
14431446
}
14441447

1448+
; negative test
1449+
; TODO: This could reduce.
1450+
14451451
define i1 @exactly_one_set_signbit_wrong_pred(i8 %x, i8 %y) {
14461452
; CHECK-LABEL: @exactly_one_set_signbit_wrong_pred(
14471453
; CHECK-NEXT: [[XSIGN:%.*]] = lshr i8 [[X:%.*]], 7

0 commit comments

Comments
 (0)