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