MaterializeDistTensorCtx Pass¶
Materializes one explicit CommCtxType parameter and argument for each
DistributedTensorType function parameter.
Overview¶
Distributed tensors need a communication context at every dispatch boundary:
host orchestration passes a per-rank device_ctx, L2 orchestration forwards it
through task args, and L1 PTO codegen uses it to lower pld.system.rank,
pld.system.nranks, notify, wait, put, and remote memory ops.
Older codegen paths synthesized those ctx values independently at several sites. This pass makes the ctx flow explicit in IR instead:
- For every function with
DistributedTensorTypeparameters, append matchingCommCtxTypeparameters at the tail of the signature, in distributed-tensor parameter order. The appended parameters areParamDirection::In. - For every
Call/Submitto such a function, append matching ctx args. If the distributed tensor arg is a caller parameter or an SSA alias of one, forward the caller's materialized ctx parameter. Return positions are matched to the callee's returned parameters, so mixed or reordered return tuples do not fall back to positional tail alignment. This holds forSubmittoo: its result positions are the callee's return positions (the trailingScalar[TASK_ID]has no ctx). Builtin ops that bind a fresh SSA var to a DistributedTensor that already exists forward that value's ctx — both output-side writebacks, which the op declares itself viaset_output_reuses_input(idx)(tile.store->args[2],tensor.assemble->args[0]), and zero-copy buffer-aliasing views (tensor.view,tile.slice,tensor.reshape, ...), whose result type propagatesDistributedTensorType::window_buffer_fromargs[0]. Tensor aliases carried throughForStmt/WhileStmtare tracked as well. In host orchestration only, if the lineage cannot be resolved, bindpld.system.get_comm_ctx(dist)immediately before the call and pass that result. Chip orchestration and device functions must resolve an explicit context; an unresolved argument is diagnosed instead of synthesizing a device-side query. - In chip orchestration and device functions, replace every
pld.system.get_comm_ctx(dist)with the resolved explicitCommCtxTypeSSA value. Host orchestration keeps the op because host codegen resolves it from the window's per-rank runtime context. - If call-site
arg_directionsare already resolved, append matchingArgDirection::Scalarentries so downstream codegen can keep treating ctx as ordinary scalar task payload.
This pass does not add CommCtxType values to IfStmt return variables or
branch yields. DistributedTensor if lowering keeps the existing requirement
that both branches refer to the same backing/context; dynamic context merges
remain outside this change (issue #2027).
A loop carry is subject to the same one-context rule. The carry is seeded from
its init value before the body is walked, so a self-carry
(data = self.comm(data)) resolves; the value yielded back into the carry is
then checked against that seed, and rebinding the carry to a different
DistributedTensor inside the loop is diagnosed rather than silently taking the
init value's context. A yield whose lineage this pass cannot trace at all leaves
the seed in place.
The pass produces IRProperty::DistTensorCtxMaterialized: no
pld.system.get_comm_ctx survives outside host orchestration. The pass enforces
this for every function it rewrites, and the property verifier checks it
independently — which also covers Programs the pass returns untouched because no
function declares a DistributedTensorType parameter. The property is listed in
GetVerifiedProperties(), so the pipeline checks it on the default verification
level rather than only when a test installs a VerificationInstrument.
It requires IRProperty::ReturnParamsExplicit: the return-position map comes
from return_lineage::ExplicitReturnedParamIndices, a pointer-identity read of
the ReturnStmt that is only meaningful once NormalizeReturnOrder has
canonicalized it.
The pass runs after LowerHostTensorCollectives and before the final
Simplify. At that point host window buffers have already been materialized by
MaterializeCommDomainScopes, host tensor collectives have been lowered, and
there is still time for the final simplify pass to clean up any forwarding
aliases.
Why CommCtx Is Different From Dynamic Dims¶
Dynamic tensor dimensions can be recovered locally from tensor descriptors at the wrapper boundary. A communication context cannot: it is real dataflow across host -> orchestration -> task payload -> kernel signature. Keeping it in IR prevents codegen sites from drifting out of sync.
API¶
| C++ | Python | Level |
|---|---|---|
pass::MaterializeDistTensorCtx() |
passes.materialize_dist_tensor_ctx() |
Program-level |
Example¶
Before:
def chip_orch(self, data: pld.DistributedTensor[[256], pl.FP32]):
return self.kernel(data)
def host_orch(self):
data = pld.window(buf, [256], dtype=pl.FP32)
self.chip_orch(data, device=r)
After:
def chip_orch(self, data, data_ctx: pld.CommCtx):
return self.kernel(data, data_ctx)
def host_orch(self):
data = pld.window(buf, [256], dtype=pl.FP32)
data_ctx = pld.system.get_comm_ctx(data)
self.chip_orch(data, data_ctx, device=r)
The kernel body does not need to change. Existing
pld.system.get_comm_ctx(data) uses in a device function are rewritten to the
explicit ctx parameter by this pass; host-orchestration uses remain runtime
queries.