Skip to content

Commit 8cb12b5

Browse files
authored
[Support] Add relative path caching to InstancePathCache (#8489)
This commit adds infrastructure for caching relative instance paths between modules in the InstanceGraph. It adds a relativePathsCache field to InstancePathCache to store paths between arbitrary module pairs
1 parent 6ca2c60 commit 8cb12b5

File tree

3 files changed

+75
-33
lines changed

3 files changed

+75
-33
lines changed

include/circt/Support/InstanceGraph.h

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -345,17 +345,21 @@ inline llvm::raw_ostream &operator<<(llvm::raw_ostream &os,
345345
return os;
346346
}
347347

348-
/// A data structure that caches and provides absolute paths to module
348+
/// A data structure that caches and provides paths to module
349349
/// instances in the IR.
350350
struct InstancePathCache {
351351
/// The instance graph of the IR.
352352
InstanceGraph &instanceGraph;
353353

354354
explicit InstancePathCache(InstanceGraph &instanceGraph)
355355
: instanceGraph(instanceGraph) {}
356+
357+
// Return all absolute paths from the top-level node to the given module.
356358
ArrayRef<InstancePath> getAbsolutePaths(ModuleOpInterface op);
357-
ArrayRef<InstancePath> getAbsolutePaths(ModuleOpInterface op,
358-
InstanceGraphNode *top);
359+
360+
// Return all relative paths from the given node to the given module.
361+
ArrayRef<InstancePath> getRelativePaths(ModuleOpInterface op,
362+
InstanceGraphNode *node);
359363

360364
/// Replace an InstanceOp. This is required to keep the cache updated.
361365
void replaceInstance(InstanceOpInterface oldOp, InstanceOpInterface newOp);
@@ -367,11 +371,18 @@ struct InstancePathCache {
367371
InstancePath prependInstance(InstanceOpInterface inst, InstancePath path);
368372

369373
private:
374+
using PathsCache = DenseMap<Operation *, ArrayRef<InstancePath>>;
375+
ArrayRef<InstancePath> getPaths(ModuleOpInterface op, InstanceGraphNode *top,
376+
PathsCache &cache);
377+
370378
/// An allocator for individual instance paths and entire path lists.
371379
llvm::BumpPtrAllocator allocator;
372380

373381
/// Cached absolute instance paths.
374-
DenseMap<Operation *, ArrayRef<InstancePath>> absolutePathsCache;
382+
PathsCache absolutePathsCache;
383+
384+
/// Cached relative instance paths.
385+
DenseMap<InstanceGraphNode *, PathsCache> relativePathsCache;
375386
};
376387

377388
} // namespace igraph

lib/Support/InstanceGraph.cpp

Lines changed: 43 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -226,36 +226,46 @@ static InstancePath empty{};
226226

227227
ArrayRef<InstancePath>
228228
InstancePathCache::getAbsolutePaths(ModuleOpInterface op) {
229-
return getAbsolutePaths(op, instanceGraph.getTopLevelNode());
229+
return getPaths(op, instanceGraph.getTopLevelNode(), absolutePathsCache);
230230
}
231231

232-
// NOLINTBEGIN(misc-no-recursion)
233232
ArrayRef<InstancePath>
234-
InstancePathCache::getAbsolutePaths(ModuleOpInterface op,
235-
InstanceGraphNode *top) {
233+
InstancePathCache::getRelativePaths(ModuleOpInterface op,
234+
InstanceGraphNode *node) {
235+
if (node == instanceGraph.getTopLevelNode())
236+
return getAbsolutePaths(op);
237+
return getPaths(op, node, relativePathsCache[node]);
238+
}
239+
240+
// NOLINTBEGIN(misc-no-recursion)
241+
ArrayRef<InstancePath> InstancePathCache::getPaths(ModuleOpInterface op,
242+
InstanceGraphNode *top,
243+
PathsCache &cache) {
236244
InstanceGraphNode *node = instanceGraph[op];
237245

238246
if (node == top) {
239247
return empty;
240248
}
241249

242250
// Fast path: hit the cache.
243-
auto cached = absolutePathsCache.find(op);
244-
if (cached != absolutePathsCache.end())
251+
auto cached = cache.find(op);
252+
if (cached != cache.end())
245253
return cached->second;
246254

247255
// For each instance, collect the instance paths to its parent and append the
248256
// instance itself to each.
249257
SmallVector<InstancePath, 8> extendedPaths;
250258
for (auto *inst : node->uses()) {
251259
if (auto module = inst->getParent()->getModule()) {
252-
auto instPaths = getAbsolutePaths(module);
260+
auto instPaths = getPaths(module, top, cache);
253261
extendedPaths.reserve(instPaths.size());
254262
for (auto path : instPaths) {
255263
extendedPaths.push_back(appendInstance(
256264
path, cast<InstanceOpInterface>(*inst->getInstance())));
257265
}
258-
} else {
266+
} else if (inst->getParent() == top) {
267+
// Special case when `inst` is a top-level instance and
268+
// `inst->getParent()` is a pseudo top-level node.
259269
extendedPaths.emplace_back(empty);
260270
}
261271
}
@@ -267,7 +277,7 @@ InstancePathCache::getAbsolutePaths(ModuleOpInterface op,
267277
std::copy(extendedPaths.begin(), extendedPaths.end(), paths);
268278
pathList = ArrayRef<InstancePath>(paths, extendedPaths.size());
269279
}
270-
absolutePathsCache.insert({op, pathList});
280+
cache.insert({op, pathList});
271281
return pathList;
272282
}
273283
// NOLINTEND(misc-no-recursion)
@@ -331,29 +341,33 @@ void InstancePathCache::replaceInstance(InstanceOpInterface oldOp,
331341
return llvm::any_of(
332342
paths, [&](InstancePath p) { return llvm::is_contained(p, oldOp); });
333343
};
334-
335-
for (auto &iter : absolutePathsCache) {
336-
if (!instanceExists(iter.getSecond()))
337-
continue;
338-
SmallVector<InstancePath, 8> updatedPaths;
339-
for (auto path : iter.getSecond()) {
340-
const auto *iter = llvm::find(path, oldOp);
341-
if (iter == path.end()) {
342-
// path does not contain the oldOp, just copy it as is.
343-
updatedPaths.push_back(path);
344+
auto updateCache = [&](PathsCache &cache) {
345+
for (auto &iter : cache) {
346+
if (!instanceExists(iter.getSecond()))
344347
continue;
348+
SmallVector<InstancePath, 8> updatedPaths;
349+
for (auto path : iter.getSecond()) {
350+
const auto *iter = llvm::find(path, oldOp);
351+
if (iter == path.end()) {
352+
// path does not contain the oldOp, just copy it as is.
353+
updatedPaths.push_back(path);
354+
continue;
355+
}
356+
auto *newPath = allocator.Allocate<InstanceOpInterface>(path.size());
357+
llvm::copy(path, newPath);
358+
newPath[iter - path.begin()] = newOp;
359+
updatedPaths.push_back(InstancePath(ArrayRef(newPath, path.size())));
345360
}
346-
auto *newPath = allocator.Allocate<InstanceOpInterface>(path.size());
347-
llvm::copy(path, newPath);
348-
newPath[iter - path.begin()] = newOp;
349-
updatedPaths.push_back(InstancePath(ArrayRef(newPath, path.size())));
361+
// Move the list of paths into the bump allocator for later quick
362+
// retrieval.
363+
auto *paths = allocator.Allocate<InstancePath>(updatedPaths.size());
364+
llvm::copy(updatedPaths, paths);
365+
iter.getSecond() = ArrayRef<InstancePath>(paths, updatedPaths.size());
350366
}
351-
// Move the list of paths into the bump allocator for later quick
352-
// retrieval.
353-
auto *paths = allocator.Allocate<InstancePath>(updatedPaths.size());
354-
llvm::copy(updatedPaths, paths);
355-
iter.getSecond() = ArrayRef<InstancePath>(paths, updatedPaths.size());
356-
}
367+
};
368+
updateCache(absolutePathsCache);
369+
for (auto &iter : relativePathsCache)
370+
updateCache(iter.getSecond());
357371
}
358372

359373
#include "circt/Support/InstanceGraphInterface.cpp.inc"

unittests/Dialect/HW/InstancePathTest.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,23 @@ TEST(InstancePathTest, Enumerate) {
4040
ASSERT_EQ(1ull, topPaths.size());
4141
}
4242

43+
TEST(InstancePathTest, RelativePath) {
44+
MLIRContext context;
45+
ModuleOp circuit = fixtures::createModule(&context);
46+
hw::InstanceGraph graph(circuit);
47+
igraph::InstancePathCache pathCache(graph);
48+
49+
auto cat = cast<HWModuleOp>(*circuit.getBody()->rbegin());
50+
auto alligator = cast<HWModuleOp>(*std::next(circuit.getBody()->begin()));
51+
auto catToAlligatorPaths = pathCache.getRelativePaths(cat, graph[alligator]);
52+
53+
ASSERT_EQ(1ull, catToAlligatorPaths.size());
54+
55+
ASSERT_EQ(2ull, catToAlligatorPaths[0].size());
56+
EXPECT_EQ("bear", catToAlligatorPaths[0][0].getInstanceName());
57+
EXPECT_EQ("cat", catToAlligatorPaths[0][1].getInstanceName());
58+
}
59+
4360
TEST(InstancePathTest, AppendPrependInstance) {
4461
MLIRContext context;
4562
ModuleOp circuit = fixtures::createModule(&context);

0 commit comments

Comments
 (0)