From 734c90b5f530b8619fc69531404a68e4a0499693 Mon Sep 17 00:00:00 2001 From: WLDFA Date: Tue, 20 Oct 2026 14:54:16 +0800 Subject: [PATCH] Unify active identity to PTO ISA 0.59.0.0 and add TLEA wrapper Move the active encoding identity (ABI, encoding-projection SHA-256, ELF release field) from the PTO 0.58.7 development golden to the published PTO ISA v0.59.0.0 release (commit b016532); unify the 0.58.7/v058 active naming; add the TLEA JCORE inline-asm wrapper and its usage page. - Identity carriers -> 0.59.0: verify_pto_identity.py ELF note, pto_tileop_api_revision.hpp, Makefile, engine-ops pto_source, engine-contract test. Rework the sync tool to read the release manifest (fail-closed), renamed sync_linxisa_v058_contract.py -> sync_pto_isa_0590_contract.py. - Keep the real LinxISA v0.58 source (no 0.59 profile) and record the development-golden lock under pto_source.development_lock. The 119-op Tile catalog is byte-identical between 0.58.7 and 0.59.0.0; only the encoding identity moved. Release manifest status is draft and numeric conformance is limited; recorded faithfully. - Rename contracts/pto-isa-0.58.7-tile-operations.json -> pto-isa-0.59.0-tile-operations.json; historical/migration material keeps its old-version identity. - TLEA (selector 0x2E, VEC; S32/U32/S64/U64 -> S64/U64 byte offsets, RowMajor; fail-closed on CUBE_M32/Shared): wrapper in jcore/template_asm.hpp, usage page, support-status, engine-contract + capability tests, positive/negative target fixtures. Backends declared separately (JCORE only; no CPU sim/AArch64). Verified: make check (exit 0); host-shim template instantiation; and on the updated Linx toolchain, real target compile + disassembly of the TLEA bundle and all 8 TLEA negative static_asserts. Co-Authored-By: Claude Opus 4.8 --- Makefile | 4 +- README.md | 30 ++-- contracts/README.md | 20 ++- contracts/linxisa-v0.58-engine-ops.json | 35 +++-- ...on => pto-isa-0.59.0-tile-operations.json} | 0 docs/tileop-usage/README.md | 28 ++-- docs/tileop-usage/generated/engines.md | 18 ++- docs/tileop-usage/support-status.md | 31 ++-- .../arithmetic/TLEA.md | 109 +++++++++++++ include/common/pto_tileop_api_revision.hpp | 4 +- include/jcore/template_asm.hpp | 132 ++++++++++++++++ test/test_v058_engine_contract.py | 139 +++++++++++++--- test/test_version_header.py | 4 +- test/tileop_api/compile.all | 2 +- test/tileop_api/run_negatives.sh | 20 +++ test/tileop_api/src/Tlea.cpp | 49 ++++++ test/tileop_api/src/TleaNegatives.cpp | 54 +++++++ test/tileop_api/verify_pto_identity.py | 12 +- tools/check_pto_catalog_alignment.py | 17 +- tools/generate_engine_docs.py | 32 ++-- tools/generate_tileop_usage_docs.py | 2 +- ...tract.py => sync_pto_isa_0590_contract.py} | 148 +++++++++++++----- 22 files changed, 740 insertions(+), 150 deletions(-) rename contracts/{pto-isa-0.58.7-tile-operations.json => pto-isa-0.59.0-tile-operations.json} (100%) create mode 100644 docs/tileop-usage/tile-scalar-and-immediate/arithmetic/TLEA.md create mode 100644 test/tileop_api/src/Tlea.cpp create mode 100644 test/tileop_api/src/TleaNegatives.cpp rename tools/{sync_linxisa_v058_contract.py => sync_pto_isa_0590_contract.py} (58%) diff --git a/Makefile b/Makefile index bc56e796..8b7f66b1 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ LIBNAME = tileop-api -VERSION = 0.58.7 +VERSION = 0.59.0 HEADERS = $(wildcard include/*.h) $(wildcard include/*.hpp) include/jcore include/cpu_sim include/aarch64 include/common TILEOP_API_REVISION ?= $(shell git rev-parse HEAD 2>/dev/null || printf unknown) TILEOP_API_REVISION_IS_EXACT ?= $(shell test -z "$$(git status --porcelain --untracked-files=all 2>/dev/null)" && printf 1 || printf 0) @@ -53,7 +53,7 @@ install: echo '#define PTO_TILEOP_API_REVISION_HPP'; \ echo ''; \ echo '#define PTO_TILEOP_API_VERSION "$(VERSION)"'; \ - echo '#define PTO_TILEOP_API_SPEC_VERSION "0.58.7"'; \ + echo '#define PTO_TILEOP_API_SPEC_VERSION "0.59.0"'; \ echo '#define PTO_TILEOP_API_REVISION "$(TILEOP_API_REVISION)"'; \ echo '#define PTO_TILEOP_API_REVISION_IS_EXACT $(TILEOP_API_REVISION_IS_EXACT)'; \ echo ''; \ diff --git a/README.md b/README.md index 7d91b4cd..d503c3f2 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,15 @@ # Linx TileOP API -Header-only C++ TileOP bindings for the LinxISA / PTO ISA 0.58.7 architectural contract. -The checked-in catalog and documentation are generated against the reviewed -PTO ISA 0.58.7 development golden (`development-not-published`, ABI -`pto-isa-0.58.7-mode-function-v1`). +Header-only C++ TileOP bindings for the LinxISA / PTO ISA 0.59.0 architectural +contract. The checked-in catalog and documentation are generated against the +published PTO ISA `v0.59.0.0` release (commit `b016532`, ABI +`pto-isa-0.59.0-mode-function-v1`). The release manifest records +`specification_status: draft` and limits implementation conformance to +`b-fpatr-and-tcvt-e8m0-asl-proven-other-numeric-domains-unproven`; this binding +carries that identity without claiming a finalized specification or full +numeric conformance. The semantic engine inventory remains the LinxISA v0.58 +authority projection, whose 119-operation Tile catalog is byte-identical to the +release catalog. Installed headers expose their provenance through ``. `PTO_TILEOP_API_VERSION` and @@ -13,7 +19,7 @@ Installed headers expose their provenance through allow consumers to reject toolchains that predate a required fix. The normative operation inventory comes from the checked-in PTO catalog at -[`contracts/pto-isa-0.58.7-tile-operations.json`](contracts/pto-isa-0.58.7-tile-operations.json). +[`contracts/pto-isa-0.59.0-tile-operations.json`](contracts/pto-isa-0.59.0-tile-operations.json). The public bindings retain the unique compiled `BSTART.TEPL` carrier for VEC/SFU source compatibility and emit the named TLSU/CUBE operation forms accepted by the current Linx compiler. The generated engine index is a wrapper compatibility @@ -26,7 +32,7 @@ view, not a replacement for the PTO ASL/NDF semantics. - [CUBE operations](docs/tileop-usage/cube/matrix-matrix/TMATMUL.md) - [Tile and Shared-register constraints](docs/tileop-usage/concepts/tile-constraints.md) - [Layout helpers](docs/tileop-usage/layout-and-rearrangement/layout/TCONCAT.md) -- [PTO ISA 0.58.7 CUBE layout operations](docs/tileop-usage/layout-and-rearrangement/layout/TPERMUTE.md) +- [PTO ISA 0.59.0 CUBE layout operations](docs/tileop-usage/layout-and-rearrangement/layout/TPERMUTE.md) - [Comparison operations](docs/tileop-usage/elementwise-tile-tile/logical/TCMP.md) - [TEXPDIF](docs/tileop-usage/elementwise-tile-tile/transcendental/TEXPDIF.md) - [Sorting operations](docs/tileop-usage/irregular-and-complex/sorting/TSORT.md) @@ -38,18 +44,20 @@ view, not a replacement for the PTO ASL/NDF semantics. make check ``` -Target compilation requires a Linx LLVM build supporting the PTO ISA 0.58.7 +Target compilation requires a Linx LLVM build supporting the PTO ISA 0.59.0 encoding ABI. The old PTO ISA 0.58.3 Linx LLVM requirement belongs only to the historical migration fixtures under `test/tileop_api` and `docs/tileop-usage/migration/pto-0583-migration.md`; it is not the current API baseline. Run the catalog and documentation checks before target compilation. -To refresh the pinned projection from the clean, exact reviewed LinxISA -authority commit recorded by the generator: +To refresh the pinned projection, provide the clean, exact reviewed LinxISA +v0.58 authority commit together with a clean checkout of `PTO-ISA/pto-spec` at +the `v0.59.0.0` release commit: ```sh -python3 tools/sync_linxisa_v058_contract.py \ - /path/to/linx-isa/isa/v0.58/linxisa-v0.58.json +python3 tools/sync_pto_isa_0590_contract.py \ + /path/to/linx-isa/isa/v0.58/linxisa-v0.58.json \ + --pto-root /path/to/pto-spec python3 tools/generate_engine_docs.py make check ``` diff --git a/contracts/README.md b/contracts/README.md index 95a1be80..2d2eef69 100644 --- a/contracts/README.md +++ b/contracts/README.md @@ -1,17 +1,23 @@ # LinxISA contract projections -`pto-isa-0.58.7-tile-operations.json` is the checked-in machine-readable snapshot -of the reviewed PTO ISA 0.58.7 development Tile catalog. It records all 119 accepted direct +`pto-isa-0.59.0-tile-operations.json` is the checked-in machine-readable snapshot +of the published PTO ISA 0.59.0.0 release Tile catalog. It records all 119 accepted direct operations plus the catalog's deleted and rejected inventories. Its source of truth is `PTO-ISA/pto-spec/spec/catalog/tile-operations.json`; refresh it only -from commit `f0a876e449a95d26841c5ee7affb4c905ebc5f5b` and review the resulting diff. +from the `v0.59.0.0` release commit `b0165320a4b575b18d2f4d93faf40178f661ab49` +and review the resulting diff. These bytes are identical to the PTO 0.58.7 +development golden catalog (SHA-256 533db9b8...); only the surrounding encoding +identity moved to the release. -`linxisa-v0.58-engine-ops.json` is a generated, provenance-pinned LinxISA/PTO -0.58.7 development projection. It records operation ownership and encodings; -it does not claim that this repository implements every projected operation: +`linxisa-v0.58-engine-ops.json` is a generated, provenance-pinned projection of +the LinxISA v0.58 authority onto the PTO ISA 0.59.0.0 release encoding identity. +It records operation ownership and encodings; it does not claim that this +repository implements every projected operation. There is no LinxISA 0.59 +profile, so the LinxISA `source` stays v0.58 and the development-golden lock it +carried is preserved under `pto_source.development_lock`: ```bash -python3 tools/sync_linxisa_v058_contract.py \ +python3 tools/sync_pto_isa_0590_contract.py \ /path/to/linx-isa/isa/v0.58/linxisa-v0.58.json \ --pto-root /path/to/pto-spec ``` diff --git a/contracts/linxisa-v0.58-engine-ops.json b/contracts/linxisa-v0.58-engine-ops.json index 0481f291..3da686e7 100644 --- a/contracts/linxisa-v0.58-engine-ops.json +++ b/contracts/linxisa-v0.58-engine-ops.json @@ -110,23 +110,36 @@ ], "profile": "v0.58", "pto_source": { - "commit": "f0a876e449a95d26841c5ee7affb4c905ebc5f5b", - "development_manifest": { - "path": "spec/development-manifest.json", - "sha256": "0c6d0b2a1ec0b49e32e13971e751a5ea19946351a3880bfdfcef0f50351944f7" - }, - "encoding_abi": "pto-isa-0.58.7-mode-function-v1", - "encoding_projection_sha256": "a5f78ecd707bde4a014542158ea257c783796b95fa4fbcce37742e41fee6a881", - "publication": null, - "release": "0.58.7", + "commit": "b0165320a4b575b18d2f4d93faf40178f661ab49", + "content_sha256": "a3e71975e7f753864f7ec09c57515e60f5a6e3e72dfdbce8e444c815a20b2835", + "development_lock": { + "catalog_sha256_matches_release": true, + "commit": "f0a876e449a95d26841c5ee7affb4c905ebc5f5b", + "development_manifest": { + "path": "spec/development-manifest.json", + "sha256": "0c6d0b2a1ec0b49e32e13971e751a5ea19946351a3880bfdfcef0f50351944f7" + }, + "note": "The LinxISA v0.58 authority locked the PTO development golden; its Tile catalog bytes equal the 0.59.0.0 release Tile catalog (both SHA-256 533db9b8...), so the v0.58 engine projection remains valid against the published release.", + "release": "0.58.7", + "tree": "fe9e8e050375fbce3f526d08acca13c37cd15830" + }, + "encoding_abi": "pto-isa-0.59.0-mode-function-v1", + "encoding_projection_sha256": "91509080ca656eb124f47830dcb09c50389dc177266b3b8df9d2d11dc37d5697", + "publication_version": "0.59.0.0", + "release": "0.59.0", + "release_manifest": { + "path": "spec/release-manifest.json", + "sha256": "3c6b20623e73822c0bd26021c10beb233b8809328b5515f57609eadad1749dc4" + }, + "release_tag": "v0.59.0.0", "repo": "https://github.com/PTO-ISA/pto-spec.git", - "status": "development-not-published", + "specification_status": "draft", "tile_catalog": { "count": 119, "path": "spec/catalog/tile-operations.json", "sha256": "533db9b8f31f118af5978de813cfaa3fa738de820ee24655faa2ee71f343a706" }, - "tree": "fe9e8e050375fbce3f526d08acca13c37cd15830" + "tree": "31ff0c2d39cbed714baf5be7929bfd06887be9fb" }, "schema": "linx-tileop-api.engine-ops-projection.v2", "semantic_engine_counts": { diff --git a/contracts/pto-isa-0.58.7-tile-operations.json b/contracts/pto-isa-0.59.0-tile-operations.json similarity index 100% rename from contracts/pto-isa-0.58.7-tile-operations.json rename to contracts/pto-isa-0.59.0-tile-operations.json diff --git a/docs/tileop-usage/README.md b/docs/tileop-usage/README.md index ebc6fe16..164dfc3f 100644 --- a/docs/tileop-usage/README.md +++ b/docs/tileop-usage/README.md @@ -6,16 +6,20 @@ ## 版本与兼容性 -本目录当前以 PTO-ISA/pto-spec 的 **0.58.7** 架构规范为对照基线: - -- architecture version:`0.58.7` -- publication version:`0.58.7.0` -- stable release commit:`de57af400cf607f03730aa522a4e9bfb160596de` -- release tag:`v0.58.7.0` -- encoding ABI:`pto-isa-0.58.7-mode-function-v1` - -PTO `main` 是开发分支;需要可复现构建时应锁定上面的 release commit。本文档描述 -的是架构规范和本仓库 wrapper 的交集,并不表示 wrapper 已实现 0.58.7 的全部操作。 +本目录当前以 PTO-ISA/pto-spec 的 **0.59.0.0** 发布规范为对照基线: + +- architecture version:`0.59.0` +- publication version:`0.59.0.0` +- release tag:`v0.59.0.0` +- release commit:`b0165320a4b575b18d2f4d93faf40178f661ab49` +- encoding ABI:`pto-isa-0.59.0-mode-function-v1` +- specification status:`draft`(发布 manifest 自身记为 draft,实现 conformance 限定为 + `b-fpatr-and-tcvt-e8m0-asl-proven-other-numeric-domains-unproven`) + +PTO `main` 是开发分支;需要可复现构建时应锁定上面的 release commit。119 个操作的 +Tile catalog 与 PTO 0.58.7 development golden 逐字节一致,只是 encoding identity 移到了 +发布版本。本文档描述的是架构规范和本仓库 wrapper 的交集,并不表示 wrapper 已实现 +0.59.0 的全部操作,也不表示该发布规范已最终定稿或数值 conformance 已全部证明。 每个操作页中的 C++ 签名以本仓库头文件为准,PTO ASL/NDF 是架构合法性的权威来源。 [0.58.3 迁移说明](migration/pto-0583-migration.md)是历史文档,保留用于迁移旧 @@ -31,7 +35,7 @@ kernel;其中的旧版本数量、旧 engine inventory 和旧 encoding identit - `PTO_TILEOP_API_REVISION_IS_EXACT`:revision 是否来自干净 checkout; - `PTO_TILEOP_API_HAS_LOCAL_B_KN_FIX`:local Right B 使用逻辑 `[K,N]` 契约。 -当前 wrapper 与 PTO 0.58.7 catalog 的覆盖边界见 +当前 wrapper 与 PTO 0.59.0 catalog 的覆盖边界见 [统一支持状态表](support-status.md)。该表区分“已实现”“仅部分 layout 支持”“尚无 wrapper”和“仅历史参考”,并单独记录 CPU simulator/JCORE、LLVM MC、LLVM compiler lowering 及 AArch64/SME 的 backend 能力;PTO catalog 中存在某个操作名, @@ -153,7 +157,7 @@ clang++ --target=linx64v5-unknown-linux-musl -mlxbc -fenable-matrix \ 也在该页面说明。 - 常规逐元素算子从 [TADD](elementwise-tile-tile/arithmetic/TADD.md) 开始;按目录选择 算术、逻辑、转换、归约、布局和不规则操作。 -- PTO ISA v0.58.7 的 CUBE layout 重排操作从 +- PTO ISA 0.59.0 的 CUBE layout 重排操作从 [TPERMUTE](layout-and-rearrangement/layout/TPERMUTE.md) 开始; [TSHUF](layout-and-rearrangement/layout/TSHUF.md)、 [TPACK](layout-and-rearrangement/layout/TPACK.md)、 diff --git a/docs/tileop-usage/generated/engines.md b/docs/tileop-usage/generated/engines.md index 9aed9ef6..e91aa8fe 100644 --- a/docs/tileop-usage/generated/engines.md +++ b/docs/tileop-usage/generated/engines.md @@ -1,14 +1,15 @@ -# LinxISA / PTO ISA v0.58.7 wrapper engine compatibility view +# LinxISA v0.58 / PTO ISA 0.59.0.0 wrapper engine compatibility view 架构定义的引擎类别只有 **VEC**, **TLSU**, **CUBE**, and **SFU**。 VEC 只包含逐元素操作;SFU 包含归约、广播、变换、排序以及其他需要更复杂硬件的操作。 TEPL 仍是唯一的编译 carrier 标识。`BSTART.VEC` 和 `BSTART.SFU` 是特定引擎的汇编别名; inline wrapper 保留 `BSTART.TEPL`,以兼容之前的工具链源码。 -下表根据本仓库固定的 LinxISA/PTO development golden 投影生成,数据记录在 +下表根据本仓库固定的 LinxISA v0.58 authority 投影生成(其操作清单与 PTO ISA 0.59.0.0 +发布 catalog 逐字节一致),数据记录在 [`contracts/linxisa-v0.58-engine-ops.json`](../../../contracts/linxisa-v0.58-engine-ops.json) 中。 -Golden 共 119 项;其中 118 项在 `include/` 有名称引用, -1 项明确没有 wrapper。名称引用不证明 ASL/NDF 语义完整实现。 +投影共 119 项;其中 119 项在 `include/` 有名称引用, +0 项明确没有 wrapper。名称引用不证明 ASL/NDF 语义完整实现。 ## VEC @@ -45,7 +46,7 @@ Golden 共 119 项;其中 118 项在 `include/` 有名称引用, | `TCMPS` | `BSTART.VEC TCMPS` | 45 | tile-scalar-and-immediate | 源码有引用;不代表完整语义一致 | | `TSELS` | `BSTART.VEC TSELS` | 58 | tile-scalar-and-immediate | 源码有引用;不代表完整语义一致 | | `TEXPANDS` | `BSTART.VEC TEXPANDS` | 59 | tile-scalar-and-immediate | 源码有引用;不代表完整语义一致 | -| `TLEA` | `BSTART.VEC TLEA` | 46 | tile-scalar-and-immediate | 尚无 wrapper | +| `TLEA` | `BSTART.VEC TLEA` | 46 | tile-scalar-and-immediate | 源码有引用;不代表完整语义一致 | ## SFU @@ -151,8 +152,9 @@ Golden 共 119 项;其中 118 项在 `include/` 有名称引用, ## 分类语义 -PTO ISA 0.58.7 将执行引擎与操作分类解耦。本表是 wrapper compatibility view; -其底层投影记录当前 development golden selector 数据。`elementwise-tile-tile` +PTO ISA 0.59.0 将执行引擎与操作分类解耦。本表是 wrapper compatibility view; +其底层投影记录 LinxISA v0.58 authority 的 selector 数据(与 0.59.0.0 发布 catalog 一致)。 +`elementwise-tile-tile` 和 `tile-scalar-and-immediate` 类别在 VEC 上执行逐元素操作,但其中的 `TEXP`、`TLOG`、`TRECIP`、`TSQRT`、`TRSQRT` 由 SFU 执行。 `reduce-and-expand`、`layout-and-rearrangement` 和 `irregular-and-complex` 类别由 SFU 执行。 @@ -161,7 +163,7 @@ PTO ISA 0.58.7 将执行引擎与操作分类解耦。本表是 wrapper compatib ## 早期版本中移除的操作 -历史版本还提供了一些已从 PTO 0.58.7 active catalog 移除的 Tile 操作(例如 ACC 风格的后处理辅助操作)。 +历史版本还提供了一些已从 PTO 0.59.0 active catalog 移除的 Tile 操作(例如 ACC 风格的后处理辅助操作)。 本库不会把已退役的操作生成到当前目录;退役名称的规范列表记录在 contract 的 `deleted_tile_names` 字段中。 ## 使用示例 diff --git a/docs/tileop-usage/support-status.md b/docs/tileop-usage/support-status.md index 87aa47a3..69547058 100644 --- a/docs/tileop-usage/support-status.md +++ b/docs/tileop-usage/support-status.md @@ -1,6 +1,6 @@ -# PTO ISA 0.58.7 wrapper 支持状态 +# PTO ISA 0.59.0 wrapper 支持状态 -本表以 `contracts/pto-isa-0.58.7-tile-operations.json` 的 119 个 +本表以 `contracts/pto-isa-0.59.0-tile-operations.json` 的 119 个 `accepted-direct-operation` 为操作清单。它描述 Linx TileOP C++ wrapper 的 公开实现状态,不替代 PTO-ISA/pto-spec 的 ASL/NDF 合法性、fault、completion、 rollback、definedness 或 memory-order 语义。 @@ -10,30 +10,41 @@ rollback、definedness 或 memory-order 语义。 | **已实现** | 当前 `include/` 有可调用 wrapper;本地测试覆盖其至少一个有效路径。 | | **仅部分 layout 支持** | wrapper 存在,但只覆盖 catalog 合法 layout/shape/属性组合的子集;其他组合必须以编译期约束拒绝,不能推断为缺陷或自动支持。 | | **尚无 wrapper** | PTO catalog 有操作,但本仓库没有公开的 C++ wrapper;不能通过拼接汇编或复用相近 API 冒充支持。 | -| **仅历史参考** | 名称来自旧版本或已删除清单;保留页面/禁用 stub 只用于迁移,不能生成当前 PTO 0.58.7 指令。 | +| **仅历史参考** | 名称来自旧版本或已删除清单;保留页面/禁用 stub 只用于迁移,不能生成当前 PTO 0.59.0 指令。 | ## 当前覆盖 | PTO catalog 范围 | 状态 | 说明 | | --- | --- | --- | | TEPL elementwise、scalar、reduce/expand、irregular(除 `TLEA`) | 已实现 | 逐操作页面和 `jcore/template_asm.hpp` 为 wrapper 权威;dtype、valid region、padding 和 selector 仍受 ASL 约束。 | -| `TLEA` | 尚无 wrapper | PTO development golden 已分配 SFU selector 31;本仓库尚无公开 C++ wrapper,不以相近操作代替。 | -| `TEXPDIF` | CPU simulator、JCORE inline-asm 已实现;LLVM MC catalog 已实现;LLVM compiler lowering 尚未完成;AArch64/SME 不支持 | PTO 0.58.7 selector 29。已有 wrapper 不等于 LLVM compiler 已具备从 IR/builtin 到 TEXPDIF 的端到端 lowering。 | +| `TLEA` | JCORE inline-asm wrapper 已实现(仅 RowMajor);CPU simulator 未实现;AArch64/SME 未实现;LLVM MC / compiler lowering 分别判断 | PTO catalog 将 TLEA 列为 `accepted-direct-operation`(`BSTART.TEPL`,**VEC** 引擎,selector `0x2E`=46,function 14/mode 1);操作数为 S32/U32/S64/U64 element index、per-PE element-width 标量与 S64/U64 byte-offset 目标。`include/jcore/template_asm.hpp` 现有 RowMajor wrapper,按 ASL 以编译期约束限定 location/dtype/signedness/layout/logical-shape;CUBE_M32 虽为合法 layout 但本仓库尚未实现(issue #371 double-CELL b64 映射待在 Linx 工具链上对照发布 ASL 验证)。element-width 的运行时合法性(8/16/32/64)由指令 legality 检查,不是编译期静态拒绝。wrapper 存在不代表 CPU simulator、AArch64 或 LLVM 端到端已具备 TLEA 支持。 | +| `TEXPDIF` | CPU simulator、JCORE inline-asm 已实现;LLVM MC catalog 已实现;LLVM compiler lowering 尚未完成;AArch64/SME 不支持 | PTO selector 29。已有 wrapper 不等于 LLVM compiler 已具备从 IR/builtin 到 TEXPDIF 的端到端 lowering。 | | TLSU `TLOAD`/`TSTORE`/`TMOV`/`TPREFETCH`/`GMOV` | 已实现 | 传输、peer move 和 prefetch 有独立 C++ 入口;layout conversion 仅对页面列出的组合开放。 | | TLSU `MGATHER`/`MSCATTER` 及 atomic/reduction variants | 仅部分 layout 支持 | wrapper 覆盖当前公开 selector;ColumnMajor selector、mask/索引 dtype 和不同 atomic 组合不得由普通 gather/scatter 重载推断。 | | CUBE TMATMUL/TGEMV 及 bias/acc/MX variants | 仅部分 layout 支持 | CUBE_M16/CUBE_M32、Shared physical shape、scale layout 和 InternalAcc 由具体 wrapper/操作页限制。 | | TEPL layout/rearrangement(`TPERMUTE`、`TSHUF`、`TPACK`、`TUNPACK`、`TGPR2T`) | 仅部分 layout 支持 | 只覆盖已实现的 CUBE/Local 路径和控制字段;未列出的组合保持拒绝。 | -| 0.58.7 `MGATHER`/`MSCATTER` family | 已适配 | 0.58.7 removes the GM row-stride operand and interprets index tiles as explicit byte displacements;wrapper 与 contract test 已改为 base-only `B.IOR`。 | -| 0.58.7 `TROWEXPAND*`/`TCOLEXPAND*` roles | 已适配 | Source roles 使用 row-broadcast/column-broadcast operation view;wrapper 约束、注释及操作文档已同步。 | +| `MGATHER`/`MSCATTER` family(byte-displacement 索引) | 已适配 | 自 PTO 0.58.7 起 GM row-stride 操作数被移除、index tile 解释为显式 byte displacement,该语义在 0.59.0.0 发布 catalog 中保持不变;wrapper 与 contract test 使用 base-only `B.IOR`。 | +| `TROWEXPAND*`/`TCOLEXPAND*` roles | 已适配 | Source roles 使用 row-broadcast/column-broadcast operation view;wrapper 约束、注释及操作文档已同步。 | | `deleted_names`、`rejected_names`,以及 `TTRANS`/`TFILLPAD` 等历史页面 | 仅历史参考 | 不属于 active catalog;页面必须保留明确的 retired 标识。 | ## 版本边界 -- 当前 API/spec 基线:PTO ISA development golden `0.58.7`,状态 - `development-not-published`,publication 为空,ABI - `pto-isa-0.58.7-mode-function-v1`。 +- 当前 API/spec 基线:已发布的 PTO ISA `v0.59.0.0` release(commit `b016532`),ABI + `pto-isa-0.59.0-mode-function-v1`、encoding projection SHA-256 + `91509080…`、ELF release 字段 `0.59.0`(见 `contracts/pto-isa-0.59.0-tile-operations.json`、 + `contracts/linxisa-v0.58-engine-ops.json` 的 `pto_source` 与 provenance 测试)。 +- 发布 manifest(`spec/release-manifest.json`)自身记为 + `specification_status: draft`,并把 implementation conformance 限定为 + `b-fpatr-and-tcvt-e8m0-asl-proven-other-numeric-domains-unproven`;本页据此 + 不宣称该规范已最终定稿或全部数值域已证明。119 个操作的 Tile catalog 与 PTO 0.58.7 + development golden 逐字节一致(SHA-256 `533db9b8…`),因此 `TLEA` 等条目在两者之间保持一致, + 只是 encoding identity 移到了发布版本。 +- 语义 authority 仍是 LinxISA v0.58 profile(无 0.59 profile)与 PTO ASL/NDF: + engine-ops 投影保留真实 LinxISA v0.58 来源,并在 `pto_source.development_lock` + 记录其曾锁定的 PTO development golden,不把旧来源伪标为 v0.59。 - backend 能力必须分别判断:CPU simulator/JCORE wrapper、LLVM MC assembler/parser、LLVM compiler lowering 以及 AArch64/SME 并不是同一个状态。 + `TLEA` 目前只有 JCORE inline-asm RowMajor wrapper,没有 CPU simulator 语义。 - `TEXPDIF` 当前已有 CPU simulator 实现、JCORE inline-asm wrapper 和 LLVM MC catalog 条目;LLVM compiler lowering 尚未完成,因此当前不能宣称 LLVM 端到端支持。 diff --git a/docs/tileop-usage/tile-scalar-and-immediate/arithmetic/TLEA.md b/docs/tileop-usage/tile-scalar-and-immediate/arithmetic/TLEA.md new file mode 100644 index 00000000..f0384d96 --- /dev/null +++ b/docs/tileop-usage/tile-scalar-and-immediate/arithmetic/TLEA.md @@ -0,0 +1,109 @@ +# TLEA + +`TLEA` 将 Local 的逻辑元素索引扩展为 64 位,并按 `element_bits / 8` 显式缩放为字节偏移; +它只生成字节偏移,不加 BaseGPR、不访存、不产生内存事件、也不更新 numeric status。 + +> 规范权威:`PTO-ISA/pto-spec` 的 +> `asl/tile/tile-scalar-and-immediate/arithmetic/TLEA.asl` 与 +> `asl/tile/model/legality/lea-operands.asl`。本页是 wrapper 使用说明,不替代 ASL/NDF。 + +## C++ 接口 + +当前 API 中可用的调用形式: + +```cpp +template +void TLEA(tile_shape_out &dst, tile_shape_in &src, unsigned element_bits); +``` + +- 编码:TEPL Mode 1 / Function 14,selector `0x02E`(46),执行引擎 **VEC**。 +- `src`:持久化 Local 索引 Tile,operation type 必须恰为 `S32`、`U32`、`S64` 或 `U64`, + 且选定 operation type 等于其 backing type。 +- `dst`:新的 Local byte-offset Tile;有符号源对应 `S64`,无符号源对应 `U64` + (裸 64 位整型不足以满足该配对)。 +- `element_bits`:per-PE private-GPR 标量,表示元素宽度(bit 数,不是字节数)。 + 其运行时合法值为 `8/16/32/64`,由指令 legality 检查;`0`(硬件零寄存器)是非法宽度。 + +### 支持的数据类型 + +支持索引 Tile 类型 `S32`、`U32`、`S64`、`U64`;目标 Tile 类型为对应的 `S64`/`U64`。 + +| 操作数角色 | 类型要求 | +| --- | --- | +| `src`(索引) | `S32`/`U32`/`S64`/`U64`,operation type 等于 backing type。 | +| `dst`(字节偏移) | 有符号源 → `S64`;无符号源 → `U64`。 | +| `element_bits`(标量) | 每 PE 的元素位宽,运行时取值 `8/16/32/64`。 | + +## 使用要求 + +- `src` 与 `dst` 必须是 `Location::Vec`(持久化 Local)Tile; +- `src` 与 `dst` 的逻辑 valid shape 必须相同,物理 geometry/capacity 可以独立; +- 符号性配对(signed→S64,unsigned→U64)必须成立,不能只检查目标是任意 64 位整型; +- 参数顺序必须与接口声明一致,不要添加接口未声明的操作数。 + +## 约束 + +- 仅 `RowMajor` 与 `CUBE_M32` 是合法 layout;`Shared`、`CUBE_N8`、`CUBE_M16` 一律拒绝。 + 本仓库 wrapper 目前只发射 `RowMajor` 形式,对 `CUBE_M32` 以编译期约束 fail closed + (issue #371 double-CELL b64 映射尚待在 Linx 工具链上对照发布 ASL 验证)。 +- 有符号索引 sign-extend 到 S64、无符号索引 zero-extend 到 U64,再乘以 `element_bits / 8`, + 保留低 64 位,不做饱和、不产生 overflow fault。 +- `PE_MASK=0000` 在读取、分配和 fault 之前是严格 no-op。 +- bundle 必须是一条终结的 Local `B.IOT`(一个索引源加重命名目标)加一条必需的 + `B.IOR`(在 `RegSrc0` 绑定 element width);未使用的 selector/目标编码为零。 + +### 有效区域与 padding + +| 项目 | 规则 | +| --- | --- | +| 有效元素 | 仅对 `src`/`dst` 共同的逻辑 valid shape 定义结果;物理 padding 不是有效数据。 | +| 物理容量 / SizeCode | 只决定容量,不重新定义逻辑 shape;源与目标容量可独立。 | +| 输出 padding | 目标物理区域中有效区以外的填充遵循 `B.DATR` 的 pad-value 约定,不可依赖未声明状态。 | + +## 异常和边界行为 + +非法索引类型、非法 element width、非法 layout、descriptor/schema 不匹配或逻辑 shape 不一致, +会在效果发生前被拒绝;目标容量不足走 `Fault_TileAllocation`。TLEA 不引入 overflow、 +访存或 numeric-status fault。合法性/分配 preflight 和源快照先于目标的原子发布;直接 +`S64`/`U64` 别名会读取旧的源 payload。 + +## 后端能力 + +- JCORE inline-asm wrapper:本仓库已实现(仅 `RowMajor`)。 +- CPU simulator:未实现。 +- AArch64/SME:未实现。 +- LLVM MC / compiler lowering:分别判断,不因 wrapper 存在而推断端到端支持。 + +详见[统一支持状态表](../../support-status.md)。 + +## Bundle 组成 + +开发者通常直接调用 C++ 接口,无需手工编写 bundle。下面保留对应汇编结构供核对: + +```asm +BSTART.VEC TLEA, SrcDataType +B.DATR PadValue, Layout (optional) +B.DIM LB0=ValidCol +B.DIM LB1=ValidRow (optional) +B.DIM LB2=DstCol (optional) +B.IOT IndexTile, mask=PE_MASK, last, ->ByteOffsetTile +B.IOR ElementBitsGPR, zero, zero, ->zero +BSTOP +``` + +## 使用示例 + +```cpp +#include + +using namespace pto; +// 源是 Local S32 元素索引;目标是对应的 Local S64 字节偏移(同一逻辑 valid shape)。 +using IndexTile = Tile; +using OffsetTile = Tile; +IndexTile indices; +OffsetTile offsets; +// 每个张量元素 4 字节 (S32/FP32) 时,element_bits = 32。 +TLEA(offsets, indices, 32u); +``` + +无符号索引改用 `uint32_t`/`uint64_t` 源并配 `uint64_t` 目标;`element_bits` 按实际元素位宽取 `8/16/32/64`。 diff --git a/include/common/pto_tileop_api_revision.hpp b/include/common/pto_tileop_api_revision.hpp index 0cf926a1..4d5f3a4d 100644 --- a/include/common/pto_tileop_api_revision.hpp +++ b/include/common/pto_tileop_api_revision.hpp @@ -1,8 +1,8 @@ #ifndef PTO_TILEOP_API_REVISION_HPP #define PTO_TILEOP_API_REVISION_HPP -#define PTO_TILEOP_API_VERSION "0.58.7" -#define PTO_TILEOP_API_SPEC_VERSION "0.58.7" +#define PTO_TILEOP_API_VERSION "0.59.0" +#define PTO_TILEOP_API_SPEC_VERSION "0.59.0" // Source-tree consumers do not necessarily build from a Git checkout. The // install target replaces these two macros with the exact checked-out commit. diff --git a/include/jcore/template_asm.hpp b/include/jcore/template_asm.hpp index 6096ed28..6108ee35 100644 --- a/include/jcore/template_asm.hpp +++ b/include/jcore/template_asm.hpp @@ -593,6 +593,138 @@ PTO_SHARED_INLINE void TMOV(Tile &dst, [ElemLayout] "i"(local_layout_code_v)); } +// TLEA: extend Local element indices to 64-bit byte offsets. +// +// PTO-TILE-TLEA (asl/tile/tile-scalar-and-immediate/arithmetic/TLEA.asl, +// asl/tile/model/legality/lea-operands.asl): TEPL Mode 1 Function 14, selector +// 0x02E (=46), VEC engine. The source is a persistent Local S32/U32/S64/U64 +// element-index Tile; the required per-PE private-GPR scalar is the element +// width in bits (8/16/32/64, checked at instruction legality, not here); the +// destination is a NEW Local S64 (signed source) or U64 (unsigned source) +// byte-offset Tile with the same logical valid shape but independent physical +// geometry. Signed indices sign-extend to S64 and unsigned indices zero-extend +// to U64 before scaling by element_bits/8, retaining the low 64 bits. TLEA +// produces byte offsets only: no BaseGPR add, no memory access, no memory +// event and no numeric-status update. Shared/CUBE_N8/CUBE_M16 reject; RowMajor +// and CUBE_M32 are the legal layouts. This wrapper emits the RowMajor form and +// fails closed on CUBE_M32, whose issue #371 double-CELL b64 mapping is not yet +// implemented here (use the RowMajor form until it is verified against the +// release ASL on the Linx toolchain). +template +void TLEA(tile_shape_out &dst, tile_shape_in &src, unsigned element_bits) { + using InT = typename tile_shape_in::DType; + using OutT = typename tile_shape_out::DType; + constexpr int in_code = type_traits::TypeCode; + constexpr int out_code = type_traits::TypeCode; + static_assert(tile_shape_in::Loc == Location::Vec && + tile_shape_out::Loc == Location::Vec, + "TLEA source and destination must be persistent Local (Vec) " + "Tiles"); + static_assert(in_code == __type_int32 || in_code == __type_uint32 || + in_code == __type_int64 || in_code == __type_uint64, + "TLEA source operation type must be exactly S32, U32, S64 or " + "U64 element indices"); + constexpr bool in_signed = + (in_code == __type_int32 || in_code == __type_int64); + static_assert((in_signed && out_code == __type_int64) || + (!in_signed && out_code == __type_uint64), + "TLEA destination must be S64 for signed indices and U64 for " + "unsigned indices; a bare 64-bit integer is not sufficient"); + static_assert(tile_shape_in::BFractal == tile_shape_out::BFractal, + "TLEA source and destination must share one Local layout"); + static_assert(tile_shape_in::BFractal == BLayout::RowMajor, + "TLEA wrapper currently emits the RowMajor form only; CUBE_M32 " + "is specified but not yet implemented, and Shared/CUBE_N8/" + "CUBE_M16 reject per PTO-TILE-TLEA"); + // Matching logical valid shape with independent physical geometry/capacity. + static_assert((tile_shape_in::ValidCol < 0) == (tile_shape_out::ValidCol < 0) && + (tile_shape_in::ValidRow < 0) == (tile_shape_out::ValidRow < 0), + "TLEA source and destination must share a static-or-dynamic " + "valid shape"); + if constexpr (tile_shape_in::ValidCol > 0 && tile_shape_out::ValidCol > 0) { + static_assert(tile_shape_in::ValidCol == tile_shape_out::ValidCol, + "TLEA source and destination must have equal ValidCol"); + } + if constexpr (tile_shape_in::ValidRow > 0 && tile_shape_out::ValidRow > 0) { + static_assert(tile_shape_in::ValidRow == tile_shape_out::ValidRow, + "TLEA source and destination must have equal ValidRow"); + } + static_assert((tile_shape_out::ValidRow < 0 || + tile_shape_out::Rows >= tile_shape_out::ValidRow) && + (tile_shape_out::ValidCol < 0 || + tile_shape_out::Cols >= tile_shape_out::ValidCol), + "TLEA destination physical shape must contain its valid region " + "(valid_rows <= rows, valid_columns <= columns)"); + // The element width is a per-PE private GPR; force it into a register so a + // compile-time constant is never folded onto the hardwired zero register, + // which is an illegal element width for an active block. + unsigned element_bits_value = element_bits; + asm("" : "+r"(element_bits_value)); + if constexpr (tile_shape_in::ValidCol > 0 && tile_shape_in::ValidRow > 0) { + asm volatile( + "BSTART.TEPL 46, %D[Type]\n" + "B.DIM zero, %c[Col], ->lb0\n" + "B.DIM zero, %c[Row], ->lb1\n" + "B.DIM zero, %c[DstCols], ->lb2\n" + "B.IOT %[Src].reuse, mask=1111, last, ->%[Dst]<%Z[TileSize]>\n" + "B.IOR [%[ElementBits]],[]\n" + : [Dst] "=Tr"(dst.data()) + : [Type] "i"(in_code), [Src] "Tr"(src.data()), + [TileSize] "i"(tile_shape_out::TilesizeCode), + [Col] "i"(tile_shape_in::ValidCol), + [Row] "i"(tile_shape_in::ValidRow), + [DstCols] "i"(tile_shape_out::Cols), + [ElementBits] "r"(element_bits_value)); + } else if constexpr (tile_shape_in::ValidCol > 0 && + tile_shape_in::ValidRow < 0) { + asm volatile( + "BSTART.TEPL 46, %D[Type]\n" + "B.DIM zero, %c[Col], ->lb0\n" + "B.DIM %[Row], 0, ->lb1\n" + "B.DIM zero, %c[DstCols], ->lb2\n" + "B.IOT %[Src].reuse, mask=1111, last, ->%[Dst]<%Z[TileSize]>\n" + "B.IOR [%[ElementBits]],[]\n" + : [Dst] "=Tr"(dst.data()) + : [Type] "i"(in_code), [Src] "Tr"(src.data()), + [TileSize] "i"(tile_shape_out::TilesizeCode), + [Col] "i"(tile_shape_in::ValidCol), + [Row] "r"(src.GetValidRow()), + [DstCols] "i"(tile_shape_out::Cols), + [ElementBits] "r"(element_bits_value)); + } else if constexpr (tile_shape_in::ValidCol < 0 && + tile_shape_in::ValidRow > 0) { + asm volatile( + "BSTART.TEPL 46, %D[Type]\n" + "B.DIM %[Col], 0, ->lb0\n" + "B.DIM zero, %c[Row], ->lb1\n" + "B.DIM zero, %c[DstCols], ->lb2\n" + "B.IOT %[Src].reuse, mask=1111, last, ->%[Dst]<%Z[TileSize]>\n" + "B.IOR [%[ElementBits]],[]\n" + : [Dst] "=Tr"(dst.data()) + : [Type] "i"(in_code), [Src] "Tr"(src.data()), + [TileSize] "i"(tile_shape_out::TilesizeCode), + [Col] "r"(src.GetValidCol()), + [Row] "i"(tile_shape_in::ValidRow), + [DstCols] "i"(tile_shape_out::Cols), + [ElementBits] "r"(element_bits_value)); + } else { + asm volatile( + "BSTART.TEPL 46, %D[Type]\n" + "B.DIM %[Col], 0, ->lb0\n" + "B.DIM %[Row], 0, ->lb1\n" + "B.DIM zero, %c[DstCols], ->lb2\n" + "B.IOT %[Src].reuse, mask=1111, last, ->%[Dst]<%Z[TileSize]>\n" + "B.IOR [%[ElementBits]],[]\n" + : [Dst] "=Tr"(dst.data()) + : [Type] "i"(in_code), [Src] "Tr"(src.data()), + [TileSize] "i"(tile_shape_out::TilesizeCode), + [Col] "r"(src.GetValidCol()), + [Row] "r"(src.GetValidRow()), + [DstCols] "i"(tile_shape_out::Cols), + [ElementBits] "r"(element_bits_value)); + } +} + template void THISTOGRAM(tile_shape_out &dst, tile_shape_in &src, tile_shape_in &Idx, int ByteId) { static_assert(pto_dependent_false_v, diff --git a/test/test_v058_engine_contract.py b/test/test_v058_engine_contract.py index 38689839..1ed32e11 100644 --- a/test/test_v058_engine_contract.py +++ b/test/test_v058_engine_contract.py @@ -1,5 +1,8 @@ #!/usr/bin/env python3 -# PTO ISA 0.58.7 development engine-contract tests for the jcore inline-asm surface. +# Engine-contract tests for the jcore inline-asm surface. The semantic engine +# inventory is the LinxISA v0.58 authority projection; the active PTO encoding +# identity is the published PTO ISA 0.59.0.0 release (see +# test_contract_carries_release_provenance). # # Rebuilt per handoff Work Package B6: the assertions reflect the current # real toolchain ABI (Tr Tile constraints + %Z TileSize printer; the %q/%D @@ -54,9 +57,9 @@ def _active_impl(self) -> str: if path.is_file() ) - # --- catalog/development-golden provenance --- + # --- catalog/release provenance --- - def test_contract_carries_development_golden_provenance(self) -> None: + def test_contract_carries_release_provenance(self) -> None: self.assertEqual(self.contract["profile"], "v0.58") self.assertEqual( self.contract["semantic_engine_counts"], @@ -74,21 +77,45 @@ def test_contract_carries_development_golden_provenance(self) -> None: src.get("sha256"), "51ca9be275518d29ec48bed570b7a9bd441a65b9c5e6d4f79072f650ee732925", ) + # The active PTO encoding identity is the published 0.59.0.0 release. pto = self.contract.get("pto_source", {}) - self.assertEqual(pto.get("release"), "0.58.7") - self.assertEqual(pto.get("status"), "development-not-published") - self.assertIsNone(pto.get("publication")) + self.assertEqual(pto.get("release"), "0.59.0") + self.assertEqual(pto.get("publication_version"), "0.59.0.0") + self.assertEqual(pto.get("release_tag"), "v0.59.0.0") + # The release manifest is itself still a draft specification; record + # that faithfully rather than claiming a finalized specification. + self.assertEqual(pto.get("specification_status"), "draft") self.assertEqual( - pto.get("commit"), "f0a876e449a95d26841c5ee7affb4c905ebc5f5b" + pto.get("commit"), "b0165320a4b575b18d2f4d93faf40178f661ab49" ) self.assertEqual( - pto.get("tree"), "fe9e8e050375fbce3f526d08acca13c37cd15830" + pto.get("tree"), "31ff0c2d39cbed714baf5be7929bfd06887be9fb" + ) + self.assertEqual( + pto.get("encoding_abi"), "pto-isa-0.59.0-mode-function-v1" ) self.assertEqual( pto.get("encoding_projection_sha256"), - "a5f78ecd707bde4a014542158ea257c783796b95fa4fbcce37742e41fee6a881", + "91509080ca656eb124f47830dcb09c50389dc177266b3b8df9d2d11dc37d5697", + ) + self.assertEqual( + pto.get("release_manifest", {}).get("sha256"), + "3c6b20623e73822c0bd26021c10beb233b8809328b5515f57609eadad1749dc4", ) self.assertEqual(pto.get("tile_catalog", {}).get("count"), 119) + self.assertEqual( + pto.get("tile_catalog", {}).get("sha256"), + "533db9b8f31f118af5978de813cfaa3fa738de820ee24655faa2ee71f343a706", + ) + # The LinxISA v0.58 authority locked the PTO development golden; its + # Tile catalog bytes equal the release catalog, which is why this v0.58 + # engine projection is valid against the 0.59.0.0 release. + lock = pto.get("development_lock", {}) + self.assertEqual(lock.get("release"), "0.58.7") + self.assertEqual( + lock.get("commit"), "f0a876e449a95d26841c5ee7affb4c905ebc5f5b" + ) + self.assertTrue(lock.get("catalog_sha256_matches_release")) def test_0587_engine_mapping_is_exact(self) -> None: engines = {row["name"]: row["engine"] for row in self.contract["tepl_ops"]} @@ -103,7 +130,7 @@ def test_0587_engine_mapping_is_exact(self) -> None: def test_engine_projection_covers_the_exact_pto_catalog(self) -> None: catalog = json.loads( - (ROOT / "contracts" / "pto-isa-0.58.7-tile-operations.json").read_text( + (ROOT / "contracts" / "pto-isa-0.59.0-tile-operations.json").read_text( encoding="utf-8" ) ) @@ -1050,9 +1077,11 @@ def test_shared_tmov_uses_unique_source_forms_and_shared_registers(self) -> None def test_deleted_tile_operations_are_migration_stubs(self) -> None: # Every deleted tile operation either has no wrapper (truly absent) # or is an instance-time static_assert stub; in no case is a - # retired TEPL selector emitted by an asm block. TFMOD (5), TLRELU - # (46), TRANDOM (105) etc. must not appear next to BSTART.TEPL. - for sel in (5, 14, 24, 25, 37, 46, 47, 56, 57, 96, 97, 105, 110): + # retired TEPL selector emitted by an asm block. TFMOD (5), TRANDOM + # (105) etc. must not appear next to BSTART.TEPL. Selector 46 (0x2E) is + # deliberately NOT in this list: the current catalog reassigns it from + # the retired TLRELU to the active TLEA (see the dedicated TLEA test). + for sel in (5, 14, 24, 25, 37, 47, 56, 57, 96, 97, 105, 110): self.assertNotRegex( self.header, rf'BSTART\.TEPL\s+{sel},', @@ -1074,6 +1103,80 @@ def test_deleted_tile_operations_are_migration_stubs(self) -> None: f"stale named TEPL alias {name} must not be emitted", ) + def test_tlea_wrapper_matches_release_catalog_and_asl(self) -> None: + # TLEA is an active 0.59.0.0 catalog operation (TEPL Mode 1 Function 14, + # selector 0x02E = 46, VEC engine) that extends Local index Tiles to + # 64-bit byte offsets. The JCORE inline-asm wrapper must exist, carry + # the ASL legality constraints, and emit the selector-46 byte-offset + # bundle; catalog existence alone is not wrapper support. + catalog = json.loads( + (ROOT / "contracts" / "pto-isa-0.59.0-tile-operations.json").read_text( + encoding="utf-8" + ) + ) + tlea = next(op for op in catalog["operations"] if op["name"] == "TLEA") + self.assertEqual(tlea["selector"], "0x02E") + self.assertEqual(tlea["mode"], 1) + self.assertEqual(tlea["function"], 14) + self.assertEqual(tlea["engine"], "VEC") + self.assertEqual(tlea["disposition"], "accepted-direct-operation") + projected = next( + row for row in self.contract["tepl_ops"] if row["name"] == "TLEA" + ) + self.assertEqual(projected["logical_selector"], 46) + self.assertEqual(projected["mode"], 1) + self.assertEqual(projected["function"], 14) + self.assertEqual(projected["engine"], "VEC") + + match = re.search(r"void TLEA\(.*?\n}\n", self.header, re.S) + self.assertIsNotNone(match, "TLEA JCORE wrapper is missing") + body = match.group(0) + # Selector-46 byte-offset bundle with the required per-PE element-width + # B.IOR; the index source is an explicit-reuse terminating binder and + # the destination is a new allocating Tile (never written .reuse). + self.assertIn('"BSTART.TEPL 46, %D[Type]\\n"', body) + self.assertIn("B.IOR [%[ElementBits]],[]", body) + self.assertRegex( + body, r'B\.IOT %\[Src\]\.reuse, mask=1111, last, ->%\[Dst\]<%Z\[TileSize\]>' + ) + # ASL legality carried as compile-time constraints. + self.assertIn("Location::Vec", body) + self.assertIn("__type_int32", body) + self.assertIn("__type_uint32", body) + self.assertIn("__type_int64", body) + self.assertIn("__type_uint64", body) + self.assertIn("S64 for signed indices and U64 for", body) + self.assertIn("BLayout::RowMajor", body) + self.assertIn("equal ValidCol", body) + self.assertIn("equal ValidRow", body) + # TLEA produces byte offsets only: no GM base-address B.IOR binder. + self.assertNotRegex(body, r'B\.IOR \[%\[Base') + + def test_tlea_backend_capability_is_not_overclaimed(self) -> None: + # The JCORE inline-asm wrapper exists, but the TileOP repository has no + # TLEA CPU simulator semantics. The support-status page must keep those + # backend dimensions separate and must not silently widen the wrapper + # into full-backend support. + status = (ROOT / "docs" / "tileop-usage" / "support-status.md").read_text( + encoding="utf-8" + ) + self.assertRegex(status, r"`TLEA`") + self.assertIn("JCORE inline-asm", status) + self.assertIn("CPU simulator", status) + # No TLEA implementation may masquerade inside the CPU simulator headers. + cpu_sim = ROOT / "include" / "cpu_sim" + if cpu_sim.is_dir(): + cpu_text = "\n".join( + p.read_text(encoding="utf-8", errors="ignore") + for p in cpu_sim.rglob("*") + if p.is_file() + ) + self.assertNotRegex( + cpu_text, + r"\bTLEA\b", + "TLEA must not claim a CPU simulator implementation it lacks", + ) + def test_retired_block_spellings_are_not_emitted(self) -> None: impl = self._active_impl() for spelling in ( @@ -1213,10 +1316,10 @@ def test_compile_all_aggregates_active_object_failures(self) -> None: def test_pto_identity_verifier_rejects_hostile_elf_notes(self) -> None: verifier = ROOT / "test" / "tileop_api" / "verify_pto_identity.py" expected = ( - b'{"encoding_abi":"pto-isa-0.58.7-mode-function-v1",' + b'{"encoding_abi":"pto-isa-0.59.0-mode-function-v1",' b'"encoding_projection_sha256":' - b'"a5f78ecd707bde4a014542158ea257c783796b95fa4fbcce37742e41fee6a881",' - b'"release":"0.58.7"}' + b'"91509080ca656eb124f47830dcb09c50389dc177266b3b8df9d2d11dc37d5697",' + b'"release":"0.59.0"}' ) def make_elf(desc: bytes = expected, owner: bytes = b"PTO\0", @@ -1273,11 +1376,11 @@ def make_note(note_desc: bytes) -> bytes: "missing": make_elf(owner=b"GNU\0"), "corrupt": make_elf(magic=b"BAD!"), "wrong-machine": make_elf(machine=0x3E), - "wrong-identity": make_elf(desc=expected.replace(b"0.58.7", b"0.58.6")), + "wrong-identity": make_elf(desc=expected.replace(b"0.59.0", b"0.59.1")), "trailing-nul": make_elf(desc=expected + b"\0"), "duplicate-segment": make_elf(extra_desc=expected), "conflicting-segment": make_elf( - extra_desc=expected.replace(b"0.58.7", b"0.58.6")), + extra_desc=expected.replace(b"0.59.0", b"0.59.1")), } for name, contents in variants.items(): path = temporary_path / f"{name}.elf" diff --git a/test/test_version_header.py b/test/test_version_header.py index e61a9e7e..3c8f1c24 100644 --- a/test/test_version_header.py +++ b/test/test_version_header.py @@ -13,8 +13,8 @@ class TileOpApiVersionHeaderTest(unittest.TestCase): def test_source_header_exposes_version_and_feature(self): header = SOURCE_HEADER.read_text(encoding="utf-8") - self.assertIn('#define PTO_TILEOP_API_VERSION "0.58.7"', header) - self.assertIn('#define PTO_TILEOP_API_SPEC_VERSION "0.58.7"', header) + self.assertIn('#define PTO_TILEOP_API_VERSION "0.59.0"', header) + self.assertIn('#define PTO_TILEOP_API_SPEC_VERSION "0.59.0"', header) self.assertIn('#define PTO_TILEOP_API_REVISION "source-tree"', header) self.assertIn('#define PTO_TILEOP_API_REVISION_IS_EXACT 0', header) self.assertIn('#define PTO_TILEOP_API_HAS_LOCAL_B_KN_FIX 1', header) diff --git a/test/tileop_api/compile.all b/test/tileop_api/compile.all index 4b36ec30..6eef8b62 100755 --- a/test/tileop_api/compile.all +++ b/test/tileop_api/compile.all @@ -29,7 +29,7 @@ ACTIVE_FIXTURES=( SharedTransposeNonSquare MatrixIntegerDtypes MXScaleVariants HiF4X2MatmulMX SharedMatmul TMatmulAccFullOptions TMatmulAccCScale TMatmulAllOptions TGEMVAllOptions TGEMVOperandOrder PostProcessCombos SharedMatrixForms TCmpMode TColSumContract TSort TPrefetch MGatherCas MGatherAtomics MScatterAtomics - TMrgSort TQuant TImg2Col GroupMatmul TStoreShared SharedTLoad TAbs + TMrgSort TQuant TImg2Col GroupMatmul TStoreShared SharedTLoad TAbs Tlea DirectCubeLayout TileRegionBinaryMixed Issue166RmsNormB128 Issue269ReductionCapacity Issue272PackPrefix Issue274PackViews Issue275PackAssemble Issue276ReinterpretMul TCvtSameTypeRounding TAdd_mask TAdd TAdds TAnd TeplAss TeplAssSpecial TOrAssSubview TLoad TStore TCvt TDiv TDivs TExp TExpdif TMax TMaxs RangeSubview RangeAssemble SharedRange TileRegionSharedSubview TileArray TileArrayCube TileArrayAssemblyOffsets TileArrayRegionAsm TileArrayTCVTE8M0 TileArrayWriterSize TileRegionUnaryAssembly TileRegion TileRegionUnary TileRegionBinary TileRegionBinaryAssembly TileRegionUnarySubviewAssembly TileRegionScalarAssembly TileRegionTCVTSubviewAssembly TileRegionTCVTSubview TileRegionShift TileRegionCubeSubview SubviewVecCube Issue138Subview Issue160ReductionPrefix Issue241ReductionPrefixBinary Issue187DynamicPrefix Issue178CubeTcvtNorm Issue195ConvCompose Issue194Timg2colNchw SubviewVecCubeIssue144 diff --git a/test/tileop_api/run_negatives.sh b/test/tileop_api/run_negatives.sh index 4cd42a00..061b2a98 100755 --- a/test/tileop_api/run_negatives.sh +++ b/test/tileop_api/run_negatives.sh @@ -50,6 +50,7 @@ TEXPDIF_CASES="type narrow n8 mixed_layout shape" TCI2D_CASES="layout location dtype shape steps m16_rows" I64_CASES="fp64_element unsupported_parent m16 short_m32 subview_pair assemble_pair writer_limit" TCOLSUM_CASES="dest_rows dest_cols dtype" +TLEA_CASES="bad_dtype dest_32bit signed_to_u64 unsigned_to_s64 shape_col shape_row cube_m32 location" PASS=0; FAIL=0 # A negative suite is meaningless when every compile is rejected before the @@ -110,6 +111,25 @@ for c in $TCOLSUM_CASES; do done expect_rejected "thistogram_retired" "SHOULD_FAIL_THISTOGRAM_RETIRED" \ TColSumNegatives.cpp "THISTOGRAM is retired" +# TLEA (PTO-TILE-TLEA): index/signedness/shape/layout/location legality is +# carried as compile-time constraints; each case must hit its static_assert. +if ! "$CXX" "${FLAGS[@]}" src/Tlea.cpp -o "$OUT/Tlea.o" >/dev/null 2>&1; then + echo "BLOCKED: TLEA positive negative-suite preflight failed" >&2 + exit 2 +fi +for c in $TLEA_CASES; do + define=SHOULD_FAIL_TLEA_$(echo "$c" | tr '[:lower:]' '[:upper:]') + case "$c" in + bad_dtype) pattern='TLEA source operation type must be exactly' ;; + dest_32bit|signed_to_u64|unsigned_to_s64) + pattern='S64 for signed indices and U64' ;; + shape_col) pattern='equal ValidCol' ;; + shape_row) pattern='equal ValidRow' ;; + cube_m32) pattern='RowMajor form only' ;; + location) pattern='persistent Local \(Vec\)' ;; + esac + expect_rejected "tlea_$c" "$define" TleaNegatives.cpp "$pattern" +done for c in $TS_CASES; do if "$CXX" "${FLAGS[@]}" -DSHOULD_FAIL_$c src/TStoreSharedNegatives.cpp \ -o "$OUT/neg_ts_$c.o" >/dev/null 2>&1; then diff --git a/test/tileop_api/src/Tlea.cpp b/test/tileop_api/src/Tlea.cpp new file mode 100644 index 00000000..936de9cf --- /dev/null +++ b/test/tileop_api/src/Tlea.cpp @@ -0,0 +1,49 @@ +#include + +// Positive TLEA fixtures (PTO-TILE-TLEA, selector 0x02E, VEC engine). +// Compiled with the Linx target compiler by test/tileop_api/compile.all. +// TLEA extends Local S32/U32/S64/U64 element indices to 64-bit byte offsets +// scaled by element_bits/8, writing a new Local S64 (signed) or U64 (unsigned) +// destination with the same logical valid shape and independent physical +// geometry. The wrapper emits the RowMajor form. + +using namespace pto; + +template +using Vec = Tile; + +// Signed source -> S64 byte-offset destination (4-byte element stride). +void tlea_s32_to_s64(Vec &idx, Vec &off) { + TLEA(off, idx, 32u); +} + +// Unsigned source -> U64 byte-offset destination. +void tlea_u32_to_u64(Vec &idx, Vec &off) { + TLEA(off, idx, 32u); +} + +// 64-bit index forms, 8-byte element stride. +void tlea_s64_to_s64(Vec &idx, Vec &off) { + TLEA(off, idx, 64u); +} + +void tlea_u64_to_u64(Vec &idx, Vec &off) { + TLEA(off, idx, 64u); +} + +// Independent physical capacity: source and destination share one logical +// valid shape (8 x 32) while the destination has a wider physical column. +void tlea_independent_capacity( + Vec &idx, + Tile &off) { + TLEA(off, idx, 16u); +} + +// Dynamic valid shape on both operands (runtime ValidCol/ValidRow). +void tlea_dynamic_shape( + Tile &idx, + Tile &off) { + TLEA(off, idx, 32u); +} + +int main() { return 0; } diff --git a/test/tileop_api/src/TleaNegatives.cpp b/test/tileop_api/src/TleaNegatives.cpp new file mode 100644 index 00000000..e0a910de --- /dev/null +++ b/test/tileop_api/src/TleaNegatives.cpp @@ -0,0 +1,54 @@ +#include + +// Negative TLEA fixtures: each -DSHOULD_FAIL_TLEA_ must be rejected at +// compile time by the intended static_assert (or concept), not by an +// unrelated parse/toolchain error. Driven by test/tileop_api/run_negatives.sh. + +using namespace pto; + +template +using Vec = Tile; + +#if defined(SHOULD_FAIL_TLEA_BAD_DTYPE) +// FP32 is not an S32/U32/S64/U64 element index. +void reject() { Vec idx; Vec off; TLEA(off, idx, 32u); } +#elif defined(SHOULD_FAIL_TLEA_DEST_32BIT) +// A 32-bit destination cannot hold a 64-bit byte offset. +void reject() { Vec idx; Vec off; TLEA(off, idx, 32u); } +#elif defined(SHOULD_FAIL_TLEA_SIGNED_TO_U64) +// Signed source must pair with an S64 destination, not U64. +void reject() { Vec idx; Vec off; TLEA(off, idx, 32u); } +#elif defined(SHOULD_FAIL_TLEA_UNSIGNED_TO_S64) +// Unsigned source must pair with a U64 destination, not S64. +void reject() { Vec idx; Vec off; TLEA(off, idx, 32u); } +#elif defined(SHOULD_FAIL_TLEA_SHAPE_COL) +// Source and destination must share the same logical ValidCol. +void reject() { + Vec idx; + Tile off; + TLEA(off, idx, 32u); +} +#elif defined(SHOULD_FAIL_TLEA_SHAPE_ROW) +// Source and destination must share the same logical ValidRow. +void reject() { + Vec idx; + Tile off; + TLEA(off, idx, 32u); +} +#elif defined(SHOULD_FAIL_TLEA_CUBE_M32) +// CUBE_M32 is a legal ISA layout but is not yet implemented by this wrapper. +void reject() { + Tile idx, off; + TLEA(off, idx, 32u); +} +#elif defined(SHOULD_FAIL_TLEA_LOCATION) +// Source and destination must be persistent Local (Vec) tiles. +void reject() { + Tile idx; + Vec off; + TLEA(off, idx, 32u); +} +#endif + +int main() { return 0; } diff --git a/test/tileop_api/verify_pto_identity.py b/test/tileop_api/verify_pto_identity.py index 2f7b52da..05a52d0a 100644 --- a/test/tileop_api/verify_pto_identity.py +++ b/test/tileop_api/verify_pto_identity.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -"""Fail-closed validation of the exact PTO 0.58.7 development ELF note.""" +"""Fail-closed validation of the exact PTO 0.59.0 release ELF note.""" from __future__ import annotations @@ -12,10 +12,10 @@ PT_NOTE = 4 SHT_NOTE = 7 EXPECTED_DESC = ( - b'{"encoding_abi":"pto-isa-0.58.7-mode-function-v1",' + b'{"encoding_abi":"pto-isa-0.59.0-mode-function-v1",' b'"encoding_projection_sha256":' - b'"a5f78ecd707bde4a014542158ea257c783796b95fa4fbcce37742e41fee6a881",' - b'"release":"0.58.7"}' + b'"91509080ca656eb124f47830dcb09c50389dc177266b3b8df9d2d11dc37d5697",' + b'"release":"0.59.0"}' ) @@ -138,7 +138,7 @@ def validate(path: Path) -> None: require(not identity_desc.endswith(b"\0"), "PTO JSON must not have a trailing NUL") require(identity_desc == EXPECTED_DESC, - "PTO identity JSON is not the exact 0.58.7 development identity") + "PTO identity JSON is not the exact 0.59.0 release identity") require(len(identities) == 1, "PTO identity must have exactly one note range") @@ -157,7 +157,7 @@ def main(argv: list[str]) -> int: except (OSError, IdentityError, struct.error) as error: print(f"FAIL PTO identity: {error}", file=sys.stderr) return 1 - print("PTO ISA 0.58.7 development ELF identity: PASS") + print("PTO ISA 0.59.0 release ELF identity: PASS") return 0 diff --git a/tools/check_pto_catalog_alignment.py b/tools/check_pto_catalog_alignment.py index 93e35fff..6d2d9e88 100644 --- a/tools/check_pto_catalog_alignment.py +++ b/tools/check_pto_catalog_alignment.py @@ -1,8 +1,11 @@ #!/usr/bin/env python3 -"""Fail-closed checks for the pinned PTO ISA 0.58.7 Tile catalog. +"""Fail-closed checks for the pinned PTO ISA 0.59.0 Tile catalog. This check deliberately verifies inventory and provenance, not the full ASL/NDF -semantics. The latter remains owned by PTO-ISA/pto-spec. +semantics. The latter remains owned by PTO-ISA/pto-spec. The 119-operation Tile +catalog is byte-identical between the PTO 0.58.7 development golden and the +published PTO ISA 0.59.0.0 release (both SHA-256 533db9b8...), so the pinned +bytes did not change when the active encoding identity moved to the release. """ from __future__ import annotations @@ -14,7 +17,7 @@ from pathlib import Path ROOT = Path(__file__).resolve().parents[1] -CATALOG = ROOT / "contracts" / "pto-isa-0.58.7-tile-operations.json" +CATALOG = ROOT / "contracts" / "pto-isa-0.59.0-tile-operations.json" INCLUDE = ROOT / "include" DOCS = ROOT / "docs" / "tileop-usage" EXPECTED_TILE_CATALOG_SHA256 = "533db9b8f31f118af5978de813cfaa3fa738de820ee24655faa2ee71f343a706" @@ -28,7 +31,7 @@ def main() -> int: catalog = json.loads(CATALOG.read_text(encoding="utf-8")) failures: list[str] = [] if hashlib.sha256(CATALOG.read_bytes()).hexdigest() != EXPECTED_TILE_CATALOG_SHA256: - failures.append("catalog bytes do not match the reviewed PTO development golden") + failures.append("catalog bytes do not match the reviewed PTO 0.59.0.0 release Tile catalog") if catalog.get("operation_count") != 119: failures.append("catalog operation_count is not 119") operations = catalog.get("operations", []) @@ -92,13 +95,13 @@ def main() -> int: failures.append(f"TEXPDIF support status is missing backend dimension: {marker}") if failures: - print("FAIL: PTO 0.58.7 catalog alignment", file=sys.stderr) + print("FAIL: PTO 0.59.0 catalog alignment", file=sys.stderr) for failure in failures: print(f" - {failure}", file=sys.stderr) return 1 print( - "PASS: PTO 0.58.7 development catalog alignment " - f"({len(names)} golden operations; {len(source_referenced)} source-referenced; " + "PASS: PTO 0.59.0.0 release catalog alignment " + f"({len(names)} release operations; {len(source_referenced)} source-referenced; " f"{len(explicitly_unsupported)} explicitly unsupported)" ) return 0 diff --git a/tools/generate_engine_docs.py b/tools/generate_engine_docs.py index 8298f0ad..ffa6b434 100644 --- a/tools/generate_engine_docs.py +++ b/tools/generate_engine_docs.py @@ -1,15 +1,17 @@ #!/usr/bin/env python3 """Generate the wrapper engine compatibility view from the pinned projection. -The output mirrors the reviewed PTO ISA 0.58.7 development catalog +The output mirrors the PTO ISA 0.59.0.0 release Tile catalog (spec/catalog/tile-operations.json) for the four architectural engine -classes: **VEC**, **SFU**, **TLSU**, and **CUBE**. Engine and -classification are decoupled (per ADR 0057): TEXP/TLOG/... are SFU-executed -elementwise operations, TGATHER/TSCATTER/TCONCAT are SFU-executed -layout/irregular operations, and TMOV is a TLSU-executed layout operation. -TEPL is the unique compiled carrier identity. `BSTART.VEC` / `BSTART.SFU` are -engine-specific assembly aliases; current inline wrappers retain TEPL so the -same source also compiles with the preceding 0.58 toolchain. +classes: **VEC**, **SFU**, **TLSU**, and **CUBE**. The engine inventory is the +LinxISA v0.58 authority projection; its 119-operation catalog is byte-identical +to the published PTO ISA 0.59.0.0 release. Engine and classification are +decoupled (per ADR 0057): TEXP/TLOG/... are SFU-executed elementwise +operations, TGATHER/TSCATTER/TCONCAT are SFU-executed layout/irregular +operations, and TMOV is a TLSU-executed layout operation. TEPL is the unique +compiled carrier identity. `BSTART.VEC` / `BSTART.SFU` are engine-specific +assembly aliases; current inline wrappers retain TEPL so the same source also +compiles with the preceding 0.58 toolchain. """ from __future__ import annotations @@ -47,16 +49,17 @@ def wrapper_status(name: str) -> str: source_referenced = sum(wrapper_status(name).startswith("源码有引用") for name in operation_names) lines = [ - "# LinxISA / PTO ISA v0.58.7 wrapper engine compatibility view", + "# LinxISA v0.58 / PTO ISA 0.59.0.0 wrapper engine compatibility view", "", "架构定义的引擎类别只有 **VEC**, **TLSU**, **CUBE**, and **SFU**。", "VEC 只包含逐元素操作;SFU 包含归约、广播、变换、排序以及其他需要更复杂硬件的操作。", "TEPL 仍是唯一的编译 carrier 标识。`BSTART.VEC` 和 `BSTART.SFU` 是特定引擎的汇编别名;", "inline wrapper 保留 `BSTART.TEPL`,以兼容之前的工具链源码。", "", - "下表根据本仓库固定的 LinxISA/PTO development golden 投影生成,数据记录在", + "下表根据本仓库固定的 LinxISA v0.58 authority 投影生成(其操作清单与 PTO ISA 0.59.0.0", + "发布 catalog 逐字节一致),数据记录在", "[`contracts/linxisa-v0.58-engine-ops.json`](../../../contracts/linxisa-v0.58-engine-ops.json) 中。", - f"Golden 共 {len(operation_names)} 项;其中 {source_referenced} 项在 `include/` 有名称引用,", + f"投影共 {len(operation_names)} 项;其中 {source_referenced} 项在 `include/` 有名称引用,", f"{len(operation_names) - source_referenced} 项明确没有 wrapper。名称引用不证明 ASL/NDF 语义完整实现。", "", ] @@ -103,8 +106,9 @@ def wrapper_status(name: str) -> str: [ "## 分类语义", "", - "PTO ISA 0.58.7 将执行引擎与操作分类解耦。本表是 wrapper compatibility view;", - "其底层投影记录当前 development golden selector 数据。`elementwise-tile-tile`", + "PTO ISA 0.59.0 将执行引擎与操作分类解耦。本表是 wrapper compatibility view;", + "其底层投影记录 LinxISA v0.58 authority 的 selector 数据(与 0.59.0.0 发布 catalog 一致)。", + "`elementwise-tile-tile`", "和 `tile-scalar-and-immediate` 类别在 VEC 上执行逐元素操作,但其中的", "`TEXP`、`TLOG`、`TRECIP`、`TSQRT`、`TRSQRT` 由 SFU 执行。", "`reduce-and-expand`、`layout-and-rearrangement` 和 `irregular-and-complex` 类别由 SFU 执行。", @@ -120,7 +124,7 @@ def wrapper_status(name: str) -> str: [ "## 早期版本中移除的操作", "", - "历史版本还提供了一些已从 PTO 0.58.7 active catalog 移除的 Tile 操作(例如 ACC 风格的后处理辅助操作)。", + "历史版本还提供了一些已从 PTO 0.59.0 active catalog 移除的 Tile 操作(例如 ACC 风格的后处理辅助操作)。", "本库不会把已退役的操作生成到当前目录;退役名称的规范列表记录在 contract 的 `deleted_tile_names` 字段中。", "", ] diff --git a/tools/generate_tileop_usage_docs.py b/tools/generate_tileop_usage_docs.py index 7b10c78d..11f10b92 100644 --- a/tools/generate_tileop_usage_docs.py +++ b/tools/generate_tileop_usage_docs.py @@ -15,7 +15,7 @@ DOC_ROOT = ROOT / "docs/tileop-usage" SPEC_DOC_ROOT = SPEC_ROOT / "docs/tile" ASL_ROOT = SPEC_ROOT / "asl/tile" -PTO_SPEC_REF = "v0.58.7" +PTO_SPEC_REF = "v0.59.0.0" # Names used by the TileDataType encoding. Keeping this list here makes the # documentation generator independent of prose wording in individual SPEC diff --git a/tools/sync_linxisa_v058_contract.py b/tools/sync_pto_isa_0590_contract.py similarity index 58% rename from tools/sync_linxisa_v058_contract.py rename to tools/sync_pto_isa_0590_contract.py index f7ffe827..1a340251 100644 --- a/tools/sync_linxisa_v058_contract.py +++ b/tools/sync_pto_isa_0590_contract.py @@ -1,5 +1,24 @@ #!/usr/bin/env python3 -"""Project the reviewed LinxISA and PTO development golden into this API.""" +"""Project the reviewed LinxISA v0.58 authority and the published PTO ISA +0.59.0.0 release into this API. + +Provenance model +---------------- +* The LinxISA v0.58 authority is unchanged: it still owns the semantic engine + projection (VEC/SFU/TLSU/CUBE operation inventory and selectors) and it + locked the PTO *development* golden through ``pto-scalar-proposal.lock.json``. +* The active PTO *encoding identity* (ABI, encoding-projection SHA-256 and ELF + ``release`` field) is the published PTO ISA ``v0.59.0.0`` release, read from a + clean ``spec/release-manifest.json``. +* There is no LinxISA ``0.59`` profile, so this tool does not fabricate one: + the LinxISA ``source`` stays ``v0.58`` and the development-golden lock is + recorded verbatim. The 119-operation Tile catalog is byte-identical between + the development golden and the 0.59.0.0 release (both SHA-256 533db9b8...), + which is what makes the v0.58 engine projection valid against the release. + +The release manifest records ``specification_status: draft``; this tool carries +that status faithfully rather than claiming a finalized specification. +""" from __future__ import annotations @@ -12,19 +31,36 @@ ROOT = Path(__file__).resolve().parents[1] DEFAULT_OUTPUT = ROOT / "contracts" / "linxisa-v0.58-engine-ops.json" -DEFAULT_PTO_OUTPUT = ROOT / "contracts" / "pto-isa-0.58.7-tile-operations.json" +DEFAULT_PTO_OUTPUT = ROOT / "contracts" / "pto-isa-0.59.0-tile-operations.json" EXPECTED_COUNTS = {"CUBE": 12, "SFU": 47, "TLSU": 28, "VEC": 32} + +# LinxISA v0.58 authority (unchanged). EXPECTED_COMMIT = "f77a8960f61f97c264a90b7aee757f99891b0943" EXPECTED_TREE = "da085d3f000a5b92031c9694024dc9a7f3cdaa89" EXPECTED_CATALOG_SHA256 = "51ca9be275518d29ec48bed570b7a9bd441a65b9c5e6d4f79072f650ee732925" -EXPECTED_PTO_COMMIT = "f0a876e449a95d26841c5ee7affb4c905ebc5f5b" -EXPECTED_PTO_TREE = "fe9e8e050375fbce3f526d08acca13c37cd15830" -EXPECTED_PTO_MANIFEST_SHA256 = "0c6d0b2a1ec0b49e32e13971e751a5ea19946351a3880bfdfcef0f50351944f7" + +# PTO development golden that the LinxISA v0.58 authority locked. +EXPECTED_DEV_COMMIT = "f0a876e449a95d26841c5ee7affb4c905ebc5f5b" +EXPECTED_DEV_TREE = "fe9e8e050375fbce3f526d08acca13c37cd15830" +EXPECTED_DEV_MANIFEST_SHA256 = "0c6d0b2a1ec0b49e32e13971e751a5ea19946351a3880bfdfcef0f50351944f7" + +# Published PTO ISA 0.59.0.0 release (the active encoding identity). +EXPECTED_PTO_COMMIT = "b0165320a4b575b18d2f4d93faf40178f661ab49" +EXPECTED_PTO_TREE = "31ff0c2d39cbed714baf5be7929bfd06887be9fb" +EXPECTED_PTO_RELEASE_MANIFEST_SHA256 = ( + "3c6b20623e73822c0bd26021c10beb233b8809328b5515f57609eadad1749dc4" +) EXPECTED_PTO_TILE_SHA256 = "533db9b8f31f118af5978de813cfaa3fa738de820ee24655faa2ee71f343a706" -EXPECTED_IDENTITY = { - "release": "0.58.7", - "encoding_abi": "pto-isa-0.58.7-mode-function-v1", - "encoding_projection_sha256": "a5f78ecd707bde4a014542158ea257c783796b95fa4fbcce37742e41fee6a881", +EXPECTED_RELEASE_IDENTITY = { + "release": "0.59.0", + "publication_version": "0.59.0.0", + "encoding_abi": "pto-isa-0.59.0-mode-function-v1", + "encoding_projection_sha256": ( + "91509080ca656eb124f47830dcb09c50389dc177266b3b8df9d2d11dc37d5697" + ), + "content_sha256": ( + "a3e71975e7f753864f7ec09c57515e60f5a6e3e72dfdbce8e444c815a20b2835" + ), } @@ -47,7 +83,7 @@ def require_clean_exact_repo(repo: Path, commit: str, tree: str, label: str) -> raise SystemExit(f"refusing dirty {label} source tree: {repo}") actual = (git(repo, "rev-parse", "HEAD"), git(repo, "rev-parse", "HEAD^{tree}")) if actual != (commit, tree): - raise SystemExit(f"{label} source identity does not match the reviewed golden") + raise SystemExit(f"{label} source identity does not match the reviewed pin") def load_sources( @@ -57,31 +93,43 @@ def load_sources( linx_repo = Path(git(source.parent, "rev-parse", "--show-toplevel")) require_clean_exact_repo(linx_repo, EXPECTED_COMMIT, EXPECTED_TREE, "LinxISA v0.58.7") if sha256(source) != EXPECTED_CATALOG_SHA256: - raise SystemExit("LinxISA catalog bytes do not match the reviewed golden") + raise SystemExit("LinxISA catalog bytes do not match the reviewed authority") pto_repo = Path(git(pto_root.resolve(), "rev-parse", "--show-toplevel")) - require_clean_exact_repo(pto_repo, EXPECTED_PTO_COMMIT, EXPECTED_PTO_TREE, "PTO ISA") - manifest_path = pto_repo / "spec" / "development-manifest.json" + require_clean_exact_repo( + pto_repo, EXPECTED_PTO_COMMIT, EXPECTED_PTO_TREE, "PTO ISA 0.59.0.0 release" + ) + manifest_path = pto_repo / "spec" / "release-manifest.json" tile_catalog_path = pto_repo / "spec" / "catalog" / "tile-operations.json" - if sha256(manifest_path) != EXPECTED_PTO_MANIFEST_SHA256: - raise SystemExit("PTO development manifest bytes do not match the reviewed golden") + if sha256(manifest_path) != EXPECTED_PTO_RELEASE_MANIFEST_SHA256: + raise SystemExit("PTO release manifest bytes do not match the reviewed release") if sha256(tile_catalog_path) != EXPECTED_PTO_TILE_SHA256: - raise SystemExit("PTO Tile catalog bytes do not match the reviewed golden") + raise SystemExit("PTO Tile catalog bytes do not match the reviewed release") linx_data = json.loads(source.read_text(encoding="utf-8")) manifest = json.loads(manifest_path.read_text(encoding="utf-8")) tile_catalog = json.loads(tile_catalog_path.read_text(encoding="utf-8")) if linx_data.get("isa") != "LinxISA" or linx_data.get("version") != "0.58.7": raise SystemExit("source is not the reviewed LinxISA 0.58.7 catalog") - if manifest.get("status") != "development-not-published" or manifest.get("publication") is not None: - raise SystemExit("PTO golden must remain an unpublished development identity") - if manifest.get("identity") != EXPECTED_IDENTITY: - raise SystemExit("unexpected PTO development identity") - if manifest.get("catalog_counts", {}).get("tile_operations") != 119: - raise SystemExit("unexpected PTO development Tile operation count") + + release_identity = { + "release": manifest.get("release"), + "publication_version": manifest.get("publication_version"), + "encoding_abi": manifest.get("encoding_abi"), + "encoding_projection_sha256": manifest.get("encoding_projection_sha256"), + "content_sha256": manifest.get("content_sha256"), + } + if release_identity != EXPECTED_RELEASE_IDENTITY: + raise SystemExit("unexpected PTO 0.59.0.0 release identity") + counts = manifest.get("catalog_counts", {}).get("tile_operations_total") + if counts != 119: + raise SystemExit("unexpected PTO release Tile operation count") if tile_catalog.get("operation_count") != 119 or len(tile_catalog.get("operations", [])) != 119: raise SystemExit("unexpected PTO Tile catalog inventory") + # The LinxISA v0.58 authority locked the PTO development golden. Keep that + # lock fail-closed and additionally require its Tile catalog bytes to equal + # the release Tile catalog, which is what makes this projection valid. lock_path = source.parent / "pto-scalar-proposal.lock.json" lock = json.loads(lock_path.read_text(encoding="utf-8")) lock_identity = ( @@ -89,16 +137,14 @@ def load_sources( lock.get("source", {}).get("commit"), lock.get("source", {}).get("tree"), lock.get("development_manifest", {}).get("sha256"), - lock.get("identity"), lock.get("catalogs", {}).get("tile_operations", {}).get("sha256"), lock.get("catalogs", {}).get("tile_operations", {}).get("count"), ) expected_lock_identity = ( "development-not-published", - EXPECTED_PTO_COMMIT, - EXPECTED_PTO_TREE, - EXPECTED_PTO_MANIFEST_SHA256, - EXPECTED_IDENTITY, + EXPECTED_DEV_COMMIT, + EXPECTED_DEV_TREE, + EXPECTED_DEV_MANIFEST_SHA256, EXPECTED_PTO_TILE_SHA256, 119, ) @@ -113,7 +159,7 @@ def build_projection(source: Path, pto_root: Path) -> tuple[dict[str, object], b if engine_ops["semantic_engine_counts"] != EXPECTED_COUNTS: raise SystemExit("unexpected LinxISA v0.58.7 engine counts") if sum(EXPECTED_COUNTS.values()) != 119: - raise SystemExit("engine counts do not cover the PTO development Tile catalog") + raise SystemExit("engine counts do not cover the PTO release Tile catalog") linx_repo = Path(git(source.resolve().parent, "rev-parse", "--show-toplevel")) relative = source.resolve().relative_to(linx_repo).as_posix() @@ -130,22 +176,43 @@ def build_projection(source: Path, pto_root: Path) -> tuple[dict[str, object], b }, "pto_source": { "repo": "https://github.com/PTO-ISA/pto-spec.git", - "status": manifest["status"], - "publication": manifest["publication"], - "release": EXPECTED_IDENTITY["release"], + "release": EXPECTED_RELEASE_IDENTITY["release"], + "publication_version": EXPECTED_RELEASE_IDENTITY["publication_version"], + "release_tag": "v0.59.0.0", + "specification_status": manifest["specification_status"], "commit": EXPECTED_PTO_COMMIT, "tree": EXPECTED_PTO_TREE, - "development_manifest": { - "path": "spec/development-manifest.json", - "sha256": EXPECTED_PTO_MANIFEST_SHA256, + "release_manifest": { + "path": "spec/release-manifest.json", + "sha256": EXPECTED_PTO_RELEASE_MANIFEST_SHA256, }, - "encoding_abi": EXPECTED_IDENTITY["encoding_abi"], - "encoding_projection_sha256": EXPECTED_IDENTITY["encoding_projection_sha256"], + "encoding_abi": EXPECTED_RELEASE_IDENTITY["encoding_abi"], + "encoding_projection_sha256": EXPECTED_RELEASE_IDENTITY[ + "encoding_projection_sha256" + ], + "content_sha256": EXPECTED_RELEASE_IDENTITY["content_sha256"], "tile_catalog": { "path": "spec/catalog/tile-operations.json", "sha256": EXPECTED_PTO_TILE_SHA256, "count": 119, }, + "development_lock": { + "release": "0.58.7", + "commit": EXPECTED_DEV_COMMIT, + "tree": EXPECTED_DEV_TREE, + "development_manifest": { + "path": "spec/development-manifest.json", + "sha256": EXPECTED_DEV_MANIFEST_SHA256, + }, + "catalog_sha256_matches_release": True, + "note": ( + "The LinxISA v0.58 authority locked the PTO development " + "golden; its Tile catalog bytes equal the 0.59.0.0 release " + "Tile catalog (both SHA-256 533db9b8...), so the v0.58 " + "engine projection remains valid against the published " + "release." + ), + }, }, "semantic_engine_counts": engine_ops["semantic_engine_counts"], "tepl_carrier": { @@ -195,7 +262,12 @@ def render(projection: dict[str, object]) -> str: def main() -> int: parser = argparse.ArgumentParser() parser.add_argument("source", type=Path, help="reviewed isa/v0.58/linxisa-v0.58.json") - parser.add_argument("--pto-root", type=Path, required=True) + parser.add_argument( + "--pto-root", + type=Path, + required=True, + help="clean checkout of PTO-ISA/pto-spec at the v0.59.0.0 release commit", + ) parser.add_argument("--output", type=Path, default=DEFAULT_OUTPUT) parser.add_argument("--pto-output", type=Path, default=DEFAULT_PTO_OUTPUT) parser.add_argument("--check", action="store_true") @@ -207,7 +279,7 @@ def main() -> int: if not args.output.exists() or args.output.read_text(encoding="utf-8") != expected: raise SystemExit(f"stale LinxISA v0.58 projection: {args.output}") if not args.pto_output.exists() or args.pto_output.read_bytes() != tile_catalog: - raise SystemExit(f"stale PTO development Tile catalog: {args.pto_output}") + raise SystemExit(f"stale PTO 0.59.0.0 release Tile catalog: {args.pto_output}") return 0 args.output.parent.mkdir(parents=True, exist_ok=True)