CIRCT  20.0.0git
HierarchicalNames.cpp
Go to the documentation of this file.
1 //===- Expressions.cpp - Slang expression conversion ----------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
10 
11 using namespace circt;
12 using namespace ImportVerilog;
13 
14 namespace {
15 struct HierPathValueExprVisitor {
16  Context &context;
17  Location loc;
18  OpBuilder &builder;
19 
20  // Such as `sub.a`, the `sub` is the outermost module for the hierarchical
21  // variable `a`.
22  const slang::ast::Symbol &outermostModule;
23 
24  HierPathValueExprVisitor(Context &context, Location loc,
25  const slang::ast::Symbol &outermostModule)
26  : context(context), loc(loc), builder(context.builder),
27  outermostModule(outermostModule) {}
28 
29  // Handle hierarchical values
30  LogicalResult visit(const slang::ast::HierarchicalValueExpression &expr) {
31  auto *currentInstBody =
32  expr.symbol.getParentScope()->getContainingInstance();
33  auto *outermostInstBody =
34  outermostModule.as_if<slang::ast::InstanceBodySymbol>();
35 
36  // Like module Foo; int a; Foo.a; endmodule.
37  // Ignore "Foo.a" invoked by this module itself.
38  if (currentInstBody == outermostInstBody)
39  return success();
40 
41  auto hierName = builder.getStringAttr(expr.symbol.name);
42  const slang::ast::InstanceBodySymbol *parentInstBody = nullptr;
43 
44  // Collect hierarchical names that are added to the port list.
45  std::function<void(const slang::ast::InstanceBodySymbol *, bool)>
46  collectHierarchicalPaths = [&](auto sym, bool isUpward) {
47  // Here we use "sameHierPaths" to avoid collecting the repeat
48  // hierarchical names on the same path.
49  if (!context.sameHierPaths.contains(hierName) ||
50  !context.hierPaths.contains(sym)) {
51  context.hierPaths[sym].push_back(
52  HierPathInfo{hierName,
53  {},
54  isUpward ? slang::ast::ArgumentDirection::Out
55  : slang::ast::ArgumentDirection::In,
56  &expr.symbol});
57  context.sameHierPaths.insert(hierName);
58  }
59 
60  // Iterate up from the current instance body symbol until meeting the
61  // outermost module.
62  parentInstBody =
63  sym->parentInstance->getParentScope()->getContainingInstance();
64  if (!parentInstBody)
65  return;
66 
67  if (isUpward) {
68  // Avoid collecting hierarchical names into the outermost module.
69  if (parentInstBody && parentInstBody != outermostInstBody) {
70  hierName =
71  builder.getStringAttr(sym->parentInstance->name +
72  llvm::Twine(".") + hierName.getValue());
73  collectHierarchicalPaths(parentInstBody, isUpward);
74  }
75  } else {
76  if (parentInstBody && parentInstBody != currentInstBody)
77  collectHierarchicalPaths(parentInstBody, isUpward);
78  }
79  };
80 
81  // Determine whether hierarchical names are upward or downward.
82  auto *tempInstBody = currentInstBody;
83  while (tempInstBody) {
84  tempInstBody = tempInstBody->parentInstance->getParentScope()
85  ->getContainingInstance();
86  if (tempInstBody == outermostInstBody) {
87  collectHierarchicalPaths(currentInstBody, true);
88  return success();
89  }
90  }
91 
92  hierName = builder.getStringAttr(currentInstBody->parentInstance->name +
93  llvm::Twine(".") + hierName.getValue());
94  collectHierarchicalPaths(outermostInstBody, false);
95  return success();
96  }
97 
98  /// TODO:Skip all others.
99  /// But we should output a warning to display which symbol had been skipped.
100  /// However, to ensure we can test smoothly, we didn't do that.
101  template <typename T>
102  LogicalResult visit(T &&node) {
103  return success();
104  }
105 
106  LogicalResult visitInvalid(const slang::ast::Expression &expr) {
107  mlir::emitError(loc, "invalid expression");
108  return failure();
109  }
110 };
111 } // namespace
112 
113 LogicalResult
114 Context::collectHierarchicalValues(const slang::ast::Expression &expr,
115  const slang::ast::Symbol &outermostModule) {
116  auto loc = convertLocation(expr.sourceRange);
117  return expr.visit(HierPathValueExprVisitor(*this, loc, outermostModule));
118 }
119 
120 /// Traverse the instance body.
121 namespace {
122 struct InstBodyVisitor {
123  Context &context;
124  Location loc;
125 
126  InstBodyVisitor(Context &context, Location loc)
127  : context(context), loc(loc) {}
128 
129  // Handle instances.
130  LogicalResult visit(const slang::ast::InstanceSymbol &instNode) {
131  return context.traverseInstanceBody(instNode.body);
132  }
133 
134  // Handle variables.
135  LogicalResult visit(const slang::ast::VariableSymbol &varNode) {
136  auto &outermostModule = varNode.getParentScope()->asSymbol();
137  if (const auto *init = varNode.getInitializer())
138  if (failed(context.collectHierarchicalValues(*init, outermostModule)))
139  return failure();
140  return success();
141  }
142 
143  // Handle nets.
144  LogicalResult visit(const slang::ast::NetSymbol &netNode) {
145  auto &outermostModule = netNode.getParentScope()->asSymbol();
146  if (const auto *init = netNode.getInitializer())
147  if (failed(context.collectHierarchicalValues(*init, outermostModule)))
148  return failure();
149  return success();
150  }
151 
152  // Handle continuous assignments.
153  LogicalResult visit(const slang::ast::ContinuousAssignSymbol &assignNode) {
154  const auto &expr =
155  assignNode.getAssignment().as<slang::ast::AssignmentExpression>();
156 
157  // Such as `sub.a`, the `sub` is the outermost module for the hierarchical
158  // variable `a`.
159  auto &outermostModule = assignNode.getParentScope()->asSymbol();
160  if (expr.left().hasHierarchicalReference())
161  if (failed(
162  context.collectHierarchicalValues(expr.left(), outermostModule)))
163  return failure();
164 
165  if (expr.right().hasHierarchicalReference())
166  if (failed(
167  context.collectHierarchicalValues(expr.right(), outermostModule)))
168  return failure();
169 
170  return success();
171  }
172 
173  /// TODO:Skip all others.
174  /// But we should output a warning to display which symbol had been skipped.
175  /// However, to ensure we can test smoothly, we didn't do that.
176  template <typename T>
177  LogicalResult visit(T &&node) {
178  return success();
179  }
180 };
181 }; // namespace
182 
183 LogicalResult Context::traverseInstanceBody(const slang::ast::Symbol &symbol) {
184  if (auto *instBodySymbol = symbol.as_if<slang::ast::InstanceBodySymbol>())
185  for (auto &member : instBodySymbol->members()) {
186  auto loc = convertLocation(member.location);
187  if (failed(member.visit(InstBodyVisitor(*this, loc))))
188  return failure();
189  }
190  return success();
191 }
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
Definition: DebugAnalysis.h:21
A helper class to facilitate the conversion from a Slang AST to MLIR operations.
LogicalResult traverseInstanceBody(const slang::ast::Symbol &symbol)
DenseSet< StringAttr > sameHierPaths
It's used to collect the repeat hierarchical names on the same path.
DenseMap< const slang::ast::InstanceBodySymbol *, SmallVector< HierPathInfo > > hierPaths
Collect all hierarchical names used for the per module/instance.
LogicalResult collectHierarchicalValues(const slang::ast::Expression &expr, const slang::ast::Symbol &outermostModule)
Location convertLocation(slang::SourceLocation loc)
Convert a slang SourceLocation into an MLIR Location.
Hierarchical path information.