21 using namespace circt;
27 : instanceGraph(instanceGraph), irn(irn) {}
30 LogicalResult processPath(Location loc, hw::HierPathOp hierPathOp,
31 PathAttr &targetPath, StringAttr &bottomModule,
32 StringAttr &component, StringAttr &field);
33 LogicalResult process(BasePathCreateOp pathOp);
34 LogicalResult process(PathCreateOp pathOp);
35 LogicalResult process(EmptyPathOp pathOp);
36 LogicalResult process(ListCreateOp pathOp);
37 LogicalResult run(ModuleOp module);
39 hw::InnerRefNamespace &irn;
43 static LogicalResult
getAccessPath(Location loc, Type type,
size_t fieldId,
45 SmallString<64> field;
47 if (
auto aliasType = dyn_cast<hw::TypeAliasType>(type))
48 type = aliasType.getCanonicalType();
49 if (
auto structType = dyn_cast<hw::StructType>(type)) {
50 auto index = structType.getIndexForFieldID(fieldId);
51 auto &element = structType.getElements()[index];
53 llvm::append_range(field, element.name.getValue());
55 fieldId -= structType.getFieldID(index);
56 }
else if (
auto arrayType = dyn_cast<hw::ArrayType>(type)) {
57 auto index = arrayType.getIndexForFieldID(fieldId);
59 Twine(index).toVector(field);
61 type = arrayType.getElementType();
62 fieldId -= arrayType.getFieldID(index);
64 return emitError(loc) <<
"can't create access path with fieldID "
65 << fieldId <<
" in type " << type;
72 LogicalResult PathVisitor::processPath(Location loc, hw::HierPathOp hierPathOp,
74 StringAttr &bottomModule,
75 StringAttr &component,
77 auto *context = hierPathOp->getContext();
79 auto namepath = hierPathOp.getNamepathAttr().getValue();
80 SmallVector<PathElement> modules;
83 auto &
end = namepath.back();
84 if (
auto innerRef = dyn_cast<hw::InnerRefAttr>(end)) {
85 auto target = irn.lookup(innerRef);
86 if (target.isPort()) {
88 auto module = cast<hw::HWModuleLike>(target.getOp());
89 auto index = target.getPort();
90 bottomModule = module.getModuleNameAttr();
92 auto loc = module.getPortLoc(index);
93 auto type = module.getPortTypes()[index];
94 if (failed(
getAccessPath(loc, type, target.getField(), field)))
97 auto *op = target.getOp();
98 assert(op &&
"innerRef should be targeting something");
100 auto currentModule = innerRef.getModule();
102 auto verilogName = op->getAttrOfType<StringAttr>(
"hw.verilogName");
104 auto diag = emitError(loc,
"component does not have verilog name");
105 diag.attachNote(op->getLoc()) <<
"component here";
111 if (
auto inst = dyn_cast<hw::HWInstanceLike>(op)) {
113 modules.emplace_back(currentModule, verilogName);
114 bottomModule = inst.getReferencedModuleNameAttr();
119 bottomModule = currentModule;
120 component = verilogName;
121 auto innerSym = cast<hw::InnerSymbolOpInterface>(op);
122 auto value = innerSym.getTargetResult();
124 target.getField(), field)))
130 auto symbolRef = cast<FlatSymbolRefAttr>(end);
131 bottomModule = symbolRef.getAttr();
137 for (
auto attr : llvm::reverse(namepath.drop_back())) {
138 auto innerRef = cast<hw::InnerRefAttr>(attr);
139 auto target = irn.lookup(innerRef);
140 assert(target.isOpOnly() &&
"can't target a port the middle of a namepath");
141 auto *op = target.getOp();
143 auto verilogName = op->getAttrOfType<StringAttr>(
"hw.verilogName");
145 auto diag = emitError(loc,
"component does not have verilog name");
146 diag.attachNote(op->getLoc()) <<
"component here";
149 modules.emplace_back(innerRef.getModule(), verilogName);
152 auto topRef = namepath.front();
154 auto topModule = isa<hw::InnerRefAttr>(topRef)
155 ? cast<hw::InnerRefAttr>(topRef).getModule()
156 : cast<FlatSymbolRefAttr>(topRef).getAttr();
159 auto *node = instanceGraph.lookup(topModule);
160 while (!node->noUses()) {
161 auto module = node->getModule<hw::HWModuleLike>();
164 if (module.isPublic())
167 if (!node->hasOneUse()) {
168 auto diag = emitError(loc) <<
"unable to uniquely resolve target "
169 "due to multiple instantiation";
170 for (
auto *use : node->uses()) {
171 if (
auto *op = use->getInstance<Operation *>())
172 diag.attachNote(op->getLoc()) <<
"instance here";
174 auto module = node->getModule();
175 diag.attachNote(module->getLoc()) <<
"module marked public";
181 auto *record = *node->usesBegin();
182 auto *inst = record->getInstance<Operation *>();
187 auto verilogName = inst->getAttrOfType<StringAttr>(
"hw.verilogName");
189 return inst->emitError(
"component does not have verilog name");
190 node = record->getParent();
191 modules.emplace_back(node->getModule().getModuleNameAttr(), verilogName);
195 targetPath =
PathAttr::get(context, llvm::to_vector(llvm::reverse(modules)));
199 LogicalResult PathVisitor::process(PathCreateOp path) {
201 irn.symTable.lookup<hw::HierPathOp>(path.getTargetAttr().getAttr());
203 StringAttr bottomModule;
206 if (failed(processPath(path.getLoc(), hierPathOp, targetPath, bottomModule,
212 auto frozenPath =
builder.create<FrozenPathCreateOp>(
213 path.getLoc(), path.getTargetKindAttr(), path->getOperand(0), targetPath,
214 bottomModule, ref, field);
215 path.replaceAllUsesWith(frozenPath.getResult());
221 LogicalResult PathVisitor::process(BasePathCreateOp path) {
223 irn.symTable.lookup<hw::HierPathOp>(path.getTargetAttr().getAttr());
225 StringAttr bottomModule;
228 if (failed(processPath(path.getLoc(), hierPathOp, targetPath, bottomModule,
233 return path->emitError(
"basepath must target an instance");
235 return path->emitError(
"basepath must not target a field");
239 auto frozenPath =
builder.create<FrozenBasePathCreateOp>(
240 path.getLoc(), path->getOperand(0), targetPath);
241 path.replaceAllUsesWith(frozenPath.getResult());
247 LogicalResult PathVisitor::process(EmptyPathOp path) {
249 auto frozenPath =
builder.create<FrozenEmptyPathOp>(path.getLoc());
250 path.replaceAllUsesWith(frozenPath.getResult());
256 LogicalResult PathVisitor::process(ListCreateOp listCreateOp) {
257 ListType listType = listCreateOp.getResult().getType();
260 bool hasPathType =
false;
262 if (isa<BasePathType, PathType>(
innerType))
270 mlir::AttrTypeReplacer replacer;
271 replacer.addReplacement([](BasePathType
innerType) {
274 replacer.addReplacement([](PathType
innerType) {
279 OpBuilder
builder(listCreateOp);
280 auto newListType = replacer.replace(listType);
281 auto newListCreateOp =
builder.create<ListCreateOp>(
282 listCreateOp.getLoc(), newListType, listCreateOp.getOperands());
283 listCreateOp.replaceAllUsesWith(newListCreateOp.getResult());
284 listCreateOp->erase();
288 LogicalResult PathVisitor::run(ModuleOp module) {
291 auto updatePathType = [&](Value
value) {
292 if (isa<BasePathType>(
value.getType()))
293 value.setType(frozenBasePathType);
294 if (isa<PathType>(
value.getType()))
295 value.setType(frozenPathType);
297 for (
auto classLike : module.getOps<ClassLike>()) {
299 for (
auto arg : classLike.getBodyBlock()->getArguments())
301 auto result = classLike->walk([&](Operation *op) -> WalkResult {
302 if (
auto basePath = dyn_cast<BasePathCreateOp>(op)) {
303 if (failed(process(basePath)))
304 return WalkResult::interrupt();
305 }
else if (
auto path = dyn_cast<PathCreateOp>(op)) {
306 if (failed(process(path)))
307 return WalkResult::interrupt();
308 }
else if (
auto path = dyn_cast<EmptyPathOp>(op)) {
309 if (failed(process(path)))
310 return WalkResult::interrupt();
311 }
else if (
auto listCreate = dyn_cast<ListCreateOp>(op)) {
312 if (failed(process(listCreate)))
313 return WalkResult::interrupt();
315 return WalkResult::advance();
317 if (result.wasInterrupted())
324 struct FreezePathsPass :
public FreezePathsBase<FreezePathsPass> {
325 void runOnOperation()
override;
329 void FreezePathsPass::runOnOperation() {
330 auto module = getOperation();
331 auto &instanceGraph = getAnalysis<hw::InstanceGraph>();
332 auto &symbolTable = getAnalysis<SymbolTable>();
333 hw::InnerSymbolTableCollection collection(module);
334 hw::InnerRefNamespace irn{symbolTable, collection};
335 if (failed(PathVisitor(instanceGraph, irn).run(module)))
340 return std::make_unique<FreezePathsPass>();
assert(baseType &&"element must be base type")
static LogicalResult getAccessPath(Location loc, Type type, size_t fieldId, StringAttr &result)
Direction get(bool isOutput)
Returns an output direction if isOutput is true, otherwise returns an input direction.
mlir::Type innerType(mlir::Type type)
std::map< std::string, std::set< std::string > > InstanceGraph
Iterates over the handshake::FuncOp's in the program to build an instance graph.
std::unique_ptr< mlir::Pass > createFreezePathsPass()
This file defines an intermediate representation for circuits acting as an abstraction for constraint...