15 #include "mlir/IR/Threading.h"
16 #include "llvm/Support/Debug.h"
18 using namespace circt;
30 this->innerSymTblOp = op;
32 walkSymbols(op, [&](StringAttr name,
const InnerSymTarget &target) {
33 auto it = symbolTable.try_emplace(name, target);
35 assert(it.second &&
"repeated symbol found");
42 return op->emitError(
"expected operation to have InnerSymbolTable trait");
45 auto result = walkSymbols(
46 op, [&](StringAttr name,
const InnerSymTarget &target) -> LogicalResult {
47 auto it = table.try_emplace(name, target);
50 auto existing = it.first->second;
53 .
append(
"redefinition of inner symbol named '", name.strref(),
"'")
54 .attachNote(existing.getOp()->getLoc())
55 .append(
"see existing inner symbol definition here");
64 auto walkSym = [&](StringAttr name,
const InnerSymTarget &target) {
65 assert(name && !name.getValue().empty());
66 return callback(name, target);
69 auto walkSyms = [&](hw::InnerSymAttr symAttr,
71 assert(baseTarget.getField() == 0);
72 for (
auto symProp : symAttr) {
73 if (failed(walkSym(symProp.getName(),
75 baseTarget, symProp.getFieldID()))))
83 !op->walk<mlir::WalkOrder::PreOrder>([&](Operation *curOp) -> WalkResult {
84 if (auto symOp = dyn_cast<InnerSymbolOpInterface>(curOp))
85 if (auto symAttr = symOp.getInnerSymAttr())
86 if (failed(walkSyms(symAttr, InnerSymTarget(symOp))))
87 return WalkResult::interrupt();
90 if (auto mod = dyn_cast<PortList>(curOp)) {
91 for (auto [i, port] : llvm::enumerate(mod.getPortList())) {
92 if (auto symAttr = port.getSym())
93 if (failed(walkSyms(symAttr, InnerSymTarget(i, curOp))))
94 return WalkResult::interrupt();
97 return WalkResult::advance();
107 return symbolTable.lookup(name);
116 auto result = lookup(name);
117 if (result.isOpOnly())
118 return result.getOp();
124 if (
auto innerSymOp = dyn_cast<InnerSymbolOpInterface>(op))
125 return innerSymOp.getInnerNameAttr();
136 auto getBase = [](
auto &target) -> hw::InnerSymAttr {
138 if (
auto mod = dyn_cast<PortList>(target.
getOp())) {
140 return mod.getPort(target.
getPort()).getSym();
144 if (
auto symOp = dyn_cast<InnerSymbolOpInterface>(target.
getOp()))
145 return symOp.getInnerSymAttr();
150 if (
auto base = getBase(target))
151 return base.getSymIfExists(target.
getField());
161 auto it = symbolTables.try_emplace(op,
nullptr);
163 it.first->second = ::std::make_unique<InnerSymbolTable>(op);
164 return *it.first->second;
170 SmallVector<Operation *> innerSymTableOps(llvm::make_filter_range(
171 llvm::make_pointer_range(innerRefNSOp->getRegion(0).front()),
173 return op->hasTrait<OpTrait::InnerSymbolTable>();
177 llvm::for_each(innerSymTableOps,
178 [&](
auto *op) { symbolTables.try_emplace(op,
nullptr); });
181 return mlir::failableParallelForEach(
182 innerRefNSOp->getContext(), innerSymTableOps, [&](
auto *op) {
183 auto it = symbolTables.find(op);
184 assert(it != symbolTables.end());
186 auto result = InnerSymbolTable::get(op);
189 it->second = std::make_unique<InnerSymbolTable>(std::move(*result));
201 auto *mod =
symTable.lookup(inner.getModule());
209 auto *mod =
symTable.lookup(inner.getModule());
228 SymbolTable symbolTable(op);
233 auto verifySymbolUserFn = [&](Operation *op) -> WalkResult {
234 if (
auto user = dyn_cast<InnerRefUserOpInterface>(op))
235 return WalkResult(user.verifyInnerRefs(ns));
236 return WalkResult::advance();
239 SmallVector<Operation *> topLevelOps;
240 for (
auto &op : op->getRegion(0).front()) {
242 if (op.getNumRegions() != 0) {
243 topLevelOps.push_back(&op);
247 if (verifySymbolUserFn(&op).wasInterrupted())
250 return mlir::failableParallelForEach(
251 op->getContext(), topLevelOps, [&](Operation *op) {
252 return success(!op->walk(verifySymbolUserFn).wasInterrupted());
260 op->hasTrait<mlir::OpTrait::SymbolTable>();
264 const mlir::RegisteredOperationName *opInfo) {
266 opInfo->hasTrait<mlir::OpTrait::SymbolTable>();
assert(baseType &&"element must be base type")
static StringAttr append(StringAttr base, const Twine &suffix)
Return a attribute with the specified suffix appended.
The target of an inner symbol, the entity the symbol is a handle for.
Operation * getOp() const
Return the target's base operation. For ports, this is the module.
auto getField() const
Return the target's fieldID.
static InnerSymTarget getTargetForSubfield(const InnerSymTarget &base, size_t fieldID)
Return a target to the specified field within the given base.
auto getPort() const
Return the target's port, if valid. Check "isPort()".
bool isPort() const
Return if this targets a port.
This class represents a collection of InnerSymbolTable's.
LogicalResult populateAndVerifyTables(Operation *innerRefNSOp)
Populate tables in parallel for all InnerSymbolTable operations in the given InnerRefNamespace operat...
InnerSymbolTable & getInnerSymbolTable(Operation *op)
Get or create the InnerSymbolTable for the specified operation.
A table of inner symbols and their resolutions.
InnerSymTarget lookup(StringRef name) const
Look up a symbol with the specified name, returning empty InnerSymTarget if no such name exists.
DenseMap< StringAttr, InnerSymTarget > TableTy
static StringAttr getInnerSymbol(Operation *op)
Get InnerSymbol for an operation.
InnerSymbolTable(Operation *op)
Build an inner symbol table for the given operation.
llvm::function_ref< LogicalResult(StringAttr, const InnerSymTarget &)> InnerSymCallbackFn
static RetTy walkSymbols(Operation *op, FuncTy &&callback)
Walk the given IST operation and invoke the callback for all encountered inner symbols.
Operation * lookupOp(StringRef name) const
Look up a symbol with the specified name, returning null if no such name exists or doesn't target jus...
static FailureOr< InnerSymbolTable > get(Operation *op)
Construct an InnerSymbolTable, checking for verification failure.
This trait is for operations that define a scope for resolving InnerRef's, and provides verification ...
A trait for inner symbol table functionality on an operation.
Direction get(bool isOutput)
Returns an output direction if isOutput is true, otherwise returns an input direction.
LogicalResult verifyInnerRefNamespace(Operation *op)
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
static bool classof(mlir::Operation *op)
Return if this operation is explicitly an IRN or appears compatible.
This class represents the namespace in which InnerRef's can be resolved.
InnerSymTarget lookup(hw::InnerRefAttr inner) const
Resolve the InnerRef to its target within this namespace, returning empty target if no such name exis...
Operation * lookupOp(hw::InnerRefAttr inner) const
Resolve the InnerRef to its target within this namespace, returning empty target if no such name exis...
InnerSymbolTableCollection & innerSymTables