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