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:
82 :
public ASTVisitor<CaptureWalker, true,
89 const SubroutineSymbol *currentFunc =
nullptr;
94 mlir::DenseSet<const InstanceBodySymbol *> visitedInstanceBodies;
105 void handle(
const SubroutineSymbol &func) {
106 llvm::SaveAndRestore guard(currentFunc, &func);
112 void handle(
const NamedValueExpression &expr) {
116 auto &var = expr.symbol;
119 if (var.kind == SymbolKind::ClassProperty)
123 if (var.kind == SymbolKind::FormalArgument)
129 if (var.kind == SymbolKind::Parameter ||
130 var.kind == SymbolKind::EnumValue || var.kind == SymbolKind::Genvar ||
131 var.kind == SymbolKind::Specparam)
145 capturedVars[currentFunc].insert(&var);
149 void handle(
const CallExpression &expr) {
151 if (
auto *
const *callee =
152 std::get_if<const SubroutineSymbol *>(&expr.subroutine))
153 callers[*callee].insert(currentFunc);
160 void handle(
const InstanceBodySymbol &instance) {
161 if (visitedInstanceBodies.insert(&instance).second) {
162 visitDefault(instance);
170 void propagateCaptures() {
171 using WorkItem = std::pair<const SubroutineSymbol *, const ValueSymbol *>;
174 for (
auto &[func, _] : callers) {
177 auto it = capturedVars.find(func);
178 if (it == capturedVars.end())
182 for (
auto *var : it->second)
183 worklist.insert({func, var});
186 while (!worklist.empty()) {
187 auto [func, cap] = worklist.pop_back_val();
188 auto callersIt = callers.find(func);
189 if (callersIt == callers.end())
191 for (
auto *caller : callersIt->second)
193 if (capturedVars[caller].insert(cap))
194 worklist.insert({caller, cap});
203 CaptureWalker walker;
205 walker.propagateCaptures();
206 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....
CaptureMap analyzeFunctionCaptures(const slang::ast::RootSymbol &root)
Analyze the AST rooted at root to determine which variables each function captures.
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.