LLVM 20.0.0git
VPlanAnalysis.cpp
Go to the documentation of this file.
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 "VPlanCFG.h"
12#include "llvm/ADT/TypeSwitch.h"
13#include "llvm/IR/Instruction.h"
15
16using namespace llvm;
17
18#define DEBUG_TYPE "vplan"
19
20Type *VPTypeAnalysis::inferScalarTypeForRecipe(const VPBlendRecipe *R) {
21 Type *ResTy = inferScalarType(R->getIncomingValue(0));
22 for (unsigned I = 1, E = R->getNumIncomingValues(); I != E; ++I) {
23 VPValue *Inc = R->getIncomingValue(I);
24 assert(inferScalarType(Inc) == ResTy &&
25 "different types inferred for different incoming values");
26 CachedTypes[Inc] = ResTy;
27 }
28 return ResTy;
29}
30
31Type *VPTypeAnalysis::inferScalarTypeForRecipe(const VPInstruction *R) {
32 // Set the result type from the first operand, check if the types for all
33 // other operands match and cache them.
34 auto SetResultTyFromOp = [this, R]() {
35 Type *ResTy = inferScalarType(R->getOperand(0));
36 for (unsigned Op = 1; Op != R->getNumOperands(); ++Op) {
37 VPValue *OtherV = R->getOperand(Op);
38 assert(inferScalarType(OtherV) == ResTy &&
39 "different types inferred for different operands");
40 CachedTypes[OtherV] = ResTy;
41 }
42 return ResTy;
43 };
44
45 unsigned Opcode = R->getOpcode();
47 return SetResultTyFromOp();
48
49 switch (Opcode) {
50 case Instruction::Select: {
51 Type *ResTy = inferScalarType(R->getOperand(1));
52 VPValue *OtherV = R->getOperand(2);
53 assert(inferScalarType(OtherV) == ResTy &&
54 "different types inferred for different operands");
55 CachedTypes[OtherV] = ResTy;
56 return ResTy;
57 }
58 case Instruction::ICmp:
60 return inferScalarType(R->getOperand(1));
63 return SetResultTyFromOp();
65 Type *BaseTy = inferScalarType(R->getOperand(0));
66 if (auto *VecTy = dyn_cast<VectorType>(BaseTy))
67 return VecTy->getElementType();
68 return BaseTy;
69 }
71 return IntegerType::get(Ctx, 1);
73 // Return the type based on the pointer argument (i.e. first operand).
74 return inferScalarType(R->getOperand(0));
77 return Type::getVoidTy(Ctx);
78 default:
79 break;
80 }
81 // Type inference not implemented for opcode.
83 dbgs() << "LV: Found unhandled opcode for: ";
84 R->getVPSingleValue()->dump();
85 });
86 llvm_unreachable("Unhandled opcode!");
87}
88
89Type *VPTypeAnalysis::inferScalarTypeForRecipe(const VPWidenRecipe *R) {
90 unsigned Opcode = R->getOpcode();
91 switch (Opcode) {
92 case Instruction::ICmp:
93 case Instruction::FCmp:
94 return IntegerType::get(Ctx, 1);
95 case Instruction::UDiv:
96 case Instruction::SDiv:
97 case Instruction::SRem:
98 case Instruction::URem:
99 case Instruction::Add:
100 case Instruction::FAdd:
101 case Instruction::Sub:
102 case Instruction::FSub:
103 case Instruction::Mul:
104 case Instruction::FMul:
105 case Instruction::FDiv:
106 case Instruction::FRem:
107 case Instruction::Shl:
108 case Instruction::LShr:
109 case Instruction::AShr:
110 case Instruction::And:
111 case Instruction::Or:
112 case Instruction::Xor: {
113 Type *ResTy = inferScalarType(R->getOperand(0));
114 assert(ResTy == inferScalarType(R->getOperand(1)) &&
115 "types for both operands must match for binary op");
116 CachedTypes[R->getOperand(1)] = ResTy;
117 return ResTy;
118 }
119 case Instruction::FNeg:
120 case Instruction::Freeze:
121 return inferScalarType(R->getOperand(0));
122 default:
123 break;
124 }
125
126 // Type inference not implemented for opcode.
127 LLVM_DEBUG({
128 dbgs() << "LV: Found unhandled opcode for: ";
129 R->getVPSingleValue()->dump();
130 });
131 llvm_unreachable("Unhandled opcode!");
132}
133
134Type *VPTypeAnalysis::inferScalarTypeForRecipe(const VPWidenCallRecipe *R) {
135 auto &CI = *cast<CallInst>(R->getUnderlyingInstr());
136 return CI.getType();
137}
138
139Type *VPTypeAnalysis::inferScalarTypeForRecipe(const VPWidenMemoryRecipe *R) {
140 assert((isa<VPWidenLoadRecipe>(R) || isa<VPWidenLoadEVLRecipe>(R)) &&
141 "Store recipes should not define any values");
142 return cast<LoadInst>(&R->getIngredient())->getType();
143}
144
145Type *VPTypeAnalysis::inferScalarTypeForRecipe(const VPWidenSelectRecipe *R) {
146 Type *ResTy = inferScalarType(R->getOperand(1));
147 VPValue *OtherV = R->getOperand(2);
148 assert(inferScalarType(OtherV) == ResTy &&
149 "different types inferred for different operands");
150 CachedTypes[OtherV] = ResTy;
151 return ResTy;
152}
153
154Type *VPTypeAnalysis::inferScalarTypeForRecipe(const VPReplicateRecipe *R) {
155 switch (R->getUnderlyingInstr()->getOpcode()) {
156 case Instruction::Call: {
157 unsigned CallIdx = R->getNumOperands() - (R->isPredicated() ? 2 : 1);
158 return cast<Function>(R->getOperand(CallIdx)->getLiveInIRValue())
159 ->getReturnType();
160 }
161 case Instruction::UDiv:
162 case Instruction::SDiv:
163 case Instruction::SRem:
164 case Instruction::URem:
165 case Instruction::Add:
166 case Instruction::FAdd:
167 case Instruction::Sub:
168 case Instruction::FSub:
169 case Instruction::Mul:
170 case Instruction::FMul:
171 case Instruction::FDiv:
172 case Instruction::FRem:
173 case Instruction::Shl:
174 case Instruction::LShr:
175 case Instruction::AShr:
176 case Instruction::And:
177 case Instruction::Or:
178 case Instruction::Xor: {
179 Type *ResTy = inferScalarType(R->getOperand(0));
180 assert(ResTy == inferScalarType(R->getOperand(1)) &&
181 "inferred types for operands of binary op don't match");
182 CachedTypes[R->getOperand(1)] = ResTy;
183 return ResTy;
184 }
185 case Instruction::Select: {
186 Type *ResTy = inferScalarType(R->getOperand(1));
187 assert(ResTy == inferScalarType(R->getOperand(2)) &&
188 "inferred types for operands of select op don't match");
189 CachedTypes[R->getOperand(2)] = ResTy;
190 return ResTy;
191 }
192 case Instruction::ICmp:
193 case Instruction::FCmp:
194 return IntegerType::get(Ctx, 1);
195 case Instruction::AddrSpaceCast:
196 case Instruction::Alloca:
197 case Instruction::BitCast:
198 case Instruction::Trunc:
199 case Instruction::SExt:
200 case Instruction::ZExt:
201 case Instruction::FPExt:
202 case Instruction::FPTrunc:
203 case Instruction::ExtractValue:
204 case Instruction::SIToFP:
205 case Instruction::UIToFP:
206 case Instruction::FPToSI:
207 case Instruction::FPToUI:
208 case Instruction::PtrToInt:
209 case Instruction::IntToPtr:
210 return R->getUnderlyingInstr()->getType();
211 case Instruction::Freeze:
212 case Instruction::FNeg:
213 case Instruction::GetElementPtr:
214 return inferScalarType(R->getOperand(0));
215 case Instruction::Load:
216 return cast<LoadInst>(R->getUnderlyingInstr())->getType();
217 case Instruction::Store:
218 // FIXME: VPReplicateRecipes with store opcodes still define a result
219 // VPValue, so we need to handle them here. Remove the code here once this
220 // is modeled accurately in VPlan.
221 return Type::getVoidTy(Ctx);
222 default:
223 break;
224 }
225 // Type inference not implemented for opcode.
226 LLVM_DEBUG({
227 dbgs() << "LV: Found unhandled opcode for: ";
228 R->getVPSingleValue()->dump();
229 });
230 llvm_unreachable("Unhandled opcode");
231}
232
234 if (Type *CachedTy = CachedTypes.lookup(V))
235 return CachedTy;
236
237 if (V->isLiveIn()) {
238 if (auto *IRValue = V->getLiveInIRValue())
239 return IRValue->getType();
240 // All VPValues without any underlying IR value (like the vector trip count
241 // or the backedge-taken count) have the same type as the canonical IV.
242 return CanonicalIVTy;
243 }
244
245 Type *ResultTy =
246 TypeSwitch<const VPRecipeBase *, Type *>(V->getDefiningRecipe())
250 [this](const auto *R) {
251 // Handle header phi recipes, except VPWidenIntOrFpInduction
252 // which needs special handling due it being possibly truncated.
253 // TODO: consider inferring/caching type of siblings, e.g.,
254 // backedge value, here and in cases below.
255 return inferScalarType(R->getStartValue());
256 })
257 .Case<VPWidenIntOrFpInductionRecipe, VPDerivedIVRecipe>(
258 [](const auto *R) { return R->getScalarType(); })
261 VPWidenCanonicalIVRecipe>([this](const VPRecipeBase *R) {
262 return inferScalarType(R->getOperand(0));
263 })
266 [this](const auto *R) { return inferScalarTypeForRecipe(R); })
267 .Case<VPInterleaveRecipe>([V](const VPInterleaveRecipe *R) {
268 // TODO: Use info from interleave group.
269 return V->getUnderlyingValue()->getType();
270 })
271 .Case<VPWidenCastRecipe>(
272 [](const VPWidenCastRecipe *R) { return R->getResultType(); })
273 .Case<VPScalarCastRecipe>(
274 [](const VPScalarCastRecipe *R) { return R->getResultType(); })
275 .Case<VPExpandSCEVRecipe>([](const VPExpandSCEVRecipe *R) {
276 return R->getSCEV()->getType();
277 })
278 .Case<VPReductionRecipe>([this](const auto *R) {
279 return inferScalarType(R->getChainOp());
280 });
281
282 assert(ResultTy && "could not infer type for the given VPValue");
283 CachedTypes[V] = ResultTy;
284 return ResultTy;
285}
286
288 VPlan &Plan, DenseSet<VPRecipeBase *> &EphRecipes) {
289 // First, collect seed recipes which are operands of assumes.
291 for (VPBasicBlock *VPBB : VPBlockUtils::blocksOnly<VPBasicBlock>(
293 for (VPRecipeBase &R : *VPBB) {
294 auto *RepR = dyn_cast<VPReplicateRecipe>(&R);
295 if (!RepR || !match(RepR->getUnderlyingInstr(),
296 PatternMatch::m_Intrinsic<Intrinsic::assume>()))
297 continue;
298 Worklist.push_back(RepR);
299 EphRecipes.insert(RepR);
300 }
301 }
302
303 // Process operands of candidates in worklist and add them to the set of
304 // ephemeral recipes, if they don't have side-effects and are only used by
305 // other ephemeral recipes.
306 while (!Worklist.empty()) {
307 VPRecipeBase *Cur = Worklist.pop_back_val();
308 for (VPValue *Op : Cur->operands()) {
309 auto *OpR = Op->getDefiningRecipe();
310 if (!OpR || OpR->mayHaveSideEffects() || EphRecipes.contains(OpR))
311 continue;
312 if (any_of(Op->users(), [EphRecipes](VPUser *U) {
313 auto *UR = dyn_cast<VPRecipeBase>(U);
314 return !UR || !EphRecipes.contains(UR);
315 }))
316 continue;
317 EphRecipes.insert(OpR);
318 Worklist.push_back(OpR);
319 }
320 }
321}
#define LLVM_DEBUG(X)
Definition: Debug.h:101
#define I(x, y, z)
Definition: MD5.cpp:58
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
This file implements the TypeSwitch template, which mimics a switch() statement whose cases are type ...
This file contains the declarations of the Vectorization Plan base classes:
This class represents an Operation in the Expression.
Implements a dense probed hash-table based set.
Definition: DenseSet.h:271
bool isBinaryOp() const
Definition: Instruction.h:279
bool isUnaryOp() const
Definition: Instruction.h:278
static IntegerType * get(LLVMContext &C, unsigned NumBits)
This static method is the primary way of constructing an IntegerType.
Definition: Type.cpp:266
bool empty() const
Definition: SmallVector.h:94
void push_back(const T &Elt)
Definition: SmallVector.h:426
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Definition: SmallVector.h:1209
This class implements a switch-like dispatch statement for a value of 'T' using dyn_cast functionalit...
Definition: TypeSwitch.h:87
TypeSwitch< T, ResultT > & Case(CallableT &&caseFn)
Add a case on the given type.
Definition: TypeSwitch.h:96
The instances of the Type class are immutable: once they are created, they are never changed.
Definition: Type.h:45
static Type * getVoidTy(LLVMContext &C)
A recipe for generating the active lane mask for the vector loop that is used to predicate the vector...
Definition: VPlan.h:2782
VPBasicBlock serves as the leaf of the Hierarchical Control-Flow Graph.
Definition: VPlan.h:2986
A recipe for vectorizing a phi-node as a sequence of mask-based select instructions.
Definition: VPlan.h:2041
Canonical scalar induction phi of the vector loop.
Definition: VPlan.h:2725
A recipe for generating the phi node for the current index of elements, adjusted in accordance with E...
Definition: VPlan.h:2814
Recipe to expand a SCEV expression.
Definition: VPlan.h:2693
This is a concrete Recipe that models a single VPlan-level instruction.
Definition: VPlan.h:1233
@ FirstOrderRecurrenceSplice
Definition: VPlan.h:1239
VPInterleaveRecipe is a recipe for transforming an interleave group of load or stores into one wide l...
Definition: VPlan.h:2098
VPPredInstPHIRecipe is a recipe for generating the phi nodes needed when control converges back from ...
Definition: VPlan.h:2428
VPRecipeBase is a base class modeling a sequence of one or more output IR instructions.
Definition: VPlan.h:766
A recipe for handling reduction phis.
Definition: VPlan.h:1982
A recipe to represent inloop reduction operations, performing a reduction on a vector operand into a ...
Definition: VPlan.h:2189
const VPBlockBase * getEntry() const
Definition: VPlan.h:3203
VPReplicateRecipe replicates a given instruction producing multiple scalar copies of the original sca...
Definition: VPlan.h:2304
VPScalarCastRecipe is a recipe to create scalar cast instructions.
Definition: VPlan.h:1495
A recipe for handling phi nodes of integer and floating-point inductions, producing their scalar valu...
Definition: VPlan.h:2936
Type * inferScalarType(const VPValue *V)
Infer the type of V. Returns the scalar type of V.
This class augments VPValue with operands which provide the inverse def-use edges from VPValue's user...
Definition: VPlanValue.h:202
operand_range operands()
Definition: VPlanValue.h:272
A recipe to compute the pointers for widened memory accesses of IndexTy for all parts.
Definition: VPlan.h:1663
A recipe for widening Call instructions.
Definition: VPlan.h:1534
A Recipe for widening the canonical induction variable of the vector loop.
Definition: VPlan.h:2850
VPWidenCastRecipe is a recipe to create vector cast instructions.
Definition: VPlan.h:1447
A recipe for handling GEP instructions.
Definition: VPlan.h:1621
A common base class for widening memory operations.
Definition: VPlan.h:2461
A recipe for handling phis that are widened in the vector loop.
Definition: VPlan.h:1910
VPWidenRecipe is a recipe for producing a widened instruction using the opcode and operands of the re...
Definition: VPlan.h:1410
VPlan models a candidate for vectorization, encoding various decisions take to produce efficient outp...
Definition: VPlan.h:3268
VPRegionBlock * getVectorLoopRegion()
Returns the VPRegionBlock of the vector loop.
Definition: VPlan.h:3470
std::pair< iterator, bool > insert(const ValueT &V)
Definition: DenseSet.h:206
bool contains(const_arg_type_t< ValueT > V) const
Check if the set contains the given element.
Definition: DenseSet.h:185
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
bool match(Val *V, const Pattern &P)
Definition: PatternMatch.h:49
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
iterator_range< df_iterator< VPBlockDeepTraversalWrapper< VPBlockBase * > > > vp_depth_first_deep(VPBlockBase *G)
Returns an iterator range to traverse the graph starting at G in depth-first order while traversing t...
Definition: VPlanCFG.h:226
bool any_of(R &&range, UnaryPredicate P)
Provide wrappers to std::any_of which take ranges instead of having to pass begin/end explicitly.
Definition: STLExtras.h:1729
void collectEphemeralRecipesForVPlan(VPlan &Plan, DenseSet< VPRecipeBase * > &EphRecipes)
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition: Debug.cpp:163
DWARFExpression::Operation Op
A recipe for handling first-order recurrence phis.
Definition: VPlan.h:1955
A recipe for widening select instructions.
Definition: VPlan.h:1587