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()))))
82 if (
auto mod = dyn_cast<PortList>(op)) {
83 for (
auto [i, port] : llvm::enumerate(mod.getPortList())) {
84 if (
auto symAttr = port.getSym())
92 !op->walk<mlir::WalkOrder::PreOrder>([&](Operation *curOp) -> WalkResult {
93 if (auto symOp = dyn_cast<InnerSymbolOpInterface>(curOp))
94 if (auto symAttr = symOp.getInnerSymAttr())
95 if (failed(walkSyms(symAttr, InnerSymTarget(symOp))))
96 return WalkResult::interrupt();
98 return WalkResult::advance();
108 return symbolTable.lookup(name);
117 auto result = lookup(name);
118 if (result.isOpOnly())
119 return result.getOp();
125 if (
auto innerSymOp = dyn_cast<InnerSymbolOpInterface>(op))
126 return innerSymOp.getInnerNameAttr();
137 auto getBase = [](
auto &target) -> hw::InnerSymAttr {
139 if (
auto mod = dyn_cast<PortList>(target.
getOp())) {
141 return mod.getPort(target.
getPort()).getSym();
145 if (
auto symOp = dyn_cast<InnerSymbolOpInterface>(target.
getOp()))
146 return symOp.getInnerSymAttr();
151 if (
auto base = getBase(target))
152 return base.getSymIfExists(target.
getField());
162 auto it = symbolTables.try_emplace(op,
nullptr);
164 it.first->second = ::std::make_unique<InnerSymbolTable>(op);
165 return *it.first->second;
171 SmallVector<Operation *> innerSymTableOps(llvm::make_filter_range(
172 llvm::make_pointer_range(innerRefNSOp->getRegion(0).front()),
174 return op->hasTrait<OpTrait::InnerSymbolTable>();
178 llvm::for_each(innerSymTableOps,
179 [&](
auto *op) { symbolTables.try_emplace(op,
nullptr); });
182 return mlir::failableParallelForEach(
183 innerRefNSOp->getContext(), innerSymTableOps, [&](
auto *op) {
184 auto it = symbolTables.find(op);
185 assert(it != symbolTables.end());
187 auto result = InnerSymbolTable::get(op);
190 it->second = std::make_unique<InnerSymbolTable>(std::move(*result));
202 auto *mod = symTable.lookup(inner.getModule());
206 return innerSymTables.getInnerSymbolTable(mod).lookup(inner.getName());
210 auto *mod = symTable.lookup(inner.getModule());
214 return innerSymTables.getInnerSymbolTable(mod).lookupOp(inner.getName());
229 SymbolTable symbolTable(op);
234 auto verifySymbolUserFn = [&](Operation *op) -> WalkResult {
235 if (
auto user = dyn_cast<InnerRefUserOpInterface>(op))
236 return WalkResult(user.verifyInnerRefs(ns));
237 return WalkResult::advance();
240 SmallVector<Operation *> topLevelOps;
241 for (
auto &op : op->getRegion(0).front()) {
243 if (op.getNumRegions() != 0) {
244 topLevelOps.push_back(&op);
248 if (verifySymbolUserFn(&op).wasInterrupted())
251 return mlir::failableParallelForEach(
252 op->getContext(), topLevelOps, [&](Operation *op) {
253 return success(!op->walk(verifySymbolUserFn).wasInterrupted());
261 op->hasTrait<mlir::OpTrait::SymbolTable>();
265 const mlir::RegisteredOperationName *opInfo) {
267 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...