Skip to content

Commit b5f6eae

Browse files
yenjamesclaude
andcommitted
iron: accept tile=None in Worker, ObjectFifoLink, RuntimeEndpoint
Worker, ObjectFifoLink (used by split/forward/join), and RuntimeEndpoint (used by rt.fill/rt.drain) now silently accept tile=None, treating it the same as the default (AnyComputeTile, AnyMemTile, or AnyShimTile respectively). This allows callers to pass None to mean "unplaced" without needing conditional keyword splat patterns. Signatures and defaults are unchanged — existing code is unaffected. Refactor mobilenet builders to use direct tile=value instead of the **tile_kw() splat helper, which is now removed. Co-Authored-By: Claude Opus 4 (1M context) <noreply@anthropic.com>
1 parent a844be0 commit b5f6eae

11 files changed

Lines changed: 46 additions & 63 deletions

File tree

programming_examples/ml/mobilenet/aie2_mobilenet_iron.py

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,6 @@
3838

3939
sys.path.insert(0, str(pathlib.Path(__file__).parent))
4040

41-
from bottleneck._common import tile_kw
4241
from bottleneck.init import init_conv
4342
from bottleneck.regular import regular_bottlenecks
4443
from bottleneck.pipeline import pipeline_bottlenecks
@@ -168,7 +167,7 @@ def _wts_tap(byte_offset, byte_size):
168167
rt.fill(
169168
act_in.prod(depth=1),
170169
inp,
171-
**tile_kw(shim.get("input")),
170+
tile=shim.get("input"),
172171
task_group=tg1,
173172
)
174173
# bn13/14 L1+L3 weight chunks from the combined cascade buffer
@@ -180,7 +179,7 @@ def _wts_tap(byte_offset, byte_size):
180179
fifo.prod(),
181180
cascade_wts,
182181
_wts_tap(off, sz),
183-
**tile_kw(s),
182+
tile=s,
184183
task_group=tg1,
185184
)
186185
# Round-trip avgpool output through L3 (shim 30/40 hop). Reuse `inp`
@@ -203,7 +202,7 @@ def _wts_tap(byte_offset, byte_size):
203202
tap=_post_l1_scratch_tap,
204203
wait=True,
205204
task_group=tg1,
206-
**tile_kw(shim.get("scratch_drain")),
205+
tile=shim.get("scratch_drain"),
207206
)
208207
rt.finish_task_group(tg1)
209208

@@ -218,7 +217,7 @@ def _wts_tap(byte_offset, byte_size):
218217
inp,
219218
tap=_post_l1_scratch_tap,
220219
task_group=tg2,
221-
**tile_kw(shim.get("fc_fill")),
220+
tile=shim.get("fc_fill"),
222221
)
223222
_post_fc_out_tap = TensorAccessPattern(
224223
(_inp_sz_i32,),
@@ -232,7 +231,7 @@ def _wts_tap(byte_offset, byte_size):
232231
tap=_post_fc_out_tap,
233232
wait=True,
234233
task_group=tg2,
235-
**tile_kw(shim.get("fc_drain")),
234+
tile=shim.get("fc_drain"),
236235
)
237236
rt.finish_task_group(tg2)
238237

@@ -243,14 +242,14 @@ def _wts_tap(byte_offset, byte_size):
243242
inp,
244243
tap=_post_fc_out_tap,
245244
task_group=tg3,
246-
**tile_kw(shim.get("fc_fill")),
245+
tile=shim.get("fc_fill"),
247246
)
248247
rt.drain(
249248
act_out_of.cons(),
250249
out,
251250
wait=True,
252251
task_group=tg3,
253-
**tile_kw(shim.get("fc_drain")),
252+
tile=shim.get("fc_drain"),
254253
)
255254
rt.finish_task_group(tg3)
256255

programming_examples/ml/mobilenet/bottleneck/_common.py

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -63,21 +63,3 @@ def layer_sf(blk, sf, idx):
6363
def skip_sf(blk, sf):
6464
"""Scale factor for the skip-add (only valid when blk.skip is True)."""
6565
return sf[sf_key(blk.name)][blk.skip_sf_key]
66-
67-
68-
def tile_kw(tile_or_dict, dict_key=None, *, kw="tile"):
69-
"""Build a keyword-arg dict for optional tile placement.
70-
71-
Returns ``{kw: tile}`` when a tile is provided, or ``{}`` when ``None``.
72-
Intended for ``**tile_kw(...)`` splat into Worker / ObjectFifo calls so
73-
that placement is only passed when explicitly requested.
74-
75-
Args:
76-
tile_or_dict: A Tile, a dict of tiles, or None.
77-
dict_key: If *tile_or_dict* is a dict, extract this key.
78-
kw: Keyword name to use (default ``"tile"``).
79-
"""
80-
if tile_or_dict is None:
81-
return {}
82-
tile = tile_or_dict[dict_key] if dict_key is not None else tile_or_dict
83-
return {kw: tile}

