Skip to content

Commit e7f1124

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
1 parent 245501d commit e7f1124

File tree

2 files changed

+66
-34
lines changed

2 files changed

+66
-34
lines changed

llvm/lib/Transforms/InstCombine/InstCombineShifts.cpp

Lines changed: 45 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1259,6 +1259,51 @@ 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::Or:
1280+
case Instruction::Xor:
1281+
// And does not work here, and sub is handled separately.
1282+
return true;
1283+
}
1284+
};
1285+
1286+
// If both the binop and the shift are nuw, then:
1287+
// ((X << nuw Z) binop nuw Y) >>u Z --> X binop nuw (Y >>u Z)
1288+
if (match(Op0, m_OneUse(m_c_BinOp(m_NUWShl(m_Value(X), m_Specific(Op1)),
1289+
m_Value(Y))))) {
1290+
BinaryOperator *Op0OB = cast<BinaryOperator>(Op0);
1291+
if (isSuitableBinOpcode(Op0OB->getOpcode())) {
1292+
if (auto *OBO = dyn_cast<OverflowingBinaryOperator>(Op0);
1293+
!OBO || OBO->hasNoUnsignedWrap()) {
1294+
Value *NewLshr = Builder.CreateLShr(Y, Op1, "", I.isExact());
1295+
auto *NewBinOp = BinaryOperator::Create(Op0OB->getOpcode(), NewLshr, X);
1296+
if (OBO) {
1297+
NewBinOp->setHasNoUnsignedWrap(true);
1298+
NewBinOp->setHasNoSignedWrap(OBO->hasNoSignedWrap());
1299+
} else if (auto *Disjoint = dyn_cast<PossiblyDisjointInst>(Op0)) {
1300+
cast<PossiblyDisjointInst>(NewBinOp)->setIsDisjoint(Disjoint->isDisjoint());
1301+
}
1302+
return NewBinOp;
1303+
}
1304+
}
1305+
}
1306+
12621307
if (match(Op1, m_APInt(C))) {
12631308
unsigned ShAmtC = C->getZExtValue();
12641309
auto *II = dyn_cast<IntrinsicInst>(Op0);
@@ -1275,7 +1320,6 @@ Instruction *InstCombinerImpl::visitLShr(BinaryOperator &I) {
12751320
return new ZExtInst(Cmp, Ty);
12761321
}
12771322

1278-
Value *X;
12791323
const APInt *C1;
12801324
if (match(Op0, m_Shl(m_Value(X), m_APInt(C1))) && C1->ult(BitWidth)) {
12811325
if (C1->ult(ShAmtC)) {
@@ -1320,7 +1364,6 @@ Instruction *InstCombinerImpl::visitLShr(BinaryOperator &I) {
13201364
// ((X << C) + Y) >>u C --> (X + (Y >>u C)) & (-1 >>u C)
13211365
// TODO: Consolidate with the more general transform that starts from shl
13221366
// (the shifts are in the opposite order).
1323-
Value *Y;
13241367
if (match(Op0,
13251368
m_OneUse(m_c_Add(m_OneUse(m_Shl(m_Value(X), m_Specific(Op1))),
13261369
m_Value(Y))))) {

llvm/test/Transforms/InstCombine/lshr.ll

Lines changed: 21 additions & 32 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
@@ -537,9 +527,8 @@ define i32 @shl_xor_lshr(i32 %x, i32 %c, i32 %y) {
537527

538528
define i32 @shl_xor_lshr_comm(i32 %x, i32 %c, i32 %y) {
539529
; CHECK-LABEL: @shl_xor_lshr_comm(
540-
; CHECK-NEXT: [[SHL:%.*]] = shl nuw i32 [[X:%.*]], [[C:%.*]]
541-
; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[SHL]], [[Y:%.*]]
542-
; CHECK-NEXT: [[LSHR:%.*]] = lshr i32 [[XOR]], [[C]]
530+
; CHECK-NEXT: [[TMP1:%.*]] = lshr i32 [[Y:%.*]], [[C:%.*]]
531+
; CHECK-NEXT: [[LSHR:%.*]] = xor i32 [[TMP1]], [[X:%.*]]
543532
; CHECK-NEXT: ret i32 [[LSHR]]
544533
;
545534
%shl = shl nuw i32 %x, %c

0 commit comments

Comments
 (0)