Skip to content

Commit fb94d49

Browse files
committed
[InstCombine] Fold ((X << nuw Z) binop nuw Y) >>u Z --> X binop nuw (Y >>u Z)
Proofs: https://alive2.llvm.org/ce/z/N9dRzP https://alive2.llvm.org/ce/z/Xrpc-Y https://alive2.llvm.org/ce/z/k2dtYZ
1 parent ae4ad96 commit fb94d49

File tree

2 files changed

+76
-44
lines changed

2 files changed

+76
-44
lines changed

llvm/lib/Transforms/InstCombine/InstCombineShifts.cpp

Lines changed: 48 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1259,6 +1259,54 @@ Instruction *InstCombinerImpl::visitLShr(BinaryOperator &I) {
12591259
match(Op1, m_SpecificIntAllowPoison(BitWidth - 1)))
12601260
return new ZExtInst(Builder.CreateIsNotNeg(X, "isnotneg"), Ty);
12611261

1262+
// ((X << nuw Z) sub nuw Y) >>u exact Z --> X sub nuw (Y >>u exact Z),
1263+
Value *Y;
1264+
if (I.isExact() &&
1265+
match(Op0, m_OneUse(m_NUWSub(m_NUWShl(m_Value(X), m_Specific(Op1)),
1266+
m_Value(Y))))) {
1267+
Value *NewLshr = Builder.CreateLShr(Y, Op1, "", /*isExact=*/true);
1268+
auto *NewSub = BinaryOperator::CreateNUWSub(X, NewLshr);
1269+
NewSub->setHasNoSignedWrap(
1270+
cast<OverflowingBinaryOperator>(Op0)->hasNoSignedWrap());
1271+
return NewSub;
1272+
}
1273+
1274+
auto isSuitableBinOpcode = [](Instruction::BinaryOps BinOpcode) {
1275+
switch (BinOpcode) {
1276+
default:
1277+
return false;
1278+
case Instruction::Add:
1279+
case Instruction::And:
1280+
case Instruction::Or:
1281+
case Instruction::Xor:
1282+
// And does not work here, and sub is handled separately.
1283+
return true;
1284+
}
1285+
};
1286+
1287+
// If both the binop and the shift are nuw, then:
1288+
// ((X << nuw Z) binop nuw Y) >>u Z --> X binop nuw (Y >>u Z)
1289+
if (match(Op0, m_OneUse(m_c_BinOp(m_NUWShl(m_Value(X), m_Specific(Op1)),
1290+
m_Value(Y))))) {
1291+
BinaryOperator *Op0OB = cast<BinaryOperator>(Op0);
1292+
if (isSuitableBinOpcode(Op0OB->getOpcode())) {
1293+
if (auto *OBO = dyn_cast<OverflowingBinaryOperator>(Op0);
1294+
!OBO || OBO->hasNoUnsignedWrap()) {
1295+
Value *NewLshr = Builder.CreateLShr(
1296+
Y, Op1, "", I.isExact() && Op0OB->getOpcode() != Instruction::And);
1297+
auto *NewBinOp = BinaryOperator::Create(Op0OB->getOpcode(), NewLshr, X);
1298+
if (OBO) {
1299+
NewBinOp->setHasNoUnsignedWrap(true);
1300+
NewBinOp->setHasNoSignedWrap(OBO->hasNoSignedWrap());
1301+
} else if (auto *Disjoint = dyn_cast<PossiblyDisjointInst>(Op0)) {
1302+
cast<PossiblyDisjointInst>(NewBinOp)->setIsDisjoint(
1303+
Disjoint->isDisjoint());
1304+
}
1305+
return NewBinOp;
1306+
}
1307+
}
1308+
}
1309+
12621310
if (match(Op1, m_APInt(C))) {
12631311
unsigned ShAmtC = C->getZExtValue();
12641312
auto *II = dyn_cast<IntrinsicInst>(Op0);
@@ -1275,7 +1323,6 @@ Instruction *InstCombinerImpl::visitLShr(BinaryOperator &I) {
12751323
return new ZExtInst(Cmp, Ty);
12761324
}
12771325

1278-
Value *X;
12791326
const APInt *C1;
12801327
if (match(Op0, m_Shl(m_Value(X), m_APInt(C1))) && C1->ult(BitWidth)) {
12811328
if (C1->ult(ShAmtC)) {
@@ -1320,7 +1367,6 @@ Instruction *InstCombinerImpl::visitLShr(BinaryOperator &I) {
13201367
// ((X << C) + Y) >>u C --> (X + (Y >>u C)) & (-1 >>u C)
13211368
// TODO: Consolidate with the more general transform that starts from shl
13221369
// (the shifts are in the opposite order).
1323-
Value *Y;
13241370
if (match(Op0,
13251371
m_OneUse(m_c_Add(m_OneUse(m_Shl(m_Value(X), m_Specific(Op1))),
13261372
m_Value(Y))))) {

llvm/test/Transforms/InstCombine/lshr.ll

Lines changed: 28 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -165,8 +165,7 @@ define <2 x i8> @lshr_exact_splat_vec(<2 x i8> %x) {
165165

166166
define <2 x i8> @lshr_exact_splat_vec_nuw(<2 x i8> %x) {
167167
; CHECK-LABEL: @lshr_exact_splat_vec_nuw(
168-
; CHECK-NEXT: [[TMP1:%.*]] = add <2 x i8> [[X:%.*]], <i8 1, i8 1>
169-
; CHECK-NEXT: [[LSHR:%.*]] = and <2 x i8> [[TMP1]], <i8 63, i8 63>
168+
; CHECK-NEXT: [[LSHR:%.*]] = add nuw <2 x i8> [[X:%.*]], <i8 1, i8 1>
170169
; CHECK-NEXT: ret <2 x i8> [[LSHR]]
171170
;
172171
%shl = shl nuw <2 x i8> %x, <i8 2, i8 2>
@@ -374,9 +373,8 @@ define <3 x i14> @mul_splat_fold_vec(<3 x i14> %x) {
374373

375374
define i32 @shl_add_lshr_flag_preservation(i32 %x, i32 %c, i32 %y) {
376375
; CHECK-LABEL: @shl_add_lshr_flag_preservation(
377-
; CHECK-NEXT: [[SHL:%.*]] = shl nuw i32 [[X:%.*]], [[C:%.*]]
378-
; CHECK-NEXT: [[ADD:%.*]] = add nuw nsw i32 [[SHL]], [[Y:%.*]]
379-
; CHECK-NEXT: [[LSHR:%.*]] = lshr exact i32 [[ADD]], [[C]]
376+
; CHECK-NEXT: [[TMP1:%.*]] = lshr exact i32 [[Y:%.*]], [[C:%.*]]
377+
; CHECK-NEXT: [[LSHR:%.*]] = add nuw nsw i32 [[TMP1]], [[X:%.*]]
380378
; CHECK-NEXT: ret i32 [[LSHR]]
381379
;
382380
%shl = shl nuw i32 %x, %c
@@ -387,9 +385,8 @@ define i32 @shl_add_lshr_flag_preservation(i32 %x, i32 %c, i32 %y) {
387385

388386
define i32 @shl_add_lshr(i32 %x, i32 %c, i32 %y) {
389387
; CHECK-LABEL: @shl_add_lshr(
390-
; CHECK-NEXT: [[SHL:%.*]] = shl nuw i32 [[X:%.*]], [[C:%.*]]
391-
; CHECK-NEXT: [[ADD:%.*]] = add nuw i32 [[SHL]], [[Y:%.*]]
392-
; CHECK-NEXT: [[LSHR:%.*]] = lshr i32 [[ADD]], [[C]]
388+
; CHECK-NEXT: [[TMP1:%.*]] = lshr i32 [[Y:%.*]], [[C:%.*]]
389+
; CHECK-NEXT: [[LSHR:%.*]] = add nuw i32 [[TMP1]], [[X:%.*]]
393390
; CHECK-NEXT: ret i32 [[LSHR]]
394391
;
395392
%shl = shl nuw i32 %x, %c
@@ -400,9 +397,8 @@ define i32 @shl_add_lshr(i32 %x, i32 %c, i32 %y) {
400397

401398
define i32 @shl_add_lshr_comm(i32 %x, i32 %c, i32 %y) {
402399
; CHECK-LABEL: @shl_add_lshr_comm(
403-
; CHECK-NEXT: [[SHL:%.*]] = shl nuw i32 [[X:%.*]], [[C:%.*]]
404-
; CHECK-NEXT: [[ADD:%.*]] = add nuw i32 [[SHL]], [[Y:%.*]]
405-
; CHECK-NEXT: [[LSHR:%.*]] = lshr i32 [[ADD]], [[C]]
400+
; CHECK-NEXT: [[TMP1:%.*]] = lshr i32 [[Y:%.*]], [[C:%.*]]
401+
; CHECK-NEXT: [[LSHR:%.*]] = add nuw i32 [[TMP1]], [[X:%.*]]
406402
; CHECK-NEXT: ret i32 [[LSHR]]
407403
;
408404
%shl = shl nuw i32 %x, %c
@@ -458,9 +454,8 @@ define i32 @shl_sub_lshr_no_nuw(i32 %x, i32 %c, i32 %y) {
458454

459455
define i32 @shl_sub_lshr(i32 %x, i32 %c, i32 %y) {
460456
; CHECK-LABEL: @shl_sub_lshr(
461-
; CHECK-NEXT: [[SHL:%.*]] = shl nuw i32 [[X:%.*]], [[C:%.*]]
462-
; CHECK-NEXT: [[SUB:%.*]] = sub nuw nsw i32 [[SHL]], [[Y:%.*]]
463-
; CHECK-NEXT: [[LSHR:%.*]] = lshr exact i32 [[SUB]], [[C]]
457+
; CHECK-NEXT: [[TMP1:%.*]] = lshr exact i32 [[Y:%.*]], [[C:%.*]]
458+
; CHECK-NEXT: [[LSHR:%.*]] = sub nuw nsw i32 [[X:%.*]], [[TMP1]]
464459
; CHECK-NEXT: ret i32 [[LSHR]]
465460
;
466461
%shl = shl nuw i32 %x, %c
@@ -471,9 +466,8 @@ define i32 @shl_sub_lshr(i32 %x, i32 %c, i32 %y) {
471466

472467
define i32 @shl_or_lshr(i32 %x, i32 %c, i32 %y) {
473468
; CHECK-LABEL: @shl_or_lshr(
474-
; CHECK-NEXT: [[SHL:%.*]] = shl nuw i32 [[X:%.*]], [[C:%.*]]
475-
; CHECK-NEXT: [[OR:%.*]] = or i32 [[SHL]], [[Y:%.*]]
476-
; CHECK-NEXT: [[LSHR:%.*]] = lshr i32 [[OR]], [[C]]
469+
; CHECK-NEXT: [[TMP1:%.*]] = lshr i32 [[Y:%.*]], [[C:%.*]]
470+
; CHECK-NEXT: [[LSHR:%.*]] = or i32 [[TMP1]], [[X:%.*]]
477471
; CHECK-NEXT: ret i32 [[LSHR]]
478472
;
479473
%shl = shl nuw i32 %x, %c
@@ -484,9 +478,8 @@ define i32 @shl_or_lshr(i32 %x, i32 %c, i32 %y) {
484478

485479
define i32 @shl_or_disjoint_lshr(i32 %x, i32 %c, i32 %y) {
486480
; CHECK-LABEL: @shl_or_disjoint_lshr(
487-
; CHECK-NEXT: [[SHL:%.*]] = shl nuw i32 [[X:%.*]], [[C:%.*]]
488-
; CHECK-NEXT: [[OR:%.*]] = or disjoint i32 [[SHL]], [[Y:%.*]]
489-
; CHECK-NEXT: [[LSHR:%.*]] = lshr i32 [[OR]], [[C]]
481+
; CHECK-NEXT: [[TMP1:%.*]] = lshr i32 [[Y:%.*]], [[C:%.*]]
482+
; CHECK-NEXT: [[LSHR:%.*]] = or disjoint i32 [[TMP1]], [[X:%.*]]
490483
; CHECK-NEXT: ret i32 [[LSHR]]
491484
;
492485
%shl = shl nuw i32 %x, %c
@@ -497,9 +490,8 @@ define i32 @shl_or_disjoint_lshr(i32 %x, i32 %c, i32 %y) {
497490

498491
define i32 @shl_or_lshr_comm(i32 %x, i32 %c, i32 %y) {
499492
; CHECK-LABEL: @shl_or_lshr_comm(
500-
; CHECK-NEXT: [[SHL:%.*]] = shl nuw i32 [[X:%.*]], [[C:%.*]]
501-
; CHECK-NEXT: [[OR:%.*]] = or i32 [[SHL]], [[Y:%.*]]
502-
; CHECK-NEXT: [[LSHR:%.*]] = lshr i32 [[OR]], [[C]]
493+
; CHECK-NEXT: [[TMP1:%.*]] = lshr i32 [[Y:%.*]], [[C:%.*]]
494+
; CHECK-NEXT: [[LSHR:%.*]] = or i32 [[TMP1]], [[X:%.*]]
503495
; CHECK-NEXT: ret i32 [[LSHR]]
504496
;
505497
%shl = shl nuw i32 %x, %c
@@ -510,9 +502,8 @@ define i32 @shl_or_lshr_comm(i32 %x, i32 %c, i32 %y) {
510502

511503
define i32 @shl_or_disjoint_lshr_comm(i32 %x, i32 %c, i32 %y) {
512504
; CHECK-LABEL: @shl_or_disjoint_lshr_comm(
513-
; CHECK-NEXT: [[SHL:%.*]] = shl nuw i32 [[X:%.*]], [[C:%.*]]
514-
; CHECK-NEXT: [[OR:%.*]] = or disjoint i32 [[SHL]], [[Y:%.*]]
515-
; CHECK-NEXT: [[LSHR:%.*]] = lshr i32 [[OR]], [[C]]
505+
; CHECK-NEXT: [[TMP1:%.*]] = lshr i32 [[Y:%.*]], [[C:%.*]]
506+
; CHECK-NEXT: [[LSHR:%.*]] = or disjoint i32 [[TMP1]], [[X:%.*]]
516507
; CHECK-NEXT: ret i32 [[LSHR]]
517508
;
518509
%shl = shl nuw i32 %x, %c
@@ -523,9 +514,8 @@ define i32 @shl_or_disjoint_lshr_comm(i32 %x, i32 %c, i32 %y) {
523514

524515
define i32 @shl_xor_lshr(i32 %x, i32 %c, i32 %y) {
525516
; CHECK-LABEL: @shl_xor_lshr(
526-
; CHECK-NEXT: [[SHL:%.*]] = shl nuw i32 [[X:%.*]], [[C:%.*]]
527-
; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[SHL]], [[Y:%.*]]
528-
; CHECK-NEXT: [[LSHR:%.*]] = lshr i32 [[XOR]], [[C]]
517+
; CHECK-NEXT: [[TMP1:%.*]] = lshr i32 [[Y:%.*]], [[C:%.*]]
518+
; CHECK-NEXT: [[LSHR:%.*]] = xor i32 [[TMP1]], [[X:%.*]]
529519
; CHECK-NEXT: ret i32 [[LSHR]]
530520
;
531521
%shl = shl nuw i32 %x, %c
@@ -536,9 +526,8 @@ define i32 @shl_xor_lshr(i32 %x, i32 %c, i32 %y) {
536526

537527
define i32 @shl_xor_lshr_comm(i32 %x, i32 %c, i32 %y) {
538528
; CHECK-LABEL: @shl_xor_lshr_comm(
539-
; CHECK-NEXT: [[SHL:%.*]] = shl nuw i32 [[X:%.*]], [[C:%.*]]
540-
; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[SHL]], [[Y:%.*]]
541-
; CHECK-NEXT: [[LSHR:%.*]] = lshr i32 [[XOR]], [[C]]
529+
; CHECK-NEXT: [[TMP1:%.*]] = lshr i32 [[Y:%.*]], [[C:%.*]]
530+
; CHECK-NEXT: [[LSHR:%.*]] = xor i32 [[TMP1]], [[X:%.*]]
542531
; CHECK-NEXT: ret i32 [[LSHR]]
543532
;
544533
%shl = shl nuw i32 %x, %c
@@ -549,9 +538,8 @@ define i32 @shl_xor_lshr_comm(i32 %x, i32 %c, i32 %y) {
549538

550539
define i32 @shl_and_lshr(i32 %x, i32 %c, i32 %y) {
551540
; CHECK-LABEL: @shl_and_lshr(
552-
; CHECK-NEXT: [[SHL:%.*]] = shl nuw i32 [[X:%.*]], [[C:%.*]]
553-
; CHECK-NEXT: [[AND:%.*]] = and i32 [[SHL]], [[Y:%.*]]
554-
; CHECK-NEXT: [[LSHR:%.*]] = lshr i32 [[AND]], [[C]]
541+
; CHECK-NEXT: [[TMP1:%.*]] = lshr i32 [[Y:%.*]], [[C:%.*]]
542+
; CHECK-NEXT: [[LSHR:%.*]] = and i32 [[TMP1]], [[X:%.*]]
555543
; CHECK-NEXT: ret i32 [[LSHR]]
556544
;
557545
%shl = shl nuw i32 %x, %c
@@ -562,9 +550,8 @@ define i32 @shl_and_lshr(i32 %x, i32 %c, i32 %y) {
562550

563551
define i32 @shl_and_lshr_comm(i32 %x, i32 %c, i32 %y) {
564552
; CHECK-LABEL: @shl_and_lshr_comm(
565-
; CHECK-NEXT: [[SHL:%.*]] = shl nuw i32 [[X:%.*]], [[C:%.*]]
566-
; CHECK-NEXT: [[AND:%.*]] = and i32 [[SHL]], [[Y:%.*]]
567-
; CHECK-NEXT: [[LSHR:%.*]] = lshr i32 [[AND]], [[C]]
553+
; CHECK-NEXT: [[TMP1:%.*]] = lshr i32 [[Y:%.*]], [[C:%.*]]
554+
; CHECK-NEXT: [[LSHR:%.*]] = and i32 [[TMP1]], [[X:%.*]]
568555
; CHECK-NEXT: ret i32 [[LSHR]]
569556
;
570557
%shl = shl nuw i32 %x, %c
@@ -575,10 +562,9 @@ define i32 @shl_and_lshr_comm(i32 %x, i32 %c, i32 %y) {
575562

576563
define i32 @shl_lshr_and_exact(i32 %x, i32 %c, i32 %y) {
577564
; CHECK-LABEL: @shl_lshr_and_exact(
578-
; CHECK-NEXT: [[TMP1:%.*]] = shl nuw i32 [[X:%.*]], [[C:%.*]]
579-
; CHECK-NEXT: [[TMP2:%.*]] = and i32 [[TMP1]], [[Y:%.*]]
580-
; CHECK-NEXT: [[TMP3:%.*]] = lshr exact i32 [[TMP2]], [[C]]
581-
; CHECK-NEXT: ret i32 [[TMP3]]
565+
; CHECK-NEXT: [[TMP1:%.*]] = lshr i32 [[Y:%.*]], [[C:%.*]]
566+
; CHECK-NEXT: [[TMP2:%.*]] = and i32 [[TMP1]], [[X:%.*]]
567+
; CHECK-NEXT: ret i32 [[TMP2]]
582568
;
583569
%2 = shl nuw i32 %x, %c
584570
%3 = and i32 %2, %y

0 commit comments

Comments
 (0)