1b1c73532SDimitry Andric //===- VPlanAnalysis.cpp - Various Analyses working on VPlan ----*- C++ -*-===//
2b1c73532SDimitry Andric //
3b1c73532SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4b1c73532SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5b1c73532SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6b1c73532SDimitry Andric //
7b1c73532SDimitry Andric //===----------------------------------------------------------------------===//
8b1c73532SDimitry Andric
9b1c73532SDimitry Andric #include "VPlanAnalysis.h"
10b1c73532SDimitry Andric #include "VPlan.h"
11ac9a064cSDimitry Andric #include "VPlanCFG.h"
12b1c73532SDimitry Andric #include "llvm/ADT/TypeSwitch.h"
13ac9a064cSDimitry Andric #include "llvm/IR/Instruction.h"
14ac9a064cSDimitry Andric #include "llvm/IR/PatternMatch.h"
15b1c73532SDimitry Andric
16b1c73532SDimitry Andric using namespace llvm;
17b1c73532SDimitry Andric
18b1c73532SDimitry Andric #define DEBUG_TYPE "vplan"
19b1c73532SDimitry Andric
inferScalarTypeForRecipe(const VPBlendRecipe * R)20b1c73532SDimitry Andric Type *VPTypeAnalysis::inferScalarTypeForRecipe(const VPBlendRecipe *R) {
21b1c73532SDimitry Andric Type *ResTy = inferScalarType(R->getIncomingValue(0));
22b1c73532SDimitry Andric for (unsigned I = 1, E = R->getNumIncomingValues(); I != E; ++I) {
23b1c73532SDimitry Andric VPValue *Inc = R->getIncomingValue(I);
24b1c73532SDimitry Andric assert(inferScalarType(Inc) == ResTy &&
25b1c73532SDimitry Andric "different types inferred for different incoming values");
26b1c73532SDimitry Andric CachedTypes[Inc] = ResTy;
27b1c73532SDimitry Andric }
28b1c73532SDimitry Andric return ResTy;
29b1c73532SDimitry Andric }
30b1c73532SDimitry Andric
inferScalarTypeForRecipe(const VPInstruction * R)31b1c73532SDimitry Andric Type *VPTypeAnalysis::inferScalarTypeForRecipe(const VPInstruction *R) {
32ac9a064cSDimitry Andric // Set the result type from the first operand, check if the types for all
33ac9a064cSDimitry Andric // other operands match and cache them.
34ac9a064cSDimitry Andric auto SetResultTyFromOp = [this, R]() {
35ac9a064cSDimitry Andric Type *ResTy = inferScalarType(R->getOperand(0));
36ac9a064cSDimitry Andric for (unsigned Op = 1; Op != R->getNumOperands(); ++Op) {
37ac9a064cSDimitry Andric VPValue *OtherV = R->getOperand(Op);
38ac9a064cSDimitry Andric assert(inferScalarType(OtherV) == ResTy &&
39ac9a064cSDimitry Andric "different types inferred for different operands");
40ac9a064cSDimitry Andric CachedTypes[OtherV] = ResTy;
41ac9a064cSDimitry Andric }
42ac9a064cSDimitry Andric return ResTy;
43ac9a064cSDimitry Andric };
44ac9a064cSDimitry Andric
45ac9a064cSDimitry Andric unsigned Opcode = R->getOpcode();
46ac9a064cSDimitry Andric if (Instruction::isBinaryOp(Opcode) || Instruction::isUnaryOp(Opcode))
47ac9a064cSDimitry Andric return SetResultTyFromOp();
48ac9a064cSDimitry Andric
49ac9a064cSDimitry Andric switch (Opcode) {
50b1c73532SDimitry Andric case Instruction::Select: {
51b1c73532SDimitry Andric Type *ResTy = inferScalarType(R->getOperand(1));
52b1c73532SDimitry Andric VPValue *OtherV = R->getOperand(2);
53b1c73532SDimitry Andric assert(inferScalarType(OtherV) == ResTy &&
54b1c73532SDimitry Andric "different types inferred for different operands");
55b1c73532SDimitry Andric CachedTypes[OtherV] = ResTy;
56b1c73532SDimitry Andric return ResTy;
57b1c73532SDimitry Andric }
58ac9a064cSDimitry Andric case Instruction::ICmp:
59ac9a064cSDimitry Andric case VPInstruction::ActiveLaneMask:
60ac9a064cSDimitry Andric return inferScalarType(R->getOperand(1));
61ac9a064cSDimitry Andric case VPInstruction::FirstOrderRecurrenceSplice:
62ac9a064cSDimitry Andric case VPInstruction::Not:
63ac9a064cSDimitry Andric return SetResultTyFromOp();
64ac9a064cSDimitry Andric case VPInstruction::ExtractFromEnd: {
65ac9a064cSDimitry Andric Type *BaseTy = inferScalarType(R->getOperand(0));
66ac9a064cSDimitry Andric if (auto *VecTy = dyn_cast<VectorType>(BaseTy))
67ac9a064cSDimitry Andric return VecTy->getElementType();
68ac9a064cSDimitry Andric return BaseTy;
69b1c73532SDimitry Andric }
70ac9a064cSDimitry Andric case VPInstruction::LogicalAnd:
71ac9a064cSDimitry Andric return IntegerType::get(Ctx, 1);
72ac9a064cSDimitry Andric case VPInstruction::PtrAdd:
73ac9a064cSDimitry Andric // Return the type based on the pointer argument (i.e. first operand).
74ac9a064cSDimitry Andric return inferScalarType(R->getOperand(0));
75ac9a064cSDimitry Andric case VPInstruction::BranchOnCond:
76ac9a064cSDimitry Andric case VPInstruction::BranchOnCount:
77ac9a064cSDimitry Andric return Type::getVoidTy(Ctx);
78b1c73532SDimitry Andric default:
79b1c73532SDimitry Andric break;
80b1c73532SDimitry Andric }
81b1c73532SDimitry Andric // Type inference not implemented for opcode.
82b1c73532SDimitry Andric LLVM_DEBUG({
83b1c73532SDimitry Andric dbgs() << "LV: Found unhandled opcode for: ";
84b1c73532SDimitry Andric R->getVPSingleValue()->dump();
85b1c73532SDimitry Andric });
86b1c73532SDimitry Andric llvm_unreachable("Unhandled opcode!");
87b1c73532SDimitry Andric }
88b1c73532SDimitry Andric
inferScalarTypeForRecipe(const VPWidenRecipe * R)89b1c73532SDimitry Andric Type *VPTypeAnalysis::inferScalarTypeForRecipe(const VPWidenRecipe *R) {
90b1c73532SDimitry Andric unsigned Opcode = R->getOpcode();
91b1c73532SDimitry Andric switch (Opcode) {
92b1c73532SDimitry Andric case Instruction::ICmp:
93b1c73532SDimitry Andric case Instruction::FCmp:
94b1c73532SDimitry Andric return IntegerType::get(Ctx, 1);
95b1c73532SDimitry Andric case Instruction::UDiv:
96b1c73532SDimitry Andric case Instruction::SDiv:
97b1c73532SDimitry Andric case Instruction::SRem:
98b1c73532SDimitry Andric case Instruction::URem:
99b1c73532SDimitry Andric case Instruction::Add:
100b1c73532SDimitry Andric case Instruction::FAdd:
101b1c73532SDimitry Andric case Instruction::Sub:
102b1c73532SDimitry Andric case Instruction::FSub:
103b1c73532SDimitry Andric case Instruction::Mul:
104b1c73532SDimitry Andric case Instruction::FMul:
105b1c73532SDimitry Andric case Instruction::FDiv:
106b1c73532SDimitry Andric case Instruction::FRem:
107b1c73532SDimitry Andric case Instruction::Shl:
108b1c73532SDimitry Andric case Instruction::LShr:
109b1c73532SDimitry Andric case Instruction::AShr:
110b1c73532SDimitry Andric case Instruction::And:
111b1c73532SDimitry Andric case Instruction::Or:
112b1c73532SDimitry Andric case Instruction::Xor: {
113b1c73532SDimitry Andric Type *ResTy = inferScalarType(R->getOperand(0));
114b1c73532SDimitry Andric assert(ResTy == inferScalarType(R->getOperand(1)) &&
115b1c73532SDimitry Andric "types for both operands must match for binary op");
116b1c73532SDimitry Andric CachedTypes[R->getOperand(1)] = ResTy;
117b1c73532SDimitry Andric return ResTy;
118b1c73532SDimitry Andric }
119b1c73532SDimitry Andric case Instruction::FNeg:
120b1c73532SDimitry Andric case Instruction::Freeze:
121b1c73532SDimitry Andric return inferScalarType(R->getOperand(0));
122b1c73532SDimitry Andric default:
123b1c73532SDimitry Andric break;
124b1c73532SDimitry Andric }
125b1c73532SDimitry Andric
126b1c73532SDimitry Andric // Type inference not implemented for opcode.
127b1c73532SDimitry Andric LLVM_DEBUG({
128b1c73532SDimitry Andric dbgs() << "LV: Found unhandled opcode for: ";
129b1c73532SDimitry Andric R->getVPSingleValue()->dump();
130b1c73532SDimitry Andric });
131b1c73532SDimitry Andric llvm_unreachable("Unhandled opcode!");
132b1c73532SDimitry Andric }
133b1c73532SDimitry Andric
inferScalarTypeForRecipe(const VPWidenCallRecipe * R)134b1c73532SDimitry Andric Type *VPTypeAnalysis::inferScalarTypeForRecipe(const VPWidenCallRecipe *R) {
135b1c73532SDimitry Andric auto &CI = *cast<CallInst>(R->getUnderlyingInstr());
136b1c73532SDimitry Andric return CI.getType();
137b1c73532SDimitry Andric }
138b1c73532SDimitry Andric
inferScalarTypeForRecipe(const VPWidenMemoryRecipe * R)139ac9a064cSDimitry Andric Type *VPTypeAnalysis::inferScalarTypeForRecipe(const VPWidenMemoryRecipe *R) {
140ac9a064cSDimitry Andric assert((isa<VPWidenLoadRecipe>(R) || isa<VPWidenLoadEVLRecipe>(R)) &&
141ac9a064cSDimitry Andric "Store recipes should not define any values");
142b1c73532SDimitry Andric return cast<LoadInst>(&R->getIngredient())->getType();
143b1c73532SDimitry Andric }
144b1c73532SDimitry Andric
inferScalarTypeForRecipe(const VPWidenSelectRecipe * R)145b1c73532SDimitry Andric Type *VPTypeAnalysis::inferScalarTypeForRecipe(const VPWidenSelectRecipe *R) {
146b1c73532SDimitry Andric Type *ResTy = inferScalarType(R->getOperand(1));
147b1c73532SDimitry Andric VPValue *OtherV = R->getOperand(2);
148b1c73532SDimitry Andric assert(inferScalarType(OtherV) == ResTy &&
149b1c73532SDimitry Andric "different types inferred for different operands");
150b1c73532SDimitry Andric CachedTypes[OtherV] = ResTy;
151b1c73532SDimitry Andric return ResTy;
152b1c73532SDimitry Andric }
153b1c73532SDimitry Andric
inferScalarTypeForRecipe(const VPReplicateRecipe * R)154b1c73532SDimitry Andric Type *VPTypeAnalysis::inferScalarTypeForRecipe(const VPReplicateRecipe *R) {
155b1c73532SDimitry Andric switch (R->getUnderlyingInstr()->getOpcode()) {
156b1c73532SDimitry Andric case Instruction::Call: {
157b1c73532SDimitry Andric unsigned CallIdx = R->getNumOperands() - (R->isPredicated() ? 2 : 1);
158b1c73532SDimitry Andric return cast<Function>(R->getOperand(CallIdx)->getLiveInIRValue())
159b1c73532SDimitry Andric ->getReturnType();
160b1c73532SDimitry Andric }
161b1c73532SDimitry Andric case Instruction::UDiv:
162b1c73532SDimitry Andric case Instruction::SDiv:
163b1c73532SDimitry Andric case Instruction::SRem:
164b1c73532SDimitry Andric case Instruction::URem:
165b1c73532SDimitry Andric case Instruction::Add:
166b1c73532SDimitry Andric case Instruction::FAdd:
167b1c73532SDimitry Andric case Instruction::Sub:
168b1c73532SDimitry Andric case Instruction::FSub:
169b1c73532SDimitry Andric case Instruction::Mul:
170b1c73532SDimitry Andric case Instruction::FMul:
171b1c73532SDimitry Andric case Instruction::FDiv:
172b1c73532SDimitry Andric case Instruction::FRem:
173b1c73532SDimitry Andric case Instruction::Shl:
174b1c73532SDimitry Andric case Instruction::LShr:
175b1c73532SDimitry Andric case Instruction::AShr:
176b1c73532SDimitry Andric case Instruction::And:
177b1c73532SDimitry Andric case Instruction::Or:
178b1c73532SDimitry Andric case Instruction::Xor: {
179b1c73532SDimitry Andric Type *ResTy = inferScalarType(R->getOperand(0));
180b1c73532SDimitry Andric assert(ResTy == inferScalarType(R->getOperand(1)) &&
181b1c73532SDimitry Andric "inferred types for operands of binary op don't match");
182b1c73532SDimitry Andric CachedTypes[R->getOperand(1)] = ResTy;
183b1c73532SDimitry Andric return ResTy;
184b1c73532SDimitry Andric }
185b1c73532SDimitry Andric case Instruction::Select: {
186b1c73532SDimitry Andric Type *ResTy = inferScalarType(R->getOperand(1));
187b1c73532SDimitry Andric assert(ResTy == inferScalarType(R->getOperand(2)) &&
188b1c73532SDimitry Andric "inferred types for operands of select op don't match");
189b1c73532SDimitry Andric CachedTypes[R->getOperand(2)] = ResTy;
190b1c73532SDimitry Andric return ResTy;
191b1c73532SDimitry Andric }
192b1c73532SDimitry Andric case Instruction::ICmp:
193b1c73532SDimitry Andric case Instruction::FCmp:
194b1c73532SDimitry Andric return IntegerType::get(Ctx, 1);
195ac9a064cSDimitry Andric case Instruction::AddrSpaceCast:
196b1c73532SDimitry Andric case Instruction::Alloca:
197b1c73532SDimitry Andric case Instruction::BitCast:
198b1c73532SDimitry Andric case Instruction::Trunc:
199b1c73532SDimitry Andric case Instruction::SExt:
200b1c73532SDimitry Andric case Instruction::ZExt:
201b1c73532SDimitry Andric case Instruction::FPExt:
202b1c73532SDimitry Andric case Instruction::FPTrunc:
203b1c73532SDimitry Andric case Instruction::ExtractValue:
204b1c73532SDimitry Andric case Instruction::SIToFP:
205b1c73532SDimitry Andric case Instruction::UIToFP:
206b1c73532SDimitry Andric case Instruction::FPToSI:
207b1c73532SDimitry Andric case Instruction::FPToUI:
208b1c73532SDimitry Andric case Instruction::PtrToInt:
209b1c73532SDimitry Andric case Instruction::IntToPtr:
210b1c73532SDimitry Andric return R->getUnderlyingInstr()->getType();
211b1c73532SDimitry Andric case Instruction::Freeze:
212b1c73532SDimitry Andric case Instruction::FNeg:
213b1c73532SDimitry Andric case Instruction::GetElementPtr:
214b1c73532SDimitry Andric return inferScalarType(R->getOperand(0));
215b1c73532SDimitry Andric case Instruction::Load:
216b1c73532SDimitry Andric return cast<LoadInst>(R->getUnderlyingInstr())->getType();
217b1c73532SDimitry Andric case Instruction::Store:
218b1c73532SDimitry Andric // FIXME: VPReplicateRecipes with store opcodes still define a result
219b1c73532SDimitry Andric // VPValue, so we need to handle them here. Remove the code here once this
220b1c73532SDimitry Andric // is modeled accurately in VPlan.
221b1c73532SDimitry Andric return Type::getVoidTy(Ctx);
222b1c73532SDimitry Andric default:
223b1c73532SDimitry Andric break;
224b1c73532SDimitry Andric }
225b1c73532SDimitry Andric // Type inference not implemented for opcode.
226b1c73532SDimitry Andric LLVM_DEBUG({
227b1c73532SDimitry Andric dbgs() << "LV: Found unhandled opcode for: ";
228b1c73532SDimitry Andric R->getVPSingleValue()->dump();
229b1c73532SDimitry Andric });
230b1c73532SDimitry Andric llvm_unreachable("Unhandled opcode");
231b1c73532SDimitry Andric }
232b1c73532SDimitry Andric
inferScalarType(const VPValue * V)233b1c73532SDimitry Andric Type *VPTypeAnalysis::inferScalarType(const VPValue *V) {
234b1c73532SDimitry Andric if (Type *CachedTy = CachedTypes.lookup(V))
235b1c73532SDimitry Andric return CachedTy;
236b1c73532SDimitry Andric
237ac9a064cSDimitry Andric if (V->isLiveIn()) {
238ac9a064cSDimitry Andric if (auto *IRValue = V->getLiveInIRValue())
239ac9a064cSDimitry Andric return IRValue->getType();
240ac9a064cSDimitry Andric // All VPValues without any underlying IR value (like the vector trip count
241ac9a064cSDimitry Andric // or the backedge-taken count) have the same type as the canonical IV.
242ac9a064cSDimitry Andric return CanonicalIVTy;
243ac9a064cSDimitry Andric }
244b1c73532SDimitry Andric
245b1c73532SDimitry Andric Type *ResultTy =
246b1c73532SDimitry Andric TypeSwitch<const VPRecipeBase *, Type *>(V->getDefiningRecipe())
247ac9a064cSDimitry Andric .Case<VPActiveLaneMaskPHIRecipe, VPCanonicalIVPHIRecipe,
248ac9a064cSDimitry Andric VPFirstOrderRecurrencePHIRecipe, VPReductionPHIRecipe,
249ac9a064cSDimitry Andric VPWidenPointerInductionRecipe, VPEVLBasedIVPHIRecipe>(
250b1c73532SDimitry Andric [this](const auto *R) {
251ac9a064cSDimitry Andric // Handle header phi recipes, except VPWidenIntOrFpInduction
252b1c73532SDimitry Andric // which needs special handling due it being possibly truncated.
253b1c73532SDimitry Andric // TODO: consider inferring/caching type of siblings, e.g.,
254b1c73532SDimitry Andric // backedge value, here and in cases below.
255b1c73532SDimitry Andric return inferScalarType(R->getStartValue());
256b1c73532SDimitry Andric })
257b1c73532SDimitry Andric .Case<VPWidenIntOrFpInductionRecipe, VPDerivedIVRecipe>(
258b1c73532SDimitry Andric [](const auto *R) { return R->getScalarType(); })
259ac9a064cSDimitry Andric .Case<VPReductionRecipe, VPPredInstPHIRecipe, VPWidenPHIRecipe,
260ac9a064cSDimitry Andric VPScalarIVStepsRecipe, VPWidenGEPRecipe, VPVectorPointerRecipe,
261ac9a064cSDimitry Andric VPWidenCanonicalIVRecipe>([this](const VPRecipeBase *R) {
262b1c73532SDimitry Andric return inferScalarType(R->getOperand(0));
263b1c73532SDimitry Andric })
264b1c73532SDimitry Andric .Case<VPBlendRecipe, VPInstruction, VPWidenRecipe, VPReplicateRecipe,
265ac9a064cSDimitry Andric VPWidenCallRecipe, VPWidenMemoryRecipe, VPWidenSelectRecipe>(
266b1c73532SDimitry Andric [this](const auto *R) { return inferScalarTypeForRecipe(R); })
267b1c73532SDimitry Andric .Case<VPInterleaveRecipe>([V](const VPInterleaveRecipe *R) {
268b1c73532SDimitry Andric // TODO: Use info from interleave group.
269b1c73532SDimitry Andric return V->getUnderlyingValue()->getType();
270b1c73532SDimitry Andric })
271b1c73532SDimitry Andric .Case<VPWidenCastRecipe>(
272ac9a064cSDimitry Andric [](const VPWidenCastRecipe *R) { return R->getResultType(); })
273ac9a064cSDimitry Andric .Case<VPScalarCastRecipe>(
274ac9a064cSDimitry Andric [](const VPScalarCastRecipe *R) { return R->getResultType(); })
275ac9a064cSDimitry Andric .Case<VPExpandSCEVRecipe>([](const VPExpandSCEVRecipe *R) {
276ac9a064cSDimitry Andric return R->getSCEV()->getType();
277ac9a064cSDimitry Andric })
278ac9a064cSDimitry Andric .Case<VPReductionRecipe>([this](const auto *R) {
279ac9a064cSDimitry Andric return inferScalarType(R->getChainOp());
280ac9a064cSDimitry Andric });
281ac9a064cSDimitry Andric
282b1c73532SDimitry Andric assert(ResultTy && "could not infer type for the given VPValue");
283b1c73532SDimitry Andric CachedTypes[V] = ResultTy;
284b1c73532SDimitry Andric return ResultTy;
285b1c73532SDimitry Andric }
286ac9a064cSDimitry Andric
collectEphemeralRecipesForVPlan(VPlan & Plan,DenseSet<VPRecipeBase * > & EphRecipes)287ac9a064cSDimitry Andric void llvm::collectEphemeralRecipesForVPlan(
288ac9a064cSDimitry Andric VPlan &Plan, DenseSet<VPRecipeBase *> &EphRecipes) {
289ac9a064cSDimitry Andric // First, collect seed recipes which are operands of assumes.
290ac9a064cSDimitry Andric SmallVector<VPRecipeBase *> Worklist;
291ac9a064cSDimitry Andric for (VPBasicBlock *VPBB : VPBlockUtils::blocksOnly<VPBasicBlock>(
292ac9a064cSDimitry Andric vp_depth_first_deep(Plan.getVectorLoopRegion()->getEntry()))) {
293ac9a064cSDimitry Andric for (VPRecipeBase &R : *VPBB) {
294ac9a064cSDimitry Andric auto *RepR = dyn_cast<VPReplicateRecipe>(&R);
295ac9a064cSDimitry Andric if (!RepR || !match(RepR->getUnderlyingInstr(),
296ac9a064cSDimitry Andric PatternMatch::m_Intrinsic<Intrinsic::assume>()))
297ac9a064cSDimitry Andric continue;
298ac9a064cSDimitry Andric Worklist.push_back(RepR);
299ac9a064cSDimitry Andric EphRecipes.insert(RepR);
300ac9a064cSDimitry Andric }
301ac9a064cSDimitry Andric }
302ac9a064cSDimitry Andric
303ac9a064cSDimitry Andric // Process operands of candidates in worklist and add them to the set of
304ac9a064cSDimitry Andric // ephemeral recipes, if they don't have side-effects and are only used by
305ac9a064cSDimitry Andric // other ephemeral recipes.
306ac9a064cSDimitry Andric while (!Worklist.empty()) {
307ac9a064cSDimitry Andric VPRecipeBase *Cur = Worklist.pop_back_val();
308ac9a064cSDimitry Andric for (VPValue *Op : Cur->operands()) {
309ac9a064cSDimitry Andric auto *OpR = Op->getDefiningRecipe();
310ac9a064cSDimitry Andric if (!OpR || OpR->mayHaveSideEffects() || EphRecipes.contains(OpR))
311ac9a064cSDimitry Andric continue;
312ac9a064cSDimitry Andric if (any_of(Op->users(), [EphRecipes](VPUser *U) {
313ac9a064cSDimitry Andric auto *UR = dyn_cast<VPRecipeBase>(U);
314ac9a064cSDimitry Andric return !UR || !EphRecipes.contains(UR);
315ac9a064cSDimitry Andric }))
316ac9a064cSDimitry Andric continue;
317ac9a064cSDimitry Andric EphRecipes.insert(OpR);
318ac9a064cSDimitry Andric Worklist.push_back(OpR);
319ac9a064cSDimitry Andric }
320ac9a064cSDimitry Andric }
321ac9a064cSDimitry Andric }
322