9#include "slang/ast/ASTVisitor.h"
10#include "slang/ast/Expression.h"
11#include "slang/ast/statements/MiscStatements.h"
12#include "slang/ast/symbols/CompilationUnitSymbols.h"
13#include "slang/ast/symbols/InstanceSymbols.h"
14#include "slang/ast/symbols/MemberSymbols.h"
15#include "slang/ast/symbols/VariableSymbols.h"
16#include "slang/syntax/AllSyntax.h"
17#include "slang/text/SourceManager.h"
19#include "mlir/IR/Location.h"
20#include "mlir/Support/FileUtilities.h"
22#include "llvm/ADT/StringExtras.h"
34inline bool definitelyOutsideMainBuffer(
const T &t, slang::BufferID bufferId) {
35 if constexpr (
requires {
40 return r.buffer() != bufferId;
43 if constexpr (
requires {
46 auto r = t.sourceRange;
47 if (r.start().valid() && r.end().valid())
48 return r.start().buffer() != bufferId && r.end().buffer() != bufferId;
51 if constexpr (
requires { t.getSyntax(); }) {
52 if (
auto *syn = t.getSyntax()) {
53 auto r = syn->sourceRange();
54 if (r.start().valid() && r.end().valid())
55 return r.start().buffer() != bufferId && r.end().buffer() != bufferId;
63 : slang::ast::ASTVisitor<VerilogIndexer, slang::ast::VisitFlags::AllGood> {
65 slang::ast::ASTVisitor<VerilogIndexer, slang::ast::VisitFlags::AllGood>;
66 VerilogIndexer(VerilogIndex &index) : index(index) {}
70 void recurseIfInMainBuffer(
const T &node) {
71 if (definitelyOutsideMainBuffer(node, index.getBufferId()))
76 void insertSymbol(
const slang::ast::Symbol *symbol, slang::SourceRange range,
77 bool isDefinition =
true) {
78 if (symbol->name.empty())
80 assert(range.start().valid() && range.end().valid() &&
81 "range must be valid");
85 if (range.start().offset() >= range.end().offset()) {
89 index.insertSymbol(symbol, range, isDefinition);
92 void insertSymbol(
const slang::ast::Symbol *symbol,
93 slang::SourceLocation from,
bool isDefinition =
false) {
94 if (symbol->name.empty())
96 assert(from.valid() &&
"location must be valid");
97 insertSymbol(symbol, slang::SourceRange(from, from + symbol->name.size()),
102 void visitExpression(
const slang::ast::Expression &expr) {
103 auto *symbol = expr.getSymbolReference(
true);
106 insertSymbol(symbol, expr.sourceRange,
false);
109 void visitSymbol(
const slang::ast::Symbol &symbol) {
110 insertSymbol(&symbol, symbol.location,
true);
113 void visit(
const slang::ast::NetSymbol &expr) {
114 insertSymbol(&expr, expr.location,
true);
115 recurseIfInMainBuffer(expr);
118 void visit(
const slang::ast::VariableSymbol &expr) {
119 insertSymbol(&expr, expr.location,
true);
120 recurseIfInMainBuffer(expr);
123 void visit(
const slang::ast::ExplicitImportSymbol &expr) {
124 auto *def = expr.package();
128 if (
auto *syn = expr.getSyntax()) {
129 if (
auto *item = syn->as_if<slang::syntax::PackageImportItemSyntax>()) {
130 insertSymbol(def, item->package.location(),
false);
133 recurseIfInMainBuffer(expr);
136 void visit(
const slang::ast::WildcardImportSymbol &expr) {
137 auto *def = expr.getPackage();
141 if (
auto *syn = expr.getSyntax()) {
142 if (
auto *item = syn->as_if<slang::syntax::PackageImportItemSyntax>()) {
143 insertSymbol(def, item->package.location(),
false);
146 recurseIfInMainBuffer(expr);
149 void visit(
const slang::ast::InstanceBodySymbol &expr) {
151 for (
const auto *symbol : expr.getPortList())
152 index.insertSymbolDefinition(symbol);
153 recurseIfInMainBuffer(expr);
156 void visit(
const slang::ast::InstanceSymbol &expr) {
157 auto *def = &expr.getDefinition();
162 insertSymbol(def, def->location,
true);
168 ->as_if<slang::syntax::HierarchicalInstanceSyntax>())
171 ->as_if<slang::syntax::HierarchyInstantiationSyntax>())
173 insertSymbol(def, modInst->type.location(),
false);
176 insertSymbol(def, expr.location,
false);
177 recurseIfInMainBuffer(expr);
180 void visit(
const slang::ast::VariableDeclStatement &expr) {
181 insertSymbol(&expr.symbol, expr.sourceRange,
true);
182 recurseIfInMainBuffer(expr);
185 template <
typename T>
186 void visit(
const T &node) {
187 if constexpr (std::is_base_of_v<slang::ast::Expression, T>)
188 visitExpression(node);
189 if constexpr (std::is_base_of_v<slang::ast::Symbol, T>)
192 recurseIfInMainBuffer(node);
195 template <
typename T>
196 void visitInvalid(
const T &t) {}
201 const auto &root = compilation.getRoot();
202 VerilogIndexer visitor(*
this);
205 for (
auto *package : compilation.getPackages()) {
209 package->visit(visitor);
213 for (
auto *inst : root.topInstances) {
217 inst->body.visit(visitor);
226 if (toParse.contains(
'\n'))
230 SmallVector<StringRef, 3> fileLineColStrs;
234 for (
auto chunk : llvm::split(toParse,
", ")) {
235 fileLineColStrs.clear();
236 chunk.split(fileLineColStrs,
':');
237 if (fileLineColStrs.size() != 3)
240 auto filePathMaybeEmpty = fileLineColStrs[0].trim();
242 if (!filePathMaybeEmpty.empty())
243 filePath = filePathMaybeEmpty;
245 auto line = fileLineColStrs[1].trim();
246 auto column = fileLineColStrs[2].trim();
250 if (line.getAsInteger(10, lineInt))
255 SmallVector<std::pair<StringRef, const char *>> columns;
258 if (column.starts_with(
'{') && column.ends_with(
'}')) {
260 for (
auto str : llvm::split(column.drop_back().drop_front(),
',')) {
261 columns.emplace_back(str,
262 first ? filePathMaybeEmpty.data() : str.data());
266 columns.push_back({column, filePathMaybeEmpty.data()});
270 for (
auto [column, start] : columns) {
272 if (column.getAsInteger(10, columnInt))
274 auto loc = mlir::FileLineColRange::get(&
mlirContext, filePath,
275 lineInt - 1, columnInt - 1,
276 lineInt - 1, columnInt - 1);
277 const char *
end = column.end();
286 auto getMainBuffer = sourceMgr.getSourceText(
getBufferId());
287 StringRef text(getMainBuffer);
294 StringRef start =
"// @[";
295 auto loc = text.find(start);
296 if (loc == StringRef::npos)
299 text = text.drop_front(loc + start.size());
300 auto endPos = text.find_first_of(
"]\n");
301 if (endPos == StringRef::npos)
303 auto toParse = text.take_front(endPos);
310 slang::SourceRange from,
bool isDefinition) {
311 assert(from.start().valid() && from.end().valid());
314 if (from.start().offset() >= from.end().offset())
317 auto lhsBufferId = from.start().buffer();
318 auto rhsBufferId = from.end().buffer();
319 if (lhsBufferId.getId() != rhsBufferId.getId() || !rhsBufferId.valid() ||
320 !lhsBufferId.valid())
325 const auto *lhsBound = buffer.data() + from.start().offset();
326 const auto *rhsBound = buffer.data() + from.end().offset();
328 if (lhsBound >= rhsBound)
339 if (!symbol->location)
341 auto size = symbol->name.size() ? symbol->name.size() : 1;
342 auto range = slang::SourceRange(symbol->location, symbol->location + size);
assert(baseType &&"element must be base type")
ReferenceMap references
References of symbols.
void parseSourceLocation()
Parse source location emitted by ExportVerilog.
void insertSymbolDefinition(const slang::ast::Symbol *symbol)
mlir::MLIRContext mlirContext
void insertSymbol(const slang::ast::Symbol *symbol, slang::SourceRange from, bool isDefinition=false)
Register a reference to a symbol symbol from from.
const slang::BufferID & getBufferId() const
MapT intervalMap
An interval map containing a corresponding definition mapped to a source interval.
void initialize(slang::ast::Compilation &compilation)
Initialize the index with the given compilation unit.
const slang::SourceManager & getSlangSourceManager() const