Skip to content

Commit 0223aa0

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 238a965 commit 0223aa0

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+
Value *Y;
1263+
// ((X << nuw Z) sub nuw Y) >>u Z --> X sub nuw (Y >>u Z)
1264+
if (match(Op0, m_OneUse(m_NUWSub(m_NUWShl(m_Value(X), m_Specific(Op1)),
1265+
m_Value(Y))))) {
1266+
Value *NewLshr = Builder.CreateLShr(Y, Op1, "", I.isExact());
1267+
auto *NewSub = BinaryOperator::CreateNUWSub(NewLshr, X);
1268+
NewSub->setHasNoSignedWrap(
1269+
cast<OverflowingBinaryOperator>(Op0)->hasNoSignedWrap());
1270+
return NewSub;
1271+
}
1272+
1273+
auto isSuitableBinOpcode = [](Instruction::BinaryOps BinOpcode) {
1274+
switch (BinOpcode) {
1275+
default:
1276+
return false;
1277+
case Instruction::Add:
1278+
case Instruction::Or:
1279+
case Instruction::Xor:
1280+
// And does not work here, and sub is handled separately.
1281+
return true;
1282+
}
1283+
};
1284+
1285+
// If both the binop and the shift are nuw, then:
1286+
// ((X << nuw Z) binop nuw Y) >>u Z --> X binop nuw (Y >>u Z)
1287+
if (match(Op0, m_OneUse(m_c_BinOp(m_NUWShl(m_Value(X), m_Specific(Op1)),
1288+
m_Value(Y))))) {
1289+
BinaryOperator *Op0OB = cast<BinaryOperator>(Op0);
1290+
if (isSuitableBinOpcode(Op0OB->getOpcode())) {
1291+
if (auto *OBO = dyn_cast<OverflowingBinaryOperator>(Op0);
1292+
!OBO || OBO->hasNoUnsignedWrap()) {
1293+
Value *NewLshr = Builder.CreateLShr(Y, Op1, "", I.isExact());
1294+
auto *NewBinOp = BinaryOperator::Create(Op0OB->getOpcode(), NewLshr, X);
1295+
if (OBO) {
1296+
NewBinOp->setHasNoUnsignedWrap(true);
1297+
NewBinOp->setHasNoSignedWrap(OBO->hasNoSignedWrap());
1298+
} else if (auto *Disjoint = dyn_cast<PossiblyDisjointInst>(Op0);
1299+
Disjoint && Disjoint->isDisjoint()) {
1300+
cast<PossiblyDisjointInst>(NewBinOp)->setIsDisjoint(true);
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
@@ -413,9 +409,8 @@ define i32 @shl_add_lshr_comm(i32 %x, i32 %c, i32 %y) {
413409

414410
define i32 @shl_sub_lshr(i32 %x, i32 %c, i32 %y) {
415411
; CHECK-LABEL: @shl_sub_lshr(
416-
; CHECK-NEXT: [[SHL:%.*]] = shl nuw i32 [[X:%.*]], [[C:%.*]]
417-
; CHECK-NEXT: [[SUB:%.*]] = sub nuw i32 [[SHL]], [[Y:%.*]]
418-
; CHECK-NEXT: [[LSHR:%.*]] = lshr i32 [[SUB]], [[C]]
412+
; CHECK-NEXT: [[TMP1:%.*]] = lshr i32 [[Y:%.*]], [[C:%.*]]
413+
; CHECK-NEXT: [[LSHR:%.*]] = sub nuw i32 [[TMP1]], [[X:%.*]]
419414
; CHECK-NEXT: ret i32 [[LSHR]]
420415
;
421416
%shl = shl nuw i32 %x, %c
@@ -426,9 +421,8 @@ define i32 @shl_sub_lshr(i32 %x, i32 %c, i32 %y) {
426421

427422
define i32 @shl_or_lshr(i32 %x, i32 %c, i32 %y) {
428423
; CHECK-LABEL: @shl_or_lshr(
429-
; CHECK-NEXT: [[SHL:%.*]] = shl nuw i32 [[X:%.*]], [[C:%.*]]
430-
; CHECK-NEXT: [[OR:%.*]] = or i32 [[SHL]], [[Y:%.*]]
431-
; CHECK-NEXT: [[LSHR:%.*]] = lshr i32 [[OR]], [[C]]
424+
; CHECK-NEXT: [[TMP1:%.*]] = lshr i32 [[Y:%.*]], [[C:%.*]]
425+
; CHECK-NEXT: [[LSHR:%.*]] = or i32 [[TMP1]], [[X:%.*]]
432426
; CHECK-NEXT: ret i32 [[LSHR]]
433427
;
434428
%shl = shl nuw i32 %x, %c
@@ -439,9 +433,8 @@ define i32 @shl_or_lshr(i32 %x, i32 %c, i32 %y) {
439433

440434
define i32 @shl_or_disjoint_lshr(i32 %x, i32 %c, i32 %y) {
441435
; CHECK-LABEL: @shl_or_disjoint_lshr(
442-
; CHECK-NEXT: [[SHL:%.*]] = shl nuw i32 [[X:%.*]], [[C:%.*]]
443-
; CHECK-NEXT: [[OR:%.*]] = or disjoint i32 [[SHL]], [[Y:%.*]]
444-
; CHECK-NEXT: [[LSHR:%.*]] = lshr i32 [[OR]], [[C]]
436+
; CHECK-NEXT: [[TMP1:%.*]] = lshr i32 [[Y:%.*]], [[C:%.*]]
437+
; CHECK-NEXT: [[LSHR:%.*]] = or disjoint i32 [[TMP1]], [[X:%.*]]
445438
; CHECK-NEXT: ret i32 [[LSHR]]
446439
;
447440
%shl = shl nuw i32 %x, %c
@@ -452,9 +445,8 @@ define i32 @shl_or_disjoint_lshr(i32 %x, i32 %c, i32 %y) {
452445

453446
define i32 @shl_or_lshr_comm(i32 %x, i32 %c, i32 %y) {
454447
; CHECK-LABEL: @shl_or_lshr_comm(
455-
; CHECK-NEXT: [[SHL:%.*]] = shl nuw i32 [[X:%.*]], [[C:%.*]]
456-
; CHECK-NEXT: [[OR:%.*]] = or i32 [[SHL]], [[Y:%.*]]
457-
; CHECK-NEXT: [[LSHR:%.*]] = lshr i32 [[OR]], [[C]]
448+
; CHECK-NEXT: [[TMP1:%.*]] = lshr i32 [[Y:%.*]], [[C:%.*]]
449+
; CHECK-NEXT: [[LSHR:%.*]] = or i32 [[TMP1]], [[X:%.*]]
458450
; CHECK-NEXT: ret i32 [[LSHR]]
459451
;
460452
%shl = shl nuw i32 %x, %c
@@ -465,9 +457,8 @@ define i32 @shl_or_lshr_comm(i32 %x, i32 %c, i32 %y) {
465457

466458
define i32 @shl_or_disjoint_lshr_comm(i32 %x, i32 %c, i32 %y) {
467459
; CHECK-LABEL: @shl_or_disjoint_lshr_comm(
468-
; CHECK-NEXT: [[SHL:%.*]] = shl nuw i32 [[X:%.*]], [[C:%.*]]
469-
; CHECK-NEXT: [[OR:%.*]] = or disjoint i32 [[SHL]], [[Y:%.*]]
470-
; CHECK-NEXT: [[LSHR:%.*]] = lshr i32 [[OR]], [[C]]
460+
; CHECK-NEXT: [[TMP1:%.*]] = lshr i32 [[Y:%.*]], [[C:%.*]]
461+
; CHECK-NEXT: [[LSHR:%.*]] = or disjoint i32 [[TMP1]], [[X:%.*]]
471462
; CHECK-NEXT: ret i32 [[LSHR]]
472463
;
473464
%shl = shl nuw i32 %x, %c
@@ -478,9 +469,8 @@ define i32 @shl_or_disjoint_lshr_comm(i32 %x, i32 %c, i32 %y) {
478469

479470
define i32 @shl_xor_lshr(i32 %x, i32 %c, i32 %y) {
480471
; CHECK-LABEL: @shl_xor_lshr(
481-
; CHECK-NEXT: [[SHL:%.*]] = shl nuw i32 [[X:%.*]], [[C:%.*]]
482-
; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[SHL]], [[Y:%.*]]
483-
; CHECK-NEXT: [[LSHR:%.*]] = lshr i32 [[XOR]], [[C]]
472+
; CHECK-NEXT: [[TMP1:%.*]] = lshr i32 [[Y:%.*]], [[C:%.*]]
473+
; CHECK-NEXT: [[LSHR:%.*]] = xor i32 [[TMP1]], [[X:%.*]]
484474
; CHECK-NEXT: ret i32 [[LSHR]]
485475
;
486476
%shl = shl nuw i32 %x, %c
@@ -492,9 +482,8 @@ define i32 @shl_xor_lshr(i32 %x, i32 %c, i32 %y) {
492482

493483
define i32 @shl_xor_lshr_comm(i32 %x, i32 %c, i32 %y) {
494484
; CHECK-LABEL: @shl_xor_lshr_comm(
495-
; CHECK-NEXT: [[SHL:%.*]] = shl nuw i32 [[X:%.*]], [[C:%.*]]
496-
; CHECK-NEXT: [[XOR:%.*]] = xor i32 [[SHL]], [[Y:%.*]]
497-
; CHECK-NEXT: [[LSHR:%.*]] = lshr i32 [[XOR]], [[C]]
485+
; CHECK-NEXT: [[TMP1:%.*]] = lshr i32 [[Y:%.*]], [[C:%.*]]
486+
; CHECK-NEXT: [[LSHR:%.*]] = xor i32 [[TMP1]], [[X:%.*]]
498487
; CHECK-NEXT: ret i32 [[LSHR]]
499488
;
500489
%shl = shl nuw i32 %x, %c

0 commit comments

Comments
 (0)