Skip to content

Commit cdb42aa

Browse files
committed
[VPlan] Add initial anlysis to infer scalar type of VPValues.
This patch adds initial type inferrence for VPValues. It infers the scalar type of a VPValue, by bottom-up traversing through defining recipes until root nodes with known types are reached (e.g. live-ins or memory recipes). The types are then propagated top down through operations. This is intended as building block for a VPlan-based cost model, which will need access to type information for VPValues/recipes. Initial testing is done by asserting the inferred type matches the type of the result value generated for a widen recipe.
1 parent eab5d33 commit cdb42aa

File tree

5 files changed

+299
-3
lines changed

5 files changed

+299
-3
lines changed

llvm/lib/Transforms/Vectorize/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ add_llvm_component_library(LLVMVectorize
66
Vectorize.cpp
77
VectorCombine.cpp
88
VPlan.cpp
9+
VPlanAnalysis.cpp
910
VPlanHCFGBuilder.cpp
1011
VPlanRecipes.cpp
1112
VPlanSLP.cpp

llvm/lib/Transforms/Vectorize/VPlan.h

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1167,6 +1167,8 @@ class VPWidenRecipe : public VPRecipeWithIRFlags, public VPValue {
11671167
/// Produce widened copies of all Ingredients.
11681168
void execute(VPTransformState &State) override;
11691169

1170+
unsigned getOpcode() const { return Opcode; }
1171+
11701172
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
11711173
/// Print the recipe.
11721174
void print(raw_ostream &O, const Twine &Indent,
@@ -1458,7 +1460,7 @@ class VPWidenIntOrFpInductionRecipe : public VPHeaderPHIRecipe {
14581460
bool isCanonical() const;
14591461

14601462
/// Returns the scalar type of the induction.
1461-
const Type *getScalarType() const {
1463+
Type *getScalarType() const {
14621464
return Trunc ? Trunc->getType() : IV->getType();
14631465
}
14641466
};
@@ -2080,7 +2082,7 @@ class VPCanonicalIVPHIRecipe : public VPHeaderPHIRecipe {
20802082
#endif
20812083

20822084
/// Returns the scalar type of the induction.
2083-
const Type *getScalarType() const {
2085+
Type *getScalarType() const {
20842086
return getOperand(0)->getLiveInIRValue()->getType();
20852087
}
20862088

@@ -2149,7 +2151,7 @@ class VPWidenCanonicalIVRecipe : public VPRecipeBase, public VPValue {
21492151
#endif
21502152

21512153
/// Returns the scalar type of the induction.
2152-
const Type *getScalarType() const {
2154+
Type *getScalarType() const {
21532155
return cast<VPCanonicalIVPHIRecipe>(getOperand(0)->getDefiningRecipe())
21542156
->getScalarType();
21552157
}
Lines changed: 225 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,225 @@
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+
12+
using namespace llvm;
13+
14+
#define DEBUG_TYPE "vplan"
15+
16+
Type *VPTypeAnalysis::inferType(const VPBlendRecipe *R) {
17+
return inferType(R->getIncomingValue(0));
18+
}
19+
20+
Type *VPTypeAnalysis::inferType(const VPInstruction *R) {
21+
switch (R->getOpcode()) {
22+
case Instruction::Select:
23+
return inferType(R->getOperand(1));
24+
case VPInstruction::FirstOrderRecurrenceSplice:
25+
return inferType(R->getOperand(0));
26+
default:
27+
llvm_unreachable("Unhandled instruction!");
28+
}
29+
}
30+
31+
Type *VPTypeAnalysis::inferType(const VPInterleaveRecipe *R) { return nullptr; }
32+
33+
Type *VPTypeAnalysis::inferType(const VPReductionPHIRecipe *R) {
34+
return R->getOperand(0)->getLiveInIRValue()->getType();
35+
}
36+
37+
Type *VPTypeAnalysis::inferType(const VPWidenRecipe *R) {
38+
unsigned Opcode = R->getOpcode();
39+
switch (Opcode) {
40+
case Instruction::ICmp:
41+
case Instruction::FCmp:
42+
return IntegerType::get(Ctx, 1);
43+
case Instruction::UDiv:
44+
case Instruction::SDiv:
45+
case Instruction::SRem:
46+
case Instruction::URem:
47+
case Instruction::Add:
48+
case Instruction::FAdd:
49+
case Instruction::Sub:
50+
case Instruction::FSub:
51+
case Instruction::FNeg:
52+
case Instruction::Mul:
53+
case Instruction::FMul:
54+
case Instruction::FDiv:
55+
case Instruction::FRem:
56+
case Instruction::Shl:
57+
case Instruction::LShr:
58+
case Instruction::AShr:
59+
case Instruction::And:
60+
case Instruction::Or:
61+
case Instruction::Xor: {
62+
Type *ResTy = inferType(R->getOperand(0));
63+
if (Opcode != Instruction::FNeg) {
64+
assert(ResTy == inferType(R->getOperand(1)));
65+
CachedTypes[R->getOperand(1)] = ResTy;
66+
}
67+
return ResTy;
68+
}
69+
case Instruction::Freeze:
70+
return inferType(R->getOperand(0));
71+
default:
72+
// This instruction is not vectorized by simple widening.
73+
// LLVM_DEBUG(dbgs() << "LV: Found an unhandled instruction: " << I);
74+
llvm_unreachable("Unhandled instruction!");
75+
}
76+
77+
return nullptr;
78+
}
79+
80+
Type *VPTypeAnalysis::inferType(const VPWidenCallRecipe *R) {
81+
auto &CI = *cast<CallInst>(R->getUnderlyingInstr());
82+
return CI.getType();
83+
}
84+
85+
Type *VPTypeAnalysis::inferType(const VPWidenIntOrFpInductionRecipe *R) {
86+
return R->getScalarType();
87+
}
88+
89+
Type *VPTypeAnalysis::inferType(const VPWidenMemoryInstructionRecipe *R) {
90+
if (R->isStore())
91+
return cast<StoreInst>(&R->getIngredient())->getValueOperand()->getType();
92+
93+
return cast<LoadInst>(&R->getIngredient())->getType();
94+
}
95+
96+
Type *VPTypeAnalysis::inferType(const VPWidenSelectRecipe *R) {
97+
return inferType(R->getOperand(1));
98+
}
99+
100+
Type *VPTypeAnalysis::inferType(const VPReplicateRecipe *R) {
101+
switch (R->getUnderlyingInstr()->getOpcode()) {
102+
case Instruction::Call: {
103+
unsigned CallIdx = R->getNumOperands() - (R->isPredicated() ? 2 : 1);
104+
return cast<Function>(R->getOperand(CallIdx)->getLiveInIRValue())
105+
->getReturnType();
106+
}
107+
case Instruction::UDiv:
108+
case Instruction::SDiv:
109+
case Instruction::SRem:
110+
case Instruction::URem:
111+
case Instruction::Add:
112+
case Instruction::FAdd:
113+
case Instruction::Sub:
114+
case Instruction::FSub:
115+
case Instruction::FNeg:
116+
case Instruction::Mul:
117+
case Instruction::FMul:
118+
case Instruction::FDiv:
119+
case Instruction::FRem:
120+
case Instruction::Shl:
121+
case Instruction::LShr:
122+
case Instruction::AShr:
123+
case Instruction::And:
124+
case Instruction::Or:
125+
case Instruction::Xor:
126+
case Instruction::ICmp:
127+
case Instruction::FCmp: {
128+
Type *ResTy = inferType(R->getOperand(0));
129+
assert(ResTy == inferType(R->getOperand(1)));
130+
CachedTypes[R->getOperand(1)] = ResTy;
131+
return ResTy;
132+
}
133+
case Instruction::Trunc:
134+
case Instruction::SExt:
135+
case Instruction::ZExt:
136+
case Instruction::FPExt:
137+
case Instruction::FPTrunc:
138+
return R->getUnderlyingInstr()->getType();
139+
case Instruction::ExtractValue: {
140+
return R->getUnderlyingValue()->getType();
141+
}
142+
case Instruction::Freeze:
143+
return inferType(R->getOperand(0));
144+
case Instruction::Load:
145+
return cast<LoadInst>(R->getUnderlyingInstr())->getType();
146+
case Instruction::Store:
147+
return cast<StoreInst>(R->getUnderlyingInstr())
148+
->getValueOperand()
149+
->getType();
150+
default:
151+
llvm_unreachable("Unhandled instruction");
152+
}
153+
154+
return nullptr;
155+
}
156+
157+
Type *VPTypeAnalysis::inferType(const VPValue *V) {
158+
auto Iter = CachedTypes.find(V);
159+
if (Iter != CachedTypes.end())
160+
return Iter->second;
161+
162+
Type *ResultTy = nullptr;
163+
if (V->isLiveIn())
164+
ResultTy = V->getLiveInIRValue()->getType();
165+
else {
166+
const VPRecipeBase *Def = V->getDefiningRecipe();
167+
switch (Def->getVPDefID()) {
168+
case VPDef::VPBlendSC:
169+
ResultTy = inferType(cast<VPBlendRecipe>(Def));
170+
break;
171+
case VPDef::VPCanonicalIVPHISC:
172+
ResultTy = cast<VPCanonicalIVPHIRecipe>(Def)->getScalarType();
173+
break;
174+
case VPDef::VPFirstOrderRecurrencePHISC:
175+
ResultTy = Def->getOperand(0)->getLiveInIRValue()->getType();
176+
break;
177+
case VPDef::VPInstructionSC:
178+
ResultTy = inferType(cast<VPInstruction>(Def));
179+
break;
180+
case VPDef::VPInterleaveSC:
181+
ResultTy = V->getUnderlyingValue()
182+
->getType(); // inferType(cast<VPInterleaveRecipe>(Def));
183+
break;
184+
case VPDef::VPPredInstPHISC:
185+
ResultTy = inferType(Def->getOperand(0));
186+
break;
187+
case VPDef::VPReductionPHISC:
188+
ResultTy = inferType(cast<VPReductionPHIRecipe>(Def));
189+
break;
190+
case VPDef::VPReplicateSC:
191+
ResultTy = inferType(cast<VPReplicateRecipe>(Def));
192+
break;
193+
case VPDef::VPScalarIVStepsSC:
194+
return inferType(Def->getOperand(0));
195+
break;
196+
case VPDef::VPWidenSC:
197+
ResultTy = inferType(cast<VPWidenRecipe>(Def));
198+
break;
199+
case VPDef::VPWidenPHISC:
200+
return inferType(Def->getOperand(0));
201+
case VPDef::VPWidenPointerInductionSC:
202+
return inferType(Def->getOperand(0));
203+
case VPDef::VPWidenCallSC:
204+
ResultTy = inferType(cast<VPWidenCallRecipe>(Def));
205+
break;
206+
case VPDef::VPWidenCastSC:
207+
ResultTy = cast<VPWidenCastRecipe>(Def)->getResultType();
208+
break;
209+
case VPDef::VPWidenGEPSC:
210+
ResultTy = PointerType::get(Ctx, 0);
211+
break;
212+
case VPDef::VPWidenIntOrFpInductionSC:
213+
ResultTy = inferType(cast<VPWidenIntOrFpInductionRecipe>(Def));
214+
break;
215+
case VPDef::VPWidenMemoryInstructionSC:
216+
ResultTy = inferType(cast<VPWidenMemoryInstructionRecipe>(Def));
217+
break;
218+
case VPDef::VPWidenSelectSC:
219+
ResultTy = inferType(cast<VPWidenSelectRecipe>(Def));
220+
break;
221+
}
222+
}
223+
CachedTypes[V] = ResultTy;
224+
return ResultTy;
225+
}
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
//===- VPlanAnalysis.h - 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+
#ifndef LLVM_TRANSFORMS_VECTORIZE_VPLANANALYSIS_H
10+
#define LLVM_TRANSFORMS_VECTORIZE_VPLANANALYSIS_H
11+
12+
#include "llvm/ADT/DenseMap.h"
13+
14+
namespace llvm {
15+
16+
class LLVMContext;
17+
class VPValue;
18+
class VPBlendRecipe;
19+
class VPInterleaveRecipe;
20+
class VPInstruction;
21+
class VPReductionPHIRecipe;
22+
class VPWidenRecipe;
23+
class VPWidenCallRecipe;
24+
class VPWidenCastRecipe;
25+
class VPWidenIntOrFpInductionRecipe;
26+
class VPWidenMemoryInstructionRecipe;
27+
struct VPWidenSelectRecipe;
28+
class VPReplicateRecipe;
29+
class Type;
30+
31+
/// An analysis for type-inferrence for VPValues.
32+
class VPTypeAnalysis {
33+
DenseMap<const VPValue *, Type *> CachedTypes;
34+
LLVMContext &Ctx;
35+
36+
Type *inferType(const VPBlendRecipe *R);
37+
Type *inferType(const VPInstruction *R);
38+
Type *inferType(const VPInterleaveRecipe *R);
39+
Type *inferType(const VPWidenCallRecipe *R);
40+
Type *inferType(const VPReductionPHIRecipe *R);
41+
Type *inferType(const VPWidenRecipe *R);
42+
Type *inferType(const VPWidenIntOrFpInductionRecipe *R);
43+
Type *inferType(const VPWidenMemoryInstructionRecipe *R);
44+
Type *inferType(const VPWidenSelectRecipe *R);
45+
Type *inferType(const VPReplicateRecipe *R);
46+
47+
public:
48+
VPTypeAnalysis(LLVMContext &Ctx) : Ctx(Ctx) {}
49+
50+
/// Infer the type of \p V. Returns the scalar type of \p V.
51+
Type *inferType(const VPValue *V);
52+
};
53+
54+
} // end namespace llvm
55+
56+
#endif // LLVM_TRANSFORMS_VECTORIZE_VPLANANALYSIS_H

llvm/lib/Transforms/Vectorize/VPlanRecipes.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
//===----------------------------------------------------------------------===//
1313

1414
#include "VPlan.h"
15+
#include "VPlanAnalysis.h"
1516
#include "llvm/ADT/STLExtras.h"
1617
#include "llvm/ADT/SmallVector.h"
1718
#include "llvm/ADT/Twine.h"
@@ -738,7 +739,18 @@ void VPWidenRecipe::execute(VPTransformState &State) {
738739
<< Instruction::getOpcodeName(Opcode));
739740
llvm_unreachable("Unhandled instruction!");
740741
} // end of switch.
742+
743+
#if !defined(NDEBUG)
744+
// Verify that VPlan type infererrence results agree with the type of the
745+
// generated values.
746+
VPTypeAnalysis A(State.Builder.GetInsertBlock()->getContext());
747+
for (unsigned Part = 0; Part < State.UF; ++Part) {
748+
assert(VectorType::get(A.inferType(getVPSingleValue()), State.VF) ==
749+
State.get(this, Part)->getType());
750+
}
751+
#endif
741752
}
753+
742754
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
743755
void VPWidenRecipe::print(raw_ostream &O, const Twine &Indent,
744756
VPSlotTracker &SlotTracker) const {

0 commit comments

Comments
 (0)