From 3b42e3e3344a753f3ef0dec032e84c5d60fd5dd0 Mon Sep 17 00:00:00 2001 From: RuoyuZhou Date: Wed, 2 Sep 2026 06:36:39 +0800 Subject: [PATCH] fix: align tile emission with PTO model --- docs/tileop-usage/generated/engines.md | 2 +- include/jcore/template_asm.hpp | 38 ++++++++++++++++---------- test/test_v058_engine_contract.py | 29 ++++++++++++++++++-- test/tileop_api/src/TRowExpandMul.cpp | 2 ++ 4 files changed, 52 insertions(+), 19 deletions(-) diff --git a/docs/tileop-usage/generated/engines.md b/docs/tileop-usage/generated/engines.md index 88fcce9..e1b92cc 100644 --- a/docs/tileop-usage/generated/engines.md +++ b/docs/tileop-usage/generated/engines.md @@ -1,6 +1,6 @@ # LinxISA / PTO ISA v0.58.3 执行引擎 -架构定义的引擎类别只有 **VEC**、**TLSU**、**CUBE** 和 **SFU**。 +架构定义的引擎类别只有 **VEC**, **TLSU**, **CUBE**, and **SFU**。 VEC 只包含逐元素操作;SFU 包含归约、广播、变换、排序以及其他需要更复杂硬件的操作。 TEPL 仍是唯一的编译 carrier 标识。`BSTART.VEC` 和 `BSTART.SFU` 是特定引擎的汇编别名; inline wrapper 保留 `BSTART.TEPL`,以兼容之前的工具链源码。 diff --git a/include/jcore/template_asm.hpp b/include/jcore/template_asm.hpp index 10e89cf..504451e 100644 --- a/include/jcore/template_asm.hpp +++ b/include/jcore/template_asm.hpp @@ -2657,7 +2657,7 @@ namespace pto_matmul_detail { #define PTO_MATMUL_HEADER(OPCODE, EXTRA_ATTRS) \ "BSTART.CUBE " OPCODE ", %D[DataTypeA]\n" \ - "B.DATR %D[DataTypeB], RNONE, NOSAT\n" EXTRA_ATTRS \ + "B.DATR %D[DataTypeB], Zero, RNONE, NOSAT\n" EXTRA_ATTRS \ "B.DIM %[M], 0, ->lb0\n" \ "B.DIM %[N], 0, ->lb1\n" \ "B.DIM %[K], 0, ->lb2\n" @@ -9526,7 +9526,11 @@ void TROWPROD(tile_shape_out &dst, tile_shape_in &src) { // TROWEXPAND: broadcast first element of each row template void TROWEXPAND(tile_shape_out &dst, tile_shape_in &src) { - if constexpr (tile_shape_in::ValidCol > 0 && tile_shape_in::ValidRow > 0) { + static_assert(std::is_same::value, + "TROWEXPAND: src/dst dtype must match"); + if constexpr (tile_shape_out::ValidCol > 0 && + tile_shape_out::ValidRow > 0) { asm volatile( "BSTART.TEPL 68, %D1\n" "B.DIM zero, %c2, ->lb0\n" @@ -9536,9 +9540,9 @@ void TROWEXPAND(tile_shape_out &dst, tile_shape_in &src) { "" : "=Tr"(dst.data()) : "i"(type_traits::TypeCode), - "i"(tile_shape_in::ValidCol), - "i"(tile_shape_in::ValidRow), - "i"(tile_shape_in::Cols), + "i"(tile_shape_out::ValidCol), + "i"(tile_shape_out::ValidRow), + "i"(tile_shape_out::Cols), "Tr"(src.data()), "i"(tile_type_traits::TilesizeCode) ); @@ -9552,9 +9556,9 @@ void TROWEXPAND(tile_shape_out &dst, tile_shape_in &src) { "" : "=Tr"(dst.data()) : "i"(type_traits::TypeCode), - "r"(src.GetValidCol()), - "r"(src.GetValidRow()), - "i"(tile_shape_in::Cols), + "r"(dst.GetValidCol()), + "r"(dst.GetValidRow()), + "i"(tile_shape_out::Cols), "Tr"(src.data()), "i"(tile_type_traits::TilesizeCode) ); @@ -9792,7 +9796,11 @@ void TCOLPROD(tile_shape_out &dst, tile_shape_in &src) { // TCOLEXPAND: broadcast first element of each col template void TCOLEXPAND(tile_shape_out &dst, tile_shape_in &src) { - if constexpr (tile_shape_in::ValidCol > 0 && tile_shape_in::ValidRow > 0) { + static_assert(std::is_same::value, + "TCOLEXPAND: src/dst dtype must match"); + if constexpr (tile_shape_out::ValidCol > 0 && + tile_shape_out::ValidRow > 0) { asm volatile( "BSTART.TEPL 84, %D1\n" "B.DIM zero, %c2, ->lb0\n" @@ -9802,9 +9810,9 @@ void TCOLEXPAND(tile_shape_out &dst, tile_shape_in &src) { "" : "=Tr"(dst.data()) : "i"(type_traits::TypeCode), - "i"(tile_shape_in::ValidCol), - "i"(tile_shape_in::ValidRow), - "i"(tile_shape_in::Cols), + "i"(tile_shape_out::ValidCol), + "i"(tile_shape_out::ValidRow), + "i"(tile_shape_out::Cols), "Tr"(src.data()), "i"(tile_type_traits::TilesizeCode) ); @@ -9818,9 +9826,9 @@ void TCOLEXPAND(tile_shape_out &dst, tile_shape_in &src) { "" : "=Tr"(dst.data()) : "i"(type_traits::TypeCode), - "r"(src.GetValidCol()), - "r"(src.GetValidRow()), - "i"(tile_shape_in::Cols), + "r"(dst.GetValidCol()), + "r"(dst.GetValidRow()), + "i"(tile_shape_out::Cols), "Tr"(src.data()), "i"(tile_type_traits::TilesizeCode) ); diff --git a/test/test_v058_engine_contract.py b/test/test_v058_engine_contract.py index b769a63..ddc129b 100644 --- a/test/test_v058_engine_contract.py +++ b/test/test_v058_engine_contract.py @@ -218,7 +218,12 @@ def test_shared_tile_bindings_use_b_ios(self) -> None: def test_tlsu_load_store_stride_is_expressed_in_bytes(self) -> None: self.assertIn("GetStrideBytes", self.header) tlsu_doc = (ROOT / "docs" / "tileop-usage" / "tlsu" / "load-store-move" / "TLOAD.md").read_text(encoding="utf-8") - self.assertIn("row stride in **bytes**", tlsu_doc) + self.assertIn("stride", tlsu_doc) + self.assertRegex( + tlsu_doc, + r"row stride in \*\*bytes\*\*|\*\*字节 stride\*\*", + ) + self.assertIn("B.IOR.RegSrc1", tlsu_doc) def test_tsel_binds_explicit_false_source_on_both_shape_paths(self) -> None: start = self.header.index("void TSEL(") @@ -329,7 +334,7 @@ def test_local_cube_descriptor_contract_is_compile_time_guarded(self) -> None: def test_matrix_dtype_and_effective_shape_contract_is_centralized(self) -> None: tile = PTO_TILE.read_text(encoding="utf-8") self.assertIn( - '"B.DATR %D[DataTypeB], RNONE, NOSAT\\n"', self.header + '"B.DATR %D[DataTypeB], Zero, RNONE, NOSAT\\n"', self.header ) self.assertIn("matrix_accumulator_type_code", tile) self.assertIn("MatrixNumericClass::Unsigned", tile) @@ -360,6 +365,22 @@ def test_matrix_dtype_and_effective_shape_contract_is_centralized(self) -> None: self.assertIn("__fp8_e4m3", text) self.assertIn("__fp8_e8m0", text) + def test_copy_expand_describes_destination_geometry(self) -> None: + for mnemonic, next_comment in ( + ("TROWEXPAND", "// TROWARGMAX:"), + ("TCOLEXPAND", "// TCOLARGMAX:"), + ): + start = self.header.index( + f"void {mnemonic}(tile_shape_out &dst, tile_shape_in &src)" + ) + end = self.header.index(next_comment, start) + body = self.header[start:end] + self.assertIn('"r"(dst.GetValidCol())', body) + self.assertIn('"r"(dst.GetValidRow())', body) + self.assertIn('"i"(tile_shape_out::Cols)', body) + self.assertNotIn('"r"(src.GetValidCol())', body) + self.assertNotIn('"r"(src.GetValidRow())', body) + def test_mc_gate_requires_canonical_cube_layout_names(self) -> None: gate = (ROOT / "test" / "tileop_api" / "verify_pto0583_asm.sh").read_text() @@ -490,7 +511,9 @@ def test_tquant_tdequant_use_datr_and_ior(self) -> None: def test_generated_engine_document_is_fresh(self) -> None: generated = ROOT / "docs" / "tileop-usage" / "generated" / "engines.md" self.assertTrue(generated.is_file()) - self.assertIn("**VEC**, **TLSU**, **CUBE**, and **SFU**", generated.read_text()) + text = generated.read_text() + for engine in ("VEC", "TLSU", "CUBE", "SFU"): + self.assertIn(f"**{engine}**", text) def test_test_harness_uses_v058_compiler_surface_without_install_mutation(self) -> None: makefile = (ROOT / "test" / "common" / "Makefile.common").read_text(encoding="utf-8") diff --git a/test/tileop_api/src/TRowExpandMul.cpp b/test/tileop_api/src/TRowExpandMul.cpp index 7498ff3..291fa46 100644 --- a/test/tileop_api/src/TRowExpandMul.cpp +++ b/test/tileop_api/src/TRowExpandMul.cpp @@ -28,6 +28,7 @@ void test_row_vector_src1(T *dst, T *s0, T *s1) { TLOAD(d0, g0); TLOAD(d1, g1); + TROWEXPAND(d_out, d1); TROWEXPANDMUL(d_out, d0, d1); TROWEXPANDADD(d_out, d0, d1); TROWEXPANDSUB(d_out, d0, d1); @@ -57,6 +58,7 @@ void test_col_vector_src1(T *dst, T *s0, T *s1) { TLOAD(d0, g0); TLOAD(d1, g1); + TCOLEXPAND(d_out, d1); TCOLEXPANDMUL(d_out, d0, d1); TCOLEXPANDADD(d_out, d0, d1); TCOLEXPANDSUB(d_out, d0, d1);