TEPL inline region path rejects CubeM32 sub-views and SharedTile sub-view sources — both contradict PTO-ISA 0.58.6
Summary
The inline Tile region producer path (pto_tile_region_inline_asm.hpp) imposes two constraints that are not grounded in the PTO-ISA specification and block legitimate, ISA-legal usage of B.SUBVIEW with TPARTVIEW on TEPL operations (TROWSUM, TADD, TEXP, …):
- CubeM32 rejection —
static_assert(SubTile::BFractal == BLayout::RowMajor) rejects CubeM32 sub-tiles even though the ISA spec normatively defines CUBE sub-view descriptor derivation (BundleCubeSubviewDescriptorOf).
- SharedTile rejection —
SubTileView::data() calls parent_->data(), which does not exist on SharedTile (Shared tiles use handle()), even though the ISA spec explicitly allows B.SUBVIEW after B.IOS (Shared binder).
Both constraints are acknowledged as intentional limitations in the compiler's own documentation (range-modifiers.md), but neither is supported by the ISA spec. The ISA spec explicitly supports both CUBE sub-views and Shared sub-views.
Constraint 1: CubeM32 sub-view rejected by RowMajor static_assert
Symptom
Compiling TPARTVIEW<CubeTileM32<float,32,4>, 1, 4>(parent) followed by TROWSUM(dst, subview) fails:
static_assert(SubTile::BFractal == BLayout::RowMajor,
"inline Tile region path requires RowMajor fragments")
Location: pto_tile_region_inline_asm.hpp:13 (in pto_region_unary)
ISA spec evidence
The PTO-ISA 0.58.6 specification normatively supports CUBE B.SUBVIEW:
NDF PTO-B-SUBVIEW-DESCRIPTOR-001 (asl/block/model/operands/subview-descriptor.asl:3-9):
A legal Local CUBE B.SUBVIEW MUST derive a bounded descriptor from the parent descriptor, XLEN offset, and encoded view capacity in CELL order. Parent lifetime and payload remain unchanged; non-CUBE, zero-valid, and out-of-range geometry is rejected with Fault_TileLegality before effects.
This NDF explicitly contemplates "Local CUBE B.SUBVIEW" as a legal construct.
BundleCubeSubviewDescriptorOf() (asl/block/model/operands/subview-descriptor.asl:36-124):
The function derives a bounded sub-view descriptor from a CUBE parent tile. It:
- Requires
TileLayoutIsCube(parent.layout) (line 44) — the function is specifically designed for CUBE layouts
- Computes
cell_rows / cell_columns from the CUBE layout (lines 59-60)
- Handles
CUBE_N8 and other CUBE layouts (e.g., CUBE_M32) in separate branches (lines 65-83)
- For non-N8 CUBE layouts (including M32):
origin_column = offset_cells * cell_columns (line 81-82)
MaterializeBundleSubview() (asl/block/model/operands/subview-descriptor.asl:264-423):
When the consuming operation is a non-CUBE (TEPL) operation like TROWSUM:
- Lines 293-295:
operation_is_cube = BundleTileDecodeFamily(...) == TileDecode_CUBE
- Lines 330-387: For non-CUBE operations, the materialized view is configured as RowMajor (
TileLayout_RowMajor, line 385), reading from the CUBE parent in its original CELL order
- Lines 389-401: Data is copied from the CUBE parent (
ReadTileElement(parent, origin_row+row, origin_column+column)) into the RowMajor materialized view
This means the ISA spec's intended behavior for a CUBE parent + TEPL consumer is: the hardware materializes a RowMajor view of the CUBE parent's sub-region at execution time. The compiler does not need to emit RowMajor fragments — it can emit B.SUBVIEW on a CUBE source and the hardware handles the CUBE→RowMajor materialization.
Applicability is total (asl/block/model/operands/subview-descriptor.asl:133-140):
B.SUBVIEW applicability is total over accepted Tile operations; the selected operation handler retains ownership of dtype, layout, shape, and definedness legality.
There is no operation-specific restriction — TROWSUM, TADD, and all other TEPL operations are legal consumers.
Compiler's own acknowledgment
docs/tileop-usage/range-modifiers.md:119-123:
CubeTileM16 and CubeTileM32 are supported by the Tile type and partition contract checks. The current region producer inline-asm path is intentionally limited to RowMajor + NoneBox; do not use TCVT or row-wise region producers with Cube fragments until the Cube binder/CELL ordering path is implemented and validated.
This is a documented known limitation and future implementation item, not an ISA constraint.
Impact
Any kernel that loads data into a CubeM32 local tile (the standard local L0 layout for matrix data) and wants to partition it with TPARTVIEW for element-wise or reduction operations is blocked. The only workaround is to use RowMajor local tiles, which is not the correct L0 layout for matrix data and forces an extra layout conversion on TLOAD.
Constraint 2: SharedTile sub-view source rejected by data() dependency
Symptom
Compiling TPARTVIEW<SharedTile<SharedMatrixLeft<float,32,4>>, 1, 4>(shared_parent) followed by TROWSUM(dst, subview) fails:
no member named 'data' in 'pto::SharedTile<...>'
Location: pto_tile_region.hpp:97 — SubTileView::data() calls parent_->data(), but SharedTile has no data() method (it exposes handle() / handle_ref() instead).
ISA spec evidence
The PTO-ISA 0.58.6 specification explicitly supports B.SUBVIEW with B.IOS (Shared):
B.SUBVIEW block composition (asl/block/operands/B.SUBVIEW.asl:1, contract "block_composition"):
Immediately follows B.IOT or B.IOS and is contiguous with the associated modifier group.
B.SUBVIEW legality (asl/block/operands/B.SUBVIEW.asl:1, contract "legality"):
SubviewSizeCode raw values 1..12 are decoded; Local-associated groups require 1..10 and Shared-associated groups accept 1..12.
The ISA distinguishes Local (SizeCode 1..10) from Shared (1..12) — Shared B.SUBVIEW is explicitly legal.
NDF PTO-B-SUBVIEW-RANGE-001 (asl/block/operands/B.SUBVIEW.asl:3-11):
B.SUBVIEW MUST decode the exact 0x53 form, preserve raw fields and the XLEN-wrapped GPR-plus-uimm11 offset, and apply only to its preceding contiguous B.IOT/B.IOS group. Raw SizeCodes 11 and 12 attached to a Local group MUST raise Fault_TileLegality before GPR reads or carrier updates; the same raw codes attached to a Shared group remain legal.
ADR-BLOCK-0016 (docs/status/decisions/ADR-BLOCK-0016-b-range-modifiers.md:93-94):
Each modifier belongs only to the immediately preceding contiguous B.IOT or B.IOS syntactic group.
TSTORE already implements this correctly
TSTORE in jcore/template_asm.hpp:2054-2180 already handles both cases:
is_subview_v<tile_shape> check (line 2054)
- Shared parent: uses
B.IOS + handle() + B.SUBVIEW (lines 2056-2118)
- Local parent: uses
B.IOT + data() + B.SUBVIEW (lines 2119-2182)
The range::Subview carrier already supports both:
data() — requires(!is_shared_tile_v<Parent>) (pto_tile.hpp:1948-1951)
handle() / handle_ref() — requires(is_shared_tile_v<Parent>) (pto_tile.hpp:1952-1959)
The compiler's range-modifiers.md:274-296 documents this as implemented for TLOAD/TSTORE:
Range carriers over a SharedTile parent bind through the Shared B.IOS binder instead of B.IOT, and expose handle() / handle_ref() instead of data().
Gap: TEPL operations lack Subview carrier support
The problem is that TEPL operations (TROWSUM, TADD, etc.) have no Subview carrier overload — only the SubTileView (from TPARTVIEW) overload in pto_tile_region_inline_asm.hpp. The SubTileView class:
- Has
data() that calls parent_->data() — fails for SharedTile
- Has no
handle() method for Shared parents
The generic TROWSUM in template_asm.hpp:9606 uses is_tile_data_v which matches Subview carriers (via is_tile<range::Subview<...>> at pto_tile.hpp:2249), but does not emit B.SUBVIEW — it would use the parent's full data without range restriction.
Impact
Any kernel that loads data into a SharedTile (the standard L1 shared storage for multi-PE cooperation) and wants to partition it with TPARTVIEW for element-wise or reduction operations is blocked. There is no workaround through the Subview carrier either, because TEPL operations don't emit B.SUBVIEW for Subview carriers.
Proposed fix
Fix A: CubeM32 sub-view in inline region path
The inline region path (pto_region_unary, pto_region_binary, etc. in pto_tile_region_inline_asm.hpp) should be extended to accept CubeM32 (and CubeM16) sub-tiles. Two possible approaches:
Option A1 (compiler-side materialization): Remove the RowMajor static_assert and emit B.IOT + B.SUBVIEW for CubeM32 sources, relying on the hardware's BundleCubeSubviewDescriptorOf + MaterializeBundleSubview to materialize the RowMajor view at execution time (as the ISA spec describes). The inline asm already emits B.SUBVIEW — the only change is removing the static_assert and ensuring the B.DIM operands use the sub-tile's ValidCol/ValidRow (which SubTileView already forwards from SubTile).
Option A2 (compiler-side CUBE→RowMajor conversion): Implement the "Cube binder/CELL ordering path" mentioned in range-modifiers.md:123. This would be a more complex change but would match the ISA spec's materialization model where the hardware copies CUBE parent data into a RowMajor materialized tile.
Option A1 is simpler and sufficient for TEPL operations (TROWSUM, TADD, etc.), since the ISA spec says non-CUBE operations consume the bounded view in RowMajor representation.
Fix B: SharedTile sub-view in TEPL operations
Two changes needed:
-
SubTileView should support Shared parents: Add handle() / handle_ref() methods to SubTileView (in pto_tile_region.hpp) that forward to parent_->handle() / parent_->handle_ref() for SharedTile parents, similar to how Subview already does (pto_tile.hpp:1952-1959).
-
Inline region path should emit B.IOS for Shared sources: In pto_region_unary / pto_region_binary (in pto_tile_region_inline_asm.hpp), add a if constexpr (is_shared_tile_v<Parent>) branch that uses B.IOS + handle() instead of B.IOT + data(), mirroring the pattern already implemented in TSTORE (template_asm.hpp:2054-2118).
Alternatively (or additionally), TEPL operations in template_asm.hpp (TROWSUM, TADD, etc.) should gain is_subview_v checks to handle Subview carriers directly, similar to TSTORE. This would allow the range::subview() factory API to be used with TEPL operations, not just TSTORE.
Reproduction
Both issues are reproducible with the rowsum_subview_local and rowsum_subview_shared test cases in SuperNPUBench/benchmark/one-level-arch/test/kernel/reduction/reducesum_row/src/.
Constraint 1 (CubeM32)
make diss TESTCASE=rowsum_subview_local \
COMPILER_DIR=$COMPILER_DIR \
ROWSUM_ROWS=128 ROWSUM_COLS=16 ROWSUM_PARTS=4 \
OBJ_ROOT=/tmp/rowsum_local_build
Error: static assertion failed: inline Tile region path requires RowMajor fragments
Constraint 2 (SharedTile)
make diss TESTCASE=rowsum_subview_shared \
COMPILER_DIR=$COMPILER_DIR \
ROWSUM_ROWS=128 ROWSUM_COLS=16 ROWSUM_PARTS=4 \
OBJ_ROOT=/tmp/rowsum_shared_build
Error: no member named 'data' in 'pto::SharedTile<...>'
References
| Source |
Path |
Key evidence |
| B.SUBVIEW ASL |
pto-spec/asl/block/operands/B.SUBVIEW.asl |
Block composition: "Immediately follows B.IOT or B.IOS"; Legality: Local 1..10, Shared 1..12 |
| Subview descriptor ASL |
pto-spec/asl/block/model/operands/subview-descriptor.asl |
NDF PTO-B-SUBVIEW-DESCRIPTOR-001: "A legal Local CUBE B.SUBVIEW"; BundleCubeSubviewDescriptorOf(): CUBE descriptor derivation; MaterializeBundleSubview(): CUBE→RowMajor materialization for non-CUBE ops |
| ADR-BLOCK-0016 |
pto-spec/docs/status/decisions/ADR-BLOCK-0016-b-range-modifiers.md |
"Each modifier attaches only to the eligible Local or Shared binding group" |
| B.SUBVIEW reader doc |
pto-spec/docs/block/operands/B.SUBVIEW.md |
Legality section: "Local-associated groups require 1..10 and Shared-associated groups accept 1..12" |
| Compiler doc (acknowledgment) |
linx-toolchain-build/src/Linx-TileOP-API/docs/tileop-usage/range-modifiers.md |
L119-123: "intentionally limited to RowMajor + NoneBox"; L274-296: Shared Tile ranges documented as implemented for TLOAD/TSTORE |
| TSTORE (reference impl) |
linx-toolchain-build/.../jcore/template_asm.hpp:2054-2180 |
is_subview_v check with Shared (B.IOS + handle) and Local (B.IOT + data) branches |
| Subview carrier |
linx-toolchain-build/.../common/pto_tile.hpp:1896-1968 |
data() for Local, handle() for Shared |
| Inline region path (constraint) |
linx-toolchain-build/.../common/pto_tile_region_inline_asm.hpp:13 |
static_assert(SubTile::BFractal == BLayout::RowMajor) |
| SubTileView (constraint) |
linx-toolchain-build/.../common/pto_tile_region.hpp:97 |
data() { return parent_->data(); } — no handle() for Shared |
| Test cases |
SuperNPUBench/.../reducesum_row/src/rowsum_subview_local.cpp |
CubeTileM32 + TPARTVIEW + TROWSUM |
| Test cases |
SuperNPUBench/.../reducesum_row/src/rowsum_subview_shared.cpp |
SharedTile + TPARTVIEW + TROWSUM |
TEPL inline region path rejects CubeM32 sub-views and SharedTile sub-view sources — both contradict PTO-ISA 0.58.6
Summary
The inline Tile region producer path (
pto_tile_region_inline_asm.hpp) imposes two constraints that are not grounded in the PTO-ISA specification and block legitimate, ISA-legal usage ofB.SUBVIEWwithTPARTVIEWon TEPL operations (TROWSUM, TADD, TEXP, …):static_assert(SubTile::BFractal == BLayout::RowMajor)rejects CubeM32 sub-tiles even though the ISA spec normatively defines CUBE sub-view descriptor derivation (BundleCubeSubviewDescriptorOf).SubTileView::data()callsparent_->data(), which does not exist onSharedTile(Shared tiles usehandle()), even though the ISA spec explicitly allowsB.SUBVIEWafterB.IOS(Shared binder).Both constraints are acknowledged as intentional limitations in the compiler's own documentation (
range-modifiers.md), but neither is supported by the ISA spec. The ISA spec explicitly supports both CUBE sub-views and Shared sub-views.Constraint 1: CubeM32 sub-view rejected by RowMajor static_assert
Symptom
Compiling
TPARTVIEW<CubeTileM32<float,32,4>, 1, 4>(parent)followed byTROWSUM(dst, subview)fails:Location:
pto_tile_region_inline_asm.hpp:13(inpto_region_unary)ISA spec evidence
The PTO-ISA 0.58.6 specification normatively supports CUBE B.SUBVIEW:
NDF
PTO-B-SUBVIEW-DESCRIPTOR-001(asl/block/model/operands/subview-descriptor.asl:3-9):This NDF explicitly contemplates "Local CUBE B.SUBVIEW" as a legal construct.
BundleCubeSubviewDescriptorOf()(asl/block/model/operands/subview-descriptor.asl:36-124):The function derives a bounded sub-view descriptor from a CUBE parent tile. It:
TileLayoutIsCube(parent.layout)(line 44) — the function is specifically designed for CUBE layoutscell_rows/cell_columnsfrom the CUBE layout (lines 59-60)CUBE_N8and other CUBE layouts (e.g.,CUBE_M32) in separate branches (lines 65-83)origin_column = offset_cells * cell_columns(line 81-82)MaterializeBundleSubview()(asl/block/model/operands/subview-descriptor.asl:264-423):When the consuming operation is a non-CUBE (TEPL) operation like TROWSUM:
operation_is_cube = BundleTileDecodeFamily(...) == TileDecode_CUBETileLayout_RowMajor, line 385), reading from the CUBE parent in its original CELL orderReadTileElement(parent, origin_row+row, origin_column+column)) into the RowMajor materialized viewThis means the ISA spec's intended behavior for a CUBE parent + TEPL consumer is: the hardware materializes a RowMajor view of the CUBE parent's sub-region at execution time. The compiler does not need to emit RowMajor fragments — it can emit B.SUBVIEW on a CUBE source and the hardware handles the CUBE→RowMajor materialization.
Applicability is total (
asl/block/model/operands/subview-descriptor.asl:133-140):There is no operation-specific restriction — TROWSUM, TADD, and all other TEPL operations are legal consumers.
Compiler's own acknowledgment
docs/tileop-usage/range-modifiers.md:119-123:This is a documented known limitation and future implementation item, not an ISA constraint.
Impact
Any kernel that loads data into a CubeM32 local tile (the standard local L0 layout for matrix data) and wants to partition it with TPARTVIEW for element-wise or reduction operations is blocked. The only workaround is to use RowMajor local tiles, which is not the correct L0 layout for matrix data and forces an extra layout conversion on TLOAD.
Constraint 2: SharedTile sub-view source rejected by data() dependency
Symptom
Compiling
TPARTVIEW<SharedTile<SharedMatrixLeft<float,32,4>>, 1, 4>(shared_parent)followed byTROWSUM(dst, subview)fails:Location:
pto_tile_region.hpp:97—SubTileView::data()callsparent_->data(), butSharedTilehas nodata()method (it exposeshandle()/handle_ref()instead).ISA spec evidence
The PTO-ISA 0.58.6 specification explicitly supports B.SUBVIEW with B.IOS (Shared):
B.SUBVIEW block composition (
asl/block/operands/B.SUBVIEW.asl:1, contract"block_composition"):B.SUBVIEW legality (
asl/block/operands/B.SUBVIEW.asl:1, contract"legality"):The ISA distinguishes Local (SizeCode 1..10) from Shared (1..12) — Shared B.SUBVIEW is explicitly legal.
NDF
PTO-B-SUBVIEW-RANGE-001(asl/block/operands/B.SUBVIEW.asl:3-11):ADR-BLOCK-0016 (
docs/status/decisions/ADR-BLOCK-0016-b-range-modifiers.md:93-94):TSTORE already implements this correctly
TSTOREinjcore/template_asm.hpp:2054-2180already handles both cases:is_subview_v<tile_shape>check (line 2054)B.IOS+handle()+B.SUBVIEW(lines 2056-2118)B.IOT+data()+B.SUBVIEW(lines 2119-2182)The
range::Subviewcarrier already supports both:data()—requires(!is_shared_tile_v<Parent>)(pto_tile.hpp:1948-1951)handle()/handle_ref()—requires(is_shared_tile_v<Parent>)(pto_tile.hpp:1952-1959)The compiler's
range-modifiers.md:274-296documents this as implemented for TLOAD/TSTORE:Gap: TEPL operations lack Subview carrier support
The problem is that TEPL operations (TROWSUM, TADD, etc.) have no Subview carrier overload — only the
SubTileView(from TPARTVIEW) overload inpto_tile_region_inline_asm.hpp. TheSubTileViewclass:data()that callsparent_->data()— fails for SharedTilehandle()method for Shared parentsThe generic TROWSUM in
template_asm.hpp:9606usesis_tile_data_vwhich matchesSubviewcarriers (viais_tile<range::Subview<...>>at pto_tile.hpp:2249), but does not emitB.SUBVIEW— it would use the parent's full data without range restriction.Impact
Any kernel that loads data into a SharedTile (the standard L1 shared storage for multi-PE cooperation) and wants to partition it with TPARTVIEW for element-wise or reduction operations is blocked. There is no workaround through the Subview carrier either, because TEPL operations don't emit B.SUBVIEW for Subview carriers.
Proposed fix
Fix A: CubeM32 sub-view in inline region path
The inline region path (
pto_region_unary,pto_region_binary, etc. inpto_tile_region_inline_asm.hpp) should be extended to accept CubeM32 (and CubeM16) sub-tiles. Two possible approaches:Option A1 (compiler-side materialization): Remove the RowMajor static_assert and emit
B.IOT+B.SUBVIEWfor CubeM32 sources, relying on the hardware'sBundleCubeSubviewDescriptorOf+MaterializeBundleSubviewto materialize the RowMajor view at execution time (as the ISA spec describes). The inline asm already emitsB.SUBVIEW— the only change is removing the static_assert and ensuring the B.DIM operands use the sub-tile's ValidCol/ValidRow (whichSubTileViewalready forwards fromSubTile).Option A2 (compiler-side CUBE→RowMajor conversion): Implement the "Cube binder/CELL ordering path" mentioned in
range-modifiers.md:123. This would be a more complex change but would match the ISA spec's materialization model where the hardware copies CUBE parent data into a RowMajor materialized tile.Option A1 is simpler and sufficient for TEPL operations (TROWSUM, TADD, etc.), since the ISA spec says non-CUBE operations consume the bounded view in RowMajor representation.
Fix B: SharedTile sub-view in TEPL operations
Two changes needed:
SubTileView should support Shared parents: Add
handle()/handle_ref()methods toSubTileView(inpto_tile_region.hpp) that forward toparent_->handle()/parent_->handle_ref()for SharedTile parents, similar to howSubviewalready does (pto_tile.hpp:1952-1959).Inline region path should emit B.IOS for Shared sources: In
pto_region_unary/pto_region_binary(inpto_tile_region_inline_asm.hpp), add aif constexpr (is_shared_tile_v<Parent>)branch that usesB.IOS+handle()instead ofB.IOT+data(), mirroring the pattern already implemented in TSTORE (template_asm.hpp:2054-2118).Alternatively (or additionally), TEPL operations in
template_asm.hpp(TROWSUM, TADD, etc.) should gainis_subview_vchecks to handleSubviewcarriers directly, similar to TSTORE. This would allow therange::subview()factory API to be used with TEPL operations, not just TSTORE.Reproduction
Both issues are reproducible with the
rowsum_subview_localandrowsum_subview_sharedtest cases inSuperNPUBench/benchmark/one-level-arch/test/kernel/reduction/reducesum_row/src/.Constraint 1 (CubeM32)
make diss TESTCASE=rowsum_subview_local \ COMPILER_DIR=$COMPILER_DIR \ ROWSUM_ROWS=128 ROWSUM_COLS=16 ROWSUM_PARTS=4 \ OBJ_ROOT=/tmp/rowsum_local_buildError:
static assertion failed: inline Tile region path requires RowMajor fragmentsConstraint 2 (SharedTile)
make diss TESTCASE=rowsum_subview_shared \ COMPILER_DIR=$COMPILER_DIR \ ROWSUM_ROWS=128 ROWSUM_COLS=16 ROWSUM_PARTS=4 \ OBJ_ROOT=/tmp/rowsum_shared_buildError:
no member named 'data' in 'pto::SharedTile<...>'References
pto-spec/asl/block/operands/B.SUBVIEW.aslpto-spec/asl/block/model/operands/subview-descriptor.aslBundleCubeSubviewDescriptorOf(): CUBE descriptor derivation;MaterializeBundleSubview(): CUBE→RowMajor materialization for non-CUBE opspto-spec/docs/status/decisions/ADR-BLOCK-0016-b-range-modifiers.mdpto-spec/docs/block/operands/B.SUBVIEW.mdlinx-toolchain-build/src/Linx-TileOP-API/docs/tileop-usage/range-modifiers.mdlinx-toolchain-build/.../jcore/template_asm.hpp:2054-2180is_subview_vcheck with Shared (B.IOS + handle) and Local (B.IOT + data) brancheslinx-toolchain-build/.../common/pto_tile.hpp:1896-1968data()for Local,handle()for Sharedlinx-toolchain-build/.../common/pto_tile_region_inline_asm.hpp:13static_assert(SubTile::BFractal == BLayout::RowMajor)linx-toolchain-build/.../common/pto_tile_region.hpp:97data() { return parent_->data(); }— no handle() for SharedSuperNPUBench/.../reducesum_row/src/rowsum_subview_local.cppSuperNPUBench/.../reducesum_row/src/rowsum_subview_shared.cpp