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 listCreateOp);
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;
74 bool isPathType =
false;
76 if (isa<BasePathType, PathType>(
innerType))
85 mlir::AttrTypeReplacer replacer;
86 replacer.addReplacement([](BasePathType
innerType) {
89 replacer.addReplacement([](PathType
innerType) {
93 return replacer.replace(type);
96 LogicalResult PathVisitor::processPath(Location loc, hw::HierPathOp hierPathOp,
98 StringAttr &bottomModule,
99 StringAttr &component,
101 auto *context = hierPathOp->getContext();
103 auto namepath = hierPathOp.getNamepathAttr().getValue();
104 SmallVector<PathElement> modules;
107 for (
auto attr : namepath.drop_back()) {
108 auto innerRef = cast<hw::InnerRefAttr>(attr);
109 auto target = irn.lookup(innerRef);
110 assert(target.isOpOnly() &&
"can't target a port the middle of a namepath");
111 auto *op = target.getOp();
113 auto verilogName = op->getAttrOfType<StringAttr>(
"hw.verilogName");
115 auto diag = emitError(loc,
"component does not have verilog name");
116 diag.attachNote(op->getLoc()) <<
"component here";
119 modules.emplace_back(innerRef.getModule(), verilogName);
123 auto &
end = namepath.back();
124 if (
auto innerRef = dyn_cast<hw::InnerRefAttr>(end)) {
125 auto target = irn.lookup(innerRef);
126 if (target.isPort()) {
128 auto module = cast<hw::HWModuleLike>(target.getOp());
129 auto index = target.getPort();
130 bottomModule = module.getModuleNameAttr();
132 auto loc = module.getPortLoc(index);
133 auto type = module.getPortTypes()[index];
134 if (failed(
getAccessPath(loc, type, target.getField(), field)))
137 auto *op = target.getOp();
138 assert(op &&
"innerRef should be targeting something");
140 auto currentModule = innerRef.getModule();
142 auto verilogName = op->getAttrOfType<StringAttr>(
"hw.verilogName");
144 auto diag = emitError(loc,
"component does not have verilog name");
145 diag.attachNote(op->getLoc()) <<
"component here";
151 if (isa<hw::HWInstanceLike>(op)) {
153 auto inst = dyn_cast<hw::InstanceOp>(op);
155 return op->emitError(
"unsupported instance operation");
157 modules.emplace_back(currentModule, verilogName);
158 bottomModule = inst.getReferencedModuleNameAttr();
163 bottomModule = currentModule;
164 component = verilogName;
165 auto innerSym = cast<hw::InnerSymbolOpInterface>(op);
166 auto value = innerSym.getTargetResult();
168 target.getField(), field)))
174 auto symbolRef = cast<FlatSymbolRefAttr>(end);
175 bottomModule = symbolRef.getAttr();
185 LogicalResult PathVisitor::process(PathCreateOp path) {
187 irn.symTable.lookup<hw::HierPathOp>(path.getTargetAttr().getAttr());
189 StringAttr bottomModule;
192 if (failed(processPath(path.getLoc(), hierPathOp, targetPath, bottomModule,
198 auto frozenPath =
builder.create<FrozenPathCreateOp>(
199 path.getLoc(), path.getTargetKindAttr(), path->getOperand(0), targetPath,
200 bottomModule, ref, field);
201 path.replaceAllUsesWith(frozenPath.getResult());
207 LogicalResult PathVisitor::process(BasePathCreateOp path) {
209 irn.symTable.lookup<hw::HierPathOp>(path.getTargetAttr().getAttr());
211 StringAttr bottomModule;
214 if (failed(processPath(path.getLoc(), hierPathOp, targetPath, bottomModule,
219 return path->emitError(
"basepath must target an instance");
221 return path->emitError(
"basepath must not target a field");
225 auto frozenPath =
builder.create<FrozenBasePathCreateOp>(
226 path.getLoc(), path->getOperand(0), targetPath);
227 path.replaceAllUsesWith(frozenPath.getResult());
233 LogicalResult PathVisitor::process(EmptyPathOp path) {
235 auto frozenPath =
builder.create<FrozenEmptyPathOp>(path.getLoc());
236 path.replaceAllUsesWith(frozenPath.getResult());
242 LogicalResult PathVisitor::process(ListCreateOp listCreateOp) {
243 ListType listType = listCreateOp.getResult().getType();
253 OpBuilder
builder(listCreateOp);
254 auto newListCreateOp =
builder.create<ListCreateOp>(
255 listCreateOp.getLoc(), newListType, listCreateOp.getOperands());
256 listCreateOp.replaceAllUsesWith(newListCreateOp.getResult());
257 listCreateOp->erase();
261 LogicalResult PathVisitor::run(ModuleOp module) {
262 auto updatePathType = [&](Value value) {
266 for (
auto classLike : module.getOps<ClassLike>()) {
268 for (
auto arg : classLike.getBodyBlock()->getArguments())
270 auto result = classLike->walk([&](Operation *op) -> WalkResult {
271 if (
auto basePath = dyn_cast<BasePathCreateOp>(op)) {
272 if (failed(process(basePath)))
273 return WalkResult::interrupt();
274 }
else if (
auto path = dyn_cast<PathCreateOp>(op)) {
275 if (failed(process(path)))
276 return WalkResult::interrupt();
277 }
else if (
auto path = dyn_cast<EmptyPathOp>(op)) {
278 if (failed(process(path)))
279 return WalkResult::interrupt();
280 }
else if (
auto listCreate = dyn_cast<ListCreateOp>(op)) {
281 if (failed(process(listCreate)))
282 return WalkResult::interrupt();
284 return WalkResult::advance();
286 if (result.wasInterrupted())
293 struct FreezePathsPass :
public FreezePathsBase<FreezePathsPass> {
294 void runOnOperation()
override;
298 void FreezePathsPass::runOnOperation() {
299 auto module = getOperation();
300 auto &instanceGraph = getAnalysis<hw::InstanceGraph>();
301 mlir::SymbolTableCollection symbolTableCollection;
302 auto &symbolTable = getAnalysis<SymbolTable>();
303 hw::InnerSymbolTableCollection collection(module);
304 hw::InnerRefNamespace irn{symbolTable, collection};
305 if (failed(PathVisitor(instanceGraph, irn).run(module)))
310 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.