xref: /llvm-project/llvm/lib/Transforms/Vectorize/VPlanAnalysis.cpp (revision 5c15caa83fec6aaae7827b9406adf8ab9fac7eac)
1b0b88643SFlorian Hahn //===- VPlanAnalysis.cpp - Various Analyses working on VPlan ----*- C++ -*-===//
2b0b88643SFlorian Hahn //
3b0b88643SFlorian Hahn // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4b0b88643SFlorian Hahn // See https://llvm.org/LICENSE.txt for license information.
5b0b88643SFlorian Hahn // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6b0b88643SFlorian Hahn //
7b0b88643SFlorian Hahn //===----------------------------------------------------------------------===//
8b0b88643SFlorian Hahn 
9b0b88643SFlorian Hahn #include "VPlanAnalysis.h"
10b0b88643SFlorian Hahn #include "VPlan.h"
11ef89e3efSFlorian Hahn #include "VPlanCFG.h"
1296e1320aSFlorian Hahn #include "VPlanDominatorTree.h"
13b0b88643SFlorian Hahn #include "llvm/ADT/TypeSwitch.h"
140d736e29SFlorian Hahn #include "llvm/Analysis/ScalarEvolution.h"
1583da21aeSFlorian Hahn #include "llvm/IR/Instruction.h"
16ef89e3efSFlorian Hahn #include "llvm/IR/PatternMatch.h"
1796e1320aSFlorian Hahn #include "llvm/Support/GenericDomTreeConstruction.h"
18b0b88643SFlorian Hahn 
19b0b88643SFlorian Hahn using namespace llvm;
20b0b88643SFlorian Hahn 
21b0b88643SFlorian Hahn #define DEBUG_TYPE "vplan"
22b0b88643SFlorian Hahn 
23b0b88643SFlorian Hahn Type *VPTypeAnalysis::inferScalarTypeForRecipe(const VPBlendRecipe *R) {
24b0b88643SFlorian Hahn   Type *ResTy = inferScalarType(R->getIncomingValue(0));
25b0b88643SFlorian Hahn   for (unsigned I = 1, E = R->getNumIncomingValues(); I != E; ++I) {
26b0b88643SFlorian Hahn     VPValue *Inc = R->getIncomingValue(I);
27b0b88643SFlorian Hahn     assert(inferScalarType(Inc) == ResTy &&
28b0b88643SFlorian Hahn            "different types inferred for different incoming values");
29b0b88643SFlorian Hahn     CachedTypes[Inc] = ResTy;
30b0b88643SFlorian Hahn   }
31b0b88643SFlorian Hahn   return ResTy;
32b0b88643SFlorian Hahn }
33b0b88643SFlorian Hahn 
34b0b88643SFlorian Hahn Type *VPTypeAnalysis::inferScalarTypeForRecipe(const VPInstruction *R) {
3583da21aeSFlorian Hahn   // Set the result type from the first operand, check if the types for all
3683da21aeSFlorian Hahn   // other operands match and cache them.
3783da21aeSFlorian Hahn   auto SetResultTyFromOp = [this, R]() {
3883da21aeSFlorian Hahn     Type *ResTy = inferScalarType(R->getOperand(0));
3983da21aeSFlorian Hahn     for (unsigned Op = 1; Op != R->getNumOperands(); ++Op) {
4083da21aeSFlorian Hahn       VPValue *OtherV = R->getOperand(Op);
4183da21aeSFlorian Hahn       assert(inferScalarType(OtherV) == ResTy &&
4283da21aeSFlorian Hahn              "different types inferred for different operands");
4383da21aeSFlorian Hahn       CachedTypes[OtherV] = ResTy;
4483da21aeSFlorian Hahn     }
4583da21aeSFlorian Hahn     return ResTy;
4683da21aeSFlorian Hahn   };
4783da21aeSFlorian Hahn 
4883da21aeSFlorian Hahn   unsigned Opcode = R->getOpcode();
4983da21aeSFlorian Hahn   if (Instruction::isBinaryOp(Opcode) || Instruction::isUnaryOp(Opcode))
5083da21aeSFlorian Hahn     return SetResultTyFromOp();
5183da21aeSFlorian Hahn 
5283da21aeSFlorian Hahn   switch (Opcode) {
53b0b88643SFlorian Hahn   case Instruction::Select: {
54b0b88643SFlorian Hahn     Type *ResTy = inferScalarType(R->getOperand(1));
55b0b88643SFlorian Hahn     VPValue *OtherV = R->getOperand(2);
56b0b88643SFlorian Hahn     assert(inferScalarType(OtherV) == ResTy &&
57b0b88643SFlorian Hahn            "different types inferred for different operands");
58b0b88643SFlorian Hahn     CachedTypes[OtherV] = ResTy;
59b0b88643SFlorian Hahn     return ResTy;
60b0b88643SFlorian Hahn   }
613d66d693SFlorian Hahn   case Instruction::ICmp:
6229b8b721SFlorian Hahn   case VPInstruction::ActiveLaneMask:
63*5c15caa8SLuke Lau     assert(inferScalarType(R->getOperand(0)) ==
64*5c15caa8SLuke Lau                inferScalarType(R->getOperand(1)) &&
65*5c15caa8SLuke Lau            "different types inferred for different operands");
66*5c15caa8SLuke Lau     return IntegerType::get(Ctx, 1);
67bb86c5ddSFlorian Hahn   case VPInstruction::ComputeReductionResult: {
68bb86c5ddSFlorian Hahn     auto *PhiR = cast<VPReductionPHIRecipe>(R->getOperand(0));
69bb86c5ddSFlorian Hahn     auto *OrigPhi = cast<PHINode>(PhiR->getUnderlyingValue());
70bb86c5ddSFlorian Hahn     return OrigPhi->getType();
71bb86c5ddSFlorian Hahn   }
7234cdd67cSFlorian Hahn   case VPInstruction::ExplicitVectorLength:
7334cdd67cSFlorian Hahn     return Type::getIntNTy(Ctx, 32);
7483da21aeSFlorian Hahn   case VPInstruction::FirstOrderRecurrenceSplice:
7583da21aeSFlorian Hahn   case VPInstruction::Not:
76bb86c5ddSFlorian Hahn   case VPInstruction::ResumePhi:
77*5c15caa8SLuke Lau   case VPInstruction::CalculateTripCountMinusVF:
78*5c15caa8SLuke Lau   case VPInstruction::CanonicalIVIncrementForPart:
79*5c15caa8SLuke Lau   case VPInstruction::AnyOf:
8083da21aeSFlorian Hahn     return SetResultTyFromOp();
8107b33013SFlorian Hahn   case VPInstruction::ExtractFromEnd: {
8207b33013SFlorian Hahn     Type *BaseTy = inferScalarType(R->getOperand(0));
8307b33013SFlorian Hahn     if (auto *VecTy = dyn_cast<VectorType>(BaseTy))
8407b33013SFlorian Hahn       return VecTy->getElementType();
8507b33013SFlorian Hahn     return BaseTy;
8607b33013SFlorian Hahn   }
8759cb55d3SRamkumar Ramachandra   case VPInstruction::LogicalAnd:
88*5c15caa8SLuke Lau     assert(inferScalarType(R->getOperand(0))->isIntegerTy(1) &&
89*5c15caa8SLuke Lau            inferScalarType(R->getOperand(1))->isIntegerTy(1) &&
90*5c15caa8SLuke Lau            "LogicalAnd operands should be bool");
9159cb55d3SRamkumar Ramachandra     return IntegerType::get(Ctx, 1);
9206bb8c9fSFlorian Hahn   case VPInstruction::PtrAdd:
9306bb8c9fSFlorian Hahn     // Return the type based on the pointer argument (i.e. first operand).
9406bb8c9fSFlorian Hahn     return inferScalarType(R->getOperand(0));
9529b8b721SFlorian Hahn   case VPInstruction::BranchOnCond:
9629b8b721SFlorian Hahn   case VPInstruction::BranchOnCount:
9729b8b721SFlorian Hahn     return Type::getVoidTy(Ctx);
98b0b88643SFlorian Hahn   default:
99b0b88643SFlorian Hahn     break;
100b0b88643SFlorian Hahn   }
101b0b88643SFlorian Hahn   // Type inference not implemented for opcode.
102b0b88643SFlorian Hahn   LLVM_DEBUG({
103b0b88643SFlorian Hahn     dbgs() << "LV: Found unhandled opcode for: ";
104b0b88643SFlorian Hahn     R->getVPSingleValue()->dump();
105b0b88643SFlorian Hahn   });
106b0b88643SFlorian Hahn   llvm_unreachable("Unhandled opcode!");
107b0b88643SFlorian Hahn }
108b0b88643SFlorian Hahn 
109b0b88643SFlorian Hahn Type *VPTypeAnalysis::inferScalarTypeForRecipe(const VPWidenRecipe *R) {
110b0b88643SFlorian Hahn   unsigned Opcode = R->getOpcode();
111042a1cc5SLiqinWeng   if (Instruction::isBinaryOp(Opcode) || Instruction::isShift(Opcode) ||
112042a1cc5SLiqinWeng       Instruction::isBitwiseLogicOp(Opcode)) {
113b0b88643SFlorian Hahn     Type *ResTy = inferScalarType(R->getOperand(0));
114b0b88643SFlorian Hahn     assert(ResTy == inferScalarType(R->getOperand(1)) &&
115b0b88643SFlorian Hahn            "types for both operands must match for binary op");
116b0b88643SFlorian Hahn     CachedTypes[R->getOperand(1)] = ResTy;
117b0b88643SFlorian Hahn     return ResTy;
118b0b88643SFlorian Hahn   }
119042a1cc5SLiqinWeng 
120042a1cc5SLiqinWeng   switch (Opcode) {
121042a1cc5SLiqinWeng   case Instruction::ICmp:
122042a1cc5SLiqinWeng   case Instruction::FCmp:
123042a1cc5SLiqinWeng     return IntegerType::get(Ctx, 1);
124b0b88643SFlorian Hahn   case Instruction::FNeg:
125b0b88643SFlorian Hahn   case Instruction::Freeze:
126b0b88643SFlorian Hahn     return inferScalarType(R->getOperand(0));
127b0b88643SFlorian Hahn   default:
128b0b88643SFlorian Hahn     break;
129b0b88643SFlorian Hahn   }
130b0b88643SFlorian Hahn 
131b0b88643SFlorian Hahn   // Type inference not implemented for opcode.
132b0b88643SFlorian Hahn   LLVM_DEBUG({
133b0b88643SFlorian Hahn     dbgs() << "LV: Found unhandled opcode for: ";
134b0b88643SFlorian Hahn     R->getVPSingleValue()->dump();
135b0b88643SFlorian Hahn   });
136b0b88643SFlorian Hahn   llvm_unreachable("Unhandled opcode!");
137b0b88643SFlorian Hahn }
138b0b88643SFlorian Hahn 
139b0b88643SFlorian Hahn Type *VPTypeAnalysis::inferScalarTypeForRecipe(const VPWidenCallRecipe *R) {
140b0b88643SFlorian Hahn   auto &CI = *cast<CallInst>(R->getUnderlyingInstr());
141b0b88643SFlorian Hahn   return CI.getType();
142b0b88643SFlorian Hahn }
143b0b88643SFlorian Hahn 
144a9bafe91SFlorian Hahn Type *VPTypeAnalysis::inferScalarTypeForRecipe(const VPWidenMemoryRecipe *R) {
145b26fe5b7SLuke Lau   assert((isa<VPWidenLoadRecipe, VPWidenLoadEVLRecipe>(R)) &&
146a9bafe91SFlorian Hahn          "Store recipes should not define any values");
147b0b88643SFlorian Hahn   return cast<LoadInst>(&R->getIngredient())->getType();
148b0b88643SFlorian Hahn }
149b0b88643SFlorian Hahn 
150b0b88643SFlorian Hahn Type *VPTypeAnalysis::inferScalarTypeForRecipe(const VPWidenSelectRecipe *R) {
151b0b88643SFlorian Hahn   Type *ResTy = inferScalarType(R->getOperand(1));
152b0b88643SFlorian Hahn   VPValue *OtherV = R->getOperand(2);
153b0b88643SFlorian Hahn   assert(inferScalarType(OtherV) == ResTy &&
154b0b88643SFlorian Hahn          "different types inferred for different operands");
155b0b88643SFlorian Hahn   CachedTypes[OtherV] = ResTy;
156b0b88643SFlorian Hahn   return ResTy;
157b0b88643SFlorian Hahn }
158b0b88643SFlorian Hahn 
159b0b88643SFlorian Hahn Type *VPTypeAnalysis::inferScalarTypeForRecipe(const VPReplicateRecipe *R) {
160042a1cc5SLiqinWeng   unsigned Opcode = R->getUnderlyingInstr()->getOpcode();
161042a1cc5SLiqinWeng 
162042a1cc5SLiqinWeng   if (Instruction::isBinaryOp(Opcode) || Instruction::isShift(Opcode) ||
163042a1cc5SLiqinWeng       Instruction::isBitwiseLogicOp(Opcode)) {
164b0b88643SFlorian Hahn     Type *ResTy = inferScalarType(R->getOperand(0));
165b0b88643SFlorian Hahn     assert(ResTy == inferScalarType(R->getOperand(1)) &&
166b0b88643SFlorian Hahn            "inferred types for operands of binary op don't match");
167b0b88643SFlorian Hahn     CachedTypes[R->getOperand(1)] = ResTy;
168b0b88643SFlorian Hahn     return ResTy;
169b0b88643SFlorian Hahn   }
170042a1cc5SLiqinWeng 
171042a1cc5SLiqinWeng   if (Instruction::isCast(Opcode))
172042a1cc5SLiqinWeng     return R->getUnderlyingInstr()->getType();
173042a1cc5SLiqinWeng 
174042a1cc5SLiqinWeng   switch (Opcode) {
175042a1cc5SLiqinWeng   case Instruction::Call: {
176042a1cc5SLiqinWeng     unsigned CallIdx = R->getNumOperands() - (R->isPredicated() ? 2 : 1);
177042a1cc5SLiqinWeng     return cast<Function>(R->getOperand(CallIdx)->getLiveInIRValue())
178042a1cc5SLiqinWeng         ->getReturnType();
179042a1cc5SLiqinWeng   }
180b0b88643SFlorian Hahn   case Instruction::Select: {
181b0b88643SFlorian Hahn     Type *ResTy = inferScalarType(R->getOperand(1));
182b0b88643SFlorian Hahn     assert(ResTy == inferScalarType(R->getOperand(2)) &&
183b0b88643SFlorian Hahn            "inferred types for operands of select op don't match");
184b0b88643SFlorian Hahn     CachedTypes[R->getOperand(2)] = ResTy;
185b0b88643SFlorian Hahn     return ResTy;
186b0b88643SFlorian Hahn   }
187b0b88643SFlorian Hahn   case Instruction::ICmp:
188b0b88643SFlorian Hahn   case Instruction::FCmp:
189b0b88643SFlorian Hahn     return IntegerType::get(Ctx, 1);
190b0b88643SFlorian Hahn   case Instruction::Alloca:
191b0b88643SFlorian Hahn   case Instruction::ExtractValue:
192b0b88643SFlorian Hahn     return R->getUnderlyingInstr()->getType();
193b0b88643SFlorian Hahn   case Instruction::Freeze:
194b0b88643SFlorian Hahn   case Instruction::FNeg:
195b0b88643SFlorian Hahn   case Instruction::GetElementPtr:
196b0b88643SFlorian Hahn     return inferScalarType(R->getOperand(0));
197b0b88643SFlorian Hahn   case Instruction::Load:
198b0b88643SFlorian Hahn     return cast<LoadInst>(R->getUnderlyingInstr())->getType();
199097ba536SFlorian Hahn   case Instruction::Store:
200097ba536SFlorian Hahn     // FIXME: VPReplicateRecipes with store opcodes still define a result
201097ba536SFlorian Hahn     // VPValue, so we need to handle them here. Remove the code here once this
202097ba536SFlorian Hahn     // is modeled accurately in VPlan.
203097ba536SFlorian Hahn     return Type::getVoidTy(Ctx);
204b0b88643SFlorian Hahn   default:
205b0b88643SFlorian Hahn     break;
206b0b88643SFlorian Hahn   }
207b0b88643SFlorian Hahn   // Type inference not implemented for opcode.
208b0b88643SFlorian Hahn   LLVM_DEBUG({
209b0b88643SFlorian Hahn     dbgs() << "LV: Found unhandled opcode for: ";
210b0b88643SFlorian Hahn     R->getVPSingleValue()->dump();
211b0b88643SFlorian Hahn   });
212b0b88643SFlorian Hahn   llvm_unreachable("Unhandled opcode");
213b0b88643SFlorian Hahn }
214b0b88643SFlorian Hahn 
215b0b88643SFlorian Hahn Type *VPTypeAnalysis::inferScalarType(const VPValue *V) {
216b0b88643SFlorian Hahn   if (Type *CachedTy = CachedTypes.lookup(V))
217b0b88643SFlorian Hahn     return CachedTy;
218b0b88643SFlorian Hahn 
2193d66d693SFlorian Hahn   if (V->isLiveIn()) {
2203d66d693SFlorian Hahn     if (auto *IRValue = V->getLiveInIRValue())
2213d66d693SFlorian Hahn       return IRValue->getType();
2223d66d693SFlorian Hahn     // All VPValues without any underlying IR value (like the vector trip count
2233d66d693SFlorian Hahn     // or the backedge-taken count) have the same type as the canonical IV.
2243d66d693SFlorian Hahn     return CanonicalIVTy;
2253d66d693SFlorian Hahn   }
226b0b88643SFlorian Hahn 
227b0b88643SFlorian Hahn   Type *ResultTy =
228b0b88643SFlorian Hahn       TypeSwitch<const VPRecipeBase *, Type *>(V->getDefiningRecipe())
22929b8b721SFlorian Hahn           .Case<VPActiveLaneMaskPHIRecipe, VPCanonicalIVPHIRecipe,
23029b8b721SFlorian Hahn                 VPFirstOrderRecurrencePHIRecipe, VPReductionPHIRecipe,
231a7fda0e1SFlorian Hahn                 VPWidenPointerInductionRecipe, VPEVLBasedIVPHIRecipe,
232a7fda0e1SFlorian Hahn                 VPScalarPHIRecipe>([this](const auto *R) {
233413a66f3SAlexey Bataev             // Handle header phi recipes, except VPWidenIntOrFpInduction
234b0b88643SFlorian Hahn             // which needs special handling due it being possibly truncated.
235b0b88643SFlorian Hahn             // TODO: consider inferring/caching type of siblings, e.g.,
236b0b88643SFlorian Hahn             // backedge value, here and in cases below.
237b0b88643SFlorian Hahn             return inferScalarType(R->getStartValue());
238b0b88643SFlorian Hahn           })
239b0b88643SFlorian Hahn           .Case<VPWidenIntOrFpInductionRecipe, VPDerivedIVRecipe>(
240b0b88643SFlorian Hahn               [](const auto *R) { return R->getScalarType(); })
24129b8b721SFlorian Hahn           .Case<VPReductionRecipe, VPPredInstPHIRecipe, VPWidenPHIRecipe,
24229b8b721SFlorian Hahn                 VPScalarIVStepsRecipe, VPWidenGEPRecipe, VPVectorPointerRecipe,
243795e35a6SSam Tebbs                 VPReverseVectorPointerRecipe, VPWidenCanonicalIVRecipe,
244795e35a6SSam Tebbs                 VPPartialReductionRecipe>([this](const VPRecipeBase *R) {
245b0b88643SFlorian Hahn             return inferScalarType(R->getOperand(0));
246b0b88643SFlorian Hahn           })
24700e40c9bSKolya Panchenko           .Case<VPBlendRecipe, VPInstruction, VPWidenRecipe, VPWidenEVLRecipe,
24800e40c9bSKolya Panchenko                 VPReplicateRecipe, VPWidenCallRecipe, VPWidenMemoryRecipe,
24900e40c9bSKolya Panchenko                 VPWidenSelectRecipe>(
250b0b88643SFlorian Hahn               [this](const auto *R) { return inferScalarTypeForRecipe(R); })
2516fbbe152SFlorian Hahn           .Case<VPWidenIntrinsicRecipe>([](const VPWidenIntrinsicRecipe *R) {
2526fbbe152SFlorian Hahn             return R->getResultType();
2536fbbe152SFlorian Hahn           })
254b0b88643SFlorian Hahn           .Case<VPInterleaveRecipe>([V](const VPInterleaveRecipe *R) {
255b0b88643SFlorian Hahn             // TODO: Use info from interleave group.
256b0b88643SFlorian Hahn             return V->getUnderlyingValue()->getType();
257b0b88643SFlorian Hahn           })
258b0b88643SFlorian Hahn           .Case<VPWidenCastRecipe>(
2590ab539fdSFlorian Hahn               [](const VPWidenCastRecipe *R) { return R->getResultType(); })
2600ab539fdSFlorian Hahn           .Case<VPScalarCastRecipe>(
2610ab539fdSFlorian Hahn               [](const VPScalarCastRecipe *R) { return R->getResultType(); })
2620ab539fdSFlorian Hahn           .Case<VPExpandSCEVRecipe>([](const VPExpandSCEVRecipe *R) {
2630ab539fdSFlorian Hahn             return R->getSCEV()->getType();
2644eb30cfbSMel Chen           })
2654eb30cfbSMel Chen           .Case<VPReductionRecipe>([this](const auto *R) {
2664eb30cfbSMel Chen             return inferScalarType(R->getChainOp());
2670ab539fdSFlorian Hahn           });
2680ab539fdSFlorian Hahn 
269b0b88643SFlorian Hahn   assert(ResultTy && "could not infer type for the given VPValue");
270b0b88643SFlorian Hahn   CachedTypes[V] = ResultTy;
271b0b88643SFlorian Hahn   return ResultTy;
272b0b88643SFlorian Hahn }
273ef89e3efSFlorian Hahn 
274ef89e3efSFlorian Hahn void llvm::collectEphemeralRecipesForVPlan(
275ef89e3efSFlorian Hahn     VPlan &Plan, DenseSet<VPRecipeBase *> &EphRecipes) {
276ef89e3efSFlorian Hahn   // First, collect seed recipes which are operands of assumes.
277ef89e3efSFlorian Hahn   SmallVector<VPRecipeBase *> Worklist;
278ef89e3efSFlorian Hahn   for (VPBasicBlock *VPBB : VPBlockUtils::blocksOnly<VPBasicBlock>(
279ef89e3efSFlorian Hahn            vp_depth_first_deep(Plan.getVectorLoopRegion()->getEntry()))) {
280ef89e3efSFlorian Hahn     for (VPRecipeBase &R : *VPBB) {
281ef89e3efSFlorian Hahn       auto *RepR = dyn_cast<VPReplicateRecipe>(&R);
282ef89e3efSFlorian Hahn       if (!RepR || !match(RepR->getUnderlyingInstr(),
283ef89e3efSFlorian Hahn                           PatternMatch::m_Intrinsic<Intrinsic::assume>()))
284ef89e3efSFlorian Hahn         continue;
285ef89e3efSFlorian Hahn       Worklist.push_back(RepR);
286ef89e3efSFlorian Hahn       EphRecipes.insert(RepR);
287ef89e3efSFlorian Hahn     }
288ef89e3efSFlorian Hahn   }
289ef89e3efSFlorian Hahn 
290ef89e3efSFlorian Hahn   // Process operands of candidates in worklist and add them to the set of
291ef89e3efSFlorian Hahn   // ephemeral recipes, if they don't have side-effects and are only used by
292ef89e3efSFlorian Hahn   // other ephemeral recipes.
293ef89e3efSFlorian Hahn   while (!Worklist.empty()) {
294ef89e3efSFlorian Hahn     VPRecipeBase *Cur = Worklist.pop_back_val();
295ef89e3efSFlorian Hahn     for (VPValue *Op : Cur->operands()) {
296ef89e3efSFlorian Hahn       auto *OpR = Op->getDefiningRecipe();
297ef89e3efSFlorian Hahn       if (!OpR || OpR->mayHaveSideEffects() || EphRecipes.contains(OpR))
298ef89e3efSFlorian Hahn         continue;
299ef89e3efSFlorian Hahn       if (any_of(Op->users(), [EphRecipes](VPUser *U) {
300ef89e3efSFlorian Hahn             auto *UR = dyn_cast<VPRecipeBase>(U);
301ef89e3efSFlorian Hahn             return !UR || !EphRecipes.contains(UR);
302ef89e3efSFlorian Hahn           }))
303ef89e3efSFlorian Hahn         continue;
304ef89e3efSFlorian Hahn       EphRecipes.insert(OpR);
305ef89e3efSFlorian Hahn       Worklist.push_back(OpR);
306ef89e3efSFlorian Hahn     }
307ef89e3efSFlorian Hahn   }
308ef89e3efSFlorian Hahn }
30996e1320aSFlorian Hahn 
31096e1320aSFlorian Hahn template void DomTreeBuilder::Calculate<DominatorTreeBase<VPBlockBase, false>>(
31196e1320aSFlorian Hahn     DominatorTreeBase<VPBlockBase, false> &DT);
31296e1320aSFlorian Hahn 
31396e1320aSFlorian Hahn bool VPDominatorTree::properlyDominates(const VPRecipeBase *A,
31496e1320aSFlorian Hahn                                         const VPRecipeBase *B) {
31596e1320aSFlorian Hahn   if (A == B)
31696e1320aSFlorian Hahn     return false;
31796e1320aSFlorian Hahn 
31896e1320aSFlorian Hahn   auto LocalComesBefore = [](const VPRecipeBase *A, const VPRecipeBase *B) {
31996e1320aSFlorian Hahn     for (auto &R : *A->getParent()) {
32096e1320aSFlorian Hahn       if (&R == A)
32196e1320aSFlorian Hahn         return true;
32296e1320aSFlorian Hahn       if (&R == B)
32396e1320aSFlorian Hahn         return false;
32496e1320aSFlorian Hahn     }
32596e1320aSFlorian Hahn     llvm_unreachable("recipe not found");
32696e1320aSFlorian Hahn   };
32796e1320aSFlorian Hahn   const VPBlockBase *ParentA = A->getParent();
32896e1320aSFlorian Hahn   const VPBlockBase *ParentB = B->getParent();
32996e1320aSFlorian Hahn   if (ParentA == ParentB)
33096e1320aSFlorian Hahn     return LocalComesBefore(A, B);
33196e1320aSFlorian Hahn 
33296e1320aSFlorian Hahn #ifndef NDEBUG
33396e1320aSFlorian Hahn   auto GetReplicateRegion = [](VPRecipeBase *R) -> VPRegionBlock * {
33496e1320aSFlorian Hahn     auto *Region = dyn_cast_or_null<VPRegionBlock>(R->getParent()->getParent());
33596e1320aSFlorian Hahn     if (Region && Region->isReplicator()) {
33696e1320aSFlorian Hahn       assert(Region->getNumSuccessors() == 1 &&
33796e1320aSFlorian Hahn              Region->getNumPredecessors() == 1 && "Expected SESE region!");
33896e1320aSFlorian Hahn       assert(R->getParent()->size() == 1 &&
33996e1320aSFlorian Hahn              "A recipe in an original replicator region must be the only "
34096e1320aSFlorian Hahn              "recipe in its block");
34196e1320aSFlorian Hahn       return Region;
34296e1320aSFlorian Hahn     }
34396e1320aSFlorian Hahn     return nullptr;
34496e1320aSFlorian Hahn   };
34596e1320aSFlorian Hahn   assert(!GetReplicateRegion(const_cast<VPRecipeBase *>(A)) &&
34696e1320aSFlorian Hahn          "No replicate regions expected at this point");
34796e1320aSFlorian Hahn   assert(!GetReplicateRegion(const_cast<VPRecipeBase *>(B)) &&
34896e1320aSFlorian Hahn          "No replicate regions expected at this point");
34996e1320aSFlorian Hahn #endif
35096e1320aSFlorian Hahn   return Base::properlyDominates(ParentA, ParentB);
35196e1320aSFlorian Hahn }
352