Skip to content
This repository was archived by the owner on Mar 28, 2020. It is now read-only.

Commit b838c5c

Browse files
committed
[VPlan] Add VPInstruction to VPRecipe transformation.
This patch introduces a VPInstructionToVPRecipe transformation, which allows us to generate code for a VPInstruction based VPlan re-using the existing infrastructure. Reviewers: dcaballe, hsaito, mssimpso, hfinkel, rengolin, mkuper, javed.absar, sguggill Reviewed By: dcaballe Differential Revision: https://reviews.llvm.org/D46827 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@334969 91177308-0d34-0410-b5e6-96231b3b80d8
1 parent 6979160 commit b838c5c

File tree

6 files changed

+292
-0
lines changed

6 files changed

+292
-0
lines changed

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_library(LLVMVectorize
66
Vectorize.cpp
77
VPlan.cpp
88
VPlanHCFGBuilder.cpp
9+
VPlanHCFGTransforms.cpp
910
VPlanVerifier.cpp
1011

1112
ADDITIONAL_HEADER_DIRS

lib/Transforms/Vectorize/VPlan.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -568,6 +568,8 @@ class VPRecipeBase : public ilist_node_with_parent<VPRecipeBase, VPBasicBlock> {
568568
/// executed, these instructions would always form a single-def expression as
569569
/// the VPInstruction is also a single def-use vertex.
570570
class VPInstruction : public VPUser, public VPRecipeBase {
571+
friend class VPlanHCFGTransforms;
572+
571573
public:
572574
/// VPlan opcodes, extending LLVM IR with idiomatics instructions.
573575
enum { Not = Instruction::OtherOpsEnd + 1 };
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
//===-- VPlanHCFGTransforms.cpp - Utility VPlan to VPlan transforms -------===//
2+
//
3+
// The LLVM Compiler Infrastructure
4+
//
5+
// This file is distributed under the University of Illinois Open Source
6+
// License. See LICENSE.TXT for details.
7+
//
8+
//===----------------------------------------------------------------------===//
9+
///
10+
/// \file
11+
/// This file implements a set of utility VPlan to VPlan transformations.
12+
///
13+
//===----------------------------------------------------------------------===//
14+
15+
#include "VPlanHCFGTransforms.h"
16+
#include "llvm/ADT/PostOrderIterator.h"
17+
18+
using namespace llvm;
19+
20+
void VPlanHCFGTransforms::VPInstructionsToVPRecipes(
21+
VPlanPtr &Plan,
22+
LoopVectorizationLegality::InductionList *Inductions,
23+
SmallPtrSetImpl<Instruction *> &DeadInstructions) {
24+
25+
VPRegionBlock *TopRegion = dyn_cast<VPRegionBlock>(Plan->getEntry());
26+
ReversePostOrderTraversal<VPBlockBase *> RPOT(TopRegion->getEntry());
27+
for (VPBlockBase *Base : RPOT) {
28+
// Do not widen instructions in pre-header and exit blocks.
29+
if (Base->getNumPredecessors() == 0 || Base->getNumSuccessors() == 0)
30+
continue;
31+
32+
VPBasicBlock *VPBB = Base->getEntryBasicBlock();
33+
VPRecipeBase *LastRecipe = nullptr;
34+
// Introduce each ingredient into VPlan.
35+
for (auto I = VPBB->begin(), E = VPBB->end(); I != E;) {
36+
VPRecipeBase *Ingredient = &*I++;
37+
// Can only handle VPInstructions.
38+
VPInstruction *VPInst = cast<VPInstruction>(Ingredient);
39+
Instruction *Inst = cast<Instruction>(VPInst->getUnderlyingValue());
40+
if (DeadInstructions.count(Inst)) {
41+
Ingredient->eraseFromParent();
42+
continue;
43+
}
44+
45+
VPRecipeBase *NewRecipe = nullptr;
46+
// Create VPWidenMemoryInstructionRecipe for loads and stores.
47+
if (isa<LoadInst>(Inst) || isa<StoreInst>(Inst))
48+
NewRecipe = new VPWidenMemoryInstructionRecipe(*Inst, nullptr /*Mask*/);
49+
else if (PHINode *Phi = dyn_cast<PHINode>(Inst)) {
50+
InductionDescriptor II = Inductions->lookup(Phi);
51+
if (II.getKind() == InductionDescriptor::IK_IntInduction ||
52+
II.getKind() == InductionDescriptor::IK_FpInduction) {
53+
NewRecipe = new VPWidenIntOrFpInductionRecipe(Phi);
54+
} else
55+
NewRecipe = new VPWidenPHIRecipe(Phi);
56+
} else {
57+
// If the last recipe is a VPWidenRecipe, add Inst to it instead of
58+
// creating a new recipe.
59+
if (VPWidenRecipe *WidenRecipe =
60+
dyn_cast_or_null<VPWidenRecipe>(LastRecipe)) {
61+
WidenRecipe->appendInstruction(Inst);
62+
Ingredient->eraseFromParent();
63+
continue;
64+
}
65+
NewRecipe = new VPWidenRecipe(Inst);
66+
}
67+
68+
NewRecipe->insertBefore(Ingredient);
69+
LastRecipe = NewRecipe;
70+
Ingredient->eraseFromParent();
71+
}
72+
}
73+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
//===- VPlanHCFGTransforms.h - Utility VPlan to VPlan transforms ----------===//
2+
//
3+
// The LLVM Compiler Infrastructure
4+
//
5+
// This file is distributed under the University of Illinois Open Source
6+
// License. See LICENSE.TXT for details.
7+
//
8+
//===----------------------------------------------------------------------===//
9+
///
10+
/// \file
11+
/// This file provides utility VPlan to VPlan transformations.
12+
//===----------------------------------------------------------------------===//
13+
14+
#ifndef LLVM_TRANSFORMS_VECTORIZE_VPLANHCFGTRANSFORMS_H
15+
#define LLVM_TRANSFORMS_VECTORIZE_VPLANHCFGTRANSFORMS_H
16+
17+
#include "VPlan.h"
18+
#include "llvm/IR/Instruction.h"
19+
#include "llvm/Transforms/Vectorize/LoopVectorizationLegality.h"
20+
21+
namespace llvm {
22+
23+
class VPlanHCFGTransforms {
24+
25+
public:
26+
/// Replaces the VPInstructions in \p Plan with corresponding
27+
/// widen recipes.
28+
static void VPInstructionsToVPRecipes(
29+
VPlanPtr &Plan,
30+
LoopVectorizationLegality::InductionList *Inductions,
31+
SmallPtrSetImpl<Instruction *> &DeadInstructions);
32+
};
33+
34+
} // namespace llvm
35+
36+
#endif // LLVM_TRANSFORMS_VECTORIZE_VPLANHCFGTRANSFORMS_H
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
set(LLVM_LINK_COMPONENTS
22
Vectorize
3+
AsmParser
34
)
45

56
add_llvm_unittest(VectorizeTests
67
VPlanTest.cpp
8+
VPlanHCFGTest.cpp
79
)
Lines changed: 178 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,178 @@
1+
//===- llvm/unittest/Transforms/Vectorize/VPlanHCFGTest.cpp ---------------===//
2+
//
3+
// The LLVM Compiler Infrastructure
4+
//
5+
// This file is distributed under the University of Illinois Open Source
6+
// License. See LICENSE.TXT for details.
7+
//
8+
//===----------------------------------------------------------------------===//
9+
10+
#include "../lib/Transforms/Vectorize/VPlan.h"
11+
#include "../lib/Transforms/Vectorize/VPlanHCFGBuilder.h"
12+
#include "../lib/Transforms/Vectorize/VPlanHCFGTransforms.h"
13+
#include "llvm/AsmParser/Parser.h"
14+
#include "llvm/IR/Dominators.h"
15+
#include "gtest/gtest.h"
16+
17+
namespace llvm {
18+
namespace {
19+
20+
class VPlanHCFGTest : public testing::Test {
21+
protected:
22+
std::unique_ptr<DominatorTree> DT;
23+
std::unique_ptr<LoopInfo> LI;
24+
25+
VPlanHCFGTest() {}
26+
27+
VPlanPtr doBuildPlan(BasicBlock *LoopHeader) {
28+
DT.reset(new DominatorTree(*LoopHeader->getParent()));
29+
LI.reset(new LoopInfo(*DT));
30+
31+
auto Plan = llvm::make_unique<VPlan>();
32+
VPlanHCFGBuilder HCFGBuilder(LI->getLoopFor(LoopHeader), LI.get());
33+
HCFGBuilder.buildHierarchicalCFG(*Plan.get());
34+
return Plan;
35+
}
36+
};
37+
38+
TEST_F(VPlanHCFGTest, testBuildHCFGInnerLoop) {
39+
LLVMContext Ctx;
40+
const char *ModuleString =
41+
"define void @f(i32* %A, i64 %N) {\n"
42+
"entry:\n"
43+
" br label %for.body\n"
44+
"for.body:\n"
45+
" %indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %for.body ]\n"
46+
" %arr.idx = getelementptr inbounds i32, i32* %A, i64 %indvars.iv\n"
47+
" %l1 = load i32, i32* %arr.idx, align 4\n"
48+
" %res = add i32 %l1, 10\n"
49+
" store i32 %res, i32* %arr.idx, align 4\n"
50+
" %indvars.iv.next = add i64 %indvars.iv, 1\n"
51+
" %exitcond = icmp ne i64 %indvars.iv.next, %N\n"
52+
" br i1 %exitcond, label %for.body, label %for.end\n"
53+
"for.end:\n"
54+
" ret void\n"
55+
"}\n";
56+
57+
SMDiagnostic Err;
58+
std::unique_ptr<Module> M = parseAssemblyString(ModuleString, Err, Ctx);
59+
60+
Function *F = M->getFunction("f");
61+
BasicBlock *LoopHeader = F->getEntryBlock().getSingleSuccessor();
62+
auto Plan = doBuildPlan(LoopHeader);
63+
64+
VPBlockBase *Entry = Plan->getEntry()->getEntryBasicBlock();
65+
EXPECT_NE(nullptr, Entry->getSingleSuccessor());
66+
EXPECT_EQ(0u, Entry->getNumPredecessors());
67+
EXPECT_EQ(1u, Entry->getNumSuccessors());
68+
69+
VPBasicBlock *VecBB = Entry->getSingleSuccessor()->getEntryBasicBlock();
70+
EXPECT_EQ(7u, VecBB->size());
71+
EXPECT_EQ(2u, VecBB->getNumPredecessors());
72+
EXPECT_EQ(2u, VecBB->getNumSuccessors());
73+
74+
auto Iter = VecBB->begin();
75+
VPInstruction *Phi = dyn_cast<VPInstruction>(&*Iter++);
76+
EXPECT_EQ(Instruction::PHI, Phi->getOpcode());
77+
78+
VPInstruction *Idx = dyn_cast<VPInstruction>(&*Iter++);
79+
EXPECT_EQ(Instruction::GetElementPtr, Idx->getOpcode());
80+
EXPECT_EQ(2u, Idx->getNumOperands());
81+
EXPECT_EQ(Phi, Idx->getOperand(1));
82+
83+
VPInstruction *Load = dyn_cast<VPInstruction>(&*Iter++);
84+
EXPECT_EQ(Instruction::Load, Load->getOpcode());
85+
EXPECT_EQ(1u, Load->getNumOperands());
86+
EXPECT_EQ(Idx, Load->getOperand(0));
87+
88+
VPInstruction *Add = dyn_cast<VPInstruction>(&*Iter++);
89+
EXPECT_EQ(Instruction::Add, Add->getOpcode());
90+
EXPECT_EQ(2u, Add->getNumOperands());
91+
EXPECT_EQ(Load, Add->getOperand(0));
92+
93+
VPInstruction *Store = dyn_cast<VPInstruction>(&*Iter++);
94+
EXPECT_EQ(Instruction::Store, Store->getOpcode());
95+
EXPECT_EQ(2u, Store->getNumOperands());
96+
EXPECT_EQ(Add, Store->getOperand(0));
97+
EXPECT_EQ(Idx, Store->getOperand(1));
98+
99+
VPInstruction *IndvarAdd = dyn_cast<VPInstruction>(&*Iter++);
100+
EXPECT_EQ(Instruction::Add, IndvarAdd->getOpcode());
101+
EXPECT_EQ(2u, IndvarAdd->getNumOperands());
102+
EXPECT_EQ(Phi, IndvarAdd->getOperand(0));
103+
104+
VPInstruction *ICmp = dyn_cast<VPInstruction>(&*Iter++);
105+
EXPECT_EQ(Instruction::ICmp, ICmp->getOpcode());
106+
EXPECT_EQ(2u, ICmp->getNumOperands());
107+
EXPECT_EQ(IndvarAdd, ICmp->getOperand(0));
108+
109+
LoopVectorizationLegality::InductionList Inductions;
110+
SmallPtrSet<Instruction *, 1> DeadInstructions;
111+
VPlanHCFGTransforms::VPInstructionsToVPRecipes(Plan, &Inductions,
112+
DeadInstructions);
113+
}
114+
115+
TEST_F(VPlanHCFGTest, testVPInstructionToVPRecipesInner) {
116+
LLVMContext Ctx;
117+
const char *ModuleString =
118+
"define void @f(i32* %A, i64 %N) {\n"
119+
"entry:\n"
120+
" br label %for.body\n"
121+
"for.body:\n"
122+
" %indvars.iv = phi i64 [ 0, %entry ], [ %indvars.iv.next, %for.body ]\n"
123+
" %arr.idx = getelementptr inbounds i32, i32* %A, i64 %indvars.iv\n"
124+
" %l1 = load i32, i32* %arr.idx, align 4\n"
125+
" %res = add i32 %l1, 10\n"
126+
" store i32 %res, i32* %arr.idx, align 4\n"
127+
" %indvars.iv.next = add i64 %indvars.iv, 1\n"
128+
" %exitcond = icmp ne i64 %indvars.iv.next, %N\n"
129+
" br i1 %exitcond, label %for.body, label %for.end\n"
130+
"for.end:\n"
131+
" ret void\n"
132+
"}\n";
133+
134+
SMDiagnostic Err;
135+
std::unique_ptr<Module> M = parseAssemblyString(ModuleString, Err, Ctx);
136+
137+
Function *F = M->getFunction("f");
138+
BasicBlock *LoopHeader = F->getEntryBlock().getSingleSuccessor();
139+
auto Plan = doBuildPlan(LoopHeader);
140+
141+
LoopVectorizationLegality::InductionList Inductions;
142+
SmallPtrSet<Instruction *, 1> DeadInstructions;
143+
VPlanHCFGTransforms::VPInstructionsToVPRecipes(Plan, &Inductions,
144+
DeadInstructions);
145+
146+
VPBlockBase *Entry = Plan->getEntry()->getEntryBasicBlock();
147+
EXPECT_NE(nullptr, Entry->getSingleSuccessor());
148+
EXPECT_EQ(0u, Entry->getNumPredecessors());
149+
EXPECT_EQ(1u, Entry->getNumSuccessors());
150+
151+
VPBasicBlock *VecBB = Entry->getSingleSuccessor()->getEntryBasicBlock();
152+
EXPECT_EQ(6u, VecBB->size());
153+
EXPECT_EQ(2u, VecBB->getNumPredecessors());
154+
EXPECT_EQ(2u, VecBB->getNumSuccessors());
155+
156+
auto Iter = VecBB->begin();
157+
auto *Phi = dyn_cast<VPWidenPHIRecipe>(&*Iter++);
158+
EXPECT_NE(nullptr, Phi);
159+
160+
auto *Idx = dyn_cast<VPWidenRecipe>(&*Iter++);
161+
EXPECT_NE(nullptr, Idx);
162+
163+
auto *Load = dyn_cast<VPWidenMemoryInstructionRecipe>(&*Iter++);
164+
EXPECT_NE(nullptr, Load);
165+
166+
auto *Add = dyn_cast<VPWidenRecipe>(&*Iter++);
167+
EXPECT_NE(nullptr, Add);
168+
169+
auto *Store = dyn_cast<VPWidenMemoryInstructionRecipe>(&*Iter++);
170+
EXPECT_NE(nullptr, Store);
171+
172+
auto *LastWiden = dyn_cast<VPWidenRecipe>(&*Iter++);
173+
EXPECT_NE(nullptr, LastWiden);
174+
EXPECT_EQ(VecBB->end(), Iter);
175+
}
176+
177+
} // namespace
178+
} // namespace llvm

0 commit comments

Comments
 (0)