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