Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions docs/en/dev/codegen/00-pto_codegen.md
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,8 @@ print(pto_code)
| `tile.add(a, b, c)` | `pto.taddc` (3-operand add) |
| `tile.adds(tile, scalar)` | `pto.tadds` (tile + scalar) |
| `tile.fillpad_expand(src, shape)` | `pto.tfillpad_expand ins(%src) outs(%dst)` (the `shape` tuple is type-deduction only; the larger `dst` and its pad come from the result type) |
| `tile.fillpad_inplace(src, pad_value=...)` | `pto.tfillpad_inplace` (shared source/result storage) |
| `tile.concat_idx(src0, src1, idx0, idx1, dst)` | `pto.tconcatidx` (reuses `dst`) |

**`tile.slice` / `tile.assemble` lowering details.** Both ops are lowered
through `pto.subview`, which is a pure view alias of the source tile (no
Expand Down
4 changes: 2 additions & 2 deletions docs/en/dev/ptoas-op-status.md
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ for lowering/compiler plumbing, plus other dialects such as VPTO, VMI, and SIMT.
| pto.tshrs | TSHRS | tile | ✅ | ✅ | ❌ | ❌ | — | path exists; historical ISA/semantic issue requires revalidation against the current pin |
| **Data Rearrangement (15)** | | | | | | | | |
| pto.tconcat | TCONCAT | tile+tensor | ✅ | ✅ | ✅ | ✅ | — | |
| pto.tconcatidx | TCONCAT (indexed) | tile | ✅ | | ❌ | ❌ | — | MISSING: lacks a complete frontend/codegen/ST path |
| pto.tconcatidx | TCONCAT (indexed) | tile | ✅ | | ❌ | ❌ | — | frontend, exact codegen, and the full dtype/index/valid-shape ST matrix are present; PTOAS v0.53 accepts the op, but A2/A3 execution reproducibly raises a CCU instruction-address exception; the pinned A2/A3 zero-segment path also underflows its repeat count |
| pto.tgather | TGATHER | tile+tensor | ✅ | ✅ | ✅ | ✅ | — | |
| pto.tgatherb | TGATHERB | tile | ✅ | ❌ | ❌ | ❌ | — | backend hook exists; IR/Python frontend and ST are missing |
| pto.tscatter | TSCATTER | tile+tensor | ✅ | ✅ | ✅ | ✅ | — | |
Expand All @@ -191,7 +191,7 @@ for lowering/compiler plumbing, plus other dialects such as VPTO, VMI, and SIMT.
| pto.textract | TEXTRACT | tile | ✅ | ✅ | ❌ | ✅ | — | |
| pto.tfillpad | TFILLPAD | tile+tensor | ✅ | ✅ | ✅ | ✅ | — | |
| pto.tfillpad_expand | TFILLPAD_EXPAND | tile+tensor | ✅ | ✅ | ✅ | ✅ | — | |
| pto.tfillpad_inplace | TFILLPAD_INPLACE | tile | ✅ | ✅ | ❌ | | — | the current codegen emits `pto.tfillpad` |
| pto.tfillpad_inplace | TFILLPAD_INPLACE | tile | ✅ | ✅ | ❌ | | — | corrected to exact same-name emission; zero/max/min modes pass on A2/A3 |

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

TFILLPAD_INPLACE marked ST-supported in both English and Chinese status docs, but hardware evidence is narrower than the claimed status. Per PR objectives, only three older A2 zero/max/min cases have actual hardware confirmation, while the new test suite defines a much broader dtype × mode × valid-shape × platform matrix that hasn't itself been run to conclusion on hardware. The shared root cause is one overclaiming status value duplicated across the two localized docs.

  • docs/en/dev/ptoas-op-status.md#L194: revert the exec/ST column to ❌ and adjust the note until the broader matrix is validated on-device.
  • docs/zh/dev/ptoas-op-status.md#L180: apply the identical reversion to keep the Chinese doc in sync with the English one.
📍 Affects 2 files
  • docs/en/dev/ptoas-op-status.md#L194-L194 (this comment)
  • docs/zh/dev/ptoas-op-status.md#L180-L180
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/en/dev/ptoas-op-status.md` at line 194, Revert the TFILLPAD_INPLACE
exec/ST status from ✅ to ❌ and revise its note to state that only the confirmed
A2 zero/max/min cases are validated pending broader on-device matrix coverage.
Apply the identical update in docs/en/dev/ptoas-op-status.md:194 and
docs/zh/dev/ptoas-op-status.md:180 to keep both localized status tables
synchronized.

| pto.textract_fp | TEXTRACT_FP / TEXTRACT | tile | ✅ | ❌ | ❌ | ❌ | — | MISSING: lacks a complete frontend/codegen/ST path |
| pto.tinsert_fp | TINSERT_FP / TINSERT | tile | ✅ | ❌ | ❌ | ❌ | — | MISSING: lacks a complete frontend/codegen/ST path |
| **Sorting (2)** | | | | | | | | |
Expand Down
2 changes: 2 additions & 0 deletions docs/zh/dev/codegen/00-pto_codegen.md
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,8 @@ print(pto_code)
| `tile.add(a, b, c)` | `pto.taddc` (三操作数加法) |
| `tile.adds(tile, scalar)` | `pto.tadds` (Tile + 标量) |
| `tile.fillpad_expand(src, shape)` | `pto.tfillpad_expand ins(%src) outs(%dst)`(`shape` 元组仅用于类型推导;更大的 `dst` 及其 pad 来自结果类型) |
| `tile.fillpad_inplace(src, pad_value=...)` | `pto.tfillpad_inplace`(源与结果共享存储) |
| `tile.concat_idx(src0, src1, idx0, idx1, dst)` | `pto.tconcatidx`(复用 `dst`) |

**`tile.slice` / `tile.assemble` 下沉细节。** 两个 op 都通过 `pto.subview`
下沉,它是源 tile 的纯视图别名(不搬数据,也不会额外发 `pto.alloc_tile`)。
Expand Down
4 changes: 2 additions & 2 deletions docs/zh/dev/ptoas-op-status.md
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ lowering/compiler plumbing 使用的额外内部 op 未纳入,也不列 VPTO
| pto.tshrs | TSHRS | tile | ✅ | ✅ | ❌ | ❌ | — | 已有链路;历史 ISA/语义问题,需按当前 pin 复验 |
| **数据重排(15)** | | | | | | | | |
| pto.tconcat | TCONCAT | tile+tensor | ✅ | ✅ | ✅ | ✅ | — | |
| pto.tconcatidx | TCONCAT (indexed) | tile | ✅ | | ❌ | ❌ | — | MISSING:缺完整前端/codegen/ST 链路 |
| pto.tconcatidx | TCONCAT (indexed) | tile | ✅ | | ❌ | ❌ | — | 已增加前端、精确 codegen 及完整 dtype/index/valid-shape ST 矩阵;PTOAS v0.53 可编译,但 A2/A3 执行稳定触发 CCU 指令地址异常;pinned A2/A3 的零长度分段路径还会发生 repeat count 下溢 |
| pto.tgather | TGATHER | tile+tensor | ✅ | ✅ | ✅ | ✅ | — | |
| pto.tgatherb | TGATHERB | tile | ✅ | ❌ | ❌ | ❌ | — | 已有 backend hook,缺 IR/Python 前端与 ST |
| pto.tscatter | TSCATTER | tile+tensor | ✅ | ✅ | ✅ | ✅ | — | |
Expand All @@ -177,7 +177,7 @@ lowering/compiler plumbing 使用的额外内部 op 未纳入,也不列 VPTO
| pto.textract | TEXTRACT | tile | ✅ | ✅ | ❌ | ✅ | — | |
| pto.tfillpad | TFILLPAD | tile+tensor | ✅ | ✅ | ✅ | ✅ | — | |
| pto.tfillpad_expand | TFILLPAD_EXPAND | tile+tensor | ✅ | ✅ | ✅ | ✅ | — | |
| pto.tfillpad_inplace | TFILLPAD_INPLACE | tile | ✅ | ✅ | ❌ | | — | 当前 codegen 发 `pto.tfillpad` |
| pto.tfillpad_inplace | TFILLPAD_INPLACE | tile | ✅ | ✅ | ❌ | | — | 已修正为同名精确发射;zero/max/min 模式在 A2/A3 通过 |
| pto.textract_fp | TEXTRACT_FP / TEXTRACT | tile | ✅ | ❌ | ❌ | ❌ | — | MISSING:缺完整前端/codegen/ST 链路 |
| pto.tinsert_fp | TINSERT_FP / TINSERT | tile | ✅ | ❌ | ❌ | ❌ | — | MISSING:缺完整前端/codegen/ST 链路 |
| **排序(2)** | | | | | | | | |
Expand Down
13 changes: 13 additions & 0 deletions python/pypto/ir/op/tile_ops.py
Original file line number Diff line number Diff line change
Expand Up @@ -438,6 +438,19 @@ def concat(
return _ir_core.create_op_call("tile.concat", [src0, src1], {}, actual_span)


def concat_idx(
src0: Expr,
src1: Expr,
src0_idx: Expr,
src1_idx: Expr,
dst: Expr,
span: Span | None = None,
) -> Call:
"""Indexed per-row concatenation into ``dst``."""
actual_span = _get_span_or_capture(span)
return _ir_core.create_op_call("tile.concat_idx", [src0, src1, src0_idx, src1_idx, dst], {}, actual_span)


def transpose_view(
tile: Expr,
span: Span | None = None,
Expand Down
2 changes: 2 additions & 0 deletions python/pypto/language/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ def scalar_func(x: pl.Scalar[pl.FP32]) -> pl.Scalar[pl.FP32]:
and_,
ands,
cmps,
concat_idx,
create_tile,
gemv,
gemv_acc,
Expand Down Expand Up @@ -325,6 +326,7 @@ def scalar_func(x: pl.Scalar[pl.FP32]) -> pl.Scalar[pl.FP32]:
"log",
"cast",
"concat",
"concat_idx",
"reshape",
"reinterpret_view",
"transpose",
Expand Down
2 changes: 2 additions & 0 deletions python/pypto/language/op/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@
and_,
ands,
cmps,
concat_idx,
gemv,
gemv_acc,
gemv_bias,
Expand Down Expand Up @@ -242,6 +243,7 @@
"recip",
"write",
"concat",
"concat_idx",
"batch_matmul",
# Promoted tile-only
"create_tile",
Expand Down
10 changes: 10 additions & 0 deletions python/pypto/language/op/tile_ops.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
"extract",
"scatter_update",
"concat",
"concat_idx",
"move",
"aiv_shard",
"aic_gather",
Expand Down Expand Up @@ -1894,6 +1895,15 @@ def transpose(tile: Tile, axis1: int, axis2: int, tmp_tile: Tile | None = None)
return Tile(expr=call_expr)


def concat_idx(src0: Tile, src1: Tile, src0_idx: Tile, src1_idx: Tile, dst: Tile) -> Tile:
"""Indexed per-row concatenation into a destination tile."""
return Tile(
expr=_ir_ops.concat_idx(
src0.unwrap(), src1.unwrap(), src0_idx.unwrap(), src1_idx.unwrap(), dst.unwrap()
)
)


def transpose_view(tile: Tile) -> Tile:
"""Zero-copy fractal-layout reinterpretation (NZ<->ZN) of a tile.

Expand Down
16 changes: 15 additions & 1 deletion src/backend/common/pto_ops_elementwise.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,18 @@ static std::string MakeNaryCodegenPTO(const std::string& pto_op_name, size_t ari
return "";
}

static std::string MakeConcatIdxCodegenPTO(const CallPtr& op, codegen::CodegenBase& codegen_base) {
auto& codegen = AsPto(codegen_base);
CheckArity(op, "pto.tconcatidx", 5);
std::vector<std::pair<std::string, std::string>> inputs;
inputs.reserve(4);
for (size_t i = 0; i < 4; ++i) {
inputs.emplace_back(codegen.GetExprAsCode(op->args_[i]), codegen.GetExprTypeAnnotation(op->args_[i]));
}
EmitInsOuts(codegen, "pto.tconcatidx", inputs);
Comment on lines +147 to +155

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== repo files around pto_ops_elementwise =="
fd -a 'pto_ops_elementwise\.cpp|codegen.*test|test.*codegen|.*ptos?.*test.*' . | sed 's#^\./##' | head -100

echo
echo "== target file outline =="
ast-grep outline src/backend/common/pto_ops_elementwise.cpp --view expanded || true

echo
echo "== target lines 100-190 =="
sed -n '100,190p' src/backend/common/pto_ops_elementwise.cpp | nl -ba -v100

echo
echo "== search concatidx/tconcatidx/codegen test markers =="
rg -n "tconcatidx|concatidx|tconcat|ins\(|outs\(|dst|destination|dest" src test tests .github tools bench 2>/dev/null | head -200 || true

Repository: hw-native-sys/pypto

Length of output: 3464


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== target file outline =="
ast-grep outline src/backend/common/pto_ops_elementwise.cpp --view expanded || true

echo
echo "== target lines 100-190 =="
nl -ba src/backend/common/pto_ops_elementwise.cpp | sed -n '100,190p'

echo
echo "== search concatidx/tconcatidx/codegen test markers =="
rg -n "tconcatidx|concatidx|tconcat|pto\.(tconcatidx|fillpad_inplace)|ins\(|outs\(|dst|destination|dest" src test tests .github tools bench 2>/dev/null | head -300 || true

echo
echo "== likely pto/ptotest files =="
git ls-files | rg 'ptotest|pto.*test|test.*pte|code.*test|elementwise.*pt|common/.*test' | head -200

Repository: hw-native-sys/pypto

Length of output: 1918


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== target file lines 100-190 =="
awk 'NR>=100 && NR<=190 { printf "%6d  %s\n", NR, $0 }' src/backend/common/pto_ops_elementwise.cpp

echo
echo "== registration/ops around concat_idx =="
awk 'NR>=420 && NR<=510 { printf "%6d  %s\n", NR, $0 }' src/backend/common/pto_ops_elementwise.cpp

echo
echo "== test_pto references to concat_idx/tconcatidx/source =="
python3 - <<'PY'
import pathlib, re
for p in pathlib.Path('tests').rglob('*'):
    if p.is_file():
        try:
            txt=p.read_text(errors='ignore')
        except Exception:
            continue
        if 'concat_idx' in txt or 'tconcatidx' in txt:
            print(f'\n--- {p} ---')
            for i,line in enumerate(txt.splitlines(),1):
                if 'concat_idx' in line or 'tconcatidx' in line:
                    print(f'{i}: {line}')
PY

echo
echo "== all files with concat_idx or tconcatidx =="
python3 - <<'PY'
import pathlib
for p in pathlib.Path('.').rglob('*'):
    if not p.is_file(): continue
    if any(part in {'.git','build','dist'} for part in p.parts): continue
    try:
        txt = p.read_text(errors='ignore')
    except Exception:
        continue
    if 'concat_idx' in txt or 'tconcatidx' in txt or 'pto.tconcatidx' in txt:
        print(p)
PY

echo
echo "== inspect EmitInsOuts definitions/usages =="
rg -n "EmitInsOuts|MakeConcatIdxCodegenPTO|ptotest|ptotest|pto.*test" src backend tests -g '*.cpp' -g '*.py' -g '*.cc' -g '*.h' | head -300 || true

Repository: hw-native-sys/pypto

Length of output: 19862


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== test_pto_codegen concat_idx test =="
awk 'NR>=480 && NR<=535 { printf "%6d  %s\n", NR, $0 }' tests/ut/codegen/test_pto_codegen.py

echo
echo "== EmitInsOuts implementation =="
awk 'NR>=350 && NR<=380 { printf "%6d  %s\n", NR, $0 }' src/backend/common/pto_ops_shared.cpp
awk 'NR>=70 && NR<=90 { printf "%6d  %s\n", NR, $0 }' src/backend/common/pto_ops_internal.h

echo
echo "== concat_idx registration and op definitions =="
awk 'NR>=505 && NR<=520 { printf "%6d  %s\n", NR, $0 }' src/backend/common/pto_ops_elementwise.cpp
rg -n -C 5 "tile\.concat_idx|concat_idx|set_output_reuses_input|set_input_layout|set_output_layout" python src tests/ut/ir/operators/test_concat_idx.py tests/st/runtime/ops/test_concat_idx.py | head -240

Repository: hw-native-sys/pypto

Length of output: 27955


Assert the exact tconcatidx codegen contract.

test_pto_codegen_concat_idx_uses_four_inputs_and_reused_destination() only checks pto.tconcatidx plus ins(/outs( markers. Add assertions for the four inputs in order, the operand type annotations, and that outs contains only dst with the destination tile/buffer type.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/backend/common/pto_ops_elementwise.cpp` around lines 147 - 155,
Strengthen test_pto_codegen_concat_idx_uses_four_inputs_and_reused_destination()
to assert the exact pto.tconcatidx codegen contract: verify all four inputs
appear in order, each has the expected operand type annotation, and outs
contains only dst with the destination tile/buffer type. Keep the existing
opcode and ins/outs marker checks.

return "";
}

