10#include "mlir/IR/SymbolTable.h"
18static bool isSymbolReference(Attribute value) {
19 auto array = dyn_cast<ArrayAttr>(value);
20 return isa<SymbolRefAttr>(value) ||
21 (array && llvm::all_of(array, llvm::IsaPred<SymbolRefAttr>));
27static void describe(Operation *op, llvm::raw_ostream &os) {
29 for (NamedAttribute attr : op->getAttrs()) {
30 if (isSymbolReference(attr.getValue()) ||
31 attr.getName() == SymbolTable::getSymbolAttrName())
33 os <<
' ' << attr.getName();
34 if (attr.getName() !=
"fifoName")
35 os <<
'=' << attr.getValue();
41 llvm::raw_string_ostream os(
features[op]);
47 links[from].push_back({label.str(), to});
48 links[to].push_back({(label +
"~").str(), from});
52 DenseMap<Operation *, unsigned>
rank;
54 auto rerank = [&](
auto &signature) {
55 SmallVector<Operation *> order(
nodes);
56 llvm::stable_sort(order, [&](Operation *a, Operation *b) {
57 return signature.at(a) < signature.at(b);
60 for (
auto [index, op] : llvm::enumerate(order)) {
61 if (index && signature.at(order[index - 1]) < signature.at(op))
67 std::map<Operation *, std::string> initial;
68 for (Operation *op :
nodes)
71 for (
unsigned previous = 0; classes != previous;) {
74 std::pair<unsigned, SmallVector<std::pair<std::string, unsigned>>>>
76 for (Operation *op :
nodes) {
77 auto &[own, around] = signature[op];
79 for (
const auto &[label, other] :
links.lookup(op))
80 around.push_back({label,
rank[other]});
91 DenseMap<Operation *, std::pair<Operation *, unsigned>> position;
92 for (Operation &op : device.getBody()->without_terminator()) {
93 if (isa<RuntimeSequenceOp>(op))
95 llvm::raw_string_ostream os(graph.
add(&op));
97 op.walk<WalkOrder::PreOrder>([&](Operation *nested) {
98 position[nested] = {&op, index++};
101 describe(nested, os);
106 for (Operation *node : SmallVector<Operation *>(graph.
nodes)) {
107 node->walk<WalkOrder::PreOrder>([&](Operation *nested) {
108 std::string at = std::to_string(position.lookup(nested).second);
109 for (
auto [index, operand] : llvm::enumerate(nested->getOperands())) {
110 Operation *def = operand.getDefiningOp();
111 if (def && def->getParentOp() == device && graph.
features.count(def))
112 graph.
link(node, def, at +
":" + std::to_string(index));
114 for (NamedAttribute attr : nested->getAttrs()) {
115 if (!isSymbolReference(attr.getValue()))
117 SmallVector<SymbolRefAttr> refs;
118 if (
auto ref = dyn_cast<SymbolRefAttr>(attr.getValue()))
123 cast<ArrayAttr>(attr.getValue()).getAsRange<SymbolRefAttr>());
124 for (
auto [index, ref] : llvm::enumerate(refs)) {
126 position.find(SymbolTable::lookupNearestSymbolFrom(nested, ref));
127 if (it == position.end())
129 auto [target, within] = it->second;
130 graph.
link(node, target,
131 at +
":" + attr.getName().str() +
":" +
132 std::to_string(index) +
"@" + std::to_string(within));
Ops and the labelled links between them, for ranking them by structure where a pass would otherwise f...
void link(mlir::Operation *from, mlir::Operation *to, llvm::StringRef label)
Link from to to under label, and to back to from.
llvm::SmallVector< mlir::Operation * > nodes
std::string & add(mlir::Operation *op)
Add op as a node whose features are its name and attributes, symbol names and references left out.
llvm::DenseMap< mlir::Operation *, unsigned > rank() const
Rank the nodes by their features and then, a round at a time until no class splits,...
llvm::DenseMap< mlir::Operation *, std::string > features
What each node is, before anything it links to is considered.
static StructuralGraph of(DeviceOp device)
The ops directly in device but its runtime sequences, each with the ops nested in it,...
llvm::DenseMap< mlir::Operation *, llvm::SmallVector< std::pair< std::string, mlir::Operation * > > > links