[llvm] VPlan: use worklist in simplifyRecipes (PR #93998)
Florian Hahn via llvm-commits
llvm-commits at lists.llvm.org
Tue Aug 20 01:25:40 PDT 2024
================
@@ -986,83 +986,140 @@ void VPlanTransforms::clearReductionWrapFlags(VPlan &Plan) {
}
}
-/// Try to simplify recipe \p R.
-static void simplifyRecipe(VPRecipeBase &R, VPTypeAnalysis &TypeInfo) {
+/// Try to simplify recipe \p R. Returns candidates for further simplification.
+static SmallVector<VPRecipeBase *>
+simplifyRecipe(VPRecipeBase *R, VPTypeAnalysis &TypeInfo, LLVMContext &Ctx) {
using namespace llvm::VPlanPatternMatch;
// Try to remove redundant blend recipes.
- if (auto *Blend = dyn_cast<VPBlendRecipe>(&R)) {
+ if (auto *Blend = dyn_cast<VPBlendRecipe>(R)) {
VPValue *Inc0 = Blend->getIncomingValue(0);
for (unsigned I = 1; I != Blend->getNumIncomingValues(); ++I)
if (Inc0 != Blend->getIncomingValue(I) &&
!match(Blend->getMask(I), m_False()))
- return;
+ return {};
Blend->replaceAllUsesWith(Inc0);
Blend->eraseFromParent();
- return;
+ return {};
}
- VPValue *A;
- if (match(&R, m_Trunc(m_ZExtOrSExt(m_VPValue(A))))) {
- VPValue *Trunc = R.getVPSingleValue();
+ VPValue *X, *X1, *Y, *Z;
+ if (match(R, m_Trunc(m_ZExtOrSExt(m_VPValue(X))))) {
+ VPValue *Trunc = R->getVPSingleValue();
Type *TruncTy = TypeInfo.inferScalarType(Trunc);
- Type *ATy = TypeInfo.inferScalarType(A);
- if (TruncTy == ATy) {
- Trunc->replaceAllUsesWith(A);
+ Type *XTy = TypeInfo.inferScalarType(X);
+ VPWidenCastRecipe *VPC = nullptr;
+ if (TruncTy == XTy) {
+ Trunc->replaceAllUsesWith(X);
} else {
// Don't replace a scalarizing recipe with a widened cast.
- if (isa<VPReplicateRecipe>(&R))
- return;
- if (ATy->getScalarSizeInBits() < TruncTy->getScalarSizeInBits()) {
-
- unsigned ExtOpcode = match(R.getOperand(0), m_SExt(m_VPValue()))
+ if (isa<VPReplicateRecipe>(R))
+ return {};
+ if (XTy->getScalarSizeInBits() < TruncTy->getScalarSizeInBits()) {
+ unsigned ExtOpcode = match(R->getOperand(0), m_SExt(m_VPValue()))
? Instruction::SExt
: Instruction::ZExt;
auto *VPC =
- new VPWidenCastRecipe(Instruction::CastOps(ExtOpcode), A, TruncTy);
- if (auto *UnderlyingExt = R.getOperand(0)->getUnderlyingValue()) {
+ new VPWidenCastRecipe(Instruction::CastOps(ExtOpcode), X, TruncTy);
+ if (auto *UnderlyingExt = R->getOperand(0)->getUnderlyingValue()) {
// UnderlyingExt has distinct return type, used to retain legacy cost.
VPC->setUnderlyingValue(UnderlyingExt);
}
- VPC->insertBefore(&R);
+ VPC->insertBefore(R);
Trunc->replaceAllUsesWith(VPC);
- } else if (ATy->getScalarSizeInBits() > TruncTy->getScalarSizeInBits()) {
- auto *VPC = new VPWidenCastRecipe(Instruction::Trunc, A, TruncTy);
- VPC->insertBefore(&R);
+ } else if (XTy->getScalarSizeInBits() > TruncTy->getScalarSizeInBits()) {
+ auto *VPC = new VPWidenCastRecipe(Instruction::Trunc, X, TruncTy);
+ VPC->insertBefore(R);
Trunc->replaceAllUsesWith(VPC);
}
}
#ifndef NDEBUG
// Verify that the cached type info is for both A and its users is still
// accurate by comparing it to freshly computed types.
VPTypeAnalysis TypeInfo2(
- R.getParent()->getPlan()->getCanonicalIV()->getScalarType(),
+ R->getParent()->getPlan()->getCanonicalIV()->getScalarType(),
TypeInfo.getContext());
- assert(TypeInfo.inferScalarType(A) == TypeInfo2.inferScalarType(A));
- for (VPUser *U : A->users()) {
+ assert(TypeInfo.inferScalarType(X) == TypeInfo2.inferScalarType(X));
+ for (VPUser *U : X->users()) {
auto *R = dyn_cast<VPRecipeBase>(U);
if (!R)
continue;
for (VPValue *VPV : R->definedValues())
assert(TypeInfo.inferScalarType(VPV) == TypeInfo2.inferScalarType(VPV));
}
#endif
+ if (VPC)
+ return {VPC};
+ return {};
}
- // Simplify (X && Y) || (X && !Y) -> X.
- // TODO: Split up into simpler, modular combines: (X && Y) || (X && Z) into X
- // && (Y || Z) and (X || !X) into true. This requires queuing newly created
- // recipes to be visited during simplification.
- VPValue *X, *Y, *X1, *Y1;
- if (match(&R,
- m_c_BinaryOr(m_LogicalAnd(m_VPValue(X), m_VPValue(Y)),
- m_LogicalAnd(m_VPValue(X1), m_Not(m_VPValue(Y1))))) &&
- X == X1 && Y == Y1) {
- R.getVPSingleValue()->replaceAllUsesWith(X);
- return;
+ // (X || !X) -> true.
+ if (match(R, m_c_BinaryOr(m_VPValue(X), m_Not(m_VPValue(X1)))) && X == X1) {
+ auto *VPV = new VPValue(ConstantInt::getTrue(Ctx));
+ R->getVPSingleValue()->replaceAllUsesWith(VPV);
+ R->eraseFromParent();
----------------
fhahn wrote:
There's nothing from preventing the same recipe being added multiple times to the worklist (probably at the moment it's not an issue, but can become one in the future). Better to let them be cleaned up later as is done now, to avoid this problem?
https://github.com/llvm/llvm-project/pull/93998
More information about the llvm-commits
mailing list