Skip to content

Commit c8ff8d2

Browse files
committed
Modify the interference analysis to correct for nested array expressions
and the boxing of arrays as arguments. Fixes f8a, f8b and f8c.
1 parent b3144a7 commit c8ff8d2

File tree

1 file changed

+106
-69
lines changed

1 file changed

+106
-69
lines changed

flang/lib/Optimizer/Transforms/ArrayValueCopy.cpp

Lines changed: 106 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -102,73 +102,86 @@ class ArrayCopyAnalysis {
102102
} // namespace
103103

104104
namespace {
105-
106105
/// Helper class to collect all array operations that produced an array value.
107106
class ReachCollector {
108107
public:
109108
ReachCollector(llvm::SmallVectorImpl<mlir::Operation *> &reach,
110109
mlir::Region *loopRegion)
111110
: reach{reach}, loopRegion{loopRegion} {}
112111

113-
// Recursively trace operands to find all array operations relating to the
114-
// values merged.
115-
void collectArrayAccessFrom(mlir::Value val) {
116-
if (!val || visited.contains(val))
112+
void collectArrayAccessFrom(mlir::Operation *op, mlir::ValueRange range) {
113+
if (range.empty()) {
114+
collectArrayAccessFrom(op, mlir::Value{});
117115
return;
118-
visited.insert(val);
119-
120-
if (auto *op = val.getDefiningOp()) {
121-
// `val` is defined by an Op, process the defining Op.
122-
// If `val` is defined by a region containing Op, we want to drill down
123-
// and through that Op's region(s).
124-
LLVM_DEBUG(llvm::dbgs() << "popset: " << val << '\n');
125-
auto popFn = [&](auto rop) {
126-
auto resNum = val.cast<mlir::OpResult>().getResultNumber();
127-
llvm::SmallVector<mlir::Value> results;
128-
rop.resultToSourceOps(results, resNum);
129-
for (auto u : results)
130-
collectArrayAccessFrom(u);
131-
};
132-
if (auto rop = mlir::dyn_cast<DoLoopOp>(op)) {
133-
popFn(rop);
134-
return;
135-
}
136-
if (auto rop = mlir::dyn_cast<IterWhileOp>(op)) {
137-
popFn(rop);
138-
return;
139-
}
140-
if (auto rop = mlir::dyn_cast<fir::IfOp>(op)) {
141-
popFn(rop);
142-
return;
143-
}
144-
145-
if (mlir::isa<fir::AllocaOp, fir::AllocMemOp>(op))
146-
// Look for any stores inside the loops, and collect an array operation
147-
// that produced the value being stored to it.
148-
for (auto user : op->getUsers())
149-
if (auto store = mlir::dyn_cast<fir::StoreOp>(user))
150-
if (opIsInsideLoops(store))
151-
collectArrayAccessFrom(store.value());
152-
153-
// Otherwise, Op does not contain a region so just chase its operands.
154-
if (mlir::isa<ArrayLoadOp, ArrayUpdateOp, ArrayModifyOp, ArrayFetchOp>(
155-
op)) {
156-
LLVM_DEBUG(llvm::dbgs() << "add " << *op << " to reachable set\n");
157-
reach.emplace_back(op);
158-
}
159-
// Array modify assignment is performed on the result. So the analysis
160-
// must look at the what is done with the result.
161-
if (mlir::isa<ArrayModifyOp>(op))
162-
for (auto user : op->getResult(0).getUsers())
163-
followUsers(user);
116+
}
117+
for (auto v : range)
118+
collectArrayAccessFrom(v);
119+
}
164120

165-
for (auto u : op->getOperands())
121+
void collectArrayAccessFrom(mlir::Operation *op, mlir::Value val) {
122+
// `val` is defined by an Op, process the defining Op.
123+
// If `val` is defined by a region containing Op, we want to drill down
124+
// and through that Op's region(s).
125+
LLVM_DEBUG(llvm::dbgs() << "popset: " << *op << '\n');
126+
auto popFn = [&](auto rop) {
127+
assert(val && "op must have a result value");
128+
auto resNum = val.cast<mlir::OpResult>().getResultNumber();
129+
llvm::SmallVector<mlir::Value> results;
130+
rop.resultToSourceOps(results, resNum);
131+
for (auto u : results)
166132
collectArrayAccessFrom(u);
133+
};
134+
if (auto rop = mlir::dyn_cast<DoLoopOp>(op)) {
135+
popFn(rop);
136+
return;
137+
}
138+
if (auto rop = mlir::dyn_cast<IterWhileOp>(op)) {
139+
popFn(rop);
140+
return;
141+
}
142+
if (auto rop = mlir::dyn_cast<fir::IfOp>(op)) {
143+
popFn(rop);
144+
return;
145+
}
146+
if (auto box = mlir::dyn_cast<EmboxOp>(op)) {
147+
for (auto *user : box.memref().getUsers())
148+
if (user != op)
149+
collectArrayAccessFrom(user, user->getResults());
150+
return;
151+
}
152+
if (auto mergeStore = mlir::dyn_cast<ArrayMergeStoreOp>(op)) {
153+
if (opIsInsideLoops(mergeStore))
154+
collectArrayAccessFrom(mergeStore.sequence());
167155
return;
168156
}
169157

170-
// Process a block argument.
171-
auto ba = val.cast<mlir::BlockArgument>();
158+
if (mlir::isa<AllocaOp, AllocMemOp>(op)) {
159+
// Look for any stores inside the loops, and collect an array operation
160+
// that produced the value being stored to it.
161+
for (auto *user : op->getUsers())
162+
if (auto store = mlir::dyn_cast<fir::StoreOp>(user))
163+
if (opIsInsideLoops(store))
164+
collectArrayAccessFrom(store.value());
165+
return;
166+
}
167+
168+
// Otherwise, Op does not contain a region so just chase its operands.
169+
if (mlir::isa<ArrayLoadOp, ArrayUpdateOp, ArrayModifyOp, ArrayFetchOp>(
170+
op)) {
171+
LLVM_DEBUG(llvm::dbgs() << "add " << *op << " to reachable set\n");
172+
reach.emplace_back(op);
173+
}
174+
// Array modify assignment is performed on the result. So the analysis
175+
// must look at the what is done with the result.
176+
if (mlir::isa<ArrayModifyOp>(op))
177+
for (auto *user : op->getResult(0).getUsers())
178+
followUsers(user);
179+
180+
for (auto u : op->getOperands())
181+
collectArrayAccessFrom(u);
182+
}
183+
184+
void collectArrayAccessFrom(mlir::BlockArgument ba) {
172185
auto *parent = ba.getOwner()->getParentOp();
173186
// If inside an Op holding a region, the block argument corresponds to an
174187
// argument passed to the containing Op.
@@ -190,8 +203,44 @@ class ReachCollector {
190203
}
191204
}
192205

206+
// Recursively trace operands to find all array operations relating to the
207+
// values merged.
208+
void collectArrayAccessFrom(mlir::Value val) {
209+
if (!val || visited.contains(val))
210+
return;
211+
visited.insert(val);
212+
213+
// Process a block argument.
214+
if (auto ba = val.dyn_cast<mlir::BlockArgument>()) {
215+
collectArrayAccessFrom(ba);
216+
return;
217+
}
218+
219+
// Process an Op.
220+
if (auto *op = val.getDefiningOp()) {
221+
collectArrayAccessFrom(op, val);
222+
return;
223+
}
224+
225+
fir::emitFatalError(val.getLoc(), "unhandled value");
226+
}
227+
228+
/// Return all ops that produce the array value that is stored into the
229+
/// `array_merge_store`.
230+
static void reachingValues(llvm::SmallVectorImpl<mlir::Operation *> &reach,
231+
mlir::Value seq) {
232+
reach.clear();
233+
mlir::Region *loopRegion = nullptr;
234+
if (auto doLoop =
235+
mlir::dyn_cast_or_null<fir::DoLoopOp>(seq.getDefiningOp()))
236+
loopRegion = &doLoop->getRegion(0);
237+
ReachCollector collector(reach, loopRegion);
238+
collector.collectArrayAccessFrom(seq);
239+
}
240+
193241
private:
194242
/// Is \op inside the loop nest region ?
243+
/// FIXME: replace this structural dependence with graph properties.
195244
bool opIsInsideLoops(mlir::Operation *op) const {
196245
auto *region = op->getParentRegion();
197246
while (region) {
@@ -219,18 +268,6 @@ class ReachCollector {
219268
};
220269
} // namespace
221270

222-
/// Return all ops that produce the array value that is stored into the
223-
/// `array_merge_store`.
224-
static void reachingValues(llvm::SmallVectorImpl<mlir::Operation *> &reach,
225-
mlir::Value seq) {
226-
reach.clear();
227-
mlir::Region *loopRegion = nullptr;
228-
if (auto doLoop = mlir::dyn_cast_or_null<fir::DoLoopOp>(seq.getDefiningOp()))
229-
loopRegion = &doLoop->getRegion(0);
230-
ReachCollector collector(reach, loopRegion);
231-
collector.collectArrayAccessFrom(seq);
232-
}
233-
234271
/// Find all the array operations that access the array value that is loaded by
235272
/// the array load operation, `load`.
236273
void ArrayCopyAnalysis::arrayAccesses(
@@ -406,7 +443,7 @@ void ArrayCopyAnalysis::construct(mlir::MutableArrayRef<mlir::Region> regions) {
406443
construct(op.getRegions());
407444
if (auto st = mlir::dyn_cast<fir::ArrayMergeStoreOp>(op)) {
408445
llvm::SmallVector<Operation *> values;
409-
reachingValues(values, st.sequence());
446+
ReachCollector::reachingValues(values, st.sequence());
410447
llvm::SmallVector<Operation *> accesses;
411448
arrayAccesses(accesses,
412449
mlir::cast<ArrayLoadOp>(st.original().getDefiningOp()));
@@ -728,9 +765,9 @@ class ArrayUpdateConversion : public ArrayUpdateConversionBase<ArrayUpdateOp> {
728765
if (!update.typeparams().empty()) {
729766
auto boxTy = fir::BoxType::get(inEleTy);
730767
mlir::Value emptyShape, emptySlice;
731-
auto lhs = rewriter.create<fir::EmboxOp>(
768+
auto lhs = rewriter.create<EmboxOp>(
732769
loc, boxTy, coor, emptyShape, emptySlice, update.typeparams());
733-
auto rhs = rewriter.create<fir::EmboxOp>(
770+
auto rhs = rewriter.create<EmboxOp>(
734771
loc, boxTy, input, emptyShape, emptySlice, update.typeparams());
735772
fir::factory::genRecordAssignment(builder, loc, fir::BoxValue(lhs),
736773
fir::BoxValue(rhs));

0 commit comments

Comments
 (0)