diff --git a/.github/workflows/pr-gate.yml b/.github/workflows/pr-gate.yml index a1fbdc6..ec887e9 100644 --- a/.github/workflows/pr-gate.yml +++ b/.github/workflows/pr-gate.yml @@ -185,6 +185,18 @@ jobs: toolchain/output/linx_blockisa_llvm_musl key: llvm-${{ runner.os }}-tileop-required-gate-v2-${{ steps.llvm-source.outputs.sha }} + - name: Install candidate TileOP headers into the cached toolchain + run: | + set -euo pipefail + RESOURCE_DIR="$(${TOOLCHAIN_INSTALL_DIR}/bin/clang -print-resource-dir)" + mkdir -p "${RESOURCE_DIR}/include/tileop-api" + rsync -a --delete \ + toolchain/src/Linx-TileOP-API/include/ \ + "${RESOURCE_DIR}/include/tileop-api/" + cmp \ + toolchain/src/Linx-TileOP-API/include/common/pto_tile.hpp \ + "${RESOURCE_DIR}/include/tileop-api/common/pto_tile.hpp" + - name: Run TileOP contract checks working-directory: toolchain/src/Linx-TileOP-API env: diff --git a/docs/tileop-usage/tlsu/load-store-move/TLOAD.md b/docs/tileop-usage/tlsu/load-store-move/TLOAD.md index 0c8fb88..d3294f1 100644 --- a/docs/tileop-usage/tlsu/load-store-move/TLOAD.md +++ b/docs/tileop-usage/tlsu/load-store-move/TLOAD.md @@ -26,6 +26,11 @@ PTO_SHARED_INLINE void TLOAD(SharedTile &dst, const gm_shape &src); 除通用 Tile 约束外,必须满足 PTO-SPEC 对本操作规定的操作数角色、数据类型组合、形状、布局、有效区域、容量、存储位置、PE mask 以及 alias 规则。对于需要 Shared Tile、标量、索引、scale、bias 或选项对象的重载,只能使用接口声明的参数形式;不能通过省略参数来伪造另一种操作数组合。 +`B.IOR.RegSrc1` carries the GM row stride in **bytes**, not elements. The +ordinary, Shared, and CUBE transport overloads therefore derive the encoded +stride with `GetStrideBytes`; callers must not pre-scale or reinterpret that +value in element units. + ## 默认值 未显式传入的可选参数使用该 C++ 重载和 PTO-SPEC contract 规定的默认值。默认选项、维度、布局、padding、scale mask 和属性字段可能与显式编码的零值不同;调用者不得把“省略”与“传入零值”自动等同。 diff --git a/include/jcore/template_asm.hpp b/include/jcore/template_asm.hpp index f2d7c36..7ce87de 100644 --- a/include/jcore/template_asm.hpp +++ b/include/jcore/template_asm.hpp @@ -6945,24 +6945,29 @@ void TPRELU(tile_shape &dst, tile_shape &src0, tile_shape &src1) { } -// TSEL: select between two tiles using mask +// TSEL: select true_src where mask is set, otherwise preserve the prior dst. +// PTO requires the false source to be bound explicitly. Model the public +// in-place API as two B.IOT bindings and keep dst read/write so the second +// binding snapshots its old value before publishing the new destination. template -void TSEL(tile_shape &dst, tile_shape &src0, tile_shape &src1) { +void TSEL(tile_shape &dst, tile_shape &mask, tile_shape &true_src) { asm volatile( - "BSTART.TEPL 26, %D1\n" - "B.DIM %2, 0, ->lb0\n" - "B.DIM %3, 0, ->lb1\n" - "B.DIM zero, %c4, ->lb2\n" - "B.IOT %5, %6, mask=1111, last, ->%0<%Z7>\n" + "BSTART.TEPL 26, %D[DataType]\n" + "B.DIM %[ValidCol], 0, ->lb0\n" + "B.DIM %[ValidRow], 0, ->lb1\n" + "B.DIM zero, %c[Cols], ->lb2\n" + "B.IOT %[Mask], %[True], mask=1111\n" + "B.IOT %[Prior], mask=1111, last, ->%[Dst]<%Z[TileSize]>\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) + : [Dst] "=Tr"(dst.data()) + : [Prior] "0"(dst.data()), + [DataType] "i"(type_traits::TypeCode), + [ValidCol] "r"(mask.GetValidCol()), + [ValidRow] "r"(mask.GetValidRow()), + [Cols] "i"(tile_shape::Cols), + [Mask] "Tr"(mask.data()), + [True] "Tr"(true_src.data()), + [TileSize] "i"(tile_type_traits::TilesizeCode) ); } diff --git a/test/test_v058_engine_contract.py b/test/test_v058_engine_contract.py index 1ba9fc2..c43c8d1 100644 --- a/test/test_v058_engine_contract.py +++ b/test/test_v058_engine_contract.py @@ -200,6 +200,21 @@ def test_tlsu_load_store_stride_is_expressed_in_bytes(self) -> None: 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) + def test_tsel_binds_the_prior_destination_as_explicit_false_source(self) -> None: + start = self.header.index("void TSEL(") + end = self.header.index("// TABS:", start) + tsel = self.header[start:end] + self.assertIn('"B.IOT %[Mask], %[True], mask=1111\\n"', tsel) + self.assertIn( + '"B.IOT %[Prior], mask=1111, last, ->%[Dst]<%Z[TileSize]>\\n"', + tsel, + ) + self.assertIn(': [Dst] "=Tr"(dst.data())', tsel) + self.assertIn('[Prior] "0"(dst.data())', tsel) + self.assertNotIn( + '"B.IOT %5, %6, mask=1111, last, ->%0<%Z7>\\n"', tsel + ) + def test_fpatr_carries_shared_transpose_controls(self) -> None: tile = PTO_TILE.read_text(encoding="utf-8") self.assertIn("bool TransA = false", tile) diff --git a/test/tileop_api/src/TSELCanonical.cpp b/test/tileop_api/src/TSELCanonical.cpp new file mode 100644 index 0000000..6102d1c --- /dev/null +++ b/test/tileop_api/src/TSELCanonical.cpp @@ -0,0 +1,11 @@ +#include + +using namespace pto; + +using SelectTile = Tile; + +void tsel_canonical(SelectTile &dst, SelectTile &mask, + SelectTile &true_src) { + TSEL(dst, mask, true_src); +} diff --git a/test/tileop_api/verify_target_cxx_frontend.sh b/test/tileop_api/verify_target_cxx_frontend.sh index 35f7616..a5321c2 100755 --- a/test/tileop_api/verify_target_cxx_frontend.sh +++ b/test/tileop_api/verify_target_cxx_frontend.sh @@ -8,9 +8,26 @@ ROOT=$(cd "$(dirname "$0")/../.." && pwd) OUT=$(mktemp -d "${TMPDIR:-/tmp}/tileop-target-cxx.XXXXXX") trap 'rm -rf "$OUT"' EXIT +# -mlxbc injects the TileOP headers installed in Clang's resource directory +# ahead of ordinary -I paths. Build a temporary resource overlay that keeps +# the toolchain's builtin headers but replaces only tileop-api with this +# checkout, otherwise this gate silently validates the packaged API instead of +# the proposed source tree. +CLANG_RESOURCE_DIR=$("$TC_DIR/clang++" -print-resource-dir) +CLANG_RESOURCE_OVERLAY="$OUT/clang-resource" +mkdir -p "$CLANG_RESOURCE_OVERLAY/include" +for resource_path in "$CLANG_RESOURCE_DIR"/include/*; do + resource_name=${resource_path##*/} + if [[ "$resource_name" != tileop-api ]]; then + ln -s "$resource_path" "$CLANG_RESOURCE_OVERLAY/include/$resource_name" + fi +done +ln -s "$ROOT/include" "$CLANG_RESOURCE_OVERLAY/include/tileop-api" + FLAGS=( --target="$LINX_TARGET" -mlxbc + -resource-dir="$CLANG_RESOURCE_OVERLAY" --sysroot="$LINX_SYSROOT" -nostdinc++ -isystem "$LINX_SYSROOT/include/c++/v1" @@ -22,7 +39,7 @@ FLAGS=( -I"$ROOT/include" ) -for source in MXScaleVariants.cpp SharedTransposeNonSquare.cpp; do +for source in MXScaleVariants.cpp SharedTransposeNonSquare.cpp TSELCanonical.cpp; do "$TC_DIR/clang++" "${FLAGS[@]}" -fsyntax-only \ "$ROOT/test/tileop_api/src/$source" done @@ -33,7 +50,10 @@ done "$ROOT/test/tileop_api/src/MXScaleVariants.cpp" -o "$OUT/MXScaleVariants.ll" "$TC_DIR/clang++" "${FLAGS[@]}" -c \ "$ROOT/test/tileop_api/src/MXScaleVariants.cpp" -o "$OUT/MXScaleVariants.o" +"$TC_DIR/clang++" "${FLAGS[@]}" -c \ + "$ROOT/test/tileop_api/src/TSELCanonical.cpp" -o "$OUT/TSELCanonical.o" "$TC_DIR/llvm-objdump" -d "$OUT/MXScaleVariants.o" > "$OUT/MXScaleVariants.dis" +"$TC_DIR/llvm-objdump" -d "$OUT/TSELCanonical.o" > "$OUT/TSELCanonical.dis" grep -q '<1024 x i32> asm sideeffect' "$OUT/SharedTLoad.ll" grep -q 'i64 asm sideeffect.*=@2Sr' "$OUT/SharedTLoad.ll" grep -q '<1024 x i32> asm sideeffect.*@2Sr' "$OUT/SharedTLoad.ll" @@ -93,4 +113,15 @@ grep -Eiq 'BSTART\.CUBE[[:space:]]+TMATMULMX\.ACC,[[:space:]]+E4M3' "$OUT/MXScal grep -Eiq 'BSTART\.CUBE[[:space:]]+TGEMVMX\.BIAS,[[:space:]]+BF16' "$OUT/MXScaleVariants.dis" grep -Eq 'B\.IOT[[:space:]]+t#[1-8], t#[1-8], mask=1111' "$OUT/MXScaleVariants.dis" +grep -Eq 'B\.IOT[[:space:]]+[tumn]#[1-8], [tumn]#[1-8], mask=1111[[:space:]]*$' \ + "$OUT/TSELCanonical.dis" +grep -Eq 'B\.IOT[[:space:]]+[tumn]#[1-8], mask=1111, last,.*->[tumn]<[0-9]+(B|KB)>' \ + "$OUT/TSELCanonical.dis" +if grep -Eq 'B\.IOT[[:space:]]+[tumn]#[1-8], [tumn]#[1-8], mask=1111, last,.*->' \ + "$OUT/TSELCanonical.dis"; then + echo "FAIL: TSEL collapsed to the forbidden single-B.IOT in-place form" >&2 + sed -n '1,120p' "$OUT/TSELCanonical.dis" >&2 + exit 1 +fi + echo "Linx target C++ frontend MX/effective-shape contract: PASS" diff --git a/tools/generate_engine_docs.py b/tools/generate_engine_docs.py index 79f8cb4..dc0c030 100644 --- a/tools/generate_engine_docs.py +++ b/tools/generate_engine_docs.py @@ -84,6 +84,25 @@ def render() -> str: "The `BSTART.VEC` / `BSTART.SFU` spellings are canonical aliases of", "the unique `BSTART.TEPL` compiled carrier (ADR 0057).", "", + "## 使用要求", + "", + "优先根据操作页面中的 C++ API 调用 TileOP;本页仅用于按执行引擎查找操作。不要仅凭分类名称推断执行引擎,具体 engine 和支持的 Tile location 以操作页面为准。", + "", + "## 约束、默认值、异常和边界行为", + "", + "每个 engine 都有自己的 Tile、PE participation、容量和 bundle 约束。省略的 bundle 字段采用具体操作 contract 的默认值;非法 engine、binder、Tile location、mask 或属性组合会在执行前被拒绝。操作的边界、padding、异常和结果语义不由本索引页定义。", + "", + "## 使用示例", + "", + "```cpp", + "// 例如从 VEC 操作页面调用 C++ wrapper。", + "TADD(dst, lhs, rhs);", + "```", + "", + "## 完整语义", + "", + "各操作的完整语义请参阅其操作页面末尾的 PTO-SPEC 链接,规范总目录见 [PTO-SPEC tile 文档](https://github.com/PTO-ISA/pto-spec/tree/v0.58.4.1/docs/tile)。", + "", ] )