xref: /freebsd-src/contrib/llvm-project/llvm/lib/Transforms/Vectorize/VPlanAnalysis.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
15f757f3fSDimitry Andric //===- VPlanAnalysis.cpp - Various Analyses working on VPlan ----*- C++ -*-===//
25f757f3fSDimitry Andric //
35f757f3fSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
45f757f3fSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
55f757f3fSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
65f757f3fSDimitry Andric //
75f757f3fSDimitry Andric //===----------------------------------------------------------------------===//
85f757f3fSDimitry Andric 
95f757f3fSDimitry Andric #include "VPlanAnalysis.h"
105f757f3fSDimitry Andric #include "VPlan.h"
11*0fca6ea1SDimitry Andric #include "VPlanCFG.h"
125f757f3fSDimitry Andric #include "llvm/ADT/TypeSwitch.h"
13*0fca6ea1SDimitry Andric #include "llvm/IR/Instruction.h"
14*0fca6ea1SDimitry Andric #include "llvm/IR/PatternMatch.h"
155f757f3fSDimitry Andric 
165f757f3fSDimitry Andric using namespace llvm;
175f757f3fSDimitry Andric 
185f757f3fSDimitry Andric #define DEBUG_TYPE "vplan"
195f757f3fSDimitry Andric 
205f757f3fSDimitry Andric Type *VPTypeAnalysis::inferScalarTypeForRecipe(const VPBlendRecipe *R) {
215f757f3fSDimitry Andric   Type *ResTy = inferScalarType(R->getIncomingValue(0));
225f757f3fSDimitry Andric   for (unsigned I = 1, E = R->getNumIncomingValues(); I != E; ++I) {
235f757f3fSDimitry Andric     VPValue *Inc = R->getIncomingValue(I);
245f757f3fSDimitry Andric     assert(inferScalarType(Inc) == ResTy &&
255f757f3fSDimitry Andric            "different types inferred for different incoming values");
265f757f3fSDimitry Andric     CachedTypes[Inc] = ResTy;
275f757f3fSDimitry Andric   }
285f757f3fSDimitry Andric   return ResTy;
295f757f3fSDimitry Andric }
305f757f3fSDimitry Andric 
315f757f3fSDimitry Andric Type *VPTypeAnalysis::inferScalarTypeForRecipe(const VPInstruction *R) {
32*0fca6ea1SDimitry Andric   // Set the result type from the first operand, check if the types for all
33*0fca6ea1SDimitry Andric   // other operands match and cache them.
34*0fca6ea1SDimitry Andric   auto SetResultTyFromOp = [this, R]() {
35*0fca6ea1SDimitry Andric     Type *ResTy = inferScalarType(R->getOperand(0));
36*0fca6ea1SDimitry Andric     for (unsigned Op = 1; Op != R->getNumOperands(); ++Op) {
37*0fca6ea1SDimitry Andric       VPValue *OtherV = R->getOperand(Op);
38*0fca6ea1SDimitry Andric       assert(inferScalarType(OtherV) == ResTy &&
39*0fca6ea1SDimitry Andric              "different types inferred for different operands");
40*0fca6ea1SDimitry Andric       CachedTypes[OtherV] = ResTy;
41*0fca6ea1SDimitry Andric     }
42*0fca6ea1SDimitry Andric     return ResTy;
43*0fca6ea1SDimitry Andric   };
44*0fca6ea1SDimitry Andric 
45*0fca6ea1SDimitry Andric   unsigned Opcode = R->getOpcode();
46*0fca6ea1SDimitry Andric   if (Instruction::isBinaryOp(Opcode) || Instruction::isUnaryOp(Opcode))
47*0fca6ea1SDimitry Andric     return SetResultTyFromOp();
48*0fca6ea1SDimitry Andric 
49*0fca6ea1SDimitry Andric   switch (Opcode) {
505f757f3fSDimitry Andric   case Instruction::Select: {
515f757f3fSDimitry Andric     Type *ResTy = inferScalarType(R->getOperand(1));
525f757f3fSDimitry Andric     VPValue *OtherV = R->getOperand(2);
535f757f3fSDimitry Andric     assert(inferScalarType(OtherV) == ResTy &&
545f757f3fSDimitry Andric            "different types inferred for different operands");
555f757f3fSDimitry Andric     CachedTypes[OtherV] = ResTy;
565f757f3fSDimitry Andric     return ResTy;
575f757f3fSDimitry Andric   }
58*0fca6ea1SDimitry Andric   case Instruction::ICmp:
59*0fca6ea1SDimitry Andric   case VPInstruction::ActiveLaneMask:
60*0fca6ea1SDimitry Andric     return inferScalarType(R->getOperand(1));
61*0fca6ea1SDimitry Andric   case VPInstruction::FirstOrderRecurrenceSplice:
62*0fca6ea1SDimitry Andric   case VPInstruction::Not:
63*0fca6ea1SDimitry Andric     return SetResultTyFromOp();
64*0fca6ea1SDimitry Andric   case VPInstruction::ExtractFromEnd: {
65*0fca6ea1SDimitry Andric     Type *BaseTy = inferScalarType(R->getOperand(0));
66*0fca6ea1SDimitry Andric     if (auto *VecTy = dyn_cast<VectorType>(BaseTy))
67*0fca6ea1SDimitry Andric       return VecTy->getElementType();
68*0fca6ea1SDimitry Andric     return BaseTy;
695f757f3fSDimitry Andric   }
70*0fca6ea1SDimitry Andric   case VPInstruction::LogicalAnd:
71*0fca6ea1SDimitry Andric     return IntegerType::get(Ctx, 1);
72*0fca6ea1SDimitry Andric   case VPInstruction::PtrAdd:
73*0fca6ea1SDimitry Andric     // Return the type based on the pointer argument (i.e. first operand).
74*0fca6ea1SDimitry Andric     return inferScalarType(R->getOperand(0));
75*0fca6ea1SDimitry Andric   case VPInstruction::BranchOnCond:
76*0fca6ea1SDimitry Andric   case VPInstruction::BranchOnCount:
77*0fca6ea1SDimitry Andric     return Type::getVoidTy(Ctx);
785f757f3fSDimitry Andric   default:
795f757f3fSDimitry Andric     break;
805f757f3fSDimitry Andric   }
815f757f3fSDimitry Andric   // Type inference not implemented for opcode.
825f757f3fSDimitry Andric   LLVM_DEBUG({
835f757f3fSDimitry Andric     dbgs() << "LV: Found unhandled opcode for: ";
845f757f3fSDimitry Andric     R->getVPSingleValue()->dump();
855f757f3fSDimitry Andric   });
865f757f3fSDimitry Andric   llvm_unreachable("Unhandled opcode!");
875f757f3fSDimitry Andric }
885f757f3fSDimitry Andric 
895f757f3fSDimitry Andric Type *VPTypeAnalysis::inferScalarTypeForRecipe(const VPWidenRecipe *R) {
905f757f3fSDimitry Andric   unsigned Opcode = R->getOpcode();
915f757f3fSDimitry Andric   switch (Opcode) {
925f757f3fSDimitry Andric   case Instruction::ICmp:
935f757f3fSDimitry Andric   case Instruction::FCmp:
945f757f3fSDimitry Andric     return IntegerType::get(Ctx, 1);
955f757f3fSDimitry Andric   case Instruction::UDiv:
965f757f3fSDimitry Andric   case Instruction::SDiv:
975f757f3fSDimitry Andric   case Instruction::SRem:
985f757f3fSDimitry Andric   case Instruction::URem:
995f757f3fSDimitry Andric   case Instruction::Add:
1005f757f3fSDimitry Andric   case Instruction::FAdd:
1015f757f3fSDimitry Andric   case Instruction::Sub:
1025f757f3fSDimitry Andric   case Instruction::FSub:
1035f757f3fSDimitry Andric   case Instruction::Mul:
1045f757f3fSDimitry Andric   case Instruction::FMul:
1055f757f3fSDimitry Andric   case Instruction::FDiv:
1065f757f3fSDimitry Andric   case Instruction::FRem:
1075f757f3fSDimitry Andric   case Instruction::Shl:
1085f757f3fSDimitry Andric   case Instruction::LShr:
1095f757f3fSDimitry Andric   case Instruction::AShr:
1105f757f3fSDimitry Andric   case Instruction::And:
1115f757f3fSDimitry Andric   case Instruction::Or:
1125f757f3fSDimitry Andric   case Instruction::Xor: {
1135f757f3fSDimitry Andric     Type *ResTy = inferScalarType(R->getOperand(0));
1145f757f3fSDimitry Andric     assert(ResTy == inferScalarType(R->getOperand(1)) &&
1155f757f3fSDimitry Andric            "types for both operands must match for binary op");
1165f757f3fSDimitry Andric     CachedTypes[R->getOperand(1)] = ResTy;
1175f757f3fSDimitry Andric     return ResTy;
1185f757f3fSDimitry Andric   }
1195f757f3fSDimitry Andric   case Instruction::FNeg:
1205f757f3fSDimitry Andric   case Instruction::Freeze:
1215f757f3fSDimitry Andric     return inferScalarType(R->getOperand(0));
1225f757f3fSDimitry Andric   default:
1235f757f3fSDimitry Andric     break;
1245f757f3fSDimitry Andric   }
1255f757f3fSDimitry Andric 
1265f757f3fSDimitry Andric   // Type inference not implemented for opcode.
1275f757f3fSDimitry Andric   LLVM_DEBUG({
1285f757f3fSDimitry Andric     dbgs() << "LV: Found unhandled opcode for: ";
1295f757f3fSDimitry Andric     R->getVPSingleValue()->dump();
1305f757f3fSDimitry Andric   });
1315f757f3fSDimitry Andric   llvm_unreachable("Unhandled opcode!");
1325f757f3fSDimitry Andric }
1335f757f3fSDimitry Andric 
1345f757f3fSDimitry Andric Type *VPTypeAnalysis::inferScalarTypeForRecipe(const VPWidenCallRecipe *R) {
1355f757f3fSDimitry Andric   auto &CI = *cast<CallInst>(R->getUnderlyingInstr());
1365f757f3fSDimitry Andric   return CI.getType();
1375f757f3fSDimitry Andric }
1385f757f3fSDimitry Andric 
139*0fca6ea1SDimitry Andric Type *VPTypeAnalysis::inferScalarTypeForRecipe(const VPWidenMemoryRecipe *R) {
140*0fca6ea1SDimitry Andric   assert((isa<VPWidenLoadRecipe>(R) || isa<VPWidenLoadEVLRecipe>(R)) &&
141*0fca6ea1SDimitry Andric          "Store recipes should not define any values");
1425f757f3fSDimitry Andric   return cast<LoadInst>(&R->getIngredient())->getType();
1435f757f3fSDimitry Andric }
1445f757f3fSDimitry Andric 
1455f757f3fSDimitry Andric Type *VPTypeAnalysis::inferScalarTypeForRecipe(const VPWidenSelectRecipe *R) {
1465f757f3fSDimitry Andric   Type *ResTy = inferScalarType(R->getOperand(1));
1475f757f3fSDimitry Andric   VPValue *OtherV = R->getOperand(2);
1485f757f3fSDimitry Andric   assert(inferScalarType(OtherV) == ResTy &&
1495f757f3fSDimitry Andric          "different types inferred for different operands");
1505f757f3fSDimitry Andric   CachedTypes[OtherV] = ResTy;
1515f757f3fSDimitry Andric   return ResTy;
1525f757f3fSDimitry Andric }
1535f757f3fSDimitry Andric 
1545f757f3fSDimitry Andric Type *VPTypeAnalysis::inferScalarTypeForRecipe(const VPReplicateRecipe *R) {
1555f757f3fSDimitry Andric   switch (R->getUnderlyingInstr()->getOpcode()) {
1565f757f3fSDimitry Andric   case Instruction::Call: {
1575f757f3fSDimitry Andric     unsigned CallIdx = R->getNumOperands() - (R->isPredicated() ? 2 : 1);
1585f757f3fSDimitry Andric     return cast<Function>(R->getOperand(CallIdx)->getLiveInIRValue())
1595f757f3fSDimitry Andric         ->getReturnType();
1605f757f3fSDimitry Andric   }
1615f757f3fSDimitry Andric   case Instruction::UDiv:
1625f757f3fSDimitry Andric   case Instruction::SDiv:
1635f757f3fSDimitry Andric   case Instruction::SRem:
1645f757f3fSDimitry Andric   case Instruction::URem:
1655f757f3fSDimitry Andric   case Instruction::Add:
1665f757f3fSDimitry Andric   case Instruction::FAdd:
1675f757f3fSDimitry Andric   case Instruction::Sub:
1685f757f3fSDimitry Andric   case Instruction::FSub:
1695f757f3fSDimitry Andric   case Instruction::Mul:
1705f757f3fSDimitry Andric   case Instruction::FMul:
1715f757f3fSDimitry Andric   case Instruction::FDiv:
1725f757f3fSDimitry Andric   case Instruction::FRem:
1735f757f3fSDimitry Andric   case Instruction::Shl:
1745f757f3fSDimitry Andric   case Instruction::LShr:
1755f757f3fSDimitry Andric   case Instruction::AShr:
1765f757f3fSDimitry Andric   case Instruction::And:
1775f757f3fSDimitry Andric   case Instruction::Or:
1785f757f3fSDimitry Andric   case Instruction::Xor: {
1795f757f3fSDimitry Andric     Type *ResTy = inferScalarType(R->getOperand(0));
1805f757f3fSDimitry Andric     assert(ResTy == inferScalarType(R->getOperand(1)) &&
1815f757f3fSDimitry Andric            "inferred types for operands of binary op don't match");
1825f757f3fSDimitry Andric     CachedTypes[R->getOperand(1)] = ResTy;
1835f757f3fSDimitry Andric     return ResTy;
1845f757f3fSDimitry Andric   }
1855f757f3fSDimitry Andric   case Instruction::Select: {
1865f757f3fSDimitry Andric     Type *ResTy = inferScalarType(R->getOperand(1));
1875f757f3fSDimitry Andric     assert(ResTy == inferScalarType(R->getOperand(2)) &&
1885f757f3fSDimitry Andric            "inferred types for operands of select op don't match");
1895f757f3fSDimitry Andric     CachedTypes[R->getOperand(2)] = ResTy;
1905f757f3fSDimitry Andric     return ResTy;
1915f757f3fSDimitry Andric   }
1925f757f3fSDimitry Andric   case Instruction::ICmp:
1935f757f3fSDimitry Andric   case Instruction::FCmp:
1945f757f3fSDimitry Andric     return IntegerType::get(Ctx, 1);
195*0fca6ea1SDimitry Andric   case Instruction::AddrSpaceCast:
1965f757f3fSDimitry Andric   case Instruction::Alloca:
1975f757f3fSDimitry Andric   case Instruction::BitCast:
1985f757f3fSDimitry Andric   case Instruction::Trunc:
1995f757f3fSDimitry Andric   case Instruction::SExt:
2005f757f3fSDimitry Andric   case Instruction::ZExt:
2015f757f3fSDimitry Andric   case Instruction::FPExt:
2025f757f3fSDimitry Andric   case Instruction::FPTrunc:
2035f757f3fSDimitry Andric   case Instruction::ExtractValue:
2045f757f3fSDimitry Andric   case Instruction::SIToFP:
2055f757f3fSDimitry Andric   case Instruction::UIToFP:
2065f757f3fSDimitry Andric   case Instruction::FPToSI:
2075f757f3fSDimitry Andric   case Instruction::FPToUI:
2085f757f3fSDimitry Andric   case Instruction::PtrToInt:
2095f757f3fSDimitry Andric   case Instruction::IntToPtr:
2105f757f3fSDimitry Andric     return R->getUnderlyingInstr()->getType();
2115f757f3fSDimitry Andric   case Instruction::Freeze:
2125f757f3fSDimitry Andric   case Instruction::FNeg:
2135f757f3fSDimitry Andric   case Instruction::GetElementPtr:
2145f757f3fSDimitry Andric     return inferScalarType(R->getOperand(0));
2155f757f3fSDimitry Andric   case Instruction::Load:
2165f757f3fSDimitry Andric     return cast<LoadInst>(R->getUnderlyingInstr())->getType();
2175f757f3fSDimitry Andric   case Instruction::Store:
2185f757f3fSDimitry Andric     // FIXME: VPReplicateRecipes with store opcodes still define a result
2195f757f3fSDimitry Andric     // VPValue, so we need to handle them here. Remove the code here once this
2205f757f3fSDimitry Andric     // is modeled accurately in VPlan.
2215f757f3fSDimitry Andric     return Type::getVoidTy(Ctx);
2225f757f3fSDimitry Andric   default:
2235f757f3fSDimitry Andric     break;
2245f757f3fSDimitry Andric   }
2255f757f3fSDimitry Andric   // Type inference not implemented for opcode.
2265f757f3fSDimitry Andric   LLVM_DEBUG({
2275f757f3fSDimitry Andric     dbgs() << "LV: Found unhandled opcode for: ";
2285f757f3fSDimitry Andric     R->getVPSingleValue()->dump();
2295f757f3fSDimitry Andric   });
2305f757f3fSDimitry Andric   llvm_unreachable("Unhandled opcode");
2315f757f3fSDimitry Andric }
2325f757f3fSDimitry Andric 
2335f757f3fSDimitry Andric Type *VPTypeAnalysis::inferScalarType(const VPValue *V) {
2345f757f3fSDimitry Andric   if (Type *CachedTy = CachedTypes.lookup(V))
2355f757f3fSDimitry Andric     return CachedTy;
2365f757f3fSDimitry Andric 
237*0fca6ea1SDimitry Andric   if (V->isLiveIn()) {
238*0fca6ea1SDimitry Andric     if (auto *IRValue = V->getLiveInIRValue())
239*0fca6ea1SDimitry Andric       return IRValue->getType();
240*0fca6ea1SDimitry Andric     // All VPValues without any underlying IR value (like the vector trip count
241*0fca6ea1SDimitry Andric     // or the backedge-taken count) have the same type as the canonical IV.
242*0fca6ea1SDimitry Andric     return CanonicalIVTy;
243*0fca6ea1SDimitry Andric   }
2445f757f3fSDimitry Andric 
2455f757f3fSDimitry Andric   Type *ResultTy =
2465f757f3fSDimitry Andric       TypeSwitch<const VPRecipeBase *, Type *>(V->getDefiningRecipe())
247*0fca6ea1SDimitry Andric           .Case<VPActiveLaneMaskPHIRecipe, VPCanonicalIVPHIRecipe,
248*0fca6ea1SDimitry Andric                 VPFirstOrderRecurrencePHIRecipe, VPReductionPHIRecipe,
249*0fca6ea1SDimitry Andric                 VPWidenPointerInductionRecipe, VPEVLBasedIVPHIRecipe>(
2505f757f3fSDimitry Andric               [this](const auto *R) {
251*0fca6ea1SDimitry Andric                 // Handle header phi recipes, except VPWidenIntOrFpInduction
2525f757f3fSDimitry Andric                 // which needs special handling due it being possibly truncated.
2535f757f3fSDimitry Andric                 // TODO: consider inferring/caching type of siblings, e.g.,
2545f757f3fSDimitry Andric                 // backedge value, here and in cases below.
2555f757f3fSDimitry Andric                 return inferScalarType(R->getStartValue());
2565f757f3fSDimitry Andric               })
2575f757f3fSDimitry Andric           .Case<VPWidenIntOrFpInductionRecipe, VPDerivedIVRecipe>(
2585f757f3fSDimitry Andric               [](const auto *R) { return R->getScalarType(); })
259*0fca6ea1SDimitry Andric           .Case<VPReductionRecipe, VPPredInstPHIRecipe, VPWidenPHIRecipe,
260*0fca6ea1SDimitry Andric                 VPScalarIVStepsRecipe, VPWidenGEPRecipe, VPVectorPointerRecipe,
261*0fca6ea1SDimitry Andric                 VPWidenCanonicalIVRecipe>([this](const VPRecipeBase *R) {
2625f757f3fSDimitry Andric             return inferScalarType(R->getOperand(0));
2635f757f3fSDimitry Andric           })
2645f757f3fSDimitry Andric           .Case<VPBlendRecipe, VPInstruction, VPWidenRecipe, VPReplicateRecipe,
265*0fca6ea1SDimitry Andric                 VPWidenCallRecipe, VPWidenMemoryRecipe, VPWidenSelectRecipe>(
2665f757f3fSDimitry Andric               [this](const auto *R) { return inferScalarTypeForRecipe(R); })
2675f757f3fSDimitry Andric           .Case<VPInterleaveRecipe>([V](const VPInterleaveRecipe *R) {
2685f757f3fSDimitry Andric             // TODO: Use info from interleave group.
2695f757f3fSDimitry Andric             return V->getUnderlyingValue()->getType();
2705f757f3fSDimitry Andric           })
2715f757f3fSDimitry Andric           .Case<VPWidenCastRecipe>(
272*0fca6ea1SDimitry Andric               [](const VPWidenCastRecipe *R) { return R->getResultType(); })
273*0fca6ea1SDimitry Andric           .Case<VPScalarCastRecipe>(
274*0fca6ea1SDimitry Andric               [](const VPScalarCastRecipe *R) { return R->getResultType(); })
275*0fca6ea1SDimitry Andric           .Case<VPExpandSCEVRecipe>([](const VPExpandSCEVRecipe *R) {
276*0fca6ea1SDimitry Andric             return R->getSCEV()->getType();
277*0fca6ea1SDimitry Andric           })
278*0fca6ea1SDimitry Andric           .Case<VPReductionRecipe>([this](const auto *R) {
279*0fca6ea1SDimitry Andric             return inferScalarType(R->getChainOp());
280*0fca6ea1SDimitry Andric           });
281*0fca6ea1SDimitry Andric 
2825f757f3fSDimitry Andric   assert(ResultTy && "could not infer type for the given VPValue");
2835f757f3fSDimitry Andric   CachedTypes[V] = ResultTy;
2845f757f3fSDimitry Andric   return ResultTy;
2855f757f3fSDimitry Andric }
286*0fca6ea1SDimitry Andric 
287*0fca6ea1SDimitry Andric void llvm::collectEphemeralRecipesForVPlan(
288*0fca6ea1SDimitry Andric     VPlan &Plan, DenseSet<VPRecipeBase *> &EphRecipes) {
289*0fca6ea1SDimitry Andric   // First, collect seed recipes which are operands of assumes.
290*0fca6ea1SDimitry Andric   SmallVector<VPRecipeBase *> Worklist;
291*0fca6ea1SDimitry Andric   for (VPBasicBlock *VPBB : VPBlockUtils::blocksOnly<VPBasicBlock>(
292*0fca6ea1SDimitry Andric            vp_depth_first_deep(Plan.getVectorLoopRegion()->getEntry()))) {
293*0fca6ea1SDimitry Andric     for (VPRecipeBase &R : *VPBB) {
294*0fca6ea1SDimitry Andric       auto *RepR = dyn_cast<VPReplicateRecipe>(&R);
295*0fca6ea1SDimitry Andric       if (!RepR || !match(RepR->getUnderlyingInstr(),
296*0fca6ea1SDimitry Andric                           PatternMatch::m_Intrinsic<Intrinsic::assume>()))
297*0fca6ea1SDimitry Andric         continue;
298*0fca6ea1SDimitry Andric       Worklist.push_back(RepR);
299*0fca6ea1SDimitry Andric       EphRecipes.insert(RepR);
300*0fca6ea1SDimitry Andric     }
301*0fca6ea1SDimitry Andric   }
302*0fca6ea1SDimitry Andric 
303*0fca6ea1SDimitry Andric   // Process operands of candidates in worklist and add them to the set of
304*0fca6ea1SDimitry Andric   // ephemeral recipes, if they don't have side-effects and are only used by
305*0fca6ea1SDimitry Andric   // other ephemeral recipes.
306*0fca6ea1SDimitry Andric   while (!Worklist.empty()) {
307*0fca6ea1SDimitry Andric     VPRecipeBase *Cur = Worklist.pop_back_val();
308*0fca6ea1SDimitry Andric     for (VPValue *Op : Cur->operands()) {
309*0fca6ea1SDimitry Andric       auto *OpR = Op->getDefiningRecipe();
310*0fca6ea1SDimitry Andric       if (!OpR || OpR->mayHaveSideEffects() || EphRecipes.contains(OpR))
311*0fca6ea1SDimitry Andric         continue;
312*0fca6ea1SDimitry Andric       if (any_of(Op->users(), [EphRecipes](VPUser *U) {
313*0fca6ea1SDimitry Andric             auto *UR = dyn_cast<VPRecipeBase>(U);
314*0fca6ea1SDimitry Andric             return !UR || !EphRecipes.contains(UR);
315*0fca6ea1SDimitry Andric           }))
316*0fca6ea1SDimitry Andric         continue;
317*0fca6ea1SDimitry Andric       EphRecipes.insert(OpR);
318*0fca6ea1SDimitry Andric       Worklist.push_back(OpR);
319*0fca6ea1SDimitry Andric     }
320*0fca6ea1SDimitry Andric   }
321*0fca6ea1SDimitry Andric }
322