static std::string MakeTileSelCodegenPTO(const CallPtr& op, codegen::CodegenBase& codegen_base) {
auto& codegen = AsPto(codegen_base);
CheckArity(op, "pto.tsel", 4);
Expand Down Expand Up @@ -439,7 +451,7 @@ static const SimpleOpEntry kSimpleOps[] = {
// Padding operations
{"tile.fillpad", "pto.tfillpad", 1},
// Inplace variant: set_output_reuses_input(0) makes src/dst share UB addr.
{"tile.fillpad_inplace", "pto.tfillpad", 1},
{"tile.fillpad_inplace", "pto.tfillpad_inplace", 1},
// Matrix multiplication operations (PipeType::M → CUBE/AIC core)
{"tile.matmul", "pto.tmatmul", 2},
{"tile.matmul_mx", "pto.tmatmul.mx", 4},
Expand Down Expand Up @@ -496,6 +508,8 @@ void RegisterElementwiseOps(Backend& backend, const std::unordered_set<std::stri
if (exclude_ops.count(op_name) > 0) return;
backend.RegisterOp(op_name).f_codegen(std::move(fn));
};
reg("tile.concat_idx",
[](const CallPtr& op, codegen::CodegenBase& codegen) { return MakeConcatIdxCodegenPTO(op, codegen); });
Comment on lines +511 to +512

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== repo files =="
git ls-files | rg 'src/backend/common/pto_ops_elementwise\.cpp|src/backend|pto_ops_elementwise' | head -100

echo "== target outline =="
ast-grep outline src/backend/common/pto_ops_elementwise.cpp --view expanded || true

echo "== target lines =="
sed -n '1,90p; 450,560p' src/backend/common/pto_ops_elementwise.cpp

echo "== searches for concat_idx / layout setup / MakeConcatIdxCodegenPTO =="
rg -n "MakeConcatIdxCodegenPTO|concat_idx|row.*major|col.*major|LayoutConfig|layout" src/backend/common/pto_ops_elementwise.cpp src/backend -S | head -200

echo "== relevant files list =="
git ls-files src/backend | head -200

Repository: hw-native-sys/pypto

Length of output: 29275


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== pto_ops_elementwise concat_idx implementation =="
sed -n '120,210p; 488,515p' src/backend/common/pto_ops_elementwise.cpp

echo "== pto_ops_common subview layout handling =="
sed -n '1,220p; 380,475p' src/backend/common/pto_ops_common.cpp

echo "== pto layout codegen for tile_type =="
rg -n "pto\.tile_type|LayoutConfig|LayoutSpec|TileLayoutSpec|input_layouts|output_layout" src backend include -S | head -240

echo "== backend registry entry layout spec behavior =="
sed -n '400,505p' src/backend/common/backend.cpp

echo "== call stack or type-check for MakeConcatIdxCodegenPTO inputs =="
grep -n "MakeConcatIdxCodegenPTO\|tile\.concat_idx\|concat_idx" src -R -S

echo "== inspect backend registry header if present =="
fd -i 'backend.*\.h' src | head -20
sed -n '1,220p' src/backend/common/backend_registry.cpp 2>/dev/null || true
sed -n '1,220p' src/backend/common/backend_registry.h 2>/dev/null || true

Repository: hw-native-sys/pypto

Length of output: 13174


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== resolve_backend_op_layouts_pass implementation =="
sed -n '110,270p' src/ir/transforms/resolve_backend_op_layouts_pass.cpp

echo "== backend.h relevant declarations =="
sed -n '70,145p; 235,255p' include/pypto/backend/common/backend.h

echo "== RegisterElementwiseOps rest =="
sed -n '360,560p' src/backend/common/pto_ops_elementwise.cpp

echo "== GetExprTypeAnnotation implementation candidates =="
rg -n "GetExprTypeAnnotation|GetCurrentResultTileBufTypeString|EmitInsOuts|GetExprAsCode" include src -S | head -200

echo "== read header files for pto codegen likely locations =="
fd -e h . include | rg 'codegen|pto|backend' | head -80

echo "== read likely header contents =="
fd -i 'codegen.*\.h|pto.*\.h' include src include | xargs -r -n1 sh -c 'echo "--- $0"; sed -n "1,220p" "$0"' | head -500

Repository: hw-native-sys/pypto

Length of output: 50377


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== backend.cpp finalize and lookup =="
sed -n '420,450p; 500,525p' src/backend/common/backend.cpp

echo "== registration macro and setter behavior =="
sed -n '130,235p' include/pypto/backend/common/backend.h
sed -n '460,505p' src/backend/common/backend.cpp

echo "== pto type annotation implementation =="
sed -n '1780,1895p' src/codegen/pto/pto_codegen.cpp

echo "== current result target/type implementation =="
sed -n '1860,1905p; 1360,1430p' src/codegen/pto/pto_codegen.cpp

echo "== layout predicates =="
rg -n "class BackendOpRegistryEntry|BackendOpRegistryEntry::~|BackendOpRegistryEntry::.*;" include src pypto backend -S
 rg -n "RequiresRowMajor|IsRowMajor|TileLayout::row_major|SetCurrentResult" include src pypto backend -S | head -200

echo "== pto op declarations for concat_idx =="
rg -n "concat_idx|tile\.concat|mrgsort_format[12]|mrgsort_format" src include -S

Repository: hw-native-sys/pypto

Length of output: 17400


Add row-max layout constraints to the custom registration.

tile.concat_idx is registered as an anonymous custom codegen slot, so it gets no BackendTileLayoutSpec: inputs 0..3 and the result tile can keep arbitrary block layout, and the row-sensitive pto.tconcatidx lowering can receive col-major operands. Chain the layout constraints on the registration entry.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/backend/common/pto_ops_elementwise.cpp` around lines 511 - 512, Update
the tile.concat_idx registration to attach the BackendTileLayoutSpec row-max
constraints for input operands 0..3 and the result tile, while preserving the
existing MakeConcatIdxCodegenPTO callback.


auto register_precision_op = [&](const char* op_name, const char* pto_op_name, size_t arity,
const char* attr_kind) {
Expand Down
69 changes: 69 additions & 0 deletions src/ir/op/tile_ops/transform.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -919,6 +919,75 @@ REGISTER_OP("tile.concat")
return DeduceTileConcatType(args, kwargs);
});

static TypePtr DeduceTileConcatIdxType(const std::vector<ExprPtr>& args) {
CHECK(args.size() == 5)
<< "tile.concat_idx requires 5 arguments (src0, src1, src0_idx, src1_idx, dst), got " << args.size();
auto src0 = As<TileType>(args[0]->GetType());
auto src1 = As<TileType>(args[1]->GetType());
auto idx0 = As<TileType>(args[2]->GetType());
auto idx1 = As<TileType>(args[3]->GetType());
auto dst = As<TileType>(args[4]->GetType());
CHECK(src0 && src1 && idx0 && idx1 && dst) << "tile.concat_idx requires five TileType operands";
CHECK(src0->dtype_ == src1->dtype_ && src0->dtype_ == dst->dtype_)
<< "tile.concat_idx requires src0, src1, and dst to have the same dtype";
const auto is_data_dtype = [](DataType dtype) {
return dtype == DataType::INT8 || dtype == DataType::UINT8 || dtype == DataType::INT16 ||
dtype == DataType::UINT16 || dtype == DataType::INT32 || dtype == DataType::UINT32 ||
dtype == DataType::FP16 || dtype == DataType::BF16 || dtype == DataType::FP32;
};
const auto is_index_dtype = [](DataType dtype) {
return dtype == DataType::INT8 || dtype == DataType::UINT8 || dtype == DataType::INT16 ||
dtype == DataType::UINT16 || dtype == DataType::INT32 || dtype == DataType::UINT32;
};
CHECK(is_data_dtype(src0->dtype_))
<< "tile.concat_idx requires 8/16/32-bit integer, FP16, BF16, or FP32 data tiles";
CHECK(idx0->dtype_ == idx1->dtype_ && is_index_dtype(idx0->dtype_))
<< "tile.concat_idx requires matching 8/16/32-bit integer index tiles";
Comment on lines +938 to +945

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail
rg -n 'DataType::UINT(8|16|32)|tile\.concat_idx|pto\.tconcatidx' \
  src/ir/op/tile_ops/transform.cpp src/backend/common/pto_ops_elementwise.cpp

Repository: hw-native-sys/pypto

Length of output: 2079


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== transform.cpp relevant section =="
sed -n '900,995p' src/ir/op/tile_ops/transform.cpp

echo "== pto_ops_elementwise.cpp relevant sections =="
sed -n '130,175p' src/backend/common/pto_ops_elementwise.cpp
sed -n '490,525p' src/backend/common/pto_ops_elementwise.cpp

echo "== dtype formatting / tconcatidx references =="
rg -n "DataType::UINT|UINT|to_dtype|dtype_name|ui8|ui16|ui32|tconcatidx|concat_idx" src backend tools include lib -g '*.{cpp,h,hpp,py,cc,cu,txt,json}' | head -n 200

Repository: hw-native-sys/pypto

Length of output: 24569


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== generate_expr_type_annotation implementation =="
sed -n '90,155p' src/codegen/codegen_base.cpp

echo "== tile concat_idx type annotations in codebase =="
python3 - <<'PY'
from pathlib import Path
import re
for path in Path('.').rglob('*'):
    if path.is_file() and path.suffix in {'.cpp', '.hpp', '.h', '.py', '.tt':True}:
        txt = path.read_text(errors='ignore')
        if 'tile.concat_idx' in txt or 'DeduceTileConcatIdxType' in txt:
            # Print concise context for each file
            print(f"\n--- {path} ---")
            lines = txt.splitlines()
            for i,l in enumerate(lines,1):
                if 'tile.concat_idx' in l or 'DeduceTileConcatIdxType' in l:
                    lo=max(1,i-8); hi=min(len(lines),i+14)
                    print(f"@@ {lo}-{hi}")
                    for j in range(lo,hi+1):
                        print(f"{j}: {lines[j-1]}")
                    break
PY

echo "== any explicit PTOAS tconcatidx dtype expectations (including docs/schema) =="
rg -n "tconcatidx|concat_idx|tile\.concat_idx|ui8|ui16|ui32|PTOAS|ptoas" . \
  -g '*.{md,txt,json,yaml,yml,py,pyi,cc,cpp,h,hpp,cu,cuh,h}' \
  | head -n 200

Repository: hw-native-sys/pypto

Length of output: 2885


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== CodegenBase::GetExprTypeAnnotation definitions/usages =="
rg -n "GetExprTypeAnnotation|EmitInsOutsClause|GenerateInsOutsClause" src include | head -n 200

echo "== pto codegen helper around tile instruction emission =="
sed -n '160,320p' src/codegen/pto/pto_scalar_expr_codegen.cpp
rg -n "i8|i16|i32|ui8|ui16|ui32|tile" src/codegen/pto/pto_scalar_expr_codegen.cpp | head -n 160

echo "== fixed file scan for tile.concat_idx =="
python3 - <<'PY'
from pathlib import Path
for path in Path('.').rglob('*'):
    if path.is_file() and path.suffix not in {'.lock'}:
        txt = path.read_text(errors='ignore')
        if 'tile.concat_idx' in txt or 'DeduceTileConcatIdxType' in txt:
            lines = txt.splitlines()
            print(f"\n--- {path} ---")
            for i,l in enumerate(lines,1):
                if 'tile.concat_idx' in l or 'DeduceTileConcatIdxType' in l:
                    for j in range(max(1,i-6), min(len(lines),i+8)+1):
                        print(f"{j}: {lines[j-1]}")
PY

Repository: hw-native-sys/pypto

Length of output: 33603


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== PTO getTypeString for integer dtypes =="
sed -n '15,80p' src/codegen/pto/pto_type_utils.cpp

echo "== GenerateInsOutsClause implementation =="
sed -n '300,380p' src/backend/common/pto_ops_shared.cpp

echo "== Test concat_idx dtype construction =="
sed -n '40,70p' tests/ut/ir/operators/test_concat_idx.py
sed -n '490,525p' tests/ut/codegen/test_pto_codegen.py

echo "== Behavioral extraction of unsigned index annotations (read-only source text) =="
python3 - <<'PY'
from pathlib import Path
text = Path("src/ir/op/tile_ops/transform.cpp").read_text()
if ("return dtype == DataType::INT8 || dtype == DataType::UINT8 || dtype == DataType::INT16 ||\n           dtype == DataType::UINT16 || dtype == DataType::INT32 || dtype == DataType::UINT32" in text):
    print("is_index_dtype accepts UINT8, UINT16, UINT32")
text = Path("src/codegen/pto/pto_type_utils.cpp").read_text()
for dtype in ("UINT8", "UINT16", "UINT32"):
    if f"\"ui{dtype[4].lower()}{dtype[5:] if len(dtype)==3 else int(dtype[4:])}\"" in text or f'return "ui{dtype[4].lower()}{dtype[5:] if len(dtype)==3 else int(dtype[4:])}"' in text:
        print(f"ptype_map emits {dtype} as ui{dtype[4].lower()}{dtype[5:] if len(dtype)==3 else int(dtype[4:])}")
text = Path("src/backend/common/pto_ops_elementwise.cpp").read_text()
print("MakeConcatIdxCodegenPTO uses GetExprTypeAnnotation:", "GetExprTypeAnnotation(op->args_[i])" in text)
PY

Repository: hw-native-sys/pypto

Length of output: 8108


🌐 Web query:

PTOAS tile.buf.type ui8 i16 i32 tconcatidx unsigned tile types

💡 Result:

In the context of the PTOAS (PTO Advanced System) project, tile.buf.type and associated parameters relate to the representation of scratchpad memory tiles within the pto MLIR dialect [1][2]. The !pto.tile_buf type is a core component of this dialect, representing a local memory buffer with metadata including placement (e.g., vec, mat), element data type, dimensions, and layout configurations [1]. Regarding your specific keywords: 1. Element Types: The dtype parameter within !pto.tile_buf supports various elemental data types, including i1, i8, i16, i32, f16, f32, and bf16 [1]. These define the size and format of the individual data elements stored within the tile buffer [1]. 2. Tile Types and Indexing: - The dialect uses !pto.tile_buf for logical buffers in Destination-Passing Style (DPS) operations [2]. - While tconcatidx is not explicitly documented as a standard primitive keyword in the primary PTOAS IR manual, the dialect frequently utilizes tiling, sub-viewing (e.g., pto.tile_subview), and concatenation operations to manage tensor data [3][1][2]. In broader MLIR tensor dialects, concatenation indices are often specified to handle merging operations across dynamic or static dimensions [4]. - Physical and logical attributes, such as rows, cols, v_row (valid rows), and v_col (valid columns), are used to define the actual storage and valid region of the tile [1]. The system is designed to handle explicit pipeline synchronization and scratchpad memory management, with IR structures often requiring explicit configuration attributes like blayout (base layout) and slayout (secondary layout) [1][2].

Citations:


Reject or normalize unsigned index tiles before PTO emission.

tile.concat_idx currently accepts UINT8/16/32, but the PTO codegen emits them as ui8/ui16/ui32 via GetExprTypeAnnotation, and PTOAS tile operands take signed integer dtype spelling. Restrict the backend contract to signed INT8/16/32, or introduce PTO-safe signed casts for the index operands before lowering.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/ir/op/tile_ops/transform.cpp` around lines 938 - 945, Update the
tile.concat_idx validation around is_index_dtype and the idx0/idx1 checks to
reject UINT8, UINT16, and UINT32 index tiles before PTO emission; accept only
matching signed INT8, INT16, or INT32 index dtypes while preserving the existing
source-data validation.

CHECK(src0->shape_.size() == 2 && src1->shape_.size() == 2 && idx0->shape_.size() == 2 &&
idx1->shape_.size() == 2 && dst->shape_.size() == 2)
<< "tile.concat_idx requires rank-2 tiles";
for (const auto& type : {src0, src1, idx0, idx1}) {
CHECK(ProveValidExtentEqual(type->shape_[0], dst->shape_[0]) == ProofResult::kTrue)
<< "tile.concat_idx requires all physical row counts to match dst";
}
const auto dst_valid = GetValidShape(dst);
for (const auto& type : {src0, src1, idx0, idx1}) {
const auto valid = GetValidShape(type);
CHECK(ProveValidExtentEqual(valid[0], dst_valid[0]) == ProofResult::kTrue)
<< "tile.concat_idx requires all valid row counts to match dst";
}
const auto idx0_valid = GetValidShape(idx0);
const auto idx1_valid = GetValidShape(idx1);
auto one = std::make_shared<ConstInt>(1, DataType::INDEX, Span::unknown());
CHECK(ProveValidExtentEqual(idx0_valid[1], one) == ProofResult::kTrue &&
ProveValidExtentEqual(idx1_valid[1], one) == ProofResult::kTrue)
<< "tile.concat_idx requires index tiles with valid_shape columns equal to 1";
Comment on lines +949 to +964

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail
rg -n 'requires all physical row counts|valid_shape columns equal to 1|ProveValidExtentEqual' \
  src/ir/op/tile_ops/transform.cpp

Repository: hw-native-sys/pypto

Length of output: 657


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect the function around the reported checks and nearby implementation.
sed -n '880,995p' src/ir/op/tile_ops/transform.cpp

# Search for tile.concat_idx implementation, shape validation docs / tests / usages.
rg -n "tile\.concat_idx|concat_idx|tile_concat_idx|TileOps|valid_shape" src tests -S | head -n 200

Repository: hw-native-sys/pypto

Length of output: 28172


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect the concat_idx lowering/semantics and index operands to determine whether shape_[0]
# and valid_shape[1] constraints are tied to actual use.
rg -n "tile\.concat_idx|concat_idx|GetValidShape|InheritTileViewLayout|DeduceTileConcatIdxType" src -S
sed -n '960,1080p' src/backend/common/pto_ops_elementwise.cpp
rg -n "src0_idx|src1_idx|x0|x1|concat_idx|cat" src backend codegen -S | head -n 240

Repository: hw-native-sys/pypto

Length of output: 35782


🏁 Script executed:

#!/bin/bash
set -euo pipefail

sed -n '130,185p' src/backend/common/pto_ops_elementwise.cpp
rg -n "MakeConcatIdxCodegenPTO|padd|concat|idx|src0_idx|src1_idx|x0|x1|col" src/backend/src -S 2>/dev/null || true
rg -n "concat_idx|tconcatidx|tile.create|tile.concat_idx" tests src -S | head -n 200

Repository: hw-native-sys/pypto

Length of output: 27364


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect tile.concat_idx behavior tests and the relevant invalid-index contract test shape.
sed -n '1,120p' tests/ut/ir/operators/test_concat_idx.py
sed -n '300,355p' tests/ut/ir/operators/test_concat_idx.py
sed -n '10,360p' tests/st/runtime/ops/test_concat_idx.py

# Inspect tile type helper definitions.
sed -n '1,130p' src/ir/type.cpp
rg -n "GetValidShape|tile_view_semantics::GetEffectiveTileView|ProveValidExtentEqual|InheritTileViewLayout" src/ir src/backend common -S | head -n 180

Repository: hw-native-sys/pypto

Length of output: 31925


Validate canonical valid extents instead of storage shape counts.

src0/src1/dst only need matching valid row counts; rejecting allocated rows larger than dst blocks valid valid-row inputs. Likewise, idx0/idx1 only need at least one valid index column, but the equality check rejects valid_shape[1] >= 2. Remove the physical-row checks and change the index-column check to >= 1.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/ir/op/tile_ops/transform.cpp` around lines 949 - 964, In the
tile.concat_idx validation block, remove the physical row-count loop that
compares type->shape_[0] with dst->shape_[0]. Retain validation using
GetValidShape for matching valid row counts, and update the
idx0_valid/idx1_valid column validation to require each valid column extent to
be at least one rather than exactly equal to one.

TileView view;
view.valid_shape = dst_valid;
InheritTileViewLayout(view, dst);
return std::make_shared<TileType>(dst->shape_, dst->dtype_, std::nullopt, view);
}

REGISTER_OP("tile.concat_idx")
.set_op_category("TileOp")
.set_description("Indexed per-row concatenation into a destination tile")
.add_argument("src0", "First source tile")
.add_argument("src1", "Second source tile")
.add_argument("src0_idx", "Per-row source-0 column count")
.add_argument("src1_idx", "Per-row source-1 column count")
.add_argument("dst", "Destination tile")
.set_input_memory(0, MemorySpace::Vec)
.set_input_memory(1, MemorySpace::Vec)
.set_input_memory(2, MemorySpace::Vec)
.set_input_memory(3, MemorySpace::Vec)
.set_input_memory(4, MemorySpace::Vec)
.set_output_memory(MemorySpace::Vec)
.set_output_reuses_input(4)
Comment on lines +971 to +985

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail
rg -n 'tile\.concat_idx|set_input_layout|set_output_layout' \
  src/backend/common/pto_ops_elementwise.cpp

Repository: hw-native-sys/pypto

Length of output: 1288


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== file around REGISTER_OP tile.concat_idx =="
sed -n '950,1000p' src/ir/op/tile_ops/transform.cpp

echo
echo "== candidate helpers near REGISTER_OP =="
rg -n 'void REGISTER_OP|struct .*Register|class .*Register|set_input_memory\(|set_input_layout\(|set_output_layout\(|add_argument' src/ir/op/tile_ops/transform.cpp src/ir/op -g'*.cpp' -g'*.h' | head -220

Repository: hw-native-sys/pypto

Length of output: 25491


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== define/register helper declarations/usages for REGISTER_OP =="
rg -n 'REGISTER_OP\b|struct .*OpRegistry|class .*OpRegistry|OpRegistry|RegEntry' src/ir/op src/include -g'*.cpp' -g'*.h' | head -200

echo
echo "== locate simple ops code =="
rg -n 'kSimpleOps|set_input_layout\\(|set_output_layout\\(' src -g'*.cpp' -g'*.h' | head -200

Repository: hw-native-sys/pypto

Length of output: 14226


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== tile concat idx in backend =="
rg -n 'concat_idx|tconcatidx|kSimpleOps|SrcSimpleOps|SimpleOps|tile\.concat_idx|set_input_layout\(' src/backend src/include -g'*.cpp' -g'*.h' -g'*.py' 2>/dev/null | head -250

echo
echo "== op registry/map definition candidates =="
rg -n 'typedef|class|struct.*OpRegistry|OpRegistry::|GetOp\\(|SimpleOp|SrcSimpleOps|kSimpleOps' src/backend src -g'*.cpp' -g'*.h' | head -250

echo
echo "== precise backend occurrences without include path dependency =="
find src -type f \
  \( -name '*.cpp' -o -name '*.h' \) -print0 \
  | xargs -0 rg -n 'tile\.concat_idx|tconcatidx|set_input_layout\\(|set_output_layout\\(|kSimpleOps|SrcSimpleOps|SimpleOp' | head -300

Repository: hw-native-sys/pypto

Length of output: 2835


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== pto_ops_elementwise around codegen and kSimpleOps =="
sed -n '1,180p' src/backend/common/pto_ops_elementwise.cpp
echo
sed -n '360,535p' src/backend/common/pto_ops_elementwise.cpp

echo
echo "== BackendOpRegistryEntry layout API =="
sed -n '460,500p' src/backend/common/backend.cpp

Repository: hw-native-sys/pypto

Length of output: 18083


Register row-major constraints for tile.concat_idx.

tile.concat_idx is registered with only the PTO codegen handler, so operands that should go to pto.tconcatidx are not required to be row-major and can fail assembler verification. Add row-major set_input_layout for inputs 0-4 and set_output_layout for the result.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/ir/op/tile_ops/transform.cpp` around lines 971 - 985, Update the
tile.concat_idx registration to add row-major set_input_layout constraints for
inputs 0 through 4 and a row-major set_output_layout constraint for the result.
Keep the existing memory-space and output-reuse settings unchanged.

.f_deduce_type([](const std::vector<ExprPtr>& args,
const std::vector<std::pair<std::string, std::any>>& /*kwargs*/) {
return DeduceTileConcatIdxType(args);
});

TypePtr DeduceTileSetValidShapeType(const std::vector<ExprPtr>& args,
const std::vector<std::pair<std::string, std::any>>& kwargs) {
CHECK(args.size() == 3)
Expand Down
Loading
Loading