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 "llvm/ADT/TypeSwitch.h" 12 13 using namespace llvm; 14 15 #define DEBUG_TYPE "vplan" 16 17 Type *VPTypeAnalysis::inferScalarTypeForRecipe(const VPBlendRecipe *R) { 18 Type *ResTy = inferScalarType(R->getIncomingValue(0)); 19 for (unsigned I = 1, E = R->getNumIncomingValues(); I != E; ++I) { 20 VPValue *Inc = R->getIncomingValue(I); 21 assert(inferScalarType(Inc) == ResTy && 22 "different types inferred for different incoming values"); 23 CachedTypes[Inc] = ResTy; 24 } 25 return ResTy; 26 } 27 28 Type *VPTypeAnalysis::inferScalarTypeForRecipe(const VPInstruction *R) { 29 switch (R->getOpcode()) { 30 case Instruction::Select: { 31 Type *ResTy = inferScalarType(R->getOperand(1)); 32 VPValue *OtherV = R->getOperand(2); 33 assert(inferScalarType(OtherV) == ResTy && 34 "different types inferred for different operands"); 35 CachedTypes[OtherV] = ResTy; 36 return ResTy; 37 } 38 case Instruction::Or: 39 case Instruction::ICmp: 40 case VPInstruction::FirstOrderRecurrenceSplice: { 41 Type *ResTy = inferScalarType(R->getOperand(0)); 42 VPValue *OtherV = R->getOperand(1); 43 assert(inferScalarType(OtherV) == ResTy && 44 "different types inferred for different operands"); 45 CachedTypes[OtherV] = ResTy; 46 return ResTy; 47 } 48 case VPInstruction::ExtractFromEnd: { 49 Type *BaseTy = inferScalarType(R->getOperand(0)); 50 if (auto *VecTy = dyn_cast<VectorType>(BaseTy)) 51 return VecTy->getElementType(); 52 return BaseTy; 53 } 54 case VPInstruction::Not: { 55 Type *ResTy = inferScalarType(R->getOperand(0)); 56 assert(IntegerType::get(Ctx, 1) == ResTy && 57 "unexpected scalar type inferred for operand"); 58 return ResTy; 59 } 60 case VPInstruction::LogicalAnd: 61 return IntegerType::get(Ctx, 1); 62 case VPInstruction::PtrAdd: 63 // Return the type based on the pointer argument (i.e. first operand). 64 return inferScalarType(R->getOperand(0)); 65 default: 66 break; 67 } 68 // Type inference not implemented for opcode. 69 LLVM_DEBUG({ 70 dbgs() << "LV: Found unhandled opcode for: "; 71 R->getVPSingleValue()->dump(); 72 }); 73 llvm_unreachable("Unhandled opcode!"); 74 } 75 76 Type *VPTypeAnalysis::inferScalarTypeForRecipe(const VPWidenRecipe *R) { 77 unsigned Opcode = R->getOpcode(); 78 switch (Opcode) { 79 case Instruction::ICmp: 80 case Instruction::FCmp: 81 return IntegerType::get(Ctx, 1); 82 case Instruction::UDiv: 83 case Instruction::SDiv: 84 case Instruction::SRem: 85 case Instruction::URem: 86 case Instruction::Add: 87 case Instruction::FAdd: 88 case Instruction::Sub: 89 case Instruction::FSub: 90 case Instruction::Mul: 91 case Instruction::FMul: 92 case Instruction::FDiv: 93 case Instruction::FRem: 94 case Instruction::Shl: 95 case Instruction::LShr: 96 case Instruction::AShr: 97 case Instruction::And: 98 case Instruction::Or: 99 case Instruction::Xor: { 100 Type *ResTy = inferScalarType(R->getOperand(0)); 101 assert(ResTy == inferScalarType(R->getOperand(1)) && 102 "types for both operands must match for binary op"); 103 CachedTypes[R->getOperand(1)] = ResTy; 104 return ResTy; 105 } 106 case Instruction::FNeg: 107 case Instruction::Freeze: 108 return inferScalarType(R->getOperand(0)); 109 default: 110 break; 111 } 112 113 // Type inference not implemented for opcode. 114 LLVM_DEBUG({ 115 dbgs() << "LV: Found unhandled opcode for: "; 116 R->getVPSingleValue()->dump(); 117 }); 118 llvm_unreachable("Unhandled opcode!"); 119 } 120 121 Type *VPTypeAnalysis::inferScalarTypeForRecipe(const VPWidenCallRecipe *R) { 122 auto &CI = *cast<CallInst>(R->getUnderlyingInstr()); 123 return CI.getType(); 124 } 125 126 Type *VPTypeAnalysis::inferScalarTypeForRecipe(const VPWidenMemoryRecipe *R) { 127 assert((isa<VPWidenLoadRecipe>(R) || isa<VPWidenLoadEVLRecipe>(R)) && 128 "Store recipes should not define any values"); 129 return cast<LoadInst>(&R->getIngredient())->getType(); 130 } 131 132 Type *VPTypeAnalysis::inferScalarTypeForRecipe(const VPWidenSelectRecipe *R) { 133 Type *ResTy = inferScalarType(R->getOperand(1)); 134 VPValue *OtherV = R->getOperand(2); 135 assert(inferScalarType(OtherV) == ResTy && 136 "different types inferred for different operands"); 137 CachedTypes[OtherV] = ResTy; 138 return ResTy; 139 } 140 141 Type *VPTypeAnalysis::inferScalarTypeForRecipe(const VPReplicateRecipe *R) { 142 switch (R->getUnderlyingInstr()->getOpcode()) { 143 case Instruction::Call: { 144 unsigned CallIdx = R->getNumOperands() - (R->isPredicated() ? 2 : 1); 145 return cast<Function>(R->getOperand(CallIdx)->getLiveInIRValue()) 146 ->getReturnType(); 147 } 148 case Instruction::UDiv: 149 case Instruction::SDiv: 150 case Instruction::SRem: 151 case Instruction::URem: 152 case Instruction::Add: 153 case Instruction::FAdd: 154 case Instruction::Sub: 155 case Instruction::FSub: 156 case Instruction::Mul: 157 case Instruction::FMul: 158 case Instruction::FDiv: 159 case Instruction::FRem: 160 case Instruction::Shl: 161 case Instruction::LShr: 162 case Instruction::AShr: 163 case Instruction::And: 164 case Instruction::Or: 165 case Instruction::Xor: { 166 Type *ResTy = inferScalarType(R->getOperand(0)); 167 assert(ResTy == inferScalarType(R->getOperand(1)) && 168 "inferred types for operands of binary op don't match"); 169 CachedTypes[R->getOperand(1)] = ResTy; 170 return ResTy; 171 } 172 case Instruction::Select: { 173 Type *ResTy = inferScalarType(R->getOperand(1)); 174 assert(ResTy == inferScalarType(R->getOperand(2)) && 175 "inferred types for operands of select op don't match"); 176 CachedTypes[R->getOperand(2)] = ResTy; 177 return ResTy; 178 } 179 case Instruction::ICmp: 180 case Instruction::FCmp: 181 return IntegerType::get(Ctx, 1); 182 case Instruction::AddrSpaceCast: 183 case Instruction::Alloca: 184 case Instruction::BitCast: 185 case Instruction::Trunc: 186 case Instruction::SExt: 187 case Instruction::ZExt: 188 case Instruction::FPExt: 189 case Instruction::FPTrunc: 190 case Instruction::ExtractValue: 191 case Instruction::SIToFP: 192 case Instruction::UIToFP: 193 case Instruction::FPToSI: 194 case Instruction::FPToUI: 195 case Instruction::PtrToInt: 196 case Instruction::IntToPtr: 197 return R->getUnderlyingInstr()->getType(); 198 case Instruction::Freeze: 199 case Instruction::FNeg: 200 case Instruction::GetElementPtr: 201 return inferScalarType(R->getOperand(0)); 202 case Instruction::Load: 203 return cast<LoadInst>(R->getUnderlyingInstr())->getType(); 204 case Instruction::Store: 205 // FIXME: VPReplicateRecipes with store opcodes still define a result 206 // VPValue, so we need to handle them here. Remove the code here once this 207 // is modeled accurately in VPlan. 208 return Type::getVoidTy(Ctx); 209 default: 210 break; 211 } 212 // Type inference not implemented for opcode. 213 LLVM_DEBUG({ 214 dbgs() << "LV: Found unhandled opcode for: "; 215 R->getVPSingleValue()->dump(); 216 }); 217 llvm_unreachable("Unhandled opcode"); 218 } 219 220 Type *VPTypeAnalysis::inferScalarType(const VPValue *V) { 221 if (Type *CachedTy = CachedTypes.lookup(V)) 222 return CachedTy; 223 224 if (V->isLiveIn()) { 225 if (auto *IRValue = V->getLiveInIRValue()) 226 return IRValue->getType(); 227 // All VPValues without any underlying IR value (like the vector trip count 228 // or the backedge-taken count) have the same type as the canonical IV. 229 return CanonicalIVTy; 230 } 231 232 Type *ResultTy = 233 TypeSwitch<const VPRecipeBase *, Type *>(V->getDefiningRecipe()) 234 .Case<VPCanonicalIVPHIRecipe, VPFirstOrderRecurrencePHIRecipe, 235 VPReductionPHIRecipe, VPWidenPointerInductionRecipe, 236 VPEVLBasedIVPHIRecipe>([this](const auto *R) { 237 // Handle header phi recipes, except VPWidenIntOrFpInduction 238 // which needs special handling due it being possibly truncated. 239 // TODO: consider inferring/caching type of siblings, e.g., 240 // backedge value, here and in cases below. 241 return inferScalarType(R->getStartValue()); 242 }) 243 .Case<VPWidenIntOrFpInductionRecipe, VPDerivedIVRecipe>( 244 [](const auto *R) { return R->getScalarType(); }) 245 .Case<VPPredInstPHIRecipe, VPWidenPHIRecipe, VPScalarIVStepsRecipe, 246 VPWidenGEPRecipe>([this](const VPRecipeBase *R) { 247 return inferScalarType(R->getOperand(0)); 248 }) 249 .Case<VPBlendRecipe, VPInstruction, VPWidenRecipe, VPReplicateRecipe, 250 VPWidenCallRecipe, VPWidenMemoryRecipe, VPWidenSelectRecipe>( 251 [this](const auto *R) { return inferScalarTypeForRecipe(R); }) 252 .Case<VPInterleaveRecipe>([V](const VPInterleaveRecipe *R) { 253 // TODO: Use info from interleave group. 254 return V->getUnderlyingValue()->getType(); 255 }) 256 .Case<VPWidenCastRecipe>( 257 [](const VPWidenCastRecipe *R) { return R->getResultType(); }) 258 .Case<VPScalarCastRecipe>( 259 [](const VPScalarCastRecipe *R) { return R->getResultType(); }) 260 .Case<VPExpandSCEVRecipe>([](const VPExpandSCEVRecipe *R) { 261 return R->getSCEV()->getType(); 262 }); 263 264 assert(ResultTy && "could not infer type for the given VPValue"); 265 CachedTypes[V] = ResultTy; 266 return ResultTy; 267 } 268