Skip to content

[RFC] feat(distributed): ergonomic pld.* collective wrappers — auto window+signal; typing, validation, docs - #2275

Open
georgebisbas wants to merge 1 commit into
hw-native-sys:mainfrom
georgebisbas:feat/ergonomic-collective-api
Open

[RFC] feat(distributed): ergonomic pld.* collective wrappers — auto window+signal; typing, validation, docs#2275
georgebisbas wants to merge 1 commit into
hw-native-sys:mainfrom
georgebisbas:feat/ergonomic-collective-api

Conversation

@georgebisbas

@georgebisbas georgebisbas commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

[RFC] feat(distributed): ergonomic pld.* collective wrappers — auto window+signal; typing, validation, docs

Status: RFC — rebased onto current origin/main (aa773212) + sim-verified, PR MERGEABLE; NPU verification pending (developer gate P=2/P=4). Head 50b18410.
Tracks: #1189 (Scheme A, orchestration-level collectives).
Branch: feat/ergonomic-collective-api — one squashed commit on origin/main.


TL;DR — what this PR is

A pure-Python ergonomic short-form API over the HOST pld.tensor.* collectives. It removes the per-call alloc_window_buffer + window signal boilerplate (and, where needed, the window boilerplate) and adds static typing, early validation, and EN/ZH docs, so distributed host code can be written as:

target = pld.all_gather(local, target)          # was: sig=window(alloc...), tensor.allgather(local, target, sig)
data   = pld.all_reduce(data, op=pld.ReduceOp.Sum)
data   = pld.reduce_scatter(target)
data   = pld.broadcast(target, root=0)
data   = pld.all_to_all(input, target)
data   = pld.all_to_all_v(input, target, send_counts, recv_counts)
sig    = pld.barrier(sig)

Every wrapper delegates to the exact same HOST builtin — same lowering, same semantics, same goldens. Zero C++/IR/codegen surface.


What this PR offers — and what it deliberately does not

✅ Offers

  1. Auto window+signal for the collectives that still need hand-plumbingall_gather, reduce_scatter, broadcast, all_to_all, all_to_all_v, barrier, and ring all_reduce. These have no compiler-side signal synthesis, so the wrapper is the only ergonomic path; signal shapes are encoded so users cannot get them wrong.
  2. Mesh all_reduce rides the compiler's shared-signal synthesis (plan 88 / feat(distributed): share synthesized allreduce signals per data-buffer lineage #2504, merged 2026-08-28): the wrapper delegates to the implicit form, so it gets one shared, hoisted, loop-safe signal with zero Python-side allocation.
  3. Static typing + early validationpld.all_reduce is Literal["mesh","ring"] + @overload; invalid mode, missing nranks for ring, ring with non-Sum/FP32, and reduce_scatter with non-Sum ops are type errors / context-rich ValueErrors at the call site, not deep in the compiler.
  4. Exports & discoverabilitypld.all_* resolves inside @pl.program host bodies (parser expansion verified).
  5. EN + ZH docs (parity-checked) — API table, a worked publish→collective→consume example, mesh-vs-ring guidance, honest constraints.

❌ Deliberately NOT (kept out of scope)

  • No C++/IR/codegen changes — the wrappers are a DSL layer over existing builtins.
  • No compiler-side signal synthesis for the sibling collectives — that is the plan-88-style generalization, tracked as future work; until then the wrapper's Python-side allocation is the ergonomic path.
  • No mode="auto" — mesh vs ring stays explicit until plan 42 (auto-select) lands.
  • No data-window hiding — the data-side choreography (window + publish/dispatch) stays explicit; hiding it is plan 82 I5 (window-less host collective), a separate design.

The 7 wrappers (python/pypto/language/distributed/op/collective_api.py)

