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