programming_examples/ml/mobilenet/bottleneck/cascade.py

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@
3434
load_wts,
3535
layer_sf as _layer_sf,
3636
skip_sf as _skip_sf,
37-
tile_kw,
3837
)
3938
from network_spec import block as nsblock
4039

@@ -332,21 +331,22 @@ def build_cascade(blk, l3_get_sym, act_in, skip_in, sf, *, data_dir, tiles=None)
332331
)
333332

334333
# Streaming weight fifos (Shim → MemTile → split → put/get tiles)
334+
t = tiles.get if tiles else lambda k: None
335335
wts_l1_full = ObjectFifo(_ty_l1_full_wts, depth=1)
336336
wts_l1_put_h, wts_l1_get_h = wts_l1_full.cons().split(
337337
offsets=[0, _l1_full_wts_sz // 2],
338338
depths=[1, 1],
339339
obj_types=[_ty_l1_split_wts, _ty_l1_split_wts],
340340
repeat_counts=[_InH, _InH],
341-
**tile_kw(tiles, "mem_l1"),
341+
tile=t("mem_l1"),
342342
)
343343
wts_l3_full = ObjectFifo(_ty_l3_full_wts, depth=1)
344344
wts_l3_put_h, wts_l3_get_h = wts_l3_full.cons().split(
345345
offsets=[0, _l3_full_wts_sz // 2],
346346
depths=[1, 1],
347347
obj_types=[_ty_l3_split_wts, _ty_l3_split_wts],
348348
repeat_counts=[_InH, _InH],
349-
**tile_kw(tiles, "mem_l3"),
349+
tile=t("mem_l3"),
350350
)
351351

352352
# L2 DW weights are static (compile-time bake-in)
@@ -377,7 +377,7 @@ def build_cascade(blk, l3_get_sym, act_in, skip_in, sf, *, data_dir, tiles=None)
377377
l1_get_cons = act_in.cons()
378378
# depth=6 on the cons handle lets the skip path buffer enough rows to
379379
# outlive the 5-tile cascade pipeline lag (l1_put → l1_get → l2 → l3_put → l3_get).
380-
skip_fifo = skip_in.cons(depth=6).forward(depth=2, **tile_kw(tiles, "mem_skip"))
380+
skip_fifo = skip_in.cons(depth=6).forward(depth=2, tile=t("mem_skip"))
381381

382382
bws = [
383383
Worker(
@@ -394,7 +394,7 @@ def build_cascade(blk, l3_get_sym, act_in, skip_in, sf, *, data_dir, tiles=None)
394394
_OC8,
395395
s1,
396396
],
397-
**tile_kw(tiles, "l1_put"),
397+
tile=t("l1_put"),
398398
),
399399
Worker(
400400
_l1_get_fn,
@@ -411,7 +411,7 @@ def build_cascade(blk, l3_get_sym, act_in, skip_in, sf, *, data_dir, tiles=None)
411411
_OC8,
412412
s1,
413413
],
414-
**tile_kw(tiles, "l1_get"),
414+
tile=t("l1_get"),
415415
),
416416
Worker(
417417
_l2_fn,
@@ -425,7 +425,7 @@ def build_cascade(blk, l3_get_sym, act_in, skip_in, sf, *, data_dir, tiles=None)
425425
_L1_OutC,
426426
s2,
427427
],
428-
**tile_kw(tiles, "l2"),
428+
tile=t("l2"),
429429
),
430430
Worker(
431431
_l3_put_fn,
@@ -441,7 +441,7 @@ def build_cascade(blk, l3_get_sym, act_in, skip_in, sf, *, data_dir, tiles=None)
441441
_OC8_out,
442442
s3,
443443
],
444-
**tile_kw(tiles, "l3_put"),
444+
tile=t("l3_put"),
445445
),
446446
Worker(
447447
_l3_get_fn,
@@ -460,7 +460,7 @@ def build_cascade(blk, l3_get_sym, act_in, skip_in, sf, *, data_dir, tiles=None)
460460
s3,
461461
s_add,
462462
],
463-
**tile_kw(tiles, "l3_get"),
463+
tile=t("l3_get"),
464464
),
465465
]
466466
# Cascade flows: L1 put→get and L3 put→get share streams between adjacent tiles.

programming_examples/ml/mobilenet/bottleneck/init.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919
from aie.iron import Buffer, Kernel, ObjectFifo, Worker
2020
from aie.iron.controlflow import range_
2121

