20 #include "mlir/Dialect/Arith/IR/Arith.h"
21 #include "mlir/IR/BuiltinTypes.h"
22 #include "mlir/IR/OperationSupport.h"
23 #include "mlir/IR/PatternMatch.h"
24 #include "llvm/ADT/TypeSwitch.h"
26 using namespace circt;
27 using namespace handshake;
40 std::string &topLevel,
41 SmallVectorImpl<std::string> &sortedFuncs) {
43 auto walkFuncOps = [&](handshake::FuncOp funcOp) {
44 auto &funcUses = instanceGraph[funcOp.getName().str()];
45 funcOp.walk([&](handshake::InstanceOp instanceOp) {
46 funcUses.insert(instanceOp.getModule().str());
49 moduleOp.walk(walkFuncOps);
54 std::set<std::string> visited, marked, candidateTopLevel;
55 SmallVector<std::string> cycleTrace;
57 llvm::transform(instanceGraph,
58 std::inserter(candidateTopLevel, candidateTopLevel.begin()),
59 [](
auto it) { return it.first; });
60 std::function<void(
const std::string &, SmallVector<std::string>)> cycleUtil =
61 [&](
const std::string &node, SmallVector<std::string> trace) {
62 if (cyclic || visited.count(node))
64 trace.push_back(node);
65 if (marked.count(node)) {
71 for (
auto use : instanceGraph[node]) {
72 candidateTopLevel.erase(use);
73 cycleUtil(use, trace);
77 sortedFuncs.insert(sortedFuncs.begin(), node);
79 for (
auto it : instanceGraph) {
80 if (visited.count(it.first) == 0)
81 cycleUtil(it.first, {});
87 auto err = moduleOp.emitOpError();
88 err <<
"cannot deduce top level function - cycle "
89 "detected in instance graph (";
91 cycleTrace, err, [&](
auto node) { err << node; },
"->");
95 assert(!candidateTopLevel.empty() &&
96 "if non-cyclic, there should be at least 1 candidate top level");
98 if (candidateTopLevel.size() > 1) {
99 auto err = moduleOp.emitOpError();
100 err <<
"multiple candidate top-level modules detected (";
101 llvm::interleaveComma(candidateTopLevel, err,
102 [&](
auto topLevel) { err << topLevel; });
103 err <<
"). Please remove one of these from the source program.";
106 topLevel = *candidateTopLevel.begin();
111 if (funcOp.isExternal())
114 auto checkUseFunc = [&](Operation *op, Value v, StringRef desc,
115 unsigned idx) -> LogicalResult {
116 auto numUses = std::distance(v.getUses().begin(), v.getUses().end());
118 return op->emitOpError() << desc <<
" " << idx <<
" has no uses.";
120 return op->emitOpError() << desc <<
" " << idx <<
" has multiple uses.";
124 for (
auto &subOp : funcOp.getOps()) {
125 for (
auto res : llvm::enumerate(subOp.getResults())) {
126 if (failed(checkUseFunc(&subOp, res.value(),
"result", res.index())))
131 Block &entryBlock = funcOp.front();
132 for (
auto barg : enumerate(entryBlock.getArguments())) {
133 if (failed(checkUseFunc(funcOp.getOperation(), barg.value(),
"argument",
142 auto *ctx = tuple.getContext();
143 mlir::SmallVector<hw::StructType::FieldInfo, 8> hwfields;
144 for (
auto [i,
innerType] : llvm::enumerate(tuple)) {
146 if (
auto tupleInnerType =
innerType.dyn_cast<TupleType>())
149 convertedInnerType});
158 return TypeSwitch<Type, Type>(t)
161 .Case<TupleType>([&](TupleType tt) {
162 llvm::SmallVector<Type> types;
168 .Case<hw::StructType>([&](
auto st) {
169 llvm::SmallVector<hw::StructType::FieldInfo> structFields(
171 for (
auto &field : structFields)
177 .Default([&](Type t) {
return t; });
183 return TypeSwitch<Type, esi::ChannelType>(t)
184 .Case<esi::ChannelType>([](
auto t) {
return t; })
187 .Case<NoneType>([](NoneType nt) {
191 .Default([](
auto t) {
202 class HandshakePortNameGenerator {
204 explicit HandshakePortNameGenerator(Operation *op)
206 auto namedOpInterface = dyn_cast<handshake::NamedIOInterface>(op);
207 if (namedOpInterface)
208 inferFromNamedOpInterface(namedOpInterface);
209 else if (
auto funcOp = dyn_cast<handshake::FuncOp>(op))
210 inferFromFuncOp(funcOp);
215 StringAttr inputName(
unsigned idx) {
return inputs[idx]; }
216 StringAttr outputName(
unsigned idx) {
return outputs[idx]; }
219 using IdxToStrF =
const std::function<std::string(
unsigned)> &;
220 void infer(Operation *op, IdxToStrF &inF, IdxToStrF &outF) {
222 llvm::enumerate(op->getOperandTypes()), std::back_inserter(
inputs),
223 [&](
auto it) { return builder.getStringAttr(inF(it.index())); });
225 llvm::enumerate(op->getResultTypes()), std::back_inserter(
outputs),
226 [&](
auto it) { return builder.getStringAttr(outF(it.index())); });
229 void inferDefault(Operation *op) {
231 op, [](
unsigned idx) {
return "in" + std::to_string(idx); },
232 [](
unsigned idx) {
return "out" + std::to_string(idx); });
235 void inferFromNamedOpInterface(handshake::NamedIOInterface op) {
237 op, [&](
unsigned idx) {
return op.getOperandName(idx); },
238 [&](
unsigned idx) {
return op.getResultName(idx); });
241 void inferFromFuncOp(handshake::FuncOp op) {
242 auto inF = [&](
unsigned idx) {
return op.getArgName(idx).str(); };
243 auto outF = [&](
unsigned idx) {
return op.getResName(idx).str(); };
245 llvm::enumerate(op.getArgumentTypes()), std::back_inserter(
inputs),
246 [&](
auto it) { return builder.getStringAttr(inF(it.index())); });
248 llvm::enumerate(op.getResultTypes()), std::back_inserter(
outputs),
249 [&](
auto it) { return builder.getStringAttr(outF(it.index())); });
260 SmallVector<hw::PortInfo> pinputs, poutputs;
262 HandshakePortNameGenerator portNames(op);
263 auto *ctx = op->getContext();
270 for (
auto arg : llvm::enumerate(
inputs)) {
272 {{portNames.inputName(arg.index()),
esiWrapper(arg.value()),
275 hw::InnerSymAttr{}});
280 for (
auto res : llvm::enumerate(
outputs)) {
282 {{portNames.outputName(res.index()),
esiWrapper(res.value()),
285 hw::InnerSymAttr{}});
293 hw::InnerSymAttr{}});
297 hw::InnerSymAttr{}});
assert(baseType &&"element must be base type")
llvm::SmallVector< StringAttr > inputs
llvm::SmallVector< StringAttr > outputs
Direction get(bool isOutput)
Returns an output direction if isOutput is true, otherwise returns an input direction.
mlir::Type innerType(mlir::Type type)
hw::ModulePortInfo getPortInfoForOpTypes(mlir::Operation *op, TypeRange inputs, TypeRange outputs)
std::map< std::string, std::set< std::string > > InstanceGraph
Iterates over the handshake::FuncOp's in the program to build an instance graph.
LogicalResult resolveInstanceGraph(ModuleOp moduleOp, InstanceGraph &instanceGraph, std::string &topLevel, SmallVectorImpl< std::string > &sortedFuncs)
Iterates over the handshake::FuncOp's in the program to build an instance graph.
static Type tupleToStruct(TupleType tuple)
LogicalResult verifyAllValuesHasOneUse(handshake::FuncOp op)
esi::ChannelType esiWrapper(mlir::Type t)
This file defines an intermediate representation for circuits acting as an abstraction for constraint...
This holds a decoded list of input/inout and output ports for a module or instance.