PTO Project Ecosystem¶
Overview¶
The PTO (Parallel Tensor/Tile Operation) project is a multi-repo toolchain for programming AI accelerators. It spans the full stack from Python-level tensor programs down to hardware instruction execution.
This document describes what each repo does, how they connect, and where the boundaries lie.
Repositories¶
All repositories live under github.com/hw-native-sys.
| Repo | Role | URL |
|---|---|---|
| pypto | Compiler framework | hw-native-sys/pypto |
| pypto-lib | Model zoo & real-world cases | hw-native-sys/pypto-lib |
| PTOAS | PTO assembler & optimizer | hw-native-sys/PTOAS |
| pto-isa | Instruction set architecture | hw-native-sys/pto-isa |
| simpler | Task runtime | hw-native-sys/simpler |
Compilation Pipeline¶
┌─────────────────────────────────────────────┐
│ pypto-lib │
│ Real-world models & primitive tensor funcs │
│ (uses pypto as its compiler framework) │
└──────────────────┬──────────────────────────┘
│ imports & compiles via
┌──────────────────▼──────────────────────────┐
│ pypto │
│ Python DSL → IR → Passes → CodeGen │
│ │
│ Produces: │
│ • .pto files (InCore kernel → AICore) │
│ • Orchestration C++ (scheduling → AICPU) │
└───┬─────────────────────────────────────┬───┘
.pto files │ │ orchestration C++
(InCore only) │ │ (runs on AICPU)
┌───▼────────────────────┐ │
│ PTOAS │ │
│ Assembler & Optimizer │ │
│ │ │
│ .pto MLIR → C++ │ │
│ (uses pto-isa hdrs) │ │
└───┬────────────────────┘ │
│ kernel C++ │
│ (includes pto-isa) │
┌───▼────────────────────┐ │
│ pto-isa │ │
│ ISA definition: │ │
│ tile instruction hdrs │ │
└───┬────────────────────┘ │
│ compiled AICore binaries │
┌───▼─────────────────────────────────────▼───┐
│ simpler │
│ Runtime: task graph execution on device │
│ Host ↔ AICPU ↔ AICore coordination │
└─────────────────────────────────────────────┘
Two codegen paths from pypto:
- InCore functions (tile-level compute) →
.pto→ PTOAS → pto-isa → AICore binaries - Orchestration functions (task scheduling) → C++ using simpler runtime API → compiled for AICPU
Component Details¶
pypto — Compiler Framework¶
The core compiler. Takes Python tensor programs and compiles them into device-executable code.
Inputs: Python programs written with pypto.language DSL (@pl.program, @pl.function)
Outputs:
.ptofiles — PTO-ISA MLIR dialect, one per InCore kernel function (runs on AICore)- Orchestration C++ — task scheduling code using simpler runtime API (runs on AICPU)
Internal pipeline:
- IR layer: Multi-level representation — Tensor ops, Tile ops, and system ops coexist in the same IR
- Pass pipeline: Progressively lowers tensor-level IR to tile-level IR (unrolling, SSA conversion, tiling, memory allocation, etc.)
- CodeGen: Two backends — PTO codegen (InCore →
.ptoMLIR for AICore) and Orchestration codegen (→ C++ for AICPU)
Key directories:
| Path | Contents |
|---|---|
include/pypto/ir/ |
C++ IR node definitions |
src/ir/transforms/ |
Compiler passes |
src/codegen/ |
PTO and Orchestration code generators |
python/pypto/language/ |
Python DSL frontend |
python/pypto/ir/ |
Pass manager, compile API |
pypto-lib — Model Zoo & Primitives¶
A library of real-world models and primitive tensor functions built on top of pypto. Serves as:
- Model zoo — end-to-end model examples (e.g., DeepSeek, FFN, LLaMA) that exercise the full compilation pipeline
- Primitive tensor functions — reusable tensor-level building blocks (elementwise, reduction, matmul) that the compiler tiles and lowers to PTO-ISA
Depends on: pypto (imports pypto.language, compiles via pypto.ir.compile)
Interface with pypto: pypto-lib programs are standard pypto programs — they use the same @pl.program/@pl.function DSL and compile through the same pipeline. No special API exists between them; pypto-lib is a consumer of the pypto framework.
Compiler CI coverage: The pypto-lib-compile job compiles all formal runnable
entries selected by pypto-lib's .github/scripts/detect_changes.py --all, using
its platform ownership rules for A2/A3 and A5. Drafts and non-runnable helpers are
excluded, including the CPU-only GLM weights round-trip, prefill reference,
and models/glm5_3_flash/prefill_fwd.py weight checks; helpers are exercised
through their callers. That GLM prefill CLI defaults to CPU weight checks and
produces no compilation records.
Other GLM kernel entries remain covered, including entries without a
--compile-only option. Device-only entries are included because compilation
needs no NPU. The adapter forces golden.run into compile-only mode, records direct compile calls, and requires PTOAS. Coverage
includes frontend, passes, verification, codegen, and PTOAS.
This does not build device binaries or check numerical results; pypto-lib-model
provides the separate device smoke tests.
The A2/A3 compile leg runs on a CANN-equipped npu host and activates the
toolkit so external CCE wrappers can resolve devkit headers at import time.
It does not acquire or execute on an NPU. The A5 leg runs on a cpu host.
To reproduce after activating a built PyPTO environment with the pinned PTOAS:
python tests/ci/compile_pypto_lib.py --lib /path/to/pypto-lib \
--platform a2a3 --jobs 4 --output build/lib-compile-a2a3
Repeat with --platform a5. Each entry has a 1200-second timeout (override with
--timeout). Compilation failures, process failures, timeouts, and zero recorded
compilations fail the job. Malformed or unreadable receipts fail their entry
without aborting the remaining entries or losing the matrix summary.
When an entry dispatches cases by launching its own script with the current
Python interpreter, each child runs through the same compile-only adapter.
Child environment, working directory, and process isolation are preserved,
and the parent combines their compilation records. The compile-output allowlist
is currently empty, so the adapter does not inject or rewrite runtime directories.
--runtime-dir may identify a replay input or belong to a separate checkpoint
mode; merely declaring that option does not enable output-directory injection.
A child failure or missing, empty, or malformed child receipt fails the entry
even if the parent exits successfully. This interception applies to the current entry
script launched by the same Python interpreter.
On compilation failure, CI uploads per-entry logs, results, and a manifest
containing the tested library revision and selected entries. Successful runs
report results in the job log and summary without uploading artifacts.
PTOAS — PTO Assembler & Optimizer¶
An MLIR-based assembler that consumes .pto files produced by pypto's codegen and produces optimized C++ kernel code.
Inputs: .pto files (PTO-ISA MLIR dialect)
Outputs: C++ source files that #include pto-isa headers
Responsibilities:
- Parse PTO-ISA MLIR dialect
- Apply PTO-level optimization passes (sync insertion, memory planning)
- Lower PTO MLIR to C++ code that calls pto-isa tile instructions
Interface with pypto: The .pto file is the contract. pypto's PTO codegen emits MLIR using the PTO dialect (ops like pto.tload, pto.tmul, pto.alloc_tile, etc.), and PTOAS parses that dialect. The two repos must agree on the PTO MLIR dialect definition.
pto-isa — Instruction Set Architecture¶
Defines the tile-level instruction set for the target hardware. Provides C++ headers that declare the hardware tile instructions (load, store, compute, sync, etc.).
Consumed by:
- PTOAS — the C++ code PTOAS generates calls pto-isa instructions
- simpler — clones pto-isa headers at first build for runtime compilation
Interface: C++ header library defining the instruction API. Downstream consumers #include pto-isa headers; the hardware vendor provides the target-specific implementations that back these headers.
runtime/pto_isa.pin is the single source of truth for the revision, and
simpler owns the only resolver (simpler_setup.pto_isa.ensure_pto_isa_root):
it manages one checkout under the runtime's build/pto-isa, reuses it only when
that tree is clean and already at the pin, re-clones it otherwise, and verifies
HEAD before returning. PyPTO delegates to it rather than resolving the pin
itself — a second resolver could hand the kernel compiler an off-pin tree, and
the compiler skips its own revision re-check precisely because the resolver
already guaranteed the pin. To change the revision, update the runtime-side pin.
PTO_ISA_ROOT is exported with the resolved path so downstream consumers that
build extern CCE kernels can find the ISA headers, but it is never read: an
ambient value is not the pin. Code that needs the headers should call
pypto.runtime.pto_isa_include_dir() instead of reading the variable.
simpler — Task Runtime¶
Executes compiled programs on Ascend hardware. Manages the three-program execution model: Host, AICPU kernel, and AICore kernel.
Inputs:
- Compiled AICore kernel binaries (InCore path: pypto → PTOAS → pto-isa → device compiler)
- Compiled AICPU orchestration binary (Orchestration path: pypto → C++ with simpler runtime API → device compiler)
Responsibilities:
- Build and execute task dependency graphs
- Coordinate Host ↔ AICPU ↔ AICore execution
- Handle device memory, synchronization, and handshake protocols
Interface with pypto: The orchestration C++ code that pypto generates uses the simpler runtime API (rt_submit_task, make_tensor_external, etc.), which simpler implements. The runtime API is the contract between pypto's orchestration codegen and simpler.
The runtime pin¶
runtime/ is the simpler submodule, so PyPTO's pin on it is the gitlink —
git rev-parse HEAD:runtime. There is no second pin file to drift, for the same reason
toolchain/versions.env declines to restate the pto-isa revision.
The installed side carries no version that tracks it: simpler's pyproject.toml says
0.1.0 and always will. Its only revision identity is _task_interface.__build_commit__,
stamped by runtime/python/bindings/CMakeLists.txt at build time from git rev-parse HEAD.
pypto.runtime.runtime_pin.check_runtime_pin() compares the two. It runs at import of the
two PyPTO modules that import simpler at module scope — pypto.runtime.task_interface and
pypto.runtime.kernel_compiler — and a mismatch raises RuntimePinMismatch (an
ImportError) naming both revisions and the reinstall command.
Simpler carries its own equivalent guard
(simpler.task_interface._assert_bindings_match_source_tree), but that one compares the
extension against its own source tree and returns early when there is no .git beside
it. A wheel, or a pip install ./runtime that copies into site-packages, is therefore
never checked — and that install is where staleness is hardest to see, because a changed
struct layout makes fields read as 0 with no error.
Two comparisons, two severities:
| Comparison | Meaning | Result |
|---|---|---|
__build_commit__ vs git -C runtime rev-parse HEAD |
the installed simpler was not built from this tree | error |
git -C runtime rev-parse HEAD vs git rev-parse HEAD:runtime |
your runtime checkout is off PyPTO's pin | warning (RuntimePinWarning) |
The second is only a warning: working on a runtime branch is legitimate.
Everything else is a skip, never a failure — a wheel-installed PyPTO with no
runtime/, an uninitialized runtime/ submodule (empty, so it has no revision of its
own), no git available, or a simpler built without git (empty stamp). Refusing to
run because the question is unanswerable would break every legitimate install. An
importable _task_interface with no __build_commit__ attribute is not a skip: the
attribute only disappears on an extension compiled before the stamp existed, which is by
definition a different revision.
Check it by hand with pypto-runtime-pin, which prints both sides and exits non-zero on a
mismatch; pypto-runtime-pin --fix reinstalls runtime/ and re-verifies in a fresh
interpreter. PYPTO_SKIP_RUNTIME_PIN_CHECK=1 bypasses the check. The unit suite sets it in
tests/ut/conftest.py because it stubs simpler and must not be gated on the installed
revision; system tests run real kernels and are deliberately not exempted.
Interface Summary¶
Each repo boundary has a well-defined interface:
pypto-lib ──[ Python API: pypto.language / pypto.ir ]──► pypto
pypto ──[ .pto files: PTO-ISA MLIR dialect ]──► PTOAS
pto-isa ──[ C++ #include: tile instruction hdrs ]──► PTOAS
pto-isa ──[ C++ #include: ISA headers ]──► simpler
pypto ──[ C++ API: simpler runtime API calls ]──► simpler
| Border | Format | Who provides | Who consumes |
|---|---|---|---|
| pypto-lib → pypto | Python imports | pypto-lib | pypto compiler |
| pypto → PTOAS | .pto MLIR files |
pypto PTO codegen | PTOAS parser |
| pto-isa → PTOAS | C++ #include |
pto-isa headers | PTOAS codegen |
| pto-isa → simpler | C++ #include |
pto-isa headers | simpler build |
| pypto → simpler | Orchestration C++ | pypto orchestration codegen | simpler runtime |
Cross-Repo Development¶
When a change spans multiple repos, identify which interfaces are affected:
| Change | Repos involved | Interface affected |
|---|---|---|
| New tile instruction | pto-isa + PTOAS + pypto | ISA headers, PTO MLIR dialect, pypto op/codegen |
| New tensor primitive | pypto-lib + pypto | Python DSL (if new ops needed) |
| New runtime feature | simpler + pypto | simpler runtime API, orchestration codegen |
| New PTO MLIR op | PTOAS + pypto | PTO MLIR dialect, pypto PTO codegen |
| New model example | pypto-lib only | None (consumer of existing APIs) |