跳转至

pl.system

同步、cache 与跨核原语。它们是产生副作用的语句而非产值算子 —— 多数没有返回值。

System operations for PyPTO Language DSL.

Sync/barrier ops are straight pass-through (no Tensor/Tile args). tpush ops wrap the IR-level functions, unwrapping Tile to Expr. tpop ops accept optional shape/dtype kwargs to create typed results.

AUTO = -1 module-attribute

KernelType

Bases: Enum

Which generated kernel an op belongs to.

A mixed InCore function is expanded into an AIC kernel and an AIV kernel. This says which of the two a cross-core sync op lands in; MIX means both take part, which only a barrier can ask for.

Two neighbouring enums mean different things:

  • FunctionType.AIC / .AIV classify a function, and this classifies an op inside one. A function already declared FunctionType.AIV needs no KernelType on its ops -- there is only one kernel to land in.
  • ir.CoreType labels one physical core in the SoC inventory, which is what Backend::GetCoreCount counts. That is hardware; this is not, and MIX has no CoreType counterpart at all.

Members carry no wire value: each op spells the same kernel differently in its IR attr (system.syncall writes "aic_only" where system.sync_set writes "aic"), so the lowering tables are explicit.

AIC = auto() class-attribute instance-attribute

AIV = auto() class-attribute instance-attribute

MIX = auto() class-attribute instance-attribute

SyncAllMode

Bases: Enum

Barrier implementation selected by system.syncall.

  • HARD: FFTS barrier with no operands; requires full-core occupancy.
  • SOFT: GM-polling barrier; works at partial occupancy.

HARD = 'hard' class-attribute instance-attribute

SOFT = 'soft' class-attribute instance-attribute

sync_src(*, set_pipe, wait_pipe, event_id, span=None)

Send a synchronization signal (Set Flag).

Parameters:

Name Type Description Default
set_pipe PipeType

Pipe that sets the flag

required
wait_pipe PipeType

Pipe that will wait on the flag

required
event_id int

Event identifier

required
span Span | None

Optional source span for debugging (auto-captured if not provided)

None

Returns:

Type Description
Call

Call expression for system.sync_src

sync_dst(*, set_pipe, wait_pipe, event_id, span=None)

Wait for a synchronization signal (Wait Flag).

Parameters:

Name Type Description Default
set_pipe PipeType

Pipe that sets the flag

required
wait_pipe PipeType

Pipe that waits on the flag

required
event_id int

Event identifier

required
span Span | None

Optional source span for debugging (auto-captured if not provided)

None

Returns:

Type Description
Call

Call expression for system.sync_dst

sync_set(event_id, *, pipe, ffts_mode=None, core_type=None, span=None)

Set a Cube/Vector cross-core event using a static or dynamic event id.

Parameters:

Name Type Description Default
event_id IntLike

Event to signal. An int in the user-available range 0-13, or a dynamic pl.Scalar[pl.INDEX]. IDs 14 and 15 are reserved.

required
pipe PipeType

Pipe the event is raised on. The matching sync_wait must name the same pipe -- pairing event ids and pipes is the author's responsibility.

required
ffts_mode int | None

Optional FFTS mode, 0, 1 or 2. Accepted by sync_set only.

None
core_type KernelType | None

pl.KernelType.AIC or pl.KernelType.AIV, to keep the event in the intended kernel when a mixed InCore function is expanded. Omit it to leave the event in both, which is what an explicitly typed kernel wants.

None
span Span | None

Optional source span

None

sync_wait(event_id, *, pipe, core_type=None, span=None)

Wait for a Cube/Vector cross-core event using a static or dynamic event id.

Parameters:

Name Type Description Default
event_id IntLike

Event to wait on -- the one a matching sync_set raises.

required
pipe PipeType

Pipe the event is awaited on; must match the sync_set.

required
core_type KernelType | None

pl.KernelType.AIC or pl.KernelType.AIV, to keep the wait in the intended kernel when a mixed InCore function is expanded. Omit it to leave the wait in both, which is what an explicitly typed kernel wants.

None
span Span | None

Optional source span

None

set_ffts(workspace, *, span=None)

Declare the A3 FFTS setup operand for explicit cross-core synchronization.

bar_v(*, span=None)

Vector unit barrier.

bar_m(*, span=None)

Matrix unit barrier.

bar_all(*, span=None)

Global barrier synchronization.

fence(*, span=None)

Memory barrier over global memory.

Lowers to pto.fence.barrier_all #pto.fence_scope<gm>.

cacheinvalid(tensor=None, shapes=None, offsets=None, *, span=None)

