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