Skip to content

Commit 33d077d

Browse files
committed
[Instcombine] Fold away shift in or reduction chain.
If we have `icmp eq or(a, shl(b)), 0` then the shift can be removed so long as it is nuw or nsw. It is still comparing the same bits against 0. https://alive2.llvm.org/ce/z/nhrBVX. This is also true of ne, and true of longer or chains. Thinking out loud, this is kind of like a "are any bits demanded" combine.
1 parent 2a9b2f8 commit 33d077d

File tree

2 files changed

+36
-18
lines changed

2 files changed

+36
-18
lines changed

llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5046,6 +5046,29 @@ static Instruction *foldICmpOrXX(ICmpInst &I, const SimplifyQuery &Q,
50465046
return nullptr;
50475047
}
50485048

5049+
static Value *foldShiftAwayFromOrChain(Instruction &I,
5050+
InstCombiner::BuilderTy &Builder) {
5051+
if (I.getOpcode() != Instruction::Or)
5052+
return nullptr;
5053+
Value *A, *B;
5054+
if (match(&I, m_c_Or(m_CombineOr(m_NSWShl(m_Value(A), m_Value()),
5055+
m_NUWShl(m_Value(A), m_Value())),
5056+
m_Value(B))))
5057+
return Builder.CreateOr(A, B);
5058+
5059+
Value *Op0 = I.getOperand(0);
5060+
if (isa<Instruction>(Op0))
5061+
if (auto *X = foldShiftAwayFromOrChain(*cast<Instruction>(Op0), Builder))
5062+
Op0 = X;
5063+
Value *Op1 = I.getOperand(1);
5064+
if (isa<Instruction>(Op1))
5065+
if (auto *X = foldShiftAwayFromOrChain(*cast<Instruction>(Op1), Builder))
5066+
Op1 = X;
5067+
if (Op0 != I.getOperand(0) || Op1 != I.getOperand(1))
5068+
return Builder.CreateOr(Op0, Op1);
5069+
return nullptr;
5070+
}
5071+
50495072
static Instruction *foldICmpXorXX(ICmpInst &I, const SimplifyQuery &Q,
50505073
InstCombinerImpl &IC) {
50515074
Value *Op0 = I.getOperand(0), *Op1 = I.getOperand(1), *A;
@@ -7869,6 +7892,11 @@ Instruction *InstCombinerImpl::visitICmpInst(ICmpInst &I) {
78697892
}
78707893
}
78717894

7895+
// icmp eq/ne or(shl(a), b), 0 -> icmp eq/ne or(a, b)
7896+
if (I.isEquality() && match(Op1, m_Zero()) && isa<Instruction>(Op0))
7897+
if (auto *Res = foldShiftAwayFromOrChain(*cast<Instruction>(Op0), Builder))
7898+
return new ICmpInst(I.getPredicate(), Res, Op1);
7899+
78727900
return Changed ? &I : nullptr;
78737901
}
78747902

llvm/test/Transforms/InstCombine/icmp-of-or-x.ll

