1 //===- VPlanAnalysis.cpp - Various Analyses working on VPlan ----*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #include "VPlanAnalysis.h" 10 #include "VPlan.h" 11 #include "VPlanCFG.h" 12 #include "VPlanDominatorTree.h" 13 #include "llvm/ADT/TypeSwitch.h" 14 #include "llvm/Analysis/ScalarEvolution.h" 15 #include "llvm/IR/Instruction.h" 16 #include "llvm/IR/PatternMatch.h" 17 #include "llvm/Support/GenericDomTreeConstruction.h" 18 19 using namespace llvm; 20 21 #define DEBUG_TYPE "vplan" 22 23 Type *VPTypeAnalysis::inferScalarTypeForRecipe(const VPBlendRecipe *R) { 24 Type *ResTy = inferScalarType(R->getIncomingValue(0)); 25 for (unsigned I = 1, E = R->getNumIncomingValues(); I != E; ++I) { 26 VPValue *Inc = R->getIncomingValue(I); 27 assert(inferScalarType(Inc) == ResTy && 28 "different types inferred for different incoming values"); 29 CachedTypes[Inc] = ResTy; 30 } 31 return ResTy; 32 } 33 34 Type *VPTypeAnalysis::inferScalarTypeForRecipe(const VPInstruction *R) { 35 // Set the result type from the first operand, check if the types for all 36 // other operands match and cache them. 37 auto SetResultTyFromOp = [this, R]() { 38 Type *ResTy = inferScalarType(R->getOperand(0)); 39 for (unsigned Op = 1; Op != R->getNumOperands(); ++Op) { 40 VPValue *OtherV = R->getOperand(Op); 41 assert(inferScalarType(OtherV) == ResTy && 42 "different types inferred for different operands"); 43 CachedTypes[OtherV] = ResTy; 44 } 45 return ResTy; 46 }; 47 48 unsigned Opcode = R->getOpcode(); 49 if (Instruction::isBinaryOp(Opcode) || Instruction::isUnaryOp(Opcode)) 50 return SetResultTyFromOp(); 51 52 switch (Opcode) { 53 case Instruction::Select: { 54 Type *ResTy = inferScalarType(R->getOperand(1)); 55 VPValue *OtherV = R->getOperand(2); 56 assert(inferScalarType(OtherV) == ResTy && 57 "different types inferred for different operands"); 58 CachedTypes[OtherV] = ResTy; 59 return ResTy; 60 } 61 case Instruction::ICmp: 62 case VPInstruction::ActiveLaneMask: 63 return inferScalarType(R->getOperand(1)); 64 case VPInstruction::ComputeReductionResult: { 65 auto *PhiR = cast<VPReductionPHIRecipe>(R->getOperand(0)); 66 auto *OrigPhi = cast<PHINode>(PhiR->getUnderlyingValue()); 67 return OrigPhi->getType(); 68 } 69 case VPInstruction::ExplicitVectorLength: 70 return Type::getIntNTy(Ctx, 32); 71 case VPInstruction::FirstOrderRecurrenceSplice: 72 case VPInstruction::Not: 73 case VPInstruction::ResumePhi: 74 return SetResultTyFromOp(); 75 case VPInstruction::ExtractFromEnd: { 76 Type *BaseTy = inferScalarType(R->getOperand(0)); 77 if (auto *VecTy = dyn_cast<VectorType>(BaseTy)) 78 return VecTy->getElementType(); 79 return BaseTy; 80 } 81 case VPInstruction::LogicalAnd: 82 return IntegerType::get(Ctx, 1); 83 case VPInstruction::PtrAdd: 84 // Return the type based on the pointer argument (i.e. first operand). 85 return inferScalarType(R->getOperand(0)); 86 case VPInstruction::BranchOnCond: 87 case VPInstruction::BranchOnCount: 88 return Type::getVoidTy(Ctx); 89 default: 90 break; 91 } 92 // Type inference not implemented for opcode. 93 LLVM_DEBUG({ 94 dbgs() << "LV: Found unhandled opcode for: "; 95 R->getVPSingleValue()->dump(); 96 }); 97 llvm_unreachable("Unhandled opcode!"); 98 } 99 100 Type *VPTypeAnalysis::inferScalarTypeForRecipe(const VPWidenRecipe *R) { 101 unsigned Opcode = R->getOpcode(); 102 if (Instruction::isBinaryOp(Opcode) || Instruction::isShift(Opcode) || 103 Instruction::isBitwiseLogicOp(Opcode)) { 104 Type *ResTy = inferScalarType(R->getOperand(0)); 105 assert(ResTy == inferScalarType(R->getOperand(1)) && 106 "types for both operands must match for binary op"); 107 CachedTypes[R->getOperand(1)] = ResTy; 108 return ResTy; 109 } 110 111 switch (Opcode) { 112 case Instruction::ICmp: 113 case Instruction::FCmp: 114 return IntegerType::get(Ctx, 1); 115 case Instruction::FNeg: 116 case Instruction::Freeze: 117 return inferScalarType(R->getOperand(0)); 118 default: 119 break; 120 } 121 122 // Type inference not implemented for opcode. 123 LLVM_DEBUG({ 124 dbgs() << "LV: Found unhandled opcode for: "; 125 R->getVPSingleValue()->dump(); 126 }); 127 llvm_unreachable("Unhandled opcode!"); 128 } 129 130 Type *VPTypeAnalysis::inferScalarTypeForRecipe(const VPWidenCallRecipe *R) { 131 auto &CI = *cast<CallInst>(R->getUnderlyingInstr()); 132 return CI.getType(); 133 } 134 135 Type *VPTypeAnalysis::inferScalarTypeForRecipe(const VPWidenMemoryRecipe *R) { 136 assert((isa<VPWidenLoadRecipe, VPWidenLoadEVLRecipe>(R)) && 137 "Store recipes should not define any values"); 138 return cast<LoadInst>(&R->getIngredient())->getType(); 139 } 140 141 Type *VPTypeAnalysis::inferScalarTypeForRecipe(const VPWidenSelectRecipe *R) { 142 Type *ResTy = inferScalarType(R->getOperand(1)); 143 VPValue *OtherV = R->getOperand(2); 144 assert(inferScalarType(OtherV) == ResTy && 145 "different types inferred for different operands"); 146 CachedTypes[OtherV] = ResTy; 147 return ResTy; 148 } 149 150 Type *VPTypeAnalysis::inferScalarTypeForRecipe(const VPReplicateRecipe *R) { 151 unsigned Opcode = R->getUnderlyingInstr()->getOpcode(); 152 153 if (Instruction::isBinaryOp(Opcode) || Instruction::isShift(Opcode) || 154 Instruction::isBitwiseLogicOp(Opcode)) { 155 Type *ResTy = inferScalarType(R->getOperand(0)); 156 assert(ResTy == inferScalarType(R->getOperand(1)) && 157 "inferred types for operands of binary op don't match"); 158 CachedTypes[R->getOperand(1)] = ResTy; 159 return ResTy; 160 } 161 162 if (Instruction::isCast(Opcode)) 163 return R->getUnderlyingInstr()->getType(); 164 165 switch (Opcode) { 166 case Instruction::Call: { 167 unsigned CallIdx = R->getNumOperands() - (R->isPredicated() ? 2 : 1); 168 return cast<Function>(R->getOperand(CallIdx)->getLiveInIRValue()) 169 ->getReturnType(); 170 } 171 case Instruction::Select: { 172 Type *ResTy = inferScalarType(R->getOperand(1)); 173 assert(ResTy == inferScalarType(R->getOperand(2)) && 174 "inferred types for operands of select op don't match"); 175 CachedTypes[R->getOperand(2)] = ResTy; 176 return ResTy; 177 } 178 case Instruction::ICmp: 179 case Instruction::FCmp: 180 return IntegerType::get(Ctx, 1); 181 case Instruction::Alloca: 182 case Instruction::ExtractValue: 183 return R->getUnderlyingInstr()->getType(); 184 case Instruction::Freeze: 185 case Instruction::FNeg: 186 case Instruction::GetElementPtr: 187 return inferScalarType(R->getOperand(0)); 188 case Instruction::Load: 189 return cast<LoadInst>(R->getUnderlyingInstr())->getType(); 190 case Instruction::Store: 191 // FIXME: VPReplicateRecipes with store opcodes still define a result 192 // VPValue, so we need to handle them here. Remove the code here once this 193 // is modeled accurately in VPlan. 194 return Type::getVoidTy(Ctx); 195 default: 196 break; 197 } 198 // Type inference not implemented for opcode. 199 LLVM_DEBUG({ 200 dbgs() << "LV: Found unhandled opcode for: "; 201 R->getVPSingleValue()->dump(); 202 }); 203 llvm_unreachable("Unhandled opcode"); 204 } 205 206 Type *VPTypeAnalysis::inferScalarType(const VPValue *V) { 207 if (Type *CachedTy = CachedTypes.lookup(V)) 208 return CachedTy; 209 210 if (V->isLiveIn()) { 211 if (auto *IRValue = V->getLiveInIRValue()) 212 return IRValue->getType(); 213 // All VPValues without any underlying IR value (like the vector trip count 214 // or the backedge-taken count) have the same type as the canonical IV. 215 return CanonicalIVTy; 216 } 217 218 Type *ResultTy = 219 TypeSwitch<const VPRecipeBase *, Type *>(V->getDefiningRecipe()) 220 .Case<VPActiveLaneMaskPHIRecipe, VPCanonicalIVPHIRecipe, 221 VPFirstOrderRecurrencePHIRecipe, VPReductionPHIRecipe, 222 VPWidenPointerInductionRecipe, VPEVLBasedIVPHIRecipe, 223 VPScalarPHIRecipe>([this](const auto *R) { 224 // Handle header phi recipes, except VPWidenIntOrFpInduction 225 // which needs special handling due it being possibly truncated. 226 // TODO: consider inferring/caching type of siblings, e.g., 227 // backedge value, here and in cases below. 228 return inferScalarType(R->getStartValue()); 229 }) 230 .Case<VPWidenIntOrFpInductionRecipe, VPDerivedIVRecipe>( 231 [](const auto *R) { return R->getScalarType(); }) 232 .Case<VPReductionRecipe, VPPredInstPHIRecipe, VPWidenPHIRecipe, 233 VPScalarIVStepsRecipe, VPWidenGEPRecipe, VPVectorPointerRecipe, 234 VPReverseVectorPointerRecipe, VPWidenCanonicalIVRecipe, 235 VPPartialReductionRecipe>([this](const VPRecipeBase *R) { 236 return inferScalarType(R->getOperand(0)); 237 }) 238 .Case<VPBlendRecipe, VPInstruction, VPWidenRecipe, VPWidenEVLRecipe, 239 VPReplicateRecipe, VPWidenCallRecipe, VPWidenMemoryRecipe, 240 VPWidenSelectRecipe>( 241 [this](const auto *R) { return inferScalarTypeForRecipe(R); }) 242 .Case<VPWidenIntrinsicRecipe>([](const VPWidenIntrinsicRecipe *R) { 243 return R->getResultType(); 244 }) 245 .Case<VPInterleaveRecipe>([V](const VPInterleaveRecipe *R) { 246 // TODO: Use info from interleave group. 247 return V->getUnderlyingValue()->getType(); 248 }) 249 .Case<VPWidenCastRecipe>( 250 [](const VPWidenCastRecipe *R) { return R->getResultType(); }) 251 .Case<VPScalarCastRecipe>( 252 [](const VPScalarCastRecipe *R) { return R->getResultType(); }) 253 .Case<VPExpandSCEVRecipe>([](const VPExpandSCEVRecipe *R) { 254 return R->getSCEV()->getType(); 255 }) 256 .Case<VPReductionRecipe>([this](const auto *R) { 257 return inferScalarType(R->getChainOp()); 258 }); 259 260 assert(ResultTy && "could not infer type for the given VPValue"); 261 CachedTypes[V] = ResultTy; 262 return ResultTy; 263 } 264 265 void llvm::collectEphemeralRecipesForVPlan( 266 VPlan &Plan, DenseSet<VPRecipeBase *> &EphRecipes) { 267 // First, collect seed recipes which are operands of assumes. 268 SmallVector<VPRecipeBase *> Worklist; 269 for (VPBasicBlock *VPBB : VPBlockUtils::blocksOnly<VPBasicBlock>( 270 vp_depth_first_deep(Plan.getVectorLoopRegion()->getEntry()))) { 271 for (VPRecipeBase &R : *VPBB) { 272 auto *RepR = dyn_cast<VPReplicateRecipe>(&R); 273 if (!RepR || !match(RepR->getUnderlyingInstr(), 274 PatternMatch::m_Intrinsic<Intrinsic::assume>())) 275 continue; 276 Worklist.push_back(RepR); 277 EphRecipes.insert(RepR); 278 } 279 } 280 281 // Process operands of candidates in worklist and add them to the set of 282 // ephemeral recipes, if they don't have side-effects and are only used by 283 // other ephemeral recipes. 284 while (!Worklist.empty()) { 285 VPRecipeBase *Cur = Worklist.pop_back_val(); 286 for (VPValue *Op : Cur->operands()) { 287 auto *OpR = Op->getDefiningRecipe(); 288 if (!OpR || OpR->mayHaveSideEffects() || EphRecipes.contains(OpR)) 289 continue; 290 if (any_of(Op->users(), [EphRecipes](VPUser *U) { 291 auto *UR = dyn_cast<VPRecipeBase>(U); 292 return !UR || !EphRecipes.contains(UR); 293 })) 294 continue; 295 EphRecipes.insert(OpR); 296 Worklist.push_back(OpR); 297 } 298 } 299 } 300 301 template void DomTreeBuilder::Calculate<DominatorTreeBase<VPBlockBase, false>>( 302 DominatorTreeBase<VPBlockBase, false> &DT); 303 304 bool VPDominatorTree::properlyDominates(const VPRecipeBase *A, 305 const VPRecipeBase *B) { 306 if (A == B) 307 return false; 308 309 auto LocalComesBefore = [](const VPRecipeBase *A, const VPRecipeBase *B) { 310 for (auto &R : *A->getParent()) { 311 if (&R == A) 312 return true; 313 if (&R == B) 314 return false; 315 } 316 llvm_unreachable("recipe not found"); 317 }; 318 const VPBlockBase *ParentA = A->getParent(); 319 const VPBlockBase *ParentB = B->getParent(); 320 if (ParentA == ParentB) 321 return LocalComesBefore(A, B); 322 323 #ifndef NDEBUG 324 auto GetReplicateRegion = [](VPRecipeBase *R) -> VPRegionBlock * { 325 auto *Region = dyn_cast_or_null<VPRegionBlock>(R->getParent()->getParent()); 326 if (Region && Region->isReplicator()) { 327 assert(Region->getNumSuccessors() == 1 && 328 Region->getNumPredecessors() == 1 && "Expected SESE region!"); 329 assert(R->getParent()->size() == 1 && 330 "A recipe in an original replicator region must be the only " 331 "recipe in its block"); 332 return Region; 333 } 334 return nullptr; 335 }; 336 assert(!GetReplicateRegion(const_cast<VPRecipeBase *>(A)) && 337 "No replicate regions expected at this point"); 338 assert(!GetReplicateRegion(const_cast<VPRecipeBase *>(B)) && 339 "No replicate regions expected at this point"); 340 #endif 341 return Base::properlyDominates(ParentA, ParentB); 342 } 343