cacheinvalid(*, span: Span | None = None) -> Call
cacheinvalid(tensor: Tensor, shapes: Sequence[int | Scalar], offsets: Sequence[int | Scalar], *, span: Span | None = None) -> Call

Invalidate one addressed cache line, or the whole GM address space.

Two forms selected by arity:

  • No arguments: invalidate the entire GM address space; lowers to pto.cmo.cacheinvalid all #pto.address_space<gm>.
  • (tensor, shapes, offsets): locate a tensor sub-region and invalidate only the cache line containing that view's base address; lowers to pto.partition_view + pto.cmo.cacheinvalid %payload_view single_cache_line : !pto.partition_tensor_view<...> for every region size, a single element included. shapes does not make the operation walk every cache line in the region.

Parameters:

Name Type Description Default
tensor Tensor | None

Target tensor whose view base addresses the cache line; omit for whole-GM.

None
shapes Sequence[int | Scalar] | None

Per-dimension region sizes; length must equal the tensor rank.

None
offsets Sequence[int | Scalar] | None

Per-dimension start offsets; length must equal the tensor rank.

None
span Span | None

Optional source span for debugging (auto-captured if not provided).

None

syncall(*, core_type=KernelType.MIX, mode=SyncAllMode.HARD, gm_workspace=None, used_cores=None, span=None)

Cross-core all-participant barrier (pto::SYNCALL).

