@@ -132,16 +132,17 @@ computeDestructuringInfo(DestructurableMemorySlot &slot,
132132// / Performs the destructuring of a destructible slot given associated
133133// / destructuring information. The provided slot will be destructured in
134134// / 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) {
140141 OpBuilder::InsertionGuard guard (builder);
141142
142143 builder.setInsertionPointToStart (slot.ptr .getParentBlock ());
143144 DenseMap<Attribute, MemorySlot> subslots =
144- allocator.destructure (slot, info.usedIndices , builder);
145+ allocator.destructure (slot, info.usedIndices , builder, newAllocators );
145146
146147 if (statistics.slotsWithMemoryBenefit &&
147148 slot.elementPtrs .size () != info.usedIndices .size ())
@@ -185,7 +186,11 @@ static void destructureSlot(DestructurableMemorySlot &slot,
185186 if (statistics.destructuredAmount )
186187 (*statistics.destructuredAmount )++;
187188
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);
189194}
190195
191196LogicalResult mlir::tryToDestructureMemorySlots (
@@ -194,16 +199,44 @@ LogicalResult mlir::tryToDestructureMemorySlots(
194199 SROAStatistics statistics) {
195200 bool destructuredAny = false ;
196201
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 ;
203218
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;
206230 }
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 ();
207240 }
208241
209242 return success (destructuredAny);
@@ -230,23 +263,16 @@ struct SROA : public impl::SROABase<SROA> {
230263
231264 OpBuilder builder (®ion.front (), region.front ().begin ());
232265
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+ });
247271
272+ // Attempt to destructure as many slots as possible.
273+ if (succeeded (tryToDestructureMemorySlots (allocators, builder, dataLayout,
274+ statistics)))
248275 changed = true ;
249- }
250276 }
251277 if (!changed)
252278 markAllAnalysesPreserved ();
0 commit comments