10#include "slang/ast/ASTVisitor.h"
11#include "llvm/ADT/MapVector.h"
12#include "llvm/Support/SaveAndRestore.h"
22 const SubroutineSymbol &func) {
23 for (
const Scope *scope = var.getParentScope(); scope;
24 scope = scope->asSymbol().getParentScope()) {
25 if (&scope->asSymbol() == &func)
27 if (scope->asSymbol().kind == SymbolKind::Subroutine)
49 for (
const Scope *scope = var.getParentScope(); scope;
50 scope = scope->asSymbol().getParentScope()) {
51 auto *body = scope->asSymbol().as_if<InstanceBodySymbol>();
54 return body->getDefinition().definitionKind == DefinitionKind::Interface;
63 for (
const Scope *scope = var.getParentScope(); scope;
64 scope = scope->asSymbol().getParentScope()) {
65 switch (scope->asSymbol().kind) {
66 case SymbolKind::Subroutine:
67 case SymbolKind::InstanceBody:
77 return kind == SymbolKind::Parameter || kind == SymbolKind::EnumValue ||
78 kind == SymbolKind::Genvar || kind == SymbolKind::Specparam;
83 for (
auto &elem : ref.path)
84 if (auto *inst = elem.symbol->as_if<InstanceSymbol>())
95 :
public ASTVisitor<CaptureWalker, VisitFlags::AllCanonical> {
99 const SubroutineSymbol *currentFunc =
nullptr;
104 mlir::DenseSet<const InstanceBodySymbol *> visitedInstanceBodies;
116 DenseMap<std::pair<const SubroutineSymbol *, const ValueSymbol *>,
117 const InstanceSymbol *>
118 hierCaptureRootInstance;
122 SmallVector<AmbiguousHierCapture> ambiguousHierCaptures;
126 void noteHierCapture(
const SubroutineSymbol &func,
const ValueSymbol &var,
127 const InstanceSymbol *rootInst) {
130 auto key = std::make_pair(&func, &var);
131 auto [it, inserted] = hierCaptureRootInstance.try_emplace(key, rootInst);
132 if (!inserted && it->second != rootInst)
133 ambiguousHierCaptures.push_back({&func, &var});
138 void handle(
const SubroutineSymbol &func) {
139 llvm::SaveAndRestore guard(currentFunc, &func);
145 void handle(
const NamedValueExpression &expr) {
149 auto &var = expr.symbol;
152 if (var.kind == SymbolKind::ClassProperty)
156 if (var.kind == SymbolKind::FormalArgument)
173 capturedVars[currentFunc].insert(&var);
179 void handle(
const HierarchicalValueExpression &expr) {
182 if (expr.ref.isViaIfacePort())
184 auto &var = expr.symbol;
188 capturedVars[currentFunc].insert(&var);
192 void handle(
const CallExpression &expr) {
194 if (
auto *
const *callee =
195 std::get_if<const SubroutineSymbol *>(&expr.subroutine))
196 callers[*callee].insert(currentFunc);
203 void handle(
const InstanceBodySymbol &instance) {
204 if (visitedInstanceBodies.insert(&instance).second) {
205 visitDefault(instance);
213 void propagateCaptures() {
214 using WorkItem = std::pair<const SubroutineSymbol *, const ValueSymbol *>;
217 for (
auto &[func, _] : callers) {
220 auto it = capturedVars.find(func);
221 if (it == capturedVars.end())
225 for (
auto *var : it->second)
226 worklist.insert({func, var});
229 while (!worklist.empty()) {
230 auto [func, cap] = worklist.pop_back_val();
231 auto callersIt = callers.find(func);
232 if (callersIt == callers.end())
234 for (
auto *caller : callersIt->second) {
236 noteHierCapture(*caller, *cap,
237 hierCaptureRootInstance.lookup({func, cap}));
238 if (capturedVars[caller].insert(cap))
239 worklist.insert({caller, cap});
250 const RootSymbol &root, SmallVectorImpl<AmbiguousHierCapture> &ambiguous) {
251 CaptureWalker walker;
253 walker.propagateCaptures();
254 ambiguous.assign(walker.ambiguousHierCaptures.begin(),
255 walker.ambiguousHierCaptures.end());
256 return std::move(walker.capturedVars);
static bool isLocalToFunction(const ValueSymbol &var, const SubroutineSymbol &func)
Check whether var is local to func.
static bool isGlobalVariable(const ValueSymbol &var)
Check whether var is a global variable.
static bool isVirtualInterfaceMemberAccess(const ValueSymbol &var)
Workaround for a slang deficiency: when accessing a member of a virtual interface (e....
const slang::ast::InstanceSymbol * getRootInstance(const slang::ast::HierarchicalReference &ref)
Return the first instance on a hierarchical reference path, i.e.
CaptureMap analyzeFunctionCaptures(const slang::ast::RootSymbol &root, SmallVectorImpl< AmbiguousHierCapture > &ambiguous)
Analyze the AST rooted at root to determine which variables each function captures: symbols reference...
bool isCompileTimeConstant(slang::ast::SymbolKind kind)
Return true if symbols of this kind are elaboration-time constants.
DenseMap< const slang::ast::SubroutineSymbol *, SmallSetVector< const slang::ast::ValueSymbol *, 4 > > CaptureMap
The result of capture analysis: for each function, the set of non-local, non-global variable symbols ...
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.