Repository navigation
Conversation
`FieldConstructor` now unwraps `__gt_allocator__` factories before choosing between the array-API path and the custom-layout path, so a factory whose allocator is an array namespace (e.g. NumPy) allocates like that namespace instead of being pushed into the `TensorBuffer` path. - `FieldBufferAllocatorFactoryProtocol.__gt_allocator__` may return an array namespace as well as a field buffer allocator. - `is_field_allocator_factory_for(obj, device)` is true only for factories providing a field buffer allocator for that device type (it raised `AttributeError` for an array namespace). Prepares embedded backends (ADR 0030), whose allocator is an array namespace.
- `Backend.__gt_allocator__` moves to the base class and returns the backend's allocator, unwrapping an allocator factory; `CompiledBackend` keeps its narrower override. - `EmbeddedBackend(Backend)`, a sibling of `CompiledBackend`, runs the Python definition directly on fields; its allocator is an array namespace (validated, NumPy by default). - New module `program_processors.runners.embedded` with `embedded_numpy` (also exported as `gtx.embedded_numpy`) and the lazily created `embedded_cupy` / `embedded_jax`, which raise `AttributeError` naming the missing optional package. - `Backend.__deepcopy__` returns the backend itself (immutable configuration; the NumPy module it holds cannot be copied), and `Program.__gt_allocator__` is a plain property, so a program used as `allocator=` does not cache a module and stays deep-copyable. Copies share the backend. Programs do not dispatch to `EmbeddedBackend` yet; that is the next step.
The dispatch helper treats an `EmbeddedBackend` like `None` (embedded execution); `None` keeps working until it becomes an error. - `Program.__gt_allocator__` returns the backend's allocator for every backend kind, so `gtx.zeros(..., allocator=program)` allocates with the array namespace of an embedded program. - Embedded calls report metrics under `prog<backend.name>` (e.g. `prog<embedded_numpy>`); `None` still reports `prog<'embedded'>`. - `.compile()` on a program or operator with an embedded backend says that embedded programs are not compiled.
- `EmbeddedDummyBackend` and `numpy_execution` / `cupy_execution` /
`jax_numpy_execution` are deleted; the `EmbeddedIds` parameters load
`runners.embedded.embedded_{numpy,cupy,jax}`.
- `cartesian_case` / `unstructured_case` always use the backend of
`exec_alloc_descriptor`; `Case.backend` is a `Backend`, never `None`, and
`Case.is_embedded` replaces the `backend is None` checks. The
`*_no_backend` cases use `cases_utils.no_backend`.
- Tests that mapped the dummy to `None` pass the embedded backend directly.
…nd=None - `decorator.DEFAULT_BACKEND` is `gtx.embedded_numpy`: programs and operators decorated without `backend=` still run embedded on NumPy. - `backend=None` raises `TypeError` when a program or operator is created (decorators, `from_function`, `with_backend`, `dataclasses.replace`), and the message names the replacement. No deprecation aliases. - The dispatch helper accepts `CompiledBackend` and `EmbeddedBackend` only; `backend` is typed `Backend` (no `None`) everywhere in the decorators. - Embedded metrics keys always use the backend name. - `iterator.runtime`: `fendef(..., backend=None)` keeps meaning iterator-level embedded execution; an `EmbeddedBackend` is rejected with a message pointing to it. Tests: `backend=None` is rejected everywhere it can be passed, the default is `embedded_numpy`, `with_backend(None)` is a mypy error, and the remaining `None`-as-embedded uses are gone.
- New ADR 0030, listed under "Embedded Execution" in the ADR index; the plain-text "ADR 0030" mentions in ADR 0029 become links. - Workshop exercises and slides use `gtx.embedded_numpy` instead of `backend = None`. - `src/gt4py/next/AGENTS.md`: embedded execution is an `EmbeddedBackend`.
The dace sessions run with `--require-optional-deps` but do not install the `jax` extra. Their selection includes the embedded JAX parameter of the backend matrix (dace tests skip non-dace backends in the test body), and that parameter now loads the real `embedded_jax` backend, which needs `jax`. Exclude the marker, as the noxfile prescribes for unmet `requires_*` markers.
egparedes
added a commit
that referenced
this pull request
Oct 29, 2026
Bring the reworked stack (#2741 backend structure, #2956 embedded backends, #2742 observability on the new design) under the pipeline PR and adapt it: - `CompiledBackend.compiler` / `.loader` and `Toolchain.frontend` are typed as `workflow.Step`; `Toolchain.translate` and `is_dace_backend` narrow to `CompilePipeline`; the dace SDFG conversion replaces the translation step inside `CompiledBackend.compiler`. - The allocator-vs-compiler device-agreement check moves from `Toolchain.__post_init__` to `CompiledBackend.__post_init__` (after the abstract-base check); its tests and the pre-built-backend checks use `backend.compiler`. - `roundtrip.gtir` keeps the default frontend (no private `Transforms`); the `Transforms.foast_to_itir` comment no longer names `roundtrip`. - ADR 0029 edits of this PR (CachedStep without `.replace`/`.chain`, static-checking scope, "Cross-step agreement is checked on construction", phasing) are carried over into the rewritten, renamed ADR; the old file stays deleted. HackTheToolchain.md / WorkflowPatterns.md / AGENTS.md use the backend vocabulary.
This was referenced Oct 29, 2026
Draft
…d-backends # Conflicts: # docs/development/ADRs/next/0029-Backend-Structure-and-Pipeline-Simplification.md
…d-backends # Conflicts: # src/gt4py/next/AGENTS.md # src/gt4py/next/backend.py
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Stack: #2741 → #2956 → #2742 → #2743. Based on #2741's branch, so the diff shows only this PR.
Implements ADR 0030 (added here). Embedded execution used to be
backend=None, with no allocator and no name, so every consumer special-cased it. It is now anEmbeddedBackend(Backend), a sibling ofCompiledBackend, and the NumPy instancegtx.embedded_numpyis the default backend.What changes
EmbeddedBackendruns the Python definition directly on fields. Itsallocatoris a validated array namespace (NumPy by default). Execution is the same for every instance; the allocator only decides where gt4py allocates buffers.runners.embedded:embedded_numpy(alsogtx.embedded_numpy), andembedded_cupy/embedded_jax, created on first access (anAttributeErrornames the missing package). Instances, not subclasses; a subclass with its own execution (e.g.jax.jit) is future work.backend=Noneis aTypeErrorat creation, naming the replacement. This covers the decorators,from_function,with_backendanddataclasses.replace. No deprecation period. The iterator-levelfendef(..., backend=None)keeps its meaning.CompiledBackendcompiles,EmbeddedBackendruns embedded, otherBackends raise..compile()on an embedded program raises aRuntimeErrorsaying embedded programs are not compiled.allocator=programworks for embedded programs.Backend.__gt_allocator__moves to the base class; allocator factories may yield an array namespace, andFieldConstructorunwraps factories before choosing the array-API or custom-layout path.prog<embedded_numpy>instead ofprog<'embedded'>.Backend.__deepcopy__returns the backend itself andProgram.__gt_allocator__is no longer cached, so default programs stay deep-copyable (the NumPy module cannot be copied). Copies share their backend, including a DaCe external workspace.EmbeddedDummyBackendis gone). CI: the dace nox sessions deselectrequires_jax, because they don't install JAX and the embedded-JAX test parameter now loads the real backend.Breaking
backend=None,.with_backend(None)in ffrontTypeError: omitbackendor passgtx.embedded_numpyDEFAULT_BACKEND is NoneDEFAULT_BACKEND is gtx.embedded_numpybackend is Noneto detect embeddedisinstance(backend, EmbeddedBackend)backend.allocator.device_typeon anyBackendCompiledBackend; an embedded allocator is an array namespace__gt_allocator__is always a field-buffer allocatorprog<'embedded'>prog<embedded_numpy>icon4py (from a code search; to re-check against its
main): dropbackend=Noneinmetric_fields.py; replace.with_backend(None)andBACKENDS["embedded"] = None; branch onisinstance(backend, EmbeddedBackend)before readingallocator.device_typeinis_cpu_backend/is_gpu_backend; replacebackend is Nonechecks and the"embedded" if backend is None else backend.namepattern (the default's name is"embedded_numpy").ADR number
This PR adds ADR 0030 (#2741 adds 0029). The draft connectivities-as-types stack (#2899, ...) claims the same numbers; whichever lands second renumbers.
Testing
Full suites run in CI. Locally: the
internalanddaceCPU nox sessions,pre-commit -a, typing exports and examples, before the latest merge from #2741, which was checked with targeted tests.