@@ -132,16 +132,17 @@ computeDestructuringInfo(DestructurableMemorySlot &slot,
132
132
// / Performs the destructuring of a destructible slot given associated
133
133
// / destructuring information. The provided slot will be destructured in
134
134
// / subslots as specified by its allocator.
135
- static void destructureSlot (DestructurableMemorySlot &slot,
136
- DestructurableAllocationOpInterface allocator,
137
- OpBuilder &builder, const DataLayout &dataLayout,
138
- MemorySlotDestructuringInfo &info,
139
- const SROAStatistics &statistics) {
135
+ static void destructureSlot (
136
+ DestructurableMemorySlot &slot,
137
+ DestructurableAllocationOpInterface allocator, OpBuilder &builder,
138
+ const DataLayout &dataLayout, MemorySlotDestructuringInfo &info,
139
+ SmallVectorImpl<DestructurableAllocationOpInterface> &newAllocators,
140
+ const SROAStatistics &statistics) {
140
141
OpBuilder::InsertionGuard guard (builder);
141
142
142
143
builder.setInsertionPointToStart (slot.ptr .getParentBlock ());
143
144
DenseMap<Attribute, MemorySlot> subslots =
144
- allocator.destructure (slot, info.usedIndices , builder);
145
+ allocator.destructure (slot, info.usedIndices , builder, newAllocators );
145
146
146
147
if (statistics.slotsWithMemoryBenefit &&
147
148
slot.elementPtrs .size () != info.usedIndices .size ())
@@ -185,7 +186,11 @@ static void destructureSlot(DestructurableMemorySlot &slot,
185
186
if (statistics.destructuredAmount )
186
187
(*statistics.destructuredAmount )++;
187
188
188
- allocator.handleDestructuringComplete (slot, builder);
189
+ std::optional<DestructurableAllocationOpInterface> newAllocator =
190
+ allocator.handleDestructuringComplete (slot, builder);
191
+ // Add newly created allocators to the worklist for further processing.
192
+ if (newAllocator)
193
+ newAllocators.push_back (*newAllocator);
189
194
}
190
195
191
196
LogicalResult mlir::tryToDestructureMemorySlots (
@@ -194,16 +199,44 @@ LogicalResult mlir::tryToDestructureMemorySlots(
194
199
SROAStatistics statistics) {
195
200
bool destructuredAny = false ;
196
201
197
- for (DestructurableAllocationOpInterface allocator : allocators) {
198
- for (DestructurableMemorySlot slot : allocator.getDestructurableSlots ()) {
199
- std::optional<MemorySlotDestructuringInfo> info =
200
- computeDestructuringInfo (slot, dataLayout);
201
- if (!info)
202
- continue ;
202
+ SmallVector<DestructurableAllocationOpInterface> workList (allocators.begin (),
203
+ allocators.end ());
204
+ SmallVector<DestructurableAllocationOpInterface> newWorkList;
205
+ newWorkList.reserve (allocators.size ());
206
+ // Destructuring a slot can allow for further destructuring of other
207
+ // slots, destructuring is tried until no destructuring succeeds.
208
+ while (true ) {
209
+ bool changesInThisRound = false ;
210
+
211
+ for (DestructurableAllocationOpInterface allocator : workList) {
212
+ bool destructuredAnySlot = false ;
213
+ for (DestructurableMemorySlot slot : allocator.getDestructurableSlots ()) {
214
+ std::optional<MemorySlotDestructuringInfo> info =
215
+ computeDestructuringInfo (slot, dataLayout);
216
+ if (!info)
217
+ continue ;
203
218
204
- destructureSlot (slot, allocator, builder, dataLayout, *info, statistics);
205
- destructuredAny = true ;
219
+ destructureSlot (slot, allocator, builder, dataLayout, *info,
220
+ newWorkList, statistics);
221
+ destructuredAnySlot = true ;
222
+
223
+ // A break is required, since destructuring a slot may invalidate the
224
+ // remaning slots of an allocator.
225
+ break ;
226
+ }
227
+ if (!destructuredAnySlot)
228
+ newWorkList.push_back (allocator);
229
+ changesInThisRound |= destructuredAnySlot;
206
230
}
231
+
232
+ if (!changesInThisRound)
233
+ break ;
234
+ destructuredAny |= changesInThisRound;
235
+
236
+ // Swap the vector's backing memory and clear the entries in newWorkList
237
+ // afterwards. This ensures that additional heap allocations can be avoided.
238
+ workList.swap (newWorkList);
239
+ newWorkList.clear ();
207
240
}
208
241
209
242
return success (destructuredAny);
@@ -230,23 +263,16 @@ struct SROA : public impl::SROABase<SROA> {
230
263
231
264
OpBuilder builder (®ion.front (), region.front ().begin ());
232
265
233
- // Destructuring a slot can allow for further destructuring of other
234
- // slots, destructuring is tried until no destructuring succeeds.
235
- while (true ) {
236
- SmallVector<DestructurableAllocationOpInterface> allocators;
237
- // Build a list of allocators to attempt to destructure the slots of.
238
- // TODO: Update list on the fly to avoid repeated visiting of the same
239
- // allocators.
240
- region.walk ([&](DestructurableAllocationOpInterface allocator) {
241
- allocators.emplace_back (allocator);
242
- });
243
-
244
- if (failed (tryToDestructureMemorySlots (allocators, builder, dataLayout,
245
- statistics)))
246
- break ;
266
+ SmallVector<DestructurableAllocationOpInterface> allocators;
267
+ // Build a list of allocators to attempt to destructure the slots of.
268
+ region.walk ([&](DestructurableAllocationOpInterface allocator) {
269
+ allocators.emplace_back (allocator);
270
+ });
247
271
272
+ // Attempt to destructure as many slots as possible.
273
+ if (succeeded (tryToDestructureMemorySlots (allocators, builder, dataLayout,
274
+ statistics)))
248
275
changed = true ;
249
- }
250
276
}
251
277
if (!changed)
252
278
markAllAnalysesPreserved ();
0 commit comments