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