[llvm] r247846 - [InstCombine] Optimize icmp slt signum(x), 1 --> icmp slt x, 1
Sanjoy Das via llvm-commits
llvm-commits at lists.llvm.org
Wed Sep 16 13:41:29 PDT 2015
Author: sanjoy
Date: Wed Sep 16 15:41:29 2015
New Revision: 247846
URL: http://llvm.org/viewvc/llvm-project?rev=247846&view=rev
Log:
[InstCombine] Optimize icmp slt signum(x), 1 --> icmp slt x, 1
Summary:
`signum(x)` is sometimes implemented as `(x >> 63) | (-x >>> 63)` (for
an `i64` `x`). This change adds a matcher for that pattern, and an
instcombine rule to optimize `signum(x) s< 1`.
Later, we can also consider optimizing:
icmp slt signum(x), 0 --> icmp slt x, 0
icmp sle signum(x), 1 --> true
etc.
Reviewers: majnemer
Subscribers: llvm-commits
Differential Revision: http://reviews.llvm.org/D12703
Modified:
llvm/trunk/include/llvm/IR/PatternMatch.h
llvm/trunk/lib/Transforms/InstCombine/InstCombineCompares.cpp
llvm/trunk/test/Transforms/InstCombine/compare-signs.ll
Modified: llvm/trunk/include/llvm/IR/PatternMatch.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/IR/PatternMatch.h?rev=247846&r1=247845&r2=247846&view=diff
==============================================================================
--- llvm/trunk/include/llvm/IR/PatternMatch.h (original)
+++ llvm/trunk/include/llvm/IR/PatternMatch.h Wed Sep 16 15:41:29 2015
@@ -1272,6 +1272,46 @@ inline typename m_Intrinsic_Ty<Opnd0, Op
return m_Intrinsic<Intrinsic::maxnum>(Op0, Op1);
}
+template <typename Opnd_t> struct Signum_match {
+ Opnd_t Val;
+ Signum_match(const Opnd_t &V) : Val(V) {}
+
+ template <typename OpTy> bool match(OpTy *V) {
+ unsigned TypeSize = V->getType()->getScalarSizeInBits();
+ if (TypeSize == 0)
+ return false;
+
+ unsigned ShiftWidth = TypeSize - 1;
+ Value *OpL = nullptr, *OpR = nullptr;
+
+ // This is the representation of signum we match:
+ //
+ // signum(x) == (x >> 63) | (-x >>u 63)
+ //
+ // An i1 value is its own signum, so it's correct to match
+ //
+ // signum(x) == (x >> 0) | (-x >>u 0)
+ //
+ // for i1 values.
+
+ auto LHS = m_AShr(m_Value(OpL), m_SpecificInt(ShiftWidth));
+ auto RHS = m_LShr(m_Neg(m_Value(OpR)), m_SpecificInt(ShiftWidth));
+ auto Signum = m_Or(LHS, RHS);
+
+ return Signum.match(V) && OpL == OpR && Val.match(OpL);
+ }
+};
+
+/// \brief Matches a signum pattern.
+///
+/// signum(x) =
+/// x > 0 -> 1
+/// x == 0 -> 0
+/// x < 0 -> -1
+template <typename Val_t> inline Signum_match<Val_t> m_Signum(const Val_t &V) {
+ return Signum_match<Val_t>(V);
+}
+
} // end namespace PatternMatch
} // end namespace llvm
Modified: llvm/trunk/lib/Transforms/InstCombine/InstCombineCompares.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/InstCombine/InstCombineCompares.cpp?rev=247846&r1=247845&r2=247846&view=diff
==============================================================================
--- llvm/trunk/lib/Transforms/InstCombine/InstCombineCompares.cpp (original)
+++ llvm/trunk/lib/Transforms/InstCombine/InstCombineCompares.cpp Wed Sep 16 15:41:29 2015
@@ -1145,6 +1145,14 @@ Instruction *InstCombiner::visitICmpInst
switch (LHSI->getOpcode()) {
case Instruction::Trunc:
+ if (RHS->isOne() && RHSV.getBitWidth() > 1) {
+ // icmp slt trunc(signum(V)) 1 --> icmp slt V, 1
+ Value *V = nullptr;
+ if (ICI.getPredicate() == ICmpInst::ICMP_SLT &&
+ match(LHSI->getOperand(0), m_Signum(m_Value(V))))
+ return new ICmpInst(ICmpInst::ICMP_SLT, V,
+ ConstantInt::get(V->getType(), 1));
+ }
if (ICI.isEquality() && LHSI->hasOneUse()) {
// Simplify icmp eq (trunc x to i8), 42 -> icmp eq x, 42|highbits if all
// of the high bits truncated out of x are known.
@@ -1467,6 +1475,15 @@ Instruction *InstCombiner::visitICmpInst
break;
case Instruction::Or: {
+ if (RHS->isOne()) {
+ // icmp slt signum(V) 1 --> icmp slt V, 1
+ Value *V = nullptr;
+ if (ICI.getPredicate() == ICmpInst::ICMP_SLT &&
+ match(LHSI, m_Signum(m_Value(V))))
+ return new ICmpInst(ICmpInst::ICMP_SLT, V,
+ ConstantInt::get(V->getType(), 1));
+ }
+
if (!ICI.isEquality() || !RHS->isNullValue() || !LHSI->hasOneUse())
break;
Value *P, *Q;
Modified: llvm/trunk/test/Transforms/InstCombine/compare-signs.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/InstCombine/compare-signs.ll?rev=247846&r1=247845&r2=247846&view=diff
==============================================================================
--- llvm/trunk/test/Transforms/InstCombine/compare-signs.ll (original)
+++ llvm/trunk/test/Transforms/InstCombine/compare-signs.ll Wed Sep 16 15:41:29 2015
@@ -56,3 +56,43 @@ entry:
; CHECK-NOT: zext
; CHECK: ret i32 %2
}
+
+define i1 @test4a(i32 %a) {
+; CHECK-LABEL: @test4a(
+ entry:
+; CHECK: %c = icmp slt i32 %a, 1
+; CHECK-NEXT: ret i1 %c
+ %l = ashr i32 %a, 31
+ %na = sub i32 0, %a
+ %r = lshr i32 %na, 31
+ %signum = or i32 %l, %r
+ %c = icmp slt i32 %signum, 1
+ ret i1 %c
+}
+
+define i1 @test4b(i64 %a) {
+; CHECK-LABEL: @test4b(
+ entry:
+; CHECK: %c = icmp slt i64 %a, 1
+; CHECK-NEXT: ret i1 %c
+ %l = ashr i64 %a, 63
+ %na = sub i64 0, %a
+ %r = lshr i64 %na, 63
+ %signum = or i64 %l, %r
+ %c = icmp slt i64 %signum, 1
+ ret i1 %c
+}
+
+define i1 @test4c(i64 %a) {
+; CHECK-LABEL: @test4c(
+ entry:
+; CHECK: %c = icmp slt i64 %a, 1
+; CHECK-NEXT: ret i1 %c
+ %l = ashr i64 %a, 63
+ %na = sub i64 0, %a
+ %r = lshr i64 %na, 63
+ %signum = or i64 %l, %r
+ %signum.trunc = trunc i64 %signum to i32
+ %c = icmp slt i32 %signum.trunc, 1
+ ret i1 %c
+}
More information about the llvm-commits
mailing list