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,
87 const SubroutineSymbol *currentFunc =
nullptr;
101 void handle(
const SubroutineSymbol &func) {
102 llvm::SaveAndRestore guard(currentFunc, &func);
108 void handle(
const NamedValueExpression &expr) {
112 auto &var = expr.symbol;
115 if (var.kind == SymbolKind::ClassProperty)
119 if (var.kind == SymbolKind::FormalArgument)
125 if (var.kind == SymbolKind::Parameter ||
126 var.kind == SymbolKind::EnumValue || var.kind == SymbolKind::Genvar ||
127 var.kind == SymbolKind::Specparam)
141 capturedVars[currentFunc].insert(&var);
145 void handle(
const CallExpression &expr) {
147 if (
auto *
const *callee =
148 std::get_if<const SubroutineSymbol *>(&expr.subroutine))
149 callers[*callee].insert(currentFunc);
157 void propagateCaptures() {
158 using WorkItem = std::pair<const SubroutineSymbol *, const ValueSymbol *>;
161 for (
auto &[func, _] : callers) {
164 auto it = capturedVars.find(func);
165 if (it == capturedVars.end())
169 for (
auto *var : it->second)
170 worklist.insert({func, var});
173 while (!worklist.empty()) {
174 auto [func, cap] = worklist.pop_back_val();
175 auto callersIt = callers.find(func);
176 if (callersIt == callers.end())
178 for (
auto *caller : callersIt->second)
180 if (capturedVars[caller].insert(cap))
181 worklist.insert({caller, cap});
190 CaptureWalker walker;
192 walker.propagateCaptures();
193 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.