[PatternMatch] allow undef elements in vectors with m_Neg

This is similar to the m_Not change from D44076.

llvm-svn: 336064
This commit is contained in:
Sanjay Patel 2018-07-01 13:42:57 +00:00
parent 1b899b8559
commit d0b447b76b
2 changed files with 50 additions and 72 deletions

View File

@ -1219,33 +1219,6 @@ m_Store(const ValueOpTy &ValueOp, const PointerOpTy &PointerOp) {
return StoreClass_match<ValueOpTy, PointerOpTy>(ValueOp, PointerOp);
}
//===----------------------------------------------------------------------===//
// Matchers for unary operators
//
template <typename LHS_t> struct neg_match {
LHS_t L;
neg_match(const LHS_t &LHS) : L(LHS) {}
template <typename OpTy> bool match(OpTy *V) {
if (auto *O = dyn_cast<Operator>(V))
if (O->getOpcode() == Instruction::Sub)
return matchIfNeg(O->getOperand(0), O->getOperand(1));
return false;
}
private:
bool matchIfNeg(Value *LHS, Value *RHS) {
return ((isa<ConstantInt>(LHS) && cast<ConstantInt>(LHS)->isZero()) ||
isa<ConstantAggregateZero>(LHS)) &&
L.match(RHS);
}
};
/// Match an integer negate.
template <typename LHS> inline neg_match<LHS> m_Neg(const LHS &L) { return L; }
//===----------------------------------------------------------------------===//
// Matchers for control flow.
//
@ -1632,46 +1605,6 @@ inline typename m_Intrinsic_Ty<Opnd0, Opnd1>::Ty m_FMax(const Opnd0 &Op0,
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);
}
};
/// 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);
}
//===----------------------------------------------------------------------===//
// Matchers for two-operands operators with the operators in either order
//
@ -1726,6 +1659,13 @@ inline BinaryOp_match<LHS, RHS, Instruction::Xor, true> m_c_Xor(const LHS &L,
return BinaryOp_match<LHS, RHS, Instruction::Xor, true>(L, R);
}
/// Matches a 'Neg' as 'sub 0, V'.
template <typename ValTy>
inline BinaryOp_match<cst_pred_ty<is_zero_int>, ValTy, Instruction::Sub>
m_Neg(const ValTy &V) {
return m_Sub(m_ZeroInt(), V);
}
/// Matches a 'Not' as 'xor V, -1' or 'xor -1, V'.
template <typename ValTy>
inline BinaryOp_match<ValTy, cst_pred_ty<is_all_ones>, Instruction::Xor, true>
@ -1772,6 +1712,46 @@ m_c_FMul(const LHS &L, const RHS &R) {
return BinaryOp_match<LHS, RHS, Instruction::FMul, true>(L, R);
}
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);
}
};
/// 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

View File

@ -121,8 +121,7 @@ define i32 @test5(i32 %A, i32 %B) {
define <2 x i8> @neg_op0_vec_undef_elt(<2 x i8> %a, <2 x i8> %b) {
; CHECK-LABEL: @neg_op0_vec_undef_elt(
; CHECK-NEXT: [[NEGA:%.*]] = sub <2 x i8> <i8 0, i8 undef>, [[A:%.*]]
; CHECK-NEXT: [[R:%.*]] = add <2 x i8> [[NEGA]], [[B:%.*]]
; CHECK-NEXT: [[R:%.*]] = sub <2 x i8> [[B:%.*]], [[A:%.*]]
; CHECK-NEXT: ret <2 x i8> [[R]]
;
%nega = sub <2 x i8> <i8 0, i8 undef>, %a
@ -132,9 +131,8 @@ define <2 x i8> @neg_op0_vec_undef_elt(<2 x i8> %a, <2 x i8> %b) {
define <2 x i8> @neg_neg_vec_undef_elt(<2 x i8> %a, <2 x i8> %b) {
; CHECK-LABEL: @neg_neg_vec_undef_elt(
; CHECK-NEXT: [[NEGA:%.*]] = sub <2 x i8> <i8 undef, i8 0>, [[A:%.*]]
; CHECK-NEXT: [[NEGB:%.*]] = sub <2 x i8> <i8 undef, i8 0>, [[B:%.*]]
; CHECK-NEXT: [[R:%.*]] = add <2 x i8> [[NEGA]], [[NEGB]]
; CHECK-NEXT: [[TMP1:%.*]] = add <2 x i8> [[A:%.*]], [[B:%.*]]
; CHECK-NEXT: [[R:%.*]] = sub <2 x i8> zeroinitializer, [[TMP1]]
; CHECK-NEXT: ret <2 x i8> [[R]]
;
%nega = sub <2 x i8> <i8 undef, i8 0>, %a