Wrapper Signal handling
pld.all_reduce(target, *, op, mode="mesh"|"ring", nranks) mesh: none — compiler-synthesized shared signal (#2504), loop-safe; ring: auto [2*(NR-1)+1, NR] (requires static nranks)
pld.all_gather(local, target) auto [world_size(), 1]
pld.reduce_scatter(target, *, op) auto [world_size()] (rank-1, per builtin requirement)
pld.broadcast(target, *, root) auto [world_size()] (rank-1)
pld.all_to_all(input, target) auto [world_size(), 1]
pld.all_to_all_v(input, target, send_counts, recv_counts) auto [world_size(), 1]
pld.barrier(signal) explicit, comm-domain-covered signal (see Constraints)

Each call allocates a fresh __auto_<op>_<n> INT32 window — no stale/reused-buffer bugs, no collisions. The self-clearing protocol (#2175/#2279) makes these reusable across calls and loop iterations; fresh-per-call is the safe default (a shared/pooled default is a tracked follow-up — plan 82 I6).


Constraints / limitations (documented, not hidden)


Testing (re-verified on the rebased main)

  • UT tests/ut/language/test_collective_api.py: 18 passed + 1 xfail — signal shape/name generation, fresh-per-call uniqueness, kwarg passthrough, parser resolution, all validation guards, printer-gap xfail.
  • ST tests/st/distributed/test_l3_ergonomic_api.py: 5/5 passed on a2a3sim — mesh AR, ring AR, broadcast, all_gather, barrier (cross-rank goldens).
  • Sibling regression test_l3_host_tensor_allreduce.py: 9 passed / 3 skipped / 4 pre-existing sim baselines (max, fp16[8193], fp16 Max/Min — Max/Min are NPU-only gates), identical to clean main.
  • pre-commit all hooks clean (incl. pyright, ruff, markdownlint, EN/ZH parity); clang-tidy N/A (Python-only).

Design decisions

  1. Pure Python — zero C++/IR/codegen surface; composes with existing host builtins.
  2. No auto-mode — user picks mesh vs ring explicitly; mode="auto" is plan 42.
  3. HOST-orchestration only — the wrappers hide the signal; data-window + publish/dispatch stay explicit (documented).
  4. Fresh-per-call signals — safe baseline; fix(ir): make composite collective barrier signals reusable #2175/feat(distributed): self-clearing barrier signals in host collective kernels #2279/feat(distributed): share synthesized allreduce signals per data-buffer lineage #2504 make pooling possible later (plan 82 I6).

Follow-ups (tracked, non-blocking)

  • Printer round-trip fix for signal-bearing IR (python_printer hoisting, own PR).
  • Window-less host collectivepld.all_reduce(plain_tensor) (plan 82 I5).
  • Compiler-side signal synthesis for sibling collectives — the plan-88 generalization; wrappers then delegate op-by-op.
  • Future workmode="auto" (plan 42), async collectives, group=, FP16/FP8 dtypes.

How to review / verify

  1. collective_api.py + tests/ut/language/test_collective_api.py (signals, validation, parser resolution).
  2. tests/st/distributed/test_l3_ergonomic_api.py (end-to-end goldens).
  3. Sim gate (UT + ST on a2a3sim) — green above.
  4. Developer gate (not yet run): NPU ST P=2 / P=4, then merge.

@coderabbitai

coderabbitai Bot commented Aug 4, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

This PR adds HOST ergonomic collective wrappers with automatic signal allocation, public exports, documentation, unit tests, and distributed end-to-end tests for all-reduce, broadcast, all-gather, and barrier.

Changes

Collective API

Layer / File(s) Summary
Collective wrapper implementation
python/pypto/language/distributed/op/collective_api.py
Adds wrappers for collective operations. The wrappers allocate fresh INT32 signals where required and delegate to HOST tensor collectives.
Public namespace exports
python/pypto/language/distributed/__init__.py, python/pypto/language/distributed/op/__init__.py, python/pypto/language/distributed/op/unified_ops.py
Re-exports the new collective operations through distributed namespaces.
Wrapper and parser validation
tests/ut/language/test_collective_api.py
Tests signal shapes, allocation uniqueness, modes, validation errors, delegation, and parser behavior.
End-to-end distributed execution
tests/st/distributed/test_l3_ergonomic_api.py
Tests mesh and ring all-reduce, broadcast, all-gather, and barrier programs across available devices.
Collective API documentation
docs/en/dev/distributed_ops.md, docs/zh/dev/distributed_ops.md
Documents wrapper constraints, signal rules, examples, and mesh versus ring all-reduce behavior.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant HostOrchestration
  participant CollectiveAPI as collective_api.all_reduce
  participant SignalWindow
  participant TensorCollective as HOST tensor allreduce
  HostOrchestration->>CollectiveAPI: invoke all_reduce(target, mode)
  CollectiveAPI->>SignalWindow: allocate fresh INT32 signal
  CollectiveAPI->>TensorCollective: delegate target and parameters
  TensorCollective-->>HostOrchestration: return distributed target
Loading

Possibly related issues

Possibly related PRs

Poem

A rabbit hops through signals bright,
Fresh buffers bloom for each invite.
Mesh and ring now share the load,
HOST collectives guide the road.
Gather, scatter, barrier too—
Binky cheers the API crew!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 11.11% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description check ✅ Passed The description clearly explains the ergonomic collective wrappers, validation, exports, documentation, testing, and known limitations. It is directly related to the changeset.
Title check ✅ Passed The title accurately identifies the main change: ergonomic distributed pld.* collective wrappers with automatic window and signal handling, typing, validation, and documentation. It is somewhat long…
Full details: Title check

Explanation

The title accurately identifies the main change: ergonomic distributed pld.* collective wrappers with automatic window and signal handling, typing, validation, and documentation. It is somewhat long but remains clear and specific.

  • Fix all pre-merge checks with AI

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@georgebisbas
georgebisbas marked this pull request as ready for review August 4, 2026 07:27

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a9c2c42947

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Returns:
The ``target`` :class:`pld.DistributedTensor` (window-as-result).
"""
signal = _fresh_signal("all_to_all_v", [world_size(), 1])

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Require static NR for all_to_all_v signals

For any call to the new pld.all_to_all_v(...) wrapper, this line builds the hidden signal as [pld.world_size(), 1], but the underlying pld.tensor.all_to_all_v type deducer requires the signal's first dimension to be a compile-time ConstInt so it can derive MAX_RECV = target.shape[0] // NR. That means the advertised short form raises during IR construction before it can reach the documented host rejection path; either require a static nranks here (like ring all-reduce) or avoid exposing this wrapper until a dynamic/world-size signal is supported.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in aec3b80: pld.all_to_all_v now requires a positive static nranks (mirroring ring allreduce) and builds the signal as [nranks, 1]; a dynamic world_size() or non-positive value raises a context-rich ValueError at the wrapper call. Added delegation + guard unit tests. Thanks — this was a real construction-time failure.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
docs/en/dev/distributed_ops.md (1)

182-186: 📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

EN and ZH docs list different ops for the credit-barrier protocol. The English doc names all_to_all_v as one of the collectives synchronized by the self-clearing credit barrier; the Chinese doc's equivalent sentence omits it. Align both lists to name the same set of ops.

  • docs/en/dev/distributed_ops.md#L182-L186: authoritative list; keep all_to_all_v here and confirm it is intentional.
  • docs/zh/dev/distributed_ops.md#L164-L165: add all_to_all_v to match the English list.

As per coding guidelines, "English documentation in docs/en/dev/ is authoritative and corresponding Chinese documentation in docs/zh/dev/ must remain aligned."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/en/dev/distributed_ops.md` around lines 182 - 186, Keep all_to_all_v in
the authoritative collective list in docs/en/dev/distributed_ops.md at lines
182-186, confirming it remains intentional; update the corresponding list in
docs/zh/dev/distributed_ops.md at lines 164-165 to add all_to_all_v so both
documentation sets name the same credit-barrier operations.

Source: Coding guidelines

🧹 Nitpick comments (2)
tests/ut/language/test_collective_api.py (1)

125-142: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add direct all_to_all_v coverage.

This test module does not call pld.all_to_all_v. Add a delegation test that checks the argument order input, target, signal, send_counts, recv_counts, plus the generated INT32 [world_size(), 1] signal.

Add this routine contract test in this module. As per coding guidelines, use unit tests in tests/ut/ for routine testing.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/ut/language/test_collective_api.py` around lines 125 - 142, Add a unit
test in this module that calls pld.all_to_all_v and verifies delegation to the
expected IR operation, argument order input, target, signal, send_counts,
recv_counts, and the generated signal’s INT32 [world_size(), 1] shape. Follow
the existing collective API test patterns and keep the coverage focused on this
routine contract.

Source: Coding guidelines

tests/st/distributed/test_l3_ergonomic_api.py (1)

240-244: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Validate all all-gather rows.

consume_step loads only row 0. The expected value at Line 376 checks only rank 0's chunk on each rank. An implementation that broadcasts rank 0 or leaves later rows invalid passes this test. Copy the complete [NR, SIZE] target into each rank output and compare all rank-indexed input chunks.

Proposed coverage change
     def consume_step(
         self,
         target: pld.DistributedTensor[[NR, SIZE], pl.FP32],
-        out: pl.Out[pl.Tensor[[1, SIZE], pl.FP32]],
-    ) -> pl.Tensor[[1, SIZE], pl.FP32]:
-        return pl.store(pl.load(target, [0, 0], [1, SIZE]), [0, 0], out)
+        out: pl.Out[pl.Tensor[[NR, SIZE], pl.FP32]],
+    ) -> pl.Tensor[[NR, SIZE], pl.FP32]:
+        return pl.store(pl.load(target, [0, 0], [NR, SIZE]), [0, 0], out)
@@
     def consume_orch(
         self,
         target: pld.DistributedTensor[[NR, SIZE], pl.FP32],
-        out: pl.Out[pl.Tensor[[1, SIZE], pl.FP32]],
-    ) -> pl.Tensor[[1, SIZE], pl.FP32]:
+        out: pl.Out[pl.Tensor[[NR, SIZE], pl.FP32]],
+    ) -> pl.Tensor[[NR, SIZE], pl.FP32]:
@@
-        outputs: pl.Out[pl.Tensor[[NR, 1, SIZE], pl.FP32]],
-    ) -> pl.Tensor[[NR, 1, SIZE], pl.FP32]:
+        outputs: pl.Out[pl.Tensor[[NR, NR, SIZE], pl.FP32]],
+    ) -> pl.Tensor[[NR, NR, SIZE], pl.FP32]:
@@
-        outputs = torch.zeros_like(inputs)
+        outputs = torch.zeros((NR, NR, SIZE), dtype=inputs.dtype, device=inputs.device)
@@
-        expected = torch.stack([inputs[0]] * NR)
+        expected = torch.stack([inputs[:, 0, :]] * NR)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/st/distributed/test_l3_ergonomic_api.py` around lines 240 - 244, Update
consume_step to load and store the complete [NR, SIZE] gathered target into out
rather than only row 0. Extend the assertions around the existing expected-value
check to validate every rank-indexed input chunk, ensuring later all-gather rows
are compared on each rank.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@python/pypto/language/distributed/op/collective_api.py`:
- Around line 12-15: Update the module documentation describing signal
allocation to explicitly state that all_reduce with mode="mesh" uses a
compiler-synthesized signal and barrier requires a caller-provided signal, while
preserving the existing fresh-signal behavior for other wrappers.
- Around line 67-69: Update the printer/serialization path for
_fresh_signal-generated buffers so alloc_window_buffer() is emitted as a named
assignment before the window() call, preserving a parser-visible binding that
parse_program() can consume. Ensure signal-bearing wrappers round-trip through
as_python() and make the strict collective API xfail pass.
- Around line 123-141: Update the nranks validation in the mode == "ring" branch
to require a static integer greater than zero, rejecting zero and negative
values before calculating the signal shape. Preserve the existing bool/type
validation and error handling, and add regression coverage for both non-positive
inputs.

---

Outside diff comments:
In `@docs/en/dev/distributed_ops.md`:
- Around line 182-186: Keep all_to_all_v in the authoritative collective list in
docs/en/dev/distributed_ops.md at lines 182-186, confirming it remains
intentional; update the corresponding list in docs/zh/dev/distributed_ops.md at
lines 164-165 to add all_to_all_v so both documentation sets name the same
credit-barrier operations.

---

Nitpick comments:
In `@tests/st/distributed/test_l3_ergonomic_api.py`:
- Around line 240-244: Update consume_step to load and store the complete [NR,
SIZE] gathered target into out rather than only row 0. Extend the assertions
around the existing expected-value check to validate every rank-indexed input
chunk, ensuring later all-gather rows are compared on each rank.

In `@tests/ut/language/test_collective_api.py`:
- Around line 125-142: Add a unit test in this module that calls
pld.all_to_all_v and verifies delegation to the expected IR operation, argument
order input, target, signal, send_counts, recv_counts, and the generated
signal’s INT32 [world_size(), 1] shape. Follow the existing collective API test
patterns and keep the coverage focused on this routine contract.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: a1458aa0-907e-4e89-95a1-21cb9bd8eb1a

📥 Commits

Reviewing files that changed from the base of the PR and between a47d300 and a9c2c42.

📒 Files selected for processing (8)
  • docs/en/dev/distributed_ops.md
  • docs/zh/dev/distributed_ops.md
  • python/pypto/language/distributed/__init__.py
  • python/pypto/language/distributed/op/__init__.py
  • python/pypto/language/distributed/op/collective_api.py
  • python/pypto/language/distributed/op/unified_ops.py
  • tests/st/distributed/test_l3_ergonomic_api.py
  • tests/ut/language/test_collective_api.py

Comment thread python/pypto/language/distributed/op/collective_api.py Outdated
Comment on lines +67 to +69
name = f"__auto_{op_name}_{next(_SIGNAL_COUNTER)}"
buf = _tensor.alloc_window_buffer(shape, dtype=DataType.INT32, name=name)
return _tensor.window(buf, shape, dtype=DataType.INT32)

@coderabbitai coderabbitai Bot Aug 4, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift

Make generated signal allocations round-trip.

_fresh_signal() embeds alloc_window_buffer() directly in window(). The printer emits that allocation inline, but parse_program() requires a named simple assignment. The strict xfail in tests/ut/language/test_collective_api.py, Lines 282-297, proves that signal-bearing wrappers cannot round-trip through as_python().

Hoist generated allocations into named statements in the printer or preserve an equivalent parser-visible binding. Make the strict xfail pass before exporting this API.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@python/pypto/language/distributed/op/collective_api.py` around lines 67 - 69,
Update the printer/serialization path for _fresh_signal-generated buffers so
alloc_window_buffer() is emitted as a named assignment before the window() call,
preserving a parser-visible binding that parse_program() can consume. Ensure
signal-bearing wrappers round-trip through as_python() and make the strict
collective API xfail pass.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed this is a real gap. It is the python_printer not hoisting generated alloc_window_buffer into a named assignment (and dropping name=), which parse_program requires. Tracked as a strict-xfail UT (proves the gap) + KNOWN_ISSUES, and scoped as a separate printer fix rather than expanding this Python-only PR into a C++ printer change — it does not affect compile/run. I will open a follow-up for the printer hoist.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@georgebisbas, acknowledged. The finding remains valid, but the printer fix is reasonably out of scope for this PR.

The strict expected-failure test and KNOWN_ISSUES document the current limitation. Please link the follow-up issue here when available. If you want, I can create the GitHub issue and assign it to you.

🐇 ✅


✏️ Learnings added
Learnt from: georgebisbas
Repo: hw-native-sys/pypto PR: 2275
File: python/pypto/language/distributed/op/collective_api.py:74-76
Timestamp: 2026-08-04T08:08:02.027Z
Learning: In `python/pypto/language/distributed/op/collective_api.py`, generated signal buffers from `_fresh_signal()` compile and run correctly, but `as_python()` does not round-trip them through `parse_program()`. The C++ `python_printer` emits `alloc_window_buffer()` inline and drops its `name=` argument, while `parse_program()` requires the allocation in a named simple assignment. The repository tracks this limitation with a strict expected-failure unit test and `KNOWN_ISSUES`; the printer hoist fix is intentionally scoped to a separate follow-up.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

You are interacting with an AI system.

Comment thread python/pypto/language/distributed/op/collective_api.py
@georgebisbas

Copy link
Copy Markdown
Contributor Author

Addressed the AI review feedback in aec3b805.

Codex (P2): all_to_all_v now requires a positive static nranks (signal [nranks, 1]); a dynamic world_size() signal was rejected at IR construction — fixed + delegation/guard unit tests.

CodeRabbit:

  • (Major, docs parity) added all_to_all_v to the ZH credit-barrier collective list (matches EN).
  • (Minor) ring all_reduce nranks <= 0 — now rejected via a shared _is_static_positive_int TypeGuard + regression test.
  • (Trivial) module docstring — states the mesh (compiler-synthesized) and barrier (caller-provided) signal exceptions.
  • (Trivial) missing all_to_all_v UT — added delegation + non-positive-nranks tests.
  • (Trivial) all_gather ST validated only row 0 — now copies/validates the full [NR, SIZE] gathered target.

CodeRabbit (Major, printer round-trip): real gap — python_printer doesn't hoist generated alloc_window_buffer into a named assignment (and drops name=), which parse_program requires. Tracked as a strict-xfail UT + KNOWN_ISSUES and scoped as a separate printer fix (not in this Python-only PR; does not affect compile/run). Follow-up to be opened.

Verified: UT 18 passed + 1 xfail, ST 5 passed on a2a3sim, pre-commit clean (incl. pyright).

@georgebisbas
georgebisbas force-pushed the feat/ergonomic-collective-api branch from aec3b80 to 7ec7dfc Compare August 4, 2026 08:18
@georgebisbas
georgebisbas force-pushed the feat/ergonomic-collective-api branch 2 times, most recently from c2463d2 to 11c1a64 Compare August 5, 2026 21:03
@georgebisbas

Copy link
Copy Markdown
Contributor Author

Heads-up for after #2279 merges: the "Fresh per call" bullet added here in docs/{en,zh}/dev/distributed_ops.md needs a citation fix.

Currently it says:

Fresh per call. Signals self-clear under the credit-barrier protocol (pypto #2175, merged), so they are safe to reuse across back-to-back calls...

#2175 only shipped self-clearing for the InCore composite rail (lower_composite_ops_pass.cpp). The HOST builtins these wrappers actually delegate to are not self-clearing yet — that's precisely what #2279 fixes. This also contradicts the very next bullet in the same section ("Loops (HOST rail)"), which correctly notes the HOST rail isn't self-clearing under #2175.

Once #2279 merges, the "Fresh per call" claim becomes true — but the citation should point to #2279 (or credit both), and the two bullets should be reconciled so they don't contradict each other.

No functional change needed: the wrappers always allocate a fresh signal per call regardless, so this is docs-only. Worth a small follow-up commit here after rebasing onto post-#2279 main (should apply cleanly — the two PRs touch non-overlapping line ranges in this file).

Convenience wrappers over the host collective builtins that auto-manage
signal windows, replacing the manual alloc_window_buffer + window +
signal boilerplate with a single call.

- all_reduce(target, op=Sum, mode="mesh"|"ring", nranks): mesh uses a
  compiler-synthesized signal (no window); ring validates positive static
  nranks and rejects non-Sum ops / non-FP32 inputs, allocating a fresh
  INT32 signal window.
- all_gather / reduce_scatter / broadcast / all_to_all / all_to_all_v:
  allocate a fresh INT32 signal window sized from world_size()/nranks;
  all_to_all_v requires a positive static nranks (signal [nranks, 1]).
- barrier(signal): caller-provided, comm-domain-covered signal.
- Each wrapper emits an __auto_<op>_<n> named window; self-clearing
  credit-barrier signals (merged hw-native-sys#2175) make repeated calls loop-safe.
- Literal/overload typing on all_reduce; context-rich ValueError guards
  (mesh nranks, ring nranks<=0, non-static all_to_all_v nranks).

Tests: tests/ut/language/test_collective_api.py; ST
tests/st/distributed/test_l3_ergonomic_api.py (a2a3sim). Docs: EN/ZH
docs/en|zh/dev/distributed_ops.md "Ergonomic collective API".
@georgebisbas
georgebisbas force-pushed the feat/ergonomic-collective-api branch from 11c1a64 to 50b1841 Compare August 28, 2026 14:08
@georgebisbas georgebisbas changed the title [RFC] feat(distributed): ergonomic pld.* collective wrappers (auto-managed signals) [RFC] feat(distributed): ergonomic pld.* collective wrappers — auto window+signal; typing, validation, docs Aug 28, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

1 participant