CIRCT 20.0.0git
Loading...
Searching...
No Matches
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
11using namespace circt;
12using namespace ImportVerilog;
13
14namespace {
15struct 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
113LogicalResult
114Context::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.
121namespace {
122struct 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
183LogicalResult 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.
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.