Skip to content

Commit ab03141

Browse files
authored
[MLIR][Affine] NFC. Move misplaced MDG init method (#71665)
MemRefDependenceGraph::init should have been in affine analysis utils since MemRefDependenceGraph is part of the affine analysis library; its move was missed. Move it. NFC.
1 parent d1ceb74 commit ab03141

File tree

2 files changed

+123
-122
lines changed

2 files changed

+123
-122
lines changed

mlir/lib/Dialect/Affine/Analysis/Utils.cpp

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@
2020
#include "mlir/Dialect/Arith/IR/Arith.h"
2121
#include "mlir/Dialect/Utils/StaticValueUtils.h"
2222
#include "mlir/IR/IntegerSet.h"
23+
#include "mlir/Interfaces/CallInterfaces.h"
24+
#include "llvm/ADT/SetVector.h"
2325
#include "llvm/ADT/SmallPtrSet.h"
2426
#include "llvm/Support/Debug.h"
2527
#include "llvm/Support/raw_ostream.h"
@@ -104,6 +106,127 @@ void Node::getLoadAndStoreMemrefSet(
104106
}
105107
}
106108

109+
// Initializes the data dependence graph by walking operations in `block`.
110+
// Assigns each node in the graph a node id based on program order in 'f'.
111+
bool MemRefDependenceGraph::init() {
112+
LLVM_DEBUG(llvm::dbgs() << "--- Initializing MDG ---\n");
113+
// Map from a memref to the set of ids of the nodes that have ops accessing
114+
// the memref.
115+
DenseMap<Value, SetVector<unsigned>> memrefAccesses;
116+
117+
DenseMap<Operation *, unsigned> forToNodeMap;
118+
for (Operation &op : block) {
119+
if (dyn_cast<AffineForOp>(op)) {
120+
// Create graph node 'id' to represent top-level 'forOp' and record
121+
// all loads and store accesses it contains.
122+
LoopNestStateCollector collector;
123+
collector.collect(&op);
124+
// Return false if a region holding op other than 'affine.for' and
125+
// 'affine.if' was found (not currently supported).
126+
if (collector.hasNonAffineRegionOp)
127+
return false;
128+
Node node(nextNodeId++, &op);
129+
for (auto *opInst : collector.loadOpInsts) {
130+
node.loads.push_back(opInst);
131+
auto memref = cast<AffineReadOpInterface>(opInst).getMemRef();
132+
memrefAccesses[memref].insert(node.id);
133+
}
134+
for (auto *opInst : collector.storeOpInsts) {
135+
node.stores.push_back(opInst);
136+
auto memref = cast<AffineWriteOpInterface>(opInst).getMemRef();
137+
memrefAccesses[memref].insert(node.id);
138+
}
139+
forToNodeMap[&op] = node.id;
140+
nodes.insert({node.id, node});
141+
} else if (dyn_cast<AffineReadOpInterface>(op)) {
142+
// Create graph node for top-level load op.
143+
Node node(nextNodeId++, &op);
144+
node.loads.push_back(&op);
145+
auto memref = cast<AffineReadOpInterface>(op).getMemRef();
146+
memrefAccesses[memref].insert(node.id);
147+
nodes.insert({node.id, node});
148+
} else if (dyn_cast<AffineWriteOpInterface>(op)) {
149+
// Create graph node for top-level store op.
150+
Node node(nextNodeId++, &op);
151+
node.stores.push_back(&op);
152+
auto memref = cast<AffineWriteOpInterface>(op).getMemRef();
153+
memrefAccesses[memref].insert(node.id);
154+
nodes.insert({node.id, node});
155+
} else if (op.getNumRegions() != 0) {
156+
// Return false if another region is found (not currently supported).
157+
return false;
158+
} else if (op.getNumResults() > 0 && !op.use_empty()) {
159+
// Create graph node for top-level producer of SSA values, which
160+
// could be used by loop nest nodes.
161+
Node node(nextNodeId++, &op);
162+
nodes.insert({node.id, node});
163+
} else if (isa<CallOpInterface>(op)) {
164+
// Create graph node for top-level Call Op that takes any argument of
165+
// memref type. Call Op that returns one or more memref type results
166+
// is already taken care of, by the previous conditions.
167+
if (llvm::any_of(op.getOperandTypes(),
168+
[&](Type t) { return isa<MemRefType>(t); })) {
169+
Node node(nextNodeId++, &op);
170+
nodes.insert({node.id, node});
171+
}
172+
} else if (hasEffect<MemoryEffects::Write, MemoryEffects::Free>(&op)) {
173+
// Create graph node for top-level op, which could have a memory write
174+
// side effect.
175+
Node node(nextNodeId++, &op);
176+
nodes.insert({node.id, node});
177+
}
178+
}
179+
180+
for (auto &idAndNode : nodes) {
181+
LLVM_DEBUG(llvm::dbgs() << "Create node " << idAndNode.first << " for:\n"
182+
<< *(idAndNode.second.op) << "\n");
183+
(void)idAndNode;
184+
}
185+
186+
// Add dependence edges between nodes which produce SSA values and their
187+
// users. Load ops can be considered as the ones producing SSA values.
188+
for (auto &idAndNode : nodes) {
189+
const Node &node = idAndNode.second;
190+
// Stores don't define SSA values, skip them.
191+
if (!node.stores.empty())
192+
continue;
193+
Operation *opInst = node.op;
194+
for (Value value : opInst->getResults()) {
195+
for (Operation *user : value.getUsers()) {
196+
// Ignore users outside of the block.
197+
if (block.getParent()->findAncestorOpInRegion(*user)->getBlock() !=
198+
&block)
199+
continue;
200+
SmallVector<AffineForOp, 4> loops;
201+
getAffineForIVs(*user, &loops);
202+
if (loops.empty())
203+
continue;
204+
assert(forToNodeMap.count(loops[0]) > 0 && "missing mapping");
205+
unsigned userLoopNestId = forToNodeMap[loops[0]];
206+
addEdge(node.id, userLoopNestId, value);
207+
}
208+
}
209+
}
210+
211+
// Walk memref access lists and add graph edges between dependent nodes.
212+
for (auto &memrefAndList : memrefAccesses) {
213+
unsigned n = memrefAndList.second.size();
214+
for (unsigned i = 0; i < n; ++i) {
215+
unsigned srcId = memrefAndList.second[i];
216+
bool srcHasStore =
217+
getNode(srcId)->getStoreOpCount(memrefAndList.first) > 0;
218+
for (unsigned j = i + 1; j < n; ++j) {
219+
unsigned dstId = memrefAndList.second[j];
220+
bool dstHasStore =
221+
getNode(dstId)->getStoreOpCount(memrefAndList.first) > 0;
222+
if (srcHasStore || dstHasStore)
223+
addEdge(srcId, dstId, memrefAndList.first);
224+
}
225+
}
226+
}
227+
return true;
228+
}
229+
107230
// Returns the graph node for 'id'.
108231
Node *MemRefDependenceGraph::getNode(unsigned id) {
109232
auto it = nodes.find(id);

mlir/lib/Dialect/Affine/Transforms/LoopFusion.cpp

Lines changed: 0 additions & 122 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@
2727
#include "llvm/ADT/DenseMap.h"
2828
#include "llvm/ADT/DenseSet.h"
2929
#include "llvm/ADT/STLExtras.h"
30-
#include "llvm/ADT/SetVector.h"
3130
#include "llvm/Support/CommandLine.h"
3231
#include "llvm/Support/Debug.h"
3332
#include "llvm/Support/raw_ostream.h"
@@ -226,127 +225,6 @@ static void gatherEscapingMemrefs(unsigned id, MemRefDependenceGraph *mdg,
226225
}
227226
}
228227

