Skip to content

Commit 59ea3ab

Browse files
author
Vasileios Porpodas
committed
fixup! [SandboxVec] Add a simple pack reuse pass
1 parent 01e0119 commit 59ea3ab

File tree

3 files changed

+42
-24
lines changed

3 files changed

+42
-24
lines changed

llvm/include/llvm/Transforms/Vectorize/SandboxVectorizer/VecUtils.h

Lines changed: 34 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -197,12 +197,32 @@ class VecUtils {
197197
/// \Returns the first integer power of 2 that is <= Num.
198198
static unsigned getFloorPowerOf2(unsigned Num);
199199

200-
/// If \p I is the last instruction of a pack pattern, then this function
201-
/// returns the instructions in the pack and the operands in the pack, else
202-
/// returns nullopt.
203-
static std::optional<
204-
std::pair<SmallVector<Instruction *>, SmallVector<Value *>>>
205-
matchPack(Instruction *I) {
200+
/// Helper struct for `matchPack()`. Describes the instructions and operands
201+
/// of a pack pattern.
202+
struct PackPattern {
203+
/// The insertelement instructions that form the pack pattern in bottom-up
204+
/// order, i.e., the first instruction in `Instrs` is the bottom-most
205+
/// InsertElement instruction of the pack pattern.
206+
/// For example in this simple pack pattern:
207+
/// %Pack0 = insertelement <2 x i8> poison, i8 %v0, i64 0
208+
/// %Pack1 = insertelement <2 x i8> %Pack0, i8 %v1, i64 1
209+
/// this is [ %Pack1, %Pack0 ].
210+
SmallVector<Instruction *> Instrs;
211+
/// The "external" operands of the pack pattern, i.e., the values that get
212+
/// packed into a vector, skipping the ones in `Instrs`. The operands are in
213+
/// bottom-up order, starting from the operands of the bottom-most insert.
214+
/// So in our example this would be [ %v1, %v0 ].
215+
SmallVector<Value *> Operands;
216+
};
217+
218+
/// If \p I is the last instruction of a pack pattern (i.e., an InsertElement
219+
/// into a vector), then this function returns the instructions in the pack
220+
/// and the operands in the pack, else returns nullopt.
221+
/// Here is an example of a matched pattern:
222+
/// %PackA0 = insertelement <2 x i8> poison, i8 %v0, i64 0
223+
/// %PackA1 = insertelement <2 x i8> %PackA0, i8 %v1, i64 1
224+
/// TODO: this currently detects only simple canonicalized patterns.
225+
static std::optional<PackPattern> matchPack(Instruction *I) {
206226
// TODO: Support vector pack patterns.
207227
// TODO: Support out-of-order inserts.
208228

@@ -213,34 +233,32 @@ class VecUtils {
213233
// The pack contains as many instrs as the lanes of the bottom-most Insert
214234
unsigned ExpectedNumInserts = VecUtils::getNumLanes(I);
215235
assert(ExpectedNumInserts >= 2 && "Expected at least 2 inserts!");
216-
SmallVector<Instruction *> PackInstrs;
217-
SmallVector<Value *> PackOperands;
218-
PackOperands.resize(ExpectedNumInserts);
236+
PackPattern Pack;
237+
Pack.Operands.resize(ExpectedNumInserts);
219238
// Collect the inserts by walking up the use-def chain.
220239
Instruction *InsertI = I;
221-
for ([[maybe_unused]] auto Cnt : seq<unsigned>(ExpectedNumInserts)) {
240+
for (auto ExpectedLane : reverse(seq<unsigned>(ExpectedNumInserts))) {
222241
if (InsertI == nullptr)
223242
return std::nullopt;
224243
if (InsertI->getParent() != BB0)
225244
return std::nullopt;
226245
// Check the lane.
227246
auto *LaneC = dyn_cast<ConstantInt>(InsertI->getOperand(2));
228-
unsigned ExpectedLane = ExpectedNumInserts - Cnt - 1;
229247
if (LaneC == nullptr || LaneC->getSExtValue() != ExpectedLane)
230248
return std::nullopt;
231-
PackInstrs.push_back(InsertI);
232-
PackOperands[ExpectedLane] = InsertI->getOperand(1);
249+
Pack.Instrs.push_back(InsertI);
250+
Pack.Operands[ExpectedLane] = InsertI->getOperand(1);
233251

234252
Value *Op = InsertI->getOperand(0);
235-
if (Cnt == ExpectedNumInserts - 1) {
253+
if (ExpectedLane == 0) {
254+
// Check the topmost insert. The operand should be a Poison.
236255
if (!isa<PoisonValue>(Op))
237256
return std::nullopt;
238257
} else {
239258
InsertI = dyn_cast<InsertElementInst>(Op);
240259
}
241260
}
242-
// Check the topmost insert. The operand should be a Poison.
243-
return std::make_pair(PackInstrs, PackOperands);
261+
return Pack;
244262
}
245263

246264
#ifndef NDEBUG

llvm/lib/Transforms/Vectorize/SandboxVectorizer/Passes/PackReuse.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,11 @@ bool PackReuse::runOnRegion(Region &Rgn, const Analyses &A) {
2121
PacksMap;
2222
// Go over the region and look for pack patterns.
2323
for (auto *I : Rgn) {
24-
auto PairOpt = VecUtils::matchPack(I);
25-
if (PairOpt) {
24+
auto PackOpt = VecUtils::matchPack(I);
25+
if (PackOpt) {
2626
// TODO: For now limit pack reuse within a BB.
27-
BasicBlock *BB = (*PairOpt->first.front()).getParent();
28-
PacksMap[{BB, PairOpt->second}].push_back(PairOpt->first);
27+
BasicBlock *BB = (*PackOpt->Instrs.front()).getParent();
28+
PacksMap[{BB, PackOpt->Operands}].push_back(PackOpt->Instrs);
2929
}
3030
}
3131
for (auto &Pair : PacksMap) {

llvm/unittests/Transforms/Vectorize/SandboxVectorizer/VecUtilsTest.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -603,10 +603,10 @@ define void @foo(i8 %v0, i8 %v1) {
603603
EXPECT_FALSE(sandboxir::VecUtils::matchPack(Pack0));
604604
EXPECT_FALSE(sandboxir::VecUtils::matchPack(Ret));
605605
{
606-
auto PairOpt = sandboxir::VecUtils::matchPack(Pack1);
607-
EXPECT_TRUE(PairOpt);
608-
EXPECT_THAT(PairOpt->first, testing::ElementsAre(Pack1, Pack0));
609-
EXPECT_THAT(PairOpt->second, testing::ElementsAre(Arg0, Arg1));
606+
auto PackOpt = sandboxir::VecUtils::matchPack(Pack1);
607+
EXPECT_TRUE(PackOpt);
608+
EXPECT_THAT(PackOpt->Instrs, testing::ElementsAre(Pack1, Pack0));
609+
EXPECT_THAT(PackOpt->Operands, testing::ElementsAre(Arg0, Arg1));
610610
}
611611
{
612612
for (auto *NotPack : {NotPack0, NotPack1, NotPack2, NotPackBB})

0 commit comments

Comments
 (0)