22-
from bottleneck._common import i8, u8, load_wts, tile_kw
22+
from bottleneck._common import i8, u8, load_wts
2323
from network_spec import block as nsblock
2424

2525

@@ -135,7 +135,7 @@ def init_fn(act_in, act_out, wts, k, inW, inH, inC, outW, outH, outC, sf):
135135
init_OutC,
136136
init_scaleFactor,
137137
],
138-
**tile_kw(placement),
138+
tile=placement,
139139
)
140140

141141
return [w_init], act_in, act_init_out

programming_examples/ml/mobilenet/bottleneck/pipeline.py

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@
2626
load_wts as _load_weights,
2727
layer_sf as _layer_sf,
2828
skip_sf as _skip_sf,
29-
tile_kw,
3029
wts_buffer as _wts_buf,
3130
)
3231
from network_spec import block as nsblock
@@ -129,26 +128,25 @@ def call(r_in, r_out, _):
129128
# L3 reads a forwarded skip path — caller passes skip_in already; we
130129
# only need its .cons() handle for this Worker.
131130
skip_h = skip_in.cons()
131+
t = tiles.get if tiles else lambda k: None
132132
workers = [
133-
Worker(l1_fn, [l1_in_h, of_12.prod(), l1_wts, k_l1], **tile_kw(tiles, "l1")),
134-
Worker(
135-
l2_fn, [of_12.cons(), of_23.prod(), l2_wts, k_l2], **tile_kw(tiles, "l2")
136-
),
133+
Worker(l1_fn, [l1_in_h, of_12.prod(), l1_wts, k_l1], tile=t("l1")),
134+
Worker(l2_fn, [of_12.cons(), of_23.prod(), l2_wts, k_l2], tile=t("l2")),
137135
]
138136
if has_skip:
139137
workers.append(
140138
Worker(
141139
l3_fn,
142140
[of_23.cons(), skip_h, out_fifo.prod(), l3_wts, k_l3],
143-
**tile_kw(tiles, "l3"),
141+
tile=t("l3"),
144142
)
145143
)
146144
else:
147145
workers.append(
148146
Worker(
149147
l3_fn,
150148
[of_23.cons(), out_fifo.prod(), l3_wts, k_l3],
151-
**tile_kw(tiles, "l3"),
149+
tile=t("l3"),
152150
)
153151
)
154152
return out_fifo, workers
@@ -305,11 +303,12 @@ def _pw():
305303
dw_tmp_prod.release(1)
306304
_pw()
307305

306+
t = tiles.get if tiles else lambda k: None
308307
workers = [
309308
Worker(
310309
bn12_l1_fn,
311310
[act_in.cons(), bn12_of_12.prod(), bn12_l1_wts, k_bn12_l1],
312-
**tile_kw(tiles, "l1"),
311+
tile=t("l1"),
313312
),
314313
Worker(
315314
bn12_l23_fn,
@@ -322,7 +321,7 @@ def _pw():
322321
k_bn12_dw,
323322
k_bn12_pw,
324323
],
325-
**tile_kw(tiles, "l23"),
324+
tile=t("l23"),
326325
),
327326
]
328327
return act_bn12_out, workers
@@ -354,7 +353,9 @@ def pipeline_bottlenecks(
354353
tiles = p.get(name)
355354
skip_in = None
356355
if has_skip:
357-
skip_in = act.cons(depth=6).forward(depth=2, **tile_kw(tiles, "mem_skip"))
356+
skip_in = act.cons(depth=6).forward(
357+
depth=2, tile=tiles.get("mem_skip") if tiles else None
358+
)
358359
# Strip mem_skip so only l1/l2/l3 are passed to the builder.
359360
if tiles is not None:
360361
tiles = {k: tiles[k] for k in ("l1", "l2", "l3")}

programming_examples/ml/mobilenet/bottleneck/post_l1.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
from aie.iron.dataflow.endpoint import ObjectFifoEndpoint
2323
from aie.iron.device import AnyMemTile
2424

25-
from bottleneck._common import i8, load_wts, tile_kw
25+
from bottleneck._common import i8, load_wts
2626
from network_spec import block as nsblock
2727

2828

@@ -154,7 +154,7 @@ def post_l1_fn(
154154
# loop intact with 1 call site). The dynamic lowering uses runtime
155155
# modulo indexing, preserving the loop structure.
156156
dynamic_objfifo_lowering=True,
157-
**tile_kw(placement, "compute"),
157+
tile=placement["compute"] if placement else None,
158158
)
159159

160160
return [w_post_l1], act_out_post_avgpool_shim

programming_examples/ml/mobilenet/bottleneck/post_l2.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
from aie.iron.dataflow.endpoint import ObjectFifoEndpoint
2222
from aie.iron.device import AnyMemTile
2323

24-
from bottleneck._common import i8, load_wts, tile_kw
24+
from bottleneck._common import i8, load_wts
2525
from network_spec import block as nsblock
2626

2727

@@ -76,7 +76,7 @@ def post_l2(act_in, sf, *, placement=None, data_dir):
7676
offsets=[i * fc_out_per_tile for i in range(n_fc_tiles)],
7777
depths=[2] * n_fc_tiles,
7878
obj_types=[np.ndarray[(co,), np.dtype[np.uint16]]] * n_fc_tiles,
79-
**tile_kw(placement, "join_memtile"),
79+
tile=placement["join_memtile"] if placement else None,
8080
)
8181

