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
13using namespace llvm;
14
15#define DEBUG_TYPE "vplan"
16
17Type *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
28Type *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
68Type *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
113Type *VPTypeAnalysis::inferScalarTypeForRecipe(const VPWidenCallRecipe *R) {
114 auto &CI = *cast<CallInst>(Val: R->getUnderlyingInstr());
115 return CI.getType();
116}
117
118Type *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
124Type *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
133Type *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
211Type *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

source code of llvm/lib/Transforms/Vectorize/VPlanAnalysis.cpp