1*c9157d92SDimitry Andric //===- VPlanAnalysis.cpp - Various Analyses working on VPlan ----*- C++ -*-===//
2*c9157d92SDimitry Andric //
3*c9157d92SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*c9157d92SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*c9157d92SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*c9157d92SDimitry Andric //
7*c9157d92SDimitry Andric //===----------------------------------------------------------------------===//
8*c9157d92SDimitry Andric
9*c9157d92SDimitry Andric #include "VPlanAnalysis.h"
10*c9157d92SDimitry Andric #include "VPlan.h"
11*c9157d92SDimitry Andric #include "llvm/ADT/TypeSwitch.h"
12*c9157d92SDimitry Andric
13*c9157d92SDimitry Andric using namespace llvm;
14*c9157d92SDimitry Andric
15*c9157d92SDimitry Andric #define DEBUG_TYPE "vplan"
16*c9157d92SDimitry Andric
inferScalarTypeForRecipe(const VPBlendRecipe * R)17*c9157d92SDimitry Andric Type *VPTypeAnalysis::inferScalarTypeForRecipe(const VPBlendRecipe *R) {
18*c9157d92SDimitry Andric Type *ResTy = inferScalarType(R->getIncomingValue(0));
19*c9157d92SDimitry Andric for (unsigned I = 1, E = R->getNumIncomingValues(); I != E; ++I) {
20*c9157d92SDimitry Andric VPValue *Inc = R->getIncomingValue(I);
21*c9157d92SDimitry Andric assert(inferScalarType(Inc) == ResTy &&
22*c9157d92SDimitry Andric "different types inferred for different incoming values");
23*c9157d92SDimitry Andric CachedTypes[Inc] = ResTy;
24*c9157d92SDimitry Andric }
25*c9157d92SDimitry Andric return ResTy;
26*c9157d92SDimitry Andric }
27*c9157d92SDimitry Andric
inferScalarTypeForRecipe(const VPInstruction * R)28*c9157d92SDimitry Andric Type *VPTypeAnalysis::inferScalarTypeForRecipe(const VPInstruction *R) {
29*c9157d92SDimitry Andric switch (R->getOpcode()) {
30*c9157d92SDimitry Andric case Instruction::Select: {
31*c9157d92SDimitry Andric Type *ResTy = inferScalarType(R->getOperand(1));
32*c9157d92SDimitry Andric VPValue *OtherV = R->getOperand(2);
33*c9157d92SDimitry Andric assert(inferScalarType(OtherV) == ResTy &&
34*c9157d92SDimitry Andric "different types inferred for different operands");
35*c9157d92SDimitry Andric CachedTypes[OtherV] = ResTy;
36*c9157d92SDimitry Andric return ResTy;
37*c9157d92SDimitry Andric }
38*c9157d92SDimitry Andric case VPInstruction::FirstOrderRecurrenceSplice: {
39*c9157d92SDimitry Andric Type *ResTy = inferScalarType(R->getOperand(0));
40*c9157d92SDimitry Andric VPValue *OtherV = R->getOperand(1);
41*c9157d92SDimitry Andric assert(inferScalarType(OtherV) == ResTy &&
42*c9157d92SDimitry Andric "different types inferred for different operands");
43*c9157d92SDimitry Andric CachedTypes[OtherV] = ResTy;
44*c9157d92SDimitry Andric return ResTy;
45*c9157d92SDimitry Andric }
46*c9157d92SDimitry Andric default:
47*c9157d92SDimitry Andric break;
48*c9157d92SDimitry Andric }
49*c9157d92SDimitry Andric // Type inference not implemented for opcode.
50*c9157d92SDimitry Andric LLVM_DEBUG({
51*c9157d92SDimitry Andric dbgs() << "LV: Found unhandled opcode for: ";
52*c9157d92SDimitry Andric R->getVPSingleValue()->dump();
53*c9157d92SDimitry Andric });
54*c9157d92SDimitry Andric llvm_unreachable("Unhandled opcode!");
55*c9157d92SDimitry Andric }
56*c9157d92SDimitry Andric
inferScalarTypeForRecipe(const VPWidenRecipe * R)57*c9157d92SDimitry Andric Type *VPTypeAnalysis::inferScalarTypeForRecipe(const VPWidenRecipe *R) {
58*c9157d92SDimitry Andric unsigned Opcode = R->getOpcode();
59*c9157d92SDimitry Andric switch (Opcode) {
60*c9157d92SDimitry Andric case Instruction::ICmp:
61*c9157d92SDimitry Andric case Instruction::FCmp:
62*c9157d92SDimitry Andric return IntegerType::get(Ctx, 1);
63*c9157d92SDimitry Andric case Instruction::UDiv:
64*c9157d92SDimitry Andric case Instruction::SDiv:
65*c9157d92SDimitry Andric case Instruction::SRem:
66*c9157d92SDimitry Andric case Instruction::URem:
67*c9157d92SDimitry Andric case Instruction::Add:
68*c9157d92SDimitry Andric case Instruction::FAdd:
69*c9157d92SDimitry Andric case Instruction::Sub:
70*c9157d92SDimitry Andric case Instruction::FSub:
71*c9157d92SDimitry Andric case Instruction::Mul:
72*c9157d92SDimitry Andric case Instruction::FMul:
73*c9157d92SDimitry Andric case Instruction::FDiv:
74*c9157d92SDimitry Andric case Instruction::FRem:
75*c9157d92SDimitry Andric case Instruction::Shl:
76*c9157d92SDimitry Andric case Instruction::LShr:
77*c9157d92SDimitry Andric case Instruction::AShr:
78*c9157d92SDimitry Andric case Instruction::And:
79*c9157d92SDimitry Andric case Instruction::Or:
80*c9157d92SDimitry Andric case Instruction::Xor: {
81*c9157d92SDimitry Andric Type *ResTy = inferScalarType(R->getOperand(0));
82*c9157d92SDimitry Andric assert(ResTy == inferScalarType(R->getOperand(1)) &&
83*c9157d92SDimitry Andric "types for both operands must match for binary op");
84*c9157d92SDimitry Andric CachedTypes[R->getOperand(1)] = ResTy;
85*c9157d92SDimitry Andric return ResTy;
86*c9157d92SDimitry Andric }
87*c9157d92SDimitry Andric case Instruction::FNeg:
88*c9157d92SDimitry Andric case Instruction::Freeze:
89*c9157d92SDimitry Andric return inferScalarType(R->getOperand(0));
90*c9157d92SDimitry Andric default:
91*c9157d92SDimitry Andric break;
92*c9157d92SDimitry Andric }
93*c9157d92SDimitry Andric
94*c9157d92SDimitry Andric // Type inference not implemented for opcode.
95*c9157d92SDimitry Andric LLVM_DEBUG({
96*c9157d92SDimitry Andric dbgs() << "LV: Found unhandled opcode for: ";
97*c9157d92SDimitry Andric R->getVPSingleValue()->dump();
98*c9157d92SDimitry Andric });
99*c9157d92SDimitry Andric llvm_unreachable("Unhandled opcode!");
100*c9157d92SDimitry Andric }
101*c9157d92SDimitry Andric
inferScalarTypeForRecipe(const VPWidenCallRecipe * R)102*c9157d92SDimitry Andric Type *VPTypeAnalysis::inferScalarTypeForRecipe(const VPWidenCallRecipe *R) {
103*c9157d92SDimitry Andric auto &CI = *cast<CallInst>(R->getUnderlyingInstr());
104*c9157d92SDimitry Andric return CI.getType();
105*c9157d92SDimitry Andric }
106*c9157d92SDimitry Andric
inferScalarTypeForRecipe(const VPWidenMemoryInstructionRecipe * R)107*c9157d92SDimitry Andric Type *VPTypeAnalysis::inferScalarTypeForRecipe(
108*c9157d92SDimitry Andric const VPWidenMemoryInstructionRecipe *R) {
109*c9157d92SDimitry Andric assert(!R->isStore() && "Store recipes should not define any values");
110*c9157d92SDimitry Andric return cast<LoadInst>(&R->getIngredient())->getType();
111*c9157d92SDimitry Andric }
112*c9157d92SDimitry Andric
inferScalarTypeForRecipe(const VPWidenSelectRecipe * R)113*c9157d92SDimitry Andric Type *VPTypeAnalysis::inferScalarTypeForRecipe(const VPWidenSelectRecipe *R) {
114*c9157d92SDimitry Andric Type *ResTy = inferScalarType(R->getOperand(1));
115*c9157d92SDimitry Andric VPValue *OtherV = R->getOperand(2);
116*c9157d92SDimitry Andric assert(inferScalarType(OtherV) == ResTy &&
117*c9157d92SDimitry Andric "different types inferred for different operands");
118*c9157d92SDimitry Andric CachedTypes[OtherV] = ResTy;
119*c9157d92SDimitry Andric return ResTy;
120*c9157d92SDimitry Andric }
121*c9157d92SDimitry Andric
inferScalarTypeForRecipe(const VPReplicateRecipe * R)122*c9157d92SDimitry Andric Type *VPTypeAnalysis::inferScalarTypeForRecipe(const VPReplicateRecipe *R) {
123*c9157d92SDimitry Andric switch (R->getUnderlyingInstr()->getOpcode()) {
124*c9157d92SDimitry Andric case Instruction::Call: {
125*c9157d92SDimitry Andric unsigned CallIdx = R->getNumOperands() - (R->isPredicated() ? 2 : 1);
126*c9157d92SDimitry Andric return cast<Function>(R->getOperand(CallIdx)->getLiveInIRValue())
127*c9157d92SDimitry Andric ->getReturnType();
128*c9157d92SDimitry Andric }
129*c9157d92SDimitry Andric case Instruction::UDiv:
130*c9157d92SDimitry Andric case Instruction::SDiv:
131*c9157d92SDimitry Andric case Instruction::SRem:
132*c9157d92SDimitry Andric case Instruction::URem:
133*c9157d92SDimitry Andric case Instruction::Add:
134*c9157d92SDimitry Andric case Instruction::FAdd:
135*c9157d92SDimitry Andric case Instruction::Sub:
136*c9157d92SDimitry Andric case Instruction::FSub:
137*c9157d92SDimitry Andric case Instruction::Mul:
138*c9157d92SDimitry Andric case Instruction::FMul:
139*c9157d92SDimitry Andric case Instruction::FDiv:
140*c9157d92SDimitry Andric case Instruction::FRem:
141*c9157d92SDimitry Andric case Instruction::Shl:
142*c9157d92SDimitry Andric case Instruction::LShr:
143*c9157d92SDimitry Andric case Instruction::AShr:
144*c9157d92SDimitry Andric case Instruction::And:
145*c9157d92SDimitry Andric case Instruction::Or:
146*c9157d92SDimitry Andric case Instruction::Xor: {
147*c9157d92SDimitry Andric Type *ResTy = inferScalarType(R->getOperand(0));
148*c9157d92SDimitry Andric assert(ResTy == inferScalarType(R->getOperand(1)) &&
149*c9157d92SDimitry Andric "inferred types for operands of binary op don't match");
150*c9157d92SDimitry Andric CachedTypes[R->getOperand(1)] = ResTy;
151*c9157d92SDimitry Andric return ResTy;
152*c9157d92SDimitry Andric }
153*c9157d92SDimitry Andric case Instruction::Select: {
154*c9157d92SDimitry Andric Type *ResTy = inferScalarType(R->getOperand(1));
155*c9157d92SDimitry Andric assert(ResTy == inferScalarType(R->getOperand(2)) &&
156*c9157d92SDimitry Andric "inferred types for operands of select op don't match");
157*c9157d92SDimitry Andric CachedTypes[R->getOperand(2)] = ResTy;
158*c9157d92SDimitry Andric return ResTy;
159*c9157d92SDimitry Andric }
160*c9157d92SDimitry Andric case Instruction::ICmp:
161*c9157d92SDimitry Andric case Instruction::FCmp:
162*c9157d92SDimitry Andric return IntegerType::get(Ctx, 1);
163*c9157d92SDimitry Andric case Instruction::Alloca:
164*c9157d92SDimitry Andric case Instruction::BitCast:
165*c9157d92SDimitry Andric case Instruction::Trunc:
166*c9157d92SDimitry Andric case Instruction::SExt:
167*c9157d92SDimitry Andric case Instruction::ZExt:
168*c9157d92SDimitry Andric case Instruction::FPExt:
169*c9157d92SDimitry Andric case Instruction::FPTrunc:
170*c9157d92SDimitry Andric case Instruction::ExtractValue:
171*c9157d92SDimitry Andric case Instruction::SIToFP:
172*c9157d92SDimitry Andric case Instruction::UIToFP:
173*c9157d92SDimitry Andric case Instruction::FPToSI:
174*c9157d92SDimitry Andric case Instruction::FPToUI:
175*c9157d92SDimitry Andric case Instruction::PtrToInt:
176*c9157d92SDimitry Andric case Instruction::IntToPtr:
177*c9157d92SDimitry Andric return R->getUnderlyingInstr()->getType();
178*c9157d92SDimitry Andric case Instruction::Freeze:
179*c9157d92SDimitry Andric case Instruction::FNeg:
180*c9157d92SDimitry Andric case Instruction::GetElementPtr:
181*c9157d92SDimitry Andric return inferScalarType(R->getOperand(0));
182*c9157d92SDimitry Andric case Instruction::Load:
183*c9157d92SDimitry Andric return cast<LoadInst>(R->getUnderlyingInstr())->getType();
184*c9157d92SDimitry Andric case Instruction::Store:
185*c9157d92SDimitry Andric // FIXME: VPReplicateRecipes with store opcodes still define a result
186*c9157d92SDimitry Andric // VPValue, so we need to handle them here. Remove the code here once this
187*c9157d92SDimitry Andric // is modeled accurately in VPlan.
188*c9157d92SDimitry Andric return Type::getVoidTy(Ctx);
189*c9157d92SDimitry Andric default:
190*c9157d92SDimitry Andric break;
191*c9157d92SDimitry Andric }
192*c9157d92SDimitry Andric // Type inference not implemented for opcode.
193*c9157d92SDimitry Andric LLVM_DEBUG({
194*c9157d92SDimitry Andric dbgs() << "LV: Found unhandled opcode for: ";
195*c9157d92SDimitry Andric R->getVPSingleValue()->dump();
196*c9157d92SDimitry Andric });
197*c9157d92SDimitry Andric llvm_unreachable("Unhandled opcode");
198*c9157d92SDimitry Andric }
199*c9157d92SDimitry Andric
inferScalarType(const VPValue * V)200*c9157d92SDimitry Andric Type *VPTypeAnalysis::inferScalarType(const VPValue *V) {
201*c9157d92SDimitry Andric if (Type *CachedTy = CachedTypes.lookup(V))
202*c9157d92SDimitry Andric return CachedTy;
203*c9157d92SDimitry Andric
204*c9157d92SDimitry Andric if (V->isLiveIn())
205*c9157d92SDimitry Andric return V->getLiveInIRValue()->getType();
206*c9157d92SDimitry Andric
207*c9157d92SDimitry Andric Type *ResultTy =
208*c9157d92SDimitry Andric TypeSwitch<const VPRecipeBase *, Type *>(V->getDefiningRecipe())
209*c9157d92SDimitry Andric .Case<VPCanonicalIVPHIRecipe, VPFirstOrderRecurrencePHIRecipe,
210*c9157d92SDimitry Andric VPReductionPHIRecipe, VPWidenPointerInductionRecipe>(
211*c9157d92SDimitry Andric [this](const auto *R) {
212*c9157d92SDimitry Andric // Handle header phi recipes, except VPWienIntOrFpInduction
213*c9157d92SDimitry Andric // which needs special handling due it being possibly truncated.
214*c9157d92SDimitry Andric // TODO: consider inferring/caching type of siblings, e.g.,
215*c9157d92SDimitry Andric // backedge value, here and in cases below.
216*c9157d92SDimitry Andric return inferScalarType(R->getStartValue());
217*c9157d92SDimitry Andric })
218*c9157d92SDimitry Andric .Case<VPWidenIntOrFpInductionRecipe, VPDerivedIVRecipe>(
219*c9157d92SDimitry Andric [](const auto *R) { return R->getScalarType(); })
220*c9157d92SDimitry Andric .Case<VPPredInstPHIRecipe, VPWidenPHIRecipe, VPScalarIVStepsRecipe,
221*c9157d92SDimitry Andric VPWidenGEPRecipe>([this](const VPRecipeBase *R) {
222*c9157d92SDimitry Andric return inferScalarType(R->getOperand(0));
223*c9157d92SDimitry Andric })
224*c9157d92SDimitry Andric .Case<VPBlendRecipe, VPInstruction, VPWidenRecipe, VPReplicateRecipe,
225*c9157d92SDimitry Andric VPWidenCallRecipe, VPWidenMemoryInstructionRecipe,
226*c9157d92SDimitry Andric VPWidenSelectRecipe>(
227*c9157d92SDimitry Andric [this](const auto *R) { return inferScalarTypeForRecipe(R); })
228*c9157d92SDimitry Andric .Case<VPInterleaveRecipe>([V](const VPInterleaveRecipe *R) {
229*c9157d92SDimitry Andric // TODO: Use info from interleave group.
230*c9157d92SDimitry Andric return V->getUnderlyingValue()->getType();
231*c9157d92SDimitry Andric })
232*c9157d92SDimitry Andric .Case<VPWidenCastRecipe>(
233*c9157d92SDimitry Andric [](const VPWidenCastRecipe *R) { return R->getResultType(); });
234*c9157d92SDimitry Andric assert(ResultTy && "could not infer type for the given VPValue");
235*c9157d92SDimitry Andric CachedTypes[V] = ResultTy;
236*c9157d92SDimitry Andric return ResultTy;
237*c9157d92SDimitry Andric }
238