diff --git a/README.md b/README.md
index 5f2dc17a..0da34fe1 100644
--- a/README.md
+++ b/README.md
@@ -130,7 +130,7 @@ details.
## One-level benchmark catalog
-The one-level manifests contain **53 build variants**. Every name below
+The one-level manifests contain **62 build variants**. Every name below
has a source-complete page with its build command and PTO intrinsic surface in
the website's **Benchmarks** section.
@@ -176,6 +176,12 @@ the website's **Benchmarks** section.
+One-level / pto_kernels (9 names, 9 variants)
+
+`pto_add`, `pto_flash_attention`, `pto_gemm`, `pto_gemm_basic`, `pto_gemm_demo`, `pto_gemm_performance`, `pto_mamulb`, `pto_tload_store`, `pto_tmatmul_acc`
+
+
+
One-level / reduction/reducemax_col (1 name, 1 variant)
`reducemax_col`
diff --git a/benchmark/one-level-arch/compile_all.sh b/benchmark/one-level-arch/compile_all.sh
index 488720fe..eb6396f3 100755
--- a/benchmark/one-level-arch/compile_all.sh
+++ b/benchmark/one-level-arch/compile_all.sh
@@ -61,6 +61,7 @@ compile_operator "$REPO_ROOT/test/kernel/reduction/reducesum_row" "reducesum_row
compile_operator "$REPO_ROOT/test/kernel/control" "control" || failures+=("control")
compile_operator "$REPO_ROOT/test/kernel/fa" "fa" || failures+=("fa")
compile_operator "$REPO_ROOT/test/kernel/sort" "sort" || failures+=("sort")
+compile_operator "$REPO_ROOT/test/kernel/pto_kernels" "pto_kernels" || failures+=("pto_kernels")
echo ""
echo "=========================================="
diff --git a/benchmark/one-level-arch/include/pto_kernel/common/linx_lowp_types.hpp b/benchmark/one-level-arch/include/pto_kernel/common/linx_lowp_types.hpp
new file mode 100644
index 00000000..5d62c14d
--- /dev/null
+++ b/benchmark/one-level-arch/include/pto_kernel/common/linx_lowp_types.hpp
@@ -0,0 +1,212 @@
+#ifndef PTO_COMMON_LINX_LOWP_TYPES_HPP
+#define PTO_COMMON_LINX_LOWP_TYPES_HPP
+
+#include
+
+namespace pto {
+
+struct fp16_t {
+ uint16_t bits;
+};
+
+#if !defined(__CPU_SIM)
+using half = fp16_t;
+#endif
+
+struct fp8_e4m3_t {
+ uint8_t bits;
+};
+
+struct fp4_e2m1_t {
+ uint8_t bits;
+};
+
+inline float fp16_to_float(fp16_t x) {
+ const uint16_t v = x.bits;
+ const uint32_t sign = static_cast(v & 0x8000u) << 16;
+ const uint32_t exp = (v >> 10) & 0x1fu;
+ const uint32_t mant = v & 0x03ffu;
+
+ uint32_t out_bits = 0u;
+ if (exp == 0u) {
+ if (mant == 0u) {
+ out_bits = sign;
+ } else {
+ int e = -14;
+ uint32_t m = mant;
+ while ((m & 0x0400u) == 0u) {
+ m <<= 1u;
+ --e;
+ }
+ m &= 0x03ffu;
+ const uint32_t exp32 = static_cast(e + 127);
+ out_bits = sign | (exp32 << 23) | (m << 13);
+ }
+ } else if (exp == 0x1fu) {
+ out_bits = sign | 0x7f800000u | (mant << 13);
+ } else {
+ const uint32_t exp32 = exp + (127u - 15u);
+ out_bits = sign | (exp32 << 23) | (mant << 13);
+ }
+
+ union {
+ uint32_t u;
+ float f;
+ } cvt = {out_bits};
+ return cvt.f;
+}
+
+inline fp16_t float_to_fp16(float x) {
+ union {
+ float f;
+ uint32_t u;
+ } cvt = {x};
+
+ const uint32_t sign = (cvt.u >> 16) & 0x8000u;
+ const int exp32 = static_cast((cvt.u >> 23) & 0xffu);
+ const uint32_t mant32 = cvt.u & 0x7fffffu;
+
+ if (exp32 == 0xff) {
+ const uint16_t nan_inf = static_cast(sign | 0x7c00u | (mant32 ? 0x0200u : 0u));
+ return fp16_t{nan_inf};
+ }
+
+ const int exp16 = exp32 - 127 + 15;
+ if (exp16 <= 0) {
+ if (exp16 < -10)
+ return fp16_t{static_cast(sign)};
+ uint32_t mant = mant32 | 0x800000u;
+ const int shift = 14 - exp16;
+ uint32_t rounded = mant >> static_cast(shift);
+ if (((mant >> static_cast(shift - 1)) & 1u) != 0u)
+ ++rounded;
+ return fp16_t{static_cast(sign | (rounded & 0x03ffu))};
+ }
+
+ if (exp16 >= 31)
+ return fp16_t{static_cast(sign | 0x7c00u)};
+
+ uint32_t mant = mant32;
+ mant += 0x1000u; // round-to-nearest-even at fp16 mantissa boundary
+ if (mant & 0x800000u) {
+ mant = 0u;
+ if (exp16 + 1 >= 31)
+ return fp16_t{static_cast(sign | 0x7c00u)};
+ return fp16_t{static_cast(sign | (static_cast(exp16 + 1) << 10))};
+ }
+
+ return fp16_t{static_cast(sign | (static_cast(exp16) << 10) | (mant >> 13))};
+}
+
+inline float fp8_e4m3_to_float(fp8_e4m3_t x) {
+ auto pow2i = [](int e) -> float {
+ float s = 1.0f;
+ if (e >= 0) {
+ for (int i = 0; i < e; ++i)
+ s *= 2.0f;
+ } else {
+ for (int i = 0; i < -e; ++i)
+ s *= 0.5f;
+ }
+ return s;
+ };
+ const uint8_t bits = x.bits;
+ const float sign = (bits & 0x80u) ? -1.0f : 1.0f;
+ const uint8_t exp = static_cast((bits >> 3) & 0x0fu);
+ const uint8_t mant = static_cast(bits & 0x07u);
+
+ if (exp == 0u) {
+ if (mant == 0u)
+ return 0.0f * sign;
+ return sign * (static_cast(mant) / 8.0f) * pow2i(-6);
+ }
+ if (exp == 0x0fu) {
+ const float sat = (1.0f + (7.0f / 8.0f)) * pow2i(7);
+ return sign * sat;
+ }
+ return sign * (1.0f + static_cast(mant) / 8.0f) *
+ pow2i(static_cast(exp) - 7);
+}
+
+inline fp8_e4m3_t float_to_fp8_e4m3(float x) {
+ if (x == 0.0f)
+ return fp8_e4m3_t{0u};
+
+ const bool neg = x < 0.0f;
+ float ax = neg ? -x : x;
+ int e = 0;
+ float norm = ax;
+ while (norm >= 2.0f && e < 30) {
+ norm *= 0.5f;
+ ++e;
+ }
+ while (norm < 1.0f && e > -30) {
+ norm *= 2.0f;
+ --e;
+ }
+ int ef = e + 7;
+
+ uint8_t sign = neg ? 0x80u : 0u;
+
+ if (ef <= 0) {
+ int mant = static_cast(ax * 512.0f + 0.5f); // ax * 2^(6+3)
+ if (mant < 0)
+ mant = 0;
+ if (mant > 7)
+ mant = 7;
+ return fp8_e4m3_t{static_cast(sign | mant)};
+ }
+
+ if (ef >= 0x0f)
+ return fp8_e4m3_t{static_cast(sign | 0x7eu)};
+
+ float frac = norm - 1.0f;
+ int mant = static_cast(frac * 8.0f + 0.5f);
+ if (mant >= 8) {
+ mant = 0;
+ ++ef;
+ if (ef >= 0x0f)
+ return fp8_e4m3_t{static_cast(sign | 0x7eu)};
+ }
+ if (mant < 0)
+ mant = 0;
+ return fp8_e4m3_t{static_cast(sign | (static_cast(ef) << 3) | static_cast(mant))};
+}
+
+inline float fp4_e2m1_to_float(fp4_e2m1_t x) {
+ const uint8_t b = static_cast(x.bits & 0x0fu);
+ static constexpr float kTable[16] = {
+ 0.0f, 0.5f, 1.0f, 1.5f, 2.0f, 3.0f, 4.0f, 6.0f,
+ -0.0f, -0.5f, -1.0f, -1.5f, -2.0f, -3.0f, -4.0f, -6.0f};
+ return kTable[b];
+}
+
+inline fp4_e2m1_t float_to_fp4_e2m1(float x) {
+ static constexpr float kTable[16] = {
+ 0.0f, 0.5f, 1.0f, 1.5f, 2.0f, 3.0f, 4.0f, 6.0f,
+ -0.0f, -0.5f, -1.0f, -1.5f, -2.0f, -3.0f, -4.0f, -6.0f};
+
+ auto absf = [](float v) -> float { return v < 0.0f ? -v : v; };
+ uint8_t best = 0u;
+ float best_err = absf(x - kTable[0]);
+ for (uint8_t i = 1u; i < 16u; ++i) {
+ const float err = absf(x - kTable[i]);
+ if (err < best_err) {
+ best_err = err;
+ best = i;
+ }
+ }
+ return fp4_e2m1_t{static_cast(best & 0x0fu)};
+}
+
+inline uint32_t lowp_word_from_fp16(fp16_t x) { return static_cast(x.bits); }
+inline uint32_t lowp_word_from_fp8(fp8_e4m3_t x) { return static_cast(x.bits); }
+inline uint32_t lowp_word_from_fp4(fp4_e2m1_t x) { return static_cast(x.bits & 0x0fu); }
+
+inline fp16_t fp16_from_lowp_word(uint32_t word) { return fp16_t{static_cast(word & 0xffffu)}; }
+inline fp8_e4m3_t fp8_from_lowp_word(uint32_t word) { return fp8_e4m3_t{static_cast(word & 0xffu)}; }
+inline fp4_e2m1_t fp4_from_lowp_word(uint32_t word) { return fp4_e2m1_t{static_cast(word & 0x0fu)}; }
+
+} // namespace pto
+
+#endif // PTO_COMMON_LINX_LOWP_TYPES_HPP
diff --git a/benchmark/one-level-arch/include/pto_kernel/common/pto_tileop.hpp b/benchmark/one-level-arch/include/pto_kernel/common/pto_tileop.hpp
new file mode 100644
index 00000000..0f4aaf2c
--- /dev/null
+++ b/benchmark/one-level-arch/include/pto_kernel/common/pto_tileop.hpp
@@ -0,0 +1,865 @@
+#ifndef PTO_COMMON_PTO_TILEOP_HPP
+#define PTO_COMMON_PTO_TILEOP_HPP
+
+#include
+
+#include
+
+namespace pto {
+
+constexpr int DYNAMIC = -1;
+
+enum class Location : uint8_t {
+ Vec,
+ Left,
+ Right,
+ Acc,
+};
+
+enum class BLayout : uint8_t {
+ RowMajor = 0,
+ ColMajor = 1,
+};
+
+template struct RowMajor {
+ static constexpr int Rows = Rows_;
+ static constexpr int Cols = Cols_;
+ static constexpr bool IsRowMajor = true;
+};
+
+template struct ColMajor {
+ static constexpr int Rows = Rows_;
+ static constexpr int Cols = Cols_;
+ static constexpr bool IsRowMajor = false;
+};
+
+template struct global_tensor {
+ using DType = Element_;
+ using Layout = Layout_;
+};
+
+namespace detail {
+
+using ptrdiff_builtin_t = __PTRDIFF_TYPE__;
+
+template using void_t = void;
+
+template struct StaticIndex {
+ static constexpr int value = Value;
+ constexpr operator int() const { return Value; }
+};
+
+template
+inline __attribute__((always_inline)) void static_for(Fn &&fn) {
+ if constexpr (Begin < End) {
+ fn(StaticIndex{});
+ static_for(fn);
+ }
+}
+
+// TMA format selectors used by B.ARG in canonical v0.57.
+constexpr long long kLayoutNorm = 0ll; // NORM.normal
+constexpr long long kLayoutND2NZ = 2ll; // ND2NZ.normal
+constexpr long long kLayoutND2ZN = 3ll; // ND2ZN.normal
+constexpr long long kLayoutDN2ZN = 8ll; // DN2ZN.normal
+constexpr long long kLayoutDN2NZ = 9ll; // DN2NZ.normal
+
+template constexpr unsigned tileBytes() {
+ constexpr int rows = TileT::Rows;
+ constexpr int cols = TileT::Cols;
+ constexpr unsigned bytes =
+ static_cast(rows * cols * sizeof(typename TileT::DType));
+ static_assert(bytes > 0u,
+ "PTO Linx canonical v0.57: tile bytes must be positive");
+ return bytes;
+}
+
+template constexpr unsigned tileSizeCode() {
+ static_assert(tileBytes() <= linx::detail::kMaxTileBytes,
+ "PTO Linx canonical v0.57: tile size exceeds 4KB");
+ // Keep one 4 KiB carrier across data types. TCVT changes the element type,
+ // but not the architectural tile-register capacity or its SSA identity.
+ return 8u;
+}
+
+template constexpr unsigned tileDTypeCode() {
+ return linx::detail::DTypeCode::value;
+}
+
+template constexpr long long tileLayoutCode() {
+ return TileT::LayoutTag == BLayout::RowMajor ? 0ll : 1ll;
+}
+
+template constexpr long long gmStrideBytes() {
+ constexpr long long elemBytes =
+ static_cast(sizeof(typename GTensor::DType));
+ if constexpr (GTensor::Layout::IsRowMajor)
+ return static_cast(GTensor::Layout::Cols) * elemBytes;
+ return static_cast(GTensor::Layout::Rows) * elemBytes;
+}
+
+template
+constexpr long long tensorTileLayoutCode() {
+ if constexpr (TileT::Loc == Location::Left || TileT::Loc == Location::Acc) {
+ return GTensor::Layout::IsRowMajor ? kLayoutND2ZN : kLayoutDN2ZN;
+ }
+ if constexpr (TileT::Loc == Location::Right) {
+ return GTensor::Layout::IsRowMajor ? kLayoutND2NZ : kLayoutDN2NZ;
+ }
+ return kLayoutNorm;
+}
+
+template constexpr long long tileLB0() {
+ return TileT::ColValid > 0 ? static_cast(TileT::ColValid)
+ : static_cast(TileT::Cols);
+}
+
+template constexpr long long tileLB1() {
+ return TileT::RowValid > 0 ? static_cast(TileT::RowValid)
+ : static_cast(TileT::Rows);
+}
+
+template
+inline ptrdiff_builtin_t tileOffset(int tileRow, int tileCol) {
+ const int row = tileRow * TileT::Rows;
+ const int col = tileCol * TileT::Cols;
+ if constexpr (GTensor::Layout::IsRowMajor) {
+ return static_cast(row) * GTensor::Layout::Cols + col;
+ }
+ return static_cast(col) * GTensor::Layout::Rows + row;
+}
+
+template
+inline auto addressPtr(const AddressLike &addr) -> decltype(addr.ptr()) {
+ return addr.ptr();
+}
+
+template inline T *addressPtr(T *addr) { return addr; }
+
+template inline const T *addressPtr(const T *addr) { return addr; }
+
+template
+struct AddressDesc {
+ static constexpr long long Layout = tileLayoutCode();
+ static constexpr long long LB0 = tileLB0();
+ static constexpr long long LB1 = tileLB1();
+ static constexpr long long StrideBytes = 0ll;
+};
+
+template
+struct AddressDesc<
+ AddressLike, TileT,
+ void_t> {
+ static constexpr long long Layout = AddressLike::kLayoutCode;
+ static constexpr long long LB0 = AddressLike::kLB0;
+ static constexpr long long LB1 = AddressLike::kLB1;
+ static constexpr long long StrideBytes = AddressLike::kStrideBytes;
+};
+
+template
+constexpr long long addressLayoutCode() {
+ return AddressDesc::Layout;
+}
+
+template
+constexpr long long addressLB0() {
+ return AddressDesc::LB0;
+}
+
+template
+constexpr long long addressLB1() {
+ return AddressDesc::LB1;
+}
+
+template
+constexpr long long addressStrideBytes() {
+ return AddressDesc::StrideBytes;
+}
+
+} // namespace detail
+
+template
+struct Tile {
+ using DType = Element_;
+ using RawTile = linx::detail::RawTile;
+ using TileDType = Tile *;
+ using ConstTileDType = const Tile *;
+
+ static constexpr Location Loc = Loc_;
+ static constexpr int Rows = Rows_;
+ static constexpr int Cols = Cols_;
+ static constexpr int RowValid = RowValid_;
+ static constexpr int ColValid = ColValid_;
+ static constexpr int ValidRow = RowValid_;
+ static constexpr int ValidCol = ColValid_;
+ static constexpr BLayout LayoutTag = Layout_;
+ static constexpr int RowStride = LayoutTag == BLayout::RowMajor ? Cols_ : 1;
+ static constexpr int ColStride = LayoutTag == BLayout::RowMajor ? 1 : Rows_;
+
+ static_assert(RowValid_ == DYNAMIC || (RowValid_ > 0 && RowValid_ <= Rows_),
+ "PTO Linx: valid rows must fit the physical tile");
+ static_assert(ColValid_ == DYNAMIC || (ColValid_ > 0 && ColValid_ <= Cols_),
+ "PTO Linx: valid columns must fit the physical tile");
+
+ Tile()
+ : valid_rows_(RowValid_ == DYNAMIC ? Rows_ : RowValid_),
+ valid_cols_(ColValid_ == DYNAMIC ? Cols_ : ColValid_) {}
+
+ Tile(int validRows, int validCols)
+ : valid_rows_(validRows), valid_cols_(validCols) {}
+
+ template explicit Tile(Scalar scalar) {
+ raw_ = linx::detail::teplSplat<0x019u, detail::tileSizeCode(),
+ detail::tileDTypeCode(), 2u>(
+ scalar, GetValidCol(), GetValidRow(), Cols);
+ }
+
+ int GetValidRow() const { return valid_rows_; }
+ int GetValidCol() const { return valid_cols_; }
+
+ void SetValidShape(int validRows, int validCols) {
+ valid_rows_ = validRows;
+ valid_cols_ = validCols;
+ }
+
+ RawTile &raw() { return raw_; }
+ const RawTile &raw() const { return raw_; }
+ TileDType data() { return this; }
+ ConstTileDType data() const { return this; }
+
+private:
+ RawTile raw_{};
+ int valid_rows_ = RowValid_ == DYNAMIC ? Rows_ : RowValid_;
+ int valid_cols_ = ColValid_ == DYNAMIC ? Cols_ : ColValid_;
+};
+
+template
+using TileLeft = Tile;
+
+template
+using TileRight = Tile;
+
+template
+using TileAcc = Tile;
+
+template class global_iterator {
+public:
+ using Element = typename GTensor::DType;
+
+ explicit global_iterator(Element *base) : base_(base) {}
+
+ struct tile_address {
+ using TensorType = GTensor;
+ using TileType = TileT;
+ static constexpr long long kLayoutCode =
+ detail::tensorTileLayoutCode();
+ // TMA contract: LB0/LB1 are GM-side inner/outer counts.
+ // ND(row-major): inner=cols, outer=rows; DN(column-major): inner=rows,
+ // outer=cols.
+ static constexpr long long kLB0 = GTensor::Layout::IsRowMajor
+ ? detail::tileLB1()
+ : detail::tileLB0();
+ static constexpr long long kLB1 = GTensor::Layout::IsRowMajor
+ ? detail::tileLB0()
+ : detail::tileLB1();
+ static constexpr long long kStrideBytes = detail::gmStrideBytes();
+
+ Element *base;
+ int tileRow;
+ int tileCol;
+
+ Element *ptr() const {
+ return base + detail::tileOffset(tileRow, tileCol);
+ }
+ };
+
+ tile_address operator()(int tileRow, int tileCol) const {
+ return tile_address{base_, tileRow, tileCol};
+ }
+
+private:
+ Element *base_;
+};
+
+namespace tepl {
+constexpr unsigned TADD = 0x000u;
+constexpr unsigned TSUB = 0x001u;
+constexpr unsigned TMUL = 0x002u;
+constexpr unsigned TDIV = 0x003u;
+constexpr unsigned TMAX = 0x004u;
+constexpr unsigned TMIN = 0x005u;
+constexpr unsigned TAND = 0x006u;
+constexpr unsigned TOR = 0x007u;
+constexpr unsigned TXOR = 0x008u;
+constexpr unsigned TSHL = 0x009u;
+constexpr unsigned TSHR = 0x00au;
+constexpr unsigned TRELU = 0x00bu;
+constexpr unsigned TPRELU = 0x00cu;
+constexpr unsigned TCVT = 0x00du;
+constexpr unsigned TEXP = 0x00eu;
+constexpr unsigned TLOG = 0x00fu;
+constexpr unsigned TSQRT = 0x010u;
+constexpr unsigned TRSQRT = 0x011u;
+constexpr unsigned TROWMAX = 0x012u;
+constexpr unsigned TROWMIN = 0x013u;
+constexpr unsigned TROWSUM = 0x014u;
+constexpr unsigned TCOLMAX = 0x015u;
+constexpr unsigned TCOLMIN = 0x016u;
+constexpr unsigned TCOLSUM = 0x017u;
+constexpr unsigned TRECIP = 0x018u;
+constexpr unsigned TEXPANDS = 0x019u;
+constexpr unsigned TGATHER = 0x01au;
+constexpr unsigned TSCATTER = 0x01bu;
+constexpr unsigned TRESHAPE = 0x01cu;
+constexpr unsigned TTRANSPOSE = 0x01du;
+constexpr unsigned TCOLEXPAND = 0x01eu;
+constexpr unsigned TROWEXPAND = 0x01fu;
+constexpr unsigned TADDS = 0x020u;
+constexpr unsigned TSUBS = 0x021u;
+constexpr unsigned TMULS = 0x022u;
+constexpr unsigned TDIVS = 0x023u;
+constexpr unsigned TMAXS = 0x024u;
+constexpr unsigned TMINS = 0x025u;
+constexpr unsigned TANDS = 0x026u;
+constexpr unsigned TORS = 0x027u;
+constexpr unsigned TXORS = 0x028u;
+constexpr unsigned TSHLS = 0x029u;
+constexpr unsigned TSHRS = 0x02au;
+constexpr unsigned TCMP = 0x02bu;
+constexpr unsigned TSEL = 0x02cu;
+constexpr unsigned TABS = 0x02du;
+constexpr unsigned TNOT = 0x02eu;
+constexpr unsigned TCMPS = 0x033u;
+constexpr unsigned TSELS = 0x034u;
+constexpr unsigned TCONCAT = 0x087u;
+constexpr unsigned TSORT = 0x0c0u;
+constexpr unsigned TMRGSORT = 0x0c1u;
+constexpr unsigned THISTOGRAM = 0x0c2u;
+constexpr unsigned TPARTADD = 0x0c3u;
+constexpr unsigned TPARTMUL = 0x0c4u;
+constexpr unsigned TPARTMAX = 0x0c5u;
+constexpr unsigned TPARTMIN = 0x0c6u;
+constexpr unsigned TPARTARGMAX = 0x0c7u;
+constexpr unsigned TPARTARGMIN = 0x0c8u;
+} // namespace tepl
+
+// Core tile ops used by PR5 FlashAttention bring-up.
+template
+inline void TLOAD(DstTile &dst, const SrcAddress &src) {
+ dst.raw() =
+ linx::detail::tileTLoad(),
+ detail::tileDTypeCode(),
+ detail::addressLayoutCode()>(
+ reinterpret_cast(detail::addressPtr(src)),
+ dst.GetValidCol(), dst.GetValidRow(), DstTile::Cols,
+ detail::addressStrideBytes());
+}
+
+template
+inline void TSTORE(const DstAddress &dst, SrcTile &src) {
+ linx::detail::tileTStore(),
+ detail::tileDTypeCode(),
+ detail::addressLayoutCode()>(
+ reinterpret_cast(detail::addressPtr(dst)), src.raw(),
+ src.GetValidCol(), src.GetValidRow(), SrcTile::Cols,
+ detail::addressStrideBytes());
+}
+
+template
+inline void TMOV(DstTile &dst, const SrcTile &src, unsigned mode = 0u) {
+ dst.SetValidShape(src.GetValidRow(), src.GetValidCol());
+ if (mode == 1u) {
+ dst.raw() =
+ linx::detail::tileTMov(),
+ detail::tileDTypeCode(),
+ detail::tileLayoutCode(), 1u, 1u>(
+ src.raw());
+ } else {
+ dst.raw() =
+ linx::detail::tileTMov(),
+ detail::tileDTypeCode(),
+ detail::tileLayoutCode(), 1u, 0u>(
+ src.raw());
+ }
+}
+
+template
+inline void TMATMUL(TileRes &dst, const TileLeft_ &lhs, const TileRight_ &rhs) {
+ // Canonical v0.57 compiler policy:
+ // tile_bytes = ceil(m*n*k*elem_bits/8) must fit <=4KB
+ // (m=Rows, n=Cols, k=lhs.Cols).
+ constexpr unsigned M = static_cast(TileRes::Rows);
+ constexpr unsigned N = static_cast(TileRes::Cols);
+ constexpr unsigned K = static_cast(TileLeft_::Cols);
+ dst.raw() = linx::detail::cubeMamulb(lhs.raw(), rhs.raw());
+}
+
+template
+inline void TMATMUL_ACC(TileRes &dst, TileRes &acc, const TileLeft_ &lhs,
+ const TileRight_ &rhs) {
+ constexpr unsigned M = static_cast(TileRes::Rows);
+ constexpr unsigned N = static_cast(TileRes::Cols);
+ constexpr unsigned K = static_cast(TileLeft_::Cols);
+ dst.raw() =
+ linx::detail::cubeMamulbAcc(acc.raw(), lhs.raw(), rhs.raw());
+}
+
+template
+inline void MATMACC(TileRes &dst, const TileLeft_ &lhs, const TileRight_ &rhs) {
+ // Keep strict CUBE accumulator-chain legality: materialize the product with
+ // TMATMUL, then accumulate explicitly with TEPL add.
+ TileRes product;
+ TMATMUL(product, lhs, rhs);
+ TADD(dst, dst, product);
+}
+
+template
+inline void TCVT(DstTile &dst, const SrcTile &src) {
+ dst.SetValidShape(src.GetValidRow(), src.GetValidCol());
+ dst.raw() =
+ linx::detail::teplUnary(),
+ detail::tileDTypeCode(),
+ detail::tileDTypeCode()>(
+ src.raw(), dst.GetValidCol(), dst.GetValidRow(), DstTile::Cols);
+}
+
+template
+inline void TADD(DstTile &dst, const SrcTile0 &src0, const SrcTile1 &src1) {
+ dst.SetValidShape(src0.GetValidRow(), src0.GetValidCol());
+ dst.raw() =
+ linx::detail::teplBinary(),
+ detail::tileDTypeCode()>(
+ src0.raw(), src1.raw(), dst.GetValidCol(), dst.GetValidRow(),
+ DstTile::Cols);
+}
+
+template
+inline void TSUB(DstTile &dst, const SrcTile0 &src0, const SrcTile1 &src1) {
+ dst.SetValidShape(src0.GetValidRow(), src0.GetValidCol());
+ dst.raw() =
+ linx::detail::teplBinary(),
+ detail::tileDTypeCode()>(
+ src0.raw(), src1.raw(), dst.GetValidCol(), dst.GetValidRow(),
+ DstTile::Cols);
+}
+
+template
+inline void TMUL(DstTile &dst, const SrcTile0 &src0, const SrcTile1 &src1) {
+ dst.SetValidShape(src0.GetValidRow(), src0.GetValidCol());
+ dst.raw() =
+ linx::detail::teplBinary(),
+ detail::tileDTypeCode()>(
+ src0.raw(), src1.raw(), dst.GetValidCol(), dst.GetValidRow(),
+ DstTile::Cols);
+}
+
+template
+inline void TMAX(DstTile &dst, const SrcTile0 &src0, const SrcTile1 &src1) {
+ dst.SetValidShape(src0.GetValidRow(), src0.GetValidCol());
+ dst.raw() =
+ linx::detail::teplBinary(),
+ detail::tileDTypeCode()>(
+ src0.raw(), src1.raw(), dst.GetValidCol(), dst.GetValidRow(),
+ DstTile::Cols);
+}
+
+template
+inline void TDIV(DstTile &dst, const SrcTile0 &src0, const SrcTile1 &src1) {
+ dst.SetValidShape(src0.GetValidRow(), src0.GetValidCol());
+ dst.raw() =
+ linx::detail::teplBinary(),
+ detail::tileDTypeCode()>(
+ src0.raw(), src1.raw(), dst.GetValidCol(), dst.GetValidRow(),
+ DstTile::Cols);
+}
+
+template
+inline void TMIN(DstTile &dst, const SrcTile0 &src0, const SrcTile1 &src1) {
+ dst.SetValidShape(src0.GetValidRow(), src0.GetValidCol());
+ dst.raw() =
+ linx::detail::teplBinary(),
+ detail::tileDTypeCode()>(
+ src0.raw(), src1.raw(), dst.GetValidCol(), dst.GetValidRow(),
+ DstTile::Cols);
+}
+
+template
+inline void TAND(DstTile &dst, const SrcTile0 &src0, const SrcTile1 &src1) {
+ dst.SetValidShape(src0.GetValidRow(), src0.GetValidCol());
+ dst.raw() =
+ linx::detail::teplBinary(),
+ detail::tileDTypeCode()>(
+ src0.raw(), src1.raw(), dst.GetValidCol(), dst.GetValidRow(),
+ DstTile::Cols);
+}
+
+template
+inline void TOR(DstTile &dst, const SrcTile0 &src0, const SrcTile1 &src1) {
+ dst.SetValidShape(src0.GetValidRow(), src0.GetValidCol());
+ dst.raw() =
+ linx::detail::teplBinary(),
+ detail::tileDTypeCode()>(
+ src0.raw(), src1.raw(), dst.GetValidCol(), dst.GetValidRow(),
+ DstTile::Cols);
+}
+
+template
+inline void TXOR(DstTile &dst, const SrcTile0 &src0, const SrcTile1 &src1) {
+ dst.SetValidShape(src0.GetValidRow(), src0.GetValidCol());
+ dst.raw() =
+ linx::detail::teplBinary(),
+ detail::tileDTypeCode()>(
+ src0.raw(), src1.raw(), dst.GetValidCol(), dst.GetValidRow(),
+ DstTile::Cols);
+}
+
+template
+inline void TSHL(DstTile &dst, const SrcTile0 &src0, const SrcTile1 &src1) {
+ dst.SetValidShape(src0.GetValidRow(), src0.GetValidCol());
+ dst.raw() =
+ linx::detail::teplBinary(),
+ detail::tileDTypeCode()>(
+ src0.raw(), src1.raw(), dst.GetValidCol(), dst.GetValidRow(),
+ DstTile::Cols);
+}
+
+template
+inline void TSHR(DstTile &dst, const SrcTile0 &src0, const SrcTile1 &src1) {
+ dst.SetValidShape(src0.GetValidRow(), src0.GetValidCol());
+ dst.raw() =
+ linx::detail::teplBinary(),
+ detail::tileDTypeCode()>(
+ src0.raw(), src1.raw(), dst.GetValidCol(), dst.GetValidRow(),
+ DstTile::Cols);
+}
+
+template
+inline void TROWMAX(DstTile &dst, const SrcTile &src) {
+ dst.SetValidShape(src.GetValidRow(), src.GetValidCol());
+ dst.raw() =
+ linx::detail::teplUnary(),
+ detail::tileDTypeCode()>(
+ src.raw(), dst.GetValidCol(), dst.GetValidRow(), DstTile::Cols);
+ dst.SetValidShape(src.GetValidRow(), 1);
+}
+
+template
+inline void TROWMIN(DstTile &dst, const SrcTile &src) {
+ dst.SetValidShape(src.GetValidRow(), src.GetValidCol());
+ dst.raw() =
+ linx::detail::teplUnary(),
+ detail::tileDTypeCode()>(
+ src.raw(), dst.GetValidCol(), dst.GetValidRow(), DstTile::Cols);
+ dst.SetValidShape(src.GetValidRow(), 1);
+}
+
+template
+inline void TROWSUM(DstTile &dst, const SrcTile &src) {
+ dst.SetValidShape(src.GetValidRow(), src.GetValidCol());
+ dst.raw() =
+ linx::detail::teplUnary(),
+ detail::tileDTypeCode()>(
+ src.raw(), dst.GetValidCol(), dst.GetValidRow(), DstTile::Cols);
+ dst.SetValidShape(src.GetValidRow(), 1);
+}
+
+template
+inline void TCOLMAX(DstTile &dst, const SrcTile &src) {
+ dst.SetValidShape(src.GetValidRow(), src.GetValidCol());
+ dst.raw() =
+ linx::detail::teplUnary(),
+ detail::tileDTypeCode()>(
+ src.raw(), dst.GetValidCol(), dst.GetValidRow(), DstTile::Cols);
+ dst.SetValidShape(1, src.GetValidCol());
+}
+
+template
+inline void TCOLMIN(DstTile &dst, const SrcTile &src) {
+ dst.SetValidShape(src.GetValidRow(), src.GetValidCol());
+ dst.raw() =
+ linx::detail::teplUnary(),
+ detail::tileDTypeCode()>(
+ src.raw(), dst.GetValidCol(), dst.GetValidRow(), DstTile::Cols);
+ dst.SetValidShape(1, src.GetValidCol());
+}
+
+template
+inline void TCOLSUM(DstTile &dst, const SrcTile &src) {
+ dst.SetValidShape(src.GetValidRow(), src.GetValidCol());
+ dst.raw() =
+ linx::detail::teplUnary(),
+ detail::tileDTypeCode()>(
+ src.raw(), dst.GetValidCol(), dst.GetValidRow(), DstTile::Cols);
+ dst.SetValidShape(1, src.GetValidCol());
+}
+
+template
+inline void TRELU(DstTile &dst, const SrcTile &src) {
+ dst.SetValidShape(src.GetValidRow(), src.GetValidCol());
+ dst.raw() =
+ linx::detail::teplUnary(),
+ detail::tileDTypeCode()>(
+ src.raw(), dst.GetValidCol(), dst.GetValidRow(), DstTile::Cols);
+}
+
+template
+inline void TEXP(DstTile &dst, const SrcTile &src) {
+ dst.SetValidShape(src.GetValidRow(), src.GetValidCol());
+ dst.raw() =
+ linx::detail::teplUnary(),
+ detail::tileDTypeCode()>(
+ src.raw(), dst.GetValidCol(), dst.GetValidRow(), DstTile::Cols);
+}
+
+template
+inline void TLOG(DstTile &dst, const SrcTile &src) {
+ dst.SetValidShape(src.GetValidRow(), src.GetValidCol());
+ dst.raw() =
+ linx::detail::teplUnary(),
+ detail::tileDTypeCode()>(
+ src.raw(), dst.GetValidCol(), dst.GetValidRow(), DstTile::Cols);
+}
+
+template
+inline void TSQRT(DstTile &dst, const SrcTile &src) {
+ dst.SetValidShape(src.GetValidRow(), src.GetValidCol());
+ dst.raw() =
+ linx::detail::teplUnary(),
+ detail::tileDTypeCode()>(
+ src.raw(), dst.GetValidCol(), dst.GetValidRow(), DstTile::Cols);
+}
+
+template
+inline void TRSQRT(DstTile &dst, const SrcTile &src) {
+ dst.SetValidShape(src.GetValidRow(), src.GetValidCol());
+ dst.raw() =
+ linx::detail::teplUnary(),
+ detail::tileDTypeCode()>(
+ src.raw(), dst.GetValidCol(), dst.GetValidRow(), DstTile::Cols);
+}
+
+template
+inline void TRECIP(DstTile &dst, const SrcTile &src) {
+ dst.SetValidShape(src.GetValidRow(), src.GetValidCol());
+ dst.raw() =
+ linx::detail::teplUnary(),
+ detail::tileDTypeCode()>(
+ src.raw(), dst.GetValidCol(), dst.GetValidRow(), DstTile::Cols);
+}
+
+template
+inline void TABS(DstTile &dst, const SrcTile &src) {
+ dst.SetValidShape(src.GetValidRow(), src.GetValidCol());
+ dst.raw() =
+ linx::detail::teplUnary(),
+ detail::tileDTypeCode()>(
+ src.raw(), dst.GetValidCol(), dst.GetValidRow(), DstTile::Cols);
+}
+
+template
+inline void TNOT(DstTile &dst, const SrcTile &src) {
+ dst.SetValidShape(src.GetValidRow(), src.GetValidCol());
+ dst.raw() =
+ linx::detail::teplUnary(),
+ detail::tileDTypeCode()>(
+ src.raw(), dst.GetValidCol(), dst.GetValidRow(), DstTile::Cols);
+}
+
+template
+inline void TRESHAPE(DstTile &dst, const SrcTile &src) {
+ dst.SetValidShape(src.GetValidRow(), src.GetValidCol());
+ dst.raw() =
+ linx::detail::teplUnary(),
+ detail::tileDTypeCode()>(
+ src.raw(), dst.GetValidCol(), dst.GetValidRow(), DstTile::Cols);
+}
+
+template
+inline void TTRANSPOSE(DstTile &dst, const SrcTile &src) {
+ dst.SetValidShape(src.GetValidRow(), src.GetValidCol());
+ dst.raw() =
+ linx::detail::teplUnary(),
+ detail::tileDTypeCode()>(
+ src.raw(), dst.GetValidCol(), dst.GetValidRow(), DstTile::Cols);
+ dst.SetValidShape(src.GetValidCol(), src.GetValidRow());
+}
+
+template
+inline void TSORT(DstTile &dst, const SrcTile &src) {
+ dst.SetValidShape(src.GetValidRow(), src.GetValidCol());
+ dst.raw() =
+ linx::detail::teplUnary(),
+ detail::tileDTypeCode()>(
+ src.raw(), dst.GetValidCol(), dst.GetValidRow(), DstTile::Cols);
+}
+
+template
+inline void THISTOGRAM(DstTile &dst, const SrcTile &src) {
+ dst.SetValidShape(src.GetValidRow(), src.GetValidCol());
+ dst.raw() =
+ linx::detail::teplUnary(),
+ detail::tileDTypeCode()>(
+ src.raw(), dst.GetValidCol(), dst.GetValidRow(), DstTile::Cols);
+ dst.SetValidShape(1, src.GetValidCol());
+}
+
+template
+inline void TGATHER(DstTile &dst, const SrcTile0 &src0, const SrcTile1 &src1) {
+ dst.SetValidShape(src0.GetValidRow(), src0.GetValidCol());
+ dst.raw() =
+ linx::detail::teplBinary(),
+ detail::tileDTypeCode()>(
+ src0.raw(), src1.raw(), dst.GetValidCol(), dst.GetValidRow(),
+ DstTile::Cols);
+}
+
+template
+inline void TSCATTER(DstTile &dst, const SrcTile0 &src0, const SrcTile1 &src1) {
+ dst.SetValidShape(src0.GetValidRow(), src0.GetValidCol());
+ dst.raw() =
+ linx::detail::teplBinary(),
+ detail::tileDTypeCode()>(
+ src0.raw(), src1.raw(), dst.GetValidCol(), dst.GetValidRow(),
+ DstTile::Cols);
+}
+
+template
+inline void TMULS(DstTile &dst, const SrcTile &src, Scalar scalar) {
+ dst.SetValidShape(src.GetValidRow(), src.GetValidCol());
+ dst.raw() =
+ linx::detail::teplBinaryScalar(),
+ detail::tileDTypeCode(), 1u>(
+ src.raw(), scalar, dst.GetValidCol(), dst.GetValidRow(),
+ DstTile::Cols);
+}
+
+template
+inline void TADDS(DstTile &dst, const SrcTile &src, Scalar scalar) {
+ dst.SetValidShape(src.GetValidRow(), src.GetValidCol());
+ dst.raw() =
+ linx::detail::teplBinaryScalar(),
+ detail::tileDTypeCode(), 1u>(
+ src.raw(), scalar, dst.GetValidCol(), dst.GetValidRow(),
+ DstTile::Cols);
+}
+
+template
+inline void TSUBS(DstTile &dst, const SrcTile &src, Scalar scalar) {
+ dst.SetValidShape(src.GetValidRow(), src.GetValidCol());
+ dst.raw() =
+ linx::detail::teplBinaryScalar(),
+ detail::tileDTypeCode(), 1u>(
+ src.raw(), scalar, dst.GetValidCol(), dst.GetValidRow(),
+ DstTile::Cols);
+}
+
+template
+inline void TDIVS(DstTile &dst, const SrcTile &src, Scalar scalar) {
+ dst.SetValidShape(src.GetValidRow(), src.GetValidCol());
+ dst.raw() =
+ linx::detail::teplBinaryScalar(),
+ detail::tileDTypeCode(), 1u>(
+ src.raw(), scalar, dst.GetValidCol(), dst.GetValidRow(),
+ DstTile::Cols);
+}
+
+template
+inline void TMAXS(DstTile &dst, const SrcTile &src, Scalar scalar) {
+ dst.SetValidShape(src.GetValidRow(), src.GetValidCol());
+ dst.raw() =
+ linx::detail::teplBinaryScalar(),
+ detail::tileDTypeCode(), 1u>(
+ src.raw(), scalar, dst.GetValidCol(), dst.GetValidRow(),
+ DstTile::Cols);
+}
+
+template
+inline void TMINS(DstTile &dst, const SrcTile &src, Scalar scalar) {
+ dst.SetValidShape(src.GetValidRow(), src.GetValidCol());
+ dst.raw() =
+ linx::detail::teplBinaryScalar(),
+ detail::tileDTypeCode(), 1u>(
+ src.raw(), scalar, dst.GetValidCol(), dst.GetValidRow(),
+ DstTile::Cols);
+}
+
+template
+inline void TXORS(DstTile &dst, const SrcTile &src, Scalar scalar) {
+ dst.SetValidShape(src.GetValidRow(), src.GetValidCol());
+ dst.raw() =
+ linx::detail::teplBinaryScalar(),
+ detail::tileDTypeCode(), 1u>(
+ src.raw(), scalar, dst.GetValidCol(), dst.GetValidRow(),
+ DstTile::Cols);
+}
+
+template
+inline void TSHLS(DstTile &dst, const SrcTile &src, Scalar scalar) {
+ dst.SetValidShape(src.GetValidRow(), src.GetValidCol());
+ dst.raw() =
+ linx::detail::teplBinaryScalar(),
+ detail::tileDTypeCode(), 1u>(
+ src.raw(), scalar, dst.GetValidCol(), dst.GetValidRow(),
+ DstTile::Cols);
+}
+
+template