Skip to content

Commit e5fae76

Browse files
[SandboxVectorizer] Add MemSeed bundle types (llvm#111584)
1 parent 0c0ec04 commit e5fae76

File tree

2 files changed

+112
-0
lines changed

2 files changed

+112
-0
lines changed

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

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,5 +123,44 @@ class SeedBundle {
123123
}
124124
#endif // NDEBUG
125125
};
126+
127+
/// Specialization of SeedBundle for memory access instructions. Keeps
128+
/// seeds sorted in ascending memory order, which is convenient for slicing
129+
/// these bundles into vectorizable groups.
130+
template <typename LoadOrStoreT> class MemSeedBundle : public SeedBundle {
131+
public:
132+
explicit MemSeedBundle(SmallVector<Instruction *> &&SV, ScalarEvolution &SE)
133+
: SeedBundle(std::move(SV)) {
134+
static_assert(std::is_same<LoadOrStoreT, LoadInst>::value ||
135+
std::is_same<LoadOrStoreT, StoreInst>::value,
136+
"Expected LoadInst or StoreInst!");
137+
assert(all_of(Seeds, [](auto *S) { return isa<LoadOrStoreT>(S); }) &&
138+
"Expected Load or Store instructions!");
139+
auto Cmp = [&SE](Instruction *I0, Instruction *I1) {
140+
return Utils::atLowerAddress(cast<LoadOrStoreT>(I0),
141+
cast<LoadOrStoreT>(I1), SE);
142+
};
143+
std::sort(Seeds.begin(), Seeds.end(), Cmp);
144+
}
145+
explicit MemSeedBundle(LoadOrStoreT *MemI) : SeedBundle(MemI) {
146+
static_assert(std::is_same<LoadOrStoreT, LoadInst>::value ||
147+
std::is_same<LoadOrStoreT, StoreInst>::value,
148+
"Expected LoadInst or StoreInst!");
149+
assert(isa<LoadOrStoreT>(MemI) && "Expected Load or Store!");
150+
}
151+
void insert(sandboxir::Instruction *I, ScalarEvolution &SE) {
152+
assert(isa<LoadOrStoreT>(I) && "Expected a Store or a Load!");
153+
auto Cmp = [&SE](Instruction *I0, Instruction *I1) {
154+
return Utils::atLowerAddress(cast<LoadOrStoreT>(I0),
155+
cast<LoadOrStoreT>(I1), SE);
156+
};
157+
// Find the first element after I in mem. Then insert I before it.
158+
insertAt(std::upper_bound(begin(), end(), I, Cmp), I);
159+
}
160+
};
161+
162+
using StoreSeedBundle = MemSeedBundle<sandboxir::StoreInst>;
163+
using LoadSeedBundle = MemSeedBundle<sandboxir::LoadInst>;
164+
126165
} // namespace llvm::sandboxir
127166
#endif // LLVM_TRANSFORMS_VECTORIZE_SANDBOXVECTORIZER_SEEDCOLLECTOR_H

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

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,13 @@
77
//===----------------------------------------------------------------------===//
88

99
#include "llvm/Transforms/Vectorize/SandboxVectorizer/SeedCollector.h"
10+
#include "llvm/Analysis/AliasAnalysis.h"
11+
#include "llvm/Analysis/AssumptionCache.h"
12+
#include "llvm/Analysis/BasicAliasAnalysis.h"
13+
#include "llvm/Analysis/LoopInfo.h"
14+
#include "llvm/Analysis/TargetLibraryInfo.h"
1015
#include "llvm/AsmParser/Parser.h"
16+
#include "llvm/IR/Dominators.h"
1117
#include "llvm/SandboxIR/Function.h"
1218
#include "llvm/SandboxIR/Instruction.h"
1319
#include "llvm/Support/SourceMgr.h"
@@ -26,6 +32,12 @@ struct SeedBundleTest : public testing::Test {
2632
if (!M)
2733
Err.print("LegalityTest", errs());
2834
}
35+
BasicBlock *getBasicBlockByName(Function &F, StringRef Name) {
36+
for (BasicBlock &BB : F)
37+
if (BB.getName() == Name)
38+
return &BB;
39+
llvm_unreachable("Expected to find basic block!");
40+
}
2941
};
3042

3143
TEST_F(SeedBundleTest, SeedBundle) {
@@ -123,3 +135,64 @@ define void @foo(float %v0, i32 %i0, i16 %i1, i8 %i2) {
123135
/* ForcePowerOf2 */ true);
124136
EXPECT_EQ(Slice4.size(), 0u);
125137
}
138+
139+
TEST_F(SeedBundleTest, MemSeedBundle) {
140+
parseIR(C, R"IR(
141+
define void @foo(ptr %ptrA, float %val, ptr %ptr) {
142+
bb:
143+
%gep0 = getelementptr float, ptr %ptr, i32 0
144+
%gep1 = getelementptr float, ptr %ptr, i32 1
145+
%gep2 = getelementptr float, ptr %ptr, i32 3
146+
%gep3 = getelementptr float, ptr %ptr, i32 4
147+
store float %val, ptr %gep0
148+
store float %val, ptr %gep1
149+
store float %val, ptr %gep2
150+
store float %val, ptr %gep3
151+
152+
load float, ptr %gep0
153+
load float, ptr %gep1
154+
load float, ptr %gep2
155+
load float, ptr %gep3
156+
157+
ret void
158+
}
159+
)IR");
160+
Function &LLVMF = *M->getFunction("foo");
161+
162+
DominatorTree DT(LLVMF);
163+
TargetLibraryInfoImpl TLII;
164+
TargetLibraryInfo TLI(TLII);
165+
DataLayout DL(M->getDataLayout());
166+
LoopInfo LI(DT);
167+
AssumptionCache AC(LLVMF);
168+
ScalarEvolution SE(LLVMF, TLI, AC, DT, LI);
169+
170+
sandboxir::Context Ctx(C);
171+
auto &F = *Ctx.createFunction(&LLVMF);
172+
auto *BB = &*F.begin();
173+
auto It = std::next(BB->begin(), 4);
174+
auto *S0 = cast<sandboxir::StoreInst>(&*It++);
175+
auto *S1 = cast<sandboxir::StoreInst>(&*It++);
176+
auto *S2 = cast<sandboxir::StoreInst>(&*It++);
177+
auto *S3 = cast<sandboxir::StoreInst>(&*It++);
178+
179+
// Single instruction constructor; test insert out of memory order
180+
sandboxir::StoreSeedBundle SB(S3);
181+
SB.insert(S1, SE);
182+
SB.insert(S2, SE);
183+
SB.insert(S0, SE);
184+
EXPECT_THAT(SB, testing::ElementsAre(S0, S1, S2, S3));
185+
186+
// Instruction list constructor; test list out of order
187+
auto *L0 = cast<sandboxir::LoadInst>(&*It++);
188+
auto *L1 = cast<sandboxir::LoadInst>(&*It++);
189+
auto *L2 = cast<sandboxir::LoadInst>(&*It++);
190+
auto *L3 = cast<sandboxir::LoadInst>(&*It++);
191+
SmallVector<sandboxir::Instruction *> Loads;
192+
Loads.push_back(L1);
193+
Loads.push_back(L3);
194+
Loads.push_back(L2);
195+
Loads.push_back(L0);
196+
sandboxir::LoadSeedBundle LB(std::move(Loads), SE);
197+
EXPECT_THAT(LB, testing::ElementsAre(L0, L1, L2, L3));
198+
}

0 commit comments

Comments
 (0)