Lines changed: 8 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -412,8 +412,7 @@ define i1 @PR38139(i8 %arg) {
412412

413413
define i1 @remove_shift_nuw_ab(i8 %a, i8 %b, i8 %s) {
414414
; CHECK-LABEL: @remove_shift_nuw_ab(
415-
; CHECK-NEXT: [[T:%.*]] = shl nuw i8 [[A:%.*]], [[S:%.*]]
416-
; CHECK-NEXT: [[OR:%.*]] = or i8 [[T]], [[B:%.*]]
415+
; CHECK-NEXT: [[OR:%.*]] = or i8 [[T:%.*]], [[B:%.*]]
417416
; CHECK-NEXT: [[IC:%.*]] = icmp eq i8 [[OR]], 0
418417
; CHECK-NEXT: ret i1 [[IC]]
419418
;
@@ -425,8 +424,7 @@ define i1 @remove_shift_nuw_ab(i8 %a, i8 %b, i8 %s) {
425424

426425
define i1 @remove_shift_nuw_ba(i8 %a, i8 %b, i8 %s) {
427426
; CHECK-LABEL: @remove_shift_nuw_ba(
428-
; CHECK-NEXT: [[T:%.*]] = shl nuw i8 [[A:%.*]], [[S:%.*]]
429-
; CHECK-NEXT: [[OR:%.*]] = or i8 [[B:%.*]], [[T]]
427+
; CHECK-NEXT: [[OR:%.*]] = or i8 [[B:%.*]], [[T:%.*]]
430428
; CHECK-NEXT: [[IC:%.*]] = icmp eq i8 [[OR]], 0
431429
; CHECK-NEXT: ret i1 [[IC]]
432430
;
@@ -438,8 +436,7 @@ define i1 @remove_shift_nuw_ba(i8 %a, i8 %b, i8 %s) {
438436

439437
define i1 @remove_shift_nsw(i8 %a, i8 %b, i8 %s) {
440438
; CHECK-LABEL: @remove_shift_nsw(
441-
; CHECK-NEXT: [[T:%.*]] = shl nsw i8 [[A:%.*]], [[S:%.*]]
442-
; CHECK-NEXT: [[OR:%.*]] = or i8 [[T]], [[B:%.*]]
439+
; CHECK-NEXT: [[OR:%.*]] = or i8 [[T:%.*]], [[B:%.*]]
443440
; CHECK-NEXT: [[IC:%.*]] = icmp eq i8 [[OR]], 0
444441
; CHECK-NEXT: ret i1 [[IC]]
445442
;
@@ -451,8 +448,7 @@ define i1 @remove_shift_nsw(i8 %a, i8 %b, i8 %s) {
451448

452449
define i1 @remove_shift_nuw_ne(i8 %a, i8 %b, i8 %s) {
453450
; CHECK-LABEL: @remove_shift_nuw_ne(
454-
; CHECK-NEXT: [[T:%.*]] = shl nuw i8 [[A:%.*]], [[S:%.*]]
455-
; CHECK-NEXT: [[OR:%.*]] = or i8 [[T]], [[B:%.*]]
451+
; CHECK-NEXT: [[OR:%.*]] = or i8 [[T:%.*]], [[B:%.*]]
456452
; CHECK-NEXT: [[IC:%.*]] = icmp eq i8 [[OR]], 0
457453
; CHECK-NEXT: ret i1 [[IC]]
458454
;
@@ -464,8 +460,7 @@ define i1 @remove_shift_nuw_ne(i8 %a, i8 %b, i8 %s) {
464460

465461
define i1 @remove_shift_nsw_ne(i8 %a, i8 %b, i8 %s) {
466462
; CHECK-LABEL: @remove_shift_nsw_ne(
467-
; CHECK-NEXT: [[T:%.*]] = shl nsw i8 [[A:%.*]], [[S:%.*]]
468-
; CHECK-NEXT: [[OR:%.*]] = or i8 [[T]], [[B:%.*]]
463+
; CHECK-NEXT: [[OR:%.*]] = or i8 [[T:%.*]], [[B:%.*]]
469464
; CHECK-NEXT: [[IC:%.*]] = icmp eq i8 [[OR]], 0
470465
; CHECK-NEXT: ret i1 [[IC]]
471466
;
@@ -490,9 +485,8 @@ define i1 @remove_shift_wraps(i8 %a, i8 %b, i8 %s) {
490485

491486
define i1 @remove_shift_chain_d(i8 %a, i8 %b, i8 %c, i8 %d, i8 %s) {
492487
; CHECK-LABEL: @remove_shift_chain_d(
493-
; CHECK-NEXT: [[DT:%.*]] = shl nuw i8 [[D:%.*]], [[S:%.*]]
494488
; CHECK-NEXT: [[OR1:%.*]] = or i8 [[A:%.*]], [[B:%.*]]
495-
; CHECK-NEXT: [[OR2:%.*]] = or i8 [[C:%.*]], [[DT]]
489+
; CHECK-NEXT: [[OR2:%.*]] = or i8 [[C:%.*]], [[DT:%.*]]
496490
; CHECK-NEXT: [[OR:%.*]] = or i8 [[OR1]], [[OR2]]
497491
; CHECK-NEXT: [[IC:%.*]] = icmp eq i8 [[OR]], 0
498492
; CHECK-NEXT: ret i1 [[IC]]
@@ -507,12 +501,8 @@ define i1 @remove_shift_chain_d(i8 %a, i8 %b, i8 %c, i8 %d, i8 %s) {
507501

508502
define i1 @remove_shift_chain_abcd(i8 %a, i8 %b, i8 %c, i8 %d, i8 %s) {
509503
; CHECK-LABEL: @remove_shift_chain_abcd(
510-
; CHECK-NEXT: [[AT:%.*]] = shl nuw i8 [[A:%.*]], [[S:%.*]]
511-
; CHECK-NEXT: [[BT:%.*]] = shl nuw i8 [[B:%.*]], 2
512-
; CHECK-NEXT: [[CT:%.*]] = shl nuw i8 [[C:%.*]], 1
513-
; CHECK-NEXT: [[DT:%.*]] = shl nuw i8 [[D:%.*]], [[S]]
514-
; CHECK-NEXT: [[OR1:%.*]] = or i8 [[AT]], [[BT]]
515-
; CHECK-NEXT: [[OR2:%.*]] = or i8 [[CT]], [[DT]]
504+
; CHECK-NEXT: [[OR1:%.*]] = or i8 [[AT:%.*]], [[BT:%.*]]
505+
; CHECK-NEXT: [[OR2:%.*]] = or i8 [[CT:%.*]], [[DT:%.*]]
516506
; CHECK-NEXT: [[OR:%.*]] = or i8 [[OR1]], [[OR2]]
517507
; CHECK-NEXT: [[IC:%.*]] = icmp eq i8 [[OR]], 0
518508
; CHECK-NEXT: ret i1 [[IC]]

0 commit comments

Comments
 (0)