Skip to content

Commit db8c0fc

Browse files
hunhoffeclaude
andcommitted
[python][iron] ObjectFifo: emit per-handle depth ArrayAttr instead of collapsing equal depths
Cherry-picks the python-side change from upstream PR Xilinx#3096 ("Fix objectfifo declared depth as minimum"). IRON's ObjectFifo previously collapsed `[prod_depth, *cons_depths]` to a single int when all values were equal, which the `aie-objectFifo-stateful-transform` lowering interpreted as "producer depth only" and silently auto-minimized each consumer's ping-pong from max-acquire -- dropping below the user's declared depth. For multi-consumer fanout with uneven acquire patterns (one consumer must buffer ahead of a peer that's waiting on upstream data), the auto-minimize sized every pool to 2 (ping-pong) regardless of what .cons(depth=N) requested, deadlocking at runtime. Concrete symptom hit in this branch: yolo26n m6 (c3k2_heavy) bot_fifo fanout to m_0_split AND cv3_cv2. ObjectFifo declared depth=6, .cons(depth=6) on both consumers, but lowered IR allocated 2 buffers per pool and m6 standalone TIMEOUT'd. After the fix the producer pool gets 6 buffers, each consumer pool gets 6 buffers, and m6 runs bit- exact at 66.9 fps. m2 (c3k2_small, same fanout pattern, also depth=6 + .cons(depth=6)x2) was getting prod=6/cons=4 pre-fix (some other auto-sizing path); post-fix it gets the full 6 everywhere and m2 perf goes 62.4 -> 69.7 fps as a side effect. Test included upstream: `test/python/objFifo_iron_multi_cons_depth.py`. Co-Authored-By: Claude Opus 4 (1M context) <noreply@anthropic.com>
1 parent b5a3004 commit db8c0fc

1 file changed

Lines changed: 17 additions & 15 deletions

File tree

python/iron/dataflow/objectfifo.py

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -267,20 +267,6 @@ def _cons_tiles_ops(self) -> list[Tile]:
267267
)
268268
return [cons.endpoint.tile.op for cons in self._cons]
269269

270-
def _get_depths(self) -> int | list[int]:
271-
if not self._prod:
272-
raise ValueError(
273-
"Cannot return depths since prod ObjectFifoHandle is not created."
274-
)
275-
if len(self._cons) == 0:
276-
raise ValueError(
277-
"Cannot return depths since no cons ObjectFifoHandles are created."
278-
)
279-
depths = [self._prod.depth] + [con.depth for con in self._cons]
280-
if len(set(depths)) == 1:
281-
return depths[0]
282-
return depths
283-
284270
def _get_endpoint(self, is_prod: bool) -> list[ObjectFifoEndpoint]:
285271
if is_prod:
286272
if self._prod:
@@ -304,11 +290,27 @@ def resolve(
304290
for con in self._cons
305291
]
306292

293+
if not self._prod:
294+
raise ValueError(
295+
f"ObjectFifo {self.name}: producer handle not created."
296+
)
297+
if len(self._cons) == 0:
298+
raise ValueError(
299+
f"ObjectFifo {self.name}: no consumer handles created."
300+
)
301+
# Always emit the per-handle ArrayAttr [prod_depth, *cons_depths].
302+
# Collapsing to a single int when all are equal triggers the
303+
# stateful-transform's auto-minimize path, which sizes each
304+
# consumer's ping-pong from max-acquire instead of honoring the
305+
# declared depth -- silently deadlocking multi-consumer fanout
306+
# designs where one consumer must buffer ahead of the others.
307+
depths = [self._prod.depth] + [con.depth for con in self._cons]
308+
307309
self._op = object_fifo(
308310
self.name,
309311
self._prod_tile_op(),
310312
self._cons_tiles_ops(),
311-
self._get_depths(),
313+
depths,
312314
np_ndarray_type_to_memref_type(self._obj_type),
313315
dimensionsToStream=self._dims_to_stream,
314316
dimensionsFromStreamPerConsumer=dims_from_stream_per_cons,

0 commit comments

Comments
 (0)