From 93f76b32599a40b086ae8d852aa4a81c73d7d64d Mon Sep 17 00:00:00 2001 From: ziyang-cheng Date: Mon, 17 Aug 2026 10:14:00 +0800 Subject: [PATCH 1/4] [tileop-api] Backfill v0.58 Tile statics for reinterpret view Add CompactMode enum (layout.hpp) and forward-declare Compact, LogicalTileBytes, TilesizeCode, IsValidActiveSize on the Tile class so the incoming reinterpret_tile view (PR 376b27a) can forward SourceTile::* without pulling in the full v0.58 header-alignment commit. LogicalTileBytes equals the existing kBytes formula; Compact is fixed at Null (no compact tiles on this baseline). Members are inert outside the reinterpret view: downstream ops read tile_type_traits::IsValidActiveSize. --- include/common/layout.hpp | 9 +++++++++ include/common/pto_tile.hpp | 19 +++++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/include/common/layout.hpp b/include/common/layout.hpp index bc5929b..634b44b 100644 --- a/include/common/layout.hpp +++ b/include/common/layout.hpp @@ -40,6 +40,15 @@ enum class LayoutEnum { kColMajor = 2, }; +// Backfilled from PTO v0.58 (layout.hpp) so the datatype-reinterpret view can +// forward SourceTile::Compact. This baseline has no compact tiles: Tile +// defaults to CompactMode::Null (see pto_tile.hpp). +enum class CompactMode { + Null, + Normal, + RowPlusOne, +}; + enum LayoutCvtEnum : uint64_t { NORM = 0, ND2DN, ND2ZZ, ND2ZN, ND2NZ, ND2NN, diff --git a/include/common/pto_tile.hpp b/include/common/pto_tile.hpp index ce3fd23..2e6c6df 100644 --- a/include/common/pto_tile.hpp +++ b/include/common/pto_tile.hpp @@ -606,6 +606,25 @@ struct Tile { static constexpr int SFractalSize = SFractalSize_; static constexpr PadValue PadVal = PadVal_; + // Backfilled from PTO v0.58 so reinterpret_tile's view can forward these. + // LogicalTileBytes matches this baseline's existing kBytes formula; there are + // no compact tiles here so Compact is fixed at Null. Downstream ops read + // tile_type_traits::IsValidActiveSize, not these members, so the + // backfill is inert outside the reinterpret view. + static constexpr CompactMode Compact = CompactMode::Null; + static constexpr int LogicalTileBytes = + (Rows * Cols * type_traits::bits + 7) / 8; + static constexpr int TilesizeCode = + LogicalTileBytes == 128 ? __tilesize_128B : + LogicalTileBytes == 256 ? __tilesize_256B : + LogicalTileBytes == 512 ? __tilesize_512B : + LogicalTileBytes == 1024 ? __tilesize_1KB : + LogicalTileBytes == 2048 ? __tilesize_2KB : + LogicalTileBytes == 4096 ? __tilesize_4KB : + LogicalTileBytes == 8192 ? __tilesize_8KB : __tilesize_unknown; + static constexpr bool IsValidActiveSize = + TilesizeCode >= __tilesize_128B && TilesizeCode <= __tilesize_8KB; + // constructor for static shape Tile() { }; template From fd184c4246ed58d4d28138f79b63268cf91a2d70 Mon Sep 17 00:00:00 2001 From: ziyang-cheng Date: Mon, 17 Aug 2026 10:16:37 +0800 Subject: [PATCH 2/4] [tileop-api] Align CmpMode/TCMP/TCMPS with PTO 0.58 CMode contract Cherry-picked onto abe8411 (headers zero-conflict; only test/tileop_api/compile.all needed a trivial union merge). (cherry picked from commit 4e977ad) Co-Authored-By: Claude Opus 4 --- include/common/pto_tile.hpp | 37 +++- include/cpu_sim/TCmp.hpp | 10 ++ include/jcore/TCmp.hpp | 10 ++ include/jcore/template_asm.hpp | 299 ++++++++++++++++++++++++++----- test/tileop_api/compile.all | 6 + test/tileop_api/src/TCmpMode.cpp | 42 +++++ 6 files changed, 357 insertions(+), 47 deletions(-) create mode 100644 test/tileop_api/src/TCmpMode.cpp diff --git a/include/common/pto_tile.hpp b/include/common/pto_tile.hpp index 2e6c6df..4280f4c 100644 --- a/include/common/pto_tile.hpp +++ b/include/common/pto_tile.hpp @@ -16,15 +16,38 @@ namespace pto { /// // signed less than comparison /// } /// @endcode -enum class CmpMode { - EQ, ///< Equal (==) - NE, ///< Not equal (!=) - GT, ///< Greater than (>) - LT, ///< Less than (<) - GE, ///< Greater than or equal (>=) - LE, ///< Less than or equal (<=) +// PTO 0.58 B.DATR CMode[31:29] encoding. Values are explicit and MUST match +// the ISA: EQ=0 NE=1 LT=2 GT=3 LE=4 GE=5 (do not rely on declaration order). +enum class CmpMode : uint8_t { + EQ = 0, ///< Equal (==) + NE = 1, ///< Not equal (!=) + LT = 2, ///< Less than (<) + GT = 3, ///< Greater than (>) + LE = 4, ///< Less than or equal (<=) + GE = 5, ///< Greater than or equal (>=) }; +/// Compile-time validity check for the six ISA comparison modes. Rejects any +/// out-of-range value that a bogus static_cast would otherwise smuggle into +/// the B.DATR CMode field. +constexpr bool is_valid_cmp_mode(CmpMode Mode) { + switch (Mode) { + case CmpMode::EQ: + case CmpMode::NE: + case CmpMode::LT: + case CmpMode::GT: + case CmpMode::LE: + case CmpMode::GE: + return true; + } + return false; +} + +/// CmpMode -> B.DATR CMode[31:29] immediate (the enum value itself). +constexpr unsigned cmp_mode_code(CmpMode Mode) { + return static_cast(Mode); +} + /// Padding Value : keep SAME with asm encoding enum class PadValue { Zero = 0, diff --git a/include/cpu_sim/TCmp.hpp b/include/cpu_sim/TCmp.hpp index b1753d8..5ff90cb 100644 --- a/include/cpu_sim/TCmp.hpp +++ b/include/cpu_sim/TCmp.hpp @@ -24,6 +24,11 @@ void TCmp_Vec_RowMajor(typename tile_shape_out::TileDType dst, dst[idx] = static_cast( src0[idx] >= src1[idx]); } else if constexpr (mode == CmpMode::LE) { dst[idx] = static_cast( src0[idx] <= src1[idx]); + } else { + static_assert(mode == CmpMode::EQ || mode == CmpMode::NE || + mode == CmpMode::LT || mode == CmpMode::GT || + mode == CmpMode::LE || mode == CmpMode::GE, + "TCMP mode must be one of the six ISA comparison modes"); } } } @@ -48,6 +53,11 @@ void TCmp_Vec_ColMajor( dst[idx] = static_cast( src0[idx] >= src1[idx]); } else if constexpr (mode == CmpMode::LE) { dst[idx] = static_cast( src0[idx] <= src1[idx]); + } else { + static_assert(mode == CmpMode::EQ || mode == CmpMode::NE || + mode == CmpMode::LT || mode == CmpMode::GT || + mode == CmpMode::LE || mode == CmpMode::GE, + "TCMP mode must be one of the six ISA comparison modes"); } } } diff --git a/include/jcore/TCmp.hpp b/include/jcore/TCmp.hpp index a140147..2ca0f6b 100644 --- a/include/jcore/TCmp.hpp +++ b/include/jcore/TCmp.hpp @@ -30,6 +30,11 @@ void __vec__ TCmp_Vec_RowMajor(typename tile_shape_out::TileDType __out__ dst, result = static_cast( a >= b); } else if constexpr (mode == CmpMode::LE) { result = static_cast( a <= b); + } else { + static_assert(mode == CmpMode::EQ || mode == CmpMode::NE || + mode == CmpMode::LT || mode == CmpMode::GT || + mode == CmpMode::LE || mode == CmpMode::GE, + "TCMP mode must be one of the six ISA comparison modes"); } blkv_get_tile_ptr(dst)[index] = result; } @@ -57,6 +62,11 @@ void __vec__ TCmp_Vec_ColMajor(typename tile_shape_out::TileDType __out__ dst, result = static_cast( a >= b); } else if constexpr (mode == CmpMode::LE) { result = static_cast( a <= b); + } else { + static_assert(mode == CmpMode::EQ || mode == CmpMode::NE || + mode == CmpMode::LT || mode == CmpMode::GT || + mode == CmpMode::LE || mode == CmpMode::GE, + "TCMP mode must be one of the six ISA comparison modes"); } blkv_get_tile_ptr(dst)[index] = result; } diff --git a/include/jcore/template_asm.hpp b/include/jcore/template_asm.hpp index 02f438e..de72e47 100644 --- a/include/jcore/template_asm.hpp +++ b/include/jcore/template_asm.hpp @@ -3333,25 +3333,131 @@ void TMIN(tile_shape &dst, tile_shape &src0, tile_shape &src1) { ); } -// TCMP: compare src0 and src1, write packed predicate -template -void TCMP(tile_shape &dst, tile_shape &src0, tile_shape &src1) { - asm volatile( - "BSTART.TEPL 13, %c1\n" - "B.DIM %2, 0, ->lb0\n" - "B.DIM %3, 0, ->lb1\n" - "B.DIM zero, %c4, ->lb2\n" - "B.IOT %5, %6, mask=15, last, ->%0<%Z7>\n" - "" - : "=Tr"(dst.data()) - : "i"(type_traits::TypeCode), - "r"(src0.GetValidCol()), - "r"(src0.GetValidRow()), - "i"(tile_shape::Cols), - "Tr"(src0.data()), - "Tr"(src1.data()), - "i"(tile_type_traits::TilesizeCode) - ); +// TCMP: compare src0 and src1, write packed predicate. The comparison mode is +// a compile-time template parameter encoded into B.DATR CMode[31:29]; the +// zero-arg form is kept as a deprecated EQ default (PTO 0.58). +template +void TCMP(tile_shape_out &dst, tile_shape_in &src0, tile_shape_in &src1) { + static_assert(is_valid_cmp_mode(Mode), "TCMP requires a valid CmpMode"); + static_assert(tile_shape_in::Rows == tile_shape_out::Rows && + tile_shape_in::Cols == tile_shape_out::Cols, + "TCMP output shape must match input shape"); + if constexpr (Mode == CmpMode::EQ) { + asm volatile( + "BSTART.TEPL 13, %c[TCode]\n" + "B.DATR Zero, eq\n" + "B.DIM %[VCOL], 0, ->lb0\n" + "B.DIM %[VROW], 0, ->lb1\n" + "B.DIM zero, %c[Cols], ->lb2\n" + "B.IOT %[S0], %[S1], mask=15, last, ->%[D]<%Z[TSize]>\n" + "" + : [D] "=Tr"(dst.data()) + : [TCode] "i"(type_traits::TypeCode), + [VCOL] "r"(src0.GetValidCol()), + [VROW] "r"(src0.GetValidRow()), + [Cols] "i"(tile_shape_in::Cols), + [S0] "Tr"(src0.data()), + [S1] "Tr"(src1.data()), + [TSize] "i"(tile_type_traits::TilesizeCode) + ); + } else if constexpr (Mode == CmpMode::NE) { + asm volatile( + "BSTART.TEPL 13, %c[TCode]\n" + "B.DATR Zero, ne\n" + "B.DIM %[VCOL], 0, ->lb0\n" + "B.DIM %[VROW], 0, ->lb1\n" + "B.DIM zero, %c[Cols], ->lb2\n" + "B.IOT %[S0], %[S1], mask=15, last, ->%[D]<%Z[TSize]>\n" + "" + : [D] "=Tr"(dst.data()) + : [TCode] "i"(type_traits::TypeCode), + [VCOL] "r"(src0.GetValidCol()), + [VROW] "r"(src0.GetValidRow()), + [Cols] "i"(tile_shape_in::Cols), + [S0] "Tr"(src0.data()), + [S1] "Tr"(src1.data()), + [TSize] "i"(tile_type_traits::TilesizeCode) + ); + } else if constexpr (Mode == CmpMode::LT) { + asm volatile( + "BSTART.TEPL 13, %c[TCode]\n" + "B.DATR Zero, lt\n" + "B.DIM %[VCOL], 0, ->lb0\n" + "B.DIM %[VROW], 0, ->lb1\n" + "B.DIM zero, %c[Cols], ->lb2\n" + "B.IOT %[S0], %[S1], mask=15, last, ->%[D]<%Z[TSize]>\n" + "" + : [D] "=Tr"(dst.data()) + : [TCode] "i"(type_traits::TypeCode), + [VCOL] "r"(src0.GetValidCol()), + [VROW] "r"(src0.GetValidRow()), + [Cols] "i"(tile_shape_in::Cols), + [S0] "Tr"(src0.data()), + [S1] "Tr"(src1.data()), + [TSize] "i"(tile_type_traits::TilesizeCode) + ); + } else if constexpr (Mode == CmpMode::GT) { + asm volatile( + "BSTART.TEPL 13, %c[TCode]\n" + "B.DATR Zero, gt\n" + "B.DIM %[VCOL], 0, ->lb0\n" + "B.DIM %[VROW], 0, ->lb1\n" + "B.DIM zero, %c[Cols], ->lb2\n" + "B.IOT %[S0], %[S1], mask=15, last, ->%[D]<%Z[TSize]>\n" + "" + : [D] "=Tr"(dst.data()) + : [TCode] "i"(type_traits::TypeCode), + [VCOL] "r"(src0.GetValidCol()), + [VROW] "r"(src0.GetValidRow()), + [Cols] "i"(tile_shape_in::Cols), + [S0] "Tr"(src0.data()), + [S1] "Tr"(src1.data()), + [TSize] "i"(tile_type_traits::TilesizeCode) + ); + } else if constexpr (Mode == CmpMode::LE) { + asm volatile( + "BSTART.TEPL 13, %c[TCode]\n" + "B.DATR Zero, le\n" + "B.DIM %[VCOL], 0, ->lb0\n" + "B.DIM %[VROW], 0, ->lb1\n" + "B.DIM zero, %c[Cols], ->lb2\n" + "B.IOT %[S0], %[S1], mask=15, last, ->%[D]<%Z[TSize]>\n" + "" + : [D] "=Tr"(dst.data()) + : [TCode] "i"(type_traits::TypeCode), + [VCOL] "r"(src0.GetValidCol()), + [VROW] "r"(src0.GetValidRow()), + [Cols] "i"(tile_shape_in::Cols), + [S0] "Tr"(src0.data()), + [S1] "Tr"(src1.data()), + [TSize] "i"(tile_type_traits::TilesizeCode) + ); + } else if constexpr (Mode == CmpMode::GE) { + asm volatile( + "BSTART.TEPL 13, %c[TCode]\n" + "B.DATR Zero, ge\n" + "B.DIM %[VCOL], 0, ->lb0\n" + "B.DIM %[VROW], 0, ->lb1\n" + "B.DIM zero, %c[Cols], ->lb2\n" + "B.IOT %[S0], %[S1], mask=15, last, ->%[D]<%Z[TSize]>\n" + "" + : [D] "=Tr"(dst.data()) + : [TCode] "i"(type_traits::TypeCode), + [VCOL] "r"(src0.GetValidCol()), + [VROW] "r"(src0.GetValidRow()), + [Cols] "i"(tile_shape_in::Cols), + [S0] "Tr"(src0.data()), + [S1] "Tr"(src1.data()), + [TSize] "i"(tile_type_traits::TilesizeCode) + ); + } +} + +// Deprecated EQ-default form retained for old callers. +template +void TCMP(tile_shape_out &dst, tile_shape_in &src0, tile_shape_in &src1) { + TCMP(dst, src0, src1); } // TPRELU: parametric ReLU with per-element slope @@ -3962,29 +4068,142 @@ void TMINS(tile_shape &dst, tile_shape &src, typename tile_shape::DType s) { ); } -// TCMPS: compare src with scalar -template -void TCMPS(tile_shape &dst, tile_shape &src, typename tile_shape::DType s) { +// TCMPS: compare src with scalar. The comparison mode is a compile-time +// template parameter encoded into B.DATR CMode[31:29]; scalar travels via the +// canonical B.IOR slot, never as a Tile source (PTO 0.58). +template +void TCMPS(tile_shape_out &dst, tile_shape_in &src, + typename tile_shape_in::DType s) { + static_assert(is_valid_cmp_mode(Mode), "TCMPS requires a valid CmpMode"); + static_assert(tile_shape_in::Rows == tile_shape_out::Rows && + tile_shape_in::Cols == tile_shape_out::Cols, + "TCMPS output shape must match input shape"); // Anti-fold: keep a compile-time-constant scalar (e.g. 0) off the zero // register so B.IOR [zero],[] still matches an instruction. - volatile typename tile_shape::DType sv = s; - asm volatile( - "BSTART.TEPL 45, %c1\n" - "B.DIM %2, 0, ->lb0\n" - "B.DIM %3, 0, ->lb1\n" - "B.DIM zero, %c4, ->lb2\n" - "B.IOT %5, mask=15, last, ->%0<%Z6>\n" - "B.IOR [%7],[]\n" - "" - : "=Tr"(dst.data()) - : "i"(type_traits::TypeCode), - "r"(src.GetValidCol()), - "r"(src.GetValidRow()), - "i"(tile_shape::Cols), - "Tr"(src.data()), - "i"(tile_type_traits::TilesizeCode), - "r"(sv) - ); + volatile typename tile_shape_in::DType sv = s; + if constexpr (Mode == CmpMode::EQ) { + asm volatile( + "BSTART.TEPL 45, %c[TCode]\n" + "B.DATR Zero, eq\n" + "B.DIM %[VCOL], 0, ->lb0\n" + "B.DIM %[VROW], 0, ->lb1\n" + "B.DIM zero, %c[Cols], ->lb2\n" + "B.IOT %[S], mask=15, last, ->%[D]<%Z[TSize]>\n" + "B.IOR [%[Scalar]],[]\n" + "" + : [D] "=Tr"(dst.data()) + : [TCode] "i"(type_traits::TypeCode), + [VCOL] "r"(src.GetValidCol()), + [VROW] "r"(src.GetValidRow()), + [Cols] "i"(tile_shape_in::Cols), + [S] "Tr"(src.data()), + [TSize] "i"(tile_type_traits::TilesizeCode), + [Scalar] "r"(sv) + ); + } else if constexpr (Mode == CmpMode::NE) { + asm volatile( + "BSTART.TEPL 45, %c[TCode]\n" + "B.DATR Zero, ne\n" + "B.DIM %[VCOL], 0, ->lb0\n" + "B.DIM %[VROW], 0, ->lb1\n" + "B.DIM zero, %c[Cols], ->lb2\n" + "B.IOT %[S], mask=15, last, ->%[D]<%Z[TSize]>\n" + "B.IOR [%[Scalar]],[]\n" + "" + : [D] "=Tr"(dst.data()) + : [TCode] "i"(type_traits::TypeCode), + [VCOL] "r"(src.GetValidCol()), + [VROW] "r"(src.GetValidRow()), + [Cols] "i"(tile_shape_in::Cols), + [S] "Tr"(src.data()), + [TSize] "i"(tile_type_traits::TilesizeCode), + [Scalar] "r"(sv) + ); + } else if constexpr (Mode == CmpMode::LT) { + asm volatile( + "BSTART.TEPL 45, %c[TCode]\n" + "B.DATR Zero, lt\n" + "B.DIM %[VCOL], 0, ->lb0\n" + "B.DIM %[VROW], 0, ->lb1\n" + "B.DIM zero, %c[Cols], ->lb2\n" + "B.IOT %[S], mask=15, last, ->%[D]<%Z[TSize]>\n" + "B.IOR [%[Scalar]],[]\n" + "" + : [D] "=Tr"(dst.data()) + : [TCode] "i"(type_traits::TypeCode), + [VCOL] "r"(src.GetValidCol()), + [VROW] "r"(src.GetValidRow()), + [Cols] "i"(tile_shape_in::Cols), + [S] "Tr"(src.data()), + [TSize] "i"(tile_type_traits::TilesizeCode), + [Scalar] "r"(sv) + ); + } else if constexpr (Mode == CmpMode::GT) { + asm volatile( + "BSTART.TEPL 45, %c[TCode]\n" + "B.DATR Zero, gt\n" + "B.DIM %[VCOL], 0, ->lb0\n" + "B.DIM %[VROW], 0, ->lb1\n" + "B.DIM zero, %c[Cols], ->lb2\n" + "B.IOT %[S], mask=15, last, ->%[D]<%Z[TSize]>\n" + "B.IOR [%[Scalar]],[]\n" + "" + : [D] "=Tr"(dst.data()) + : [TCode] "i"(type_traits::TypeCode), + [VCOL] "r"(src.GetValidCol()), + [VROW] "r"(src.GetValidRow()), + [Cols] "i"(tile_shape_in::Cols), + [S] "Tr"(src.data()), + [TSize] "i"(tile_type_traits::TilesizeCode), + [Scalar] "r"(sv) + ); + } else if constexpr (Mode == CmpMode::LE) { + asm volatile( + "BSTART.TEPL 45, %c[TCode]\n" + "B.DATR Zero, le\n" + "B.DIM %[VCOL], 0, ->lb0\n" + "B.DIM %[VROW], 0, ->lb1\n" + "B.DIM zero, %c[Cols], ->lb2\n" + "B.IOT %[S], mask=15, last, ->%[D]<%Z[TSize]>\n" + "B.IOR [%[Scalar]],[]\n" + "" + : [D] "=Tr"(dst.data()) + : [TCode] "i"(type_traits::TypeCode), + [VCOL] "r"(src.GetValidCol()), + [VROW] "r"(src.GetValidRow()), + [Cols] "i"(tile_shape_in::Cols), + [S] "Tr"(src.data()), + [TSize] "i"(tile_type_traits::TilesizeCode), + [Scalar] "r"(sv) + ); + } else if constexpr (Mode == CmpMode::GE) { + asm volatile( + "BSTART.TEPL 45, %c[TCode]\n" + "B.DATR Zero, ge\n" + "B.DIM %[VCOL], 0, ->lb0\n" + "B.DIM %[VROW], 0, ->lb1\n" + "B.DIM zero, %c[Cols], ->lb2\n" + "B.IOT %[S], mask=15, last, ->%[D]<%Z[TSize]>\n" + "B.IOR [%[Scalar]],[]\n" + "" + : [D] "=Tr"(dst.data()) + : [TCode] "i"(type_traits::TypeCode), + [VCOL] "r"(src.GetValidCol()), + [VROW] "r"(src.GetValidRow()), + [Cols] "i"(tile_shape_in::Cols), + [S] "Tr"(src.data()), + [TSize] "i"(tile_type_traits::TilesizeCode), + [Scalar] "r"(sv) + ); + } +} + +// Deprecated EQ-default form retained for old callers. +template +void TCMPS(tile_shape_out &dst, tile_shape_in &src, + typename tile_shape_in::DType s) { + TCMPS(dst, src, s); } // TLRELU: leaky ReLU with scalar slope diff --git a/test/tileop_api/compile.all b/test/tileop_api/compile.all index 05ac21e..7901937 100755 --- a/test/tileop_api/compile.all +++ b/test/tileop_api/compile.all @@ -5,6 +5,12 @@ make clean;make TESTCASE=MatMacc make clean;make TESTCASE=MatMul_e4m3 make clean;make TESTCASE=MatMul make clean;make TESTCASE=SharedMatmul +make clean;make TESTCASE=TMatmulAccFullOptions +make clean;make TESTCASE=TMatmulAllOptions +make clean;make TESTCASE=TGEMVAllOptions +make clean;make TESTCASE=PostProcessCombos +make clean;make TESTCASE=SharedMatrixForms +make clean;make TESTCASE=TCmpMode make clean;make TESTCASE=SharedTLoad make clean;make TESTCASE=TAbs make clean;make TESTCASE=TAdd_mask diff --git a/test/tileop_api/src/TCmpMode.cpp b/test/tileop_api/src/TCmpMode.cpp new file mode 100644 index 0000000..5f82465 --- /dev/null +++ b/test/tileop_api/src/TCmpMode.cpp @@ -0,0 +1,42 @@ +// TCMP/TCMPS compile-time comparison-mode test. +// Verifies each of the six ISA CmpMode values compiles and that the +// deprecated no-mode forms resolve to EQ. +#include + +using namespace pto; + +using Src = Tile; +using Dst = Tile; + +__attribute__((noinline)) void tcmp_modes(Dst &d, Src &a, Src &b) { + TCMP(d, a, b); + TCMP(d, a, b); + TCMP(d, a, b); + TCMP(d, a, b); + TCMP(d, a, b); + TCMP(d, a, b); + // deprecated EQ-default forms + TCMP(d, a, b); + TCMPS(d, a, 1.0f); +} + +__attribute__((noinline)) void tcmps_modes(Dst &d, Src &a) { + TCMPS(d, a, 0.0f); + TCMPS(d, a, 0.0f); + TCMPS(d, a, 0.0f); + TCMPS(d, a, 0.0f); + TCMPS(d, a, 0.0f); + TCMPS(d, a, 0.0f); +} + +void use(void *) {} + +int main() { + Src a; + Src b; + Dst d; + tcmp_modes(d, a, b); + tcmps_modes(d, a); + use(&d); + return 0; +} From 986266362e1ac10b4b0916d43a3667a5297d22d9 Mon Sep 17 00:00:00 2001 From: LinxISA Automation Date: Thu, 13 Aug 2026 21:00:23 +0800 Subject: [PATCH 3/4] [tileop-api] Add local tile datatype reinterpret view (cherry picked from commit 376b27a2a26a07a1b275e111bd0aaaa09a827057) --- include/common/pto_tile.hpp | 149 ++++++++++++++++++++++++++++++++++++ 1 file changed, 149 insertions(+) diff --git a/include/common/pto_tile.hpp b/include/common/pto_tile.hpp index 4280f4c..3e69a2b 100644 --- a/include/common/pto_tile.hpp +++ b/include/common/pto_tile.hpp @@ -1284,4 +1284,153 @@ void print_tile_info() { } // namespace pto +//===--- Tile datatype reinterpret view (PTO v0.58) ---===// +// reinterpret_tile(src): zero-instruction datatype reinterpret. +// The underlying Tile register/storage bit pattern is unchanged; only the +// static DType (and downstream ISA datatype encoding) is re-interpreted by +// the view. First phase: Local Tile -> Local view, equal-bit-width only, +// layout/shape/valid/Location preserved, no TCVT, no payload copy. +namespace pto { + +// Whether T has a PTO TypeCode (has a type_traits specialization). +template struct has_ptotype_traits : std::false_type {}; +template +struct has_ptotype_traits::TypeCode)>> + : std::true_type {}; + +template +inline constexpr bool is_supported_dtype_v = + has_ptotype_traits>::value && + (type_traits>::bits > 0); + +// Zero-instruction datatype view over an existing Local Tile. Storage carrier +// (TileDType) and data() forward to the source; DType and all shape/role +// statics are re-declared so downstream ops see NewDType while binding the +// source's exact Tile register. +template +class ReinterpretedTileView { +public: + using DType = NewDType; + using Source = SourceTile; + // Same storage carrier as the source Tile: on __linx this is the fixed + // 4 KB TileDType, so tile_type_traits<...TileDType>::TilesizeCode and the + // physical bytes are unchanged by the reinterpret. + using TileDType = typename SourceTile::TileDType; + + static constexpr Location Loc = SourceTile::Loc; + static constexpr int Rows = SourceTile::Rows; + static constexpr int Cols = SourceTile::Cols; + static constexpr int RowStride = SourceTile::RowStride; + static constexpr int ColStride = SourceTile::ColStride; + static constexpr int ValidRow = SourceTile::ValidRow; + static constexpr int ValidCol = SourceTile::ValidCol; + static constexpr BLayout BFractal = SourceTile::BFractal; + static constexpr SLayout SFractal = SourceTile::SFractal; + static constexpr int SFractalSize = SourceTile::SFractalSize; + static constexpr PadValue PadVal = SourceTile::PadVal; + static constexpr CompactMode Compact = SourceTile::Compact; + static constexpr bool isRowMajor = SourceTile::isRowMajor; + static constexpr bool isBoxedLayout = SourceTile::isBoxedLayout; + static constexpr bool isInnerRowMajor = SourceTile::isInnerRowMajor; + static constexpr bool isInnerColMajor = SourceTile::isInnerColMajor; + static constexpr int InnerRows = SourceTile::InnerRows; + static constexpr int InnerCols = SourceTile::InnerCols; + static constexpr int InnerNumel = SourceTile::InnerNumel; + static constexpr int Numel = SourceTile::Numel; + static constexpr int byteSize = SourceTile::byteSize; + // Physical storage identity: the view occupies exactly the source bytes. + static constexpr int kBytes = SourceTile::kBytes; + static constexpr int LogicalTileBytes = SourceTile::LogicalTileBytes; + static constexpr int TilesizeCode = SourceTile::TilesizeCode; + static constexpr bool IsValidActiveSize = SourceTile::IsValidActiveSize; + + explicit constexpr ReinterpretedTileView(SourceTile &Source) + : SourceValue(Source) {} + + // Same register carrier as the source (no copy). Only const access is + // exposed for const sources; the non-const path keeps the same carrier. + decltype(auto) data() { return SourceValue.data(); } + decltype(auto) data() const { return SourceValue.data(); } + + template + static constexpr std::enable_if_t<(RowMask > 0), int> GetValidRow() { + return SourceTile::template GetValidRow(); + } + template + std::enable_if_t GetValidRow() const { + return SourceValue.GetValidRow(); + } + template + static constexpr std::enable_if_t<(ColMask > 0), int> GetValidCol() { + return SourceTile::template GetValidCol(); + } + template + std::enable_if_t GetValidCol() const { + return SourceValue.GetValidCol(); + } + +private: + SourceTile &SourceValue; +}; + +// A ReinterpretedTileView is a Local tile-shaped operand (not Shared). +template +struct is_tile> : std::true_type { + static constexpr SLayout layout_enum = SourceTile::SFractal; +}; + +// Equal bit-width is required: the reinterpret must not change the number of +// logical elements, physical bytes or TileSizeCode. +template +constexpr bool reinterpret_tile_equal_width_v = + type_traits::bits == + type_traits::bits; + +// The source must be an ordinary Local Tile (Shared is out of scope for the +// first phase; a Shared view would need the Sr binder contract). +template +constexpr bool reinterpret_tile_source_is_local_v = + is_tile::value && + SourceTile::Loc != Location::Shared; + +// The new dtype must be encodable in the source's layout. We accept any +// equal-width dtype whose type_traits exists; boxed/fractal layouts are +// preserved unchanged because rows/cols/inner box are untouched, so the +// existing Tile layout static_asserts remain valid for the same dimensions. +// A NewDType with no PTO TypeCode is rejected by is_supported_dtype_v. +template +constexpr bool reinterpret_tile_layout_legal_v = + reinterpret_tile_equal_width_v && + is_supported_dtype_v; + +// Physical storage preservation: same bytes, same TilesizeCode, same carrier. +template +constexpr bool reinterpret_tile_storage_compatible_v = + reinterpret_tile_equal_width_v; + +// The view must not dangle: it holds a reference, so it must not be bound to +// a temporary Tile. reinterpret_tile takes SourceTile& (non-const), which +// already rejects rvalues; the const overload takes const SourceTile&, which +// also rejects prvalue temporaries (they bind to const& only via materialized +// temporaries -- rejected by requiring a named lvalue at the call site). + +/// Zero-instruction datatype reinterpret over a Local Tile. +template +inline auto reinterpret_tile(SourceTile &Source) { + using OldDType = typename SourceTile::DType; + static_assert(is_supported_dtype_v, + "reinterpret_tile target dtype has no PTO TypeCode"); + static_assert(reinterpret_tile_source_is_local_v, + "reinterpret_tile first phase supports Local Tiles only" + " (Shared requires a separate Shared view)"); + static_assert(reinterpret_tile_layout_legal_v, + "reinterpret_tile requires equal-bit-width dtypes " + "compatible with the source layout"); + static_assert(reinterpret_tile_storage_compatible_v, + "reinterpret_tile must preserve the source Tile storage"); + return ReinterpretedTileView(Source); +} + +} // namespace pto + #endif From cb47f6d548e0bff357122a4cf97351f0aca27c7e Mon Sep 17 00:00:00 2001 From: ziyang-cheng Date: Mon, 17 Aug 2026 16:30:11 +0800 Subject: [PATCH 4/4] [tileop-api] Emit lb2 (physical col width) from TCVT_T TCVT_T was the only TEPL elementwise op that did not emit the lb2 (physical column width) shape descriptor, unlike TABS/TEXP/TRECIP/ TADDS/TMULS/TANDS/TMAX/TROWMAX. For a boxed valid-col-1 tile whose last producer is TCVT, the emulator falls back to physicalCol=validCol (Block.cpp), collapsing col to 1; a subsequent TSTORE declaring tile::Cols then fails IsCompatibleDataTile (col 1 != Cols). Append `B.DIM zero, %c7, ->lb2` with input `"i"(tile_shape_out::Cols)` to align TCVT_T with the other elementwise ops. Co-Authored-By: Claude Opus 4 --- include/jcore/template_asm.hpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/include/jcore/template_asm.hpp b/include/jcore/template_asm.hpp index de72e47..9947890 100644 --- a/include/jcore/template_asm.hpp +++ b/include/jcore/template_asm.hpp @@ -115,13 +115,15 @@ void TCVT_T(tile_shape_out &dst, tile_shape_in &src) { "B.IOT %3, mask=15, last, ->%0<%Z4>\n" "B.DIM %5, 0, ->lb0\n" "B.DIM %6, 0, ->lb1\n" + "B.DIM zero, %c7, ->lb2\n" : "=Tr"(dst.data()) : "i"(type_traits::TypeCode), "i"(type_traits::TypeCode), "Tr"(src.data()), "i"(tile_type_traits::TilesizeCode), "r"(valid_col), - "r"(valid_row) + "r"(valid_row), + "i"(tile_shape_out::Cols) ); }