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::ExplicitVectorLength: 65 return Type::getIntNTy(Ctx, 32); 66 case VPInstruction::FirstOrderRecurrenceSplice: 67 case VPInstruction::Not: 68 return SetResultTyFromOp(); 69 case VPInstruction::ExtractFromEnd: { 70 Type *BaseTy = inferScalarType(R->getOperand(0)); 71 if (auto *VecTy = dyn_cast<VectorType>(BaseTy)) 72 return VecTy->getElementType(); 73 return BaseTy; 74 } 75 case VPInstruction::LogicalAnd: 76 return IntegerType::get(Ctx, 1); 77 case VPInstruction::PtrAdd: 78 // Return the type based on the pointer argument (i.e. first operand). 79 return inferScalarType(R->getOperand(0)); 80 case VPInstruction::BranchOnCond: 81 case VPInstruction::BranchOnCount: 82 return Type::getVoidTy(Ctx); 83 default: 84 break; 85 } 86 // Type inference not implemented for opcode. 87 LLVM_DEBUG({ 88 dbgs() << "LV: Found unhandled opcode for: "; 89 R->getVPSingleValue()->dump(); 90 }); 91 llvm_unreachable("Unhandled opcode!"); 92 } 93 94 Type *VPTypeAnalysis::inferScalarTypeForRecipe(const VPWidenRecipe *R) { 95 unsigned Opcode = R->getOpcode(); 96 switch (Opcode) { 97 case Instruction::ICmp: 98 case Instruction::FCmp: 99 return IntegerType::get(Ctx, 1); 100 case Instruction::UDiv: 101 case Instruction::SDiv: 102 case Instruction::SRem: 103 case Instruction::URem: 104 case Instruction::Add: 105 case Instruction::FAdd: 106 case Instruction::Sub: 107 case Instruction::FSub: 108 case Instruction::Mul: 109 case Instruction::FMul: 110 case Instruction::FDiv: 111 case Instruction::FRem: 112 case Instruction::Shl: 113 case Instruction::LShr: 114 case Instruction::AShr: 115 case Instruction::And: 116 case Instruction::Or: 117 case Instruction::Xor: { 118 Type *ResTy = inferScalarType(R->getOperand(0)); 119 assert(ResTy == inferScalarType(R->getOperand(1)) && 120 "types for both operands must match for binary op"); 121 CachedTypes[R->getOperand(1)] = ResTy; 122 return ResTy; 123 } 124 case Instruction::FNeg: 125 case Instruction::Freeze: 126 return inferScalarType(R->getOperand(0)); 127 default: 128 break; 129 } 130 131 // Type inference not implemented for opcode. 132 LLVM_DEBUG({ 133 dbgs() << "LV: Found unhandled opcode for: "; 134 R->getVPSingleValue()->dump(); 135 }); 136 llvm_unreachable("Unhandled opcode!"); 137 } 138 139 Type *VPTypeAnalysis::inferScalarTypeForRecipe(const VPWidenCallRecipe *R) { 140 auto &CI = *cast<CallInst>(R->getUnderlyingInstr()); 141 return CI.getType(); 142 } 143 144 Type *VPTypeAnalysis::inferScalarTypeForRecipe(const VPWidenMemoryRecipe *R) { 145 assert((isa<VPWidenLoadRecipe>(R) || isa<VPWidenLoadEVLRecipe>(R)) && 146 "Store recipes should not define any values"); 147 return cast<LoadInst>(&R->getIngredient())->getType(); 148 } 149 150 Type *VPTypeAnalysis::inferScalarTypeForRecipe(const VPWidenSelectRecipe *R) { 151 Type *ResTy = inferScalarType(R->getOperand(1)); 152 VPValue *OtherV = R->getOperand(2); 153 assert(inferScalarType(OtherV) == ResTy && 154 "different types inferred for different operands"); 155 CachedTypes[OtherV] = ResTy; 156 return ResTy; 157 } 158 159 Type *VPTypeAnalysis::inferScalarTypeForRecipe(const VPReplicateRecipe *R) { 160 switch (R->getUnderlyingInstr()->getOpcode()) { 161 case Instruction::Call: { 162 unsigned CallIdx = R->getNumOperands() - (R->isPredicated() ? 2 : 1); 163 return cast<Function>(R->getOperand(CallIdx)->getLiveInIRValue()) 164 ->getReturnType(); 165 } 166 case Instruction::UDiv: 167 case Instruction::SDiv: 168 case Instruction::SRem: 169 case Instruction::URem: 170 case Instruction::Add: 171 case Instruction::FAdd: 172 case Instruction::Sub: 173 case Instruction::FSub: 174 case Instruction::Mul: 175 case Instruction::FMul: 176 case Instruction::FDiv: 177 case Instruction::FRem: 178 case Instruction::Shl: 179 case Instruction::LShr: 180 case Instruction::AShr: 181 case Instruction::And: 182 case Instruction::Or: 183 case Instruction::Xor: { 184 Type *ResTy = inferScalarType(R->getOperand(0)); 185 assert(ResTy == inferScalarType(R->getOperand(1)) && 186 "inferred types for operands of binary op don't match"); 187 CachedTypes[R->getOperand(1)] = ResTy; 188 return ResTy; 189 } 190 case Instruction::Select: { 191 Type *ResTy = inferScalarType(R->getOperand(1)); 192 assert(ResTy == inferScalarType(R->getOperand(2)) && 193 "inferred types for operands of select op don't match"); 194 CachedTypes[R->getOperand(2)] = ResTy; 195 return ResTy; 196 } 197 case Instruction::ICmp: 198 case Instruction::FCmp: 199 return IntegerType::get(Ctx, 1); 200 case Instruction::AddrSpaceCast: 201 case Instruction::Alloca: 202 case Instruction::BitCast: 203 case Instruction::Trunc: 204 case Instruction::SExt: 205 case Instruction::ZExt: 206 case Instruction::FPExt: 207 case Instruction::FPTrunc: 208 case Instruction::ExtractValue: 209 case Instruction::SIToFP: 210 case Instruction::UIToFP: 211 case Instruction::FPToSI: 212 case Instruction::FPToUI: 213 case Instruction::PtrToInt: 214 case Instruction::IntToPtr: 215 return R->getUnderlyingInstr()->getType(); 216 case Instruction::Freeze: 217 case Instruction::FNeg: 218 case Instruction::GetElementPtr: 219 return inferScalarType(R->getOperand(0)); 220 case Instruction::Load: 221 return cast<LoadInst>(R->getUnderlyingInstr())->getType(); 222 case Instruction::Store: 223 // FIXME: VPReplicateRecipes with store opcodes still define a result 224 // VPValue, so we need to handle them here. Remove the code here once this 225 // is modeled accurately in VPlan. 226 return Type::getVoidTy(Ctx); 227 default: 228 break; 229 } 230 // Type inference not implemented for opcode. 231 LLVM_DEBUG({ 232 dbgs() << "LV: Found unhandled opcode for: "; 233 R->getVPSingleValue()->dump(); 234 }); 235 llvm_unreachable("Unhandled opcode"); 236 } 237 238 Type *VPTypeAnalysis::inferScalarType(const VPValue *V) { 239 if (Type *CachedTy = CachedTypes.lookup(V)) 240 return CachedTy; 241 242 if (V->isLiveIn()) { 243 if (auto *IRValue = V->getLiveInIRValue()) 244 return IRValue->getType(); 245 // All VPValues without any underlying IR value (like the vector trip count 246 // or the backedge-taken count) have the same type as the canonical IV. 247 return CanonicalIVTy; 248 } 249 250 Type *ResultTy = 251 TypeSwitch<const VPRecipeBase *, Type *>(V->getDefiningRecipe()) 252 .Case<VPActiveLaneMaskPHIRecipe, VPCanonicalIVPHIRecipe, 253 VPFirstOrderRecurrencePHIRecipe, VPReductionPHIRecipe, 254 VPWidenPointerInductionRecipe, VPEVLBasedIVPHIRecipe>( 255 [this](const auto *R) { 256 // Handle header phi recipes, except VPWidenIntOrFpInduction 257 // which needs special handling due it being possibly truncated. 258 // TODO: consider inferring/caching type of siblings, e.g., 259 // backedge value, here and in cases below. 260 return inferScalarType(R->getStartValue()); 261 }) 262 .Case<VPWidenIntOrFpInductionRecipe, VPDerivedIVRecipe>( 263 [](const auto *R) { return R->getScalarType(); }) 264 .Case<VPReductionRecipe, VPPredInstPHIRecipe, VPWidenPHIRecipe, 265 VPScalarIVStepsRecipe, VPWidenGEPRecipe, VPVectorPointerRecipe, 266 VPReverseVectorPointerRecipe, VPWidenCanonicalIVRecipe>( 267 [this](const VPRecipeBase *R) { 268 return inferScalarType(R->getOperand(0)); 269 }) 270 .Case<VPBlendRecipe, VPInstruction, VPWidenRecipe, VPWidenEVLRecipe, 271 VPReplicateRecipe, VPWidenCallRecipe, VPWidenMemoryRecipe, 272 VPWidenSelectRecipe>( 273 [this](const auto *R) { return inferScalarTypeForRecipe(R); }) 274 .Case<VPWidenIntrinsicRecipe>([](const VPWidenIntrinsicRecipe *R) { 275 return R->getResultType(); 276 }) 277 .Case<VPInterleaveRecipe>([V](const VPInterleaveRecipe *R) { 278 // TODO: Use info from interleave group. 279 return V->getUnderlyingValue()->getType(); 280 }) 281 .Case<VPWidenCastRecipe>( 282 [](const VPWidenCastRecipe *R) { return R->getResultType(); }) 283 .Case<VPScalarCastRecipe>( 284 [](const VPScalarCastRecipe *R) { return R->getResultType(); }) 285 .Case<VPExpandSCEVRecipe>([](const VPExpandSCEVRecipe *R) { 286 return R->getSCEV()->getType(); 287 }) 288 .Case<VPReductionRecipe>([this](const auto *R) { 289 return inferScalarType(R->getChainOp()); 290 }); 291 292 assert(ResultTy && "could not infer type for the given VPValue"); 293 CachedTypes[V] = ResultTy; 294 return ResultTy; 295 } 296 297 void llvm::collectEphemeralRecipesForVPlan( 298 VPlan &Plan, DenseSet<VPRecipeBase *> &EphRecipes) { 299 // First, collect seed recipes which are operands of assumes. 300 SmallVector<VPRecipeBase *> Worklist; 301 for (VPBasicBlock *VPBB : VPBlockUtils::blocksOnly<VPBasicBlock>( 302 vp_depth_first_deep(Plan.getVectorLoopRegion()->getEntry()))) { 303 for (VPRecipeBase &R : *VPBB) { 304 auto *RepR = dyn_cast<VPReplicateRecipe>(&R); 305 if (!RepR || !match(RepR->getUnderlyingInstr(), 306 PatternMatch::m_Intrinsic<Intrinsic::assume>())) 307 continue; 308 Worklist.push_back(RepR); 309 EphRecipes.insert(RepR); 310 } 311 } 312 313 // Process operands of candidates in worklist and add them to the set of 314 // ephemeral recipes, if they don't have side-effects and are only used by 315 // other ephemeral recipes. 316 while (!Worklist.empty()) { 317 VPRecipeBase *Cur = Worklist.pop_back_val(); 318 for (VPValue *Op : Cur->operands()) { 319 auto *OpR = Op->getDefiningRecipe(); 320 if (!OpR || OpR->mayHaveSideEffects() || EphRecipes.contains(OpR)) 321 continue; 322 if (any_of(Op->users(), [EphRecipes](VPUser *U) { 323 auto *UR = dyn_cast<VPRecipeBase>(U); 324 return !UR || !EphRecipes.contains(UR); 325 })) 326 continue; 327 EphRecipes.insert(OpR); 328 Worklist.push_back(OpR); 329 } 330 } 331 } 332 333 template void DomTreeBuilder::Calculate<DominatorTreeBase<VPBlockBase, false>>( 334 DominatorTreeBase<VPBlockBase, false> &DT); 335 336 bool VPDominatorTree::properlyDominates(const VPRecipeBase *A, 337 const VPRecipeBase *B) { 338 if (A == B) 339 return false; 340 341 auto LocalComesBefore = [](const VPRecipeBase *A, const VPRecipeBase *B) { 342 for (auto &R : *A->getParent()) { 343 if (&R == A) 344 return true; 345 if (&R == B) 346 return false; 347 } 348 llvm_unreachable("recipe not found"); 349 }; 350 const VPBlockBase *ParentA = A->getParent(); 351 const VPBlockBase *ParentB = B->getParent(); 352 if (ParentA == ParentB) 353 return LocalComesBefore(A, B); 354 355 #ifndef NDEBUG 356 auto GetReplicateRegion = [](VPRecipeBase *R) -> VPRegionBlock * { 357 auto *Region = dyn_cast_or_null<VPRegionBlock>(R->getParent()->getParent()); 358 if (Region && Region->isReplicator()) { 359 assert(Region->getNumSuccessors() == 1 && 360 Region->getNumPredecessors() == 1 && "Expected SESE region!"); 361 assert(R->getParent()->size() == 1 && 362 "A recipe in an original replicator region must be the only " 363 "recipe in its block"); 364 return Region; 365 } 366 return nullptr; 367 }; 368 assert(!GetReplicateRegion(const_cast<VPRecipeBase *>(A)) && 369 "No replicate regions expected at this point"); 370 assert(!GetReplicateRegion(const_cast<VPRecipeBase *>(B)) && 371 "No replicate regions expected at this point"); 372 #endif 373 return Base::properlyDominates(ParentA, ParentB); 374 } 375