24 #include "llvm/Support/Debug.h"
26 #define DEBUG_TYPE "firrtl-inject-dut-hier"
28 using namespace circt;
29 using namespace firrtl;
32 struct InjectDUTHierarchy :
public InjectDUTHierarchyBase<InjectDUTHierarchy> {
33 void runOnOperation()
override;
46 InstanceOp wrapperInst) {
47 auto namepath = path.getNamepath().getValue();
50 SmallVector<Attribute> newNamepath;
51 newNamepath.reserve(namepath.size() + 1);
52 while (path.modPart(nlaIdx) != dut.getNameAttr())
53 newNamepath.push_back(namepath[nlaIdx++]);
58 if (
auto dutRef = namepath[nlaIdx].dyn_cast<hw::InnerRefAttr>())
60 wrapperInst.getModuleNameAttr().getAttr(), dutRef.getName()));
62 newNamepath.push_back(
66 auto back = namepath.drop_front(nlaIdx + 1);
67 newNamepath.append(back.begin(), back.end());
68 path.setNamepathAttr(
ArrayAttr::get(dut.getContext(), newNamepath));
71 void InjectDUTHierarchy::runOnOperation() {
72 LLVM_DEBUG(
llvm::dbgs() <<
"===- Running InjectDUTHierarchyPass "
73 "-----------------------------------------===\n");
75 CircuitOp circuit = getOperation();
85 StringAttr wrapperName;
95 auto name = anno.
getMember<StringAttr>(
"name");
97 emitError(circuit->getLoc())
98 <<
"contained a malformed "
99 "'sifive.enterprise.firrtl.InjectDUTHierarchyAnnotation' "
100 "annotation that did not contain a 'name' field";
106 emitError(circuit->getLoc())
107 <<
"contained multiple "
108 "'sifive.enterprise.firrtl.InjectDUTHierarchyAnnotation' "
109 "annotations when at most one is allowed";
119 return signalPassFailure();
124 return markAllAnalysesPreserved();
130 for (
auto mod : circuit.getOps<FModuleOp>()) {
134 auto diag = emitError(mod.getLoc())
136 << dut.getModuleName()
137 <<
"' also had such an annotation (this should "
139 diag.attachNote(dut.getLoc()) <<
"the first DUT was found here";
147 return signalPassFailure();
152 if (wrapperName && !dut) {
153 emitError(circuit->getLoc())
160 return signalPassFailure();
169 OpBuilder b(circuit.getContext());
172 b.setInsertionPointAfter(dut);
173 auto newDUT = b.create<FModuleOp>(dut.getLoc(), dut.getNameAttr(),
174 dut.getConventionAttr(), dut.getPorts(),
175 dut.getAnnotations());
177 SymbolTable::setSymbolVisibility(newDUT, dut.getVisibility());
178 dut.setName(b.getStringAttr(circuitNS.newName(wrapperName.getValue())));
187 [](
auto,
auto) {
return true; });
192 b.setInsertionPointToStart(dut.getBodyBlock());
193 hw::InnerSymbolNamespace dutNS(dut);
194 auto wrapperInst = b.create<InstanceOp>(
195 b.getUnknownLoc(), wrapper, wrapper.getModuleName(),
196 NameKindEnum::DroppableName, ArrayRef<Attribute>{}, ArrayRef<Attribute>{},
197 false, b.getStringAttr(dutNS.newName(wrapper.getModuleName())));
198 for (
const auto &pair : llvm::enumerate(wrapperInst.getResults())) {
199 Value lhs = dut.getArgument(pair.index());
200 Value rhs = pair.value();
207 DenseSet<StringAttr> dutPaths, dutPortSyms;
209 auto sym = anno.
getMember<FlatSymbolRefAttr>(
"circt.nonlocal");
211 dutPaths.insert(sym.getAttr());
213 for (
size_t i = 0, e = dut.getNumPorts(); i != e; ++i) {
214 auto portSym = dut.getPortSymbolAttr(i);
216 dutPortSyms.insert(portSym.getSymName());
218 auto sym = anno.
getMember<FlatSymbolRefAttr>(
"circt.nonlocal");
220 dutPaths.insert(sym.getAttr());
226 for (
auto path : dutPaths)
229 for (
auto sym : dutPortSyms)
243 LLVM_DEBUG(
llvm::dbgs() <<
"Processing hierarchical paths:\n");
244 auto &nlaTable = getAnalysis<NLATable>();
245 DenseMap<StringAttr, hw::HierPathOp> dutRenames;
246 for (
auto nla : llvm::make_early_inc_range(nlaTable.lookup(dut))) {
247 LLVM_DEBUG(
llvm::dbgs() <<
" - " << nla <<
"\n");
248 auto namepath = nla.getNamepath().getValue();
252 if (nla.root() == dut.getNameAttr()) {
253 assert(namepath.size() > 1 &&
"namepath size must be greater than one");
255 wrapper.getNameAttr(),
256 namepath.front().cast<hw::InnerRefAttr>().getName())};
257 auto tail = namepath.drop_front();
258 newNamepath.append(tail.begin(), tail.end());
259 nla->setAttr(
"namepath", b.getArrayAttr(newNamepath));
275 if (nla.leafMod() == dut.getNameAttr()) {
277 if (nla.isComponent() && dutPortSyms.count(nla.ref()))
283 if (nla.isModule() && dutPaths.contains(nla.getSymNameAttr())) {
284 OpBuilder::InsertionGuard guard(b);
285 b.setInsertionPoint(nla);
286 auto clone = cast<hw::HierPathOp>(b.clone(*nla));
287 clone.setSymNameAttr(b.getStringAttr(
288 circuitNS.newName(clone.getSymNameAttr().getValue())));
289 dutRenames.insert({nla.getSymNameAttr(), clone});
298 SmallVector<Annotation> newAnnotations;
299 auto removeAndUpdateNLAs = [&](
Annotation anno) ->
bool {
300 auto sym = anno.
getMember<FlatSymbolRefAttr>(
"circt.nonlocal");
303 if (!dutRenames.count(sym.getAttr()))
308 newAnnotations.push_back(anno);
314 annotations.removeAnnotations(removeAndUpdateNLAs);
315 annotations.addAnnotations(newAnnotations);
316 annotations.applyToOperation(dut);
317 for (
size_t i = 0, e = dut.getNumPorts(); i != e; ++i) {
318 newAnnotations.clear();
320 annotations.removeAnnotations(removeAndUpdateNLAs);
321 annotations.addAnnotations(newAnnotations);
322 annotations.applyToPort(dut, i);
331 return std::make_unique<InjectDUTHierarchy>();
assert(baseType &&"element must be base type")
static void addHierarchy(hw::HierPathOp path, FModuleOp dut, InstanceOp wrapperInst)
Add an extra level of hierarchy to a hierarchical path that places the wrapper instance after the DUT...
This class provides a read-only projection over the MLIR attributes that represent a set of annotatio...
bool removeAnnotations(llvm::function_ref< bool(Annotation)> predicate)
Remove all annotations from this annotation set for which predicate returns true.
static bool removePortAnnotations(Operation *module, llvm::function_ref< bool(unsigned, Annotation)> predicate)
Remove all port annotations from a module or extmodule for which predicate returns true.
static AnnotationSet forPort(FModuleLike op, size_t portNo)
Get an annotation set for the specified port.
This class provides a read-only projection of an annotation.
AttrClass getMember(StringAttr name) const
Return a member of the annotation.
void setMember(StringAttr name, Attribute value)
Add or set a member of the annotation to a value.
bool isClass(Args... names) const
Return true if this annotation matches any of the specified class names.
Direction get(bool isOutput)
Returns an output direction if isOutput is true, otherwise returns an input direction.
constexpr const char * injectDUTHierarchyAnnoClass
constexpr const char * dutAnnoClass
std::unique_ptr< mlir::Pass > createInjectDUTHierarchyPass()
void emitConnect(OpBuilder &builder, Location loc, Value lhs, Value rhs)
Emit a connect between two values.
StringAttr getInnerSymName(Operation *op)
Return the StringAttr for the inner_sym name, if it exists.
This file defines an intermediate representation for circuits acting as an abstraction for constraint...
mlir::raw_indented_ostream & dbgs()
The namespace of a CircuitOp, generally inhabited by modules.