Skip to content

Commit 318d2f5

Browse files
authored
[SandboxVec][DAG] Boilerplate (#108862)
This patch adds a very basic implementation of the Dependency Graph to be used by the vectorizer.
1 parent defb8fb commit 318d2f5

File tree

6 files changed

+228
-0
lines changed

6 files changed

+228
-0
lines changed
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
//===- DependencyGraph.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+
// This file declares the dependency graph used by the vectorizer's instruction
10+
// scheduler.
11+
//
12+
// The nodes of the graph are objects of the `DGNode` class. Each `DGNode`
13+
// object points to an instruction.
14+
// The edges between `DGNode`s are implicitly defined by an ordered set of
15+
// predecessor nodes, to save memory.
16+
// Finally the whole dependency graph is an object of the `DependencyGraph`
17+
// class, which also provides the API for creating/extending the graph from
18+
// input Sandbox IR.
19+
//
20+
//===----------------------------------------------------------------------===//
21+
22+
#ifndef LLVM_TRANSFORMS_VECTORIZE_SANDBOXVECTORIZER_DEPENDENCYGRAPH_H
23+
#define LLVM_TRANSFORMS_VECTORIZE_SANDBOXVECTORIZER_DEPENDENCYGRAPH_H
24+
25+
#include "llvm/ADT/DenseMap.h"
26+
#include "llvm/ADT/iterator_range.h"
27+
#include "llvm/SandboxIR/SandboxIR.h"
28+
29+
namespace llvm::sandboxir {
30+
31+
/// A DependencyGraph Node that points to an Instruction and contains memory
32+
/// dependency edges.
33+
class DGNode {
34+
Instruction *I;
35+
/// Memory predecessors.
36+
DenseSet<DGNode *> MemPreds;
37+
38+
public:
39+
DGNode(Instruction *I) : I(I) {}
40+
Instruction *getInstruction() const { return I; }
41+
void addMemPred(DGNode *PredN) { MemPreds.insert(PredN); }
42+
/// \Returns all memory dependency predecessors.
43+
iterator_range<DenseSet<DGNode *>::const_iterator> memPreds() const {
44+
return make_range(MemPreds.begin(), MemPreds.end());
45+
}
46+
/// \Returns true if there is a memory dependency N->this.
47+
bool hasMemPred(DGNode *N) const { return MemPreds.count(N); }
48+
#ifndef NDEBUG
49+
void print(raw_ostream &OS, bool PrintDeps = true) const;
50+
friend raw_ostream &operator<<(DGNode &N, raw_ostream &OS) {
51+
N.print(OS);
52+
return OS;
53+
}
54+
LLVM_DUMP_METHOD void dump() const;
55+
#endif // NDEBUG
56+
};
57+
58+
class DependencyGraph {
59+
private:
60+
DenseMap<Instruction *, std::unique_ptr<DGNode>> InstrToNodeMap;
61+
62+
public:
63+
DependencyGraph() {}
64+
65+
DGNode *getNode(Instruction *I) const {
66+
auto It = InstrToNodeMap.find(I);
67+
return It != InstrToNodeMap.end() ? It->second.get() : nullptr;
68+
}
69+
DGNode *getOrCreateNode(Instruction *I) {
70+
auto [It, NotInMap] = InstrToNodeMap.try_emplace(I);
71+
if (NotInMap)
72+
It->second = std::make_unique<DGNode>(I);
73+
return It->second.get();
74+
}
75+
// TODO: extend() should work with intervals not the whole BB.
76+
/// Build the dependency graph for \p BB.
77+
void extend(BasicBlock *BB);
78+
#ifndef NDEBUG
79+
void print(raw_ostream &OS) const;
80+
LLVM_DUMP_METHOD void dump() const;
81+
#endif // NDEBUG
82+
};
83+
84+
} // namespace llvm::sandboxir
85+
86+
#endif // LLVM_TRANSFORMS_VECTORIZE_SANDBOXVECTORIZER_DEPENDENCYGRAPH_H

llvm/lib/Transforms/Vectorize/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ add_llvm_component_library(LLVMVectorize
33
LoopIdiomVectorize.cpp
44
LoopVectorizationLegality.cpp
55
LoopVectorize.cpp
6+
SandboxVectorizer/DependencyGraph.cpp
67
SandboxVectorizer/Passes/BottomUpVec.cpp
78
SandboxVectorizer/SandboxVectorizer.cpp
89
SLPVectorizer.cpp
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
//===- DependencyGraph.cpp ------------------------------------------===//
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/DependencyGraph.h"
10+
11+
using namespace llvm::sandboxir;
12+
13+
#ifndef NDEBUG
14+
void DGNode::print(raw_ostream &OS, bool PrintDeps) const {
15+
I->dumpOS(OS);
16+
if (PrintDeps) {
17+
OS << "\n";
18+
// Print memory preds.
19+
static constexpr const unsigned Indent = 4;
20+
for (auto *Pred : MemPreds) {
21+
OS.indent(Indent) << "<-";
22+
Pred->print(OS, false);
23+
OS << "\n";
24+
}
25+
}
26+
}
27+
void DGNode::dump() const {
28+
print(dbgs());
29+
dbgs() << "\n";
30+
}
31+
#endif // NDEBUG
32+
33+
void DependencyGraph::extend(BasicBlock *BB) {
34+
if (BB->empty())
35+
return;
36+
// TODO: For now create a chain of dependencies.
37+
DGNode *LastN = getOrCreateNode(&*BB->begin());
38+
for (auto &I : drop_begin(*BB)) {
39+
auto *N = getOrCreateNode(&I);
40+
N->addMemPred(LastN);
41+
LastN = N;
42+
}
43+
}
44+
45+
#ifndef NDEBUG
46+
void DependencyGraph::print(raw_ostream &OS) const {
47+
// InstrToNodeMap is unordered so we need to create an ordered vector.
48+
SmallVector<DGNode *> Nodes;
49+
Nodes.reserve(InstrToNodeMap.size());
50+
for (const auto &Pair : InstrToNodeMap)
51+
Nodes.push_back(Pair.second.get());
52+
// Sort them based on which one comes first in the BB.
53+
sort(Nodes, [](DGNode *N1, DGNode *N2) {
54+
return N1->getInstruction()->comesBefore(N2->getInstruction());
55+
});
56+
for (auto *N : Nodes)
57+
N->print(OS, /*PrintDeps=*/true);
58+
}
59+
60+
void DependencyGraph::dump() const {
61+
print(dbgs());
62+
dbgs() << "\n";
63+
}
64+
#endif // NDEBUG

llvm/unittests/Transforms/Vectorize/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
add_subdirectory(SandboxVectorizer)
2+
13
set(LLVM_LINK_COMPONENTS
24
Analysis
35
Core
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
set(LLVM_LINK_COMPONENTS
2+
Analysis
3+
Core
4+
Vectorize
5+
AsmParser
6+
TargetParser
7+
SandboxIR
8+
)
9+
10+
add_llvm_unittest(SandboxVectorizerTests
11+
DependencyGraphTest.cpp
12+
)
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
//===- DependencyGraphTest.cpp --------------------------------------------===//
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/DependencyGraph.h"
10+
#include "llvm/AsmParser/Parser.h"
11+
#include "llvm/SandboxIR/SandboxIR.h"
12+
#include "llvm/Support/SourceMgr.h"
13+
#include "gmock/gmock-matchers.h"
14+
#include "gtest/gtest.h"
15+
16+
using namespace llvm;
17+
18+
struct DependencyGraphTest : public testing::Test {
19+
LLVMContext C;
20+
std::unique_ptr<Module> M;
21+
22+
void parseIR(LLVMContext &C, const char *IR) {
23+
SMDiagnostic Err;
24+
M = parseAssemblyString(IR, Err, C);
25+
if (!M)
26+
Err.print("DependencyGraphTest", errs());
27+
}
28+
};
29+
30+
TEST_F(DependencyGraphTest, Basic) {
31+
parseIR(C, R"IR(
32+
define void @foo(ptr %ptr, i8 %v0, i8 %v1) {
33+
store i8 %v0, ptr %ptr
34+
store i8 %v1, ptr %ptr
35+
ret void
36+
}
37+
)IR");
38+
llvm::Function *LLVMF = &*M->getFunction("foo");
39+
sandboxir::Context Ctx(C);
40+
auto *F = Ctx.createFunction(LLVMF);
41+
auto *BB = &*F->begin();
42+
auto It = BB->begin();
43+
auto *S0 = cast<sandboxir::StoreInst>(&*It++);
44+
auto *S1 = cast<sandboxir::StoreInst>(&*It++);
45+
auto *Ret = cast<sandboxir::ReturnInst>(&*It++);
46+
sandboxir::DependencyGraph DAG;
47+
DAG.extend(BB);
48+
49+
sandboxir::DGNode *N0 = DAG.getNode(S0);
50+
sandboxir::DGNode *N1 = DAG.getNode(S1);
51+
sandboxir::DGNode *N2 = DAG.getNode(Ret);
52+
// Check getInstruction().
53+
EXPECT_EQ(N0->getInstruction(), S0);
54+
EXPECT_EQ(N1->getInstruction(), S1);
55+
// Check hasMemPred()
56+
EXPECT_TRUE(N1->hasMemPred(N0));
57+
EXPECT_FALSE(N0->hasMemPred(N1));
58+
59+
// Check memPreds().
60+
EXPECT_TRUE(N0->memPreds().empty());
61+
EXPECT_THAT(N1->memPreds(), testing::ElementsAre(N0));
62+
EXPECT_THAT(N2->memPreds(), testing::ElementsAre(N1));
63+
}

0 commit comments

Comments
 (0)