[llvm] [Instcombine] Fold away shift in or reduction chain. (PR #137875)
David Green via llvm-commits
llvm-commits at lists.llvm.org
Wed Apr 30 12:11:38 PDT 2025
https://github.com/davemgreen updated https://github.com/llvm/llvm-project/pull/137875
>From 097fc866dc714b1638a490faf55c1e9bdb84a907 Mon Sep 17 00:00:00 2001
From: David Green <david.green at arm.com>
Date: Tue, 29 Apr 2025 17:07:01 +0100
Subject: [PATCH 1/3] [InstCombine] Add test for shifts from or chains
---
.../Transforms/InstCombine/icmp-of-or-x.ll | 119 ++++++++++++++++++
1 file changed, 119 insertions(+)
diff --git a/llvm/test/Transforms/InstCombine/icmp-of-or-x.ll b/llvm/test/Transforms/InstCombine/icmp-of-or-x.ll
index 993325f6ff0b0..d06a2f6526ac0 100644
--- a/llvm/test/Transforms/InstCombine/icmp-of-or-x.ll
+++ b/llvm/test/Transforms/InstCombine/icmp-of-or-x.ll
@@ -409,3 +409,122 @@ define i1 @PR38139(i8 %arg) {
%r = icmp ne i8 %masked, %arg
ret i1 %r
}
+
+define i1 @remove_shift_nuw_ab(i8 %a, i8 %b, i8 %s) {
+; CHECK-LABEL: @remove_shift_nuw_ab(
+; CHECK-NEXT: [[T:%.*]] = shl nuw i8 [[A:%.*]], [[S:%.*]]
+; CHECK-NEXT: [[OR:%.*]] = or i8 [[T]], [[B:%.*]]
+; CHECK-NEXT: [[IC:%.*]] = icmp eq i8 [[OR]], 0
+; CHECK-NEXT: ret i1 [[IC]]
+;
+ %t = shl nuw i8 %a, %s
+ %or = or i8 %t, %b
+ %ic = icmp eq i8 %or, 0
+ ret i1 %ic
+}
+
+define i1 @remove_shift_nuw_ba(i8 %a, i8 %b, i8 %s) {
+; CHECK-LABEL: @remove_shift_nuw_ba(
+; CHECK-NEXT: [[T:%.*]] = shl nuw i8 [[A:%.*]], [[S:%.*]]
+; CHECK-NEXT: [[OR:%.*]] = or i8 [[B:%.*]], [[T]]
+; CHECK-NEXT: [[IC:%.*]] = icmp eq i8 [[OR]], 0
+; CHECK-NEXT: ret i1 [[IC]]
+;
+ %t = shl nuw i8 %a, %s
+ %or = or i8 %b, %t
+ %ic = icmp eq i8 %or, 0
+ ret i1 %ic
+}
+
+define i1 @remove_shift_nsw(i8 %a, i8 %b, i8 %s) {
+; CHECK-LABEL: @remove_shift_nsw(
+; CHECK-NEXT: [[T:%.*]] = shl nsw i8 [[A:%.*]], [[S:%.*]]
+; CHECK-NEXT: [[OR:%.*]] = or i8 [[T]], [[B:%.*]]
+; CHECK-NEXT: [[IC:%.*]] = icmp eq i8 [[OR]], 0
+; CHECK-NEXT: ret i1 [[IC]]
+;
+ %t = shl nsw i8 %a, %s
+ %or = or i8 %t, %b
+ %ic = icmp eq i8 %or, 0
+ ret i1 %ic
+}
+
+define i1 @remove_shift_nuw_ne(i8 %a, i8 %b, i8 %s) {
+; CHECK-LABEL: @remove_shift_nuw_ne(
+; CHECK-NEXT: [[T:%.*]] = shl nuw i8 [[A:%.*]], [[S:%.*]]
+; CHECK-NEXT: [[OR:%.*]] = or i8 [[T]], [[B:%.*]]
+; CHECK-NEXT: [[IC:%.*]] = icmp eq i8 [[OR]], 0
+; CHECK-NEXT: ret i1 [[IC]]
+;
+ %t = shl nuw i8 %a, %s
+ %or = or i8 %t, %b
+ %ic = icmp eq i8 %or, 0
+ ret i1 %ic
+}
+
+define i1 @remove_shift_nsw_ne(i8 %a, i8 %b, i8 %s) {
+; CHECK-LABEL: @remove_shift_nsw_ne(
+; CHECK-NEXT: [[T:%.*]] = shl nsw i8 [[A:%.*]], [[S:%.*]]
+; CHECK-NEXT: [[OR:%.*]] = or i8 [[T]], [[B:%.*]]
+; CHECK-NEXT: [[IC:%.*]] = icmp eq i8 [[OR]], 0
+; CHECK-NEXT: ret i1 [[IC]]
+;
+ %t = shl nsw i8 %a, %s
+ %or = or i8 %t, %b
+ %ic = icmp eq i8 %or, 0
+ ret i1 %ic
+}
+
+define i1 @remove_shift_wraps(i8 %a, i8 %b, i8 %s) {
+; CHECK-LABEL: @remove_shift_wraps(
+; CHECK-NEXT: [[T:%.*]] = shl i8 [[A:%.*]], [[S:%.*]]
+; CHECK-NEXT: [[OR:%.*]] = or i8 [[T]], [[B:%.*]]
+; CHECK-NEXT: [[IC:%.*]] = icmp eq i8 [[OR]], 0
+; CHECK-NEXT: ret i1 [[IC]]
+;
+ %t = shl i8 %a, %s
+ %or = or i8 %t, %b
+ %ic = icmp eq i8 %or, 0
+ ret i1 %ic
+}
+
+define i1 @remove_shift_chain_d(i8 %a, i8 %b, i8 %c, i8 %d, i8 %s) {
+; CHECK-LABEL: @remove_shift_chain_d(
+; CHECK-NEXT: [[DT:%.*]] = shl nuw i8 [[D:%.*]], [[S:%.*]]
+; CHECK-NEXT: [[OR1:%.*]] = or i8 [[A:%.*]], [[B:%.*]]
+; CHECK-NEXT: [[OR2:%.*]] = or i8 [[C:%.*]], [[DT]]
+; CHECK-NEXT: [[OR:%.*]] = or i8 [[OR1]], [[OR2]]
+; CHECK-NEXT: [[IC:%.*]] = icmp eq i8 [[OR]], 0
+; CHECK-NEXT: ret i1 [[IC]]
+;
+ %dt = shl nuw i8 %d, %s
+ %or1 = or i8 %a, %b
+ %or2 = or i8 %c, %dt
+ %or = or i8 %or1, %or2
+ %ic = icmp eq i8 %or, 0
+ ret i1 %ic
+}
+
+define i1 @remove_shift_chain_abcd(i8 %a, i8 %b, i8 %c, i8 %d, i8 %s) {
+; CHECK-LABEL: @remove_shift_chain_abcd(
+; CHECK-NEXT: [[AT:%.*]] = shl nuw i8 [[A:%.*]], [[S:%.*]]
+; CHECK-NEXT: [[BT:%.*]] = shl nuw i8 [[B:%.*]], 2
+; CHECK-NEXT: [[CT:%.*]] = shl nuw i8 [[C:%.*]], 1
+; CHECK-NEXT: [[DT:%.*]] = shl nuw i8 [[D:%.*]], [[S]]
+; CHECK-NEXT: [[OR1:%.*]] = or i8 [[AT]], [[BT]]
+; CHECK-NEXT: [[OR2:%.*]] = or i8 [[CT]], [[DT]]
+; CHECK-NEXT: [[OR:%.*]] = or i8 [[OR1]], [[OR2]]
+; CHECK-NEXT: [[IC:%.*]] = icmp eq i8 [[OR]], 0
+; CHECK-NEXT: ret i1 [[IC]]
+;
+ %at = shl nuw i8 %a, %s
+ %bt = shl nuw i8 %b, 2
+ %ct = shl nuw i8 %c, 1
+ %dt = shl nuw i8 %d, %s
+ %or1 = or i8 %at, %bt
+ %or2 = or i8 %ct, %dt
+ %or = or i8 %or1, %or2
+ %ic = icmp eq i8 %or, 0
+ ret i1 %ic
+}
+
>From 271a489e2e588bc71d847f8ce1a41ff1b9d0ab79 Mon Sep 17 00:00:00 2001
From: David Green <david.green at arm.com>
Date: Tue, 29 Apr 2025 19:08:01 +0100
Subject: [PATCH 2/3] [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.
---
.../InstCombine/InstCombineCompares.cpp | 28 +++++++++++++++++++
.../Transforms/InstCombine/icmp-of-or-x.ll | 26 ++++++-----------
2 files changed, 36 insertions(+), 18 deletions(-)
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
index 27d26900de6be..338dda9238704 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
@@ -5046,6 +5046,29 @@ static Instruction *foldICmpOrXX(ICmpInst &I, const SimplifyQuery &Q,
return nullptr;
}
+static Value *foldShiftAwayFromOrChain(Instruction &I,
+ InstCombiner::BuilderTy &Builder) {
+ if (I.getOpcode() != Instruction::Or)
+ return nullptr;
+ Value *A, *B;
+ if (match(&I, m_c_Or(m_CombineOr(m_NSWShl(m_Value(A), m_Value()),
+ m_NUWShl(m_Value(A), m_Value())),
+ m_Value(B))))
+ return Builder.CreateOr(A, B);
+
+ Value *Op0 = I.getOperand(0);
+ if (isa<Instruction>(Op0))
+ if (auto *X = foldShiftAwayFromOrChain(*cast<Instruction>(Op0), Builder))
+ Op0 = X;
+ Value *Op1 = I.getOperand(1);
+ if (isa<Instruction>(Op1))
+ if (auto *X = foldShiftAwayFromOrChain(*cast<Instruction>(Op1), Builder))
+ Op1 = X;
+ if (Op0 != I.getOperand(0) || Op1 != I.getOperand(1))
+ return Builder.CreateOr(Op0, Op1);
+ return nullptr;
+}
+
static Instruction *foldICmpXorXX(ICmpInst &I, const SimplifyQuery &Q,
InstCombinerImpl &IC) {
Value *Op0 = I.getOperand(0), *Op1 = I.getOperand(1), *A;
@@ -7868,6 +7891,11 @@ Instruction *InstCombinerImpl::visitICmpInst(ICmpInst &I) {
}
}
+ // icmp eq/ne or(shl(a), b), 0 -> icmp eq/ne or(a, b)
+ if (I.isEquality() && match(Op1, m_Zero()) && isa<Instruction>(Op0))
+ if (auto *Res = foldShiftAwayFromOrChain(*cast<Instruction>(Op0), Builder))
+ return new ICmpInst(I.getPredicate(), Res, Op1);
+
return Changed ? &I : nullptr;
}
diff --git a/llvm/test/Transforms/InstCombine/icmp-of-or-x.ll b/llvm/test/Transforms/InstCombine/icmp-of-or-x.ll
index d06a2f6526ac0..baaa754e52894 100644
--- a/llvm/test/Transforms/InstCombine/icmp-of-or-x.ll
+++ b/llvm/test/Transforms/InstCombine/icmp-of-or-x.ll
@@ -412,8 +412,7 @@ define i1 @PR38139(i8 %arg) {
define i1 @remove_shift_nuw_ab(i8 %a, i8 %b, i8 %s) {
; CHECK-LABEL: @remove_shift_nuw_ab(
-; CHECK-NEXT: [[T:%.*]] = shl nuw i8 [[A:%.*]], [[S:%.*]]
-; CHECK-NEXT: [[OR:%.*]] = or i8 [[T]], [[B:%.*]]
+; CHECK-NEXT: [[OR:%.*]] = or i8 [[T:%.*]], [[B:%.*]]
; CHECK-NEXT: [[IC:%.*]] = icmp eq i8 [[OR]], 0
; CHECK-NEXT: ret i1 [[IC]]
;
@@ -425,8 +424,7 @@ define i1 @remove_shift_nuw_ab(i8 %a, i8 %b, i8 %s) {
define i1 @remove_shift_nuw_ba(i8 %a, i8 %b, i8 %s) {
; CHECK-LABEL: @remove_shift_nuw_ba(
-; CHECK-NEXT: [[T:%.*]] = shl nuw i8 [[A:%.*]], [[S:%.*]]
-; CHECK-NEXT: [[OR:%.*]] = or i8 [[B:%.*]], [[T]]
+; CHECK-NEXT: [[OR:%.*]] = or i8 [[B:%.*]], [[T:%.*]]
; CHECK-NEXT: [[IC:%.*]] = icmp eq i8 [[OR]], 0
; CHECK-NEXT: ret i1 [[IC]]
;
@@ -438,8 +436,7 @@ define i1 @remove_shift_nuw_ba(i8 %a, i8 %b, i8 %s) {
define i1 @remove_shift_nsw(i8 %a, i8 %b, i8 %s) {
; CHECK-LABEL: @remove_shift_nsw(
-; CHECK-NEXT: [[T:%.*]] = shl nsw i8 [[A:%.*]], [[S:%.*]]
-; CHECK-NEXT: [[OR:%.*]] = or i8 [[T]], [[B:%.*]]
+; CHECK-NEXT: [[OR:%.*]] = or i8 [[T:%.*]], [[B:%.*]]
; CHECK-NEXT: [[IC:%.*]] = icmp eq i8 [[OR]], 0
; CHECK-NEXT: ret i1 [[IC]]
;
@@ -451,8 +448,7 @@ define i1 @remove_shift_nsw(i8 %a, i8 %b, i8 %s) {
define i1 @remove_shift_nuw_ne(i8 %a, i8 %b, i8 %s) {
; CHECK-LABEL: @remove_shift_nuw_ne(
-; CHECK-NEXT: [[T:%.*]] = shl nuw i8 [[A:%.*]], [[S:%.*]]
-; CHECK-NEXT: [[OR:%.*]] = or i8 [[T]], [[B:%.*]]
+; CHECK-NEXT: [[OR:%.*]] = or i8 [[T:%.*]], [[B:%.*]]
; CHECK-NEXT: [[IC:%.*]] = icmp eq i8 [[OR]], 0
; CHECK-NEXT: ret i1 [[IC]]
;
@@ -464,8 +460,7 @@ define i1 @remove_shift_nuw_ne(i8 %a, i8 %b, i8 %s) {
define i1 @remove_shift_nsw_ne(i8 %a, i8 %b, i8 %s) {
; CHECK-LABEL: @remove_shift_nsw_ne(
-; CHECK-NEXT: [[T:%.*]] = shl nsw i8 [[A:%.*]], [[S:%.*]]
-; CHECK-NEXT: [[OR:%.*]] = or i8 [[T]], [[B:%.*]]
+; CHECK-NEXT: [[OR:%.*]] = or i8 [[T:%.*]], [[B:%.*]]
; CHECK-NEXT: [[IC:%.*]] = icmp eq i8 [[OR]], 0
; CHECK-NEXT: ret i1 [[IC]]
;
@@ -490,9 +485,8 @@ define i1 @remove_shift_wraps(i8 %a, i8 %b, i8 %s) {
define i1 @remove_shift_chain_d(i8 %a, i8 %b, i8 %c, i8 %d, i8 %s) {
; CHECK-LABEL: @remove_shift_chain_d(
-; CHECK-NEXT: [[DT:%.*]] = shl nuw i8 [[D:%.*]], [[S:%.*]]
; CHECK-NEXT: [[OR1:%.*]] = or i8 [[A:%.*]], [[B:%.*]]
-; CHECK-NEXT: [[OR2:%.*]] = or i8 [[C:%.*]], [[DT]]
+; CHECK-NEXT: [[OR2:%.*]] = or i8 [[C:%.*]], [[DT:%.*]]
; CHECK-NEXT: [[OR:%.*]] = or i8 [[OR1]], [[OR2]]
; CHECK-NEXT: [[IC:%.*]] = icmp eq i8 [[OR]], 0
; 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) {
define i1 @remove_shift_chain_abcd(i8 %a, i8 %b, i8 %c, i8 %d, i8 %s) {
; CHECK-LABEL: @remove_shift_chain_abcd(
-; CHECK-NEXT: [[AT:%.*]] = shl nuw i8 [[A:%.*]], [[S:%.*]]
-; CHECK-NEXT: [[BT:%.*]] = shl nuw i8 [[B:%.*]], 2
-; CHECK-NEXT: [[CT:%.*]] = shl nuw i8 [[C:%.*]], 1
-; CHECK-NEXT: [[DT:%.*]] = shl nuw i8 [[D:%.*]], [[S]]
-; CHECK-NEXT: [[OR1:%.*]] = or i8 [[AT]], [[BT]]
-; CHECK-NEXT: [[OR2:%.*]] = or i8 [[CT]], [[DT]]
+; CHECK-NEXT: [[OR1:%.*]] = or i8 [[AT:%.*]], [[BT:%.*]]
+; CHECK-NEXT: [[OR2:%.*]] = or i8 [[CT:%.*]], [[DT:%.*]]
; CHECK-NEXT: [[OR:%.*]] = or i8 [[OR1]], [[OR2]]
; CHECK-NEXT: [[IC:%.*]] = icmp eq i8 [[OR]], 0
; CHECK-NEXT: ret i1 [[IC]]
>From 4bc6794d088cf2d9fb81190e20b7d4a7ffddc006 Mon Sep 17 00:00:00 2001
From: David Green <david.green at arm.com>
Date: Wed, 30 Apr 2025 20:09:51 +0100
Subject: [PATCH 3/3] Address comments
---
.../InstCombine/InstCombineCompares.cpp | 61 ++++++++++---------
.../Transforms/InstCombine/icmp-of-or-x.ll | 24 ++++++++
2 files changed, 57 insertions(+), 28 deletions(-)
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
index 338dda9238704..e507c400c3f36 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
@@ -1223,6 +1223,33 @@ Instruction *InstCombinerImpl::foldSignBitTest(ICmpInst &I) {
X, ConstantInt::getNullValue(XTy));
}
+/// Combine away instructions providing they are still equivalent when compared
+/// against 0. i.e do they have any bits set.
+static Value *combineAwayHasAnyBitsSetChain(Value *V,
+ InstCombiner::BuilderTy &Builder) {
+ auto *I = dyn_cast<Instruction>(V);
+ if (!I || I->getOpcode() != Instruction::Or || !I->hasOneUse())
+ return nullptr;
+
+ // Remove the shl in or(shl(x, y), z) so long as the shl is nuw or nsw.
+ Value *A, *B;
+ if (match(I, m_c_Or(m_CombineOr(m_NSWShl(m_Value(A), m_Value()),
+ m_NUWShl(m_Value(A), m_Value())),
+ m_Value(B))))
+ return Builder.CreateOr(A, B);
+
+ // Look deeper into the chain of or's.
+ Value *Op0 = I->getOperand(0);
+ if (auto *NOp = combineAwayHasAnyBitsSetChain(Op0, Builder))
+ Op0 = NOp;
+ Value *Op1 = I->getOperand(1);
+ if (auto *NOp = combineAwayHasAnyBitsSetChain(Op1, Builder))
+ Op1 = NOp;
+ if (Op0 != I->getOperand(0) || Op1 != I->getOperand(1))
+ return Builder.CreateOr(Op0, Op1);
+ return nullptr;
+}
+
// Handle icmp pred X, 0
Instruction *InstCombinerImpl::foldICmpWithZero(ICmpInst &Cmp) {
CmpInst::Predicate Pred = Cmp.getPredicate();
@@ -1298,6 +1325,12 @@ Instruction *InstCombinerImpl::foldICmpWithZero(ICmpInst &Cmp) {
// eq/ne (mul X, Y)) with (icmp eq/ne X/Y) and if X/Y is known non-zero that
// will fold to a constant elsewhere.
}
+
+ // icmp eq/ne or(shl(a), b), 0 -> icmp eq/ne or(a, b), 0
+ if (ICmpInst::isEquality(Pred))
+ if (auto *Res = combineAwayHasAnyBitsSetChain(Cmp.getOperand(0), Builder))
+ return new ICmpInst(Pred, Res, Cmp.getOperand(1));
+
return nullptr;
}
@@ -5046,29 +5079,6 @@ static Instruction *foldICmpOrXX(ICmpInst &I, const SimplifyQuery &Q,
return nullptr;
}
-static Value *foldShiftAwayFromOrChain(Instruction &I,
- InstCombiner::BuilderTy &Builder) {
- if (I.getOpcode() != Instruction::Or)
- return nullptr;
- Value *A, *B;
- if (match(&I, m_c_Or(m_CombineOr(m_NSWShl(m_Value(A), m_Value()),
- m_NUWShl(m_Value(A), m_Value())),
- m_Value(B))))
- return Builder.CreateOr(A, B);
-
- Value *Op0 = I.getOperand(0);
- if (isa<Instruction>(Op0))
- if (auto *X = foldShiftAwayFromOrChain(*cast<Instruction>(Op0), Builder))
- Op0 = X;
- Value *Op1 = I.getOperand(1);
- if (isa<Instruction>(Op1))
- if (auto *X = foldShiftAwayFromOrChain(*cast<Instruction>(Op1), Builder))
- Op1 = X;
- if (Op0 != I.getOperand(0) || Op1 != I.getOperand(1))
- return Builder.CreateOr(Op0, Op1);
- return nullptr;
-}
-
static Instruction *foldICmpXorXX(ICmpInst &I, const SimplifyQuery &Q,
InstCombinerImpl &IC) {
Value *Op0 = I.getOperand(0), *Op1 = I.getOperand(1), *A;
@@ -7891,11 +7901,6 @@ Instruction *InstCombinerImpl::visitICmpInst(ICmpInst &I) {
}
}
- // icmp eq/ne or(shl(a), b), 0 -> icmp eq/ne or(a, b)
- if (I.isEquality() && match(Op1, m_Zero()) && isa<Instruction>(Op0))
- if (auto *Res = foldShiftAwayFromOrChain(*cast<Instruction>(Op0), Builder))
- return new ICmpInst(I.getPredicate(), Res, Op1);
-
return Changed ? &I : nullptr;
}
diff --git a/llvm/test/Transforms/InstCombine/icmp-of-or-x.ll b/llvm/test/Transforms/InstCombine/icmp-of-or-x.ll
index baaa754e52894..83fe9c8fe4bdc 100644
--- a/llvm/test/Transforms/InstCombine/icmp-of-or-x.ll
+++ b/llvm/test/Transforms/InstCombine/icmp-of-or-x.ll
@@ -518,3 +518,27 @@ define i1 @remove_shift_chain_abcd(i8 %a, i8 %b, i8 %c, i8 %d, i8 %s) {
ret i1 %ic
}
+define i1 @remove_shift_chain_abcd_multiuse(i8 %a, i8 %b, i8 %c, i8 %d, i8 %s) {
+; CHECK-LABEL: @remove_shift_chain_abcd_multiuse(
+; CHECK-NEXT: [[AT:%.*]] = shl nuw i8 [[A:%.*]], [[S:%.*]]
+; CHECK-NEXT: [[BT:%.*]] = shl nuw i8 [[B:%.*]], 2
+; CHECK-NEXT: [[CT:%.*]] = shl nuw i8 [[C:%.*]], 1
+; CHECK-NEXT: [[DT:%.*]] = shl nuw i8 [[D:%.*]], [[S]]
+; CHECK-NEXT: [[OR1:%.*]] = or i8 [[AT]], [[BT]]
+; CHECK-NEXT: [[OR2:%.*]] = or i8 [[CT]], [[DT]]
+; CHECK-NEXT: [[OR:%.*]] = or i8 [[OR1]], [[OR2]]
+; CHECK-NEXT: [[IC:%.*]] = icmp eq i8 [[OR]], 0
+; CHECK-NEXT: call void @use.i8(i8 [[OR]])
+; CHECK-NEXT: ret i1 [[IC]]
+;
+ %at = shl nuw i8 %a, %s
+ %bt = shl nuw i8 %b, 2
+ %ct = shl nuw i8 %c, 1
+ %dt = shl nuw i8 %d, %s
+ %or1 = or i8 %at, %bt
+ %or2 = or i8 %ct, %dt
+ %or = or i8 %or1, %or2
+ %ic = icmp eq i8 %or, 0
+ call void @use.i8(i8 %or)
+ ret i1 %ic
+}
More information about the llvm-commits
mailing list