19 #include "mlir/Pass/Pass.h"
23 #define GEN_PASS_DEF_FREEZEPATHS
24 #include "circt/Dialect/OM/OMPasses.h.inc"
28 using namespace circt;
34 : instanceGraph(instanceGraph), irn(irn) {}
37 LogicalResult processPath(Location loc, hw::HierPathOp hierPathOp,
38 PathAttr &targetPath, StringAttr &bottomModule,
39 StringAttr &component, StringAttr &field);
40 LogicalResult process(BasePathCreateOp pathOp);
41 LogicalResult process(PathCreateOp pathOp);
42 LogicalResult process(EmptyPathOp pathOp);
43 LogicalResult process(ListCreateOp listCreateOp);
44 LogicalResult run(ModuleOp module);
46 hw::InnerRefNamespace &irn;
50 static LogicalResult
getAccessPath(Location loc, Type type,
size_t fieldId,
52 SmallString<64> field;
54 if (
auto aliasType = dyn_cast<hw::TypeAliasType>(type))
55 type = aliasType.getCanonicalType();
56 if (
auto structType = dyn_cast<hw::StructType>(type)) {
57 auto index = structType.getIndexForFieldID(fieldId);
58 auto &element = structType.getElements()[index];
60 llvm::append_range(field, element.name.getValue());
62 fieldId -= structType.getFieldID(index);
63 }
else if (
auto arrayType = dyn_cast<hw::ArrayType>(type)) {
64 auto index = arrayType.getIndexForFieldID(fieldId);
66 Twine(index).toVector(field);
68 type = arrayType.getElementType();
69 fieldId -= arrayType.getFieldID(index);
71 return emitError(loc) <<
"can't create access path with fieldID "
72 << fieldId <<
" in type " << type;
81 bool isPathType =
false;
83 if (isa<BasePathType, PathType>(
innerType))
92 mlir::AttrTypeReplacer replacer;
93 replacer.addReplacement([](BasePathType
innerType) {
96 replacer.addReplacement([](PathType
innerType) {
100 return replacer.replace(type);
103 LogicalResult PathVisitor::processPath(Location loc, hw::HierPathOp hierPathOp,
104 PathAttr &targetPath,
105 StringAttr &bottomModule,
106 StringAttr &component,
108 auto *context = hierPathOp->getContext();
110 auto namepath = hierPathOp.getNamepathAttr().getValue();
111 SmallVector<PathElement> modules;
114 for (
auto attr : namepath.drop_back()) {
115 auto innerRef = cast<hw::InnerRefAttr>(attr);
116 auto target = irn.lookup(innerRef);
117 assert(target.isOpOnly() &&
"can't target a port the middle of a namepath");
118 auto *op = target.getOp();
120 auto verilogName = op->getAttrOfType<StringAttr>(
"hw.verilogName");
122 auto diag = emitError(loc,
"component does not have verilog name");
123 diag.attachNote(op->getLoc()) <<
"component here";
126 modules.emplace_back(innerRef.getModule(), verilogName);
130 auto &
end = namepath.back();
131 if (
auto innerRef = dyn_cast<hw::InnerRefAttr>(end)) {
132 auto target = irn.lookup(innerRef);
133 if (target.isPort()) {
135 auto module = cast<hw::HWModuleLike>(target.getOp());
136 auto index = target.getPort();
137 bottomModule = module.getModuleNameAttr();
139 auto loc = module.getPortLoc(index);
140 auto type = module.getPortTypes()[index];
141 if (failed(
getAccessPath(loc, type, target.getField(), field)))
144 auto *op = target.getOp();
145 assert(op &&
"innerRef should be targeting something");
147 auto currentModule = innerRef.getModule();
149 auto verilogName = op->getAttrOfType<StringAttr>(
"hw.verilogName");
151 auto diag = emitError(loc,
"component does not have verilog name");
152 diag.attachNote(op->getLoc()) <<
"component here";
158 if (isa<hw::HWInstanceLike>(op)) {
160 auto inst = dyn_cast<hw::InstanceOp>(op);
162 return op->emitError(
"unsupported instance operation");
164 modules.emplace_back(currentModule, verilogName);
165 bottomModule = inst.getReferencedModuleNameAttr();
170 bottomModule = currentModule;
171 component = verilogName;
172 auto innerSym = cast<hw::InnerSymbolOpInterface>(op);
173 auto value = innerSym.getTargetResult();
175 target.getField(), field)))
181 auto symbolRef = cast<FlatSymbolRefAttr>(end);
182 bottomModule = symbolRef.getAttr();
192 LogicalResult PathVisitor::process(PathCreateOp path) {
194 irn.symTable.lookup<hw::HierPathOp>(path.getTargetAttr().getAttr());
196 StringAttr bottomModule;
199 if (failed(processPath(path.getLoc(), hierPathOp, targetPath, bottomModule,
204 OpBuilder builder(path);
205 auto frozenPath = builder.create<FrozenPathCreateOp>(
206 path.getLoc(), path.getTargetKindAttr(), path->getOperand(0), targetPath,
207 bottomModule, ref, field);
208 path.replaceAllUsesWith(frozenPath.getResult());
214 LogicalResult PathVisitor::process(BasePathCreateOp path) {
216 irn.symTable.lookup<hw::HierPathOp>(path.getTargetAttr().getAttr());
218 StringAttr bottomModule;
221 if (failed(processPath(path.getLoc(), hierPathOp, targetPath, bottomModule,
226 return path->emitError(
"basepath must target an instance");
228 return path->emitError(
"basepath must not target a field");
231 OpBuilder builder(path);
232 auto frozenPath = builder.create<FrozenBasePathCreateOp>(
233 path.getLoc(), path->getOperand(0), targetPath);
234 path.replaceAllUsesWith(frozenPath.getResult());
240 LogicalResult PathVisitor::process(EmptyPathOp path) {
241 OpBuilder builder(path);
242 auto frozenPath = builder.create<FrozenEmptyPathOp>(path.getLoc());
243 path.replaceAllUsesWith(frozenPath.getResult());
249 LogicalResult PathVisitor::process(ListCreateOp listCreateOp) {
250 ListType listType = listCreateOp.getResult().getType();
260 OpBuilder builder(listCreateOp);
261 auto newListCreateOp = builder.create<ListCreateOp>(
262 listCreateOp.getLoc(), newListType, listCreateOp.getOperands());
263 listCreateOp.replaceAllUsesWith(newListCreateOp.getResult());
264 listCreateOp->erase();
268 LogicalResult PathVisitor::run(ModuleOp module) {
269 auto updatePathType = [&](Value value) {
273 for (
auto classLike : module.getOps<ClassLike>()) {
275 for (
auto arg : classLike.getBodyBlock()->getArguments())
277 auto result = classLike->walk([&](Operation *op) -> WalkResult {
278 if (
auto basePath = dyn_cast<BasePathCreateOp>(op)) {
279 if (failed(process(basePath)))
280 return WalkResult::interrupt();
281 }
else if (
auto path = dyn_cast<PathCreateOp>(op)) {
282 if (failed(process(path)))
283 return WalkResult::interrupt();
284 }
else if (
auto path = dyn_cast<EmptyPathOp>(op)) {
285 if (failed(process(path)))
286 return WalkResult::interrupt();
287 }
else if (
auto listCreate = dyn_cast<ListCreateOp>(op)) {
288 if (failed(process(listCreate)))
289 return WalkResult::interrupt();
291 return WalkResult::advance();
293 if (result.wasInterrupted())
300 struct FreezePathsPass
301 :
public circt::om::impl::FreezePathsBase<FreezePathsPass> {
302 void runOnOperation()
override;
306 void FreezePathsPass::runOnOperation() {
307 auto module = getOperation();
308 auto &instanceGraph = getAnalysis<hw::InstanceGraph>();
309 mlir::SymbolTableCollection symbolTableCollection;
310 auto &symbolTable = getAnalysis<SymbolTable>();
311 hw::InnerSymbolTableCollection collection(module);
312 hw::InnerRefNamespace irn{symbolTable, collection};
313 if (failed(PathVisitor(instanceGraph, irn).run(module)))
318 return std::make_unique<FreezePathsPass>();
assert(baseType &&"element must be base type")
static bool hasPathType(Type type)
static LogicalResult getAccessPath(Location loc, Type type, size_t fieldId, StringAttr &result)
static Type processType(Type type)
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()
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.