diff --git a/docs/tileop-usage/elementwise-tile-tile/logical/TCMP.md b/docs/tileop-usage/elementwise-tile-tile/logical/TCMP.md index 33ae6cc..0dae0cb 100644 --- a/docs/tileop-usage/elementwise-tile-tile/logical/TCMP.md +++ b/docs/tileop-usage/elementwise-tile-tile/logical/TCMP.md @@ -62,6 +62,10 @@ void TCMP_ASS(D &assembled_dst, A &src0, B &src1); // Mode = EQ 输入与输出的 Tile location、layout、dtype、物理 shape 和 valid region 必须满足该操作的 逐项规则;除非本页明确允许,不应假定可原地执行或允许 alias。 +`src0`、`src1` 和 predicate `dst` 必须具有相同的物理 `Rows x Cols` 与 +`BLayout`,并且 valid shape 也必须一致。`validCol < Cols` 只表示尾部物理列 +不参与有效计算,不允许用不同物理列数的 Tile 作为 compare 链的另一输入。 + 操作数角色、数据类型组合、容量、PE mask 和 alias 必须符合上方约束;只能使用所选重载声明的操作数形式。 ### 有效区域与 padding @@ -142,4 +146,4 @@ TSTORE(result_global, result); 示例选择相等位置的 `left`,其他位置保留预先放入 `result` 的 `right`。 -涉及标量、索引、scale 或 bias 的操作,请按上方实际重载替换示例参数。 \ No newline at end of file +涉及标量、索引、scale 或 bias 的操作,请按上方实际重载替换示例参数。 diff --git a/docs/tileop-usage/elementwise-tile-tile/logical/TSEL.md b/docs/tileop-usage/elementwise-tile-tile/logical/TSEL.md index 792f6c7..4453928 100644 --- a/docs/tileop-usage/elementwise-tile-tile/logical/TSEL.md +++ b/docs/tileop-usage/elementwise-tile-tile/logical/TSEL.md @@ -47,6 +47,10 @@ src_true(数值源)可使用**等元素位宽、非打包 4-bit** 的异类 输入与输出的 Tile location、layout、dtype、物理 shape 和 valid region 必须满足该操作的 逐项规则;除非本页明确允许,不应假定可原地执行或允许 alias。 +`dst`、`predicate` 和 `src_true` 必须具有相同的物理 `Rows x Cols` 与 +`BLayout`,并且 valid shape 也必须一致。`validCol < Cols` 不会把不同物理列 +布局的 Tile 变成可兼容的 compare/select 操作数。 + 操作数角色、数据类型组合、容量、PE mask 和 alias 必须符合上方约束;只能使用所选重载声明的操作数形式。 ### 有效区域与 padding @@ -117,4 +121,4 @@ TSTORE(dst_global, dst); // TileT dst; TSEL(dst, predicate, src_true); // 错误:dst/false source 未初始化 ``` -涉及标量、索引、scale 或 bias 的操作,请按上方实际重载替换示例参数。 \ No newline at end of file +涉及标量、索引、scale 或 bias 的操作,请按上方实际重载替换示例参数。 diff --git a/docs/tileop-usage/options.md b/docs/tileop-usage/options.md index 9c0d985..eed5eb7 100644 --- a/docs/tileop-usage/options.md +++ b/docs/tileop-usage/options.md @@ -274,6 +274,13 @@ TMATMUL(d, a, b, fixp::f16().prelu(prelu)); `U8` 可通过 `High=true` 选择高半 carrier。valid shape 必须满足一个 GPR carrier 的字段容量,跨多个 GPR 的结果需要由调用者拆分 source view 或分组处理。 +## 6.3 TCMP/TSEL partial-column shape + +`TCMP` 和 `TSEL` 可以处理 `ValidCol < Cols` 的 partial-column Tile,但参与同一 +compare/select 操作的操作数仍必须保持相同的物理 `Rows x Cols` 和 `BLayout`,并且 +valid shape 必须一致。不能用 `[M, N]`、`ValidCol=1` 的 Tile 与物理 `[M, 1]` Tile +混用;这两种 Tile 的行距和 descriptor geometry 不同,应在 API 层编译期拒绝。 + PTO #311 row-reduction results may retain a wide physical CUBE carrier while publishing only `ValidCol=1`. Use `TREDUCEPREFIXVIEW(reduction)` to borrow the first 128-byte CELL without a `TCVT` copy. The view is accepted diff --git a/include/jcore/template_asm.hpp b/include/jcore/template_asm.hpp index 1656ad3..0b3727d 100644 --- a/include/jcore/template_asm.hpp +++ b/include/jcore/template_asm.hpp @@ -12256,6 +12256,12 @@ void TCMP(tile_shape_out &dst, tile_shape_in0 &src0, tile_shape_in1 &src1) { static_assert(tile_shape_in0::Rows == tile_shape_out::Rows && tile_shape_in0::Cols == tile_shape_out::Cols, "TCMP output shape must match input shape"); + static_assert(tile_shape_in0::Rows == tile_shape_in1::Rows && + tile_shape_in0::Cols == tile_shape_in1::Cols && + tile_shape_in0::BFractal == tile_shape_in1::BFractal, + "TCMP source physical shapes and layouts must match"); + static_assert(tile_shape_in0::BFractal == tile_shape_out::BFractal, + "TCMP predicate layout must match input layout"); static_assert(tile_shape_in0::ValidRow == tile_shape_in1::ValidRow && tile_shape_in0::ValidCol == tile_shape_in1::ValidCol, "TCMP source valid shapes must match"); @@ -12745,6 +12751,13 @@ void TSEL(tile_shape &dst, mask_shape &mask, true_shape &true_src) { true_shape::ValidRow == tile_shape::ValidRow && true_shape::ValidCol == tile_shape::ValidCol, "TSEL mask/true-source valid shapes must match the destination"); + static_assert(mask_shape::Rows == tile_shape::Rows && + true_shape::Rows == tile_shape::Rows && + mask_shape::Cols == tile_shape::Cols && + true_shape::Cols == tile_shape::Cols && + mask_shape::BFractal == tile_shape::BFractal && + true_shape::BFractal == tile_shape::BFractal, + "TSEL physical shapes and layouts must match the destination"); if constexpr (tile_shape::ValidCol > 0 && tile_shape::ValidRow > 0) { asm volatile( "BSTART.TEPL 26, %D2\n" diff --git a/test/test_issue290_compare_select_shape.py b/test/test_issue290_compare_select_shape.py new file mode 100644 index 0000000..1f7e4db --- /dev/null +++ b/test/test_issue290_compare_select_shape.py @@ -0,0 +1,70 @@ +import os +import shutil +import subprocess +import tempfile +import unittest +from pathlib import Path + + +ROOT = Path(__file__).resolve().parents[1] +HEADER = ROOT / "include/jcore/template_asm.hpp" +SYSROOT = Path(os.environ.get( + "LINX_SYSROOT", + "/home/zhuwei/linx-toolchain-build-online-main/output/linx_blockisa_llvm_musl/sysroot", +)) +CXX = os.environ.get("LINX_CXX", "/home/zhuwei/linx-llvm/build/bin/clang++") + + +SOURCE = r''' +#include +using namespace pto; +using WideF = Tile; +using NarrowF = Tile; +using WideP = Tile; +void bad_cmp(WideP &d, WideF &a, NarrowF &b) { + TCMP(d, a, b); +} +''' + + +class Issue290CompareSelectShapeTest(unittest.TestCase): + def test_header_has_physical_shape_contracts(self): + text = HEADER.read_text(encoding="utf-8") + self.assertIn("TCMP source physical shapes and layouts must match", text) + self.assertIn("TSEL physical shapes and layouts must match the destination", text) + + def test_mismatched_physical_shape_is_compile_error(self): + if not Path(CXX).is_file() or not SYSROOT.is_dir(): + self.skipTest("Linx target compiler/sysroot unavailable") + with tempfile.TemporaryDirectory() as temporary: + temporary_path = Path(temporary) + resource_dir = temporary_path / "clang-resource" + shutil.copytree( + Path(subprocess.check_output( + [CXX, "-print-resource-dir"], text=True).strip(), + ), + resource_dir, + ) + shutil.rmtree(resource_dir / "include/tileop-api", ignore_errors=True) + shutil.copytree(ROOT / "include", resource_dir / "include/tileop-api") + source = temporary_path / "negative.cpp" + source.write_text(SOURCE, encoding="utf-8") + result = subprocess.run( + [ + CXX, "-resource-dir", str(resource_dir), + "--target=linx64v5-unknown-linux-musl", "-mlxbc", + "--sysroot", str(SYSROOT), "-nostdinc++", + "-isystem", str(SYSROOT / "usr/include/c++/v1"), + "-fenable-matrix", "-O2", "-std=c++20", "-D__linx", + "-DENABLE_TENSOR_INSTR", "-fsyntax-only", str(source), + ], + text=True, + stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, + ) + self.assertNotEqual(result.returncode, 0) + self.assertIn("TCMP source physical shapes and layouts must match", result.stdout) + + +if __name__ == "__main__": + unittest.main() diff --git a/test/tileop_api/compile.all b/test/tileop_api/compile.all index c0fc0df..740d912 100755 --- a/test/tileop_api/compile.all +++ b/test/tileop_api/compile.all @@ -33,7 +33,7 @@ ACTIVE_FIXTURES=( DirectCubeLayout TileRegionBinaryMixed Issue166RmsNormB128 Issue269ReductionCapacity Issue272PackPrefix Issue274PackViews Issue275PackAssemble Issue276ReinterpretMul Issue288CubeM32BinaryAssembly 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 - ValidShapeImmediate ValidShapePerDim ValidShapePerDimSweep CoopGroupMOverloads CubeInternalAcc TSELCanonical Issue200TcmpsGpr Issue203CubeTcvtTileArray IssueA2CubeMxFp4Tcvt Issue111SharedSlot + ValidShapeImmediate ValidShapePerDim ValidShapePerDimSweep CoopGroupMOverloads CubeInternalAcc TSELCanonical Issue200TcmpsGpr Issue203CubeTcvtTileArray IssueA2CubeMxFp4Tcvt Issue111SharedSlot Issue290PartialCompareSelect ) # Keep element conformance fixtures separate from the upstream operation list. diff --git a/test/tileop_api/src/Issue290PartialCompareSelect.cpp b/test/tileop_api/src/Issue290PartialCompareSelect.cpp new file mode 100644 index 0000000..14c5ffe --- /dev/null +++ b/test/tileop_api/src/Issue290PartialCompareSelect.cpp @@ -0,0 +1,12 @@ +#include + +using namespace pto; + +using WideF = Tile; +using WideP = Tile; + +void valid_partial_shapes(WideP &predicate, WideF &left, WideF &right, + WideF &dst) { + TCMP(predicate, left, right); + TSEL(dst, predicate, left); +}