15 #include "mlir/IR/ImplicitLocOpBuilder.h"
17 using namespace circt;
18 using namespace firrtl;
23 : circuit(circuit), symbolTable(circuit), instanceGraph(instanceGraph),
24 hierPathCache(circuit, symbolTable),
25 builder(OpBuilder::atBlockBegin(circuit->getBlock())) {}
30 LogicalResult resolveHierPath(Location loc,
const AnnoPathValue &target,
31 FlatSymbolRefAttr &op) {
37 module = target.
instances.front()->getParentOfType<FModuleLike>();
38 auto *node = instanceGraph[module];
39 while (!node->noUses()) {
40 if (!node->hasOneUse()) {
41 auto diag = emitError(loc) <<
"unable to uniquely resolve target due "
42 "to multiple instantiation";
43 for (
auto *use : node->uses())
44 diag.attachNote(use->getInstance().getLoc()) <<
"instance here";
47 node = (*node->usesBegin())->getParent();
53 auto *it = llvm::find_if(target.
instances, [&](InstanceOp instance) {
54 auto *node = instanceGraph[instanceGraph.getReferencedModule(instance)];
55 return !node->hasOneUse();
60 auto pathLength = std::distance(it, target.
instances.end());
61 if (pathLength == 0) {
67 SmallVector<Attribute> insts;
68 insts.reserve(pathLength);
69 std::transform(it, target.
instances.end(), std::back_inserter(insts),
70 [&](InstanceOp instance) {
71 return OpAnnoTarget(instance).getNLAReference(
72 namespaces[instance->getParentOfType<FModuleLike>()]);
81 op = hierPathCache.getRefFor(instAttr);
85 LogicalResult resolve(UnresolvedPathOp unresolved) {
86 auto loc = unresolved.getLoc();
87 ImplicitLocOpBuilder b(loc, unresolved);
88 auto *context = b.getContext();
91 auto target = unresolved.getTarget();
95 if (target.consume_front(
"OMDeleted")) {
97 return emitError(loc,
"OMDeleted references can not have targets");
102 auto resolved = b.create<PathOp>(targetKind, id);
103 unresolved->replaceAllUsesWith(resolved);
109 TargetKind targetKind;
110 if (target.consume_front(
"OMDontTouchedReferenceTarget")) {
111 targetKind = TargetKind::DontTouch;
112 }
else if (target.consume_front(
"OMInstanceTarget")) {
113 targetKind = TargetKind::Instance;
114 }
else if (target.consume_front(
"OMMemberInstanceTarget")) {
115 targetKind = TargetKind::MemberInstance;
116 }
else if (target.consume_front(
"OMMemberReferenceTarget")) {
117 targetKind = TargetKind::MemberReference;
118 }
else if (target.consume_front(
"OMReferenceTarget")) {
119 targetKind = TargetKind::Reference;
121 return emitError(loc)
122 <<
"unknown or missing OM reference type in target string: \""
128 if (!target.consume_front(
":"))
129 return emitError(loc,
"expected ':' in target string");
133 return emitError(loc)
134 <<
"cannot tokenize annotation path \"" << target <<
"\"";
137 auto path =
resolveEntities(*token, circuit, symbolTable, targetCache);
144 if (Type targetType = path->ref.getType()) {
145 auto fieldId = path->fieldIdx;
146 auto baseType = dyn_cast<FIRRTLBaseType>(targetType);
148 return emitError(loc,
"unable to target non-hardware type ")
151 if (isa<BundleType, FVectorType>(targetType))
152 return emitError(loc,
"unable to target aggregate type ") << targetType;
159 FlatSymbolRefAttr hierPathName;
160 if (failed(resolveHierPath(loc, *path, hierPathName)))
164 NamedAttrList fields;
165 fields.append(
"id",
id);
168 fields.append(
"circt.nonlocal", hierPathName);
169 if (path->fieldIdx != 0)
170 fields.append(
"circt.fieldID", b.getI64IntegerAttr(path->fieldIdx));
174 auto annoTarget = path->ref;
175 auto annotations = annoTarget.getAnnotations();
176 annotations.addAnnotations(annotation);
177 if (targetKindAttr.getValue() == TargetKind::DontTouch)
178 annotations.addDontTouch();
179 annoTarget.setAnnotations(annotations);
182 auto resolved = b.create<PathOp>(targetKindAttr, id);
183 unresolved->replaceAllUsesWith(resolved);
189 SymbolTable symbolTable;
192 hw::InnerSymbolNamespaceCollection namespaces;
203 struct ResolvePathsPass :
public ResolvePathsBase<ResolvePathsPass> {
204 void runOnOperation()
override;
208 void ResolvePathsPass::runOnOperation() {
209 auto circuit = getOperation();
210 auto &instanceGraph = getAnalysis<InstanceGraph>();
211 PathResolver resolver(circuit, instanceGraph);
212 auto result = circuit.walk([&](UnresolvedPathOp unresolved) {
213 if (failed(resolver.resolve(unresolved))) {
215 return WalkResult::interrupt();
217 return WalkResult::advance();
219 if (result.wasInterrupted())
221 markAnalysesPreserved<InstanceGraph>();
225 return std::make_unique<ResolvePathsPass>();
This graph tracks modules and where they are instantiated.
Direction get(bool isOutput)
Returns an output direction if isOutput is true, otherwise returns an input direction.
std::unique_ptr< mlir::Pass > createResolvePathsPass()
std::optional< AnnoPathValue > resolveEntities(TokenAnnoTarget path, CircuitOp circuit, SymbolTable &symTbl, CircuitTargetCache &cache)
Convert a parsed target string to a resolved target structure.
std::optional< TokenAnnoTarget > tokenizePath(StringRef origTarget)
Parse a FIRRTL annotation path into its constituent parts.
::mlir::Type getFinalTypeByFieldID(Type type, uint64_t fieldID)
This file defines an intermediate representation for circuits acting as an abstraction for constraint...
SmallVector< InstanceOp > instances
FModuleLike getModule() const
Get the parent module of the target.
Cache AnnoTargets for a circuit's modules, walked as needed.
A cache of existing HierPathOps, mostly used to facilitate HierPathOp reuse.