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