CIRCT  20.0.0git
InnerSymbolTable.h
Go to the documentation of this file.
1 //===- InnerSymbolTable.h - Inner Symbol Table -----------------*- C++ -*-===//
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 //
9 // This file declares the InnerSymbolTable and related classes, used for
10 // managing and tracking "inner symbols".
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #ifndef CIRCT_DIALECT_HW_INNERSYMBOLTABLE_H
15 #define CIRCT_DIALECT_HW_INNERSYMBOLTABLE_H
16 
18 #include "circt/Support/LLVM.h"
19 #include "mlir/IR/BuiltinAttributes.h"
20 #include "mlir/IR/SymbolTable.h"
21 #include "llvm/ADT/StringRef.h"
22 
23 namespace circt {
24 namespace hw {
25 
26 /// The target of an inner symbol, the entity the symbol is a handle for.
28 public:
29  /// Default constructor, invalid.
30  InnerSymTarget() { assert(!*this); }
31 
32  /// Target an operation.
33  explicit InnerSymTarget(Operation *op) : InnerSymTarget(op, 0) {}
34 
35  /// Target an operation and a field (=0 means the op itself).
36  InnerSymTarget(Operation *op, size_t fieldID)
38 
39  /// Target a port, and optionally a field (=0 means the port itself).
40  InnerSymTarget(size_t portIdx, Operation *op, size_t fieldID = 0)
42 
43  InnerSymTarget(const InnerSymTarget &) = default;
45 
46  // Accessors:
47 
48  /// Return the target's fieldID.
49  auto getField() const { return fieldID; }
50 
51  /// Return the target's base operation. For ports, this is the module.
52  Operation *getOp() const { return op; }
53 
54  /// Return the target's port, if valid. Check "isPort()".
55  auto getPort() const {
56  assert(isPort());
57  return portIdx;
58  }
59 
60  // Classification:
61 
62  /// Return if this targets a field (nonzero fieldID).
63  bool isField() const { return fieldID != 0; }
64 
65  /// Return if this targets a port.
66  bool isPort() const { return portIdx != invalidPort; }
67 
68  /// Returns if this targets an operation only (not port or field).
69  bool isOpOnly() const { return !isPort() && !isField(); }
70 
71  /// Return a target to the specified field within the given base.
72  /// FieldID is relative to the specified base target.
74  size_t fieldID) {
75  if (base.isPort())
76  return InnerSymTarget(base.portIdx, base.op, base.fieldID + fieldID);
77  return InnerSymTarget(base.op, base.fieldID + fieldID);
78  }
79 
80 private:
81  auto asTuple() const { return std::tie(op, portIdx, fieldID); }
82  Operation *op = nullptr;
83  size_t portIdx = 0;
84  size_t fieldID = 0;
85  static constexpr size_t invalidPort = ~size_t{0};
86 
87 public:
88  // Operators are defined below.
89 
90  // Comparison operators:
91  bool operator==(const InnerSymTarget &rhs) const {
92  return asTuple() == rhs.asTuple();
93  }
94 
95  // Assignment operators:
98 
99  /// Check if this target is valid.
100  operator bool() const { return op; }
101 };
102 
103 /// A table of inner symbols and their resolutions.
105 public:
106  /// Build an inner symbol table for the given operation. The operation must
107  /// have the InnerSymbolTable trait.
108  explicit InnerSymbolTable(Operation *op);
109 
110  /// Non-copyable
113 
114  // Moveable
117 
118  /// Look up a symbol with the specified name, returning empty InnerSymTarget
119  /// if no such name exists. Names never include the @ on them.
120  InnerSymTarget lookup(StringRef name) const;
121  InnerSymTarget lookup(StringAttr name) const;
122 
123  /// Look up a symbol with the specified name, returning null if no such
124  /// name exists or doesn't target just an operation.
125  Operation *lookupOp(StringRef name) const;
126  template <typename T>
127  T lookupOp(StringRef name) const {
128  return dyn_cast_or_null<T>(lookupOp(name));
129  }
130 
131  /// Look up a symbol with the specified name, returning null if no such
132  /// name exists or doesn't target just an operation.
133  Operation *lookupOp(StringAttr name) const;
134  template <typename T>
135  T lookupOp(StringAttr name) const {
136  return dyn_cast_or_null<T>(lookupOp(name));
137  }
138 
139  /// Get InnerSymbol for an operation.
140  static StringAttr getInnerSymbol(Operation *op);
141 
142  /// Get InnerSymbol for a target.
143  static StringAttr getInnerSymbol(const InnerSymTarget &target);
144 
145  /// Return the name of the attribute used for inner symbol names.
146  static StringRef getInnerSymbolAttrName() { return "inner_sym"; }
147 
148  /// Construct an InnerSymbolTable, checking for verification failure.
149  /// Emits diagnostics describing encountered issues.
150  static FailureOr<InnerSymbolTable> get(Operation *op);
151 
153  llvm::function_ref<LogicalResult(StringAttr, const InnerSymTarget &)>;
154 
155  /// Walk the given IST operation and invoke the callback for all encountered
156  /// inner symbols.
157  /// This variant allows callbacks that return LogicalResult OR void,
158  /// and wraps the underlying implementation.
159  template <typename FuncTy, typename RetTy = typename std::invoke_result_t<
160  FuncTy, StringAttr, const InnerSymTarget &>>
161  static RetTy walkSymbols(Operation *op, FuncTy &&callback) {
162  if constexpr (std::is_void_v<RetTy>)
163  return (void)walkSymbols(
164  op, InnerSymCallbackFn(
165  [&](StringAttr name, const InnerSymTarget &target) {
166  std::invoke(std::forward<FuncTy>(callback), name, target);
167  return success();
168  }));
169  else
170  return walkSymbols(
171  op, InnerSymCallbackFn([&](StringAttr name,
172  const InnerSymTarget &target) {
173  return std::invoke(std::forward<FuncTy>(callback), name, target);
174  }));
175  }
176 
177  /// Walk the given IST operation and invoke the callback for all encountered
178  /// inner symbols.
179  /// This variant is the underlying implementation.
180  /// If callback returns failure, the walk is aborted and failure is returned.
181  /// A successful walk with no failures returns success.
182  static LogicalResult walkSymbols(Operation *op, InnerSymCallbackFn callback);
183 
184 private:
185  using TableTy = DenseMap<StringAttr, InnerSymTarget>;
186  /// Construct an inner symbol table for the given operation,
187  /// with pre-populated table contents.
188  explicit InnerSymbolTable(Operation *op, TableTy &&table)
189  : innerSymTblOp(op), symbolTable(table){};
190 
191  /// This is the operation this table is constructed for, which must have the
192  /// InnerSymbolTable trait.
193  Operation *innerSymTblOp;
194 
195  /// This maps inner symbol names to their targets.
197 };
198 
199 /// This class represents a collection of InnerSymbolTable's.
201 public:
202  /// Get or create the InnerSymbolTable for the specified operation.
203  InnerSymbolTable &getInnerSymbolTable(Operation *op);
204 
205  /// Populate tables in parallel for all InnerSymbolTable operations in the
206  /// given InnerRefNamespace operation, verifying each and returning
207  /// the verification result.
208  LogicalResult populateAndVerifyTables(Operation *innerRefNSOp);
209 
210  explicit InnerSymbolTableCollection() = default;
211  explicit InnerSymbolTableCollection(Operation *innerRefNSOp) {
212  // Caller is not interested in verification, no way to report it upwards.
213  auto result = populateAndVerifyTables(innerRefNSOp);
214  (void)result;
215  assert(succeeded(result));
216  }
220 
221 private:
222  /// This maps Operations to their InnnerSymbolTable's.
223  DenseMap<Operation *, std::unique_ptr<InnerSymbolTable>> symbolTables;
224 };
225 
226 /// This class represents the namespace in which InnerRef's can be resolved.
228  SymbolTable &symTable;
230 
231  /// Resolve the InnerRef to its target within this namespace, returning empty
232  /// target if no such name exists.
233  InnerSymTarget lookup(hw::InnerRefAttr inner) const;
234 
235  /// Resolve the InnerRef to its target within this namespace, returning
236  /// empty target if no such name exists or it's not an operation.
237  /// Template type can be used to limit results to specified op type.
238  Operation *lookupOp(hw::InnerRefAttr inner) const;
239  template <typename T>
240  T lookupOp(hw::InnerRefAttr inner) const {
241  return dyn_cast_or_null<T>(lookupOp(inner));
242  }
243 };
244 
245 /// Printing InnerSymTarget's.
246 template <typename OS>
247 OS &operator<<(OS &os, const InnerSymTarget &target) {
248  if (!target)
249  return os << "<invalid target>";
250 
251  if (target.isField())
252  os << "field " << target.getField() << " of ";
253 
254  if (target.isPort())
255  os << "port " << target.getPort() << " on @"
256  << SymbolTable::getSymbolName(target.getOp()).getValue() << "";
257  else
258  os << "op " << *target.getOp() << "";
259 
260  return os;
261 }
262 
263 } // namespace hw
264 } // namespace circt
265 
266 #endif // CIRCT_DIALECT_FIRRTL_INNERSYMBOLTABLE_H
assert(baseType &&"element must be base type")
The target of an inner symbol, the entity the symbol is a handle for.
bool isOpOnly() const
Returns if this targets an operation only (not port or field).
InnerSymTarget(size_t portIdx, Operation *op, size_t fieldID=0)
Target a port, and optionally a field (=0 means the port itself).
Operation * getOp() const
Return the target's base operation. For ports, this is the module.
auto getField() const
Return the target's fieldID.
bool isField() const
Return if this targets a field (nonzero fieldID).
static InnerSymTarget getTargetForSubfield(const InnerSymTarget &base, size_t fieldID)
Return a target to the specified field within the given base.
InnerSymTarget(InnerSymTarget &&)=default
InnerSymTarget(Operation *op)
Target an operation.
auto getPort() const
Return the target's port, if valid. Check "isPort()".
InnerSymTarget(Operation *op, size_t fieldID)
Target an operation and a field (=0 means the op itself).
InnerSymTarget()
Default constructor, invalid.
bool operator==(const InnerSymTarget &rhs) const
bool isPort() const
Return if this targets a port.
InnerSymTarget(const InnerSymTarget &)=default
InnerSymTarget & operator=(const InnerSymTarget &)=default
InnerSymTarget & operator=(InnerSymTarget &&)=default
static constexpr size_t invalidPort
This class represents a collection of InnerSymbolTable's.
DenseMap< Operation *, std::unique_ptr< InnerSymbolTable > > symbolTables
This maps Operations to their InnnerSymbolTable's.
InnerSymbolTableCollection(Operation *innerRefNSOp)
LogicalResult populateAndVerifyTables(Operation *innerRefNSOp)
Populate tables in parallel for all InnerSymbolTable operations in the given InnerRefNamespace operat...
InnerSymbolTableCollection & operator=(const InnerSymbolTableCollection &)=delete
InnerSymbolTableCollection(const InnerSymbolTableCollection &)=delete
InnerSymbolTable & getInnerSymbolTable(Operation *op)
Get or create the InnerSymbolTable for the specified operation.
A table of inner symbols and their resolutions.
Operation * innerSymTblOp
This is the operation this table is constructed for, which must have the InnerSymbolTable trait.
T lookupOp(StringAttr name) const
InnerSymbolTable(const InnerSymbolTable &)=delete
Non-copyable.
InnerSymbolTable & operator=(InnerSymbolTable &&)=default
T lookupOp(StringRef name) const
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
InnerSymbolTable(InnerSymbolTable &&)=default
static RetTy walkSymbols(Operation *op, FuncTy &&callback)
Walk the given IST operation and invoke the callback for all encountered inner symbols.
InnerSymbolTable(Operation *op, TableTy &&table)
Construct an inner symbol table for the given operation, with pre-populated table contents.
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.
InnerSymbolTable & operator=(const InnerSymbolTable &)=delete
TableTy symbolTable
This maps inner symbol names to their targets.
static StringRef getInnerSymbolAttrName()
Return the name of the attribute used for inner symbol names.
OS & operator<<(OS &os, const InnerSymTarget &target)
Printing InnerSymTarget's.
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
Definition: DebugAnalysis.h:21
Definition: hw.py:1
This class represents the namespace in which InnerRef's can be resolved.
T lookupOp(hw::InnerRefAttr inner) const
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