quadrants.lang.ast.ast_transformers.checkpoint_transformer#
AST recognition, validation, and auto-wrap lowering for qd.checkpoint(...) with blocks.
Lives alongside call_transformer.py / function_def_transformer.py so that ast_transformer.py doesn’t have to
grow per-feature. ASTTransformer.build_With and ASTTransformer._is_checkpoint_call forward calls into the static
methods here. FunctionDefTransformer.build_FunctionDef calls auto_wrap_for_loops on the kernel body when the
kernel was decorated with @qd.kernel(graph=True, checkpoints=True), so that every top-level for-loop not already
inside a with qd.checkpoint(...) becomes its own implicit no-yield checkpoint.
See docs/source/user_guide/graph.md for the user-facing surface and perso_hugh/doc/qipc/reentrant.md for the
design.
Classes#
Resolved metadata for a qd.checkpoint(...) call recognised in the AST. |
|
Module Contents#
- class quadrants.lang.ast.ast_transformers.checkpoint_transformer.CheckpointCallInfo[source]#
Resolved metadata for a qd.checkpoint(…) call recognised in the AST.
cp_id: the user-supplied label (anintorIntEnumvalue), orNonefor an auto-wrap implicit checkpoint.yield_on: name of the kernel parameter passed asyield_on=(anast.Nameis required), orNonefor an implicit checkpoint.is_implicit:Trueiff this Call was synthesised byauto_wrap_for_loops.
- class quadrants.lang.ast.ast_transformers.checkpoint_transformer.CheckpointTransformer[source]#
- static is_explicit_checkpoint_with(stmt: ast.stmt) bool[source]#
Return True iff stmt is a single-item with qd.checkpoint(…): block (explicit or implicit). Used by
auto_wrap_for_loopsto leave already-wrapped for-loops alone.
- static is_checkpoint_call(node: ast.expr, global_vars: dict) CheckpointCallInfo | None[source]#
If node is a qd.checkpoint(…) call return a CheckpointCallInfo; otherwise return None.
Validates the call shape and raises QuadrantsSyntaxError for misuse so the user gets a clear message at the with site rather than a vague “not stream_parallel” error later. Implicit calls (the synthetic qd.checkpoint() no-arg calls produced by auto_wrap_for_loops) are recognised via the _qd_implicit attribute and bypass user-call argument validation entirely.
- static build_checkpoint_with(ctx: quadrants.lang.ast.ast_transformer_utils.ASTTransformerFuncContext, node: ast.With, info: CheckpointCallInfo, build_stmts) None[source]#
Handles a with qd.checkpoint(…): block (explicit or auto-wrapped implicit).
Validates the use-site (kernel must be graph=True, checkpoints=True, no nesting; for explicit calls, the yield_on arg must be a kernel parameter and the cp_id must be unique across the kernel) and appends an entry to kernel.checkpoint_yield_on_args + kernel.checkpoint_user_labels_by_cp_id. Walks the body transparently – for-loops inside the with become normal top-level for-loops in the kernel’s frontend IR. The internal cp_id is assigned by declaration order (the C++ ASTBuilder.begin_checkpoint() counter, mirrored as the list index in checkpoint_yield_on_args).
- static auto_wrap_for_loops(stmts: list[ast.stmt]) list[ast.stmt][source]#
Auto-wrap pass for @qd.kernel(graph=True, checkpoints=True) kernels.
Walks stmts and returns a new list where every ast.For not already inside a with qd.checkpoint(…) block is wrapped in a synthetic implicit checkpoint. Recurses into while qd.graph_do_while(…) bodies so for-loops nested in the WHILE body get the same treatment. Other compound statements (ast.If, ast.With, non-graph_do_while ast.While, ast.Try) are passed through unchanged – they’re not the common pattern in Quadrants kernel bodies and recursing into them risks wrapping nested for-loops that the user intended to be sub-tasks of a larger control-flow block. Bare top-level statements (assignments, expressions, coverage probes) are also passed through unchanged so they remain in the kernel prologue with cp_id=-1 and run on every launch.