From 9f2ae7e2d122db53b26828b3e9a4a49a1d1a77d6 Mon Sep 17 00:00:00 2001 From: Simon Pilgrim Date: Tue, 6 Feb 2018 18:39:23 +0000 Subject: [PATCH] [InstCombine][ValueTracking] Match non-uniform constant power-of-two vectors Generalize existing constant matching to work with non-uniform constant vectors as well. Differential Revision: https://reviews.llvm.org/D42818 llvm-svn: 324369 --- llvm/include/llvm/IR/PatternMatch.h | 29 +++++++++++++++++-- llvm/lib/Analysis/ValueTracking.cpp | 13 ++++----- .../Transforms/InstCombine/vector-urem.ll | 2 +- 3 files changed, 33 insertions(+), 11 deletions(-) diff --git a/llvm/include/llvm/IR/PatternMatch.h b/llvm/include/llvm/IR/PatternMatch.h index 794e1e456c8c..3072bb5a2405 100644 --- a/llvm/include/llvm/IR/PatternMatch.h +++ b/llvm/include/llvm/IR/PatternMatch.h @@ -289,10 +289,27 @@ template struct cst_pred_ty : public Predicate { template bool match(ITy *V) { if (const auto *CI = dyn_cast(V)) return this->isValue(CI->getValue()); - if (V->getType()->isVectorTy()) - if (const auto *C = dyn_cast(V)) + if (V->getType()->isVectorTy()) { + if (const auto *C = dyn_cast(V)) { if (const auto *CI = dyn_cast_or_null(C->getSplatValue())) return this->isValue(CI->getValue()); + + // Non-splat vector constant: check each element for a match. + unsigned NumElts = V->getType()->getVectorNumElements(); + assert(NumElts != 0 && "Constant vector with no elements?"); + for (unsigned i = 0; i != NumElts; ++i) { + Constant *Elt = C->getAggregateElement(i); + if (!Elt) + return false; + if (isa(Elt)) + continue; + auto *CI = dyn_cast(Elt); + if (!CI || !this->isValue(CI->getValue())) + return false; + } + return true; + } + } return false; } }; @@ -330,6 +347,14 @@ struct is_power2 { inline cst_pred_ty m_Power2() { return cst_pred_ty(); } inline api_pred_ty m_Power2(const APInt *&V) { return V; } +struct is_power2_or_zero { + bool isValue(const APInt &C) { return !C || C.isPowerOf2(); } +}; + +/// \brief Match an integer or vector of zero or power of 2 values. +inline cst_pred_ty m_Power2OrZero() { return cst_pred_ty(); } +inline api_pred_ty m_Power2OrZero(const APInt *&V) { return V; } + struct is_maxsignedvalue { bool isValue(const APInt &C) { return C.isMaxSignedValue(); } }; diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp index 14a26b5c151f..5a8bd4bb7a18 100644 --- a/llvm/lib/Analysis/ValueTracking.cpp +++ b/llvm/lib/Analysis/ValueTracking.cpp @@ -1646,14 +1646,11 @@ bool isKnownToBeAPowerOfTwo(const Value *V, bool OrZero, unsigned Depth, const Query &Q) { assert(Depth <= MaxDepth && "Limit Search Depth"); - if (const Constant *C = dyn_cast(V)) { - if (C->isNullValue()) - return OrZero; - - const APInt *ConstIntOrConstSplatInt; - if (match(C, m_APInt(ConstIntOrConstSplatInt))) - return ConstIntOrConstSplatInt->isPowerOf2(); - } + // Attempt to match against constants. + if (OrZero && match(V, m_Power2OrZero())) + return true; + if (match(V, m_Power2())) + return true; // 1 << X is clearly a power of two if the one is not shifted off the end. If // it is shifted off the end then the result is undefined. diff --git a/llvm/test/Transforms/InstCombine/vector-urem.ll b/llvm/test/Transforms/InstCombine/vector-urem.ll index 9a266f7f4d0e..bf538d0ea80c 100644 --- a/llvm/test/Transforms/InstCombine/vector-urem.ll +++ b/llvm/test/Transforms/InstCombine/vector-urem.ll @@ -12,7 +12,7 @@ define <4 x i32> @test_v4i32_splatconst_pow2(<4 x i32> %a0) { define <4 x i32> @test_v4i32_const_pow2(<4 x i32> %a0) { ; CHECK-LABEL: @test_v4i32_const_pow2( -; CHECK-NEXT: [[TMP1:%.*]] = urem <4 x i32> [[A0:%.*]], +; CHECK-NEXT: [[TMP1:%.*]] = and <4 x i32> [[A0:%.*]], ; CHECK-NEXT: ret <4 x i32> [[TMP1]] ; %1 = urem <4 x i32> %a0,