Skip to content

Commit 727e642

Browse files
committed
[InstCombine] generalize fold for mask-with-signbit-splat
(iN X s>> (N-1)) & Y --> (X < 0) ? Y : 0 https://alive2.llvm.org/ce/z/qeYhdz I was looking at a missing abs() transform and found my way to this generalization of an existing fold that was added with D67799. As discussed in that review, we want to make sure codegen handles this difference well, and for all of the targets/types that I spot-checked, it looks good. I am leaving the existing fold in place in this commit because it covers a potentially missing icmp fold, but I plan to remove that as a follow-up commit as suggested during review. Differential Revision: https://reviews.llvm.org/D111410
1 parent 3b48e11 commit 727e642

File tree

5 files changed

+55
-39
lines changed

5 files changed

+55
-39
lines changed

llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2062,14 +2062,24 @@ Instruction *InstCombinerImpl::visitAnd(BinaryOperator &I) {
20622062
return SelectInst::Create(A, Op0, Constant::getNullValue(Ty));
20632063

20642064
// and(ashr(subNSW(Y, X), ScalarSizeInBits(Y)-1), X) --> X s> Y ? X : 0.
2065-
if (match(&I, m_c_And(m_OneUse(m_AShr(
2066-
m_NSWSub(m_Value(Y), m_Value(X)),
2067-
m_SpecificInt(Ty->getScalarSizeInBits() - 1))),
2065+
// TODO: This is a specific case of the more general pattern below, so it
2066+
// should be removed.
2067+
unsigned FullShift = Ty->getScalarSizeInBits() - 1;
2068+
if (match(&I, m_c_And(m_OneUse(m_AShr(m_NSWSub(m_Value(Y), m_Value(X)),
2069+
m_SpecificInt(FullShift))),
20682070
m_Deferred(X)))) {
20692071
Value *NewICmpInst = Builder.CreateICmpSGT(X, Y);
20702072
return SelectInst::Create(NewICmpInst, X, ConstantInt::getNullValue(Ty));
20712073
}
20722074

2075+
// (iN X s>> (N-1)) & Y --> (X < 0) ? Y : 0
2076+
if (match(&I, m_c_And(m_OneUse(m_AShr(m_Value(X), m_SpecificInt(FullShift))),
2077+
m_Value(Y)))) {
2078+
Constant *Zero = ConstantInt::getNullValue(Ty);
2079+
Value *Cmp = Builder.CreateICmpSLT(X, Zero, "isneg");
2080+
return SelectInst::Create(Cmp, Y, Zero);
2081+
}
2082+
20732083
// (~x) & y --> ~(x | (~y)) iff that gets rid of inversions
20742084
if (sinkNotIntoOtherHandOfAndOrOr(I))
20752085
return &I;

llvm/test/Transforms/InstCombine/and.ll

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1403,8 +1403,8 @@ define <2 x i8> @flip_masked_bit_nonuniform(<2 x i8> %A) {
14031403

14041404
define i8 @ashr_bitwidth_mask(i8 %x, i8 %y) {
14051405
; CHECK-LABEL: @ashr_bitwidth_mask(
1406-
; CHECK-NEXT: [[SIGN:%.*]] = ashr i8 [[X:%.*]], 7
1407-
; CHECK-NEXT: [[NEG_OR_ZERO:%.*]] = and i8 [[SIGN]], [[Y:%.*]]
1406+
; CHECK-NEXT: [[ISNEG:%.*]] = icmp slt i8 [[X:%.*]], 0
1407+
; CHECK-NEXT: [[NEG_OR_ZERO:%.*]] = select i1 [[ISNEG]], i8 [[Y:%.*]], i8 0
14081408
; CHECK-NEXT: ret i8 [[NEG_OR_ZERO]]
14091409
;
14101410
%sign = ashr i8 %x, 7
@@ -1415,8 +1415,8 @@ define i8 @ashr_bitwidth_mask(i8 %x, i8 %y) {
14151415
define <2 x i8> @ashr_bitwidth_mask_vec_commute(<2 x i8> %x, <2 x i8> %py) {
14161416
; CHECK-LABEL: @ashr_bitwidth_mask_vec_commute(
14171417
; CHECK-NEXT: [[Y:%.*]] = mul <2 x i8> [[PY:%.*]], <i8 42, i8 2>
1418-
; CHECK-NEXT: [[SIGN:%.*]] = ashr <2 x i8> [[X:%.*]], <i8 7, i8 7>
1419-
; CHECK-NEXT: [[NEG_OR_ZERO:%.*]] = and <2 x i8> [[Y]], [[SIGN]]
1418+
; CHECK-NEXT: [[ISNEG:%.*]] = icmp slt <2 x i8> [[X:%.*]], zeroinitializer
1419+
; CHECK-NEXT: [[NEG_OR_ZERO:%.*]] = select <2 x i1> [[ISNEG]], <2 x i8> [[Y]], <2 x i8> zeroinitializer
14201420
; CHECK-NEXT: ret <2 x i8> [[NEG_OR_ZERO]]
14211421
;
14221422
%y = mul <2 x i8> %py, <i8 42, i8 2> ; thwart complexity-based ordering
@@ -1425,6 +1425,8 @@ define <2 x i8> @ashr_bitwidth_mask_vec_commute(<2 x i8> %x, <2 x i8> %py) {
14251425
ret <2 x i8> %neg_or_zero
14261426
}
14271427

1428+
; negative test - extra use
1429+
14281430
define i8 @ashr_bitwidth_mask_use(i8 %x, i8 %y) {
14291431
; CHECK-LABEL: @ashr_bitwidth_mask_use(
14301432
; CHECK-NEXT: [[SIGN:%.*]] = ashr i8 [[X:%.*]], 7
@@ -1438,6 +1440,8 @@ define i8 @ashr_bitwidth_mask_use(i8 %x, i8 %y) {
14381440
ret i8 %r
14391441
}
14401442

1443+
; negative test - wrong shift amount
1444+
14411445
define i8 @ashr_not_bitwidth_mask(i8 %x, i8 %y) {
14421446
; CHECK-LABEL: @ashr_not_bitwidth_mask(
14431447
; CHECK-NEXT: [[SIGN:%.*]] = ashr i8 [[X:%.*]], 6
@@ -1449,6 +1453,8 @@ define i8 @ashr_not_bitwidth_mask(i8 %x, i8 %y) {
14491453
ret i8 %r
14501454
}
14511455

1456+
; negative test - wrong shift opcode
1457+
14521458
define i8 @lshr_bitwidth_mask(i8 %x, i8 %y) {
14531459
; CHECK-LABEL: @lshr_bitwidth_mask(
14541460
; CHECK-NEXT: [[SIGN:%.*]] = lshr i8 [[X:%.*]], 7

llvm/test/Transforms/InstCombine/icmp.ll

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -100,8 +100,8 @@ define <2 x i1> @test5_zero() {
100100

101101
define i32 @test6(i32 %a, i32 %b) {
102102
; CHECK-LABEL: @test6(
103-
; CHECK-NEXT: [[A_LOBIT_NEG:%.*]] = ashr i32 [[A:%.*]], 31
104-
; CHECK-NEXT: [[F:%.*]] = and i32 [[A_LOBIT_NEG]], [[B:%.*]]
103+
; CHECK-NEXT: [[ISNEG:%.*]] = icmp slt i32 [[A:%.*]], 0
104+
; CHECK-NEXT: [[F:%.*]] = select i1 [[ISNEG]], i32 [[B:%.*]], i32 0
105105
; CHECK-NEXT: ret i32 [[F]]
106106
;
107107
%c = icmp sle i32 %a, -1

llvm/test/Transforms/InstCombine/mul-inseltpoison.ll

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,8 @@ define i32 @neg(i32 %i) {
4545

4646
define i32 @test10(i32 %a, i32 %b) {
4747
; CHECK-LABEL: @test10(
48-
; CHECK-NEXT: [[TMP1:%.*]] = ashr i32 [[A:%.*]], 31
49-
; CHECK-NEXT: [[E:%.*]] = and i32 [[TMP1]], [[B:%.*]]
48+
; CHECK-NEXT: [[ISNEG:%.*]] = icmp slt i32 [[A:%.*]], 0
49+
; CHECK-NEXT: [[E:%.*]] = select i1 [[ISNEG]], i32 [[B:%.*]], i32 0
5050
; CHECK-NEXT: ret i32 [[E]]
5151
;
5252
%c = icmp slt i32 %a, 0
@@ -57,8 +57,8 @@ define i32 @test10(i32 %a, i32 %b) {
5757

5858
define i32 @test11(i32 %a, i32 %b) {
5959
; CHECK-LABEL: @test11(
60-
; CHECK-NEXT: [[TMP1:%.*]] = ashr i32 [[A:%.*]], 31
61-
; CHECK-NEXT: [[E:%.*]] = and i32 [[TMP1]], [[B:%.*]]
60+
; CHECK-NEXT: [[ISNEG:%.*]] = icmp slt i32 [[A:%.*]], 0
61+
; CHECK-NEXT: [[E:%.*]] = select i1 [[ISNEG]], i32 [[B:%.*]], i32 0
6262
; CHECK-NEXT: ret i32 [[E]]
6363
;
6464
%c = icmp sle i32 %a, -1
@@ -72,8 +72,8 @@ declare void @use32(i32)
7272
define i32 @test12(i32 %a, i32 %b) {
7373
; CHECK-LABEL: @test12(
7474
; CHECK-NEXT: [[A_LOBIT:%.*]] = lshr i32 [[A:%.*]], 31
75-
; CHECK-NEXT: [[TMP1:%.*]] = ashr i32 [[A]], 31
76-
; CHECK-NEXT: [[E:%.*]] = and i32 [[TMP1]], [[B:%.*]]
75+
; CHECK-NEXT: [[ISNEG:%.*]] = icmp slt i32 [[A]], 0
76+
; CHECK-NEXT: [[E:%.*]] = select i1 [[ISNEG]], i32 [[B:%.*]], i32 0
7777
; CHECK-NEXT: call void @use32(i32 [[A_LOBIT]])
7878
; CHECK-NEXT: ret i32 [[E]]
7979
;
@@ -310,8 +310,8 @@ define i32 @mul_bools_mixed_ext_use3(i1 %x, i1 %y) {
310310

311311
define i32 @signbit_mul(i32 %a, i32 %b) {
312312
; CHECK-LABEL: @signbit_mul(
313-
; CHECK-NEXT: [[TMP1:%.*]] = ashr i32 [[A:%.*]], 31
314-
; CHECK-NEXT: [[E:%.*]] = and i32 [[TMP1]], [[B:%.*]]
313+
; CHECK-NEXT: [[ISNEG:%.*]] = icmp slt i32 [[A:%.*]], 0
314+
; CHECK-NEXT: [[E:%.*]] = select i1 [[ISNEG]], i32 [[B:%.*]], i32 0
315315
; CHECK-NEXT: ret i32 [[E]]
316316
;
317317
%d = lshr i32 %a, 31
@@ -322,8 +322,8 @@ define i32 @signbit_mul(i32 %a, i32 %b) {
322322
define i32 @signbit_mul_commute_extra_use(i32 %a, i32 %b) {
323323
; CHECK-LABEL: @signbit_mul_commute_extra_use(
324324
; CHECK-NEXT: [[D:%.*]] = lshr i32 [[A:%.*]], 31
325-
; CHECK-NEXT: [[TMP1:%.*]] = ashr i32 [[A]], 31
326-
; CHECK-NEXT: [[E:%.*]] = and i32 [[TMP1]], [[B:%.*]]
325+
; CHECK-NEXT: [[ISNEG:%.*]] = icmp slt i32 [[A]], 0
326+
; CHECK-NEXT: [[E:%.*]] = select i1 [[ISNEG]], i32 [[B:%.*]], i32 0
327327
; CHECK-NEXT: call void @use32(i32 [[D]])
328328
; CHECK-NEXT: ret i32 [[E]]
329329
;
@@ -337,8 +337,8 @@ define i32 @signbit_mul_commute_extra_use(i32 %a, i32 %b) {
337337

338338
define <2 x i32> @signbit_mul_vec(<2 x i32> %a, <2 x i32> %b) {
339339
; CHECK-LABEL: @signbit_mul_vec(
340-
; CHECK-NEXT: [[TMP1:%.*]] = ashr <2 x i32> [[A:%.*]], <i32 31, i32 31>
341-
; CHECK-NEXT: [[E:%.*]] = and <2 x i32> [[TMP1]], [[B:%.*]]
340+
; CHECK-NEXT: [[ISNEG:%.*]] = icmp slt <2 x i32> [[A:%.*]], zeroinitializer
341+
; CHECK-NEXT: [[E:%.*]] = select <2 x i1> [[ISNEG]], <2 x i32> [[B:%.*]], <2 x i32> zeroinitializer
342342
; CHECK-NEXT: ret <2 x i32> [[E]]
343343
;
344344
%d = lshr <2 x i32> %a, <i32 31, i32 31>
@@ -348,8 +348,8 @@ define <2 x i32> @signbit_mul_vec(<2 x i32> %a, <2 x i32> %b) {
348348

349349
define <2 x i32> @signbit_mul_vec_commute(<2 x i32> %a, <2 x i32> %b) {
350350
; CHECK-LABEL: @signbit_mul_vec_commute(
351-
; CHECK-NEXT: [[TMP1:%.*]] = ashr <2 x i32> [[A:%.*]], <i32 31, i32 31>
352-
; CHECK-NEXT: [[E:%.*]] = and <2 x i32> [[TMP1]], [[B:%.*]]
351+
; CHECK-NEXT: [[ISNEG:%.*]] = icmp slt <2 x i32> [[A:%.*]], zeroinitializer
352+
; CHECK-NEXT: [[E:%.*]] = select <2 x i1> [[ISNEG]], <2 x i32> [[B:%.*]], <2 x i32> zeroinitializer
353353
; CHECK-NEXT: ret <2 x i32> [[E]]
354354
;
355355
%d = lshr <2 x i32> %a, <i32 31, i32 31>

llvm/test/Transforms/InstCombine/mul.ll

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,8 @@ define i32 @neg(i32 %i) {
4545

4646
define i32 @test10(i32 %a, i32 %b) {
4747
; CHECK-LABEL: @test10(
48-
; CHECK-NEXT: [[TMP1:%.*]] = ashr i32 [[A:%.*]], 31
49-
; CHECK-NEXT: [[E:%.*]] = and i32 [[TMP1]], [[B:%.*]]
48+
; CHECK-NEXT: [[ISNEG:%.*]] = icmp slt i32 [[A:%.*]], 0
49+
; CHECK-NEXT: [[E:%.*]] = select i1 [[ISNEG]], i32 [[B:%.*]], i32 0
5050
; CHECK-NEXT: ret i32 [[E]]
5151
;
5252
%c = icmp slt i32 %a, 0
@@ -57,8 +57,8 @@ define i32 @test10(i32 %a, i32 %b) {
5757

5858
define i32 @test11(i32 %a, i32 %b) {
5959
; CHECK-LABEL: @test11(
60-
; CHECK-NEXT: [[TMP1:%.*]] = ashr i32 [[A:%.*]], 31
61-
; CHECK-NEXT: [[E:%.*]] = and i32 [[TMP1]], [[B:%.*]]
60+
; CHECK-NEXT: [[ISNEG:%.*]] = icmp slt i32 [[A:%.*]], 0
61+
; CHECK-NEXT: [[E:%.*]] = select i1 [[ISNEG]], i32 [[B:%.*]], i32 0
6262
; CHECK-NEXT: ret i32 [[E]]
6363
;
6464
%c = icmp sle i32 %a, -1
@@ -72,8 +72,8 @@ declare void @use32(i32)
7272
define i32 @test12(i32 %a, i32 %b) {
7373
; CHECK-LABEL: @test12(
7474
; CHECK-NEXT: [[A_LOBIT:%.*]] = lshr i32 [[A:%.*]], 31
75-
; CHECK-NEXT: [[TMP1:%.*]] = ashr i32 [[A]], 31
76-
; CHECK-NEXT: [[E:%.*]] = and i32 [[TMP1]], [[B:%.*]]
75+
; CHECK-NEXT: [[ISNEG:%.*]] = icmp slt i32 [[A]], 0
76+
; CHECK-NEXT: [[E:%.*]] = select i1 [[ISNEG]], i32 [[B:%.*]], i32 0
7777
; CHECK-NEXT: call void @use32(i32 [[A_LOBIT]])
7878
; CHECK-NEXT: ret i32 [[E]]
7979
;
@@ -376,12 +376,12 @@ define i32 @mul_bools_mixed_ext_use3(i1 %x, i1 %y) {
376376
ret i32 %r
377377
}
378378

379-
; (A >>u 31) * B --> (A >>s 31) & B
379+
; (A >>u 31) * B --> (A >>s 31) & B --> A < 0 ? B : 0
380380

381381
define i32 @signbit_mul(i32 %a, i32 %b) {
382382
; CHECK-LABEL: @signbit_mul(
383-
; CHECK-NEXT: [[TMP1:%.*]] = ashr i32 [[A:%.*]], 31
384-
; CHECK-NEXT: [[E:%.*]] = and i32 [[TMP1]], [[B:%.*]]
383+
; CHECK-NEXT: [[ISNEG:%.*]] = icmp slt i32 [[A:%.*]], 0
384+
; CHECK-NEXT: [[E:%.*]] = select i1 [[ISNEG]], i32 [[B:%.*]], i32 0
385385
; CHECK-NEXT: ret i32 [[E]]
386386
;
387387
%d = lshr i32 %a, 31
@@ -392,8 +392,8 @@ define i32 @signbit_mul(i32 %a, i32 %b) {
392392
define i32 @signbit_mul_commute_extra_use(i32 %a, i32 %b) {
393393
; CHECK-LABEL: @signbit_mul_commute_extra_use(
394394
; CHECK-NEXT: [[D:%.*]] = lshr i32 [[A:%.*]], 31
395-
; CHECK-NEXT: [[TMP1:%.*]] = ashr i32 [[A]], 31
396-
; CHECK-NEXT: [[E:%.*]] = and i32 [[TMP1]], [[B:%.*]]
395+
; CHECK-NEXT: [[ISNEG:%.*]] = icmp slt i32 [[A]], 0
396+
; CHECK-NEXT: [[E:%.*]] = select i1 [[ISNEG]], i32 [[B:%.*]], i32 0
397397
; CHECK-NEXT: call void @use32(i32 [[D]])
398398
; CHECK-NEXT: ret i32 [[E]]
399399
;
@@ -403,12 +403,12 @@ define i32 @signbit_mul_commute_extra_use(i32 %a, i32 %b) {
403403
ret i32 %e
404404
}
405405

406-
; (A >>u 31)) * B --> (A >>s 31) & B
406+
; (A >>u 31)) * B --> (A >>s 31) & B --> A < 0 ? B : 0
407407

408408
define <2 x i32> @signbit_mul_vec(<2 x i32> %a, <2 x i32> %b) {
409409
; CHECK-LABEL: @signbit_mul_vec(
410-
; CHECK-NEXT: [[TMP1:%.*]] = ashr <2 x i32> [[A:%.*]], <i32 31, i32 31>
411-
; CHECK-NEXT: [[E:%.*]] = and <2 x i32> [[TMP1]], [[B:%.*]]
410+
; CHECK-NEXT: [[ISNEG:%.*]] = icmp slt <2 x i32> [[A:%.*]], zeroinitializer
411+
; CHECK-NEXT: [[E:%.*]] = select <2 x i1> [[ISNEG]], <2 x i32> [[B:%.*]], <2 x i32> zeroinitializer
412412
; CHECK-NEXT: ret <2 x i32> [[E]]
413413
;
414414
%d = lshr <2 x i32> %a, <i32 31, i32 31>
@@ -418,8 +418,8 @@ define <2 x i32> @signbit_mul_vec(<2 x i32> %a, <2 x i32> %b) {
418418

419419
define <2 x i32> @signbit_mul_vec_commute(<2 x i32> %a, <2 x i32> %b) {
420420
; CHECK-LABEL: @signbit_mul_vec_commute(
421-
; CHECK-NEXT: [[TMP1:%.*]] = ashr <2 x i32> [[A:%.*]], <i32 31, i32 31>
422-
; CHECK-NEXT: [[E:%.*]] = and <2 x i32> [[TMP1]], [[B:%.*]]
421+
; CHECK-NEXT: [[ISNEG:%.*]] = icmp slt <2 x i32> [[A:%.*]], zeroinitializer
422+
; CHECK-NEXT: [[E:%.*]] = select <2 x i1> [[ISNEG]], <2 x i32> [[B:%.*]], <2 x i32> zeroinitializer
423423
; CHECK-NEXT: ret <2 x i32> [[E]]
424424
;
425425
%d = lshr <2 x i32> %a, <i32 31, i32 31>

0 commit comments

Comments
 (0)