Skip to content

Commit 5ecce45

Browse files
authored
[SandboxVec] Move seed collection into its own separate pass (#127132)
This patch moves the seed collection logic from the BottomUpVec pass into a new Sandbox IR Function pass. The new "seed-collection" pass collects the seeds, builds a region and runs the region pass pipeline.
1 parent 426148b commit 5ecce45

File tree

21 files changed

+251
-120
lines changed

21 files changed

+251
-120
lines changed

llvm/include/llvm/SandboxIR/Region.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,10 @@ class Region {
120120
/// Set \p I as the \p Idx'th element in the auxiliary vector.
121121
/// NOTE: This is for internal use, it does not set the metadata.
122122
void setAux(unsigned Idx, Instruction *I);
123+
/// Helper for dropping Aux metadata for \p I.
124+
void dropAuxMetadata(Instruction *I);
125+
/// Remove instruction \p I from Aux and drop metadata.
126+
void removeFromAux(Instruction *I);
123127

124128
public:
125129
Region(Context &Ctx, TargetTransformInfo &TTI);

llvm/include/llvm/Transforms/Vectorize/SandboxVectorizer/Passes/BottomUpVec.h

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,23 @@
1616
#include "llvm/ADT/StringRef.h"
1717
#include "llvm/SandboxIR/Constant.h"
1818
#include "llvm/SandboxIR/Pass.h"
19-
#include "llvm/SandboxIR/PassManager.h"
2019
#include "llvm/Support/raw_ostream.h"
2120
#include "llvm/Transforms/Vectorize/SandboxVectorizer/InstrMaps.h"
2221
#include "llvm/Transforms/Vectorize/SandboxVectorizer/Legality.h"
2322

2423
namespace llvm::sandboxir {
2524

26-
class BottomUpVec final : public FunctionPass {
25+
/// This is a simple bottom-up vectorizer Region pass.
26+
/// It expects a "seed slice" as an input in the Region's Aux vector.
27+
/// The "seed slice" is a vector of instructions that can be used as a starting
28+
/// point for vectorization, like stores to consecutive memory addresses.
29+
/// Starting from the seed instructions, it walks up the def-use chain looking
30+
/// for more instructions that can be vectorized. This pass will generate vector
31+
/// code if it can legally vectorize the code, regardless of whether it is
32+
/// profitable or not. For now profitability is checked at the end of the region
33+
/// pass pipeline by a dedicated pass that accepts or rejects the IR
34+
/// transaction, depending on the cost.
35+
class BottomUpVec final : public RegionPass {
2736
bool Change = false;
2837
std::unique_ptr<LegalityAnalysis> Legality;
2938
/// The original instructions that are potentially dead after vectorization.
@@ -55,16 +64,9 @@ class BottomUpVec final : public FunctionPass {
5564
/// Entry point for vectorization starting from \p Seeds.
5665
bool tryVectorize(ArrayRef<Value *> Seeds);
5766

58-
/// The PM containing the pipeline of region passes.
59-
RegionPassManager RPM;
60-
6167
public:
62-
BottomUpVec(StringRef Pipeline);
63-
bool runOnFunction(Function &F, const Analyses &A) final;
64-
void printPipeline(raw_ostream &OS) const final {
65-
OS << getName() << "\n";
66-
RPM.printPipeline(OS);
67-
}
68+
BottomUpVec() : RegionPass("bottom-up-vec") {}
69+
bool runOnRegion(Region &Rgn, const Analyses &A) final;
6870
};
6971

7072
} // namespace llvm::sandboxir
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
//===- SeedCollection.h -----------------------------------------*- 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+
// The seed-collection pass of the bottom-up vectorizer.
10+
//
11+
12+
#ifndef LLVM_TRANSFORMS_VECTORIZE_SANDBOXVECTORIZER_PASSES_SEEDCOLLECTION_H
13+
#define LLVM_TRANSFORMS_VECTORIZE_SANDBOXVECTORIZER_PASSES_SEEDCOLLECTION_H
14+
15+
#include "llvm/SandboxIR/Pass.h"
16+
#include "llvm/SandboxIR/PassManager.h"
17+
18+
namespace llvm::sandboxir {
19+
20+
/// This pass collects the instructions that can become vectorization "seeds",
21+
/// like stores to consecutive memory addresses. It then goes over the collected
22+
/// seeds, slicing them into appropriately sized chunks, creating a Region with
23+
/// the seed slice as the Auxiliary vector and runs the region pass pipeline.
24+
class SeedCollection final : public FunctionPass {
25+
26+
/// The PM containing the pipeline of region passes.
27+
RegionPassManager RPM;
28+
29+
public:
30+
SeedCollection(StringRef Pipeline);
31+
bool runOnFunction(Function &F, const Analyses &A) final;
32+
void printPipeline(raw_ostream &OS) const final {
33+
OS << getName() << "\n";
34+
RPM.printPipeline(OS);
35+
}
36+
};
37+
38+
} // namespace llvm::sandboxir
39+
40+
#endif // LLVM_TRANSFORMS_VECTORIZE_SANDBOXVECTORIZER_PASSES_SEEDCOLLECTION_H

llvm/lib/SandboxIR/Region.cpp

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,10 @@ Region::Region(Context &Ctx, TargetTransformInfo &TTI)
4040

4141
CreateInstCB = Ctx.registerCreateInstrCallback(
4242
[this](Instruction *NewInst) { add(NewInst); });
43-
EraseInstCB = Ctx.registerEraseInstrCallback(
44-
[this](Instruction *ErasedInst) { remove(ErasedInst); });
43+
EraseInstCB = Ctx.registerEraseInstrCallback([this](Instruction *ErasedInst) {
44+
remove(ErasedInst);
45+
removeFromAux(ErasedInst);
46+
});
4547
}
4648

4749
Region::~Region() {
@@ -84,11 +86,22 @@ void Region::setAux(unsigned Idx, Instruction *I) {
8486
Aux[Idx] = I;
8587
}
8688

89+
void Region::dropAuxMetadata(Instruction *I) {
90+
auto *LLVMI = cast<llvm::Instruction>(I->Val);
91+
LLVMI->setMetadata(AuxMDKind, nullptr);
92+
}
93+
94+
void Region::removeFromAux(Instruction *I) {
95+
auto It = find(Aux, I);
96+
if (It == Aux.end())
97+
return;
98+
dropAuxMetadata(I);
99+
Aux.erase(It);
100+
}
101+
87102
void Region::clearAux() {
88-
for (unsigned Idx : seq<unsigned>(0, Aux.size())) {
89-
auto *LLVMI = cast<llvm::Instruction>(Aux[Idx]->Val);
90-
LLVMI->setMetadata(AuxMDKind, nullptr);
91-
}
103+
for (unsigned Idx : seq<unsigned>(0, Aux.size()))
104+
dropAuxMetadata(Aux[Idx]);
92105
Aux.clear();
93106
}
94107

llvm/lib/Transforms/Vectorize/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ add_llvm_component_library(LLVMVectorize
99
SandboxVectorizer/Legality.cpp
1010
SandboxVectorizer/Passes/BottomUpVec.cpp
1111
SandboxVectorizer/Passes/RegionsFromMetadata.cpp
12+
SandboxVectorizer/Passes/SeedCollection.cpp
1213
SandboxVectorizer/Passes/TransactionAcceptOrRevert.cpp
1314
SandboxVectorizer/SandboxVectorizer.cpp
1415
SandboxVectorizer/SandboxVectorizerPassBuilder.cpp

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

Lines changed: 11 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -14,20 +14,10 @@
1414
#include "llvm/SandboxIR/Module.h"
1515
#include "llvm/SandboxIR/Region.h"
1616
#include "llvm/SandboxIR/Utils.h"
17-
#include "llvm/Transforms/Vectorize/SandboxVectorizer/SandboxVectorizerPassBuilder.h"
18-
#include "llvm/Transforms/Vectorize/SandboxVectorizer/SeedCollector.h"
1917
#include "llvm/Transforms/Vectorize/SandboxVectorizer/VecUtils.h"
2018

2119
namespace llvm {
2220

23-
static cl::opt<unsigned>
24-
OverrideVecRegBits("sbvec-vec-reg-bits", cl::init(0), cl::Hidden,
25-
cl::desc("Override the vector register size in bits, "
26-
"which is otherwise found by querying TTI."));
27-
static cl::opt<bool>
28-
AllowNonPow2("sbvec-allow-non-pow2", cl::init(false), cl::Hidden,
29-
cl::desc("Allow non-power-of-2 vectorization."));
30-
3121
#ifndef NDEBUG
3222
static cl::opt<bool>
3323
AlwaysVerify("sbvec-always-verify", cl::init(false), cl::Hidden,
@@ -37,10 +27,6 @@ static cl::opt<bool>
3727

3828
namespace sandboxir {
3929

40-
BottomUpVec::BottomUpVec(StringRef Pipeline)
41-
: FunctionPass("bottom-up-vec"),
42-
RPM("rpm", Pipeline, SandboxVectorizerPassBuilder::createRegionPass) {}
43-
4430
static SmallVector<Value *, 4> getOperand(ArrayRef<Value *> Bndl,
4531
unsigned OpIdx) {
4632
SmallVector<Value *, 4> Operands;
@@ -413,90 +399,29 @@ Value *BottomUpVec::vectorizeRec(ArrayRef<Value *> Bndl,
413399
}
414400

415401
bool BottomUpVec::tryVectorize(ArrayRef<Value *> Bndl) {
402+
Change = false;
416403
DeadInstrCandidates.clear();
417404
Legality->clear();
418405
vectorizeRec(Bndl, {}, /*Depth=*/0);
419406
tryEraseDeadInstrs();
420407
return Change;
421408
}
422409

423-
bool BottomUpVec::runOnFunction(Function &F, const Analyses &A) {
410+
bool BottomUpVec::runOnRegion(Region &Rgn, const Analyses &A) {
411+
const auto &SeedSlice = Rgn.getAux();
412+
assert(SeedSlice.size() >= 2 && "Bad slice!");
413+
Function &F = *SeedSlice[0]->getParent()->getParent();
424414
IMaps = std::make_unique<InstrMaps>(F.getContext());
425415
Legality = std::make_unique<LegalityAnalysis>(
426416
A.getAA(), A.getScalarEvolution(), F.getParent()->getDataLayout(),
427417
F.getContext(), *IMaps);
428-
Change = false;
429-
const auto &DL = F.getParent()->getDataLayout();
430-
unsigned VecRegBits =
431-
OverrideVecRegBits != 0
432-
? OverrideVecRegBits
433-
: A.getTTI()
434-
.getRegisterBitWidth(TargetTransformInfo::RGK_FixedWidthVector)
435-
.getFixedValue();
436-
437-
// TODO: Start from innermost BBs first
438-
for (auto &BB : F) {
439-
SeedCollector SC(&BB, A.getScalarEvolution());
440-
for (SeedBundle &Seeds : SC.getStoreSeeds()) {
441-
unsigned ElmBits =
442-
Utils::getNumBits(VecUtils::getElementType(Utils::getExpectedType(
443-
Seeds[Seeds.getFirstUnusedElementIdx()])),
444-
DL);
445-
446-
auto DivideBy2 = [](unsigned Num) {
447-
auto Floor = VecUtils::getFloorPowerOf2(Num);
448-
if (Floor == Num)
449-
return Floor / 2;
450-
return Floor;
451-
};
452-
// Try to create the largest vector supported by the target. If it fails
453-
// reduce the vector size by half.
454-
for (unsigned SliceElms = std::min(VecRegBits / ElmBits,
455-
Seeds.getNumUnusedBits() / ElmBits);
456-
SliceElms >= 2u; SliceElms = DivideBy2(SliceElms)) {
457-
if (Seeds.allUsed())
458-
break;
459-
// Keep trying offsets after FirstUnusedElementIdx, until we vectorize
460-
// the slice. This could be quite expensive, so we enforce a limit.
461-
for (unsigned Offset = Seeds.getFirstUnusedElementIdx(),
462-
OE = Seeds.size();
463-
Offset + 1 < OE; Offset += 1) {
464-
// Seeds are getting used as we vectorize, so skip them.
465-
if (Seeds.isUsed(Offset))
466-
continue;
467-
if (Seeds.allUsed())
468-
break;
469418

470-
auto SeedSlice =
471-
Seeds.getSlice(Offset, SliceElms * ElmBits, !AllowNonPow2);
472-
if (SeedSlice.empty())
473-
continue;
474-
475-
assert(SeedSlice.size() >= 2 && "Should have been rejected!");
476-
477-
// TODO: Refactor to remove the unnecessary copy to SeedSliceVals.
478-
SmallVector<Value *> SeedSliceVals(SeedSlice.begin(),
479-
SeedSlice.end());
480-
// Create an empty region. Instructions get added to the region
481-
// automatically by the callbacks.
482-
auto &Ctx = F.getContext();
483-
Region Rgn(Ctx, A.getTTI());
484-
// Save the state of the IR before we make any changes. The
485-
// transaction gets accepted/reverted by the tr-accept-or-revert pass.
486-
Ctx.save();
487-
// Try to vectorize starting from the seed slice. The returned value
488-
// is true if we found vectorizable code and generated some vector
489-
// code for it. It does not mean that the code is profitable.
490-
bool VecSuccess = tryVectorize(SeedSliceVals);
491-
if (VecSuccess)
492-
// WARNING: All passes should return false, except those that
493-
// accept/revert the state.
494-
Change |= RPM.runOnRegion(Rgn, A);
495-
}
496-
}
497-
}
498-
}
499-
return Change;
419+
// TODO: Refactor to remove the unnecessary copy to SeedSliceVals.
420+
SmallVector<Value *> SeedSliceVals(SeedSlice.begin(), SeedSlice.end());
421+
// Try to vectorize starting from the seed slice. The returned value
422+
// is true if we found vectorizable code and generated some vector
423+
// code for it. It does not mean that the code is profitable.
424+
return tryVectorize(SeedSliceVals);
500425
}
501426

502427
} // namespace sandboxir

llvm/lib/Transforms/Vectorize/SandboxVectorizer/Passes/PassRegistry.def

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,15 @@ REGION_PASS("null", ::llvm::sandboxir::NullPass)
2121
REGION_PASS("print-instruction-count", ::llvm::sandboxir::PrintInstructionCount)
2222
REGION_PASS("tr-accept", ::llvm::sandboxir::TransactionAlwaysAccept)
2323
REGION_PASS("tr-accept-or-revert", ::llvm::sandboxir::TransactionAcceptOrRevert)
24+
REGION_PASS("bottom-up-vec", ::llvm::sandboxir::BottomUpVec)
2425

2526
#undef REGION_PASS
2627

2728
#ifndef FUNCTION_PASS_WITH_PARAMS
2829
#define FUNCTION_PASS_WITH_PARAMS(NAME, CLASS_NAME)
2930
#endif
3031

31-
FUNCTION_PASS_WITH_PARAMS("bottom-up-vec", ::llvm::sandboxir::BottomUpVec)
32+
FUNCTION_PASS_WITH_PARAMS("seed-collection", ::llvm::sandboxir::SeedCollection)
3233
FUNCTION_PASS_WITH_PARAMS("regions-from-metadata", ::llvm::sandboxir::RegionsFromMetadata)
3334

3435
#undef FUNCTION_PASS_WITH_PARAMS
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
//===- SeedCollection.cpp - Seed collection pass --------------------------===//
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 "llvm/Transforms/Vectorize/SandboxVectorizer/Passes/SeedCollection.h"
10+
#include "llvm/Analysis/TargetTransformInfo.h"
11+
#include "llvm/SandboxIR/Module.h"
12+
#include "llvm/SandboxIR/Region.h"
13+
#include "llvm/Transforms/Vectorize/SandboxVectorizer/SandboxVectorizerPassBuilder.h"
14+
#include "llvm/Transforms/Vectorize/SandboxVectorizer/SeedCollector.h"
15+
#include "llvm/Transforms/Vectorize/SandboxVectorizer/VecUtils.h"
16+
17+
namespace llvm {
18+
19+
static cl::opt<unsigned>
20+
OverrideVecRegBits("sbvec-vec-reg-bits", cl::init(0), cl::Hidden,
21+
cl::desc("Override the vector register size in bits, "
22+
"which is otherwise found by querying TTI."));
23+
static cl::opt<bool>
24+
AllowNonPow2("sbvec-allow-non-pow2", cl::init(false), cl::Hidden,
25+
cl::desc("Allow non-power-of-2 vectorization."));
26+
27+
namespace sandboxir {
28+
SeedCollection::SeedCollection(StringRef Pipeline)
29+
: FunctionPass("seed-collection"),
30+
RPM("rpm", Pipeline, SandboxVectorizerPassBuilder::createRegionPass) {}
31+
32+
bool SeedCollection::runOnFunction(Function &F, const Analyses &A) {
33+
bool Change = false;
34+
const auto &DL = F.getParent()->getDataLayout();
35+
unsigned VecRegBits =
36+
OverrideVecRegBits != 0
37+
? OverrideVecRegBits
38+
: A.getTTI()
39+
.getRegisterBitWidth(TargetTransformInfo::RGK_FixedWidthVector)
40+
.getFixedValue();
41+
42+
// TODO: Start from innermost BBs first
43+
for (auto &BB : F) {
44+
SeedCollector SC(&BB, A.getScalarEvolution());
45+
for (SeedBundle &Seeds : SC.getStoreSeeds()) {
46+
unsigned ElmBits =
47+
Utils::getNumBits(VecUtils::getElementType(Utils::getExpectedType(
48+
Seeds[Seeds.getFirstUnusedElementIdx()])),
49+
DL);
50+
51+
auto DivideBy2 = [](unsigned Num) {
52+
auto Floor = VecUtils::getFloorPowerOf2(Num);
53+
if (Floor == Num)
54+
return Floor / 2;
55+
return Floor;
56+
};
57+
// Try to create the largest vector supported by the target. If it fails
58+
// reduce the vector size by half.
59+
for (unsigned SliceElms = std::min(VecRegBits / ElmBits,
60+
Seeds.getNumUnusedBits() / ElmBits);
61+
SliceElms >= 2u; SliceElms = DivideBy2(SliceElms)) {
62+
if (Seeds.allUsed())
63+
break;
64+
// Keep trying offsets after FirstUnusedElementIdx, until we vectorize
65+
// the slice. This could be quite expensive, so we enforce a limit.
66+
for (unsigned Offset = Seeds.getFirstUnusedElementIdx(),
67+
OE = Seeds.size();
68+
Offset + 1 < OE; Offset += 1) {
69+
// Seeds are getting used as we vectorize, so skip them.
70+
if (Seeds.isUsed(Offset))
71+
continue;
72+
if (Seeds.allUsed())
73+
break;
74+
75+
auto SeedSlice =
76+
Seeds.getSlice(Offset, SliceElms * ElmBits, !AllowNonPow2);
77+
if (SeedSlice.empty())
78+
continue;
79+
80+
assert(SeedSlice.size() >= 2 && "Should have been rejected!");
81+
82+
// Create a region containing the seed slice.
83+
auto &Ctx = F.getContext();
84+
Region Rgn(Ctx, A.getTTI());
85+
// TODO: Replace save() with a save pass in the pass pipeline.
86+
Ctx.save();
87+
Rgn.setAux(SeedSlice);
88+
// Run the region pass pipeline.
89+
Change |= RPM.runOnRegion(Rgn, A);
90+
Rgn.clearAux();
91+
}
92+
}
93+
}
94+
}
95+
return Change;
96+
}
97+
} // namespace sandboxir
98+
} // namespace llvm

0 commit comments

Comments
 (0)