xref: /llvm-project/llvm/lib/Transforms/Vectorize/VPlanAnalysis.cpp (revision 59cb55d384a10e370ad5fdb2a8a48209e6bbc2bd)
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