Two modes:

  • mode=pl.SyncAllMode.HARD (default): FFTS barrier with no operands. Requires the enclosing pl.spmd launch to fill all physical cores of core_type (a partial launch deadlocks on device — error 507018). The compiler rejects a partial-occupancy hard launch at compile time (HardSyncallOccupancy verifier, issue #1935). See pypto.ir.op.system_ops.syncall.
  • mode=pl.SyncAllMode.SOFT: GM-polling barrier that works at partial occupancy. Each participant updates a shared counter in an exclusive 64-byte GM cache line and polls until all participants arrive. Supported for every participant set.

Both modes synchronize arrival only. They do not wait for preceding data instructions or publish/invalidate business-data cache lines. For a cross-core GM handoff that may span multiple cache lines, conservatively call whole-GM pl.system.cacheinvalid() and pl.system.fence() before the barrier, then call pl.system.cacheinvalid() again on the consumer before it reads. The tensor-region overload covers only the cache line containing the view's base address.

Soft-mode arguments:

Parameters:

Name Type Description Default
core_type KernelType

Participant set, a KernelType member — MIX rendezvouses both kernels, and then used_cores is the total AIC + AIV participant count.

MIX
mode SyncAllMode

A SyncAllMode member.

HARD
gm_workspace Tensor | None

Soft mode only. A shared, zero-initialized GM INT32 tensor with at least 16 elements (64 bytes), visible to every participating block. Pass it as a kernel parameter so all SPMD blocks share one buffer. The buffer must occupy an exclusive cache line and be zero-initialized before its first use.

None
used_cores IntLike | None

Soft mode only. Required participant count as a Python int in the INT32 range or an INT32 scalar. Pass 0 explicitly to ask PTO-ISA to derive the count from the device launch configuration. That opt-in is unsafe when the runtime's logical grid differs from the device launch registers, including the currently pinned Simpler runtime.

None
span Span | None

Optional source span for debugging (auto-captured if not provided).

None

Returns:

Type Description
Call

Call expression for system.syncall.

tpush_to_aiv(tile, *, split, lane_stride=None, id=None, span=None)

Push tile data from AIC to AIV via cross-core pipe.

The Vector side receives it with tpop_from_aic and releases the slot with tfree_to_aic; split and id must match across all three.

Parameters:

Name Type Description Default
tile Tile

Tile to send. Its Cube-side buffer stays live until the consumer frees the slot.

required
split int

pto-isa split code (0=none, 1/2=up-down/left-right, 3/4=the same axes over an odd extent). Selects the axis along which the two AIV lanes divide the tile, and how their extents relate; 0 sends it whole.

required
lane_stride int | None

Partition stride carried when a ragged boundary was balanced across the two AIV lanes; omit for the default box partition.

None
id int | None

Optional frontend pipe id. Omit to use PTOAS default id 0.

None
span Span | None

Optional source span

None

tpush_to_aic(tile, *, split, id=None, span=None)

Push tile data from AIV to AIC via cross-core pipe.

The Cube side receives it with tpop_from_aiv and releases the slot with tfree_to_aiv; split and id must match across all three.

Parameters:

Name Type Description Default
tile Tile

Tile to send. Its Vector-side buffer stays live until the consumer frees the slot.

required
split int

Split mode (0=none, 1=up-down, 2=left-right). Selects the axis along which the two AIV lanes divide the tile; 0 sends it whole.

required
id int | None

Optional frontend pipe id. Omit to use PTOAS default id 0.

None
span Span | None

Optional source span

None

tpop_from_aic(*, shape=None, dtype=None, split=0, lane_stride=None, id=None, span=None)

Pop tile data from AIC cross-core pipe into AIV.

Parameters:

Name Type Description Default
shape list[int] | None

Shape of the tile to receive

None
dtype DataType | None

Data type of the tile to receive

None
split int

pto-isa split code (0=none, 1/2=up-down/left-right, 3/4=the same axes over an odd extent)

0
lane_stride int | None

Partition stride carried when a ragged boundary was balanced across the two AIV lanes; omit for the box partition

None
id int | None

Optional frontend pipe id. Omit to use PTOAS default id 0.

None
span Span | None

Optional source span

None

tpop_from_aiv(*, shape=None, dtype=None, split=0, id=None, span=None)

Pop tile data from AIV cross-core pipe into AIC.

Parameters:

Name Type Description Default
shape list[int] | None

Shape of the tile to receive

None
dtype DataType | None

Data type of the tile to receive

None
split int

Split mode (0=none, 1=up-down, 2=left-right)

0
id int | None

Optional frontend pipe id. Omit to use PTOAS default id 0.

None
span Span | None

Optional source span

None

aic_initialize_pipe(c2v_consumer_buf=0, v2c_consumer_buf=0, *, dir_mask, slot_size, slot_num=None, local_slot_num=None, id=None, span=None)

Initialize cross-core pipe on AIC side.

Parameters:

Name Type Description Default
c2v_consumer_buf PipeBufOperand

C2V consumer buffer base (Expr, int, or DSL Scalar; default 0)

0
v2c_consumer_buf PipeBufOperand

V2C consumer buffer base (Expr, int, or DSL Scalar; default 0)

0
dir_mask int

Direction mask for pipe

required
slot_size int

Size of each pipe slot

required
slot_num int | None

Optional ring-buffer slot count. Omit to let PTOAS pick its default (8 unidirectional, 4 per direction bidirectional).

None
local_slot_num int | None

Optional local slot count (a2/a3 only, must be <= slot_num). On a3 the reserved/imported buffer is sized slot_size * local_slot_num; on a5 it is slot_size * slot_num.

None
id int | None

Optional frontend pipe id. Omit to use PTOAS default id 0.

None
span Span | None

Optional source span

None

aiv_initialize_pipe(c2v_consumer_buf=0, v2c_consumer_buf=0, *, dir_mask, slot_size, slot_num=None, local_slot_num=None, id=None, span=None)

Initialize cross-core pipe on AIV side.

Parameters:

Name Type Description Default
c2v_consumer_buf PipeBufOperand

C2V consumer buffer base (Expr, int, or DSL Scalar; default 0)

0
v2c_consumer_buf PipeBufOperand

V2C consumer buffer base (Expr, int, or DSL Scalar; default 0)

0
dir_mask int

Direction mask for pipe

required
slot_size int

Size of each pipe slot

required
slot_num int | None

Optional ring-buffer slot count. Omit to let PTOAS pick its default (8 unidirectional, 4 per direction bidirectional).

None
local_slot_num int | None

Optional local slot count (a2/a3 only, must be <= slot_num). On a3 the reserved/imported buffer is sized slot_size * local_slot_num; on a5 it is slot_size * slot_num.

None
id int | None

Optional frontend pipe id. Omit to use PTOAS default id 0.

None
span Span | None

Optional source span

None

reserve_buffer(*, name, size, base=AUTO, span=None)

Reserve a named buffer for cross-core communication.

Parameters:

Name Type Description Default
name str

Buffer name for cross-core reference.

required
size int

Buffer size in bytes.

required
base int

Base address in local SRAM. Use AUTO (-1) to let the compiler pick a non-conflicting address, or an explicit integer for manual kernels.

AUTO
span Span | None

Optional source span.

None

Returns:

Type Description
Scalar

pl.Scalar[pl.INT32] wrapping the system.reserve_buffer IR call (PTO ... -> i32).

import_peer_buffer(*, name, peer_func, span=None)

Import a buffer from a peer function in the same group.

Parameters:

Name Type Description Default
name str

Buffer name to import (must match peer's reserve_buffer name).

required
peer_func str

Name of the peer function that owns the buffer.

required
span Span | None

Optional source span.

None

Returns:

Type Description
Scalar

pl.Scalar[pl.INT32] wrapping the system.import_peer_buffer IR call (PTO ... -> i32).

tfree_to_aic(tile, span=None, *, split=None, id=None)

Release ring buffer slot back to AIC producer.

Call this once the tile from tpop_from_aic has been consumed. Until it runs, the slot stays occupied and the producer blocks once the ring fills.

Parameters:

Name Type Description Default
tile Tile

The tile returned by the matching tpop_from_aic.

required
span Span | None

Optional source span

None
split int | None

Leave None. The StampTfreeSplit pass always takes this from the originating tpop, so a value passed here cannot override it.

None
id int | None

Optional frontend pipe id, inherited from the originating tpop when omitted. Supplying one that disagrees with the tpop is rejected.

None

tfree_to_aiv(tile, span=None, *, split=None, id=None)

Release ring buffer slot back to AIV producer.

Call this once the tile from tpop_from_aiv has been consumed. Until it runs, the slot stays occupied and the producer blocks once the ring fills.

Parameters:

Name Type Description Default
tile Tile

The tile returned by the matching tpop_from_aiv.

required
span Span | None

Optional source span

None
split int | None

Leave None. The StampTfreeSplit pass always takes this from the originating tpop, so a value passed here cannot override it.

None
id int | None

Optional frontend pipe id, inherited from the originating tpop when omitted. Supplying one that disagrees with the tpop is rejected.

None

task_invalid(*, span=None)

Sentinel pl.Scalar[pl.TASK_ID] for the "no producer" TaskId.

DSL surface of the IR-level system.task_invalid op. The printer emits pl.system.task_invalid() for auto-scope TaskId placeholders so dumps are valid Python; user code in pl.manual_scope normally writes None and the parser lowers it to this op.

Parameters:

Name Type Description Default
span Span | None

Optional source span.

None

Returns:

Type Description
Scalar

pl.Scalar[pl.TASK_ID] wrapping the system.task_invalid IR call.

task_dummy(*, deps)

Dependency-only dummy TaskId barrier.

This is a parser construct: pl.system.task_dummy(deps=[...]) is intercepted syntactically and lowered to system.task_dummy with manual dep edges. The body exists so the public DSL name resolves for static checkers and imports.

Parameters:

Name Type Description Default
deps Sequence[Scalar | Array | None]

TaskIds the barrier waits on -- each a pl.Scalar[pl.TASK_ID] returned by pl.submit, or a pl.array of them for fan-in. None entries are skipped, so a conditionally-produced TaskId needs no branch at the call site.

required

Returns:

Type Description
Scalar

A pl.Scalar[pl.TASK_ID] that becomes ready once every dep has. Depend on

Scalar

it instead of listing all of deps again at each consumer.

available_cluster_count(*, span=None)

This run's MIX cluster (= AIC) count, as reported by the runtime.

Use it as the core_num of a mixed (AIC+AIV) or cube-only pl.spmd launch instead of a literal: the count belongs to the device the run lands on, so a baked-in literal under- or over-fills the launch on any device with a different usable cluster count. A hard pl.system.syncall needs full occupancy to complete, so this is the only launch width that keeps it deadlock-free across devices.

Codegen lowers it to the orchestration helper rt_available_cluster_count().

Parameters:

Name Type Description Default
span Span | None

Optional source span.

None

Returns:

Type Description
Scalar

pl.Scalar[pl.INT32] wrapping the system.available_cluster_count IR call.

Example

with pl.spmd(pl.system.available_cluster_count(), sync_start=True): ... out = self.mixed_kernel(a, b, out)

Pass the call directly as core_num as shown. Binding it to a name first (n = pl.system.available_cluster_count()) also compiles, but the launch width then reaches the outlined Spmd wrapper as a reference to a variable in the caller, which the IR printer cannot re-parse.

available_aiv_count(*, span=None)

This run's standalone AIV core count, as reported by the runtime.

The AIV counterpart of available_cluster_count — the core_num of a vector-only pl.spmd launch. A mixed launch sizes itself on available_cluster_count (one block per cluster), not on this.

Codegen lowers it to the orchestration helper rt_available_aiv_count().

Parameters:

Name Type Description Default
span Span | None

Optional source span.

None

Returns:

Type Description
Scalar

pl.Scalar[pl.INT32] wrapping the system.available_aiv_count IR call.

Example

with pl.spmd(pl.system.available_aiv_count(), sync_start=True): ... out = self.aiv_kernel(a, b, out)