8282
def _u16(shape):

programming_examples/ml/mobilenet/bottleneck/regular.py

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@
3030
u8 as _u8,
3131
layer_sf as _layer_sf,
3232
skip_sf as _skip_sf,
33-
tile_kw,
3433
wts_buffer as _wts_buffer,
3534
)
3635
from network_spec import block as nsblock
@@ -270,7 +269,7 @@ def _pw_pair(rows_in):
270269
k_l3,
271270
],
272271
while_true=False,
273-
**tile_kw(tile),
272+
tile=tile,
274273
)
275274
return out_fifo, worker
276275

@@ -386,7 +385,7 @@ def _skip(skip_row):
386385
k_skip,
387386
],
388387
while_true=False,
389-
**tile_kw(tile),
388+
tile=tile,
390389
)
391390
return out_fifo, worker
392391

@@ -473,14 +472,12 @@ def _kernels(name, dw_ch, in_c_local, out_c_local, l1_sz, l2_sz, l3_sz):
473472
out_fifo = ObjectFifo(_i8((in_w, 1, b_out_c)), depth=out_depth)
474473

475474
# Self-loop fifos (no synchronization — single core).
476-
_dt = tile_kw(alloc_tile, kw="delegate_tile")
477-
478475
def _of(ch, depth):
479476
return ObjectFifo(
480477
_u8((in_w, 1, ch)),
481478
depth=depth,
482479
disable_synchronization=True,
483-
**_dt,
480+
delegate_tile=alloc_tile,
484481
)
485482

486483
f_a12 = _of(a_dw_ch, 3)
@@ -489,7 +486,7 @@ def _of(ch, depth):
489486
_i8((in_w, 1, a_out_c)),
490487
depth=2,
491488
disable_synchronization=True,
492-
**_dt,
489+
delegate_tile=alloc_tile,
493490
)
494491
f_b12 = _of(b_dw_ch, 3)
495492
f_b23 = _of(b_dw_ch, 1)
@@ -666,7 +663,7 @@ def b_sliding_iter():
666663
kb_skip,
667664
],
668665
while_true=False,
669-
**tile_kw(compute_tile),
666+
tile=compute_tile,
670667
)
671668
return out_fifo, worker
672669

python/iron/dataflow/objectfifo.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -779,7 +779,7 @@ def __init__(
779779
Args:
780780
srcs (list[ObjectFifoHandle] | ObjectFifoHandle): A list of consumer ObjectFifoHandles to link.
781781
dsts (list[ObjectFifoHandle] | ObjectFifoHandle): A list of producer ObjectFifoHandles to link.
782-
tile (Tile, optional): The tile where the link occurs. Defaults to AnyMemTile.
782+
tile (Tile, optional): The tile where the link occurs. Also accepts None (treated as AnyMemTile). Defaults to AnyMemTile.
783783
src_offsets (list[int], optional): If many sources, one offset per source is required to split the destination. Defaults to [].
784784
dst_offsets (list[int], optional): If many destinations, one offset per destination is required to split the source. Defaults to [].
785785
@@ -813,6 +813,8 @@ def __init__(
813813
s.endpoint = self
814814
for d in self._dsts:
815815
d.endpoint = self
816+
if tile is None:
817+
tile = AnyMemTile
816818
tile = tile.copy()
817819
if tile.tile_type is None:
818820
tile.tile_type = AIETileType.MemTile

python/iron/runtime/endpoint.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ class RuntimeEndpoint(ObjectFifoEndpoint):
1919
"""
2020

2121
def __init__(self, tile: Tile = AnyShimTile) -> None:
22+
if tile is None:
23+
tile = AnyShimTile
2224
tile = tile.copy()
2325
if tile.tile_type is not None and tile.tile_type != AIETileType.ShimNOCTile:
2426
raise ValueError(

0 commit comments

Comments
 (0)