229-
// Initializes the data dependence graph by walking operations in `block`.
230-
// Assigns each node in the graph a node id based on program order in 'f'.
231-
bool MemRefDependenceGraph::init() {
232-
LLVM_DEBUG(llvm::dbgs() << "--- Initializing MDG ---\n");
233-
// Map from a memref to the set of ids of the nodes that have ops accessing
234-
// the memref.
235-
DenseMap<Value, SetVector<unsigned>> memrefAccesses;
236-
237-
DenseMap<Operation *, unsigned> forToNodeMap;
238-
for (Operation &op : block) {
239-
if (dyn_cast<AffineForOp>(op)) {
240-
// Create graph node 'id' to represent top-level 'forOp' and record
241-
// all loads and store accesses it contains.
242-
LoopNestStateCollector collector;
243-
collector.collect(&op);
244-
// Return false if a region holding op other than 'affine.for' and
245-
// 'affine.if' was found (not currently supported).
246-
if (collector.hasNonAffineRegionOp)
247-
return false;
248-
Node node(nextNodeId++, &op);
249-
for (auto *opInst : collector.loadOpInsts) {
250-
node.loads.push_back(opInst);
251-
auto memref = cast<AffineReadOpInterface>(opInst).getMemRef();
252-
memrefAccesses[memref].insert(node.id);
253-
}
254-
for (auto *opInst : collector.storeOpInsts) {
255-
node.stores.push_back(opInst);
256-
auto memref = cast<AffineWriteOpInterface>(opInst).getMemRef();
257-
memrefAccesses[memref].insert(node.id);
258-
}
259-
forToNodeMap[&op] = node.id;
260-
nodes.insert({node.id, node});
261-
} else if (dyn_cast<AffineReadOpInterface>(op)) {
262-
// Create graph node for top-level load op.
263-
Node node(nextNodeId++, &op);
264-
node.loads.push_back(&op);
265-
auto memref = cast<AffineReadOpInterface>(op).getMemRef();
266-
memrefAccesses[memref].insert(node.id);
267-
nodes.insert({node.id, node});
268-
} else if (dyn_cast<AffineWriteOpInterface>(op)) {
269-
// Create graph node for top-level store op.
270-
Node node(nextNodeId++, &op);
271-
node.stores.push_back(&op);
272-
auto memref = cast<AffineWriteOpInterface>(op).getMemRef();
273-
memrefAccesses[memref].insert(node.id);
274-
nodes.insert({node.id, node});
275-
} else if (op.getNumRegions() != 0) {
276-
// Return false if another region is found (not currently supported).
277-
return false;
278-
} else if (op.getNumResults() > 0 && !op.use_empty()) {
279-
// Create graph node for top-level producer of SSA values, which
280-
// could be used by loop nest nodes.
281-
Node node(nextNodeId++, &op);
282-
nodes.insert({node.id, node});
283-
} else if (isa<CallOpInterface>(op)) {
284-
// Create graph node for top-level Call Op that takes any argument of
285-
// memref type. Call Op that returns one or more memref type results
286-
// is already taken care of, by the previous conditions.
287-
if (llvm::any_of(op.getOperandTypes(),
288-
[&](Type t) { return isa<MemRefType>(t); })) {
289-
Node node(nextNodeId++, &op);
290-
nodes.insert({node.id, node});
291-
}
292-
} else if (hasEffect<MemoryEffects::Write, MemoryEffects::Free>(&op)) {
293-
// Create graph node for top-level op, which could have a memory write
294-
// side effect.
295-
Node node(nextNodeId++, &op);
296-
nodes.insert({node.id, node});
297-
}
298-
}
299-
300-
for (auto &idAndNode : nodes) {
301-
LLVM_DEBUG(llvm::dbgs() << "Create node " << idAndNode.first << " for:\n"
302-
<< *(idAndNode.second.op) << "\n");
303-
(void)idAndNode;
304-
}
305-
306-
// Add dependence edges between nodes which produce SSA values and their
307-
// users. Load ops can be considered as the ones producing SSA values.
308-
for (auto &idAndNode : nodes) {
309-
const Node &node = idAndNode.second;
310-
// Stores don't define SSA values, skip them.
311-
if (!node.stores.empty())
312-
continue;
313-
Operation *opInst = node.op;
314-
for (Value value : opInst->getResults()) {
315-
for (Operation *user : value.getUsers()) {
316-
// Ignore users outside of the block.
317-
if (block.getParent()->findAncestorOpInRegion(*user)->getBlock() !=
318-
&block)
319-
continue;
320-
SmallVector<AffineForOp, 4> loops;
321-
getAffineForIVs(*user, &loops);
322-
if (loops.empty())
323-
continue;
324-
assert(forToNodeMap.count(loops[0]) > 0 && "missing mapping");
325-
unsigned userLoopNestId = forToNodeMap[loops[0]];
326-
addEdge(node.id, userLoopNestId, value);
327-
}
328-
}
329-
}
330-
331-
// Walk memref access lists and add graph edges between dependent nodes.
332-
for (auto &memrefAndList : memrefAccesses) {
333-
unsigned n = memrefAndList.second.size();
334-
for (unsigned i = 0; i < n; ++i) {
335-
unsigned srcId = memrefAndList.second[i];
336-
bool srcHasStore =
337-
getNode(srcId)->getStoreOpCount(memrefAndList.first) > 0;
338-
for (unsigned j = i + 1; j < n; ++j) {
339-
unsigned dstId = memrefAndList.second[j];
340-
bool dstHasStore =
341-
getNode(dstId)->getStoreOpCount(memrefAndList.first) > 0;
342-
if (srcHasStore || dstHasStore)
343-
addEdge(srcId, dstId, memrefAndList.first);
344-
}
345-
}
346-
}
347-
return true;
348-
}
349-
350228
// Sinks all sequential loops to the innermost levels (while preserving
351229
// relative order among them) and moves all parallel loops to the
352230
// outermost (while again preserving relative order among them).

0 commit comments

Comments
 (0)